pax_global_header00006660000000000000000000000064152010570510014506gustar00rootroot0000000000000052 comment=583d0128bb5ebfac263496bc8fe32d4aef440178 opencryptoki-opencryptoki-451d99c/000077500000000000000000000000001520105705100173245ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/.githooks/000077500000000000000000000000001520105705100212315ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/.githooks/pre-commit000066400000000000000000000033661520105705100232400ustar00rootroot00000000000000#!/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 opencryptoki-opencryptoki-451d99c/.gitignore000066400000000000000000000115721520105705100213220ustar00rootroot00000000000000# COPYRIGHT (c) International Business Machines Corp. 2001-2022 # # This program is provided under the terms of the Common Public License, # version 1.0 (CPL-1.0). Any use, reproduction or distribution for this 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 # # project specific ignore patterns # ignore executables testcases/build/cpp_test testcases/crypto/ab_tests testcases/crypto/aes_tests testcases/crypto/des3_tests testcases/crypto/des_tests testcases/crypto/dh_tests testcases/crypto/digest_tests testcases/crypto/dilithium_tests testcases/crypto/dsa_tests testcases/crypto/ec_tests testcases/crypto/ibm_ml_dsa_tests testcases/crypto/ibm_ml_kem_tests testcases/crypto/ml_dsa_tests testcases/crypto/ml_kem_tests testcases/crypto/rsa_tests testcases/crypto/rsaupdate_tests testcases/crypto/ssl3_tests testcases/crypto/kyber_tests testcases/init_token.sh 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/misc_tests/always_auth testcases/misc_tests/cca_export_import_test testcases/misc_tests/cca_ep11_export_import_test testcases/misc_tests/events testcases/misc_tests/fork testcases/misc_tests/multi_instance testcases/misc_tests/obj_lock testcases/misc_tests/obj_mgmt_lock_tests testcases/misc_tests/obj_mgmt_tests testcases/misc_tests/reencrypt testcases/misc_tests/speed testcases/misc_tests/threadmkobj testcases/misc_tests/tok2tok_transport testcases/misc_tests/tok_des testcases/misc_tests/tok_obj testcases/misc_tests/tok_rsa testcases/misc_tests/dual_functions testcases/ock_tests.sh testcases/pkcs11/attribute testcases/pkcs11/copyobjects testcases/pkcs11/destroyobjects testcases/pkcs11/findobjects testcases/pkcs11/gen_purpose testcases/pkcs11/generate_keypair testcases/pkcs11/get_interface testcases/pkcs11/getobjectsize testcases/pkcs11/hw_fn testcases/pkcs11/sess_bench testcases/pkcs11/sess_mgmt_tests testcases/pkcs11/sess_opstate testcases/policy/policytest testcases/policy/policytest.sh testcases/unit/configdump testcases/unit/hashmaptest testcases/unit/mechtabletest testcases/unit/policytest testcases/unit/buffertest testcases/unit/uritest testcases/unit/pintest usr/sbin/p11sak/p11sak usr/sbin/p11kmip/p11kmip usr/sbin/pkcscca/pkcscca usr/sbin/pkcsconf/pkcsconf usr/sbin/pkcsicsf/pkcsicsf usr/sbin/pkcsslotd/pkcsslotd usr/sbin/pkcsstats/pkcsstats usr/sbin/pkcstok_migrate/pkcstok_migrate usr/sbin/pkcstok_admin/pkcstok_admin usr/sbin/pkcsep11_migrate/pkcsep11_migrate usr/sbin/pkcsep11_session/pkcsep11_session usr/sbin/pkcshsm_mk_change/pkcshsm_mk_change tools/policyexamplegen tools/tableidxgen # ignore test logs *.log *.trs # ignore build stubs *.lai libtool # ignore generated source (from .in) usr/lib/api/shrd_mem.c man/man1/p11sak.1 man/man1/p11kmip.1 man/man1/pkcsep11_session.1 man/man1/pkcsicsf.1 man/man1/pkcstok_migrate.1 man/man1/pkcstok_admin.1 man/man1/pkcsep11_migrate.1 man/man1/pkcscca.1 man/man1/pkcsconf.1 man/man1/pkcsstats.1 man/man1/pkcshsm_mk_change.1 man/man5/policy.conf.5 man/man5/p11kmip.conf.5 man/man5/p11sak_defined_attrs.conf.5 man/man5/opencryptoki.conf.5 man/man5/strength.conf.5 man/man8/pkcsslotd.8 man/man7/opencryptoki.7 misc/opencryptoki.conf misc/pkcsslotd.service misc/pkcsslotd misc/opencryptoki.pc testcases/init_vhsm.exp testcases/policy/policytest.sh testcases/ock_tests.sh testcases/cleanup_vhsm.exp testcases/init_token.sh # ignore generated source (other) doc/policy-example.conf usr/lib/api/mechtable-gen.h usr/lib/api/mechtable.c usr/lib/api/mechtable.log usr/lib/api/shrd_mem.c usr/lib/config/cfglex.c usr/lib/config/cfglex.h usr/lib/config/cfgparse.c usr/lib/config/cfgparse.h usr/lib/config/cfgparse.output # common C ignores *.d *.o *.obj *.elf *.ilk *.map *.exp *.gch *.pch *.lib *.a *.la *.lo *.so *.so.* *.dylib *.out *.hex *.dSYM/ *.su *.idb *.pdb # common autotools ignores Makefile.in /ar-lib /mdate-sh /py-compile /test-driver /ylwrap .deps/ .dirstamp autom4te.cache /autoscan.log /autoscan-*.log /aclocal.m4 /compile /config.cache /config.guess /config.h.in /config.log /config.status /config.sub /configure /configure.scan /depcomp /install-sh /missing /stamp-h1 /ltmain.sh /texinfo.tex m4/libtool.m4 m4/ltoptions.m4 m4/ltsugar.m4 m4/ltversion.m4 m4/lt~obsolete.m4 Makefile # common tag ignores TAGS .TAGS !TAGS/ tags .tags !tags/ gtags.files GTAGS GRTAGS GPATH GSYMS cscope.files cscope.out cscope.in.out cscope.po.out # common emacs ignores *~ \#*\# /.emacs.desktop /.emacs.desktop.lock *.elc auto-save-list tramp .\#* .org-id-locations *_archive *_flymake.* /eshell/history /eshell/lastdir /elpa/ *.rel /auto/ .cask/ dist/ flycheck_*.el /server/ .projectile .dir-locals.el /network-security.data # common vim ignores [._]*.s[a-v][a-z] [._]*.sw[a-p] [._]s[a-rt-v][a-z] [._]ss[a-gi-z] [._]sw[a-p] Session.vim Sessionx.vim .netrwhist *~ [._]*.un~ opencryptoki-opencryptoki-451d99c/.indent.pro000066400000000000000000000011331520105705100214030ustar00rootroot00000000000000-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 opencryptoki-opencryptoki-451d99c/.travis.yml000066400000000000000000000075771520105705100214550ustar00rootroot00000000000000os: linux dist: noble language: c before_install: - if [[ "$TRAVIS_DIST" != "focal" ]]; then sudo apt-get -qq update; fi - sudo apt-get install -y expect libldap2-dev wget libudev-dev autoconf-archive libcap-dev pv curl jq - if [[ "$TRAVIS_CPU_ARCH" != "amd64" ]]; then sudo apt-get install -y trousers libtspi-dev; fi - if [[ "$TRAVIS_CPU_ARCH" = "s390x" && "$TRAVIS_DIST" != "focal" ]]; then sudo apt-get install -y libica4 libica-dev; fi - if [[ "$TRAVIS_CPU_ARCH" = "s390x" && "$TRAVIS_DIST" = "focal" ]]; then sudo apt-get install -y libica3 libica-dev; fi jobs: include: - name: "linux-x86-clang" os: linux compiler: clang env: CONFIG_OPTS="--enable-swtok --enable-icsftok --enable-ccatok --enable-testcases --with-systemd" CFLAGS="-O3 -Werror -Wno-error=unused-but-set-variable -DDEBUG" - name: "linux-x86-gcc" os: linux compiler: gcc env: CONFIG_OPTS="--enable-swtok --enable-icsftok --enable-ccatok --enable-testcases --with-systemd" CFLAGS="-O3 -Wno-clobbered -Werror" - name: "linux-ppc64le-clang" os: linux arch: ppc64le compiler: clang env: CONFIG_OPTS="--enable-swtok --enable-icsftok --enable-ccatok --enable-tpmtok --enable-testcases --with-systemd" CFLAGS="-O3 -Werror -Wno-error=unused-but-set-variable" - name: "linux-ppc64le-gcc" os: linux arch: ppc64le compiler: gcc env: CONFIG_OPTS="--enable-swtok --enable-icsftok --enable-ccatok --enable-tpmtok --enable-testcases --with-systemd" CFLAGS="-O3 -Wno-clobbered -Werror -DDEBUG" - name: "linux-s390x-clang" os: linux arch: s390x compiler: clang env: CONFIG_OPTS="--enable-swtok --enable-icsftok --enable-ccatok --enable-tpmtok --enable-icatok --enable-ep11tok --enable-testcases --with-systemd" CFLAGS="-O3 -Werror -Wno-error=unused-but-set-variable -DDEBUG" - name: "linux-s390x-gcc" os: linux arch: s390x compiler: gcc env: CONFIG_OPTS="--enable-swtok --enable-icsftok --enable-ccatok --enable-tpmtok --enable-icatok --enable-ep11tok --enable-testcases --with-systemd" CFLAGS="-O3 -Wno-clobbered -Werror" - name: "linux-arm64-clang" os: linux arch: arm64 compiler: clang env: CONFIG_OPTS="--enable-swtok --enable-icsftok --enable-ccatok --enable-tpmtok --enable-testcases --with-systemd" CFLAGS="-O3 -Werror -Wno-error=unused-but-set-variable" - name: "linux-arm64-gcc" os: linux arch: arm64 compiler: gcc env: CONFIG_OPTS="--enable-swtok --enable-icsftok --enable-ccatok --enable-tpmtok --enable-testcases --with-systemd" CFLAGS="-O3 -Wno-clobbered -Werror -DDEBUG" - name: "linux-s390x-gcc-openssl-1.1.1" os: linux dist: focal arch: s390x compiler: gcc env: CONFIG_OPTS="--enable-swtok --enable-icsftok --enable-ccatok --enable-tpmtok --enable-icatok --enable-ep11tok --enable-testcases --with-systemd" CFLAGS="-O3 -Wno-clobbered -Werror" before_script: - ./bootstrap.sh 2> >(tee) script: - set -o pipefail - openssl version 2> >(tee) - ./configure --silent $CONFIG_OPTS 2> >(tee) && make -j 5 V=0 2> >(tee) - make check V=0 2> >(tee) - sudo make install 2> >(tee) - sudo ldconfig 2> >(tee) - sudo pkcsslotd 2> >(tee) - sudo pkcsconf -i 2> >(tee) - sudo pkcsconf -s 2> >(tee) - sudo pkcsconf -t 2> >(tee) - cd testcases - sudo PKCS11_SO_PIN=76543210 PKCS11_USER_PIN=01234567 PKCSLIB=/usr/local/lib/pkcs11/libopencryptoki.so ./ock_tests.sh -s 3 | grep --line-buffered -A 2 -B 2 "SKIP\|FAIL\|ERROR\|Total=\|Now executing" | pv -t -i 1 -f - sudo SLOT=3 PKCS11_USER_PIN=01234567 PKCS11_SO_PIN=76543210 PKCSLIB=/usr/local/lib/pkcs11/libopencryptoki.so ./misc_tests/p11sak_test.sh 2> >(tee) opencryptoki-opencryptoki-451d99c/CONTRIBUTING.md000066400000000000000000000077621520105705100215710ustar00rootroot00000000000000# 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 current [PKCS #11 standard](https://www.oasis-open.org/committees/tc_home.php?wg_abbrev=pkcs11). * 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. * In case AI assisted you to identify the issue, please state the name of the AI tool or framework. * 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 to certify the Developer Certificate of Origin (DCO): ```text 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 ``` * AI agents MUST NOT add Signed-off-by tags. Only humans can legally certify the Developer Certificate of Origin (DCO). The human submitter is responsible for: * Reviewing all AI-generated code. * Ensuring compliance with licensing requirements. * Adding their own Signed-off-by tag to certify the Developer Certificate of Origin. * Taking full responsibility for the contribution. * 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. ## Attribution When AI tools contribute to openCryptoki, proper attribution helps track the evolving role of AI in the development process. Contributions should include an Assisted-by tag in the following format: ```text Assisted-by: AGENT_NAME:MODEL_VERSION [TOOL1] [TOOL2] ``` Where: * AGENT_NAME is the name of the AI tool or framework * MODEL_VERSION is the specific model version used * \[TOOL1\] \[TOOL2\] are optional specialized analysis tools used (e.g., coccinelle, sparse, smatch, clang-tidy) Basic development tools (git, gcc, make, editors) should not be listed. ## Submitting Changes * Sign your commits, as mentioned above. * Submit a pull request to the opencryptoki repository on opencryptoki organization. * Include test information/results 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. * Have fun in the process, coding is fun! opencryptoki-opencryptoki-451d99c/COPYING000066400000000000000000000270121520105705100203610ustar00rootroot00000000000000 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. opencryptoki-opencryptoki-451d99c/COPYRIGHTS000066400000000000000000000142571520105705100207530ustar00rootroot00000000000000Base openCryptoki Code and IBM submissions (C) COPYRIGHT International Business Machines Corp. 2001, 2023 For code originating from OpenSSL: * - usr/lib/ica_s390_stdll/rsa_sup_mul.c: Copied from OpenSSL from * crypto/bn/rsa_sup_mul.c and modified to fit to the OpenCrptoki environment. * See comment in usr/lib/ica_s390_stdll/rsa_sup_mul.c for a list of changes. * Note that in OpenSSL the file crypto/bn/rsa_sup_mul.c does no longer * exist, it was removed with commit https://github.com/openssl/openssl/commit/4209ce68d8fe8b1506494efa03d378d05baf9ff8 * - usr/lib/common/constant_time.h: Copied unchanged from OpenSSL from * include/internal/constant_time.h * - The implementation of function rsa_parse_block_type_2() in * usr/lib/common/mech_rsa.c is copied from OpenSSL's function * ossl_rsa_padding_check_PKCS1_type_2() in crypto/rsa/rsa_pk1.c * and is slightly modified to fit to the OpenCryptoki environment. * See comment in function rsa_parse_block_type_2() for a list of changes. * - The implementation of function openssl_specific_rsa_derive_kdk() in * usr/lib/common/mech_openssl.c is copied from OpenSSL's function * derive_kdk() in crypto/rsa/rsa_ossl.c and is slightly modified to fit to * the OpenCryptoki environment. See comment in function * openssl_specific_rsa_derive_kdk() for a list of changes. * - The implementation of function openssl_specific_rsa_prf() in * usr/lib/common/mech_openssl.c is copied from OpenSSL's function * ossl_rsa_prf() in crypto/rsa/rsapk1.c and is slightly modified to fit to * the OpenCryptoki environment. See comment in function * openssl_specific_rsa_prf() for a list of changes. * - The implementation of function decode_eme_oaep() in * usr/lib/common/mech_rsa.c is copied from OpenSSL's function * RSA_padding_check_PKCS1_OAEP_mgf1() in crypto/rsa/rsa_oaep.c and is * slightly modified to fit to the OpenCryptoki environment. See comment in * function decode_eme_oaep() for a list of changes. * - The implementation of the AESKW functions in usr/lib/common/mech_aes.c is * copied from OpenSSL's source file crypto/modes/wrap128.c and is slightly * modified to fit to the OpenCryptoki environment. See comment in * file usr/lib/common/mech_aes.c for a list of changes. * * Copyright 1999-2024 The OpenSSL Project Authors. All Rights Reserved. * * The OpenSSL code is licensed under the Apache License 2.0 (the "License"). * You can obtain a copy in the file LICENSE in the OpenSSL source distribution * or at https://www.openssl.org/source/license.html 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. For code that is used only on AIX, importing Linux-specific popular behaviour. 1. err.c: * Implementation of the err/errx/verr/verrx/warn/warnx/vwarn/vwarnx * functions from BSD. * * This file is public-domain; anyone may deal in it without restriction. * * Written by Graue on January 16, 2006. 2. getopt_long.c: * getopt_long() -- long options parser * * Portions Copyright (c) 1987, 1993, 1994 * The Regents of the University of California. All rights reserved. * * Portions Copyright (c) 2003 * PostgreSQL Global Development Group * * 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 the University 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 REGENTS 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 THE REGENTS OR 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. opencryptoki-opencryptoki-451d99c/ChangeLog000066400000000000000000000526501520105705100211060ustar00rootroot00000000000000+ openCryptoki 3.27 - Add base support for PKCS#11 v3.2. - Add support for PKCS#11 v3.2 C_VerifySignature[Init|Update|Final]. - Add support for PKCS#11 v3.2 C_EncapsulateKey/C_DecapsulateKey. - Soft/ICA/CCA/EP11: Add support for PKCS#11 v3.2 en-/decapsulate with RSA-PKCS and RSA-OAEP mechanisms. - Soft/ICA/CCA/EP11: Add support for PKCS#11 v3.2 en-/decapsulate with the ECDH mechanism. - Soft/EP11: Add support for PKCS#11 v3.2 en-/decapsulate with the DH-PKCS mechanism. - Soft: Add support for PKCS#11 v3.2 ML-DSA and ML-KEM key types and mechanisms (requires OpenSSL 3.5 or later, or the OQS-provider must be configured). - CCA: Add support for PKCS#11 v3.2 ML-DSA key type and mechanisms (requires CCA v8.4 or later) - EP11: Add support for PKCS#11 v3.2 ML-DSA and ML-KEM key types and mechanisms (requires an EP11 host library v4.2 or later, and a CEX8P crypto card with firmware v9.6 or later on IBM z17, and v8.39 or later on IBM z16). - p11sak: Add support for PKCS#11 v3.2 ML-DSA and ML-KEM key types. - Soft/ICA: Add support for PKCS#11 v3.2 mechanisms CKM_ECDH_X_AES_KEY_WRAP and CKM_ECDH_COF_AES_KEY_WRAP. - p11sak: Add support for key wrapping with PKCS#11 v3.2 mechanisms CKM_ECDH_X_AES_KEY_WRAP and CKM_ECDH_COF_AES_KEY_WRAP. - Soft/ICA/CCA/EP11: Add support for PKCS#11 v3.2 mechanism CKM_PUB_KEY_FROM_PRIV_KEY. - Soft/ICA/CCA/EP11: Add support for PKCS#11 v3.0 Edwards and Montgomery key types and mechanisms. - Soft/ICA: Support CKM_ECDH_AES_KEY_WRAP also for Montgomery keys. - p11sak: Add support for PKCS#11 v3.0 Edwards and Montgomery key types. - Soft: Add support for CKM_ECDH1_COFACTOR_DERIVE. - CCA: Add support for additional RSA public exponent values 5, 17, or 257. - p11sak: Add option to list-key command to show EP11 session IDs. - Make the maximum number of token objects supported configurable. - Fixes for CVE-2026-40253, CVE-2026-23893, and CVE-2026-22791. - Bug fixes. + openCryptoki 3.26 - Soft: Add support for RSA keys up to 16K bits. - CCA: Add support for RSA keys up to 8K bits (requires CCA v8.4 or v7.6 or later). - p11sak: Add support for generating RSA keys up to 16K bits. - Soft/ICA: Add support for SHA512/224 and SHA512/256 key derivation mechanism (CKM_SHA512_224_KEY_DERIVATION and CKM_SHA512_256_KEY_DERIVATION). - Soft/ICA/CCA/EP11: Add support for SHA-HMAC key types CKK_SHAxxx_HMAC and key gen mechanisms CKM_SHAxxx_KEY_GEN. - p11sak: Add support for SHA-HMAC key types and key generation. - p11sak: Add support for key wrap and unwrap commands to export and import private and secret keys by means of key wrapping/unwrapping with various key wrapping mechanism. - p11kmip: Add support for using an HSM-protected TLS client key via a PKCS#11 provider. - p11sak: Add support for exporting non-sensitive private keys to password protected PEM files. - Add support for canceling an operation via NULL mechanism pointer at C_XxxInit() call as an alternative to C_SessionCancel() (PKCS#11 v3.0). - EP11: Add support for pairing friendly BLS12-381 EC curve for sign/verify using CKM_IBM_ECDSA_OTHER and signature/public key aggregation using CKM_IBM_EC_AGGREGATE. - p11sak: Add support for generating BLS12-381 EC keys. - EP11: Add support for IBM-specific ML-DSA and ML-KEM key types and mechanisms (requires an EP11 host library v4.2 or later, and a CEX8P crypto card with firmware v9.6 or later on IBM z17, and v8.39 or later on IBM z16). - CCA: Add support for IBM-specific ML-DSA and ML-KEM key types and mechanisms (requires CCA v8.4 or later). - Soft: Add support for IBM-specific ML-DSA and ML-KEM key types and mechanisms (requires OpenSSL 3.5 or later, or the OQS-provider must be configured). - p11sak: Add support for IBM-specific ML-DSA and ML-KEM key types. - Bug fixes. + openCryptoki 3.25 - ICA/Soft: Add support for PKCS#11 v3.0 SHAKE key derivation - EP11: Add support for PKCS#11 v3.0 SHA3 and SHA3-HMAC mechanisms - EP11: Add support for PKCS#11 v3.0 SHA3 mechanisms and MGFs for RSA-OAEP - EP11: Add support for PKCS#11 v3.0 SHA3 variants of RSA-PKCS and ECDSA mechanisms - CCA: Add support for CCA AES CIPHER secure key types - CCA: Add support for the CKM_ECDH1_DERIVE mechanism - Soft/ICA: Add support for the CKM_AES_KEY_WRAP[_*] mechanisms - CCA/Soft/ICA: Add support for the CKM_RSA_AES_KEY_WRAP mechanism - Soft/ICA: Add support for the CKM_ECDH_AES_KEY_WRAP mechanism - ICA: Report mechanisms dependent on if libica is in FIPS mode - P11KMIP: Add a tool for import and exporting PKCS#11 keys to a KMIP server - EP11: Add support for opaque secure key blob import via C_CreateObject - Soft/ICA: Add support for key wrapping with AES-GCM - CCA: Add support for newer CCA versions on s390x and non-s390x platforms - CCA: Add support for CKM_AES_GCM (single-part operations only) - Bug fixes + openCryptoki 3.24 - Add support for building Opencryptoki on the IBM AIX platform - Add support for the CCA token on non-IBM Z platforms (x86_64, ppc64) - Add support for protecting tokens with a token specific user group - EP11: Add support for combined CKA_EXTRACTABLE and CKA_IBM_PROTKEY_EXTRACTABLE - CCA: Add support for Koblitz curve secp256k1. Requires CCA v7.2 or later - CCA: Add support for IBM Dilithium (CKM_IBM_DILITHIUM). On Linux on IBM Z: Requires CCA v7.1 or later for Round2-65, and CCA v8.0 for the Round 3 variants. On other platforms: Requires CCA v7.2.43 or later for Round2-65, the Round 3 variants are currently not supported - CCA: Add support for RSA-OAEP with SHA224, SHA384, and SHA512 on en-/decrypt. Requires CCA v8.1 or later on Linux on IBM Z, not supported on other platforms - CCA: Add support for PKCS#11 v3.0 SHA3 mechanisms. Requires CCA v8.1 on Linux on IBM Z, not supported on other platforms - ICA: Support new libica AES-GCM api using the KMA instruction on z14 and later - ICA/Soft/ICSF: Add support for PKCS#11 v3.0 SHA3 mechanisms - ICA/Soft: Add support for SHA based key derivation mechanisms - ICA/Soft: Add support for CKD_*_SP800 KDFs for ECDH - EP11/CCA/ICA/Soft: Add support for CKA_ALWAYS_AUTHENTICATE - EP11/CCA: Support live guest relocation for protected key (PKEY) operations - Soft: Experimental support for IBM Dilithium via OpenSSL OQS provider - ICSF: Add support for SHA-2 mechanisms - ICSF: Performance improvements for attribute retrieval - p11sak: Add support for exporting a key or certificate as URI-PEM file - p11sak: Import/export of IBM Dilithium keys in 'oqsprovider' format PEM files - p11sak: Add option to show the master key verification patterns of secure keys - Bug fixes + openCryptoki 3.23 - EP11: Add support for FIPS-session mode - Updates to harden against RSA timing attacks - Bug fixes + openCryptoki 3.22 - CCA: Add support for the AES-XTS key type using CPACF protected keys - p11sak: Add support for managing certificate objects - p11sak: Add support for public sessions (no-login option) - p11sak: Add support for logging in as SO (security Officer) - p11sak: Add support for importing/exporting Edwards and Montgomery keys - p11sak: Add support for importing of RSA-PSS keys and certificates - CCA/EP11/Soft/ICA: Ensure that the 2 key parts of an AES-XTS key are different - Bug fixes + openCryptoki 3.21 - EP11 and CCA: Support concurrent HSM master key changes - CCA: protected-key option - pkcsslotd: no longer run as root user and further hardening - p11sak: Add support for additional key types (DH, DSA, generic secret) - p11sak: Allow wildcards in label filter - p11sak: Allow to specify hex value for CKA_ID attribute - p11sak: Support sorting when listing keys - p11sak: New commands: set-key-attr, copy-key to modify and copy keys - p11sak: New commands: import-key, export-key to import and export keys - Remove support for --disable-locks (transactional memory) - Updates to harden against RSA timing attacks - Bug fixes + openCryptoki 3.20 - Soft/ICA: add support for the AES-XTS key type (PKCS#11 v3.0) - ICSF: add support for ECDH and additional SHA variants - ICSF: add support for CKM_TLS_PRE_MASTER_KEY_GEN and CKM_TLS_KEY_AND_MAC_DERIVE - EP11: add support for the EP11 host library version 4 - EP11: add support for additional IBM specific Dilithium round 2 and 3 variants - EP11: add support for the IBM specific Kyber key type and mechanism - EP11: add support for the AES-XTS key type using CPACF protected keys - p11sak: add support for the AES-XTS key type - p11sak: add support for additional Dilithium variants and the Kyber key type - Bug fixes + openCryptoki 3.19 - CCA: check for expected master key verification patterns at token init - CCA: check master key verification pattern of created keys to be as expected - EP11: check for expected wrapping key verification pattern at token init - EP11: check wrapping key verification pattern of created keys to be as expected - p11sak/pkcsconf: display PKCS#11 URIs - p11sak: add support for IBM specific Dilithium keys - p11sak: allow to list keys filtered by label - common: add support for dual-function cryptographic functions - Add support for C_SessionCancel function (PKCS#11 v3.0) - EP11: add support for schnorr signatures (mechanism CKM_IBM_ECDSA_OTHER) - EP11: add support for Bitcoin key derivation (mechanism CKM_IBM_BTC_DERIVE) - Bug fixes + openCryptoki 3.18 - Default to FIPS compliant token data format (tokversion = 3.12) - Add support for restricting usage of mechanisms and keys via a global policy - Add support for statistics counting of mechanism usage - ICA/EP11: Support libica version 4 - p11sak tool: Allow to set different attributes for public and private keys + openCryptoki 3.17 - tools: added function to list keys to p11sak - common: added support for OpenSSL 3.0 - common: added support for event notifications - ICA: added SW fallbacks + openCryptoki 3.16 - EP11: protected-key option - EP11: support attribute-bound keys - CCA: import and export of secure key objects - Bug fixes + openCryptoki 3.15.1 - Bug fixes + openCryptoki 3.15 - common: conform to PKCS 11 3.0 Baseline Provider profile - Introduce new vendor defined interface named "Vendor IBM" - Support C_IBM_ReencryptSingle via "Vendor IBM" interface - CCA: support key wrapping - SOFT: support ECC - p11sak tool: add remove-key command - Bug fixes + 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 opencryptoki-opencryptoki-451d99c/FAQ000066400000000000000000000100741520105705100176600ustar00rootroot00000000000000 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 opencryptoki-opencryptoki-451d99c/INSTALL000066400000000000000000000153661520105705100203700ustar00rootroot00000000000000Basic 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. Note: Do not specify 'prefix=/foo/bar', 'libdir=/foo/bar' with the 'make' invocation. Specify them with 'configure' instead. Specifying them with 'make' is not supported by the openCryptoki package and may produce unexpected results! 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. opencryptoki-opencryptoki-451d99c/LICENSE000066400000000000000000000270121520105705100203330ustar00rootroot00000000000000 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. opencryptoki-opencryptoki-451d99c/Makefile.am000066400000000000000000000336031520105705100213650ustar00rootroot00000000000000ACLOCAL_AMFLAGS = -I m4 CLEANFILES = DISTCLEANFILES = *~ opencryptoki.map.sym opencryptoki_tok.map.sym MAINTAINERCLEANFILES = test-driver \ Makefile.in aclocal.m4 compile configure config.guess \ config.sub depcomp install-sh ltmain.sh m4/* missing \ depcomp ylwrap if AIX EXTRA_DIST = bootstrap.sh opencryptoki.map opencryptoki_tok.map \ opencryptoki.map.sym opencryptoki_tok.map.sym FAQ LICENSE SHLIBEXT=a LNFLAG=fs KILLALL = ./kill-all else EXTRA_DIST = bootstrap.sh opencryptoki.map opencryptoki_tok.map FAQ LICENSE SHLIBEXT=so LNFLAG=nfs KILLALL = killall endif 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 include tools/tools.mk include doc/doc.mk install-data-hook: if AIX lsgroup $(pkcs_group) > /dev/null || $(GROUPADD) -a pkcs11 lsuser $(pkcsslotd_user) > /dev/null || $(USERADD) -g $(pkcs_group) -d $(DESTDIR)$(RUN_PATH)/opencryptoki -c "Opencryptoki pkcsslotd user" $(pkcsslotd_user) else getent group $(pkcs_group) > /dev/null || $(GROUPADD) -r $(pkcs_group) getent passwd $(pkcsslotd_user) >/dev/null || $(USERADD) -r -g $(pkcs_group) -d $(RUN_PATH)/opencryptoki -s /sbin/nologin -c "Opencryptoki pkcsslotd user" $(pkcsslotd_user) endif $(MKDIR_P) $(DESTDIR)$(RUN_PATH)/opencryptoki/ $(CHOWN) $(pkcsslotd_user):$(pkcs_group) $(DESTDIR)$(RUN_PATH)/opencryptoki/ $(CHGRP) $(pkcs_group) $(DESTDIR)$(RUN_PATH)/opencryptoki/ $(CHMOD) 0710 $(DESTDIR)$(RUN_PATH)/opencryptoki/ $(MKDIR_P) $(DESTDIR)$(localstatedir)/lib/opencryptoki $(CHGRP) $(pkcs_group) $(DESTDIR)$(localstatedir)/lib/opencryptoki $(CHMOD) 0770 $(DESTDIR)$(localstatedir)/lib/opencryptoki if ENABLE_LIBRARY $(MKDIR_P) $(DESTDIR)$(libdir)/opencryptoki/stdll $(MKDIR_P) $(DESTDIR)$(libdir)/pkcs11 cd $(DESTDIR)$(libdir)/opencryptoki && \ ln -fs libopencryptoki.$(SHLIBEXT) PKCS11_API.$(SHLIBEXT) cd $(DESTDIR)$(libdir)/opencryptoki && \ ln -$(LNFLAG) $(sbindir) methods cd $(DESTDIR)$(libdir)/pkcs11 && \ ln -$(LNFLAG) $(sbindir) methods cd $(DESTDIR)$(libdir)/pkcs11 && \ ln -fs ../opencryptoki/libopencryptoki.$(SHLIBEXT) PKCS11_API.$(SHLIBEXT) cd $(DESTDIR)$(libdir)/pkcs11 && \ ln -fs ../opencryptoki/libopencryptoki.$(SHLIBEXT) libopencryptoki.$(SHLIBEXT) cd $(DESTDIR)$(libdir)/pkcs11 && \ ln -$(LNFLAG) ../opencryptoki/stdll/ stdll endif if ENABLE_PKCSHSM_MK_CHANGE $(MKDIR_P) $(DESTDIR)$(localstatedir)/lib/opencryptoki/HSM_MK_CHANGE $(CHGRP) $(pkcs_group) $(DESTDIR)$(localstatedir)/lib/opencryptoki/HSM_MK_CHANGE $(CHMOD) 0770 $(DESTDIR)$(localstatedir)/lib/opencryptoki/HSM_MK_CHANGE endif if ENABLE_CCATOK cd $(DESTDIR)$(libdir)/opencryptoki/stdll && \ ln -fs libpkcs11_cca.$(SHLIBEXT) PKCS11_CCA.$(SHLIBEXT) $(MKDIR_P) $(DESTDIR)$(localstatedir)/lib/opencryptoki/ccatok/TOK_OBJ $(CHGRP) $(pkcs_group) $(DESTDIR)$(localstatedir)/lib/opencryptoki/ccatok/TOK_OBJ $(CHGRP) $(pkcs_group) $(DESTDIR)$(localstatedir)/lib/opencryptoki/ccatok $(CHMOD) 0770 $(DESTDIR)$(localstatedir)/lib/opencryptoki/ccatok/TOK_OBJ $(CHMOD) 0770 $(DESTDIR)$(localstatedir)/lib/opencryptoki/ccatok $(MKDIR_P) $(DESTDIR)$(lockdir)/ccatok $(CHGRP) $(pkcs_group) $(DESTDIR)$(lockdir)/ccatok $(CHMOD) 0770 $(DESTDIR)$(lockdir)/ccatok test -f $(DESTDIR)$(sysconfdir)/opencryptoki || $(MKDIR_P) $(DESTDIR)$(sysconfdir)/opencryptoki || true test -f $(DESTDIR)$(sysconfdir)/opencryptoki/ccatok.conf || $(INSTALL) -m 644 $(srcdir)/usr/lib/cca_stdll/ccatok.conf $(DESTDIR)$(sysconfdir)/opencryptoki/ccatok.conf || true endif if ENABLE_EP11TOK cd $(DESTDIR)$(libdir)/opencryptoki/stdll && \ ln -fs libpkcs11_ep11.$(SHLIBEXT) PKCS11_EP11.$(SHLIBEXT) $(MKDIR_P) $(DESTDIR)$(localstatedir)/lib/opencryptoki/ep11tok/TOK_OBJ $(CHGRP) $(pkcs_group) $(DESTDIR)$(localstatedir)/lib/opencryptoki/ep11tok/TOK_OBJ $(CHGRP) $(pkcs_group) $(DESTDIR)$(localstatedir)/lib/opencryptoki/ep11tok $(CHMOD) 0770 $(DESTDIR)$(localstatedir)/lib/opencryptoki/ep11tok/TOK_OBJ $(CHMOD) 0770 $(DESTDIR)$(localstatedir)/lib/opencryptoki/ep11tok $(MKDIR_P) $(DESTDIR)$(lockdir)/ep11tok $(CHGRP) $(pkcs_group) $(DESTDIR)$(lockdir)/ep11tok $(CHMOD) 0770 $(DESTDIR)$(lockdir)/ep11tok test -f $(DESTDIR)$(sysconfdir)/opencryptoki || $(MKDIR_P) $(DESTDIR)$(sysconfdir)/opencryptoki || true test -f $(DESTDIR)$(sysconfdir)/opencryptoki/ep11tok.conf || $(INSTALL) -m 644 $(srcdir)/usr/lib/ep11_stdll/ep11tok.conf $(DESTDIR)$(sysconfdir)/opencryptoki/ep11tok.conf || true 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_P11SAK test -f $(DESTDIR)$(sysconfdir)/opencryptoki || $(MKDIR_P) $(DESTDIR)$(sysconfdir)/opencryptoki || true test -f $(DESTDIR)$(sysconfdir)/opencryptoki/p11sak_defined_attrs.conf || $(INSTALL) -g $(pkcs_group) -m 0640 $(srcdir)/usr/sbin/p11sak/p11sak_defined_attrs.conf $(DESTDIR)$(sysconfdir)/opencryptoki/p11sak_defined_attrs.conf || true endif if ENABLE_P11KMIP test -f $(DESTDIR)$(sysconfdir)/opencryptoki || $(MKDIR_P) $(DESTDIR)$(sysconfdir)/opencryptoki || true test -f $(DESTDIR)$(sysconfdir)/opencryptoki/p11kmip.conf || $(INSTALL) -g $(pkcs_group) -m 0640 $(srcdir)/usr/sbin/p11kmip/p11kmip.conf $(DESTDIR)$(sysconfdir)/opencryptoki/p11kmip.conf || true endif if ENABLE_ICATOK cd $(DESTDIR)$(libdir)/opencryptoki/stdll && \ ln -fs libpkcs11_ica.$(SHLIBEXT) PKCS11_ICA.$(SHLIBEXT) $(MKDIR_P) $(DESTDIR)$(localstatedir)/lib/opencryptoki/lite/TOK_OBJ $(CHGRP) $(pkcs_group) $(DESTDIR)$(localstatedir)/lib/opencryptoki/lite/TOK_OBJ $(CHGRP) $(pkcs_group) $(DESTDIR)$(localstatedir)/lib/opencryptoki/lite $(CHMOD) 0770 $(DESTDIR)$(localstatedir)/lib/opencryptoki/lite/TOK_OBJ $(CHMOD) 0770 $(DESTDIR)$(localstatedir)/lib/opencryptoki/lite $(MKDIR_P) $(DESTDIR)$(lockdir)/lite $(CHGRP) $(pkcs_group) $(DESTDIR)$(lockdir)/lite $(CHMOD) 0770 $(DESTDIR)$(lockdir)/lite endif if ENABLE_SWTOK cd $(DESTDIR)$(libdir)/opencryptoki/stdll && \ ln -fs libpkcs11_sw.$(SHLIBEXT) PKCS11_SW.$(SHLIBEXT) $(MKDIR_P) $(DESTDIR)$(localstatedir)/lib/opencryptoki/swtok/TOK_OBJ $(CHGRP) $(pkcs_group) $(DESTDIR)$(localstatedir)/lib/opencryptoki/swtok/TOK_OBJ $(CHGRP) $(pkcs_group) $(DESTDIR)$(localstatedir)/lib/opencryptoki/swtok $(CHMOD) 0770 $(DESTDIR)$(localstatedir)/lib/opencryptoki/swtok/TOK_OBJ $(CHMOD) 0770 $(DESTDIR)$(localstatedir)/lib/opencryptoki/swtok $(MKDIR_P) $(DESTDIR)$(lockdir)/swtok $(CHGRP) $(pkcs_group) $(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.$(SHLIBEXT) PKCS11_TPM.$(SHLIBEXT) $(MKDIR_P) $(DESTDIR)$(localstatedir)/lib/opencryptoki/tpm $(CHGRP) $(pkcs_group) $(DESTDIR)$(localstatedir)/lib/opencryptoki/tpm $(CHMOD) 0770 $(DESTDIR)$(localstatedir)/lib/opencryptoki/tpm $(MKDIR_P) $(DESTDIR)$(lockdir)/tpm $(CHGRP) $(pkcs_group) $(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.$(SHLIBEXT) PKCS11_ICSF.$(SHLIBEXT) $(MKDIR_P) $(DESTDIR)$(localstatedir)/lib/opencryptoki/icsf $(CHGRP) $(pkcs_group) $(DESTDIR)$(localstatedir)/lib/opencryptoki/icsf $(CHMOD) 0770 $(DESTDIR)$(localstatedir)/lib/opencryptoki/icsf $(MKDIR_P) $(DESTDIR)$(lockdir)/icsf $(CHGRP) $(pkcs_group) $(DESTDIR)$(lockdir)/icsf $(CHMOD) 0770 $(DESTDIR)$(lockdir)/icsf endif if ENABLE_DAEMON test -f $(DESTDIR)$(sysconfdir)/opencryptoki || $(MKDIR_P) $(DESTDIR)$(sysconfdir)/opencryptoki || true test -f $(DESTDIR)$(sysconfdir)/opencryptoki/opencryptoki.conf || $(INSTALL) -m 644 $(srcdir)/usr/sbin/pkcsslotd/opencryptoki.conf $(DESTDIR)$(sysconfdir)/opencryptoki/opencryptoki.conf || true test -f $(DESTDIR)$(sysconfdir)/opencryptoki/strength.conf || $(INSTALL) -m 640 -o root -g $(pkcs_group) -T $(srcdir)/doc/strength-example.conf $(DESTDIR)$(sysconfdir)/opencryptoki/strength.conf || true endif if !AIX $(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 "--------------------------------------------------------------" endif $(MKDIR_P) $(DESTDIR)$(lockdir) $(DESTDIR)$(logdir) $(CHGRP) $(pkcs_group) $(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.$(SHLIBEXT) && \ rm -f methods; fi if test -d $(DESTDIR)$(libdir)/pkcs11; then \ cd $(DESTDIR)$(libdir)/pkcs11 && \ rm -f methods && \ rm -f PKCS11_API.$(SHLIBEXT) && \ rm -f libopencryptoki.$(SHLIBEXT) && \ 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.$(SHLIBEXT); fi rm -f $(DESTDIR)$(sysconfdir)/opencryptoki/ccatok.conf endif if ENABLE_EP11TOK if test -d $(DESTDIR)$(libdir)/opencryptoki/stdll; then \ cd $(DESTDIR)$(libdir)/opencryptoki/stdll && \ rm -f PKCS11_EP11.$(SHLIBEXT); fi rm -f $(DESTDIR)$(sysconfdir)/opencryptoki/ep11tok.conf rm -f $(DESTDIR)$(sysconfdir)/opencryptoki/ep11cpfilter.conf endif if ENABLE_ICATOK if test -d $(DESTDIR)$(libdir)/opencryptoki/stdll; then \ cd $(DESTDIR)$(libdir)/opencryptoki/stdll && \ rm -f PKCS11_ICA.$(SHLIBEXT); fi endif if ENABLE_SWTOK if test -d $(DESTDIR)$(libdir)/opencryptoki/stdll; then \ cd $(DESTDIR)$(libdir)/opencryptoki/stdll && \ rm -f PKCS11_SW.$(SHLIBEXT); fi endif if ENABLE_TPMTOK if test -d $(DESTDIR)$(libdir)/opencryptoki/stdll; then \ cd $(DESTDIR)$(libdir)/opencryptoki/stdll && \ rm -rf PKCS11_TPM.$(SHLIBEXT); fi endif if !AIX rm -f $(DESTDIR)/etc/ld.so.conf.d/opencryptoki-$(target_cpu).conf endif if ENABLE_ICSFTOK if test -d $(DESTDIR)$(libdir)/opencryptoki/stdll; then \ cd $(DESTDIR)$(libdir)/opencryptoki/stdll && \ rm -rf PKCS11_ICSF.$(SHLIBEXT); 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 if ENABLE_P11SAK rm -f $(DESTDIR)$(sysconfdir)/opencryptoki/p11sak_defined_attrs.conf || true endif if ENABLE_P11KMIP rm -f $(DESTDIR)$(sysconfdir)/opencryptoki/p11kmip.conf || true endif rm -f $(DESTDIR)$(sysconfdir)/opencryptoki/opencryptoki.conf || true rm -f $(DESTDIR)$(sysconfdir)/opencryptoki/strength.conf || true if ENABLE_TESTCASES PKCS11_SO_PIN ?= 76543210 PKCS11_USER_PIN ?= 01234567 PKCS11_VHSM_PIN ?= 1234567890 if AIX PKCSLIB = '@libdir@/opencryptoki/libopencryptoki.a(libopencryptoki.so.0)' else PKCSLIB ?= @libdir@/opencryptoki/libopencryptoki.so endif ci-prepare: $(KILLALL) -HUP pkcsslotd || true ${srcdir}/testcases/ciconfig.sh "$(sysconfdir)/opencryptoki" "$(sysconfdir)/opencryptoki" "$(sysconfdir)/opencryptoki" "${srcdir}/testcases/test_combined_extract.slots" @sbindir@/pkcsslotd @sbindir@/pkcsstats --reset-all for slot in `awk '/^slot (.*)/ { print $$2; }' $(sysconfdir)/opencryptoki/opencryptoki.conf`; do @sbindir@/pkcsconf -c $$slot -t | grep "Flags:" | grep -q TOKEN_INITIALIZED || PKCS11_USER_PIN=$(PKCS11_USER_PIN) PKCS11_SO_PIN=$(PKCS11_SO_PIN) PKCSLIB=$(PKCSLIB) ${srcdir}/testcases/init_token.sh $$slot || exit; done # cd ${srcdir}/testcases && PKCS11_USER_PIN=$(PKCS11_USER_PIN) PKCS11_VHSM_PIN=$(PKCS11_VHSM_PIN) PKCSLIB=$(PKCSLIB) ./init_vhsm.exp 42 # echo "VHSM_MODE" >> "$(sysconfdir)/opencryptoki/ep11tok42.conf" installcheck-local: all check $(KILLALL) -HUP pkcsslotd || true @sbindir@/pkcsslotd if test ! -z ${PKCS11_TEST_USER}; then \ chmod 777 ${srcdir}/testcases && \ cd ${srcdir}/testcases && \ su ${PKCS11_TEST_USER} -s /bin/bash -c "PKCS11_SO_PIN=$(PKCS11_SO_PIN) PKCS11_USER_PIN=$(PKCS11_USER_PIN) PKCSLIB=$(PKCSLIB) /bin/bash ./ock_tests.sh || true"; \ else \ cd ${srcdir}/testcases && \ PKCS11_SO_PIN=$(PKCS11_SO_PIN) PKCS11_USER_PIN=$(PKCS11_USER_PIN) PKCSLIB=$(PKCSLIB) ./ock_tests.sh || true; \ fi $(KILLALL) -HUP pkcsslotd ci-installcheck: ci-prepare installcheck $(KILLALL) -HUP pkcsslotd || true @sbindir@/pkcsslotd cd ${srcdir}/testcases \ && export PKCSLIB=$(PKCSLIB) \ && export PKCS11_USER_PIN=$(PKCS11_USER_PIN) \ && export PKCS11_SO_PIN=$(PKCS11_SO_PIN) \ && SBINDIR=@sbindir@ ./misc_tests/p11sak_test.sh | tee log-p11sak.txt \ && SBINDIR=@sbindir@ ./misc_tests/pkcsconf_test.sh | tee log-pkcsconf.txt if [[ -n "${KMIP_IP}" ]] && [[ -n "${KMIP_REST_USER}" ]] && [[ -n "${KMIP_REST_PASSWORD}" ]]; then \ cd ${srcdir}/testcases \ && export PKCSLIB=$(PKCSLIB) \ && export PKCS11_USER_PIN=$(PKCS11_USER_PIN) \ && export PKCS11_SO_PIN=$(PKCS11_SO_PIN) \ && SBINDIR=@sbindir@ ./misc_tests/p11kmip_test.sh | tee log-p11kmip.txt;\ fi @sbindir@/pkcsstats --all $(KILLALL) -HUP pkcsslotd rm ${srcdir}/testcases/test_combined_extract.slots -f @echo "done" ci-cleanup: @sbindir@/pkcsstats --delete-all || true $(KILLALL) -HUP pkcsslotd || true # @sbindir@/pkcsslotd # cd ${srcdir}/testcases && PKCS11_USER_PIN=$(PKCS11_USER_PIN) PKCSLIB=$(PKCLSIB) ./cleanup_vhsm.exp 42 # $(KILLALL) -HUP pkcsslotd rm ${srcdir}/testcases/test_combined_extract.slots -f ci-uninstall: uninstall rm -f $(sysconfdir)/opencryptoki/ep11tok*.conf rm -rf $(localstatedir)/lib/opencryptoki/* rm -rf $(lockdir)/* rm -rf $(logdir)/* .PHONY: ci-prepare ci-installcheck ci-uninstall endif opencryptoki-opencryptoki-451d99c/README.md000066400000000000000000000303221520105705100206030ustar00rootroot00000000000000[![Build Status](https://app.travis-ci.com/opencryptoki/opencryptoki.svg?branch=master)](https://app.travis-ci.com/opencryptoki/opencryptoki) [![Coverity Scan Build Status](https://img.shields.io/coverity/scan/16802.svg?branch=master)](https://scan.coverity.com/projects/opencryptoki-opencryptoki) # openCryptoki Package version 3.27 Please see [ChangeLog](ChangeLog) for release specific information. ## OVERVIEW openCryptoki version 3.27 implements the PKCS#11 specification version 3.0 and partially versions 3.1 and 3.2. This package includes several cryptographic tokens: CCA, ICA, TPM, SWToken, ICSF and EP11. For a more in-depth overview of openCryptoki, please refer to manual [openCryptoki - An Open Source Implementation of PKCS #11](https://www.ibm.com/docs/en/linux-on-systems?topic=support-opencryptoki-open-source-pkcs-11) **Note:** The TPM token is deprecated, because it supports only TPM version 1.2. Does not work with TPM version 2.0. We plan to remove the TPM token in a future openCryptoki release or version. AIX only supports the CCA and software tokens, and both are enabled in a default build configuration. Other tokens are unsupported and cannot be force-enabled, even through the `configure` utility. ## REQUIREMENTS ### Common Building opencryptoki needs the following utilities. - flex - bison - make - autoconf - automake - pkg-config - libtool - m4 - openldap-devel - openssl-devel - libcap-devel (Linux-only) - systemd-devel (Linux-only) These libraries are usually provided by your platform's package management utilities. On AIX, they must be installed from the AIX Toolbox repositories. ### Tokens - IBM ICA - requires libica library version 3.3.0 or higher for accessing ICA hardware crypto on IBM zSeries. - IBM CCA - requires the CCA host library with version 7.1 or higher, and IBM Crypto CEX3C card (or higher) on Linux for IBM Z. On AIX, Linux on x64, and Linux on Power only the IBM CEX7S (4769) crypto card is supported. On all platforms, this token needs the `lber` library, which is usually part of the `openldap` package. - TPM (**deprecated**) - requires a TPM, TPM tools, and TCG software stack. Supports TPM version 1.2 only. - SWToken - The software token uses OpenSSL version 1.1.1 or higher. This token needs the `lber` library, which is usually part of openldap. - 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 **Note:** Building opencryptoki on AIX is only supported on AIX 7.2 and above. Attempts to build on older AIX releases will fail due to missing APIs. 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: ```bash $ ./bootstrap.sh ``` **Note:** This package used the `AX_PROG_CC_FOR_BUILD` autoconf macro from the autoconf archive to support cross compiler builds. If your system does not provide this macro, you might need to install the `autoconf-archive` package or download the macro and place it into the `m4` directory. See [here](https://www.gnu.org/software/autoconf-archive/ax_prog_cc_for_build.html) for a link to the latest version of `ax_prog_cc_for_build.m4`. 2. Configure the source code by typing: ```bash $ ./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: ```bash $ ./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. **Note:** When compiling on AIX, `CFLAGS` and `LDFLAGS` must be set to the correct paths where it can find openldap libraries and header files correctly. If using the `openldap-devel` package from the [AIX Toolbox](https://www.ibm.com/support/pages/aix-toolbox-open-source-software-downloads-alpha#O), then `CFLAGS` and `LDFLAGS` must be set to `-I/opt/freeware/include` and `-L/opt/freeware/lib`, respectively, before or with the `./configure` invocation. For instance, ```bash $ CPPFLAGS="-L/path/lib" LDFLAGS="-I/path/include" ./configure ``` See `./configure --help` for info on various options. The default behavior is to build all tokens that have their prerequisites met. The ICA and EP11 tokens can only be built on s390x, since that is the only platform that fulfils the prerequisites. On AIX, only the CCA and software tokens can be built. Other tokens may be enabled using the corresponding `--enable-` configuration option, provided the appropriate libraries are available and the token is supported on the platform you are compiling. While running, `configure` prints some messages telling which features is it checking for. **Note**: On AIX, if you wish to run `make distcheck`, the environment variable `DISTCHECK_CONFIGURE_FLAGS` to include the appropriate values for `CFLAGS` and `CXXFLAGS` 3. Compile the package by typing: ```bash $ make ``` **Note:** Do not specify `prefix=/foo/bar`, `libdir=/foo/bar` with the `make` invocation. Specify them with `configure` instead. Specifying them with `make` is not supported by the openCryptoki package and may produce unexpected results! 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: ```bash # groupadd pkcs11 ``` In addition, add the necessary user to the pkcs11 group (root doesn't need to be in pkcs11 group): ```bash # usermod -a -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: ```text ${prefix}/sbin/p11kmip ${prefix}/sbin/p11sak ${prefix}/sbin/pkcscca ${prefix}/sbin/pkcsconf ${prefix}/sbin/pkcsep11_migrate ${prefix}/sbin/pkcsep11_session ${prefix}/sbin/pkcshsm_mk_change ${prefix}/sbin/pkcsicsf ${prefix}/sbin/pkcsslotd ${prefix}/sbin/pkcsstats ${prefix}/sbin/pkcstok_admin ${prefix}/sbin/pkcstok_migrate ${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 ${prefix}/etc/opencryptoki/ccatok.conf ${prefix}/etc/opencryptoki/ep11cpfilter.conf ${prefix}/etc/opencryptoki/ep11tok.conf ${prefix}/etc/opencryptoki/p11kmip.conf ${prefix}/etc/opencryptoki/p11sak_defined_attrs.conf ${prefix}/etc/opencryptoki/strength.conf ${prefix}/share/doc/opencryptoki/policy-example.conf ${prefix}/share/doc/opencryptoki/strength-example.conf ``` Token libraries, which may be optionally built, go to the following locations: ```text ${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): ```text ${prefix}/${libdir}/opencryptoki/PKCS11_API.so - Symlink to ${prefix}/${libdir}/opencryptoki/libopencryptoki.so ${prefix}/${libdir}/opencryptoki/stdll/PKCS11_CCA.so - Symlink to ${prefix}/${libdir}/opencryptoki/stdll/libpkcs11_cca.so ${prefix}/${libdir}/opencryptoki/stdll/PKCS11_EP11.so - Symlink to ${prefix}/${libdir}/opencryptoki/stdll/libpkcs11_ep11.so ${prefix}/${libdir}/opencryptoki/stdll/PKCS11_ICA.so - Symlink to ${prefix}/${libdir}/opencryptoki/stdll/libpkcs11_ica.so ${prefix}/${libdir}/opencryptoki/stdll/PKCS11_ICSF.so - Symlink to ${prefix}/${libdir}/opencryptoki/stdll/libpkcs11_icsf.so ${prefix}/${libdir}/opencryptoki/stdll/PKCS11_SW.so - Symlink to ${prefix}/${libdir}/opencryptoki/stdll/libpkcs11_sw.so ${prefix}/${libdir}/pkcs11/PKCS11_API.so - Symlink to ${prefix}/${libdir}/opencryptoki/libopencryptoki.so ${prefix}/${libdir}/pkcs11 - Directory created if non-existent ${prefix}/${libdir}/pkcs11/methods - Symlink to ${prefix}/sbin ${prefix}/${libdir}/pkcs11/stdll - Symlink to ${prefix}/${libdir}/opencryptoki/stdll ``` 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: ```bash PATH="/home/luser/bin:${PATH}" export PATH ``` If you are using csh or tcsh, then use this line instead: ```bash 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 [Preparing openCryptoki](https://www.ibm.com/docs/en/linux-on-systems?topic=325-preparing-opencryptoki). 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`: ```bash $ 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: ```bash $ pkcsconf -P -c ``` You can initialize and change the user PIN by typing: ```bash $ pkcsconf -u -c ``` You can later change the user PIN again by typing: ```bash $ pkcsconf -p -c ``` ## CONTRIBUTING See [CONTRIBUTING.md](CONTRIBUTING.md). opencryptoki-opencryptoki-451d99c/bootstrap.sh000077500000000000000000000006661520105705100217100ustar00rootroot00000000000000#!/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 opencryptoki-opencryptoki-451d99c/cleanup.sh000077500000000000000000000006521520105705100213150ustar00rootroot00000000000000#!/bin/sh # # COPYRIGHT (c) International Business Machines Corp. 2001-2022 # # This program is provided under the terms of the Common Public License, # version 1.0 (CPL-1.0). Any use, reproduction or distribution for this 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 # test -f Makefile && make maintainer-clean opencryptoki-opencryptoki-451d99c/configure.ac000066400000000000000000000655561520105705100216330ustar00rootroot00000000000000dnl Process this file with autoconf to produce a configure script. AC_PREREQ([2.69]) AC_INIT([openCryptoki],[3.27.0],[https://github.com/opencryptoki/opencryptoki/issues],[],[https://github.com/opencryptoki/opencryptoki]) AC_CONFIG_SRCDIR([testcases/common/common.c]) dnl Needed for $target! AC_CANONICAL_TARGET AC_CANONICAL_HOST AM_INIT_AUTOMAKE([-Wall -Wno-override -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 \ 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_MKTIME AC_FUNC_MMAP 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], [mkgroup], [/usr/sbin/groupadd]) AC_PATH_PROG([USERADD], [useradd], [/usr/sbin/useradd]) AC_PATH_PROG([CAT], [cat], [/bin/cat]) AC_PATH_PROG([CHMOD], [chmod], [/bin/chmod]) AC_PATH_PROG([CHGRP], [chgrp], [/bin/chgrp]) AC_PATH_PROG([CHOWN], [chown], [/bin/chown]) AC_PROG_AWK AC_PROG_INSTALL AC_PROG_LN_S 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_CHECK_PROG([YACC], [bison], [bison], [no]) if test "x$YACC" = "xno"; then AC_MSG_ERROR(['bison' program is missing on your system. Please install 'bison'.]) fi AM_CONDITIONAL([CROSS], [test "x$cross_compiling" = xyes]) 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 --- sanitizer support AC_ARG_ENABLE([sanitizer], AS_HELP_STRING([--enable-sanitizer],[enable sanitizer build (may not work in all environments) @<:@default=no@:>@]), [], [enable_sanitizer=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 libica development files are 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 token is enabled@:>@]), [], [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 token is enabled@:>@]), [], [enable_pkcsep11_session=check]) dnl --- locking support AC_ARG_ENABLE([locks], AS_HELP_STRING([--disable-locks],[This option is no longer supported, ignored if specified.])) dnl --- p11sak tool AC_ARG_ENABLE([p11sak], AS_HELP_STRING([--enable-p11sak],[build p11sak tool @<:@default=enabled@:>@]), [], [enable_p11sak=yes]) dnl --- p11kmip tool AC_ARG_ENABLE([p11kmip], AS_HELP_STRING([--enable-p11kmip],[build p11kmip tool @<:@default=no@:>@]), [], [enable_p11kmip=yes]) dnl --- pkcstok_migrate AC_ARG_ENABLE([pkcstok_migrate], AS_HELP_STRING([--enable-pkcstok_migrate],[build pkcstok_migrate tool @<:@default=enabled@:>@]), [], [enable_pkcstok_migrate=yes]) dnl --- pkcsstats AC_ARG_ENABLE([pkcsstats], AS_HELP_STRING([--enable-pkcsstats],[build pkcsstats tool @<:@default=enabled@:>@]), [], [enable_pkcsstats=yes]) dnl --- pkcscca AC_ARG_ENABLE([pkcscca], AS_HELP_STRING([--enable-pkcscca],[build pkcscca tool @<:@default=enabled@:>@ on non-AIX platforms]), [], [enable_pkcscca=yes]) dnl --- support for MD2 AC_ARG_ENABLE([md2], AS_HELP_STRING([--enable-md2],[build opencryptoki with support for MD2])) dnl --- pkcshsm_mk_change AC_ARG_ENABLE([pkcshsm_mk_change], AS_HELP_STRING([--enable-pkcshsm_mk_change],[build pkcshsm_mk_change tool @<:@default=enabled@:>@]), [], [enable_pkcshsm_mk_change=yes]) dnl --- pkcstok_admin AC_ARG_ENABLE([pkcstok_admin], AS_HELP_STRING([--enable-pkcstok_admin],[build pkcstok_admin tool @<:@default=enabled@:>@]), [], [enable_pkcstok_admin=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 --- TSS (TrouSerS) development files AC_ARG_WITH([tss], AS_HELP_STRING([--with-tss@<:@=DIR@:>@],[TrouSerS development files location]), [], [with_tss=check]) dnl --- systemd system unit files location AC_ARG_WITH([systemd], AS_HELP_STRING([--with-systemd@<:@=DIR@:>@], [Build a systemd service unit file for pkcsslotd (default yes), and optionally specify the systemd system unit files location. Specify '--without-systemd' to build an init-d script instead]), [], [with_systemd=yes]) dnl --- libudev development files AC_ARG_WITH([libudev], AS_HELP_STRING([--with-libudev@<:@=DIR@:>@],[libudev development files location]), [], [with_libudev=check]) dnl --- pkcsslotd user AC_ARG_WITH([pkcsslotd-user], AS_HELP_STRING([--with-pkcsslotd-user=USER],[set the user under which pkcsslotd runs (default: pkcsslotd)]), [pkcsslotd_user=$withval], [pkcsslotd_user=pkcsslotd]) dnl --- pkcs group AC_ARG_WITH([pkcs-group], AS_HELP_STRING([--with-pkcs-group=GROUP],[set the group that all openCryptoki applications must belong to (default: pkcs11)]), [pkcs_group=$withval], [pkcs_group=pkcs11]) dnl --- max-token-objects AC_ARG_WITH([max-token-objects], AS_HELP_STRING([--with-max-token-objects=NUMBER],[set the maximum number of token objects that are supported (default: 2048). Opencryptioki supports up to that number of public token objects (CKA_PRIVATE=FALSE) plus up to that number of private token objects (CKA_PRIVATE=TRUE).]), [max_token_objects=$withval], [max_token_objects=2048]) dnl --- dnl --- dnl --- Now that we have all the options, let's check for a valid build dnl --- dnl --- enable_pkey enable_pkey=no case $target in *s390x*) enable_pkey=yes ;; *s390*) CFLAGS="$CFLAGS -m31" AC_DEFINE([NO_PKEY]) ;; *ppc64* | *x86_64*) AC_DEFINE([NO_PKEY]) ;; *ppc* | i*86*) CFLAGS="$CFLAGS -m32" AC_DEFINE([NO_PKEY]) ;; *) AC_DEFINE([NO_PKEY]) ;; esac AM_CONDITIONAL([NO_PKEY], [test "x$enable_pkey" != "xyes"]) dnl Check and save whether the platform is AIX dnl Using the pthread library requires the _THREAD_SAFE macro to be set build_aix=no case "${host_os}" in aix*) build_aix=yes AC_DEFINE([_ALL_SOURCE]) AC_DEFINE([_THREAD_SAFE]) with_systemd=no with_libica=no enable_ccatok=yes enable_swtok=yes enable_tpmtok=no enable_icsftok=no enable_ep11tok=no echo "Disabling migration utilities on AIX: pkcscca pkcstok_migrate" enable_pkcscca=no enable_pkcstok_migrate=no echo "Disabling the following unsupported features on AIX: systemd libica tpmtok icsftok ep11tok" pkcsslotd_user=slotd echo "Shortening username to $pkcsslotd_user due to platform restrictions" function parse_map { grep -E '^[ ]+' $1 | tr -d ';' | tr -d ' ' > "$1".sym } parse_map opencryptoki.map parse_map opencryptoki_tok.map ;; esac dnl Define custom variables lockdir=${localstatedir}/lock/opencryptoki logdir=${localstatedir}/log/opencryptoki dnl runstatedir is only defined starting from autoconf 2.70 dnl this script has a prereq of 2.69, so instead build it from localstatedir if test "x$build_aix" = "xyes"; then run_path=${localstatedir}/run else run_path=/run fi AC_SUBST([lockdir]) AC_SUBST([logdir]) AC_SUBST(RUN_PATH, [$run_path]) AM_CONDITIONAL([AIX], [test "x$build_aix" = "xyes" ]) dnl define _GNU_SOURCE on non-AIX platforms if test "x$build_aix" = "xno"; then AC_DEFINE([_GNU_SOURCE]) fi dnl --- enable_debug if test "x$enable_debug" = "xyes"; then if test "x$build_aix" = "xyes"; then CFLAGS="$CFLAGS -g3 -O0" else CFLAGS="$CFLAGS -gdwarf-2 -g3 -O0" fi AC_DEFINE([DEBUG]) else CFLAGS="$CFLAGS -O2 -g3" fi dnl --- enable_sanitizer if test "x$enable_sanitizer" = "xyes"; then AC_CHECK_LIB([asan], [strcpy], [LDFLAGS="-lasan $LDFLAGS"], [AC_MSG_ERROR(['libasan' library is missing on your system. Please install 'libasan'.])]) AC_CHECK_LIB([ubsan], [strcpy], [LDFLAGS="-lubsan $LDFLAGS"], [AC_MSG_ERROR(['libubsan' library is missing on your system. Please install 'libubsan'.])]) if test "x$enable_debug" = "xyes"; then CFLAGS="$CFLAGS -O2 -g3 -DDEBUG" fi CFLAGS="$CFLAGS -fstack-protector-all -fsanitize=address,signed-integer-overflow,undefined -Wformat -Wformat-security -Werror=format-security -Warray-bounds -Werror=array-bounds -D_FORTIFY_SOURCE=2" AC_DEFINE([WITH_SANITIZER]) fi if test "x$build_aix" = "xno"; then LIBCAP_LIBS= AC_CHECK_LIB([cap], [cap_get_proc], [LIBCAP_LIBS="-lcap"], [AC_MSG_ERROR(['libcap' library is missing on your system. Please install 'libcap-devel'.])]) AC_SUBST([LIBCAP_LIBS]) fi dnl --- cca and soft tokens need lber, icsf needs only ldap 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'.])]) AC_SUBST([OPENLDAP_LIBS]) 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/include" OPENSSL_LIBS="-L$with_openssl" fi old_cflags="$CFLAGS" old_libs="$LIBS" CFLAGS="$CFLAGS $OPENSSL_CFLAGS" LIBS="$LIBS $OPENSSL_LIBS" AC_CHECK_HEADER([openssl/evp.h], [], [ AC_MSG_ERROR([OpenSSL 1.1.1 or later is required but OpenSSL headers couldn't be found]) ]) AC_MSG_CHECKING([whether OpenSSL has alternate fix for CVE 2022-4304]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM( [[ #include #if OPENSSL_VERSION_NUMBER < 0x1010115fL #error "< OpenSSl 1.1.1u" #endif #if OPENSSL_VERSION_NUMBER >= 0x30000000L && OPENSSL_VERSION_NUMBER < 0x30000090L #error "< OpenSSl 3.0.9" #endif #if OPENSSL_VERSION_NUMBER >= 0x30100000L && OPENSSL_VERSION_NUMBER < 0x30100010L #error "< OpenSSl 3.1.1" #endif ]],[[int dummy;]])], [have_alt_fix_for_cve_2022_4304=yes CFLAGS="$CFLAGS -DHAVE_ALT_FIX_FOR_CVE2022_4304" AC_MSG_RESULT([yes])], [have_alt_fix_for_cve_2022_4304=no AC_MSG_RESULT([no])]) if test "x$with_openssl" != "xno"; then AC_CHECK_LIB([crypto], [EVP_sha3_256], [ OPENSSL_LIBS="$OPENSSL_LIBS -lcrypto" with_openssl=yes], [ AC_MSG_ERROR([OpenSSL 1.1.1 or later is required but OpenSSL libraries version 1.1.1 or later couldn't be found]) ]) fi if test "x$with_openssl" = "xno"; then CFLAGS="$old_cflags" LIBS="$old_libs" fi fi if test "x$with_openssl" != "xyes"; then AC_MSG_ERROR([OpenSSL 1.1.1 or later is required but build without OpenSSL was requested]) fi AC_SUBST([OPENSSL_CFLAGS]) AC_SUBST([OPENSSL_LIBS]) AM_CONDITIONAL([HAVE_ALT_FIX_FOR_CVE_2022_4304], [test "x$have_alt_fix_for_cve_2022_4304" = "xyes"]) dnl --- with_libica LIBICA_CFLAGS= 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/include" LIBICA_LIBS="-L$with_libica/src/.libs" 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_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_libudev LIBUDEV_CFLAGS= LIBUDEV_LIBS= if test "x$with_libudev" != "xno"; then if test "x$with_libudev" != "xyes" -a "x$with_libudev" != "xcheck"; then LIBUDEV_CFLAGS="-I$with_libudev" LIBUDEV_LIBS="-L$with_libudev" fi old_cflags="$CFLAGS" old_libs="$LIBS" CFLAGS="$CFLAGS $LIBUDEV_CFLAGS" LIBS="$LIBS $LIBUDEV_LIBS" # Use libudev only on s390 platforms, only s390 emits AP related uevents case $target in *s390x* | *s390*) AC_DEFINE([WITH_LIBUDEV]) ;; *) if test "x$with_libudev" != "xyes"; then with_libudev=no echo "Default to 'with_libudev=no' on non-s390 platforms" fi ;; esac if test "x$with_libudev" != "xno"; then AC_CHECK_HEADER([libudev.h], [with_libudev=yes], [ AC_MSG_ERROR([Build with libudev requested but libudev headers couldn't be found]) ]) AC_CHECK_LIB([udev], [udev_monitor_new_from_netlink], [with_libudev=yes], [ AC_MSG_ERROR([Build with libudev requested but libudev libraries couldn't be found]) ]) fi if test "x$with_libudev" = "xno"; then CFLAGS="$old_cflags" LIBS="$old_libs" fi fi AC_SUBST([LIBUDEV_CFLAGS]) AC_SUBST([LIBUDEV_LIBS]) AM_CONDITIONAL([HAVE_LIBUDEV], [test "x$with_libudev" = "xyes"]) 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 require 'expect' interpreter, which wasn't found]) enable_testcases=no fi AC_CHECK_PROG([HAVE_OPENSSL], [openssl], [yes], [no]) if test "x$HAVE_OPENSSL" = "xno"; then AC_MSG_ERROR([*** testcases require 'openssl' command line tool, which wasn't found]) enable_testcases=no fi AC_CHECK_PROG([HAVE_CURL], [curl], [yes], [no]) if test "x$HAVE_CURL" = "xno"; then AC_MSG_ERROR([*** testcases require 'curl' command line tool, which wasn't found]) enable_testcases=no fi AC_CHECK_PROG([HAVE_JQ], [jq], [yes], [no]) if test "x$HAVE_JQ" = "xno"; then AC_MSG_ERROR([*** testcases require 'jq' command line tool, 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 if test "x$enable_ccatok" = "xyes" -a "x$enable_pkey" = "xyes"; then AC_CHECK_HEADER([asm/pkey.h], [], [ AC_MSG_ERROR([cca token build requested but Kernel's pkey header couldn't be found]) ]) fi if test "x$enable_ccatok" != "xno"; then enable_ccatok=yes if test "x$enable_pkey" = "xyes"; then AC_CHECK_HEADER([asm/pkey.h], [], [ enable_ccatok=no ]) fi else enable_ccatok=no fi AM_CONDITIONAL([ENABLE_CCATOK], [test "x$enable_ccatok" = "xyes"]) dnl --- enable_swtok 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 AC_CHECK_HEADER([ica_api.h], [], [ AC_MSG_ERROR([ep11 token build requested but Libica headers couldn't be found]) ]) AC_CHECK_HEADER([asm/pkey.h], [], [ AC_MSG_ERROR([ep11 token build requested but Kernel's pkey header couldn't be found]) ]) fi if test "x$enable_ep11tok" != "xno"; then enable_ep11tok=yes AC_CHECK_HEADER([ica_api.h], [], [ enable_ep11tok=no ]) AC_CHECK_HEADER([asm/pkey.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$enable_ep11tok" != "xyes"; then AC_MSG_ERROR([pkcsep11_migrate build requested but the ep11 token is not enabled]) enable_pkcsep11_migrate=no fi fi if test "x$enable_pkcsep11_migrate" != "xno" -a "x$enable_ep11tok" = "xyes"; 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$enable_ep11tok" != "xyes"; then AC_MSG_ERROR([pkcsep11_session build requested but the ep11 token is not enabled]) enable_pkcsep11_session=no fi fi if test "x$enable_pkcsep11_session" != "xno" -a "x$enable_ep11tok" = "xyes"; 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_p11kmip AM_CONDITIONAL([ENABLE_P11KMIP], [test "x$enable_p11kmip" = "xyes"]) dnl --- enable_pkcstok_migrate AM_CONDITIONAL([ENABLE_PKCSTOK_MIGRATE], [test "x$enable_pkcstok_migrate" = "xyes"]) dnl --- enable_pkcsstats AM_CONDITIONAL([ENABLE_PKCSSTATS], [test "x$enable_pkcsstats" = "xyes"]) dnl --- enable_pkcscca AM_CONDITIONAL([ENABLE_PKCSCCA], [test "x$enable_pkcscca" = "xyes"]) dnl --- enable_pkcshsm_mk_change AM_CONDITIONAL([ENABLE_PKCSHSM_MK_CHANGE], [test "x$enable_pkcshsm_mk_change" = "xyes"]) dnl --- enable_pkcstok_admin AM_CONDITIONAL([ENABLE_PKCSTOK_ADMIN], [test "x$enable_pkcstok_admin" = "xyes"]) dnl --- enable_locks if test "x$enable_locks" = "xno"; then AC_MSG_WARN([The --disable-locks option is no longer supported, it is ignored.]) fi dnl --- enable_md2 if test "x$enable_md2" = "xyes"; then enable_md2=yes else enable_md2=no AC_DEFINE([NOMD2]) fi AM_CONDITIONAL([ENABLE_MD2], [test "x$enable_md2" = "xyes"]) AC_SUBST([pkcsslotd_user]) AC_SUBST([pkcs_group]) AC_DEFINE([PKCS64]) AC_DEFINE([_XOPEN_SOURCE], [600], [POSIX 2004]) AC_PROG_CC([xlc xlc_r gcc clang]) AC_PROG_CC_STDC if test "x$build_aix" = "xyes"; then CFLAGS="$CFLAGS -qinfo=pro:cns:lan:nocmp:nocnv:nogot:notrd -qalign=natural -qarch=pwr7 -qsuppress=1506-1527:1500-029 -qlanglvl=stdc99 -qsrcmsg -lbsd -q64 -qtls" # msg is used to ensure compilers that ignore the error pragma are still caught AC_COMPILE_IFELSE([AC_LANG_PROGRAM( [[#if (__xlC__ >> 8) < 16 #msg "xlc 16.x or newer required" #endif]] )],, [AC_MSG_ERROR([xlc 16.x or newer is required. Please install a newer release of the xlc compiler.])]) else CFLAGS="$CFLAGS -Wall -Wextra" CFLAGS+=" -std=c99 -Werror=implicit-int -Werror=implicit-function-declaration -Werror=int-conversion -Werror=strict-prototypes -Werror=old-style-definition -pedantic" fi AC_DEFINE_UNQUOTED([PKCSSLOTD_USER], "$pkcsslotd_user") AC_DEFINE_UNQUOTED([PKCS_GROUP], "$pkcs_group") AC_DEFINE_UNQUOTED([MAX_TOK_OBJS], $max_token_objects) CFLAGS="$CFLAGS"' -DCONFIG_PATH=\"$(localstatedir)/lib/opencryptoki\" -DSBIN_PATH=\"$(sbindir)\" -DLIB_PATH=\"$(libdir)\" -DRUN_PATH=\"$(RUN_PATH)\" -DLOCKDIR_PATH=\"$(lockdir)\" -DOCK_CONFDIR=\"$(sysconfdir)/opencryptoki\" -DOCK_LOGDIR=\"$(logdir)\"' # At this point, CFLAGS is set to something sensible AX_PROG_CC_FOR_BUILD AC_PROG_CXX([xlC_r xlC g++ clang++]) # AC_PROG_CXX will return "g++" even if no c++ compiler is installed. # Check for that case, and issue an error if so. AC_LANG_PUSH([C++]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM( [[#ifndef __cplusplus #error "broken C++" #endif]])],, [AC_MSG_ERROR([C++ compiler is missing on your system. Please install 'gcc-c++'.])]) AC_LANG_POP([C++]) AC_CONFIG_MACRO_DIRS([m4]) AM_COND_IF([ENABLE_ICSFTOK], [AC_CONFIG_FILES([man/man1/pkcsicsf.1])]) AM_COND_IF([ENABLE_PKCSCCA], [AC_CONFIG_FILES([man/man1/pkcscca.1])]) AM_COND_IF([ENABLE_PKCSHSM_MK_CHANGE], [AC_CONFIG_FILES([man/man1/pkcshsm_mk_change.1])]) AM_COND_IF([ENABLE_PKCSSTATS], [AC_CONFIG_FILES([man/man1/pkcsstats.1])]) AM_COND_IF([ENABLE_P11SAK], [AC_CONFIG_FILES([man/man1/p11sak.1])]) AM_COND_IF([ENABLE_P11KMIP], [AC_CONFIG_FILES([man/man1/p11kmip.1])]) AM_COND_IF([ENABLE_PKCSEP11_MIGRATE], [AC_CONFIG_FILES([man/man1/pkcsep11_migrate.1])]) AM_COND_IF([ENABLE_PKCSEP11_SESSION], [AC_CONFIG_FILES([man/man1/pkcsep11_session.1])]) AM_COND_IF([ENABLE_PKCSTOK_MIGRATE], [AC_CONFIG_FILES([man/man1/pkcstok_migrate.1])]) AC_CONFIG_FILES([Makefile \ misc/opencryptoki.pc \ usr/lib/api/shrd_mem.c \ man/man1/pkcsconf.1 \ man/man5/opencryptoki.conf.5 \ man/man5/p11sak_defined_attrs.conf.5 \ man/man5/strength.conf.5 \ man/man5/policy.conf.5 \ man/man5/p11kmip.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 libudev: $with_libudev" echo " Build p11sak tool: $enable_p11sak" echo " Build p11kmip tool: $enable_p11kmip" echo " token migrate tool: $enable_pkcstok_migrate" echo " token admin tool: $enable_pkcstok_admin" echo " statistics tool: $enable_pkcsstats" echo " HSM MK change tool: $enable_pkcshsm_mk_change" 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 " pkcscca build: $enable_pkcscca" echo echo "pkcsslotd user: $pkcsslotd_user" echo "pkcs group: $pkcs_group" echo "max token objects: $max_token_objects" echo echo "CFLAGS=$CFLAGS" echo "LDFLAGS=$LDFLAGS" echo if test "x$enable_sanitizer" = "xyes"; then echo "Sanitizer is enabled, \"export LSAN_OPTIONS=fast_unwind_on_malloc=false\" may be required to get useful stack traces." fi opencryptoki-opencryptoki-451d99c/doc/000077500000000000000000000000001520105705100200715ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/doc/README.cca_stdll000066400000000000000000000223511520105705100227030ustar00rootroot00000000000000CCA 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. For more details about the CCA token, please also see https://www.ibm.com/docs/en/linux-on-systems?topic=specifications-cca-token Configuration ------------- To use the CCA token a slot entry must be defined in the opencryptoki.conf configuration file that sets the stdll attribute to libpkcs11_cca.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 or AES key, dependent on the tokversion setting in opencryptoki.conf) 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. 7. You may now want to migrate the data stores of the CCA token to a FIPS compliant format using the pkcstok_migrate tool. For details, please see https://www.ibm.com/docs/en/linux-on-systems?topic=tools-pkcstok-migrate 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. opencryptoki-opencryptoki-451d99c/doc/README.devel000066400000000000000000000120741520105705100220530ustar00rootroot00000000000000Policy Update ============= During development of openCryptoki several updates might be needed to the policy code. Places where to update the policy code are marked with the comment POLICY: New followed by a description of what is added. E.g., if you add a new key type, the comment is POLICY: New CKK which marks the places where policy-specific code has to be added for this key type. Similar places exist for adding new mechanisms where the comment is POLICY: New CKM For new mechanisms, the comment is also followed by a distinction of the kind of mechanism. For example, there are places where only digest mechanisms have to be added, or places where mechanisms related to signatures and the corresponding verification have to be added. To make EC curves, MGFs, or KDFs available to the policy code, see the corresponding translation.c file in usr/lib/common (i.e., ec_curve_translation.c, mgf_translation.c, or kdf_translation.c). PRFs are special currently since we only support one PRF so far and gperf then generates a file that compiles with warnings. So we did not use gperf for it, but hard-code the supported PRF string comparison in usr/lib/common/stringtranslations.h. When adding new EC curves, MGFs, KDFs, or PRFs, please also update the code in tools/policyexamplegen.c which will generate the policy example that should contain everything that is supported by OpenCryptoki at this time. The code does not have to be touched if new mechanisms are added. For adding new mechanisms please see the section about the mechanism table. The remaining tools will use the mechanism table and will automatically be aware of the added mechanism. Additionally, some code might be needed in the STDLLs to support policy checking of the specific mechanism if the mechanism creates multiple keys or uses parameters that involve key handles. In the latter case, the STDLL first needs to translate the key handle into an appropriate struct objstrength which can then be passed to the policy code. This became necessary to support different STDLLs that do not use the OBJECT structure from openCryptoki common code. Mechanism Table =============== To have a single source for all mechanisms, we added a mechanism table to OpenCryptoki. The mechanism table itself is kept as a constant structure in the file usr/lib/api/mechtable.inc. You can simply add a new mechanism to this structure. Note, however, that the mechanisms added to this structure have to be unique w.r.t. the numeric representation. This leads to problems if the same mechanism has multiple names and thus multiple string representations. You should put the string representation you want to see in the output into the table. Also note that the order of the table is important. Tools might rely on the index of a specific mechanism to accumulate, e.g., counters. So please be careful when changing the order of rows. The table usage API is defined in usr/lib/api/mechtable.h. This file also includes a generated header that provides the MECHTABLE_NUM_ELEMS macro. This macro specifies the number of rows in the table. This allows users to iterate over the `mechtable_rows`. While iteration is one basic way to process the table, we also generate fast index structures for the string representation and the numeric representation. These indices can be accessed via the `mechtable_idx_from_numeric`, `mechtable_idx_from_string`, `mechrow_from_numeric`, or `mechrow_from_string` functions. These functions internally use jump tables to efficiently search for the corresponding element. To keep the table only in one library, the API library passes a pointer to a constant `struct mechtable_funcs` to every `STDLL_TokData_t`. This structure contains pointers to the above mentioned four functions and allows STDLLs to use the table without including it in the STDLL (and thus without adding the table multiple times to the resident set). The index functions are automatically generated by tools/tableidxgen.c. This file includes usr/lib/api/mechtable.inc and produces a file usr/lib/api/mechtable.c and the header usr/lib/api/mechtable-gen.h. During generation, it also produces the file usr/lib/api/mechtable.log which logs the alphabet mappings and the jump table it uses. For strings, the generator has support for alias via an internal variable `aliases`. Whenever you have to add an alternative string representation for a representation that is already in the table, simply add a structure to the `aliases` array. The member `string` should be the string to add (which should not already be in the table), and the member `alias` should be the string that is already in the table and contains the information for this alternative. When trying to interpret the generated log file, keep in mind that the generator removes common prefixes. In our case, it removes the prefix "CKM_", so the first node in the string match case contains the jump table for the letter after "CKM_". Also note that in both cases, strings and numeric, the generator performs alphabet compression to remove unused character values from the alphabet and thereby compressing the jump table. opencryptoki-opencryptoki-451d99c/doc/README.ep11_stdll000066400000000000000000000134621520105705100227260ustar00rootroot00000000000000EP11 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 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. For more details about the EP11 token, please also see https://www.ibm.com/docs/en/linux-on-systems?topic=specifications-ep11-token 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 allow list starting with a line containing the key word APQN_ALLOWLIST followed by one or more lines containing each two integers (in the range of 0 - 255) separated by a white space. The allow list is ended with a line containing the key word END. In each of lines of the allow 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). 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 should 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. You can change the default for CKA_SENSITIVE to TRUE by specifying keyword FORCE_SENSITIVE in the EP11 token config file. 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. opencryptoki-opencryptoki-451d99c/doc/README.icsf_stdll000066400000000000000000000257121520105705100231050ustar00rootroot00000000000000THE 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 the related z/OS documentation for more information on the z/OS LDAP server requirements and remote crypto configuration, as well as on ICSF PKCS#11. 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. For more details about the ICSF token, please also see https://www.ibm.com/docs/en/linux-on-systems?topic=specifications-icsf-token ----------------------------------------------------------------------- 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. opencryptoki-opencryptoki-451d99c/doc/README.token_data000066400000000000000000000114431520105705100230640ustar00rootroot00000000000000PKCS#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. Starting with openCryptoki vesion 3.12, a new, FIPS compliant format can be used to store the token objects. You may now want to migrate the data stores of an EP11 token, a CCA token, an ICA token, or a Soft token to a FIPS compliant format using the pkcstok_migrate tool. For details, please see https://www.ibm.com/docs/en/linux-on-systems?topic=tools-pkcstok-migrate 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. opencryptoki-opencryptoki-451d99c/doc/README.tpm_stdll000066400000000000000000000072201520105705100227530ustar00rootroot00000000000000TPM 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. opencryptoki-opencryptoki-451d99c/doc/coding_style.md000066400000000000000000000112211520105705100230730ustar00rootroot00000000000000# 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. All conditional preprocessor definitions must be indented, along with the `#` token. e.g.: ```c #ifdef DEF_A #define DEF_A1 #else #define DEF_B1 #endif ``` ## 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.: ```c if (x == 0) { do_y(); } ``` This applies to all non-function statement blocks (if, switch, for, while, do). Another example: ```c 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.: ```c int func(int x) { do_something(); } ``` Follow other examples: ```c do { do_something(); } while (condition); ``` ```c 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.: ```c if (x == 1) do_something(); ``` and ```c 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.: ```c 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.: ```c if (condition) { .. } ``` The following keywords should not have a space between them and their parentheses: ``` sizeof, typeof ``` E.g.: ```c s = sizeof(struct alg); ``` Do **not** add spaces around (inside) parenthesized expressions, e.g.: ```c 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.: ```c 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.: ```c 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: ```c /* * This is a multi-line comment. * * A column of asterisks on the left side, with beginning and ending * almost-blank lines. */ ``` opencryptoki-opencryptoki-451d99c/doc/doc.mk000066400000000000000000000010561520105705100211710ustar00rootroot00000000000000doc_DATA = doc/strength-example.conf doc/opencryptoki-howto.md doc/README.token_data nodist_doc_DATA = doc/policy-example.conf doc/policy-example.conf: tools/policyexamplegen $(AM_V_GEN) $(MKDIR_P) doc && tools/policyexamplegen > doc/policy-example.conf EXTRA_DIST += $(doc_DATA) CLEANFILES += doc/policy-example.conf if ENABLE_CCATOK EXTRA_DIST += doc/README.cca_stdll endif if ENABLE_EP11TOK EXTRA_DIST += doc/README.ep11_stdll endif if ENABLE_ICSFTOK EXTRA_DIST += doc/README.icsf_stdll endif if ENABLE_TPMTOK EXTRA_DIST += doc/README.tpm_stdll endif opencryptoki-opencryptoki-451d99c/doc/opencryptoki-howto.md000066400000000000000000000004631520105705100243020ustar00rootroot00000000000000# PKCS #11 openCryptoki for Linux HOWTO Please see manual [openCryptoki - An Open Source Implementation of PKCS #11](https://www.ibm.com/docs/en/linux-on-systems?topic=support-opencryptoki-open-source-pkcs-11) for details about openCryptoki, how to install and configure it, and some programming examples. opencryptoki-opencryptoki-451d99c/doc/strength-example.conf000066400000000000000000000015421520105705100242310ustar00rootroot00000000000000# OpenCryptoki strength example corresponding to NIST recommendations # See https://www.keylength.com/en/4/ # Move/copy to /etc/opencryptoki/strength.conf to use it with opencryptoki. # Then chown it to root:pkcs11 and chmod it to 0640. version strength-0 strength 112 { MOD_EXP = 2048 ECC = 224 SYMMETRIC = 112 digest = 224 signature = 112 } strength 128 { MOD_EXP = 3072 ECC = 256 SYMMETRIC = 128 digest = 256 signature = 128 } strength 192 { MOD_EXP = 7680 ECC = 384 SYMMETRIC = 192 digest = 384 signature = 192 } strength 256 { MOD_EXP = 15360 ECC = 512 SYMMETRIC = 256 digest = 512 signature = 256 } opencryptoki-opencryptoki-451d99c/doc/system_resources000066400000000000000000000070411520105705100234340ustar00rootroot00000000000000The following are the system resources used by openCryptoki Please also see https://www.ibm.com/docs/en/linux-on-systems?topic=features-architecture-components-opencryptoki 1.Shared memory = 1 per token + 1 segment between pkcsslotd & api + 1 statistic segment per user (if statistics are enabled) 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 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 c. If collection of statistics is enabled, there is one shared memory segment per user. It is created at the first usage of openCryptoki of a user, and is named var.lib.opencryptoki_stats_ where is the numeric user id of the user. Use the pkcsstats tool to display the statistics, and remove statistics segments for users no longer needed. 2. Sockets - 1 a.Unix socket between pkcsslotd and api to transfer slot information. b.Unix socket between pkcsslotd and an event source to deliver events to tokens of running openCryptoki applications. c.Netlink socket owned by pkcsslotd to listen for udev events (s390 platform only). This is used to produce events on APQNs becoming online or offline. d.epoll socket owned by pkcsslotd to wait for events on all the other sockets. 3. Files a. Lock files - 1 global API LCK file + 1 per token (except tpm) + 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 (some are optional) # ls -lh /etc/opencryptoki/ total 32K -rw-r--r--. 1 root root 4.6K Mar 15 13:47 ep11cpfilter.conf -rw-r--r--. 1 root root 4.0K Mar 15 13:24 ep11tok.conf -rw-r--r--. 1 root root 808 Mar 15 13:49 opencryptoki.conf -rw-r-----. 1 root pkcs11 584 Feb 1 16:38 p11sak_defined_attrs.conf -rw-r-----. 1 root pkcs11 5.6K Mar 2 16:45 policy.conf -rw-r-----. 1 root pkcs11 865 Feb 1 16:38 strength.conf d. Token data files - 3 files per token + 1 additional RACF file for icsf token + 1 MK_PRIVATE file for tpm token 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 + as many number of private token objects for tokens OBJ_IDX - A list of current token objects. opencryptoki-opencryptoki-451d99c/kill-all000077500000000000000000000005671520105705100207630ustar00rootroot00000000000000#!/bin/bash # Basic script to provide Linux-equivalent killall on AIX progname= sig= if [ -z "$2" ]; then # no signal provided, $1 is the progname progname="$1" sig=-TERM else # both signal and progname provided, set appropriately progname="$2" sig="$1" fi pids=$(ps -efo pid,comm | grep -w "$progname" | awk '{print $1}') for pid in $pids; do kill $sig $pid done opencryptoki-opencryptoki-451d99c/m4/000077500000000000000000000000001520105705100176445ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/m4/.dont_remove000066400000000000000000000002241520105705100221640ustar00rootroot00000000000000REQUIRED FILE, PLEASE DON'T REMOVE IT. The current configure.ac requires the m4 directory, but git don't save empty directories in the repository. opencryptoki-opencryptoki-451d99c/man/000077500000000000000000000000001520105705100200775ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/man/man.mk000066400000000000000000000001441520105705100212020ustar00rootroot00000000000000include man/man1/man1.mk include man/man5/man5.mk include man/man7/man7.mk include man/man8/man8.mk opencryptoki-opencryptoki-451d99c/man/man1/000077500000000000000000000000001520105705100207335ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/man/man1/man1.mk000066400000000000000000000020151520105705100221160ustar00rootroot00000000000000man1_MANS += man/man1/pkcsconf.1 if ENABLE_ICSFTOK man1_MANS += man/man1/pkcsicsf.1 endif if ENABLE_PKCSHSM_MK_CHANGE man1_MANS += man/man1/pkcshsm_mk_change.1 endif if ENABLE_PKCSSTATS man1_MANS += man/man1/pkcsstats.1 endif if ENABLE_PKCSTOK_MIGRATE man1_MANS += man/man1/pkcstok_migrate.1 endif 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 if ENABLE_PKCSCCA man1_MANS += man/man1/pkcscca.1 endif endif if ENABLE_P11SAK man1_MANS += man/man1/p11sak.1 endif if ENABLE_P11KMIP man1_MANS += man/man1/p11kmip.1 endif if ENABLE_PKCSTOK_ADMIN man1_MANS += man/man1/pkcstok_admin.1 man/man1/pkcstok_admin.1: man/man1/pkcstok_admin.1.in $(AM_V_GEN)@SED@ -e s!\@sysconfdir\@!"$(sysconfdir)"!g \ -e s!\@pkcs_group\@!"$(pkcs_group)"!g \ -e s!\@localstatedir\@!"$(localstatedir)"!g \ < $< > $@-t && \ $(am__mv) $@-t $@ endif EXTRA_DIST += man/man1/pkcstok_admin.1.in CLEANFILES += man/man1/*.1 opencryptoki-opencryptoki-451d99c/man/man1/p11kmip.1.in000066400000000000000000000620261520105705100227120ustar00rootroot00000000000000.TH P11KMIP 1 "August 2023" "@PACKAGE_VERSION@" "openCryptoki" .SH NAME p11kmip \- Transfer cryptographic keys between PKCS\~#11 and KMIP. . . . .SH SYNOPSIS .B p11kmip .I command .RB [ OPTIONS ] .PP . .B p11kmip .BR \-\-help | \-h .br .B p11kmip .BR \-\-version | \-v . . . .SH DESCRIPTION The \fBp11kmip\fP tool can be used to transfer target keys between a PKCS\~#11 key repository and a KMIP server. Target keys may be imported or exported, and are wrapped using public-key cryptography during transit. Keys used for wrapping may also be sent and received. Only AES keys are supported as target keys, and only RSA is supported for key wrapping. .PP .SS KMIP CLIENT AUTHENTICATION KMIP authenticates the users with the client certificate exchanged during TLS handshake. Thus, the client must generate a private RSA or EC key and a client certificate. The client certificate must be registered with the KMIP server. This is a KMIP server product-specific out-of-band process, which is not described here. The client certificate can be a self-signed certificate or a CA-signed certificate. In a production environment, use a CA-signed certificate. .PP The client private key identifies the client to the KMIP server, and thus must be kept secret. If the client private key gets stolen by an attacker then the attacker can identify itself at the KMIP server and thus gets access to the keys stored in the KMIP server. .PP .SS USING A CLEAR CLIENT KEY You can generate the client private key with OpenSSL command line tools. In this case, the private key is a clear key stored in a PEM file. For security reasons, store the client private key in a password-protected PEM file. See an example on how to create a password-protected client key and a self-signed certificate using OpenSSL commands: .PP \fB openssl genpkey \-algorithm RSA \-pkeyopt rsa_keygen_bits:2048 \\ \-out '/path_to_client_key/client.key' \-pass stdin \\ \-aes\-256\-cbc \fP .PP If you want to generate an EC key instead, use \fB\-algorithm EC\fP and \fB\-pkeyopt ec_paramgen_curve:\fP. Create a self-signed certificate with the just generated client key as follows: .PP \fB openssl req \-x509 \-key '/path_to_client_key/client.key' \\ \-out '/path_to_client_certificate/selfsigned_client.crt' \\ \-nodes \-days 3650 \\ \-subj '/CN=www.mydom.com/O=My Company Name LTD./C=US' \fP .PP When using a password-protected client key PEM file, then you are prompted for the PEM password. You are also prompted for further information for the certificate to create, unless these details are supplied via the OpenSSL config file. Refer to the man page of the \fBopenssl req\fP command for further details. .PP If you want to generate a CA-signed certificate instead, omit the \fB\-x509\fP option. Thus, the command generates a certificate signing request instead, that you pass to the CA. With this request, you let the CA sign the certificate and issue a CA-signed certificate for you. .PP .SS USING AN HSM-PROTECTED CLIENT KEY A more secure way to protect the client private key is to generate and store the client key inside a PKCS#11 token. If a secure key token, such as a CCA or EP11 token, is used then the client private key is HSM protected and can not be stolen. This requires the use of a PKCS#11 OpenSSL provider (with OpenSSL 3.0.0 or later), that is, the \fBpkcs11\-provider\fP from \fBhttps://github.com/latchset/pkcs11\-provider\fP. The PKCS#11 provider must be installed and configured properly to allow access to openCryptoki. Use an OpenSSL configuration file similar to the following: .PP \fB [openssl_init] providers = provider_sect [provider_sect] default = default_sect pkcs11 = pkcs11_sect [default_sect] activate = 1 [pkcs11_sect] pkcs11\-module\-path = /path/to/libopencryptoki.so activate = 1 \fP .PP .PP Generate an RSA client key pair in a PKCS#11 token: .PP \fB p11sak generate\-key rsa 2048 \-\-label '' \-\-slot \fP .PP If you want to generate an EC key instead, use: .PP \fB p11sak generate\-key EC \-\-label '' \-\-slot \fP .PP Then export the private client key as a URI-PEM file. A URI-PEM file contains a PKCS#11 URI referencing the key in the PKCS#11 token, but no key material. By default, the PKCS#11 URI does not contain the PKCS#11 user PIN. Refer to the man page of \fBp11sak\fP(1) and option \fB\-\-uri\-pem\fP for details about how to include the PKCS#11 user PIN or a PIN source into the URI. .PP \fB p11sak export\-key \-\-label ':prv' \-\-uri\-pem \\ \-\-file '/path_to_client_key/client.key' \\ \-\-slot > \fP .PP With that private client key as URI-PEM file you can create a self-signed certificate using the following OpenSSL command: .PP \fB openssl req \-x509 \-key '/path_to_client_key/client.key' \\ \-out '/path_to_client_certificate/selfsigned_client.crt' \\ \-nodes \-days 3650 \\ \-subj '/CN=www.mydom.com/O=My Company Name LTD./C=US' \fP .PP You are prompted for the PKCS#11 user PIN, unless the user PIN is contained in the PKCS#11 URI. You are also prompted for further information for the certificate to create, unless these details are supplied via the OpenSSL config file. Refer to the man page of the \fBopenssl req\fP command for further details. .PP If you want to generate a CA-signed certificate instead, omit the \fB\-x509\fP option. Thus, the command generates a certificate signing request instead, that you pass to the CA. With this request, you let the CA sign the certificate and issue a CA-signed certificate for you. .PP Instead of using an URI-PEM file, you can also use the PKCS#11 URI directly. Use the \fBp11sak list\-key\fP command with the \fB\-\-long\fP option to display the PKCS#11 URI of the client private key object. Then specify this URI as-is at the \fB\-key\fP option of the \fBopenssl req\fP command from above: .PP \fB openssl req \-x509 \-key 'pkcs11:....;type=private' \\ \-out '/path_to_client_certificate/selfsigned_client.crt' \\ \-nodes \-days 3650 \\ \-subj '/CN=www.mydom.com/O=My Company Name LTD./C=US' \fP .PP There is no need to export the client private key as URI-PEM file in this case. .PP .SS USING THE CLIENT KEY AND CERTIFICATE WITH P11KMIP Use the private client key as URI-PEM (\fB'/path_to_client_key/client.key'\fP) or as PKCS#11 URI (\fB'pkcs11:....;type=private'\fP) and the client certificate (\fB'/path_to_client_certificate/selfsigned_client.crt'\fP) with the \fBp11kmip\fP commands described below. You can specify the client key and client certificate using options \fB\-\-kmip\-client\-key\fP and \fB\-\-kmip\-client\-cert\fP, or in the \fB/etc/opencryptoki/p11kmip.conf\fP configuration file, or via environment variables. .PP When using a URI-PEM file, or a password-protected PEM file as client key, then you are prompted for the PKCS#11 user PIN or the PEM password when the \fBp11kmip\fP tool reads the client key PEM file, unless the PEM password is specified using the \fB\-\-pem\-password\fP option. The prompt looks like this: .PP \fB Please enter PEM password for '/path_to_client_key/client.key': \fP .PP Note that the prompt message is the same when using a URI-PEM file, and it is prompting for the PKCS#11 user PIN. For a URI-PEM file, the PEM password is the PKCS#11 user PIN required to access the PKCS#11 token that contains the key the URI is referring to. .PP If you specify a PKCS#11 URI directly as client private key, then you are explicitely prompted for the PKCS#11 user PIN for the specified URI. . . . .SH COMMANDS The \fBp11kmip\fP tool supports commands to import and export keys between a PKCS\~#11 token repository and KMIP server. .PP .SS "Importing target keys" .B p11kmip .BR import\-key | import | imp .BR \-\-targkey\-label | \-t .I TARGKEY\-LABEL .BR \-\-wrapkey\-label | \-w .I WRAPKEY\-LABEL .RB [ \-\-unwrapkey\-label | \-u .IR UNWRAPKEY\-LABEL ] .RB [ \-\-send\-wrapkey ] .RB [ \-\-targkey\-attrs .IR TARGKEY\-ATTRS ] .RB [ \-\-targkey\-id .IR ID ] .RB [ \-\-gen\-targkey ] .RB [ \-\-targkey\-length .IR LENGTH ] .RB [ OPTIONS ] .PP Use the .BR import\-key command to import a target key located on a KMIP server to a PKCS\~#11 token repository. Importing a key from a KMIP server requires a wrapping key present on the server with its corresponding unwrapping key present in a local PKCS\#11 slot. Currently RSA is supported for wrapping and unwrapping keys and AES is supported for target keys. The .BR \-\-targkey\-label | \-t .I TARGKEY\-LABEL option specifies the KMIP name attribute of the target key to be imported. Once imported into the PKCS\~#11 token repository, the .B CKA_LABEL attribute of the target key will be set to the same value as .IR TARGKEY\-LABEL . The .BR \-\-wrapkey\-label | \-w .I WRAPKEY\-LABEL option specifies the KMIP name attribute of the key to be used for wrapping. This wrapping key must already be present on the KMIP server, unless the .BR \-\-send\-wrapkey option is specified. The imported key will be unwrapped using a corresponding unwrapping key located in the PKCS\~#11 token repository with a .B CKA_LABEL attribute value that is the same as .I WRAPKEY\-LABEL , unless the .B \-\-unwrapkey\-label | \-u .I UNWRAPKEY\-LABEL option identifies a different private key instead. When the .BR \-\-send\-wrapkey option is specified, the .BR \-\-wrapkey\-label | \-w .I WRAPKEY\-LABEL option will instead be used to identify a public key located in the PKCS\~#11 token repository, with a .B CKA_LABEL attribute value that is the same as specified by .IR WRAPKEY\-LABEL . This public key is sent and registered on the KMIP server with a KMIP name specified by .BR \-\-wrapkey\-label . The public key will then be used for wrapping. After the import operation has been completed successfully, information will be displayed about the keys involved. This includes the .B CKA_LABEL attribute values of the imported target key and wrapping key, the KMIP UID attributes of both keys, and a SHA-256 digest of the imported target key from both the KMIP server and the PKCS\~#11 token repository. Example: Target Key PKCS#11 Label...TARGET_KEY_LABEL PKCS#11 Digest..FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF KMIP UID........TARGET_KEY_UUID KMIP Digest.....AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA Wrapping Key PKCS#11 Label...WRAPPING_KEY_LABEL KMIP UID........WRAPPING_KEY_UUID The .B \-\-targkey\-attrs .I TARGKEY\-ATTRS option can be used to set the boolean attributes of the imported target key (see below for detailed description of the attributes). The .B \-\-targkey\-id .I ID option may be used to set the value of the .BR CKA_ID attribute of the target key. When the .BR \-\-gen\-targkey option is specified, the target key will first be generated on the KMIP server. In this case, the value of the .BR \-\-targkey\-label | \-t .I TARGKEY\-LABEL option will be used as the KMIP name attribute of the generated key. Currently, only AES symmetric keys may be generated in this way. The .B \-\-targkey\-length .I LENGTH option may be used to specify the length of the generated with the .BR \-\-gen\-targkey option, and is only valid when specified with that option. .I LENGTH must be one of 128, 192, or 256. The default is 256. See below for a detailed description of .BR OPTIONS . The .BR \-\-help | \-h option will also show the arguments and options available. . .PP .SS "Exporting target keys" .B p11kmip .BR export\-key | export | exp .BR \-\-targkey\-label | \-t .I TARGKEY\-LABEL .BR \-\-wrapkey\-label | \-w .I WRAPKEY\-LABEL .RB [ \-\-retr\-wrapkey ] .RB [ \-\-wrapkey\-attrs .IR WRAPKEY\-ATTRS ] .RB [ \-\-wrapkey\-id .IR ID ] .RB [ OPTIONS ] .PP Use the .BR export\-key command to export a target key located in a PKCS\~#11 token repository to a KMIP server. Exporting a key from a PKCS\~#11 slot to a KMIP server requires an unwrapping key to be present on the server with a corresponding wrapping key present in the PKCS\~#11 slot. Currently only RSA is supported for wrapping and unwrapping keys and AES for target keys. The .BR \-\-targkey\-label | \-t .I TARGKEY\-LABEL option specifies the .B CKA_LABEL attribute value of the target key to be exported. Once exported to the KMIP server, the KMIP name attribute of the target key will be set to the same value as .IR TARGKEY\-LABEL . The .BR \-\-wrapkey\-label | \-w .I WRAPKEY\-LABEL option species the .B CKA_LABEL attribute value of key to be used for wrapping the exported key. The wrapping key must already be present in PKCS\~#11 token repository, unless the .BR \-\-retr\-wrapkey option is specified. The exported key will be unwrapped corresponding unwrapping key located on the KMIP server with a KMIP name attribute that is the same as .I WRAPKEY\-LABEL . When the .BR \-\-retr\-wrapkey option is specified, the .BR \-\-wrapkey\-label | \-w .I WRAPKEY\-LABEL option will instead be used to identify a wrapping key located on the KMIP server with a KMIP name attribute that is the same as .IR WRAPKEY\-LABEL . This wrapping key will be retrieved from the KMIP server and imported into the PKCS\~#11 token repository, with a .B CKA_LABEL attribute value of .I WRAPKEY\-LABEL , and used to wrap the exported key. When the wrapping key is being retrieved from the KMIP server, the .B \-\-wrapkey\-attrs .I WRAPKEY\-ATTRS option can be used to set the boolean attributes of the retrieved wrapping key (see below for detailed description of the attributes). The .B \-\-wrapkey\-id .I ID option may be used to set the value of the .BR CKA_ID attribute of the public key. After the export operation has been completed successfully, information will be displayed about the keys involved. This includes the .B CKA_LABEL attribute values of the exported target key and public key, the KMIP UID attributes of both keys, and a SHA-256 digest of the exported target key from both the KMIP server and the PKCS\~#11 token repository. Example: Target Key PKCS#11 Label...TARGET_KEY_LABEL PKCS#11 Digest..FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF KMIP UID........TARGET_KEY_UUID KMIP Digest.....AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA Wrapping Key PKCS#11 Label...WRAPPING_KEY_LABEL KMIP UID........WRAPPING_KEY_UUID See below for a detailed description of .BR OPTIONS . The .BR \-\-help | \-h option will also show the arguments and options available. . . .SH OPTIONS .TP 8 .BR \-\-wrapkey\-attrs \-a\~\fIWRAPKEY\-ATTRS\fP | \-\-targkey\-attrs \-a\~\fITARGKEY\-ATTRS\fP For the .B export\-key command, specify the PKCS\~#11 boolean attributes that are to be set for the retrieved wrapping key. For the .B import\-key , specify the PKCS\~#11 boolean attributes that are to be set for the imported target key. .PP .RS 8 .B Note: Not all boolean attributes are applicable to all key types and/or commands and will be silently ignored if not applicable. .PP The respective attributes are set to .B TRUE when the corresponding letter is specified in uppercase, or .B FALSE when the corresponding letter is specified in lowercase. Attributes (except \fBCKA_TOKEN\fP and \fBCKA_SENSITIVE\fP, see below) that are not specified get the default value as defined by the PKCS\~#11 standard or the used PKCS\~#11 token implementation when generating keys, or are not updated when setting the attributes of an existing key. .PP Attribute .B CKA_TOKEN is always set to \fBTRUE\fP for imported symmetric keys, and is set to \fBTRUE\fP by default for public keys. This is because session keys are not persistent, and thus would no longer exist after the session that the .B p11kmip tool has opened is closed when it exists. For public keys only, this can be overridden by specifying the respective uppercase or lowercase letter for the CKA_TOKEN attribute in the attribute string, as desired. .PP When importing or recieving a key with the .B p11kmip tool, attribute .B CKA_SENSITIVE defaults to \fBTRUE\fP for symmetric keys. However, this can be overridden by specifying the respective uppercase or lowercase letter for the CKA_SENSITIVE attribute in the attribute string, as desired. .PP .B Note: The default setting for the .B CKA_SENSITIVE attribute is defined by the .B p11kmip tool, and might be different from the default setting that would be chosen by the used PKCS\~#11 implementation. .PP The following letters are associated with the respective .BR CK_ATTRIBUTE : .IP "\(bu" 2 .B H \- CKA_TOKEN .IP "\(bu" 2 .B P \- CKA_PRIVATE .IP "\(bu" 2 .B M \- CKA_MODIFIABLE .IP "\(bu" 2 .B B \- CKA_COPYABLE .IP "\(bu" 2 .B Y \- CKA_DESTROYABLE .IP "\(bu" 2 .B S \- CKA_SENSITIVE .IP "\(bu" 2 .B X \- CKA_EXTRACTABLE .IP "\(bu" 2 .B K \- CKA_IBM_PROTKEY_EXTRACTABLE (IBM specific, not all tokens support this) .PP For multiple attributes, specify a set of these letters without any blanks in between, e. g. \fB'MlD'\fP. An uppercase letter means \fBTRUE\fP, while a lowercase letter means \fBFALSE\fP. From Example above, \fB'MbS'\fP corresponds to: \fBCKA_MODIFIABLE=TRUE, CKA_COPYABLE=FALSE, CKA_SENSITIVE=TRUE\fP. .PP .RE . . . .TP 8 .BR \-\-slot | \-s\~\fISLOT\fP Specifies the slot number of the PKCS\~#11 token to use. .PP .RS 8 Alternatively, the slot number may be specified using the .B PKCS11_SLOT_ID environment variable or the \fBp11kmip.conf\fP configuration file. See \fBp11kmip.conf\fP(5) for more details about using the configuration file. When one or more of these are set, the option takes highest priority, the environment variable second highest, and the configuration file least priority. When none are set, an error occurs. .RE . . . .TP 8 .BR \-\-pin | \-p\~\fIPIN\fP Specifies the PKCS\~#11 token user PIN to login with. .PP .RS 8 Alternatively, the .B PKCS11_USER_PIN environment variable may be used to provide the token user PIN. If neither this option is specified nor the environment variable is set, the user is prompted for the PIN. .RE .PP . . . .TP 8 .BR \-\-force\-pin\-prompt Force the .B p11kmip tool to prompt for the token user PIN (regardless of if it has been specified elsewhere) .PP . . . .TP 8 .BR \-\-kmip\-host\~\fIHOSTNAME\fP The hostname of the KMIP server with which to connect. .PP .RS 8 Alternatively, the hostname may be specified using the .B KMIP_HOSTNAME environment variable or the \fBp11kmip.conf\fP configuration file. See \fBp11kmip.conf\fP(5) for more details about using the configuration file. When one or more of these are set, the option takes highest priority, the environment variable second highest, and the configuration file least priority. When none are set, an error occurs. .RE . . . .TP 8 .BR \-\-kmip\-client\-cert\~\fICERT\-PATH\fP A path to the TLS client certificate to use for the KMIP connection. .PP .RS 8 Alternatively, the client certificate path may be specified using the .B KMIP_CLIENT_CERT environment variable, or the \fBp11kmip.conf\fP configuration file. See \fBp11kmip.conf\fP(5) for more details about using the configuration file. When one or more of these are set, the option takes highest priority, the environment variable second highest, and the configuration file least priority. When none are set, an error occurs. .RE . . . .TP 8 .BR \-\-kmip\-client\-key\~\fIKEY\-PATH\fP A path to the TLS client private key to use for the KMIP connection. .PP .RS 8 Alternatively, the client private key path may be specified using the .B KMIP_CLIENT_KEY environment variable or the \fBp11kmip.conf\fP configuration file. See \fBp11kmip.conf\fP(5) for more more details about using the configuration file. When one or more of these are set, the option takes highest priority, the environment variable second highest, and the configuration file least priority. When none are set, an error occurs. .RE . . . .TP 8 .BR \-\-pem\-password\~\fIPEM\-PASSWORD\fP The password to use for the TLS client key PEM file, if it is password-protected. .PP .RS 8 Alternatively, the PEM password may be specified using the .B KMIP_PEM_PASSWORD environment variable. When both are set, the option takes higher priority. When neither are set, the user is prompted for the password. .RE .PP . . . .TP 8 .BR \-\-force\-pem\-password\-prompt Force the .B p11kmip tool to prompt for the TLS client key PEM password (regardless of if it has been specified elsewhere). .PP . . . .TP 8 .BR \-\-tls\-verify\-hostname Enforce verification of the KMIP server hostname. .PP . . . .TP 8 .BR \-\-tls\-no\-verify\-certificate Skip verification of the KMIP server TLS certificate. .PP . . . .TP 8 .BR \-\-tls\-trust\-server\-cert Perform verification of the KMIP server TLS certificate, but do not prompt the user for trust of this server. .PP . . . .TP 8 .BR \-\-debug | \-d Increase debug information. .PP . . . .TP 8 .BR \-\-quiet | \-q Suppress messages. .PP . . . .TP 8 .BR \-\-short | \-r Print shortened results. Example: SECRET_KEY_LABEL:FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SECRET_KEY_UUID:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA .PP . . . .TP 8 .BR \-\-help | \-h Prints help for the usage of the .B p11kmip tool and/or the respective command and then exits. .RE .PP . . . .TP 8 .BR \-\-version | \-v Prints the version of the .B p11kmip tool and then exits. .RE .PP . . . .SH "FILES" . .SS "/etc/opencryptoki/p11kmip.conf" This configuration file can be used to specify persistent settings to be used by the .B p11kmip for connections to KMIP servers and interactions with PKCS\~#11 token repositories. A custom file path can be set with environment variable \fBP11KMIP_DEFAULT_CONF_FILE\fP. If the environment variable is not set, then the global \fB/etc/opencryptoki/p11kmip.conf\fP config file is read. If this file is unavailable, an error message is displayed. .PP . . . .SH "ENVIRONMENT VARIABLES" .SS "P11KMIP_DEFAULT_CONF_FILE" A custom path for the \fBp11kmip.conf\fP config file can be set with the environment variable \fBP11KMIP_DEFAULT_CONF_FILE\fP. If the environment variable is not set, then the global \fB/etc/opencryptoki/p11kmip.conf\fP config file is read. If this file is unavailable, an error message is displayed. .PP . .SS "PKCS11_USER_PIN" The PKCS\~#11 token user PIN can be specified via the environment variable \fBPKCS11_USER_PIN\fP. If this environment variable is not set, and the option .BR \-\-pin | \-p .I PIN is not specified, p11kmip will prompt for the token user PIN interactively. .PP . .SS "PKCS11_SLOT_ID" The PKCS\~#11 token slot number can be specified via the environment variable \fBPKCS11_SLOT_ID\fP. If this environment variable is not set, and the option .BR \-\-pin | \-p\~\fIPIN\fP is not specified, the value will be read from the \fBp11kmip.conf\fP configuration file. .PP . .SS "PKCSLIB" An alternative PKCS\~#11 library name can be specified with the \fBPKCSLIB\fP environment variable. If this environment variable is not set, then the default PKCS\~#11 library \fBlibopencryptoki.so\fP is used. .PP . .SS "KMIP_HOSTNAME" The hostname of the KMIP server with which to connect can be specified using the \fBKMIP_HOSTNAME\fP environment variable. If this environment variable is not set, and the option .BR \-\-kmip\-host\~\fHOSTNAME\fP is not specified, the value will be read from the \fBp11kmip.conf\fP configuration file. .PP . .SS "KMIP_CLIENT_CERT" The path to the TLS client certificate to use for the KMIP connection can be specified using the \fBKMIP_CLIENT_CERT\fP environment variable. If this environment variable is not set, and the option .BR \-\-kmip\-client\-cert\~\fCERT\-PATH\fP .PP . .SS "KMIP_CLIENT_KEY" The path to the TLS client key to use for the KMIP connection can be specified using the \fBKMIP_CLIENT_KEY\fP environment variable. If this environment variable is not set, and the option .BR \-\-kmip\-client\-key\~\fBKEY\-PATH\fP .PP . .SS "KMIP_PEM_PASSWORD" The PEM file used for the TLS client key may be password protected. The PEM password can be specified via the environment variable \fBKMIP_PEM_PASSWORD\fP. If this environment variable is not set, and the option .BR \-\-pem\-password\~\fPEM\-PASSWORD\fP is not specified, p11kmip will prompt for the PEM password interactively. . . . .SH "EXIT STATUS" The .B p11kmip tool returns error codes as defined by the PKCS\~#11 standard, i.e. the \fBCKR_nnn\fP errors. On success, \fBCKR_OK\fP (which is zero) is returned. .PP The PKCS\~#11 error codes may originate from a PKCS\~#11 function called by the .B p11kmip tool, or from the .B p11kmip tool itself, like the following: .SS CKR_ARGUMENTS_BAD (0x00000007): An argument, option or keyword is not valid. .PP . . . .SS CKR_DATA_INVALID (0x00000020): The \fBp11kmip.conf\fP cannot be parsed or its syntax is invalid. .PP . . . .SS CKR_MECHANISM_INVALID (0x00000070): The token does not support the key generation mechanism for the specified key type. .PP . . . .SS CKR_KEY_SIZE_RANGE (0x00000062): The token does not support the key size for the specified key type. .PP . . . .SS CKR_HOST_MEMORY (0x00000002): Allocating memory has failed. .PP . . . .SS CKR_FUNCTION_FAILED (0x00000006): A subfunction or library call has failed. .PP . . . .SH "SEE ALSO" .PD 0 .TP \fBp11kmip.conf\fP(5) .TP \fBp11sak\fP(1) .TP \fBopenssl\-genpkey\fP(1) .TP \fBopenssl\-req\fP(1) .PD opencryptoki-opencryptoki-451d99c/man/man1/p11sak.1.in000066400000000000000000003143211520105705100225260ustar00rootroot00000000000000.TH P11SAK 1 "May 2025" "@PACKAGE_VERSION@" "openCryptoki" .SH NAME p11sak \- Manage token keys in a PKCS\~#11 token repository. . . . .SH SYNOPSIS .B p11sak .I command .RB [ ARGUMENTS ] .RB [ OPTIONS ] .PP . .B p11sak .BR \-\-help | \-h .br .B p11sak .BR \-\-version | \-v . . . .SH DESCRIPTION The \fBp11sak\fP tool can be used to manage token keys and certificates in a PKCS\~#11 token repository. The utility provides a flexible key management tool to generate, list, remove, update, copy, import, and export symmetric (DES, 3DES, generic, SHA\-HMAC, AES, AES\-XTS) and asymmetric (RSA, DH, DSA, EC, EC\-Edwards, EC\-Montgomery, IBM Dilithium, IBM Kyber, IBM ML\-DSA, IBM ML\-KEM, ML\-DSA, ML\-KEM) keys. This tool is also capable of listing the keys with their PKCS\~#11 attributes and their values (not all attributes may be displayed if a key is sensitive). It also supports the import, export, copy, and listing of certificates. Public keys inside certificates and private keys can be extracted and added to the token repository as new public key objects. .PP .B Note: The .B p11sak tool only operates on token keys (i.e. \fBCKA_TOKEN=TRUE\fP), but not on session keys (\fBCKA_TOKEN=FALSE\fP). Token keys are stored persistently in the token's repository, while session keys are not stored persistently, and only exist as long as the session is alive. Thus, session keys generated or imported by the .B p11sak tool would not exist anymore when the .B p11sak tool has exited. . . . .SH COMMANDS The \fBp11sak\fP tool supports various commands to generate, list, remove, update, import, and export token keys and certificates in a PKCS\~#11 token repository. .PP .SS "Generating symmetric and asymmetric keys" .B p11sak .BR generate\-key | gen\-key | gen .I KEYTYPE .RB [ ARGUMENTS ] .RB [ OPTIONS ] .PP Use the .BR generate\-key | gen\-key | gen command to generate a token key of the specified .I KEYTYPE with the respective .B ARGUMENTS and .BR OPTIONS . Possible values for the .I KEYTYPE argument are: .BR des |\: 3des |\: generic |\: sha\-1\-hmac |\: sha224\-hmac |\: \ sha256\-hmac |\: sha384\-hmac |\: sha512\-hmac |\: sha512/224\-hmac |\: \ sha512/256\-hmac |\: sha3\-224\-hmac |\: sha3\-256\-hmac |\: sha3\-384\-hmac \ |\: sha3\-512\-hmac |\: aes |\: aes\-xts |\: rsa |\: dh |\: dsa |\: ec |\: \ ec\-edwards |\: ec\-montgomery |\: ibm\-dilithium |\: ibm\-kyber |\: \ ibm\-ml\-dsa |\: ibm\-ml\-kem |\: ml\-dsa |\: ml\-kem . See below for a detailed description of the arguments and options. The .BR \-\-help | \-h option also shows the arguments and options available. . .PP .SS "Generating DES/3DES keys" . .B p11sak .BR generate\-key | gen\-key | gen .BR des | 3des .BR \-\-slot | \-s .I SLOTID .RB [ \-\-pin | \-p .IR PIN ] .RB [ \-\-force\-pin\-prompt ] .RB [ \-\-no\-login | \-N ] .RB [ \-\-so ] .BR \-\-label | \-L .I LABEL .BR \-\-attr | \-a .I ATTRS .RB [ \-\-id | \-i .IR ID ] .RB [ \-\-help | \-h ] .PP Use the .BR generate\-key | gen\-key | gen command with the .B des|3des .I KEYTYPE argument to generate a DES or 3DES key (\fBCKK_DES\fP or \fBCKK_DES3\fP). The .BR \-\-label | \-L .I LABEL option sets the .B CKA_LABEL attribute of the key and the .BR \-\-attr | \-a .I ATTRS option can be used to set the boolean attributes of the key (see below for detailed description of the attributes). The .BR \-\-id | \-i .I ID option can be used to set the value of the .B CKA_ID attribute of the key. .PP .SS "Generating generic secret keys" . .B p11sak .BR generate\-key | gen\-key | gen .BR generic .I KEYBITS .BR \-\-slot | \-s .I SLOTID .RB [ \-\-pin | \-p .IR PIN ] .RB [ \-\-force\-pin\-prompt ] .RB [ \-\-no\-login | \-N ] .RB [ \-\-so ] .BR \-\-label | \-L .I LABEL .BR \-\-attr | \-a .I ATTRS .RB [ \-\-id | \-i .IR ID ] .RB [ \-\-help | \-h ] .PP Use the .BR generate\-key | gen\-key | gen .B generic .I KEYBITS command and .I KEYTYPE argument to generate a generic secret key (\fBCKK_GENERIC_SECRET\fP) with the key size in bits as specified by the .I KEYBITS argument. The .BR \-\-label | \-L .I LABEL option sets the .B CKA_LABEL attribute of the key and the .BR \-\-attr | \-a .I ATTRS option can be used to set the boolean attributes of the key (see below for detailed description of the attributes). The .BR \-\-id | \-i .I ID option can be used to set the value of the .B CKA_ID attribute of the key. . .PP .SS "Generating SHA\-HMAC keys" . .B p11sak .BR generate\-key | gen\-key | gen .BR sha\-1\-hmac |\: sha224\-hmac |\: sha256\-hmac |\: sha384\-hmac |\: \ sha512\-hmac |\: sha512/224\-hmac |\: sha512/256\-hmac |\: sha3\-224\-hmac |\: \ sha3\-256\-hmac |\: sha3\-384\-hmac |\: sha3\-512\-hmac .I KEYBITS .BR \-\-slot | \-s .I SLOTID .RB [ \-\-pin | \-p .IR PIN ] .RB [ \-\-force\-pin\-prompt ] .RB [ \-\-no\-login | \-N ] .RB [ \-\-so ] .BR \-\-label | \-L .I LABEL .BR \-\-attr | \-a .I ATTRS .RB [ \-\-id | \-i .IR ID ] .RB [ \-\-help | \-h ] .PP Use the .BR generate\-key | gen\-key | gen .B sha\fInnn\fB\-hmac .I KEYBITS command and .I KEYTYPE argument to generate a SHA\-HMAC key (\fBCKK_SHAnnn_HMAC\fP) with the key size in bits as specified by the .I KEYBITS argument. The .BR \-\-label | \-L .I LABEL option sets the .B CKA_LABEL attribute of the key and the .BR \-\-attr | \-a .I ATTRS option can be used to set the boolean attributes of the key (see below for detailed description of the attributes). The .BR \-\-id | \-i .I ID option can be used to set the value of the .B CKA_ID attribute of the key. . .PP .SS "Generating AES keys" . .B p11sak .BR generate\-key | gen\-key | gen .BR aes .BR 128 | 192 | 256 .BR \-\-slot | \-s .I SLOTID .RB [ \-\-pin | \-p .IR PIN ] .RB [ \-\-force\-pin\-prompt ] .RB [ \-\-no\-login | \-N ] .RB [ \-\-so ] .BR \-\-label | \-L .I LABEL .BR \-\-attr | \-a .I ATTRS .RB [ \-\-id | \-i .IR ID ] .RB [ \-\-help | \-h ] .PP Use the .BR generate\-key | gen\-key | gen .B aes .B 128|192|256 command and .I KEYTYPE argument to generate a AES key (\fBCKK_AES\fP) with 128-, 192-, or 256-bit length, respectively. The .BR \-\-label | \-L .I LABEL option sets the .B CKA_LABEL attribute of the key and the .BR \-\-attr | \-a .I ATTRS option can be used to set the boolean attributes of the key (see below for detailed description of the attributes). The .BR \-\-id | \-i .I ID option can be used to set the value of the .B CKA_ID attribute of the key. . .PP .SS "Generating AES\-XTS keys" . .B p11sak .BR generate\-key | gen\-key | gen .BR aes\-xts .BR 128 | 256 .BR \-\-slot | \-s .I SLOTID .RB [ \-\-pin | \-p .IR PIN ] .RB [ \-\-force\-pin\-prompt ] .RB [ \-\-no\-login | \-N ] .RB [ \-\-so ] .BR \-\-label | \-L .I LABEL .BR \-\-attr | \-a .I ATTRS .RB [ \-\-id | \-i .IR ID ] .RB [ \-\-help | \-h ] .PP Use the .BR generate\-key | gen\-key | gen .B aes\-xts .B 128|256 command and .I KEYTYPE argument to generate a AES\-XTS key (\fBCKK_AES_XTS\fP) with 128- or 256-bit length, respectively. The .BR \-\-label | \-L .I LABEL option sets the .B CKA_LABEL attribute of the key and the .BR \-\-attr | \-a .I ATTRS option can be used to set the boolean attributes of the key (see below for detailed description of the attributes). The .BR \-\-id | \-i .I ID option can be used to set the value of the .B CKA_ID attribute of the key. . .PP .SS "Generating RSA keys" . .B p11sak .BR generate\-key | gen\-key | gen .BR rsa .I KEYBITS .RI [ PUBL\-EXP ] .BR \-\-slot | \-s .I SLOTID .RB [ \-\-pin | \-p .IR PIN ] .RB [ \-\-force\-pin\-prompt ] .RB [ \-\-no\-login | \-N ] .RB [ \-\-so ] .BR \-\-label | \-L .IR LABEL | PUB\-LABEL : PRIV\-LABEL .BR \-\-attr | \-a .IR ATTRS | PUB\-ATTRS : PRIV\-ATTRS .RB [ \-\-id | \-i .IR ID ] .RB [ \-\-help | \-h ] .PP Use the .BR generate\-key | gen\-key | gen .B rsa .I KEYBITS command and .I KEYTYPE argument to generate an RSA key (\fBCKK_RSA\fP) with the key size in bits as specified by the .I KEYBITS argument. The key size must be from 512 to 16384 and a multiple of 8 bits. Typical key sizes are 512, 1024, 2048, 4096, or 8192. Not all RSA key sizes might be supported by all tokens. The .BR \-\-label | \-L .IR LABEL | PUB\-LABEL : PRIV\-LABEL option sets the .B CKA_LABEL attribute of the key and the .BR \-\-attr | \-a .IR ATTRS | PUB\-ATTRS : PRIV\-ATTRS option can be used to set the boolean attributes of the key (see below for detailed description of the attributes). Optionally, set individual key attributes for public and private key separated by a colon (\fB:\fP). The .BR \-\-id | \-i .I ID option can be used to set the value of the .B CKA_ID attribute of the key. Furthermore, the optional .I PUBL\-EXP argument allows the user to specify the exponent used for generating the RSA key. The default is set to 65537 according to the PKCS\~#11 standard. . .PP .SS "Generating DH keys" . .B p11sak .BR generate\-key | gen\-key | gen .BR dh .IR GROUP | DH\-PARAM\-PEM\-FILE .RI [ PRIV\-BITS ] .BR \-\-slot | \-s .I SLOTID .RB [ \-\-pin | \-p .IR PIN ] .RB [ \-\-force\-pin\-prompt ] .RB [ \-\-no\-login | \-N ] .RB [ \-\-so ] .BR \-\-label | \-L .IR LABEL | PUB\-LABEL : PRIV\-LABEL .BR \-\-attr | \-a .IR ATTRS | PUB\-ATTRS : PRIV\-ATTRS .RB [ \-\-id | \-i .IR ID ] .RB [ \-\-help | \-h ] .PP Use the .BR generate\-key | gen\-key | gen .B dh .IR GROUP | DH\-PARAM\-PEM\-FILE command and .I KEYTYPE argument to generate a DH key (\fBCKK_DH\fP), where .I GROUP specifies the Diffie\-Hellman FFC group name or .I DH\-PARAM\-PEM\-FILE specifies the name of a DH parameters PEM file. The following arguments can be used for respective groups: .BR ffdhe2048 |\: ffdhe3072 |\: ffdhe4096 |\: ffdhe6144 |\: ffdhe8192 |\: \ modp1536 |\: modp2048 |\: modp3072 |\: modp4096 |\: modp6144 |\: modp8192 .PP .B Note: Not all groups are supported by all tokens and key generation fails when the specified .I GROUP is not supported. Also, not all groups are supported by all OpenSSL versions. If the .B p11sak tool is compiled against an OpenSSL version that does not support certain groups, then those groups are not accepted for the .I GROUP argument. .PP Alternatively, specify a DH parameters PEM file as .I DH\-PARAM\-PEM\-FILE argument. You can for example generate DH parameters using the .B OpenSSL command line tool as follows: '\fBopenssl dhparam \-out \-outform PEM'\fP. See the OpenSSL man page for details about this command. .PP The .BR \-\-label | \-L .IR LABEL | PUB\-LABEL : PRIV\-LABEL option sets the .B CKA_LABEL attribute of the key and the .BR \-\-attr | \-a .IR ATTRS | PUB\-ATTRS : PRIV\-ATTRS option can be used to set the boolean attributes of the key (see below for detailed description of the attributes). Optionally, set individual key attributes for public and private key separated by a colon (\fB:\fP). The .BR \-\-id | \-i .I ID option can be used to set the value of the .B CKA_ID attribute of the key. Furthermore, the optional .I PRIV\-BITS argument allows the user to specify the size of the private key in bits. . .PP .SS "Generating DSA keys" . .B p11sak .BR generate\-key | gen\-key | gen .BR dsa .I DSA\-PARAM\-PEM\-FILE .BR \-\-slot | \-s .I SLOTID .RB [ \-\-pin | \-p .IR PIN ] .RB [ \-\-force\-pin\-prompt ] .RB [ \-\-no\-login | \-N ] .RB [ \-\-so ] .BR \-\-label | \-L .IR LABEL | PUB\-LABEL : PRIV\-LABEL .BR \-\-attr | \-a .IR ATTRS | PUB\-ATTRS : PRIV\-ATTRS .RB [ \-\-id | \-i .IR ID ] .RB [ \-\-help | \-h ] .PP Use the .BR generate\-key | gen\-key | gen .B dsa .I DSA\-PARAM\-PEM\-FILE command and .I KEYTYPE argument to generate a DSA key (\fBCKK_DSA\fP), where .I DSA\-PARAM\-PEM\-FILE specifies the name of a DSA parameters PEM file. You can for example generate DSA parameters using the .B OpenSSL command line tool as follows: '\fBopenssl dsaparam \-out \-outform PEM'\fP. See the OpenSSL man page for details about this command. .PP The .BR \-\-label | \-L .IR LABEL | PUB\-LABEL : PRIV\-LABEL option sets the .B CKA_LABEL attribute of the key and the .BR \-\-attr | \-a .IR ATTRS | PUB\-ATTRS : PRIV\-ATTRS option can be used to set the boolean attributes of the key (see below for detailed description of the attributes). Optionally, set individual key attributes for public and private key separated by a colon (\fB:\fP). The .BR \-\-id | \-i .I ID option can be used to set the value of the .B CKA_ID attribute of the key. .PP .SS "Generating EC keys" . .B p11sak .BR generate\-key | gen\-key | gen .BR ec .I CURVE .BR \-\-slot | \-s .I SLOTID .RB [ \-\-pin | \-p .IR PIN ] .RB [ \-\-force\-pin\-prompt ] .RB [ \-\-no\-login | \-N ] .RB [ \-\-so ] .BR \-\-label | \-L .IR LABEL | PUB\-LABEL : PRIV\-LABEL .BR \-\-attr | \-a .IR ATTRS | PUB\-ATTRS : PRIV\-ATTRS .RB [ \-\-id | \-i .IR ID ] .RB [ \-\-help | \-h ] .PP Use the .BR generate\-key | gen\-key | gen .B ec .I CURVE command and .I KEYTYPE argument to generate an EC key (\fBCKK_EC\fP), where .I CURVE specifies the elliptic curve used to create the EC key. The following arguments can be used for respective curves: .BR prime256v1 |\: prime192 |\: secp224 |\: secp384r1 |\: secp521r1 |\: \ secp265k1 |\: brainpoolP160r1 |\: brainpoolP160t1 |\: brainpoolP192r1 |\: \ brainpoolP192t1 |\: brainpoolP224r1 |\: brainpoolP224t1 |\: brainpoolP256r1 \ |\: brainpoolP256t1 |\: brainpoolP320r1 |\: brainpoolP320t1 |\: \ brainpoolP384r1 |\: brainpoolP384t1 |\: brainpoolP512r1 |\: brainpoolP512t1 \ |\: curve25519 |\: curve448 |\: ed25519 |\: ed448 |\: bls12-381 Note that using an Edwards or Montgomery curve for the EC key type only works for the EP11 token and produces a non-PKCS#11-standard EC key. .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. .PP The .BR \-\-label | \-L .IR LABEL | PUB\-LABEL : PRIV\-LABEL option sets the .B CKA_LABEL attribute of the key and the .BR \-\-attr | \-a .IR ATTRS | PUB\-ATTRS : PRIV\-ATTRS option can be used to set the boolean attributes of the key (see below for detailed description of the attributes). Optionally, set individual key attributes for public and private key separated by a colon (\fB:\fP). The .BR \-\-id | \-i .I ID option can be used to set the value of the .B CKA_ID attribute of the key. . .PP .SS "Generating EC\-Edwards keys" . .B p11sak .BR generate\-key | gen\-key | gen .BR ec\-edwards .I CURVE .BR \-\-slot | \-s .I SLOTID .RB [ \-\-pin | \-p .IR PIN ] .RB [ \-\-force\-pin\-prompt ] .RB [ \-\-no\-login | \-N ] .RB [ \-\-so ] .BR \-\-label | \-L .IR LABEL | PUB\-LABEL : PRIV\-LABEL .BR \-\-attr | \-a .IR ATTRS | PUB\-ATTRS : PRIV\-ATTRS .RB [ \-\-id | \-i .IR ID ] .RB [ \-\-help | \-h ] .PP Use the .BR generate\-key | gen\-key | gen .B ec\-edwards .I CURVE command and .I KEYTYPE argument to generate an EC\-Edwards key (\fBCKK_EC_EDWARDS\fP), where .I CURVE specifies the edwards curve used to create the EC-Edwards key. The following arguments can be used for respective curves: .BR ed25519 |\: ed448 . .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. .PP The .BR \-\-label | \-L .IR LABEL | PUB\-LABEL : PRIV\-LABEL option sets the .B CKA_LABEL attribute of the key and the .BR \-\-attr | \-a .IR ATTRS | PUB\-ATTRS : PRIV\-ATTRS option can be used to set the boolean attributes of the key (see below for detailed description of the attributes). Optionally, set individual key attributes for public and private key separated by a colon (\fB:\fP). The .BR \-\-id | \-i .I ID option can be used to set the value of the .B CKA_ID attribute of the key. . .PP .SS "Generating EC\-Montgomery keys" . .B p11sak .BR generate\-key | gen\-key | gen .BR ec\-montgomery .I CURVE .BR \-\-slot | \-s .I SLOTID .RB [ \-\-pin | \-p .IR PIN ] .RB [ \-\-force\-pin\-prompt ] .RB [ \-\-no\-login | \-N ] .RB [ \-\-so ] .BR \-\-label | \-L .IR LABEL | PUB\-LABEL : PRIV\-LABEL .BR \-\-attr | \-a .IR ATTRS | PUB\-ATTRS : PRIV\-ATTRS .RB [ \-\-id | \-i .IR ID ] .RB [ \-\-help | \-h ] .PP Use the .BR generate\-key | gen\-key | gen .B ec\-montgomery .I CURVE command and .I KEYTYPE argument to generate an EC\-Montgomery key (\fBCKK_EC_MONTGOMERY\fP), where .I CURVE specifies the montgomery curve used to create the EC\-Montgomery key. The following arguments can be used for respective curves: .BR curve25519 |\: curve448 . .PP .B Note: Not all curves are supported by all tokens and key generation fails when the specified .I CURVE is not supported. .PP The .BR \-\-label | \-L .IR LABEL | PUB\-LABEL : PRIV\-LABEL option sets the .B CKA_LABEL attribute of the key and the .BR \-\-attr | \-a .IR ATTRS | PUB\-ATTRS : PRIV\-ATTRS option can be used to set the boolean attributes of the key (see below for detailed description of the attributes). Optionally, set individual key attributes for public and private key separated by a colon (\fB:\fP). The .BR \-\-id | \-i .I ID option can be used to set the value of the .B CKA_ID attribute of the key. . .PP .SS "Generating IBM Dilithium keys" . .B p11sak .BR generate\-key | gen\-key | gen .BR ibm\-dilithium .I VERSION .BR \-\-slot | \-s .I SLOTID .RB [ \-\-pin | \-p .IR PIN ] .RB [ \-\-force\-pin\-prompt ] .RB [ \-\-no\-login | \-N ] .RB [ \-\-so ] .BR \-\-label | \-L .IR LABEL | PUB\-LABEL : PRIV\-LABEL .BR \-\-attr | \-a .IR ATTRS | PUB\-ATTRS : PRIV\-ATTRS .RB [ \-\-id | \-i .IR ID ] .RB [ \-\-help | \-h ] .PP Use the .BR generate\-key | gen\-key | gen .B ibm\-dilithium .I VERSION command and .I KEYTYPE argument to generate an IBM Dilithium key (\fBCKK_IBM_PQC_DILITHIUM\fP), where .I VERSION specifies the version of the IBM Dilithium keypair. The following arguments can be used for respective keys: .BR r2_65 |\: r2_87 |\: r3_44 |\: r3_65 |\: r3_87 .PP .B Note: Not all IBM Dilithium versions are supported by all tokens and key generation fails when the specified .I VERSION is not supported. .PP The .BR \-\-label | \-L .IR LABEL | PUB\-LABEL : PRIV\-LABEL option sets the .B CKA_LABEL attribute of the key and the .BR \-\-attr | \-a .I ATTRS can be used to set the boolean attributes of the key (see below for detailed description of the attributes). Optionally, set individual key attributes for public and private key separated by a colon (\fB:\fP). The .BR \-\-id | \-i .I ID option can be used to set the value of the .B CKA_ID attribute of the key. . .PP .SS "Generating IBM Kyber keys" . .B p11sak .BR generate\-key | gen\-key | gen .BR ibm\-kyber .I VERSION .BR \-\-slot | \-s .I SLOTID .RB [ \-\-pin | \-p .IR PIN ] .RB [ \-\-force\-pin\-prompt ] .RB [ \-\-no\-login | \-N ] .RB [ \-\-so ] .BR \-\-label | \-L .IR LABEL | PUB\-LABEL : PRIV\-LABEL .BR \-\-attr | \-a .IR ATTRS | PUB\-ATTRS : PRIV\-ATTRS .RB [ \-\-id | \-i .IR ID ] .RB [ \-\-help | \-h ] .PP Use the .BR generate\-key | gen\-key | gen .B ibm\-kyber .I VERSION command and .I KEYTYPE argument to generate an IBM Kyber key (\fBCKK_IBM_PQC_KYBER\fP), where .I VERSION specifies the version of the IBM Kyber keypair. The following arguments can be used for respective keys: .BR r2_768 | r2_1024 .PP .B Note: Not all IBM Kyber versions are supported by all tokens and key generation fails when the specified .I VERSION is not supported. .PP The .BR \-\-label | \-L .IR LABEL | PUB\-LABEL : PRIV\-LABEL option sets the .B CKA_LABEL attribute of the key and the .BR \-\-attr | \-a .I ATTRS can be used to set the boolean attributes of the key (see below for detailed description of the attributes). Optionally, set individual key attributes for public and private key separated by a colon (\fB:\fP). The .BR \-\-id | \-i .I ID option can be used to set the value of the .B CKA_ID attribute of the key. . .PP .SS "Generating IBM ML\-DSA keys" . .B p11sak .BR generate\-key | gen\-key | gen .BR ibm\-ml\-dsa .I VERSION .BR \-\-slot | \-s .I SLOTID .RB [ \-\-pin | \-p .IR PIN ] .RB [ \-\-force\-pin\-prompt ] .RB [ \-\-no\-login | \-N ] .RB [ \-\-so ] .BR \-\-label | \-L .IR LABEL | PUB\-LABEL : PRIV\-LABEL .BR \-\-attr | \-a .IR ATTRS | PUB\-ATTRS : PRIV\-ATTRS .RB [ \-\-id | \-i .IR ID ] .RB [ \-\-help | \-h ] .PP Use the .BR generate\-key | gen\-key | gen .B ibm\-ml\-dsa .I VERSION command and .I KEYTYPE argument to generate an IBM ML\-DSA key (\fBCKK_IBM_ML_DSA\fP), where .I VERSION specifies the version of the IBM ML\-DSA keypair. The following arguments can be used for respective keys: .BR 44 | 65 | 87 .PP .B Note: Not all IBM ML\-DSA versions will be supported by all tokens and key generation will fail when the specified .I VERSION is not supported. .PP The .BR \-\-label | \-L .IR LABEL | PUB\-LABEL : PRIV\-LABEL option sets the .B CKA_LABEL attribute of the key and the .BR \-\-attr | \-a .I ATTRS can be used to set the boolean attributes of the key (see below for detailed description of the attributes). Optionally, set individual key attributes for public and private key separated by a colon (\fB:\fP). The .BR \-\-id | \-i .I ID option can be used to set the value of the .B CKA_ID attribute of the key. . .PP .SS "Generating IBM ML\-KEM keys" . .B p11sak .BR generate\-key | gen\-key | gen .BR ibm\-ml\-kem .I VERSION .BR \-\-slot | \-s .I SLOTID .RB [ \-\-pin | \-p .IR PIN ] .RB [ \-\-force\-pin\-prompt ] .RB [ \-\-no\-login | \-N ] .RB [ \-\-so ] .BR \-\-label | \-L .IR LABEL | PUB\-LABEL : PRIV\-LABEL .BR \-\-attr | \-a .IR ATTRS | PUB\-ATTRS : PRIV\-ATTRS .RB [ \-\-id | \-i .IR ID ] .RB [ \-\-help | \-h ] .PP Use the .BR generate\-key | gen\-key | gen .B ibm\-ml\-kem .I VERSION command and .I KEYTYPE argument to generate an IBM ML\-KEM key (\fBCKK_IBM_ML_KEM\fP), where .I VERSION specifies the version of the IBM ML\-KEM keypair. The following arguments can be used for respective keys: .BR 512 | 768 | 1024 .PP .B Note: Not all IBM ML\-KEM versions will be supported by all tokens and key generation will fail when the specified .I VERSION is not supported. .PP The .BR \-\-label | \-L .IR LABEL | PUB\-LABEL : PRIV\-LABEL option sets the .B CKA_LABEL attribute of the key and the .BR \-\-attr | \-a .I ATTRS can be used to set the boolean attributes of the key (see below for detailed description of the attributes). Optionally, set individual key attributes for public and private key separated by a colon (\fB:\fP). The .BR \-\-id | \-i .I ID option can be used to set the value of the .B CKA_ID attribute of the key. . .PP .SS "Generating ML\-DSA keys" . .B p11sak .BR generate\-key | gen\-key | gen .BR ml\-dsa .I VERSION .BR \-\-slot | \-s .I SLOTID .RB [ \-\-pin | \-p .IR PIN ] .RB [ \-\-force\-pin\-prompt ] .RB [ \-\-no\-login | \-N ] .RB [ \-\-so ] .BR \-\-label | \-L .IR LABEL | PUB\-LABEL : PRIV\-LABEL .BR \-\-attr | \-a .IR ATTRS | PUB\-ATTRS : PRIV\-ATTRS .RB [ \-\-id | \-i .IR ID ] .RB [ \-\-help | \-h ] .PP Use the .BR generate\-key | gen\-key | gen .B ml\-dsa .I VERSION command and .I KEYTYPE argument to generate an ML\-DSA key (\fBCKK_ML_DSA\fP), where .I VERSION specifies the version of the ML\-DSA keypair. The following arguments can be used for respective keys: .BR 44 | 65 | 87 .PP .B Note: Not all ML\-DSA versions will be supported by all tokens and key generation will fail when the specified .I VERSION is not supported. .PP The .BR \-\-label | \-L .IR LABEL | PUB\-LABEL : PRIV\-LABEL option sets the .B CKA_LABEL attribute of the key and the .BR \-\-attr | \-a .I ATTRS can be used to set the boolean attributes of the key (see below for detailed description of the attributes). Optionally, set individual key attributes for public and private key separated by a colon (\fB:\fP). The .BR \-\-id | \-i .I ID option can be used to set the value of the .B CKA_ID attribute of the key. . .PP .SS "Generating ML\-KEM keys" . .B p11sak .BR generate\-key | gen\-key | gen .BR ml\-kem .I VERSION .BR \-\-slot | \-s .I SLOTID .RB [ \-\-pin | \-p .IR PIN ] .RB [ \-\-force\-pin\-prompt ] .RB [ \-\-no\-login | \-N ] .RB [ \-\-so ] .BR \-\-label | \-L .IR LABEL | PUB\-LABEL : PRIV\-LABEL .BR \-\-attr | \-a .IR ATTRS | PUB\-ATTRS : PRIV\-ATTRS .RB [ \-\-id | \-i .IR ID ] .RB [ \-\-help | \-h ] .PP Use the .BR generate\-key | gen\-key | gen .B ml\-kem .I VERSION command and .I KEYTYPE argument to generate an ML\-KEM key (\fBCKK_ML_KEM\fP), where .I VERSION specifies the version of the ML\-KEM keypair. The following arguments can be used for respective keys: .BR 512 | 768 | 1024 .PP .B Note: Not all ML\-KEM versions will be supported by all tokens and key generation will fail when the specified .I VERSION is not supported. .PP The .BR \-\-label | \-L .IR LABEL | PUB\-LABEL : PRIV\-LABEL option sets the .B CKA_LABEL attribute of the key and the .BR \-\-attr | \-a .I ATTRS can be used to set the boolean attributes of the key (see below for detailed description of the attributes). Optionally, set individual key attributes for public and private key separated by a colon (\fB:\fP). The .BR \-\-id | \-i .I ID option can be used to set the value of the .B CKA_ID attribute of the key. . .PP .SS "Listing symmetric and asymmetric keys" . .B p11sak .BR list\-key | ls\-key | ls .RI [ KEYTYPE ] .BR \-\-slot | \-s .I SLOTID .RB [ \-\-pin | \-p .IR PIN ] .RB [ \-\-force\-pin\-prompt ] .RB [ \-\-no\-login | \-N ] .RB [ \-\-so ] .RB [ \-\-label | \-L .IR LABEL ] .RB [ \-\-id | \-i .IR ID ] .RB [ \-\-attr | \-a .IR ATTRS ] .RB [ \-\-long | \-l ] .RB [ \-\-detailed\-uri ] .RB [ \-\-hsm\-mkvp | \-m ] .RB [ \-\-ep11\-session\-id | \-e ] .RB [ \-\-sort | \-S .IR SORT\-SPEC ] .RB [ \-\-help | \-h ] .PP Use the .BR list\-key | ls\-key | ls command and the optional .I KEYTYPE argument to list symmetric or asymmetric keys. Public, private, secret, or all keys can also be listed irrespective of the key type. .PP Possible values for the .I KEYTYPE argument are: .BR des |\: 3des |\: generic |\: sha\-1\-hmac |\: sha224\-hmac |\: \ sha256\-hmac |\: sha384\-hmac |\: sha512\-hmac |\: sha512/224\-hmac |\: \ sha512/256\-hmac |\: sha3\-224\-hmac |\: sha3\-256\-hmac |\: sha3\-384\-hmac \ |\: sha3\-512\-hmac |\: aes |\: aes\-xts |\: rsa |\: dh |\: dsa |\: ec |\: \ ec\-edwards |\: ec\-montgomery |\: ibm\-dilithium |\: ibm\-kyber |\: \ ibm\-ml\-dsa |\: ibm\-ml\-kem |\: ml\-dsa |\: ml\-kem |\: public |\: private \ |\: secret |\: all . If .I KEYTYPE is omitted, then all key types are listed. .PP Specify the .BR \-\-label | \-L .IR LABEL , the .BR \-\-id | \-i .IR ID , and/or the .BR \-\-attr | \-a .I ATTRS options to filter the list of keys to display. You can use wildcards (\fB*\fP and \fB?\fP) in the .I LABEL specification. To specify a wildcard character that should not be treated as a wildcard, it must be escaped using a backslash (\fB\e*\fP or \fB\e?\fP). Also, a backslash character that should not be treated as an escape character must be escaped (\fB\e\e\fP). The .B ID must be specified as hex string (not prefixed with 0x) of any number of bytes. .PP By default, the keys are listed in a short, tabular format showing only the boolean attributes, the key type (\fBCKA_KEY_TYPE\fP) and the key label (\fPCKA_LABEL\fP). The attributes are denoted using the same single letters as used with the .BR \-\-attr | \-a .IR ATTRS | PUB\-ATTRS : PRIV\-ATTRS option. When option .BR \-\-long | \-l is specified, the keys are listed in long format, displaying the values of all attributes defined for the key type, including non-boolean attributes. When option .BR \-\-hsm\-mkvp | \-m is specified, the HSM master key verification patterns (MKVPs) of the keys are displayed. This is only possible for secure key tokens, such as the CCA and EP11 tokens. When option .BR \-\-ep11\-session\-id | \-e is specified, the EP11 session-IDs of the keys are displayed. This is only possible for EP11 tokens. .PP By default, the keys are displayed in the order as they are retrieved from the PKCS\~#11 implementation. To display the keys in a certain order, specify the .BR \-\-sort | \-S .I SORT\-SPEC option. You can sort the keys by label, key type, object class, and/or key size. For details, see the description of the .BR \-\-sort | \-S .I SORT\-SPEC option below. . .PP .SS "Deleting symmetric and asymmetric keys" . .B p11sak .BR remove\-key | rm\-key | rm .RI [ KEYTYPE ] .BR \-\-slot | \-s .I SLOTID .RB [ \-\-pin | \-p .IR PIN ] .RB [ \-\-force\-pin\-prompt ] .RB [ \-\-no\-login | \-N ] .RB [ \-\-so ] .RB [ \-\-label | \-L .IR LABEL ] .RB [ \-\-id | \-i .IR ID ] .RB [ \-\-attr | \-a .IR ATTRS ] .RB [ \-\-long | \-l ] .RB [ \-\-force | \-f ] .RB [ \-\-help | \-h ] .PP Use the .BR remove\-key | rm\-key | rm command and the optional .I KEYTYPE argument to remove symmetric or asymmetric keys. Public, private, secret, or all keys can also be selected for removal irrespective of the key type. .PP Possible values for the .I KEYTYPE argument are: .BR des |\: 3des |\: generic |\: sha\-1\-hmac |\: sha224\-hmac |\: \ sha256\-hmac |\: sha384\-hmac |\: sha512\-hmac |\: sha512/224\-hmac |\: \ sha512/256\-hmac |\: sha3\-224\-hmac |\: sha3\-256\-hmac |\: sha3\-384\-hmac \ |\: sha3\-512\-hmac |\: aes |\: aes\-xts |\: rsa |\: dh |\: dsa |\: ec |\: \ ec\-edwards |\: ec\-montgomery |\: ibm\-dilithium |\: ibm\-kyber |\: \ ibm\-ml\-dsa |\: ibm\-ml\-kem |\: ml\-dsa |\: ml\-kem |\: public |\: private \ |\: secret |\: all . If .I KEYTYPE is omitted, then all key types are selected for removal. .PP Specify the .BR \-\-label | \-L .IR LABEL , the .BR \-\-id | \-i .IR ID , and/or the .BR \-\-attr | \-a .I ATTRS options to filter the list of keys to remove. You can use wildcards (\fB*\fP and \fB?\fP) in the .I LABEL specification. To specify a wildcard character that should not be treated as a wildcard, it must be escaped using a backslash (\fB\e*\fP or \fB\e?\fP). Also, a backslash character that should not be treated as an escape character must be escaped (\fB\e\e\fP). The .B ID must be specified as hex string (not prefixed with 0x) of any number of bytes. .PP The user is prompted to confirm the removal of the key. To suppress the prompt, use the .BR \-\-force | \-f option. .PP . .SS "Setting or updating attributes of symmetric and asymmetric keys" . .B p11sak .BR set\-key\-attr | set\-key | set .RI [ KEYTYPE ] .BR \-\-slot | \-s .I SLOTID .RB [ \-\-pin | \-p .IR PIN ] .RB [ \-\-force\-pin\-prompt ] .RB [ \-\-no\-login | \-N ] .RB [ \-\-so ] .RB [ \-\-label | \-L .IR LABEL ] .RB [ \-\-id | \-i .IR ID ] .RB [ \-\-attr | \-a .IR ATTRS ] .RB [ \-\-force | \-f ] .RB [ \-\-new\-attr | \-A .IR ATTRS ] .RB [ \-\-new\-label | \-l .IR LABEL ] .RB [ \-\-new\-id | \-I .IR ID ] .RB [ \-\-help | \-h ] .PP Use the .B set\-key\-attrs | set\-key | set command and the optional .I KEYTYPE argument to set or update boolean attributes of symmetric or asymmetric keys. Public, private, secret, or all keys can also be selected for updating irrespective of the key type. .PP Possible values for the .I KEYTYPE argument are: .BR des |\: 3des |\: generic |\: sha\-1\-hmac |\: sha224\-hmac |\: \ sha256\-hmac |\: sha384\-hmac |\: sha512\-hmac |\: sha512/224\-hmac |\: \ sha512/256\-hmac |\: sha3\-224\-hmac |\: sha3\-256\-hmac |\: sha3\-384\-hmac \ |\: sha3\-512\-hmac |\: aes |\: aes\-xts |\: rsa |\: dh |\: dsa |\: ec |\: \ ec\-edwards |\: ec\-montgomery |\: ibm\-dilithium |\: ibm\-kyber |\: \ ibm\-ml\-dsa |\: ibm\-ml\-kem |\: ml\-dsa |\: ml\-kem |\: public |\: private \ |\: secret |\: all . If .I KEYTYPE is omitted, then all key types are selected for updating. .PP Specify the .BR \-\-label | \-L .IR LABEL , the .BR \-\-id | \-i .IR ID , and/or the .BR \-\-attr | \-a .I ATTRS options to filter the list of keys to set or update. You can use wildcards (\fB*\fP and \fB?\fP) in the .I LABEL specification. To specify a wildcard character that should not be treated as a wildcard, it must be escaped using a backslash (\fB\e*\fP or \fB\e?\fP). Also, a backslash character that should not be treated as an escape character must be escaped (\fB\e\e\fP). The .B ID must be specified as hex string (not prefixed with 0x) of any number of bytes. .PP Use the .BR \-\-new\-attr | \-A .I ATTRS option to specify the boolean attributes of the key you want to update (see below for detailed description of the attributes). Attributes that are not specified are not changed. Use the .BR \-\-new\-label | \-l .I LABEL option to specify the new label, or the .BR \-\-new\-id | \-I .I ID option to specify the new ID to set for the key. At least one of the .BR \-\-new\-attr | \-A .IR ATTRS , .BR \-\-new\-label | \-l .IR LABEL , or .BR \-\-new\-id | \-I .I ID options must be specified. .PP The user is prompted to confirm the updating of the key. To suppress the prompt, use the .BR \-\-force | \-f option. .PP . .SS "Coyping symmetric and asymmetric keys" . .B p11sak .BR copy\-key | copy | cp .RI [ KEYTYPE ] .BR \-\-slot | \-s .I SLOTID .RB [ \-\-pin | \-p .IR PIN ] .RB [ \-\-force\-pin\-prompt ] .RB [ \-\-no\-login | \-N ] .RB [ \-\-so ] .RB [ \-\-label | \-L .IR LABEL ] .RB [ \-\-id | \-i .IR ID ] .RB [ \-\-attr | \-a .IR ATTRS ] .RB [ \-\-force | \-f ] .RB [ \-\-new\-attr | \-A .IR ATTRS ] .RB [ \-\-new\-label | \-l .IR LABEL ] .RB [ \-\-new\-id | \-I .IR ID ] .RB [ \-\-help | \-h ] .PP Use the .B copy\-key | copy | cp command and the optional .I KEYTYPE argument to copy symmetric or asymmetric keys and optionally set or change boolean attributes, the label, or ID of the copied keys. Public, private, secret, or all keys can also be copied irrespective of the key type. .PP Possible values for the .I KEYTYPE argument are: .BR des |\: 3des |\: generic |\: sha\-1\-hmac |\: sha224\-hmac |\: \ sha256\-hmac |\: sha384\-hmac |\: sha512\-hmac |\: sha512/224\-hmac |\: \ sha512/256\-hmac |\: sha3\-224\-hmac |\: sha3\-256\-hmac |\: sha3\-384\-hmac \ |\: sha3\-512\-hmac |\: aes |\: aes\-xts |\: rsa |\: dh |\: dsa |\: ec |\: \ ec\-edwards |\: ec\-montgomery |\: ibm\-dilithium |\: ibm\-kyber |\: \ ibm\-ml\-dsa |\: ibm\-ml\-kem |\: ml\-dsa |\: ml\-kem |\: public |\: private \ |\: secret |\: all . If .I KEYTYPE is omitted, then all key types are selected for copying. .PP Specify the .BR \-\-label | \-L .IR LABEL , the .BR \-\-id | \-i .IR ID , and/or the .BR \-\-attr | \-a .I ATTRS options to filter the list of keys to copy. You can use wildcards (\fB*\fP and \fB?\fP) in the .I LABEL specification. To specify a wildcard character that should not be treated as a wildcard, it must be escaped using a backslash (\fB\e*\fP or \fB\e?\fP). Also, a backslash character that should not be treated as an escape character must be escaped (\fB\e\e\fP). The .B ID must be specified as hex string (not prefixed with 0x) of any number of bytes. .PP Use the .BR \-\-new\-attr | \-A .I ATTRS option to specify the boolean attributes of the copied key you want to set or update (see below for detailed description of the attributes). Attributes that are not specified are not changed. Use the .BR \-\-new\-label | \-l .I LABEL option to specify the new label, or the .BR \-\-new\-id | \-I .I ID option to specify the new ID to set for the copied key. .PP The user is prompted to confirm the copying of the key. To suppress the prompt, use the .BR \-\-force | \-f option. .PP . .SS "Importing symmetric and asymmetric keys from a file" . .B p11sak .BR import\-key | import | imp .I KEYTYPE .RI [ KIND ] .BR \-\-slot | \-s .I SLOTID .RB [ \-\-pin | \-p .IR PIN ] .RB [ \-\-force\-pin\-prompt ] .RB [ \-\-no\-login | \-N ] .RB [ \-\-so ] .BR \-\-label | \-L .I LABEL .RB [ \-\-id | \-i .IR ID ] .RB [ \-\-force | \-f ] .RB [ \-\-attr | \-a .IR ATTRS ] .BR \-\-file | \-F .I FILENAME .RB [ \-\-pem\-password | \-P .IR PASSWORD ] .RB [ \-\-force\-pem\-pwd\-prompt ] .RB [ \-\-opaque | \-o ] .RB [ \-\-oqsprovider\-pem ] .RB [ \-\-help | \-h ] .PP Use the .BR import\-key | import | imp command and .I KEYTYPE argument to import an symmetric or asymmetric key from a file. When importing an asymmetric key, the .I KIND argument is required and specifies to either import a .B private or .B public key. .PP Possible values for the .I KEYTYPE argument are: .BR des |\: 3des |\: generic |\: sha\-1\-hmac |\: sha224\-hmac |\: \ sha256\-hmac |\: sha384\-hmac |\: sha512\-hmac |\: sha512/224\-hmac |\: \ sha512/256\-hmac |\: sha3\-224\-hmac |\: sha3\-256\-hmac |\: sha3\-384\-hmac \ |\: sha3\-512\-hmac |\: aes |\: aes\-xts |\: rsa |\: dh |\: dsa |\: ec |\: \ ec\-edwards |\: ec\-montgomery |\: ibm\-dilithium |\: ibm\-kyber |\: \ ibm\-ml\-dsa |\: ibm\-ml\-kem |\: ml\-dsa |\: ml\-kem |\: public |\: private \ |\: secret |\: all . .PP The .BR \-\-label | \-L .IR LABEL option sets the .B CKA_LABEL attribute of the key and the .BR \-\-attr | \-a .I ATTRS can be used to set the boolean attributes of the key (see below for detailed description of the attributes). The .BR \-\-id | \-i .I ID option can be used to set the value of the .B CKA_ID attribute of the key. .PP The .BR \-\-file | \-F .I FILENAME option specifies the file name of the file that contains the key to be imported. For symmetric keys, this is a binary file containing the key material in clear. For asymmetric keys, this is an OpenSSL PEM file containing a public or private key. PEM files can optionally be password protected. Specify the PEM password with the .BR \-\-pem\-password | \-P .I PASSWORD option or environment variable .BR P11SAK_PEM_PASSWORD . If the PEM file is password protected, but no PEM password is specified, you are prompted for the PEM password. Specify the .BR \-\-opaque | \-o option to import an opaque secure key blob. Not all tokens support this. .PP Specify the .BR \-\-oqsprovider\-pem option when the key material in the PEM file is in the .B oqsprovider format. This option is only valid for the .B ibm\-dilithium keytype. PEM files in .B oqsprovider format are only supported when the .B oqsprovider from .B https://github.com/open\-quantum\-safe/oqs\-provider has been configured with OpenSSL 3.0 or later. This is an experimental feature, it may change in an incompatible way in the future! . .SS "Exporting symmetric and asymmetric keys to a file" . .B p11sak .BR export\-key | export | exp .RI [ KEYTYPE ] .BR \-\-slot | \-s .I SLOTID .RB [ \-\-pin | \-p .IR PIN ] .RB [ \-\-force\-pin\-prompt ] .RB [ \-\-no\-login | \-N ] .RB [ \-\-so ] .RB [ \-\-label | \-L .IR LABEL ] .RB [ \-\-id | \-i .IR ID ] .RB [ \-\-attr | \-a .IR ATTRS ] .RB [ \-\-force | \-f ] .BR \-\-file | \-F .I FILENAME .RB [ \-\-encrypted\-pem | \-e ] .RB [ \-\-pem\-password | \-P .IR PASSWORD ] .RB [ \-\-force\-pem\-pwd\-prompt ] .RB [ \-\-opaque | \-o ] .RB [ \-\-spki | \-S ] .RB [ \-\-uri\-pem | \-u ] .RB [ \-\-uri\-pin\-value ] .RB [ \-\-uri\-pin\-source .IR FILENAME ] .RB [ \-\-oqsprovider\-pem ] .RB [ \-\-help | \-h ] .PP Use the .BR export\-key | export | exp command and the optional .I KEYTYPE argument to export symmetric or asymmetric keys to a file. Public, private, secret, or all keys can also be selected for export irrespective of the key type. .PP Possible values for the .I KEYTYPE argument are: .BR des |\: 3des |\: generic |\: sha\-1\-hmac |\: sha224\-hmac |\: \ sha256\-hmac |\: sha384\-hmac |\: sha512\-hmac |\: sha512/224\-hmac |\: \ sha512/256\-hmac |\: sha3\-224\-hmac |\: sha3\-256\-hmac |\: sha3\-384\-hmac \ |\: sha3\-512\-hmac |\: aes |\: aes\-xts |\: rsa |\: dh |\: dsa |\: ec |\: \ ec\-edwards |\: ec\-montgomery |\: ibm\-dilithium |\: ibm\-kyber |\: \ ibm\-ml\-dsa |\: ibm\-ml\-kem |\: ml\-dsa |\: ml\-kem |\: public |\: private \ |\: secret |\: all . If .I KEYTYPE is omitted, then all key types are selected for export. .PP Specify the .BR \-\-label | \-L .IR LABEL , the .BR \-\-id | \-i .IR ID , and/or the .BR \-\-attr | \-a .I ATTRS options to filter the list of keys to export. You can use wildcards (\fB*\fP and \fB?\fP) in the .I LABEL specification. To specify a wildcard character that should not be treated as a wildcard, it must be escaped using a backslash (\fB\e*\fP or \fB\e?\fP). Also, a backslash character that should not be treated as an escape character must be escaped (\fB\e\e\fP). The .B ID must be specified as hex string (not prefixed with 0x) of any number of bytes. .PP The .BR \-\-file | \-F .I FILENAME option specifies the file name of the file to which the keys to be exported are written to. For symmetric keys, this is a binary file where the key material in clear is written to. For asymmetric keys, this is an OpenSSL PEM file where the public or private keys are written to. If multiple asymmetric keys match the filter, the keys are appended to the PEM file specified with the .BR \-\-file | \-F .I FILENAME option. If multiple symmetric keys or a mixture of asymmetric and symmetric keys match the filter, you are prompted to confirm to overwrite the previously created file, unless the .BR \-\-force | \-f option is specified. .PP Private keys in PEM files can optionally be password protected. Specify the .BR \-\-encrypted\-pem | \-e option to encrypt the exported private keys using .B AES\-CBC and an .B AES 256 bit key derived from a password via .BR PBKDF2 . Specify the PEM password with the .BR \-\-pem\-password | \-P .I PASSWORD option or environment variable .BR P11SAK_PEM_PASSWORD , otherwise you are prompted for the PEM password. .PP Specify the .BR \-\-opaque | \-o option to export the opaque secure key blobs of the key. Not all tokens support this. .PP Specify the .BR \-\-spki | \-S option to export the Subject Public Key Info (SPKI) from the .B CKA_PUBLIC_KEY_INFO attribute of an asymmetric private key instead of its private key material. This option can only be used with private keys. .PP Specify the .BR \-\-oqsprovider\-pem option when the key material is to be exported in .B oqsprovider format into the PEM file. This option is only valid for the .B ibm\-dilithium keytype. PEM files in .B oqsprovider format are only supported when the .B oqsprovider from .B https://github.com/open\-quantum\-safe/oqs\-provider has been configured with OpenSSL 3.0 or later. This is an experimental feature, it may change in an incompatible way in the future! .PP .B Note: Not all keys can be exported, because its attribute setting may forbid to reveal the values of certain attributes. To allow exporting of a secret .RB ( CKO_SECRET_KEY ) or private .RB ( CKO_PRIVATE_KEY ) key, attribute .B CKA_SENSITIVE must be .B CK_FALSE and attribute .B CKA_EXTRACTABLE must be .BR CK_TRUE . Secret or private keys that contain an opaque secure key blob (attribute .BR CKA_IBM_OPAQUE ) can also not be exported in clear, even if the attributes would allow it. For such keys only the opaque secure key blob can be exported by using the .BR \-\-opaque | \-o option. .PP Specify the .BR \-\-uri\-pem | \-u option to export the PKCS#11 URI of the key in PEM form instead of the key material. Such an URI-PEM file can then be used with the .B pkcs11\-provider from .BR https://github.com/latchset/pkcs11\-provider . By default, the PKCS#11 URI does not contain the PKCS#11 user pin. Specify option .B \-\-uri\-pin\-value to include the PKCS#11 user pin in the URI using the .B pin\-value query attribute. This reveals the PKCS#11 user pin in clear, use with care! Alternatively, specify option .B \-\-uri\-pin\-source .I FILENAME to include the .B pin\-source query attribute in the URI, referencing the file name specified with this option. The PKCS#11 user pin value is written into that file as part of the export operation. This reveals the PKCS#11 user pin in clear, use with care! Adjust the file permissions of the specified pin\-source file so that it can only be read by the desired user(s). By default the file permissions are set so that only the owner user can read and write that file, but no one else (i.e. 0600). . . . .SS "Extracting the public key of private key objects" . .B p11sak .BR extract\-pubkey | extr\-pubkey | expub .RI [ KEYTYPE ] .BR \-\-slot | \-s .I SLOTID .RB [ \-\-pin | \-p .IR PIN ] .RB [ \-\-force\-pin\-prompt ] .RB [ \-\-no\-login | \-N ] .RB [ \-\-so ] .RB [ \-\-label | \-L .IR LABEL ] .RB [ \-\-id | \-i .IR ID ] .RB [ \-\-attr | \-a .IR ATTRS ] .RB [ \-\-new\-attr | \-A .IR ATTRS ] .RB [ \-\-new\-label | \-l .IR LABEL ] .RB [ \-\-new\-id | \-I .IR ID ] .RB [ \-\-force | \-f ] .RB [ \-\-help | \-h ] .PP Use the .BR extract\-pubkey | extr\-pubkey | expub command and the optional .I KEYTYPE argument to extract the public key from private key objects and save it as new token object. .PP Possible values for the .I KEYTYPE argument are: .BR rsa |\: dh |\: dsa |\: ec |\: ec\-edwards |\: ec\-montgomery |\: \ ibm\-dilithium |\: ibm\-kyber |\: ibm\-ml\-dsa |\: ibm\-ml\-kem |\: ml\-dsa \ |\: ml\-kem |\: private |\: all . If .I KEYTYPE is omitted, then all private key types are selected for export. .PP Specify the .BR \-\-label | \-L .IR LABEL , the .BR \-\-id | \-i .IR ID , and/or the .BR \-\-attr | \-a .I ATTRS options to filter the private keys of which the public keys are to be extracted. You can use wildcards (\fB*\fP and \fB?\fP) in the .I LABEL specification. To specify a wildcard character that should not be treated as a wildcard, it must be escaped using a backslash (\fB\e*\fP or \fB\e?\fP). Also, a backslash character that should not be treated as an escape character must be escaped (\fB\e\e\fP). The .B ID must be specified as hex string (not prefixed with 0x) of any number of bytes. .PP Use the .BR \-\-new\-attr | \-A .I ATTRS option to specify the boolean attributes of the public key object you want to set (see below for detailed description of the attributes). Use the .BR \-\-new\-label | \-l .I LABEL option to specify the new label. If no new label is specified, the label of the public key object is derived from the private key label by appending .BR _pubkey . .PP Use the .BR \-\-new\-id | \-I .I ID option to set an ID for the extracted public key object. .PP The user is prompted to confirm the extraction of the public key from the private key objects. To suppress the prompt, use the .BR \-\-force | \-f option. .PP . . . .SS "Exporting a key by wrapping it with a key encrypting key" . .B p11sak .BR wrap\-key | wrap .I WRAP\-MECH .RI [ KEYTYPE ] .BR \-\-slot | \-s .I SLOTID .RB [ \-\-pin | \-p .IR PIN ] .RB [ \-\-force\-pin\-prompt ] .RB [ \-\-no\-login | \-N ] .RB [ \-\-so ] .RB [ \-\-kek\-label | \-K .IR LABEL ] .RB [ \-\-kek\-id | \-k .IR ID ] .RB [ \-\-label | \-L .IR LABEL ] .RB [ \-\-id | \-i .IR ID ] .RB [ \-\-attr | \-a .IR ATTRS ] .RB [ \-\-force | \-f ] .BR \-\-file | \-F .I FILENAME .RB [ \-\-raw | \-R ] .RB [ "options specific for" .IR WRAP\-MECH ] .RB [ \-\-help | \-h ] .PP Use the .BR wrap\-key | wrap command and the .I WRAP\-MECH argument to export symmetric or asymmetric keys by wrapping it with a key encrypting key. Dependent on the key wrapping mechanism, additional options may be supported to specify mechanism parameters. The optional .I KEYTYPE argument can be used to filter the list of keys to export by key type. Only private and secret keys can be wrapped. Possible values for the .I KEYTYPE argument are: .BR des |\: 3des |\: generic |\: sha\-1\-hmac |\: sha224\-hmac |\: \ sha256\-hmac |\: sha384\-hmac |\: sha512\-hmac |\: sha512/224\-hmac |\: \ sha512/256\-hmac |\: sha3\-224\-hmac |\: sha3\-256\-hmac |\: sha3\-384\-hmac \ |\: sha3\-512\-hmac |\: aes |\: aes\-xts |\: rsa |\: dh |\: dsa |\: ec |\: \ ec\-edwards |\: ec\-montgomery |\: ibm\-dilithium |\: ibm\-kyber |\: \ ibm\-ml\-dsa |\: ibm\-ml\-kem |\: ml\-dsa |\: ml\-kem |\: private |\: secret \ |\: all . If .I KEYTYPE is omitted, then all key types are selected for wrapping. .PP Possible values for the .I WRAP\-MECH argument are: .IP "\(bu" 2 .BR aes\-cbc\-pad : Use mechanism .B CKM_AES_CBC_PAD for key wrapping. Wrapping and unwrapping is done with an AES key. Use the .BR \-\-iv | \-I .I IV option to specify the initialization vector (IV) for the AES\-CBC operation. .IP "\(bu" 2 .BR aeskw\-kwp : Use mechanism .B CKM_AES_KEY_WRAP_KWP for key wrapping. Wrapping and unwrapping is done with an AES key. Use the .BR \-\-iv | \-I .I IV option to specify the initialization vector (IV) for the AESKW\-KWP operation. .IP "\(bu" 2 .BR aeskw\-pkcs7 : Use mechanism .B CKM_AES_KEY_WRAP_PKCS7 for key wrapping. Wrapping and unwrapping is done with an AES key. Use the .BR \-\-iv | \-I .I IV option to specify the initialization vector (IV) for the AESKW\-PKCS7 operation. .IP "\(bu" 2 .BR rsa\-pkcs : Use mechanism .B CKM_RSA_PKCS for key wrapping. Wrapping is done with an RSA public key, unwrapping is done with the corresponding RSA private key. Only keys whose key material size is up to the KEK's RSA modulus size minus 11 bytes can be wrapped with this mechanism. .IP "\(bu" 2 .BR rsa\-oaep : Use mechanism .B CKM_RSA_PKCS_OAEP for key wrapping. Wrapping is done with an RSA public key, unwrapping is done with the corresponding RSA private key. Only keys whose key material size is up to the KEK's RSA modulus size minus 2 times the hash\-alg digest size bytes minus 2 bytes wrapped with this mechanism. Use the .BR \-\-hash\-alg .IR HASH\-ALG , .BR \-\-mgf\-alg .IR MGF\-ALG , and .B \-\-source\-data .IR SOURCE\-DATA , options to specify the OAEP mechanism parameters. .IP "\(bu" 2 .BR rsa\-aeskw : Use mechanism .B CKM_RSA_AES_KEY_WRAP for key wrapping. Wrapping is done with an RSA public key, unwrapping is done with the corresponding RSA private key. Use the .BR \-\-aes\-key\-size .I AES\-KEYBITS option to specify the key size of the temporary AES key, and the .BR \-\-hash\-alg .IR HASH\-ALG , .BR \-\-mgf\-alg .IR MGF\-ALG , and .B \-\-source\-data .IR SOURCE\-DATA , options to specify the OAEP mechanism parameters. .IP "\(bu" 2 .BR ecdh\-aeskw , .BR ecdh\-cof\-aeskw , and .BR ecdh\-x\-aeskw : Use mechanisms .BR CKM_ECDH_AES_KEY_WRAP , .BR CKM_ECDH_COF_AES_KEY_WRAP , and .B CKM_ECDH_X_AES_KEY_WRAP respectively for key wrapping. Wrapping is done with an EC or EC-Montgomery public key (for .BR ecdh\-aeskw ), an EC public key (for .BR ecdh\-cof\-aeskw ), or an EC-Montgomery public key (for .BR ecdh\-x\-aeskw ). Unwrapping is done with the corresponding EC or EC-Montgomery private key (for .BR ecdh\-aeskw ), an EC private key (for .BR ecdh\-cof\-aeskw ), or an EC-Montgomery private key (for .BR ecdh\-x\-aeskw ). Use the .BR \-\-aes\-key\-size .I AES\-KEYBITS option to specify the key size of the temporary AES key, and the .BR \-\-kdf\-alg .IR KDF\-ALG , and .B \-\-shared\-data .IR SHARED\-DATA , options to specify the ECDH mechanism parameters. .PP Specify the .BR \-\-kek\-label | \-K .IR LABEL , and/or the .BR \-\-kek\-id | \-k .IR ID option to select the key encrypting key (KEK). Only keys with the right object class and key type that fit to the wrapping mechanism are selected. If multiple key objects match, you are prompted to confirm to use the desired key object. If the .BR \-\-force | \-f option is specified, then the first matching key object is used. You can use wildcards (\fB*\fP and \fB?\fP) in the .I LABEL specification. To specify a wildcard character that should not be treated as a wildcard, it must be escaped using a backslash (\fB\e*\fP or \fB\e?\fP). Also, a backslash character that should not be treated as an escape character must be escaped (\fB\e\e\fP). The .B ID must be specified as hex string (not prefixed with 0x) of any number of bytes. .PP Specify the .BR \-\-label | \-L .IR LABEL , the .BR \-\-id | \-i .IR ID , and/or the .BR \-\-attr | \-a .I ATTRS options to filter the list of keys to wrap. You can use wildcards (\fB*\fP and \fB?\fP) in the .I LABEL specification. To specify a wildcard character that should not be treated as a wildcard, it must be escaped using a backslash (\fB\e*\fP or \fB\e?\fP). Also, a backslash character that should not be treated as an escape character must be escaped (\fB\e\e\fP). The .B ID must be specified as hex string (not prefixed with 0x) of any number of bytes. .PP The .BR \-\-file | \-F .I FILENAME option specifies the file name of the file to which the wrapped key material is written to. By default this is a PEM file using a p11sak-specific type and a header that contains information about the wrapping mechanism and mechanism parameters (if any). If option .BR \-\-raw | \-R is specified then the file is a raw binary file and the raw wrapped key material is written to it. If multiple keys match the filter, the keys are appended to the PEM file specified with the .BR \-\-file | \-F .I FILENAME option. If option .BR \-\-raw | \-R is specified, and multiple keys match the filter, you are prompted to confirm to overwrite the previously created file, unless the .BR \-\-force | \-f option is specified. .PP .B Note: Not all keys can be wrapped, because its attribute setting may forbid to extract the key material. To allow exporting of a secret .RB ( CKO_SECRET_KEY ) or private .RB ( CKO_PRIVATE_KEY ) key, attribute .B CKA_EXTRACTABLE must be .BR CK_TRUE . A token may not support all wrapping mechanisms, nor all mechanism parameter combinations. Also, not all tokens may support to wrap all key types. Furthermore, a token might limit the support of wrapping a key with a weaker key encrypting key. . . . .SS "Importing a key by unwrapping it with a key encrypting key" . .B p11sak .BR unwrap\-key | unwrap .RI [ WRAP\-MECH ] .RI [ KEYTYPE ] .BR \-\-slot | \-s .I SLOTID .RB [ \-\-pin | \-p .IR PIN ] .RB [ \-\-force\-pin\-prompt ] .RB [ \-\-no\-login | \-N ] .RB [ \-\-so ] .RB [ \-\-kek\-label | \-K .IR LABEL ] .RB [ \-\-kek\-id | \-k .IR ID ] .RB [ \-\-label | \-L .IR LABEL ] .RB [ \-\-id | \-i .IR ID ] .RB [ \-\-attr | \-a .IR ATTRS ] .RB [ \-\-force | \-f ] .BR \-\-file | \-F .I FILENAME .RB [ \-\-raw | \-R ] .RB [ "options specific for" .IR WRAP\-MECH ] .RB [ \-\-help | \-h ] .PP Use the .BR unwrap\-key | unwrap command and the optional .I WRAP\-MECH and .I KEYTYPE arguments to import symmetric or asymmetric keys by unwrapping it with a key encrypting key. Dependent on the key wrapping mechanism, additional options may be supported to specify mechanism parameters. Only private and secret keys can be unwrapped. .PP Arguments .I WRAP\-MECH and .IR KEYTYPE , as well as wrapping mechanism specific options to specify mechanism parameters are only required if the .BR \-\-raw | \-R option is specified. Otherwise this information is read from the PEM file specified with the .BR \-\-file | \-F .I FILENAME option. .PP Possible values for the .I WRAP\-MECH argument are: .IP "\(bu" 2 .BR aes\-cbc\-pad : Use mechanism .B CKM_AES_CBC_PAD for key wrapping. Wrapping and unwrapping is done with an AES key. Use the .BR \-\-iv | \-I .I IV option to specify the initialization vector (IV) for the AES\-CBC operation. .IP "\(bu" 2 .BR aeskw\-kwp : Use mechanism .B CKM_AES_KEY_WRAP_KWP for key wrapping. Wrapping and unwrapping is done with an AES key. Use the .BR \-\-iv | \-I .I IV option to specify the initialization vector (IV) for the AESKW\-KWP operation. .IP "\(bu" 2 .BR aeskw\-pkcs7 : Use mechanism .B CKM_AES_KEY_WRAP_PKCS7 for key wrapping. Wrapping and unwrapping is done with an AES key. Use the .BR \-\-iv | \-I .I IV option to specify the initialization vector (IV) for the AESKW\-PKCS7 operation. .IP "\(bu" 2 .BR rsa\-pkcs : Use mechanism .B CKM_RSA_PKCS for key wrapping. Wrapping is done with an RSA public key, unwrapping is done with the corresponding RSA private key. Only keys whose key material size is up to the KEK's RSA modulus size minus 11 bytes can be wrapped with this mechanism. .IP "\(bu" 2 .BR rsa\-oaep : Use mechanism .B CKM_RSA_PKCS_OAEP for key wrapping. Wrapping is done with an RSA public key, unwrapping is done with the corresponding RSA private key. Only keys whose key material size is up to the KEK's RSA modulus size minus 2 times the hash\-alg digest size bytes minus 2 bytes wrapped with this mechanism. Use the .BR \-\-hash\-alg .IR HASH\-ALG , .BR \-\-mgf\-alg .IR MGF\-ALG , and .B \-\-source\-data .IR SOURCE\-DATA , options to specify the OAEP mechanism parameters. .IP "\(bu" 2 .BR rsa\-aeskw : Use mechanism .B CKM_RSA_AES_KEY_WRAP for key wrapping. Wrapping is done with an RSA public key, unwrapping is done with the corresponding RSA private key. Use the .BR \-\-aes\-key\-size .I AES\-KEYBITS option to specify the key size of the temporary AES key, and the .BR \-\-hash\-alg .IR HASH\-ALG , .BR \-\-mgf\-alg .IR MGF\-ALG , and .B \-\-source\-data .IR SOURCE\-DATA , options to specify the OAEP mechanism parameters. .IP "\(bu" 2 .BR ecdh\-aeskw , .BR ecdh\-cof\-aeskw , and .BR ecdh\-x\-aeskw : Use mechanisms .BR CKM_ECDH_AES_KEY_WRAP , .BR CKM_ECDH_COF_AES_KEY_WRAP , and .B CKM_ECDH_X_AES_KEY_WRAP respectively for key wrapping. Wrapping is done with an EC or EC-Montgomery public key (for .BR ecdh\-aeskw ), an EC public key (for .BR ecdh\-cof\-aeskw ), or an EC-Montgomery public key (for .BR ecdh\-x\-aeskw ). Unwrapping is done with the corresponding EC or EC-Montgomery private key (for .BR ecdh\-aeskw ), an EC private key (for .BR ecdh\-cof\-aeskw ), or an EC-Montgomery private key (for .BR ecdh\-x\-aeskw ). Use the .BR \-\-aes\-key\-size .I AES\-KEYBITS option to specify the key size of the temporary AES key, and the .BR \-\-kdf\-alg .IR KDF\-ALG , and .B \-\-shared\-data .IR SHARED\-DATA , options to specify the ECDH mechanism parameters. .PP Possible values for the .I KEYTYPE argument are: .BR des |\: 3des |\: generic |\: sha\-1\-hmac |\: sha224\-hmac |\: \ sha256\-hmac |\: sha384\-hmac |\: sha512\-hmac |\: sha512/224\-hmac |\: \ sha512/256\-hmac |\: sha3\-224\-hmac |\: sha3\-256\-hmac |\: sha3\-384\-hmac \ |\: sha3\-512\-hmac |\: aes |\: aes\-xts |\: rsa |\: dh |\: dsa |\: ec |\: \ ec\-edwards |\: ec\-montgomery |\: ibm\-dilithium |\: ibm\-kyber |\: \ ibm\-ml\-dsa |\: ibm\-ml\-kem |\: ml\-dsa |\: ml\-kem . .PP Specify the .BR \-\-kek\-label | \-K .IR LABEL , and/or the .BR \-\-kek\-id | \-k .IR ID option to select the key encrypting key (KEK). Only keys with the right object class and key type that fit to the wrapping mechanism are selected. If multiple key objects match, you are prompted to confirm to use the desired key object. If the .BR \-\-force | \-f option is specified, then the first matching key object is used. You can use wildcards (\fB*\fP and \fB?\fP) in the .I LABEL specification. To specify a wildcard character that should not be treated as a wildcard, it must be escaped using a backslash (\fB\e*\fP or \fB\e?\fP). Also, a backslash character that should not be treated as an escape character must be escaped (\fB\e\e\fP). The .B ID must be specified as hex string (not prefixed with 0x) of any number of bytes. .PP The .BR \-\-label | \-L .I LABEL option sets the .B CKA_LABEL attribute of the unwrapped key and the .BR \-\-attr | \-a .I ATTRS option can be used to set the boolean attributes of the unwrapped key (see below for detailed description of the attributes). The .BR \-\-id | \-i .I ID option can be used to set the value of the .B CKA_ID attribute of the unwrapped key. .PP The .BR \-\-file | \-F .I FILENAME option specifies the file name of the file containing the wrapped key material. By default this is a PEM file using a p11sak-specific type and a header that contains information about the wrapping mechanism and mechanism parameters (if any). If option .BR \-\-raw | \-R is specified then the file is a raw binary file and the raw wrapped key material is contained. In this case, arguments .I WRAP\-MECH and .IR KEYTYPE , as well as wrapping mechanism specific options to specify mechanism parameters are required. .PP .B Note: A token may not support all wrapping mechanisms, nor all mechanism parameter combinations. Also, not all tokens may support to unwrap all key types. . . . .PP .SS "Listing certificates" . .B p11sak .BR list\-cert | ls\-cert | lsc .RI [ CERTTYPE ] .BR \-\-slot | \-s .I SLOTID .RB [ \-\-pin | \-p .IR PIN ] .RB [ \-\-force\-pin\-prompt ] .RB [ \-\-no\-login | \-N ] .RB [ \-\-so ] .RB [ \-\-label | \-L .IR LABEL ] .RB [ \-\-id | \-i .IR ID ] .RB [ \-\-attr | \-a .IR ATTRS ] .RB [ \-\-long | \-l ] .RB [ \-\-detailed\-uri ] .RB [ \-\-sort | \-S .IR SORT\-SPEC ] .RB [ \-\-help | \-h ] .PP Use the .BR list\-cert | ls\-cert | lsc command and the optional .I CERTTYPE argument to list certificates. .PP Possible values for the .I CERTTYPE argument are: .BR x509 . If .I CERTTYPE is omitted, then x509 certificates are listed by default, because no other certificate types are supported. .PP Specify the .BR \-\-label | \-L .IR LABEL , the .BR \-\-id | \-i .IR ID , and/or the .BR \-\-attr | \-a .I ATTRS options to filter the list of certificates to display. You can use wildcards (\fB*\fP and \fB?\fP) in the .I LABEL specification. To specify a wildcard character that should not be treated as a wildcard, it must be escaped using a backslash (\fB\e*\fP or \fB\e?\fP). Also, a backslash character that should not be treated as an escape character must be escaped (\fB\e\e\fP). The .B ID must be specified as hex string (not prefixed with 0x) of any number of bytes. .PP By default, the certificates are listed in a short, tabular format showing only the boolean attributes, the certificate type (\fBCKA_CERTIFICATE_TYPE\fP) and the certificate label (\fPCKA_LABEL\fP). The attributes are denoted using the same single letters as used with the .BR \-\-attr | \-a .I ATTRS option. When option .BR \-\-long | \-l is specified, the certificates are listed in long format, displaying the values of all attributes defined for the certificate type, including non-boolean attributes. .PP By default, the certificates are displayed in the order as they are retrieved from the PKCS\~#11 implementation. To display the certificates in a certain order, specify the .BR \-\-sort | \-S .I SORT\-SPEC option. You can sort the certificates by label and/or subject common name (CN). For details, see the description of the .BR \-\-sort | \-S .I SORT\-SPEC option below. . .PP .SS "Deleting certificates" . .B p11sak .BR remove\-cert | rm\-cert | rmc .RI [ CERTTYPE ] .BR \-\-slot | \-s .I SLOTID .RB [ \-\-pin | \-p .IR PIN ] .RB [ \-\-force\-pin\-prompt ] .RB [ \-\-no\-login | \-N ] .RB [ \-\-so ] .RB [ \-\-label | \-L .IR LABEL ] .RB [ \-\-id | \-i .IR ID ] .RB [ \-\-attr | \-a .IR ATTRS ] .RB [ \-\-force | \-f ] .RB [ \-\-help | \-h ] .PP Use the .BR remove\-cert | rm\-cert | rmc command and the optional .I CERTTYPE argument to remove certificates from the repository. .PP Possible values for the .I CERTTYPE argument are: .BR x509 . If .I CERTTYPE is omitted, then x509 is used by default, because no other certificate types are supported. .PP Specify the .BR \-\-label | \-L .IR LABEL , the .BR \-\-id | \-i .IR ID , and/or the .BR \-\-attr | \-a .I ATTRS options to filter the list of certificates to remove. You can use wildcards (\fB*\fP and \fB?\fP) in the .I LABEL specification. To specify a wildcard character that should not be treated as a wildcard, it must be escaped using a backslash (\fB\e*\fP or \fB\e?\fP). Also, a backslash character that should not be treated as an escape character must be escaped (\fB\e\e\fP). The .B ID must be specified as hex string (not prefixed with 0x) of any number of bytes. .PP The user is prompted to confirm the removal of the certificate. To suppress the prompt, use the .BR \-\-force | \-f option. .PP . .PP .SS "Setting or updating attributes of certificates" . .B p11sak .BR set\-cert\-attr | set\-cert | setc .RI [ CERTTYPE ] .BR \-\-slot | \-s .I SLOTID .RB [ \-\-pin | \-p .IR PIN ] .RB [ \-\-force\-pin\-prompt ] .RB [ \-\-no\-login | \-N ] .RB [ \-\-so ] .RB [ \-\-label | \-L .IR LABEL ] .RB [ \-\-id | \-i .IR ID ] .RB [ \-\-attr | \-a .IR ATTRS ] .RB [ \-\-force | \-f ] .RB [ \-\-new\-attr | \-A .IR ATTRS ] .RB [ \-\-new\-label | \-l .IR LABEL ] .RB [ \-\-new\-id | \-I .IR ID ] .RB [ \-\-help | \-h ] .PP Use the .B set\-cert\-attrs | set\-cert | sect command and the optional .I CERTTYPE argument to set or update boolean attributes of certificates. .PP Possible values for the .I CERTTYPE argument are: .BR x509 . If .I CERTTYPE is omitted, x509 is used by default, because no other certificate types are supported. .PP Specify the .BR \-\-label | \-L .IR LABEL , the .BR \-\-id | \-i .IR ID , and/or the .BR \-\-attr | \-a .I ATTRS options to filter the list of certificates to set or update. You can use wildcards (\fB*\fP and \fB?\fP) in the .I LABEL specification. To specify a wildcard character that should not be treated as a wildcard, it must be escaped using a backslash (\fB\e*\fP or \fB\e?\fP). Also, a backslash character that should not be treated as an escape character must be escaped (\fB\e\e\fP). The .B ID must be specified as hex string (not prefixed with 0x) of any number of bytes. .PP Use the .BR \-\-new\-attr | \-A .I ATTRS option to specify the boolean attributes of the certificate you want to update (see below for detailed description of the attributes). Attributes that are not specified are not changed. Use the .BR \-\-new\-label | \-l .I LABEL option to specify the new label, or the .BR \-\-new\-id | \-I .I ID option to specify the new ID to set for the certificate. At least one of the .BR \-\-new\-attr | \-A .IR ATTRS , .BR \-\-new\-label | \-l .IR LABEL , or .BR \-\-new\-id | \-I .I ID options must be specified. .PP The user is prompted to confirm the updating of the certificate. To suppress the prompt, use the .BR \-\-force | \-f option. .PP . .SS "Coyping certificates" . .B p11sak .BR copy\-cert | copyc | cpc .RI [ CERTTYPE ] .BR \-\-slot | \-s .I SLOTID .RB [ \-\-pin | \-p .IR PIN ] .RB [ \-\-force\-pin\-prompt ] .RB [ \-\-no\-login | \-N ] .RB [ \-\-so ] .RB [ \-\-label | \-L .IR LABEL ] .RB [ \-\-id | \-i .IR ID ] .RB [ \-\-attr | \-a .IR ATTRS ] .RB [ \-\-force | \-f ] .RB [ \-\-new\-attr | \-A .IR ATTRS ] .RB [ \-\-new\-label | \-l .IR LABEL ] .RB [ \-\-new\-id | \-I .IR ID ] .RB [ \-\-help | \-h ] .PP Use the .B copy\-cert | copyc | cpc command and the optional .I CERTTYPE argument to copy certificates and optionally set or change boolean attributes, the label, or ID of the copied certificates. .PP Possible values for the .I CERTTYPE argument are: .BR x509 . If .I CERTTYPE is omitted, then x509 is used by default, because no other certificate type is supported. .PP Specify the .BR \-\-label | \-L .IR LABEL , the .BR \-\-id | \-i .IR ID , and/or the .BR \-\-attr | \-a .I ATTRS options to filter the list of certificates to copy. You can use wildcards (\fB*\fP and \fB?\fP) in the .I LABEL specification. To specify a wildcard character that should not be treated as a wildcard, it must be escaped using a backslash (\fB\e*\fP or \fB\e?\fP). Also, a backslash character that should not be treated as an escape character must be escaped (\fB\e\e\fP). The .B ID must be specified as hex string (not prefixed with 0x) of any number of bytes. .PP Use the .BR \-\-new\-attr | \-A .I ATTRS option to specify the boolean attributes of the copied certificates you want to set or update (see below for detailed description of the attributes). Attributes that are not specified are not changed. Use the .BR \-\-new\-label | \-l .I LABEL option to specify the new label, or the .BR \-\-new\-id | \-I .I ID option to specify the new ID to set for the copied certificate. .PP The user is prompted to confirm the copying of the certificate. To suppress the prompt, use the .BR \-\-force | \-f option. .PP . .SS "Importing x.509 certificates from a file" . .B p11sak .BR import\-cert | importc | impc .I CERTTYPE .BR \-\-slot | \-s .I SLOTID .RB [ \-\-pin | \-p .IR PIN ] .RB [ \-\-force\-pin\-prompt ] .RB [ \-\-no\-login | \-N ] .RB [ \-\-so ] .BR \-\-label | \-L .I LABEL .RB [ \-\-id | \-i .IR ID ] .RB [ \-\-attr | \-a .IR ATTRS ] .BR \-\-file | \-F .I FILENAME .RB [ \-\-ca\-cert | \-C ] .RB [ \-\-help | \-h ] .PP Use the .BR import\-cert | importc | impc command and .I CERTTYPE argument to import an x.509 certificate from a file. .PP Possible values for the .I CERTTYPE argument are: .BR x509 . If .I CERTTYPE is omitted, then x509 is used by default, because no other certificate type is supported. .PP The .BR \-\-label | \-L .IR LABEL option sets the .B CKA_LABEL attribute of the certificate and the .BR \-\-attr | \-a .I ATTRS can be used to set the boolean attributes of the certificate (see below for detailed description of the attributes. Applicable attributes for certificates are P M B Y T). The .BR \-\-id | \-i .I ID option can be used to set the value of the .B CKA_ID attribute of the certificate. .PP The .BR \-\-file | \-F .I FILENAME option specifies the file name of the file that contains the certificate to be imported. Supported input formats are PEM and binary (DER-encoded). The format is automatically detected. .PP The .BR \-\-ca\-cert | \-C option flags the certificate as a Certificate Authority (CA) certificate. If the certificate has the \fBBasicConstraints CA\fP flag on, it is also flagged as Certificate Authority (CA) certificate. . .SS "Exporting certificates to a file" . .B p11sak .BR export\-cert | exportc | expc .RI [ CERTTYPE ] .BR \-\-slot | \-s .I SLOTID .RB [ \-\-pin | \-p .IR PIN ] .RB [ \-\-force\-pin\-prompt ] .RB [ \-\-no\-login | \-N ] .RB [ \-\-so ] .RB [ \-\-label | \-L .IR LABEL ] .RB [ \-\-id | \-i .IR ID ] .RB [ \-\-attr | \-a .IR ATTRS ] .RB [ \-\-force | \-f ] .BR \-\-file | \-F .I FILENAME .RB [ \-\-der | \- D ] .RB [ \-\-uri\-pem | \-u ] .RB [ \-\-uri\-pin\-value ] .RB [ \-\-uri\-pin\-source .IR FILENAME ] .RB [ \-\-help | \-h ] .PP Use the .BR export\-cert | exportc | expc command and the optional .I CERTTYPE argument to export x.509 public key certificates to a file. .PP Possible values for the .I CERTTYPE argument are: .BR x509 . If .I CERTTYPE is omitted, then x509 is used by default, because no other certificate types are supported. .PP Specify the .BR \-\-label | \-L .IR LABEL , the .BR \-\-id | \-i .IR ID , and/or the .BR \-\-attr | \-a .I ATTRS options to filter the list of certificates to export. You can use wildcards (\fB*\fP and \fB?\fP) in the .I LABEL specification. To specify a wildcard character that should not be treated as a wildcard, it must be escaped using a backslash (\fB\e*\fP or \fB\e?\fP). Also, a backslash character that should not be treated as an escape character must be escaped (\fB\e\e\fP). The .B ID must be specified as hex string (not prefixed with 0x) of any number of bytes. .PP The .BR \-\-file | \-F .I FILENAME option specifies the file name of the file to which the certificates to be exported are written to. This can be an OpenSSL PEM file or binary (DER-encoded) file. If it's a PEM file, multiple certificates can be exported to the same file. If it's a binary file, each subsequent export overwrites the previous data in the output file. You are prompted to confirm to overwrite the previously created file, unless the .BR \-\-force | \-f option is specified. .PP Specify the .BR \-\-der | \-D option to export the certificate(s) in binary (DER-encoded) form. Default is PEM format. .PP Specify the .BR \-\-uri\-pem | \-u option to export the PKCS#11 URI of the certificate in PEM form instead of the certificate material. Such an URI-PEM file can then be used with the .B pkcs11\-provider from .BR https://github.com/latchset/pkcs11\-provider . By default, the PKCS#11 URI does not contain the PKCS#11 user pin. Specify option .B \-\-uri\-pin\-value to include the PKCS#11 user pin in the URI using the .B pin\-value query attribute. This reveals the PKCS#11 user pin in clear, use with care! Alternatively, specify option .B \-\-uri\-pin\-source .I FILENAME to include the .B pin\-source query attribute in the URI, referencing the file name specified with this option. The PKCS#11 user pin value is written into that file as part of the export operation. This reveals the PKCS#11 user pin in clear, use with care! Adjust the file permissions of the specified pin\-source file so that it can only be read by the desired user(s). By default the file permissions are set so that only the owner user can read and write that file, but no one else (i.e. 0600). .PP . .SS "Extracting the public key of certificates" . .B p11sak .BR extract\-cert\-pubkey | extrc\-pubkey | excpub .RI [ CERTTYPE ] .BR \-\-slot | \-s .I SLOTID .RB [ \-\-pin | \-p .IR PIN ] .RB [ \-\-force\-pin\-prompt ] .RB [ \-\-no\-login | \-N ] .RB [ \-\-so ] .RB [ \-\-label | \-L .IR LABEL ] .RB [ \-\-id | \-i .IR ID ] .RB [ \-\-attr | \-a .IR ATTRS ] .RB [ \-\-new\-attr | \-A .IR ATTRS ] .RB [ \-\-new\-label | \-l .IR LABEL ] .RB [ \-\-new\-id | \-I .IR ID ] .RB [ \-\-force | \-f ] .RB [ \-\-help | \-h ] .PP Use the .BR extract\-cert\-pubkey | extrc\-pubkey | excpub command and the optional .I CERTTYPE argument to extract the public key from certificates and save it as new token object. .PP Possible values for the .I CERTTYPE argument are: .BR x509 . If .I CERTTYPE is omitted, then x509 is used by default, because no other certificate types are supported. .PP Specify the .BR \-\-label | \-L .IR LABEL , the .BR \-\-id | \-i .IR ID , and/or the .BR \-\-attr | \-a .I ATTRS options to filter the certificates of which the public keys are to be extracted. You can use wildcards (\fB*\fP and \fB?\fP) in the .I LABEL specification. To specify a wildcard character that should not be treated as a wildcard, it must be escaped using a backslash (\fB\e*\fP or \fB\e?\fP). Also, a backslash character that should not be treated as an escape character must be escaped (\fB\e\e\fP). The .B ID must be specified as hex string (not prefixed with 0x) of any number of bytes. .PP Use the .BR \-\-new\-attr | \-A .I ATTRS option to specify the boolean attributes of the public key object you want to set (see below for detailed description of the attributes). Use the .BR \-\-new\-label | \-l .I LABEL option to specify the new label. If no new label is specified, the label of the public key object is derived from the certificate label by appending .BR _pubkey . .PP Use the .BR \-\-new\-id | \-I .I ID option to set an ID for the extracted public key object. .PP The user is prompted to confirm the extraction of the public key from the certificate. To suppress the prompt, use the .BR \-\-force | \-f option. .PP . . .SH ARGUMENTS . .SS "KEYTYPE" . Selects the respective symmetric or asymmetric key to be generated, imported or selected. Possible values are: .BR des |\: 3des |\: generic |\: sha\-1\-hmac |\: sha224\-hmac |\: \ sha256\-hmac |\: sha384\-hmac |\: sha512\-hmac |\: sha512/224\-hmac |\: \ sha512/256\-hmac |\: sha3\-224\-hmac |\: sha3\-256\-hmac |\: sha3\-384\-hmac \ |\: sha3\-512\-hmac |\: aes |\: aes\-xts |\: rsa |\: dh |\: dsa |\: ec |\: \ ec\-edwards |\: ec\-montgomery |\: ibm\-dilithium |\: ibm\-kyber |\: \ ibm\-ml\-dsa |\: ibm\-ml\-kem |\: ml\-dsa |\: ml\-kem |\: public |\: private \ |\: secret |\: all . The .BR public |\: private |\: secret |\: all argument can only be used with commands that use the .I KEYTYPE argument as filter, such as the .B list\-key command, the .B remove\-key command, the .B set\-key\-attrs command, or the .B export\-key command. .PP . .SS "CERTTYPE" . Selects the type of certificate to be imported, exported, listed, copied, updated, removed, or selected for public key extraction. Possible values are: .BR x509 . If no certificate type is specified, certificate type x509 is used, because currently no other certificate types are supported. . .PP . .SS "KEYBITS" . Specifies the size of the key in bits. For the .B aes key type, possible values are .BR 128 | 192 | 256 . For the .B aes\-xts key type, possible values are .BR 128 | 256 . For the .B rsa key type, the key size must be from 512 to 16384 and a multiple of 8 bits. Typical key sizes are 512, 1024, 2048, 4096, or 8192. Not all RSA key sizes might be supported by all tokens. .PP . .SS "PUBL\-EXP" . Specifies the public exponent for an RSA key. If not specified, the default is 65537 according to the PKCS\~#11 standard. .PP . .SS "PRIV\-BITS" . Specifies the size of the private key in bits for an DH key. .PP . .SS "GROUP" . Specifies the Diffie\-Hellman FFC group name for an DH key. Possible values are .BR ffdhe2048 |\: ffdhe3072 |\: ffdhe4096 |\: ffdhe6144 |\: ffdhe8192 |\: \ modp1536 |\: modp2048 |\: modp3072 |\: modp4096 |\: modp6144 |\: modp8192 . .PP .B Note: Not all groups are supported by all tokens and key generation fails when the specified .I GROUP is not supported. Also, not all groups are supported by all OpenSSL versions. If the .B p11sak tool is compiled against an OpenSSL version that does not support certain groups, then those groups are not accepted for the .I GROUP argument. .PP . .SS "DH\-PARAM\-PEM\-FILE" . Specifies the DH parameters PEM file name. You can for example generate DH parameters using the OpenSSL command line tool as follows: \fB'openssl dhparam \-out \-outform PEM' \fP. See the OpenSSL man page for details about this command. .PP . .SS "DSA\-PARAM\-PEM\-FILE" . Specifies the DSA parameters PEM file name. You can for example generate DSA parameters using the OpenSSL command line tool as follows: \fB'openssl dsaparam \-out \-outform PEM' \fP. See the OpenSSL man page for details about this command. .PP . .SS "CURVE" . Specifies the curve for an EC, EC-Edwards, or EC-Montgomery key. For the EC key type possible values are: .BR prime256v1 |\: prime192 |\: secp224 |\: secp384r1 |\: secp521r1 |\: \ secp265k1 |\: brainpoolP160r1 |\: brainpoolP160t1 |\: brainpoolP192r1 |\: \ brainpoolP192t1 |\: brainpoolP224r1 |\: brainpoolP224t1 |\: brainpoolP256r1 \ |\: brainpoolP256t1 |\: brainpoolP320r1 |\: brainpoolP320t1 |\: \ brainpoolP384r1 |\: brainpoolP384t1 |\: brainpoolP512r1 |\: brainpoolP512t1 \ |\: curve25519 |\: curve448 |\: ed25519 |\: ed448 |\: bls12-381 . Note that using an Edwards or Montgomery curve for the EC key type only works for the EP11 token and produces a non-PKCS#11-standard EC key. For the EC-Edwards key type possible values are: .BR ed25519 |\: ed448 . For the EC-Montgomery key type possible values are: .BR curve25519 |\: curve448 . .PP . .SS "VERSION" . Specifies the version for an IBM Dilithium, IBM Kyber, IBM ML\-DSA, IBM ML\-KEM, ML\-DSA, or ML\-KEM key. For the .B ibm\-dilithium key type, possible values are .BR r2_65 |\: r2_87 |\: r3_44 |\: r3_65 |\: r3_87 . For the .B ibm\-kyber key type, possible values are .BR r2_768 |\: r2_1024 . For the .B ibm\-ml\-dsa and .B ml\-dsa key types, possible values are .BR 44 |\: 65 |\: 87 . For the .B ibm\-ml\-kem and .B ml\-kem key types, possible values are .BR 512 |\: 768 |\: 1024 . .PP . .SS "KIND" . Specifies the kind of the asymmetric key to import. Possible values are .BR public | private . .PP . .SS "WRAP\-MECH" . Specifies the wrapping mechanism for use with exporting or importing a key by wrapping it with a key encrypting key. Possible values are .BR aes\-cbc\-pad |\: aeskw\-kwp |\: aeskw\-pkcs7 |\: rsa\-pkcs |\: rsa\-oaep \ |\: rsa\-aeskw |\: ecdh\-aeskw |\: ecdh\-cof\-aeskw |\: ecdh\-x\-aeskw . Dependent on the key wrapping mechanism, additional options may be supported to specify mechanism parameters. See sections .B Exporting a key by wrapping it with a key encrypting key and .B Importing a key by unwrapping it with a key encrypting key under .B COMMANDS for a description of the wrapping mechanism and its mechanism parameter options. .PP . . . .SH OPTIONS .TP 8 .BR \-\-slot | \-s\~\fISLOT\fP Specifies the slot number of the token to use. .PP . . . .TP 8 .BR \-\-pin | \-p\~\fIPIN\fP Specifies the token user PIN to login with. .PP .RS 8 Alternatively, the .B PKCS11_USER_PIN environment variable may be used to provide the token user PIN. If neither this option is specified nor the environment variable is set, you are prompted for the PIN. .RE .PP . . . .TP 8 .BR \-\-force\-pin\-prompt Enforce the .B p11sak tool to prompt for the token user PIN (regardless if it has been specified elsewhere) .PP . . . .TP 8 .BR \-\-no\-login | \-N Do not login the session. This means that only public token objects .RB ( CKA_PRIVATE = FALSE ) can be accessed. .PP . . . .TP 8 .BR \-\-so Login as .BR SO \~( security\~officer ). Option .BR \-\-pin | \-p .I PIN must specify the SO pin, or if the .BR \-\-pin | \-p .I PIN option is not specified, environment variable .B PKCS11_SO_PIN is used. If .B PKCS11_SO_PIN is not set, you are prompted for the SO PIN. SO can only access public token objects .RB ( CKA_PRIVATE = FALSE ), but SO can set attribute .B CKA_TRUSTED to .B TRUE for secret key objects, public key objects, and certificate objects. .PP . . . .TP 8 .BR \-\-label | \-L\~\fILABEL\fP | \fIPUB\-LABEL\fP : \fIPRIV\-LABEL\fP Specifies the key label attribute value (\fBCKA_LABEL\fP). .PP .RS 8 For commands such as the .B list\-key command, the .B remove\-key command, the .B set\-key\-attrs command, the .B export\-key command, and the .B wrap\-key command, specify the label to filter the list of keys to operate on. You can use wildcards (\fB*\fP and \fB?\fP) in the .I LABEL specification. To specify a wildcard character that should not be treated as a wildcard, it must be escaped using a backslash (\fB\e*\fP or \fB\e?\fP). Also, a backslash character that should not be treated as an escape character must be escaped (\fB\e\e\fP). .PP For generation of asymmetric keys, the specified label is appended by \fB:pub\fP and \fB:prv\fP for the public and private key objects. Optionally, a user can set different labels for the public and private key objects by specifying them separated by a colon (\fB:\fP), e.g. \fBpub\-label:priv\-label\fP. The label string in front of the colon is used as label for the public key object, the label string after the colon is used for the private key object. To set the public and private key label the exact same, use \fBpub\-label:=\fP. The equal sign (\fB=\fP) means to use the same label string for the private key objects as for the public key object. In case a colon character or a equal sign is supposed to appear within a label string, it must be escaped using a back slash (\fB\\\fP), e.g. \fBabc\\:xyz\fP results in \fBabx:xyz\fP where the colon is not treated as separator character. Note that the shell may interpret escape characters as well, so better quote the \fILABEL\fP|\fIPUB\-LABEL\fP:\fIPRIV\-LABEL\fP specification. .RE .PP . . . .TP 8 .BR \-\-id | \-i\~\fIID\fP Specifies the key ID attribute value (\fBCKA_ID\fP) as hex string (not prefixed with 0x) of any number of bytes. .PP .RS 8 For commands such as the .B list\-key command, the .B remove\-key command, the .B set\-key\-attrs command, the .B export\-key command, and the .B wrap\-key command, specify the key ID to filter the list of keys to operate on. .PP For generation of asymmetric keys, the same ID is set for both, the public and the private key. .RE .PP . . . .TP 8 .BR \-\-attr | \-a\~\fIATTRS\fP | \fIPUB\-ATTRS\fP : \fIPRIV\-ATTRS\fP For the .B generate\-key command, the .B import\-key command, and the .B unwrap\-key command, specify the boolean attributes that are to be set for the new key(s). For commands such as the .B list\-key command, the .B remove\-key command, the .B set\-key\-attrs command, the .B export\-key command, and the .B wrap\-key command, specify the attribute values to filter the list of keys to operate on. .PP .RS 8 .B Note: Not all boolean attributes are applicable to all key types and/or commands and are silently ignored if not applicable. .PP The respective attributes are set to .B TRUE when the corresponding letter is specified in uppercase, or .B FALSE when the corresponding letter is specified in lowercase. Attributes (except \fBCKA_TOKEN\fP and \fBCKA_SENSITIVE\fP, see below) that are not specified get the default value as defined by the PKCS\~#11 standard or the used PKCS\~#11 token implementation when generating keys, or are not updated when setting the attributes of an existing key. .PP Attribute .B CKA_TOKEN is always set to \fBTRUE\fP when generating a key. The .B p11sak tool always generates token keys, since session keys are not persistent, and thus would no longer exist after the session that the .B p11sak tool has opened for generating the key is closed when it exists. .PP When generating or importing a key with the .B p11sak tool, attribute .B CKA_SENSITIVE defaults to \fBTRUE\fP for secret keys or the private key of asymmetric key pairs. However, this can be overridden by specifying the respective uppercase or lowercase letter for the CKA_SENSITIVE attribute in the attribute string, as desired. .PP .B Note: The default setting for the .B CKA_SENSITIVE attribute is defined by the .B p11sak tool, and might be different from the default setting that would be chosen by the used PKCS\~#11 implementation. .PP The following letters are associated with the respective .BR CK_ATTRIBUTE : .IP "\(bu" 2 .B P \- CKA_PRIVATE .IP "\(bu" 2 .B L \- CKA_LOCAL (read only) .IP "\(bu" 2 .B M \- CKA_MODIFIABLE .IP "\(bu" 2 .B B \- CKA_COPYABLE .IP "\(bu" 2 .B Y \- CKA_DESTROYABLE .IP "\(bu" 2 .B R \- CKA_DERIVE .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 C \- CKA_SIGN_RECOVER .IP "\(bu" 2 .B V \- CKA_VERIFY .IP "\(bu" 2 .B O \- CKA_VERIFY_RECOVER .IP "\(bu" 2 .B W \- CKA_WRAP .IP "\(bu" 2 .B U \- CKA_UNWRAP .IP "\(bu" 2 .B S \- CKA_SENSITIVE .IP "\(bu" 2 .B A \- CKA_ALWAYS_SENSITIVE (read only) .IP "\(bu" 2 .B X \- CKA_EXTRACTABLE .IP "\(bu" 2 .B N \- CKA_NEVER_EXTRACTABLE (read only) .IP "\(bu" 2 .B T \- CKA_TRUSTED (can only be set to TRUE by SO user) .IP "\(bu" 2 .B I \- CKA_WRAP_WITH_TRUSTED .IP "\(bu" 2 .B H \- CKA_ALWAYS_AUTHENTICATE (for keys of class CKO_PRIVATE_KEY only, can only be set to TRUE if CKA_PRIVATE is also TRUE) .IP "\(bu" 2 .B J \- CKA_ENCAPSULATE .IP "\(bu" 2 .B Q \- CKA_DECAPSULATE .IP "\(bu" 2 .B K \- CKA_IBM_PROTKEY_EXTRACTABLE (IBM specific, not all tokens support this) .IP "\(bu" 2 .B Z \- CKA_IBM_PROTKEY_NEVER_EXTRACTABLE (IBM specific, not all tokens support this, read only) .PP For multiple attributes, specify a set of these letters without any blanks in between, e. g. \fB'MlD'\fP. An uppercase letter means \fBTRUE\fP, while a lowercase letter means \fBFALSE\fP. From Example above, \fB'MlD'\fP corresponds to: \fBCKA_MODIFIABLE=TRUE, CKA_LOCAL=FALSE, CKA_DECRYPT=TRUE\fP. .PP For generating asymmetric keys set individual key attributes for public and private key separated by a colon (\fB:\fP). The attributes in front of the colon are set for the public key and the attributes after the colon are set for the private key. When no colon is used, the same attribute set is used for both, the public and private keys. To set a configuration for only the public key, the string must end with the colon and respectively, to use a configuration for the private key only, the string must start with the colon. .PP .RE . . . .TP 8 .BR \-\-new\-attr | \-A\~\fIATTRS\fP Specifies the boolean attributes to set or update for a key with the .B set\-key\-attr or .B copy\-key commands. See the description of the .BR \-\-attr | \-a option above for a list of letters that are associated with the respective .BR CK_ATTRIBUTE . . . . .TP 8 .BR \-\-new\-label | \-L\~\fILABEL\fP Specifies the new label attribute value (\fBCKA_LABEL\fP) to set for the key. .RE .PP . . . .TP 8 .BR \-\-new\-id | \-I\~\fIID\fP Specifies the new ID attribute value (\fBCKA_ID\fP) as hex string (not prefixed with 0x) of any number of bytes to set for the key. .RE .PP . . . .TP 8 .BR \-\-long | \-l Prints the .B list\-key output in long format, displaying the values of all attributes defined for the key type, including non-boolean attributes. If the .BR \-\-long | \-l option is omitted, the output is in a short, tabular format, showing only the boolean attributes, the key type (\fBCKA_KEY_TYPE\fP) and the key label (\fBCKA_LABEL\fP). .RE .PP . . . .TP 8 .B \-\-detailed\-uri Displayes a detailed PKCS\~#11 URI. .RE .PP . . . .TP 8 .BR \-\-hsm\-mkvp | \-m Shows the HSM master key verification patterns (MKVPs) of the key objects. This option is only valid for secure key tokens, such as the CCA and EP11 tokens. .RE .PP . . . .TP 8 .BR \-\-ep11\-session\-id | \-e Shows the EP11 session-IDs of the key objects. This option is only valid for EP11 tokens. .RE .PP . . . .TP 8 .BR \-\-sort | \-S\~\fISORT\-SPEC\fP Sort the keys by label, key type, object class, and/or key size. Sort certificates by label and/or subject common name (CN). Specify a sort selection of up to 4 fields, each field represented by its corresponding letter, separated by comma .RB ( , ): .RS 8 .IP "\(bu" 2 .B l - sort by label (keys and certificates) .RB ( CKA_LABEL ) .IP "\(bu" 2 .B k - sort by key type (keys only) .RB ( CKA_KEY_TYPE ) .IP "\(bu" 2 .B c - sort by object class (keys only) .RB ( CKA_CLASS , secret key, private key, public key) .IP "\(bu" 2 .B s - sort by key size (keys only) .RB ( CKA_VALUE_LEN , or derived from other key type specific attribute) .IP "\(bu" 2 .B n - sort by common name (certificates only) .PP The sort order can be appended to the field designator by a colon .RB ( : ) and its corresponding letter: .IP "\(bu" 2 .B a - ascending order (default) .IP "\(bu" 2 .B d - descending order .PP Example: .B l:a,k:d sorts by label in ascending order and then by key type in descending order. .RE .PP . . . .TP 8 .BR \-\-force | \-f Suppress the prompt whether the user wants to remove, update, or export the keys matching the specified \fIKEYTYPE\fP, label, and ID filter (if specified). For the .B wrap\-key command and the command, and the .B unwrap\-key command, also supress the prompt for a confirmation to use a key as KEK. .RE .PP . . . .TP 8 .BR \-\-file | \-F\~\fIFILENAME\fP For the .B import\-key command, this option specifies the file name of the file that contains the key to be imported. For symmetric keys, this is a binary file containing the key material in clear. For asymmetric keys, this is an OpenSSL PEM file containing a public or private key. PEM files used for importing keys can be password protected. Specify the PEM password with the .BR \-\-pem\-password | \-P .I PASSWORD option or environment variable .BR P11SAK_PEM_PASSWORD . If the PEM file is password protected, but no PEM password is specified, you are prompted for the PEM password. .PP .RS 8 For the .B export\-key command, this option specifies the file name of the file to which the keys to be exported are written to. For symmetric keys, this is a binary file where the key material in clear is written to. For asymmetric keys, this is an OpenSSL PEM file where the public or private keys are written to. If multiple asymmetric keys match the filter, the keys are appended to the PEM file specified with this option. If multiple symmetric keys or a mixture of asymmetric and symmetric keys match the filter, you are prompted to confirm to overwrite the previously created file, unless the .BR \-\-force | \-f option is specified. .PP For the .B wrap\-key command, this option specifies the file name of the file to which the wrapped key material is written to. By default this is a PEM file using a p11sak specific type and a header that contains information about the wrapping mechanism and mechanism parameters (if any). If option .BR \-\-raw | \-R is specified then the file is a raw binary file and the raw wrapped key material is written to it. If multiple keys match the filter, the keys are appended to the PEM file specified with the .BR \-\-file | \-F .I FILENAME option. If option .BR \-\-raw | \-R is specified, and multiple keys match the filter, you are prompted to confirm to overwrite the previously created file, unless the .BR \-\-force | \-f option is specified. .PP For the .B unwrap\-key command, this option specifies the file name of the file containing the wrapped key material. By default this is a PEM file using a p11sak-specific type and a header that contains information about the wrapping mechanism and mechanism parameters (if any). If option .BR \-\-raw | \-R is specified then the file is a raw binary file and the raw wrapped key material is contained. .RE .PP . . . .TP 8 .BR \-\-encrypted\-pem Encrypt the PEM file using .B AES\-CBC with an .B AES 256 bit key derived from a password via .BR PBKDF2 . The PEM password can be specified with the .BR \-\-pem\-password | \-P .I PASSWORD option, or environment variable .BR P11SAK_PEM_PASSWORD , otherwise you are prompted for the PEM password. This option is only valid for exporting private keys. It is not allowed when exporting SPKIs, opaque secure key blobs, or URI-PEMs, and it is ignored when exporting public or secret keys. .RE .PP . . . .TP 8 .BR \-\-pem\-password | \-P\~\fIPASSWORD\fP Specifies the password of the PEM file specified with the .BR \-\-file | \-F .I FILENAME option for the .B import\-key and .B export\-key commands. If the PEM file is password protected, but this option is not specified, nor environment variable .B P11SAK_PEM_PASSWORD is set, you are prompted for the PEM password. .RE .PP . . . .TP 8 .BR \-\-force\-pem\-pwd\-prompt Enforce the import\-key command to prompt for the PEM password (regardless if it has been specified elsewhere). .RE .PP . . . .TP 8 .BR \-\-opaque The key material in the file specified with the .BR \-\-file | \-F .I FILENAME option is an opaque secure key blob. Not all tokens support this. .RE .PP . . . .TP 8 .BR \-\-oqsprovider\-pem The key material in the PEM file specified with the .BR \-\-file | \-F .I FILENAME option is in the .B oqsprovider format. This option is only valid for the .B ibm\-dilithium keytype. PEM files in .B oqsprovider format are only supported when the .B oqsprovider from .B https://github.com/open\-quantum\-safe/oqs\-provider has been configured with OpenSSL 3.0 or later. .PP .RS 8 .B Note: This is an experimental feature, it may change in an incompatible way in the future! .RE .PP . . . .TP 8 .BR \-\-der | \-D The certificate is written to the file in binary (DER-encoded) form. Default is PEM format. Note that only one certificate can be written into a given file in DER-encoded form, while multiple certificates can be written into the same file in PEM format. .RE .PP . . . .TP 8 .BR \-\-uri\-pem | \-u Export the key's or certificate's PKCS#11 URI in PEM form instead of the key or certificate material. Such an URI-PEM file can then be used with the .B pkcs11\-provider from .BR https://github.com/latchset/pkcs11\-provider . .RE .PP . . . .TP 8 .BR \-\-uri\-pin\-value When exporting the key's or certificate's PKCS#11 URI in PEM form, include the PKCS#11 user pin value in the URI using the .B pin\-value query attribute. This reveals the PKCS#11 user pin in clear, use with care! This option can only be used together with the .BR \-\-uri\-pem | \-u option, and when options .BR \-\-no\-login | \-N and .BR \-\-so are not specified. .RE .PP . . . .TP 8 .BR \-\-uri\-pin\-source\~\fIFILENAME\fP When exporting the key's or certificate's PKCS#11 URI in PEM form, include the .B pin\-source query attribute in the URI, referencing the file name specified with this option. The PKCS#11 user pin value is written into that file as part of the export operation. This reveals the PKCS#11 user pin in clear, use with care! Adjust the file permissions of the specified file so that it can only be read by the desired user(s). This option can only be used together with the .BR \-\-uri\-pem | \-u option, and when options .BR \-\-no\-login | \-N and .BR \-\-so are not specified. .RE .PP . . . .TP 8 .BR \-\-kek\-label | \-K\~\fILABEL\fP Select the key encrypting key (KEK) by label. Only keys with the right object class and key type that fit to the wrapping mechanism are selected. If multiple key objects match, you are prompted to confirm to use the desired key object. If the .BR \-\-force | \-f option is specified, then the first matching key object is used. You can use wildcards (\fB*\fP and \fB?\fP) in the .I LABEL specification. To specify a wildcard character that should not be treated as a wildcard, it must be escaped using a backslash (\fB\e*\fP or \fB\e?\fP). Also, a backslash character that should not be treated as an escape character must be escaped (\fB\e\e\fP). .RE .PP . . . .TP 8 .BR \-\-kek\-id | \-k\~\fILABEL\fP Select the key encrypting key (KEK) by ID. Only keys with the right object class and key type that fit to the wrapping mechanism are selected. Specify a hex string (not prefixed with 0x) of any number of bytes. If multiple key objects match, you are prompted to confirm to use the desired key object. If the .BR \-\-force | \-f option is specified, then the first matching key object is used. .RE .PP . . . .TP 8 .BR \-\-ca\-cert | \-C Flag the certificate as a Certificate Authority (CA) certificate. If the certificate has the \fBBasicConstraints CA\fP flag on, it is also flagged as Certificate Authority (CA) certificate. .RE .PP . . . .TP 8 .BR \-\-help | \-h Prints help for the usage of the .B p11sak tool and/or the respective command and then exits. .RE .PP . . . .TP 8 .BR \-\-version | \-v Prints the version of the .B p11sak tool and then exits. .RE .PP . . . .SS OPTIONS FOR ARGUMENT \fIWRAP\-MECH\fB VALUE aes\-cbc\-pad: . .TP 8 .BR \-\-iv | \-I~\fIIV\fP The initialization vector (IV) for the AES\-CBC operation. Specify a hex string (not prefixed with 0x) of exactly 16 bytes. The default is to use 16 all zero bytes. .RE .PP . . . .SS OPTIONS FOR ARGUMENT \fIWRAP\-MECH\fB VALUE aeskw\-kwp: . .TP 8 .BR \-\-iv | \-I~\fIIV\fP The initialization vector (IV) for the AESKW\-KWP operation. Specify a hex string (not prefixed with 0x) of exactly 4 bytes. If no IV is specified then the default IV as per AESKW\-KWP specification is used. .RE .PP . . . .SS OPTIONS FOR ARGUMENT \fIWRAP\-MECH\fB VALUE aeskw\-pkcs7: . .TP 8 .BR \-\-iv | \-I~\fIIV\fP The initialization vector (IV) for the AESKW\-PKCS7 operation. Specify a hex string (not prefixed with 0x) of exactly 8 bytes. If no IV is specified then the default IV as per AESKW\-PKCS7 specification is used. .RE .PP . . . .SS OPTIONS FOR ARGUMENT \fIWRAP\-MECH\fB VALUE rsa\-oaep: . .TP 8 .BR \-\-hash\-alg\~\fIHASH\-ALG\fP The message digest algorithm used to calculate the digest of the OAEP encoding parameter. The default is to use the samealgorithm as specified with option .BR \-\-mgf\-alg , or SHA256 if neither is specified. Possible algorithms are: .BR SHA\-1 |\: SHA224 |\: SHA256 |\: SHA384 |\: SHA512 |\: SHA3\-224 |\: \ SHA3\-256 |\: SHA3\-384 |\: SHA3\-512 . . . . .TP 8 .BR \-\-mgf\-alg\~\fIMGF\-ALG\fP The mask generation function algorithm to use on the encoded block. The default is to use the same algorithm as specified with option .BR \-\-hash\-alg , or SHA256 if neither is specified. Possible algorithms are: .BR SHA\-1 |\: SHA224 |\: SHA256 |\: SHA384 |\: SHA512 |\: SHA3\-224 |\: \ SHA3\-256 |\: SHA3\-384 |\: SHA3\-512 . . . . .TP 8 .BR \-\-source\-data\~\fISOURCE\-DATA\fP The source of the OAEP encoding parameter. Specify a hex string (not prefixed with 0x) of any number of bytes. The default is that no source data is used. .RE .PP . . . .SS OPTIONS FOR ARGUMENT \fIWRAP\-MECH\fB VALUE rsa\-aeskw: . .TP 8 .BR \-\-aes\-key\-size\~\fIAES\-KEYBITS\fP The size of the temporary AES key in bits. The default is 256 bits. Possible key sizes are: .BR 128 | 192 | 256 . . . . .TP 8 .BR \-\-hash\-alg\~\fIHASH\-ALG\fP The message digest algorithm used to calculate the digest of the OAEP encoding parameter. The default is to use the samealgorithm as specified with option .BR \-\-mgf\-alg , or SHA256 if neither is specified. Possible algorithms are: .BR SHA\-1 |\: SHA224 |\: SHA256 |\: SHA384 |\: SHA512 |\: SHA3\-224 |\: \ SHA3\-256 |\: SHA3\-384 |\: SHA3\-512 . . . . .TP 8 .BR \-\-mgf\-alg\~\fIMGF\-ALG\fP The mask generation function algorithm to use on the encoded block. The default is to use the same algorithm as specified with option .BR \-\-hash\-alg , or SHA256 if neither is specified. Possible algorithms are: .BR SHA\-1 |\: SHA224 |\: SHA256 |\: SHA384 |\: SHA512 |\: SHA3\-224 |\: \ SHA3\-256 |\: SHA3\-384 |\: SHA3\-512 . . . . .TP 8 .BR \-\-source\-data\~\fISOURCE\-DATA\fP The source of the OAEP encoding parameter. Specify a hex string (not prefixed with 0x) of any number of bytes. The default is that no source data is used. .RE .PP . . . .SS OPTIONS FOR ARGUMENT \fIWRAP\-MECH\fB VALUE ecdh\-aeskw, ecdh\-cof\-aeskw, \ and ecdh\-x\-aeskw: . .TP 8 .BR \-\-aes\-key\-size\~\fIAES\-KEYBITS\fP The size of the temporary AES key in bits. The default is 256 bits. Possible key sizes are: .BR 128 | 192 | 256 . . . . .TP 8 .BR \-\-kdf\-alg\~\fIKDF\-ALG\fP The key derivation function algorithm used on the shared secret value to generate the internal AES key. The default is SHA256. Possible algorithms are: .BR SHA\-1 |\: SHA224 |\: SHA256 |\: SHA384 |\: SHA512 |\: SHA3\-224 |\: \ SHA3\-256 |\: SHA3\-384 |\: SHA3\-512 |\: SHA\-1\-SP800 |\: SHA224\-SP800 |\: \ SHA256\-SP800 |\: SHA384\-SP800 |\: SHA512\-SP800 |\: SHA3\-224\-SP800 |\: \ SHA3\-256\-SP800 |\: SHA3\-384\-SP800 |\: SHA3\-512\-SP800 . . . . .TP 8 .BR \-\-shared\-data\~\fISHARED\-DATA\fP Some data shared between the two parties. Specify a hex string (not prefixed with 0x) of any number of bytes. The default is that no shared data is used. .RE .PP . . . .SH "FILES" . .SS "/etc/opencryptoki/p11sak_defined_attrs.conf" .SS "~/.p11sak_defined_attrs.conf" In the output config file a user can define additional attributes, which are not mentioned in the PKCS#11 standard or are not known by the .B p11sak tool. A custom file path can be set with environment variable \fBP11SAK_DEFAULT_CONF_FILE\fP. If the environment variable is not set, then \fB.p11sak_defined_attrs.conf\fP is first tried to be read from the current user's home directory. If this is not available, the global \fB/etc/opencryptoki/p11sak_defined_attrs.conf\fP config file is read. If none of these files are available, a warning message is displayed, and printing of custom attributes is not available. .PP . . . .SH "ENVIRONMENT VARIABLES" .SS "P11SAK_DEFAULT_CONF_FILE" A custom path for the \fBp11sak_defined_attrs.conf\fP config file can be set with the environment variable \fBP11SAK_DEFAULT_CONF_FILE\fP. If the environment variable is not set, then \fB.p11sak_defined_attrs.conf\fP is first tried to be read from the current user's home directory. If this is not available, the global \fB/etc/opencryptoki/p11sak_defined_attrs.conf\fP config file is read. If none of these files are available, a warning message is displayed, and printing of custom attributes is not available. .PP . .SS "PKCS11_USER_PIN" The token user PIN can be specified via the environment variable \fBPKCS11_USER_PIN\fP. If this environment variable is not set, and the option .BR \-\-pin | \-p .I PIN is not specified, p11sak prompts for the token user PIN interactively. .PP . .SS "PKCS11_SO_PIN" When option .B \-\-so is specified, the token SO PIN can be specified via the environment variable \fBPKCS11_SO_PIN\fP. If this environment variable is not set, and the option .BR \-\-pin | \-p .I PIN is not specified, p11sak prompts for the token SO PIN interactively. .PP . .SS "PKCSLIB" An alternative PKCS\~#11 library name can be specified with the \fBPKCSLIB\fP environment variable. If this environment variable is not set, then the default PKCS\~#11 library \fBlibopencryptoki.so\fP is used. .PP . .SS "P11SAK_PEM_PASSWORD" PEM files used for importing and exporting keys can be password protected. The PEM password can be specified via the environment variable \fBP11SAK_PEM_PASSWORD\fP. If this environment variable is not set, and the option .BR \-\-pem\-password | \-P .I PASSWORD is not specified, p11sak prompts for the PEM password interactively. . . . .SH "EXIT STATUS" The .B p11sak tool returns error codes as defined by the PKCS\~#11 standard, i.e. the \fBCKR_nnn\fP errors. On success, \fBCKR_OK\fP (which is zero) is returned. .PP The PKCS\~#11 error codes may originate from a PKCS\~#11 function called by the .B p11sak tool, or from the .B p11sak tool itself, like the following: .SS CKR_ARGUMENTS_BAD (0x00000007): An argument, option or keyword is not valid. .PP . . . .SS CKR_DATA_INVALID (0x00000020): The \fBp11sak_defined_attrs.conf\fP cannot be parsed or its syntax is invalid. .PP . . . .SS CKR_MECHANISM_INVALID (0x00000070): The token does not support the key generation mechanism for the specified key type. .PP . . . .SS CKR_KEY_SIZE_RANGE (0x00000062): The token does not support the key size for the specified key type. .PP . . . .SS CKR_HOST_MEMORY (0x00000002): Allocating memory has failed. .PP . . . .SS CKR_FUNCTION_FAILED (0x00000006): A subfunction or library call has failed. .PP . . . .SS CKR_KEY_UNEXTRACTABLE (0x0000006A): A key has attribute .B CKA_EXTRACTABLE set to .B CK_FALSE and can thus not be wrapped or extracted otherwise. .PP . . . .SS CKR_KEY_NOT_WRAPPABLE (0x00000069): A key can not be wrapped, because the token does not support to wrap that key type with the used wrapping mechanism. .PP . . . .SH "SEE ALSO" .PD 0 .TP \fBp11sak_defined_attrs.conf\fP(5) .PD opencryptoki-opencryptoki-451d99c/man/man1/pkcscca.1.in000066400000000000000000000062601520105705100230350ustar00rootroot00000000000000.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] .SS "OLD RSA KEY MIGRATION" \fBpkcscca\fP [\fB-m oldrsakeys\fP] [\fB-s SLOTID\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. Up to opencryptoki version 3.14.0, RSA keys were created using the RSA-CRT key token format (private key section X'08'). RSA-CRT keys are encrypted with the CCA ASYM master key, and can not be used for certain mechanisms, e.g. RSA-PSS or RSA-OAEP. In newer opencryptoki versions, RSA keys are created using the RSA-AESC key token format (private key section X'31'). Up to version 3.16.0, RSA public keys also contained full CCA secure key tokens, including the private key section (which is encrypted by the CCA master key). The \fBoldrsakeys\fP migration option migrates old RSA private key tokens to the new format, and also extracts the public key sections from RSA public key tokens containing a full CCA secure key token. .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 "OLD RSA KEY MIGRATION" .IP "\fB-m oldrsakeys\fP" 5 Converts old RSA keys (RSA-CRT) to the new format (RSA-AESC) and extracts the public key section only from key objects containing the full RSA key token. .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 opencryptoki-opencryptoki-451d99c/man/man1/pkcsconf.1.in000066400000000000000000000026241520105705100232340ustar00rootroot00000000000000.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 opencryptoki-opencryptoki-451d99c/man/man1/pkcsep11_migrate.1.in000066400000000000000000000036201520105705100245620ustar00rootroot00000000000000.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 opencryptoki-opencryptoki-451d99c/man/man1/pkcsep11_session.1.in000066400000000000000000000052701520105705100246200ustar00rootroot00000000000000.TH PKCSEP11_SESSION 1 "Dec 2023" "@PACKAGE_VERSION@" "openCryptoki" .SH NAME pkcsep11_session \- manage EP11 sessions. .SH SYNOPSIS .B pkcep11_session .RB [ -h ] .RB [ show | logout | vhsmpin | fipspin | status ] .RB [ -slot .IR slot-number ] .RB [ -id .IR session-ID ] .RB [ -pid .IR process-ID ] .RB [-date .IR yyyy/mm/dd ] .RB [ -force ] .SH DESCRIPTION Use .B pkcep11_session to set the VHSM and FIPS-session pins, and list and logout leftover EP11 sessions. EP11 sessions are created and destroyed when a PKCS#11 session is logged in and out, 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, VHSM_MODE, or FIPS_SESSION_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. Set the VHSM PIN before enabling the VHSM_MODE in the EP11 configuration file. .br \fBNote:\fP When changing the VHSM PIN, all existing keys stored as token objects become unusable! .IP "\fBfipspin\fP" 10 sets the FIPS PIN used for the FIPS_SESSION_MODE. The FIPS PIN must contain between 8 and 16 alphanumeric characters. Set the FIPS PIN before enabling the FIPS_SESSION_MODE in the EP11 configuration file. .br \fBNote:\fP When changing the FIPS PIN, all existing keys stored as token objects become unusable! .IP "\fBstatus\fP" 10 shows the maximum and currently available number of EP11 sessions for each available EP11 APQN. .SH "OPTIONS" .IP "\fB-slot\fP \fIslot-number\fP" 10 specifies the slot of the EP11 token. This option is required for all commands except the \fBstatus\fP command. .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 opencryptoki-opencryptoki-451d99c/man/man1/pkcshsm_mk_change.1.in000066400000000000000000000261041520105705100250710ustar00rootroot00000000000000.\" pkcshsm_mk_change.1 .\" .\" Copyright IBM Corp. 2022 .\" See LICENSE for details. .\" .TH PKCSHSM_MK_CHANGE 1 "August 2022" "@PACKAGE_VERSION@" "openCryptoki" .SH NAME pkcshsm_mk_change \- utility to manage and control the re-enciphering of secure keys for a concurrent HSM master key change for openCryptoki. .SH SYNOPSIS .B pkcshsm_mk_change .I command .RB [ OPTIONS ] . .PP .B pkcshsm_mk_change .BR \-\-help | \-h .br .SH DESCRIPTION Manages and controls the re-enciphering of secure keys for a concurrent HSM master key change for openCryptoki. Secure keys are encrypted by the HSM master key(s). The HSM master key(s) must be changed (rolled) from time to time, dependent on policies defined by the HSM security officer. Whenever a HSM master key is changed, all secure keys that are encrypted with that HSM master key must be re-enciphered with the new to be set master key. .PP Changing HSM master keys needs to be coordinated between the HSM security officer and an openCryptoki administrator. The HSM security officer performs a master key change via the TKE (Trusted Key Entry), while the openCryptoki administrator performs administrative steps using the \fBpkcshsm_mk_change\fP tool to re-encipher all openCryptoki token and session key objects, as well as currently active crypto operation states with the new master key. Applications using those keys can continue to run, the re-enciphering process takes place transparently to them. \fBImportant:\fB CCA does not support the concept of APQNs when running on AIX, Linux on x64, and Linux on Power; whenever an APQN is being used as input, the user must specify the value \fB0.0\fB. .PP A concurrent master key change works as follows: .RS 2 .nr step 1 1 .IP "\n[step]." 3 The HSM security officer loads the new master keys using the TKE into the NEW register of the set of APQNs logically belonging together. .IP "\n+[step]." 3 The HSM security officer notifies the openCryptoki administrator that new master keys have been loaded for all the APQNs. . .IP "\n+[step]." 3 The openCryptoki administrator uses the \fBpkcshsm_mk_change\fP to initiate a master key change for openCryptoki, specifying the set of APQNs (and master key types) that are to be changed. The \fBpkcshsm_mk_change\fP tool communicates with running applications and performs/controls re-encipherment of the key objects with the new master key. . .IP "\n+[step]." 3 When the \fBpkcshsm_mk_change\fP tool has completed its re-encipherment processing, the openCryptoki administrator notifies the HSM security officer that openCryptoki is ready to set/activate the new master keys. . .IP "\n+[step]." 3 The HSM security officer coordinates with other (non-openCryptoki) applications and once all users of the APQNs are OK, he sets/activates the new master keys on the APQNs. . .IP "\n+[step]." 3 The HSM security officer notifies the openCyptoki administrator when for all APQNs the new master key have been set/activated. . .IP "\n+[step]." 3 The openCryptoki administrator uses the \fBpkcshsm_mk_change\fP tool to finalize the master key change for openCryptoki. The tool communicates with running applications and performs/controls finalizing the re-encipherment of the key objects with the new master key. . .IP "\n+[step]." 3 When the \fBpkcshsm_mk_change\fP tool has completed its finalizing processing, the master key change operation is complete. .RE . .PP The whole procedure can take an arbitrary amount of time. Especially the time between the moment when the new master key has been loaded on all APQNs, and the moment the new master keys are set/activated can even last several days, due to time required for coordination with other (non-openCryptoki) applications/users of the APQNs to prepare for the master key change. .PP The time to perform the re-encipherment and finalization (steps 3 and 7) of all key objects as such depends on the amount of keys and openCryptoki applications using them, but is usually relatively short, i.e. seconds up to a few minutes. .PP The system where openCryptoki runs may be restarted while a master key change is ongoing, provided that the re-encipherment and finalization steps (steps 3 and 7) are not interrupted. .PP An ongoing master key change operation can be canceled using the \fBpkcshsm_mk_change\fP tool, as long as for none of the APQNs the new master key has been set/activated, that is up to step 5 from above. . .SH COMMANDS .SS "Initiate a master key change for openCryptoki" . .B pkcshsm_mk_change reencipher .RB [ \-\-apqns | \-a .IR APQNS ] .RB [ \-\-ep11\-wkvp | \-e .IR WKVP ] .RB [ \-\-cca\-sym\-mkvp | \-s .IR MKVP ] .RB [ \-\-cca\-asym\-mkvp | \-S .IR MKVP ] .RB [ \-\-cca\-aes\-mkvp | \-A .IR MKVP ] .RB [ \-\-cca\-apka\-mkvp | \-p .IR MKVP ] .RB [ \-\-verbose | \-v .IR LEVEL ] .PP . Use the \fBreencipher\fP command to initiate a master key change operation for the specified APQNs and master key types and re-encipher all session and token key objects of the affected tokens. For each master key type that is changed, the verification pattern of the new, to be set master key must be specified. .PP A CryptoExpress adapter in \fBCCA\fP coprocessor mode has 4 different master keys: \fBSYM\fP, \fBASYM\fP, \fBAES\fP, and \fBAPKA\fP. The CCA token of openCryptoki only uses SYM, AES, and APKA. Each master key type can be change individually, or together with others. You can use the TKE or the \fBpanel.exe\fP tool to query the master key verification patterns: .B 'panel.exe --mk-query --mktype= --mkregister=NEW'. For master key types \fBSYM\fP and \fBASYM\fP, use the hex string under \fB[RND]\fP, for types \fBAES\fP and \fBAPKA\fP use the hex string under \fB[VER]\fP. For AES and APKA you can also find the master key verification patterns in sysfs: .B 'cat /sys/bus/ap/devices/./mkvps'. .PP A CryptoExpress adapter in \fBEP11\fP coprocessor mode has only one master key, called the EP11 wrapping key (WK). You can use the TKE or the \fBep11info\fP tool to query the current wrapping key verification pattern (WKVP) of an EP11 APQN: .B 'ep11info -m -d -D'. You can also find the wrapping key verification pattern for EP11 APQNs in sysfs: .B 'cat /sys/bus/ap/devices/./mkvps'. .PP the \fBpkcshsm_mk_change reencipher\fP command will query all available slots and determine if the token in the slot is affected by the master key change, based on the list of APQNs and master key types. For each affected slot, it prompts for the \fBUSER pin\fP. .PP On successful completion, the id of the master key change operation is displayed. This id must later be specified when finalizing or canceling the operation using the \fBfinalize\fP or \fBcancel\fP command. . .SS "Finalize a master key change for openCryptoki" . .B pkcshsm_mk_change finalize .RB [ \-\-id | \-i .IR OPERATION-ID ] .RB [ \-\-verbose | \-v .IR LEVEL ] .PP . Use the \fBfinalize\fP command to finalize a master key change operation when the new master key has been activated on the APQNs. The id of the master key change operation to finalize must be specified. . .SS "Cancel a master key change for openCryptoki" . .B pkcshsm_mk_change cancel .RB [ \-\-id | \-i .IR OPERATION-ID ] .RB [ \-\-verbose | \-v .IR LEVEL ] .PP . Use the \fBcancel\fP command to finalize a master key change operation. The id of the master key change operation to cancel must be specified. A master key change operation can only be canceled as long as for none of the APQNs the new master key have been set/activated. . .SS "List master key change operations" . .B pkcshsm_mk_change list .RB [ \-\-id | \-i .IR OPERATION-ID ] .RB [ \-\-verbose | \-v .IR LEVEL ] .PP . Use the \fBlist\fP command to list currently active master key change operations. If no operation ID is specified, all currently active master key change operations are displayed, otherwise only the specified one is displayed. .SH "OPTIONS" .TP .BR \-a ", " \-\-apqns\~\fIAPQNS\fP Specifies a comma separated list of APQNs for which a master key change is to be performed. Each APQN must be specified in the form \fB card.domain\fP, where both \fBcard\fP and \fBdomain\fP are in hex, as displayed by the \fBlszcrypt\fP command. Multiple APQNs are separated by a comma. This options is only valid with the \fBreencipher\fP command. .TP .BR \-e ", " \-\-ep11\-wkvp\~\fIWKVP\fP Specifies the EP11 wrapping key verification pattern (WKVP) of the new, to be set EP11 wrapping key as a 16 bytes hex string. This options is only valid with the \fBreencipher\fP command. You can use the TKE or the \fBep11info\fP tool to query the current wrapping key verification pattern (WKVP) of an EP11 APQN: .B 'ep11info -m -d -D'. You can also find the wrapping key verification pattern for EP11 APQNs in sysfs: .B 'cat /sys/bus/ap/devices/./mkvps'. .TP .BR \-s ", " \-\-cca\-sym\-mkvp\~\fIMKVP\fP Specifies the CCA master key verification pattern (MKVP) of the new, to be set CCA SYM master key as a 8 bytes hex string. This options is only valid with the \fBreencipher\fP command. You can use the TKE or the \fBpanel.exe\fP tool to query the master key verification patterns: .B 'panel.exe --mk-query --mktype=SYM --mkregister=NEW'. Use the hex string under \fB[RND]\fP. .TP .BR \-S ", " \-\-cca\-asym\-mkvp\~\fIMKVP\fP Specifies the CCA master key verification pattern (MKVP) of the new, to be set CCA ASYM master key as a 8 bytes hex string. This options is only valid with the \fBreencipher\fP command. You can use the TKE or the \fBpanel.exe\fP tool to query the master key verification patterns: .B 'panel.exe --mk-query --mktype=ASYM --mkregister=NEW'. Use the hex string under \fB[RND]\fP. .TP .BR \-A ", " \-\-cca\-aes\-mkvp\~\fIMKVP\fP Specifies the CCA master key verification pattern (MKVP) of the new, to be set CCA AES master key as a 8 bytes hex string. This options is only valid with the \fBreencipher\fP command. You can use the TKE or the \fBpanel.exe\fP tool to query the master key verification patterns: .B 'panel.exe --mk-query --mktype=AES --mkregister=NEW'. Use the hex string under \fB[VER]\fP. You can also find the AES master key verification patterns in sysfs: .B 'cat /sys/bus/ap/devices/./mkvps'. .TP .BR \-p ", " \-\-cca\-apka\-mkvp\~\fIMKVP\fP Specifies the CCA master key verification pattern (MKVP) of the new, to be set CCA APKA master key as a 8 bytes hex string. This options is only valid with the \fBreencipher\fP command. You can use the TKE or the \fBpanel.exe\fP tool to query the master key verification patterns: .B 'panel.exe --mk-query --mktype=APKA --mkregister=NEW'. Use the hex string under \fB[VER]\fP. You can also find the APKA master key verification patterns in sysfs: .B 'cat /sys/bus/ap/devices/./mkvps'. .TP .BR \-i ", " \-\-id\~\fIOPERATION-ID\fP Specifies the id of the master key change operation for the \fBfinalize\fP, \fBcancel\fP, or \fBlist\fP command. On successful completion of the \fBreencipher\fP command, the id of the master key change operation is displayed. .TP .BR \-v ", " \-\-verbose\~\fILEVEL\fP Specifies the verbose level (optional): \fBnone\fP (default), \fBerror\fP, \fBwarn\fP, \fBinfo\fP, \fBdevel\fP, or \fBdebug\fP. .TP .BR \-h ", " \-\-help Displays help text and exits. .SH SEE ALSO .PD 0 .TP \fBopencryptoki\fP(7) .PDopencryptoki-opencryptoki-451d99c/man/man1/pkcsicsf.1.in000066400000000000000000000053021520105705100232270ustar00rootroot00000000000000.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. The \fBpkcsicsf\fP utility must be run as root when adding an ICSF token to opencryptoki. .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 opencryptoki-opencryptoki-451d99c/man/man1/pkcsstats.1.in000066400000000000000000000136531520105705100234510ustar00rootroot00000000000000.\" pkcsstats.1 .\" .\" Copyright IBM Corp. 2021 .\" See LICENSE for details. .\" .TH PKCSSTATS 1 "October 2021" "@PACKAGE_VERSION@" "openCryptoki" .SH NAME pkcsstats \- utility to display mechanism usage statistics for openCryptoki. .SH SYNOPSIS .B pkcsstats .RB [ OPTIONS ] . .PP .B pkcsstats .BR \-\-help | \-h .br .SH DESCRIPTION Displays mechanism usage statistics for openCryptoki. Usage statistics are collected by openCryptoki on a per user basis. For each user, mechanism usage is counted per configured slot and mechanism. For each mechanism a set of counters exist, one for each cryptographic strength of the cryptographic key used with the mechanism. .PP The available strengths are defined in the strength configuration file \fB/etc/opencryptoki/strength.conf\fP. Supported strengths are 112, 128, 192, and 256 representing the corresponding strength in bits. The strength configuration file defines how the strength is determined for the various key types. A strength of zero is used to count those mechanisms that do not use a key, or where the key strength is less than 112 bits. .PP .B Note: The strength does not specify the cryptographic strength of the mechanism, but the cryptographic strength of the key used with the mechanism (if any). For example, usage of mechanism CKM\_SHA256 is reported under strength 0, because no key is used with this mechanism. However, usage of mechanism CKM\_AES\_CBC is reported under strength 128, 192, or 256, dependent on the cryptographic size of the AES key used with it (and the definitions in the strength configuration file). .PP Statistics collection is enabled by default. It can be disabled and configured in the openCryptoki configuration file \fB/etc/opencryptoki/opencryptoki.conf\fP. By default only explicit mechanism usage statistics from PKCS#11 applications are collected. .PP Optionally, implicit mechanism usage statistics can be collected, where additional mechanisms are specified in mechanism parameters. For example, RSA\-PSS or RSA\-OAEP allows to specify a hash mechanism and a mask generation function (MGF) in the mechanism parameter. ECDH allows to specify a key derivation function (KDF) in the mechanism parameter. The PBKDF2 mechanism allows to specify a pseudo random function (PRF) in the mechanism parameter. .PP Also optionally, opencryptoki\-internal mechanism usage statistics can be collected. This collects usage statistics for crypto operations used internally for pin handling and encryption of private token objects in the data store. .PP .B Note: Implicit or internal mechanism usage can not be distinguished from explicit mechanism usage of PKCS#11 applications in the displayed statistics. .PP Statistics are collected in a POSIX shared memory segment per user. This shared memory segment contains all counters for all configured slots, mechanisms, and strengths. The shared memory segments are named \fBvar.lib.opencryptoki_stats_\fP, where \fBuid\fP is the numeric user\-id of the user the statistics belong to. The shared memory segments are automatically created for a user on the first attempt to collect statistics (when not already existent). The shared memory segments can be deleted using the \fBpkcsstats\fP command with the \fB\-\-delete\fP, or \fB\-\-delete\-all\fP options. .PP The usage of a mechanism is counted once when the cryptographic operation is sucessfully initialized, i.e. during \fBC_DigestInit\fP, \fBC_EncryptInit\fP, \fBC_DecryptInit\fP, \fBC_SignInit\fP, \fBC_SignRecoverInit\fP, and \fBC_VerifyInit\fP. Multi-part operations involving the update functions like \fBC_DigestUpdate\fP, \fBC_EncryptUpdate\fP, \fBC_DecryptUpdate\fP, \fBC_SignUpdate\fP, and \fBC_VerifyUpdate\fP, are not counted additionally. .PP Other operations such as key generation, key derivation, key wrapping and unwrapping are counted during the respective functions like \fBC_GenerateKey\fP, \fBC_GenerateKeyPair\fP, \fBC_DeriveKey\fP, \fBC_DeriveKey\fP, \fBC_UnwrapKey\fP. .SH "OPTIONS" .TP .BR \-U ", " \-\-user\~\fIuser\-id\fP Specifies the user\-id of the user to display, reset, or delete statistics for. If this option is omitted, the statistics of the current user are displayed, resetted, or deleted. Only the \fBroot\fP user can display, reset, or delete statistics of other users. .TP .BR \-S ", " \-\-summary Shows the accumulated statistics from all users. Only the \fBroot\fP user can display the accumulated statistics from other users. .TP .BR \-A ", " \-\-all Shows the statistics from all users. Only the \fBroot\fP user can display statistics from all users. .TP .BR \-a ", " \-\-all\-mechs Shows the statistics for all mechanisms, also those with all\-zero counters. If this option is omitted, only those mechanisms are displayed where at least one counter is non\-zero. .TP .BR \-s ", " \-\-slot\~\fIslot\-id\fP Specifies the slot\-id to display statistics for. If this option is omitted, the statistics for all configured slots are displayed. .TP .BR \-r ", " \-\-reset Resets the statistics counters for the current user, or for the user specified with the \fB\-\-user\fP option. Only the \fBroot\fP user can reset the statistics from other users. .TP .BR \-R ", " \-\-reset\-all Resets the statistics counters for all users. Only the \fBroot\fP user can reset the statistics from other users. .TP .BR \-d ", " \-\-delete Deletes the shared memory segment containing the statistics counters for the current user, or for the user specified with the \fB\-\-user\fP option. Only the \fBroot\fP user can delete the statistics from other users. .TP .BR \-D ", " \-\-delete\-all Deletes the shared memory segment containing the statistics counters for all users. Only the \fBroot\fP user can delete the statistics from other users. .TP .BR \-j ", " \-\-json Shows the statistics in JSON format. This is usefull to get the statistics in a machine readable format. .TP .BR \-h ", " \-\-help Displays help text and exits. .SH SEE ALSO .PD 0 .TP \fBopencryptoki.conf\fP(5). .TP \fBstrength.conf\fP(5), .TP \fBopencryptoki\fP(7), .PD opencryptoki-opencryptoki-451d99c/man/man1/pkcstok_admin.1.in000066400000000000000000000256331520105705100242610ustar00rootroot00000000000000.TH pkcstok_admin 1 "July 2024" "@PACKAGE_VERSION@" "openCryptoki" .SH NAME pkcstok_admin \- utility to administrate token directories of the Opencryptoki token repository. . . . .SH SYNOPSIS . .B pkcstok_admin .I command .RB [ OPTIONS ] .PP . .B pkcstok_admin .BR \-\-help | \-h .br .B pkcstok_admin .BR \-\-version | \-v . . . .SH DESCRIPTION . The \fBpkcstok_admin\fP utility can be used to administrate token directories of the Opencryptoki token repository with proper permissions and owners. By default token directories are owned by the \fB@pkcs_group@\fP group, and every user that is a member of the \fB@pkcs_group@\fP group has access to the token and its token objects (i.e. keys, certificates, etc.). .PP A token directory can alternatively be owned by a token specific group. Specify the group name with keyword \fBusergroup\fP in the slot definition in the \fBopencryptoki.conf\fP configuration file located in \fB@sysconfdir@/opencryptoki/\fP. With that, only users that are members of the configured token specific group have access to the token and its token objects. Users that are only members of the \fB@pkcs_group@\fP group, but are not also members of the token specific group do not have access to the token. Users of the token specific group must still also be members of the \fB@pkcs_group@\fP group to be able to use Opencryptoki. .PP Token specific files are usually stored in \fB@localstatedir@/lib/opencryptoki//\fP. Additionally token specific lock files are stored in \fB@localstatedir@/lock/opencryptoki//\fP. Furthermore, a token specific POSIX shared memory segment exists under \fB/dev/shm/\fP. All files and directories within these token specific directories as well as the shared memory segment are owned by the token specific group, or by the \fB@pkcs_group@\fP group if no token specific group has been configured. .PP The \fBpkcstok_admin\fP utility must be run as \fBroot\fP, and the \fBpkcsslotd\fP must be stopped before running this utility. .PP .PP .B Note: Do not use the \fBpkcstok_admin\fP utility on a \fBTPM token\fP. The \fBTPM token\fP uses a different directory structure, and stores token objects on a per user basis. The \fBpkcstok_admin\fP utility is not capable of setting the owners correctly on such a directory structure. Furthermore, the \fBTPM token\fP is deprecated, because it supports only TPM version 1.2. It does not work with TPM version 2.0. . . . .SH COMMANDS . The \fBpkcstok_admin\fP tool supports various commands to administrate token directories. .PP .SS "Creating a new token and its directories" .B pkcstok_admin .B create .BR \-\-token | \-t .I TOKNAME .RB [ \-\-group | \-g .IR GROUP ] .RB [ \-\-force ] .RB [ \-\-verbose ] .PP Use the \fBcreate\fP command to create a new token and its directories. .PP Use the .BR \-\-token | \-t .I TOKNAME option to specify the name of the token to create. The token name must also be specified in the slot definition in the \fBopencryptoki.conf\fP configuration file located in \fB@sysconfdir@/opencryptoki/\fP with keyword \fBtokname\fP. .PP Use the .RB [ \-\-group | \-g .IR GROUP ] option to specify the token specific user group used as group owner of the token directories. If no group is specified, the token directories will be owned by the \fB@pkcs_group@\fP group. If a group is specified, then it must also be specified in the slot definition in the \fBopencryptoki.conf\fP configuration file located in \fB@sysconfdir@/opencryptoki/\fP with keyword \fBusergroup\fP. .PP The \fBpkcstok_admin\fP tool prompts for a confirmation before the token directories are created. To omit the prompt, specify the .B \-\-force option. Use this option with care! .PP Specify the .B \-\-verbose option to see more detailed messages about the actions the tool is performing. . . . .PP .SS "Changing the owner of an existing token and its directories" .B pkcstok_admin .B chown .BR \-\-token | \-t .I TOKNAME .RB [ \-\-group | \-g .IR GROUP ] .RB [ \-\-force ] .RB [ \-\-verbose ] .PP Use the \fBchown\fP command to change the owner of an existing token and its directories. .PP Use the .BR \-\-token | \-t .I TOKNAME option to specify the name of the token to change the owner for. The token name is usually specified in the slot definition in the \fBopencryptoki.conf\fP configuration file located in \fB@sysconfdir@/opencryptoki/\fP with keyword \fBtokname\fP. If the slot definition does not specify a \fBtokname\fP keyword, then a default token name is used, dependent on the token model. The \fBICA token\fP uses \fBlite\fP as default token name, the \fBCCA token\fP uses \fBccatok\fP, the \fBSoft token\fP uses \fBswtok\fP, the \fBEP11 token\fP uses \fBep11tok\fP, the \fBICSF token\fP uses \fBicsf\fP, and the \fBTPM token\fP (deprecated) uses \fBtpm\fP. .PP Use the .RB [ \-\-group | \-g .IR GROUP ] option to specify the token specific user group to set as group owner of the token directories. If no group is specified, the token directories will be changed to be owned by the \fB@pkcs_group@\fP group. If a group is specified, then it must also be specified in the slot definition in the \fBopencryptoki.conf\fP configuration file located in \fB@sysconfdir@/opencryptoki/\fP with keyword \fBusergroup\fP. If no group is specified, then remove the \fBusergroup\fP keyword from the slot definition, or change its value to \fB@pkcs_group@\fP. .PP The \fBpkcstok_admin\fP tool prompts for a confirmation before the owner of the token directories is changed. To omit the prompt, specify the .B \-\-force option. Use this option with care! .PP Specify the .B \-\-verbose option to see more detailed messages about the actions the tool is performing. . . . .PP .SS "Removing an existing token and its directories" .B pkcstok_admin .B remove .BR \-\-token | \-t .I TOKNAME .RB [ \-\-force ] .RB [ \-\-verbose ] .PP Use the \fBremove\fP command to remove an existing token and its directories. This also removes all token objects of that token. Use with care! .PP Use the .BR \-\-token | \-t .I TOKNAME option to specify the name of the token to remove. You must also remove the corresponding slot definition from the \fBopencryptoki.conf\fP configuration file located in \fB@sysconfdir@/opencryptoki/\fP. The token name is usually specified in the slot definition in the \fBopencryptoki.conf\fP configuration file. If the slot definition does not specify a \fBtokname\fP keyword, then a default token name is used, dependent on the token model. The \fBICA token\fP uses \fBlite\fP as default token name, the \fBCCA token\fP uses \fBccatok\fP, the \fBSoft token\fP uses \fBswtok\fP, the \fBEP11 token\fP uses \fBep11tok\fP, the \fBICSF token\fP uses \fBicsf\fP, and the \fBTPM token\fP (deprecated) uses \fBtpm\fP. .PP The \fBpkcstok_admin\fP tool prompts for a confirmation before the token directories are removed. To omit the prompt, specify the .B \-\-force option. Use this option with care! .PP Specify the .B \-\-verbose option to see more detailed messages about the actions the tool is performing. . . . .PP .SS "Resetting a token to its initial state" .B pkcstok_admin .B reset .BR \-\-token | \-t .I TOKNAME .RB [ \-\-force ] .RB [ \-\-verbose ] .PP Use the \fBreset\fP command to reset a token to its initial state. This also resets all PINs and removes all token objects. Use with care! .PP Resetting a token can be required if you forgot the SO pin, or the SO pin got locked due to too many login attempts using a wrong SO PIN. .PP Use the .BR \-\-token | \-t .I TOKNAME option to specify the name of the token to reset. The token name is usually specified in the slot definition in the \fBopencryptoki.conf\fP configuration file located in \fB@sysconfdir@/opencryptoki/\fP with keyword \fBtokname\fP. If the slot definition does not specify a \fBtokname\fP keyword, then a default token name is used, dependent on the token model. The \fBICA token\fP uses \fBlite\fP as default token name, the \fBCCA token\fP uses \fBccatok\fP, the \fBSoft token\fP uses \fBswtok\fP, the \fBEP11 token\fP uses \fBep11tok\fP, the \fBICSF token\fP uses \fBicsf\fP, and the \fBTPM token\fP (deprecated) uses \fBtpm\fP. .PP The \fBpkcstok_admin\fP tool prompts for a confirmation before the token is resetted. To omit the prompt, specify the .B \-\-force option. Use this option with care! .PP Specify the .B \-\-verbose option to see more detailed messages about the actions the tool is performing. .PP After resetting a token, it must be initialized freshly using \fBpkcsconf -I\fP, setting the SO pin using \fBpkcsconf -P\fP and then initializing the USER pin using \fBpkcsconf -u\P. . . . .SH OPTIONS . .TP 8 .BR \-\-token | \-t\~\fITOKNAME\fP Specifies the name of the token to operate on. The token name must also be specified in the slot definition in the \fBopencryptoki.conf\fP configuration file located in \fB@sysconfdir@/opencryptoki/\fP with keyword \fBtokname\fP. If the slot definition does not specify a \fBtokname\fP keyword, then a default token name is used, dependent on the token model. The \fBICA token\fP uses \fBlite\fP as default token name, the \fBCCA token\fP uses \fBccatok\fP, the \fBSoft token\fP uses \fBswtok\fP, the \fBEP11 token\fP uses \fBep11tok\fP, the \fBICSF token\fP uses \fBicsf\fP, and the \fBTPM token\fP (deprecated) uses \fBtpm\fP. .RE .PP . .TP 8 .BR \-\-group | \-g\~\fIGROUP\fP Specifies the token specific user group used as group owner of the token directories. If this option is omitted, the token directories will be owned by the \fB@pkcs_group@\fP group. If a group is specified, then it must also be specified in the slot definition in the \fBopencryptoki.conf\fP configuration file located in \fB@sysconfdir@/opencryptoki/\fP with keyword \fBusergroup\fP. .RE .PP . .TP 8 .BR \-\-force | \-f The \fBpkcstok_admin\fP tool prompts for a confirmation before the token directories are created. To omit the prompt, specify this option. Use this with care! .RE .PP . .TP 8 .BR \-\-verbose | \-V Turn on verbose mode to see more detailed messages about the actions the tool is performing. .RE .PP . .TP 8 .BR \-\-help | \-h Prints help for the usage of the .B pkcstok_admin tool and then exits. .RE .PP . .TP 8 .BR \-\-version | \-v Prints the version of the .B pkcstok_admin tool and then exits. .RE .PP . . . .SH "FILES" . .SS "@localstatedir@/lib/opencryptoki//" Contains the token specific data, like the token's master key encrypted with the SO and USER PINs (\fBMK_SO\fP and \fBMK_USER\fP), as well as the non volatile token state data (\fBNVTOK.DAT\fP). Subdirectory \fBTOK_OBJ\fP contains the token objects and an index file (\fBOBJ.IDX\fP). . .SS "@localstatedir@/lock/opencryptoki//" Contains a token specific lock file (\fBLCK..\fP) that is used to synchronize access to the token data across multiple processes. .SS "Token specific POSIX shared memory segment under /dev/shm/" Contains token specific shared state data for tracking updates to token objects done by processes. Its name is derived from the token specific directory under \fB@localstatedir@/lib/opencryptoki/\fP. . . . .SH SEE ALSO . .PD 0 \fBopencryptoki.conf\fP(5). .PDopencryptoki-opencryptoki-451d99c/man/man1/pkcstok_migrate.1.in000066400000000000000000000054371520105705100246210ustar00rootroot00000000000000.\" pkcstok_migrate.1 .\" .\" Copyright IBM Corp. 2020 .\" See LICENSE for details. .\" .TH PKCSTOK_MIGRATE 1 "June 2020" "@PACKAGE_VERSION@" "openCryptoki" .SH NAME pkcstok_migrate \- utility to migrate an ICA, CCA, Soft, or EP11 token repository to the FIPS compliant format introduced with openCryptoki 3.12. .SH SYNOPSIS \fBpkcstok_migrate\fP [\fB-h\fP] .br \fBpkcstok_migrate\fP \fB--slotid\fP \fIslot-number\fP \fB--datastore\fP \fIdatastore\fP \fB--confdir\fP \fIconfdir\fP [\fB--sopin\fP \fIsopin\fP] [\fB--userpin\fP \fIuserpin\fP] [\fB--verbose\fP \fIlevel\fP] .SH DESCRIPTION Convert all objects inside a token repository to the new format introduced with version 3.12. All encrypted data inside the new format is stored using FIPS compliant methods. The new format affects the token's master key files (MK_SO and MK_USER), the NVTOK.DAT, and the token object files in the TOK_OBJ folder. While using this tool no process using the token to be migrated must be running. Especially the pkcsslotd must be stopped before running this tool. The tool creates a backup of the token repository to be migrated, and performs all migration actions on this backup, leaving the original repository folder completely untouched. The backup folder is located in the same directory as the original repository and is suffixed with _PKCSTOK_MIGRATE_TMP. After a successful migration, the original repository is renamed with a suffix of _BAK and the backup folder is renamed to the original repository name, so that the migrated repository can immediately be used. The old folder may be deleted by the user manually later. After a successful migration, the tool adds parameter 'tokversion = 3.12' to the token's slot configuration in the opencryptoki.conf file. The original config file is still available as opencryptoki.conf_BAK and may be removed by the user manually. After an unsuccessful migration, the original repository is still available unchanged. The \fBpkcstok_migrate\fP utility must be run as root. .SH "OPTIONS SUMMARY" .IP "\fB--slotid -s\fP \fISLOT-NUMBER\fP" 10 specifies the token slot number of the token repository to be migrated .IP "\fB--datastore -d\fP \fIDATASTORE\fP" 10 specifies the directory of the token repository to be migrated. .IP "\fB--confdir -c\fP \fICONFDIR\fP" 10 specifies the directory where the opencryptoki.conf file is located. .IP "\fB--sopin -p\fP \fISOPIN\fP" 10 specifies the SO pin. If not specified, the SO pin is prompted. .IP "\fB--userpin -u\fP \fIUSERPIN\fP" 10 specifies the user pin. If not specified, the user pin is prompted. .IP "\fB--verbose -v\fP \fILEVEL\fP" 10 specifies the verbose level: \fInone\fP, error, warn, info, devel, debug .IP "\fB--help -h\fP" 10 show usage information .SH SEE ALSO .PD 0 .TP \fBpkcsconf\fP(1), .TP \fBopencryptoki\fP(7), .TP \fBpkcsslotd\fP(8). .PD opencryptoki-opencryptoki-451d99c/man/man5/000077500000000000000000000000001520105705100207375ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/man/man5/man5.mk000066400000000000000000000003411520105705100221260ustar00rootroot00000000000000man5_MANS += man/man5/opencryptoki.conf.5 man/man5/strength.conf.5 man/man5/policy.conf.5 if ENABLE_P11SAK man5_MANS += man/man5/p11sak_defined_attrs.conf.5 endif if ENABLE_P11KMIP man5_MANS += man/man5/p11kmip.conf.5 endifopencryptoki-opencryptoki-451d99c/man/man5/opencryptoki.conf.5.in000066400000000000000000000111431520105705100251040ustar00rootroot00000000000000.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 optional global definitions, and slot descriptions. The following global definitions are valid: .TP .BR disable-event-support If this keyword is specified the openCryptoki event support is disabled. .TP .BR statistics\~(off | on [ ,implicit ][ ,internal ] ) Enables or disables collection of statistics of mechanism usage. By default, statistics collection is enabled. A value of \fB(off)\fP disables all statistics collection. A value of \fB(on)\fP enables collection of mechanism usage. The collected statistics can be displayed using the \fBpkcsstats\fP tool. In addition to enabling statistics collection for mechanisms used by PKCS#11 applications, you can specify \fB(on,implicit)\fP to also enable collection of implicit mechanism usage, where additional mechanisms are specified in mechanism parameters. For example, RSA-PSS or RSA-OAEP allow to specify a hash mechanism and a mask generation function (MGF) in the mechanism parameter. ECDH allows to specify a key derivation function (KDF) in the mechanism parameter. You can additionally enable statistics collection of mechanisms internally used by Opencryptoki by specifying \fB(on,internal)\fP. This additionally collects usage statistics for crypto operations used internally for pin handling and encryption of private token objects in the data store. Implicit and internal statistics collection can also be combined: \fB(on,implicit,internal)\fP .P 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 .. .TP .BR usergroup Specifies the name of a user group that is set as the owner of the token directory. Only users that are members of this group have access to the token and its objects. Users that are not a member of this group will not see the token as being available (e.g. via \fBpkcsconf -t\fP or via \fBC_GetTokenInfo\fP). All uses that are a member of this group must also be members of the \fB@pkcs_group@\fP group to be able to use Opencryptoki. Note: This key-value pair is optional: If not specified, the token belongs to the \fB@pkcs_group@\fP group. .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), .TP \fBpkcsstats\fP(1), .PD opencryptoki-opencryptoki-451d99c/man/man5/p11kmip.conf.5.in000066400000000000000000000075011520105705100236430ustar00rootroot00000000000000.TH P11KMIP.CONF 5 "August 2023" "@PACKAGE_VERSION@" "openCryptoki" .SH NAME p11kmip.conf \- Configuration file for the \fBp11kmip\fP command. . . . .SH DESCRIPTION The .B p11kmip tool uses the configuration file \fB/etc/opencryptoki/p11kmip.conf\fP to read information about how to connect to a KMIP server and interact with a PKCS\~#11 token repository. .PP A custom file path can be set with environment variable \fBP11KMIP_DEFAULT_CONF_FILE\fP. If the environment variable is not set, then the global \fB/etc/opencryptoki/p11kmip.conf\fP config file is read. If this file is unavailable, an error message is displayed. . . . .SH SYNTAX . .P There are two sections in the configuration. Both consist of a title, brackets, and a set of key\-value pairs. The first section configures the connection to the KMIP server. It contains the following keywords: \fBhost\fR, \fBtls_client_cert\fR, \fBtls_client_key\fR, \fBwrap_key_format\fR, \fBwrap_key_algorithm\fR, \fBwrap_key_size\fR, \fBwrap_padding_method\fR, \fBwrap_hashing_algorithm\fR. .PP Example: kmip { host = "0.0.0.0:5696" tls_client_cert = "/tmp/certs/client_certificate_jane_doe.pem" tls_client_key = "/tmp/certs/client_key_jane_doe.pem" wrap_key_format = "PKCS1" wrap_key_algorithm = "RSA" wrap_key_size = 2048 wrap_padding_method = "PKCS1.5" wrap_hashing_algorithm = "SHA-1" } The .B host attribute must be specified in the format "hostname[:port]" when using plain TLS, where "hostname" may be an IPv4 address, IPv6 address, or a symbolical hostname, and "port" may optionally be used to specify a non-standard port number. If "port" is not specified, 5696 is used as the default. The .B tls_client_cert attribute must specify the path to a PEM format file containing the client certificate used for TLS authentication to the KMIP server. The .B tls_client_key attribute must specify the path to a PEM format file containing the client private key used for TLS authentication to the KMIP server. The .B wrap_key_format attribute specifies the format used to transmit the wrapping key, and must be one of "PKCS1", "PKCS8", or "TransparentPublicKey". The .B wrap_key_algorithm attribute specifies the algorithm used for key wrapping. Currently only "RSA" is supported. The .B wrap_key_size attribute specifies the length of the key used for wrapping. This value must match the length of the actual wrapping and unwrapping key which are provided when the tool is invoked. The .B wrap_padding_method attribute specifies padding method used during the key wrap. Currently padding methods "PKCS1.5" and "OAEP" are supported. The .B wrap_hashing_algorithm specifies the hashing algorithm used by the padding method. Only the "OAEP" padding method requires a hashing algorithm to be specified. For the "OAEP" padding method, only the "SHA-1" and "SHA-256" hashing algorithms are supported. For all other padding methods this field is ignored, and may be absent. The second section configures interaction with the PKCS\~#11 token repository. It contains the following keyword: .B slot . .PP Example: pkcs11 { slot = 0 } The .B slot attribute must be an integer specifying the slot number to use. Of these attributes, the .B host , .B tls_client_cert , .B tls_client_key attributes of the .B kmip section and the .B slot attribute of the .B pkcs11 section may be absent from the file if specified by an environment variable or command option. The remaining attributes will be treated as the the default values shown in this example when they are absent. The configuration file need not be present if all required attributes are specified by other means. Attributes and groups may be specified in any order within the configuration file. .PP .SH Notes The pound sign ('#') is used to indicate a comment up to and including the end of line. .SH "SEE ALSO" .PD 0 .TP \fBp11kmip\fP(1) .PD opencryptoki-opencryptoki-451d99c/man/man5/p11sak_defined_attrs.conf.5.in000066400000000000000000000033341520105705100263540ustar00rootroot00000000000000.TH P11SAK_DEFINED_ATTRS.CONF 5 "September 2021" "@PACKAGE_VERSION@" "openCryptoki" .SH NAME p11sak_defined_attrs.conf \- Configuration file for \fBp11sak list\-key\fP command. . . . .SH DESCRIPTION The .B p11sak tool uses the configuration files \fB~/.p11sak_defined_attrs.conf\fP and \fB/etc/opencryptoki/p11sak_defined_attrs.conf\fP to read information about custom attributes that shall be printed with the \fBp11sak list\-key\fP command. .PP This configuration file path can be overwritten by the user with the environment variable \fBP11SAK_DEFAULT_CONF_FILE\fP. If the environment variable is not set, then \fB.p11sak_defined_attrs.conf\fP is first tried to be read from the current user's home directory. If this is not available, the global \fB/etc/opencryptoki/p11sak_defined_attrs.conf\fP config file is read. If none of these files are available, a warning message is displayed, and printing of custom attributes is not available. . . . .SH SYNTAX . .P Each attribute description is composed of the attribute title, brackets and three key\-value pairs. .PP Example: attribute { name = CKA_IBM_RESTRICTABLE id = 0x80010001 type = CK_BBOOL } All three keywords .B name , .B id , .B type are required to define an attribute. The .B name must start with a letter followed by an arbitrary number of letters, numbers, underscores, dots, minuses, or slashes. The .B id can be in decimal as well as in hexadecimal, when started with 0x, format. The only valid values for .B type are: .IP "\(bu" 2 .B CK_BBOOL .IP "\(bu" 2 .B CK_ULONG .IP "\(bu" 2 .B CK_BYTE .IP "\(bu" 2 .B CK_DATE .PP .SH Notes The pound sign ('#') is used to indicate a comment up to and including the end of line. .SH "SEE ALSO" .PD 0 .TP \fBp11sak\fP(1) .PD opencryptoki-opencryptoki-451d99c/man/man5/policy.conf.5.in000066400000000000000000000140061520105705100236560ustar00rootroot00000000000000.TH POLICY.CONF 5 "September 2021" "@PACKAGE_VERSION@" "openCryptoki" .SH NAME policy.conf \- Configuration file for openCryptoki policies. .SH DESCRIPTION openCryptoki uses a policy configuration file at /etc/opencryptoki/policy.conf This configuration file restricts the operations of openCryptoki to a specific set of allowed operations. The policy allows users to restrict keys to a minimal cryptographic strength, restrict supported elliptic curves, mechanisms, MGFs, KDFs, or PRFs. .SH SYNTAX This file starts with a version specification of the form \fBversion policy-0\fR followed by policy constraints. .P A policy constraint assigns a value to a configuration key. The syntax depends of the value of the key: .TP .BR strength This key defines the minimal required strength for keys, and digest and signature sizes. It corresponds to the definition in /etc/opencryptoki/strength.conf. Valid values are 0, 112, 128, 192, and 256. The special value 0 allows every key and arbitrary size of digests and signatures. The format is a simple assignment: strength = number If other values are used, they are rounded up to the next supported value. Values greater than 256 are rounded down to 256. .TP .BR allowedmechs This key specifies a list of mechanisms that are allowed by this policy. The list should contain a comma-separated list of .BR CKM_ constants supported by openCryptoki. The list is placed inside brackets: allowedmechs ( mech1, mech2 ) Note: This key is optional. If not present, all mechanisms are allowed. If an empty list is provided, no mechanism would be allowed. .TP .BR allowedcurves This key specifies a list of allowed elliptic curves. Keys that do not belong to any of the allowed curves cannot be created or used. The list has the same format as the .BR allowedmechs key: allowedcurves ( curve1, curve2 ) Valid curve names are: .RS .IP \(bu BRAINPOOL_P160R1 .IP \(bu BRAINPOOL_P160T1 .IP \(bu BRAINPOOL_P192R1 .IP \(bu BRAINPOOL_P192T1 .IP \(bu BRAINPOOL_P224R1 .IP \(bu BRAINPOOL_P224T1 .IP \(bu BRAINPOOL_P256R1 .IP \(bu BRAINPOOL_P256T1 .IP \(bu BRAINPOOL_P320R1 .IP \(bu BRAINPOOL_P320T1 .IP \(bu BRAINPOOL_P384R1 .IP \(bu BRAINPOOL_P384T1 .IP \(bu BRAINPOOL_P512R1 .IP \(bu BRAINPOOL_P512T1 .IP \(bu PRIME192V1 .IP \(bu SECP224R1 .IP \(bu PRIME256V1 .IP \(bu SECP384R1 .IP \(bu SECP521R1 .IP \(bu SECP256K1 .IP \(bu CURVE25519 .IP \(bu CURVE448 .IP \(bu ED25519 .IP \(bu ED448 .RE Note: This key is optional. If not present, all curves are allowed. An empty list allows no curve. .TP .BR allowedmgfs This key specifies the allowed Message Generation Functions (MGFs) for use in RSA OAEP and RSA PSS. The value is a list of .BR CKG_ constants supported by openCryptoki. The list has the same format as the .BR allowedmechs key: allowedmgfs ( mgf1, mgf2 ) Note: This key is optional. If not present, all MGFs are allowed. An empty list allows no MGF. .TP .BR allowedkdfs This key specifies the allowed Key Derivation Functions (KDFs) for use in ECDH key derivation and Kyber KEM. The value is a list of .BR CKD_ constants supported by openCryptoki. This list has the same format as the .BR allowedmechs key: allowedkdfs ( kdf1, kdf2 ) Note: This key is optional. If not present, all KDFs are allowed. An empty list allows no KDF. .TP .BR allowedprfs This key specifies the allowed Pseudo-Random Functions (PRFs) for use in PKCS #5 PBKDF. The value is a list of PRFs. Currently, the only supported value is .BR CKP_PKCS5_PBKD2_HMAC_SHA256 .BR CKP_PKCS5_PBKD2_HMAC_SHA512 which leads to the list allowedprfs ( CKP_PKCS5_PBKD2_HMAC_SHA512, CKP_PKCS5_PBKD2_HMAC_SHA256 ) Note: This key is optional. If not present, all PRFs are allowed. An empty list allows no PRF. .SH NOTES The policy configuration file has to be owned by \fBroot:@pkcs_group@\fP and have mode 0640. Otherwise, openCryptoki will return \fBCKR_FUNCTION_FAILED\fR on \fBC_Initialize\fR and log the reason into syslog. .PP 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 can be used at the beginning of a line (including before the file version specification), after the strength value, after a comma, and before and after the bracket. .PP Since the policy indirectly refers to a strength configuration, a strength configuration has to exist and be valid. If no strength configuration exists, no policy will be enforced. If an existing policy configuration is invalid, openCryptoki cannot be used. .PP openCryptoki uses some cryptographic operations to store token objects. These operations have to be allowed by the policy. Which operations are needed depends on the token store format and the token (since the ICSF Token as a remote token uses different crypto operations to store its management data): .RS .IP "FIPS compliant format" Token stores in the FIPS compliant format need the mechanisms .BR CKM_AES_KEY_GEN, .BR CKM_AES_KEY_WRAP, .BR CKM_AES_GCM, .BR CKM_PKCS5_PBKD2, the PRF .BR CKP_PKCS5_PBKD2_HMAC_SHA512, and must allow 256 bit AES keys. .IP "legacy format" Token stores in legacy format need the mechanisms .BR CKM_DES3_KEY_GEN, .BR CKM_DES3_CBC, .BR CKM_AES_KEY_GEN, .BR CKM_AES_CBC, .BR CKM_SHA1, .BR CKM_MD5 and must allow 2-key TDES keys (80 bit symmetric keys with 64 bit signatures). .IP "ICSF Token store" .BR CKM_AES_KEY_GEN, .BR CKM_AES_CBC, .BR CKM_SHA1, .BR CKM_MD5 .BR CKM_PKCS5_PBKD2, the PRF .BR CKP_PKCS5_PBKD2_HMAC_SHA256, and must allow 256 bit AES keys. .RE Tokens cannot be loaded if their token store format is not supported by the policy. If a token cannot be loaded, a message is printed into syslog detailing the policy violation. To fix this problem, make sure the token format is allowed by your policy (either by satisfying above constraints or by temporarily removing /etc/opencryptoki/policy.conf) and migrate your token store, e.g., to the FIPS-compliant format. .SH "SEE ALSO" .PD 0 .TP \fBstrength.conf\fP(5), .TP \fBopencryptoki\fP(7), .TP \fBpkcstok_migrate\fP(1), .TP /usr/share/doc/opencryptoki/policy-example.conf .PD opencryptoki-opencryptoki-451d99c/man/man5/strength.conf.5.in000066400000000000000000000063441520105705100242230ustar00rootroot00000000000000.TH STRENGTH.CONF 5 "September 2021" "@PACKAGE_VERSION@" "openCryptoki" .SH NAME strength.conf \- Configuration file for openCryptoki strength configuration. .SH DESCRIPTION openCryptoki uses a strength configuration file at /etc/opencryptoki/strength.conf This configuration file allows users to configure openCryptoki cryptographic key strength determination based on key attributes. This file is required by openCryptoki. .SH SYNTAX This file starts with a version specification of the form \fBversion strength-0\fR followed by the definition of various strengths. .P Each strength definition is composed of a strength, brackets and key-value pairs. strength number { ... } Supported numbers are 112, 128, 192, and 256 representing the corresponding strength in bits. Note: These definitions are optional. If a definition is missing, no key can have the strength. If no strength definition is present, all keys will have strength 0. More than one key-value pair may be used within a strength description. A key-value pair is composed of .B keyword = value where .B value is an unsigned number. The following keywords are valid: .TP .BR MOD_EXP Specifies the minimum number of bits required for RSA moduli, and DH and DSA primes such that the corresponding key is of the currently defined strength. Note: This key-value pair is optional. If not present, no RSA, DH, or DSA key can have the currently defined strength. .TP .BR ECC Specifies the minimum number of bits in the prime field of the elliptic curve such that the corresponding key is of the currently defined strength. Note: This key-value pair is optional. If not present, no EC key can have the currently defined strength. .TP .BR SYMMETRIC Specifies the minimum number of bits required for symmetric keys such that the corresponding key is of the currently defined strength. Note: This key-value pair is optional. If not present, no symmetric key can have the currently defined strength. .TP .BR digest Specifies the minimum size in bits of digest outputs required by the currently defined strength. Note: This key-value pair is optional. If not present, this strength definition does not constrain the size of digests. .TP .BR signature Specifies the minimum size in bits of signatures required by the currently defined strength. Note: This key-value pair is optional. If not present, this strength definition does not constrain the size of signatures. .SH NOTES The strength configuration file has to be owned by \fBroot:@pkcs_group@\fP, have mode 0640, and be parsable. Otherwise, openCryptoki will return \fBCKR_FUNCTION_FAILED\fR on \fBC_Initialize\fR and log a corresponding message to syslog detailing the reason why the strength configuration could not be used. In this case, fix the problem described in syslog to be able to use openCryptoki again. .PP 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 can be used at the beginning of a line (including before the file version specification), after a value, and before and after the braces. .SH "SEE ALSO" .PD 0 .TP \fBstrength.conf\fP(5), .TP \fBopencryptoki\fP(7), .TP /usr/share/doc/opencryptoki/strength-example.conf .PD opencryptoki-opencryptoki-451d99c/man/man7/000077500000000000000000000000001520105705100207415ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/man/man7/man7.mk000066400000000000000000000000451520105705100221330ustar00rootroot00000000000000man7_MANS += man/man7/opencryptoki.7 opencryptoki-opencryptoki-451d99c/man/man7/opencryptoki.7.in000066400000000000000000000022611520105705100241650ustar00rootroot00000000000000.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 \fI@pkcs_group@\fP group to be able to communicate with the \fIpkcsslotd\fP daemon. Only fully trusted users should be granted membership in the group. Group members can block other openCryptoki users from accessing PKCS#11 tokens. .SH "SEE ALSO" .PD 0 .TP \fBpkcsslotd\fP(8), .TP \fBpkcsconf\fP(1), .TP \fBopencryptoki.conf\fP(5). .PD opencryptoki-opencryptoki-451d99c/man/man8/000077500000000000000000000000001520105705100207425ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/man/man8/man8.mk000066400000000000000000000000421520105705100221320ustar00rootroot00000000000000man8_MANS += man/man8/pkcsslotd.8 opencryptoki-opencryptoki-451d99c/man/man8/pkcsslotd.8.in000066400000000000000000000022611520105705100234470ustar00rootroot00000000000000.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 \fI@pkcs_group@\fP group. All non-root users that should be able to use openCryptoki need to be members of the group. Only trusted users should be assigned to the group, see the "SECURITY NOTE" in the \fBopencryptoki\fP(7) manual page for details. .SH "SEE ALSO" .PD 0 .TP \fBopencryptoki\fP(7), .TP \fBopencryptoki.conf\fP(5), .TP \fBpkcsconf\fP(1), .PD opencryptoki-opencryptoki-451d99c/misc/000077500000000000000000000000001520105705100202575ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/misc/misc.mk000066400000000000000000000025201520105705100215420ustar00rootroot00000000000000EXTRA_DIST += misc/pkcsslotd.in misc/pkcsslotd.service.in \ misc/tmpfiles.conf.in misc/opencryptoki.pc.in pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = misc/opencryptoki.pc if ENABLE_DAEMON if ENABLE_SYSTEMD servicedir = $(unitdir) service_DATA = misc/pkcsslotd.service tmpfilesdir = /usr/lib/tmpfiles.d tmpfiles_DATA = misc/opencryptoki.conf CLEANFILES += misc/pkcsslotd.service misc/opencryptoki.conf ${srcdir}/misc/pkcsslotd.service: ${srcdir}/misc/pkcsslotd.service.in @SED@ -e s!\@sbindir\@!"@sbindir@"!g \ -e s!\@localstatedir\@!$(localstatedir)!g \ -e s!\@pkcsslotd_user\@!$(pkcsslotd_user)!g \ -e s!\@pkcs_group\@!$(pkcs_group)!g < $< > $@-t mv $@-t $@ ${srcdir}/misc/opencryptoki.conf: ${srcdir}/misc/tmpfiles.conf.in @SED@ -e s!\@lockdir\@!$(lockdir)!g \ -e s!\@logdir\@!$(logdir)!g \ -e s!\@localstatedir\@!$(localstatedir)!g \ -e s!\@pkcsslotd_user\@!$(pkcsslotd_user)!g \ -e s!\@pkcs_group\@!$(pkcs_group)!g< $< > $@-t 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 \ -e s!\@pkcsslotd_user\@!$(pkcsslotd_user)!g \ -e s!\@pkcs_group\@!$(pkcs_group)!g< $< > $@-t @CHMOD@ a+x $@-t mv $@-t $@ endif endif opencryptoki-opencryptoki-451d99c/misc/opencryptoki.pc.in000066400000000000000000000005301520105705100237340ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@/opencryptoki stdlldir=@libdir@/opencryptoki/stdll includedir=@includedir@/opencryptoki Name: Opencryptoki Description: Opencryptoki PKCS#11 module URL: https://github.com/opencryptoki/opencryptoki Version: @VERSION@ Cflags: -I${includedir} Libs: -L${libdir} -lopencryptoki opencryptoki-opencryptoki-451d99c/misc/pkcsslotd.in000066400000000000000000000025531520105705100226220ustar00rootroot00000000000000#!/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 RUNDIR=/run/opencryptoki PIDFILE=$RUNDIR/pkcsslotd.pid LOCKFILE=/var/lock/subsys/pkcsslotd SLOTDBIN=@sbindir@/pkcsslotd start() { [ -x $SLOTDBIN ] || exit 5 echo -n $"Starting pkcsslotd: " mkdir -p $RUNDIR chown @pkcsslotd_user@:@pkcs_group@ $RUNDIR chmod 710 $RUNDIR daemon --user=@pkcsslotd_user@ $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 $? opencryptoki-opencryptoki-451d99c/misc/pkcsslotd.service.in000066400000000000000000000046061520105705100242620ustar00rootroot00000000000000[Unit] Description=Daemon which manages cryptographic hardware tokens for the openCryptoki package After=local-fs.target [Service] User=@pkcsslotd_user@ Group=@pkcs_group@ Type=forking PIDFile=/run/opencryptoki/pkcsslotd.pid ExecStart=@sbindir@/pkcsslotd # Uncomment the following line to allow pkcsslotd to increase the receive buffer # size of the UDEV monitor's netlink socket via udev_monitor_set_receive_buffer_size(): # AmbientCapabilities=CAP_NET_ADMIN # Sandboxing Settings: # Many of them are not really needed, pkcsslotd run under an unpriviledged user. NoNewPrivileges=yes UMask=0022 PrivateTmp=yes PrivateUsers=no PrivateNetwork=no RestrictAddressFamilies=AF_UNIX AF_NETLINK IPAddressDeny=any ProtectClock=yes ProtectKernelTunables=yes ProtectKernelModules=yes ProtectKernelLogs=yes ProtectControlGroups=yes ProtectHome=yes ProtectHostname=yes ProtectProc=default ProtectSystem=strict ReadWritePaths=@localstatedir@ ProcSubset=all MemoryDenyWriteExecute=yes RestrictRealtime=yes RestrictNamespaces=yes PrivateDevices=yes RestrictSUIDSGID=yes LockPersonality=yes RemoveIPC=yes CapabilityBoundingSet=~CAP_SETUID CAP_SETGID CAP_SETPCAP CapabilityBoundingSet=~CAP_SYS_ADMIN CapabilityBoundingSet=~CAP_SYS_PTRACE CapabilityBoundingSet=~CAP_CHOWN CAP_FSETID CAP_SETFCAP CapabilityBoundingSet=~CAP_DAC_OVERRIDE CAP_DAC_READ_SEARCH CAP_FOWNER CAP_IPC_OWNER CapabilityBoundingSet=~CAP_SYS_MODULE CapabilityBoundingSet=~CAP_SYS_RAWIO CapabilityBoundingSet=~CAP_SYS_TIME CapabilityBoundingSet=~CAP_AUDIT_CONTROL CAP_AUDIT_READ CAP_AUDIT_WRITE CapabilityBoundingSet=~CAP_KILL CapabilityBoundingSet=~CAP_NET_BIND_SERVICE CAP_NET_BROADCAST CAP_NET_RAW CapabilityBoundingSet=~CAP_SYS_NICE CAP_SYS_RESOURCE CapabilityBoundingSet=~CAP_MAC_ADMIN CAP_MAC_OVERRIDE CapabilityBoundingSet=~CAP_SYS_BOOT CapabilityBoundingSet=~CAP_LINUX_IMMUTABLE CapabilityBoundingSet=~CAP_IPC_LOCK CapabilityBoundingSet=~CAP_SYS_CHROOT CapabilityBoundingSet=~CAP_BLOCK_SUSPEND CapabilityBoundingSet=~CAP_LEASE CapabilityBoundingSet=~CAP_SYS_PACCT CapabilityBoundingSet=~CAP_SYS_TTY_CONFIG CapabilityBoundingSet=~CAP_PERFMON CAP_BPF CAP_CHECKPOINT_RESTORE SystemCallFilter=~@clock SystemCallFilter=~@debug SystemCallFilter=~@module SystemCallFilter=~@mount SystemCallFilter=~@raw-io SystemCallFilter=~@reboot SystemCallFilter=~@swap SystemCallFilter=~@resources SystemCallFilter=~@cpu-emulation SystemCallFilter=~@obsolete [Install] WantedBy=multi-user.target opencryptoki-opencryptoki-451d99c/misc/tmpfiles.conf.in000066400000000000000000000004001520105705100233500ustar00rootroot00000000000000# path mode uid gid age D /run/opencryptoki 710 @pkcsslotd_user@ @pkcs_group@ - d @localstatedir@/lib/opencryptoki 0770 root @pkcs_group@ - d @logdir@ 0770 root @pkcs_group@ - D @lockdir@ 0770 root @pkcs_group@ - opencryptoki-opencryptoki-451d99c/opencryptoki.map000066400000000000000000000052511520105705100225540ustar00rootroot00000000000000OPENCRYPTOKI_3.27 { 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_WrapKey; C_UnwrapKey; C_Verify; C_VerifyFinal; C_VerifyInit; C_VerifyRecover; C_VerifyRecoverInit; C_VerifyUpdate; C_WaitForSlotEvent; C_GetInterfaceList; C_GetInterface; C_LoginUser; C_SessionCancel; C_MessageEncryptInit; C_EncryptMessage; C_EncryptMessageBegin; C_EncryptMessageNext; C_MessageEncryptFinal; C_MessageDecryptInit; C_DecryptMessage; C_DecryptMessageBegin; C_DecryptMessageNext; C_MessageDecryptFinal; C_MessageSignInit; C_SignMessage; C_SignMessageBegin; C_SignMessageNext; C_MessageSignFinal; C_MessageVerifyInit; C_VerifyMessage; C_VerifyMessageBegin; C_VerifyMessageNext; C_MessageVerifyFinal; C_EncapsulateKey; C_DecapsulateKey; C_VerifySignatureInit; C_VerifySignature; C_VerifySignatureUpdate; C_VerifySignatureFinal; C_GetSessionValidationFlags; C_AsyncComplete; C_AsyncGetID; C_AsyncJoin; C_WrapKeyAuthenticated; C_UnwrapKeyAuthenticated; C_IBM_ReencryptSingle; local: *; }; opencryptoki-opencryptoki-451d99c/opencryptoki_tok.map000066400000000000000000000035721520105705100234350ustar00rootroot00000000000000OPENCRYPTOKI_TOK_3.27 { 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; SC_IBM_ReencryptSingle; SC_SessionCancel; SC_EncapsulateKey; SC_DecapsulateKey; SC_VerifySignatureInit; SC_VerifySignature; SC_VerifySignatureUpdate; SC_VerifySignatureFinal; ST_Initialize; local: *; }; opencryptoki-opencryptoki-451d99c/rpm/000077500000000000000000000000001520105705100201225ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/rpm/opencryptoki.spec000066400000000000000000000330611520105705100235270ustar00rootroot00000000000000%global _hardened_build 1 Name: opencryptoki Summary: Implementation of the PKCS#11 (Cryptoki) specification v3.0 and partially v3.1, v3.2 Version: 3.27.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: gcc BuildRequires: openssl-devel >= 1.1.1 %if 0%{?tpmtok} BuildRequires: trousers-devel %endif BuildRequires: openldap-devel BuildRequires: autoconf automake libtool autoconf-archive BuildRequires: bison flex %ifarch s390 s390x BuildRequires: systemd-devel %endif BuildRequires: libcap-devel BuildRequires: make %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 partially v3.1, v3.2 for a set of cryptographic hardware, such as IBM 4767, 4768, 4769 and 4770 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 v3.0 and partially v3.1 and v3.2 for a set of cryptographic hardware, such as IBM 4767, 4768, 4769 and 4770 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 v3.0 and partially v3.1 and v3.2 for a set of cryptographic hardware, such as IBM 4767, 4768, 4769 and 4770 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 v3.0 and partially v3.1 and v3.2 for a set of cryptographic hardware, such as IBM 4767, 4768, 4769 and 4770 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 v3.0 and partially v3.1 and v3.2 for a set of cryptographic hardware, such as IBM 4767, 4768, 4769 and 4770 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 v3.0 and partially v3.1 and v3.2 for a set of cryptographic hardware, such as IBM 4767, 4768, 4769 and 4770 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 4767, 4768, 4769 and 4770 that uses the "accelerator" or "clear-key" path. %endif %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 v3.0 and partially v3.1 and v3.2 for a set of cryptographic hardware, such as IBM 4767, 4768, 4769 and 4770 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 4767, 4768, 4769 and 4770 that uses the "co-processor" or "secure-key" path. %ifarch s390 s390x %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 v3.0 and partially v3.1 and v3.2 for a set of cryptographic hardware, such as IBM 4767, 4768, 4769 and 4770 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} \ --with-pkcsslotd-user=pkcsslotd --with-pkcs-group=pkcs11 \ %if 0%{?tpmtok} --enable-tpmtok \ %else --disable-tpmtok \ %endif %ifarch s390 s390x x86_64 ppc64le --enable-ccatok \ %else --disable-ccatok \ %endif %ifarch s390 s390x --enable-icatok --enable-ep11tok --enable-pkcsep11_migrate %else --disable-icatok --disable-ep11tok --disable-pkcsep11_migrate --enable-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 %endif %post ccatok -p /sbin/ldconfig %ifarch s390 s390x %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 %endif %postun ccatok -p /sbin/ldconfig %ifarch s390 s390x %postun ep11tok -p /sbin/ldconfig %endif %pre libs # Create pkcs11 group and pkcsslotd user getent group pkcs11 >/dev/null || groupadd -r pkcs11 getent passwd pkcsslotd >/dev/null || useradd -r -g pkcs11 -d /run/opencryptoki -s /sbin/nologin -c "Opencryptoki pkcsslotd user" pkcsslotd exit 0 %post %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 %doc doc/policy-example.conf %doc doc/strength-example.conf %dir %{_sysconfdir}/%{name} %config(noreplace) %{_sysconfdir}/%{name}/%{name}.conf %attr(0640, root, pkcs11) %config(noreplace) %{_sysconfdir}/%{name}/strength.conf %attr(0640, root, pkcs11) %config(noreplace) %{_sysconfdir}/%{name}/p11sak_defined_attrs.conf %attr(0640, root, pkcs11) %config(noreplace) %{_sysconfdir}/%{name}/p11kmip.conf %{_prefix}/lib/tmpfiles.d/%{name}.conf %{_unitdir}/pkcsslotd.service %{_sbindir}/pkcsconf %{_sbindir}/pkcsslotd %{_sbindir}/p11kmip %{_sbindir}/p11sak %{_sbindir}/pkcstok_migrate %{_sbindir}/pkcsstats %{_sbindir}/pkcshsm_mk_change %{_sbindir}/pkcstok_admin %{_mandir}/man1/pkcsconf.1* %{_mandir}/man1/p11kmip.1* %{_mandir}/man1/p11sak.1* %{_mandir}/man1/pkcstok_migrate.1* %{_mandir}/man1/pkcsstats.1* %{_mandir}/man1/pkcshsm_mk_change.1* %{_mandir}/man1/pkcstok_admin.1* %{_mandir}/man5/%{name}.conf.5* %{_mandir}/man5/p11sak_defined_attrs.conf.5* %{_mandir}/man5/policy.conf.5* %{_mandir}/man5/strength.conf.5* %{_mandir}/man5/p11kmip.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) %{_sharedstatedir}/%{name}/HSM_MK_CHANGE/ %dir %attr(770,root,pkcs11) %{_localstatedir}/lock/%{name} %dir %attr(770,root,pkcs11) %{_localstatedir}/lock/%{name}/* %dir %attr(710,pkcsslotd,pkcs11) /run/%{name}/ %files libs %license LICENSE %{_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}/ %{_libdir}/pkgconfig/%{name}.pc %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/ %if 0%{?tpmtok} %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/ %endif %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/ %endif %ifarch s390 s390x x86_64 ppc64le %files ccatok %doc doc/README.cca_stdll %config(noreplace) %{_sysconfdir}/%{name}/ccatok.conf %{_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/ %endif %ifarch s390 s390x %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 opencryptoki-opencryptoki-451d99c/testcases/000077500000000000000000000000001520105705100213225ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/testcases/README000066400000000000000000000041211520105705100222000ustar00rootroot00000000000000openCryptoki 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. build ----- This directory contains build tests: a failed test is indicated by a build break. policy ------ This directory contains policy related tests. Test results are dependent on the current policy and strength settings. unit ---- This directory contains unit tests that are run via 'make check'. ock_test.sh ----------- This driver runs the various testcases on all tokens currently configured, unless the '-s SLOT' option is specified. It initializes the tokens and sets SO and USER pins, if the tokens are not already initialized. Set environment variables PKCS11_SO_PIN and PKCS11_USER_PIN to the pins to use. ciconfig.sh ----------- This script sets up the openCryptoki tokens for a run in the CI. It creates an opencryptoki.conf config file together with several token specific config files. The CI run is started via 'make ci-installcheck'. Do NOT run this outside of the CI, it may destroy your openCryptoki setup, tokens, and objects! For help, open an issue at https://github.com/opencryptoki/opencryptoki/issues opencryptoki-opencryptoki-451d99c/testcases/build/000077500000000000000000000000001520105705100224215ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/testcases/build/build.mk000066400000000000000000000003521520105705100240510ustar00rootroot00000000000000noinst_PROGRAMS += \ testcases/build/cpp_test testcases_build_cpp_test_CXXFLAGS = ${testcases_inc} testcases_build_cpp_test_LDADD = testcases/common/libcommon.la testcases_build_cpp_test_SOURCES = testcases/build/cpp_test.cpp opencryptoki-opencryptoki-451d99c/testcases/build/cpp_test.cpp000066400000000000000000000013221520105705100247440ustar00rootroot00000000000000/* * 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 */ /* * Test if our public header files can be savely included from C++. */ // pkcs11.h: #include "apiclient.h" #include "pkcs11types.h" // Additional ECC stuff: #include "ec_curves.h" int main(void) { int rv; rv = 0; /* make sure we return non-zero if rv is non-zero */ return ((rv == 0) || (rv % 256) ? (int)rv : -1); } opencryptoki-opencryptoki-451d99c/testcases/ciconfig.sh000077500000000000000000000074561520105705100234560ustar00rootroot00000000000000#!/bin/bash OCKCONFDIR="$1" EPCONFDIR="$2" CCACONFDIR="$3" COMBINED_EXTRACT_FILE="$4" LATESTCEXP="CEX8P" CCA_SYM_MKVP="5776993D2741EB4A" CCA_AES_MKVP="E9A49A58CD039BED" CCA_APKA_MKVP="5F2F27AAA2D59B4A" EP11_WKVP="8b991263e3a8f4e4be0d5ec8f0a4df9e" USENEWFORMAT=/bin/false # Usage: addslot slot-num stdll slot-name [confname] function addslot() { cat <> "${OCKCONFDIR}/opencryptoki.conf" slot $1 { stdll = $2 tokname = $3 EOF if $USENEWFORMAT; then echo "tokversion = 3.12" >> "${OCKCONFDIR}/opencryptoki.conf" fi if [ "x$4" != "x" ]; then echo "confname = $4" >> "${OCKCONFDIR}/opencryptoki.conf" fi if test ! -z ${TOKEN_GROUP}; then echo "usergroup = ${TOKEN_GROUP}" >> "${OCKCONFDIR}/opencryptoki.conf" fi echo "}" >> "${OCKCONFDIR}/opencryptoki.conf" pkcstok_admin remove --token $3 --force &> /dev/null if test ! -z ${TOKEN_GROUP}; then pkcstok_admin create --token $3 --group ${TOKEN_GROUP} --force &> /dev/null fi } # Usage: genep11cfg num configline function genep11cfg() { cat < "${EPCONFDIR}/ep11tok${1}.conf" ${2} APQN_ANY EOF } # Usage: genlatestep11cfg num configline # Return: 0 if successful function genlatestep11cfg() { local res=1 lszcrypt | grep "$LATESTCEXP" | perl -ne '/([0-9a-fA-F]+)\.([0-9a-fA-F]+)\s.*/ && print "0x$1 0x$2\n"' > tmp.apqns if test -s tmp.apqns; then echo "${2}" > "${EPCONFDIR}/ep11tok${1}.conf" echo "APQN_WHITELIST" >> "${EPCONFDIR}/ep11tok${1}.conf" cat tmp.apqns >> "${EPCONFDIR}/ep11tok${1}.conf" echo "END" >> "${EPCONFDIR}/ep11tok${1}.conf" res=0 fi rm -f tmp.apqns return $res } # Usage: genccacfg num function genccacfg() { cat < "${CCACONFDIR}/ccatok${1}.conf" version cca-0 EXPECTED_MKVPS { SYM = "$CCA_SYM_MKVP" AES = "$CCA_AES_MKVP" APKA = "$CCA_APKA_MKVP" } PKEY_MODE = ENABLED AES_KEY_MODE = CIPHER EOF } if test $(($(date +%-j)%2)) == 1; then USENEWFORMAT=/bin/true echo "Using FIPS compliant token store" else echo "Using legacy token store" fi if test ! -z ${PKCS11_TEST_USER}; then if test ! -z ${PKCS11_TEST_GROUP}; then TOKEN_GROUP=${PKCS11_TEST_GROUP} else TOKEN_GROUP="tokgroup" fi getent group ${TOKEN_GROUP} >/dev/null || groupadd -r ${TOKEN_GROUP} usermod -a -G ${TOKEN_GROUP} ${PKCS11_TEST_USER} fi # initialize opencryptoki.conf echo "version opencryptoki-3.27" > "${OCKCONFDIR}/opencryptoki.conf" # enable full statistics echo "statistics (on,implicit,internal)" >> "${OCKCONFDIR}/opencryptoki.conf" # ICA token addslot 10 libpkcs11_ica.so ica0 addslot 11 libpkcs11_ica.so ica1 # CCA token genccacfg 20 addslot 20 libpkcs11_cca.so cca0 ccatok20.conf addslot 21 libpkcs11_cca.so cca1 # SW token addslot 30 libpkcs11_sw.so sw0 addslot 31 libpkcs11_sw.so sw1 # EP11 token # 0: # APQN_ANY # EXPECTED_WKVP "wkvp" genep11cfg 40 "EXPECTED_WKVP \"$EP11_WKVP\"" addslot 40 libpkcs11_ep11.so ep0 ep11tok40.conf # 1: # FORCE_SENSITIVE # APQN_ANY genep11cfg 41 "FORCE_SENSITIVE" addslot 41 libpkcs11_ep11.so ep1 ep11tok41.conf # 2: # STRICT_MODE # APQN_ANY # later appended: VHSM_MODE #genep11cfg 42 "STRICT_MODE" #addslot 42 libpkcs11_ep11.so ep2 ep11tok42.conf # 3: # OPTIMIZE_SINGLE_PART_OPERATIONS # APQN_ANY genep11cfg 43 "OPTIMIZE_SINGLE_PART_OPERATIONS" addslot 43 libpkcs11_ep11.so ep3 ep11tok43.conf # 4: # DIGEST_LIBICA OFF # APQN_ANY genep11cfg 44 "DIGEST_LIBICA OFF" addslot 44 libpkcs11_ep11.so ep4 ep11tok44.conf # 5: latest (CEX8 only) # PKEY_MODE ENABLE4NONEXTR if genlatestep11cfg 45 "PKEY_MODE ENABLE4NONEXTR"; then addslot 45 libpkcs11_ep11.so ep5 ep11tok45.conf fi # 6: latest (CEX8 only) # PKEY_MODE ENABLE4ALL if genlatestep11cfg 46 "PKEY_MODE ENABLE4ALL"; then addslot 46 libpkcs11_ep11.so ep6 ep11tok46.conf echo "46" > $COMBINED_EXTRACT_FILE fi opencryptoki-opencryptoki-451d99c/testcases/cleanup_vhsm.exp.in000066400000000000000000000016511520105705100251340ustar00rootroot00000000000000#!/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 # spawn @sbindir@/pkcsep11_session logout -force -slot [lindex $argv 0] expect { "Enter the USER PIN:" { sleep .1; send $env(PKCS11_USER_PIN); send "\r"; } eof { send_user "Unexpected EOF on user pin\n"; exit 1 } timeout { send_user "Timeout on user pin\n"; exit 1 } } expect { "EP11-Sessions logged out" {} eof { send_user "Unexpected EOF at the end\n"; exit 1 } timeout { send_user "Unexpected timeout at the end\n"; exit 1 } } expect { eof {} timeout { send_user "Unexpected timeout at the end\n"; exit 1 } } opencryptoki-opencryptoki-451d99c/testcases/common/000077500000000000000000000000001520105705100226125ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/testcases/common/common.c000066400000000000000000002413731520105705100242600ustar00rootroot00000000000000/* * 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 "platform.h" #include "ec_curves.h" #define UNUSED(var) ((void)(var)) CK_FUNCTION_LIST *funcs; CK_FUNCTION_LIST_3_0 *funcs3; CK_FUNCTION_LIST_3_2 *funcs3_2; CK_INTERFACE *ifs; CK_SLOT_ID SLOT_ID; CK_BBOOL skip_token_obj; CK_BBOOL no_stop; CK_BBOOL no_init; CK_BBOOL securekey; /* * The pkey flag controls whether tests shall exploit the protected key * option. To allow easy integration into the CI, this is not provided as * a cmdline option, but affected tests are run twice, with and without * pkey option. */ CK_BBOOL pkey = CK_FALSE; CK_BBOOL combined_extract = CK_FALSE; CK_BBOOL rsa8k = CK_FALSE; 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) { #ifndef WITH_SANITIZER dlclose(pkcs11lib); #endif } } static void free_ifs(void) { free(ifs); ifs = NULL; } 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; /* min and max being zero indicate no key size limitation */ if (mech_info.ulMinKeySize == 0 && mech_info.ulMaxKeySize == 0) return TRUE; 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; } int encapsulate_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_ENCAPSULATE; return rc; } int decapsulate_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_DECAPSULATE; return rc; } /** * Check if the last CKR_FUNCTION__FAILED error was due to policy restrictions */ int is_rejected_by_policy(CK_RV ret_code, CK_SESSION_HANDLE session) { CK_SESSION_INFO info; CK_RV rc; if (ret_code != CKR_FUNCTION_FAILED) return 0; rc = funcs->C_GetSessionInfo(session, &info); if (rc != CKR_OK) { testcase_error("C_GetSessionInfo(), rc=%s.", p11_get_ckr(rc)); return 0; } if (info.ulDeviceError != 0 && info.ulDeviceError != CKR_POLICY_VIOLATION) { testcase_notice("CK_SESSION_INFO.ulDeviceError: 0x%lx", info.ulDeviceError); } return (info.ulDeviceError == CKR_POLICY_VIOLATION); } /** Create an AES key handle with given value **/ CK_RV create_AESKey(CK_SESSION_HANDLE session, CK_BBOOL extractable, unsigned char key[], unsigned char key_len, CK_KEY_TYPE keyType, CK_OBJECT_HANDLE * h_key) { CK_RV rc; CK_BBOOL true = TRUE; CK_BBOOL false = FALSE; CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY; CK_BBOOL pkeyextractable = !extractable; CK_ATTRIBUTE keyTemplate[] = { {CKA_EXTRACTABLE, &extractable, sizeof(CK_BBOOL)}, {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}, {CKA_IBM_PROTKEY_EXTRACTABLE, &pkeyextractable, sizeof(CK_BBOOL)}, }; CK_ULONG keyTemplate_len = sizeof(keyTemplate) / sizeof(CK_ATTRIBUTE); if (combined_extract) pkeyextractable = CK_TRUE; rc = funcs->C_CreateObject(session, keyTemplate, keyTemplate_len, h_key); if (rc != CKR_OK) { if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); } return rc; } /** Generate an AES key handle **/ CK_RV generate_AESKey(CK_SESSION_HANDLE session, CK_ULONG key_len, CK_BBOOL extractable, CK_MECHANISM * mechkey, CK_OBJECT_HANDLE * h_key) { CK_BBOOL pkeyextractable = !extractable; CK_ATTRIBUTE key_gen_tmpl[] = { {CKA_EXTRACTABLE, &extractable, sizeof(CK_BBOOL)}, {CKA_VALUE_LEN, &key_len, sizeof(CK_ULONG)}, {CKA_IBM_PROTKEY_EXTRACTABLE, &pkeyextractable, sizeof(CK_BBOOL)}, }; CK_ULONG key_gen_tmpl_len = sizeof(key_gen_tmpl) / sizeof(CK_ATTRIBUTE); if (combined_extract) pkeyextractable = CK_TRUE; CK_RV rc = funcs->C_GenerateKey(session, mechkey, key_gen_tmpl, key_gen_tmpl_len, h_key); if (rc != CKR_OK) { if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else testcase_error("C_GenerateKey rc=%s", p11_get_ckr(rc)); } return rc; } /** Create a DES key handle with given value **/ CK_RV 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) { if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); } return rc; } /** Create DES2 key handle with given value **/ CK_RV 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) { if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); } return rc; } /** Create DES3 key handle with given value **/ CK_RV 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) { if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); } return rc; } /** Create Generic Secret key handle with given value **/ CK_RV create_GenericSecretKey(CK_SESSION_HANDLE session, CK_KEY_TYPE key_type, CK_BYTE key[], CK_ULONG key_len, CK_OBJECT_HANDLE * h_key) { CK_OBJECT_CLASS key_class = CKO_SECRET_KEY; 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) { if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else 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} }; CK_ULONG template_len = sizeof(template) / sizeof(CK_ATTRIBUTE); if (prime1 == NULL || prime1_len == 0 || prime2 == NULL || prime2_len == 0 || exponent1 == NULL || exponent1_len == 0 || exponent2 == NULL || exponent2_len == 0 || coefficient == NULL || coefficient_len == 0) template_len -= 5; // create key rc = funcs->C_CreateObject(session, template, template_len, priv_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) testcase_notice("C_CreateObject rc=%s", p11_get_ckr(rc)); else if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else 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) { if (rc == CKR_KEY_SIZE_RANGE) testcase_notice("C_CreateObject rc=%s", p11_get_ckr(rc)); else if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else 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_MECHANISM_TYPE mech_type, 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 = { mech_type, 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_ENCAPSULATE, &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)}, {CKA_DECAPSULATE, &true, sizeof(true)}, }; // generate keys rc = funcs->C_GenerateKeyPair(session, &mech, publicKeyTemplate, 6, privateKeyTemplate, 9, publ_key, priv_key); if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; return rc; // no error checking due to // ICA Token + public exponent values + CKR_TEMPLATE_INCONSISTENT // work around // see rsa_func.c } struct rsa_key_cache_entry { CK_SESSION_HANDLE session; CK_MECHANISM_TYPE keygen_mech_type; CK_ULONG modulusBits; CK_BYTE *publicExponent; CK_ULONG publicExponent_len; CK_OBJECT_HANDLE publ_key; CK_OBJECT_HANDLE priv_key; }; struct rsa_key_cache_entry *rsa_key_cache = NULL; CK_ULONG rsa_key_cache_size = 0; CK_RV generate_RSA_PKCS_KeyPair_cached(CK_SESSION_HANDLE session, CK_MECHANISM_TYPE mech_type, CK_ULONG modulusBits, CK_BYTE publicExponent[], CK_ULONG publicExponent_len, CK_OBJECT_HANDLE *publ_key, CK_OBJECT_HANDLE *priv_key) { struct rsa_key_cache_entry *tmp, *free = NULL; CK_ULONG i; CK_RV rc; for (i = 0; i < rsa_key_cache_size; i++) { if (rsa_key_cache[i].session == session && rsa_key_cache[i].keygen_mech_type == mech_type && rsa_key_cache[i].modulusBits == modulusBits && rsa_key_cache[i].publicExponent_len == publicExponent_len && memcmp(rsa_key_cache[i].publicExponent, publicExponent, publicExponent_len) == 0) { *publ_key = rsa_key_cache[i].publ_key; *priv_key = rsa_key_cache[i].priv_key; return CKR_OK; } if (rsa_key_cache[i].session == CK_INVALID_HANDLE && free == NULL) free = &rsa_key_cache[i]; } rc = generate_RSA_PKCS_KeyPair(session, mech_type, modulusBits, publicExponent, publicExponent_len, publ_key, priv_key); if (rc != CKR_OK) return rc; if (free == NULL) { tmp = realloc(rsa_key_cache, (rsa_key_cache_size + 1) * sizeof(struct rsa_key_cache_entry)); if (tmp == NULL) { testcase_error("realloc failed to enlarge the RSA key cache"); return CKR_HOST_MEMORY; } free = &tmp[rsa_key_cache_size]; memset(free, 0, sizeof(*free)); rsa_key_cache = tmp; rsa_key_cache_size++; } free->session = session; free->keygen_mech_type = mech_type; free->modulusBits = modulusBits; free->publicExponent_len = publicExponent_len; free->publicExponent = malloc(publicExponent_len); if (free->publicExponent == NULL) { testcase_error("failed to allocate the public exponent cache entry"); return CKR_HOST_MEMORY; } memcpy(free->publicExponent, publicExponent, publicExponent_len); free->publ_key = *publ_key; free->priv_key = *priv_key; return CKR_OK; } void free_rsa_key_cache(CK_SESSION_HANDLE session) { CK_ULONG i; for (i = 0; i < rsa_key_cache_size; i++) { if (rsa_key_cache[i].session == CK_INVALID_HANDLE) continue; if (session != CK_INVALID_HANDLE && rsa_key_cache[i].session != session) continue; funcs->C_DestroyObject(rsa_key_cache[i].session, rsa_key_cache[i].publ_key); funcs->C_DestroyObject(rsa_key_cache[i].session, rsa_key_cache[i].priv_key); free(rsa_key_cache[i].publicExponent); /* mark as free */ memset(&rsa_key_cache[i], 0, sizeof(rsa_key_cache[i])); } if (session == CK_INVALID_HANDLE) { free(rsa_key_cache); rsa_key_cache = NULL; rsa_key_cache_size = 0; } } /** Generate an EC key pair **/ CK_RV generate_EC_KeyPair(CK_SESSION_HANDLE session, CK_MECHANISM_TYPE keygen_mech, CK_BYTE* ec_params, CK_ULONG ec_params_len, CK_OBJECT_HANDLE * publ_key, CK_OBJECT_HANDLE * priv_key, CK_BBOOL extractable) { CK_RV rc; CK_MECHANISM mech = { keygen_mech, NULL, 0 }; CK_BBOOL pkeyextractable = !extractable; CK_BYTE subject[] = {0}; CK_BYTE id[] = { 123 }; CK_BBOOL true = TRUE; CK_BBOOL false = FALSE; const CK_BYTE bls12_381[] = OCK_BLS12_381; CK_ATTRIBUTE publicKeyTemplate[] = { {CKA_VERIFY, &true, sizeof(true)}, {CKA_EC_PARAMS, ec_params, ec_params_len}, {CKA_IBM_PROTKEY_EXTRACTABLE, &pkeyextractable, sizeof(CK_BBOOL)}, {CKA_DERIVE, (ec_params_len == sizeof(bls12_381) && memcmp(ec_params, bls12_381, sizeof(bls12_381)) == 0) ? &true : &false, sizeof(CK_BBOOL)}, }; 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_SIGN, &true, sizeof(true)}, {CKA_DERIVE, &true, sizeof(true)}, {CKA_EXTRACTABLE, &extractable, sizeof(CK_BBOOL)}, {CKA_IBM_PROTKEY_EXTRACTABLE, &pkeyextractable, sizeof(CK_BBOOL)}, }; CK_ULONG num_publ_attrs = sizeof(publicKeyTemplate) / sizeof(CK_ATTRIBUTE); CK_ULONG num_priv_attrs = sizeof(privateKeyTemplate) / sizeof(CK_ATTRIBUTE); if (combined_extract) pkeyextractable = CK_TRUE; // generate keys rc = funcs->C_GenerateKeyPair(session, &mech, publicKeyTemplate, num_publ_attrs, privateKeyTemplate, num_priv_attrs, publ_key, priv_key); if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; return rc; } /** 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_KEY_TYPE key_type, CK_BYTE params[], CK_ULONG params_len, CK_BYTE privatekey[], CK_ULONG privatekey_len, CK_OBJECT_HANDLE * priv_key, CK_BBOOL extractable, CK_BBOOL derive) { CK_OBJECT_CLASS class = CKO_PRIVATE_KEY; CK_BBOOL pkeyextractable = !extractable; 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, &key_type, sizeof(key_type)}, {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_DERIVE, &derive, sizeof(derive)}, {CKA_EC_PARAMS, params, params_len}, {CKA_VALUE, privatekey, privatekey_len}, {CKA_EXTRACTABLE, &extractable, sizeof(CK_BBOOL)}, {CKA_IBM_PROTKEY_EXTRACTABLE, &pkeyextractable, sizeof(CK_BBOOL)}, }; if (combined_extract) pkeyextractable = CK_TRUE; // create key rc = funcs->C_CreateObject(session, template, sizeof(template) / sizeof(CK_ATTRIBUTE), priv_key); if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; return rc; } /** Create an EC public key using ec params and point 'Q' **/ CK_RV create_ECPublicKey(CK_SESSION_HANDLE session, CK_KEY_TYPE key_type, CK_BYTE params[], CK_ULONG params_len, CK_BYTE pointq[], CK_ULONG pointq_len, CK_OBJECT_HANDLE * publ_key, CK_BBOOL extractable) { CK_RV rc; CK_OBJECT_CLASS class = CKO_PUBLIC_KEY; CK_BBOOL pkeyextractable = !extractable; CK_UTF8CHAR label[] = "An EC public key object"; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &key_type, sizeof(key_type)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)}, {CKA_VERIFY, &true, sizeof(true)}, {CKA_DERIVE, &true, sizeof(true)}, {CKA_EC_PARAMS, params, params_len}, {CKA_EC_POINT, pointq, pointq_len}, {CKA_IBM_PROTKEY_EXTRACTABLE, &pkeyextractable, sizeof(CK_BBOOL)}, }; // create key rc = funcs->C_CreateObject(session, template, sizeof(template) / sizeof(CK_ATTRIBUTE), publ_key); if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; return rc; } /** Generate an EC key pair **/ CK_RV generate_Dilithium_KeyPair(CK_SESSION_HANDLE session, CK_ULONG keyform, CK_OBJECT_HANDLE *publ_key, CK_OBJECT_HANDLE *priv_key, CK_BBOOL extractable) { CK_RV rc; CK_MECHANISM mech = { CKM_IBM_DILITHIUM, NULL, 0 }; CK_BBOOL pkeyextractable = !extractable; CK_BYTE subject[] = {0}; CK_BYTE id[] = { 123 }; CK_BBOOL true = TRUE; CK_ATTRIBUTE publicKeyTemplate[] = { {CKA_VERIFY, &true, sizeof(true)}, {CKA_IBM_DILITHIUM_KEYFORM, &keyform, sizeof(keyform)}, }; 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_SIGN, &true, sizeof(true)}, {CKA_EXTRACTABLE, &extractable, sizeof(CK_BBOOL)}, {CKA_IBM_PROTKEY_EXTRACTABLE, &pkeyextractable, sizeof(CK_BBOOL)}, {CKA_IBM_DILITHIUM_KEYFORM, &keyform, sizeof(keyform)}, }; CK_ULONG num_publ_attrs = sizeof(publicKeyTemplate) / sizeof(CK_ATTRIBUTE); CK_ULONG num_priv_attrs = sizeof(privateKeyTemplate) / sizeof(CK_ATTRIBUTE); if (combined_extract) pkeyextractable = CK_TRUE; // generate keys rc = funcs->C_GenerateKeyPair(session, &mech, publicKeyTemplate, num_publ_attrs, privateKeyTemplate, num_priv_attrs, publ_key, priv_key); if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; return rc; } /** Create an IBM Dilithium private key using private values **/ CK_RV create_DilithiumPrivateKey(CK_SESSION_HANDLE session, CK_BYTE pkcs8[], CK_ULONG pkcs8_len, CK_ULONG keyform, 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_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)}, }; CK_ATTRIBUTE template_pkcs8[] = { {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_VALUE, pkcs8, pkcs8_len}, }; // create key if (pkcs8_len > 0) rc = funcs->C_CreateObject(session, template_pkcs8, sizeof(template_pkcs8) / sizeof(CK_ATTRIBUTE), priv_key); else rc = funcs->C_CreateObject(session, template, sizeof(template) / sizeof(CK_ATTRIBUTE), priv_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) testcase_notice("C_CreateObject rc=%s", p11_get_ckr(rc)); else if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else 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 spki[], CK_ULONG spki_len, CK_ULONG keyform, 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_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)}, }; CK_ATTRIBUTE template_spki[] = { {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_VALUE, spki, spki_len}, }; // create key if (spki_len > 0) rc = funcs->C_CreateObject(session, template_spki, sizeof(template_spki) / sizeof(CK_ATTRIBUTE), publ_key); else rc = funcs->C_CreateObject(session, template, sizeof(template) / sizeof(CK_ATTRIBUTE), publ_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) testcase_notice("C_CreateObject rc=%s", p11_get_ckr(rc)); else if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); } return rc; } /** Create an IBM Kyber private key using private values **/ CK_RV create_KyberPrivateKey(CK_SESSION_HANDLE session, CK_BYTE pkcs8[], CK_ULONG pkcs8_len, CK_ULONG keyform, CK_BYTE sk[], CK_ULONG sk_len, CK_BYTE pk[], CK_ULONG pk_len, CK_OBJECT_HANDLE * priv_key) { CK_OBJECT_CLASS class = CKO_PRIVATE_KEY; CK_KEY_TYPE keyType = CKK_IBM_PQC_KYBER; CK_UTF8CHAR label[] = "A Kyber 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_SIGN, &true, sizeof(true)}, {CKA_DERIVE, &true, sizeof(true)}, {CKA_IBM_KYBER_SK, sk, sk_len}, {CKA_IBM_KYBER_PK, pk, pk_len}, {CKA_IBM_KYBER_KEYFORM, &keyform, sizeof(keyform)}, }; CK_ATTRIBUTE template_pkcs8[] = { {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_DERIVE, &true, sizeof(true)}, {CKA_VALUE, pkcs8, pkcs8_len}, }; // create key if (pkcs8_len > 0) rc = funcs->C_CreateObject(session, template_pkcs8, sizeof(template_pkcs8) / sizeof(CK_ATTRIBUTE), priv_key); else rc = funcs->C_CreateObject(session, template, sizeof(template) / sizeof(CK_ATTRIBUTE), priv_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) testcase_notice("C_CreateObject rc=%s", p11_get_ckr(rc)); else if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); } return rc; } /** Create an IBM Kyber public key using public values **/ CK_RV create_KyberPublicKey(CK_SESSION_HANDLE session, CK_BYTE spki[], CK_ULONG spki_len, CK_ULONG keyform, CK_BYTE pk[], CK_ULONG pk_len, CK_OBJECT_HANDLE * publ_key) { CK_RV rc; CK_OBJECT_CLASS class = CKO_PUBLIC_KEY; CK_KEY_TYPE keyType = CKK_IBM_PQC_KYBER; CK_UTF8CHAR label[] = "A Kyber 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_VERIFY, &true, sizeof(true)}, {CKA_DERIVE, &true, sizeof(true)}, {CKA_IBM_KYBER_PK, pk, pk_len}, {CKA_IBM_KYBER_KEYFORM, &keyform, sizeof(keyform)}, }; CK_ATTRIBUTE template_spki[] = { {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_DERIVE, &true, sizeof(true)}, {CKA_VALUE, spki, spki_len}, }; // create key if (spki_len > 0) rc = funcs->C_CreateObject(session, template_spki, sizeof(template_spki) / sizeof(CK_ATTRIBUTE), publ_key); else rc = funcs->C_CreateObject(session, template, sizeof(template) / sizeof(CK_ATTRIBUTE), publ_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) testcase_notice("C_CreateObject rc=%s", p11_get_ckr(rc)); else if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); } return rc; } CK_RV generate_IBM_ML_DSA_KeyPair(CK_SESSION_HANDLE session, CK_ULONG parameter_set, CK_OBJECT_HANDLE *publ_key, CK_OBJECT_HANDLE *priv_key, CK_BBOOL extractable) { CK_RV rc; CK_MECHANISM mech = { CKM_IBM_ML_DSA_KEY_PAIR_GEN, NULL, 0 }; CK_BBOOL pkeyextractable = !extractable; CK_BYTE subject[] = {0}; CK_BYTE id[] = { 123 }; CK_BBOOL true = TRUE; CK_ATTRIBUTE publicKeyTemplate[] = { {CKA_VERIFY, &true, sizeof(true)}, {CKA_IBM_PARAMETER_SET, ¶meter_set, sizeof(parameter_set)}, }; 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_SIGN, &true, sizeof(true)}, {CKA_EXTRACTABLE, &extractable, sizeof(CK_BBOOL)}, {CKA_IBM_PROTKEY_EXTRACTABLE, &pkeyextractable, sizeof(CK_BBOOL)}, {CKA_IBM_PARAMETER_SET, ¶meter_set, sizeof(parameter_set)}, }; CK_ULONG num_publ_attrs = sizeof(publicKeyTemplate) / sizeof(CK_ATTRIBUTE); CK_ULONG num_priv_attrs = sizeof(privateKeyTemplate) / sizeof(CK_ATTRIBUTE); if (combined_extract) pkeyextractable = CK_TRUE; // generate keys rc = funcs->C_GenerateKeyPair(session, &mech, publicKeyTemplate, num_publ_attrs, privateKeyTemplate, num_priv_attrs, publ_key, priv_key); if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; return rc; } /** Create an IBM ML-DSA private key using private values **/ CK_RV create_IBM_ML_DSA_PrivateKey(CK_SESSION_HANDLE session, CK_BYTE pkcs8[], CK_ULONG pkcs8_len, CK_ULONG parameter_set, 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_BYTE priv_seed[], CK_ULONG priv_seed_len, CK_OBJECT_HANDLE * priv_key) { CK_OBJECT_CLASS class = CKO_PRIVATE_KEY; CK_KEY_TYPE keyType = CKK_IBM_ML_DSA; CK_UTF8CHAR label[] = "A IBM ML-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_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_ML_DSA_RHO, rho, rho_len}, {CKA_IBM_ML_DSA_SEED, seed, seed_len}, {CKA_IBM_ML_DSA_TR, tr, tr_len}, {CKA_IBM_ML_DSA_S1, s1, s1_len}, {CKA_IBM_ML_DSA_S2, s2, s2_len}, {CKA_IBM_ML_DSA_T0, t0, t0_len}, {CKA_IBM_ML_DSA_T1, t1, t1_len}, {CKA_IBM_PARAMETER_SET, ¶meter_set, sizeof(parameter_set)}, }; CK_ATTRIBUTE template_pkcs8[] = { {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_VALUE, pkcs8, pkcs8_len}, }; CK_ATTRIBUTE template_seed[] = { {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_ML_DSA_PRIVATE_SEED, priv_seed, priv_seed_len}, {CKA_IBM_PARAMETER_SET, ¶meter_set, sizeof(parameter_set)}, }; // create key if (pkcs8_len > 0) rc = funcs->C_CreateObject(session, template_pkcs8, sizeof(template_pkcs8) / sizeof(CK_ATTRIBUTE), priv_key); else if (priv_seed_len > 0) rc = funcs->C_CreateObject(session, template_seed, sizeof(template_seed) / sizeof(CK_ATTRIBUTE), priv_key); else rc = funcs->C_CreateObject(session, template, sizeof(template) / sizeof(CK_ATTRIBUTE), priv_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) testcase_notice("C_CreateObject rc=%s", p11_get_ckr(rc)); else if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); } return rc; } /** Create an IBM ML-DSA public key using (rho, t1) **/ CK_RV create_IBM_ML_DSA_PublicKey(CK_SESSION_HANDLE session, CK_BYTE spki[], CK_ULONG spki_len, CK_ULONG parameter_set, 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_ML_DSA; CK_UTF8CHAR label[] = "A IBM ML-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_VERIFY, &true, sizeof(true)}, {CKA_IBM_ML_DSA_RHO, rho, rho_len}, {CKA_IBM_ML_DSA_T1, t1, t1_len}, {CKA_IBM_PARAMETER_SET, ¶meter_set, sizeof(parameter_set)}, }; CK_ATTRIBUTE template_spki[] = { {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_VALUE, spki, spki_len}, }; // create key if (spki_len > 0) rc = funcs->C_CreateObject(session, template_spki, sizeof(template_spki) / sizeof(CK_ATTRIBUTE), publ_key); else rc = funcs->C_CreateObject(session, template, sizeof(template) / sizeof(CK_ATTRIBUTE), publ_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) testcase_notice("C_CreateObject rc=%s", p11_get_ckr(rc)); else if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); } return rc; } CK_RV generate_IBM_ML_KEM_KeyPair(CK_SESSION_HANDLE session, CK_ULONG parameter_set, CK_OBJECT_HANDLE *publ_key, CK_OBJECT_HANDLE *priv_key, CK_BBOOL extractable) { CK_RV rc; CK_MECHANISM mech = { CKM_IBM_ML_KEM_KEY_PAIR_GEN, NULL, 0 }; CK_BBOOL pkeyextractable = !extractable; CK_BYTE subject[] = {0}; CK_BYTE id[] = { 123 }; CK_BBOOL true = TRUE; CK_ATTRIBUTE publicKeyTemplate[] = { {CKA_DERIVE, &true, sizeof(true)}, {CKA_IBM_PARAMETER_SET, ¶meter_set, sizeof(parameter_set)}, }; 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_DERIVE, &true, sizeof(true)}, {CKA_EXTRACTABLE, &extractable, sizeof(CK_BBOOL)}, {CKA_IBM_PROTKEY_EXTRACTABLE, &pkeyextractable, sizeof(CK_BBOOL)}, {CKA_IBM_PARAMETER_SET, ¶meter_set, sizeof(parameter_set)}, }; CK_ULONG num_publ_attrs = sizeof(publicKeyTemplate) / sizeof(CK_ATTRIBUTE); CK_ULONG num_priv_attrs = sizeof(privateKeyTemplate) / sizeof(CK_ATTRIBUTE); if (combined_extract) pkeyextractable = CK_TRUE; // generate keys rc = funcs->C_GenerateKeyPair(session, &mech, publicKeyTemplate, num_publ_attrs, privateKeyTemplate, num_priv_attrs, publ_key, priv_key); if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; return rc; } /** Create an IBM ML-KEM private key using private values **/ CK_RV create_IBM_ML_KEM_PrivateKey(CK_SESSION_HANDLE session, CK_BYTE pkcs8[], CK_ULONG pkcs8_len, CK_ULONG parameter_set, CK_BYTE sk[], CK_ULONG sk_len, CK_BYTE pk[], CK_ULONG pk_len, CK_BYTE priv_seed[], CK_ULONG priv_seed_len, CK_OBJECT_HANDLE * priv_key) { CK_OBJECT_CLASS class = CKO_PRIVATE_KEY; CK_KEY_TYPE keyType = CKK_IBM_ML_KEM; CK_UTF8CHAR label[] = "A IBM ML-KEM 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_SIGN, &true, sizeof(true)}, {CKA_DERIVE, &true, sizeof(true)}, {CKA_IBM_ML_KEM_SK, sk, sk_len}, {CKA_IBM_ML_KEM_PK, pk, pk_len}, {CKA_IBM_PARAMETER_SET, ¶meter_set, sizeof(parameter_set)}, }; CK_ATTRIBUTE template_pkcs8[] = { {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_DERIVE, &true, sizeof(true)}, {CKA_VALUE, pkcs8, pkcs8_len}, }; CK_ATTRIBUTE template_seed[] = { {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_DERIVE, &true, sizeof(true)}, {CKA_IBM_ML_KEM_PRIVATE_SEED, priv_seed, priv_seed_len}, {CKA_IBM_PARAMETER_SET, ¶meter_set, sizeof(parameter_set)}, }; // create key if (pkcs8_len > 0) rc = funcs->C_CreateObject(session, template_pkcs8, sizeof(template_pkcs8) / sizeof(CK_ATTRIBUTE), priv_key); else if (priv_seed_len > 0) rc = funcs->C_CreateObject(session, template_seed, sizeof(template_seed) / sizeof(CK_ATTRIBUTE), priv_key); else rc = funcs->C_CreateObject(session, template, sizeof(template) / sizeof(CK_ATTRIBUTE), priv_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) testcase_notice("C_CreateObject rc=%s", p11_get_ckr(rc)); else if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); } return rc; } /** Create an IBM ML-KEM public key using **/ CK_RV create_IBM_ML_KEM_PublicKey(CK_SESSION_HANDLE session, CK_BYTE spki[], CK_ULONG spki_len, CK_ULONG parameter_set, CK_BYTE pk[], CK_ULONG pk_len, CK_OBJECT_HANDLE * publ_key) { CK_RV rc; CK_OBJECT_CLASS class = CKO_PUBLIC_KEY; CK_KEY_TYPE keyType = CKK_IBM_ML_KEM; CK_UTF8CHAR label[] = "A IBM ML-KEM 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_VERIFY, &true, sizeof(true)}, {CKA_DERIVE, &true, sizeof(true)}, {CKA_IBM_ML_KEM_PK, pk, pk_len}, {CKA_IBM_PARAMETER_SET, ¶meter_set, sizeof(parameter_set)}, }; CK_ATTRIBUTE template_spki[] = { {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_DERIVE, &true, sizeof(true)}, {CKA_VALUE, spki, spki_len}, }; // create key if (spki_len > 0) rc = funcs->C_CreateObject(session, template_spki, sizeof(template_spki) / sizeof(CK_ATTRIBUTE), publ_key); else rc = funcs->C_CreateObject(session, template, sizeof(template) / sizeof(CK_ATTRIBUTE), publ_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) testcase_notice("C_CreateObject rc=%s", p11_get_ckr(rc)); else if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); } return rc; } CK_RV generate_ML_DSA_KeyPair(CK_SESSION_HANDLE session, CK_ULONG parameter_set, CK_OBJECT_HANDLE *publ_key, CK_OBJECT_HANDLE *priv_key, CK_BBOOL extractable) { CK_RV rc; CK_MECHANISM mech = { CKM_ML_DSA_KEY_PAIR_GEN, NULL, 0 }; CK_BBOOL pkeyextractable = !extractable; CK_BYTE subject[] = {0}; CK_BYTE id[] = { 123 }; CK_BBOOL true = TRUE; CK_ATTRIBUTE publicKeyTemplate[] = { {CKA_VERIFY, &true, sizeof(true)}, {CKA_PARAMETER_SET, ¶meter_set, sizeof(parameter_set)}, }; 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_SIGN, &true, sizeof(true)}, {CKA_EXTRACTABLE, &extractable, sizeof(CK_BBOOL)}, {CKA_IBM_PROTKEY_EXTRACTABLE, &pkeyextractable, sizeof(CK_BBOOL)}, {CKA_PARAMETER_SET, ¶meter_set, sizeof(parameter_set)}, }; CK_ULONG num_publ_attrs = sizeof(publicKeyTemplate) / sizeof(CK_ATTRIBUTE); CK_ULONG num_priv_attrs = sizeof(privateKeyTemplate) / sizeof(CK_ATTRIBUTE); if (combined_extract) pkeyextractable = CK_TRUE; // generate keys rc = funcs->C_GenerateKeyPair(session, &mech, publicKeyTemplate, num_publ_attrs, privateKeyTemplate, num_priv_attrs, publ_key, priv_key); if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; return rc; } /** Create an ML-DSA private key using private values **/ CK_RV create_ML_DSA_PrivateKey(CK_SESSION_HANDLE session, CK_ULONG parameter_set, CK_BYTE value[], CK_ULONG value_len, CK_BYTE priv_seed[], CK_ULONG priv_seed_len, CK_OBJECT_HANDLE * priv_key, CK_BBOOL is_cca_token, CK_IBM_CCA_ML_DSA_KEY_MODE_TYPE cca_ml_dsa_mode) { CK_OBJECT_CLASS class = CKO_PRIVATE_KEY; CK_KEY_TYPE keyType = CKK_ML_DSA; CK_UTF8CHAR label[] = "A ML-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_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_VALUE, value, value_len}, {CKA_PARAMETER_SET, ¶meter_set, sizeof(parameter_set)}, {CKA_IBM_CCA_ML_DSA_KEY_MODE, &cca_ml_dsa_mode, sizeof(cca_ml_dsa_mode)}, }; CK_ULONG num_attrs = sizeof(template) / sizeof(CK_ATTRIBUTE); CK_ATTRIBUTE template_seed[] = { {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_SEED, priv_seed, priv_seed_len}, {CKA_PARAMETER_SET, ¶meter_set, sizeof(parameter_set)}, {CKA_IBM_CCA_ML_DSA_KEY_MODE, &cca_ml_dsa_mode, sizeof(cca_ml_dsa_mode)}, }; CK_ULONG num_seed_attrs = sizeof(template_seed) / sizeof(CK_ATTRIBUTE); if (!is_cca_token) { num_attrs--; num_seed_attrs--; } // create key if (priv_seed_len > 0) rc = funcs->C_CreateObject(session, template_seed, num_seed_attrs, priv_key); else rc = funcs->C_CreateObject(session, template, num_attrs, priv_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) testcase_notice("C_CreateObject rc=%s", p11_get_ckr(rc)); else if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); } return rc; } /** Create an ML-DSA public key **/ CK_RV create_ML_DSA_PublicKey(CK_SESSION_HANDLE session, CK_ULONG parameter_set, CK_BYTE value[], CK_ULONG value_len, CK_OBJECT_HANDLE * publ_key, CK_BBOOL is_cca_token, CK_IBM_CCA_ML_DSA_KEY_MODE_TYPE cca_ml_dsa_mode) { CK_RV rc; CK_OBJECT_CLASS class = CKO_PUBLIC_KEY; CK_KEY_TYPE keyType = CKK_ML_DSA; CK_UTF8CHAR label[] = "A ML-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_VERIFY, &true, sizeof(true)}, {CKA_VALUE, value, value_len}, {CKA_PARAMETER_SET, ¶meter_set, sizeof(parameter_set)}, {CKA_IBM_CCA_ML_DSA_KEY_MODE, &cca_ml_dsa_mode, sizeof(cca_ml_dsa_mode)}, }; CK_ULONG num_attrs = sizeof(template) / sizeof(CK_ATTRIBUTE); if (!is_cca_token) num_attrs--; // create key rc = funcs->C_CreateObject(session, template, num_attrs, publ_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) testcase_notice("C_CreateObject rc=%s", p11_get_ckr(rc)); else if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); } return rc; } CK_RV generate_ML_KEM_KeyPair(CK_SESSION_HANDLE session, CK_ULONG parameter_set, CK_OBJECT_HANDLE *publ_key, CK_OBJECT_HANDLE *priv_key, CK_BBOOL extractable) { CK_RV rc; CK_MECHANISM mech = { CKM_ML_KEM_KEY_PAIR_GEN, NULL, 0 }; CK_BBOOL pkeyextractable = !extractable; CK_BYTE subject[] = {0}; CK_BYTE id[] = { 123 }; CK_BBOOL true = TRUE; CK_ATTRIBUTE publicKeyTemplate[] = { {CKA_ENCAPSULATE, &true, sizeof(true)}, {CKA_PARAMETER_SET, ¶meter_set, sizeof(parameter_set)}, }; 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_DECAPSULATE, &true, sizeof(true)}, {CKA_EXTRACTABLE, &extractable, sizeof(CK_BBOOL)}, {CKA_IBM_PROTKEY_EXTRACTABLE, &pkeyextractable, sizeof(CK_BBOOL)}, {CKA_PARAMETER_SET, ¶meter_set, sizeof(parameter_set)}, }; CK_ULONG num_publ_attrs = sizeof(publicKeyTemplate) / sizeof(CK_ATTRIBUTE); CK_ULONG num_priv_attrs = sizeof(privateKeyTemplate) / sizeof(CK_ATTRIBUTE); if (combined_extract) pkeyextractable = CK_TRUE; // generate keys rc = funcs->C_GenerateKeyPair(session, &mech, publicKeyTemplate, num_publ_attrs, privateKeyTemplate, num_priv_attrs, publ_key, priv_key); if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; return rc; } /** Create an ML-KEM private key using private values **/ CK_RV create_ML_KEM_PrivateKey(CK_SESSION_HANDLE session, CK_ULONG parameter_set, CK_BYTE value[], CK_ULONG value_len, CK_BYTE priv_seed[], CK_ULONG priv_seed_len, CK_OBJECT_HANDLE * priv_key) { CK_OBJECT_CLASS class = CKO_PRIVATE_KEY; CK_KEY_TYPE keyType = CKK_ML_KEM; CK_UTF8CHAR label[] = "A ML-KEM 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_DECAPSULATE, &true, sizeof(true)}, {CKA_VALUE, value, value_len}, {CKA_PARAMETER_SET, ¶meter_set, sizeof(parameter_set)}, }; CK_ATTRIBUTE template_seed[] = { {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_DECAPSULATE, &true, sizeof(true)}, {CKA_SEED, priv_seed, priv_seed_len}, {CKA_PARAMETER_SET, ¶meter_set, sizeof(parameter_set)}, }; // create key if (priv_seed_len > 0) rc = funcs->C_CreateObject(session, template_seed, sizeof(template_seed) / sizeof(CK_ATTRIBUTE), priv_key); else rc = funcs->C_CreateObject(session, template, sizeof(template) / sizeof(CK_ATTRIBUTE), priv_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) testcase_notice("C_CreateObject rc=%s", p11_get_ckr(rc)); else if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); } return rc; } /** Create an ML-KEM public key **/ CK_RV create_ML_KEM_PublicKey(CK_SESSION_HANDLE session, CK_ULONG parameter_set, CK_BYTE value[], CK_ULONG value_len, CK_OBJECT_HANDLE * publ_key) { CK_RV rc; CK_OBJECT_CLASS class = CKO_PUBLIC_KEY; CK_KEY_TYPE keyType = CKK_ML_KEM; CK_UTF8CHAR label[] = "A ML-KEM 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_ENCAPSULATE, &true, sizeof(true)}, {CKA_VALUE, value, value_len}, {CKA_PARAMETER_SET, ¶meter_set, sizeof(parameter_set)}, }; // create key rc = funcs->C_CreateObject(session, template, sizeof(template) / sizeof(CK_ATTRIBUTE), publ_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) testcase_notice("C_CreateObject rc=%s", p11_get_ckr(rc)); else if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else 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) { if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else 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) { if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else 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) { if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else 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) { if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else 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) { if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else 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 EP11 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 exp5[] = { 0x05 }; // 5 CK_BYTE exp17[] = { 0x11 }; // 17 CK_BYTE exp257[] = { 0x01, 0x01 }; // 257 CK_BYTE exp65537[] = { 0x01, 0x00, 0x01 }; // 65537 // trim any leading zero bytes while (pubexp_len > 1 && pubexp[0] == 0x00) { pubexp++; pubexp_len--; } return (pubexp_len == 1 && (!memcmp(pubexp, exp3, 1))) || (pubexp_len == 1 && (!memcmp(pubexp, exp5, 1))) || (pubexp_len == 1 && (!memcmp(pubexp, exp17, 1))) || (pubexp_len == 2 && (!memcmp(pubexp, exp257, 2))) || (pubexp_len == 3 && (!memcmp(pubexp, exp65537, 3))); } /** Returns true if pubexp is valid for Soft Tokens **/ int is_valid_soft_pubexp(CK_BYTE pubexp[], CK_ULONG pubexp_len) { UNUSED(pubexp); UNUSED(pubexp_len); return TRUE; } /** 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, "Soft") == NULL) && (strstr((const char *) tokinfo.model, "TPM") == 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 Soft 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, "Soft") != 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.tv_usec - t1.tv_usec) / 1000; long s = t2.tv_sec - t1.tv_sec; 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] [-combined-extract] " "[-rsa8k] [-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 if (strcmp(argv[i], "-combined-extract") == 0) { combined_extract = TRUE; } else if (strcmp(argv[i], "-rsa8k") == 0) { rsa8k = 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; } // // CK_BBOOL do_GetFunctionList(void) { CK_INTERFACE *interface; CK_VERSION version; CK_FLAGS flags; CK_BBOOL rv; CK_RV rc; CK_RV(*getfunclist)(CK_FUNCTION_LIST **funcs); CK_RV(*getinterfacelist)(CK_INTERFACE_PTR interfaces, CK_ULONG *count); CK_RV(*getinterface)(CK_UTF8CHAR_PTR name, CK_VERSION_PTR version, CK_INTERFACE_PTR_PTR interface, CK_FLAGS flags); char *e; char *f = OCK_API_LIBNAME; CK_ULONG nmemb = 0; rv = FALSE; e = getenv("PKCSLIB"); if (e == NULL) e = f; pkcs11lib = dlopen(e, DYNLIB_LDFLAGS); if (pkcs11lib == NULL) goto ret; *(void **)(&getfunclist) = dlsym(pkcs11lib, "C_GetFunctionList"); if (getfunclist == NULL) goto ret; rc = getfunclist(&funcs); if (rc != CKR_OK) { testcase_error("C_GetFunctionList rc=%s", p11_get_ckr(rc)); goto ret; } *(void **)(&getinterfacelist) = dlsym(pkcs11lib, "C_GetInterfaceList"); if (getinterfacelist == NULL) { goto ret; } rc = getinterfacelist(NULL, &nmemb); if (rc != CKR_OK) { testcase_error("C_GetInterfaceList rc=%s", p11_get_ckr(rc)); goto ret; } ifs = calloc(nmemb, sizeof(*ifs)); if (ifs == NULL) { goto ret; } rc = getinterfacelist(ifs, &nmemb); if (rc != CKR_OK) { testcase_error("C_GetInterfaceList rc=%s", p11_get_ckr(rc)); goto ret; } *(void **)(&getinterface) = dlsym(pkcs11lib, "C_GetInterface"); if (getinterface == NULL) { goto ret; } version.major = 0x03; version.minor = 0x00; flags = CKF_INTERFACE_FORK_SAFE; rc = getinterface((CK_UTF8CHAR *)"PKCS 11", &version, &interface, flags); if (rc != CKR_OK) { testcase_error("C_GetInterface (v3.0) rc=%s", p11_get_ckr(rc)); goto ret; } funcs3 = interface->pFunctionList; version.major = 0x03; version.minor = 0x02; flags = CKF_INTERFACE_FORK_SAFE; rc = getinterface((CK_UTF8CHAR *)"PKCS 11", &version, &interface, flags); if (rc != CKR_OK) { testcase_error("C_GetInterface (v3.2) rc=%s", p11_get_ckr(rc)); goto ret; } funcs3_2 = interface->pFunctionList; rv = TRUE; ret: if (rv == TRUE) { atexit(free_ifs); atexit(unload_pkcslib); } else { free(ifs); ifs = NULL; if (pkcs11lib != NULL) { #ifndef WITH_SANITIZER dlclose(pkcs11lib); #endif pkcs11lib = NULL; } } return rv; } opencryptoki-opencryptoki-451d99c/testcases/common/common.mk000066400000000000000000000005611520105705100244350ustar00rootroot00000000000000noinst_LTLIBRARIES += testcases/common/libcommon.la testcases_common_libcommon_la_LIBADD = -lc -ldl -lpthread testcases_common_libcommon_la_CFLAGS = -c ${testcases_inc} \ -I${top_builddir}/usr/lib/api testcases_common_libcommon_la_SOURCES = usr/lib/common/p11util.c \ testcases/common/common.c nodist_testcases_common_libcommon_la_SOURCES = usr/lib/api/mechtable.c opencryptoki-opencryptoki-451d99c/testcases/crypto/000077500000000000000000000000001520105705100226425ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/testcases/crypto/README000066400000000000000000000023311520105705100235210ustar00rootroot00000000000000Notes: 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. opencryptoki-opencryptoki-451d99c/testcases/crypto/abfunc.c000066400000000000000000001417221520105705100242530ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2006-2021 * * 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 "common.c" #include "regress.h" #include "mech_to_str.h" #include "ec_curves.h" #define NUMKEYS 16 struct keys { union keysunion { struct details { // AB keys CK_OBJECT_HANDLE aes; CK_OBJECT_HANDLE des2; CK_OBJECT_HANDLE des3; CK_OBJECT_HANDLE generic; CK_OBJECT_HANDLE rsapub; CK_OBJECT_HANDLE rsapriv; CK_OBJECT_HANDLE ecpub; CK_OBJECT_HANDLE ecpriv; CK_OBJECT_HANDLE dsapub; CK_OBJECT_HANDLE dsapriv; CK_OBJECT_HANDLE dhpub; CK_OBJECT_HANDLE dhpriv; // non-AB key CK_OBJECT_HANDLE nonabpub; CK_OBJECT_HANDLE nonabpriv; CK_OBJECT_HANDLE nonabecpub; CK_OBJECT_HANDLE nonabecpriv; } d; CK_OBJECT_HANDLE keys[NUMKEYS]; } u; } keys; 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_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 AES_KEY_VAL[] = { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c }; 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_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 }; 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 }; /// Helper functions #define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0])) static void dumpEP11Blob(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key, const char *fmt, ...) { CK_ATTRIBUTE blobattr = { CKA_IBM_OPAQUE, NULL, 0 }; unsigned char *blob = NULL; char fname[1024]; FILE *f = NULL; va_list va; int rc; va_start(va, fmt); vsnprintf(fname, sizeof(fname), fmt, va); va_end(va); rc = funcs->C_GetAttributeValue(session, key, &blobattr, 1); if (rc != CKR_OK) return; blob = (unsigned char *)malloc(blobattr.ulValueLen); if (!blob) return; blobattr.pValue = blob; rc = funcs->C_GetAttributeValue(session, key, &blobattr, 1); if (rc != CKR_OK) goto out; f = fopen(fname, "wb"); if (!f) goto out; fwrite(blob, blobattr.ulValueLen, 1, f); out: free(blob); if (f) fclose(f); } static void dumpSPKI(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key, const char *fmt, ...) { CK_ATTRIBUTE blobattr = { CKA_PUBLIC_KEY_INFO, NULL, 0 }; unsigned char *blob = NULL; char fname[1024]; FILE *f = NULL; va_list va; int rc; va_start(va, fmt); vsnprintf(fname, sizeof(fname), fmt, va); va_end(va); rc = funcs->C_GetAttributeValue(session, key, &blobattr, 1); if (rc != CKR_OK) return; blob = (unsigned char *)malloc(blobattr.ulValueLen); if (!blob) return; blobattr.pValue = blob; rc = funcs->C_GetAttributeValue(session, key, &blobattr, 1); if (rc != CKR_OK) goto out; f = fopen(fname, "wb"); if (!f) goto out; fwrite(blob, blobattr.ulValueLen, 1, f); out: free(blob); if (f) fclose(f); } CK_RV compareDESKeys(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE source, CK_OBJECT_HANDLE dest) { CK_BYTE data[16] = {0}; CK_BYTE iv[] = {1,2,3,4,5,6,7,8}; CK_MECHANISM mech = {CKM_DES3_CBC_PAD, iv, sizeof(iv)}; CK_BYTE resultsource[24]; CK_BYTE resultdest[24]; CK_ULONG reslensource = 24; CK_ULONG reslendest = 24; CK_RV rc; rc = funcs->C_EncryptInit(session, &mech, source); if (rc != CKR_OK) return rc; rc = funcs->C_Encrypt(session, data, sizeof(data), resultsource, &reslensource); if (rc != CKR_OK) return rc; rc = funcs->C_EncryptInit(session, &mech, dest); if (rc != CKR_OK) return rc; rc = funcs->C_Encrypt(session, data, sizeof(data), resultdest, &reslendest); if (rc != CKR_OK) return rc; if (reslensource != reslendest || memcmp(resultsource, resultdest, reslendest)) return CKR_FUNCTION_FAILED; return CKR_OK; } CK_RV compareECKeys(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE sign, CK_OBJECT_HANDLE verify) { CK_BYTE data[16] = {0}; CK_BYTE *signature = NULL; CK_MECHANISM signmech = {CKM_ECDSA, 0, 0}; CK_MECHANISM verifymech = {CKM_ECDSA, 0, 0}; CK_ULONG signaturelen = 0; CK_RV rc; rc = funcs->C_SignInit(session, &signmech, sign); if (rc != CKR_OK) return rc; rc = funcs->C_Sign(session, data, sizeof(data), signature, &signaturelen); if (rc != CKR_OK) return rc; signature = calloc(1, signaturelen); if (!signature) return CKR_HOST_MEMORY; rc = funcs->C_Sign(session, data, sizeof(data), signature, &signaturelen); if (rc != CKR_OK) goto out; rc = funcs->C_VerifyInit(session, &verifymech, verify); if (rc != CKR_OK) goto out; rc = funcs->C_Verify(session, data, sizeof(data), signature, signaturelen); out: free(signature); return rc; } // expected to fail CK_RV createABAESKey(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE *handle) { 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, AES_KEY_VAL, sizeof(AES_KEY_VAL)}, {CKA_IBM_ATTRBOUND, &true, sizeof(true)}, {CKA_SENSITIVE, &true, sizeof(true)} }; return funcs->C_CreateObject(session, keyTemplate, ARRAY_SIZE(keyTemplate), handle); } CK_RV createABPublicDSAKey(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE *handle) { CK_OBJECT_CLASS class = CKO_PUBLIC_KEY; CK_KEY_TYPE keyType = CKK_DSA; CK_UTF8CHAR label[] = "A 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, DSA1024_PRIME, sizeof(DSA1024_PRIME)}, {CKA_SUBPRIME, DSA1024_SUBPRIME, sizeof(DSA1024_SUBPRIME)}, {CKA_BASE, DSA1024_BASE, sizeof(DSA1024_BASE)}, {CKA_VALUE, DSA1024_PUBLIC, sizeof(DSA1024_PUBLIC)}, {CKA_IBM_ATTRBOUND, &true, sizeof(true)} }; return funcs->C_CreateObject(session, template, ARRAY_SIZE(template), handle); } // expected to fail CK_RV createABPrivateDSAKey(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE *handle) { 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_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, DSA1024_PRIME, sizeof(DSA1024_PRIME)}, {CKA_SUBPRIME, DSA1024_SUBPRIME, sizeof(DSA1024_SUBPRIME)}, {CKA_BASE, DSA1024_BASE, sizeof(DSA1024_BASE)}, {CKA_VALUE, DSA1024_PRIVATE, sizeof(DSA1024_PRIVATE)}, {CKA_IBM_ATTRBOUND, &true, sizeof(true)}, {CKA_SENSITIVE, &true, sizeof(true)} }; return funcs->C_CreateObject(session, template, ARRAY_SIZE(template), handle); } CK_RV generateABAESKey(CK_SESSION_HANDLE session, CK_ULONG key_len, CK_OBJECT_HANDLE *handle) { CK_BBOOL cktrue = TRUE; CK_ATTRIBUTE key_gen_tmpl[] = { {CKA_VALUE_LEN, &key_len, sizeof(CK_ULONG)}, {CKA_IBM_ATTRBOUND, &cktrue, sizeof(CK_BBOOL)}, {CKA_SENSITIVE, &cktrue, sizeof(CK_BBOOL)} }; CK_MECHANISM mech = { .mechanism = CKM_AES_KEY_GEN, .ulParameterLen = 0, .pParameter = NULL, }; return funcs->C_GenerateKey(session, &mech, key_gen_tmpl, ARRAY_SIZE(key_gen_tmpl), handle); } CK_RV generateABDESKey(CK_SESSION_HANDLE session, CK_MECHANISM_TYPE type, CK_OBJECT_HANDLE *handle) { CK_MECHANISM mech = { type, NULL, 0 }; CK_BBOOL true = TRUE; CK_ATTRIBUTE tmpl[] = { {CKA_IBM_ATTRBOUND, &true, sizeof(true)}, {CKA_SENSITIVE, &true, sizeof(true)} }; return funcs->C_GenerateKey(session, &mech, tmpl, ARRAY_SIZE(tmpl), handle); } CK_RV generateABGenericSecret(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE *handle) { CK_OBJECT_CLASS class = CKO_SECRET_KEY; CK_BBOOL true = TRUE; CK_ULONG keylen = 20; CK_ATTRIBUTE tmpl[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_VALUE_LEN, &keylen, sizeof(keylen)}, {CKA_IBM_ATTRBOUND, &true, sizeof(true)}, {CKA_SENSITIVE, &true, sizeof(true)} }; CK_MECHANISM mech = { CKM_GENERIC_SECRET_KEY_GEN, NULL, 0 }; return funcs->C_GenerateKey(session, &mech, tmpl, ARRAY_SIZE(tmpl), handle); } CK_RV generateABRSAKey(CK_SESSION_HANDLE session, CK_BBOOL abpub, CK_BBOOL abpriv, CK_BBOOL sensitive, CK_OBJECT_HANDLE *pubkey, CK_OBJECT_HANDLE *privkey) { CK_MECHANISM mech = { CKM_RSA_PKCS_KEY_PAIR_GEN, NULL, 0 }; CK_BYTE subject[] = {0}; CK_BYTE id[] = {123}; CK_BBOOL cktrue = TRUE; CK_ULONG modulusBits = 4096; CK_BYTE publicExponent[] = {0x01, 0x00, 0x01}; CK_ATTRIBUTE pubkeyTemplate[] = { {CKA_ENCRYPT, &cktrue, sizeof(cktrue)}, {CKA_VERIFY, &cktrue, sizeof(cktrue)}, {CKA_WRAP, &cktrue, sizeof(cktrue)}, {CKA_MODULUS_BITS, &modulusBits, sizeof(modulusBits)}, {CKA_PUBLIC_EXPONENT, publicExponent, sizeof(publicExponent)}, {CKA_IBM_ATTRBOUND, &abpub, sizeof(abpub)} }; CK_ATTRIBUTE privkeyTemplate[] = { {CKA_TOKEN, &cktrue, sizeof(cktrue)}, {CKA_PRIVATE, &cktrue, sizeof(cktrue)}, {CKA_SUBJECT, subject, 0}, {CKA_ID, id, sizeof(id)}, {CKA_DECRYPT, &cktrue, sizeof(cktrue)}, {CKA_SIGN, &cktrue, sizeof(cktrue)}, {CKA_UNWRAP, &cktrue, sizeof(cktrue)}, {CKA_IBM_ATTRBOUND, &abpriv, sizeof(abpriv)}, {CKA_SENSITIVE, &sensitive, sizeof(sensitive)} }; return funcs->C_GenerateKeyPair(session, &mech, pubkeyTemplate, ARRAY_SIZE(pubkeyTemplate), privkeyTemplate, ARRAY_SIZE(privkeyTemplate), pubkey, privkey); } CK_RV generateABECKey(CK_SESSION_HANDLE session, CK_BBOOL ab, CK_OBJECT_HANDLE *pubkey, CK_OBJECT_HANDLE *privkey) { CK_BYTE prime256v1[] = OCK_PRIME256V1; CK_MECHANISM mech = { CKM_EC_KEY_PAIR_GEN, NULL, 0 }; CK_BYTE subject[] = {0}; CK_BYTE id[] = { 123 }; CK_BBOOL true = TRUE; CK_ATTRIBUTE publicKeyTemplate[] = { {CKA_VERIFY, &true, sizeof(true)}, {CKA_EC_PARAMS, &prime256v1, sizeof(prime256v1)}, {CKA_IBM_ATTRBOUND, &ab, sizeof(true)} }; 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_SIGN, &true, sizeof(true)}, {CKA_DERIVE, &true, sizeof(true)}, {CKA_IBM_ATTRBOUND, &ab, sizeof(true)}, {CKA_SENSITIVE, &true, sizeof(true)} }; return funcs->C_GenerateKeyPair(session, &mech, publicKeyTemplate, ARRAY_SIZE(publicKeyTemplate), privateKeyTemplate, ARRAY_SIZE(privateKeyTemplate), pubkey, privkey); } CK_RV generateABDSAKey(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE *pubkey, CK_OBJECT_HANDLE *privkey) { CK_MECHANISM mech = { CKM_DSA_KEY_PAIR_GEN, NULL, 0 }; CK_BBOOL true = TRUE; 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)}, {CKA_IBM_ATTRBOUND, &true, sizeof(true)} }; CK_ATTRIBUTE priv_tmpl[] = { {CKA_IBM_ATTRBOUND, &true, sizeof(true)}, {CKA_SENSITIVE, &true, sizeof(true)} }; return funcs->C_GenerateKeyPair(session, &mech, publ_tmpl, ARRAY_SIZE(publ_tmpl), priv_tmpl, ARRAY_SIZE(priv_tmpl), pubkey, privkey); } CK_RV generateABDHKey(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE *pubkey, CK_OBJECT_HANDLE *privkey) { CK_MECHANISM mech = { CKM_DH_PKCS_KEY_PAIR_GEN, NULL, 0 }; CK_BBOOL true = TRUE; CK_OBJECT_CLASS pub_key_class = CKO_PUBLIC_KEY; CK_KEY_TYPE key_type = CKK_DH; CK_UTF8CHAR publ_label[] = "An AB DH public key object"; CK_OBJECT_CLASS priv_key_class = CKO_PRIVATE_KEY; CK_UTF8CHAR priv_label[] = "An AB DH private key object"; 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)}, {CKA_IBM_ATTRBOUND, &true, sizeof(true)} }; 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, &true, sizeof(true)}, {CKA_IBM_ATTRBOUND, &true, sizeof(true)}, {CKA_SENSITIVE, &true, sizeof(true)} }; return funcs->C_GenerateKeyPair(session, &mech, publ_tmpl, ARRAY_SIZE(publ_tmpl), priv_tmpl, ARRAY_SIZE(priv_tmpl), pubkey, privkey); } // Expected to fail CK_RV generateABDilithiumKey(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE *pubkey, CK_OBJECT_HANDLE *privkey) { CK_MECHANISM mech = { CKM_IBM_DILITHIUM, NULL, 0 }; CK_BBOOL cktrue = TRUE; CK_ATTRIBUTE pubkeyTemplate[] = { {CKA_VERIFY, &cktrue, sizeof(cktrue)}, {CKA_IBM_ATTRBOUND, &cktrue, sizeof(cktrue)} }; CK_ATTRIBUTE privkeyTemplate[] = { {CKA_SIGN, &cktrue, sizeof(cktrue)}, {CKA_IBM_ATTRBOUND, &cktrue, sizeof(cktrue)}, {CKA_SENSITIVE, &cktrue, sizeof(cktrue)} }; return funcs->C_GenerateKeyPair(session, &mech, pubkeyTemplate, ARRAY_SIZE(pubkeyTemplate), privkeyTemplate, ARRAY_SIZE(privkeyTemplate), pubkey, privkey); } void teardown(CK_SESSION_HANDLE session) { int i; for (i = 0; i < NUMKEYS; ++i) funcs->C_DestroyObject(session, keys.u.keys[i]); } /// Test functions CK_RV do_CheckMechanismInfo(void) { CK_IBM_ATTRIBUTEBOUND_WRAP_PARAMS params = { .hSignVerifyKey = CK_INVALID_HANDLE }; CK_MECHANISM mech = { .mechanism = CKM_IBM_ATTRIBUTEBOUND_WRAP, .pParameter = ¶ms, .ulParameterLen = sizeof(params) }; CK_RV res = CKR_OK; // begin testsuite testsuite_begin("Check CKM_IBM_ATTRIBUTEBOUND_WRAP mechanism info."); // skip tests if the slot doesn't support this mechanism if (!mech_supported(SLOT_ID, CKM_IBM_ATTRIBUTEBOUND_WRAP)) { testsuite_skip(2, "Slot %u doesn't support CKM_IBM_ATTRIBUTEBOUND_WRAP (0x%x)", (unsigned int) SLOT_ID, (unsigned int) CKM_IBM_ATTRIBUTEBOUND_WRAP); res = CKR_FUNCTION_NOT_SUPPORTED; goto testcase_cleanup; } testcase_new_assertion(); testcase_begin("CKM_IBM_ATTRIBUTEBOUND_WRAP supported for wrapping"); if (!wrap_supported(SLOT_ID, mech)) testcase_fail("CKM_IBM_ATTRIBUTEBOUND_WRAP does NOT support wrapping"); else testcase_pass("CKM_IBM_ATTRIBUTEBOUND_WRAP does support wrapping"); testcase_new_assertion(); testcase_begin("CKM_IBM_ATTRIBUTEBOUND_WRAP supported for unwrapping"); if (!unwrap_supported(SLOT_ID, mech)) testcase_fail("CKM_IBM_ATTRIBUTEBOUND_WRAP does NOT support unwrapping"); else testcase_pass("CKM_IBM_ATTRIBUTEBOUND_WRAP does support unwrapping"); testcase_cleanup: return res; } void do_TestInvalidKeys(CK_SESSION_HANDLE session) { CK_OBJECT_HANDLE pubkey = CK_INVALID_HANDLE, privkey = CK_INVALID_HANDLE; CK_RV rc; // Expected to fail with CKR_TEMPLATE_INCONSISTENT testcase_begin("Create RSA AB key without CKA_SENSITIVE"); testcase_new_assertion(); rc = generateABRSAKey(session, TRUE, TRUE, FALSE, &pubkey, &privkey); if (rc != CKR_TEMPLATE_INCONSISTENT) testcase_fail("Create RSA AB key without CKA_SENSITIVE did not return CKR_TEMPLATE_INCONSISTENT but %s", p11_get_ckr(rc)); else testcase_pass("Create RSA AB key without CKA_SENSITIVE returned CKR_TEMPLATE_INCONSISTENT as expected"); if (pubkey != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, pubkey); if (privkey != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, privkey); testcase_begin("Create RSA AB key with non-AB private key"); testcase_new_assertion(); rc = generateABRSAKey(session, FALSE, TRUE, TRUE, &pubkey, &privkey); if (rc != CKR_TEMPLATE_INCONSISTENT) testcase_fail("Create RSA AB key with non-AB private key did not return CKR_TEMPLATE_INCONSISTENT but %s", p11_get_ckr(rc)); else testcase_pass("Create RSA AB key with non-AB private key returned CKR_TEMPLATE_INCONSISTENT as expected"); if (pubkey != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, pubkey); if (privkey != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, privkey); testcase_begin("Create RSA AB key with non-AB public key"); testcase_new_assertion(); rc = generateABRSAKey(session, TRUE, FALSE, TRUE, &pubkey, &privkey); if (rc != CKR_TEMPLATE_INCONSISTENT) testcase_fail("Create RSA AB key with non-AB public key did not return CKR_TEMPLATE_INCONSISTENT but %s", p11_get_ckr(rc)); else testcase_pass("Create RSA AB key with non-AB public key returned CKR_TEMPLATE_INCONSISTENT as expected"); if (pubkey != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, pubkey); if (privkey != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, privkey); } void do_CreateKeyObjects(CK_SESSION_HANDLE session) { CK_RV rc; CK_OBJECT_HANDLE handle = CK_INVALID_HANDLE; testcase_begin("Create AB AES key via C_CreateObject"); testcase_new_assertion(); rc = createABAESKey(session, &handle); if (is_rejected_by_policy(rc, session)) testcase_skip("Key import is not allowed by policy"); else if (rc != CKR_ATTRIBUTE_VALUE_INVALID) testcase_fail("C_CreateObject for AB AES key returned %s (expected CKR_ATTRIBUTE_VALUE_INVALID)", p11_get_ckr(rc)); else testcase_pass("C_CreateObject for AB AES key returned CKR_ATTRIBUTE_VALUE_INVALID as expected"); if (handle != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, handle); testcase_begin("Create AB DSA private key via C_CreateObject"); testcase_new_assertion(); rc = createABPrivateDSAKey(session, &handle); if (is_rejected_by_policy(rc, session)) testcase_skip("Key import is not allowed by policy"); else if (rc != CKR_ATTRIBUTE_VALUE_INVALID) testcase_fail("C_CreateObject for AB DSA private key returned %s (expected CKR_ATTRIBUTE_VALUE_INVALID)", p11_get_ckr(rc)); else testcase_pass("C_CreateObject for AB DSA private key returned CKR_ATTRIBUTE_VALUE_INVALID as expected"); if (handle != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, handle); testcase_begin("Create AB DSA public key via C_CreateObject"); testcase_new_assertion(); rc = createABPublicDSAKey(session, &handle); if (is_rejected_by_policy(rc, session)) testcase_skip("Key import is not allowed by policy"); else if (rc != CKR_OK) testcase_fail("C_CreateObject for AB DSA public key returned %s (expected CKR_OK)", p11_get_ckr(rc)); else testcase_pass("C_CreateObject for AB DSA public key returned CKR_OK as expected"); if (handle != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, handle); } CK_RV do_SetupKeys(CK_SESSION_HANDLE session) { CK_RV rc; int i; for (i = 0; i < NUMKEYS; ++i) keys.u.keys[i] = CK_INVALID_HANDLE; testcase_begin("Create AB AES key"); testcase_new_assertion(); rc = generateABAESKey(session, 32, &keys.u.d.aes); if (is_rejected_by_policy(rc, session)) testcase_skip("Key generation is not allowed by policy"); else if (rc != CKR_OK) testcase_fail("Create AB AES key failed with rc=%s", p11_get_ckr(rc)); else testcase_pass("Successfully created AB AES key"); testcase_begin("Create AB DES2 key"); testcase_new_assertion(); rc = generateABDESKey(session, CKM_DES2_KEY_GEN, &keys.u.d.des2); if (is_rejected_by_policy(rc, session)) testcase_skip("Key generation is not allowed by policy"); else if (rc != CKR_OK) testcase_fail("Create AB DES2 key failed with rc=%s", p11_get_ckr(rc)); else testcase_pass("Successfully created AB DES2 key"); testcase_begin("Create AB DES3 key"); testcase_new_assertion(); rc = generateABDESKey(session, CKM_DES3_KEY_GEN, &keys.u.d.des3); if (is_rejected_by_policy(rc, session)) testcase_skip("Key generation is not allowed by policy"); else if (rc != CKR_OK) testcase_fail("Create AB DES3 key failed with rc=%s", p11_get_ckr(rc)); else testcase_pass("Successfully created AB DES3 key"); testcase_begin("Create AB generic secret key"); testcase_new_assertion(); if (!mech_supported(SLOT_ID, CKM_GENERIC_SECRET_KEY_GEN)) { testcase_skip("CKM_GENERIC_SECRET_KEY_GEN not supported"); } else { rc = generateABGenericSecret(session, &keys.u.d.generic); if (is_rejected_by_policy(rc, session)) testcase_skip("Key generation is not allowed by policy"); else if (rc != CKR_OK) testcase_fail("Create AB generic secret key failed with rc=%s", p11_get_ckr(rc)); else testcase_pass("Successfully created AB generic secret key"); } testcase_begin("Create AB RSA key"); testcase_new_assertion(); rc = generateABRSAKey(session, TRUE, TRUE, TRUE, &keys.u.d.rsapub, &keys.u.d.rsapriv); if (is_rejected_by_policy(rc, session)) testcase_skip("Key generation is not allowed by policy"); else if (rc != CKR_OK) testcase_fail("Create AB RSA key failed with rc=%s", p11_get_ckr(rc)); else testcase_pass("Successfully created AB RSA key"); testcase_begin("Create AB EC key"); testcase_new_assertion(); rc = generateABECKey(session, TRUE, &keys.u.d.ecpub, &keys.u.d.ecpriv); if (is_rejected_by_policy(rc, session)) testcase_skip("Key generation is not allowed by policy"); else if (rc != CKR_OK) testcase_fail("Create AB EC key failed with rc=%s", p11_get_ckr(rc)); else testcase_pass("Successfully created AB EC key"); testcase_begin("Create AB DSA key"); testcase_new_assertion(); rc = generateABDSAKey(session, &keys.u.d.dsapub, &keys.u.d.dsapriv); if (is_rejected_by_policy(rc, session)) testcase_skip("Key generation is not allowed by policy"); else if (rc != CKR_OK) testcase_fail("Create AB DSA key failed with rc=%s", p11_get_ckr(rc)); else testcase_pass("Successfully created AB DSA key"); testcase_begin("Create AB DH key"); testcase_new_assertion(); rc = generateABDHKey(session, &keys.u.d.dhpub, &keys.u.d.dhpriv); if (is_rejected_by_policy(rc, session)) testcase_skip("Key generation is not allowed by policy"); else if (rc != CKR_OK) testcase_fail("Create AB DH key failed with rc=%s", p11_get_ckr(rc)); else testcase_pass("Successfully created AB DH key"); // These are not a test in this suite since it is covered by other suites... rc = generateABRSAKey(session, FALSE, FALSE, FALSE, &keys.u.d.nonabpub, &keys.u.d.nonabpriv); if (is_rejected_by_policy(rc, session)) { testcase_skip("Key generation is not allowed by policy"); rc = CKR_POLICY_VIOLATION; } if (rc != CKR_OK) return rc; rc = generateABECKey(session, FALSE, &keys.u.d.nonabecpub, &keys.u.d.nonabecpriv); if (is_rejected_by_policy(rc, session)) { testcase_skip("Key generation is not allowed by policy"); rc = CKR_POLICY_VIOLATION; } for (i = 0; i < NUMKEYS; ++i) { if (keys.u.keys[i] == CK_INVALID_HANDLE) rc = CKR_POLICY_VIOLATION; } return rc; } void do_TestKeyWrappingUnwrapping(CK_SESSION_HANDLE session) { CK_BYTE wrappedkey[16384]; CK_ULONG wrappedkeylen; CK_RV rc; unsigned i; static CK_KEY_TYPE deskt = CKK_DES3, eckt = CKK_EC; static CK_OBJECT_CLASS secretoc = CKO_SECRET_KEY, privateoc = CKO_PRIVATE_KEY; static CK_BBOOL cktrue = TRUE; static CK_ATTRIBUTE desunwrapattrs[] = { {CKA_CLASS, &secretoc, sizeof(CK_OBJECT_CLASS)}, {CKA_KEY_TYPE, &deskt, sizeof(CK_KEY_TYPE)}, {CKA_IBM_ATTRBOUND, &cktrue, sizeof(CK_BBOOL)} }; static CK_ATTRIBUTE ecprivunwrapattrs[] = { {CKA_CLASS, &privateoc, sizeof(CK_OBJECT_CLASS)}, {CKA_KEY_TYPE, &eckt, sizeof(CK_KEY_TYPE)}, {CKA_IBM_ATTRBOUND, &cktrue, sizeof(CK_BBOOL)} }; static const struct { CK_OBJECT_HANDLE *keytowrap; CK_OBJECT_HANDLE *wrappingkey; CK_OBJECT_HANDLE *signingkey; CK_OBJECT_HANDLE *unwrappingkey; CK_OBJECT_HANDLE *verificationkey; CK_RV wrapres; CK_RV unwrapres;// ignored if wrapres != CKR_OK // ignored if wrapres != CKR_OK or unwrapres != CKR_OK CK_RV (*compare)(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE source, CK_OBJECT_HANDLE dest); CK_OBJECT_HANDLE *comparedest; CK_ATTRIBUTE *unwraptemplate; CK_ULONG unwraptemplatesize; } config[] = { // symm, symm, symm /*0*/{&keys.u.d.des3, &keys.u.d.aes, &keys.u.d.aes, &keys.u.d.aes, &keys.u.d.aes, CKR_OK, CKR_OK, compareDESKeys, &keys.u.d.des3, desunwrapattrs, ARRAY_SIZE(desunwrapattrs)}, // symm, symm, asymm /*1*/{&keys.u.d.des3, &keys.u.d.aes, &keys.u.d.ecpriv, &keys.u.d.aes, &keys.u.d.ecpub, CKR_OK, CKR_OK, compareDESKeys, &keys.u.d.des3, desunwrapattrs, ARRAY_SIZE(desunwrapattrs)}, // symm, asymm, symm /*2*/{&keys.u.d.des3, &keys.u.d.rsapub, &keys.u.d.ecpriv, &keys.u.d.rsapriv, &keys.u.d.ecpub, CKR_OK, CKR_OK, compareDESKeys, &keys.u.d.des3, desunwrapattrs, ARRAY_SIZE(desunwrapattrs)}, // symm, asymm, asymm /*3*/{&keys.u.d.des3, &keys.u.d.rsapub, &keys.u.d.ecpriv, &keys.u.d.rsapriv, &keys.u.d.ecpub, CKR_OK, CKR_OK, compareDESKeys, &keys.u.d.des3, desunwrapattrs, ARRAY_SIZE(desunwrapattrs)}, // asymm, symm, symm /*4*/{&keys.u.d.ecpriv, &keys.u.d.aes, &keys.u.d.aes, &keys.u.d.aes, &keys.u.d.aes, CKR_OK, CKR_OK, compareECKeys, &keys.u.d.ecpub, ecprivunwrapattrs, ARRAY_SIZE(ecprivunwrapattrs)}, // asymm, symm, asymm /*5*/{&keys.u.d.ecpriv, &keys.u.d.aes, &keys.u.d.ecpriv, &keys.u.d.aes, &keys.u.d.ecpub, CKR_OK, CKR_OK, compareECKeys, &keys.u.d.ecpub, ecprivunwrapattrs, ARRAY_SIZE(ecprivunwrapattrs)}, // asymm, asymm, symm /*6*/{&keys.u.d.ecpriv, &keys.u.d.rsapub, &keys.u.d.ecpriv, &keys.u.d.rsapriv, &keys.u.d.ecpub, CKR_OK, CKR_OK, compareECKeys, &keys.u.d.ecpub, ecprivunwrapattrs, ARRAY_SIZE(ecprivunwrapattrs)}, // asymm, asymm, asymm /*7*/{&keys.u.d.ecpriv, &keys.u.d.rsapub, &keys.u.d.ecpriv, &keys.u.d.rsapriv, &keys.u.d.ecpub, CKR_OK, CKR_OK, compareECKeys, &keys.u.d.ecpub, ecprivunwrapattrs, ARRAY_SIZE(ecprivunwrapattrs)}, // kek unsupported /*8*/{&keys.u.d.des3, &keys.u.d.ecpub, &keys.u.d.aes, &keys.u.d.ecpriv, &keys.u.d.aes, CKR_WRAPPING_KEY_TYPE_INCONSISTENT, CKR_OK, 0, 0, 0, 0}, /*9*/{&keys.u.d.des3, &keys.u.d.rsapub, &keys.u.d.aes, &keys.u.d.dsapriv, &keys.u.d.aes, CKR_OK, CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT, 0, 0, desunwrapattrs, ARRAY_SIZE(desunwrapattrs)}, // kek not ab /*10*/{&keys.u.d.des3, &keys.u.d.nonabpub, &keys.u.d.aes, &keys.u.d.nonabpriv, &keys.u.d.aes, CKR_KEY_FUNCTION_NOT_PERMITTED, CKR_OK, 0, 0, 0, 0}, /*11*/{&keys.u.d.des3, &keys.u.d.rsapub, &keys.u.d.aes, &keys.u.d.nonabpriv, &keys.u.d.aes, CKR_OK, CKR_KEY_FUNCTION_NOT_PERMITTED, 0, 0, desunwrapattrs, ARRAY_SIZE(desunwrapattrs)}, // sign/verify key not ab /*12*/{&keys.u.d.des3, &keys.u.d.rsapub, &keys.u.d.nonabpriv, &keys.u.d.rsapriv, &keys.u.d.aes, CKR_KEY_FUNCTION_NOT_PERMITTED, CKR_OK, 0, 0, 0, 0}, /*13*/{&keys.u.d.des3, &keys.u.d.rsapub, &keys.u.d.aes, &keys.u.d.rsapriv, &keys.u.d.nonabpub, CKR_OK, CKR_KEY_FUNCTION_NOT_PERMITTED, 0, 0, desunwrapattrs, ARRAY_SIZE(desunwrapattrs)}, // signing key not able to sign /*14*/{&keys.u.d.des3, &keys.u.d.rsapub, &keys.u.d.ecpub, &keys.u.d.rsapriv, &keys.u.d.ecpub, CKR_KEY_FUNCTION_NOT_PERMITTED, CKR_OK, 0, 0, 0, 0}, /*15*/{&keys.u.d.des3, &keys.u.d.rsapub, &keys.u.d.ecpriv, &keys.u.d.rsapriv, &keys.u.d.ecpriv, CKR_OK, CKR_KEY_FUNCTION_NOT_PERMITTED, 0, 0, desunwrapattrs, ARRAY_SIZE(desunwrapattrs)}, // target non-ab /*16*/{&keys.u.d.nonabpriv, &keys.u.d.rsapub, &keys.u.d.aes, &keys.u.d.rsapriv, &keys.u.d.aes, CKR_KEY_NOT_WRAPPABLE, CKR_OK, 0, 0, 0, 0}, // Wrong key type in unwrap template /*17*/{&keys.u.d.des3, &keys.u.d.aes, &keys.u.d.aes, &keys.u.d.aes, &keys.u.d.aes, CKR_OK, CKR_TEMPLATE_INCONSISTENT, 0, 0, ecprivunwrapattrs, ARRAY_SIZE(ecprivunwrapattrs)} }; for (i = 0; i < ARRAY_SIZE(config); ++i) { CK_OBJECT_HANDLE unwrapped; CK_IBM_ATTRIBUTEBOUND_WRAP_PARAMS params; CK_MECHANISM mech = {CKM_IBM_ATTRIBUTEBOUND_WRAP, ¶ms, sizeof(params)}; params.hSignVerifyKey = *(config[i].signingkey); testcase_begin("AB Wrap/Unwrap test %u", i); testcase_new_assertion(); wrappedkeylen = sizeof(wrappedkey); rc = funcs->C_WrapKey(session, &mech, *(config[i].wrappingkey), *(config[i].keytowrap), wrappedkey, &wrappedkeylen); if (rc != config[i].wrapres) { testcase_fail("Wrap/Unwrap test %u: wrapping: expected %s, got %s", i, p11_get_ckr(config[i].wrapres), p11_get_ckr(rc)); // Skip rest of the test continue; } else if (rc != CKR_OK) { testcase_pass("Wrap/Unwrap test %u: wrapping failed as expected", i); // Wrapping failed as expected. So skip unwrapping. continue; } params.hSignVerifyKey = *(config[i].verificationkey); rc = funcs->C_UnwrapKey(session, &mech, *(config[i].unwrappingkey), wrappedkey, wrappedkeylen, config[i].unwraptemplate, config[i].unwraptemplatesize, &unwrapped); if (rc != config[i].unwrapres) { testcase_fail("Wrap/Unwrap test %u: unwrapping: expected %s, got %s", i, p11_get_ckr(config[i].unwrapres), p11_get_ckr(rc)); // Skip rest of the test continue; } else if (rc != CKR_OK) { testcase_pass("Wrap/Unwrap test %u: unwrapping failed as expected", i); continue; } rc = config[i].compare(session, unwrapped, *(config[i].comparedest)); if (rc != CKR_OK) { dumpEP11Blob(session, *(config[i].wrappingkey), "dump-wrappingkey-%u", i); dumpEP11Blob(session, *(config[i].keytowrap), "dump-keytowrap-%u", i); dumpEP11Blob(session, *(config[i].signingkey), "dump-signingkey-%u", i); dumpEP11Blob(session, unwrapped, "dump-unwrapped-%u", i); dumpSPKI(session, *(config[i].keytowrap), "dump-keytowrap-spki-%u", i); dumpSPKI(session, unwrapped, "dump-unwrapped-spki-%u", i); testcase_fail("Wrap/Unwrap test %u: compare returned %s", i, p11_get_ckr(rc)); } else { testcase_pass("Wrap/Unwrap test %u: cycle passed", i); } funcs->C_DestroyObject(session, unwrapped); } } void do_TestAttributeChange(CK_SESSION_HANDLE session) { CK_BBOOL cktrue = TRUE, ckfalse=FALSE; CK_ATTRIBUTE attr = { .type = CKA_IBM_ATTRBOUND, .ulValueLen = sizeof(CK_BBOOL) }; CK_RV rc; CK_OBJECT_HANDLE copyres = CK_INVALID_HANDLE; testcase_begin("Set CKA_IBM_ATTRBOUND to TRUE via C_SetAttributeValue"); testcase_new_assertion(); attr.pValue = &cktrue; rc = funcs->C_SetAttributeValue(session, keys.u.d.nonabpub, &attr, 1); if (rc != CKR_ATTRIBUTE_READ_ONLY) testcase_fail("Changed CKA_IBM_ATTRBOUND via C_SetAttributeValue to TRUE"); else testcase_pass("Could not change CKA_IBM_ATTRBOUND via C_SetAttributeValue to TRUE"); testcase_begin("Set CKA_IBM_ATTRBOUND to TRUE via C_CopyObject"); testcase_new_assertion(); attr.pValue = &cktrue; rc = funcs->C_CopyObject(session, keys.u.d.nonabpub, &attr, 1, ©res); if (rc != CKR_ATTRIBUTE_READ_ONLY) testcase_fail("Changed CKA_IBM_ATTRBOUND via C_CopyObject to TRUE"); else testcase_pass("Could not change CKA_IBM_ATTRBOUND via C_CopyObject to TRUE"); if (copyres != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, copyres); copyres = CK_INVALID_HANDLE; testcase_begin("Set CKA_IBM_ATTRBOUND to FALSE via C_SetAttributeValue"); testcase_new_assertion(); attr.pValue = &ckfalse; rc = funcs->C_SetAttributeValue(session, keys.u.d.des2, &attr, 1); if (rc != CKR_ATTRIBUTE_READ_ONLY) testcase_fail("Changed CKA_IBM_ATTRBOUND via C_SetAttributeValue to FALSE"); else testcase_pass("Could not change CKA_IBM_ATTRBOUND via C_SetAttributeValue to FALSE"); testcase_begin("Set CKA_IBM_ATTRBOUND to FALSE via C_CopyObject"); testcase_new_assertion(); attr.pValue = &ckfalse; rc = funcs->C_CopyObject(session, keys.u.d.des2, &attr, 1, ©res); if (rc != CKR_ATTRIBUTE_READ_ONLY) testcase_fail("Changed CKA_IBM_ATTRBOUND via C_CopyObject to FALSE"); else testcase_pass("Could not change CKA_IBM_ATTRBOUND via C_CopyObject to FALSE"); if (copyres != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, copyres); } void do_TestDerive(CK_SESSION_HANDLE session) { CK_RV rc; unsigned i; CK_BBOOL val, checkval, true = TRUE; CK_OBJECT_CLASS class = CKO_SECRET_KEY; CK_KEY_TYPE key_type = CKK_GENERIC_SECRET; CK_ULONG valuelen = 10; // Cannot be static because of @val CK_ATTRIBUTE derive_tmpl[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &key_type, sizeof(key_type)}, {CKA_SENSITIVE, &true, sizeof(true)}, {CKA_VALUE_LEN, &valuelen, sizeof(CK_ULONG)}, {CKA_IBM_ATTRBOUND, &val, sizeof(CK_BBOOL)} }; CK_ATTRIBUTE derive_tmpl_noab[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &key_type, sizeof(key_type)}, {CKA_SENSITIVE, &true, sizeof(true)}, {CKA_VALUE_LEN, &valuelen, sizeof(CK_ULONG)} }; // Workaround since templates are not static CK_ATTRIBUTE *tmpls[] = { derive_tmpl, derive_tmpl_noab }; CK_ULONG tmplsizes[] = { ARRAY_SIZE(derive_tmpl), ARRAY_SIZE(derive_tmpl_noab) }; CK_ATTRIBUTE checkattr = {CKA_IBM_ATTRBOUND, &checkval, sizeof(CK_BBOOL)}; CK_ECDH1_DERIVE_PARAMS parm; CK_MECHANISM mech = {CKM_ECDH1_DERIVE, &parm, sizeof(parm)}; CK_BYTE pubkey_value[256]; CK_ATTRIBUTE extr_tmpl = {CKA_EC_POINT, pubkey_value, sizeof(pubkey_value)}; CK_OBJECT_HANDLE handle; static const struct { CK_OBJECT_HANDLE *basekey; CK_OBJECT_HANDLE *pubkey; CK_ULONG tmplidx; CK_BBOOL abval; CK_RV exprc; CK_BBOOL expabval; } config[] = { // AB from AB with explicit template /*0*/{&keys.u.d.ecpriv, &keys.u.d.ecpub, 0, TRUE, CKR_OK, TRUE}, // AB from AB with implicit template /*1*/{&keys.u.d.ecpriv, &keys.u.d.ecpub, 1, TRUE, CKR_OK, TRUE}, // non-AB from AB /*2*/{&keys.u.d.ecpriv, &keys.u.d.ecpub, 0, FALSE, CKR_OK, FALSE}, // AB from non-AB (expected to fail) /*3*/{&keys.u.d.nonabecpriv, &keys.u.d.nonabecpub, 0, TRUE, CKR_TEMPLATE_INCONSISTENT, FALSE} }; for (i = 0; i < ARRAY_SIZE(config); ++i) { handle = CK_INVALID_HANDLE; val = config[i].abval; testcase_begin("Derive Test %u", i); testcase_new_assertion(); rc = funcs->C_GetAttributeValue(session, *(config[i].pubkey), &extr_tmpl, 1); if (rc != CKR_OK) { testcase_fail("Derive Test %u failed to extract EC point (rc=%s)", i, p11_get_ckr(rc)); continue; } parm.kdf = CKD_NULL; parm.pSharedData = NULL; parm.ulSharedDataLen = 0; parm.pPublicData = extr_tmpl.pValue; parm.ulPublicDataLen = extr_tmpl.ulValueLen; rc = funcs->C_DeriveKey(session, &mech, *(config[i].basekey), tmpls[config[i].tmplidx], tmplsizes[config[i].tmplidx], &handle); if (rc == CKR_MECHANISM_INVALID) { /* Special handling for bug in EP11: ECDH only supported for newer cards. */ testcase_skip("Derive Test %u skipped due to bad card level\n", i); continue; }else if (rc != config[i].exprc) { testcase_fail("Derive Test %u got unexpected derive result (got: %s; expected %s)", i, p11_get_ckr(rc), p11_get_ckr(config[i].exprc)); continue; } if (rc == CKR_OK) { rc = funcs->C_GetAttributeValue(session, handle, &checkattr, 1); if (rc == CKR_TEMPLATE_INCOMPLETE) { // Treat this as okay, but non-AB rc = CKR_OK; checkval = FALSE; } if (rc != CKR_OK) { testcase_fail("Derive Test %u failed to retrieve AB attribute (rc=%s)", i, p11_get_ckr(rc)); } else if (checkval == config[i].expabval) { testcase_pass("Derive Test %u: cycle completed", i); } else { testcase_fail("Derive Test %u got wrong AB value (expected %s)", i, config[i].expabval ? "TRUE" : "FALSE"); } } else { testcase_pass("Derive Test %u failed as expected", i); } funcs->C_DestroyObject(session, handle); } } void testdriver(void) { CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; CK_ULONG user_pin_len; CK_SESSION_HANDLE session; CK_FLAGS flags; CK_RV rc = CKR_OK; testsuite_begin("Attribute Bound Keys Tests"); testcase_rw_session(); testcase_user_login(); do_TestInvalidKeys(session); do_CreateKeyObjects(session); rc = do_SetupKeys(session); if (rc == CKR_POLICY_VIOLATION) { rc = CKR_OK; goto testcase_cleanup; } if (rc != CKR_OK) { testcase_error("Bail out since keys were not properly created!"); goto testcase_cleanup; } do_TestKeyWrappingUnwrapping(session); do_TestDerive(session); do_TestAttributeChange(session); testcase_cleanup: teardown(session); testcase_user_logout(); testcase_close_session(); } 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) { 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; } } if (is_ep11_token(SLOT_ID)) { testcase_setup(); rc = do_CheckMechanismInfo(); if (rc != CKR_OK) { // Skip, but don't crash the test executor rc = 0; } else { testdriver(); testcase_print_result(); } } else { rc = 0; testcase_begin("%s\n", __func__); testcase_skip("%s only supported on the EP11 token.\n", argv[0]); } funcs->C_Finalize(NULL); return testcase_return(rc); } opencryptoki-opencryptoki-451d99c/testcases/crypto/aes.h000066400000000000000000003255731520105705100236020ustar00rootroot00000000000000/* * 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 #define AES_KEY_WRAP_BLOCK_SIZE 8 #define AES_KEY_WRAP_IV_SIZE AES_KEY_WRAP_BLOCK_SIZE #define AES_KEY_WRAP_KWP_IV_SIZE 4 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 * 8, .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, .ulIvBits = AES_BLOCK_SIZE * 8, .ulAADLen = 0, .ulTagBits = 16, }; struct CK_MECHANISM aes_keygen = { .mechanism = CKM_AES_KEY_GEN, .ulParameterLen = 0, .pParameter = NULL, }; struct CK_MECHANISM aes_xts_keygen = { .mechanism = CKM_AES_XTS_KEY_GEN, .ulParameterLen = 0, .pParameter = NULL, }; struct mac_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_mac_test_suite_info { const char *name; unsigned int tvcount; struct mac_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}, } }; static struct aes_test_vector aes_xts_tv[] = { { // #0 .key = {0x46, 0xe6, 0xed, 0x9e, 0xf4, 0x2d, 0xcd, 0xb3, 0xc8, 0x93, 0x09, 0x3c, 0x28, 0xe1, 0xfc, 0x0f, 0x91, 0xf5, 0xca, 0xa3, 0xb6, 0xe0, 0xbc, 0x5a, 0x14, 0xe7, 0x83, 0x21, 0x5c, 0x1d, 0x5b, 0x61,}, .klen = 32, .plaintext = {0xe3, 0x77, 0x8d, 0x68, 0xe7, 0x30, 0xef, 0x94, 0x5b, 0x4a, 0xe3, 0xbc, 0x5b, 0x93, 0x6b, 0xdd,}, .plen = 16, .ciphertext = {0x97, 0x40, 0x9f, 0x1f, 0x71, 0xae, 0x45, 0x21, 0xcb, 0x49, 0xa3, 0x29, 0x73, 0xde, 0x4d, 0x05,}, .clen = 16, .iv = {0x72, 0xf3, 0xb0, 0x54, 0xcb, 0xdc, 0x2f, 0x9e, 0x3c, 0x5b, 0xc5, 0x51, 0xd4, 0x4d, 0xdb, 0xa0}, .ivlen = 16, .num_chunks_ciph = 3, .chunks_ciph = {10, 0, 6}, }, { // #1 .key = {0x93, 0x56, 0xcd, 0xad, 0x25, 0x1a, 0xb6, 0x11, 0x14, 0xce, 0xc2, 0xc4, 0x4a, 0x60, 0x92, 0xdd, 0xe9, 0xf7, 0x46, 0xcc, 0x65, 0xae, 0x3b, 0xd4, 0x96, 0x68, 0x64, 0xaa, 0x36, 0x26, 0xd1, 0x88,}, .klen = 32, .plaintext = {0xce, 0x17, 0x6b, 0xdd, 0xe3, 0x39, 0x50, 0x5b, 0xa1, 0x5d, 0xea, 0x36, 0xd2, 0x8c, 0xe8, 0x7d,}, .plen = 16, .ciphertext = {0x22, 0xf5, 0xf9, 0x37, 0xdf, 0xb3, 0x9e, 0x5b, 0x74, 0x25, 0xed, 0x86, 0x3d, 0x31, 0x0b, 0xe1,}, .clen = 16, .iv = {0x68, 0x88, 0x27, 0x83, 0x65, 0x24, 0x36, 0xc4, 0x85, 0x7a, 0x88, 0xc0, 0xc3, 0x73, 0x41, 0x7e,}, .ivlen = 16, .num_chunks_ciph = 3, .chunks_ciph = {10, -1, 6}, }, { // #2 .key = {0x97, 0x09, 0x8b, 0x46, 0x5a, 0x44, 0xca, 0x75, 0xe7, 0xa1, 0xc2, 0xdb, 0xfc, 0x40, 0xb7, 0xa6, 0x1a, 0x20, 0xe3, 0x2c, 0x6d, 0x9d, 0xbf, 0xda, 0x80, 0x72, 0x6f, 0xee, 0x10, 0x54, 0x1b, 0xab, 0x47, 0x54, 0x63, 0xca, 0x07, 0xc1, 0xc1, 0xe4, 0x49, 0x61, 0x73, 0x32, 0x14, 0x68, 0xd1, 0xab, 0x3f, 0xad, 0x8a, 0xd9, 0x1f, 0xcd, 0xc6, 0x2a, 0xbe, 0x07, 0xbf, 0xf8, 0xef, 0x96, 0x1b, 0x6b,}, .klen = 64, .plaintext = {0xd1, 0x9c, 0xfb, 0x38, 0x3b, 0xaf, 0x87, 0x2e, 0x6f, 0x12, 0x16, 0x87, 0x45, 0x1d, 0xe1, 0x5c,}, .plen = 16, .ciphertext = {0xeb, 0x22, 0x26, 0x9b, 0x14, 0x90, 0x50, 0x27, 0xdc, 0x73, 0xc4, 0xa4, 0x0f, 0x93, 0x80, 0x69,}, .clen = 16, .iv = {0x15, 0x60, 0x1e, 0x2e, 0x35, 0x85, 0x10, 0xa0, 0x9d, 0xdc, 0xa4, 0xea, 0x17, 0x51, 0xf4, 0x3c,}, .ivlen = 16, .num_chunks_ciph = 4, .chunks_ciph = {4, 4, 4, 4}, }, { // #3 .key = {0xfb, 0xf0, 0x77, 0x6e, 0x7d, 0xbe, 0x49, 0x10, 0xfb, 0x0c, 0x12, 0x0f, 0x41, 0x85, 0x71, 0x21, 0x92, 0x6c, 0x05, 0x2f, 0xd6, 0x5a, 0x27, 0x8c, 0xd2, 0xf0, 0xd9, 0x8d, 0xa5, 0x4e, 0xdf, 0xd5, 0x08, 0x03, 0xa4, 0x2f, 0xbe, 0x6f, 0xd1, 0x33, 0x58, 0x49, 0x00, 0xe8, 0xdc, 0x7a, 0x11, 0x52, 0x39, 0x1f, 0x82, 0x2d, 0x76, 0xa7, 0x56, 0x68, 0xcf, 0xce, 0x7f, 0x8d, 0xde, 0x20, 0x3e, 0xc8,}, .klen = 64, .plaintext = {0x3e, 0x2e, 0x26, 0x9d, 0x78, 0x3a, 0x2b, 0x29, 0xe8, 0x73, 0xd6, 0x73, 0x47, 0x9f, 0x51, 0x16, 0x73, 0x4f, 0xe0, 0x3e, 0xe3, 0x29, 0x65, 0xed, 0xc4, 0x79, 0x35, 0xc0, 0xea, 0x99, 0xa0, 0x64, 0xbd, 0x44, 0x4b, 0xec, 0x12, 0x5b, 0x2c, 0x78, 0x9d, 0xb9, 0xde, 0x6d, 0x18, 0x35, 0x92, 0x05, 0x3b, 0x48, 0xa8, 0x77, 0xa9, 0x5a, 0xc2, 0x55, 0x9c, 0x3d, 0xdf, 0xc7, 0xb4, 0xdb, 0x99, 0x07,}, .plen = 64, .ciphertext = {0x4c, 0x70, 0xbd, 0xbb, 0x77, 0x30, 0x2b, 0x7f, 0x1f, 0xdd, 0xca, 0x50, 0xdc, 0x70, 0x73, 0x1e, 0x00, 0x8a, 0x26, 0x55, 0xd2, 0x2a, 0xd0, 0x20, 0x0c, 0x11, 0x1f, 0xd3, 0x2a, 0x67, 0x5a, 0x7e, 0x09, 0x97, 0x11, 0x43, 0x6f, 0x98, 0xd2, 0x1c, 0x72, 0x77, 0x2e, 0x0d, 0xd7, 0x67, 0x2f, 0xf5, 0xfd, 0x00, 0xdd, 0xcb, 0xe1, 0x1e, 0xb9, 0x7e, 0x69, 0x87, 0x83, 0xbf, 0xa4, 0x05, 0x46, 0xe3,}, .clen = 64, .iv = {0x39, 0x5b, 0x6a, 0xcf, 0x9a, 0xdc, 0xd2, 0x91, 0xc2, 0xc9, 0x48, 0x86, 0x36, 0x33, 0xaf, 0xf8,}, .ivlen = 16, .num_chunks_ciph = 6, .chunks_ciph = {15, 0, 18, -1, 10, 21}, }, { // #4 .key = {0x00, 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 }, .klen = 64, .iv = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, .ivlen = 16, .plaintext = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10}, .plen = 17, .ciphertext = {0x02, 0x04, 0x4b, 0x67, 0x14, 0x6e, 0x6a, 0x91, 0xbf, 0x0c, 0xc1, 0xfe, 0xe7, 0xcd, 0x88, 0x12, 0xb8}, .clen = 17, .num_chunks_ciph = 3, .chunks_ciph = { 5, 5, 7}, } }; /* Test vectors from RFC 3394 */ static struct aes_test_vector aes_key_wrap_tv[] = { { // #0 .key = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,}, .klen = 16, .plaintext = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,}, .plen = 16, .ciphertext = {0x1F, 0xA6, 0x8B, 0x0A, 0x81, 0x12, 0xB4, 0x47, 0xAE, 0xF3, 0x4B, 0xD8, 0xFB, 0x5A, 0x7B, 0x82, 0x9D, 0x3E, 0x86, 0x23, 0x71, 0xD2, 0xCF, 0xE5,}, .clen = 24, }, { // #1 .key = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,}, .klen = 24, .plaintext = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,}, .plen = 16, .ciphertext = {0x96, 0x77, 0x8B, 0x25, 0xAE, 0x6C, 0xA4, 0x35, 0xF9, 0x2B, 0x5B, 0x97, 0xC0, 0x50, 0xAE, 0xD2, 0x46, 0x8A, 0xB8, 0xA1, 0x7A, 0xD8, 0x4E, 0x5D,}, .clen = 24, }, { // #2 .key = {0x00, 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,}, .klen = 32, .plaintext = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,}, .plen = 16, .ciphertext = {0x64, 0xE8, 0xC3, 0xF9, 0xCE, 0x0F, 0x5B, 0xA2, 0x63, 0xE9, 0x77, 0x79, 0x05, 0x81, 0x8A, 0x2A, 0x93, 0xC8, 0x19, 0x1E, 0x7D, 0x6E, 0x8A, 0xE7,}, .clen = 24, }, { // #3 .key = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,}, .klen = 24, .plaintext = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,}, .plen = 24, .ciphertext = {0x03, 0x1D, 0x33, 0x26, 0x4E, 0x15, 0xD3, 0x32, 0x68, 0xF2, 0x4E, 0xC2, 0x60, 0x74, 0x3E, 0xDC, 0xE1, 0xC6, 0xC7, 0xDD, 0xEE, 0x72, 0x5A, 0x93, 0x6B, 0xA8, 0x14, 0x91, 0x5C, 0x67, 0x62, 0xD2,}, .clen = 32, }, { // #4 .key = {0x00, 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,}, .klen = 32, .plaintext = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,}, .plen = 24, .ciphertext = {0xA8, 0xF9, 0xBC, 0x16, 0x12, 0xC6, 0x8B, 0x3F, 0xF6, 0xE6, 0xF4, 0xFB, 0xE3, 0x0E, 0x71, 0xE4, 0x76, 0x9C, 0x8B, 0x80, 0xA3, 0x2C, 0xB8, 0x95, 0x8C, 0xD5, 0xD1, 0x7D, 0x6B, 0x25, 0x4D, 0xA1,}, .clen = 32, }, { // #5 .key = {0x00, 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,}, .klen = 32, .plaintext = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,}, .plen = 32, .ciphertext = {0x28, 0xC9, 0xF4, 0x04, 0xC4, 0xB8, 0x10, 0xF4, 0xCB, 0xCC, 0xB3, 0x5C, 0xFB, 0x87, 0xF8, 0x26, 0x3F, 0x57, 0x86, 0xE2, 0xD8, 0x0E, 0xD3, 0x26, 0xCB, 0xC7, 0xF0, 0xE7, 0x1A, 0x99, 0xF4, 0x3B, 0xFB, 0x98, 0x8B, 0x9B, 0x7A, 0x02, 0xDD, 0x21,}, .clen = 40, } }; /* Test vectors (Padded Key Wrap Examples) from RFC 5649 */ static struct aes_test_vector aes_key_wrap_kwp_tv[] = { { // #0 .key = {0x58, 0x40, 0xdf, 0x6e, 0x29, 0xb0, 0x2a, 0xf1, 0xab, 0x49, 0x3b, 0x70, 0x5b, 0xf1, 0x6e, 0xa1, 0xae, 0x83, 0x38, 0xf4, 0xdc, 0xc1, 0x76, 0xa8,}, .klen = 24, .plaintext = {0xc3, 0x7b, 0x7e, 0x64, 0x92, 0x58, 0x43, 0x40, 0xbe, 0xd1, 0x22, 0x07, 0x80, 0x89, 0x41, 0x15, 0x50, 0x68, 0xf7, 0x38,}, .plen = 20, .ciphertext = {0x13, 0x8b, 0xde, 0xaa, 0x9b, 0x8f, 0xa7, 0xfc, 0x61, 0xf9, 0x77, 0x42, 0xe7, 0x22, 0x48, 0xee, 0x5a, 0xe6, 0xae, 0x53, 0x60, 0xd1, 0xae, 0x6a, 0x5f, 0x54, 0xf3, 0x73, 0xfa, 0x54, 0x3b, 0x6a,}, .clen = 32, }, { // #1 .key = {0x58, 0x40, 0xdf, 0x6e, 0x29, 0xb0, 0x2a, 0xf1, 0xab, 0x49, 0x3b, 0x70, 0x5b, 0xf1, 0x6e, 0xa1, 0xae, 0x83, 0x38, 0xf4, 0xdc, 0xc1, 0x76, 0xa8,}, .klen = 24, .plaintext = {0x46, 0x6f, 0x72, 0x50, 0x61, 0x73, 0x69,}, .plen = 7, .ciphertext = {0xaf, 0xbe, 0xb0, 0xf0, 0x7d, 0xfb, 0xf5, 0x41, 0x92, 0x00, 0xf2, 0xcc, 0xb5, 0x0b, 0xb2, 0x4f,}, .clen = 16, }, }; /** * NIST Special Publication 800-38B * https://csrc.nist.gov/Projects/Cryptographic-Algorithm-Validation-Program/ * CAVP-TESTING-BLOCK-CIPHER-MODES#CMAC **/ static struct mac_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 mac_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 mac_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, } }; /** * Derived CBC-MAC test vectors from AES-CBC test vectors * https://csrc.nist.gov/projects/cryptographic-algorithm-validation-program/ * block-ciphers#AES **/ static struct mac_test_vector aes128_cbc_mac_tv[] = { { // 0 .key = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, .klen = 16, .msg = { 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, .mlen = 16, .mac = { 0x3a,0xd7,0x8e,0x72,0x6c,0x1e,0xc0,0x2b,0x7e, 0xbf,0xe9,0x2b,0x23,0xd9,0xec,0x34 }, .tlen = 4, }, { // 1 .key = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, .klen = 16, .msg = { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, .mlen = 16, .mac = { 0xf8,0x07,0xc3,0xe7,0x98,0x5f,0xe0,0xf5,0xa5, 0x0e,0x2c,0xdb,0x25,0xc5,0x10,0x9e }, .tlen = 15, }, { // 2 .key = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, .klen = 16, .msg = { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff }, .mlen = 16, .mac = { 0x3f,0x5b,0x8c,0xc9,0xea,0x85,0x5a,0x0a,0xfa, 0x73,0x47,0xd2,0x3e,0x8d,0x66,0x4e }, .tlen = 10, }, { // 3 .key = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, .klen = 16, .msg = { 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, .mlen = 16, .mac = { 0x3a,0xd7,0x8e,0x72,0x6c,0x1e,0xc0,0x2b,0x7e, 0xbf,0xe9,0x2b,0x23,0xd9,0xec,0x34 }, .tlen = 4, .chunks_msg = { 7, 7, 2 }, .num_chunks_message = 3, }, { // 4 .key = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, .klen = 16, .msg = { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, .mlen = 16, .mac = { 0xf8,0x07,0xc3,0xe7,0x98,0x5f,0xe0,0xf5,0xa5, 0x0e,0x2c,0xdb,0x25,0xc5,0x10,0x9e }, .tlen = 15, .chunks_msg = { 5, 7, 4 }, .num_chunks_message = 3, }, { // 5 .key = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, .klen = 16, .msg = { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff }, .mlen = 16, .mac = { 0x3f,0x5b,0x8c,0xc9,0xea,0x85,0x5a,0x0a,0xfa, 0x73,0x47,0xd2,0x3e,0x8d,0x66,0x4e }, .tlen = 10, .chunks_msg = { 1, 2, 3, 4, 6 }, .num_chunks_message = 5, }, { // 6 .key = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, .klen = 16, .msg = { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff }, .mlen = 32, .mac = { 0x7e,0x75,0x51,0x49,0x15,0x3e,0x01,0x75,0xfb, 0x9e,0x26,0x6e,0xe8,0x04,0x4d,0x0d }, .tlen = 10, .chunks_msg = { 10, 2, 8, 10, 2 }, .num_chunks_message = 5, }, { // 7 .key = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, .klen = 16, .msg = { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff }, .mlen = 30, .mac = { 0x3d,0x40,0xa3,0x24,0x33,0x75,0xcc,0x40,0xb6, 0xa8,0x63,0xdd,0x05,0x8b,0xe6,0x04 }, .tlen = 10, .chunks_msg = { 10, 2, 8, 10 }, .num_chunks_message = 4, } }; /** * Derived CBC-MAC test vectors from AES-CBC test vectors * https://csrc.nist.gov/projects/cryptographic-algorithm-validation-program/ * block-ciphers#AES **/ static struct mac_test_vector aes192_cbc_mac_tv[] = { { // 0 .key = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00 }, .klen = 24, .msg = { 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, .mlen = 16, .mac = { 0x6c,0xd0,0x25,0x13,0xe8,0xd4,0xdc,0x98,0x6b, 0x4a,0xfe,0x08,0x7a,0x60,0xbd,0x0c }, .tlen = 4, }, { // 1 .key = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00 }, .klen = 24, .msg = { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, .mlen = 16, .mac = { 0x93,0xba,0xaf,0xfb,0x35,0xfb,0xe7,0x39,0xc1, 0x7c,0x6a,0xc2,0x2e,0xec,0xf1,0x8f }, .tlen = 15, }, { // 2 .key = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00 }, .klen = 24, .msg = { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff }, .mlen = 16, .mac = { 0xb1,0x3d,0xb4,0xda,0x1f,0x71,0x8b,0xc6,0x90, 0x47,0x97,0xc8,0x2b,0xcf,0x2d,0x32 }, .tlen = 10, }, { // 3 .key = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00 }, .klen = 24, .msg = { 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, .mlen = 16, .mac = { 0x6c,0xd0,0x25,0x13,0xe8,0xd4,0xdc,0x98,0x6b, 0x4a,0xfe,0x08,0x7a,0x60,0xbd,0x0c }, .tlen = 4, .chunks_msg = { 7, 7, 2 }, .num_chunks_message = 3, }, { // 4 .key = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00 }, .klen = 24, .msg = { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, .mlen = 16, .mac = { 0x93,0xba,0xaf,0xfb,0x35,0xfb,0xe7,0x39,0xc1, 0x7c,0x6a,0xc2,0x2e,0xec,0xf1,0x8f }, .tlen = 15, .chunks_msg = { 5, 7, 4 }, .num_chunks_message = 3, }, { // 5 .key = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00 }, .klen = 24, .msg = { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff }, .mlen = 16, .mac = { 0xb1,0x3d,0xb4,0xda,0x1f,0x71,0x8b,0xc6,0x90, 0x47,0x97,0xc8,0x2b,0xcf,0x2d,0x32 }, .tlen = 10, .chunks_msg = { 1, 2, 3, 4, 6 }, .num_chunks_message = 5, }, { // 6 .key = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00 }, .klen = 24, .msg = { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff }, .mlen = 32, .mac = { 0x60,0x4f,0x50,0xbc,0xdc,0x29,0x13,0xce,0xc7, 0xb5,0x94,0xcc,0xd3,0x3e,0x6b,0xaa }, .tlen = 10, .chunks_msg = { 10, 2, 8, 10, 2 }, .num_chunks_message = 5, }, { // 7 .key = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00 }, .klen = 24, .msg = { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff }, .mlen = 30, .mac = { 0x79,0x64,0xcf,0x7d,0x8f,0x2d,0xee,0x93,0x99, 0x5f,0x8e,0xb7,0xa7,0x3f,0xb0,0xab }, .tlen = 10, .chunks_msg = { 10, 2, 8, 10 }, .num_chunks_message = 4, } }; /** * Derived CBC-MAC test vectors from AES-CBC test vectors * https://csrc.nist.gov/projects/cryptographic-algorithm-validation-program/ * block-ciphers#AES **/ static struct mac_test_vector aes256_cbc_mac_tv[] = { { // 0 .key = { 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 }, .klen = 32, .msg = { 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, .mlen = 16, .mac = { 0xdd,0xc6,0xbf,0x79,0x0c,0x15,0x76,0x0d,0x8d, 0x9a,0xeb,0x6f,0x9a,0x75,0xfd,0x4e }, .tlen = 4, }, { // 1 .key = { 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 }, .klen = 32, .msg = { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, .mlen = 16, .mac = { 0x9b,0x58,0xdb,0xfd,0x77,0xfe,0x5a,0xca,0x9c, 0xfc,0x19,0x0c,0xd1,0xb8,0x2d,0x19 }, .tlen = 15, }, { // 2 .key = { 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 }, .klen = 32, .msg = { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff }, .mlen = 16, .mac = { 0xac,0xda,0xce,0x80,0x78,0xa3,0x2b,0x1a,0x18, 0x2b,0xfa,0x49,0x87,0xca,0x13,0x47 }, .tlen = 10, }, { // 3 .key = { 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 }, .klen = 32, .msg = { 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, .mlen = 16, .mac = { 0xdd,0xc6,0xbf,0x79,0x0c,0x15,0x76,0x0d,0x8d, 0x9a,0xeb,0x6f,0x9a,0x75,0xfd,0x4e }, .tlen = 4, .chunks_msg = { 7, 7, 2 }, .num_chunks_message = 3, }, { // 4 .key = { 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 }, .klen = 32, .msg = { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, .mlen = 16, .mac = { 0x9b,0x58,0xdb,0xfd,0x77,0xfe,0x5a,0xca,0x9c, 0xfc,0x19,0x0c,0xd1,0xb8,0x2d,0x19 }, .tlen = 15, .chunks_msg = { 5, 7, 4 }, .num_chunks_message = 3, }, { // 5 .key = { 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 }, .klen = 32, .msg = { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff }, .mlen = 16, .mac = { 0xac,0xda,0xce,0x80,0x78,0xa3,0x2b,0x1a,0x18, 0x2b,0xfa,0x49,0x87,0xca,0x13,0x47 }, .tlen = 10, .chunks_msg = { 1, 2, 3, 4, 6 }, .num_chunks_message = 5, }, { // 6 .key = { 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 }, .klen = 32, .msg = { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff }, .mlen = 32, .mac = { 0xc4,0xa5,0x8e,0xcb,0x0d,0x79,0x41,0xd2,0xa5, 0x90,0xc1,0xcb,0x95,0xd3,0x1d,0xfc }, .tlen = 10, .chunks_msg = { 10, 2, 8, 10, 2 }, .num_chunks_message = 5, }, { // 7 .key = { 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 }, .klen = 32, .msg = { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff }, .mlen = 30, .mac = { 0xca,0x87,0x7f,0x3d,0x45,0x0b,0x8a,0x09,0x0a, 0xad,0xf5,0xb9,0xab,0xe6,0x06,0xaf }, .tlen = 10, .chunks_msg = { 10, 2, 8, 10 }, .num_chunks_message = 4, } }; #define NUM_OF_PUBLISHED_TESTSUITES 10 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, NULL, 0}, }, { .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}, }, { .name = "AES_XTS", .tvcount = 5, .tv = aes_xts_tv, .size = AES_BLOCK_SIZE, .mech = {CKM_AES_XTS, &aes_iv, AES_IV_SIZE}, }, { .name = "AES_KEY_WRAP", .tvcount = 6, .tv = aes_key_wrap_tv, .size = AES_KEY_WRAP_BLOCK_SIZE, .mech = {CKM_AES_KEY_WRAP, NULL, 0}, }, { .name = "AES_KEY_WRAP_KWP", .tvcount = 2, .tv = aes_key_wrap_kwp_tv, .size = AES_KEY_WRAP_BLOCK_SIZE, .mech = {CKM_AES_KEY_WRAP_KWP, NULL, 0}, } }; #define NUM_OF_GENERATED_TESTSUITES 11 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)}, }, { .name = "AES_XTS", .mech = {CKM_AES_XTS, &aes_iv, AES_IV_SIZE}, }, { .name = "AES_KEY_WRAP", .mech = {CKM_AES_KEY_WRAP, NULL, 0}, }, { .name = "AES_KEY_WRAP (with IV)", .mech = {CKM_AES_KEY_WRAP, aes_iv, AES_KEY_WRAP_IV_SIZE}, }, { .name = "AES_KEY_WRAP_PAD", .mech = {CKM_AES_KEY_WRAP_PAD, NULL, 0}, }, { .name = "AES_KEY_WRAP_KWP", .mech = {CKM_AES_KEY_WRAP_KWP, NULL, 0}, }, { .name = "AES_KEY_WRAP_KWP (with IV)", .mech = {CKM_AES_KEY_WRAP_KWP, aes_iv, AES_KEY_WRAP_KWP_IV_SIZE}, }, { .name = "AES_KEY_WRAP_PKCS7", .mech = {CKM_AES_KEY_WRAP_PKCS7, NULL, 0}, }, }; #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_MAC_TESTSUITES 15 struct published_mac_test_suite_info published_mac_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}, }, { .name = "AES_MAC_GENERAL (128)", .tvcount = 8, .tv = aes128_cbc_mac_tv, .mech = {CKM_AES_MAC_GENERAL, 0, 0}, }, { .name = "AES_MAC_GENERAL (192)", .tvcount = 8, .tv = aes192_cbc_mac_tv, .mech = {CKM_AES_MAC_GENERAL, 0, 0}, }, { .name = "AES_MAC_GENERAL (256)", .tvcount = 8, .tv = aes256_cbc_mac_tv, .mech = {CKM_AES_MAC_GENERAL, 0, 0}, }, { .name = "AES_MAC (128)", .tvcount = 8, .tv = aes128_cbc_mac_tv, .mech = {CKM_AES_MAC, 0, 0}, }, { .name = "AES_MAC (192)", .tvcount = 8, .tv = aes192_cbc_mac_tv, .mech = {CKM_AES_MAC, 0, 0}, }, { .name = "AES_MAC (256)", .tvcount = 8, .tv = aes256_cbc_mac_tv, .mech = {CKM_AES_MAC, 0, 0}, }, }; opencryptoki-opencryptoki-451d99c/testcases/crypto/aes_func.c000066400000000000000000003132121520105705100245730ustar00rootroot00000000000000/* * 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 #include "pkcs11types.h" #include "regress.h" #include "aes.h" #include "common.c" #include "mechtable.h" #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 + 2 * AES_BLOCK_SIZE]; CK_BYTE decrypt[BIG_REQUEST + 2 * 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 pkey = true, but the slot doesn't support protected keys*/ if (pkey && !is_ep11_token(slot_id) && !is_cca_token(SLOT_ID)) { testsuite_skip(3, "pkey test option is true, but slot %u doesn't support protected keys", (unsigned int) slot_id); goto testcase_cleanup; } /** 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 (0x%x)", (unsigned int) slot_id, mech_to_str(tsuite->mech.mechanism), (unsigned int) tsuite->mech.mechanism); goto testcase_cleanup; } /* Skip tests if pkey = false, but the slot doesn't support CKM_AES_XTS */ if ((is_ep11_token(slot_id) || is_cca_token(slot_id)) && tsuite->mech.mechanism == CKM_AES_XTS && pkey == FALSE) { testcase_skip("Slot supports AES-XTS only for protected keys.\n"); goto testcase_cleanup; } /** iterate over test key sizes **/ for (i = 0; i < 3; i++) { if (tsuite->mech.mechanism == CKM_AES_XTS && key_lens[i] == 24) continue; testcase_begin("%s Encryption/Decryption with key len=%lu and pkey=%X.", tsuite->name, key_lens[i], pkey); /** set crypto mech **/ mech = tsuite->mech; /** generate key **/ mechkey = mech.mechanism == CKM_AES_XTS ? aes_xts_keygen : aes_keygen; rc = generate_AESKey(session, mech.mechanism == CKM_AES_XTS ? key_lens[i] * 2 : key_lens[i], !pkey, &mechkey, &h_key); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("AES key generation is not allowed by policy"); continue; } 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); switch (tsuite->mech.mechanism) { case CKM_AES_CBC_PAD: case CKM_AES_KEY_WRAP_PAD: case CKM_AES_KEY_WRAP_KWP: case CKM_AES_KEY_WRAP_PKCS7: orig_len -= 3; /* not a multiple of 8 bytes (force padding) */ break; } for (j = 0; j < orig_len; j++) original[j] = j % 255; /** 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=%lu, but found length=%lu\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 %lu 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 tests if pkey = true, but the slot doesn't support protected keys*/ if (pkey && !is_ep11_token(slot_id) && !is_cca_token(SLOT_ID)) { testsuite_skip(3, "pkey test option is true, but slot %u doesn't support protected keys", (unsigned int) slot_id); goto testcase_cleanup; } /** 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 (0x%x)", (unsigned int) slot_id, mech_to_str(tsuite->mech.mechanism), (unsigned int) tsuite->mech.mechanism); goto testcase_cleanup; } /* Skip tests if pkey = false, but the slot doesn't support CKM_AES_XTS */ if ((is_ep11_token(slot_id) || is_cca_token(slot_id)) && tsuite->mech.mechanism == CKM_AES_XTS && pkey == FALSE) { testcase_skip("Slot supports AES-XTS only for protected keys.\n"); goto testcase_cleanup; } switch (tsuite->mech.mechanism) { case CKM_AES_KEY_WRAP: case CKM_AES_KEY_WRAP_PAD: case CKM_AES_KEY_WRAP_KWP: case CKM_AES_KEY_WRAP_PKCS7: testcase_skip("Mechanism %s (0x%x) does not support multi-part " "operations.\n", mech_to_str(tsuite->mech.mechanism), (unsigned int) tsuite->mech.mechanism); goto testcase_cleanup; } /** iterate over key sizes **/ for (i = 0; i < 3; i++) { if (tsuite->mech.mechanism == CKM_AES_XTS && key_lens[i] == 24) continue; testcase_begin("%s Multipart Encryption/Decryption with " "key len=%lu and pkey=%X.", tsuite->name, key_lens[i], pkey); /** set crypto mech **/ mech = tsuite->mech; /** generate key **/ mechkey = mech.mechanism == CKM_AES_XTS ? aes_xts_keygen : aes_keygen; rc = generate_AESKey(session, mech.mechanism == CKM_AES_XTS ? key_lens[i] * 2 : key_lens[i], !pkey, &mechkey, &h_key); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("AES key generation is not allowed by policy"); continue; } 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; /** 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 or XTS, 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 && mech.mechanism != CKM_AES_XTS) { 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 or XTS 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 && mech.mechanism != CKM_AES_XTS) { 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=%lu, but found length=%lu\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 %lu 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 alloc_gcm_param(CK_GCM_PARAMS *gcm_param, CK_BYTE *pIV, CK_ULONG ulIVLen, CK_BYTE *pAAD, CK_ULONG ulAADLen) { gcm_param->pIv = malloc(ulIVLen); if (gcm_param->pIv == NULL) return CKR_HOST_MEMORY; gcm_param->ulIvLen = ulIVLen; memcpy(gcm_param->pIv, pIV, ulIVLen); gcm_param->ulIvBits = ulIVLen * 8; if (ulAADLen > 0) { gcm_param->pAAD = malloc(ulAADLen); if (gcm_param->pAAD == NULL) { free(gcm_param->pIv); gcm_param->pIv = NULL; return CKR_HOST_MEMORY; } memcpy(gcm_param->pAAD, pAAD, ulAADLen); } else { gcm_param->pAAD = NULL; } gcm_param->ulAADLen = ulAADLen; return CKR_OK; } void free_gcm_param(CK_GCM_PARAMS *gcm_param) { if (gcm_param == NULL) return; if (gcm_param->pIv != NULL) { memset(gcm_param->pIv, 0, gcm_param->ulIvLen); free(gcm_param->pIv); } gcm_param->pIv = NULL; gcm_param->ulIvLen = 0; if (gcm_param->pAAD != NULL) { memset(gcm_param->pAAD, 0, gcm_param->ulAADLen); free(gcm_param->pAAD); } gcm_param->pAAD = NULL; gcm_param->ulAADLen = 0; } 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 = { .mechanism = 0, .pParameter = NULL, .ulParameterLen = 0 }; 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; CK_AES_CTR_PARAMS ctr_param; /** begin testsuite **/ testsuite_begin("%s Encryption.", tsuite->name); testcase_rw_session(); testcase_user_login(); /* Skip tests if pkey = true, but the slot doesn't support protected keys*/ if (pkey && !is_ep11_token(slot_id) && !is_cca_token(SLOT_ID)) { testsuite_skip(tsuite->tvcount, "pkey test option is true, but slot %u doesn't support protected keys", (unsigned int) slot_id); goto testcase_cleanup; } /** 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 (0x%x)", (unsigned int) slot_id, mech_to_str(tsuite->mech.mechanism), (unsigned int) tsuite->mech.mechanism); goto testcase_cleanup; } /* Skip tests if pkey = false, but the slot doesn't support CKM_AES_XTS */ if ((is_ep11_token(slot_id) || is_cca_token(slot_id)) && tsuite->mech.mechanism == CKM_AES_XTS && pkey == FALSE) { testcase_skip("Slot supports AES-XTS only for protected keys.\n"); goto testcase_cleanup; } for (i = 0; i < tsuite->tvcount; i++) { testcase_begin("%s Encryption with published test vector %u and pkey=%X.", tsuite->name, i, pkey); /** get mech **/ mech = tsuite->mech; /** create key handle **/ rc = create_AESKey(session, !pkey, tsuite->tv[i].key, tsuite->tv[i].klen, mech.mechanism == CKM_AES_XTS ? CKK_AES_XTS : CKK_AES, &h_key); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("AES key import is not allowed by policy"); continue; } testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); goto error; } if (mech.mechanism == CKM_AES_GCM) { gcm_param = ((CK_GCM_PARAMS *) mech.pParameter); gcm_param->ulTagBits = tsuite->tv[i].taglen; rc = alloc_gcm_param(gcm_param, (CK_BYTE *)tsuite->tv[i].iv, tsuite->tv[i].ivlen, (CK_BYTE *) tsuite->tv[i].aad, tsuite->tv[i].aadlen); if (rc != CKR_OK) { testcase_error("alloc_gcm_param rc=%s", p11_get_ckr(rc)); goto error; } } else if (mech.mechanism == CKM_AES_XTS) { mech.pParameter = tsuite->tv[i].iv; mech.ulParameterLen = tsuite->tv[i].ivlen; } else if (mech.mechanism == CKM_AES_CTR) { memset(&ctr_param, 0, sizeof(ctr_param)); ctr_param.ulCounterBits = tsuite->tv[i].counterbits; memcpy(ctr_param.cb, tsuite->tv[i].counter, tsuite->tv[i].counterlen); mech.pParameter = &ctr_param; mech.ulParameterLen = sizeof(ctr_param); } /** 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; } if (mech.mechanism == CKM_AES_GCM) { /* * Zeroise and free the GCM parameters now to test that * Update/Final does not require access to the GCM parameters * anymore */ gcm_param = ((CK_GCM_PARAMS *) mech.pParameter); free_gcm_param(gcm_param); } 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=%lu, but found length=%lu\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 %u " "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: if (mech.mechanism == CKM_AES_GCM) { gcm_param = ((CK_GCM_PARAMS *) mech.pParameter); free_gcm_param(gcm_param); } 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 = { .mechanism = 0, .pParameter = NULL, .ulParameterLen = 0 }; 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; CK_AES_CTR_PARAMS ctr_param; testsuite_begin("%s Multipart Encryption.", tsuite->name); testcase_rw_session(); testcase_user_login(); /* Skip tests if pkey = true, but the slot doesn't support protected keys*/ if (pkey && !is_ep11_token(slot_id) && !is_cca_token(SLOT_ID)) { testsuite_skip(tsuite->tvcount, "pkey test option is true, but slot %u doesn't support protected keys", (unsigned int) slot_id); goto testcase_cleanup; } /** 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 (0x%x)", (unsigned int) slot_id, mech_to_str(tsuite->mech.mechanism), (unsigned int) tsuite->mech.mechanism); goto testcase_cleanup; } switch (tsuite->mech.mechanism) { case CKM_AES_KEY_WRAP: case CKM_AES_KEY_WRAP_PAD: case CKM_AES_KEY_WRAP_KWP: case CKM_AES_KEY_WRAP_PKCS7: testcase_skip("Mechanism %s (0x%x) does not support multi-part " "operations.\n", mech_to_str(tsuite->mech.mechanism), (unsigned int) tsuite->mech.mechanism); goto testcase_cleanup; } /* Skip tests if pkey = false, but the slot doesn't support CKM_AES_XTS */ if (is_ep11_token(slot_id) && tsuite->mech.mechanism == CKM_AES_XTS && pkey == FALSE) { testcase_skip("Slot supports AES-XTS only for protected keys.\n"); goto testcase_cleanup; } if (is_cca_token(slot_id) && tsuite->mech.mechanism == CKM_AES_XTS && pkey == FALSE) { testcase_skip("Slot supports AES-XTS only for protected keys.\n"); goto testcase_cleanup; } if (is_cca_token(slot_id) && tsuite->mech.mechanism == CKM_AES_GCM) { testcase_skip("Slot supports AES-GCM only in single-chunk mode.\n"); goto testcase_cleanup; } for (i = 0; i < tsuite->tvcount; i++) { testcase_begin("%s Multipart Encryption with published test " "vector %u and pkey=%X.", tsuite->name, i, pkey); /** get mech **/ mech = tsuite->mech; /** create key handle **/ rc = create_AESKey(session, !pkey, tsuite->tv[i].key, tsuite->tv[i].klen, mech.mechanism == CKM_AES_XTS ? CKK_AES_XTS : CKK_AES, &h_key); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("AES key import is not allowed by policy"); continue; } testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); goto error; } if (mech.mechanism == CKM_AES_GCM) { gcm_param = ((CK_GCM_PARAMS *) mech.pParameter); gcm_param->ulTagBits = tsuite->tv[i].taglen; rc = alloc_gcm_param(gcm_param, (CK_BYTE *)tsuite->tv[i].iv, tsuite->tv[i].ivlen, (CK_BYTE *) tsuite->tv[i].aad, tsuite->tv[i].aadlen); if (rc != CKR_OK) { testcase_error("alloc_gcm_param rc=%s", p11_get_ckr(rc)); goto error; } } else if (mech.mechanism == CKM_AES_XTS) { mech.pParameter = tsuite->tv[i].iv; mech.ulParameterLen = tsuite->tv[i].ivlen; } else if (mech.mechanism == CKM_AES_CTR) { memset(&ctr_param, 0, sizeof(ctr_param)); ctr_param.ulCounterBits = tsuite->tv[i].counterbits; memcpy(ctr_param.cb, tsuite->tv[i].counter, tsuite->tv[i].counterlen); mech.pParameter = &ctr_param; mech.ulParameterLen = sizeof(ctr_param); } /** 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; } if (mech.mechanism == CKM_AES_GCM) { /* * Zeroise and free the GCM parameters now to test that * Update/Final does not require access to the GCM parameters * anymore */ gcm_param = ((CK_GCM_PARAMS *) mech.pParameter); free_gcm_param(gcm_param); } /* 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=%lu, but found length=%lu" "\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 %u 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: if (mech.mechanism == CKM_AES_GCM) { gcm_param = ((CK_GCM_PARAMS *) mech.pParameter); free_gcm_param(gcm_param); } 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 = { .mechanism = 0, .pParameter = NULL, .ulParameterLen = 0 }; 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; CK_AES_CTR_PARAMS ctr_param; testsuite_begin("%s Decryption.", tsuite->name); testcase_rw_session(); testcase_user_login(); /* Skip tests if pkey = true, but the slot doesn't support protected keys*/ if (pkey && !is_ep11_token(slot_id) && !is_cca_token(SLOT_ID)) { testsuite_skip(tsuite->tvcount, "pkey test option is true, but slot %u doesn't support protected keys", (unsigned int) slot_id); goto testcase_cleanup; } /** 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 (0x%x)", (unsigned int) slot_id, mech_to_str(tsuite->mech.mechanism), (unsigned int) tsuite->mech.mechanism); goto testcase_cleanup; } /* Skip tests if pkey = false, but the slot doesn't support CKM_AES_XTS */ if (is_ep11_token(slot_id) && tsuite->mech.mechanism == CKM_AES_XTS && pkey == FALSE) { testcase_skip("Slot supports AES-XTS only for protected keys.\n"); goto testcase_cleanup; } if (is_cca_token(slot_id) && tsuite->mech.mechanism == CKM_AES_XTS && pkey == FALSE) { testcase_skip("Slot supports AES-XTS only for protected keys.\n"); goto testcase_cleanup; } for (i = 0; i < tsuite->tvcount; i++) { testcase_begin("%s Decryption with published test vector %u and pkey=%X.", tsuite->name, i, pkey); /** get mech **/ mech = tsuite->mech; /** create key handle **/ rc = create_AESKey(session, !pkey, tsuite->tv[i].key, tsuite->tv[i].klen, mech.mechanism == CKM_AES_XTS ? CKK_AES_XTS : CKK_AES, &h_key); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("AES key import is not allowed by policy"); continue; } testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); goto error; } if (mech.mechanism == CKM_AES_GCM) { gcm_param = ((CK_GCM_PARAMS *) mech.pParameter); gcm_param->ulTagBits = tsuite->tv[i].taglen; rc = alloc_gcm_param(gcm_param, (CK_BYTE *)tsuite->tv[i].iv, tsuite->tv[i].ivlen, (CK_BYTE *) tsuite->tv[i].aad, tsuite->tv[i].aadlen); if (rc != CKR_OK) { testcase_error("alloc_gcm_param rc=%s", p11_get_ckr(rc)); goto error; } } else if (mech.mechanism == CKM_AES_XTS) { mech.pParameter = tsuite->tv[i].iv; mech.ulParameterLen = tsuite->tv[i].ivlen; } else if (mech.mechanism == CKM_AES_CTR) { memset(&ctr_param, 0, sizeof(ctr_param)); ctr_param.ulCounterBits = tsuite->tv[i].counterbits; memcpy(ctr_param.cb, tsuite->tv[i].counter, tsuite->tv[i].counterlen); mech.pParameter = &ctr_param; mech.ulParameterLen = sizeof(ctr_param); } /** 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; } if (mech.mechanism == CKM_AES_GCM) { /* * Zeroise and free the GCM parameters now to test that * Update/Final does not require access to the GCM parameters * anymore */ gcm_param = ((CK_GCM_PARAMS *) mech.pParameter); free_gcm_param(gcm_param); } 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=%lu, but found length=%lu\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 %u " "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: if (mech.mechanism == CKM_AES_GCM) { gcm_param = ((CK_GCM_PARAMS *) mech.pParameter); free_gcm_param(gcm_param); } 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 = { .mechanism = 0, .pParameter = NULL, .ulParameterLen = 0 }; 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; CK_AES_CTR_PARAMS ctr_param; testsuite_begin("%s Multipart Decryption.", tsuite->name); testcase_rw_session(); testcase_user_login(); /* Skip tests if pkey = true, but the slot doesn't support protected keys*/ if (pkey && !is_ep11_token(slot_id) && !is_cca_token(SLOT_ID)) { testsuite_skip(tsuite->tvcount, "pkey test option is true, but slot %u doesn't support protected keys", (unsigned int) slot_id); goto testcase_cleanup; } /** 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 (0x%x)", (unsigned int) slot_id, mech_to_str(tsuite->mech.mechanism), (unsigned int) tsuite->mech.mechanism); goto testcase_cleanup; } switch (tsuite->mech.mechanism) { case CKM_AES_KEY_WRAP: case CKM_AES_KEY_WRAP_PAD: case CKM_AES_KEY_WRAP_KWP: case CKM_AES_KEY_WRAP_PKCS7: testcase_skip("Mechanism %s (0x%x) does not support multi-part " "operations.\n", mech_to_str(tsuite->mech.mechanism), (unsigned int) tsuite->mech.mechanism); goto testcase_cleanup; } /* Skip tests if pkey = false, but the slot doesn't support CKM_AES_XTS */ if (is_ep11_token(slot_id) && tsuite->mech.mechanism == CKM_AES_XTS && pkey == FALSE) { testcase_skip("Slot supports AES-XTS only for protected keys.\n"); goto testcase_cleanup; } if (is_cca_token(slot_id) && tsuite->mech.mechanism == CKM_AES_XTS && pkey == FALSE) { testcase_skip("Slot supports AES-XTS only for protected keys.\n"); goto testcase_cleanup; } if (is_cca_token(slot_id) && tsuite->mech.mechanism == CKM_AES_GCM) { testcase_skip("Slot supports AES-GCM only in single-chunk mode.\n"); goto testcase_cleanup; } for (i = 0; i < tsuite->tvcount; i++) { testcase_begin("%s Multipart Decryption with published test " "vector %u and pkey=%X.", tsuite->name, i, pkey); /** get mech **/ mech = tsuite->mech; /** create key handle **/ rc = create_AESKey(session, !pkey, tsuite->tv[i].key, tsuite->tv[i].klen, mech.mechanism == CKM_AES_XTS ? CKK_AES_XTS : CKK_AES, &h_key); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("AES key import is not allowed by policy"); continue; } 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->ulTagBits = tsuite->tv[i].taglen; rc = alloc_gcm_param(gcm_param, (CK_BYTE *)tsuite->tv[i].iv, tsuite->tv[i].ivlen, (CK_BYTE *) tsuite->tv[i].aad, tsuite->tv[i].aadlen); if (rc != CKR_OK) { testcase_error("alloc_gcm_param rc=%s", p11_get_ckr(rc)); goto error; } } else if (mech.mechanism == CKM_AES_XTS) { mech.pParameter = tsuite->tv[i].iv; mech.ulParameterLen = tsuite->tv[i].ivlen; } else if (mech.mechanism == CKM_AES_CTR) { memset(&ctr_param, 0, sizeof(ctr_param)); ctr_param.ulCounterBits = tsuite->tv[i].counterbits; memcpy(ctr_param.cb, tsuite->tv[i].counter, tsuite->tv[i].counterlen); mech.pParameter = &ctr_param; mech.ulParameterLen = sizeof(ctr_param); } /** 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; } if (mech.mechanism == CKM_AES_GCM) { /* * Zeroise and free the GCM parameters now to test that * Update/Final does not require access to the GCM parameters * anymore */ gcm_param = ((CK_GCM_PARAMS *) mech.pParameter); free_gcm_param(gcm_param); } /* 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=%lu, but found " "length=%lu\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 %u 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: if (mech.mechanism == CKM_AES_GCM) { gcm_param = ((CK_GCM_PARAMS *) mech.pParameter); free_gcm_param(gcm_param); } 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 + 2 * AES_BLOCK_SIZE]; CK_BYTE decrypt[BIG_REQUEST + 2 * 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; 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 tests if pkey = true, but the slot doesn't support protected keys*/ if (pkey && !is_ep11_token(slot_id) && !is_cca_token(SLOT_ID)) { testsuite_skip(3, "pkey test option is true, but slot %u doesn't support protected keys", (unsigned int) slot_id); goto testcase_cleanup; } /** 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 (0x%x)", (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 (0x%x)", (unsigned int) slot_id, mech_to_str(tsuite->mech.mechanism), (unsigned int) tsuite->mech.mechanism); goto testcase_cleanup; } /* Skip tests if pkey = false, but the slot doesn't support CKM_AES_XTS */ if ((is_ep11_token(slot_id) || is_cca_token(slot_id)) && tsuite->mech.mechanism == CKM_AES_XTS && pkey == FALSE) { testcase_skip("Slot supports AES-XTS only for protected keys.\n"); 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; if (tsuite->mech.mechanism == CKM_AES_XTS && key_lens[i] == 24) continue; testcase_begin("%s Wrap/Unwrap key test with keylength=%lu and pkey=%X.", tsuite->name, key_lens[i], pkey); /** set mechanisms **/ mech = tsuite->mech; mechkey = mech.mechanism == CKM_AES_XTS ? aes_xts_keygen : aes_keygen; key_type = mech.mechanism == CKM_AES_XTS ? CKK_AES_XTS : CKK_AES; /** 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 (must be extractable) **/ rc = generate_AESKey(session, mech.mechanism == CKM_AES_XTS ? key_lens[i] * 2 : key_lens[i], CK_TRUE, &mechkey, &h_key); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("AES key generation is not allowed by policy"); continue; } testcase_error("C_GenerateKey rc=%s", p11_get_ckr(rc)); goto error; } /** generate wrapping key **/ rc = generate_AESKey(session, mech.mechanism == CKM_AES_XTS ? key_lens[i] * 2 : key_lens[i], !pkey, &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 + 2 * AES_BLOCK_SIZE; decrypt_len = BIG_REQUEST + 2 * 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 + 2 * AES_BLOCK_SIZE]; CK_BYTE wrapped_data[BIG_REQUEST + 2 * 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_BBOOL extractable = !pkey; CK_BBOOL pkeyextractable = pkey; CK_ATTRIBUTE pub_tmpl[] = { {CKA_MODULUS_BITS, &bits, sizeof(bits)}, {CKA_PUBLIC_EXPONENT, &pub_exp, sizeof(pub_exp)}, }; CK_ULONG pub_tmpl_len = sizeof(pub_tmpl) / sizeof(CK_ATTRIBUTE); CK_ATTRIBUTE uw_tmpl[] = { {CKA_CLASS, &keyclass, sizeof(keyclass)}, {CKA_KEY_TYPE, &keytype, sizeof(keytype)}, }; CK_ATTRIBUTE key_gen_tmpl[] = { {CKA_EXTRACTABLE, &extractable, sizeof(CK_BBOOL)}, {CKA_VALUE_LEN, &key_size, sizeof(CK_ULONG)}, {CKA_IBM_PROTKEY_EXTRACTABLE, &pkeyextractable, sizeof(CK_BBOOL)}, }; CK_ULONG key_gen_tmpl_len = sizeof(key_gen_tmpl) / sizeof(CK_ATTRIBUTE); testsuite_begin("%s wrap/unwrap of RSA key.", tsuite->name); testcase_rw_session(); testcase_user_login(); /* Skip tests if pkey = true, but the slot doesn't support protected keys*/ if (pkey && !is_ep11_token(slot_id) && !is_cca_token(SLOT_ID)) { testsuite_skip(3, "pkey test option is true, but slot %u doesn't support protected keys", (unsigned int) slot_id); goto testcase_cleanup; } /** 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 (0x%x)", (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 (0x%x)", (unsigned int) slot_id, mech_to_str(CKM_RSA_PKCS), (unsigned int) CKM_RSA_PKCS); goto testcase_cleanup; } if (!mech_supported(slot_id, CKM_RSA_PKCS_KEY_PAIR_GEN)) { testsuite_skip(3, "Slot %u doesn't support CKM_RSA_PKCS_KEY_PAIR_GEN", (unsigned int) slot_id); goto testcase_cleanup; } if (!wrap_supported(slot_id, tsuite->mech)) { testsuite_skip(3, "Slot %u doesn't support wrapping with %s (0x%x)", (unsigned int) slot_id, mech_to_str(tsuite->mech.mechanism), (unsigned int) tsuite->mech.mechanism); goto testcase_cleanup; } rc = funcs->C_GetMechanismInfo(slot_id, CKM_RSA_PKCS_KEY_PAIR_GEN, &mech_info); if (rc != CKR_OK) { testcase_error("C_GetMechanismInfo rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } if (bits < mech_info.ulMinKeySize) bits = mech_info.ulMinKeySize; for (i = 0; i < 3; i++) { if (tsuite->mech.mechanism == CKM_AES_XTS && key_lens[i] == 24) continue; testcase_begin("%s wrap/unwrap of RSA key for key length=%lu and pkey=%X.", tsuite->name, key_lens[i], pkey); key_size = tsuite->mech.mechanism == CKM_AES_XTS ? key_lens[i] * 2 : key_lens[i]; /** first mechanism generate AES wrapping key **/ mech.mechanism = tsuite->mech.mechanism == CKM_AES_XTS ? CKM_AES_XTS_KEY_GEN : 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, pub_tmpl_len, NULL, 0, &publ_key, &priv_key); if (rc != CKR_OK) { if (is_rejected_by_policy(rc, session)) { testcase_skip("RSA key generation is not allowed by policy"); continue; } 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, key_gen_tmpl_len, &w_key); if (rc != CKR_OK) { if (is_rejected_by_policy(rc, session)) { testcase_skip("AES key generation is not allowed by policy"); continue; } 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: " "%lu vs %lu\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_ULONG pub_tmpl_len = sizeof(pub_tmpl) / sizeof(CK_ATTRIBUTE); CK_ATTRIBUTE key_gen_tmpl[] = { {CKA_VALUE_LEN, &key_size, sizeof(CK_ULONG)} }; CK_ULONG key_gen_tmpl_len = sizeof(key_gen_tmpl) / sizeof(CK_ATTRIBUTE); testsuite_begin("%s wrap/unwrap of RSA key.", tsuite->name); testcase_rw_session(); testcase_user_login(); /* Skip tests if pkey = true, but the slot doesn't support protected keys*/ if (pkey && !is_ep11_token(slot_id) && !is_cca_token(SLOT_ID)) { testsuite_skip(3, "pkey test option is true, but slot %u doesn't support protected keys", (unsigned int) slot_id); goto testcase_cleanup; } /** 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 (0x%x)", (unsigned int) slot_id, mech_to_str(tsuite->mech.mechanism), (unsigned int) tsuite->mech.mechanism); goto testcase_cleanup; } if (!mech_supported(slot_id, CKM_AES_KEY_GEN)) { testsuite_skip(3, "Slot %u doesn't support CKM_AES_KEY_GEN)", (unsigned int) slot_id); goto testcase_cleanup; } if (mech_supported_flags(slot_id, tsuite->mech.mechanism, CKF_WRAP) && !mech_supported(slot_id, CKM_AES_CBC_PAD)) { testsuite_skip(3, "Slot %u doesn't support CKM_AES_CBC_PAD)", (unsigned int) slot_id); goto testcase_cleanup; } if (!mech_supported(slot_id, CKM_RSA_PKCS_KEY_PAIR_GEN)) { testsuite_skip(3, "Slot %u doesn't support CKM_RSA_PKCS_KEY_PAIR_GEN", (unsigned int) slot_id); goto testcase_cleanup; } rc = funcs->C_GetMechanismInfo(slot_id, CKM_RSA_PKCS_KEY_PAIR_GEN, &mech_info); if (rc != CKR_OK) { testcase_error("C_GetMechanismInfo rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } if (bits < mech_info.ulMinKeySize) bits = mech_info.ulMinKeySize; for (i = 0; i < 3; i++) { testcase_begin("%s wrap/unwrap of RSA key for key length=%lu and pkey=%X.", tsuite->name, key_lens[i], pkey); 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, pub_tmpl_len, NULL, 0, &publ_key, &priv_key); if (rc != CKR_OK) { if (is_rejected_by_policy(rc, session)) { testcase_skip("RSA key generation is not allowed by policy"); continue; } 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, key_gen_tmpl_len, &w_key); if (rc != CKR_OK) { if (is_rejected_by_policy(rc, session)) { testcase_skip("AES key generation is not allowed by policy"); continue; } 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_ULONG pub_tmpl_len = sizeof(pub_tmpl) / sizeof(CK_ATTRIBUTE); 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)} }; CK_ULONG key_gen_tmpl_len = sizeof(key_gen_tmpl) / sizeof(CK_ATTRIBUTE); testsuite_begin("%s wrap/unwrap of RSA key.", tsuite->name); testcase_rw_session(); testcase_user_login(); /* Skip tests if pkey = true, but the slot doesn't support protected keys*/ if (pkey && !is_ep11_token(slot_id) && !is_cca_token(SLOT_ID)) { testsuite_skip(3, "pkey test option is true, but slot %u doesn't support protected keys", (unsigned int) slot_id); goto testcase_cleanup; } /** 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 (0x%x)", (unsigned int) slot_id, mech_to_str(tsuite->mech.mechanism), (unsigned int) tsuite->mech.mechanism); goto testcase_cleanup; } if (!mech_supported(slot_id, CKM_AES_KEY_GEN)) { testsuite_skip(3, "Slot %u doesn't support CKM_AES_KEY_GEN)", (unsigned int) slot_id); goto testcase_cleanup; } if (mech_supported_flags(slot_id, tsuite->mech.mechanism, CKF_UNWRAP) && !mech_supported(slot_id, CKM_AES_CBC_PAD)) { testsuite_skip(3, "Slot %u doesn't support CKM_AES_CBC_PAD)", (unsigned int) slot_id); goto testcase_cleanup; } if (!mech_supported(slot_id, CKM_RSA_PKCS_KEY_PAIR_GEN)) { testsuite_skip(3, "Slot %u doesn't support CKM_RSA_PKCS_KEY_PAIR_GEN", (unsigned int) slot_id); goto testcase_cleanup; } rc = funcs->C_GetMechanismInfo(slot_id, CKM_RSA_PKCS_KEY_PAIR_GEN, &mech_info); if (rc != CKR_OK) { testcase_error("C_GetMechanismInfo rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } if (bits < mech_info.ulMinKeySize) bits = mech_info.ulMinKeySize; for (i = 0; i < 3; i++) { testcase_begin("%s wrap/unwrap of RSA key for key length=%lu and pkey=%X.", tsuite->name, key_lens[i], pkey); 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, pub_tmpl_len, NULL, 0, &publ_key, &priv_key); if (rc != CKR_OK) { if (is_rejected_by_policy(rc, session)) { testcase_skip("RSA key generation is not allowed by policy"); continue; } 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, key_gen_tmpl_len, &w_key); if (rc != CKR_OK) { if (is_rejected_by_policy(rc, session)) { testcase_skip("AES key generation is not allowed by policy"); continue; } 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_SignVerifyMAC(struct published_mac_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, mac_len; testsuite_begin("%s Sign/Verify MAC.", tsuite->name); testcase_rw_session(); testcase_user_login(); /* Skip tests if pkey = true, but the slot doesn't support protected keys*/ if (pkey && !is_ep11_token(slot_id) && !is_cca_token(SLOT_ID)) { testsuite_skip(3, "pkey test option is true, but slot %u doesn't support protected keys", (unsigned int) slot_id); goto testcase_cleanup; } /** 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 (0x%x)", (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 MAC with published test vector %u and pkey=%X.", tsuite->name, i, pkey); /** create key handle **/ rc = create_AESKey(session, !pkey, tsuite->tv[i].key, tsuite->tv[i].klen, CKK_AES, &h_key); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("AES key import is not allowed by policy"); continue; } testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); goto error; } /** get mech **/ mech = tsuite->mech; switch (mech.mechanism) { case CKM_AES_CMAC_GENERAL: case CKM_AES_MAC_GENERAL: mac_param = tsuite->tv[i].tlen; mech.pParameter = &mac_param; mech.ulParameterLen = sizeof(mac_param); mac_len = mac_param; break; case CKM_AES_CMAC: case CKM_IBM_CMAC: mac_len = AES_BLOCK_SIZE; break; case CKM_AES_MAC: mac_len = AES_BLOCK_SIZE / 2; break; default: testcase_error("Invalid mechanism: %s", p11_get_ckm(&mechtable_funcs, mech.mechanism)); goto error; } /** initialize signing **/ rc = funcs->C_SignInit(session, &mech, h_key); if (rc != CKR_OK) { if (is_rejected_by_policy(rc, session)) { testcase_skip("C_SignInit with mech %s is not allowed by policy", mech_to_str(mech.mechanism)); goto error; } 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 || mech.mechanism == CKM_AES_MAC_GENERAL) && actual_len != tsuite->tv[i].tlen) { testcase_fail("signature length does not match test vector's " "signature length\nexpected length=%u, found " "length=%lu", tsuite->tv[i].tlen, actual_len); } else if (mech.mechanism != CKM_AES_CMAC_GENERAL && mech.mechanism != CKM_AES_MAC_GENERAL && actual_len != mac_len) { testcase_fail("signature length does not match test vector's " "signature length\nexpected length=%lu, found " "length=%lu", mac_len, actual_len); } else if (memcmp(actual, tsuite->tv[i].mac, tsuite->tv[i].tlen < mac_len ? tsuite->tv[i].tlen : mac_len)) { testcase_fail("signature does not match test vector's signature"); } else { testcase_pass("%s Sign/Verify MAC with test vector %u " "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 do_SetAttributeValuesPkey(void) { CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; CK_FLAGS flags; CK_ULONG user_pin_len; CK_SLOT_ID slot_id = SLOT_ID; CK_OBJECT_HANDLE h_key = CK_INVALID_HANDLE; CK_SESSION_HANDLE session; CK_MECHANISM keygen_mech = { CKM_AES_KEY_GEN, 0, 0 }; CK_RV rc; CK_BBOOL pkey_extr; CK_ATTRIBUTE tmpl[] = { {CKA_IBM_PROTKEY_EXTRACTABLE, &pkey_extr, sizeof(CK_BBOOL)}, }; CK_ULONG tmpl_len = sizeof(tmpl) / sizeof(CK_ATTRIBUTE); testsuite_begin("do_SetAttributeValuesPkey"); testcase_rw_session(); testcase_user_login(); /* Skip tests if the slot doesn't support protected keys*/ if (!is_ep11_token(slot_id) && !is_cca_token(slot_id)) { testsuite_skip(1, "Slot %u doesn't support protected keys", (unsigned int) slot_id); goto testcase_cleanup; } testcase_begin("Generate AES key and change CKA_IBM_PROTKEY_EXTRACTABLE"); testcase_new_assertion(); /* Generate a test key */ rc = generate_AESKey(session, 16, CK_FALSE, &keygen_mech, &h_key); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("AES key generation is not allowed by policy"); goto testcase_cleanup; } testcase_fail("generate_AESKey rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } /* Check value of CKA_IBM_PROTKEY_EXTRACTABLE */ rc = funcs->C_GetAttributeValue(session, h_key, tmpl, tmpl_len); if (rc != CKR_OK) { testcase_fail("C_GetAttributeValue rc = %s", p11_get_ckr(rc)); goto testcase_cleanup; } /* Change CKA_IBM_PROTKEY_EXTRACTABLE to false if it's true. This requires * token option PKEY_MODE = ENABLE4xxx. It cannot be changed from false * to true via C_SetAttributeValue. */ if (pkey_extr) { pkey_extr = CK_FALSE; rc = funcs->C_SetAttributeValue(session, h_key, tmpl, tmpl_len); if (rc != CKR_OK) { testcase_fail("C_SetAttributeValue rc = %s", p11_get_ckr(rc)); goto testcase_cleanup; } } /* Verify that the attempted change from false to true fails. The attribute * is false when using PKEY_MODE = DISABLED or DEFAULT. On older systems, * not supporting CKM_IBM_CPACF_WRAP, we get CKR_ATTRIBUTE_TYPE_INVALID * here.*/ if (!pkey_extr) { pkey_extr = CK_TRUE; rc = funcs->C_SetAttributeValue(session, h_key, tmpl, tmpl_len); if (rc != CKR_ATTRIBUTE_READ_ONLY) { testcase_fail("Expected CKR_ATTRIBUTE_READ_ONLY, trying to change CKA_IBM_PROTKEY_EXTRACTABLE to true."); goto testcase_cleanup; } } testcase_pass("Generate AES key and change CKA_IBM_PROTKEY_EXTRACTABLE"); testcase_cleanup: if (h_key != CK_INVALID_HANDLE) { rc = funcs->C_DestroyObject(session, h_key); if (rc != CKR_OK) testcase_error("C_DestroyObject rc=%s", p11_get_ckr(rc)); } testcase_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_EncryptDecryptAESPkey(void) { CK_ULONG keylen = 16; CK_BBOOL btrue = CK_TRUE; CK_BBOOL bfalse = CK_FALSE; CK_RV rc = CKR_OK; CK_MECHANISM keygen_mech = { CKM_AES_KEY_GEN, 0, 0 }; CK_MECHANISM encr_mech = { CKM_AES_ECB, 0, 0 }; CK_OBJECT_HANDLE h_key = CK_INVALID_HANDLE; CK_OBJECT_HANDLE h_key2[2] = {CK_INVALID_HANDLE, CK_INVALID_HANDLE}; CK_SESSION_HANDLE session; char label[100]; CK_ATTRIBUTE keygen_tmpl[] = { {CKA_TOKEN, &btrue, sizeof(CK_BBOOL)}, {CKA_LABEL, &label, 0}, {CKA_EXTRACTABLE, &bfalse, sizeof(CK_BBOOL)}, {CKA_VALUE_LEN, &keylen, sizeof(CK_ULONG)} }; CK_ULONG keygen_tmpl_len = sizeof(keygen_tmpl) / sizeof(CK_ATTRIBUTE); CK_ATTRIBUTE find_tmpl[] = { {CKA_LABEL, &label, 0}, }; CK_ULONG find_tmpl_len = sizeof(find_tmpl) / sizeof(CK_ATTRIBUTE); CK_ULONG count = 0; CK_BYTE input[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; CK_BYTE output[32]; CK_BYTE decrypted[32]; CK_ULONG outlen = sizeof(output), decrlen = sizeof(decrypted); CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; CK_FLAGS flags; CK_ULONG user_pin_len; CK_SLOT_ID slot_id = SLOT_ID; int i; testsuite_begin("do_EncryptDecryptAESPkey"); testcase_rw_session(); testcase_user_login(); /* Skip tests if the slot doesn't support protected keys*/ if (!is_ep11_token(slot_id) && !is_cca_token(slot_id)) { testsuite_skip(6, "Slot %u doesn't support protected keys", (unsigned int) slot_id); goto testcase_cleanup; } testcase_begin("Generate token key object and encrypt"); testcase_new_assertion(); /* Prepare a unique label name */ sprintf(label, "A test key for protected key support (pid: %u)", getpid()); keygen_tmpl[1].ulValueLen = strlen(label); find_tmpl[0].ulValueLen = strlen(label); /* Generate token object */ rc = funcs->C_GenerateKey(session, &keygen_mech, keygen_tmpl, keygen_tmpl_len, &h_key); if (rc != CKR_OK) { if (is_rejected_by_policy(rc, session)) { testcase_skip("AES key generation is not allowed by policy"); goto testcase_cleanup; } testcase_fail("C_GenerateKey rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } /* Encrypt some data with this key object */ rc = funcs->C_EncryptInit(session, &encr_mech, h_key); if (rc != CKR_OK) { testcase_fail("C_EncryptInit rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } memset(output, 0, sizeof(output)); rc = funcs->C_Encrypt(session, input, sizeof(input), output, &outlen); if (rc != CKR_OK) { testcase_fail("C_Encrypt rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } testcase_pass("Generate token key object and encrypt"); testcase_begin("Log out, close session, and login in again in new session"); testcase_new_assertion(); /* Log out and close session */ testcase_user_logout(); rc = funcs->C_CloseAllSessions(slot_id); if (rc != CKR_OK) { testcase_fail("C_CloseAllSessions rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } /* Log in again read/only, ok for just decrypt with an existing pkey */ testcase_rw_session(); testcase_user_login(); testcase_pass("Log out, close session, and login in again in new session"); testcase_begin("Retrieve the key from repository"); testcase_new_assertion(); /* Retrieve the key from repository */ rc = funcs->C_FindObjectsInit(session, find_tmpl, find_tmpl_len); if (rc != CKR_OK) { testcase_fail("C_FindObjectsInit rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } rc = funcs->C_FindObjects(session, h_key2, 2, &count); if (rc != CKR_OK) { testcase_fail("C_FindObjects rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } if (count == 0) { testcase_fail("Didn't find key with label '%s'in repository", label); goto testcase_cleanup; } else if (count > 1) { testcase_skip("Found %lu objs with label '%s', only expected one. " "Skipping this test.\n", count, label); rc = funcs->C_FindObjectsFinal(session); goto testcase_cleanup; } /* h_key2[0] points to the same object as h_key in our first session, * so invalidate h_key to avoid a double destroy obj later. */ h_key = CK_INVALID_HANDLE; rc = funcs->C_FindObjectsFinal(session); if (rc != CKR_OK) { testcase_fail("C_FindObjectsFinal rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } testcase_pass("Retrieve the key from repository"); testcase_begin("Decrypt encrypted data with retrieved token object"); testcase_new_assertion(); /* Decrypt encrypted data with the retrieved token object */ rc = funcs->C_DecryptInit(session, &encr_mech, h_key2[0]); if (rc != CKR_OK) { testcase_fail("C_DecryptInit rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } memset(decrypted, 0, sizeof(decrypted)); rc = funcs->C_Decrypt(session, output, sizeof(input), decrypted, &decrlen); if (rc != CKR_OK) { testcase_error("C_Decrypt rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } testcase_pass("Decrypt encrypted data with retrieved token object"); testcase_begin("Check if result correct"); testcase_new_assertion(); /* Check if result correct */ if (memcmp(input, decrypted, decrlen) != 0) { testcase_fail("Decrypted data incorrect"); goto testcase_cleanup; } testcase_pass("Check if result correct"); testcase_begin("Try to retrieve the protected key attribute"); testcase_new_assertion(); /* Try to retrieve the protected key attribute from token object*/ CK_BYTE pkey_buf[64]; CK_ATTRIBUTE extr_tmpl[] = { {CKA_IBM_OPAQUE_PKEY, &pkey_buf, sizeof(pkey_buf)}, }; CK_ULONG extr_tmpl_len = sizeof(extr_tmpl) / sizeof(CK_ATTRIBUTE); memset(&pkey_buf, 0, sizeof(pkey_buf)); rc = funcs->C_GetAttributeValue(session, h_key2[0], extr_tmpl, extr_tmpl_len); if (rc != CKR_ATTRIBUTE_SENSITIVE) { testcase_fail("C_GetAttributeValue rc = %s, expected CKR_ATTRIBUTE_SENSITIVE", p11_get_ckr(rc)); goto testcase_cleanup; } testcase_pass("Try to retrieve the protected key attribute"); testcase_cleanup: 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)); } for (i = 0; i < 2; i++) { if (h_key2[i] != CK_INVALID_HANDLE) { rc = funcs->C_DestroyObject(session, h_key2[i]); if (rc != CKR_OK) testcase_error("C_DestroyObject rc=%s", p11_get_ckr(rc)); } } 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; } /** * Special tests for protected key support. */ CK_RV aes_funcs_pkey(void) { CK_RV rv; rv = do_EncryptDecryptAESPkey(); rv += do_SetAttributeValuesPkey(); return rv; } CK_RV aes_funcs(void) { 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; } /* MAC test cases */ for (i = 0; i < NUM_OF_PUBLISHED_MAC_TESTSUITES; i++) { rv = do_SignVerifyMAC(&published_mac_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 options: combined_extract: %d, nostop: %d\n", combined_extract, no_stop); if (combined_extract) printf("\n--------------------------------------------------------\n" "Caution: combined_extract does only work on systems with\n" "control point 75 (XCP_CPB_ALLOW_COMBINED_EXTRACT)='on'.\n" "--------------------------------------------------------\n\n"); 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(); pkey = CK_FALSE; rv = aes_funcs(); #ifndef NO_PKEY if (is_ep11_token(SLOT_ID) || is_cca_token(SLOT_ID)) { pkey = CK_TRUE; rv += aes_funcs(); rv += aes_funcs_pkey(); } #endif testcase_print_result(); funcs->C_Finalize(NULL); return testcase_return(rv); } opencryptoki-opencryptoki-451d99c/testcases/crypto/crypto.mk000066400000000000000000000102401520105705100245100ustar00rootroot00000000000000noinst_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 testcases/crypto/ab_tests \ testcases/crypto/kyber_tests testcases/crypto/ibm_ml_dsa_tests \ testcases/crypto/ibm_ml_kem_tests \ testcases/crypto/ml_dsa_tests testcases/crypto/ml_kem_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/dilithium.h testcases/crypto/kyber.h \ testcases/crypto/ibm_ml_dsa.h testcases/crypto/ibm_ml_kem.h \ testcases/crypto/ml_dsa.h testcases/crypto/ml_kem.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_LDFLAGS = -lcrypto 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 testcases_crypto_ab_tests_CFLAGS = ${testcases_inc} testcases_crypto_ab_tests_LDADD = testcases/common/libcommon.la testcases_crypto_ab_tests_SOURCES = testcases/crypto/abfunc.c testcases_crypto_kyber_tests_CFLAGS = ${testcases_inc} testcases_crypto_kyber_tests_LDADD = testcases/common/libcommon.la testcases_crypto_kyber_tests_SOURCES = testcases/crypto/kyber_func.c testcases_crypto_ibm_ml_dsa_tests_CFLAGS = ${testcases_inc} testcases_crypto_ibm_ml_dsa_tests_LDADD = testcases/common/libcommon.la testcases_crypto_ibm_ml_dsa_tests_SOURCES = testcases/crypto/ibm_ml_dsa_func.c testcases_crypto_ibm_ml_kem_tests_CFLAGS = ${testcases_inc} testcases_crypto_ibm_ml_kem_tests_LDADD = testcases/common/libcommon.la testcases_crypto_ibm_ml_kem_tests_SOURCES = testcases/crypto/ibm_ml_kem_func.c testcases_crypto_ml_dsa_tests_CFLAGS = ${testcases_inc} testcases_crypto_ml_dsa_tests_LDADD = testcases/common/libcommon.la testcases_crypto_ml_dsa_tests_SOURCES = testcases/crypto/ml_dsa_func.c testcases_crypto_ml_kem_tests_CFLAGS = ${testcases_inc} testcases_crypto_ml_kem_tests_LDADD = testcases/common/libcommon.la testcases_crypto_ml_kem_tests_SOURCES = testcases/crypto/ml_kem_func.c opencryptoki-opencryptoki-451d99c/testcases/crypto/des.h000066400000000000000000000113401520105705100235650ustar00rootroot00000000000000/* * 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}, } }; opencryptoki-opencryptoki-451d99c/testcases/crypto/des3.h000066400000000000000000002122361520105705100236570ustar00rootroot00000000000000/* * 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 mac_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_mac_test_suite_info { const char *name; unsigned int tvcount; struct mac_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 mac_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 mac_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, } }; /** * Derived CBC-MAC test vectors from DES3-CBC test vectors * http://csrc.nist.gov/groups/STM/cavp/documents/des/tdesmmt.zip * TCBCMMT3.rsp **/ static struct mac_test_vector des3_cbc_mac_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, .msg = { 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, .mlen = 8, .mac = { 0x36,0x77,0x03,0x73}, .tlen = 4, }, { // 1 .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, .msg = { 0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00 }, .mlen = 8, .mac = { 0x97,0x6a,0x35,0x19,0xeb,0xcd}, .tlen = 6, }, { // 2 .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, .msg = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01 }, .mlen = 8, .mac = { 0xd2,0x36,0x82,0x9a,0x4c}, .tlen = 5, }, { // 3 .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, .msg = { 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, .mlen = 8, .mac = { 0x36,0x77,0x03,0x73}, .tlen = 4, .chunks_msg = { 2, 3, 3 }, .num_chunks_message = 3, }, { // 4 .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, .msg = { 0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00 }, .mlen = 8, .mac = { 0x97,0x6a,0x35,0x19,0xeb,0xcd}, .tlen = 6, .chunks_msg = { 1, 1, 6 }, .num_chunks_message = 3, }, { // 5 .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, .msg = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01 }, .mlen = 8, .mac = { 0xd2,0x36,0x82,0x9a,0x4c}, .tlen = 5, .chunks_msg = { 1, 2, 1, 2, 2 }, .num_chunks_message = 5, }, { // 6 .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, .msg = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x01 }, .mlen = 16, .mac = { 0xcd,0x02,0xf0,0xd2,0xb4}, .tlen = 5, .chunks_msg = { 5, 5, 1, 2, 3 }, .num_chunks_message = 5, }, { // 7 .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, .msg = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00, 0x00,0x00,0x00,0x00,0x01 }, .mlen = 14, .mac = { 0x59,0x45,0x53,0xd5,0x67}, .tlen = 5, .chunks_msg = { 7, 2, 1, 2, 2 }, .num_chunks_message = 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_MAC_TESTSUITES 7 struct published_mac_test_suite_info published_mac_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, }, { .name = "3DES_MAC_GENERAL", .tvcount = 8, .tv = des3_cbc_mac_tv, .mech = {CKM_DES3_MAC_GENERAL, 0, 0}, .key_type = CKK_DES3, }, { .name = "3DES_MAC", .tvcount = 8, .tv = des3_cbc_mac_tv, .mech = {CKM_DES3_MAC, 0, 0}, .key_type = CKK_DES3, } }; opencryptoki-opencryptoki-451d99c/testcases/crypto/des3_func.c000066400000000000000000001410731520105705100246650ustar00rootroot00000000000000/* * 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" #include "mechtable.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 (0x%x)", (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 %u", 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) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("DES3 key import is not allowed by policy"); continue; } 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=%lu, but found length=" "%lu\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 " "%u 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 (0x%x)", (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 %u.", 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) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("DES3 key import is not allowed by policy"); continue; } 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=%lu, but found length=%lu\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" " %u 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 (0x%x)", (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 %u.", 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) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("DES3 key import is not allowed by policy"); continue; } 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=" "%lu, but found length=%lu\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 %u " "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 (0x%x)", (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 %u.", 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) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("DES3 key import is not allowed by policy"); continue; } 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=%lu, but " "found length=%lu\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 %u 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 (0x%x)", (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=%lu, but found length=%lu\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 (0x%x)", (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=%lu, but " "found length=%lu\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 (0x%x)", (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 (0x%x)", (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=%lu, but found length=%lu\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_SignVerifyMAC(struct published_mac_test_suite_info *tsuite) { unsigned int i; int k; CK_SESSION_HANDLE session; CK_MECHANISM mech; CK_OBJECT_HANDLE h_key = CK_INVALID_HANDLE; CK_FLAGS flags; CK_RV rc = CKR_OK; CK_SLOT_ID slot_id = SLOT_ID; CK_ULONG user_pin_len; CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; CK_MAC_GENERAL_PARAMS mac_param; CK_ULONG ofs; CK_BYTE actual[MAX_KEY_SIZE]; CK_ULONG actual_len, mac_len; testsuite_begin("%s Sign/Verify MAC.", 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 (0x%x)", (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 MAC with published test vector %u.", 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) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("DES2/DES3 key import is not allowed by policy"); continue; } testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); goto error; } /** get mech **/ mech = tsuite->mech; switch (mech.mechanism) { case CKM_DES3_CMAC_GENERAL: case CKM_DES3_MAC_GENERAL: mac_param = tsuite->tv[i].tlen; mech.pParameter = &mac_param; mech.ulParameterLen = sizeof(mac_param); mac_len = mac_param; break; case CKM_DES3_CMAC: case CKM_IBM_CMAC: mac_len = DES3_BLOCK_SIZE; break; case CKM_DES3_MAC: mac_len = DES3_BLOCK_SIZE / 2; break; default: testcase_error("Invalid mechanism: %s", p11_get_ckm(&mechtable_funcs, mech.mechanism)); 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; } 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 || mech.mechanism == CKM_DES3_MAC_GENERAL) && actual_len != tsuite->tv[i].tlen) { testcase_fail("signature length does not match test vector's " "signature length\nexpected length=%u, found " "length=%lu", tsuite->tv[i].tlen, actual_len); } else if (mech.mechanism != CKM_DES3_CMAC_GENERAL && mech.mechanism != CKM_DES3_MAC_GENERAL && actual_len != mac_len) { testcase_fail("signature length does not match test vector's " "signature length\nexpected length=%lu, found " "length=%lu", mac_len, actual_len); } else if (memcmp(actual, tsuite->tv[i].mac, tsuite->tv[i].tlen < mac_len ? tsuite->tv[i].tlen : mac_len)) { testcase_fail("signature does not match test vector's signature"); } else { testcase_pass("%s Sign/Verify MAC with test vector %u " "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: if (h_key != CK_INVALID_HANDLE) rc = funcs->C_DestroyObject(session, h_key); if (rc != CKR_OK) testcase_error("C_DestroyObject rc=%s", p11_get_ckr(rc)); testcase_cleanup: testcase_close_session(); return rc; } CK_RV do_PBE(void) { CK_SESSION_HANDLE session; CK_OBJECT_HANDLE h_key = CK_INVALID_HANDLE; CK_FLAGS flags; CK_RV rc = CKR_OK; CK_SLOT_ID slot_id = SLOT_ID; CK_ULONG user_pin_len; CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; CK_BYTE iv[DES3_IV_SIZE]; CK_BYTE clear[BIG_REQUEST]; CK_BYTE encrypted[BIG_REQUEST]; CK_ULONG clear_len, encrypted_len; CK_PBE_PARAMS pbe_param; CK_MECHANISM mech = { CKM_PBE_SHA1_DES3_EDE_CBC, &pbe_param, sizeof(pbe_param) }; CK_MECHANISM enc_mech = { CKM_DES3_CBC, iv, sizeof(iv) }; testsuite_begin("PBE."); testcase_rw_session(); testcase_user_login(); /** skip tests if the slot doesn't support this mechanism **/ if (!mech_supported(slot_id, mech.mechanism)) { testsuite_skip(3, "Slot %u doesn't support %s (0x%x)", (unsigned int) slot_id, mech_to_str(mech.mechanism), (unsigned int) mech.mechanism); goto testcase_cleanup; } if (!mech_supported(slot_id, enc_mech.mechanism)) { testsuite_skip(3, "Slot %u doesn't support %s (0x%x)", (unsigned int) slot_id, mech_to_str(enc_mech.mechanism), (unsigned int) enc_mech.mechanism); goto testcase_cleanup; } testcase_begin("PBE with %s", mech_to_str(mech.mechanism)); testcase_new_assertion(); pbe_param.pInitVector = iv; pbe_param.pPassword = (CK_BYTE *)"Password"; pbe_param.ulPasswordLen = 4; pbe_param.pSalt = (CK_BYTE *)"Salt"; pbe_param.ulSaltLen = 4; pbe_param.ulIteration = 1000; rc = funcs->C_GenerateKey(session, &mech, NULL, 0, &h_key); if (rc != CKR_OK) { testcase_error("C_GenerateKey rc=%s", p11_get_ckr(rc)); goto error; } rc = funcs->C_EncryptInit(session, &enc_mech, h_key); if (rc != CKR_OK) { testcase_error("C_EncryptInit rc=%s", p11_get_ckr(rc)); goto error; } memset(clear, 0x55, sizeof(clear)); clear_len = sizeof(clear); memset(encrypted, 0x00, sizeof(encrypted)); encrypted_len = sizeof(encrypted); rc = funcs->C_Encrypt(session, clear, clear_len, encrypted, &encrypted_len); if (rc != CKR_OK) { testcase_error("C_Encrypt rc=%s", p11_get_ckr(rc)); goto error; } testcase_pass("PBE with %s" ,mech_to_str(mech.mechanism)); goto testcase_cleanup; error: if (h_key != CK_INVALID_HANDLE) rc = funcs->C_DestroyObject(session, h_key); if (rc != CKR_OK) testcase_error("C_DestroyObject rc=%s", p11_get_ckr(rc)); testcase_cleanup: testcase_close_session(); return rc; } CK_RV des3_funcs(void) { int i; 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; } /* MAC test cases */ for (i = 0; i < NUM_OF_PUBLISHED_MAC_TESTSUITES; i++) { rv = do_SignVerifyMAC(&published_mac_test_suites[i]); if (rv != CKR_OK && (!no_stop)) break; } /* CKM_PBE_SHA1_DES3_EDE_CBC */ rv = do_PBE(); 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(); rc = des3_funcs(); testcase_print_result(); funcs->C_Finalize(NULL); return testcase_return(rc); } opencryptoki-opencryptoki-451d99c/testcases/crypto/des_func.c000066400000000000000000001107201520105705100245750ustar00rootroot00000000000000/* * 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 (0x%x)", (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 " "%u.", 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) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("DES key import is not allowed by policy"); continue; } 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=%lu, but found" " length=%lu\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 %u " "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 (0x%x)", (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 %u.", 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) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("DES key import is not allowed by policy"); continue; } 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=%lu, " "but found length=%lu\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 %u 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 (0x%x)", (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 %u.", 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) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("DES key import is not allowed by policy"); continue; } 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=%lu, but found" " length=%lu\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 %u " "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 (0x%x)", (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 %u.", 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) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("DES key import is not allowed by policy"); continue; } 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=%lu, but " "found length=%lu\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 %u 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 (0x%x)", (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=%lu, " "but found length=%lu\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 (0x%x)", (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=%lu," " but found length=%lu\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 (0x%x)", (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 (0x%x)", (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=%lu, but found length=%lu" "\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(void) { 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(); rc = des_funcs(); testcase_print_result(); funcs->C_Finalize(NULL); return testcase_return(rc); } opencryptoki-opencryptoki-451d99c/testcases/crypto/dh_func.c000066400000000000000000000707751520105705100244340ustar00rootroot00000000000000/* * 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) { if (is_rejected_by_policy(rc, session)) { testcase_skip("DH key generation is not allowed by policy"); rc = CKR_OK; goto testcase_cleanup; } 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; } 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) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("DH key import is not allowed by policy"); rc = CKR_OK; goto testcase_cleanup; } 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) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("DH key import is not allowed by policy"); rc = CKR_OK; goto testcase_cleanup; } 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) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("DH key import is not allowed by policy"); rc = CKR_OK; goto testcase_cleanup; } 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) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("DH key import is not allowed by policy"); rc = CKR_OK; goto testcase_cleanup; } 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; } 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; } // 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; } 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 (extr1_tmpl[0].ulValueLen != extr2_tmpl[0].ulValueLen || memcmp(key1_value, key2_value, extr1_tmpl[0].ulValueLen) != 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; } // 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 do_EnDecapsulateDHKey(void) { 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 secret_key1 = CK_INVALID_HANDLE; CK_OBJECT_HANDLE secret_key2 = 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; CK_ULONG i; CK_BYTE clear[32]; CK_BYTE encrypted1[32]; CK_BYTE encrypted2[32]; CK_ULONG encrypted1_len = sizeof(encrypted1); CK_ULONG encrypted2_len = sizeof(encrypted2); CK_BBOOL ck_true = CK_TRUE; CK_BBOOL ck_false = CK_TRUE; CK_BYTE *cipher = NULL; CK_ULONG cipher_len = 0; 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 = 32; CK_OBJECT_CLASS secret_key_class = CKO_SECRET_KEY; CK_KEY_TYPE secret_key_type = CKK_AES; CK_UTF8CHAR secret_label[] = "An AES secret key object"; 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)}, {CKA_ENCAPSULATE, &ck_true, sizeof(ck_true)} }; 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, &ck_false, sizeof(ck_false)}, {CKA_DECAPSULATE, &ck_true, sizeof(ck_true)} }; 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}, {CKA_EXTRACTABLE, &ck_false, sizeof(ck_false)} }; testcase_begin("starting do_GenerateDeriveDHKey..."); testcase_rw_session(); testcase_user_login(); testcase_new_assertion(); /* 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, 6, priv_tmpl, 5, &publ_key, &priv_key); if (rc != CKR_OK) { if (is_rejected_by_policy(rc, session)) { testcase_skip("DH key generation is not allowed by policy"); rc = CKR_OK; goto testcase_cleanup; } testcase_fail("C_GenerateKeyPair #1: rc = %s", p11_get_ckr(rc)); goto testcase_cleanup; } testcase_pass("Successfully generated an DH key"); /* Testcase #2 - Now encapsulate/decapsulate the secrets... */ testcase_new_assertion(); /* Now, encapsulate an AES key using party A's public key */ mech.mechanism = CKM_DH_PKCS_DERIVE; mech.ulParameterLen = 0; mech.pParameter = NULL; rc = funcs3_2->C_EncapsulateKey(session, &mech, publ_key, secret_tmpl, 5, NULL, &cipher_len, NULL); if (rc != CKR_OK) { testcase_fail("C_EncapsulateKey #1: rc = %s", p11_get_ckr(rc)); goto testcase_cleanup; } cipher = calloc(cipher_len, sizeof(CK_BYTE)); if (cipher == NULL) { testcase_error("Can't allocate memory for %lu bytes.", cipher_len); rc = CKR_HOST_MEMORY; goto testcase_cleanup; } rc = funcs3_2->C_EncapsulateKey(session, &mech, publ_key, secret_tmpl, 5, cipher, &cipher_len, &secret_key1); if (rc != CKR_OK) { testcase_fail("C_EncapsulateKey #2: rc = %s", p11_get_ckr(rc)); goto testcase_cleanup; } /* Now, decapsulate an AES key using A's private key */ rc = funcs3_2->C_DecapsulateKey(session, &mech, priv_key, secret_tmpl, 5, cipher, cipher_len, &secret_key2); if (rc != CKR_OK) { testcase_fail("C_DecapsulateKey #1: rc = %s", p11_get_ckr(rc)); goto testcase_cleanup; } /* CHeck if the same keys were en/decapsulated */ for (i = 0; i < sizeof(clear); i++) clear[i] = i; mech.mechanism = CKM_AES_ECB; mech.ulParameterLen = 0; mech.pParameter = NULL; rc = funcs->C_EncryptInit(session, &mech, secret_key1); if (rc != CKR_OK) { testcase_error("C_EncryptInit secret_key1: rc = %s", p11_get_ckr(rc)); goto testcase_cleanup; } rc = funcs->C_Encrypt(session, clear, sizeof(clear), encrypted1, &encrypted1_len); if (rc != CKR_OK) { testcase_error("C_Encrypt secret_key1: rc = %s", p11_get_ckr(rc)); goto testcase_cleanup; } rc = funcs->C_EncryptInit(session, &mech, secret_key2); if (rc != CKR_OK) { testcase_error("C_EncryptInit secret_key2: rc = %s", p11_get_ckr(rc)); goto testcase_cleanup; } rc = funcs->C_Encrypt(session, clear, sizeof(clear), encrypted2, &encrypted2_len); if (rc != CKR_OK) { testcase_error("C_Encrypt secret_key2: rc = %s", p11_get_ckr(rc)); goto testcase_cleanup; } if (encrypted1_len != encrypted2_len || memcmp(encrypted1, encrypted2, encrypted1_len) != 0) { testcase_fail("ERROR: data mismatch"); goto testcase_cleanup; } testcase_pass("En/Decapsulate secrets"); testcase_cleanup: if (cipher) free(cipher); funcs->C_DestroyObject(session, publ_key); funcs->C_DestroyObject(session, priv_key); funcs->C_DestroyObject(session, secret_key1); funcs->C_DestroyObject(session, secret_key2); 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; } CK_RV dh_functions(void) { 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) rv = do_DeriveDHKey(TRUE); if (rv == CKR_OK && (mechinfo.flags & CKF_ENCAPSULATE) != 0 && (mechinfo.flags & CKF_DECAPSULATE) != 0) rv = do_EnDecapsulateDHKey(); } 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(); rv = dh_functions(); testcase_print_result(); funcs->C_Finalize(NULL); return testcase_return(rv); } opencryptoki-opencryptoki-451d99c/testcases/crypto/digest.h000066400000000000000000023204551520105705100243050ustar00rootroot00000000000000/* * 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 19 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}, }, { .name = "SHA3-224", .tvcount = 6, .tv = sha3_224_digest_test_vector, .mech = {CKM_SHA3_224, 0, 0}, }, { .name = "SHA3-256", .tvcount = 6, .tv = sha3_256_digest_test_vector, .mech = {CKM_SHA3_256, 0, 0}, }, { .name = "SHA3-384", .tvcount = 6, .tv = sha3_384_digest_test_vector, .mech = {CKM_SHA3_384, 0, 0}, }, { .name = "SHA3-512", .tvcount = 6, .tv = sha3_512_digest_test_vector, .mech = {CKM_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 SHA512/224: */ struct HMAC_TEST_VECTOR sha512_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 = {0xb2,0x44,0xba,0x01,0x30,0x7c,0x0e,0x7a,0x8c, 0xca,0xad,0x13,0xb1,0x06,0x7a,0x4c,0xf6,0xb9, 0x61,0xfe,0x0c,0x6a,0x20,0xbd,0xa3,0xd9,0x20, 0x39} }, { .key = {'J', 'e', 'f', 'e'}, .key_len = 4, .data = {"what do ya want for nothing?"}, .data_len = 28, .mac_len = 28, .mac = {0x4a,0x53,0x0b,0x31,0xa7,0x9e,0xbc,0xce,0x36, 0x91,0x65,0x46,0x31,0x7c,0x45,0xf2,0x47,0xd8, 0x32,0x41,0xdf,0xb8,0x18,0xfd,0x37,0x25,0x4b, 0xde} } }; /* * Test vectors for HMAC SHA512/256: */ struct HMAC_TEST_VECTOR sha512_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 = {0x9f,0x91,0x26,0xc3,0xd9,0xc3,0xc3,0x30,0xd7, 0x60,0x42,0x5c,0xa8,0xa2,0x17,0xe3,0x1f,0xea, 0xe3,0x1b,0xfe,0x70,0x19,0x6f,0xf8,0x16,0x42, 0xb8,0x68,0x40,0x2e,0xab} }, { .key = {'J', 'e', 'f', 'e'}, .key_len = 4, .data = {"what do ya want for nothing?"}, .data_len = 28, .mac_len = 32, .mac = {0x6d,0xf7,0xb2,0x46,0x30,0xd5,0xcc,0xb2,0xee, 0x33,0x54,0x07,0x08,0x1a,0x87,0x18,0x8c,0x22, 0x14,0x89,0x76,0x8f,0xa2,0x02,0x05,0x13,0xb2, 0xd5,0x93,0x35,0x94,0x56} } }; /* 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} } }; /* * Test vectors for HMAC SHA512/224: */ struct HMAC_TEST_VECTOR sha512_224_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 = {0xb2,0x44,0xba,0x01,0x30,0x7c,0x0e,0x7a,0x8c, 0xca,0xad,0x13,0xb1,0x06,0x7a,0x4c} }, { .key = {'J', 'e', 'f', 'e'}, .key_len = 4, .data = {"what do ya want for nothing?"}, .data_len = 28, .mac_len = 16, .mac = {0x4a,0x53,0x0b,0x31,0xa7,0x9e,0xbc,0xce,0x36, 0x91,0x65,0x46,0x31,0x7c,0x45,0xf2} } }; /* * Test vectors for HMAC SHA512/256: */ struct HMAC_TEST_VECTOR sha512_256_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 = {0x9f,0x91,0x26,0xc3,0xd9,0xc3,0xc3,0x30,0xd7, 0x60,0x42,0x5c,0xa8,0xa2,0x17,0xe3} }, { .key = {'J', 'e', 'f', 'e'}, .key_len = 4, .data = {"what do ya want for nothing?"}, .data_len = 28, .mac_len = 16, .mac = {0x6d,0xf7,0xb2,0x46,0x30,0xd5,0xcc,0xb2,0xee, 0x33,0x54,0x07,0x08,0x1a,0x87,0x18} } }; /* Test vectors for HMAC SHA3-224: */ struct HMAC_TEST_VECTOR sha3_224_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 = {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 = 10, .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 = 10, .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 = 10, .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 = 10, .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 = 10, .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_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 = {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 = 10, .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 = 10, .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 = 10, .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 = 10, .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 = 10, .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_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 = {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 = 10, .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 = 10, .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 = 10, .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 = 10, .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 = 10, .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_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 = {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 = 10, .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 = 10, .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 = 10, .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 = 10, .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 = 10, .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} } }; /* 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 28 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 = "SHA-512/224 HMAC", .tvcount = 2, .tv = sha512_224_hmac_test_vector, .mech = { CKM_SHA512_224_HMAC, 0, 0 }, }, { .name = "SHA-512/256 HMAC", .tvcount = 2, .tv = sha512_256_hmac_test_vector, .mech = { CKM_SHA512_256_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 = "SHA-512/224 HMAC General", .tvcount = 2, .tv = sha512_224_hmac_general_test_vector, .mech = { CKM_SHA512_224_HMAC_GENERAL,&sixteen,sizeof(CK_ULONG) }, }, { .name = "SHA-512/256 HMAC General", .tvcount = 2, .tv = sha512_256_hmac_general_test_vector, .mech = { CKM_SHA512_256_HMAC_GENERAL,&sixteen,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 }, }, { .name = "SHA3-224 HMAC", .tvcount = 6, .tv = sha3_224_hmac_test_vector, .mech = { CKM_SHA3_224_HMAC, 0, 0 }, }, { .name = "SHA3-256 HMAC", .tvcount = 6, .tv = sha3_256_hmac_test_vector, .mech = { CKM_SHA3_256_HMAC, 0, 0 }, }, { .name = "SHA3-384 HMAC", .tvcount = 6, .tv = sha3_384_hmac_test_vector, .mech = { CKM_SHA3_384_HMAC, 0, 0 }, }, { .name = "SHA3-512 HMAC", .tvcount = 6, .tv = sha3_512_hmac_test_vector, .mech = { CKM_SHA3_512_HMAC, 0, 0 }, }, { .name = "SHA3-224 HMAC General", .tvcount = 6, .tv = sha3_224_hmac_general_test_vector, .mech = { CKM_SHA3_224_HMAC_GENERAL, &ten, sizeof(CK_ULONG) }, }, { .name = "SHA3-256 HMAC General", .tvcount = 6, .tv = sha3_256_hmac_general_test_vector, .mech = { CKM_SHA3_256_HMAC_GENERAL, &ten, sizeof(CK_ULONG) }, }, { .name = "SHA3-384 HMAC General", .tvcount = 6, .tv = sha3_384_hmac_general_test_vector, .mech = { CKM_SHA3_384_HMAC_GENERAL, &ten, sizeof(CK_ULONG) }, }, { .name = "SHA3-512 HMAC General", .tvcount = 6, .tv = sha3_512_hmac_general_test_vector, .mech = { CKM_SHA3_512_HMAC_GENERAL, &ten, sizeof(CK_ULONG) }, }, }; opencryptoki-opencryptoki-451d99c/testcases/crypto/digest_func.c000066400000000000000000002045671520105705100253160ustar00rootroot00000000000000/* * 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" #include "mech_to_str.h" #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 %lu", 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 %u.", 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=%lu, found length=%lu.", 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 %u 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 %lu", 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 %u.", 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 " "%u 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 %lu", 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 %u.", 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, CKK_GENERIC_SECRET, key, key_len, &h_key); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("generic secret key generation is not allowed by policy"); continue; } 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) { if (is_rejected_by_policy(rc, session)) { testcase_skip("C_SignInit with mech %s is not allowed by policy", mech_to_str(mech.mechanism)); goto error; } 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=%lu, found length=%lu", 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 %u 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 %lu", 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 %u.", 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, CKK_GENERIC_SECRET, key, key_len, &h_key); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("generic secret key generation is not allowed by policy"); continue; } 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) { if (is_rejected_by_policy(rc, session)) { testcase_skip("C_VerifyInit with mech %s is not allowed by policy", mech_to_str(mech.mechanism)); goto error; } 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 %u 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 %lu", 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 %u.", 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, CKK_GENERIC_SECRET, key, key_len, &h_key); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("generic secret key generation is not allowed by policy"); continue; } 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=%lu, found length=%lu", 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 %u 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 %lu", 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 %u.", 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, CKK_GENERIC_SECRET, key, key_len, &h_key); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("generic secret key generation is not allowed by policy"); continue; } 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 %u 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 %lu", 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 %u.", 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, CKK_GENERIC_SECRET, key, key_len, &h_key); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("generic secret key generation is not allowed by policy"); continue; } 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=%lu, found length=%lu", 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 %u 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 %lu", 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 %u.", 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, CKK_GENERIC_SECRET, key, key_len, &h_key); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("generic secret key generation is not allowed by policy"); continue; } 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 %u 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 %lu", 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 %u.", 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 %lu is not supported in slot %lu", 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, CKK_GENERIC_SECRET, key, key_len, &h_key); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("generic secret key generation is not allowed by policy"); continue; } 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) { if (is_rejected_by_policy(rc, session)) { testcase_skip("C_SignInit with mech %s is not allowed by policy", mech_to_str(mech.mechanism)); goto error; } 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; } /** Initialize verification using C_VerifyInit **/ 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; } /** Initialize verification using C_VerifySignatureInit **/ rc = funcs3_2->C_VerifySignatureInit(session, &mech, h_key, actual, actual_len); if (rc != CKR_OK) { testcase_error("C_VerifySignatureInit rc=%s", p11_get_ckr(rc)); goto error; } /** do verification **/ rc = funcs3_2->C_VerifySignature(session, data, data_len); if (rc != CKR_OK) { testcase_error("C_VerifySignature 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=" "%lu, found length=%lu", 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 %u " "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 %lu", tsuite->name, slot_id); goto testcase_cleanup; } if (tsuite->mech.mechanism == CKM_MD2_HMAC || tsuite->mech.mechanism == CKM_MD2_HMAC_GENERAL || tsuite->mech.mechanism == CKM_MD5_HMAC || tsuite->mech.mechanism == CKM_MD5_HMAC_GENERAL) { testsuite_skip(tsuite->tvcount, "mechanism %s does not support multi-part sign", tsuite->name); 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 %u.", 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 %lu is not supported in slot %lu", 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, CKK_GENERIC_SECRET, key, key_len, &h_key); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("generic secret key generation is not allowed by policy"); continue; } 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; } } } else { rc = funcs->C_SignUpdate(session, NULL, 0); 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; } /** Initialize verification using C_VerifyInit **/ 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; } } } else { rc = funcs->C_VerifyUpdate(session, NULL, 0); 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; } /** Initialize verification using C_VerifySignatureInit **/ rc = funcs3_2->C_VerifySignatureInit(session, &mech, h_key, actual, actual_len); if (rc != CKR_OK) { testcase_error("C_VerifySignatureInit rc=%s", p11_get_ckr(rc)); goto error; } /** do verification **/ if (data_len > 0) { rc = funcs3_2->C_VerifySignatureUpdate(session, data, len1); if (rc != CKR_OK) { testcase_error("C_VerifySignatureUpdate rc=%s", p11_get_ckr(rc)); goto error; } if (len2) { rc = funcs3_2->C_VerifySignatureUpdate(session, data + len1, len2); if (rc != CKR_OK) { testcase_error("C_VerifySignatureUpdate rc=%s", p11_get_ckr(rc)); goto error; } } } else { rc = funcs3_2->C_VerifySignatureUpdate(session, NULL, 0); if (rc != CKR_OK) { testcase_error("C_VerifySignatureUpdate rc=%s", p11_get_ckr(rc)); goto error; } } rc = funcs3_2->C_VerifySignatureFinal(session); if (rc != CKR_OK) { testcase_error("C_VerifySignatureFinal 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=" "%lu, found length=%lu", 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 %u " "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; } static struct hmac_mech_info { CK_MECHANISM keygen_mech; CK_MECHANISM hmac_mech; CK_ULONG key_len; CK_RV exp_rc; } hmac_mechs[] = { { { CKM_GENERIC_SECRET_KEY_GEN, 0, 0 }, { CKM_SHA_1_HMAC, 0, 0 }, 20, CKR_OK }, { { CKM_SHA_1_KEY_GEN, 0, 0 }, { CKM_SHA_1_HMAC, 0, 0 }, 20, CKR_OK }, { { CKM_SHA224_KEY_GEN, 0, 0 }, { CKM_SHA224_HMAC, 0, 0 }, 28, CKR_OK }, { { CKM_SHA256_KEY_GEN, 0, 0 }, { CKM_SHA256_HMAC, 0, 0 }, 32, CKR_OK }, { { CKM_SHA384_KEY_GEN, 0, 0 }, { CKM_SHA384_HMAC, 0, 0 }, 48, CKR_OK }, { { CKM_SHA512_KEY_GEN, 0, 0 }, { CKM_SHA512_HMAC, 0, 0 }, 64, CKR_OK }, { { CKM_SHA512_224_KEY_GEN, 0, 0 }, { CKM_SHA512_224_HMAC, 0, 0 }, 28, CKR_OK }, { { CKM_SHA512_256_KEY_GEN, 0, 0 }, { CKM_SHA512_256_HMAC, 0, 0 }, 32, CKR_OK }, { { CKM_SHA3_224_KEY_GEN, 0, 0 }, { CKM_SHA3_224_HMAC, 0, 0 }, 28, CKR_OK }, { { CKM_SHA3_256_KEY_GEN, 0, 0 }, { CKM_SHA3_256_HMAC, 0, 0 }, 32, CKR_OK }, { { CKM_SHA3_384_KEY_GEN, 0, 0 }, { CKM_SHA3_384_HMAC, 0, 0 }, 48, CKR_OK }, { { CKM_SHA3_512_KEY_GEN, 0, 0 }, { CKM_SHA3_512_HMAC, 0, 0 }, 64, CKR_OK }, { { CKM_SHA_1_KEY_GEN, 0, 0 }, { CKM_SHA256_HMAC, 0, 0 }, 20, CKR_KEY_TYPE_INCONSISTENT }, }; /* This function tests generating a generic secret key to be used * with hmac sign and verify. */ CK_RV do_HMAC_SignVerify_WithGenKey(void) { 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_INVALID_HANDLE; CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; CK_ULONG user_pin_len; CK_ULONG i; /** begin test **/ testsuite_begin("do_HMAC_SignVerify_WithGenKey"); testcase_rw_session(); testcase_user_login(); for (i = 0; i < sizeof(hmac_mechs) / sizeof(struct hmac_mech_info); i++) { testcase_begin("Generate HMAC Key with %s (0x%lx) and Sign/Verify " "with %s (0x%lx).", mech_to_str(hmac_mechs[i].keygen_mech.mechanism), hmac_mechs[i].keygen_mech.mechanism, mech_to_str(hmac_mechs[i].hmac_mech.mechanism), hmac_mechs[i].hmac_mech.mechanism); rc = CKR_OK; /* 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, hmac_mechs[i].keygen_mech.mechanism)) { testcase_skip("mechanism %s (0x%lx) is not supported with slot %lu", mech_to_str(hmac_mechs[i].keygen_mech.mechanism), hmac_mechs[i].keygen_mech.mechanism, slot_id); goto error; } if (!mech_supported(SLOT_ID, hmac_mechs[i].hmac_mech.mechanism)) { testcase_skip("mechanism %s (0x%lx) is not supported with slot %lu", mech_to_str(hmac_mechs[i].hmac_mech.mechanism), hmac_mechs[i].hmac_mech.mechanism, slot_id); goto error; } /** clear buffers **/ memset(actual, 0, sizeof(actual)); /** get test vector info **/ actual_len = sizeof(actual); /** generate key object **/ rc = generate_SecretKey(session, hmac_mechs[i].key_len, &hmac_mechs[i].keygen_mech, &h_key); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("generic secret key generation is not allowed by " "policy"); goto error; } testcase_error("generate_SecretKey rc=%s", p11_get_ckr(rc)); goto error; } /** initialize signing **/ rc = funcs->C_SignInit(session, &hmac_mechs[i].hmac_mech, h_key); if (rc != hmac_mechs[i].exp_rc) { testcase_error("C_SignInit rc=%s (expected: %s)", p11_get_ckr(rc), p11_get_ckr(hmac_mechs[i].exp_rc)); goto error; } if (rc != CKR_OK) 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, &hmac_mechs[i].hmac_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("Generate HMAC Key with %s (0x%lx) and Sign/Verify " "with %s (0x%lx) passed.", mech_to_str(hmac_mechs[i].keygen_mech.mechanism), hmac_mechs[i].keygen_mech.mechanism, mech_to_str(hmac_mechs[i].hmac_mech.mechanism), hmac_mechs[i].hmac_mech.mechanism); error: if (h_key != CK_INVALID_HANDLE && funcs->C_DestroyObject(session, h_key) != CKR_OK) testcase_error("C_DestroyObject rc=%s.", p11_get_ckr(rc)); h_key = CK_INVALID_HANDLE; } 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 do_SHA_derive_key(void) { CK_MECHANISM secret_mech = { CKM_AES_KEY_GEN, 0, 0 }; CK_ULONG key_len; CK_SESSION_HANDLE session; CK_SLOT_ID slot_id = SLOT_ID; CK_ULONG flags; CK_RV rc; CK_OBJECT_HANDLE h_key = CK_INVALID_HANDLE; CK_OBJECT_HANDLE h_derived_key = CK_INVALID_HANDLE; CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; CK_ULONG user_pin_len; CK_OBJECT_CLASS class = CKO_SECRET_KEY; CK_KEY_TYPE key_type = CKK_GENERIC_SECRET; unsigned int i, k; CK_BBOOL true = CK_TRUE; CK_ATTRIBUTE key_gen_tmpl[] = { {CKA_EXTRACTABLE, &true, sizeof(CK_BBOOL)}, {CKA_VALUE_LEN, &key_len, sizeof(CK_ULONG)}, {CKA_DERIVE, &true, sizeof(CK_BBOOL)}, {CKA_IBM_USE_AS_DATA, &true, sizeof(CK_BBOOL)}, }; CK_ULONG key_gen_tmpl_len = sizeof(key_gen_tmpl) / sizeof(CK_ATTRIBUTE); CK_ATTRIBUTE derive_tmpl[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &key_type, sizeof(key_type)}, {CKA_VALUE_LEN, &key_len, sizeof(CK_ULONG)}, }; CK_ULONG derive_tmpl_len = sizeof(derive_tmpl) / sizeof(CK_ATTRIBUTE); CK_MECHANISM derive_mechs[13] = { { CKM_SHA1_KEY_DERIVATION, 0, 0 }, { CKM_SHA224_KEY_DERIVATION, 0, 0 }, { CKM_SHA256_KEY_DERIVATION, 0, 0 }, { CKM_SHA384_KEY_DERIVATION, 0, 0 }, { CKM_SHA512_KEY_DERIVATION, 0, 0 }, { CKM_SHA512_224_KEY_DERIVATION, 0, 0 }, { CKM_SHA512_256_KEY_DERIVATION, 0, 0 }, { CKM_SHA3_224_KEY_DERIVATION, 0, 0 }, { CKM_SHA3_256_KEY_DERIVATION, 0, 0 }, { CKM_SHA3_384_KEY_DERIVATION, 0, 0 }, { CKM_SHA3_512_KEY_DERIVATION, 0, 0 }, { CKM_SHAKE_128_KEY_DERIVATION, 0, 0 }, { CKM_SHAKE_256_KEY_DERIVATION, 0, 0 } }; struct { CK_KEY_TYPE keytype; CK_ULONG key_len; } attributes[5] = { { -1, 0 }, { CKK_GENERIC_SECRET, 0 }, { CKK_GENERIC_SECRET, 20 }, { CKK_DES3, 0 }, { CKK_AES, 16 }, }; testsuite_begin("do_SHA_derive_key"); testcase_rw_session(); testcase_user_login(); if (!mech_supported(SLOT_ID, secret_mech.mechanism)) { testsuite_skip(1, "mechanism %lu not supported with slot %lu", secret_mech.mechanism, slot_id); goto testcase_cleanup; } key_len = 32; rc = funcs->C_GenerateKey(session, &secret_mech, key_gen_tmpl, key_gen_tmpl_len, &h_key); if (rc != CKR_OK) { if (is_rejected_by_policy(rc, session)) { testsuite_skip(1, "AES key generation is not allowed by policy"); goto testcase_cleanup; } testcase_error("generate_SecretKey rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } for (i = 0; i < sizeof(derive_mechs) / sizeof(CK_MECHANISM); i++) { for (k = 0; k < sizeof(attributes) / sizeof(attributes[0]); k++) { key_type = attributes[k].keytype; key_len = attributes[k].key_len; /* SHA-1 can produce only 20 bytes, not sufficient for a 3DES key */ if (key_type == CKK_DES3 && derive_mechs[i].mechanism == CKM_SHA1_KEY_DERIVATION) continue; /* * SHAKE doesn't have a default digest size, so key type and/or * length must be specified */ if ((derive_mechs[i].mechanism == CKM_SHAKE_128_KEY_DERIVATION || derive_mechs[i].mechanism == CKM_SHAKE_256_KEY_DERIVATION) && (key_type == (CK_ULONG)-1 || (key_type == CKK_GENERIC_SECRET && key_len == 0))) continue; testcase_begin("Derive key with %s keytype=0x%lx, value_len=%lu", mech_to_str(derive_mechs[i].mechanism), key_type, key_len); if (!mech_supported(SLOT_ID, derive_mechs[i].mechanism)) { testcase_skip("mechanism %lu not supported with slot %lu", derive_mechs[i].mechanism, slot_id); continue; } if (key_type == (CK_ULONG)-1) derive_tmpl_len = 1; else if (key_len == 0) derive_tmpl_len = 2; else derive_tmpl_len = 3; rc = funcs->C_DeriveKey(session, &derive_mechs[i], h_key, derive_tmpl, derive_tmpl_len, &h_derived_key); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("key derivation is not allowed by policy"); continue; } testcase_new_assertion(); testcase_fail("Derive key with %s keytype=0x%lx, value_len=%lu: rc: %s", mech_to_str(derive_mechs[i].mechanism), key_type, key_len, p11_get_ckr(rc)); } else { testcase_new_assertion(); testcase_pass("Derive key with %s keytype=0x%lx, value_len=%lu", mech_to_str(derive_mechs[i].mechanism), key_type, key_len); } if (h_derived_key != CK_INVALID_HANDLE && (rc = funcs->C_DestroyObject(session, h_derived_key)) != CKR_OK) testcase_error("C_DestroyObject rc=%s.", p11_get_ckr(rc)); h_derived_key = CK_INVALID_HANDLE; } } if (h_key != CK_INVALID_HANDLE && (rc = funcs->C_DestroyObject(session, h_key)) != CKR_OK) testcase_error("C_DestroyObject rc=%s.", p11_get_ckr(rc)); if (h_derived_key != CK_INVALID_HANDLE && (rc = funcs->C_DestroyObject(session, h_derived_key)) != CKR_OK) testcase_error("C_DestroyObject rc=%s.", p11_get_ckr(rc)); testcase_cleanup: testcase_user_logout(); if ((rc = funcs->C_CloseAllSessions(slot_id)) != CKR_OK) testcase_error("C_CloseAllSessions rc=%s", p11_get_ckr(rc)); return rc; } CK_RV digest_funcs(void) { CK_RV rc; 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; } for (i = 0; i < NUM_OF_HMAC_TEST_SUITES; i++) { rc = do_SignVerify_HMAC_Update(&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 **/ 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(); rc = do_SHA_derive_key(); 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(); rv = digest_funcs(); testcase_print_result(); funcs->C_Finalize(NULL); return testcase_return(rv); } opencryptoki-opencryptoki-451d99c/testcases/crypto/dilithium.h000066400000000000000000043463771520105705100250330ustar00rootroot00000000000000/* * 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.xxx * * 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 keyform; 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[672]; CK_ULONG s2_len; CK_BYTE s2[768]; CK_ULONG t0_len; CK_BYTE t0[3584]; CK_ULONG t1_len; CK_BYTE t1[2560]; CK_BYTE pkcs8[8192]; CK_ULONG pkcs8_len; CK_BYTE spki[8192]; CK_ULONG spki_len; CK_ULONG msg_len; CK_BYTE msg[4096]; // adjust to max msg len CK_ULONG sig_len; CK_BYTE sig[4668]; }; /** * test vectors from: https://csrc.nist.gov/Projects/post-quantum-cryptography/round-2-submissions */ struct DILITHIUM_TEST_VECTOR dilithium_tv[] = { { .name = "Dilithium Round 2, Level 4 (6-5) KAT 0 (PKCS#8/SPKI)", .version = 0, .keyform = 0, .rho_len = 0, .seed_len = 0, .tr_len = 0, .s1_len = 0, .s2_len = 0, .t0_len = 0, .t1_len = 0, .pkcs8_len = 5652, .pkcs8 = { 0x30, 0x82, 0x16, 0x10, 0x02, 0x01, 0x00, 0x30, 0x0f, 0x06, 0x0b, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x02, 0x82, 0x0b, 0x01, 0x06, 0x05, 0x05, 0x00, 0x04, 0x82, 0x15, 0xf8, 0x30, 0x82, 0x15, 0xf4, 0x02, 0x01, 0x00, 0x03, 0x21, 0x00, 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, 0x03, 0x21, 0x00, 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, 0x03, 0x31, 0x00, 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, 0x03, 0x82, 0x01, 0xe1, 0x00, 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, 0x03, 0x82, 0x02, 0x41, 0x00, 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, 0x03, 0x82, 0x0a, 0x81, 0x00, 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, 0xa0, 0x82, 0x06, 0xc5, 0x03, 0x82, 0x06, 0xc1, 0x00, 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, }, .spki_len = 1798, .spki = { 0x30, 0x82, 0x07, 0x02, 0x30, 0x0f, 0x06, 0x0b, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x02, 0x82, 0x0b, 0x01, 0x06, 0x05, 0x05, 0x00, 0x03, 0x82, 0x06, 0xed, 0x00, 0x30, 0x82, 0x06, 0xe8, 0x03, 0x21, 0x00, 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, 0x03, 0x82, 0x06, 0xc1, 0x00, 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 Round 2, Level 4 (6-5) KAT 0", .version = 0, .keyform = CK_IBM_DILITHIUM_KEYFORM_ROUND2_65, .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 }, .pkcs8_len = 0, .spki_len = 0, .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 Round 2, Level 4 (6-5) KAT 1", .version = 0, .keyform = CK_IBM_DILITHIUM_KEYFORM_ROUND2_65, .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 }, .pkcs8_len = 0, .spki_len = 0, .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 Round 2, Level 4 (6-5) KAT 2", .version = 0, .keyform = CK_IBM_DILITHIUM_KEYFORM_ROUND2_65, .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 }, .pkcs8_len = 0, .spki_len = 0, .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 Round 2, Level 4 (6-5) KAT 3", .version = 0, .keyform = CK_IBM_DILITHIUM_KEYFORM_ROUND2_65, .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 }, .pkcs8_len = 0, .spki_len = 0, .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 }, }, { .name = "Dilithium Round 2, Level 5 (8-7) KAT 0 (PKCS#8/SPKI)", .version = 0, .keyform = 0, .rho_len = 0, .seed_len = 0, .tr_len = 0, .s1_len = 0, .s2_len = 0, .t0_len = 0, .t1_len = 0, .pkcs8_len = 7508, .pkcs8 = { 0x30, 0x82, 0x1D, 0x50, 0x02, 0x01, 0x00, 0x30, 0x0F, 0x06, 0x0B, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x02, 0x82, 0x0B, 0x01, 0x08, 0x07, 0x05, 0x00, 0x04, 0x82, 0x1D, 0x38, 0x30, 0x82, 0x1D, 0x34, 0x02, 0x01, 0x00, 0x03, 0x21, 0x00, 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, 0x03, 0x21, 0x00, 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, 0x03, 0x31, 0x00, 0x89, 0xDB, 0xBF, 0xC3, 0x69, 0x33, 0x5D, 0x8F, 0x70, 0xE7, 0xBC, 0xB4, 0xD1, 0x66, 0xD4, 0xBD, 0xD0, 0xD8, 0x36, 0xE4, 0x5D, 0xE9, 0x37, 0x92, 0xED, 0xC4, 0x26, 0x10, 0x6F, 0xBF, 0x5A, 0xF2, 0x7C, 0x68, 0xA9, 0x50, 0xB4, 0xA1, 0xA6, 0x42, 0x28, 0x01, 0xC6, 0xF2, 0xAC, 0xC3, 0xA9, 0xFA, 0x03, 0x82, 0x02, 0xA1, 0x00, 0x91, 0xB4, 0x2D, 0xA1, 0x38, 0x24, 0x08, 0x19, 0x24, 0x1A, 0x30, 0x4D, 0x40, 0xA8, 0x6C, 0xD8, 0x04, 0x6A, 0x03, 0x28, 0x04, 0x41, 0x38, 0x22, 0x22, 0x39, 0x0A, 0xE2, 0x80, 0x0D, 0x12, 0x49, 0x91, 0x24, 0xB4, 0x50, 0x93, 0x46, 0x89, 0xD1, 0x30, 0x4C, 0x04, 0x20, 0x24, 0x20, 0x20, 0x31, 0x59, 0x92, 0x41, 0xC3, 0x26, 0x61, 0x14, 0x47, 0x32, 0xDB, 0x12, 0x69, 0x63, 0x46, 0x01, 0x10, 0x93, 0x91, 0x10, 0x39, 0x81, 0x5B, 0x26, 0x71, 0x40, 0xB0, 0x01, 0x03, 0x41, 0x48, 0x04, 0x19, 0x09, 0x13, 0xB4, 0x91, 0x0C, 0x46, 0x08, 0xD4, 0x08, 0x09, 0x0C, 0x99, 0x04, 0x00, 0x35, 0x61, 0x13, 0x14, 0x4C, 0x19, 0x41, 0x28, 0x1C, 0x16, 0x80, 0x88, 0xA0, 0x29, 0x1A, 0x30, 0x02, 0x10, 0x80, 0x4C, 0x13, 0x43, 0x25, 0x04, 0x08, 0x81, 0x20, 0x43, 0x70, 0x14, 0x11, 0x6A, 0x99, 0x00, 0x40, 0x48, 0x82, 0x31, 0x12, 0x42, 0x20, 0x48, 0x06, 0x0D, 0xE2, 0xA2, 0x0C, 0x82, 0xB0, 0x28, 0xE2, 0x36, 0x10, 0x49, 0x16, 0x84, 0xD8, 0x04, 0x4C, 0x51, 0xB8, 0x68, 0xC2, 0x84, 0x90, 0x9B, 0x10, 0x31, 0x21, 0x49, 0x32, 0x94, 0x20, 0x0D, 0x04, 0x41, 0x24, 0xCB, 0xA4, 0x6D, 0x1A, 0x82, 0x61, 0x08, 0x40, 0x8E, 0xA4, 0x00, 0x44, 0x93, 0x92, 0x91, 0x8C, 0x30, 0x62, 0x60, 0xB2, 0x90, 0x58, 0x40, 0x62, 0x11, 0x97, 0x31, 0x21, 0x11, 0x81, 0x0C, 0x28, 0x88, 0x09, 0x07, 0x42, 0x88, 0x40, 0x6C, 0xC0, 0x96, 0x28, 0x81, 0x28, 0x8A, 0xC0, 0x12, 0x0C, 0x93, 0x48, 0x4C, 0x89, 0x82, 0x25, 0xD8, 0x00, 0x22, 0x24, 0x45, 0x41, 0x1B, 0x95, 0x2C, 0xA0, 0x92, 0x61, 0x84, 0xA2, 0x70, 0x59, 0x86, 0x10, 0x0B, 0x87, 0x08, 0x10, 0x98, 0x61, 0xD3, 0x40, 0x0D, 0x40, 0xB0, 0x8D, 0x09, 0x05, 0x71, 0x60, 0x84, 0x70, 0x18, 0x80, 0x61, 0x1A, 0x16, 0x2E, 0x63, 0x32, 0x06, 0x80, 0x80, 0x88, 0x50, 0xC6, 0x8C, 0x00, 0x10, 0x24, 0xC1, 0x00, 0x26, 0x94, 0x90, 0x48, 0x44, 0xB6, 0x29, 0x1A, 0x35, 0x48, 0xD3, 0xB0, 0x91, 0x21, 0xA4, 0x08, 0x11, 0x34, 0x32, 0x03, 0x01, 0x05, 0x21, 0x32, 0x46, 0x1B, 0x31, 0x31, 0x1B, 0x86, 0x0C, 0x1A, 0x28, 0x0D, 0xD1, 0x08, 0x28, 0x8B, 0xA8, 0x0D, 0x98, 0x90, 0x05, 0xD0, 0xA8, 0x29, 0x83, 0x48, 0x71, 0x03, 0x33, 0x80, 0x24, 0x90, 0x68, 0xD1, 0xA0, 0x2C, 0x23, 0x10, 0x4D, 0x12, 0x95, 0x11, 0xE4, 0x14, 0x21, 0x14, 0x39, 0x4E, 0x12, 0x01, 0x70, 0x0C, 0x25, 0x71, 0x24, 0x83, 0x89, 0x54, 0x30, 0x06, 0x11, 0x90, 0x45, 0x12, 0x03, 0x04, 0x59, 0xB0, 0x4C, 0x20, 0x36, 0x8A, 0x19, 0x30, 0x72, 0x98, 0x94, 0x4C, 0x14, 0x81, 0x40, 0xA2, 0xC6, 0x84, 0xCB, 0xA2, 0x48, 0x0C, 0xC1, 0x2D, 0x8A, 0xC4, 0x05, 0x42, 0x94, 0x45, 0x5B, 0xB4, 0x08, 0xDB, 0x18, 0x24, 0x88, 0x20, 0x90, 0x1B, 0xC3, 0x50, 0xA1, 0x96, 0x4D, 0x0B, 0x31, 0x6D, 0x93, 0x26, 0x46, 0x00, 0x35, 0x52, 0x01, 0x13, 0x42, 0xDA, 0x46, 0x6A, 0x1A, 0x34, 0x01, 0x40, 0x92, 0x41, 0xC0, 0x08, 0x66, 0xE3, 0x94, 0x01, 0x63, 0x28, 0x69, 0x0C, 0x25, 0x31, 0x0B, 0x21, 0x24, 0x43, 0xA2, 0x30, 0xD3, 0x22, 0x44, 0xCB, 0x36, 0x71, 0x02, 0x02, 0x42, 0x1A, 0xC1, 0x2C, 0x20, 0x23, 0x80, 0x8B, 0xA8, 0x85, 0x88, 0x08, 0x4A, 0x94, 0x10, 0x48, 0x18, 0x81, 0x29, 0xE2, 0xB4, 0x4C, 0x89, 0x88, 0x51, 0xC9, 0x06, 0x09, 0xD3, 0x96, 0x71, 0x54, 0xB0, 0x91, 0x53, 0x86, 0x04, 0x53, 0xC4, 0x44, 0x81, 0x98, 0x11, 0x88, 0x20, 0x04, 0xA0, 0x16, 0x0A, 0x49, 0xA0, 0x10, 0x1A, 0x17, 0x44, 0x21, 0x26, 0x66, 0xE0, 0xC0, 0x09, 0x59, 0x90, 0x8C, 0x93, 0x10, 0x49, 0x00, 0x85, 0x65, 0x4C, 0xC6, 0x0D, 0x00, 0x18, 0x30, 0x1B, 0x12, 0x6E, 0x10, 0x02, 0x45, 0xA2, 0x12, 0x49, 0x22, 0xC8, 0x20, 0x03, 0xC5, 0x48, 0x12, 0x04, 0x52, 0xA1, 0x88, 0x25, 0x40, 0xB2, 0x4D, 0x4B, 0x38, 0x28, 0x23, 0xB2, 0x64, 0xC2, 0x38, 0x90, 0x09, 0x46, 0x92, 0x0C, 0x90, 0x0D, 0x04, 0x06, 0x0C, 0x4C, 0x16, 0x2D, 0x08, 0x10, 0x49, 0x20, 0x47, 0x65, 0x50, 0x28, 0x29, 0x1A, 0x88, 0x80, 0x40, 0x30, 0x6D, 0x88, 0x36, 0x70, 0x63, 0x98, 0x71, 0x99, 0x96, 0x2C, 0x1B, 0x91, 0x61, 0x61, 0x40, 0x06, 0x13, 0x35, 0x04, 0x09, 0x08, 0x8E, 0x54, 0xB8, 0x44, 0x81, 0x30, 0x08, 0xC8, 0x10, 0x2C, 0x5A, 0xB0, 0x04, 0x42, 0x46, 0x61, 0x20, 0x03, 0x88, 0x91, 0xA0, 0x91, 0x81, 0x10, 0x4D, 0x12, 0xB7, 0x81, 0x20, 0x42, 0x02, 0x54, 0x94, 0x24, 0x59, 0xC4, 0x25, 0x8C, 0x44, 0x70, 0xE3, 0x32, 0x8E, 0x9A, 0x02, 0x60, 0xE4, 0xA6, 0x21, 0x4A, 0xB2, 0x85, 0x93, 0x36, 0x20, 0x03, 0x82, 0x03, 0x01, 0x00, 0x01, 0x05, 0x32, 0x11, 0x44, 0x66, 0xE2, 0x06, 0x40, 0x14, 0x49, 0x6C, 0x0B, 0x86, 0x80, 0x02, 0x47, 0x26, 0xD2, 0xB2, 0x25, 0x58, 0x48, 0x0E, 0x58, 0x44, 0x11, 0xD1, 0x44, 0x50, 0x51, 0xB8, 0x81, 0xC4, 0xA0, 0x48, 0x10, 0xC9, 0x50, 0x08, 0x98, 0x88, 0xD8, 0x28, 0x2A, 0x52, 0xC0, 0x4D, 0xD1, 0x38, 0x12, 0xD8, 0x46, 0x89, 0x00, 0x94, 0x00, 0xDA, 0xC4, 0x45, 0x9B, 0x44, 0x6E, 0x0B, 0x44, 0x0C, 0xC0, 0xC0, 0x01, 0x20, 0xC1, 0x0C, 0xC0, 0x04, 0x4C, 0x08, 0x24, 0x21, 0x23, 0xC7, 0x65, 0x03, 0xA0, 0x80, 0x91, 0xC2, 0x50, 0x21, 0x10, 0x31, 0x99, 0x36, 0x00, 0x64, 0x28, 0x70, 0x81, 0x38, 0x05, 0x4A, 0x18, 0x80, 0x1C, 0x89, 0x24, 0x08, 0x95, 0x49, 0x24, 0x39, 0x40, 0x24, 0x15, 0x22, 0xD9, 0x32, 0x90, 0x23, 0x24, 0x71, 0xC4, 0x46, 0x50, 0xCB, 0x86, 0x65, 0xE4, 0x94, 0x8C, 0x42, 0x04, 0x82, 0x8A, 0x86, 0x71, 0x13, 0xA3, 0x00, 0xDB, 0x44, 0x04, 0x23, 0x82, 0x10, 0x23, 0x46, 0x26, 0x0B, 0x08, 0x08, 0x60, 0x16, 0x11, 0xA4, 0xB6, 0x24, 0xE1, 0x32, 0x69, 0x04, 0x17, 0x86, 0xE3, 0x84, 0x2C, 0x9C, 0x32, 0x41, 0x92, 0xC8, 0x61, 0x5A, 0x32, 0x26, 0x24, 0xC3, 0x29, 0x5A, 0xC8, 0x05, 0x0A, 0x06, 0x8E, 0xE1, 0x16, 0x20, 0x99, 0x94, 0x61, 0x19, 0xA2, 0x0C, 0x1B, 0x05, 0x2E, 0x1B, 0x44, 0x64, 0x9A, 0x00, 0x84, 0x8C, 0x18, 0x52, 0x84, 0xB4, 0x60, 0x82, 0x20, 0x08, 0x42, 0x48, 0x09, 0x84, 0x08, 0x46, 0x11, 0x00, 0x46, 0x13, 0x43, 0x01, 0xE1, 0x06, 0x91, 0x1B, 0x44, 0x8E, 0x01, 0x94, 0x64, 0x4A, 0x12, 0x09, 0x98, 0x38, 0x0E, 0xE4, 0x06, 0x25, 0x24, 0x13, 0x68, 0x13, 0x21, 0x06, 0x04, 0xB9, 0x40, 0x54, 0x24, 0x25, 0x14, 0x88, 0x69, 0x82, 0x38, 0x01, 0xA4, 0x28, 0x72, 0x50, 0x86, 0x61, 0x23, 0xB1, 0x88, 0xA2, 0x90, 0x08, 0x1C, 0x95, 0x30, 0x1C, 0x40, 0x82, 0x49, 0xC8, 0x64, 0xCA, 0x04, 0x40, 0x44, 0x98, 0x21, 0x0B, 0x24, 0x61, 0x1C, 0xA0, 0x4C, 0x09, 0xA4, 0x21, 0xC9, 0x08, 0x8A, 0x22, 0x13, 0x41, 0x80, 0xC8, 0x89, 0x23, 0xB1, 0x64, 0x1C, 0x11, 0x49, 0x40, 0xA2, 0x29, 0x61, 0xC8, 0x8C, 0x8B, 0x96, 0x91, 0x83, 0x02, 0x42, 0xE1, 0xB6, 0x85, 0x51, 0x86, 0x4C, 0x04, 0x43, 0x91, 0x4B, 0xB8, 0x69, 0x50, 0x24, 0x81, 0xC8, 0x04, 0x2E, 0x1B, 0xB9, 0x31, 0x93, 0x24, 0x00, 0x23, 0x86, 0x81, 0xC2, 0xB8, 0x61, 0x09, 0x00, 0x62, 0x14, 0x99, 0x41, 0x19, 0x37, 0x6E, 0x1C, 0x16, 0x30, 0x0A, 0x27, 0x45, 0x51, 0x10, 0x0D, 0x1C, 0x33, 0x4A, 0x10, 0x40, 0x80, 0xA0, 0x34, 0x62, 0xD8, 0x44, 0x4A, 0x01, 0x06, 0x45, 0x23, 0x83, 0x8C, 0x24, 0xA4, 0x85, 0x01, 0x04, 0x0C, 0x09, 0x03, 0x32, 0xDB, 0x90, 0x09, 0x4A, 0x14, 0x42, 0x01, 0x08, 0x21, 0x22, 0x08, 0x66, 0x8B, 0x28, 0x70, 0x24, 0x38, 0x31, 0x0C, 0x46, 0x69, 0x43, 0x44, 0x69, 0x9A, 0x34, 0x4D, 0x82, 0xC8, 0x40, 0x42, 0x42, 0x01, 0x23, 0xC7, 0x29, 0x91, 0x32, 0x72, 0x1B, 0x36, 0x4C, 0x1B, 0x33, 0x05, 0x13, 0x35, 0x61, 0x14, 0x02, 0x46, 0x08, 0x03, 0x65, 0x21, 0x87, 0x20, 0x09, 0x03, 0x91, 0xC1, 0xC4, 0x25, 0xE2, 0xA6, 0x4C, 0x81, 0x14, 0x48, 0x20, 0x25, 0x4D, 0x03, 0x19, 0x69, 0xA3, 0x00, 0x69, 0x54, 0xA8, 0x30, 0x9C, 0x86, 0x05, 0x9C, 0x36, 0x82, 0x03, 0x37, 0x0C, 0x0A, 0x15, 0x50, 0x9C, 0xC0, 0x91, 0x04, 0xB6, 0x91, 0x0C, 0x11, 0x80, 0x09, 0xB5, 0x70, 0x63, 0x20, 0x92, 0x44, 0x22, 0x71, 0xC1, 0x48, 0x44, 0x98, 0xC4, 0x6D, 0x64, 0xA6, 0x89, 0x0A, 0xA9, 0x40, 0x04, 0xB8, 0x50, 0x04, 0x34, 0x8C, 0xE2, 0xC4, 0x80, 0x02, 0x00, 0x12, 0xA3, 0x36, 0x46, 0xD2, 0x00, 0x01, 0x1C, 0x45, 0x46, 0x22, 0x33, 0x6D, 0x81, 0x92, 0x01, 0x08, 0x12, 0x86, 0x9C, 0x04, 0x51, 0xA3, 0x98, 0x30, 0x48, 0x10, 0x91, 0x19, 0xA0, 0x44, 0xC3, 0x04, 0x8D, 0x42, 0x90, 0x40, 0x43, 0x80, 0x44, 0xA4, 0x46, 0x71, 0x0B, 0xA2, 0x60, 0x52, 0x18, 0x6D, 0x0B, 0xB6, 0x85, 0x1B, 0xB2, 0x0C, 0x94, 0x12, 0x09, 0x04, 0xB6, 0x41, 0x18, 0xA8, 0x84, 0x10, 0x00, 0x22, 0x53, 0x42, 0x69, 0xC3, 0xA8, 0x81, 0x00, 0x25, 0x32, 0x81, 0x16, 0x28, 0x81, 0x44, 0x2D, 0xD4, 0xB4, 0x4D, 0x08, 0xC8, 0x45, 0x5A, 0x04, 0x01, 0xC1, 0x90, 0x50, 0x22, 0x14, 0x82, 0x63, 0xC6, 0x6D, 0x04, 0x22, 0x72, 0x1C, 0xB9, 0x44, 0x9B, 0x46, 0x0D, 0xC2, 0x14, 0x22, 0x91, 0xB0, 0x44, 0x21, 0x89, 0x68, 0xC4, 0x96, 0x08, 0x0A, 0xB9, 0x8C, 0x22, 0xB9, 0x40, 0xE2, 0x26, 0x50, 0x8C, 0x88, 0x25, 0xCB, 0xB8, 0x04, 0x54, 0x16, 0x25, 0x63, 0x34, 0x0C, 0x24, 0xB0, 0x29, 0xA3, 0x44, 0x20, 0x43, 0x46, 0x40, 0x9C, 0x02, 0x48, 0x5A, 0xC8, 0x2C, 0x00, 0x05, 0x31, 0x09, 0x18, 0x00, 0xDB, 0x46, 0x51, 0xD2, 0xB6, 0x2C, 0x44, 0x40, 0x88, 0x9A, 0x96, 0x24, 0x12, 0xA5, 0x90, 0x04, 0x39, 0x86, 0x10, 0x80, 0x2D, 0x10, 0x99, 0x21, 0x60, 0x06, 0x66, 0x21, 0x89, 0x4C, 0x91, 0x04, 0x60, 0x23, 0xB9, 0x01, 0x12, 0x11, 0x48, 0x12, 0x29, 0x51, 0xA1, 0x06, 0x45, 0x44, 0x22, 0x12, 0x03, 0x27, 0x8E, 0x23, 0x94, 0x84, 0x0C, 0x29, 0x06, 0x94, 0x86, 0x50, 0xE0, 0x48, 0x10, 0x24, 0x26, 0x40, 0x61, 0x04, 0x66, 0x9C, 0xB2, 0x84, 0x54, 0xC2, 0x2C, 0x03, 0x82, 0x0E, 0x01, 0x00, 0xD6, 0xD4, 0x27, 0x24, 0xCA, 0xFD, 0xF2, 0x81, 0xB9, 0xCA, 0xDC, 0x58, 0x04, 0x84, 0x83, 0x95, 0x49, 0x25, 0x4C, 0x9B, 0xE0, 0xA1, 0xF9, 0xAA, 0x9D, 0x76, 0xE6, 0x54, 0x63, 0xCD, 0x83, 0x14, 0x20, 0x65, 0xE7, 0xF7, 0x47, 0xBD, 0x27, 0x4C, 0xF3, 0x7E, 0x85, 0x70, 0xE0, 0xE6, 0x3A, 0xDB, 0xF8, 0x5F, 0x31, 0x79, 0x14, 0x75, 0xFF, 0x1A, 0x2F, 0x50, 0x5B, 0x53, 0x24, 0x77, 0x2C, 0xB0, 0xEB, 0x21, 0x9E, 0x2C, 0x28, 0xC4, 0xEF, 0xBC, 0x31, 0xE7, 0x13, 0xDF, 0x18, 0x77, 0x25, 0xB7, 0xBD, 0xE2, 0x90, 0xE6, 0x08, 0x98, 0x5B, 0x7D, 0x8A, 0x71, 0x14, 0x42, 0xD4, 0x03, 0xD2, 0x56, 0xF5, 0x35, 0xA4, 0x27, 0x1F, 0x6C, 0xC6, 0x5F, 0x91, 0xF1, 0xA7, 0x3F, 0x3B, 0x33, 0x94, 0x83, 0x3D, 0xF0, 0x12, 0x79, 0xDC, 0x71, 0xFB, 0x60, 0xBD, 0x14, 0x13, 0xBF, 0x23, 0xBA, 0x3A, 0x20, 0xC7, 0x15, 0xC1, 0x30, 0xDA, 0x19, 0x2D, 0x05, 0x1F, 0xF6, 0xEA, 0x7E, 0xDD, 0xBB, 0x81, 0xDB, 0xC4, 0xBE, 0xBA, 0xF6, 0x71, 0x41, 0x23, 0x6E, 0x5D, 0x9E, 0x09, 0x93, 0xFB, 0x7D, 0xC7, 0x06, 0x44, 0x83, 0xDA, 0x06, 0x99, 0xE8, 0x40, 0x21, 0x76, 0xC6, 0xB2, 0x0F, 0x24, 0x0D, 0x35, 0x87, 0xBC, 0x1B, 0x07, 0x3C, 0x9A, 0xA0, 0x09, 0xCB, 0xC1, 0xB0, 0x5F, 0x49, 0xCC, 0xBB, 0x25, 0x13, 0x12, 0x96, 0x92, 0xDF, 0x1C, 0xEC, 0xDA, 0x29, 0x54, 0xCC, 0xEC, 0xC1, 0x7B, 0xBB, 0x1D, 0x11, 0x96, 0x4F, 0xAE, 0xB0, 0xF9, 0xE0, 0x29, 0x21, 0x29, 0x59, 0xB6, 0x8E, 0x4B, 0xE0, 0x66, 0x64, 0xF9, 0x58, 0x74, 0x32, 0xC0, 0x2D, 0xE6, 0x15, 0x88, 0x51, 0x55, 0x57, 0x56, 0x5A, 0x26, 0xA6, 0xEC, 0xD6, 0xB4, 0xDE, 0x47, 0xF0, 0xB6, 0x47, 0x63, 0x77, 0x81, 0xEC, 0x19, 0x49, 0x32, 0xD2, 0x82, 0xFF, 0x1F, 0x83, 0x5E, 0xB8, 0x09, 0x66, 0xAB, 0xA2, 0x16, 0xB4, 0xE7, 0xF8, 0x8E, 0xAB, 0x97, 0x05, 0x21, 0x26, 0x4D, 0xB5, 0xD6, 0xF2, 0x83, 0xA4, 0xF6, 0x79, 0x1E, 0x32, 0x9F, 0xB8, 0xCB, 0x54, 0x25, 0xB9, 0x13, 0x9E, 0x96, 0xAB, 0xB3, 0x94, 0x4E, 0x35, 0xBB, 0x88, 0x64, 0x2A, 0xC0, 0xE7, 0xDC, 0xDA, 0xB9, 0xB5, 0x59, 0xD0, 0x9E, 0x29, 0x55, 0x72, 0xB2, 0x52, 0x92, 0xC0, 0x3C, 0xD5, 0xAB, 0x5E, 0x7B, 0xBE, 0x77, 0x61, 0xD8, 0x58, 0x3F, 0xAD, 0x91, 0x66, 0x91, 0x3F, 0xDE, 0x1B, 0x65, 0x8F, 0x87, 0x26, 0xC3, 0xF7, 0xE6, 0xD2, 0x65, 0x63, 0x17, 0xDA, 0xAF, 0xB9, 0x2E, 0x78, 0x7D, 0x24, 0xC5, 0xD8, 0x94, 0x7F, 0xF5, 0x95, 0xA5, 0x85, 0x3D, 0x61, 0x11, 0x73, 0xDF, 0x20, 0xF0, 0xAE, 0x01, 0x50, 0x75, 0x8C, 0x6B, 0x13, 0x1D, 0xFD, 0xEF, 0x36, 0xA0, 0x1D, 0x7C, 0x87, 0x4D, 0x0B, 0x8C, 0xD0, 0xC2, 0x53, 0x83, 0x56, 0x94, 0x06, 0xCB, 0xE4, 0x2A, 0x72, 0xD7, 0x09, 0x7E, 0x84, 0xD9, 0x82, 0x58, 0x39, 0xEB, 0xD1, 0x4F, 0x17, 0x5E, 0xD5, 0x1E, 0x6A, 0xC1, 0xA3, 0xF7, 0xF7, 0xBE, 0xFF, 0x60, 0xF5, 0xC0, 0x72, 0x73, 0x42, 0xD7, 0xDD, 0x34, 0x76, 0xDC, 0x9A, 0xE0, 0xE2, 0x7E, 0xDB, 0xB8, 0x86, 0xBF, 0xA0, 0x0D, 0x36, 0xFE, 0x80, 0xDA, 0x81, 0x6A, 0x45, 0xE0, 0xC8, 0x00, 0x0B, 0x6E, 0x23, 0xE9, 0xB5, 0xCA, 0xD0, 0x13, 0xB6, 0xDE, 0xBF, 0x74, 0x9E, 0xB7, 0x27, 0xB8, 0xD8, 0x3B, 0xFE, 0x26, 0xF6, 0xC5, 0x99, 0xD5, 0xBD, 0x45, 0xB5, 0x82, 0xB8, 0x4F, 0x4F, 0xC8, 0x34, 0x10, 0xEE, 0x2A, 0x67, 0x5C, 0x66, 0x14, 0x5F, 0x52, 0xCF, 0x36, 0x83, 0x29, 0x0C, 0xC7, 0x2A, 0x29, 0x28, 0x5D, 0x70, 0x66, 0x7A, 0x3A, 0x31, 0x58, 0x93, 0x54, 0xD9, 0x19, 0x31, 0x62, 0x5F, 0xFA, 0xCF, 0xB7, 0xE0, 0x2C, 0x03, 0xFE, 0x48, 0x09, 0x2A, 0x12, 0x0E, 0x5F, 0x43, 0x12, 0x76, 0xE8, 0x37, 0x4D, 0xBE, 0x15, 0x40, 0x96, 0xC8, 0x6C, 0x58, 0x79, 0x10, 0xF5, 0x05, 0x1A, 0x86, 0x14, 0x17, 0xC0, 0x6A, 0x73, 0x48, 0x0C, 0xE3, 0x19, 0x5C, 0xC9, 0x99, 0xF6, 0xB8, 0xB3, 0x01, 0x9B, 0x22, 0x37, 0x96, 0xC5, 0xE1, 0x1F, 0x73, 0x42, 0xC9, 0x74, 0x6A, 0xED, 0xBF, 0xA9, 0x44, 0xCD, 0x79, 0xB8, 0x5C, 0x10, 0x00, 0x07, 0xBB, 0x58, 0x69, 0x84, 0x3A, 0x23, 0xAD, 0x06, 0xD8, 0x1F, 0x5C, 0xB2, 0x9D, 0xD1, 0x7B, 0xCE, 0xE7, 0x55, 0x72, 0xB9, 0xE0, 0xCF, 0xDB, 0xD5, 0xA8, 0x3A, 0x30, 0x57, 0x44, 0x2D, 0xF0, 0x00, 0xDA, 0x7A, 0x3A, 0xA6, 0xFC, 0x5F, 0xB2, 0x89, 0xA1, 0x29, 0x99, 0x24, 0xD9, 0x23, 0x1F, 0xE1, 0xD0, 0xCF, 0x3C, 0x17, 0xF1, 0x80, 0x3F, 0x61, 0x43, 0xC0, 0x97, 0xF9, 0x54, 0x2C, 0x9A, 0xBB, 0x8F, 0x98, 0x77, 0xE4, 0xAE, 0xC5, 0x4A, 0xB9, 0x39, 0x93, 0xDC, 0x49, 0x87, 0xDF, 0x67, 0x80, 0x8B, 0xF7, 0xBE, 0xDE, 0xA8, 0x6B, 0x5C, 0x83, 0xD2, 0x48, 0xE9, 0x5E, 0xA3, 0x02, 0x45, 0x3F, 0x5F, 0x6B, 0x7F, 0xF5, 0xB5, 0xF5, 0x8B, 0x65, 0xD9, 0x32, 0xD2, 0xBF, 0x73, 0x7C, 0x51, 0x89, 0x3D, 0x89, 0xF0, 0x7D, 0xA5, 0xBF, 0xEA, 0x79, 0xD7, 0xE7, 0xFB, 0x2A, 0xAB, 0x82, 0x33, 0xA2, 0x7E, 0xB4, 0x4C, 0x68, 0x58, 0x05, 0x1D, 0x92, 0xB9, 0x98, 0xBC, 0x47, 0x51, 0xA4, 0x90, 0x2A, 0xA2, 0x22, 0xDE, 0x2D, 0x5C, 0xDC, 0xEC, 0x26, 0xB3, 0x6D, 0xBA, 0x47, 0xCC, 0xEB, 0x41, 0xFB, 0x19, 0x2D, 0xDF, 0xFD, 0x55, 0x12, 0xD8, 0x2B, 0x1B, 0xD3, 0x4D, 0x1E, 0xAA, 0x42, 0xF8, 0xCC, 0x50, 0x3F, 0x23, 0x85, 0x92, 0x42, 0x07, 0x9C, 0xBC, 0x1A, 0x55, 0xF0, 0x95, 0xAB, 0xB3, 0xC1, 0x87, 0x9F, 0xD1, 0xB4, 0x85, 0x04, 0xD8, 0x05, 0x4C, 0x15, 0xEB, 0x3E, 0xBF, 0x54, 0xA3, 0x2C, 0x5B, 0x62, 0xC0, 0x55, 0x55, 0xE4, 0xAC, 0x60, 0x36, 0x91, 0x9B, 0xB9, 0xA1, 0xBB, 0x53, 0x9E, 0x78, 0x86, 0x7A, 0x74, 0xF5, 0x3C, 0x23, 0xB1, 0xA1, 0x35, 0x98, 0x7D, 0x8B, 0xDD, 0x63, 0xE0, 0x92, 0xAB, 0x2B, 0xF1, 0xD8, 0xF6, 0x60, 0x38, 0xE1, 0x49, 0xAE, 0x41, 0x0B, 0x09, 0xAB, 0x25, 0xB4, 0xFE, 0x65, 0x53, 0xB3, 0x0E, 0x7B, 0xA7, 0xBF, 0x01, 0x36, 0x36, 0x8E, 0x3B, 0x8B, 0x73, 0x23, 0xA1, 0x24, 0x89, 0x02, 0x94, 0x7B, 0x2A, 0x39, 0x85, 0xB5, 0xC5, 0xCB, 0x80, 0x27, 0xAE, 0xF8, 0xA9, 0xE3, 0x42, 0xA3, 0xB7, 0x54, 0x3C, 0x31, 0x54, 0x72, 0x49, 0xFC, 0x77, 0x7C, 0x59, 0x2A, 0x31, 0xB8, 0x5B, 0x4B, 0x07, 0xE0, 0xAD, 0x87, 0x61, 0x2C, 0x3D, 0xF4, 0x9B, 0x9E, 0xB6, 0x6A, 0x53, 0xF4, 0x11, 0xC6, 0xD6, 0xDE, 0x9F, 0x26, 0x86, 0x95, 0x07, 0x74, 0x80, 0x6A, 0xD0, 0xCE, 0xBF, 0x25, 0x4C, 0x18, 0x2F, 0x3A, 0x5D, 0xF9, 0xE4, 0x29, 0xF0, 0x79, 0x2E, 0x96, 0x35, 0x95, 0xB8, 0x42, 0x6B, 0xB0, 0xCB, 0x53, 0x62, 0x75, 0x36, 0x26, 0x5C, 0x4F, 0x63, 0x46, 0xB4, 0xB0, 0x72, 0xEA, 0xB4, 0xD1, 0xE6, 0x87, 0xA4, 0xDE, 0x7B, 0x82, 0x89, 0x90, 0xEB, 0xF3, 0x38, 0x1F, 0x0B, 0x70, 0xE9, 0x26, 0xD6, 0x7B, 0x76, 0x89, 0x73, 0xF1, 0x02, 0x40, 0x80, 0xBD, 0x40, 0xC6, 0x7B, 0x81, 0x04, 0x09, 0x34, 0xD1, 0xC3, 0xC3, 0x77, 0x4D, 0xDE, 0x93, 0x28, 0xBE, 0x69, 0xBB, 0xD5, 0xDF, 0xE3, 0xF2, 0x80, 0xDB, 0x77, 0xFF, 0xC1, 0xA7, 0x8D, 0x11, 0x13, 0x34, 0xB4, 0x21, 0x97, 0x00, 0x2B, 0xD8, 0x5C, 0xD7, 0xCD, 0xF7, 0xCB, 0xB6, 0xED, 0x3F, 0x41, 0xCB, 0xB9, 0xAD, 0x48, 0x1F, 0x44, 0xA3, 0x35, 0x11, 0x55, 0xA5, 0x22, 0x35, 0x0A, 0x65, 0x8F, 0x69, 0x92, 0x11, 0xD7, 0xAA, 0x5E, 0x68, 0xA5, 0x27, 0x94, 0x76, 0xC0, 0x0B, 0xD9, 0xEE, 0x01, 0x0C, 0xEC, 0x6E, 0x51, 0x02, 0xD2, 0x70, 0x54, 0xC9, 0x74, 0xD1, 0x6B, 0xE4, 0xA6, 0xC6, 0x85, 0x99, 0xAE, 0x83, 0x01, 0x9C, 0xB1, 0x32, 0x4E, 0x35, 0x10, 0x4F, 0x10, 0x5A, 0x59, 0xE6, 0xCF, 0x07, 0x67, 0x30, 0xF3, 0x3A, 0x03, 0xED, 0xD7, 0xC9, 0x2E, 0x07, 0x36, 0xB5, 0x42, 0x98, 0x79, 0x0C, 0xA8, 0xD5, 0x28, 0x72, 0x74, 0x28, 0x23, 0x73, 0x19, 0x9E, 0x90, 0xB9, 0x49, 0x13, 0xB9, 0x9C, 0x06, 0xD7, 0xD5, 0xB6, 0xC4, 0x18, 0xF5, 0x5B, 0x66, 0x14, 0x13, 0x31, 0x13, 0x0E, 0x6B, 0xD5, 0x61, 0x52, 0xB8, 0xDB, 0x19, 0xB2, 0xFB, 0x1B, 0xB6, 0x5C, 0x8D, 0x21, 0xFC, 0xD4, 0xBE, 0x45, 0x1A, 0x4A, 0x1C, 0x0F, 0xEE, 0x73, 0xDB, 0xC3, 0x55, 0x7D, 0x36, 0x2C, 0x45, 0x3D, 0x8E, 0x6A, 0x43, 0xE9, 0x9E, 0x47, 0x97, 0xD1, 0xF2, 0x5B, 0x1A, 0x58, 0x98, 0x14, 0x81, 0x1D, 0x66, 0xB7, 0x31, 0xA7, 0x5E, 0x99, 0x3F, 0xF1, 0xD3, 0xBC, 0x42, 0x11, 0xF8, 0xC1, 0x51, 0x0B, 0x90, 0x40, 0x50, 0x68, 0x94, 0xB8, 0x6B, 0xA9, 0xFB, 0xA3, 0x55, 0x49, 0x61, 0xDF, 0x34, 0xFD, 0xB7, 0x65, 0x5F, 0xD9, 0x28, 0x37, 0x8B, 0x4E, 0x65, 0x00, 0x14, 0x77, 0xD1, 0xFC, 0xF1, 0x8C, 0xB7, 0x1C, 0x5E, 0x41, 0x71, 0x69, 0x6F, 0x33, 0xB2, 0xB6, 0x76, 0x30, 0x38, 0xD5, 0x12, 0xAC, 0xB0, 0xF7, 0xFE, 0xEE, 0x76, 0xF0, 0xFB, 0x16, 0x4E, 0x30, 0xFE, 0xB7, 0xD6, 0x37, 0xB3, 0xAB, 0x1E, 0x7F, 0x25, 0x1E, 0xF8, 0xC0, 0x54, 0x31, 0x46, 0x1C, 0x3A, 0xB9, 0x0F, 0x05, 0x7D, 0xA0, 0xF4, 0xD8, 0xC3, 0xB3, 0x78, 0x7A, 0xE5, 0x8C, 0xB0, 0x13, 0x6D, 0x68, 0xAC, 0xB6, 0x40, 0x7B, 0xCF, 0x67, 0x16, 0x20, 0x72, 0x3A, 0x02, 0x30, 0xD4, 0xF7, 0xDD, 0x7A, 0xDE, 0x77, 0x0C, 0x41, 0x8F, 0xCA, 0xD9, 0x97, 0x8F, 0x7C, 0x96, 0x22, 0x26, 0xCA, 0x6D, 0x65, 0x79, 0xBA, 0xDC, 0x67, 0x52, 0x23, 0x7C, 0x99, 0xD2, 0x4C, 0xA8, 0x04, 0xE9, 0xF1, 0xFC, 0xDC, 0x9A, 0xAA, 0x11, 0x1F, 0x2C, 0x90, 0x5E, 0xF0, 0x31, 0x69, 0x0D, 0x17, 0x65, 0xE8, 0x21, 0x93, 0x8A, 0x0B, 0x78, 0x46, 0xC3, 0xBB, 0x80, 0xDB, 0xEF, 0x95, 0x30, 0xC6, 0x8C, 0xAA, 0x0A, 0xDA, 0x96, 0x2A, 0x59, 0x5F, 0xD9, 0xE7, 0xAB, 0xD9, 0xE1, 0xF7, 0x6F, 0xF2, 0x97, 0xE1, 0x78, 0x50, 0x54, 0x13, 0xEE, 0x95, 0xFC, 0x0A, 0x95, 0x8D, 0x72, 0x0C, 0x2A, 0x23, 0x86, 0xA1, 0x64, 0x50, 0xF9, 0x7D, 0xE5, 0x8E, 0xE2, 0x27, 0xBF, 0xA3, 0x3C, 0xAA, 0xC0, 0x3F, 0x13, 0x5A, 0x83, 0x45, 0x46, 0x9F, 0x26, 0xC7, 0x70, 0x26, 0x91, 0x5E, 0xE2, 0x0F, 0xBD, 0x82, 0xB0, 0x9B, 0x02, 0xFE, 0xA7, 0x7A, 0xBC, 0xFB, 0x9D, 0xA8, 0x94, 0xD8, 0x67, 0x6E, 0x16, 0x0F, 0x1E, 0x1C, 0xEA, 0x42, 0x0B, 0x2C, 0xFE, 0x14, 0xFF, 0x08, 0xE1, 0x65, 0x0D, 0x56, 0x5B, 0x6C, 0xDF, 0x6A, 0xD7, 0xEE, 0x51, 0x3D, 0xC1, 0xE7, 0x34, 0x30, 0x96, 0xDD, 0x26, 0x5C, 0x45, 0x9F, 0xA1, 0x7C, 0x55, 0xE5, 0xD6, 0xC6, 0x38, 0x28, 0xBC, 0xC4, 0xB7, 0x2A, 0x2A, 0x02, 0x7C, 0x31, 0xD2, 0x43, 0x8A, 0x7B, 0xFF, 0x42, 0x77, 0x3F, 0xED, 0x94, 0x35, 0xC3, 0xC6, 0xED, 0x66, 0x4D, 0x35, 0x41, 0x86, 0x58, 0xCB, 0x13, 0x37, 0x43, 0xF4, 0x82, 0x73, 0x2F, 0x6F, 0xB2, 0xC8, 0x9C, 0x68, 0x00, 0x05, 0x20, 0x9D, 0xFB, 0xEE, 0xAB, 0x70, 0x2A, 0x39, 0x11, 0xA8, 0x7D, 0xD5, 0x5E, 0xF3, 0x9F, 0x40, 0x93, 0x70, 0xBE, 0x94, 0x88, 0x84, 0x42, 0xB0, 0x8D, 0xB3, 0x37, 0x08, 0xBC, 0xB3, 0x1A, 0x14, 0x07, 0x30, 0x3B, 0x4F, 0xED, 0xF3, 0x11, 0xC1, 0x52, 0x63, 0x57, 0x9F, 0x81, 0x74, 0x6C, 0xED, 0xFB, 0x79, 0x0C, 0xA0, 0x30, 0x4C, 0x88, 0xFC, 0xCA, 0x59, 0x56, 0xE9, 0xF8, 0x19, 0xFE, 0xFF, 0xAC, 0x13, 0xC6, 0x4D, 0x96, 0xC4, 0x3C, 0x98, 0xD8, 0x8F, 0xEC, 0x8F, 0xD9, 0x83, 0xC1, 0xC5, 0x19, 0xCB, 0x88, 0x4D, 0x2E, 0x7A, 0x90, 0xCD, 0xF3, 0x65, 0xFE, 0x5F, 0xB5, 0xDA, 0x8F, 0xAB, 0x74, 0xF0, 0x73, 0xBA, 0x25, 0x8D, 0x26, 0x4F, 0x94, 0x2D, 0x14, 0xD6, 0xE2, 0xE9, 0x08, 0x29, 0xAE, 0x35, 0x74, 0x6D, 0x05, 0x7A, 0x18, 0x0E, 0x56, 0x38, 0x42, 0xF5, 0x4C, 0x4B, 0xC7, 0xD5, 0x00, 0x49, 0x43, 0x24, 0x72, 0xD1, 0xED, 0xF1, 0x38, 0xF2, 0xE5, 0x86, 0x26, 0xAB, 0x8C, 0x96, 0xE6, 0x00, 0xED, 0x19, 0x36, 0xF3, 0x38, 0x80, 0xF4, 0xF2, 0x20, 0x1B, 0x61, 0x07, 0xC4, 0xEF, 0xB9, 0xC0, 0x2E, 0xCF, 0x31, 0x44, 0xE3, 0xAC, 0x55, 0xB0, 0xEE, 0x51, 0x68, 0xA7, 0x93, 0xB1, 0x5D, 0xB4, 0xA6, 0x1B, 0xFF, 0xFC, 0x8B, 0xE4, 0xA3, 0x80, 0x40, 0xA0, 0x6C, 0x31, 0xF5, 0x15, 0x2D, 0x7C, 0x95, 0xF8, 0xC4, 0x94, 0x45, 0x12, 0x4D, 0x07, 0x20, 0x95, 0xFC, 0x14, 0xF6, 0x79, 0xDF, 0x55, 0xDC, 0x1E, 0x7F, 0xBE, 0x48, 0x83, 0xDA, 0xA3, 0x50, 0xF2, 0x16, 0x98, 0xEB, 0x78, 0xB2, 0x9A, 0xDB, 0xD0, 0x71, 0x53, 0x58, 0xF9, 0x65, 0x27, 0x8A, 0xF8, 0x67, 0xC1, 0x2E, 0x2B, 0xB1, 0x9F, 0xFA, 0x16, 0x50, 0x27, 0x69, 0xF4, 0xFB, 0xDB, 0x20, 0x82, 0x2D, 0x1D, 0xE1, 0xFB, 0x6E, 0x41, 0x6D, 0x82, 0x29, 0x32, 0xB5, 0xCD, 0x5B, 0x37, 0x0A, 0x58, 0x65, 0x56, 0x07, 0x56, 0xD7, 0x6D, 0x8C, 0x2F, 0xE4, 0x70, 0x4E, 0x0B, 0x15, 0x83, 0xEB, 0x5D, 0x23, 0x5E, 0xC3, 0xFE, 0x7F, 0xF4, 0x98, 0xE1, 0x35, 0x61, 0x00, 0xC5, 0x80, 0x76, 0x3E, 0xB5, 0xF2, 0x36, 0x35, 0x62, 0x0C, 0xF6, 0xCC, 0x56, 0xE7, 0x4B, 0x48, 0x22, 0x3C, 0x70, 0xB5, 0xE5, 0x23, 0xAC, 0x61, 0xEA, 0xAE, 0xF8, 0x8E, 0x4D, 0xD1, 0x50, 0x5D, 0x25, 0xC9, 0x65, 0x8B, 0x96, 0xE9, 0x32, 0xCE, 0x0B, 0xD0, 0xEF, 0xFE, 0x80, 0xBA, 0xA5, 0xD1, 0x05, 0xA6, 0x51, 0x4B, 0x25, 0x57, 0x8D, 0x1F, 0x3F, 0xCC, 0x8F, 0xF5, 0xF9, 0x3A, 0x7C, 0xDD, 0xCC, 0xE0, 0x84, 0x0F, 0x63, 0x1B, 0xE0, 0x2B, 0xCA, 0x85, 0x20, 0x98, 0xDC, 0xFA, 0x06, 0x56, 0xF0, 0x8A, 0xF1, 0xBD, 0xC8, 0xE2, 0x4A, 0x27, 0x46, 0x74, 0x16, 0xF4, 0x87, 0xAD, 0x02, 0x60, 0x22, 0xDD, 0x5E, 0x1E, 0x1E, 0xFD, 0xC9, 0xC2, 0xB4, 0x71, 0xE3, 0x26, 0x53, 0x65, 0xF2, 0x0B, 0xC8, 0x21, 0x86, 0x37, 0x66, 0x25, 0x5D, 0x0A, 0xAC, 0x67, 0xB6, 0x58, 0xE6, 0x63, 0x3F, 0xD2, 0xC9, 0x3F, 0x80, 0xE5, 0x55, 0x5C, 0x6B, 0x3F, 0x9B, 0x9C, 0x54, 0x02, 0x62, 0xF9, 0x2E, 0x57, 0x5E, 0xCA, 0x8C, 0xBD, 0xDE, 0xA2, 0x5E, 0x35, 0x59, 0x9F, 0xAF, 0xE0, 0x90, 0x20, 0x1D, 0x53, 0x1A, 0x96, 0xA6, 0x59, 0x5F, 0x6B, 0xC0, 0xA0, 0x83, 0x47, 0xF4, 0x54, 0xFC, 0x12, 0x6A, 0x16, 0x21, 0x64, 0xA0, 0xD5, 0x07, 0x39, 0xF3, 0x0A, 0xB2, 0x29, 0x89, 0xF8, 0x88, 0xE4, 0xDF, 0xA3, 0x56, 0x13, 0x7A, 0x3E, 0x65, 0xEC, 0xB5, 0xF4, 0x7E, 0x20, 0x0E, 0x73, 0x36, 0xA2, 0xF0, 0xA5, 0xC5, 0x47, 0xA2, 0x36, 0x7F, 0x1D, 0x0F, 0xDE, 0xA8, 0x9D, 0x00, 0x69, 0x8D, 0x96, 0x2E, 0x62, 0xE8, 0xDA, 0xA5, 0x70, 0xEE, 0x07, 0x7B, 0x9E, 0xB8, 0x18, 0xED, 0x82, 0x75, 0xB2, 0x3E, 0x73, 0x39, 0xFA, 0x3A, 0x6C, 0x9E, 0xF0, 0xD3, 0xC9, 0x78, 0xEE, 0xF7, 0x5B, 0xC9, 0x77, 0xAA, 0xFE, 0x87, 0xB1, 0xA4, 0x1F, 0xED, 0x4C, 0x7D, 0xA1, 0x7E, 0x2B, 0xBE, 0xCC, 0xA8, 0xF4, 0x06, 0xF0, 0x40, 0xB1, 0x6F, 0xDD, 0xFB, 0x2E, 0x8F, 0x47, 0x0C, 0x25, 0x40, 0x9B, 0x8C, 0x7C, 0x13, 0x88, 0xE6, 0x08, 0xEB, 0xBA, 0xE2, 0x67, 0xF7, 0x7C, 0x5F, 0xE0, 0x10, 0xF6, 0x91, 0x7B, 0xC6, 0xCA, 0x7B, 0xF6, 0x86, 0x5F, 0xAA, 0x73, 0xE1, 0x0F, 0x2F, 0x60, 0xD2, 0x2D, 0xB2, 0x4A, 0x21, 0x71, 0x81, 0xBE, 0x56, 0xFD, 0x47, 0x3E, 0xE7, 0xAF, 0x5E, 0xD5, 0x60, 0x9A, 0xDA, 0x02, 0x36, 0xFA, 0xB3, 0x06, 0x6C, 0x3D, 0xAD, 0x28, 0xA2, 0x4F, 0x67, 0xD4, 0xCC, 0x1C, 0xEF, 0xE6, 0x10, 0x6F, 0x5E, 0x54, 0x27, 0xAC, 0xCD, 0xC7, 0x3F, 0xF8, 0x85, 0x76, 0xA2, 0x7A, 0xEB, 0xE7, 0x1A, 0x33, 0xDB, 0x3C, 0x08, 0x02, 0xD6, 0x97, 0x18, 0x95, 0x6C, 0xD9, 0xD1, 0x5A, 0xAA, 0x9A, 0x2D, 0xE3, 0xAC, 0x62, 0x10, 0x10, 0x0A, 0x2E, 0x39, 0xAF, 0x5B, 0xA9, 0x1D, 0xFA, 0x21, 0x8C, 0x53, 0x72, 0x66, 0x06, 0x2E, 0x32, 0x6E, 0x2F, 0xF8, 0xC4, 0x4D, 0x17, 0x80, 0xFB, 0xAF, 0xF4, 0xAD, 0xBA, 0x82, 0x71, 0x17, 0xE0, 0xBC, 0xB7, 0xA4, 0xC8, 0xF2, 0x61, 0x39, 0x81, 0x71, 0x3F, 0xA5, 0x98, 0xA4, 0x68, 0x3A, 0x46, 0x70, 0x85, 0x4C, 0x94, 0x67, 0xF2, 0x5A, 0x65, 0x6D, 0xDB, 0x6E, 0x7C, 0x3E, 0xF1, 0x92, 0xEB, 0xBD, 0xEE, 0x15, 0x3A, 0x59, 0x41, 0x61, 0x95, 0x26, 0xB3, 0x17, 0x87, 0x54, 0x4F, 0xE2, 0x31, 0x2A, 0x28, 0x98, 0x9C, 0x6A, 0xA3, 0xAC, 0xC0, 0xFE, 0x44, 0x23, 0x14, 0xFD, 0xFB, 0xD8, 0x08, 0x7F, 0x2B, 0x75, 0x5E, 0xB4, 0xB7, 0x35, 0x55, 0x76, 0x28, 0x3F, 0xA8, 0x6C, 0xD2, 0xD9, 0xEC, 0x1A, 0x6B, 0xD9, 0x4E, 0x6C, 0x5D, 0x72, 0x82, 0x02, 0xEC, 0x0B, 0x6E, 0xDF, 0xE1, 0xF3, 0x35, 0x84, 0x11, 0xC4, 0x9E, 0xC1, 0x10, 0x63, 0xAC, 0x1E, 0xDE, 0xB2, 0x1B, 0x95, 0xD7, 0x13, 0xD9, 0x0B, 0xE4, 0x96, 0xD8, 0x55, 0x84, 0xAA, 0x64, 0x25, 0x47, 0x14, 0x80, 0x84, 0x4E, 0x5B, 0xE2, 0xD7, 0x05, 0x3E, 0x87, 0x22, 0x03, 0x64, 0x79, 0xBD, 0xCB, 0x36, 0x38, 0x35, 0xBB, 0x08, 0xB0, 0x10, 0xDD, 0x0C, 0x08, 0x0E, 0x3D, 0x85, 0x24, 0xAE, 0x62, 0x21, 0x3E, 0x20, 0x8E, 0xC4, 0x12, 0xD0, 0x1F, 0xC9, 0xCE, 0xFA, 0x9C, 0x0A, 0xBD, 0x39, 0x64, 0x96, 0x45, 0x51, 0x84, 0xDB, 0x24, 0x4A, 0xD6, 0xBE, 0xB4, 0x5F, 0xB7, 0x68, 0x47, 0x91, 0x62, 0x47, 0x44, 0x33, 0x52, 0x0C, 0xE0, 0x63, 0x03, 0xFF, 0xC6, 0x06, 0x07, 0xDD, 0x43, 0x29, 0x62, 0x88, 0x4F, 0x8A, 0xA6, 0x54, 0x39, 0x98, 0xE1, 0xFB, 0x24, 0xDA, 0xF8, 0xAB, 0x3F, 0xF8, 0x62, 0xA8, 0x16, 0xA3, 0x98, 0x28, 0xF5, 0x7B, 0x54, 0x7A, 0xE7, 0x66, 0x98, 0x3F, 0x7C, 0xFA, 0xC8, 0x50, 0x23, 0xDC, 0x65, 0x53, 0x43, 0x12, 0x74, 0xB8, 0x40, 0x19, 0xDB, 0xD8, 0x5D, 0x2C, 0x42, 0x9D, 0x2B, 0x01, 0xE3, 0xC0, 0xA5, 0xDE, 0x1E, 0x6C, 0xC8, 0x5E, 0x62, 0x57, 0x9B, 0x00, 0x12, 0x6E, 0x6F, 0xE8, 0x1A, 0xB2, 0xEC, 0x08, 0x85, 0xD4, 0x30, 0x98, 0xA6, 0xF2, 0x15, 0x94, 0xD6, 0x67, 0x0F, 0x3E, 0xAB, 0x54, 0xEF, 0x3E, 0x30, 0xC7, 0x38, 0x96, 0x46, 0x1F, 0xE3, 0xCA, 0x4E, 0x8E, 0xD9, 0x29, 0x3E, 0x4F, 0x27, 0x6E, 0x18, 0xAA, 0xC8, 0x54, 0x46, 0xC0, 0xC2, 0x34, 0xFF, 0x6F, 0x9A, 0xE1, 0x1A, 0x09, 0x89, 0x9B, 0x3D, 0x22, 0x1C, 0xC6, 0xC4, 0xB3, 0x63, 0xF7, 0xBE, 0x27, 0xAD, 0xF3, 0xF5, 0x1C, 0xE4, 0xBD, 0x8F, 0x51, 0xC2, 0x1C, 0x7F, 0x44, 0xE3, 0x08, 0x3C, 0x8D, 0x04, 0x71, 0x24, 0x08, 0x4C, 0x1E, 0xDB, 0x09, 0x0A, 0x7D, 0x80, 0x56, 0x51, 0x7B, 0xBB, 0xD1, 0xF1, 0x87, 0xC4, 0x27, 0xDD, 0xA5, 0x9E, 0x54, 0x5E, 0x8C, 0x60, 0x03, 0xCA, 0x0B, 0xC5, 0xBD, 0x38, 0x9E, 0xBD, 0x90, 0xB9, 0x97, 0x08, 0xC3, 0xD3, 0xC7, 0x40, 0x44, 0xEB, 0x2A, 0xB3, 0xCA, 0x6F, 0x72, 0xD4, 0xB2, 0xD4, 0x91, 0x02, 0xB9, 0x74, 0x89, 0x64, 0x56, 0xFC, 0x67, 0x38, 0xE9, 0x0B, 0x94, 0x8C, 0x62, 0xE0, 0x16, 0x17, 0x14, 0x87, 0x1F, 0x57, 0x41, 0x9E, 0xCB, 0xAA, 0x16, 0xD0, 0x16, 0x65, 0xAC, 0xEB, 0x39, 0x69, 0xB4, 0x84, 0xA2, 0xE0, 0x29, 0xED, 0x6A, 0x73, 0x30, 0x0E, 0x06, 0xC8, 0x50, 0xAF, 0xEF, 0xFC, 0x08, 0xCE, 0x29, 0x61, 0x85, 0x4E, 0x9A, 0xA0, 0x65, 0x38, 0xFF, 0x6D, 0x9F, 0x5A, 0xEE, 0xAF, 0x57, 0x76, 0x1C, 0xB6, 0xAE, 0x36, 0x87, 0x1D, 0xC4, 0x17, 0x33, 0x2F, 0x30, 0x63, 0xBF, 0x91, 0x37, 0x21, 0x22, 0x68, 0xC3, 0x1F, 0x27, 0x8D, 0xC6, 0x85, 0xC1, 0xAD, 0x44, 0xD2, 0x22, 0x56, 0x6F, 0x9F, 0x18, 0x82, 0x3D, 0x55, 0x0E, 0x89, 0x86, 0x51, 0xD7, 0x65, 0x57, 0x1A, 0x10, 0x69, 0xB8, 0x27, 0x48, 0x61, 0x85, 0x34, 0x59, 0xCF, 0x49, 0xDB, 0x92, 0x37, 0x44, 0xC9, 0xC5, 0xC9, 0x3D, 0xD2, 0x6F, 0x66, 0x3F, 0x9A, 0xDD, 0xD0, 0xBF, 0x56, 0x38, 0x05, 0xB4, 0xB7, 0x47, 0xC0, 0xA6, 0xE5, 0xB5, 0x86, 0x90, 0x0C, 0x57, 0x25, 0x96, 0xF2, 0x12, 0x01, 0xD3, 0x74, 0x55, 0x53, 0xCA, 0x09, 0xD2, 0x19, 0xCB, 0x01, 0x79, 0xF0, 0xB1, 0x00, 0x17, 0xF0, 0xF1, 0x4D, 0x5A, 0xF3, 0xB9, 0x4B, 0xB4, 0xA9, 0x38, 0x61, 0x78, 0xA8, 0x2D, 0x2B, 0x14, 0x11, 0xED, 0x8B, 0x95, 0xAC, 0x40, 0xAE, 0x73, 0xB2, 0x36, 0xD9, 0xB7, 0x83, 0x25, 0x0F, 0x1B, 0x9B, 0xBD, 0xBD, 0x88, 0xC0, 0x9E, 0xEB, 0x29, 0x0A, 0x83, 0xD8, 0x0A, 0x44, 0x47, 0x60, 0xB9, 0x83, 0xB2, 0x70, 0x20, 0xF1, 0x28, 0xED, 0x00, 0xE5, 0xD1, 0xD3, 0xBB, 0xC8, 0xCE, 0x86, 0x21, 0x4E, 0xB5, 0xF5, 0x33, 0xCC, 0x80, 0xF2, 0x78, 0xB1, 0x92, 0xB5, 0x7A, 0xBB, 0x0F, 0xFA, 0x70, 0x3E, 0xBF, 0x0B, 0xAA, 0xE4, 0x92, 0x6D, 0x63, 0xC0, 0xFF, 0x51, 0x8A, 0x9B, 0xBE, 0xB3, 0x48, 0xD5, 0xB5, 0xA0, 0x4F, 0x6F, 0xFF, 0xCF, 0xD3, 0xA4, 0x25, 0xE5, 0x08, 0xBD, 0xAB, 0x88, 0xB4, 0x05, 0x7D, 0x94, 0xD6, 0xF8, 0xB1, 0xB0, 0x56, 0x78, 0x3F, 0xE4, 0x0B, 0xE6, 0xD6, 0xEF, 0xDF, 0x53, 0x1F, 0x52, 0x81, 0x15, 0xE2, 0xB3, 0x21, 0x11, 0xD2, 0xB7, 0xCE, 0x59, 0x90, 0x84, 0xE2, 0x0F, 0x9E, 0xAD, 0x59, 0x5A, 0xC9, 0x15, 0xCB, 0xAB, 0x2A, 0x48, 0x6C, 0x98, 0x5F, 0xB5, 0x0F, 0x6E, 0x2F, 0x3E, 0x16, 0x02, 0xD8, 0xE8, 0xCF, 0xA7, 0x68, 0x5A, 0xAA, 0x30, 0x5C, 0x06, 0x0F, 0x11, 0xDB, 0x98, 0x07, 0x40, 0xBB, 0xF4, 0xBD, 0xF4, 0xA7, 0x1A, 0x1C, 0x7E, 0x37, 0xC6, 0xC6, 0xE8, 0x91, 0x20, 0xAD, 0x91, 0x2C, 0x2F, 0x2A, 0xC0, 0x25, 0x0F, 0x0F, 0xCE, 0x82, 0x6C, 0x55, 0xB6, 0xFB, 0x0F, 0x63, 0x8D, 0xC0, 0xC5, 0x5E, 0x32, 0x7E, 0x92, 0x2D, 0xC4, 0x53, 0x75, 0x18, 0x69, 0xCD, 0xAB, 0xBC, 0x95, 0xA3, 0xC3, 0x50, 0x36, 0x8A, 0xF7, 0xAB, 0x4C, 0x17, 0xB0, 0x1D, 0x8B, 0xC4, 0x77, 0x74, 0xB9, 0x01, 0xA1, 0x8A, 0xDB, 0x86, 0x98, 0x10, 0x37, 0x67, 0x21, 0xDC, 0x23, 0x3D, 0x81, 0x1D, 0xF2, 0x20, 0x8C, 0x04, 0xDF, 0x9B, 0xEE, 0xB8, 0x28, 0xB0, 0x02, 0xEA, 0xA1, 0xF8, 0x64, 0x09, 0x1C, 0x1C, 0xD0, 0x90, 0xEA, 0x6F, 0xAB, 0xCC, 0x0B, 0x06, 0x4E, 0xD2, 0x91, 0x6A, 0xA1, 0x0F, 0x14, 0x4E, 0xE4, 0x47, 0x0A, 0x75, 0xAB, 0x04, 0xF2, 0xCC, 0xA1, 0xD8, 0xAC, 0x42, 0x48, 0x4D, 0xCE, 0x93, 0x46, 0x76, 0xE7, 0x4A, 0x2A, 0x9E, 0x19, 0xB0, 0x96, 0xF1, 0x08, 0x8E, 0xBD, 0x2F, 0xDE, 0x8D, 0x16, 0x78, 0x46, 0xAA, 0x33, 0xD1, 0x81, 0x31, 0x72, 0xE9, 0x2B, 0x13, 0xB6, 0x70, 0x81, 0xC4, 0x4C, 0x35, 0xF2, 0x55, 0xBB, 0x23, 0x6D, 0x0C, 0xF2, 0x9A, 0x58, 0xD0, 0xCC, 0xDE, 0xC3, 0x70, 0xC8, 0x6F, 0x84, 0x0D, 0xC6, 0xF9, 0x7A, 0x74, 0xBF, 0xAA, 0xCE, 0xFA, 0xBA, 0x55, 0x65, 0xD7, 0x73, 0x62, 0x3A, 0x24, 0x32, 0x92, 0xE6, 0xDC, 0x76, 0x57, 0x39, 0x23, 0xD5, 0x9A, 0xC4, 0x43, 0xDB, 0x86, 0xA3, 0x12, 0x9A, 0x54, 0x73, 0xB1, 0x19, 0x4D, 0x21, 0xA4, 0x61, 0xF6, 0x11, 0x4F, 0xDE, 0xC3, 0xA6, 0xD3, 0x8F, 0x28, 0xB3, 0x9B, 0x87, 0xF2, 0xEA, 0x06, 0x86, 0x67, 0x40, 0x94, 0x6B, 0x0D, 0x09, 0x7A, 0xF4, 0xB2, 0xC0, 0x6D, 0x36, 0xE9, 0xFC, 0xD2, 0x40, 0x48, 0x90, 0x8E, 0x38, 0xA6, 0xF7, 0x6E, 0xAB, 0xBC, 0x19, 0x76, 0x17, 0x92, 0x82, 0xEB, 0x0E, 0x51, 0xD0, 0xE8, 0x3B, 0xE5, 0xCD, 0x93, 0xE6, 0x14, 0xC1, 0x6B, 0xEC, 0x1E, 0xEC, 0xB9, 0xF1, 0x81, 0x08, 0x61, 0x70, 0x47, 0x59, 0xD1, 0xA0, 0x78, 0x92, 0xBF, 0x52, 0xF5, 0x5F, 0x89, 0x39, 0xA4, 0xDC, 0x30, 0x88, 0xFA, 0x16, 0x65, 0xF1, 0x35, 0xBD, 0x04, 0x77, 0xD0, 0x2D, 0xCD, 0xE5, 0x7E, 0x0C, 0x1C, 0x0F, 0xAC, 0x0F, 0xA7, 0x0A, 0x25, 0x6F, 0x9B, 0x9B, 0xEB, 0xC7, 0xEB, 0x33, 0xF6, 0x6D, 0xB4, 0xE7, 0x9D, 0xF4, 0xB0, 0x70, 0xD8, 0x31, 0x81, 0x56, 0xFD, 0x65, 0xE1, 0xB3, 0x6D, 0x37, 0xAC, 0xF9, 0xB0, 0xAA, 0xF0, 0x7C, 0x60, 0x34, 0x37, 0xC4, 0xA3, 0xD2, 0xFA, 0x2D, 0xCE, 0x6B, 0xCF, 0xAF, 0x18, 0x3F, 0x92, 0x1C, 0x6E, 0xE3, 0xE8, 0x7B, 0xD1, 0x75, 0x05, 0x7B, 0xC9, 0x97, 0xF9, 0x0D, 0x18, 0x59, 0xEF, 0x76, 0x01, 0xE6, 0x8D, 0x35, 0x84, 0x62, 0xAF, 0xE3, 0xBA, 0xD1, 0x92, 0x83, 0x60, 0xE1, 0xAA, 0xFC, 0xCC, 0x17, 0x0D, 0x0F, 0xD7, 0x65, 0x18, 0x0B, 0x57, 0xB0, 0x33, 0xCF, 0xCC, 0xE2, 0x89, 0x87, 0x8F, 0x41, 0x9B, 0x7D, 0x44, 0x71, 0xB7, 0xB0, 0xF3, 0xBF, 0x42, 0x56, 0xC0, 0x68, 0xDB, 0xCD, 0xBA, 0x7B, 0x0F, 0x20, 0x2C, 0xC7, 0x52, 0x9A, 0x76, 0xC0, 0x9D, 0xB1, 0x66, 0xA1, 0x98, 0x5E, 0x10, 0xB4, 0x6F, 0x83, 0x0F, 0x08, 0xF7, 0x3E, 0xB2, 0x54, 0xCC, 0x3E, 0x33, 0xD6, 0x90, 0xDF, 0xAB, 0xED, 0x3F, 0x77, 0xE4, 0xC4, 0x65, 0x47, 0x39, 0x90, 0x9E, 0x86, 0x1D, 0x04, 0x87, 0x49, 0x35, 0xD1, 0x20, 0x5D, 0xF3, 0x94, 0x1B, 0x10, 0x3D, 0x60, 0xF7, 0x1C, 0x36, 0x2B, 0xF0, 0x21, 0x91, 0x93, 0xF9, 0xAD, 0xAE, 0x49, 0xD3, 0x06, 0xF5, 0x0A, 0x34, 0x79, 0x09, 0x70, 0x8A, 0x41, 0x7C, 0x74, 0xF8, 0xB8, 0xC4, 0x4D, 0x8C, 0x7F, 0xBE, 0xD5, 0x2F, 0x1A, 0x00, 0x98, 0x88, 0xED, 0x7D, 0xA2, 0x55, 0x12, 0xD7, 0x3C, 0xA3, 0x76, 0x02, 0xD4, 0x6E, 0xEC, 0x02, 0x9D, 0x4F, 0x16, 0x84, 0x91, 0xC7, 0x0F, 0x2D, 0x0F, 0x13, 0x58, 0xCE, 0x37, 0x0C, 0x2C, 0xF2, 0x82, 0x35, 0x00, 0xE9, 0x89, 0xFB, 0x24, 0x72, 0x3C, 0x21, 0xDD, 0xA0, 0x82, 0x09, 0x05, 0x03, 0x82, 0x09, 0x01, 0x00, 0x94, 0x06, 0xE4, 0xDC, 0xE8, 0x12, 0xBE, 0x92, 0xE1, 0x53, 0xE0, 0x75, 0x2C, 0xFE, 0x26, 0xC1, 0x12, 0x7E, 0x9C, 0x80, 0xC8, 0x11, 0x3E, 0x12, 0x16, 0x95, 0xF9, 0x01, 0x4E, 0x03, 0xFF, 0xF1, 0xFD, 0x7B, 0xE3, 0xB0, 0xF4, 0x0E, 0xEE, 0x5B, 0x02, 0xF5, 0x60, 0x1E, 0x2F, 0xC3, 0xAF, 0xF0, 0xCD, 0xF7, 0xE7, 0xE7, 0x34, 0x99, 0x9C, 0x7F, 0xC4, 0xEB, 0x9D, 0xDA, 0x81, 0x8C, 0x52, 0x06, 0x93, 0xFE, 0x38, 0xE4, 0x49, 0xBE, 0x4C, 0xCF, 0x03, 0xFE, 0xA1, 0x72, 0x8E, 0x4C, 0xCA, 0x64, 0xFD, 0x11, 0x0B, 0xFC, 0x8E, 0xC9, 0xCB, 0x79, 0x50, 0x3B, 0xD5, 0x53, 0xF5, 0x89, 0x9A, 0x2F, 0x63, 0x16, 0x5D, 0x19, 0x32, 0x72, 0x7D, 0xB7, 0x44, 0x72, 0x65, 0xF7, 0x96, 0xF4, 0xFD, 0xBC, 0xFE, 0xA6, 0xF4, 0x05, 0x9E, 0x88, 0x34, 0x34, 0xC7, 0x98, 0xB8, 0x68, 0xF9, 0x86, 0x60, 0x5D, 0x4D, 0x03, 0xD3, 0x04, 0xB6, 0x77, 0xE3, 0x0F, 0xF7, 0xD7, 0x83, 0x0A, 0xDD, 0x06, 0x65, 0x2B, 0xCC, 0x1B, 0xF0, 0x4D, 0x33, 0xDF, 0xFE, 0xFC, 0xEF, 0x63, 0x4A, 0xF5, 0xBA, 0xE0, 0xD5, 0xC6, 0xBA, 0xB6, 0xC5, 0x64, 0xF1, 0x95, 0x20, 0x82, 0xAA, 0x38, 0x25, 0x53, 0x20, 0x01, 0x9C, 0xBC, 0x8E, 0xCA, 0x07, 0x3D, 0x80, 0xAF, 0x0A, 0x59, 0x6E, 0x4D, 0x33, 0xAD, 0x73, 0xB4, 0xF1, 0xED, 0xD4, 0x20, 0xE0, 0x90, 0x0B, 0xED, 0x47, 0x49, 0x5A, 0x88, 0x62, 0xD4, 0xA9, 0xCD, 0xDE, 0xD0, 0xDE, 0xA7, 0x74, 0xCD, 0xE0, 0x23, 0x8C, 0x71, 0x2B, 0x8A, 0xA9, 0x82, 0x47, 0x56, 0x66, 0x0D, 0x2B, 0x34, 0xE4, 0x7E, 0x4B, 0x59, 0x42, 0x5F, 0x17, 0xA9, 0x60, 0x8D, 0xAD, 0x38, 0x28, 0xEC, 0x9D, 0x8A, 0xDB, 0x5D, 0xD3, 0x8C, 0x7D, 0x53, 0xDD, 0xA6, 0xDA, 0xC7, 0x4D, 0x3F, 0xD0, 0x3C, 0x00, 0xB5, 0x9E, 0xE9, 0xA0, 0xE5, 0x27, 0x6E, 0x3E, 0x75, 0xD0, 0x13, 0x61, 0x01, 0x66, 0x49, 0x1D, 0x87, 0x3A, 0x7D, 0xA2, 0xC9, 0xFD, 0xA3, 0x60, 0xA6, 0x47, 0x73, 0x25, 0x00, 0x58, 0x41, 0x8F, 0xA7, 0x62, 0x63, 0x2D, 0xCB, 0x12, 0x63, 0x85, 0x27, 0x32, 0x60, 0x02, 0x18, 0x67, 0x53, 0xE6, 0xB5, 0xD3, 0x31, 0xE5, 0x64, 0x23, 0xC9, 0x70, 0x9D, 0x34, 0x9C, 0x69, 0x5A, 0x32, 0x8A, 0x56, 0x2B, 0x13, 0x9A, 0xF5, 0x98, 0xF8, 0x5D, 0xCB, 0x35, 0x98, 0x40, 0x7D, 0x82, 0xF8, 0x49, 0xC2, 0x9A, 0x87, 0xDC, 0x41, 0xFA, 0xA7, 0x69, 0x8F, 0xAC, 0x7F, 0x20, 0x4D, 0x70, 0xD0, 0x7D, 0x4A, 0xDC, 0x1D, 0x68, 0xFB, 0x46, 0x08, 0x63, 0xBB, 0x00, 0x2F, 0x3A, 0x23, 0x57, 0xCB, 0x65, 0xFB, 0x4B, 0x03, 0xBA, 0xB6, 0x8D, 0xB9, 0xB1, 0x1A, 0x09, 0xC9, 0x02, 0xE8, 0x12, 0x95, 0x91, 0x54, 0x16, 0xB4, 0x51, 0xD8, 0xE5, 0xFB, 0xF7, 0x81, 0x33, 0xBE, 0xD2, 0x81, 0x81, 0x37, 0x17, 0xE3, 0x74, 0xC5, 0xB4, 0x15, 0xE7, 0x77, 0x3F, 0x95, 0xD8, 0x3D, 0x8B, 0xF9, 0x7D, 0x4A, 0xC4, 0x5E, 0xAC, 0x28, 0x1E, 0x50, 0x89, 0x69, 0x32, 0xF7, 0xEE, 0xA4, 0x83, 0xE6, 0x98, 0xED, 0xD6, 0x07, 0xC3, 0xFF, 0xDD, 0xD3, 0x4C, 0x56, 0x67, 0x03, 0x28, 0xEB, 0xA5, 0xE1, 0xEB, 0x24, 0x9B, 0x8E, 0x26, 0x85, 0x38, 0xBF, 0x4C, 0xF3, 0x43, 0x2E, 0xD5, 0xA9, 0x33, 0xB8, 0x2E, 0x6C, 0x0E, 0x96, 0x0D, 0xE1, 0x8A, 0x20, 0x9F, 0xA3, 0x90, 0x96, 0x93, 0x87, 0x88, 0x4D, 0xAD, 0x8D, 0x8E, 0xE7, 0xE6, 0x0A, 0x89, 0x69, 0x90, 0x62, 0x16, 0x2F, 0x90, 0xBB, 0x28, 0xE4, 0xCC, 0xBA, 0x1A, 0x5F, 0x52, 0x6D, 0xE9, 0xCF, 0x7F, 0xEF, 0xEC, 0x7A, 0x77, 0xDD, 0xA0, 0x7C, 0xD7, 0x00, 0x09, 0xE4, 0x8E, 0xBF, 0x8E, 0xDD, 0x9B, 0x34, 0x87, 0x26, 0xA9, 0x37, 0xE1, 0x4F, 0xF5, 0xEB, 0x6E, 0x79, 0xE3, 0xDB, 0x1B, 0x60, 0xD7, 0x0A, 0x73, 0x05, 0x11, 0x15, 0x4A, 0x8A, 0xB8, 0x75, 0xF8, 0x6D, 0xEB, 0xCB, 0x9D, 0x79, 0x0F, 0xC4, 0x32, 0x84, 0x4E, 0x90, 0x3C, 0x8B, 0xD9, 0xFD, 0xB2, 0x8F, 0x99, 0x88, 0xDF, 0xAE, 0xA5, 0x56, 0xE9, 0x20, 0xE5, 0x79, 0x25, 0x47, 0xAE, 0xA7, 0xA4, 0x5B, 0x4C, 0x7E, 0x68, 0x41, 0x61, 0x1E, 0x33, 0x06, 0x4E, 0x5C, 0xB5, 0x9B, 0xBA, 0xEC, 0xA6, 0x9E, 0x38, 0xA0, 0x99, 0x94, 0xAE, 0xEA, 0x3D, 0x10, 0xF6, 0xFC, 0x53, 0xF6, 0x43, 0x56, 0x2F, 0xA0, 0x0A, 0x34, 0x12, 0xD4, 0xAF, 0xF8, 0x01, 0xD4, 0x8D, 0x0C, 0x58, 0xBA, 0x05, 0x5A, 0x42, 0xCD, 0xF6, 0xB8, 0xF1, 0x86, 0x16, 0x99, 0xEF, 0xD9, 0xAD, 0x9D, 0xF4, 0xCB, 0xB9, 0x88, 0xE7, 0x22, 0x17, 0x12, 0xBB, 0x42, 0xA4, 0x3B, 0xE8, 0x32, 0x25, 0x09, 0x11, 0x1D, 0x3A, 0x8E, 0xBC, 0x97, 0xFA, 0xEB, 0xF9, 0xF8, 0x5D, 0x69, 0x20, 0x76, 0x5A, 0x18, 0x2A, 0xD9, 0xC4, 0x54, 0x27, 0x99, 0x31, 0x70, 0x5E, 0xA2, 0x90, 0x3F, 0x6E, 0x18, 0x7D, 0x2A, 0xF6, 0xA5, 0xE4, 0xA8, 0x30, 0x54, 0x16, 0x8A, 0xA6, 0xA6, 0xF1, 0x27, 0xC8, 0xCE, 0x0C, 0x56, 0xA2, 0xEF, 0x67, 0xDC, 0x1C, 0xD9, 0xB2, 0x2A, 0x51, 0x39, 0xDA, 0xC1, 0x92, 0xFF, 0xC5, 0x3A, 0x13, 0xEC, 0x52, 0xA3, 0x22, 0x07, 0xA9, 0x6A, 0x4F, 0xED, 0xB1, 0x20, 0x55, 0xFF, 0xDD, 0xBE, 0xE6, 0xAE, 0xF0, 0x72, 0xF7, 0x5D, 0xB7, 0xC6, 0xCD, 0x37, 0xB2, 0x58, 0x9D, 0xC0, 0x0F, 0xBE, 0xF1, 0x33, 0x3E, 0xB1, 0x13, 0xC8, 0x22, 0x1B, 0xF8, 0x74, 0x0F, 0xD7, 0xBF, 0x7F, 0x39, 0xA5, 0x7E, 0x4A, 0xE2, 0xCE, 0x86, 0xE0, 0xE8, 0xB4, 0xE9, 0x21, 0x4D, 0x67, 0x21, 0x46, 0xED, 0xE9, 0x85, 0x87, 0x15, 0x71, 0x56, 0x5E, 0x9F, 0x59, 0xCD, 0xA5, 0x92, 0x22, 0xAC, 0x9C, 0x6C, 0x00, 0xD5, 0xA7, 0xC9, 0xD8, 0xA3, 0xE5, 0x46, 0xDE, 0xC8, 0x3C, 0x65, 0x54, 0xEA, 0x89, 0x13, 0x72, 0xBB, 0xCA, 0xE7, 0xD7, 0x76, 0x88, 0xDE, 0xD6, 0x0B, 0x52, 0x6C, 0x04, 0xC9, 0xBF, 0x0A, 0x7D, 0x96, 0x56, 0x81, 0x90, 0x4D, 0xAC, 0x03, 0x79, 0x1F, 0x08, 0xB0, 0x71, 0xF0, 0xEE, 0x5B, 0xAB, 0xA1, 0xC4, 0x6B, 0x15, 0x61, 0x75, 0x6E, 0x58, 0x9C, 0x33, 0x7B, 0xAB, 0x4F, 0x2B, 0x75, 0xAE, 0x3B, 0xF6, 0xE7, 0x74, 0x3F, 0x6C, 0xEE, 0x5F, 0x09, 0x93, 0xE7, 0x18, 0xC9, 0x58, 0x4D, 0x47, 0xEA, 0xD4, 0xC9, 0x61, 0xAE, 0x96, 0xF6, 0xD6, 0x02, 0xA5, 0x06, 0xA2, 0xA4, 0xC0, 0xF5, 0x7E, 0x88, 0x1D, 0x51, 0xDC, 0x24, 0xF2, 0x77, 0xEB, 0xA9, 0xCC, 0x3C, 0x6F, 0x23, 0x58, 0x29, 0xB5, 0xBA, 0x87, 0xC2, 0x1F, 0x12, 0x32, 0x1C, 0xEE, 0x8B, 0x6E, 0xE9, 0x08, 0x9B, 0xB5, 0x2C, 0x3A, 0x71, 0xAD, 0x61, 0x12, 0x46, 0xAE, 0xD9, 0x80, 0xC1, 0xB9, 0x47, 0xA6, 0x7C, 0x88, 0xA1, 0x10, 0xA7, 0xBD, 0x84, 0x49, 0xD0, 0x9C, 0xE3, 0x90, 0x6C, 0x65, 0x35, 0x45, 0x7D, 0x02, 0xF2, 0x32, 0x5C, 0x70, 0xEE, 0x78, 0x63, 0xAE, 0x63, 0x23, 0x0F, 0xC2, 0x3D, 0xEC, 0xA2, 0x99, 0xBB, 0x5B, 0x0E, 0x4B, 0x1A, 0xE8, 0xE2, 0x40, 0x1D, 0xFB, 0x9D, 0x4B, 0xDD, 0xD0, 0x61, 0x18, 0xBD, 0x15, 0x0F, 0x4B, 0x5C, 0xD3, 0x85, 0xAF, 0xB4, 0xFA, 0xD4, 0xEC, 0xA4, 0x6D, 0x61, 0xBE, 0xCA, 0xB1, 0x1D, 0x02, 0x70, 0x26, 0x67, 0x33, 0x33, 0xAB, 0x31, 0x4B, 0x9E, 0xF9, 0x1B, 0x7A, 0x7F, 0x94, 0x0B, 0xDA, 0x44, 0x44, 0xAE, 0xFE, 0x37, 0x03, 0x6A, 0x43, 0xF2, 0xB6, 0x8D, 0x0D, 0xFF, 0xD7, 0xAF, 0x33, 0xA3, 0x63, 0x0F, 0xDB, 0x32, 0x5A, 0x74, 0xDA, 0x7B, 0x09, 0x0F, 0x94, 0x9D, 0x06, 0x4B, 0xF7, 0x45, 0xB8, 0x93, 0x37, 0x15, 0x2B, 0x98, 0x0E, 0x4E, 0x20, 0xCC, 0x23, 0xFF, 0xAF, 0xCC, 0xBC, 0x7E, 0x95, 0x77, 0x04, 0xE9, 0x4B, 0xE7, 0xF3, 0xE8, 0x5F, 0x7F, 0xE8, 0x49, 0x6F, 0xD5, 0xAA, 0xB9, 0x67, 0xB2, 0x7C, 0x3F, 0x17, 0x3E, 0x26, 0x26, 0x80, 0xD0, 0x44, 0x08, 0x85, 0xE6, 0xC0, 0xB2, 0xAA, 0xB0, 0x9A, 0xB8, 0x1F, 0x6D, 0xE5, 0xB2, 0x2D, 0x17, 0xD5, 0xA2, 0x11, 0x97, 0xD6, 0x98, 0x93, 0xBE, 0xED, 0x51, 0x83, 0x4E, 0x2D, 0x7E, 0x3D, 0xAF, 0xF0, 0x4C, 0xF8, 0x4A, 0xA9, 0xC7, 0x79, 0x6E, 0xBB, 0x6A, 0xE2, 0x06, 0xC4, 0xE1, 0x66, 0x25, 0xFD, 0xFD, 0x61, 0x39, 0x85, 0x05, 0x48, 0x06, 0x26, 0x7C, 0xD6, 0x9B, 0xFA, 0x8F, 0x5D, 0xD6, 0x0F, 0x4F, 0x21, 0x94, 0x12, 0xDF, 0x2B, 0xAB, 0xC9, 0x56, 0x41, 0xAE, 0x15, 0x54, 0x87, 0xFA, 0xF4, 0x13, 0x33, 0xF5, 0xE5, 0x1B, 0xEF, 0xC2, 0xF9, 0x63, 0xE6, 0x2B, 0x74, 0x8B, 0x3D, 0x9C, 0x20, 0x20, 0x66, 0xD1, 0xEC, 0xBA, 0xB6, 0x03, 0x21, 0x79, 0x10, 0x58, 0x9B, 0xB9, 0x69, 0x55, 0x21, 0xA5, 0xC5, 0x2F, 0x12, 0x38, 0x2F, 0x0D, 0xE3, 0x24, 0x3F, 0x9E, 0x92, 0xED, 0x60, 0x53, 0x12, 0x63, 0x7D, 0xCC, 0xE5, 0xAD, 0x80, 0x7D, 0xA0, 0xC9, 0x2E, 0x99, 0x32, 0x52, 0x05, 0x20, 0x41, 0xC7, 0xB6, 0x8F, 0x4E, 0xB1, 0xBB, 0xB7, 0x08, 0x5A, 0x5B, 0x02, 0x04, 0x77, 0x98, 0x92, 0x30, 0xCB, 0xA8, 0x9F, 0x96, 0x6D, 0x34, 0x97, 0xC4, 0x04, 0x3D, 0x05, 0x6F, 0x79, 0x7E, 0xA0, 0xB4, 0x8E, 0x24, 0x7C, 0xAB, 0xBC, 0x7E, 0x59, 0x73, 0x07, 0xDA, 0x60, 0x5A, 0x00, 0x81, 0x45, 0x45, 0x51, 0xC8, 0x96, 0xAB, 0x4E, 0xE1, 0x34, 0x6B, 0x90, 0x4E, 0x35, 0x8A, 0x58, 0xCA, 0x2F, 0x7B, 0x93, 0xDA, 0x32, 0x9D, 0x08, 0x0A, 0x49, 0xDC, 0xF9, 0xD2, 0xC9, 0xD1, 0xBB, 0xD6, 0xBA, 0x82, 0x6C, 0xA7, 0x13, 0x3A, 0xB2, 0xDF, 0x61, 0xD7, 0x13, 0x16, 0xEB, 0xDD, 0xED, 0x88, 0x2E, 0x49, 0x83, 0xB7, 0x67, 0x46, 0xF7, 0x14, 0x36, 0xD2, 0xD7, 0xC1, 0x4D, 0x94, 0x34, 0x71, 0x70, 0xEE, 0x00, 0x15, 0x54, 0x00, 0x28, 0x1B, 0xD3, 0xC6, 0xBF, 0xE5, 0xEC, 0xBF, 0x69, 0xDE, 0xA0, 0x59, 0x01, 0x63, 0xE3, 0xA2, 0x97, 0x10, 0xC4, 0x10, 0x7A, 0x08, 0xD4, 0xDD, 0x30, 0xFD, 0x6E, 0x05, 0x0E, 0xA1, 0xE9, 0xE3, 0xF3, 0xBA, 0xCD, 0x74, 0x10, 0x35, 0xE3, 0x47, 0x18, 0xAF, 0xA9, 0xA9, 0xC8, 0xAB, 0x19, 0xEA, 0x9C, 0xD8, 0x75, 0x11, 0xCC, 0x59, 0xCC, 0x60, 0x1B, 0xC6, 0x3B, 0x82, 0x0F, 0xD0, 0x96, 0x87, 0x1F, 0x95, 0x26, 0x34, 0xA2, 0xA3, 0x78, 0x87, 0x83, 0xAA, 0xE7, 0x6D, 0xA2, 0x05, 0xB1, 0xEB, 0x5E, 0x94, 0x42, 0x16, 0x19, 0xFF, 0x47, 0x52, 0x5F, 0x05, 0x62, 0xE4, 0xA3, 0x63, 0x3A, 0xC7, 0xC4, 0x01, 0x7D, 0xA2, 0xC8, 0x13, 0x07, 0xBD, 0xBD, 0x74, 0xB2, 0xD9, 0x16, 0x1E, 0x99, 0xC1, 0x68, 0x6A, 0x9A, 0xB1, 0xC9, 0x44, 0x1B, 0x0D, 0x35, 0xC1, 0xCE, 0x7E, 0x9A, 0x62, 0x88, 0x28, 0x92, 0x85, 0x02, 0x33, 0x20, 0x88, 0x9B, 0x63, 0x9E, 0xB9, 0xCD, 0x0A, 0x56, 0x92, 0x93, 0xE3, 0x67, 0xC2, 0xBD, 0x1F, 0xEA, 0x68, 0x7F, 0x45, 0x1B, 0x3D, 0xA8, 0x80, 0x9A, 0x77, 0xCA, 0x31, 0x9D, 0xFC, 0xFF, 0xBA, 0xD4, 0x27, 0x24, 0xF2, 0xE0, 0x67, 0xCB, 0x3A, 0x85, 0xE7, 0x23, 0xCD, 0xD0, 0xEF, 0xC6, 0xB4, 0xC9, 0x7B, 0x5A, 0x13, 0x6B, 0xBE, 0xFC, 0xB6, 0xF1, 0x34, 0x59, 0x2C, 0xED, 0xDD, 0x6A, 0xFC, 0x98, 0x30, 0x36, 0x5D, 0x75, 0xF7, 0x5A, 0x27, 0xCA, 0xC7, 0x22, 0x56, 0x07, 0x8E, 0xD0, 0x20, 0xA4, 0x49, 0x30, 0xDE, 0x9C, 0x35, 0xCE, 0x96, 0xE1, 0x54, 0x4E, 0xE9, 0x85, 0x1B, 0xE6, 0x78, 0x48, 0x2A, 0x32, 0x7C, 0xFA, 0x37, 0xA9, 0x13, 0xE0, 0x45, 0xC8, 0xC2, 0x63, 0xD9, 0xB2, 0x5E, 0xAE, 0x21, 0xA2, 0x66, 0x4A, 0xF9, 0x43, 0x03, 0x95, 0x16, 0x3F, 0x04, 0x56, 0xD1, 0xA5, 0x18, 0xF6, 0x09, 0x7C, 0x96, 0xDB, 0x8F, 0x50, 0x5F, 0x34, 0x40, 0xA6, 0xC8, 0xCC, 0x31, 0xB5, 0x95, 0xAC, 0xFE, 0x9A, 0xA9, 0xCC, 0x1C, 0xCF, 0xF9, 0xFD, 0xA6, 0x56, 0xBC, 0xDB, 0x5E, 0xEB, 0x57, 0xF4, 0x1E, 0x94, 0x67, 0xC6, 0x43, 0xBA, 0x62, 0x79, 0xE5, 0x41, 0xE8, 0x6C, 0x91, 0x07, 0x4E, 0x55, 0xC6, 0x3A, 0xDF, 0x41, 0x51, 0x7C, 0xEA, 0x5A, 0x6F, 0x62, 0x29, 0xF7, 0x10, 0x16, 0x62, 0xBB, 0x0A, 0xA0, 0xCE, 0xAB, 0x2B, 0x7F, 0x62, 0x11, 0x96, 0xC7, 0xA7, 0x7B, 0xB3, 0x27, 0xC7, 0x68, 0xC4, 0x3D, 0x06, 0x9D, 0x71, 0xC3, 0x2C, 0x71, 0x2C, 0x83, 0x1D, 0x68, 0x50, 0xE6, 0xEB, 0x79, 0x3D, 0x7D, 0xEB, 0x08, 0xDE, 0x7A, 0x70, 0x4B, 0x38, 0x6D, 0xFD, 0x2B, 0x30, 0x72, 0xC2, 0x6B, 0x89, 0xDF, 0x8D, 0x07, 0x2B, 0x3E, 0x9F, 0x56, 0x96, 0xA0, 0x73, 0x2E, 0x21, 0x5D, 0xF6, 0xDE, 0x47, 0x5D, 0x3A, 0x69, 0xF1, 0x11, 0x2F, 0x8B, 0x6B, 0x8E, 0xE7, 0x6B, 0x73, 0x9C, 0x92, 0x76, 0xD9, 0xEE, 0x78, 0x17, 0xD9, 0x89, 0xAA, 0x07, 0x90, 0xD4, 0x6F, 0x8B, 0xE9, 0xBC, 0xF8, 0xA9, 0xDE, 0x83, 0xD3, 0xF3, 0xC3, 0x02, 0xA8, 0xAA, 0xBE, 0xE5, 0xC8, 0xFE, 0xBC, 0x2A, 0xDC, 0x70, 0x6F, 0xC0, 0xEA, 0x55, 0xCD, 0x6F, 0x38, 0x37, 0x74, 0xF9, 0x55, 0xFE, 0xC7, 0x0A, 0x5F, 0x83, 0x80, 0x74, 0xDC, 0xB7, 0x31, 0x53, 0x2C, 0x94, 0x9C, 0x88, 0x84, 0xE9, 0x5F, 0xDE, 0xCE, 0x3A, 0x7D, 0x9F, 0x7E, 0xA2, 0x1A, 0xC5, 0xA8, 0xAC, 0xDF, 0xAA, 0x89, 0x68, 0x1E, 0x95, 0x01, 0x4D, 0x5A, 0x23, 0x44, 0x31, 0x5B, 0xF8, 0xB3, 0xFF, 0x97, 0x12, 0xA0, 0x9A, 0x8F, 0xDE, 0xB8, 0x29, 0x4C, 0x25, 0x7D, 0x16, 0xCC, 0xEF, 0xAA, 0x78, 0xDD, 0x0F, 0x5D, 0xFF, 0xE0, 0x49, 0xCE, 0x2B, 0x8A, 0xC7, 0xE1, 0x60, 0x02, 0xED, 0x1E, 0x32, 0x8C, 0x62, 0x86, 0xA1, 0x67, 0x4A, 0x5C, 0x06, 0xF6, 0x28, 0x37, 0xAA, 0xF3, 0xEE, 0xFF, 0xFC, 0x11, 0x46, 0x94, 0x7A, 0x63, 0x0D, 0x82, 0x44, 0xAA, 0x72, 0x89, 0x8D, 0xFE, 0x5B, 0x94, 0x78, 0x63, 0x70, 0x64, 0x8A, 0x13, 0xF0, 0xE1, 0x6D, 0x50, 0x27, 0x77, 0xEB, 0x8D, 0xF9, 0x62, 0xFC, 0x86, 0x3C, 0x77, 0xC1, 0x59, 0xBF, 0x64, 0xCC, 0x2A, 0x47, 0xCA, 0xF6, 0xB2, 0x12, 0xCB, 0xC6, 0x14, 0x2B, 0x5C, 0x9F, 0x5B, 0xFF, 0xE2, 0xDD, 0x3B, 0xB1, 0xF8, 0x63, 0x23, 0x10, 0x74, 0x82, 0x96, 0xBB, 0x81, 0xB3, 0x62, 0xB7, 0xE4, 0x56, 0xEE, 0xE8, 0xDF, 0x29, 0x55, 0xFC, 0xDC, 0x04, 0xE5, 0x5D, 0x25, 0x16, 0xA8, 0x28, 0x07, 0x12, 0xCA, 0x5B, 0x60, 0xEA, 0x90, 0x7D, 0x51, 0xB2, 0xFA, 0x72, 0xF9, 0xC7, 0x3D, 0xA7, 0xFE, 0x2C, 0x25, 0x98, 0x8F, 0x5B, 0xE1, 0xB8, 0x23, 0x68, 0x25, 0xC8, 0x3A, 0x02, 0x38, 0x22, 0x39, 0x40, 0x2A, 0x29, 0x4E, 0xA4, 0xBE, 0x31, 0xA1, 0x7D, 0xBD, 0x31, 0xBA, 0x1B, 0xFF, 0xF8, 0x04, 0xCC, 0x78, 0x2F, 0xED, 0x78, 0x95, 0x09, 0x7F, 0x58, 0x3D, 0xD1, 0x3A, 0xCC, 0x85, 0x49, 0x1B, 0xDD, 0x12, 0x3F, 0xE0, 0x2C, 0x14, 0x12, 0xE3, 0x42, 0x61, 0x7D, 0x9C, 0x26, 0xB8, 0xD9, 0x87, 0x7C, 0xAD, 0x5A, 0x72, 0xD2, 0x32, 0x80, 0xB5, 0x27, 0x61, 0x47, 0xA7, 0x25, 0x84, 0xDA, 0xE6, 0x17, 0x23, 0x15, 0x8B, 0x9A, 0x54, 0x79, 0xD6, 0x6B, 0x6D, 0x8A, 0x6C, 0x4D, 0xB0, 0xF2, 0xE7, 0x1E, 0xDD, 0x46, 0x58, 0x85, 0xC3, 0x3A, 0x69, 0xA8, 0xA7, 0x4E, 0x78, 0x16, 0x08, 0xF0, 0x64, 0x16, 0x86, 0x6D, 0x19, 0x6B, 0x69, 0x5E, 0x70, 0xA4, 0x3B, 0x7D, 0xEA, 0xBE, 0x8C, 0x00, 0x0D, 0x79, 0xEE, 0x16, 0x03, 0xD4, 0x7C, 0x45, 0xCC, 0xB8, 0x5B, 0xBF, 0x79, 0x2D, 0x59, 0x14, 0x6F, 0xA3, 0x22, 0x86, 0x97, 0x6F, 0xF5, 0x91, 0x72, 0x62, 0x96, 0x38, 0xE1, 0xA0, 0x70, 0xCB, 0x0F, 0x0E, 0xCB, 0xF8, 0x09, 0xF9, 0xF5, 0xB8, 0x73, 0xFB, 0xEF, 0x96, 0x87, 0x4F, 0xCD, 0xED, 0x58, 0xA2, 0xC0, 0xA4, 0x99, 0x06, 0xD9, 0x09, 0x1D, 0x29, 0xB2, 0x1D, 0x0A, 0x7B, 0x89, 0x94, 0x52, 0x5D, 0x08, 0x88, 0x74, 0x8F, 0xB7, 0xDE, 0xE1, 0x60, 0xF2, 0xFC, 0xC7, 0x89, 0x52, 0xBB, 0x57, 0xBE, 0x4D, 0x36, 0x68, 0x5B, 0xE4, 0xF2, 0xB1, 0x45, 0xBC, 0xAC, 0x40, 0xE0, 0xDB, 0x30, 0x60, 0x87, 0x2D, 0x81, 0x76, 0x63, 0x91, 0xD4, 0xEC, 0x0B, 0x04, 0x60, 0x9F, 0x4F, 0x2D, 0xA2, 0x28, 0x94, 0x15, 0x45, 0x8D, 0x5F, 0x15, 0x22, 0x3C, 0x8E, 0x91, 0x11, 0x88, 0xC7, 0x82, 0x5F, 0x52, 0xA0, 0xA3, 0xA2, 0xC2, 0xCA, 0x8B, 0x62, 0xA7, 0x4B, 0x03, 0x71, 0x59, 0xE5, 0x4D, 0x99, 0x73, 0xC8, 0x00, 0x54, 0x3D, 0x2F, 0x6C, 0x4C, 0x0D, 0x9E, 0x3B, 0x09, 0x39, 0xC1, 0xC1, 0x68, 0x05, 0xE5, 0x79, 0x46, 0x95, 0x49, 0x9C, 0xE0, 0x13, 0xCF, 0xB9, 0xB0, 0xEA, 0xEE, 0xD8, 0xDD, }, .spki_len = 2374, .spki = { 0x30, 0x82, 0x09, 0x42, 0x30, 0x0F, 0x06, 0x0B, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x02, 0x82, 0x0B, 0x01, 0x08, 0x07, 0x05, 0x00, 0x03, 0x82, 0x09, 0x2D, 0x00, 0x30, 0x82, 0x09, 0x28, 0x03, 0x21, 0x00, 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, 0x03, 0x82, 0x09, 0x01, 0x00, 0x94, 0x06, 0xE4, 0xDC, 0xE8, 0x12, 0xBE, 0x92, 0xE1, 0x53, 0xE0, 0x75, 0x2C, 0xFE, 0x26, 0xC1, 0x12, 0x7E, 0x9C, 0x80, 0xC8, 0x11, 0x3E, 0x12, 0x16, 0x95, 0xF9, 0x01, 0x4E, 0x03, 0xFF, 0xF1, 0xFD, 0x7B, 0xE3, 0xB0, 0xF4, 0x0E, 0xEE, 0x5B, 0x02, 0xF5, 0x60, 0x1E, 0x2F, 0xC3, 0xAF, 0xF0, 0xCD, 0xF7, 0xE7, 0xE7, 0x34, 0x99, 0x9C, 0x7F, 0xC4, 0xEB, 0x9D, 0xDA, 0x81, 0x8C, 0x52, 0x06, 0x93, 0xFE, 0x38, 0xE4, 0x49, 0xBE, 0x4C, 0xCF, 0x03, 0xFE, 0xA1, 0x72, 0x8E, 0x4C, 0xCA, 0x64, 0xFD, 0x11, 0x0B, 0xFC, 0x8E, 0xC9, 0xCB, 0x79, 0x50, 0x3B, 0xD5, 0x53, 0xF5, 0x89, 0x9A, 0x2F, 0x63, 0x16, 0x5D, 0x19, 0x32, 0x72, 0x7D, 0xB7, 0x44, 0x72, 0x65, 0xF7, 0x96, 0xF4, 0xFD, 0xBC, 0xFE, 0xA6, 0xF4, 0x05, 0x9E, 0x88, 0x34, 0x34, 0xC7, 0x98, 0xB8, 0x68, 0xF9, 0x86, 0x60, 0x5D, 0x4D, 0x03, 0xD3, 0x04, 0xB6, 0x77, 0xE3, 0x0F, 0xF7, 0xD7, 0x83, 0x0A, 0xDD, 0x06, 0x65, 0x2B, 0xCC, 0x1B, 0xF0, 0x4D, 0x33, 0xDF, 0xFE, 0xFC, 0xEF, 0x63, 0x4A, 0xF5, 0xBA, 0xE0, 0xD5, 0xC6, 0xBA, 0xB6, 0xC5, 0x64, 0xF1, 0x95, 0x20, 0x82, 0xAA, 0x38, 0x25, 0x53, 0x20, 0x01, 0x9C, 0xBC, 0x8E, 0xCA, 0x07, 0x3D, 0x80, 0xAF, 0x0A, 0x59, 0x6E, 0x4D, 0x33, 0xAD, 0x73, 0xB4, 0xF1, 0xED, 0xD4, 0x20, 0xE0, 0x90, 0x0B, 0xED, 0x47, 0x49, 0x5A, 0x88, 0x62, 0xD4, 0xA9, 0xCD, 0xDE, 0xD0, 0xDE, 0xA7, 0x74, 0xCD, 0xE0, 0x23, 0x8C, 0x71, 0x2B, 0x8A, 0xA9, 0x82, 0x47, 0x56, 0x66, 0x0D, 0x2B, 0x34, 0xE4, 0x7E, 0x4B, 0x59, 0x42, 0x5F, 0x17, 0xA9, 0x60, 0x8D, 0xAD, 0x38, 0x28, 0xEC, 0x9D, 0x8A, 0xDB, 0x5D, 0xD3, 0x8C, 0x7D, 0x53, 0xDD, 0xA6, 0xDA, 0xC7, 0x4D, 0x3F, 0xD0, 0x3C, 0x00, 0xB5, 0x9E, 0xE9, 0xA0, 0xE5, 0x27, 0x6E, 0x3E, 0x75, 0xD0, 0x13, 0x61, 0x01, 0x66, 0x49, 0x1D, 0x87, 0x3A, 0x7D, 0xA2, 0xC9, 0xFD, 0xA3, 0x60, 0xA6, 0x47, 0x73, 0x25, 0x00, 0x58, 0x41, 0x8F, 0xA7, 0x62, 0x63, 0x2D, 0xCB, 0x12, 0x63, 0x85, 0x27, 0x32, 0x60, 0x02, 0x18, 0x67, 0x53, 0xE6, 0xB5, 0xD3, 0x31, 0xE5, 0x64, 0x23, 0xC9, 0x70, 0x9D, 0x34, 0x9C, 0x69, 0x5A, 0x32, 0x8A, 0x56, 0x2B, 0x13, 0x9A, 0xF5, 0x98, 0xF8, 0x5D, 0xCB, 0x35, 0x98, 0x40, 0x7D, 0x82, 0xF8, 0x49, 0xC2, 0x9A, 0x87, 0xDC, 0x41, 0xFA, 0xA7, 0x69, 0x8F, 0xAC, 0x7F, 0x20, 0x4D, 0x70, 0xD0, 0x7D, 0x4A, 0xDC, 0x1D, 0x68, 0xFB, 0x46, 0x08, 0x63, 0xBB, 0x00, 0x2F, 0x3A, 0x23, 0x57, 0xCB, 0x65, 0xFB, 0x4B, 0x03, 0xBA, 0xB6, 0x8D, 0xB9, 0xB1, 0x1A, 0x09, 0xC9, 0x02, 0xE8, 0x12, 0x95, 0x91, 0x54, 0x16, 0xB4, 0x51, 0xD8, 0xE5, 0xFB, 0xF7, 0x81, 0x33, 0xBE, 0xD2, 0x81, 0x81, 0x37, 0x17, 0xE3, 0x74, 0xC5, 0xB4, 0x15, 0xE7, 0x77, 0x3F, 0x95, 0xD8, 0x3D, 0x8B, 0xF9, 0x7D, 0x4A, 0xC4, 0x5E, 0xAC, 0x28, 0x1E, 0x50, 0x89, 0x69, 0x32, 0xF7, 0xEE, 0xA4, 0x83, 0xE6, 0x98, 0xED, 0xD6, 0x07, 0xC3, 0xFF, 0xDD, 0xD3, 0x4C, 0x56, 0x67, 0x03, 0x28, 0xEB, 0xA5, 0xE1, 0xEB, 0x24, 0x9B, 0x8E, 0x26, 0x85, 0x38, 0xBF, 0x4C, 0xF3, 0x43, 0x2E, 0xD5, 0xA9, 0x33, 0xB8, 0x2E, 0x6C, 0x0E, 0x96, 0x0D, 0xE1, 0x8A, 0x20, 0x9F, 0xA3, 0x90, 0x96, 0x93, 0x87, 0x88, 0x4D, 0xAD, 0x8D, 0x8E, 0xE7, 0xE6, 0x0A, 0x89, 0x69, 0x90, 0x62, 0x16, 0x2F, 0x90, 0xBB, 0x28, 0xE4, 0xCC, 0xBA, 0x1A, 0x5F, 0x52, 0x6D, 0xE9, 0xCF, 0x7F, 0xEF, 0xEC, 0x7A, 0x77, 0xDD, 0xA0, 0x7C, 0xD7, 0x00, 0x09, 0xE4, 0x8E, 0xBF, 0x8E, 0xDD, 0x9B, 0x34, 0x87, 0x26, 0xA9, 0x37, 0xE1, 0x4F, 0xF5, 0xEB, 0x6E, 0x79, 0xE3, 0xDB, 0x1B, 0x60, 0xD7, 0x0A, 0x73, 0x05, 0x11, 0x15, 0x4A, 0x8A, 0xB8, 0x75, 0xF8, 0x6D, 0xEB, 0xCB, 0x9D, 0x79, 0x0F, 0xC4, 0x32, 0x84, 0x4E, 0x90, 0x3C, 0x8B, 0xD9, 0xFD, 0xB2, 0x8F, 0x99, 0x88, 0xDF, 0xAE, 0xA5, 0x56, 0xE9, 0x20, 0xE5, 0x79, 0x25, 0x47, 0xAE, 0xA7, 0xA4, 0x5B, 0x4C, 0x7E, 0x68, 0x41, 0x61, 0x1E, 0x33, 0x06, 0x4E, 0x5C, 0xB5, 0x9B, 0xBA, 0xEC, 0xA6, 0x9E, 0x38, 0xA0, 0x99, 0x94, 0xAE, 0xEA, 0x3D, 0x10, 0xF6, 0xFC, 0x53, 0xF6, 0x43, 0x56, 0x2F, 0xA0, 0x0A, 0x34, 0x12, 0xD4, 0xAF, 0xF8, 0x01, 0xD4, 0x8D, 0x0C, 0x58, 0xBA, 0x05, 0x5A, 0x42, 0xCD, 0xF6, 0xB8, 0xF1, 0x86, 0x16, 0x99, 0xEF, 0xD9, 0xAD, 0x9D, 0xF4, 0xCB, 0xB9, 0x88, 0xE7, 0x22, 0x17, 0x12, 0xBB, 0x42, 0xA4, 0x3B, 0xE8, 0x32, 0x25, 0x09, 0x11, 0x1D, 0x3A, 0x8E, 0xBC, 0x97, 0xFA, 0xEB, 0xF9, 0xF8, 0x5D, 0x69, 0x20, 0x76, 0x5A, 0x18, 0x2A, 0xD9, 0xC4, 0x54, 0x27, 0x99, 0x31, 0x70, 0x5E, 0xA2, 0x90, 0x3F, 0x6E, 0x18, 0x7D, 0x2A, 0xF6, 0xA5, 0xE4, 0xA8, 0x30, 0x54, 0x16, 0x8A, 0xA6, 0xA6, 0xF1, 0x27, 0xC8, 0xCE, 0x0C, 0x56, 0xA2, 0xEF, 0x67, 0xDC, 0x1C, 0xD9, 0xB2, 0x2A, 0x51, 0x39, 0xDA, 0xC1, 0x92, 0xFF, 0xC5, 0x3A, 0x13, 0xEC, 0x52, 0xA3, 0x22, 0x07, 0xA9, 0x6A, 0x4F, 0xED, 0xB1, 0x20, 0x55, 0xFF, 0xDD, 0xBE, 0xE6, 0xAE, 0xF0, 0x72, 0xF7, 0x5D, 0xB7, 0xC6, 0xCD, 0x37, 0xB2, 0x58, 0x9D, 0xC0, 0x0F, 0xBE, 0xF1, 0x33, 0x3E, 0xB1, 0x13, 0xC8, 0x22, 0x1B, 0xF8, 0x74, 0x0F, 0xD7, 0xBF, 0x7F, 0x39, 0xA5, 0x7E, 0x4A, 0xE2, 0xCE, 0x86, 0xE0, 0xE8, 0xB4, 0xE9, 0x21, 0x4D, 0x67, 0x21, 0x46, 0xED, 0xE9, 0x85, 0x87, 0x15, 0x71, 0x56, 0x5E, 0x9F, 0x59, 0xCD, 0xA5, 0x92, 0x22, 0xAC, 0x9C, 0x6C, 0x00, 0xD5, 0xA7, 0xC9, 0xD8, 0xA3, 0xE5, 0x46, 0xDE, 0xC8, 0x3C, 0x65, 0x54, 0xEA, 0x89, 0x13, 0x72, 0xBB, 0xCA, 0xE7, 0xD7, 0x76, 0x88, 0xDE, 0xD6, 0x0B, 0x52, 0x6C, 0x04, 0xC9, 0xBF, 0x0A, 0x7D, 0x96, 0x56, 0x81, 0x90, 0x4D, 0xAC, 0x03, 0x79, 0x1F, 0x08, 0xB0, 0x71, 0xF0, 0xEE, 0x5B, 0xAB, 0xA1, 0xC4, 0x6B, 0x15, 0x61, 0x75, 0x6E, 0x58, 0x9C, 0x33, 0x7B, 0xAB, 0x4F, 0x2B, 0x75, 0xAE, 0x3B, 0xF6, 0xE7, 0x74, 0x3F, 0x6C, 0xEE, 0x5F, 0x09, 0x93, 0xE7, 0x18, 0xC9, 0x58, 0x4D, 0x47, 0xEA, 0xD4, 0xC9, 0x61, 0xAE, 0x96, 0xF6, 0xD6, 0x02, 0xA5, 0x06, 0xA2, 0xA4, 0xC0, 0xF5, 0x7E, 0x88, 0x1D, 0x51, 0xDC, 0x24, 0xF2, 0x77, 0xEB, 0xA9, 0xCC, 0x3C, 0x6F, 0x23, 0x58, 0x29, 0xB5, 0xBA, 0x87, 0xC2, 0x1F, 0x12, 0x32, 0x1C, 0xEE, 0x8B, 0x6E, 0xE9, 0x08, 0x9B, 0xB5, 0x2C, 0x3A, 0x71, 0xAD, 0x61, 0x12, 0x46, 0xAE, 0xD9, 0x80, 0xC1, 0xB9, 0x47, 0xA6, 0x7C, 0x88, 0xA1, 0x10, 0xA7, 0xBD, 0x84, 0x49, 0xD0, 0x9C, 0xE3, 0x90, 0x6C, 0x65, 0x35, 0x45, 0x7D, 0x02, 0xF2, 0x32, 0x5C, 0x70, 0xEE, 0x78, 0x63, 0xAE, 0x63, 0x23, 0x0F, 0xC2, 0x3D, 0xEC, 0xA2, 0x99, 0xBB, 0x5B, 0x0E, 0x4B, 0x1A, 0xE8, 0xE2, 0x40, 0x1D, 0xFB, 0x9D, 0x4B, 0xDD, 0xD0, 0x61, 0x18, 0xBD, 0x15, 0x0F, 0x4B, 0x5C, 0xD3, 0x85, 0xAF, 0xB4, 0xFA, 0xD4, 0xEC, 0xA4, 0x6D, 0x61, 0xBE, 0xCA, 0xB1, 0x1D, 0x02, 0x70, 0x26, 0x67, 0x33, 0x33, 0xAB, 0x31, 0x4B, 0x9E, 0xF9, 0x1B, 0x7A, 0x7F, 0x94, 0x0B, 0xDA, 0x44, 0x44, 0xAE, 0xFE, 0x37, 0x03, 0x6A, 0x43, 0xF2, 0xB6, 0x8D, 0x0D, 0xFF, 0xD7, 0xAF, 0x33, 0xA3, 0x63, 0x0F, 0xDB, 0x32, 0x5A, 0x74, 0xDA, 0x7B, 0x09, 0x0F, 0x94, 0x9D, 0x06, 0x4B, 0xF7, 0x45, 0xB8, 0x93, 0x37, 0x15, 0x2B, 0x98, 0x0E, 0x4E, 0x20, 0xCC, 0x23, 0xFF, 0xAF, 0xCC, 0xBC, 0x7E, 0x95, 0x77, 0x04, 0xE9, 0x4B, 0xE7, 0xF3, 0xE8, 0x5F, 0x7F, 0xE8, 0x49, 0x6F, 0xD5, 0xAA, 0xB9, 0x67, 0xB2, 0x7C, 0x3F, 0x17, 0x3E, 0x26, 0x26, 0x80, 0xD0, 0x44, 0x08, 0x85, 0xE6, 0xC0, 0xB2, 0xAA, 0xB0, 0x9A, 0xB8, 0x1F, 0x6D, 0xE5, 0xB2, 0x2D, 0x17, 0xD5, 0xA2, 0x11, 0x97, 0xD6, 0x98, 0x93, 0xBE, 0xED, 0x51, 0x83, 0x4E, 0x2D, 0x7E, 0x3D, 0xAF, 0xF0, 0x4C, 0xF8, 0x4A, 0xA9, 0xC7, 0x79, 0x6E, 0xBB, 0x6A, 0xE2, 0x06, 0xC4, 0xE1, 0x66, 0x25, 0xFD, 0xFD, 0x61, 0x39, 0x85, 0x05, 0x48, 0x06, 0x26, 0x7C, 0xD6, 0x9B, 0xFA, 0x8F, 0x5D, 0xD6, 0x0F, 0x4F, 0x21, 0x94, 0x12, 0xDF, 0x2B, 0xAB, 0xC9, 0x56, 0x41, 0xAE, 0x15, 0x54, 0x87, 0xFA, 0xF4, 0x13, 0x33, 0xF5, 0xE5, 0x1B, 0xEF, 0xC2, 0xF9, 0x63, 0xE6, 0x2B, 0x74, 0x8B, 0x3D, 0x9C, 0x20, 0x20, 0x66, 0xD1, 0xEC, 0xBA, 0xB6, 0x03, 0x21, 0x79, 0x10, 0x58, 0x9B, 0xB9, 0x69, 0x55, 0x21, 0xA5, 0xC5, 0x2F, 0x12, 0x38, 0x2F, 0x0D, 0xE3, 0x24, 0x3F, 0x9E, 0x92, 0xED, 0x60, 0x53, 0x12, 0x63, 0x7D, 0xCC, 0xE5, 0xAD, 0x80, 0x7D, 0xA0, 0xC9, 0x2E, 0x99, 0x32, 0x52, 0x05, 0x20, 0x41, 0xC7, 0xB6, 0x8F, 0x4E, 0xB1, 0xBB, 0xB7, 0x08, 0x5A, 0x5B, 0x02, 0x04, 0x77, 0x98, 0x92, 0x30, 0xCB, 0xA8, 0x9F, 0x96, 0x6D, 0x34, 0x97, 0xC4, 0x04, 0x3D, 0x05, 0x6F, 0x79, 0x7E, 0xA0, 0xB4, 0x8E, 0x24, 0x7C, 0xAB, 0xBC, 0x7E, 0x59, 0x73, 0x07, 0xDA, 0x60, 0x5A, 0x00, 0x81, 0x45, 0x45, 0x51, 0xC8, 0x96, 0xAB, 0x4E, 0xE1, 0x34, 0x6B, 0x90, 0x4E, 0x35, 0x8A, 0x58, 0xCA, 0x2F, 0x7B, 0x93, 0xDA, 0x32, 0x9D, 0x08, 0x0A, 0x49, 0xDC, 0xF9, 0xD2, 0xC9, 0xD1, 0xBB, 0xD6, 0xBA, 0x82, 0x6C, 0xA7, 0x13, 0x3A, 0xB2, 0xDF, 0x61, 0xD7, 0x13, 0x16, 0xEB, 0xDD, 0xED, 0x88, 0x2E, 0x49, 0x83, 0xB7, 0x67, 0x46, 0xF7, 0x14, 0x36, 0xD2, 0xD7, 0xC1, 0x4D, 0x94, 0x34, 0x71, 0x70, 0xEE, 0x00, 0x15, 0x54, 0x00, 0x28, 0x1B, 0xD3, 0xC6, 0xBF, 0xE5, 0xEC, 0xBF, 0x69, 0xDE, 0xA0, 0x59, 0x01, 0x63, 0xE3, 0xA2, 0x97, 0x10, 0xC4, 0x10, 0x7A, 0x08, 0xD4, 0xDD, 0x30, 0xFD, 0x6E, 0x05, 0x0E, 0xA1, 0xE9, 0xE3, 0xF3, 0xBA, 0xCD, 0x74, 0x10, 0x35, 0xE3, 0x47, 0x18, 0xAF, 0xA9, 0xA9, 0xC8, 0xAB, 0x19, 0xEA, 0x9C, 0xD8, 0x75, 0x11, 0xCC, 0x59, 0xCC, 0x60, 0x1B, 0xC6, 0x3B, 0x82, 0x0F, 0xD0, 0x96, 0x87, 0x1F, 0x95, 0x26, 0x34, 0xA2, 0xA3, 0x78, 0x87, 0x83, 0xAA, 0xE7, 0x6D, 0xA2, 0x05, 0xB1, 0xEB, 0x5E, 0x94, 0x42, 0x16, 0x19, 0xFF, 0x47, 0x52, 0x5F, 0x05, 0x62, 0xE4, 0xA3, 0x63, 0x3A, 0xC7, 0xC4, 0x01, 0x7D, 0xA2, 0xC8, 0x13, 0x07, 0xBD, 0xBD, 0x74, 0xB2, 0xD9, 0x16, 0x1E, 0x99, 0xC1, 0x68, 0x6A, 0x9A, 0xB1, 0xC9, 0x44, 0x1B, 0x0D, 0x35, 0xC1, 0xCE, 0x7E, 0x9A, 0x62, 0x88, 0x28, 0x92, 0x85, 0x02, 0x33, 0x20, 0x88, 0x9B, 0x63, 0x9E, 0xB9, 0xCD, 0x0A, 0x56, 0x92, 0x93, 0xE3, 0x67, 0xC2, 0xBD, 0x1F, 0xEA, 0x68, 0x7F, 0x45, 0x1B, 0x3D, 0xA8, 0x80, 0x9A, 0x77, 0xCA, 0x31, 0x9D, 0xFC, 0xFF, 0xBA, 0xD4, 0x27, 0x24, 0xF2, 0xE0, 0x67, 0xCB, 0x3A, 0x85, 0xE7, 0x23, 0xCD, 0xD0, 0xEF, 0xC6, 0xB4, 0xC9, 0x7B, 0x5A, 0x13, 0x6B, 0xBE, 0xFC, 0xB6, 0xF1, 0x34, 0x59, 0x2C, 0xED, 0xDD, 0x6A, 0xFC, 0x98, 0x30, 0x36, 0x5D, 0x75, 0xF7, 0x5A, 0x27, 0xCA, 0xC7, 0x22, 0x56, 0x07, 0x8E, 0xD0, 0x20, 0xA4, 0x49, 0x30, 0xDE, 0x9C, 0x35, 0xCE, 0x96, 0xE1, 0x54, 0x4E, 0xE9, 0x85, 0x1B, 0xE6, 0x78, 0x48, 0x2A, 0x32, 0x7C, 0xFA, 0x37, 0xA9, 0x13, 0xE0, 0x45, 0xC8, 0xC2, 0x63, 0xD9, 0xB2, 0x5E, 0xAE, 0x21, 0xA2, 0x66, 0x4A, 0xF9, 0x43, 0x03, 0x95, 0x16, 0x3F, 0x04, 0x56, 0xD1, 0xA5, 0x18, 0xF6, 0x09, 0x7C, 0x96, 0xDB, 0x8F, 0x50, 0x5F, 0x34, 0x40, 0xA6, 0xC8, 0xCC, 0x31, 0xB5, 0x95, 0xAC, 0xFE, 0x9A, 0xA9, 0xCC, 0x1C, 0xCF, 0xF9, 0xFD, 0xA6, 0x56, 0xBC, 0xDB, 0x5E, 0xEB, 0x57, 0xF4, 0x1E, 0x94, 0x67, 0xC6, 0x43, 0xBA, 0x62, 0x79, 0xE5, 0x41, 0xE8, 0x6C, 0x91, 0x07, 0x4E, 0x55, 0xC6, 0x3A, 0xDF, 0x41, 0x51, 0x7C, 0xEA, 0x5A, 0x6F, 0x62, 0x29, 0xF7, 0x10, 0x16, 0x62, 0xBB, 0x0A, 0xA0, 0xCE, 0xAB, 0x2B, 0x7F, 0x62, 0x11, 0x96, 0xC7, 0xA7, 0x7B, 0xB3, 0x27, 0xC7, 0x68, 0xC4, 0x3D, 0x06, 0x9D, 0x71, 0xC3, 0x2C, 0x71, 0x2C, 0x83, 0x1D, 0x68, 0x50, 0xE6, 0xEB, 0x79, 0x3D, 0x7D, 0xEB, 0x08, 0xDE, 0x7A, 0x70, 0x4B, 0x38, 0x6D, 0xFD, 0x2B, 0x30, 0x72, 0xC2, 0x6B, 0x89, 0xDF, 0x8D, 0x07, 0x2B, 0x3E, 0x9F, 0x56, 0x96, 0xA0, 0x73, 0x2E, 0x21, 0x5D, 0xF6, 0xDE, 0x47, 0x5D, 0x3A, 0x69, 0xF1, 0x11, 0x2F, 0x8B, 0x6B, 0x8E, 0xE7, 0x6B, 0x73, 0x9C, 0x92, 0x76, 0xD9, 0xEE, 0x78, 0x17, 0xD9, 0x89, 0xAA, 0x07, 0x90, 0xD4, 0x6F, 0x8B, 0xE9, 0xBC, 0xF8, 0xA9, 0xDE, 0x83, 0xD3, 0xF3, 0xC3, 0x02, 0xA8, 0xAA, 0xBE, 0xE5, 0xC8, 0xFE, 0xBC, 0x2A, 0xDC, 0x70, 0x6F, 0xC0, 0xEA, 0x55, 0xCD, 0x6F, 0x38, 0x37, 0x74, 0xF9, 0x55, 0xFE, 0xC7, 0x0A, 0x5F, 0x83, 0x80, 0x74, 0xDC, 0xB7, 0x31, 0x53, 0x2C, 0x94, 0x9C, 0x88, 0x84, 0xE9, 0x5F, 0xDE, 0xCE, 0x3A, 0x7D, 0x9F, 0x7E, 0xA2, 0x1A, 0xC5, 0xA8, 0xAC, 0xDF, 0xAA, 0x89, 0x68, 0x1E, 0x95, 0x01, 0x4D, 0x5A, 0x23, 0x44, 0x31, 0x5B, 0xF8, 0xB3, 0xFF, 0x97, 0x12, 0xA0, 0x9A, 0x8F, 0xDE, 0xB8, 0x29, 0x4C, 0x25, 0x7D, 0x16, 0xCC, 0xEF, 0xAA, 0x78, 0xDD, 0x0F, 0x5D, 0xFF, 0xE0, 0x49, 0xCE, 0x2B, 0x8A, 0xC7, 0xE1, 0x60, 0x02, 0xED, 0x1E, 0x32, 0x8C, 0x62, 0x86, 0xA1, 0x67, 0x4A, 0x5C, 0x06, 0xF6, 0x28, 0x37, 0xAA, 0xF3, 0xEE, 0xFF, 0xFC, 0x11, 0x46, 0x94, 0x7A, 0x63, 0x0D, 0x82, 0x44, 0xAA, 0x72, 0x89, 0x8D, 0xFE, 0x5B, 0x94, 0x78, 0x63, 0x70, 0x64, 0x8A, 0x13, 0xF0, 0xE1, 0x6D, 0x50, 0x27, 0x77, 0xEB, 0x8D, 0xF9, 0x62, 0xFC, 0x86, 0x3C, 0x77, 0xC1, 0x59, 0xBF, 0x64, 0xCC, 0x2A, 0x47, 0xCA, 0xF6, 0xB2, 0x12, 0xCB, 0xC6, 0x14, 0x2B, 0x5C, 0x9F, 0x5B, 0xFF, 0xE2, 0xDD, 0x3B, 0xB1, 0xF8, 0x63, 0x23, 0x10, 0x74, 0x82, 0x96, 0xBB, 0x81, 0xB3, 0x62, 0xB7, 0xE4, 0x56, 0xEE, 0xE8, 0xDF, 0x29, 0x55, 0xFC, 0xDC, 0x04, 0xE5, 0x5D, 0x25, 0x16, 0xA8, 0x28, 0x07, 0x12, 0xCA, 0x5B, 0x60, 0xEA, 0x90, 0x7D, 0x51, 0xB2, 0xFA, 0x72, 0xF9, 0xC7, 0x3D, 0xA7, 0xFE, 0x2C, 0x25, 0x98, 0x8F, 0x5B, 0xE1, 0xB8, 0x23, 0x68, 0x25, 0xC8, 0x3A, 0x02, 0x38, 0x22, 0x39, 0x40, 0x2A, 0x29, 0x4E, 0xA4, 0xBE, 0x31, 0xA1, 0x7D, 0xBD, 0x31, 0xBA, 0x1B, 0xFF, 0xF8, 0x04, 0xCC, 0x78, 0x2F, 0xED, 0x78, 0x95, 0x09, 0x7F, 0x58, 0x3D, 0xD1, 0x3A, 0xCC, 0x85, 0x49, 0x1B, 0xDD, 0x12, 0x3F, 0xE0, 0x2C, 0x14, 0x12, 0xE3, 0x42, 0x61, 0x7D, 0x9C, 0x26, 0xB8, 0xD9, 0x87, 0x7C, 0xAD, 0x5A, 0x72, 0xD2, 0x32, 0x80, 0xB5, 0x27, 0x61, 0x47, 0xA7, 0x25, 0x84, 0xDA, 0xE6, 0x17, 0x23, 0x15, 0x8B, 0x9A, 0x54, 0x79, 0xD6, 0x6B, 0x6D, 0x8A, 0x6C, 0x4D, 0xB0, 0xF2, 0xE7, 0x1E, 0xDD, 0x46, 0x58, 0x85, 0xC3, 0x3A, 0x69, 0xA8, 0xA7, 0x4E, 0x78, 0x16, 0x08, 0xF0, 0x64, 0x16, 0x86, 0x6D, 0x19, 0x6B, 0x69, 0x5E, 0x70, 0xA4, 0x3B, 0x7D, 0xEA, 0xBE, 0x8C, 0x00, 0x0D, 0x79, 0xEE, 0x16, 0x03, 0xD4, 0x7C, 0x45, 0xCC, 0xB8, 0x5B, 0xBF, 0x79, 0x2D, 0x59, 0x14, 0x6F, 0xA3, 0x22, 0x86, 0x97, 0x6F, 0xF5, 0x91, 0x72, 0x62, 0x96, 0x38, 0xE1, 0xA0, 0x70, 0xCB, 0x0F, 0x0E, 0xCB, 0xF8, 0x09, 0xF9, 0xF5, 0xB8, 0x73, 0xFB, 0xEF, 0x96, 0x87, 0x4F, 0xCD, 0xED, 0x58, 0xA2, 0xC0, 0xA4, 0x99, 0x06, 0xD9, 0x09, 0x1D, 0x29, 0xB2, 0x1D, 0x0A, 0x7B, 0x89, 0x94, 0x52, 0x5D, 0x08, 0x88, 0x74, 0x8F, 0xB7, 0xDE, 0xE1, 0x60, 0xF2, 0xFC, 0xC7, 0x89, 0x52, 0xBB, 0x57, 0xBE, 0x4D, 0x36, 0x68, 0x5B, 0xE4, 0xF2, 0xB1, 0x45, 0xBC, 0xAC, 0x40, 0xE0, 0xDB, 0x30, 0x60, 0x87, 0x2D, 0x81, 0x76, 0x63, 0x91, 0xD4, 0xEC, 0x0B, 0x04, 0x60, 0x9F, 0x4F, 0x2D, 0xA2, 0x28, 0x94, 0x15, 0x45, 0x8D, 0x5F, 0x15, 0x22, 0x3C, 0x8E, 0x91, 0x11, 0x88, 0xC7, 0x82, 0x5F, 0x52, 0xA0, 0xA3, 0xA2, 0xC2, 0xCA, 0x8B, 0x62, 0xA7, 0x4B, 0x03, 0x71, 0x59, 0xE5, 0x4D, 0x99, 0x73, 0xC8, 0x00, 0x54, 0x3D, 0x2F, 0x6C, 0x4C, 0x0D, 0x9E, 0x3B, 0x09, 0x39, 0xC1, 0xC1, 0x68, 0x05, 0xE5, 0x79, 0x46, 0x95, 0x49, 0x9C, 0xE0, 0x13, 0xCF, 0xB9, 0xB0, 0xEA, 0xEE, 0xD8, 0xDD, }, .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 = 4668, .sig = { 0x37, 0xBD, 0x0C, 0xCB, 0xC5, 0x4E, 0x5A, 0x48, 0x0F, 0x2F, 0xBB, 0x8E, 0xF3, 0x87, 0x9E, 0x83, 0x40, 0xD7, 0xF6, 0xC7, 0x42, 0x42, 0xAD, 0x44, 0xD3, 0xE8, 0xB0, 0x78, 0x3C, 0xC5, 0xBF, 0x21, 0x36, 0xD7, 0xBD, 0x4A, 0x32, 0xA9, 0x55, 0x2F, 0xE0, 0xE8, 0xAF, 0x8E, 0x87, 0xD5, 0x41, 0x1D, 0x76, 0x8A, 0x69, 0x2F, 0xE2, 0xC5, 0x03, 0xA7, 0x0C, 0xCB, 0xC0, 0x3A, 0x34, 0xB3, 0xC1, 0xF0, 0x81, 0x5B, 0x26, 0x4B, 0x57, 0x2A, 0x9E, 0x74, 0x60, 0x9B, 0x9A, 0xD7, 0x29, 0x3B, 0xE3, 0x72, 0x7B, 0xFE, 0x17, 0x58, 0x3B, 0x3B, 0x63, 0x4F, 0x0A, 0x11, 0x9D, 0x79, 0x3E, 0xB1, 0x4D, 0xFF, 0x18, 0x64, 0x3D, 0x1C, 0x34, 0x6B, 0x65, 0xE5, 0x73, 0xEF, 0xB9, 0xD5, 0x3B, 0xFA, 0x4C, 0x20, 0x05, 0x5D, 0x55, 0xF7, 0x54, 0xAF, 0x2F, 0x73, 0xFC, 0x38, 0x62, 0x67, 0xD5, 0x89, 0x0B, 0x39, 0x13, 0x01, 0x41, 0x55, 0x93, 0xB2, 0xC5, 0x69, 0x5B, 0x9C, 0x06, 0xF0, 0x01, 0xF8, 0x84, 0x5C, 0x7C, 0xFA, 0xD7, 0x7C, 0x04, 0xE4, 0x11, 0x65, 0x18, 0xDF, 0x80, 0xF0, 0x41, 0xA5, 0x8A, 0x85, 0x74, 0x48, 0xE7, 0x68, 0xA7, 0x1A, 0x7A, 0x01, 0xF2, 0x43, 0x31, 0x70, 0xB3, 0x71, 0xE8, 0xE3, 0x01, 0xA5, 0x37, 0x87, 0xD5, 0xEC, 0x77, 0x05, 0xA5, 0xEE, 0x1F, 0xE4, 0xFC, 0x04, 0x91, 0xCD, 0xC6, 0xC8, 0x76, 0x96, 0x8A, 0x60, 0x6E, 0xC1, 0x38, 0x6F, 0x45, 0x1C, 0xE8, 0x54, 0x77, 0x34, 0x8D, 0xE1, 0xC6, 0x8E, 0xCC, 0x33, 0x95, 0x41, 0x61, 0x24, 0x90, 0xB2, 0x4C, 0x24, 0x2D, 0x25, 0x87, 0x39, 0x81, 0xF9, 0xDE, 0xA6, 0x6D, 0x13, 0xF3, 0xC2, 0x10, 0x93, 0xEA, 0x48, 0x11, 0x51, 0xD1, 0x76, 0xA5, 0x50, 0x08, 0x42, 0x55, 0x0C, 0x26, 0xD0, 0xAF, 0xB1, 0xC6, 0xAE, 0xBE, 0x8E, 0x42, 0x67, 0xE3, 0x6F, 0xD5, 0x70, 0x1E, 0x45, 0xD1, 0xDF, 0x15, 0x95, 0x9C, 0x7D, 0xC4, 0x4E, 0x7F, 0x5B, 0x6B, 0xA8, 0xCA, 0x04, 0xED, 0xF1, 0xE3, 0xE6, 0x48, 0x69, 0xFA, 0x15, 0x3B, 0xA7, 0x46, 0x7F, 0x0D, 0x7B, 0x2F, 0xDC, 0x91, 0x24, 0x3A, 0x22, 0x39, 0x06, 0xF1, 0xAE, 0xA0, 0xD9, 0xFC, 0x14, 0x0F, 0x70, 0xCD, 0x02, 0x5A, 0x31, 0xB4, 0x0F, 0x22, 0xC4, 0x71, 0xBD, 0xD2, 0x36, 0x5E, 0xD6, 0x30, 0x2D, 0x14, 0x81, 0x31, 0x6E, 0xE3, 0xC4, 0xC1, 0x70, 0xA1, 0x62, 0xEF, 0xE9, 0xFF, 0x41, 0x85, 0xE4, 0x50, 0x08, 0xF0, 0x7F, 0x6B, 0xDB, 0xAC, 0x22, 0x1D, 0xEC, 0x0B, 0xF0, 0xAF, 0x88, 0x4B, 0x16, 0xC9, 0x5F, 0x34, 0x35, 0x01, 0xAA, 0x09, 0x8A, 0xD4, 0xA1, 0xF8, 0x20, 0x68, 0xFA, 0x1F, 0xBF, 0xF0, 0xE0, 0x40, 0x94, 0x6D, 0xCD, 0x50, 0xBF, 0x00, 0x9D, 0xF1, 0xFC, 0xA4, 0xA3, 0xAA, 0xDB, 0x1C, 0x29, 0x51, 0xC0, 0x86, 0xD2, 0x7F, 0x20, 0x02, 0xDF, 0xD8, 0x54, 0xE5, 0x98, 0x52, 0xF4, 0x15, 0x30, 0x90, 0xDD, 0xC1, 0xA2, 0x1A, 0x6E, 0x0B, 0xE5, 0x92, 0x18, 0x7A, 0x68, 0xAE, 0x08, 0x5B, 0x1D, 0x5D, 0x98, 0xBE, 0x8F, 0xCE, 0x5E, 0x24, 0x03, 0x1F, 0x47, 0xF8, 0x34, 0x30, 0x6B, 0xE5, 0xA5, 0xB6, 0x80, 0xAC, 0xFC, 0xD9, 0xF4, 0x04, 0xC1, 0xDE, 0x85, 0x79, 0x66, 0xD2, 0x54, 0x6E, 0x66, 0x94, 0x01, 0x5F, 0x05, 0x02, 0xD0, 0xE6, 0x56, 0x8C, 0x9A, 0xA1, 0xB1, 0x3B, 0x3D, 0x7B, 0x61, 0xEE, 0x6A, 0x3D, 0xA0, 0x16, 0xDD, 0x34, 0xD6, 0x44, 0xB1, 0x29, 0x7E, 0x63, 0x8D, 0xF0, 0xFC, 0xB6, 0xF6, 0x85, 0x57, 0x7E, 0x16, 0x4F, 0x5D, 0x6A, 0xA6, 0xF0, 0x70, 0xC1, 0xD0, 0x21, 0x55, 0x8C, 0xBC, 0xFD, 0x6F, 0x9B, 0xA3, 0x75, 0xE2, 0x89, 0x1F, 0x67, 0x26, 0xCC, 0xE4, 0xCE, 0xBC, 0x89, 0xA9, 0x63, 0x57, 0x93, 0x0D, 0x04, 0x4C, 0x16, 0xAB, 0x29, 0x45, 0x30, 0x2C, 0xE0, 0xF2, 0xB6, 0x46, 0x17, 0x04, 0x6C, 0x3C, 0x1C, 0x4A, 0x6B, 0x34, 0xD5, 0xAA, 0x07, 0x4E, 0x5F, 0xCB, 0x10, 0xBB, 0xA4, 0xC2, 0xA6, 0x08, 0x26, 0x5F, 0x45, 0xD7, 0x45, 0x10, 0x75, 0x0E, 0xAC, 0x67, 0x3A, 0x82, 0x8D, 0x5D, 0x30, 0x8F, 0x34, 0x07, 0x92, 0x31, 0x33, 0xD5, 0x50, 0xB2, 0x57, 0x85, 0xA8, 0x39, 0x02, 0x42, 0xDC, 0x27, 0xB0, 0x82, 0xD3, 0x87, 0xAB, 0xCC, 0xDA, 0x7C, 0xD4, 0xD6, 0xEE, 0x5E, 0xAB, 0x8D, 0x51, 0xC8, 0x76, 0x9C, 0x24, 0x3A, 0x95, 0x88, 0xF0, 0x45, 0xCC, 0xD9, 0xA5, 0x17, 0x2D, 0x99, 0xD0, 0x4E, 0xE4, 0x39, 0x59, 0xDC, 0x4D, 0x95, 0xBE, 0xAC, 0x06, 0x14, 0xA2, 0xF8, 0x50, 0x97, 0xED, 0x1C, 0x47, 0x61, 0x38, 0x42, 0x9D, 0x12, 0xC7, 0x75, 0x8F, 0xA5, 0x28, 0x75, 0xC7, 0x38, 0xD4, 0x6E, 0xF2, 0xD9, 0x67, 0x51, 0x90, 0xFB, 0x72, 0x65, 0xF9, 0xAA, 0xC8, 0xC6, 0xF1, 0x73, 0xE8, 0xD5, 0x5C, 0x6B, 0x33, 0x81, 0x9F, 0xBF, 0x9B, 0x5B, 0xD3, 0x12, 0x4D, 0x30, 0xC5, 0x81, 0x3E, 0x44, 0x7F, 0xAE, 0x23, 0xFC, 0xA5, 0xDB, 0x43, 0x8E, 0xC5, 0xCC, 0x8A, 0x66, 0xDE, 0xEB, 0xEB, 0x39, 0x53, 0x49, 0x29, 0xCE, 0x4C, 0xE0, 0xB9, 0x8F, 0x1C, 0xA0, 0xE2, 0xC7, 0xD4, 0x53, 0x81, 0xC8, 0xF2, 0xE2, 0xFD, 0x2F, 0xED, 0x40, 0x6B, 0x29, 0xCC, 0x6A, 0x09, 0xD8, 0x1B, 0x44, 0xA4, 0x4F, 0x16, 0xC1, 0x50, 0xD8, 0x65, 0xE8, 0xEA, 0x60, 0x60, 0xA8, 0x58, 0x39, 0x7C, 0x07, 0xF8, 0x57, 0x3A, 0x9C, 0xA2, 0x93, 0x00, 0x7D, 0x1B, 0xE4, 0xDD, 0xD8, 0xA5, 0x37, 0xDD, 0x9A, 0x57, 0x7F, 0x5E, 0x42, 0xF3, 0xEC, 0xB4, 0x8F, 0x75, 0x81, 0x51, 0xA4, 0x01, 0xCA, 0xF2, 0x26, 0xA4, 0x8D, 0x94, 0x81, 0x9D, 0x2A, 0x43, 0xED, 0x08, 0xCD, 0xB6, 0xAE, 0xDD, 0x64, 0x01, 0x14, 0x03, 0x22, 0x31, 0x3B, 0xFD, 0xE2, 0x76, 0x05, 0x71, 0x7E, 0x35, 0x66, 0xDD, 0x31, 0xBB, 0x5C, 0x52, 0x71, 0x45, 0x90, 0x45, 0x93, 0xA4, 0x74, 0x41, 0xD2, 0xF3, 0xC7, 0x44, 0x2C, 0x63, 0x69, 0x5D, 0xD0, 0xC3, 0x60, 0xBD, 0xA9, 0x95, 0xFB, 0xFE, 0xC3, 0xE6, 0xC6, 0x63, 0xD1, 0xD2, 0x2D, 0x89, 0x0D, 0x7D, 0xF7, 0x05, 0x98, 0xF1, 0xBB, 0xC6, 0x19, 0x2A, 0x4F, 0x3A, 0x0A, 0x45, 0x8A, 0x95, 0x44, 0xCA, 0xDD, 0x6F, 0x18, 0xDF, 0xA9, 0xEE, 0xA6, 0xE3, 0x20, 0x6B, 0xDE, 0x60, 0xED, 0x1C, 0x57, 0xCC, 0xC8, 0x00, 0x5F, 0x7C, 0x7C, 0x82, 0x74, 0xC1, 0x40, 0x7C, 0x8F, 0xAF, 0x4E, 0xBD, 0x69, 0xD5, 0x76, 0x19, 0x79, 0xF9, 0x07, 0xCF, 0xD0, 0x62, 0x4E, 0xC7, 0xBA, 0x1F, 0xD7, 0xB5, 0x67, 0x81, 0xAC, 0x71, 0xA4, 0xA5, 0x26, 0x84, 0xFF, 0xC3, 0x2D, 0x5B, 0x53, 0x3C, 0xB5, 0x6C, 0x07, 0xF6, 0x35, 0xF5, 0x79, 0x69, 0xC8, 0xF1, 0x58, 0x8D, 0x34, 0xD0, 0xE7, 0xA1, 0xC7, 0xA9, 0x42, 0xAA, 0xA3, 0xF3, 0x56, 0x0B, 0x0D, 0xB4, 0xF8, 0xCE, 0xBC, 0xAF, 0x6F, 0x25, 0x24, 0x11, 0x4A, 0x5F, 0x6A, 0xF7, 0x1B, 0x5F, 0x50, 0xE9, 0x42, 0xE6, 0x74, 0xA8, 0x77, 0xC1, 0x74, 0xD9, 0x22, 0x00, 0x86, 0x5A, 0x5A, 0x06, 0xFB, 0x2D, 0x7F, 0xB4, 0x74, 0x41, 0x46, 0x75, 0xED, 0x31, 0x72, 0xF5, 0xF1, 0x53, 0x8F, 0x58, 0x1E, 0xDE, 0x5E, 0xDD, 0x74, 0x5B, 0x55, 0xF9, 0xA2, 0xFC, 0x49, 0x95, 0xEB, 0x98, 0x4B, 0x8A, 0x12, 0xD6, 0xF6, 0x5A, 0xAE, 0xDF, 0x8D, 0x8D, 0x6F, 0xF5, 0x3C, 0xE2, 0x38, 0xC3, 0xA6, 0x6C, 0xF2, 0x34, 0xF5, 0x94, 0x36, 0x47, 0x1C, 0x9F, 0xCB, 0xD3, 0x8E, 0x7F, 0x26, 0xBD, 0xF9, 0x74, 0x1B, 0x59, 0x9E, 0x16, 0xB8, 0xF7, 0xED, 0x46, 0x44, 0xBB, 0x6A, 0xBE, 0x81, 0xBB, 0x94, 0x0C, 0x24, 0xFA, 0x62, 0x0F, 0x44, 0x35, 0x84, 0xF9, 0x9B, 0xB9, 0xDC, 0x25, 0x71, 0xB5, 0xEB, 0x81, 0x19, 0x27, 0x52, 0x9C, 0x7A, 0xDC, 0xEB, 0xEE, 0xF7, 0xAF, 0x05, 0xBA, 0x7E, 0x88, 0x89, 0x9F, 0xAB, 0xF8, 0x74, 0x0F, 0xCD, 0xD1, 0x27, 0x5B, 0x12, 0xF7, 0x2A, 0x75, 0xC6, 0xD0, 0x00, 0x56, 0x5C, 0x5A, 0xC8, 0x8F, 0xB1, 0xFD, 0x99, 0x5B, 0x84, 0xED, 0x38, 0x4D, 0x5D, 0x6A, 0x60, 0x29, 0x37, 0x37, 0xD7, 0x2C, 0xC1, 0x09, 0x44, 0x36, 0x39, 0x71, 0xDA, 0x44, 0xD5, 0xEA, 0xE9, 0xE8, 0xB1, 0xE8, 0x0D, 0x75, 0x76, 0xC5, 0x0A, 0xAF, 0xF6, 0x7E, 0x42, 0x31, 0x96, 0xF3, 0x78, 0x57, 0xD1, 0xD2, 0x35, 0xAB, 0x28, 0x39, 0xAE, 0x37, 0x79, 0xF9, 0xF2, 0xF9, 0xB7, 0x59, 0xFC, 0x52, 0xDA, 0xAE, 0xB8, 0x63, 0x7B, 0x8F, 0x4F, 0xC9, 0x0B, 0xD9, 0x4A, 0xDB, 0x6F, 0x57, 0x72, 0x20, 0x82, 0xE9, 0x43, 0xD7, 0xCE, 0x3E, 0x73, 0x50, 0x1D, 0x8C, 0x93, 0xB5, 0x21, 0x2D, 0xEC, 0xE4, 0x95, 0x35, 0x53, 0x6E, 0xFC, 0xEA, 0xB8, 0xB8, 0x5E, 0xB2, 0xAA, 0x94, 0xCB, 0xE7, 0x7B, 0xAA, 0xDF, 0x46, 0x58, 0x92, 0x01, 0xA3, 0xA8, 0xAC, 0xA4, 0x83, 0x9E, 0x51, 0x9B, 0x6F, 0xD0, 0xCC, 0x52, 0xEA, 0x58, 0xA8, 0xAC, 0x08, 0xDC, 0x15, 0xEE, 0xF4, 0x8E, 0xDB, 0x89, 0xA1, 0xFC, 0x46, 0xE7, 0x13, 0x53, 0xFE, 0x73, 0xF6, 0x8E, 0x0F, 0x48, 0x55, 0xB7, 0xFF, 0x73, 0x27, 0xAE, 0x4B, 0xCB, 0xA0, 0x9D, 0xE0, 0x33, 0x53, 0xD4, 0x1E, 0xDE, 0x26, 0x78, 0x5A, 0x94, 0x49, 0x6A, 0xCB, 0x4E, 0x74, 0x3B, 0xA0, 0x65, 0xD1, 0x79, 0x3F, 0xBE, 0x5B, 0x29, 0x3A, 0x77, 0x1C, 0xCB, 0x8B, 0x8D, 0x8B, 0xD2, 0x76, 0x77, 0xD5, 0xFF, 0xF7, 0x43, 0xF9, 0x49, 0x77, 0x21, 0x9D, 0x55, 0x57, 0x35, 0xE5, 0xD0, 0xAC, 0xE1, 0x18, 0xC2, 0x57, 0x1F, 0xC6, 0x96, 0xAF, 0x1F, 0xB0, 0xA1, 0x97, 0x6A, 0x37, 0x85, 0xB0, 0x89, 0x61, 0x11, 0x7F, 0x19, 0x98, 0xB7, 0xE6, 0x1C, 0xF8, 0x14, 0xFE, 0x91, 0xA8, 0xB8, 0x1D, 0x62, 0xE4, 0x8D, 0x93, 0xB0, 0x28, 0x0D, 0xBA, 0xBF, 0x18, 0xE1, 0x12, 0x12, 0x43, 0xBF, 0xF3, 0x7B, 0x5A, 0xF7, 0x1E, 0x29, 0xA3, 0x1B, 0x48, 0x4A, 0xDA, 0x4F, 0x1F, 0xBC, 0x88, 0x30, 0x11, 0x27, 0x76, 0x60, 0xAE, 0xB4, 0x71, 0xB3, 0x09, 0xFA, 0x00, 0x32, 0x23, 0x5B, 0x3B, 0x2E, 0x2B, 0x2C, 0xAF, 0xCC, 0xC5, 0x44, 0x61, 0xB0, 0xB4, 0x5A, 0xE1, 0x5D, 0x92, 0xAD, 0x61, 0xB6, 0x4C, 0x5F, 0x37, 0x4A, 0x23, 0x74, 0x44, 0xF9, 0x63, 0x1D, 0xE4, 0x3C, 0x0B, 0x67, 0x8D, 0x03, 0xB6, 0x4E, 0xA3, 0xF9, 0x9B, 0xBB, 0xD1, 0x79, 0x61, 0x15, 0x39, 0xFC, 0x91, 0x69, 0x3B, 0x81, 0xE6, 0xA2, 0xF2, 0xFC, 0x81, 0x70, 0xE8, 0xBF, 0xD6, 0xD5, 0xB7, 0x8A, 0x5C, 0xD6, 0x44, 0x88, 0x1A, 0x67, 0xFD, 0x28, 0xAC, 0xDA, 0x74, 0x70, 0x58, 0x47, 0x27, 0x6C, 0x16, 0xBD, 0xF0, 0x9E, 0xBE, 0xBB, 0x21, 0x8C, 0xC6, 0x89, 0xB4, 0x50, 0x85, 0x43, 0xC3, 0x9E, 0xA6, 0x56, 0x44, 0xA7, 0xF3, 0x3D, 0xF4, 0x7D, 0x32, 0x72, 0xA3, 0x7C, 0xA8, 0x30, 0x76, 0x7B, 0x23, 0xF5, 0x52, 0xA1, 0xB3, 0x89, 0xF1, 0x4B, 0xE8, 0x71, 0xFF, 0x72, 0x59, 0xFB, 0x3A, 0x32, 0x93, 0x0F, 0x56, 0xDD, 0x42, 0x71, 0xF0, 0x21, 0xAA, 0xAC, 0xD7, 0xA2, 0xAC, 0x82, 0x03, 0xCF, 0x69, 0xE9, 0x64, 0x30, 0xA1, 0x6A, 0x2F, 0x96, 0xC1, 0x1F, 0xD2, 0xCD, 0x44, 0xE0, 0x86, 0xE1, 0x16, 0x8A, 0x8C, 0x1A, 0x63, 0x7E, 0x23, 0x21, 0xF6, 0x0C, 0xA5, 0x93, 0x0C, 0x02, 0xF9, 0x2D, 0xFF, 0x2D, 0x30, 0xAB, 0x10, 0x5A, 0xF8, 0x46, 0xB1, 0x6A, 0x90, 0xE2, 0xA7, 0x4D, 0xBC, 0x97, 0xDA, 0x40, 0xA1, 0x3F, 0x40, 0x5B, 0x71, 0x04, 0xBF, 0x2F, 0x22, 0xFC, 0xA4, 0x2E, 0x3A, 0x50, 0x0A, 0x72, 0x7A, 0xE1, 0xEA, 0x24, 0x01, 0x21, 0x60, 0x16, 0xFE, 0x8B, 0xF0, 0xDD, 0xBA, 0xE6, 0x8E, 0xD8, 0x74, 0x17, 0xFA, 0x76, 0x0D, 0xBA, 0x07, 0xD8, 0x4C, 0x26, 0x9C, 0xF4, 0x2B, 0xBE, 0xB3, 0x7D, 0x5B, 0x90, 0xEB, 0x23, 0x69, 0x76, 0xB8, 0x6F, 0x4D, 0x8F, 0x35, 0xE7, 0x82, 0x83, 0x7E, 0x32, 0xA1, 0x95, 0xF9, 0xCF, 0xD6, 0xC6, 0x73, 0x53, 0x6A, 0xA0, 0x43, 0x5B, 0x38, 0x0C, 0x02, 0xD1, 0xB7, 0xB0, 0xDE, 0x3C, 0x47, 0x9F, 0xE6, 0xB5, 0xFE, 0x6C, 0xF9, 0x7C, 0x3B, 0xD7, 0x46, 0x10, 0xCF, 0x15, 0x06, 0xE5, 0x99, 0x86, 0xF3, 0x81, 0x46, 0xB9, 0xA8, 0x96, 0x3C, 0xAE, 0x08, 0x00, 0x30, 0x75, 0xFF, 0x60, 0x7D, 0x47, 0x0E, 0x87, 0xA7, 0x2E, 0x8F, 0xFB, 0xC7, 0xE1, 0x38, 0x38, 0xDA, 0x93, 0xDC, 0x3A, 0x4B, 0x3E, 0x52, 0x34, 0x75, 0xCD, 0xC4, 0xE4, 0x8C, 0x2A, 0x54, 0x5F, 0x30, 0xE5, 0x89, 0x24, 0x7C, 0x64, 0x62, 0x2F, 0xA1, 0x05, 0x59, 0xB7, 0x24, 0xBB, 0x5F, 0xE8, 0x73, 0xED, 0xDF, 0x78, 0x38, 0xE1, 0x83, 0x2A, 0xD2, 0x17, 0xD4, 0xE8, 0x0B, 0x58, 0xB9, 0xFB, 0x39, 0xB6, 0x6C, 0xBE, 0x9F, 0x26, 0x48, 0x09, 0xEE, 0xD5, 0x94, 0x23, 0xF0, 0xA3, 0xCD, 0x3F, 0x00, 0xAD, 0xFC, 0x47, 0x42, 0xCE, 0x1B, 0x3C, 0xB6, 0x5B, 0x2B, 0xD2, 0xE3, 0x10, 0x59, 0x50, 0x9A, 0xFC, 0x7E, 0x48, 0x36, 0xDF, 0x0A, 0xE6, 0xF9, 0xD5, 0xC0, 0x63, 0x30, 0x95, 0x3F, 0xA2, 0xBB, 0x6F, 0xD0, 0x18, 0x7A, 0x6C, 0xAB, 0x88, 0x14, 0xEE, 0x12, 0xD1, 0x4E, 0xBC, 0x6D, 0xEF, 0xFC, 0x23, 0xE1, 0xC9, 0x01, 0x65, 0xE2, 0xE7, 0x78, 0x59, 0x45, 0xF1, 0x8B, 0xCC, 0x74, 0xD8, 0xB1, 0xC6, 0xAF, 0xA1, 0x5B, 0x32, 0x6C, 0x04, 0x7D, 0x94, 0x66, 0x8C, 0x03, 0x32, 0xD1, 0x47, 0xAF, 0x57, 0x52, 0x17, 0x64, 0x52, 0xC7, 0x12, 0x20, 0xB0, 0xA4, 0x32, 0xD4, 0x89, 0x9B, 0x6C, 0xEA, 0xA5, 0x87, 0x59, 0x9C, 0xAC, 0xF0, 0x04, 0xBA, 0x12, 0xA9, 0x0B, 0x26, 0x06, 0x21, 0x43, 0x06, 0xFA, 0x30, 0x0A, 0x4A, 0x13, 0xBF, 0x8F, 0x99, 0x4F, 0x46, 0xF5, 0xDF, 0x92, 0xE6, 0xD3, 0xBF, 0x47, 0x2C, 0xF7, 0x29, 0xFF, 0xF6, 0x66, 0xF2, 0x07, 0xEA, 0x71, 0xD5, 0x2C, 0xF6, 0xF2, 0xB1, 0x9C, 0x87, 0xCE, 0xAF, 0x08, 0xCD, 0x44, 0x5D, 0x18, 0x4F, 0x89, 0x81, 0xCA, 0x28, 0xCB, 0xFE, 0xA0, 0x03, 0x06, 0xAC, 0x76, 0x8B, 0x47, 0x15, 0x42, 0xF3, 0x27, 0x48, 0x76, 0x68, 0x4B, 0xCE, 0x7C, 0x17, 0xEB, 0xEC, 0x6C, 0xC6, 0xD7, 0xF9, 0x0E, 0xC1, 0x3D, 0xA9, 0x4C, 0xD7, 0xB4, 0xE9, 0x8E, 0x1C, 0xFA, 0xBA, 0x8F, 0x9C, 0xDD, 0xBF, 0x08, 0xCF, 0xD7, 0xDD, 0x5E, 0x3A, 0x73, 0x25, 0x66, 0x36, 0x65, 0x98, 0x0D, 0x3F, 0x55, 0x59, 0x22, 0x60, 0x8A, 0x05, 0xD9, 0xDC, 0x20, 0x76, 0x69, 0x29, 0x41, 0x30, 0x66, 0xB3, 0xB1, 0xAF, 0x98, 0x44, 0x31, 0x34, 0x5F, 0xD0, 0x12, 0x1D, 0x16, 0x42, 0xEA, 0xB5, 0x84, 0xF7, 0x47, 0x37, 0x3D, 0x08, 0xCE, 0x5B, 0x2E, 0x26, 0xE7, 0x6B, 0x51, 0xAB, 0x58, 0xE3, 0x9E, 0x6F, 0x9E, 0x6C, 0x4C, 0x33, 0xF1, 0x52, 0xE5, 0x03, 0x7F, 0x7F, 0x52, 0x76, 0x0A, 0x98, 0x36, 0x94, 0x1D, 0x43, 0xF4, 0x3C, 0x2E, 0x8C, 0x34, 0x6E, 0x40, 0x4A, 0xF3, 0x51, 0x80, 0x13, 0x3C, 0x2C, 0x8B, 0x44, 0x03, 0x86, 0x98, 0xFB, 0xE6, 0xE8, 0x44, 0xEB, 0xC9, 0x66, 0x57, 0xD5, 0xD3, 0x24, 0xCE, 0xB2, 0xCC, 0x38, 0xA4, 0xF2, 0xE3, 0xB0, 0x09, 0x38, 0x39, 0x3B, 0x05, 0x4E, 0x19, 0xA1, 0xAF, 0x2C, 0x7E, 0x2C, 0xBB, 0xC1, 0xC4, 0x52, 0xB6, 0x9D, 0x02, 0xA4, 0xBF, 0x04, 0xEB, 0x58, 0x42, 0xAA, 0x6A, 0x0A, 0xF8, 0xFB, 0x9D, 0x85, 0xD7, 0x98, 0x5B, 0x9B, 0xB2, 0x3D, 0x86, 0x06, 0x24, 0xB4, 0xE4, 0x04, 0x7E, 0x14, 0x26, 0xF7, 0x17, 0x76, 0x7E, 0x51, 0x5C, 0x3D, 0x99, 0xF4, 0xF3, 0xA1, 0x05, 0x66, 0x56, 0x23, 0x2A, 0x21, 0x1C, 0xC2, 0xC8, 0x07, 0xF1, 0xF9, 0xF9, 0x61, 0x1D, 0xC8, 0xAE, 0x50, 0x81, 0x94, 0xF7, 0xD6, 0x18, 0x2E, 0xE3, 0xAE, 0x96, 0x71, 0xB3, 0x45, 0xD0, 0x23, 0x18, 0x94, 0x78, 0x6E, 0x70, 0x72, 0x42, 0xF0, 0x68, 0x80, 0x69, 0x5A, 0x3F, 0xA6, 0x26, 0x89, 0x15, 0x74, 0xFA, 0xEE, 0xEE, 0x83, 0x39, 0xDE, 0xBE, 0x23, 0x0E, 0xE7, 0x6B, 0x82, 0xA9, 0xAE, 0x4F, 0x03, 0xD9, 0xCC, 0xA2, 0x8F, 0x3B, 0x9F, 0x2F, 0x06, 0xAC, 0x23, 0xE3, 0xD2, 0xCF, 0x76, 0xF0, 0x19, 0x50, 0x6F, 0xEC, 0x5C, 0x6E, 0x99, 0x07, 0x58, 0x7F, 0xB3, 0xBF, 0x4C, 0x2B, 0xE6, 0x58, 0xC5, 0x6E, 0xD6, 0x31, 0x88, 0x46, 0x56, 0xD6, 0xC2, 0x0E, 0xE1, 0x0B, 0x78, 0xD8, 0xF2, 0xD8, 0x01, 0x82, 0x30, 0xCD, 0xF9, 0x5E, 0xB8, 0x6E, 0x9C, 0xFD, 0xA2, 0xE1, 0x55, 0xBA, 0x33, 0x58, 0x12, 0xFC, 0x72, 0xEB, 0x88, 0x0B, 0xEA, 0x3A, 0x8C, 0x3A, 0x98, 0xCB, 0x56, 0x71, 0xE0, 0xE4, 0x03, 0x70, 0x4A, 0x55, 0x33, 0x62, 0x5B, 0x3E, 0xFA, 0x5C, 0xD3, 0x6C, 0x93, 0xDA, 0x37, 0x77, 0x21, 0xBF, 0x43, 0x82, 0xA0, 0xD0, 0x11, 0x77, 0xBC, 0xC5, 0xBC, 0xB4, 0xB7, 0x08, 0x23, 0x32, 0xE3, 0xE5, 0x85, 0x1B, 0x17, 0xF7, 0xB9, 0xD9, 0x10, 0xD2, 0x19, 0xEC, 0x5F, 0x98, 0xB9, 0xCE, 0x2E, 0xD2, 0x7F, 0x40, 0xB5, 0x72, 0x13, 0x8F, 0xE9, 0xA0, 0x3F, 0x15, 0x48, 0x65, 0x23, 0xB2, 0x9A, 0xA4, 0xC6, 0x07, 0x60, 0x17, 0xEF, 0xD2, 0x70, 0x70, 0x56, 0x0A, 0xC6, 0x13, 0xB3, 0x1D, 0x76, 0xB9, 0x60, 0x07, 0xEA, 0x98, 0xD7, 0xB0, 0x1D, 0x9A, 0x92, 0x54, 0x0C, 0x6A, 0x03, 0x0C, 0x4D, 0x0B, 0x98, 0x50, 0x8A, 0x14, 0x51, 0xE6, 0x48, 0x7F, 0x11, 0x2E, 0xF9, 0xE9, 0x05, 0xBA, 0x88, 0x92, 0x7A, 0xD6, 0x19, 0xEE, 0xEC, 0x6B, 0x58, 0xEE, 0xF0, 0x62, 0xE9, 0x1D, 0x35, 0x10, 0xB4, 0xED, 0xDA, 0xB2, 0xE5, 0xF9, 0x15, 0x46, 0x70, 0xEA, 0x8C, 0xF0, 0x00, 0x4C, 0xA4, 0xE2, 0xCC, 0xB5, 0xCE, 0x6C, 0x18, 0x70, 0xDA, 0x6B, 0xD8, 0xFD, 0xDC, 0x36, 0x41, 0x03, 0x91, 0x08, 0x82, 0x23, 0xF1, 0x53, 0xF6, 0x83, 0x97, 0x6B, 0xAB, 0x00, 0x87, 0xB2, 0xAF, 0x15, 0x7C, 0xA7, 0x89, 0x3E, 0x5C, 0x34, 0xF8, 0x38, 0xB2, 0x2A, 0xE6, 0x51, 0x4A, 0xB3, 0x81, 0xF4, 0x7A, 0x63, 0x3E, 0xC8, 0x9A, 0x2E, 0x1E, 0x51, 0x11, 0x18, 0x75, 0xB3, 0xAE, 0x9A, 0xEB, 0x66, 0x7D, 0xC8, 0x38, 0x6D, 0xB8, 0x1F, 0x13, 0xFF, 0x8D, 0xF7, 0x38, 0xB1, 0x02, 0x15, 0xDA, 0x52, 0x21, 0x01, 0xEF, 0xB8, 0xAD, 0xC9, 0xB1, 0x08, 0x75, 0xA4, 0x79, 0xB6, 0x47, 0x93, 0xB2, 0x4C, 0x67, 0x68, 0x41, 0xE3, 0x5C, 0x97, 0xA8, 0xE7, 0xEE, 0xBC, 0x6C, 0x51, 0x72, 0xCA, 0x88, 0x66, 0x1F, 0x2B, 0x62, 0x86, 0x46, 0x31, 0x2A, 0x68, 0x8C, 0xCC, 0x12, 0x43, 0x7D, 0x70, 0x39, 0x0C, 0x3E, 0x16, 0x21, 0x92, 0x0E, 0x65, 0x53, 0x98, 0xFF, 0x9A, 0x7E, 0x53, 0x74, 0xDF, 0xEC, 0xE4, 0x00, 0x19, 0x5B, 0x6A, 0x43, 0x1C, 0xDC, 0xC4, 0xB2, 0xF4, 0x4D, 0xAA, 0xC9, 0xBF, 0x91, 0x5E, 0x1B, 0x23, 0xA8, 0x5F, 0xED, 0x35, 0xE3, 0xC4, 0x3F, 0xCF, 0x02, 0x13, 0x04, 0x02, 0x10, 0x94, 0x83, 0x13, 0x48, 0x98, 0x37, 0x08, 0x0F, 0x1D, 0x80, 0x30, 0x27, 0xB0, 0x98, 0x95, 0x11, 0xD0, 0x63, 0x16, 0x7B, 0x36, 0x58, 0xD3, 0xF9, 0x8C, 0x0D, 0x2C, 0xA8, 0x79, 0x76, 0x53, 0x49, 0x28, 0x98, 0xC8, 0x14, 0x0E, 0x21, 0x86, 0x9C, 0x56, 0x3A, 0x5C, 0x03, 0xB7, 0x86, 0x07, 0x8F, 0x63, 0x4D, 0x75, 0xED, 0x2B, 0xDA, 0xD2, 0x74, 0x22, 0x51, 0xB6, 0x36, 0x48, 0x7D, 0x1A, 0xFF, 0xAB, 0xF3, 0x1E, 0x66, 0x46, 0x98, 0xC1, 0x77, 0x3F, 0x4E, 0x4D, 0xE9, 0xF2, 0xC3, 0xA4, 0xFE, 0xE7, 0x58, 0xEA, 0x07, 0x34, 0x89, 0x46, 0x99, 0x48, 0xBC, 0x9B, 0x50, 0xDB, 0x60, 0xD0, 0x5D, 0x9F, 0x18, 0x31, 0x41, 0x48, 0x94, 0xC2, 0x06, 0x19, 0x0E, 0xCD, 0xE8, 0xF2, 0x49, 0xBD, 0x43, 0x57, 0x7C, 0x8D, 0x40, 0xCA, 0x61, 0x1D, 0x23, 0xB6, 0xF7, 0x54, 0xCB, 0x06, 0xC6, 0x77, 0xC7, 0x1A, 0x77, 0x00, 0xCB, 0x8A, 0xF9, 0x30, 0xC5, 0xFF, 0xDB, 0x55, 0x4C, 0xA6, 0xAB, 0xE6, 0xD0, 0x83, 0xEE, 0x1A, 0x5A, 0xBF, 0xAA, 0x27, 0xA6, 0xF3, 0x1A, 0x83, 0x02, 0xBF, 0xD5, 0x78, 0xBC, 0x52, 0x93, 0xBD, 0xA4, 0xC1, 0x84, 0xE7, 0xD7, 0xBB, 0x58, 0x9F, 0x6D, 0xEA, 0x11, 0xC9, 0xF3, 0x9A, 0xB9, 0xCD, 0x09, 0x8A, 0x72, 0x81, 0x63, 0xD7, 0x96, 0x2B, 0x6A, 0x40, 0x06, 0xF2, 0x65, 0x27, 0x73, 0xD5, 0xD8, 0xCA, 0xDA, 0x35, 0xFB, 0x07, 0xDD, 0x8D, 0x39, 0x2D, 0xF7, 0x07, 0x9D, 0x1D, 0x72, 0x1D, 0xFA, 0xEC, 0xFF, 0xAC, 0xDB, 0x80, 0x81, 0x42, 0xFB, 0xA4, 0xF3, 0xC9, 0xB5, 0xC3, 0x1C, 0x81, 0xBB, 0x58, 0xA9, 0xAA, 0x30, 0x1F, 0x3D, 0x54, 0xEB, 0x4B, 0x0D, 0xBF, 0xF7, 0xF2, 0x67, 0x73, 0xB4, 0x56, 0xD5, 0xC0, 0x2F, 0x94, 0x25, 0x4E, 0xB7, 0x7E, 0x35, 0x3A, 0x68, 0x75, 0x3D, 0xCD, 0xC6, 0x2E, 0xC2, 0x3B, 0xDD, 0x5D, 0x6B, 0xBA, 0x07, 0xDB, 0x3E, 0xAC, 0x51, 0xE6, 0x4C, 0x34, 0xB4, 0xB5, 0x34, 0x38, 0xBF, 0x7C, 0x6E, 0xF9, 0xC6, 0x23, 0x7B, 0x68, 0xF6, 0x98, 0xE4, 0x31, 0x50, 0x77, 0x23, 0xA2, 0xE3, 0xBC, 0x43, 0xDD, 0xB6, 0xD9, 0x52, 0xA4, 0xF1, 0x2B, 0x43, 0xF7, 0x64, 0xF7, 0x5B, 0x5C, 0x6C, 0xB8, 0x82, 0xF7, 0xFE, 0xB7, 0x38, 0xAE, 0x3F, 0xB9, 0x1C, 0xBF, 0x49, 0x7E, 0x8E, 0x1D, 0x1B, 0x1D, 0x59, 0x22, 0x79, 0xAF, 0x26, 0x16, 0x6C, 0xCA, 0x5A, 0xBD, 0xD2, 0x8E, 0x6E, 0xFF, 0x4F, 0xBA, 0x74, 0x60, 0x5E, 0xA8, 0x85, 0xCE, 0xEB, 0x5A, 0x01, 0xEA, 0xFD, 0xE3, 0x16, 0x93, 0x9C, 0x35, 0xB8, 0x01, 0x0D, 0xD8, 0x57, 0x9A, 0x3A, 0x94, 0xFC, 0x68, 0x5E, 0xEB, 0x1F, 0x62, 0x83, 0xC5, 0xE6, 0xAD, 0x51, 0xE8, 0x2A, 0x93, 0x51, 0xC9, 0xD1, 0xA3, 0xFD, 0xB8, 0xB3, 0xD2, 0x6D, 0x02, 0x93, 0xA8, 0xBC, 0xBF, 0x25, 0x6B, 0x5E, 0x5B, 0xB3, 0x31, 0x23, 0x3A, 0x30, 0xDA, 0xF0, 0xFE, 0x4A, 0xDE, 0x80, 0x82, 0xB3, 0x03, 0xC3, 0x9E, 0x55, 0x1D, 0xBC, 0xC3, 0x02, 0xBF, 0x9B, 0x8A, 0xD3, 0x93, 0x3C, 0xB9, 0xAD, 0x90, 0x0A, 0x68, 0x25, 0x36, 0x7E, 0x15, 0x3E, 0x89, 0x6B, 0xC9, 0xAF, 0xDF, 0x8E, 0x40, 0x55, 0xA9, 0xD0, 0x9B, 0x85, 0x4C, 0xA8, 0x3D, 0x3A, 0xDF, 0x6E, 0x00, 0x43, 0x75, 0xC4, 0xED, 0xE4, 0xEC, 0x5C, 0x57, 0x80, 0x5F, 0x79, 0xA2, 0x06, 0x03, 0x4C, 0x51, 0x40, 0xCC, 0x60, 0x27, 0x7E, 0xAA, 0x74, 0xCD, 0xEE, 0xE9, 0xF0, 0x49, 0x3E, 0x90, 0x91, 0xC2, 0x29, 0x98, 0xB6, 0x13, 0x86, 0x3C, 0xE3, 0xAB, 0x77, 0x98, 0x39, 0x2E, 0x69, 0x67, 0x58, 0xC0, 0x32, 0x28, 0x6E, 0x10, 0x39, 0xBB, 0x13, 0x6C, 0x7C, 0x54, 0x30, 0xCB, 0xCD, 0x6D, 0x99, 0x9A, 0xA1, 0xF7, 0xB2, 0x8B, 0xE6, 0x03, 0x32, 0xCE, 0x70, 0xF5, 0x6E, 0xE3, 0x1C, 0x9E, 0xAB, 0x2D, 0x1E, 0x41, 0x3F, 0x0E, 0x65, 0x59, 0xE1, 0xF5, 0xCC, 0x6A, 0x5A, 0xAA, 0x8A, 0xD2, 0x64, 0x46, 0x88, 0x85, 0x52, 0x18, 0x1B, 0x8A, 0xA5, 0x30, 0xE4, 0xC6, 0x64, 0x68, 0x01, 0x08, 0x00, 0xAD, 0x5A, 0x94, 0xF3, 0xA0, 0xDD, 0x36, 0x9F, 0x1D, 0x5D, 0x16, 0xA8, 0x3A, 0x5F, 0xF7, 0x49, 0xC5, 0xFE, 0xC8, 0x67, 0x2F, 0x92, 0xE5, 0xC8, 0x40, 0x0B, 0xD7, 0x67, 0x1F, 0x91, 0xFC, 0x06, 0x97, 0x21, 0x53, 0x14, 0xF0, 0x26, 0x51, 0x61, 0x42, 0xCA, 0xA6, 0x03, 0xED, 0x19, 0x11, 0x5A, 0xAC, 0x9C, 0x32, 0x5D, 0x18, 0x34, 0x0E, 0x67, 0x62, 0xEF, 0xBA, 0xCF, 0xEF, 0x8E, 0x33, 0x13, 0x3C, 0x0F, 0x8F, 0x84, 0xBE, 0x6C, 0x1F, 0x95, 0xCB, 0x24, 0x45, 0x3D, 0xD8, 0x46, 0xEB, 0xC6, 0x29, 0x5C, 0x7E, 0x7D, 0xF9, 0x44, 0xB0, 0x17, 0xF1, 0xEF, 0x8A, 0x47, 0x85, 0x22, 0x96, 0xF0, 0x91, 0x96, 0xD1, 0x51, 0xB7, 0x8D, 0x77, 0xC9, 0xC1, 0xDA, 0x7D, 0x99, 0x75, 0xE5, 0x89, 0x83, 0xD3, 0x31, 0xE1, 0x78, 0x3F, 0xA6, 0x3B, 0xD9, 0x0C, 0x58, 0xC8, 0x2E, 0x4B, 0xFD, 0xDF, 0x8F, 0x0B, 0x4C, 0x37, 0xBB, 0xA4, 0x39, 0x07, 0x4F, 0x32, 0xE4, 0x1A, 0xBB, 0xCC, 0x90, 0xB5, 0x6C, 0x6A, 0xD3, 0x6E, 0xC8, 0xAB, 0x1F, 0xB3, 0x34, 0xCE, 0x59, 0xDA, 0x0E, 0xEF, 0xBE, 0x46, 0x5B, 0xF9, 0x62, 0x67, 0x4D, 0x25, 0x81, 0x5F, 0x22, 0x10, 0x84, 0x86, 0x56, 0x93, 0xB0, 0x3A, 0x44, 0xF6, 0x39, 0xF3, 0xA4, 0x7C, 0x36, 0xEE, 0xB2, 0x46, 0xD3, 0x90, 0x7D, 0x2F, 0x1D, 0x23, 0x78, 0xD7, 0xD7, 0x93, 0xD3, 0x95, 0xC3, 0x65, 0x52, 0x5A, 0x46, 0x5D, 0x9C, 0xE4, 0x15, 0x25, 0x41, 0xE5, 0x94, 0xA7, 0x29, 0xAC, 0x62, 0xEE, 0x4E, 0x3A, 0xB5, 0x89, 0xE7, 0xB0, 0x01, 0xD5, 0xF2, 0x35, 0x4E, 0x3E, 0x30, 0xB1, 0x82, 0xBD, 0x69, 0xDC, 0x5A, 0x87, 0x7F, 0xF1, 0xCB, 0x87, 0xFB, 0x9C, 0x25, 0x60, 0xBF, 0xE8, 0x2D, 0x3E, 0xDB, 0x06, 0x3B, 0xB7, 0x4D, 0x4B, 0x1F, 0x5C, 0xF3, 0x31, 0xB2, 0xD8, 0x4B, 0x45, 0x98, 0x8E, 0x04, 0xF7, 0x18, 0x32, 0xF0, 0x27, 0x2C, 0xD5, 0xA8, 0x44, 0x91, 0x9E, 0xC3, 0x41, 0x3A, 0xE0, 0xE9, 0x9F, 0x0A, 0x8D, 0xAD, 0xC1, 0x87, 0xE9, 0xBD, 0x9A, 0x4D, 0xF9, 0xE1, 0x05, 0xD1, 0x81, 0x37, 0x60, 0xC4, 0xFA, 0x32, 0x95, 0xBC, 0x22, 0x51, 0x7E, 0x89, 0x07, 0xD9, 0x85, 0xD2, 0x79, 0xEA, 0x25, 0x67, 0x4C, 0x78, 0x53, 0x18, 0x80, 0x5D, 0x1D, 0xBC, 0xD7, 0x97, 0x62, 0x46, 0x83, 0xC3, 0x63, 0xEA, 0xCA, 0xFE, 0x62, 0xC0, 0x78, 0x83, 0x4A, 0x5B, 0x13, 0x78, 0x7F, 0xAF, 0x0A, 0xB3, 0xB4, 0xD2, 0x45, 0x71, 0x3B, 0x02, 0x22, 0x2A, 0x8A, 0x60, 0x56, 0x23, 0xA5, 0xE1, 0xE5, 0x0F, 0x5D, 0xBB, 0xAB, 0x95, 0x6A, 0xBC, 0xA5, 0xF0, 0x64, 0x11, 0xD5, 0x97, 0xB0, 0xFB, 0x2D, 0x6D, 0xCC, 0x65, 0x0E, 0x77, 0x65, 0xF5, 0xE2, 0x3C, 0x4B, 0x8B, 0xC2, 0xB7, 0xAE, 0x0C, 0x88, 0x58, 0xB6, 0x50, 0xD1, 0x66, 0x89, 0x10, 0x38, 0x54, 0x39, 0x2C, 0xB2, 0x41, 0x0E, 0xBD, 0x20, 0x8D, 0xF2, 0xE8, 0xD6, 0xF2, 0x21, 0x33, 0xCB, 0x63, 0xBC, 0x21, 0xE9, 0x69, 0xDC, 0x67, 0xA0, 0xE2, 0xEE, 0xDC, 0x42, 0x8E, 0x3B, 0x71, 0xC8, 0x31, 0x89, 0x9B, 0x8D, 0x41, 0x22, 0xE5, 0x96, 0x69, 0xC1, 0x42, 0xBA, 0xB2, 0x0A, 0xFF, 0x7E, 0xD1, 0x89, 0x54, 0xB6, 0x52, 0x4B, 0x8C, 0x58, 0xD3, 0x91, 0xE3, 0x70, 0x61, 0xD1, 0xD5, 0x66, 0xEA, 0x04, 0x42, 0x7E, 0x91, 0x44, 0x09, 0x5F, 0xDB, 0x1A, 0x28, 0xC1, 0xFD, 0x49, 0xCA, 0xD9, 0xFD, 0x55, 0xD7, 0x54, 0x7F, 0xF9, 0xD6, 0x0D, 0x54, 0xF7, 0x20, 0x5E, 0xBE, 0xD4, 0x96, 0xD1, 0xE9, 0xDE, 0xDB, 0x8B, 0x28, 0xCE, 0xF8, 0x1D, 0x1A, 0xA5, 0x78, 0x05, 0x76, 0xD6, 0x7D, 0x70, 0x23, 0x21, 0xE5, 0x89, 0xD4, 0x4A, 0x60, 0xE2, 0x1F, 0xA0, 0x7B, 0xD9, 0x2D, 0xCF, 0xA1, 0x57, 0xF1, 0x0D, 0xA6, 0x0F, 0xAD, 0x6E, 0x44, 0x28, 0x07, 0xD4, 0xE1, 0xCF, 0x5F, 0x7A, 0xBD, 0x0B, 0xB4, 0xBF, 0x1D, 0x7F, 0xF3, 0x6A, 0x0E, 0x63, 0x6E, 0x30, 0x0C, 0xD8, 0x57, 0x55, 0x33, 0x1B, 0x22, 0x05, 0x97, 0x87, 0x23, 0xD9, 0xAC, 0xE6, 0xF2, 0xD5, 0x6F, 0xEC, 0x9D, 0x54, 0x59, 0x4C, 0xDB, 0x64, 0x3B, 0x8A, 0x9D, 0x8E, 0x6F, 0x76, 0x5C, 0xCE, 0xEF, 0x28, 0x19, 0xB3, 0xEF, 0x55, 0xDE, 0x38, 0x9F, 0xDC, 0x00, 0x79, 0x27, 0xD2, 0x22, 0xF1, 0x1D, 0x22, 0x76, 0xDD, 0x18, 0xD4, 0xDF, 0x86, 0xE8, 0xE7, 0xE2, 0xA4, 0xD9, 0x94, 0x3D, 0xD8, 0x83, 0xD7, 0x0B, 0xC0, 0x45, 0xB6, 0xAF, 0xAB, 0xED, 0xDF, 0x42, 0x18, 0xA2, 0x5A, 0xBF, 0x3F, 0xB0, 0xD4, 0x13, 0xD6, 0x18, 0x37, 0xC4, 0x5B, 0x86, 0xF9, 0xE6, 0xC6, 0x25, 0x53, 0x37, 0xC3, 0x8A, 0xF3, 0x5B, 0xE8, 0x2B, 0xE1, 0xF0, 0x3A, 0xF0, 0x81, 0x1F, 0x2F, 0x1E, 0xEB, 0x25, 0x27, 0x6B, 0xF6, 0xAB, 0x27, 0xB9, 0x25, 0x64, 0x33, 0x4F, 0x06, 0x3A, 0x83, 0x18, 0xFC, 0x69, 0xC1, 0x34, 0x70, 0xDA, 0x6F, 0xD9, 0x47, 0xB7, 0xEE, 0x2F, 0x67, 0xA7, 0x60, 0x5F, 0x6A, 0x57, 0x95, 0x3F, 0x96, 0xA3, 0x35, 0xB5, 0x50, 0x12, 0x63, 0x98, 0x67, 0x49, 0x02, 0x11, 0x88, 0x62, 0xF0, 0x86, 0x3F, 0x93, 0x13, 0xA3, 0x6A, 0xD0, 0x57, 0x34, 0xE5, 0x1F, 0x54, 0x98, 0x62, 0x17, 0x0E, 0xC3, 0x69, 0x5A, 0x67, 0xE0, 0xC1, 0x6C, 0xDC, 0xDE, 0xA7, 0x7B, 0x39, 0x5D, 0x1F, 0xC4, 0xF8, 0xF1, 0x3A, 0x08, 0xBA, 0x8D, 0x4C, 0xC4, 0x09, 0xCA, 0xBC, 0x9B, 0x15, 0xF1, 0x00, 0x7A, 0x4E, 0x3E, 0x4A, 0x71, 0x37, 0xB7, 0x00, 0xBE, 0xF5, 0xC3, 0x32, 0x97, 0x73, 0x5B, 0xE4, 0xC0, 0xAD, 0xB5, 0x4A, 0xA2, 0xDB, 0xE0, 0x96, 0x2D, 0x16, 0x83, 0x55, 0x5C, 0xFC, 0xB8, 0x84, 0x17, 0xD7, 0x19, 0x4B, 0x7A, 0xDF, 0x09, 0xB3, 0xD2, 0xD5, 0xBA, 0xDE, 0xB1, 0xE8, 0x47, 0xAF, 0x62, 0x11, 0x65, 0x45, 0x4C, 0x4D, 0xA0, 0x0D, 0x11, 0x85, 0x06, 0xE8, 0x25, 0xBD, 0x8F, 0x90, 0xDE, 0x0C, 0xC1, 0x1A, 0xFA, 0xD8, 0x5E, 0x08, 0xE9, 0x0E, 0xB5, 0xC4, 0x42, 0xD5, 0xB8, 0x5C, 0x9A, 0x9B, 0x86, 0xF2, 0x75, 0x8F, 0x4B, 0xB9, 0xDA, 0x95, 0xA7, 0xB5, 0xB5, 0x85, 0xD6, 0x1A, 0x5C, 0x0E, 0x6E, 0x92, 0x0B, 0xBC, 0x43, 0x64, 0x97, 0xBB, 0x6C, 0x9A, 0xB8, 0x18, 0xAF, 0xCB, 0x5C, 0xE8, 0x14, 0x81, 0x09, 0xED, 0x99, 0x94, 0x2E, 0x07, 0x90, 0xC5, 0xE2, 0x71, 0x4F, 0x4A, 0x88, 0x06, 0x74, 0xF4, 0xC6, 0x86, 0xF0, 0x7B, 0x48, 0xF5, 0xB8, 0x35, 0x9F, 0x9A, 0xF6, 0x3E, 0xB2, 0x05, 0xA3, 0x7B, 0xC0, 0xC6, 0x39, 0xDF, 0x09, 0x3F, 0x88, 0xBB, 0x45, 0xCA, 0x1B, 0xA0, 0xDD, 0xD7, 0x1D, 0xB7, 0x4A, 0x22, 0xCE, 0x88, 0x4B, 0x39, 0x83, 0xD4, 0x54, 0xD5, 0x69, 0x56, 0x66, 0xED, 0x88, 0xDB, 0xB1, 0x66, 0xE9, 0x98, 0x96, 0xEA, 0xBF, 0x67, 0x6B, 0xB8, 0x6D, 0x0E, 0xF3, 0xBD, 0xCF, 0x24, 0x1F, 0x50, 0xF2, 0x67, 0x2E, 0x3C, 0xD3, 0xBD, 0xAE, 0x60, 0xE6, 0xEC, 0xCD, 0xEF, 0x96, 0xDF, 0x63, 0x90, 0x88, 0xE4, 0x45, 0x7A, 0xEE, 0xE7, 0x74, 0x6C, 0x24, 0xBD, 0x67, 0x6F, 0x3E, 0xFE, 0xA2, 0x7D, 0xDC, 0xDA, 0xC8, 0xA4, 0x1C, 0xA5, 0xBF, 0x9E, 0x03, 0xC8, 0xF5, 0xAF, 0xBB, 0xC8, 0x9B, 0x6D, 0x96, 0xBF, 0x90, 0xD9, 0x4C, 0xFF, 0xD9, 0x1E, 0x3A, 0x8A, 0x07, 0xCC, 0xF0, 0x44, 0x93, 0xA5, 0xCB, 0x44, 0x1A, 0x9F, 0x59, 0x61, 0xEA, 0xC7, 0x1C, 0xEA, 0xB0, 0x4A, 0x78, 0xF7, 0x0B, 0x4F, 0x52, 0xF4, 0x63, 0x09, 0x45, 0xAC, 0xC4, 0x5F, 0x4F, 0x83, 0xEE, 0x96, 0x7C, 0xF2, 0xB2, 0x37, 0x5D, 0x0F, 0xCE, 0x3A, 0x3F, 0x6E, 0x43, 0x96, 0x36, 0x14, 0xCC, 0xE0, 0x36, 0x03, 0xF0, 0x59, 0x7D, 0x30, 0xE1, 0xD6, 0x75, 0xC0, 0x0F, 0x3C, 0xCA, 0xC4, 0x49, 0x21, 0xD2, 0x92, 0x28, 0xFF, 0x52, 0x96, 0xD4, 0x35, 0x25, 0x2F, 0x9C, 0xB3, 0x26, 0xA4, 0xD6, 0xFC, 0x34, 0xF0, 0x79, 0x89, 0xC1, 0x84, 0x28, 0x86, 0x74, 0x59, 0xD1, 0x82, 0x95, 0xD2, 0xD6, 0x12, 0x10, 0x7F, 0x75, 0x35, 0xED, 0x27, 0xF6, 0x84, 0x6C, 0xA8, 0xD3, 0xB1, 0x73, 0x9D, 0x23, 0x45, 0xD2, 0x8B, 0xCC, 0xC4, 0xFD, 0x1A, 0x63, 0x14, 0xFD, 0x47, 0x88, 0x9B, 0x53, 0xA1, 0xA7, 0x34, 0x63, 0x4B, 0xEC, 0x0C, 0x0A, 0x1C, 0x8A, 0x0A, 0x89, 0xAC, 0x66, 0xB0, 0xF4, 0xE5, 0x32, 0x8F, 0x76, 0x39, 0x2D, 0x01, 0x73, 0xE1, 0x74, 0xEB, 0x8F, 0xA6, 0x0F, 0x86, 0xC9, 0x7F, 0x00, 0x20, 0xDC, 0xFA, 0x4E, 0x69, 0x94, 0xFC, 0x08, 0xFD, 0xCF, 0x40, 0x5A, 0x44, 0xB1, 0xC4, 0x8C, 0xC2, 0x1C, 0x51, 0xA0, 0x92, 0x81, 0x73, 0x71, 0xF9, 0x6E, 0x64, 0xBD, 0x2B, 0x69, 0xBA, 0x79, 0xD7, 0xE4, 0xDD, 0x2C, 0x1F, 0x71, 0x8B, 0xF4, 0x56, 0x39, 0xCB, 0x45, 0x39, 0xE1, 0xF8, 0x9C, 0xF0, 0xE5, 0xEF, 0x25, 0x88, 0xE2, 0x5D, 0xEB, 0x44, 0x10, 0x1D, 0x3C, 0x12, 0xE1, 0x4B, 0x99, 0x3C, 0x0A, 0xB3, 0x55, 0x61, 0x13, 0x82, 0x19, 0x59, 0xC6, 0xE9, 0xFC, 0x9A, 0xCC, 0x95, 0xBA, 0x17, 0x31, 0x4A, 0xC5, 0x6D, 0x2B, 0x26, 0xA0, 0x39, 0x10, 0x69, 0x2A, 0xA4, 0xE1, 0x58, 0xF6, 0x81, 0xCB, 0xAA, 0x7C, 0x0F, 0xF8, 0x03, 0xD6, 0x66, 0x4B, 0x60, 0x9E, 0x5A, 0x4A, 0x25, 0x73, 0x58, 0x9F, 0xCD, 0x16, 0x8D, 0x17, 0x90, 0x13, 0x32, 0x3E, 0x4B, 0x4F, 0x51, 0x53, 0x68, 0x6B, 0x74, 0x75, 0x78, 0x7C, 0xA2, 0xAF, 0xB6, 0xC4, 0xC5, 0xF4, 0xF8, 0x0D, 0x1D, 0x37, 0x46, 0x4D, 0x55, 0x57, 0x6A, 0x7B, 0x8C, 0xAC, 0xB2, 0xC6, 0xC7, 0xC8, 0xD2, 0xEA, 0xF4, 0xF9, 0xFC, 0x18, 0x19, 0x20, 0x25, 0x27, 0x39, 0x5A, 0x5E, 0x90, 0xA4, 0xAF, 0xE8, 0xEF, 0xF2, 0xF8, 0xF9, 0x11, 0x29, 0x38, 0x68, 0x76, 0xAC, 0xAD, 0xBD, 0xD6, 0xDA, 0xE1, 0xEB, 0xF3, 0x1B, 0x38, 0x5D, 0x67, 0x76, 0x81, 0x87, 0x8A, 0x91, 0x94, 0xAE, 0xC2, 0xD6, 0xD9, 0xDF, 0xFF, 0x01, 0x02, 0x1B, 0x2F, 0x34, 0x3B, 0x3F, 0x40, 0x58, 0x94, 0xAE, 0xB1, 0xBD, 0xC5, 0xD5, 0xD7, 0x0A, 0x20, 0x23, 0x2D, 0x30, 0x3C, 0x65, 0x6C, 0x75, 0x76, 0x7E, 0x83, 0x90, 0xC2, 0xE7, 0xEB, 0x0C, 0x51, 0x64, 0x77, 0x88, 0xA4, 0xBB, 0xC1, 0xC7, 0xDB, 0xDC, 0xE5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x28, 0x38, 0x45, 0x55, 0x65, 0x75, 0x81, 0x02, 0x10, 0x1C, 0x20, 0x18, 0x40, 0x08, 0x09, 0x06, 0x4C, 0x04, 0x04, 0x02, 0x85, 0x00, 0x1D, 0xA0, 0x42, 0x9C, 0x48, 0x00, 0x81, 0x8C, 0x40, 0xC1, 0x42, 0x00, 0xC1, 0x0D, 0x09, 0x01, 0x94, 0xE8, 0x78, 0x5E, 0x1F, 0xF5, 0x65, 0x11, 0x03, }, }, { .name = "Dilithium Round 2, Level 5 (8-7) KAT 0", .version = 0, .keyform = CK_IBM_DILITHIUM_KEYFORM_ROUND2_87, .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 = { 0x89, 0xDB, 0xBF, 0xC3, 0x69, 0x33, 0x5D, 0x8F, 0x70, 0xE7, 0xBC, 0xB4, 0xD1, 0x66, 0xD4, 0xBD, 0xD0, 0xD8, 0x36, 0xE4, 0x5D, 0xE9, 0x37, 0x92, 0xED, 0xC4, 0x26, 0x10, 0x6F, 0xBF, 0x5A, 0xF2, 0x7C, 0x68, 0xA9, 0x50, 0xB4, 0xA1, 0xA6, 0x42, 0x28, 0x01, 0xC6, 0xF2, 0xAC, 0xC3, 0xA9, 0xFA, }, .s1_len = 672, .s1 = { 0x91, 0xB4, 0x2D, 0xA1, 0x38, 0x24, 0x08, 0x19, 0x24, 0x1A, 0x30, 0x4D, 0x40, 0xA8, 0x6C, 0xD8, 0x04, 0x6A, 0x03, 0x28, 0x04, 0x41, 0x38, 0x22, 0x22, 0x39, 0x0A, 0xE2, 0x80, 0x0D, 0x12, 0x49, 0x91, 0x24, 0xB4, 0x50, 0x93, 0x46, 0x89, 0xD1, 0x30, 0x4C, 0x04, 0x20, 0x24, 0x20, 0x20, 0x31, 0x59, 0x92, 0x41, 0xC3, 0x26, 0x61, 0x14, 0x47, 0x32, 0xDB, 0x12, 0x69, 0x63, 0x46, 0x01, 0x10, 0x93, 0x91, 0x10, 0x39, 0x81, 0x5B, 0x26, 0x71, 0x40, 0xB0, 0x01, 0x03, 0x41, 0x48, 0x04, 0x19, 0x09, 0x13, 0xB4, 0x91, 0x0C, 0x46, 0x08, 0xD4, 0x08, 0x09, 0x0C, 0x99, 0x04, 0x00, 0x35, 0x61, 0x13, 0x14, 0x4C, 0x19, 0x41, 0x28, 0x1C, 0x16, 0x80, 0x88, 0xA0, 0x29, 0x1A, 0x30, 0x02, 0x10, 0x80, 0x4C, 0x13, 0x43, 0x25, 0x04, 0x08, 0x81, 0x20, 0x43, 0x70, 0x14, 0x11, 0x6A, 0x99, 0x00, 0x40, 0x48, 0x82, 0x31, 0x12, 0x42, 0x20, 0x48, 0x06, 0x0D, 0xE2, 0xA2, 0x0C, 0x82, 0xB0, 0x28, 0xE2, 0x36, 0x10, 0x49, 0x16, 0x84, 0xD8, 0x04, 0x4C, 0x51, 0xB8, 0x68, 0xC2, 0x84, 0x90, 0x9B, 0x10, 0x31, 0x21, 0x49, 0x32, 0x94, 0x20, 0x0D, 0x04, 0x41, 0x24, 0xCB, 0xA4, 0x6D, 0x1A, 0x82, 0x61, 0x08, 0x40, 0x8E, 0xA4, 0x00, 0x44, 0x93, 0x92, 0x91, 0x8C, 0x30, 0x62, 0x60, 0xB2, 0x90, 0x58, 0x40, 0x62, 0x11, 0x97, 0x31, 0x21, 0x11, 0x81, 0x0C, 0x28, 0x88, 0x09, 0x07, 0x42, 0x88, 0x40, 0x6C, 0xC0, 0x96, 0x28, 0x81, 0x28, 0x8A, 0xC0, 0x12, 0x0C, 0x93, 0x48, 0x4C, 0x89, 0x82, 0x25, 0xD8, 0x00, 0x22, 0x24, 0x45, 0x41, 0x1B, 0x95, 0x2C, 0xA0, 0x92, 0x61, 0x84, 0xA2, 0x70, 0x59, 0x86, 0x10, 0x0B, 0x87, 0x08, 0x10, 0x98, 0x61, 0xD3, 0x40, 0x0D, 0x40, 0xB0, 0x8D, 0x09, 0x05, 0x71, 0x60, 0x84, 0x70, 0x18, 0x80, 0x61, 0x1A, 0x16, 0x2E, 0x63, 0x32, 0x06, 0x80, 0x80, 0x88, 0x50, 0xC6, 0x8C, 0x00, 0x10, 0x24, 0xC1, 0x00, 0x26, 0x94, 0x90, 0x48, 0x44, 0xB6, 0x29, 0x1A, 0x35, 0x48, 0xD3, 0xB0, 0x91, 0x21, 0xA4, 0x08, 0x11, 0x34, 0x32, 0x03, 0x01, 0x05, 0x21, 0x32, 0x46, 0x1B, 0x31, 0x31, 0x1B, 0x86, 0x0C, 0x1A, 0x28, 0x0D, 0xD1, 0x08, 0x28, 0x8B, 0xA8, 0x0D, 0x98, 0x90, 0x05, 0xD0, 0xA8, 0x29, 0x83, 0x48, 0x71, 0x03, 0x33, 0x80, 0x24, 0x90, 0x68, 0xD1, 0xA0, 0x2C, 0x23, 0x10, 0x4D, 0x12, 0x95, 0x11, 0xE4, 0x14, 0x21, 0x14, 0x39, 0x4E, 0x12, 0x01, 0x70, 0x0C, 0x25, 0x71, 0x24, 0x83, 0x89, 0x54, 0x30, 0x06, 0x11, 0x90, 0x45, 0x12, 0x03, 0x04, 0x59, 0xB0, 0x4C, 0x20, 0x36, 0x8A, 0x19, 0x30, 0x72, 0x98, 0x94, 0x4C, 0x14, 0x81, 0x40, 0xA2, 0xC6, 0x84, 0xCB, 0xA2, 0x48, 0x0C, 0xC1, 0x2D, 0x8A, 0xC4, 0x05, 0x42, 0x94, 0x45, 0x5B, 0xB4, 0x08, 0xDB, 0x18, 0x24, 0x88, 0x20, 0x90, 0x1B, 0xC3, 0x50, 0xA1, 0x96, 0x4D, 0x0B, 0x31, 0x6D, 0x93, 0x26, 0x46, 0x00, 0x35, 0x52, 0x01, 0x13, 0x42, 0xDA, 0x46, 0x6A, 0x1A, 0x34, 0x01, 0x40, 0x92, 0x41, 0xC0, 0x08, 0x66, 0xE3, 0x94, 0x01, 0x63, 0x28, 0x69, 0x0C, 0x25, 0x31, 0x0B, 0x21, 0x24, 0x43, 0xA2, 0x30, 0xD3, 0x22, 0x44, 0xCB, 0x36, 0x71, 0x02, 0x02, 0x42, 0x1A, 0xC1, 0x2C, 0x20, 0x23, 0x80, 0x8B, 0xA8, 0x85, 0x88, 0x08, 0x4A, 0x94, 0x10, 0x48, 0x18, 0x81, 0x29, 0xE2, 0xB4, 0x4C, 0x89, 0x88, 0x51, 0xC9, 0x06, 0x09, 0xD3, 0x96, 0x71, 0x54, 0xB0, 0x91, 0x53, 0x86, 0x04, 0x53, 0xC4, 0x44, 0x81, 0x98, 0x11, 0x88, 0x20, 0x04, 0xA0, 0x16, 0x0A, 0x49, 0xA0, 0x10, 0x1A, 0x17, 0x44, 0x21, 0x26, 0x66, 0xE0, 0xC0, 0x09, 0x59, 0x90, 0x8C, 0x93, 0x10, 0x49, 0x00, 0x85, 0x65, 0x4C, 0xC6, 0x0D, 0x00, 0x18, 0x30, 0x1B, 0x12, 0x6E, 0x10, 0x02, 0x45, 0xA2, 0x12, 0x49, 0x22, 0xC8, 0x20, 0x03, 0xC5, 0x48, 0x12, 0x04, 0x52, 0xA1, 0x88, 0x25, 0x40, 0xB2, 0x4D, 0x4B, 0x38, 0x28, 0x23, 0xB2, 0x64, 0xC2, 0x38, 0x90, 0x09, 0x46, 0x92, 0x0C, 0x90, 0x0D, 0x04, 0x06, 0x0C, 0x4C, 0x16, 0x2D, 0x08, 0x10, 0x49, 0x20, 0x47, 0x65, 0x50, 0x28, 0x29, 0x1A, 0x88, 0x80, 0x40, 0x30, 0x6D, 0x88, 0x36, 0x70, 0x63, 0x98, 0x71, 0x99, 0x96, 0x2C, 0x1B, 0x91, 0x61, 0x61, 0x40, 0x06, 0x13, 0x35, 0x04, 0x09, 0x08, 0x8E, 0x54, 0xB8, 0x44, 0x81, 0x30, 0x08, 0xC8, 0x10, 0x2C, 0x5A, 0xB0, 0x04, 0x42, 0x46, 0x61, 0x20, 0x03, 0x88, 0x91, 0xA0, 0x91, 0x81, 0x10, 0x4D, 0x12, 0xB7, 0x81, 0x20, 0x42, 0x02, 0x54, 0x94, 0x24, 0x59, 0xC4, 0x25, 0x8C, 0x44, 0x70, 0xE3, 0x32, 0x8E, 0x9A, 0x02, 0x60, 0xE4, 0xA6, 0x21, 0x4A, 0xB2, 0x85, 0x93, 0x36, 0x20, }, .s2_len = 768, .s2 = { 0x01, 0x05, 0x32, 0x11, 0x44, 0x66, 0xE2, 0x06, 0x40, 0x14, 0x49, 0x6C, 0x0B, 0x86, 0x80, 0x02, 0x47, 0x26, 0xD2, 0xB2, 0x25, 0x58, 0x48, 0x0E, 0x58, 0x44, 0x11, 0xD1, 0x44, 0x50, 0x51, 0xB8, 0x81, 0xC4, 0xA0, 0x48, 0x10, 0xC9, 0x50, 0x08, 0x98, 0x88, 0xD8, 0x28, 0x2A, 0x52, 0xC0, 0x4D, 0xD1, 0x38, 0x12, 0xD8, 0x46, 0x89, 0x00, 0x94, 0x00, 0xDA, 0xC4, 0x45, 0x9B, 0x44, 0x6E, 0x0B, 0x44, 0x0C, 0xC0, 0xC0, 0x01, 0x20, 0xC1, 0x0C, 0xC0, 0x04, 0x4C, 0x08, 0x24, 0x21, 0x23, 0xC7, 0x65, 0x03, 0xA0, 0x80, 0x91, 0xC2, 0x50, 0x21, 0x10, 0x31, 0x99, 0x36, 0x00, 0x64, 0x28, 0x70, 0x81, 0x38, 0x05, 0x4A, 0x18, 0x80, 0x1C, 0x89, 0x24, 0x08, 0x95, 0x49, 0x24, 0x39, 0x40, 0x24, 0x15, 0x22, 0xD9, 0x32, 0x90, 0x23, 0x24, 0x71, 0xC4, 0x46, 0x50, 0xCB, 0x86, 0x65, 0xE4, 0x94, 0x8C, 0x42, 0x04, 0x82, 0x8A, 0x86, 0x71, 0x13, 0xA3, 0x00, 0xDB, 0x44, 0x04, 0x23, 0x82, 0x10, 0x23, 0x46, 0x26, 0x0B, 0x08, 0x08, 0x60, 0x16, 0x11, 0xA4, 0xB6, 0x24, 0xE1, 0x32, 0x69, 0x04, 0x17, 0x86, 0xE3, 0x84, 0x2C, 0x9C, 0x32, 0x41, 0x92, 0xC8, 0x61, 0x5A, 0x32, 0x26, 0x24, 0xC3, 0x29, 0x5A, 0xC8, 0x05, 0x0A, 0x06, 0x8E, 0xE1, 0x16, 0x20, 0x99, 0x94, 0x61, 0x19, 0xA2, 0x0C, 0x1B, 0x05, 0x2E, 0x1B, 0x44, 0x64, 0x9A, 0x00, 0x84, 0x8C, 0x18, 0x52, 0x84, 0xB4, 0x60, 0x82, 0x20, 0x08, 0x42, 0x48, 0x09, 0x84, 0x08, 0x46, 0x11, 0x00, 0x46, 0x13, 0x43, 0x01, 0xE1, 0x06, 0x91, 0x1B, 0x44, 0x8E, 0x01, 0x94, 0x64, 0x4A, 0x12, 0x09, 0x98, 0x38, 0x0E, 0xE4, 0x06, 0x25, 0x24, 0x13, 0x68, 0x13, 0x21, 0x06, 0x04, 0xB9, 0x40, 0x54, 0x24, 0x25, 0x14, 0x88, 0x69, 0x82, 0x38, 0x01, 0xA4, 0x28, 0x72, 0x50, 0x86, 0x61, 0x23, 0xB1, 0x88, 0xA2, 0x90, 0x08, 0x1C, 0x95, 0x30, 0x1C, 0x40, 0x82, 0x49, 0xC8, 0x64, 0xCA, 0x04, 0x40, 0x44, 0x98, 0x21, 0x0B, 0x24, 0x61, 0x1C, 0xA0, 0x4C, 0x09, 0xA4, 0x21, 0xC9, 0x08, 0x8A, 0x22, 0x13, 0x41, 0x80, 0xC8, 0x89, 0x23, 0xB1, 0x64, 0x1C, 0x11, 0x49, 0x40, 0xA2, 0x29, 0x61, 0xC8, 0x8C, 0x8B, 0x96, 0x91, 0x83, 0x02, 0x42, 0xE1, 0xB6, 0x85, 0x51, 0x86, 0x4C, 0x04, 0x43, 0x91, 0x4B, 0xB8, 0x69, 0x50, 0x24, 0x81, 0xC8, 0x04, 0x2E, 0x1B, 0xB9, 0x31, 0x93, 0x24, 0x00, 0x23, 0x86, 0x81, 0xC2, 0xB8, 0x61, 0x09, 0x00, 0x62, 0x14, 0x99, 0x41, 0x19, 0x37, 0x6E, 0x1C, 0x16, 0x30, 0x0A, 0x27, 0x45, 0x51, 0x10, 0x0D, 0x1C, 0x33, 0x4A, 0x10, 0x40, 0x80, 0xA0, 0x34, 0x62, 0xD8, 0x44, 0x4A, 0x01, 0x06, 0x45, 0x23, 0x83, 0x8C, 0x24, 0xA4, 0x85, 0x01, 0x04, 0x0C, 0x09, 0x03, 0x32, 0xDB, 0x90, 0x09, 0x4A, 0x14, 0x42, 0x01, 0x08, 0x21, 0x22, 0x08, 0x66, 0x8B, 0x28, 0x70, 0x24, 0x38, 0x31, 0x0C, 0x46, 0x69, 0x43, 0x44, 0x69, 0x9A, 0x34, 0x4D, 0x82, 0xC8, 0x40, 0x42, 0x42, 0x01, 0x23, 0xC7, 0x29, 0x91, 0x32, 0x72, 0x1B, 0x36, 0x4C, 0x1B, 0x33, 0x05, 0x13, 0x35, 0x61, 0x14, 0x02, 0x46, 0x08, 0x03, 0x65, 0x21, 0x87, 0x20, 0x09, 0x03, 0x91, 0xC1, 0xC4, 0x25, 0xE2, 0xA6, 0x4C, 0x81, 0x14, 0x48, 0x20, 0x25, 0x4D, 0x03, 0x19, 0x69, 0xA3, 0x00, 0x69, 0x54, 0xA8, 0x30, 0x9C, 0x86, 0x05, 0x9C, 0x36, 0x82, 0x03, 0x37, 0x0C, 0x0A, 0x15, 0x50, 0x9C, 0xC0, 0x91, 0x04, 0xB6, 0x91, 0x0C, 0x11, 0x80, 0x09, 0xB5, 0x70, 0x63, 0x20, 0x92, 0x44, 0x22, 0x71, 0xC1, 0x48, 0x44, 0x98, 0xC4, 0x6D, 0x64, 0xA6, 0x89, 0x0A, 0xA9, 0x40, 0x04, 0xB8, 0x50, 0x04, 0x34, 0x8C, 0xE2, 0xC4, 0x80, 0x02, 0x00, 0x12, 0xA3, 0x36, 0x46, 0xD2, 0x00, 0x01, 0x1C, 0x45, 0x46, 0x22, 0x33, 0x6D, 0x81, 0x92, 0x01, 0x08, 0x12, 0x86, 0x9C, 0x04, 0x51, 0xA3, 0x98, 0x30, 0x48, 0x10, 0x91, 0x19, 0xA0, 0x44, 0xC3, 0x04, 0x8D, 0x42, 0x90, 0x40, 0x43, 0x80, 0x44, 0xA4, 0x46, 0x71, 0x0B, 0xA2, 0x60, 0x52, 0x18, 0x6D, 0x0B, 0xB6, 0x85, 0x1B, 0xB2, 0x0C, 0x94, 0x12, 0x09, 0x04, 0xB6, 0x41, 0x18, 0xA8, 0x84, 0x10, 0x00, 0x22, 0x53, 0x42, 0x69, 0xC3, 0xA8, 0x81, 0x00, 0x25, 0x32, 0x81, 0x16, 0x28, 0x81, 0x44, 0x2D, 0xD4, 0xB4, 0x4D, 0x08, 0xC8, 0x45, 0x5A, 0x04, 0x01, 0xC1, 0x90, 0x50, 0x22, 0x14, 0x82, 0x63, 0xC6, 0x6D, 0x04, 0x22, 0x72, 0x1C, 0xB9, 0x44, 0x9B, 0x46, 0x0D, 0xC2, 0x14, 0x22, 0x91, 0xB0, 0x44, 0x21, 0x89, 0x68, 0xC4, 0x96, 0x08, 0x0A, 0xB9, 0x8C, 0x22, 0xB9, 0x40, 0xE2, 0x26, 0x50, 0x8C, 0x88, 0x25, 0xCB, 0xB8, 0x04, 0x54, 0x16, 0x25, 0x63, 0x34, 0x0C, 0x24, 0xB0, 0x29, 0xA3, 0x44, 0x20, 0x43, 0x46, 0x40, 0x9C, 0x02, 0x48, 0x5A, 0xC8, 0x2C, 0x00, 0x05, 0x31, 0x09, 0x18, 0x00, 0xDB, 0x46, 0x51, 0xD2, 0xB6, 0x2C, 0x44, 0x40, 0x88, 0x9A, 0x96, 0x24, 0x12, 0xA5, 0x90, 0x04, 0x39, 0x86, 0x10, 0x80, 0x2D, 0x10, 0x99, 0x21, 0x60, 0x06, 0x66, 0x21, 0x89, 0x4C, 0x91, 0x04, 0x60, 0x23, 0xB9, 0x01, 0x12, 0x11, 0x48, 0x12, 0x29, 0x51, 0xA1, 0x06, 0x45, 0x44, 0x22, 0x12, 0x03, 0x27, 0x8E, 0x23, 0x94, 0x84, 0x0C, 0x29, 0x06, 0x94, 0x86, 0x50, 0xE0, 0x48, 0x10, 0x24, 0x26, 0x40, 0x61, 0x04, 0x66, 0x9C, 0xB2, 0x84, 0x54, 0xC2, 0x2C, }, .t0_len = 3584, .t0 = { 0xD6, 0xD4, 0x27, 0x24, 0xCA, 0xFD, 0xF2, 0x81, 0xB9, 0xCA, 0xDC, 0x58, 0x04, 0x84, 0x83, 0x95, 0x49, 0x25, 0x4C, 0x9B, 0xE0, 0xA1, 0xF9, 0xAA, 0x9D, 0x76, 0xE6, 0x54, 0x63, 0xCD, 0x83, 0x14, 0x20, 0x65, 0xE7, 0xF7, 0x47, 0xBD, 0x27, 0x4C, 0xF3, 0x7E, 0x85, 0x70, 0xE0, 0xE6, 0x3A, 0xDB, 0xF8, 0x5F, 0x31, 0x79, 0x14, 0x75, 0xFF, 0x1A, 0x2F, 0x50, 0x5B, 0x53, 0x24, 0x77, 0x2C, 0xB0, 0xEB, 0x21, 0x9E, 0x2C, 0x28, 0xC4, 0xEF, 0xBC, 0x31, 0xE7, 0x13, 0xDF, 0x18, 0x77, 0x25, 0xB7, 0xBD, 0xE2, 0x90, 0xE6, 0x08, 0x98, 0x5B, 0x7D, 0x8A, 0x71, 0x14, 0x42, 0xD4, 0x03, 0xD2, 0x56, 0xF5, 0x35, 0xA4, 0x27, 0x1F, 0x6C, 0xC6, 0x5F, 0x91, 0xF1, 0xA7, 0x3F, 0x3B, 0x33, 0x94, 0x83, 0x3D, 0xF0, 0x12, 0x79, 0xDC, 0x71, 0xFB, 0x60, 0xBD, 0x14, 0x13, 0xBF, 0x23, 0xBA, 0x3A, 0x20, 0xC7, 0x15, 0xC1, 0x30, 0xDA, 0x19, 0x2D, 0x05, 0x1F, 0xF6, 0xEA, 0x7E, 0xDD, 0xBB, 0x81, 0xDB, 0xC4, 0xBE, 0xBA, 0xF6, 0x71, 0x41, 0x23, 0x6E, 0x5D, 0x9E, 0x09, 0x93, 0xFB, 0x7D, 0xC7, 0x06, 0x44, 0x83, 0xDA, 0x06, 0x99, 0xE8, 0x40, 0x21, 0x76, 0xC6, 0xB2, 0x0F, 0x24, 0x0D, 0x35, 0x87, 0xBC, 0x1B, 0x07, 0x3C, 0x9A, 0xA0, 0x09, 0xCB, 0xC1, 0xB0, 0x5F, 0x49, 0xCC, 0xBB, 0x25, 0x13, 0x12, 0x96, 0x92, 0xDF, 0x1C, 0xEC, 0xDA, 0x29, 0x54, 0xCC, 0xEC, 0xC1, 0x7B, 0xBB, 0x1D, 0x11, 0x96, 0x4F, 0xAE, 0xB0, 0xF9, 0xE0, 0x29, 0x21, 0x29, 0x59, 0xB6, 0x8E, 0x4B, 0xE0, 0x66, 0x64, 0xF9, 0x58, 0x74, 0x32, 0xC0, 0x2D, 0xE6, 0x15, 0x88, 0x51, 0x55, 0x57, 0x56, 0x5A, 0x26, 0xA6, 0xEC, 0xD6, 0xB4, 0xDE, 0x47, 0xF0, 0xB6, 0x47, 0x63, 0x77, 0x81, 0xEC, 0x19, 0x49, 0x32, 0xD2, 0x82, 0xFF, 0x1F, 0x83, 0x5E, 0xB8, 0x09, 0x66, 0xAB, 0xA2, 0x16, 0xB4, 0xE7, 0xF8, 0x8E, 0xAB, 0x97, 0x05, 0x21, 0x26, 0x4D, 0xB5, 0xD6, 0xF2, 0x83, 0xA4, 0xF6, 0x79, 0x1E, 0x32, 0x9F, 0xB8, 0xCB, 0x54, 0x25, 0xB9, 0x13, 0x9E, 0x96, 0xAB, 0xB3, 0x94, 0x4E, 0x35, 0xBB, 0x88, 0x64, 0x2A, 0xC0, 0xE7, 0xDC, 0xDA, 0xB9, 0xB5, 0x59, 0xD0, 0x9E, 0x29, 0x55, 0x72, 0xB2, 0x52, 0x92, 0xC0, 0x3C, 0xD5, 0xAB, 0x5E, 0x7B, 0xBE, 0x77, 0x61, 0xD8, 0x58, 0x3F, 0xAD, 0x91, 0x66, 0x91, 0x3F, 0xDE, 0x1B, 0x65, 0x8F, 0x87, 0x26, 0xC3, 0xF7, 0xE6, 0xD2, 0x65, 0x63, 0x17, 0xDA, 0xAF, 0xB9, 0x2E, 0x78, 0x7D, 0x24, 0xC5, 0xD8, 0x94, 0x7F, 0xF5, 0x95, 0xA5, 0x85, 0x3D, 0x61, 0x11, 0x73, 0xDF, 0x20, 0xF0, 0xAE, 0x01, 0x50, 0x75, 0x8C, 0x6B, 0x13, 0x1D, 0xFD, 0xEF, 0x36, 0xA0, 0x1D, 0x7C, 0x87, 0x4D, 0x0B, 0x8C, 0xD0, 0xC2, 0x53, 0x83, 0x56, 0x94, 0x06, 0xCB, 0xE4, 0x2A, 0x72, 0xD7, 0x09, 0x7E, 0x84, 0xD9, 0x82, 0x58, 0x39, 0xEB, 0xD1, 0x4F, 0x17, 0x5E, 0xD5, 0x1E, 0x6A, 0xC1, 0xA3, 0xF7, 0xF7, 0xBE, 0xFF, 0x60, 0xF5, 0xC0, 0x72, 0x73, 0x42, 0xD7, 0xDD, 0x34, 0x76, 0xDC, 0x9A, 0xE0, 0xE2, 0x7E, 0xDB, 0xB8, 0x86, 0xBF, 0xA0, 0x0D, 0x36, 0xFE, 0x80, 0xDA, 0x81, 0x6A, 0x45, 0xE0, 0xC8, 0x00, 0x0B, 0x6E, 0x23, 0xE9, 0xB5, 0xCA, 0xD0, 0x13, 0xB6, 0xDE, 0xBF, 0x74, 0x9E, 0xB7, 0x27, 0xB8, 0xD8, 0x3B, 0xFE, 0x26, 0xF6, 0xC5, 0x99, 0xD5, 0xBD, 0x45, 0xB5, 0x82, 0xB8, 0x4F, 0x4F, 0xC8, 0x34, 0x10, 0xEE, 0x2A, 0x67, 0x5C, 0x66, 0x14, 0x5F, 0x52, 0xCF, 0x36, 0x83, 0x29, 0x0C, 0xC7, 0x2A, 0x29, 0x28, 0x5D, 0x70, 0x66, 0x7A, 0x3A, 0x31, 0x58, 0x93, 0x54, 0xD9, 0x19, 0x31, 0x62, 0x5F, 0xFA, 0xCF, 0xB7, 0xE0, 0x2C, 0x03, 0xFE, 0x48, 0x09, 0x2A, 0x12, 0x0E, 0x5F, 0x43, 0x12, 0x76, 0xE8, 0x37, 0x4D, 0xBE, 0x15, 0x40, 0x96, 0xC8, 0x6C, 0x58, 0x79, 0x10, 0xF5, 0x05, 0x1A, 0x86, 0x14, 0x17, 0xC0, 0x6A, 0x73, 0x48, 0x0C, 0xE3, 0x19, 0x5C, 0xC9, 0x99, 0xF6, 0xB8, 0xB3, 0x01, 0x9B, 0x22, 0x37, 0x96, 0xC5, 0xE1, 0x1F, 0x73, 0x42, 0xC9, 0x74, 0x6A, 0xED, 0xBF, 0xA9, 0x44, 0xCD, 0x79, 0xB8, 0x5C, 0x10, 0x00, 0x07, 0xBB, 0x58, 0x69, 0x84, 0x3A, 0x23, 0xAD, 0x06, 0xD8, 0x1F, 0x5C, 0xB2, 0x9D, 0xD1, 0x7B, 0xCE, 0xE7, 0x55, 0x72, 0xB9, 0xE0, 0xCF, 0xDB, 0xD5, 0xA8, 0x3A, 0x30, 0x57, 0x44, 0x2D, 0xF0, 0x00, 0xDA, 0x7A, 0x3A, 0xA6, 0xFC, 0x5F, 0xB2, 0x89, 0xA1, 0x29, 0x99, 0x24, 0xD9, 0x23, 0x1F, 0xE1, 0xD0, 0xCF, 0x3C, 0x17, 0xF1, 0x80, 0x3F, 0x61, 0x43, 0xC0, 0x97, 0xF9, 0x54, 0x2C, 0x9A, 0xBB, 0x8F, 0x98, 0x77, 0xE4, 0xAE, 0xC5, 0x4A, 0xB9, 0x39, 0x93, 0xDC, 0x49, 0x87, 0xDF, 0x67, 0x80, 0x8B, 0xF7, 0xBE, 0xDE, 0xA8, 0x6B, 0x5C, 0x83, 0xD2, 0x48, 0xE9, 0x5E, 0xA3, 0x02, 0x45, 0x3F, 0x5F, 0x6B, 0x7F, 0xF5, 0xB5, 0xF5, 0x8B, 0x65, 0xD9, 0x32, 0xD2, 0xBF, 0x73, 0x7C, 0x51, 0x89, 0x3D, 0x89, 0xF0, 0x7D, 0xA5, 0xBF, 0xEA, 0x79, 0xD7, 0xE7, 0xFB, 0x2A, 0xAB, 0x82, 0x33, 0xA2, 0x7E, 0xB4, 0x4C, 0x68, 0x58, 0x05, 0x1D, 0x92, 0xB9, 0x98, 0xBC, 0x47, 0x51, 0xA4, 0x90, 0x2A, 0xA2, 0x22, 0xDE, 0x2D, 0x5C, 0xDC, 0xEC, 0x26, 0xB3, 0x6D, 0xBA, 0x47, 0xCC, 0xEB, 0x41, 0xFB, 0x19, 0x2D, 0xDF, 0xFD, 0x55, 0x12, 0xD8, 0x2B, 0x1B, 0xD3, 0x4D, 0x1E, 0xAA, 0x42, 0xF8, 0xCC, 0x50, 0x3F, 0x23, 0x85, 0x92, 0x42, 0x07, 0x9C, 0xBC, 0x1A, 0x55, 0xF0, 0x95, 0xAB, 0xB3, 0xC1, 0x87, 0x9F, 0xD1, 0xB4, 0x85, 0x04, 0xD8, 0x05, 0x4C, 0x15, 0xEB, 0x3E, 0xBF, 0x54, 0xA3, 0x2C, 0x5B, 0x62, 0xC0, 0x55, 0x55, 0xE4, 0xAC, 0x60, 0x36, 0x91, 0x9B, 0xB9, 0xA1, 0xBB, 0x53, 0x9E, 0x78, 0x86, 0x7A, 0x74, 0xF5, 0x3C, 0x23, 0xB1, 0xA1, 0x35, 0x98, 0x7D, 0x8B, 0xDD, 0x63, 0xE0, 0x92, 0xAB, 0x2B, 0xF1, 0xD8, 0xF6, 0x60, 0x38, 0xE1, 0x49, 0xAE, 0x41, 0x0B, 0x09, 0xAB, 0x25, 0xB4, 0xFE, 0x65, 0x53, 0xB3, 0x0E, 0x7B, 0xA7, 0xBF, 0x01, 0x36, 0x36, 0x8E, 0x3B, 0x8B, 0x73, 0x23, 0xA1, 0x24, 0x89, 0x02, 0x94, 0x7B, 0x2A, 0x39, 0x85, 0xB5, 0xC5, 0xCB, 0x80, 0x27, 0xAE, 0xF8, 0xA9, 0xE3, 0x42, 0xA3, 0xB7, 0x54, 0x3C, 0x31, 0x54, 0x72, 0x49, 0xFC, 0x77, 0x7C, 0x59, 0x2A, 0x31, 0xB8, 0x5B, 0x4B, 0x07, 0xE0, 0xAD, 0x87, 0x61, 0x2C, 0x3D, 0xF4, 0x9B, 0x9E, 0xB6, 0x6A, 0x53, 0xF4, 0x11, 0xC6, 0xD6, 0xDE, 0x9F, 0x26, 0x86, 0x95, 0x07, 0x74, 0x80, 0x6A, 0xD0, 0xCE, 0xBF, 0x25, 0x4C, 0x18, 0x2F, 0x3A, 0x5D, 0xF9, 0xE4, 0x29, 0xF0, 0x79, 0x2E, 0x96, 0x35, 0x95, 0xB8, 0x42, 0x6B, 0xB0, 0xCB, 0x53, 0x62, 0x75, 0x36, 0x26, 0x5C, 0x4F, 0x63, 0x46, 0xB4, 0xB0, 0x72, 0xEA, 0xB4, 0xD1, 0xE6, 0x87, 0xA4, 0xDE, 0x7B, 0x82, 0x89, 0x90, 0xEB, 0xF3, 0x38, 0x1F, 0x0B, 0x70, 0xE9, 0x26, 0xD6, 0x7B, 0x76, 0x89, 0x73, 0xF1, 0x02, 0x40, 0x80, 0xBD, 0x40, 0xC6, 0x7B, 0x81, 0x04, 0x09, 0x34, 0xD1, 0xC3, 0xC3, 0x77, 0x4D, 0xDE, 0x93, 0x28, 0xBE, 0x69, 0xBB, 0xD5, 0xDF, 0xE3, 0xF2, 0x80, 0xDB, 0x77, 0xFF, 0xC1, 0xA7, 0x8D, 0x11, 0x13, 0x34, 0xB4, 0x21, 0x97, 0x00, 0x2B, 0xD8, 0x5C, 0xD7, 0xCD, 0xF7, 0xCB, 0xB6, 0xED, 0x3F, 0x41, 0xCB, 0xB9, 0xAD, 0x48, 0x1F, 0x44, 0xA3, 0x35, 0x11, 0x55, 0xA5, 0x22, 0x35, 0x0A, 0x65, 0x8F, 0x69, 0x92, 0x11, 0xD7, 0xAA, 0x5E, 0x68, 0xA5, 0x27, 0x94, 0x76, 0xC0, 0x0B, 0xD9, 0xEE, 0x01, 0x0C, 0xEC, 0x6E, 0x51, 0x02, 0xD2, 0x70, 0x54, 0xC9, 0x74, 0xD1, 0x6B, 0xE4, 0xA6, 0xC6, 0x85, 0x99, 0xAE, 0x83, 0x01, 0x9C, 0xB1, 0x32, 0x4E, 0x35, 0x10, 0x4F, 0x10, 0x5A, 0x59, 0xE6, 0xCF, 0x07, 0x67, 0x30, 0xF3, 0x3A, 0x03, 0xED, 0xD7, 0xC9, 0x2E, 0x07, 0x36, 0xB5, 0x42, 0x98, 0x79, 0x0C, 0xA8, 0xD5, 0x28, 0x72, 0x74, 0x28, 0x23, 0x73, 0x19, 0x9E, 0x90, 0xB9, 0x49, 0x13, 0xB9, 0x9C, 0x06, 0xD7, 0xD5, 0xB6, 0xC4, 0x18, 0xF5, 0x5B, 0x66, 0x14, 0x13, 0x31, 0x13, 0x0E, 0x6B, 0xD5, 0x61, 0x52, 0xB8, 0xDB, 0x19, 0xB2, 0xFB, 0x1B, 0xB6, 0x5C, 0x8D, 0x21, 0xFC, 0xD4, 0xBE, 0x45, 0x1A, 0x4A, 0x1C, 0x0F, 0xEE, 0x73, 0xDB, 0xC3, 0x55, 0x7D, 0x36, 0x2C, 0x45, 0x3D, 0x8E, 0x6A, 0x43, 0xE9, 0x9E, 0x47, 0x97, 0xD1, 0xF2, 0x5B, 0x1A, 0x58, 0x98, 0x14, 0x81, 0x1D, 0x66, 0xB7, 0x31, 0xA7, 0x5E, 0x99, 0x3F, 0xF1, 0xD3, 0xBC, 0x42, 0x11, 0xF8, 0xC1, 0x51, 0x0B, 0x90, 0x40, 0x50, 0x68, 0x94, 0xB8, 0x6B, 0xA9, 0xFB, 0xA3, 0x55, 0x49, 0x61, 0xDF, 0x34, 0xFD, 0xB7, 0x65, 0x5F, 0xD9, 0x28, 0x37, 0x8B, 0x4E, 0x65, 0x00, 0x14, 0x77, 0xD1, 0xFC, 0xF1, 0x8C, 0xB7, 0x1C, 0x5E, 0x41, 0x71, 0x69, 0x6F, 0x33, 0xB2, 0xB6, 0x76, 0x30, 0x38, 0xD5, 0x12, 0xAC, 0xB0, 0xF7, 0xFE, 0xEE, 0x76, 0xF0, 0xFB, 0x16, 0x4E, 0x30, 0xFE, 0xB7, 0xD6, 0x37, 0xB3, 0xAB, 0x1E, 0x7F, 0x25, 0x1E, 0xF8, 0xC0, 0x54, 0x31, 0x46, 0x1C, 0x3A, 0xB9, 0x0F, 0x05, 0x7D, 0xA0, 0xF4, 0xD8, 0xC3, 0xB3, 0x78, 0x7A, 0xE5, 0x8C, 0xB0, 0x13, 0x6D, 0x68, 0xAC, 0xB6, 0x40, 0x7B, 0xCF, 0x67, 0x16, 0x20, 0x72, 0x3A, 0x02, 0x30, 0xD4, 0xF7, 0xDD, 0x7A, 0xDE, 0x77, 0x0C, 0x41, 0x8F, 0xCA, 0xD9, 0x97, 0x8F, 0x7C, 0x96, 0x22, 0x26, 0xCA, 0x6D, 0x65, 0x79, 0xBA, 0xDC, 0x67, 0x52, 0x23, 0x7C, 0x99, 0xD2, 0x4C, 0xA8, 0x04, 0xE9, 0xF1, 0xFC, 0xDC, 0x9A, 0xAA, 0x11, 0x1F, 0x2C, 0x90, 0x5E, 0xF0, 0x31, 0x69, 0x0D, 0x17, 0x65, 0xE8, 0x21, 0x93, 0x8A, 0x0B, 0x78, 0x46, 0xC3, 0xBB, 0x80, 0xDB, 0xEF, 0x95, 0x30, 0xC6, 0x8C, 0xAA, 0x0A, 0xDA, 0x96, 0x2A, 0x59, 0x5F, 0xD9, 0xE7, 0xAB, 0xD9, 0xE1, 0xF7, 0x6F, 0xF2, 0x97, 0xE1, 0x78, 0x50, 0x54, 0x13, 0xEE, 0x95, 0xFC, 0x0A, 0x95, 0x8D, 0x72, 0x0C, 0x2A, 0x23, 0x86, 0xA1, 0x64, 0x50, 0xF9, 0x7D, 0xE5, 0x8E, 0xE2, 0x27, 0xBF, 0xA3, 0x3C, 0xAA, 0xC0, 0x3F, 0x13, 0x5A, 0x83, 0x45, 0x46, 0x9F, 0x26, 0xC7, 0x70, 0x26, 0x91, 0x5E, 0xE2, 0x0F, 0xBD, 0x82, 0xB0, 0x9B, 0x02, 0xFE, 0xA7, 0x7A, 0xBC, 0xFB, 0x9D, 0xA8, 0x94, 0xD8, 0x67, 0x6E, 0x16, 0x0F, 0x1E, 0x1C, 0xEA, 0x42, 0x0B, 0x2C, 0xFE, 0x14, 0xFF, 0x08, 0xE1, 0x65, 0x0D, 0x56, 0x5B, 0x6C, 0xDF, 0x6A, 0xD7, 0xEE, 0x51, 0x3D, 0xC1, 0xE7, 0x34, 0x30, 0x96, 0xDD, 0x26, 0x5C, 0x45, 0x9F, 0xA1, 0x7C, 0x55, 0xE5, 0xD6, 0xC6, 0x38, 0x28, 0xBC, 0xC4, 0xB7, 0x2A, 0x2A, 0x02, 0x7C, 0x31, 0xD2, 0x43, 0x8A, 0x7B, 0xFF, 0x42, 0x77, 0x3F, 0xED, 0x94, 0x35, 0xC3, 0xC6, 0xED, 0x66, 0x4D, 0x35, 0x41, 0x86, 0x58, 0xCB, 0x13, 0x37, 0x43, 0xF4, 0x82, 0x73, 0x2F, 0x6F, 0xB2, 0xC8, 0x9C, 0x68, 0x00, 0x05, 0x20, 0x9D, 0xFB, 0xEE, 0xAB, 0x70, 0x2A, 0x39, 0x11, 0xA8, 0x7D, 0xD5, 0x5E, 0xF3, 0x9F, 0x40, 0x93, 0x70, 0xBE, 0x94, 0x88, 0x84, 0x42, 0xB0, 0x8D, 0xB3, 0x37, 0x08, 0xBC, 0xB3, 0x1A, 0x14, 0x07, 0x30, 0x3B, 0x4F, 0xED, 0xF3, 0x11, 0xC1, 0x52, 0x63, 0x57, 0x9F, 0x81, 0x74, 0x6C, 0xED, 0xFB, 0x79, 0x0C, 0xA0, 0x30, 0x4C, 0x88, 0xFC, 0xCA, 0x59, 0x56, 0xE9, 0xF8, 0x19, 0xFE, 0xFF, 0xAC, 0x13, 0xC6, 0x4D, 0x96, 0xC4, 0x3C, 0x98, 0xD8, 0x8F, 0xEC, 0x8F, 0xD9, 0x83, 0xC1, 0xC5, 0x19, 0xCB, 0x88, 0x4D, 0x2E, 0x7A, 0x90, 0xCD, 0xF3, 0x65, 0xFE, 0x5F, 0xB5, 0xDA, 0x8F, 0xAB, 0x74, 0xF0, 0x73, 0xBA, 0x25, 0x8D, 0x26, 0x4F, 0x94, 0x2D, 0x14, 0xD6, 0xE2, 0xE9, 0x08, 0x29, 0xAE, 0x35, 0x74, 0x6D, 0x05, 0x7A, 0x18, 0x0E, 0x56, 0x38, 0x42, 0xF5, 0x4C, 0x4B, 0xC7, 0xD5, 0x00, 0x49, 0x43, 0x24, 0x72, 0xD1, 0xED, 0xF1, 0x38, 0xF2, 0xE5, 0x86, 0x26, 0xAB, 0x8C, 0x96, 0xE6, 0x00, 0xED, 0x19, 0x36, 0xF3, 0x38, 0x80, 0xF4, 0xF2, 0x20, 0x1B, 0x61, 0x07, 0xC4, 0xEF, 0xB9, 0xC0, 0x2E, 0xCF, 0x31, 0x44, 0xE3, 0xAC, 0x55, 0xB0, 0xEE, 0x51, 0x68, 0xA7, 0x93, 0xB1, 0x5D, 0xB4, 0xA6, 0x1B, 0xFF, 0xFC, 0x8B, 0xE4, 0xA3, 0x80, 0x40, 0xA0, 0x6C, 0x31, 0xF5, 0x15, 0x2D, 0x7C, 0x95, 0xF8, 0xC4, 0x94, 0x45, 0x12, 0x4D, 0x07, 0x20, 0x95, 0xFC, 0x14, 0xF6, 0x79, 0xDF, 0x55, 0xDC, 0x1E, 0x7F, 0xBE, 0x48, 0x83, 0xDA, 0xA3, 0x50, 0xF2, 0x16, 0x98, 0xEB, 0x78, 0xB2, 0x9A, 0xDB, 0xD0, 0x71, 0x53, 0x58, 0xF9, 0x65, 0x27, 0x8A, 0xF8, 0x67, 0xC1, 0x2E, 0x2B, 0xB1, 0x9F, 0xFA, 0x16, 0x50, 0x27, 0x69, 0xF4, 0xFB, 0xDB, 0x20, 0x82, 0x2D, 0x1D, 0xE1, 0xFB, 0x6E, 0x41, 0x6D, 0x82, 0x29, 0x32, 0xB5, 0xCD, 0x5B, 0x37, 0x0A, 0x58, 0x65, 0x56, 0x07, 0x56, 0xD7, 0x6D, 0x8C, 0x2F, 0xE4, 0x70, 0x4E, 0x0B, 0x15, 0x83, 0xEB, 0x5D, 0x23, 0x5E, 0xC3, 0xFE, 0x7F, 0xF4, 0x98, 0xE1, 0x35, 0x61, 0x00, 0xC5, 0x80, 0x76, 0x3E, 0xB5, 0xF2, 0x36, 0x35, 0x62, 0x0C, 0xF6, 0xCC, 0x56, 0xE7, 0x4B, 0x48, 0x22, 0x3C, 0x70, 0xB5, 0xE5, 0x23, 0xAC, 0x61, 0xEA, 0xAE, 0xF8, 0x8E, 0x4D, 0xD1, 0x50, 0x5D, 0x25, 0xC9, 0x65, 0x8B, 0x96, 0xE9, 0x32, 0xCE, 0x0B, 0xD0, 0xEF, 0xFE, 0x80, 0xBA, 0xA5, 0xD1, 0x05, 0xA6, 0x51, 0x4B, 0x25, 0x57, 0x8D, 0x1F, 0x3F, 0xCC, 0x8F, 0xF5, 0xF9, 0x3A, 0x7C, 0xDD, 0xCC, 0xE0, 0x84, 0x0F, 0x63, 0x1B, 0xE0, 0x2B, 0xCA, 0x85, 0x20, 0x98, 0xDC, 0xFA, 0x06, 0x56, 0xF0, 0x8A, 0xF1, 0xBD, 0xC8, 0xE2, 0x4A, 0x27, 0x46, 0x74, 0x16, 0xF4, 0x87, 0xAD, 0x02, 0x60, 0x22, 0xDD, 0x5E, 0x1E, 0x1E, 0xFD, 0xC9, 0xC2, 0xB4, 0x71, 0xE3, 0x26, 0x53, 0x65, 0xF2, 0x0B, 0xC8, 0x21, 0x86, 0x37, 0x66, 0x25, 0x5D, 0x0A, 0xAC, 0x67, 0xB6, 0x58, 0xE6, 0x63, 0x3F, 0xD2, 0xC9, 0x3F, 0x80, 0xE5, 0x55, 0x5C, 0x6B, 0x3F, 0x9B, 0x9C, 0x54, 0x02, 0x62, 0xF9, 0x2E, 0x57, 0x5E, 0xCA, 0x8C, 0xBD, 0xDE, 0xA2, 0x5E, 0x35, 0x59, 0x9F, 0xAF, 0xE0, 0x90, 0x20, 0x1D, 0x53, 0x1A, 0x96, 0xA6, 0x59, 0x5F, 0x6B, 0xC0, 0xA0, 0x83, 0x47, 0xF4, 0x54, 0xFC, 0x12, 0x6A, 0x16, 0x21, 0x64, 0xA0, 0xD5, 0x07, 0x39, 0xF3, 0x0A, 0xB2, 0x29, 0x89, 0xF8, 0x88, 0xE4, 0xDF, 0xA3, 0x56, 0x13, 0x7A, 0x3E, 0x65, 0xEC, 0xB5, 0xF4, 0x7E, 0x20, 0x0E, 0x73, 0x36, 0xA2, 0xF0, 0xA5, 0xC5, 0x47, 0xA2, 0x36, 0x7F, 0x1D, 0x0F, 0xDE, 0xA8, 0x9D, 0x00, 0x69, 0x8D, 0x96, 0x2E, 0x62, 0xE8, 0xDA, 0xA5, 0x70, 0xEE, 0x07, 0x7B, 0x9E, 0xB8, 0x18, 0xED, 0x82, 0x75, 0xB2, 0x3E, 0x73, 0x39, 0xFA, 0x3A, 0x6C, 0x9E, 0xF0, 0xD3, 0xC9, 0x78, 0xEE, 0xF7, 0x5B, 0xC9, 0x77, 0xAA, 0xFE, 0x87, 0xB1, 0xA4, 0x1F, 0xED, 0x4C, 0x7D, 0xA1, 0x7E, 0x2B, 0xBE, 0xCC, 0xA8, 0xF4, 0x06, 0xF0, 0x40, 0xB1, 0x6F, 0xDD, 0xFB, 0x2E, 0x8F, 0x47, 0x0C, 0x25, 0x40, 0x9B, 0x8C, 0x7C, 0x13, 0x88, 0xE6, 0x08, 0xEB, 0xBA, 0xE2, 0x67, 0xF7, 0x7C, 0x5F, 0xE0, 0x10, 0xF6, 0x91, 0x7B, 0xC6, 0xCA, 0x7B, 0xF6, 0x86, 0x5F, 0xAA, 0x73, 0xE1, 0x0F, 0x2F, 0x60, 0xD2, 0x2D, 0xB2, 0x4A, 0x21, 0x71, 0x81, 0xBE, 0x56, 0xFD, 0x47, 0x3E, 0xE7, 0xAF, 0x5E, 0xD5, 0x60, 0x9A, 0xDA, 0x02, 0x36, 0xFA, 0xB3, 0x06, 0x6C, 0x3D, 0xAD, 0x28, 0xA2, 0x4F, 0x67, 0xD4, 0xCC, 0x1C, 0xEF, 0xE6, 0x10, 0x6F, 0x5E, 0x54, 0x27, 0xAC, 0xCD, 0xC7, 0x3F, 0xF8, 0x85, 0x76, 0xA2, 0x7A, 0xEB, 0xE7, 0x1A, 0x33, 0xDB, 0x3C, 0x08, 0x02, 0xD6, 0x97, 0x18, 0x95, 0x6C, 0xD9, 0xD1, 0x5A, 0xAA, 0x9A, 0x2D, 0xE3, 0xAC, 0x62, 0x10, 0x10, 0x0A, 0x2E, 0x39, 0xAF, 0x5B, 0xA9, 0x1D, 0xFA, 0x21, 0x8C, 0x53, 0x72, 0x66, 0x06, 0x2E, 0x32, 0x6E, 0x2F, 0xF8, 0xC4, 0x4D, 0x17, 0x80, 0xFB, 0xAF, 0xF4, 0xAD, 0xBA, 0x82, 0x71, 0x17, 0xE0, 0xBC, 0xB7, 0xA4, 0xC8, 0xF2, 0x61, 0x39, 0x81, 0x71, 0x3F, 0xA5, 0x98, 0xA4, 0x68, 0x3A, 0x46, 0x70, 0x85, 0x4C, 0x94, 0x67, 0xF2, 0x5A, 0x65, 0x6D, 0xDB, 0x6E, 0x7C, 0x3E, 0xF1, 0x92, 0xEB, 0xBD, 0xEE, 0x15, 0x3A, 0x59, 0x41, 0x61, 0x95, 0x26, 0xB3, 0x17, 0x87, 0x54, 0x4F, 0xE2, 0x31, 0x2A, 0x28, 0x98, 0x9C, 0x6A, 0xA3, 0xAC, 0xC0, 0xFE, 0x44, 0x23, 0x14, 0xFD, 0xFB, 0xD8, 0x08, 0x7F, 0x2B, 0x75, 0x5E, 0xB4, 0xB7, 0x35, 0x55, 0x76, 0x28, 0x3F, 0xA8, 0x6C, 0xD2, 0xD9, 0xEC, 0x1A, 0x6B, 0xD9, 0x4E, 0x6C, 0x5D, 0x72, 0x82, 0x02, 0xEC, 0x0B, 0x6E, 0xDF, 0xE1, 0xF3, 0x35, 0x84, 0x11, 0xC4, 0x9E, 0xC1, 0x10, 0x63, 0xAC, 0x1E, 0xDE, 0xB2, 0x1B, 0x95, 0xD7, 0x13, 0xD9, 0x0B, 0xE4, 0x96, 0xD8, 0x55, 0x84, 0xAA, 0x64, 0x25, 0x47, 0x14, 0x80, 0x84, 0x4E, 0x5B, 0xE2, 0xD7, 0x05, 0x3E, 0x87, 0x22, 0x03, 0x64, 0x79, 0xBD, 0xCB, 0x36, 0x38, 0x35, 0xBB, 0x08, 0xB0, 0x10, 0xDD, 0x0C, 0x08, 0x0E, 0x3D, 0x85, 0x24, 0xAE, 0x62, 0x21, 0x3E, 0x20, 0x8E, 0xC4, 0x12, 0xD0, 0x1F, 0xC9, 0xCE, 0xFA, 0x9C, 0x0A, 0xBD, 0x39, 0x64, 0x96, 0x45, 0x51, 0x84, 0xDB, 0x24, 0x4A, 0xD6, 0xBE, 0xB4, 0x5F, 0xB7, 0x68, 0x47, 0x91, 0x62, 0x47, 0x44, 0x33, 0x52, 0x0C, 0xE0, 0x63, 0x03, 0xFF, 0xC6, 0x06, 0x07, 0xDD, 0x43, 0x29, 0x62, 0x88, 0x4F, 0x8A, 0xA6, 0x54, 0x39, 0x98, 0xE1, 0xFB, 0x24, 0xDA, 0xF8, 0xAB, 0x3F, 0xF8, 0x62, 0xA8, 0x16, 0xA3, 0x98, 0x28, 0xF5, 0x7B, 0x54, 0x7A, 0xE7, 0x66, 0x98, 0x3F, 0x7C, 0xFA, 0xC8, 0x50, 0x23, 0xDC, 0x65, 0x53, 0x43, 0x12, 0x74, 0xB8, 0x40, 0x19, 0xDB, 0xD8, 0x5D, 0x2C, 0x42, 0x9D, 0x2B, 0x01, 0xE3, 0xC0, 0xA5, 0xDE, 0x1E, 0x6C, 0xC8, 0x5E, 0x62, 0x57, 0x9B, 0x00, 0x12, 0x6E, 0x6F, 0xE8, 0x1A, 0xB2, 0xEC, 0x08, 0x85, 0xD4, 0x30, 0x98, 0xA6, 0xF2, 0x15, 0x94, 0xD6, 0x67, 0x0F, 0x3E, 0xAB, 0x54, 0xEF, 0x3E, 0x30, 0xC7, 0x38, 0x96, 0x46, 0x1F, 0xE3, 0xCA, 0x4E, 0x8E, 0xD9, 0x29, 0x3E, 0x4F, 0x27, 0x6E, 0x18, 0xAA, 0xC8, 0x54, 0x46, 0xC0, 0xC2, 0x34, 0xFF, 0x6F, 0x9A, 0xE1, 0x1A, 0x09, 0x89, 0x9B, 0x3D, 0x22, 0x1C, 0xC6, 0xC4, 0xB3, 0x63, 0xF7, 0xBE, 0x27, 0xAD, 0xF3, 0xF5, 0x1C, 0xE4, 0xBD, 0x8F, 0x51, 0xC2, 0x1C, 0x7F, 0x44, 0xE3, 0x08, 0x3C, 0x8D, 0x04, 0x71, 0x24, 0x08, 0x4C, 0x1E, 0xDB, 0x09, 0x0A, 0x7D, 0x80, 0x56, 0x51, 0x7B, 0xBB, 0xD1, 0xF1, 0x87, 0xC4, 0x27, 0xDD, 0xA5, 0x9E, 0x54, 0x5E, 0x8C, 0x60, 0x03, 0xCA, 0x0B, 0xC5, 0xBD, 0x38, 0x9E, 0xBD, 0x90, 0xB9, 0x97, 0x08, 0xC3, 0xD3, 0xC7, 0x40, 0x44, 0xEB, 0x2A, 0xB3, 0xCA, 0x6F, 0x72, 0xD4, 0xB2, 0xD4, 0x91, 0x02, 0xB9, 0x74, 0x89, 0x64, 0x56, 0xFC, 0x67, 0x38, 0xE9, 0x0B, 0x94, 0x8C, 0x62, 0xE0, 0x16, 0x17, 0x14, 0x87, 0x1F, 0x57, 0x41, 0x9E, 0xCB, 0xAA, 0x16, 0xD0, 0x16, 0x65, 0xAC, 0xEB, 0x39, 0x69, 0xB4, 0x84, 0xA2, 0xE0, 0x29, 0xED, 0x6A, 0x73, 0x30, 0x0E, 0x06, 0xC8, 0x50, 0xAF, 0xEF, 0xFC, 0x08, 0xCE, 0x29, 0x61, 0x85, 0x4E, 0x9A, 0xA0, 0x65, 0x38, 0xFF, 0x6D, 0x9F, 0x5A, 0xEE, 0xAF, 0x57, 0x76, 0x1C, 0xB6, 0xAE, 0x36, 0x87, 0x1D, 0xC4, 0x17, 0x33, 0x2F, 0x30, 0x63, 0xBF, 0x91, 0x37, 0x21, 0x22, 0x68, 0xC3, 0x1F, 0x27, 0x8D, 0xC6, 0x85, 0xC1, 0xAD, 0x44, 0xD2, 0x22, 0x56, 0x6F, 0x9F, 0x18, 0x82, 0x3D, 0x55, 0x0E, 0x89, 0x86, 0x51, 0xD7, 0x65, 0x57, 0x1A, 0x10, 0x69, 0xB8, 0x27, 0x48, 0x61, 0x85, 0x34, 0x59, 0xCF, 0x49, 0xDB, 0x92, 0x37, 0x44, 0xC9, 0xC5, 0xC9, 0x3D, 0xD2, 0x6F, 0x66, 0x3F, 0x9A, 0xDD, 0xD0, 0xBF, 0x56, 0x38, 0x05, 0xB4, 0xB7, 0x47, 0xC0, 0xA6, 0xE5, 0xB5, 0x86, 0x90, 0x0C, 0x57, 0x25, 0x96, 0xF2, 0x12, 0x01, 0xD3, 0x74, 0x55, 0x53, 0xCA, 0x09, 0xD2, 0x19, 0xCB, 0x01, 0x79, 0xF0, 0xB1, 0x00, 0x17, 0xF0, 0xF1, 0x4D, 0x5A, 0xF3, 0xB9, 0x4B, 0xB4, 0xA9, 0x38, 0x61, 0x78, 0xA8, 0x2D, 0x2B, 0x14, 0x11, 0xED, 0x8B, 0x95, 0xAC, 0x40, 0xAE, 0x73, 0xB2, 0x36, 0xD9, 0xB7, 0x83, 0x25, 0x0F, 0x1B, 0x9B, 0xBD, 0xBD, 0x88, 0xC0, 0x9E, 0xEB, 0x29, 0x0A, 0x83, 0xD8, 0x0A, 0x44, 0x47, 0x60, 0xB9, 0x83, 0xB2, 0x70, 0x20, 0xF1, 0x28, 0xED, 0x00, 0xE5, 0xD1, 0xD3, 0xBB, 0xC8, 0xCE, 0x86, 0x21, 0x4E, 0xB5, 0xF5, 0x33, 0xCC, 0x80, 0xF2, 0x78, 0xB1, 0x92, 0xB5, 0x7A, 0xBB, 0x0F, 0xFA, 0x70, 0x3E, 0xBF, 0x0B, 0xAA, 0xE4, 0x92, 0x6D, 0x63, 0xC0, 0xFF, 0x51, 0x8A, 0x9B, 0xBE, 0xB3, 0x48, 0xD5, 0xB5, 0xA0, 0x4F, 0x6F, 0xFF, 0xCF, 0xD3, 0xA4, 0x25, 0xE5, 0x08, 0xBD, 0xAB, 0x88, 0xB4, 0x05, 0x7D, 0x94, 0xD6, 0xF8, 0xB1, 0xB0, 0x56, 0x78, 0x3F, 0xE4, 0x0B, 0xE6, 0xD6, 0xEF, 0xDF, 0x53, 0x1F, 0x52, 0x81, 0x15, 0xE2, 0xB3, 0x21, 0x11, 0xD2, 0xB7, 0xCE, 0x59, 0x90, 0x84, 0xE2, 0x0F, 0x9E, 0xAD, 0x59, 0x5A, 0xC9, 0x15, 0xCB, 0xAB, 0x2A, 0x48, 0x6C, 0x98, 0x5F, 0xB5, 0x0F, 0x6E, 0x2F, 0x3E, 0x16, 0x02, 0xD8, 0xE8, 0xCF, 0xA7, 0x68, 0x5A, 0xAA, 0x30, 0x5C, 0x06, 0x0F, 0x11, 0xDB, 0x98, 0x07, 0x40, 0xBB, 0xF4, 0xBD, 0xF4, 0xA7, 0x1A, 0x1C, 0x7E, 0x37, 0xC6, 0xC6, 0xE8, 0x91, 0x20, 0xAD, 0x91, 0x2C, 0x2F, 0x2A, 0xC0, 0x25, 0x0F, 0x0F, 0xCE, 0x82, 0x6C, 0x55, 0xB6, 0xFB, 0x0F, 0x63, 0x8D, 0xC0, 0xC5, 0x5E, 0x32, 0x7E, 0x92, 0x2D, 0xC4, 0x53, 0x75, 0x18, 0x69, 0xCD, 0xAB, 0xBC, 0x95, 0xA3, 0xC3, 0x50, 0x36, 0x8A, 0xF7, 0xAB, 0x4C, 0x17, 0xB0, 0x1D, 0x8B, 0xC4, 0x77, 0x74, 0xB9, 0x01, 0xA1, 0x8A, 0xDB, 0x86, 0x98, 0x10, 0x37, 0x67, 0x21, 0xDC, 0x23, 0x3D, 0x81, 0x1D, 0xF2, 0x20, 0x8C, 0x04, 0xDF, 0x9B, 0xEE, 0xB8, 0x28, 0xB0, 0x02, 0xEA, 0xA1, 0xF8, 0x64, 0x09, 0x1C, 0x1C, 0xD0, 0x90, 0xEA, 0x6F, 0xAB, 0xCC, 0x0B, 0x06, 0x4E, 0xD2, 0x91, 0x6A, 0xA1, 0x0F, 0x14, 0x4E, 0xE4, 0x47, 0x0A, 0x75, 0xAB, 0x04, 0xF2, 0xCC, 0xA1, 0xD8, 0xAC, 0x42, 0x48, 0x4D, 0xCE, 0x93, 0x46, 0x76, 0xE7, 0x4A, 0x2A, 0x9E, 0x19, 0xB0, 0x96, 0xF1, 0x08, 0x8E, 0xBD, 0x2F, 0xDE, 0x8D, 0x16, 0x78, 0x46, 0xAA, 0x33, 0xD1, 0x81, 0x31, 0x72, 0xE9, 0x2B, 0x13, 0xB6, 0x70, 0x81, 0xC4, 0x4C, 0x35, 0xF2, 0x55, 0xBB, 0x23, 0x6D, 0x0C, 0xF2, 0x9A, 0x58, 0xD0, 0xCC, 0xDE, 0xC3, 0x70, 0xC8, 0x6F, 0x84, 0x0D, 0xC6, 0xF9, 0x7A, 0x74, 0xBF, 0xAA, 0xCE, 0xFA, 0xBA, 0x55, 0x65, 0xD7, 0x73, 0x62, 0x3A, 0x24, 0x32, 0x92, 0xE6, 0xDC, 0x76, 0x57, 0x39, 0x23, 0xD5, 0x9A, 0xC4, 0x43, 0xDB, 0x86, 0xA3, 0x12, 0x9A, 0x54, 0x73, 0xB1, 0x19, 0x4D, 0x21, 0xA4, 0x61, 0xF6, 0x11, 0x4F, 0xDE, 0xC3, 0xA6, 0xD3, 0x8F, 0x28, 0xB3, 0x9B, 0x87, 0xF2, 0xEA, 0x06, 0x86, 0x67, 0x40, 0x94, 0x6B, 0x0D, 0x09, 0x7A, 0xF4, 0xB2, 0xC0, 0x6D, 0x36, 0xE9, 0xFC, 0xD2, 0x40, 0x48, 0x90, 0x8E, 0x38, 0xA6, 0xF7, 0x6E, 0xAB, 0xBC, 0x19, 0x76, 0x17, 0x92, 0x82, 0xEB, 0x0E, 0x51, 0xD0, 0xE8, 0x3B, 0xE5, 0xCD, 0x93, 0xE6, 0x14, 0xC1, 0x6B, 0xEC, 0x1E, 0xEC, 0xB9, 0xF1, 0x81, 0x08, 0x61, 0x70, 0x47, 0x59, 0xD1, 0xA0, 0x78, 0x92, 0xBF, 0x52, 0xF5, 0x5F, 0x89, 0x39, 0xA4, 0xDC, 0x30, 0x88, 0xFA, 0x16, 0x65, 0xF1, 0x35, 0xBD, 0x04, 0x77, 0xD0, 0x2D, 0xCD, 0xE5, 0x7E, 0x0C, 0x1C, 0x0F, 0xAC, 0x0F, 0xA7, 0x0A, 0x25, 0x6F, 0x9B, 0x9B, 0xEB, 0xC7, 0xEB, 0x33, 0xF6, 0x6D, 0xB4, 0xE7, 0x9D, 0xF4, 0xB0, 0x70, 0xD8, 0x31, 0x81, 0x56, 0xFD, 0x65, 0xE1, 0xB3, 0x6D, 0x37, 0xAC, 0xF9, 0xB0, 0xAA, 0xF0, 0x7C, 0x60, 0x34, 0x37, 0xC4, 0xA3, 0xD2, 0xFA, 0x2D, 0xCE, 0x6B, 0xCF, 0xAF, 0x18, 0x3F, 0x92, 0x1C, 0x6E, 0xE3, 0xE8, 0x7B, 0xD1, 0x75, 0x05, 0x7B, 0xC9, 0x97, 0xF9, 0x0D, 0x18, 0x59, 0xEF, 0x76, 0x01, 0xE6, 0x8D, 0x35, 0x84, 0x62, 0xAF, 0xE3, 0xBA, 0xD1, 0x92, 0x83, 0x60, 0xE1, 0xAA, 0xFC, 0xCC, 0x17, 0x0D, 0x0F, 0xD7, 0x65, 0x18, 0x0B, 0x57, 0xB0, 0x33, 0xCF, 0xCC, 0xE2, 0x89, 0x87, 0x8F, 0x41, 0x9B, 0x7D, 0x44, 0x71, 0xB7, 0xB0, 0xF3, 0xBF, 0x42, 0x56, 0xC0, 0x68, 0xDB, 0xCD, 0xBA, 0x7B, 0x0F, 0x20, 0x2C, 0xC7, 0x52, 0x9A, 0x76, 0xC0, 0x9D, 0xB1, 0x66, 0xA1, 0x98, 0x5E, 0x10, 0xB4, 0x6F, 0x83, 0x0F, 0x08, 0xF7, 0x3E, 0xB2, 0x54, 0xCC, 0x3E, 0x33, 0xD6, 0x90, 0xDF, 0xAB, 0xED, 0x3F, 0x77, 0xE4, 0xC4, 0x65, 0x47, 0x39, 0x90, 0x9E, 0x86, 0x1D, 0x04, 0x87, 0x49, 0x35, 0xD1, 0x20, 0x5D, 0xF3, 0x94, 0x1B, 0x10, 0x3D, 0x60, 0xF7, 0x1C, 0x36, 0x2B, 0xF0, 0x21, 0x91, 0x93, 0xF9, 0xAD, 0xAE, 0x49, 0xD3, 0x06, 0xF5, 0x0A, 0x34, 0x79, 0x09, 0x70, 0x8A, 0x41, 0x7C, 0x74, 0xF8, 0xB8, 0xC4, 0x4D, 0x8C, 0x7F, 0xBE, 0xD5, 0x2F, 0x1A, 0x00, 0x98, 0x88, 0xED, 0x7D, 0xA2, 0x55, 0x12, 0xD7, 0x3C, 0xA3, 0x76, 0x02, 0xD4, 0x6E, 0xEC, 0x02, 0x9D, 0x4F, 0x16, 0x84, 0x91, 0xC7, 0x0F, 0x2D, 0x0F, 0x13, 0x58, 0xCE, 0x37, 0x0C, 0x2C, 0xF2, 0x82, 0x35, 0x00, 0xE9, 0x89, 0xFB, 0x24, 0x72, 0x3C, 0x21, 0xDD, }, .t1_len = 2304, .t1 = { 0x94, 0x06, 0xE4, 0xDC, 0xE8, 0x12, 0xBE, 0x92, 0xE1, 0x53, 0xE0, 0x75, 0x2C, 0xFE, 0x26, 0xC1, 0x12, 0x7E, 0x9C, 0x80, 0xC8, 0x11, 0x3E, 0x12, 0x16, 0x95, 0xF9, 0x01, 0x4E, 0x03, 0xFF, 0xF1, 0xFD, 0x7B, 0xE3, 0xB0, 0xF4, 0x0E, 0xEE, 0x5B, 0x02, 0xF5, 0x60, 0x1E, 0x2F, 0xC3, 0xAF, 0xF0, 0xCD, 0xF7, 0xE7, 0xE7, 0x34, 0x99, 0x9C, 0x7F, 0xC4, 0xEB, 0x9D, 0xDA, 0x81, 0x8C, 0x52, 0x06, 0x93, 0xFE, 0x38, 0xE4, 0x49, 0xBE, 0x4C, 0xCF, 0x03, 0xFE, 0xA1, 0x72, 0x8E, 0x4C, 0xCA, 0x64, 0xFD, 0x11, 0x0B, 0xFC, 0x8E, 0xC9, 0xCB, 0x79, 0x50, 0x3B, 0xD5, 0x53, 0xF5, 0x89, 0x9A, 0x2F, 0x63, 0x16, 0x5D, 0x19, 0x32, 0x72, 0x7D, 0xB7, 0x44, 0x72, 0x65, 0xF7, 0x96, 0xF4, 0xFD, 0xBC, 0xFE, 0xA6, 0xF4, 0x05, 0x9E, 0x88, 0x34, 0x34, 0xC7, 0x98, 0xB8, 0x68, 0xF9, 0x86, 0x60, 0x5D, 0x4D, 0x03, 0xD3, 0x04, 0xB6, 0x77, 0xE3, 0x0F, 0xF7, 0xD7, 0x83, 0x0A, 0xDD, 0x06, 0x65, 0x2B, 0xCC, 0x1B, 0xF0, 0x4D, 0x33, 0xDF, 0xFE, 0xFC, 0xEF, 0x63, 0x4A, 0xF5, 0xBA, 0xE0, 0xD5, 0xC6, 0xBA, 0xB6, 0xC5, 0x64, 0xF1, 0x95, 0x20, 0x82, 0xAA, 0x38, 0x25, 0x53, 0x20, 0x01, 0x9C, 0xBC, 0x8E, 0xCA, 0x07, 0x3D, 0x80, 0xAF, 0x0A, 0x59, 0x6E, 0x4D, 0x33, 0xAD, 0x73, 0xB4, 0xF1, 0xED, 0xD4, 0x20, 0xE0, 0x90, 0x0B, 0xED, 0x47, 0x49, 0x5A, 0x88, 0x62, 0xD4, 0xA9, 0xCD, 0xDE, 0xD0, 0xDE, 0xA7, 0x74, 0xCD, 0xE0, 0x23, 0x8C, 0x71, 0x2B, 0x8A, 0xA9, 0x82, 0x47, 0x56, 0x66, 0x0D, 0x2B, 0x34, 0xE4, 0x7E, 0x4B, 0x59, 0x42, 0x5F, 0x17, 0xA9, 0x60, 0x8D, 0xAD, 0x38, 0x28, 0xEC, 0x9D, 0x8A, 0xDB, 0x5D, 0xD3, 0x8C, 0x7D, 0x53, 0xDD, 0xA6, 0xDA, 0xC7, 0x4D, 0x3F, 0xD0, 0x3C, 0x00, 0xB5, 0x9E, 0xE9, 0xA0, 0xE5, 0x27, 0x6E, 0x3E, 0x75, 0xD0, 0x13, 0x61, 0x01, 0x66, 0x49, 0x1D, 0x87, 0x3A, 0x7D, 0xA2, 0xC9, 0xFD, 0xA3, 0x60, 0xA6, 0x47, 0x73, 0x25, 0x00, 0x58, 0x41, 0x8F, 0xA7, 0x62, 0x63, 0x2D, 0xCB, 0x12, 0x63, 0x85, 0x27, 0x32, 0x60, 0x02, 0x18, 0x67, 0x53, 0xE6, 0xB5, 0xD3, 0x31, 0xE5, 0x64, 0x23, 0xC9, 0x70, 0x9D, 0x34, 0x9C, 0x69, 0x5A, 0x32, 0x8A, 0x56, 0x2B, 0x13, 0x9A, 0xF5, 0x98, 0xF8, 0x5D, 0xCB, 0x35, 0x98, 0x40, 0x7D, 0x82, 0xF8, 0x49, 0xC2, 0x9A, 0x87, 0xDC, 0x41, 0xFA, 0xA7, 0x69, 0x8F, 0xAC, 0x7F, 0x20, 0x4D, 0x70, 0xD0, 0x7D, 0x4A, 0xDC, 0x1D, 0x68, 0xFB, 0x46, 0x08, 0x63, 0xBB, 0x00, 0x2F, 0x3A, 0x23, 0x57, 0xCB, 0x65, 0xFB, 0x4B, 0x03, 0xBA, 0xB6, 0x8D, 0xB9, 0xB1, 0x1A, 0x09, 0xC9, 0x02, 0xE8, 0x12, 0x95, 0x91, 0x54, 0x16, 0xB4, 0x51, 0xD8, 0xE5, 0xFB, 0xF7, 0x81, 0x33, 0xBE, 0xD2, 0x81, 0x81, 0x37, 0x17, 0xE3, 0x74, 0xC5, 0xB4, 0x15, 0xE7, 0x77, 0x3F, 0x95, 0xD8, 0x3D, 0x8B, 0xF9, 0x7D, 0x4A, 0xC4, 0x5E, 0xAC, 0x28, 0x1E, 0x50, 0x89, 0x69, 0x32, 0xF7, 0xEE, 0xA4, 0x83, 0xE6, 0x98, 0xED, 0xD6, 0x07, 0xC3, 0xFF, 0xDD, 0xD3, 0x4C, 0x56, 0x67, 0x03, 0x28, 0xEB, 0xA5, 0xE1, 0xEB, 0x24, 0x9B, 0x8E, 0x26, 0x85, 0x38, 0xBF, 0x4C, 0xF3, 0x43, 0x2E, 0xD5, 0xA9, 0x33, 0xB8, 0x2E, 0x6C, 0x0E, 0x96, 0x0D, 0xE1, 0x8A, 0x20, 0x9F, 0xA3, 0x90, 0x96, 0x93, 0x87, 0x88, 0x4D, 0xAD, 0x8D, 0x8E, 0xE7, 0xE6, 0x0A, 0x89, 0x69, 0x90, 0x62, 0x16, 0x2F, 0x90, 0xBB, 0x28, 0xE4, 0xCC, 0xBA, 0x1A, 0x5F, 0x52, 0x6D, 0xE9, 0xCF, 0x7F, 0xEF, 0xEC, 0x7A, 0x77, 0xDD, 0xA0, 0x7C, 0xD7, 0x00, 0x09, 0xE4, 0x8E, 0xBF, 0x8E, 0xDD, 0x9B, 0x34, 0x87, 0x26, 0xA9, 0x37, 0xE1, 0x4F, 0xF5, 0xEB, 0x6E, 0x79, 0xE3, 0xDB, 0x1B, 0x60, 0xD7, 0x0A, 0x73, 0x05, 0x11, 0x15, 0x4A, 0x8A, 0xB8, 0x75, 0xF8, 0x6D, 0xEB, 0xCB, 0x9D, 0x79, 0x0F, 0xC4, 0x32, 0x84, 0x4E, 0x90, 0x3C, 0x8B, 0xD9, 0xFD, 0xB2, 0x8F, 0x99, 0x88, 0xDF, 0xAE, 0xA5, 0x56, 0xE9, 0x20, 0xE5, 0x79, 0x25, 0x47, 0xAE, 0xA7, 0xA4, 0x5B, 0x4C, 0x7E, 0x68, 0x41, 0x61, 0x1E, 0x33, 0x06, 0x4E, 0x5C, 0xB5, 0x9B, 0xBA, 0xEC, 0xA6, 0x9E, 0x38, 0xA0, 0x99, 0x94, 0xAE, 0xEA, 0x3D, 0x10, 0xF6, 0xFC, 0x53, 0xF6, 0x43, 0x56, 0x2F, 0xA0, 0x0A, 0x34, 0x12, 0xD4, 0xAF, 0xF8, 0x01, 0xD4, 0x8D, 0x0C, 0x58, 0xBA, 0x05, 0x5A, 0x42, 0xCD, 0xF6, 0xB8, 0xF1, 0x86, 0x16, 0x99, 0xEF, 0xD9, 0xAD, 0x9D, 0xF4, 0xCB, 0xB9, 0x88, 0xE7, 0x22, 0x17, 0x12, 0xBB, 0x42, 0xA4, 0x3B, 0xE8, 0x32, 0x25, 0x09, 0x11, 0x1D, 0x3A, 0x8E, 0xBC, 0x97, 0xFA, 0xEB, 0xF9, 0xF8, 0x5D, 0x69, 0x20, 0x76, 0x5A, 0x18, 0x2A, 0xD9, 0xC4, 0x54, 0x27, 0x99, 0x31, 0x70, 0x5E, 0xA2, 0x90, 0x3F, 0x6E, 0x18, 0x7D, 0x2A, 0xF6, 0xA5, 0xE4, 0xA8, 0x30, 0x54, 0x16, 0x8A, 0xA6, 0xA6, 0xF1, 0x27, 0xC8, 0xCE, 0x0C, 0x56, 0xA2, 0xEF, 0x67, 0xDC, 0x1C, 0xD9, 0xB2, 0x2A, 0x51, 0x39, 0xDA, 0xC1, 0x92, 0xFF, 0xC5, 0x3A, 0x13, 0xEC, 0x52, 0xA3, 0x22, 0x07, 0xA9, 0x6A, 0x4F, 0xED, 0xB1, 0x20, 0x55, 0xFF, 0xDD, 0xBE, 0xE6, 0xAE, 0xF0, 0x72, 0xF7, 0x5D, 0xB7, 0xC6, 0xCD, 0x37, 0xB2, 0x58, 0x9D, 0xC0, 0x0F, 0xBE, 0xF1, 0x33, 0x3E, 0xB1, 0x13, 0xC8, 0x22, 0x1B, 0xF8, 0x74, 0x0F, 0xD7, 0xBF, 0x7F, 0x39, 0xA5, 0x7E, 0x4A, 0xE2, 0xCE, 0x86, 0xE0, 0xE8, 0xB4, 0xE9, 0x21, 0x4D, 0x67, 0x21, 0x46, 0xED, 0xE9, 0x85, 0x87, 0x15, 0x71, 0x56, 0x5E, 0x9F, 0x59, 0xCD, 0xA5, 0x92, 0x22, 0xAC, 0x9C, 0x6C, 0x00, 0xD5, 0xA7, 0xC9, 0xD8, 0xA3, 0xE5, 0x46, 0xDE, 0xC8, 0x3C, 0x65, 0x54, 0xEA, 0x89, 0x13, 0x72, 0xBB, 0xCA, 0xE7, 0xD7, 0x76, 0x88, 0xDE, 0xD6, 0x0B, 0x52, 0x6C, 0x04, 0xC9, 0xBF, 0x0A, 0x7D, 0x96, 0x56, 0x81, 0x90, 0x4D, 0xAC, 0x03, 0x79, 0x1F, 0x08, 0xB0, 0x71, 0xF0, 0xEE, 0x5B, 0xAB, 0xA1, 0xC4, 0x6B, 0x15, 0x61, 0x75, 0x6E, 0x58, 0x9C, 0x33, 0x7B, 0xAB, 0x4F, 0x2B, 0x75, 0xAE, 0x3B, 0xF6, 0xE7, 0x74, 0x3F, 0x6C, 0xEE, 0x5F, 0x09, 0x93, 0xE7, 0x18, 0xC9, 0x58, 0x4D, 0x47, 0xEA, 0xD4, 0xC9, 0x61, 0xAE, 0x96, 0xF6, 0xD6, 0x02, 0xA5, 0x06, 0xA2, 0xA4, 0xC0, 0xF5, 0x7E, 0x88, 0x1D, 0x51, 0xDC, 0x24, 0xF2, 0x77, 0xEB, 0xA9, 0xCC, 0x3C, 0x6F, 0x23, 0x58, 0x29, 0xB5, 0xBA, 0x87, 0xC2, 0x1F, 0x12, 0x32, 0x1C, 0xEE, 0x8B, 0x6E, 0xE9, 0x08, 0x9B, 0xB5, 0x2C, 0x3A, 0x71, 0xAD, 0x61, 0x12, 0x46, 0xAE, 0xD9, 0x80, 0xC1, 0xB9, 0x47, 0xA6, 0x7C, 0x88, 0xA1, 0x10, 0xA7, 0xBD, 0x84, 0x49, 0xD0, 0x9C, 0xE3, 0x90, 0x6C, 0x65, 0x35, 0x45, 0x7D, 0x02, 0xF2, 0x32, 0x5C, 0x70, 0xEE, 0x78, 0x63, 0xAE, 0x63, 0x23, 0x0F, 0xC2, 0x3D, 0xEC, 0xA2, 0x99, 0xBB, 0x5B, 0x0E, 0x4B, 0x1A, 0xE8, 0xE2, 0x40, 0x1D, 0xFB, 0x9D, 0x4B, 0xDD, 0xD0, 0x61, 0x18, 0xBD, 0x15, 0x0F, 0x4B, 0x5C, 0xD3, 0x85, 0xAF, 0xB4, 0xFA, 0xD4, 0xEC, 0xA4, 0x6D, 0x61, 0xBE, 0xCA, 0xB1, 0x1D, 0x02, 0x70, 0x26, 0x67, 0x33, 0x33, 0xAB, 0x31, 0x4B, 0x9E, 0xF9, 0x1B, 0x7A, 0x7F, 0x94, 0x0B, 0xDA, 0x44, 0x44, 0xAE, 0xFE, 0x37, 0x03, 0x6A, 0x43, 0xF2, 0xB6, 0x8D, 0x0D, 0xFF, 0xD7, 0xAF, 0x33, 0xA3, 0x63, 0x0F, 0xDB, 0x32, 0x5A, 0x74, 0xDA, 0x7B, 0x09, 0x0F, 0x94, 0x9D, 0x06, 0x4B, 0xF7, 0x45, 0xB8, 0x93, 0x37, 0x15, 0x2B, 0x98, 0x0E, 0x4E, 0x20, 0xCC, 0x23, 0xFF, 0xAF, 0xCC, 0xBC, 0x7E, 0x95, 0x77, 0x04, 0xE9, 0x4B, 0xE7, 0xF3, 0xE8, 0x5F, 0x7F, 0xE8, 0x49, 0x6F, 0xD5, 0xAA, 0xB9, 0x67, 0xB2, 0x7C, 0x3F, 0x17, 0x3E, 0x26, 0x26, 0x80, 0xD0, 0x44, 0x08, 0x85, 0xE6, 0xC0, 0xB2, 0xAA, 0xB0, 0x9A, 0xB8, 0x1F, 0x6D, 0xE5, 0xB2, 0x2D, 0x17, 0xD5, 0xA2, 0x11, 0x97, 0xD6, 0x98, 0x93, 0xBE, 0xED, 0x51, 0x83, 0x4E, 0x2D, 0x7E, 0x3D, 0xAF, 0xF0, 0x4C, 0xF8, 0x4A, 0xA9, 0xC7, 0x79, 0x6E, 0xBB, 0x6A, 0xE2, 0x06, 0xC4, 0xE1, 0x66, 0x25, 0xFD, 0xFD, 0x61, 0x39, 0x85, 0x05, 0x48, 0x06, 0x26, 0x7C, 0xD6, 0x9B, 0xFA, 0x8F, 0x5D, 0xD6, 0x0F, 0x4F, 0x21, 0x94, 0x12, 0xDF, 0x2B, 0xAB, 0xC9, 0x56, 0x41, 0xAE, 0x15, 0x54, 0x87, 0xFA, 0xF4, 0x13, 0x33, 0xF5, 0xE5, 0x1B, 0xEF, 0xC2, 0xF9, 0x63, 0xE6, 0x2B, 0x74, 0x8B, 0x3D, 0x9C, 0x20, 0x20, 0x66, 0xD1, 0xEC, 0xBA, 0xB6, 0x03, 0x21, 0x79, 0x10, 0x58, 0x9B, 0xB9, 0x69, 0x55, 0x21, 0xA5, 0xC5, 0x2F, 0x12, 0x38, 0x2F, 0x0D, 0xE3, 0x24, 0x3F, 0x9E, 0x92, 0xED, 0x60, 0x53, 0x12, 0x63, 0x7D, 0xCC, 0xE5, 0xAD, 0x80, 0x7D, 0xA0, 0xC9, 0x2E, 0x99, 0x32, 0x52, 0x05, 0x20, 0x41, 0xC7, 0xB6, 0x8F, 0x4E, 0xB1, 0xBB, 0xB7, 0x08, 0x5A, 0x5B, 0x02, 0x04, 0x77, 0x98, 0x92, 0x30, 0xCB, 0xA8, 0x9F, 0x96, 0x6D, 0x34, 0x97, 0xC4, 0x04, 0x3D, 0x05, 0x6F, 0x79, 0x7E, 0xA0, 0xB4, 0x8E, 0x24, 0x7C, 0xAB, 0xBC, 0x7E, 0x59, 0x73, 0x07, 0xDA, 0x60, 0x5A, 0x00, 0x81, 0x45, 0x45, 0x51, 0xC8, 0x96, 0xAB, 0x4E, 0xE1, 0x34, 0x6B, 0x90, 0x4E, 0x35, 0x8A, 0x58, 0xCA, 0x2F, 0x7B, 0x93, 0xDA, 0x32, 0x9D, 0x08, 0x0A, 0x49, 0xDC, 0xF9, 0xD2, 0xC9, 0xD1, 0xBB, 0xD6, 0xBA, 0x82, 0x6C, 0xA7, 0x13, 0x3A, 0xB2, 0xDF, 0x61, 0xD7, 0x13, 0x16, 0xEB, 0xDD, 0xED, 0x88, 0x2E, 0x49, 0x83, 0xB7, 0x67, 0x46, 0xF7, 0x14, 0x36, 0xD2, 0xD7, 0xC1, 0x4D, 0x94, 0x34, 0x71, 0x70, 0xEE, 0x00, 0x15, 0x54, 0x00, 0x28, 0x1B, 0xD3, 0xC6, 0xBF, 0xE5, 0xEC, 0xBF, 0x69, 0xDE, 0xA0, 0x59, 0x01, 0x63, 0xE3, 0xA2, 0x97, 0x10, 0xC4, 0x10, 0x7A, 0x08, 0xD4, 0xDD, 0x30, 0xFD, 0x6E, 0x05, 0x0E, 0xA1, 0xE9, 0xE3, 0xF3, 0xBA, 0xCD, 0x74, 0x10, 0x35, 0xE3, 0x47, 0x18, 0xAF, 0xA9, 0xA9, 0xC8, 0xAB, 0x19, 0xEA, 0x9C, 0xD8, 0x75, 0x11, 0xCC, 0x59, 0xCC, 0x60, 0x1B, 0xC6, 0x3B, 0x82, 0x0F, 0xD0, 0x96, 0x87, 0x1F, 0x95, 0x26, 0x34, 0xA2, 0xA3, 0x78, 0x87, 0x83, 0xAA, 0xE7, 0x6D, 0xA2, 0x05, 0xB1, 0xEB, 0x5E, 0x94, 0x42, 0x16, 0x19, 0xFF, 0x47, 0x52, 0x5F, 0x05, 0x62, 0xE4, 0xA3, 0x63, 0x3A, 0xC7, 0xC4, 0x01, 0x7D, 0xA2, 0xC8, 0x13, 0x07, 0xBD, 0xBD, 0x74, 0xB2, 0xD9, 0x16, 0x1E, 0x99, 0xC1, 0x68, 0x6A, 0x9A, 0xB1, 0xC9, 0x44, 0x1B, 0x0D, 0x35, 0xC1, 0xCE, 0x7E, 0x9A, 0x62, 0x88, 0x28, 0x92, 0x85, 0x02, 0x33, 0x20, 0x88, 0x9B, 0x63, 0x9E, 0xB9, 0xCD, 0x0A, 0x56, 0x92, 0x93, 0xE3, 0x67, 0xC2, 0xBD, 0x1F, 0xEA, 0x68, 0x7F, 0x45, 0x1B, 0x3D, 0xA8, 0x80, 0x9A, 0x77, 0xCA, 0x31, 0x9D, 0xFC, 0xFF, 0xBA, 0xD4, 0x27, 0x24, 0xF2, 0xE0, 0x67, 0xCB, 0x3A, 0x85, 0xE7, 0x23, 0xCD, 0xD0, 0xEF, 0xC6, 0xB4, 0xC9, 0x7B, 0x5A, 0x13, 0x6B, 0xBE, 0xFC, 0xB6, 0xF1, 0x34, 0x59, 0x2C, 0xED, 0xDD, 0x6A, 0xFC, 0x98, 0x30, 0x36, 0x5D, 0x75, 0xF7, 0x5A, 0x27, 0xCA, 0xC7, 0x22, 0x56, 0x07, 0x8E, 0xD0, 0x20, 0xA4, 0x49, 0x30, 0xDE, 0x9C, 0x35, 0xCE, 0x96, 0xE1, 0x54, 0x4E, 0xE9, 0x85, 0x1B, 0xE6, 0x78, 0x48, 0x2A, 0x32, 0x7C, 0xFA, 0x37, 0xA9, 0x13, 0xE0, 0x45, 0xC8, 0xC2, 0x63, 0xD9, 0xB2, 0x5E, 0xAE, 0x21, 0xA2, 0x66, 0x4A, 0xF9, 0x43, 0x03, 0x95, 0x16, 0x3F, 0x04, 0x56, 0xD1, 0xA5, 0x18, 0xF6, 0x09, 0x7C, 0x96, 0xDB, 0x8F, 0x50, 0x5F, 0x34, 0x40, 0xA6, 0xC8, 0xCC, 0x31, 0xB5, 0x95, 0xAC, 0xFE, 0x9A, 0xA9, 0xCC, 0x1C, 0xCF, 0xF9, 0xFD, 0xA6, 0x56, 0xBC, 0xDB, 0x5E, 0xEB, 0x57, 0xF4, 0x1E, 0x94, 0x67, 0xC6, 0x43, 0xBA, 0x62, 0x79, 0xE5, 0x41, 0xE8, 0x6C, 0x91, 0x07, 0x4E, 0x55, 0xC6, 0x3A, 0xDF, 0x41, 0x51, 0x7C, 0xEA, 0x5A, 0x6F, 0x62, 0x29, 0xF7, 0x10, 0x16, 0x62, 0xBB, 0x0A, 0xA0, 0xCE, 0xAB, 0x2B, 0x7F, 0x62, 0x11, 0x96, 0xC7, 0xA7, 0x7B, 0xB3, 0x27, 0xC7, 0x68, 0xC4, 0x3D, 0x06, 0x9D, 0x71, 0xC3, 0x2C, 0x71, 0x2C, 0x83, 0x1D, 0x68, 0x50, 0xE6, 0xEB, 0x79, 0x3D, 0x7D, 0xEB, 0x08, 0xDE, 0x7A, 0x70, 0x4B, 0x38, 0x6D, 0xFD, 0x2B, 0x30, 0x72, 0xC2, 0x6B, 0x89, 0xDF, 0x8D, 0x07, 0x2B, 0x3E, 0x9F, 0x56, 0x96, 0xA0, 0x73, 0x2E, 0x21, 0x5D, 0xF6, 0xDE, 0x47, 0x5D, 0x3A, 0x69, 0xF1, 0x11, 0x2F, 0x8B, 0x6B, 0x8E, 0xE7, 0x6B, 0x73, 0x9C, 0x92, 0x76, 0xD9, 0xEE, 0x78, 0x17, 0xD9, 0x89, 0xAA, 0x07, 0x90, 0xD4, 0x6F, 0x8B, 0xE9, 0xBC, 0xF8, 0xA9, 0xDE, 0x83, 0xD3, 0xF3, 0xC3, 0x02, 0xA8, 0xAA, 0xBE, 0xE5, 0xC8, 0xFE, 0xBC, 0x2A, 0xDC, 0x70, 0x6F, 0xC0, 0xEA, 0x55, 0xCD, 0x6F, 0x38, 0x37, 0x74, 0xF9, 0x55, 0xFE, 0xC7, 0x0A, 0x5F, 0x83, 0x80, 0x74, 0xDC, 0xB7, 0x31, 0x53, 0x2C, 0x94, 0x9C, 0x88, 0x84, 0xE9, 0x5F, 0xDE, 0xCE, 0x3A, 0x7D, 0x9F, 0x7E, 0xA2, 0x1A, 0xC5, 0xA8, 0xAC, 0xDF, 0xAA, 0x89, 0x68, 0x1E, 0x95, 0x01, 0x4D, 0x5A, 0x23, 0x44, 0x31, 0x5B, 0xF8, 0xB3, 0xFF, 0x97, 0x12, 0xA0, 0x9A, 0x8F, 0xDE, 0xB8, 0x29, 0x4C, 0x25, 0x7D, 0x16, 0xCC, 0xEF, 0xAA, 0x78, 0xDD, 0x0F, 0x5D, 0xFF, 0xE0, 0x49, 0xCE, 0x2B, 0x8A, 0xC7, 0xE1, 0x60, 0x02, 0xED, 0x1E, 0x32, 0x8C, 0x62, 0x86, 0xA1, 0x67, 0x4A, 0x5C, 0x06, 0xF6, 0x28, 0x37, 0xAA, 0xF3, 0xEE, 0xFF, 0xFC, 0x11, 0x46, 0x94, 0x7A, 0x63, 0x0D, 0x82, 0x44, 0xAA, 0x72, 0x89, 0x8D, 0xFE, 0x5B, 0x94, 0x78, 0x63, 0x70, 0x64, 0x8A, 0x13, 0xF0, 0xE1, 0x6D, 0x50, 0x27, 0x77, 0xEB, 0x8D, 0xF9, 0x62, 0xFC, 0x86, 0x3C, 0x77, 0xC1, 0x59, 0xBF, 0x64, 0xCC, 0x2A, 0x47, 0xCA, 0xF6, 0xB2, 0x12, 0xCB, 0xC6, 0x14, 0x2B, 0x5C, 0x9F, 0x5B, 0xFF, 0xE2, 0xDD, 0x3B, 0xB1, 0xF8, 0x63, 0x23, 0x10, 0x74, 0x82, 0x96, 0xBB, 0x81, 0xB3, 0x62, 0xB7, 0xE4, 0x56, 0xEE, 0xE8, 0xDF, 0x29, 0x55, 0xFC, 0xDC, 0x04, 0xE5, 0x5D, 0x25, 0x16, 0xA8, 0x28, 0x07, 0x12, 0xCA, 0x5B, 0x60, 0xEA, 0x90, 0x7D, 0x51, 0xB2, 0xFA, 0x72, 0xF9, 0xC7, 0x3D, 0xA7, 0xFE, 0x2C, 0x25, 0x98, 0x8F, 0x5B, 0xE1, 0xB8, 0x23, 0x68, 0x25, 0xC8, 0x3A, 0x02, 0x38, 0x22, 0x39, 0x40, 0x2A, 0x29, 0x4E, 0xA4, 0xBE, 0x31, 0xA1, 0x7D, 0xBD, 0x31, 0xBA, 0x1B, 0xFF, 0xF8, 0x04, 0xCC, 0x78, 0x2F, 0xED, 0x78, 0x95, 0x09, 0x7F, 0x58, 0x3D, 0xD1, 0x3A, 0xCC, 0x85, 0x49, 0x1B, 0xDD, 0x12, 0x3F, 0xE0, 0x2C, 0x14, 0x12, 0xE3, 0x42, 0x61, 0x7D, 0x9C, 0x26, 0xB8, 0xD9, 0x87, 0x7C, 0xAD, 0x5A, 0x72, 0xD2, 0x32, 0x80, 0xB5, 0x27, 0x61, 0x47, 0xA7, 0x25, 0x84, 0xDA, 0xE6, 0x17, 0x23, 0x15, 0x8B, 0x9A, 0x54, 0x79, 0xD6, 0x6B, 0x6D, 0x8A, 0x6C, 0x4D, 0xB0, 0xF2, 0xE7, 0x1E, 0xDD, 0x46, 0x58, 0x85, 0xC3, 0x3A, 0x69, 0xA8, 0xA7, 0x4E, 0x78, 0x16, 0x08, 0xF0, 0x64, 0x16, 0x86, 0x6D, 0x19, 0x6B, 0x69, 0x5E, 0x70, 0xA4, 0x3B, 0x7D, 0xEA, 0xBE, 0x8C, 0x00, 0x0D, 0x79, 0xEE, 0x16, 0x03, 0xD4, 0x7C, 0x45, 0xCC, 0xB8, 0x5B, 0xBF, 0x79, 0x2D, 0x59, 0x14, 0x6F, 0xA3, 0x22, 0x86, 0x97, 0x6F, 0xF5, 0x91, 0x72, 0x62, 0x96, 0x38, 0xE1, 0xA0, 0x70, 0xCB, 0x0F, 0x0E, 0xCB, 0xF8, 0x09, 0xF9, 0xF5, 0xB8, 0x73, 0xFB, 0xEF, 0x96, 0x87, 0x4F, 0xCD, 0xED, 0x58, 0xA2, 0xC0, 0xA4, 0x99, 0x06, 0xD9, 0x09, 0x1D, 0x29, 0xB2, 0x1D, 0x0A, 0x7B, 0x89, 0x94, 0x52, 0x5D, 0x08, 0x88, 0x74, 0x8F, 0xB7, 0xDE, 0xE1, 0x60, 0xF2, 0xFC, 0xC7, 0x89, 0x52, 0xBB, 0x57, 0xBE, 0x4D, 0x36, 0x68, 0x5B, 0xE4, 0xF2, 0xB1, 0x45, 0xBC, 0xAC, 0x40, 0xE0, 0xDB, 0x30, 0x60, 0x87, 0x2D, 0x81, 0x76, 0x63, 0x91, 0xD4, 0xEC, 0x0B, 0x04, 0x60, 0x9F, 0x4F, 0x2D, 0xA2, 0x28, 0x94, 0x15, 0x45, 0x8D, 0x5F, 0x15, 0x22, 0x3C, 0x8E, 0x91, 0x11, 0x88, 0xC7, 0x82, 0x5F, 0x52, 0xA0, 0xA3, 0xA2, 0xC2, 0xCA, 0x8B, 0x62, 0xA7, 0x4B, 0x03, 0x71, 0x59, 0xE5, 0x4D, 0x99, 0x73, 0xC8, 0x00, 0x54, 0x3D, 0x2F, 0x6C, 0x4C, 0x0D, 0x9E, 0x3B, 0x09, 0x39, 0xC1, 0xC1, 0x68, 0x05, 0xE5, 0x79, 0x46, 0x95, 0x49, 0x9C, 0xE0, 0x13, 0xCF, 0xB9, 0xB0, 0xEA, 0xEE, 0xD8, 0xDD, }, .pkcs8_len = 0, .spki_len = 0, .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 = 4668, .sig = { 0x37, 0xBD, 0x0C, 0xCB, 0xC5, 0x4E, 0x5A, 0x48, 0x0F, 0x2F, 0xBB, 0x8E, 0xF3, 0x87, 0x9E, 0x83, 0x40, 0xD7, 0xF6, 0xC7, 0x42, 0x42, 0xAD, 0x44, 0xD3, 0xE8, 0xB0, 0x78, 0x3C, 0xC5, 0xBF, 0x21, 0x36, 0xD7, 0xBD, 0x4A, 0x32, 0xA9, 0x55, 0x2F, 0xE0, 0xE8, 0xAF, 0x8E, 0x87, 0xD5, 0x41, 0x1D, 0x76, 0x8A, 0x69, 0x2F, 0xE2, 0xC5, 0x03, 0xA7, 0x0C, 0xCB, 0xC0, 0x3A, 0x34, 0xB3, 0xC1, 0xF0, 0x81, 0x5B, 0x26, 0x4B, 0x57, 0x2A, 0x9E, 0x74, 0x60, 0x9B, 0x9A, 0xD7, 0x29, 0x3B, 0xE3, 0x72, 0x7B, 0xFE, 0x17, 0x58, 0x3B, 0x3B, 0x63, 0x4F, 0x0A, 0x11, 0x9D, 0x79, 0x3E, 0xB1, 0x4D, 0xFF, 0x18, 0x64, 0x3D, 0x1C, 0x34, 0x6B, 0x65, 0xE5, 0x73, 0xEF, 0xB9, 0xD5, 0x3B, 0xFA, 0x4C, 0x20, 0x05, 0x5D, 0x55, 0xF7, 0x54, 0xAF, 0x2F, 0x73, 0xFC, 0x38, 0x62, 0x67, 0xD5, 0x89, 0x0B, 0x39, 0x13, 0x01, 0x41, 0x55, 0x93, 0xB2, 0xC5, 0x69, 0x5B, 0x9C, 0x06, 0xF0, 0x01, 0xF8, 0x84, 0x5C, 0x7C, 0xFA, 0xD7, 0x7C, 0x04, 0xE4, 0x11, 0x65, 0x18, 0xDF, 0x80, 0xF0, 0x41, 0xA5, 0x8A, 0x85, 0x74, 0x48, 0xE7, 0x68, 0xA7, 0x1A, 0x7A, 0x01, 0xF2, 0x43, 0x31, 0x70, 0xB3, 0x71, 0xE8, 0xE3, 0x01, 0xA5, 0x37, 0x87, 0xD5, 0xEC, 0x77, 0x05, 0xA5, 0xEE, 0x1F, 0xE4, 0xFC, 0x04, 0x91, 0xCD, 0xC6, 0xC8, 0x76, 0x96, 0x8A, 0x60, 0x6E, 0xC1, 0x38, 0x6F, 0x45, 0x1C, 0xE8, 0x54, 0x77, 0x34, 0x8D, 0xE1, 0xC6, 0x8E, 0xCC, 0x33, 0x95, 0x41, 0x61, 0x24, 0x90, 0xB2, 0x4C, 0x24, 0x2D, 0x25, 0x87, 0x39, 0x81, 0xF9, 0xDE, 0xA6, 0x6D, 0x13, 0xF3, 0xC2, 0x10, 0x93, 0xEA, 0x48, 0x11, 0x51, 0xD1, 0x76, 0xA5, 0x50, 0x08, 0x42, 0x55, 0x0C, 0x26, 0xD0, 0xAF, 0xB1, 0xC6, 0xAE, 0xBE, 0x8E, 0x42, 0x67, 0xE3, 0x6F, 0xD5, 0x70, 0x1E, 0x45, 0xD1, 0xDF, 0x15, 0x95, 0x9C, 0x7D, 0xC4, 0x4E, 0x7F, 0x5B, 0x6B, 0xA8, 0xCA, 0x04, 0xED, 0xF1, 0xE3, 0xE6, 0x48, 0x69, 0xFA, 0x15, 0x3B, 0xA7, 0x46, 0x7F, 0x0D, 0x7B, 0x2F, 0xDC, 0x91, 0x24, 0x3A, 0x22, 0x39, 0x06, 0xF1, 0xAE, 0xA0, 0xD9, 0xFC, 0x14, 0x0F, 0x70, 0xCD, 0x02, 0x5A, 0x31, 0xB4, 0x0F, 0x22, 0xC4, 0x71, 0xBD, 0xD2, 0x36, 0x5E, 0xD6, 0x30, 0x2D, 0x14, 0x81, 0x31, 0x6E, 0xE3, 0xC4, 0xC1, 0x70, 0xA1, 0x62, 0xEF, 0xE9, 0xFF, 0x41, 0x85, 0xE4, 0x50, 0x08, 0xF0, 0x7F, 0x6B, 0xDB, 0xAC, 0x22, 0x1D, 0xEC, 0x0B, 0xF0, 0xAF, 0x88, 0x4B, 0x16, 0xC9, 0x5F, 0x34, 0x35, 0x01, 0xAA, 0x09, 0x8A, 0xD4, 0xA1, 0xF8, 0x20, 0x68, 0xFA, 0x1F, 0xBF, 0xF0, 0xE0, 0x40, 0x94, 0x6D, 0xCD, 0x50, 0xBF, 0x00, 0x9D, 0xF1, 0xFC, 0xA4, 0xA3, 0xAA, 0xDB, 0x1C, 0x29, 0x51, 0xC0, 0x86, 0xD2, 0x7F, 0x20, 0x02, 0xDF, 0xD8, 0x54, 0xE5, 0x98, 0x52, 0xF4, 0x15, 0x30, 0x90, 0xDD, 0xC1, 0xA2, 0x1A, 0x6E, 0x0B, 0xE5, 0x92, 0x18, 0x7A, 0x68, 0xAE, 0x08, 0x5B, 0x1D, 0x5D, 0x98, 0xBE, 0x8F, 0xCE, 0x5E, 0x24, 0x03, 0x1F, 0x47, 0xF8, 0x34, 0x30, 0x6B, 0xE5, 0xA5, 0xB6, 0x80, 0xAC, 0xFC, 0xD9, 0xF4, 0x04, 0xC1, 0xDE, 0x85, 0x79, 0x66, 0xD2, 0x54, 0x6E, 0x66, 0x94, 0x01, 0x5F, 0x05, 0x02, 0xD0, 0xE6, 0x56, 0x8C, 0x9A, 0xA1, 0xB1, 0x3B, 0x3D, 0x7B, 0x61, 0xEE, 0x6A, 0x3D, 0xA0, 0x16, 0xDD, 0x34, 0xD6, 0x44, 0xB1, 0x29, 0x7E, 0x63, 0x8D, 0xF0, 0xFC, 0xB6, 0xF6, 0x85, 0x57, 0x7E, 0x16, 0x4F, 0x5D, 0x6A, 0xA6, 0xF0, 0x70, 0xC1, 0xD0, 0x21, 0x55, 0x8C, 0xBC, 0xFD, 0x6F, 0x9B, 0xA3, 0x75, 0xE2, 0x89, 0x1F, 0x67, 0x26, 0xCC, 0xE4, 0xCE, 0xBC, 0x89, 0xA9, 0x63, 0x57, 0x93, 0x0D, 0x04, 0x4C, 0x16, 0xAB, 0x29, 0x45, 0x30, 0x2C, 0xE0, 0xF2, 0xB6, 0x46, 0x17, 0x04, 0x6C, 0x3C, 0x1C, 0x4A, 0x6B, 0x34, 0xD5, 0xAA, 0x07, 0x4E, 0x5F, 0xCB, 0x10, 0xBB, 0xA4, 0xC2, 0xA6, 0x08, 0x26, 0x5F, 0x45, 0xD7, 0x45, 0x10, 0x75, 0x0E, 0xAC, 0x67, 0x3A, 0x82, 0x8D, 0x5D, 0x30, 0x8F, 0x34, 0x07, 0x92, 0x31, 0x33, 0xD5, 0x50, 0xB2, 0x57, 0x85, 0xA8, 0x39, 0x02, 0x42, 0xDC, 0x27, 0xB0, 0x82, 0xD3, 0x87, 0xAB, 0xCC, 0xDA, 0x7C, 0xD4, 0xD6, 0xEE, 0x5E, 0xAB, 0x8D, 0x51, 0xC8, 0x76, 0x9C, 0x24, 0x3A, 0x95, 0x88, 0xF0, 0x45, 0xCC, 0xD9, 0xA5, 0x17, 0x2D, 0x99, 0xD0, 0x4E, 0xE4, 0x39, 0x59, 0xDC, 0x4D, 0x95, 0xBE, 0xAC, 0x06, 0x14, 0xA2, 0xF8, 0x50, 0x97, 0xED, 0x1C, 0x47, 0x61, 0x38, 0x42, 0x9D, 0x12, 0xC7, 0x75, 0x8F, 0xA5, 0x28, 0x75, 0xC7, 0x38, 0xD4, 0x6E, 0xF2, 0xD9, 0x67, 0x51, 0x90, 0xFB, 0x72, 0x65, 0xF9, 0xAA, 0xC8, 0xC6, 0xF1, 0x73, 0xE8, 0xD5, 0x5C, 0x6B, 0x33, 0x81, 0x9F, 0xBF, 0x9B, 0x5B, 0xD3, 0x12, 0x4D, 0x30, 0xC5, 0x81, 0x3E, 0x44, 0x7F, 0xAE, 0x23, 0xFC, 0xA5, 0xDB, 0x43, 0x8E, 0xC5, 0xCC, 0x8A, 0x66, 0xDE, 0xEB, 0xEB, 0x39, 0x53, 0x49, 0x29, 0xCE, 0x4C, 0xE0, 0xB9, 0x8F, 0x1C, 0xA0, 0xE2, 0xC7, 0xD4, 0x53, 0x81, 0xC8, 0xF2, 0xE2, 0xFD, 0x2F, 0xED, 0x40, 0x6B, 0x29, 0xCC, 0x6A, 0x09, 0xD8, 0x1B, 0x44, 0xA4, 0x4F, 0x16, 0xC1, 0x50, 0xD8, 0x65, 0xE8, 0xEA, 0x60, 0x60, 0xA8, 0x58, 0x39, 0x7C, 0x07, 0xF8, 0x57, 0x3A, 0x9C, 0xA2, 0x93, 0x00, 0x7D, 0x1B, 0xE4, 0xDD, 0xD8, 0xA5, 0x37, 0xDD, 0x9A, 0x57, 0x7F, 0x5E, 0x42, 0xF3, 0xEC, 0xB4, 0x8F, 0x75, 0x81, 0x51, 0xA4, 0x01, 0xCA, 0xF2, 0x26, 0xA4, 0x8D, 0x94, 0x81, 0x9D, 0x2A, 0x43, 0xED, 0x08, 0xCD, 0xB6, 0xAE, 0xDD, 0x64, 0x01, 0x14, 0x03, 0x22, 0x31, 0x3B, 0xFD, 0xE2, 0x76, 0x05, 0x71, 0x7E, 0x35, 0x66, 0xDD, 0x31, 0xBB, 0x5C, 0x52, 0x71, 0x45, 0x90, 0x45, 0x93, 0xA4, 0x74, 0x41, 0xD2, 0xF3, 0xC7, 0x44, 0x2C, 0x63, 0x69, 0x5D, 0xD0, 0xC3, 0x60, 0xBD, 0xA9, 0x95, 0xFB, 0xFE, 0xC3, 0xE6, 0xC6, 0x63, 0xD1, 0xD2, 0x2D, 0x89, 0x0D, 0x7D, 0xF7, 0x05, 0x98, 0xF1, 0xBB, 0xC6, 0x19, 0x2A, 0x4F, 0x3A, 0x0A, 0x45, 0x8A, 0x95, 0x44, 0xCA, 0xDD, 0x6F, 0x18, 0xDF, 0xA9, 0xEE, 0xA6, 0xE3, 0x20, 0x6B, 0xDE, 0x60, 0xED, 0x1C, 0x57, 0xCC, 0xC8, 0x00, 0x5F, 0x7C, 0x7C, 0x82, 0x74, 0xC1, 0x40, 0x7C, 0x8F, 0xAF, 0x4E, 0xBD, 0x69, 0xD5, 0x76, 0x19, 0x79, 0xF9, 0x07, 0xCF, 0xD0, 0x62, 0x4E, 0xC7, 0xBA, 0x1F, 0xD7, 0xB5, 0x67, 0x81, 0xAC, 0x71, 0xA4, 0xA5, 0x26, 0x84, 0xFF, 0xC3, 0x2D, 0x5B, 0x53, 0x3C, 0xB5, 0x6C, 0x07, 0xF6, 0x35, 0xF5, 0x79, 0x69, 0xC8, 0xF1, 0x58, 0x8D, 0x34, 0xD0, 0xE7, 0xA1, 0xC7, 0xA9, 0x42, 0xAA, 0xA3, 0xF3, 0x56, 0x0B, 0x0D, 0xB4, 0xF8, 0xCE, 0xBC, 0xAF, 0x6F, 0x25, 0x24, 0x11, 0x4A, 0x5F, 0x6A, 0xF7, 0x1B, 0x5F, 0x50, 0xE9, 0x42, 0xE6, 0x74, 0xA8, 0x77, 0xC1, 0x74, 0xD9, 0x22, 0x00, 0x86, 0x5A, 0x5A, 0x06, 0xFB, 0x2D, 0x7F, 0xB4, 0x74, 0x41, 0x46, 0x75, 0xED, 0x31, 0x72, 0xF5, 0xF1, 0x53, 0x8F, 0x58, 0x1E, 0xDE, 0x5E, 0xDD, 0x74, 0x5B, 0x55, 0xF9, 0xA2, 0xFC, 0x49, 0x95, 0xEB, 0x98, 0x4B, 0x8A, 0x12, 0xD6, 0xF6, 0x5A, 0xAE, 0xDF, 0x8D, 0x8D, 0x6F, 0xF5, 0x3C, 0xE2, 0x38, 0xC3, 0xA6, 0x6C, 0xF2, 0x34, 0xF5, 0x94, 0x36, 0x47, 0x1C, 0x9F, 0xCB, 0xD3, 0x8E, 0x7F, 0x26, 0xBD, 0xF9, 0x74, 0x1B, 0x59, 0x9E, 0x16, 0xB8, 0xF7, 0xED, 0x46, 0x44, 0xBB, 0x6A, 0xBE, 0x81, 0xBB, 0x94, 0x0C, 0x24, 0xFA, 0x62, 0x0F, 0x44, 0x35, 0x84, 0xF9, 0x9B, 0xB9, 0xDC, 0x25, 0x71, 0xB5, 0xEB, 0x81, 0x19, 0x27, 0x52, 0x9C, 0x7A, 0xDC, 0xEB, 0xEE, 0xF7, 0xAF, 0x05, 0xBA, 0x7E, 0x88, 0x89, 0x9F, 0xAB, 0xF8, 0x74, 0x0F, 0xCD, 0xD1, 0x27, 0x5B, 0x12, 0xF7, 0x2A, 0x75, 0xC6, 0xD0, 0x00, 0x56, 0x5C, 0x5A, 0xC8, 0x8F, 0xB1, 0xFD, 0x99, 0x5B, 0x84, 0xED, 0x38, 0x4D, 0x5D, 0x6A, 0x60, 0x29, 0x37, 0x37, 0xD7, 0x2C, 0xC1, 0x09, 0x44, 0x36, 0x39, 0x71, 0xDA, 0x44, 0xD5, 0xEA, 0xE9, 0xE8, 0xB1, 0xE8, 0x0D, 0x75, 0x76, 0xC5, 0x0A, 0xAF, 0xF6, 0x7E, 0x42, 0x31, 0x96, 0xF3, 0x78, 0x57, 0xD1, 0xD2, 0x35, 0xAB, 0x28, 0x39, 0xAE, 0x37, 0x79, 0xF9, 0xF2, 0xF9, 0xB7, 0x59, 0xFC, 0x52, 0xDA, 0xAE, 0xB8, 0x63, 0x7B, 0x8F, 0x4F, 0xC9, 0x0B, 0xD9, 0x4A, 0xDB, 0x6F, 0x57, 0x72, 0x20, 0x82, 0xE9, 0x43, 0xD7, 0xCE, 0x3E, 0x73, 0x50, 0x1D, 0x8C, 0x93, 0xB5, 0x21, 0x2D, 0xEC, 0xE4, 0x95, 0x35, 0x53, 0x6E, 0xFC, 0xEA, 0xB8, 0xB8, 0x5E, 0xB2, 0xAA, 0x94, 0xCB, 0xE7, 0x7B, 0xAA, 0xDF, 0x46, 0x58, 0x92, 0x01, 0xA3, 0xA8, 0xAC, 0xA4, 0x83, 0x9E, 0x51, 0x9B, 0x6F, 0xD0, 0xCC, 0x52, 0xEA, 0x58, 0xA8, 0xAC, 0x08, 0xDC, 0x15, 0xEE, 0xF4, 0x8E, 0xDB, 0x89, 0xA1, 0xFC, 0x46, 0xE7, 0x13, 0x53, 0xFE, 0x73, 0xF6, 0x8E, 0x0F, 0x48, 0x55, 0xB7, 0xFF, 0x73, 0x27, 0xAE, 0x4B, 0xCB, 0xA0, 0x9D, 0xE0, 0x33, 0x53, 0xD4, 0x1E, 0xDE, 0x26, 0x78, 0x5A, 0x94, 0x49, 0x6A, 0xCB, 0x4E, 0x74, 0x3B, 0xA0, 0x65, 0xD1, 0x79, 0x3F, 0xBE, 0x5B, 0x29, 0x3A, 0x77, 0x1C, 0xCB, 0x8B, 0x8D, 0x8B, 0xD2, 0x76, 0x77, 0xD5, 0xFF, 0xF7, 0x43, 0xF9, 0x49, 0x77, 0x21, 0x9D, 0x55, 0x57, 0x35, 0xE5, 0xD0, 0xAC, 0xE1, 0x18, 0xC2, 0x57, 0x1F, 0xC6, 0x96, 0xAF, 0x1F, 0xB0, 0xA1, 0x97, 0x6A, 0x37, 0x85, 0xB0, 0x89, 0x61, 0x11, 0x7F, 0x19, 0x98, 0xB7, 0xE6, 0x1C, 0xF8, 0x14, 0xFE, 0x91, 0xA8, 0xB8, 0x1D, 0x62, 0xE4, 0x8D, 0x93, 0xB0, 0x28, 0x0D, 0xBA, 0xBF, 0x18, 0xE1, 0x12, 0x12, 0x43, 0xBF, 0xF3, 0x7B, 0x5A, 0xF7, 0x1E, 0x29, 0xA3, 0x1B, 0x48, 0x4A, 0xDA, 0x4F, 0x1F, 0xBC, 0x88, 0x30, 0x11, 0x27, 0x76, 0x60, 0xAE, 0xB4, 0x71, 0xB3, 0x09, 0xFA, 0x00, 0x32, 0x23, 0x5B, 0x3B, 0x2E, 0x2B, 0x2C, 0xAF, 0xCC, 0xC5, 0x44, 0x61, 0xB0, 0xB4, 0x5A, 0xE1, 0x5D, 0x92, 0xAD, 0x61, 0xB6, 0x4C, 0x5F, 0x37, 0x4A, 0x23, 0x74, 0x44, 0xF9, 0x63, 0x1D, 0xE4, 0x3C, 0x0B, 0x67, 0x8D, 0x03, 0xB6, 0x4E, 0xA3, 0xF9, 0x9B, 0xBB, 0xD1, 0x79, 0x61, 0x15, 0x39, 0xFC, 0x91, 0x69, 0x3B, 0x81, 0xE6, 0xA2, 0xF2, 0xFC, 0x81, 0x70, 0xE8, 0xBF, 0xD6, 0xD5, 0xB7, 0x8A, 0x5C, 0xD6, 0x44, 0x88, 0x1A, 0x67, 0xFD, 0x28, 0xAC, 0xDA, 0x74, 0x70, 0x58, 0x47, 0x27, 0x6C, 0x16, 0xBD, 0xF0, 0x9E, 0xBE, 0xBB, 0x21, 0x8C, 0xC6, 0x89, 0xB4, 0x50, 0x85, 0x43, 0xC3, 0x9E, 0xA6, 0x56, 0x44, 0xA7, 0xF3, 0x3D, 0xF4, 0x7D, 0x32, 0x72, 0xA3, 0x7C, 0xA8, 0x30, 0x76, 0x7B, 0x23, 0xF5, 0x52, 0xA1, 0xB3, 0x89, 0xF1, 0x4B, 0xE8, 0x71, 0xFF, 0x72, 0x59, 0xFB, 0x3A, 0x32, 0x93, 0x0F, 0x56, 0xDD, 0x42, 0x71, 0xF0, 0x21, 0xAA, 0xAC, 0xD7, 0xA2, 0xAC, 0x82, 0x03, 0xCF, 0x69, 0xE9, 0x64, 0x30, 0xA1, 0x6A, 0x2F, 0x96, 0xC1, 0x1F, 0xD2, 0xCD, 0x44, 0xE0, 0x86, 0xE1, 0x16, 0x8A, 0x8C, 0x1A, 0x63, 0x7E, 0x23, 0x21, 0xF6, 0x0C, 0xA5, 0x93, 0x0C, 0x02, 0xF9, 0x2D, 0xFF, 0x2D, 0x30, 0xAB, 0x10, 0x5A, 0xF8, 0x46, 0xB1, 0x6A, 0x90, 0xE2, 0xA7, 0x4D, 0xBC, 0x97, 0xDA, 0x40, 0xA1, 0x3F, 0x40, 0x5B, 0x71, 0x04, 0xBF, 0x2F, 0x22, 0xFC, 0xA4, 0x2E, 0x3A, 0x50, 0x0A, 0x72, 0x7A, 0xE1, 0xEA, 0x24, 0x01, 0x21, 0x60, 0x16, 0xFE, 0x8B, 0xF0, 0xDD, 0xBA, 0xE6, 0x8E, 0xD8, 0x74, 0x17, 0xFA, 0x76, 0x0D, 0xBA, 0x07, 0xD8, 0x4C, 0x26, 0x9C, 0xF4, 0x2B, 0xBE, 0xB3, 0x7D, 0x5B, 0x90, 0xEB, 0x23, 0x69, 0x76, 0xB8, 0x6F, 0x4D, 0x8F, 0x35, 0xE7, 0x82, 0x83, 0x7E, 0x32, 0xA1, 0x95, 0xF9, 0xCF, 0xD6, 0xC6, 0x73, 0x53, 0x6A, 0xA0, 0x43, 0x5B, 0x38, 0x0C, 0x02, 0xD1, 0xB7, 0xB0, 0xDE, 0x3C, 0x47, 0x9F, 0xE6, 0xB5, 0xFE, 0x6C, 0xF9, 0x7C, 0x3B, 0xD7, 0x46, 0x10, 0xCF, 0x15, 0x06, 0xE5, 0x99, 0x86, 0xF3, 0x81, 0x46, 0xB9, 0xA8, 0x96, 0x3C, 0xAE, 0x08, 0x00, 0x30, 0x75, 0xFF, 0x60, 0x7D, 0x47, 0x0E, 0x87, 0xA7, 0x2E, 0x8F, 0xFB, 0xC7, 0xE1, 0x38, 0x38, 0xDA, 0x93, 0xDC, 0x3A, 0x4B, 0x3E, 0x52, 0x34, 0x75, 0xCD, 0xC4, 0xE4, 0x8C, 0x2A, 0x54, 0x5F, 0x30, 0xE5, 0x89, 0x24, 0x7C, 0x64, 0x62, 0x2F, 0xA1, 0x05, 0x59, 0xB7, 0x24, 0xBB, 0x5F, 0xE8, 0x73, 0xED, 0xDF, 0x78, 0x38, 0xE1, 0x83, 0x2A, 0xD2, 0x17, 0xD4, 0xE8, 0x0B, 0x58, 0xB9, 0xFB, 0x39, 0xB6, 0x6C, 0xBE, 0x9F, 0x26, 0x48, 0x09, 0xEE, 0xD5, 0x94, 0x23, 0xF0, 0xA3, 0xCD, 0x3F, 0x00, 0xAD, 0xFC, 0x47, 0x42, 0xCE, 0x1B, 0x3C, 0xB6, 0x5B, 0x2B, 0xD2, 0xE3, 0x10, 0x59, 0x50, 0x9A, 0xFC, 0x7E, 0x48, 0x36, 0xDF, 0x0A, 0xE6, 0xF9, 0xD5, 0xC0, 0x63, 0x30, 0x95, 0x3F, 0xA2, 0xBB, 0x6F, 0xD0, 0x18, 0x7A, 0x6C, 0xAB, 0x88, 0x14, 0xEE, 0x12, 0xD1, 0x4E, 0xBC, 0x6D, 0xEF, 0xFC, 0x23, 0xE1, 0xC9, 0x01, 0x65, 0xE2, 0xE7, 0x78, 0x59, 0x45, 0xF1, 0x8B, 0xCC, 0x74, 0xD8, 0xB1, 0xC6, 0xAF, 0xA1, 0x5B, 0x32, 0x6C, 0x04, 0x7D, 0x94, 0x66, 0x8C, 0x03, 0x32, 0xD1, 0x47, 0xAF, 0x57, 0x52, 0x17, 0x64, 0x52, 0xC7, 0x12, 0x20, 0xB0, 0xA4, 0x32, 0xD4, 0x89, 0x9B, 0x6C, 0xEA, 0xA5, 0x87, 0x59, 0x9C, 0xAC, 0xF0, 0x04, 0xBA, 0x12, 0xA9, 0x0B, 0x26, 0x06, 0x21, 0x43, 0x06, 0xFA, 0x30, 0x0A, 0x4A, 0x13, 0xBF, 0x8F, 0x99, 0x4F, 0x46, 0xF5, 0xDF, 0x92, 0xE6, 0xD3, 0xBF, 0x47, 0x2C, 0xF7, 0x29, 0xFF, 0xF6, 0x66, 0xF2, 0x07, 0xEA, 0x71, 0xD5, 0x2C, 0xF6, 0xF2, 0xB1, 0x9C, 0x87, 0xCE, 0xAF, 0x08, 0xCD, 0x44, 0x5D, 0x18, 0x4F, 0x89, 0x81, 0xCA, 0x28, 0xCB, 0xFE, 0xA0, 0x03, 0x06, 0xAC, 0x76, 0x8B, 0x47, 0x15, 0x42, 0xF3, 0x27, 0x48, 0x76, 0x68, 0x4B, 0xCE, 0x7C, 0x17, 0xEB, 0xEC, 0x6C, 0xC6, 0xD7, 0xF9, 0x0E, 0xC1, 0x3D, 0xA9, 0x4C, 0xD7, 0xB4, 0xE9, 0x8E, 0x1C, 0xFA, 0xBA, 0x8F, 0x9C, 0xDD, 0xBF, 0x08, 0xCF, 0xD7, 0xDD, 0x5E, 0x3A, 0x73, 0x25, 0x66, 0x36, 0x65, 0x98, 0x0D, 0x3F, 0x55, 0x59, 0x22, 0x60, 0x8A, 0x05, 0xD9, 0xDC, 0x20, 0x76, 0x69, 0x29, 0x41, 0x30, 0x66, 0xB3, 0xB1, 0xAF, 0x98, 0x44, 0x31, 0x34, 0x5F, 0xD0, 0x12, 0x1D, 0x16, 0x42, 0xEA, 0xB5, 0x84, 0xF7, 0x47, 0x37, 0x3D, 0x08, 0xCE, 0x5B, 0x2E, 0x26, 0xE7, 0x6B, 0x51, 0xAB, 0x58, 0xE3, 0x9E, 0x6F, 0x9E, 0x6C, 0x4C, 0x33, 0xF1, 0x52, 0xE5, 0x03, 0x7F, 0x7F, 0x52, 0x76, 0x0A, 0x98, 0x36, 0x94, 0x1D, 0x43, 0xF4, 0x3C, 0x2E, 0x8C, 0x34, 0x6E, 0x40, 0x4A, 0xF3, 0x51, 0x80, 0x13, 0x3C, 0x2C, 0x8B, 0x44, 0x03, 0x86, 0x98, 0xFB, 0xE6, 0xE8, 0x44, 0xEB, 0xC9, 0x66, 0x57, 0xD5, 0xD3, 0x24, 0xCE, 0xB2, 0xCC, 0x38, 0xA4, 0xF2, 0xE3, 0xB0, 0x09, 0x38, 0x39, 0x3B, 0x05, 0x4E, 0x19, 0xA1, 0xAF, 0x2C, 0x7E, 0x2C, 0xBB, 0xC1, 0xC4, 0x52, 0xB6, 0x9D, 0x02, 0xA4, 0xBF, 0x04, 0xEB, 0x58, 0x42, 0xAA, 0x6A, 0x0A, 0xF8, 0xFB, 0x9D, 0x85, 0xD7, 0x98, 0x5B, 0x9B, 0xB2, 0x3D, 0x86, 0x06, 0x24, 0xB4, 0xE4, 0x04, 0x7E, 0x14, 0x26, 0xF7, 0x17, 0x76, 0x7E, 0x51, 0x5C, 0x3D, 0x99, 0xF4, 0xF3, 0xA1, 0x05, 0x66, 0x56, 0x23, 0x2A, 0x21, 0x1C, 0xC2, 0xC8, 0x07, 0xF1, 0xF9, 0xF9, 0x61, 0x1D, 0xC8, 0xAE, 0x50, 0x81, 0x94, 0xF7, 0xD6, 0x18, 0x2E, 0xE3, 0xAE, 0x96, 0x71, 0xB3, 0x45, 0xD0, 0x23, 0x18, 0x94, 0x78, 0x6E, 0x70, 0x72, 0x42, 0xF0, 0x68, 0x80, 0x69, 0x5A, 0x3F, 0xA6, 0x26, 0x89, 0x15, 0x74, 0xFA, 0xEE, 0xEE, 0x83, 0x39, 0xDE, 0xBE, 0x23, 0x0E, 0xE7, 0x6B, 0x82, 0xA9, 0xAE, 0x4F, 0x03, 0xD9, 0xCC, 0xA2, 0x8F, 0x3B, 0x9F, 0x2F, 0x06, 0xAC, 0x23, 0xE3, 0xD2, 0xCF, 0x76, 0xF0, 0x19, 0x50, 0x6F, 0xEC, 0x5C, 0x6E, 0x99, 0x07, 0x58, 0x7F, 0xB3, 0xBF, 0x4C, 0x2B, 0xE6, 0x58, 0xC5, 0x6E, 0xD6, 0x31, 0x88, 0x46, 0x56, 0xD6, 0xC2, 0x0E, 0xE1, 0x0B, 0x78, 0xD8, 0xF2, 0xD8, 0x01, 0x82, 0x30, 0xCD, 0xF9, 0x5E, 0xB8, 0x6E, 0x9C, 0xFD, 0xA2, 0xE1, 0x55, 0xBA, 0x33, 0x58, 0x12, 0xFC, 0x72, 0xEB, 0x88, 0x0B, 0xEA, 0x3A, 0x8C, 0x3A, 0x98, 0xCB, 0x56, 0x71, 0xE0, 0xE4, 0x03, 0x70, 0x4A, 0x55, 0x33, 0x62, 0x5B, 0x3E, 0xFA, 0x5C, 0xD3, 0x6C, 0x93, 0xDA, 0x37, 0x77, 0x21, 0xBF, 0x43, 0x82, 0xA0, 0xD0, 0x11, 0x77, 0xBC, 0xC5, 0xBC, 0xB4, 0xB7, 0x08, 0x23, 0x32, 0xE3, 0xE5, 0x85, 0x1B, 0x17, 0xF7, 0xB9, 0xD9, 0x10, 0xD2, 0x19, 0xEC, 0x5F, 0x98, 0xB9, 0xCE, 0x2E, 0xD2, 0x7F, 0x40, 0xB5, 0x72, 0x13, 0x8F, 0xE9, 0xA0, 0x3F, 0x15, 0x48, 0x65, 0x23, 0xB2, 0x9A, 0xA4, 0xC6, 0x07, 0x60, 0x17, 0xEF, 0xD2, 0x70, 0x70, 0x56, 0x0A, 0xC6, 0x13, 0xB3, 0x1D, 0x76, 0xB9, 0x60, 0x07, 0xEA, 0x98, 0xD7, 0xB0, 0x1D, 0x9A, 0x92, 0x54, 0x0C, 0x6A, 0x03, 0x0C, 0x4D, 0x0B, 0x98, 0x50, 0x8A, 0x14, 0x51, 0xE6, 0x48, 0x7F, 0x11, 0x2E, 0xF9, 0xE9, 0x05, 0xBA, 0x88, 0x92, 0x7A, 0xD6, 0x19, 0xEE, 0xEC, 0x6B, 0x58, 0xEE, 0xF0, 0x62, 0xE9, 0x1D, 0x35, 0x10, 0xB4, 0xED, 0xDA, 0xB2, 0xE5, 0xF9, 0x15, 0x46, 0x70, 0xEA, 0x8C, 0xF0, 0x00, 0x4C, 0xA4, 0xE2, 0xCC, 0xB5, 0xCE, 0x6C, 0x18, 0x70, 0xDA, 0x6B, 0xD8, 0xFD, 0xDC, 0x36, 0x41, 0x03, 0x91, 0x08, 0x82, 0x23, 0xF1, 0x53, 0xF6, 0x83, 0x97, 0x6B, 0xAB, 0x00, 0x87, 0xB2, 0xAF, 0x15, 0x7C, 0xA7, 0x89, 0x3E, 0x5C, 0x34, 0xF8, 0x38, 0xB2, 0x2A, 0xE6, 0x51, 0x4A, 0xB3, 0x81, 0xF4, 0x7A, 0x63, 0x3E, 0xC8, 0x9A, 0x2E, 0x1E, 0x51, 0x11, 0x18, 0x75, 0xB3, 0xAE, 0x9A, 0xEB, 0x66, 0x7D, 0xC8, 0x38, 0x6D, 0xB8, 0x1F, 0x13, 0xFF, 0x8D, 0xF7, 0x38, 0xB1, 0x02, 0x15, 0xDA, 0x52, 0x21, 0x01, 0xEF, 0xB8, 0xAD, 0xC9, 0xB1, 0x08, 0x75, 0xA4, 0x79, 0xB6, 0x47, 0x93, 0xB2, 0x4C, 0x67, 0x68, 0x41, 0xE3, 0x5C, 0x97, 0xA8, 0xE7, 0xEE, 0xBC, 0x6C, 0x51, 0x72, 0xCA, 0x88, 0x66, 0x1F, 0x2B, 0x62, 0x86, 0x46, 0x31, 0x2A, 0x68, 0x8C, 0xCC, 0x12, 0x43, 0x7D, 0x70, 0x39, 0x0C, 0x3E, 0x16, 0x21, 0x92, 0x0E, 0x65, 0x53, 0x98, 0xFF, 0x9A, 0x7E, 0x53, 0x74, 0xDF, 0xEC, 0xE4, 0x00, 0x19, 0x5B, 0x6A, 0x43, 0x1C, 0xDC, 0xC4, 0xB2, 0xF4, 0x4D, 0xAA, 0xC9, 0xBF, 0x91, 0x5E, 0x1B, 0x23, 0xA8, 0x5F, 0xED, 0x35, 0xE3, 0xC4, 0x3F, 0xCF, 0x02, 0x13, 0x04, 0x02, 0x10, 0x94, 0x83, 0x13, 0x48, 0x98, 0x37, 0x08, 0x0F, 0x1D, 0x80, 0x30, 0x27, 0xB0, 0x98, 0x95, 0x11, 0xD0, 0x63, 0x16, 0x7B, 0x36, 0x58, 0xD3, 0xF9, 0x8C, 0x0D, 0x2C, 0xA8, 0x79, 0x76, 0x53, 0x49, 0x28, 0x98, 0xC8, 0x14, 0x0E, 0x21, 0x86, 0x9C, 0x56, 0x3A, 0x5C, 0x03, 0xB7, 0x86, 0x07, 0x8F, 0x63, 0x4D, 0x75, 0xED, 0x2B, 0xDA, 0xD2, 0x74, 0x22, 0x51, 0xB6, 0x36, 0x48, 0x7D, 0x1A, 0xFF, 0xAB, 0xF3, 0x1E, 0x66, 0x46, 0x98, 0xC1, 0x77, 0x3F, 0x4E, 0x4D, 0xE9, 0xF2, 0xC3, 0xA4, 0xFE, 0xE7, 0x58, 0xEA, 0x07, 0x34, 0x89, 0x46, 0x99, 0x48, 0xBC, 0x9B, 0x50, 0xDB, 0x60, 0xD0, 0x5D, 0x9F, 0x18, 0x31, 0x41, 0x48, 0x94, 0xC2, 0x06, 0x19, 0x0E, 0xCD, 0xE8, 0xF2, 0x49, 0xBD, 0x43, 0x57, 0x7C, 0x8D, 0x40, 0xCA, 0x61, 0x1D, 0x23, 0xB6, 0xF7, 0x54, 0xCB, 0x06, 0xC6, 0x77, 0xC7, 0x1A, 0x77, 0x00, 0xCB, 0x8A, 0xF9, 0x30, 0xC5, 0xFF, 0xDB, 0x55, 0x4C, 0xA6, 0xAB, 0xE6, 0xD0, 0x83, 0xEE, 0x1A, 0x5A, 0xBF, 0xAA, 0x27, 0xA6, 0xF3, 0x1A, 0x83, 0x02, 0xBF, 0xD5, 0x78, 0xBC, 0x52, 0x93, 0xBD, 0xA4, 0xC1, 0x84, 0xE7, 0xD7, 0xBB, 0x58, 0x9F, 0x6D, 0xEA, 0x11, 0xC9, 0xF3, 0x9A, 0xB9, 0xCD, 0x09, 0x8A, 0x72, 0x81, 0x63, 0xD7, 0x96, 0x2B, 0x6A, 0x40, 0x06, 0xF2, 0x65, 0x27, 0x73, 0xD5, 0xD8, 0xCA, 0xDA, 0x35, 0xFB, 0x07, 0xDD, 0x8D, 0x39, 0x2D, 0xF7, 0x07, 0x9D, 0x1D, 0x72, 0x1D, 0xFA, 0xEC, 0xFF, 0xAC, 0xDB, 0x80, 0x81, 0x42, 0xFB, 0xA4, 0xF3, 0xC9, 0xB5, 0xC3, 0x1C, 0x81, 0xBB, 0x58, 0xA9, 0xAA, 0x30, 0x1F, 0x3D, 0x54, 0xEB, 0x4B, 0x0D, 0xBF, 0xF7, 0xF2, 0x67, 0x73, 0xB4, 0x56, 0xD5, 0xC0, 0x2F, 0x94, 0x25, 0x4E, 0xB7, 0x7E, 0x35, 0x3A, 0x68, 0x75, 0x3D, 0xCD, 0xC6, 0x2E, 0xC2, 0x3B, 0xDD, 0x5D, 0x6B, 0xBA, 0x07, 0xDB, 0x3E, 0xAC, 0x51, 0xE6, 0x4C, 0x34, 0xB4, 0xB5, 0x34, 0x38, 0xBF, 0x7C, 0x6E, 0xF9, 0xC6, 0x23, 0x7B, 0x68, 0xF6, 0x98, 0xE4, 0x31, 0x50, 0x77, 0x23, 0xA2, 0xE3, 0xBC, 0x43, 0xDD, 0xB6, 0xD9, 0x52, 0xA4, 0xF1, 0x2B, 0x43, 0xF7, 0x64, 0xF7, 0x5B, 0x5C, 0x6C, 0xB8, 0x82, 0xF7, 0xFE, 0xB7, 0x38, 0xAE, 0x3F, 0xB9, 0x1C, 0xBF, 0x49, 0x7E, 0x8E, 0x1D, 0x1B, 0x1D, 0x59, 0x22, 0x79, 0xAF, 0x26, 0x16, 0x6C, 0xCA, 0x5A, 0xBD, 0xD2, 0x8E, 0x6E, 0xFF, 0x4F, 0xBA, 0x74, 0x60, 0x5E, 0xA8, 0x85, 0xCE, 0xEB, 0x5A, 0x01, 0xEA, 0xFD, 0xE3, 0x16, 0x93, 0x9C, 0x35, 0xB8, 0x01, 0x0D, 0xD8, 0x57, 0x9A, 0x3A, 0x94, 0xFC, 0x68, 0x5E, 0xEB, 0x1F, 0x62, 0x83, 0xC5, 0xE6, 0xAD, 0x51, 0xE8, 0x2A, 0x93, 0x51, 0xC9, 0xD1, 0xA3, 0xFD, 0xB8, 0xB3, 0xD2, 0x6D, 0x02, 0x93, 0xA8, 0xBC, 0xBF, 0x25, 0x6B, 0x5E, 0x5B, 0xB3, 0x31, 0x23, 0x3A, 0x30, 0xDA, 0xF0, 0xFE, 0x4A, 0xDE, 0x80, 0x82, 0xB3, 0x03, 0xC3, 0x9E, 0x55, 0x1D, 0xBC, 0xC3, 0x02, 0xBF, 0x9B, 0x8A, 0xD3, 0x93, 0x3C, 0xB9, 0xAD, 0x90, 0x0A, 0x68, 0x25, 0x36, 0x7E, 0x15, 0x3E, 0x89, 0x6B, 0xC9, 0xAF, 0xDF, 0x8E, 0x40, 0x55, 0xA9, 0xD0, 0x9B, 0x85, 0x4C, 0xA8, 0x3D, 0x3A, 0xDF, 0x6E, 0x00, 0x43, 0x75, 0xC4, 0xED, 0xE4, 0xEC, 0x5C, 0x57, 0x80, 0x5F, 0x79, 0xA2, 0x06, 0x03, 0x4C, 0x51, 0x40, 0xCC, 0x60, 0x27, 0x7E, 0xAA, 0x74, 0xCD, 0xEE, 0xE9, 0xF0, 0x49, 0x3E, 0x90, 0x91, 0xC2, 0x29, 0x98, 0xB6, 0x13, 0x86, 0x3C, 0xE3, 0xAB, 0x77, 0x98, 0x39, 0x2E, 0x69, 0x67, 0x58, 0xC0, 0x32, 0x28, 0x6E, 0x10, 0x39, 0xBB, 0x13, 0x6C, 0x7C, 0x54, 0x30, 0xCB, 0xCD, 0x6D, 0x99, 0x9A, 0xA1, 0xF7, 0xB2, 0x8B, 0xE6, 0x03, 0x32, 0xCE, 0x70, 0xF5, 0x6E, 0xE3, 0x1C, 0x9E, 0xAB, 0x2D, 0x1E, 0x41, 0x3F, 0x0E, 0x65, 0x59, 0xE1, 0xF5, 0xCC, 0x6A, 0x5A, 0xAA, 0x8A, 0xD2, 0x64, 0x46, 0x88, 0x85, 0x52, 0x18, 0x1B, 0x8A, 0xA5, 0x30, 0xE4, 0xC6, 0x64, 0x68, 0x01, 0x08, 0x00, 0xAD, 0x5A, 0x94, 0xF3, 0xA0, 0xDD, 0x36, 0x9F, 0x1D, 0x5D, 0x16, 0xA8, 0x3A, 0x5F, 0xF7, 0x49, 0xC5, 0xFE, 0xC8, 0x67, 0x2F, 0x92, 0xE5, 0xC8, 0x40, 0x0B, 0xD7, 0x67, 0x1F, 0x91, 0xFC, 0x06, 0x97, 0x21, 0x53, 0x14, 0xF0, 0x26, 0x51, 0x61, 0x42, 0xCA, 0xA6, 0x03, 0xED, 0x19, 0x11, 0x5A, 0xAC, 0x9C, 0x32, 0x5D, 0x18, 0x34, 0x0E, 0x67, 0x62, 0xEF, 0xBA, 0xCF, 0xEF, 0x8E, 0x33, 0x13, 0x3C, 0x0F, 0x8F, 0x84, 0xBE, 0x6C, 0x1F, 0x95, 0xCB, 0x24, 0x45, 0x3D, 0xD8, 0x46, 0xEB, 0xC6, 0x29, 0x5C, 0x7E, 0x7D, 0xF9, 0x44, 0xB0, 0x17, 0xF1, 0xEF, 0x8A, 0x47, 0x85, 0x22, 0x96, 0xF0, 0x91, 0x96, 0xD1, 0x51, 0xB7, 0x8D, 0x77, 0xC9, 0xC1, 0xDA, 0x7D, 0x99, 0x75, 0xE5, 0x89, 0x83, 0xD3, 0x31, 0xE1, 0x78, 0x3F, 0xA6, 0x3B, 0xD9, 0x0C, 0x58, 0xC8, 0x2E, 0x4B, 0xFD, 0xDF, 0x8F, 0x0B, 0x4C, 0x37, 0xBB, 0xA4, 0x39, 0x07, 0x4F, 0x32, 0xE4, 0x1A, 0xBB, 0xCC, 0x90, 0xB5, 0x6C, 0x6A, 0xD3, 0x6E, 0xC8, 0xAB, 0x1F, 0xB3, 0x34, 0xCE, 0x59, 0xDA, 0x0E, 0xEF, 0xBE, 0x46, 0x5B, 0xF9, 0x62, 0x67, 0x4D, 0x25, 0x81, 0x5F, 0x22, 0x10, 0x84, 0x86, 0x56, 0x93, 0xB0, 0x3A, 0x44, 0xF6, 0x39, 0xF3, 0xA4, 0x7C, 0x36, 0xEE, 0xB2, 0x46, 0xD3, 0x90, 0x7D, 0x2F, 0x1D, 0x23, 0x78, 0xD7, 0xD7, 0x93, 0xD3, 0x95, 0xC3, 0x65, 0x52, 0x5A, 0x46, 0x5D, 0x9C, 0xE4, 0x15, 0x25, 0x41, 0xE5, 0x94, 0xA7, 0x29, 0xAC, 0x62, 0xEE, 0x4E, 0x3A, 0xB5, 0x89, 0xE7, 0xB0, 0x01, 0xD5, 0xF2, 0x35, 0x4E, 0x3E, 0x30, 0xB1, 0x82, 0xBD, 0x69, 0xDC, 0x5A, 0x87, 0x7F, 0xF1, 0xCB, 0x87, 0xFB, 0x9C, 0x25, 0x60, 0xBF, 0xE8, 0x2D, 0x3E, 0xDB, 0x06, 0x3B, 0xB7, 0x4D, 0x4B, 0x1F, 0x5C, 0xF3, 0x31, 0xB2, 0xD8, 0x4B, 0x45, 0x98, 0x8E, 0x04, 0xF7, 0x18, 0x32, 0xF0, 0x27, 0x2C, 0xD5, 0xA8, 0x44, 0x91, 0x9E, 0xC3, 0x41, 0x3A, 0xE0, 0xE9, 0x9F, 0x0A, 0x8D, 0xAD, 0xC1, 0x87, 0xE9, 0xBD, 0x9A, 0x4D, 0xF9, 0xE1, 0x05, 0xD1, 0x81, 0x37, 0x60, 0xC4, 0xFA, 0x32, 0x95, 0xBC, 0x22, 0x51, 0x7E, 0x89, 0x07, 0xD9, 0x85, 0xD2, 0x79, 0xEA, 0x25, 0x67, 0x4C, 0x78, 0x53, 0x18, 0x80, 0x5D, 0x1D, 0xBC, 0xD7, 0x97, 0x62, 0x46, 0x83, 0xC3, 0x63, 0xEA, 0xCA, 0xFE, 0x62, 0xC0, 0x78, 0x83, 0x4A, 0x5B, 0x13, 0x78, 0x7F, 0xAF, 0x0A, 0xB3, 0xB4, 0xD2, 0x45, 0x71, 0x3B, 0x02, 0x22, 0x2A, 0x8A, 0x60, 0x56, 0x23, 0xA5, 0xE1, 0xE5, 0x0F, 0x5D, 0xBB, 0xAB, 0x95, 0x6A, 0xBC, 0xA5, 0xF0, 0x64, 0x11, 0xD5, 0x97, 0xB0, 0xFB, 0x2D, 0x6D, 0xCC, 0x65, 0x0E, 0x77, 0x65, 0xF5, 0xE2, 0x3C, 0x4B, 0x8B, 0xC2, 0xB7, 0xAE, 0x0C, 0x88, 0x58, 0xB6, 0x50, 0xD1, 0x66, 0x89, 0x10, 0x38, 0x54, 0x39, 0x2C, 0xB2, 0x41, 0x0E, 0xBD, 0x20, 0x8D, 0xF2, 0xE8, 0xD6, 0xF2, 0x21, 0x33, 0xCB, 0x63, 0xBC, 0x21, 0xE9, 0x69, 0xDC, 0x67, 0xA0, 0xE2, 0xEE, 0xDC, 0x42, 0x8E, 0x3B, 0x71, 0xC8, 0x31, 0x89, 0x9B, 0x8D, 0x41, 0x22, 0xE5, 0x96, 0x69, 0xC1, 0x42, 0xBA, 0xB2, 0x0A, 0xFF, 0x7E, 0xD1, 0x89, 0x54, 0xB6, 0x52, 0x4B, 0x8C, 0x58, 0xD3, 0x91, 0xE3, 0x70, 0x61, 0xD1, 0xD5, 0x66, 0xEA, 0x04, 0x42, 0x7E, 0x91, 0x44, 0x09, 0x5F, 0xDB, 0x1A, 0x28, 0xC1, 0xFD, 0x49, 0xCA, 0xD9, 0xFD, 0x55, 0xD7, 0x54, 0x7F, 0xF9, 0xD6, 0x0D, 0x54, 0xF7, 0x20, 0x5E, 0xBE, 0xD4, 0x96, 0xD1, 0xE9, 0xDE, 0xDB, 0x8B, 0x28, 0xCE, 0xF8, 0x1D, 0x1A, 0xA5, 0x78, 0x05, 0x76, 0xD6, 0x7D, 0x70, 0x23, 0x21, 0xE5, 0x89, 0xD4, 0x4A, 0x60, 0xE2, 0x1F, 0xA0, 0x7B, 0xD9, 0x2D, 0xCF, 0xA1, 0x57, 0xF1, 0x0D, 0xA6, 0x0F, 0xAD, 0x6E, 0x44, 0x28, 0x07, 0xD4, 0xE1, 0xCF, 0x5F, 0x7A, 0xBD, 0x0B, 0xB4, 0xBF, 0x1D, 0x7F, 0xF3, 0x6A, 0x0E, 0x63, 0x6E, 0x30, 0x0C, 0xD8, 0x57, 0x55, 0x33, 0x1B, 0x22, 0x05, 0x97, 0x87, 0x23, 0xD9, 0xAC, 0xE6, 0xF2, 0xD5, 0x6F, 0xEC, 0x9D, 0x54, 0x59, 0x4C, 0xDB, 0x64, 0x3B, 0x8A, 0x9D, 0x8E, 0x6F, 0x76, 0x5C, 0xCE, 0xEF, 0x28, 0x19, 0xB3, 0xEF, 0x55, 0xDE, 0x38, 0x9F, 0xDC, 0x00, 0x79, 0x27, 0xD2, 0x22, 0xF1, 0x1D, 0x22, 0x76, 0xDD, 0x18, 0xD4, 0xDF, 0x86, 0xE8, 0xE7, 0xE2, 0xA4, 0xD9, 0x94, 0x3D, 0xD8, 0x83, 0xD7, 0x0B, 0xC0, 0x45, 0xB6, 0xAF, 0xAB, 0xED, 0xDF, 0x42, 0x18, 0xA2, 0x5A, 0xBF, 0x3F, 0xB0, 0xD4, 0x13, 0xD6, 0x18, 0x37, 0xC4, 0x5B, 0x86, 0xF9, 0xE6, 0xC6, 0x25, 0x53, 0x37, 0xC3, 0x8A, 0xF3, 0x5B, 0xE8, 0x2B, 0xE1, 0xF0, 0x3A, 0xF0, 0x81, 0x1F, 0x2F, 0x1E, 0xEB, 0x25, 0x27, 0x6B, 0xF6, 0xAB, 0x27, 0xB9, 0x25, 0x64, 0x33, 0x4F, 0x06, 0x3A, 0x83, 0x18, 0xFC, 0x69, 0xC1, 0x34, 0x70, 0xDA, 0x6F, 0xD9, 0x47, 0xB7, 0xEE, 0x2F, 0x67, 0xA7, 0x60, 0x5F, 0x6A, 0x57, 0x95, 0x3F, 0x96, 0xA3, 0x35, 0xB5, 0x50, 0x12, 0x63, 0x98, 0x67, 0x49, 0x02, 0x11, 0x88, 0x62, 0xF0, 0x86, 0x3F, 0x93, 0x13, 0xA3, 0x6A, 0xD0, 0x57, 0x34, 0xE5, 0x1F, 0x54, 0x98, 0x62, 0x17, 0x0E, 0xC3, 0x69, 0x5A, 0x67, 0xE0, 0xC1, 0x6C, 0xDC, 0xDE, 0xA7, 0x7B, 0x39, 0x5D, 0x1F, 0xC4, 0xF8, 0xF1, 0x3A, 0x08, 0xBA, 0x8D, 0x4C, 0xC4, 0x09, 0xCA, 0xBC, 0x9B, 0x15, 0xF1, 0x00, 0x7A, 0x4E, 0x3E, 0x4A, 0x71, 0x37, 0xB7, 0x00, 0xBE, 0xF5, 0xC3, 0x32, 0x97, 0x73, 0x5B, 0xE4, 0xC0, 0xAD, 0xB5, 0x4A, 0xA2, 0xDB, 0xE0, 0x96, 0x2D, 0x16, 0x83, 0x55, 0x5C, 0xFC, 0xB8, 0x84, 0x17, 0xD7, 0x19, 0x4B, 0x7A, 0xDF, 0x09, 0xB3, 0xD2, 0xD5, 0xBA, 0xDE, 0xB1, 0xE8, 0x47, 0xAF, 0x62, 0x11, 0x65, 0x45, 0x4C, 0x4D, 0xA0, 0x0D, 0x11, 0x85, 0x06, 0xE8, 0x25, 0xBD, 0x8F, 0x90, 0xDE, 0x0C, 0xC1, 0x1A, 0xFA, 0xD8, 0x5E, 0x08, 0xE9, 0x0E, 0xB5, 0xC4, 0x42, 0xD5, 0xB8, 0x5C, 0x9A, 0x9B, 0x86, 0xF2, 0x75, 0x8F, 0x4B, 0xB9, 0xDA, 0x95, 0xA7, 0xB5, 0xB5, 0x85, 0xD6, 0x1A, 0x5C, 0x0E, 0x6E, 0x92, 0x0B, 0xBC, 0x43, 0x64, 0x97, 0xBB, 0x6C, 0x9A, 0xB8, 0x18, 0xAF, 0xCB, 0x5C, 0xE8, 0x14, 0x81, 0x09, 0xED, 0x99, 0x94, 0x2E, 0x07, 0x90, 0xC5, 0xE2, 0x71, 0x4F, 0x4A, 0x88, 0x06, 0x74, 0xF4, 0xC6, 0x86, 0xF0, 0x7B, 0x48, 0xF5, 0xB8, 0x35, 0x9F, 0x9A, 0xF6, 0x3E, 0xB2, 0x05, 0xA3, 0x7B, 0xC0, 0xC6, 0x39, 0xDF, 0x09, 0x3F, 0x88, 0xBB, 0x45, 0xCA, 0x1B, 0xA0, 0xDD, 0xD7, 0x1D, 0xB7, 0x4A, 0x22, 0xCE, 0x88, 0x4B, 0x39, 0x83, 0xD4, 0x54, 0xD5, 0x69, 0x56, 0x66, 0xED, 0x88, 0xDB, 0xB1, 0x66, 0xE9, 0x98, 0x96, 0xEA, 0xBF, 0x67, 0x6B, 0xB8, 0x6D, 0x0E, 0xF3, 0xBD, 0xCF, 0x24, 0x1F, 0x50, 0xF2, 0x67, 0x2E, 0x3C, 0xD3, 0xBD, 0xAE, 0x60, 0xE6, 0xEC, 0xCD, 0xEF, 0x96, 0xDF, 0x63, 0x90, 0x88, 0xE4, 0x45, 0x7A, 0xEE, 0xE7, 0x74, 0x6C, 0x24, 0xBD, 0x67, 0x6F, 0x3E, 0xFE, 0xA2, 0x7D, 0xDC, 0xDA, 0xC8, 0xA4, 0x1C, 0xA5, 0xBF, 0x9E, 0x03, 0xC8, 0xF5, 0xAF, 0xBB, 0xC8, 0x9B, 0x6D, 0x96, 0xBF, 0x90, 0xD9, 0x4C, 0xFF, 0xD9, 0x1E, 0x3A, 0x8A, 0x07, 0xCC, 0xF0, 0x44, 0x93, 0xA5, 0xCB, 0x44, 0x1A, 0x9F, 0x59, 0x61, 0xEA, 0xC7, 0x1C, 0xEA, 0xB0, 0x4A, 0x78, 0xF7, 0x0B, 0x4F, 0x52, 0xF4, 0x63, 0x09, 0x45, 0xAC, 0xC4, 0x5F, 0x4F, 0x83, 0xEE, 0x96, 0x7C, 0xF2, 0xB2, 0x37, 0x5D, 0x0F, 0xCE, 0x3A, 0x3F, 0x6E, 0x43, 0x96, 0x36, 0x14, 0xCC, 0xE0, 0x36, 0x03, 0xF0, 0x59, 0x7D, 0x30, 0xE1, 0xD6, 0x75, 0xC0, 0x0F, 0x3C, 0xCA, 0xC4, 0x49, 0x21, 0xD2, 0x92, 0x28, 0xFF, 0x52, 0x96, 0xD4, 0x35, 0x25, 0x2F, 0x9C, 0xB3, 0x26, 0xA4, 0xD6, 0xFC, 0x34, 0xF0, 0x79, 0x89, 0xC1, 0x84, 0x28, 0x86, 0x74, 0x59, 0xD1, 0x82, 0x95, 0xD2, 0xD6, 0x12, 0x10, 0x7F, 0x75, 0x35, 0xED, 0x27, 0xF6, 0x84, 0x6C, 0xA8, 0xD3, 0xB1, 0x73, 0x9D, 0x23, 0x45, 0xD2, 0x8B, 0xCC, 0xC4, 0xFD, 0x1A, 0x63, 0x14, 0xFD, 0x47, 0x88, 0x9B, 0x53, 0xA1, 0xA7, 0x34, 0x63, 0x4B, 0xEC, 0x0C, 0x0A, 0x1C, 0x8A, 0x0A, 0x89, 0xAC, 0x66, 0xB0, 0xF4, 0xE5, 0x32, 0x8F, 0x76, 0x39, 0x2D, 0x01, 0x73, 0xE1, 0x74, 0xEB, 0x8F, 0xA6, 0x0F, 0x86, 0xC9, 0x7F, 0x00, 0x20, 0xDC, 0xFA, 0x4E, 0x69, 0x94, 0xFC, 0x08, 0xFD, 0xCF, 0x40, 0x5A, 0x44, 0xB1, 0xC4, 0x8C, 0xC2, 0x1C, 0x51, 0xA0, 0x92, 0x81, 0x73, 0x71, 0xF9, 0x6E, 0x64, 0xBD, 0x2B, 0x69, 0xBA, 0x79, 0xD7, 0xE4, 0xDD, 0x2C, 0x1F, 0x71, 0x8B, 0xF4, 0x56, 0x39, 0xCB, 0x45, 0x39, 0xE1, 0xF8, 0x9C, 0xF0, 0xE5, 0xEF, 0x25, 0x88, 0xE2, 0x5D, 0xEB, 0x44, 0x10, 0x1D, 0x3C, 0x12, 0xE1, 0x4B, 0x99, 0x3C, 0x0A, 0xB3, 0x55, 0x61, 0x13, 0x82, 0x19, 0x59, 0xC6, 0xE9, 0xFC, 0x9A, 0xCC, 0x95, 0xBA, 0x17, 0x31, 0x4A, 0xC5, 0x6D, 0x2B, 0x26, 0xA0, 0x39, 0x10, 0x69, 0x2A, 0xA4, 0xE1, 0x58, 0xF6, 0x81, 0xCB, 0xAA, 0x7C, 0x0F, 0xF8, 0x03, 0xD6, 0x66, 0x4B, 0x60, 0x9E, 0x5A, 0x4A, 0x25, 0x73, 0x58, 0x9F, 0xCD, 0x16, 0x8D, 0x17, 0x90, 0x13, 0x32, 0x3E, 0x4B, 0x4F, 0x51, 0x53, 0x68, 0x6B, 0x74, 0x75, 0x78, 0x7C, 0xA2, 0xAF, 0xB6, 0xC4, 0xC5, 0xF4, 0xF8, 0x0D, 0x1D, 0x37, 0x46, 0x4D, 0x55, 0x57, 0x6A, 0x7B, 0x8C, 0xAC, 0xB2, 0xC6, 0xC7, 0xC8, 0xD2, 0xEA, 0xF4, 0xF9, 0xFC, 0x18, 0x19, 0x20, 0x25, 0x27, 0x39, 0x5A, 0x5E, 0x90, 0xA4, 0xAF, 0xE8, 0xEF, 0xF2, 0xF8, 0xF9, 0x11, 0x29, 0x38, 0x68, 0x76, 0xAC, 0xAD, 0xBD, 0xD6, 0xDA, 0xE1, 0xEB, 0xF3, 0x1B, 0x38, 0x5D, 0x67, 0x76, 0x81, 0x87, 0x8A, 0x91, 0x94, 0xAE, 0xC2, 0xD6, 0xD9, 0xDF, 0xFF, 0x01, 0x02, 0x1B, 0x2F, 0x34, 0x3B, 0x3F, 0x40, 0x58, 0x94, 0xAE, 0xB1, 0xBD, 0xC5, 0xD5, 0xD7, 0x0A, 0x20, 0x23, 0x2D, 0x30, 0x3C, 0x65, 0x6C, 0x75, 0x76, 0x7E, 0x83, 0x90, 0xC2, 0xE7, 0xEB, 0x0C, 0x51, 0x64, 0x77, 0x88, 0xA4, 0xBB, 0xC1, 0xC7, 0xDB, 0xDC, 0xE5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x28, 0x38, 0x45, 0x55, 0x65, 0x75, 0x81, 0x02, 0x10, 0x1C, 0x20, 0x18, 0x40, 0x08, 0x09, 0x06, 0x4C, 0x04, 0x04, 0x02, 0x85, 0x00, 0x1D, 0xA0, 0x42, 0x9C, 0x48, 0x00, 0x81, 0x8C, 0x40, 0xC1, 0x42, 0x00, 0xC1, 0x0D, 0x09, 0x01, 0x94, 0xE8, 0x78, 0x5E, 0x1F, 0xF5, 0x65, 0x11, 0x03, }, }, { .name = "Dilithium Round 2, Level 5 (8-7) KAT 1", .version = 0, .keyform = CK_IBM_DILITHIUM_KEYFORM_ROUND2_87, .rho_len = 32, .rho = { 0x4B, 0x62, 0x2D, 0xE1, 0x35, 0x01, 0x19, 0xC4, 0x5A, 0x9F, 0x2E, 0x2E, 0xF3, 0xDC, 0x5D, 0xF5, 0x0A, 0x75, 0x9D, 0x13, 0x8C, 0xDF, 0xBD, 0x64, 0xC8, 0x1C, 0xC7, 0xCC, 0x2F, 0x51, 0x33, 0x45, }, .seed_len = 32, .seed = { 0x13, 0x77, 0x46, 0xE7, 0x45, 0x56, 0x52, 0xAF, 0x6F, 0xB7, 0x64, 0x83, 0x32, 0x42, 0xF0, 0x64, 0xFA, 0xAA, 0xDD, 0x99, 0x3B, 0x49, 0xFE, 0x63, 0xBC, 0xDF, 0xA2, 0xC5, 0x5E, 0xD3, 0xEC, 0xD4, }, .tr_len = 48, .tr = { 0x83, 0x21, 0xD1, 0x46, 0x16, 0x74, 0x43, 0x38, 0x73, 0xC0, 0xDB, 0x53, 0x59, 0x75, 0xEA, 0xD8, 0x1F, 0x18, 0xBD, 0x73, 0x99, 0xE7, 0xAE, 0xC5, 0x4C, 0xA2, 0xF3, 0x61, 0x91, 0x83, 0xD0, 0xA9, 0x89, 0x77, 0xFA, 0x2D, 0x99, 0x1C, 0x2C, 0x01, 0x8D, 0xBE, 0xDE, 0xBF, 0xBC, 0x8C, 0xAE, 0x66, }, .s1_len = 672, .s1 = { 0x1B, 0x86, 0x4D, 0x02, 0xB0, 0x0D, 0x92, 0x34, 0x12, 0x4C, 0xC8, 0x71, 0x93, 0xB0, 0x65, 0x8B, 0x16, 0x4C, 0xC0, 0xA4, 0x89, 0xC9, 0x46, 0x0C, 0x5C, 0x34, 0x44, 0x4A, 0x24, 0x10, 0xD4, 0xB4, 0x81, 0x8C, 0x04, 0x32, 0xD3, 0x84, 0x00, 0x04, 0xC0, 0x91, 0x8C, 0x04, 0x29, 0xD1, 0x46, 0x91, 0x10, 0x91, 0x20, 0x19, 0x06, 0x24, 0x94, 0x14, 0x2E, 0x64, 0x48, 0x82, 0x0B, 0xA9, 0x90, 0x20, 0x24, 0x0D, 0x11, 0xC2, 0x05, 0x20, 0xA7, 0x20, 0x98, 0x28, 0x91, 0x60, 0x48, 0x86, 0xD1, 0xA0, 0x44, 0x5B, 0x86, 0x0C, 0x21, 0x89, 0x4D, 0x04, 0x99, 0x08, 0xA4, 0xA4, 0x2C, 0xD0, 0x08, 0x52, 0x42, 0x42, 0x26, 0x00, 0x31, 0x85, 0x50, 0x12, 0x92, 0x12, 0x91, 0x91, 0x02, 0x14, 0x6E, 0xE3, 0xB2, 0x0D, 0x41, 0x40, 0x68, 0xD8, 0x98, 0x10, 0x9B, 0x84, 0x69, 0x21, 0xB3, 0x05, 0x62, 0x16, 0x68, 0x22, 0x19, 0x41, 0x44, 0x10, 0x4C, 0x49, 0x94, 0x41, 0x58, 0x46, 0x52, 0x0B, 0x09, 0x04, 0x10, 0x98, 0x29, 0x61, 0xB8, 0x01, 0x01, 0x19, 0x50, 0x23, 0x12, 0x49, 0xDB, 0x02, 0x41, 0x88, 0x38, 0x66, 0xE4, 0x92, 0x65, 0x9A, 0xA0, 0x08, 0x62, 0x48, 0x2D, 0xC4, 0x94, 0x01, 0xD9, 0xA8, 0x69, 0x18, 0x10, 0x08, 0x4B, 0x14, 0x10, 0x24, 0x08, 0x8C, 0xC8, 0x36, 0x4D, 0x99, 0x20, 0x61, 0x43, 0x32, 0x68, 0x11, 0x86, 0x48, 0xCB, 0x82, 0x88, 0xC8, 0x16, 0x71, 0x9C, 0xC6, 0x29, 0x63, 0x00, 0x6A, 0x4B, 0x14, 0x84, 0x23, 0xC3, 0x49, 0x1B, 0x11, 0x64, 0xDC, 0x92, 0x05, 0x60, 0x80, 0x60, 0x22, 0xB3, 0x8C, 0x43, 0x08, 0x11, 0x8C, 0x22, 0x25, 0x41, 0x86, 0x08, 0x20, 0x40, 0x31, 0x8B, 0x12, 0x90, 0x18, 0xB2, 0x28, 0xC3, 0x08, 0x0C, 0x93, 0x00, 0x82, 0x13, 0x00, 0x80, 0x22, 0x05, 0x8C, 0x12, 0x15, 0x08, 0x22, 0xA2, 0x25, 0xD1, 0x12, 0x68, 0x48, 0x14, 0x6D, 0x93, 0x26, 0x60, 0xDC, 0x02, 0x89, 0x1C, 0x35, 0x8D, 0x8C, 0x22, 0x82, 0x80, 0x98, 0x64, 0xC1, 0x30, 0x30, 0x02, 0xB5, 0x21, 0x1C, 0x10, 0x30, 0x00, 0x82, 0x24, 0xCA, 0x88, 0x70, 0x4C, 0x08, 0x4E, 0x18, 0x16, 0x46, 0x90, 0x14, 0x62, 0xE3, 0xC6, 0x69, 0xD0, 0x30, 0x42, 0x62, 0x96, 0x91, 0xD3, 0xC4, 0x8C, 0x41, 0x06, 0x92, 0xCA, 0xA0, 0x11, 0x21, 0x36, 0x81, 0x20, 0xA6, 0x2D, 0x20, 0x14, 0x89, 0xC1, 0x00, 0x42, 0x12, 0x43, 0x2C, 0xD3, 0xA0, 0x85, 0x64, 0x30, 0x8A, 0x59, 0x10, 0x28, 0xE3, 0x98, 0x11, 0x24, 0xC9, 0x4D, 0x5C, 0x42, 0x00, 0x5C, 0xB0, 0x4C, 0x02, 0xB8, 0x2C, 0x60, 0xA6, 0x01, 0xA3, 0x14, 0x62, 0x83, 0x88, 0x50, 0x24, 0x08, 0x85, 0x92, 0x00, 0x2A, 0x1A, 0xA3, 0x21, 0x04, 0xC9, 0x89, 0xA3, 0x14, 0x8D, 0xC1, 0x18, 0x0E, 0xCA, 0x48, 0x24, 0x90, 0xA0, 0x8C, 0x13, 0x09, 0x90, 0xA3, 0x48, 0x12, 0x61, 0x30, 0x71, 0x50, 0x86, 0x41, 0x13, 0x11, 0x80, 0xC8, 0x88, 0x24, 0x1C, 0x99, 0x61, 0x0A, 0x83, 0x64, 0x12, 0xB8, 0x4D, 0xC0, 0x12, 0x80, 0x1B, 0x08, 0x0C, 0x84, 0x82, 0x01, 0xC0, 0x00, 0x0C, 0x03, 0x94, 0x01, 0x04, 0x44, 0x68, 0x00, 0x25, 0x71, 0x5B, 0x38, 0x71, 0x0B, 0xB3, 0x4C, 0x04, 0xB4, 0x25, 0x83, 0x30, 0x44, 0x60, 0xA2, 0x51, 0x5C, 0xC0, 0x48, 0xA3, 0x30, 0x6A, 0x9B, 0x10, 0x4D, 0x24, 0x24, 0x82, 0xD9, 0x86, 0x44, 0x10, 0x00, 0x64, 0x1B, 0x31, 0x6D, 0x0A, 0x20, 0x25, 0x41, 0xC0, 0x71, 0xA4, 0x12, 0x91, 0x0C, 0x21, 0x6C, 0xA2, 0x86, 0x61, 0x13, 0xB9, 0x28, 0xC2, 0x14, 0x52, 0x04, 0x29, 0x30, 0x1C, 0xB3, 0x04, 0x02, 0x10, 0x8E, 0x44, 0x26, 0x65, 0x20, 0x48, 0x8E, 0x1A, 0xC0, 0x29, 0x02, 0xB9, 0x30, 0xE4, 0x22, 0x8E, 0x19, 0xC5, 0x4D, 0x04, 0xB2, 0x8D, 0xDC, 0xB0, 0x0D, 0x53, 0x16, 0x72, 0x42, 0xB6, 0x70, 0x60, 0x32, 0x32, 0xCA, 0xC2, 0x0C, 0x1C, 0x19, 0x4D, 0x11, 0xA7, 0x2C, 0x23, 0x31, 0x46, 0xA1, 0x82, 0x0D, 0x04, 0x10, 0x64, 0xA1, 0x02, 0x31, 0xE3, 0x04, 0x44, 0x22, 0x37, 0x6A, 0x1C, 0x87, 0x2C, 0x1A, 0x86, 0x49, 0x9A, 0x48, 0x8E, 0xA0, 0x96, 0x90, 0x0B, 0xB7, 0x64, 0xE2, 0x48, 0x8A, 0xE1, 0x80, 0x08, 0x22, 0x14, 0x11, 0x0A, 0x05, 0x86, 0x41, 0x34, 0x0D, 0x00, 0xB0, 0x40, 0xCC, 0x32, 0x0A, 0x4C, 0x36, 0x4E, 0x22, 0xC5, 0x29, 0x84, 0x48, 0x70, 0x00, 0x84, 0x81, 0xE1, 0x10, 0x85, 0xDC, 0x30, 0x29, 0xE2, 0x38, 0x2E, 0x91, 0x40, 0x81, 0x04, 0x90, 0x64, 0x9A, 0xB0, 0x01, 0x12, 0xB5, 0x04, 0x8C, 0x34, 0x31, 0x21, 0x00, 0x4E, 0xD3, 0x28, 0x68, 0x23, 0xC9, 0x4D, 0xD3, 0x16, 0x8E, 0x21, 0x91, 0x90, 0x12, 0x87, 0x29, 0x23, 0xA7, 0x48, 0x04, 0xC0, 0x81, 0x08, 0x26, 0x09, }, .s2_len = 768, .s2 = { 0x48, 0x32, 0x46, 0x09, 0x10, 0x4D, 0x04, 0x05, 0x70, 0x59, 0x92, 0x20, 0x59, 0x44, 0x0A, 0x58, 0x42, 0x65, 0x91, 0x34, 0x72, 0x14, 0x23, 0x6D, 0x8C, 0x38, 0x2D, 0x80, 0x92, 0x69, 0x21, 0x90, 0x6D, 0x10, 0xC0, 0x50, 0x12, 0x86, 0x49, 0xC2, 0xB2, 0x40, 0x9B, 0x34, 0x90, 0x5B, 0x08, 0x8A, 0x98, 0x44, 0x68, 0xDB, 0x22, 0x71, 0xC3, 0x34, 0x51, 0x09, 0xC4, 0x71, 0x4A, 0x82, 0x04, 0x94, 0x24, 0x02, 0x1A, 0x36, 0x88, 0x4A, 0x48, 0x02, 0x91, 0x02, 0x6E, 0x8A, 0x22, 0x2C, 0x61, 0xA2, 0x80, 0x20, 0x99, 0x28, 0x54, 0x14, 0x31, 0x22, 0x31, 0x6C, 0x0C, 0xB1, 0x21, 0xA3, 0x08, 0x71, 0x88, 0x34, 0x22, 0xD3, 0x44, 0x6C, 0x02, 0x44, 0x0A, 0x8A, 0x80, 0x71, 0x80, 0x14, 0x6C, 0x9B, 0x42, 0x50, 0xC3, 0x34, 0x72, 0xC9, 0xA2, 0x90, 0x58, 0x44, 0x71, 0x43, 0x00, 0x00, 0x44, 0x34, 0x0D, 0xD3, 0xC8, 0x8C, 0xA1, 0x26, 0x70, 0x41, 0xC2, 0x24, 0x03, 0x35, 0x52, 0x58, 0xB2, 0x71, 0x09, 0x43, 0x4C, 0x1A, 0xB4, 0x91, 0xDA, 0xC6, 0x85, 0x89, 0xC6, 0x91, 0x23, 0x24, 0x8A, 0x40, 0x34, 0x4D, 0x19, 0x15, 0x84, 0x14, 0x48, 0x8D, 0xD3, 0x30, 0x20, 0x80, 0xC8, 0x61, 0x93, 0x38, 0x0D, 0x88, 0x26, 0x8E, 0x12, 0x47, 0x21, 0x21, 0x19, 0x26, 0x09, 0x42, 0x64, 0x19, 0xA0, 0x84, 0x02, 0xC0, 0x70, 0x88, 0x98, 0x29, 0xC0, 0x00, 0x2A, 0x53, 0x22, 0x85, 0x90, 0x08, 0x8D, 0xD0, 0x30, 0x40, 0x1C, 0x13, 0x0C, 0x00, 0x86, 0x90, 0x62, 0x28, 0x32, 0x1C, 0x27, 0x20, 0x49, 0x42, 0x22, 0x8A, 0x02, 0x29, 0xCB, 0xC0, 0x49, 0x44, 0x00, 0x4E, 0x11, 0x19, 0x8D, 0x13, 0x07, 0x72, 0x60, 0x86, 0x04, 0x5A, 0x28, 0x52, 0x88, 0xA4, 0x71, 0x0A, 0xB5, 0x31, 0x12, 0x21, 0x04, 0x9C, 0x28, 0x81, 0x00, 0x35, 0x6C, 0x64, 0x34, 0x0A, 0x14, 0x92, 0x71, 0xE3, 0x10, 0x72, 0x00, 0x96, 0x4C, 0x24, 0x43, 0x45, 0xCA, 0x24, 0x2C, 0x5B, 0x34, 0x30, 0xA0, 0x96, 0x24, 0x14, 0x29, 0x89, 0x1B, 0x08, 0x01, 0x80, 0xC6, 0x8C, 0x12, 0x15, 0x71, 0x13, 0x16, 0x44, 0x12, 0xB0, 0x49, 0x4A, 0x00, 0x91, 0x10, 0x80, 0x08, 0x93, 0xB0, 0x40, 0xCC, 0xB6, 0x01, 0x89, 0xC8, 0x20, 0xC9, 0xC2, 0x84, 0x8B, 0xB8, 0x08, 0x18, 0x96, 0x2D, 0x1B, 0x11, 0x32, 0x83, 0xA6, 0x69, 0x11, 0x07, 0x45, 0x81, 0x14, 0x31, 0x0C, 0x36, 0x4A, 0x0A, 0x01, 0x82, 0x51, 0xA2, 0x10, 0xA3, 0x00, 0x52, 0x44, 0x28, 0x45, 0x60, 0x12, 0x8D, 0x80, 0x06, 0x64, 0x18, 0xC2, 0x2D, 0x13, 0x93, 0x24, 0x1A, 0x20, 0x68, 0xCB, 0xB0, 0x0D, 0x58, 0xB0, 0x31, 0x94, 0x44, 0x8A, 0xC2, 0x36, 0x06, 0x90, 0x80, 0x64, 0x61, 0x92, 0x81, 0x98, 0xB0, 0x04, 0x93, 0x12, 0x21, 0xA0, 0xB0, 0x25, 0x22, 0x19, 0x69, 0x1B, 0x29, 0x8D, 0xC2, 0x44, 0x4E, 0xD2, 0x14, 0x04, 0xA1, 0x90, 0x0D, 0x4C, 0x28, 0x26, 0x0C, 0x07, 0x8C, 0x83, 0x30, 0x50, 0xE2, 0xC6, 0x29, 0x5A, 0x94, 0x00, 0x12, 0x15, 0x00, 0xC9, 0x04, 0x04, 0xC8, 0x42, 0x4A, 0xC4, 0x10, 0x61, 0xC9, 0xC0, 0x31, 0xCC, 0x00, 0x2E, 0xC0, 0x22, 0x8A, 0x18, 0x05, 0x92, 0x50, 0x84, 0x41, 0x21, 0x81, 0x28, 0x13, 0x18, 0x70, 0xD1, 0x00, 0x11, 0x03, 0x22, 0x06, 0x04, 0x91, 0x65, 0x14, 0x84, 0x4D, 0x62, 0x28, 0x8E, 0x23, 0x96, 0x2C, 0xC3, 0x84, 0x30, 0x0B, 0x21, 0x4E, 0x18, 0x27, 0x2A, 0x42, 0x16, 0x21, 0x62, 0xB8, 0x31, 0x22, 0x43, 0x40, 0x94, 0x22, 0x2D, 0x11, 0x06, 0x62, 0x80, 0x02, 0x85, 0x44, 0x86, 0x08, 0x41, 0x46, 0x41, 0x40, 0xC8, 0x4C, 0x5C, 0xC6, 0x50, 0xE1, 0x08, 0x01, 0x0A, 0x21, 0x80, 0x9B, 0xA0, 0x49, 0x19, 0xB7, 0x24, 0x19, 0x18, 0x66, 0x01, 0x81, 0x6D, 0x40, 0xC0, 0x69, 0x52, 0x24, 0x6C, 0x02, 0xA4, 0x00, 0x40, 0xB8, 0x50, 0x18, 0x37, 0x65, 0xD1, 0x90, 0x84, 0x21, 0x03, 0x25, 0x41, 0x34, 0x45, 0x60, 0x94, 0x41, 0xDA, 0xC0, 0x84, 0x81, 0x22, 0x6A, 0xC2, 0x48, 0x52, 0x1B, 0x36, 0x2A, 0xE3, 0x28, 0x8A, 0x59, 0xA6, 0x25, 0x03, 0xB4, 0x90, 0x0B, 0xB5, 0x29, 0xC0, 0x44, 0x04, 0x89, 0xB0, 0x2C, 0x83, 0x18, 0x22, 0x20, 0xB9, 0x68, 0xD4, 0x42, 0x62, 0x4A, 0xA2, 0x2C, 0x01, 0x12, 0x4E, 0xCC, 0x48, 0x80, 0xD3, 0x96, 0x09, 0x02, 0xC6, 0x64, 0x81, 0x32, 0x29, 0x02, 0x84, 0x0C, 0x1B, 0xA1, 0x2D, 0x24, 0x23, 0x09, 0x88, 0x90, 0x25, 0xC8, 0xB6, 0x69, 0x54, 0xB2, 0x25, 0xDC, 0xA6, 0x2C, 0x09, 0x45, 0x46, 0x88, 0xB6, 0x91, 0x14, 0x87, 0x28, 0x18, 0xC7, 0x2D, 0x1A, 0x85, 0x05, 0x4C, 0x14, 0x82, 0xDB, 0x14, 0x01, 0x20, 0x44, 0x6D, 0x4B, 0x28, 0x2E, 0x8C, 0x00, 0x29, 0x13, 0x41, 0x84, 0x19, 0x13, 0x8D, 0x00, 0x94, 0x8D, 0x98, 0x82, 0x29, 0x04, 0x23, 0x4E, 0xC1, 0xA2, 0x28, 0x12, 0xC4, 0x70, 0x8B, 0xA8, 0x09, 0xDA, 0x08, 0x65, 0x62, 0x10, 0x81, 0x20, 0x03, 0x8A, 0x80, 0x34, 0x4A, 0x20, 0xC9, 0x88, 0x22, 0x94, 0x11, 0xC8, 0x92, 0x89, 0xD4, 0xC4, 0x41, 0xA1, 0xB4, 0x84, 0x93, 0x02, 0x89, 0x12, 0x23, 0x41, 0x13, 0xB7, 0x25, 0x49, 0x36, 0x2A, 0x0C, 0xB3, 0x40, 0x49, 0x36, 0x70, 0x10, 0x41, 0x00, 0x19, 0xB7, 0x09, 0x22, 0x39, 0x8D, 0x63, 0x40, 0x80, 0xA3, 0x94, 0x28, 0x90, 0x04, 0x41, 0x40, 0x18, 0x89, 0x12, 0x47, 0x61, 0x83, 0x12, 0x4E, 0x1A, 0x48, 0x2E, }, .t0_len = 3584, .t0 = { 0x75, 0x48, 0xEF, 0x27, 0x75, 0xAA, 0x88, 0x5A, 0xB6, 0x93, 0x11, 0x4A, 0x06, 0x0F, 0x01, 0xDC, 0x38, 0x75, 0xEB, 0x2F, 0x16, 0x52, 0xD4, 0x2F, 0x8B, 0x5F, 0x3C, 0xC2, 0xBC, 0xAB, 0x20, 0x9A, 0xD5, 0xFD, 0x34, 0x18, 0xAC, 0x20, 0x93, 0x0D, 0x7B, 0xA9, 0x80, 0xCB, 0xCC, 0xA8, 0x4C, 0x5F, 0x2F, 0xEE, 0x1F, 0x3F, 0x9B, 0x28, 0x19, 0x28, 0x74, 0x9C, 0x2E, 0x1B, 0xF1, 0x7C, 0x8A, 0x14, 0x04, 0x6B, 0x24, 0xFA, 0x37, 0x08, 0x83, 0x9B, 0xB4, 0xEE, 0x75, 0x8C, 0xD2, 0xEA, 0x55, 0x64, 0xA2, 0x0F, 0x21, 0xA2, 0x3B, 0xAE, 0x26, 0xDE, 0x9F, 0x9B, 0xC0, 0x42, 0xF9, 0xD4, 0xF2, 0x59, 0xBB, 0x1A, 0xDD, 0x41, 0x80, 0xF6, 0x73, 0x5D, 0xC5, 0xD3, 0x26, 0x1D, 0xF9, 0xD0, 0xA3, 0x1F, 0xAB, 0x24, 0xED, 0x65, 0x47, 0x32, 0x73, 0xF7, 0x63, 0xD7, 0xBC, 0x48, 0x30, 0xCE, 0xE9, 0xA1, 0x5E, 0x8F, 0xAE, 0x6E, 0x06, 0x85, 0x34, 0x56, 0x3D, 0x34, 0x71, 0x88, 0xAA, 0xD7, 0xBC, 0x6B, 0xD6, 0x12, 0x68, 0x49, 0x00, 0x44, 0xEB, 0x30, 0x0B, 0x47, 0xA0, 0xCD, 0x78, 0xBC, 0x26, 0x31, 0x41, 0xAA, 0xEB, 0x3B, 0x96, 0xF4, 0x08, 0x9B, 0x38, 0x5B, 0x46, 0x53, 0x37, 0x29, 0xDE, 0xAA, 0x68, 0x4E, 0x01, 0xAB, 0xD6, 0xE8, 0x9A, 0xFF, 0xF3, 0xBD, 0xAE, 0x91, 0xD4, 0x04, 0x5E, 0x0F, 0x4A, 0xED, 0x84, 0xD3, 0x18, 0xC6, 0x83, 0x45, 0x7B, 0x88, 0xEA, 0x50, 0x1F, 0xAA, 0x75, 0x13, 0x23, 0x35, 0x07, 0xE3, 0xE7, 0x77, 0xD5, 0xFD, 0x43, 0x48, 0xA9, 0xAB, 0xBC, 0xB8, 0x41, 0x0A, 0x47, 0x81, 0xD9, 0x45, 0x60, 0x83, 0x0E, 0x3A, 0x61, 0xE6, 0xB3, 0xE0, 0xB8, 0x09, 0xE9, 0x34, 0x47, 0xD3, 0x74, 0x08, 0xD3, 0x1B, 0x90, 0x7F, 0x72, 0xBE, 0xAE, 0x2F, 0x66, 0x3B, 0xE2, 0xC7, 0xFF, 0xF3, 0xE0, 0x7E, 0xF3, 0xB8, 0x5D, 0x69, 0xA4, 0xF8, 0x7C, 0x4F, 0x2F, 0x07, 0xF7, 0xED, 0x77, 0x69, 0xF9, 0x19, 0xA2, 0xBD, 0xEE, 0xE1, 0x7E, 0x65, 0xA7, 0x30, 0x9D, 0xE5, 0x9D, 0x2B, 0x0F, 0xA0, 0x5A, 0xB4, 0xAA, 0x92, 0xBA, 0xC3, 0x52, 0xD1, 0xE3, 0x97, 0x7E, 0xB8, 0xE4, 0x66, 0x22, 0x6D, 0x5A, 0xCE, 0x95, 0x51, 0x05, 0x8C, 0x8E, 0xC4, 0x67, 0x7D, 0x03, 0x95, 0xC2, 0x88, 0xE2, 0xFE, 0xC4, 0xAA, 0x85, 0x46, 0x18, 0xED, 0x25, 0xFF, 0xA9, 0x2E, 0x59, 0xBD, 0xD0, 0xAB, 0x72, 0x50, 0x34, 0x58, 0xA8, 0x89, 0x79, 0x81, 0x68, 0x8A, 0xB5, 0x4E, 0x92, 0x8D, 0x11, 0x1E, 0x7D, 0x62, 0x19, 0x27, 0x57, 0xA5, 0xA3, 0xFC, 0x5C, 0xB6, 0xBC, 0x2A, 0x89, 0xC2, 0x8D, 0x40, 0x41, 0x04, 0x4C, 0x0E, 0x75, 0x04, 0x07, 0xBB, 0x05, 0xFE, 0xF1, 0xF6, 0xF4, 0x59, 0xED, 0x35, 0x72, 0xB2, 0x69, 0x70, 0xF8, 0x3C, 0xDF, 0x6D, 0x88, 0x62, 0x9D, 0x43, 0xEF, 0x95, 0x5E, 0x85, 0x13, 0x5C, 0x13, 0x8A, 0x67, 0x36, 0xAC, 0x4E, 0xB1, 0xD3, 0x48, 0x1F, 0xCD, 0x14, 0x06, 0x4B, 0x03, 0x45, 0x81, 0x04, 0x6F, 0x47, 0x57, 0xA8, 0x4F, 0x6F, 0x36, 0x7C, 0x31, 0x58, 0xCE, 0x87, 0xD6, 0x59, 0x9B, 0xEB, 0x20, 0xA9, 0x20, 0xCD, 0xEE, 0xF8, 0xD6, 0xCC, 0x12, 0xB7, 0xD9, 0x50, 0x15, 0xED, 0x10, 0xD4, 0xA9, 0xB2, 0x80, 0xEE, 0x82, 0x61, 0xC9, 0xD9, 0x58, 0x3E, 0xC3, 0xCF, 0xCB, 0x31, 0xAC, 0x4F, 0x6B, 0x99, 0x3B, 0xF7, 0xC3, 0xE4, 0x49, 0x2B, 0xF9, 0x82, 0xA2, 0x8D, 0x54, 0x44, 0x5B, 0x76, 0x1B, 0xDD, 0x7B, 0x6D, 0x7E, 0x53, 0x78, 0x70, 0x9F, 0xCD, 0xDB, 0x00, 0x18, 0x1A, 0xC3, 0xE9, 0x54, 0xA5, 0x5C, 0xCA, 0x5F, 0xE5, 0x24, 0x4A, 0x7B, 0xD7, 0xDA, 0x86, 0xC6, 0xA5, 0x09, 0x01, 0xEB, 0xC6, 0xBC, 0xBD, 0xF3, 0xC1, 0xBD, 0x5A, 0x8A, 0xB4, 0x86, 0xAF, 0x90, 0xC2, 0x35, 0xC8, 0xCF, 0xA1, 0xD7, 0x72, 0xD3, 0x15, 0xA2, 0xCA, 0x08, 0x3A, 0x9C, 0x58, 0x28, 0xB6, 0x87, 0xC9, 0x86, 0x07, 0xAE, 0xD4, 0xFD, 0xE6, 0x4E, 0x17, 0x2C, 0x35, 0xC0, 0x5A, 0x8B, 0xF5, 0xB2, 0xF4, 0x84, 0xDD, 0x47, 0xD9, 0x6D, 0x9D, 0xC7, 0xB7, 0x76, 0x56, 0xFD, 0x9F, 0x8B, 0xA3, 0x9A, 0xB5, 0xEB, 0x46, 0x28, 0x9A, 0x3E, 0x95, 0x30, 0x25, 0x6A, 0x2E, 0x05, 0x6A, 0xE0, 0x05, 0xA7, 0xCD, 0xEC, 0x89, 0x5D, 0xD3, 0x20, 0xDE, 0x82, 0xA1, 0xE1, 0x3A, 0x25, 0x07, 0x8B, 0xCE, 0xA8, 0x38, 0x8F, 0x22, 0x04, 0xB5, 0x38, 0x1D, 0xB8, 0xC9, 0xB2, 0x4D, 0xAA, 0x79, 0x3D, 0x8B, 0x94, 0x84, 0x43, 0xDC, 0xF3, 0x32, 0x84, 0xA4, 0x37, 0x1E, 0x10, 0x1C, 0xF6, 0xE3, 0x04, 0x1F, 0xC5, 0x41, 0xFF, 0x18, 0xD1, 0xE4, 0xC6, 0x72, 0x9E, 0x44, 0xB9, 0xBA, 0xCA, 0x61, 0xF4, 0x7E, 0xD5, 0x94, 0x93, 0x19, 0x6C, 0xFF, 0xEA, 0x45, 0x8C, 0xF2, 0x27, 0xCF, 0x84, 0x85, 0x55, 0xCB, 0x92, 0x1C, 0xAB, 0x40, 0xEB, 0xF6, 0x66, 0xD7, 0xA9, 0xA7, 0x0A, 0xC7, 0x04, 0x6A, 0x60, 0x63, 0x45, 0x16, 0x1F, 0x36, 0x55, 0x87, 0xC1, 0xC0, 0x5F, 0x84, 0x5A, 0x8C, 0x39, 0x57, 0xF1, 0xC8, 0x76, 0x4F, 0x29, 0xF7, 0xA8, 0xFC, 0x56, 0x03, 0xA0, 0x9E, 0x10, 0xF6, 0x82, 0xAF, 0xB3, 0x4E, 0xDE, 0xB3, 0xEA, 0xC5, 0x77, 0xDA, 0x3F, 0x94, 0xD0, 0xBF, 0x15, 0x3C, 0xB6, 0xC3, 0xAF, 0xDD, 0x69, 0xA4, 0xCA, 0xF2, 0xC8, 0xD3, 0x1D, 0x09, 0x0B, 0xD3, 0x08, 0xD7, 0x12, 0x50, 0x90, 0x63, 0x27, 0x37, 0xC6, 0xAC, 0xE8, 0x6A, 0x3D, 0x8C, 0xAC, 0xBD, 0xCF, 0x8E, 0xAB, 0x94, 0x5C, 0x07, 0xE6, 0x4E, 0x8E, 0x08, 0x42, 0xBA, 0xCE, 0xCA, 0xBA, 0x6B, 0x31, 0xF5, 0x8C, 0x96, 0xD2, 0x7A, 0x15, 0xF4, 0xDE, 0xAF, 0x85, 0x33, 0x5B, 0xB8, 0x3E, 0xFB, 0x83, 0x39, 0x02, 0x9D, 0xDC, 0xF2, 0xC2, 0xD9, 0x3D, 0x93, 0x57, 0x02, 0xDA, 0x86, 0x65, 0xE4, 0xC0, 0xE1, 0xC3, 0xFD, 0x4F, 0xF0, 0x44, 0x2A, 0xD5, 0xE8, 0x92, 0xD8, 0x96, 0x95, 0x29, 0x37, 0xA2, 0xC2, 0xC7, 0x7C, 0x50, 0x69, 0x8E, 0x13, 0x31, 0x4B, 0xAE, 0x4A, 0x12, 0x25, 0x97, 0x26, 0x7F, 0x8D, 0xCD, 0x92, 0x41, 0x0C, 0x5F, 0x7C, 0xFB, 0x3C, 0xA1, 0x97, 0xA2, 0x85, 0x38, 0xDF, 0x23, 0xAF, 0x8D, 0x92, 0xFD, 0xF1, 0xD7, 0xEC, 0x65, 0xF7, 0xAB, 0x52, 0x8D, 0xEB, 0xD7, 0x69, 0x20, 0x34, 0x68, 0x11, 0x43, 0xE9, 0x42, 0x64, 0x04, 0x58, 0x6C, 0x7B, 0xF1, 0xBD, 0xC0, 0x6A, 0xEC, 0x6F, 0x6D, 0x5B, 0x69, 0x91, 0x7A, 0x0A, 0x02, 0xE6, 0x15, 0xB9, 0xDB, 0x54, 0x6B, 0x6C, 0x7D, 0xB8, 0xFD, 0xA7, 0x2A, 0x70, 0x7F, 0x36, 0x4F, 0x3D, 0x8B, 0x78, 0x85, 0xE4, 0x04, 0x35, 0x35, 0xE1, 0x55, 0x82, 0x3C, 0x12, 0xA4, 0xC6, 0x9D, 0x63, 0xDC, 0x82, 0xAC, 0x85, 0x03, 0x4C, 0x98, 0x41, 0x91, 0x8D, 0xA4, 0x8B, 0xDA, 0xA0, 0x9A, 0x80, 0x29, 0x55, 0x1C, 0xF4, 0x35, 0xD2, 0x2A, 0x07, 0xB0, 0x00, 0x7F, 0xCC, 0x0F, 0x13, 0xC6, 0xFF, 0x1E, 0x19, 0xF9, 0xA9, 0xD6, 0x4B, 0x86, 0xE8, 0xFA, 0xD6, 0x3A, 0xAA, 0xDD, 0xCC, 0xFD, 0x14, 0x08, 0x54, 0x27, 0x43, 0x3F, 0x27, 0xE3, 0x3B, 0x54, 0x30, 0x57, 0xEE, 0x79, 0x98, 0x18, 0x8B, 0xDD, 0x4D, 0xAF, 0x90, 0x47, 0xCC, 0x46, 0x1A, 0x3E, 0xDF, 0x45, 0x3D, 0x2F, 0xD4, 0xCD, 0x99, 0x26, 0xC6, 0x56, 0xB7, 0xC1, 0xB3, 0x8F, 0x5A, 0xEF, 0xC0, 0x11, 0x84, 0x2D, 0x1E, 0x7D, 0xCD, 0x0B, 0xC2, 0x6D, 0xCC, 0xC6, 0x0B, 0x62, 0xEB, 0xEC, 0x8D, 0x0E, 0xD3, 0xAE, 0x69, 0x96, 0x59, 0xA4, 0xEB, 0xA4, 0xAF, 0x7A, 0xF4, 0x4D, 0x96, 0x99, 0x9E, 0xE3, 0x55, 0x46, 0x9D, 0x75, 0x0C, 0x0B, 0xAF, 0xDD, 0xFA, 0x2E, 0xBD, 0xD2, 0x77, 0xF0, 0x2D, 0x3E, 0xBA, 0xB6, 0x8D, 0xA6, 0x52, 0xD3, 0x35, 0x99, 0xB6, 0xEC, 0x02, 0x34, 0x10, 0x37, 0x4B, 0xCD, 0x33, 0x07, 0x06, 0xA7, 0x1B, 0xA6, 0x81, 0x35, 0x06, 0xD6, 0x08, 0x68, 0xA4, 0xC6, 0xFF, 0x7B, 0xA5, 0xA2, 0x36, 0x7E, 0x0E, 0x54, 0x79, 0x64, 0x36, 0x01, 0x2A, 0xD2, 0x27, 0x74, 0xFE, 0x63, 0x82, 0x27, 0x9C, 0x32, 0x39, 0x61, 0xCC, 0xFD, 0x10, 0x87, 0xEF, 0x2B, 0xCC, 0xEB, 0x49, 0xC8, 0x71, 0xCE, 0x3C, 0x6A, 0x73, 0x7F, 0xA5, 0xEA, 0xB5, 0x35, 0x77, 0x3A, 0x60, 0x69, 0x42, 0xFA, 0xA7, 0xF5, 0xE1, 0xE5, 0x88, 0x5D, 0x8F, 0xC1, 0x70, 0xD8, 0xC0, 0x1A, 0x44, 0x93, 0x9E, 0x76, 0x80, 0x06, 0xA1, 0xE0, 0x7C, 0xD4, 0x31, 0x61, 0xB7, 0x55, 0xB0, 0xB9, 0x18, 0x1B, 0x87, 0x08, 0xDD, 0x50, 0x65, 0xD9, 0xE8, 0x81, 0xB2, 0xE7, 0xAE, 0xAE, 0x9F, 0x60, 0xBD, 0x6E, 0xE5, 0x9B, 0x5C, 0x62, 0x7C, 0x55, 0xEB, 0x5D, 0x6B, 0xF3, 0x3C, 0x27, 0xC3, 0xFA, 0xF3, 0x4C, 0xEE, 0xC1, 0xF6, 0xAA, 0x96, 0x93, 0xF3, 0xB5, 0x11, 0x58, 0xCA, 0x91, 0x91, 0x7B, 0xD0, 0x63, 0x02, 0x96, 0xB8, 0x5F, 0x08, 0x2E, 0xBC, 0x6F, 0x3F, 0x09, 0x28, 0x07, 0x49, 0x26, 0xD0, 0xAD, 0x77, 0xBA, 0xA3, 0x62, 0x4C, 0xD5, 0xFC, 0xB2, 0xB8, 0x1A, 0xFC, 0x35, 0xE6, 0x55, 0x2E, 0x4F, 0xF4, 0xA7, 0xEB, 0xE0, 0x02, 0x51, 0x66, 0x16, 0xE9, 0xDB, 0x33, 0x11, 0x80, 0x8C, 0x38, 0xEE, 0xD2, 0x42, 0xBC, 0x62, 0x8F, 0x93, 0x7F, 0xD8, 0x01, 0xC5, 0x54, 0x7D, 0xB2, 0xAE, 0xF9, 0x67, 0xE4, 0x85, 0x85, 0x03, 0x3D, 0xCC, 0x40, 0x71, 0x6D, 0xB4, 0x56, 0x11, 0xCA, 0x2E, 0xDF, 0xCB, 0xAC, 0x20, 0x2D, 0xD7, 0xA4, 0x71, 0xFF, 0xF7, 0xB5, 0xE1, 0x56, 0x18, 0xB0, 0x53, 0x24, 0x63, 0xBC, 0x9C, 0xBD, 0x36, 0x25, 0xE5, 0x9B, 0x43, 0x65, 0x7F, 0x5E, 0x97, 0x5B, 0x07, 0x32, 0x4A, 0x86, 0x21, 0x68, 0xCF, 0x26, 0x83, 0xC6, 0x75, 0x33, 0x91, 0xE6, 0xC0, 0xF9, 0xC0, 0xEA, 0xD9, 0x37, 0x32, 0x08, 0x44, 0xBE, 0xF4, 0xF6, 0xDE, 0xC9, 0x6F, 0x73, 0x6C, 0x3E, 0xDE, 0x48, 0x66, 0x60, 0xE5, 0x46, 0xF8, 0xF9, 0xBD, 0xBD, 0xB8, 0x85, 0x34, 0x3C, 0x46, 0xC7, 0x29, 0xFA, 0x8D, 0x9A, 0x4D, 0x8B, 0xE2, 0x2C, 0xC0, 0x5D, 0xDE, 0x83, 0xF8, 0xC1, 0x87, 0xC6, 0xF6, 0xC5, 0xE5, 0xB8, 0x5B, 0x1D, 0x0B, 0xB7, 0xEB, 0x2C, 0xB1, 0xAD, 0x93, 0xB9, 0xEF, 0xC9, 0x26, 0xAE, 0xDB, 0xF8, 0x8A, 0x8F, 0x6E, 0x42, 0x1D, 0x41, 0xAD, 0x9A, 0x1F, 0x57, 0x5D, 0x08, 0xE7, 0x1A, 0x07, 0xFF, 0x54, 0xFE, 0x6B, 0xCC, 0xDA, 0xDA, 0xCA, 0xE3, 0x62, 0x95, 0x88, 0xF6, 0xAC, 0xEE, 0xCF, 0x99, 0x27, 0xE0, 0xC8, 0xA8, 0xE3, 0x50, 0xFB, 0x2B, 0xF0, 0x71, 0xBF, 0x62, 0xC6, 0x76, 0xEC, 0xA8, 0x00, 0xC6, 0xAC, 0x69, 0x00, 0xF0, 0x10, 0xCC, 0x17, 0x10, 0xCD, 0x43, 0x7A, 0x11, 0xC9, 0x93, 0xB9, 0x3F, 0xD9, 0xCE, 0x9A, 0x7C, 0xB5, 0x63, 0x13, 0x4F, 0x8C, 0xF0, 0x7A, 0x88, 0x2A, 0xC1, 0x20, 0x92, 0xFC, 0x45, 0x71, 0x5F, 0x74, 0xEF, 0x9C, 0xBA, 0x1F, 0x52, 0xD3, 0x5E, 0x3E, 0xA4, 0x48, 0x78, 0xC4, 0x56, 0x35, 0xEF, 0xA3, 0xD7, 0xFA, 0xB5, 0xED, 0xE9, 0x74, 0xFB, 0xFA, 0xF4, 0x36, 0x61, 0x93, 0x3A, 0x01, 0x40, 0xCF, 0xA5, 0x87, 0x1A, 0xEB, 0x27, 0xD7, 0x5D, 0x05, 0x07, 0xFF, 0xD4, 0x41, 0x09, 0x3D, 0x9F, 0x71, 0x32, 0x49, 0x73, 0x90, 0x64, 0x6E, 0x67, 0xDA, 0x55, 0x6C, 0xD7, 0x9C, 0xAB, 0x31, 0xC1, 0x6B, 0x86, 0x9B, 0x14, 0xAF, 0x9F, 0xD9, 0xF6, 0x0E, 0xB7, 0x71, 0x73, 0x96, 0x28, 0x0D, 0x98, 0x52, 0x68, 0x18, 0x51, 0xE2, 0x7B, 0x88, 0xD4, 0x46, 0xF6, 0x05, 0x7C, 0x04, 0x1F, 0x1B, 0xAB, 0xD7, 0x5F, 0xDE, 0xCA, 0x14, 0x51, 0x91, 0x61, 0x4E, 0x9B, 0xCD, 0x98, 0x52, 0xE2, 0xF2, 0x7B, 0x5C, 0xAF, 0x0B, 0x7D, 0x85, 0x1B, 0x8B, 0x75, 0xFF, 0xB4, 0x24, 0x40, 0x22, 0x0C, 0xD4, 0x91, 0xCE, 0x8C, 0x9E, 0xFE, 0xA8, 0x36, 0x5B, 0xA7, 0xCF, 0x05, 0x05, 0xD2, 0x07, 0xA8, 0xD9, 0x35, 0x67, 0x52, 0x95, 0xBC, 0x82, 0x55, 0xDB, 0xB8, 0x22, 0xD0, 0xCB, 0x29, 0x7D, 0x36, 0xEB, 0x50, 0xE8, 0x33, 0x07, 0x66, 0xF3, 0x53, 0x83, 0xAE, 0x91, 0xF5, 0x79, 0x7D, 0x70, 0x2A, 0x1D, 0x45, 0x16, 0xDE, 0x66, 0x35, 0x92, 0x7A, 0xEC, 0x0F, 0x66, 0xA1, 0xC1, 0x0B, 0x1C, 0xDB, 0xF8, 0x23, 0x89, 0xDA, 0xE9, 0xAD, 0x73, 0x4D, 0x53, 0x2C, 0x83, 0x2C, 0xA6, 0xDB, 0xAF, 0x4B, 0xD0, 0x57, 0xDB, 0x6A, 0x92, 0xE2, 0x8D, 0x41, 0x11, 0x35, 0xA2, 0x92, 0x50, 0x80, 0xE9, 0x2F, 0x8F, 0x2C, 0xD1, 0xEC, 0xD7, 0x00, 0xFB, 0xF4, 0xE2, 0x4F, 0x00, 0xAE, 0xA8, 0xBF, 0x37, 0x15, 0xE7, 0xE0, 0x43, 0xD1, 0x43, 0x0F, 0xDC, 0x8F, 0x08, 0x61, 0x63, 0x8A, 0x91, 0xA0, 0xA1, 0x4A, 0xDB, 0x38, 0x7A, 0x07, 0x9F, 0x78, 0xBA, 0x85, 0x25, 0x77, 0x1A, 0x54, 0x97, 0x7D, 0x35, 0x7F, 0x4C, 0x98, 0x90, 0xE5, 0xAE, 0xD7, 0xB4, 0x88, 0xE9, 0x3D, 0x55, 0x6B, 0x1B, 0x12, 0x12, 0xA1, 0x81, 0xBC, 0x0B, 0xFC, 0x47, 0xEA, 0x47, 0x2B, 0x02, 0x9A, 0xF5, 0x54, 0x2A, 0x2C, 0x87, 0x7D, 0xA2, 0x84, 0x6B, 0x60, 0x5D, 0x40, 0x6B, 0x3A, 0xF6, 0xE9, 0xDD, 0x9C, 0xE5, 0xC1, 0x80, 0x13, 0xE1, 0x52, 0xE6, 0x54, 0xBF, 0x31, 0x0E, 0xE9, 0x81, 0xAD, 0x99, 0x1F, 0x4A, 0xDD, 0x6E, 0xFB, 0xC1, 0x68, 0x82, 0x8A, 0x17, 0x64, 0xB1, 0x80, 0xE4, 0x1F, 0x77, 0xFD, 0xE5, 0xF8, 0x29, 0x7D, 0x76, 0xEB, 0xD5, 0xC1, 0xBE, 0x90, 0x3C, 0xA6, 0xF6, 0x7C, 0x3A, 0xD4, 0xF4, 0x8B, 0xC8, 0x25, 0xF5, 0x9E, 0x22, 0x8C, 0xBC, 0xAA, 0x8F, 0xC8, 0xEA, 0x24, 0x6C, 0xB8, 0x1A, 0xC5, 0x08, 0xBD, 0x99, 0x3E, 0x2B, 0x3E, 0xC0, 0xAE, 0xF7, 0x88, 0x0B, 0x68, 0xE6, 0xB9, 0xC9, 0x2D, 0x6A, 0x86, 0x39, 0x09, 0xF1, 0x48, 0x79, 0x02, 0x03, 0x37, 0x21, 0xB4, 0xE2, 0x5E, 0xF8, 0x90, 0x99, 0xE5, 0x37, 0x6B, 0xE2, 0x0A, 0x98, 0x6E, 0x15, 0x28, 0xD8, 0xF0, 0xC1, 0x1E, 0xC4, 0xF3, 0x9D, 0x42, 0xA4, 0x56, 0xE8, 0x74, 0x1E, 0x2B, 0x00, 0x02, 0xFA, 0xC3, 0x67, 0xAC, 0x9D, 0xC0, 0xE5, 0x52, 0x4C, 0xBC, 0x43, 0x6F, 0xE6, 0x22, 0x62, 0xCB, 0x46, 0x34, 0xAA, 0x3E, 0xC7, 0x3A, 0xF8, 0xC4, 0x88, 0x95, 0x90, 0xBF, 0x48, 0xDF, 0x21, 0xE4, 0x2B, 0x14, 0x02, 0x1A, 0x41, 0xA3, 0xCC, 0x11, 0xEE, 0xBC, 0x91, 0xBA, 0x2F, 0xFB, 0xB5, 0xEE, 0x3C, 0x24, 0x0D, 0xB2, 0xA0, 0xE7, 0x04, 0x58, 0x85, 0x73, 0x6F, 0xDA, 0x1B, 0x1F, 0x7A, 0x02, 0x7C, 0x67, 0x2E, 0x12, 0x4D, 0x1E, 0x6F, 0x89, 0x39, 0xDE, 0x75, 0xC0, 0xD0, 0x97, 0x37, 0x11, 0xDD, 0xBC, 0x93, 0x90, 0xE1, 0xC8, 0x5B, 0x4A, 0x22, 0xCB, 0xE0, 0x03, 0x74, 0xBA, 0xB4, 0xE4, 0xDF, 0xA5, 0xAA, 0x37, 0x26, 0x75, 0x6B, 0xDD, 0x00, 0xFF, 0x42, 0x9E, 0x4F, 0xB8, 0x0D, 0x77, 0x4E, 0xB2, 0xC6, 0x4B, 0xC6, 0x6E, 0x04, 0x2E, 0xC3, 0x62, 0x1A, 0xDB, 0x4C, 0xE2, 0x00, 0xBF, 0x88, 0x5B, 0x7B, 0x75, 0x6F, 0x25, 0x0E, 0x73, 0x32, 0x3A, 0xB5, 0x17, 0x5E, 0x83, 0xA7, 0xB7, 0x31, 0xD5, 0xAE, 0x85, 0xB5, 0xC9, 0x8E, 0xC2, 0xF7, 0x0D, 0x30, 0x26, 0x47, 0x9E, 0x0B, 0x68, 0xEA, 0x67, 0xF5, 0xB8, 0xFF, 0x1D, 0xFB, 0x63, 0xE9, 0x40, 0xB7, 0x86, 0xD9, 0x3E, 0x35, 0x1F, 0x8C, 0xDC, 0x94, 0x79, 0x19, 0x6A, 0xA8, 0xD7, 0x84, 0x26, 0xAB, 0x0E, 0x65, 0x03, 0x19, 0x90, 0xD0, 0xFE, 0xF6, 0xF6, 0x41, 0xFF, 0xE6, 0x87, 0x7F, 0x31, 0x0D, 0xD4, 0xFA, 0x50, 0xD4, 0xB4, 0x18, 0xB4, 0x96, 0x36, 0x2F, 0x30, 0xED, 0x54, 0x7B, 0xBD, 0x70, 0x1C, 0x67, 0xB4, 0xB7, 0x6A, 0xBA, 0x94, 0xAD, 0x52, 0x9E, 0xF3, 0x72, 0x38, 0xA1, 0x3D, 0xB9, 0x1D, 0xBC, 0x97, 0xDA, 0xD3, 0x40, 0x6D, 0x3B, 0xB4, 0x33, 0x0F, 0xA5, 0xE4, 0x6F, 0x19, 0x37, 0xF3, 0xFE, 0x70, 0xEB, 0xB1, 0x6A, 0x7D, 0x53, 0x28, 0x93, 0x22, 0x13, 0xBE, 0x26, 0xE3, 0x06, 0x0F, 0x5D, 0x6D, 0xA2, 0xB7, 0x23, 0x60, 0xC3, 0x6C, 0x1A, 0x06, 0xC3, 0x85, 0x67, 0x48, 0xE3, 0x04, 0xC4, 0xAC, 0x1F, 0xA6, 0x01, 0xBA, 0xB9, 0xD7, 0x5A, 0x18, 0x02, 0x62, 0x63, 0xB0, 0xCE, 0x54, 0xEF, 0xA3, 0x10, 0xF6, 0x65, 0xE9, 0xC0, 0xB0, 0xF5, 0x8D, 0xE2, 0x60, 0xBF, 0x20, 0xC9, 0x82, 0xCC, 0x67, 0xFC, 0x45, 0xF5, 0x9F, 0x88, 0x1E, 0x1F, 0xE2, 0xF1, 0x01, 0x9D, 0x6F, 0xC0, 0xE7, 0x3B, 0x7B, 0x6B, 0x31, 0xA3, 0xFB, 0x1A, 0x99, 0x10, 0x5E, 0x2F, 0xF7, 0xDC, 0x97, 0x91, 0xE9, 0xA3, 0xB9, 0x72, 0xDA, 0xC1, 0xE8, 0x58, 0x94, 0xDE, 0x9D, 0xEC, 0x2B, 0x76, 0xEB, 0xF2, 0xEC, 0xD9, 0x0D, 0x22, 0x9D, 0xA4, 0xB1, 0x80, 0x3F, 0x67, 0xDC, 0x36, 0x34, 0x73, 0x7A, 0x03, 0xA3, 0x58, 0x8B, 0xFC, 0x03, 0x5C, 0x85, 0x0D, 0x22, 0x97, 0x78, 0xB5, 0xC1, 0x57, 0x36, 0x2C, 0x6B, 0x8A, 0xAA, 0xD4, 0x6B, 0x49, 0xD5, 0xF0, 0xB6, 0x53, 0xC8, 0x9B, 0xFE, 0x01, 0xFA, 0xF3, 0x38, 0x55, 0xFC, 0xA3, 0xD3, 0x8B, 0x00, 0x98, 0xA7, 0x66, 0x81, 0xCF, 0x99, 0x51, 0xC4, 0x3E, 0x6C, 0xEC, 0x60, 0x93, 0x82, 0x1E, 0x38, 0xB0, 0x64, 0x14, 0x07, 0x8A, 0xB9, 0x5F, 0x83, 0xED, 0x8B, 0x1F, 0x1A, 0xDB, 0x90, 0xDF, 0xEE, 0x9E, 0x52, 0xA8, 0x56, 0xB9, 0x71, 0xE6, 0xE4, 0x34, 0x72, 0x71, 0x5A, 0xA6, 0xA5, 0x8C, 0x11, 0x20, 0x45, 0x1A, 0xBC, 0x52, 0xBB, 0x65, 0x44, 0xD3, 0x86, 0x9F, 0x5F, 0x4A, 0x18, 0x09, 0x1D, 0xF1, 0xCC, 0x2C, 0x02, 0x1F, 0xBE, 0x0A, 0x80, 0x8B, 0xE8, 0x6E, 0x70, 0x6C, 0x32, 0x69, 0x1E, 0xBD, 0x0E, 0xFD, 0x32, 0x2E, 0x5A, 0x29, 0xE0, 0xA1, 0x79, 0xB2, 0x77, 0xAD, 0xAA, 0xC5, 0x50, 0x60, 0x35, 0xD4, 0xD2, 0x3C, 0x31, 0x66, 0xD8, 0x69, 0x27, 0x1A, 0xAD, 0x66, 0x4A, 0xCA, 0x50, 0xEB, 0x62, 0x2E, 0x8D, 0x8A, 0x2D, 0x09, 0xA3, 0x47, 0x72, 0x00, 0x80, 0x0E, 0xF8, 0xDF, 0xDC, 0x01, 0xC3, 0x06, 0x2F, 0xC9, 0x8E, 0x53, 0x9F, 0x4F, 0x6F, 0xE1, 0x59, 0x4E, 0x92, 0xA2, 0xCF, 0x66, 0xD2, 0x84, 0x97, 0xC1, 0xB4, 0xDD, 0xF5, 0x4A, 0x32, 0x40, 0xC4, 0x06, 0x88, 0xA3, 0xFF, 0x30, 0xBB, 0x10, 0xFD, 0x97, 0x82, 0xE9, 0xD1, 0x96, 0x6B, 0xD2, 0x2A, 0x23, 0xEA, 0x12, 0xB3, 0xFE, 0xD0, 0xE1, 0xD3, 0x2F, 0x61, 0xEE, 0xFA, 0xEA, 0x7B, 0xB5, 0xEF, 0xBE, 0xE4, 0x10, 0xA8, 0x7A, 0xB0, 0x79, 0x16, 0x1B, 0x2A, 0xF6, 0xD8, 0x16, 0x47, 0x0E, 0xB8, 0x50, 0xF7, 0x24, 0x70, 0x54, 0xE0, 0xED, 0xB1, 0xD6, 0x56, 0x4D, 0x15, 0xA2, 0x3B, 0xC2, 0xDF, 0x89, 0x6B, 0xEB, 0x07, 0xDE, 0xE2, 0xE0, 0x2E, 0xC6, 0xC2, 0x4F, 0x12, 0xEE, 0x96, 0x95, 0x75, 0xCA, 0xF3, 0xDD, 0x72, 0x23, 0x52, 0xC9, 0x81, 0x46, 0x4A, 0x9F, 0x5D, 0xED, 0x7E, 0xF3, 0x71, 0x16, 0x1A, 0x8A, 0x62, 0x0C, 0xB4, 0x29, 0xDE, 0x55, 0x48, 0xE5, 0xC0, 0xE3, 0xBC, 0x2C, 0x3D, 0xBA, 0xB7, 0x93, 0x28, 0xD5, 0xFA, 0x70, 0xA4, 0xF6, 0x99, 0xE5, 0x4D, 0x3C, 0x22, 0x4C, 0xF3, 0xCB, 0xA4, 0x1E, 0x7D, 0xE7, 0xE3, 0xAF, 0xC3, 0x20, 0xDE, 0xCA, 0x7C, 0x36, 0x2F, 0xAC, 0x7C, 0xC9, 0x26, 0x78, 0x46, 0x4D, 0x41, 0x3D, 0xD4, 0x22, 0x9E, 0x76, 0xAA, 0x90, 0x93, 0x80, 0x9C, 0x0F, 0x5E, 0xDE, 0x53, 0x0A, 0xCB, 0xFE, 0xCF, 0x08, 0x2B, 0xC5, 0xD2, 0x18, 0xD0, 0xB8, 0xF3, 0xF1, 0x76, 0x89, 0x7A, 0xCF, 0xF3, 0x59, 0xF1, 0xA6, 0xA8, 0x06, 0xB7, 0xA8, 0x66, 0x9C, 0x72, 0xC2, 0x26, 0xF2, 0xB8, 0x45, 0x2E, 0xC8, 0xD3, 0x5F, 0xA6, 0x6B, 0xFE, 0x93, 0x63, 0xAE, 0x9E, 0x84, 0x42, 0xD1, 0x85, 0x50, 0x80, 0x1B, 0x00, 0x62, 0x24, 0x68, 0x57, 0x3C, 0xAD, 0x37, 0xBD, 0x18, 0x99, 0xC2, 0xAB, 0x37, 0x5F, 0x98, 0xB0, 0xEF, 0x9C, 0x51, 0x84, 0xD4, 0x0F, 0x23, 0x93, 0x05, 0x4E, 0xCE, 0x1E, 0xAB, 0x24, 0xDE, 0x05, 0x22, 0xFE, 0x0F, 0xDF, 0xF7, 0x01, 0x6E, 0xAF, 0x4F, 0x88, 0xBB, 0x28, 0xF3, 0x64, 0xAE, 0x4A, 0xD3, 0xDA, 0x4B, 0x70, 0xAC, 0x0E, 0x47, 0xD2, 0xB6, 0x7B, 0x9A, 0x60, 0x37, 0x68, 0x61, 0xC6, 0x7C, 0x6B, 0x85, 0x74, 0xCC, 0x07, 0x83, 0x88, 0x92, 0xC3, 0xC8, 0x55, 0x68, 0x0A, 0xF6, 0x97, 0x18, 0x9C, 0xFF, 0xD3, 0x7C, 0xA8, 0x3A, 0x33, 0x71, 0x0F, 0x7A, 0xE9, 0xB0, 0xA8, 0x57, 0x95, 0xFC, 0x6E, 0x4A, 0x57, 0x79, 0x1D, 0x93, 0x2D, 0xD1, 0x10, 0x8B, 0x90, 0x86, 0xBB, 0x3E, 0x29, 0x65, 0x24, 0xE2, 0x91, 0x07, 0xE3, 0x35, 0x4B, 0x4C, 0x40, 0xAD, 0xDB, 0x8C, 0x16, 0x5D, 0xBB, 0xA9, 0x50, 0xFD, 0xCC, 0x0B, 0x3D, 0x92, 0x88, 0x83, 0x9D, 0x9B, 0xA6, 0x35, 0x37, 0x23, 0x17, 0x73, 0xC6, 0x61, 0xDA, 0xD4, 0x0C, 0xC3, 0xA5, 0xD7, 0xAB, 0x1C, 0x59, 0x43, 0xEA, 0xB0, 0x3C, 0x81, 0xFB, 0x39, 0xB5, 0xA6, 0x7B, 0x04, 0xD3, 0x34, 0x82, 0x88, 0x55, 0x6A, 0xB8, 0xDA, 0xD4, 0x5E, 0x1D, 0xFF, 0x68, 0x6C, 0x07, 0x12, 0x83, 0x5D, 0xB6, 0x16, 0x6B, 0x2A, 0xDD, 0xA6, 0x2D, 0x95, 0x08, 0x66, 0xCC, 0xE4, 0x9E, 0xD3, 0x71, 0xE8, 0x76, 0x8C, 0x8E, 0x6E, 0x49, 0xB9, 0x00, 0x0E, 0xA2, 0x93, 0xBD, 0x56, 0x96, 0x87, 0x8F, 0x8C, 0xB1, 0x7C, 0xF8, 0x79, 0xA8, 0x89, 0x7E, 0xD9, 0xDE, 0xD7, 0x74, 0x26, 0x3A, 0x83, 0x0E, 0x4D, 0xEE, 0x2E, 0xD7, 0x52, 0x0B, 0x4C, 0x59, 0xFF, 0x69, 0x71, 0x1F, 0xB3, 0x5F, 0x67, 0x0D, 0x48, 0x77, 0xC7, 0xD3, 0x12, 0x24, 0xA3, 0xAD, 0xD1, 0x43, 0xAA, 0xB9, 0x65, 0x30, 0xB1, 0x80, 0xE5, 0xFB, 0x5E, 0xC9, 0xD8, 0x3F, 0x57, 0x1A, 0xB7, 0x94, 0x77, 0xAD, 0xEA, 0x40, 0x9C, 0x2B, 0xA9, 0x86, 0xC7, 0xA0, 0x54, 0xE6, 0x14, 0x8F, 0x03, 0x7D, 0xB9, 0x71, 0x07, 0x92, 0xF6, 0x12, 0x15, 0xA3, 0xFD, 0xF1, 0x28, 0xFF, 0xA7, 0x15, 0x4F, 0xB0, 0x1C, 0xF4, 0xEF, 0x18, 0xFB, 0xC2, 0xA2, 0x03, 0xBD, 0x37, 0x6D, 0x68, 0x6C, 0x36, 0x70, 0x6F, 0x13, 0x2E, 0x20, 0x81, 0xB9, 0x10, 0xFD, 0x15, 0x46, 0x0C, 0x5A, 0x05, 0x09, 0x9C, 0x84, 0x23, 0x6F, 0x98, 0x2F, 0xBE, 0xBC, 0x62, 0x51, 0xEB, 0x07, 0x68, 0x88, 0xF9, 0x64, 0xE5, 0x79, 0x94, 0x42, 0x16, 0x0D, 0xA2, 0x60, 0x80, 0x29, 0xD6, 0x1B, 0xE9, 0xAD, 0x99, 0xB4, 0x5B, 0x7B, 0xEC, 0x36, 0xD7, 0xFA, 0x12, 0xBA, 0x3F, 0x50, 0x28, 0xFD, 0x5B, 0x90, 0xE4, 0x26, 0xB9, 0x04, 0x88, 0x49, 0x92, 0x18, 0x27, 0x9E, 0xCB, 0xDC, 0x33, 0xF1, 0xE7, 0x17, 0xBD, 0x44, 0x0F, 0x5C, 0x85, 0x80, 0x8D, 0x72, 0x91, 0xF6, 0x36, 0xE8, 0xF5, 0xDE, 0xA6, 0xEA, 0x59, 0x18, 0x6F, 0xFC, 0x6C, 0xF8, 0x59, 0x2A, 0x09, 0x72, 0x46, 0x34, 0xA3, 0x01, 0x8C, 0xA8, 0xE5, 0x52, 0x5E, 0x3E, 0xC7, 0xAE, 0x6F, 0x01, 0x5E, 0x28, 0x7E, 0xA0, 0x6A, 0x6F, 0x19, 0x3E, 0xB6, 0x50, 0xEC, 0x00, 0x95, 0xAF, 0x8F, 0x43, 0xFE, 0x12, 0x2A, 0xC3, 0xF4, 0x7D, 0xEC, 0xDB, 0x72, 0xDD, 0x4F, 0x68, 0x69, 0x86, 0x64, 0x5D, 0x61, 0xD9, 0x7D, 0xD6, 0x97, 0x64, 0x9F, 0x1E, 0x7B, 0xE0, 0x17, 0x30, 0xD1, 0xBD, 0xBD, 0xF7, 0x62, 0x71, 0x40, 0xDC, 0x0E, 0x18, 0xE6, 0xB3, 0x55, 0x7B, 0xA3, 0x67, 0xF0, 0x90, 0xFB, 0xD7, 0xC5, 0x47, 0x5E, 0xD3, 0xFA, 0x05, 0x5B, 0x32, 0x5D, 0x4B, 0x61, 0x35, 0x9F, 0x45, 0xBC, 0xFE, 0xF1, 0xA6, 0x06, 0xC7, 0x2E, 0xF3, 0x62, 0x62, 0xA0, 0x45, 0x51, 0xBC, 0x8C, 0x24, 0xFA, 0xB3, 0x53, 0x21, 0xFC, 0xE8, 0xBC, 0xE5, 0x56, 0x06, 0x27, 0x9A, 0x29, 0x15, 0x69, 0x76, 0xFB, 0x45, 0xEE, 0x76, 0x1D, 0x92, 0x50, 0x14, 0xCB, 0x69, 0x1F, 0xF7, 0x6B, 0x5F, 0xEF, 0xE1, 0xB8, 0x39, 0x5B, 0x81, 0x10, 0x6A, 0x24, 0x5C, 0x93, 0x0E, 0x2D, 0x99, 0x54, 0xF1, 0xCC, 0x5A, 0x3A, 0xAA, 0x2C, 0x9C, 0xD5, 0x62, 0xA7, 0xB5, 0xC7, 0x4D, 0x84, 0xC0, 0xC2, 0xFE, 0xE6, 0x2E, 0x0E, 0xDB, 0xE1, 0xE8, 0xFB, 0x96, 0x90, 0xA2, 0xF4, 0x0B, 0x8D, 0xFD, 0xE1, 0x34, 0xC8, 0xBE, 0xDA, 0x37, 0x0A, 0x7B, 0x17, 0x0D, 0xAA, 0xBC, 0xA6, 0xB9, 0xFE, 0x48, 0x9E, 0xF4, 0xEA, 0x66, 0x29, 0xF0, 0x3E, 0x5E, 0x44, 0x30, 0xC2, 0xFA, 0x57, 0x31, 0xEB, 0xC7, 0x47, 0x6A, 0xE6, 0x3F, 0xF8, 0x9B, 0x39, 0x49, 0xC9, 0x93, 0x71, 0x77, 0xD3, 0x63, 0x1E, 0x14, 0xC1, 0x26, 0x57, 0x9F, 0x79, 0x74, 0xD9, 0x6C, 0x37, 0xCD, 0x73, 0x0A, 0x09, 0x8D, 0xFE, 0xCB, 0x6A, 0xFC, 0x86, 0x41, 0x65, 0x66, 0x8F, 0x03, 0xD5, 0x12, 0xA4, 0xCA, 0xDC, 0x49, 0xA4, 0xEB, 0xEE, 0x2E, 0x1A, 0x26, 0x7E, 0xE2, 0xE2, 0xA7, 0x6B, 0xBB, 0x2C, 0x77, 0x6A, 0x44, 0x87, 0xBC, 0xC0, 0xFC, 0x00, 0xAF, 0xD7, 0xC1, 0x81, 0x7F, 0x7E, 0x89, 0x00, 0x26, 0xD5, 0xD4, 0x25, 0x4C, 0x9C, 0xCC, 0xBA, 0x2B, 0xB3, 0x01, 0xBA, 0x57, 0xCE, 0x7C, 0xD4, 0x7A, 0xE1, 0x8D, 0x65, 0x3F, 0x9A, 0x92, 0x05, 0x3A, 0xF9, 0x0B, 0xEE, 0xC3, 0xA8, 0x29, 0xB8, 0x52, 0xC2, 0x3D, 0x0D, 0xF7, 0x52, 0x07, 0x70, 0x1E, 0x67, 0x49, 0x74, 0xED, 0x56, 0x2F, 0xF5, 0x9A, 0x81, 0x1B, 0xB8, 0x5C, 0xCF, 0x62, 0x13, 0x64, 0xCD, 0x9F, 0x87, 0xC9, 0xE7, 0x8B, 0x9D, 0x2F, 0x2E, 0xB2, 0x6F, 0x00, 0x41, 0xAF, 0x1A, 0x47, 0xA4, 0x37, 0xC4, 0x0C, 0x02, 0x93, 0x9B, 0x62, 0xC8, 0x90, 0x52, 0x13, 0x5A, 0x06, 0x63, 0x2E, 0x43, 0xDE, 0x35, 0x34, 0x8E, 0xEA, 0x91, 0x75, 0x03, 0x47, 0xB8, 0x6A, 0xC2, 0xFA, 0xB5, 0x55, 0x53, 0x24, 0x9F, 0xC2, 0x5D, 0x2B, 0x57, 0x49, 0x69, 0x92, 0x91, 0x38, 0xA4, 0x83, 0x71, 0xDC, 0x74, 0x6E, 0xAC, 0x5F, 0xA1, 0x08, 0xE2, 0x6C, 0xBC, 0xC5, 0xB6, }, .t1_len = 2304, .t1 = { 0x1B, 0xEA, 0x94, 0x79, 0x6B, 0xBA, 0xD0, 0x5D, 0xA6, 0xD7, 0xD2, 0x58, 0x1A, 0x10, 0xE9, 0x7C, 0xF1, 0xF8, 0x9D, 0x66, 0xED, 0x7A, 0x7A, 0xE2, 0x3B, 0xBE, 0xB6, 0x8B, 0x87, 0xF5, 0x1E, 0xE2, 0x69, 0xDA, 0x47, 0x6D, 0x3F, 0xCA, 0x1C, 0xA5, 0x4D, 0x27, 0x26, 0x72, 0xB3, 0x7A, 0x61, 0x11, 0x25, 0x5E, 0x37, 0xA6, 0xF7, 0x71, 0x9B, 0xC2, 0xDD, 0x38, 0x97, 0xC2, 0xA7, 0x74, 0x89, 0x4C, 0x4B, 0xD8, 0xE6, 0xF5, 0xE7, 0xE1, 0x10, 0xA6, 0xDF, 0x0E, 0x58, 0x44, 0x20, 0x8D, 0x94, 0x11, 0x53, 0xCC, 0xDD, 0x77, 0xA3, 0x4B, 0xBC, 0x37, 0x26, 0xA0, 0x87, 0x85, 0xD7, 0x28, 0x02, 0xE2, 0xF1, 0x52, 0xB3, 0x30, 0x67, 0x89, 0xB1, 0xEA, 0x50, 0x2D, 0x42, 0x22, 0x71, 0x24, 0x9A, 0xC5, 0x57, 0x11, 0x39, 0xE1, 0x7F, 0x62, 0x9A, 0xF3, 0x5C, 0x9D, 0x7F, 0x43, 0x49, 0x1D, 0x83, 0xCC, 0x01, 0x07, 0x7C, 0x58, 0x84, 0xC6, 0x2A, 0x1A, 0x87, 0xE7, 0x5E, 0x68, 0x48, 0xE6, 0xD1, 0x2D, 0xC1, 0x3A, 0xE8, 0x43, 0x1A, 0x93, 0xAB, 0xCA, 0xB7, 0x9E, 0x05, 0x2E, 0xFC, 0xAE, 0x5E, 0x02, 0xF4, 0x49, 0xE8, 0x11, 0x8E, 0x6D, 0x9F, 0x36, 0x9F, 0xDD, 0x0A, 0x59, 0x33, 0x37, 0xE4, 0xC0, 0xC7, 0x50, 0xFE, 0x4A, 0x4F, 0xAE, 0x5F, 0x83, 0xC0, 0x17, 0x93, 0xBF, 0xD7, 0x6E, 0xA0, 0x81, 0x77, 0xBC, 0xA3, 0x78, 0x71, 0xD9, 0x14, 0x51, 0xC5, 0xA8, 0x19, 0x5A, 0xBB, 0x3C, 0x5B, 0x46, 0xCC, 0x66, 0x08, 0xBE, 0xD7, 0x7E, 0x92, 0x3C, 0xE1, 0x51, 0x64, 0x25, 0x06, 0x54, 0x16, 0x95, 0xA4, 0xE2, 0x96, 0xCB, 0xC6, 0x4D, 0x3B, 0x32, 0x3F, 0x77, 0xBE, 0x7B, 0x72, 0x4C, 0xC4, 0x38, 0xF0, 0xF7, 0xB6, 0xAC, 0xA6, 0xE1, 0xC9, 0x90, 0x8A, 0xA0, 0x86, 0xF3, 0x0B, 0x3D, 0x3C, 0x0C, 0x1D, 0xB6, 0x44, 0x90, 0x37, 0xB4, 0x9D, 0x10, 0x67, 0x40, 0xC9, 0xDB, 0x8D, 0x99, 0xC5, 0x7B, 0x49, 0xA7, 0xBC, 0x14, 0xB1, 0x71, 0x07, 0x35, 0xAF, 0x96, 0x1B, 0x77, 0x60, 0xA8, 0x2D, 0xFB, 0xB1, 0xD8, 0x9C, 0x72, 0xD7, 0x09, 0x4F, 0xC8, 0x95, 0x1B, 0xB0, 0xE9, 0x83, 0x97, 0xD3, 0x25, 0xBF, 0x12, 0x00, 0x1B, 0x04, 0xAC, 0xC6, 0x64, 0x79, 0x28, 0x2C, 0x30, 0x57, 0x47, 0x6D, 0xA0, 0x5A, 0x3B, 0x76, 0xD7, 0x59, 0x2F, 0xBE, 0xF9, 0xDA, 0x06, 0x0E, 0xBA, 0xF4, 0xF7, 0x33, 0xAE, 0x63, 0x63, 0x76, 0xB7, 0x60, 0x5D, 0x9B, 0xBE, 0x60, 0x52, 0x2E, 0x3E, 0xF0, 0xE8, 0x6A, 0x83, 0x4F, 0x36, 0xA0, 0xCE, 0xC9, 0x6F, 0xBB, 0x4A, 0x8B, 0xF3, 0x1E, 0xAC, 0x2D, 0x5A, 0x52, 0x3B, 0xF4, 0x84, 0x5D, 0xB6, 0xD4, 0xD8, 0x7C, 0x3D, 0x50, 0xC9, 0xE0, 0x27, 0x52, 0xB6, 0x4F, 0x42, 0x06, 0x2F, 0x62, 0x5A, 0x19, 0x12, 0x53, 0xFA, 0x7A, 0xA4, 0xA3, 0x6E, 0xED, 0x8E, 0xE9, 0xD9, 0x86, 0xFA, 0x86, 0xC1, 0x3B, 0xB3, 0xF1, 0x7D, 0x64, 0x1B, 0x8B, 0x26, 0x7F, 0x01, 0x36, 0x9A, 0xD1, 0x27, 0x0D, 0xD5, 0x41, 0x3C, 0x94, 0xEF, 0x0B, 0x77, 0x2D, 0x28, 0x9E, 0x7A, 0xCD, 0xAF, 0x20, 0x75, 0x57, 0x6C, 0xF2, 0x15, 0x7B, 0x5C, 0xFA, 0x48, 0x79, 0x68, 0x66, 0x15, 0xFA, 0xBA, 0xF3, 0x85, 0x74, 0x35, 0x87, 0x41, 0xB9, 0x02, 0xE1, 0x82, 0x7A, 0xC7, 0x1B, 0x9A, 0xED, 0x0B, 0xBC, 0xEE, 0x5F, 0x85, 0x43, 0xD4, 0x5A, 0xB9, 0xCF, 0x4F, 0xF9, 0xA9, 0x5A, 0x5B, 0xF2, 0x86, 0x9A, 0x64, 0xBC, 0x68, 0x10, 0xB7, 0x57, 0x46, 0x15, 0x4A, 0x4D, 0xA6, 0x49, 0xD6, 0x9B, 0x3E, 0xA9, 0x53, 0xFF, 0xC9, 0x4F, 0xD2, 0x01, 0x27, 0x22, 0xF9, 0x33, 0x4B, 0x8F, 0xCD, 0x4C, 0x12, 0x65, 0xEA, 0x60, 0x8B, 0xF5, 0x5B, 0x57, 0xAB, 0x08, 0xBE, 0x22, 0x53, 0xE1, 0x57, 0x40, 0x81, 0xC3, 0xC4, 0xD2, 0xB7, 0x41, 0xC8, 0x80, 0x3E, 0x88, 0x8D, 0xEC, 0x54, 0x85, 0x2B, 0xEF, 0xE9, 0x35, 0x2C, 0x4C, 0x97, 0xC7, 0x6A, 0xFF, 0xC3, 0x64, 0x98, 0x57, 0x8F, 0xCE, 0x72, 0xE5, 0x82, 0x6A, 0xB4, 0xFC, 0x52, 0xFC, 0x26, 0xF1, 0x1C, 0xF1, 0x23, 0x69, 0xCE, 0xD7, 0x04, 0x63, 0xB0, 0x84, 0x04, 0x93, 0xDD, 0x67, 0x56, 0x04, 0xB0, 0xAE, 0x0D, 0x22, 0x14, 0xC7, 0x8B, 0x34, 0xEE, 0x32, 0x46, 0x9F, 0x68, 0x37, 0x01, 0x12, 0x4A, 0xC4, 0xF9, 0xB7, 0xF4, 0xFA, 0xE7, 0x6E, 0xDD, 0xFF, 0x67, 0x81, 0xCB, 0xE1, 0x1B, 0x87, 0x61, 0x32, 0x29, 0x95, 0x0C, 0x77, 0xC1, 0x4E, 0xAA, 0x0D, 0xB1, 0xE3, 0x21, 0xF0, 0x1A, 0x59, 0x3B, 0x60, 0xDE, 0xE0, 0x31, 0x88, 0xB2, 0x07, 0xB2, 0x41, 0x32, 0x11, 0xF5, 0x95, 0xDB, 0x92, 0x8D, 0xA0, 0x94, 0x4F, 0x45, 0x4F, 0x08, 0xBA, 0xCA, 0xE4, 0x14, 0xD8, 0xBF, 0x25, 0x9E, 0xAF, 0xBE, 0x3F, 0x74, 0x26, 0xD2, 0xBF, 0x94, 0x9D, 0xB2, 0xCB, 0x67, 0xD5, 0x83, 0x2D, 0xFA, 0x3F, 0xF9, 0xD8, 0x23, 0x72, 0xDE, 0x65, 0x7E, 0x61, 0x7F, 0x67, 0xEE, 0x95, 0xDA, 0xC7, 0xEC, 0xE1, 0x60, 0xBA, 0x14, 0x5C, 0xBA, 0x8E, 0x98, 0xBC, 0x5E, 0x98, 0x9C, 0x41, 0xD4, 0x87, 0x5A, 0x65, 0x95, 0x9B, 0xBE, 0x28, 0x1C, 0xB6, 0xDA, 0x72, 0x1F, 0xCC, 0x90, 0x29, 0xDA, 0x97, 0xDD, 0xE8, 0x3F, 0x7B, 0x1B, 0x95, 0x9A, 0x1A, 0xD4, 0x04, 0x19, 0x49, 0x55, 0x12, 0x66, 0xFE, 0xED, 0x89, 0x6E, 0x98, 0x89, 0xE0, 0xAC, 0xF4, 0xF7, 0x61, 0x4D, 0x27, 0xCA, 0x7D, 0x05, 0x2C, 0xDB, 0x7A, 0x22, 0xE4, 0x4B, 0x40, 0x92, 0x4A, 0xF7, 0x27, 0xE9, 0x16, 0xB9, 0x23, 0x7E, 0xD2, 0x01, 0x7C, 0x61, 0xD0, 0x0E, 0x30, 0x16, 0xD3, 0xBD, 0xFD, 0x8B, 0xFC, 0x4E, 0x73, 0xC6, 0xEC, 0x77, 0x7F, 0x8B, 0x06, 0x87, 0xF4, 0x1F, 0x0F, 0x21, 0xE7, 0xFE, 0xFC, 0x1A, 0x79, 0x6A, 0xB5, 0x02, 0x63, 0x79, 0x03, 0xE8, 0xA1, 0x8C, 0x6B, 0x9A, 0x1A, 0xF9, 0xDC, 0x30, 0x68, 0x22, 0x41, 0xB5, 0x81, 0x41, 0xC5, 0x82, 0xE9, 0xE8, 0xD6, 0x91, 0x4D, 0xD1, 0xF4, 0x01, 0xBC, 0x05, 0x18, 0xBE, 0x7F, 0x01, 0x47, 0xB3, 0xA1, 0x35, 0xAB, 0x6D, 0x45, 0x89, 0x3B, 0x07, 0x51, 0xC7, 0xED, 0x8C, 0xA6, 0xE5, 0xA6, 0xF1, 0xAE, 0xFB, 0xD5, 0x52, 0x49, 0x24, 0x3A, 0x20, 0x77, 0x26, 0x93, 0xCA, 0xEB, 0x7F, 0xA1, 0xE4, 0x86, 0xF4, 0x63, 0x1E, 0xD4, 0x9D, 0x7D, 0xA0, 0x23, 0x18, 0x3B, 0xC2, 0x14, 0xEE, 0x22, 0xD8, 0x94, 0x83, 0xD2, 0xC9, 0xD2, 0x17, 0x63, 0x79, 0xD8, 0x29, 0x55, 0xE9, 0x2D, 0x93, 0xC0, 0xD4, 0x12, 0x05, 0xAB, 0xAA, 0x72, 0x5E, 0x4D, 0x89, 0x97, 0xCA, 0xB1, 0x4B, 0x45, 0xF0, 0x94, 0xD0, 0xAA, 0xA6, 0x4D, 0x37, 0xBD, 0x82, 0xA7, 0x4B, 0x3D, 0xFA, 0xA4, 0x04, 0xD9, 0x43, 0x1C, 0x1A, 0x49, 0xDB, 0x8A, 0x29, 0x77, 0xF1, 0xCE, 0x24, 0x5A, 0xB2, 0xB1, 0x23, 0x69, 0xB3, 0x4E, 0xE8, 0xEB, 0x01, 0x7A, 0xE2, 0xF0, 0x7F, 0xB4, 0xA5, 0x56, 0xF6, 0xE9, 0x44, 0x16, 0xE1, 0xA5, 0x4C, 0x08, 0x50, 0x28, 0x8D, 0x24, 0xBA, 0x57, 0x9F, 0x59, 0xA4, 0xDF, 0xAF, 0xAC, 0xA8, 0xF9, 0x87, 0xD4, 0x29, 0x5F, 0x2F, 0xF6, 0xEC, 0x31, 0x6A, 0x7E, 0x65, 0xD1, 0xC6, 0x67, 0x79, 0x5B, 0x9E, 0xF9, 0x87, 0x05, 0x25, 0x5A, 0x4B, 0xC3, 0x40, 0x97, 0xBC, 0xDD, 0x99, 0x3B, 0xAE, 0x4D, 0x86, 0x79, 0x6A, 0x79, 0x93, 0x52, 0xB7, 0xBF, 0xC0, 0xD2, 0x2A, 0xD1, 0x7C, 0x6B, 0x68, 0xA3, 0x5A, 0x2B, 0x1C, 0x6B, 0xA1, 0x70, 0x6B, 0x0F, 0x37, 0xC7, 0xED, 0x09, 0x76, 0xBA, 0x2A, 0xFB, 0xFC, 0xF1, 0x93, 0x0B, 0x77, 0x3C, 0xEB, 0x06, 0x44, 0x80, 0x18, 0xBD, 0x43, 0x14, 0xBE, 0x3E, 0xF1, 0x35, 0x4F, 0xC2, 0xD1, 0xAA, 0x05, 0xEF, 0xFA, 0x54, 0x46, 0x20, 0x21, 0xC5, 0x20, 0x74, 0xC6, 0xE4, 0xA6, 0x34, 0x65, 0xE4, 0x4F, 0xBC, 0x53, 0xBC, 0x64, 0x3E, 0x48, 0x5E, 0xD0, 0xAD, 0xE0, 0x76, 0xFB, 0xB4, 0x9F, 0x0F, 0x64, 0xA3, 0xE2, 0x2E, 0xD1, 0xF8, 0xCD, 0x91, 0xC1, 0x18, 0xFB, 0x30, 0x61, 0x12, 0x0F, 0x20, 0x3F, 0xC9, 0x25, 0x7C, 0xE3, 0x06, 0xA5, 0x63, 0x78, 0x73, 0xD5, 0x4B, 0x68, 0x13, 0xD5, 0xA6, 0xFF, 0x60, 0x4A, 0x8B, 0xA2, 0x5F, 0xEB, 0x1E, 0xD1, 0xF8, 0x07, 0xEB, 0x93, 0x9D, 0xA4, 0x5D, 0xBD, 0xE0, 0xE6, 0xE3, 0x1B, 0x57, 0xC7, 0x6E, 0xF0, 0xD3, 0x3D, 0x93, 0x61, 0x20, 0xA6, 0x43, 0x3D, 0xE5, 0xA4, 0x03, 0x97, 0xF5, 0x01, 0x8A, 0x49, 0x21, 0x34, 0x57, 0x23, 0xA1, 0xB5, 0xEF, 0x49, 0x06, 0xB7, 0x15, 0x10, 0x1A, 0x01, 0x72, 0x8E, 0x00, 0x1A, 0x1A, 0x95, 0xE4, 0x36, 0x66, 0xFF, 0xE4, 0x39, 0x3F, 0xC9, 0xB8, 0x72, 0xE7, 0x72, 0x9E, 0x9F, 0x4B, 0x50, 0x82, 0xF3, 0xB8, 0x41, 0x82, 0x58, 0xBB, 0x97, 0xE7, 0x36, 0x0A, 0xE5, 0x8A, 0xAC, 0x97, 0x6A, 0xE9, 0x20, 0xCD, 0xA1, 0x59, 0x2B, 0xF4, 0x2B, 0x06, 0x9E, 0x70, 0x10, 0x5D, 0x08, 0x18, 0x2A, 0x32, 0x57, 0xED, 0xAF, 0x75, 0x5D, 0x98, 0xF0, 0xFF, 0x20, 0xD1, 0x39, 0xD1, 0x9C, 0x1D, 0x3E, 0x8F, 0xD4, 0x24, 0x60, 0x94, 0x20, 0xAC, 0x86, 0x00, 0x31, 0x76, 0x18, 0xF5, 0x1F, 0xEB, 0x55, 0xBA, 0x8C, 0xD0, 0x2C, 0x2F, 0x8F, 0x0C, 0x54, 0xB2, 0x0D, 0x4A, 0xA2, 0xC3, 0xBB, 0x82, 0x65, 0xA7, 0x37, 0x51, 0x27, 0xBD, 0x11, 0x84, 0xBE, 0x38, 0xC1, 0xD4, 0x71, 0x2A, 0x58, 0x95, 0x63, 0x82, 0x35, 0x08, 0xC6, 0x9B, 0x3C, 0xDF, 0x66, 0x0E, 0x4F, 0x7E, 0x4B, 0x45, 0xBA, 0xAA, 0x30, 0x90, 0xE3, 0x75, 0xCE, 0x59, 0xB8, 0x44, 0xE4, 0x37, 0x7B, 0x4B, 0x46, 0xD9, 0x4B, 0x5A, 0x22, 0x7C, 0x20, 0x7A, 0xB9, 0x4B, 0x55, 0xE0, 0x67, 0xFF, 0x5B, 0xF3, 0xEB, 0xCE, 0x81, 0x0A, 0x7B, 0x92, 0xB9, 0xF4, 0xD3, 0xB5, 0xAC, 0x98, 0xEF, 0x1A, 0x17, 0x5A, 0xD2, 0xC4, 0x39, 0x1B, 0xAC, 0x9A, 0x70, 0xE1, 0xA6, 0x25, 0x56, 0x3A, 0x9D, 0x5B, 0x59, 0x44, 0x80, 0x1D, 0xD2, 0xDB, 0xCC, 0xFC, 0xDB, 0xE2, 0xD7, 0xA5, 0x17, 0x4F, 0xF3, 0xD1, 0xFC, 0x61, 0xED, 0x47, 0x87, 0xEA, 0x99, 0x17, 0xDC, 0x27, 0x23, 0x6F, 0x7B, 0x38, 0x30, 0x65, 0xD7, 0xB3, 0x8E, 0x28, 0xC1, 0x03, 0xF6, 0xDD, 0x72, 0x8E, 0xB2, 0x88, 0x23, 0x58, 0xB0, 0x36, 0xA6, 0xB1, 0xE7, 0xFD, 0xC3, 0x77, 0x1F, 0xD1, 0xFE, 0xD5, 0xFF, 0xA2, 0x59, 0x6D, 0x2B, 0x9F, 0xD8, 0xDA, 0x08, 0x92, 0xE2, 0x42, 0x7C, 0xA0, 0x87, 0xE9, 0xFE, 0x17, 0x4A, 0x66, 0x57, 0xA1, 0x8D, 0xC6, 0x69, 0x4C, 0x7D, 0x73, 0x7E, 0x49, 0xD2, 0xC6, 0x8D, 0x07, 0xA2, 0x3B, 0x51, 0xC7, 0x67, 0xF4, 0x66, 0x5F, 0xCB, 0x85, 0x5A, 0x9B, 0x8C, 0x84, 0xC4, 0xD7, 0x08, 0x2E, 0x3C, 0x5A, 0x73, 0x4B, 0xBA, 0xF8, 0x45, 0x76, 0x64, 0x74, 0x0A, 0x51, 0x73, 0xEE, 0xB6, 0x8A, 0xC4, 0xFB, 0x83, 0x4B, 0x16, 0x14, 0x8A, 0xAE, 0x1E, 0xAA, 0xFE, 0xC3, 0x42, 0x73, 0x0C, 0xB8, 0x7B, 0xDD, 0x1F, 0xAB, 0xAE, 0xAC, 0xA9, 0xA0, 0x55, 0x0D, 0xCD, 0x92, 0x4F, 0xCD, 0x70, 0x0A, 0xCF, 0x2B, 0xB8, 0x30, 0x5B, 0xD9, 0x90, 0xDE, 0x98, 0x89, 0xE7, 0xDF, 0x95, 0x7A, 0x70, 0xEF, 0x25, 0xEA, 0xFF, 0x34, 0x52, 0xFE, 0xFA, 0xEC, 0xFB, 0x1C, 0x20, 0x9E, 0xD6, 0x98, 0xB9, 0x29, 0x5D, 0x24, 0xCA, 0x18, 0xF6, 0xEF, 0xFC, 0x1F, 0x38, 0xD4, 0xED, 0x7E, 0x9E, 0x2E, 0x60, 0x6D, 0x94, 0x7D, 0xF2, 0x6C, 0x5E, 0xEA, 0x72, 0xDD, 0x3A, 0xED, 0x4D, 0xDB, 0x17, 0xA6, 0x9E, 0x96, 0xAE, 0xE7, 0x3C, 0x7A, 0xFD, 0xA6, 0xD5, 0x52, 0x8C, 0xE8, 0x50, 0xF6, 0x4A, 0x0F, 0xDF, 0x91, 0x13, 0xA4, 0x04, 0xE8, 0xB7, 0x89, 0x72, 0xD1, 0x1A, 0x5E, 0x05, 0x6C, 0x14, 0xA8, 0x8E, 0x64, 0x72, 0x58, 0x47, 0xC8, 0x23, 0x80, 0x3A, 0xEE, 0xC9, 0x7E, 0x51, 0x4E, 0x21, 0xCC, 0x6F, 0xDA, 0x9B, 0xF8, 0x04, 0x9B, 0xEA, 0x60, 0x23, 0xAF, 0x26, 0xBD, 0xCD, 0xA4, 0x35, 0x33, 0xD2, 0x72, 0xE6, 0xF8, 0x34, 0x53, 0x85, 0xBA, 0x73, 0x96, 0x40, 0x26, 0x53, 0x6C, 0x87, 0x65, 0xE5, 0xD3, 0x27, 0x45, 0x64, 0x4E, 0xE3, 0x86, 0x4B, 0xD1, 0xE3, 0x24, 0x85, 0xA3, 0x16, 0x42, 0xBE, 0xDF, 0x6B, 0x18, 0xD9, 0x41, 0xF3, 0x77, 0x79, 0x11, 0xB5, 0x97, 0xB3, 0x3E, 0xD0, 0x70, 0xA1, 0x8F, 0x5E, 0xD1, 0x29, 0x69, 0xD5, 0xF2, 0xAD, 0x3B, 0xDF, 0x30, 0xD4, 0xDB, 0xE1, 0x14, 0x48, 0x90, 0x12, 0xEE, 0xB7, 0x77, 0x6C, 0x81, 0x5D, 0x79, 0x9B, 0xBC, 0xDA, 0x08, 0xC8, 0xB1, 0xD6, 0x92, 0xBC, 0x7E, 0x50, 0x1A, 0x79, 0x24, 0x91, 0x98, 0x29, 0xD1, 0x8E, 0x24, 0x07, 0xDB, 0x13, 0xDC, 0x7C, 0xB2, 0x4E, 0xB1, 0x50, 0xC4, 0x3C, 0x69, 0x5C, 0xC9, 0xD6, 0xBA, 0x71, 0x4E, 0xB2, 0x3F, 0xF7, 0xE5, 0x37, 0x7B, 0x9D, 0xE1, 0x88, 0x95, 0xB4, 0xF9, 0x29, 0x7D, 0x9F, 0x60, 0xDD, 0xA9, 0x76, 0x3B, 0x93, 0xAB, 0xB9, 0xBD, 0x3B, 0x8A, 0x0D, 0x82, 0xB2, 0xF1, 0x97, 0xAC, 0x68, 0xA1, 0xA2, 0xC1, 0xFE, 0x93, 0xF9, 0x7F, 0xCD, 0x03, 0x5D, 0x97, 0x3A, 0x9C, 0x8E, 0xD4, 0xD5, 0x48, 0x71, 0x1E, 0x24, 0xE8, 0x59, 0x46, 0x75, 0xDE, 0x0C, 0xD3, 0x51, 0x76, 0x69, 0x49, 0xE6, 0x91, 0x78, 0x57, 0x0B, 0xEE, 0x83, 0xF9, 0xB4, 0x51, 0x0E, 0x39, 0x14, 0xD2, 0x7D, 0x4E, 0xEF, 0xF2, 0x79, 0xC3, 0x08, 0x3F, 0x65, 0x2B, 0x87, 0x17, 0x24, 0x16, 0xB1, 0x70, 0x4C, 0x75, 0xA6, 0x9D, 0x05, 0x14, 0x91, 0xD6, 0x2A, 0x36, 0x11, 0x8D, 0x5F, 0x3B, 0x76, 0x1E, 0x32, 0xBA, 0x0E, 0x5C, 0x65, 0xEE, 0x2C, 0x81, 0xA9, 0xF5, 0xB5, 0x55, 0xC8, 0x50, 0x89, 0x18, 0xBB, 0xC0, 0x02, 0x09, 0xCD, 0xBD, 0x6C, 0x54, 0x06, 0xA8, 0xCC, 0x1C, 0x00, 0x29, 0x24, 0x0D, 0x10, 0x76, 0xE7, 0x22, 0x3E, 0x26, 0x89, 0x8C, 0x27, 0xC9, 0x75, 0x07, 0x97, 0xD6, 0x41, 0xF6, 0x5F, 0x2C, 0x92, 0x4A, 0x07, 0xCF, 0xCD, 0x02, 0x46, 0x1C, 0x7A, 0x27, 0x51, 0x91, 0xDA, 0x37, 0x2E, 0x33, 0x9A, 0xCD, 0xDA, 0x38, 0xFA, 0x3B, 0x01, 0x4F, 0x06, 0x7E, 0xBD, 0x22, 0x31, 0xE1, 0x87, 0xD6, 0x0B, 0xB7, 0x37, 0xB7, 0x5D, 0x3E, 0xEA, 0x8C, 0x88, 0xB6, 0xA1, 0xEB, 0xCF, 0x8B, 0x25, 0xAF, 0xCB, 0xB0, 0x71, 0x23, 0x6F, 0x64, 0x40, 0xE5, 0x65, 0xCB, 0xF3, 0xAF, 0x26, 0x32, 0xA2, 0xC9, 0xF6, 0x2F, 0xF3, 0x8B, 0xD8, 0x82, 0x08, 0x08, 0xE8, 0xAB, 0x59, 0x29, 0xED, 0x2B, 0x16, 0x9A, 0x7F, 0xE8, 0xB8, 0x3C, 0x92, 0x59, 0x19, 0xC9, 0xBC, 0xAA, 0x4B, 0x2F, 0xE6, 0x4F, 0x4D, 0x4C, 0xED, 0x8F, 0x0F, 0xC9, 0xAA, 0xD8, 0x54, 0xC3, 0xE7, 0x5D, 0xF0, 0x51, 0x3C, 0x5E, 0x24, 0x76, 0x4E, 0xAD, 0xEE, 0x40, 0xA1, 0xCA, 0xE8, 0x9C, 0x42, 0x56, 0xF4, 0x44, 0x54, 0x1A, 0x51, 0x54, 0x5A, 0xCE, 0xEC, 0x09, 0xA9, 0xA0, 0xD8, 0xF4, 0x81, 0xC5, 0xE1, 0x56, 0x90, 0xE7, 0x49, 0x67, 0x40, 0x98, 0x13, 0x99, 0x5D, 0x02, 0x6F, 0x02, 0x02, 0x38, 0x5F, 0xBF, 0x7D, 0xDA, 0x81, 0x74, 0x79, 0x1E, 0x9E, 0x28, 0xA9, 0x01, 0x04, 0x76, 0x54, 0xE0, 0xAE, 0x54, 0x5A, 0x90, 0xAC, 0x56, 0xA1, 0x92, 0x3A, 0x8D, 0x83, 0xAB, 0x8D, 0x08, 0x5B, 0x49, 0xC5, 0xBA, 0x0A, 0xBB, 0x68, 0x3E, 0x72, 0xBA, 0x9F, 0x03, 0xFC, 0xC7, 0x20, 0x01, 0x24, 0x40, 0x87, 0xF4, 0xF9, 0xB7, 0xE2, 0xE9, 0xD0, 0xE8, 0x20, 0x66, 0x44, 0xC1, 0x36, 0x60, 0xD2, 0x81, 0xBD, 0x7B, 0xB1, 0x65, 0x32, 0x86, 0x38, 0xFF, 0xA3, 0x13, 0x60, 0x0B, 0x30, 0x85, 0xDE, 0x3B, 0x9A, 0xA2, 0x20, 0xBA, 0xD0, 0x3C, 0x08, 0x90, 0xFA, 0x3C, 0x90, 0x0E, 0x49, 0x16, 0x21, 0x87, 0xC0, 0x2E, 0x7E, 0xD7, 0x3D, 0xCF, 0x50, 0xF5, 0xB0, 0x8C, 0xA5, 0xEB, 0x8E, 0xDE, 0x36, 0x7A, 0x28, 0xAE, 0x94, 0xFF, 0x29, 0xB3, 0x62, 0x98, 0x72, 0xAD, 0x99, 0xEA, 0x2B, 0x22, 0x67, 0x37, 0x4D, 0xDB, 0x56, 0x41, 0x29, 0x80, 0x3A, 0x78, 0xDA, 0xBE, 0xC9, 0x07, 0x16, 0xC3, 0x13, 0xF7, 0xAB, 0xCE, 0xC4, 0xD3, 0x43, 0x0E, 0x2E, 0xC3, 0x80, 0x3F, 0x91, 0x9C, 0x85, 0x65, 0x94, 0x0A, 0x3A, 0xCC, 0x80, 0x89, 0x9E, 0xDB, 0xB4, 0x86, 0xED, 0x52, 0xBF, 0xC1, 0x9D, 0x0E, 0xA3, 0xC5, 0x82, 0x77, 0x5E, 0x29, 0x15, 0x4E, 0x99, 0xF4, 0x41, 0x89, 0x7F, 0x09, 0x96, 0xAA, 0xC5, 0xC5, 0xCA, 0x5B, 0xBB, 0xF4, 0x97, 0x23, 0x48, 0x32, 0xC8, 0xB5, 0x79, 0x1C, 0xB8, 0xC8, 0xAC, 0xEA, 0x8D, 0xB3, 0xE0, 0x06, 0x50, }, .pkcs8_len = 0, .spki_len = 0, .msg_len = 66, .msg = { 0x22, 0x5D, 0x5C, 0xE2, 0xCE, 0xAC, 0x61, 0x93, 0x0A, 0x07, 0x50, 0x3F, 0xB5, 0x9F, 0x7C, 0x2F, 0x93, 0x6A, 0x3E, 0x07, 0x54, 0x81, 0xDA, 0x3C, 0xA2, 0x99, 0xA8, 0x0F, 0x8C, 0x5D, 0xF9, 0x22, 0x3A, 0x07, 0x3E, 0x7B, 0x90, 0xE0, 0x2E, 0xBF, 0x98, 0xCA, 0x22, 0x27, 0xEB, 0xA3, 0x8C, 0x1A, 0xB2, 0x56, 0x82, 0x09, 0xE4, 0x6D, 0xBA, 0x96, 0x18, 0x69, 0xC6, 0xF8, 0x39, 0x83, 0xB1, 0x7D, 0xCD, 0x49, }, .sig_len = 4668, .sig = { 0x8B, 0xCE, 0xDB, 0xF2, 0xD6, 0x06, 0x90, 0x0B, 0x70, 0xFD, 0xF9, 0x1F, 0x0F, 0x93, 0xE8, 0x36, 0x56, 0x40, 0x89, 0x72, 0xBB, 0x47, 0xE0, 0x17, 0x95, 0x13, 0x74, 0x62, 0x46, 0x38, 0x0C, 0xAE, 0x70, 0x9A, 0x59, 0x62, 0x2B, 0x9B, 0x23, 0x2D, 0x5B, 0x0D, 0x2D, 0xF5, 0x11, 0x71, 0xCE, 0x64, 0x42, 0x5B, 0x04, 0x38, 0x93, 0x24, 0xA0, 0xA0, 0x03, 0x84, 0x17, 0x00, 0x28, 0x74, 0x50, 0xF7, 0x5A, 0x81, 0x7B, 0x1C, 0x1D, 0x63, 0xCF, 0xB5, 0x0A, 0xF6, 0x1D, 0x8A, 0xF1, 0x9C, 0xC0, 0xFC, 0xB1, 0xA6, 0x3D, 0x53, 0x72, 0xB8, 0xE7, 0xFF, 0xD0, 0xAF, 0xCB, 0xAC, 0x05, 0xF6, 0x3A, 0xC0, 0x55, 0xDE, 0x27, 0x8F, 0x46, 0x25, 0x22, 0x34, 0x1C, 0x3E, 0xD6, 0xA1, 0xEE, 0x74, 0x6E, 0x3A, 0xCA, 0x17, 0x4E, 0xA5, 0x1E, 0x0D, 0xCD, 0xEC, 0x02, 0xBB, 0x5C, 0x68, 0x46, 0x88, 0x64, 0x54, 0x75, 0x90, 0xE0, 0xDE, 0xF0, 0x76, 0x11, 0x1C, 0x3B, 0x45, 0xD1, 0xFA, 0xA7, 0xF3, 0xF3, 0x4C, 0x2E, 0x63, 0x6D, 0x68, 0xB4, 0xF7, 0xD2, 0xBC, 0x04, 0xB7, 0x38, 0x39, 0x59, 0xE0, 0x9E, 0xF7, 0xB8, 0x4B, 0x04, 0x5C, 0x29, 0xEB, 0xD5, 0x0A, 0xE8, 0x87, 0x42, 0x71, 0xAC, 0x3A, 0x7C, 0xB1, 0xEE, 0x94, 0xC5, 0x53, 0x9A, 0xD0, 0x7E, 0x7E, 0xF9, 0xF6, 0x4D, 0x30, 0x16, 0xDA, 0xF9, 0x66, 0x1F, 0xEE, 0x09, 0xB9, 0xBF, 0x27, 0xB0, 0xFF, 0x9B, 0xEA, 0x68, 0x90, 0x98, 0x04, 0x13, 0xAC, 0x23, 0x42, 0xC0, 0x9B, 0x4A, 0x65, 0xA8, 0x3B, 0x58, 0x3F, 0x3A, 0x33, 0x23, 0x04, 0x88, 0xCC, 0x43, 0xAE, 0x30, 0x0D, 0x12, 0xE9, 0xB0, 0x55, 0xC6, 0x5B, 0xD9, 0xC3, 0xA5, 0x1A, 0xA2, 0x7E, 0xF8, 0xBD, 0x04, 0x76, 0x4E, 0x78, 0xDD, 0x8F, 0x1C, 0x62, 0xC6, 0x5C, 0x7F, 0x7E, 0x86, 0x30, 0xD0, 0xC8, 0x6B, 0xEA, 0x6A, 0x87, 0xFF, 0x8D, 0x2D, 0x6E, 0x16, 0x70, 0x24, 0x8C, 0x89, 0xE1, 0x8E, 0x77, 0x5D, 0xC7, 0x93, 0x1E, 0xC5, 0xAA, 0x3B, 0xAB, 0x0F, 0xFC, 0xC4, 0x49, 0xE1, 0xB2, 0x0F, 0x42, 0x2C, 0xA4, 0xDD, 0x2F, 0xD2, 0x9B, 0x40, 0x51, 0x0B, 0xB4, 0x1D, 0x63, 0x6B, 0x37, 0x22, 0x2D, 0xE4, 0xA0, 0x85, 0x55, 0xC0, 0x4F, 0xBA, 0x4B, 0x3C, 0x0F, 0x89, 0x7C, 0x99, 0x8A, 0x2C, 0xE2, 0x16, 0x1B, 0xD1, 0xB3, 0x5D, 0x20, 0xBF, 0x93, 0xA9, 0xD4, 0xFF, 0x8C, 0x28, 0xD2, 0x95, 0xB8, 0x4F, 0x41, 0xF7, 0xF2, 0x74, 0x04, 0x71, 0xF2, 0x76, 0xEE, 0xA4, 0x66, 0xF5, 0xE3, 0xAC, 0xF8, 0x1B, 0xD5, 0xB6, 0xE9, 0x3B, 0xE4, 0x5F, 0x81, 0x15, 0x85, 0x64, 0xF9, 0x0D, 0x3B, 0xAD, 0x75, 0x52, 0xF5, 0x77, 0x72, 0x51, 0x60, 0xE9, 0x46, 0x7C, 0xBA, 0xEC, 0x5C, 0x8D, 0x86, 0x2B, 0xEA, 0x9D, 0x83, 0xE1, 0xC1, 0x83, 0x97, 0xC4, 0x1D, 0x68, 0x68, 0x17, 0x74, 0x2E, 0xF5, 0x7E, 0x74, 0x33, 0xC8, 0xEB, 0x9B, 0xA1, 0x56, 0x9B, 0xB7, 0xF4, 0x1A, 0x8E, 0xD8, 0x89, 0xE2, 0x23, 0xBB, 0xCA, 0x15, 0x3E, 0xBC, 0x02, 0xC0, 0x46, 0x9C, 0x71, 0xD6, 0x63, 0xC4, 0xD2, 0x85, 0x00, 0x8B, 0xF1, 0x85, 0x49, 0x24, 0x3D, 0x0E, 0x46, 0xC8, 0x16, 0xD0, 0xBE, 0x77, 0x50, 0x2C, 0x79, 0x5C, 0x16, 0x8E, 0x07, 0x53, 0x52, 0xFA, 0x7D, 0xDB, 0xF9, 0xD0, 0xF2, 0xBE, 0xB4, 0x52, 0x8B, 0x48, 0xB5, 0xAB, 0xB2, 0x81, 0x0E, 0x37, 0x7F, 0x53, 0x30, 0xB3, 0xE2, 0xE6, 0x1B, 0xFF, 0x7B, 0xE9, 0x6B, 0xDC, 0xAB, 0xA5, 0xB5, 0x6B, 0x6C, 0xA5, 0x7C, 0x66, 0x0E, 0x54, 0xE4, 0x49, 0xEC, 0x3B, 0x4C, 0xA2, 0x66, 0x4F, 0xD3, 0xB7, 0xC4, 0xA8, 0x91, 0x97, 0x3E, 0x2A, 0x31, 0xCC, 0xF8, 0x27, 0x89, 0x2A, 0x1F, 0x75, 0x7F, 0x68, 0x0B, 0x36, 0xF4, 0x0B, 0x08, 0x2C, 0x6A, 0xD5, 0x06, 0x02, 0x1B, 0xAB, 0x7F, 0xE2, 0x2D, 0x46, 0xF6, 0x83, 0x93, 0x34, 0x18, 0x58, 0x67, 0xC0, 0x16, 0x26, 0xAC, 0x63, 0xA4, 0x16, 0x28, 0x58, 0xA9, 0xDA, 0xC3, 0x25, 0x81, 0x68, 0xDF, 0x61, 0xCB, 0x66, 0xA3, 0xFF, 0x9F, 0xD4, 0x38, 0x76, 0x59, 0x06, 0x19, 0xDB, 0xB3, 0xE5, 0xBE, 0x1E, 0xBA, 0x5D, 0x67, 0x59, 0x85, 0xE3, 0xBA, 0x6E, 0xC9, 0x84, 0x01, 0x1F, 0x3E, 0x23, 0xCB, 0xFC, 0xDD, 0x7A, 0xB5, 0xE5, 0x50, 0xC6, 0x1A, 0x0B, 0xAA, 0xBA, 0xBC, 0xBF, 0x16, 0xFA, 0xBC, 0x41, 0x4F, 0xCF, 0x4B, 0xC1, 0x43, 0x4B, 0xAA, 0x03, 0xAE, 0xDD, 0xB8, 0x15, 0x6D, 0xA3, 0x58, 0x71, 0xD4, 0x83, 0xF1, 0x94, 0xAC, 0x3B, 0xF9, 0x18, 0xC9, 0xB7, 0x7B, 0xBA, 0x65, 0x95, 0x97, 0xAD, 0x5B, 0xA2, 0xB8, 0x95, 0x4E, 0xF4, 0x12, 0x1F, 0xDA, 0xDF, 0x0A, 0xE5, 0xA1, 0x2D, 0x5B, 0xDF, 0x3C, 0xBB, 0xD8, 0xEA, 0x5C, 0x76, 0xBE, 0x81, 0x6E, 0x7E, 0x9A, 0x79, 0x92, 0x70, 0x16, 0x5E, 0x7E, 0x9F, 0xD7, 0xCB, 0x70, 0x18, 0x80, 0x81, 0x1E, 0xDE, 0x73, 0xF6, 0x12, 0x1E, 0xEC, 0xEE, 0x27, 0x1A, 0xE4, 0xF1, 0x8D, 0xF1, 0x9F, 0x28, 0xA8, 0x10, 0xAB, 0x43, 0x23, 0x2A, 0xA8, 0x40, 0xF6, 0xDD, 0xCC, 0xB8, 0x6A, 0xE3, 0x96, 0xFE, 0x54, 0xA5, 0x79, 0x77, 0x8F, 0x96, 0xC2, 0xFA, 0x85, 0x70, 0x62, 0x04, 0x7F, 0xF5, 0x3C, 0xA5, 0x42, 0xC4, 0xBA, 0xC1, 0x42, 0x0D, 0x0B, 0x2C, 0x52, 0xA4, 0x2E, 0xAD, 0xBA, 0xAA, 0x58, 0x5A, 0x44, 0x02, 0x73, 0x17, 0xA7, 0x66, 0x6E, 0x47, 0x4C, 0x55, 0xBF, 0x6F, 0xE0, 0x54, 0xE4, 0x22, 0x92, 0x61, 0x79, 0x88, 0xEE, 0x0A, 0xBF, 0xE2, 0x28, 0xC7, 0x1B, 0xA4, 0x74, 0x93, 0x26, 0x8C, 0x32, 0x83, 0xBB, 0x62, 0xE4, 0x0A, 0xA0, 0x5D, 0xEF, 0x2C, 0x10, 0xC6, 0x12, 0x1F, 0x76, 0x7F, 0x33, 0xB1, 0x48, 0x9A, 0x1D, 0x20, 0x48, 0x2A, 0x3D, 0x8D, 0xF8, 0x89, 0x1D, 0xDD, 0x2A, 0x9B, 0xE4, 0xBD, 0x2B, 0x00, 0x73, 0xC5, 0x92, 0x92, 0x34, 0x4A, 0x69, 0x92, 0x79, 0x73, 0x8C, 0xB6, 0xDB, 0x24, 0xA8, 0x97, 0x63, 0x88, 0x7F, 0x2D, 0x78, 0xE7, 0xE2, 0x6A, 0x04, 0x0E, 0xC2, 0x77, 0x7A, 0xAD, 0xED, 0xCA, 0xE5, 0xB2, 0x62, 0x72, 0xAE, 0x40, 0xCB, 0x65, 0x67, 0xC4, 0x16, 0x72, 0x1D, 0xD4, 0x5C, 0x7B, 0x8F, 0x75, 0x1B, 0x82, 0x13, 0x11, 0x80, 0xEA, 0x9E, 0x80, 0xEA, 0x97, 0x26, 0x8A, 0x2C, 0x2E, 0x00, 0x9A, 0xD7, 0xBE, 0x1F, 0xDD, 0x4F, 0xD2, 0xA6, 0x17, 0xF7, 0xA8, 0xD7, 0xE2, 0x6B, 0x6D, 0x94, 0x37, 0x30, 0x99, 0x81, 0xB5, 0x01, 0x3F, 0xC0, 0x72, 0xBE, 0x94, 0xEB, 0x2F, 0x03, 0x6D, 0xD9, 0x0A, 0x78, 0x8D, 0xC5, 0xC1, 0x42, 0xDF, 0x50, 0x5A, 0xCD, 0x26, 0xA0, 0x0D, 0xAF, 0xDC, 0x30, 0xF5, 0x19, 0x0B, 0x0A, 0x91, 0xBC, 0xBE, 0x49, 0x58, 0x7F, 0x89, 0xB1, 0xD9, 0x99, 0xDE, 0x49, 0x00, 0x9C, 0x0B, 0xD7, 0xEB, 0x95, 0x5E, 0xB3, 0x08, 0x86, 0x73, 0x6B, 0x6D, 0xD4, 0xDC, 0x1D, 0x8D, 0x1D, 0xA6, 0x80, 0x69, 0x02, 0x39, 0x87, 0x9B, 0x3D, 0x6D, 0xD7, 0x64, 0x72, 0xF3, 0xD6, 0xE3, 0x3B, 0xC8, 0xFD, 0x90, 0xE4, 0x47, 0xE7, 0x0F, 0xD7, 0xE9, 0xF5, 0x0B, 0xF9, 0xA1, 0xA0, 0xAC, 0x9D, 0x88, 0x32, 0xA4, 0x36, 0xE8, 0x9E, 0x36, 0x44, 0x03, 0x75, 0xF5, 0xDE, 0x88, 0xDC, 0x70, 0xD9, 0x17, 0xCE, 0x13, 0x22, 0x35, 0xB9, 0x1B, 0x20, 0xAE, 0x41, 0x1B, 0x86, 0xC2, 0x19, 0xB5, 0xA3, 0x4D, 0xB0, 0x29, 0x16, 0x80, 0xE6, 0x15, 0x54, 0xDD, 0x50, 0xF3, 0x26, 0x1F, 0xEA, 0x06, 0xB5, 0xF1, 0x74, 0xEA, 0x6B, 0x13, 0x65, 0x0C, 0x97, 0x9C, 0x5A, 0x72, 0x8F, 0x13, 0xF8, 0xDA, 0x45, 0x57, 0xEF, 0x8D, 0x9A, 0xF6, 0x41, 0x22, 0x8F, 0xE5, 0xDD, 0x7D, 0x92, 0x28, 0xD7, 0x8C, 0x9A, 0xE8, 0x7E, 0xFE, 0xEA, 0x22, 0x4C, 0x02, 0x12, 0x5E, 0xC2, 0x86, 0xBB, 0x85, 0xC8, 0xB1, 0x2A, 0xCB, 0x40, 0xF7, 0xEA, 0x12, 0xB0, 0x26, 0xC1, 0xE6, 0x11, 0xEF, 0x99, 0xE0, 0x07, 0x7E, 0xF8, 0x04, 0xD6, 0x56, 0xD0, 0x6B, 0xB4, 0x0C, 0x50, 0xDC, 0xCF, 0xC5, 0x98, 0xC9, 0xD4, 0x04, 0xBF, 0x6B, 0x56, 0x4F, 0x02, 0xE1, 0x8B, 0x48, 0x2C, 0x7F, 0xB7, 0x4C, 0x68, 0x13, 0xA8, 0xE9, 0x75, 0x8E, 0x6F, 0xCB, 0xF2, 0x28, 0x9C, 0x8F, 0x24, 0x5D, 0xD2, 0x41, 0x67, 0x21, 0x89, 0x9D, 0x7A, 0xD4, 0xC7, 0x90, 0xD0, 0x0E, 0x47, 0xF5, 0x14, 0x8C, 0xAC, 0x29, 0x0C, 0x66, 0x07, 0x21, 0x6B, 0xD6, 0x6F, 0x2A, 0x6C, 0xA1, 0xC4, 0xE7, 0x6F, 0x9C, 0xC0, 0x15, 0x08, 0x9D, 0x08, 0xF8, 0x39, 0xA0, 0x95, 0x2F, 0x3B, 0x3C, 0xA8, 0x23, 0x58, 0x16, 0x44, 0xAD, 0x7D, 0xDA, 0x18, 0xC0, 0xBC, 0xC6, 0xE7, 0x46, 0xA7, 0x31, 0xCA, 0xE4, 0x28, 0xCE, 0x7A, 0xD4, 0xCC, 0x81, 0x3B, 0xA9, 0x5D, 0x83, 0xDC, 0x7D, 0x6E, 0xE0, 0xA3, 0xCD, 0xDC, 0xAB, 0x94, 0x35, 0x00, 0x03, 0x45, 0xC7, 0x1A, 0x09, 0x16, 0x28, 0x2F, 0xD5, 0x3C, 0x4A, 0x86, 0x99, 0xD5, 0x6E, 0x55, 0x20, 0x74, 0x2F, 0x5D, 0xA8, 0x1C, 0xAA, 0xFA, 0x16, 0x78, 0x26, 0xCF, 0x38, 0x6E, 0xB7, 0x2C, 0xD5, 0x12, 0x6A, 0x59, 0xE2, 0x4F, 0x74, 0x00, 0x9B, 0xB0, 0x45, 0x6C, 0x8D, 0x58, 0x51, 0x9C, 0xD6, 0x7A, 0x9C, 0xE0, 0x9B, 0xA8, 0x7F, 0x1C, 0xF0, 0x36, 0xEA, 0x9C, 0x7E, 0xDA, 0xD3, 0xBC, 0xD6, 0xDA, 0x32, 0x76, 0x51, 0x8A, 0xFB, 0xB0, 0x4D, 0xF9, 0xA7, 0xE7, 0x73, 0x32, 0x0E, 0xA4, 0x41, 0xA6, 0x2C, 0x64, 0xEA, 0xEA, 0x8D, 0x42, 0xFC, 0x30, 0x80, 0x4B, 0xFF, 0xEC, 0xC9, 0xBC, 0x2D, 0x2F, 0x46, 0x19, 0x67, 0x56, 0x2D, 0x8D, 0x60, 0x84, 0xC9, 0xFE, 0xD5, 0x21, 0x34, 0xD4, 0xE0, 0x46, 0x90, 0x1E, 0xC0, 0x31, 0x86, 0x83, 0x32, 0x6D, 0xD0, 0xC8, 0xBE, 0x19, 0xB9, 0xAE, 0x3F, 0x38, 0xFA, 0x2E, 0xE9, 0x46, 0x54, 0x02, 0x98, 0x5E, 0x8E, 0x27, 0x40, 0x67, 0x28, 0x9A, 0x79, 0xEB, 0x55, 0x91, 0x83, 0x2D, 0x6E, 0xA6, 0x57, 0x8D, 0xF4, 0x77, 0xDF, 0x52, 0xE1, 0x26, 0x45, 0xD1, 0x86, 0x11, 0x24, 0x52, 0x99, 0x0E, 0xA7, 0x53, 0xE4, 0xFF, 0x3F, 0x0C, 0x3D, 0x0A, 0x14, 0x0F, 0xF7, 0x0F, 0x9B, 0xBE, 0x9A, 0x75, 0x5B, 0xF2, 0x79, 0x50, 0x8A, 0x3C, 0x89, 0x8E, 0x40, 0x85, 0xFC, 0xFC, 0x39, 0x9C, 0x46, 0xC6, 0x82, 0x6D, 0x46, 0xF7, 0xF0, 0x06, 0x3E, 0xA5, 0xA4, 0xC7, 0xE6, 0x6D, 0xC5, 0x60, 0x8E, 0x37, 0xAF, 0xAF, 0xF8, 0xFC, 0x43, 0xAE, 0x82, 0xC3, 0x36, 0x1C, 0xA8, 0xB2, 0xC6, 0xFB, 0xDE, 0xF1, 0x98, 0xFE, 0xFE, 0x74, 0x50, 0xE4, 0xDA, 0x66, 0x2F, 0x32, 0x42, 0xD5, 0x2C, 0x0C, 0xE0, 0x2D, 0xBC, 0xAF, 0xF9, 0x44, 0x5A, 0x63, 0x0F, 0x85, 0x74, 0xEA, 0x0E, 0xE0, 0x97, 0x05, 0xC9, 0x1D, 0x39, 0xB8, 0xFA, 0xD7, 0x8C, 0x35, 0xEF, 0xDF, 0x54, 0x7F, 0xB1, 0x01, 0x8C, 0xDC, 0x89, 0x2A, 0x0C, 0x81, 0x62, 0xFA, 0x7E, 0x07, 0x34, 0xC1, 0xEE, 0x07, 0xFA, 0xD9, 0x47, 0x52, 0x0A, 0xE9, 0x5B, 0x30, 0x22, 0x30, 0x3D, 0xDB, 0x32, 0xF3, 0xD8, 0xDC, 0x4D, 0x68, 0x21, 0x21, 0x15, 0x13, 0xC6, 0x4E, 0x78, 0x5E, 0x4E, 0xE4, 0x38, 0x5C, 0xD3, 0x75, 0x7D, 0x68, 0x0A, 0xAE, 0xD5, 0x4E, 0x15, 0xFA, 0xE5, 0x27, 0xB4, 0x5A, 0xAE, 0x14, 0xD5, 0x63, 0x82, 0x57, 0x8C, 0xA2, 0xE1, 0x16, 0xFD, 0x95, 0x4B, 0x56, 0xAC, 0x37, 0x8C, 0x70, 0x44, 0xDA, 0xCC, 0xB8, 0x86, 0xF3, 0x2B, 0xC3, 0xA5, 0x22, 0xBD, 0xEB, 0xEC, 0xBC, 0xAE, 0x5B, 0x77, 0x4B, 0x8E, 0x60, 0x34, 0xFB, 0xB1, 0x15, 0x6D, 0xE5, 0xC5, 0xF2, 0x16, 0x51, 0x4B, 0xFA, 0x0D, 0x1B, 0x17, 0xD4, 0x73, 0xCD, 0xD2, 0xA0, 0x1D, 0x42, 0x2E, 0xD4, 0x41, 0xAD, 0xC7, 0x17, 0x79, 0x5E, 0x07, 0x82, 0xE4, 0x43, 0xA2, 0xF7, 0x4B, 0x01, 0x36, 0x53, 0x65, 0x9C, 0xA3, 0x9F, 0x5C, 0x74, 0xC5, 0xDC, 0x98, 0x71, 0x5D, 0x3E, 0xA2, 0x2A, 0x0D, 0x0D, 0xD8, 0x26, 0xCF, 0xB3, 0xBA, 0x7F, 0xB0, 0x09, 0x3B, 0x9C, 0x80, 0x76, 0x3A, 0x30, 0x8C, 0x22, 0x87, 0x15, 0x3E, 0x21, 0xFB, 0xDE, 0x26, 0xD2, 0xB7, 0x2A, 0x39, 0x32, 0xD7, 0xB5, 0x3B, 0x88, 0xA4, 0xE1, 0xAE, 0xCF, 0x37, 0x49, 0x21, 0xAD, 0x6F, 0x44, 0x47, 0xA6, 0x31, 0x57, 0xCF, 0x7E, 0x05, 0x8E, 0xF9, 0xBA, 0x1D, 0x72, 0x0B, 0x43, 0xF2, 0x18, 0x0D, 0x2F, 0x55, 0x7F, 0xA2, 0x0E, 0x22, 0xA3, 0xEF, 0x78, 0x5A, 0x08, 0xB5, 0x93, 0x11, 0x1A, 0xBB, 0x4B, 0x00, 0xDF, 0x39, 0x88, 0x34, 0xC7, 0xE4, 0x80, 0xF0, 0x40, 0x45, 0x3E, 0x9E, 0x92, 0x5C, 0x8D, 0x77, 0x85, 0xD5, 0x98, 0x43, 0x04, 0xB7, 0xE9, 0x9B, 0x20, 0x89, 0x51, 0x9D, 0x3F, 0x59, 0x14, 0x31, 0x3C, 0xE1, 0x2D, 0x26, 0xE1, 0x90, 0xA4, 0x36, 0xA5, 0x9F, 0x79, 0xB0, 0xB1, 0x25, 0x19, 0x1D, 0x85, 0x43, 0x49, 0x54, 0x78, 0x18, 0x08, 0x16, 0xC9, 0xE6, 0x50, 0x57, 0x99, 0x32, 0x80, 0x4D, 0xCA, 0x0E, 0x02, 0xE4, 0x69, 0xDD, 0x68, 0x78, 0xFC, 0xE9, 0x2D, 0xFB, 0x49, 0x31, 0xBE, 0xC0, 0xAA, 0x8D, 0x3F, 0x89, 0x7F, 0x2B, 0x9B, 0x91, 0x29, 0xAC, 0x59, 0xF4, 0x76, 0x51, 0xC1, 0xC8, 0xBE, 0xD8, 0x94, 0x9E, 0xF4, 0x37, 0xA6, 0x74, 0xCB, 0x0D, 0xD1, 0xD2, 0xFC, 0xDB, 0x15, 0x82, 0x14, 0xB6, 0x71, 0xBA, 0xCA, 0x72, 0xDB, 0xD3, 0xBF, 0xCD, 0x34, 0x51, 0xC9, 0x26, 0x20, 0xDE, 0xE4, 0xDA, 0xC4, 0x06, 0x98, 0x79, 0xE5, 0x0B, 0x3D, 0xD0, 0x22, 0x74, 0xC5, 0x0D, 0x68, 0x37, 0x2E, 0x22, 0x30, 0xAA, 0x56, 0x26, 0xB0, 0x3B, 0x04, 0xBB, 0x4D, 0x2C, 0xF9, 0x99, 0x97, 0xE0, 0x83, 0x7C, 0xB8, 0xD5, 0xB3, 0x07, 0xCB, 0x35, 0xA1, 0x7D, 0x5A, 0x23, 0xC7, 0xA1, 0x79, 0x76, 0x26, 0x7E, 0xB5, 0x2D, 0x12, 0x31, 0x78, 0xC0, 0x88, 0xFF, 0xE7, 0x2E, 0x88, 0x4B, 0x38, 0x79, 0xFD, 0x9F, 0xF6, 0x8D, 0xBE, 0xE5, 0x68, 0x7E, 0x89, 0x3F, 0xAA, 0xB7, 0xF4, 0x5A, 0x17, 0xFC, 0x45, 0x59, 0x4B, 0xAF, 0x56, 0x92, 0xAA, 0xDD, 0xF4, 0x3F, 0xC0, 0x4E, 0xE1, 0x4B, 0x44, 0xE3, 0xA4, 0x6E, 0xA9, 0xEE, 0x53, 0x54, 0x60, 0x49, 0xA3, 0xB1, 0x50, 0x0C, 0x28, 0xEB, 0x86, 0xA7, 0xF4, 0xEF, 0x5F, 0x87, 0x91, 0xF6, 0x44, 0x55, 0x14, 0x14, 0x58, 0x1A, 0x00, 0x3C, 0x8D, 0x48, 0x49, 0x57, 0xAF, 0x27, 0xC4, 0x7B, 0x65, 0x3B, 0x48, 0xF1, 0xC0, 0xC3, 0x7D, 0xD0, 0x09, 0x99, 0x69, 0xDC, 0x22, 0xF3, 0xB6, 0x6B, 0xB3, 0x91, 0x03, 0xEF, 0xE7, 0x53, 0xC6, 0xCA, 0x52, 0x8F, 0x64, 0x47, 0x73, 0xDF, 0x5A, 0xCF, 0xCA, 0xE5, 0x53, 0x4D, 0x52, 0x75, 0xDF, 0x3A, 0xF0, 0xAE, 0x87, 0xBF, 0x90, 0x57, 0xD7, 0x15, 0xBA, 0x0E, 0x26, 0xF6, 0xBE, 0x7A, 0xB9, 0x02, 0xBD, 0xAD, 0xE9, 0x98, 0x3E, 0x1F, 0xE1, 0xA5, 0xBC, 0xF6, 0x7A, 0x21, 0xB3, 0x5D, 0x00, 0xF3, 0x28, 0x48, 0x28, 0x37, 0x99, 0x83, 0x91, 0x3E, 0x86, 0xA1, 0xBF, 0x1E, 0x8F, 0x29, 0x80, 0xFF, 0x17, 0x48, 0x1E, 0x0B, 0x80, 0x3E, 0x4B, 0xAE, 0xD1, 0x7A, 0x5C, 0x46, 0xB2, 0x61, 0x76, 0xF6, 0x2B, 0xA5, 0x4E, 0x8C, 0x7D, 0xCA, 0x90, 0xD8, 0xA9, 0x82, 0xA9, 0xE6, 0xC6, 0xAC, 0x70, 0x81, 0x23, 0x4A, 0xC3, 0xF4, 0x01, 0xA4, 0x31, 0x03, 0xA2, 0x17, 0xE4, 0x15, 0xE3, 0x08, 0x83, 0x74, 0x9F, 0x30, 0xA3, 0x97, 0x49, 0x93, 0x40, 0x6D, 0x90, 0xB2, 0x07, 0x22, 0xD5, 0xD1, 0xB7, 0x26, 0x52, 0xFF, 0x6C, 0x0B, 0x43, 0x2C, 0xA1, 0x90, 0x10, 0xDF, 0x98, 0x4F, 0x78, 0x5D, 0xBB, 0xBE, 0xBE, 0x8B, 0xD6, 0x94, 0x76, 0xD5, 0xCA, 0xAF, 0xE7, 0x10, 0x5A, 0x12, 0x05, 0xCA, 0x28, 0x41, 0x44, 0x4C, 0x82, 0xF4, 0x4B, 0x3A, 0x1D, 0xC6, 0xAD, 0x47, 0xF9, 0x2C, 0x95, 0x2A, 0x43, 0xBF, 0x25, 0x24, 0xBD, 0x14, 0x93, 0x0E, 0xAF, 0xEA, 0x65, 0xFB, 0xEA, 0x4F, 0x40, 0x28, 0x98, 0x7C, 0x9D, 0x07, 0x51, 0xC5, 0x5C, 0x4D, 0x63, 0xDE, 0x04, 0x50, 0xF6, 0x26, 0x3A, 0x42, 0x8A, 0xA7, 0x9B, 0xD4, 0xDC, 0xFC, 0x64, 0x7E, 0xDD, 0xC4, 0x13, 0x66, 0x4E, 0xCF, 0x20, 0x72, 0xCA, 0xB2, 0x1D, 0x57, 0xB2, 0x44, 0x7E, 0xDF, 0xA7, 0x19, 0x4C, 0x4B, 0xCE, 0xDC, 0xAE, 0x28, 0x93, 0xD3, 0xDE, 0x6B, 0xD1, 0xD6, 0xB2, 0xFA, 0xF2, 0x1C, 0xBC, 0x02, 0x12, 0xC6, 0x36, 0xF6, 0x1B, 0x7A, 0x22, 0x31, 0x28, 0xA3, 0x13, 0xC0, 0x09, 0x9B, 0xF3, 0xAB, 0x1D, 0x28, 0x8A, 0x5C, 0xFD, 0x89, 0x30, 0x25, 0x75, 0x33, 0x1E, 0x00, 0xB6, 0x53, 0xD5, 0x26, 0xB7, 0xB8, 0x74, 0x20, 0x9B, 0x63, 0x14, 0xFE, 0x15, 0xE7, 0x70, 0x7C, 0x90, 0x9C, 0x97, 0x31, 0xA9, 0xC4, 0xB7, 0xF0, 0xE3, 0xD0, 0x2D, 0xA0, 0x53, 0x1D, 0x22, 0x67, 0xDF, 0xBA, 0x35, 0x5E, 0x85, 0x32, 0x1F, 0x8C, 0x0C, 0xA9, 0x7A, 0x98, 0x66, 0x66, 0xCA, 0x84, 0xCA, 0xBF, 0x3F, 0xDB, 0xBC, 0x0F, 0xCD, 0x50, 0xB0, 0x60, 0xF8, 0x74, 0x4F, 0x83, 0xD3, 0x93, 0xC1, 0xF9, 0x60, 0x22, 0x1F, 0x14, 0xB3, 0xAF, 0x44, 0xF3, 0x03, 0x99, 0xB8, 0xA8, 0xF8, 0x34, 0x6C, 0x44, 0x66, 0xA2, 0xBD, 0x4F, 0x01, 0x02, 0x9C, 0x4E, 0x38, 0xA4, 0x54, 0xC9, 0xA9, 0x8D, 0xF2, 0xCD, 0x92, 0xAE, 0x9F, 0x68, 0x6C, 0x1B, 0x21, 0x62, 0xFE, 0xF3, 0x5F, 0x82, 0xA4, 0xF6, 0x87, 0x68, 0x41, 0x50, 0x31, 0xCD, 0xE2, 0x12, 0x02, 0x78, 0x55, 0x7C, 0x30, 0xAD, 0xFC, 0x51, 0xAA, 0xA6, 0xD9, 0xD6, 0x5D, 0x7B, 0x3B, 0x58, 0xB1, 0xD1, 0xAF, 0x6B, 0xF1, 0x0B, 0x61, 0x25, 0xAC, 0xDE, 0xB0, 0x53, 0xAA, 0xEE, 0xBC, 0x2A, 0x26, 0x4E, 0x2E, 0x06, 0x55, 0xA3, 0xDE, 0x02, 0x61, 0x13, 0x13, 0x37, 0xF8, 0x42, 0x73, 0x3E, 0x92, 0x64, 0x4F, 0x0B, 0x38, 0x89, 0x5D, 0xEC, 0xDB, 0xB3, 0xA9, 0x7B, 0x74, 0xDD, 0xCE, 0x55, 0xA3, 0x38, 0x24, 0x8F, 0x74, 0xF8, 0x0B, 0x8A, 0x13, 0x35, 0x1F, 0xD4, 0x33, 0x32, 0xFB, 0x36, 0xC7, 0xAD, 0xE7, 0xD8, 0x20, 0xD5, 0xE5, 0x50, 0x44, 0xF7, 0x42, 0x31, 0xEE, 0x6A, 0xFF, 0x8A, 0x9D, 0xC2, 0xFC, 0xE0, 0x12, 0xCB, 0x40, 0x69, 0xD0, 0x3D, 0xE1, 0xB7, 0x50, 0x67, 0x15, 0xDD, 0x36, 0x98, 0x05, 0xC6, 0xCE, 0x3B, 0x16, 0x0C, 0x6C, 0x7D, 0xE3, 0x50, 0x49, 0xC1, 0x65, 0x53, 0x47, 0x98, 0x27, 0x2B, 0x68, 0x0F, 0xA0, 0x20, 0xDD, 0x32, 0x8B, 0xBE, 0xB9, 0x1A, 0x0D, 0x46, 0x6E, 0x3A, 0x57, 0xFA, 0x2E, 0x66, 0x5D, 0xE4, 0x21, 0x2F, 0xDB, 0x7E, 0xE9, 0x14, 0xA8, 0xB0, 0xD6, 0xFD, 0x5C, 0xE2, 0x03, 0x27, 0x89, 0xE4, 0x8A, 0x35, 0xD0, 0x29, 0x3B, 0x57, 0x42, 0x4C, 0xAA, 0x60, 0xF4, 0xA6, 0x70, 0x40, 0x7F, 0x48, 0x48, 0xD7, 0xA2, 0x4A, 0x5E, 0xC2, 0xC2, 0x0F, 0x83, 0x96, 0x42, 0x5A, 0x2B, 0x1A, 0xCC, 0x57, 0xB0, 0x8D, 0x96, 0x68, 0xC3, 0x99, 0x16, 0x7B, 0x46, 0x8E, 0x07, 0x36, 0xB3, 0x3D, 0x46, 0x97, 0xB2, 0x22, 0x55, 0x24, 0x34, 0x82, 0x2A, 0xB6, 0x5B, 0x06, 0x5F, 0x8C, 0x18, 0x57, 0x58, 0xAC, 0xBC, 0x98, 0xA8, 0xB6, 0x47, 0xDA, 0x05, 0x27, 0x96, 0x61, 0xC4, 0xEF, 0x63, 0xD8, 0xB9, 0x91, 0x2B, 0x0D, 0x29, 0xF3, 0x32, 0x45, 0xD0, 0x5E, 0x8D, 0xFD, 0x79, 0x5C, 0x6C, 0x89, 0x7F, 0x3C, 0xEF, 0xF4, 0x23, 0x8C, 0x1E, 0xFA, 0x1D, 0xEF, 0xD4, 0xA5, 0x49, 0x98, 0xD4, 0x77, 0x5D, 0x08, 0xA9, 0xD1, 0xF5, 0xE7, 0x11, 0x54, 0x14, 0x6F, 0xCC, 0xE7, 0x59, 0x0B, 0x1F, 0x7E, 0xEE, 0x85, 0x15, 0x55, 0xC0, 0x63, 0xB7, 0xC7, 0xCC, 0xCD, 0x01, 0xD1, 0x43, 0x3E, 0x07, 0x3E, 0x3E, 0x13, 0xDA, 0x20, 0x44, 0x28, 0x93, 0xDF, 0xBB, 0x37, 0xAF, 0xBA, 0xCD, 0x27, 0x14, 0xEB, 0x43, 0xB4, 0xAD, 0xAC, 0xA2, 0x62, 0x16, 0xF1, 0x4B, 0xFC, 0xDD, 0x71, 0xCF, 0x0A, 0xA3, 0x43, 0xA6, 0x91, 0xF9, 0x91, 0x69, 0xF3, 0x01, 0x5D, 0x01, 0x96, 0x72, 0x67, 0x84, 0x12, 0x12, 0x8A, 0x71, 0x6F, 0x93, 0xA7, 0x38, 0xD7, 0x20, 0x43, 0x72, 0xF1, 0x64, 0xD6, 0xC8, 0x05, 0x6D, 0xDF, 0x11, 0x88, 0x8A, 0x3E, 0xFA, 0x15, 0xFE, 0xD6, 0x61, 0x2A, 0x1F, 0xFA, 0xBF, 0x06, 0x81, 0x3F, 0x74, 0x33, 0x04, 0xB9, 0xDD, 0x41, 0xD6, 0x75, 0x2D, 0x43, 0x3C, 0xAC, 0xA9, 0xE5, 0x42, 0xD1, 0x8B, 0x47, 0x6B, 0x80, 0x4F, 0x73, 0xB9, 0x0A, 0x2A, 0x4E, 0x7B, 0x50, 0x3F, 0xC2, 0xD0, 0x41, 0x8D, 0xC8, 0x19, 0x21, 0x60, 0x10, 0xA8, 0x6E, 0x8F, 0x45, 0x15, 0x3C, 0xC5, 0xAE, 0xD1, 0xE2, 0x3A, 0xF6, 0x84, 0x89, 0xFA, 0x37, 0x5C, 0x7F, 0x51, 0x81, 0x49, 0xA6, 0xB7, 0x07, 0xCD, 0x6E, 0x52, 0xF6, 0x99, 0xF8, 0x3F, 0x01, 0xEC, 0xFF, 0x69, 0x21, 0x2B, 0x85, 0x30, 0xC8, 0xBE, 0x5E, 0x25, 0x29, 0x6E, 0x24, 0xE0, 0x98, 0xAB, 0xD9, 0x45, 0x5F, 0x34, 0x0B, 0xD5, 0x75, 0x54, 0x72, 0x5E, 0x23, 0x71, 0x7D, 0x53, 0xA0, 0xA2, 0xC5, 0x0A, 0x84, 0x78, 0x00, 0xE3, 0x82, 0x29, 0x49, 0xDD, 0x52, 0xC1, 0x70, 0x00, 0x50, 0xE3, 0xB7, 0xE4, 0xE0, 0xF0, 0x84, 0x63, 0xBF, 0x15, 0xAD, 0xC3, 0x21, 0xE9, 0x51, 0xDE, 0xA6, 0x7E, 0x87, 0x04, 0x9B, 0x98, 0x0D, 0x54, 0x50, 0x33, 0x71, 0x42, 0x89, 0x47, 0x6F, 0xF3, 0x4D, 0x42, 0xD0, 0x61, 0xF8, 0x4A, 0x68, 0x47, 0xFD, 0x5C, 0xA2, 0xC4, 0x4C, 0x3A, 0x3F, 0xDB, 0xEA, 0x68, 0x99, 0x95, 0x7C, 0xBA, 0x96, 0x0B, 0xA9, 0x12, 0x5A, 0x03, 0x26, 0xA6, 0x04, 0xC2, 0x57, 0xAC, 0xFE, 0xE8, 0x29, 0xD9, 0x66, 0x0D, 0xDE, 0x12, 0x53, 0x9C, 0xD6, 0x72, 0x9D, 0x33, 0xA0, 0x5C, 0x83, 0x57, 0x75, 0xDD, 0x6C, 0xD7, 0x32, 0x6E, 0x07, 0xD5, 0x2F, 0xE2, 0xDF, 0xED, 0xF6, 0xBB, 0xF9, 0xA8, 0x02, 0x72, 0xC2, 0x5A, 0x90, 0x5A, 0xD9, 0x2B, 0x5D, 0x75, 0x27, 0xD5, 0xA2, 0x22, 0xBA, 0x82, 0xC9, 0xCD, 0x28, 0xE4, 0xDF, 0xE8, 0x99, 0xAC, 0x17, 0x9F, 0x1F, 0x63, 0xFE, 0x08, 0xA9, 0x86, 0x65, 0x15, 0x41, 0x02, 0xA0, 0xFC, 0xD0, 0xCF, 0xB6, 0x16, 0x62, 0xDB, 0x95, 0x56, 0x52, 0x34, 0xBB, 0xE1, 0xAB, 0x3A, 0xF9, 0x45, 0xE3, 0x78, 0x23, 0x30, 0xAC, 0x78, 0xD8, 0x4F, 0x8C, 0x85, 0x0B, 0xA3, 0x60, 0xA2, 0xFB, 0xB8, 0x06, 0x2C, 0xB5, 0xBA, 0xA8, 0xCA, 0xF5, 0x0F, 0x8C, 0xF8, 0x04, 0x24, 0x66, 0x42, 0x0B, 0x4E, 0x56, 0xD5, 0xD1, 0x5C, 0x49, 0xBA, 0xE5, 0x24, 0xA4, 0x5C, 0x04, 0x45, 0x60, 0x64, 0xC2, 0xF4, 0x54, 0x35, 0xDD, 0x1A, 0xBB, 0xA2, 0x49, 0x45, 0x34, 0xE4, 0xD1, 0xEF, 0xCD, 0x39, 0x8D, 0xE0, 0xC4, 0xA7, 0x77, 0xD1, 0x61, 0xE2, 0x3E, 0xB6, 0xC9, 0x74, 0xED, 0xED, 0xDF, 0x08, 0xF0, 0xA9, 0xC7, 0x58, 0x04, 0xCC, 0xD7, 0x3A, 0x0D, 0xD3, 0x2C, 0xF4, 0x6A, 0xBD, 0x5F, 0x9E, 0xF1, 0x22, 0x63, 0x27, 0xB7, 0x35, 0x5C, 0xF3, 0x45, 0xAD, 0x09, 0xF8, 0x57, 0xB9, 0x65, 0x3C, 0xDC, 0x1A, 0x4B, 0xF0, 0xF4, 0xC7, 0xAA, 0xC1, 0xF3, 0xDF, 0xB0, 0xA9, 0xE1, 0x04, 0x8E, 0xBE, 0x0C, 0xBA, 0xB1, 0x72, 0xA3, 0xB0, 0x29, 0x89, 0xCD, 0x6E, 0x63, 0x06, 0x22, 0xE8, 0x74, 0x4C, 0x2F, 0x98, 0x96, 0xB4, 0x40, 0x4D, 0x3A, 0x0B, 0xC2, 0x7C, 0x05, 0x09, 0xE3, 0xAA, 0x9A, 0x3B, 0x5D, 0x17, 0x1E, 0x91, 0x85, 0x45, 0xAF, 0xB2, 0xE9, 0xC0, 0xB6, 0xEC, 0x5D, 0x3E, 0x50, 0x07, 0x5B, 0x0D, 0x4C, 0x4E, 0x71, 0xD7, 0x8D, 0x85, 0x3E, 0xAE, 0xFA, 0xA5, 0x9B, 0xED, 0x8C, 0xB9, 0x0D, 0x2B, 0xD6, 0x2A, 0x04, 0x22, 0xB3, 0x6A, 0x88, 0x80, 0x7B, 0x65, 0x21, 0xF4, 0xCB, 0xA0, 0xC3, 0x66, 0x70, 0x5B, 0x11, 0x8E, 0x14, 0x83, 0x1E, 0xD6, 0xCD, 0x78, 0xE3, 0xB2, 0x72, 0x16, 0xDD, 0xE4, 0x05, 0xAE, 0xEE, 0x96, 0xA0, 0x1A, 0xF1, 0x1D, 0x72, 0x40, 0x03, 0x95, 0x72, 0x7E, 0x7A, 0x93, 0x0C, 0xC7, 0x72, 0x88, 0x18, 0x68, 0xC7, 0xFA, 0xBD, 0x34, 0xF5, 0xB5, 0x39, 0x2C, 0x76, 0xA0, 0x24, 0x00, 0xDC, 0xCC, 0xEF, 0xED, 0xF2, 0x7B, 0xD9, 0x8C, 0xAD, 0xA7, 0x5E, 0x0E, 0x2E, 0x1E, 0xDE, 0x18, 0x99, 0x29, 0x08, 0xE4, 0x6D, 0x81, 0x93, 0x81, 0x04, 0xB7, 0xD8, 0xE3, 0x19, 0x13, 0x29, 0x55, 0xA3, 0xC8, 0x0C, 0x93, 0x8E, 0x87, 0x73, 0xD5, 0x93, 0x27, 0x75, 0x99, 0xF8, 0xC9, 0x57, 0xBD, 0x72, 0xE6, 0xC3, 0x3C, 0xF5, 0x2D, 0xEB, 0x84, 0xA1, 0x36, 0x2D, 0xAC, 0x0A, 0x49, 0xED, 0xE1, 0x80, 0x23, 0x49, 0x5C, 0x50, 0x8C, 0x79, 0x31, 0x93, 0x79, 0xAF, 0xC2, 0xD8, 0x23, 0x2A, 0x8F, 0x6C, 0x19, 0xAD, 0x0E, 0x35, 0x7E, 0xE1, 0xD7, 0x10, 0x66, 0x48, 0x76, 0xFC, 0x90, 0x2D, 0xB9, 0x3B, 0x1A, 0x0C, 0x1E, 0x25, 0xBB, 0xF1, 0x02, 0x27, 0xC1, 0x53, 0xC6, 0xF9, 0x8C, 0x14, 0xDA, 0xB8, 0x6C, 0x7A, 0x90, 0x53, 0xFC, 0x81, 0xC7, 0x32, 0xB0, 0x5D, 0x9F, 0x1F, 0x9F, 0x69, 0xB6, 0xE0, 0x86, 0xAB, 0xFF, 0xB8, 0xD9, 0x0D, 0xA2, 0x72, 0xFA, 0x6C, 0x2B, 0x9D, 0x5C, 0x90, 0xFA, 0xCD, 0x34, 0xDD, 0x8F, 0x96, 0xCC, 0x81, 0x60, 0xB6, 0x8D, 0x5C, 0xB2, 0x7C, 0xCB, 0xD3, 0x5B, 0x48, 0xBF, 0xE6, 0x83, 0xCB, 0x7C, 0x12, 0x6C, 0xF4, 0x97, 0x68, 0x72, 0xAA, 0x46, 0x9D, 0x77, 0xB4, 0x1D, 0x43, 0x23, 0x90, 0x68, 0xDC, 0x37, 0x56, 0x31, 0x84, 0x17, 0x7E, 0xD5, 0x73, 0xA4, 0x78, 0x3E, 0x0B, 0xB8, 0xCF, 0xE4, 0x50, 0x68, 0x44, 0x6C, 0xCD, 0xBC, 0x39, 0xEA, 0x8A, 0x6D, 0x52, 0x25, 0xF4, 0x69, 0x7C, 0x28, 0x47, 0x21, 0xE8, 0xEC, 0xA8, 0x26, 0x13, 0x56, 0x87, 0xDC, 0x28, 0x58, 0xE6, 0xCC, 0x73, 0x85, 0xBF, 0xD7, 0x43, 0xA4, 0x62, 0xEC, 0x80, 0xA6, 0x8F, 0x3A, 0xB2, 0xA8, 0xAE, 0x47, 0x32, 0x25, 0x52, 0x15, 0x60, 0xFB, 0x27, 0x0E, 0xEE, 0xBA, 0x33, 0x4B, 0x4E, 0x48, 0x00, 0x47, 0xDA, 0x1E, 0x40, 0x98, 0xE6, 0x94, 0x7A, 0xB1, 0x2B, 0xE9, 0x53, 0xB3, 0x95, 0x90, 0xFF, 0x82, 0x57, 0x73, 0xC8, 0xCE, 0x23, 0x18, 0x5E, 0x15, 0x7D, 0xA9, 0x27, 0x13, 0x0E, 0xCD, 0x74, 0x8E, 0x47, 0xB6, 0x2C, 0xA9, 0x80, 0x0A, 0x8D, 0x5F, 0x67, 0x29, 0xCE, 0x3B, 0x8E, 0x94, 0xF5, 0x55, 0xFB, 0xE3, 0x44, 0x6A, 0xA6, 0xE6, 0xCB, 0x0F, 0xC6, 0xCF, 0xDD, 0xA1, 0x8E, 0x61, 0x7B, 0xBB, 0x86, 0xE0, 0xBE, 0xD6, 0x36, 0xD9, 0x04, 0xAC, 0x41, 0xB2, 0xB2, 0x03, 0x66, 0x3E, 0x44, 0x57, 0x2D, 0x7C, 0x8B, 0x88, 0x4D, 0x37, 0x4B, 0xA6, 0x65, 0x18, 0x12, 0xB4, 0x62, 0xB5, 0xEF, 0x40, 0xB8, 0xBB, 0x0B, 0xCE, 0xFC, 0x51, 0xEE, 0x4D, 0xE4, 0xC5, 0x73, 0x35, 0xF3, 0xE1, 0xB6, 0x5B, 0xE1, 0x36, 0xF7, 0x18, 0x7C, 0x34, 0xD7, 0x08, 0xA5, 0xEF, 0x4B, 0xCC, 0x83, 0x3C, 0x6E, 0x57, 0xD7, 0xF6, 0xC2, 0xBD, 0x8C, 0x40, 0x48, 0xA9, 0xC9, 0x97, 0x35, 0xBE, 0x30, 0x13, 0x7C, 0xCB, 0xEF, 0xFE, 0x31, 0x92, 0x4B, 0x52, 0x06, 0x18, 0xD0, 0x8F, 0x43, 0xE5, 0x6F, 0xB5, 0xAF, 0x1A, 0x5C, 0xDD, 0x81, 0xC4, 0xCF, 0x6F, 0x74, 0x41, 0x8F, 0xA2, 0xB4, 0x22, 0xDA, 0x65, 0x53, 0x3D, 0x8B, 0xF5, 0xF8, 0xE6, 0x42, 0x4C, 0x55, 0x3C, 0x99, 0x49, 0x45, 0xEE, 0xF2, 0x5F, 0x51, 0x2E, 0x98, 0x26, 0xF7, 0xB0, 0x82, 0xEF, 0xC0, 0x55, 0x48, 0x9A, 0xF4, 0xFC, 0x78, 0x9D, 0x93, 0x6F, 0x6F, 0x9A, 0x7A, 0x53, 0x29, 0x76, 0x25, 0x87, 0x86, 0xE3, 0xDE, 0x00, 0xF3, 0x4E, 0x75, 0x08, 0xA0, 0x49, 0x51, 0xC8, 0x0D, 0xCA, 0x14, 0xBC, 0xEE, 0x0F, 0x79, 0x42, 0x8D, 0x52, 0xB9, 0xAF, 0x57, 0x84, 0x6D, 0xC9, 0xD4, 0x85, 0x38, 0xF8, 0xDB, 0x52, 0x60, 0x74, 0x7C, 0xA2, 0x93, 0xBB, 0xFB, 0x2B, 0x43, 0x90, 0xD3, 0x31, 0x73, 0xD9, 0x56, 0x05, 0x37, 0x89, 0x81, 0xD0, 0x39, 0xE2, 0xB4, 0x89, 0xE3, 0xB5, 0xF2, 0x30, 0xB6, 0xB9, 0x8F, 0x3B, 0x8E, 0x4C, 0x67, 0x26, 0x2B, 0x60, 0xFF, 0xD4, 0x30, 0xEE, 0xFE, 0xB0, 0xB1, 0xCF, 0x43, 0x57, 0xFC, 0x65, 0x8D, 0xA2, 0x3C, 0xC4, 0x82, 0x81, 0x7A, 0x68, 0xAB, 0x4B, 0x2F, 0xC9, 0x73, 0xA4, 0xE6, 0xE2, 0xDF, 0x59, 0x35, 0x62, 0x24, 0x8F, 0xBD, 0xBA, 0xAD, 0x2F, 0xB5, 0x4B, 0xE0, 0xBE, 0xFA, 0x6E, 0x64, 0x7E, 0x9F, 0x9B, 0x1E, 0x34, 0x7D, 0x1A, 0x61, 0x4D, 0xE4, 0xC5, 0x87, 0x0C, 0xC9, 0x81, 0x30, 0x9B, 0x87, 0x06, 0xBD, 0xF1, 0xDB, 0x02, 0x8D, 0x04, 0xC0, 0xD5, 0xAD, 0x67, 0xE1, 0x8E, 0x6F, 0x80, 0x6B, 0xE3, 0xD8, 0x61, 0xEB, 0xA9, 0x72, 0x08, 0xDC, 0xAA, 0xF9, 0x32, 0xC9, 0x79, 0xBC, 0xA1, 0xA6, 0xD1, 0xC9, 0x8C, 0x8A, 0xE4, 0x4E, 0xE7, 0xE3, 0xF8, 0x22, 0xBD, 0x31, 0x7D, 0xEB, 0x6B, 0xB3, 0x7A, 0xCF, 0x83, 0x19, 0x29, 0x14, 0x83, 0xD5, 0x1D, 0x74, 0xE0, 0xA9, 0x95, 0x30, 0xEE, 0xC7, 0xBB, 0x30, 0x21, 0x62, 0x88, 0xB2, 0x8F, 0x89, 0x19, 0x64, 0x0C, 0xA6, 0x71, 0x8A, 0x6F, 0x81, 0x89, 0xCF, 0xAC, 0x6D, 0xD9, 0x0A, 0x4A, 0xF3, 0xC0, 0xCE, 0x07, 0x08, 0x63, 0x71, 0xF8, 0xCC, 0x98, 0x0F, 0xC2, 0xA7, 0x0B, 0x2B, 0xF6, 0x4B, 0xA4, 0xC6, 0xE2, 0xE4, 0xC3, 0x5A, 0x46, 0xBE, 0x9E, 0xCC, 0x75, 0x1A, 0xFB, 0x11, 0x7D, 0x98, 0x35, 0xA7, 0xB8, 0x27, 0xFD, 0x04, 0xEE, 0xF4, 0x4E, 0x5A, 0xEF, 0x2F, 0xE8, 0xFA, 0xD6, 0x70, 0xA9, 0x6C, 0xEE, 0x19, 0x97, 0x21, 0x22, 0x77, 0xAC, 0x1A, 0x5F, 0x45, 0x51, 0xA3, 0x23, 0x62, 0xC1, 0xB2, 0xF7, 0xC5, 0x43, 0x7B, 0x5F, 0x2E, 0x21, 0xA8, 0xD8, 0xEA, 0x30, 0x8C, 0x7D, 0xF5, 0x75, 0x4D, 0x48, 0xCF, 0x0B, 0xB2, 0xC4, 0x64, 0x6C, 0x51, 0x2E, 0x50, 0x44, 0x07, 0x5E, 0xD3, 0x85, 0x2B, 0x13, 0x16, 0xDD, 0xE1, 0x54, 0x90, 0x55, 0x54, 0x74, 0x77, 0x3F, 0x9D, 0x62, 0xB3, 0xC5, 0xCC, 0xCC, 0xBE, 0x51, 0x35, 0xB5, 0x31, 0x47, 0x2D, 0xA5, 0xF2, 0x5E, 0x64, 0x7D, 0x84, 0xE0, 0xD2, 0x19, 0x3A, 0xF3, 0x69, 0x3F, 0xEB, 0x10, 0xE9, 0xBA, 0xE8, 0x22, 0x3B, 0x5F, 0x4A, 0xE3, 0x53, 0x60, 0x18, 0x1E, 0xCB, 0x84, 0xF6, 0xE7, 0x90, 0x98, 0x35, 0x8F, 0xD5, 0x4D, 0x28, 0x39, 0x75, 0x2F, 0xBC, 0x34, 0x04, 0x8B, 0xC4, 0x3C, 0x1F, 0xE9, 0xC0, 0xB4, 0xD9, 0x9A, 0x36, 0x47, 0x09, 0xA6, 0x8C, 0x1E, 0x1E, 0x9D, 0xBE, 0x00, 0x8A, 0x2F, 0x49, 0x13, 0x61, 0x7B, 0x41, 0x6B, 0x13, 0x87, 0xE9, 0x3C, 0x9A, 0xA8, 0xAA, 0x63, 0x3B, 0x9C, 0x3E, 0xD6, 0xC7, 0x6A, 0xB5, 0xB0, 0xD3, 0x06, 0xAD, 0x73, 0x65, 0x92, 0xF6, 0x7C, 0xD1, 0x84, 0x65, 0x4D, 0x89, 0x41, 0x85, 0x5A, 0x02, 0x85, 0xD0, 0xEE, 0xF2, 0x97, 0x8C, 0xC5, 0xD6, 0xA3, 0x04, 0x5A, 0x2C, 0xEB, 0x4D, 0x5C, 0xEE, 0xCF, 0xC9, 0x13, 0x38, 0xD5, 0xB9, 0x18, 0x0B, 0x0B, 0xE7, 0xCE, 0xBC, 0x82, 0xFA, 0x0C, 0xAA, 0x28, 0x31, 0x90, 0x2A, 0x5B, 0x36, 0x58, 0x89, 0x64, 0x65, 0x28, 0x23, 0xD2, 0x5C, 0xB2, 0xC8, 0x1C, 0x3C, 0xBF, 0xFB, 0xB6, 0x91, 0x70, 0xD6, 0x67, 0xF5, 0xE5, 0x24, 0xC6, 0xED, 0xCD, 0x0C, 0x09, 0x91, 0x85, 0xE9, 0xC1, 0xCB, 0xFF, 0x57, 0xF8, 0x75, 0x56, 0x0C, 0xBD, 0xD4, 0x68, 0xE7, 0x78, 0xD9, 0x37, 0x2B, 0xDC, 0x61, 0xC1, 0xAD, 0xD1, 0x53, 0x21, 0xBD, 0xA9, 0xCC, 0xF4, 0xAF, 0xD4, 0xE1, 0xCE, 0x80, 0x10, 0x06, 0xC1, 0xED, 0xE8, 0x0E, 0xA2, 0xE2, 0x11, 0xBE, 0x68, 0x24, 0x62, 0xBC, 0xFA, 0x72, 0xDA, 0x1B, 0x58, 0x3C, 0xD7, 0x57, 0xD5, 0xC7, 0x38, 0xA7, 0x5E, 0x07, 0xC9, 0x00, 0xDB, 0x5C, 0xEE, 0xFF, 0xDF, 0xF2, 0x95, 0xD0, 0xD5, 0xA8, 0x1C, 0x46, 0x0D, 0x8B, 0xB5, 0x50, 0x9A, 0x06, 0x9D, 0x50, 0x43, 0x84, 0x2A, 0x48, 0x33, 0xDA, 0x80, 0xE1, 0x4A, 0xC7, 0xAB, 0xBD, 0x5B, 0xE2, 0x48, 0xFC, 0x1E, 0x4D, 0x96, 0x8E, 0xE3, 0x8E, 0x48, 0xCE, 0xFA, 0x79, 0x05, 0x20, 0xA7, 0x40, 0x72, 0x93, 0x33, 0xF4, 0x33, 0xDA, 0xC9, 0x28, 0x38, 0x0C, 0xDF, 0x83, 0x11, 0x32, 0x80, 0x71, 0xFA, 0x95, 0x75, 0x7F, 0xA6, 0x2A, 0x93, 0x55, 0x1A, 0x58, 0x06, 0x2D, 0x14, 0x27, 0x09, 0x1A, 0x59, 0x20, 0xF7, 0x57, 0x6E, 0x2F, 0x4D, 0x6B, 0x07, 0x0B, 0x0E, 0x16, 0x3A, 0x4E, 0x58, 0x70, 0x88, 0x97, 0x9B, 0xB6, 0xC4, 0xDA, 0xDD, 0xFC, 0x09, 0x0E, 0x24, 0x27, 0x2B, 0x3B, 0x52, 0x57, 0x5E, 0x63, 0x66, 0x71, 0x7F, 0xA0, 0xF0, 0x07, 0x16, 0x37, 0x43, 0x4A, 0x4C, 0x6F, 0x78, 0x7C, 0xAC, 0xB4, 0xBF, 0xC7, 0xE4, 0xFA, 0x17, 0x2F, 0x4C, 0x83, 0x87, 0xAA, 0xB7, 0xD0, 0xF5, 0x02, 0x35, 0x3E, 0x56, 0x5F, 0x6A, 0x89, 0x91, 0xB2, 0xC2, 0xC5, 0xCF, 0xDF, 0xEE, 0x1F, 0x31, 0x52, 0x5B, 0x90, 0xA8, 0xB9, 0xC6, 0xE0, 0xEB, 0xED, 0x03, 0x45, 0x56, 0x5E, 0x6D, 0x70, 0x8F, 0x97, 0xD0, 0xD7, 0xDE, 0x04, 0x11, 0x2D, 0x30, 0x47, 0x71, 0x72, 0x8F, 0x97, 0xAE, 0xB1, 0xB6, 0xC2, 0xC8, 0xE1, 0xE4, 0xE7, 0xF1, 0xFB, 0xFC, 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, 0x10, 0x1F, 0x2E, 0x37, 0x45, 0x50, 0x5B, 0x6F, 0x00, 0x85, 0x0C, 0x10, 0x38, 0x0E, 0x88, 0x00, 0xB4, 0x00, 0x61, 0x84, 0x02, 0x26, 0x00, 0x02, 0x90, 0x80, 0x0E, 0x88, 0x88, 0x63, 0x82, 0x0B, 0x00, 0x02, 0x04, 0x21, 0x80, 0x18, 0x33, 0x60, 0x7D, 0xAE, 0xCB, 0x4F, 0xC3, 0xB6, 0xD6, 0x0E, }, }, { .name = "Dilithium Round 3, Level 3 (4-4) KAT 0 (PKCS#8/SPKI)", .version = 0, .keyform = 0, .rho_len = 0, .seed_len = 0, .tr_len = 0, .s1_len = 0, .s2_len = 0, .t0_len = 0, .t1_len = 0, .pkcs8_len = 3876, .pkcs8 = { 0x30, 0x82, 0x0F, 0x20, 0x02, 0x01, 0x00, 0x30, 0x0F, 0x06, 0x0B, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x02, 0x82, 0x0B, 0x07, 0x04, 0x04, 0x05, 0x00, 0x04, 0x82, 0x0F, 0x08, 0x30, 0x82, 0x0F, 0x04, 0x02, 0x01, 0x00, 0x03, 0x21, 0x00, 0x1C, 0x0E, 0xE1, 0x11, 0x1B, 0x08, 0x00, 0x3F, 0x28, 0xE6, 0x5E, 0x8B, 0x3B, 0xDE, 0xB0, 0x37, 0xCF, 0x8F, 0x22, 0x1D, 0xFC, 0xDA, 0xF5, 0x95, 0x0E, 0xDB, 0x38, 0xD5, 0x06, 0xD8, 0x5B, 0xEF, 0x03, 0x21, 0x00, 0x39, 0x4D, 0x16, 0x95, 0x05, 0x9D, 0xFF, 0x40, 0xAE, 0x25, 0x6C, 0x5D, 0x5E, 0xDA, 0xBF, 0xB6, 0x9F, 0x5F, 0x40, 0xF3, 0x7A, 0x58, 0x8F, 0x50, 0x53, 0x2C, 0xA4, 0x08, 0xA8, 0x16, 0x8A, 0xB1, 0x03, 0x21, 0x00, 0x87, 0xD0, 0xAD, 0x11, 0x52, 0x21, 0x10, 0x93, 0x14, 0x94, 0xBF, 0x2C, 0xAE, 0xAE, 0x36, 0x97, 0x97, 0x11, 0xBC, 0x58, 0x5B, 0x32, 0xF0, 0x8C, 0x78, 0x49, 0x6F, 0x37, 0x9D, 0x60, 0x4D, 0x53, 0x03, 0x82, 0x01, 0x81, 0x00, 0xC0, 0xA6, 0x71, 0x1A, 0x96, 0x6C, 0x11, 0x31, 0x2A, 0xD9, 0xA8, 0x21, 0xD8, 0x08, 0x65, 0x42, 0xA6, 0x00, 0xA4, 0xB4, 0x2C, 0x19, 0x40, 0x72, 0x02, 0x42, 0x62, 0x81, 0x06, 0x21, 0x0A, 0x43, 0x85, 0x23, 0x31, 0x70, 0x93, 0x08, 0x10, 0x8B, 0x18, 0x8C, 0x02, 0x24, 0x92, 0xC1, 0xB2, 0x84, 0x12, 0xC4, 0x21, 0x8B, 0x04, 0x21, 0x81, 0xC8, 0x61, 0x02, 0x48, 0x05, 0x9C, 0x92, 0x01, 0xC0, 0x34, 0x88, 0x19, 0x32, 0x6C, 0x58, 0x20, 0x46, 0x89, 0x18, 0x68, 0xA2, 0xC2, 0x8D, 0x82, 0x34, 0x6A, 0x1C, 0x09, 0x42, 0x00, 0xA2, 0x8C, 0xE3, 0xA6, 0x49, 0x1C, 0x11, 0x2C, 0xC2, 0x48, 0x12, 0xE0, 0x90, 0x21, 0x91, 0x98, 0x50, 0x62, 0xC0, 0x84, 0x62, 0x24, 0x51, 0xCA, 0x06, 0x2C, 0x64, 0x24, 0x0E, 0x1B, 0xB3, 0x31, 0x24, 0x96, 0x85, 0x4B, 0x46, 0x06, 0xDB, 0x26, 0x68, 0xC3, 0x82, 0x68, 0x44, 0x10, 0x46, 0xC9, 0xB6, 0x21, 0x14, 0x04, 0x81, 0x14, 0x45, 0x50, 0x24, 0x42, 0x08, 0x44, 0x22, 0x71, 0x0B, 0x92, 0x45, 0x9A, 0xA0, 0x81, 0x1A, 0x91, 0x70, 0x9C, 0x24, 0x10, 0x03, 0x95, 0x70, 0x04, 0xC5, 0x04, 0xC8, 0x26, 0x92, 0xD2, 0x92, 0x00, 0xC0, 0xB2, 0x60, 0xC0, 0xA2, 0x68, 0x09, 0x19, 0x0A, 0xA2, 0x30, 0x0E, 0x18, 0x89, 0x69, 0xE0, 0x00, 0x8D, 0xD8, 0x48, 0x62, 0xDA, 0x14, 0x71, 0x20, 0x18, 0x05, 0x19, 0x07, 0x44, 0x04, 0x12, 0x40, 0x9B, 0x12, 0x40, 0x11, 0x80, 0x10, 0xD1, 0x42, 0x81, 0x99, 0x28, 0x50, 0x8B, 0x10, 0x91, 0x02, 0x24, 0x64, 0xA0, 0x20, 0x6D, 0x12, 0x46, 0x21, 0x1C, 0x83, 0x8C, 0x1B, 0x47, 0x69, 0x01, 0x06, 0x90, 0xCC, 0x06, 0x24, 0x81, 0x84, 0x69, 0x20, 0x98, 0x2C, 0x24, 0x12, 0x05, 0x21, 0xB1, 0x50, 0x41, 0x36, 0x02, 0x98, 0x44, 0x6E, 0xD1, 0xA6, 0x31, 0x11, 0x05, 0x6A, 0xD3, 0xA8, 0x40, 0xCA, 0xA8, 0x4C, 0x62, 0xB0, 0x00, 0x03, 0x13, 0x4A, 0x53, 0x34, 0x46, 0x14, 0x19, 0x40, 0x04, 0xC5, 0x4C, 0xE3, 0x06, 0x69, 0x5A, 0xB0, 0x89, 0x61, 0x16, 0x8E, 0xCB, 0x10, 0x80, 0x8B, 0x16, 0x8E, 0xD9, 0x90, 0x64, 0x0B, 0x94, 0x60, 0x24, 0x83, 0x85, 0x1A, 0xB3, 0x04, 0x54, 0x26, 0x22, 0x51, 0xB8, 0x25, 0x1C, 0x42, 0x4A, 0x0B, 0x81, 0x48, 0x42, 0xC4, 0x44, 0x5A, 0x10, 0x20, 0x23, 0x80, 0x84, 0x09, 0xB7, 0x25, 0x4C, 0xC6, 0x48, 0x14, 0x85, 0x4D, 0x19, 0x38, 0x0E, 0x60, 0x16, 0x51, 0xD8, 0x32, 0x6A, 0x0A, 0x91, 0x89, 0x08, 0xC1, 0x70, 0xE0, 0x96, 0x4D, 0x18, 0x46, 0x8C, 0x01, 0x32, 0x8D, 0x91, 0xC4, 0x05, 0x4A, 0x00, 0x61, 0x23, 0x08, 0x68, 0xA2, 0x10, 0x42, 0x10, 0xA8, 0x61, 0x13, 0x06, 0x21, 0x03, 0x82, 0x01, 0x81, 0x00, 0x8A, 0x24, 0x8E, 0x62, 0x06, 0x89, 0xC9, 0xB2, 0x45, 0x08, 0x27, 0x84, 0x51, 0x20, 0x0D, 0x98, 0x04, 0x66, 0xDC, 0x42, 0x05, 0x44, 0x24, 0x85, 0x24, 0x26, 0x28, 0x22, 0x21, 0x61, 0x20, 0x16, 0x09, 0x0B, 0xA6, 0x2C, 0x0A, 0x11, 0x44, 0xE0, 0x92, 0x81, 0x58, 0x48, 0x0D, 0x42, 0x22, 0x10, 0xA0, 0x06, 0x09, 0x8B, 0x24, 0x6E, 0x81, 0x28, 0x8C, 0xC0, 0x24, 0x80, 0x90, 0x30, 0x8D, 0x84, 0x36, 0x40, 0x4C, 0xA6, 0x84, 0x50, 0x04, 0x24, 0x94, 0xB6, 0x8D, 0xA2, 0x92, 0x6D, 0x18, 0xB3, 0x44, 0xA0, 0x00, 0x85, 0xE3, 0xB8, 0x05, 0x14, 0x05, 0x04, 0xA4, 0xC2, 0x90, 0x84, 0x22, 0x81, 0xC3, 0x26, 0x2D, 0x0B, 0x20, 0x66, 0xCC, 0x90, 0x31, 0x98, 0x38, 0x28, 0x10, 0x16, 0x6C, 0xC1, 0x34, 0x45, 0xC0, 0x10, 0x22, 0x24, 0xC6, 0x88, 0x03, 0x46, 0x32, 0xD8, 0x40, 0x90, 0x1C, 0x20, 0x68, 0x04, 0x15, 0x28, 0x9A, 0x18, 0x81, 0x44, 0x98, 0x8D, 0x9C, 0x20, 0x6E, 0x9C, 0x30, 0x2C, 0xC1, 0xB8, 0x20, 0x61, 0x42, 0x21, 0x08, 0x03, 0x10, 0xA0, 0xC2, 0x8C, 0x58, 0x12, 0x85, 0x53, 0x20, 0x4C, 0x03, 0x30, 0x81, 0x4C, 0xA4, 0x8D, 0x44, 0xC0, 0x8D, 0x51, 0x40, 0x4C, 0x1C, 0xA7, 0x2C, 0x44, 0x08, 0x65, 0xA0, 0x38, 0x40, 0xDA, 0x20, 0x80, 0x81, 0x06, 0x85, 0x8C, 0x26, 0x0D, 0xE2, 0xA8, 0x8C, 0x9C, 0x44, 0x11, 0x59, 0x42, 0x28, 0xC4, 0x26, 0x04, 0x44, 0x14, 0x26, 0xA1, 0x42, 0x64, 0x08, 0xC0, 0x85, 0x11, 0x01, 0x86, 0x9B, 0x48, 0x31, 0x99, 0xB2, 0x0C, 0x80, 0x46, 0x44, 0x59, 0xA8, 0x8C, 0x00, 0x42, 0x08, 0x98, 0x82, 0x90, 0x0A, 0xB5, 0x45, 0x62, 0x24, 0x48, 0x12, 0x96, 0x05, 0x44, 0x12, 0x46, 0x00, 0xC8, 0x88, 0x13, 0xA0, 0x61, 0xE1, 0x28, 0x4D, 0x0A, 0xB9, 0x91, 0x4B, 0x96, 0x20, 0x99, 0xB8, 0x44, 0x00, 0x31, 0x4E, 0x98, 0x12, 0x85, 0x00, 0xB6, 0x01, 0x83, 0xA0, 0x0D, 0x14, 0x15, 0x0E, 0x18, 0x81, 0x10, 0x19, 0x01, 0x22, 0x4A, 0x06, 0x68, 0x1A, 0x49, 0x8D, 0xE1, 0xA2, 0x84, 0x11, 0xC6, 0x31, 0x21, 0x26, 0x25, 0x91, 0xA0, 0x6D, 0x03, 0x05, 0x24, 0xA1, 0xB6, 0x08, 0x94, 0x44, 0x72, 0x43, 0x34, 0x12, 0x5B, 0xB4, 0x20, 0x41, 0xB6, 0x50, 0xD0, 0x88, 0x8D, 0x0B, 0x07, 0x4D, 0x1C, 0x94, 0x64, 0x4C, 0x20, 0x8E, 0x8B, 0x88, 0x08, 0xE0, 0x30, 0x09, 0x44, 0x20, 0x05, 0x49, 0x86, 0x4D, 0x03, 0x13, 0x4E, 0x19, 0xC9, 0x84, 0x09, 0x37, 0x61, 0x1A, 0x43, 0x68, 0x4A, 0x80, 0x90, 0x02, 0x04, 0x31, 0x1C, 0x17, 0x42, 0x18, 0x40, 0x80, 0xC8, 0x30, 0x8E, 0xE1, 0xA2, 0x41, 0xC3, 0x34, 0x04, 0xA3, 0x28, 0x22, 0x51, 0x24, 0x71, 0x03, 0x82, 0x06, 0x81, 0x00, 0x88, 0xD6, 0xFE, 0xF4, 0x67, 0x12, 0xCA, 0x18, 0x28, 0x72, 0xAB, 0x29, 0x19, 0x67, 0x8A, 0xFF, 0x9D, 0x94, 0xE7, 0x43, 0xE0, 0x63, 0xA3, 0x9E, 0x0C, 0x35, 0xCA, 0xF7, 0x2A, 0x7F, 0x2E, 0xDA, 0x28, 0xE6, 0x58, 0x58, 0x52, 0x0D, 0x5D, 0x84, 0x67, 0xDE, 0x74, 0x7C, 0xF3, 0x40, 0x65, 0x3B, 0x52, 0xC2, 0x68, 0xF5, 0x54, 0x13, 0xF5, 0xAD, 0xDC, 0x7D, 0x49, 0x01, 0x1E, 0xC3, 0x3E, 0xDD, 0x53, 0x74, 0x23, 0xA8, 0x42, 0x88, 0x86, 0x93, 0x37, 0xAE, 0xA0, 0x78, 0x1A, 0x12, 0x42, 0x69, 0x07, 0x14, 0x51, 0x72, 0x2D, 0xB3, 0xBB, 0x8F, 0x2C, 0xE5, 0xB1, 0x55, 0x2F, 0x83, 0xD2, 0xAF, 0x07, 0xF2, 0x56, 0x13, 0x91, 0x8A, 0x9F, 0x4E, 0x6F, 0x12, 0x57, 0x60, 0x38, 0x88, 0xE5, 0x89, 0x30, 0x8C, 0xA5, 0xF9, 0x5F, 0x07, 0x14, 0x3D, 0x23, 0xBA, 0xAE, 0x17, 0x52, 0x0B, 0x36, 0xB6, 0xE0, 0xE9, 0x4F, 0xAF, 0x68, 0x45, 0xEB, 0x21, 0x31, 0xAE, 0xC3, 0x83, 0xE6, 0x3B, 0xC8, 0x64, 0x4E, 0xE5, 0xF1, 0xAC, 0xCB, 0xA8, 0x2F, 0x92, 0x11, 0xE5, 0x7A, 0xFC, 0xBF, 0x50, 0x9C, 0x11, 0x31, 0xA3, 0x74, 0x66, 0xBC, 0x91, 0xB3, 0x57, 0xDC, 0xBB, 0xBC, 0x14, 0xCC, 0xC3, 0x19, 0xC4, 0xCC, 0x6A, 0xC7, 0x5F, 0xCD, 0xC8, 0x2C, 0x65, 0x96, 0xD0, 0x77, 0x70, 0xC8, 0x27, 0x7A, 0xD3, 0x70, 0xB1, 0x92, 0xA0, 0xB4, 0xE0, 0x5F, 0x81, 0x2E, 0x0E, 0x26, 0x5D, 0x29, 0x12, 0xAA, 0x29, 0xF0, 0x3F, 0xC9, 0xF7, 0x2D, 0xFA, 0x69, 0xC9, 0xB1, 0x29, 0x1A, 0x3F, 0xC5, 0x83, 0x64, 0x2B, 0x23, 0x5F, 0x69, 0x91, 0xA9, 0x54, 0x78, 0x83, 0x47, 0xF6, 0x0A, 0x03, 0x28, 0xC4, 0x8E, 0xCE, 0xE5, 0x1B, 0xA0, 0x2D, 0xFF, 0x32, 0x3A, 0xBD, 0x91, 0x16, 0x67, 0xCB, 0x14, 0x54, 0x9B, 0x61, 0x8F, 0x1C, 0x5D, 0x25, 0x0C, 0xAC, 0x9E, 0x35, 0xE0, 0x71, 0x60, 0x19, 0x92, 0xFB, 0xEC, 0x0B, 0xAE, 0x6F, 0x74, 0x21, 0x30, 0x81, 0x40, 0x47, 0x44, 0xD1, 0x2F, 0x2A, 0x0E, 0x04, 0xBD, 0xB2, 0x65, 0xE0, 0x92, 0x4C, 0xAD, 0xA4, 0x0D, 0x1F, 0xA1, 0xF3, 0x8A, 0xCA, 0x46, 0x06, 0xBF, 0xD4, 0x57, 0x57, 0x12, 0xB8, 0x26, 0x0A, 0x45, 0x6F, 0xDD, 0xEE, 0xEF, 0xE7, 0xCA, 0x25, 0x9B, 0xCD, 0xA9, 0x7B, 0x9B, 0x93, 0x9A, 0x5F, 0xD2, 0x88, 0x9C, 0x9B, 0x49, 0xFB, 0x7D, 0x4E, 0x35, 0x53, 0xDE, 0xA6, 0x1B, 0x33, 0x39, 0xBD, 0x0E, 0x6B, 0x16, 0xBF, 0x3B, 0xB2, 0x27, 0x10, 0x3B, 0xF9, 0x20, 0x2E, 0x72, 0xDC, 0x50, 0x2E, 0x28, 0xF7, 0xCE, 0x15, 0x59, 0xA4, 0x63, 0x1F, 0x37, 0x25, 0x20, 0x32, 0x4E, 0x4E, 0xBA, 0x07, 0x54, 0x5F, 0x78, 0xBF, 0x4D, 0x94, 0xB0, 0xE5, 0xB8, 0xBF, 0x51, 0xB8, 0xF1, 0x76, 0x53, 0x3D, 0x5C, 0xFE, 0xA5, 0x23, 0x2F, 0x28, 0x3A, 0x47, 0x60, 0x5F, 0xA6, 0x5D, 0xDB, 0x17, 0xC8, 0x91, 0xC2, 0x51, 0x01, 0x1C, 0x4E, 0x98, 0xEE, 0xB6, 0xEB, 0x00, 0xCB, 0x65, 0xBA, 0x31, 0xC8, 0xF0, 0x25, 0xC8, 0x7A, 0x9F, 0xE0, 0x2D, 0xBC, 0x10, 0xC5, 0xD8, 0x3A, 0x06, 0x5E, 0xBA, 0x5D, 0x7B, 0x2A, 0x19, 0xD5, 0xA1, 0xCB, 0x2C, 0x16, 0x0A, 0xE1, 0x66, 0xE8, 0x67, 0xF2, 0xAF, 0x8C, 0x7D, 0x49, 0xD6, 0x3F, 0xB8, 0x3A, 0x61, 0x49, 0x57, 0xFC, 0x0A, 0x3B, 0x5A, 0x5C, 0x74, 0x99, 0x0E, 0x9A, 0x2B, 0x02, 0x12, 0x0C, 0x7E, 0x6D, 0xE3, 0x7E, 0x15, 0x5F, 0xB4, 0x72, 0xF5, 0x0F, 0x0A, 0x45, 0xE4, 0x7C, 0xF5, 0xF9, 0xD7, 0xA4, 0xC8, 0x29, 0x82, 0xC9, 0xDC, 0x86, 0xAE, 0x87, 0x7C, 0x3F, 0xD1, 0x88, 0x59, 0x43, 0xE4, 0x39, 0xFB, 0x00, 0x3C, 0x7A, 0x9A, 0x42, 0xF7, 0x1B, 0x4F, 0xF6, 0xF0, 0xA2, 0x8B, 0x14, 0x0C, 0xBD, 0xBA, 0x6E, 0x71, 0xB1, 0x3A, 0xC3, 0x1B, 0x23, 0xDE, 0x9E, 0xAB, 0x78, 0x37, 0xE1, 0x5A, 0x69, 0xF8, 0x33, 0xEB, 0x7B, 0x56, 0xA7, 0x1D, 0x8B, 0xC2, 0xCA, 0xF1, 0xF2, 0xA3, 0x1C, 0x34, 0x5B, 0xD5, 0xF4, 0x6E, 0xE0, 0x13, 0xA7, 0xC6, 0x89, 0x37, 0x23, 0x37, 0x19, 0x1D, 0xAA, 0x80, 0x0C, 0x0A, 0xC6, 0xC4, 0x6C, 0x9F, 0xF6, 0x88, 0xB1, 0xA0, 0x13, 0x47, 0xF2, 0x57, 0xC4, 0x74, 0xAA, 0x3D, 0x97, 0xC1, 0xD6, 0x3A, 0x8C, 0x00, 0xE0, 0xA3, 0x7B, 0x68, 0x16, 0x73, 0xF5, 0x7C, 0x1C, 0x9C, 0x8F, 0xCC, 0xD4, 0x6F, 0x17, 0x4C, 0x74, 0xA2, 0x9D, 0x84, 0xCE, 0xB7, 0x1F, 0x7E, 0x6B, 0x2F, 0x8C, 0xD2, 0xB0, 0x89, 0xED, 0x43, 0xF7, 0xC9, 0x6D, 0xAE, 0x81, 0xA2, 0x23, 0x41, 0x8C, 0x20, 0xB1, 0x6F, 0x1D, 0xF3, 0xD1, 0xA9, 0x78, 0xAE, 0x28, 0xF6, 0xDF, 0x35, 0xEC, 0x55, 0x9D, 0x04, 0xD2, 0x0E, 0xC7, 0x4B, 0x22, 0x4A, 0xEA, 0x31, 0xA2, 0x89, 0xB0, 0x15, 0xB0, 0x69, 0xE9, 0xCB, 0xBB, 0xF7, 0xCF, 0x6D, 0xE9, 0x4C, 0xFB, 0x2A, 0x96, 0xE4, 0xAE, 0x34, 0x62, 0xC9, 0x60, 0x03, 0xCD, 0xDA, 0x87, 0xDB, 0x56, 0x1A, 0xF2, 0xCE, 0x3C, 0x0B, 0xA1, 0xD9, 0x04, 0x13, 0xFD, 0xCE, 0x3C, 0xCF, 0x43, 0x90, 0xC0, 0x2C, 0x1C, 0xB9, 0xF6, 0x54, 0xF4, 0x82, 0x0E, 0xC3, 0x30, 0x15, 0x45, 0x7D, 0x4A, 0x62, 0x9F, 0xBF, 0x39, 0x41, 0x9C, 0xAB, 0x76, 0x42, 0xD6, 0x88, 0x5E, 0x10, 0x3F, 0xCE, 0x0D, 0x42, 0x06, 0xCC, 0xE7, 0xC1, 0x2C, 0x6F, 0xC4, 0x4F, 0xA3, 0x3A, 0xD0, 0x86, 0x4C, 0x33, 0x71, 0xA7, 0xCB, 0xE8, 0x20, 0xE3, 0xB3, 0x71, 0xB6, 0x56, 0xA3, 0x8F, 0x2E, 0x7F, 0xF1, 0x8F, 0xE4, 0xA5, 0x0C, 0x8A, 0xB3, 0xF8, 0x5D, 0x78, 0x3F, 0xB5, 0x78, 0x35, 0xCE, 0xD8, 0x49, 0x0B, 0x84, 0xEE, 0x0D, 0x99, 0xAF, 0x0D, 0x64, 0xC4, 0x83, 0xCE, 0xB6, 0x36, 0x6F, 0xF5, 0x4F, 0x8A, 0xC8, 0xA4, 0x0D, 0xB1, 0xAF, 0xA5, 0x73, 0xA4, 0xFB, 0x32, 0x6C, 0x74, 0xF0, 0x23, 0x6E, 0xCE, 0xF3, 0xDA, 0x71, 0x20, 0x66, 0x5C, 0xCE, 0x05, 0xDD, 0x65, 0x4B, 0x50, 0x71, 0x72, 0x3A, 0x83, 0x48, 0xE7, 0xCD, 0x77, 0x93, 0x51, 0x38, 0x19, 0xB6, 0x1C, 0xB6, 0x4E, 0x13, 0x28, 0xE8, 0xB2, 0x2E, 0x76, 0x64, 0xBD, 0x6B, 0x41, 0xB5, 0x71, 0x0D, 0x19, 0xEA, 0x88, 0x09, 0xD4, 0x45, 0x08, 0x50, 0xE9, 0x07, 0xDF, 0xC4, 0xD0, 0xB7, 0x5F, 0x58, 0x8C, 0xEC, 0xE9, 0x62, 0xE9, 0xE0, 0x93, 0x7C, 0xE1, 0x40, 0x24, 0x46, 0xA4, 0xD2, 0x89, 0x1A, 0x46, 0xE6, 0x61, 0x7F, 0xB2, 0x9D, 0x4F, 0xCD, 0x71, 0x26, 0x06, 0xF7, 0x81, 0x9E, 0xCA, 0x60, 0xF7, 0xE0, 0xD5, 0xB1, 0x9E, 0x7F, 0xFB, 0x57, 0xC7, 0x3C, 0x16, 0xFF, 0xEE, 0xB9, 0x00, 0x38, 0x41, 0x0C, 0xB9, 0xFC, 0xBB, 0x5E, 0x9D, 0x51, 0xEB, 0x3E, 0xB6, 0x29, 0x7E, 0x9F, 0xF6, 0xAB, 0x70, 0x88, 0xFE, 0x2D, 0x9B, 0x23, 0x7B, 0xC2, 0x4C, 0xF7, 0xF8, 0x29, 0x01, 0x18, 0xA5, 0xE0, 0xE0, 0x0A, 0x0B, 0x90, 0x3F, 0xB6, 0x37, 0x5C, 0x84, 0x81, 0x76, 0xCD, 0x0A, 0x8C, 0x88, 0x75, 0xCC, 0x59, 0x19, 0x9C, 0xDA, 0x11, 0xA8, 0x7A, 0x78, 0xF6, 0x5C, 0xC4, 0x04, 0x33, 0x0B, 0x08, 0x75, 0x71, 0xFD, 0x06, 0x33, 0xE2, 0x71, 0x29, 0xFD, 0xAB, 0x5A, 0x8A, 0x1F, 0x79, 0x3E, 0x52, 0x41, 0x2B, 0x00, 0x83, 0xFD, 0x5C, 0x74, 0xDB, 0x3C, 0xF6, 0x0C, 0x25, 0x43, 0xCE, 0x7C, 0x91, 0xB2, 0x80, 0x0E, 0x40, 0x20, 0x3F, 0x8D, 0x99, 0xFE, 0x5F, 0xDE, 0x5B, 0x10, 0x8E, 0x7E, 0xDC, 0x80, 0xEB, 0xB9, 0xBB, 0x34, 0x98, 0x6E, 0xC5, 0xC5, 0xA8, 0xF5, 0x80, 0xE7, 0x57, 0x52, 0x90, 0x7F, 0xF0, 0xF2, 0x94, 0xC8, 0x66, 0xC2, 0xCF, 0x1F, 0x36, 0x2E, 0x84, 0x0B, 0x68, 0x81, 0xBD, 0x43, 0x21, 0x92, 0x01, 0x78, 0x1C, 0x63, 0xB0, 0x03, 0x9A, 0x95, 0xBC, 0xFB, 0x4A, 0x0F, 0xEC, 0xE5, 0x69, 0xDF, 0x00, 0x52, 0x3C, 0xE9, 0xC0, 0x84, 0xB0, 0x22, 0xB3, 0xB0, 0x22, 0x24, 0x2E, 0x28, 0x41, 0x97, 0x96, 0xAC, 0xF0, 0xA0, 0xC9, 0x95, 0xF9, 0x48, 0xDB, 0xFF, 0xFD, 0x30, 0xD7, 0x7E, 0xD1, 0x05, 0xA3, 0xC9, 0x94, 0x3C, 0x40, 0x6B, 0x30, 0x5B, 0xC8, 0x1A, 0x6A, 0x24, 0x8A, 0x29, 0x15, 0x48, 0xF2, 0xA6, 0x7F, 0x43, 0x8D, 0x96, 0x6A, 0x57, 0xD5, 0x3F, 0x4B, 0x7B, 0xE1, 0x53, 0x54, 0xE5, 0x81, 0xBE, 0x16, 0xF7, 0xAD, 0x64, 0xD1, 0x64, 0xE8, 0x57, 0x87, 0xDF, 0x58, 0x49, 0xC8, 0x10, 0xAF, 0xC2, 0x8D, 0x06, 0x48, 0x2F, 0x44, 0x1B, 0x5F, 0xDE, 0x3D, 0xB2, 0xED, 0x36, 0xDD, 0x25, 0xAA, 0x66, 0x64, 0xD4, 0xD4, 0x3F, 0xFA, 0x32, 0xED, 0xA2, 0x56, 0x89, 0xC9, 0xF4, 0xA5, 0xD5, 0x14, 0xFC, 0x66, 0x23, 0x1C, 0x54, 0x01, 0x52, 0x09, 0x22, 0x52, 0x44, 0x38, 0xEF, 0x1D, 0xC7, 0x8D, 0x69, 0x3C, 0x97, 0x18, 0xDE, 0xBB, 0xD2, 0x43, 0x31, 0x26, 0x74, 0xC8, 0x99, 0xF1, 0x89, 0x10, 0xE3, 0x89, 0xC8, 0xEB, 0xE5, 0x05, 0x82, 0x4B, 0xCC, 0x42, 0xCD, 0x4A, 0x9A, 0xCE, 0x19, 0x37, 0x68, 0x22, 0x02, 0x19, 0x01, 0x1F, 0x3B, 0x1F, 0x33, 0x54, 0x27, 0xBF, 0xF9, 0xE8, 0xBD, 0xED, 0x5C, 0x08, 0x71, 0x1A, 0x09, 0xC2, 0xB7, 0x1C, 0xB9, 0x64, 0xC5, 0x6A, 0x83, 0x93, 0xBF, 0xD2, 0xB5, 0x6E, 0x9B, 0x6B, 0x2F, 0x51, 0x3E, 0x68, 0x25, 0x87, 0xDC, 0x1B, 0x8E, 0xD1, 0x96, 0x06, 0x63, 0x26, 0x87, 0x10, 0x25, 0x62, 0x80, 0x36, 0x70, 0x00, 0x63, 0x17, 0x6D, 0x34, 0x5D, 0xE3, 0x84, 0xE1, 0x82, 0xD6, 0xC4, 0x17, 0xA3, 0x2A, 0xB1, 0x10, 0x95, 0xEF, 0x59, 0xBB, 0x4D, 0x17, 0x1B, 0x9C, 0xF8, 0x1D, 0x17, 0xAC, 0x42, 0x66, 0x4D, 0xED, 0x93, 0x3C, 0xCB, 0x72, 0x2C, 0x69, 0x85, 0x7F, 0xFC, 0x53, 0xC8, 0xE7, 0xF2, 0x47, 0x4B, 0x0C, 0xB2, 0xDF, 0xF2, 0xDD, 0xC8, 0xA5, 0xC6, 0x01, 0xC8, 0x4A, 0x70, 0x19, 0x81, 0x19, 0x9B, 0xCC, 0xF7, 0x41, 0x12, 0xA6, 0xEC, 0x06, 0x2C, 0x4F, 0xEB, 0x60, 0x1A, 0x02, 0x8A, 0xF0, 0x10, 0x32, 0xAD, 0xB6, 0xBD, 0x15, 0xD4, 0xC2, 0xB9, 0x55, 0x0A, 0xA8, 0x50, 0xAD, 0x62, 0xCC, 0xC3, 0xA3, 0x66, 0x5D, 0x52, 0x12, 0xB1, 0x2E, 0x0F, 0xD5, 0xC5, 0x32, 0x6A, 0x1E, 0x5E, 0xB1, 0xF1, 0x0D, 0x55, 0x7D, 0x94, 0x60, 0x5E, 0x8E, 0x3F, 0x35, 0x6E, 0x08, 0xFF, 0x7F, 0xD8, 0x84, 0xED, 0x3C, 0x42, 0x05, 0x46, 0x35, 0x94, 0xC9, 0xAF, 0x2F, 0x39, 0xE4, 0xB1, 0x27, 0x46, 0x95, 0x23, 0x4B, 0x54, 0xEE, 0xCE, 0xD9, 0x3F, 0x46, 0x0E, 0xDF, 0x1A, 0x13, 0xC2, 0xCB, 0x4B, 0x17, 0xD3, 0x22, 0xF6, 0xF7, 0x9F, 0xE1, 0x6F, 0x03, 0x57, 0xC1, 0xC4, 0x73, 0x98, 0x63, 0xE7, 0x96, 0x79, 0x1F, 0x86, 0x47, 0xFA, 0xBF, 0x73, 0x0A, 0xB0, 0x0E, 0x0D, 0xA5, 0x09, 0x70, 0x6D, 0x94, 0x57, 0x17, 0x40, 0xF6, 0x1F, 0x7B, 0xAF, 0x36, 0x6D, 0x27, 0x74, 0xC9, 0xB5, 0xB8, 0xC6, 0x1D, 0xD6, 0xBE, 0x98, 0x19, 0xA6, 0x02, 0x8B, 0x26, 0x4B, 0xB2, 0xE4, 0xAE, 0xA5, 0x4B, 0x56, 0xD4, 0xEC, 0xAB, 0x5B, 0x52, 0x8C, 0xE0, 0xC0, 0xC0, 0xCC, 0xDB, 0x73, 0x02, 0x33, 0x52, 0xCB, 0x00, 0x44, 0x5B, 0xAB, 0x6F, 0x74, 0x67, 0xB4, 0x64, 0x4D, 0x43, 0x61, 0xC4, 0x64, 0xFA, 0xC6, 0xB5, 0xB1, 0x37, 0xD3, 0x23, 0x91, 0x02, 0x1B, 0x47, 0x5F, 0xCB, 0x5F, 0x31, 0x77, 0x4F, 0xD8, 0xEC, 0xAB, 0xDF, 0x65, 0x47, 0x5F, 0x25, 0x57, 0x4C, 0x65, 0x55, 0x9C, 0xB3, 0x31, 0xF4, 0x1C, 0x0F, 0x49, 0x8B, 0x74, 0xDD, 0x94, 0x1C, 0x34, 0x4C, 0x50, 0xD8, 0xE6, 0x4F, 0x95, 0x78, 0x71, 0x4A, 0x32, 0x56, 0x1F, 0xAA, 0xCE, 0xAF, 0x78, 0x14, 0x8E, 0x6D, 0xA4, 0xB5, 0x66, 0x82, 0x69, 0x25, 0x71, 0x4B, 0x17, 0x10, 0x8A, 0xFD, 0xD5, 0x46, 0x38, 0x5A, 0x3C, 0xD4, 0x54, 0xD5, 0xCA, 0xA1, 0x69, 0x60, 0x91, 0x62, 0x82, 0xA4, 0x7C, 0x43, 0x15, 0xCE, 0x23, 0x6B, 0xD9, 0xE3, 0x25, 0x5C, 0x60, 0x4E, 0xBD, 0xC3, 0x97, 0x72, 0xDB, 0x5C, 0xE0, 0xB2, 0x36, 0xA0, 0x82, 0x05, 0x05, 0x03, 0x82, 0x05, 0x01, 0x00, 0x61, 0x77, 0xE3, 0xDE, 0x0D, 0x4F, 0x1E, 0xF5, 0x84, 0x77, 0x35, 0x94, 0x7B, 0x56, 0xD0, 0x8E, 0x84, 0x1D, 0xB2, 0x44, 0x4F, 0xA2, 0xB7, 0x29, 0xAD, 0xEB, 0x14, 0x17, 0xCA, 0x7A, 0xDF, 0x42, 0xA1, 0x49, 0x0C, 0x5A, 0x09, 0x7F, 0x00, 0x27, 0x60, 0xC1, 0xFC, 0x41, 0x9B, 0xE8, 0x32, 0x5A, 0xAD, 0x01, 0x97, 0xC5, 0x2C, 0xED, 0x80, 0xD3, 0xDF, 0x18, 0xE7, 0x77, 0x42, 0x65, 0xB2, 0x89, 0x91, 0x2C, 0xEC, 0xA1, 0xBE, 0x3A, 0x90, 0xD8, 0xA4, 0xFD, 0xE6, 0x5C, 0x84, 0xC6, 0x10, 0x86, 0x4E, 0x47, 0xDE, 0xEC, 0xAE, 0x3E, 0xEA, 0x44, 0x30, 0xB9, 0x90, 0x95, 0x59, 0x40, 0x8D, 0x11, 0xA6, 0xAB, 0xDB, 0x7D, 0xB9, 0x33, 0x6D, 0xF7, 0xF9, 0x6E, 0xAB, 0x48, 0x64, 0xA6, 0x57, 0x97, 0x91, 0x26, 0x5F, 0xA5, 0x6C, 0x34, 0x8C, 0xB7, 0xD2, 0xDD, 0xC9, 0x0E, 0x13, 0x3A, 0x95, 0xC3, 0xF6, 0xB1, 0x36, 0x01, 0x42, 0x9F, 0x54, 0x08, 0xBD, 0x99, 0x9A, 0xA4, 0x79, 0xC1, 0x01, 0x81, 0x59, 0x55, 0x0E, 0xC5, 0x5A, 0x11, 0x3C, 0x49, 0x3B, 0xE6, 0x48, 0xF4, 0xE0, 0x36, 0xDD, 0x4F, 0x8C, 0x80, 0x9E, 0x03, 0x6B, 0x4F, 0xBB, 0x91, 0x8C, 0x2C, 0x48, 0x4A, 0xD8, 0xE1, 0x74, 0x7A, 0xE0, 0x55, 0x85, 0xAB, 0x43, 0x3F, 0xDF, 0x46, 0x1A, 0xF0, 0x3C, 0x25, 0xA7, 0x73, 0x70, 0x07, 0x21, 0xAA, 0x05, 0xF7, 0x37, 0x9F, 0xE7, 0xF5, 0xED, 0x96, 0x17, 0x5D, 0x40, 0x21, 0x07, 0x6E, 0x7F, 0x52, 0xB6, 0x03, 0x08, 0xEF, 0xF5, 0xD4, 0x2B, 0xA6, 0xE0, 0x93, 0xB3, 0xD0, 0x81, 0x5E, 0xB3, 0x49, 0x66, 0x46, 0xE4, 0x92, 0x30, 0xA9, 0xB3, 0x5C, 0x8D, 0x41, 0x90, 0x0C, 0x2B, 0xB8, 0xD3, 0xB4, 0x46, 0xA2, 0x31, 0x27, 0xF7, 0xE0, 0x96, 0xD8, 0x5A, 0x1C, 0x79, 0x4A, 0xD4, 0xC8, 0x92, 0x77, 0x90, 0x4F, 0xC6, 0xBF, 0xEC, 0x57, 0xB1, 0xCD, 0xD8, 0x0D, 0xF9, 0x95, 0x50, 0x30, 0xFD, 0xCA, 0x74, 0x1A, 0xFB, 0xDA, 0xC8, 0x27, 0xB1, 0x3C, 0xCD, 0x54, 0x03, 0x58, 0x8A, 0xF4, 0x64, 0x40, 0x03, 0xC2, 0x26, 0x5D, 0xFA, 0x4D, 0x41, 0x9D, 0xBC, 0xCD, 0x20, 0x64, 0x89, 0x23, 0x86, 0x51, 0x8B, 0xE9, 0xD5, 0x1C, 0x16, 0x49, 0x82, 0x75, 0xEB, 0xEC, 0xF5, 0xCD, 0xC7, 0xA8, 0x20, 0xF2, 0xC2, 0x93, 0x14, 0xAC, 0x4A, 0x6F, 0x08, 0xB2, 0x25, 0x2A, 0xD3, 0xCF, 0xB1, 0x99, 0xAA, 0x42, 0xFE, 0x0B, 0x4F, 0xB5, 0x71, 0x97, 0x5C, 0x10, 0x20, 0xD9, 0x49, 0xE1, 0x94, 0xEE, 0x1E, 0xAD, 0x93, 0x7B, 0xFB, 0x55, 0x0B, 0xB3, 0xBA, 0x8E, 0x35, 0x7A, 0x02, 0x9C, 0x29, 0xF0, 0x77, 0x55, 0x46, 0x02, 0xE1, 0xCA, 0x2F, 0x22, 0x89, 0xCB, 0x91, 0x69, 0x94, 0x1C, 0x3A, 0xAF, 0xDB, 0x8E, 0x58, 0xC7, 0xF2, 0xAC, 0x77, 0x29, 0x1F, 0xB4, 0x14, 0x7C, 0x65, 0xF6, 0xB0, 0x31, 0xD3, 0xEB, 0xA4, 0x2F, 0x2A, 0xCF, 0xD9, 0x44, 0x8A, 0x5B, 0xC2, 0x2B, 0x47, 0x6E, 0x07, 0xCC, 0xCE, 0xDA, 0x23, 0x06, 0xC5, 0x54, 0xEC, 0x9B, 0x7A, 0xB6, 0x55, 0xF1, 0xD7, 0x31, 0x8C, 0x2B, 0x7E, 0x67, 0xD5, 0xF6, 0x9B, 0xED, 0xF5, 0x60, 0x00, 0xFD, 0xA9, 0x89, 0x86, 0xB5, 0xAB, 0x1B, 0x3A, 0x22, 0xD8, 0xDF, 0xD6, 0x68, 0x16, 0x97, 0xB2, 0x3A, 0x55, 0xC9, 0x6E, 0x87, 0x10, 0xF3, 0xF9, 0x8C, 0x04, 0x4F, 0xB1, 0x5F, 0x60, 0x63, 0x13, 0xEE, 0x56, 0xC0, 0xF1, 0xF5, 0xCA, 0x0F, 0x51, 0x2E, 0x08, 0x48, 0x4F, 0xCB, 0x35, 0x8E, 0x6E, 0x52, 0x8F, 0xFA, 0x89, 0xF8, 0xA8, 0x66, 0xCC, 0xFF, 0x3C, 0x0C, 0x58, 0x13, 0x14, 0x7E, 0xC5, 0x9A, 0xF0, 0x47, 0x0C, 0x4A, 0xAD, 0x01, 0x41, 0xD3, 0x4F, 0x10, 0x1D, 0xA2, 0xE5, 0xE1, 0xBD, 0x52, 0xD0, 0xD4, 0xC9, 0xB1, 0x3B, 0x3E, 0x3D, 0x87, 0xD1, 0x58, 0x61, 0x05, 0x79, 0x67, 0x54, 0xE7, 0x97, 0x8C, 0xA1, 0xC6, 0x8A, 0x7D, 0x85, 0xDF, 0x11, 0x2B, 0x7A, 0xB9, 0x21, 0xB3, 0x59, 0xA9, 0xF0, 0x3C, 0xBD, 0x27, 0xA7, 0xEA, 0xC8, 0x7A, 0x9A, 0x80, 0xB0, 0xB2, 0x6B, 0x4C, 0x96, 0x57, 0xED, 0x85, 0xAD, 0x7F, 0xA2, 0x61, 0x6A, 0xB3, 0x45, 0xEB, 0x82, 0x26, 0xF6, 0x9F, 0xC0, 0xF4, 0x81, 0x83, 0xFF, 0x57, 0x4B, 0xCD, 0x76, 0x7B, 0x56, 0x76, 0x41, 0x3A, 0xDB, 0x12, 0xEA, 0x21, 0x50, 0xA0, 0xE9, 0x76, 0x83, 0xEE, 0x54, 0x24, 0x3C, 0x25, 0xB7, 0xEA, 0x8A, 0x71, 0x86, 0x06, 0xF8, 0x69, 0x93, 0xD8, 0xD0, 0xDA, 0xCE, 0x83, 0x4E, 0xD3, 0x41, 0xEE, 0xB7, 0x24, 0xFE, 0x3D, 0x5F, 0xF0, 0xBC, 0x8B, 0x8A, 0x7B, 0x81, 0x04, 0xBA, 0x26, 0x9D, 0x34, 0x13, 0x3A, 0x4C, 0xF8, 0x30, 0x0A, 0x2D, 0x68, 0x84, 0x96, 0xB5, 0x9B, 0x6F, 0xCB, 0xC6, 0x1A, 0xE9, 0x60, 0x62, 0xEA, 0x1D, 0x8E, 0x5B, 0x41, 0x0C, 0x56, 0x71, 0xF4, 0x24, 0x41, 0x7E, 0xD6, 0x93, 0x32, 0x9C, 0xD9, 0x83, 0x00, 0x1F, 0xFC, 0xD1, 0x00, 0x23, 0xD5, 0x98, 0x85, 0x9F, 0xB7, 0xAD, 0x5F, 0xD2, 0x63, 0x54, 0x71, 0x17, 0x10, 0x06, 0x90, 0xC6, 0xCE, 0x74, 0x38, 0x95, 0x6E, 0x6C, 0xC5, 0x7F, 0x1B, 0x5D, 0xE5, 0x3B, 0xB0, 0xDC, 0x72, 0xCE, 0x9B, 0x6D, 0xEA, 0xA8, 0x57, 0x89, 0x59, 0x9A, 0x70, 0xF0, 0x05, 0x1F, 0x1A, 0x0E, 0x25, 0xE8, 0x6D, 0x88, 0x8B, 0x00, 0xDF, 0x36, 0xBD, 0xBC, 0x93, 0xEF, 0x72, 0x17, 0xC4, 0x5A, 0xCE, 0x11, 0xC0, 0x79, 0x0D, 0x70, 0xE9, 0x95, 0x3E, 0x5B, 0x41, 0x7B, 0xA2, 0xFD, 0x9A, 0x4C, 0xAF, 0x82, 0xF1, 0xFC, 0xE6, 0xF4, 0x5F, 0x53, 0xE2, 0x15, 0xB8, 0x35, 0x5E, 0xF6, 0x1D, 0x89, 0x1D, 0xF1, 0xC7, 0x94, 0x23, 0x1C, 0x16, 0x2D, 0xD2, 0x41, 0x64, 0xB5, 0x34, 0xA9, 0xD4, 0x84, 0x67, 0xCD, 0xC3, 0x23, 0x62, 0x4C, 0x2F, 0x95, 0xD4, 0x40, 0x2F, 0xF9, 0xD6, 0x6A, 0xB1, 0x19, 0x1A, 0x81, 0x24, 0x14, 0x4A, 0xFA, 0x35, 0xD4, 0xE3, 0x1D, 0xC8, 0x6C, 0xAA, 0x79, 0x7C, 0x31, 0xF6, 0x8B, 0x85, 0x85, 0x4C, 0xD9, 0x59, 0xC4, 0xFA, 0xC5, 0xEC, 0x53, 0xB3, 0xB5, 0x6D, 0x37, 0x4B, 0x88, 0x8A, 0x9E, 0x97, 0x9A, 0x65, 0x76, 0xB6, 0x34, 0x5E, 0xC8, 0x52, 0x2C, 0x96, 0x06, 0x99, 0x02, 0x81, 0xBF, 0x3E, 0xF7, 0xC5, 0x94, 0x5D, 0x10, 0xFD, 0x21, 0xA2, 0xA1, 0xD2, 0xE5, 0x40, 0x4C, 0x5C, 0xF2, 0x12, 0x20, 0x64, 0x13, 0x91, 0xB9, 0x8B, 0xCF, 0x82, 0x53, 0x98, 0x30, 0x5B, 0x56, 0xE5, 0x8B, 0x61, 0x1F, 0xE5, 0x25, 0x32, 0x03, 0xE3, 0xDF, 0x0D, 0x22, 0x46, 0x6A, 0x73, 0xB3, 0xF0, 0xFB, 0xE4, 0x3B, 0x9A, 0x62, 0x92, 0x80, 0x91, 0x89, 0x8B, 0x8A, 0x0E, 0x5B, 0x26, 0x9D, 0xB5, 0x86, 0xB0, 0xE4, 0xDD, 0xEF, 0x50, 0xD6, 0x82, 0xA1, 0x2D, 0x2C, 0x1B, 0xE8, 0x24, 0x14, 0x9A, 0xA2, 0x54, 0xC6, 0x38, 0x1B, 0xB4, 0x12, 0xD7, 0x7C, 0x3F, 0x9A, 0xA9, 0x02, 0xB6, 0x88, 0xC8, 0x17, 0x15, 0xA5, 0x9C, 0x83, 0x95, 0x58, 0x55, 0x6D, 0x35, 0xED, 0x4F, 0xC8, 0x3B, 0x4A, 0xB1, 0x81, 0x81, 0xF4, 0x0F, 0x73, 0xDC, 0xD7, 0x68, 0x60, 0xD8, 0xD8, 0xBF, 0x94, 0x52, 0x02, 0x37, 0xC2, 0xAC, 0x0E, 0x46, 0x3B, 0xA0, 0x9E, 0x3C, 0x97, 0x82, 0x38, 0x0D, 0xC0, 0x7F, 0xE4, 0xFC, 0xBA, 0x34, 0x0C, 0xC2, 0x00, 0x34, 0x39, 0xFD, 0x23, 0x14, 0x61, 0x06, 0x38, 0x07, 0x0D, 0x6C, 0x9E, 0xEA, 0x0A, 0x70, 0xBA, 0xE8, 0x3B, 0x5D, 0x5D, 0x3C, 0x5D, 0x3F, 0xDE, 0x26, 0xDD, 0x01, 0x60, 0x6C, 0x8C, 0x52, 0x01, 0x58, 0xE7, 0xE5, 0x10, 0x40, 0x20, 0xF2, 0x48, 0xCE, 0xAA, 0x66, 0x64, 0x57, 0xC1, 0x0A, 0xEB, 0xF0, 0x68, 0xF8, 0xA3, 0xBD, 0x5C, 0xE7, 0xB5, 0x2C, 0x6A, 0xF0, 0xAB, 0xD5, 0x94, 0x4A, 0xF1, 0xAD, 0x47, 0x52, 0xC9, 0x11, 0x39, 0x76, 0x08, 0x3C, 0x03, 0xB6, 0xC3, 0x4E, 0x1D, 0x47, 0xED, 0x69, 0x64, 0x4C, 0xAD, 0x78, 0x2C, 0x2F, 0x7D, 0x05, 0xF8, 0xA1, 0x48, 0x96, 0x1D, 0x96, 0x5F, 0xA2, 0xE1, 0x72, 0x3A, 0x8D, 0xDE, 0xBC, 0x22, 0xA9, 0x0C, 0xD7, 0x83, 0xDD, 0x1F, 0x4D, 0xB3, 0x8F, 0xB9, 0xAE, 0x5A, 0x67, 0x14, 0xB3, 0xD9, 0x46, 0x78, 0x16, 0x43, 0xD3, 0x17, 0xB7, 0xDD, 0x79, 0x38, 0x1C, 0xF7, 0x89, 0xA9, 0x58, 0x8B, 0xB3, 0xE1, 0x93, 0xB9, 0x2A, 0x0B, 0x60, 0xD6, 0xB0, 0x7D, 0x04, 0x7F, 0x69, 0x84, 0xB0, 0x60, 0x9E, 0xC5, 0x75, 0x43, 0xC3, 0x94, 0xCA, 0x8D, 0x5E, 0x5B, 0xCC, 0x2A, 0x73, 0x1A, 0x79, 0x61, 0x8B, 0xD1, 0xE2, 0xE0, 0xDA, 0x87, 0x04, 0xAF, 0x98, 0xF2, 0x0F, 0x5F, 0x8F, 0x54, 0x52, 0xDD, 0xF6, 0x46, 0xB9, 0x5B, 0x34, 0x1D, 0xD7, 0xF0, 0xD2, 0xCC, 0x1F, 0xA1, 0x5B, 0xD9, 0x89, 0x5C, 0xD5, 0xB6, 0x5A, 0xA1, 0xCB, 0x94, 0xB5, 0xE2, 0xE7, 0x88, 0xFD, 0xA9, 0x82, 0x5B, 0x65, 0x66, 0x39, 0x19, 0x3D, 0x98, 0x32, 0x81, 0x54, 0xA4, 0xF2, 0xC3, 0x54, 0x95, 0xA3, 0x8B, 0x6E, 0xA0, 0xD2, 0xFF, 0xAA, 0xA3, 0x5D, 0xF9, 0x2C, 0x20, 0x3C, 0x7F, 0x31, 0xCB, 0xBC, 0xA7, 0xBD, 0x03, 0xC3, 0xC2, 0x30, 0x21, 0x90, 0xCE, 0xCD, 0x16, 0x1F, 0xD4, 0x92, 0x37, 0xE4, 0xF8, 0x39, 0xE3, 0xF3, }, .spki_len = 1350, .spki = { 0x30, 0x82, 0x05, 0x42, 0x30, 0x0F, 0x06, 0x0B, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x02, 0x82, 0x0B, 0x07, 0x04, 0x04, 0x05, 0x00, 0x03, 0x82, 0x05, 0x2D, 0x00, 0x30, 0x82, 0x05, 0x28, 0x03, 0x21, 0x00, 0x1C, 0x0E, 0xE1, 0x11, 0x1B, 0x08, 0x00, 0x3F, 0x28, 0xE6, 0x5E, 0x8B, 0x3B, 0xDE, 0xB0, 0x37, 0xCF, 0x8F, 0x22, 0x1D, 0xFC, 0xDA, 0xF5, 0x95, 0x0E, 0xDB, 0x38, 0xD5, 0x06, 0xD8, 0x5B, 0xEF, 0x03, 0x82, 0x05, 0x01, 0x00, 0x61, 0x77, 0xE3, 0xDE, 0x0D, 0x4F, 0x1E, 0xF5, 0x84, 0x77, 0x35, 0x94, 0x7B, 0x56, 0xD0, 0x8E, 0x84, 0x1D, 0xB2, 0x44, 0x4F, 0xA2, 0xB7, 0x29, 0xAD, 0xEB, 0x14, 0x17, 0xCA, 0x7A, 0xDF, 0x42, 0xA1, 0x49, 0x0C, 0x5A, 0x09, 0x7F, 0x00, 0x27, 0x60, 0xC1, 0xFC, 0x41, 0x9B, 0xE8, 0x32, 0x5A, 0xAD, 0x01, 0x97, 0xC5, 0x2C, 0xED, 0x80, 0xD3, 0xDF, 0x18, 0xE7, 0x77, 0x42, 0x65, 0xB2, 0x89, 0x91, 0x2C, 0xEC, 0xA1, 0xBE, 0x3A, 0x90, 0xD8, 0xA4, 0xFD, 0xE6, 0x5C, 0x84, 0xC6, 0x10, 0x86, 0x4E, 0x47, 0xDE, 0xEC, 0xAE, 0x3E, 0xEA, 0x44, 0x30, 0xB9, 0x90, 0x95, 0x59, 0x40, 0x8D, 0x11, 0xA6, 0xAB, 0xDB, 0x7D, 0xB9, 0x33, 0x6D, 0xF7, 0xF9, 0x6E, 0xAB, 0x48, 0x64, 0xA6, 0x57, 0x97, 0x91, 0x26, 0x5F, 0xA5, 0x6C, 0x34, 0x8C, 0xB7, 0xD2, 0xDD, 0xC9, 0x0E, 0x13, 0x3A, 0x95, 0xC3, 0xF6, 0xB1, 0x36, 0x01, 0x42, 0x9F, 0x54, 0x08, 0xBD, 0x99, 0x9A, 0xA4, 0x79, 0xC1, 0x01, 0x81, 0x59, 0x55, 0x0E, 0xC5, 0x5A, 0x11, 0x3C, 0x49, 0x3B, 0xE6, 0x48, 0xF4, 0xE0, 0x36, 0xDD, 0x4F, 0x8C, 0x80, 0x9E, 0x03, 0x6B, 0x4F, 0xBB, 0x91, 0x8C, 0x2C, 0x48, 0x4A, 0xD8, 0xE1, 0x74, 0x7A, 0xE0, 0x55, 0x85, 0xAB, 0x43, 0x3F, 0xDF, 0x46, 0x1A, 0xF0, 0x3C, 0x25, 0xA7, 0x73, 0x70, 0x07, 0x21, 0xAA, 0x05, 0xF7, 0x37, 0x9F, 0xE7, 0xF5, 0xED, 0x96, 0x17, 0x5D, 0x40, 0x21, 0x07, 0x6E, 0x7F, 0x52, 0xB6, 0x03, 0x08, 0xEF, 0xF5, 0xD4, 0x2B, 0xA6, 0xE0, 0x93, 0xB3, 0xD0, 0x81, 0x5E, 0xB3, 0x49, 0x66, 0x46, 0xE4, 0x92, 0x30, 0xA9, 0xB3, 0x5C, 0x8D, 0x41, 0x90, 0x0C, 0x2B, 0xB8, 0xD3, 0xB4, 0x46, 0xA2, 0x31, 0x27, 0xF7, 0xE0, 0x96, 0xD8, 0x5A, 0x1C, 0x79, 0x4A, 0xD4, 0xC8, 0x92, 0x77, 0x90, 0x4F, 0xC6, 0xBF, 0xEC, 0x57, 0xB1, 0xCD, 0xD8, 0x0D, 0xF9, 0x95, 0x50, 0x30, 0xFD, 0xCA, 0x74, 0x1A, 0xFB, 0xDA, 0xC8, 0x27, 0xB1, 0x3C, 0xCD, 0x54, 0x03, 0x58, 0x8A, 0xF4, 0x64, 0x40, 0x03, 0xC2, 0x26, 0x5D, 0xFA, 0x4D, 0x41, 0x9D, 0xBC, 0xCD, 0x20, 0x64, 0x89, 0x23, 0x86, 0x51, 0x8B, 0xE9, 0xD5, 0x1C, 0x16, 0x49, 0x82, 0x75, 0xEB, 0xEC, 0xF5, 0xCD, 0xC7, 0xA8, 0x20, 0xF2, 0xC2, 0x93, 0x14, 0xAC, 0x4A, 0x6F, 0x08, 0xB2, 0x25, 0x2A, 0xD3, 0xCF, 0xB1, 0x99, 0xAA, 0x42, 0xFE, 0x0B, 0x4F, 0xB5, 0x71, 0x97, 0x5C, 0x10, 0x20, 0xD9, 0x49, 0xE1, 0x94, 0xEE, 0x1E, 0xAD, 0x93, 0x7B, 0xFB, 0x55, 0x0B, 0xB3, 0xBA, 0x8E, 0x35, 0x7A, 0x02, 0x9C, 0x29, 0xF0, 0x77, 0x55, 0x46, 0x02, 0xE1, 0xCA, 0x2F, 0x22, 0x89, 0xCB, 0x91, 0x69, 0x94, 0x1C, 0x3A, 0xAF, 0xDB, 0x8E, 0x58, 0xC7, 0xF2, 0xAC, 0x77, 0x29, 0x1F, 0xB4, 0x14, 0x7C, 0x65, 0xF6, 0xB0, 0x31, 0xD3, 0xEB, 0xA4, 0x2F, 0x2A, 0xCF, 0xD9, 0x44, 0x8A, 0x5B, 0xC2, 0x2B, 0x47, 0x6E, 0x07, 0xCC, 0xCE, 0xDA, 0x23, 0x06, 0xC5, 0x54, 0xEC, 0x9B, 0x7A, 0xB6, 0x55, 0xF1, 0xD7, 0x31, 0x8C, 0x2B, 0x7E, 0x67, 0xD5, 0xF6, 0x9B, 0xED, 0xF5, 0x60, 0x00, 0xFD, 0xA9, 0x89, 0x86, 0xB5, 0xAB, 0x1B, 0x3A, 0x22, 0xD8, 0xDF, 0xD6, 0x68, 0x16, 0x97, 0xB2, 0x3A, 0x55, 0xC9, 0x6E, 0x87, 0x10, 0xF3, 0xF9, 0x8C, 0x04, 0x4F, 0xB1, 0x5F, 0x60, 0x63, 0x13, 0xEE, 0x56, 0xC0, 0xF1, 0xF5, 0xCA, 0x0F, 0x51, 0x2E, 0x08, 0x48, 0x4F, 0xCB, 0x35, 0x8E, 0x6E, 0x52, 0x8F, 0xFA, 0x89, 0xF8, 0xA8, 0x66, 0xCC, 0xFF, 0x3C, 0x0C, 0x58, 0x13, 0x14, 0x7E, 0xC5, 0x9A, 0xF0, 0x47, 0x0C, 0x4A, 0xAD, 0x01, 0x41, 0xD3, 0x4F, 0x10, 0x1D, 0xA2, 0xE5, 0xE1, 0xBD, 0x52, 0xD0, 0xD4, 0xC9, 0xB1, 0x3B, 0x3E, 0x3D, 0x87, 0xD1, 0x58, 0x61, 0x05, 0x79, 0x67, 0x54, 0xE7, 0x97, 0x8C, 0xA1, 0xC6, 0x8A, 0x7D, 0x85, 0xDF, 0x11, 0x2B, 0x7A, 0xB9, 0x21, 0xB3, 0x59, 0xA9, 0xF0, 0x3C, 0xBD, 0x27, 0xA7, 0xEA, 0xC8, 0x7A, 0x9A, 0x80, 0xB0, 0xB2, 0x6B, 0x4C, 0x96, 0x57, 0xED, 0x85, 0xAD, 0x7F, 0xA2, 0x61, 0x6A, 0xB3, 0x45, 0xEB, 0x82, 0x26, 0xF6, 0x9F, 0xC0, 0xF4, 0x81, 0x83, 0xFF, 0x57, 0x4B, 0xCD, 0x76, 0x7B, 0x56, 0x76, 0x41, 0x3A, 0xDB, 0x12, 0xEA, 0x21, 0x50, 0xA0, 0xE9, 0x76, 0x83, 0xEE, 0x54, 0x24, 0x3C, 0x25, 0xB7, 0xEA, 0x8A, 0x71, 0x86, 0x06, 0xF8, 0x69, 0x93, 0xD8, 0xD0, 0xDA, 0xCE, 0x83, 0x4E, 0xD3, 0x41, 0xEE, 0xB7, 0x24, 0xFE, 0x3D, 0x5F, 0xF0, 0xBC, 0x8B, 0x8A, 0x7B, 0x81, 0x04, 0xBA, 0x26, 0x9D, 0x34, 0x13, 0x3A, 0x4C, 0xF8, 0x30, 0x0A, 0x2D, 0x68, 0x84, 0x96, 0xB5, 0x9B, 0x6F, 0xCB, 0xC6, 0x1A, 0xE9, 0x60, 0x62, 0xEA, 0x1D, 0x8E, 0x5B, 0x41, 0x0C, 0x56, 0x71, 0xF4, 0x24, 0x41, 0x7E, 0xD6, 0x93, 0x32, 0x9C, 0xD9, 0x83, 0x00, 0x1F, 0xFC, 0xD1, 0x00, 0x23, 0xD5, 0x98, 0x85, 0x9F, 0xB7, 0xAD, 0x5F, 0xD2, 0x63, 0x54, 0x71, 0x17, 0x10, 0x06, 0x90, 0xC6, 0xCE, 0x74, 0x38, 0x95, 0x6E, 0x6C, 0xC5, 0x7F, 0x1B, 0x5D, 0xE5, 0x3B, 0xB0, 0xDC, 0x72, 0xCE, 0x9B, 0x6D, 0xEA, 0xA8, 0x57, 0x89, 0x59, 0x9A, 0x70, 0xF0, 0x05, 0x1F, 0x1A, 0x0E, 0x25, 0xE8, 0x6D, 0x88, 0x8B, 0x00, 0xDF, 0x36, 0xBD, 0xBC, 0x93, 0xEF, 0x72, 0x17, 0xC4, 0x5A, 0xCE, 0x11, 0xC0, 0x79, 0x0D, 0x70, 0xE9, 0x95, 0x3E, 0x5B, 0x41, 0x7B, 0xA2, 0xFD, 0x9A, 0x4C, 0xAF, 0x82, 0xF1, 0xFC, 0xE6, 0xF4, 0x5F, 0x53, 0xE2, 0x15, 0xB8, 0x35, 0x5E, 0xF6, 0x1D, 0x89, 0x1D, 0xF1, 0xC7, 0x94, 0x23, 0x1C, 0x16, 0x2D, 0xD2, 0x41, 0x64, 0xB5, 0x34, 0xA9, 0xD4, 0x84, 0x67, 0xCD, 0xC3, 0x23, 0x62, 0x4C, 0x2F, 0x95, 0xD4, 0x40, 0x2F, 0xF9, 0xD6, 0x6A, 0xB1, 0x19, 0x1A, 0x81, 0x24, 0x14, 0x4A, 0xFA, 0x35, 0xD4, 0xE3, 0x1D, 0xC8, 0x6C, 0xAA, 0x79, 0x7C, 0x31, 0xF6, 0x8B, 0x85, 0x85, 0x4C, 0xD9, 0x59, 0xC4, 0xFA, 0xC5, 0xEC, 0x53, 0xB3, 0xB5, 0x6D, 0x37, 0x4B, 0x88, 0x8A, 0x9E, 0x97, 0x9A, 0x65, 0x76, 0xB6, 0x34, 0x5E, 0xC8, 0x52, 0x2C, 0x96, 0x06, 0x99, 0x02, 0x81, 0xBF, 0x3E, 0xF7, 0xC5, 0x94, 0x5D, 0x10, 0xFD, 0x21, 0xA2, 0xA1, 0xD2, 0xE5, 0x40, 0x4C, 0x5C, 0xF2, 0x12, 0x20, 0x64, 0x13, 0x91, 0xB9, 0x8B, 0xCF, 0x82, 0x53, 0x98, 0x30, 0x5B, 0x56, 0xE5, 0x8B, 0x61, 0x1F, 0xE5, 0x25, 0x32, 0x03, 0xE3, 0xDF, 0x0D, 0x22, 0x46, 0x6A, 0x73, 0xB3, 0xF0, 0xFB, 0xE4, 0x3B, 0x9A, 0x62, 0x92, 0x80, 0x91, 0x89, 0x8B, 0x8A, 0x0E, 0x5B, 0x26, 0x9D, 0xB5, 0x86, 0xB0, 0xE4, 0xDD, 0xEF, 0x50, 0xD6, 0x82, 0xA1, 0x2D, 0x2C, 0x1B, 0xE8, 0x24, 0x14, 0x9A, 0xA2, 0x54, 0xC6, 0x38, 0x1B, 0xB4, 0x12, 0xD7, 0x7C, 0x3F, 0x9A, 0xA9, 0x02, 0xB6, 0x88, 0xC8, 0x17, 0x15, 0xA5, 0x9C, 0x83, 0x95, 0x58, 0x55, 0x6D, 0x35, 0xED, 0x4F, 0xC8, 0x3B, 0x4A, 0xB1, 0x81, 0x81, 0xF4, 0x0F, 0x73, 0xDC, 0xD7, 0x68, 0x60, 0xD8, 0xD8, 0xBF, 0x94, 0x52, 0x02, 0x37, 0xC2, 0xAC, 0x0E, 0x46, 0x3B, 0xA0, 0x9E, 0x3C, 0x97, 0x82, 0x38, 0x0D, 0xC0, 0x7F, 0xE4, 0xFC, 0xBA, 0x34, 0x0C, 0xC2, 0x00, 0x34, 0x39, 0xFD, 0x23, 0x14, 0x61, 0x06, 0x38, 0x07, 0x0D, 0x6C, 0x9E, 0xEA, 0x0A, 0x70, 0xBA, 0xE8, 0x3B, 0x5D, 0x5D, 0x3C, 0x5D, 0x3F, 0xDE, 0x26, 0xDD, 0x01, 0x60, 0x6C, 0x8C, 0x52, 0x01, 0x58, 0xE7, 0xE5, 0x10, 0x40, 0x20, 0xF2, 0x48, 0xCE, 0xAA, 0x66, 0x64, 0x57, 0xC1, 0x0A, 0xEB, 0xF0, 0x68, 0xF8, 0xA3, 0xBD, 0x5C, 0xE7, 0xB5, 0x2C, 0x6A, 0xF0, 0xAB, 0xD5, 0x94, 0x4A, 0xF1, 0xAD, 0x47, 0x52, 0xC9, 0x11, 0x39, 0x76, 0x08, 0x3C, 0x03, 0xB6, 0xC3, 0x4E, 0x1D, 0x47, 0xED, 0x69, 0x64, 0x4C, 0xAD, 0x78, 0x2C, 0x2F, 0x7D, 0x05, 0xF8, 0xA1, 0x48, 0x96, 0x1D, 0x96, 0x5F, 0xA2, 0xE1, 0x72, 0x3A, 0x8D, 0xDE, 0xBC, 0x22, 0xA9, 0x0C, 0xD7, 0x83, 0xDD, 0x1F, 0x4D, 0xB3, 0x8F, 0xB9, 0xAE, 0x5A, 0x67, 0x14, 0xB3, 0xD9, 0x46, 0x78, 0x16, 0x43, 0xD3, 0x17, 0xB7, 0xDD, 0x79, 0x38, 0x1C, 0xF7, 0x89, 0xA9, 0x58, 0x8B, 0xB3, 0xE1, 0x93, 0xB9, 0x2A, 0x0B, 0x60, 0xD6, 0xB0, 0x7D, 0x04, 0x7F, 0x69, 0x84, 0xB0, 0x60, 0x9E, 0xC5, 0x75, 0x43, 0xC3, 0x94, 0xCA, 0x8D, 0x5E, 0x5B, 0xCC, 0x2A, 0x73, 0x1A, 0x79, 0x61, 0x8B, 0xD1, 0xE2, 0xE0, 0xDA, 0x87, 0x04, 0xAF, 0x98, 0xF2, 0x0F, 0x5F, 0x8F, 0x54, 0x52, 0xDD, 0xF6, 0x46, 0xB9, 0x5B, 0x34, 0x1D, 0xD7, 0xF0, 0xD2, 0xCC, 0x1F, 0xA1, 0x5B, 0xD9, 0x89, 0x5C, 0xD5, 0xB6, 0x5A, 0xA1, 0xCB, 0x94, 0xB5, 0xE2, 0xE7, 0x88, 0xFD, 0xA9, 0x82, 0x5B, 0x65, 0x66, 0x39, 0x19, 0x3D, 0x98, 0x32, 0x81, 0x54, 0xA4, 0xF2, 0xC3, 0x54, 0x95, 0xA3, 0x8B, 0x6E, 0xA0, 0xD2, 0xFF, 0xAA, 0xA3, 0x5D, 0xF9, 0x2C, 0x20, 0x3C, 0x7F, 0x31, 0xCB, 0xBC, 0xA7, 0xBD, 0x03, 0xC3, 0xC2, 0x30, 0x21, 0x90, 0xCE, 0xCD, 0x16, 0x1F, 0xD4, 0x92, 0x37, 0xE4, 0xF8, 0x39, 0xE3, 0xF3, }, .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 = 2420, .sig = { 0xAF, 0x59, 0x20, 0x77, 0x46, 0x03, 0xD2, 0x0E, 0x98, 0xA7, 0x9A, 0xA3, 0xAB, 0xFA, 0x32, 0xB6, 0xE2, 0x25, 0x19, 0xE6, 0x73, 0xE3, 0x7A, 0xC4, 0xAC, 0x73, 0xFE, 0x85, 0x34, 0x1E, 0x2C, 0x29, 0x23, 0xC1, 0x99, 0x2E, 0x1B, 0x0B, 0xBE, 0x38, 0x73, 0xD7, 0xC8, 0xFC, 0x56, 0x62, 0xF2, 0x07, 0xBF, 0x58, 0xEA, 0x38, 0x1C, 0xD4, 0xA3, 0xA0, 0xC0, 0x62, 0xDE, 0xC4, 0x5B, 0xDA, 0xF8, 0xBA, 0x0A, 0xA5, 0x2B, 0xEF, 0x6F, 0xA1, 0x4F, 0x3F, 0x6C, 0xF2, 0x8F, 0x76, 0x20, 0xBF, 0x94, 0xA9, 0x2C, 0xC2, 0x7D, 0x04, 0x54, 0x14, 0xA6, 0x4D, 0x65, 0xC0, 0x14, 0x96, 0x30, 0x52, 0x80, 0x24, 0x28, 0xBF, 0x39, 0x87, 0xA2, 0xD4, 0x75, 0x16, 0xCA, 0x5C, 0x78, 0xAA, 0xB9, 0x6B, 0x7B, 0xE1, 0x1B, 0xCA, 0x5F, 0x2C, 0x5A, 0x26, 0xF3, 0xFC, 0xE3, 0xA2, 0x6E, 0x8E, 0x09, 0xA2, 0x73, 0x8F, 0x38, 0x6F, 0x75, 0xD4, 0x48, 0xF9, 0x37, 0xEF, 0x19, 0xA8, 0x46, 0xBD, 0x4D, 0xD9, 0x49, 0xCA, 0xAF, 0x36, 0xDB, 0x56, 0x29, 0x88, 0x4A, 0xF5, 0x3A, 0x02, 0x3E, 0x3F, 0x18, 0x0F, 0xE4, 0xC0, 0xFA, 0xFF, 0x7B, 0xE5, 0xDF, 0xE4, 0xE8, 0x9A, 0xDE, 0x30, 0x95, 0xA6, 0x56, 0x00, 0x42, 0x14, 0x61, 0xAD, 0x08, 0xC1, 0x29, 0xD6, 0xCE, 0xA8, 0x51, 0xBB, 0x39, 0xC0, 0xD7, 0xA7, 0xD1, 0x51, 0x40, 0x56, 0x89, 0xA0, 0x91, 0xFA, 0x4D, 0xEB, 0xAC, 0x37, 0x3C, 0xF5, 0x4A, 0xE0, 0x78, 0xF0, 0xAF, 0x75, 0x57, 0xBB, 0xC6, 0xF0, 0x6A, 0x53, 0x5A, 0xE8, 0x94, 0x9E, 0x0C, 0x65, 0x30, 0x8A, 0x59, 0x84, 0x00, 0x72, 0x37, 0x52, 0x95, 0x80, 0x2D, 0x0E, 0x2C, 0xE9, 0xA3, 0xDA, 0x98, 0x42, 0x6A, 0x00, 0xFF, 0x03, 0xFE, 0x80, 0x21, 0x8C, 0x0E, 0xEC, 0x8E, 0xFE, 0x58, 0x1C, 0xB9, 0xCC, 0x9A, 0x7D, 0x66, 0xB2, 0x06, 0x45, 0xA8, 0xCD, 0x04, 0x90, 0xD3, 0xCE, 0x4F, 0x7E, 0x6F, 0xEA, 0xE9, 0xC9, 0xEB, 0x7A, 0x57, 0xF9, 0x64, 0xD0, 0xEB, 0xC7, 0xC9, 0x0B, 0x7A, 0x9F, 0x86, 0x30, 0x0B, 0x3E, 0x80, 0x95, 0xE6, 0x4D, 0x12, 0x94, 0xCF, 0xC4, 0xB4, 0xD9, 0xE2, 0x72, 0xE8, 0xFA, 0x8D, 0xB5, 0x70, 0x7D, 0x70, 0x04, 0xAF, 0x22, 0xDB, 0xFF, 0x9C, 0xFD, 0x48, 0x63, 0xDF, 0x57, 0x3F, 0xE0, 0x04, 0x34, 0x1D, 0xA3, 0xCD, 0x4A, 0x30, 0x82, 0x53, 0x2C, 0x26, 0x20, 0x45, 0x5F, 0xA3, 0x7C, 0x56, 0x2B, 0xAF, 0xD5, 0x68, 0x4E, 0xA1, 0x28, 0xAF, 0xC7, 0x9E, 0x01, 0xFC, 0x9B, 0x31, 0xE8, 0x43, 0x3B, 0xAD, 0x7C, 0x02, 0x9F, 0x2F, 0x13, 0xCC, 0x10, 0x59, 0x2D, 0x23, 0x32, 0xE3, 0xE0, 0x8B, 0x80, 0xD3, 0x50, 0x46, 0x3D, 0xE7, 0x27, 0x50, 0xB1, 0xF8, 0x06, 0xF4, 0x93, 0xE1, 0x43, 0xBD, 0x5F, 0xCA, 0x7D, 0x16, 0x98, 0x08, 0x1B, 0x31, 0xBF, 0x87, 0x6B, 0x2A, 0x1B, 0xC9, 0xDF, 0x50, 0x95, 0x2D, 0x13, 0xB6, 0xC1, 0x32, 0x1B, 0x11, 0x11, 0x17, 0x21, 0x45, 0xA6, 0x27, 0xAE, 0x0B, 0x44, 0x27, 0xB9, 0x89, 0x75, 0xCB, 0xFF, 0xF7, 0xD6, 0x82, 0x75, 0x75, 0x4B, 0x45, 0xB6, 0x82, 0xD7, 0x09, 0xE1, 0x68, 0x52, 0x2E, 0x84, 0xFE, 0xA7, 0xDD, 0x3B, 0xB0, 0xF4, 0x15, 0x05, 0xFF, 0x71, 0x92, 0x64, 0x31, 0xD1, 0xA9, 0x0D, 0x4C, 0xBF, 0x9A, 0x52, 0x7A, 0xD4, 0xE2, 0x84, 0x97, 0x6F, 0xFF, 0x8B, 0xD9, 0xD6, 0x22, 0x4A, 0x4F, 0x26, 0x03, 0x91, 0xA9, 0x87, 0xFB, 0x6D, 0xA6, 0xEE, 0x42, 0xC2, 0xA4, 0x90, 0x0F, 0x40, 0x7C, 0xE1, 0xF0, 0x2E, 0x32, 0x24, 0x75, 0xD3, 0x13, 0xFB, 0xEB, 0xB6, 0x8C, 0x2E, 0x05, 0x73, 0x08, 0x09, 0x44, 0x8A, 0x74, 0x28, 0xA5, 0x94, 0x01, 0x39, 0xEB, 0xDF, 0x1B, 0x55, 0x56, 0xFC, 0xC5, 0xD4, 0x2E, 0x1A, 0x13, 0xF3, 0x22, 0x30, 0xCB, 0x6F, 0x07, 0x24, 0x83, 0x1D, 0x0D, 0x07, 0x1B, 0xBA, 0x5A, 0x67, 0x04, 0x80, 0x6F, 0x47, 0x5B, 0x74, 0xBA, 0x91, 0xB6, 0xE3, 0x85, 0xD4, 0x86, 0x20, 0x95, 0x8D, 0x0A, 0xB1, 0xBF, 0x2B, 0x18, 0x4E, 0x10, 0xF3, 0xE7, 0x53, 0xB7, 0x13, 0x37, 0xBE, 0x9E, 0xB6, 0x53, 0x78, 0x67, 0x85, 0xB4, 0x3A, 0xC7, 0xE5, 0xC4, 0x94, 0xAC, 0x1B, 0xCB, 0x04, 0x3D, 0x46, 0x14, 0x25, 0xB3, 0x60, 0x98, 0xAC, 0x93, 0x05, 0x5A, 0x01, 0x05, 0xAB, 0x85, 0x23, 0xB6, 0x1D, 0x02, 0x4A, 0x6E, 0x9B, 0x56, 0xA4, 0x2D, 0x3C, 0x04, 0x72, 0x65, 0x12, 0xAE, 0x4C, 0xFE, 0x05, 0x71, 0x04, 0x46, 0xB0, 0x6F, 0x69, 0x42, 0x34, 0xEE, 0x4F, 0xA8, 0xFE, 0xED, 0xDD, 0xC5, 0xF2, 0x8A, 0x65, 0xED, 0xE2, 0xEB, 0x58, 0xE9, 0x65, 0xFE, 0x36, 0x27, 0xA5, 0x71, 0xBC, 0x45, 0xB3, 0x97, 0xED, 0x09, 0x2A, 0xB4, 0xBE, 0x00, 0x04, 0x17, 0x29, 0xC4, 0xD1, 0x92, 0xFE, 0x30, 0x67, 0x82, 0x79, 0xD2, 0x23, 0xA8, 0x48, 0xCF, 0x43, 0x66, 0xE9, 0x2B, 0x3F, 0x68, 0xDE, 0xE9, 0x7C, 0x9B, 0x4A, 0x7F, 0xF2, 0x2F, 0x93, 0x7B, 0xE6, 0xC5, 0x66, 0x39, 0x96, 0x1D, 0xB2, 0x9F, 0xA3, 0xCF, 0xEC, 0xFF, 0xF2, 0x93, 0x14, 0x08, 0x86, 0xFF, 0xB9, 0x2E, 0xBC, 0x79, 0xDA, 0xB5, 0x9C, 0xEA, 0xF8, 0x69, 0xC6, 0x4F, 0x8E, 0xAF, 0x58, 0x5C, 0xE9, 0x7D, 0xD6, 0xB7, 0x8F, 0x89, 0x27, 0x72, 0xDB, 0x88, 0xA9, 0x58, 0xCF, 0x0A, 0xB5, 0x57, 0xA7, 0xFA, 0xA8, 0x3F, 0xE6, 0x21, 0x47, 0x7E, 0x2B, 0x84, 0x49, 0x7A, 0xB5, 0xA8, 0xEC, 0xF4, 0xA7, 0xBD, 0x32, 0xDF, 0xB9, 0x02, 0xF0, 0x5D, 0x2C, 0xA3, 0x10, 0x47, 0xD0, 0xF1, 0x91, 0x9A, 0xDD, 0xE1, 0xEE, 0x6D, 0xFD, 0x58, 0xE5, 0x9B, 0xC4, 0xDA, 0xB3, 0xCC, 0xBB, 0xA3, 0x6A, 0xAA, 0xF6, 0xAF, 0xCC, 0xC7, 0xB0, 0x95, 0xCA, 0x94, 0xA1, 0x95, 0xBE, 0x9A, 0x28, 0x95, 0x26, 0xB5, 0x88, 0xC3, 0xA9, 0xC5, 0x68, 0x76, 0xFC, 0x41, 0x5D, 0x52, 0x1D, 0x44, 0x2B, 0xAC, 0x02, 0x98, 0xD3, 0x02, 0x41, 0x9A, 0xD5, 0x27, 0xDA, 0x24, 0x9C, 0x2A, 0x66, 0x0C, 0xD0, 0x64, 0x21, 0x3F, 0xFA, 0xD5, 0x63, 0x18, 0x3F, 0x37, 0x97, 0x25, 0x78, 0xEE, 0xB9, 0xF7, 0x0A, 0xC6, 0x7A, 0xEE, 0x6C, 0xC2, 0xB7, 0x1F, 0x28, 0x3A, 0x95, 0x93, 0x0B, 0x55, 0x47, 0x38, 0x55, 0x57, 0x91, 0xC2, 0x5E, 0x7A, 0x39, 0x9E, 0x68, 0x56, 0x36, 0xD5, 0x8D, 0x69, 0xCB, 0x6B, 0xE7, 0x93, 0xB4, 0x5C, 0x19, 0x69, 0xE7, 0xD5, 0x61, 0x56, 0x27, 0xEB, 0xC3, 0x2E, 0xED, 0x45, 0x44, 0x0F, 0x87, 0x88, 0x0D, 0x28, 0x29, 0xFA, 0x4F, 0xC8, 0x71, 0x86, 0x61, 0x64, 0xD2, 0x59, 0xED, 0x95, 0xD2, 0x73, 0x18, 0x71, 0x01, 0x7F, 0xF5, 0x18, 0x94, 0x06, 0x6F, 0xAE, 0x1F, 0xFA, 0x6F, 0x4B, 0x4A, 0x6F, 0x84, 0xFC, 0xFF, 0xDA, 0x09, 0xE7, 0x18, 0xFA, 0x17, 0x13, 0x5E, 0xDB, 0x3F, 0x48, 0x55, 0x8D, 0x5B, 0xA6, 0x7F, 0x9E, 0x6F, 0x09, 0x00, 0x34, 0x0B, 0xD0, 0x4D, 0xFE, 0x59, 0xB7, 0xBD, 0x67, 0x74, 0x58, 0x84, 0xFB, 0x84, 0xAE, 0x3F, 0x8E, 0xE7, 0x63, 0xD2, 0x02, 0x74, 0x36, 0x52, 0xD4, 0xF7, 0x33, 0x34, 0x50, 0x58, 0x04, 0x90, 0xB9, 0xC7, 0x44, 0x93, 0x5B, 0x19, 0xC1, 0xD5, 0xFB, 0x0D, 0xB5, 0xFB, 0xB4, 0x61, 0x41, 0x13, 0x62, 0x83, 0x80, 0x37, 0xEB, 0x7E, 0xC3, 0xF6, 0x3F, 0x26, 0xC8, 0x93, 0xE7, 0xCC, 0x1C, 0x3B, 0x3F, 0x47, 0x67, 0xAB, 0xAE, 0x00, 0xFE, 0xB7, 0xBB, 0x99, 0xB1, 0x42, 0x0B, 0xB2, 0x9E, 0xA6, 0x14, 0x74, 0x78, 0x96, 0xD9, 0xED, 0xCF, 0x81, 0x07, 0xFE, 0x50, 0x4C, 0x9C, 0x30, 0x8A, 0x82, 0x64, 0xDA, 0xCE, 0x31, 0x8D, 0x87, 0xCF, 0xE4, 0x76, 0x18, 0x03, 0xE9, 0xA6, 0x0D, 0xEF, 0xA6, 0x14, 0x4A, 0xAB, 0xC1, 0xF1, 0x0A, 0x45, 0xB1, 0x40, 0xDE, 0xD7, 0x54, 0xE7, 0x35, 0x86, 0xC4, 0x67, 0xBB, 0x7B, 0xF1, 0x9E, 0xDE, 0xF2, 0x5B, 0xE0, 0xC6, 0x5E, 0x93, 0xC5, 0xE5, 0xEB, 0x8F, 0x88, 0x0C, 0xCE, 0x4A, 0x85, 0x87, 0x57, 0xF8, 0xFF, 0x56, 0x06, 0x2B, 0x10, 0x67, 0xF4, 0x10, 0x6F, 0x76, 0xB7, 0x00, 0x7F, 0x6E, 0xA6, 0xF9, 0x45, 0x04, 0x7E, 0x85, 0xBD, 0x0F, 0xAD, 0x9D, 0x26, 0x99, 0x4F, 0x67, 0x8A, 0x06, 0x12, 0xB8, 0x7C, 0xCF, 0x9C, 0x0C, 0xF9, 0xA4, 0x33, 0xD8, 0x89, 0xC9, 0x6E, 0x4C, 0x12, 0xBE, 0x37, 0x22, 0x77, 0x00, 0x5B, 0x06, 0xAD, 0x12, 0x71, 0x05, 0xD1, 0x6D, 0x8F, 0xB1, 0x42, 0xAE, 0xAE, 0x53, 0x73, 0xAB, 0xD6, 0x1D, 0x9A, 0xDC, 0xFC, 0x55, 0x50, 0xD6, 0x23, 0xCA, 0x3B, 0x88, 0x24, 0xB0, 0xE2, 0xE0, 0x8C, 0x2B, 0xF4, 0xE2, 0x84, 0x1E, 0xAC, 0x4C, 0x5D, 0xC5, 0x6C, 0xF8, 0x95, 0x4C, 0xF2, 0x07, 0xC2, 0x63, 0xF2, 0x7C, 0x9F, 0x30, 0x9F, 0x10, 0x30, 0x7C, 0x0D, 0x84, 0xA6, 0x58, 0x78, 0x42, 0x50, 0x31, 0x37, 0x5D, 0xD8, 0x10, 0xD2, 0xD7, 0xE5, 0x10, 0x98, 0xA3, 0x81, 0x43, 0x50, 0x79, 0x5C, 0x4A, 0x07, 0x7F, 0xA4, 0x0D, 0xD4, 0x4F, 0x0F, 0xA7, 0x51, 0x0F, 0x7C, 0x3F, 0x63, 0x14, 0x07, 0xCF, 0x34, 0xF6, 0x04, 0xC7, 0xB3, 0x35, 0x63, 0x2A, 0x20, 0xD2, 0xAD, 0x41, 0x9B, 0xD7, 0xCC, 0x6D, 0x42, 0x42, 0xB1, 0xC6, 0x6C, 0x35, 0xE5, 0xA5, 0xED, 0xCC, 0xB1, 0x3C, 0xA3, 0x7D, 0x3B, 0x50, 0x46, 0x5F, 0x3B, 0x4A, 0xAF, 0xF7, 0xE3, 0x16, 0x1E, 0x79, 0x36, 0x08, 0x8A, 0xE0, 0x84, 0x01, 0xFD, 0x2C, 0x37, 0xD6, 0x7A, 0x2F, 0xF9, 0x1D, 0x3E, 0x6F, 0x08, 0x68, 0x6D, 0x64, 0xBC, 0x2F, 0xC6, 0xC5, 0x71, 0x06, 0xE4, 0x9F, 0xA3, 0x84, 0xAC, 0x22, 0x21, 0x9F, 0x07, 0xEE, 0x89, 0x96, 0xCA, 0x3D, 0xFF, 0x59, 0xDC, 0xC5, 0x09, 0x2A, 0x4B, 0xAD, 0xBE, 0x87, 0xAE, 0xDE, 0x7F, 0x69, 0xA0, 0x4C, 0x79, 0xB3, 0x3B, 0xDF, 0x35, 0xD4, 0xA0, 0xE4, 0xCB, 0x4B, 0x55, 0x01, 0x9C, 0xB0, 0xBF, 0x27, 0x52, 0x95, 0xB9, 0x3B, 0xDA, 0xBE, 0xA5, 0x16, 0xCA, 0x2B, 0x61, 0x6A, 0x56, 0x91, 0x86, 0x00, 0xB7, 0x24, 0xBE, 0x7A, 0x01, 0xEC, 0x4E, 0xF5, 0x43, 0x12, 0xB3, 0x0D, 0x66, 0xF5, 0x07, 0x81, 0x5F, 0x27, 0x80, 0xFF, 0xEE, 0x7C, 0x30, 0xF8, 0x42, 0x5A, 0x92, 0x25, 0x2C, 0xE5, 0x50, 0xFA, 0xB4, 0xE9, 0x02, 0xE7, 0xB3, 0x82, 0xD4, 0x6D, 0xBD, 0x20, 0xEF, 0xE1, 0xBB, 0x0E, 0xF8, 0xA4, 0x96, 0x87, 0x3C, 0x09, 0xC4, 0xCE, 0xB0, 0x30, 0x3C, 0x7F, 0x1D, 0xAB, 0xA0, 0x10, 0x2D, 0xE9, 0x41, 0x90, 0xB6, 0xAC, 0x6D, 0xC8, 0x10, 0xF7, 0x2B, 0xCA, 0x3A, 0xA2, 0x92, 0xFF, 0x38, 0xBD, 0x51, 0xA7, 0xFA, 0xB8, 0x50, 0x9E, 0xC4, 0xFB, 0xE0, 0xEA, 0xA3, 0xC9, 0x86, 0x16, 0x6A, 0x67, 0x4B, 0x78, 0x71, 0x15, 0x5C, 0x34, 0x8C, 0x47, 0x7E, 0xF8, 0xCE, 0xDC, 0x83, 0x2B, 0x5A, 0xBE, 0xE7, 0x1A, 0x8D, 0x18, 0xD0, 0x6D, 0xD0, 0xF5, 0x22, 0x11, 0x60, 0xAB, 0xEB, 0x71, 0xE6, 0xE8, 0x2C, 0xFA, 0xBF, 0x73, 0x1E, 0xA3, 0x51, 0x5A, 0x76, 0xEF, 0x07, 0xB2, 0xC1, 0x6C, 0x63, 0xB3, 0x7F, 0x7A, 0xB7, 0x3B, 0x67, 0xF0, 0x05, 0x92, 0x9A, 0x75, 0x3E, 0x45, 0x3B, 0x93, 0x0C, 0x0A, 0xF4, 0x32, 0x27, 0x7F, 0xD7, 0x7D, 0x8A, 0x1E, 0xB8, 0x02, 0x2C, 0xDE, 0x96, 0x65, 0x76, 0x3B, 0x01, 0x4F, 0x0A, 0x67, 0x2A, 0x04, 0x16, 0x0B, 0x0A, 0x06, 0xF5, 0x54, 0x0F, 0x4C, 0x26, 0x4B, 0x7F, 0x22, 0x74, 0x06, 0x90, 0xA2, 0x35, 0x2D, 0xC8, 0x63, 0xB5, 0x88, 0x30, 0x3A, 0xD5, 0x1F, 0x0A, 0xE1, 0x62, 0xBF, 0x79, 0x79, 0x7F, 0x07, 0xB5, 0x34, 0x50, 0x1C, 0xBB, 0xFD, 0xB7, 0x13, 0xA7, 0x24, 0xAA, 0x98, 0xE1, 0x95, 0x32, 0x18, 0x71, 0x80, 0xCC, 0xFA, 0xDC, 0x6E, 0xBE, 0x31, 0x42, 0xFA, 0x7D, 0xB6, 0x6C, 0xD4, 0xDE, 0x7B, 0x9F, 0xBD, 0x4C, 0x82, 0x35, 0x68, 0x6D, 0xB6, 0x8C, 0xAF, 0x48, 0x9A, 0xFA, 0x4E, 0x1E, 0x87, 0xAE, 0xF0, 0xCE, 0xFD, 0x80, 0x37, 0xE3, 0xA5, 0x78, 0xEE, 0x62, 0xEB, 0x7F, 0x94, 0xED, 0x5B, 0xC0, 0xB5, 0x8E, 0xEA, 0x4B, 0x4C, 0x45, 0xFC, 0x56, 0xD3, 0x1D, 0x29, 0x94, 0x4D, 0x09, 0x5A, 0xC9, 0x6C, 0x29, 0x08, 0x3D, 0xA2, 0xC7, 0x71, 0x81, 0xD9, 0x7A, 0x55, 0xFE, 0x6E, 0x90, 0x3A, 0x2F, 0x27, 0x83, 0xDE, 0x0B, 0xAA, 0x5F, 0x47, 0xD7, 0x04, 0x78, 0x5C, 0x33, 0xE8, 0xD5, 0xC8, 0x7E, 0xD6, 0x1E, 0x65, 0x45, 0x91, 0x67, 0x31, 0x0E, 0xB7, 0xA9, 0x95, 0x74, 0xEF, 0x81, 0x9A, 0xE9, 0x16, 0x1A, 0x3B, 0xD0, 0x96, 0x34, 0x80, 0x3D, 0x9E, 0x1E, 0x4E, 0xC7, 0x38, 0x6D, 0x79, 0x46, 0x98, 0x45, 0x17, 0x21, 0x3A, 0xB9, 0xCF, 0x66, 0xAE, 0xA5, 0x51, 0xCC, 0x45, 0x7C, 0x39, 0xF8, 0x6A, 0xF2, 0x94, 0xCF, 0x7B, 0x07, 0x3F, 0x56, 0x3E, 0xD4, 0xDA, 0xB9, 0x41, 0x9B, 0xDF, 0x00, 0x4B, 0xD0, 0x5C, 0x92, 0xB4, 0xE8, 0x0E, 0xC3, 0xCF, 0xEA, 0xC9, 0x7E, 0x1D, 0xDA, 0x55, 0x4F, 0xDA, 0x62, 0x5C, 0x4B, 0x9B, 0x03, 0x9B, 0xAA, 0x7C, 0x5A, 0x2F, 0x6F, 0x97, 0x05, 0x77, 0x92, 0x48, 0x3C, 0xF5, 0xF8, 0x52, 0xD4, 0xC3, 0xAC, 0x71, 0xAD, 0x50, 0xF7, 0x79, 0x95, 0x3D, 0xCF, 0xE2, 0xF6, 0x3E, 0xD2, 0x35, 0xD8, 0xE1, 0xD5, 0x34, 0x5D, 0x6C, 0x6D, 0xF0, 0x55, 0x5C, 0xC2, 0x63, 0x1D, 0xEA, 0xD9, 0xB7, 0x14, 0xBC, 0x4C, 0x16, 0x50, 0x1E, 0x01, 0x26, 0x13, 0x81, 0xF3, 0x67, 0x97, 0x15, 0x34, 0x51, 0x23, 0x38, 0x8C, 0x85, 0x2D, 0x57, 0xDC, 0xF1, 0x94, 0x1D, 0x09, 0x11, 0xD4, 0x9F, 0xEA, 0x71, 0x43, 0xFD, 0x2F, 0xC3, 0x43, 0xA5, 0x07, 0x5B, 0x64, 0xCC, 0xA4, 0x82, 0x91, 0xDC, 0x28, 0xB8, 0x3F, 0x76, 0x07, 0x45, 0x89, 0xEA, 0xB2, 0x17, 0xC7, 0x84, 0x78, 0x40, 0x65, 0x2C, 0x0E, 0x3A, 0xE2, 0x78, 0xB3, 0xB6, 0xFB, 0x0D, 0x80, 0x0C, 0x5E, 0x7D, 0xB7, 0x9D, 0x5C, 0xB9, 0xCC, 0x1A, 0x87, 0x45, 0x0C, 0x00, 0xB7, 0x67, 0x78, 0x12, 0xD2, 0x2E, 0xE2, 0x0F, 0xDE, 0x8C, 0x17, 0x53, 0xA7, 0xFB, 0x93, 0xBA, 0x8B, 0xBB, 0x85, 0x95, 0xA6, 0x39, 0x3D, 0xF5, 0x4A, 0xA9, 0xCD, 0xB6, 0xE0, 0x87, 0x9A, 0x26, 0xE4, 0x9B, 0xD3, 0xB0, 0x15, 0x13, 0xC6, 0x05, 0x3A, 0x07, 0x46, 0xC8, 0x59, 0x6C, 0xE5, 0xE5, 0xB2, 0x25, 0xCF, 0xCA, 0x26, 0xAB, 0x8B, 0xF1, 0x2F, 0x1F, 0xE0, 0xA6, 0x47, 0xA9, 0xE4, 0x45, 0x30, 0x39, 0xA1, 0x22, 0x61, 0x94, 0xC4, 0x6E, 0x8B, 0x98, 0xAC, 0xD7, 0x10, 0xF1, 0x8F, 0xB7, 0xEC, 0x05, 0x47, 0x6C, 0x1C, 0xD8, 0xFC, 0x31, 0x12, 0xCC, 0xDD, 0xB1, 0x58, 0x2B, 0x88, 0x17, 0xC1, 0x8F, 0xE3, 0x15, 0x35, 0x3E, 0x7A, 0x47, 0xC8, 0x21, 0xE9, 0xEE, 0x3A, 0x43, 0xCA, 0xDE, 0x1B, 0x80, 0xD9, 0x2A, 0x0A, 0xE8, 0xDC, 0xEB, 0x4D, 0xFF, 0x76, 0x6A, 0x54, 0xDF, 0x36, 0x65, 0xFE, 0xFE, 0x3C, 0x25, 0x2B, 0x72, 0xDA, 0xD7, 0xB1, 0xE3, 0x35, 0x9E, 0x7F, 0xA2, 0x55, 0x62, 0xC3, 0xE3, 0x9D, 0xB5, 0x21, 0xCE, 0x18, 0x74, 0x11, 0x1F, 0xB0, 0x90, 0xDB, 0xD3, 0x8B, 0x31, 0x80, 0xAD, 0x03, 0x4B, 0x57, 0xB0, 0x31, 0xDC, 0x4D, 0xD6, 0xAF, 0x7C, 0x1A, 0x8A, 0xF3, 0xF6, 0xCE, 0x7E, 0xDB, 0x1A, 0x9E, 0x4B, 0x6D, 0x4A, 0x59, 0x20, 0xE3, 0x62, 0x08, 0x18, 0x82, 0x06, 0x59, 0x76, 0x2E, 0xF7, 0xA4, 0x24, 0x3F, 0x51, 0xDF, 0x2D, 0x8A, 0x90, 0x07, 0x37, 0xD5, 0x81, 0x05, 0x69, 0x9B, 0x4E, 0x10, 0xCB, 0xCB, 0x35, 0x9C, 0x7F, 0x3A, 0x40, 0x07, 0x69, 0x7C, 0x48, 0x20, 0x50, 0xEC, 0x33, 0xCF, 0x80, 0x41, 0x91, 0x6A, 0x3B, 0x91, 0x9A, 0x50, 0xD9, 0x6E, 0xF0, 0xF5, 0x89, 0xFD, 0x45, 0x56, 0xF3, 0x0D, 0xBD, 0xD9, 0x42, 0xEA, 0xB7, 0x9D, 0xFA, 0x97, 0xC0, 0x7E, 0x30, 0x24, 0x70, 0x74, 0x35, 0x2E, 0x1B, 0xF9, 0x8E, 0x34, 0x9C, 0xC7, 0xEF, 0xA5, 0xA1, 0xB8, 0xFC, 0xE4, 0xF1, 0x8F, 0x1F, 0xAF, 0x6F, 0x07, 0xC9, 0x9C, 0x32, 0x14, 0x48, 0xB0, 0x39, 0x5C, 0x8A, 0x9C, 0xBC, 0x46, 0x64, 0x12, 0xF8, 0x9C, 0x1A, 0x98, 0xBF, 0x57, 0x15, 0x84, 0x28, 0x44, 0xF0, 0xE8, 0x23, 0x6F, 0xA4, 0x69, 0x6C, 0x46, 0x58, 0xB8, 0xFD, 0xE4, 0x42, 0x5D, 0x09, 0xD6, 0x7A, 0x38, 0xAC, 0x72, 0x58, 0xE5, 0xD5, 0x96, 0x6F, 0x2D, 0x3F, 0xF6, 0x6A, 0x0C, 0x0C, 0xE7, 0x6E, 0x7F, 0x6B, 0x81, 0xA1, 0xBC, 0xD0, 0x47, 0xFD, 0x3A, 0x20, 0x5B, 0xF0, 0xCC, 0xAE, 0xA3, 0xB1, 0x10, 0x79, 0x90, 0x9C, 0x6C, 0xE5, 0x69, 0x8F, 0x32, 0xE1, 0xF3, 0x40, 0x96, 0x58, 0xFF, 0xA0, 0x1E, 0xAE, 0xCB, 0x4A, 0xE2, 0xB0, 0x92, 0xB7, 0x89, 0x89, 0xDA, 0xAD, 0x66, 0x23, 0xBB, 0x11, 0xF4, 0x9F, 0x0F, 0x8F, 0x86, 0x99, 0xEC, 0x05, 0x66, 0x15, 0x02, 0xFF, 0xCA, 0xD0, 0x3C, 0xF4, 0x15, 0x19, 0x1A, 0x22, 0x2D, 0x3C, 0x4C, 0x7B, 0x8A, 0xB0, 0xB5, 0xB9, 0xBB, 0xC2, 0xD9, 0xDC, 0xEF, 0xF7, 0x20, 0x2D, 0x3F, 0x42, 0x44, 0x49, 0x4F, 0x52, 0x53, 0x64, 0x66, 0x69, 0x74, 0xC4, 0xD9, 0xE6, 0xF5, 0xFA, 0x00, 0x01, 0x04, 0x19, 0x27, 0x37, 0x3D, 0x5A, 0x76, 0x80, 0xB8, 0xC1, 0xC9, 0xFE, 0x20, 0x29, 0x38, 0x3B, 0x3C, 0x48, 0x4D, 0x56, 0x5F, 0x65, 0x79, 0x9D, 0x9E, 0xA6, 0xA9, 0xAD, 0xD2, 0xDE, 0xE5, 0xE7, 0xF7, 0xF9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x24, 0x32, 0x48, }, }, { .name = "Dilithium Round 3, Level 3 (4-4) KAT 0", .version = 0, .keyform = CK_IBM_DILITHIUM_KEYFORM_ROUND3_44, .rho_len = 32, .rho = { 0x1C, 0x0E, 0xE1, 0x11, 0x1B, 0x08, 0x00, 0x3F, 0x28, 0xE6, 0x5E, 0x8B, 0x3B, 0xDE, 0xB0, 0x37, 0xCF, 0x8F, 0x22, 0x1D, 0xFC, 0xDA, 0xF5, 0x95, 0x0E, 0xDB, 0x38, 0xD5, 0x06, 0xD8, 0x5B, 0xEF, }, .seed_len = 32, .seed = { 0x39, 0x4D, 0x16, 0x95, 0x05, 0x9D, 0xFF, 0x40, 0xAE, 0x25, 0x6C, 0x5D, 0x5E, 0xDA, 0xBF, 0xB6, 0x9F, 0x5F, 0x40, 0xF3, 0x7A, 0x58, 0x8F, 0x50, 0x53, 0x2C, 0xA4, 0x08, 0xA8, 0x16, 0x8A, 0xB1, }, .tr_len = 32, .tr = { 0x87, 0xD0, 0xAD, 0x11, 0x52, 0x21, 0x10, 0x93, 0x14, 0x94, 0xBF, 0x2C, 0xAE, 0xAE, 0x36, 0x97, 0x97, 0x11, 0xBC, 0x58, 0x5B, 0x32, 0xF0, 0x8C, 0x78, 0x49, 0x6F, 0x37, 0x9D, 0x60, 0x4D, 0x53, }, .s1_len = 384, .s1 = { 0xC0, 0xA6, 0x71, 0x1A, 0x96, 0x6C, 0x11, 0x31, 0x2A, 0xD9, 0xA8, 0x21, 0xD8, 0x08, 0x65, 0x42, 0xA6, 0x00, 0xA4, 0xB4, 0x2C, 0x19, 0x40, 0x72, 0x02, 0x42, 0x62, 0x81, 0x06, 0x21, 0x0A, 0x43, 0x85, 0x23, 0x31, 0x70, 0x93, 0x08, 0x10, 0x8B, 0x18, 0x8C, 0x02, 0x24, 0x92, 0xC1, 0xB2, 0x84, 0x12, 0xC4, 0x21, 0x8B, 0x04, 0x21, 0x81, 0xC8, 0x61, 0x02, 0x48, 0x05, 0x9C, 0x92, 0x01, 0xC0, 0x34, 0x88, 0x19, 0x32, 0x6C, 0x58, 0x20, 0x46, 0x89, 0x18, 0x68, 0xA2, 0xC2, 0x8D, 0x82, 0x34, 0x6A, 0x1C, 0x09, 0x42, 0x00, 0xA2, 0x8C, 0xE3, 0xA6, 0x49, 0x1C, 0x11, 0x2C, 0xC2, 0x48, 0x12, 0xE0, 0x90, 0x21, 0x91, 0x98, 0x50, 0x62, 0xC0, 0x84, 0x62, 0x24, 0x51, 0xCA, 0x06, 0x2C, 0x64, 0x24, 0x0E, 0x1B, 0xB3, 0x31, 0x24, 0x96, 0x85, 0x4B, 0x46, 0x06, 0xDB, 0x26, 0x68, 0xC3, 0x82, 0x68, 0x44, 0x10, 0x46, 0xC9, 0xB6, 0x21, 0x14, 0x04, 0x81, 0x14, 0x45, 0x50, 0x24, 0x42, 0x08, 0x44, 0x22, 0x71, 0x0B, 0x92, 0x45, 0x9A, 0xA0, 0x81, 0x1A, 0x91, 0x70, 0x9C, 0x24, 0x10, 0x03, 0x95, 0x70, 0x04, 0xC5, 0x04, 0xC8, 0x26, 0x92, 0xD2, 0x92, 0x00, 0xC0, 0xB2, 0x60, 0xC0, 0xA2, 0x68, 0x09, 0x19, 0x0A, 0xA2, 0x30, 0x0E, 0x18, 0x89, 0x69, 0xE0, 0x00, 0x8D, 0xD8, 0x48, 0x62, 0xDA, 0x14, 0x71, 0x20, 0x18, 0x05, 0x19, 0x07, 0x44, 0x04, 0x12, 0x40, 0x9B, 0x12, 0x40, 0x11, 0x80, 0x10, 0xD1, 0x42, 0x81, 0x99, 0x28, 0x50, 0x8B, 0x10, 0x91, 0x02, 0x24, 0x64, 0xA0, 0x20, 0x6D, 0x12, 0x46, 0x21, 0x1C, 0x83, 0x8C, 0x1B, 0x47, 0x69, 0x01, 0x06, 0x90, 0xCC, 0x06, 0x24, 0x81, 0x84, 0x69, 0x20, 0x98, 0x2C, 0x24, 0x12, 0x05, 0x21, 0xB1, 0x50, 0x41, 0x36, 0x02, 0x98, 0x44, 0x6E, 0xD1, 0xA6, 0x31, 0x11, 0x05, 0x6A, 0xD3, 0xA8, 0x40, 0xCA, 0xA8, 0x4C, 0x62, 0xB0, 0x00, 0x03, 0x13, 0x4A, 0x53, 0x34, 0x46, 0x14, 0x19, 0x40, 0x04, 0xC5, 0x4C, 0xE3, 0x06, 0x69, 0x5A, 0xB0, 0x89, 0x61, 0x16, 0x8E, 0xCB, 0x10, 0x80, 0x8B, 0x16, 0x8E, 0xD9, 0x90, 0x64, 0x0B, 0x94, 0x60, 0x24, 0x83, 0x85, 0x1A, 0xB3, 0x04, 0x54, 0x26, 0x22, 0x51, 0xB8, 0x25, 0x1C, 0x42, 0x4A, 0x0B, 0x81, 0x48, 0x42, 0xC4, 0x44, 0x5A, 0x10, 0x20, 0x23, 0x80, 0x84, 0x09, 0xB7, 0x25, 0x4C, 0xC6, 0x48, 0x14, 0x85, 0x4D, 0x19, 0x38, 0x0E, 0x60, 0x16, 0x51, 0xD8, 0x32, 0x6A, 0x0A, 0x91, 0x89, 0x08, 0xC1, 0x70, 0xE0, 0x96, 0x4D, 0x18, 0x46, 0x8C, 0x01, 0x32, 0x8D, 0x91, 0xC4, 0x05, 0x4A, 0x00, 0x61, 0x23, 0x08, 0x68, 0xA2, 0x10, 0x42, 0x10, 0xA8, 0x61, 0x13, 0x06, 0x21, }, .s2_len = 384, .s2 = { 0x8A, 0x24, 0x8E, 0x62, 0x06, 0x89, 0xC9, 0xB2, 0x45, 0x08, 0x27, 0x84, 0x51, 0x20, 0x0D, 0x98, 0x04, 0x66, 0xDC, 0x42, 0x05, 0x44, 0x24, 0x85, 0x24, 0x26, 0x28, 0x22, 0x21, 0x61, 0x20, 0x16, 0x09, 0x0B, 0xA6, 0x2C, 0x0A, 0x11, 0x44, 0xE0, 0x92, 0x81, 0x58, 0x48, 0x0D, 0x42, 0x22, 0x10, 0xA0, 0x06, 0x09, 0x8B, 0x24, 0x6E, 0x81, 0x28, 0x8C, 0xC0, 0x24, 0x80, 0x90, 0x30, 0x8D, 0x84, 0x36, 0x40, 0x4C, 0xA6, 0x84, 0x50, 0x04, 0x24, 0x94, 0xB6, 0x8D, 0xA2, 0x92, 0x6D, 0x18, 0xB3, 0x44, 0xA0, 0x00, 0x85, 0xE3, 0xB8, 0x05, 0x14, 0x05, 0x04, 0xA4, 0xC2, 0x90, 0x84, 0x22, 0x81, 0xC3, 0x26, 0x2D, 0x0B, 0x20, 0x66, 0xCC, 0x90, 0x31, 0x98, 0x38, 0x28, 0x10, 0x16, 0x6C, 0xC1, 0x34, 0x45, 0xC0, 0x10, 0x22, 0x24, 0xC6, 0x88, 0x03, 0x46, 0x32, 0xD8, 0x40, 0x90, 0x1C, 0x20, 0x68, 0x04, 0x15, 0x28, 0x9A, 0x18, 0x81, 0x44, 0x98, 0x8D, 0x9C, 0x20, 0x6E, 0x9C, 0x30, 0x2C, 0xC1, 0xB8, 0x20, 0x61, 0x42, 0x21, 0x08, 0x03, 0x10, 0xA0, 0xC2, 0x8C, 0x58, 0x12, 0x85, 0x53, 0x20, 0x4C, 0x03, 0x30, 0x81, 0x4C, 0xA4, 0x8D, 0x44, 0xC0, 0x8D, 0x51, 0x40, 0x4C, 0x1C, 0xA7, 0x2C, 0x44, 0x08, 0x65, 0xA0, 0x38, 0x40, 0xDA, 0x20, 0x80, 0x81, 0x06, 0x85, 0x8C, 0x26, 0x0D, 0xE2, 0xA8, 0x8C, 0x9C, 0x44, 0x11, 0x59, 0x42, 0x28, 0xC4, 0x26, 0x04, 0x44, 0x14, 0x26, 0xA1, 0x42, 0x64, 0x08, 0xC0, 0x85, 0x11, 0x01, 0x86, 0x9B, 0x48, 0x31, 0x99, 0xB2, 0x0C, 0x80, 0x46, 0x44, 0x59, 0xA8, 0x8C, 0x00, 0x42, 0x08, 0x98, 0x82, 0x90, 0x0A, 0xB5, 0x45, 0x62, 0x24, 0x48, 0x12, 0x96, 0x05, 0x44, 0x12, 0x46, 0x00, 0xC8, 0x88, 0x13, 0xA0, 0x61, 0xE1, 0x28, 0x4D, 0x0A, 0xB9, 0x91, 0x4B, 0x96, 0x20, 0x99, 0xB8, 0x44, 0x00, 0x31, 0x4E, 0x98, 0x12, 0x85, 0x00, 0xB6, 0x01, 0x83, 0xA0, 0x0D, 0x14, 0x15, 0x0E, 0x18, 0x81, 0x10, 0x19, 0x01, 0x22, 0x4A, 0x06, 0x68, 0x1A, 0x49, 0x8D, 0xE1, 0xA2, 0x84, 0x11, 0xC6, 0x31, 0x21, 0x26, 0x25, 0x91, 0xA0, 0x6D, 0x03, 0x05, 0x24, 0xA1, 0xB6, 0x08, 0x94, 0x44, 0x72, 0x43, 0x34, 0x12, 0x5B, 0xB4, 0x20, 0x41, 0xB6, 0x50, 0xD0, 0x88, 0x8D, 0x0B, 0x07, 0x4D, 0x1C, 0x94, 0x64, 0x4C, 0x20, 0x8E, 0x8B, 0x88, 0x08, 0xE0, 0x30, 0x09, 0x44, 0x20, 0x05, 0x49, 0x86, 0x4D, 0x03, 0x13, 0x4E, 0x19, 0xC9, 0x84, 0x09, 0x37, 0x61, 0x1A, 0x43, 0x68, 0x4A, 0x80, 0x90, 0x02, 0x04, 0x31, 0x1C, 0x17, 0x42, 0x18, 0x40, 0x80, 0xC8, 0x30, 0x8E, 0xE1, 0xA2, 0x41, 0xC3, 0x34, 0x04, 0xA3, 0x28, 0x22, 0x51, 0x24, 0x71, }, .t0_len = 1664, .t0 = { 0x88, 0xD6, 0xFE, 0xF4, 0x67, 0x12, 0xCA, 0x18, 0x28, 0x72, 0xAB, 0x29, 0x19, 0x67, 0x8A, 0xFF, 0x9D, 0x94, 0xE7, 0x43, 0xE0, 0x63, 0xA3, 0x9E, 0x0C, 0x35, 0xCA, 0xF7, 0x2A, 0x7F, 0x2E, 0xDA, 0x28, 0xE6, 0x58, 0x58, 0x52, 0x0D, 0x5D, 0x84, 0x67, 0xDE, 0x74, 0x7C, 0xF3, 0x40, 0x65, 0x3B, 0x52, 0xC2, 0x68, 0xF5, 0x54, 0x13, 0xF5, 0xAD, 0xDC, 0x7D, 0x49, 0x01, 0x1E, 0xC3, 0x3E, 0xDD, 0x53, 0x74, 0x23, 0xA8, 0x42, 0x88, 0x86, 0x93, 0x37, 0xAE, 0xA0, 0x78, 0x1A, 0x12, 0x42, 0x69, 0x07, 0x14, 0x51, 0x72, 0x2D, 0xB3, 0xBB, 0x8F, 0x2C, 0xE5, 0xB1, 0x55, 0x2F, 0x83, 0xD2, 0xAF, 0x07, 0xF2, 0x56, 0x13, 0x91, 0x8A, 0x9F, 0x4E, 0x6F, 0x12, 0x57, 0x60, 0x38, 0x88, 0xE5, 0x89, 0x30, 0x8C, 0xA5, 0xF9, 0x5F, 0x07, 0x14, 0x3D, 0x23, 0xBA, 0xAE, 0x17, 0x52, 0x0B, 0x36, 0xB6, 0xE0, 0xE9, 0x4F, 0xAF, 0x68, 0x45, 0xEB, 0x21, 0x31, 0xAE, 0xC3, 0x83, 0xE6, 0x3B, 0xC8, 0x64, 0x4E, 0xE5, 0xF1, 0xAC, 0xCB, 0xA8, 0x2F, 0x92, 0x11, 0xE5, 0x7A, 0xFC, 0xBF, 0x50, 0x9C, 0x11, 0x31, 0xA3, 0x74, 0x66, 0xBC, 0x91, 0xB3, 0x57, 0xDC, 0xBB, 0xBC, 0x14, 0xCC, 0xC3, 0x19, 0xC4, 0xCC, 0x6A, 0xC7, 0x5F, 0xCD, 0xC8, 0x2C, 0x65, 0x96, 0xD0, 0x77, 0x70, 0xC8, 0x27, 0x7A, 0xD3, 0x70, 0xB1, 0x92, 0xA0, 0xB4, 0xE0, 0x5F, 0x81, 0x2E, 0x0E, 0x26, 0x5D, 0x29, 0x12, 0xAA, 0x29, 0xF0, 0x3F, 0xC9, 0xF7, 0x2D, 0xFA, 0x69, 0xC9, 0xB1, 0x29, 0x1A, 0x3F, 0xC5, 0x83, 0x64, 0x2B, 0x23, 0x5F, 0x69, 0x91, 0xA9, 0x54, 0x78, 0x83, 0x47, 0xF6, 0x0A, 0x03, 0x28, 0xC4, 0x8E, 0xCE, 0xE5, 0x1B, 0xA0, 0x2D, 0xFF, 0x32, 0x3A, 0xBD, 0x91, 0x16, 0x67, 0xCB, 0x14, 0x54, 0x9B, 0x61, 0x8F, 0x1C, 0x5D, 0x25, 0x0C, 0xAC, 0x9E, 0x35, 0xE0, 0x71, 0x60, 0x19, 0x92, 0xFB, 0xEC, 0x0B, 0xAE, 0x6F, 0x74, 0x21, 0x30, 0x81, 0x40, 0x47, 0x44, 0xD1, 0x2F, 0x2A, 0x0E, 0x04, 0xBD, 0xB2, 0x65, 0xE0, 0x92, 0x4C, 0xAD, 0xA4, 0x0D, 0x1F, 0xA1, 0xF3, 0x8A, 0xCA, 0x46, 0x06, 0xBF, 0xD4, 0x57, 0x57, 0x12, 0xB8, 0x26, 0x0A, 0x45, 0x6F, 0xDD, 0xEE, 0xEF, 0xE7, 0xCA, 0x25, 0x9B, 0xCD, 0xA9, 0x7B, 0x9B, 0x93, 0x9A, 0x5F, 0xD2, 0x88, 0x9C, 0x9B, 0x49, 0xFB, 0x7D, 0x4E, 0x35, 0x53, 0xDE, 0xA6, 0x1B, 0x33, 0x39, 0xBD, 0x0E, 0x6B, 0x16, 0xBF, 0x3B, 0xB2, 0x27, 0x10, 0x3B, 0xF9, 0x20, 0x2E, 0x72, 0xDC, 0x50, 0x2E, 0x28, 0xF7, 0xCE, 0x15, 0x59, 0xA4, 0x63, 0x1F, 0x37, 0x25, 0x20, 0x32, 0x4E, 0x4E, 0xBA, 0x07, 0x54, 0x5F, 0x78, 0xBF, 0x4D, 0x94, 0xB0, 0xE5, 0xB8, 0xBF, 0x51, 0xB8, 0xF1, 0x76, 0x53, 0x3D, 0x5C, 0xFE, 0xA5, 0x23, 0x2F, 0x28, 0x3A, 0x47, 0x60, 0x5F, 0xA6, 0x5D, 0xDB, 0x17, 0xC8, 0x91, 0xC2, 0x51, 0x01, 0x1C, 0x4E, 0x98, 0xEE, 0xB6, 0xEB, 0x00, 0xCB, 0x65, 0xBA, 0x31, 0xC8, 0xF0, 0x25, 0xC8, 0x7A, 0x9F, 0xE0, 0x2D, 0xBC, 0x10, 0xC5, 0xD8, 0x3A, 0x06, 0x5E, 0xBA, 0x5D, 0x7B, 0x2A, 0x19, 0xD5, 0xA1, 0xCB, 0x2C, 0x16, 0x0A, 0xE1, 0x66, 0xE8, 0x67, 0xF2, 0xAF, 0x8C, 0x7D, 0x49, 0xD6, 0x3F, 0xB8, 0x3A, 0x61, 0x49, 0x57, 0xFC, 0x0A, 0x3B, 0x5A, 0x5C, 0x74, 0x99, 0x0E, 0x9A, 0x2B, 0x02, 0x12, 0x0C, 0x7E, 0x6D, 0xE3, 0x7E, 0x15, 0x5F, 0xB4, 0x72, 0xF5, 0x0F, 0x0A, 0x45, 0xE4, 0x7C, 0xF5, 0xF9, 0xD7, 0xA4, 0xC8, 0x29, 0x82, 0xC9, 0xDC, 0x86, 0xAE, 0x87, 0x7C, 0x3F, 0xD1, 0x88, 0x59, 0x43, 0xE4, 0x39, 0xFB, 0x00, 0x3C, 0x7A, 0x9A, 0x42, 0xF7, 0x1B, 0x4F, 0xF6, 0xF0, 0xA2, 0x8B, 0x14, 0x0C, 0xBD, 0xBA, 0x6E, 0x71, 0xB1, 0x3A, 0xC3, 0x1B, 0x23, 0xDE, 0x9E, 0xAB, 0x78, 0x37, 0xE1, 0x5A, 0x69, 0xF8, 0x33, 0xEB, 0x7B, 0x56, 0xA7, 0x1D, 0x8B, 0xC2, 0xCA, 0xF1, 0xF2, 0xA3, 0x1C, 0x34, 0x5B, 0xD5, 0xF4, 0x6E, 0xE0, 0x13, 0xA7, 0xC6, 0x89, 0x37, 0x23, 0x37, 0x19, 0x1D, 0xAA, 0x80, 0x0C, 0x0A, 0xC6, 0xC4, 0x6C, 0x9F, 0xF6, 0x88, 0xB1, 0xA0, 0x13, 0x47, 0xF2, 0x57, 0xC4, 0x74, 0xAA, 0x3D, 0x97, 0xC1, 0xD6, 0x3A, 0x8C, 0x00, 0xE0, 0xA3, 0x7B, 0x68, 0x16, 0x73, 0xF5, 0x7C, 0x1C, 0x9C, 0x8F, 0xCC, 0xD4, 0x6F, 0x17, 0x4C, 0x74, 0xA2, 0x9D, 0x84, 0xCE, 0xB7, 0x1F, 0x7E, 0x6B, 0x2F, 0x8C, 0xD2, 0xB0, 0x89, 0xED, 0x43, 0xF7, 0xC9, 0x6D, 0xAE, 0x81, 0xA2, 0x23, 0x41, 0x8C, 0x20, 0xB1, 0x6F, 0x1D, 0xF3, 0xD1, 0xA9, 0x78, 0xAE, 0x28, 0xF6, 0xDF, 0x35, 0xEC, 0x55, 0x9D, 0x04, 0xD2, 0x0E, 0xC7, 0x4B, 0x22, 0x4A, 0xEA, 0x31, 0xA2, 0x89, 0xB0, 0x15, 0xB0, 0x69, 0xE9, 0xCB, 0xBB, 0xF7, 0xCF, 0x6D, 0xE9, 0x4C, 0xFB, 0x2A, 0x96, 0xE4, 0xAE, 0x34, 0x62, 0xC9, 0x60, 0x03, 0xCD, 0xDA, 0x87, 0xDB, 0x56, 0x1A, 0xF2, 0xCE, 0x3C, 0x0B, 0xA1, 0xD9, 0x04, 0x13, 0xFD, 0xCE, 0x3C, 0xCF, 0x43, 0x90, 0xC0, 0x2C, 0x1C, 0xB9, 0xF6, 0x54, 0xF4, 0x82, 0x0E, 0xC3, 0x30, 0x15, 0x45, 0x7D, 0x4A, 0x62, 0x9F, 0xBF, 0x39, 0x41, 0x9C, 0xAB, 0x76, 0x42, 0xD6, 0x88, 0x5E, 0x10, 0x3F, 0xCE, 0x0D, 0x42, 0x06, 0xCC, 0xE7, 0xC1, 0x2C, 0x6F, 0xC4, 0x4F, 0xA3, 0x3A, 0xD0, 0x86, 0x4C, 0x33, 0x71, 0xA7, 0xCB, 0xE8, 0x20, 0xE3, 0xB3, 0x71, 0xB6, 0x56, 0xA3, 0x8F, 0x2E, 0x7F, 0xF1, 0x8F, 0xE4, 0xA5, 0x0C, 0x8A, 0xB3, 0xF8, 0x5D, 0x78, 0x3F, 0xB5, 0x78, 0x35, 0xCE, 0xD8, 0x49, 0x0B, 0x84, 0xEE, 0x0D, 0x99, 0xAF, 0x0D, 0x64, 0xC4, 0x83, 0xCE, 0xB6, 0x36, 0x6F, 0xF5, 0x4F, 0x8A, 0xC8, 0xA4, 0x0D, 0xB1, 0xAF, 0xA5, 0x73, 0xA4, 0xFB, 0x32, 0x6C, 0x74, 0xF0, 0x23, 0x6E, 0xCE, 0xF3, 0xDA, 0x71, 0x20, 0x66, 0x5C, 0xCE, 0x05, 0xDD, 0x65, 0x4B, 0x50, 0x71, 0x72, 0x3A, 0x83, 0x48, 0xE7, 0xCD, 0x77, 0x93, 0x51, 0x38, 0x19, 0xB6, 0x1C, 0xB6, 0x4E, 0x13, 0x28, 0xE8, 0xB2, 0x2E, 0x76, 0x64, 0xBD, 0x6B, 0x41, 0xB5, 0x71, 0x0D, 0x19, 0xEA, 0x88, 0x09, 0xD4, 0x45, 0x08, 0x50, 0xE9, 0x07, 0xDF, 0xC4, 0xD0, 0xB7, 0x5F, 0x58, 0x8C, 0xEC, 0xE9, 0x62, 0xE9, 0xE0, 0x93, 0x7C, 0xE1, 0x40, 0x24, 0x46, 0xA4, 0xD2, 0x89, 0x1A, 0x46, 0xE6, 0x61, 0x7F, 0xB2, 0x9D, 0x4F, 0xCD, 0x71, 0x26, 0x06, 0xF7, 0x81, 0x9E, 0xCA, 0x60, 0xF7, 0xE0, 0xD5, 0xB1, 0x9E, 0x7F, 0xFB, 0x57, 0xC7, 0x3C, 0x16, 0xFF, 0xEE, 0xB9, 0x00, 0x38, 0x41, 0x0C, 0xB9, 0xFC, 0xBB, 0x5E, 0x9D, 0x51, 0xEB, 0x3E, 0xB6, 0x29, 0x7E, 0x9F, 0xF6, 0xAB, 0x70, 0x88, 0xFE, 0x2D, 0x9B, 0x23, 0x7B, 0xC2, 0x4C, 0xF7, 0xF8, 0x29, 0x01, 0x18, 0xA5, 0xE0, 0xE0, 0x0A, 0x0B, 0x90, 0x3F, 0xB6, 0x37, 0x5C, 0x84, 0x81, 0x76, 0xCD, 0x0A, 0x8C, 0x88, 0x75, 0xCC, 0x59, 0x19, 0x9C, 0xDA, 0x11, 0xA8, 0x7A, 0x78, 0xF6, 0x5C, 0xC4, 0x04, 0x33, 0x0B, 0x08, 0x75, 0x71, 0xFD, 0x06, 0x33, 0xE2, 0x71, 0x29, 0xFD, 0xAB, 0x5A, 0x8A, 0x1F, 0x79, 0x3E, 0x52, 0x41, 0x2B, 0x00, 0x83, 0xFD, 0x5C, 0x74, 0xDB, 0x3C, 0xF6, 0x0C, 0x25, 0x43, 0xCE, 0x7C, 0x91, 0xB2, 0x80, 0x0E, 0x40, 0x20, 0x3F, 0x8D, 0x99, 0xFE, 0x5F, 0xDE, 0x5B, 0x10, 0x8E, 0x7E, 0xDC, 0x80, 0xEB, 0xB9, 0xBB, 0x34, 0x98, 0x6E, 0xC5, 0xC5, 0xA8, 0xF5, 0x80, 0xE7, 0x57, 0x52, 0x90, 0x7F, 0xF0, 0xF2, 0x94, 0xC8, 0x66, 0xC2, 0xCF, 0x1F, 0x36, 0x2E, 0x84, 0x0B, 0x68, 0x81, 0xBD, 0x43, 0x21, 0x92, 0x01, 0x78, 0x1C, 0x63, 0xB0, 0x03, 0x9A, 0x95, 0xBC, 0xFB, 0x4A, 0x0F, 0xEC, 0xE5, 0x69, 0xDF, 0x00, 0x52, 0x3C, 0xE9, 0xC0, 0x84, 0xB0, 0x22, 0xB3, 0xB0, 0x22, 0x24, 0x2E, 0x28, 0x41, 0x97, 0x96, 0xAC, 0xF0, 0xA0, 0xC9, 0x95, 0xF9, 0x48, 0xDB, 0xFF, 0xFD, 0x30, 0xD7, 0x7E, 0xD1, 0x05, 0xA3, 0xC9, 0x94, 0x3C, 0x40, 0x6B, 0x30, 0x5B, 0xC8, 0x1A, 0x6A, 0x24, 0x8A, 0x29, 0x15, 0x48, 0xF2, 0xA6, 0x7F, 0x43, 0x8D, 0x96, 0x6A, 0x57, 0xD5, 0x3F, 0x4B, 0x7B, 0xE1, 0x53, 0x54, 0xE5, 0x81, 0xBE, 0x16, 0xF7, 0xAD, 0x64, 0xD1, 0x64, 0xE8, 0x57, 0x87, 0xDF, 0x58, 0x49, 0xC8, 0x10, 0xAF, 0xC2, 0x8D, 0x06, 0x48, 0x2F, 0x44, 0x1B, 0x5F, 0xDE, 0x3D, 0xB2, 0xED, 0x36, 0xDD, 0x25, 0xAA, 0x66, 0x64, 0xD4, 0xD4, 0x3F, 0xFA, 0x32, 0xED, 0xA2, 0x56, 0x89, 0xC9, 0xF4, 0xA5, 0xD5, 0x14, 0xFC, 0x66, 0x23, 0x1C, 0x54, 0x01, 0x52, 0x09, 0x22, 0x52, 0x44, 0x38, 0xEF, 0x1D, 0xC7, 0x8D, 0x69, 0x3C, 0x97, 0x18, 0xDE, 0xBB, 0xD2, 0x43, 0x31, 0x26, 0x74, 0xC8, 0x99, 0xF1, 0x89, 0x10, 0xE3, 0x89, 0xC8, 0xEB, 0xE5, 0x05, 0x82, 0x4B, 0xCC, 0x42, 0xCD, 0x4A, 0x9A, 0xCE, 0x19, 0x37, 0x68, 0x22, 0x02, 0x19, 0x01, 0x1F, 0x3B, 0x1F, 0x33, 0x54, 0x27, 0xBF, 0xF9, 0xE8, 0xBD, 0xED, 0x5C, 0x08, 0x71, 0x1A, 0x09, 0xC2, 0xB7, 0x1C, 0xB9, 0x64, 0xC5, 0x6A, 0x83, 0x93, 0xBF, 0xD2, 0xB5, 0x6E, 0x9B, 0x6B, 0x2F, 0x51, 0x3E, 0x68, 0x25, 0x87, 0xDC, 0x1B, 0x8E, 0xD1, 0x96, 0x06, 0x63, 0x26, 0x87, 0x10, 0x25, 0x62, 0x80, 0x36, 0x70, 0x00, 0x63, 0x17, 0x6D, 0x34, 0x5D, 0xE3, 0x84, 0xE1, 0x82, 0xD6, 0xC4, 0x17, 0xA3, 0x2A, 0xB1, 0x10, 0x95, 0xEF, 0x59, 0xBB, 0x4D, 0x17, 0x1B, 0x9C, 0xF8, 0x1D, 0x17, 0xAC, 0x42, 0x66, 0x4D, 0xED, 0x93, 0x3C, 0xCB, 0x72, 0x2C, 0x69, 0x85, 0x7F, 0xFC, 0x53, 0xC8, 0xE7, 0xF2, 0x47, 0x4B, 0x0C, 0xB2, 0xDF, 0xF2, 0xDD, 0xC8, 0xA5, 0xC6, 0x01, 0xC8, 0x4A, 0x70, 0x19, 0x81, 0x19, 0x9B, 0xCC, 0xF7, 0x41, 0x12, 0xA6, 0xEC, 0x06, 0x2C, 0x4F, 0xEB, 0x60, 0x1A, 0x02, 0x8A, 0xF0, 0x10, 0x32, 0xAD, 0xB6, 0xBD, 0x15, 0xD4, 0xC2, 0xB9, 0x55, 0x0A, 0xA8, 0x50, 0xAD, 0x62, 0xCC, 0xC3, 0xA3, 0x66, 0x5D, 0x52, 0x12, 0xB1, 0x2E, 0x0F, 0xD5, 0xC5, 0x32, 0x6A, 0x1E, 0x5E, 0xB1, 0xF1, 0x0D, 0x55, 0x7D, 0x94, 0x60, 0x5E, 0x8E, 0x3F, 0x35, 0x6E, 0x08, 0xFF, 0x7F, 0xD8, 0x84, 0xED, 0x3C, 0x42, 0x05, 0x46, 0x35, 0x94, 0xC9, 0xAF, 0x2F, 0x39, 0xE4, 0xB1, 0x27, 0x46, 0x95, 0x23, 0x4B, 0x54, 0xEE, 0xCE, 0xD9, 0x3F, 0x46, 0x0E, 0xDF, 0x1A, 0x13, 0xC2, 0xCB, 0x4B, 0x17, 0xD3, 0x22, 0xF6, 0xF7, 0x9F, 0xE1, 0x6F, 0x03, 0x57, 0xC1, 0xC4, 0x73, 0x98, 0x63, 0xE7, 0x96, 0x79, 0x1F, 0x86, 0x47, 0xFA, 0xBF, 0x73, 0x0A, 0xB0, 0x0E, 0x0D, 0xA5, 0x09, 0x70, 0x6D, 0x94, 0x57, 0x17, 0x40, 0xF6, 0x1F, 0x7B, 0xAF, 0x36, 0x6D, 0x27, 0x74, 0xC9, 0xB5, 0xB8, 0xC6, 0x1D, 0xD6, 0xBE, 0x98, 0x19, 0xA6, 0x02, 0x8B, 0x26, 0x4B, 0xB2, 0xE4, 0xAE, 0xA5, 0x4B, 0x56, 0xD4, 0xEC, 0xAB, 0x5B, 0x52, 0x8C, 0xE0, 0xC0, 0xC0, 0xCC, 0xDB, 0x73, 0x02, 0x33, 0x52, 0xCB, 0x00, 0x44, 0x5B, 0xAB, 0x6F, 0x74, 0x67, 0xB4, 0x64, 0x4D, 0x43, 0x61, 0xC4, 0x64, 0xFA, 0xC6, 0xB5, 0xB1, 0x37, 0xD3, 0x23, 0x91, 0x02, 0x1B, 0x47, 0x5F, 0xCB, 0x5F, 0x31, 0x77, 0x4F, 0xD8, 0xEC, 0xAB, 0xDF, 0x65, 0x47, 0x5F, 0x25, 0x57, 0x4C, 0x65, 0x55, 0x9C, 0xB3, 0x31, 0xF4, 0x1C, 0x0F, 0x49, 0x8B, 0x74, 0xDD, 0x94, 0x1C, 0x34, 0x4C, 0x50, 0xD8, 0xE6, 0x4F, 0x95, 0x78, 0x71, 0x4A, 0x32, 0x56, 0x1F, 0xAA, 0xCE, 0xAF, 0x78, 0x14, 0x8E, 0x6D, 0xA4, 0xB5, 0x66, 0x82, 0x69, 0x25, 0x71, 0x4B, 0x17, 0x10, 0x8A, 0xFD, 0xD5, 0x46, 0x38, 0x5A, 0x3C, 0xD4, 0x54, 0xD5, 0xCA, 0xA1, 0x69, 0x60, 0x91, 0x62, 0x82, 0xA4, 0x7C, 0x43, 0x15, 0xCE, 0x23, 0x6B, 0xD9, 0xE3, 0x25, 0x5C, 0x60, 0x4E, 0xBD, 0xC3, 0x97, 0x72, 0xDB, 0x5C, 0xE0, 0xB2, 0x36, }, .t1_len = 1280, .t1 = { 0x61, 0x77, 0xE3, 0xDE, 0x0D, 0x4F, 0x1E, 0xF5, 0x84, 0x77, 0x35, 0x94, 0x7B, 0x56, 0xD0, 0x8E, 0x84, 0x1D, 0xB2, 0x44, 0x4F, 0xA2, 0xB7, 0x29, 0xAD, 0xEB, 0x14, 0x17, 0xCA, 0x7A, 0xDF, 0x42, 0xA1, 0x49, 0x0C, 0x5A, 0x09, 0x7F, 0x00, 0x27, 0x60, 0xC1, 0xFC, 0x41, 0x9B, 0xE8, 0x32, 0x5A, 0xAD, 0x01, 0x97, 0xC5, 0x2C, 0xED, 0x80, 0xD3, 0xDF, 0x18, 0xE7, 0x77, 0x42, 0x65, 0xB2, 0x89, 0x91, 0x2C, 0xEC, 0xA1, 0xBE, 0x3A, 0x90, 0xD8, 0xA4, 0xFD, 0xE6, 0x5C, 0x84, 0xC6, 0x10, 0x86, 0x4E, 0x47, 0xDE, 0xEC, 0xAE, 0x3E, 0xEA, 0x44, 0x30, 0xB9, 0x90, 0x95, 0x59, 0x40, 0x8D, 0x11, 0xA6, 0xAB, 0xDB, 0x7D, 0xB9, 0x33, 0x6D, 0xF7, 0xF9, 0x6E, 0xAB, 0x48, 0x64, 0xA6, 0x57, 0x97, 0x91, 0x26, 0x5F, 0xA5, 0x6C, 0x34, 0x8C, 0xB7, 0xD2, 0xDD, 0xC9, 0x0E, 0x13, 0x3A, 0x95, 0xC3, 0xF6, 0xB1, 0x36, 0x01, 0x42, 0x9F, 0x54, 0x08, 0xBD, 0x99, 0x9A, 0xA4, 0x79, 0xC1, 0x01, 0x81, 0x59, 0x55, 0x0E, 0xC5, 0x5A, 0x11, 0x3C, 0x49, 0x3B, 0xE6, 0x48, 0xF4, 0xE0, 0x36, 0xDD, 0x4F, 0x8C, 0x80, 0x9E, 0x03, 0x6B, 0x4F, 0xBB, 0x91, 0x8C, 0x2C, 0x48, 0x4A, 0xD8, 0xE1, 0x74, 0x7A, 0xE0, 0x55, 0x85, 0xAB, 0x43, 0x3F, 0xDF, 0x46, 0x1A, 0xF0, 0x3C, 0x25, 0xA7, 0x73, 0x70, 0x07, 0x21, 0xAA, 0x05, 0xF7, 0x37, 0x9F, 0xE7, 0xF5, 0xED, 0x96, 0x17, 0x5D, 0x40, 0x21, 0x07, 0x6E, 0x7F, 0x52, 0xB6, 0x03, 0x08, 0xEF, 0xF5, 0xD4, 0x2B, 0xA6, 0xE0, 0x93, 0xB3, 0xD0, 0x81, 0x5E, 0xB3, 0x49, 0x66, 0x46, 0xE4, 0x92, 0x30, 0xA9, 0xB3, 0x5C, 0x8D, 0x41, 0x90, 0x0C, 0x2B, 0xB8, 0xD3, 0xB4, 0x46, 0xA2, 0x31, 0x27, 0xF7, 0xE0, 0x96, 0xD8, 0x5A, 0x1C, 0x79, 0x4A, 0xD4, 0xC8, 0x92, 0x77, 0x90, 0x4F, 0xC6, 0xBF, 0xEC, 0x57, 0xB1, 0xCD, 0xD8, 0x0D, 0xF9, 0x95, 0x50, 0x30, 0xFD, 0xCA, 0x74, 0x1A, 0xFB, 0xDA, 0xC8, 0x27, 0xB1, 0x3C, 0xCD, 0x54, 0x03, 0x58, 0x8A, 0xF4, 0x64, 0x40, 0x03, 0xC2, 0x26, 0x5D, 0xFA, 0x4D, 0x41, 0x9D, 0xBC, 0xCD, 0x20, 0x64, 0x89, 0x23, 0x86, 0x51, 0x8B, 0xE9, 0xD5, 0x1C, 0x16, 0x49, 0x82, 0x75, 0xEB, 0xEC, 0xF5, 0xCD, 0xC7, 0xA8, 0x20, 0xF2, 0xC2, 0x93, 0x14, 0xAC, 0x4A, 0x6F, 0x08, 0xB2, 0x25, 0x2A, 0xD3, 0xCF, 0xB1, 0x99, 0xAA, 0x42, 0xFE, 0x0B, 0x4F, 0xB5, 0x71, 0x97, 0x5C, 0x10, 0x20, 0xD9, 0x49, 0xE1, 0x94, 0xEE, 0x1E, 0xAD, 0x93, 0x7B, 0xFB, 0x55, 0x0B, 0xB3, 0xBA, 0x8E, 0x35, 0x7A, 0x02, 0x9C, 0x29, 0xF0, 0x77, 0x55, 0x46, 0x02, 0xE1, 0xCA, 0x2F, 0x22, 0x89, 0xCB, 0x91, 0x69, 0x94, 0x1C, 0x3A, 0xAF, 0xDB, 0x8E, 0x58, 0xC7, 0xF2, 0xAC, 0x77, 0x29, 0x1F, 0xB4, 0x14, 0x7C, 0x65, 0xF6, 0xB0, 0x31, 0xD3, 0xEB, 0xA4, 0x2F, 0x2A, 0xCF, 0xD9, 0x44, 0x8A, 0x5B, 0xC2, 0x2B, 0x47, 0x6E, 0x07, 0xCC, 0xCE, 0xDA, 0x23, 0x06, 0xC5, 0x54, 0xEC, 0x9B, 0x7A, 0xB6, 0x55, 0xF1, 0xD7, 0x31, 0x8C, 0x2B, 0x7E, 0x67, 0xD5, 0xF6, 0x9B, 0xED, 0xF5, 0x60, 0x00, 0xFD, 0xA9, 0x89, 0x86, 0xB5, 0xAB, 0x1B, 0x3A, 0x22, 0xD8, 0xDF, 0xD6, 0x68, 0x16, 0x97, 0xB2, 0x3A, 0x55, 0xC9, 0x6E, 0x87, 0x10, 0xF3, 0xF9, 0x8C, 0x04, 0x4F, 0xB1, 0x5F, 0x60, 0x63, 0x13, 0xEE, 0x56, 0xC0, 0xF1, 0xF5, 0xCA, 0x0F, 0x51, 0x2E, 0x08, 0x48, 0x4F, 0xCB, 0x35, 0x8E, 0x6E, 0x52, 0x8F, 0xFA, 0x89, 0xF8, 0xA8, 0x66, 0xCC, 0xFF, 0x3C, 0x0C, 0x58, 0x13, 0x14, 0x7E, 0xC5, 0x9A, 0xF0, 0x47, 0x0C, 0x4A, 0xAD, 0x01, 0x41, 0xD3, 0x4F, 0x10, 0x1D, 0xA2, 0xE5, 0xE1, 0xBD, 0x52, 0xD0, 0xD4, 0xC9, 0xB1, 0x3B, 0x3E, 0x3D, 0x87, 0xD1, 0x58, 0x61, 0x05, 0x79, 0x67, 0x54, 0xE7, 0x97, 0x8C, 0xA1, 0xC6, 0x8A, 0x7D, 0x85, 0xDF, 0x11, 0x2B, 0x7A, 0xB9, 0x21, 0xB3, 0x59, 0xA9, 0xF0, 0x3C, 0xBD, 0x27, 0xA7, 0xEA, 0xC8, 0x7A, 0x9A, 0x80, 0xB0, 0xB2, 0x6B, 0x4C, 0x96, 0x57, 0xED, 0x85, 0xAD, 0x7F, 0xA2, 0x61, 0x6A, 0xB3, 0x45, 0xEB, 0x82, 0x26, 0xF6, 0x9F, 0xC0, 0xF4, 0x81, 0x83, 0xFF, 0x57, 0x4B, 0xCD, 0x76, 0x7B, 0x56, 0x76, 0x41, 0x3A, 0xDB, 0x12, 0xEA, 0x21, 0x50, 0xA0, 0xE9, 0x76, 0x83, 0xEE, 0x54, 0x24, 0x3C, 0x25, 0xB7, 0xEA, 0x8A, 0x71, 0x86, 0x06, 0xF8, 0x69, 0x93, 0xD8, 0xD0, 0xDA, 0xCE, 0x83, 0x4E, 0xD3, 0x41, 0xEE, 0xB7, 0x24, 0xFE, 0x3D, 0x5F, 0xF0, 0xBC, 0x8B, 0x8A, 0x7B, 0x81, 0x04, 0xBA, 0x26, 0x9D, 0x34, 0x13, 0x3A, 0x4C, 0xF8, 0x30, 0x0A, 0x2D, 0x68, 0x84, 0x96, 0xB5, 0x9B, 0x6F, 0xCB, 0xC6, 0x1A, 0xE9, 0x60, 0x62, 0xEA, 0x1D, 0x8E, 0x5B, 0x41, 0x0C, 0x56, 0x71, 0xF4, 0x24, 0x41, 0x7E, 0xD6, 0x93, 0x32, 0x9C, 0xD9, 0x83, 0x00, 0x1F, 0xFC, 0xD1, 0x00, 0x23, 0xD5, 0x98, 0x85, 0x9F, 0xB7, 0xAD, 0x5F, 0xD2, 0x63, 0x54, 0x71, 0x17, 0x10, 0x06, 0x90, 0xC6, 0xCE, 0x74, 0x38, 0x95, 0x6E, 0x6C, 0xC5, 0x7F, 0x1B, 0x5D, 0xE5, 0x3B, 0xB0, 0xDC, 0x72, 0xCE, 0x9B, 0x6D, 0xEA, 0xA8, 0x57, 0x89, 0x59, 0x9A, 0x70, 0xF0, 0x05, 0x1F, 0x1A, 0x0E, 0x25, 0xE8, 0x6D, 0x88, 0x8B, 0x00, 0xDF, 0x36, 0xBD, 0xBC, 0x93, 0xEF, 0x72, 0x17, 0xC4, 0x5A, 0xCE, 0x11, 0xC0, 0x79, 0x0D, 0x70, 0xE9, 0x95, 0x3E, 0x5B, 0x41, 0x7B, 0xA2, 0xFD, 0x9A, 0x4C, 0xAF, 0x82, 0xF1, 0xFC, 0xE6, 0xF4, 0x5F, 0x53, 0xE2, 0x15, 0xB8, 0x35, 0x5E, 0xF6, 0x1D, 0x89, 0x1D, 0xF1, 0xC7, 0x94, 0x23, 0x1C, 0x16, 0x2D, 0xD2, 0x41, 0x64, 0xB5, 0x34, 0xA9, 0xD4, 0x84, 0x67, 0xCD, 0xC3, 0x23, 0x62, 0x4C, 0x2F, 0x95, 0xD4, 0x40, 0x2F, 0xF9, 0xD6, 0x6A, 0xB1, 0x19, 0x1A, 0x81, 0x24, 0x14, 0x4A, 0xFA, 0x35, 0xD4, 0xE3, 0x1D, 0xC8, 0x6C, 0xAA, 0x79, 0x7C, 0x31, 0xF6, 0x8B, 0x85, 0x85, 0x4C, 0xD9, 0x59, 0xC4, 0xFA, 0xC5, 0xEC, 0x53, 0xB3, 0xB5, 0x6D, 0x37, 0x4B, 0x88, 0x8A, 0x9E, 0x97, 0x9A, 0x65, 0x76, 0xB6, 0x34, 0x5E, 0xC8, 0x52, 0x2C, 0x96, 0x06, 0x99, 0x02, 0x81, 0xBF, 0x3E, 0xF7, 0xC5, 0x94, 0x5D, 0x10, 0xFD, 0x21, 0xA2, 0xA1, 0xD2, 0xE5, 0x40, 0x4C, 0x5C, 0xF2, 0x12, 0x20, 0x64, 0x13, 0x91, 0xB9, 0x8B, 0xCF, 0x82, 0x53, 0x98, 0x30, 0x5B, 0x56, 0xE5, 0x8B, 0x61, 0x1F, 0xE5, 0x25, 0x32, 0x03, 0xE3, 0xDF, 0x0D, 0x22, 0x46, 0x6A, 0x73, 0xB3, 0xF0, 0xFB, 0xE4, 0x3B, 0x9A, 0x62, 0x92, 0x80, 0x91, 0x89, 0x8B, 0x8A, 0x0E, 0x5B, 0x26, 0x9D, 0xB5, 0x86, 0xB0, 0xE4, 0xDD, 0xEF, 0x50, 0xD6, 0x82, 0xA1, 0x2D, 0x2C, 0x1B, 0xE8, 0x24, 0x14, 0x9A, 0xA2, 0x54, 0xC6, 0x38, 0x1B, 0xB4, 0x12, 0xD7, 0x7C, 0x3F, 0x9A, 0xA9, 0x02, 0xB6, 0x88, 0xC8, 0x17, 0x15, 0xA5, 0x9C, 0x83, 0x95, 0x58, 0x55, 0x6D, 0x35, 0xED, 0x4F, 0xC8, 0x3B, 0x4A, 0xB1, 0x81, 0x81, 0xF4, 0x0F, 0x73, 0xDC, 0xD7, 0x68, 0x60, 0xD8, 0xD8, 0xBF, 0x94, 0x52, 0x02, 0x37, 0xC2, 0xAC, 0x0E, 0x46, 0x3B, 0xA0, 0x9E, 0x3C, 0x97, 0x82, 0x38, 0x0D, 0xC0, 0x7F, 0xE4, 0xFC, 0xBA, 0x34, 0x0C, 0xC2, 0x00, 0x34, 0x39, 0xFD, 0x23, 0x14, 0x61, 0x06, 0x38, 0x07, 0x0D, 0x6C, 0x9E, 0xEA, 0x0A, 0x70, 0xBA, 0xE8, 0x3B, 0x5D, 0x5D, 0x3C, 0x5D, 0x3F, 0xDE, 0x26, 0xDD, 0x01, 0x60, 0x6C, 0x8C, 0x52, 0x01, 0x58, 0xE7, 0xE5, 0x10, 0x40, 0x20, 0xF2, 0x48, 0xCE, 0xAA, 0x66, 0x64, 0x57, 0xC1, 0x0A, 0xEB, 0xF0, 0x68, 0xF8, 0xA3, 0xBD, 0x5C, 0xE7, 0xB5, 0x2C, 0x6A, 0xF0, 0xAB, 0xD5, 0x94, 0x4A, 0xF1, 0xAD, 0x47, 0x52, 0xC9, 0x11, 0x39, 0x76, 0x08, 0x3C, 0x03, 0xB6, 0xC3, 0x4E, 0x1D, 0x47, 0xED, 0x69, 0x64, 0x4C, 0xAD, 0x78, 0x2C, 0x2F, 0x7D, 0x05, 0xF8, 0xA1, 0x48, 0x96, 0x1D, 0x96, 0x5F, 0xA2, 0xE1, 0x72, 0x3A, 0x8D, 0xDE, 0xBC, 0x22, 0xA9, 0x0C, 0xD7, 0x83, 0xDD, 0x1F, 0x4D, 0xB3, 0x8F, 0xB9, 0xAE, 0x5A, 0x67, 0x14, 0xB3, 0xD9, 0x46, 0x78, 0x16, 0x43, 0xD3, 0x17, 0xB7, 0xDD, 0x79, 0x38, 0x1C, 0xF7, 0x89, 0xA9, 0x58, 0x8B, 0xB3, 0xE1, 0x93, 0xB9, 0x2A, 0x0B, 0x60, 0xD6, 0xB0, 0x7D, 0x04, 0x7F, 0x69, 0x84, 0xB0, 0x60, 0x9E, 0xC5, 0x75, 0x43, 0xC3, 0x94, 0xCA, 0x8D, 0x5E, 0x5B, 0xCC, 0x2A, 0x73, 0x1A, 0x79, 0x61, 0x8B, 0xD1, 0xE2, 0xE0, 0xDA, 0x87, 0x04, 0xAF, 0x98, 0xF2, 0x0F, 0x5F, 0x8F, 0x54, 0x52, 0xDD, 0xF6, 0x46, 0xB9, 0x5B, 0x34, 0x1D, 0xD7, 0xF0, 0xD2, 0xCC, 0x1F, 0xA1, 0x5B, 0xD9, 0x89, 0x5C, 0xD5, 0xB6, 0x5A, 0xA1, 0xCB, 0x94, 0xB5, 0xE2, 0xE7, 0x88, 0xFD, 0xA9, 0x82, 0x5B, 0x65, 0x66, 0x39, 0x19, 0x3D, 0x98, 0x32, 0x81, 0x54, 0xA4, 0xF2, 0xC3, 0x54, 0x95, 0xA3, 0x8B, 0x6E, 0xA0, 0xD2, 0xFF, 0xAA, 0xA3, 0x5D, 0xF9, 0x2C, 0x20, 0x3C, 0x7F, 0x31, 0xCB, 0xBC, 0xA7, 0xBD, 0x03, 0xC3, 0xC2, 0x30, 0x21, 0x90, 0xCE, 0xCD, 0x16, 0x1F, 0xD4, 0x92, 0x37, 0xE4, 0xF8, 0x39, 0xE3, 0xF3, }, .pkcs8_len = 0, .spki_len = 0, .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 = 2420, .sig = { 0xAF, 0x59, 0x20, 0x77, 0x46, 0x03, 0xD2, 0x0E, 0x98, 0xA7, 0x9A, 0xA3, 0xAB, 0xFA, 0x32, 0xB6, 0xE2, 0x25, 0x19, 0xE6, 0x73, 0xE3, 0x7A, 0xC4, 0xAC, 0x73, 0xFE, 0x85, 0x34, 0x1E, 0x2C, 0x29, 0x23, 0xC1, 0x99, 0x2E, 0x1B, 0x0B, 0xBE, 0x38, 0x73, 0xD7, 0xC8, 0xFC, 0x56, 0x62, 0xF2, 0x07, 0xBF, 0x58, 0xEA, 0x38, 0x1C, 0xD4, 0xA3, 0xA0, 0xC0, 0x62, 0xDE, 0xC4, 0x5B, 0xDA, 0xF8, 0xBA, 0x0A, 0xA5, 0x2B, 0xEF, 0x6F, 0xA1, 0x4F, 0x3F, 0x6C, 0xF2, 0x8F, 0x76, 0x20, 0xBF, 0x94, 0xA9, 0x2C, 0xC2, 0x7D, 0x04, 0x54, 0x14, 0xA6, 0x4D, 0x65, 0xC0, 0x14, 0x96, 0x30, 0x52, 0x80, 0x24, 0x28, 0xBF, 0x39, 0x87, 0xA2, 0xD4, 0x75, 0x16, 0xCA, 0x5C, 0x78, 0xAA, 0xB9, 0x6B, 0x7B, 0xE1, 0x1B, 0xCA, 0x5F, 0x2C, 0x5A, 0x26, 0xF3, 0xFC, 0xE3, 0xA2, 0x6E, 0x8E, 0x09, 0xA2, 0x73, 0x8F, 0x38, 0x6F, 0x75, 0xD4, 0x48, 0xF9, 0x37, 0xEF, 0x19, 0xA8, 0x46, 0xBD, 0x4D, 0xD9, 0x49, 0xCA, 0xAF, 0x36, 0xDB, 0x56, 0x29, 0x88, 0x4A, 0xF5, 0x3A, 0x02, 0x3E, 0x3F, 0x18, 0x0F, 0xE4, 0xC0, 0xFA, 0xFF, 0x7B, 0xE5, 0xDF, 0xE4, 0xE8, 0x9A, 0xDE, 0x30, 0x95, 0xA6, 0x56, 0x00, 0x42, 0x14, 0x61, 0xAD, 0x08, 0xC1, 0x29, 0xD6, 0xCE, 0xA8, 0x51, 0xBB, 0x39, 0xC0, 0xD7, 0xA7, 0xD1, 0x51, 0x40, 0x56, 0x89, 0xA0, 0x91, 0xFA, 0x4D, 0xEB, 0xAC, 0x37, 0x3C, 0xF5, 0x4A, 0xE0, 0x78, 0xF0, 0xAF, 0x75, 0x57, 0xBB, 0xC6, 0xF0, 0x6A, 0x53, 0x5A, 0xE8, 0x94, 0x9E, 0x0C, 0x65, 0x30, 0x8A, 0x59, 0x84, 0x00, 0x72, 0x37, 0x52, 0x95, 0x80, 0x2D, 0x0E, 0x2C, 0xE9, 0xA3, 0xDA, 0x98, 0x42, 0x6A, 0x00, 0xFF, 0x03, 0xFE, 0x80, 0x21, 0x8C, 0x0E, 0xEC, 0x8E, 0xFE, 0x58, 0x1C, 0xB9, 0xCC, 0x9A, 0x7D, 0x66, 0xB2, 0x06, 0x45, 0xA8, 0xCD, 0x04, 0x90, 0xD3, 0xCE, 0x4F, 0x7E, 0x6F, 0xEA, 0xE9, 0xC9, 0xEB, 0x7A, 0x57, 0xF9, 0x64, 0xD0, 0xEB, 0xC7, 0xC9, 0x0B, 0x7A, 0x9F, 0x86, 0x30, 0x0B, 0x3E, 0x80, 0x95, 0xE6, 0x4D, 0x12, 0x94, 0xCF, 0xC4, 0xB4, 0xD9, 0xE2, 0x72, 0xE8, 0xFA, 0x8D, 0xB5, 0x70, 0x7D, 0x70, 0x04, 0xAF, 0x22, 0xDB, 0xFF, 0x9C, 0xFD, 0x48, 0x63, 0xDF, 0x57, 0x3F, 0xE0, 0x04, 0x34, 0x1D, 0xA3, 0xCD, 0x4A, 0x30, 0x82, 0x53, 0x2C, 0x26, 0x20, 0x45, 0x5F, 0xA3, 0x7C, 0x56, 0x2B, 0xAF, 0xD5, 0x68, 0x4E, 0xA1, 0x28, 0xAF, 0xC7, 0x9E, 0x01, 0xFC, 0x9B, 0x31, 0xE8, 0x43, 0x3B, 0xAD, 0x7C, 0x02, 0x9F, 0x2F, 0x13, 0xCC, 0x10, 0x59, 0x2D, 0x23, 0x32, 0xE3, 0xE0, 0x8B, 0x80, 0xD3, 0x50, 0x46, 0x3D, 0xE7, 0x27, 0x50, 0xB1, 0xF8, 0x06, 0xF4, 0x93, 0xE1, 0x43, 0xBD, 0x5F, 0xCA, 0x7D, 0x16, 0x98, 0x08, 0x1B, 0x31, 0xBF, 0x87, 0x6B, 0x2A, 0x1B, 0xC9, 0xDF, 0x50, 0x95, 0x2D, 0x13, 0xB6, 0xC1, 0x32, 0x1B, 0x11, 0x11, 0x17, 0x21, 0x45, 0xA6, 0x27, 0xAE, 0x0B, 0x44, 0x27, 0xB9, 0x89, 0x75, 0xCB, 0xFF, 0xF7, 0xD6, 0x82, 0x75, 0x75, 0x4B, 0x45, 0xB6, 0x82, 0xD7, 0x09, 0xE1, 0x68, 0x52, 0x2E, 0x84, 0xFE, 0xA7, 0xDD, 0x3B, 0xB0, 0xF4, 0x15, 0x05, 0xFF, 0x71, 0x92, 0x64, 0x31, 0xD1, 0xA9, 0x0D, 0x4C, 0xBF, 0x9A, 0x52, 0x7A, 0xD4, 0xE2, 0x84, 0x97, 0x6F, 0xFF, 0x8B, 0xD9, 0xD6, 0x22, 0x4A, 0x4F, 0x26, 0x03, 0x91, 0xA9, 0x87, 0xFB, 0x6D, 0xA6, 0xEE, 0x42, 0xC2, 0xA4, 0x90, 0x0F, 0x40, 0x7C, 0xE1, 0xF0, 0x2E, 0x32, 0x24, 0x75, 0xD3, 0x13, 0xFB, 0xEB, 0xB6, 0x8C, 0x2E, 0x05, 0x73, 0x08, 0x09, 0x44, 0x8A, 0x74, 0x28, 0xA5, 0x94, 0x01, 0x39, 0xEB, 0xDF, 0x1B, 0x55, 0x56, 0xFC, 0xC5, 0xD4, 0x2E, 0x1A, 0x13, 0xF3, 0x22, 0x30, 0xCB, 0x6F, 0x07, 0x24, 0x83, 0x1D, 0x0D, 0x07, 0x1B, 0xBA, 0x5A, 0x67, 0x04, 0x80, 0x6F, 0x47, 0x5B, 0x74, 0xBA, 0x91, 0xB6, 0xE3, 0x85, 0xD4, 0x86, 0x20, 0x95, 0x8D, 0x0A, 0xB1, 0xBF, 0x2B, 0x18, 0x4E, 0x10, 0xF3, 0xE7, 0x53, 0xB7, 0x13, 0x37, 0xBE, 0x9E, 0xB6, 0x53, 0x78, 0x67, 0x85, 0xB4, 0x3A, 0xC7, 0xE5, 0xC4, 0x94, 0xAC, 0x1B, 0xCB, 0x04, 0x3D, 0x46, 0x14, 0x25, 0xB3, 0x60, 0x98, 0xAC, 0x93, 0x05, 0x5A, 0x01, 0x05, 0xAB, 0x85, 0x23, 0xB6, 0x1D, 0x02, 0x4A, 0x6E, 0x9B, 0x56, 0xA4, 0x2D, 0x3C, 0x04, 0x72, 0x65, 0x12, 0xAE, 0x4C, 0xFE, 0x05, 0x71, 0x04, 0x46, 0xB0, 0x6F, 0x69, 0x42, 0x34, 0xEE, 0x4F, 0xA8, 0xFE, 0xED, 0xDD, 0xC5, 0xF2, 0x8A, 0x65, 0xED, 0xE2, 0xEB, 0x58, 0xE9, 0x65, 0xFE, 0x36, 0x27, 0xA5, 0x71, 0xBC, 0x45, 0xB3, 0x97, 0xED, 0x09, 0x2A, 0xB4, 0xBE, 0x00, 0x04, 0x17, 0x29, 0xC4, 0xD1, 0x92, 0xFE, 0x30, 0x67, 0x82, 0x79, 0xD2, 0x23, 0xA8, 0x48, 0xCF, 0x43, 0x66, 0xE9, 0x2B, 0x3F, 0x68, 0xDE, 0xE9, 0x7C, 0x9B, 0x4A, 0x7F, 0xF2, 0x2F, 0x93, 0x7B, 0xE6, 0xC5, 0x66, 0x39, 0x96, 0x1D, 0xB2, 0x9F, 0xA3, 0xCF, 0xEC, 0xFF, 0xF2, 0x93, 0x14, 0x08, 0x86, 0xFF, 0xB9, 0x2E, 0xBC, 0x79, 0xDA, 0xB5, 0x9C, 0xEA, 0xF8, 0x69, 0xC6, 0x4F, 0x8E, 0xAF, 0x58, 0x5C, 0xE9, 0x7D, 0xD6, 0xB7, 0x8F, 0x89, 0x27, 0x72, 0xDB, 0x88, 0xA9, 0x58, 0xCF, 0x0A, 0xB5, 0x57, 0xA7, 0xFA, 0xA8, 0x3F, 0xE6, 0x21, 0x47, 0x7E, 0x2B, 0x84, 0x49, 0x7A, 0xB5, 0xA8, 0xEC, 0xF4, 0xA7, 0xBD, 0x32, 0xDF, 0xB9, 0x02, 0xF0, 0x5D, 0x2C, 0xA3, 0x10, 0x47, 0xD0, 0xF1, 0x91, 0x9A, 0xDD, 0xE1, 0xEE, 0x6D, 0xFD, 0x58, 0xE5, 0x9B, 0xC4, 0xDA, 0xB3, 0xCC, 0xBB, 0xA3, 0x6A, 0xAA, 0xF6, 0xAF, 0xCC, 0xC7, 0xB0, 0x95, 0xCA, 0x94, 0xA1, 0x95, 0xBE, 0x9A, 0x28, 0x95, 0x26, 0xB5, 0x88, 0xC3, 0xA9, 0xC5, 0x68, 0x76, 0xFC, 0x41, 0x5D, 0x52, 0x1D, 0x44, 0x2B, 0xAC, 0x02, 0x98, 0xD3, 0x02, 0x41, 0x9A, 0xD5, 0x27, 0xDA, 0x24, 0x9C, 0x2A, 0x66, 0x0C, 0xD0, 0x64, 0x21, 0x3F, 0xFA, 0xD5, 0x63, 0x18, 0x3F, 0x37, 0x97, 0x25, 0x78, 0xEE, 0xB9, 0xF7, 0x0A, 0xC6, 0x7A, 0xEE, 0x6C, 0xC2, 0xB7, 0x1F, 0x28, 0x3A, 0x95, 0x93, 0x0B, 0x55, 0x47, 0x38, 0x55, 0x57, 0x91, 0xC2, 0x5E, 0x7A, 0x39, 0x9E, 0x68, 0x56, 0x36, 0xD5, 0x8D, 0x69, 0xCB, 0x6B, 0xE7, 0x93, 0xB4, 0x5C, 0x19, 0x69, 0xE7, 0xD5, 0x61, 0x56, 0x27, 0xEB, 0xC3, 0x2E, 0xED, 0x45, 0x44, 0x0F, 0x87, 0x88, 0x0D, 0x28, 0x29, 0xFA, 0x4F, 0xC8, 0x71, 0x86, 0x61, 0x64, 0xD2, 0x59, 0xED, 0x95, 0xD2, 0x73, 0x18, 0x71, 0x01, 0x7F, 0xF5, 0x18, 0x94, 0x06, 0x6F, 0xAE, 0x1F, 0xFA, 0x6F, 0x4B, 0x4A, 0x6F, 0x84, 0xFC, 0xFF, 0xDA, 0x09, 0xE7, 0x18, 0xFA, 0x17, 0x13, 0x5E, 0xDB, 0x3F, 0x48, 0x55, 0x8D, 0x5B, 0xA6, 0x7F, 0x9E, 0x6F, 0x09, 0x00, 0x34, 0x0B, 0xD0, 0x4D, 0xFE, 0x59, 0xB7, 0xBD, 0x67, 0x74, 0x58, 0x84, 0xFB, 0x84, 0xAE, 0x3F, 0x8E, 0xE7, 0x63, 0xD2, 0x02, 0x74, 0x36, 0x52, 0xD4, 0xF7, 0x33, 0x34, 0x50, 0x58, 0x04, 0x90, 0xB9, 0xC7, 0x44, 0x93, 0x5B, 0x19, 0xC1, 0xD5, 0xFB, 0x0D, 0xB5, 0xFB, 0xB4, 0x61, 0x41, 0x13, 0x62, 0x83, 0x80, 0x37, 0xEB, 0x7E, 0xC3, 0xF6, 0x3F, 0x26, 0xC8, 0x93, 0xE7, 0xCC, 0x1C, 0x3B, 0x3F, 0x47, 0x67, 0xAB, 0xAE, 0x00, 0xFE, 0xB7, 0xBB, 0x99, 0xB1, 0x42, 0x0B, 0xB2, 0x9E, 0xA6, 0x14, 0x74, 0x78, 0x96, 0xD9, 0xED, 0xCF, 0x81, 0x07, 0xFE, 0x50, 0x4C, 0x9C, 0x30, 0x8A, 0x82, 0x64, 0xDA, 0xCE, 0x31, 0x8D, 0x87, 0xCF, 0xE4, 0x76, 0x18, 0x03, 0xE9, 0xA6, 0x0D, 0xEF, 0xA6, 0x14, 0x4A, 0xAB, 0xC1, 0xF1, 0x0A, 0x45, 0xB1, 0x40, 0xDE, 0xD7, 0x54, 0xE7, 0x35, 0x86, 0xC4, 0x67, 0xBB, 0x7B, 0xF1, 0x9E, 0xDE, 0xF2, 0x5B, 0xE0, 0xC6, 0x5E, 0x93, 0xC5, 0xE5, 0xEB, 0x8F, 0x88, 0x0C, 0xCE, 0x4A, 0x85, 0x87, 0x57, 0xF8, 0xFF, 0x56, 0x06, 0x2B, 0x10, 0x67, 0xF4, 0x10, 0x6F, 0x76, 0xB7, 0x00, 0x7F, 0x6E, 0xA6, 0xF9, 0x45, 0x04, 0x7E, 0x85, 0xBD, 0x0F, 0xAD, 0x9D, 0x26, 0x99, 0x4F, 0x67, 0x8A, 0x06, 0x12, 0xB8, 0x7C, 0xCF, 0x9C, 0x0C, 0xF9, 0xA4, 0x33, 0xD8, 0x89, 0xC9, 0x6E, 0x4C, 0x12, 0xBE, 0x37, 0x22, 0x77, 0x00, 0x5B, 0x06, 0xAD, 0x12, 0x71, 0x05, 0xD1, 0x6D, 0x8F, 0xB1, 0x42, 0xAE, 0xAE, 0x53, 0x73, 0xAB, 0xD6, 0x1D, 0x9A, 0xDC, 0xFC, 0x55, 0x50, 0xD6, 0x23, 0xCA, 0x3B, 0x88, 0x24, 0xB0, 0xE2, 0xE0, 0x8C, 0x2B, 0xF4, 0xE2, 0x84, 0x1E, 0xAC, 0x4C, 0x5D, 0xC5, 0x6C, 0xF8, 0x95, 0x4C, 0xF2, 0x07, 0xC2, 0x63, 0xF2, 0x7C, 0x9F, 0x30, 0x9F, 0x10, 0x30, 0x7C, 0x0D, 0x84, 0xA6, 0x58, 0x78, 0x42, 0x50, 0x31, 0x37, 0x5D, 0xD8, 0x10, 0xD2, 0xD7, 0xE5, 0x10, 0x98, 0xA3, 0x81, 0x43, 0x50, 0x79, 0x5C, 0x4A, 0x07, 0x7F, 0xA4, 0x0D, 0xD4, 0x4F, 0x0F, 0xA7, 0x51, 0x0F, 0x7C, 0x3F, 0x63, 0x14, 0x07, 0xCF, 0x34, 0xF6, 0x04, 0xC7, 0xB3, 0x35, 0x63, 0x2A, 0x20, 0xD2, 0xAD, 0x41, 0x9B, 0xD7, 0xCC, 0x6D, 0x42, 0x42, 0xB1, 0xC6, 0x6C, 0x35, 0xE5, 0xA5, 0xED, 0xCC, 0xB1, 0x3C, 0xA3, 0x7D, 0x3B, 0x50, 0x46, 0x5F, 0x3B, 0x4A, 0xAF, 0xF7, 0xE3, 0x16, 0x1E, 0x79, 0x36, 0x08, 0x8A, 0xE0, 0x84, 0x01, 0xFD, 0x2C, 0x37, 0xD6, 0x7A, 0x2F, 0xF9, 0x1D, 0x3E, 0x6F, 0x08, 0x68, 0x6D, 0x64, 0xBC, 0x2F, 0xC6, 0xC5, 0x71, 0x06, 0xE4, 0x9F, 0xA3, 0x84, 0xAC, 0x22, 0x21, 0x9F, 0x07, 0xEE, 0x89, 0x96, 0xCA, 0x3D, 0xFF, 0x59, 0xDC, 0xC5, 0x09, 0x2A, 0x4B, 0xAD, 0xBE, 0x87, 0xAE, 0xDE, 0x7F, 0x69, 0xA0, 0x4C, 0x79, 0xB3, 0x3B, 0xDF, 0x35, 0xD4, 0xA0, 0xE4, 0xCB, 0x4B, 0x55, 0x01, 0x9C, 0xB0, 0xBF, 0x27, 0x52, 0x95, 0xB9, 0x3B, 0xDA, 0xBE, 0xA5, 0x16, 0xCA, 0x2B, 0x61, 0x6A, 0x56, 0x91, 0x86, 0x00, 0xB7, 0x24, 0xBE, 0x7A, 0x01, 0xEC, 0x4E, 0xF5, 0x43, 0x12, 0xB3, 0x0D, 0x66, 0xF5, 0x07, 0x81, 0x5F, 0x27, 0x80, 0xFF, 0xEE, 0x7C, 0x30, 0xF8, 0x42, 0x5A, 0x92, 0x25, 0x2C, 0xE5, 0x50, 0xFA, 0xB4, 0xE9, 0x02, 0xE7, 0xB3, 0x82, 0xD4, 0x6D, 0xBD, 0x20, 0xEF, 0xE1, 0xBB, 0x0E, 0xF8, 0xA4, 0x96, 0x87, 0x3C, 0x09, 0xC4, 0xCE, 0xB0, 0x30, 0x3C, 0x7F, 0x1D, 0xAB, 0xA0, 0x10, 0x2D, 0xE9, 0x41, 0x90, 0xB6, 0xAC, 0x6D, 0xC8, 0x10, 0xF7, 0x2B, 0xCA, 0x3A, 0xA2, 0x92, 0xFF, 0x38, 0xBD, 0x51, 0xA7, 0xFA, 0xB8, 0x50, 0x9E, 0xC4, 0xFB, 0xE0, 0xEA, 0xA3, 0xC9, 0x86, 0x16, 0x6A, 0x67, 0x4B, 0x78, 0x71, 0x15, 0x5C, 0x34, 0x8C, 0x47, 0x7E, 0xF8, 0xCE, 0xDC, 0x83, 0x2B, 0x5A, 0xBE, 0xE7, 0x1A, 0x8D, 0x18, 0xD0, 0x6D, 0xD0, 0xF5, 0x22, 0x11, 0x60, 0xAB, 0xEB, 0x71, 0xE6, 0xE8, 0x2C, 0xFA, 0xBF, 0x73, 0x1E, 0xA3, 0x51, 0x5A, 0x76, 0xEF, 0x07, 0xB2, 0xC1, 0x6C, 0x63, 0xB3, 0x7F, 0x7A, 0xB7, 0x3B, 0x67, 0xF0, 0x05, 0x92, 0x9A, 0x75, 0x3E, 0x45, 0x3B, 0x93, 0x0C, 0x0A, 0xF4, 0x32, 0x27, 0x7F, 0xD7, 0x7D, 0x8A, 0x1E, 0xB8, 0x02, 0x2C, 0xDE, 0x96, 0x65, 0x76, 0x3B, 0x01, 0x4F, 0x0A, 0x67, 0x2A, 0x04, 0x16, 0x0B, 0x0A, 0x06, 0xF5, 0x54, 0x0F, 0x4C, 0x26, 0x4B, 0x7F, 0x22, 0x74, 0x06, 0x90, 0xA2, 0x35, 0x2D, 0xC8, 0x63, 0xB5, 0x88, 0x30, 0x3A, 0xD5, 0x1F, 0x0A, 0xE1, 0x62, 0xBF, 0x79, 0x79, 0x7F, 0x07, 0xB5, 0x34, 0x50, 0x1C, 0xBB, 0xFD, 0xB7, 0x13, 0xA7, 0x24, 0xAA, 0x98, 0xE1, 0x95, 0x32, 0x18, 0x71, 0x80, 0xCC, 0xFA, 0xDC, 0x6E, 0xBE, 0x31, 0x42, 0xFA, 0x7D, 0xB6, 0x6C, 0xD4, 0xDE, 0x7B, 0x9F, 0xBD, 0x4C, 0x82, 0x35, 0x68, 0x6D, 0xB6, 0x8C, 0xAF, 0x48, 0x9A, 0xFA, 0x4E, 0x1E, 0x87, 0xAE, 0xF0, 0xCE, 0xFD, 0x80, 0x37, 0xE3, 0xA5, 0x78, 0xEE, 0x62, 0xEB, 0x7F, 0x94, 0xED, 0x5B, 0xC0, 0xB5, 0x8E, 0xEA, 0x4B, 0x4C, 0x45, 0xFC, 0x56, 0xD3, 0x1D, 0x29, 0x94, 0x4D, 0x09, 0x5A, 0xC9, 0x6C, 0x29, 0x08, 0x3D, 0xA2, 0xC7, 0x71, 0x81, 0xD9, 0x7A, 0x55, 0xFE, 0x6E, 0x90, 0x3A, 0x2F, 0x27, 0x83, 0xDE, 0x0B, 0xAA, 0x5F, 0x47, 0xD7, 0x04, 0x78, 0x5C, 0x33, 0xE8, 0xD5, 0xC8, 0x7E, 0xD6, 0x1E, 0x65, 0x45, 0x91, 0x67, 0x31, 0x0E, 0xB7, 0xA9, 0x95, 0x74, 0xEF, 0x81, 0x9A, 0xE9, 0x16, 0x1A, 0x3B, 0xD0, 0x96, 0x34, 0x80, 0x3D, 0x9E, 0x1E, 0x4E, 0xC7, 0x38, 0x6D, 0x79, 0x46, 0x98, 0x45, 0x17, 0x21, 0x3A, 0xB9, 0xCF, 0x66, 0xAE, 0xA5, 0x51, 0xCC, 0x45, 0x7C, 0x39, 0xF8, 0x6A, 0xF2, 0x94, 0xCF, 0x7B, 0x07, 0x3F, 0x56, 0x3E, 0xD4, 0xDA, 0xB9, 0x41, 0x9B, 0xDF, 0x00, 0x4B, 0xD0, 0x5C, 0x92, 0xB4, 0xE8, 0x0E, 0xC3, 0xCF, 0xEA, 0xC9, 0x7E, 0x1D, 0xDA, 0x55, 0x4F, 0xDA, 0x62, 0x5C, 0x4B, 0x9B, 0x03, 0x9B, 0xAA, 0x7C, 0x5A, 0x2F, 0x6F, 0x97, 0x05, 0x77, 0x92, 0x48, 0x3C, 0xF5, 0xF8, 0x52, 0xD4, 0xC3, 0xAC, 0x71, 0xAD, 0x50, 0xF7, 0x79, 0x95, 0x3D, 0xCF, 0xE2, 0xF6, 0x3E, 0xD2, 0x35, 0xD8, 0xE1, 0xD5, 0x34, 0x5D, 0x6C, 0x6D, 0xF0, 0x55, 0x5C, 0xC2, 0x63, 0x1D, 0xEA, 0xD9, 0xB7, 0x14, 0xBC, 0x4C, 0x16, 0x50, 0x1E, 0x01, 0x26, 0x13, 0x81, 0xF3, 0x67, 0x97, 0x15, 0x34, 0x51, 0x23, 0x38, 0x8C, 0x85, 0x2D, 0x57, 0xDC, 0xF1, 0x94, 0x1D, 0x09, 0x11, 0xD4, 0x9F, 0xEA, 0x71, 0x43, 0xFD, 0x2F, 0xC3, 0x43, 0xA5, 0x07, 0x5B, 0x64, 0xCC, 0xA4, 0x82, 0x91, 0xDC, 0x28, 0xB8, 0x3F, 0x76, 0x07, 0x45, 0x89, 0xEA, 0xB2, 0x17, 0xC7, 0x84, 0x78, 0x40, 0x65, 0x2C, 0x0E, 0x3A, 0xE2, 0x78, 0xB3, 0xB6, 0xFB, 0x0D, 0x80, 0x0C, 0x5E, 0x7D, 0xB7, 0x9D, 0x5C, 0xB9, 0xCC, 0x1A, 0x87, 0x45, 0x0C, 0x00, 0xB7, 0x67, 0x78, 0x12, 0xD2, 0x2E, 0xE2, 0x0F, 0xDE, 0x8C, 0x17, 0x53, 0xA7, 0xFB, 0x93, 0xBA, 0x8B, 0xBB, 0x85, 0x95, 0xA6, 0x39, 0x3D, 0xF5, 0x4A, 0xA9, 0xCD, 0xB6, 0xE0, 0x87, 0x9A, 0x26, 0xE4, 0x9B, 0xD3, 0xB0, 0x15, 0x13, 0xC6, 0x05, 0x3A, 0x07, 0x46, 0xC8, 0x59, 0x6C, 0xE5, 0xE5, 0xB2, 0x25, 0xCF, 0xCA, 0x26, 0xAB, 0x8B, 0xF1, 0x2F, 0x1F, 0xE0, 0xA6, 0x47, 0xA9, 0xE4, 0x45, 0x30, 0x39, 0xA1, 0x22, 0x61, 0x94, 0xC4, 0x6E, 0x8B, 0x98, 0xAC, 0xD7, 0x10, 0xF1, 0x8F, 0xB7, 0xEC, 0x05, 0x47, 0x6C, 0x1C, 0xD8, 0xFC, 0x31, 0x12, 0xCC, 0xDD, 0xB1, 0x58, 0x2B, 0x88, 0x17, 0xC1, 0x8F, 0xE3, 0x15, 0x35, 0x3E, 0x7A, 0x47, 0xC8, 0x21, 0xE9, 0xEE, 0x3A, 0x43, 0xCA, 0xDE, 0x1B, 0x80, 0xD9, 0x2A, 0x0A, 0xE8, 0xDC, 0xEB, 0x4D, 0xFF, 0x76, 0x6A, 0x54, 0xDF, 0x36, 0x65, 0xFE, 0xFE, 0x3C, 0x25, 0x2B, 0x72, 0xDA, 0xD7, 0xB1, 0xE3, 0x35, 0x9E, 0x7F, 0xA2, 0x55, 0x62, 0xC3, 0xE3, 0x9D, 0xB5, 0x21, 0xCE, 0x18, 0x74, 0x11, 0x1F, 0xB0, 0x90, 0xDB, 0xD3, 0x8B, 0x31, 0x80, 0xAD, 0x03, 0x4B, 0x57, 0xB0, 0x31, 0xDC, 0x4D, 0xD6, 0xAF, 0x7C, 0x1A, 0x8A, 0xF3, 0xF6, 0xCE, 0x7E, 0xDB, 0x1A, 0x9E, 0x4B, 0x6D, 0x4A, 0x59, 0x20, 0xE3, 0x62, 0x08, 0x18, 0x82, 0x06, 0x59, 0x76, 0x2E, 0xF7, 0xA4, 0x24, 0x3F, 0x51, 0xDF, 0x2D, 0x8A, 0x90, 0x07, 0x37, 0xD5, 0x81, 0x05, 0x69, 0x9B, 0x4E, 0x10, 0xCB, 0xCB, 0x35, 0x9C, 0x7F, 0x3A, 0x40, 0x07, 0x69, 0x7C, 0x48, 0x20, 0x50, 0xEC, 0x33, 0xCF, 0x80, 0x41, 0x91, 0x6A, 0x3B, 0x91, 0x9A, 0x50, 0xD9, 0x6E, 0xF0, 0xF5, 0x89, 0xFD, 0x45, 0x56, 0xF3, 0x0D, 0xBD, 0xD9, 0x42, 0xEA, 0xB7, 0x9D, 0xFA, 0x97, 0xC0, 0x7E, 0x30, 0x24, 0x70, 0x74, 0x35, 0x2E, 0x1B, 0xF9, 0x8E, 0x34, 0x9C, 0xC7, 0xEF, 0xA5, 0xA1, 0xB8, 0xFC, 0xE4, 0xF1, 0x8F, 0x1F, 0xAF, 0x6F, 0x07, 0xC9, 0x9C, 0x32, 0x14, 0x48, 0xB0, 0x39, 0x5C, 0x8A, 0x9C, 0xBC, 0x46, 0x64, 0x12, 0xF8, 0x9C, 0x1A, 0x98, 0xBF, 0x57, 0x15, 0x84, 0x28, 0x44, 0xF0, 0xE8, 0x23, 0x6F, 0xA4, 0x69, 0x6C, 0x46, 0x58, 0xB8, 0xFD, 0xE4, 0x42, 0x5D, 0x09, 0xD6, 0x7A, 0x38, 0xAC, 0x72, 0x58, 0xE5, 0xD5, 0x96, 0x6F, 0x2D, 0x3F, 0xF6, 0x6A, 0x0C, 0x0C, 0xE7, 0x6E, 0x7F, 0x6B, 0x81, 0xA1, 0xBC, 0xD0, 0x47, 0xFD, 0x3A, 0x20, 0x5B, 0xF0, 0xCC, 0xAE, 0xA3, 0xB1, 0x10, 0x79, 0x90, 0x9C, 0x6C, 0xE5, 0x69, 0x8F, 0x32, 0xE1, 0xF3, 0x40, 0x96, 0x58, 0xFF, 0xA0, 0x1E, 0xAE, 0xCB, 0x4A, 0xE2, 0xB0, 0x92, 0xB7, 0x89, 0x89, 0xDA, 0xAD, 0x66, 0x23, 0xBB, 0x11, 0xF4, 0x9F, 0x0F, 0x8F, 0x86, 0x99, 0xEC, 0x05, 0x66, 0x15, 0x02, 0xFF, 0xCA, 0xD0, 0x3C, 0xF4, 0x15, 0x19, 0x1A, 0x22, 0x2D, 0x3C, 0x4C, 0x7B, 0x8A, 0xB0, 0xB5, 0xB9, 0xBB, 0xC2, 0xD9, 0xDC, 0xEF, 0xF7, 0x20, 0x2D, 0x3F, 0x42, 0x44, 0x49, 0x4F, 0x52, 0x53, 0x64, 0x66, 0x69, 0x74, 0xC4, 0xD9, 0xE6, 0xF5, 0xFA, 0x00, 0x01, 0x04, 0x19, 0x27, 0x37, 0x3D, 0x5A, 0x76, 0x80, 0xB8, 0xC1, 0xC9, 0xFE, 0x20, 0x29, 0x38, 0x3B, 0x3C, 0x48, 0x4D, 0x56, 0x5F, 0x65, 0x79, 0x9D, 0x9E, 0xA6, 0xA9, 0xAD, 0xD2, 0xDE, 0xE5, 0xE7, 0xF7, 0xF9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x24, 0x32, 0x48, }, }, { .name = "Dilithium Round 3, Level 3 (4-4) KAT 1", .version = 0, .keyform = CK_IBM_DILITHIUM_KEYFORM_ROUND3_44, .rho_len = 32, .rho = { 0xB5, 0x41, 0xC1, 0xE9, 0x2C, 0xEA, 0xDD, 0x90, 0x4A, 0x09, 0xEC, 0x08, 0xAD, 0x30, 0x6D, 0x97, 0x47, 0x34, 0xA0, 0x77, 0x86, 0x84, 0x71, 0xE5, 0x8D, 0x07, 0x71, 0x87, 0xC4, 0x66, 0x04, 0xCF, }, .seed_len = 32, .seed = { 0x95, 0x2D, 0x21, 0x81, 0xAC, 0x1F, 0x62, 0x59, 0x6F, 0x76, 0x7E, 0xFC, 0xA0, 0xB5, 0x5D, 0xB0, 0x92, 0xEF, 0x81, 0xDB, 0x66, 0xF9, 0xFF, 0xF1, 0x5F, 0x13, 0xD7, 0xAE, 0xEA, 0xCD, 0x8B, 0x3A, }, .tr_len = 32, .tr = { 0x57, 0x96, 0xFB, 0xFE, 0x5B, 0x4E, 0x2E, 0xDE, 0xC5, 0xDB, 0xC9, 0x52, 0xF6, 0x0E, 0xB1, 0x22, 0x90, 0x18, 0x93, 0xCA, 0x25, 0x2D, 0xD7, 0x30, 0x41, 0x2A, 0xC4, 0xB6, 0xE0, 0x20, 0x09, 0x71, }, .s1_len = 384, .s1 = { 0x03, 0x40, 0x28, 0x8C, 0x88, 0x60, 0x21, 0xB1, 0x90, 0x0C, 0x12, 0x0D, 0x58, 0x18, 0x09, 0x23, 0x44, 0x86, 0x03, 0x02, 0x84, 0x89, 0xB2, 0x28, 0x0C, 0x97, 0x2C, 0x11, 0xC2, 0x09, 0x18, 0x32, 0x08, 0x09, 0x10, 0x91, 0x14, 0x82, 0x8C, 0x13, 0x03, 0x05, 0x11, 0x01, 0x4C, 0x62, 0x18, 0x8A, 0xDB, 0x08, 0x8A, 0x93, 0x38, 0x12, 0x09, 0xA9, 0x20, 0xE4, 0xA8, 0x41, 0x1A, 0xA1, 0x40, 0xD1, 0x42, 0x2E, 0x59, 0x92, 0x24, 0xD0, 0x26, 0x00, 0x19, 0x93, 0x84, 0xE2, 0x28, 0x92, 0x1B, 0x19, 0x50, 0xA3, 0x10, 0x8E, 0xA2, 0x28, 0x20, 0x93, 0x34, 0x70, 0x94, 0xC0, 0x4D, 0x24, 0x35, 0x41, 0x14, 0x05, 0x62, 0xC2, 0x22, 0x31, 0x1A, 0x38, 0x4E, 0xCC, 0x42, 0x44, 0x13, 0x20, 0x82, 0x08, 0x18, 0x6D, 0xE0, 0x14, 0x0D, 0x01, 0x36, 0x61, 0x08, 0x22, 0x29, 0x14, 0xB5, 0x11, 0x49, 0x22, 0x32, 0xE2, 0x42, 0x26, 0xE4, 0x04, 0x01, 0x5B, 0x48, 0x2A, 0x11, 0x02, 0x60, 0x63, 0x02, 0x48, 0x4A, 0x24, 0x2C, 0x62, 0x40, 0x90, 0x03, 0x41, 0x8D, 0x18, 0xC8, 0x30, 0x82, 0x02, 0x82, 0x51, 0x98, 0x69, 0xA2, 0x24, 0x50, 0x0A, 0x39, 0x4D, 0x84, 0x00, 0x8E, 0x84, 0x08, 0x21, 0xD9, 0x30, 0x6C, 0xE3, 0x18, 0x29, 0x23, 0x45, 0x6E, 0xCA, 0x24, 0x66, 0x08, 0x21, 0x49, 0x14, 0x16, 0x52, 0xDA, 0xA0, 0x0C, 0x22, 0x19, 0x62, 0xC1, 0xB8, 0x08, 0x8A, 0x88, 0x8C, 0x22, 0xB1, 0x0C, 0x23, 0xB8, 0x0D, 0x00, 0x93, 0x64, 0x93, 0x16, 0x82, 0x63, 0x32, 0x30, 0xDC, 0xA2, 0x41, 0xD1, 0x48, 0x42, 0x82, 0xA2, 0x64, 0xD4, 0x24, 0x48, 0x94, 0x48, 0x25, 0x02, 0x82, 0x65, 0xD9, 0x08, 0x69, 0x12, 0x44, 0x21, 0x54, 0x24, 0x70, 0x04, 0x80, 0x84, 0xDA, 0x44, 0x25, 0xA0, 0x24, 0x8A, 0x13, 0x35, 0x60, 0x84, 0xA0, 0x4C, 0x93, 0x90, 0x48, 0x13, 0x47, 0x02, 0x83, 0x20, 0x05, 0x64, 0xB4, 0x0C, 0x5C, 0x12, 0x72, 0x42, 0x14, 0x86, 0x60, 0x02, 0x12, 0x50, 0x44, 0x04, 0x0B, 0x82, 0x11, 0x91, 0x18, 0x72, 0x48, 0x88, 0x10, 0xD0, 0x40, 0x4D, 0xCB, 0x98, 0x51, 0x49, 0xA4, 0x8D, 0x18, 0x25, 0x89, 0xD4, 0x32, 0x8E, 0x52, 0xA4, 0x10, 0x11, 0x40, 0x12, 0x88, 0x26, 0x88, 0x21, 0x17, 0x6A, 0xA2, 0xB2, 0x41, 0xE4, 0x02, 0x89, 0xA1, 0xA0, 0x30, 0x94, 0xC8, 0x41, 0x1B, 0x83, 0x64, 0x12, 0x05, 0x0A, 0x1C, 0x43, 0x8C, 0x84, 0x06, 0x31, 0x0A, 0xA2, 0x6D, 0x24, 0x17, 0x31, 0xC3, 0x98, 0x28, 0x42, 0x88, 0x25, 0x8C, 0x30, 0x52, 0xA0, 0x02, 0x0E, 0x98, 0x36, 0x88, 0x03, 0x81, 0x31, 0x64, 0x18, 0x6C, 0x09, 0x82, 0x69, 0x19, 0x41, 0x4C, 0xA0, 0x26, 0x11, 0x23, 0x35, 0x60, }, .s2_len = 384, .s2 = { 0x01, 0x04, 0x85, 0x64, 0x86, 0x30, 0xD9, 0x20, 0x84, 0xD9, 0x08, 0x2A, 0xDC, 0x32, 0x61, 0x1C, 0xC2, 0x80, 0x89, 0x82, 0x51, 0x14, 0x10, 0x40, 0x19, 0x05, 0x80, 0x58, 0x04, 0x06, 0x99, 0x08, 0x84, 0x09, 0x27, 0x41, 0xCA, 0x20, 0x8A, 0x93, 0x00, 0x91, 0x03, 0xC6, 0x81, 0xC2, 0xC8, 0x09, 0xC3, 0x30, 0x4D, 0x23, 0x12, 0x0A, 0x9B, 0x42, 0x8D, 0x20, 0x23, 0x6A, 0x54, 0x30, 0x22, 0xCC, 0xA4, 0x29, 0xA2, 0x18, 0x31, 0x40, 0x20, 0x6E, 0x92, 0x90, 0x48, 0x41, 0xB8, 0x45, 0x83, 0x38, 0x08, 0x5C, 0x46, 0x80, 0x59, 0x36, 0x45, 0xE3, 0xB0, 0x31, 0x18, 0x06, 0x6A, 0x53, 0x16, 0x6D, 0x21, 0x99, 0x81, 0x00, 0x30, 0x4E, 0xC8, 0x26, 0x48, 0x18, 0xC0, 0x88, 0x19, 0x14, 0x92, 0xC1, 0x98, 0x45, 0x98, 0x08, 0x84, 0x9B, 0x10, 0x4D, 0x0C, 0x96, 0x90, 0x08, 0x91, 0x69, 0x0C, 0xB1, 0x4D, 0x91, 0x28, 0x6E, 0xC9, 0x06, 0x8C, 0x58, 0x00, 0x0A, 0x0C, 0x96, 0x05, 0x8A, 0x46, 0x06, 0xD4, 0x98, 0x29, 0x83, 0x26, 0x50, 0xE1, 0x10, 0x61, 0xD0, 0x96, 0x50, 0x23, 0x12, 0x24, 0x52, 0x20, 0x80, 0xE4, 0x04, 0x48, 0x0C, 0x23, 0x92, 0x0B, 0xB7, 0x0D, 0x0C, 0x82, 0x90, 0xD1, 0x10, 0x90, 0x21, 0x22, 0x11, 0x0A, 0x12, 0x64, 0x53, 0xB6, 0x71, 0x99, 0x28, 0x69, 0xC1, 0xC4, 0x4D, 0x04, 0xA0, 0x8D, 0xCB, 0x96, 0x41, 0x58, 0x14, 0x06, 0x0C, 0x21, 0x70, 0x8B, 0x30, 0x25, 0x52, 0xA2, 0x25, 0x21, 0x19, 0x30, 0x00, 0xA3, 0x28, 0xD0, 0xB8, 0x09, 0xCC, 0x16, 0x12, 0xDC, 0x94, 0x6D, 0x01, 0x20, 0x81, 0xDC, 0x42, 0x42, 0xE1, 0x28, 0x01, 0x0C, 0x87, 0x89, 0x02, 0x84, 0x09, 0x02, 0x17, 0x88, 0xD8, 0x34, 0x30, 0x1C, 0x33, 0x64, 0x44, 0xA0, 0x09, 0xA0, 0xA0, 0x0D, 0xE3, 0x90, 0x4D, 0x01, 0x08, 0x65, 0xE2, 0x42, 0x69, 0xA2, 0xC0, 0x91, 0x99, 0x16, 0x62, 0x9B, 0x02, 0x60, 0x40, 0x88, 0x50, 0x40, 0x86, 0x71, 0xA4, 0xC4, 0x61, 0x62, 0x22, 0x20, 0x10, 0x12, 0x11, 0x4B, 0x26, 0x22, 0x09, 0x07, 0x88, 0x1A, 0x26, 0x85, 0x58, 0x86, 0x80, 0xDA, 0xA0, 0x8C, 0x0B, 0x85, 0x68, 0x42, 0x22, 0x82, 0x88, 0x24, 0x61, 0x8C, 0x98, 0x8C, 0x23, 0x30, 0x25, 0x24, 0x40, 0x45, 0x08, 0xC8, 0x6C, 0x23, 0x14, 0x28, 0x4A, 0x28, 0x10, 0x81, 0x20, 0x72, 0x88, 0x32, 0x26, 0x93, 0xA6, 0x6D, 0x5B, 0xB6, 0x29, 0xC1, 0x24, 0x0D, 0x49, 0x20, 0x70, 0x59, 0x48, 0x26, 0x20, 0x26, 0x65, 0xCB, 0xA4, 0x88, 0x4A, 0xA6, 0x30, 0x08, 0x45, 0x8E, 0x00, 0x32, 0x88, 0x24, 0x33, 0x0D, 0xA1, 0x46, 0x72, 0x9B, 0x12, 0x00, 0x14, 0xB5, 0x21, 0xE3, 0x02, 0x09, 0x23, 0x42, 0x28, }, .t0_len = 1664, .t0 = { 0x2A, 0xD8, 0xD7, 0x4C, 0xE8, 0x1B, 0x82, 0x66, 0x32, 0x1C, 0x15, 0xEA, 0x97, 0x8C, 0xCC, 0x75, 0xCC, 0x04, 0x3E, 0x18, 0xFA, 0x5B, 0x8E, 0x92, 0x21, 0x9E, 0x47, 0x6F, 0x1F, 0x36, 0xA1, 0x92, 0x43, 0x5C, 0x3F, 0x9B, 0x0A, 0xD4, 0xA6, 0x80, 0x32, 0x18, 0xAA, 0xA1, 0x48, 0x1E, 0x6D, 0x8A, 0x89, 0x48, 0xF1, 0xF6, 0xE0, 0x40, 0x54, 0xBC, 0x30, 0x7F, 0x5B, 0x19, 0xC4, 0x2E, 0x66, 0x90, 0x2C, 0x8C, 0x44, 0xF2, 0xDC, 0xA9, 0xAC, 0x1B, 0xC0, 0x1E, 0x57, 0x6D, 0x59, 0xCA, 0xDC, 0x5C, 0x69, 0x09, 0x02, 0x35, 0xB0, 0x3D, 0x49, 0xA1, 0x09, 0xD9, 0x97, 0xD6, 0x25, 0x68, 0x26, 0xAE, 0xCC, 0x7E, 0xD0, 0xC1, 0x7D, 0xB4, 0xEB, 0x50, 0xCB, 0x82, 0xE6, 0xF1, 0x79, 0xFC, 0x67, 0xAF, 0x16, 0x8F, 0xF5, 0x3E, 0xDA, 0x67, 0x44, 0xBB, 0xF0, 0x92, 0xCE, 0x8A, 0x1F, 0x01, 0xFE, 0xEA, 0x71, 0xB4, 0xD1, 0xA9, 0xB2, 0x7D, 0x6E, 0x21, 0x68, 0x98, 0x38, 0xAB, 0x07, 0x69, 0xFF, 0xD7, 0x59, 0x3A, 0x2B, 0x06, 0x29, 0x72, 0xB3, 0x80, 0xD9, 0xB2, 0x9C, 0x98, 0x7D, 0xC7, 0x60, 0x39, 0x10, 0xC1, 0x5F, 0x4B, 0xD1, 0x98, 0xCE, 0xB6, 0x57, 0xBD, 0x10, 0x3C, 0x2A, 0x43, 0xC7, 0x6D, 0x89, 0xB9, 0x77, 0x90, 0x1F, 0x4E, 0x0E, 0x9C, 0xD8, 0xAC, 0x60, 0x22, 0x8F, 0x96, 0x27, 0x86, 0x49, 0x0A, 0x65, 0xFF, 0xE9, 0x10, 0x4B, 0x9A, 0x6C, 0x32, 0xCF, 0xDE, 0xA6, 0xD0, 0x77, 0x79, 0x17, 0x56, 0x5F, 0xF3, 0x25, 0xD1, 0x19, 0x37, 0x32, 0x32, 0xF9, 0x14, 0xCD, 0xD1, 0xBB, 0xBA, 0xF9, 0x34, 0x45, 0x4D, 0x79, 0x5C, 0xE6, 0xDB, 0xE4, 0xD1, 0x5D, 0x67, 0x27, 0x31, 0xA7, 0x1A, 0x5B, 0xB8, 0x30, 0x43, 0xEB, 0x76, 0x8F, 0x8A, 0x91, 0x85, 0x0A, 0xF4, 0x7C, 0xF5, 0x33, 0xBF, 0x95, 0xEA, 0x40, 0xDB, 0xDD, 0x4F, 0x37, 0xAC, 0x84, 0x93, 0x43, 0x86, 0x06, 0x1E, 0xD5, 0xB5, 0x41, 0xC5, 0x61, 0x6C, 0x68, 0xCA, 0x55, 0xE2, 0xE7, 0xB8, 0x7A, 0x16, 0x28, 0xFA, 0x55, 0x52, 0xA0, 0x48, 0xC0, 0x93, 0x29, 0x6E, 0x22, 0xCE, 0x02, 0x88, 0xC7, 0x6E, 0x7A, 0x13, 0x03, 0xD4, 0xE7, 0x01, 0x23, 0xDD, 0xCF, 0xCF, 0x43, 0xA0, 0x15, 0xDE, 0xE8, 0x39, 0x95, 0x9E, 0x04, 0x4F, 0x7C, 0xBF, 0x57, 0x84, 0xE4, 0x9F, 0x1E, 0xA3, 0x54, 0x00, 0x08, 0x60, 0xB9, 0x56, 0x1B, 0xC4, 0xED, 0xBD, 0xF9, 0x68, 0x20, 0x97, 0xEA, 0xFB, 0xEB, 0xE5, 0x21, 0x5C, 0x8B, 0x4E, 0x8B, 0x03, 0xD1, 0x3A, 0x29, 0x76, 0x5E, 0xE3, 0xF0, 0x53, 0x3F, 0x79, 0x34, 0x28, 0xE2, 0x62, 0xF3, 0x38, 0x54, 0xA6, 0xFE, 0x00, 0x3C, 0x28, 0x4B, 0xDC, 0xB6, 0x6C, 0xD6, 0x8F, 0x98, 0xFB, 0xAA, 0x02, 0x02, 0xCD, 0x1B, 0x85, 0x42, 0x32, 0x5A, 0x15, 0xAA, 0xA2, 0xD2, 0xE7, 0xF8, 0x38, 0xB6, 0x2D, 0x7C, 0x03, 0x64, 0x01, 0x6A, 0xFD, 0xC0, 0x6F, 0xA3, 0xFA, 0x85, 0xAE, 0x8F, 0x8B, 0x1B, 0xEA, 0x4E, 0x62, 0xAA, 0xDF, 0x96, 0x61, 0x82, 0x56, 0x18, 0x5E, 0x6E, 0xF3, 0x1B, 0xF3, 0x0C, 0xAD, 0x1F, 0x72, 0x7F, 0x67, 0x98, 0x0D, 0x03, 0xF7, 0x52, 0xE1, 0x93, 0x64, 0xE5, 0x92, 0xA6, 0xF8, 0xF9, 0x84, 0x95, 0x3E, 0x29, 0x31, 0xA1, 0xA2, 0xF6, 0xEA, 0x01, 0x11, 0xE5, 0x5B, 0xDA, 0x28, 0xA9, 0xFA, 0x6C, 0x05, 0xBB, 0x00, 0x0F, 0x6A, 0x32, 0x03, 0x93, 0x97, 0xA2, 0xA1, 0x97, 0x67, 0x17, 0x26, 0x4B, 0x54, 0xF4, 0x76, 0xE7, 0x09, 0xF6, 0x5B, 0xBA, 0x59, 0x20, 0x33, 0x49, 0x93, 0x0B, 0x18, 0x69, 0x8F, 0x6F, 0xA8, 0x64, 0xE1, 0x47, 0x6B, 0xAD, 0xB4, 0x2E, 0x41, 0xC6, 0xD9, 0xF6, 0xA7, 0xA6, 0x8B, 0x31, 0x6E, 0xA0, 0xC6, 0x2D, 0x3F, 0x01, 0x31, 0x93, 0x4E, 0xD8, 0xD2, 0x90, 0x22, 0xE6, 0x7D, 0x87, 0x12, 0x2C, 0x62, 0x48, 0x68, 0x86, 0x10, 0x7E, 0x8D, 0x45, 0x9D, 0x68, 0x65, 0xE8, 0xA4, 0x3B, 0x3F, 0xCF, 0xFA, 0x27, 0xAE, 0xF2, 0x2C, 0x04, 0x8A, 0x31, 0x35, 0xEE, 0x8A, 0x85, 0x7E, 0x81, 0x3C, 0x24, 0x72, 0x5B, 0x43, 0xF4, 0x26, 0x57, 0xBE, 0xDE, 0xDD, 0x37, 0x3E, 0xD8, 0x5E, 0x39, 0x07, 0x0C, 0x58, 0x5F, 0x1D, 0x78, 0xD7, 0xAD, 0xE4, 0xC4, 0x4A, 0x20, 0x82, 0x27, 0x0A, 0xA6, 0x32, 0x29, 0xA1, 0x64, 0xFC, 0x04, 0x6A, 0x34, 0x41, 0x90, 0x83, 0x57, 0x4E, 0x66, 0xC2, 0xB4, 0x4B, 0x13, 0xDF, 0x71, 0x70, 0x4A, 0xE3, 0x89, 0x05, 0x18, 0x66, 0x61, 0x5B, 0xF1, 0xB2, 0x11, 0x97, 0x0E, 0x40, 0x33, 0x06, 0xBD, 0xF1, 0x51, 0x02, 0xB8, 0x31, 0x44, 0x8B, 0x23, 0xAE, 0xB1, 0x9F, 0x48, 0x69, 0xE9, 0x37, 0x33, 0x3F, 0x67, 0x88, 0xE4, 0xC2, 0x94, 0x31, 0x27, 0xC6, 0x4E, 0x21, 0xCF, 0xC2, 0x99, 0xAD, 0xD8, 0x48, 0xFD, 0x4E, 0xE4, 0x0B, 0x89, 0x1A, 0x8A, 0x5F, 0x51, 0xD1, 0x7A, 0x51, 0x0F, 0x57, 0xA5, 0x4C, 0xD3, 0xD8, 0x3E, 0x86, 0xD0, 0x7B, 0x50, 0x4E, 0xDF, 0x33, 0xE0, 0xDE, 0xED, 0xAC, 0xF7, 0x66, 0xE9, 0x6F, 0x87, 0x05, 0x39, 0x3F, 0xDA, 0xCF, 0xB8, 0x31, 0xBD, 0x42, 0x52, 0xA1, 0x52, 0xF1, 0x49, 0x8D, 0xE3, 0x59, 0xA8, 0xA6, 0x3B, 0x71, 0x61, 0x4E, 0x9A, 0xB3, 0x73, 0x52, 0x61, 0xC8, 0xA6, 0xA9, 0xB3, 0x5E, 0x13, 0x6A, 0x66, 0x04, 0x97, 0x52, 0x02, 0x95, 0x0E, 0x97, 0xFF, 0x52, 0xC7, 0x58, 0xC1, 0x9E, 0x5A, 0x3B, 0x7A, 0xAB, 0x9C, 0xCA, 0xC7, 0x95, 0xDA, 0xE7, 0x19, 0x9D, 0xC0, 0x39, 0xD6, 0x56, 0x67, 0xDB, 0xC6, 0xFD, 0x54, 0xA4, 0xF7, 0x84, 0xFB, 0xD7, 0x24, 0xF1, 0x0D, 0x17, 0x93, 0x4B, 0x81, 0x29, 0xA7, 0xFB, 0xF9, 0xA2, 0x57, 0x73, 0x53, 0xF4, 0x9F, 0xE5, 0x34, 0x7C, 0x66, 0x99, 0x05, 0x23, 0xAD, 0x4F, 0x42, 0x95, 0x35, 0x2F, 0xAE, 0x6C, 0x08, 0x55, 0xE5, 0x40, 0xBB, 0x0E, 0xA6, 0x16, 0xE3, 0x04, 0xEB, 0x26, 0x0C, 0x80, 0xB8, 0x79, 0x20, 0xB9, 0x24, 0xF5, 0xAB, 0x8C, 0x9C, 0x74, 0x5D, 0x45, 0xEE, 0x0E, 0xC0, 0xD1, 0x9B, 0xBB, 0x9E, 0x4D, 0x94, 0xEA, 0x4D, 0xCF, 0x31, 0xC1, 0x67, 0xA4, 0x8D, 0x14, 0xA7, 0x0D, 0xB0, 0x24, 0x9B, 0xCB, 0xAE, 0x69, 0xA0, 0x79, 0xC9, 0x50, 0xAB, 0x2C, 0xF0, 0x53, 0x59, 0x5F, 0xBC, 0xB6, 0x1C, 0x1A, 0xFE, 0x13, 0xE7, 0x4C, 0xE1, 0xA9, 0x73, 0xCA, 0x55, 0xC7, 0x49, 0x77, 0x21, 0xE3, 0xFA, 0xD9, 0xF5, 0x57, 0xD6, 0x71, 0xB3, 0x0B, 0x6C, 0x49, 0xA6, 0x38, 0xA1, 0xEB, 0x2C, 0x4A, 0xC9, 0xBD, 0x6C, 0x68, 0xBF, 0xB5, 0x33, 0xD4, 0xDE, 0xDE, 0xAD, 0xC8, 0xEA, 0xB6, 0x48, 0xA1, 0x1A, 0x97, 0xAF, 0x9C, 0x76, 0x15, 0xE4, 0x15, 0x7C, 0xD0, 0x74, 0x97, 0xE8, 0xBA, 0x6E, 0xBB, 0x8A, 0xA3, 0x4C, 0x89, 0xFF, 0x42, 0xF7, 0x66, 0x04, 0x38, 0x00, 0xBA, 0xC8, 0xD0, 0x7C, 0x94, 0x7B, 0xD0, 0x0D, 0xAF, 0xA4, 0x25, 0x39, 0xBD, 0x78, 0x81, 0x31, 0x71, 0x7D, 0x1D, 0x1D, 0xE3, 0x54, 0xFD, 0xDF, 0x30, 0xDC, 0xCC, 0xFD, 0x62, 0x2F, 0x6C, 0xDD, 0xF0, 0x34, 0xC8, 0x9D, 0x19, 0xC0, 0x15, 0xF3, 0x7E, 0xC3, 0x26, 0x25, 0x7F, 0xB6, 0x1C, 0xA6, 0x67, 0x73, 0x6D, 0x9C, 0x72, 0x39, 0xA8, 0x1F, 0x84, 0xEF, 0x76, 0x16, 0xA1, 0x45, 0x85, 0x6B, 0xB9, 0x79, 0x29, 0x04, 0xE8, 0xD5, 0x0E, 0x93, 0x8F, 0x2B, 0x87, 0x62, 0x3D, 0x56, 0xE4, 0xFB, 0x91, 0xB5, 0x34, 0xF5, 0x7F, 0x3D, 0xB4, 0x44, 0xC6, 0x83, 0x7B, 0x4C, 0xDC, 0xA3, 0xA6, 0x47, 0x97, 0xFD, 0xC5, 0x2E, 0xC6, 0x70, 0xD6, 0xA1, 0x7B, 0x3F, 0xA1, 0x97, 0x93, 0x02, 0x66, 0xD0, 0x3B, 0x4C, 0x0B, 0xEE, 0xE6, 0xEE, 0x27, 0xC1, 0xC4, 0x86, 0xFD, 0x22, 0xC3, 0xB2, 0x0E, 0xE1, 0x81, 0xE4, 0x2C, 0x71, 0x34, 0x70, 0x32, 0x8C, 0x14, 0x36, 0x23, 0xA2, 0x53, 0xAA, 0xE0, 0xB1, 0x45, 0x3D, 0xA0, 0x09, 0xD8, 0xD4, 0xF2, 0x15, 0xD2, 0xF5, 0x77, 0xDD, 0xC9, 0xF8, 0x2D, 0xCB, 0x66, 0x9C, 0x9D, 0x99, 0xF1, 0x74, 0x48, 0x6C, 0x8A, 0x4D, 0x08, 0x04, 0xD3, 0x42, 0xE8, 0xD3, 0x64, 0xF3, 0xB7, 0x36, 0x89, 0x94, 0x96, 0x31, 0xB2, 0x99, 0xD8, 0x73, 0x50, 0x15, 0xDB, 0x99, 0x70, 0x42, 0x07, 0xF0, 0x91, 0x4E, 0x6F, 0xCB, 0xF9, 0x21, 0xA1, 0x8D, 0xF0, 0xC8, 0x08, 0x40, 0x45, 0x09, 0x28, 0x39, 0xCC, 0x96, 0xEA, 0xA5, 0xD2, 0xF6, 0xB6, 0x60, 0x00, 0x61, 0x6B, 0x7D, 0x2D, 0xED, 0x28, 0x5F, 0xF9, 0xA9, 0x24, 0x06, 0x81, 0x4A, 0x57, 0xC2, 0x64, 0x68, 0xCC, 0x1D, 0x6C, 0x69, 0x47, 0x97, 0x63, 0x7B, 0x5B, 0xA5, 0x36, 0x4F, 0xD4, 0x60, 0x68, 0xCF, 0xE5, 0xC8, 0x22, 0xD2, 0xBB, 0xBD, 0xB3, 0x57, 0xC7, 0x6A, 0x36, 0x39, 0xAB, 0x99, 0x96, 0x85, 0xED, 0x6D, 0x6D, 0x3A, 0xFE, 0x6B, 0x48, 0xB8, 0x0C, 0x87, 0x01, 0x26, 0x60, 0xD9, 0x6F, 0x75, 0x1C, 0x11, 0x1C, 0x9F, 0x4A, 0x0D, 0x30, 0xA0, 0x60, 0xAF, 0x55, 0x43, 0x5D, 0xB3, 0x38, 0x97, 0xE6, 0x09, 0x1E, 0x6E, 0x02, 0xD0, 0x85, 0x66, 0xF0, 0x90, 0xE6, 0xEE, 0xA4, 0x31, 0x04, 0x8D, 0x8D, 0xB9, 0xC9, 0xC4, 0x98, 0x5A, 0x2A, 0x81, 0x14, 0xC9, 0xFF, 0x35, 0xCA, 0x39, 0x72, 0x33, 0x14, 0x98, 0x5D, 0x93, 0x96, 0x15, 0x4D, 0xE5, 0xC2, 0x95, 0xC9, 0xE6, 0x35, 0xB3, 0x1A, 0x4D, 0x23, 0x4B, 0x79, 0xE0, 0xE8, 0x04, 0xB3, 0xFE, 0x11, 0xCD, 0xD2, 0x99, 0xEE, 0x77, 0xE7, 0x2E, 0x16, 0xD4, 0x26, 0x3B, 0xFC, 0x4C, 0xF8, 0x97, 0x21, 0xAB, 0x5E, 0x9B, 0xBC, 0x64, 0xFF, 0xA8, 0xDE, 0xC4, 0x52, 0x0D, 0xCB, 0x5E, 0x88, 0x81, 0xF3, 0x61, 0xCD, 0x18, 0xF2, 0x13, 0x9C, 0x8C, 0xB4, 0x2A, 0x4D, 0x67, 0xFD, 0x7F, 0xA4, 0x27, 0x63, 0x56, 0xB4, 0xC3, 0x9B, 0xC2, 0x63, 0x23, 0x4E, 0xA6, 0xA9, 0xCA, 0xBC, 0xE7, 0x2D, 0x86, 0xF4, 0xEF, 0x36, 0x44, 0x82, 0x05, 0x02, 0x3F, 0x62, 0xCC, 0x4D, 0xE6, 0x19, 0xF5, 0x57, 0x26, 0x87, 0x13, 0x89, 0xB3, 0x05, 0xEE, 0x54, 0x5E, 0x69, 0x29, 0xDF, 0x24, 0x2F, 0xDF, 0xA8, 0xF9, 0x9B, 0x3F, 0x9C, 0xBF, 0x86, 0x21, 0x0A, 0xD1, 0x15, 0x4A, 0x64, 0xF2, 0x79, 0x99, 0x51, 0x52, 0xCC, 0x39, 0xB0, 0x17, 0xE4, 0x58, 0x95, 0xE7, 0xC0, 0xF8, 0xBC, 0xA0, 0xE1, 0xD9, 0xF2, 0x94, 0xE1, 0xE0, 0x63, 0xCF, 0xDC, 0x9A, 0xE0, 0xC7, 0x37, 0x57, 0x90, 0x48, 0x2E, 0x5B, 0xB0, 0xFD, 0x67, 0xB7, 0xA1, 0xAC, 0xA1, 0x6A, 0xB1, 0xDD, 0xB3, 0xE3, 0x8B, 0xE9, 0x2C, 0x9D, 0x76, 0xA7, 0x99, 0xC7, 0x94, 0x7C, 0xB6, 0xD7, 0x75, 0xBD, 0xFD, 0x85, 0x93, 0x50, 0xBF, 0x85, 0x89, 0x0A, 0x37, 0xD8, 0x8E, 0xA1, 0x60, 0x6A, 0xDE, 0x48, 0x03, 0xF0, 0x75, 0xEB, 0x1A, 0x13, 0x04, 0xF0, 0xF7, 0xBA, 0xDA, 0xFF, 0xF4, 0x4D, 0xA2, 0xC7, 0xF9, 0x32, 0xB2, 0x5F, 0x2D, 0xAA, 0x9B, 0xCD, 0xCF, 0x0C, 0xB8, 0x42, 0x77, 0xAB, 0xC2, 0xCB, 0xF6, 0xA7, 0x1C, 0x1C, 0xED, 0xE8, 0x79, 0xAA, 0x0D, 0x0C, 0x56, 0xE0, 0xE0, 0x40, 0x91, 0xBE, 0xD2, 0x3F, 0x22, 0x3D, 0x66, 0xF7, 0x3C, 0x77, 0x10, 0x49, 0x64, 0x44, 0xBE, 0x4E, 0x39, 0x5F, 0x46, 0xCA, 0xA8, 0x34, 0x79, 0x51, 0xB2, 0xB1, 0xF0, 0xD1, 0x87, 0x4F, 0x31, 0x78, 0xE1, 0xE3, 0x20, 0xA9, 0x18, 0x17, 0xBD, 0xCE, 0x17, 0x8F, 0x64, 0x9D, 0x68, 0xB1, 0x4D, 0x55, 0x9F, 0x06, 0x74, 0x3F, 0xA7, 0xCC, 0x74, 0x35, 0x2E, 0xF2, 0x27, 0x50, 0x34, 0x34, 0x8D, 0x75, 0x55, 0x6E, 0x49, 0xEA, 0xA2, 0xF9, 0xC7, 0xDA, 0xA9, 0xBC, 0x3F, 0x32, 0x8D, 0x2F, 0x4E, 0x65, 0x78, 0xA6, 0xE4, 0xC4, 0xA4, 0x73, 0x2F, 0xB0, 0x04, 0x25, 0x22, 0x9E, 0xEC, 0x97, 0xD1, 0x40, 0xB7, 0xEC, 0x1E, 0x4A, 0x1C, 0xED, 0x27, 0xB7, 0x72, 0xD9, 0x99, 0x10, 0xFE, 0x1E, 0x28, 0xD2, 0x5B, 0xA9, 0x9F, 0xC2, 0x56, 0xF3, 0xAA, 0xD1, 0x9C, 0x1D, 0x55, 0x9A, 0x4B, 0xD8, 0xA4, }, .t1_len = 1280, .t1 = { 0x2D, 0xD6, 0x04, 0xD5, 0x36, 0x57, 0x11, 0xDA, 0xA1, 0xAF, 0xD0, 0x6E, 0x8E, 0xAF, 0x68, 0x7C, 0x39, 0x99, 0x62, 0x4D, 0x3C, 0x18, 0x10, 0x84, 0xA0, 0x72, 0x73, 0xB5, 0x5E, 0xF3, 0xA8, 0x4C, 0x60, 0x98, 0x70, 0x3E, 0xCF, 0x97, 0xF7, 0xD4, 0x64, 0xC6, 0x52, 0x17, 0xAB, 0x2D, 0x5D, 0x34, 0x89, 0x35, 0x3C, 0x3E, 0x2B, 0x17, 0x27, 0x24, 0x55, 0xB0, 0x8A, 0x92, 0x18, 0x0B, 0xBC, 0x9E, 0xCB, 0x88, 0x16, 0xC5, 0x4D, 0x98, 0x80, 0x01, 0x34, 0xB2, 0x38, 0xE0, 0x15, 0x84, 0xC1, 0x07, 0x7C, 0xAB, 0x47, 0x12, 0x83, 0x80, 0xD9, 0x26, 0x34, 0xCB, 0x29, 0x1E, 0x95, 0x8A, 0x62, 0xAC, 0x22, 0xF0, 0x50, 0x1C, 0xFF, 0x04, 0x7A, 0xB9, 0x75, 0x6D, 0x58, 0xE2, 0xC4, 0x6C, 0xA1, 0xCB, 0xED, 0xC6, 0x11, 0x85, 0x72, 0x1F, 0xE0, 0x0D, 0xAF, 0xFC, 0x5E, 0xFD, 0xFD, 0x40, 0xE2, 0xD4, 0x5F, 0x06, 0x8A, 0xD1, 0x8C, 0x42, 0xCD, 0xDC, 0x6C, 0x26, 0xF0, 0x42, 0xFB, 0xBA, 0xF8, 0xDE, 0x52, 0x4B, 0xF1, 0x0C, 0x5E, 0x56, 0xA6, 0x36, 0x9F, 0xCB, 0xF7, 0x41, 0x4B, 0xA8, 0x51, 0xD7, 0x54, 0x6C, 0x0A, 0xDB, 0xA0, 0xDD, 0xDE, 0x66, 0xA9, 0x85, 0x2F, 0x05, 0xB8, 0x12, 0xFC, 0xCB, 0x66, 0xCA, 0x7A, 0x0E, 0xD2, 0xC5, 0xBD, 0x36, 0x55, 0xBF, 0xD8, 0xAA, 0x4B, 0xEF, 0xB8, 0x63, 0xFC, 0xEE, 0xE2, 0xEB, 0x4F, 0x66, 0x81, 0xC7, 0x5A, 0x75, 0xD4, 0x2C, 0xA4, 0x60, 0x01, 0x6B, 0x98, 0xA7, 0x75, 0x11, 0x4C, 0xC8, 0x37, 0x6C, 0x74, 0x2B, 0xD7, 0x20, 0x2F, 0x81, 0xE3, 0x7E, 0xAB, 0xA9, 0xE4, 0x37, 0x8B, 0x7B, 0xD3, 0xF0, 0xED, 0xBA, 0x40, 0xAA, 0xB7, 0x15, 0xD4, 0x5E, 0x66, 0x63, 0xC9, 0x9B, 0xE6, 0x34, 0x38, 0xB9, 0x58, 0x36, 0x8C, 0xB2, 0x3F, 0x42, 0xF5, 0x4E, 0xBC, 0xDC, 0xDA, 0x4F, 0x85, 0x70, 0xCA, 0xFE, 0x2E, 0xA1, 0x72, 0x8C, 0x0B, 0x23, 0xD9, 0xBB, 0x22, 0xFA, 0xB6, 0x92, 0x2E, 0xA6, 0x69, 0x4D, 0x7F, 0xDF, 0xCA, 0x08, 0xC7, 0x7E, 0xD4, 0x88, 0xAC, 0x5F, 0xEF, 0xDC, 0xA7, 0x88, 0x9E, 0xE4, 0xED, 0x5F, 0xDA, 0xA7, 0xA1, 0x26, 0xDC, 0xA6, 0xD5, 0xEF, 0x6C, 0x43, 0xBF, 0x35, 0xB6, 0x12, 0x2E, 0x6E, 0xF0, 0xE5, 0x81, 0xAC, 0x33, 0x82, 0x38, 0xE5, 0x14, 0xAA, 0x3A, 0xA9, 0x62, 0x48, 0xEB, 0x6D, 0x58, 0x38, 0xD3, 0x41, 0x74, 0x12, 0x75, 0x82, 0x33, 0xA0, 0x5C, 0x56, 0xEC, 0x4B, 0x5C, 0x5F, 0x1B, 0x59, 0x22, 0x5E, 0x53, 0xEE, 0x2D, 0xA1, 0xF8, 0x32, 0x6C, 0x50, 0xE6, 0x98, 0x8B, 0xF6, 0x14, 0x58, 0x7F, 0x37, 0xBE, 0xA8, 0x7B, 0xF4, 0x57, 0x15, 0x46, 0x34, 0xCC, 0xF3, 0xE7, 0xE9, 0xA6, 0xD1, 0x59, 0x04, 0x92, 0x51, 0x80, 0xDB, 0xE0, 0xEA, 0x7B, 0x2B, 0xDA, 0x61, 0x5A, 0x4D, 0xE6, 0xE8, 0x3A, 0x48, 0x47, 0xD6, 0x0A, 0xC4, 0xAC, 0x7F, 0x80, 0xA9, 0x3D, 0xC6, 0xBE, 0x06, 0xA4, 0x80, 0x10, 0x21, 0xFE, 0x7C, 0x71, 0x78, 0x58, 0xF5, 0x64, 0x8A, 0x5E, 0x53, 0x87, 0x0C, 0x6D, 0x42, 0xB7, 0x7D, 0x29, 0x89, 0x0E, 0xB5, 0x45, 0x65, 0x7B, 0x7A, 0xF6, 0xE1, 0x40, 0xA7, 0xE1, 0x4B, 0x88, 0xD3, 0x1D, 0xC0, 0x72, 0xCD, 0x9A, 0x41, 0xC6, 0x6B, 0xB2, 0xC7, 0x08, 0x9F, 0x4F, 0x16, 0x7B, 0xA0, 0xDD, 0xF9, 0x08, 0xAD, 0x7A, 0x2A, 0xB0, 0xCE, 0x19, 0xCC, 0x4A, 0x17, 0x7E, 0x0C, 0xF1, 0x2C, 0x8A, 0xFE, 0xC9, 0x85, 0x8C, 0x39, 0x24, 0x73, 0x8F, 0x04, 0xDD, 0xDF, 0xDA, 0xF8, 0x53, 0xF7, 0xED, 0xCB, 0xE5, 0x2F, 0xCA, 0xF3, 0xE3, 0x82, 0xC7, 0x12, 0xC4, 0xE8, 0x21, 0xC2, 0x4D, 0xF9, 0x1D, 0x15, 0x73, 0xA7, 0x4C, 0xE2, 0x1E, 0x44, 0xEF, 0xBA, 0x8A, 0x8E, 0xC6, 0xE6, 0xD5, 0xEE, 0x0B, 0xD8, 0xEB, 0xE0, 0x24, 0x36, 0x62, 0x35, 0x72, 0x35, 0x3E, 0x42, 0x10, 0xCB, 0x84, 0xD1, 0x28, 0x3E, 0x1F, 0x6B, 0xA7, 0x26, 0xB2, 0x74, 0x6E, 0xB4, 0x36, 0x2D, 0x46, 0x4C, 0xF2, 0xE2, 0x78, 0xB2, 0xC4, 0x35, 0x68, 0xC9, 0xD7, 0x76, 0x14, 0xDD, 0xCA, 0x1B, 0x19, 0x3D, 0x3C, 0xCA, 0x67, 0xFC, 0x7B, 0x4B, 0x41, 0x17, 0xD1, 0xFE, 0x2D, 0x17, 0x80, 0xEF, 0x90, 0x53, 0x8A, 0xFA, 0xEA, 0xDF, 0xB3, 0x76, 0xE3, 0x18, 0x33, 0x0E, 0x78, 0x5A, 0xF1, 0x03, 0x75, 0x3F, 0xD5, 0x99, 0x17, 0xBA, 0xBB, 0xC0, 0xC8, 0xD7, 0x53, 0x2E, 0x0A, 0x54, 0xBF, 0x8E, 0x91, 0xF4, 0xAA, 0xAA, 0xDC, 0x9D, 0x53, 0x51, 0x3A, 0x04, 0xA1, 0xB5, 0x30, 0xD7, 0x11, 0xC4, 0x04, 0x69, 0x06, 0x3A, 0xB2, 0xFB, 0xF5, 0xEA, 0xEB, 0x2A, 0x94, 0x1A, 0x58, 0x12, 0x6E, 0xB5, 0x80, 0x2D, 0x1A, 0x97, 0xD4, 0x4B, 0xF3, 0x40, 0x82, 0xB0, 0x26, 0x41, 0x0A, 0x83, 0xD4, 0x2D, 0xFB, 0x4C, 0x5D, 0xD1, 0xDB, 0xA8, 0xC1, 0x9D, 0x33, 0xDD, 0x53, 0xB6, 0x1A, 0x7B, 0x58, 0x6A, 0xA0, 0x6D, 0xC4, 0x41, 0x4B, 0xB4, 0xC5, 0x3F, 0x26, 0xE0, 0x5A, 0x69, 0xCB, 0x71, 0x9C, 0xFD, 0xCE, 0x1E, 0x27, 0x29, 0x77, 0xC5, 0x26, 0xCF, 0xC1, 0xB3, 0xA7, 0x24, 0x82, 0xAA, 0x24, 0x61, 0xF1, 0xC4, 0x67, 0x24, 0xF2, 0xD9, 0xCA, 0x9D, 0x31, 0xF9, 0x3E, 0x9D, 0x3C, 0x55, 0xD9, 0x44, 0xA5, 0x6D, 0xB9, 0x47, 0x0E, 0x45, 0x41, 0xE2, 0x17, 0xC8, 0x02, 0xC1, 0x9A, 0x2F, 0x93, 0x23, 0xEF, 0xB5, 0x8F, 0x62, 0xCA, 0xF6, 0xFA, 0x86, 0x06, 0x1D, 0xD8, 0x8A, 0x89, 0xF0, 0x82, 0x71, 0x31, 0x8D, 0xE8, 0xA8, 0x1A, 0x56, 0x65, 0x64, 0x33, 0x20, 0x10, 0xFF, 0xE4, 0xC8, 0x8A, 0x2A, 0x02, 0x26, 0x51, 0xAA, 0x32, 0xF5, 0x73, 0xB3, 0xB1, 0x54, 0xAA, 0x8C, 0xF1, 0x0D, 0xFB, 0xDC, 0xC0, 0xC5, 0x7B, 0x23, 0x41, 0xCF, 0x9D, 0x6E, 0x5F, 0xDA, 0x17, 0xA7, 0xA3, 0x61, 0x6D, 0x24, 0x24, 0xCA, 0x2B, 0x9F, 0xE0, 0x8D, 0xC6, 0xC2, 0x96, 0xDF, 0xA2, 0xBE, 0x9D, 0xE8, 0xE5, 0x3C, 0x32, 0x8B, 0x8D, 0x66, 0x14, 0x2A, 0xE2, 0x33, 0xEF, 0xA3, 0x0D, 0x90, 0xE9, 0x1A, 0x75, 0x78, 0x67, 0x56, 0xB8, 0xAB, 0x25, 0xC1, 0x5B, 0x91, 0xCF, 0x34, 0xA0, 0xE1, 0x2D, 0xAC, 0x9D, 0x5E, 0x52, 0x5A, 0xA5, 0x8D, 0x22, 0x9D, 0x4E, 0x60, 0xDC, 0x2A, 0xB2, 0x7C, 0x61, 0x79, 0x0F, 0xAE, 0x21, 0x5C, 0x20, 0x05, 0x20, 0x21, 0x6C, 0xBB, 0x39, 0x8A, 0x20, 0x9B, 0x78, 0x4E, 0x31, 0xAF, 0x7E, 0x15, 0xF0, 0xA0, 0x07, 0x31, 0x95, 0x74, 0x88, 0x7E, 0x6C, 0x27, 0x66, 0xA0, 0x40, 0x96, 0xAF, 0x1E, 0xDC, 0x45, 0x93, 0xF2, 0xFA, 0x91, 0x8F, 0x1A, 0x48, 0x51, 0xEF, 0x4C, 0xDB, 0x7A, 0xDD, 0xC4, 0x08, 0xDC, 0x3C, 0x57, 0x91, 0x5C, 0x8B, 0xD9, 0x90, 0xC1, 0x00, 0x06, 0x16, 0x9D, 0x84, 0xFB, 0xDF, 0x13, 0xC7, 0x09, 0x7B, 0xEC, 0x77, 0xE3, 0xF1, 0x47, 0x57, 0x60, 0x23, 0x23, 0x2A, 0x74, 0x50, 0xF7, 0x86, 0x4F, 0x21, 0xB3, 0x28, 0xAC, 0xBA, 0x0A, 0x4B, 0x21, 0x25, 0x6B, 0x1B, 0x08, 0xD4, 0xA4, 0xCD, 0x7A, 0xA5, 0x3A, 0x30, 0x7B, 0xC1, 0xAE, 0x36, 0x0D, 0x78, 0xE9, 0x3D, 0x43, 0x82, 0xBC, 0xD5, 0x83, 0x6E, 0x30, 0x19, 0xF6, 0x7A, 0x1F, 0x5C, 0x39, 0xA3, 0x0E, 0x8E, 0x9F, 0xA7, 0xB9, 0x62, 0x2C, 0xFA, 0xD1, 0x1A, 0x50, 0xF2, 0xE4, 0xF1, 0x7D, 0xBE, 0x8F, 0xF2, 0x49, 0x8B, 0xEF, 0xCE, 0x52, 0x8F, 0x24, 0x13, 0x14, 0x26, 0x38, 0xED, 0x76, 0x59, 0x5E, 0xA2, 0x5D, 0xDD, 0x6F, 0xA9, 0xAC, 0x4D, 0xF3, 0x62, 0xFD, 0xC1, 0xAA, 0x83, 0x64, 0x0A, 0x03, 0x39, 0x19, 0x4D, 0xDE, 0x83, 0x03, 0x61, 0xA1, 0x2D, 0xD3, 0xF1, 0xBB, 0x83, 0xAA, 0x7B, 0x22, 0xC4, 0xD5, 0xFC, 0x7A, 0x69, 0xFA, 0xEB, 0xEB, 0xC4, 0x80, 0xEE, 0x83, 0xE8, 0x0B, 0x62, 0xD7, 0xBB, 0x68, 0xFF, 0xAC, 0xBC, 0xAA, 0xB2, 0xE4, 0x8F, 0xE8, 0x1F, 0x20, 0x9B, 0xD9, 0x24, 0x91, 0x51, 0xB2, 0x55, 0x2F, 0xFA, 0x3E, 0x5D, 0x79, 0xFF, 0x54, 0x13, 0xC9, 0x4E, 0x6F, 0xF7, 0x69, 0xDE, 0xB9, 0x7B, 0x29, 0x08, 0xDC, 0xDC, 0x83, 0x6E, 0xC7, 0x0B, 0xFF, 0xE8, 0xF7, 0x07, 0x8E, 0xEB, 0x14, 0x44, 0x0E, 0x01, 0x40, 0xFB, 0x22, 0xE0, 0x25, 0xBC, 0x1A, 0x10, 0x32, 0x67, 0xF9, 0xEA, 0x89, 0x71, 0x06, 0x34, 0x72, 0xB3, 0x39, 0x49, 0xAD, 0x2A, 0x15, 0xC1, 0x74, 0x02, 0x51, 0x31, 0x00, 0x20, 0x8D, 0x72, 0x60, 0x97, 0x18, 0x2F, 0xA1, 0x01, 0xFC, 0x38, 0xC5, 0xC4, 0x81, 0x6A, 0x3A, 0xBC, 0xCF, 0x9E, 0x44, 0xBF, 0x3F, 0x2D, 0x63, 0x4D, 0xA9, 0xBE, 0xC7, 0x67, 0x97, 0x71, 0x49, 0x14, 0x85, 0x21, 0x3D, 0xD6, 0x25, 0xB3, 0x27, 0xD5, 0x3F, 0xF4, 0xED, 0x21, 0xE1, 0xFF, 0x19, 0xE5, 0xD6, 0xC0, 0x44, 0x7F, 0x77, 0xBB, 0xED, 0xF3, 0xF3, 0x7C, 0x63, 0x7A, 0x18, 0x5F, 0xFC, 0x18, 0xA5, 0xEF, 0xCA, 0x43, 0x77, 0xE3, 0x48, 0x6C, 0xED, 0xF5, 0x8A, 0x03, 0xDB, 0x4B, 0x02, 0x3C, 0xF5, 0x17, 0xE1, 0x1D, 0x80, 0xE8, 0xE2, 0x93, 0x54, 0x40, 0x20, 0xA4, 0xFA, 0xB7, 0x80, 0x9D, 0x32, 0xCB, 0xF0, 0x15, 0x1F, 0xF2, 0x3C, 0xC1, 0xB2, 0xC4, 0xBD, 0x0E, 0x41, 0x07, 0xC5, 0xC0, 0xD2, 0x72, 0x2E, }, .pkcs8_len = 0, .spki_len = 0, .msg_len = 66, .msg = { 0x22, 0x5D, 0x5C, 0xE2, 0xCE, 0xAC, 0x61, 0x93, 0x0A, 0x07, 0x50, 0x3F, 0xB5, 0x9F, 0x7C, 0x2F, 0x93, 0x6A, 0x3E, 0x07, 0x54, 0x81, 0xDA, 0x3C, 0xA2, 0x99, 0xA8, 0x0F, 0x8C, 0x5D, 0xF9, 0x22, 0x3A, 0x07, 0x3E, 0x7B, 0x90, 0xE0, 0x2E, 0xBF, 0x98, 0xCA, 0x22, 0x27, 0xEB, 0xA3, 0x8C, 0x1A, 0xB2, 0x56, 0x82, 0x09, 0xE4, 0x6D, 0xBA, 0x96, 0x18, 0x69, 0xC6, 0xF8, 0x39, 0x83, 0xB1, 0x7D, 0xCD, 0x49, }, .sig_len = 2420, .sig = { 0xB5, 0xF8, 0x9A, 0xE9, 0x07, 0x73, 0xF4, 0x9F, 0xB0, 0xAE, 0xFA, 0xFA, 0x2E, 0x5A, 0xC9, 0x5D, 0xB6, 0x5E, 0x53, 0x4A, 0x43, 0x1E, 0x7B, 0x64, 0x1F, 0xEE, 0x75, 0x1F, 0x89, 0x96, 0xC3, 0x67, 0x17, 0xF3, 0xA8, 0x44, 0x7C, 0x99, 0x5D, 0x47, 0x5B, 0xC1, 0xC3, 0x40, 0x4A, 0xDF, 0x42, 0xE9, 0xFD, 0x89, 0x8B, 0x54, 0xED, 0x09, 0x9A, 0xB5, 0x4C, 0x5F, 0x47, 0x1B, 0xC7, 0xC4, 0xBB, 0x39, 0x25, 0x30, 0xF8, 0x21, 0x05, 0x8D, 0xE4, 0xB2, 0xF4, 0x0E, 0xA7, 0xEF, 0x2A, 0x29, 0x7E, 0xC4, 0x0D, 0x65, 0x44, 0x67, 0x95, 0x48, 0x88, 0x55, 0x7D, 0x89, 0xC2, 0x2F, 0x79, 0xCB, 0x44, 0xCC, 0x93, 0x11, 0xFF, 0x98, 0x7A, 0x9E, 0xE2, 0x61, 0x91, 0xE4, 0x27, 0xE9, 0xAF, 0x8F, 0xC8, 0x0F, 0xE7, 0x58, 0xFD, 0x4B, 0xB1, 0x88, 0x6D, 0x83, 0xB2, 0x30, 0x63, 0x4F, 0xD6, 0x5C, 0xE5, 0x3A, 0x03, 0x69, 0x9E, 0xAB, 0xF3, 0x29, 0x20, 0x15, 0x78, 0x14, 0xC9, 0x7D, 0xEE, 0x6C, 0x48, 0x5C, 0x7E, 0x98, 0xA4, 0x31, 0x73, 0x26, 0xF5, 0xD6, 0x39, 0x9D, 0x73, 0xB3, 0x85, 0x5C, 0xEB, 0x17, 0x77, 0x91, 0xE3, 0x39, 0x09, 0x3D, 0x62, 0xE6, 0x7D, 0x2C, 0x5B, 0x2E, 0x16, 0xAC, 0x2D, 0xCC, 0x0C, 0x54, 0x7D, 0x78, 0x19, 0xF1, 0xC0, 0xCF, 0x3F, 0xE7, 0x34, 0x61, 0x44, 0xA8, 0x9E, 0x87, 0x5B, 0xA1, 0xCB, 0xC0, 0x75, 0x28, 0xFF, 0x75, 0xE5, 0x7C, 0x7E, 0x06, 0xDB, 0xE9, 0x96, 0x58, 0xB6, 0xAF, 0x15, 0xD9, 0x17, 0x37, 0x16, 0xBE, 0xD3, 0xFD, 0xEF, 0x7C, 0xEA, 0x4D, 0x33, 0x0C, 0x31, 0xF6, 0x73, 0x37, 0x32, 0x53, 0xC5, 0x5A, 0x75, 0xA1, 0x14, 0xBC, 0xD0, 0x7F, 0x0C, 0xF5, 0x23, 0xDA, 0x09, 0xDC, 0x23, 0xAD, 0xCF, 0x8F, 0x82, 0x8A, 0xEB, 0xE8, 0x20, 0x79, 0x39, 0x41, 0x5D, 0x0B, 0x0D, 0xCE, 0xDF, 0xFF, 0x1A, 0x04, 0xA4, 0xC2, 0x3B, 0xD5, 0x62, 0x13, 0x29, 0x20, 0xD6, 0xD3, 0xEA, 0x9F, 0x63, 0x3D, 0xBF, 0x48, 0x5C, 0x24, 0x6C, 0x0D, 0xC7, 0x6C, 0xF4, 0x09, 0x80, 0xE3, 0x51, 0xA8, 0x8B, 0x19, 0xE9, 0x38, 0x5D, 0x98, 0x7A, 0xD9, 0xC5, 0x84, 0xC4, 0x25, 0xD3, 0x5D, 0xDB, 0x4D, 0xE7, 0x95, 0x6B, 0x8B, 0x12, 0xEF, 0x2B, 0xC1, 0x1A, 0x5C, 0xDA, 0x22, 0xA7, 0xD3, 0x38, 0xD8, 0x10, 0x7C, 0x63, 0x79, 0x16, 0xCD, 0x9F, 0x8F, 0xB4, 0x04, 0xEB, 0x18, 0xB1, 0xB6, 0xCA, 0x08, 0xB5, 0xE9, 0xD3, 0x9C, 0xD4, 0x1F, 0xA8, 0xF0, 0xE1, 0x66, 0xE8, 0x12, 0xD2, 0x34, 0x9F, 0x6A, 0x15, 0x65, 0x4A, 0xB7, 0x13, 0xC3, 0xEB, 0x19, 0x05, 0x6E, 0x02, 0xF9, 0x5B, 0x71, 0xB9, 0x18, 0xC6, 0x10, 0x9A, 0x39, 0x79, 0xC4, 0x66, 0x29, 0x0B, 0x0B, 0xCD, 0x4E, 0xD5, 0x79, 0xC5, 0x08, 0x4F, 0x70, 0x5E, 0xF1, 0xA0, 0x21, 0x07, 0x59, 0x96, 0x89, 0xBE, 0xB4, 0xB3, 0xE0, 0x63, 0x0E, 0xC5, 0xCD, 0x7F, 0x3C, 0xE5, 0x8D, 0xF5, 0xEA, 0x60, 0x12, 0xE0, 0x9E, 0x30, 0xB9, 0xDF, 0xF6, 0x5D, 0x0C, 0xD5, 0x5B, 0xCA, 0x59, 0xBE, 0xDB, 0xB2, 0xA4, 0x53, 0x68, 0x3D, 0x71, 0xA1, 0xD6, 0x99, 0x92, 0x76, 0x1D, 0xA4, 0xF6, 0xC2, 0xB3, 0x76, 0xA8, 0x7D, 0x7E, 0x78, 0x03, 0xF7, 0xC2, 0xA9, 0x92, 0x7E, 0x4A, 0x56, 0x0B, 0xE5, 0xF8, 0x0A, 0xCA, 0x92, 0xF8, 0x28, 0xC9, 0x9A, 0x63, 0xD8, 0x2A, 0x3A, 0xAA, 0xCC, 0xC6, 0xD9, 0xBC, 0x7B, 0xC8, 0xC5, 0xF6, 0x70, 0x6C, 0x05, 0x48, 0xF5, 0x11, 0x0A, 0xDF, 0x48, 0x64, 0xEC, 0x62, 0x01, 0xE7, 0xB2, 0x2A, 0x6C, 0x13, 0xB6, 0x7F, 0x12, 0xB7, 0xA0, 0x59, 0x8C, 0x98, 0xD6, 0xC2, 0x7E, 0x60, 0xD4, 0x81, 0x0F, 0xD5, 0x16, 0x79, 0x95, 0xE6, 0x6E, 0x30, 0x77, 0x3B, 0xF7, 0xCB, 0x03, 0xF3, 0x53, 0x9E, 0xB8, 0xE7, 0x2B, 0x83, 0x84, 0x53, 0x4D, 0xEB, 0x7D, 0xB7, 0x2B, 0x84, 0x7D, 0xD5, 0xC6, 0x6D, 0x02, 0xFB, 0x4E, 0x95, 0x05, 0xB0, 0x08, 0x41, 0x9C, 0x72, 0x23, 0x02, 0xA1, 0x55, 0x95, 0x7B, 0x79, 0x6B, 0xE8, 0x77, 0xCF, 0xDB, 0x17, 0xCB, 0x68, 0xEC, 0xFC, 0x59, 0x0C, 0x6F, 0x12, 0x58, 0x34, 0x68, 0xCB, 0x45, 0x4C, 0x67, 0xBE, 0x3F, 0x2E, 0x86, 0x1A, 0x38, 0x9E, 0x6F, 0x20, 0x65, 0xDD, 0x2E, 0x4F, 0xBC, 0x1D, 0x4C, 0xDD, 0xC3, 0xAD, 0x1C, 0x9A, 0x31, 0x16, 0xEF, 0x31, 0xF6, 0x0E, 0xD8, 0x55, 0x77, 0xAA, 0x2E, 0xE2, 0xEF, 0xF7, 0x21, 0x7D, 0xC0, 0xA1, 0x73, 0x4E, 0x01, 0x43, 0xCC, 0xDB, 0x34, 0x64, 0x23, 0x4E, 0xDE, 0xFE, 0xFA, 0x8D, 0x05, 0x61, 0xD1, 0xB2, 0xEC, 0x9A, 0xA9, 0xE7, 0x8E, 0xC8, 0x2F, 0xB0, 0x59, 0xB3, 0xEE, 0xD3, 0x29, 0xD4, 0x00, 0x26, 0xAB, 0x73, 0x95, 0xC4, 0x2C, 0xA5, 0x98, 0xD3, 0x7E, 0x69, 0x72, 0x9C, 0x37, 0x3A, 0x07, 0xFE, 0x48, 0xA1, 0x91, 0xB9, 0x1F, 0xF3, 0xC9, 0x62, 0xE2, 0x9D, 0x0C, 0x9C, 0x40, 0x53, 0x6B, 0xA7, 0xB6, 0x52, 0x20, 0x12, 0xA2, 0xEE, 0x48, 0x95, 0x64, 0x0F, 0x07, 0x42, 0xA6, 0xF2, 0x02, 0x89, 0xAB, 0x8E, 0x6C, 0x60, 0x4C, 0x1C, 0x56, 0x9B, 0xBE, 0x1F, 0x6B, 0xC3, 0x44, 0x9F, 0x44, 0xFD, 0x1C, 0xA2, 0x51, 0xD2, 0xFF, 0x2C, 0xA4, 0x69, 0x23, 0x0F, 0x79, 0x12, 0x97, 0x75, 0xBF, 0xC7, 0x2D, 0xBA, 0x91, 0x2F, 0xB7, 0xE9, 0x6A, 0x7F, 0x87, 0x5C, 0x90, 0xC6, 0x5C, 0xA6, 0xB9, 0x9D, 0x17, 0x28, 0xB7, 0x92, 0xE2, 0x71, 0x95, 0x16, 0x26, 0x5D, 0xCF, 0x90, 0x63, 0xCD, 0x70, 0x99, 0xC7, 0x29, 0xF0, 0x42, 0x5A, 0xE7, 0x47, 0xF7, 0xE0, 0x26, 0xBF, 0x41, 0xFF, 0xCB, 0x32, 0xEC, 0x89, 0xEF, 0xAD, 0x91, 0x44, 0x88, 0x00, 0x38, 0xC5, 0x72, 0x0E, 0x54, 0xFE, 0xBD, 0x97, 0x33, 0x37, 0xC0, 0x5D, 0x55, 0x7B, 0x74, 0x11, 0x2B, 0xF2, 0x31, 0x87, 0xCE, 0x41, 0xDE, 0x9C, 0xED, 0x15, 0x6F, 0x08, 0x43, 0x93, 0x81, 0x3A, 0xFB, 0x43, 0x3C, 0x29, 0x2E, 0xFB, 0x37, 0xF1, 0x37, 0xE6, 0x00, 0x6A, 0x95, 0xAD, 0xCD, 0x58, 0x0E, 0x36, 0x72, 0x18, 0x1B, 0xE8, 0xD3, 0x09, 0x13, 0xCA, 0x87, 0xE0, 0x08, 0x06, 0xBF, 0x82, 0xA7, 0x50, 0x9F, 0xD2, 0x57, 0xA7, 0x75, 0x91, 0xF6, 0x7A, 0x78, 0x0F, 0x26, 0x49, 0x9C, 0xC0, 0xE9, 0x3C, 0xB0, 0x42, 0x60, 0x00, 0x1D, 0xA3, 0x43, 0xC7, 0x89, 0x75, 0x2C, 0xC1, 0xA4, 0x38, 0x39, 0x8F, 0xE0, 0x48, 0xF1, 0x9B, 0x0D, 0x83, 0xD1, 0xAF, 0x95, 0x60, 0xB9, 0x09, 0xCF, 0xFE, 0x13, 0x64, 0x15, 0x6F, 0x4B, 0x45, 0x62, 0xD1, 0x57, 0x5E, 0x32, 0xC7, 0x7F, 0x8F, 0x0A, 0x26, 0x7B, 0xE4, 0x3E, 0x83, 0x72, 0xEB, 0x4A, 0x59, 0x69, 0x5A, 0x62, 0x5B, 0x84, 0xC2, 0x79, 0x5C, 0x72, 0x4A, 0xC2, 0x40, 0xFC, 0x81, 0xCC, 0x1F, 0x03, 0xE0, 0x10, 0x04, 0xF9, 0x82, 0x20, 0xF3, 0xB4, 0x9E, 0x1B, 0x89, 0x6B, 0x42, 0x20, 0x49, 0xD1, 0x5C, 0x4E, 0x54, 0x80, 0xD2, 0xE6, 0xDA, 0xE9, 0xA7, 0xAD, 0x5E, 0x5B, 0xB4, 0xF3, 0x06, 0xEA, 0xFB, 0x6A, 0xA5, 0x16, 0x6D, 0xFB, 0x5A, 0xCF, 0x5E, 0x7F, 0xF0, 0x57, 0x3E, 0x35, 0x42, 0xCF, 0xEA, 0xFE, 0x1E, 0xDB, 0x4F, 0x1E, 0x40, 0x5D, 0xD3, 0x16, 0x7A, 0x92, 0x8E, 0x30, 0xDC, 0xC6, 0x0E, 0xF8, 0x62, 0xB5, 0xA0, 0xDB, 0xCF, 0x00, 0x27, 0x8B, 0x03, 0x23, 0xEC, 0x6C, 0xBA, 0xE1, 0x4C, 0x8D, 0x79, 0x9B, 0xCC, 0x31, 0x10, 0x89, 0x30, 0x12, 0xEA, 0x81, 0x7E, 0xA0, 0x6F, 0x85, 0x32, 0x87, 0x48, 0xDF, 0x00, 0x9B, 0x7D, 0xD3, 0x6C, 0x46, 0x65, 0x52, 0xC6, 0x3F, 0x55, 0x0A, 0xF2, 0xD2, 0x36, 0x7A, 0x3C, 0x17, 0xF7, 0x86, 0x6F, 0xA2, 0x2F, 0x1C, 0x8F, 0x16, 0xD2, 0xCB, 0x9F, 0x9A, 0xD7, 0x9F, 0xAE, 0xD0, 0x1E, 0x61, 0xEB, 0x31, 0xB0, 0x0A, 0xFD, 0x17, 0xA9, 0x84, 0x43, 0x5B, 0x1C, 0xA2, 0x7A, 0xE4, 0xBB, 0xC3, 0x42, 0x48, 0x2F, 0x24, 0x72, 0x45, 0x11, 0x18, 0xB2, 0x89, 0x7E, 0x6C, 0xF7, 0x50, 0xFC, 0x1F, 0x53, 0xAC, 0x80, 0x81, 0xA6, 0x98, 0x66, 0x28, 0x4E, 0xEF, 0x08, 0x72, 0xAC, 0x3E, 0xB3, 0x42, 0x7A, 0x51, 0x55, 0xA1, 0x66, 0x06, 0xBC, 0x5D, 0x6D, 0x05, 0x06, 0xDC, 0x48, 0xF1, 0xEB, 0x3E, 0x85, 0xF7, 0x1F, 0xCA, 0x62, 0xD5, 0xD9, 0xD3, 0xAB, 0xE3, 0xBB, 0x3E, 0x9B, 0x03, 0xC4, 0xEE, 0xF7, 0xB2, 0x69, 0xB5, 0xA8, 0x5E, 0xD3, 0xCB, 0x14, 0xCD, 0xED, 0x13, 0xC1, 0xAB, 0x92, 0x69, 0x41, 0x52, 0x2A, 0x5B, 0xED, 0x34, 0xB2, 0xBC, 0x33, 0xC1, 0x17, 0x33, 0x14, 0x22, 0x23, 0xC4, 0x5D, 0x50, 0x55, 0x46, 0x27, 0x84, 0x00, 0xEA, 0x96, 0x96, 0xA4, 0xF4, 0x19, 0xCC, 0x80, 0xB1, 0x3F, 0xFC, 0x3D, 0xF5, 0xE0, 0xE6, 0x35, 0x41, 0x29, 0x3B, 0x51, 0xCE, 0x00, 0x6A, 0xD0, 0xA5, 0x1C, 0xE9, 0x56, 0xFA, 0x3C, 0xF9, 0x05, 0xFF, 0x13, 0x19, 0x93, 0x76, 0x78, 0x18, 0x27, 0x8F, 0x21, 0x23, 0xF0, 0x9F, 0x42, 0x21, 0x21, 0x21, 0x46, 0xFD, 0x06, 0xB7, 0x1D, 0xC1, 0x3D, 0xC2, 0x64, 0xCC, 0xC9, 0xE3, 0xDD, 0x94, 0x6E, 0xBE, 0xB9, 0xB4, 0x06, 0x56, 0x83, 0x81, 0x87, 0x33, 0xA9, 0x77, 0x54, 0xCC, 0x85, 0xBC, 0x86, 0x9B, 0x69, 0x7B, 0x1B, 0x99, 0x01, 0x1C, 0x32, 0xEB, 0x6E, 0xC4, 0xFF, 0x8A, 0xE3, 0xF6, 0xFC, 0x4E, 0xEA, 0xED, 0x42, 0x84, 0x09, 0xC5, 0xB0, 0x34, 0x25, 0x7A, 0x0B, 0x96, 0xF0, 0x05, 0x73, 0x7D, 0x47, 0x56, 0xE7, 0x7C, 0xA5, 0x44, 0xB9, 0x0E, 0x84, 0x1F, 0x8B, 0x47, 0xEE, 0x82, 0x04, 0xEA, 0x85, 0xE3, 0xCB, 0xA9, 0x14, 0xA0, 0x39, 0xCC, 0xD9, 0xCC, 0xD0, 0x60, 0x4F, 0x13, 0x78, 0x95, 0xB0, 0x35, 0x29, 0x17, 0xDA, 0x69, 0x90, 0xB0, 0x1A, 0x87, 0xAB, 0x5B, 0xBE, 0xBD, 0x41, 0x20, 0x7C, 0x8E, 0x9A, 0x43, 0xCA, 0x10, 0x27, 0x9D, 0x7C, 0xA7, 0x09, 0xD6, 0x4D, 0x36, 0xCF, 0xA2, 0x2E, 0xD5, 0x01, 0x34, 0xDE, 0x4B, 0xA3, 0x83, 0x49, 0x11, 0x64, 0x92, 0xD7, 0x4B, 0x23, 0x92, 0x08, 0xDF, 0xD1, 0x94, 0x84, 0xEA, 0xBC, 0xFE, 0x39, 0x9C, 0x98, 0x5C, 0xD0, 0xCB, 0xCF, 0xE4, 0x50, 0x25, 0xD3, 0x55, 0x8E, 0xC9, 0xD3, 0x80, 0xAA, 0x29, 0xB1, 0xBE, 0x2E, 0x65, 0x46, 0x20, 0x93, 0xB7, 0x3A, 0xF6, 0x45, 0x77, 0x7A, 0x19, 0x2C, 0x0B, 0x47, 0x12, 0x06, 0xC1, 0x4F, 0xE2, 0xE4, 0xDC, 0xD6, 0x11, 0x5B, 0x4C, 0x97, 0xEC, 0xB1, 0x28, 0x86, 0x4D, 0x2B, 0xA0, 0x31, 0xF1, 0x2B, 0x44, 0xF3, 0x86, 0x1B, 0x4D, 0xA5, 0x71, 0x4E, 0x78, 0xB4, 0xF7, 0xCC, 0x31, 0xB5, 0xC8, 0xB5, 0x04, 0xD1, 0x91, 0x5E, 0x5D, 0xB8, 0x96, 0x60, 0xF4, 0xCD, 0x7A, 0x54, 0x57, 0x68, 0x36, 0x74, 0xBE, 0xB3, 0x1C, 0x09, 0x67, 0x9F, 0x30, 0xAE, 0xD2, 0x29, 0xCF, 0xE5, 0xEA, 0xC8, 0xF2, 0xF6, 0x18, 0x41, 0x6B, 0x00, 0x9B, 0x17, 0xED, 0x3E, 0x95, 0x36, 0x9E, 0xD1, 0xFB, 0xC8, 0x4F, 0xD8, 0x11, 0xB9, 0x3B, 0xE7, 0x65, 0xC4, 0x3A, 0xD7, 0xE1, 0x31, 0x3F, 0x7C, 0x23, 0x36, 0x4C, 0xC5, 0xA5, 0xCE, 0xD5, 0x25, 0x9A, 0x16, 0xD6, 0x99, 0xB7, 0xDC, 0x93, 0x8A, 0xF8, 0xAB, 0xF2, 0xB7, 0xF7, 0x22, 0x67, 0x76, 0xCD, 0xF8, 0x77, 0xD5, 0xA8, 0x3B, 0x22, 0x24, 0xCE, 0xDD, 0x49, 0x4A, 0x40, 0x79, 0x15, 0x74, 0x7F, 0x9A, 0x26, 0x80, 0x41, 0xB7, 0x43, 0x9F, 0x1C, 0x49, 0xB8, 0x80, 0x51, 0xB1, 0x2D, 0x1F, 0x03, 0x9D, 0xBF, 0xA7, 0xBD, 0x0D, 0x4B, 0x83, 0xA6, 0x66, 0xA5, 0xD9, 0xA3, 0x41, 0x86, 0x61, 0x36, 0xA6, 0xF6, 0xFE, 0xCF, 0xDD, 0xFA, 0x37, 0x94, 0xC5, 0x2B, 0xE1, 0x38, 0xC6, 0xAB, 0x66, 0x27, 0x0E, 0x37, 0xF0, 0x49, 0x0F, 0x39, 0x7C, 0x80, 0x61, 0xBD, 0x05, 0xBC, 0x57, 0x55, 0x69, 0x78, 0xC0, 0x3E, 0x9A, 0x34, 0x60, 0xB4, 0xBC, 0x82, 0x4D, 0x3D, 0xB7, 0xF5, 0x1E, 0x37, 0x08, 0xF5, 0x06, 0x2B, 0x42, 0xF1, 0x61, 0x7A, 0x33, 0x39, 0xD7, 0x7B, 0x03, 0x3A, 0xB6, 0x3A, 0xD0, 0x0E, 0xC0, 0xC7, 0xD1, 0xF0, 0x76, 0x50, 0xBD, 0x1E, 0x26, 0xB4, 0xDB, 0x37, 0x5E, 0xEB, 0x35, 0xAF, 0x5D, 0xC2, 0x26, 0xA7, 0x42, 0x4C, 0xF1, 0x19, 0x15, 0x32, 0x4A, 0x96, 0x29, 0x5B, 0xA9, 0xCE, 0x3E, 0x94, 0xCA, 0x41, 0x16, 0x9D, 0x7F, 0x93, 0xE6, 0x50, 0xE1, 0x00, 0xE8, 0x63, 0xD2, 0x59, 0x2B, 0xDB, 0x0D, 0xC0, 0x3C, 0x3B, 0x12, 0x50, 0x69, 0xFB, 0x24, 0x80, 0x9A, 0x27, 0x9A, 0xC6, 0xCE, 0x58, 0x1A, 0x7C, 0x8C, 0x94, 0xB6, 0x2B, 0x2E, 0x5F, 0x9A, 0x92, 0x00, 0x33, 0x4E, 0x07, 0x92, 0x4A, 0xE3, 0x8D, 0xF3, 0xF4, 0x0D, 0xB3, 0x91, 0x0C, 0x35, 0xE6, 0xD5, 0xE7, 0xE9, 0x54, 0xC4, 0x4A, 0xC8, 0xE3, 0xBE, 0x20, 0xDB, 0x46, 0x99, 0x05, 0x74, 0x13, 0x02, 0x43, 0x1F, 0xB9, 0x75, 0xED, 0x1E, 0xDB, 0x26, 0x15, 0x26, 0x33, 0x28, 0xFF, 0x51, 0xBA, 0xAC, 0x89, 0xFD, 0xAC, 0xAD, 0xAB, 0x5E, 0x79, 0xE5, 0xDE, 0x54, 0xCA, 0x24, 0xC1, 0xE3, 0x94, 0x32, 0x5A, 0xD8, 0x02, 0x34, 0x67, 0xB2, 0x3A, 0x8F, 0xF7, 0xEC, 0x22, 0x7E, 0x88, 0x32, 0x7B, 0x97, 0x40, 0x8F, 0x8A, 0xD2, 0x3A, 0xFE, 0xA5, 0xF9, 0xA8, 0x1E, 0x39, 0x9B, 0x92, 0x79, 0xC2, 0xDE, 0x78, 0x77, 0x37, 0xAD, 0xF3, 0x83, 0xB4, 0x83, 0x58, 0x56, 0x8B, 0xA0, 0x4B, 0x41, 0x24, 0x89, 0xBF, 0x78, 0xD6, 0x35, 0xC0, 0xA5, 0xDA, 0x0F, 0xED, 0xCD, 0xC0, 0xB7, 0xAF, 0xCB, 0x88, 0xF3, 0xB8, 0x35, 0x89, 0x4B, 0xD0, 0x38, 0x57, 0x32, 0x51, 0x37, 0xA4, 0x26, 0x4D, 0xBD, 0x40, 0x12, 0x92, 0x6F, 0x9E, 0x8C, 0x3E, 0xC6, 0x21, 0x66, 0x99, 0x57, 0x41, 0x3E, 0xC5, 0x11, 0xCD, 0xCB, 0xB4, 0xA3, 0x1F, 0x3F, 0x60, 0x7D, 0x28, 0x9E, 0xEB, 0xEC, 0xCD, 0x86, 0xE9, 0x92, 0x30, 0x31, 0x66, 0xE6, 0x0B, 0x8A, 0x12, 0x6C, 0xEF, 0x13, 0x90, 0x2D, 0x4A, 0xB1, 0x77, 0xFA, 0x23, 0xB0, 0xEC, 0x0D, 0x72, 0x6C, 0x59, 0x57, 0x67, 0x04, 0x58, 0xE3, 0x22, 0x53, 0x9B, 0xF0, 0xFC, 0x19, 0x3E, 0xE5, 0x24, 0xDA, 0xBC, 0xEA, 0x6C, 0x74, 0x33, 0xFE, 0xDD, 0x56, 0x37, 0x87, 0x23, 0x76, 0xD9, 0xE4, 0x91, 0x8F, 0xF5, 0x51, 0xA6, 0xE0, 0xF4, 0x0C, 0x1A, 0xB7, 0x54, 0xDF, 0x60, 0x6D, 0xE6, 0x45, 0xE3, 0xE7, 0x82, 0x0C, 0x85, 0x3F, 0xEE, 0xC0, 0x6A, 0x7D, 0x45, 0xCF, 0x87, 0x9F, 0x79, 0x07, 0x2C, 0x30, 0x59, 0x51, 0x52, 0xF2, 0x9E, 0xE3, 0xB3, 0xBA, 0x04, 0xAE, 0x33, 0xA2, 0x87, 0x29, 0x80, 0xFC, 0x6D, 0xD7, 0xC2, 0x31, 0xC7, 0xFA, 0x34, 0x7C, 0xBD, 0x68, 0xD9, 0xB2, 0xEE, 0xF5, 0x78, 0x6E, 0x48, 0xF7, 0x8A, 0x8A, 0x28, 0x02, 0x50, 0x60, 0x90, 0x28, 0x49, 0xCA, 0xC6, 0x70, 0x25, 0x83, 0xB1, 0x1D, 0x37, 0x67, 0x78, 0x68, 0x08, 0x1E, 0x06, 0xFC, 0x6A, 0x7E, 0xDF, 0xBE, 0x6B, 0x9C, 0xBB, 0xD2, 0xC7, 0x37, 0x0B, 0x29, 0x61, 0x70, 0x4B, 0x05, 0xF3, 0x57, 0xFB, 0x46, 0x33, 0xA9, 0xEF, 0x6B, 0x2E, 0xFE, 0xB2, 0xD8, 0xFF, 0xA3, 0x1C, 0xC9, 0x0F, 0xC4, 0x51, 0x5A, 0x95, 0x3F, 0x8F, 0x7F, 0x68, 0x81, 0x93, 0x18, 0x71, 0x2E, 0x06, 0x44, 0x09, 0x3A, 0x0A, 0x18, 0xE4, 0x31, 0xE4, 0x64, 0x28, 0x76, 0x31, 0x6C, 0xFC, 0x12, 0x7D, 0x67, 0x4B, 0x67, 0x6F, 0x29, 0xC9, 0x0C, 0x9D, 0x25, 0x14, 0x21, 0x49, 0x54, 0x17, 0xC0, 0xC1, 0xF0, 0x96, 0xBC, 0x1C, 0xC8, 0xD6, 0xBF, 0xF1, 0x7F, 0x95, 0x3B, 0xF2, 0x48, 0x5D, 0x19, 0x50, 0xA0, 0x9D, 0x3C, 0x3A, 0x92, 0x88, 0xE6, 0xCE, 0xE2, 0x30, 0xCF, 0x41, 0xC3, 0x4B, 0x1F, 0x3B, 0xB8, 0x33, 0x0A, 0x96, 0x07, 0xCB, 0x62, 0xA9, 0x51, 0x0F, 0xC2, 0x5A, 0x0E, 0x5F, 0x67, 0x0B, 0x48, 0x69, 0x3C, 0x06, 0xF8, 0xA0, 0x2C, 0x29, 0x7D, 0xBB, 0xAF, 0xE5, 0x67, 0x61, 0x86, 0x08, 0x29, 0xE4, 0xB5, 0x5D, 0xF0, 0xC7, 0xE0, 0x06, 0x91, 0xB5, 0xE0, 0x88, 0xCE, 0xC8, 0x06, 0x78, 0x0B, 0xB3, 0xAB, 0x6C, 0x2C, 0x06, 0x8C, 0x4E, 0xD8, 0xFC, 0x47, 0xFE, 0x39, 0x76, 0xD1, 0x65, 0x1E, 0x63, 0x0E, 0xCE, 0x0F, 0xA7, 0x7B, 0x5F, 0x05, 0xA6, 0xFE, 0x70, 0x20, 0x9D, 0x31, 0x86, 0x0C, 0xEB, 0x98, 0xFA, 0x49, 0xB7, 0xEC, 0x55, 0x25, 0x1A, 0xEB, 0x7C, 0x7C, 0x90, 0x16, 0xD1, 0x80, 0x40, 0x5A, 0x1E, 0x5A, 0x24, 0x69, 0x15, 0x51, 0xCF, 0xE6, 0xFD, 0x8E, 0x8F, 0x36, 0x17, 0x90, 0x2B, 0xE0, 0xF6, 0x33, 0x53, 0xE7, 0x3F, 0x05, 0x46, 0x01, 0xF0, 0xCD, 0x2B, 0x1C, 0xE8, 0xBF, 0xB2, 0x0B, 0x7C, 0x64, 0x9D, 0x31, 0xCE, 0x52, 0xC1, 0xB7, 0xEF, 0xDD, 0xE9, 0xD9, 0xD8, 0x6B, 0x39, 0x52, 0x18, 0x6C, 0xAF, 0x0C, 0x3C, 0xCE, 0x1F, 0xDD, 0x13, 0x04, 0x26, 0xE4, 0x2E, 0x02, 0x09, 0x0F, 0x5B, 0x5D, 0x5E, 0x74, 0x75, 0x7B, 0x82, 0xA7, 0xB4, 0xC2, 0xCF, 0xDB, 0xE4, 0x10, 0x40, 0x43, 0x4E, 0x62, 0x66, 0x67, 0x69, 0x8B, 0x98, 0x9B, 0xA4, 0xB2, 0xD2, 0xE0, 0xE9, 0xF7, 0x09, 0x21, 0x2A, 0x3B, 0x46, 0x52, 0x58, 0x71, 0x8E, 0xC0, 0xD7, 0xE1, 0xE6, 0xED, 0xF5, 0x10, 0x28, 0x32, 0x39, 0x4F, 0x56, 0x57, 0x78, 0x80, 0x8F, 0x9B, 0xAE, 0xB2, 0xDE, 0xEF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x20, 0x2F, 0x3E, }, }, { .name = "Dilithium Round 3, Level 3 (6-5) KAT 0 (PKCS#8/SPKI)", .version = 0, .keyform = 0, .rho_len = 0, .seed_len = 0, .tr_len = 0, .s1_len = 0, .s2_len = 0, .t0_len = 0, .t1_len = 0, .pkcs8_len = 5988, .pkcs8 = { 0x30, 0x82, 0x17, 0x60, 0x02, 0x01, 0x00, 0x30, 0x0F, 0x06, 0x0B, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x02, 0x82, 0x0B, 0x07, 0x06, 0x05, 0x05, 0x00, 0x04, 0x82, 0x17, 0x48, 0x30, 0x82, 0x17, 0x44, 0x02, 0x01, 0x00, 0x03, 0x21, 0x00, 0x1C, 0x0E, 0xE1, 0x11, 0x1B, 0x08, 0x00, 0x3F, 0x28, 0xE6, 0x5E, 0x8B, 0x3B, 0xDE, 0xB0, 0x37, 0xCF, 0x8F, 0x22, 0x1D, 0xFC, 0xDA, 0xF5, 0x95, 0x0E, 0xDB, 0x38, 0xD5, 0x06, 0xD8, 0x5B, 0xEF, 0x03, 0x21, 0x00, 0x39, 0x4D, 0x16, 0x95, 0x05, 0x9D, 0xFF, 0x40, 0xAE, 0x25, 0x6C, 0x5D, 0x5E, 0xDA, 0xBF, 0xB6, 0x9F, 0x5F, 0x40, 0xF3, 0x7A, 0x58, 0x8F, 0x50, 0x53, 0x2C, 0xA4, 0x08, 0xA8, 0x16, 0x8A, 0xB1, 0x03, 0x21, 0x00, 0xE6, 0x4F, 0x14, 0x64, 0x27, 0x54, 0x3D, 0x8C, 0x36, 0xB3, 0xB6, 0x52, 0x26, 0x76, 0x9A, 0x22, 0x91, 0x1A, 0x5A, 0x31, 0x3E, 0xAC, 0x17, 0xC4, 0xAB, 0xA2, 0x52, 0x84, 0x51, 0x4F, 0xC6, 0x13, 0x03, 0x82, 0x02, 0x81, 0x00, 0x35, 0x78, 0x08, 0x33, 0x02, 0x23, 0x16, 0x43, 0x37, 0x65, 0x80, 0x75, 0x78, 0x71, 0x45, 0x24, 0x81, 0x01, 0x73, 0x15, 0x44, 0x83, 0x65, 0x26, 0x41, 0x33, 0x30, 0x22, 0x30, 0x26, 0x14, 0x73, 0x70, 0x52, 0x21, 0x07, 0x81, 0x26, 0x50, 0x61, 0x85, 0x85, 0x07, 0x75, 0x46, 0x18, 0x58, 0x05, 0x48, 0x53, 0x30, 0x18, 0x70, 0x66, 0x47, 0x51, 0x82, 0x67, 0x73, 0x77, 0x33, 0x50, 0x02, 0x70, 0x31, 0x28, 0x78, 0x82, 0x15, 0x80, 0x71, 0x40, 0x26, 0x73, 0x43, 0x20, 0x61, 0x62, 0x50, 0x61, 0x73, 0x71, 0x01, 0x03, 0x11, 0x45, 0x36, 0x81, 0x52, 0x30, 0x24, 0x65, 0x03, 0x48, 0x14, 0x37, 0x08, 0x37, 0x18, 0x25, 0x50, 0x84, 0x06, 0x08, 0x60, 0x17, 0x62, 0x58, 0x31, 0x31, 0x28, 0x27, 0x00, 0x17, 0x18, 0x48, 0x16, 0x67, 0x31, 0x78, 0x61, 0x07, 0x37, 0x23, 0x55, 0x74, 0x47, 0x15, 0x10, 0x10, 0x11, 0x21, 0x10, 0x66, 0x27, 0x42, 0x12, 0x08, 0x35, 0x46, 0x22, 0x85, 0x13, 0x13, 0x88, 0x16, 0x48, 0x86, 0x83, 0x35, 0x10, 0x47, 0x60, 0x26, 0x11, 0x83, 0x15, 0x74, 0x25, 0x00, 0x74, 0x24, 0x40, 0x64, 0x25, 0x15, 0x86, 0x13, 0x65, 0x61, 0x37, 0x77, 0x11, 0x84, 0x78, 0x05, 0x08, 0x62, 0x43, 0x70, 0x64, 0x06, 0x85, 0x27, 0x63, 0x11, 0x50, 0x13, 0x56, 0x23, 0x21, 0x68, 0x41, 0x41, 0x77, 0x24, 0x08, 0x48, 0x30, 0x87, 0x85, 0x75, 0x43, 0x85, 0x08, 0x63, 0x68, 0x54, 0x26, 0x84, 0x50, 0x56, 0x84, 0x37, 0x02, 0x40, 0x07, 0x16, 0x17, 0x84, 0x54, 0x38, 0x00, 0x61, 0x27, 0x05, 0x82, 0x62, 0x06, 0x76, 0x52, 0x11, 0x12, 0x14, 0x83, 0x88, 0x06, 0x78, 0x14, 0x75, 0x55, 0x02, 0x12, 0x22, 0x85, 0x52, 0x31, 0x08, 0x45, 0x03, 0x70, 0x13, 0x64, 0x31, 0x80, 0x05, 0x37, 0x68, 0x37, 0x65, 0x02, 0x46, 0x53, 0x15, 0x07, 0x60, 0x06, 0x25, 0x33, 0x12, 0x51, 0x20, 0x05, 0x41, 0x60, 0x63, 0x24, 0x23, 0x52, 0x41, 0x50, 0x77, 0x31, 0x45, 0x70, 0x33, 0x47, 0x65, 0x64, 0x31, 0x23, 0x18, 0x03, 0x33, 0x65, 0x16, 0x75, 0x87, 0x14, 0x13, 0x04, 0x11, 0x17, 0x15, 0x54, 0x68, 0x12, 0x60, 0x53, 0x73, 0x42, 0x38, 0x82, 0x43, 0x27, 0x83, 0x37, 0x12, 0x22, 0x81, 0x74, 0x81, 0x81, 0x20, 0x13, 0x63, 0x27, 0x64, 0x75, 0x10, 0x28, 0x03, 0x22, 0x68, 0x65, 0x08, 0x76, 0x55, 0x35, 0x63, 0x33, 0x81, 0x04, 0x47, 0x48, 0x58, 0x54, 0x30, 0x12, 0x43, 0x18, 0x08, 0x38, 0x64, 0x38, 0x53, 0x83, 0x08, 0x41, 0x27, 0x04, 0x64, 0x64, 0x63, 0x34, 0x64, 0x61, 0x06, 0x80, 0x70, 0x60, 0x23, 0x75, 0x51, 0x68, 0x25, 0x74, 0x11, 0x52, 0x88, 0x22, 0x01, 0x57, 0x78, 0x58, 0x33, 0x31, 0x34, 0x31, 0x55, 0x82, 0x84, 0x03, 0x16, 0x36, 0x01, 0x06, 0x48, 0x14, 0x80, 0x46, 0x43, 0x68, 0x46, 0x17, 0x57, 0x21, 0x36, 0x31, 0x65, 0x74, 0x65, 0x22, 0x15, 0x17, 0x71, 0x32, 0x05, 0x10, 0x66, 0x46, 0x83, 0x16, 0x46, 0x71, 0x47, 0x28, 0x31, 0x35, 0x55, 0x14, 0x73, 0x32, 0x81, 0x82, 0x60, 0x73, 0x15, 0x54, 0x36, 0x87, 0x08, 0x03, 0x28, 0x43, 0x26, 0x24, 0x16, 0x05, 0x32, 0x05, 0x20, 0x23, 0x67, 0x72, 0x58, 0x28, 0x18, 0x10, 0x85, 0x42, 0x67, 0x85, 0x15, 0x52, 0x80, 0x00, 0x72, 0x82, 0x27, 0x18, 0x31, 0x12, 0x08, 0x68, 0x37, 0x72, 0x44, 0x42, 0x05, 0x48, 0x64, 0x72, 0x05, 0x35, 0x08, 0x61, 0x73, 0x86, 0x27, 0x12, 0x46, 0x77, 0x51, 0x08, 0x52, 0x76, 0x33, 0x40, 0x37, 0x34, 0x32, 0x11, 0x54, 0x24, 0x06, 0x54, 0x02, 0x34, 0x50, 0x80, 0x04, 0x17, 0x72, 0x84, 0x62, 0x73, 0x61, 0x68, 0x68, 0x07, 0x81, 0x52, 0x46, 0x71, 0x06, 0x82, 0x55, 0x45, 0x81, 0x63, 0x62, 0x76, 0x41, 0x80, 0x57, 0x12, 0x44, 0x25, 0x57, 0x08, 0x04, 0x51, 0x06, 0x63, 0x61, 0x15, 0x85, 0x86, 0x30, 0x46, 0x52, 0x07, 0x05, 0x32, 0x75, 0x02, 0x18, 0x22, 0x42, 0x83, 0x71, 0x02, 0x38, 0x52, 0x75, 0x28, 0x44, 0x20, 0x33, 0x00, 0x17, 0x23, 0x11, 0x14, 0x02, 0x15, 0x76, 0x88, 0x38, 0x47, 0x62, 0x31, 0x85, 0x13, 0x52, 0x52, 0x10, 0x84, 0x38, 0x25, 0x55, 0x56, 0x74, 0x11, 0x44, 0x54, 0x67, 0x27, 0x85, 0x46, 0x58, 0x61, 0x70, 0x43, 0x07, 0x58, 0x80, 0x06, 0x84, 0x55, 0x13, 0x53, 0x47, 0x81, 0x38, 0x12, 0x08, 0x00, 0x84, 0x31, 0x56, 0x22, 0x14, 0x66, 0x03, 0x15, 0x60, 0x01, 0x63, 0x68, 0x56, 0x36, 0x73, 0x61, 0x80, 0x80, 0x04, 0x55, 0x54, 0x03, 0x82, 0x03, 0x01, 0x00, 0x33, 0x73, 0x12, 0x58, 0x40, 0x31, 0x14, 0x80, 0x42, 0x03, 0x67, 0x33, 0x01, 0x82, 0x71, 0x55, 0x60, 0x65, 0x60, 0x34, 0x40, 0x51, 0x44, 0x34, 0x55, 0x48, 0x51, 0x12, 0x23, 0x76, 0x45, 0x10, 0x64, 0x33, 0x73, 0x25, 0x38, 0x23, 0x38, 0x06, 0x24, 0x51, 0x61, 0x70, 0x81, 0x54, 0x11, 0x67, 0x17, 0x32, 0x00, 0x85, 0x32, 0x60, 0x40, 0x43, 0x71, 0x06, 0x80, 0x37, 0x37, 0x60, 0x70, 0x86, 0x40, 0x87, 0x00, 0x03, 0x52, 0x45, 0x71, 0x48, 0x26, 0x22, 0x03, 0x50, 0x53, 0x56, 0x66, 0x03, 0x72, 0x18, 0x01, 0x37, 0x10, 0x37, 0x10, 0x36, 0x52, 0x78, 0x43, 0x28, 0x24, 0x64, 0x23, 0x20, 0x47, 0x64, 0x23, 0x84, 0x00, 0x00, 0x67, 0x43, 0x64, 0x56, 0x52, 0x26, 0x21, 0x76, 0x65, 0x21, 0x24, 0x13, 0x88, 0x73, 0x47, 0x65, 0x08, 0x43, 0x12, 0x17, 0x01, 0x64, 0x71, 0x46, 0x54, 0x03, 0x87, 0x24, 0x41, 0x77, 0x74, 0x13, 0x76, 0x78, 0x55, 0x21, 0x64, 0x11, 0x17, 0x31, 0x60, 0x50, 0x48, 0x26, 0x04, 0x14, 0x84, 0x74, 0x66, 0x38, 0x03, 0x35, 0x15, 0x58, 0x01, 0x73, 0x51, 0x26, 0x21, 0x33, 0x62, 0x22, 0x27, 0x10, 0x63, 0x45, 0x60, 0x16, 0x57, 0x20, 0x77, 0x85, 0x48, 0x32, 0x72, 0x48, 0x31, 0x56, 0x16, 0x78, 0x34, 0x56, 0x40, 0x57, 0x68, 0x67, 0x34, 0x58, 0x35, 0x25, 0x35, 0x20, 0x81, 0x55, 0x65, 0x48, 0x10, 0x32, 0x05, 0x33, 0x40, 0x16, 0x60, 0x74, 0x23, 0x71, 0x50, 0x16, 0x32, 0x53, 0x34, 0x66, 0x72, 0x70, 0x81, 0x11, 0x18, 0x24, 0x37, 0x32, 0x13, 0x11, 0x54, 0x42, 0x40, 0x82, 0x61, 0x37, 0x75, 0x04, 0x67, 0x10, 0x08, 0x02, 0x61, 0x38, 0x68, 0x50, 0x71, 0x28, 0x37, 0x52, 0x66, 0x72, 0x24, 0x23, 0x08, 0x02, 0x10, 0x05, 0x01, 0x55, 0x20, 0x48, 0x37, 0x44, 0x37, 0x71, 0x16, 0x42, 0x01, 0x23, 0x16, 0x71, 0x07, 0x82, 0x38, 0x08, 0x07, 0x10, 0x11, 0x24, 0x68, 0x25, 0x82, 0x40, 0x18, 0x15, 0x85, 0x18, 0x74, 0x20, 0x85, 0x38, 0x25, 0x83, 0x10, 0x66, 0x75, 0x13, 0x12, 0x52, 0x85, 0x27, 0x65, 0x25, 0x60, 0x31, 0x47, 0x81, 0x62, 0x13, 0x81, 0x53, 0x47, 0x04, 0x22, 0x61, 0x05, 0x71, 0x55, 0x67, 0x44, 0x68, 0x20, 0x05, 0x45, 0x50, 0x51, 0x48, 0x41, 0x13, 0x03, 0x83, 0x02, 0x41, 0x47, 0x47, 0x15, 0x62, 0x72, 0x02, 0x16, 0x53, 0x21, 0x03, 0x03, 0x87, 0x36, 0x03, 0x48, 0x67, 0x51, 0x76, 0x65, 0x27, 0x21, 0x42, 0x17, 0x26, 0x25, 0x76, 0x65, 0x36, 0x12, 0x11, 0x12, 0x16, 0x87, 0x48, 0x45, 0x40, 0x33, 0x42, 0x68, 0x35, 0x44, 0x40, 0x68, 0x13, 0x60, 0x50, 0x31, 0x08, 0x17, 0x43, 0x56, 0x75, 0x06, 0x34, 0x61, 0x84, 0x75, 0x57, 0x58, 0x58, 0x65, 0x44, 0x84, 0x07, 0x62, 0x31, 0x86, 0x70, 0x34, 0x33, 0x67, 0x58, 0x66, 0x67, 0x73, 0x20, 0x75, 0x17, 0x10, 0x36, 0x05, 0x27, 0x37, 0x24, 0x12, 0x20, 0x17, 0x38, 0x87, 0x54, 0x40, 0x32, 0x26, 0x30, 0x62, 0x13, 0x54, 0x18, 0x36, 0x81, 0x55, 0x77, 0x32, 0x00, 0x10, 0x03, 0x65, 0x18, 0x57, 0x41, 0x86, 0x02, 0x14, 0x44, 0x33, 0x41, 0x02, 0x37, 0x55, 0x63, 0x58, 0x75, 0x02, 0x61, 0x88, 0x64, 0x18, 0x51, 0x76, 0x24, 0x15, 0x85, 0x07, 0x11, 0x80, 0x35, 0x41, 0x51, 0x57, 0x42, 0x42, 0x58, 0x54, 0x56, 0x35, 0x45, 0x15, 0x57, 0x07, 0x63, 0x86, 0x77, 0x24, 0x00, 0x17, 0x67, 0x83, 0x86, 0x86, 0x25, 0x88, 0x17, 0x75, 0x08, 0x61, 0x23, 0x60, 0x60, 0x65, 0x07, 0x33, 0x35, 0x06, 0x60, 0x52, 0x75, 0x02, 0x47, 0x24, 0x33, 0x64, 0x51, 0x35, 0x45, 0x52, 0x55, 0x41, 0x48, 0x60, 0x42, 0x16, 0x43, 0x15, 0x63, 0x33, 0x16, 0x55, 0x67, 0x60, 0x70, 0x34, 0x26, 0x77, 0x08, 0x07, 0x60, 0x55, 0x30, 0x63, 0x50, 0x13, 0x37, 0x70, 0x77, 0x01, 0x37, 0x45, 0x72, 0x74, 0x51, 0x28, 0x72, 0x83, 0x64, 0x74, 0x77, 0x80, 0x27, 0x30, 0x36, 0x44, 0x23, 0x10, 0x55, 0x24, 0x15, 0x43, 0x11, 0x63, 0x14, 0x65, 0x33, 0x63, 0x12, 0x11, 0x84, 0x63, 0x12, 0x63, 0x88, 0x37, 0x62, 0x67, 0x48, 0x35, 0x13, 0x86, 0x35, 0x17, 0x83, 0x12, 0x58, 0x14, 0x47, 0x88, 0x56, 0x08, 0x48, 0x01, 0x42, 0x71, 0x64, 0x77, 0x53, 0x64, 0x73, 0x54, 0x66, 0x05, 0x56, 0x60, 0x52, 0x37, 0x00, 0x46, 0x40, 0x31, 0x10, 0x55, 0x50, 0x45, 0x36, 0x48, 0x42, 0x34, 0x06, 0x61, 0x11, 0x75, 0x52, 0x61, 0x58, 0x52, 0x15, 0x73, 0x57, 0x31, 0x56, 0x15, 0x87, 0x78, 0x74, 0x45, 0x03, 0x87, 0x20, 0x54, 0x56, 0x11, 0x66, 0x22, 0x04, 0x46, 0x14, 0x14, 0x61, 0x83, 0x00, 0x06, 0x86, 0x64, 0x06, 0x00, 0x47, 0x37, 0x44, 0x22, 0x50, 0x56, 0x01, 0x04, 0x57, 0x73, 0x50, 0x74, 0x87, 0x02, 0x66, 0x37, 0x48, 0x68, 0x48, 0x02, 0x63, 0x28, 0x52, 0x63, 0x58, 0x11, 0x30, 0x44, 0x28, 0x68, 0x32, 0x61, 0x10, 0x61, 0x88, 0x26, 0x07, 0x00, 0x73, 0x38, 0x62, 0x55, 0x27, 0x15, 0x53, 0x45, 0x32, 0x14, 0x25, 0x73, 0x23, 0x12, 0x21, 0x87, 0x86, 0x55, 0x67, 0x25, 0x67, 0x46, 0x74, 0x72, 0x81, 0x44, 0x54, 0x64, 0x15, 0x77, 0x41, 0x07, 0x80, 0x60, 0x56, 0x13, 0x16, 0x15, 0x40, 0x44, 0x63, 0x47, 0x53, 0x30, 0x77, 0x61, 0x62, 0x50, 0x13, 0x38, 0x41, 0x47, 0x42, 0x66, 0x70, 0x52, 0x06, 0x70, 0x81, 0x25, 0x43, 0x17, 0x77, 0x70, 0x15, 0x22, 0x21, 0x82, 0x50, 0x03, 0x82, 0x09, 0xC1, 0x00, 0x01, 0x31, 0x73, 0x16, 0x9D, 0xB8, 0x08, 0x6B, 0x12, 0x27, 0x01, 0x70, 0x6A, 0xE4, 0x9B, 0x99, 0x30, 0x5E, 0xE6, 0xD0, 0x16, 0xF1, 0x6F, 0x9F, 0xAC, 0xC1, 0xF8, 0x35, 0x29, 0x8B, 0x41, 0xE2, 0x16, 0x64, 0x20, 0x60, 0x05, 0xCE, 0xB9, 0x81, 0xA3, 0x5F, 0x18, 0x65, 0x1C, 0xDB, 0x90, 0xE6, 0x8C, 0x1F, 0x95, 0x0B, 0x05, 0x9F, 0x73, 0xD6, 0xD3, 0x14, 0x3A, 0x1F, 0x47, 0xAA, 0x21, 0xD8, 0x0A, 0x05, 0xFA, 0xF5, 0xD3, 0xA4, 0x0F, 0x67, 0x14, 0x8D, 0x3A, 0x89, 0xA9, 0xFD, 0xA8, 0x03, 0x64, 0xD5, 0x7C, 0x7B, 0x8F, 0x68, 0x05, 0x8A, 0x25, 0xD0, 0x84, 0x98, 0xD9, 0xA9, 0xC3, 0x78, 0xC9, 0x81, 0x85, 0xDB, 0x13, 0x25, 0x91, 0x59, 0xCA, 0xC4, 0x76, 0x9C, 0x34, 0xA0, 0x80, 0x23, 0xA3, 0x38, 0x8C, 0x35, 0x05, 0x40, 0x6F, 0xB2, 0x1C, 0x69, 0xEE, 0xC1, 0x2D, 0xAC, 0x95, 0xA3, 0xC9, 0xBA, 0x61, 0x18, 0x52, 0x37, 0xF0, 0xFF, 0x1E, 0x0E, 0x05, 0xF1, 0xA6, 0xF5, 0xA0, 0xC0, 0x90, 0x90, 0x10, 0x06, 0x65, 0xA1, 0xAD, 0x3A, 0xFB, 0x10, 0x76, 0x84, 0x7B, 0x23, 0x2E, 0xEE, 0xA7, 0x84, 0x09, 0xBD, 0x90, 0x55, 0xDB, 0x57, 0xC1, 0xB3, 0x1E, 0x28, 0xA0, 0x1D, 0x09, 0x99, 0x90, 0x35, 0xBD, 0xFC, 0x65, 0x7A, 0x61, 0x04, 0x01, 0x03, 0xEC, 0xEB, 0xDC, 0x79, 0x34, 0x09, 0x73, 0x37, 0x34, 0xD9, 0x34, 0x2C, 0xC5, 0xA0, 0x69, 0xE0, 0x70, 0xC2, 0x42, 0x1D, 0xDE, 0x11, 0xC4, 0x9E, 0x17, 0x2D, 0xBE, 0x7F, 0xEA, 0xF9, 0xDE, 0xDD, 0xFB, 0x3D, 0xA5, 0xDA, 0xA6, 0xB3, 0xDD, 0x13, 0x20, 0x0B, 0x09, 0x04, 0x2E, 0x14, 0x4E, 0xEA, 0x95, 0x1B, 0x43, 0xDA, 0x48, 0x15, 0x3C, 0x1F, 0x1D, 0x5C, 0x07, 0xFC, 0xF4, 0x73, 0xFA, 0x7F, 0x32, 0x1E, 0x72, 0x53, 0x45, 0x77, 0xC8, 0x95, 0x15, 0x1B, 0x46, 0xE4, 0x83, 0x31, 0xDD, 0xE6, 0x1D, 0xA4, 0x5F, 0x86, 0x09, 0xAC, 0x59, 0x58, 0x18, 0x14, 0x66, 0x6E, 0x16, 0x58, 0xB4, 0x91, 0x14, 0x52, 0x4B, 0xA3, 0x84, 0x0C, 0x6B, 0xC5, 0x59, 0x65, 0x51, 0xAE, 0xF4, 0x24, 0x12, 0xC8, 0xAA, 0xCC, 0xDD, 0x8E, 0xF6, 0x9E, 0x46, 0x38, 0x0E, 0x6D, 0xEF, 0x60, 0xFD, 0x91, 0x22, 0x8B, 0x99, 0xCB, 0x51, 0x1D, 0x68, 0xEF, 0x66, 0x31, 0x74, 0x8A, 0x05, 0x48, 0x08, 0x3A, 0x21, 0x54, 0x45, 0xEC, 0x54, 0x69, 0x34, 0x71, 0xA8, 0x31, 0x04, 0x2C, 0xF4, 0x1D, 0x09, 0xAF, 0x89, 0x81, 0x19, 0xB0, 0xFC, 0x64, 0x6E, 0x48, 0x45, 0x39, 0xC8, 0xC3, 0x2D, 0x5D, 0xC2, 0x4F, 0x94, 0x39, 0xD3, 0x3E, 0xEE, 0xA0, 0x33, 0xA4, 0x08, 0x15, 0x50, 0xFD, 0xB0, 0xB0, 0x89, 0x23, 0xDB, 0xA5, 0xD4, 0x4A, 0x1A, 0x87, 0x6F, 0xE7, 0xEE, 0x43, 0x20, 0xBF, 0x02, 0xF9, 0xBE, 0x26, 0xF4, 0x18, 0xF3, 0x09, 0xFA, 0x11, 0xFC, 0xD0, 0xC8, 0x64, 0xA7, 0xAA, 0x34, 0x11, 0x50, 0x83, 0xC1, 0xEA, 0x77, 0x53, 0x45, 0xAC, 0x05, 0x48, 0xC8, 0x77, 0xC6, 0x85, 0xEA, 0x8C, 0x91, 0xB9, 0x24, 0xAF, 0x4F, 0x60, 0x7E, 0xF3, 0x7A, 0x02, 0x08, 0xE2, 0x13, 0x09, 0xAB, 0x6D, 0x0F, 0x2F, 0x8A, 0x4E, 0xAA, 0x04, 0x51, 0xFF, 0x4A, 0x47, 0xE6, 0xF4, 0x82, 0x95, 0x8D, 0x81, 0xA1, 0x66, 0xA6, 0xA0, 0x8A, 0x6A, 0x10, 0xFC, 0x8F, 0x9A, 0xDA, 0x42, 0xB6, 0x4A, 0x12, 0xB9, 0x35, 0x7D, 0x59, 0x8A, 0x36, 0x64, 0xE9, 0xDF, 0x13, 0x75, 0x5C, 0x10, 0xFF, 0xD7, 0x17, 0x7E, 0x59, 0x4D, 0xFC, 0xBC, 0xFB, 0x5D, 0x11, 0xB6, 0xAD, 0xB1, 0x60, 0x74, 0x45, 0x47, 0x9A, 0x5D, 0xB1, 0xAD, 0x8C, 0xA6, 0xD9, 0x15, 0xF8, 0x97, 0x95, 0xD2, 0x40, 0xCB, 0xED, 0xFA, 0xD2, 0x53, 0x9D, 0x10, 0x51, 0x8E, 0x53, 0xCC, 0x45, 0x0D, 0x6F, 0xC5, 0x38, 0x5A, 0xD6, 0xD7, 0x6B, 0x78, 0x30, 0xF1, 0x38, 0x28, 0x12, 0x06, 0x45, 0xE3, 0xA0, 0xA5, 0xDC, 0xDE, 0xAF, 0x15, 0xF1, 0x96, 0x8E, 0x64, 0xB3, 0xB1, 0xCE, 0xAF, 0x53, 0x6C, 0xAA, 0x29, 0x53, 0xD1, 0x61, 0xC7, 0x55, 0x28, 0xC3, 0xFA, 0x84, 0x93, 0xE0, 0xC1, 0x77, 0xAE, 0x80, 0x7C, 0xED, 0x37, 0x64, 0x8A, 0x82, 0xC9, 0xBE, 0x8B, 0xA9, 0x70, 0x29, 0x6D, 0x54, 0x3F, 0x6F, 0xBD, 0x67, 0x24, 0xA9, 0x9A, 0x68, 0xD2, 0xF6, 0x8C, 0x1F, 0xD3, 0x33, 0xF9, 0xDE, 0xF8, 0x52, 0x6D, 0xB7, 0x83, 0x64, 0x55, 0xB3, 0x13, 0xE6, 0xBC, 0x36, 0x61, 0x78, 0xC9, 0xC5, 0x77, 0x21, 0x60, 0x1E, 0xC0, 0x33, 0x50, 0x54, 0xF0, 0x67, 0xB7, 0x8E, 0x66, 0x3A, 0x05, 0x8D, 0xBD, 0xA1, 0xC1, 0x2D, 0x80, 0xA3, 0x92, 0xF8, 0x9C, 0x0A, 0xD9, 0xE2, 0xA3, 0xB2, 0xEA, 0x17, 0xE9, 0xC9, 0xA3, 0xB1, 0x4D, 0x17, 0x68, 0x22, 0xEE, 0xAC, 0x5F, 0xB5, 0xFF, 0x7D, 0x4C, 0x87, 0xD7, 0x60, 0x80, 0xD2, 0xD4, 0x2D, 0x9A, 0xA4, 0xC9, 0x51, 0xF4, 0xCA, 0xF1, 0x1A, 0x24, 0x4E, 0xDA, 0x71, 0x1D, 0x12, 0x0A, 0x2E, 0xA3, 0x21, 0xD1, 0x55, 0x1D, 0x86, 0xCA, 0x92, 0x65, 0xE9, 0xCD, 0x5F, 0xA9, 0x59, 0x1D, 0x88, 0x0E, 0x40, 0x3B, 0x68, 0x44, 0xF0, 0x51, 0xDC, 0x04, 0x87, 0x99, 0x72, 0xC8, 0x63, 0xB9, 0x7C, 0x72, 0xB4, 0x09, 0xC1, 0x9D, 0x5E, 0xBE, 0xE8, 0xAB, 0x58, 0xC6, 0xE7, 0xB3, 0x93, 0x8A, 0x68, 0xA9, 0xCA, 0xD7, 0x5D, 0x80, 0xC6, 0xFF, 0xC4, 0xF2, 0x22, 0x54, 0xFF, 0x44, 0x20, 0xC6, 0x06, 0xAD, 0x12, 0x0C, 0xC2, 0x03, 0x46, 0xA7, 0xE7, 0x32, 0x4E, 0x78, 0xC8, 0x62, 0xE0, 0xDE, 0xE1, 0x61, 0xA6, 0x4F, 0x44, 0x91, 0x7D, 0xB0, 0xC3, 0x8C, 0x1F, 0x79, 0xC9, 0x69, 0x22, 0x0D, 0x20, 0x2F, 0x88, 0x02, 0xD0, 0xF9, 0xD7, 0xAB, 0xFB, 0x2D, 0xE4, 0x34, 0xB1, 0xC5, 0x3D, 0xAB, 0xB5, 0x75, 0x75, 0xEE, 0xBB, 0xBF, 0x31, 0xCF, 0xB2, 0x92, 0x48, 0x72, 0xFA, 0x01, 0x47, 0x3B, 0x39, 0x76, 0xAE, 0xAD, 0xC9, 0x96, 0x99, 0xB1, 0x38, 0x20, 0xFA, 0x08, 0x68, 0xF2, 0xC9, 0xFD, 0x0D, 0x35, 0x2E, 0x25, 0x93, 0x27, 0x3C, 0xD6, 0x21, 0xB1, 0x97, 0x4F, 0xFA, 0x61, 0x87, 0xFA, 0x05, 0xC4, 0x11, 0x8D, 0x45, 0x17, 0xC9, 0x34, 0x15, 0x1C, 0x1F, 0xA3, 0x4B, 0xEC, 0x3E, 0xD3, 0x63, 0x95, 0x98, 0xCB, 0xA2, 0x4E, 0x28, 0x22, 0x9C, 0xE9, 0xFD, 0x3B, 0x1D, 0xB4, 0x96, 0x9C, 0x12, 0xEE, 0x49, 0xE1, 0x8B, 0x36, 0xCE, 0x2B, 0x91, 0x45, 0xAA, 0xC7, 0x54, 0x28, 0xDF, 0xFA, 0x14, 0x53, 0x02, 0xF4, 0x1D, 0x9E, 0x33, 0x94, 0xF3, 0x8D, 0x3F, 0x3C, 0x03, 0x34, 0xC4, 0x77, 0x4F, 0x1E, 0x94, 0x29, 0x6D, 0xE3, 0x6D, 0xC6, 0xE4, 0x30, 0xE4, 0xC0, 0xA5, 0x37, 0xE6, 0x8B, 0xDD, 0x41, 0xAF, 0x04, 0x21, 0x19, 0x3B, 0x16, 0xAB, 0x18, 0x91, 0xFA, 0x83, 0x6C, 0xBC, 0x36, 0x7B, 0x40, 0x37, 0x05, 0xAB, 0xA5, 0xD2, 0xF9, 0xF2, 0xA4, 0xC2, 0xF2, 0x75, 0xEC, 0x01, 0x0B, 0x2E, 0xAB, 0x84, 0x09, 0x5A, 0x56, 0x9D, 0xBA, 0xE4, 0x45, 0x7C, 0xC2, 0xAC, 0x1C, 0xFE, 0xB1, 0xED, 0xA4, 0x3C, 0x3E, 0x28, 0x19, 0x27, 0x3C, 0x48, 0x7A, 0xCB, 0xEB, 0xFA, 0x0A, 0x0E, 0xD1, 0xCC, 0x46, 0x67, 0xA6, 0xF5, 0x77, 0xF6, 0x2D, 0xFB, 0x1B, 0xC8, 0xFE, 0xAF, 0xD8, 0x6D, 0x90, 0x10, 0x8E, 0x16, 0xB8, 0xB0, 0xE6, 0xC2, 0x67, 0x86, 0x86, 0xC9, 0x28, 0xA6, 0x68, 0xBB, 0x98, 0x57, 0xFF, 0xB2, 0x8D, 0xE9, 0x05, 0x45, 0xCD, 0x44, 0x37, 0xDD, 0x32, 0xCC, 0xCC, 0xC6, 0xED, 0x58, 0xFB, 0x46, 0xFB, 0xF8, 0x5E, 0x0A, 0xEC, 0x0C, 0x81, 0x4E, 0x53, 0x62, 0x45, 0x25, 0x2B, 0x80, 0x29, 0xF0, 0xA2, 0xAB, 0x44, 0xB9, 0x02, 0x7A, 0x7E, 0x35, 0xA9, 0x41, 0xFA, 0x11, 0x3C, 0x8D, 0x82, 0x97, 0x4E, 0xA2, 0x2D, 0xF0, 0x2D, 0x84, 0xE5, 0x32, 0x8C, 0xEA, 0x83, 0xD1, 0x2D, 0x39, 0x9C, 0x7F, 0x02, 0x59, 0x05, 0x5F, 0x4B, 0x3A, 0xD7, 0x07, 0xE7, 0xB3, 0xE5, 0x37, 0xB9, 0x3D, 0xEA, 0x1A, 0x06, 0x6B, 0xDC, 0x77, 0x5F, 0xC7, 0xD1, 0xA6, 0xF0, 0xFE, 0x29, 0xDD, 0xAF, 0xA9, 0xA7, 0xDA, 0x63, 0x0A, 0x46, 0x7E, 0xF6, 0xCB, 0xF5, 0xCC, 0xDF, 0xFD, 0x79, 0xF1, 0xC8, 0xBB, 0x6B, 0xB3, 0x88, 0x20, 0x35, 0xC7, 0x3C, 0xDF, 0x7E, 0xCF, 0xFB, 0x53, 0xC7, 0x12, 0xA7, 0xC7, 0xEA, 0xA5, 0x97, 0x65, 0xEF, 0xA9, 0x60, 0xBF, 0x21, 0xE2, 0x5A, 0x67, 0x03, 0xFB, 0x30, 0x4F, 0x07, 0x73, 0x9F, 0xEB, 0xC6, 0x3F, 0x49, 0x6B, 0x13, 0xCC, 0xAA, 0x07, 0x73, 0x38, 0xA0, 0xB9, 0xA9, 0x76, 0xA9, 0xF0, 0xFC, 0x57, 0x42, 0xD8, 0x5C, 0x4A, 0xF4, 0x01, 0xA4, 0xCE, 0x34, 0x1B, 0x47, 0xBE, 0x25, 0x94, 0xFF, 0x7E, 0x30, 0x19, 0xA0, 0xE0, 0x64, 0x53, 0x5F, 0x9D, 0x93, 0x95, 0xCC, 0x74, 0xA6, 0xA6, 0xF0, 0x0E, 0x0C, 0x4E, 0x35, 0x30, 0xA7, 0xFE, 0x93, 0x10, 0xCE, 0x30, 0xB6, 0x92, 0x2D, 0x04, 0xFD, 0xE0, 0xAA, 0x74, 0x9C, 0xC3, 0xFD, 0xED, 0xB4, 0xD8, 0x70, 0x8C, 0x1F, 0x69, 0x68, 0xBB, 0xED, 0xDD, 0xD5, 0x83, 0x3B, 0x29, 0x9D, 0x79, 0xD6, 0x14, 0x28, 0x18, 0x00, 0x99, 0xB0, 0xA9, 0x46, 0xA5, 0xD7, 0x90, 0x85, 0xDF, 0x7F, 0x87, 0x2C, 0xBD, 0xD2, 0x19, 0xE6, 0xB8, 0xEF, 0x8B, 0x8A, 0xB5, 0xC1, 0xA1, 0x49, 0xE6, 0xE1, 0x5E, 0xF2, 0x82, 0x86, 0x54, 0xFA, 0xBE, 0xC2, 0x49, 0xAF, 0xAA, 0xC4, 0xDC, 0x0B, 0x3B, 0x54, 0x23, 0x34, 0x16, 0x2F, 0xB0, 0x98, 0x00, 0xB6, 0xC3, 0x6C, 0xC9, 0x0F, 0x2A, 0x10, 0x65, 0x58, 0xBA, 0xE2, 0x19, 0x8F, 0xA7, 0xD1, 0xE2, 0xD7, 0x30, 0xDE, 0x46, 0xE3, 0x55, 0xAE, 0xA9, 0x32, 0x48, 0xE5, 0x3A, 0xB2, 0x1B, 0x51, 0x8E, 0xC9, 0x9D, 0x5F, 0x3B, 0x02, 0x11, 0x96, 0xA0, 0xF6, 0x14, 0xA4, 0x6B, 0x94, 0x75, 0x62, 0x12, 0x34, 0x73, 0x3A, 0x28, 0xA4, 0x65, 0xCC, 0x5A, 0x7F, 0xD4, 0x32, 0xC3, 0x62, 0x58, 0x12, 0xAA, 0xBB, 0xB4, 0x2D, 0x2D, 0x9C, 0xBE, 0xF1, 0x6C, 0xBE, 0xD9, 0x36, 0x72, 0x02, 0xB0, 0x28, 0x94, 0xD0, 0x6B, 0xB8, 0x01, 0xBD, 0xA8, 0x47, 0x2B, 0x99, 0x18, 0xB7, 0xD7, 0x24, 0xE3, 0x65, 0x57, 0xDB, 0xE6, 0xB7, 0x63, 0x3A, 0x5F, 0xD2, 0x2D, 0x0E, 0x33, 0x6E, 0x55, 0x57, 0xAF, 0xC0, 0x18, 0xC8, 0x12, 0xE9, 0xE6, 0xA3, 0x5B, 0xFD, 0x8C, 0x60, 0xAB, 0x38, 0x2E, 0x14, 0xFF, 0x51, 0x14, 0x2B, 0x2D, 0x2C, 0x75, 0xA7, 0x67, 0xF3, 0x24, 0x13, 0xBA, 0x38, 0x48, 0x75, 0x58, 0xF9, 0x34, 0x5C, 0xBE, 0x6F, 0xD1, 0xD6, 0xB7, 0x8C, 0x2E, 0x62, 0x2F, 0x3B, 0x97, 0x62, 0x30, 0xF9, 0x9D, 0x6C, 0xBA, 0xF0, 0xBB, 0xD1, 0x49, 0x49, 0x51, 0x0A, 0x52, 0x64, 0x4E, 0xF3, 0xF3, 0x07, 0x88, 0x65, 0x03, 0x7A, 0x1C, 0x10, 0xF4, 0x7B, 0x59, 0x54, 0x66, 0x99, 0xE1, 0xBD, 0x53, 0x9C, 0x7D, 0xDC, 0xC0, 0x3F, 0x71, 0xA0, 0x15, 0x8E, 0xA9, 0xF0, 0x17, 0x8E, 0x18, 0x7B, 0xB6, 0xD4, 0x94, 0x40, 0xDF, 0x2B, 0x10, 0x63, 0x0F, 0xBE, 0x2F, 0xEB, 0x50, 0x97, 0xE4, 0x7F, 0x28, 0x57, 0x11, 0xCA, 0x6F, 0x83, 0x5A, 0x10, 0xD3, 0xAA, 0x75, 0xC0, 0x3C, 0x41, 0x84, 0xC0, 0x3E, 0xF3, 0x07, 0x5D, 0x49, 0xDC, 0xB2, 0x17, 0x7A, 0xBD, 0x53, 0xAD, 0x73, 0x99, 0xD2, 0x90, 0xEA, 0x69, 0x1D, 0x64, 0x73, 0x29, 0x05, 0x63, 0x40, 0xE8, 0xC8, 0x36, 0xE9, 0x75, 0x0F, 0xD8, 0x81, 0xDC, 0xE3, 0x09, 0xD3, 0x09, 0xA9, 0x5B, 0x82, 0x49, 0x2D, 0x4B, 0xDC, 0x15, 0xEC, 0xF8, 0xC7, 0xF5, 0xD3, 0xB9, 0xDD, 0x27, 0x55, 0x48, 0x51, 0x2D, 0xB5, 0xEF, 0x80, 0xCD, 0x40, 0x9E, 0xD3, 0x2B, 0x51, 0x48, 0xB8, 0x2B, 0xF2, 0x40, 0xA7, 0xDC, 0x72, 0xA1, 0x85, 0x23, 0xD8, 0x08, 0xB7, 0xA4, 0xF9, 0xE2, 0x54, 0x79, 0x9E, 0x17, 0x27, 0x8F, 0xA8, 0x8D, 0xAE, 0xBC, 0x94, 0x46, 0x32, 0xE8, 0x3F, 0x86, 0x09, 0xD6, 0x81, 0xAB, 0x46, 0x35, 0x13, 0x02, 0x3D, 0x67, 0xCD, 0x51, 0xB1, 0x53, 0xF0, 0x96, 0x29, 0x12, 0xDD, 0x64, 0xAB, 0x8F, 0x65, 0x29, 0xDC, 0x22, 0xAA, 0x89, 0xE5, 0x72, 0xA7, 0xF8, 0x9C, 0xB9, 0x7A, 0x8F, 0x45, 0x09, 0x31, 0x9D, 0x22, 0x3B, 0xB2, 0x99, 0x74, 0x95, 0x17, 0x16, 0xFD, 0x31, 0x77, 0x14, 0x0A, 0x31, 0xEA, 0x20, 0x04, 0x8B, 0xAF, 0x0F, 0xCA, 0x23, 0x0C, 0xEF, 0x21, 0x96, 0x7A, 0xBD, 0x83, 0x30, 0x9A, 0x4F, 0xF7, 0xE3, 0x5E, 0x88, 0x78, 0x4D, 0xCA, 0x77, 0xAC, 0x07, 0x90, 0x20, 0xEC, 0x0C, 0xA6, 0xDD, 0xEF, 0xBC, 0xBB, 0x7E, 0x31, 0x73, 0x29, 0x31, 0x46, 0x65, 0xD7, 0xC5, 0x1F, 0x63, 0x1F, 0x68, 0x1B, 0x60, 0x03, 0x64, 0xE4, 0x75, 0x74, 0xF2, 0x52, 0xBA, 0xD6, 0x39, 0x6B, 0x3F, 0x5B, 0x17, 0xAD, 0xC2, 0x20, 0x96, 0x6A, 0x93, 0xCE, 0x8F, 0x31, 0x5A, 0x2F, 0x83, 0x06, 0x8D, 0x2E, 0xA0, 0x69, 0x52, 0xE6, 0xEB, 0xD8, 0x02, 0x47, 0x3A, 0x22, 0x64, 0xEF, 0xA4, 0x05, 0xB3, 0xE4, 0x91, 0xBE, 0x77, 0x6C, 0x50, 0x40, 0x6E, 0x11, 0x50, 0xC5, 0x6B, 0x89, 0x4C, 0xF8, 0x64, 0x54, 0x6B, 0x0C, 0x7A, 0x65, 0xE3, 0xF1, 0xA2, 0xBE, 0xFE, 0xF2, 0xA9, 0x99, 0x0B, 0xAF, 0xE7, 0x0B, 0x6C, 0xA9, 0xF9, 0x1A, 0x8F, 0x3D, 0xD2, 0x13, 0x07, 0xA3, 0x9A, 0x2A, 0xFB, 0xDF, 0xBD, 0xE9, 0xB7, 0xCA, 0x3D, 0x78, 0x28, 0xB1, 0x3F, 0x49, 0xDE, 0xCD, 0x72, 0x9C, 0x00, 0x39, 0xE9, 0x4E, 0xBB, 0x7B, 0x4B, 0xDA, 0x09, 0xB3, 0x50, 0x55, 0x29, 0xA1, 0x2C, 0xB1, 0xE2, 0xFD, 0x79, 0xB9, 0xE5, 0x08, 0x7C, 0xD7, 0xC3, 0xBC, 0x05, 0xF7, 0xCF, 0xFB, 0xBA, 0x93, 0x2A, 0x7B, 0xFF, 0x8E, 0x67, 0x55, 0x5F, 0xEE, 0x03, 0x04, 0xD8, 0x90, 0x31, 0x3F, 0x86, 0xE1, 0x89, 0x25, 0x69, 0xE2, 0xD6, 0xF1, 0x4A, 0x89, 0x93, 0x87, 0x17, 0xAA, 0xA3, 0xA3, 0x2A, 0xD1, 0x16, 0x71, 0x50, 0x29, 0x9C, 0x21, 0x82, 0x0A, 0xBD, 0x70, 0xFF, 0x90, 0x2B, 0x00, 0x4C, 0x6D, 0xE9, 0x1C, 0x1C, 0x0B, 0x40, 0x70, 0x64, 0x42, 0xAF, 0x53, 0x1E, 0xC4, 0x90, 0xB0, 0x12, 0x75, 0x0B, 0xCB, 0x48, 0x77, 0x93, 0x5A, 0x7E, 0x54, 0x03, 0x17, 0x02, 0xBB, 0x98, 0x8E, 0xB3, 0xF9, 0x29, 0x14, 0xCD, 0xBD, 0x42, 0x97, 0x9A, 0xD7, 0xD2, 0x7B, 0x22, 0x33, 0xEC, 0x12, 0x79, 0xD0, 0x54, 0x93, 0xB1, 0x2D, 0x3F, 0x5F, 0xBB, 0x77, 0x57, 0x53, 0x60, 0x21, 0xB5, 0xF4, 0xCD, 0x93, 0x2B, 0x48, 0x0E, 0x40, 0xCB, 0xAE, 0x50, 0xD2, 0x32, 0xE0, 0xA2, 0xEF, 0xFE, 0x0E, 0x8C, 0xB5, 0x88, 0x08, 0x66, 0x91, 0x99, 0xF0, 0x83, 0x08, 0x72, 0xF3, 0x69, 0x73, 0x86, 0x82, 0xF8, 0x46, 0xF6, 0xDE, 0xAD, 0x09, 0x5B, 0xFF, 0xCD, 0x67, 0x0A, 0x4A, 0x9C, 0xD1, 0x42, 0x39, 0x6C, 0x58, 0x50, 0x6E, 0xA7, 0xA6, 0x8B, 0x21, 0xAB, 0xDC, 0xC1, 0x9C, 0xCC, 0x06, 0xF6, 0xDA, 0x55, 0xC8, 0x85, 0xA8, 0x55, 0xC4, 0x56, 0x68, 0x0C, 0xD4, 0x47, 0x7B, 0xCA, 0x2B, 0xBA, 0x91, 0x53, 0xDC, 0xAE, 0xE6, 0x82, 0x65, 0x5B, 0x74, 0xEC, 0xA6, 0xF7, 0xE4, 0x4C, 0x3B, 0xFE, 0x1E, 0x2D, 0x45, 0x74, 0x91, 0xED, 0x1B, 0xC6, 0x4E, 0x1C, 0xF6, 0xCE, 0x18, 0xCF, 0x44, 0xA0, 0x16, 0x6D, 0x1B, 0x24, 0x44, 0x80, 0x88, 0x2C, 0x1B, 0x35, 0xCE, 0xA7, 0x03, 0x15, 0x8E, 0x18, 0xC7, 0xEC, 0x6E, 0x0C, 0xF8, 0x27, 0xD5, 0x50, 0x4A, 0x45, 0xAE, 0x61, 0x15, 0x23, 0x09, 0xBC, 0x8A, 0x18, 0xA5, 0x2C, 0x0E, 0x76, 0x99, 0xA8, 0x7C, 0x4E, 0x31, 0xC6, 0x91, 0x1A, 0x83, 0x05, 0x35, 0x15, 0x55, 0xB2, 0x97, 0x1C, 0x94, 0x60, 0x2B, 0x70, 0xE6, 0x70, 0xAA, 0x30, 0xB9, 0x07, 0x34, 0xEC, 0x1D, 0xAA, 0xD0, 0x3A, 0x30, 0xA9, 0x6F, 0x58, 0x47, 0xC5, 0xC3, 0xF7, 0x97, 0x3C, 0xF4, 0x57, 0x2D, 0x16, 0x6C, 0x51, 0xD1, 0xE9, 0x4A, 0x50, 0xA4, 0xC1, 0xC8, 0x94, 0xA2, 0x05, 0xF8, 0xEC, 0xB3, 0x4E, 0x80, 0xF8, 0x4C, 0xA8, 0xDC, 0x31, 0xA4, 0x29, 0xD5, 0x60, 0x05, 0x96, 0x17, 0x9D, 0x10, 0x93, 0xE2, 0xA3, 0x89, 0xCC, 0xFE, 0x9C, 0x04, 0x02, 0xEE, 0x49, 0x55, 0x17, 0x10, 0xFF, 0xC2, 0x5B, 0xDB, 0xE4, 0x78, 0xF3, 0x9F, 0x20, 0x63, 0xF3, 0x1F, 0x75, 0xD7, 0x43, 0x2E, 0xCA, 0x1C, 0x59, 0xEB, 0xD8, 0xF4, 0x6D, 0x86, 0xA0, 0x92, 0xDB, 0x12, 0xF8, 0x10, 0xFA, 0x91, 0x1C, 0x20, 0xD4, 0xCC, 0x1E, 0x42, 0x5C, 0x54, 0x3D, 0xC6, 0x45, 0x77, 0xE4, 0x4D, 0x84, 0xF4, 0x22, 0xD9, 0x66, 0x1E, 0x3D, 0x35, 0x92, 0x13, 0x50, 0xD6, 0xF7, 0x09, 0x9C, 0x54, 0x25, 0xE5, 0x09, 0xE1, 0x45, 0x8A, 0x05, 0x00, 0xAE, 0x5E, 0xB4, 0xCC, 0x6B, 0xB5, 0x06, 0x26, 0xD0, 0x13, 0x0F, 0x09, 0x36, 0x17, 0x17, 0xA9, 0x59, 0x19, 0xAE, 0xD3, 0x55, 0x92, 0xFA, 0x4A, 0xBE, 0x7B, 0x2B, 0xD4, 0xF9, 0x99, 0x42, 0x21, 0x51, 0xE6, 0x3D, 0x4E, 0xD0, 0x0C, 0xC7, 0x51, 0xA5, 0x86, 0x79, 0x77, 0xF1, 0x5E, 0x48, 0x2E, 0xFA, 0x01, 0xE5, 0xCC, 0xC4, 0x40, 0x64, 0xF5, 0xB9, 0xFF, 0xE2, 0x9A, 0xFF, 0xE6, 0x26, 0xC4, 0xD5, 0x17, 0x0A, 0xDA, 0x1D, 0xF0, 0x27, 0xAB, 0x41, 0x79, 0x60, 0x8C, 0x40, 0x93, 0xCC, 0xE2, 0xC4, 0x09, 0x30, 0x8C, 0xD8, 0x98, 0x37, 0x1A, 0x49, 0xFB, 0xEA, 0x2A, 0x2F, 0x2B, 0xA1, 0x3B, 0xDE, 0xBA, 0xC1, 0xF4, 0x15, 0x9F, 0x4B, 0x03, 0x68, 0xFB, 0x21, 0xD7, 0x0A, 0x9D, 0x79, 0x31, 0xD7, 0xEF, 0xF9, 0x34, 0xE6, 0xC5, 0x44, 0xE1, 0x3B, 0x7B, 0x73, 0xD4, 0x65, 0x57, 0x6C, 0x6E, 0x81, 0xFD, 0x6D, 0x5F, 0xD9, 0x43, 0x93, 0xE8, 0x02, 0x42, 0xF9, 0x42, 0x0A, 0xCC, 0x0E, 0xD3, 0x53, 0xEF, 0x18, 0xCA, 0x07, 0x0F, 0x5E, 0x9A, 0x28, 0x5A, 0xC4, 0xBC, 0xBA, 0xB1, 0x9A, 0x38, 0x35, 0x6F, 0x55, 0x7B, 0x07, 0x0E, 0x17, 0xAE, 0x5C, 0xF1, 0xF1, 0xBE, 0xD4, 0x26, 0x01, 0xE8, 0x9C, 0x8C, 0x4C, 0xA0, 0x82, 0x07, 0x85, 0x03, 0x82, 0x07, 0x81, 0x00, 0xD9, 0xFD, 0xE3, 0xA4, 0x96, 0xF7, 0x58, 0x19, 0xF0, 0xA2, 0x0D, 0x04, 0x41, 0xDC, 0x78, 0x30, 0xB4, 0xAA, 0x1C, 0xB8, 0xEC, 0xFC, 0x91, 0xBA, 0x0E, 0xEC, 0x3A, 0xFB, 0x67, 0x44, 0xE4, 0x77, 0xB4, 0xE6, 0xEC, 0x3F, 0xDA, 0xE7, 0x50, 0x48, 0xFF, 0xEB, 0xAA, 0xBE, 0xA8, 0xE8, 0x22, 0x11, 0x7D, 0x57, 0x87, 0xF7, 0x90, 0x70, 0xEA, 0x88, 0x28, 0x7C, 0xE3, 0xCD, 0x50, 0x11, 0xFD, 0x8D, 0x93, 0xAB, 0x7E, 0x8B, 0x51, 0xF2, 0x61, 0x16, 0xBF, 0x9B, 0x6D, 0x21, 0xC0, 0x3F, 0x88, 0xBF, 0xEC, 0x48, 0x88, 0x76, 0xF4, 0xD0, 0x75, 0xA1, 0x42, 0xD4, 0xE7, 0x84, 0xD7, 0x34, 0x40, 0x75, 0x11, 0xF9, 0x92, 0x06, 0x93, 0x53, 0xF1, 0xDB, 0x67, 0xAC, 0xF7, 0x30, 0x34, 0xA4, 0x68, 0xA1, 0x18, 0x58, 0x80, 0x62, 0x11, 0x1D, 0x32, 0x0E, 0x00, 0xBC, 0xFF, 0x6D, 0xC6, 0x35, 0x73, 0xFC, 0xED, 0x1E, 0x96, 0xAA, 0xEB, 0xA6, 0x45, 0x2E, 0x3C, 0x7A, 0xCD, 0x19, 0x18, 0x1F, 0x9B, 0x81, 0x4B, 0xA1, 0x9D, 0x39, 0xB4, 0xBA, 0xB5, 0x49, 0x6D, 0xC0, 0x55, 0x42, 0x6E, 0x7E, 0xA4, 0x61, 0xAF, 0x55, 0xD5, 0xB9, 0xFE, 0x97, 0xF9, 0xDF, 0x7E, 0x25, 0x32, 0x03, 0xC1, 0xF9, 0xE1, 0x52, 0xE9, 0x6D, 0x75, 0xF9, 0xD9, 0xA8, 0x4F, 0x5C, 0x26, 0x3E, 0xC8, 0xC2, 0x50, 0x44, 0x0A, 0xDC, 0x98, 0x6F, 0x4E, 0x36, 0x41, 0x4C, 0x70, 0x3B, 0x3E, 0x05, 0x42, 0x6B, 0x28, 0xB7, 0x06, 0x59, 0x50, 0xDA, 0x6D, 0x0E, 0x0B, 0x2C, 0x60, 0xAC, 0x36, 0x72, 0xDB, 0x6F, 0x3C, 0x78, 0x44, 0x7D, 0xB7, 0xC2, 0x09, 0x15, 0x77, 0x0E, 0xA6, 0xFC, 0xE8, 0x1D, 0xAB, 0x53, 0x39, 0xC1, 0xD5, 0xAF, 0x82, 0xA5, 0xD3, 0x32, 0x40, 0x99, 0xDF, 0x56, 0x51, 0x6A, 0x07, 0xDB, 0x7C, 0x0F, 0xC6, 0x43, 0x83, 0x80, 0x5C, 0x65, 0xF2, 0xB0, 0x2F, 0xBC, 0xFC, 0xE6, 0x3E, 0x93, 0xC4, 0xBF, 0x09, 0x40, 0x9F, 0x9F, 0x0F, 0x77, 0xE7, 0x3D, 0xA3, 0xB0, 0x01, 0x9F, 0x20, 0x57, 0xE4, 0xCD, 0x7C, 0xFF, 0x0E, 0x57, 0x45, 0xEF, 0x18, 0xC3, 0xFD, 0x76, 0x6E, 0x01, 0x74, 0x7A, 0x64, 0xD4, 0x15, 0xFC, 0x97, 0x89, 0xAB, 0xFA, 0x62, 0x28, 0x4E, 0x11, 0xC7, 0xFF, 0x05, 0xD0, 0x54, 0x8D, 0x97, 0x3F, 0x67, 0x95, 0x59, 0xA6, 0xA3, 0xAA, 0xD7, 0x7E, 0xD5, 0x13, 0x2D, 0x01, 0x50, 0xC0, 0x14, 0xC3, 0xEC, 0x3A, 0x39, 0x5F, 0x01, 0x7E, 0x7A, 0xCF, 0xE3, 0xEA, 0xBF, 0xCA, 0x44, 0x91, 0x0C, 0xA0, 0x6F, 0xF3, 0x35, 0x42, 0xEC, 0xCE, 0x62, 0x41, 0x97, 0x47, 0x42, 0x35, 0x7D, 0x37, 0xF5, 0xC2, 0x84, 0xBF, 0x0F, 0xE1, 0xA7, 0x4B, 0x50, 0xC0, 0x73, 0x55, 0x13, 0x72, 0x13, 0x3A, 0xF2, 0xDD, 0x41, 0xE2, 0x1B, 0xAF, 0xC9, 0xC5, 0x90, 0xEE, 0x6E, 0xBC, 0x4A, 0xCE, 0x73, 0x1E, 0xF5, 0x66, 0x15, 0x6C, 0xA0, 0x37, 0x55, 0xDC, 0x49, 0x3C, 0x13, 0x70, 0x28, 0xAF, 0x3B, 0x3D, 0xE5, 0xB0, 0x0B, 0xD6, 0xCB, 0x3D, 0x9A, 0x87, 0xD0, 0x15, 0x1F, 0x88, 0x7C, 0x67, 0x68, 0xBC, 0x6C, 0xA0, 0x2A, 0x94, 0xFB, 0x20, 0x86, 0x55, 0x1A, 0x0F, 0x89, 0xBA, 0x26, 0x15, 0x4E, 0x9D, 0x45, 0x06, 0xAD, 0x9F, 0xAF, 0x39, 0xF5, 0x72, 0x3E, 0x23, 0x4E, 0x06, 0xCF, 0xDE, 0xD6, 0x9D, 0x4E, 0xE4, 0x14, 0x6B, 0x73, 0xE5, 0xDC, 0x1E, 0x41, 0x52, 0xA2, 0xA3, 0x15, 0x9D, 0x73, 0xDB, 0xC8, 0x33, 0xD3, 0xD4, 0x17, 0xCD, 0x5C, 0xF7, 0xFB, 0x3D, 0xC7, 0x74, 0x5C, 0xEE, 0xD4, 0xDC, 0x0F, 0x5B, 0x1C, 0x6D, 0x6B, 0x69, 0xC1, 0x76, 0x41, 0x57, 0xEA, 0x43, 0xDF, 0x9D, 0xBB, 0x44, 0x2E, 0xFA, 0x39, 0xD1, 0xD0, 0x16, 0x2E, 0x87, 0xC2, 0xD3, 0x0C, 0x50, 0x12, 0xFD, 0x16, 0xD8, 0x69, 0xC8, 0xA1, 0xFC, 0xBB, 0x45, 0xED, 0xCC, 0x8E, 0x18, 0x13, 0xB2, 0xB1, 0x90, 0xA9, 0x61, 0xF9, 0xFC, 0x86, 0x59, 0x1D, 0x3A, 0xBC, 0x53, 0x88, 0xAF, 0x67, 0x8F, 0xF0, 0x3D, 0xA7, 0x8B, 0x7C, 0xC0, 0xF6, 0x18, 0x57, 0x21, 0xC0, 0xDF, 0x33, 0xCC, 0x90, 0x64, 0x35, 0x22, 0x5D, 0xF2, 0x61, 0x10, 0x02, 0xDF, 0x12, 0x0E, 0x83, 0x56, 0x65, 0x32, 0x29, 0x2D, 0xEA, 0x3D, 0x8A, 0xCD, 0x10, 0x9A, 0x0D, 0xFF, 0xAB, 0x3B, 0x0B, 0x43, 0x01, 0x27, 0x96, 0xDB, 0x5B, 0x50, 0x68, 0x3F, 0xB4, 0xC2, 0xD2, 0x50, 0xDA, 0xB7, 0x6A, 0xAE, 0x35, 0xA4, 0x8E, 0x8C, 0x8D, 0x4A, 0x5C, 0xC1, 0x54, 0x75, 0x97, 0x45, 0xF0, 0xA1, 0x23, 0x0F, 0x6C, 0xA9, 0xDD, 0x9C, 0x99, 0xE2, 0xF8, 0x0E, 0xDC, 0x83, 0x30, 0x4C, 0xE0, 0x1E, 0x98, 0xF6, 0xC9, 0x48, 0x95, 0x29, 0xA8, 0x22, 0xF9, 0x00, 0x33, 0xC2, 0x28, 0x31, 0x5E, 0xB2, 0xFC, 0xC8, 0xDB, 0xA3, 0x82, 0xED, 0x43, 0x01, 0xE0, 0x76, 0x07, 0xA5, 0xB0, 0x76, 0xC7, 0x25, 0xF1, 0x24, 0x99, 0x4F, 0x18, 0xA9, 0x97, 0xD2, 0xC5, 0xBB, 0xF9, 0xA3, 0x24, 0x60, 0x52, 0x65, 0x10, 0x8A, 0xCB, 0xF4, 0x61, 0x0F, 0xA1, 0xC3, 0x37, 0x44, 0x08, 0x85, 0x0A, 0x08, 0x64, 0xE2, 0xB6, 0x10, 0x17, 0xEB, 0xEC, 0x1F, 0xBA, 0xB8, 0x9D, 0xE3, 0xAB, 0x1B, 0x93, 0xCE, 0x49, 0x18, 0xB9, 0xE2, 0xC9, 0xE3, 0xFE, 0x45, 0x67, 0x58, 0x06, 0x2A, 0x9F, 0x88, 0x2B, 0x28, 0x33, 0x18, 0x27, 0x1F, 0x4B, 0x95, 0x52, 0xFC, 0xF3, 0x26, 0x24, 0xA9, 0xFD, 0xAA, 0x44, 0xC6, 0x5C, 0x60, 0xE2, 0xB3, 0x64, 0x8B, 0xEF, 0x1F, 0x17, 0xD0, 0xB7, 0xC7, 0x48, 0x69, 0xEE, 0x0B, 0x53, 0xC4, 0xA6, 0x2A, 0x24, 0x84, 0x5D, 0xCE, 0xA5, 0xBC, 0xBF, 0x93, 0xB9, 0x2E, 0x4C, 0x26, 0x64, 0x85, 0x84, 0xE3, 0x34, 0x79, 0x28, 0x2E, 0x6C, 0x8B, 0x1D, 0x8F, 0xE2, 0x11, 0x81, 0xBD, 0x9C, 0xF7, 0x5F, 0x8A, 0x96, 0x17, 0x24, 0xD4, 0xC4, 0x30, 0x97, 0x79, 0xF1, 0xF1, 0xB7, 0x75, 0xD2, 0x54, 0xF7, 0x0B, 0xD1, 0x76, 0x9C, 0xC7, 0xC0, 0xED, 0xD2, 0xA9, 0x5F, 0xE5, 0xC9, 0xD8, 0x4B, 0x16, 0xF7, 0xC5, 0x4D, 0x85, 0xCC, 0xE4, 0xC8, 0xA1, 0x82, 0x81, 0x08, 0x09, 0xED, 0x81, 0xE9, 0x7D, 0x07, 0x48, 0x84, 0xEE, 0xDF, 0x40, 0x1C, 0xCA, 0xCD, 0xAE, 0xAD, 0x82, 0xC1, 0x4D, 0x06, 0xB6, 0x8A, 0xEA, 0x6C, 0xE1, 0x4B, 0x86, 0x1B, 0x0C, 0xFD, 0x16, 0x09, 0x0C, 0xBB, 0xF4, 0x69, 0xC5, 0xE0, 0x84, 0x31, 0x4C, 0x0D, 0x8D, 0x39, 0x60, 0xEA, 0x06, 0xA3, 0x42, 0x6D, 0x8B, 0x3F, 0xE7, 0x62, 0xE0, 0x0D, 0x09, 0xBD, 0xA3, 0x74, 0xF3, 0xAE, 0x2C, 0xBE, 0xDE, 0x28, 0x38, 0xFF, 0x89, 0xD8, 0x1D, 0xEB, 0x30, 0x13, 0x09, 0x0E, 0x44, 0x19, 0x9A, 0xED, 0x60, 0x49, 0x63, 0xEA, 0xF9, 0x19, 0x91, 0x4C, 0xE0, 0x4F, 0x20, 0x7A, 0xC8, 0x2C, 0xD4, 0x35, 0x1F, 0xEF, 0x7B, 0x2D, 0x94, 0x39, 0x30, 0x66, 0xFE, 0x4D, 0x44, 0xE3, 0xCC, 0x59, 0x52, 0xE7, 0x5E, 0xB6, 0xF3, 0x71, 0x40, 0x58, 0x91, 0x5D, 0xE0, 0xEE, 0x18, 0x4D, 0x8C, 0x55, 0x30, 0x0F, 0x57, 0x6A, 0x8B, 0x82, 0xA8, 0x63, 0xE8, 0x1A, 0xF3, 0x34, 0x17, 0xBD, 0x4C, 0xFC, 0x94, 0xE7, 0xA6, 0x12, 0x63, 0xB3, 0x9F, 0x01, 0xF6, 0xE2, 0xE7, 0x07, 0x48, 0xB6, 0xE5, 0xE5, 0x9C, 0xF6, 0xCA, 0x01, 0xB0, 0x02, 0x8C, 0x93, 0xBB, 0xBC, 0xEB, 0xC5, 0x48, 0xF9, 0x87, 0xF1, 0x07, 0x55, 0xBF, 0x33, 0xCA, 0x58, 0x5C, 0xB4, 0x1C, 0xF5, 0x78, 0xDF, 0x5F, 0xFE, 0x37, 0x92, 0x4E, 0x3C, 0x2C, 0x07, 0x2E, 0xD1, 0xDA, 0xC9, 0x16, 0x21, 0x76, 0x97, 0x29, 0x71, 0xE7, 0x9B, 0x62, 0xFB, 0x20, 0x8F, 0x1A, 0x73, 0xBF, 0x03, 0x61, 0xE2, 0x99, 0x3D, 0xCC, 0xCD, 0x31, 0x10, 0xC3, 0x4D, 0x83, 0x9D, 0x18, 0xDD, 0x43, 0xA5, 0xE8, 0xF0, 0xD9, 0x41, 0xE9, 0x9A, 0xDC, 0xF4, 0x41, 0x40, 0x5F, 0x32, 0x10, 0x76, 0x71, 0xB2, 0xD8, 0xB2, 0x24, 0x4F, 0x7B, 0xA9, 0x2D, 0xCE, 0xD5, 0x87, 0xA2, 0x10, 0xFE, 0x8F, 0xF4, 0x3C, 0x61, 0x6A, 0xCB, 0x5E, 0x76, 0x6E, 0x6A, 0xF2, 0xCE, 0xB0, 0x35, 0x99, 0xBA, 0x3D, 0xE3, 0x76, 0xEB, 0x57, 0x35, 0xEF, 0x16, 0x14, 0x39, 0x53, 0xD1, 0xFD, 0xDB, 0x7E, 0x9F, 0x28, 0x74, 0xB0, 0xD6, 0x08, 0x3D, 0xD7, 0xEC, 0x43, 0x86, 0xAE, 0x00, 0x3F, 0x51, 0xCC, 0xF2, 0xD2, 0x1E, 0xF6, 0x05, 0x91, 0x63, 0xC5, 0x15, 0x21, 0x74, 0x42, 0x3F, 0x57, 0x11, 0x9D, 0x0F, 0xCE, 0x62, 0x7D, 0x76, 0x3D, 0x81, 0xC1, 0x0A, 0xA1, 0x32, 0x9F, 0x74, 0xC8, 0xD4, 0x45, 0x43, 0x7B, 0xA6, 0x71, 0x8A, 0x33, 0xDB, 0x6E, 0x79, 0x37, 0x51, 0x72, 0xB2, 0xAE, 0x35, 0x91, 0x82, 0x19, 0x78, 0xD5, 0x20, 0x82, 0x4E, 0x2D, 0x2F, 0xF8, 0x98, 0xB7, 0xF4, 0xC8, 0x67, 0xFF, 0x46, 0x27, 0x22, 0xBC, 0x07, 0xEA, 0xDA, 0xD3, 0x89, 0xA9, 0x10, 0xB6, 0xF6, 0x54, 0x29, 0xDA, 0x12, 0x97, 0x35, 0xFE, 0x04, 0x9E, 0x3E, 0xCB, 0x38, 0x89, 0xF6, 0x04, 0x7C, 0xF2, 0xBD, 0x2A, 0x88, 0xD5, 0x0A, 0x65, 0x1B, 0x32, 0x35, 0xD2, 0x48, 0x0E, 0x1D, 0xA5, 0xA3, 0x52, 0x47, 0xFA, 0x76, 0xC8, 0x31, 0x73, 0x63, 0x99, 0xD3, 0x7E, 0x8D, 0x03, 0x3C, 0x1D, 0x05, 0x1C, 0x9B, 0x6A, 0x99, 0xAB, 0x80, 0xB1, 0x31, 0x3F, 0xA2, 0x4C, 0x5C, 0x59, 0x76, 0x6E, 0x6C, 0x51, 0xA3, 0x8F, 0xE9, 0xF1, 0x18, 0x6A, 0x76, 0x7E, 0xEB, 0xD0, 0xD8, 0x80, 0x01, 0xAE, 0x02, 0x46, 0xCD, 0x4E, 0xBE, 0x2C, 0x97, 0x9D, 0xE8, 0x2C, 0x30, 0xBB, 0xDB, 0x98, 0xB4, 0x74, 0x4F, 0x11, 0xF9, 0xE6, 0x39, 0xED, 0xDD, 0x8C, 0x19, 0x4D, 0x79, 0x11, 0x20, 0x1A, 0x8F, 0xA7, 0x45, 0x99, 0x1B, 0x4D, 0x8A, 0x57, 0x09, 0xB6, 0x2A, 0x21, 0xB6, 0x3B, 0x97, 0x62, 0x91, 0x3D, 0x36, 0xCE, 0x99, 0x5C, 0x2D, 0x6B, 0x79, 0x15, 0x1E, 0x8D, 0x83, 0x83, 0x8C, 0xD1, 0xF3, 0x88, 0x40, 0xA9, 0x41, 0x72, 0x55, 0xDD, 0x16, 0x6B, 0x7A, 0x35, 0x84, 0x49, 0x90, 0x03, 0xFB, 0x62, 0x56, 0x11, 0x40, 0x4C, 0x95, 0xB9, 0x60, 0xDF, 0x0D, 0xB1, 0xBC, 0xF1, 0x57, 0x4B, 0x09, 0x65, 0xDB, 0xD8, 0x34, 0xEE, 0x14, 0x81, 0x17, 0xD5, 0xE0, 0x5A, 0x7C, 0xC7, 0xCC, 0x1A, 0x86, 0x56, 0x18, 0xA2, 0xBE, 0x48, 0x54, 0xDB, 0x89, 0x35, 0xCD, 0xA1, 0xE6, 0x8B, 0xD8, 0xD0, 0x9E, 0x72, 0xF0, 0xAC, 0x90, 0x53, 0xC8, 0x82, 0xC4, 0xAB, 0xA4, 0x00, 0x4A, 0x61, 0x4D, 0x10, 0x50, 0x53, 0x00, 0xB6, 0x17, 0x6C, 0xA1, 0xF3, 0x24, 0xE2, 0x2E, 0x78, 0x24, 0x29, 0x9F, 0x9C, 0x40, 0x75, 0x5B, 0x71, 0xD8, 0x2B, 0x67, 0x95, 0x47, 0xF0, 0x6A, 0xD4, 0x8B, 0xE6, 0x6D, 0x68, 0x07, 0x2C, 0x93, 0x90, 0x23, 0x3C, 0x93, 0x3F, 0x80, 0xA1, 0x4F, 0x8D, 0x4A, 0x6B, 0x0B, 0x4E, 0x19, 0x70, 0xE1, 0xAC, 0xC1, 0xBE, 0xA7, 0xF5, 0xD3, 0xBE, 0x22, 0x44, 0x48, 0xF8, 0x57, 0xBA, 0xB6, 0x8A, 0xEF, 0xA6, 0xD8, 0xCB, 0x81, 0x9B, 0x64, 0x29, 0x4A, 0x12, 0x99, 0x79, 0x16, 0xCD, 0xBF, 0x56, 0xE9, 0xA8, 0xD0, 0x02, 0xDD, 0x06, 0x5F, 0x12, 0xC6, 0x18, 0x23, 0xF4, 0xFC, 0x21, 0x45, 0x08, 0x23, 0x2E, 0x43, 0x1F, 0x0B, 0x68, 0x98, 0x47, 0x5B, 0xB5, 0xDD, 0x0D, 0x7D, 0x52, 0x8E, 0x84, 0x0C, 0x22, 0x80, 0x9A, 0xF7, 0xE1, 0x53, 0x63, 0x72, 0x4A, 0x61, 0x3A, 0xCC, 0xFB, 0xE2, 0xB3, 0x74, 0x38, 0xC1, 0x59, 0xCE, 0x14, 0xCB, 0x0C, 0x98, 0xBF, 0xD4, 0x99, 0xC0, 0x8D, 0xAC, 0x0C, 0xF4, 0x5D, 0x82, 0x1C, 0xC2, 0xFA, 0x47, 0x31, 0x9B, 0x6F, 0xB4, 0xCE, 0xD7, 0xE5, 0x98, 0x5E, 0xC8, 0x27, 0x4D, 0xE0, 0x90, 0x71, 0xD3, 0xC1, 0x0D, 0xA5, 0xBF, 0x9E, 0x52, 0x2B, 0x01, 0xCE, 0x91, 0xD6, 0x6B, 0x91, 0x79, 0x5D, 0x3D, 0x22, 0xC0, 0x04, 0x83, 0x45, 0x42, 0x75, 0xDD, 0x2B, 0xBD, 0xD7, 0xC2, 0xDC, 0xC4, 0xA1, 0x67, 0xE5, 0xD7, 0xFC, 0xDB, 0xB9, 0xF6, 0x20, 0x8C, 0xD4, 0xC9, 0xA4, 0x85, 0xFA, 0xAE, 0xB8, 0x09, 0xA7, 0x71, 0x1D, 0xAC, 0x28, 0x65, 0xCE, 0xD4, 0x30, 0x64, 0x74, 0xB2, 0x2B, 0x44, 0x48, 0xF8, 0x5D, 0xF3, 0x34, 0x17, 0xF3, 0xFA, 0xCE, 0x1C, 0x05, 0xD4, 0x27, 0x03, 0xED, 0x31, 0x30, 0x42, 0xA0, 0x5D, 0xE0, 0x36, 0x27, 0x40, 0x13, 0x01, 0x88, 0xEC, 0xB4, 0x45, 0xBB, 0x25, 0x5D, 0xC7, 0x6E, 0xE8, 0x44, 0x3F, 0x73, 0x31, 0x17, 0xF8, 0x35, 0x1F, 0x17, 0x60, 0x31, 0x75, 0x55, 0x4F, 0xEB, 0x00, 0xB7, 0xFF, 0x54, 0xD8, 0x07, 0x86, 0xF3, 0x05, 0xCD, 0xE1, 0x8C, 0xD5, 0xEC, 0x56, 0xEC, 0x09, 0x62, 0xA3, 0xE0, 0x44, 0x82, 0xDC, 0xE3, 0x62, 0x2D, 0x04, 0x0D, 0x24, 0xC4, 0x0F, 0x2E, 0x8A, 0x14, 0xA4, 0x47, 0x65, 0x9D, 0x6C, 0x56, 0x1F, 0x2F, 0xFE, 0xE6, 0x8F, 0x8D, 0x3D, 0xE5, 0x11, 0xB2, 0x3E, 0x8B, 0x17, 0x2A, 0x01, 0xA3, 0xED, 0xA4, 0xD3, 0x78, 0x0E, 0x74, 0xC6, 0x77, 0x24, 0x43, 0x30, 0xE9, 0xAE, 0xFF, 0x01, 0x9F, 0xE0, 0x7B, 0xE3, 0xD3, 0x3F, 0x32, 0x2F, 0x9C, 0xE2, 0x21, 0x4B, 0x9D, 0x9C, 0xFF, 0x99, 0xD0, 0x5A, 0x59, 0xE4, 0x75, 0x51, 0x43, 0x2A, 0xE7, 0x6F, 0x4C, 0xD4, 0xF8, 0xDD, 0x51, 0x52, 0x0F, 0xFE, 0x81, 0x1B, 0x4B, 0x93, 0xCD, 0x62, 0x19, 0xC8, 0x1B, 0x63, 0xB1, 0xD6, 0x27, 0x78, 0x5C, 0x2A, 0x0F, 0xC2, 0x2E, 0x3A, 0xEA, 0x86, 0xCE, 0xEE, 0x1F, 0x7F, 0xBC, 0x4E, 0xFC, 0xB4, 0x6D, 0xDF, 0xBC, 0xD8, 0x8A, 0x02, 0xF3, 0xB4, 0xE6, 0x7C, 0x5F, 0xF2, 0xE8, 0xDC, 0x68, 0xBF, 0x16, 0xC7, 0x46, 0x99, 0xBB, 0xB6, 0x28, 0x90, 0x2F, 0x72, 0xC3, 0xDE, 0xBC, 0x8B, 0xF5, 0xDF, 0x70, 0x6D, 0x47, 0xA6, 0x05, 0xA1, 0x07, 0xDA, 0xA0, 0x01, 0x41, 0x39, 0xCE, 0x40, 0xF0, 0xD4, 0x6D, 0x8D, 0x6D, 0xC7, }, .spki_len = 1990, .spki = { 0x30, 0x82, 0x07, 0xC2, 0x30, 0x0F, 0x06, 0x0B, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x02, 0x82, 0x0B, 0x07, 0x06, 0x05, 0x05, 0x00, 0x03, 0x82, 0x07, 0xAD, 0x00, 0x30, 0x82, 0x07, 0xA8, 0x03, 0x21, 0x00, 0x1C, 0x0E, 0xE1, 0x11, 0x1B, 0x08, 0x00, 0x3F, 0x28, 0xE6, 0x5E, 0x8B, 0x3B, 0xDE, 0xB0, 0x37, 0xCF, 0x8F, 0x22, 0x1D, 0xFC, 0xDA, 0xF5, 0x95, 0x0E, 0xDB, 0x38, 0xD5, 0x06, 0xD8, 0x5B, 0xEF, 0x03, 0x82, 0x07, 0x81, 0x00, 0xD9, 0xFD, 0xE3, 0xA4, 0x96, 0xF7, 0x58, 0x19, 0xF0, 0xA2, 0x0D, 0x04, 0x41, 0xDC, 0x78, 0x30, 0xB4, 0xAA, 0x1C, 0xB8, 0xEC, 0xFC, 0x91, 0xBA, 0x0E, 0xEC, 0x3A, 0xFB, 0x67, 0x44, 0xE4, 0x77, 0xB4, 0xE6, 0xEC, 0x3F, 0xDA, 0xE7, 0x50, 0x48, 0xFF, 0xEB, 0xAA, 0xBE, 0xA8, 0xE8, 0x22, 0x11, 0x7D, 0x57, 0x87, 0xF7, 0x90, 0x70, 0xEA, 0x88, 0x28, 0x7C, 0xE3, 0xCD, 0x50, 0x11, 0xFD, 0x8D, 0x93, 0xAB, 0x7E, 0x8B, 0x51, 0xF2, 0x61, 0x16, 0xBF, 0x9B, 0x6D, 0x21, 0xC0, 0x3F, 0x88, 0xBF, 0xEC, 0x48, 0x88, 0x76, 0xF4, 0xD0, 0x75, 0xA1, 0x42, 0xD4, 0xE7, 0x84, 0xD7, 0x34, 0x40, 0x75, 0x11, 0xF9, 0x92, 0x06, 0x93, 0x53, 0xF1, 0xDB, 0x67, 0xAC, 0xF7, 0x30, 0x34, 0xA4, 0x68, 0xA1, 0x18, 0x58, 0x80, 0x62, 0x11, 0x1D, 0x32, 0x0E, 0x00, 0xBC, 0xFF, 0x6D, 0xC6, 0x35, 0x73, 0xFC, 0xED, 0x1E, 0x96, 0xAA, 0xEB, 0xA6, 0x45, 0x2E, 0x3C, 0x7A, 0xCD, 0x19, 0x18, 0x1F, 0x9B, 0x81, 0x4B, 0xA1, 0x9D, 0x39, 0xB4, 0xBA, 0xB5, 0x49, 0x6D, 0xC0, 0x55, 0x42, 0x6E, 0x7E, 0xA4, 0x61, 0xAF, 0x55, 0xD5, 0xB9, 0xFE, 0x97, 0xF9, 0xDF, 0x7E, 0x25, 0x32, 0x03, 0xC1, 0xF9, 0xE1, 0x52, 0xE9, 0x6D, 0x75, 0xF9, 0xD9, 0xA8, 0x4F, 0x5C, 0x26, 0x3E, 0xC8, 0xC2, 0x50, 0x44, 0x0A, 0xDC, 0x98, 0x6F, 0x4E, 0x36, 0x41, 0x4C, 0x70, 0x3B, 0x3E, 0x05, 0x42, 0x6B, 0x28, 0xB7, 0x06, 0x59, 0x50, 0xDA, 0x6D, 0x0E, 0x0B, 0x2C, 0x60, 0xAC, 0x36, 0x72, 0xDB, 0x6F, 0x3C, 0x78, 0x44, 0x7D, 0xB7, 0xC2, 0x09, 0x15, 0x77, 0x0E, 0xA6, 0xFC, 0xE8, 0x1D, 0xAB, 0x53, 0x39, 0xC1, 0xD5, 0xAF, 0x82, 0xA5, 0xD3, 0x32, 0x40, 0x99, 0xDF, 0x56, 0x51, 0x6A, 0x07, 0xDB, 0x7C, 0x0F, 0xC6, 0x43, 0x83, 0x80, 0x5C, 0x65, 0xF2, 0xB0, 0x2F, 0xBC, 0xFC, 0xE6, 0x3E, 0x93, 0xC4, 0xBF, 0x09, 0x40, 0x9F, 0x9F, 0x0F, 0x77, 0xE7, 0x3D, 0xA3, 0xB0, 0x01, 0x9F, 0x20, 0x57, 0xE4, 0xCD, 0x7C, 0xFF, 0x0E, 0x57, 0x45, 0xEF, 0x18, 0xC3, 0xFD, 0x76, 0x6E, 0x01, 0x74, 0x7A, 0x64, 0xD4, 0x15, 0xFC, 0x97, 0x89, 0xAB, 0xFA, 0x62, 0x28, 0x4E, 0x11, 0xC7, 0xFF, 0x05, 0xD0, 0x54, 0x8D, 0x97, 0x3F, 0x67, 0x95, 0x59, 0xA6, 0xA3, 0xAA, 0xD7, 0x7E, 0xD5, 0x13, 0x2D, 0x01, 0x50, 0xC0, 0x14, 0xC3, 0xEC, 0x3A, 0x39, 0x5F, 0x01, 0x7E, 0x7A, 0xCF, 0xE3, 0xEA, 0xBF, 0xCA, 0x44, 0x91, 0x0C, 0xA0, 0x6F, 0xF3, 0x35, 0x42, 0xEC, 0xCE, 0x62, 0x41, 0x97, 0x47, 0x42, 0x35, 0x7D, 0x37, 0xF5, 0xC2, 0x84, 0xBF, 0x0F, 0xE1, 0xA7, 0x4B, 0x50, 0xC0, 0x73, 0x55, 0x13, 0x72, 0x13, 0x3A, 0xF2, 0xDD, 0x41, 0xE2, 0x1B, 0xAF, 0xC9, 0xC5, 0x90, 0xEE, 0x6E, 0xBC, 0x4A, 0xCE, 0x73, 0x1E, 0xF5, 0x66, 0x15, 0x6C, 0xA0, 0x37, 0x55, 0xDC, 0x49, 0x3C, 0x13, 0x70, 0x28, 0xAF, 0x3B, 0x3D, 0xE5, 0xB0, 0x0B, 0xD6, 0xCB, 0x3D, 0x9A, 0x87, 0xD0, 0x15, 0x1F, 0x88, 0x7C, 0x67, 0x68, 0xBC, 0x6C, 0xA0, 0x2A, 0x94, 0xFB, 0x20, 0x86, 0x55, 0x1A, 0x0F, 0x89, 0xBA, 0x26, 0x15, 0x4E, 0x9D, 0x45, 0x06, 0xAD, 0x9F, 0xAF, 0x39, 0xF5, 0x72, 0x3E, 0x23, 0x4E, 0x06, 0xCF, 0xDE, 0xD6, 0x9D, 0x4E, 0xE4, 0x14, 0x6B, 0x73, 0xE5, 0xDC, 0x1E, 0x41, 0x52, 0xA2, 0xA3, 0x15, 0x9D, 0x73, 0xDB, 0xC8, 0x33, 0xD3, 0xD4, 0x17, 0xCD, 0x5C, 0xF7, 0xFB, 0x3D, 0xC7, 0x74, 0x5C, 0xEE, 0xD4, 0xDC, 0x0F, 0x5B, 0x1C, 0x6D, 0x6B, 0x69, 0xC1, 0x76, 0x41, 0x57, 0xEA, 0x43, 0xDF, 0x9D, 0xBB, 0x44, 0x2E, 0xFA, 0x39, 0xD1, 0xD0, 0x16, 0x2E, 0x87, 0xC2, 0xD3, 0x0C, 0x50, 0x12, 0xFD, 0x16, 0xD8, 0x69, 0xC8, 0xA1, 0xFC, 0xBB, 0x45, 0xED, 0xCC, 0x8E, 0x18, 0x13, 0xB2, 0xB1, 0x90, 0xA9, 0x61, 0xF9, 0xFC, 0x86, 0x59, 0x1D, 0x3A, 0xBC, 0x53, 0x88, 0xAF, 0x67, 0x8F, 0xF0, 0x3D, 0xA7, 0x8B, 0x7C, 0xC0, 0xF6, 0x18, 0x57, 0x21, 0xC0, 0xDF, 0x33, 0xCC, 0x90, 0x64, 0x35, 0x22, 0x5D, 0xF2, 0x61, 0x10, 0x02, 0xDF, 0x12, 0x0E, 0x83, 0x56, 0x65, 0x32, 0x29, 0x2D, 0xEA, 0x3D, 0x8A, 0xCD, 0x10, 0x9A, 0x0D, 0xFF, 0xAB, 0x3B, 0x0B, 0x43, 0x01, 0x27, 0x96, 0xDB, 0x5B, 0x50, 0x68, 0x3F, 0xB4, 0xC2, 0xD2, 0x50, 0xDA, 0xB7, 0x6A, 0xAE, 0x35, 0xA4, 0x8E, 0x8C, 0x8D, 0x4A, 0x5C, 0xC1, 0x54, 0x75, 0x97, 0x45, 0xF0, 0xA1, 0x23, 0x0F, 0x6C, 0xA9, 0xDD, 0x9C, 0x99, 0xE2, 0xF8, 0x0E, 0xDC, 0x83, 0x30, 0x4C, 0xE0, 0x1E, 0x98, 0xF6, 0xC9, 0x48, 0x95, 0x29, 0xA8, 0x22, 0xF9, 0x00, 0x33, 0xC2, 0x28, 0x31, 0x5E, 0xB2, 0xFC, 0xC8, 0xDB, 0xA3, 0x82, 0xED, 0x43, 0x01, 0xE0, 0x76, 0x07, 0xA5, 0xB0, 0x76, 0xC7, 0x25, 0xF1, 0x24, 0x99, 0x4F, 0x18, 0xA9, 0x97, 0xD2, 0xC5, 0xBB, 0xF9, 0xA3, 0x24, 0x60, 0x52, 0x65, 0x10, 0x8A, 0xCB, 0xF4, 0x61, 0x0F, 0xA1, 0xC3, 0x37, 0x44, 0x08, 0x85, 0x0A, 0x08, 0x64, 0xE2, 0xB6, 0x10, 0x17, 0xEB, 0xEC, 0x1F, 0xBA, 0xB8, 0x9D, 0xE3, 0xAB, 0x1B, 0x93, 0xCE, 0x49, 0x18, 0xB9, 0xE2, 0xC9, 0xE3, 0xFE, 0x45, 0x67, 0x58, 0x06, 0x2A, 0x9F, 0x88, 0x2B, 0x28, 0x33, 0x18, 0x27, 0x1F, 0x4B, 0x95, 0x52, 0xFC, 0xF3, 0x26, 0x24, 0xA9, 0xFD, 0xAA, 0x44, 0xC6, 0x5C, 0x60, 0xE2, 0xB3, 0x64, 0x8B, 0xEF, 0x1F, 0x17, 0xD0, 0xB7, 0xC7, 0x48, 0x69, 0xEE, 0x0B, 0x53, 0xC4, 0xA6, 0x2A, 0x24, 0x84, 0x5D, 0xCE, 0xA5, 0xBC, 0xBF, 0x93, 0xB9, 0x2E, 0x4C, 0x26, 0x64, 0x85, 0x84, 0xE3, 0x34, 0x79, 0x28, 0x2E, 0x6C, 0x8B, 0x1D, 0x8F, 0xE2, 0x11, 0x81, 0xBD, 0x9C, 0xF7, 0x5F, 0x8A, 0x96, 0x17, 0x24, 0xD4, 0xC4, 0x30, 0x97, 0x79, 0xF1, 0xF1, 0xB7, 0x75, 0xD2, 0x54, 0xF7, 0x0B, 0xD1, 0x76, 0x9C, 0xC7, 0xC0, 0xED, 0xD2, 0xA9, 0x5F, 0xE5, 0xC9, 0xD8, 0x4B, 0x16, 0xF7, 0xC5, 0x4D, 0x85, 0xCC, 0xE4, 0xC8, 0xA1, 0x82, 0x81, 0x08, 0x09, 0xED, 0x81, 0xE9, 0x7D, 0x07, 0x48, 0x84, 0xEE, 0xDF, 0x40, 0x1C, 0xCA, 0xCD, 0xAE, 0xAD, 0x82, 0xC1, 0x4D, 0x06, 0xB6, 0x8A, 0xEA, 0x6C, 0xE1, 0x4B, 0x86, 0x1B, 0x0C, 0xFD, 0x16, 0x09, 0x0C, 0xBB, 0xF4, 0x69, 0xC5, 0xE0, 0x84, 0x31, 0x4C, 0x0D, 0x8D, 0x39, 0x60, 0xEA, 0x06, 0xA3, 0x42, 0x6D, 0x8B, 0x3F, 0xE7, 0x62, 0xE0, 0x0D, 0x09, 0xBD, 0xA3, 0x74, 0xF3, 0xAE, 0x2C, 0xBE, 0xDE, 0x28, 0x38, 0xFF, 0x89, 0xD8, 0x1D, 0xEB, 0x30, 0x13, 0x09, 0x0E, 0x44, 0x19, 0x9A, 0xED, 0x60, 0x49, 0x63, 0xEA, 0xF9, 0x19, 0x91, 0x4C, 0xE0, 0x4F, 0x20, 0x7A, 0xC8, 0x2C, 0xD4, 0x35, 0x1F, 0xEF, 0x7B, 0x2D, 0x94, 0x39, 0x30, 0x66, 0xFE, 0x4D, 0x44, 0xE3, 0xCC, 0x59, 0x52, 0xE7, 0x5E, 0xB6, 0xF3, 0x71, 0x40, 0x58, 0x91, 0x5D, 0xE0, 0xEE, 0x18, 0x4D, 0x8C, 0x55, 0x30, 0x0F, 0x57, 0x6A, 0x8B, 0x82, 0xA8, 0x63, 0xE8, 0x1A, 0xF3, 0x34, 0x17, 0xBD, 0x4C, 0xFC, 0x94, 0xE7, 0xA6, 0x12, 0x63, 0xB3, 0x9F, 0x01, 0xF6, 0xE2, 0xE7, 0x07, 0x48, 0xB6, 0xE5, 0xE5, 0x9C, 0xF6, 0xCA, 0x01, 0xB0, 0x02, 0x8C, 0x93, 0xBB, 0xBC, 0xEB, 0xC5, 0x48, 0xF9, 0x87, 0xF1, 0x07, 0x55, 0xBF, 0x33, 0xCA, 0x58, 0x5C, 0xB4, 0x1C, 0xF5, 0x78, 0xDF, 0x5F, 0xFE, 0x37, 0x92, 0x4E, 0x3C, 0x2C, 0x07, 0x2E, 0xD1, 0xDA, 0xC9, 0x16, 0x21, 0x76, 0x97, 0x29, 0x71, 0xE7, 0x9B, 0x62, 0xFB, 0x20, 0x8F, 0x1A, 0x73, 0xBF, 0x03, 0x61, 0xE2, 0x99, 0x3D, 0xCC, 0xCD, 0x31, 0x10, 0xC3, 0x4D, 0x83, 0x9D, 0x18, 0xDD, 0x43, 0xA5, 0xE8, 0xF0, 0xD9, 0x41, 0xE9, 0x9A, 0xDC, 0xF4, 0x41, 0x40, 0x5F, 0x32, 0x10, 0x76, 0x71, 0xB2, 0xD8, 0xB2, 0x24, 0x4F, 0x7B, 0xA9, 0x2D, 0xCE, 0xD5, 0x87, 0xA2, 0x10, 0xFE, 0x8F, 0xF4, 0x3C, 0x61, 0x6A, 0xCB, 0x5E, 0x76, 0x6E, 0x6A, 0xF2, 0xCE, 0xB0, 0x35, 0x99, 0xBA, 0x3D, 0xE3, 0x76, 0xEB, 0x57, 0x35, 0xEF, 0x16, 0x14, 0x39, 0x53, 0xD1, 0xFD, 0xDB, 0x7E, 0x9F, 0x28, 0x74, 0xB0, 0xD6, 0x08, 0x3D, 0xD7, 0xEC, 0x43, 0x86, 0xAE, 0x00, 0x3F, 0x51, 0xCC, 0xF2, 0xD2, 0x1E, 0xF6, 0x05, 0x91, 0x63, 0xC5, 0x15, 0x21, 0x74, 0x42, 0x3F, 0x57, 0x11, 0x9D, 0x0F, 0xCE, 0x62, 0x7D, 0x76, 0x3D, 0x81, 0xC1, 0x0A, 0xA1, 0x32, 0x9F, 0x74, 0xC8, 0xD4, 0x45, 0x43, 0x7B, 0xA6, 0x71, 0x8A, 0x33, 0xDB, 0x6E, 0x79, 0x37, 0x51, 0x72, 0xB2, 0xAE, 0x35, 0x91, 0x82, 0x19, 0x78, 0xD5, 0x20, 0x82, 0x4E, 0x2D, 0x2F, 0xF8, 0x98, 0xB7, 0xF4, 0xC8, 0x67, 0xFF, 0x46, 0x27, 0x22, 0xBC, 0x07, 0xEA, 0xDA, 0xD3, 0x89, 0xA9, 0x10, 0xB6, 0xF6, 0x54, 0x29, 0xDA, 0x12, 0x97, 0x35, 0xFE, 0x04, 0x9E, 0x3E, 0xCB, 0x38, 0x89, 0xF6, 0x04, 0x7C, 0xF2, 0xBD, 0x2A, 0x88, 0xD5, 0x0A, 0x65, 0x1B, 0x32, 0x35, 0xD2, 0x48, 0x0E, 0x1D, 0xA5, 0xA3, 0x52, 0x47, 0xFA, 0x76, 0xC8, 0x31, 0x73, 0x63, 0x99, 0xD3, 0x7E, 0x8D, 0x03, 0x3C, 0x1D, 0x05, 0x1C, 0x9B, 0x6A, 0x99, 0xAB, 0x80, 0xB1, 0x31, 0x3F, 0xA2, 0x4C, 0x5C, 0x59, 0x76, 0x6E, 0x6C, 0x51, 0xA3, 0x8F, 0xE9, 0xF1, 0x18, 0x6A, 0x76, 0x7E, 0xEB, 0xD0, 0xD8, 0x80, 0x01, 0xAE, 0x02, 0x46, 0xCD, 0x4E, 0xBE, 0x2C, 0x97, 0x9D, 0xE8, 0x2C, 0x30, 0xBB, 0xDB, 0x98, 0xB4, 0x74, 0x4F, 0x11, 0xF9, 0xE6, 0x39, 0xED, 0xDD, 0x8C, 0x19, 0x4D, 0x79, 0x11, 0x20, 0x1A, 0x8F, 0xA7, 0x45, 0x99, 0x1B, 0x4D, 0x8A, 0x57, 0x09, 0xB6, 0x2A, 0x21, 0xB6, 0x3B, 0x97, 0x62, 0x91, 0x3D, 0x36, 0xCE, 0x99, 0x5C, 0x2D, 0x6B, 0x79, 0x15, 0x1E, 0x8D, 0x83, 0x83, 0x8C, 0xD1, 0xF3, 0x88, 0x40, 0xA9, 0x41, 0x72, 0x55, 0xDD, 0x16, 0x6B, 0x7A, 0x35, 0x84, 0x49, 0x90, 0x03, 0xFB, 0x62, 0x56, 0x11, 0x40, 0x4C, 0x95, 0xB9, 0x60, 0xDF, 0x0D, 0xB1, 0xBC, 0xF1, 0x57, 0x4B, 0x09, 0x65, 0xDB, 0xD8, 0x34, 0xEE, 0x14, 0x81, 0x17, 0xD5, 0xE0, 0x5A, 0x7C, 0xC7, 0xCC, 0x1A, 0x86, 0x56, 0x18, 0xA2, 0xBE, 0x48, 0x54, 0xDB, 0x89, 0x35, 0xCD, 0xA1, 0xE6, 0x8B, 0xD8, 0xD0, 0x9E, 0x72, 0xF0, 0xAC, 0x90, 0x53, 0xC8, 0x82, 0xC4, 0xAB, 0xA4, 0x00, 0x4A, 0x61, 0x4D, 0x10, 0x50, 0x53, 0x00, 0xB6, 0x17, 0x6C, 0xA1, 0xF3, 0x24, 0xE2, 0x2E, 0x78, 0x24, 0x29, 0x9F, 0x9C, 0x40, 0x75, 0x5B, 0x71, 0xD8, 0x2B, 0x67, 0x95, 0x47, 0xF0, 0x6A, 0xD4, 0x8B, 0xE6, 0x6D, 0x68, 0x07, 0x2C, 0x93, 0x90, 0x23, 0x3C, 0x93, 0x3F, 0x80, 0xA1, 0x4F, 0x8D, 0x4A, 0x6B, 0x0B, 0x4E, 0x19, 0x70, 0xE1, 0xAC, 0xC1, 0xBE, 0xA7, 0xF5, 0xD3, 0xBE, 0x22, 0x44, 0x48, 0xF8, 0x57, 0xBA, 0xB6, 0x8A, 0xEF, 0xA6, 0xD8, 0xCB, 0x81, 0x9B, 0x64, 0x29, 0x4A, 0x12, 0x99, 0x79, 0x16, 0xCD, 0xBF, 0x56, 0xE9, 0xA8, 0xD0, 0x02, 0xDD, 0x06, 0x5F, 0x12, 0xC6, 0x18, 0x23, 0xF4, 0xFC, 0x21, 0x45, 0x08, 0x23, 0x2E, 0x43, 0x1F, 0x0B, 0x68, 0x98, 0x47, 0x5B, 0xB5, 0xDD, 0x0D, 0x7D, 0x52, 0x8E, 0x84, 0x0C, 0x22, 0x80, 0x9A, 0xF7, 0xE1, 0x53, 0x63, 0x72, 0x4A, 0x61, 0x3A, 0xCC, 0xFB, 0xE2, 0xB3, 0x74, 0x38, 0xC1, 0x59, 0xCE, 0x14, 0xCB, 0x0C, 0x98, 0xBF, 0xD4, 0x99, 0xC0, 0x8D, 0xAC, 0x0C, 0xF4, 0x5D, 0x82, 0x1C, 0xC2, 0xFA, 0x47, 0x31, 0x9B, 0x6F, 0xB4, 0xCE, 0xD7, 0xE5, 0x98, 0x5E, 0xC8, 0x27, 0x4D, 0xE0, 0x90, 0x71, 0xD3, 0xC1, 0x0D, 0xA5, 0xBF, 0x9E, 0x52, 0x2B, 0x01, 0xCE, 0x91, 0xD6, 0x6B, 0x91, 0x79, 0x5D, 0x3D, 0x22, 0xC0, 0x04, 0x83, 0x45, 0x42, 0x75, 0xDD, 0x2B, 0xBD, 0xD7, 0xC2, 0xDC, 0xC4, 0xA1, 0x67, 0xE5, 0xD7, 0xFC, 0xDB, 0xB9, 0xF6, 0x20, 0x8C, 0xD4, 0xC9, 0xA4, 0x85, 0xFA, 0xAE, 0xB8, 0x09, 0xA7, 0x71, 0x1D, 0xAC, 0x28, 0x65, 0xCE, 0xD4, 0x30, 0x64, 0x74, 0xB2, 0x2B, 0x44, 0x48, 0xF8, 0x5D, 0xF3, 0x34, 0x17, 0xF3, 0xFA, 0xCE, 0x1C, 0x05, 0xD4, 0x27, 0x03, 0xED, 0x31, 0x30, 0x42, 0xA0, 0x5D, 0xE0, 0x36, 0x27, 0x40, 0x13, 0x01, 0x88, 0xEC, 0xB4, 0x45, 0xBB, 0x25, 0x5D, 0xC7, 0x6E, 0xE8, 0x44, 0x3F, 0x73, 0x31, 0x17, 0xF8, 0x35, 0x1F, 0x17, 0x60, 0x31, 0x75, 0x55, 0x4F, 0xEB, 0x00, 0xB7, 0xFF, 0x54, 0xD8, 0x07, 0x86, 0xF3, 0x05, 0xCD, 0xE1, 0x8C, 0xD5, 0xEC, 0x56, 0xEC, 0x09, 0x62, 0xA3, 0xE0, 0x44, 0x82, 0xDC, 0xE3, 0x62, 0x2D, 0x04, 0x0D, 0x24, 0xC4, 0x0F, 0x2E, 0x8A, 0x14, 0xA4, 0x47, 0x65, 0x9D, 0x6C, 0x56, 0x1F, 0x2F, 0xFE, 0xE6, 0x8F, 0x8D, 0x3D, 0xE5, 0x11, 0xB2, 0x3E, 0x8B, 0x17, 0x2A, 0x01, 0xA3, 0xED, 0xA4, 0xD3, 0x78, 0x0E, 0x74, 0xC6, 0x77, 0x24, 0x43, 0x30, 0xE9, 0xAE, 0xFF, 0x01, 0x9F, 0xE0, 0x7B, 0xE3, 0xD3, 0x3F, 0x32, 0x2F, 0x9C, 0xE2, 0x21, 0x4B, 0x9D, 0x9C, 0xFF, 0x99, 0xD0, 0x5A, 0x59, 0xE4, 0x75, 0x51, 0x43, 0x2A, 0xE7, 0x6F, 0x4C, 0xD4, 0xF8, 0xDD, 0x51, 0x52, 0x0F, 0xFE, 0x81, 0x1B, 0x4B, 0x93, 0xCD, 0x62, 0x19, 0xC8, 0x1B, 0x63, 0xB1, 0xD6, 0x27, 0x78, 0x5C, 0x2A, 0x0F, 0xC2, 0x2E, 0x3A, 0xEA, 0x86, 0xCE, 0xEE, 0x1F, 0x7F, 0xBC, 0x4E, 0xFC, 0xB4, 0x6D, 0xDF, 0xBC, 0xD8, 0x8A, 0x02, 0xF3, 0xB4, 0xE6, 0x7C, 0x5F, 0xF2, 0xE8, 0xDC, 0x68, 0xBF, 0x16, 0xC7, 0x46, 0x99, 0xBB, 0xB6, 0x28, 0x90, 0x2F, 0x72, 0xC3, 0xDE, 0xBC, 0x8B, 0xF5, 0xDF, 0x70, 0x6D, 0x47, 0xA6, 0x05, 0xA1, 0x07, 0xDA, 0xA0, 0x01, 0x41, 0x39, 0xCE, 0x40, 0xF0, 0xD4, 0x6D, 0x8D, 0x6D, 0xC7, }, .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 = 3293, .sig = { 0xB0, 0x55, 0xB0, 0xE1, 0x76, 0x10, 0xBF, 0x54, 0xB3, 0x3B, 0x96, 0x09, 0x8D, 0x79, 0x6E, 0x98, 0xF7, 0x89, 0x9F, 0x48, 0x56, 0xCB, 0xC8, 0xD7, 0x04, 0xF9, 0xD7, 0x77, 0x8C, 0x18, 0x77, 0xF1, 0xE1, 0x24, 0xBF, 0x62, 0xA0, 0xD1, 0x7F, 0x01, 0x3B, 0xE4, 0x34, 0x0F, 0xD5, 0x7B, 0x4F, 0xA6, 0x22, 0x2D, 0x9C, 0xDB, 0x90, 0x28, 0xE8, 0xB0, 0x2B, 0x92, 0x6E, 0x15, 0x54, 0xD1, 0x45, 0xF4, 0x47, 0x98, 0xAA, 0xC2, 0xFA, 0xA2, 0x03, 0x3C, 0x4A, 0xEF, 0xB6, 0xCC, 0xB6, 0xCF, 0xE5, 0xC2, 0xA6, 0x23, 0x8E, 0xE7, 0x9C, 0x5C, 0xC2, 0xF0, 0xE8, 0x04, 0xBE, 0xD1, 0x7F, 0x75, 0xC1, 0xF3, 0x99, 0x4D, 0xD7, 0xE7, 0xA0, 0xF2, 0xA7, 0x03, 0x4C, 0x0C, 0x8C, 0x98, 0x64, 0x80, 0x40, 0x57, 0xE2, 0xE5, 0x57, 0x67, 0x3F, 0xDF, 0xD6, 0x64, 0x35, 0x6F, 0xAB, 0xD0, 0x51, 0xF9, 0x07, 0x5B, 0x34, 0x00, 0xA0, 0xC7, 0xE8, 0x45, 0x59, 0x55, 0x3E, 0xDF, 0x98, 0x9B, 0xFF, 0xD2, 0x11, 0x2B, 0x29, 0x60, 0x22, 0x03, 0x06, 0x6B, 0xDE, 0xA7, 0x84, 0x35, 0xEB, 0xC6, 0xE3, 0x81, 0x8C, 0xC9, 0x2D, 0x61, 0xBC, 0xC1, 0x25, 0xA8, 0x57, 0x5B, 0x5A, 0x8A, 0xEE, 0x42, 0x25, 0xFB, 0x9C, 0x62, 0x48, 0x3F, 0x3E, 0xD1, 0x18, 0x5A, 0x6A, 0x96, 0x82, 0x2E, 0x5E, 0xFC, 0x1B, 0xA7, 0xCD, 0x8D, 0x5F, 0xD8, 0xCC, 0x18, 0x7D, 0x2A, 0x26, 0x69, 0xCA, 0xDF, 0x58, 0xFA, 0xD6, 0x62, 0x89, 0x79, 0x4C, 0x96, 0x48, 0x5B, 0x2C, 0x46, 0x45, 0xC7, 0xD3, 0xD3, 0x56, 0x84, 0xB7, 0x42, 0x9B, 0x5E, 0xF3, 0x15, 0x45, 0x76, 0x99, 0xBE, 0x80, 0x30, 0xBC, 0x3D, 0xEB, 0x81, 0x66, 0x60, 0x2A, 0xC5, 0x48, 0x19, 0x82, 0x48, 0x83, 0xA2, 0x46, 0xC8, 0xA1, 0xA3, 0x4F, 0xC8, 0x9B, 0x2F, 0xE0, 0x32, 0x9B, 0x5C, 0xA0, 0x5D, 0x4E, 0x14, 0xB6, 0xDF, 0xFC, 0x21, 0x44, 0x60, 0x6A, 0xB3, 0x60, 0xBB, 0x3B, 0x8A, 0xC5, 0xA1, 0x78, 0x99, 0x8B, 0x46, 0x21, 0x81, 0x81, 0xCA, 0xC8, 0xDE, 0x4C, 0x29, 0x48, 0x30, 0xD4, 0x9D, 0x8F, 0x00, 0xEC, 0x12, 0xC3, 0xD3, 0xAC, 0x7B, 0x4A, 0x2C, 0x30, 0x17, 0x58, 0xE6, 0x8A, 0x56, 0x81, 0x17, 0x7F, 0xF2, 0xA7, 0x5D, 0x1D, 0x4B, 0xF1, 0xC9, 0x26, 0x88, 0x0B, 0x34, 0xB7, 0x28, 0xF7, 0xC3, 0x2E, 0x40, 0x60, 0x99, 0xD9, 0x5A, 0xB4, 0x48, 0x92, 0xF7, 0x48, 0xAA, 0xFE, 0xB5, 0x5B, 0x26, 0xBE, 0x31, 0x75, 0x12, 0xB0, 0x37, 0x7D, 0xBE, 0x89, 0x1A, 0xC5, 0x45, 0x6A, 0x92, 0x4C, 0x36, 0x83, 0x9B, 0xC8, 0x01, 0xDB, 0x2A, 0xC5, 0xB7, 0x11, 0x0A, 0x9B, 0xAF, 0x4C, 0x3C, 0x49, 0xD0, 0x05, 0x39, 0x3C, 0xDF, 0xFA, 0xD4, 0xF9, 0x68, 0x61, 0x20, 0xF4, 0xFD, 0xE0, 0x16, 0x8A, 0x9E, 0x45, 0x8E, 0x72, 0x9F, 0x4B, 0x0A, 0xE1, 0xA4, 0xC4, 0x12, 0x4C, 0xA3, 0x4D, 0xF5, 0xB6, 0x3B, 0xC2, 0xE7, 0xCB, 0xEE, 0x01, 0xA3, 0x8D, 0x31, 0xA0, 0xED, 0x8D, 0x3C, 0x4C, 0x38, 0x03, 0xC3, 0xC2, 0x4C, 0x5C, 0xAD, 0xEB, 0xE3, 0xE9, 0x1A, 0x8D, 0x2E, 0x1B, 0xFC, 0xF0, 0x50, 0x8A, 0x27, 0x88, 0xD8, 0x9D, 0xFE, 0xA2, 0x0F, 0xD6, 0x38, 0x18, 0xB8, 0x39, 0x60, 0xA6, 0xCF, 0x93, 0x08, 0x72, 0xB9, 0x57, 0x85, 0x57, 0x50, 0x88, 0xCF, 0x7E, 0x8B, 0x63, 0xA1, 0x89, 0x5A, 0x8C, 0x1C, 0x77, 0xA8, 0x4C, 0xB9, 0xCC, 0x6B, 0xD1, 0xD5, 0xFA, 0x93, 0x96, 0x77, 0xAF, 0x17, 0xEE, 0xBE, 0x2D, 0x2E, 0xE6, 0x84, 0xC6, 0x60, 0x15, 0xF1, 0xBB, 0x14, 0x2A, 0x72, 0x77, 0x79, 0x58, 0x0D, 0xA1, 0xBC, 0x5E, 0x97, 0x5A, 0xA5, 0x6E, 0xF5, 0xD7, 0x7A, 0x84, 0x07, 0xE5, 0x06, 0xA5, 0xDE, 0xEE, 0xA5, 0xE8, 0xB0, 0x79, 0x7F, 0x10, 0x64, 0x60, 0x05, 0x64, 0x80, 0x22, 0x21, 0x3C, 0xCB, 0x86, 0xA7, 0x7D, 0xF5, 0xD7, 0xB3, 0x16, 0xE8, 0x5D, 0x55, 0xB9, 0xDA, 0x0F, 0xDF, 0xD5, 0xF2, 0x35, 0x52, 0xDD, 0x47, 0xCC, 0xFA, 0x96, 0x4A, 0xC3, 0x9E, 0xE6, 0x84, 0xBD, 0x63, 0x79, 0x3B, 0xB7, 0xDC, 0xAB, 0x69, 0xBE, 0x7E, 0xD9, 0x4D, 0x8D, 0xDB, 0xA1, 0x85, 0xE8, 0x0A, 0x7A, 0xAE, 0xE7, 0x4E, 0x87, 0x8F, 0x50, 0xA2, 0x13, 0xF3, 0xB4, 0xFF, 0xB6, 0x6E, 0x6D, 0x34, 0xA3, 0x9C, 0x0A, 0xAE, 0x2B, 0x1D, 0x61, 0x36, 0x6F, 0xE4, 0x03, 0x53, 0x9C, 0x69, 0xA0, 0x88, 0x75, 0x1F, 0x56, 0x90, 0x1A, 0x10, 0xBC, 0x44, 0x23, 0x13, 0xA3, 0x5C, 0x2D, 0x83, 0x54, 0x76, 0xD0, 0xFA, 0xD4, 0x47, 0xC7, 0x70, 0x08, 0x0F, 0xA4, 0x1B, 0xF3, 0x8D, 0x68, 0x5F, 0xB3, 0x1B, 0x11, 0xA7, 0xD2, 0xE6, 0xFB, 0x52, 0x67, 0x3D, 0x16, 0x87, 0x23, 0xE6, 0x89, 0x08, 0xC0, 0x67, 0x2A, 0x0F, 0x36, 0xE2, 0x5A, 0x19, 0x9E, 0x17, 0xA6, 0xFE, 0x5B, 0x8B, 0x82, 0x5B, 0x96, 0xEA, 0xB7, 0xAB, 0x4B, 0x7D, 0x83, 0x81, 0xDB, 0xC5, 0x00, 0x31, 0xA5, 0xF2, 0xE0, 0x9E, 0x4B, 0xE8, 0x71, 0x53, 0x3A, 0xDC, 0x5D, 0x08, 0xD0, 0x09, 0x42, 0x9B, 0xBF, 0x5C, 0x86, 0xF8, 0x12, 0x0D, 0x09, 0x5C, 0x8E, 0xEC, 0xBE, 0xF3, 0xE0, 0x99, 0xDE, 0x61, 0x8D, 0x43, 0x77, 0x24, 0x1B, 0x50, 0x36, 0x9E, 0xDE, 0x51, 0xAA, 0x74, 0xAB, 0x96, 0x65, 0x89, 0xE2, 0xC6, 0x87, 0xD6, 0xC0, 0x9F, 0xAC, 0x9C, 0x6D, 0x6C, 0x54, 0x61, 0xF5, 0xA6, 0x30, 0x08, 0xE9, 0x83, 0x5F, 0xF4, 0xB5, 0xBD, 0x42, 0x65, 0xF1, 0x12, 0x8C, 0x09, 0x2C, 0x27, 0xD4, 0xDA, 0x50, 0x8F, 0xD4, 0xF5, 0x0E, 0xFA, 0x74, 0xA7, 0x31, 0x57, 0x05, 0x9A, 0x4B, 0x2F, 0x41, 0xFE, 0x8B, 0xF9, 0x67, 0x16, 0x79, 0x69, 0xB9, 0x3B, 0xF5, 0x20, 0x45, 0x84, 0x26, 0x90, 0x32, 0x42, 0x9E, 0x35, 0x77, 0x70, 0x4B, 0xDF, 0x68, 0x98, 0x00, 0xDD, 0x8B, 0xDE, 0x82, 0x6B, 0x74, 0xCE, 0xF5, 0x10, 0xA1, 0xE0, 0x87, 0x02, 0x3F, 0x09, 0x26, 0xE9, 0x7F, 0x37, 0x92, 0x6B, 0x16, 0xEF, 0x78, 0x6C, 0x37, 0xEC, 0x21, 0xF2, 0x40, 0x71, 0x04, 0xD3, 0x95, 0x4A, 0x7A, 0x07, 0xC3, 0x0D, 0xE2, 0xD6, 0x78, 0x84, 0x02, 0xD7, 0x1A, 0x56, 0x2E, 0xA5, 0x4C, 0x79, 0xB4, 0x19, 0x7D, 0x20, 0x2C, 0x97, 0x72, 0x5D, 0x2D, 0x8B, 0x7E, 0x73, 0x32, 0xF3, 0xFF, 0x1A, 0x6F, 0xAD, 0x49, 0xA4, 0xC0, 0x0C, 0xD1, 0xA4, 0x47, 0x65, 0x1B, 0x8E, 0x08, 0xD8, 0x50, 0x6B, 0xCA, 0x82, 0x3E, 0x10, 0xEF, 0x41, 0x16, 0xE6, 0xCF, 0x49, 0x67, 0x5C, 0x43, 0x30, 0xA1, 0xDE, 0x19, 0x08, 0xDD, 0xB5, 0x9F, 0x7E, 0xA5, 0xF8, 0x9C, 0x94, 0xCE, 0x50, 0x0F, 0x82, 0xB4, 0x3C, 0xE7, 0x89, 0x15, 0x84, 0x73, 0xB9, 0xE0, 0x79, 0x05, 0xD8, 0xE8, 0x61, 0x5E, 0xDE, 0xF0, 0x21, 0x38, 0x3F, 0xC3, 0x1D, 0x61, 0x8C, 0x5C, 0xE6, 0x25, 0x65, 0x3B, 0x40, 0xC2, 0x1B, 0xD7, 0xE0, 0xBC, 0x78, 0x3D, 0x93, 0xBE, 0xC1, 0xB7, 0xA5, 0xB4, 0xBB, 0xC6, 0xC2, 0x81, 0xB7, 0x77, 0x55, 0x47, 0x39, 0x0E, 0xF3, 0xD3, 0x0E, 0x27, 0x73, 0x99, 0x36, 0x93, 0x08, 0xD8, 0xA1, 0xCD, 0xC2, 0xE1, 0xDB, 0xD6, 0xF1, 0x58, 0x97, 0x0A, 0xC2, 0xAC, 0x5C, 0x2C, 0x94, 0x81, 0x97, 0x5B, 0x80, 0x95, 0x80, 0xC0, 0xEA, 0x89, 0x91, 0x2C, 0x07, 0x66, 0xF4, 0x58, 0x30, 0xA8, 0x96, 0x3F, 0xBB, 0x7E, 0x17, 0xD8, 0x43, 0x85, 0x17, 0x5A, 0x6E, 0x07, 0x54, 0x68, 0x3C, 0xBF, 0xBB, 0xA6, 0x36, 0x45, 0x94, 0xF6, 0xB5, 0x00, 0x5C, 0x15, 0xBD, 0x5F, 0x85, 0x73, 0x2B, 0x5A, 0x63, 0xF2, 0x62, 0x67, 0xAB, 0x17, 0x04, 0x8C, 0x61, 0x99, 0x20, 0x00, 0x19, 0xAD, 0xD6, 0xA4, 0xD1, 0xAC, 0xD0, 0x40, 0x5C, 0x38, 0x76, 0x66, 0xE8, 0x71, 0x11, 0xB9, 0x82, 0x5A, 0xFB, 0x97, 0x51, 0xCD, 0x3F, 0x9D, 0x8A, 0x45, 0xC6, 0xB2, 0x08, 0xD2, 0xD3, 0x33, 0xB6, 0xC5, 0x9F, 0x98, 0xBC, 0xF2, 0x84, 0xC8, 0x54, 0xCF, 0x7D, 0x4F, 0x67, 0x54, 0xFD, 0x75, 0xEE, 0x06, 0x8C, 0x88, 0x67, 0x8E, 0xE7, 0x56, 0x5B, 0x47, 0xB3, 0x6E, 0x68, 0xA1, 0xFD, 0x7B, 0xB6, 0x0E, 0x2A, 0x8E, 0x0D, 0xF7, 0x12, 0x70, 0x20, 0xF5, 0xC6, 0x27, 0x7B, 0x3E, 0xE0, 0x58, 0x77, 0x3F, 0x9B, 0xBF, 0x1D, 0xC2, 0xE3, 0x98, 0xBC, 0x30, 0x12, 0x02, 0x12, 0x1C, 0x69, 0x9C, 0x00, 0x37, 0x9D, 0x83, 0x50, 0x09, 0x96, 0x26, 0xF9, 0x09, 0x23, 0x65, 0x92, 0x40, 0x08, 0xB1, 0xA9, 0xCD, 0x9F, 0x87, 0x87, 0x82, 0x2B, 0xEE, 0x96, 0x1A, 0xBA, 0x23, 0x9C, 0xDC, 0xB4, 0x18, 0xE9, 0x38, 0x60, 0xEF, 0x34, 0x8A, 0x5E, 0x96, 0x45, 0x38, 0x9A, 0x0A, 0x87, 0x8D, 0x39, 0x4F, 0x36, 0x5A, 0xEB, 0xFE, 0x28, 0x0B, 0xEE, 0x68, 0x74, 0xA3, 0x05, 0x4C, 0xD9, 0x8C, 0xBD, 0x87, 0x16, 0x66, 0x28, 0x04, 0x72, 0x9F, 0xD4, 0x6F, 0xCE, 0xA9, 0xC4, 0xCF, 0x92, 0x9F, 0x2F, 0x12, 0x00, 0x06, 0xCE, 0xBC, 0xC0, 0xBF, 0x75, 0x69, 0x2D, 0x63, 0xC0, 0x44, 0x63, 0x5D, 0x1A, 0x1D, 0xB6, 0x1A, 0xD1, 0x78, 0x94, 0x15, 0xE5, 0xF2, 0x24, 0x2B, 0x74, 0x00, 0xA8, 0xA7, 0x93, 0x68, 0xED, 0x60, 0x2C, 0x33, 0x64, 0x92, 0xF2, 0x70, 0x34, 0x5B, 0xE9, 0x8B, 0x2D, 0xD6, 0xEA, 0x8E, 0x4C, 0x53, 0xAC, 0xA3, 0x6E, 0x3C, 0x9B, 0xA2, 0x88, 0xF2, 0x75, 0x86, 0x13, 0x4C, 0xF0, 0xB5, 0xCA, 0x9B, 0xA1, 0xEE, 0xDF, 0x20, 0xD1, 0xAB, 0x4F, 0x2D, 0x08, 0xF3, 0xB0, 0x42, 0xDB, 0x89, 0xDE, 0xCF, 0xFD, 0xD2, 0x38, 0x54, 0xF3, 0x51, 0x20, 0xAD, 0xDE, 0x16, 0x03, 0x33, 0x5D, 0x56, 0x8D, 0xA9, 0x58, 0x91, 0xCF, 0x3A, 0xB2, 0x1D, 0x9A, 0xFA, 0xF6, 0x6C, 0x28, 0x6C, 0x13, 0x00, 0x01, 0x9C, 0xA9, 0xBA, 0xF2, 0xFF, 0x3F, 0x67, 0x25, 0x23, 0x0C, 0x4B, 0x26, 0x98, 0x92, 0xF7, 0xA3, 0xDF, 0xD6, 0xEA, 0xB7, 0x4C, 0x31, 0x4A, 0x86, 0xF8, 0xB4, 0x7E, 0xAE, 0x49, 0xF4, 0x19, 0xE4, 0xA2, 0x91, 0x7B, 0x98, 0x4F, 0xE9, 0xA0, 0x03, 0x32, 0xAF, 0xB7, 0xA5, 0x6E, 0x5E, 0x67, 0x52, 0x23, 0xAE, 0xCC, 0x50, 0x34, 0x20, 0xAF, 0x8B, 0x39, 0xFA, 0xA9, 0x20, 0xE3, 0xAD, 0xA1, 0xA4, 0x3C, 0xE7, 0xBD, 0x1F, 0x7D, 0xF2, 0x30, 0x1C, 0x90, 0x27, 0xCC, 0x1C, 0xE5, 0x66, 0x6E, 0xB0, 0x93, 0x62, 0x10, 0xAF, 0xA5, 0x9E, 0x10, 0xF3, 0x07, 0xCA, 0x1F, 0x78, 0x63, 0xED, 0xD6, 0xC3, 0xBB, 0x8F, 0x5D, 0x63, 0xC0, 0xCF, 0x0E, 0xA8, 0xF0, 0x6E, 0xF0, 0x8C, 0xCC, 0x24, 0xC1, 0x4F, 0x29, 0x5D, 0xD2, 0x86, 0xFD, 0x9F, 0x4E, 0x71, 0x02, 0x10, 0x9D, 0x53, 0xFF, 0x5E, 0xFF, 0x4A, 0x01, 0xDC, 0xAA, 0xD5, 0xFB, 0x60, 0x55, 0xA0, 0x70, 0x3C, 0xD4, 0x71, 0xB2, 0x0B, 0x5F, 0xA4, 0x56, 0x0B, 0xDE, 0xAA, 0x13, 0x13, 0xC7, 0x64, 0x7A, 0xE7, 0x56, 0xAE, 0x85, 0x91, 0x57, 0x9E, 0xA5, 0x12, 0x0E, 0x09, 0xD6, 0x79, 0x48, 0x40, 0x62, 0x9B, 0x9F, 0xEF, 0xEF, 0xC2, 0x0D, 0xB5, 0x94, 0xBA, 0xDC, 0xD1, 0x29, 0xEC, 0x49, 0x1C, 0x3C, 0xF7, 0x5A, 0xB4, 0x0C, 0x47, 0x2A, 0xD2, 0x2C, 0x2D, 0xED, 0xBC, 0x77, 0xBA, 0x26, 0x71, 0xC8, 0x43, 0x48, 0x65, 0x60, 0xDC, 0x76, 0x52, 0x31, 0xBF, 0x5F, 0xDC, 0xDB, 0xCC, 0x77, 0xC8, 0x30, 0x0F, 0x9D, 0x2B, 0x53, 0xEC, 0x34, 0x46, 0xD8, 0x2F, 0x08, 0x7B, 0x89, 0xBD, 0x99, 0x2F, 0x7A, 0xB0, 0xA7, 0x80, 0xB5, 0x38, 0x81, 0x18, 0xBB, 0xF1, 0x7C, 0xCB, 0xEC, 0x2D, 0x19, 0x6F, 0x3E, 0xDC, 0x47, 0x8F, 0xB9, 0x47, 0xD8, 0x30, 0x2B, 0x04, 0x0A, 0x60, 0xD0, 0xBA, 0xB8, 0x5C, 0x1C, 0x5C, 0x47, 0x4E, 0xAB, 0x41, 0xE0, 0x64, 0x41, 0x06, 0x95, 0xC6, 0x0E, 0x1A, 0xCE, 0xE7, 0x9E, 0x13, 0x7D, 0x70, 0x2E, 0x4A, 0x31, 0x39, 0x68, 0xA5, 0x57, 0xB9, 0x7C, 0xE6, 0x43, 0x31, 0x88, 0x8B, 0x52, 0x89, 0xCC, 0xB3, 0x7A, 0x66, 0x25, 0xE5, 0x22, 0x73, 0x71, 0x1B, 0x84, 0x64, 0x58, 0xD5, 0xD8, 0xBA, 0x1A, 0xE4, 0x96, 0x53, 0x78, 0xCB, 0xE9, 0x18, 0xBF, 0x0F, 0x4B, 0xEE, 0xE1, 0xBD, 0x08, 0xFE, 0xCC, 0x66, 0x06, 0xD2, 0xF3, 0x97, 0x0C, 0x87, 0x4B, 0x0A, 0x09, 0xC4, 0x10, 0xE0, 0xC7, 0xD3, 0xD6, 0x00, 0x4D, 0x93, 0xF0, 0x6F, 0xBC, 0x25, 0x8F, 0x96, 0x4A, 0x96, 0x19, 0xB2, 0xC6, 0xCA, 0x28, 0xA3, 0xA2, 0x52, 0x9B, 0xF4, 0x4F, 0xB9, 0xF2, 0x44, 0x38, 0x2C, 0xBE, 0xF9, 0x93, 0xC4, 0x18, 0xA3, 0x88, 0x0F, 0x8D, 0x5F, 0xBA, 0x41, 0xF0, 0x58, 0x24, 0xF4, 0xF3, 0x3B, 0x24, 0xB8, 0x86, 0xD1, 0x15, 0xB8, 0x19, 0x81, 0x6C, 0x9B, 0x7D, 0xB5, 0x1F, 0x2A, 0xA0, 0xCC, 0x6B, 0x01, 0xB6, 0xAB, 0x21, 0x1F, 0xAD, 0x55, 0x28, 0x4C, 0xDC, 0x04, 0x52, 0x47, 0x85, 0x90, 0x59, 0xBD, 0x36, 0x88, 0x7F, 0x3A, 0xE2, 0xB6, 0xCF, 0x7F, 0x87, 0xEC, 0x2D, 0xF3, 0xC8, 0x9D, 0x43, 0xD2, 0x7E, 0x5E, 0x48, 0x88, 0xBA, 0xE6, 0x5B, 0x69, 0x24, 0xFA, 0x5D, 0xF0, 0xB2, 0xED, 0x44, 0xE3, 0xE3, 0x79, 0x4B, 0x68, 0x90, 0xF9, 0x33, 0xF9, 0xFB, 0xA7, 0xA7, 0x89, 0xFC, 0x63, 0xCE, 0xB7, 0x43, 0x60, 0xD4, 0xAC, 0x9C, 0x64, 0xF1, 0x0C, 0xFC, 0x0A, 0xB3, 0x74, 0xC7, 0x12, 0xA3, 0xCC, 0x6C, 0x87, 0x6B, 0x22, 0xF6, 0xD9, 0xFE, 0xF1, 0xC3, 0x87, 0xBF, 0x6B, 0xDE, 0x75, 0x79, 0x2A, 0xF9, 0x09, 0x4E, 0xC1, 0x7E, 0xB8, 0xB5, 0x5D, 0x35, 0x5F, 0xF0, 0xAE, 0x9D, 0x62, 0x11, 0x1A, 0xD8, 0xA3, 0xCB, 0xA4, 0xF5, 0x66, 0x3D, 0x94, 0xA3, 0x8A, 0x43, 0xE3, 0x52, 0x97, 0x9D, 0xB3, 0xDF, 0xDF, 0x32, 0x98, 0x85, 0x34, 0xCD, 0x45, 0xFD, 0x43, 0x6E, 0x69, 0x9C, 0x46, 0x7F, 0x6D, 0xDD, 0x50, 0x76, 0xB4, 0xE5, 0xF7, 0xF3, 0x82, 0xAF, 0x45, 0xD3, 0x17, 0x0F, 0x25, 0xB5, 0x41, 0x50, 0xD6, 0x4D, 0x35, 0xA8, 0x18, 0x55, 0xF4, 0xB2, 0x2B, 0xAC, 0x9F, 0xA1, 0x7D, 0xEF, 0xAD, 0x73, 0xB1, 0x4B, 0x15, 0x84, 0x0E, 0x08, 0x70, 0xDA, 0xF5, 0xB9, 0x2A, 0x30, 0xD2, 0x37, 0xBF, 0x0C, 0x08, 0xCB, 0x8C, 0x9E, 0xBD, 0x41, 0x59, 0xD3, 0xBB, 0x2D, 0x47, 0x4E, 0x3E, 0x10, 0x6C, 0xC4, 0x68, 0xE6, 0xA2, 0x43, 0x35, 0x12, 0x48, 0x10, 0xF4, 0x86, 0xA6, 0x47, 0x3C, 0x26, 0xA5, 0xD7, 0x83, 0x26, 0x4F, 0xD8, 0xA3, 0x68, 0x5C, 0x09, 0xD4, 0xEF, 0x77, 0xBD, 0x9A, 0x9A, 0x5C, 0x0B, 0x57, 0x8C, 0x95, 0xE7, 0xCA, 0xA3, 0x4E, 0xCE, 0x46, 0xF8, 0x48, 0x37, 0x47, 0xEE, 0x58, 0x4D, 0xBB, 0x2D, 0x97, 0x20, 0x76, 0xD7, 0x63, 0xB0, 0xB5, 0x50, 0xE2, 0xCA, 0xE8, 0x34, 0x9E, 0x06, 0x09, 0xF1, 0x4F, 0x0A, 0x8F, 0x51, 0x10, 0xCA, 0xA4, 0xCD, 0xAB, 0xDD, 0x44, 0x40, 0xAD, 0x16, 0x9C, 0x2A, 0xBE, 0x86, 0xEE, 0x1C, 0x68, 0x0D, 0x6E, 0x94, 0x88, 0x29, 0x64, 0xD8, 0x70, 0xCF, 0xEF, 0x70, 0xA4, 0xF4, 0xC0, 0x4B, 0x49, 0xCC, 0x4A, 0x4F, 0xF6, 0xD4, 0xB9, 0xE3, 0x69, 0x18, 0xC1, 0x8A, 0x6D, 0x5C, 0x4A, 0xF4, 0x7C, 0xCF, 0x09, 0xFF, 0x64, 0xC7, 0x7A, 0xE3, 0xBF, 0xBC, 0xFA, 0x50, 0x4E, 0x16, 0x9E, 0xAB, 0xB3, 0x06, 0x95, 0x1A, 0x28, 0xAF, 0xF2, 0xFA, 0xB7, 0xA5, 0xBA, 0x47, 0x6F, 0x56, 0x50, 0xBC, 0x7D, 0xA1, 0x92, 0xD4, 0xB0, 0xEB, 0xFA, 0xAB, 0xAB, 0xE7, 0x72, 0xED, 0xE2, 0xA1, 0x07, 0x1D, 0x5C, 0x4F, 0xC3, 0x3C, 0x25, 0x25, 0xE4, 0x0D, 0x08, 0x2F, 0xA9, 0x35, 0xBD, 0x32, 0xFF, 0x25, 0x06, 0xB3, 0xA1, 0x31, 0xE3, 0x15, 0x81, 0xB6, 0xC9, 0x44, 0xC2, 0x5F, 0x2D, 0x81, 0x75, 0x5C, 0x39, 0xD3, 0xBF, 0xC0, 0xC6, 0xDE, 0x93, 0xE3, 0x55, 0x57, 0xAB, 0x1C, 0xF3, 0x47, 0x2B, 0x4A, 0x32, 0x98, 0x09, 0x86, 0xA3, 0x1F, 0x88, 0x28, 0x73, 0x52, 0x19, 0x38, 0xD8, 0xBF, 0xFE, 0x97, 0x36, 0x9F, 0xE2, 0x97, 0x46, 0xAC, 0xFC, 0x8F, 0x12, 0xDE, 0xEE, 0x0E, 0x9A, 0xC3, 0xE1, 0x67, 0x60, 0x20, 0x22, 0x43, 0x43, 0x58, 0xF9, 0xDC, 0x33, 0xB2, 0xD4, 0x40, 0x8F, 0xD0, 0x89, 0x54, 0xF9, 0x74, 0x5A, 0x0B, 0xD6, 0x5B, 0xC7, 0x7E, 0xE8, 0xBE, 0xA7, 0x1B, 0xFA, 0x76, 0x40, 0xC1, 0x35, 0xED, 0x19, 0xCC, 0x2F, 0x1C, 0x22, 0xE0, 0xD6, 0xB0, 0x2D, 0xA6, 0xDF, 0x24, 0xDB, 0x05, 0xA6, 0x48, 0x0D, 0xB4, 0x52, 0x27, 0xDC, 0xC9, 0x7A, 0xDC, 0xEC, 0xB3, 0x91, 0x7F, 0x08, 0x6C, 0x6E, 0x98, 0x08, 0x3A, 0x21, 0x2D, 0x54, 0xDC, 0x4B, 0x81, 0x0F, 0x68, 0x9C, 0x4F, 0x98, 0x43, 0xD2, 0xFB, 0x9F, 0x57, 0x26, 0xB8, 0x76, 0x64, 0xCD, 0x32, 0x2C, 0x28, 0xB6, 0xF1, 0xE0, 0x1F, 0xA9, 0x1A, 0xB3, 0x50, 0x2F, 0xAC, 0x01, 0xAF, 0xCF, 0x52, 0xC9, 0xB3, 0xD2, 0xAA, 0x20, 0xE1, 0xB3, 0x85, 0xEF, 0x47, 0x0C, 0xB3, 0x30, 0x78, 0x19, 0x8B, 0x5C, 0x43, 0x95, 0xA0, 0x32, 0x9C, 0xB1, 0x0F, 0x9A, 0x4E, 0x96, 0xF4, 0x3E, 0x51, 0x16, 0x1F, 0xAA, 0xE1, 0x90, 0xEB, 0x8C, 0x39, 0x69, 0xCE, 0xC2, 0x97, 0x7B, 0x08, 0xF6, 0x8D, 0x24, 0xEF, 0xCE, 0x56, 0x65, 0x11, 0xFE, 0xB6, 0x54, 0xCC, 0x5F, 0xA1, 0xFE, 0x67, 0x57, 0x1F, 0x58, 0xD8, 0x48, 0xBE, 0x7C, 0x56, 0x4A, 0xF5, 0x66, 0x39, 0x06, 0x39, 0xF8, 0x16, 0x92, 0xA7, 0xB7, 0xC0, 0xF9, 0xF5, 0xAD, 0x85, 0xB8, 0x2F, 0x6A, 0x83, 0x2C, 0x9D, 0xA5, 0x2B, 0x6A, 0x47, 0xD2, 0x3F, 0x9E, 0xCF, 0xAD, 0x44, 0x99, 0x83, 0xC9, 0x39, 0x65, 0x46, 0x58, 0xB1, 0x0A, 0xDD, 0xC0, 0xB4, 0xAA, 0xDB, 0xB7, 0xB8, 0x5E, 0xA6, 0x02, 0xDA, 0x76, 0x17, 0xD1, 0xB4, 0xA4, 0x5D, 0x86, 0xB8, 0xD0, 0x9D, 0x2C, 0x5A, 0x40, 0x2A, 0x67, 0x58, 0xE0, 0x6A, 0xAA, 0x15, 0x4A, 0xD0, 0x96, 0x67, 0x8C, 0xBD, 0xD9, 0xCA, 0x6F, 0x5D, 0x92, 0xB0, 0xD7, 0x38, 0x50, 0x1E, 0x18, 0xC1, 0xDC, 0xD2, 0x68, 0xDE, 0x01, 0x12, 0x00, 0x59, 0x48, 0x2D, 0xFC, 0xD1, 0x2B, 0x9B, 0xF2, 0x6E, 0x1C, 0xF3, 0xB0, 0x99, 0x70, 0xC4, 0x3C, 0xF5, 0x62, 0x0C, 0xA8, 0xD4, 0xE2, 0xFD, 0x31, 0xE5, 0xA8, 0x9E, 0xF8, 0xDD, 0x93, 0x17, 0xE6, 0xCF, 0x55, 0xB3, 0xFB, 0x19, 0xC0, 0x72, 0xE9, 0xD5, 0xDD, 0xB9, 0x74, 0xEF, 0x60, 0x82, 0x71, 0x1E, 0x99, 0x15, 0xD3, 0x43, 0x4E, 0x7D, 0x34, 0xE7, 0xC3, 0x25, 0xA8, 0xD9, 0x2B, 0x66, 0xB0, 0x83, 0xDF, 0xD6, 0xCF, 0xD1, 0x62, 0xFD, 0x66, 0x65, 0xDF, 0x9A, 0xBF, 0x18, 0x8F, 0x2D, 0xC5, 0x83, 0xFD, 0xFA, 0xBC, 0x99, 0x7D, 0x78, 0x70, 0xE9, 0x11, 0xD3, 0xC5, 0xEB, 0x5B, 0xDF, 0x80, 0xBA, 0x8D, 0xE6, 0xC4, 0x6C, 0x88, 0xE0, 0x49, 0xD3, 0x9E, 0x2F, 0xA2, 0x96, 0xCB, 0xE0, 0x69, 0xCA, 0x69, 0x49, 0x4F, 0x89, 0x08, 0x87, 0x67, 0x9C, 0xB3, 0xB0, 0xE6, 0x04, 0x3D, 0x02, 0xB8, 0xF2, 0x4A, 0x3F, 0x14, 0x83, 0xC9, 0x47, 0x81, 0xB6, 0xB0, 0x1A, 0xF8, 0x01, 0x60, 0x63, 0x99, 0xC3, 0xAC, 0x62, 0x60, 0x3D, 0x86, 0xF7, 0xD5, 0x29, 0x55, 0xC3, 0x12, 0x59, 0x58, 0xC0, 0x4D, 0x57, 0x2A, 0x34, 0x63, 0x4C, 0xD2, 0x36, 0x73, 0x58, 0xA8, 0x6A, 0xD2, 0xB4, 0x81, 0xB3, 0x26, 0xF2, 0xF8, 0x9D, 0x4B, 0x4D, 0xC0, 0x94, 0xE9, 0x89, 0x18, 0xB5, 0xAE, 0xD8, 0xF4, 0xEB, 0xA4, 0x9C, 0x56, 0x17, 0x2B, 0x16, 0x51, 0xB6, 0x60, 0xB8, 0x70, 0x47, 0xBA, 0x65, 0x2A, 0x64, 0x0C, 0xA7, 0xB0, 0x69, 0x97, 0x1F, 0xA2, 0xA6, 0x6C, 0x01, 0x95, 0x67, 0xC3, 0x8B, 0x7F, 0x5D, 0x26, 0x21, 0xE7, 0xCB, 0x4B, 0xAA, 0x41, 0x40, 0xEF, 0x5B, 0xB4, 0x91, 0x96, 0x0D, 0x80, 0xF5, 0x01, 0x01, 0xA0, 0x04, 0xE0, 0x79, 0xF5, 0xB5, 0x1F, 0x39, 0x4B, 0x02, 0x9E, 0x3E, 0xBF, 0xBD, 0xFC, 0x33, 0x59, 0x4E, 0x95, 0xF6, 0xA3, 0x7B, 0xC4, 0xF6, 0xA3, 0x29, 0xB5, 0xC1, 0xD8, 0xE0, 0x41, 0x45, 0x40, 0x3D, 0x33, 0xA5, 0xC7, 0x04, 0xB3, 0x43, 0x51, 0x82, 0x31, 0xB0, 0x86, 0x46, 0xE4, 0xDA, 0x9D, 0x5A, 0x4E, 0xCA, 0xBC, 0xF5, 0x0F, 0x2B, 0x39, 0x21, 0xE8, 0x5A, 0x84, 0xC4, 0x09, 0xA1, 0xF6, 0x27, 0xEE, 0x0F, 0x6E, 0xB1, 0xB1, 0xB9, 0xA9, 0xFC, 0xCA, 0x9C, 0xBD, 0x65, 0xCE, 0xA9, 0x00, 0x88, 0x79, 0x7D, 0xF7, 0x51, 0x0B, 0x86, 0x1B, 0x86, 0xCA, 0x4E, 0x99, 0x8A, 0xF0, 0x75, 0x94, 0x9B, 0x16, 0x7C, 0xBD, 0x66, 0xBC, 0xBE, 0x4C, 0x51, 0x30, 0x34, 0x7D, 0x87, 0x7C, 0xE5, 0xA8, 0x47, 0x9F, 0x4D, 0x56, 0xD3, 0x98, 0x14, 0x6C, 0xE2, 0xF1, 0xA7, 0x85, 0x42, 0x8D, 0xDD, 0xED, 0xAD, 0x66, 0xAA, 0xB2, 0x87, 0xCA, 0xAE, 0x59, 0x14, 0x24, 0x35, 0x56, 0x1A, 0x40, 0x1B, 0x50, 0x93, 0x43, 0x92, 0xD4, 0x32, 0x9C, 0x3C, 0x21, 0xAE, 0x48, 0x32, 0x86, 0x53, 0xE3, 0xAE, 0x57, 0x5E, 0x18, 0x1D, 0xB3, 0x89, 0xBE, 0x43, 0x97, 0x16, 0xF6, 0xE3, 0xF3, 0xE2, 0xDC, 0x61, 0xE4, 0xEC, 0xCF, 0xE5, 0x48, 0xAB, 0x7D, 0x71, 0x5E, 0xAB, 0x49, 0xCF, 0xD7, 0x64, 0x1D, 0xC3, 0x7F, 0x5C, 0x0C, 0x0C, 0x34, 0x96, 0x5C, 0x06, 0xA1, 0x56, 0x70, 0x5F, 0x98, 0x69, 0x58, 0x79, 0x1A, 0x59, 0xCD, 0x5B, 0x48, 0x90, 0xD9, 0xA1, 0xB1, 0xCF, 0x08, 0x54, 0x1A, 0x7A, 0x93, 0xD0, 0x65, 0xDC, 0xF3, 0xB9, 0xF6, 0xC5, 0x13, 0xC0, 0x27, 0x94, 0x37, 0xD4, 0xBD, 0xBE, 0x62, 0x71, 0x40, 0xD2, 0x94, 0x63, 0x26, 0x39, 0xB7, 0x46, 0x89, 0x1C, 0xA9, 0x70, 0xDF, 0x6D, 0x73, 0x21, 0xF1, 0xA9, 0x13, 0xAD, 0x9B, 0xED, 0x3F, 0xE0, 0xBC, 0x02, 0xAF, 0xBB, 0x87, 0x20, 0xB7, 0x42, 0xEB, 0x40, 0x9E, 0xB8, 0x2C, 0x66, 0x96, 0x7F, 0x60, 0xEB, 0xF4, 0xCE, 0xE2, 0x50, 0x8E, 0xF7, 0xF7, 0x03, 0x5B, 0x7F, 0xC7, 0xD9, 0x17, 0x8E, 0x73, 0xED, 0xA0, 0x52, 0x9B, 0xCC, 0x9E, 0xB2, 0x0B, 0x9C, 0xD7, 0x74, 0xC5, 0x64, 0x88, 0x2D, 0xD5, 0x7C, 0xCF, 0xB5, 0x46, 0x63, 0xCF, 0xA8, 0x1B, 0x91, 0x4E, 0x14, 0xC4, 0xD7, 0xD7, 0x4B, 0xCE, 0x13, 0x9B, 0x7E, 0xC5, 0x3E, 0xA6, 0x1B, 0x0B, 0xF0, 0xDB, 0x61, 0xC7, 0x3A, 0x7A, 0x95, 0xF5, 0x96, 0xE1, 0x28, 0xEC, 0xA7, 0xA8, 0xC9, 0xEB, 0x92, 0xC2, 0x94, 0x4E, 0xF5, 0x64, 0x94, 0x3E, 0xDA, 0xCF, 0xD4, 0x8A, 0x5A, 0x8B, 0xDC, 0x7D, 0x0F, 0xAB, 0xFA, 0xB6, 0xDA, 0xD3, 0xC5, 0xFE, 0xEE, 0xB1, 0x39, 0x81, 0x8C, 0x85, 0x73, 0xA7, 0xBD, 0x75, 0x06, 0xB1, 0x8B, 0xFC, 0xE2, 0xBA, 0x15, 0x10, 0x5B, 0x7C, 0xEC, 0x83, 0x09, 0x6C, 0x8C, 0xAE, 0x99, 0xFB, 0xE5, 0xEA, 0x2C, 0x10, 0xF1, 0xBC, 0xF3, 0xF1, 0x58, 0x26, 0xA0, 0xD8, 0xEC, 0xA9, 0x7C, 0x42, 0xBB, 0x17, 0xCB, 0x9B, 0xED, 0x21, 0x9A, 0x8C, 0xDA, 0x9A, 0x57, 0x62, 0x85, 0x7E, 0xFB, 0xA4, 0x3B, 0x7F, 0x34, 0x15, 0x7A, 0xEB, 0x49, 0x2F, 0x81, 0xD2, 0xEA, 0x15, 0x6F, 0xF4, 0x99, 0x12, 0xA4, 0x04, 0x9B, 0xE9, 0x3E, 0x12, 0xA2, 0x26, 0x29, 0x5D, 0x8F, 0x68, 0x5C, 0x89, 0xBD, 0xA3, 0x83, 0x1E, 0xB7, 0x3B, 0xE4, 0x65, 0x7D, 0xBE, 0x3B, 0x09, 0xC0, 0x9D, 0x1D, 0xAF, 0x94, 0x4C, 0x26, 0x64, 0xE9, 0xBD, 0xE9, 0x17, 0x41, 0x98, 0xFE, 0x3D, 0xBA, 0xE4, 0xDE, 0x09, 0x45, 0x22, 0x9E, 0xDD, 0xF5, 0x96, 0x1B, 0x2F, 0x3D, 0x71, 0x9F, 0xAB, 0xAE, 0xB9, 0xBB, 0xD0, 0xD6, 0x3F, 0x6B, 0x74, 0xF1, 0x47, 0x70, 0x9C, 0xB2, 0xC5, 0xCD, 0xDD, 0x25, 0x35, 0x41, 0xA2, 0xD4, 0xDB, 0xFE, 0x2F, 0x61, 0x9F, 0xB6, 0xC0, 0xD8, 0x0D, 0x1D, 0x3D, 0x84, 0x93, 0x98, 0xBD, 0xF1, 0xFB, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x0F, 0x16, 0x1D, 0x23, 0x2D, }, }, { .name = "Dilithium Round 3, Level 3 (6-5) KAT 0", .version = 0, .keyform = CK_IBM_DILITHIUM_KEYFORM_ROUND3_65, .rho_len = 32, .rho = { 0x1C, 0x0E, 0xE1, 0x11, 0x1B, 0x08, 0x00, 0x3F, 0x28, 0xE6, 0x5E, 0x8B, 0x3B, 0xDE, 0xB0, 0x37, 0xCF, 0x8F, 0x22, 0x1D, 0xFC, 0xDA, 0xF5, 0x95, 0x0E, 0xDB, 0x38, 0xD5, 0x06, 0xD8, 0x5B, 0xEF, }, .seed_len = 32, .seed = { 0x39, 0x4D, 0x16, 0x95, 0x05, 0x9D, 0xFF, 0x40, 0xAE, 0x25, 0x6C, 0x5D, 0x5E, 0xDA, 0xBF, 0xB6, 0x9F, 0x5F, 0x40, 0xF3, 0x7A, 0x58, 0x8F, 0x50, 0x53, 0x2C, 0xA4, 0x08, 0xA8, 0x16, 0x8A, 0xB1, }, .tr_len = 32, .tr = { 0xE6, 0x4F, 0x14, 0x64, 0x27, 0x54, 0x3D, 0x8C, 0x36, 0xB3, 0xB6, 0x52, 0x26, 0x76, 0x9A, 0x22, 0x91, 0x1A, 0x5A, 0x31, 0x3E, 0xAC, 0x17, 0xC4, 0xAB, 0xA2, 0x52, 0x84, 0x51, 0x4F, 0xC6, 0x13, }, .s1_len = 640, .s1 = { 0x35, 0x78, 0x08, 0x33, 0x02, 0x23, 0x16, 0x43, 0x37, 0x65, 0x80, 0x75, 0x78, 0x71, 0x45, 0x24, 0x81, 0x01, 0x73, 0x15, 0x44, 0x83, 0x65, 0x26, 0x41, 0x33, 0x30, 0x22, 0x30, 0x26, 0x14, 0x73, 0x70, 0x52, 0x21, 0x07, 0x81, 0x26, 0x50, 0x61, 0x85, 0x85, 0x07, 0x75, 0x46, 0x18, 0x58, 0x05, 0x48, 0x53, 0x30, 0x18, 0x70, 0x66, 0x47, 0x51, 0x82, 0x67, 0x73, 0x77, 0x33, 0x50, 0x02, 0x70, 0x31, 0x28, 0x78, 0x82, 0x15, 0x80, 0x71, 0x40, 0x26, 0x73, 0x43, 0x20, 0x61, 0x62, 0x50, 0x61, 0x73, 0x71, 0x01, 0x03, 0x11, 0x45, 0x36, 0x81, 0x52, 0x30, 0x24, 0x65, 0x03, 0x48, 0x14, 0x37, 0x08, 0x37, 0x18, 0x25, 0x50, 0x84, 0x06, 0x08, 0x60, 0x17, 0x62, 0x58, 0x31, 0x31, 0x28, 0x27, 0x00, 0x17, 0x18, 0x48, 0x16, 0x67, 0x31, 0x78, 0x61, 0x07, 0x37, 0x23, 0x55, 0x74, 0x47, 0x15, 0x10, 0x10, 0x11, 0x21, 0x10, 0x66, 0x27, 0x42, 0x12, 0x08, 0x35, 0x46, 0x22, 0x85, 0x13, 0x13, 0x88, 0x16, 0x48, 0x86, 0x83, 0x35, 0x10, 0x47, 0x60, 0x26, 0x11, 0x83, 0x15, 0x74, 0x25, 0x00, 0x74, 0x24, 0x40, 0x64, 0x25, 0x15, 0x86, 0x13, 0x65, 0x61, 0x37, 0x77, 0x11, 0x84, 0x78, 0x05, 0x08, 0x62, 0x43, 0x70, 0x64, 0x06, 0x85, 0x27, 0x63, 0x11, 0x50, 0x13, 0x56, 0x23, 0x21, 0x68, 0x41, 0x41, 0x77, 0x24, 0x08, 0x48, 0x30, 0x87, 0x85, 0x75, 0x43, 0x85, 0x08, 0x63, 0x68, 0x54, 0x26, 0x84, 0x50, 0x56, 0x84, 0x37, 0x02, 0x40, 0x07, 0x16, 0x17, 0x84, 0x54, 0x38, 0x00, 0x61, 0x27, 0x05, 0x82, 0x62, 0x06, 0x76, 0x52, 0x11, 0x12, 0x14, 0x83, 0x88, 0x06, 0x78, 0x14, 0x75, 0x55, 0x02, 0x12, 0x22, 0x85, 0x52, 0x31, 0x08, 0x45, 0x03, 0x70, 0x13, 0x64, 0x31, 0x80, 0x05, 0x37, 0x68, 0x37, 0x65, 0x02, 0x46, 0x53, 0x15, 0x07, 0x60, 0x06, 0x25, 0x33, 0x12, 0x51, 0x20, 0x05, 0x41, 0x60, 0x63, 0x24, 0x23, 0x52, 0x41, 0x50, 0x77, 0x31, 0x45, 0x70, 0x33, 0x47, 0x65, 0x64, 0x31, 0x23, 0x18, 0x03, 0x33, 0x65, 0x16, 0x75, 0x87, 0x14, 0x13, 0x04, 0x11, 0x17, 0x15, 0x54, 0x68, 0x12, 0x60, 0x53, 0x73, 0x42, 0x38, 0x82, 0x43, 0x27, 0x83, 0x37, 0x12, 0x22, 0x81, 0x74, 0x81, 0x81, 0x20, 0x13, 0x63, 0x27, 0x64, 0x75, 0x10, 0x28, 0x03, 0x22, 0x68, 0x65, 0x08, 0x76, 0x55, 0x35, 0x63, 0x33, 0x81, 0x04, 0x47, 0x48, 0x58, 0x54, 0x30, 0x12, 0x43, 0x18, 0x08, 0x38, 0x64, 0x38, 0x53, 0x83, 0x08, 0x41, 0x27, 0x04, 0x64, 0x64, 0x63, 0x34, 0x64, 0x61, 0x06, 0x80, 0x70, 0x60, 0x23, 0x75, 0x51, 0x68, 0x25, 0x74, 0x11, 0x52, 0x88, 0x22, 0x01, 0x57, 0x78, 0x58, 0x33, 0x31, 0x34, 0x31, 0x55, 0x82, 0x84, 0x03, 0x16, 0x36, 0x01, 0x06, 0x48, 0x14, 0x80, 0x46, 0x43, 0x68, 0x46, 0x17, 0x57, 0x21, 0x36, 0x31, 0x65, 0x74, 0x65, 0x22, 0x15, 0x17, 0x71, 0x32, 0x05, 0x10, 0x66, 0x46, 0x83, 0x16, 0x46, 0x71, 0x47, 0x28, 0x31, 0x35, 0x55, 0x14, 0x73, 0x32, 0x81, 0x82, 0x60, 0x73, 0x15, 0x54, 0x36, 0x87, 0x08, 0x03, 0x28, 0x43, 0x26, 0x24, 0x16, 0x05, 0x32, 0x05, 0x20, 0x23, 0x67, 0x72, 0x58, 0x28, 0x18, 0x10, 0x85, 0x42, 0x67, 0x85, 0x15, 0x52, 0x80, 0x00, 0x72, 0x82, 0x27, 0x18, 0x31, 0x12, 0x08, 0x68, 0x37, 0x72, 0x44, 0x42, 0x05, 0x48, 0x64, 0x72, 0x05, 0x35, 0x08, 0x61, 0x73, 0x86, 0x27, 0x12, 0x46, 0x77, 0x51, 0x08, 0x52, 0x76, 0x33, 0x40, 0x37, 0x34, 0x32, 0x11, 0x54, 0x24, 0x06, 0x54, 0x02, 0x34, 0x50, 0x80, 0x04, 0x17, 0x72, 0x84, 0x62, 0x73, 0x61, 0x68, 0x68, 0x07, 0x81, 0x52, 0x46, 0x71, 0x06, 0x82, 0x55, 0x45, 0x81, 0x63, 0x62, 0x76, 0x41, 0x80, 0x57, 0x12, 0x44, 0x25, 0x57, 0x08, 0x04, 0x51, 0x06, 0x63, 0x61, 0x15, 0x85, 0x86, 0x30, 0x46, 0x52, 0x07, 0x05, 0x32, 0x75, 0x02, 0x18, 0x22, 0x42, 0x83, 0x71, 0x02, 0x38, 0x52, 0x75, 0x28, 0x44, 0x20, 0x33, 0x00, 0x17, 0x23, 0x11, 0x14, 0x02, 0x15, 0x76, 0x88, 0x38, 0x47, 0x62, 0x31, 0x85, 0x13, 0x52, 0x52, 0x10, 0x84, 0x38, 0x25, 0x55, 0x56, 0x74, 0x11, 0x44, 0x54, 0x67, 0x27, 0x85, 0x46, 0x58, 0x61, 0x70, 0x43, 0x07, 0x58, 0x80, 0x06, 0x84, 0x55, 0x13, 0x53, 0x47, 0x81, 0x38, 0x12, 0x08, 0x00, 0x84, 0x31, 0x56, 0x22, 0x14, 0x66, 0x03, 0x15, 0x60, 0x01, 0x63, 0x68, 0x56, 0x36, 0x73, 0x61, 0x80, 0x80, 0x04, 0x55, 0x54, }, .s2_len = 768, .s2 = { 0x33, 0x73, 0x12, 0x58, 0x40, 0x31, 0x14, 0x80, 0x42, 0x03, 0x67, 0x33, 0x01, 0x82, 0x71, 0x55, 0x60, 0x65, 0x60, 0x34, 0x40, 0x51, 0x44, 0x34, 0x55, 0x48, 0x51, 0x12, 0x23, 0x76, 0x45, 0x10, 0x64, 0x33, 0x73, 0x25, 0x38, 0x23, 0x38, 0x06, 0x24, 0x51, 0x61, 0x70, 0x81, 0x54, 0x11, 0x67, 0x17, 0x32, 0x00, 0x85, 0x32, 0x60, 0x40, 0x43, 0x71, 0x06, 0x80, 0x37, 0x37, 0x60, 0x70, 0x86, 0x40, 0x87, 0x00, 0x03, 0x52, 0x45, 0x71, 0x48, 0x26, 0x22, 0x03, 0x50, 0x53, 0x56, 0x66, 0x03, 0x72, 0x18, 0x01, 0x37, 0x10, 0x37, 0x10, 0x36, 0x52, 0x78, 0x43, 0x28, 0x24, 0x64, 0x23, 0x20, 0x47, 0x64, 0x23, 0x84, 0x00, 0x00, 0x67, 0x43, 0x64, 0x56, 0x52, 0x26, 0x21, 0x76, 0x65, 0x21, 0x24, 0x13, 0x88, 0x73, 0x47, 0x65, 0x08, 0x43, 0x12, 0x17, 0x01, 0x64, 0x71, 0x46, 0x54, 0x03, 0x87, 0x24, 0x41, 0x77, 0x74, 0x13, 0x76, 0x78, 0x55, 0x21, 0x64, 0x11, 0x17, 0x31, 0x60, 0x50, 0x48, 0x26, 0x04, 0x14, 0x84, 0x74, 0x66, 0x38, 0x03, 0x35, 0x15, 0x58, 0x01, 0x73, 0x51, 0x26, 0x21, 0x33, 0x62, 0x22, 0x27, 0x10, 0x63, 0x45, 0x60, 0x16, 0x57, 0x20, 0x77, 0x85, 0x48, 0x32, 0x72, 0x48, 0x31, 0x56, 0x16, 0x78, 0x34, 0x56, 0x40, 0x57, 0x68, 0x67, 0x34, 0x58, 0x35, 0x25, 0x35, 0x20, 0x81, 0x55, 0x65, 0x48, 0x10, 0x32, 0x05, 0x33, 0x40, 0x16, 0x60, 0x74, 0x23, 0x71, 0x50, 0x16, 0x32, 0x53, 0x34, 0x66, 0x72, 0x70, 0x81, 0x11, 0x18, 0x24, 0x37, 0x32, 0x13, 0x11, 0x54, 0x42, 0x40, 0x82, 0x61, 0x37, 0x75, 0x04, 0x67, 0x10, 0x08, 0x02, 0x61, 0x38, 0x68, 0x50, 0x71, 0x28, 0x37, 0x52, 0x66, 0x72, 0x24, 0x23, 0x08, 0x02, 0x10, 0x05, 0x01, 0x55, 0x20, 0x48, 0x37, 0x44, 0x37, 0x71, 0x16, 0x42, 0x01, 0x23, 0x16, 0x71, 0x07, 0x82, 0x38, 0x08, 0x07, 0x10, 0x11, 0x24, 0x68, 0x25, 0x82, 0x40, 0x18, 0x15, 0x85, 0x18, 0x74, 0x20, 0x85, 0x38, 0x25, 0x83, 0x10, 0x66, 0x75, 0x13, 0x12, 0x52, 0x85, 0x27, 0x65, 0x25, 0x60, 0x31, 0x47, 0x81, 0x62, 0x13, 0x81, 0x53, 0x47, 0x04, 0x22, 0x61, 0x05, 0x71, 0x55, 0x67, 0x44, 0x68, 0x20, 0x05, 0x45, 0x50, 0x51, 0x48, 0x41, 0x13, 0x03, 0x83, 0x02, 0x41, 0x47, 0x47, 0x15, 0x62, 0x72, 0x02, 0x16, 0x53, 0x21, 0x03, 0x03, 0x87, 0x36, 0x03, 0x48, 0x67, 0x51, 0x76, 0x65, 0x27, 0x21, 0x42, 0x17, 0x26, 0x25, 0x76, 0x65, 0x36, 0x12, 0x11, 0x12, 0x16, 0x87, 0x48, 0x45, 0x40, 0x33, 0x42, 0x68, 0x35, 0x44, 0x40, 0x68, 0x13, 0x60, 0x50, 0x31, 0x08, 0x17, 0x43, 0x56, 0x75, 0x06, 0x34, 0x61, 0x84, 0x75, 0x57, 0x58, 0x58, 0x65, 0x44, 0x84, 0x07, 0x62, 0x31, 0x86, 0x70, 0x34, 0x33, 0x67, 0x58, 0x66, 0x67, 0x73, 0x20, 0x75, 0x17, 0x10, 0x36, 0x05, 0x27, 0x37, 0x24, 0x12, 0x20, 0x17, 0x38, 0x87, 0x54, 0x40, 0x32, 0x26, 0x30, 0x62, 0x13, 0x54, 0x18, 0x36, 0x81, 0x55, 0x77, 0x32, 0x00, 0x10, 0x03, 0x65, 0x18, 0x57, 0x41, 0x86, 0x02, 0x14, 0x44, 0x33, 0x41, 0x02, 0x37, 0x55, 0x63, 0x58, 0x75, 0x02, 0x61, 0x88, 0x64, 0x18, 0x51, 0x76, 0x24, 0x15, 0x85, 0x07, 0x11, 0x80, 0x35, 0x41, 0x51, 0x57, 0x42, 0x42, 0x58, 0x54, 0x56, 0x35, 0x45, 0x15, 0x57, 0x07, 0x63, 0x86, 0x77, 0x24, 0x00, 0x17, 0x67, 0x83, 0x86, 0x86, 0x25, 0x88, 0x17, 0x75, 0x08, 0x61, 0x23, 0x60, 0x60, 0x65, 0x07, 0x33, 0x35, 0x06, 0x60, 0x52, 0x75, 0x02, 0x47, 0x24, 0x33, 0x64, 0x51, 0x35, 0x45, 0x52, 0x55, 0x41, 0x48, 0x60, 0x42, 0x16, 0x43, 0x15, 0x63, 0x33, 0x16, 0x55, 0x67, 0x60, 0x70, 0x34, 0x26, 0x77, 0x08, 0x07, 0x60, 0x55, 0x30, 0x63, 0x50, 0x13, 0x37, 0x70, 0x77, 0x01, 0x37, 0x45, 0x72, 0x74, 0x51, 0x28, 0x72, 0x83, 0x64, 0x74, 0x77, 0x80, 0x27, 0x30, 0x36, 0x44, 0x23, 0x10, 0x55, 0x24, 0x15, 0x43, 0x11, 0x63, 0x14, 0x65, 0x33, 0x63, 0x12, 0x11, 0x84, 0x63, 0x12, 0x63, 0x88, 0x37, 0x62, 0x67, 0x48, 0x35, 0x13, 0x86, 0x35, 0x17, 0x83, 0x12, 0x58, 0x14, 0x47, 0x88, 0x56, 0x08, 0x48, 0x01, 0x42, 0x71, 0x64, 0x77, 0x53, 0x64, 0x73, 0x54, 0x66, 0x05, 0x56, 0x60, 0x52, 0x37, 0x00, 0x46, 0x40, 0x31, 0x10, 0x55, 0x50, 0x45, 0x36, 0x48, 0x42, 0x34, 0x06, 0x61, 0x11, 0x75, 0x52, 0x61, 0x58, 0x52, 0x15, 0x73, 0x57, 0x31, 0x56, 0x15, 0x87, 0x78, 0x74, 0x45, 0x03, 0x87, 0x20, 0x54, 0x56, 0x11, 0x66, 0x22, 0x04, 0x46, 0x14, 0x14, 0x61, 0x83, 0x00, 0x06, 0x86, 0x64, 0x06, 0x00, 0x47, 0x37, 0x44, 0x22, 0x50, 0x56, 0x01, 0x04, 0x57, 0x73, 0x50, 0x74, 0x87, 0x02, 0x66, 0x37, 0x48, 0x68, 0x48, 0x02, 0x63, 0x28, 0x52, 0x63, 0x58, 0x11, 0x30, 0x44, 0x28, 0x68, 0x32, 0x61, 0x10, 0x61, 0x88, 0x26, 0x07, 0x00, 0x73, 0x38, 0x62, 0x55, 0x27, 0x15, 0x53, 0x45, 0x32, 0x14, 0x25, 0x73, 0x23, 0x12, 0x21, 0x87, 0x86, 0x55, 0x67, 0x25, 0x67, 0x46, 0x74, 0x72, 0x81, 0x44, 0x54, 0x64, 0x15, 0x77, 0x41, 0x07, 0x80, 0x60, 0x56, 0x13, 0x16, 0x15, 0x40, 0x44, 0x63, 0x47, 0x53, 0x30, 0x77, 0x61, 0x62, 0x50, 0x13, 0x38, 0x41, 0x47, 0x42, 0x66, 0x70, 0x52, 0x06, 0x70, 0x81, 0x25, 0x43, 0x17, 0x77, 0x70, 0x15, 0x22, 0x21, 0x82, 0x50, }, .t0_len = 2496, .t0 = { 0x01, 0x31, 0x73, 0x16, 0x9D, 0xB8, 0x08, 0x6B, 0x12, 0x27, 0x01, 0x70, 0x6A, 0xE4, 0x9B, 0x99, 0x30, 0x5E, 0xE6, 0xD0, 0x16, 0xF1, 0x6F, 0x9F, 0xAC, 0xC1, 0xF8, 0x35, 0x29, 0x8B, 0x41, 0xE2, 0x16, 0x64, 0x20, 0x60, 0x05, 0xCE, 0xB9, 0x81, 0xA3, 0x5F, 0x18, 0x65, 0x1C, 0xDB, 0x90, 0xE6, 0x8C, 0x1F, 0x95, 0x0B, 0x05, 0x9F, 0x73, 0xD6, 0xD3, 0x14, 0x3A, 0x1F, 0x47, 0xAA, 0x21, 0xD8, 0x0A, 0x05, 0xFA, 0xF5, 0xD3, 0xA4, 0x0F, 0x67, 0x14, 0x8D, 0x3A, 0x89, 0xA9, 0xFD, 0xA8, 0x03, 0x64, 0xD5, 0x7C, 0x7B, 0x8F, 0x68, 0x05, 0x8A, 0x25, 0xD0, 0x84, 0x98, 0xD9, 0xA9, 0xC3, 0x78, 0xC9, 0x81, 0x85, 0xDB, 0x13, 0x25, 0x91, 0x59, 0xCA, 0xC4, 0x76, 0x9C, 0x34, 0xA0, 0x80, 0x23, 0xA3, 0x38, 0x8C, 0x35, 0x05, 0x40, 0x6F, 0xB2, 0x1C, 0x69, 0xEE, 0xC1, 0x2D, 0xAC, 0x95, 0xA3, 0xC9, 0xBA, 0x61, 0x18, 0x52, 0x37, 0xF0, 0xFF, 0x1E, 0x0E, 0x05, 0xF1, 0xA6, 0xF5, 0xA0, 0xC0, 0x90, 0x90, 0x10, 0x06, 0x65, 0xA1, 0xAD, 0x3A, 0xFB, 0x10, 0x76, 0x84, 0x7B, 0x23, 0x2E, 0xEE, 0xA7, 0x84, 0x09, 0xBD, 0x90, 0x55, 0xDB, 0x57, 0xC1, 0xB3, 0x1E, 0x28, 0xA0, 0x1D, 0x09, 0x99, 0x90, 0x35, 0xBD, 0xFC, 0x65, 0x7A, 0x61, 0x04, 0x01, 0x03, 0xEC, 0xEB, 0xDC, 0x79, 0x34, 0x09, 0x73, 0x37, 0x34, 0xD9, 0x34, 0x2C, 0xC5, 0xA0, 0x69, 0xE0, 0x70, 0xC2, 0x42, 0x1D, 0xDE, 0x11, 0xC4, 0x9E, 0x17, 0x2D, 0xBE, 0x7F, 0xEA, 0xF9, 0xDE, 0xDD, 0xFB, 0x3D, 0xA5, 0xDA, 0xA6, 0xB3, 0xDD, 0x13, 0x20, 0x0B, 0x09, 0x04, 0x2E, 0x14, 0x4E, 0xEA, 0x95, 0x1B, 0x43, 0xDA, 0x48, 0x15, 0x3C, 0x1F, 0x1D, 0x5C, 0x07, 0xFC, 0xF4, 0x73, 0xFA, 0x7F, 0x32, 0x1E, 0x72, 0x53, 0x45, 0x77, 0xC8, 0x95, 0x15, 0x1B, 0x46, 0xE4, 0x83, 0x31, 0xDD, 0xE6, 0x1D, 0xA4, 0x5F, 0x86, 0x09, 0xAC, 0x59, 0x58, 0x18, 0x14, 0x66, 0x6E, 0x16, 0x58, 0xB4, 0x91, 0x14, 0x52, 0x4B, 0xA3, 0x84, 0x0C, 0x6B, 0xC5, 0x59, 0x65, 0x51, 0xAE, 0xF4, 0x24, 0x12, 0xC8, 0xAA, 0xCC, 0xDD, 0x8E, 0xF6, 0x9E, 0x46, 0x38, 0x0E, 0x6D, 0xEF, 0x60, 0xFD, 0x91, 0x22, 0x8B, 0x99, 0xCB, 0x51, 0x1D, 0x68, 0xEF, 0x66, 0x31, 0x74, 0x8A, 0x05, 0x48, 0x08, 0x3A, 0x21, 0x54, 0x45, 0xEC, 0x54, 0x69, 0x34, 0x71, 0xA8, 0x31, 0x04, 0x2C, 0xF4, 0x1D, 0x09, 0xAF, 0x89, 0x81, 0x19, 0xB0, 0xFC, 0x64, 0x6E, 0x48, 0x45, 0x39, 0xC8, 0xC3, 0x2D, 0x5D, 0xC2, 0x4F, 0x94, 0x39, 0xD3, 0x3E, 0xEE, 0xA0, 0x33, 0xA4, 0x08, 0x15, 0x50, 0xFD, 0xB0, 0xB0, 0x89, 0x23, 0xDB, 0xA5, 0xD4, 0x4A, 0x1A, 0x87, 0x6F, 0xE7, 0xEE, 0x43, 0x20, 0xBF, 0x02, 0xF9, 0xBE, 0x26, 0xF4, 0x18, 0xF3, 0x09, 0xFA, 0x11, 0xFC, 0xD0, 0xC8, 0x64, 0xA7, 0xAA, 0x34, 0x11, 0x50, 0x83, 0xC1, 0xEA, 0x77, 0x53, 0x45, 0xAC, 0x05, 0x48, 0xC8, 0x77, 0xC6, 0x85, 0xEA, 0x8C, 0x91, 0xB9, 0x24, 0xAF, 0x4F, 0x60, 0x7E, 0xF3, 0x7A, 0x02, 0x08, 0xE2, 0x13, 0x09, 0xAB, 0x6D, 0x0F, 0x2F, 0x8A, 0x4E, 0xAA, 0x04, 0x51, 0xFF, 0x4A, 0x47, 0xE6, 0xF4, 0x82, 0x95, 0x8D, 0x81, 0xA1, 0x66, 0xA6, 0xA0, 0x8A, 0x6A, 0x10, 0xFC, 0x8F, 0x9A, 0xDA, 0x42, 0xB6, 0x4A, 0x12, 0xB9, 0x35, 0x7D, 0x59, 0x8A, 0x36, 0x64, 0xE9, 0xDF, 0x13, 0x75, 0x5C, 0x10, 0xFF, 0xD7, 0x17, 0x7E, 0x59, 0x4D, 0xFC, 0xBC, 0xFB, 0x5D, 0x11, 0xB6, 0xAD, 0xB1, 0x60, 0x74, 0x45, 0x47, 0x9A, 0x5D, 0xB1, 0xAD, 0x8C, 0xA6, 0xD9, 0x15, 0xF8, 0x97, 0x95, 0xD2, 0x40, 0xCB, 0xED, 0xFA, 0xD2, 0x53, 0x9D, 0x10, 0x51, 0x8E, 0x53, 0xCC, 0x45, 0x0D, 0x6F, 0xC5, 0x38, 0x5A, 0xD6, 0xD7, 0x6B, 0x78, 0x30, 0xF1, 0x38, 0x28, 0x12, 0x06, 0x45, 0xE3, 0xA0, 0xA5, 0xDC, 0xDE, 0xAF, 0x15, 0xF1, 0x96, 0x8E, 0x64, 0xB3, 0xB1, 0xCE, 0xAF, 0x53, 0x6C, 0xAA, 0x29, 0x53, 0xD1, 0x61, 0xC7, 0x55, 0x28, 0xC3, 0xFA, 0x84, 0x93, 0xE0, 0xC1, 0x77, 0xAE, 0x80, 0x7C, 0xED, 0x37, 0x64, 0x8A, 0x82, 0xC9, 0xBE, 0x8B, 0xA9, 0x70, 0x29, 0x6D, 0x54, 0x3F, 0x6F, 0xBD, 0x67, 0x24, 0xA9, 0x9A, 0x68, 0xD2, 0xF6, 0x8C, 0x1F, 0xD3, 0x33, 0xF9, 0xDE, 0xF8, 0x52, 0x6D, 0xB7, 0x83, 0x64, 0x55, 0xB3, 0x13, 0xE6, 0xBC, 0x36, 0x61, 0x78, 0xC9, 0xC5, 0x77, 0x21, 0x60, 0x1E, 0xC0, 0x33, 0x50, 0x54, 0xF0, 0x67, 0xB7, 0x8E, 0x66, 0x3A, 0x05, 0x8D, 0xBD, 0xA1, 0xC1, 0x2D, 0x80, 0xA3, 0x92, 0xF8, 0x9C, 0x0A, 0xD9, 0xE2, 0xA3, 0xB2, 0xEA, 0x17, 0xE9, 0xC9, 0xA3, 0xB1, 0x4D, 0x17, 0x68, 0x22, 0xEE, 0xAC, 0x5F, 0xB5, 0xFF, 0x7D, 0x4C, 0x87, 0xD7, 0x60, 0x80, 0xD2, 0xD4, 0x2D, 0x9A, 0xA4, 0xC9, 0x51, 0xF4, 0xCA, 0xF1, 0x1A, 0x24, 0x4E, 0xDA, 0x71, 0x1D, 0x12, 0x0A, 0x2E, 0xA3, 0x21, 0xD1, 0x55, 0x1D, 0x86, 0xCA, 0x92, 0x65, 0xE9, 0xCD, 0x5F, 0xA9, 0x59, 0x1D, 0x88, 0x0E, 0x40, 0x3B, 0x68, 0x44, 0xF0, 0x51, 0xDC, 0x04, 0x87, 0x99, 0x72, 0xC8, 0x63, 0xB9, 0x7C, 0x72, 0xB4, 0x09, 0xC1, 0x9D, 0x5E, 0xBE, 0xE8, 0xAB, 0x58, 0xC6, 0xE7, 0xB3, 0x93, 0x8A, 0x68, 0xA9, 0xCA, 0xD7, 0x5D, 0x80, 0xC6, 0xFF, 0xC4, 0xF2, 0x22, 0x54, 0xFF, 0x44, 0x20, 0xC6, 0x06, 0xAD, 0x12, 0x0C, 0xC2, 0x03, 0x46, 0xA7, 0xE7, 0x32, 0x4E, 0x78, 0xC8, 0x62, 0xE0, 0xDE, 0xE1, 0x61, 0xA6, 0x4F, 0x44, 0x91, 0x7D, 0xB0, 0xC3, 0x8C, 0x1F, 0x79, 0xC9, 0x69, 0x22, 0x0D, 0x20, 0x2F, 0x88, 0x02, 0xD0, 0xF9, 0xD7, 0xAB, 0xFB, 0x2D, 0xE4, 0x34, 0xB1, 0xC5, 0x3D, 0xAB, 0xB5, 0x75, 0x75, 0xEE, 0xBB, 0xBF, 0x31, 0xCF, 0xB2, 0x92, 0x48, 0x72, 0xFA, 0x01, 0x47, 0x3B, 0x39, 0x76, 0xAE, 0xAD, 0xC9, 0x96, 0x99, 0xB1, 0x38, 0x20, 0xFA, 0x08, 0x68, 0xF2, 0xC9, 0xFD, 0x0D, 0x35, 0x2E, 0x25, 0x93, 0x27, 0x3C, 0xD6, 0x21, 0xB1, 0x97, 0x4F, 0xFA, 0x61, 0x87, 0xFA, 0x05, 0xC4, 0x11, 0x8D, 0x45, 0x17, 0xC9, 0x34, 0x15, 0x1C, 0x1F, 0xA3, 0x4B, 0xEC, 0x3E, 0xD3, 0x63, 0x95, 0x98, 0xCB, 0xA2, 0x4E, 0x28, 0x22, 0x9C, 0xE9, 0xFD, 0x3B, 0x1D, 0xB4, 0x96, 0x9C, 0x12, 0xEE, 0x49, 0xE1, 0x8B, 0x36, 0xCE, 0x2B, 0x91, 0x45, 0xAA, 0xC7, 0x54, 0x28, 0xDF, 0xFA, 0x14, 0x53, 0x02, 0xF4, 0x1D, 0x9E, 0x33, 0x94, 0xF3, 0x8D, 0x3F, 0x3C, 0x03, 0x34, 0xC4, 0x77, 0x4F, 0x1E, 0x94, 0x29, 0x6D, 0xE3, 0x6D, 0xC6, 0xE4, 0x30, 0xE4, 0xC0, 0xA5, 0x37, 0xE6, 0x8B, 0xDD, 0x41, 0xAF, 0x04, 0x21, 0x19, 0x3B, 0x16, 0xAB, 0x18, 0x91, 0xFA, 0x83, 0x6C, 0xBC, 0x36, 0x7B, 0x40, 0x37, 0x05, 0xAB, 0xA5, 0xD2, 0xF9, 0xF2, 0xA4, 0xC2, 0xF2, 0x75, 0xEC, 0x01, 0x0B, 0x2E, 0xAB, 0x84, 0x09, 0x5A, 0x56, 0x9D, 0xBA, 0xE4, 0x45, 0x7C, 0xC2, 0xAC, 0x1C, 0xFE, 0xB1, 0xED, 0xA4, 0x3C, 0x3E, 0x28, 0x19, 0x27, 0x3C, 0x48, 0x7A, 0xCB, 0xEB, 0xFA, 0x0A, 0x0E, 0xD1, 0xCC, 0x46, 0x67, 0xA6, 0xF5, 0x77, 0xF6, 0x2D, 0xFB, 0x1B, 0xC8, 0xFE, 0xAF, 0xD8, 0x6D, 0x90, 0x10, 0x8E, 0x16, 0xB8, 0xB0, 0xE6, 0xC2, 0x67, 0x86, 0x86, 0xC9, 0x28, 0xA6, 0x68, 0xBB, 0x98, 0x57, 0xFF, 0xB2, 0x8D, 0xE9, 0x05, 0x45, 0xCD, 0x44, 0x37, 0xDD, 0x32, 0xCC, 0xCC, 0xC6, 0xED, 0x58, 0xFB, 0x46, 0xFB, 0xF8, 0x5E, 0x0A, 0xEC, 0x0C, 0x81, 0x4E, 0x53, 0x62, 0x45, 0x25, 0x2B, 0x80, 0x29, 0xF0, 0xA2, 0xAB, 0x44, 0xB9, 0x02, 0x7A, 0x7E, 0x35, 0xA9, 0x41, 0xFA, 0x11, 0x3C, 0x8D, 0x82, 0x97, 0x4E, 0xA2, 0x2D, 0xF0, 0x2D, 0x84, 0xE5, 0x32, 0x8C, 0xEA, 0x83, 0xD1, 0x2D, 0x39, 0x9C, 0x7F, 0x02, 0x59, 0x05, 0x5F, 0x4B, 0x3A, 0xD7, 0x07, 0xE7, 0xB3, 0xE5, 0x37, 0xB9, 0x3D, 0xEA, 0x1A, 0x06, 0x6B, 0xDC, 0x77, 0x5F, 0xC7, 0xD1, 0xA6, 0xF0, 0xFE, 0x29, 0xDD, 0xAF, 0xA9, 0xA7, 0xDA, 0x63, 0x0A, 0x46, 0x7E, 0xF6, 0xCB, 0xF5, 0xCC, 0xDF, 0xFD, 0x79, 0xF1, 0xC8, 0xBB, 0x6B, 0xB3, 0x88, 0x20, 0x35, 0xC7, 0x3C, 0xDF, 0x7E, 0xCF, 0xFB, 0x53, 0xC7, 0x12, 0xA7, 0xC7, 0xEA, 0xA5, 0x97, 0x65, 0xEF, 0xA9, 0x60, 0xBF, 0x21, 0xE2, 0x5A, 0x67, 0x03, 0xFB, 0x30, 0x4F, 0x07, 0x73, 0x9F, 0xEB, 0xC6, 0x3F, 0x49, 0x6B, 0x13, 0xCC, 0xAA, 0x07, 0x73, 0x38, 0xA0, 0xB9, 0xA9, 0x76, 0xA9, 0xF0, 0xFC, 0x57, 0x42, 0xD8, 0x5C, 0x4A, 0xF4, 0x01, 0xA4, 0xCE, 0x34, 0x1B, 0x47, 0xBE, 0x25, 0x94, 0xFF, 0x7E, 0x30, 0x19, 0xA0, 0xE0, 0x64, 0x53, 0x5F, 0x9D, 0x93, 0x95, 0xCC, 0x74, 0xA6, 0xA6, 0xF0, 0x0E, 0x0C, 0x4E, 0x35, 0x30, 0xA7, 0xFE, 0x93, 0x10, 0xCE, 0x30, 0xB6, 0x92, 0x2D, 0x04, 0xFD, 0xE0, 0xAA, 0x74, 0x9C, 0xC3, 0xFD, 0xED, 0xB4, 0xD8, 0x70, 0x8C, 0x1F, 0x69, 0x68, 0xBB, 0xED, 0xDD, 0xD5, 0x83, 0x3B, 0x29, 0x9D, 0x79, 0xD6, 0x14, 0x28, 0x18, 0x00, 0x99, 0xB0, 0xA9, 0x46, 0xA5, 0xD7, 0x90, 0x85, 0xDF, 0x7F, 0x87, 0x2C, 0xBD, 0xD2, 0x19, 0xE6, 0xB8, 0xEF, 0x8B, 0x8A, 0xB5, 0xC1, 0xA1, 0x49, 0xE6, 0xE1, 0x5E, 0xF2, 0x82, 0x86, 0x54, 0xFA, 0xBE, 0xC2, 0x49, 0xAF, 0xAA, 0xC4, 0xDC, 0x0B, 0x3B, 0x54, 0x23, 0x34, 0x16, 0x2F, 0xB0, 0x98, 0x00, 0xB6, 0xC3, 0x6C, 0xC9, 0x0F, 0x2A, 0x10, 0x65, 0x58, 0xBA, 0xE2, 0x19, 0x8F, 0xA7, 0xD1, 0xE2, 0xD7, 0x30, 0xDE, 0x46, 0xE3, 0x55, 0xAE, 0xA9, 0x32, 0x48, 0xE5, 0x3A, 0xB2, 0x1B, 0x51, 0x8E, 0xC9, 0x9D, 0x5F, 0x3B, 0x02, 0x11, 0x96, 0xA0, 0xF6, 0x14, 0xA4, 0x6B, 0x94, 0x75, 0x62, 0x12, 0x34, 0x73, 0x3A, 0x28, 0xA4, 0x65, 0xCC, 0x5A, 0x7F, 0xD4, 0x32, 0xC3, 0x62, 0x58, 0x12, 0xAA, 0xBB, 0xB4, 0x2D, 0x2D, 0x9C, 0xBE, 0xF1, 0x6C, 0xBE, 0xD9, 0x36, 0x72, 0x02, 0xB0, 0x28, 0x94, 0xD0, 0x6B, 0xB8, 0x01, 0xBD, 0xA8, 0x47, 0x2B, 0x99, 0x18, 0xB7, 0xD7, 0x24, 0xE3, 0x65, 0x57, 0xDB, 0xE6, 0xB7, 0x63, 0x3A, 0x5F, 0xD2, 0x2D, 0x0E, 0x33, 0x6E, 0x55, 0x57, 0xAF, 0xC0, 0x18, 0xC8, 0x12, 0xE9, 0xE6, 0xA3, 0x5B, 0xFD, 0x8C, 0x60, 0xAB, 0x38, 0x2E, 0x14, 0xFF, 0x51, 0x14, 0x2B, 0x2D, 0x2C, 0x75, 0xA7, 0x67, 0xF3, 0x24, 0x13, 0xBA, 0x38, 0x48, 0x75, 0x58, 0xF9, 0x34, 0x5C, 0xBE, 0x6F, 0xD1, 0xD6, 0xB7, 0x8C, 0x2E, 0x62, 0x2F, 0x3B, 0x97, 0x62, 0x30, 0xF9, 0x9D, 0x6C, 0xBA, 0xF0, 0xBB, 0xD1, 0x49, 0x49, 0x51, 0x0A, 0x52, 0x64, 0x4E, 0xF3, 0xF3, 0x07, 0x88, 0x65, 0x03, 0x7A, 0x1C, 0x10, 0xF4, 0x7B, 0x59, 0x54, 0x66, 0x99, 0xE1, 0xBD, 0x53, 0x9C, 0x7D, 0xDC, 0xC0, 0x3F, 0x71, 0xA0, 0x15, 0x8E, 0xA9, 0xF0, 0x17, 0x8E, 0x18, 0x7B, 0xB6, 0xD4, 0x94, 0x40, 0xDF, 0x2B, 0x10, 0x63, 0x0F, 0xBE, 0x2F, 0xEB, 0x50, 0x97, 0xE4, 0x7F, 0x28, 0x57, 0x11, 0xCA, 0x6F, 0x83, 0x5A, 0x10, 0xD3, 0xAA, 0x75, 0xC0, 0x3C, 0x41, 0x84, 0xC0, 0x3E, 0xF3, 0x07, 0x5D, 0x49, 0xDC, 0xB2, 0x17, 0x7A, 0xBD, 0x53, 0xAD, 0x73, 0x99, 0xD2, 0x90, 0xEA, 0x69, 0x1D, 0x64, 0x73, 0x29, 0x05, 0x63, 0x40, 0xE8, 0xC8, 0x36, 0xE9, 0x75, 0x0F, 0xD8, 0x81, 0xDC, 0xE3, 0x09, 0xD3, 0x09, 0xA9, 0x5B, 0x82, 0x49, 0x2D, 0x4B, 0xDC, 0x15, 0xEC, 0xF8, 0xC7, 0xF5, 0xD3, 0xB9, 0xDD, 0x27, 0x55, 0x48, 0x51, 0x2D, 0xB5, 0xEF, 0x80, 0xCD, 0x40, 0x9E, 0xD3, 0x2B, 0x51, 0x48, 0xB8, 0x2B, 0xF2, 0x40, 0xA7, 0xDC, 0x72, 0xA1, 0x85, 0x23, 0xD8, 0x08, 0xB7, 0xA4, 0xF9, 0xE2, 0x54, 0x79, 0x9E, 0x17, 0x27, 0x8F, 0xA8, 0x8D, 0xAE, 0xBC, 0x94, 0x46, 0x32, 0xE8, 0x3F, 0x86, 0x09, 0xD6, 0x81, 0xAB, 0x46, 0x35, 0x13, 0x02, 0x3D, 0x67, 0xCD, 0x51, 0xB1, 0x53, 0xF0, 0x96, 0x29, 0x12, 0xDD, 0x64, 0xAB, 0x8F, 0x65, 0x29, 0xDC, 0x22, 0xAA, 0x89, 0xE5, 0x72, 0xA7, 0xF8, 0x9C, 0xB9, 0x7A, 0x8F, 0x45, 0x09, 0x31, 0x9D, 0x22, 0x3B, 0xB2, 0x99, 0x74, 0x95, 0x17, 0x16, 0xFD, 0x31, 0x77, 0x14, 0x0A, 0x31, 0xEA, 0x20, 0x04, 0x8B, 0xAF, 0x0F, 0xCA, 0x23, 0x0C, 0xEF, 0x21, 0x96, 0x7A, 0xBD, 0x83, 0x30, 0x9A, 0x4F, 0xF7, 0xE3, 0x5E, 0x88, 0x78, 0x4D, 0xCA, 0x77, 0xAC, 0x07, 0x90, 0x20, 0xEC, 0x0C, 0xA6, 0xDD, 0xEF, 0xBC, 0xBB, 0x7E, 0x31, 0x73, 0x29, 0x31, 0x46, 0x65, 0xD7, 0xC5, 0x1F, 0x63, 0x1F, 0x68, 0x1B, 0x60, 0x03, 0x64, 0xE4, 0x75, 0x74, 0xF2, 0x52, 0xBA, 0xD6, 0x39, 0x6B, 0x3F, 0x5B, 0x17, 0xAD, 0xC2, 0x20, 0x96, 0x6A, 0x93, 0xCE, 0x8F, 0x31, 0x5A, 0x2F, 0x83, 0x06, 0x8D, 0x2E, 0xA0, 0x69, 0x52, 0xE6, 0xEB, 0xD8, 0x02, 0x47, 0x3A, 0x22, 0x64, 0xEF, 0xA4, 0x05, 0xB3, 0xE4, 0x91, 0xBE, 0x77, 0x6C, 0x50, 0x40, 0x6E, 0x11, 0x50, 0xC5, 0x6B, 0x89, 0x4C, 0xF8, 0x64, 0x54, 0x6B, 0x0C, 0x7A, 0x65, 0xE3, 0xF1, 0xA2, 0xBE, 0xFE, 0xF2, 0xA9, 0x99, 0x0B, 0xAF, 0xE7, 0x0B, 0x6C, 0xA9, 0xF9, 0x1A, 0x8F, 0x3D, 0xD2, 0x13, 0x07, 0xA3, 0x9A, 0x2A, 0xFB, 0xDF, 0xBD, 0xE9, 0xB7, 0xCA, 0x3D, 0x78, 0x28, 0xB1, 0x3F, 0x49, 0xDE, 0xCD, 0x72, 0x9C, 0x00, 0x39, 0xE9, 0x4E, 0xBB, 0x7B, 0x4B, 0xDA, 0x09, 0xB3, 0x50, 0x55, 0x29, 0xA1, 0x2C, 0xB1, 0xE2, 0xFD, 0x79, 0xB9, 0xE5, 0x08, 0x7C, 0xD7, 0xC3, 0xBC, 0x05, 0xF7, 0xCF, 0xFB, 0xBA, 0x93, 0x2A, 0x7B, 0xFF, 0x8E, 0x67, 0x55, 0x5F, 0xEE, 0x03, 0x04, 0xD8, 0x90, 0x31, 0x3F, 0x86, 0xE1, 0x89, 0x25, 0x69, 0xE2, 0xD6, 0xF1, 0x4A, 0x89, 0x93, 0x87, 0x17, 0xAA, 0xA3, 0xA3, 0x2A, 0xD1, 0x16, 0x71, 0x50, 0x29, 0x9C, 0x21, 0x82, 0x0A, 0xBD, 0x70, 0xFF, 0x90, 0x2B, 0x00, 0x4C, 0x6D, 0xE9, 0x1C, 0x1C, 0x0B, 0x40, 0x70, 0x64, 0x42, 0xAF, 0x53, 0x1E, 0xC4, 0x90, 0xB0, 0x12, 0x75, 0x0B, 0xCB, 0x48, 0x77, 0x93, 0x5A, 0x7E, 0x54, 0x03, 0x17, 0x02, 0xBB, 0x98, 0x8E, 0xB3, 0xF9, 0x29, 0x14, 0xCD, 0xBD, 0x42, 0x97, 0x9A, 0xD7, 0xD2, 0x7B, 0x22, 0x33, 0xEC, 0x12, 0x79, 0xD0, 0x54, 0x93, 0xB1, 0x2D, 0x3F, 0x5F, 0xBB, 0x77, 0x57, 0x53, 0x60, 0x21, 0xB5, 0xF4, 0xCD, 0x93, 0x2B, 0x48, 0x0E, 0x40, 0xCB, 0xAE, 0x50, 0xD2, 0x32, 0xE0, 0xA2, 0xEF, 0xFE, 0x0E, 0x8C, 0xB5, 0x88, 0x08, 0x66, 0x91, 0x99, 0xF0, 0x83, 0x08, 0x72, 0xF3, 0x69, 0x73, 0x86, 0x82, 0xF8, 0x46, 0xF6, 0xDE, 0xAD, 0x09, 0x5B, 0xFF, 0xCD, 0x67, 0x0A, 0x4A, 0x9C, 0xD1, 0x42, 0x39, 0x6C, 0x58, 0x50, 0x6E, 0xA7, 0xA6, 0x8B, 0x21, 0xAB, 0xDC, 0xC1, 0x9C, 0xCC, 0x06, 0xF6, 0xDA, 0x55, 0xC8, 0x85, 0xA8, 0x55, 0xC4, 0x56, 0x68, 0x0C, 0xD4, 0x47, 0x7B, 0xCA, 0x2B, 0xBA, 0x91, 0x53, 0xDC, 0xAE, 0xE6, 0x82, 0x65, 0x5B, 0x74, 0xEC, 0xA6, 0xF7, 0xE4, 0x4C, 0x3B, 0xFE, 0x1E, 0x2D, 0x45, 0x74, 0x91, 0xED, 0x1B, 0xC6, 0x4E, 0x1C, 0xF6, 0xCE, 0x18, 0xCF, 0x44, 0xA0, 0x16, 0x6D, 0x1B, 0x24, 0x44, 0x80, 0x88, 0x2C, 0x1B, 0x35, 0xCE, 0xA7, 0x03, 0x15, 0x8E, 0x18, 0xC7, 0xEC, 0x6E, 0x0C, 0xF8, 0x27, 0xD5, 0x50, 0x4A, 0x45, 0xAE, 0x61, 0x15, 0x23, 0x09, 0xBC, 0x8A, 0x18, 0xA5, 0x2C, 0x0E, 0x76, 0x99, 0xA8, 0x7C, 0x4E, 0x31, 0xC6, 0x91, 0x1A, 0x83, 0x05, 0x35, 0x15, 0x55, 0xB2, 0x97, 0x1C, 0x94, 0x60, 0x2B, 0x70, 0xE6, 0x70, 0xAA, 0x30, 0xB9, 0x07, 0x34, 0xEC, 0x1D, 0xAA, 0xD0, 0x3A, 0x30, 0xA9, 0x6F, 0x58, 0x47, 0xC5, 0xC3, 0xF7, 0x97, 0x3C, 0xF4, 0x57, 0x2D, 0x16, 0x6C, 0x51, 0xD1, 0xE9, 0x4A, 0x50, 0xA4, 0xC1, 0xC8, 0x94, 0xA2, 0x05, 0xF8, 0xEC, 0xB3, 0x4E, 0x80, 0xF8, 0x4C, 0xA8, 0xDC, 0x31, 0xA4, 0x29, 0xD5, 0x60, 0x05, 0x96, 0x17, 0x9D, 0x10, 0x93, 0xE2, 0xA3, 0x89, 0xCC, 0xFE, 0x9C, 0x04, 0x02, 0xEE, 0x49, 0x55, 0x17, 0x10, 0xFF, 0xC2, 0x5B, 0xDB, 0xE4, 0x78, 0xF3, 0x9F, 0x20, 0x63, 0xF3, 0x1F, 0x75, 0xD7, 0x43, 0x2E, 0xCA, 0x1C, 0x59, 0xEB, 0xD8, 0xF4, 0x6D, 0x86, 0xA0, 0x92, 0xDB, 0x12, 0xF8, 0x10, 0xFA, 0x91, 0x1C, 0x20, 0xD4, 0xCC, 0x1E, 0x42, 0x5C, 0x54, 0x3D, 0xC6, 0x45, 0x77, 0xE4, 0x4D, 0x84, 0xF4, 0x22, 0xD9, 0x66, 0x1E, 0x3D, 0x35, 0x92, 0x13, 0x50, 0xD6, 0xF7, 0x09, 0x9C, 0x54, 0x25, 0xE5, 0x09, 0xE1, 0x45, 0x8A, 0x05, 0x00, 0xAE, 0x5E, 0xB4, 0xCC, 0x6B, 0xB5, 0x06, 0x26, 0xD0, 0x13, 0x0F, 0x09, 0x36, 0x17, 0x17, 0xA9, 0x59, 0x19, 0xAE, 0xD3, 0x55, 0x92, 0xFA, 0x4A, 0xBE, 0x7B, 0x2B, 0xD4, 0xF9, 0x99, 0x42, 0x21, 0x51, 0xE6, 0x3D, 0x4E, 0xD0, 0x0C, 0xC7, 0x51, 0xA5, 0x86, 0x79, 0x77, 0xF1, 0x5E, 0x48, 0x2E, 0xFA, 0x01, 0xE5, 0xCC, 0xC4, 0x40, 0x64, 0xF5, 0xB9, 0xFF, 0xE2, 0x9A, 0xFF, 0xE6, 0x26, 0xC4, 0xD5, 0x17, 0x0A, 0xDA, 0x1D, 0xF0, 0x27, 0xAB, 0x41, 0x79, 0x60, 0x8C, 0x40, 0x93, 0xCC, 0xE2, 0xC4, 0x09, 0x30, 0x8C, 0xD8, 0x98, 0x37, 0x1A, 0x49, 0xFB, 0xEA, 0x2A, 0x2F, 0x2B, 0xA1, 0x3B, 0xDE, 0xBA, 0xC1, 0xF4, 0x15, 0x9F, 0x4B, 0x03, 0x68, 0xFB, 0x21, 0xD7, 0x0A, 0x9D, 0x79, 0x31, 0xD7, 0xEF, 0xF9, 0x34, 0xE6, 0xC5, 0x44, 0xE1, 0x3B, 0x7B, 0x73, 0xD4, 0x65, 0x57, 0x6C, 0x6E, 0x81, 0xFD, 0x6D, 0x5F, 0xD9, 0x43, 0x93, 0xE8, 0x02, 0x42, 0xF9, 0x42, 0x0A, 0xCC, 0x0E, 0xD3, 0x53, 0xEF, 0x18, 0xCA, 0x07, 0x0F, 0x5E, 0x9A, 0x28, 0x5A, 0xC4, 0xBC, 0xBA, 0xB1, 0x9A, 0x38, 0x35, 0x6F, 0x55, 0x7B, 0x07, 0x0E, 0x17, 0xAE, 0x5C, 0xF1, 0xF1, 0xBE, 0xD4, 0x26, 0x01, 0xE8, 0x9C, 0x8C, 0x4C, }, .t1_len = 1920, .t1 = { 0xD9, 0xFD, 0xE3, 0xA4, 0x96, 0xF7, 0x58, 0x19, 0xF0, 0xA2, 0x0D, 0x04, 0x41, 0xDC, 0x78, 0x30, 0xB4, 0xAA, 0x1C, 0xB8, 0xEC, 0xFC, 0x91, 0xBA, 0x0E, 0xEC, 0x3A, 0xFB, 0x67, 0x44, 0xE4, 0x77, 0xB4, 0xE6, 0xEC, 0x3F, 0xDA, 0xE7, 0x50, 0x48, 0xFF, 0xEB, 0xAA, 0xBE, 0xA8, 0xE8, 0x22, 0x11, 0x7D, 0x57, 0x87, 0xF7, 0x90, 0x70, 0xEA, 0x88, 0x28, 0x7C, 0xE3, 0xCD, 0x50, 0x11, 0xFD, 0x8D, 0x93, 0xAB, 0x7E, 0x8B, 0x51, 0xF2, 0x61, 0x16, 0xBF, 0x9B, 0x6D, 0x21, 0xC0, 0x3F, 0x88, 0xBF, 0xEC, 0x48, 0x88, 0x76, 0xF4, 0xD0, 0x75, 0xA1, 0x42, 0xD4, 0xE7, 0x84, 0xD7, 0x34, 0x40, 0x75, 0x11, 0xF9, 0x92, 0x06, 0x93, 0x53, 0xF1, 0xDB, 0x67, 0xAC, 0xF7, 0x30, 0x34, 0xA4, 0x68, 0xA1, 0x18, 0x58, 0x80, 0x62, 0x11, 0x1D, 0x32, 0x0E, 0x00, 0xBC, 0xFF, 0x6D, 0xC6, 0x35, 0x73, 0xFC, 0xED, 0x1E, 0x96, 0xAA, 0xEB, 0xA6, 0x45, 0x2E, 0x3C, 0x7A, 0xCD, 0x19, 0x18, 0x1F, 0x9B, 0x81, 0x4B, 0xA1, 0x9D, 0x39, 0xB4, 0xBA, 0xB5, 0x49, 0x6D, 0xC0, 0x55, 0x42, 0x6E, 0x7E, 0xA4, 0x61, 0xAF, 0x55, 0xD5, 0xB9, 0xFE, 0x97, 0xF9, 0xDF, 0x7E, 0x25, 0x32, 0x03, 0xC1, 0xF9, 0xE1, 0x52, 0xE9, 0x6D, 0x75, 0xF9, 0xD9, 0xA8, 0x4F, 0x5C, 0x26, 0x3E, 0xC8, 0xC2, 0x50, 0x44, 0x0A, 0xDC, 0x98, 0x6F, 0x4E, 0x36, 0x41, 0x4C, 0x70, 0x3B, 0x3E, 0x05, 0x42, 0x6B, 0x28, 0xB7, 0x06, 0x59, 0x50, 0xDA, 0x6D, 0x0E, 0x0B, 0x2C, 0x60, 0xAC, 0x36, 0x72, 0xDB, 0x6F, 0x3C, 0x78, 0x44, 0x7D, 0xB7, 0xC2, 0x09, 0x15, 0x77, 0x0E, 0xA6, 0xFC, 0xE8, 0x1D, 0xAB, 0x53, 0x39, 0xC1, 0xD5, 0xAF, 0x82, 0xA5, 0xD3, 0x32, 0x40, 0x99, 0xDF, 0x56, 0x51, 0x6A, 0x07, 0xDB, 0x7C, 0x0F, 0xC6, 0x43, 0x83, 0x80, 0x5C, 0x65, 0xF2, 0xB0, 0x2F, 0xBC, 0xFC, 0xE6, 0x3E, 0x93, 0xC4, 0xBF, 0x09, 0x40, 0x9F, 0x9F, 0x0F, 0x77, 0xE7, 0x3D, 0xA3, 0xB0, 0x01, 0x9F, 0x20, 0x57, 0xE4, 0xCD, 0x7C, 0xFF, 0x0E, 0x57, 0x45, 0xEF, 0x18, 0xC3, 0xFD, 0x76, 0x6E, 0x01, 0x74, 0x7A, 0x64, 0xD4, 0x15, 0xFC, 0x97, 0x89, 0xAB, 0xFA, 0x62, 0x28, 0x4E, 0x11, 0xC7, 0xFF, 0x05, 0xD0, 0x54, 0x8D, 0x97, 0x3F, 0x67, 0x95, 0x59, 0xA6, 0xA3, 0xAA, 0xD7, 0x7E, 0xD5, 0x13, 0x2D, 0x01, 0x50, 0xC0, 0x14, 0xC3, 0xEC, 0x3A, 0x39, 0x5F, 0x01, 0x7E, 0x7A, 0xCF, 0xE3, 0xEA, 0xBF, 0xCA, 0x44, 0x91, 0x0C, 0xA0, 0x6F, 0xF3, 0x35, 0x42, 0xEC, 0xCE, 0x62, 0x41, 0x97, 0x47, 0x42, 0x35, 0x7D, 0x37, 0xF5, 0xC2, 0x84, 0xBF, 0x0F, 0xE1, 0xA7, 0x4B, 0x50, 0xC0, 0x73, 0x55, 0x13, 0x72, 0x13, 0x3A, 0xF2, 0xDD, 0x41, 0xE2, 0x1B, 0xAF, 0xC9, 0xC5, 0x90, 0xEE, 0x6E, 0xBC, 0x4A, 0xCE, 0x73, 0x1E, 0xF5, 0x66, 0x15, 0x6C, 0xA0, 0x37, 0x55, 0xDC, 0x49, 0x3C, 0x13, 0x70, 0x28, 0xAF, 0x3B, 0x3D, 0xE5, 0xB0, 0x0B, 0xD6, 0xCB, 0x3D, 0x9A, 0x87, 0xD0, 0x15, 0x1F, 0x88, 0x7C, 0x67, 0x68, 0xBC, 0x6C, 0xA0, 0x2A, 0x94, 0xFB, 0x20, 0x86, 0x55, 0x1A, 0x0F, 0x89, 0xBA, 0x26, 0x15, 0x4E, 0x9D, 0x45, 0x06, 0xAD, 0x9F, 0xAF, 0x39, 0xF5, 0x72, 0x3E, 0x23, 0x4E, 0x06, 0xCF, 0xDE, 0xD6, 0x9D, 0x4E, 0xE4, 0x14, 0x6B, 0x73, 0xE5, 0xDC, 0x1E, 0x41, 0x52, 0xA2, 0xA3, 0x15, 0x9D, 0x73, 0xDB, 0xC8, 0x33, 0xD3, 0xD4, 0x17, 0xCD, 0x5C, 0xF7, 0xFB, 0x3D, 0xC7, 0x74, 0x5C, 0xEE, 0xD4, 0xDC, 0x0F, 0x5B, 0x1C, 0x6D, 0x6B, 0x69, 0xC1, 0x76, 0x41, 0x57, 0xEA, 0x43, 0xDF, 0x9D, 0xBB, 0x44, 0x2E, 0xFA, 0x39, 0xD1, 0xD0, 0x16, 0x2E, 0x87, 0xC2, 0xD3, 0x0C, 0x50, 0x12, 0xFD, 0x16, 0xD8, 0x69, 0xC8, 0xA1, 0xFC, 0xBB, 0x45, 0xED, 0xCC, 0x8E, 0x18, 0x13, 0xB2, 0xB1, 0x90, 0xA9, 0x61, 0xF9, 0xFC, 0x86, 0x59, 0x1D, 0x3A, 0xBC, 0x53, 0x88, 0xAF, 0x67, 0x8F, 0xF0, 0x3D, 0xA7, 0x8B, 0x7C, 0xC0, 0xF6, 0x18, 0x57, 0x21, 0xC0, 0xDF, 0x33, 0xCC, 0x90, 0x64, 0x35, 0x22, 0x5D, 0xF2, 0x61, 0x10, 0x02, 0xDF, 0x12, 0x0E, 0x83, 0x56, 0x65, 0x32, 0x29, 0x2D, 0xEA, 0x3D, 0x8A, 0xCD, 0x10, 0x9A, 0x0D, 0xFF, 0xAB, 0x3B, 0x0B, 0x43, 0x01, 0x27, 0x96, 0xDB, 0x5B, 0x50, 0x68, 0x3F, 0xB4, 0xC2, 0xD2, 0x50, 0xDA, 0xB7, 0x6A, 0xAE, 0x35, 0xA4, 0x8E, 0x8C, 0x8D, 0x4A, 0x5C, 0xC1, 0x54, 0x75, 0x97, 0x45, 0xF0, 0xA1, 0x23, 0x0F, 0x6C, 0xA9, 0xDD, 0x9C, 0x99, 0xE2, 0xF8, 0x0E, 0xDC, 0x83, 0x30, 0x4C, 0xE0, 0x1E, 0x98, 0xF6, 0xC9, 0x48, 0x95, 0x29, 0xA8, 0x22, 0xF9, 0x00, 0x33, 0xC2, 0x28, 0x31, 0x5E, 0xB2, 0xFC, 0xC8, 0xDB, 0xA3, 0x82, 0xED, 0x43, 0x01, 0xE0, 0x76, 0x07, 0xA5, 0xB0, 0x76, 0xC7, 0x25, 0xF1, 0x24, 0x99, 0x4F, 0x18, 0xA9, 0x97, 0xD2, 0xC5, 0xBB, 0xF9, 0xA3, 0x24, 0x60, 0x52, 0x65, 0x10, 0x8A, 0xCB, 0xF4, 0x61, 0x0F, 0xA1, 0xC3, 0x37, 0x44, 0x08, 0x85, 0x0A, 0x08, 0x64, 0xE2, 0xB6, 0x10, 0x17, 0xEB, 0xEC, 0x1F, 0xBA, 0xB8, 0x9D, 0xE3, 0xAB, 0x1B, 0x93, 0xCE, 0x49, 0x18, 0xB9, 0xE2, 0xC9, 0xE3, 0xFE, 0x45, 0x67, 0x58, 0x06, 0x2A, 0x9F, 0x88, 0x2B, 0x28, 0x33, 0x18, 0x27, 0x1F, 0x4B, 0x95, 0x52, 0xFC, 0xF3, 0x26, 0x24, 0xA9, 0xFD, 0xAA, 0x44, 0xC6, 0x5C, 0x60, 0xE2, 0xB3, 0x64, 0x8B, 0xEF, 0x1F, 0x17, 0xD0, 0xB7, 0xC7, 0x48, 0x69, 0xEE, 0x0B, 0x53, 0xC4, 0xA6, 0x2A, 0x24, 0x84, 0x5D, 0xCE, 0xA5, 0xBC, 0xBF, 0x93, 0xB9, 0x2E, 0x4C, 0x26, 0x64, 0x85, 0x84, 0xE3, 0x34, 0x79, 0x28, 0x2E, 0x6C, 0x8B, 0x1D, 0x8F, 0xE2, 0x11, 0x81, 0xBD, 0x9C, 0xF7, 0x5F, 0x8A, 0x96, 0x17, 0x24, 0xD4, 0xC4, 0x30, 0x97, 0x79, 0xF1, 0xF1, 0xB7, 0x75, 0xD2, 0x54, 0xF7, 0x0B, 0xD1, 0x76, 0x9C, 0xC7, 0xC0, 0xED, 0xD2, 0xA9, 0x5F, 0xE5, 0xC9, 0xD8, 0x4B, 0x16, 0xF7, 0xC5, 0x4D, 0x85, 0xCC, 0xE4, 0xC8, 0xA1, 0x82, 0x81, 0x08, 0x09, 0xED, 0x81, 0xE9, 0x7D, 0x07, 0x48, 0x84, 0xEE, 0xDF, 0x40, 0x1C, 0xCA, 0xCD, 0xAE, 0xAD, 0x82, 0xC1, 0x4D, 0x06, 0xB6, 0x8A, 0xEA, 0x6C, 0xE1, 0x4B, 0x86, 0x1B, 0x0C, 0xFD, 0x16, 0x09, 0x0C, 0xBB, 0xF4, 0x69, 0xC5, 0xE0, 0x84, 0x31, 0x4C, 0x0D, 0x8D, 0x39, 0x60, 0xEA, 0x06, 0xA3, 0x42, 0x6D, 0x8B, 0x3F, 0xE7, 0x62, 0xE0, 0x0D, 0x09, 0xBD, 0xA3, 0x74, 0xF3, 0xAE, 0x2C, 0xBE, 0xDE, 0x28, 0x38, 0xFF, 0x89, 0xD8, 0x1D, 0xEB, 0x30, 0x13, 0x09, 0x0E, 0x44, 0x19, 0x9A, 0xED, 0x60, 0x49, 0x63, 0xEA, 0xF9, 0x19, 0x91, 0x4C, 0xE0, 0x4F, 0x20, 0x7A, 0xC8, 0x2C, 0xD4, 0x35, 0x1F, 0xEF, 0x7B, 0x2D, 0x94, 0x39, 0x30, 0x66, 0xFE, 0x4D, 0x44, 0xE3, 0xCC, 0x59, 0x52, 0xE7, 0x5E, 0xB6, 0xF3, 0x71, 0x40, 0x58, 0x91, 0x5D, 0xE0, 0xEE, 0x18, 0x4D, 0x8C, 0x55, 0x30, 0x0F, 0x57, 0x6A, 0x8B, 0x82, 0xA8, 0x63, 0xE8, 0x1A, 0xF3, 0x34, 0x17, 0xBD, 0x4C, 0xFC, 0x94, 0xE7, 0xA6, 0x12, 0x63, 0xB3, 0x9F, 0x01, 0xF6, 0xE2, 0xE7, 0x07, 0x48, 0xB6, 0xE5, 0xE5, 0x9C, 0xF6, 0xCA, 0x01, 0xB0, 0x02, 0x8C, 0x93, 0xBB, 0xBC, 0xEB, 0xC5, 0x48, 0xF9, 0x87, 0xF1, 0x07, 0x55, 0xBF, 0x33, 0xCA, 0x58, 0x5C, 0xB4, 0x1C, 0xF5, 0x78, 0xDF, 0x5F, 0xFE, 0x37, 0x92, 0x4E, 0x3C, 0x2C, 0x07, 0x2E, 0xD1, 0xDA, 0xC9, 0x16, 0x21, 0x76, 0x97, 0x29, 0x71, 0xE7, 0x9B, 0x62, 0xFB, 0x20, 0x8F, 0x1A, 0x73, 0xBF, 0x03, 0x61, 0xE2, 0x99, 0x3D, 0xCC, 0xCD, 0x31, 0x10, 0xC3, 0x4D, 0x83, 0x9D, 0x18, 0xDD, 0x43, 0xA5, 0xE8, 0xF0, 0xD9, 0x41, 0xE9, 0x9A, 0xDC, 0xF4, 0x41, 0x40, 0x5F, 0x32, 0x10, 0x76, 0x71, 0xB2, 0xD8, 0xB2, 0x24, 0x4F, 0x7B, 0xA9, 0x2D, 0xCE, 0xD5, 0x87, 0xA2, 0x10, 0xFE, 0x8F, 0xF4, 0x3C, 0x61, 0x6A, 0xCB, 0x5E, 0x76, 0x6E, 0x6A, 0xF2, 0xCE, 0xB0, 0x35, 0x99, 0xBA, 0x3D, 0xE3, 0x76, 0xEB, 0x57, 0x35, 0xEF, 0x16, 0x14, 0x39, 0x53, 0xD1, 0xFD, 0xDB, 0x7E, 0x9F, 0x28, 0x74, 0xB0, 0xD6, 0x08, 0x3D, 0xD7, 0xEC, 0x43, 0x86, 0xAE, 0x00, 0x3F, 0x51, 0xCC, 0xF2, 0xD2, 0x1E, 0xF6, 0x05, 0x91, 0x63, 0xC5, 0x15, 0x21, 0x74, 0x42, 0x3F, 0x57, 0x11, 0x9D, 0x0F, 0xCE, 0x62, 0x7D, 0x76, 0x3D, 0x81, 0xC1, 0x0A, 0xA1, 0x32, 0x9F, 0x74, 0xC8, 0xD4, 0x45, 0x43, 0x7B, 0xA6, 0x71, 0x8A, 0x33, 0xDB, 0x6E, 0x79, 0x37, 0x51, 0x72, 0xB2, 0xAE, 0x35, 0x91, 0x82, 0x19, 0x78, 0xD5, 0x20, 0x82, 0x4E, 0x2D, 0x2F, 0xF8, 0x98, 0xB7, 0xF4, 0xC8, 0x67, 0xFF, 0x46, 0x27, 0x22, 0xBC, 0x07, 0xEA, 0xDA, 0xD3, 0x89, 0xA9, 0x10, 0xB6, 0xF6, 0x54, 0x29, 0xDA, 0x12, 0x97, 0x35, 0xFE, 0x04, 0x9E, 0x3E, 0xCB, 0x38, 0x89, 0xF6, 0x04, 0x7C, 0xF2, 0xBD, 0x2A, 0x88, 0xD5, 0x0A, 0x65, 0x1B, 0x32, 0x35, 0xD2, 0x48, 0x0E, 0x1D, 0xA5, 0xA3, 0x52, 0x47, 0xFA, 0x76, 0xC8, 0x31, 0x73, 0x63, 0x99, 0xD3, 0x7E, 0x8D, 0x03, 0x3C, 0x1D, 0x05, 0x1C, 0x9B, 0x6A, 0x99, 0xAB, 0x80, 0xB1, 0x31, 0x3F, 0xA2, 0x4C, 0x5C, 0x59, 0x76, 0x6E, 0x6C, 0x51, 0xA3, 0x8F, 0xE9, 0xF1, 0x18, 0x6A, 0x76, 0x7E, 0xEB, 0xD0, 0xD8, 0x80, 0x01, 0xAE, 0x02, 0x46, 0xCD, 0x4E, 0xBE, 0x2C, 0x97, 0x9D, 0xE8, 0x2C, 0x30, 0xBB, 0xDB, 0x98, 0xB4, 0x74, 0x4F, 0x11, 0xF9, 0xE6, 0x39, 0xED, 0xDD, 0x8C, 0x19, 0x4D, 0x79, 0x11, 0x20, 0x1A, 0x8F, 0xA7, 0x45, 0x99, 0x1B, 0x4D, 0x8A, 0x57, 0x09, 0xB6, 0x2A, 0x21, 0xB6, 0x3B, 0x97, 0x62, 0x91, 0x3D, 0x36, 0xCE, 0x99, 0x5C, 0x2D, 0x6B, 0x79, 0x15, 0x1E, 0x8D, 0x83, 0x83, 0x8C, 0xD1, 0xF3, 0x88, 0x40, 0xA9, 0x41, 0x72, 0x55, 0xDD, 0x16, 0x6B, 0x7A, 0x35, 0x84, 0x49, 0x90, 0x03, 0xFB, 0x62, 0x56, 0x11, 0x40, 0x4C, 0x95, 0xB9, 0x60, 0xDF, 0x0D, 0xB1, 0xBC, 0xF1, 0x57, 0x4B, 0x09, 0x65, 0xDB, 0xD8, 0x34, 0xEE, 0x14, 0x81, 0x17, 0xD5, 0xE0, 0x5A, 0x7C, 0xC7, 0xCC, 0x1A, 0x86, 0x56, 0x18, 0xA2, 0xBE, 0x48, 0x54, 0xDB, 0x89, 0x35, 0xCD, 0xA1, 0xE6, 0x8B, 0xD8, 0xD0, 0x9E, 0x72, 0xF0, 0xAC, 0x90, 0x53, 0xC8, 0x82, 0xC4, 0xAB, 0xA4, 0x00, 0x4A, 0x61, 0x4D, 0x10, 0x50, 0x53, 0x00, 0xB6, 0x17, 0x6C, 0xA1, 0xF3, 0x24, 0xE2, 0x2E, 0x78, 0x24, 0x29, 0x9F, 0x9C, 0x40, 0x75, 0x5B, 0x71, 0xD8, 0x2B, 0x67, 0x95, 0x47, 0xF0, 0x6A, 0xD4, 0x8B, 0xE6, 0x6D, 0x68, 0x07, 0x2C, 0x93, 0x90, 0x23, 0x3C, 0x93, 0x3F, 0x80, 0xA1, 0x4F, 0x8D, 0x4A, 0x6B, 0x0B, 0x4E, 0x19, 0x70, 0xE1, 0xAC, 0xC1, 0xBE, 0xA7, 0xF5, 0xD3, 0xBE, 0x22, 0x44, 0x48, 0xF8, 0x57, 0xBA, 0xB6, 0x8A, 0xEF, 0xA6, 0xD8, 0xCB, 0x81, 0x9B, 0x64, 0x29, 0x4A, 0x12, 0x99, 0x79, 0x16, 0xCD, 0xBF, 0x56, 0xE9, 0xA8, 0xD0, 0x02, 0xDD, 0x06, 0x5F, 0x12, 0xC6, 0x18, 0x23, 0xF4, 0xFC, 0x21, 0x45, 0x08, 0x23, 0x2E, 0x43, 0x1F, 0x0B, 0x68, 0x98, 0x47, 0x5B, 0xB5, 0xDD, 0x0D, 0x7D, 0x52, 0x8E, 0x84, 0x0C, 0x22, 0x80, 0x9A, 0xF7, 0xE1, 0x53, 0x63, 0x72, 0x4A, 0x61, 0x3A, 0xCC, 0xFB, 0xE2, 0xB3, 0x74, 0x38, 0xC1, 0x59, 0xCE, 0x14, 0xCB, 0x0C, 0x98, 0xBF, 0xD4, 0x99, 0xC0, 0x8D, 0xAC, 0x0C, 0xF4, 0x5D, 0x82, 0x1C, 0xC2, 0xFA, 0x47, 0x31, 0x9B, 0x6F, 0xB4, 0xCE, 0xD7, 0xE5, 0x98, 0x5E, 0xC8, 0x27, 0x4D, 0xE0, 0x90, 0x71, 0xD3, 0xC1, 0x0D, 0xA5, 0xBF, 0x9E, 0x52, 0x2B, 0x01, 0xCE, 0x91, 0xD6, 0x6B, 0x91, 0x79, 0x5D, 0x3D, 0x22, 0xC0, 0x04, 0x83, 0x45, 0x42, 0x75, 0xDD, 0x2B, 0xBD, 0xD7, 0xC2, 0xDC, 0xC4, 0xA1, 0x67, 0xE5, 0xD7, 0xFC, 0xDB, 0xB9, 0xF6, 0x20, 0x8C, 0xD4, 0xC9, 0xA4, 0x85, 0xFA, 0xAE, 0xB8, 0x09, 0xA7, 0x71, 0x1D, 0xAC, 0x28, 0x65, 0xCE, 0xD4, 0x30, 0x64, 0x74, 0xB2, 0x2B, 0x44, 0x48, 0xF8, 0x5D, 0xF3, 0x34, 0x17, 0xF3, 0xFA, 0xCE, 0x1C, 0x05, 0xD4, 0x27, 0x03, 0xED, 0x31, 0x30, 0x42, 0xA0, 0x5D, 0xE0, 0x36, 0x27, 0x40, 0x13, 0x01, 0x88, 0xEC, 0xB4, 0x45, 0xBB, 0x25, 0x5D, 0xC7, 0x6E, 0xE8, 0x44, 0x3F, 0x73, 0x31, 0x17, 0xF8, 0x35, 0x1F, 0x17, 0x60, 0x31, 0x75, 0x55, 0x4F, 0xEB, 0x00, 0xB7, 0xFF, 0x54, 0xD8, 0x07, 0x86, 0xF3, 0x05, 0xCD, 0xE1, 0x8C, 0xD5, 0xEC, 0x56, 0xEC, 0x09, 0x62, 0xA3, 0xE0, 0x44, 0x82, 0xDC, 0xE3, 0x62, 0x2D, 0x04, 0x0D, 0x24, 0xC4, 0x0F, 0x2E, 0x8A, 0x14, 0xA4, 0x47, 0x65, 0x9D, 0x6C, 0x56, 0x1F, 0x2F, 0xFE, 0xE6, 0x8F, 0x8D, 0x3D, 0xE5, 0x11, 0xB2, 0x3E, 0x8B, 0x17, 0x2A, 0x01, 0xA3, 0xED, 0xA4, 0xD3, 0x78, 0x0E, 0x74, 0xC6, 0x77, 0x24, 0x43, 0x30, 0xE9, 0xAE, 0xFF, 0x01, 0x9F, 0xE0, 0x7B, 0xE3, 0xD3, 0x3F, 0x32, 0x2F, 0x9C, 0xE2, 0x21, 0x4B, 0x9D, 0x9C, 0xFF, 0x99, 0xD0, 0x5A, 0x59, 0xE4, 0x75, 0x51, 0x43, 0x2A, 0xE7, 0x6F, 0x4C, 0xD4, 0xF8, 0xDD, 0x51, 0x52, 0x0F, 0xFE, 0x81, 0x1B, 0x4B, 0x93, 0xCD, 0x62, 0x19, 0xC8, 0x1B, 0x63, 0xB1, 0xD6, 0x27, 0x78, 0x5C, 0x2A, 0x0F, 0xC2, 0x2E, 0x3A, 0xEA, 0x86, 0xCE, 0xEE, 0x1F, 0x7F, 0xBC, 0x4E, 0xFC, 0xB4, 0x6D, 0xDF, 0xBC, 0xD8, 0x8A, 0x02, 0xF3, 0xB4, 0xE6, 0x7C, 0x5F, 0xF2, 0xE8, 0xDC, 0x68, 0xBF, 0x16, 0xC7, 0x46, 0x99, 0xBB, 0xB6, 0x28, 0x90, 0x2F, 0x72, 0xC3, 0xDE, 0xBC, 0x8B, 0xF5, 0xDF, 0x70, 0x6D, 0x47, 0xA6, 0x05, 0xA1, 0x07, 0xDA, 0xA0, 0x01, 0x41, 0x39, 0xCE, 0x40, 0xF0, 0xD4, 0x6D, 0x8D, 0x6D, 0xC7, }, .pkcs8_len = 0, .spki_len = 0, .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 = 3293, .sig = { 0xB0, 0x55, 0xB0, 0xE1, 0x76, 0x10, 0xBF, 0x54, 0xB3, 0x3B, 0x96, 0x09, 0x8D, 0x79, 0x6E, 0x98, 0xF7, 0x89, 0x9F, 0x48, 0x56, 0xCB, 0xC8, 0xD7, 0x04, 0xF9, 0xD7, 0x77, 0x8C, 0x18, 0x77, 0xF1, 0xE1, 0x24, 0xBF, 0x62, 0xA0, 0xD1, 0x7F, 0x01, 0x3B, 0xE4, 0x34, 0x0F, 0xD5, 0x7B, 0x4F, 0xA6, 0x22, 0x2D, 0x9C, 0xDB, 0x90, 0x28, 0xE8, 0xB0, 0x2B, 0x92, 0x6E, 0x15, 0x54, 0xD1, 0x45, 0xF4, 0x47, 0x98, 0xAA, 0xC2, 0xFA, 0xA2, 0x03, 0x3C, 0x4A, 0xEF, 0xB6, 0xCC, 0xB6, 0xCF, 0xE5, 0xC2, 0xA6, 0x23, 0x8E, 0xE7, 0x9C, 0x5C, 0xC2, 0xF0, 0xE8, 0x04, 0xBE, 0xD1, 0x7F, 0x75, 0xC1, 0xF3, 0x99, 0x4D, 0xD7, 0xE7, 0xA0, 0xF2, 0xA7, 0x03, 0x4C, 0x0C, 0x8C, 0x98, 0x64, 0x80, 0x40, 0x57, 0xE2, 0xE5, 0x57, 0x67, 0x3F, 0xDF, 0xD6, 0x64, 0x35, 0x6F, 0xAB, 0xD0, 0x51, 0xF9, 0x07, 0x5B, 0x34, 0x00, 0xA0, 0xC7, 0xE8, 0x45, 0x59, 0x55, 0x3E, 0xDF, 0x98, 0x9B, 0xFF, 0xD2, 0x11, 0x2B, 0x29, 0x60, 0x22, 0x03, 0x06, 0x6B, 0xDE, 0xA7, 0x84, 0x35, 0xEB, 0xC6, 0xE3, 0x81, 0x8C, 0xC9, 0x2D, 0x61, 0xBC, 0xC1, 0x25, 0xA8, 0x57, 0x5B, 0x5A, 0x8A, 0xEE, 0x42, 0x25, 0xFB, 0x9C, 0x62, 0x48, 0x3F, 0x3E, 0xD1, 0x18, 0x5A, 0x6A, 0x96, 0x82, 0x2E, 0x5E, 0xFC, 0x1B, 0xA7, 0xCD, 0x8D, 0x5F, 0xD8, 0xCC, 0x18, 0x7D, 0x2A, 0x26, 0x69, 0xCA, 0xDF, 0x58, 0xFA, 0xD6, 0x62, 0x89, 0x79, 0x4C, 0x96, 0x48, 0x5B, 0x2C, 0x46, 0x45, 0xC7, 0xD3, 0xD3, 0x56, 0x84, 0xB7, 0x42, 0x9B, 0x5E, 0xF3, 0x15, 0x45, 0x76, 0x99, 0xBE, 0x80, 0x30, 0xBC, 0x3D, 0xEB, 0x81, 0x66, 0x60, 0x2A, 0xC5, 0x48, 0x19, 0x82, 0x48, 0x83, 0xA2, 0x46, 0xC8, 0xA1, 0xA3, 0x4F, 0xC8, 0x9B, 0x2F, 0xE0, 0x32, 0x9B, 0x5C, 0xA0, 0x5D, 0x4E, 0x14, 0xB6, 0xDF, 0xFC, 0x21, 0x44, 0x60, 0x6A, 0xB3, 0x60, 0xBB, 0x3B, 0x8A, 0xC5, 0xA1, 0x78, 0x99, 0x8B, 0x46, 0x21, 0x81, 0x81, 0xCA, 0xC8, 0xDE, 0x4C, 0x29, 0x48, 0x30, 0xD4, 0x9D, 0x8F, 0x00, 0xEC, 0x12, 0xC3, 0xD3, 0xAC, 0x7B, 0x4A, 0x2C, 0x30, 0x17, 0x58, 0xE6, 0x8A, 0x56, 0x81, 0x17, 0x7F, 0xF2, 0xA7, 0x5D, 0x1D, 0x4B, 0xF1, 0xC9, 0x26, 0x88, 0x0B, 0x34, 0xB7, 0x28, 0xF7, 0xC3, 0x2E, 0x40, 0x60, 0x99, 0xD9, 0x5A, 0xB4, 0x48, 0x92, 0xF7, 0x48, 0xAA, 0xFE, 0xB5, 0x5B, 0x26, 0xBE, 0x31, 0x75, 0x12, 0xB0, 0x37, 0x7D, 0xBE, 0x89, 0x1A, 0xC5, 0x45, 0x6A, 0x92, 0x4C, 0x36, 0x83, 0x9B, 0xC8, 0x01, 0xDB, 0x2A, 0xC5, 0xB7, 0x11, 0x0A, 0x9B, 0xAF, 0x4C, 0x3C, 0x49, 0xD0, 0x05, 0x39, 0x3C, 0xDF, 0xFA, 0xD4, 0xF9, 0x68, 0x61, 0x20, 0xF4, 0xFD, 0xE0, 0x16, 0x8A, 0x9E, 0x45, 0x8E, 0x72, 0x9F, 0x4B, 0x0A, 0xE1, 0xA4, 0xC4, 0x12, 0x4C, 0xA3, 0x4D, 0xF5, 0xB6, 0x3B, 0xC2, 0xE7, 0xCB, 0xEE, 0x01, 0xA3, 0x8D, 0x31, 0xA0, 0xED, 0x8D, 0x3C, 0x4C, 0x38, 0x03, 0xC3, 0xC2, 0x4C, 0x5C, 0xAD, 0xEB, 0xE3, 0xE9, 0x1A, 0x8D, 0x2E, 0x1B, 0xFC, 0xF0, 0x50, 0x8A, 0x27, 0x88, 0xD8, 0x9D, 0xFE, 0xA2, 0x0F, 0xD6, 0x38, 0x18, 0xB8, 0x39, 0x60, 0xA6, 0xCF, 0x93, 0x08, 0x72, 0xB9, 0x57, 0x85, 0x57, 0x50, 0x88, 0xCF, 0x7E, 0x8B, 0x63, 0xA1, 0x89, 0x5A, 0x8C, 0x1C, 0x77, 0xA8, 0x4C, 0xB9, 0xCC, 0x6B, 0xD1, 0xD5, 0xFA, 0x93, 0x96, 0x77, 0xAF, 0x17, 0xEE, 0xBE, 0x2D, 0x2E, 0xE6, 0x84, 0xC6, 0x60, 0x15, 0xF1, 0xBB, 0x14, 0x2A, 0x72, 0x77, 0x79, 0x58, 0x0D, 0xA1, 0xBC, 0x5E, 0x97, 0x5A, 0xA5, 0x6E, 0xF5, 0xD7, 0x7A, 0x84, 0x07, 0xE5, 0x06, 0xA5, 0xDE, 0xEE, 0xA5, 0xE8, 0xB0, 0x79, 0x7F, 0x10, 0x64, 0x60, 0x05, 0x64, 0x80, 0x22, 0x21, 0x3C, 0xCB, 0x86, 0xA7, 0x7D, 0xF5, 0xD7, 0xB3, 0x16, 0xE8, 0x5D, 0x55, 0xB9, 0xDA, 0x0F, 0xDF, 0xD5, 0xF2, 0x35, 0x52, 0xDD, 0x47, 0xCC, 0xFA, 0x96, 0x4A, 0xC3, 0x9E, 0xE6, 0x84, 0xBD, 0x63, 0x79, 0x3B, 0xB7, 0xDC, 0xAB, 0x69, 0xBE, 0x7E, 0xD9, 0x4D, 0x8D, 0xDB, 0xA1, 0x85, 0xE8, 0x0A, 0x7A, 0xAE, 0xE7, 0x4E, 0x87, 0x8F, 0x50, 0xA2, 0x13, 0xF3, 0xB4, 0xFF, 0xB6, 0x6E, 0x6D, 0x34, 0xA3, 0x9C, 0x0A, 0xAE, 0x2B, 0x1D, 0x61, 0x36, 0x6F, 0xE4, 0x03, 0x53, 0x9C, 0x69, 0xA0, 0x88, 0x75, 0x1F, 0x56, 0x90, 0x1A, 0x10, 0xBC, 0x44, 0x23, 0x13, 0xA3, 0x5C, 0x2D, 0x83, 0x54, 0x76, 0xD0, 0xFA, 0xD4, 0x47, 0xC7, 0x70, 0x08, 0x0F, 0xA4, 0x1B, 0xF3, 0x8D, 0x68, 0x5F, 0xB3, 0x1B, 0x11, 0xA7, 0xD2, 0xE6, 0xFB, 0x52, 0x67, 0x3D, 0x16, 0x87, 0x23, 0xE6, 0x89, 0x08, 0xC0, 0x67, 0x2A, 0x0F, 0x36, 0xE2, 0x5A, 0x19, 0x9E, 0x17, 0xA6, 0xFE, 0x5B, 0x8B, 0x82, 0x5B, 0x96, 0xEA, 0xB7, 0xAB, 0x4B, 0x7D, 0x83, 0x81, 0xDB, 0xC5, 0x00, 0x31, 0xA5, 0xF2, 0xE0, 0x9E, 0x4B, 0xE8, 0x71, 0x53, 0x3A, 0xDC, 0x5D, 0x08, 0xD0, 0x09, 0x42, 0x9B, 0xBF, 0x5C, 0x86, 0xF8, 0x12, 0x0D, 0x09, 0x5C, 0x8E, 0xEC, 0xBE, 0xF3, 0xE0, 0x99, 0xDE, 0x61, 0x8D, 0x43, 0x77, 0x24, 0x1B, 0x50, 0x36, 0x9E, 0xDE, 0x51, 0xAA, 0x74, 0xAB, 0x96, 0x65, 0x89, 0xE2, 0xC6, 0x87, 0xD6, 0xC0, 0x9F, 0xAC, 0x9C, 0x6D, 0x6C, 0x54, 0x61, 0xF5, 0xA6, 0x30, 0x08, 0xE9, 0x83, 0x5F, 0xF4, 0xB5, 0xBD, 0x42, 0x65, 0xF1, 0x12, 0x8C, 0x09, 0x2C, 0x27, 0xD4, 0xDA, 0x50, 0x8F, 0xD4, 0xF5, 0x0E, 0xFA, 0x74, 0xA7, 0x31, 0x57, 0x05, 0x9A, 0x4B, 0x2F, 0x41, 0xFE, 0x8B, 0xF9, 0x67, 0x16, 0x79, 0x69, 0xB9, 0x3B, 0xF5, 0x20, 0x45, 0x84, 0x26, 0x90, 0x32, 0x42, 0x9E, 0x35, 0x77, 0x70, 0x4B, 0xDF, 0x68, 0x98, 0x00, 0xDD, 0x8B, 0xDE, 0x82, 0x6B, 0x74, 0xCE, 0xF5, 0x10, 0xA1, 0xE0, 0x87, 0x02, 0x3F, 0x09, 0x26, 0xE9, 0x7F, 0x37, 0x92, 0x6B, 0x16, 0xEF, 0x78, 0x6C, 0x37, 0xEC, 0x21, 0xF2, 0x40, 0x71, 0x04, 0xD3, 0x95, 0x4A, 0x7A, 0x07, 0xC3, 0x0D, 0xE2, 0xD6, 0x78, 0x84, 0x02, 0xD7, 0x1A, 0x56, 0x2E, 0xA5, 0x4C, 0x79, 0xB4, 0x19, 0x7D, 0x20, 0x2C, 0x97, 0x72, 0x5D, 0x2D, 0x8B, 0x7E, 0x73, 0x32, 0xF3, 0xFF, 0x1A, 0x6F, 0xAD, 0x49, 0xA4, 0xC0, 0x0C, 0xD1, 0xA4, 0x47, 0x65, 0x1B, 0x8E, 0x08, 0xD8, 0x50, 0x6B, 0xCA, 0x82, 0x3E, 0x10, 0xEF, 0x41, 0x16, 0xE6, 0xCF, 0x49, 0x67, 0x5C, 0x43, 0x30, 0xA1, 0xDE, 0x19, 0x08, 0xDD, 0xB5, 0x9F, 0x7E, 0xA5, 0xF8, 0x9C, 0x94, 0xCE, 0x50, 0x0F, 0x82, 0xB4, 0x3C, 0xE7, 0x89, 0x15, 0x84, 0x73, 0xB9, 0xE0, 0x79, 0x05, 0xD8, 0xE8, 0x61, 0x5E, 0xDE, 0xF0, 0x21, 0x38, 0x3F, 0xC3, 0x1D, 0x61, 0x8C, 0x5C, 0xE6, 0x25, 0x65, 0x3B, 0x40, 0xC2, 0x1B, 0xD7, 0xE0, 0xBC, 0x78, 0x3D, 0x93, 0xBE, 0xC1, 0xB7, 0xA5, 0xB4, 0xBB, 0xC6, 0xC2, 0x81, 0xB7, 0x77, 0x55, 0x47, 0x39, 0x0E, 0xF3, 0xD3, 0x0E, 0x27, 0x73, 0x99, 0x36, 0x93, 0x08, 0xD8, 0xA1, 0xCD, 0xC2, 0xE1, 0xDB, 0xD6, 0xF1, 0x58, 0x97, 0x0A, 0xC2, 0xAC, 0x5C, 0x2C, 0x94, 0x81, 0x97, 0x5B, 0x80, 0x95, 0x80, 0xC0, 0xEA, 0x89, 0x91, 0x2C, 0x07, 0x66, 0xF4, 0x58, 0x30, 0xA8, 0x96, 0x3F, 0xBB, 0x7E, 0x17, 0xD8, 0x43, 0x85, 0x17, 0x5A, 0x6E, 0x07, 0x54, 0x68, 0x3C, 0xBF, 0xBB, 0xA6, 0x36, 0x45, 0x94, 0xF6, 0xB5, 0x00, 0x5C, 0x15, 0xBD, 0x5F, 0x85, 0x73, 0x2B, 0x5A, 0x63, 0xF2, 0x62, 0x67, 0xAB, 0x17, 0x04, 0x8C, 0x61, 0x99, 0x20, 0x00, 0x19, 0xAD, 0xD6, 0xA4, 0xD1, 0xAC, 0xD0, 0x40, 0x5C, 0x38, 0x76, 0x66, 0xE8, 0x71, 0x11, 0xB9, 0x82, 0x5A, 0xFB, 0x97, 0x51, 0xCD, 0x3F, 0x9D, 0x8A, 0x45, 0xC6, 0xB2, 0x08, 0xD2, 0xD3, 0x33, 0xB6, 0xC5, 0x9F, 0x98, 0xBC, 0xF2, 0x84, 0xC8, 0x54, 0xCF, 0x7D, 0x4F, 0x67, 0x54, 0xFD, 0x75, 0xEE, 0x06, 0x8C, 0x88, 0x67, 0x8E, 0xE7, 0x56, 0x5B, 0x47, 0xB3, 0x6E, 0x68, 0xA1, 0xFD, 0x7B, 0xB6, 0x0E, 0x2A, 0x8E, 0x0D, 0xF7, 0x12, 0x70, 0x20, 0xF5, 0xC6, 0x27, 0x7B, 0x3E, 0xE0, 0x58, 0x77, 0x3F, 0x9B, 0xBF, 0x1D, 0xC2, 0xE3, 0x98, 0xBC, 0x30, 0x12, 0x02, 0x12, 0x1C, 0x69, 0x9C, 0x00, 0x37, 0x9D, 0x83, 0x50, 0x09, 0x96, 0x26, 0xF9, 0x09, 0x23, 0x65, 0x92, 0x40, 0x08, 0xB1, 0xA9, 0xCD, 0x9F, 0x87, 0x87, 0x82, 0x2B, 0xEE, 0x96, 0x1A, 0xBA, 0x23, 0x9C, 0xDC, 0xB4, 0x18, 0xE9, 0x38, 0x60, 0xEF, 0x34, 0x8A, 0x5E, 0x96, 0x45, 0x38, 0x9A, 0x0A, 0x87, 0x8D, 0x39, 0x4F, 0x36, 0x5A, 0xEB, 0xFE, 0x28, 0x0B, 0xEE, 0x68, 0x74, 0xA3, 0x05, 0x4C, 0xD9, 0x8C, 0xBD, 0x87, 0x16, 0x66, 0x28, 0x04, 0x72, 0x9F, 0xD4, 0x6F, 0xCE, 0xA9, 0xC4, 0xCF, 0x92, 0x9F, 0x2F, 0x12, 0x00, 0x06, 0xCE, 0xBC, 0xC0, 0xBF, 0x75, 0x69, 0x2D, 0x63, 0xC0, 0x44, 0x63, 0x5D, 0x1A, 0x1D, 0xB6, 0x1A, 0xD1, 0x78, 0x94, 0x15, 0xE5, 0xF2, 0x24, 0x2B, 0x74, 0x00, 0xA8, 0xA7, 0x93, 0x68, 0xED, 0x60, 0x2C, 0x33, 0x64, 0x92, 0xF2, 0x70, 0x34, 0x5B, 0xE9, 0x8B, 0x2D, 0xD6, 0xEA, 0x8E, 0x4C, 0x53, 0xAC, 0xA3, 0x6E, 0x3C, 0x9B, 0xA2, 0x88, 0xF2, 0x75, 0x86, 0x13, 0x4C, 0xF0, 0xB5, 0xCA, 0x9B, 0xA1, 0xEE, 0xDF, 0x20, 0xD1, 0xAB, 0x4F, 0x2D, 0x08, 0xF3, 0xB0, 0x42, 0xDB, 0x89, 0xDE, 0xCF, 0xFD, 0xD2, 0x38, 0x54, 0xF3, 0x51, 0x20, 0xAD, 0xDE, 0x16, 0x03, 0x33, 0x5D, 0x56, 0x8D, 0xA9, 0x58, 0x91, 0xCF, 0x3A, 0xB2, 0x1D, 0x9A, 0xFA, 0xF6, 0x6C, 0x28, 0x6C, 0x13, 0x00, 0x01, 0x9C, 0xA9, 0xBA, 0xF2, 0xFF, 0x3F, 0x67, 0x25, 0x23, 0x0C, 0x4B, 0x26, 0x98, 0x92, 0xF7, 0xA3, 0xDF, 0xD6, 0xEA, 0xB7, 0x4C, 0x31, 0x4A, 0x86, 0xF8, 0xB4, 0x7E, 0xAE, 0x49, 0xF4, 0x19, 0xE4, 0xA2, 0x91, 0x7B, 0x98, 0x4F, 0xE9, 0xA0, 0x03, 0x32, 0xAF, 0xB7, 0xA5, 0x6E, 0x5E, 0x67, 0x52, 0x23, 0xAE, 0xCC, 0x50, 0x34, 0x20, 0xAF, 0x8B, 0x39, 0xFA, 0xA9, 0x20, 0xE3, 0xAD, 0xA1, 0xA4, 0x3C, 0xE7, 0xBD, 0x1F, 0x7D, 0xF2, 0x30, 0x1C, 0x90, 0x27, 0xCC, 0x1C, 0xE5, 0x66, 0x6E, 0xB0, 0x93, 0x62, 0x10, 0xAF, 0xA5, 0x9E, 0x10, 0xF3, 0x07, 0xCA, 0x1F, 0x78, 0x63, 0xED, 0xD6, 0xC3, 0xBB, 0x8F, 0x5D, 0x63, 0xC0, 0xCF, 0x0E, 0xA8, 0xF0, 0x6E, 0xF0, 0x8C, 0xCC, 0x24, 0xC1, 0x4F, 0x29, 0x5D, 0xD2, 0x86, 0xFD, 0x9F, 0x4E, 0x71, 0x02, 0x10, 0x9D, 0x53, 0xFF, 0x5E, 0xFF, 0x4A, 0x01, 0xDC, 0xAA, 0xD5, 0xFB, 0x60, 0x55, 0xA0, 0x70, 0x3C, 0xD4, 0x71, 0xB2, 0x0B, 0x5F, 0xA4, 0x56, 0x0B, 0xDE, 0xAA, 0x13, 0x13, 0xC7, 0x64, 0x7A, 0xE7, 0x56, 0xAE, 0x85, 0x91, 0x57, 0x9E, 0xA5, 0x12, 0x0E, 0x09, 0xD6, 0x79, 0x48, 0x40, 0x62, 0x9B, 0x9F, 0xEF, 0xEF, 0xC2, 0x0D, 0xB5, 0x94, 0xBA, 0xDC, 0xD1, 0x29, 0xEC, 0x49, 0x1C, 0x3C, 0xF7, 0x5A, 0xB4, 0x0C, 0x47, 0x2A, 0xD2, 0x2C, 0x2D, 0xED, 0xBC, 0x77, 0xBA, 0x26, 0x71, 0xC8, 0x43, 0x48, 0x65, 0x60, 0xDC, 0x76, 0x52, 0x31, 0xBF, 0x5F, 0xDC, 0xDB, 0xCC, 0x77, 0xC8, 0x30, 0x0F, 0x9D, 0x2B, 0x53, 0xEC, 0x34, 0x46, 0xD8, 0x2F, 0x08, 0x7B, 0x89, 0xBD, 0x99, 0x2F, 0x7A, 0xB0, 0xA7, 0x80, 0xB5, 0x38, 0x81, 0x18, 0xBB, 0xF1, 0x7C, 0xCB, 0xEC, 0x2D, 0x19, 0x6F, 0x3E, 0xDC, 0x47, 0x8F, 0xB9, 0x47, 0xD8, 0x30, 0x2B, 0x04, 0x0A, 0x60, 0xD0, 0xBA, 0xB8, 0x5C, 0x1C, 0x5C, 0x47, 0x4E, 0xAB, 0x41, 0xE0, 0x64, 0x41, 0x06, 0x95, 0xC6, 0x0E, 0x1A, 0xCE, 0xE7, 0x9E, 0x13, 0x7D, 0x70, 0x2E, 0x4A, 0x31, 0x39, 0x68, 0xA5, 0x57, 0xB9, 0x7C, 0xE6, 0x43, 0x31, 0x88, 0x8B, 0x52, 0x89, 0xCC, 0xB3, 0x7A, 0x66, 0x25, 0xE5, 0x22, 0x73, 0x71, 0x1B, 0x84, 0x64, 0x58, 0xD5, 0xD8, 0xBA, 0x1A, 0xE4, 0x96, 0x53, 0x78, 0xCB, 0xE9, 0x18, 0xBF, 0x0F, 0x4B, 0xEE, 0xE1, 0xBD, 0x08, 0xFE, 0xCC, 0x66, 0x06, 0xD2, 0xF3, 0x97, 0x0C, 0x87, 0x4B, 0x0A, 0x09, 0xC4, 0x10, 0xE0, 0xC7, 0xD3, 0xD6, 0x00, 0x4D, 0x93, 0xF0, 0x6F, 0xBC, 0x25, 0x8F, 0x96, 0x4A, 0x96, 0x19, 0xB2, 0xC6, 0xCA, 0x28, 0xA3, 0xA2, 0x52, 0x9B, 0xF4, 0x4F, 0xB9, 0xF2, 0x44, 0x38, 0x2C, 0xBE, 0xF9, 0x93, 0xC4, 0x18, 0xA3, 0x88, 0x0F, 0x8D, 0x5F, 0xBA, 0x41, 0xF0, 0x58, 0x24, 0xF4, 0xF3, 0x3B, 0x24, 0xB8, 0x86, 0xD1, 0x15, 0xB8, 0x19, 0x81, 0x6C, 0x9B, 0x7D, 0xB5, 0x1F, 0x2A, 0xA0, 0xCC, 0x6B, 0x01, 0xB6, 0xAB, 0x21, 0x1F, 0xAD, 0x55, 0x28, 0x4C, 0xDC, 0x04, 0x52, 0x47, 0x85, 0x90, 0x59, 0xBD, 0x36, 0x88, 0x7F, 0x3A, 0xE2, 0xB6, 0xCF, 0x7F, 0x87, 0xEC, 0x2D, 0xF3, 0xC8, 0x9D, 0x43, 0xD2, 0x7E, 0x5E, 0x48, 0x88, 0xBA, 0xE6, 0x5B, 0x69, 0x24, 0xFA, 0x5D, 0xF0, 0xB2, 0xED, 0x44, 0xE3, 0xE3, 0x79, 0x4B, 0x68, 0x90, 0xF9, 0x33, 0xF9, 0xFB, 0xA7, 0xA7, 0x89, 0xFC, 0x63, 0xCE, 0xB7, 0x43, 0x60, 0xD4, 0xAC, 0x9C, 0x64, 0xF1, 0x0C, 0xFC, 0x0A, 0xB3, 0x74, 0xC7, 0x12, 0xA3, 0xCC, 0x6C, 0x87, 0x6B, 0x22, 0xF6, 0xD9, 0xFE, 0xF1, 0xC3, 0x87, 0xBF, 0x6B, 0xDE, 0x75, 0x79, 0x2A, 0xF9, 0x09, 0x4E, 0xC1, 0x7E, 0xB8, 0xB5, 0x5D, 0x35, 0x5F, 0xF0, 0xAE, 0x9D, 0x62, 0x11, 0x1A, 0xD8, 0xA3, 0xCB, 0xA4, 0xF5, 0x66, 0x3D, 0x94, 0xA3, 0x8A, 0x43, 0xE3, 0x52, 0x97, 0x9D, 0xB3, 0xDF, 0xDF, 0x32, 0x98, 0x85, 0x34, 0xCD, 0x45, 0xFD, 0x43, 0x6E, 0x69, 0x9C, 0x46, 0x7F, 0x6D, 0xDD, 0x50, 0x76, 0xB4, 0xE5, 0xF7, 0xF3, 0x82, 0xAF, 0x45, 0xD3, 0x17, 0x0F, 0x25, 0xB5, 0x41, 0x50, 0xD6, 0x4D, 0x35, 0xA8, 0x18, 0x55, 0xF4, 0xB2, 0x2B, 0xAC, 0x9F, 0xA1, 0x7D, 0xEF, 0xAD, 0x73, 0xB1, 0x4B, 0x15, 0x84, 0x0E, 0x08, 0x70, 0xDA, 0xF5, 0xB9, 0x2A, 0x30, 0xD2, 0x37, 0xBF, 0x0C, 0x08, 0xCB, 0x8C, 0x9E, 0xBD, 0x41, 0x59, 0xD3, 0xBB, 0x2D, 0x47, 0x4E, 0x3E, 0x10, 0x6C, 0xC4, 0x68, 0xE6, 0xA2, 0x43, 0x35, 0x12, 0x48, 0x10, 0xF4, 0x86, 0xA6, 0x47, 0x3C, 0x26, 0xA5, 0xD7, 0x83, 0x26, 0x4F, 0xD8, 0xA3, 0x68, 0x5C, 0x09, 0xD4, 0xEF, 0x77, 0xBD, 0x9A, 0x9A, 0x5C, 0x0B, 0x57, 0x8C, 0x95, 0xE7, 0xCA, 0xA3, 0x4E, 0xCE, 0x46, 0xF8, 0x48, 0x37, 0x47, 0xEE, 0x58, 0x4D, 0xBB, 0x2D, 0x97, 0x20, 0x76, 0xD7, 0x63, 0xB0, 0xB5, 0x50, 0xE2, 0xCA, 0xE8, 0x34, 0x9E, 0x06, 0x09, 0xF1, 0x4F, 0x0A, 0x8F, 0x51, 0x10, 0xCA, 0xA4, 0xCD, 0xAB, 0xDD, 0x44, 0x40, 0xAD, 0x16, 0x9C, 0x2A, 0xBE, 0x86, 0xEE, 0x1C, 0x68, 0x0D, 0x6E, 0x94, 0x88, 0x29, 0x64, 0xD8, 0x70, 0xCF, 0xEF, 0x70, 0xA4, 0xF4, 0xC0, 0x4B, 0x49, 0xCC, 0x4A, 0x4F, 0xF6, 0xD4, 0xB9, 0xE3, 0x69, 0x18, 0xC1, 0x8A, 0x6D, 0x5C, 0x4A, 0xF4, 0x7C, 0xCF, 0x09, 0xFF, 0x64, 0xC7, 0x7A, 0xE3, 0xBF, 0xBC, 0xFA, 0x50, 0x4E, 0x16, 0x9E, 0xAB, 0xB3, 0x06, 0x95, 0x1A, 0x28, 0xAF, 0xF2, 0xFA, 0xB7, 0xA5, 0xBA, 0x47, 0x6F, 0x56, 0x50, 0xBC, 0x7D, 0xA1, 0x92, 0xD4, 0xB0, 0xEB, 0xFA, 0xAB, 0xAB, 0xE7, 0x72, 0xED, 0xE2, 0xA1, 0x07, 0x1D, 0x5C, 0x4F, 0xC3, 0x3C, 0x25, 0x25, 0xE4, 0x0D, 0x08, 0x2F, 0xA9, 0x35, 0xBD, 0x32, 0xFF, 0x25, 0x06, 0xB3, 0xA1, 0x31, 0xE3, 0x15, 0x81, 0xB6, 0xC9, 0x44, 0xC2, 0x5F, 0x2D, 0x81, 0x75, 0x5C, 0x39, 0xD3, 0xBF, 0xC0, 0xC6, 0xDE, 0x93, 0xE3, 0x55, 0x57, 0xAB, 0x1C, 0xF3, 0x47, 0x2B, 0x4A, 0x32, 0x98, 0x09, 0x86, 0xA3, 0x1F, 0x88, 0x28, 0x73, 0x52, 0x19, 0x38, 0xD8, 0xBF, 0xFE, 0x97, 0x36, 0x9F, 0xE2, 0x97, 0x46, 0xAC, 0xFC, 0x8F, 0x12, 0xDE, 0xEE, 0x0E, 0x9A, 0xC3, 0xE1, 0x67, 0x60, 0x20, 0x22, 0x43, 0x43, 0x58, 0xF9, 0xDC, 0x33, 0xB2, 0xD4, 0x40, 0x8F, 0xD0, 0x89, 0x54, 0xF9, 0x74, 0x5A, 0x0B, 0xD6, 0x5B, 0xC7, 0x7E, 0xE8, 0xBE, 0xA7, 0x1B, 0xFA, 0x76, 0x40, 0xC1, 0x35, 0xED, 0x19, 0xCC, 0x2F, 0x1C, 0x22, 0xE0, 0xD6, 0xB0, 0x2D, 0xA6, 0xDF, 0x24, 0xDB, 0x05, 0xA6, 0x48, 0x0D, 0xB4, 0x52, 0x27, 0xDC, 0xC9, 0x7A, 0xDC, 0xEC, 0xB3, 0x91, 0x7F, 0x08, 0x6C, 0x6E, 0x98, 0x08, 0x3A, 0x21, 0x2D, 0x54, 0xDC, 0x4B, 0x81, 0x0F, 0x68, 0x9C, 0x4F, 0x98, 0x43, 0xD2, 0xFB, 0x9F, 0x57, 0x26, 0xB8, 0x76, 0x64, 0xCD, 0x32, 0x2C, 0x28, 0xB6, 0xF1, 0xE0, 0x1F, 0xA9, 0x1A, 0xB3, 0x50, 0x2F, 0xAC, 0x01, 0xAF, 0xCF, 0x52, 0xC9, 0xB3, 0xD2, 0xAA, 0x20, 0xE1, 0xB3, 0x85, 0xEF, 0x47, 0x0C, 0xB3, 0x30, 0x78, 0x19, 0x8B, 0x5C, 0x43, 0x95, 0xA0, 0x32, 0x9C, 0xB1, 0x0F, 0x9A, 0x4E, 0x96, 0xF4, 0x3E, 0x51, 0x16, 0x1F, 0xAA, 0xE1, 0x90, 0xEB, 0x8C, 0x39, 0x69, 0xCE, 0xC2, 0x97, 0x7B, 0x08, 0xF6, 0x8D, 0x24, 0xEF, 0xCE, 0x56, 0x65, 0x11, 0xFE, 0xB6, 0x54, 0xCC, 0x5F, 0xA1, 0xFE, 0x67, 0x57, 0x1F, 0x58, 0xD8, 0x48, 0xBE, 0x7C, 0x56, 0x4A, 0xF5, 0x66, 0x39, 0x06, 0x39, 0xF8, 0x16, 0x92, 0xA7, 0xB7, 0xC0, 0xF9, 0xF5, 0xAD, 0x85, 0xB8, 0x2F, 0x6A, 0x83, 0x2C, 0x9D, 0xA5, 0x2B, 0x6A, 0x47, 0xD2, 0x3F, 0x9E, 0xCF, 0xAD, 0x44, 0x99, 0x83, 0xC9, 0x39, 0x65, 0x46, 0x58, 0xB1, 0x0A, 0xDD, 0xC0, 0xB4, 0xAA, 0xDB, 0xB7, 0xB8, 0x5E, 0xA6, 0x02, 0xDA, 0x76, 0x17, 0xD1, 0xB4, 0xA4, 0x5D, 0x86, 0xB8, 0xD0, 0x9D, 0x2C, 0x5A, 0x40, 0x2A, 0x67, 0x58, 0xE0, 0x6A, 0xAA, 0x15, 0x4A, 0xD0, 0x96, 0x67, 0x8C, 0xBD, 0xD9, 0xCA, 0x6F, 0x5D, 0x92, 0xB0, 0xD7, 0x38, 0x50, 0x1E, 0x18, 0xC1, 0xDC, 0xD2, 0x68, 0xDE, 0x01, 0x12, 0x00, 0x59, 0x48, 0x2D, 0xFC, 0xD1, 0x2B, 0x9B, 0xF2, 0x6E, 0x1C, 0xF3, 0xB0, 0x99, 0x70, 0xC4, 0x3C, 0xF5, 0x62, 0x0C, 0xA8, 0xD4, 0xE2, 0xFD, 0x31, 0xE5, 0xA8, 0x9E, 0xF8, 0xDD, 0x93, 0x17, 0xE6, 0xCF, 0x55, 0xB3, 0xFB, 0x19, 0xC0, 0x72, 0xE9, 0xD5, 0xDD, 0xB9, 0x74, 0xEF, 0x60, 0x82, 0x71, 0x1E, 0x99, 0x15, 0xD3, 0x43, 0x4E, 0x7D, 0x34, 0xE7, 0xC3, 0x25, 0xA8, 0xD9, 0x2B, 0x66, 0xB0, 0x83, 0xDF, 0xD6, 0xCF, 0xD1, 0x62, 0xFD, 0x66, 0x65, 0xDF, 0x9A, 0xBF, 0x18, 0x8F, 0x2D, 0xC5, 0x83, 0xFD, 0xFA, 0xBC, 0x99, 0x7D, 0x78, 0x70, 0xE9, 0x11, 0xD3, 0xC5, 0xEB, 0x5B, 0xDF, 0x80, 0xBA, 0x8D, 0xE6, 0xC4, 0x6C, 0x88, 0xE0, 0x49, 0xD3, 0x9E, 0x2F, 0xA2, 0x96, 0xCB, 0xE0, 0x69, 0xCA, 0x69, 0x49, 0x4F, 0x89, 0x08, 0x87, 0x67, 0x9C, 0xB3, 0xB0, 0xE6, 0x04, 0x3D, 0x02, 0xB8, 0xF2, 0x4A, 0x3F, 0x14, 0x83, 0xC9, 0x47, 0x81, 0xB6, 0xB0, 0x1A, 0xF8, 0x01, 0x60, 0x63, 0x99, 0xC3, 0xAC, 0x62, 0x60, 0x3D, 0x86, 0xF7, 0xD5, 0x29, 0x55, 0xC3, 0x12, 0x59, 0x58, 0xC0, 0x4D, 0x57, 0x2A, 0x34, 0x63, 0x4C, 0xD2, 0x36, 0x73, 0x58, 0xA8, 0x6A, 0xD2, 0xB4, 0x81, 0xB3, 0x26, 0xF2, 0xF8, 0x9D, 0x4B, 0x4D, 0xC0, 0x94, 0xE9, 0x89, 0x18, 0xB5, 0xAE, 0xD8, 0xF4, 0xEB, 0xA4, 0x9C, 0x56, 0x17, 0x2B, 0x16, 0x51, 0xB6, 0x60, 0xB8, 0x70, 0x47, 0xBA, 0x65, 0x2A, 0x64, 0x0C, 0xA7, 0xB0, 0x69, 0x97, 0x1F, 0xA2, 0xA6, 0x6C, 0x01, 0x95, 0x67, 0xC3, 0x8B, 0x7F, 0x5D, 0x26, 0x21, 0xE7, 0xCB, 0x4B, 0xAA, 0x41, 0x40, 0xEF, 0x5B, 0xB4, 0x91, 0x96, 0x0D, 0x80, 0xF5, 0x01, 0x01, 0xA0, 0x04, 0xE0, 0x79, 0xF5, 0xB5, 0x1F, 0x39, 0x4B, 0x02, 0x9E, 0x3E, 0xBF, 0xBD, 0xFC, 0x33, 0x59, 0x4E, 0x95, 0xF6, 0xA3, 0x7B, 0xC4, 0xF6, 0xA3, 0x29, 0xB5, 0xC1, 0xD8, 0xE0, 0x41, 0x45, 0x40, 0x3D, 0x33, 0xA5, 0xC7, 0x04, 0xB3, 0x43, 0x51, 0x82, 0x31, 0xB0, 0x86, 0x46, 0xE4, 0xDA, 0x9D, 0x5A, 0x4E, 0xCA, 0xBC, 0xF5, 0x0F, 0x2B, 0x39, 0x21, 0xE8, 0x5A, 0x84, 0xC4, 0x09, 0xA1, 0xF6, 0x27, 0xEE, 0x0F, 0x6E, 0xB1, 0xB1, 0xB9, 0xA9, 0xFC, 0xCA, 0x9C, 0xBD, 0x65, 0xCE, 0xA9, 0x00, 0x88, 0x79, 0x7D, 0xF7, 0x51, 0x0B, 0x86, 0x1B, 0x86, 0xCA, 0x4E, 0x99, 0x8A, 0xF0, 0x75, 0x94, 0x9B, 0x16, 0x7C, 0xBD, 0x66, 0xBC, 0xBE, 0x4C, 0x51, 0x30, 0x34, 0x7D, 0x87, 0x7C, 0xE5, 0xA8, 0x47, 0x9F, 0x4D, 0x56, 0xD3, 0x98, 0x14, 0x6C, 0xE2, 0xF1, 0xA7, 0x85, 0x42, 0x8D, 0xDD, 0xED, 0xAD, 0x66, 0xAA, 0xB2, 0x87, 0xCA, 0xAE, 0x59, 0x14, 0x24, 0x35, 0x56, 0x1A, 0x40, 0x1B, 0x50, 0x93, 0x43, 0x92, 0xD4, 0x32, 0x9C, 0x3C, 0x21, 0xAE, 0x48, 0x32, 0x86, 0x53, 0xE3, 0xAE, 0x57, 0x5E, 0x18, 0x1D, 0xB3, 0x89, 0xBE, 0x43, 0x97, 0x16, 0xF6, 0xE3, 0xF3, 0xE2, 0xDC, 0x61, 0xE4, 0xEC, 0xCF, 0xE5, 0x48, 0xAB, 0x7D, 0x71, 0x5E, 0xAB, 0x49, 0xCF, 0xD7, 0x64, 0x1D, 0xC3, 0x7F, 0x5C, 0x0C, 0x0C, 0x34, 0x96, 0x5C, 0x06, 0xA1, 0x56, 0x70, 0x5F, 0x98, 0x69, 0x58, 0x79, 0x1A, 0x59, 0xCD, 0x5B, 0x48, 0x90, 0xD9, 0xA1, 0xB1, 0xCF, 0x08, 0x54, 0x1A, 0x7A, 0x93, 0xD0, 0x65, 0xDC, 0xF3, 0xB9, 0xF6, 0xC5, 0x13, 0xC0, 0x27, 0x94, 0x37, 0xD4, 0xBD, 0xBE, 0x62, 0x71, 0x40, 0xD2, 0x94, 0x63, 0x26, 0x39, 0xB7, 0x46, 0x89, 0x1C, 0xA9, 0x70, 0xDF, 0x6D, 0x73, 0x21, 0xF1, 0xA9, 0x13, 0xAD, 0x9B, 0xED, 0x3F, 0xE0, 0xBC, 0x02, 0xAF, 0xBB, 0x87, 0x20, 0xB7, 0x42, 0xEB, 0x40, 0x9E, 0xB8, 0x2C, 0x66, 0x96, 0x7F, 0x60, 0xEB, 0xF4, 0xCE, 0xE2, 0x50, 0x8E, 0xF7, 0xF7, 0x03, 0x5B, 0x7F, 0xC7, 0xD9, 0x17, 0x8E, 0x73, 0xED, 0xA0, 0x52, 0x9B, 0xCC, 0x9E, 0xB2, 0x0B, 0x9C, 0xD7, 0x74, 0xC5, 0x64, 0x88, 0x2D, 0xD5, 0x7C, 0xCF, 0xB5, 0x46, 0x63, 0xCF, 0xA8, 0x1B, 0x91, 0x4E, 0x14, 0xC4, 0xD7, 0xD7, 0x4B, 0xCE, 0x13, 0x9B, 0x7E, 0xC5, 0x3E, 0xA6, 0x1B, 0x0B, 0xF0, 0xDB, 0x61, 0xC7, 0x3A, 0x7A, 0x95, 0xF5, 0x96, 0xE1, 0x28, 0xEC, 0xA7, 0xA8, 0xC9, 0xEB, 0x92, 0xC2, 0x94, 0x4E, 0xF5, 0x64, 0x94, 0x3E, 0xDA, 0xCF, 0xD4, 0x8A, 0x5A, 0x8B, 0xDC, 0x7D, 0x0F, 0xAB, 0xFA, 0xB6, 0xDA, 0xD3, 0xC5, 0xFE, 0xEE, 0xB1, 0x39, 0x81, 0x8C, 0x85, 0x73, 0xA7, 0xBD, 0x75, 0x06, 0xB1, 0x8B, 0xFC, 0xE2, 0xBA, 0x15, 0x10, 0x5B, 0x7C, 0xEC, 0x83, 0x09, 0x6C, 0x8C, 0xAE, 0x99, 0xFB, 0xE5, 0xEA, 0x2C, 0x10, 0xF1, 0xBC, 0xF3, 0xF1, 0x58, 0x26, 0xA0, 0xD8, 0xEC, 0xA9, 0x7C, 0x42, 0xBB, 0x17, 0xCB, 0x9B, 0xED, 0x21, 0x9A, 0x8C, 0xDA, 0x9A, 0x57, 0x62, 0x85, 0x7E, 0xFB, 0xA4, 0x3B, 0x7F, 0x34, 0x15, 0x7A, 0xEB, 0x49, 0x2F, 0x81, 0xD2, 0xEA, 0x15, 0x6F, 0xF4, 0x99, 0x12, 0xA4, 0x04, 0x9B, 0xE9, 0x3E, 0x12, 0xA2, 0x26, 0x29, 0x5D, 0x8F, 0x68, 0x5C, 0x89, 0xBD, 0xA3, 0x83, 0x1E, 0xB7, 0x3B, 0xE4, 0x65, 0x7D, 0xBE, 0x3B, 0x09, 0xC0, 0x9D, 0x1D, 0xAF, 0x94, 0x4C, 0x26, 0x64, 0xE9, 0xBD, 0xE9, 0x17, 0x41, 0x98, 0xFE, 0x3D, 0xBA, 0xE4, 0xDE, 0x09, 0x45, 0x22, 0x9E, 0xDD, 0xF5, 0x96, 0x1B, 0x2F, 0x3D, 0x71, 0x9F, 0xAB, 0xAE, 0xB9, 0xBB, 0xD0, 0xD6, 0x3F, 0x6B, 0x74, 0xF1, 0x47, 0x70, 0x9C, 0xB2, 0xC5, 0xCD, 0xDD, 0x25, 0x35, 0x41, 0xA2, 0xD4, 0xDB, 0xFE, 0x2F, 0x61, 0x9F, 0xB6, 0xC0, 0xD8, 0x0D, 0x1D, 0x3D, 0x84, 0x93, 0x98, 0xBD, 0xF1, 0xFB, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x0F, 0x16, 0x1D, 0x23, 0x2D, }, }, { .name = "Dilithium Round 3, Level 3 (6-5) KAT 1", .version = 0, .keyform = CK_IBM_DILITHIUM_KEYFORM_ROUND3_65, .rho_len = 32, .rho = { 0xB5, 0x41, 0xC1, 0xE9, 0x2C, 0xEA, 0xDD, 0x90, 0x4A, 0x09, 0xEC, 0x08, 0xAD, 0x30, 0x6D, 0x97, 0x47, 0x34, 0xA0, 0x77, 0x86, 0x84, 0x71, 0xE5, 0x8D, 0x07, 0x71, 0x87, 0xC4, 0x66, 0x04, 0xCF, }, .seed_len = 32, .seed = { 0x95, 0x2D, 0x21, 0x81, 0xAC, 0x1F, 0x62, 0x59, 0x6F, 0x76, 0x7E, 0xFC, 0xA0, 0xB5, 0x5D, 0xB0, 0x92, 0xEF, 0x81, 0xDB, 0x66, 0xF9, 0xFF, 0xF1, 0x5F, 0x13, 0xD7, 0xAE, 0xEA, 0xCD, 0x8B, 0x3A, }, .tr_len = 32, .tr = { 0x2F, 0x2C, 0xFF, 0x6F, 0x47, 0xA6, 0x66, 0xF4, 0xAA, 0xE3, 0x22, 0xC8, 0xEC, 0xA7, 0x34, 0x32, 0x87, 0x99, 0xBC, 0xD5, 0x1D, 0x74, 0x93, 0x9F, 0x63, 0x5B, 0xEA, 0x9C, 0x37, 0x6A, 0x1F, 0xD5, }, .s1_len = 640, .s1 = { 0x05, 0x62, 0x52, 0x31, 0x01, 0x18, 0x65, 0x21, 0x53, 0x35, 0x41, 0x52, 0x03, 0x67, 0x04, 0x15, 0x60, 0x14, 0x16, 0x76, 0x16, 0x34, 0x61, 0x06, 0x86, 0x87, 0x65, 0x58, 0x02, 0x61, 0x00, 0x71, 0x02, 0x84, 0x17, 0x70, 0x51, 0x51, 0x55, 0x73, 0x86, 0x43, 0x28, 0x18, 0x46, 0x24, 0x36, 0x82, 0x54, 0x27, 0x68, 0x81, 0x11, 0x56, 0x32, 0x02, 0x40, 0x16, 0x87, 0x63, 0x20, 0x07, 0x36, 0x72, 0x02, 0x31, 0x72, 0x22, 0x40, 0x43, 0x20, 0x52, 0x01, 0x33, 0x64, 0x34, 0x75, 0x88, 0x30, 0x25, 0x81, 0x06, 0x63, 0x44, 0x35, 0x54, 0x48, 0x71, 0x30, 0x15, 0x82, 0x47, 0x53, 0x74, 0x18, 0x43, 0x11, 0x88, 0x46, 0x14, 0x31, 0x55, 0x87, 0x03, 0x70, 0x50, 0x04, 0x64, 0x73, 0x43, 0x81, 0x38, 0x37, 0x33, 0x78, 0x65, 0x66, 0x25, 0x75, 0x20, 0x81, 0x45, 0x68, 0x75, 0x11, 0x56, 0x88, 0x43, 0x22, 0x40, 0x73, 0x80, 0x21, 0x42, 0x80, 0x73, 0x86, 0x60, 0x08, 0x47, 0x10, 0x10, 0x83, 0x40, 0x67, 0x57, 0x38, 0x07, 0x63, 0x10, 0x77, 0x42, 0x27, 0x58, 0x61, 0x46, 0x47, 0x68, 0x31, 0x72, 0x65, 0x24, 0x11, 0x07, 0x05, 0x35, 0x66, 0x70, 0x67, 0x68, 0x62, 0x80, 0x40, 0x37, 0x85, 0x64, 0x10, 0x40, 0x76, 0x26, 0x28, 0x42, 0x32, 0x02, 0x48, 0x70, 0x17, 0x38, 0x80, 0x88, 0x72, 0x36, 0x24, 0x17, 0x22, 0x36, 0x71, 0x77, 0x82, 0x46, 0x64, 0x40, 0x16, 0x27, 0x78, 0x81, 0x81, 0x15, 0x11, 0x01, 0x54, 0x45, 0x38, 0x12, 0x81, 0x28, 0x11, 0x74, 0x42, 0x67, 0x15, 0x16, 0x57, 0x08, 0x02, 0x86, 0x44, 0x83, 0x58, 0x88, 0x17, 0x36, 0x73, 0x61, 0x04, 0x42, 0x32, 0x37, 0x70, 0x50, 0x82, 0x45, 0x17, 0x63, 0x48, 0x72, 0x27, 0x17, 0x70, 0x74, 0x03, 0x85, 0x53, 0x12, 0x11, 0x85, 0x32, 0x08, 0x01, 0x14, 0x85, 0x56, 0x38, 0x01, 0x27, 0x04, 0x86, 0x07, 0x88, 0x35, 0x04, 0x08, 0x05, 0x66, 0x86, 0x23, 0x01, 0x43, 0x61, 0x43, 0x68, 0x67, 0x42, 0x75, 0x52, 0x72, 0x48, 0x37, 0x27, 0x47, 0x77, 0x26, 0x55, 0x30, 0x71, 0x82, 0x57, 0x72, 0x71, 0x31, 0x05, 0x65, 0x26, 0x42, 0x12, 0x25, 0x72, 0x78, 0x02, 0x35, 0x54, 0x10, 0x78, 0x28, 0x52, 0x66, 0x72, 0x54, 0x85, 0x77, 0x47, 0x64, 0x68, 0x43, 0x68, 0x41, 0x57, 0x61, 0x44, 0x40, 0x46, 0x21, 0x15, 0x85, 0x01, 0x44, 0x02, 0x76, 0x66, 0x58, 0x41, 0x55, 0x26, 0x08, 0x48, 0x22, 0x15, 0x04, 0x48, 0x74, 0x43, 0x04, 0x26, 0x67, 0x66, 0x68, 0x18, 0x67, 0x07, 0x01, 0x02, 0x08, 0x66, 0x76, 0x56, 0x22, 0x26, 0x42, 0x28, 0x81, 0x12, 0x36, 0x61, 0x64, 0x78, 0x01, 0x41, 0x51, 0x04, 0x40, 0x43, 0x13, 0x53, 0x70, 0x22, 0x44, 0x60, 0x10, 0x75, 0x53, 0x28, 0x68, 0x68, 0x48, 0x17, 0x86, 0x08, 0x24, 0x27, 0x43, 0x23, 0x71, 0x67, 0x04, 0x21, 0x50, 0x21, 0x08, 0x46, 0x84, 0x74, 0x12, 0x88, 0x75, 0x64, 0x67, 0x14, 0x27, 0x37, 0x18, 0x36, 0x47, 0x52, 0x34, 0x30, 0x24, 0x03, 0x64, 0x67, 0x15, 0x33, 0x43, 0x16, 0x33, 0x76, 0x07, 0x51, 0x11, 0x64, 0x57, 0x28, 0x75, 0x51, 0x58, 0x78, 0x38, 0x70, 0x05, 0x85, 0x41, 0x81, 0x68, 0x15, 0x82, 0x86, 0x40, 0x35, 0x57, 0x32, 0x27, 0x23, 0x03, 0x13, 0x16, 0x52, 0x05, 0x34, 0x16, 0x76, 0x25, 0x18, 0x57, 0x61, 0x06, 0x01, 0x44, 0x41, 0x71, 0x04, 0x43, 0x32, 0x01, 0x24, 0x71, 0x88, 0x88, 0x58, 0x58, 0x34, 0x35, 0x86, 0x20, 0x88, 0x72, 0x18, 0x88, 0x44, 0x50, 0x24, 0x77, 0x34, 0x42, 0x64, 0x61, 0x30, 0x61, 0x43, 0x32, 0x31, 0x54, 0x31, 0x45, 0x56, 0x62, 0x64, 0x08, 0x11, 0x81, 0x50, 0x41, 0x56, 0x14, 0x63, 0x58, 0x33, 0x45, 0x37, 0x57, 0x65, 0x05, 0x12, 0x53, 0x40, 0x65, 0x57, 0x80, 0x57, 0x46, 0x11, 0x57, 0x12, 0x83, 0x07, 0x42, 0x58, 0x38, 0x87, 0x34, 0x30, 0x05, 0x73, 0x88, 0x46, 0x28, 0x74, 0x43, 0x17, 0x65, 0x81, 0x77, 0x28, 0x74, 0x14, 0x42, 0x06, 0x06, 0x34, 0x73, 0x62, 0x26, 0x61, 0x84, 0x76, 0x20, 0x25, 0x68, 0x08, 0x65, 0x13, 0x77, 0x83, 0x68, 0x85, 0x55, 0x74, 0x68, 0x32, 0x43, 0x86, 0x70, 0x63, 0x05, 0x30, 0x88, 0x82, 0x44, 0x84, 0x26, 0x86, 0x17, 0x87, 0x31, 0x28, 0x87, 0x33, 0x53, 0x02, 0x81, 0x88, 0x30, 0x03, 0x51, 0x74, 0x80, 0x53, 0x65, 0x78, 0x17, 0x77, 0x02, 0x61, 0x37, 0x38, 0x36, 0x23, 0x42, 0x35, 0x86, 0x13, 0x00, 0x38, 0x47, 0x58, 0x24, 0x81, 0x84, 0x78, 0x87, 0x77, 0x11, }, .s2_len = 768, .s2 = { 0x41, 0x51, 0x50, 0x83, 0x02, 0x36, 0x55, 0x53, 0x14, 0x86, 0x41, 0x14, 0x18, 0x51, 0x73, 0x54, 0x86, 0x58, 0x16, 0x74, 0x14, 0x70, 0x76, 0x32, 0x16, 0x38, 0x05, 0x48, 0x85, 0x00, 0x17, 0x23, 0x87, 0x64, 0x44, 0x86, 0x32, 0x72, 0x45, 0x37, 0x02, 0x58, 0x32, 0x13, 0x44, 0x15, 0x56, 0x02, 0x45, 0x78, 0x70, 0x14, 0x76, 0x84, 0x33, 0x88, 0x04, 0x56, 0x16, 0x57, 0x06, 0x64, 0x01, 0x67, 0x66, 0x35, 0x37, 0x48, 0x13, 0x43, 0x77, 0x37, 0x01, 0x23, 0x03, 0x82, 0x21, 0x02, 0x00, 0x30, 0x36, 0x47, 0x22, 0x74, 0x67, 0x47, 0x57, 0x42, 0x87, 0x64, 0x03, 0x55, 0x01, 0x05, 0x73, 0x40, 0x62, 0x78, 0x37, 0x70, 0x16, 0x65, 0x80, 0x22, 0x10, 0x38, 0x48, 0x44, 0x78, 0x04, 0x15, 0x28, 0x27, 0x12, 0x86, 0x53, 0x12, 0x13, 0x46, 0x47, 0x53, 0x82, 0x35, 0x14, 0x33, 0x50, 0x41, 0x77, 0x05, 0x25, 0x38, 0x31, 0x75, 0x35, 0x02, 0x01, 0x83, 0x86, 0x22, 0x31, 0x16, 0x41, 0x64, 0x55, 0x71, 0x06, 0x32, 0x38, 0x42, 0x81, 0x06, 0x23, 0x86, 0x53, 0x02, 0x84, 0x51, 0x12, 0x74, 0x55, 0x64, 0x34, 0x28, 0x02, 0x35, 0x30, 0x50, 0x38, 0x58, 0x56, 0x81, 0x54, 0x01, 0x23, 0x50, 0x75, 0x53, 0x53, 0x31, 0x52, 0x55, 0x32, 0x17, 0x74, 0x78, 0x07, 0x84, 0x14, 0x12, 0x30, 0x23, 0x51, 0x55, 0x10, 0x60, 0x52, 0x15, 0x03, 0x43, 0x72, 0x35, 0x01, 0x17, 0x76, 0x25, 0x10, 0x83, 0x35, 0x84, 0x23, 0x13, 0x63, 0x48, 0x31, 0x54, 0x33, 0x78, 0x64, 0x35, 0x64, 0x58, 0x80, 0x73, 0x12, 0x55, 0x00, 0x71, 0x15, 0x64, 0x71, 0x34, 0x66, 0x64, 0x66, 0x15, 0x80, 0x50, 0x32, 0x87, 0x05, 0x56, 0x80, 0x74, 0x85, 0x88, 0x46, 0x68, 0x40, 0x36, 0x78, 0x61, 0x22, 0x18, 0x66, 0x20, 0x78, 0x18, 0x43, 0x60, 0x53, 0x75, 0x70, 0x47, 0x15, 0x58, 0x06, 0x75, 0x73, 0x76, 0x52, 0x11, 0x42, 0x40, 0x10, 0x77, 0x27, 0x16, 0x43, 0x23, 0x46, 0x70, 0x76, 0x05, 0x81, 0x58, 0x27, 0x21, 0x26, 0x55, 0x02, 0x47, 0x75, 0x41, 0x31, 0x87, 0x37, 0x83, 0x33, 0x28, 0x71, 0x27, 0x68, 0x11, 0x70, 0x34, 0x46, 0x04, 0x62, 0x86, 0x27, 0x12, 0x23, 0x76, 0x44, 0x00, 0x03, 0x44, 0x14, 0x23, 0x03, 0x34, 0x44, 0x34, 0x38, 0x16, 0x75, 0x32, 0x40, 0x25, 0x52, 0x68, 0x04, 0x45, 0x55, 0x55, 0x04, 0x85, 0x57, 0x05, 0x04, 0x85, 0x80, 0x37, 0x86, 0x40, 0x14, 0x60, 0x80, 0x70, 0x63, 0x28, 0x60, 0x44, 0x85, 0x21, 0x80, 0x03, 0x00, 0x16, 0x36, 0x23, 0x64, 0x00, 0x32, 0x58, 0x64, 0x67, 0x35, 0x23, 0x15, 0x04, 0x15, 0x26, 0x04, 0x68, 0x52, 0x01, 0x41, 0x02, 0x87, 0x68, 0x21, 0x81, 0x81, 0x65, 0x83, 0x26, 0x22, 0x16, 0x05, 0x25, 0x76, 0x04, 0x30, 0x14, 0x34, 0x51, 0x74, 0x47, 0x07, 0x31, 0x27, 0x76, 0x64, 0x73, 0x22, 0x64, 0x84, 0x72, 0x77, 0x85, 0x05, 0x73, 0x73, 0x81, 0x22, 0x34, 0x25, 0x43, 0x00, 0x66, 0x12, 0x58, 0x41, 0x52, 0x36, 0x82, 0x24, 0x33, 0x37, 0x11, 0x65, 0x26, 0x04, 0x83, 0x28, 0x76, 0x27, 0x26, 0x56, 0x87, 0x40, 0x05, 0x08, 0x42, 0x68, 0x48, 0x33, 0x02, 0x58, 0x53, 0x45, 0x71, 0x20, 0x75, 0x16, 0x14, 0x00, 0x28, 0x54, 0x80, 0x12, 0x66, 0x21, 0x40, 0x53, 0x25, 0x78, 0x67, 0x56, 0x12, 0x25, 0x41, 0x60, 0x21, 0x07, 0x87, 0x74, 0x41, 0x38, 0x70, 0x63, 0x72, 0x78, 0x75, 0x25, 0x85, 0x83, 0x63, 0x12, 0x65, 0x00, 0x20, 0x74, 0x02, 0x43, 0x18, 0x30, 0x27, 0x14, 0x38, 0x15, 0x42, 0x81, 0x87, 0x34, 0x55, 0x48, 0x78, 0x48, 0x17, 0x68, 0x01, 0x22, 0x43, 0x70, 0x86, 0x55, 0x04, 0x21, 0x60, 0x24, 0x56, 0x51, 0x50, 0x45, 0x40, 0x44, 0x88, 0x23, 0x73, 0x60, 0x37, 0x56, 0x66, 0x41, 0x11, 0x40, 0x04, 0x55, 0x75, 0x32, 0x07, 0x38, 0x65, 0x26, 0x65, 0x33, 0x80, 0x30, 0x24, 0x42, 0x32, 0x64, 0x43, 0x08, 0x07, 0x56, 0x05, 0x08, 0x03, 0x58, 0x10, 0x17, 0x63, 0x18, 0x84, 0x48, 0x70, 0x35, 0x16, 0x75, 0x06, 0x40, 0x52, 0x57, 0x88, 0x43, 0x10, 0x05, 0x65, 0x36, 0x75, 0x40, 0x30, 0x41, 0x26, 0x18, 0x75, 0x34, 0x66, 0x08, 0x54, 0x55, 0x23, 0x61, 0x58, 0x28, 0x82, 0x18, 0x20, 0x84, 0x20, 0x08, 0x75, 0x14, 0x16, 0x66, 0x11, 0x51, 0x23, 0x36, 0x44, 0x17, 0x42, 0x28, 0x31, 0x12, 0x71, 0x45, 0x66, 0x13, 0x12, 0x67, 0x76, 0x06, 0x83, 0x00, 0x02, 0x82, 0x41, 0x62, 0x05, 0x64, 0x58, 0x22, 0x75, 0x15, 0x74, 0x10, 0x20, 0x41, 0x83, 0x18, 0x26, 0x05, 0x86, 0x50, 0x11, 0x13, 0x42, 0x47, 0x14, 0x48, 0x84, 0x42, 0x44, 0x83, 0x30, 0x75, 0x21, 0x67, 0x44, 0x13, 0x00, 0x14, 0x53, 0x66, 0x42, 0x54, 0x20, 0x28, 0x17, 0x88, 0x37, 0x50, 0x45, 0x55, 0x66, 0x34, 0x44, 0x32, 0x14, 0x26, 0x37, 0x75, 0x42, 0x24, 0x84, 0x46, 0x52, 0x18, 0x86, 0x74, 0x58, 0x64, 0x48, 0x16, 0x84, 0x26, 0x62, 0x72, 0x03, 0x70, 0x27, 0x54, 0x85, 0x17, 0x07, 0x67, 0x22, 0x63, 0x60, 0x35, 0x38, 0x41, 0x15, 0x20, 0x07, 0x52, 0x70, 0x48, 0x25, 0x81, 0x71, 0x17, 0x68, 0x84, 0x16, 0x41, 0x76, 0x20, 0x80, 0x02, 0x84, 0x34, 0x33, 0x63, 0x77, 0x44, 0x07, 0x70, 0x66, 0x51, 0x75, 0x11, 0x17, 0x55, 0x22, 0x65, 0x03, 0x82, 0x28, 0x13, 0x65, 0x55, 0x78, 0x22, 0x75, 0x26, 0x66, 0x33, 0x18, 0x84, 0x35, 0x75, 0x87, 0x58, }, .t0_len = 2496, .t0 = { 0xD0, 0xC2, 0x55, 0xD5, 0x1F, 0x82, 0x80, 0xDF, 0x43, 0x10, 0x6E, 0xB1, 0x51, 0xD4, 0x44, 0xAD, 0x6E, 0x4C, 0xAB, 0x4B, 0xAC, 0xC5, 0x85, 0xAA, 0x37, 0xD7, 0x44, 0xB2, 0x45, 0x13, 0x20, 0x40, 0xDC, 0x3D, 0x76, 0xAB, 0xCE, 0xA9, 0xCD, 0x44, 0x72, 0xC1, 0xCC, 0xA1, 0xF0, 0x7A, 0x49, 0x92, 0xDB, 0xD4, 0xD0, 0x52, 0x4A, 0x48, 0x2B, 0x50, 0x95, 0x71, 0x10, 0x96, 0x2A, 0xEB, 0x75, 0xFE, 0x2A, 0xCD, 0x2C, 0xA3, 0x84, 0xB2, 0x06, 0xAE, 0x68, 0x98, 0xAE, 0xE2, 0x58, 0x22, 0x18, 0xC0, 0x30, 0x05, 0x9C, 0xF0, 0x61, 0x0D, 0xF2, 0x3F, 0x62, 0xFA, 0x94, 0xCE, 0x63, 0xF5, 0x05, 0x41, 0x6E, 0xE5, 0x6F, 0x21, 0x3B, 0x1B, 0x04, 0xA3, 0xED, 0x78, 0x6E, 0xDE, 0x5A, 0x02, 0x74, 0xDF, 0xB8, 0x62, 0xB7, 0x64, 0x84, 0x7B, 0x48, 0x2B, 0x73, 0xD1, 0xA3, 0xE4, 0x36, 0x74, 0x43, 0x40, 0xCC, 0xA3, 0x97, 0x20, 0xC7, 0xDB, 0x10, 0x16, 0x3D, 0x6B, 0x95, 0x2C, 0xDC, 0x3D, 0x8A, 0x19, 0x46, 0x7F, 0xAB, 0xB0, 0x74, 0x89, 0xDE, 0x13, 0x9D, 0x57, 0x2C, 0x8B, 0x74, 0xAB, 0x10, 0x28, 0x7B, 0xCD, 0x40, 0x20, 0x5D, 0xF4, 0x8A, 0xD5, 0x43, 0x4E, 0xE1, 0x7E, 0xA0, 0x16, 0x99, 0x35, 0x36, 0x38, 0xB7, 0xBE, 0x07, 0x23, 0xE6, 0xC5, 0xF2, 0x76, 0xC9, 0xA5, 0x71, 0x82, 0xB0, 0x99, 0xEC, 0xE8, 0xE9, 0x2C, 0xF0, 0xF1, 0xD1, 0xCC, 0xAC, 0xAD, 0x71, 0xBC, 0x0C, 0x7C, 0xBC, 0x0E, 0xFE, 0x26, 0x43, 0x31, 0xC2, 0xB4, 0x6F, 0x00, 0x1A, 0x3C, 0x7E, 0x3A, 0xE8, 0x35, 0xA8, 0xD1, 0x00, 0xF7, 0xF4, 0xD7, 0x1C, 0x18, 0xBA, 0x1E, 0x66, 0x5C, 0xBB, 0xA8, 0xBE, 0x55, 0x9B, 0x8E, 0xD9, 0x55, 0x13, 0x67, 0xE9, 0x50, 0x05, 0x74, 0xEA, 0xDD, 0x85, 0x6E, 0x77, 0x02, 0x43, 0xD0, 0x7A, 0x30, 0x61, 0xEA, 0xDD, 0x87, 0x97, 0xC5, 0xBA, 0x13, 0x83, 0xC1, 0x39, 0x1E, 0x31, 0x6F, 0xCA, 0x75, 0x2A, 0x9D, 0xD2, 0xD5, 0x30, 0xA8, 0x59, 0xEA, 0xCC, 0x06, 0x06, 0xEC, 0xD0, 0x19, 0xD8, 0x75, 0xAD, 0xF0, 0x6D, 0x81, 0xC2, 0x5C, 0xE0, 0x7B, 0x30, 0x49, 0x21, 0xC8, 0x22, 0x24, 0xF6, 0x83, 0x95, 0x72, 0x47, 0xA6, 0x62, 0xDD, 0xB7, 0xBA, 0xF0, 0x49, 0x07, 0xCD, 0x17, 0x43, 0x19, 0x37, 0xA2, 0x6D, 0x62, 0xE1, 0x87, 0xCB, 0xB9, 0xDF, 0x11, 0x35, 0xA0, 0xF0, 0x34, 0x8F, 0xE7, 0xA9, 0x25, 0xF8, 0x6F, 0xCA, 0x96, 0xB2, 0xED, 0x92, 0xE6, 0x9F, 0x45, 0xAD, 0x55, 0xF9, 0x45, 0xD0, 0xFE, 0x8A, 0xA7, 0xA4, 0x71, 0x91, 0x5B, 0x5F, 0x0F, 0xE9, 0x65, 0x75, 0xCB, 0x2D, 0xEF, 0x41, 0xD5, 0x0D, 0x11, 0x3B, 0xA1, 0xBE, 0x2D, 0x0B, 0x5D, 0x47, 0xDE, 0x93, 0xA1, 0x97, 0x86, 0xBE, 0xAB, 0x57, 0xEE, 0x1A, 0x03, 0x60, 0xFC, 0xD5, 0xE6, 0x9F, 0x25, 0x6B, 0x12, 0x8D, 0x17, 0xD1, 0xC3, 0x91, 0x63, 0xF1, 0x34, 0x5A, 0xD0, 0xFC, 0xC8, 0x5F, 0xD1, 0x48, 0x8D, 0x78, 0x78, 0x14, 0xBC, 0x6E, 0x3E, 0x93, 0xD7, 0x1D, 0x24, 0x6F, 0x60, 0xA5, 0x0C, 0xEE, 0x91, 0x13, 0xB3, 0xA8, 0x5E, 0xED, 0x84, 0x28, 0x69, 0x31, 0xB6, 0xCF, 0x66, 0x98, 0x21, 0x5B, 0x29, 0x62, 0xFD, 0xCB, 0x9E, 0x95, 0x68, 0xCB, 0xC3, 0x84, 0xBE, 0x82, 0x65, 0x58, 0xFF, 0x8D, 0xFF, 0x68, 0xA3, 0xE0, 0x1B, 0x24, 0x70, 0xB7, 0x19, 0x2B, 0x94, 0x92, 0xDF, 0xDE, 0x2C, 0x9F, 0xE0, 0x91, 0xE8, 0xA6, 0x38, 0xDD, 0x1B, 0xC8, 0x79, 0x4B, 0xA3, 0xB2, 0x77, 0x95, 0xB2, 0x20, 0x69, 0x7B, 0x05, 0xCF, 0x1D, 0x68, 0x59, 0x06, 0xF1, 0x4C, 0xDD, 0x9E, 0x43, 0xE1, 0x11, 0x4B, 0x0A, 0x88, 0xC0, 0x74, 0x38, 0xEE, 0x1E, 0x69, 0x01, 0xBE, 0x4F, 0x57, 0x7C, 0x78, 0x66, 0x3B, 0x0D, 0x34, 0x39, 0xFB, 0x39, 0x00, 0x95, 0x9A, 0x10, 0x7B, 0xCA, 0xD3, 0x61, 0x10, 0xB4, 0xCD, 0x2B, 0x61, 0xBE, 0x46, 0xEF, 0x4F, 0x68, 0x00, 0x0D, 0xBC, 0x64, 0xCC, 0xF4, 0x0E, 0x6B, 0x6E, 0xDE, 0x65, 0x77, 0xF8, 0xEA, 0x36, 0x3B, 0x5A, 0x0B, 0xEA, 0x0A, 0x81, 0x91, 0x9B, 0xCF, 0xC1, 0xEC, 0x98, 0x82, 0xAC, 0x51, 0x40, 0x93, 0x17, 0xEB, 0x24, 0x89, 0x23, 0x34, 0xF4, 0x61, 0xBD, 0xF0, 0x4D, 0x4D, 0x6B, 0x16, 0x91, 0xA7, 0xD4, 0x86, 0x56, 0x25, 0xC7, 0x4E, 0xA7, 0xBB, 0xE2, 0x6B, 0x28, 0x4B, 0xC4, 0x46, 0x8E, 0x39, 0x5C, 0xE5, 0x62, 0xF8, 0x24, 0xD9, 0x02, 0x9B, 0x83, 0xE7, 0x61, 0x48, 0xDF, 0x2E, 0xE9, 0x62, 0x5C, 0xCF, 0xBB, 0x88, 0x03, 0x94, 0x11, 0xB0, 0x81, 0x67, 0x41, 0x96, 0xF4, 0xEB, 0xFB, 0xBF, 0x9E, 0x51, 0xD0, 0x47, 0xD0, 0x86, 0xEB, 0xCB, 0xA7, 0xBB, 0xDF, 0x1C, 0xF3, 0x60, 0xC4, 0x03, 0x19, 0xFB, 0x7B, 0x5C, 0xE6, 0xF6, 0xCE, 0x04, 0xE6, 0xAC, 0xB9, 0xA0, 0xEC, 0x0F, 0x15, 0x15, 0x5E, 0xD5, 0x9D, 0xC1, 0xCC, 0x46, 0x8E, 0xB2, 0x5F, 0x9F, 0x62, 0xC9, 0xD9, 0x24, 0xCB, 0x0B, 0x01, 0x99, 0xA5, 0x27, 0x6D, 0x59, 0xE4, 0x48, 0x38, 0x53, 0x4B, 0x62, 0xE8, 0x6E, 0x5F, 0xAD, 0x68, 0xC8, 0x1B, 0x2F, 0x0F, 0xC9, 0xAB, 0xE2, 0x4D, 0xAC, 0x0F, 0xF2, 0x65, 0x24, 0x9C, 0x41, 0x0D, 0x96, 0xAA, 0x8E, 0x98, 0x35, 0x4A, 0x6E, 0x23, 0x88, 0x4D, 0xB4, 0xB5, 0xB0, 0x90, 0xA8, 0xEA, 0x5A, 0x7D, 0xBF, 0x4E, 0x68, 0x12, 0x5B, 0xFD, 0xF7, 0xD2, 0xD6, 0xB3, 0x20, 0xE6, 0x9F, 0x8E, 0x61, 0x72, 0x5B, 0xD5, 0x7F, 0xF4, 0xB9, 0x05, 0xC4, 0xD1, 0x4F, 0xA1, 0x7D, 0xDB, 0xE9, 0xF2, 0x26, 0x28, 0x3B, 0xC4, 0x62, 0xC1, 0x3E, 0xB7, 0x51, 0x12, 0x1D, 0xBB, 0xE6, 0xC0, 0x2C, 0xBA, 0xCF, 0x43, 0x14, 0x0E, 0x51, 0xBF, 0x9C, 0xFD, 0x39, 0x38, 0x3E, 0x24, 0x7E, 0xB9, 0x76, 0x0F, 0x8F, 0x40, 0x43, 0xA0, 0x46, 0xF9, 0xDB, 0x54, 0x0D, 0x84, 0x5C, 0x15, 0x73, 0x86, 0x43, 0xBC, 0xFA, 0x3B, 0x8E, 0x27, 0x8B, 0x07, 0x34, 0xBB, 0xEE, 0x3E, 0xBD, 0xE2, 0x81, 0x09, 0x2E, 0xA3, 0xAE, 0xCB, 0x56, 0xB9, 0x87, 0x4E, 0x4B, 0x9D, 0x3E, 0x2A, 0xCD, 0xC8, 0x04, 0xB2, 0xAE, 0xCE, 0xB9, 0x92, 0xEE, 0x99, 0xAB, 0x11, 0xA3, 0x7C, 0x51, 0x5E, 0x07, 0xF5, 0xAA, 0xE3, 0x2E, 0x36, 0x70, 0x8B, 0x1C, 0xC0, 0xF4, 0xE2, 0xA6, 0x4D, 0xE5, 0x9A, 0x94, 0xFD, 0x3D, 0xCC, 0x08, 0x9B, 0xD2, 0x94, 0x19, 0x61, 0x42, 0x5F, 0xE9, 0x65, 0xB7, 0x15, 0xF1, 0x9B, 0x4E, 0xBA, 0xD8, 0xD7, 0x4B, 0x1B, 0x06, 0x01, 0x76, 0x76, 0x0D, 0x7A, 0xD7, 0x3E, 0x45, 0x3E, 0xBF, 0xEB, 0xC7, 0x87, 0x6F, 0xFF, 0xFE, 0x6B, 0xDB, 0x77, 0xFA, 0xB2, 0x0F, 0x0A, 0x2C, 0x04, 0x31, 0x57, 0xA8, 0xEA, 0x4A, 0xC8, 0x0F, 0x98, 0xA3, 0xC7, 0xB8, 0x24, 0xC1, 0x59, 0xF1, 0x23, 0x6D, 0xA5, 0x2C, 0xE5, 0xA1, 0x0F, 0x0B, 0xC0, 0x25, 0x74, 0x18, 0x61, 0x4D, 0x52, 0x37, 0xFB, 0x4C, 0x65, 0x3E, 0xC6, 0x65, 0x97, 0xFB, 0x8B, 0xB8, 0x1E, 0xC7, 0xD6, 0xA2, 0x09, 0x9A, 0x9D, 0xD8, 0x37, 0xC4, 0x99, 0xC9, 0x92, 0x77, 0x99, 0xC2, 0xB3, 0xE2, 0xD8, 0xAE, 0x18, 0xAF, 0xB3, 0xE2, 0x3C, 0x7E, 0x5D, 0x24, 0xDF, 0xA5, 0x79, 0x6D, 0xB5, 0x15, 0x6C, 0x45, 0x82, 0x93, 0xF7, 0xA0, 0xEF, 0x2F, 0xE8, 0xB9, 0x93, 0x74, 0xD3, 0x34, 0x9C, 0x60, 0x73, 0x49, 0xE3, 0x39, 0x7E, 0x2A, 0x9E, 0x17, 0x45, 0x6E, 0x42, 0xFB, 0x5B, 0xF0, 0x6C, 0x61, 0xB4, 0x41, 0xF5, 0x77, 0xCC, 0x8A, 0xB9, 0x3E, 0xFD, 0x7D, 0xCD, 0x6B, 0x84, 0xDB, 0xAB, 0x85, 0xA0, 0x36, 0x35, 0x78, 0x47, 0xBC, 0xF5, 0x39, 0xEA, 0x74, 0xA5, 0x7E, 0x7D, 0xF5, 0x04, 0x84, 0x24, 0xBE, 0xAC, 0x6E, 0xD1, 0x1A, 0xE1, 0xCF, 0x05, 0xB8, 0x95, 0x1F, 0x3A, 0xE5, 0x52, 0x5B, 0x1A, 0xAF, 0x22, 0x3C, 0xAC, 0x2D, 0xF8, 0x0E, 0x5C, 0x74, 0x7E, 0x3D, 0x9C, 0x21, 0x2B, 0xB6, 0x6D, 0x17, 0xD5, 0x12, 0x65, 0x51, 0xA8, 0x61, 0x9E, 0x3F, 0x24, 0xF5, 0x79, 0x88, 0xC4, 0xC3, 0xEB, 0x78, 0x11, 0x80, 0xBF, 0xA1, 0x37, 0x79, 0x93, 0xCD, 0xA6, 0xD5, 0x74, 0x0D, 0x0A, 0x84, 0xDC, 0xD1, 0x87, 0x93, 0x46, 0xD4, 0xA9, 0x73, 0x5E, 0x22, 0xAB, 0x56, 0xF0, 0x14, 0x96, 0xCD, 0x4E, 0xEF, 0xE6, 0xF8, 0xE0, 0x10, 0xD4, 0xB3, 0xF3, 0x50, 0x33, 0x89, 0xE4, 0xA8, 0x52, 0x48, 0xB3, 0x0F, 0xC4, 0x75, 0x9C, 0x38, 0x07, 0x3B, 0x1E, 0x73, 0x1A, 0x24, 0xB4, 0x91, 0xE6, 0xA7, 0xC2, 0xA8, 0x77, 0x35, 0x0A, 0x3D, 0xBD, 0x8D, 0xDD, 0x6C, 0x0F, 0x55, 0xFC, 0x81, 0x2D, 0x5B, 0x2D, 0x54, 0xD3, 0x23, 0x7B, 0x21, 0x37, 0x10, 0xB2, 0x71, 0xB4, 0x70, 0xF2, 0x53, 0xE0, 0x85, 0x2D, 0xDA, 0x5D, 0x84, 0xED, 0xE1, 0xEF, 0xAB, 0xAF, 0xFA, 0x6D, 0xA8, 0x63, 0xD6, 0xEE, 0x11, 0x3A, 0xBB, 0xA1, 0x48, 0xA9, 0x01, 0x8A, 0x4E, 0x5C, 0x3D, 0x8F, 0x57, 0xCA, 0x9D, 0xF0, 0x05, 0xB5, 0x9A, 0x0D, 0x3E, 0x47, 0x40, 0x6D, 0x97, 0xE3, 0x37, 0xBB, 0x20, 0x1D, 0x78, 0x8B, 0x83, 0x29, 0xFF, 0x50, 0x66, 0x26, 0x8F, 0x4E, 0xFD, 0x51, 0x0D, 0x91, 0xB0, 0x94, 0xC0, 0xEE, 0x3D, 0x05, 0x3F, 0x2C, 0xCB, 0x39, 0x13, 0x86, 0x34, 0xB1, 0x22, 0xD5, 0x37, 0x59, 0x14, 0x13, 0x2B, 0x31, 0x55, 0x08, 0x84, 0xFE, 0x2E, 0x9A, 0x31, 0xE5, 0x12, 0x7B, 0x2E, 0x03, 0x42, 0x7D, 0xBC, 0xF7, 0xD2, 0x55, 0x7C, 0x5B, 0x71, 0x81, 0xBD, 0xA6, 0x83, 0x4B, 0xB9, 0x30, 0xCD, 0x3A, 0x0E, 0x0E, 0x0E, 0xAD, 0x09, 0x12, 0x0A, 0x57, 0x2B, 0xEE, 0xF7, 0x51, 0x86, 0x3A, 0xFA, 0xB3, 0x38, 0xBA, 0xC3, 0xE9, 0xA8, 0x17, 0x9F, 0x2B, 0x5C, 0x90, 0xF0, 0xBB, 0xA6, 0xB7, 0x5F, 0xDC, 0x2A, 0xB5, 0xF7, 0x20, 0x0F, 0xEF, 0x3A, 0x65, 0xBB, 0x77, 0x64, 0x3D, 0xA0, 0xD6, 0xFE, 0xB1, 0x2D, 0x75, 0x3D, 0xF7, 0x75, 0xEA, 0x71, 0x4E, 0x28, 0x3E, 0x0E, 0x99, 0x62, 0xA2, 0x39, 0xA0, 0x44, 0x90, 0xE7, 0xD2, 0xF9, 0x81, 0x93, 0xBB, 0xEB, 0xD6, 0xE2, 0xF5, 0x26, 0xAB, 0x0B, 0x27, 0x7E, 0x49, 0xDB, 0xC3, 0xFA, 0x52, 0x04, 0x92, 0xD3, 0x24, 0x17, 0x28, 0x3B, 0xAB, 0xF3, 0xCE, 0xEE, 0xE0, 0xBE, 0xED, 0xBE, 0x66, 0x0C, 0x04, 0x3B, 0x19, 0x28, 0xAC, 0xDE, 0x60, 0x2F, 0x98, 0x61, 0xA5, 0x3A, 0x9E, 0xFA, 0x9A, 0x0D, 0x9D, 0x31, 0xBB, 0xE6, 0x2B, 0xCE, 0xDE, 0x01, 0x33, 0x32, 0xF9, 0xF3, 0x3B, 0xE6, 0xA7, 0x43, 0x13, 0xFD, 0x17, 0x09, 0xAA, 0x72, 0x9B, 0xBE, 0xB7, 0xEE, 0x47, 0x91, 0xAB, 0xA7, 0x23, 0xC2, 0x5C, 0xB3, 0xB0, 0xC6, 0x48, 0x7C, 0x62, 0x64, 0x29, 0x1E, 0xDA, 0x8F, 0x9E, 0xFF, 0x54, 0xDA, 0x37, 0x48, 0x97, 0xF9, 0x49, 0x0B, 0xF7, 0xD2, 0x05, 0x33, 0xBC, 0x29, 0x3B, 0x9A, 0x06, 0xC4, 0x30, 0xA3, 0x37, 0x04, 0x70, 0x6C, 0x0E, 0xF0, 0x9C, 0x36, 0x95, 0xD3, 0xC0, 0x81, 0x1C, 0x05, 0xCD, 0x85, 0x5E, 0x51, 0xE9, 0xD7, 0x4E, 0x7E, 0x3C, 0xFE, 0xEB, 0x7C, 0xDA, 0xAA, 0x89, 0x3C, 0xB9, 0x73, 0x21, 0xB2, 0x4B, 0x5B, 0xE6, 0x33, 0x3B, 0x6A, 0xBE, 0xC8, 0x11, 0xE3, 0xBC, 0xC2, 0x9C, 0xA0, 0xFA, 0xF9, 0x3B, 0x2B, 0xBD, 0x43, 0x32, 0xD9, 0xB2, 0xE7, 0xC7, 0x89, 0xCB, 0xDE, 0x03, 0xD4, 0xFC, 0xBB, 0x47, 0x5F, 0xAD, 0x05, 0x35, 0xFE, 0xF2, 0xDD, 0xC1, 0xE2, 0x86, 0x26, 0x84, 0x19, 0x89, 0x6C, 0x41, 0x7F, 0x66, 0x5E, 0x7A, 0x02, 0x4F, 0x2C, 0xE0, 0xAB, 0x15, 0x47, 0x57, 0x28, 0xF4, 0xE3, 0x9C, 0xAD, 0x47, 0xFE, 0x33, 0xD9, 0x10, 0x74, 0xC7, 0xB3, 0x46, 0x4E, 0xB0, 0x5E, 0x6A, 0x32, 0x3D, 0x17, 0xD7, 0x43, 0xC0, 0xE7, 0x9C, 0x9E, 0x62, 0xA2, 0x31, 0xED, 0xF4, 0x0E, 0x75, 0x34, 0x0A, 0x23, 0x93, 0x12, 0xC4, 0xB4, 0xE5, 0xBB, 0xAC, 0x6F, 0x51, 0x1C, 0xF2, 0x54, 0x8C, 0xF8, 0x22, 0x4C, 0xCB, 0xC7, 0x3A, 0x21, 0xF8, 0xEB, 0xD3, 0xA6, 0x64, 0x50, 0x61, 0x8D, 0x1F, 0x5B, 0x26, 0x49, 0x5F, 0xF6, 0xE8, 0x4F, 0xA1, 0xC8, 0x97, 0x82, 0xEB, 0x21, 0x1E, 0x2F, 0xB7, 0xFA, 0xD4, 0x56, 0x91, 0xBF, 0x67, 0x9E, 0x83, 0x7F, 0x88, 0xFE, 0x5C, 0x62, 0x08, 0xAA, 0xAF, 0xAB, 0x7A, 0x42, 0x38, 0x7B, 0x0A, 0x1A, 0x48, 0xCB, 0xD5, 0x3B, 0x13, 0x81, 0x78, 0x09, 0x44, 0x5E, 0x00, 0x91, 0xBC, 0xBC, 0xEE, 0x8E, 0x9D, 0xDB, 0x41, 0x3D, 0x13, 0x28, 0x8F, 0x53, 0xFF, 0xE6, 0xDC, 0x03, 0x9C, 0xEA, 0xE2, 0x4C, 0xE5, 0x69, 0x1E, 0xC6, 0x36, 0xBE, 0x10, 0x52, 0xEA, 0x72, 0xCD, 0x81, 0x9F, 0x5F, 0xF2, 0xF2, 0x79, 0x11, 0x5E, 0x07, 0x82, 0x12, 0x46, 0x12, 0x2E, 0xF2, 0xAE, 0xF1, 0xC3, 0xC8, 0x49, 0x5C, 0xEA, 0xBF, 0x2B, 0x6D, 0xC3, 0xD6, 0x5C, 0x60, 0xEB, 0x2F, 0xD5, 0x69, 0x14, 0x5A, 0x63, 0xD9, 0xAB, 0xC5, 0xD4, 0x37, 0xF7, 0xC7, 0xFC, 0x5A, 0xE2, 0x2D, 0x87, 0x87, 0x4A, 0x78, 0xDA, 0x40, 0xD5, 0x72, 0x72, 0xF7, 0xED, 0x93, 0xE0, 0xA1, 0xB4, 0x8C, 0x8B, 0xD6, 0x1A, 0x92, 0xF0, 0x8A, 0x16, 0xD0, 0x14, 0x42, 0xF0, 0x20, 0xFB, 0xDB, 0xFF, 0xBD, 0xB1, 0x8F, 0xC5, 0xBB, 0xAD, 0x8A, 0x14, 0x21, 0x84, 0xEF, 0x9A, 0x32, 0x86, 0x13, 0xC0, 0x3D, 0x67, 0xF8, 0xBB, 0x74, 0x0F, 0x6F, 0x08, 0x3C, 0x39, 0x3C, 0x88, 0xE8, 0x08, 0xBC, 0xC9, 0xA4, 0xCF, 0x4B, 0xEA, 0x75, 0xA1, 0x6C, 0x7A, 0x81, 0xF5, 0x1F, 0x6D, 0x9E, 0x00, 0x3E, 0xBC, 0xB8, 0xE3, 0x28, 0xA8, 0x6D, 0x7B, 0x73, 0x13, 0x3E, 0x59, 0x66, 0x09, 0x6A, 0xFC, 0x1D, 0x1B, 0xCC, 0xCB, 0x7C, 0x84, 0xF1, 0x12, 0x35, 0x89, 0x2D, 0xEC, 0x5C, 0xFC, 0xCD, 0xF6, 0x47, 0x22, 0x49, 0x94, 0x3F, 0xB3, 0x9C, 0x7B, 0x85, 0x86, 0xC4, 0xA2, 0xE5, 0xE8, 0x11, 0xE3, 0xFA, 0xF0, 0x68, 0xA1, 0xBC, 0xA6, 0x1F, 0x50, 0xB7, 0x59, 0xF7, 0x04, 0x2D, 0xE3, 0x4D, 0x73, 0x8F, 0x2D, 0x7C, 0x3D, 0xAB, 0x26, 0xA7, 0x39, 0x70, 0xE5, 0x08, 0x15, 0xC5, 0x1A, 0xD7, 0x3C, 0xFC, 0xD3, 0x53, 0x0B, 0xDA, 0x1C, 0x2E, 0x91, 0x2E, 0x69, 0x4E, 0x9E, 0xE7, 0x9C, 0x09, 0x33, 0x4E, 0x4C, 0x29, 0x33, 0x9F, 0x75, 0x82, 0x30, 0x3B, 0x2E, 0x28, 0x5C, 0x7A, 0xE8, 0x4B, 0xFF, 0x01, 0xDE, 0x1D, 0x90, 0xCA, 0xAD, 0xA4, 0x2A, 0xA4, 0xA6, 0x52, 0xC7, 0x78, 0x20, 0x75, 0xB5, 0x15, 0x14, 0xB1, 0x0C, 0x95, 0x92, 0xD3, 0x0B, 0x5A, 0x73, 0x62, 0xD9, 0xA3, 0x2A, 0xCD, 0x26, 0x6B, 0x62, 0x86, 0x8F, 0x50, 0x73, 0x8D, 0xCA, 0xB7, 0x80, 0xCF, 0x83, 0x19, 0x83, 0x89, 0x34, 0x0F, 0x3E, 0x7A, 0x86, 0x39, 0xFE, 0x94, 0xAE, 0x0F, 0x45, 0x67, 0x29, 0x17, 0x01, 0xEE, 0x62, 0x04, 0x58, 0x7E, 0x29, 0x53, 0x19, 0xA0, 0x05, 0x6B, 0x30, 0x4C, 0x79, 0x01, 0x19, 0x71, 0x92, 0xA8, 0xA6, 0xF4, 0xA3, 0xEA, 0x8C, 0xA3, 0x94, 0x18, 0x61, 0xE7, 0x60, 0x1F, 0x3A, 0x89, 0xFE, 0x6F, 0x9D, 0x8C, 0x49, 0xF9, 0xBB, 0x3D, 0x95, 0xC1, 0xA0, 0x23, 0x35, 0x75, 0x98, 0x3C, 0xD7, 0xD8, 0x8F, 0x9D, 0x31, 0x5C, 0xAA, 0x9F, 0x39, 0x54, 0xB6, 0x3C, 0x6D, 0xF2, 0x92, 0x0E, 0x16, 0xF0, 0x07, 0x6B, 0x72, 0x98, 0x35, 0x2E, 0xEF, 0x1A, 0x7E, 0x13, 0x41, 0xA3, 0x72, 0xD0, 0x76, 0x23, 0x3D, 0x01, 0x0A, 0xD4, 0xDE, 0x4C, 0x28, 0x45, 0xA6, 0xEB, 0xB6, 0x43, 0x74, 0x5D, 0xB2, 0xDE, 0x2A, 0x02, 0xF2, 0x41, 0xD5, 0x2F, 0x16, 0xAA, 0xA8, 0x7F, 0x75, 0xC3, 0x39, 0x5C, 0x40, 0xAD, 0x3B, 0x71, 0xD3, 0x12, 0x39, 0xAD, 0x31, 0x87, 0xAF, 0xFE, 0x18, 0xF0, 0x37, 0x0A, 0xE0, 0x83, 0x10, 0x93, 0xD9, 0x99, 0x06, 0x71, 0xE5, 0xC2, 0xAD, 0x4D, 0x99, 0xA4, 0x9C, 0x07, 0x83, 0x90, 0x7D, 0x1E, 0x1B, 0x8B, 0xF6, 0x15, 0x23, 0xFD, 0x6F, 0xC2, 0x5C, 0x1A, 0x5C, 0xB0, 0xF1, 0xF6, 0x63, 0x16, 0x8F, 0xEA, 0x17, 0xEA, 0x6B, 0x71, 0xE0, 0xE7, 0x61, 0x83, 0x0A, 0xD7, 0xB4, 0x9F, 0xF1, 0xE7, 0x1E, 0x6D, 0xC4, 0x9D, 0xDC, 0x86, 0x5E, 0x62, 0xDF, 0x12, 0xCE, 0x5F, 0x13, 0x84, 0x16, 0xBE, 0x79, 0x44, 0x0C, 0x72, 0x13, 0xFC, 0x2E, 0x49, 0xB5, 0x0E, 0x60, 0xA5, 0x3D, 0x50, 0xDB, 0xEA, 0xD4, 0xAD, 0x36, 0x79, 0xB0, 0xE5, 0x85, 0x45, 0xEE, 0xA9, 0xE5, 0xE8, 0xD5, 0xDE, 0xD9, 0xC3, 0x90, 0x16, 0xE8, 0x88, 0x96, 0xDA, 0xB5, 0x9A, 0x84, 0xEB, 0xC7, 0xCC, 0xA2, 0x86, 0x67, 0xF4, 0x62, 0x20, 0x09, 0x74, 0x8F, 0x6B, 0x58, 0x54, 0xA5, 0xE0, 0xCF, 0x07, 0x0A, 0xB6, 0x1C, 0xAC, 0xCD, 0xBF, 0x1A, 0x7E, 0xCA, 0x53, 0x1A, 0x5B, 0x5F, 0xEF, 0xDC, 0x3F, 0xF6, 0x60, 0xDD, 0xBD, 0xF0, 0x44, 0x7B, 0x70, 0x35, 0x98, 0xB7, 0x6A, 0xCD, 0xBB, 0xE8, 0x62, 0x1E, 0x7F, 0xFC, 0xDA, 0x81, 0x08, 0xA3, 0xA1, 0x18, 0x07, 0xAC, 0x99, 0x92, 0xEC, 0x30, 0x1F, 0xDC, 0x3F, 0x65, 0x67, 0xA9, 0x99, 0x85, 0xC1, 0xA1, 0x6D, 0x9A, 0xA9, 0x28, 0x6E, 0xAB, 0x8C, 0x65, 0xE8, 0xD1, 0x9D, 0xB0, 0x4F, 0x01, 0xD9, 0x18, 0xCA, 0x04, 0xCD, 0xA3, 0x77, 0x55, 0x95, 0x49, 0x4A, 0x4C, 0x2D, 0x53, 0x63, 0x57, 0xE5, 0x0A, 0x3C, 0x3C, 0xEC, 0x15, 0x3F, 0xB3, 0x78, 0xDD, 0x9D, 0x2C, 0x05, 0xC1, 0xEC, 0xF8, 0x9E, 0x89, 0xA8, 0xBC, 0xC4, 0xBD, 0x27, 0x76, 0xC7, 0x9F, 0x34, 0xFA, 0x92, 0x10, 0xE9, 0xE9, 0x68, 0x1A, 0x2B, 0x37, 0x3C, 0x85, 0x7E, 0x88, 0x30, 0xAF, 0x24, 0x60, 0x5A, 0x93, 0xA3, 0x95, 0xEB, 0xA1, 0x74, 0x4C, 0xC2, 0xF5, 0xEA, 0xA1, 0x7A, 0x42, 0x33, 0x6F, 0xE2, 0x7F, 0xDC, 0xCE, 0x42, 0xDE, 0x68, 0x92, 0xF2, 0x23, 0x4B, 0x9E, 0x11, 0x15, 0x35, 0xF4, 0x24, 0xF0, 0xF6, 0x8D, 0xDB, 0x22, 0x0C, 0x13, 0x76, 0x24, 0x66, 0x36, 0x1E, 0x5C, 0xC9, 0xD8, 0xBE, 0x3A, 0xB7, 0xA4, 0x59, 0x76, 0xAD, 0xEF, 0x07, 0x6E, }, .t1_len = 1920, .t1 = { 0xA7, 0x2C, 0x15, 0x0F, 0xCC, 0xC9, 0xD1, 0x65, 0xCC, 0x64, 0x12, 0x64, 0xAD, 0x38, 0xCB, 0x41, 0x9B, 0xFA, 0x5E, 0x48, 0xB1, 0x9E, 0xFB, 0xA6, 0x46, 0xA1, 0x85, 0x9B, 0xB4, 0x00, 0x63, 0xA5, 0x21, 0x2E, 0xD8, 0xFB, 0x5A, 0x60, 0x27, 0x07, 0x93, 0xBE, 0x84, 0xC6, 0xD8, 0x65, 0xA8, 0x67, 0x12, 0x76, 0xE0, 0x8E, 0xE7, 0x71, 0xD7, 0x4A, 0x35, 0xCC, 0xDE, 0x95, 0xC6, 0x1D, 0x6B, 0x19, 0x29, 0x21, 0x0E, 0xAE, 0x6E, 0xA1, 0x03, 0xCE, 0x2A, 0x04, 0x1E, 0xAE, 0x6A, 0xA0, 0xBA, 0xED, 0x9F, 0x73, 0x6C, 0x54, 0x23, 0x8D, 0xA9, 0xFB, 0x05, 0x73, 0x6C, 0x0A, 0x79, 0x2D, 0x31, 0x06, 0x41, 0xA0, 0xCF, 0x46, 0xC5, 0x02, 0xDA, 0x44, 0x98, 0x1C, 0x7C, 0x85, 0xDA, 0x6B, 0xC4, 0x4A, 0x39, 0xD6, 0x0F, 0xCC, 0x79, 0xAA, 0xE5, 0x2B, 0x79, 0x43, 0xBC, 0x34, 0x91, 0x58, 0x07, 0xA9, 0x61, 0x13, 0x40, 0x9A, 0xF8, 0x4C, 0x95, 0x6C, 0xBF, 0x7E, 0x8F, 0x1E, 0x44, 0xCF, 0x8E, 0x37, 0x51, 0x4A, 0x1C, 0xC7, 0x78, 0x01, 0xA2, 0x07, 0x0A, 0x3B, 0xBE, 0xC6, 0xA6, 0x7F, 0xD5, 0xBF, 0xB6, 0x67, 0x68, 0x16, 0x76, 0x44, 0xE5, 0x7C, 0x03, 0x69, 0x0C, 0x12, 0xA4, 0xA1, 0x8B, 0xBD, 0xEA, 0x35, 0xFB, 0x3A, 0x2D, 0x61, 0x9A, 0x55, 0xBE, 0x10, 0xCB, 0x9B, 0x79, 0xA8, 0x4B, 0x10, 0xD8, 0xE6, 0xD3, 0x85, 0x56, 0x46, 0x5B, 0x5A, 0x10, 0x57, 0x69, 0x66, 0xF1, 0xD4, 0xCC, 0x4A, 0x1F, 0x4E, 0x36, 0x2A, 0xD5, 0x84, 0x36, 0x3F, 0xDA, 0xF0, 0xAD, 0x0B, 0xF1, 0x79, 0x29, 0x0D, 0x57, 0xC3, 0xD8, 0xD2, 0x74, 0x01, 0xB0, 0xF2, 0x14, 0x18, 0x3A, 0x7C, 0x36, 0x9A, 0x06, 0x53, 0xF5, 0x10, 0x57, 0xE7, 0x6F, 0x6E, 0x8B, 0x68, 0x34, 0x2D, 0x59, 0x2E, 0x2B, 0xA1, 0xA1, 0xDB, 0x44, 0x40, 0x98, 0x0C, 0x1D, 0x61, 0x6E, 0x8B, 0xF5, 0xF1, 0x5A, 0x18, 0xC3, 0x1E, 0xDD, 0xAC, 0xC2, 0x9A, 0xC5, 0x80, 0x43, 0x8E, 0x5A, 0x64, 0x52, 0x68, 0x89, 0x19, 0x1F, 0x01, 0x99, 0xE1, 0x98, 0x84, 0xC4, 0xA6, 0xDA, 0xE8, 0x92, 0x10, 0x10, 0xAE, 0x79, 0xC0, 0xA4, 0x19, 0xBC, 0x3B, 0x0E, 0x62, 0x2E, 0xE0, 0xAD, 0xC0, 0xFE, 0xF4, 0xFD, 0x43, 0xB7, 0xBD, 0x4B, 0x80, 0x0D, 0xE3, 0x00, 0xA3, 0xD7, 0xD2, 0xDD, 0x26, 0xF3, 0x34, 0xFE, 0x9C, 0x5B, 0x14, 0xF8, 0xBC, 0xA4, 0x09, 0x9E, 0x6F, 0x9D, 0xAE, 0x55, 0xB8, 0xF6, 0xC4, 0xB1, 0x17, 0x45, 0x9E, 0xE6, 0xD7, 0xEE, 0xEF, 0xB1, 0x03, 0x95, 0x69, 0x29, 0x7C, 0x14, 0x7B, 0xF0, 0x12, 0xC5, 0x0C, 0xFA, 0xBC, 0x34, 0x13, 0x48, 0x39, 0xEF, 0x54, 0x57, 0xBF, 0xFB, 0x88, 0x3F, 0x3C, 0x01, 0xC7, 0x5B, 0xA9, 0x4A, 0x47, 0xE2, 0xDC, 0xAE, 0x22, 0xC5, 0xB7, 0xF3, 0x9C, 0x16, 0xA2, 0x1A, 0x9D, 0x27, 0xF6, 0x88, 0x84, 0x30, 0xCC, 0x25, 0x50, 0xF8, 0x6D, 0xA8, 0x04, 0xAA, 0x1E, 0x29, 0xF1, 0x55, 0x0A, 0xD8, 0x8F, 0xC4, 0x99, 0xE2, 0x07, 0x0D, 0xCB, 0xD9, 0xAB, 0xFA, 0x39, 0x10, 0x4D, 0x76, 0x65, 0xA9, 0xB8, 0xC5, 0x8B, 0xE9, 0x8B, 0x41, 0x83, 0xC7, 0xF1, 0xA6, 0x6E, 0x55, 0x7C, 0x60, 0x91, 0x83, 0xE5, 0xF2, 0x02, 0x09, 0x05, 0x16, 0xAA, 0xBF, 0x8D, 0x31, 0x07, 0xE2, 0x49, 0x9B, 0x29, 0xD3, 0x59, 0x3D, 0xE2, 0xBA, 0x9D, 0x16, 0xB5, 0x39, 0xD0, 0xC1, 0x51, 0xF7, 0xF0, 0xE1, 0x96, 0xFD, 0xF5, 0x7A, 0xE6, 0xF3, 0xB4, 0xE5, 0x8A, 0xE9, 0xB9, 0xA0, 0x3A, 0xEC, 0x96, 0x70, 0x0B, 0xE5, 0xBF, 0x52, 0x4E, 0xA4, 0x48, 0xEC, 0xAE, 0x16, 0x82, 0x5C, 0x29, 0xA9, 0xE1, 0x6E, 0x38, 0xC3, 0x79, 0x24, 0xEB, 0x7E, 0xD5, 0xE8, 0x33, 0x87, 0x2E, 0x0D, 0x09, 0x9C, 0x96, 0x15, 0x4C, 0xBC, 0x53, 0xF0, 0xF1, 0x9C, 0x50, 0xB6, 0x70, 0xDD, 0xE7, 0xC9, 0x72, 0x23, 0x35, 0x74, 0xC6, 0x5A, 0xA0, 0x00, 0x67, 0x32, 0x99, 0x36, 0x5B, 0x43, 0x70, 0x56, 0xCB, 0xDE, 0x78, 0xF6, 0x88, 0x78, 0x6E, 0xB9, 0xDD, 0x75, 0x32, 0x54, 0xA2, 0x30, 0x15, 0xA5, 0xE5, 0x4B, 0xE0, 0x4F, 0xB7, 0xA6, 0x08, 0xB6, 0xE6, 0x89, 0xBB, 0x4F, 0x2C, 0x72, 0xF0, 0x99, 0x37, 0x87, 0x9E, 0xA7, 0x9B, 0x0E, 0x0E, 0xC0, 0x0A, 0xB8, 0xD6, 0x6C, 0xC7, 0x87, 0xE4, 0xD9, 0x67, 0x59, 0x1D, 0x6B, 0xE1, 0xEB, 0x98, 0x44, 0x11, 0x2A, 0x52, 0x7E, 0x9D, 0x1F, 0xA5, 0xEE, 0x7F, 0x95, 0x38, 0xB7, 0x54, 0xFD, 0xF2, 0x19, 0x96, 0xB1, 0x45, 0xBA, 0xD0, 0x1C, 0xD7, 0x3D, 0x04, 0x2D, 0x2B, 0xE3, 0x70, 0x15, 0x3D, 0x5E, 0xD5, 0x3E, 0x5E, 0xD4, 0x33, 0x32, 0x3A, 0x8D, 0xB0, 0xBF, 0x83, 0xF0, 0x3F, 0x8B, 0x96, 0xC4, 0x2C, 0xD9, 0xC9, 0xA3, 0x81, 0x20, 0x8F, 0xFD, 0xA0, 0x58, 0xA4, 0xA0, 0xC2, 0xF4, 0xA3, 0x7E, 0x98, 0x53, 0x09, 0xE8, 0xD0, 0x80, 0xB7, 0x35, 0x32, 0x62, 0xE0, 0x6B, 0xF6, 0x3F, 0x82, 0xE7, 0xAD, 0x07, 0xBF, 0x06, 0x8B, 0xC0, 0x93, 0xB6, 0x85, 0x04, 0x4C, 0x4F, 0x41, 0xF9, 0x64, 0xCA, 0x1B, 0xED, 0x2F, 0x1F, 0xD8, 0x54, 0xD6, 0x13, 0x13, 0x9B, 0x1F, 0xBD, 0xE1, 0x6B, 0xAD, 0x79, 0x93, 0x0A, 0xEE, 0xEE, 0x86, 0x58, 0xAE, 0x71, 0xD1, 0xB4, 0xB9, 0x65, 0x95, 0xE4, 0xFC, 0xED, 0x1A, 0x2C, 0x29, 0x1E, 0xC7, 0x26, 0x10, 0x70, 0x0C, 0xA0, 0xE3, 0x69, 0x24, 0x84, 0xEA, 0x07, 0xCE, 0xE7, 0x2C, 0x9B, 0x8A, 0x2E, 0x5A, 0x97, 0x12, 0x93, 0xBE, 0x38, 0x2D, 0x2A, 0xB0, 0xFE, 0x1F, 0x3F, 0x36, 0x54, 0x19, 0x22, 0xE1, 0x03, 0x0A, 0xB0, 0x65, 0xD0, 0x76, 0x64, 0x53, 0x96, 0xD7, 0x12, 0x9F, 0xE7, 0xEF, 0xBB, 0x73, 0x75, 0x39, 0x02, 0x27, 0x18, 0x9B, 0xED, 0xBD, 0x3C, 0x83, 0xB1, 0x61, 0x7E, 0x5A, 0x2A, 0x0B, 0x06, 0xFA, 0xEA, 0x43, 0x9A, 0x1D, 0xE1, 0xCD, 0x7E, 0x9C, 0xB4, 0x0A, 0xD8, 0xB2, 0x97, 0x68, 0x8C, 0x0C, 0xF8, 0x25, 0x47, 0xD0, 0xB6, 0x5C, 0x6A, 0x9D, 0x2A, 0x7F, 0xE3, 0x96, 0x78, 0xB3, 0xC9, 0x6B, 0xE4, 0xD0, 0xE6, 0xD0, 0x1A, 0x51, 0xF6, 0xA2, 0x19, 0x80, 0xB0, 0x0E, 0x43, 0x16, 0x7F, 0xCD, 0x36, 0x6F, 0x00, 0x6D, 0x90, 0x53, 0xA6, 0x1A, 0x9A, 0xA1, 0xFE, 0x19, 0x6B, 0xAC, 0x97, 0xA4, 0xF5, 0xD4, 0x3F, 0x5A, 0x99, 0xF2, 0xB5, 0x72, 0x18, 0xA1, 0x9C, 0x07, 0xAF, 0xE6, 0x31, 0xC0, 0x55, 0xD3, 0x6F, 0x8F, 0x23, 0x58, 0xD0, 0x69, 0xC7, 0x9C, 0xC6, 0x46, 0xAE, 0x4E, 0x30, 0x41, 0x4F, 0xC6, 0x0A, 0x8D, 0x0E, 0xC0, 0x45, 0xED, 0x10, 0xC2, 0x74, 0x41, 0xB4, 0x45, 0x78, 0x58, 0x40, 0x63, 0xE7, 0x26, 0xA9, 0x38, 0xB1, 0xB0, 0x9F, 0x22, 0x09, 0xC8, 0x10, 0x5C, 0xCC, 0xF9, 0xA1, 0x90, 0x82, 0x9F, 0xE4, 0x7F, 0xED, 0x26, 0x4A, 0xCF, 0xBE, 0xC7, 0x8F, 0x8E, 0x8B, 0x1A, 0x8E, 0x10, 0x28, 0xB0, 0xDD, 0x2C, 0x59, 0xBF, 0xEF, 0xE2, 0x47, 0xDC, 0xCD, 0x85, 0x98, 0x54, 0x42, 0x13, 0xA3, 0x6A, 0x5F, 0x19, 0x05, 0xC8, 0x7D, 0x96, 0xAC, 0x8C, 0xC1, 0x2D, 0x37, 0xAC, 0xE5, 0x96, 0x97, 0xA1, 0x39, 0xD3, 0x53, 0x69, 0x7E, 0x1E, 0xEA, 0xB1, 0x24, 0x1C, 0x6D, 0xFA, 0x70, 0x76, 0x21, 0xEC, 0x47, 0x51, 0x13, 0xA5, 0x26, 0xD9, 0x11, 0x1F, 0xC9, 0xB5, 0x95, 0x7A, 0xA5, 0x44, 0xD6, 0x1D, 0x9F, 0xB7, 0x60, 0xAD, 0xE4, 0xA2, 0x86, 0xDF, 0x28, 0x5B, 0xBD, 0x1A, 0xE6, 0x48, 0x63, 0xF7, 0x04, 0xEA, 0x46, 0x44, 0xD9, 0xCB, 0x2E, 0x77, 0xD2, 0x23, 0x80, 0x01, 0xE7, 0xC8, 0x96, 0x1E, 0xFA, 0x19, 0x54, 0xEC, 0xE6, 0xEC, 0x59, 0xA4, 0x75, 0x8B, 0x87, 0xC3, 0x18, 0x81, 0x9F, 0x86, 0x5D, 0x73, 0x54, 0xC1, 0xD5, 0xDF, 0xCF, 0xDE, 0x5B, 0x41, 0xF4, 0xEE, 0xA9, 0x30, 0xA7, 0xFE, 0x40, 0x80, 0x8D, 0xE9, 0x50, 0xBD, 0x88, 0x19, 0x96, 0xC6, 0xA3, 0x33, 0xAF, 0x6F, 0xB0, 0x90, 0xDD, 0x2E, 0xF3, 0x94, 0x5F, 0x9C, 0xCC, 0x0A, 0x60, 0x17, 0xA3, 0x6C, 0xE4, 0x84, 0x47, 0xFD, 0xD9, 0x61, 0xE4, 0xB1, 0x7D, 0xD0, 0x2B, 0x4A, 0x3A, 0xA7, 0xB5, 0xE9, 0x8A, 0x86, 0xEA, 0x97, 0x3E, 0x66, 0x97, 0xCA, 0x03, 0x44, 0xCB, 0xFC, 0xB5, 0xF2, 0xD9, 0xAE, 0xE9, 0xEF, 0x6E, 0xF6, 0xF5, 0x7F, 0x62, 0x72, 0x88, 0x6D, 0x67, 0x11, 0x23, 0x46, 0xB2, 0x56, 0xBF, 0xF7, 0xA5, 0xA1, 0x5B, 0x6E, 0x31, 0x07, 0x5D, 0x68, 0xA9, 0xBD, 0x73, 0x8B, 0x16, 0x0D, 0x9D, 0x2B, 0x06, 0x9B, 0x45, 0xB2, 0xC5, 0x8C, 0xA7, 0x01, 0x65, 0xF6, 0x00, 0x9F, 0xEF, 0xE9, 0xFB, 0xE6, 0xB7, 0xD2, 0x51, 0x95, 0x1C, 0xF8, 0x16, 0x23, 0x3D, 0x0C, 0x0B, 0xE5, 0x99, 0xE6, 0xA6, 0x9D, 0xDD, 0xAD, 0x52, 0xD2, 0x15, 0xE1, 0xBA, 0xB1, 0xF7, 0xF8, 0x54, 0x45, 0x38, 0x39, 0xA0, 0x07, 0x0A, 0xC4, 0x28, 0x2A, 0x48, 0x75, 0xF3, 0x85, 0xF7, 0x2C, 0x7A, 0x9D, 0xE6, 0x92, 0x1B, 0xCA, 0xD9, 0xE1, 0x73, 0xE1, 0x3D, 0x33, 0xB6, 0xA0, 0x94, 0xF0, 0xE4, 0x66, 0xA0, 0xE4, 0xC9, 0x49, 0x5E, 0xA0, 0x75, 0x43, 0xE1, 0x2D, 0x9F, 0x95, 0x20, 0x96, 0xDB, 0xCD, 0xA1, 0x57, 0x5B, 0xC1, 0x0C, 0xCC, 0xF0, 0xAF, 0x60, 0xCD, 0x4A, 0x75, 0x7A, 0xF9, 0x0E, 0x4E, 0xCD, 0x08, 0x32, 0x26, 0xE8, 0x31, 0x87, 0x09, 0x68, 0x5D, 0x3C, 0x26, 0xB6, 0xF9, 0x51, 0x5B, 0x0E, 0x08, 0xFC, 0x51, 0xF0, 0x90, 0x6D, 0x73, 0x30, 0x50, 0x4C, 0xD4, 0x13, 0x6F, 0xF6, 0x2D, 0xC5, 0x6A, 0xB2, 0x3B, 0xB5, 0xAB, 0x4B, 0x4D, 0x71, 0x3F, 0xCD, 0x4C, 0xB6, 0x84, 0x03, 0x6A, 0x74, 0x36, 0x6B, 0xBC, 0x67, 0x46, 0x52, 0xAC, 0x6E, 0xDD, 0x0B, 0x7B, 0xB2, 0xF1, 0x5D, 0x70, 0xF0, 0x86, 0x85, 0x1B, 0x94, 0x65, 0x24, 0x71, 0x52, 0x7C, 0xA2, 0x7F, 0x06, 0x74, 0x45, 0x9A, 0x7B, 0x00, 0x8B, 0x35, 0x53, 0x9E, 0xC2, 0x4F, 0x65, 0x16, 0x03, 0x4F, 0xCF, 0x6F, 0x84, 0xCD, 0x65, 0xD2, 0xA5, 0x06, 0x26, 0xE0, 0xD6, 0x62, 0xBC, 0x02, 0x9F, 0x52, 0x54, 0xFB, 0x20, 0xAD, 0x8C, 0x92, 0xB2, 0xBB, 0xE2, 0x75, 0xBB, 0x69, 0x67, 0xF4, 0x18, 0x22, 0xA9, 0x21, 0x6C, 0x30, 0x6C, 0x2A, 0x32, 0x7E, 0x13, 0xEF, 0x14, 0xC4, 0x65, 0x1D, 0x0F, 0x42, 0x5B, 0xDD, 0xD3, 0x07, 0x08, 0x1C, 0xDB, 0x6D, 0xC7, 0xB4, 0x0C, 0xF6, 0xB2, 0x73, 0xFC, 0xEE, 0x1D, 0x78, 0x19, 0x6C, 0xE7, 0xAF, 0x83, 0xEB, 0x85, 0x03, 0x9A, 0x00, 0x17, 0x86, 0x2F, 0xF3, 0x04, 0x8B, 0xB6, 0x5B, 0xBD, 0xCF, 0x5B, 0x4D, 0x3E, 0x25, 0x3C, 0x1B, 0x3F, 0x52, 0x2E, 0x33, 0x74, 0x74, 0x5E, 0x35, 0xFB, 0x32, 0x20, 0x8D, 0xCC, 0x5C, 0x25, 0x6A, 0x5C, 0x87, 0xF4, 0x03, 0x34, 0x41, 0xB7, 0x6F, 0x6B, 0x4C, 0x11, 0xE2, 0x84, 0xB0, 0xD5, 0x3B, 0xB5, 0x03, 0x64, 0x1D, 0x8B, 0x4C, 0x41, 0xBE, 0x7B, 0xE2, 0x17, 0xDD, 0xCC, 0xCA, 0xBE, 0xBB, 0xDE, 0x2C, 0x48, 0xCE, 0x37, 0x55, 0x0F, 0x8A, 0xA1, 0x7F, 0x41, 0x7E, 0x8F, 0x6D, 0x76, 0x58, 0x0C, 0x69, 0x03, 0x0F, 0xE1, 0x7E, 0x5C, 0x16, 0x6B, 0xC5, 0x11, 0x32, 0xBB, 0xC5, 0x26, 0x4C, 0x87, 0x64, 0x9E, 0x2F, 0xA3, 0x56, 0xD6, 0xF8, 0x95, 0x78, 0x5F, 0x2D, 0xFC, 0x46, 0x77, 0xA6, 0xEA, 0xF7, 0xBA, 0xE8, 0x68, 0xB0, 0x90, 0xD9, 0x0C, 0xCF, 0x11, 0xEA, 0x20, 0x97, 0x93, 0x3D, 0x5F, 0x19, 0x9A, 0x9A, 0x32, 0x4B, 0xF9, 0x7A, 0xDE, 0xE6, 0x8A, 0x04, 0x07, 0x13, 0x41, 0x66, 0xB1, 0x0C, 0x5E, 0x52, 0x31, 0x32, 0xBB, 0x93, 0xDE, 0x89, 0xB3, 0x86, 0xE4, 0xB2, 0x70, 0x98, 0x0C, 0x35, 0x13, 0x2B, 0x67, 0x7C, 0xE9, 0xD9, 0xF2, 0x50, 0x80, 0x2E, 0x4C, 0x77, 0x9C, 0x44, 0x15, 0x3A, 0x3A, 0x4F, 0xD0, 0x86, 0x64, 0x10, 0x2F, 0x5A, 0xE9, 0x9C, 0xE9, 0xF0, 0x40, 0x38, 0x35, 0x00, 0xE9, 0x99, 0x65, 0x54, 0x04, 0x7A, 0x90, 0xDC, 0x24, 0xB2, 0x2F, 0x77, 0xD1, 0x99, 0xCB, 0xAD, 0xD9, 0xC4, 0xA5, 0xC4, 0xF0, 0x10, 0x60, 0x80, 0xDE, 0xE3, 0x6F, 0xBE, 0x4A, 0x1F, 0xBE, 0x3E, 0x71, 0x68, 0xB5, 0x4F, 0x88, 0xD5, 0xEF, 0xE7, 0x5E, 0x07, 0x05, 0xE7, 0xF2, 0xBB, 0xD5, 0xF0, 0x1C, 0xA8, 0x8A, 0x3A, 0x5C, 0xAD, 0x44, 0x16, 0x26, 0x34, 0x8B, 0xE4, 0xF6, 0x5B, 0xED, 0xC6, 0x5D, 0xA4, 0xF9, 0x21, 0x8A, 0xCE, 0xBF, 0x93, 0x9D, 0x48, 0xD5, 0x3D, 0x54, 0x01, 0xF4, 0x60, 0x91, 0x77, 0xCE, 0xF8, 0x3B, 0x1D, 0xBD, 0xCF, 0x5E, 0xE2, 0x6B, 0xB5, 0x47, 0x62, 0x37, 0x1D, 0xBA, 0xCA, 0x8E, 0x4D, 0x17, 0xF9, 0xE0, 0xBE, 0x96, 0x11, 0x15, 0xA7, 0x15, 0x15, 0x36, 0x8B, 0xDC, 0x16, 0xF5, 0xB8, 0x57, 0xF7, 0xCD, 0xDE, 0xB5, 0xE7, 0x8A, 0xFB, 0x58, 0x6F, 0x19, 0x72, 0x5B, 0xD6, 0xEC, 0xA4, 0xA7, 0x76, 0xB2, 0xE7, 0x13, 0x1F, 0x66, 0x19, 0x9E, 0xD5, 0x5A, 0x68, 0x91, 0xA6, 0x32, 0x6A, 0xC9, 0x3C, 0xBF, 0x2C, 0xA2, 0x24, 0xB4, 0xB8, 0x04, 0xC4, 0x89, 0x3C, 0x97, 0x7C, 0xFB, 0x75, 0xBA, 0xDC, 0xCF, 0x56, 0x7B, 0x49, 0x05, 0x8C, 0x60, 0xF5, 0x49, 0x52, 0x22, 0x64, 0xDC, 0x5E, 0xF9, 0xCA, 0x9D, 0xA5, 0x30, 0x0D, 0x10, 0xC5, 0x5A, 0x3E, 0x0B, 0x91, 0x68, 0x1C, 0x35, 0xB8, 0x44, 0xEC, 0x78, 0xAC, 0x03, 0x42, 0x95, 0x71, 0x61, 0x36, 0x9F, 0x19, 0x2F, 0xC6, 0xB6, 0xE6, 0x25, 0xF1, 0xF8, 0xC0, 0x59, 0x73, 0x0A, 0x99, 0xD1, 0xA4, 0x73, 0xD3, 0x89, 0x2B, 0x95, 0x5F, 0xAC, 0xCF, 0x92, 0x66, 0x02, 0x32, 0xB0, 0x29, 0x6F, 0xA6, 0xE9, 0xCA, 0xC5, 0x6C, 0xCB, 0xB2, 0xE9, 0xD9, 0xC6, 0x55, 0x30, 0x14, 0x5A, 0xFB, 0x13, 0x41, 0xB8, 0x73, 0x75, 0xB5, 0x15, 0x88, 0x93, 0xB9, 0x3A, 0xE9, 0x9E, 0x39, 0x2B, 0xFE, 0x69, 0x40, }, .pkcs8_len = 0, .spki_len = 0, .msg_len = 66, .msg = { 0x22, 0x5D, 0x5C, 0xE2, 0xCE, 0xAC, 0x61, 0x93, 0x0A, 0x07, 0x50, 0x3F, 0xB5, 0x9F, 0x7C, 0x2F, 0x93, 0x6A, 0x3E, 0x07, 0x54, 0x81, 0xDA, 0x3C, 0xA2, 0x99, 0xA8, 0x0F, 0x8C, 0x5D, 0xF9, 0x22, 0x3A, 0x07, 0x3E, 0x7B, 0x90, 0xE0, 0x2E, 0xBF, 0x98, 0xCA, 0x22, 0x27, 0xEB, 0xA3, 0x8C, 0x1A, 0xB2, 0x56, 0x82, 0x09, 0xE4, 0x6D, 0xBA, 0x96, 0x18, 0x69, 0xC6, 0xF8, 0x39, 0x83, 0xB1, 0x7D, 0xCD, 0x49, }, .sig_len = 3293, .sig = { 0xBE, 0xE5, 0x9E, 0x79, 0x09, 0xC2, 0xA0, 0xAB, 0xBD, 0xC3, 0xF9, 0xD0, 0x7D, 0x40, 0x5A, 0x96, 0x2E, 0x64, 0x2A, 0x1F, 0x1C, 0x1F, 0xD0, 0xB7, 0xAD, 0x6D, 0x99, 0x99, 0x0C, 0xE6, 0x9D, 0x5D, 0x8D, 0x2D, 0xF8, 0x9B, 0xB9, 0x6F, 0xF9, 0xB5, 0xB6, 0xFC, 0xA6, 0x48, 0xDF, 0x08, 0x56, 0x45, 0x7B, 0x91, 0x9B, 0x38, 0x13, 0x16, 0x35, 0xDD, 0x81, 0x4A, 0x7A, 0xA8, 0xB0, 0xB9, 0x47, 0xDD, 0x70, 0xA6, 0x7E, 0x49, 0x73, 0xFE, 0x33, 0xE1, 0xE0, 0x02, 0x22, 0x59, 0x7C, 0x2B, 0xE8, 0xF8, 0x67, 0x80, 0x12, 0x26, 0x41, 0x53, 0xAA, 0xCA, 0x64, 0x80, 0xC5, 0xF1, 0x8C, 0xA3, 0xC0, 0x50, 0x45, 0x0D, 0x42, 0xD9, 0xE5, 0x6B, 0x9B, 0x5E, 0x76, 0xF3, 0xAE, 0x3B, 0xDB, 0x58, 0x95, 0x81, 0xC4, 0xAC, 0xF8, 0x10, 0x75, 0x35, 0xB1, 0xFE, 0x7D, 0x49, 0x42, 0xCB, 0xBC, 0xDF, 0xBA, 0x4E, 0xC1, 0xAF, 0xBA, 0xA4, 0x60, 0x95, 0x61, 0x95, 0xB1, 0x72, 0x93, 0xDC, 0x18, 0xCF, 0x0A, 0x3B, 0x43, 0x6E, 0xC4, 0x74, 0x60, 0x0B, 0xE1, 0xB6, 0xE6, 0x1A, 0xE6, 0x1C, 0x4F, 0x9B, 0x2F, 0xB1, 0x22, 0x98, 0x36, 0x2D, 0x9E, 0xF0, 0x1E, 0xC6, 0x8A, 0x46, 0x22, 0x95, 0x7B, 0x96, 0x4C, 0x30, 0x56, 0x29, 0xC4, 0x26, 0x34, 0xCF, 0x88, 0x47, 0xA7, 0x58, 0x12, 0x09, 0x41, 0x8E, 0x24, 0x58, 0x90, 0x6E, 0x15, 0xC8, 0xE3, 0x0E, 0x74, 0xD8, 0xC8, 0x74, 0xD8, 0x5D, 0xC6, 0x3E, 0xB1, 0x1A, 0x96, 0x07, 0x57, 0xAD, 0xD9, 0xED, 0xAA, 0x6D, 0x9A, 0xF8, 0xB2, 0xE3, 0x55, 0x10, 0x22, 0xB2, 0x34, 0x26, 0x31, 0x9D, 0x37, 0xAD, 0xF1, 0x92, 0xC2, 0x4E, 0xFD, 0xCF, 0x8D, 0x95, 0xEF, 0xE8, 0x6C, 0x16, 0x45, 0x9A, 0xAC, 0xA0, 0xDF, 0x6A, 0xE4, 0x14, 0xCD, 0x93, 0xB7, 0x0D, 0x57, 0xE7, 0xA7, 0x64, 0x4C, 0x48, 0x91, 0xC0, 0x87, 0x96, 0xB3, 0xFD, 0x59, 0x2E, 0x51, 0xB1, 0xFA, 0x59, 0x1F, 0xD7, 0x1B, 0xC4, 0xFE, 0xC3, 0xB9, 0xA8, 0xDF, 0x5A, 0x92, 0x53, 0x57, 0xDF, 0x46, 0x82, 0xA4, 0x58, 0x3F, 0x78, 0x8B, 0x61, 0x9D, 0x6D, 0xEC, 0x6A, 0xCD, 0x4A, 0x5A, 0x17, 0xE8, 0xF4, 0x16, 0x53, 0x96, 0x2A, 0x83, 0xB4, 0x5D, 0xA6, 0xC0, 0x87, 0xC8, 0xBE, 0xF1, 0x6E, 0x95, 0xD2, 0xD4, 0x34, 0x38, 0x52, 0x7E, 0x92, 0x73, 0x64, 0x5E, 0x22, 0x58, 0x4E, 0xE6, 0xAD, 0xCE, 0xA4, 0xE2, 0x51, 0xCD, 0x79, 0xA0, 0x78, 0xEF, 0xF9, 0xC2, 0x9C, 0xE4, 0x52, 0xEA, 0xBA, 0x9C, 0xE3, 0x21, 0x25, 0x71, 0x9F, 0xBE, 0xE5, 0xF9, 0xA9, 0x01, 0x31, 0xDF, 0x0C, 0xFD, 0xCA, 0x49, 0x49, 0x6A, 0xDC, 0x48, 0x5E, 0x8B, 0x08, 0xF3, 0x0F, 0xC3, 0xED, 0x0A, 0x29, 0x2A, 0x15, 0x4E, 0x3E, 0x3C, 0x89, 0x34, 0x4A, 0xB9, 0xBA, 0x4E, 0x33, 0x23, 0xDD, 0x16, 0xC6, 0xEE, 0xD1, 0x84, 0xFE, 0x25, 0xE5, 0x62, 0xAC, 0x6B, 0xF7, 0xD0, 0x44, 0x15, 0xEA, 0x37, 0x0B, 0x72, 0xE5, 0x1A, 0x44, 0x9E, 0xE6, 0xB5, 0x81, 0x83, 0x25, 0x0C, 0xDC, 0xB2, 0x27, 0x20, 0x5E, 0xCE, 0x5E, 0x9F, 0x63, 0x1D, 0xFE, 0xDE, 0x70, 0x2C, 0xE4, 0xEC, 0x66, 0xF8, 0x3B, 0xA7, 0x9D, 0x3F, 0xB4, 0x42, 0x2A, 0xD6, 0xF4, 0x3B, 0x64, 0x41, 0x18, 0x95, 0x3E, 0x56, 0x47, 0x5D, 0x2D, 0x0C, 0x3A, 0x92, 0x51, 0xD9, 0x6A, 0x98, 0x67, 0xD8, 0x04, 0x9D, 0xF2, 0x17, 0x72, 0x4B, 0x42, 0x0F, 0xC3, 0xA4, 0xDF, 0x2B, 0x86, 0x78, 0xD2, 0x90, 0x2B, 0x32, 0xD4, 0x4D, 0x93, 0x3F, 0xC5, 0x6C, 0x3F, 0x80, 0x22, 0xF8, 0x7A, 0xFD, 0xA3, 0x76, 0x89, 0x10, 0x5C, 0xAC, 0x8E, 0xCB, 0x2C, 0x8C, 0x2A, 0x92, 0x8B, 0xDB, 0xAE, 0x81, 0x01, 0xE3, 0x44, 0x9F, 0x61, 0x36, 0xB0, 0x53, 0xAA, 0xA2, 0x0C, 0x14, 0x0B, 0xD9, 0x20, 0xB9, 0xBB, 0x67, 0x65, 0x5E, 0xE7, 0x9B, 0xC4, 0xE2, 0x63, 0x6C, 0xB0, 0xCA, 0x4A, 0x7E, 0xFE, 0x39, 0x72, 0xF9, 0xA0, 0xC6, 0xCF, 0x16, 0xAD, 0x16, 0x33, 0xCE, 0x51, 0xF2, 0xC5, 0x4A, 0x77, 0x12, 0xE6, 0x9D, 0x57, 0x7A, 0x20, 0x83, 0x4C, 0x4A, 0xD1, 0xCC, 0xE4, 0xE3, 0xF8, 0xC1, 0xAB, 0x65, 0xC1, 0x54, 0x8B, 0x00, 0x02, 0x67, 0x28, 0xE5, 0x7D, 0x42, 0xA2, 0x94, 0x28, 0x82, 0xB2, 0x4B, 0x45, 0x94, 0x44, 0xEB, 0x43, 0x2B, 0x89, 0x5A, 0xCA, 0x2A, 0x71, 0xA6, 0x2A, 0x34, 0x92, 0x7E, 0x56, 0x75, 0x81, 0xD8, 0xBA, 0x2A, 0x1E, 0x52, 0xF0, 0xAE, 0xEE, 0xE1, 0xB0, 0x86, 0x4B, 0xF3, 0x7D, 0x7A, 0xE5, 0xCA, 0x2D, 0x2F, 0x15, 0x2E, 0x73, 0x89, 0x22, 0x4C, 0xA7, 0xF9, 0x13, 0x2B, 0x89, 0x39, 0xE1, 0xB1, 0xCC, 0xBF, 0xC0, 0x3B, 0x2B, 0xE9, 0xA4, 0x60, 0xCF, 0xC7, 0xDC, 0x5A, 0xA5, 0x04, 0xF7, 0xFC, 0xD9, 0x46, 0xDC, 0xE5, 0xC6, 0x39, 0x9D, 0xA6, 0xC0, 0xC8, 0xD8, 0xCC, 0x8B, 0x0C, 0x0B, 0x30, 0x73, 0x6C, 0x63, 0x10, 0x25, 0xA6, 0xA3, 0xA9, 0xE2, 0xD9, 0x4C, 0xDC, 0xBD, 0x3C, 0xE7, 0xA6, 0x8D, 0x7F, 0xFD, 0xEE, 0xAA, 0x45, 0x9B, 0x10, 0x4B, 0xB7, 0x30, 0xED, 0x7C, 0x9E, 0x87, 0xBB, 0x02, 0xE8, 0x9D, 0xEE, 0x4F, 0x91, 0x5F, 0xD2, 0xE3, 0x1B, 0xF4, 0x18, 0xA1, 0x55, 0x02, 0xA4, 0xB2, 0xE4, 0x26, 0xED, 0xEA, 0x8A, 0x14, 0x26, 0x90, 0xA4, 0x5E, 0xDA, 0xB3, 0xE6, 0x37, 0xF7, 0x97, 0xE7, 0xA7, 0x86, 0xB8, 0xA8, 0xE9, 0x0E, 0x9E, 0xE0, 0xD5, 0x78, 0x1E, 0xCD, 0x16, 0x91, 0x1F, 0xB0, 0xF4, 0xEB, 0x5B, 0x0C, 0x70, 0x74, 0x98, 0xFE, 0x7D, 0x8C, 0x2A, 0xE6, 0x73, 0xA3, 0x33, 0x4A, 0xFB, 0x95, 0xAC, 0x6B, 0x18, 0x5A, 0xF3, 0x6F, 0xA1, 0x87, 0x74, 0x93, 0x8B, 0xA6, 0x56, 0xB2, 0x2F, 0xDC, 0x9A, 0xCB, 0xCF, 0xBF, 0x95, 0xD1, 0xBF, 0x5E, 0xDF, 0x7D, 0x90, 0x5C, 0xF1, 0xB5, 0x40, 0xE1, 0x7B, 0xAB, 0x93, 0x7B, 0x4B, 0xD3, 0x62, 0x0D, 0x59, 0x4C, 0x0D, 0x9B, 0xDB, 0xC7, 0x15, 0x99, 0xCE, 0x69, 0xE5, 0x70, 0x6F, 0xA3, 0x33, 0x20, 0xFE, 0xE0, 0x63, 0x96, 0xCB, 0x97, 0x37, 0xDB, 0x17, 0xA6, 0x2C, 0x96, 0x5F, 0x77, 0xE3, 0x5A, 0xF9, 0xF7, 0x85, 0xBB, 0x0E, 0x50, 0xAB, 0xB8, 0x10, 0x6F, 0xE8, 0xB9, 0x04, 0xD0, 0xCD, 0x1E, 0x15, 0xB9, 0x25, 0x55, 0xF0, 0x5C, 0x24, 0xE7, 0x6E, 0x94, 0xEC, 0x41, 0xEC, 0x90, 0xE9, 0x60, 0x39, 0xB4, 0xA7, 0xCA, 0x9F, 0x8E, 0xD1, 0x3F, 0x1B, 0xE6, 0xFA, 0x85, 0x03, 0x44, 0xD4, 0x46, 0xB1, 0x68, 0x3B, 0x04, 0xB7, 0x5B, 0xBA, 0x0C, 0x08, 0xF7, 0x40, 0x25, 0x67, 0x8E, 0x75, 0x40, 0x35, 0x32, 0x21, 0x9F, 0x37, 0x48, 0xF3, 0xC7, 0x3A, 0xA2, 0x0E, 0x34, 0xD5, 0xEB, 0x1B, 0x0C, 0xBB, 0x58, 0xDA, 0x9A, 0x01, 0xF3, 0x7E, 0x74, 0xC0, 0x63, 0xD0, 0x3A, 0xF3, 0xBA, 0x8F, 0xBA, 0x28, 0x59, 0x2E, 0x41, 0x93, 0x27, 0x0A, 0x00, 0xCD, 0x15, 0x86, 0xF8, 0x33, 0xDF, 0xA8, 0xDB, 0xF4, 0x0C, 0x15, 0xE7, 0x04, 0xD2, 0x53, 0x65, 0x8C, 0xC0, 0x6C, 0x6A, 0x48, 0x88, 0x1B, 0xAE, 0x68, 0xBD, 0x4C, 0xBE, 0x38, 0xE7, 0xC8, 0x94, 0x87, 0x3E, 0x86, 0x3A, 0x2C, 0x4C, 0xA2, 0x24, 0xB7, 0x6E, 0xD6, 0x2B, 0xDC, 0x06, 0xD9, 0x0D, 0x7A, 0x7E, 0xC6, 0x8B, 0x62, 0x2E, 0xB3, 0x8A, 0x42, 0x63, 0x93, 0xA4, 0x6E, 0xCA, 0x77, 0xF2, 0x88, 0x11, 0x5A, 0x2A, 0xEF, 0xAC, 0xC1, 0x5F, 0x44, 0xD9, 0x28, 0x08, 0x8C, 0x5B, 0xC1, 0x9E, 0x08, 0x95, 0xF9, 0x61, 0x9A, 0x08, 0x92, 0x65, 0xB7, 0x6E, 0xEE, 0x26, 0x61, 0xD2, 0x0D, 0x1B, 0xFB, 0x84, 0x79, 0xC2, 0x1C, 0x15, 0x3E, 0x1D, 0xCA, 0xB0, 0xF0, 0x04, 0xF8, 0x0A, 0x07, 0x2D, 0xE3, 0xE4, 0xAB, 0xB6, 0xF6, 0x99, 0xAE, 0xB8, 0x52, 0xF3, 0x5E, 0x3A, 0xFE, 0x0F, 0xA7, 0x99, 0x35, 0x5E, 0x6B, 0x7E, 0xC6, 0xD6, 0x59, 0x20, 0xDC, 0xA5, 0x24, 0x8B, 0x45, 0x5B, 0x90, 0xE7, 0xD2, 0xE9, 0x85, 0x9B, 0x18, 0x30, 0x18, 0x65, 0x74, 0xA9, 0x5C, 0xB6, 0x2A, 0x0F, 0x07, 0x3C, 0xAB, 0x4A, 0xCF, 0x1A, 0x9D, 0x52, 0xA0, 0xD1, 0xF1, 0x76, 0xFE, 0x50, 0x48, 0x77, 0x42, 0xC4, 0x7D, 0x7D, 0x9A, 0x82, 0xC7, 0xEB, 0xCF, 0x67, 0xAE, 0xBC, 0x8C, 0x77, 0xDF, 0xD0, 0x0E, 0x7C, 0xDC, 0xBD, 0xB6, 0x9D, 0x82, 0x12, 0xD5, 0xD4, 0x56, 0x1E, 0x83, 0x1C, 0x1C, 0xEE, 0xC7, 0x57, 0x14, 0x91, 0x1B, 0xFE, 0xDA, 0xBB, 0x71, 0x4E, 0xDB, 0xEC, 0xD8, 0x6D, 0x3B, 0x5B, 0x65, 0xD1, 0x54, 0x28, 0x83, 0x33, 0xEC, 0x57, 0x32, 0x7E, 0x2A, 0x27, 0xF2, 0xCD, 0xF1, 0x93, 0xA4, 0x6F, 0xF1, 0x1B, 0x6A, 0x19, 0xD3, 0xDC, 0x71, 0x12, 0x95, 0xB5, 0x08, 0xBF, 0x44, 0x3F, 0x02, 0xAC, 0x9E, 0xB0, 0x4F, 0x37, 0xB6, 0x7A, 0x8E, 0xD5, 0x49, 0x3F, 0x41, 0xE9, 0x24, 0xF8, 0x48, 0x9F, 0xE2, 0x6A, 0xCA, 0xE5, 0xF6, 0xB0, 0x7B, 0x67, 0x68, 0x31, 0xE2, 0x71, 0xBC, 0xDE, 0x12, 0xC8, 0x0F, 0x65, 0xE8, 0xD0, 0x30, 0x0D, 0x8F, 0xDE, 0xD5, 0xE9, 0xBF, 0x1A, 0x59, 0xC8, 0x8E, 0xD3, 0x89, 0x45, 0x37, 0x14, 0x51, 0xE1, 0x13, 0x54, 0xB3, 0x07, 0x40, 0x47, 0x61, 0x9B, 0x3A, 0x27, 0x66, 0x58, 0x41, 0x7A, 0xA1, 0x75, 0x02, 0x67, 0x49, 0xA4, 0xE4, 0x61, 0xF0, 0x59, 0xAF, 0x85, 0xE2, 0x07, 0xF4, 0xD0, 0x21, 0xBB, 0x9C, 0x12, 0xFD, 0xF3, 0x02, 0x90, 0x79, 0x59, 0x72, 0x17, 0xAA, 0x39, 0x15, 0x20, 0x78, 0x0A, 0x7C, 0x90, 0xC2, 0x32, 0x65, 0x91, 0x14, 0x39, 0x31, 0x84, 0x4F, 0x85, 0x6B, 0x08, 0x4A, 0xC1, 0x7A, 0xEB, 0xC5, 0x93, 0xAC, 0xE9, 0x32, 0xF0, 0xAD, 0x36, 0xE2, 0x13, 0x57, 0xCE, 0xFF, 0xF3, 0x75, 0xCC, 0xC8, 0x43, 0x42, 0xB8, 0x61, 0x94, 0xA2, 0xBC, 0x77, 0x16, 0x5E, 0xDB, 0x9E, 0xFE, 0x35, 0x93, 0x51, 0xAD, 0x8E, 0x4B, 0xDD, 0x4C, 0xA6, 0xEC, 0xFA, 0x05, 0x20, 0xCC, 0x2F, 0x46, 0xCF, 0x8A, 0xA1, 0x10, 0x9E, 0x62, 0x68, 0x2B, 0x37, 0xC7, 0x01, 0x42, 0x1F, 0xEE, 0x8F, 0xB5, 0x0A, 0x7D, 0x11, 0xB2, 0xF5, 0xA0, 0x50, 0x14, 0xED, 0x63, 0xBF, 0x91, 0x0C, 0xBB, 0x06, 0xFA, 0x47, 0xF1, 0xD8, 0x49, 0xAF, 0x11, 0x86, 0xF9, 0x77, 0xD8, 0x07, 0x3D, 0x72, 0x78, 0x3C, 0x4E, 0xE3, 0xC1, 0x9F, 0xF9, 0x5F, 0x23, 0xFC, 0xBD, 0x98, 0x87, 0x9A, 0x46, 0x82, 0xA8, 0xCF, 0xA7, 0x68, 0x7E, 0xA5, 0x20, 0xCE, 0x58, 0x7E, 0x9A, 0x3E, 0x8F, 0x68, 0x4E, 0x00, 0x09, 0x6A, 0xFE, 0x61, 0x7C, 0xEC, 0xFE, 0x0A, 0x6F, 0xDE, 0xB4, 0x5D, 0x49, 0x3E, 0x7E, 0x35, 0xCC, 0x25, 0xB6, 0x44, 0xF9, 0xBD, 0xF4, 0xED, 0x10, 0x41, 0x76, 0xCB, 0x96, 0x1B, 0x0C, 0x95, 0x7F, 0x8F, 0x3C, 0xB4, 0x29, 0xFA, 0x14, 0x4D, 0x60, 0x6D, 0x2D, 0xFE, 0x27, 0xC0, 0x90, 0xA3, 0xC2, 0x26, 0x9C, 0x84, 0xB5, 0xF4, 0x95, 0xC1, 0xC6, 0x6D, 0xD0, 0x79, 0x49, 0x27, 0x4D, 0x99, 0x49, 0x9B, 0x63, 0x3B, 0xFE, 0xA8, 0xF0, 0x44, 0x52, 0x1A, 0xB2, 0x56, 0xF6, 0xF6, 0x24, 0x6A, 0x0C, 0x0A, 0xEA, 0x3A, 0xDE, 0xFD, 0x14, 0xC8, 0xB1, 0xBE, 0x92, 0xA2, 0x34, 0x7C, 0xD1, 0xFB, 0xEE, 0xAD, 0x71, 0x2C, 0xC0, 0xA8, 0xBE, 0x4C, 0xE0, 0xF4, 0x77, 0x9E, 0xAB, 0x56, 0xF7, 0x1D, 0x9A, 0x7B, 0x3F, 0x4B, 0xA7, 0x25, 0x24, 0x34, 0xB9, 0x84, 0xDF, 0xE9, 0xD7, 0x59, 0x65, 0x45, 0x66, 0x5F, 0x2F, 0x1E, 0x51, 0x61, 0xC9, 0xDC, 0x9E, 0xA5, 0x89, 0xE3, 0x01, 0xC7, 0x50, 0xB7, 0x3E, 0x55, 0x26, 0xEF, 0xE6, 0x5F, 0xA0, 0x79, 0x2A, 0xF2, 0xF6, 0x4C, 0xEF, 0xDA, 0x89, 0x1F, 0xB0, 0x81, 0x20, 0x37, 0xFD, 0x0A, 0x31, 0xE7, 0x60, 0x22, 0x83, 0xBE, 0x2B, 0x8D, 0xF6, 0xA7, 0xDB, 0x90, 0xF3, 0x0F, 0x8B, 0x3B, 0x2D, 0x30, 0xC0, 0x9B, 0x90, 0x0F, 0xA4, 0x00, 0xFD, 0x1C, 0x4B, 0x42, 0x56, 0x3D, 0xF1, 0xEB, 0x8E, 0x39, 0xF9, 0x46, 0x85, 0x95, 0x11, 0x2C, 0x92, 0xD4, 0xA8, 0x43, 0xEE, 0xE8, 0x70, 0x34, 0x3F, 0xC8, 0x9E, 0x57, 0xC6, 0xBA, 0xCC, 0x37, 0x0D, 0x01, 0x4A, 0x5E, 0x2A, 0xFE, 0xEF, 0x1C, 0x25, 0xEB, 0xA0, 0x80, 0xEC, 0x13, 0x4E, 0x85, 0x8C, 0xFD, 0x65, 0x4D, 0x0E, 0x96, 0x14, 0x02, 0xD9, 0xA8, 0x07, 0xA9, 0x71, 0xCF, 0x59, 0x2F, 0x33, 0xD1, 0x8E, 0xB2, 0x21, 0x0A, 0x59, 0xE0, 0xFE, 0x94, 0x83, 0x18, 0xE6, 0x0E, 0x6D, 0x61, 0x8D, 0x2D, 0x04, 0x0C, 0x77, 0x3C, 0xE3, 0x0F, 0x91, 0x64, 0xCC, 0xD4, 0x19, 0xF3, 0x25, 0xF2, 0xFA, 0x3D, 0xDE, 0x63, 0xF5, 0xDF, 0x54, 0x76, 0x42, 0x41, 0x25, 0xE4, 0xA9, 0x23, 0x7F, 0x18, 0xEC, 0x9B, 0x41, 0x09, 0x9E, 0x89, 0x05, 0xC1, 0x73, 0xDC, 0x60, 0xDD, 0xB3, 0x6D, 0x18, 0x09, 0xC0, 0xF2, 0x2B, 0x3F, 0xA8, 0xB3, 0x9D, 0x84, 0x2E, 0x44, 0xFD, 0xEC, 0x4D, 0xAB, 0x65, 0x0E, 0x9E, 0x60, 0xE3, 0x1C, 0x05, 0x8E, 0x8C, 0x86, 0x2F, 0x06, 0x9E, 0xD7, 0x00, 0x13, 0x15, 0x77, 0x3A, 0x51, 0x90, 0xC8, 0x64, 0xDC, 0x01, 0xAE, 0x44, 0x5C, 0x59, 0x03, 0xB1, 0x40, 0x07, 0x1A, 0xD7, 0x16, 0xD9, 0x34, 0x3D, 0x78, 0x8A, 0x0D, 0x36, 0x4A, 0x8F, 0x64, 0x46, 0x5E, 0x68, 0x74, 0x86, 0x12, 0xE9, 0x41, 0xC2, 0xE1, 0xC8, 0xC2, 0x77, 0xCE, 0xF0, 0xF6, 0xCC, 0x08, 0xED, 0xFA, 0xA3, 0xCC, 0x4C, 0x0F, 0x26, 0x21, 0x59, 0x9C, 0x3A, 0xF4, 0x06, 0xBC, 0x4C, 0xEA, 0x92, 0x33, 0x1B, 0xC6, 0x85, 0x32, 0x12, 0xB2, 0xB3, 0xB1, 0x52, 0x60, 0xFC, 0x54, 0x71, 0x95, 0xBE, 0xCB, 0x95, 0xB0, 0xA5, 0x47, 0x8E, 0x0F, 0xE5, 0x50, 0xAC, 0xE0, 0xBC, 0x24, 0xE7, 0x2A, 0xC9, 0x83, 0x0F, 0xC7, 0xB4, 0x94, 0xFF, 0x40, 0x9B, 0x49, 0xF9, 0xB3, 0xCC, 0x00, 0x0B, 0x1B, 0x22, 0xE9, 0xFD, 0xDA, 0xBE, 0x17, 0x68, 0xB8, 0xB1, 0x72, 0x53, 0xE1, 0xC1, 0x6D, 0x44, 0x3F, 0x51, 0xC5, 0xE3, 0x6B, 0xA2, 0x1D, 0xC0, 0x99, 0x62, 0xF8, 0x3F, 0xAF, 0xE8, 0x33, 0x9E, 0xD0, 0xAD, 0x32, 0x37, 0x88, 0xDB, 0xFA, 0xCE, 0x7B, 0xBA, 0xD5, 0xE8, 0xEA, 0x20, 0x7D, 0x9C, 0x49, 0x5E, 0x57, 0x9A, 0xD7, 0xA7, 0xCB, 0xD3, 0x29, 0xA2, 0x5E, 0xCD, 0x11, 0xE0, 0x98, 0x21, 0x1D, 0x60, 0xEF, 0xB9, 0x01, 0x37, 0x3B, 0x87, 0xDA, 0xBD, 0x64, 0xA0, 0xAF, 0xE0, 0xDC, 0x2C, 0xA6, 0x15, 0x98, 0xB7, 0xAD, 0x36, 0x70, 0x8B, 0x53, 0x80, 0x0B, 0xE4, 0x57, 0x47, 0x69, 0x82, 0xA3, 0xB9, 0x31, 0x57, 0x14, 0x90, 0x0C, 0x93, 0x3A, 0x34, 0xB2, 0xAD, 0x9C, 0xBF, 0x16, 0x92, 0xBB, 0xDF, 0x3A, 0x6D, 0xC8, 0x72, 0x03, 0x42, 0x22, 0x89, 0xCD, 0xFD, 0xBC, 0x7D, 0xB7, 0x60, 0x93, 0x69, 0xF0, 0xF2, 0x6B, 0xEB, 0x7F, 0x12, 0x8E, 0x64, 0x37, 0x13, 0x5C, 0x53, 0x58, 0x26, 0xFF, 0xCC, 0xFA, 0x65, 0xF4, 0xC9, 0xC2, 0x0D, 0xB3, 0xFC, 0xA3, 0x0B, 0xC5, 0xD3, 0xEA, 0x17, 0xA6, 0x93, 0xE5, 0x13, 0x54, 0x3F, 0x9C, 0xEC, 0x71, 0x51, 0x2B, 0xB8, 0x75, 0x54, 0x9E, 0x3B, 0x5C, 0xB9, 0xF2, 0xF7, 0x7D, 0x2A, 0x80, 0xBF, 0xAC, 0xFC, 0xC4, 0x53, 0x50, 0x8D, 0xDB, 0x91, 0xAE, 0xF1, 0xEA, 0x69, 0xAD, 0x8A, 0x00, 0x43, 0x99, 0xF5, 0xF6, 0x69, 0x4E, 0x6F, 0x8A, 0x96, 0xE7, 0x3D, 0x4B, 0xE5, 0x02, 0x70, 0x61, 0x73, 0x4F, 0x13, 0x2C, 0x9E, 0xD5, 0x27, 0xF3, 0xB3, 0xC3, 0xC5, 0xC8, 0x48, 0x94, 0x1C, 0x79, 0xC7, 0x58, 0xCA, 0x48, 0x5E, 0xAD, 0x8F, 0x99, 0x4F, 0x9C, 0x31, 0x31, 0xA2, 0x7B, 0x1E, 0x1E, 0x93, 0xB6, 0xE0, 0x1C, 0xAA, 0x85, 0x04, 0xA0, 0x48, 0xEB, 0xC3, 0xE2, 0x7C, 0x3C, 0xF1, 0xFF, 0x94, 0xA0, 0x58, 0x60, 0x76, 0x2D, 0x07, 0xE7, 0x90, 0x5E, 0x13, 0x17, 0x53, 0xF5, 0xBA, 0x4D, 0xA6, 0xE7, 0x94, 0xE4, 0x25, 0xEF, 0x41, 0x94, 0xA7, 0x60, 0xBA, 0xBA, 0xA5, 0xBE, 0xED, 0x8D, 0x39, 0x9C, 0xB3, 0x80, 0x1C, 0x87, 0x27, 0xBC, 0x84, 0x7D, 0x2A, 0x77, 0x1E, 0x02, 0x6F, 0xF6, 0x13, 0x25, 0x5D, 0xD1, 0xA1, 0xF8, 0x8A, 0x1A, 0xA2, 0xC4, 0xA4, 0xBA, 0x48, 0xAE, 0x71, 0xEE, 0xC2, 0x2B, 0x38, 0xE6, 0x84, 0x2F, 0xD3, 0x18, 0x41, 0x60, 0x06, 0xE8, 0xBA, 0x1A, 0x96, 0x73, 0xD1, 0x43, 0xEB, 0x80, 0x49, 0x1F, 0x98, 0xD6, 0x34, 0xB4, 0x6C, 0xAB, 0x31, 0x0E, 0xCC, 0x1F, 0x70, 0x22, 0x97, 0xF6, 0xF0, 0xA8, 0x4A, 0x2B, 0xC2, 0xB7, 0x90, 0xAF, 0xEA, 0xAF, 0xE7, 0x3F, 0x06, 0x3B, 0x3A, 0xA4, 0xFF, 0xAE, 0xD3, 0x52, 0x67, 0xFD, 0x2B, 0x52, 0x69, 0x50, 0x3C, 0x88, 0x83, 0xAD, 0x7D, 0x9E, 0x77, 0xD4, 0x67, 0xB3, 0xB3, 0x5B, 0xDC, 0xD5, 0xDD, 0xFC, 0x58, 0x02, 0x41, 0x78, 0x24, 0x6D, 0xF1, 0x24, 0x66, 0x23, 0x8F, 0x28, 0x6D, 0x85, 0xD9, 0x2A, 0x23, 0x55, 0xC6, 0x3A, 0xF9, 0xA4, 0x59, 0x07, 0x7E, 0xAF, 0x28, 0xCD, 0xAD, 0x26, 0xCC, 0x71, 0xC6, 0xFF, 0x60, 0x7B, 0x50, 0xBC, 0xAB, 0x69, 0x3E, 0x09, 0x1F, 0x25, 0x09, 0x39, 0xC5, 0x23, 0x5C, 0x61, 0x6B, 0x84, 0x01, 0x2C, 0x12, 0xFA, 0xAB, 0xE4, 0x0A, 0x66, 0x16, 0x84, 0x24, 0x01, 0x99, 0xB2, 0xDD, 0x9C, 0x86, 0x17, 0x9A, 0xBF, 0x8D, 0x3B, 0x96, 0xDE, 0xD1, 0x67, 0x50, 0x24, 0x6A, 0x8F, 0x03, 0x30, 0x5E, 0xE0, 0x67, 0xAD, 0xF2, 0x2C, 0x39, 0xEC, 0xB1, 0xFA, 0xF8, 0x57, 0x8D, 0xED, 0x3A, 0x25, 0xE5, 0x44, 0x85, 0xA1, 0x0B, 0xC9, 0x8A, 0x82, 0x4D, 0xBD, 0xFC, 0x2F, 0x6B, 0x14, 0x5F, 0x42, 0x16, 0xA2, 0x9D, 0xB5, 0xFA, 0x7A, 0x9C, 0x2B, 0x6D, 0x51, 0xCB, 0x37, 0x59, 0xC3, 0xC5, 0x89, 0x46, 0xDD, 0x2E, 0x64, 0x8A, 0x1F, 0x36, 0xD2, 0x0C, 0x09, 0xBC, 0x58, 0xBA, 0x91, 0xE2, 0x57, 0x03, 0x63, 0x98, 0xB7, 0xD5, 0xDA, 0x10, 0x6E, 0x5C, 0x6B, 0xDE, 0x1F, 0xF1, 0x98, 0xB9, 0x5D, 0x12, 0xDE, 0xFD, 0xC5, 0x4A, 0x5B, 0x3D, 0xD5, 0x5A, 0xFF, 0x42, 0x00, 0xAA, 0x27, 0xED, 0x5B, 0xCB, 0xD7, 0xFD, 0x6D, 0x6A, 0xD9, 0x1E, 0x15, 0x96, 0x53, 0x35, 0x2E, 0xDE, 0xE8, 0xF9, 0x60, 0xE4, 0xEB, 0x6F, 0x09, 0x42, 0xAF, 0x52, 0x51, 0xEF, 0x39, 0xC1, 0xAB, 0xBD, 0xC4, 0x2D, 0x8B, 0xE0, 0xB8, 0x80, 0x06, 0x7A, 0x79, 0xCE, 0xB1, 0x69, 0x90, 0x1E, 0xA8, 0x14, 0x71, 0xC4, 0xDC, 0x78, 0x23, 0x32, 0xBA, 0xC6, 0x26, 0x40, 0xA2, 0x80, 0xDD, 0x9B, 0x32, 0x3C, 0xC5, 0xC3, 0x93, 0xB2, 0xB3, 0x7F, 0xE8, 0x21, 0xBA, 0x45, 0xD5, 0xC0, 0x5B, 0xCF, 0xEB, 0x11, 0x75, 0xF7, 0xE5, 0xAE, 0x12, 0xE7, 0x7D, 0xCF, 0x92, 0xB5, 0xDC, 0xB7, 0xF4, 0x87, 0x52, 0xA7, 0x2E, 0x6F, 0x6E, 0x25, 0x0A, 0x65, 0x27, 0xF5, 0xA6, 0xF3, 0x59, 0xEB, 0x4D, 0x1C, 0x69, 0xDD, 0x65, 0x1D, 0x89, 0xF3, 0xF2, 0x22, 0x9C, 0xEF, 0x12, 0xF5, 0x01, 0x2A, 0x96, 0x68, 0xD2, 0x60, 0xF7, 0x79, 0x3C, 0x91, 0xA7, 0x62, 0x2E, 0x5E, 0xCC, 0x3B, 0x58, 0x21, 0xBA, 0x43, 0x9E, 0xCC, 0x75, 0x33, 0xDF, 0xB5, 0x32, 0xA2, 0xB6, 0x4A, 0x96, 0x0C, 0x4C, 0xA0, 0x43, 0x1B, 0x3D, 0x09, 0x57, 0x3B, 0x0B, 0x63, 0x75, 0x74, 0x8A, 0x47, 0x5D, 0xD0, 0xDC, 0x92, 0x90, 0xCE, 0xCA, 0xFD, 0x05, 0x9D, 0xC0, 0x03, 0x8C, 0xD1, 0x29, 0x54, 0x68, 0xA4, 0xCE, 0x11, 0x8E, 0x8B, 0x5B, 0x03, 0x70, 0x7C, 0x56, 0xB1, 0x4E, 0xDF, 0x9A, 0xF6, 0x21, 0x9E, 0xF7, 0x68, 0xDF, 0xCF, 0x3D, 0x45, 0x52, 0x84, 0x4C, 0x58, 0x54, 0x1C, 0xFA, 0x0D, 0x17, 0x5C, 0xF7, 0xEF, 0xBB, 0x5F, 0xA2, 0x81, 0x30, 0xCB, 0x78, 0xD8, 0x21, 0x20, 0xAC, 0xB7, 0xB4, 0x03, 0xCC, 0x75, 0xB8, 0x1C, 0x3F, 0xF1, 0x24, 0x0D, 0xBE, 0xF6, 0xE7, 0xF1, 0xCB, 0xA8, 0x80, 0x7A, 0x5A, 0x21, 0x31, 0x0C, 0x29, 0x79, 0x5B, 0x4E, 0x32, 0xCC, 0x4A, 0x49, 0xC4, 0x7F, 0xB5, 0x1B, 0xAC, 0xDD, 0x14, 0x3C, 0xD4, 0x95, 0xC0, 0xF5, 0xC1, 0x0D, 0xF9, 0xFE, 0x06, 0xBF, 0x22, 0x41, 0xBC, 0xEC, 0xEA, 0x21, 0x29, 0xD3, 0xDB, 0xC5, 0x7B, 0xA1, 0x06, 0x8F, 0x43, 0x2D, 0xDF, 0x57, 0x24, 0x14, 0xAD, 0x6F, 0x12, 0xD6, 0x37, 0x10, 0x64, 0xFD, 0xEE, 0x0D, 0x5C, 0xCF, 0x97, 0x30, 0xBA, 0xD1, 0xBB, 0xB4, 0x74, 0x9C, 0x87, 0x00, 0x7E, 0xB0, 0xBD, 0x66, 0x60, 0xC9, 0x94, 0xFF, 0xCC, 0x7F, 0xC7, 0xD7, 0x69, 0xAB, 0xF0, 0x16, 0x0B, 0xA6, 0xDF, 0x93, 0xB7, 0x19, 0xC7, 0x3B, 0x6D, 0xA6, 0xB5, 0xB1, 0x51, 0xDC, 0x44, 0xA3, 0x9D, 0x54, 0x3A, 0xF0, 0x73, 0xD3, 0x74, 0xE0, 0x4B, 0x03, 0x3D, 0x1A, 0xFA, 0xB9, 0x59, 0x08, 0x2E, 0x5E, 0x02, 0xB2, 0x07, 0xA2, 0x55, 0x10, 0x5B, 0xB4, 0xD4, 0xC7, 0xE6, 0xB2, 0x5A, 0x62, 0x65, 0x8C, 0x13, 0xCF, 0x91, 0x35, 0x1F, 0x50, 0xCC, 0x23, 0x74, 0x16, 0x41, 0x06, 0x67, 0xFA, 0xA8, 0x9D, 0xEC, 0x53, 0x8E, 0xB1, 0xAE, 0x2C, 0xBE, 0x55, 0x8D, 0xCC, 0xEE, 0xB5, 0xAA, 0xE9, 0x08, 0xBD, 0x1E, 0xE7, 0x90, 0xA8, 0x43, 0xDB, 0x06, 0x73, 0x29, 0xC7, 0x05, 0x04, 0x5B, 0xBC, 0x0A, 0x7A, 0xCB, 0xA0, 0xA5, 0x1D, 0xB8, 0x39, 0xAA, 0xAF, 0xB6, 0xA3, 0x6F, 0x4E, 0xC1, 0xC2, 0xD4, 0x3F, 0x5B, 0xF1, 0xAC, 0x55, 0xAA, 0x6E, 0x82, 0x0B, 0x26, 0xC4, 0x7C, 0x38, 0x06, 0x0C, 0x61, 0xB1, 0xE3, 0xA7, 0xB2, 0xCC, 0x26, 0x1D, 0x54, 0xC0, 0xB3, 0x4F, 0x5A, 0x25, 0x74, 0xF5, 0x24, 0x3B, 0x2A, 0x08, 0x29, 0xBE, 0xBB, 0xA9, 0x93, 0x30, 0x11, 0x89, 0x7E, 0x98, 0x08, 0x69, 0xD6, 0xDD, 0x5A, 0xC7, 0xB3, 0x1A, 0x9B, 0xA9, 0xAA, 0x98, 0xA3, 0xEC, 0x20, 0x14, 0x5A, 0x81, 0xB2, 0x7B, 0x33, 0xAB, 0x66, 0x62, 0xDB, 0x34, 0x87, 0xFC, 0xAA, 0x32, 0xBA, 0xFA, 0x6E, 0x1B, 0x28, 0x55, 0x02, 0x5D, 0x5F, 0xB5, 0xC8, 0x69, 0x67, 0x75, 0x20, 0x03, 0xBE, 0x2F, 0xD8, 0xE2, 0x98, 0xB3, 0x73, 0xD1, 0x01, 0x7E, 0xD7, 0xD1, 0xAC, 0xCB, 0x6D, 0x31, 0x6F, 0x19, 0x40, 0x19, 0x76, 0xF2, 0x13, 0x38, 0x62, 0xAA, 0x3C, 0xC4, 0x82, 0x39, 0x0C, 0xE5, 0x5D, 0x1E, 0x63, 0xEC, 0x4A, 0x40, 0xFE, 0x82, 0x6E, 0x62, 0x8D, 0x3E, 0x81, 0x1C, 0xDF, 0x57, 0x27, 0x70, 0x48, 0x0F, 0x20, 0x3A, 0x36, 0xA6, 0xFD, 0xAB, 0xD1, 0xD2, 0xCB, 0x6D, 0xE5, 0xD7, 0xC2, 0xA3, 0x2A, 0xD4, 0x5B, 0xF3, 0x72, 0x5F, 0x59, 0x9D, 0x29, 0xD0, 0xF1, 0x34, 0x2E, 0x3B, 0x57, 0x98, 0x63, 0x3B, 0x6E, 0x72, 0xA4, 0x3F, 0x48, 0x33, 0xF2, 0x21, 0xEA, 0x9D, 0x90, 0x4B, 0x00, 0x2D, 0x8D, 0x13, 0xF6, 0xE7, 0x44, 0x10, 0x05, 0xBD, 0x3D, 0xA8, 0x8B, 0x64, 0x9B, 0xEE, 0x65, 0xAC, 0x9F, 0xF6, 0xDB, 0x40, 0x7E, 0xED, 0x65, 0x3E, 0x18, 0x87, 0x35, 0xF5, 0xFF, 0xDB, 0xBC, 0x4A, 0x1E, 0x2E, 0x08, 0x9C, 0x7B, 0xC4, 0x60, 0x6B, 0xCA, 0x32, 0x34, 0xF2, 0xD8, 0x9D, 0x40, 0x39, 0x55, 0xF4, 0x4A, 0x44, 0x4A, 0x42, 0xA2, 0x0D, 0xFE, 0xE5, 0xC4, 0x9C, 0x84, 0x42, 0x5E, 0x1A, 0x17, 0x2C, 0xA4, 0x44, 0x82, 0xFE, 0xBB, 0x45, 0x16, 0xDD, 0x4B, 0x64, 0x9C, 0x6F, 0x31, 0x5A, 0x7E, 0x2D, 0xDB, 0xE1, 0x94, 0xFE, 0xA2, 0xA9, 0x17, 0x28, 0xE1, 0xDF, 0x45, 0x11, 0x08, 0xE2, 0x10, 0x56, 0xA7, 0xBD, 0x3D, 0x45, 0x5B, 0x8A, 0xA8, 0xB7, 0x11, 0x1C, 0x26, 0x79, 0x7C, 0xB7, 0xBA, 0x0C, 0x24, 0x60, 0x8E, 0x93, 0xDC, 0xFC, 0x31, 0x41, 0x5D, 0x98, 0xCB, 0xD1, 0xFE, 0x1A, 0x20, 0x7C, 0x81, 0xCD, 0xEB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x09, 0x10, 0x17, 0x1E, 0x24, }, }, { .name = "Dilithium Round 3, Level 5 (8-7) KAT 0 (PKCS#8/SPKI)", .version = 0, .keyform = 0, .rho_len = 0, .seed_len = 0, .tr_len = 0, .s1_len = 0, .s2_len = 0, .t0_len = 0, .t1_len = 0, .pkcs8_len = 7492, .pkcs8 = { 0x30, 0x82, 0x1D, 0x40, 0x02, 0x01, 0x00, 0x30, 0x0F, 0x06, 0x0B, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x02, 0x82, 0x0B, 0x07, 0x08, 0x07, 0x05, 0x00, 0x04, 0x82, 0x1D, 0x28, 0x30, 0x82, 0x1D, 0x24, 0x02, 0x01, 0x00, 0x03, 0x21, 0x00, 0x1C, 0x0E, 0xE1, 0x11, 0x1B, 0x08, 0x00, 0x3F, 0x28, 0xE6, 0x5E, 0x8B, 0x3B, 0xDE, 0xB0, 0x37, 0xCF, 0x8F, 0x22, 0x1D, 0xFC, 0xDA, 0xF5, 0x95, 0x0E, 0xDB, 0x38, 0xD5, 0x06, 0xD8, 0x5B, 0xEF, 0x03, 0x21, 0x00, 0x39, 0x4D, 0x16, 0x95, 0x05, 0x9D, 0xFF, 0x40, 0xAE, 0x25, 0x6C, 0x5D, 0x5E, 0xDA, 0xBF, 0xB6, 0x9F, 0x5F, 0x40, 0xF3, 0x7A, 0x58, 0x8F, 0x50, 0x53, 0x2C, 0xA4, 0x08, 0xA8, 0x16, 0x8A, 0xB1, 0x03, 0x21, 0x00, 0x85, 0xF6, 0x84, 0xAE, 0xB4, 0x01, 0xB9, 0xAA, 0xAF, 0x81, 0x2A, 0x00, 0xE1, 0x24, 0xFF, 0x56, 0xFE, 0xE5, 0x1B, 0xA7, 0xC1, 0x12, 0x82, 0x61, 0x7F, 0x05, 0x72, 0xCC, 0x79, 0x1D, 0xC8, 0x1C, 0x03, 0x82, 0x02, 0xA1, 0x00, 0xC0, 0xA6, 0x71, 0x1A, 0x96, 0x6C, 0x11, 0x31, 0x2A, 0xD9, 0xA8, 0x21, 0xD8, 0x08, 0x65, 0x42, 0xA6, 0x00, 0xA4, 0xB4, 0x2C, 0x19, 0x40, 0x72, 0x02, 0x42, 0x62, 0x81, 0x06, 0x21, 0x0A, 0x43, 0x85, 0x23, 0x31, 0x70, 0x93, 0x08, 0x10, 0x8B, 0x18, 0x8C, 0x02, 0x24, 0x92, 0xC1, 0xB2, 0x84, 0x12, 0xC4, 0x21, 0x8B, 0x04, 0x21, 0x81, 0xC8, 0x61, 0x02, 0x48, 0x05, 0x9C, 0x92, 0x01, 0xC0, 0x34, 0x88, 0x19, 0x32, 0x6C, 0x58, 0x20, 0x46, 0x89, 0x18, 0x68, 0xA2, 0xC2, 0x8D, 0x82, 0x34, 0x6A, 0x1C, 0x09, 0x42, 0x00, 0xA2, 0x8C, 0xE3, 0xA6, 0x49, 0x1C, 0x11, 0x2C, 0xC2, 0x48, 0x12, 0xE0, 0x90, 0x21, 0x91, 0x98, 0x50, 0x62, 0xC0, 0x84, 0x62, 0x24, 0x51, 0xCA, 0x06, 0x2C, 0x64, 0x24, 0x0E, 0x1B, 0xB3, 0x31, 0x24, 0x96, 0x85, 0x4B, 0x46, 0x06, 0xDB, 0x26, 0x68, 0xC3, 0x82, 0x68, 0x44, 0x10, 0x46, 0xC9, 0xB6, 0x21, 0x14, 0x04, 0x81, 0x14, 0x45, 0x50, 0x24, 0x42, 0x08, 0x44, 0x22, 0x71, 0x0B, 0x92, 0x45, 0x9A, 0xA0, 0x81, 0x1A, 0x91, 0x70, 0x9C, 0x24, 0x10, 0x03, 0x95, 0x70, 0x04, 0xC5, 0x04, 0xC8, 0x26, 0x92, 0xD2, 0x92, 0x00, 0xC0, 0xB2, 0x60, 0xC0, 0xA2, 0x68, 0x09, 0x19, 0x0A, 0xA2, 0x30, 0x0E, 0x18, 0x89, 0x69, 0xE0, 0x00, 0x8D, 0xD8, 0x48, 0x62, 0xDA, 0x14, 0x71, 0x20, 0x18, 0x05, 0x19, 0x07, 0x44, 0x04, 0x12, 0x40, 0x9B, 0x12, 0x40, 0x11, 0x80, 0x10, 0xD1, 0x42, 0x81, 0x99, 0x28, 0x50, 0x8B, 0x10, 0x91, 0x02, 0x24, 0x64, 0xA0, 0x20, 0x6D, 0x12, 0x46, 0x21, 0x1C, 0x83, 0x8C, 0x1B, 0x47, 0x69, 0x01, 0x06, 0x90, 0xCC, 0x06, 0x24, 0x81, 0x84, 0x69, 0x20, 0x98, 0x2C, 0x24, 0x12, 0x05, 0x21, 0xB1, 0x50, 0x41, 0x36, 0x02, 0x98, 0x44, 0x6E, 0xD1, 0xA6, 0x31, 0x11, 0x05, 0x6A, 0xD3, 0xA8, 0x40, 0xCA, 0xA8, 0x4C, 0x62, 0xB0, 0x00, 0x03, 0x13, 0x4A, 0x53, 0x34, 0x46, 0x14, 0x19, 0x40, 0x04, 0xC5, 0x4C, 0xE3, 0x06, 0x69, 0x5A, 0xB0, 0x89, 0x61, 0x16, 0x8E, 0xCB, 0x10, 0x80, 0x8B, 0x16, 0x8E, 0xD9, 0x90, 0x64, 0x0B, 0x94, 0x60, 0x24, 0x83, 0x85, 0x1A, 0xB3, 0x04, 0x54, 0x26, 0x22, 0x51, 0xB8, 0x25, 0x1C, 0x42, 0x4A, 0x0B, 0x81, 0x48, 0x42, 0xC4, 0x44, 0x5A, 0x10, 0x20, 0x23, 0x80, 0x84, 0x09, 0xB7, 0x25, 0x4C, 0xC6, 0x48, 0x14, 0x85, 0x4D, 0x19, 0x38, 0x0E, 0x60, 0x16, 0x51, 0xD8, 0x32, 0x6A, 0x0A, 0x91, 0x89, 0x08, 0xC1, 0x70, 0xE0, 0x96, 0x4D, 0x18, 0x46, 0x8C, 0x01, 0x32, 0x8D, 0x91, 0xC4, 0x05, 0x4A, 0x00, 0x61, 0x23, 0x08, 0x68, 0xA2, 0x10, 0x42, 0x10, 0xA8, 0x61, 0x13, 0x06, 0x21, 0x8A, 0x24, 0x8E, 0x62, 0x06, 0x89, 0xC9, 0xB2, 0x45, 0x08, 0x27, 0x84, 0x51, 0x20, 0x0D, 0x98, 0x04, 0x66, 0xDC, 0x42, 0x05, 0x44, 0x24, 0x85, 0x24, 0x26, 0x28, 0x22, 0x21, 0x61, 0x20, 0x16, 0x09, 0x0B, 0xA6, 0x2C, 0x0A, 0x11, 0x44, 0xE0, 0x92, 0x81, 0x58, 0x48, 0x0D, 0x42, 0x22, 0x10, 0xA0, 0x06, 0x09, 0x8B, 0x24, 0x6E, 0x81, 0x28, 0x8C, 0xC0, 0x24, 0x80, 0x90, 0x30, 0x8D, 0x84, 0x36, 0x40, 0x4C, 0xA6, 0x84, 0x50, 0x04, 0x24, 0x94, 0xB6, 0x8D, 0xA2, 0x92, 0x6D, 0x18, 0xB3, 0x44, 0xA0, 0x00, 0x85, 0xE3, 0xB8, 0x05, 0x14, 0x05, 0x04, 0xA4, 0xC2, 0x90, 0x84, 0x22, 0x81, 0xC3, 0x26, 0x2D, 0x0B, 0x20, 0x66, 0xCC, 0x90, 0x31, 0x98, 0x38, 0x28, 0x10, 0x16, 0x6C, 0xC1, 0x34, 0x45, 0xC0, 0x10, 0x22, 0x24, 0xC6, 0x88, 0x03, 0x46, 0x32, 0xD8, 0x40, 0x90, 0x1C, 0x20, 0x68, 0x04, 0x15, 0x28, 0x9A, 0x18, 0x81, 0x44, 0x98, 0x8D, 0x9C, 0x20, 0x6E, 0x9C, 0x30, 0x2C, 0xC1, 0xB8, 0x20, 0x61, 0x42, 0x21, 0x08, 0x03, 0x10, 0xA0, 0xC2, 0x8C, 0x58, 0x12, 0x85, 0x53, 0x20, 0x4C, 0x03, 0x30, 0x81, 0x4C, 0xA4, 0x8D, 0x44, 0xC0, 0x8D, 0x51, 0x40, 0x4C, 0x1C, 0xA7, 0x2C, 0x44, 0x08, 0x65, 0xA0, 0x38, 0x40, 0xDA, 0x20, 0x80, 0x81, 0x06, 0x85, 0x8C, 0x26, 0x0D, 0xE2, 0xA8, 0x8C, 0x9C, 0x44, 0x11, 0x59, 0x42, 0x28, 0xC4, 0x26, 0x04, 0x44, 0x14, 0x26, 0xA1, 0x42, 0x64, 0x08, 0xC0, 0x85, 0x11, 0x01, 0x86, 0x9B, 0x48, 0x31, 0x99, 0xB2, 0x0C, 0x80, 0x46, 0x44, 0x59, 0xA8, 0x8C, 0x00, 0x42, 0x08, 0x98, 0x82, 0x90, 0x0A, 0xB5, 0x45, 0x62, 0x24, 0x48, 0x12, 0x96, 0x05, 0x44, 0x12, 0x46, 0x00, 0xC8, 0x88, 0x13, 0xA0, 0x61, 0xE1, 0x28, 0x4D, 0x0A, 0xB9, 0x91, 0x4B, 0x96, 0x20, 0x99, 0xB8, 0x44, 0x00, 0x31, 0x4E, 0x98, 0x12, 0x85, 0x00, 0xB6, 0x01, 0x83, 0xA0, 0x0D, 0x14, 0x15, 0x0E, 0x18, 0x81, 0x10, 0x19, 0x01, 0x22, 0x4A, 0x06, 0x68, 0x03, 0x82, 0x03, 0x01, 0x00, 0x1A, 0x49, 0x8D, 0xE1, 0xA2, 0x84, 0x11, 0xC6, 0x31, 0x21, 0x26, 0x25, 0x91, 0xA0, 0x6D, 0x03, 0x05, 0x24, 0xA1, 0xB6, 0x08, 0x94, 0x44, 0x72, 0x43, 0x34, 0x12, 0x5B, 0xB4, 0x20, 0x41, 0xB6, 0x50, 0xD0, 0x88, 0x8D, 0x0B, 0x07, 0x4D, 0x1C, 0x94, 0x64, 0x4C, 0x20, 0x8E, 0x8B, 0x88, 0x08, 0xE0, 0x30, 0x09, 0x44, 0x20, 0x05, 0x49, 0x86, 0x4D, 0x03, 0x13, 0x4E, 0x19, 0xC9, 0x84, 0x09, 0x37, 0x61, 0x1A, 0x43, 0x68, 0x4A, 0x80, 0x90, 0x02, 0x04, 0x31, 0x1C, 0x17, 0x42, 0x18, 0x40, 0x80, 0xC8, 0x30, 0x8E, 0xE1, 0xA2, 0x41, 0xC3, 0x34, 0x04, 0xA3, 0x28, 0x22, 0x51, 0x24, 0x71, 0x82, 0x84, 0x01, 0x1B, 0xC0, 0x64, 0x23, 0x47, 0x72, 0x82, 0x14, 0x66, 0x5B, 0x38, 0x68, 0xE1, 0xC6, 0x29, 0x9B, 0x90, 0x40, 0x60, 0x38, 0x86, 0x83, 0xA0, 0x40, 0x84, 0x20, 0x04, 0x4C, 0x94, 0x01, 0x10, 0x25, 0x8D, 0x82, 0x02, 0x4D, 0x9A, 0xB2, 0x69, 0x20, 0x15, 0x10, 0x60, 0x46, 0x2D, 0xC2, 0x14, 0x2E, 0x0C, 0xA8, 0x2C, 0x54, 0x16, 0x22, 0x03, 0x46, 0x89, 0x92, 0x06, 0x60, 0x08, 0x07, 0x82, 0x0B, 0x47, 0x44, 0x48, 0x98, 0x09, 0x09, 0x43, 0x0E, 0xE4, 0x32, 0x0A, 0x1A, 0xC0, 0x65, 0xC0, 0xA4, 0x21, 0x44, 0xB2, 0x91, 0x58, 0xC6, 0x04, 0x11, 0x45, 0x20, 0xC4, 0xA4, 0x21, 0x02, 0xA0, 0x70, 0x21, 0x22, 0x26, 0x23, 0xB2, 0x68, 0x4B, 0x08, 0x40, 0x01, 0x03, 0x91, 0x8B, 0x34, 0x81, 0x1A, 0x04, 0x04, 0x0C, 0xB0, 0x05, 0xC2, 0x92, 0x69, 0x90, 0x14, 0x68, 0x04, 0x46, 0x49, 0x14, 0x83, 0x49, 0xA2, 0x34, 0x89, 0x19, 0xC7, 0x28, 0x94, 0x44, 0x71, 0x00, 0xC9, 0x49, 0x58, 0x38, 0x72, 0x02, 0x02, 0x90, 0x42, 0xC6, 0x4C, 0x0C, 0x17, 0x32, 0x48, 0xC6, 0x8C, 0x59, 0x28, 0x31, 0x09, 0xB7, 0x28, 0xCB, 0x48, 0x0E, 0x9A, 0x22, 0x85, 0x1C, 0xB9, 0x11, 0xE3, 0xC6, 0x30, 0xC3, 0x48, 0x28, 0xCC, 0xB8, 0x28, 0x03, 0xC8, 0x08, 0xA4, 0xB6, 0x04, 0xD0, 0x18, 0x8C, 0x60, 0x18, 0x72, 0xD0, 0x20, 0x92, 0x82, 0x02, 0x2E, 0x59, 0x18, 0x89, 0x08, 0x19, 0x32, 0xC9, 0x06, 0x52, 0x60, 0x90, 0x8C, 0x09, 0x80, 0x29, 0xA4, 0xB4, 0x8C, 0x8C, 0x34, 0x82, 0x08, 0x42, 0x10, 0x02, 0x00, 0x08, 0x13, 0x01, 0x50, 0x83, 0xB6, 0x08, 0x41, 0x94, 0x4D, 0x1B, 0x49, 0x6C, 0x19, 0x39, 0x11, 0xCB, 0x32, 0x41, 0x02, 0xC0, 0x65, 0x48, 0x88, 0x91, 0x9B, 0x98, 0x61, 0x08, 0xB5, 0x04, 0x49, 0xB4, 0x45, 0xD3, 0x30, 0x01, 0x98, 0x04, 0x6D, 0x53, 0x00, 0x89, 0x42, 0x32, 0x60, 0x8C, 0xB0, 0x90, 0x64, 0x88, 0x68, 0xD4, 0x32, 0x45, 0x48, 0x14, 0x71, 0x14, 0x98, 0x05, 0x81, 0x00, 0x22, 0xDB, 0x44, 0x69, 0xD9, 0x24, 0x89, 0x11, 0x41, 0x12, 0x09, 0x19, 0x50, 0x92, 0xA0, 0x84, 0xC0, 0x34, 0x22, 0x4A, 0x24, 0x10, 0xDA, 0xC8, 0x09, 0xD2, 0xA8, 0x0D, 0x22, 0x85, 0x21, 0x8B, 0xC8, 0x90, 0xC1, 0x00, 0x66, 0x5C, 0xC0, 0x25, 0x99, 0xA4, 0x61, 0x1A, 0xA4, 0x11, 0x0A, 0x24, 0x28, 0x5B, 0xC4, 0x48, 0x13, 0x14, 0x89, 0x63, 0x92, 0x61, 0x20, 0x30, 0x0C, 0x40, 0x02, 0x25, 0x21, 0x88, 0x28, 0x24, 0x01, 0x8C, 0x10, 0x81, 0x6D, 0x4C, 0x42, 0x49, 0x01, 0x22, 0x2D, 0xC1, 0x96, 0x0C, 0x08, 0x48, 0x90, 0x01, 0xC1, 0x30, 0x23, 0xC1, 0x89, 0xA1, 0xC4, 0x64, 0x12, 0x97, 0x09, 0xCC, 0x90, 0x91, 0x60, 0x20, 0x66, 0x1B, 0x96, 0x48, 0x82, 0xA8, 0x71, 0x91, 0xC0, 0x65, 0xDB, 0xC2, 0x01, 0x84, 0x36, 0x0A, 0x09, 0x24, 0x29, 0x52, 0x10, 0x4E, 0xDB, 0x24, 0x0A, 0x61, 0x02, 0x10, 0x20, 0x38, 0x25, 0x98, 0x34, 0x60, 0x82, 0x24, 0x30, 0xC4, 0x12, 0x49, 0xC0, 0xA2, 0x05, 0x0C, 0x08, 0x85, 0x93, 0x28, 0x09, 0x63, 0xB2, 0x05, 0x23, 0x96, 0x20, 0x42, 0x12, 0x0D, 0xD1, 0xC0, 0x10, 0x08, 0xC5, 0x40, 0xC1, 0x82, 0x65, 0x1B, 0x15, 0x92, 0xA4, 0x14, 0x51, 0x84, 0x04, 0x26, 0x53, 0x42, 0x52, 0x24, 0x23, 0x6D, 0x9C, 0x28, 0x4E, 0x50, 0x14, 0x05, 0x8C, 0x20, 0x80, 0x24, 0x26, 0x65, 0x61, 0x44, 0x4C, 0x02, 0x11, 0x20, 0xC8, 0xC0, 0x4C, 0x18, 0xA0, 0x0D, 0x00, 0x38, 0x70, 0x99, 0x16, 0x12, 0xA1, 0x16, 0x40, 0xC4, 0x18, 0x45, 0x09, 0x93, 0x88, 0x4C, 0x82, 0x21, 0xCB, 0xB2, 0x81, 0x21, 0x26, 0x61, 0xD1, 0xA8, 0x24, 0x41, 0x30, 0x84, 0x08, 0x80, 0x71, 0x00, 0xC6, 0x20, 0x52, 0x42, 0x92, 0x89, 0x24, 0x12, 0xA4, 0x26, 0x89, 0xE3, 0xB0, 0x88, 0x21, 0x98, 0x8C, 0x11, 0x96, 0x2C, 0xE1, 0x96, 0x20, 0x51, 0xC2, 0x81, 0x20, 0x91, 0x80, 0x94, 0x16, 0x6E, 0x14, 0x94, 0x60, 0x20, 0xC9, 0x45, 0x9B, 0x22, 0x45, 0xA2, 0x38, 0x20, 0xC0, 0x36, 0x08, 0x60, 0x90, 0x8D, 0x41, 0x06, 0x02, 0x5B, 0x06, 0x6E, 0xE1, 0x40, 0x0A, 0x89, 0x34, 0x6C, 0x1A, 0xB2, 0x69, 0xA4, 0x16, 0x10, 0x03, 0x33, 0x0E, 0x1A, 0x42, 0x28, 0x03, 0x19, 0x6E, 0x11, 0x44, 0x84, 0x0B, 0x24, 0x4A, 0x1C, 0x16, 0x6A, 0x19, 0x98, 0x40, 0x03, 0xA2, 0x85, 0x41, 0xC0, 0x8C, 0xD2, 0x22, 0x61, 0x0C, 0x82, 0x10, 0x5A, 0xB0, 0x0D, 0x21, 0x14, 0x72, 0x5A, 0x82, 0x80, 0x02, 0x86, 0x10, 0x0C, 0x27, 0x26, 0x5C, 0x48, 0x6E, 0xC9, 0x40, 0x6C, 0x1B, 0x49, 0x04, 0xE4, 0xB8, 0x49, 0xDB, 0x32, 0x8A, 0x9C, 0x24, 0x2C, 0x40, 0x38, 0x80, 0x22, 0xA9, 0x45, 0x03, 0x82, 0x0D, 0x01, 0x00, 0x12, 0x29, 0xA4, 0xE6, 0x5E, 0xD3, 0x1C, 0x79, 0x3E, 0xCB, 0x5B, 0x89, 0xC5, 0x5D, 0xC3, 0x33, 0xA2, 0x77, 0xBF, 0x5C, 0x41, 0x28, 0xA2, 0x14, 0x01, 0xAF, 0xA8, 0xD4, 0x28, 0xC8, 0x21, 0xE9, 0x7A, 0xEA, 0x05, 0xB3, 0xAD, 0x29, 0x23, 0xBD, 0x97, 0x10, 0x87, 0x1C, 0xE8, 0xB3, 0xB1, 0x1A, 0x71, 0x1C, 0x9A, 0xAC, 0xBA, 0x10, 0x8C, 0xAF, 0x43, 0xA1, 0x72, 0xD6, 0x59, 0x94, 0x01, 0xDB, 0x89, 0x68, 0x1D, 0x0B, 0x87, 0x4E, 0xC3, 0x57, 0xA5, 0x29, 0x5C, 0x0A, 0x08, 0xD5, 0x89, 0xC4, 0x53, 0x9F, 0x9C, 0x59, 0xF3, 0x3F, 0x06, 0x44, 0x64, 0x41, 0x20, 0x49, 0x84, 0xE1, 0xF9, 0x87, 0x3C, 0x1F, 0x97, 0x75, 0xB9, 0x7E, 0xD4, 0x00, 0xC9, 0x98, 0xB0, 0x51, 0x62, 0xB6, 0x18, 0x98, 0x61, 0xF2, 0x8D, 0xAE, 0x36, 0xC2, 0x13, 0x37, 0x65, 0x71, 0x11, 0x76, 0xCA, 0xAF, 0x5A, 0x1D, 0xCB, 0x2A, 0x0E, 0x22, 0x3A, 0x5F, 0x07, 0x9B, 0x07, 0x41, 0xA5, 0xE6, 0xD5, 0x10, 0xE5, 0x87, 0x32, 0xDC, 0x03, 0x59, 0xD7, 0x9A, 0x77, 0x41, 0xA3, 0x79, 0x1C, 0xA6, 0x50, 0x4F, 0x07, 0xCA, 0x8A, 0x2C, 0x03, 0x12, 0x71, 0x18, 0x45, 0x20, 0xEB, 0x76, 0xA0, 0x0B, 0x9B, 0x46, 0x26, 0xDB, 0x37, 0x34, 0x1C, 0x71, 0x80, 0x65, 0xED, 0x95, 0xFE, 0x4C, 0xB0, 0x54, 0xBF, 0xE7, 0x1E, 0x80, 0x26, 0x0D, 0x21, 0x90, 0x7B, 0x9B, 0xFA, 0xEC, 0x86, 0xAC, 0x83, 0xA4, 0x85, 0x63, 0xC0, 0xB9, 0xB2, 0xEF, 0x4B, 0x9B, 0x4E, 0xCB, 0xCB, 0x2F, 0x12, 0x91, 0x98, 0x4E, 0x89, 0xE8, 0x4C, 0x55, 0x69, 0x06, 0x47, 0xE2, 0x65, 0x47, 0xD7, 0x3E, 0x4C, 0xB7, 0xF0, 0xE0, 0x6E, 0xFF, 0xC3, 0xC4, 0x79, 0xE2, 0x56, 0x8E, 0x74, 0x64, 0xEA, 0xBF, 0x1D, 0x1C, 0x4E, 0xFE, 0x21, 0x11, 0x12, 0xE6, 0x2B, 0xEA, 0x8B, 0x85, 0x5F, 0x50, 0xD7, 0x16, 0x51, 0x32, 0x9C, 0x00, 0xEF, 0x61, 0x9F, 0x53, 0x7E, 0x45, 0x4B, 0x09, 0x5A, 0x9D, 0xF6, 0xA8, 0x59, 0x0E, 0x5B, 0xBA, 0xA1, 0x5C, 0x9E, 0x64, 0xE7, 0x01, 0xE3, 0x74, 0x69, 0x74, 0x94, 0x62, 0xA2, 0x11, 0x95, 0x41, 0xE7, 0x55, 0x49, 0xD0, 0x56, 0xA2, 0x5B, 0xBC, 0xEE, 0x11, 0xCD, 0x9F, 0xC6, 0x72, 0x42, 0x2A, 0xD2, 0xAE, 0x97, 0x91, 0x3D, 0x30, 0xBE, 0x3C, 0xD8, 0x5F, 0x58, 0xCF, 0xA9, 0x04, 0xF4, 0x43, 0xAC, 0x3A, 0x8D, 0xFD, 0xBC, 0x2C, 0xC9, 0xC8, 0xC3, 0x9B, 0x24, 0x4E, 0xE7, 0xE0, 0xD9, 0x5B, 0xEC, 0x69, 0x27, 0xA2, 0xB0, 0xB9, 0x4E, 0x97, 0x3F, 0x98, 0x12, 0x24, 0x46, 0x43, 0x14, 0x6E, 0x19, 0x01, 0x3B, 0x7F, 0xE1, 0x71, 0x14, 0xA0, 0xF3, 0x9F, 0x92, 0x28, 0x6B, 0xE0, 0xF0, 0xEE, 0x39, 0x6F, 0xB7, 0x4C, 0x76, 0xC9, 0x10, 0x04, 0xB8, 0x27, 0xD2, 0x18, 0x95, 0x1C, 0x77, 0xBD, 0xB8, 0x15, 0x90, 0xAE, 0xDF, 0xEA, 0x9E, 0x62, 0xBE, 0x0F, 0x22, 0xAF, 0xF5, 0x5E, 0x36, 0xAB, 0x57, 0x2D, 0xF1, 0x3A, 0xB9, 0xF5, 0xEA, 0xFC, 0xBC, 0x34, 0xDF, 0x26, 0x6F, 0xE1, 0x60, 0xC6, 0xB6, 0x35, 0xB0, 0xC3, 0xB6, 0x3C, 0x89, 0x29, 0x20, 0x18, 0x5F, 0x11, 0x2B, 0x96, 0x99, 0x8B, 0x5B, 0x5B, 0xB9, 0x73, 0xB3, 0x90, 0x08, 0xB2, 0xF0, 0x43, 0x40, 0x35, 0xD4, 0x3B, 0xD2, 0xE4, 0x9F, 0x2C, 0x17, 0x45, 0x20, 0xD3, 0xA8, 0x98, 0x54, 0xCD, 0x82, 0x50, 0xD6, 0x20, 0x0A, 0x1E, 0xB5, 0x10, 0x79, 0x22, 0x46, 0x56, 0xD0, 0xB3, 0x34, 0xCE, 0xE3, 0x43, 0x0B, 0x87, 0xE1, 0xFF, 0x90, 0x4D, 0x10, 0x34, 0xC2, 0xD8, 0xA7, 0x04, 0x7B, 0x2D, 0x22, 0x56, 0x33, 0x19, 0x04, 0x10, 0x01, 0x2C, 0x16, 0x1C, 0x76, 0x8C, 0x1F, 0xF8, 0xFC, 0x17, 0x9A, 0x44, 0x68, 0x64, 0xDF, 0x93, 0xE0, 0x9D, 0x1E, 0x6C, 0x29, 0x48, 0x7C, 0xAB, 0x04, 0x4E, 0xF8, 0x68, 0xD4, 0x31, 0xB1, 0x76, 0x31, 0x84, 0xAD, 0xCB, 0x39, 0x51, 0x6D, 0xD1, 0x27, 0x6B, 0xD8, 0x41, 0xEC, 0x49, 0x2A, 0x84, 0x51, 0x77, 0x4E, 0xDA, 0x10, 0x6E, 0x73, 0x21, 0xED, 0x5A, 0x62, 0x25, 0xC3, 0x53, 0x24, 0xC5, 0x10, 0x66, 0x3B, 0x9B, 0xEA, 0x05, 0xF1, 0xDB, 0xC8, 0xD5, 0xDB, 0x69, 0xA7, 0x7E, 0xCE, 0x3E, 0x42, 0x65, 0xC5, 0xE8, 0x10, 0x69, 0x86, 0x45, 0x80, 0xB5, 0x28, 0xCC, 0x2C, 0xBB, 0xFB, 0xDE, 0x62, 0x5A, 0xF2, 0xC1, 0xC5, 0xCB, 0x06, 0xDD, 0x80, 0x58, 0x54, 0x04, 0x96, 0x4D, 0x21, 0x11, 0x4B, 0x8B, 0x13, 0xCA, 0xFB, 0x6D, 0xBE, 0x1B, 0x42, 0x8E, 0xBC, 0x87, 0x17, 0xCC, 0xD1, 0x1B, 0xFB, 0x34, 0x72, 0x60, 0xAA, 0x70, 0x1B, 0xF2, 0x28, 0x35, 0xB3, 0xF1, 0x06, 0x2E, 0xAD, 0x36, 0xAC, 0xB9, 0x6D, 0x74, 0x96, 0xF7, 0x2A, 0xA5, 0xFF, 0x1A, 0x13, 0x04, 0xBC, 0x02, 0xE3, 0x58, 0xE6, 0x0B, 0x1C, 0x82, 0x30, 0xBF, 0x8F, 0xFA, 0xFD, 0x36, 0xE0, 0xF6, 0xB2, 0xE3, 0xD8, 0x58, 0x2F, 0xD3, 0xA4, 0x38, 0x11, 0xAC, 0x24, 0xD0, 0x60, 0x08, 0x10, 0x35, 0x42, 0x87, 0x8C, 0xB5, 0xCE, 0x99, 0xF8, 0x92, 0x0C, 0xC8, 0x02, 0xDA, 0x4E, 0xD2, 0x18, 0x39, 0x56, 0x83, 0x4D, 0xA4, 0xC7, 0x19, 0x55, 0x0D, 0xB2, 0x47, 0x95, 0xAC, 0xE0, 0x9D, 0x88, 0xCA, 0x30, 0x43, 0xAF, 0xCC, 0xC9, 0xAB, 0x0F, 0x03, 0x06, 0x67, 0x1F, 0xD1, 0xF2, 0x50, 0x95, 0x7C, 0xC6, 0x24, 0x64, 0xC9, 0xEA, 0x5E, 0x44, 0x4C, 0x6E, 0xB4, 0x76, 0xD0, 0x92, 0x46, 0x56, 0x08, 0xFE, 0xB6, 0xB7, 0xD5, 0x39, 0x8A, 0x02, 0x9E, 0x1E, 0xEA, 0xE5, 0x0D, 0xB5, 0xF9, 0xF9, 0x95, 0x50, 0xA9, 0x66, 0x83, 0x43, 0xEF, 0x29, 0x70, 0xF2, 0x25, 0x31, 0x67, 0x8E, 0x36, 0x71, 0x3B, 0x81, 0xCB, 0x36, 0x33, 0xF1, 0xDD, 0xD4, 0x67, 0x69, 0x82, 0x6E, 0x43, 0x60, 0xDE, 0x19, 0xA5, 0x63, 0x18, 0xD9, 0xEB, 0x59, 0xF9, 0x7A, 0x9B, 0x3E, 0xD2, 0x2B, 0xFD, 0x89, 0x50, 0x11, 0x26, 0x29, 0x5E, 0x89, 0xFC, 0x73, 0x5C, 0x36, 0x19, 0xD7, 0x7F, 0x6F, 0xB9, 0x35, 0xC2, 0xFB, 0x46, 0xED, 0xD0, 0xA4, 0xD2, 0x92, 0x17, 0x77, 0xB0, 0xEF, 0xCD, 0x58, 0xBE, 0xDC, 0xEB, 0x9E, 0xA5, 0x66, 0x6B, 0x18, 0xDF, 0xAC, 0xF9, 0xBF, 0x76, 0x33, 0x3C, 0x5E, 0xDA, 0xC7, 0x2B, 0x04, 0xE6, 0x57, 0xE4, 0xE0, 0x86, 0x5E, 0x04, 0x3A, 0x64, 0x68, 0xC5, 0xE6, 0x9D, 0x5B, 0xCB, 0xE5, 0x84, 0x2B, 0xF4, 0x5B, 0xEE, 0x77, 0x91, 0x5F, 0x05, 0x71, 0xD1, 0x50, 0xD6, 0x06, 0xA6, 0xF2, 0xAC, 0x37, 0x37, 0x92, 0x90, 0x88, 0x91, 0xBA, 0x85, 0xF4, 0x5C, 0xB4, 0x09, 0xD9, 0x63, 0xE4, 0x9B, 0x5B, 0x96, 0x97, 0x8A, 0x19, 0x39, 0x16, 0x0A, 0x8D, 0xB9, 0xD6, 0x3C, 0x4E, 0xA0, 0xD6, 0xA7, 0xD0, 0x93, 0x70, 0xAC, 0x1C, 0x24, 0x49, 0x8D, 0x21, 0xA8, 0xD5, 0xB7, 0x64, 0xA3, 0x9A, 0x41, 0x2E, 0x5B, 0x54, 0xBD, 0x1C, 0x96, 0x4D, 0x24, 0x4A, 0x45, 0x55, 0x64, 0x5F, 0x1F, 0x90, 0x53, 0xF8, 0xBB, 0x33, 0xF6, 0xF7, 0x51, 0x46, 0x80, 0x7B, 0x4E, 0x9E, 0x07, 0xB2, 0x3C, 0x98, 0x06, 0xFF, 0x75, 0x72, 0x46, 0x9C, 0x09, 0x43, 0x99, 0xBA, 0x97, 0x79, 0xB9, 0x62, 0xB4, 0xC8, 0xA9, 0x57, 0xF8, 0x69, 0x91, 0x1E, 0xB1, 0x3F, 0x14, 0x02, 0x24, 0xAC, 0x4E, 0xE7, 0x62, 0x01, 0xC0, 0x2F, 0x24, 0xC7, 0xED, 0xC3, 0xA9, 0x80, 0x89, 0x9A, 0x30, 0xBA, 0xD2, 0xB1, 0x2D, 0x57, 0x28, 0xF0, 0x97, 0x17, 0x6D, 0x00, 0x17, 0xF3, 0x47, 0x3D, 0x2F, 0xBB, 0xD4, 0x3C, 0xC2, 0x3A, 0x50, 0x1E, 0x81, 0xE3, 0x81, 0xBE, 0x01, 0x79, 0xBF, 0x68, 0xCA, 0x50, 0xFD, 0x23, 0x55, 0xCA, 0x7B, 0x64, 0xF5, 0x3E, 0x0C, 0x7D, 0x5B, 0xCA, 0x4E, 0x7B, 0xE6, 0x91, 0x63, 0xE3, 0x16, 0xFE, 0xBB, 0x49, 0xA9, 0x34, 0x0F, 0x15, 0x7B, 0xAC, 0x3B, 0x0B, 0xD8, 0x4A, 0x3B, 0x02, 0x7A, 0x2F, 0xE4, 0x4E, 0xC2, 0x66, 0xA8, 0xCE, 0x4A, 0x17, 0x1B, 0x91, 0x82, 0x8F, 0x45, 0x43, 0x02, 0xAA, 0x9B, 0x66, 0x49, 0x67, 0xE6, 0x7D, 0xB3, 0x8A, 0xA4, 0xE3, 0xBC, 0x35, 0x3D, 0x15, 0x18, 0xA7, 0xFE, 0xC1, 0x18, 0x8B, 0x7D, 0x5B, 0x7E, 0x19, 0x52, 0x1F, 0x1A, 0x28, 0x77, 0x00, 0x69, 0x89, 0xB0, 0xFE, 0x91, 0x89, 0x46, 0xB7, 0x59, 0x3E, 0xD1, 0x51, 0x20, 0xBF, 0x7D, 0x23, 0xF9, 0x92, 0x10, 0xDD, 0xB7, 0x6D, 0xAF, 0x86, 0xE2, 0x37, 0xB2, 0x37, 0x9C, 0xA1, 0x2E, 0x55, 0x63, 0x6C, 0x83, 0x40, 0x8E, 0x6D, 0x2B, 0x35, 0x85, 0xFA, 0xBC, 0xBC, 0x0F, 0x6C, 0x48, 0x76, 0x7E, 0x36, 0x3A, 0xC8, 0x47, 0xCC, 0xC6, 0x7E, 0xB7, 0xC9, 0x37, 0xBB, 0xD9, 0x41, 0x10, 0x0D, 0x78, 0x77, 0x4A, 0xE1, 0xF4, 0x43, 0x39, 0xDC, 0xDC, 0xB0, 0xE7, 0x00, 0xAC, 0x10, 0x8D, 0xAA, 0x92, 0xCD, 0x9E, 0xA1, 0x9F, 0x82, 0x38, 0xF2, 0x86, 0x76, 0xFE, 0xE7, 0xBD, 0x1B, 0x9F, 0x37, 0xA6, 0xCA, 0x17, 0xD7, 0xCF, 0x40, 0x42, 0xFE, 0x39, 0xDD, 0x93, 0x77, 0x82, 0x6C, 0x4C, 0xAB, 0x29, 0x32, 0xE1, 0x2D, 0xE5, 0x3B, 0x08, 0x1A, 0x6C, 0x25, 0xC0, 0xF4, 0x7D, 0xA3, 0xD9, 0x16, 0x83, 0x1E, 0x42, 0x47, 0xD0, 0x97, 0x81, 0x1E, 0x1A, 0x08, 0x70, 0xCB, 0x61, 0xF4, 0xAC, 0xA1, 0x27, 0xEA, 0xF8, 0x5A, 0x9C, 0xA6, 0x66, 0xFA, 0x6C, 0x36, 0x39, 0x8F, 0x0E, 0x74, 0x20, 0xCA, 0x98, 0x95, 0xC6, 0x3A, 0x1A, 0xC4, 0xDB, 0x49, 0xA1, 0xD7, 0x5F, 0x56, 0x46, 0x4C, 0x1E, 0x0C, 0xF9, 0x28, 0x3A, 0x45, 0x44, 0x56, 0x50, 0xF9, 0x5F, 0xAD, 0xF6, 0xC8, 0x8D, 0xB3, 0xCE, 0x7C, 0x0E, 0x5D, 0x0E, 0x72, 0x61, 0xE8, 0x04, 0xC0, 0x3A, 0x41, 0x9E, 0x4C, 0xC2, 0x50, 0x10, 0x99, 0xCA, 0x53, 0x63, 0x44, 0x60, 0x7B, 0x07, 0xE8, 0x25, 0x32, 0x3A, 0xD3, 0x0B, 0xE7, 0x5F, 0x84, 0xE6, 0xC5, 0xBE, 0x23, 0x8E, 0xC7, 0x86, 0x17, 0xA0, 0xA2, 0x34, 0x14, 0xC7, 0xF8, 0xCD, 0x60, 0x91, 0x30, 0x31, 0xBC, 0x93, 0x01, 0x78, 0x6D, 0x5C, 0x19, 0xD9, 0x30, 0xB5, 0x06, 0xC4, 0x95, 0x98, 0x32, 0x23, 0xEC, 0x1B, 0xF7, 0x87, 0xC3, 0x3D, 0x22, 0x8A, 0x11, 0x0E, 0x57, 0x42, 0x87, 0x73, 0xE3, 0x4F, 0x12, 0x66, 0x3D, 0x11, 0xC1, 0x55, 0xDF, 0xCE, 0x38, 0x0D, 0x65, 0x76, 0x4C, 0x26, 0x59, 0xEA, 0xA0, 0xA1, 0xA2, 0xE7, 0x64, 0xEB, 0xB5, 0xA9, 0xE5, 0xA7, 0x19, 0x2E, 0x90, 0x86, 0xA6, 0xDE, 0x4A, 0x38, 0xFC, 0xFD, 0x04, 0x12, 0x42, 0x42, 0x60, 0x62, 0x0C, 0x1E, 0x56, 0x7A, 0x2D, 0x8B, 0x1A, 0xF3, 0x55, 0x48, 0x19, 0xA0, 0x0D, 0x5C, 0x7E, 0x56, 0x66, 0xD0, 0xE6, 0x56, 0xF8, 0xD4, 0x5C, 0x67, 0xC5, 0x44, 0x8D, 0xAB, 0x5E, 0xB6, 0xE6, 0x02, 0x93, 0x79, 0xC4, 0x7A, 0x24, 0xD0, 0x11, 0xF5, 0x6E, 0x5F, 0xAA, 0x49, 0xFC, 0x6B, 0xB2, 0xD7, 0x50, 0xED, 0x4C, 0x95, 0xF8, 0x35, 0x38, 0x4F, 0x2F, 0xAA, 0xB1, 0x3C, 0x1C, 0xCA, 0x71, 0xA1, 0xEB, 0xD2, 0x29, 0x9E, 0x96, 0x32, 0xE5, 0x29, 0xCE, 0x77, 0x14, 0x9F, 0x5F, 0xAC, 0x31, 0xAB, 0x28, 0xDC, 0xC7, 0x06, 0x70, 0xBB, 0xAB, 0x9F, 0x7B, 0x6F, 0xFE, 0xAA, 0xBC, 0x7D, 0xC4, 0x51, 0x3D, 0x8F, 0xAC, 0x4B, 0xCF, 0x7E, 0x5E, 0x72, 0x97, 0xDB, 0x69, 0xE4, 0xB6, 0x25, 0x38, 0xF9, 0xCA, 0xBD, 0x90, 0x2B, 0x10, 0x07, 0xE3, 0xBA, 0xF6, 0x7F, 0x94, 0x3D, 0xFD, 0xC6, 0xAA, 0x75, 0x62, 0xFA, 0xBB, 0x1E, 0x8F, 0xAC, 0xF8, 0x11, 0xC7, 0x63, 0x35, 0x79, 0x0A, 0x16, 0xF2, 0x1E, 0xCB, 0x72, 0xFC, 0x1B, 0xA9, 0x42, 0x76, 0xB2, 0x09, 0x80, 0x7E, 0xA5, 0x2E, 0x74, 0xF2, 0xB6, 0xCA, 0x0B, 0x3F, 0xDC, 0x30, 0x50, 0x1F, 0x63, 0x10, 0xEC, 0x99, 0x55, 0xB0, 0x51, 0x81, 0x8D, 0xAE, 0x10, 0x80, 0xFD, 0x4D, 0xD2, 0x4C, 0x72, 0x2D, 0x68, 0xDE, 0x33, 0xEA, 0x76, 0x9B, 0x4E, 0x63, 0x70, 0x07, 0xCF, 0xDC, 0xE1, 0x80, 0x4A, 0xC2, 0xA7, 0x71, 0xF8, 0x8F, 0x59, 0xBA, 0xCE, 0xDB, 0x4D, 0xFB, 0x79, 0xA4, 0x1E, 0xA7, 0x0F, 0x14, 0xAC, 0xCE, 0x6A, 0x5A, 0x8A, 0x88, 0x43, 0xB5, 0x95, 0x89, 0xE4, 0x52, 0x8B, 0xA8, 0x52, 0x10, 0x42, 0x1D, 0x1E, 0x59, 0x5F, 0x84, 0xC2, 0x75, 0x90, 0x47, 0xDB, 0x47, 0x22, 0x26, 0x73, 0x86, 0x8C, 0x00, 0x27, 0xEE, 0xFD, 0x99, 0x6E, 0xF8, 0xC8, 0xC4, 0xF3, 0x67, 0xA9, 0x1D, 0xEC, 0xF1, 0x79, 0x43, 0x22, 0x7D, 0x4D, 0x00, 0x44, 0x7F, 0xFC, 0x6C, 0xC8, 0x66, 0x5E, 0x08, 0xD2, 0x93, 0xA4, 0xDE, 0x4E, 0xE1, 0x15, 0x69, 0xB9, 0x5B, 0xB4, 0xDA, 0xE7, 0x58, 0x15, 0x0E, 0x55, 0x78, 0x32, 0x55, 0xE2, 0xF3, 0x22, 0x27, 0xB4, 0x5A, 0x9D, 0x26, 0x19, 0x77, 0x1C, 0xED, 0x51, 0x2D, 0x5C, 0xD8, 0x90, 0x18, 0xC9, 0x9E, 0x2F, 0x05, 0x23, 0x3E, 0xF5, 0x86, 0x0F, 0xEC, 0xB3, 0x79, 0x1B, 0x53, 0xAD, 0x2C, 0x22, 0x8A, 0xBA, 0xBB, 0x9F, 0xD1, 0xF5, 0x04, 0x38, 0xE9, 0xB0, 0xC6, 0xEA, 0x61, 0xE2, 0x0B, 0xB5, 0xAC, 0x0A, 0xAD, 0x30, 0x50, 0x9F, 0xEA, 0x9A, 0x44, 0x1D, 0x55, 0x5C, 0xDD, 0x34, 0x50, 0x9C, 0xFC, 0x60, 0x62, 0xE6, 0xB8, 0x1D, 0xCA, 0xCF, 0xD5, 0xF5, 0xC9, 0xC5, 0x26, 0xB3, 0x8D, 0x70, 0x4C, 0x1F, 0x0F, 0x28, 0xB4, 0xFB, 0x7C, 0x1A, 0xC6, 0x9A, 0xA1, 0x96, 0xCF, 0x81, 0x2E, 0x44, 0x46, 0xEF, 0x68, 0x02, 0x87, 0x44, 0xD2, 0xA5, 0x40, 0xFA, 0x7A, 0x69, 0xCF, 0x87, 0xA1, 0xF9, 0x68, 0x24, 0xE4, 0xC6, 0x87, 0x82, 0x35, 0xF0, 0xCC, 0xA3, 0xE9, 0x7B, 0x2B, 0x22, 0xB0, 0x93, 0xD9, 0x5E, 0xE1, 0x8D, 0xBF, 0xE6, 0x76, 0x1D, 0xFA, 0xF8, 0x34, 0x47, 0x51, 0x86, 0x07, 0x56, 0x02, 0x31, 0x3E, 0xE2, 0xA2, 0x99, 0xBC, 0xCC, 0xC6, 0x53, 0x1E, 0xDA, 0x54, 0x10, 0xCC, 0xFA, 0x09, 0xEC, 0xB8, 0xA6, 0x0D, 0x28, 0x33, 0x7A, 0xA5, 0x56, 0x58, 0x6D, 0x78, 0x48, 0x49, 0x38, 0x0F, 0x02, 0xEB, 0xB8, 0x37, 0xCB, 0x0B, 0xDE, 0x57, 0xBB, 0xA9, 0x07, 0xB6, 0x7C, 0x7A, 0xD8, 0x66, 0xE1, 0xDD, 0xB1, 0xC7, 0x9D, 0x96, 0x1D, 0x70, 0xF5, 0x5D, 0x05, 0x9A, 0xCF, 0xD3, 0x9F, 0x5B, 0xD3, 0x03, 0x74, 0xB4, 0x84, 0x5E, 0x04, 0xEC, 0x26, 0xE8, 0xB5, 0xB9, 0x3F, 0xC4, 0x54, 0x4F, 0x24, 0xAE, 0x99, 0xC9, 0xE5, 0x1E, 0x43, 0x57, 0x75, 0xD2, 0x20, 0x80, 0xE1, 0x9E, 0x3A, 0xC2, 0x25, 0xC7, 0xE1, 0xEE, 0x0A, 0x56, 0xB9, 0x52, 0x30, 0x7F, 0x44, 0xBA, 0xCF, 0x4C, 0x87, 0x85, 0x35, 0x5C, 0x09, 0xDB, 0xD0, 0xD8, 0x60, 0x57, 0xF0, 0xA6, 0xA9, 0x88, 0xC3, 0x65, 0x74, 0x20, 0x25, 0x19, 0xDE, 0xBA, 0x04, 0x56, 0x98, 0xD7, 0x24, 0x27, 0x77, 0x0C, 0x37, 0x31, 0xC9, 0xB7, 0x53, 0x5F, 0xAA, 0xF0, 0xCC, 0xA9, 0xD1, 0x3C, 0x42, 0x12, 0xB7, 0x62, 0x94, 0x57, 0x52, 0xE7, 0xA6, 0x53, 0x9B, 0x47, 0xBE, 0xA9, 0x66, 0x48, 0x23, 0x18, 0xA9, 0xCF, 0xE3, 0xBA, 0xEC, 0x6A, 0x83, 0xFB, 0x34, 0xF0, 0xB6, 0x8E, 0xE9, 0x77, 0x97, 0x42, 0x0F, 0xAD, 0xC3, 0xF0, 0x25, 0xEE, 0x9F, 0x18, 0xBE, 0xA3, 0x8F, 0xBE, 0xC0, 0xC5, 0xDE, 0xAA, 0xC7, 0xA5, 0x2F, 0x7E, 0xB8, 0xD9, 0x4F, 0xE4, 0xC6, 0x62, 0x54, 0x14, 0x57, 0xA1, 0x53, 0x82, 0x4B, 0xE6, 0x0D, 0x7D, 0xB8, 0x33, 0x89, 0x0F, 0x3A, 0xC3, 0xF7, 0xBD, 0x6D, 0x73, 0xF8, 0x0C, 0x67, 0x2B, 0x76, 0xA5, 0x26, 0x7D, 0xF2, 0x2C, 0xFB, 0x5E, 0x1B, 0x92, 0xB0, 0xCD, 0x68, 0xE9, 0xA9, 0x20, 0x92, 0x43, 0xA4, 0x2A, 0x30, 0xF7, 0xAA, 0x1F, 0x03, 0xD0, 0xD9, 0x11, 0x3F, 0x04, 0xB7, 0x6E, 0xB5, 0xAA, 0x69, 0xBC, 0x9B, 0x8F, 0xE7, 0x98, 0xE7, 0x75, 0x01, 0xB0, 0x56, 0x30, 0x29, 0xF5, 0x02, 0xF7, 0x79, 0x4D, 0xD3, 0x90, 0x74, 0x7A, 0xED, 0x08, 0x5C, 0x22, 0xB2, 0x16, 0x11, 0xA9, 0xC7, 0x62, 0x38, 0xEF, 0x65, 0x84, 0xAE, 0xFB, 0xB3, 0x57, 0xF8, 0x36, 0x25, 0x86, 0xC5, 0x9F, 0xCA, 0x8E, 0x09, 0x26, 0x10, 0x11, 0x5F, 0x4D, 0xC2, 0x93, 0x0D, 0x72, 0x24, 0x28, 0x5E, 0xB8, 0xFD, 0x99, 0x2F, 0x82, 0x17, 0xAE, 0x94, 0x70, 0xA7, 0x4A, 0xE3, 0xE8, 0x06, 0x01, 0x0C, 0x8D, 0x02, 0x19, 0x48, 0xBE, 0x57, 0xAB, 0x1D, 0x62, 0xC0, 0x41, 0x2E, 0xA5, 0xC9, 0x69, 0xD0, 0x56, 0x68, 0x41, 0xF2, 0xE2, 0x56, 0x8E, 0x01, 0x33, 0x64, 0xD8, 0x7C, 0xAF, 0x33, 0x22, 0x9D, 0x2A, 0xA6, 0xC5, 0x6B, 0x9F, 0xB4, 0xC1, 0x36, 0xA1, 0x3F, 0x5E, 0x73, 0x3A, 0x91, 0xEF, 0xF2, 0x1D, 0xCB, 0x29, 0x0D, 0x8E, 0xC6, 0xDC, 0x0A, 0x50, 0xE5, 0x7C, 0x1F, 0x65, 0xEB, 0x2B, 0xA1, 0xC3, 0x9D, 0xDB, 0x1C, 0x09, 0x54, 0x24, 0xE6, 0xF4, 0x1F, 0x9E, 0x86, 0x56, 0x7F, 0x91, 0x14, 0x00, 0xD8, 0x5C, 0x90, 0xD6, 0x4F, 0xC7, 0xE6, 0xEC, 0xC2, 0x88, 0x04, 0xF2, 0x70, 0x42, 0x40, 0x24, 0x9E, 0xFC, 0x8F, 0xEC, 0x69, 0xE3, 0x66, 0xF3, 0x68, 0x7A, 0x76, 0x20, 0x5C, 0x0D, 0x1D, 0xD6, 0x48, 0x39, 0x12, 0xA8, 0xF6, 0x8E, 0xAE, 0x2C, 0xB3, 0x52, 0x0A, 0x8B, 0x17, 0x2C, 0xF2, 0xCD, 0x2B, 0x03, 0x80, 0x2E, 0x5F, 0xA7, 0xB1, 0xF1, 0xEF, 0x8C, 0xA0, 0xA6, 0x08, 0x0B, 0xF9, 0xDA, 0x37, 0x82, 0xD2, 0xBD, 0xE4, 0xB3, 0xA3, 0xC6, 0x5C, 0xFB, 0x9F, 0x1B, 0x39, 0x05, 0xB9, 0x36, 0x1D, 0x1E, 0x0C, 0x8F, 0xEB, 0x5A, 0xB4, 0x0A, 0x3F, 0xFE, 0xB3, 0xAE, 0x95, 0xF5, 0x75, 0x62, 0xA0, 0x7C, 0xD2, 0x43, 0x18, 0xC0, 0xE7, 0xEE, 0x6E, 0xBE, 0x57, 0x0C, 0xB7, 0xDC, 0x1C, 0x62, 0x1A, 0x84, 0x92, 0x13, 0xE7, 0x13, 0x92, 0x42, 0x75, 0x81, 0x28, 0xC1, 0x6C, 0xFE, 0x52, 0xF8, 0xE2, 0xED, 0xA5, 0xBA, 0x23, 0x23, 0x15, 0x6F, 0x85, 0x3A, 0xBC, 0x61, 0xB1, 0x39, 0x04, 0x1A, 0x4B, 0x83, 0x40, 0x37, 0xAA, 0x19, 0xDC, 0xEE, 0x76, 0x06, 0xAE, 0x84, 0xC1, 0xA7, 0x4D, 0x0E, 0xEB, 0x6A, 0x4D, 0xAB, 0xD5, 0x90, 0x8D, 0xAE, 0x2C, 0x23, 0xA6, 0x38, 0x76, 0xE7, 0xE9, 0xF8, 0xE9, 0x03, 0x66, 0xA1, 0xFD, 0x89, 0xF2, 0x28, 0x3D, 0x75, 0x30, 0x09, 0xE0, 0x56, 0xDD, 0x5A, 0xB9, 0x53, 0xDB, 0x3D, 0x8F, 0x48, 0x30, 0xA4, 0xD0, 0x93, 0x79, 0x39, 0x5F, 0x21, 0xED, 0x03, 0xB6, 0xCC, 0xD5, 0xD7, 0xF8, 0xF8, 0x1F, 0x40, 0x0B, 0x3E, 0x3B, 0xC6, 0x96, 0x08, 0x8D, 0x58, 0x17, 0x75, 0x21, 0x11, 0x0B, 0x6C, 0x84, 0x74, 0xF3, 0xE4, 0x49, 0xD8, 0xEC, 0x7F, 0x46, 0x6C, 0x2E, 0xB3, 0x43, 0x65, 0x9F, 0xF5, 0x33, 0x97, 0x58, 0x7B, 0xC6, 0x30, 0x0D, 0xEE, 0xBD, 0xC2, 0xBE, 0x67, 0x4B, 0x78, 0x30, 0x90, 0xEA, 0xCC, 0xB9, 0x3B, 0x6A, 0xE9, 0x49, 0x56, 0xA3, 0x33, 0xE8, 0x58, 0x37, 0x64, 0x73, 0xCA, 0x67, 0xAF, 0x05, 0x43, 0xE5, 0x99, 0x94, 0x1E, 0xB4, 0xE8, 0xC6, 0xD9, 0x5D, 0x47, 0x9F, 0xEE, 0xE0, 0x5E, 0x3E, 0x8B, 0xF5, 0xF0, 0xAA, 0xCD, 0x34, 0x51, 0xC0, 0xED, 0x48, 0x1F, 0x52, 0x6D, 0x38, 0xEB, 0x3B, 0x26, 0xA4, 0xFD, 0x98, 0xE1, 0x1B, 0xAF, 0x67, 0xED, 0xEA, 0xB2, 0xEC, 0xC7, 0xD3, 0x97, 0xE9, 0x68, 0xF8, 0xD1, 0x03, 0xE8, 0x01, 0x44, 0xA4, 0xCD, 0xB7, 0x00, 0xC4, 0x1A, 0x42, 0x83, 0x4B, 0x07, 0xFD, 0x7E, 0x91, 0xF3, 0xC5, 0x24, 0x09, 0xC6, 0x88, 0x2C, 0xF4, 0x15, 0xA4, 0x2F, 0x71, 0xE2, 0x1F, 0xE7, 0x00, 0x17, 0xD6, 0x2B, 0x1F, 0xE4, 0x3A, 0x2A, 0x32, 0xD8, 0x15, 0xE3, 0xF1, 0xA4, 0x4E, 0x72, 0x67, 0xB1, 0xBB, 0xF5, 0x52, 0xF3, 0x8E, 0x88, 0x97, 0x75, 0xEC, 0xD8, 0x5C, 0x4B, 0xF4, 0x65, 0x02, 0x22, 0xF3, 0x30, 0xFA, 0xE4, 0xB6, 0x17, 0x65, 0x52, 0x54, 0x03, 0xFB, 0xDE, 0x0A, 0x18, 0xF9, 0x73, 0x65, 0x7C, 0xAB, 0xEB, 0x05, 0xFE, 0x6B, 0x97, 0x29, 0xD3, 0xB3, 0x73, 0x0A, 0xEF, 0xDF, 0x3C, 0x18, 0x96, 0x99, 0x7A, 0x94, 0x9B, 0x60, 0x3C, 0x43, 0xFE, 0xCC, 0x3E, 0xAC, 0xCB, 0xF0, 0x0C, 0x03, 0x76, 0x59, 0x41, 0x80, 0x0C, 0xE4, 0x2F, 0xD0, 0x38, 0x4E, 0x1C, 0x1C, 0x61, 0x17, 0x31, 0x6C, 0xBA, 0x1A, 0x81, 0xA2, 0x09, 0x03, 0x3C, 0x5B, 0x53, 0xAE, 0x3B, 0x60, 0xBC, 0x1A, 0xFC, 0x6E, 0x7C, 0x95, 0xC5, 0xCB, 0x99, 0xC2, 0x6A, 0x4C, 0x88, 0x1F, 0x62, 0x6A, 0x21, 0x9A, 0x61, 0x9B, 0xC3, 0x5C, 0xF4, 0xEF, 0x0A, 0x3B, 0x67, 0x25, 0x34, 0x9D, 0x2C, 0x13, 0xD8, 0x9D, 0xE6, 0x5D, 0x9F, 0x7A, 0x35, 0x51, 0xCC, 0xCF, 0xC5, 0x61, 0x1D, 0xC9, 0xC8, 0x73, 0x7B, 0x0E, 0xF0, 0xFA, 0xDF, 0x86, 0x5A, 0x65, 0x33, 0x9F, 0x46, 0x4C, 0xB0, 0x65, 0xBA, 0x8F, 0xE4, 0x81, 0x06, 0x46, 0xA3, 0x44, 0x5B, 0x70, 0x2F, 0x51, 0xD6, 0xA9, 0x13, 0x49, 0xFD, 0x70, 0xA3, 0x56, 0x49, 0xFD, 0x4D, 0xAE, 0xE6, 0x13, 0x10, 0xA3, 0xCC, 0xA5, 0xED, 0x3A, 0xBD, 0xBF, 0xF8, 0x35, 0x5B, 0x51, 0x14, 0x83, 0x5F, 0xDE, 0x73, 0xC9, 0xF5, 0x2A, 0xC2, 0x29, 0xB1, 0x5E, 0x84, 0xD3, 0xF5, 0x9D, 0xCB, 0x13, 0x02, 0x55, 0x1E, 0xA4, 0xDD, 0x6F, 0x41, 0x5D, 0x01, 0x39, 0x11, 0xD6, 0x53, 0x15, 0xC8, 0xE5, 0x9B, 0x12, 0x20, 0x4A, 0xAA, 0xF5, 0x25, 0x75, 0x4E, 0x96, 0xEC, 0x3C, 0xB1, 0x3E, 0x19, 0x72, 0x62, 0x1F, 0x9C, 0x86, 0xF5, 0xDE, 0x4A, 0xDA, 0xB9, 0x80, 0xCF, 0x83, 0x69, 0x12, 0x7C, 0x2B, 0x3E, 0x4E, 0xF1, 0xA8, 0x2B, 0x7A, 0xC9, 0x59, 0xAB, 0x45, 0xD9, 0x7E, 0xEE, 0x7A, 0x14, 0xE4, 0x14, 0x5B, 0x34, 0x9B, 0x53, 0x3D, 0xD9, 0x2D, 0xD2, 0xC1, 0x77, 0xC7, 0x7A, 0xBA, 0x32, 0x5D, 0xD7, 0x5C, 0x77, 0xB3, 0x1A, 0x6A, 0xB3, 0xAA, 0xBE, 0x54, 0xA6, 0xCF, 0xA2, 0xDC, 0xA3, 0x5E, 0x20, 0x99, 0x35, 0xEF, 0x9D, 0x94, 0x7A, 0x37, 0xE8, 0x35, 0x97, 0xB9, 0x4F, 0xCA, 0xF5, 0x8A, 0x56, 0xD1, 0x4A, 0x05, 0x69, 0x12, 0xC2, 0x2A, 0x54, 0xA6, 0xFF, 0x2F, 0xE8, 0x25, 0xBA, 0xAD, 0x8A, 0xBF, 0x1D, 0xD8, 0x7F, 0xB0, 0xFA, 0x15, 0x19, 0xA5, 0xB7, 0xB4, 0x2F, 0x4B, 0xB2, 0xF7, 0x57, 0xEF, 0xF7, 0xC1, 0x2A, 0x2C, 0xD1, 0xB9, 0x1F, 0xAE, 0xBF, 0x80, 0x86, 0x51, 0x6D, 0xCD, 0xD5, 0x5F, 0x63, 0x84, 0x18, 0x8F, 0x53, 0xC6, 0xA7, 0x81, 0x86, 0x2F, 0xB5, 0xCC, 0x3C, 0xC6, 0x1A, 0xDE, 0x2F, 0x11, 0x08, 0xD1, 0x51, 0x63, 0xC3, 0x8C, 0x4C, 0xA0, 0x1B, 0xF7, 0xF2, 0xC8, 0x1B, 0x8C, 0x79, 0xAD, 0x69, 0x4A, 0x01, 0x61, 0x7B, 0xC0, 0x4F, 0x84, 0x70, 0xC2, 0xC7, 0x71, 0xBE, 0xE2, 0x9A, 0x66, 0x6B, 0xE8, 0x51, 0x42, 0xCB, 0x96, 0x7E, 0xC5, 0x69, 0xA4, 0x02, 0x2A, 0x64, 0xFC, 0x5D, 0x95, 0xA5, 0x57, 0x76, 0xAC, 0x73, 0x27, 0x55, 0xB2, 0x39, 0x29, 0xF2, 0x59, 0x86, 0xD9, 0x3C, 0x01, 0x9B, 0xBB, 0xFB, 0x15, 0x4C, 0x26, 0xBB, 0x47, 0xA2, 0xBA, 0x4B, 0x32, 0x97, 0xDC, 0xE4, 0x47, 0xC5, 0x61, 0xA1, 0xC4, 0x9F, 0x75, 0x35, 0xA7, 0xA1, 0x4C, 0x98, 0x30, 0x18, 0x6A, 0xA0, 0xDD, 0xFA, 0x00, 0x1A, 0xEA, 0x0D, 0x94, 0xC4, 0x0A, 0xC8, 0xA8, 0x41, 0x8E, 0x8D, 0x57, 0x8D, 0x84, 0x21, 0x41, 0x3F, 0xB7, 0xE8, 0x20, 0x23, 0x7E, 0xF3, 0xB5, 0xCB, 0xF6, 0x08, 0x1C, 0x44, 0x2C, 0x13, 0xB4, 0x98, 0x5E, 0xE6, 0x39, 0xE8, 0xF8, 0x6D, 0xB2, 0x87, 0x3B, 0xC2, 0xC9, 0xD3, 0xA9, 0xE5, 0x17, 0xAD, 0x70, 0x31, 0xDA, 0x3C, 0xC9, 0x2F, 0xC1, 0x5F, 0x50, 0x2F, 0xAD, 0x3F, 0xC5, 0xFD, 0xBB, 0xCD, 0x2C, 0x95, 0x50, 0xA8, 0x95, 0x25, 0xF0, 0x06, 0x7C, 0xC3, 0xEA, 0x22, 0xD8, 0xD5, 0xB6, 0x1A, 0xFA, 0xA4, 0xB5, 0x53, 0xAC, 0x30, 0x39, 0x20, 0xF2, 0x5D, 0x6D, 0x58, 0xF6, 0x1F, 0x63, 0x56, 0x68, 0x5E, 0x43, 0x50, 0x9A, 0x00, 0x62, 0xF8, 0x37, 0xBC, 0xB9, 0xA1, 0xA2, 0x2C, 0xFF, 0x08, 0x10, 0x80, 0x18, 0xD6, 0xD2, 0x4B, 0xDC, 0x2B, 0x09, 0x6D, 0x2E, 0xA0, 0x82, 0x0A, 0x05, 0x03, 0x82, 0x0A, 0x01, 0x00, 0x03, 0x23, 0x69, 0xA2, 0xCE, 0x57, 0x2F, 0xD0, 0x8B, 0xFC, 0x30, 0x4B, 0x48, 0x48, 0xE7, 0x8D, 0x75, 0x2D, 0x77, 0xE9, 0x7A, 0x28, 0xB9, 0x9B, 0x9B, 0xB6, 0xFB, 0x5C, 0x7C, 0x63, 0x37, 0x51, 0x4B, 0x32, 0x1E, 0xCD, 0xC1, 0xFB, 0x66, 0x9F, 0x26, 0xD4, 0x17, 0x1A, 0xB4, 0x2B, 0x72, 0x72, 0x0E, 0xE7, 0x0E, 0x05, 0x19, 0xA6, 0xE1, 0xD3, 0xD6, 0xD9, 0x91, 0x4E, 0xC1, 0xB2, 0x1C, 0xDE, 0x38, 0xB4, 0x1A, 0xAC, 0x1D, 0x3A, 0xBE, 0xE6, 0xF2, 0xB7, 0x49, 0x5C, 0x4C, 0x82, 0x0C, 0x1F, 0xC0, 0xCC, 0x9E, 0x71, 0xE2, 0x4C, 0xFB, 0x5C, 0x9C, 0x0D, 0x8E, 0xEF, 0x42, 0x64, 0xAF, 0x48, 0x4F, 0xAE, 0x4D, 0x6E, 0x5D, 0xDE, 0x65, 0xD4, 0xDF, 0x72, 0xB6, 0x1C, 0x6D, 0xBD, 0x26, 0xF8, 0x61, 0xA5, 0xE0, 0xB8, 0x53, 0xAC, 0x54, 0x13, 0x22, 0x6F, 0xEB, 0xBA, 0xBA, 0x5E, 0xB4, 0x74, 0xC6, 0xFB, 0x25, 0xA8, 0x26, 0x78, 0xEA, 0x16, 0x06, 0xB4, 0x52, 0xA2, 0x31, 0x12, 0x22, 0x10, 0x17, 0xB8, 0xC0, 0x73, 0xC1, 0x03, 0x78, 0xF9, 0x14, 0x56, 0x41, 0xA8, 0xC0, 0x78, 0xC0, 0xED, 0x9E, 0x42, 0x16, 0x50, 0xF7, 0x48, 0x89, 0x25, 0x22, 0xAB, 0x9F, 0xB7, 0xD1, 0xFF, 0x8C, 0xF1, 0xCC, 0x71, 0xB8, 0x56, 0x6E, 0x8D, 0xA3, 0x3C, 0xD7, 0x36, 0x17, 0x70, 0xC0, 0x44, 0x34, 0x9A, 0xC4, 0x40, 0xCC, 0xCD, 0xC6, 0xBB, 0xE3, 0x5E, 0x6C, 0x55, 0x78, 0x27, 0x66, 0xF3, 0x8E, 0x68, 0x8B, 0xF4, 0x78, 0x21, 0x03, 0x72, 0x99, 0xE3, 0x44, 0xEC, 0xDE, 0xCA, 0x17, 0xAD, 0x5D, 0x15, 0xCD, 0x27, 0xA4, 0xF7, 0xB0, 0x70, 0x66, 0x11, 0x38, 0xED, 0xE8, 0xED, 0x72, 0xA8, 0x95, 0x9C, 0x5A, 0xE3, 0x6B, 0x1C, 0x46, 0x09, 0x4A, 0x53, 0xCB, 0x21, 0xA7, 0xA4, 0x26, 0x73, 0xF1, 0x40, 0x1C, 0x2B, 0x25, 0x94, 0x94, 0x09, 0x0E, 0x2F, 0x53, 0xD7, 0xEE, 0x70, 0x63, 0x43, 0x1E, 0xE5, 0x85, 0x80, 0x02, 0xD8, 0x50, 0xAF, 0x90, 0x9C, 0x37, 0x83, 0x43, 0x60, 0x10, 0xF7, 0xEA, 0x88, 0x62, 0x5A, 0x36, 0xA0, 0xF0, 0x18, 0x9F, 0xDE, 0x75, 0xB7, 0xE8, 0xC7, 0xE4, 0xB1, 0x9D, 0x85, 0x27, 0x00, 0x83, 0x28, 0xAD, 0xBC, 0x92, 0x9B, 0xBC, 0x86, 0xE9, 0x64, 0xCF, 0xC4, 0x8B, 0x8C, 0xF1, 0xDA, 0x5D, 0x7E, 0xD3, 0x33, 0x3A, 0xB5, 0x5C, 0x15, 0x07, 0x28, 0x32, 0x21, 0x4A, 0x77, 0x9A, 0x5F, 0xD1, 0x0C, 0xC0, 0x40, 0x05, 0xF4, 0x6C, 0x1A, 0xA8, 0x88, 0x4A, 0x16, 0x19, 0x92, 0x47, 0x2F, 0xD5, 0x35, 0xB9, 0x5E, 0xD1, 0x8B, 0xDE, 0x1C, 0x6D, 0x8C, 0xE6, 0x78, 0xD2, 0x81, 0x7D, 0x69, 0xF9, 0x05, 0x71, 0x10, 0x3E, 0x85, 0x20, 0xE7, 0x31, 0x3C, 0xE7, 0xB9, 0x30, 0xC5, 0xEB, 0xFA, 0xF2, 0xF4, 0xEC, 0x75, 0x8B, 0x62, 0x6B, 0x55, 0x43, 0xA0, 0x68, 0xCD, 0xE0, 0xFD, 0x0E, 0x94, 0xE6, 0xA6, 0x44, 0x75, 0xB2, 0x32, 0x68, 0xBF, 0x03, 0x80, 0xD0, 0x75, 0x50, 0x8F, 0x85, 0x12, 0x8C, 0xA2, 0x6F, 0x31, 0xA9, 0x0C, 0x4A, 0x7D, 0x28, 0x44, 0x0D, 0x54, 0xD4, 0x06, 0x6B, 0x40, 0x45, 0x88, 0x58, 0x8B, 0x4C, 0xCF, 0x85, 0x0B, 0x97, 0x5C, 0x73, 0xAF, 0xE6, 0x8C, 0xBC, 0xD1, 0x02, 0x75, 0x5F, 0x61, 0xEB, 0x3E, 0x60, 0x32, 0x3C, 0x57, 0x6E, 0x52, 0x9E, 0xC0, 0xBF, 0x23, 0xBF, 0xA5, 0xBE, 0xA3, 0x9C, 0xB7, 0x3C, 0x37, 0xE8, 0x39, 0x5D, 0x8D, 0xBD, 0x4C, 0x8D, 0xC8, 0xAB, 0x2F, 0x70, 0xA0, 0xBF, 0xC3, 0xA7, 0x8C, 0x0D, 0x41, 0x3F, 0x08, 0xD1, 0x4D, 0x63, 0x2B, 0xC0, 0x40, 0x3B, 0x03, 0x83, 0xDB, 0xBB, 0x22, 0xBD, 0x9B, 0x11, 0x3C, 0x89, 0x45, 0x2A, 0xEA, 0xB1, 0x12, 0x10, 0x09, 0x79, 0x47, 0xFE, 0xAA, 0xA3, 0xC9, 0xF0, 0x5D, 0x1D, 0x30, 0x0C, 0x33, 0xA5, 0x5E, 0x3F, 0xBC, 0x81, 0x25, 0x9E, 0x86, 0x27, 0x05, 0xC3, 0xA1, 0x3B, 0x9E, 0xE3, 0x5F, 0x6B, 0x23, 0xED, 0x10, 0xF4, 0xED, 0xEA, 0x95, 0x19, 0xFA, 0x91, 0xB7, 0xBC, 0xD0, 0xD5, 0x01, 0xB5, 0xED, 0x57, 0xD9, 0x04, 0x9F, 0xAB, 0x91, 0xAA, 0x77, 0x9C, 0x72, 0x5F, 0xF8, 0xE9, 0xF7, 0x80, 0x17, 0xEA, 0x78, 0x07, 0xFA, 0x25, 0x4B, 0x71, 0x05, 0xE8, 0x26, 0xD0, 0x96, 0xC0, 0x1A, 0xDA, 0xE2, 0xC5, 0xD1, 0x38, 0x25, 0x1A, 0x92, 0xA4, 0x78, 0xA3, 0x33, 0x73, 0xF4, 0xDE, 0x91, 0x2B, 0x83, 0xB6, 0xFB, 0x4B, 0x0D, 0x0D, 0xE6, 0xBC, 0x11, 0x18, 0xBB, 0x2F, 0xCF, 0xB0, 0x7B, 0xD2, 0x27, 0xA5, 0xF7, 0xF9, 0x91, 0x43, 0x9A, 0x13, 0xDE, 0x12, 0x38, 0x18, 0x0C, 0xDC, 0x55, 0x11, 0x9E, 0x65, 0xC4, 0x18, 0x58, 0x4D, 0x80, 0x7A, 0x92, 0x6E, 0x4A, 0x9C, 0x0F, 0x70, 0x15, 0x5E, 0xE1, 0x96, 0xFB, 0x07, 0x65, 0x6D, 0x9A, 0xA7, 0x98, 0x2B, 0x87, 0x95, 0xDB, 0xAD, 0x43, 0xD1, 0x05, 0x9C, 0xA7, 0xF5, 0x80, 0xD3, 0x32, 0x0C, 0x04, 0x38, 0xA5, 0xED, 0x5A, 0x70, 0x32, 0xB2, 0xE9, 0x59, 0x67, 0x84, 0x10, 0xF1, 0x1A, 0xD9, 0x8B, 0xE8, 0x82, 0x6A, 0x44, 0x26, 0x26, 0x15, 0x64, 0x5D, 0x75, 0x9A, 0x86, 0x2B, 0x2A, 0xC5, 0x2D, 0x3B, 0x01, 0x4A, 0x25, 0xE8, 0x47, 0x3F, 0x1F, 0x1E, 0xA4, 0xCF, 0xA8, 0x19, 0x93, 0x0A, 0xB3, 0xA3, 0x4D, 0x71, 0x0D, 0xEE, 0xE7, 0x0C, 0xA1, 0x3E, 0x88, 0xFD, 0x71, 0xAA, 0x06, 0x4E, 0x6C, 0xB4, 0x69, 0x7D, 0xE0, 0xE4, 0x63, 0xB1, 0x37, 0x0A, 0x6A, 0x3B, 0xFE, 0x98, 0xFD, 0xFE, 0x7B, 0x54, 0x71, 0xFF, 0x8D, 0xF6, 0xA6, 0x87, 0x9F, 0xBE, 0xF9, 0xAF, 0xB3, 0x51, 0x9D, 0x78, 0x07, 0x57, 0xD6, 0x74, 0x40, 0xAC, 0x36, 0xE8, 0x37, 0xBA, 0xC3, 0x83, 0x3E, 0xEA, 0xA9, 0x80, 0xBD, 0x82, 0xB7, 0x93, 0x64, 0x36, 0xA0, 0x30, 0x7D, 0x16, 0x4B, 0x64, 0x38, 0x86, 0x9A, 0xE6, 0x06, 0xE9, 0x80, 0x51, 0x8E, 0x91, 0x3D, 0x0E, 0xE3, 0x02, 0x39, 0x6E, 0xF4, 0xEB, 0x25, 0xD9, 0x86, 0x6E, 0x4B, 0xAF, 0xA1, 0x01, 0xE5, 0x99, 0x29, 0x31, 0x36, 0x1C, 0x4A, 0x98, 0x22, 0x53, 0xD5, 0x8A, 0xBE, 0x3B, 0xD5, 0x71, 0x07, 0x63, 0x5A, 0x46, 0xF0, 0x95, 0x12, 0x08, 0x5F, 0x4A, 0xDA, 0x08, 0xEC, 0x8B, 0x1B, 0x39, 0x10, 0xB0, 0x15, 0x3B, 0x2A, 0xAF, 0xCA, 0xE5, 0x03, 0x3E, 0xDD, 0x41, 0x53, 0x24, 0x8D, 0xCD, 0x85, 0xB0, 0x2C, 0x9A, 0x25, 0xD8, 0xBD, 0xC4, 0x06, 0x8B, 0xB8, 0x57, 0x41, 0x72, 0x62, 0x97, 0xA2, 0x5A, 0xEC, 0x55, 0xC4, 0x4A, 0xA2, 0x80, 0x59, 0xB7, 0x1B, 0xB9, 0xF3, 0x40, 0x67, 0x88, 0x7A, 0xDE, 0x4C, 0x1C, 0xA4, 0x90, 0x8B, 0x19, 0xB3, 0xD7, 0x81, 0x23, 0x45, 0x38, 0x76, 0xDB, 0x4D, 0xCE, 0xB4, 0x27, 0x73, 0x06, 0x95, 0x72, 0xCD, 0x87, 0x77, 0xE6, 0x2C, 0xFB, 0xAF, 0x72, 0x03, 0xF0, 0x20, 0xF2, 0x81, 0xA6, 0x67, 0x8F, 0x79, 0x07, 0x20, 0xEA, 0xA2, 0x0E, 0x34, 0x32, 0x7D, 0x7A, 0x63, 0x68, 0x8B, 0x09, 0xA0, 0x1F, 0x4D, 0x70, 0x88, 0xF7, 0xB5, 0x05, 0x9E, 0xDD, 0xEB, 0x45, 0xC0, 0xCE, 0x39, 0x32, 0x1C, 0x79, 0x52, 0x1D, 0x79, 0xA5, 0x9E, 0xCD, 0xD4, 0x68, 0xCE, 0xD0, 0xEA, 0x82, 0xCA, 0x48, 0x49, 0x28, 0x70, 0x2F, 0x57, 0xD6, 0xFC, 0x18, 0xD3, 0x47, 0xAF, 0x3E, 0xD2, 0x2A, 0xAF, 0x45, 0xAB, 0xB0, 0xF2, 0x0B, 0xAB, 0x9E, 0x01, 0x55, 0x76, 0x07, 0xAE, 0x3E, 0xD9, 0xCF, 0x0E, 0x26, 0xD3, 0x4D, 0x30, 0x54, 0x49, 0x66, 0x9E, 0xC6, 0xFC, 0x1B, 0xEC, 0xEA, 0xDC, 0xE1, 0x83, 0xF7, 0xA5, 0x94, 0xCE, 0xA1, 0x96, 0xD0, 0x59, 0xA1, 0xE5, 0x50, 0xE5, 0x47, 0x86, 0x6C, 0xC0, 0x87, 0x33, 0x3F, 0x03, 0x0E, 0x62, 0x8F, 0x2C, 0xF1, 0x14, 0x79, 0x25, 0x41, 0x0E, 0xD0, 0x42, 0x1D, 0xC7, 0x50, 0x61, 0x38, 0xB1, 0xD1, 0x90, 0x99, 0xC6, 0x95, 0xE1, 0xAF, 0xDA, 0xCE, 0x41, 0x53, 0x82, 0x5B, 0x66, 0xA8, 0xEC, 0xF5, 0x5A, 0x02, 0x1D, 0x21, 0xEB, 0x9F, 0x84, 0x8F, 0xE5, 0x5C, 0x21, 0x76, 0x9A, 0x75, 0x5F, 0xA9, 0x80, 0x7E, 0xF7, 0x3A, 0x6C, 0x5B, 0xA1, 0x5A, 0x06, 0x34, 0x7D, 0x3F, 0x1C, 0x5C, 0x61, 0x9A, 0x31, 0x55, 0x98, 0x62, 0x91, 0x06, 0xAC, 0x0B, 0x86, 0xAE, 0x0D, 0x8E, 0x55, 0x57, 0x82, 0x92, 0x51, 0x72, 0x58, 0xAE, 0x85, 0xF7, 0x2E, 0x73, 0x7A, 0xF5, 0x63, 0x8D, 0x09, 0x6B, 0x76, 0xA3, 0xC5, 0x7F, 0x1B, 0x9C, 0x80, 0xE7, 0x70, 0xA2, 0xD4, 0xEA, 0x4E, 0x42, 0xFE, 0x46, 0x9A, 0xD4, 0x21, 0x28, 0x52, 0x41, 0x96, 0x0A, 0x8A, 0x86, 0x35, 0x5E, 0xF2, 0x2F, 0x58, 0x3F, 0xE3, 0xBA, 0xCA, 0xDF, 0x8D, 0xA3, 0x1D, 0x5C, 0x2D, 0xE2, 0x54, 0x16, 0x1B, 0xC6, 0xD1, 0x0F, 0x98, 0x41, 0xDD, 0x27, 0xED, 0x46, 0x2A, 0x6B, 0x94, 0xB6, 0xDE, 0xEA, 0x90, 0xCB, 0xAB, 0x68, 0x7F, 0xB8, 0x4B, 0x56, 0x39, 0x5D, 0xA7, 0x63, 0xAB, 0x4B, 0x7F, 0xE3, 0x09, 0x5D, 0x57, 0x2D, 0x77, 0xEF, 0xF3, 0xFF, 0x0D, 0x8F, 0x9D, 0x19, 0xAA, 0x5A, 0xF7, 0xB6, 0x76, 0x05, 0x3D, 0xBE, 0xF6, 0x4E, 0x61, 0xDD, 0x0A, 0x41, 0xD4, 0x02, 0x31, 0x8E, 0x33, 0x08, 0x66, 0x91, 0x06, 0x25, 0x9B, 0xF7, 0xA4, 0xCE, 0x31, 0xB3, 0x46, 0xA9, 0xE9, 0x83, 0xED, 0xAB, 0xA0, 0x51, 0x80, 0x14, 0x9A, 0xB0, 0x57, 0xF9, 0x97, 0x29, 0x77, 0xDA, 0x7C, 0x6F, 0x46, 0xE0, 0xCD, 0xF8, 0x6F, 0x30, 0x91, 0xF0, 0x4F, 0xD4, 0xE8, 0x3C, 0x60, 0x22, 0xE1, 0x8C, 0xE4, 0x38, 0x2B, 0x54, 0xD5, 0xDA, 0xBA, 0x82, 0xE4, 0xDF, 0x1E, 0x53, 0xBF, 0x31, 0xFE, 0x4B, 0xB6, 0x5A, 0x85, 0x24, 0xED, 0xA8, 0x3F, 0xD2, 0x9D, 0x07, 0xE4, 0x97, 0x47, 0xB7, 0x52, 0x91, 0xCB, 0xC8, 0xF8, 0xEE, 0x14, 0x15, 0xEC, 0x92, 0x1E, 0x19, 0x02, 0x2A, 0xDE, 0x2C, 0x04, 0x7E, 0x4D, 0xF3, 0x50, 0x72, 0x89, 0xE9, 0xD7, 0x9A, 0x8E, 0x69, 0x92, 0xB4, 0x8B, 0x88, 0x64, 0x20, 0x4A, 0x41, 0x6B, 0x76, 0x9C, 0xC7, 0x87, 0xD6, 0xDF, 0x44, 0x07, 0xE9, 0x3D, 0x12, 0x1F, 0x7F, 0xBE, 0xE0, 0xE4, 0x08, 0x96, 0x3E, 0x06, 0x09, 0xA9, 0xC7, 0x5C, 0xB3, 0x11, 0x7C, 0xA5, 0x83, 0xDF, 0x6E, 0x79, 0xF3, 0x1C, 0x63, 0x5B, 0xF0, 0xF1, 0xBE, 0x98, 0xDF, 0x55, 0x07, 0x27, 0xA4, 0x5D, 0x3C, 0xA3, 0x37, 0xD7, 0x9D, 0xE5, 0xDC, 0xDB, 0x0B, 0x91, 0xCA, 0xBB, 0xC3, 0x0D, 0x7E, 0xF0, 0xAE, 0x1C, 0xA1, 0xE9, 0x49, 0x04, 0xF7, 0x8C, 0x1F, 0xD8, 0xFB, 0xA8, 0x75, 0x45, 0xFD, 0xC1, 0x74, 0xAD, 0x81, 0x90, 0xF9, 0xB5, 0xED, 0x7B, 0x58, 0x69, 0x49, 0x4F, 0xFA, 0x91, 0x03, 0x3F, 0xDC, 0x61, 0x17, 0xBF, 0x66, 0x2E, 0xC5, 0xF2, 0xAF, 0x26, 0x34, 0xBA, 0x3F, 0x8C, 0x02, 0x21, 0x0F, 0x1C, 0x9B, 0xCD, 0xDA, 0x9B, 0xB3, 0x97, 0x60, 0xE0, 0x0F, 0x25, 0xA7, 0x27, 0x0C, 0x34, 0x56, 0x66, 0xFB, 0x6D, 0xF8, 0x5C, 0x91, 0x9A, 0xA1, 0x50, 0xCA, 0x7F, 0xC8, 0x0F, 0xC0, 0xEA, 0xCF, 0xE2, 0x42, 0xEF, 0x55, 0xF4, 0x29, 0x80, 0x63, 0x62, 0x8E, 0x61, 0x05, 0x6C, 0x96, 0x6D, 0xB9, 0x96, 0x44, 0x28, 0xD9, 0xCE, 0x99, 0x10, 0x82, 0x71, 0xE2, 0x9A, 0x12, 0x32, 0x8E, 0x23, 0x99, 0x97, 0x34, 0xE0, 0x36, 0xF1, 0x8A, 0x0E, 0xB8, 0xF0, 0x30, 0xE8, 0x80, 0x62, 0xC5, 0x67, 0x17, 0xE7, 0xA3, 0x63, 0x14, 0xE4, 0x4E, 0xCF, 0x35, 0x7F, 0xF5, 0x6E, 0xED, 0xF9, 0x0D, 0x3F, 0xB1, 0x1B, 0x22, 0xA1, 0xB2, 0x59, 0x05, 0xB3, 0x79, 0xFC, 0xCA, 0x5C, 0xA1, 0xAC, 0xB9, 0x56, 0xE1, 0x78, 0xAD, 0x3F, 0x51, 0xD5, 0x35, 0xAD, 0x11, 0x98, 0x13, 0xB1, 0xE7, 0x0F, 0x73, 0x17, 0x65, 0x1B, 0xC7, 0x5C, 0xAC, 0x64, 0x27, 0x6B, 0xB9, 0x81, 0x10, 0xB5, 0x4E, 0xA0, 0xEF, 0x34, 0x54, 0x1D, 0x73, 0x91, 0x07, 0x21, 0xD6, 0x57, 0x38, 0x76, 0x77, 0xE3, 0x32, 0xE9, 0xC8, 0x81, 0x1C, 0x3F, 0xC1, 0xB9, 0x23, 0xB2, 0xEE, 0x9C, 0x51, 0x2F, 0x6D, 0x09, 0xDF, 0x37, 0x2A, 0x5F, 0x97, 0xFA, 0xD7, 0x12, 0x33, 0x89, 0xCE, 0xE1, 0x97, 0xB5, 0xC2, 0x69, 0xE2, 0x21, 0xD7, 0xEE, 0xD3, 0x16, 0x0A, 0x52, 0x1E, 0x56, 0xFF, 0x8A, 0xAF, 0xAB, 0x68, 0x61, 0x79, 0xD0, 0x9D, 0x78, 0xFC, 0x38, 0x7B, 0x3E, 0xA6, 0xA6, 0x72, 0x03, 0x4D, 0x24, 0xAC, 0x79, 0x99, 0xD1, 0x96, 0xB2, 0x31, 0x64, 0x75, 0xF3, 0x7D, 0xB8, 0xE9, 0xED, 0x43, 0x1D, 0xF5, 0x83, 0x41, 0xFA, 0x88, 0x00, 0x3D, 0x3C, 0x64, 0x89, 0xE7, 0x80, 0x53, 0xD8, 0xE4, 0x4C, 0xE7, 0xE1, 0x6A, 0xEF, 0x41, 0x68, 0x59, 0xB3, 0xD2, 0xAE, 0xCE, 0x09, 0x08, 0x6A, 0x74, 0x8B, 0x7B, 0xCF, 0xD1, 0x0F, 0x73, 0xE3, 0xCF, 0x8B, 0x31, 0xF0, 0xCC, 0x44, 0xDA, 0x05, 0x9C, 0x69, 0xAB, 0xA5, 0xBC, 0x8E, 0xFA, 0xD4, 0x5D, 0x3F, 0x37, 0x6A, 0xF3, 0xA0, 0xDE, 0x6E, 0x16, 0x98, 0x78, 0xBD, 0x84, 0x2E, 0x28, 0x79, 0x8E, 0x47, 0x43, 0xF8, 0x43, 0x84, 0x4B, 0xCD, 0xF8, 0x50, 0x6F, 0x13, 0x63, 0x91, 0xEC, 0x8E, 0x72, 0x1D, 0xC2, 0xB6, 0x28, 0x2D, 0x9C, 0x50, 0xFA, 0xB6, 0x53, 0xA6, 0xAB, 0xF2, 0x89, 0x47, 0x42, 0x0E, 0x8C, 0x22, 0xA9, 0xA4, 0x87, 0xD7, 0x6A, 0x93, 0x89, 0x33, 0xB3, 0x4E, 0x49, 0x7D, 0xA9, 0x53, 0x94, 0x17, 0x6B, 0x27, 0x74, 0xC0, 0x9E, 0xF0, 0xBB, 0x1E, 0xD8, 0xC3, 0xB1, 0x31, 0xA2, 0x19, 0x57, 0xB3, 0x1A, 0x0B, 0x47, 0xCB, 0xFB, 0xFF, 0x05, 0x33, 0xCA, 0xF3, 0x31, 0x25, 0x22, 0x1D, 0xB6, 0xBA, 0x4A, 0x51, 0x88, 0x64, 0x89, 0x2C, 0xF2, 0x1D, 0x3D, 0x4D, 0x58, 0xB5, 0x99, 0xA3, 0x7A, 0x08, 0xF3, 0x44, 0xAA, 0x7E, 0xF9, 0x8E, 0x7D, 0x7D, 0x9D, 0x33, 0x16, 0xA6, 0xB1, 0x15, 0xD9, 0xB8, 0xF2, 0x0F, 0x93, 0xBC, 0x68, 0x65, 0x73, 0x46, 0x99, 0xEB, 0x54, 0xC8, 0x88, 0xD7, 0xE5, 0xA0, 0xAC, 0xAF, 0xD1, 0x91, 0x53, 0x52, 0xB2, 0x94, 0x24, 0x37, 0x12, 0xCF, 0xE8, 0x2F, 0x85, 0x24, 0x8B, 0x00, 0x04, 0x5C, 0xF3, 0xD0, 0x90, 0xC0, 0xC0, 0x0D, 0x7C, 0xA0, 0xE3, 0xA1, 0xF1, 0x47, 0x70, 0x3F, 0xD9, 0x4F, 0x71, 0x7E, 0x49, 0xC8, 0x1A, 0x7C, 0x3A, 0x76, 0x94, 0x6E, 0x20, 0xA6, 0x3F, 0x3B, 0x7C, 0x3E, 0xAB, 0xA9, 0x22, 0x5A, 0xBE, 0x0B, 0x34, 0xCB, 0x0C, 0xF2, 0x35, 0x06, 0x39, 0x67, 0xD1, 0x6B, 0xC8, 0xA6, 0x9C, 0x13, 0x0C, 0xCE, 0x28, 0x76, 0x15, 0xCC, 0x05, 0x31, 0x14, 0x16, 0x7E, 0xAC, 0x4E, 0x95, 0xBB, 0xAB, 0xDF, 0xBB, 0xCF, 0x96, 0xBC, 0x0C, 0x0D, 0x65, 0xEA, 0x00, 0x0A, 0xEA, 0xF4, 0x90, 0xD7, 0x23, 0x95, 0x5B, 0xD1, 0xB4, 0xD6, 0x91, 0x54, 0xD2, 0x62, 0xF6, 0xA6, 0xD3, 0x53, 0x4B, 0xB0, 0xBC, 0x39, 0x7C, 0x29, 0xEC, 0xC6, 0xB1, 0x44, 0x7B, 0x75, 0xC9, 0x53, 0xAF, 0x44, 0x1D, 0xE2, 0xE7, 0x13, 0x3A, 0x7A, 0xC9, 0x89, 0x88, 0xA7, 0xEF, 0x9E, 0x6E, 0xE6, 0x35, 0x58, 0xAA, 0xAD, 0xA0, 0x60, 0x3B, 0xD5, 0x29, 0x77, 0x6F, 0x05, 0x55, 0x8D, 0x2D, 0xF5, 0x64, 0x1C, 0x41, 0x2E, 0x73, 0x47, 0x44, 0x0F, 0x65, 0xEB, 0x82, 0x3A, 0xFC, 0x7C, 0xCA, 0xE6, 0xB9, 0x71, 0x08, 0xB8, 0x57, 0x28, 0x7A, 0x04, 0x86, 0xDB, 0xBE, 0x68, 0x9D, 0x77, 0x0C, 0xA9, 0x24, 0x71, 0x30, 0x9E, 0x73, 0xAD, 0x39, 0x0A, 0xBF, 0x56, 0x91, 0x2B, 0x2B, 0x7C, 0x49, 0x24, 0x2C, 0xEC, 0x15, 0x7B, 0xDB, 0xBD, 0x49, 0x35, 0x53, 0x73, 0x5C, 0xB1, 0xD9, 0xB4, 0x0A, 0xFC, 0x21, 0x4D, 0xA1, 0x53, 0x35, 0x9C, 0x9D, 0xF5, 0x76, 0x13, 0x59, 0x01, 0xC2, 0xFD, 0xA5, 0x8C, 0x00, 0x95, 0xB6, 0xFC, 0xE3, 0xFD, 0x07, 0x31, 0xDF, 0x34, 0x86, 0x3A, 0xF2, 0x88, 0x2D, 0x53, 0x77, 0x3C, 0xE7, 0xC1, 0x82, 0x47, 0x37, 0x22, 0xAA, 0x79, 0xA6, 0xB3, 0x7D, 0x3E, 0xDD, 0xDE, 0x38, 0xFA, 0x71, 0xDF, 0x8C, 0x0E, 0xDC, 0x08, 0x1E, 0xFE, 0xD8, 0xCE, 0x60, 0x6E, 0x48, 0x29, 0x91, 0x80, 0xEC, 0x6F, 0xE3, 0x5F, 0xAB, 0x64, 0x99, 0x10, 0xC4, 0x8A, 0x6A, 0x29, 0xF9, 0xD0, 0xF8, 0x55, 0x57, 0xE1, 0x0B, 0xC5, 0xAE, 0x2E, 0xCF, 0x02, 0x8A, 0xE3, 0x99, 0xF5, 0x5C, 0xD7, 0x97, 0x60, 0x28, 0x93, 0x5C, 0xC0, 0x3C, 0x0C, 0xAF, 0xD5, 0x00, 0x3C, 0x9E, 0xAE, 0xD2, 0x47, 0xFB, 0xE3, 0x0A, 0x28, 0x4C, 0xC4, 0x47, 0x0A, 0x55, 0x25, 0xA6, 0x49, 0x8E, 0x1D, 0xBB, 0xD3, 0x08, 0x5C, 0x3F, 0x9D, 0x77, 0xC6, 0x06, 0x4D, 0x01, 0x81, 0xBC, 0x5A, 0x82, 0x95, 0x61, 0x56, 0x0A, 0xA9, 0xA4, 0xEA, 0x81, 0x73, 0xD7, 0x93, 0x7A, 0x94, 0x28, 0x10, 0x9C, 0xB3, 0xA6, 0x6B, 0x2B, 0x3D, 0xE1, 0x1F, 0x88, 0xF5, 0x5A, 0xB2, 0x1E, 0xB4, 0x9B, 0x77, 0xA3, 0x97, 0x62, 0xCA, 0x92, 0x64, 0xE0, 0x15, 0x65, 0x66, 0x76, 0x5E, 0x2D, 0x36, 0x26, 0xB7, 0x2B, 0x80, 0xBD, 0x14, 0x11, 0xE4, 0xEC, 0x53, 0x55, 0x28, 0x28, 0xA2, 0x4B, 0xC8, 0xCD, 0xC4, 0x7F, 0x46, 0x5F, 0xDD, 0xF4, 0x77, 0x2C, 0x7B, 0xC0, 0x20, 0x66, 0x85, 0x40, 0x11, 0x28, 0x7F, 0x73, 0x9A, 0xBA, 0x60, 0x47, 0x59, 0x67, 0x47, 0xF4, 0x23, 0x4A, 0xE2, 0x27, 0xDB, 0xFF, 0xAB, 0xF0, 0xE1, 0x31, 0x53, 0xE2, 0xE0, 0x69, 0xF0, 0xB7, 0x90, 0x25, 0x1B, 0xE8, 0x77, 0xFE, 0x5A, 0x19, 0x8E, 0x80, 0x82, 0x58, 0x63, 0x9F, 0x5E, 0x79, 0xD3, 0xD5, 0xCD, 0x16, 0xF1, 0xA5, 0x73, 0x72, 0x4D, 0xD6, 0xA9, 0xF6, 0x99, 0x0C, 0x45, 0x02, 0x33, 0x4D, 0xC6, 0x6F, 0x65, 0x49, 0x34, 0x90, 0x67, 0x3A, 0xB3, 0x0D, 0xCA, 0x7C, 0x03, 0x1F, 0x0C, 0x21, 0x2C, 0x0D, 0x8B, 0xC9, 0xD0, 0xC8, 0x74, 0xB3, 0x19, 0xA9, 0x7A, 0xD1, 0xCE, 0x93, 0x95, 0xD3, 0xD1, 0x54, 0x20, 0x31, 0x56, 0xC5, 0x1C, 0xC3, 0xB9, 0xCB, 0x13, 0xD0, 0xBA, 0x1B, 0xDF, 0x61, 0x8B, 0xC8, 0xEE, 0xCA, 0x9D, 0xDD, 0x94, 0x12, 0x05, 0x0C, 0xFA, 0x09, 0x23, 0x57, 0x27, 0xAA, 0x50, 0xD4, 0x6F, 0x79, 0xAD, 0x6F, 0x3C, 0x5A, 0x1B, 0xB6, 0xB2, 0x84, 0xC8, 0x31, 0x1D, 0xCF, 0x93, 0x75, 0x68, 0x59, 0x70, 0x4D, 0xF8, 0xFC, 0x3B, 0xB8, 0xD2, 0xF5, 0xE0, 0x94, 0xE0, 0x45, 0x02, 0x35, 0x49, 0x42, 0xE9, 0xC8, 0x52, 0xB2, 0x08, 0xD4, 0x90, 0x18, 0x34, 0x33, 0x2E, 0xBC, 0x60, 0x32, 0x70, 0xCB, 0x57, 0xED, 0x41, 0x8C, 0x34, 0xCE, 0x48, 0xAA, }, .spki_len = 2630, .spki = { 0x30, 0x82, 0x0A, 0x42, 0x30, 0x0F, 0x06, 0x0B, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x02, 0x82, 0x0B, 0x07, 0x08, 0x07, 0x05, 0x00, 0x03, 0x82, 0x0A, 0x2D, 0x00, 0x30, 0x82, 0x0A, 0x28, 0x03, 0x21, 0x00, 0x1C, 0x0E, 0xE1, 0x11, 0x1B, 0x08, 0x00, 0x3F, 0x28, 0xE6, 0x5E, 0x8B, 0x3B, 0xDE, 0xB0, 0x37, 0xCF, 0x8F, 0x22, 0x1D, 0xFC, 0xDA, 0xF5, 0x95, 0x0E, 0xDB, 0x38, 0xD5, 0x06, 0xD8, 0x5B, 0xEF, 0x03, 0x82, 0x0A, 0x01, 0x00, 0x03, 0x23, 0x69, 0xA2, 0xCE, 0x57, 0x2F, 0xD0, 0x8B, 0xFC, 0x30, 0x4B, 0x48, 0x48, 0xE7, 0x8D, 0x75, 0x2D, 0x77, 0xE9, 0x7A, 0x28, 0xB9, 0x9B, 0x9B, 0xB6, 0xFB, 0x5C, 0x7C, 0x63, 0x37, 0x51, 0x4B, 0x32, 0x1E, 0xCD, 0xC1, 0xFB, 0x66, 0x9F, 0x26, 0xD4, 0x17, 0x1A, 0xB4, 0x2B, 0x72, 0x72, 0x0E, 0xE7, 0x0E, 0x05, 0x19, 0xA6, 0xE1, 0xD3, 0xD6, 0xD9, 0x91, 0x4E, 0xC1, 0xB2, 0x1C, 0xDE, 0x38, 0xB4, 0x1A, 0xAC, 0x1D, 0x3A, 0xBE, 0xE6, 0xF2, 0xB7, 0x49, 0x5C, 0x4C, 0x82, 0x0C, 0x1F, 0xC0, 0xCC, 0x9E, 0x71, 0xE2, 0x4C, 0xFB, 0x5C, 0x9C, 0x0D, 0x8E, 0xEF, 0x42, 0x64, 0xAF, 0x48, 0x4F, 0xAE, 0x4D, 0x6E, 0x5D, 0xDE, 0x65, 0xD4, 0xDF, 0x72, 0xB6, 0x1C, 0x6D, 0xBD, 0x26, 0xF8, 0x61, 0xA5, 0xE0, 0xB8, 0x53, 0xAC, 0x54, 0x13, 0x22, 0x6F, 0xEB, 0xBA, 0xBA, 0x5E, 0xB4, 0x74, 0xC6, 0xFB, 0x25, 0xA8, 0x26, 0x78, 0xEA, 0x16, 0x06, 0xB4, 0x52, 0xA2, 0x31, 0x12, 0x22, 0x10, 0x17, 0xB8, 0xC0, 0x73, 0xC1, 0x03, 0x78, 0xF9, 0x14, 0x56, 0x41, 0xA8, 0xC0, 0x78, 0xC0, 0xED, 0x9E, 0x42, 0x16, 0x50, 0xF7, 0x48, 0x89, 0x25, 0x22, 0xAB, 0x9F, 0xB7, 0xD1, 0xFF, 0x8C, 0xF1, 0xCC, 0x71, 0xB8, 0x56, 0x6E, 0x8D, 0xA3, 0x3C, 0xD7, 0x36, 0x17, 0x70, 0xC0, 0x44, 0x34, 0x9A, 0xC4, 0x40, 0xCC, 0xCD, 0xC6, 0xBB, 0xE3, 0x5E, 0x6C, 0x55, 0x78, 0x27, 0x66, 0xF3, 0x8E, 0x68, 0x8B, 0xF4, 0x78, 0x21, 0x03, 0x72, 0x99, 0xE3, 0x44, 0xEC, 0xDE, 0xCA, 0x17, 0xAD, 0x5D, 0x15, 0xCD, 0x27, 0xA4, 0xF7, 0xB0, 0x70, 0x66, 0x11, 0x38, 0xED, 0xE8, 0xED, 0x72, 0xA8, 0x95, 0x9C, 0x5A, 0xE3, 0x6B, 0x1C, 0x46, 0x09, 0x4A, 0x53, 0xCB, 0x21, 0xA7, 0xA4, 0x26, 0x73, 0xF1, 0x40, 0x1C, 0x2B, 0x25, 0x94, 0x94, 0x09, 0x0E, 0x2F, 0x53, 0xD7, 0xEE, 0x70, 0x63, 0x43, 0x1E, 0xE5, 0x85, 0x80, 0x02, 0xD8, 0x50, 0xAF, 0x90, 0x9C, 0x37, 0x83, 0x43, 0x60, 0x10, 0xF7, 0xEA, 0x88, 0x62, 0x5A, 0x36, 0xA0, 0xF0, 0x18, 0x9F, 0xDE, 0x75, 0xB7, 0xE8, 0xC7, 0xE4, 0xB1, 0x9D, 0x85, 0x27, 0x00, 0x83, 0x28, 0xAD, 0xBC, 0x92, 0x9B, 0xBC, 0x86, 0xE9, 0x64, 0xCF, 0xC4, 0x8B, 0x8C, 0xF1, 0xDA, 0x5D, 0x7E, 0xD3, 0x33, 0x3A, 0xB5, 0x5C, 0x15, 0x07, 0x28, 0x32, 0x21, 0x4A, 0x77, 0x9A, 0x5F, 0xD1, 0x0C, 0xC0, 0x40, 0x05, 0xF4, 0x6C, 0x1A, 0xA8, 0x88, 0x4A, 0x16, 0x19, 0x92, 0x47, 0x2F, 0xD5, 0x35, 0xB9, 0x5E, 0xD1, 0x8B, 0xDE, 0x1C, 0x6D, 0x8C, 0xE6, 0x78, 0xD2, 0x81, 0x7D, 0x69, 0xF9, 0x05, 0x71, 0x10, 0x3E, 0x85, 0x20, 0xE7, 0x31, 0x3C, 0xE7, 0xB9, 0x30, 0xC5, 0xEB, 0xFA, 0xF2, 0xF4, 0xEC, 0x75, 0x8B, 0x62, 0x6B, 0x55, 0x43, 0xA0, 0x68, 0xCD, 0xE0, 0xFD, 0x0E, 0x94, 0xE6, 0xA6, 0x44, 0x75, 0xB2, 0x32, 0x68, 0xBF, 0x03, 0x80, 0xD0, 0x75, 0x50, 0x8F, 0x85, 0x12, 0x8C, 0xA2, 0x6F, 0x31, 0xA9, 0x0C, 0x4A, 0x7D, 0x28, 0x44, 0x0D, 0x54, 0xD4, 0x06, 0x6B, 0x40, 0x45, 0x88, 0x58, 0x8B, 0x4C, 0xCF, 0x85, 0x0B, 0x97, 0x5C, 0x73, 0xAF, 0xE6, 0x8C, 0xBC, 0xD1, 0x02, 0x75, 0x5F, 0x61, 0xEB, 0x3E, 0x60, 0x32, 0x3C, 0x57, 0x6E, 0x52, 0x9E, 0xC0, 0xBF, 0x23, 0xBF, 0xA5, 0xBE, 0xA3, 0x9C, 0xB7, 0x3C, 0x37, 0xE8, 0x39, 0x5D, 0x8D, 0xBD, 0x4C, 0x8D, 0xC8, 0xAB, 0x2F, 0x70, 0xA0, 0xBF, 0xC3, 0xA7, 0x8C, 0x0D, 0x41, 0x3F, 0x08, 0xD1, 0x4D, 0x63, 0x2B, 0xC0, 0x40, 0x3B, 0x03, 0x83, 0xDB, 0xBB, 0x22, 0xBD, 0x9B, 0x11, 0x3C, 0x89, 0x45, 0x2A, 0xEA, 0xB1, 0x12, 0x10, 0x09, 0x79, 0x47, 0xFE, 0xAA, 0xA3, 0xC9, 0xF0, 0x5D, 0x1D, 0x30, 0x0C, 0x33, 0xA5, 0x5E, 0x3F, 0xBC, 0x81, 0x25, 0x9E, 0x86, 0x27, 0x05, 0xC3, 0xA1, 0x3B, 0x9E, 0xE3, 0x5F, 0x6B, 0x23, 0xED, 0x10, 0xF4, 0xED, 0xEA, 0x95, 0x19, 0xFA, 0x91, 0xB7, 0xBC, 0xD0, 0xD5, 0x01, 0xB5, 0xED, 0x57, 0xD9, 0x04, 0x9F, 0xAB, 0x91, 0xAA, 0x77, 0x9C, 0x72, 0x5F, 0xF8, 0xE9, 0xF7, 0x80, 0x17, 0xEA, 0x78, 0x07, 0xFA, 0x25, 0x4B, 0x71, 0x05, 0xE8, 0x26, 0xD0, 0x96, 0xC0, 0x1A, 0xDA, 0xE2, 0xC5, 0xD1, 0x38, 0x25, 0x1A, 0x92, 0xA4, 0x78, 0xA3, 0x33, 0x73, 0xF4, 0xDE, 0x91, 0x2B, 0x83, 0xB6, 0xFB, 0x4B, 0x0D, 0x0D, 0xE6, 0xBC, 0x11, 0x18, 0xBB, 0x2F, 0xCF, 0xB0, 0x7B, 0xD2, 0x27, 0xA5, 0xF7, 0xF9, 0x91, 0x43, 0x9A, 0x13, 0xDE, 0x12, 0x38, 0x18, 0x0C, 0xDC, 0x55, 0x11, 0x9E, 0x65, 0xC4, 0x18, 0x58, 0x4D, 0x80, 0x7A, 0x92, 0x6E, 0x4A, 0x9C, 0x0F, 0x70, 0x15, 0x5E, 0xE1, 0x96, 0xFB, 0x07, 0x65, 0x6D, 0x9A, 0xA7, 0x98, 0x2B, 0x87, 0x95, 0xDB, 0xAD, 0x43, 0xD1, 0x05, 0x9C, 0xA7, 0xF5, 0x80, 0xD3, 0x32, 0x0C, 0x04, 0x38, 0xA5, 0xED, 0x5A, 0x70, 0x32, 0xB2, 0xE9, 0x59, 0x67, 0x84, 0x10, 0xF1, 0x1A, 0xD9, 0x8B, 0xE8, 0x82, 0x6A, 0x44, 0x26, 0x26, 0x15, 0x64, 0x5D, 0x75, 0x9A, 0x86, 0x2B, 0x2A, 0xC5, 0x2D, 0x3B, 0x01, 0x4A, 0x25, 0xE8, 0x47, 0x3F, 0x1F, 0x1E, 0xA4, 0xCF, 0xA8, 0x19, 0x93, 0x0A, 0xB3, 0xA3, 0x4D, 0x71, 0x0D, 0xEE, 0xE7, 0x0C, 0xA1, 0x3E, 0x88, 0xFD, 0x71, 0xAA, 0x06, 0x4E, 0x6C, 0xB4, 0x69, 0x7D, 0xE0, 0xE4, 0x63, 0xB1, 0x37, 0x0A, 0x6A, 0x3B, 0xFE, 0x98, 0xFD, 0xFE, 0x7B, 0x54, 0x71, 0xFF, 0x8D, 0xF6, 0xA6, 0x87, 0x9F, 0xBE, 0xF9, 0xAF, 0xB3, 0x51, 0x9D, 0x78, 0x07, 0x57, 0xD6, 0x74, 0x40, 0xAC, 0x36, 0xE8, 0x37, 0xBA, 0xC3, 0x83, 0x3E, 0xEA, 0xA9, 0x80, 0xBD, 0x82, 0xB7, 0x93, 0x64, 0x36, 0xA0, 0x30, 0x7D, 0x16, 0x4B, 0x64, 0x38, 0x86, 0x9A, 0xE6, 0x06, 0xE9, 0x80, 0x51, 0x8E, 0x91, 0x3D, 0x0E, 0xE3, 0x02, 0x39, 0x6E, 0xF4, 0xEB, 0x25, 0xD9, 0x86, 0x6E, 0x4B, 0xAF, 0xA1, 0x01, 0xE5, 0x99, 0x29, 0x31, 0x36, 0x1C, 0x4A, 0x98, 0x22, 0x53, 0xD5, 0x8A, 0xBE, 0x3B, 0xD5, 0x71, 0x07, 0x63, 0x5A, 0x46, 0xF0, 0x95, 0x12, 0x08, 0x5F, 0x4A, 0xDA, 0x08, 0xEC, 0x8B, 0x1B, 0x39, 0x10, 0xB0, 0x15, 0x3B, 0x2A, 0xAF, 0xCA, 0xE5, 0x03, 0x3E, 0xDD, 0x41, 0x53, 0x24, 0x8D, 0xCD, 0x85, 0xB0, 0x2C, 0x9A, 0x25, 0xD8, 0xBD, 0xC4, 0x06, 0x8B, 0xB8, 0x57, 0x41, 0x72, 0x62, 0x97, 0xA2, 0x5A, 0xEC, 0x55, 0xC4, 0x4A, 0xA2, 0x80, 0x59, 0xB7, 0x1B, 0xB9, 0xF3, 0x40, 0x67, 0x88, 0x7A, 0xDE, 0x4C, 0x1C, 0xA4, 0x90, 0x8B, 0x19, 0xB3, 0xD7, 0x81, 0x23, 0x45, 0x38, 0x76, 0xDB, 0x4D, 0xCE, 0xB4, 0x27, 0x73, 0x06, 0x95, 0x72, 0xCD, 0x87, 0x77, 0xE6, 0x2C, 0xFB, 0xAF, 0x72, 0x03, 0xF0, 0x20, 0xF2, 0x81, 0xA6, 0x67, 0x8F, 0x79, 0x07, 0x20, 0xEA, 0xA2, 0x0E, 0x34, 0x32, 0x7D, 0x7A, 0x63, 0x68, 0x8B, 0x09, 0xA0, 0x1F, 0x4D, 0x70, 0x88, 0xF7, 0xB5, 0x05, 0x9E, 0xDD, 0xEB, 0x45, 0xC0, 0xCE, 0x39, 0x32, 0x1C, 0x79, 0x52, 0x1D, 0x79, 0xA5, 0x9E, 0xCD, 0xD4, 0x68, 0xCE, 0xD0, 0xEA, 0x82, 0xCA, 0x48, 0x49, 0x28, 0x70, 0x2F, 0x57, 0xD6, 0xFC, 0x18, 0xD3, 0x47, 0xAF, 0x3E, 0xD2, 0x2A, 0xAF, 0x45, 0xAB, 0xB0, 0xF2, 0x0B, 0xAB, 0x9E, 0x01, 0x55, 0x76, 0x07, 0xAE, 0x3E, 0xD9, 0xCF, 0x0E, 0x26, 0xD3, 0x4D, 0x30, 0x54, 0x49, 0x66, 0x9E, 0xC6, 0xFC, 0x1B, 0xEC, 0xEA, 0xDC, 0xE1, 0x83, 0xF7, 0xA5, 0x94, 0xCE, 0xA1, 0x96, 0xD0, 0x59, 0xA1, 0xE5, 0x50, 0xE5, 0x47, 0x86, 0x6C, 0xC0, 0x87, 0x33, 0x3F, 0x03, 0x0E, 0x62, 0x8F, 0x2C, 0xF1, 0x14, 0x79, 0x25, 0x41, 0x0E, 0xD0, 0x42, 0x1D, 0xC7, 0x50, 0x61, 0x38, 0xB1, 0xD1, 0x90, 0x99, 0xC6, 0x95, 0xE1, 0xAF, 0xDA, 0xCE, 0x41, 0x53, 0x82, 0x5B, 0x66, 0xA8, 0xEC, 0xF5, 0x5A, 0x02, 0x1D, 0x21, 0xEB, 0x9F, 0x84, 0x8F, 0xE5, 0x5C, 0x21, 0x76, 0x9A, 0x75, 0x5F, 0xA9, 0x80, 0x7E, 0xF7, 0x3A, 0x6C, 0x5B, 0xA1, 0x5A, 0x06, 0x34, 0x7D, 0x3F, 0x1C, 0x5C, 0x61, 0x9A, 0x31, 0x55, 0x98, 0x62, 0x91, 0x06, 0xAC, 0x0B, 0x86, 0xAE, 0x0D, 0x8E, 0x55, 0x57, 0x82, 0x92, 0x51, 0x72, 0x58, 0xAE, 0x85, 0xF7, 0x2E, 0x73, 0x7A, 0xF5, 0x63, 0x8D, 0x09, 0x6B, 0x76, 0xA3, 0xC5, 0x7F, 0x1B, 0x9C, 0x80, 0xE7, 0x70, 0xA2, 0xD4, 0xEA, 0x4E, 0x42, 0xFE, 0x46, 0x9A, 0xD4, 0x21, 0x28, 0x52, 0x41, 0x96, 0x0A, 0x8A, 0x86, 0x35, 0x5E, 0xF2, 0x2F, 0x58, 0x3F, 0xE3, 0xBA, 0xCA, 0xDF, 0x8D, 0xA3, 0x1D, 0x5C, 0x2D, 0xE2, 0x54, 0x16, 0x1B, 0xC6, 0xD1, 0x0F, 0x98, 0x41, 0xDD, 0x27, 0xED, 0x46, 0x2A, 0x6B, 0x94, 0xB6, 0xDE, 0xEA, 0x90, 0xCB, 0xAB, 0x68, 0x7F, 0xB8, 0x4B, 0x56, 0x39, 0x5D, 0xA7, 0x63, 0xAB, 0x4B, 0x7F, 0xE3, 0x09, 0x5D, 0x57, 0x2D, 0x77, 0xEF, 0xF3, 0xFF, 0x0D, 0x8F, 0x9D, 0x19, 0xAA, 0x5A, 0xF7, 0xB6, 0x76, 0x05, 0x3D, 0xBE, 0xF6, 0x4E, 0x61, 0xDD, 0x0A, 0x41, 0xD4, 0x02, 0x31, 0x8E, 0x33, 0x08, 0x66, 0x91, 0x06, 0x25, 0x9B, 0xF7, 0xA4, 0xCE, 0x31, 0xB3, 0x46, 0xA9, 0xE9, 0x83, 0xED, 0xAB, 0xA0, 0x51, 0x80, 0x14, 0x9A, 0xB0, 0x57, 0xF9, 0x97, 0x29, 0x77, 0xDA, 0x7C, 0x6F, 0x46, 0xE0, 0xCD, 0xF8, 0x6F, 0x30, 0x91, 0xF0, 0x4F, 0xD4, 0xE8, 0x3C, 0x60, 0x22, 0xE1, 0x8C, 0xE4, 0x38, 0x2B, 0x54, 0xD5, 0xDA, 0xBA, 0x82, 0xE4, 0xDF, 0x1E, 0x53, 0xBF, 0x31, 0xFE, 0x4B, 0xB6, 0x5A, 0x85, 0x24, 0xED, 0xA8, 0x3F, 0xD2, 0x9D, 0x07, 0xE4, 0x97, 0x47, 0xB7, 0x52, 0x91, 0xCB, 0xC8, 0xF8, 0xEE, 0x14, 0x15, 0xEC, 0x92, 0x1E, 0x19, 0x02, 0x2A, 0xDE, 0x2C, 0x04, 0x7E, 0x4D, 0xF3, 0x50, 0x72, 0x89, 0xE9, 0xD7, 0x9A, 0x8E, 0x69, 0x92, 0xB4, 0x8B, 0x88, 0x64, 0x20, 0x4A, 0x41, 0x6B, 0x76, 0x9C, 0xC7, 0x87, 0xD6, 0xDF, 0x44, 0x07, 0xE9, 0x3D, 0x12, 0x1F, 0x7F, 0xBE, 0xE0, 0xE4, 0x08, 0x96, 0x3E, 0x06, 0x09, 0xA9, 0xC7, 0x5C, 0xB3, 0x11, 0x7C, 0xA5, 0x83, 0xDF, 0x6E, 0x79, 0xF3, 0x1C, 0x63, 0x5B, 0xF0, 0xF1, 0xBE, 0x98, 0xDF, 0x55, 0x07, 0x27, 0xA4, 0x5D, 0x3C, 0xA3, 0x37, 0xD7, 0x9D, 0xE5, 0xDC, 0xDB, 0x0B, 0x91, 0xCA, 0xBB, 0xC3, 0x0D, 0x7E, 0xF0, 0xAE, 0x1C, 0xA1, 0xE9, 0x49, 0x04, 0xF7, 0x8C, 0x1F, 0xD8, 0xFB, 0xA8, 0x75, 0x45, 0xFD, 0xC1, 0x74, 0xAD, 0x81, 0x90, 0xF9, 0xB5, 0xED, 0x7B, 0x58, 0x69, 0x49, 0x4F, 0xFA, 0x91, 0x03, 0x3F, 0xDC, 0x61, 0x17, 0xBF, 0x66, 0x2E, 0xC5, 0xF2, 0xAF, 0x26, 0x34, 0xBA, 0x3F, 0x8C, 0x02, 0x21, 0x0F, 0x1C, 0x9B, 0xCD, 0xDA, 0x9B, 0xB3, 0x97, 0x60, 0xE0, 0x0F, 0x25, 0xA7, 0x27, 0x0C, 0x34, 0x56, 0x66, 0xFB, 0x6D, 0xF8, 0x5C, 0x91, 0x9A, 0xA1, 0x50, 0xCA, 0x7F, 0xC8, 0x0F, 0xC0, 0xEA, 0xCF, 0xE2, 0x42, 0xEF, 0x55, 0xF4, 0x29, 0x80, 0x63, 0x62, 0x8E, 0x61, 0x05, 0x6C, 0x96, 0x6D, 0xB9, 0x96, 0x44, 0x28, 0xD9, 0xCE, 0x99, 0x10, 0x82, 0x71, 0xE2, 0x9A, 0x12, 0x32, 0x8E, 0x23, 0x99, 0x97, 0x34, 0xE0, 0x36, 0xF1, 0x8A, 0x0E, 0xB8, 0xF0, 0x30, 0xE8, 0x80, 0x62, 0xC5, 0x67, 0x17, 0xE7, 0xA3, 0x63, 0x14, 0xE4, 0x4E, 0xCF, 0x35, 0x7F, 0xF5, 0x6E, 0xED, 0xF9, 0x0D, 0x3F, 0xB1, 0x1B, 0x22, 0xA1, 0xB2, 0x59, 0x05, 0xB3, 0x79, 0xFC, 0xCA, 0x5C, 0xA1, 0xAC, 0xB9, 0x56, 0xE1, 0x78, 0xAD, 0x3F, 0x51, 0xD5, 0x35, 0xAD, 0x11, 0x98, 0x13, 0xB1, 0xE7, 0x0F, 0x73, 0x17, 0x65, 0x1B, 0xC7, 0x5C, 0xAC, 0x64, 0x27, 0x6B, 0xB9, 0x81, 0x10, 0xB5, 0x4E, 0xA0, 0xEF, 0x34, 0x54, 0x1D, 0x73, 0x91, 0x07, 0x21, 0xD6, 0x57, 0x38, 0x76, 0x77, 0xE3, 0x32, 0xE9, 0xC8, 0x81, 0x1C, 0x3F, 0xC1, 0xB9, 0x23, 0xB2, 0xEE, 0x9C, 0x51, 0x2F, 0x6D, 0x09, 0xDF, 0x37, 0x2A, 0x5F, 0x97, 0xFA, 0xD7, 0x12, 0x33, 0x89, 0xCE, 0xE1, 0x97, 0xB5, 0xC2, 0x69, 0xE2, 0x21, 0xD7, 0xEE, 0xD3, 0x16, 0x0A, 0x52, 0x1E, 0x56, 0xFF, 0x8A, 0xAF, 0xAB, 0x68, 0x61, 0x79, 0xD0, 0x9D, 0x78, 0xFC, 0x38, 0x7B, 0x3E, 0xA6, 0xA6, 0x72, 0x03, 0x4D, 0x24, 0xAC, 0x79, 0x99, 0xD1, 0x96, 0xB2, 0x31, 0x64, 0x75, 0xF3, 0x7D, 0xB8, 0xE9, 0xED, 0x43, 0x1D, 0xF5, 0x83, 0x41, 0xFA, 0x88, 0x00, 0x3D, 0x3C, 0x64, 0x89, 0xE7, 0x80, 0x53, 0xD8, 0xE4, 0x4C, 0xE7, 0xE1, 0x6A, 0xEF, 0x41, 0x68, 0x59, 0xB3, 0xD2, 0xAE, 0xCE, 0x09, 0x08, 0x6A, 0x74, 0x8B, 0x7B, 0xCF, 0xD1, 0x0F, 0x73, 0xE3, 0xCF, 0x8B, 0x31, 0xF0, 0xCC, 0x44, 0xDA, 0x05, 0x9C, 0x69, 0xAB, 0xA5, 0xBC, 0x8E, 0xFA, 0xD4, 0x5D, 0x3F, 0x37, 0x6A, 0xF3, 0xA0, 0xDE, 0x6E, 0x16, 0x98, 0x78, 0xBD, 0x84, 0x2E, 0x28, 0x79, 0x8E, 0x47, 0x43, 0xF8, 0x43, 0x84, 0x4B, 0xCD, 0xF8, 0x50, 0x6F, 0x13, 0x63, 0x91, 0xEC, 0x8E, 0x72, 0x1D, 0xC2, 0xB6, 0x28, 0x2D, 0x9C, 0x50, 0xFA, 0xB6, 0x53, 0xA6, 0xAB, 0xF2, 0x89, 0x47, 0x42, 0x0E, 0x8C, 0x22, 0xA9, 0xA4, 0x87, 0xD7, 0x6A, 0x93, 0x89, 0x33, 0xB3, 0x4E, 0x49, 0x7D, 0xA9, 0x53, 0x94, 0x17, 0x6B, 0x27, 0x74, 0xC0, 0x9E, 0xF0, 0xBB, 0x1E, 0xD8, 0xC3, 0xB1, 0x31, 0xA2, 0x19, 0x57, 0xB3, 0x1A, 0x0B, 0x47, 0xCB, 0xFB, 0xFF, 0x05, 0x33, 0xCA, 0xF3, 0x31, 0x25, 0x22, 0x1D, 0xB6, 0xBA, 0x4A, 0x51, 0x88, 0x64, 0x89, 0x2C, 0xF2, 0x1D, 0x3D, 0x4D, 0x58, 0xB5, 0x99, 0xA3, 0x7A, 0x08, 0xF3, 0x44, 0xAA, 0x7E, 0xF9, 0x8E, 0x7D, 0x7D, 0x9D, 0x33, 0x16, 0xA6, 0xB1, 0x15, 0xD9, 0xB8, 0xF2, 0x0F, 0x93, 0xBC, 0x68, 0x65, 0x73, 0x46, 0x99, 0xEB, 0x54, 0xC8, 0x88, 0xD7, 0xE5, 0xA0, 0xAC, 0xAF, 0xD1, 0x91, 0x53, 0x52, 0xB2, 0x94, 0x24, 0x37, 0x12, 0xCF, 0xE8, 0x2F, 0x85, 0x24, 0x8B, 0x00, 0x04, 0x5C, 0xF3, 0xD0, 0x90, 0xC0, 0xC0, 0x0D, 0x7C, 0xA0, 0xE3, 0xA1, 0xF1, 0x47, 0x70, 0x3F, 0xD9, 0x4F, 0x71, 0x7E, 0x49, 0xC8, 0x1A, 0x7C, 0x3A, 0x76, 0x94, 0x6E, 0x20, 0xA6, 0x3F, 0x3B, 0x7C, 0x3E, 0xAB, 0xA9, 0x22, 0x5A, 0xBE, 0x0B, 0x34, 0xCB, 0x0C, 0xF2, 0x35, 0x06, 0x39, 0x67, 0xD1, 0x6B, 0xC8, 0xA6, 0x9C, 0x13, 0x0C, 0xCE, 0x28, 0x76, 0x15, 0xCC, 0x05, 0x31, 0x14, 0x16, 0x7E, 0xAC, 0x4E, 0x95, 0xBB, 0xAB, 0xDF, 0xBB, 0xCF, 0x96, 0xBC, 0x0C, 0x0D, 0x65, 0xEA, 0x00, 0x0A, 0xEA, 0xF4, 0x90, 0xD7, 0x23, 0x95, 0x5B, 0xD1, 0xB4, 0xD6, 0x91, 0x54, 0xD2, 0x62, 0xF6, 0xA6, 0xD3, 0x53, 0x4B, 0xB0, 0xBC, 0x39, 0x7C, 0x29, 0xEC, 0xC6, 0xB1, 0x44, 0x7B, 0x75, 0xC9, 0x53, 0xAF, 0x44, 0x1D, 0xE2, 0xE7, 0x13, 0x3A, 0x7A, 0xC9, 0x89, 0x88, 0xA7, 0xEF, 0x9E, 0x6E, 0xE6, 0x35, 0x58, 0xAA, 0xAD, 0xA0, 0x60, 0x3B, 0xD5, 0x29, 0x77, 0x6F, 0x05, 0x55, 0x8D, 0x2D, 0xF5, 0x64, 0x1C, 0x41, 0x2E, 0x73, 0x47, 0x44, 0x0F, 0x65, 0xEB, 0x82, 0x3A, 0xFC, 0x7C, 0xCA, 0xE6, 0xB9, 0x71, 0x08, 0xB8, 0x57, 0x28, 0x7A, 0x04, 0x86, 0xDB, 0xBE, 0x68, 0x9D, 0x77, 0x0C, 0xA9, 0x24, 0x71, 0x30, 0x9E, 0x73, 0xAD, 0x39, 0x0A, 0xBF, 0x56, 0x91, 0x2B, 0x2B, 0x7C, 0x49, 0x24, 0x2C, 0xEC, 0x15, 0x7B, 0xDB, 0xBD, 0x49, 0x35, 0x53, 0x73, 0x5C, 0xB1, 0xD9, 0xB4, 0x0A, 0xFC, 0x21, 0x4D, 0xA1, 0x53, 0x35, 0x9C, 0x9D, 0xF5, 0x76, 0x13, 0x59, 0x01, 0xC2, 0xFD, 0xA5, 0x8C, 0x00, 0x95, 0xB6, 0xFC, 0xE3, 0xFD, 0x07, 0x31, 0xDF, 0x34, 0x86, 0x3A, 0xF2, 0x88, 0x2D, 0x53, 0x77, 0x3C, 0xE7, 0xC1, 0x82, 0x47, 0x37, 0x22, 0xAA, 0x79, 0xA6, 0xB3, 0x7D, 0x3E, 0xDD, 0xDE, 0x38, 0xFA, 0x71, 0xDF, 0x8C, 0x0E, 0xDC, 0x08, 0x1E, 0xFE, 0xD8, 0xCE, 0x60, 0x6E, 0x48, 0x29, 0x91, 0x80, 0xEC, 0x6F, 0xE3, 0x5F, 0xAB, 0x64, 0x99, 0x10, 0xC4, 0x8A, 0x6A, 0x29, 0xF9, 0xD0, 0xF8, 0x55, 0x57, 0xE1, 0x0B, 0xC5, 0xAE, 0x2E, 0xCF, 0x02, 0x8A, 0xE3, 0x99, 0xF5, 0x5C, 0xD7, 0x97, 0x60, 0x28, 0x93, 0x5C, 0xC0, 0x3C, 0x0C, 0xAF, 0xD5, 0x00, 0x3C, 0x9E, 0xAE, 0xD2, 0x47, 0xFB, 0xE3, 0x0A, 0x28, 0x4C, 0xC4, 0x47, 0x0A, 0x55, 0x25, 0xA6, 0x49, 0x8E, 0x1D, 0xBB, 0xD3, 0x08, 0x5C, 0x3F, 0x9D, 0x77, 0xC6, 0x06, 0x4D, 0x01, 0x81, 0xBC, 0x5A, 0x82, 0x95, 0x61, 0x56, 0x0A, 0xA9, 0xA4, 0xEA, 0x81, 0x73, 0xD7, 0x93, 0x7A, 0x94, 0x28, 0x10, 0x9C, 0xB3, 0xA6, 0x6B, 0x2B, 0x3D, 0xE1, 0x1F, 0x88, 0xF5, 0x5A, 0xB2, 0x1E, 0xB4, 0x9B, 0x77, 0xA3, 0x97, 0x62, 0xCA, 0x92, 0x64, 0xE0, 0x15, 0x65, 0x66, 0x76, 0x5E, 0x2D, 0x36, 0x26, 0xB7, 0x2B, 0x80, 0xBD, 0x14, 0x11, 0xE4, 0xEC, 0x53, 0x55, 0x28, 0x28, 0xA2, 0x4B, 0xC8, 0xCD, 0xC4, 0x7F, 0x46, 0x5F, 0xDD, 0xF4, 0x77, 0x2C, 0x7B, 0xC0, 0x20, 0x66, 0x85, 0x40, 0x11, 0x28, 0x7F, 0x73, 0x9A, 0xBA, 0x60, 0x47, 0x59, 0x67, 0x47, 0xF4, 0x23, 0x4A, 0xE2, 0x27, 0xDB, 0xFF, 0xAB, 0xF0, 0xE1, 0x31, 0x53, 0xE2, 0xE0, 0x69, 0xF0, 0xB7, 0x90, 0x25, 0x1B, 0xE8, 0x77, 0xFE, 0x5A, 0x19, 0x8E, 0x80, 0x82, 0x58, 0x63, 0x9F, 0x5E, 0x79, 0xD3, 0xD5, 0xCD, 0x16, 0xF1, 0xA5, 0x73, 0x72, 0x4D, 0xD6, 0xA9, 0xF6, 0x99, 0x0C, 0x45, 0x02, 0x33, 0x4D, 0xC6, 0x6F, 0x65, 0x49, 0x34, 0x90, 0x67, 0x3A, 0xB3, 0x0D, 0xCA, 0x7C, 0x03, 0x1F, 0x0C, 0x21, 0x2C, 0x0D, 0x8B, 0xC9, 0xD0, 0xC8, 0x74, 0xB3, 0x19, 0xA9, 0x7A, 0xD1, 0xCE, 0x93, 0x95, 0xD3, 0xD1, 0x54, 0x20, 0x31, 0x56, 0xC5, 0x1C, 0xC3, 0xB9, 0xCB, 0x13, 0xD0, 0xBA, 0x1B, 0xDF, 0x61, 0x8B, 0xC8, 0xEE, 0xCA, 0x9D, 0xDD, 0x94, 0x12, 0x05, 0x0C, 0xFA, 0x09, 0x23, 0x57, 0x27, 0xAA, 0x50, 0xD4, 0x6F, 0x79, 0xAD, 0x6F, 0x3C, 0x5A, 0x1B, 0xB6, 0xB2, 0x84, 0xC8, 0x31, 0x1D, 0xCF, 0x93, 0x75, 0x68, 0x59, 0x70, 0x4D, 0xF8, 0xFC, 0x3B, 0xB8, 0xD2, 0xF5, 0xE0, 0x94, 0xE0, 0x45, 0x02, 0x35, 0x49, 0x42, 0xE9, 0xC8, 0x52, 0xB2, 0x08, 0xD4, 0x90, 0x18, 0x34, 0x33, 0x2E, 0xBC, 0x60, 0x32, 0x70, 0xCB, 0x57, 0xED, 0x41, 0x8C, 0x34, 0xCE, 0x48, 0xAA, }, .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 = 4595, .sig = { 0xBB, 0xF8, 0x5F, 0xFD, 0x0E, 0x01, 0xC8, 0x0C, 0x8C, 0x1C, 0x19, 0x31, 0xCD, 0x64, 0x0B, 0xF2, 0x73, 0xD4, 0x96, 0x93, 0xC4, 0xC4, 0xBF, 0xF5, 0xDD, 0x20, 0xD9, 0x4C, 0xF3, 0x75, 0x7A, 0xBD, 0x45, 0x47, 0x3B, 0x9D, 0x01, 0xB1, 0x87, 0x13, 0x05, 0xDA, 0x90, 0xED, 0xC6, 0x70, 0x7D, 0x54, 0x17, 0x12, 0x94, 0x67, 0xF6, 0x1F, 0x72, 0x39, 0x50, 0xC1, 0xAE, 0xDF, 0x70, 0x55, 0xEC, 0x1D, 0x47, 0x77, 0xAD, 0x88, 0x08, 0xE8, 0xB3, 0x47, 0xD1, 0xD0, 0x92, 0x1E, 0xBA, 0xB8, 0x90, 0xCC, 0xA8, 0xE3, 0xA0, 0xDF, 0xD3, 0x00, 0x3D, 0xE9, 0xF9, 0xCB, 0x4A, 0x97, 0xD8, 0x84, 0xE1, 0xDD, 0x04, 0x2C, 0x95, 0x8B, 0x81, 0x6F, 0x72, 0x37, 0x03, 0x2B, 0x20, 0xF8, 0x39, 0x9A, 0x51, 0x82, 0xF4, 0x65, 0x25, 0xEC, 0x35, 0x7D, 0x2F, 0x03, 0x43, 0x74, 0x03, 0xE0, 0xCB, 0x5D, 0xCA, 0x4A, 0x13, 0xFD, 0x2F, 0x1B, 0x09, 0x20, 0x5B, 0x98, 0x90, 0xF0, 0x2E, 0xE5, 0xAF, 0x54, 0x29, 0x43, 0xE6, 0xF9, 0x37, 0x5E, 0xD0, 0x8A, 0x38, 0x53, 0x30, 0x42, 0xD6, 0xBB, 0xD5, 0x0F, 0x37, 0x25, 0x1B, 0x15, 0x90, 0xF6, 0x3B, 0x4B, 0x58, 0xA7, 0xD1, 0xE1, 0xF3, 0x1C, 0xE6, 0x2E, 0x3D, 0x2A, 0xA9, 0x1E, 0x1C, 0x76, 0x7B, 0x9C, 0x3F, 0x5C, 0xB2, 0x68, 0x23, 0xF9, 0x7A, 0xD1, 0xD9, 0xFF, 0xAB, 0x28, 0x75, 0xEB, 0x68, 0xFF, 0xA9, 0xB0, 0x99, 0x46, 0xEF, 0x1D, 0x70, 0x12, 0xC0, 0x29, 0x19, 0xEF, 0x13, 0xCB, 0x10, 0x0C, 0x2E, 0x2C, 0x79, 0x87, 0xA0, 0xA5, 0x78, 0x5B, 0x5F, 0x3F, 0x3B, 0x94, 0x8B, 0x7F, 0xD6, 0x4B, 0x85, 0xB1, 0x65, 0xAE, 0x2F, 0xBF, 0x3C, 0x47, 0xE0, 0x39, 0xC3, 0x07, 0x3C, 0xA7, 0x8F, 0xC9, 0x00, 0xBB, 0xCD, 0xC0, 0x69, 0xFE, 0x90, 0x68, 0x85, 0xD5, 0xB1, 0x37, 0x40, 0xA2, 0x23, 0xAF, 0x52, 0x54, 0xF9, 0x8C, 0x1D, 0x58, 0xE2, 0xFC, 0x92, 0xB0, 0x37, 0x3E, 0x2A, 0x93, 0x33, 0x53, 0xCC, 0x3E, 0xEC, 0xD3, 0x9F, 0x71, 0xD5, 0x9C, 0xFA, 0x09, 0x29, 0x4E, 0x38, 0x26, 0x2A, 0x44, 0x89, 0x40, 0x0D, 0x22, 0x29, 0x82, 0xF9, 0xC7, 0x80, 0xCD, 0x07, 0x31, 0xD4, 0xEE, 0xD9, 0x16, 0xC5, 0xA3, 0x1A, 0xBC, 0xD0, 0x2A, 0x59, 0x0E, 0xD8, 0xC6, 0xFF, 0xE1, 0x8B, 0x5F, 0xC7, 0xB6, 0x88, 0x8E, 0x74, 0x72, 0x69, 0x40, 0xD0, 0x2C, 0xCC, 0x62, 0xD7, 0x8B, 0xCA, 0xED, 0xDA, 0x2E, 0x02, 0x8E, 0x53, 0x5C, 0xDA, 0xFC, 0x0E, 0x09, 0x1B, 0xEF, 0x50, 0xDE, 0x2D, 0xFD, 0x12, 0x4F, 0x1E, 0x85, 0x4F, 0x56, 0x85, 0x27, 0xAE, 0xF4, 0xDC, 0x84, 0x55, 0xFD, 0xA0, 0x1B, 0x6D, 0x0D, 0x43, 0x04, 0x8E, 0xD5, 0xAB, 0x42, 0xB1, 0xD4, 0x08, 0x13, 0x99, 0x4B, 0x9F, 0x6A, 0xA0, 0xC0, 0x36, 0xC0, 0xDC, 0xF0, 0x8F, 0x46, 0xB0, 0x0F, 0xDA, 0x01, 0x44, 0x77, 0xCF, 0x87, 0x9B, 0x8F, 0xE5, 0xEA, 0xC4, 0x54, 0x1B, 0x82, 0xDA, 0x00, 0xB4, 0x34, 0x60, 0x46, 0x86, 0x5B, 0x09, 0x2E, 0xD6, 0xAE, 0x01, 0x15, 0xFC, 0x83, 0x4B, 0x58, 0xF7, 0x5F, 0xF9, 0x28, 0xD7, 0xD9, 0x9A, 0xC8, 0x69, 0x1F, 0xF7, 0x00, 0x20, 0xAB, 0xA2, 0x54, 0x80, 0xAB, 0xBC, 0xC7, 0x09, 0xE4, 0x6E, 0xC5, 0x10, 0xF4, 0xB8, 0xCA, 0xDD, 0x60, 0x04, 0x59, 0x54, 0xD3, 0xED, 0xDA, 0x7C, 0x23, 0xE0, 0x3D, 0x91, 0x69, 0x4D, 0x3C, 0x3E, 0xA2, 0x92, 0xC9, 0x25, 0x35, 0xE6, 0xB5, 0xFE, 0x17, 0x1C, 0x56, 0x7D, 0xF3, 0x72, 0x94, 0x06, 0xCD, 0xBA, 0x2A, 0x5E, 0xFA, 0x59, 0xF1, 0x56, 0xE9, 0xCC, 0xD0, 0x30, 0x2F, 0xDC, 0x0F, 0x8B, 0xB7, 0x59, 0xB0, 0x5D, 0xFF, 0x5D, 0xD8, 0x02, 0xCE, 0x4D, 0x55, 0x06, 0xA1, 0x9A, 0x69, 0xD7, 0x0B, 0x3A, 0xB4, 0x8A, 0xB1, 0x7A, 0x2F, 0xE5, 0x95, 0x89, 0xF7, 0x30, 0x83, 0xCC, 0xA5, 0x47, 0xFF, 0xB3, 0xF1, 0x46, 0x83, 0xC9, 0x14, 0xBC, 0x13, 0x45, 0xE7, 0x38, 0x7E, 0x83, 0x1E, 0xE6, 0x03, 0x75, 0x01, 0x49, 0x5C, 0x92, 0xC3, 0x57, 0x70, 0x5A, 0x69, 0xF9, 0x52, 0xA2, 0xF7, 0xCD, 0x30, 0xE0, 0x33, 0x36, 0xAF, 0xAA, 0xFC, 0x9C, 0x56, 0x60, 0x4C, 0xD5, 0x45, 0xE8, 0x2A, 0xA1, 0x2A, 0xF0, 0x58, 0xDA, 0xBA, 0x97, 0x43, 0x87, 0xFE, 0x8D, 0xCD, 0xEC, 0x69, 0x9A, 0x1E, 0x38, 0x53, 0xE2, 0x6D, 0x29, 0xE1, 0x57, 0x81, 0x89, 0xAA, 0x8C, 0x2B, 0xBA, 0x15, 0x50, 0xDF, 0xBE, 0xDD, 0x1E, 0x4F, 0x22, 0x4E, 0xFC, 0xD6, 0x54, 0x91, 0xE5, 0x4E, 0x56, 0x12, 0x8A, 0xE7, 0xC2, 0xDC, 0x85, 0x66, 0x79, 0x7A, 0xBF, 0x2D, 0x94, 0x55, 0x91, 0x52, 0x03, 0xA5, 0xC8, 0x9E, 0x55, 0xDD, 0x23, 0xDF, 0x82, 0x74, 0x36, 0xA8, 0xD6, 0xDC, 0xC5, 0xAC, 0xA8, 0x2F, 0x9B, 0x18, 0x36, 0x92, 0x15, 0x9E, 0xC0, 0x3F, 0x2B, 0x79, 0x8E, 0x55, 0x7D, 0x14, 0x73, 0x46, 0xD8, 0x35, 0xA8, 0xD8, 0x1B, 0x2E, 0x3D, 0x40, 0x86, 0x39, 0x66, 0x86, 0x3A, 0x54, 0xD9, 0xC8, 0x7B, 0x5A, 0xAC, 0xE9, 0x63, 0xCD, 0x52, 0x9A, 0xDB, 0xAE, 0x07, 0x07, 0x0C, 0xEA, 0x00, 0xB7, 0x80, 0xE1, 0x81, 0x31, 0xE6, 0x4F, 0x0A, 0xD7, 0x0E, 0x91, 0x58, 0xF5, 0x90, 0xD0, 0x0A, 0xD9, 0x17, 0x79, 0x08, 0xB9, 0x03, 0x45, 0xFD, 0x79, 0xD0, 0x25, 0x57, 0x71, 0xC6, 0x08, 0xAF, 0x65, 0xEE, 0x5A, 0xC3, 0xC5, 0x01, 0x66, 0xBA, 0xD0, 0x57, 0x38, 0x02, 0x58, 0x68, 0x19, 0x41, 0x56, 0x0F, 0x11, 0x33, 0x40, 0x5F, 0xC2, 0xD7, 0x61, 0x13, 0x14, 0xB4, 0x38, 0x1D, 0x54, 0x59, 0xDC, 0xDE, 0xDE, 0x4D, 0x39, 0xF3, 0x82, 0x3B, 0xC4, 0x42, 0x2B, 0xB1, 0xD7, 0x36, 0xE7, 0x47, 0x4A, 0x80, 0x89, 0xF0, 0xEC, 0xFA, 0x3C, 0x30, 0xAA, 0xC1, 0x19, 0xFF, 0xA4, 0x2B, 0xF7, 0x43, 0xF4, 0x8E, 0x0F, 0xDD, 0x96, 0x02, 0x92, 0xD3, 0xE4, 0x9A, 0x14, 0xEB, 0x05, 0x90, 0xC8, 0xE0, 0x2E, 0x42, 0x1D, 0x54, 0xAE, 0x8A, 0x52, 0x19, 0x51, 0x5E, 0x21, 0x89, 0x59, 0x89, 0xA0, 0xD7, 0x1D, 0x4F, 0x45, 0x16, 0x69, 0xCD, 0x65, 0x2D, 0xA3, 0x48, 0x9E, 0x5C, 0xDB, 0xC0, 0x87, 0x6B, 0xA0, 0xA0, 0x89, 0x9E, 0x7D, 0x87, 0x73, 0xB2, 0x4A, 0xFC, 0x2C, 0xD6, 0xD3, 0x7C, 0xA3, 0x80, 0xA5, 0xD0, 0xDD, 0x43, 0x63, 0x04, 0xD6, 0xE1, 0xA4, 0xDC, 0xD6, 0x38, 0xE8, 0xB9, 0x5E, 0x6C, 0x95, 0x46, 0x5C, 0x66, 0x90, 0xD4, 0xEF, 0xE8, 0xF4, 0x46, 0x91, 0xE4, 0x8D, 0xE2, 0x2C, 0xFC, 0x69, 0x1C, 0x75, 0x61, 0xAD, 0x8C, 0xC1, 0xA2, 0xC3, 0xCC, 0x9F, 0xB8, 0x6F, 0xF6, 0xF4, 0x70, 0x5A, 0x57, 0x3A, 0x72, 0x04, 0x71, 0xED, 0x33, 0xA0, 0x0E, 0x8A, 0x60, 0x20, 0x38, 0x18, 0xA3, 0x96, 0x1E, 0x4D, 0x21, 0x3A, 0x78, 0xB8, 0x62, 0x63, 0x94, 0xF7, 0x5C, 0x28, 0x23, 0x15, 0x57, 0x4C, 0xCD, 0x72, 0x5A, 0x67, 0xE2, 0x0F, 0x0B, 0xF2, 0x24, 0xBF, 0xFC, 0xAB, 0xD7, 0x02, 0xBF, 0xD4, 0xE1, 0xCC, 0x5F, 0x78, 0xBE, 0xC0, 0xE0, 0x42, 0xE1, 0x2E, 0xD4, 0xC9, 0x47, 0x4B, 0xDD, 0x5E, 0xED, 0x2A, 0xEB, 0x53, 0xF4, 0xA9, 0x58, 0xD7, 0xF8, 0x4E, 0xFD, 0x56, 0xEC, 0x03, 0x0A, 0x94, 0xD2, 0x00, 0xA5, 0x39, 0xDE, 0x16, 0x4E, 0x53, 0xC8, 0x2A, 0xFE, 0x8C, 0x5F, 0x71, 0xBB, 0x99, 0xA0, 0x1F, 0x72, 0x30, 0xB7, 0xAE, 0xBC, 0x21, 0x3E, 0xCD, 0xDB, 0xEF, 0x5B, 0x9E, 0x90, 0x64, 0x87, 0x43, 0x96, 0xF8, 0xA9, 0x1B, 0x05, 0x75, 0xF6, 0x8A, 0x45, 0x15, 0xDD, 0x15, 0x81, 0x78, 0xBF, 0x27, 0x7A, 0x90, 0xA3, 0xFE, 0xA2, 0x00, 0x92, 0x00, 0xDA, 0x2E, 0xDA, 0x2C, 0x8B, 0x3A, 0x47, 0xC1, 0x04, 0xD3, 0x50, 0xDF, 0x68, 0xE9, 0x4C, 0x8A, 0x40, 0x23, 0xD3, 0xAE, 0xFB, 0xB7, 0x07, 0x18, 0xFA, 0x2E, 0x27, 0xE6, 0xA5, 0xC3, 0xF9, 0x92, 0x7E, 0xC5, 0x96, 0xAB, 0x54, 0x0F, 0x46, 0x3A, 0xE0, 0x10, 0xEF, 0x71, 0xB8, 0x9B, 0x49, 0x49, 0x7F, 0x0C, 0xFD, 0x29, 0x39, 0xFF, 0xAB, 0x2A, 0x7D, 0xD1, 0x24, 0x7D, 0xC4, 0xA5, 0x9D, 0x84, 0x11, 0xA8, 0x43, 0xBD, 0x84, 0xF1, 0xEA, 0x8D, 0xA3, 0x3C, 0x07, 0x01, 0xD7, 0x0A, 0xC2, 0x7C, 0x4B, 0xDB, 0xD0, 0xD9, 0xA0, 0xCA, 0xB8, 0x6B, 0x1F, 0xC5, 0xBE, 0x12, 0x45, 0x8A, 0x25, 0x80, 0xA6, 0xCA, 0xB4, 0xB7, 0x65, 0xB8, 0x42, 0xC6, 0x7A, 0xD5, 0x4C, 0xA5, 0xD4, 0x0A, 0x24, 0xE2, 0xDD, 0xBC, 0xF0, 0x1E, 0x46, 0x6E, 0x08, 0xD9, 0xB3, 0x44, 0x9F, 0x13, 0xE8, 0x2E, 0x16, 0xD6, 0x1C, 0x72, 0x3F, 0xB9, 0x46, 0x2E, 0x97, 0xB7, 0xAB, 0xC7, 0x0B, 0x22, 0x10, 0xEC, 0xA1, 0x6B, 0x16, 0x0D, 0x5B, 0x8F, 0x98, 0xA1, 0x79, 0x4D, 0xCA, 0x92, 0xCD, 0x4F, 0x02, 0x7F, 0x3E, 0x41, 0x52, 0xEA, 0x87, 0x95, 0x07, 0xDD, 0xFE, 0x7F, 0x1F, 0x21, 0x51, 0x41, 0x53, 0xF0, 0x36, 0xAA, 0xBC, 0x33, 0xF1, 0x72, 0xC9, 0x5A, 0x9B, 0x77, 0x47, 0x22, 0x80, 0x0F, 0x2E, 0x08, 0xCC, 0x44, 0xF9, 0x23, 0x54, 0x0D, 0x8A, 0xF6, 0x4B, 0x42, 0x99, 0x68, 0xB2, 0x80, 0x36, 0x4C, 0x1B, 0x7B, 0x4B, 0x3E, 0x9B, 0xEE, 0x40, 0xC5, 0x00, 0x02, 0x65, 0x7D, 0x99, 0x46, 0x31, 0xF3, 0x3A, 0x8F, 0x8F, 0x13, 0x4A, 0x27, 0xEB, 0x69, 0xBA, 0x43, 0x95, 0x90, 0x8B, 0xA4, 0x06, 0x34, 0xB8, 0xF2, 0x70, 0x31, 0x49, 0x27, 0x5F, 0xFB, 0xBE, 0x8B, 0x48, 0x3E, 0xA1, 0xBB, 0xA9, 0x1C, 0x28, 0x10, 0x51, 0x36, 0xD9, 0x7C, 0x47, 0x0E, 0xE8, 0x3C, 0xD2, 0x1C, 0xEB, 0x2B, 0x21, 0xAA, 0xED, 0x98, 0xDB, 0x8A, 0xB1, 0x65, 0xA7, 0xB4, 0xBE, 0x55, 0x9E, 0x7E, 0xAC, 0xA6, 0x84, 0x60, 0x30, 0x15, 0xBC, 0x34, 0x9B, 0x0A, 0x51, 0x21, 0x4E, 0x4E, 0x8F, 0xBE, 0x1D, 0x2D, 0x88, 0x3F, 0x79, 0xFD, 0x3F, 0x1E, 0xDC, 0xDD, 0x3F, 0xA6, 0xD4, 0xB5, 0xBB, 0xD2, 0xA5, 0xB3, 0x00, 0x3A, 0x80, 0xF1, 0xDA, 0xDE, 0x97, 0x5B, 0x50, 0x2C, 0x7F, 0x72, 0x03, 0x73, 0x16, 0xBC, 0x55, 0xC1, 0xE5, 0x7E, 0x50, 0x06, 0x27, 0xD6, 0x0E, 0x31, 0x08, 0x74, 0x31, 0xD2, 0xC9, 0xD0, 0x2C, 0xA9, 0xF0, 0xEB, 0xCC, 0xD4, 0xBF, 0xE3, 0xC4, 0xBB, 0x53, 0x6D, 0x4C, 0xFE, 0xF7, 0x51, 0x07, 0x50, 0x45, 0x2D, 0x44, 0x4B, 0xE2, 0xC3, 0xD6, 0x4D, 0x84, 0xA8, 0x32, 0x96, 0x53, 0x05, 0x26, 0x4A, 0xBB, 0x53, 0xE3, 0x61, 0x49, 0x40, 0xF9, 0xB2, 0xF1, 0xEA, 0x6F, 0x41, 0xCA, 0x8F, 0x69, 0xE7, 0x26, 0x69, 0x0B, 0xA6, 0x30, 0x63, 0x0F, 0x8A, 0x91, 0x6E, 0xE8, 0x56, 0x26, 0x82, 0x51, 0xB7, 0x73, 0xDC, 0x2A, 0x5D, 0xB4, 0x5D, 0x22, 0xDF, 0xB2, 0x43, 0x9C, 0xA4, 0xB7, 0xAB, 0x70, 0x21, 0x5D, 0x23, 0xE1, 0xF2, 0xE2, 0x61, 0x73, 0x94, 0xFF, 0x78, 0x3B, 0x0B, 0xFF, 0x6D, 0xF0, 0x34, 0x5C, 0xC9, 0x27, 0x05, 0x3D, 0x02, 0xC6, 0x5F, 0xE2, 0xA8, 0x6D, 0xEF, 0xBE, 0xBF, 0x52, 0x43, 0xA2, 0xEF, 0x6A, 0x63, 0x12, 0xBA, 0xED, 0xB6, 0xE6, 0x0D, 0xBB, 0x0C, 0x67, 0xCC, 0x9A, 0x65, 0x55, 0x85, 0xCB, 0x45, 0x8D, 0x6A, 0x04, 0x18, 0x11, 0x94, 0x81, 0x5F, 0x03, 0xBE, 0x87, 0xF6, 0xE8, 0x00, 0x49, 0x2A, 0x24, 0xC5, 0xD5, 0x02, 0xD5, 0xEC, 0xD5, 0x3D, 0xD6, 0xDA, 0x36, 0x79, 0x95, 0xD3, 0x2E, 0x8B, 0xBA, 0xA3, 0xEF, 0x62, 0x72, 0x7E, 0x8A, 0x61, 0x0E, 0x8D, 0x6B, 0x5C, 0x8F, 0xAB, 0xCB, 0xE8, 0x89, 0x3B, 0xDB, 0x5E, 0x03, 0x86, 0x27, 0xF7, 0x07, 0xE8, 0x46, 0x4C, 0x55, 0xDC, 0xBB, 0x76, 0xF0, 0x83, 0x6A, 0xDD, 0x29, 0x8A, 0x96, 0x7C, 0x45, 0x95, 0x08, 0xBC, 0x4E, 0x88, 0xBA, 0x5C, 0xA3, 0x8F, 0x5A, 0x56, 0x1A, 0x6D, 0x2D, 0x6C, 0xB2, 0x17, 0x8D, 0x90, 0xAC, 0x85, 0x0C, 0xA2, 0x73, 0x4B, 0x45, 0xC4, 0xA8, 0x9A, 0xA0, 0xF1, 0x52, 0xA3, 0xB5, 0x3B, 0xCF, 0x1E, 0x13, 0x53, 0x2B, 0x2B, 0x5B, 0x38, 0x78, 0xB2, 0x05, 0xBD, 0x2B, 0x32, 0x7D, 0xC4, 0x9E, 0xB6, 0x66, 0x0B, 0x95, 0x11, 0xBF, 0xAE, 0x90, 0xC1, 0xDE, 0xA5, 0xBD, 0xEB, 0x6D, 0xC5, 0xDA, 0x06, 0x8B, 0xCB, 0xDC, 0x6C, 0x09, 0x3E, 0x57, 0x27, 0xE3, 0x87, 0x37, 0x4F, 0x45, 0x2F, 0x96, 0x3C, 0x30, 0x7D, 0xEE, 0x86, 0x5D, 0x41, 0xAA, 0x12, 0x4C, 0xA8, 0x03, 0xC1, 0x2F, 0x9A, 0xE9, 0x29, 0x9C, 0x3C, 0xB1, 0x34, 0x5F, 0xCC, 0x56, 0x8C, 0x6E, 0x71, 0xBE, 0x33, 0x66, 0xBF, 0x30, 0xEF, 0xEE, 0xEF, 0xC7, 0x69, 0x3C, 0x36, 0xAC, 0xE5, 0x76, 0xB0, 0xD1, 0x0F, 0x40, 0x2F, 0x38, 0x00, 0x09, 0xFD, 0x0E, 0xC0, 0x68, 0xCB, 0x2D, 0x45, 0x98, 0x48, 0x84, 0xED, 0xF1, 0x6B, 0xC9, 0x0B, 0x0F, 0xF6, 0xDC, 0x96, 0x30, 0x9E, 0xA3, 0x77, 0xA3, 0xCE, 0xC0, 0x43, 0xCB, 0x76, 0xB6, 0xC8, 0x85, 0xBB, 0xB8, 0x48, 0xC4, 0x74, 0x5B, 0x71, 0xE1, 0x8C, 0x58, 0xE7, 0x80, 0x50, 0xE1, 0x9B, 0xD7, 0xBE, 0x08, 0x31, 0xEF, 0xE9, 0x05, 0x2A, 0x6A, 0x7D, 0xF8, 0xD4, 0xE8, 0xB9, 0xFC, 0x3E, 0x08, 0x2A, 0x4D, 0x40, 0xAD, 0x73, 0xE4, 0xB3, 0x18, 0x5E, 0x2F, 0x6D, 0xED, 0xE7, 0xEE, 0x51, 0xA4, 0x06, 0x8F, 0xF2, 0xDA, 0x57, 0x37, 0x3F, 0xD7, 0xE7, 0xBD, 0x46, 0xE0, 0x08, 0x0F, 0x4C, 0x2C, 0x1F, 0x41, 0xBC, 0x25, 0x0E, 0x6D, 0xA4, 0x5A, 0x34, 0x1F, 0x21, 0x47, 0x71, 0xF5, 0x53, 0x1A, 0x67, 0xB0, 0xFD, 0x97, 0xB5, 0x3C, 0xD7, 0x2C, 0xFA, 0xC7, 0x21, 0x5B, 0xC4, 0x11, 0x1F, 0x09, 0x40, 0x30, 0xA9, 0x13, 0x83, 0xD2, 0x01, 0x82, 0x21, 0x0F, 0xCE, 0xCD, 0x75, 0xE5, 0x9C, 0x4B, 0x0B, 0x33, 0xA3, 0xF9, 0x3D, 0x86, 0x5D, 0x84, 0x7E, 0xC2, 0x41, 0xE1, 0xB9, 0x84, 0x81, 0xC5, 0xD9, 0xD2, 0x7F, 0x0A, 0xE2, 0x62, 0xB3, 0x28, 0x65, 0x0C, 0xDC, 0x13, 0xCD, 0x99, 0x86, 0x6B, 0xE9, 0xA5, 0xA0, 0x30, 0xE8, 0x3D, 0x84, 0xE3, 0x2B, 0xD2, 0x13, 0xC9, 0x4B, 0xD6, 0xAF, 0x95, 0x04, 0x33, 0xA4, 0xF0, 0x0C, 0x61, 0x49, 0x78, 0x3B, 0x00, 0x75, 0x0C, 0xDF, 0xD4, 0xF4, 0x7A, 0xE7, 0x52, 0x17, 0xEE, 0xD1, 0xF6, 0x0C, 0x36, 0x6F, 0xA0, 0x2C, 0xDB, 0x20, 0x6F, 0xEB, 0x2A, 0x68, 0x5D, 0x6B, 0x7D, 0x6A, 0x4C, 0x13, 0x55, 0x3E, 0x2B, 0xE2, 0x77, 0x94, 0xF5, 0x3B, 0x0E, 0xF5, 0x73, 0x15, 0x20, 0x32, 0x63, 0xEB, 0x02, 0x6E, 0xA5, 0xE6, 0x70, 0x67, 0xD2, 0x2F, 0x92, 0xE2, 0x6E, 0x98, 0xDF, 0x9A, 0xB3, 0x86, 0xC2, 0x70, 0x5B, 0x43, 0x16, 0xA6, 0x98, 0x92, 0x68, 0x8E, 0x60, 0x1E, 0x74, 0x27, 0x59, 0x5A, 0xCE, 0xE6, 0xE4, 0x7F, 0x5E, 0xC5, 0x98, 0xCC, 0x48, 0xC2, 0xF2, 0xDA, 0x1C, 0x32, 0xE0, 0x62, 0xA3, 0x49, 0xD8, 0x9D, 0xCC, 0x8C, 0x05, 0xC6, 0x2E, 0x7B, 0x0C, 0xED, 0x6F, 0x2E, 0x93, 0xA7, 0xBD, 0x48, 0xA8, 0x00, 0x4A, 0x8C, 0x5C, 0x60, 0x5D, 0xFF, 0xC8, 0x05, 0xDE, 0x07, 0x9E, 0xDE, 0xE7, 0xCE, 0xD9, 0x86, 0x39, 0xA9, 0x2F, 0x6C, 0xBA, 0x92, 0xF2, 0x08, 0x9B, 0x14, 0x5D, 0x2D, 0x61, 0xD9, 0x63, 0x8C, 0x07, 0x34, 0x7A, 0x2E, 0xF6, 0xB3, 0x0F, 0xD9, 0x0E, 0x11, 0x1A, 0x7F, 0x59, 0x13, 0xF6, 0xE1, 0x87, 0x95, 0xC1, 0x9E, 0x0B, 0x9F, 0x60, 0xF8, 0x5B, 0xD8, 0xF5, 0xC9, 0xA9, 0x63, 0x33, 0x94, 0x41, 0xE4, 0xA5, 0xB7, 0x9E, 0xB2, 0xE8, 0x67, 0x96, 0x1B, 0x18, 0xA1, 0x88, 0x4A, 0x01, 0xA7, 0x44, 0x83, 0xD8, 0x0B, 0x40, 0x3E, 0xFB, 0xDB, 0xD4, 0xED, 0xDD, 0xC1, 0x92, 0x2D, 0xA3, 0xFB, 0xB3, 0x7B, 0xEA, 0x97, 0xE0, 0xA5, 0xB6, 0x34, 0x3E, 0x43, 0x67, 0x60, 0x1B, 0xD2, 0x1D, 0xB6, 0x69, 0x41, 0xC2, 0x69, 0x8B, 0xF5, 0x06, 0xB0, 0x48, 0x61, 0xB5, 0xF3, 0xD3, 0xD8, 0x0A, 0xC6, 0xDC, 0xB6, 0x84, 0xD9, 0xC4, 0x36, 0x9A, 0xBD, 0x04, 0xBC, 0x4B, 0xDB, 0xEF, 0x49, 0xC6, 0x6E, 0x38, 0x44, 0x51, 0x3A, 0x3F, 0x3B, 0xDD, 0x40, 0x0C, 0x08, 0x0A, 0xC6, 0xEA, 0xD8, 0x1E, 0x8B, 0xB0, 0xE7, 0xCB, 0x36, 0xDB, 0x7B, 0x7E, 0xAB, 0x47, 0x28, 0x39, 0x18, 0x57, 0xF5, 0x97, 0xA3, 0x46, 0x48, 0x63, 0xC3, 0x12, 0x64, 0x5B, 0x20, 0xAF, 0x02, 0xF7, 0xD0, 0xBD, 0x9A, 0x74, 0xDE, 0x23, 0x61, 0xA0, 0xD2, 0xD9, 0x8A, 0x69, 0x89, 0x75, 0xB3, 0x0F, 0x10, 0x10, 0xD9, 0x0A, 0x12, 0x60, 0x78, 0x58, 0x4A, 0x45, 0xFF, 0xBC, 0xC6, 0x5B, 0x47, 0x97, 0x6A, 0xF6, 0x57, 0xEA, 0x84, 0xE9, 0x73, 0x0D, 0x9E, 0x36, 0x37, 0x33, 0x73, 0x6A, 0xC8, 0x01, 0x03, 0xDC, 0x1C, 0x75, 0x73, 0xC4, 0xDE, 0xE2, 0x8A, 0x7B, 0xAC, 0x9E, 0xF7, 0x2C, 0xB8, 0x29, 0x45, 0x0B, 0x53, 0xEA, 0xF9, 0x84, 0xCD, 0x01, 0xAA, 0x31, 0x41, 0x6C, 0xE8, 0x91, 0x4B, 0x7D, 0x7E, 0xF8, 0x49, 0xEB, 0x9C, 0xC1, 0x72, 0xD7, 0x09, 0x6D, 0xEF, 0xDA, 0xCF, 0x59, 0x6B, 0x9B, 0x21, 0xA5, 0x73, 0xE3, 0x46, 0xA4, 0x7A, 0x5A, 0x46, 0x9E, 0x1D, 0x79, 0x39, 0xBE, 0x19, 0x82, 0xCB, 0x39, 0x54, 0xC2, 0x14, 0xED, 0x3A, 0x37, 0x07, 0xD7, 0x40, 0xC0, 0x33, 0xE3, 0xEF, 0x78, 0x0F, 0x4C, 0x48, 0xBA, 0xDD, 0x86, 0x38, 0x48, 0xBB, 0xFC, 0x9D, 0xAA, 0x8E, 0x38, 0x06, 0xA8, 0x4B, 0x2C, 0xAC, 0x0C, 0xA2, 0x32, 0x00, 0x0C, 0xAF, 0x02, 0x03, 0xE9, 0x08, 0xFC, 0xE1, 0x8B, 0x5D, 0x62, 0x77, 0x72, 0x25, 0xD2, 0xD7, 0xD5, 0x84, 0xF2, 0xED, 0x71, 0x88, 0x5D, 0xFA, 0xF5, 0xA4, 0xDB, 0xEE, 0x02, 0xF2, 0x85, 0xBC, 0x34, 0x55, 0x9B, 0x88, 0xEA, 0x9C, 0xE1, 0x5B, 0x47, 0xA3, 0xB9, 0x2A, 0x8D, 0x6F, 0x91, 0x59, 0x1C, 0x32, 0x9A, 0x5A, 0xA2, 0x1A, 0x1B, 0xC4, 0x24, 0xBA, 0x2B, 0xDB, 0xD1, 0x64, 0xCE, 0x1A, 0x8B, 0x78, 0xB3, 0x8B, 0xEF, 0x2B, 0x47, 0xF2, 0x1F, 0x7F, 0xB7, 0xA3, 0xC5, 0x4E, 0x3E, 0xA4, 0x53, 0x6E, 0x81, 0x6E, 0x01, 0x65, 0x6C, 0x8E, 0x26, 0xAD, 0x42, 0xF3, 0xCB, 0x90, 0x61, 0x69, 0x67, 0xC0, 0xDD, 0x07, 0x9F, 0x95, 0x6C, 0x9F, 0x3C, 0x84, 0x4D, 0x5F, 0x33, 0x9C, 0x62, 0xEE, 0x8A, 0x35, 0x8C, 0x4B, 0xEC, 0x2D, 0x27, 0x8A, 0xF7, 0x18, 0xAD, 0x50, 0x9C, 0x6B, 0x66, 0x61, 0x3B, 0x58, 0x04, 0x43, 0xFA, 0x6F, 0x11, 0xCD, 0x8D, 0x10, 0x76, 0x93, 0xB5, 0xD7, 0xB7, 0x38, 0xAA, 0x7E, 0x2F, 0xE6, 0x62, 0x50, 0x2D, 0x75, 0x04, 0xA9, 0xF5, 0x96, 0x19, 0x41, 0x80, 0xF8, 0x70, 0x0D, 0xC4, 0xE6, 0xF7, 0xE8, 0xE7, 0xD2, 0x30, 0x72, 0x34, 0x49, 0x4B, 0x8D, 0xF1, 0xD5, 0x7E, 0xE1, 0x4D, 0x6C, 0x97, 0x92, 0x6E, 0xB1, 0xD8, 0x90, 0x4D, 0x80, 0x89, 0xBE, 0x7D, 0x13, 0x5B, 0x13, 0xD6, 0xDE, 0x30, 0xAA, 0x87, 0x20, 0xD6, 0x71, 0x59, 0xBB, 0x50, 0xA8, 0x34, 0xDE, 0x90, 0x79, 0x92, 0x2B, 0x88, 0x93, 0x1D, 0x45, 0x85, 0x00, 0x62, 0x68, 0x34, 0xDA, 0x04, 0x0D, 0xB7, 0x68, 0xDD, 0xDB, 0xE6, 0x7A, 0x75, 0x8A, 0x02, 0xB4, 0x48, 0xE3, 0x6B, 0xA4, 0x55, 0x03, 0x4A, 0xDE, 0x36, 0x80, 0x2A, 0xA4, 0x2A, 0x7F, 0x2F, 0x23, 0x4A, 0x5E, 0x1C, 0xC2, 0x41, 0xE5, 0x66, 0x1C, 0x63, 0xAF, 0xCE, 0x59, 0xDF, 0xDC, 0xC0, 0x89, 0x83, 0x47, 0xD2, 0x83, 0x4D, 0x72, 0x64, 0xF5, 0xB2, 0x1A, 0x47, 0xC5, 0x21, 0x4A, 0xDC, 0x57, 0xAF, 0x76, 0xCE, 0x9E, 0xBD, 0xB6, 0x8C, 0x71, 0x02, 0x9B, 0xCF, 0x0C, 0x4C, 0x74, 0x5A, 0x33, 0x45, 0x4A, 0xCF, 0x0C, 0xF6, 0xD5, 0xC6, 0x8D, 0xEA, 0x06, 0xC4, 0x5E, 0x7D, 0x4D, 0x17, 0x55, 0xC5, 0xAC, 0xDC, 0x37, 0xFC, 0x24, 0x34, 0x14, 0x0E, 0xF7, 0x07, 0xFD, 0x55, 0xFA, 0xF0, 0x6C, 0xBB, 0x17, 0x07, 0xC2, 0x7C, 0xE9, 0xD9, 0x05, 0x90, 0x5E, 0x37, 0xE2, 0xF1, 0x47, 0xC9, 0xCB, 0x88, 0x08, 0xEC, 0xD0, 0x5D, 0xF7, 0x1F, 0xC5, 0xF1, 0xDA, 0xF9, 0x10, 0xD7, 0xBD, 0x68, 0xB6, 0x91, 0x49, 0x38, 0xBF, 0x0C, 0xAB, 0xCF, 0x66, 0xC9, 0x05, 0xC4, 0x95, 0x63, 0xD7, 0xD7, 0x0F, 0x2C, 0x3D, 0x3A, 0x4A, 0x4F, 0x62, 0x9E, 0x3A, 0xFD, 0xE5, 0x3B, 0xD1, 0x4C, 0xD6, 0xE5, 0x27, 0xE4, 0xF0, 0x38, 0xD6, 0xA3, 0x31, 0xD0, 0x14, 0x68, 0xE2, 0x2D, 0xFE, 0x93, 0xA3, 0x79, 0xB3, 0xEC, 0x6D, 0xA6, 0xD1, 0xC2, 0xF6, 0xD5, 0xEA, 0xB1, 0x41, 0xE5, 0x75, 0xF9, 0x3C, 0x8C, 0xC5, 0x58, 0x0D, 0xF4, 0xA3, 0xDB, 0x5C, 0x4C, 0x87, 0xD8, 0x54, 0x8E, 0x9A, 0x85, 0x19, 0x46, 0xD1, 0xB9, 0x0D, 0x75, 0x27, 0x40, 0x7F, 0x1B, 0xA1, 0x12, 0x1E, 0xAC, 0x54, 0xA1, 0x1E, 0x6E, 0xDA, 0x45, 0xAB, 0xB0, 0x8A, 0x7A, 0x78, 0xAB, 0x36, 0xA7, 0x6E, 0xAD, 0x7F, 0xAC, 0x46, 0x78, 0xE5, 0x24, 0x64, 0xEF, 0xF3, 0x98, 0xE9, 0x02, 0x15, 0xAC, 0x31, 0x6D, 0xE5, 0xA6, 0xEF, 0xE5, 0xA7, 0xB4, 0xA9, 0x5D, 0xF9, 0x2E, 0x41, 0x29, 0xF3, 0xF9, 0x1B, 0x31, 0x6F, 0x75, 0x67, 0x08, 0xBD, 0xF3, 0x7C, 0x01, 0xC1, 0x2B, 0xBA, 0xA0, 0x91, 0xF9, 0x48, 0x84, 0xE3, 0x8A, 0xFF, 0x3C, 0x7B, 0x81, 0x40, 0x88, 0x8C, 0xAB, 0x4F, 0x7F, 0x86, 0x7E, 0xAD, 0xB0, 0x41, 0x85, 0x84, 0xB6, 0xF7, 0x70, 0x74, 0x02, 0x50, 0x93, 0x6A, 0x13, 0x8A, 0xFF, 0x52, 0x88, 0x88, 0x40, 0x67, 0x7D, 0x81, 0x21, 0xC5, 0x83, 0x80, 0x6F, 0xE2, 0x71, 0x04, 0xDE, 0x52, 0x88, 0x13, 0xE5, 0x62, 0x26, 0xB6, 0x52, 0xC5, 0x86, 0x9B, 0xB5, 0x00, 0x30, 0x38, 0x34, 0xD9, 0xC9, 0xD1, 0x97, 0xDB, 0xA1, 0xDD, 0x5C, 0x47, 0x34, 0x30, 0x7A, 0xB8, 0xBD, 0x00, 0x6B, 0x66, 0xEF, 0x45, 0xAB, 0xED, 0x2E, 0x31, 0x37, 0x7B, 0xEA, 0xA1, 0x9D, 0xAE, 0x6E, 0xC8, 0x2A, 0xD7, 0x7C, 0x4C, 0x07, 0x74, 0x4F, 0x9B, 0x93, 0xA8, 0xDD, 0x4C, 0xEE, 0x1A, 0x62, 0xA5, 0x52, 0xED, 0xF4, 0xE2, 0x77, 0xCA, 0xCF, 0xF1, 0xF9, 0x64, 0xDA, 0x7A, 0xF8, 0xFA, 0xFF, 0x6B, 0x56, 0xE3, 0xEB, 0xC0, 0x68, 0x50, 0xA9, 0xF7, 0x6E, 0xCF, 0xB2, 0xC2, 0xBA, 0xA6, 0x60, 0x95, 0x8C, 0x6D, 0x1B, 0xA9, 0x6B, 0xA8, 0x57, 0x8D, 0x06, 0x6D, 0x6A, 0xFE, 0x6E, 0x8F, 0xB2, 0x05, 0x2B, 0x74, 0x21, 0xD5, 0x7D, 0xE5, 0xAB, 0x4C, 0x1F, 0xD5, 0x51, 0x70, 0xE9, 0xEE, 0x33, 0xEB, 0x32, 0xFB, 0x3D, 0x2C, 0x88, 0x61, 0x42, 0x05, 0x5E, 0xE8, 0x42, 0x8B, 0xD7, 0x45, 0xAA, 0xBE, 0x1D, 0x15, 0x19, 0x1F, 0xFC, 0x93, 0xA3, 0xFA, 0x7A, 0x86, 0xB4, 0x27, 0xEB, 0x23, 0x70, 0xB7, 0x8A, 0x67, 0xA4, 0x85, 0xAF, 0x96, 0x3B, 0xBE, 0x1F, 0x22, 0x46, 0x11, 0x9F, 0xB4, 0x69, 0xA0, 0x02, 0xD7, 0x02, 0x9F, 0xC4, 0xF5, 0xF7, 0xE0, 0x12, 0x5F, 0xDA, 0x73, 0x05, 0xAC, 0xF6, 0xC8, 0x0C, 0x7B, 0xD3, 0xF6, 0x68, 0x89, 0x7B, 0xA8, 0x14, 0x35, 0xF4, 0x26, 0xB8, 0x42, 0x5C, 0x98, 0x55, 0xCD, 0x46, 0xC3, 0x44, 0x8B, 0xBA, 0xD0, 0x73, 0x9B, 0xA8, 0x8A, 0xBC, 0x27, 0x3B, 0xCD, 0x0F, 0xA1, 0xFD, 0xA7, 0xF4, 0xF8, 0x18, 0x3B, 0x5D, 0x73, 0xD1, 0x6C, 0x40, 0x7C, 0x45, 0x2A, 0xEF, 0xA2, 0xE3, 0xCA, 0x9F, 0x2D, 0x9D, 0x63, 0x8D, 0x96, 0x6A, 0x58, 0x78, 0x8B, 0x48, 0xBF, 0xC5, 0x7D, 0x3F, 0xC2, 0x08, 0x5F, 0xE8, 0x5A, 0x7F, 0x7A, 0xDD, 0xD9, 0x1E, 0xFD, 0x1B, 0xA0, 0x22, 0x60, 0x46, 0xB1, 0x27, 0xA9, 0x7B, 0xC4, 0x80, 0x47, 0x9B, 0x92, 0x88, 0x1A, 0x58, 0xA0, 0xBC, 0x04, 0xD8, 0xDD, 0x9E, 0x68, 0xB6, 0xD2, 0xBC, 0x50, 0x34, 0xCF, 0x23, 0x43, 0x0D, 0x1F, 0xE5, 0x49, 0x91, 0xA6, 0x90, 0x8B, 0x01, 0x9E, 0xE0, 0x18, 0xC8, 0x43, 0xB9, 0xFA, 0x53, 0xEC, 0x7E, 0xE5, 0xF1, 0x14, 0xAB, 0xE2, 0xB7, 0x50, 0xD4, 0xE1, 0xE7, 0x2E, 0xAF, 0xB4, 0xFB, 0xB3, 0x3A, 0x1E, 0x2C, 0x4D, 0x62, 0x72, 0xCE, 0xE2, 0x7B, 0xBB, 0x13, 0xB5, 0xD2, 0x3E, 0x24, 0xF6, 0x12, 0x9C, 0xF5, 0x82, 0x5F, 0x34, 0xAF, 0xC0, 0x56, 0xF9, 0x5F, 0x53, 0xA0, 0x9F, 0x6F, 0xCA, 0x94, 0x35, 0xCD, 0x5F, 0xB6, 0xC0, 0x5F, 0x88, 0xB4, 0xDC, 0xE8, 0x6C, 0xEA, 0xBD, 0x7E, 0x0C, 0x78, 0x53, 0x61, 0xD2, 0x53, 0xBB, 0x9C, 0xDB, 0x3A, 0x0C, 0x6B, 0xC8, 0x51, 0x83, 0x01, 0xFF, 0x44, 0xF9, 0xE8, 0x7F, 0x7A, 0x97, 0xEC, 0x9F, 0x02, 0xFA, 0xB5, 0x13, 0x4F, 0x3B, 0xBF, 0xA1, 0xCB, 0xE4, 0x4F, 0xA8, 0x3F, 0x1C, 0x54, 0x3E, 0xD9, 0xB8, 0x70, 0x65, 0x75, 0x43, 0x5A, 0xC6, 0xA1, 0x5F, 0x7B, 0x0D, 0xEB, 0xA9, 0xD4, 0x5A, 0xF5, 0x54, 0xBB, 0x0C, 0xCB, 0xCA, 0x12, 0xA6, 0xC1, 0x6E, 0x5E, 0xE6, 0xFA, 0xD6, 0x37, 0x21, 0xE4, 0xC3, 0xCC, 0x8D, 0x9E, 0xA6, 0x8C, 0x61, 0x49, 0x99, 0x30, 0x80, 0x95, 0x24, 0x07, 0xAF, 0xA2, 0x03, 0xF5, 0x04, 0xA8, 0x87, 0xB3, 0xBF, 0x84, 0xD2, 0xBB, 0x6E, 0x45, 0xE7, 0xCC, 0x53, 0x26, 0x53, 0x3D, 0x63, 0x96, 0x3F, 0xFB, 0x72, 0xA9, 0x27, 0x2C, 0x8F, 0xF6, 0x37, 0xBE, 0x6E, 0x24, 0x73, 0xE9, 0xFC, 0xAB, 0x6B, 0x5E, 0x5E, 0x7C, 0xF3, 0xED, 0xBD, 0xDA, 0xEF, 0x51, 0xC9, 0x8D, 0x53, 0x17, 0x0F, 0x9B, 0x64, 0xBC, 0xA5, 0xD4, 0x9F, 0x76, 0xAF, 0x17, 0x6D, 0x01, 0xA6, 0xF2, 0xEC, 0xB3, 0x39, 0x15, 0x1F, 0x49, 0xE4, 0x9A, 0x8F, 0x6E, 0x28, 0x6C, 0x6D, 0x41, 0x22, 0xD6, 0x50, 0xD5, 0x01, 0x59, 0x10, 0xFF, 0x7F, 0x28, 0x02, 0x46, 0x93, 0x89, 0x5C, 0x58, 0x03, 0xDD, 0xFF, 0xCB, 0x1E, 0xDC, 0x46, 0x79, 0xC8, 0xF5, 0x35, 0xAC, 0x15, 0x97, 0xD9, 0xB2, 0x8A, 0xC4, 0x6E, 0x62, 0x88, 0x81, 0x01, 0x29, 0xC1, 0x79, 0x55, 0x6A, 0xF7, 0x88, 0x2D, 0xEE, 0x17, 0xD5, 0x8A, 0x97, 0xF4, 0x34, 0xDF, 0x83, 0x64, 0x6B, 0x33, 0xCF, 0xBA, 0xB9, 0x0A, 0x62, 0x50, 0x85, 0x1C, 0xF5, 0x3D, 0x4B, 0xDB, 0x45, 0x26, 0x33, 0x7D, 0xCC, 0xB9, 0xD9, 0x8A, 0x92, 0x16, 0x76, 0xB5, 0x13, 0x65, 0xDD, 0x08, 0xA5, 0x30, 0x4D, 0x2A, 0x93, 0x53, 0x4C, 0x52, 0x42, 0x7E, 0x9A, 0xE5, 0xC1, 0x44, 0x05, 0x92, 0xC5, 0x53, 0x6E, 0x17, 0x1C, 0xF4, 0xFD, 0x1F, 0x43, 0x57, 0x8F, 0xEA, 0xFB, 0x32, 0xFF, 0x01, 0xD4, 0xFE, 0xD6, 0x35, 0xD7, 0x52, 0x56, 0x8F, 0x90, 0xEC, 0xFB, 0xB1, 0x64, 0xA5, 0xB1, 0x76, 0x3F, 0x70, 0xC7, 0x2F, 0xD5, 0xBC, 0xDF, 0x61, 0xD0, 0x1F, 0xF3, 0x23, 0x66, 0x39, 0xC9, 0x1C, 0x06, 0x3C, 0x0B, 0x7A, 0x56, 0xAD, 0x03, 0xF4, 0x02, 0x0E, 0x80, 0xBD, 0x9A, 0x5E, 0x2F, 0x16, 0x1E, 0x05, 0x78, 0x46, 0x9B, 0x99, 0x50, 0x26, 0x6B, 0xA9, 0x6B, 0xBB, 0x73, 0xC0, 0x8E, 0x7F, 0xAE, 0x85, 0x6E, 0x17, 0x03, 0xCF, 0x3C, 0xBD, 0x21, 0x41, 0x80, 0x89, 0x14, 0x8F, 0x7A, 0x9F, 0x40, 0xD4, 0xD9, 0x11, 0x51, 0xDB, 0xC4, 0xBA, 0xE8, 0x54, 0x23, 0x59, 0xE8, 0x82, 0xA1, 0x9A, 0x99, 0x49, 0xCE, 0xD5, 0xB7, 0x5F, 0xF7, 0xB1, 0x92, 0xDC, 0x27, 0x9B, 0x3E, 0xD1, 0x00, 0x76, 0x05, 0x3F, 0x58, 0xDE, 0x43, 0x5F, 0xC5, 0x87, 0x56, 0x54, 0xE9, 0x86, 0x33, 0xA3, 0x97, 0x14, 0x11, 0x42, 0x22, 0x9D, 0x8C, 0xD6, 0x13, 0xC6, 0x63, 0x44, 0x32, 0x6D, 0x83, 0x99, 0x2B, 0x3C, 0x08, 0xF1, 0x7B, 0xE0, 0xEC, 0x28, 0xFB, 0xDB, 0xAB, 0xA1, 0x2C, 0xB0, 0x00, 0xB2, 0xA2, 0xB0, 0x4E, 0x24, 0xD0, 0xC4, 0x1B, 0xD6, 0xB5, 0x80, 0xE9, 0x99, 0xB2, 0x57, 0xC0, 0x07, 0x96, 0x5C, 0x44, 0x75, 0xA9, 0xD5, 0x31, 0x4C, 0xD6, 0xC1, 0xFB, 0x9F, 0xED, 0xD5, 0x16, 0xE6, 0xB3, 0xC0, 0xDD, 0xD4, 0x04, 0xD6, 0x8D, 0x78, 0xFD, 0x4D, 0xE4, 0x09, 0x31, 0xB1, 0xB8, 0x72, 0xD4, 0xD0, 0x1A, 0x2D, 0x46, 0xC9, 0xB2, 0x93, 0x90, 0x0D, 0x34, 0xEC, 0x91, 0xD3, 0xB6, 0x93, 0xF4, 0xE7, 0x2C, 0x22, 0x8E, 0xD0, 0x29, 0x4F, 0x6D, 0xC9, 0xB7, 0x17, 0x26, 0x0E, 0xBE, 0x75, 0xA4, 0x71, 0xEA, 0x4D, 0x78, 0x00, 0xA3, 0xE7, 0xB7, 0xB4, 0x76, 0xD6, 0x4D, 0xEA, 0x6F, 0x4D, 0xA7, 0x26, 0xB3, 0x76, 0xF0, 0x78, 0x00, 0xDB, 0x5F, 0x83, 0xC0, 0xA3, 0xDC, 0xC2, 0xC7, 0x02, 0x6A, 0x4C, 0x37, 0x8E, 0x88, 0x09, 0x94, 0x88, 0x5D, 0x6F, 0x7A, 0x88, 0x19, 0xD9, 0x1A, 0x2D, 0x50, 0xD1, 0x6D, 0x22, 0xBE, 0x59, 0x2B, 0xED, 0x38, 0x33, 0x04, 0x10, 0xE1, 0x4C, 0xDD, 0xD4, 0xCE, 0x0C, 0x48, 0xD6, 0x2B, 0x77, 0x97, 0xDE, 0x44, 0xC0, 0x7F, 0x26, 0xA7, 0x9E, 0xF3, 0xA5, 0x83, 0x0F, 0x32, 0x1A, 0x35, 0xAC, 0x50, 0x7E, 0x94, 0x3C, 0x6D, 0xE6, 0x3F, 0xE1, 0x36, 0x82, 0x32, 0x25, 0xD6, 0xFC, 0x73, 0xD8, 0x6D, 0x4C, 0x84, 0x39, 0x90, 0x13, 0xE0, 0x64, 0xE6, 0x68, 0x34, 0x92, 0x90, 0x7C, 0x7B, 0x78, 0xAE, 0xF2, 0xAA, 0xB1, 0x80, 0xDC, 0x33, 0xE5, 0xE6, 0xBD, 0xBD, 0x6D, 0x49, 0x0E, 0x3A, 0xA8, 0xBE, 0x8E, 0x82, 0xFA, 0x6C, 0xB1, 0x3B, 0xEA, 0x36, 0x0C, 0x51, 0x0F, 0x9B, 0x4B, 0x5B, 0xA6, 0x64, 0x04, 0x27, 0xAD, 0xDD, 0xF3, 0xD6, 0x6D, 0xED, 0x41, 0xD1, 0xE2, 0xA0, 0x61, 0x31, 0xE9, 0x50, 0x13, 0x68, 0x42, 0x73, 0x2C, 0x27, 0x34, 0x98, 0xD6, 0xA4, 0x7C, 0xED, 0x4E, 0xD1, 0x89, 0xB6, 0xE7, 0x39, 0x36, 0x1F, 0x68, 0xCC, 0xA0, 0xA9, 0x9D, 0x56, 0x02, 0xB9, 0x76, 0x55, 0xAB, 0x26, 0x82, 0xE8, 0x37, 0xDB, 0xD6, 0x88, 0xC1, 0x73, 0xDD, 0x49, 0x50, 0xDD, 0x4C, 0xD4, 0xD3, 0xA3, 0x38, 0xF3, 0xFC, 0xFF, 0x8C, 0x71, 0x16, 0xEB, 0xC6, 0x30, 0xD0, 0x5A, 0xFA, 0xB8, 0xDF, 0x7C, 0x75, 0x60, 0xF4, 0xDE, 0x9A, 0xD9, 0x22, 0x16, 0x26, 0x8E, 0xE1, 0x43, 0xA7, 0x22, 0xC0, 0x34, 0x97, 0xCE, 0x17, 0xEF, 0xE9, 0x8F, 0x67, 0x58, 0x0F, 0x0D, 0xDE, 0xF5, 0x7F, 0x15, 0x25, 0x5E, 0x68, 0x85, 0x6D, 0x39, 0xA4, 0xEB, 0x33, 0x8A, 0x65, 0x33, 0x46, 0xFE, 0xDE, 0x46, 0x66, 0x3A, 0x62, 0x30, 0x7F, 0x65, 0x90, 0xE2, 0xEE, 0x7A, 0xB9, 0x28, 0xAC, 0x5E, 0x8F, 0xA1, 0x63, 0xAA, 0x74, 0xE4, 0x02, 0x55, 0xD8, 0xD2, 0x41, 0x66, 0x8A, 0x1C, 0x71, 0x7E, 0x3F, 0x28, 0x99, 0x43, 0x50, 0xF4, 0x99, 0x08, 0xA3, 0x2E, 0x6F, 0xEC, 0x62, 0x06, 0xBD, 0xF7, 0x93, 0x6D, 0xD2, 0xCF, 0x6A, 0x87, 0xB9, 0x99, 0x40, 0x45, 0x55, 0x2A, 0xCC, 0xE6, 0xEA, 0xF1, 0x29, 0x4E, 0x73, 0x27, 0xA1, 0x3E, 0x6E, 0xAC, 0x16, 0x22, 0x1A, 0x67, 0x6F, 0x60, 0x5D, 0x6D, 0xA6, 0x36, 0x5D, 0x0D, 0xB0, 0x11, 0x35, 0x40, 0x50, 0x13, 0xF8, 0x74, 0x48, 0x1A, 0x68, 0x33, 0x04, 0x55, 0x28, 0x1A, 0x41, 0xE8, 0x3D, 0xF7, 0x6D, 0x20, 0xD1, 0xDF, 0x75, 0xDF, 0xEC, 0xA0, 0x91, 0x7F, 0x3E, 0x94, 0xBE, 0xD2, 0x2D, 0x1E, 0xCE, 0xD8, 0xA9, 0xFC, 0x7B, 0x2A, 0x2E, 0x4A, 0x5B, 0x74, 0xD0, 0xB0, 0xC9, 0x28, 0x2B, 0xD6, 0x12, 0xA4, 0x86, 0x48, 0x99, 0x3F, 0x9F, 0x01, 0x2B, 0xD7, 0x0A, 0x0E, 0x43, 0xDC, 0x3D, 0x1C, 0x0A, 0x16, 0x71, 0x1E, 0xBF, 0x6E, 0xA4, 0x79, 0xDB, 0x94, 0x1F, 0x68, 0xA6, 0x70, 0x1B, 0x57, 0xF7, 0xB8, 0x37, 0xB3, 0x0C, 0x0A, 0x6D, 0x77, 0x11, 0x23, 0xD6, 0xFC, 0x70, 0xBD, 0xBE, 0x24, 0x44, 0x0C, 0xE4, 0xE2, 0x54, 0xA0, 0x70, 0x53, 0x4F, 0x1C, 0x18, 0x13, 0xC5, 0x16, 0x79, 0x12, 0x60, 0xA7, 0x36, 0x89, 0xDF, 0xE1, 0xBE, 0xAD, 0x6E, 0xBF, 0x6A, 0xFF, 0x7E, 0xE4, 0x8D, 0xE1, 0xD5, 0x9C, 0x62, 0x22, 0x8B, 0x38, 0x3E, 0x0A, 0xCA, 0x06, 0x90, 0xF8, 0x05, 0xFE, 0xFD, 0xC5, 0x4F, 0xC4, 0xF9, 0x74, 0xBF, 0xAC, 0xCD, 0xFE, 0x33, 0x21, 0x6C, 0xD2, 0xBC, 0x06, 0xBA, 0x7C, 0x2F, 0x55, 0xD7, 0xA0, 0x70, 0x8C, 0x48, 0x01, 0x4F, 0xF0, 0xC5, 0x35, 0xCD, 0x83, 0xD5, 0x47, 0x08, 0xFD, 0x70, 0x3E, 0x8E, 0xF5, 0x10, 0xFA, 0x60, 0x72, 0xE2, 0x5F, 0xDA, 0xEB, 0x95, 0x33, 0xD4, 0x80, 0x60, 0x53, 0x07, 0x6C, 0xB8, 0xE4, 0xFE, 0x69, 0x46, 0xFD, 0x1A, 0x67, 0x0D, 0x1B, 0xDA, 0x92, 0x31, 0x1D, 0x5E, 0xD5, 0xFA, 0x24, 0x5F, 0xA7, 0x4A, 0x6F, 0x04, 0xAE, 0x66, 0xE3, 0xC9, 0xE0, 0xA7, 0x18, 0x2C, 0xFD, 0xB2, 0x10, 0xE5, 0xA2, 0xF2, 0x8C, 0x95, 0x43, 0x99, 0x64, 0x74, 0x2A, 0x98, 0x7A, 0x16, 0x29, 0x85, 0xDB, 0x91, 0xDF, 0x91, 0xD9, 0x52, 0x9D, 0x8B, 0x85, 0x0B, 0x86, 0x28, 0xA9, 0xC5, 0xC8, 0x45, 0x5B, 0xDB, 0x41, 0x7C, 0x92, 0x72, 0x24, 0xA9, 0xA8, 0xFF, 0xCD, 0xFE, 0x00, 0xC2, 0x28, 0xFA, 0x28, 0x4C, 0x50, 0x52, 0x57, 0x70, 0x98, 0x15, 0x1E, 0x33, 0x78, 0x7F, 0x82, 0x87, 0xCB, 0x0D, 0x24, 0x31, 0x32, 0x45, 0x55, 0x84, 0x8A, 0x8D, 0x9C, 0xDF, 0xE3, 0xE4, 0xF0, 0xF1, 0x42, 0x61, 0xD0, 0xFB, 0xFC, 0x02, 0x3C, 0x59, 0x6C, 0x74, 0x9E, 0xAE, 0xFB, 0x0A, 0x17, 0x84, 0xC8, 0xCF, 0xE5, 0xE7, 0x44, 0x8A, 0x98, 0x9F, 0xD8, 0xD9, 0x43, 0x66, 0xB4, 0xC7, 0xD6, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x0F, 0x1E, 0x23, 0x2B, 0x32, 0x38, 0x3E, }, }, { .name = "Dilithium Round 3, Level 5 (8-7) KAT 0", .version = 0, .keyform = CK_IBM_DILITHIUM_KEYFORM_ROUND3_87, .rho_len = 32, .rho = { 0x1C, 0x0E, 0xE1, 0x11, 0x1B, 0x08, 0x00, 0x3F, 0x28, 0xE6, 0x5E, 0x8B, 0x3B, 0xDE, 0xB0, 0x37, 0xCF, 0x8F, 0x22, 0x1D, 0xFC, 0xDA, 0xF5, 0x95, 0x0E, 0xDB, 0x38, 0xD5, 0x06, 0xD8, 0x5B, 0xEF, }, .seed_len = 32, .seed = { 0x39, 0x4D, 0x16, 0x95, 0x05, 0x9D, 0xFF, 0x40, 0xAE, 0x25, 0x6C, 0x5D, 0x5E, 0xDA, 0xBF, 0xB6, 0x9F, 0x5F, 0x40, 0xF3, 0x7A, 0x58, 0x8F, 0x50, 0x53, 0x2C, 0xA4, 0x08, 0xA8, 0x16, 0x8A, 0xB1, }, .tr_len = 32, .tr = { 0x85, 0xF6, 0x84, 0xAE, 0xB4, 0x01, 0xB9, 0xAA, 0xAF, 0x81, 0x2A, 0x00, 0xE1, 0x24, 0xFF, 0x56, 0xFE, 0xE5, 0x1B, 0xA7, 0xC1, 0x12, 0x82, 0x61, 0x7F, 0x05, 0x72, 0xCC, 0x79, 0x1D, 0xC8, 0x1C, }, .s1_len = 672, .s1 = { 0xC0, 0xA6, 0x71, 0x1A, 0x96, 0x6C, 0x11, 0x31, 0x2A, 0xD9, 0xA8, 0x21, 0xD8, 0x08, 0x65, 0x42, 0xA6, 0x00, 0xA4, 0xB4, 0x2C, 0x19, 0x40, 0x72, 0x02, 0x42, 0x62, 0x81, 0x06, 0x21, 0x0A, 0x43, 0x85, 0x23, 0x31, 0x70, 0x93, 0x08, 0x10, 0x8B, 0x18, 0x8C, 0x02, 0x24, 0x92, 0xC1, 0xB2, 0x84, 0x12, 0xC4, 0x21, 0x8B, 0x04, 0x21, 0x81, 0xC8, 0x61, 0x02, 0x48, 0x05, 0x9C, 0x92, 0x01, 0xC0, 0x34, 0x88, 0x19, 0x32, 0x6C, 0x58, 0x20, 0x46, 0x89, 0x18, 0x68, 0xA2, 0xC2, 0x8D, 0x82, 0x34, 0x6A, 0x1C, 0x09, 0x42, 0x00, 0xA2, 0x8C, 0xE3, 0xA6, 0x49, 0x1C, 0x11, 0x2C, 0xC2, 0x48, 0x12, 0xE0, 0x90, 0x21, 0x91, 0x98, 0x50, 0x62, 0xC0, 0x84, 0x62, 0x24, 0x51, 0xCA, 0x06, 0x2C, 0x64, 0x24, 0x0E, 0x1B, 0xB3, 0x31, 0x24, 0x96, 0x85, 0x4B, 0x46, 0x06, 0xDB, 0x26, 0x68, 0xC3, 0x82, 0x68, 0x44, 0x10, 0x46, 0xC9, 0xB6, 0x21, 0x14, 0x04, 0x81, 0x14, 0x45, 0x50, 0x24, 0x42, 0x08, 0x44, 0x22, 0x71, 0x0B, 0x92, 0x45, 0x9A, 0xA0, 0x81, 0x1A, 0x91, 0x70, 0x9C, 0x24, 0x10, 0x03, 0x95, 0x70, 0x04, 0xC5, 0x04, 0xC8, 0x26, 0x92, 0xD2, 0x92, 0x00, 0xC0, 0xB2, 0x60, 0xC0, 0xA2, 0x68, 0x09, 0x19, 0x0A, 0xA2, 0x30, 0x0E, 0x18, 0x89, 0x69, 0xE0, 0x00, 0x8D, 0xD8, 0x48, 0x62, 0xDA, 0x14, 0x71, 0x20, 0x18, 0x05, 0x19, 0x07, 0x44, 0x04, 0x12, 0x40, 0x9B, 0x12, 0x40, 0x11, 0x80, 0x10, 0xD1, 0x42, 0x81, 0x99, 0x28, 0x50, 0x8B, 0x10, 0x91, 0x02, 0x24, 0x64, 0xA0, 0x20, 0x6D, 0x12, 0x46, 0x21, 0x1C, 0x83, 0x8C, 0x1B, 0x47, 0x69, 0x01, 0x06, 0x90, 0xCC, 0x06, 0x24, 0x81, 0x84, 0x69, 0x20, 0x98, 0x2C, 0x24, 0x12, 0x05, 0x21, 0xB1, 0x50, 0x41, 0x36, 0x02, 0x98, 0x44, 0x6E, 0xD1, 0xA6, 0x31, 0x11, 0x05, 0x6A, 0xD3, 0xA8, 0x40, 0xCA, 0xA8, 0x4C, 0x62, 0xB0, 0x00, 0x03, 0x13, 0x4A, 0x53, 0x34, 0x46, 0x14, 0x19, 0x40, 0x04, 0xC5, 0x4C, 0xE3, 0x06, 0x69, 0x5A, 0xB0, 0x89, 0x61, 0x16, 0x8E, 0xCB, 0x10, 0x80, 0x8B, 0x16, 0x8E, 0xD9, 0x90, 0x64, 0x0B, 0x94, 0x60, 0x24, 0x83, 0x85, 0x1A, 0xB3, 0x04, 0x54, 0x26, 0x22, 0x51, 0xB8, 0x25, 0x1C, 0x42, 0x4A, 0x0B, 0x81, 0x48, 0x42, 0xC4, 0x44, 0x5A, 0x10, 0x20, 0x23, 0x80, 0x84, 0x09, 0xB7, 0x25, 0x4C, 0xC6, 0x48, 0x14, 0x85, 0x4D, 0x19, 0x38, 0x0E, 0x60, 0x16, 0x51, 0xD8, 0x32, 0x6A, 0x0A, 0x91, 0x89, 0x08, 0xC1, 0x70, 0xE0, 0x96, 0x4D, 0x18, 0x46, 0x8C, 0x01, 0x32, 0x8D, 0x91, 0xC4, 0x05, 0x4A, 0x00, 0x61, 0x23, 0x08, 0x68, 0xA2, 0x10, 0x42, 0x10, 0xA8, 0x61, 0x13, 0x06, 0x21, 0x8A, 0x24, 0x8E, 0x62, 0x06, 0x89, 0xC9, 0xB2, 0x45, 0x08, 0x27, 0x84, 0x51, 0x20, 0x0D, 0x98, 0x04, 0x66, 0xDC, 0x42, 0x05, 0x44, 0x24, 0x85, 0x24, 0x26, 0x28, 0x22, 0x21, 0x61, 0x20, 0x16, 0x09, 0x0B, 0xA6, 0x2C, 0x0A, 0x11, 0x44, 0xE0, 0x92, 0x81, 0x58, 0x48, 0x0D, 0x42, 0x22, 0x10, 0xA0, 0x06, 0x09, 0x8B, 0x24, 0x6E, 0x81, 0x28, 0x8C, 0xC0, 0x24, 0x80, 0x90, 0x30, 0x8D, 0x84, 0x36, 0x40, 0x4C, 0xA6, 0x84, 0x50, 0x04, 0x24, 0x94, 0xB6, 0x8D, 0xA2, 0x92, 0x6D, 0x18, 0xB3, 0x44, 0xA0, 0x00, 0x85, 0xE3, 0xB8, 0x05, 0x14, 0x05, 0x04, 0xA4, 0xC2, 0x90, 0x84, 0x22, 0x81, 0xC3, 0x26, 0x2D, 0x0B, 0x20, 0x66, 0xCC, 0x90, 0x31, 0x98, 0x38, 0x28, 0x10, 0x16, 0x6C, 0xC1, 0x34, 0x45, 0xC0, 0x10, 0x22, 0x24, 0xC6, 0x88, 0x03, 0x46, 0x32, 0xD8, 0x40, 0x90, 0x1C, 0x20, 0x68, 0x04, 0x15, 0x28, 0x9A, 0x18, 0x81, 0x44, 0x98, 0x8D, 0x9C, 0x20, 0x6E, 0x9C, 0x30, 0x2C, 0xC1, 0xB8, 0x20, 0x61, 0x42, 0x21, 0x08, 0x03, 0x10, 0xA0, 0xC2, 0x8C, 0x58, 0x12, 0x85, 0x53, 0x20, 0x4C, 0x03, 0x30, 0x81, 0x4C, 0xA4, 0x8D, 0x44, 0xC0, 0x8D, 0x51, 0x40, 0x4C, 0x1C, 0xA7, 0x2C, 0x44, 0x08, 0x65, 0xA0, 0x38, 0x40, 0xDA, 0x20, 0x80, 0x81, 0x06, 0x85, 0x8C, 0x26, 0x0D, 0xE2, 0xA8, 0x8C, 0x9C, 0x44, 0x11, 0x59, 0x42, 0x28, 0xC4, 0x26, 0x04, 0x44, 0x14, 0x26, 0xA1, 0x42, 0x64, 0x08, 0xC0, 0x85, 0x11, 0x01, 0x86, 0x9B, 0x48, 0x31, 0x99, 0xB2, 0x0C, 0x80, 0x46, 0x44, 0x59, 0xA8, 0x8C, 0x00, 0x42, 0x08, 0x98, 0x82, 0x90, 0x0A, 0xB5, 0x45, 0x62, 0x24, 0x48, 0x12, 0x96, 0x05, 0x44, 0x12, 0x46, 0x00, 0xC8, 0x88, 0x13, 0xA0, 0x61, 0xE1, 0x28, 0x4D, 0x0A, 0xB9, 0x91, 0x4B, 0x96, 0x20, 0x99, 0xB8, 0x44, 0x00, 0x31, 0x4E, 0x98, 0x12, 0x85, 0x00, 0xB6, 0x01, 0x83, 0xA0, 0x0D, 0x14, 0x15, 0x0E, 0x18, 0x81, 0x10, 0x19, 0x01, 0x22, 0x4A, 0x06, 0x68, }, .s2_len = 768, .s2 = { 0x1A, 0x49, 0x8D, 0xE1, 0xA2, 0x84, 0x11, 0xC6, 0x31, 0x21, 0x26, 0x25, 0x91, 0xA0, 0x6D, 0x03, 0x05, 0x24, 0xA1, 0xB6, 0x08, 0x94, 0x44, 0x72, 0x43, 0x34, 0x12, 0x5B, 0xB4, 0x20, 0x41, 0xB6, 0x50, 0xD0, 0x88, 0x8D, 0x0B, 0x07, 0x4D, 0x1C, 0x94, 0x64, 0x4C, 0x20, 0x8E, 0x8B, 0x88, 0x08, 0xE0, 0x30, 0x09, 0x44, 0x20, 0x05, 0x49, 0x86, 0x4D, 0x03, 0x13, 0x4E, 0x19, 0xC9, 0x84, 0x09, 0x37, 0x61, 0x1A, 0x43, 0x68, 0x4A, 0x80, 0x90, 0x02, 0x04, 0x31, 0x1C, 0x17, 0x42, 0x18, 0x40, 0x80, 0xC8, 0x30, 0x8E, 0xE1, 0xA2, 0x41, 0xC3, 0x34, 0x04, 0xA3, 0x28, 0x22, 0x51, 0x24, 0x71, 0x82, 0x84, 0x01, 0x1B, 0xC0, 0x64, 0x23, 0x47, 0x72, 0x82, 0x14, 0x66, 0x5B, 0x38, 0x68, 0xE1, 0xC6, 0x29, 0x9B, 0x90, 0x40, 0x60, 0x38, 0x86, 0x83, 0xA0, 0x40, 0x84, 0x20, 0x04, 0x4C, 0x94, 0x01, 0x10, 0x25, 0x8D, 0x82, 0x02, 0x4D, 0x9A, 0xB2, 0x69, 0x20, 0x15, 0x10, 0x60, 0x46, 0x2D, 0xC2, 0x14, 0x2E, 0x0C, 0xA8, 0x2C, 0x54, 0x16, 0x22, 0x03, 0x46, 0x89, 0x92, 0x06, 0x60, 0x08, 0x07, 0x82, 0x0B, 0x47, 0x44, 0x48, 0x98, 0x09, 0x09, 0x43, 0x0E, 0xE4, 0x32, 0x0A, 0x1A, 0xC0, 0x65, 0xC0, 0xA4, 0x21, 0x44, 0xB2, 0x91, 0x58, 0xC6, 0x04, 0x11, 0x45, 0x20, 0xC4, 0xA4, 0x21, 0x02, 0xA0, 0x70, 0x21, 0x22, 0x26, 0x23, 0xB2, 0x68, 0x4B, 0x08, 0x40, 0x01, 0x03, 0x91, 0x8B, 0x34, 0x81, 0x1A, 0x04, 0x04, 0x0C, 0xB0, 0x05, 0xC2, 0x92, 0x69, 0x90, 0x14, 0x68, 0x04, 0x46, 0x49, 0x14, 0x83, 0x49, 0xA2, 0x34, 0x89, 0x19, 0xC7, 0x28, 0x94, 0x44, 0x71, 0x00, 0xC9, 0x49, 0x58, 0x38, 0x72, 0x02, 0x02, 0x90, 0x42, 0xC6, 0x4C, 0x0C, 0x17, 0x32, 0x48, 0xC6, 0x8C, 0x59, 0x28, 0x31, 0x09, 0xB7, 0x28, 0xCB, 0x48, 0x0E, 0x9A, 0x22, 0x85, 0x1C, 0xB9, 0x11, 0xE3, 0xC6, 0x30, 0xC3, 0x48, 0x28, 0xCC, 0xB8, 0x28, 0x03, 0xC8, 0x08, 0xA4, 0xB6, 0x04, 0xD0, 0x18, 0x8C, 0x60, 0x18, 0x72, 0xD0, 0x20, 0x92, 0x82, 0x02, 0x2E, 0x59, 0x18, 0x89, 0x08, 0x19, 0x32, 0xC9, 0x06, 0x52, 0x60, 0x90, 0x8C, 0x09, 0x80, 0x29, 0xA4, 0xB4, 0x8C, 0x8C, 0x34, 0x82, 0x08, 0x42, 0x10, 0x02, 0x00, 0x08, 0x13, 0x01, 0x50, 0x83, 0xB6, 0x08, 0x41, 0x94, 0x4D, 0x1B, 0x49, 0x6C, 0x19, 0x39, 0x11, 0xCB, 0x32, 0x41, 0x02, 0xC0, 0x65, 0x48, 0x88, 0x91, 0x9B, 0x98, 0x61, 0x08, 0xB5, 0x04, 0x49, 0xB4, 0x45, 0xD3, 0x30, 0x01, 0x98, 0x04, 0x6D, 0x53, 0x00, 0x89, 0x42, 0x32, 0x60, 0x8C, 0xB0, 0x90, 0x64, 0x88, 0x68, 0xD4, 0x32, 0x45, 0x48, 0x14, 0x71, 0x14, 0x98, 0x05, 0x81, 0x00, 0x22, 0xDB, 0x44, 0x69, 0xD9, 0x24, 0x89, 0x11, 0x41, 0x12, 0x09, 0x19, 0x50, 0x92, 0xA0, 0x84, 0xC0, 0x34, 0x22, 0x4A, 0x24, 0x10, 0xDA, 0xC8, 0x09, 0xD2, 0xA8, 0x0D, 0x22, 0x85, 0x21, 0x8B, 0xC8, 0x90, 0xC1, 0x00, 0x66, 0x5C, 0xC0, 0x25, 0x99, 0xA4, 0x61, 0x1A, 0xA4, 0x11, 0x0A, 0x24, 0x28, 0x5B, 0xC4, 0x48, 0x13, 0x14, 0x89, 0x63, 0x92, 0x61, 0x20, 0x30, 0x0C, 0x40, 0x02, 0x25, 0x21, 0x88, 0x28, 0x24, 0x01, 0x8C, 0x10, 0x81, 0x6D, 0x4C, 0x42, 0x49, 0x01, 0x22, 0x2D, 0xC1, 0x96, 0x0C, 0x08, 0x48, 0x90, 0x01, 0xC1, 0x30, 0x23, 0xC1, 0x89, 0xA1, 0xC4, 0x64, 0x12, 0x97, 0x09, 0xCC, 0x90, 0x91, 0x60, 0x20, 0x66, 0x1B, 0x96, 0x48, 0x82, 0xA8, 0x71, 0x91, 0xC0, 0x65, 0xDB, 0xC2, 0x01, 0x84, 0x36, 0x0A, 0x09, 0x24, 0x29, 0x52, 0x10, 0x4E, 0xDB, 0x24, 0x0A, 0x61, 0x02, 0x10, 0x20, 0x38, 0x25, 0x98, 0x34, 0x60, 0x82, 0x24, 0x30, 0xC4, 0x12, 0x49, 0xC0, 0xA2, 0x05, 0x0C, 0x08, 0x85, 0x93, 0x28, 0x09, 0x63, 0xB2, 0x05, 0x23, 0x96, 0x20, 0x42, 0x12, 0x0D, 0xD1, 0xC0, 0x10, 0x08, 0xC5, 0x40, 0xC1, 0x82, 0x65, 0x1B, 0x15, 0x92, 0xA4, 0x14, 0x51, 0x84, 0x04, 0x26, 0x53, 0x42, 0x52, 0x24, 0x23, 0x6D, 0x9C, 0x28, 0x4E, 0x50, 0x14, 0x05, 0x8C, 0x20, 0x80, 0x24, 0x26, 0x65, 0x61, 0x44, 0x4C, 0x02, 0x11, 0x20, 0xC8, 0xC0, 0x4C, 0x18, 0xA0, 0x0D, 0x00, 0x38, 0x70, 0x99, 0x16, 0x12, 0xA1, 0x16, 0x40, 0xC4, 0x18, 0x45, 0x09, 0x93, 0x88, 0x4C, 0x82, 0x21, 0xCB, 0xB2, 0x81, 0x21, 0x26, 0x61, 0xD1, 0xA8, 0x24, 0x41, 0x30, 0x84, 0x08, 0x80, 0x71, 0x00, 0xC6, 0x20, 0x52, 0x42, 0x92, 0x89, 0x24, 0x12, 0xA4, 0x26, 0x89, 0xE3, 0xB0, 0x88, 0x21, 0x98, 0x8C, 0x11, 0x96, 0x2C, 0xE1, 0x96, 0x20, 0x51, 0xC2, 0x81, 0x20, 0x91, 0x80, 0x94, 0x16, 0x6E, 0x14, 0x94, 0x60, 0x20, 0xC9, 0x45, 0x9B, 0x22, 0x45, 0xA2, 0x38, 0x20, 0xC0, 0x36, 0x08, 0x60, 0x90, 0x8D, 0x41, 0x06, 0x02, 0x5B, 0x06, 0x6E, 0xE1, 0x40, 0x0A, 0x89, 0x34, 0x6C, 0x1A, 0xB2, 0x69, 0xA4, 0x16, 0x10, 0x03, 0x33, 0x0E, 0x1A, 0x42, 0x28, 0x03, 0x19, 0x6E, 0x11, 0x44, 0x84, 0x0B, 0x24, 0x4A, 0x1C, 0x16, 0x6A, 0x19, 0x98, 0x40, 0x03, 0xA2, 0x85, 0x41, 0xC0, 0x8C, 0xD2, 0x22, 0x61, 0x0C, 0x82, 0x10, 0x5A, 0xB0, 0x0D, 0x21, 0x14, 0x72, 0x5A, 0x82, 0x80, 0x02, 0x86, 0x10, 0x0C, 0x27, 0x26, 0x5C, 0x48, 0x6E, 0xC9, 0x40, 0x6C, 0x1B, 0x49, 0x04, 0xE4, 0xB8, 0x49, 0xDB, 0x32, 0x8A, 0x9C, 0x24, 0x2C, 0x40, 0x38, 0x80, 0x22, 0xA9, 0x45, }, .t0_len = 3328, .t0 = { 0x12, 0x29, 0xA4, 0xE6, 0x5E, 0xD3, 0x1C, 0x79, 0x3E, 0xCB, 0x5B, 0x89, 0xC5, 0x5D, 0xC3, 0x33, 0xA2, 0x77, 0xBF, 0x5C, 0x41, 0x28, 0xA2, 0x14, 0x01, 0xAF, 0xA8, 0xD4, 0x28, 0xC8, 0x21, 0xE9, 0x7A, 0xEA, 0x05, 0xB3, 0xAD, 0x29, 0x23, 0xBD, 0x97, 0x10, 0x87, 0x1C, 0xE8, 0xB3, 0xB1, 0x1A, 0x71, 0x1C, 0x9A, 0xAC, 0xBA, 0x10, 0x8C, 0xAF, 0x43, 0xA1, 0x72, 0xD6, 0x59, 0x94, 0x01, 0xDB, 0x89, 0x68, 0x1D, 0x0B, 0x87, 0x4E, 0xC3, 0x57, 0xA5, 0x29, 0x5C, 0x0A, 0x08, 0xD5, 0x89, 0xC4, 0x53, 0x9F, 0x9C, 0x59, 0xF3, 0x3F, 0x06, 0x44, 0x64, 0x41, 0x20, 0x49, 0x84, 0xE1, 0xF9, 0x87, 0x3C, 0x1F, 0x97, 0x75, 0xB9, 0x7E, 0xD4, 0x00, 0xC9, 0x98, 0xB0, 0x51, 0x62, 0xB6, 0x18, 0x98, 0x61, 0xF2, 0x8D, 0xAE, 0x36, 0xC2, 0x13, 0x37, 0x65, 0x71, 0x11, 0x76, 0xCA, 0xAF, 0x5A, 0x1D, 0xCB, 0x2A, 0x0E, 0x22, 0x3A, 0x5F, 0x07, 0x9B, 0x07, 0x41, 0xA5, 0xE6, 0xD5, 0x10, 0xE5, 0x87, 0x32, 0xDC, 0x03, 0x59, 0xD7, 0x9A, 0x77, 0x41, 0xA3, 0x79, 0x1C, 0xA6, 0x50, 0x4F, 0x07, 0xCA, 0x8A, 0x2C, 0x03, 0x12, 0x71, 0x18, 0x45, 0x20, 0xEB, 0x76, 0xA0, 0x0B, 0x9B, 0x46, 0x26, 0xDB, 0x37, 0x34, 0x1C, 0x71, 0x80, 0x65, 0xED, 0x95, 0xFE, 0x4C, 0xB0, 0x54, 0xBF, 0xE7, 0x1E, 0x80, 0x26, 0x0D, 0x21, 0x90, 0x7B, 0x9B, 0xFA, 0xEC, 0x86, 0xAC, 0x83, 0xA4, 0x85, 0x63, 0xC0, 0xB9, 0xB2, 0xEF, 0x4B, 0x9B, 0x4E, 0xCB, 0xCB, 0x2F, 0x12, 0x91, 0x98, 0x4E, 0x89, 0xE8, 0x4C, 0x55, 0x69, 0x06, 0x47, 0xE2, 0x65, 0x47, 0xD7, 0x3E, 0x4C, 0xB7, 0xF0, 0xE0, 0x6E, 0xFF, 0xC3, 0xC4, 0x79, 0xE2, 0x56, 0x8E, 0x74, 0x64, 0xEA, 0xBF, 0x1D, 0x1C, 0x4E, 0xFE, 0x21, 0x11, 0x12, 0xE6, 0x2B, 0xEA, 0x8B, 0x85, 0x5F, 0x50, 0xD7, 0x16, 0x51, 0x32, 0x9C, 0x00, 0xEF, 0x61, 0x9F, 0x53, 0x7E, 0x45, 0x4B, 0x09, 0x5A, 0x9D, 0xF6, 0xA8, 0x59, 0x0E, 0x5B, 0xBA, 0xA1, 0x5C, 0x9E, 0x64, 0xE7, 0x01, 0xE3, 0x74, 0x69, 0x74, 0x94, 0x62, 0xA2, 0x11, 0x95, 0x41, 0xE7, 0x55, 0x49, 0xD0, 0x56, 0xA2, 0x5B, 0xBC, 0xEE, 0x11, 0xCD, 0x9F, 0xC6, 0x72, 0x42, 0x2A, 0xD2, 0xAE, 0x97, 0x91, 0x3D, 0x30, 0xBE, 0x3C, 0xD8, 0x5F, 0x58, 0xCF, 0xA9, 0x04, 0xF4, 0x43, 0xAC, 0x3A, 0x8D, 0xFD, 0xBC, 0x2C, 0xC9, 0xC8, 0xC3, 0x9B, 0x24, 0x4E, 0xE7, 0xE0, 0xD9, 0x5B, 0xEC, 0x69, 0x27, 0xA2, 0xB0, 0xB9, 0x4E, 0x97, 0x3F, 0x98, 0x12, 0x24, 0x46, 0x43, 0x14, 0x6E, 0x19, 0x01, 0x3B, 0x7F, 0xE1, 0x71, 0x14, 0xA0, 0xF3, 0x9F, 0x92, 0x28, 0x6B, 0xE0, 0xF0, 0xEE, 0x39, 0x6F, 0xB7, 0x4C, 0x76, 0xC9, 0x10, 0x04, 0xB8, 0x27, 0xD2, 0x18, 0x95, 0x1C, 0x77, 0xBD, 0xB8, 0x15, 0x90, 0xAE, 0xDF, 0xEA, 0x9E, 0x62, 0xBE, 0x0F, 0x22, 0xAF, 0xF5, 0x5E, 0x36, 0xAB, 0x57, 0x2D, 0xF1, 0x3A, 0xB9, 0xF5, 0xEA, 0xFC, 0xBC, 0x34, 0xDF, 0x26, 0x6F, 0xE1, 0x60, 0xC6, 0xB6, 0x35, 0xB0, 0xC3, 0xB6, 0x3C, 0x89, 0x29, 0x20, 0x18, 0x5F, 0x11, 0x2B, 0x96, 0x99, 0x8B, 0x5B, 0x5B, 0xB9, 0x73, 0xB3, 0x90, 0x08, 0xB2, 0xF0, 0x43, 0x40, 0x35, 0xD4, 0x3B, 0xD2, 0xE4, 0x9F, 0x2C, 0x17, 0x45, 0x20, 0xD3, 0xA8, 0x98, 0x54, 0xCD, 0x82, 0x50, 0xD6, 0x20, 0x0A, 0x1E, 0xB5, 0x10, 0x79, 0x22, 0x46, 0x56, 0xD0, 0xB3, 0x34, 0xCE, 0xE3, 0x43, 0x0B, 0x87, 0xE1, 0xFF, 0x90, 0x4D, 0x10, 0x34, 0xC2, 0xD8, 0xA7, 0x04, 0x7B, 0x2D, 0x22, 0x56, 0x33, 0x19, 0x04, 0x10, 0x01, 0x2C, 0x16, 0x1C, 0x76, 0x8C, 0x1F, 0xF8, 0xFC, 0x17, 0x9A, 0x44, 0x68, 0x64, 0xDF, 0x93, 0xE0, 0x9D, 0x1E, 0x6C, 0x29, 0x48, 0x7C, 0xAB, 0x04, 0x4E, 0xF8, 0x68, 0xD4, 0x31, 0xB1, 0x76, 0x31, 0x84, 0xAD, 0xCB, 0x39, 0x51, 0x6D, 0xD1, 0x27, 0x6B, 0xD8, 0x41, 0xEC, 0x49, 0x2A, 0x84, 0x51, 0x77, 0x4E, 0xDA, 0x10, 0x6E, 0x73, 0x21, 0xED, 0x5A, 0x62, 0x25, 0xC3, 0x53, 0x24, 0xC5, 0x10, 0x66, 0x3B, 0x9B, 0xEA, 0x05, 0xF1, 0xDB, 0xC8, 0xD5, 0xDB, 0x69, 0xA7, 0x7E, 0xCE, 0x3E, 0x42, 0x65, 0xC5, 0xE8, 0x10, 0x69, 0x86, 0x45, 0x80, 0xB5, 0x28, 0xCC, 0x2C, 0xBB, 0xFB, 0xDE, 0x62, 0x5A, 0xF2, 0xC1, 0xC5, 0xCB, 0x06, 0xDD, 0x80, 0x58, 0x54, 0x04, 0x96, 0x4D, 0x21, 0x11, 0x4B, 0x8B, 0x13, 0xCA, 0xFB, 0x6D, 0xBE, 0x1B, 0x42, 0x8E, 0xBC, 0x87, 0x17, 0xCC, 0xD1, 0x1B, 0xFB, 0x34, 0x72, 0x60, 0xAA, 0x70, 0x1B, 0xF2, 0x28, 0x35, 0xB3, 0xF1, 0x06, 0x2E, 0xAD, 0x36, 0xAC, 0xB9, 0x6D, 0x74, 0x96, 0xF7, 0x2A, 0xA5, 0xFF, 0x1A, 0x13, 0x04, 0xBC, 0x02, 0xE3, 0x58, 0xE6, 0x0B, 0x1C, 0x82, 0x30, 0xBF, 0x8F, 0xFA, 0xFD, 0x36, 0xE0, 0xF6, 0xB2, 0xE3, 0xD8, 0x58, 0x2F, 0xD3, 0xA4, 0x38, 0x11, 0xAC, 0x24, 0xD0, 0x60, 0x08, 0x10, 0x35, 0x42, 0x87, 0x8C, 0xB5, 0xCE, 0x99, 0xF8, 0x92, 0x0C, 0xC8, 0x02, 0xDA, 0x4E, 0xD2, 0x18, 0x39, 0x56, 0x83, 0x4D, 0xA4, 0xC7, 0x19, 0x55, 0x0D, 0xB2, 0x47, 0x95, 0xAC, 0xE0, 0x9D, 0x88, 0xCA, 0x30, 0x43, 0xAF, 0xCC, 0xC9, 0xAB, 0x0F, 0x03, 0x06, 0x67, 0x1F, 0xD1, 0xF2, 0x50, 0x95, 0x7C, 0xC6, 0x24, 0x64, 0xC9, 0xEA, 0x5E, 0x44, 0x4C, 0x6E, 0xB4, 0x76, 0xD0, 0x92, 0x46, 0x56, 0x08, 0xFE, 0xB6, 0xB7, 0xD5, 0x39, 0x8A, 0x02, 0x9E, 0x1E, 0xEA, 0xE5, 0x0D, 0xB5, 0xF9, 0xF9, 0x95, 0x50, 0xA9, 0x66, 0x83, 0x43, 0xEF, 0x29, 0x70, 0xF2, 0x25, 0x31, 0x67, 0x8E, 0x36, 0x71, 0x3B, 0x81, 0xCB, 0x36, 0x33, 0xF1, 0xDD, 0xD4, 0x67, 0x69, 0x82, 0x6E, 0x43, 0x60, 0xDE, 0x19, 0xA5, 0x63, 0x18, 0xD9, 0xEB, 0x59, 0xF9, 0x7A, 0x9B, 0x3E, 0xD2, 0x2B, 0xFD, 0x89, 0x50, 0x11, 0x26, 0x29, 0x5E, 0x89, 0xFC, 0x73, 0x5C, 0x36, 0x19, 0xD7, 0x7F, 0x6F, 0xB9, 0x35, 0xC2, 0xFB, 0x46, 0xED, 0xD0, 0xA4, 0xD2, 0x92, 0x17, 0x77, 0xB0, 0xEF, 0xCD, 0x58, 0xBE, 0xDC, 0xEB, 0x9E, 0xA5, 0x66, 0x6B, 0x18, 0xDF, 0xAC, 0xF9, 0xBF, 0x76, 0x33, 0x3C, 0x5E, 0xDA, 0xC7, 0x2B, 0x04, 0xE6, 0x57, 0xE4, 0xE0, 0x86, 0x5E, 0x04, 0x3A, 0x64, 0x68, 0xC5, 0xE6, 0x9D, 0x5B, 0xCB, 0xE5, 0x84, 0x2B, 0xF4, 0x5B, 0xEE, 0x77, 0x91, 0x5F, 0x05, 0x71, 0xD1, 0x50, 0xD6, 0x06, 0xA6, 0xF2, 0xAC, 0x37, 0x37, 0x92, 0x90, 0x88, 0x91, 0xBA, 0x85, 0xF4, 0x5C, 0xB4, 0x09, 0xD9, 0x63, 0xE4, 0x9B, 0x5B, 0x96, 0x97, 0x8A, 0x19, 0x39, 0x16, 0x0A, 0x8D, 0xB9, 0xD6, 0x3C, 0x4E, 0xA0, 0xD6, 0xA7, 0xD0, 0x93, 0x70, 0xAC, 0x1C, 0x24, 0x49, 0x8D, 0x21, 0xA8, 0xD5, 0xB7, 0x64, 0xA3, 0x9A, 0x41, 0x2E, 0x5B, 0x54, 0xBD, 0x1C, 0x96, 0x4D, 0x24, 0x4A, 0x45, 0x55, 0x64, 0x5F, 0x1F, 0x90, 0x53, 0xF8, 0xBB, 0x33, 0xF6, 0xF7, 0x51, 0x46, 0x80, 0x7B, 0x4E, 0x9E, 0x07, 0xB2, 0x3C, 0x98, 0x06, 0xFF, 0x75, 0x72, 0x46, 0x9C, 0x09, 0x43, 0x99, 0xBA, 0x97, 0x79, 0xB9, 0x62, 0xB4, 0xC8, 0xA9, 0x57, 0xF8, 0x69, 0x91, 0x1E, 0xB1, 0x3F, 0x14, 0x02, 0x24, 0xAC, 0x4E, 0xE7, 0x62, 0x01, 0xC0, 0x2F, 0x24, 0xC7, 0xED, 0xC3, 0xA9, 0x80, 0x89, 0x9A, 0x30, 0xBA, 0xD2, 0xB1, 0x2D, 0x57, 0x28, 0xF0, 0x97, 0x17, 0x6D, 0x00, 0x17, 0xF3, 0x47, 0x3D, 0x2F, 0xBB, 0xD4, 0x3C, 0xC2, 0x3A, 0x50, 0x1E, 0x81, 0xE3, 0x81, 0xBE, 0x01, 0x79, 0xBF, 0x68, 0xCA, 0x50, 0xFD, 0x23, 0x55, 0xCA, 0x7B, 0x64, 0xF5, 0x3E, 0x0C, 0x7D, 0x5B, 0xCA, 0x4E, 0x7B, 0xE6, 0x91, 0x63, 0xE3, 0x16, 0xFE, 0xBB, 0x49, 0xA9, 0x34, 0x0F, 0x15, 0x7B, 0xAC, 0x3B, 0x0B, 0xD8, 0x4A, 0x3B, 0x02, 0x7A, 0x2F, 0xE4, 0x4E, 0xC2, 0x66, 0xA8, 0xCE, 0x4A, 0x17, 0x1B, 0x91, 0x82, 0x8F, 0x45, 0x43, 0x02, 0xAA, 0x9B, 0x66, 0x49, 0x67, 0xE6, 0x7D, 0xB3, 0x8A, 0xA4, 0xE3, 0xBC, 0x35, 0x3D, 0x15, 0x18, 0xA7, 0xFE, 0xC1, 0x18, 0x8B, 0x7D, 0x5B, 0x7E, 0x19, 0x52, 0x1F, 0x1A, 0x28, 0x77, 0x00, 0x69, 0x89, 0xB0, 0xFE, 0x91, 0x89, 0x46, 0xB7, 0x59, 0x3E, 0xD1, 0x51, 0x20, 0xBF, 0x7D, 0x23, 0xF9, 0x92, 0x10, 0xDD, 0xB7, 0x6D, 0xAF, 0x86, 0xE2, 0x37, 0xB2, 0x37, 0x9C, 0xA1, 0x2E, 0x55, 0x63, 0x6C, 0x83, 0x40, 0x8E, 0x6D, 0x2B, 0x35, 0x85, 0xFA, 0xBC, 0xBC, 0x0F, 0x6C, 0x48, 0x76, 0x7E, 0x36, 0x3A, 0xC8, 0x47, 0xCC, 0xC6, 0x7E, 0xB7, 0xC9, 0x37, 0xBB, 0xD9, 0x41, 0x10, 0x0D, 0x78, 0x77, 0x4A, 0xE1, 0xF4, 0x43, 0x39, 0xDC, 0xDC, 0xB0, 0xE7, 0x00, 0xAC, 0x10, 0x8D, 0xAA, 0x92, 0xCD, 0x9E, 0xA1, 0x9F, 0x82, 0x38, 0xF2, 0x86, 0x76, 0xFE, 0xE7, 0xBD, 0x1B, 0x9F, 0x37, 0xA6, 0xCA, 0x17, 0xD7, 0xCF, 0x40, 0x42, 0xFE, 0x39, 0xDD, 0x93, 0x77, 0x82, 0x6C, 0x4C, 0xAB, 0x29, 0x32, 0xE1, 0x2D, 0xE5, 0x3B, 0x08, 0x1A, 0x6C, 0x25, 0xC0, 0xF4, 0x7D, 0xA3, 0xD9, 0x16, 0x83, 0x1E, 0x42, 0x47, 0xD0, 0x97, 0x81, 0x1E, 0x1A, 0x08, 0x70, 0xCB, 0x61, 0xF4, 0xAC, 0xA1, 0x27, 0xEA, 0xF8, 0x5A, 0x9C, 0xA6, 0x66, 0xFA, 0x6C, 0x36, 0x39, 0x8F, 0x0E, 0x74, 0x20, 0xCA, 0x98, 0x95, 0xC6, 0x3A, 0x1A, 0xC4, 0xDB, 0x49, 0xA1, 0xD7, 0x5F, 0x56, 0x46, 0x4C, 0x1E, 0x0C, 0xF9, 0x28, 0x3A, 0x45, 0x44, 0x56, 0x50, 0xF9, 0x5F, 0xAD, 0xF6, 0xC8, 0x8D, 0xB3, 0xCE, 0x7C, 0x0E, 0x5D, 0x0E, 0x72, 0x61, 0xE8, 0x04, 0xC0, 0x3A, 0x41, 0x9E, 0x4C, 0xC2, 0x50, 0x10, 0x99, 0xCA, 0x53, 0x63, 0x44, 0x60, 0x7B, 0x07, 0xE8, 0x25, 0x32, 0x3A, 0xD3, 0x0B, 0xE7, 0x5F, 0x84, 0xE6, 0xC5, 0xBE, 0x23, 0x8E, 0xC7, 0x86, 0x17, 0xA0, 0xA2, 0x34, 0x14, 0xC7, 0xF8, 0xCD, 0x60, 0x91, 0x30, 0x31, 0xBC, 0x93, 0x01, 0x78, 0x6D, 0x5C, 0x19, 0xD9, 0x30, 0xB5, 0x06, 0xC4, 0x95, 0x98, 0x32, 0x23, 0xEC, 0x1B, 0xF7, 0x87, 0xC3, 0x3D, 0x22, 0x8A, 0x11, 0x0E, 0x57, 0x42, 0x87, 0x73, 0xE3, 0x4F, 0x12, 0x66, 0x3D, 0x11, 0xC1, 0x55, 0xDF, 0xCE, 0x38, 0x0D, 0x65, 0x76, 0x4C, 0x26, 0x59, 0xEA, 0xA0, 0xA1, 0xA2, 0xE7, 0x64, 0xEB, 0xB5, 0xA9, 0xE5, 0xA7, 0x19, 0x2E, 0x90, 0x86, 0xA6, 0xDE, 0x4A, 0x38, 0xFC, 0xFD, 0x04, 0x12, 0x42, 0x42, 0x60, 0x62, 0x0C, 0x1E, 0x56, 0x7A, 0x2D, 0x8B, 0x1A, 0xF3, 0x55, 0x48, 0x19, 0xA0, 0x0D, 0x5C, 0x7E, 0x56, 0x66, 0xD0, 0xE6, 0x56, 0xF8, 0xD4, 0x5C, 0x67, 0xC5, 0x44, 0x8D, 0xAB, 0x5E, 0xB6, 0xE6, 0x02, 0x93, 0x79, 0xC4, 0x7A, 0x24, 0xD0, 0x11, 0xF5, 0x6E, 0x5F, 0xAA, 0x49, 0xFC, 0x6B, 0xB2, 0xD7, 0x50, 0xED, 0x4C, 0x95, 0xF8, 0x35, 0x38, 0x4F, 0x2F, 0xAA, 0xB1, 0x3C, 0x1C, 0xCA, 0x71, 0xA1, 0xEB, 0xD2, 0x29, 0x9E, 0x96, 0x32, 0xE5, 0x29, 0xCE, 0x77, 0x14, 0x9F, 0x5F, 0xAC, 0x31, 0xAB, 0x28, 0xDC, 0xC7, 0x06, 0x70, 0xBB, 0xAB, 0x9F, 0x7B, 0x6F, 0xFE, 0xAA, 0xBC, 0x7D, 0xC4, 0x51, 0x3D, 0x8F, 0xAC, 0x4B, 0xCF, 0x7E, 0x5E, 0x72, 0x97, 0xDB, 0x69, 0xE4, 0xB6, 0x25, 0x38, 0xF9, 0xCA, 0xBD, 0x90, 0x2B, 0x10, 0x07, 0xE3, 0xBA, 0xF6, 0x7F, 0x94, 0x3D, 0xFD, 0xC6, 0xAA, 0x75, 0x62, 0xFA, 0xBB, 0x1E, 0x8F, 0xAC, 0xF8, 0x11, 0xC7, 0x63, 0x35, 0x79, 0x0A, 0x16, 0xF2, 0x1E, 0xCB, 0x72, 0xFC, 0x1B, 0xA9, 0x42, 0x76, 0xB2, 0x09, 0x80, 0x7E, 0xA5, 0x2E, 0x74, 0xF2, 0xB6, 0xCA, 0x0B, 0x3F, 0xDC, 0x30, 0x50, 0x1F, 0x63, 0x10, 0xEC, 0x99, 0x55, 0xB0, 0x51, 0x81, 0x8D, 0xAE, 0x10, 0x80, 0xFD, 0x4D, 0xD2, 0x4C, 0x72, 0x2D, 0x68, 0xDE, 0x33, 0xEA, 0x76, 0x9B, 0x4E, 0x63, 0x70, 0x07, 0xCF, 0xDC, 0xE1, 0x80, 0x4A, 0xC2, 0xA7, 0x71, 0xF8, 0x8F, 0x59, 0xBA, 0xCE, 0xDB, 0x4D, 0xFB, 0x79, 0xA4, 0x1E, 0xA7, 0x0F, 0x14, 0xAC, 0xCE, 0x6A, 0x5A, 0x8A, 0x88, 0x43, 0xB5, 0x95, 0x89, 0xE4, 0x52, 0x8B, 0xA8, 0x52, 0x10, 0x42, 0x1D, 0x1E, 0x59, 0x5F, 0x84, 0xC2, 0x75, 0x90, 0x47, 0xDB, 0x47, 0x22, 0x26, 0x73, 0x86, 0x8C, 0x00, 0x27, 0xEE, 0xFD, 0x99, 0x6E, 0xF8, 0xC8, 0xC4, 0xF3, 0x67, 0xA9, 0x1D, 0xEC, 0xF1, 0x79, 0x43, 0x22, 0x7D, 0x4D, 0x00, 0x44, 0x7F, 0xFC, 0x6C, 0xC8, 0x66, 0x5E, 0x08, 0xD2, 0x93, 0xA4, 0xDE, 0x4E, 0xE1, 0x15, 0x69, 0xB9, 0x5B, 0xB4, 0xDA, 0xE7, 0x58, 0x15, 0x0E, 0x55, 0x78, 0x32, 0x55, 0xE2, 0xF3, 0x22, 0x27, 0xB4, 0x5A, 0x9D, 0x26, 0x19, 0x77, 0x1C, 0xED, 0x51, 0x2D, 0x5C, 0xD8, 0x90, 0x18, 0xC9, 0x9E, 0x2F, 0x05, 0x23, 0x3E, 0xF5, 0x86, 0x0F, 0xEC, 0xB3, 0x79, 0x1B, 0x53, 0xAD, 0x2C, 0x22, 0x8A, 0xBA, 0xBB, 0x9F, 0xD1, 0xF5, 0x04, 0x38, 0xE9, 0xB0, 0xC6, 0xEA, 0x61, 0xE2, 0x0B, 0xB5, 0xAC, 0x0A, 0xAD, 0x30, 0x50, 0x9F, 0xEA, 0x9A, 0x44, 0x1D, 0x55, 0x5C, 0xDD, 0x34, 0x50, 0x9C, 0xFC, 0x60, 0x62, 0xE6, 0xB8, 0x1D, 0xCA, 0xCF, 0xD5, 0xF5, 0xC9, 0xC5, 0x26, 0xB3, 0x8D, 0x70, 0x4C, 0x1F, 0x0F, 0x28, 0xB4, 0xFB, 0x7C, 0x1A, 0xC6, 0x9A, 0xA1, 0x96, 0xCF, 0x81, 0x2E, 0x44, 0x46, 0xEF, 0x68, 0x02, 0x87, 0x44, 0xD2, 0xA5, 0x40, 0xFA, 0x7A, 0x69, 0xCF, 0x87, 0xA1, 0xF9, 0x68, 0x24, 0xE4, 0xC6, 0x87, 0x82, 0x35, 0xF0, 0xCC, 0xA3, 0xE9, 0x7B, 0x2B, 0x22, 0xB0, 0x93, 0xD9, 0x5E, 0xE1, 0x8D, 0xBF, 0xE6, 0x76, 0x1D, 0xFA, 0xF8, 0x34, 0x47, 0x51, 0x86, 0x07, 0x56, 0x02, 0x31, 0x3E, 0xE2, 0xA2, 0x99, 0xBC, 0xCC, 0xC6, 0x53, 0x1E, 0xDA, 0x54, 0x10, 0xCC, 0xFA, 0x09, 0xEC, 0xB8, 0xA6, 0x0D, 0x28, 0x33, 0x7A, 0xA5, 0x56, 0x58, 0x6D, 0x78, 0x48, 0x49, 0x38, 0x0F, 0x02, 0xEB, 0xB8, 0x37, 0xCB, 0x0B, 0xDE, 0x57, 0xBB, 0xA9, 0x07, 0xB6, 0x7C, 0x7A, 0xD8, 0x66, 0xE1, 0xDD, 0xB1, 0xC7, 0x9D, 0x96, 0x1D, 0x70, 0xF5, 0x5D, 0x05, 0x9A, 0xCF, 0xD3, 0x9F, 0x5B, 0xD3, 0x03, 0x74, 0xB4, 0x84, 0x5E, 0x04, 0xEC, 0x26, 0xE8, 0xB5, 0xB9, 0x3F, 0xC4, 0x54, 0x4F, 0x24, 0xAE, 0x99, 0xC9, 0xE5, 0x1E, 0x43, 0x57, 0x75, 0xD2, 0x20, 0x80, 0xE1, 0x9E, 0x3A, 0xC2, 0x25, 0xC7, 0xE1, 0xEE, 0x0A, 0x56, 0xB9, 0x52, 0x30, 0x7F, 0x44, 0xBA, 0xCF, 0x4C, 0x87, 0x85, 0x35, 0x5C, 0x09, 0xDB, 0xD0, 0xD8, 0x60, 0x57, 0xF0, 0xA6, 0xA9, 0x88, 0xC3, 0x65, 0x74, 0x20, 0x25, 0x19, 0xDE, 0xBA, 0x04, 0x56, 0x98, 0xD7, 0x24, 0x27, 0x77, 0x0C, 0x37, 0x31, 0xC9, 0xB7, 0x53, 0x5F, 0xAA, 0xF0, 0xCC, 0xA9, 0xD1, 0x3C, 0x42, 0x12, 0xB7, 0x62, 0x94, 0x57, 0x52, 0xE7, 0xA6, 0x53, 0x9B, 0x47, 0xBE, 0xA9, 0x66, 0x48, 0x23, 0x18, 0xA9, 0xCF, 0xE3, 0xBA, 0xEC, 0x6A, 0x83, 0xFB, 0x34, 0xF0, 0xB6, 0x8E, 0xE9, 0x77, 0x97, 0x42, 0x0F, 0xAD, 0xC3, 0xF0, 0x25, 0xEE, 0x9F, 0x18, 0xBE, 0xA3, 0x8F, 0xBE, 0xC0, 0xC5, 0xDE, 0xAA, 0xC7, 0xA5, 0x2F, 0x7E, 0xB8, 0xD9, 0x4F, 0xE4, 0xC6, 0x62, 0x54, 0x14, 0x57, 0xA1, 0x53, 0x82, 0x4B, 0xE6, 0x0D, 0x7D, 0xB8, 0x33, 0x89, 0x0F, 0x3A, 0xC3, 0xF7, 0xBD, 0x6D, 0x73, 0xF8, 0x0C, 0x67, 0x2B, 0x76, 0xA5, 0x26, 0x7D, 0xF2, 0x2C, 0xFB, 0x5E, 0x1B, 0x92, 0xB0, 0xCD, 0x68, 0xE9, 0xA9, 0x20, 0x92, 0x43, 0xA4, 0x2A, 0x30, 0xF7, 0xAA, 0x1F, 0x03, 0xD0, 0xD9, 0x11, 0x3F, 0x04, 0xB7, 0x6E, 0xB5, 0xAA, 0x69, 0xBC, 0x9B, 0x8F, 0xE7, 0x98, 0xE7, 0x75, 0x01, 0xB0, 0x56, 0x30, 0x29, 0xF5, 0x02, 0xF7, 0x79, 0x4D, 0xD3, 0x90, 0x74, 0x7A, 0xED, 0x08, 0x5C, 0x22, 0xB2, 0x16, 0x11, 0xA9, 0xC7, 0x62, 0x38, 0xEF, 0x65, 0x84, 0xAE, 0xFB, 0xB3, 0x57, 0xF8, 0x36, 0x25, 0x86, 0xC5, 0x9F, 0xCA, 0x8E, 0x09, 0x26, 0x10, 0x11, 0x5F, 0x4D, 0xC2, 0x93, 0x0D, 0x72, 0x24, 0x28, 0x5E, 0xB8, 0xFD, 0x99, 0x2F, 0x82, 0x17, 0xAE, 0x94, 0x70, 0xA7, 0x4A, 0xE3, 0xE8, 0x06, 0x01, 0x0C, 0x8D, 0x02, 0x19, 0x48, 0xBE, 0x57, 0xAB, 0x1D, 0x62, 0xC0, 0x41, 0x2E, 0xA5, 0xC9, 0x69, 0xD0, 0x56, 0x68, 0x41, 0xF2, 0xE2, 0x56, 0x8E, 0x01, 0x33, 0x64, 0xD8, 0x7C, 0xAF, 0x33, 0x22, 0x9D, 0x2A, 0xA6, 0xC5, 0x6B, 0x9F, 0xB4, 0xC1, 0x36, 0xA1, 0x3F, 0x5E, 0x73, 0x3A, 0x91, 0xEF, 0xF2, 0x1D, 0xCB, 0x29, 0x0D, 0x8E, 0xC6, 0xDC, 0x0A, 0x50, 0xE5, 0x7C, 0x1F, 0x65, 0xEB, 0x2B, 0xA1, 0xC3, 0x9D, 0xDB, 0x1C, 0x09, 0x54, 0x24, 0xE6, 0xF4, 0x1F, 0x9E, 0x86, 0x56, 0x7F, 0x91, 0x14, 0x00, 0xD8, 0x5C, 0x90, 0xD6, 0x4F, 0xC7, 0xE6, 0xEC, 0xC2, 0x88, 0x04, 0xF2, 0x70, 0x42, 0x40, 0x24, 0x9E, 0xFC, 0x8F, 0xEC, 0x69, 0xE3, 0x66, 0xF3, 0x68, 0x7A, 0x76, 0x20, 0x5C, 0x0D, 0x1D, 0xD6, 0x48, 0x39, 0x12, 0xA8, 0xF6, 0x8E, 0xAE, 0x2C, 0xB3, 0x52, 0x0A, 0x8B, 0x17, 0x2C, 0xF2, 0xCD, 0x2B, 0x03, 0x80, 0x2E, 0x5F, 0xA7, 0xB1, 0xF1, 0xEF, 0x8C, 0xA0, 0xA6, 0x08, 0x0B, 0xF9, 0xDA, 0x37, 0x82, 0xD2, 0xBD, 0xE4, 0xB3, 0xA3, 0xC6, 0x5C, 0xFB, 0x9F, 0x1B, 0x39, 0x05, 0xB9, 0x36, 0x1D, 0x1E, 0x0C, 0x8F, 0xEB, 0x5A, 0xB4, 0x0A, 0x3F, 0xFE, 0xB3, 0xAE, 0x95, 0xF5, 0x75, 0x62, 0xA0, 0x7C, 0xD2, 0x43, 0x18, 0xC0, 0xE7, 0xEE, 0x6E, 0xBE, 0x57, 0x0C, 0xB7, 0xDC, 0x1C, 0x62, 0x1A, 0x84, 0x92, 0x13, 0xE7, 0x13, 0x92, 0x42, 0x75, 0x81, 0x28, 0xC1, 0x6C, 0xFE, 0x52, 0xF8, 0xE2, 0xED, 0xA5, 0xBA, 0x23, 0x23, 0x15, 0x6F, 0x85, 0x3A, 0xBC, 0x61, 0xB1, 0x39, 0x04, 0x1A, 0x4B, 0x83, 0x40, 0x37, 0xAA, 0x19, 0xDC, 0xEE, 0x76, 0x06, 0xAE, 0x84, 0xC1, 0xA7, 0x4D, 0x0E, 0xEB, 0x6A, 0x4D, 0xAB, 0xD5, 0x90, 0x8D, 0xAE, 0x2C, 0x23, 0xA6, 0x38, 0x76, 0xE7, 0xE9, 0xF8, 0xE9, 0x03, 0x66, 0xA1, 0xFD, 0x89, 0xF2, 0x28, 0x3D, 0x75, 0x30, 0x09, 0xE0, 0x56, 0xDD, 0x5A, 0xB9, 0x53, 0xDB, 0x3D, 0x8F, 0x48, 0x30, 0xA4, 0xD0, 0x93, 0x79, 0x39, 0x5F, 0x21, 0xED, 0x03, 0xB6, 0xCC, 0xD5, 0xD7, 0xF8, 0xF8, 0x1F, 0x40, 0x0B, 0x3E, 0x3B, 0xC6, 0x96, 0x08, 0x8D, 0x58, 0x17, 0x75, 0x21, 0x11, 0x0B, 0x6C, 0x84, 0x74, 0xF3, 0xE4, 0x49, 0xD8, 0xEC, 0x7F, 0x46, 0x6C, 0x2E, 0xB3, 0x43, 0x65, 0x9F, 0xF5, 0x33, 0x97, 0x58, 0x7B, 0xC6, 0x30, 0x0D, 0xEE, 0xBD, 0xC2, 0xBE, 0x67, 0x4B, 0x78, 0x30, 0x90, 0xEA, 0xCC, 0xB9, 0x3B, 0x6A, 0xE9, 0x49, 0x56, 0xA3, 0x33, 0xE8, 0x58, 0x37, 0x64, 0x73, 0xCA, 0x67, 0xAF, 0x05, 0x43, 0xE5, 0x99, 0x94, 0x1E, 0xB4, 0xE8, 0xC6, 0xD9, 0x5D, 0x47, 0x9F, 0xEE, 0xE0, 0x5E, 0x3E, 0x8B, 0xF5, 0xF0, 0xAA, 0xCD, 0x34, 0x51, 0xC0, 0xED, 0x48, 0x1F, 0x52, 0x6D, 0x38, 0xEB, 0x3B, 0x26, 0xA4, 0xFD, 0x98, 0xE1, 0x1B, 0xAF, 0x67, 0xED, 0xEA, 0xB2, 0xEC, 0xC7, 0xD3, 0x97, 0xE9, 0x68, 0xF8, 0xD1, 0x03, 0xE8, 0x01, 0x44, 0xA4, 0xCD, 0xB7, 0x00, 0xC4, 0x1A, 0x42, 0x83, 0x4B, 0x07, 0xFD, 0x7E, 0x91, 0xF3, 0xC5, 0x24, 0x09, 0xC6, 0x88, 0x2C, 0xF4, 0x15, 0xA4, 0x2F, 0x71, 0xE2, 0x1F, 0xE7, 0x00, 0x17, 0xD6, 0x2B, 0x1F, 0xE4, 0x3A, 0x2A, 0x32, 0xD8, 0x15, 0xE3, 0xF1, 0xA4, 0x4E, 0x72, 0x67, 0xB1, 0xBB, 0xF5, 0x52, 0xF3, 0x8E, 0x88, 0x97, 0x75, 0xEC, 0xD8, 0x5C, 0x4B, 0xF4, 0x65, 0x02, 0x22, 0xF3, 0x30, 0xFA, 0xE4, 0xB6, 0x17, 0x65, 0x52, 0x54, 0x03, 0xFB, 0xDE, 0x0A, 0x18, 0xF9, 0x73, 0x65, 0x7C, 0xAB, 0xEB, 0x05, 0xFE, 0x6B, 0x97, 0x29, 0xD3, 0xB3, 0x73, 0x0A, 0xEF, 0xDF, 0x3C, 0x18, 0x96, 0x99, 0x7A, 0x94, 0x9B, 0x60, 0x3C, 0x43, 0xFE, 0xCC, 0x3E, 0xAC, 0xCB, 0xF0, 0x0C, 0x03, 0x76, 0x59, 0x41, 0x80, 0x0C, 0xE4, 0x2F, 0xD0, 0x38, 0x4E, 0x1C, 0x1C, 0x61, 0x17, 0x31, 0x6C, 0xBA, 0x1A, 0x81, 0xA2, 0x09, 0x03, 0x3C, 0x5B, 0x53, 0xAE, 0x3B, 0x60, 0xBC, 0x1A, 0xFC, 0x6E, 0x7C, 0x95, 0xC5, 0xCB, 0x99, 0xC2, 0x6A, 0x4C, 0x88, 0x1F, 0x62, 0x6A, 0x21, 0x9A, 0x61, 0x9B, 0xC3, 0x5C, 0xF4, 0xEF, 0x0A, 0x3B, 0x67, 0x25, 0x34, 0x9D, 0x2C, 0x13, 0xD8, 0x9D, 0xE6, 0x5D, 0x9F, 0x7A, 0x35, 0x51, 0xCC, 0xCF, 0xC5, 0x61, 0x1D, 0xC9, 0xC8, 0x73, 0x7B, 0x0E, 0xF0, 0xFA, 0xDF, 0x86, 0x5A, 0x65, 0x33, 0x9F, 0x46, 0x4C, 0xB0, 0x65, 0xBA, 0x8F, 0xE4, 0x81, 0x06, 0x46, 0xA3, 0x44, 0x5B, 0x70, 0x2F, 0x51, 0xD6, 0xA9, 0x13, 0x49, 0xFD, 0x70, 0xA3, 0x56, 0x49, 0xFD, 0x4D, 0xAE, 0xE6, 0x13, 0x10, 0xA3, 0xCC, 0xA5, 0xED, 0x3A, 0xBD, 0xBF, 0xF8, 0x35, 0x5B, 0x51, 0x14, 0x83, 0x5F, 0xDE, 0x73, 0xC9, 0xF5, 0x2A, 0xC2, 0x29, 0xB1, 0x5E, 0x84, 0xD3, 0xF5, 0x9D, 0xCB, 0x13, 0x02, 0x55, 0x1E, 0xA4, 0xDD, 0x6F, 0x41, 0x5D, 0x01, 0x39, 0x11, 0xD6, 0x53, 0x15, 0xC8, 0xE5, 0x9B, 0x12, 0x20, 0x4A, 0xAA, 0xF5, 0x25, 0x75, 0x4E, 0x96, 0xEC, 0x3C, 0xB1, 0x3E, 0x19, 0x72, 0x62, 0x1F, 0x9C, 0x86, 0xF5, 0xDE, 0x4A, 0xDA, 0xB9, 0x80, 0xCF, 0x83, 0x69, 0x12, 0x7C, 0x2B, 0x3E, 0x4E, 0xF1, 0xA8, 0x2B, 0x7A, 0xC9, 0x59, 0xAB, 0x45, 0xD9, 0x7E, 0xEE, 0x7A, 0x14, 0xE4, 0x14, 0x5B, 0x34, 0x9B, 0x53, 0x3D, 0xD9, 0x2D, 0xD2, 0xC1, 0x77, 0xC7, 0x7A, 0xBA, 0x32, 0x5D, 0xD7, 0x5C, 0x77, 0xB3, 0x1A, 0x6A, 0xB3, 0xAA, 0xBE, 0x54, 0xA6, 0xCF, 0xA2, 0xDC, 0xA3, 0x5E, 0x20, 0x99, 0x35, 0xEF, 0x9D, 0x94, 0x7A, 0x37, 0xE8, 0x35, 0x97, 0xB9, 0x4F, 0xCA, 0xF5, 0x8A, 0x56, 0xD1, 0x4A, 0x05, 0x69, 0x12, 0xC2, 0x2A, 0x54, 0xA6, 0xFF, 0x2F, 0xE8, 0x25, 0xBA, 0xAD, 0x8A, 0xBF, 0x1D, 0xD8, 0x7F, 0xB0, 0xFA, 0x15, 0x19, 0xA5, 0xB7, 0xB4, 0x2F, 0x4B, 0xB2, 0xF7, 0x57, 0xEF, 0xF7, 0xC1, 0x2A, 0x2C, 0xD1, 0xB9, 0x1F, 0xAE, 0xBF, 0x80, 0x86, 0x51, 0x6D, 0xCD, 0xD5, 0x5F, 0x63, 0x84, 0x18, 0x8F, 0x53, 0xC6, 0xA7, 0x81, 0x86, 0x2F, 0xB5, 0xCC, 0x3C, 0xC6, 0x1A, 0xDE, 0x2F, 0x11, 0x08, 0xD1, 0x51, 0x63, 0xC3, 0x8C, 0x4C, 0xA0, 0x1B, 0xF7, 0xF2, 0xC8, 0x1B, 0x8C, 0x79, 0xAD, 0x69, 0x4A, 0x01, 0x61, 0x7B, 0xC0, 0x4F, 0x84, 0x70, 0xC2, 0xC7, 0x71, 0xBE, 0xE2, 0x9A, 0x66, 0x6B, 0xE8, 0x51, 0x42, 0xCB, 0x96, 0x7E, 0xC5, 0x69, 0xA4, 0x02, 0x2A, 0x64, 0xFC, 0x5D, 0x95, 0xA5, 0x57, 0x76, 0xAC, 0x73, 0x27, 0x55, 0xB2, 0x39, 0x29, 0xF2, 0x59, 0x86, 0xD9, 0x3C, 0x01, 0x9B, 0xBB, 0xFB, 0x15, 0x4C, 0x26, 0xBB, 0x47, 0xA2, 0xBA, 0x4B, 0x32, 0x97, 0xDC, 0xE4, 0x47, 0xC5, 0x61, 0xA1, 0xC4, 0x9F, 0x75, 0x35, 0xA7, 0xA1, 0x4C, 0x98, 0x30, 0x18, 0x6A, 0xA0, 0xDD, 0xFA, 0x00, 0x1A, 0xEA, 0x0D, 0x94, 0xC4, 0x0A, 0xC8, 0xA8, 0x41, 0x8E, 0x8D, 0x57, 0x8D, 0x84, 0x21, 0x41, 0x3F, 0xB7, 0xE8, 0x20, 0x23, 0x7E, 0xF3, 0xB5, 0xCB, 0xF6, 0x08, 0x1C, 0x44, 0x2C, 0x13, 0xB4, 0x98, 0x5E, 0xE6, 0x39, 0xE8, 0xF8, 0x6D, 0xB2, 0x87, 0x3B, 0xC2, 0xC9, 0xD3, 0xA9, 0xE5, 0x17, 0xAD, 0x70, 0x31, 0xDA, 0x3C, 0xC9, 0x2F, 0xC1, 0x5F, 0x50, 0x2F, 0xAD, 0x3F, 0xC5, 0xFD, 0xBB, 0xCD, 0x2C, 0x95, 0x50, 0xA8, 0x95, 0x25, 0xF0, 0x06, 0x7C, 0xC3, 0xEA, 0x22, 0xD8, 0xD5, 0xB6, 0x1A, 0xFA, 0xA4, 0xB5, 0x53, 0xAC, 0x30, 0x39, 0x20, 0xF2, 0x5D, 0x6D, 0x58, 0xF6, 0x1F, 0x63, 0x56, 0x68, 0x5E, 0x43, 0x50, 0x9A, 0x00, 0x62, 0xF8, 0x37, 0xBC, 0xB9, 0xA1, 0xA2, 0x2C, 0xFF, 0x08, 0x10, 0x80, 0x18, 0xD6, 0xD2, 0x4B, 0xDC, 0x2B, 0x09, 0x6D, 0x2E, }, .t1_len = 2560, .t1 = { 0x03, 0x23, 0x69, 0xA2, 0xCE, 0x57, 0x2F, 0xD0, 0x8B, 0xFC, 0x30, 0x4B, 0x48, 0x48, 0xE7, 0x8D, 0x75, 0x2D, 0x77, 0xE9, 0x7A, 0x28, 0xB9, 0x9B, 0x9B, 0xB6, 0xFB, 0x5C, 0x7C, 0x63, 0x37, 0x51, 0x4B, 0x32, 0x1E, 0xCD, 0xC1, 0xFB, 0x66, 0x9F, 0x26, 0xD4, 0x17, 0x1A, 0xB4, 0x2B, 0x72, 0x72, 0x0E, 0xE7, 0x0E, 0x05, 0x19, 0xA6, 0xE1, 0xD3, 0xD6, 0xD9, 0x91, 0x4E, 0xC1, 0xB2, 0x1C, 0xDE, 0x38, 0xB4, 0x1A, 0xAC, 0x1D, 0x3A, 0xBE, 0xE6, 0xF2, 0xB7, 0x49, 0x5C, 0x4C, 0x82, 0x0C, 0x1F, 0xC0, 0xCC, 0x9E, 0x71, 0xE2, 0x4C, 0xFB, 0x5C, 0x9C, 0x0D, 0x8E, 0xEF, 0x42, 0x64, 0xAF, 0x48, 0x4F, 0xAE, 0x4D, 0x6E, 0x5D, 0xDE, 0x65, 0xD4, 0xDF, 0x72, 0xB6, 0x1C, 0x6D, 0xBD, 0x26, 0xF8, 0x61, 0xA5, 0xE0, 0xB8, 0x53, 0xAC, 0x54, 0x13, 0x22, 0x6F, 0xEB, 0xBA, 0xBA, 0x5E, 0xB4, 0x74, 0xC6, 0xFB, 0x25, 0xA8, 0x26, 0x78, 0xEA, 0x16, 0x06, 0xB4, 0x52, 0xA2, 0x31, 0x12, 0x22, 0x10, 0x17, 0xB8, 0xC0, 0x73, 0xC1, 0x03, 0x78, 0xF9, 0x14, 0x56, 0x41, 0xA8, 0xC0, 0x78, 0xC0, 0xED, 0x9E, 0x42, 0x16, 0x50, 0xF7, 0x48, 0x89, 0x25, 0x22, 0xAB, 0x9F, 0xB7, 0xD1, 0xFF, 0x8C, 0xF1, 0xCC, 0x71, 0xB8, 0x56, 0x6E, 0x8D, 0xA3, 0x3C, 0xD7, 0x36, 0x17, 0x70, 0xC0, 0x44, 0x34, 0x9A, 0xC4, 0x40, 0xCC, 0xCD, 0xC6, 0xBB, 0xE3, 0x5E, 0x6C, 0x55, 0x78, 0x27, 0x66, 0xF3, 0x8E, 0x68, 0x8B, 0xF4, 0x78, 0x21, 0x03, 0x72, 0x99, 0xE3, 0x44, 0xEC, 0xDE, 0xCA, 0x17, 0xAD, 0x5D, 0x15, 0xCD, 0x27, 0xA4, 0xF7, 0xB0, 0x70, 0x66, 0x11, 0x38, 0xED, 0xE8, 0xED, 0x72, 0xA8, 0x95, 0x9C, 0x5A, 0xE3, 0x6B, 0x1C, 0x46, 0x09, 0x4A, 0x53, 0xCB, 0x21, 0xA7, 0xA4, 0x26, 0x73, 0xF1, 0x40, 0x1C, 0x2B, 0x25, 0x94, 0x94, 0x09, 0x0E, 0x2F, 0x53, 0xD7, 0xEE, 0x70, 0x63, 0x43, 0x1E, 0xE5, 0x85, 0x80, 0x02, 0xD8, 0x50, 0xAF, 0x90, 0x9C, 0x37, 0x83, 0x43, 0x60, 0x10, 0xF7, 0xEA, 0x88, 0x62, 0x5A, 0x36, 0xA0, 0xF0, 0x18, 0x9F, 0xDE, 0x75, 0xB7, 0xE8, 0xC7, 0xE4, 0xB1, 0x9D, 0x85, 0x27, 0x00, 0x83, 0x28, 0xAD, 0xBC, 0x92, 0x9B, 0xBC, 0x86, 0xE9, 0x64, 0xCF, 0xC4, 0x8B, 0x8C, 0xF1, 0xDA, 0x5D, 0x7E, 0xD3, 0x33, 0x3A, 0xB5, 0x5C, 0x15, 0x07, 0x28, 0x32, 0x21, 0x4A, 0x77, 0x9A, 0x5F, 0xD1, 0x0C, 0xC0, 0x40, 0x05, 0xF4, 0x6C, 0x1A, 0xA8, 0x88, 0x4A, 0x16, 0x19, 0x92, 0x47, 0x2F, 0xD5, 0x35, 0xB9, 0x5E, 0xD1, 0x8B, 0xDE, 0x1C, 0x6D, 0x8C, 0xE6, 0x78, 0xD2, 0x81, 0x7D, 0x69, 0xF9, 0x05, 0x71, 0x10, 0x3E, 0x85, 0x20, 0xE7, 0x31, 0x3C, 0xE7, 0xB9, 0x30, 0xC5, 0xEB, 0xFA, 0xF2, 0xF4, 0xEC, 0x75, 0x8B, 0x62, 0x6B, 0x55, 0x43, 0xA0, 0x68, 0xCD, 0xE0, 0xFD, 0x0E, 0x94, 0xE6, 0xA6, 0x44, 0x75, 0xB2, 0x32, 0x68, 0xBF, 0x03, 0x80, 0xD0, 0x75, 0x50, 0x8F, 0x85, 0x12, 0x8C, 0xA2, 0x6F, 0x31, 0xA9, 0x0C, 0x4A, 0x7D, 0x28, 0x44, 0x0D, 0x54, 0xD4, 0x06, 0x6B, 0x40, 0x45, 0x88, 0x58, 0x8B, 0x4C, 0xCF, 0x85, 0x0B, 0x97, 0x5C, 0x73, 0xAF, 0xE6, 0x8C, 0xBC, 0xD1, 0x02, 0x75, 0x5F, 0x61, 0xEB, 0x3E, 0x60, 0x32, 0x3C, 0x57, 0x6E, 0x52, 0x9E, 0xC0, 0xBF, 0x23, 0xBF, 0xA5, 0xBE, 0xA3, 0x9C, 0xB7, 0x3C, 0x37, 0xE8, 0x39, 0x5D, 0x8D, 0xBD, 0x4C, 0x8D, 0xC8, 0xAB, 0x2F, 0x70, 0xA0, 0xBF, 0xC3, 0xA7, 0x8C, 0x0D, 0x41, 0x3F, 0x08, 0xD1, 0x4D, 0x63, 0x2B, 0xC0, 0x40, 0x3B, 0x03, 0x83, 0xDB, 0xBB, 0x22, 0xBD, 0x9B, 0x11, 0x3C, 0x89, 0x45, 0x2A, 0xEA, 0xB1, 0x12, 0x10, 0x09, 0x79, 0x47, 0xFE, 0xAA, 0xA3, 0xC9, 0xF0, 0x5D, 0x1D, 0x30, 0x0C, 0x33, 0xA5, 0x5E, 0x3F, 0xBC, 0x81, 0x25, 0x9E, 0x86, 0x27, 0x05, 0xC3, 0xA1, 0x3B, 0x9E, 0xE3, 0x5F, 0x6B, 0x23, 0xED, 0x10, 0xF4, 0xED, 0xEA, 0x95, 0x19, 0xFA, 0x91, 0xB7, 0xBC, 0xD0, 0xD5, 0x01, 0xB5, 0xED, 0x57, 0xD9, 0x04, 0x9F, 0xAB, 0x91, 0xAA, 0x77, 0x9C, 0x72, 0x5F, 0xF8, 0xE9, 0xF7, 0x80, 0x17, 0xEA, 0x78, 0x07, 0xFA, 0x25, 0x4B, 0x71, 0x05, 0xE8, 0x26, 0xD0, 0x96, 0xC0, 0x1A, 0xDA, 0xE2, 0xC5, 0xD1, 0x38, 0x25, 0x1A, 0x92, 0xA4, 0x78, 0xA3, 0x33, 0x73, 0xF4, 0xDE, 0x91, 0x2B, 0x83, 0xB6, 0xFB, 0x4B, 0x0D, 0x0D, 0xE6, 0xBC, 0x11, 0x18, 0xBB, 0x2F, 0xCF, 0xB0, 0x7B, 0xD2, 0x27, 0xA5, 0xF7, 0xF9, 0x91, 0x43, 0x9A, 0x13, 0xDE, 0x12, 0x38, 0x18, 0x0C, 0xDC, 0x55, 0x11, 0x9E, 0x65, 0xC4, 0x18, 0x58, 0x4D, 0x80, 0x7A, 0x92, 0x6E, 0x4A, 0x9C, 0x0F, 0x70, 0x15, 0x5E, 0xE1, 0x96, 0xFB, 0x07, 0x65, 0x6D, 0x9A, 0xA7, 0x98, 0x2B, 0x87, 0x95, 0xDB, 0xAD, 0x43, 0xD1, 0x05, 0x9C, 0xA7, 0xF5, 0x80, 0xD3, 0x32, 0x0C, 0x04, 0x38, 0xA5, 0xED, 0x5A, 0x70, 0x32, 0xB2, 0xE9, 0x59, 0x67, 0x84, 0x10, 0xF1, 0x1A, 0xD9, 0x8B, 0xE8, 0x82, 0x6A, 0x44, 0x26, 0x26, 0x15, 0x64, 0x5D, 0x75, 0x9A, 0x86, 0x2B, 0x2A, 0xC5, 0x2D, 0x3B, 0x01, 0x4A, 0x25, 0xE8, 0x47, 0x3F, 0x1F, 0x1E, 0xA4, 0xCF, 0xA8, 0x19, 0x93, 0x0A, 0xB3, 0xA3, 0x4D, 0x71, 0x0D, 0xEE, 0xE7, 0x0C, 0xA1, 0x3E, 0x88, 0xFD, 0x71, 0xAA, 0x06, 0x4E, 0x6C, 0xB4, 0x69, 0x7D, 0xE0, 0xE4, 0x63, 0xB1, 0x37, 0x0A, 0x6A, 0x3B, 0xFE, 0x98, 0xFD, 0xFE, 0x7B, 0x54, 0x71, 0xFF, 0x8D, 0xF6, 0xA6, 0x87, 0x9F, 0xBE, 0xF9, 0xAF, 0xB3, 0x51, 0x9D, 0x78, 0x07, 0x57, 0xD6, 0x74, 0x40, 0xAC, 0x36, 0xE8, 0x37, 0xBA, 0xC3, 0x83, 0x3E, 0xEA, 0xA9, 0x80, 0xBD, 0x82, 0xB7, 0x93, 0x64, 0x36, 0xA0, 0x30, 0x7D, 0x16, 0x4B, 0x64, 0x38, 0x86, 0x9A, 0xE6, 0x06, 0xE9, 0x80, 0x51, 0x8E, 0x91, 0x3D, 0x0E, 0xE3, 0x02, 0x39, 0x6E, 0xF4, 0xEB, 0x25, 0xD9, 0x86, 0x6E, 0x4B, 0xAF, 0xA1, 0x01, 0xE5, 0x99, 0x29, 0x31, 0x36, 0x1C, 0x4A, 0x98, 0x22, 0x53, 0xD5, 0x8A, 0xBE, 0x3B, 0xD5, 0x71, 0x07, 0x63, 0x5A, 0x46, 0xF0, 0x95, 0x12, 0x08, 0x5F, 0x4A, 0xDA, 0x08, 0xEC, 0x8B, 0x1B, 0x39, 0x10, 0xB0, 0x15, 0x3B, 0x2A, 0xAF, 0xCA, 0xE5, 0x03, 0x3E, 0xDD, 0x41, 0x53, 0x24, 0x8D, 0xCD, 0x85, 0xB0, 0x2C, 0x9A, 0x25, 0xD8, 0xBD, 0xC4, 0x06, 0x8B, 0xB8, 0x57, 0x41, 0x72, 0x62, 0x97, 0xA2, 0x5A, 0xEC, 0x55, 0xC4, 0x4A, 0xA2, 0x80, 0x59, 0xB7, 0x1B, 0xB9, 0xF3, 0x40, 0x67, 0x88, 0x7A, 0xDE, 0x4C, 0x1C, 0xA4, 0x90, 0x8B, 0x19, 0xB3, 0xD7, 0x81, 0x23, 0x45, 0x38, 0x76, 0xDB, 0x4D, 0xCE, 0xB4, 0x27, 0x73, 0x06, 0x95, 0x72, 0xCD, 0x87, 0x77, 0xE6, 0x2C, 0xFB, 0xAF, 0x72, 0x03, 0xF0, 0x20, 0xF2, 0x81, 0xA6, 0x67, 0x8F, 0x79, 0x07, 0x20, 0xEA, 0xA2, 0x0E, 0x34, 0x32, 0x7D, 0x7A, 0x63, 0x68, 0x8B, 0x09, 0xA0, 0x1F, 0x4D, 0x70, 0x88, 0xF7, 0xB5, 0x05, 0x9E, 0xDD, 0xEB, 0x45, 0xC0, 0xCE, 0x39, 0x32, 0x1C, 0x79, 0x52, 0x1D, 0x79, 0xA5, 0x9E, 0xCD, 0xD4, 0x68, 0xCE, 0xD0, 0xEA, 0x82, 0xCA, 0x48, 0x49, 0x28, 0x70, 0x2F, 0x57, 0xD6, 0xFC, 0x18, 0xD3, 0x47, 0xAF, 0x3E, 0xD2, 0x2A, 0xAF, 0x45, 0xAB, 0xB0, 0xF2, 0x0B, 0xAB, 0x9E, 0x01, 0x55, 0x76, 0x07, 0xAE, 0x3E, 0xD9, 0xCF, 0x0E, 0x26, 0xD3, 0x4D, 0x30, 0x54, 0x49, 0x66, 0x9E, 0xC6, 0xFC, 0x1B, 0xEC, 0xEA, 0xDC, 0xE1, 0x83, 0xF7, 0xA5, 0x94, 0xCE, 0xA1, 0x96, 0xD0, 0x59, 0xA1, 0xE5, 0x50, 0xE5, 0x47, 0x86, 0x6C, 0xC0, 0x87, 0x33, 0x3F, 0x03, 0x0E, 0x62, 0x8F, 0x2C, 0xF1, 0x14, 0x79, 0x25, 0x41, 0x0E, 0xD0, 0x42, 0x1D, 0xC7, 0x50, 0x61, 0x38, 0xB1, 0xD1, 0x90, 0x99, 0xC6, 0x95, 0xE1, 0xAF, 0xDA, 0xCE, 0x41, 0x53, 0x82, 0x5B, 0x66, 0xA8, 0xEC, 0xF5, 0x5A, 0x02, 0x1D, 0x21, 0xEB, 0x9F, 0x84, 0x8F, 0xE5, 0x5C, 0x21, 0x76, 0x9A, 0x75, 0x5F, 0xA9, 0x80, 0x7E, 0xF7, 0x3A, 0x6C, 0x5B, 0xA1, 0x5A, 0x06, 0x34, 0x7D, 0x3F, 0x1C, 0x5C, 0x61, 0x9A, 0x31, 0x55, 0x98, 0x62, 0x91, 0x06, 0xAC, 0x0B, 0x86, 0xAE, 0x0D, 0x8E, 0x55, 0x57, 0x82, 0x92, 0x51, 0x72, 0x58, 0xAE, 0x85, 0xF7, 0x2E, 0x73, 0x7A, 0xF5, 0x63, 0x8D, 0x09, 0x6B, 0x76, 0xA3, 0xC5, 0x7F, 0x1B, 0x9C, 0x80, 0xE7, 0x70, 0xA2, 0xD4, 0xEA, 0x4E, 0x42, 0xFE, 0x46, 0x9A, 0xD4, 0x21, 0x28, 0x52, 0x41, 0x96, 0x0A, 0x8A, 0x86, 0x35, 0x5E, 0xF2, 0x2F, 0x58, 0x3F, 0xE3, 0xBA, 0xCA, 0xDF, 0x8D, 0xA3, 0x1D, 0x5C, 0x2D, 0xE2, 0x54, 0x16, 0x1B, 0xC6, 0xD1, 0x0F, 0x98, 0x41, 0xDD, 0x27, 0xED, 0x46, 0x2A, 0x6B, 0x94, 0xB6, 0xDE, 0xEA, 0x90, 0xCB, 0xAB, 0x68, 0x7F, 0xB8, 0x4B, 0x56, 0x39, 0x5D, 0xA7, 0x63, 0xAB, 0x4B, 0x7F, 0xE3, 0x09, 0x5D, 0x57, 0x2D, 0x77, 0xEF, 0xF3, 0xFF, 0x0D, 0x8F, 0x9D, 0x19, 0xAA, 0x5A, 0xF7, 0xB6, 0x76, 0x05, 0x3D, 0xBE, 0xF6, 0x4E, 0x61, 0xDD, 0x0A, 0x41, 0xD4, 0x02, 0x31, 0x8E, 0x33, 0x08, 0x66, 0x91, 0x06, 0x25, 0x9B, 0xF7, 0xA4, 0xCE, 0x31, 0xB3, 0x46, 0xA9, 0xE9, 0x83, 0xED, 0xAB, 0xA0, 0x51, 0x80, 0x14, 0x9A, 0xB0, 0x57, 0xF9, 0x97, 0x29, 0x77, 0xDA, 0x7C, 0x6F, 0x46, 0xE0, 0xCD, 0xF8, 0x6F, 0x30, 0x91, 0xF0, 0x4F, 0xD4, 0xE8, 0x3C, 0x60, 0x22, 0xE1, 0x8C, 0xE4, 0x38, 0x2B, 0x54, 0xD5, 0xDA, 0xBA, 0x82, 0xE4, 0xDF, 0x1E, 0x53, 0xBF, 0x31, 0xFE, 0x4B, 0xB6, 0x5A, 0x85, 0x24, 0xED, 0xA8, 0x3F, 0xD2, 0x9D, 0x07, 0xE4, 0x97, 0x47, 0xB7, 0x52, 0x91, 0xCB, 0xC8, 0xF8, 0xEE, 0x14, 0x15, 0xEC, 0x92, 0x1E, 0x19, 0x02, 0x2A, 0xDE, 0x2C, 0x04, 0x7E, 0x4D, 0xF3, 0x50, 0x72, 0x89, 0xE9, 0xD7, 0x9A, 0x8E, 0x69, 0x92, 0xB4, 0x8B, 0x88, 0x64, 0x20, 0x4A, 0x41, 0x6B, 0x76, 0x9C, 0xC7, 0x87, 0xD6, 0xDF, 0x44, 0x07, 0xE9, 0x3D, 0x12, 0x1F, 0x7F, 0xBE, 0xE0, 0xE4, 0x08, 0x96, 0x3E, 0x06, 0x09, 0xA9, 0xC7, 0x5C, 0xB3, 0x11, 0x7C, 0xA5, 0x83, 0xDF, 0x6E, 0x79, 0xF3, 0x1C, 0x63, 0x5B, 0xF0, 0xF1, 0xBE, 0x98, 0xDF, 0x55, 0x07, 0x27, 0xA4, 0x5D, 0x3C, 0xA3, 0x37, 0xD7, 0x9D, 0xE5, 0xDC, 0xDB, 0x0B, 0x91, 0xCA, 0xBB, 0xC3, 0x0D, 0x7E, 0xF0, 0xAE, 0x1C, 0xA1, 0xE9, 0x49, 0x04, 0xF7, 0x8C, 0x1F, 0xD8, 0xFB, 0xA8, 0x75, 0x45, 0xFD, 0xC1, 0x74, 0xAD, 0x81, 0x90, 0xF9, 0xB5, 0xED, 0x7B, 0x58, 0x69, 0x49, 0x4F, 0xFA, 0x91, 0x03, 0x3F, 0xDC, 0x61, 0x17, 0xBF, 0x66, 0x2E, 0xC5, 0xF2, 0xAF, 0x26, 0x34, 0xBA, 0x3F, 0x8C, 0x02, 0x21, 0x0F, 0x1C, 0x9B, 0xCD, 0xDA, 0x9B, 0xB3, 0x97, 0x60, 0xE0, 0x0F, 0x25, 0xA7, 0x27, 0x0C, 0x34, 0x56, 0x66, 0xFB, 0x6D, 0xF8, 0x5C, 0x91, 0x9A, 0xA1, 0x50, 0xCA, 0x7F, 0xC8, 0x0F, 0xC0, 0xEA, 0xCF, 0xE2, 0x42, 0xEF, 0x55, 0xF4, 0x29, 0x80, 0x63, 0x62, 0x8E, 0x61, 0x05, 0x6C, 0x96, 0x6D, 0xB9, 0x96, 0x44, 0x28, 0xD9, 0xCE, 0x99, 0x10, 0x82, 0x71, 0xE2, 0x9A, 0x12, 0x32, 0x8E, 0x23, 0x99, 0x97, 0x34, 0xE0, 0x36, 0xF1, 0x8A, 0x0E, 0xB8, 0xF0, 0x30, 0xE8, 0x80, 0x62, 0xC5, 0x67, 0x17, 0xE7, 0xA3, 0x63, 0x14, 0xE4, 0x4E, 0xCF, 0x35, 0x7F, 0xF5, 0x6E, 0xED, 0xF9, 0x0D, 0x3F, 0xB1, 0x1B, 0x22, 0xA1, 0xB2, 0x59, 0x05, 0xB3, 0x79, 0xFC, 0xCA, 0x5C, 0xA1, 0xAC, 0xB9, 0x56, 0xE1, 0x78, 0xAD, 0x3F, 0x51, 0xD5, 0x35, 0xAD, 0x11, 0x98, 0x13, 0xB1, 0xE7, 0x0F, 0x73, 0x17, 0x65, 0x1B, 0xC7, 0x5C, 0xAC, 0x64, 0x27, 0x6B, 0xB9, 0x81, 0x10, 0xB5, 0x4E, 0xA0, 0xEF, 0x34, 0x54, 0x1D, 0x73, 0x91, 0x07, 0x21, 0xD6, 0x57, 0x38, 0x76, 0x77, 0xE3, 0x32, 0xE9, 0xC8, 0x81, 0x1C, 0x3F, 0xC1, 0xB9, 0x23, 0xB2, 0xEE, 0x9C, 0x51, 0x2F, 0x6D, 0x09, 0xDF, 0x37, 0x2A, 0x5F, 0x97, 0xFA, 0xD7, 0x12, 0x33, 0x89, 0xCE, 0xE1, 0x97, 0xB5, 0xC2, 0x69, 0xE2, 0x21, 0xD7, 0xEE, 0xD3, 0x16, 0x0A, 0x52, 0x1E, 0x56, 0xFF, 0x8A, 0xAF, 0xAB, 0x68, 0x61, 0x79, 0xD0, 0x9D, 0x78, 0xFC, 0x38, 0x7B, 0x3E, 0xA6, 0xA6, 0x72, 0x03, 0x4D, 0x24, 0xAC, 0x79, 0x99, 0xD1, 0x96, 0xB2, 0x31, 0x64, 0x75, 0xF3, 0x7D, 0xB8, 0xE9, 0xED, 0x43, 0x1D, 0xF5, 0x83, 0x41, 0xFA, 0x88, 0x00, 0x3D, 0x3C, 0x64, 0x89, 0xE7, 0x80, 0x53, 0xD8, 0xE4, 0x4C, 0xE7, 0xE1, 0x6A, 0xEF, 0x41, 0x68, 0x59, 0xB3, 0xD2, 0xAE, 0xCE, 0x09, 0x08, 0x6A, 0x74, 0x8B, 0x7B, 0xCF, 0xD1, 0x0F, 0x73, 0xE3, 0xCF, 0x8B, 0x31, 0xF0, 0xCC, 0x44, 0xDA, 0x05, 0x9C, 0x69, 0xAB, 0xA5, 0xBC, 0x8E, 0xFA, 0xD4, 0x5D, 0x3F, 0x37, 0x6A, 0xF3, 0xA0, 0xDE, 0x6E, 0x16, 0x98, 0x78, 0xBD, 0x84, 0x2E, 0x28, 0x79, 0x8E, 0x47, 0x43, 0xF8, 0x43, 0x84, 0x4B, 0xCD, 0xF8, 0x50, 0x6F, 0x13, 0x63, 0x91, 0xEC, 0x8E, 0x72, 0x1D, 0xC2, 0xB6, 0x28, 0x2D, 0x9C, 0x50, 0xFA, 0xB6, 0x53, 0xA6, 0xAB, 0xF2, 0x89, 0x47, 0x42, 0x0E, 0x8C, 0x22, 0xA9, 0xA4, 0x87, 0xD7, 0x6A, 0x93, 0x89, 0x33, 0xB3, 0x4E, 0x49, 0x7D, 0xA9, 0x53, 0x94, 0x17, 0x6B, 0x27, 0x74, 0xC0, 0x9E, 0xF0, 0xBB, 0x1E, 0xD8, 0xC3, 0xB1, 0x31, 0xA2, 0x19, 0x57, 0xB3, 0x1A, 0x0B, 0x47, 0xCB, 0xFB, 0xFF, 0x05, 0x33, 0xCA, 0xF3, 0x31, 0x25, 0x22, 0x1D, 0xB6, 0xBA, 0x4A, 0x51, 0x88, 0x64, 0x89, 0x2C, 0xF2, 0x1D, 0x3D, 0x4D, 0x58, 0xB5, 0x99, 0xA3, 0x7A, 0x08, 0xF3, 0x44, 0xAA, 0x7E, 0xF9, 0x8E, 0x7D, 0x7D, 0x9D, 0x33, 0x16, 0xA6, 0xB1, 0x15, 0xD9, 0xB8, 0xF2, 0x0F, 0x93, 0xBC, 0x68, 0x65, 0x73, 0x46, 0x99, 0xEB, 0x54, 0xC8, 0x88, 0xD7, 0xE5, 0xA0, 0xAC, 0xAF, 0xD1, 0x91, 0x53, 0x52, 0xB2, 0x94, 0x24, 0x37, 0x12, 0xCF, 0xE8, 0x2F, 0x85, 0x24, 0x8B, 0x00, 0x04, 0x5C, 0xF3, 0xD0, 0x90, 0xC0, 0xC0, 0x0D, 0x7C, 0xA0, 0xE3, 0xA1, 0xF1, 0x47, 0x70, 0x3F, 0xD9, 0x4F, 0x71, 0x7E, 0x49, 0xC8, 0x1A, 0x7C, 0x3A, 0x76, 0x94, 0x6E, 0x20, 0xA6, 0x3F, 0x3B, 0x7C, 0x3E, 0xAB, 0xA9, 0x22, 0x5A, 0xBE, 0x0B, 0x34, 0xCB, 0x0C, 0xF2, 0x35, 0x06, 0x39, 0x67, 0xD1, 0x6B, 0xC8, 0xA6, 0x9C, 0x13, 0x0C, 0xCE, 0x28, 0x76, 0x15, 0xCC, 0x05, 0x31, 0x14, 0x16, 0x7E, 0xAC, 0x4E, 0x95, 0xBB, 0xAB, 0xDF, 0xBB, 0xCF, 0x96, 0xBC, 0x0C, 0x0D, 0x65, 0xEA, 0x00, 0x0A, 0xEA, 0xF4, 0x90, 0xD7, 0x23, 0x95, 0x5B, 0xD1, 0xB4, 0xD6, 0x91, 0x54, 0xD2, 0x62, 0xF6, 0xA6, 0xD3, 0x53, 0x4B, 0xB0, 0xBC, 0x39, 0x7C, 0x29, 0xEC, 0xC6, 0xB1, 0x44, 0x7B, 0x75, 0xC9, 0x53, 0xAF, 0x44, 0x1D, 0xE2, 0xE7, 0x13, 0x3A, 0x7A, 0xC9, 0x89, 0x88, 0xA7, 0xEF, 0x9E, 0x6E, 0xE6, 0x35, 0x58, 0xAA, 0xAD, 0xA0, 0x60, 0x3B, 0xD5, 0x29, 0x77, 0x6F, 0x05, 0x55, 0x8D, 0x2D, 0xF5, 0x64, 0x1C, 0x41, 0x2E, 0x73, 0x47, 0x44, 0x0F, 0x65, 0xEB, 0x82, 0x3A, 0xFC, 0x7C, 0xCA, 0xE6, 0xB9, 0x71, 0x08, 0xB8, 0x57, 0x28, 0x7A, 0x04, 0x86, 0xDB, 0xBE, 0x68, 0x9D, 0x77, 0x0C, 0xA9, 0x24, 0x71, 0x30, 0x9E, 0x73, 0xAD, 0x39, 0x0A, 0xBF, 0x56, 0x91, 0x2B, 0x2B, 0x7C, 0x49, 0x24, 0x2C, 0xEC, 0x15, 0x7B, 0xDB, 0xBD, 0x49, 0x35, 0x53, 0x73, 0x5C, 0xB1, 0xD9, 0xB4, 0x0A, 0xFC, 0x21, 0x4D, 0xA1, 0x53, 0x35, 0x9C, 0x9D, 0xF5, 0x76, 0x13, 0x59, 0x01, 0xC2, 0xFD, 0xA5, 0x8C, 0x00, 0x95, 0xB6, 0xFC, 0xE3, 0xFD, 0x07, 0x31, 0xDF, 0x34, 0x86, 0x3A, 0xF2, 0x88, 0x2D, 0x53, 0x77, 0x3C, 0xE7, 0xC1, 0x82, 0x47, 0x37, 0x22, 0xAA, 0x79, 0xA6, 0xB3, 0x7D, 0x3E, 0xDD, 0xDE, 0x38, 0xFA, 0x71, 0xDF, 0x8C, 0x0E, 0xDC, 0x08, 0x1E, 0xFE, 0xD8, 0xCE, 0x60, 0x6E, 0x48, 0x29, 0x91, 0x80, 0xEC, 0x6F, 0xE3, 0x5F, 0xAB, 0x64, 0x99, 0x10, 0xC4, 0x8A, 0x6A, 0x29, 0xF9, 0xD0, 0xF8, 0x55, 0x57, 0xE1, 0x0B, 0xC5, 0xAE, 0x2E, 0xCF, 0x02, 0x8A, 0xE3, 0x99, 0xF5, 0x5C, 0xD7, 0x97, 0x60, 0x28, 0x93, 0x5C, 0xC0, 0x3C, 0x0C, 0xAF, 0xD5, 0x00, 0x3C, 0x9E, 0xAE, 0xD2, 0x47, 0xFB, 0xE3, 0x0A, 0x28, 0x4C, 0xC4, 0x47, 0x0A, 0x55, 0x25, 0xA6, 0x49, 0x8E, 0x1D, 0xBB, 0xD3, 0x08, 0x5C, 0x3F, 0x9D, 0x77, 0xC6, 0x06, 0x4D, 0x01, 0x81, 0xBC, 0x5A, 0x82, 0x95, 0x61, 0x56, 0x0A, 0xA9, 0xA4, 0xEA, 0x81, 0x73, 0xD7, 0x93, 0x7A, 0x94, 0x28, 0x10, 0x9C, 0xB3, 0xA6, 0x6B, 0x2B, 0x3D, 0xE1, 0x1F, 0x88, 0xF5, 0x5A, 0xB2, 0x1E, 0xB4, 0x9B, 0x77, 0xA3, 0x97, 0x62, 0xCA, 0x92, 0x64, 0xE0, 0x15, 0x65, 0x66, 0x76, 0x5E, 0x2D, 0x36, 0x26, 0xB7, 0x2B, 0x80, 0xBD, 0x14, 0x11, 0xE4, 0xEC, 0x53, 0x55, 0x28, 0x28, 0xA2, 0x4B, 0xC8, 0xCD, 0xC4, 0x7F, 0x46, 0x5F, 0xDD, 0xF4, 0x77, 0x2C, 0x7B, 0xC0, 0x20, 0x66, 0x85, 0x40, 0x11, 0x28, 0x7F, 0x73, 0x9A, 0xBA, 0x60, 0x47, 0x59, 0x67, 0x47, 0xF4, 0x23, 0x4A, 0xE2, 0x27, 0xDB, 0xFF, 0xAB, 0xF0, 0xE1, 0x31, 0x53, 0xE2, 0xE0, 0x69, 0xF0, 0xB7, 0x90, 0x25, 0x1B, 0xE8, 0x77, 0xFE, 0x5A, 0x19, 0x8E, 0x80, 0x82, 0x58, 0x63, 0x9F, 0x5E, 0x79, 0xD3, 0xD5, 0xCD, 0x16, 0xF1, 0xA5, 0x73, 0x72, 0x4D, 0xD6, 0xA9, 0xF6, 0x99, 0x0C, 0x45, 0x02, 0x33, 0x4D, 0xC6, 0x6F, 0x65, 0x49, 0x34, 0x90, 0x67, 0x3A, 0xB3, 0x0D, 0xCA, 0x7C, 0x03, 0x1F, 0x0C, 0x21, 0x2C, 0x0D, 0x8B, 0xC9, 0xD0, 0xC8, 0x74, 0xB3, 0x19, 0xA9, 0x7A, 0xD1, 0xCE, 0x93, 0x95, 0xD3, 0xD1, 0x54, 0x20, 0x31, 0x56, 0xC5, 0x1C, 0xC3, 0xB9, 0xCB, 0x13, 0xD0, 0xBA, 0x1B, 0xDF, 0x61, 0x8B, 0xC8, 0xEE, 0xCA, 0x9D, 0xDD, 0x94, 0x12, 0x05, 0x0C, 0xFA, 0x09, 0x23, 0x57, 0x27, 0xAA, 0x50, 0xD4, 0x6F, 0x79, 0xAD, 0x6F, 0x3C, 0x5A, 0x1B, 0xB6, 0xB2, 0x84, 0xC8, 0x31, 0x1D, 0xCF, 0x93, 0x75, 0x68, 0x59, 0x70, 0x4D, 0xF8, 0xFC, 0x3B, 0xB8, 0xD2, 0xF5, 0xE0, 0x94, 0xE0, 0x45, 0x02, 0x35, 0x49, 0x42, 0xE9, 0xC8, 0x52, 0xB2, 0x08, 0xD4, 0x90, 0x18, 0x34, 0x33, 0x2E, 0xBC, 0x60, 0x32, 0x70, 0xCB, 0x57, 0xED, 0x41, 0x8C, 0x34, 0xCE, 0x48, 0xAA, }, .pkcs8_len = 0, .spki_len = 0, .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 = 4595, .sig = { 0xBB, 0xF8, 0x5F, 0xFD, 0x0E, 0x01, 0xC8, 0x0C, 0x8C, 0x1C, 0x19, 0x31, 0xCD, 0x64, 0x0B, 0xF2, 0x73, 0xD4, 0x96, 0x93, 0xC4, 0xC4, 0xBF, 0xF5, 0xDD, 0x20, 0xD9, 0x4C, 0xF3, 0x75, 0x7A, 0xBD, 0x45, 0x47, 0x3B, 0x9D, 0x01, 0xB1, 0x87, 0x13, 0x05, 0xDA, 0x90, 0xED, 0xC6, 0x70, 0x7D, 0x54, 0x17, 0x12, 0x94, 0x67, 0xF6, 0x1F, 0x72, 0x39, 0x50, 0xC1, 0xAE, 0xDF, 0x70, 0x55, 0xEC, 0x1D, 0x47, 0x77, 0xAD, 0x88, 0x08, 0xE8, 0xB3, 0x47, 0xD1, 0xD0, 0x92, 0x1E, 0xBA, 0xB8, 0x90, 0xCC, 0xA8, 0xE3, 0xA0, 0xDF, 0xD3, 0x00, 0x3D, 0xE9, 0xF9, 0xCB, 0x4A, 0x97, 0xD8, 0x84, 0xE1, 0xDD, 0x04, 0x2C, 0x95, 0x8B, 0x81, 0x6F, 0x72, 0x37, 0x03, 0x2B, 0x20, 0xF8, 0x39, 0x9A, 0x51, 0x82, 0xF4, 0x65, 0x25, 0xEC, 0x35, 0x7D, 0x2F, 0x03, 0x43, 0x74, 0x03, 0xE0, 0xCB, 0x5D, 0xCA, 0x4A, 0x13, 0xFD, 0x2F, 0x1B, 0x09, 0x20, 0x5B, 0x98, 0x90, 0xF0, 0x2E, 0xE5, 0xAF, 0x54, 0x29, 0x43, 0xE6, 0xF9, 0x37, 0x5E, 0xD0, 0x8A, 0x38, 0x53, 0x30, 0x42, 0xD6, 0xBB, 0xD5, 0x0F, 0x37, 0x25, 0x1B, 0x15, 0x90, 0xF6, 0x3B, 0x4B, 0x58, 0xA7, 0xD1, 0xE1, 0xF3, 0x1C, 0xE6, 0x2E, 0x3D, 0x2A, 0xA9, 0x1E, 0x1C, 0x76, 0x7B, 0x9C, 0x3F, 0x5C, 0xB2, 0x68, 0x23, 0xF9, 0x7A, 0xD1, 0xD9, 0xFF, 0xAB, 0x28, 0x75, 0xEB, 0x68, 0xFF, 0xA9, 0xB0, 0x99, 0x46, 0xEF, 0x1D, 0x70, 0x12, 0xC0, 0x29, 0x19, 0xEF, 0x13, 0xCB, 0x10, 0x0C, 0x2E, 0x2C, 0x79, 0x87, 0xA0, 0xA5, 0x78, 0x5B, 0x5F, 0x3F, 0x3B, 0x94, 0x8B, 0x7F, 0xD6, 0x4B, 0x85, 0xB1, 0x65, 0xAE, 0x2F, 0xBF, 0x3C, 0x47, 0xE0, 0x39, 0xC3, 0x07, 0x3C, 0xA7, 0x8F, 0xC9, 0x00, 0xBB, 0xCD, 0xC0, 0x69, 0xFE, 0x90, 0x68, 0x85, 0xD5, 0xB1, 0x37, 0x40, 0xA2, 0x23, 0xAF, 0x52, 0x54, 0xF9, 0x8C, 0x1D, 0x58, 0xE2, 0xFC, 0x92, 0xB0, 0x37, 0x3E, 0x2A, 0x93, 0x33, 0x53, 0xCC, 0x3E, 0xEC, 0xD3, 0x9F, 0x71, 0xD5, 0x9C, 0xFA, 0x09, 0x29, 0x4E, 0x38, 0x26, 0x2A, 0x44, 0x89, 0x40, 0x0D, 0x22, 0x29, 0x82, 0xF9, 0xC7, 0x80, 0xCD, 0x07, 0x31, 0xD4, 0xEE, 0xD9, 0x16, 0xC5, 0xA3, 0x1A, 0xBC, 0xD0, 0x2A, 0x59, 0x0E, 0xD8, 0xC6, 0xFF, 0xE1, 0x8B, 0x5F, 0xC7, 0xB6, 0x88, 0x8E, 0x74, 0x72, 0x69, 0x40, 0xD0, 0x2C, 0xCC, 0x62, 0xD7, 0x8B, 0xCA, 0xED, 0xDA, 0x2E, 0x02, 0x8E, 0x53, 0x5C, 0xDA, 0xFC, 0x0E, 0x09, 0x1B, 0xEF, 0x50, 0xDE, 0x2D, 0xFD, 0x12, 0x4F, 0x1E, 0x85, 0x4F, 0x56, 0x85, 0x27, 0xAE, 0xF4, 0xDC, 0x84, 0x55, 0xFD, 0xA0, 0x1B, 0x6D, 0x0D, 0x43, 0x04, 0x8E, 0xD5, 0xAB, 0x42, 0xB1, 0xD4, 0x08, 0x13, 0x99, 0x4B, 0x9F, 0x6A, 0xA0, 0xC0, 0x36, 0xC0, 0xDC, 0xF0, 0x8F, 0x46, 0xB0, 0x0F, 0xDA, 0x01, 0x44, 0x77, 0xCF, 0x87, 0x9B, 0x8F, 0xE5, 0xEA, 0xC4, 0x54, 0x1B, 0x82, 0xDA, 0x00, 0xB4, 0x34, 0x60, 0x46, 0x86, 0x5B, 0x09, 0x2E, 0xD6, 0xAE, 0x01, 0x15, 0xFC, 0x83, 0x4B, 0x58, 0xF7, 0x5F, 0xF9, 0x28, 0xD7, 0xD9, 0x9A, 0xC8, 0x69, 0x1F, 0xF7, 0x00, 0x20, 0xAB, 0xA2, 0x54, 0x80, 0xAB, 0xBC, 0xC7, 0x09, 0xE4, 0x6E, 0xC5, 0x10, 0xF4, 0xB8, 0xCA, 0xDD, 0x60, 0x04, 0x59, 0x54, 0xD3, 0xED, 0xDA, 0x7C, 0x23, 0xE0, 0x3D, 0x91, 0x69, 0x4D, 0x3C, 0x3E, 0xA2, 0x92, 0xC9, 0x25, 0x35, 0xE6, 0xB5, 0xFE, 0x17, 0x1C, 0x56, 0x7D, 0xF3, 0x72, 0x94, 0x06, 0xCD, 0xBA, 0x2A, 0x5E, 0xFA, 0x59, 0xF1, 0x56, 0xE9, 0xCC, 0xD0, 0x30, 0x2F, 0xDC, 0x0F, 0x8B, 0xB7, 0x59, 0xB0, 0x5D, 0xFF, 0x5D, 0xD8, 0x02, 0xCE, 0x4D, 0x55, 0x06, 0xA1, 0x9A, 0x69, 0xD7, 0x0B, 0x3A, 0xB4, 0x8A, 0xB1, 0x7A, 0x2F, 0xE5, 0x95, 0x89, 0xF7, 0x30, 0x83, 0xCC, 0xA5, 0x47, 0xFF, 0xB3, 0xF1, 0x46, 0x83, 0xC9, 0x14, 0xBC, 0x13, 0x45, 0xE7, 0x38, 0x7E, 0x83, 0x1E, 0xE6, 0x03, 0x75, 0x01, 0x49, 0x5C, 0x92, 0xC3, 0x57, 0x70, 0x5A, 0x69, 0xF9, 0x52, 0xA2, 0xF7, 0xCD, 0x30, 0xE0, 0x33, 0x36, 0xAF, 0xAA, 0xFC, 0x9C, 0x56, 0x60, 0x4C, 0xD5, 0x45, 0xE8, 0x2A, 0xA1, 0x2A, 0xF0, 0x58, 0xDA, 0xBA, 0x97, 0x43, 0x87, 0xFE, 0x8D, 0xCD, 0xEC, 0x69, 0x9A, 0x1E, 0x38, 0x53, 0xE2, 0x6D, 0x29, 0xE1, 0x57, 0x81, 0x89, 0xAA, 0x8C, 0x2B, 0xBA, 0x15, 0x50, 0xDF, 0xBE, 0xDD, 0x1E, 0x4F, 0x22, 0x4E, 0xFC, 0xD6, 0x54, 0x91, 0xE5, 0x4E, 0x56, 0x12, 0x8A, 0xE7, 0xC2, 0xDC, 0x85, 0x66, 0x79, 0x7A, 0xBF, 0x2D, 0x94, 0x55, 0x91, 0x52, 0x03, 0xA5, 0xC8, 0x9E, 0x55, 0xDD, 0x23, 0xDF, 0x82, 0x74, 0x36, 0xA8, 0xD6, 0xDC, 0xC5, 0xAC, 0xA8, 0x2F, 0x9B, 0x18, 0x36, 0x92, 0x15, 0x9E, 0xC0, 0x3F, 0x2B, 0x79, 0x8E, 0x55, 0x7D, 0x14, 0x73, 0x46, 0xD8, 0x35, 0xA8, 0xD8, 0x1B, 0x2E, 0x3D, 0x40, 0x86, 0x39, 0x66, 0x86, 0x3A, 0x54, 0xD9, 0xC8, 0x7B, 0x5A, 0xAC, 0xE9, 0x63, 0xCD, 0x52, 0x9A, 0xDB, 0xAE, 0x07, 0x07, 0x0C, 0xEA, 0x00, 0xB7, 0x80, 0xE1, 0x81, 0x31, 0xE6, 0x4F, 0x0A, 0xD7, 0x0E, 0x91, 0x58, 0xF5, 0x90, 0xD0, 0x0A, 0xD9, 0x17, 0x79, 0x08, 0xB9, 0x03, 0x45, 0xFD, 0x79, 0xD0, 0x25, 0x57, 0x71, 0xC6, 0x08, 0xAF, 0x65, 0xEE, 0x5A, 0xC3, 0xC5, 0x01, 0x66, 0xBA, 0xD0, 0x57, 0x38, 0x02, 0x58, 0x68, 0x19, 0x41, 0x56, 0x0F, 0x11, 0x33, 0x40, 0x5F, 0xC2, 0xD7, 0x61, 0x13, 0x14, 0xB4, 0x38, 0x1D, 0x54, 0x59, 0xDC, 0xDE, 0xDE, 0x4D, 0x39, 0xF3, 0x82, 0x3B, 0xC4, 0x42, 0x2B, 0xB1, 0xD7, 0x36, 0xE7, 0x47, 0x4A, 0x80, 0x89, 0xF0, 0xEC, 0xFA, 0x3C, 0x30, 0xAA, 0xC1, 0x19, 0xFF, 0xA4, 0x2B, 0xF7, 0x43, 0xF4, 0x8E, 0x0F, 0xDD, 0x96, 0x02, 0x92, 0xD3, 0xE4, 0x9A, 0x14, 0xEB, 0x05, 0x90, 0xC8, 0xE0, 0x2E, 0x42, 0x1D, 0x54, 0xAE, 0x8A, 0x52, 0x19, 0x51, 0x5E, 0x21, 0x89, 0x59, 0x89, 0xA0, 0xD7, 0x1D, 0x4F, 0x45, 0x16, 0x69, 0xCD, 0x65, 0x2D, 0xA3, 0x48, 0x9E, 0x5C, 0xDB, 0xC0, 0x87, 0x6B, 0xA0, 0xA0, 0x89, 0x9E, 0x7D, 0x87, 0x73, 0xB2, 0x4A, 0xFC, 0x2C, 0xD6, 0xD3, 0x7C, 0xA3, 0x80, 0xA5, 0xD0, 0xDD, 0x43, 0x63, 0x04, 0xD6, 0xE1, 0xA4, 0xDC, 0xD6, 0x38, 0xE8, 0xB9, 0x5E, 0x6C, 0x95, 0x46, 0x5C, 0x66, 0x90, 0xD4, 0xEF, 0xE8, 0xF4, 0x46, 0x91, 0xE4, 0x8D, 0xE2, 0x2C, 0xFC, 0x69, 0x1C, 0x75, 0x61, 0xAD, 0x8C, 0xC1, 0xA2, 0xC3, 0xCC, 0x9F, 0xB8, 0x6F, 0xF6, 0xF4, 0x70, 0x5A, 0x57, 0x3A, 0x72, 0x04, 0x71, 0xED, 0x33, 0xA0, 0x0E, 0x8A, 0x60, 0x20, 0x38, 0x18, 0xA3, 0x96, 0x1E, 0x4D, 0x21, 0x3A, 0x78, 0xB8, 0x62, 0x63, 0x94, 0xF7, 0x5C, 0x28, 0x23, 0x15, 0x57, 0x4C, 0xCD, 0x72, 0x5A, 0x67, 0xE2, 0x0F, 0x0B, 0xF2, 0x24, 0xBF, 0xFC, 0xAB, 0xD7, 0x02, 0xBF, 0xD4, 0xE1, 0xCC, 0x5F, 0x78, 0xBE, 0xC0, 0xE0, 0x42, 0xE1, 0x2E, 0xD4, 0xC9, 0x47, 0x4B, 0xDD, 0x5E, 0xED, 0x2A, 0xEB, 0x53, 0xF4, 0xA9, 0x58, 0xD7, 0xF8, 0x4E, 0xFD, 0x56, 0xEC, 0x03, 0x0A, 0x94, 0xD2, 0x00, 0xA5, 0x39, 0xDE, 0x16, 0x4E, 0x53, 0xC8, 0x2A, 0xFE, 0x8C, 0x5F, 0x71, 0xBB, 0x99, 0xA0, 0x1F, 0x72, 0x30, 0xB7, 0xAE, 0xBC, 0x21, 0x3E, 0xCD, 0xDB, 0xEF, 0x5B, 0x9E, 0x90, 0x64, 0x87, 0x43, 0x96, 0xF8, 0xA9, 0x1B, 0x05, 0x75, 0xF6, 0x8A, 0x45, 0x15, 0xDD, 0x15, 0x81, 0x78, 0xBF, 0x27, 0x7A, 0x90, 0xA3, 0xFE, 0xA2, 0x00, 0x92, 0x00, 0xDA, 0x2E, 0xDA, 0x2C, 0x8B, 0x3A, 0x47, 0xC1, 0x04, 0xD3, 0x50, 0xDF, 0x68, 0xE9, 0x4C, 0x8A, 0x40, 0x23, 0xD3, 0xAE, 0xFB, 0xB7, 0x07, 0x18, 0xFA, 0x2E, 0x27, 0xE6, 0xA5, 0xC3, 0xF9, 0x92, 0x7E, 0xC5, 0x96, 0xAB, 0x54, 0x0F, 0x46, 0x3A, 0xE0, 0x10, 0xEF, 0x71, 0xB8, 0x9B, 0x49, 0x49, 0x7F, 0x0C, 0xFD, 0x29, 0x39, 0xFF, 0xAB, 0x2A, 0x7D, 0xD1, 0x24, 0x7D, 0xC4, 0xA5, 0x9D, 0x84, 0x11, 0xA8, 0x43, 0xBD, 0x84, 0xF1, 0xEA, 0x8D, 0xA3, 0x3C, 0x07, 0x01, 0xD7, 0x0A, 0xC2, 0x7C, 0x4B, 0xDB, 0xD0, 0xD9, 0xA0, 0xCA, 0xB8, 0x6B, 0x1F, 0xC5, 0xBE, 0x12, 0x45, 0x8A, 0x25, 0x80, 0xA6, 0xCA, 0xB4, 0xB7, 0x65, 0xB8, 0x42, 0xC6, 0x7A, 0xD5, 0x4C, 0xA5, 0xD4, 0x0A, 0x24, 0xE2, 0xDD, 0xBC, 0xF0, 0x1E, 0x46, 0x6E, 0x08, 0xD9, 0xB3, 0x44, 0x9F, 0x13, 0xE8, 0x2E, 0x16, 0xD6, 0x1C, 0x72, 0x3F, 0xB9, 0x46, 0x2E, 0x97, 0xB7, 0xAB, 0xC7, 0x0B, 0x22, 0x10, 0xEC, 0xA1, 0x6B, 0x16, 0x0D, 0x5B, 0x8F, 0x98, 0xA1, 0x79, 0x4D, 0xCA, 0x92, 0xCD, 0x4F, 0x02, 0x7F, 0x3E, 0x41, 0x52, 0xEA, 0x87, 0x95, 0x07, 0xDD, 0xFE, 0x7F, 0x1F, 0x21, 0x51, 0x41, 0x53, 0xF0, 0x36, 0xAA, 0xBC, 0x33, 0xF1, 0x72, 0xC9, 0x5A, 0x9B, 0x77, 0x47, 0x22, 0x80, 0x0F, 0x2E, 0x08, 0xCC, 0x44, 0xF9, 0x23, 0x54, 0x0D, 0x8A, 0xF6, 0x4B, 0x42, 0x99, 0x68, 0xB2, 0x80, 0x36, 0x4C, 0x1B, 0x7B, 0x4B, 0x3E, 0x9B, 0xEE, 0x40, 0xC5, 0x00, 0x02, 0x65, 0x7D, 0x99, 0x46, 0x31, 0xF3, 0x3A, 0x8F, 0x8F, 0x13, 0x4A, 0x27, 0xEB, 0x69, 0xBA, 0x43, 0x95, 0x90, 0x8B, 0xA4, 0x06, 0x34, 0xB8, 0xF2, 0x70, 0x31, 0x49, 0x27, 0x5F, 0xFB, 0xBE, 0x8B, 0x48, 0x3E, 0xA1, 0xBB, 0xA9, 0x1C, 0x28, 0x10, 0x51, 0x36, 0xD9, 0x7C, 0x47, 0x0E, 0xE8, 0x3C, 0xD2, 0x1C, 0xEB, 0x2B, 0x21, 0xAA, 0xED, 0x98, 0xDB, 0x8A, 0xB1, 0x65, 0xA7, 0xB4, 0xBE, 0x55, 0x9E, 0x7E, 0xAC, 0xA6, 0x84, 0x60, 0x30, 0x15, 0xBC, 0x34, 0x9B, 0x0A, 0x51, 0x21, 0x4E, 0x4E, 0x8F, 0xBE, 0x1D, 0x2D, 0x88, 0x3F, 0x79, 0xFD, 0x3F, 0x1E, 0xDC, 0xDD, 0x3F, 0xA6, 0xD4, 0xB5, 0xBB, 0xD2, 0xA5, 0xB3, 0x00, 0x3A, 0x80, 0xF1, 0xDA, 0xDE, 0x97, 0x5B, 0x50, 0x2C, 0x7F, 0x72, 0x03, 0x73, 0x16, 0xBC, 0x55, 0xC1, 0xE5, 0x7E, 0x50, 0x06, 0x27, 0xD6, 0x0E, 0x31, 0x08, 0x74, 0x31, 0xD2, 0xC9, 0xD0, 0x2C, 0xA9, 0xF0, 0xEB, 0xCC, 0xD4, 0xBF, 0xE3, 0xC4, 0xBB, 0x53, 0x6D, 0x4C, 0xFE, 0xF7, 0x51, 0x07, 0x50, 0x45, 0x2D, 0x44, 0x4B, 0xE2, 0xC3, 0xD6, 0x4D, 0x84, 0xA8, 0x32, 0x96, 0x53, 0x05, 0x26, 0x4A, 0xBB, 0x53, 0xE3, 0x61, 0x49, 0x40, 0xF9, 0xB2, 0xF1, 0xEA, 0x6F, 0x41, 0xCA, 0x8F, 0x69, 0xE7, 0x26, 0x69, 0x0B, 0xA6, 0x30, 0x63, 0x0F, 0x8A, 0x91, 0x6E, 0xE8, 0x56, 0x26, 0x82, 0x51, 0xB7, 0x73, 0xDC, 0x2A, 0x5D, 0xB4, 0x5D, 0x22, 0xDF, 0xB2, 0x43, 0x9C, 0xA4, 0xB7, 0xAB, 0x70, 0x21, 0x5D, 0x23, 0xE1, 0xF2, 0xE2, 0x61, 0x73, 0x94, 0xFF, 0x78, 0x3B, 0x0B, 0xFF, 0x6D, 0xF0, 0x34, 0x5C, 0xC9, 0x27, 0x05, 0x3D, 0x02, 0xC6, 0x5F, 0xE2, 0xA8, 0x6D, 0xEF, 0xBE, 0xBF, 0x52, 0x43, 0xA2, 0xEF, 0x6A, 0x63, 0x12, 0xBA, 0xED, 0xB6, 0xE6, 0x0D, 0xBB, 0x0C, 0x67, 0xCC, 0x9A, 0x65, 0x55, 0x85, 0xCB, 0x45, 0x8D, 0x6A, 0x04, 0x18, 0x11, 0x94, 0x81, 0x5F, 0x03, 0xBE, 0x87, 0xF6, 0xE8, 0x00, 0x49, 0x2A, 0x24, 0xC5, 0xD5, 0x02, 0xD5, 0xEC, 0xD5, 0x3D, 0xD6, 0xDA, 0x36, 0x79, 0x95, 0xD3, 0x2E, 0x8B, 0xBA, 0xA3, 0xEF, 0x62, 0x72, 0x7E, 0x8A, 0x61, 0x0E, 0x8D, 0x6B, 0x5C, 0x8F, 0xAB, 0xCB, 0xE8, 0x89, 0x3B, 0xDB, 0x5E, 0x03, 0x86, 0x27, 0xF7, 0x07, 0xE8, 0x46, 0x4C, 0x55, 0xDC, 0xBB, 0x76, 0xF0, 0x83, 0x6A, 0xDD, 0x29, 0x8A, 0x96, 0x7C, 0x45, 0x95, 0x08, 0xBC, 0x4E, 0x88, 0xBA, 0x5C, 0xA3, 0x8F, 0x5A, 0x56, 0x1A, 0x6D, 0x2D, 0x6C, 0xB2, 0x17, 0x8D, 0x90, 0xAC, 0x85, 0x0C, 0xA2, 0x73, 0x4B, 0x45, 0xC4, 0xA8, 0x9A, 0xA0, 0xF1, 0x52, 0xA3, 0xB5, 0x3B, 0xCF, 0x1E, 0x13, 0x53, 0x2B, 0x2B, 0x5B, 0x38, 0x78, 0xB2, 0x05, 0xBD, 0x2B, 0x32, 0x7D, 0xC4, 0x9E, 0xB6, 0x66, 0x0B, 0x95, 0x11, 0xBF, 0xAE, 0x90, 0xC1, 0xDE, 0xA5, 0xBD, 0xEB, 0x6D, 0xC5, 0xDA, 0x06, 0x8B, 0xCB, 0xDC, 0x6C, 0x09, 0x3E, 0x57, 0x27, 0xE3, 0x87, 0x37, 0x4F, 0x45, 0x2F, 0x96, 0x3C, 0x30, 0x7D, 0xEE, 0x86, 0x5D, 0x41, 0xAA, 0x12, 0x4C, 0xA8, 0x03, 0xC1, 0x2F, 0x9A, 0xE9, 0x29, 0x9C, 0x3C, 0xB1, 0x34, 0x5F, 0xCC, 0x56, 0x8C, 0x6E, 0x71, 0xBE, 0x33, 0x66, 0xBF, 0x30, 0xEF, 0xEE, 0xEF, 0xC7, 0x69, 0x3C, 0x36, 0xAC, 0xE5, 0x76, 0xB0, 0xD1, 0x0F, 0x40, 0x2F, 0x38, 0x00, 0x09, 0xFD, 0x0E, 0xC0, 0x68, 0xCB, 0x2D, 0x45, 0x98, 0x48, 0x84, 0xED, 0xF1, 0x6B, 0xC9, 0x0B, 0x0F, 0xF6, 0xDC, 0x96, 0x30, 0x9E, 0xA3, 0x77, 0xA3, 0xCE, 0xC0, 0x43, 0xCB, 0x76, 0xB6, 0xC8, 0x85, 0xBB, 0xB8, 0x48, 0xC4, 0x74, 0x5B, 0x71, 0xE1, 0x8C, 0x58, 0xE7, 0x80, 0x50, 0xE1, 0x9B, 0xD7, 0xBE, 0x08, 0x31, 0xEF, 0xE9, 0x05, 0x2A, 0x6A, 0x7D, 0xF8, 0xD4, 0xE8, 0xB9, 0xFC, 0x3E, 0x08, 0x2A, 0x4D, 0x40, 0xAD, 0x73, 0xE4, 0xB3, 0x18, 0x5E, 0x2F, 0x6D, 0xED, 0xE7, 0xEE, 0x51, 0xA4, 0x06, 0x8F, 0xF2, 0xDA, 0x57, 0x37, 0x3F, 0xD7, 0xE7, 0xBD, 0x46, 0xE0, 0x08, 0x0F, 0x4C, 0x2C, 0x1F, 0x41, 0xBC, 0x25, 0x0E, 0x6D, 0xA4, 0x5A, 0x34, 0x1F, 0x21, 0x47, 0x71, 0xF5, 0x53, 0x1A, 0x67, 0xB0, 0xFD, 0x97, 0xB5, 0x3C, 0xD7, 0x2C, 0xFA, 0xC7, 0x21, 0x5B, 0xC4, 0x11, 0x1F, 0x09, 0x40, 0x30, 0xA9, 0x13, 0x83, 0xD2, 0x01, 0x82, 0x21, 0x0F, 0xCE, 0xCD, 0x75, 0xE5, 0x9C, 0x4B, 0x0B, 0x33, 0xA3, 0xF9, 0x3D, 0x86, 0x5D, 0x84, 0x7E, 0xC2, 0x41, 0xE1, 0xB9, 0x84, 0x81, 0xC5, 0xD9, 0xD2, 0x7F, 0x0A, 0xE2, 0x62, 0xB3, 0x28, 0x65, 0x0C, 0xDC, 0x13, 0xCD, 0x99, 0x86, 0x6B, 0xE9, 0xA5, 0xA0, 0x30, 0xE8, 0x3D, 0x84, 0xE3, 0x2B, 0xD2, 0x13, 0xC9, 0x4B, 0xD6, 0xAF, 0x95, 0x04, 0x33, 0xA4, 0xF0, 0x0C, 0x61, 0x49, 0x78, 0x3B, 0x00, 0x75, 0x0C, 0xDF, 0xD4, 0xF4, 0x7A, 0xE7, 0x52, 0x17, 0xEE, 0xD1, 0xF6, 0x0C, 0x36, 0x6F, 0xA0, 0x2C, 0xDB, 0x20, 0x6F, 0xEB, 0x2A, 0x68, 0x5D, 0x6B, 0x7D, 0x6A, 0x4C, 0x13, 0x55, 0x3E, 0x2B, 0xE2, 0x77, 0x94, 0xF5, 0x3B, 0x0E, 0xF5, 0x73, 0x15, 0x20, 0x32, 0x63, 0xEB, 0x02, 0x6E, 0xA5, 0xE6, 0x70, 0x67, 0xD2, 0x2F, 0x92, 0xE2, 0x6E, 0x98, 0xDF, 0x9A, 0xB3, 0x86, 0xC2, 0x70, 0x5B, 0x43, 0x16, 0xA6, 0x98, 0x92, 0x68, 0x8E, 0x60, 0x1E, 0x74, 0x27, 0x59, 0x5A, 0xCE, 0xE6, 0xE4, 0x7F, 0x5E, 0xC5, 0x98, 0xCC, 0x48, 0xC2, 0xF2, 0xDA, 0x1C, 0x32, 0xE0, 0x62, 0xA3, 0x49, 0xD8, 0x9D, 0xCC, 0x8C, 0x05, 0xC6, 0x2E, 0x7B, 0x0C, 0xED, 0x6F, 0x2E, 0x93, 0xA7, 0xBD, 0x48, 0xA8, 0x00, 0x4A, 0x8C, 0x5C, 0x60, 0x5D, 0xFF, 0xC8, 0x05, 0xDE, 0x07, 0x9E, 0xDE, 0xE7, 0xCE, 0xD9, 0x86, 0x39, 0xA9, 0x2F, 0x6C, 0xBA, 0x92, 0xF2, 0x08, 0x9B, 0x14, 0x5D, 0x2D, 0x61, 0xD9, 0x63, 0x8C, 0x07, 0x34, 0x7A, 0x2E, 0xF6, 0xB3, 0x0F, 0xD9, 0x0E, 0x11, 0x1A, 0x7F, 0x59, 0x13, 0xF6, 0xE1, 0x87, 0x95, 0xC1, 0x9E, 0x0B, 0x9F, 0x60, 0xF8, 0x5B, 0xD8, 0xF5, 0xC9, 0xA9, 0x63, 0x33, 0x94, 0x41, 0xE4, 0xA5, 0xB7, 0x9E, 0xB2, 0xE8, 0x67, 0x96, 0x1B, 0x18, 0xA1, 0x88, 0x4A, 0x01, 0xA7, 0x44, 0x83, 0xD8, 0x0B, 0x40, 0x3E, 0xFB, 0xDB, 0xD4, 0xED, 0xDD, 0xC1, 0x92, 0x2D, 0xA3, 0xFB, 0xB3, 0x7B, 0xEA, 0x97, 0xE0, 0xA5, 0xB6, 0x34, 0x3E, 0x43, 0x67, 0x60, 0x1B, 0xD2, 0x1D, 0xB6, 0x69, 0x41, 0xC2, 0x69, 0x8B, 0xF5, 0x06, 0xB0, 0x48, 0x61, 0xB5, 0xF3, 0xD3, 0xD8, 0x0A, 0xC6, 0xDC, 0xB6, 0x84, 0xD9, 0xC4, 0x36, 0x9A, 0xBD, 0x04, 0xBC, 0x4B, 0xDB, 0xEF, 0x49, 0xC6, 0x6E, 0x38, 0x44, 0x51, 0x3A, 0x3F, 0x3B, 0xDD, 0x40, 0x0C, 0x08, 0x0A, 0xC6, 0xEA, 0xD8, 0x1E, 0x8B, 0xB0, 0xE7, 0xCB, 0x36, 0xDB, 0x7B, 0x7E, 0xAB, 0x47, 0x28, 0x39, 0x18, 0x57, 0xF5, 0x97, 0xA3, 0x46, 0x48, 0x63, 0xC3, 0x12, 0x64, 0x5B, 0x20, 0xAF, 0x02, 0xF7, 0xD0, 0xBD, 0x9A, 0x74, 0xDE, 0x23, 0x61, 0xA0, 0xD2, 0xD9, 0x8A, 0x69, 0x89, 0x75, 0xB3, 0x0F, 0x10, 0x10, 0xD9, 0x0A, 0x12, 0x60, 0x78, 0x58, 0x4A, 0x45, 0xFF, 0xBC, 0xC6, 0x5B, 0x47, 0x97, 0x6A, 0xF6, 0x57, 0xEA, 0x84, 0xE9, 0x73, 0x0D, 0x9E, 0x36, 0x37, 0x33, 0x73, 0x6A, 0xC8, 0x01, 0x03, 0xDC, 0x1C, 0x75, 0x73, 0xC4, 0xDE, 0xE2, 0x8A, 0x7B, 0xAC, 0x9E, 0xF7, 0x2C, 0xB8, 0x29, 0x45, 0x0B, 0x53, 0xEA, 0xF9, 0x84, 0xCD, 0x01, 0xAA, 0x31, 0x41, 0x6C, 0xE8, 0x91, 0x4B, 0x7D, 0x7E, 0xF8, 0x49, 0xEB, 0x9C, 0xC1, 0x72, 0xD7, 0x09, 0x6D, 0xEF, 0xDA, 0xCF, 0x59, 0x6B, 0x9B, 0x21, 0xA5, 0x73, 0xE3, 0x46, 0xA4, 0x7A, 0x5A, 0x46, 0x9E, 0x1D, 0x79, 0x39, 0xBE, 0x19, 0x82, 0xCB, 0x39, 0x54, 0xC2, 0x14, 0xED, 0x3A, 0x37, 0x07, 0xD7, 0x40, 0xC0, 0x33, 0xE3, 0xEF, 0x78, 0x0F, 0x4C, 0x48, 0xBA, 0xDD, 0x86, 0x38, 0x48, 0xBB, 0xFC, 0x9D, 0xAA, 0x8E, 0x38, 0x06, 0xA8, 0x4B, 0x2C, 0xAC, 0x0C, 0xA2, 0x32, 0x00, 0x0C, 0xAF, 0x02, 0x03, 0xE9, 0x08, 0xFC, 0xE1, 0x8B, 0x5D, 0x62, 0x77, 0x72, 0x25, 0xD2, 0xD7, 0xD5, 0x84, 0xF2, 0xED, 0x71, 0x88, 0x5D, 0xFA, 0xF5, 0xA4, 0xDB, 0xEE, 0x02, 0xF2, 0x85, 0xBC, 0x34, 0x55, 0x9B, 0x88, 0xEA, 0x9C, 0xE1, 0x5B, 0x47, 0xA3, 0xB9, 0x2A, 0x8D, 0x6F, 0x91, 0x59, 0x1C, 0x32, 0x9A, 0x5A, 0xA2, 0x1A, 0x1B, 0xC4, 0x24, 0xBA, 0x2B, 0xDB, 0xD1, 0x64, 0xCE, 0x1A, 0x8B, 0x78, 0xB3, 0x8B, 0xEF, 0x2B, 0x47, 0xF2, 0x1F, 0x7F, 0xB7, 0xA3, 0xC5, 0x4E, 0x3E, 0xA4, 0x53, 0x6E, 0x81, 0x6E, 0x01, 0x65, 0x6C, 0x8E, 0x26, 0xAD, 0x42, 0xF3, 0xCB, 0x90, 0x61, 0x69, 0x67, 0xC0, 0xDD, 0x07, 0x9F, 0x95, 0x6C, 0x9F, 0x3C, 0x84, 0x4D, 0x5F, 0x33, 0x9C, 0x62, 0xEE, 0x8A, 0x35, 0x8C, 0x4B, 0xEC, 0x2D, 0x27, 0x8A, 0xF7, 0x18, 0xAD, 0x50, 0x9C, 0x6B, 0x66, 0x61, 0x3B, 0x58, 0x04, 0x43, 0xFA, 0x6F, 0x11, 0xCD, 0x8D, 0x10, 0x76, 0x93, 0xB5, 0xD7, 0xB7, 0x38, 0xAA, 0x7E, 0x2F, 0xE6, 0x62, 0x50, 0x2D, 0x75, 0x04, 0xA9, 0xF5, 0x96, 0x19, 0x41, 0x80, 0xF8, 0x70, 0x0D, 0xC4, 0xE6, 0xF7, 0xE8, 0xE7, 0xD2, 0x30, 0x72, 0x34, 0x49, 0x4B, 0x8D, 0xF1, 0xD5, 0x7E, 0xE1, 0x4D, 0x6C, 0x97, 0x92, 0x6E, 0xB1, 0xD8, 0x90, 0x4D, 0x80, 0x89, 0xBE, 0x7D, 0x13, 0x5B, 0x13, 0xD6, 0xDE, 0x30, 0xAA, 0x87, 0x20, 0xD6, 0x71, 0x59, 0xBB, 0x50, 0xA8, 0x34, 0xDE, 0x90, 0x79, 0x92, 0x2B, 0x88, 0x93, 0x1D, 0x45, 0x85, 0x00, 0x62, 0x68, 0x34, 0xDA, 0x04, 0x0D, 0xB7, 0x68, 0xDD, 0xDB, 0xE6, 0x7A, 0x75, 0x8A, 0x02, 0xB4, 0x48, 0xE3, 0x6B, 0xA4, 0x55, 0x03, 0x4A, 0xDE, 0x36, 0x80, 0x2A, 0xA4, 0x2A, 0x7F, 0x2F, 0x23, 0x4A, 0x5E, 0x1C, 0xC2, 0x41, 0xE5, 0x66, 0x1C, 0x63, 0xAF, 0xCE, 0x59, 0xDF, 0xDC, 0xC0, 0x89, 0x83, 0x47, 0xD2, 0x83, 0x4D, 0x72, 0x64, 0xF5, 0xB2, 0x1A, 0x47, 0xC5, 0x21, 0x4A, 0xDC, 0x57, 0xAF, 0x76, 0xCE, 0x9E, 0xBD, 0xB6, 0x8C, 0x71, 0x02, 0x9B, 0xCF, 0x0C, 0x4C, 0x74, 0x5A, 0x33, 0x45, 0x4A, 0xCF, 0x0C, 0xF6, 0xD5, 0xC6, 0x8D, 0xEA, 0x06, 0xC4, 0x5E, 0x7D, 0x4D, 0x17, 0x55, 0xC5, 0xAC, 0xDC, 0x37, 0xFC, 0x24, 0x34, 0x14, 0x0E, 0xF7, 0x07, 0xFD, 0x55, 0xFA, 0xF0, 0x6C, 0xBB, 0x17, 0x07, 0xC2, 0x7C, 0xE9, 0xD9, 0x05, 0x90, 0x5E, 0x37, 0xE2, 0xF1, 0x47, 0xC9, 0xCB, 0x88, 0x08, 0xEC, 0xD0, 0x5D, 0xF7, 0x1F, 0xC5, 0xF1, 0xDA, 0xF9, 0x10, 0xD7, 0xBD, 0x68, 0xB6, 0x91, 0x49, 0x38, 0xBF, 0x0C, 0xAB, 0xCF, 0x66, 0xC9, 0x05, 0xC4, 0x95, 0x63, 0xD7, 0xD7, 0x0F, 0x2C, 0x3D, 0x3A, 0x4A, 0x4F, 0x62, 0x9E, 0x3A, 0xFD, 0xE5, 0x3B, 0xD1, 0x4C, 0xD6, 0xE5, 0x27, 0xE4, 0xF0, 0x38, 0xD6, 0xA3, 0x31, 0xD0, 0x14, 0x68, 0xE2, 0x2D, 0xFE, 0x93, 0xA3, 0x79, 0xB3, 0xEC, 0x6D, 0xA6, 0xD1, 0xC2, 0xF6, 0xD5, 0xEA, 0xB1, 0x41, 0xE5, 0x75, 0xF9, 0x3C, 0x8C, 0xC5, 0x58, 0x0D, 0xF4, 0xA3, 0xDB, 0x5C, 0x4C, 0x87, 0xD8, 0x54, 0x8E, 0x9A, 0x85, 0x19, 0x46, 0xD1, 0xB9, 0x0D, 0x75, 0x27, 0x40, 0x7F, 0x1B, 0xA1, 0x12, 0x1E, 0xAC, 0x54, 0xA1, 0x1E, 0x6E, 0xDA, 0x45, 0xAB, 0xB0, 0x8A, 0x7A, 0x78, 0xAB, 0x36, 0xA7, 0x6E, 0xAD, 0x7F, 0xAC, 0x46, 0x78, 0xE5, 0x24, 0x64, 0xEF, 0xF3, 0x98, 0xE9, 0x02, 0x15, 0xAC, 0x31, 0x6D, 0xE5, 0xA6, 0xEF, 0xE5, 0xA7, 0xB4, 0xA9, 0x5D, 0xF9, 0x2E, 0x41, 0x29, 0xF3, 0xF9, 0x1B, 0x31, 0x6F, 0x75, 0x67, 0x08, 0xBD, 0xF3, 0x7C, 0x01, 0xC1, 0x2B, 0xBA, 0xA0, 0x91, 0xF9, 0x48, 0x84, 0xE3, 0x8A, 0xFF, 0x3C, 0x7B, 0x81, 0x40, 0x88, 0x8C, 0xAB, 0x4F, 0x7F, 0x86, 0x7E, 0xAD, 0xB0, 0x41, 0x85, 0x84, 0xB6, 0xF7, 0x70, 0x74, 0x02, 0x50, 0x93, 0x6A, 0x13, 0x8A, 0xFF, 0x52, 0x88, 0x88, 0x40, 0x67, 0x7D, 0x81, 0x21, 0xC5, 0x83, 0x80, 0x6F, 0xE2, 0x71, 0x04, 0xDE, 0x52, 0x88, 0x13, 0xE5, 0x62, 0x26, 0xB6, 0x52, 0xC5, 0x86, 0x9B, 0xB5, 0x00, 0x30, 0x38, 0x34, 0xD9, 0xC9, 0xD1, 0x97, 0xDB, 0xA1, 0xDD, 0x5C, 0x47, 0x34, 0x30, 0x7A, 0xB8, 0xBD, 0x00, 0x6B, 0x66, 0xEF, 0x45, 0xAB, 0xED, 0x2E, 0x31, 0x37, 0x7B, 0xEA, 0xA1, 0x9D, 0xAE, 0x6E, 0xC8, 0x2A, 0xD7, 0x7C, 0x4C, 0x07, 0x74, 0x4F, 0x9B, 0x93, 0xA8, 0xDD, 0x4C, 0xEE, 0x1A, 0x62, 0xA5, 0x52, 0xED, 0xF4, 0xE2, 0x77, 0xCA, 0xCF, 0xF1, 0xF9, 0x64, 0xDA, 0x7A, 0xF8, 0xFA, 0xFF, 0x6B, 0x56, 0xE3, 0xEB, 0xC0, 0x68, 0x50, 0xA9, 0xF7, 0x6E, 0xCF, 0xB2, 0xC2, 0xBA, 0xA6, 0x60, 0x95, 0x8C, 0x6D, 0x1B, 0xA9, 0x6B, 0xA8, 0x57, 0x8D, 0x06, 0x6D, 0x6A, 0xFE, 0x6E, 0x8F, 0xB2, 0x05, 0x2B, 0x74, 0x21, 0xD5, 0x7D, 0xE5, 0xAB, 0x4C, 0x1F, 0xD5, 0x51, 0x70, 0xE9, 0xEE, 0x33, 0xEB, 0x32, 0xFB, 0x3D, 0x2C, 0x88, 0x61, 0x42, 0x05, 0x5E, 0xE8, 0x42, 0x8B, 0xD7, 0x45, 0xAA, 0xBE, 0x1D, 0x15, 0x19, 0x1F, 0xFC, 0x93, 0xA3, 0xFA, 0x7A, 0x86, 0xB4, 0x27, 0xEB, 0x23, 0x70, 0xB7, 0x8A, 0x67, 0xA4, 0x85, 0xAF, 0x96, 0x3B, 0xBE, 0x1F, 0x22, 0x46, 0x11, 0x9F, 0xB4, 0x69, 0xA0, 0x02, 0xD7, 0x02, 0x9F, 0xC4, 0xF5, 0xF7, 0xE0, 0x12, 0x5F, 0xDA, 0x73, 0x05, 0xAC, 0xF6, 0xC8, 0x0C, 0x7B, 0xD3, 0xF6, 0x68, 0x89, 0x7B, 0xA8, 0x14, 0x35, 0xF4, 0x26, 0xB8, 0x42, 0x5C, 0x98, 0x55, 0xCD, 0x46, 0xC3, 0x44, 0x8B, 0xBA, 0xD0, 0x73, 0x9B, 0xA8, 0x8A, 0xBC, 0x27, 0x3B, 0xCD, 0x0F, 0xA1, 0xFD, 0xA7, 0xF4, 0xF8, 0x18, 0x3B, 0x5D, 0x73, 0xD1, 0x6C, 0x40, 0x7C, 0x45, 0x2A, 0xEF, 0xA2, 0xE3, 0xCA, 0x9F, 0x2D, 0x9D, 0x63, 0x8D, 0x96, 0x6A, 0x58, 0x78, 0x8B, 0x48, 0xBF, 0xC5, 0x7D, 0x3F, 0xC2, 0x08, 0x5F, 0xE8, 0x5A, 0x7F, 0x7A, 0xDD, 0xD9, 0x1E, 0xFD, 0x1B, 0xA0, 0x22, 0x60, 0x46, 0xB1, 0x27, 0xA9, 0x7B, 0xC4, 0x80, 0x47, 0x9B, 0x92, 0x88, 0x1A, 0x58, 0xA0, 0xBC, 0x04, 0xD8, 0xDD, 0x9E, 0x68, 0xB6, 0xD2, 0xBC, 0x50, 0x34, 0xCF, 0x23, 0x43, 0x0D, 0x1F, 0xE5, 0x49, 0x91, 0xA6, 0x90, 0x8B, 0x01, 0x9E, 0xE0, 0x18, 0xC8, 0x43, 0xB9, 0xFA, 0x53, 0xEC, 0x7E, 0xE5, 0xF1, 0x14, 0xAB, 0xE2, 0xB7, 0x50, 0xD4, 0xE1, 0xE7, 0x2E, 0xAF, 0xB4, 0xFB, 0xB3, 0x3A, 0x1E, 0x2C, 0x4D, 0x62, 0x72, 0xCE, 0xE2, 0x7B, 0xBB, 0x13, 0xB5, 0xD2, 0x3E, 0x24, 0xF6, 0x12, 0x9C, 0xF5, 0x82, 0x5F, 0x34, 0xAF, 0xC0, 0x56, 0xF9, 0x5F, 0x53, 0xA0, 0x9F, 0x6F, 0xCA, 0x94, 0x35, 0xCD, 0x5F, 0xB6, 0xC0, 0x5F, 0x88, 0xB4, 0xDC, 0xE8, 0x6C, 0xEA, 0xBD, 0x7E, 0x0C, 0x78, 0x53, 0x61, 0xD2, 0x53, 0xBB, 0x9C, 0xDB, 0x3A, 0x0C, 0x6B, 0xC8, 0x51, 0x83, 0x01, 0xFF, 0x44, 0xF9, 0xE8, 0x7F, 0x7A, 0x97, 0xEC, 0x9F, 0x02, 0xFA, 0xB5, 0x13, 0x4F, 0x3B, 0xBF, 0xA1, 0xCB, 0xE4, 0x4F, 0xA8, 0x3F, 0x1C, 0x54, 0x3E, 0xD9, 0xB8, 0x70, 0x65, 0x75, 0x43, 0x5A, 0xC6, 0xA1, 0x5F, 0x7B, 0x0D, 0xEB, 0xA9, 0xD4, 0x5A, 0xF5, 0x54, 0xBB, 0x0C, 0xCB, 0xCA, 0x12, 0xA6, 0xC1, 0x6E, 0x5E, 0xE6, 0xFA, 0xD6, 0x37, 0x21, 0xE4, 0xC3, 0xCC, 0x8D, 0x9E, 0xA6, 0x8C, 0x61, 0x49, 0x99, 0x30, 0x80, 0x95, 0x24, 0x07, 0xAF, 0xA2, 0x03, 0xF5, 0x04, 0xA8, 0x87, 0xB3, 0xBF, 0x84, 0xD2, 0xBB, 0x6E, 0x45, 0xE7, 0xCC, 0x53, 0x26, 0x53, 0x3D, 0x63, 0x96, 0x3F, 0xFB, 0x72, 0xA9, 0x27, 0x2C, 0x8F, 0xF6, 0x37, 0xBE, 0x6E, 0x24, 0x73, 0xE9, 0xFC, 0xAB, 0x6B, 0x5E, 0x5E, 0x7C, 0xF3, 0xED, 0xBD, 0xDA, 0xEF, 0x51, 0xC9, 0x8D, 0x53, 0x17, 0x0F, 0x9B, 0x64, 0xBC, 0xA5, 0xD4, 0x9F, 0x76, 0xAF, 0x17, 0x6D, 0x01, 0xA6, 0xF2, 0xEC, 0xB3, 0x39, 0x15, 0x1F, 0x49, 0xE4, 0x9A, 0x8F, 0x6E, 0x28, 0x6C, 0x6D, 0x41, 0x22, 0xD6, 0x50, 0xD5, 0x01, 0x59, 0x10, 0xFF, 0x7F, 0x28, 0x02, 0x46, 0x93, 0x89, 0x5C, 0x58, 0x03, 0xDD, 0xFF, 0xCB, 0x1E, 0xDC, 0x46, 0x79, 0xC8, 0xF5, 0x35, 0xAC, 0x15, 0x97, 0xD9, 0xB2, 0x8A, 0xC4, 0x6E, 0x62, 0x88, 0x81, 0x01, 0x29, 0xC1, 0x79, 0x55, 0x6A, 0xF7, 0x88, 0x2D, 0xEE, 0x17, 0xD5, 0x8A, 0x97, 0xF4, 0x34, 0xDF, 0x83, 0x64, 0x6B, 0x33, 0xCF, 0xBA, 0xB9, 0x0A, 0x62, 0x50, 0x85, 0x1C, 0xF5, 0x3D, 0x4B, 0xDB, 0x45, 0x26, 0x33, 0x7D, 0xCC, 0xB9, 0xD9, 0x8A, 0x92, 0x16, 0x76, 0xB5, 0x13, 0x65, 0xDD, 0x08, 0xA5, 0x30, 0x4D, 0x2A, 0x93, 0x53, 0x4C, 0x52, 0x42, 0x7E, 0x9A, 0xE5, 0xC1, 0x44, 0x05, 0x92, 0xC5, 0x53, 0x6E, 0x17, 0x1C, 0xF4, 0xFD, 0x1F, 0x43, 0x57, 0x8F, 0xEA, 0xFB, 0x32, 0xFF, 0x01, 0xD4, 0xFE, 0xD6, 0x35, 0xD7, 0x52, 0x56, 0x8F, 0x90, 0xEC, 0xFB, 0xB1, 0x64, 0xA5, 0xB1, 0x76, 0x3F, 0x70, 0xC7, 0x2F, 0xD5, 0xBC, 0xDF, 0x61, 0xD0, 0x1F, 0xF3, 0x23, 0x66, 0x39, 0xC9, 0x1C, 0x06, 0x3C, 0x0B, 0x7A, 0x56, 0xAD, 0x03, 0xF4, 0x02, 0x0E, 0x80, 0xBD, 0x9A, 0x5E, 0x2F, 0x16, 0x1E, 0x05, 0x78, 0x46, 0x9B, 0x99, 0x50, 0x26, 0x6B, 0xA9, 0x6B, 0xBB, 0x73, 0xC0, 0x8E, 0x7F, 0xAE, 0x85, 0x6E, 0x17, 0x03, 0xCF, 0x3C, 0xBD, 0x21, 0x41, 0x80, 0x89, 0x14, 0x8F, 0x7A, 0x9F, 0x40, 0xD4, 0xD9, 0x11, 0x51, 0xDB, 0xC4, 0xBA, 0xE8, 0x54, 0x23, 0x59, 0xE8, 0x82, 0xA1, 0x9A, 0x99, 0x49, 0xCE, 0xD5, 0xB7, 0x5F, 0xF7, 0xB1, 0x92, 0xDC, 0x27, 0x9B, 0x3E, 0xD1, 0x00, 0x76, 0x05, 0x3F, 0x58, 0xDE, 0x43, 0x5F, 0xC5, 0x87, 0x56, 0x54, 0xE9, 0x86, 0x33, 0xA3, 0x97, 0x14, 0x11, 0x42, 0x22, 0x9D, 0x8C, 0xD6, 0x13, 0xC6, 0x63, 0x44, 0x32, 0x6D, 0x83, 0x99, 0x2B, 0x3C, 0x08, 0xF1, 0x7B, 0xE0, 0xEC, 0x28, 0xFB, 0xDB, 0xAB, 0xA1, 0x2C, 0xB0, 0x00, 0xB2, 0xA2, 0xB0, 0x4E, 0x24, 0xD0, 0xC4, 0x1B, 0xD6, 0xB5, 0x80, 0xE9, 0x99, 0xB2, 0x57, 0xC0, 0x07, 0x96, 0x5C, 0x44, 0x75, 0xA9, 0xD5, 0x31, 0x4C, 0xD6, 0xC1, 0xFB, 0x9F, 0xED, 0xD5, 0x16, 0xE6, 0xB3, 0xC0, 0xDD, 0xD4, 0x04, 0xD6, 0x8D, 0x78, 0xFD, 0x4D, 0xE4, 0x09, 0x31, 0xB1, 0xB8, 0x72, 0xD4, 0xD0, 0x1A, 0x2D, 0x46, 0xC9, 0xB2, 0x93, 0x90, 0x0D, 0x34, 0xEC, 0x91, 0xD3, 0xB6, 0x93, 0xF4, 0xE7, 0x2C, 0x22, 0x8E, 0xD0, 0x29, 0x4F, 0x6D, 0xC9, 0xB7, 0x17, 0x26, 0x0E, 0xBE, 0x75, 0xA4, 0x71, 0xEA, 0x4D, 0x78, 0x00, 0xA3, 0xE7, 0xB7, 0xB4, 0x76, 0xD6, 0x4D, 0xEA, 0x6F, 0x4D, 0xA7, 0x26, 0xB3, 0x76, 0xF0, 0x78, 0x00, 0xDB, 0x5F, 0x83, 0xC0, 0xA3, 0xDC, 0xC2, 0xC7, 0x02, 0x6A, 0x4C, 0x37, 0x8E, 0x88, 0x09, 0x94, 0x88, 0x5D, 0x6F, 0x7A, 0x88, 0x19, 0xD9, 0x1A, 0x2D, 0x50, 0xD1, 0x6D, 0x22, 0xBE, 0x59, 0x2B, 0xED, 0x38, 0x33, 0x04, 0x10, 0xE1, 0x4C, 0xDD, 0xD4, 0xCE, 0x0C, 0x48, 0xD6, 0x2B, 0x77, 0x97, 0xDE, 0x44, 0xC0, 0x7F, 0x26, 0xA7, 0x9E, 0xF3, 0xA5, 0x83, 0x0F, 0x32, 0x1A, 0x35, 0xAC, 0x50, 0x7E, 0x94, 0x3C, 0x6D, 0xE6, 0x3F, 0xE1, 0x36, 0x82, 0x32, 0x25, 0xD6, 0xFC, 0x73, 0xD8, 0x6D, 0x4C, 0x84, 0x39, 0x90, 0x13, 0xE0, 0x64, 0xE6, 0x68, 0x34, 0x92, 0x90, 0x7C, 0x7B, 0x78, 0xAE, 0xF2, 0xAA, 0xB1, 0x80, 0xDC, 0x33, 0xE5, 0xE6, 0xBD, 0xBD, 0x6D, 0x49, 0x0E, 0x3A, 0xA8, 0xBE, 0x8E, 0x82, 0xFA, 0x6C, 0xB1, 0x3B, 0xEA, 0x36, 0x0C, 0x51, 0x0F, 0x9B, 0x4B, 0x5B, 0xA6, 0x64, 0x04, 0x27, 0xAD, 0xDD, 0xF3, 0xD6, 0x6D, 0xED, 0x41, 0xD1, 0xE2, 0xA0, 0x61, 0x31, 0xE9, 0x50, 0x13, 0x68, 0x42, 0x73, 0x2C, 0x27, 0x34, 0x98, 0xD6, 0xA4, 0x7C, 0xED, 0x4E, 0xD1, 0x89, 0xB6, 0xE7, 0x39, 0x36, 0x1F, 0x68, 0xCC, 0xA0, 0xA9, 0x9D, 0x56, 0x02, 0xB9, 0x76, 0x55, 0xAB, 0x26, 0x82, 0xE8, 0x37, 0xDB, 0xD6, 0x88, 0xC1, 0x73, 0xDD, 0x49, 0x50, 0xDD, 0x4C, 0xD4, 0xD3, 0xA3, 0x38, 0xF3, 0xFC, 0xFF, 0x8C, 0x71, 0x16, 0xEB, 0xC6, 0x30, 0xD0, 0x5A, 0xFA, 0xB8, 0xDF, 0x7C, 0x75, 0x60, 0xF4, 0xDE, 0x9A, 0xD9, 0x22, 0x16, 0x26, 0x8E, 0xE1, 0x43, 0xA7, 0x22, 0xC0, 0x34, 0x97, 0xCE, 0x17, 0xEF, 0xE9, 0x8F, 0x67, 0x58, 0x0F, 0x0D, 0xDE, 0xF5, 0x7F, 0x15, 0x25, 0x5E, 0x68, 0x85, 0x6D, 0x39, 0xA4, 0xEB, 0x33, 0x8A, 0x65, 0x33, 0x46, 0xFE, 0xDE, 0x46, 0x66, 0x3A, 0x62, 0x30, 0x7F, 0x65, 0x90, 0xE2, 0xEE, 0x7A, 0xB9, 0x28, 0xAC, 0x5E, 0x8F, 0xA1, 0x63, 0xAA, 0x74, 0xE4, 0x02, 0x55, 0xD8, 0xD2, 0x41, 0x66, 0x8A, 0x1C, 0x71, 0x7E, 0x3F, 0x28, 0x99, 0x43, 0x50, 0xF4, 0x99, 0x08, 0xA3, 0x2E, 0x6F, 0xEC, 0x62, 0x06, 0xBD, 0xF7, 0x93, 0x6D, 0xD2, 0xCF, 0x6A, 0x87, 0xB9, 0x99, 0x40, 0x45, 0x55, 0x2A, 0xCC, 0xE6, 0xEA, 0xF1, 0x29, 0x4E, 0x73, 0x27, 0xA1, 0x3E, 0x6E, 0xAC, 0x16, 0x22, 0x1A, 0x67, 0x6F, 0x60, 0x5D, 0x6D, 0xA6, 0x36, 0x5D, 0x0D, 0xB0, 0x11, 0x35, 0x40, 0x50, 0x13, 0xF8, 0x74, 0x48, 0x1A, 0x68, 0x33, 0x04, 0x55, 0x28, 0x1A, 0x41, 0xE8, 0x3D, 0xF7, 0x6D, 0x20, 0xD1, 0xDF, 0x75, 0xDF, 0xEC, 0xA0, 0x91, 0x7F, 0x3E, 0x94, 0xBE, 0xD2, 0x2D, 0x1E, 0xCE, 0xD8, 0xA9, 0xFC, 0x7B, 0x2A, 0x2E, 0x4A, 0x5B, 0x74, 0xD0, 0xB0, 0xC9, 0x28, 0x2B, 0xD6, 0x12, 0xA4, 0x86, 0x48, 0x99, 0x3F, 0x9F, 0x01, 0x2B, 0xD7, 0x0A, 0x0E, 0x43, 0xDC, 0x3D, 0x1C, 0x0A, 0x16, 0x71, 0x1E, 0xBF, 0x6E, 0xA4, 0x79, 0xDB, 0x94, 0x1F, 0x68, 0xA6, 0x70, 0x1B, 0x57, 0xF7, 0xB8, 0x37, 0xB3, 0x0C, 0x0A, 0x6D, 0x77, 0x11, 0x23, 0xD6, 0xFC, 0x70, 0xBD, 0xBE, 0x24, 0x44, 0x0C, 0xE4, 0xE2, 0x54, 0xA0, 0x70, 0x53, 0x4F, 0x1C, 0x18, 0x13, 0xC5, 0x16, 0x79, 0x12, 0x60, 0xA7, 0x36, 0x89, 0xDF, 0xE1, 0xBE, 0xAD, 0x6E, 0xBF, 0x6A, 0xFF, 0x7E, 0xE4, 0x8D, 0xE1, 0xD5, 0x9C, 0x62, 0x22, 0x8B, 0x38, 0x3E, 0x0A, 0xCA, 0x06, 0x90, 0xF8, 0x05, 0xFE, 0xFD, 0xC5, 0x4F, 0xC4, 0xF9, 0x74, 0xBF, 0xAC, 0xCD, 0xFE, 0x33, 0x21, 0x6C, 0xD2, 0xBC, 0x06, 0xBA, 0x7C, 0x2F, 0x55, 0xD7, 0xA0, 0x70, 0x8C, 0x48, 0x01, 0x4F, 0xF0, 0xC5, 0x35, 0xCD, 0x83, 0xD5, 0x47, 0x08, 0xFD, 0x70, 0x3E, 0x8E, 0xF5, 0x10, 0xFA, 0x60, 0x72, 0xE2, 0x5F, 0xDA, 0xEB, 0x95, 0x33, 0xD4, 0x80, 0x60, 0x53, 0x07, 0x6C, 0xB8, 0xE4, 0xFE, 0x69, 0x46, 0xFD, 0x1A, 0x67, 0x0D, 0x1B, 0xDA, 0x92, 0x31, 0x1D, 0x5E, 0xD5, 0xFA, 0x24, 0x5F, 0xA7, 0x4A, 0x6F, 0x04, 0xAE, 0x66, 0xE3, 0xC9, 0xE0, 0xA7, 0x18, 0x2C, 0xFD, 0xB2, 0x10, 0xE5, 0xA2, 0xF2, 0x8C, 0x95, 0x43, 0x99, 0x64, 0x74, 0x2A, 0x98, 0x7A, 0x16, 0x29, 0x85, 0xDB, 0x91, 0xDF, 0x91, 0xD9, 0x52, 0x9D, 0x8B, 0x85, 0x0B, 0x86, 0x28, 0xA9, 0xC5, 0xC8, 0x45, 0x5B, 0xDB, 0x41, 0x7C, 0x92, 0x72, 0x24, 0xA9, 0xA8, 0xFF, 0xCD, 0xFE, 0x00, 0xC2, 0x28, 0xFA, 0x28, 0x4C, 0x50, 0x52, 0x57, 0x70, 0x98, 0x15, 0x1E, 0x33, 0x78, 0x7F, 0x82, 0x87, 0xCB, 0x0D, 0x24, 0x31, 0x32, 0x45, 0x55, 0x84, 0x8A, 0x8D, 0x9C, 0xDF, 0xE3, 0xE4, 0xF0, 0xF1, 0x42, 0x61, 0xD0, 0xFB, 0xFC, 0x02, 0x3C, 0x59, 0x6C, 0x74, 0x9E, 0xAE, 0xFB, 0x0A, 0x17, 0x84, 0xC8, 0xCF, 0xE5, 0xE7, 0x44, 0x8A, 0x98, 0x9F, 0xD8, 0xD9, 0x43, 0x66, 0xB4, 0xC7, 0xD6, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x0F, 0x1E, 0x23, 0x2B, 0x32, 0x38, 0x3E, }, }, { .name = "Dilithium Round 3, Level 5 (8-7) KAT 1", .version = 0, .keyform = CK_IBM_DILITHIUM_KEYFORM_ROUND3_87, .rho_len = 32, .rho = { 0xB5, 0x41, 0xC1, 0xE9, 0x2C, 0xEA, 0xDD, 0x90, 0x4A, 0x09, 0xEC, 0x08, 0xAD, 0x30, 0x6D, 0x97, 0x47, 0x34, 0xA0, 0x77, 0x86, 0x84, 0x71, 0xE5, 0x8D, 0x07, 0x71, 0x87, 0xC4, 0x66, 0x04, 0xCF, }, .seed_len = 32, .seed = { 0x95, 0x2D, 0x21, 0x81, 0xAC, 0x1F, 0x62, 0x59, 0x6F, 0x76, 0x7E, 0xFC, 0xA0, 0xB5, 0x5D, 0xB0, 0x92, 0xEF, 0x81, 0xDB, 0x66, 0xF9, 0xFF, 0xF1, 0x5F, 0x13, 0xD7, 0xAE, 0xEA, 0xCD, 0x8B, 0x3A, }, .tr_len = 32, .tr = { 0x6C, 0xA7, 0x8E, 0x25, 0x84, 0x0D, 0x7D, 0xA0, 0x3C, 0x92, 0xE0, 0x1B, 0x8D, 0xD2, 0xC6, 0xDB, 0x77, 0xFC, 0x68, 0x70, 0x64, 0x73, 0x6C, 0xA8, 0x44, 0x8D, 0x40, 0x3E, 0x6F, 0x18, 0xC0, 0x2C, }, .s1_len = 672, .s1 = { 0x03, 0x40, 0x28, 0x8C, 0x88, 0x60, 0x21, 0xB1, 0x90, 0x0C, 0x12, 0x0D, 0x58, 0x18, 0x09, 0x23, 0x44, 0x86, 0x03, 0x02, 0x84, 0x89, 0xB2, 0x28, 0x0C, 0x97, 0x2C, 0x11, 0xC2, 0x09, 0x18, 0x32, 0x08, 0x09, 0x10, 0x91, 0x14, 0x82, 0x8C, 0x13, 0x03, 0x05, 0x11, 0x01, 0x4C, 0x62, 0x18, 0x8A, 0xDB, 0x08, 0x8A, 0x93, 0x38, 0x12, 0x09, 0xA9, 0x20, 0xE4, 0xA8, 0x41, 0x1A, 0xA1, 0x40, 0xD1, 0x42, 0x2E, 0x59, 0x92, 0x24, 0xD0, 0x26, 0x00, 0x19, 0x93, 0x84, 0xE2, 0x28, 0x92, 0x1B, 0x19, 0x50, 0xA3, 0x10, 0x8E, 0xA2, 0x28, 0x20, 0x93, 0x34, 0x70, 0x94, 0xC0, 0x4D, 0x24, 0x35, 0x41, 0x14, 0x05, 0x62, 0xC2, 0x22, 0x31, 0x1A, 0x38, 0x4E, 0xCC, 0x42, 0x44, 0x13, 0x20, 0x82, 0x08, 0x18, 0x6D, 0xE0, 0x14, 0x0D, 0x01, 0x36, 0x61, 0x08, 0x22, 0x29, 0x14, 0xB5, 0x11, 0x49, 0x22, 0x32, 0xE2, 0x42, 0x26, 0xE4, 0x04, 0x01, 0x5B, 0x48, 0x2A, 0x11, 0x02, 0x60, 0x63, 0x02, 0x48, 0x4A, 0x24, 0x2C, 0x62, 0x40, 0x90, 0x03, 0x41, 0x8D, 0x18, 0xC8, 0x30, 0x82, 0x02, 0x82, 0x51, 0x98, 0x69, 0xA2, 0x24, 0x50, 0x0A, 0x39, 0x4D, 0x84, 0x00, 0x8E, 0x84, 0x08, 0x21, 0xD9, 0x30, 0x6C, 0xE3, 0x18, 0x29, 0x23, 0x45, 0x6E, 0xCA, 0x24, 0x66, 0x08, 0x21, 0x49, 0x14, 0x16, 0x52, 0xDA, 0xA0, 0x0C, 0x22, 0x19, 0x62, 0xC1, 0xB8, 0x08, 0x8A, 0x88, 0x8C, 0x22, 0xB1, 0x0C, 0x23, 0xB8, 0x0D, 0x00, 0x93, 0x64, 0x93, 0x16, 0x82, 0x63, 0x32, 0x30, 0xDC, 0xA2, 0x41, 0xD1, 0x48, 0x42, 0x82, 0xA2, 0x64, 0xD4, 0x24, 0x48, 0x94, 0x48, 0x25, 0x02, 0x82, 0x65, 0xD9, 0x08, 0x69, 0x12, 0x44, 0x21, 0x54, 0x24, 0x70, 0x04, 0x80, 0x84, 0xDA, 0x44, 0x25, 0xA0, 0x24, 0x8A, 0x13, 0x35, 0x60, 0x84, 0xA0, 0x4C, 0x93, 0x90, 0x48, 0x13, 0x47, 0x02, 0x83, 0x20, 0x05, 0x64, 0xB4, 0x0C, 0x5C, 0x12, 0x72, 0x42, 0x14, 0x86, 0x60, 0x02, 0x12, 0x50, 0x44, 0x04, 0x0B, 0x82, 0x11, 0x91, 0x18, 0x72, 0x48, 0x88, 0x10, 0xD0, 0x40, 0x4D, 0xCB, 0x98, 0x51, 0x49, 0xA4, 0x8D, 0x18, 0x25, 0x89, 0xD4, 0x32, 0x8E, 0x52, 0xA4, 0x10, 0x11, 0x40, 0x12, 0x88, 0x26, 0x88, 0x21, 0x17, 0x6A, 0xA2, 0xB2, 0x41, 0xE4, 0x02, 0x89, 0xA1, 0xA0, 0x30, 0x94, 0xC8, 0x41, 0x1B, 0x83, 0x64, 0x12, 0x05, 0x0A, 0x1C, 0x43, 0x8C, 0x84, 0x06, 0x31, 0x0A, 0xA2, 0x6D, 0x24, 0x17, 0x31, 0xC3, 0x98, 0x28, 0x42, 0x88, 0x25, 0x8C, 0x30, 0x52, 0xA0, 0x02, 0x0E, 0x98, 0x36, 0x88, 0x03, 0x81, 0x31, 0x64, 0x18, 0x6C, 0x09, 0x82, 0x69, 0x19, 0x41, 0x4C, 0xA0, 0x26, 0x11, 0x23, 0x35, 0x60, 0x01, 0x04, 0x85, 0x64, 0x86, 0x30, 0xD9, 0x20, 0x84, 0xD9, 0x08, 0x2A, 0xDC, 0x32, 0x61, 0x1C, 0xC2, 0x80, 0x89, 0x82, 0x51, 0x14, 0x10, 0x40, 0x19, 0x05, 0x80, 0x58, 0x04, 0x06, 0x99, 0x08, 0x84, 0x09, 0x27, 0x41, 0xCA, 0x20, 0x8A, 0x93, 0x00, 0x91, 0x03, 0xC6, 0x81, 0xC2, 0xC8, 0x09, 0xC3, 0x30, 0x4D, 0x23, 0x12, 0x0A, 0x9B, 0x42, 0x8D, 0x20, 0x23, 0x6A, 0x54, 0x30, 0x22, 0xCC, 0xA4, 0x29, 0xA2, 0x18, 0x31, 0x40, 0x20, 0x6E, 0x92, 0x90, 0x48, 0x41, 0xB8, 0x45, 0x83, 0x38, 0x08, 0x5C, 0x46, 0x80, 0x59, 0x36, 0x45, 0xE3, 0xB0, 0x31, 0x18, 0x06, 0x6A, 0x53, 0x16, 0x6D, 0x21, 0x99, 0x81, 0x00, 0x30, 0x4E, 0xC8, 0x26, 0x48, 0x18, 0xC0, 0x88, 0x19, 0x14, 0x92, 0xC1, 0x98, 0x45, 0x98, 0x08, 0x84, 0x9B, 0x10, 0x4D, 0x0C, 0x96, 0x90, 0x08, 0x91, 0x69, 0x0C, 0xB1, 0x4D, 0x91, 0x28, 0x6E, 0xC9, 0x06, 0x8C, 0x58, 0x00, 0x0A, 0x0C, 0x96, 0x05, 0x8A, 0x46, 0x06, 0xD4, 0x98, 0x29, 0x83, 0x26, 0x50, 0xE1, 0x10, 0x61, 0xD0, 0x96, 0x50, 0x23, 0x12, 0x24, 0x52, 0x20, 0x80, 0xE4, 0x04, 0x48, 0x0C, 0x23, 0x92, 0x0B, 0xB7, 0x0D, 0x0C, 0x82, 0x90, 0xD1, 0x10, 0x90, 0x21, 0x22, 0x11, 0x0A, 0x12, 0x64, 0x53, 0xB6, 0x71, 0x99, 0x28, 0x69, 0xC1, 0xC4, 0x4D, 0x04, 0xA0, 0x8D, 0xCB, 0x96, 0x41, 0x58, 0x14, 0x06, 0x0C, 0x21, 0x70, 0x8B, 0x30, 0x25, 0x52, 0xA2, 0x25, 0x21, 0x19, 0x30, 0x00, 0xA3, 0x28, 0xD0, 0xB8, 0x09, 0xCC, 0x16, 0x12, 0xDC, 0x94, 0x6D, 0x01, 0x20, 0x81, 0xDC, 0x42, 0x42, 0xE1, 0x28, 0x01, 0x0C, 0x87, 0x89, 0x02, 0x84, 0x09, 0x02, 0x17, 0x88, 0xD8, 0x34, 0x30, 0x1C, 0x33, 0x64, 0x44, 0xA0, 0x09, 0xA0, 0xA0, 0x0D, 0xE3, 0x90, 0x4D, 0x01, 0x08, 0x65, 0xE2, 0x42, 0x69, 0xA2, 0xC0, 0x91, 0x99, 0x16, 0x62, 0x9B, 0x02, 0x60, 0x40, 0x88, 0x50, 0x40, 0x86, 0x71, 0xA4, 0xC4, 0x61, 0x62, 0x22, 0x20, 0x10, 0x12, 0x11, }, .s2_len = 768, .s2 = { 0x4B, 0x26, 0x22, 0x09, 0x07, 0x88, 0x1A, 0x26, 0x85, 0x58, 0x86, 0x80, 0xDA, 0xA0, 0x8C, 0x0B, 0x85, 0x68, 0x42, 0x22, 0x82, 0x88, 0x24, 0x61, 0x8C, 0x98, 0x8C, 0x23, 0x30, 0x25, 0x24, 0x40, 0x45, 0x08, 0xC8, 0x6C, 0x23, 0x14, 0x28, 0x4A, 0x28, 0x10, 0x81, 0x20, 0x72, 0x88, 0x32, 0x26, 0x93, 0xA6, 0x6D, 0x5B, 0xB6, 0x29, 0xC1, 0x24, 0x0D, 0x49, 0x20, 0x70, 0x59, 0x48, 0x26, 0x20, 0x26, 0x65, 0xCB, 0xA4, 0x88, 0x4A, 0xA6, 0x30, 0x08, 0x45, 0x8E, 0x00, 0x32, 0x88, 0x24, 0x33, 0x0D, 0xA1, 0x46, 0x72, 0x9B, 0x12, 0x00, 0x14, 0xB5, 0x21, 0xE3, 0x02, 0x09, 0x23, 0x42, 0x28, 0x19, 0xB2, 0x05, 0x92, 0xA4, 0x44, 0x00, 0x06, 0x45, 0x04, 0xC6, 0x29, 0x5C, 0x12, 0x50, 0xA2, 0x90, 0x45, 0x92, 0x22, 0x86, 0x9B, 0x24, 0x31, 0x9C, 0x12, 0x65, 0x94, 0xB0, 0x01, 0x98, 0x26, 0x65, 0xD2, 0x48, 0x0E, 0x62, 0x46, 0x20, 0x89, 0x82, 0x61, 0x08, 0x45, 0x08, 0x64, 0xA6, 0x91, 0x9C, 0x42, 0x6D, 0x9A, 0x96, 0x0C, 0x49, 0x24, 0x32, 0x04, 0xB1, 0x65, 0x83, 0x16, 0x45, 0x8A, 0x22, 0x22, 0x1A, 0x42, 0x02, 0x83, 0x46, 0x2C, 0x1C, 0x33, 0x72, 0x5A, 0x24, 0x00, 0xD4, 0x30, 0x80, 0x0A, 0x23, 0x08, 0x24, 0xA4, 0x84, 0x01, 0xC0, 0x41, 0x44, 0xC0, 0x09, 0x51, 0xA8, 0x2C, 0x01, 0x20, 0x8D, 0x82, 0x14, 0x72, 0x23, 0x30, 0x12, 0x11, 0x12, 0x52, 0x0A, 0x11, 0x00, 0x00, 0x43, 0x90, 0xDC, 0x36, 0x4D, 0x88, 0x96, 0x05, 0xC9, 0xB8, 0x45, 0x64, 0x02, 0x4A, 0x61, 0x00, 0x0C, 0x82, 0x18, 0x4E, 0x91, 0x00, 0x8E, 0x23, 0x12, 0x91, 0x41, 0xB8, 0x91, 0x1B, 0x18, 0x0C, 0x0B, 0x46, 0x89, 0xD2, 0x18, 0x8D, 0x19, 0x84, 0x10, 0xC0, 0x86, 0x0D, 0x03, 0x16, 0x25, 0xC3, 0xC2, 0x70, 0x19, 0x87, 0x31, 0x1A, 0x24, 0x2C, 0x08, 0x14, 0x01, 0x14, 0x04, 0x6C, 0xC2, 0x46, 0x04, 0x13, 0x10, 0x06, 0xC9, 0x08, 0x49, 0x04, 0xB1, 0x70, 0x54, 0xA2, 0x0C, 0x01, 0x24, 0x6A, 0x90, 0x18, 0x45, 0x24, 0x47, 0x49, 0x1B, 0xA2, 0x40, 0x02, 0x32, 0x80, 0x60, 0x98, 0x50, 0x8B, 0x48, 0x91, 0x5A, 0x46, 0x12, 0x13, 0x49, 0x71, 0x1C, 0x96, 0x01, 0x22, 0x15, 0x29, 0x20, 0xB5, 0x00, 0x04, 0xC3, 0x05, 0x4C, 0x24, 0x12, 0x80, 0x40, 0x4E, 0x14, 0xA1, 0x4C, 0xDB, 0x16, 0x4D, 0x00, 0x08, 0x24, 0xE2, 0x48, 0x80, 0xD4, 0x98, 0x44, 0x89, 0xC2, 0x68, 0x84, 0x24, 0x52, 0x02, 0x24, 0x61, 0x5C, 0x38, 0x11, 0x60, 0x96, 0x44, 0xA3, 0x02, 0x0E, 0x04, 0xB5, 0x81, 0xD1, 0x48, 0x24, 0xE0, 0x18, 0x49, 0x91, 0x06, 0x88, 0x93, 0x88, 0x61, 0x52, 0xA8, 0x20, 0x50, 0x22, 0x85, 0x23, 0x28, 0x2C, 0xC3, 0x08, 0x12, 0x89, 0x22, 0x8D, 0x11, 0x22, 0x0D, 0xC2, 0x30, 0x12, 0x0A, 0x98, 0x2D, 0x22, 0x19, 0x86, 0x08, 0x89, 0x40, 0x0B, 0x21, 0x69, 0x04, 0xB3, 0x00, 0x61, 0x38, 0x0D, 0x04, 0x10, 0x2D, 0x5A, 0x24, 0x65, 0x8C, 0x12, 0x0A, 0x5C, 0x42, 0x0E, 0x5A, 0x26, 0x90, 0xA1, 0x36, 0x88, 0xA1, 0x38, 0x4D, 0x1B, 0x04, 0x8E, 0xDC, 0x00, 0x0A, 0x0B, 0x35, 0x6A, 0xC2, 0x02, 0x91, 0x83, 0x48, 0x20, 0x11, 0x02, 0x86, 0xD2, 0xA2, 0x2D, 0x1C, 0x00, 0x29, 0x0C, 0x30, 0x12, 0x20, 0x91, 0x6D, 0x02, 0x87, 0x91, 0x40, 0x82, 0x44, 0x09, 0x98, 0x4C, 0x24, 0x13, 0x52, 0x09, 0x92, 0x4C, 0x4A, 0xB0, 0x01, 0x01, 0x46, 0x80, 0x10, 0x03, 0x44, 0x94, 0xB6, 0x49, 0xDC, 0xA0, 0x51, 0xA4, 0x04, 0x0C, 0x14, 0xC6, 0x68, 0x24, 0x09, 0x22, 0x9B, 0x20, 0x0E, 0x09, 0x28, 0x69, 0xDA, 0x16, 0x69, 0x09, 0xA4, 0x80, 0x0C, 0x39, 0x60, 0xDC, 0xC0, 0x10, 0x23, 0x89, 0x0D, 0xDB, 0x10, 0x41, 0xCB, 0xB2, 0x6C, 0x12, 0xC2, 0x04, 0x08, 0x92, 0x68, 0xCA, 0x06, 0x20, 0xE0, 0x36, 0x0E, 0x04, 0xC2, 0x49, 0x18, 0x27, 0x68, 0x24, 0xA8, 0x29, 0x42, 0x42, 0x6A, 0x8B, 0xB6, 0x25, 0x82, 0x26, 0x00, 0x1C, 0x07, 0x42, 0x1B, 0x02, 0x26, 0x94, 0x90, 0x85, 0x13, 0xA7, 0x30, 0x09, 0x24, 0x40, 0x5A, 0xA8, 0x44, 0x49, 0x00, 0x8A, 0x59, 0x18, 0x24, 0x90, 0x28, 0x80, 0x88, 0x08, 0x71, 0x21, 0x47, 0x2D, 0x52, 0x34, 0x80, 0x0B, 0x96, 0x04, 0x9C, 0x38, 0x09, 0x8C, 0xA4, 0x30, 0x19, 0xA9, 0x8C, 0x03, 0x45, 0x4C, 0x51, 0xA0, 0x68, 0x04, 0x22, 0x42, 0x11, 0x18, 0x82, 0xA2, 0x96, 0x48, 0xE4, 0x36, 0x72, 0xCB, 0x24, 0x28, 0x23, 0xA7, 0x2D, 0xDC, 0x38, 0x00, 0x89, 0x36, 0x06, 0x4B, 0x92, 0x89, 0x03, 0x49, 0x71, 0xDA, 0x10, 0x06, 0x0A, 0x39, 0x0C, 0x40, 0x14, 0x82, 0xDA, 0x80, 0x48, 0x9A, 0x86, 0x88, 0x59, 0x44, 0x50, 0x89, 0xC4, 0x61, 0x59, 0x22, 0x42, 0x10, 0xB0, 0x24, 0x8B, 0x40, 0x6C, 0x8C, 0x20, 0x46, 0x23, 0x09, 0x60, 0xC4, 0x98, 0x85, 0x5A, 0xA4, 0x01, 0x01, 0x39, 0x46, 0xC1, 0x94, 0x71, 0x8C, 0xC2, 0x40, 0x0C, 0x22, 0x25, 0x53, 0x00, 0x66, 0x4C, 0x26, 0x30, 0x21, 0xC0, 0x2D, 0x98, 0x30, 0x6A, 0x94, 0x24, 0x50, 0x21, 0x12, 0x81, 0x0B, 0x12, 0x00, 0x9C, 0x94, 0x0C, 0x9B, 0x36, 0x6C, 0x94, 0x26, 0x85, 0x8A, 0x12, 0x30, 0xA3, 0xA0, 0x89, 0x42, 0x08, 0x50, 0x44, 0x16, 0x2C, 0x20, 0x38, 0x29, 0x5C, 0x32, 0x61, 0x63, 0xA4, 0x6D, 0x58, 0x48, 0x72, 0xDA, 0x26, 0x22, 0x89, 0xA4, 0x8D, 0xD3, 0x32, 0x26, 0x0C, 0x32, 0x04, }, .t0_len = 3328, .t0 = { 0xDD, 0x9E, 0x51, 0x56, 0xEB, 0x0F, 0xB3, 0x78, 0x1A, 0x12, 0x27, 0x3B, 0xE3, 0x14, 0xE7, 0x1E, 0x56, 0x59, 0x60, 0x44, 0xDA, 0x83, 0xAB, 0xFB, 0x24, 0xC7, 0x79, 0x9A, 0x81, 0x46, 0x43, 0x4E, 0x93, 0x49, 0x03, 0x49, 0x29, 0x00, 0x0A, 0xF0, 0x29, 0xBA, 0x14, 0x68, 0x07, 0x48, 0xA8, 0x99, 0xE8, 0x3D, 0xD9, 0x21, 0x1D, 0x3E, 0x8D, 0xE8, 0x41, 0x9C, 0xE1, 0x20, 0xCF, 0x5B, 0xCA, 0x55, 0x29, 0x7A, 0x27, 0xD8, 0x35, 0x4F, 0x66, 0xFB, 0x83, 0x7B, 0x10, 0x8D, 0x7D, 0xC7, 0xE3, 0x2D, 0x14, 0x5B, 0xB4, 0x01, 0x65, 0x24, 0x42, 0xEB, 0xF5, 0x45, 0xC4, 0xA1, 0x2C, 0x70, 0x19, 0x18, 0xD2, 0x49, 0x4C, 0x03, 0xA1, 0x12, 0xC0, 0xD9, 0x42, 0xDC, 0xB4, 0x4D, 0xFA, 0xEC, 0x31, 0xAE, 0xAA, 0xE3, 0x2A, 0x5B, 0xAD, 0xBB, 0x8C, 0x82, 0xC6, 0x21, 0x77, 0x1C, 0xEA, 0x9A, 0x1E, 0xDA, 0xF7, 0x7B, 0x77, 0x7C, 0x52, 0x40, 0x28, 0x67, 0x04, 0xC0, 0x61, 0xC3, 0xAA, 0x6D, 0x68, 0x51, 0x22, 0xB4, 0xC9, 0x82, 0x46, 0x7C, 0x32, 0x9C, 0xDF, 0x89, 0x9D, 0x00, 0xF3, 0x01, 0xC5, 0x54, 0xAF, 0x57, 0xE2, 0xF9, 0x93, 0x4C, 0x3A, 0x3F, 0x36, 0xEE, 0x2D, 0xD5, 0xCB, 0x35, 0x6C, 0x47, 0x52, 0x08, 0x30, 0x79, 0x81, 0x78, 0x00, 0xA0, 0x92, 0x84, 0x51, 0x27, 0x8A, 0x26, 0xCC, 0xD6, 0x07, 0x17, 0xD4, 0x17, 0x59, 0xBC, 0x8C, 0x6F, 0x77, 0x9A, 0xFA, 0xBD, 0xFD, 0xFA, 0xFA, 0xA3, 0xA4, 0xD6, 0x2E, 0x9D, 0x1E, 0x9B, 0x3C, 0x8E, 0xDB, 0xAF, 0xBE, 0x29, 0xD7, 0x8E, 0x4D, 0x71, 0xB0, 0xCE, 0x4C, 0xF4, 0xCF, 0x15, 0x1E, 0x3E, 0x54, 0x1C, 0x29, 0x9C, 0x6E, 0xAD, 0x63, 0xA7, 0x27, 0x15, 0xCD, 0xC9, 0x5F, 0x58, 0x4C, 0x6E, 0xB3, 0x75, 0x7C, 0x66, 0x0A, 0x27, 0x59, 0x63, 0x19, 0x2B, 0xA8, 0xFD, 0xE8, 0xC2, 0xAC, 0xBD, 0x7E, 0xA9, 0xE5, 0x25, 0x92, 0x62, 0x42, 0x66, 0x59, 0xF7, 0xA5, 0x55, 0x5B, 0x80, 0xBD, 0x2C, 0xD5, 0xE7, 0xB5, 0xA6, 0xC9, 0x9B, 0x03, 0x0C, 0x88, 0x70, 0x90, 0xEE, 0x9E, 0x64, 0x67, 0xA3, 0x75, 0x5A, 0x07, 0x58, 0xC9, 0xFF, 0xD7, 0xDB, 0x4D, 0x9D, 0x03, 0x1B, 0x7B, 0x6C, 0x77, 0xCC, 0x5D, 0xA2, 0x8A, 0xF2, 0xA6, 0xD3, 0x3A, 0x25, 0x18, 0x7F, 0x7E, 0x2F, 0x5E, 0x45, 0xDD, 0x48, 0xE5, 0x1B, 0xBE, 0xAA, 0x9C, 0x06, 0xE5, 0xD2, 0xE8, 0xB0, 0x0D, 0x92, 0x58, 0x32, 0x31, 0xBB, 0xE0, 0x1F, 0x2A, 0x78, 0xA9, 0xFE, 0xB5, 0x10, 0x72, 0xC2, 0xF1, 0x13, 0x8A, 0x5C, 0x68, 0x15, 0x78, 0x66, 0x6F, 0xE5, 0x46, 0x85, 0x00, 0xB6, 0x16, 0xAC, 0x60, 0x40, 0x22, 0x5F, 0xF0, 0xA8, 0xE9, 0xBF, 0x86, 0xD6, 0x45, 0x0F, 0xD2, 0xAC, 0x8C, 0x2A, 0x3F, 0x0A, 0xE0, 0x67, 0x93, 0xBD, 0xE4, 0x34, 0x71, 0x4F, 0x1F, 0xCA, 0x30, 0xC7, 0xB1, 0x41, 0x34, 0xFF, 0xB5, 0xE7, 0x43, 0x72, 0x52, 0x17, 0x0C, 0xD4, 0x2E, 0x04, 0xBB, 0x76, 0xF5, 0x36, 0x5A, 0x3C, 0x2F, 0x80, 0xF0, 0x2A, 0x86, 0xC4, 0x07, 0xB9, 0x84, 0x03, 0xBA, 0x84, 0x8C, 0xCD, 0xF5, 0x4B, 0x60, 0x09, 0x21, 0x77, 0x46, 0x85, 0x0A, 0x67, 0x03, 0x84, 0x4A, 0x49, 0x6E, 0x1A, 0x09, 0x21, 0x9D, 0xA8, 0xA6, 0x40, 0xC9, 0x20, 0x67, 0xC0, 0xBB, 0x66, 0xA5, 0x70, 0x00, 0x78, 0x50, 0xF9, 0xB3, 0x03, 0x33, 0xA6, 0x68, 0x28, 0x3D, 0x5A, 0x15, 0xB0, 0xAF, 0x09, 0x9D, 0xEA, 0x4F, 0x52, 0xDF, 0x86, 0x5B, 0xC3, 0x58, 0x6A, 0x8C, 0x04, 0x73, 0xE7, 0xDA, 0x12, 0xDA, 0xA1, 0xA5, 0x0B, 0xF7, 0xCA, 0x5E, 0x2B, 0xBD, 0x53, 0xCB, 0xAD, 0xDC, 0xBA, 0x09, 0x18, 0x29, 0x44, 0xE8, 0x1B, 0xAE, 0xC6, 0x0D, 0xAE, 0xD7, 0x8A, 0xA8, 0xB6, 0xC3, 0xA2, 0xF4, 0x5B, 0x07, 0x16, 0xAA, 0x84, 0x29, 0xA1, 0x06, 0xDD, 0x71, 0x69, 0x40, 0x29, 0xFD, 0x1A, 0x02, 0xC5, 0xCA, 0x2D, 0x3D, 0xFD, 0xE3, 0x2E, 0xCD, 0xC5, 0x78, 0x0F, 0x72, 0x3F, 0x1E, 0x2D, 0xB7, 0x68, 0xA5, 0xA3, 0xCD, 0xAE, 0x48, 0xF9, 0x39, 0xCA, 0x15, 0x86, 0xE2, 0x30, 0x83, 0xF7, 0x3C, 0x2F, 0x62, 0x3A, 0x12, 0x1F, 0x54, 0x67, 0xAF, 0x24, 0xDA, 0xA8, 0x72, 0x63, 0x98, 0xEE, 0xED, 0x8B, 0xB1, 0xDF, 0xA4, 0x60, 0xA1, 0x12, 0xC5, 0x97, 0xAE, 0x2D, 0xD6, 0x4E, 0x90, 0x40, 0x02, 0xE0, 0xF1, 0xA9, 0x0C, 0x00, 0xF9, 0x2C, 0xAF, 0xFA, 0x7F, 0xC4, 0x46, 0x74, 0x44, 0xA6, 0xFC, 0x40, 0x39, 0x18, 0x80, 0x3A, 0x92, 0xDC, 0x2A, 0xFC, 0x3A, 0x17, 0xBC, 0xAC, 0x18, 0x7A, 0xD8, 0xB3, 0xDE, 0x0D, 0x87, 0x28, 0x30, 0xB8, 0xA7, 0xB5, 0xE5, 0x58, 0x0A, 0xBD, 0x1E, 0x27, 0xD5, 0x59, 0x4C, 0x1A, 0x6A, 0x00, 0x3D, 0x6C, 0x7C, 0x21, 0xB8, 0x71, 0xC7, 0xB6, 0x31, 0x49, 0x7A, 0x2E, 0xFE, 0x0F, 0x86, 0x2B, 0x65, 0xF6, 0x65, 0x6B, 0x09, 0x4D, 0xDB, 0xA8, 0x20, 0xE9, 0xE6, 0x31, 0x4B, 0x4B, 0xD8, 0xF7, 0x81, 0x51, 0x8D, 0x17, 0x40, 0x54, 0x97, 0xBB, 0x39, 0x06, 0x3E, 0x68, 0x33, 0xB0, 0x4D, 0xE0, 0xD3, 0x6B, 0xFC, 0x9F, 0x06, 0x14, 0xDC, 0xB7, 0xDE, 0x8D, 0x31, 0xF0, 0xE0, 0x1A, 0xB1, 0x50, 0xDE, 0x23, 0xC9, 0xD5, 0x2F, 0x80, 0x14, 0xE8, 0x85, 0x7E, 0x78, 0x6D, 0xCA, 0xED, 0x8E, 0xA4, 0x1F, 0x78, 0x09, 0x97, 0x39, 0x4F, 0x87, 0x7F, 0x52, 0x8B, 0x59, 0x9F, 0xDB, 0x85, 0x7E, 0x8F, 0xCF, 0xCA, 0x77, 0x4F, 0x35, 0x08, 0x46, 0xD0, 0x5F, 0x97, 0x3C, 0x2A, 0x1C, 0xF5, 0xFF, 0x0C, 0x58, 0xE3, 0x75, 0x90, 0xA6, 0x2F, 0x5B, 0x2A, 0x3B, 0x21, 0x26, 0x20, 0x63, 0x68, 0x2D, 0xBB, 0x0A, 0x20, 0x50, 0xBA, 0xD8, 0x44, 0x99, 0xEF, 0x5C, 0xAD, 0xCF, 0xFE, 0x41, 0xB0, 0xE7, 0x1B, 0x3F, 0x4F, 0xC3, 0x5E, 0x1E, 0x37, 0x60, 0x48, 0xE3, 0xA3, 0x4B, 0xF6, 0xBC, 0xF4, 0xF6, 0x1D, 0x2D, 0x3C, 0x35, 0x39, 0x54, 0x24, 0x94, 0xFB, 0x04, 0x57, 0xBB, 0x76, 0x2F, 0x03, 0x99, 0x63, 0x21, 0x35, 0x0B, 0x64, 0x87, 0x4B, 0xBD, 0xCE, 0x72, 0x04, 0xAB, 0x86, 0x06, 0x24, 0x58, 0x34, 0xE5, 0x99, 0x35, 0x2C, 0x36, 0x8D, 0x36, 0xC2, 0xC4, 0x63, 0x49, 0x76, 0x11, 0x9B, 0xF9, 0x72, 0xC3, 0xA4, 0xAB, 0x28, 0x76, 0x67, 0x7B, 0xEE, 0x0E, 0xBC, 0xBE, 0x30, 0xF1, 0x31, 0x66, 0x2D, 0x68, 0x64, 0x7E, 0xD5, 0xD0, 0xA8, 0xF6, 0xC8, 0x9A, 0xFB, 0xBC, 0x8B, 0xFA, 0xF1, 0xD1, 0x1B, 0x20, 0x6C, 0x33, 0x17, 0xAE, 0xD7, 0x88, 0x21, 0x35, 0x95, 0x72, 0x70, 0xEF, 0x87, 0x85, 0x2A, 0x32, 0x0A, 0x9B, 0x18, 0x4A, 0x60, 0x8C, 0xA6, 0xBC, 0x82, 0x58, 0x38, 0x2E, 0x0B, 0x19, 0xBE, 0xAA, 0x38, 0x41, 0x62, 0x3F, 0xA3, 0x07, 0x93, 0xD8, 0xF4, 0x99, 0xB8, 0x37, 0xC4, 0x40, 0xCC, 0x11, 0x3C, 0x70, 0x35, 0x0C, 0x01, 0xC3, 0xE1, 0xAC, 0xE0, 0x53, 0xDB, 0x30, 0xED, 0xFF, 0x7B, 0xA5, 0x26, 0x9D, 0x41, 0x8E, 0x8E, 0x48, 0xB9, 0x2A, 0xAC, 0x17, 0x09, 0x3D, 0x58, 0xE3, 0xAD, 0xDC, 0x78, 0xDA, 0x7B, 0xCF, 0xD9, 0xA8, 0xA8, 0xCA, 0xAB, 0x3D, 0xA2, 0x5A, 0x46, 0x34, 0xC1, 0xBC, 0x95, 0xC6, 0x4E, 0xDF, 0x2F, 0x6F, 0xE7, 0xED, 0xFB, 0xAA, 0x1B, 0xAD, 0x2D, 0x23, 0x12, 0x98, 0x0B, 0xD6, 0x80, 0xB0, 0x68, 0x92, 0xB5, 0x55, 0xF3, 0x16, 0x74, 0xA9, 0x52, 0xA1, 0x25, 0xE8, 0x87, 0x10, 0x4D, 0x1C, 0xF8, 0x3E, 0x97, 0xA0, 0x59, 0x0F, 0x47, 0x2B, 0xB3, 0xD1, 0xA2, 0xB9, 0x08, 0x32, 0x3B, 0x0E, 0xA9, 0x9F, 0x8F, 0x91, 0xFA, 0x30, 0xB9, 0x09, 0x42, 0xD7, 0xB6, 0x90, 0xAF, 0xC6, 0x1A, 0x02, 0x77, 0x99, 0xD7, 0x70, 0x2D, 0x56, 0xB7, 0x68, 0x6A, 0x8F, 0x9B, 0xB0, 0x4E, 0xDE, 0xE3, 0xCF, 0xA3, 0x92, 0x7E, 0xF5, 0x16, 0xA7, 0xF5, 0x20, 0x88, 0x59, 0x07, 0x31, 0x9B, 0x95, 0x84, 0xC8, 0x24, 0xFE, 0x97, 0xDC, 0xAF, 0xBA, 0xB5, 0xA3, 0xA7, 0x26, 0x71, 0xBA, 0x0C, 0x21, 0x88, 0x37, 0x91, 0x3B, 0x16, 0x1B, 0x42, 0x70, 0x6B, 0x9B, 0x85, 0xCB, 0x42, 0x3B, 0x9D, 0xE5, 0xF2, 0x3C, 0x23, 0x80, 0x0B, 0x9C, 0x07, 0x11, 0x13, 0x2C, 0x40, 0x34, 0x75, 0x8D, 0x2E, 0xC8, 0x6D, 0xF5, 0x78, 0xE1, 0xB9, 0xF1, 0x78, 0x5F, 0x5C, 0x79, 0x5C, 0x8B, 0xC2, 0x0F, 0xBC, 0xFF, 0xD9, 0xE4, 0xCA, 0x2E, 0x93, 0xC7, 0xCA, 0xE4, 0xDA, 0x91, 0xB9, 0xC0, 0x0E, 0x77, 0x8E, 0x3C, 0x42, 0x86, 0x53, 0x0C, 0x6C, 0x80, 0xC1, 0x02, 0x7C, 0x8F, 0xA0, 0xDD, 0x78, 0xCF, 0x0A, 0x55, 0x4A, 0xD2, 0x7B, 0x19, 0xAF, 0x2B, 0x0C, 0x28, 0xE0, 0x50, 0xD0, 0x35, 0x5F, 0xE6, 0x1D, 0xE7, 0xF7, 0x02, 0xDC, 0x07, 0x3C, 0x90, 0x47, 0xC9, 0x7D, 0x87, 0xC8, 0x15, 0x78, 0xD1, 0x98, 0xD9, 0x7B, 0x52, 0x3E, 0xBB, 0x15, 0x06, 0xD9, 0xA7, 0x52, 0x92, 0x46, 0x5E, 0x44, 0x0B, 0x20, 0x6F, 0xF9, 0x53, 0xE4, 0xA6, 0x8C, 0xBC, 0x57, 0x3E, 0x7C, 0x36, 0x45, 0xE2, 0xF8, 0xC0, 0x8F, 0xDA, 0x3B, 0xD5, 0x8E, 0xD1, 0xC9, 0x0A, 0x4F, 0x63, 0xED, 0xFD, 0xF2, 0x0C, 0x8B, 0x25, 0x7E, 0xC9, 0x16, 0xCD, 0x6A, 0xEA, 0xB8, 0xEB, 0xA4, 0x77, 0xC1, 0xF4, 0xC0, 0x9B, 0x8F, 0x69, 0xD6, 0xFE, 0xD9, 0x33, 0x19, 0xED, 0xA8, 0xEC, 0xF8, 0xC0, 0xEF, 0xE8, 0x4E, 0x5E, 0xC2, 0x71, 0x96, 0x66, 0x8E, 0x00, 0x71, 0xA0, 0x39, 0xDF, 0x3D, 0xBB, 0x87, 0x2B, 0x88, 0xAC, 0xC8, 0x53, 0xA0, 0x82, 0x20, 0x6B, 0x95, 0xE0, 0x64, 0x34, 0xFC, 0xBF, 0x3F, 0xA3, 0x09, 0xDA, 0xE2, 0x5A, 0x25, 0x1D, 0xDB, 0x58, 0x40, 0x71, 0x81, 0x39, 0xCA, 0xDF, 0x13, 0xF3, 0x92, 0xE0, 0xCE, 0x7B, 0x9C, 0x27, 0x17, 0x22, 0x26, 0xEE, 0x84, 0x71, 0xD0, 0x13, 0xB1, 0xFF, 0x45, 0x42, 0x97, 0xB7, 0x81, 0xAB, 0xAC, 0xEA, 0x43, 0x2D, 0x41, 0xFC, 0xF6, 0x9D, 0xB8, 0x85, 0x6E, 0x37, 0x7B, 0x8B, 0x4E, 0x24, 0x00, 0x86, 0xD2, 0xFB, 0x73, 0x11, 0x88, 0x51, 0x45, 0x06, 0x9A, 0x72, 0x09, 0x86, 0x9D, 0xB0, 0x61, 0xA2, 0x45, 0xB9, 0x62, 0xE1, 0x86, 0x81, 0x0A, 0x19, 0x23, 0x74, 0x70, 0x18, 0x85, 0x79, 0x31, 0x24, 0x69, 0x84, 0x7C, 0x53, 0x85, 0x66, 0x6E, 0xA0, 0xF3, 0xB5, 0x94, 0x22, 0xC0, 0xF6, 0x9B, 0x09, 0xB5, 0xB8, 0xBD, 0x08, 0x07, 0xCE, 0x99, 0x92, 0x14, 0x2A, 0x34, 0xEE, 0x32, 0x7E, 0x8F, 0xDA, 0x2C, 0xBA, 0x0F, 0x40, 0x10, 0xF6, 0xD5, 0x24, 0xFF, 0x0C, 0x5B, 0xE4, 0x12, 0x9E, 0x98, 0xB2, 0x01, 0xAB, 0x91, 0x8A, 0x52, 0x76, 0xA7, 0x35, 0x6B, 0x15, 0x2E, 0x60, 0x70, 0xCF, 0xDC, 0x27, 0x0C, 0x5D, 0x8D, 0x70, 0x8E, 0xE8, 0xCB, 0xB7, 0x01, 0x95, 0xCF, 0xA6, 0xA2, 0x9E, 0x8B, 0x07, 0x2F, 0x25, 0xF0, 0x3F, 0x25, 0x36, 0x2D, 0x59, 0x0F, 0x5B, 0xB2, 0xB6, 0x7B, 0xD6, 0x3F, 0x3F, 0xA5, 0x2F, 0x2C, 0x61, 0x1D, 0x72, 0x57, 0x25, 0xF0, 0x42, 0xD5, 0x82, 0x4C, 0x77, 0x3C, 0xF8, 0xE6, 0x1F, 0xED, 0xBA, 0x92, 0xC5, 0x80, 0xDC, 0xA7, 0x33, 0x48, 0xEC, 0x67, 0x60, 0x9D, 0x30, 0x1E, 0x74, 0x16, 0x44, 0xAA, 0x3A, 0x0B, 0x24, 0x41, 0xC5, 0x88, 0xED, 0x7F, 0x17, 0x1B, 0xC7, 0xB9, 0x54, 0x92, 0xEF, 0x14, 0xAE, 0xB5, 0x44, 0x78, 0x6F, 0x23, 0x27, 0x35, 0x08, 0x56, 0x1C, 0xCB, 0x81, 0x03, 0xE2, 0xFA, 0x97, 0xD3, 0x5F, 0x29, 0xD7, 0xDE, 0x89, 0x08, 0x97, 0xF1, 0xEC, 0x97, 0x41, 0x81, 0xC7, 0x9B, 0xE3, 0x20, 0x01, 0xFC, 0x0E, 0x91, 0xA0, 0xFB, 0xD7, 0xB0, 0xEF, 0xB8, 0xCC, 0x2D, 0xB6, 0x19, 0xD3, 0x64, 0x85, 0xCC, 0xCF, 0xD3, 0xB5, 0xDB, 0x94, 0xC0, 0x82, 0x0A, 0x53, 0x6C, 0xC8, 0xA2, 0xD7, 0x8F, 0x5A, 0x9B, 0x95, 0xCE, 0xF4, 0xD3, 0x7B, 0xC8, 0x74, 0x14, 0x22, 0xBB, 0x61, 0xC3, 0xD0, 0xFE, 0x5B, 0xA4, 0x9D, 0x75, 0x42, 0x67, 0xA0, 0x10, 0x31, 0xF4, 0xDF, 0x52, 0xDE, 0xFF, 0xB5, 0xC8, 0x98, 0xA0, 0x96, 0x47, 0xEF, 0x3F, 0x02, 0x4F, 0xCD, 0xD9, 0x0E, 0xFA, 0x94, 0x38, 0xC9, 0xDE, 0x93, 0xAA, 0xD9, 0x8E, 0xFF, 0x29, 0x49, 0xEE, 0xC8, 0xBC, 0x3A, 0x0F, 0x3E, 0x60, 0xE4, 0xB5, 0x6B, 0xED, 0x02, 0x63, 0xE0, 0x4A, 0x5D, 0x3C, 0x68, 0x68, 0x76, 0x49, 0xA1, 0x00, 0x58, 0x34, 0x88, 0xF9, 0x83, 0xCD, 0x7F, 0x43, 0x41, 0x30, 0x90, 0xFC, 0x88, 0x0C, 0x11, 0xE8, 0x5E, 0xDC, 0x24, 0x44, 0x6C, 0x35, 0x70, 0xAA, 0xB5, 0xDA, 0xEE, 0x3B, 0x7E, 0xD4, 0xD3, 0x53, 0x98, 0x8D, 0x02, 0xC7, 0x3D, 0x77, 0x7D, 0xCE, 0x26, 0xD1, 0x2A, 0x39, 0x5E, 0xB1, 0xB9, 0x5F, 0xFC, 0x7A, 0xB5, 0x83, 0x43, 0xAE, 0xCD, 0x2D, 0xCE, 0xCA, 0xB0, 0x0A, 0x97, 0xF5, 0x78, 0xB9, 0x32, 0x7D, 0x0A, 0x9D, 0x1F, 0xDB, 0x65, 0x10, 0xF8, 0x60, 0x68, 0x5C, 0xC3, 0x03, 0x6F, 0xD8, 0x32, 0x6F, 0x59, 0xA4, 0xE9, 0xA0, 0xDD, 0x7B, 0x02, 0xCE, 0x1D, 0x36, 0xBF, 0x46, 0xF4, 0xFA, 0x41, 0x15, 0x17, 0x2C, 0xBF, 0xDA, 0xDA, 0x6D, 0x59, 0x35, 0x26, 0xB7, 0x47, 0xE2, 0x36, 0x7B, 0x10, 0xA8, 0x83, 0x92, 0x68, 0x7D, 0xE2, 0x23, 0xBF, 0x1D, 0x5A, 0xF1, 0xD7, 0x3D, 0x8A, 0x24, 0x84, 0x5C, 0x87, 0xFF, 0x76, 0x67, 0x5D, 0x73, 0xD5, 0x09, 0xF2, 0x83, 0xDA, 0x66, 0xB9, 0x43, 0xAD, 0x45, 0x6A, 0xFE, 0x70, 0x92, 0x51, 0xB1, 0x7F, 0x9E, 0x43, 0x58, 0x7E, 0x52, 0x0C, 0xD6, 0xA1, 0xE9, 0xA2, 0x4B, 0x55, 0x8F, 0x4F, 0x6E, 0x46, 0x57, 0xF4, 0xC6, 0x35, 0x1D, 0xEA, 0x9B, 0xB9, 0x47, 0xB3, 0x2D, 0xC4, 0x6E, 0x35, 0x20, 0xFC, 0xE3, 0xBD, 0x21, 0x97, 0x3C, 0x3B, 0x8B, 0x95, 0x15, 0x04, 0x58, 0xCB, 0x5E, 0x42, 0x48, 0xE2, 0x6D, 0x6E, 0x52, 0xE7, 0x6B, 0x8E, 0x6B, 0xF2, 0xBC, 0xE3, 0xC8, 0xAC, 0x1C, 0x6C, 0xFD, 0x7F, 0x43, 0x51, 0x3A, 0x91, 0x8F, 0xEC, 0x31, 0xCE, 0xC0, 0xD4, 0x29, 0x66, 0x05, 0xAB, 0x21, 0xBC, 0xE4, 0x1E, 0x32, 0x9F, 0x47, 0xFB, 0x1B, 0xB6, 0x74, 0x48, 0xD9, 0x1F, 0x41, 0x9B, 0x18, 0x26, 0xC8, 0xB7, 0x46, 0x65, 0x5F, 0xEB, 0x8F, 0x4A, 0x0D, 0x95, 0xE6, 0x99, 0x0D, 0xB8, 0xA4, 0xBE, 0x33, 0xC1, 0x36, 0x2F, 0xCC, 0x17, 0x1B, 0x08, 0x43, 0x21, 0xE2, 0x2A, 0xCD, 0x06, 0x13, 0x1D, 0x2C, 0x34, 0xA0, 0x43, 0x48, 0xE4, 0x30, 0xDC, 0x78, 0x52, 0x78, 0x58, 0xBB, 0x38, 0x6B, 0xA2, 0xF4, 0xEC, 0xC0, 0xF3, 0xA0, 0x62, 0xCB, 0xDF, 0xF2, 0xA4, 0x8F, 0x23, 0x71, 0x60, 0x58, 0x59, 0xEE, 0x81, 0xD6, 0xF8, 0xEA, 0x88, 0x6E, 0x00, 0x60, 0x66, 0x19, 0x34, 0x32, 0xAF, 0xCD, 0x97, 0x08, 0xE8, 0x38, 0x2B, 0x1C, 0xC2, 0xE8, 0x3C, 0x79, 0x2D, 0xF4, 0xB4, 0xB9, 0xE0, 0xE0, 0x5D, 0x42, 0x34, 0x79, 0xE2, 0x54, 0xCC, 0xA4, 0xDF, 0x99, 0x90, 0x80, 0x26, 0x1D, 0x45, 0x0C, 0x3E, 0xD7, 0x33, 0x0E, 0x6F, 0xFF, 0xFF, 0x5E, 0x6D, 0x6C, 0x89, 0x37, 0x20, 0xD3, 0x1B, 0x4E, 0x83, 0xB5, 0x14, 0x80, 0x5B, 0xFF, 0x76, 0x58, 0x6B, 0x63, 0x05, 0xD7, 0xBE, 0x0A, 0x96, 0xD7, 0x4F, 0x2B, 0x86, 0xC9, 0x74, 0xED, 0x21, 0x0F, 0x5C, 0xF7, 0xFF, 0xAD, 0xE8, 0x54, 0x53, 0xA9, 0xFA, 0x1B, 0xF3, 0x40, 0xBD, 0x0B, 0xD8, 0xA5, 0xAC, 0x15, 0x2B, 0xE5, 0x59, 0x8D, 0x77, 0xB0, 0x08, 0x15, 0x22, 0x66, 0xA0, 0x1E, 0xFE, 0x20, 0x61, 0x5D, 0xC2, 0x51, 0x48, 0x4D, 0xF4, 0xCF, 0xF5, 0xF5, 0x71, 0xA7, 0x32, 0xDA, 0x1A, 0x9E, 0xD8, 0x9F, 0x6C, 0x44, 0x61, 0x7F, 0x32, 0x72, 0xA0, 0xF4, 0xE7, 0x27, 0x58, 0x18, 0x6B, 0xD4, 0xDC, 0xA1, 0xB4, 0xA4, 0x5D, 0xBA, 0x23, 0x2A, 0xE7, 0xF2, 0x21, 0x48, 0xA4, 0x95, 0xBC, 0xEA, 0x2E, 0xC3, 0x76, 0x1D, 0x1E, 0x06, 0x10, 0x3B, 0xCC, 0xE3, 0x6F, 0xAC, 0x74, 0xBD, 0x2F, 0x8E, 0x42, 0xAF, 0xBB, 0xE8, 0x0B, 0x25, 0xDC, 0xB8, 0x09, 0xD4, 0x4E, 0xF9, 0x5D, 0xBF, 0x7F, 0x1A, 0x96, 0x5E, 0xDA, 0xF9, 0x89, 0xAF, 0xA3, 0xBB, 0xF4, 0x9C, 0x2F, 0xEA, 0x9E, 0xE2, 0x09, 0xE8, 0xF1, 0x17, 0x8F, 0x5D, 0x01, 0x8B, 0xF9, 0xC0, 0x15, 0xC4, 0x51, 0x12, 0xEC, 0x17, 0xAE, 0x38, 0x0B, 0x09, 0xB2, 0x31, 0xE0, 0x15, 0xFF, 0xE2, 0xC3, 0x50, 0x48, 0x1A, 0xA8, 0xE1, 0x1B, 0x2B, 0xB5, 0x9A, 0x25, 0x1B, 0x0D, 0xEA, 0x0D, 0x30, 0x79, 0xF0, 0x40, 0xF3, 0x3B, 0x6A, 0x6C, 0xCE, 0x48, 0xB6, 0xAB, 0x24, 0x00, 0x8A, 0xAB, 0xE1, 0x81, 0xE3, 0x1B, 0x55, 0x3A, 0xE4, 0x95, 0xB0, 0xFD, 0x76, 0xA1, 0x3E, 0x07, 0x62, 0x0A, 0x72, 0x4B, 0x25, 0x6E, 0x34, 0x4F, 0x0B, 0x54, 0x1A, 0x57, 0x46, 0x0F, 0x6A, 0x75, 0x27, 0xC8, 0x26, 0xA4, 0x63, 0x67, 0x53, 0xB7, 0xDE, 0xD6, 0x28, 0x48, 0xDB, 0x83, 0xDC, 0xE4, 0xBD, 0x08, 0x54, 0xD9, 0x98, 0x1D, 0x38, 0xA9, 0x63, 0xC6, 0xC7, 0x87, 0xF3, 0xE1, 0x82, 0x6B, 0xF6, 0xDA, 0x44, 0xD9, 0x5A, 0x31, 0x55, 0xB0, 0x3D, 0xA5, 0xC9, 0xA4, 0x27, 0xCF, 0x6A, 0xD3, 0x6B, 0x6D, 0x67, 0x6F, 0x0D, 0xF8, 0x21, 0x10, 0x61, 0xFE, 0x33, 0x23, 0xF3, 0x20, 0x37, 0x74, 0x78, 0x70, 0x04, 0x36, 0xD9, 0xFE, 0xEC, 0x76, 0xF8, 0x10, 0xFE, 0x20, 0xBC, 0xA5, 0xD0, 0xBA, 0xBB, 0xD0, 0x2E, 0xD8, 0xA3, 0x8B, 0xA4, 0x28, 0x04, 0x49, 0x20, 0xFE, 0x0C, 0x68, 0xDC, 0x6A, 0xDE, 0x9F, 0xA6, 0xE3, 0x97, 0x68, 0x0C, 0x03, 0xED, 0x81, 0x5F, 0x68, 0x48, 0x59, 0xE6, 0x7C, 0xFA, 0x06, 0x37, 0xBE, 0x55, 0x56, 0xF9, 0x5F, 0x27, 0x0D, 0x5E, 0xC9, 0x1C, 0x64, 0x42, 0x94, 0xCB, 0xA9, 0x65, 0xDF, 0xD9, 0x61, 0x71, 0x3E, 0xCE, 0x53, 0x32, 0x8D, 0x99, 0x17, 0xB1, 0xCE, 0xF8, 0x9C, 0xF1, 0x7B, 0x9F, 0x5B, 0x65, 0x57, 0x49, 0xD8, 0x6C, 0x10, 0x95, 0x63, 0x7B, 0xAD, 0x53, 0x2A, 0xFC, 0x5B, 0x39, 0xF3, 0xDA, 0xA0, 0x1F, 0x74, 0x0C, 0xBF, 0x49, 0xF7, 0x57, 0x0F, 0x4B, 0xDC, 0xF1, 0x92, 0x41, 0xB6, 0x14, 0x9C, 0x8C, 0xF2, 0x49, 0x2B, 0x02, 0x57, 0xCA, 0x67, 0xC3, 0x95, 0xEC, 0xB1, 0x9C, 0x04, 0x95, 0x9A, 0x85, 0x93, 0x79, 0xB6, 0x54, 0xDB, 0x7B, 0x67, 0xCC, 0xB7, 0xAE, 0x99, 0xDA, 0x88, 0xC1, 0x84, 0x1F, 0xD6, 0xEE, 0x6E, 0xA5, 0x21, 0xA6, 0x06, 0x9E, 0x64, 0x26, 0xD3, 0x82, 0xF8, 0x8C, 0xD2, 0x57, 0x17, 0xD8, 0x04, 0x51, 0xD1, 0xA8, 0xF1, 0x09, 0x7D, 0xA5, 0xD7, 0x15, 0x28, 0xF4, 0x48, 0xF3, 0x72, 0xA2, 0x25, 0x53, 0x60, 0x62, 0x67, 0x85, 0x8E, 0x1C, 0x9D, 0xEF, 0x6F, 0x45, 0x66, 0x98, 0x5C, 0xDE, 0xC3, 0x17, 0xCD, 0xCE, 0x2D, 0x59, 0x56, 0x08, 0x66, 0x86, 0xFA, 0x9E, 0xDC, 0x49, 0xDB, 0xEB, 0xF2, 0x60, 0xEB, 0x23, 0xB8, 0x57, 0x3B, 0x98, 0x07, 0x6E, 0x4B, 0x11, 0xA7, 0x13, 0xE7, 0x24, 0x78, 0xD2, 0x0D, 0x10, 0xE9, 0xE9, 0x20, 0xB1, 0xFC, 0xC5, 0x62, 0xE0, 0x8F, 0x9A, 0xB7, 0xA6, 0xDB, 0x96, 0x00, 0x58, 0xD7, 0x99, 0x30, 0x31, 0x53, 0xB1, 0x3D, 0x2F, 0xC2, 0x54, 0x47, 0x07, 0x46, 0x92, 0xD6, 0xD4, 0x6F, 0x8B, 0x5C, 0x7C, 0xE9, 0xF6, 0x17, 0xDC, 0x28, 0x13, 0x58, 0xF9, 0xF1, 0x0E, 0x26, 0x87, 0xDA, 0x06, 0x54, 0x1B, 0x50, 0xD1, 0x05, 0x06, 0xBA, 0x3A, 0xF2, 0x98, 0x75, 0x5A, 0xA1, 0xB4, 0x7D, 0x8D, 0x56, 0x13, 0x5E, 0xCA, 0xFE, 0xD1, 0xD1, 0xCD, 0xE7, 0xD5, 0xBF, 0xD0, 0x9E, 0x37, 0xB4, 0x64, 0x9B, 0xFE, 0x06, 0x55, 0x7B, 0x4E, 0x86, 0xF9, 0x04, 0xD3, 0xA8, 0xCB, 0x7F, 0x28, 0x21, 0x71, 0x57, 0xA8, 0x3C, 0x5E, 0x04, 0x2D, 0x19, 0xC1, 0x2D, 0x8E, 0xD0, 0x9D, 0x68, 0xB2, 0xAB, 0x73, 0x07, 0xBB, 0x6C, 0xAF, 0x63, 0x9B, 0x3A, 0xEE, 0xB5, 0x13, 0xD3, 0x3C, 0xEE, 0x09, 0x8D, 0x6D, 0xD0, 0x36, 0x0C, 0x83, 0x2C, 0x3B, 0x7B, 0x18, 0x3D, 0xB5, 0xE7, 0xFD, 0xB4, 0x55, 0x8D, 0x93, 0x3E, 0x56, 0x10, 0xBC, 0x2A, 0x08, 0x2E, 0x16, 0x9E, 0x04, 0xFE, 0x34, 0x1B, 0x07, 0x84, 0xAE, 0xB5, 0x29, 0x10, 0xE7, 0xA2, 0x01, 0x82, 0x0F, 0x6B, 0x3C, 0x57, 0x2B, 0x37, 0x74, 0xF2, 0x9A, 0x7B, 0xF1, 0x61, 0xAC, 0xBA, 0xBE, 0x5F, 0x0B, 0x14, 0xB3, 0xC1, 0xDE, 0x8D, 0x8F, 0xBB, 0x20, 0x5E, 0xE7, 0x40, 0x0A, 0x06, 0x81, 0xF7, 0x98, 0x52, 0xE6, 0xBF, 0x1B, 0x5A, 0x50, 0x33, 0xD9, 0x04, 0x01, 0x47, 0xE0, 0x64, 0xDC, 0x10, 0xEA, 0xC0, 0x42, 0x11, 0x0C, 0x43, 0x09, 0x2D, 0xD4, 0x40, 0x2B, 0x64, 0x58, 0x4A, 0x81, 0xD6, 0xD2, 0x11, 0xD4, 0x00, 0x8E, 0xE1, 0xF1, 0x9E, 0xB0, 0x0E, 0x84, 0xDC, 0x3A, 0x3D, 0xBE, 0x22, 0x1A, 0xE8, 0x6E, 0xAC, 0xAE, 0xA6, 0x83, 0x24, 0xD2, 0xF1, 0xA5, 0x73, 0x0F, 0x03, 0x32, 0xEA, 0xD6, 0x4F, 0x02, 0xB9, 0xB5, 0x97, 0x09, 0xF1, 0x51, 0x03, 0xE2, 0x6D, 0x89, 0x71, 0xB7, 0xB6, 0xDB, 0xCF, 0xC8, 0x75, 0x04, 0xFE, 0xB0, 0x0E, 0xD4, 0x1A, 0x02, 0x78, 0x9E, 0xB9, 0x79, 0xE2, 0xCB, 0xF7, 0x47, 0x26, 0x89, 0x64, 0xAB, 0xC8, 0x41, 0x2A, 0x53, 0x93, 0x70, 0xBF, 0x52, 0x0D, 0x9A, 0xAE, 0xF9, 0x29, 0xE8, 0xBA, 0xFD, 0x8E, 0x18, 0x5B, 0xE2, 0xAA, 0xB0, 0x40, 0xA7, 0x7A, 0x7B, 0xF6, 0x80, 0x7F, 0x0A, 0x8A, 0x41, 0xAC, 0x61, 0x89, 0xBF, 0x00, 0xAB, 0xC7, 0x7C, 0x62, 0x05, 0x17, 0xBE, 0xAF, 0xBF, 0x0A, 0x63, 0x05, 0x8D, 0x8D, 0x47, 0x8F, 0xCB, 0xC4, 0x2C, 0x6A, 0x77, 0x83, 0xC7, 0x69, 0x51, 0x6F, 0x24, 0x06, 0xD4, 0x4C, 0x23, 0x52, 0x99, 0xBF, 0x2E, 0x4E, 0x1C, 0xFF, 0xB7, 0xBE, 0xA0, 0x04, 0x0C, 0x94, 0x58, 0xA1, 0xC7, 0x74, 0x18, 0x63, 0x66, 0xC1, 0x17, 0x4B, 0x04, 0xB5, 0x43, 0xF7, 0x2B, 0xD5, 0x4A, 0x30, 0xFF, 0x99, 0x47, 0xE8, 0x2E, 0x90, 0x47, 0x4C, 0xDD, 0xC6, 0xF0, 0x69, 0xB4, 0x1F, 0xC7, 0x68, 0xB8, 0x0A, 0x02, 0xED, 0x29, 0xC8, 0x30, 0xAD, 0x27, 0xCD, 0xFC, 0x68, 0x6C, 0x64, 0x6A, 0xEA, 0x27, 0x9B, 0x22, 0xE6, 0x09, 0x2E, 0xD3, 0xA1, 0x72, 0x72, 0x19, 0xB2, 0x81, 0xE9, 0x72, 0xF5, 0x0C, 0x88, 0x66, 0xF4, 0x4E, 0x19, 0x8B, 0x0F, 0x24, 0xFF, 0xA6, 0xA7, 0x39, 0x5D, 0x1E, 0x41, 0x05, 0x84, 0x2A, 0x60, 0xE0, 0x17, 0x35, 0x50, 0x48, 0x1C, 0x64, 0x12, 0xF6, 0xB5, 0xAE, 0x7F, 0xF6, 0x54, 0xFD, 0x43, 0xC0, 0xD6, 0x7E, 0x8A, 0x65, 0xB6, 0x6D, 0x6D, 0x52, 0x47, 0xD6, 0xB1, 0xD5, 0xC6, 0x60, 0xCB, 0xAC, 0xF2, 0xCB, 0xDF, 0x0D, 0x81, 0xA1, 0x68, 0xED, 0x6C, 0x82, 0x7D, 0xDC, 0xDB, 0xA0, 0xAF, 0x5B, 0xF2, 0x50, 0x42, 0x72, 0x85, 0xF3, 0x0F, 0x5C, 0x6D, 0x20, 0xED, 0x03, 0x47, 0x20, 0x33, 0x76, 0x4F, 0x2B, 0x19, 0x88, 0x4F, 0x66, 0x2D, 0x45, 0x45, 0xBA, 0x21, 0x89, 0xD2, 0xA2, 0xA3, 0xC2, 0x9F, 0x4E, 0x89, 0xD5, 0xF5, 0x5E, 0xC6, 0xDC, 0x8E, 0x49, 0x7B, 0xA6, 0x75, 0xFE, 0x22, 0x42, 0xDA, 0x34, 0x80, 0x8C, 0x8D, 0xA5, 0xD0, 0xE5, 0x68, 0xE7, 0x86, 0x91, 0x96, 0xCB, 0x45, 0x9D, 0x6B, 0x65, 0xA2, 0x77, 0x82, 0x0F, 0x7D, 0xD7, 0x8A, 0x31, 0xA5, 0x3B, 0x2F, 0xE7, 0x02, 0x1C, 0x9F, 0x51, 0xBB, 0x63, 0x41, 0xCB, 0xE3, 0xCF, 0xA5, 0xF6, 0x89, 0xB8, 0xE5, 0x4F, 0x00, 0x28, 0x51, 0x71, 0x4B, 0xAA, 0x8D, 0x2D, 0x8E, 0xF9, 0x13, 0xDB, 0x9A, 0x14, 0x4B, 0x6F, 0xF6, 0x6A, 0xEC, 0x4C, 0xEF, 0x06, 0xE9, 0xD2, 0x73, 0x49, 0x60, 0xD7, 0xFA, 0xEC, 0x0E, 0x64, 0x2D, 0xC5, 0x69, 0xCA, 0xFA, 0xB3, 0xA9, 0x32, 0x08, 0x81, 0xAE, 0xAF, 0xF8, 0x02, 0x72, 0x36, 0x18, 0xB5, 0x77, 0x69, 0x1C, 0x93, 0x72, 0x02, 0x1D, 0x40, 0x92, 0xE0, 0xBD, 0x91, 0x3D, 0x38, 0xD7, 0x69, 0x55, 0xAA, 0x79, 0x2A, 0x85, 0x20, 0x2B, 0x5A, 0x90, 0x62, 0xD9, 0x7F, 0xE6, 0x57, 0x45, 0xD8, 0xC5, 0x50, 0xCF, 0xD0, 0xD4, 0x18, }, .t1_len = 2560, .t1 = { 0x2C, 0xAF, 0xB7, 0x2F, 0x71, 0x55, 0x72, 0xBF, 0x43, 0x28, 0x38, 0xE0, 0x80, 0xCA, 0x4A, 0x19, 0x8A, 0x28, 0x4B, 0xBD, 0xF0, 0xC4, 0x54, 0xF0, 0x94, 0x5E, 0x95, 0x3D, 0xD0, 0x71, 0x99, 0xD2, 0xC6, 0x21, 0x0E, 0x59, 0xE6, 0xED, 0x17, 0x7D, 0xA8, 0xF0, 0xBB, 0x19, 0xEF, 0x02, 0x9E, 0x6F, 0xDB, 0x3B, 0xAC, 0x91, 0x00, 0x13, 0x11, 0x60, 0x51, 0x8B, 0xB2, 0xA8, 0x85, 0x56, 0xA8, 0xF4, 0x8A, 0xA1, 0x97, 0x23, 0x6B, 0x4F, 0x00, 0x46, 0x78, 0x6C, 0xF0, 0xD2, 0x37, 0x4D, 0xA1, 0x9A, 0x5D, 0xF8, 0x0B, 0x19, 0xB1, 0x3D, 0xB3, 0x33, 0xB0, 0xD3, 0x0D, 0x7B, 0x1C, 0xE8, 0xD8, 0x1F, 0x71, 0x66, 0xB0, 0x5E, 0x0E, 0x45, 0x67, 0x02, 0x92, 0x34, 0x83, 0x41, 0xCE, 0xF0, 0xCF, 0xEC, 0xB2, 0xC6, 0x1F, 0xAE, 0x5B, 0x5E, 0x8C, 0x05, 0x3E, 0xB2, 0x94, 0x71, 0xE1, 0x79, 0xA2, 0x1F, 0x0D, 0xDF, 0x15, 0xB7, 0xA9, 0xF2, 0x8C, 0xF3, 0x58, 0x0F, 0x7D, 0x0E, 0xBA, 0x06, 0xE7, 0x22, 0x67, 0xEB, 0xBA, 0x35, 0xAB, 0xDC, 0xD3, 0x12, 0xBD, 0x3B, 0xBE, 0x6A, 0xC8, 0xEF, 0x24, 0x64, 0xD0, 0xB4, 0xBC, 0xA5, 0x44, 0x16, 0x7A, 0xF7, 0x53, 0x19, 0x5B, 0x40, 0x57, 0x00, 0x27, 0x3A, 0xDB, 0xAF, 0x24, 0x5F, 0x73, 0x3B, 0x1F, 0xD7, 0x74, 0xBC, 0x5D, 0xE7, 0x7C, 0xE2, 0xD8, 0x27, 0x2B, 0xCF, 0x6F, 0x99, 0xCC, 0x2C, 0xB2, 0x3E, 0x08, 0x27, 0xA0, 0x2F, 0x3F, 0x0F, 0xCA, 0x3B, 0xEC, 0x62, 0x22, 0xAE, 0xFC, 0x76, 0x22, 0x52, 0x5D, 0x86, 0xF7, 0x59, 0xF5, 0x19, 0xE4, 0xCE, 0xD5, 0x5B, 0x93, 0xD5, 0x6E, 0xA1, 0x09, 0x18, 0x2F, 0x0A, 0x75, 0x65, 0xD9, 0xF8, 0x4D, 0x74, 0x6A, 0x9A, 0x32, 0xB4, 0x42, 0x7B, 0xF6, 0x92, 0x99, 0x53, 0x36, 0x63, 0x37, 0xAE, 0x46, 0xCF, 0x78, 0xAB, 0xE2, 0x11, 0x92, 0xBD, 0x6A, 0x6C, 0x90, 0xAC, 0x8D, 0xAD, 0x66, 0xBF, 0x71, 0x37, 0x48, 0xC1, 0xA3, 0xE6, 0x73, 0x7D, 0xB3, 0x93, 0xB0, 0x18, 0x6C, 0xEA, 0x9D, 0x0E, 0xBA, 0x62, 0x47, 0xB9, 0x0C, 0x94, 0x32, 0x86, 0xED, 0x0E, 0x13, 0x4C, 0xF2, 0x89, 0x27, 0xA3, 0x29, 0xD3, 0x56, 0x45, 0x5A, 0x6E, 0x56, 0x5D, 0x14, 0xDD, 0xDF, 0x5F, 0xA7, 0x0B, 0xF3, 0xAD, 0x13, 0xF4, 0xEE, 0x51, 0x65, 0x8A, 0x92, 0x38, 0xCB, 0x97, 0x90, 0x24, 0xE5, 0x8D, 0x64, 0xF3, 0x79, 0x6F, 0x4C, 0xE3, 0x7C, 0x23, 0xF1, 0x0E, 0x44, 0x1F, 0x50, 0xD9, 0x76, 0x38, 0x8C, 0x6D, 0xEC, 0xED, 0x8E, 0xD9, 0x35, 0xD2, 0xC6, 0xC6, 0xBB, 0x12, 0xC6, 0x12, 0xAF, 0xB7, 0xA0, 0x2D, 0x91, 0x34, 0x26, 0xB6, 0xAE, 0x22, 0x39, 0x00, 0x4E, 0xEC, 0x58, 0xAD, 0xA2, 0xFE, 0x3C, 0x67, 0xC4, 0xE2, 0xA9, 0xF0, 0x3E, 0x49, 0x03, 0x50, 0xFC, 0x47, 0x18, 0xF3, 0x6A, 0x86, 0x1D, 0x93, 0xD2, 0x47, 0x3C, 0xCB, 0x31, 0xB7, 0xF1, 0xD7, 0xAD, 0xAE, 0xD5, 0xE0, 0xCE, 0x6A, 0xA9, 0x38, 0x18, 0x57, 0x9E, 0x15, 0x71, 0x27, 0x19, 0x0A, 0xB4, 0x08, 0x40, 0x20, 0x40, 0x4C, 0x61, 0xC2, 0xE5, 0xC6, 0x78, 0xDC, 0x37, 0xCB, 0x53, 0x65, 0x40, 0xA4, 0x3F, 0x5C, 0xC6, 0x99, 0xDC, 0x40, 0x95, 0xFE, 0x03, 0xFB, 0x7C, 0xEC, 0x5E, 0xFD, 0x3D, 0x9C, 0x87, 0x50, 0x32, 0xDF, 0x94, 0x57, 0x16, 0x46, 0x2B, 0xA3, 0xAE, 0x6D, 0xBF, 0x6C, 0x5B, 0xC8, 0x99, 0xAB, 0x8A, 0x7C, 0x59, 0xC5, 0xF6, 0x6B, 0x74, 0x78, 0xB1, 0x61, 0xF4, 0x22, 0x98, 0x6C, 0xDA, 0x91, 0xD0, 0x8B, 0xE7, 0x58, 0x49, 0x4B, 0xA1, 0x75, 0x9B, 0x1E, 0x05, 0x7E, 0x31, 0xA4, 0x15, 0xD7, 0x0A, 0xCC, 0xC0, 0x80, 0xC7, 0x6D, 0x6C, 0x32, 0x09, 0x9C, 0xF7, 0x45, 0xAC, 0x61, 0xCC, 0x42, 0xA9, 0x6E, 0x59, 0x4F, 0x3D, 0x78, 0x76, 0x98, 0x31, 0x3D, 0x62, 0xAD, 0x6C, 0xD4, 0x6A, 0xF5, 0x90, 0x66, 0xE1, 0xE5, 0xCA, 0x9F, 0x83, 0xC7, 0xE5, 0xC6, 0x8C, 0xAE, 0x2D, 0x63, 0x2C, 0xF4, 0xF6, 0xA1, 0x7A, 0xA8, 0x0F, 0xF5, 0x34, 0x97, 0xB6, 0xFE, 0x50, 0xB3, 0xE6, 0x21, 0x5C, 0x2F, 0xE4, 0x65, 0x7B, 0xB1, 0xE2, 0x56, 0x94, 0xE0, 0x79, 0x7E, 0xA4, 0x0E, 0x95, 0x75, 0x8B, 0xE6, 0x8E, 0xF3, 0x0E, 0xB9, 0xE3, 0xF5, 0xB6, 0xAF, 0xFF, 0x45, 0xA7, 0x7D, 0xAC, 0xD0, 0xEA, 0xB5, 0xC1, 0x03, 0x14, 0xE3, 0x1B, 0x6C, 0xDF, 0x85, 0xF4, 0x74, 0x1B, 0xFF, 0xE6, 0xD0, 0x1C, 0xE2, 0xA2, 0xB9, 0xC3, 0xDF, 0x0A, 0xE8, 0x7A, 0x4A, 0x7A, 0x99, 0x02, 0xBC, 0xA1, 0x24, 0x90, 0xDC, 0x27, 0x9B, 0x81, 0xC0, 0x37, 0xA4, 0xF9, 0xE8, 0xAF, 0xB9, 0xC9, 0xD8, 0x52, 0x4F, 0x84, 0x7D, 0xED, 0xF8, 0x0C, 0x41, 0xBB, 0xE2, 0x36, 0xCC, 0x0D, 0x1C, 0xD7, 0x9D, 0x46, 0x3B, 0xFF, 0x96, 0xCD, 0x7C, 0x31, 0x87, 0x95, 0x24, 0x76, 0x32, 0xAB, 0x01, 0xA1, 0xF0, 0x52, 0xF4, 0xF7, 0x30, 0xDD, 0xD1, 0x7B, 0xD1, 0x0A, 0xBF, 0x36, 0x34, 0x41, 0x52, 0xD5, 0xB8, 0x41, 0x15, 0x5B, 0x71, 0x79, 0x2B, 0xB4, 0x1F, 0x5C, 0x9E, 0x33, 0x16, 0x5D, 0x3D, 0xCE, 0x8E, 0xA5, 0xFE, 0xFE, 0xC6, 0x3F, 0xAD, 0x10, 0x8B, 0x26, 0xC0, 0xC3, 0x77, 0x33, 0x92, 0x57, 0x0D, 0x13, 0x6D, 0x67, 0xFC, 0xEF, 0xC7, 0x10, 0x8D, 0x1E, 0x9D, 0x99, 0x30, 0x2B, 0xD5, 0x78, 0x45, 0x33, 0xD5, 0x62, 0x44, 0xE0, 0x12, 0x67, 0x54, 0x0F, 0x5D, 0x06, 0xC1, 0xD4, 0xCA, 0xF6, 0x5B, 0x4E, 0xAA, 0x67, 0x38, 0x51, 0x48, 0xCB, 0xD1, 0xC7, 0x3E, 0xAD, 0x46, 0x74, 0x31, 0x9A, 0xBF, 0x03, 0x14, 0x03, 0x05, 0x4A, 0x39, 0x05, 0x49, 0x52, 0x48, 0x47, 0xE6, 0x9C, 0x93, 0x29, 0x40, 0x22, 0x0C, 0xB6, 0xFC, 0x18, 0xE0, 0x6F, 0x11, 0x29, 0x89, 0xA2, 0x37, 0xAB, 0x7F, 0x3B, 0x65, 0x41, 0xF6, 0x99, 0xE0, 0x2F, 0x71, 0x43, 0x53, 0x99, 0x59, 0x15, 0xFF, 0xB7, 0x34, 0xC6, 0xC0, 0xB7, 0x15, 0x0D, 0x5D, 0xD4, 0xB1, 0x72, 0x83, 0x6F, 0x7A, 0x75, 0xD1, 0x0C, 0x58, 0xCE, 0x5F, 0x68, 0x62, 0x1F, 0x2C, 0x6C, 0xB6, 0xDC, 0x49, 0xF1, 0x14, 0xCE, 0x55, 0x6C, 0xDB, 0xF5, 0xF4, 0x73, 0x91, 0x21, 0x2F, 0x1B, 0xCB, 0xFB, 0xB4, 0xAA, 0x7C, 0x99, 0x27, 0x80, 0xFC, 0x51, 0x2D, 0x21, 0x5E, 0xCC, 0xB1, 0x60, 0x52, 0x4E, 0x4E, 0xAC, 0x73, 0x8A, 0x04, 0x83, 0x0A, 0xE4, 0x11, 0xA0, 0x9D, 0xFC, 0xEE, 0x5D, 0xEF, 0x02, 0xC9, 0x75, 0xD2, 0xCD, 0x08, 0x88, 0xAD, 0x16, 0xA2, 0xDF, 0x46, 0x99, 0xD5, 0xE7, 0x10, 0xFF, 0xFC, 0x45, 0xF0, 0x2C, 0x4C, 0xC9, 0xD9, 0x64, 0x7F, 0x1A, 0xAC, 0x14, 0x06, 0x00, 0x12, 0x23, 0xFE, 0x56, 0x4D, 0xD5, 0xA4, 0x3C, 0xBA, 0xAE, 0xFE, 0xD2, 0xBC, 0x94, 0x4F, 0x1C, 0x10, 0x8A, 0x8C, 0x2D, 0xA4, 0x48, 0x53, 0xFF, 0xE8, 0x38, 0x4A, 0x07, 0x4D, 0xD7, 0x26, 0x96, 0xDC, 0x68, 0x3F, 0x64, 0x48, 0x17, 0x4B, 0xF0, 0x4B, 0x6A, 0x4F, 0x8A, 0x09, 0xE8, 0x21, 0xDC, 0xD4, 0xEF, 0x92, 0xB4, 0xDC, 0x54, 0x0C, 0x7C, 0x46, 0x54, 0x53, 0x67, 0x37, 0x33, 0x2B, 0xE9, 0x61, 0xC0, 0xD9, 0xBA, 0xC6, 0xC4, 0x4C, 0xE8, 0x78, 0x92, 0x94, 0x2E, 0xA4, 0xE6, 0x81, 0xD7, 0xAB, 0x65, 0xAB, 0x2F, 0xCA, 0x41, 0x83, 0x7E, 0x0F, 0x45, 0x5F, 0x4E, 0x55, 0xC9, 0xE5, 0x11, 0xA7, 0xD9, 0xD7, 0x60, 0x25, 0xA7, 0x9B, 0x43, 0x45, 0x6F, 0xEA, 0x7F, 0xB3, 0x49, 0x2E, 0xF8, 0xAA, 0x06, 0x9C, 0x46, 0x8C, 0xF7, 0x4D, 0x02, 0xA6, 0xB5, 0x52, 0xD1, 0xB8, 0xA1, 0x44, 0x18, 0x8C, 0xD6, 0x8A, 0x8A, 0x60, 0x99, 0x85, 0xAB, 0x62, 0xD1, 0xCC, 0xBC, 0xCA, 0x7E, 0xFF, 0x91, 0xDE, 0x5C, 0xC6, 0xE0, 0x80, 0x1D, 0x04, 0xE3, 0x30, 0x93, 0xEB, 0x70, 0x49, 0x8E, 0xA8, 0xCB, 0x05, 0x06, 0x18, 0xB2, 0x72, 0xAF, 0x06, 0x2D, 0xD4, 0xDC, 0x10, 0x9C, 0x19, 0xC8, 0x63, 0xAA, 0x59, 0xF5, 0xB8, 0xAF, 0x74, 0x42, 0xBD, 0xA3, 0xE4, 0x11, 0xCE, 0x36, 0xD1, 0x44, 0xD6, 0xCD, 0x3F, 0x57, 0x2F, 0x1C, 0xFE, 0x67, 0x26, 0x98, 0xB0, 0xC0, 0x74, 0x3B, 0xCE, 0xD7, 0x32, 0x9A, 0xDB, 0x98, 0x45, 0xCA, 0xFF, 0x6C, 0x10, 0xB2, 0x6C, 0x32, 0x51, 0x6F, 0x9E, 0x53, 0x8C, 0x83, 0x0B, 0x61, 0x62, 0x7D, 0x68, 0xEA, 0x76, 0x8D, 0xD0, 0x3E, 0x98, 0x0B, 0x40, 0x2B, 0x76, 0x59, 0xEA, 0x65, 0x66, 0xD7, 0x36, 0xF7, 0x88, 0x1A, 0x8D, 0x0E, 0x42, 0xA8, 0xCA, 0x24, 0x7E, 0x51, 0x29, 0xB0, 0x28, 0x92, 0x5B, 0xE7, 0x53, 0xC3, 0x91, 0xD7, 0x75, 0x03, 0x5A, 0x44, 0x69, 0x6E, 0x26, 0xF8, 0xA6, 0x48, 0x7C, 0x7C, 0x8D, 0xE7, 0xD0, 0x49, 0x22, 0xB8, 0x75, 0xCC, 0xD3, 0xD2, 0x12, 0x11, 0x66, 0xC3, 0x34, 0x6B, 0x51, 0xD5, 0xD5, 0x43, 0x76, 0x53, 0xCC, 0xDB, 0xDF, 0x49, 0x85, 0x65, 0xB1, 0xBF, 0x1B, 0xDF, 0x91, 0x82, 0xC4, 0x3B, 0x15, 0x4B, 0x00, 0xC0, 0x42, 0x48, 0x00, 0xB6, 0xA8, 0xE9, 0x64, 0xF4, 0x37, 0xD3, 0xDF, 0xA6, 0xA6, 0x48, 0x20, 0x0D, 0xC0, 0xE0, 0x7D, 0xD2, 0xDA, 0x98, 0x19, 0xFC, 0xF2, 0xB2, 0x25, 0x8E, 0x07, 0xF0, 0xC5, 0x0A, 0xF4, 0x43, 0x30, 0x43, 0x5B, 0x23, 0x48, 0xB7, 0x4C, 0xCC, 0x5F, 0x24, 0xE5, 0xDC, 0xCF, 0x67, 0xB0, 0x63, 0xDB, 0x59, 0x70, 0xBC, 0x7B, 0x59, 0x04, 0x99, 0xB2, 0xDB, 0x49, 0xFB, 0x2E, 0xB3, 0xF0, 0x88, 0x3E, 0x97, 0x04, 0x20, 0x9A, 0xFF, 0x45, 0xBF, 0xB6, 0x12, 0x70, 0xEB, 0xB1, 0x3D, 0x89, 0x14, 0x60, 0xBD, 0x5E, 0x8B, 0x5F, 0xCE, 0x07, 0x3B, 0x50, 0x82, 0xC6, 0x5B, 0x0F, 0xE3, 0x7C, 0x7D, 0xC4, 0x14, 0xCC, 0xA3, 0xEF, 0xD1, 0x08, 0x5F, 0x58, 0x16, 0xFC, 0x71, 0x0C, 0xF4, 0x5B, 0x45, 0x5B, 0x98, 0xAE, 0x53, 0xA2, 0x4A, 0x2D, 0x92, 0x40, 0x0B, 0xCD, 0x15, 0xA0, 0xFE, 0xA7, 0x94, 0xC4, 0x63, 0xBB, 0x59, 0x15, 0x39, 0xD1, 0x17, 0x19, 0x50, 0xCA, 0xA3, 0x47, 0x61, 0x67, 0x90, 0xCF, 0x8D, 0x22, 0xC5, 0x46, 0xE7, 0x5A, 0x6E, 0xEB, 0x72, 0x68, 0x09, 0xD0, 0xC0, 0x72, 0xFF, 0x21, 0x61, 0xA2, 0xA4, 0x41, 0xFD, 0xF3, 0x9C, 0xAD, 0x7A, 0x18, 0xF2, 0xB0, 0xB4, 0x26, 0x1D, 0xC2, 0xD3, 0xB4, 0x17, 0xB8, 0x44, 0xAD, 0xB7, 0x1E, 0xB7, 0xE7, 0x2F, 0xE2, 0x4F, 0x8D, 0xDE, 0x92, 0xD7, 0xC4, 0xF2, 0xDA, 0x29, 0x3A, 0xCC, 0x92, 0x23, 0xA8, 0x73, 0x3A, 0x84, 0x99, 0x65, 0x63, 0x2D, 0x77, 0x10, 0xF7, 0xA7, 0xBB, 0x87, 0x04, 0x1A, 0x3D, 0x3A, 0x51, 0x66, 0xBA, 0x90, 0x65, 0x7E, 0x03, 0xAF, 0x26, 0xA9, 0xD1, 0x0D, 0x66, 0x19, 0x9E, 0x60, 0xEE, 0x70, 0xD3, 0xFB, 0xF3, 0x9F, 0xE4, 0x6C, 0xFC, 0x8D, 0xDC, 0x73, 0x68, 0x34, 0xE4, 0xE4, 0x05, 0xF8, 0x3C, 0xDD, 0x0C, 0xAA, 0xF8, 0x16, 0x28, 0xC7, 0x98, 0x99, 0xEA, 0xED, 0xBF, 0x25, 0x03, 0x18, 0x77, 0xE1, 0x62, 0x67, 0x5D, 0x9C, 0x57, 0xF6, 0xA4, 0xD9, 0xFF, 0xE0, 0xFD, 0x68, 0x40, 0xF9, 0x9B, 0xEC, 0xE9, 0x06, 0x2C, 0x98, 0xE0, 0x74, 0xBB, 0x30, 0x71, 0x76, 0xA7, 0x8C, 0x4A, 0x4D, 0xCE, 0x9E, 0x40, 0x31, 0xBD, 0x10, 0x28, 0x55, 0x39, 0xC1, 0x80, 0xF4, 0xB8, 0xBD, 0x33, 0xE8, 0xCB, 0x11, 0xBC, 0x9C, 0x1D, 0xD9, 0x37, 0x6D, 0x73, 0xD3, 0x1D, 0x6E, 0xFE, 0x1A, 0xCC, 0x61, 0x7E, 0xC9, 0x92, 0xE3, 0x9B, 0x49, 0x6B, 0x05, 0xB1, 0x1A, 0xCA, 0xFF, 0x35, 0x6D, 0x72, 0x53, 0x7C, 0x60, 0x11, 0x0C, 0x90, 0x51, 0xD6, 0x91, 0x7C, 0x1F, 0xFB, 0x03, 0x1B, 0x69, 0xD3, 0x9B, 0x94, 0x28, 0x85, 0x8A, 0x4B, 0xF7, 0x28, 0x83, 0xB4, 0xC7, 0x87, 0x9F, 0xEF, 0x69, 0xBF, 0xCC, 0x31, 0xA1, 0xCF, 0xB3, 0x39, 0xC5, 0x79, 0x47, 0xFC, 0x79, 0x1B, 0xDA, 0x3E, 0x81, 0x20, 0x5D, 0x04, 0x6E, 0x1B, 0xFA, 0xB8, 0xE0, 0x45, 0x19, 0xEA, 0x65, 0x24, 0xD5, 0xFF, 0x16, 0x6D, 0x56, 0xA8, 0xB3, 0xC2, 0x02, 0xCF, 0x32, 0x5D, 0x29, 0x76, 0x60, 0xDD, 0x94, 0x14, 0xE9, 0xD2, 0xAF, 0x1F, 0xE0, 0x11, 0xC2, 0xA1, 0x6F, 0xCE, 0x6A, 0x5B, 0x75, 0x1E, 0x7B, 0xB0, 0x55, 0xDD, 0x40, 0x23, 0x72, 0xB8, 0xDB, 0xE6, 0x43, 0xDB, 0xAA, 0x8B, 0xAD, 0x19, 0xEA, 0x47, 0xE1, 0x4D, 0xD6, 0xC0, 0x06, 0xC8, 0x82, 0xC0, 0xCE, 0x27, 0x51, 0x82, 0xD5, 0xC7, 0x93, 0xA7, 0x24, 0x6E, 0x35, 0xA7, 0x2F, 0xA9, 0x71, 0x89, 0x48, 0xD8, 0x9D, 0x7C, 0x70, 0x07, 0xE4, 0x65, 0x09, 0x67, 0xF0, 0x1A, 0x6C, 0xCD, 0x2F, 0x9B, 0x23, 0xD8, 0x5C, 0xB7, 0x0E, 0xAB, 0x54, 0x05, 0x96, 0xD4, 0xE7, 0xEF, 0xD3, 0xC4, 0x64, 0x26, 0x69, 0x36, 0xCE, 0x6B, 0xCB, 0x38, 0x86, 0x4A, 0xFC, 0xC9, 0x0C, 0xA7, 0x4D, 0xED, 0xD2, 0x45, 0xDE, 0x19, 0xD8, 0x62, 0x36, 0xD8, 0xB5, 0xF2, 0xAD, 0xD8, 0xEA, 0x9B, 0xA7, 0x4C, 0x3C, 0xC9, 0x7F, 0xC9, 0xDD, 0xE8, 0x60, 0x6F, 0xB3, 0x43, 0xCC, 0xB1, 0x98, 0x37, 0x59, 0xDB, 0x7F, 0xCD, 0x2D, 0x18, 0x7E, 0xE6, 0x42, 0xC9, 0x8B, 0x05, 0x0E, 0xB1, 0x67, 0xF0, 0x19, 0xDB, 0x78, 0x8B, 0x7E, 0x56, 0xD5, 0xD5, 0xB4, 0xC0, 0x77, 0x0B, 0xC0, 0x96, 0x97, 0xCF, 0xA3, 0xF0, 0xC7, 0xBC, 0x6F, 0x30, 0xCE, 0xEE, 0x06, 0xC6, 0x55, 0x84, 0x85, 0xB4, 0xB6, 0x2B, 0xE0, 0x18, 0x3D, 0x79, 0x86, 0x7C, 0x2C, 0x91, 0x04, 0xD3, 0x85, 0xC0, 0xFC, 0xEE, 0xE9, 0x4C, 0x42, 0x49, 0x01, 0x1B, 0x6F, 0x72, 0xE3, 0x7F, 0xD5, 0xE6, 0x6D, 0xCC, 0x00, 0x4F, 0x37, 0xB6, 0x76, 0x1B, 0x6C, 0xE7, 0xC4, 0xD2, 0x08, 0x98, 0xCB, 0xC1, 0x1E, 0x19, 0xD8, 0xCB, 0x88, 0x1A, 0xCE, 0xC8, 0x3C, 0x12, 0x70, 0x4F, 0x26, 0xC1, 0x29, 0x19, 0x14, 0x08, 0x8F, 0xCE, 0x3F, 0x88, 0x05, 0xDF, 0xE5, 0x73, 0x2A, 0xA4, 0xAC, 0xD5, 0x69, 0xDD, 0x4F, 0x80, 0x9B, 0x3A, 0xEC, 0x3B, 0x0A, 0xE8, 0xF8, 0xA4, 0xBA, 0xC2, 0x21, 0x72, 0x96, 0x6C, 0x95, 0x39, 0x15, 0x29, 0x52, 0x43, 0x8F, 0xBD, 0x34, 0xD8, 0x67, 0xC3, 0x28, 0xCD, 0xED, 0x82, 0xAE, 0xD9, 0x64, 0x46, 0x4B, 0xAE, 0x83, 0xBC, 0xE5, 0xCA, 0xF6, 0xE7, 0xE7, 0x19, 0x0F, 0x46, 0x4B, 0xBF, 0x7C, 0x8F, 0x51, 0x58, 0xDB, 0xFA, 0x9A, 0xF4, 0x20, 0xBC, 0xA2, 0xB3, 0xD2, 0xFE, 0x6E, 0xC6, 0x0E, 0xAB, 0xDE, 0x95, 0x86, 0x9C, 0x8A, 0x74, 0xAE, 0x6C, 0x0A, 0x18, 0x6F, 0xBF, 0x75, 0xE3, 0x3C, 0x8E, 0x87, 0x6F, 0x57, 0xD1, 0x67, 0xD5, 0xB7, 0x43, 0x34, 0x5E, 0x21, 0x1E, 0xF3, 0x73, 0x3D, 0x0F, 0xF6, 0x07, 0x98, 0x2E, 0x60, 0xFB, 0x3C, 0x2A, 0x59, 0xEA, 0xC1, 0x67, 0x60, 0x02, 0xED, 0x1E, 0xC8, 0xD1, 0xE2, 0xE6, 0x9E, 0xD0, 0x9B, 0xD4, 0xAB, 0xD8, 0x4B, 0xEE, 0xFA, 0xAA, 0x06, 0xFD, 0x40, 0x09, 0xF6, 0x78, 0x77, 0x85, 0x2E, 0x9E, 0x7E, 0x38, 0xA0, 0x86, 0xEC, 0xBC, 0x42, 0x4E, 0xC7, 0xBA, 0x2C, 0x7E, 0x82, 0x56, 0x9F, 0xB1, 0xD1, 0xDE, 0xF5, 0xD4, 0x47, 0x98, 0xB2, 0x48, 0x06, 0x55, 0x3D, 0xC6, 0x92, 0x33, 0x4D, 0xA0, 0xBC, 0x09, 0xC9, 0x19, 0x19, 0x31, 0x34, 0x0C, 0xAA, 0xA9, 0xD0, 0x9E, 0x45, 0xBA, 0xFD, 0x94, 0x62, 0xA6, 0xDD, 0xE7, 0x62, 0xB4, 0x66, 0x79, 0x6C, 0xC4, 0xAA, 0x7C, 0xA0, 0x6A, 0x3E, 0x25, 0x0E, 0xC7, 0x04, 0x4C, 0xF0, 0x93, 0x2B, 0x45, 0xE1, 0xD7, 0x81, 0xF3, 0xE3, 0xE8, 0x10, 0x5D, 0xFB, 0x56, 0x48, 0x35, 0x04, 0xAD, 0xBB, 0xE5, 0x2A, 0xBA, 0x41, 0xF3, 0xC7, 0x13, 0x88, 0x7A, 0x94, 0x53, 0x4B, 0x92, 0xF9, 0x9D, 0x5F, 0xF7, 0x00, 0xD9, 0x57, 0x8A, 0xF2, 0xBA, 0x61, 0xEF, 0xA3, 0x5F, 0x7D, 0xF3, 0xF0, 0xA0, 0xAD, 0x15, 0x37, 0x2C, 0xBE, 0x39, 0x2C, 0xA3, 0x07, 0x88, 0x0C, 0x28, 0xD1, 0x9A, 0xC4, 0x1F, 0x8E, 0x9A, 0x41, 0x41, 0x63, 0x0F, 0xB6, 0x49, 0x6A, 0xBB, 0x4F, 0xAF, 0x12, 0xB4, 0xC2, 0xF9, 0x8A, 0x34, 0x0A, 0x74, 0x48, 0x3C, 0x17, 0xEF, 0x9F, 0x14, 0x7C, 0x88, 0xBA, 0x65, 0x86, 0xDD, 0xCA, 0x75, 0xC2, 0x27, 0x96, 0xBA, 0xD2, 0xE5, 0x4A, 0x42, 0x64, 0x7A, 0x39, 0x44, 0x4F, 0xDE, 0xA1, 0x81, 0x42, 0xF0, 0x27, 0xCD, 0xA7, 0x65, 0xAD, 0x63, 0x97, 0x12, 0x5F, 0x0A, 0x52, 0xF8, 0xB5, 0xF4, 0x24, 0x84, 0xD7, 0x27, 0x88, 0x76, 0x30, 0x81, 0x4B, 0x20, 0x80, 0xD0, 0xC8, 0xF5, 0x17, 0xBD, 0x57, 0x77, 0xC2, 0x45, 0xAD, 0xDE, 0x98, 0x59, 0x05, 0x73, 0x7D, 0x79, 0x96, 0x1D, 0x81, 0xEE, 0xB0, 0xAF, 0xB4, 0x9A, 0xAC, 0x22, 0x9F, 0x65, 0x79, 0xDE, 0xBC, 0x47, 0xC4, 0xDC, 0xFD, 0x68, 0x63, 0x1B, 0xE8, 0x27, 0x54, 0xFF, 0x8D, 0x84, 0xF0, 0xFE, 0xA3, 0xFB, 0x2B, 0x83, 0xD2, 0xFB, 0x38, 0x4D, 0x40, 0xCF, 0xB4, 0x2E, 0xA8, 0xFF, 0x2B, 0xC0, 0xC5, 0x5C, 0x87, 0xE4, 0xF7, 0x0C, 0x76, 0x58, 0xA5, 0x4D, 0xD2, 0xF5, 0x34, 0x22, 0xAE, 0x1F, 0xE0, 0xFC, 0x28, 0x6E, 0x8B, 0x32, 0xE9, 0xD4, 0x5C, 0x96, 0x7A, 0xF0, 0x0D, 0xAA, 0x9C, 0x68, 0x5F, 0x78, 0x10, 0x98, 0x36, 0x65, 0xE5, 0x94, 0xFD, 0x5B, 0x77, 0x25, 0x8A, 0x06, 0x41, 0x3D, 0x5B, 0x84, 0xC8, 0x01, 0x72, 0x7A, 0xA5, 0x34, 0x71, 0xE0, 0xE8, 0x71, 0x6A, 0xB4, 0x11, 0x0A, 0x8A, 0x05, 0x74, 0x4D, 0xA2, 0x5E, 0xA4, 0x84, 0xBD, 0x11, 0x41, 0x25, 0x3E, 0xB8, 0x7B, 0xD8, 0x67, 0x36, 0xDD, 0xE8, 0x66, 0x2F, 0x77, 0x65, 0x5F, 0x83, 0x61, 0xD4, 0xB4, 0x3B, 0x2B, 0x4F, 0xD3, 0xC5, 0x6C, 0xF7, 0x10, 0x11, 0xDC, 0x1E, 0xD9, 0x18, 0x13, 0x4F, 0x49, 0x74, 0xB4, 0xD5, 0x60, 0x83, 0x72, 0xF1, 0xDF, 0x37, 0x84, 0xBF, 0xF9, 0xAB, 0x1C, 0xB4, 0xAF, 0x5E, 0x53, 0x33, 0xD0, 0x44, 0x51, 0x2D, 0x7C, 0xA5, 0xB3, 0xA8, 0x2F, 0xC2, 0x91, 0x5D, 0xD5, 0x0C, 0x82, 0xA2, 0xFE, 0x52, 0x1D, 0x04, 0x73, 0x8A, 0x76, 0xB8, 0x27, 0xC8, 0xB1, 0x32, 0x75, 0x99, 0xDE, 0xFF, 0xD2, 0x24, 0x59, 0x02, 0x53, 0xB7, 0x56, 0x66, 0xEF, 0xE4, 0x8A, 0x9C, 0x29, 0x66, 0x1F, 0x55, 0xEC, 0x36, 0x8F, 0xE0, 0x36, 0x79, 0x44, 0x95, 0xC8, 0xF6, 0xA4, 0xEE, 0x7F, 0x92, 0xB2, 0x0C, 0x4C, 0x38, 0xFB, 0x09, 0xF9, 0x48, 0x50, 0xBC, 0x0B, 0x97, 0xC2, 0x5C, 0x1E, 0x16, 0x36, 0xD5, 0xE5, 0xAD, 0x7E, 0xF7, 0x37, 0x53, 0xA9, 0x01, 0xD8, 0x38, 0x50, 0x3A, 0x94, 0x4A, }, .pkcs8_len = 0, .spki_len = 0, .msg_len = 66, .msg = { 0x22, 0x5D, 0x5C, 0xE2, 0xCE, 0xAC, 0x61, 0x93, 0x0A, 0x07, 0x50, 0x3F, 0xB5, 0x9F, 0x7C, 0x2F, 0x93, 0x6A, 0x3E, 0x07, 0x54, 0x81, 0xDA, 0x3C, 0xA2, 0x99, 0xA8, 0x0F, 0x8C, 0x5D, 0xF9, 0x22, 0x3A, 0x07, 0x3E, 0x7B, 0x90, 0xE0, 0x2E, 0xBF, 0x98, 0xCA, 0x22, 0x27, 0xEB, 0xA3, 0x8C, 0x1A, 0xB2, 0x56, 0x82, 0x09, 0xE4, 0x6D, 0xBA, 0x96, 0x18, 0x69, 0xC6, 0xF8, 0x39, 0x83, 0xB1, 0x7D, 0xCD, 0x49, }, .sig_len = 4595, .sig = { 0x5C, 0x04, 0x77, 0x77, 0xB8, 0xEB, 0x60, 0x8F, 0x9B, 0xD9, 0x11, 0xCD, 0xF6, 0x2B, 0x8B, 0xEB, 0x36, 0x61, 0xF9, 0x3F, 0xE4, 0xE6, 0x2E, 0x9A, 0x0C, 0x4E, 0x20, 0xA8, 0x88, 0x90, 0x81, 0x2C, 0x2F, 0xC6, 0x4D, 0xEC, 0x6A, 0x3A, 0xDB, 0x78, 0x83, 0xFA, 0x86, 0xAD, 0x62, 0xC4, 0xF0, 0x72, 0x98, 0x89, 0xEC, 0xBD, 0x7B, 0x49, 0xAC, 0x68, 0x89, 0x3C, 0xD0, 0xEE, 0x56, 0x3E, 0x08, 0x41, 0xE5, 0x3E, 0xF9, 0xC5, 0x23, 0x69, 0xA1, 0x70, 0x42, 0x82, 0x68, 0x4F, 0xDA, 0x5C, 0x61, 0x5F, 0x3B, 0x71, 0x24, 0x3B, 0x17, 0x09, 0x85, 0xD9, 0xEB, 0x28, 0x23, 0xB0, 0xAA, 0xDE, 0xAE, 0x32, 0x05, 0xBA, 0x95, 0x63, 0xF3, 0xAD, 0xC9, 0x04, 0x71, 0x95, 0x77, 0x9B, 0x51, 0x72, 0x02, 0x83, 0xC1, 0x88, 0x30, 0x2E, 0x0D, 0xC4, 0xE6, 0x4D, 0xA8, 0xC8, 0xE2, 0x6D, 0x1A, 0x12, 0x6F, 0x1E, 0x23, 0x6A, 0xDA, 0x99, 0x40, 0x3E, 0x4E, 0x29, 0xDF, 0x8D, 0x52, 0x21, 0xB5, 0x18, 0x57, 0x60, 0x80, 0x7E, 0x17, 0x8E, 0x46, 0xB7, 0x59, 0x5A, 0x1E, 0x31, 0x27, 0x30, 0xDA, 0x4C, 0x10, 0xE9, 0x6D, 0x67, 0x45, 0x84, 0x89, 0x92, 0xFA, 0xFB, 0x10, 0x12, 0x58, 0xF8, 0xFE, 0xCE, 0xFA, 0x10, 0x1C, 0xC8, 0xC1, 0x92, 0x46, 0x84, 0xA4, 0x23, 0x4A, 0xB3, 0x47, 0x56, 0xAC, 0x49, 0x61, 0xC9, 0xAB, 0x5D, 0xF0, 0xE1, 0xC8, 0x61, 0x38, 0x0A, 0x88, 0x1F, 0xDC, 0x18, 0xA8, 0x62, 0x45, 0x67, 0x23, 0xE9, 0x4C, 0xA9, 0x54, 0xAE, 0x50, 0xF5, 0x68, 0x83, 0x34, 0x28, 0x8A, 0x93, 0xD4, 0xB7, 0x89, 0x67, 0x3A, 0xC0, 0xBC, 0x57, 0xD8, 0x3B, 0x71, 0x04, 0xF5, 0x6E, 0x40, 0x7D, 0x2A, 0x79, 0x38, 0x31, 0xAA, 0x69, 0x87, 0x19, 0xB2, 0xED, 0xE0, 0xDE, 0x3C, 0x8D, 0x70, 0xDE, 0xAB, 0x53, 0x79, 0x6C, 0x98, 0xF1, 0x01, 0xA3, 0x76, 0xBC, 0x48, 0x88, 0xE7, 0xF8, 0x8D, 0x9D, 0xA1, 0xBD, 0x9C, 0x0A, 0x39, 0x75, 0x5F, 0xFC, 0xB4, 0xFA, 0x96, 0x99, 0x59, 0x60, 0x17, 0x62, 0x54, 0x2A, 0x01, 0xE6, 0xD6, 0x07, 0x9B, 0x38, 0x2A, 0xCF, 0xFC, 0xEE, 0x1F, 0x17, 0x36, 0x91, 0x6B, 0xDC, 0x57, 0xD8, 0x61, 0xC0, 0x47, 0xFD, 0xF9, 0xAB, 0x49, 0x6C, 0x2B, 0x99, 0x97, 0x0C, 0x0F, 0x1D, 0x10, 0x70, 0xFF, 0x37, 0xEB, 0x5A, 0x5C, 0x1A, 0xF6, 0x5B, 0x87, 0x75, 0xA9, 0x13, 0x83, 0x89, 0x9E, 0xBE, 0x44, 0xB3, 0xFC, 0x98, 0x11, 0xAB, 0xE5, 0x3D, 0x74, 0xDF, 0x1E, 0x58, 0xBC, 0x0A, 0xFC, 0xEC, 0x6D, 0xEF, 0xB3, 0xC7, 0x4C, 0xF6, 0xED, 0x4C, 0xC2, 0x13, 0x05, 0xBC, 0xD5, 0x82, 0xF0, 0xD1, 0xD5, 0x5B, 0x81, 0xF3, 0x16, 0x6E, 0x90, 0x04, 0xFF, 0x1D, 0x98, 0x98, 0x21, 0x74, 0xB7, 0x32, 0x57, 0x6C, 0x4F, 0x08, 0x00, 0x4A, 0xA1, 0x72, 0xB6, 0xED, 0xD3, 0x59, 0xEC, 0xAB, 0x95, 0xF9, 0x77, 0x5C, 0x23, 0x2B, 0x11, 0x12, 0xFD, 0xF6, 0x65, 0xB2, 0x45, 0x10, 0x8A, 0x3C, 0xF9, 0x57, 0xD9, 0x08, 0xEB, 0xB1, 0xFA, 0x5E, 0x38, 0x5B, 0xED, 0x36, 0xDD, 0x4A, 0xE0, 0x9C, 0xB3, 0xB4, 0x94, 0x42, 0xC8, 0x1B, 0x49, 0xA0, 0x5C, 0xE7, 0xF3, 0xB8, 0xC7, 0x1F, 0x1A, 0xE2, 0x8E, 0xC4, 0xCD, 0xE8, 0x51, 0xA2, 0x27, 0xB9, 0x9E, 0x4A, 0xDE, 0xB4, 0x7C, 0xBB, 0x12, 0xAF, 0x98, 0xBF, 0x8E, 0x1D, 0xDA, 0x9E, 0xCB, 0x09, 0x68, 0x3A, 0x74, 0xAB, 0x05, 0x3D, 0x62, 0x78, 0xFD, 0xEF, 0xA2, 0x19, 0x83, 0xB3, 0xD3, 0xFE, 0x23, 0x96, 0x3F, 0x1C, 0x2A, 0xD9, 0x6F, 0x46, 0x64, 0xB9, 0xDF, 0x8A, 0x4A, 0xF0, 0x98, 0x5B, 0x73, 0x1E, 0xB3, 0x3C, 0xDB, 0x49, 0x5D, 0xB1, 0x28, 0xE5, 0xDC, 0x5B, 0x36, 0x55, 0x9E, 0xFD, 0xA1, 0x17, 0x17, 0xDD, 0xBB, 0xEC, 0x43, 0x8B, 0xC8, 0x6A, 0xE7, 0x3D, 0x7D, 0x69, 0x66, 0x81, 0xF9, 0x0E, 0x6B, 0xBC, 0x24, 0x43, 0xB6, 0xA6, 0x23, 0x21, 0xF9, 0x26, 0xC6, 0x48, 0xC3, 0x36, 0x05, 0xAB, 0x61, 0x9B, 0x02, 0xEF, 0xFD, 0x5B, 0x48, 0x4B, 0x00, 0x45, 0x15, 0x0A, 0x47, 0x53, 0xB9, 0x22, 0x52, 0x27, 0x9E, 0xA1, 0x20, 0x4F, 0x42, 0xF3, 0x0B, 0xB0, 0xD8, 0x2D, 0x39, 0xD5, 0x58, 0x88, 0x1F, 0xFB, 0x4C, 0xD2, 0x96, 0x75, 0x6E, 0xF2, 0x8D, 0x08, 0x71, 0x20, 0xEB, 0xD5, 0xFC, 0x1D, 0x42, 0x72, 0xBC, 0x7C, 0x75, 0xB9, 0xBB, 0x0F, 0xC3, 0x31, 0x09, 0x51, 0xCE, 0xA4, 0x5A, 0x7D, 0x06, 0xC8, 0xDC, 0xA5, 0x9E, 0xDB, 0x6F, 0x34, 0xEE, 0xEF, 0x55, 0x60, 0xF5, 0xCF, 0xD6, 0xC3, 0x44, 0xC2, 0xEF, 0x06, 0xED, 0x7B, 0xBA, 0x25, 0x74, 0x9A, 0x2E, 0xF5, 0x62, 0xE2, 0x9F, 0xEF, 0x5C, 0xB4, 0x7C, 0x25, 0x50, 0xAB, 0x72, 0xF3, 0xA1, 0x0D, 0x15, 0x89, 0x34, 0xB1, 0xF2, 0x69, 0x51, 0x59, 0x30, 0xD1, 0x05, 0x3E, 0x34, 0xF2, 0xB1, 0xA6, 0x8D, 0x36, 0x94, 0xEE, 0x4B, 0xC2, 0x06, 0xD8, 0x62, 0x66, 0x58, 0x68, 0x90, 0x4C, 0xAF, 0xCD, 0x9E, 0x2D, 0xAD, 0x4B, 0x26, 0x2B, 0x2A, 0x11, 0x18, 0xEE, 0xA1, 0xFA, 0x5B, 0xF0, 0x21, 0x88, 0xE8, 0x5A, 0x8A, 0xFE, 0xA1, 0xF8, 0xBA, 0x8E, 0x36, 0x04, 0xED, 0x67, 0xC0, 0xA8, 0xC4, 0x4D, 0x61, 0x0E, 0xCE, 0x21, 0x03, 0x3D, 0x23, 0x03, 0x4A, 0x28, 0xB9, 0xBC, 0x3F, 0x54, 0xCE, 0x7C, 0xA6, 0x3F, 0xD0, 0xC5, 0x4E, 0xC5, 0x9A, 0x3A, 0xE6, 0xF0, 0xF0, 0x15, 0x33, 0x86, 0xC2, 0xC0, 0x8B, 0x9F, 0x22, 0xC3, 0xC9, 0x21, 0xE9, 0xB6, 0xC5, 0xF6, 0x8C, 0x95, 0x02, 0x58, 0x4B, 0x57, 0x58, 0x92, 0xE6, 0xC1, 0x00, 0xBA, 0x24, 0x38, 0x30, 0x15, 0x75, 0x22, 0x09, 0xCD, 0x36, 0x17, 0x1A, 0x86, 0x42, 0xE1, 0xAB, 0xC1, 0x77, 0xB3, 0x99, 0x58, 0x23, 0xAA, 0x56, 0x2D, 0xC8, 0xCE, 0xD9, 0x22, 0x08, 0x68, 0xD0, 0x98, 0x71, 0x5C, 0x2B, 0xE9, 0x9C, 0x10, 0x14, 0x3B, 0x1C, 0x47, 0x6E, 0x60, 0x73, 0x1B, 0xA5, 0x7E, 0x29, 0x36, 0x4B, 0xDE, 0xC6, 0x38, 0x4C, 0x4F, 0xC8, 0x6C, 0x72, 0x93, 0xEC, 0xBF, 0x24, 0xED, 0xE4, 0x23, 0x1F, 0x63, 0xF4, 0xD7, 0x43, 0x0C, 0x74, 0xB4, 0x5C, 0xBC, 0xD8, 0x8F, 0xA6, 0x3C, 0xA8, 0x19, 0xE3, 0xE9, 0x82, 0x26, 0x3F, 0xAD, 0xDF, 0xEB, 0xA6, 0xFE, 0x21, 0xB3, 0xB2, 0x43, 0x7F, 0x34, 0xF8, 0x6E, 0xB3, 0x76, 0xA9, 0x3B, 0xAF, 0x4E, 0x55, 0x51, 0x99, 0xE1, 0x29, 0x91, 0x7F, 0x6A, 0x60, 0xF0, 0x8E, 0x7E, 0x4F, 0x38, 0x73, 0x09, 0x76, 0x94, 0x6B, 0x73, 0x7E, 0xDF, 0x30, 0x2C, 0x11, 0x45, 0x95, 0x47, 0x42, 0xD1, 0x46, 0x85, 0x43, 0x09, 0x33, 0x53, 0xBF, 0xE6, 0x64, 0x94, 0xEC, 0x60, 0x02, 0x24, 0xAA, 0x5E, 0x76, 0x62, 0x66, 0x04, 0x3F, 0x6B, 0x8E, 0x65, 0xFB, 0x89, 0xF0, 0x85, 0x23, 0x9A, 0xD8, 0xD6, 0x69, 0x3C, 0x23, 0xFD, 0x3A, 0x6F, 0x29, 0x8C, 0x3E, 0xA0, 0xF4, 0x8C, 0x6D, 0x56, 0x3E, 0x62, 0xFD, 0x78, 0x57, 0xD6, 0xA1, 0x1D, 0x10, 0xAF, 0x8C, 0xF3, 0x6F, 0x8B, 0x34, 0xFC, 0x60, 0x66, 0x4E, 0xCE, 0x43, 0xC0, 0xA6, 0x50, 0x3F, 0x68, 0x57, 0x7C, 0x8A, 0x7B, 0xEF, 0xA1, 0xFF, 0x91, 0xBC, 0x51, 0x0B, 0xD7, 0xB9, 0xDA, 0xCA, 0x4A, 0xB6, 0xD4, 0x00, 0xAC, 0x2D, 0x42, 0xD7, 0x07, 0x7A, 0x23, 0xD8, 0xE2, 0xF3, 0x04, 0xE8, 0x57, 0x68, 0xC1, 0x11, 0xDC, 0xAA, 0x8B, 0x1E, 0x8D, 0x05, 0x9A, 0x3E, 0xB2, 0x38, 0x42, 0x88, 0xC9, 0x8C, 0x0F, 0x26, 0xF9, 0xB6, 0x0F, 0x61, 0x71, 0x37, 0x25, 0x4B, 0xA0, 0x77, 0x6C, 0x27, 0x2C, 0xA2, 0x3A, 0x26, 0x81, 0x0E, 0x00, 0x6A, 0x25, 0x43, 0xE3, 0x7B, 0x78, 0x94, 0x57, 0xFE, 0xA7, 0x30, 0x41, 0xD6, 0x55, 0xEC, 0x6B, 0xA3, 0x1C, 0xAA, 0x2C, 0xDE, 0x59, 0xD4, 0x42, 0x09, 0x6A, 0xA7, 0x10, 0xF4, 0xF5, 0x03, 0x19, 0xA2, 0xB6, 0x2D, 0x4C, 0x28, 0xD8, 0xC8, 0x8C, 0xC8, 0xFD, 0x80, 0x8F, 0x26, 0xB6, 0xF8, 0x7C, 0x9D, 0xF4, 0x85, 0xAF, 0xC9, 0xDF, 0xC3, 0x69, 0xDE, 0x7D, 0xB6, 0xFD, 0xE5, 0x12, 0x9A, 0x36, 0xB0, 0xFF, 0xBC, 0x30, 0x13, 0x13, 0x24, 0xDD, 0x0F, 0x33, 0x27, 0xF7, 0x6F, 0x6E, 0xFB, 0x80, 0xD7, 0x84, 0x4A, 0x13, 0x3A, 0xA8, 0x48, 0x70, 0x80, 0x16, 0x59, 0x0B, 0xB3, 0xB5, 0xA4, 0x20, 0x63, 0xD0, 0xC3, 0xCE, 0x9F, 0x7D, 0x23, 0xD6, 0x06, 0x15, 0xAC, 0xEC, 0x34, 0x71, 0x5B, 0x80, 0xEC, 0x4B, 0xFB, 0xBE, 0x78, 0xB4, 0xC1, 0x08, 0x0D, 0xCF, 0xED, 0x7F, 0xE9, 0x08, 0xE1, 0xC7, 0x10, 0xD2, 0x50, 0xB5, 0xA0, 0xCB, 0xBB, 0x6A, 0xCC, 0x45, 0x06, 0x59, 0xB3, 0x47, 0xC6, 0xAD, 0x16, 0xDC, 0xED, 0x0F, 0x6B, 0x6A, 0x56, 0x71, 0x4B, 0x89, 0x9D, 0x4E, 0x25, 0xE1, 0x81, 0x13, 0x89, 0xB9, 0x41, 0x26, 0x91, 0x8E, 0x11, 0x7E, 0x62, 0xB3, 0x3F, 0xE6, 0x63, 0x6C, 0xF8, 0xA2, 0x30, 0x23, 0x24, 0x92, 0xA5, 0x8A, 0x84, 0x6F, 0x7C, 0xCC, 0xF1, 0x65, 0x60, 0xE5, 0xB2, 0x51, 0xB4, 0x2D, 0xD6, 0xCC, 0xEC, 0xED, 0x51, 0xB2, 0x83, 0x83, 0xA4, 0x18, 0x85, 0x11, 0x13, 0x21, 0x0B, 0x8D, 0x81, 0xF7, 0xA9, 0xE5, 0x10, 0xCB, 0xBD, 0x2B, 0xAA, 0xB9, 0x29, 0xC6, 0xBA, 0x85, 0xA1, 0x4A, 0x93, 0xAC, 0xA2, 0x3E, 0xE7, 0x7B, 0xF8, 0x96, 0x52, 0xB3, 0x59, 0x24, 0x3F, 0xEA, 0xAF, 0x9E, 0x91, 0x0D, 0xB4, 0xB9, 0xBE, 0x57, 0x01, 0xCF, 0xD4, 0xDE, 0xDC, 0xF7, 0x99, 0x41, 0xAD, 0xF7, 0x5C, 0xB9, 0xF3, 0x5B, 0x0E, 0xC4, 0xF4, 0x65, 0x80, 0x00, 0x99, 0xA5, 0xF0, 0x96, 0x27, 0x84, 0x6B, 0xE4, 0x67, 0x08, 0x3D, 0xDD, 0x93, 0xF9, 0x44, 0xA1, 0x6A, 0xD7, 0x4B, 0x80, 0x28, 0x5D, 0xEF, 0x16, 0x08, 0x0B, 0x2E, 0xEB, 0xD9, 0xF8, 0xE2, 0x5A, 0x5C, 0x05, 0x26, 0xFC, 0xEB, 0xD9, 0x8E, 0xE7, 0xD0, 0x7F, 0x5E, 0xC7, 0x7B, 0x10, 0x71, 0x19, 0xC0, 0x4A, 0xBB, 0x2E, 0x3F, 0xC3, 0x4D, 0xED, 0xDE, 0x18, 0x58, 0xB9, 0x20, 0x58, 0xF8, 0x26, 0xCC, 0x0B, 0xC9, 0xCA, 0x16, 0x1B, 0xF6, 0x24, 0xCF, 0x04, 0x30, 0xBC, 0x66, 0x11, 0xC8, 0xFB, 0x28, 0xC4, 0xD9, 0x4B, 0x54, 0x25, 0x78, 0x7A, 0xDB, 0x82, 0xD9, 0x99, 0xD5, 0x36, 0xC8, 0xBF, 0xC5, 0xAE, 0xAD, 0x0F, 0xED, 0xB2, 0xDB, 0x1A, 0x84, 0x6D, 0x53, 0x4F, 0x25, 0x19, 0x73, 0x74, 0xC1, 0x0C, 0x99, 0x14, 0xB5, 0xF4, 0x6D, 0xC8, 0x3F, 0x02, 0x26, 0x86, 0x28, 0xFC, 0x8A, 0xC1, 0x24, 0x6B, 0xD3, 0x52, 0x8B, 0x84, 0xBE, 0x0F, 0xA9, 0x41, 0x12, 0x7E, 0xBD, 0x45, 0x97, 0x0C, 0xA2, 0x15, 0x8B, 0xF7, 0x9A, 0xA2, 0x14, 0x1B, 0x59, 0xCC, 0xE0, 0x98, 0x34, 0x17, 0x21, 0xAE, 0x4F, 0xAB, 0x6D, 0x2A, 0xAF, 0x10, 0x9F, 0x5E, 0xF6, 0xC0, 0x06, 0xB8, 0x5C, 0xCD, 0xF5, 0x0F, 0x8F, 0x79, 0xF5, 0x5B, 0xAC, 0x2B, 0xC6, 0x8B, 0x7F, 0x9D, 0x81, 0x3A, 0xE9, 0xBE, 0xCA, 0xE6, 0x11, 0xC4, 0xC0, 0x08, 0xDC, 0xEC, 0x7D, 0xB4, 0xC2, 0xEA, 0x46, 0x37, 0x46, 0x3D, 0xC6, 0xBE, 0x33, 0xDB, 0x94, 0x40, 0x69, 0x1D, 0x66, 0x84, 0x63, 0x6F, 0x14, 0x6A, 0x90, 0x3B, 0x18, 0x9F, 0x52, 0xB3, 0x46, 0x32, 0x29, 0x2C, 0x08, 0xE5, 0xAA, 0x28, 0xAA, 0xAB, 0x37, 0xE9, 0x12, 0x14, 0xFA, 0xFD, 0xB0, 0xDF, 0xCF, 0x92, 0x92, 0x30, 0x2D, 0x6C, 0x97, 0xD0, 0x8E, 0x91, 0x8C, 0x7D, 0x94, 0x7B, 0x8A, 0xFD, 0xB6, 0xAB, 0xF9, 0x6B, 0xDE, 0x5B, 0x44, 0x13, 0xDC, 0xA9, 0xD2, 0x2C, 0xAD, 0xED, 0x06, 0xF8, 0x5C, 0x1E, 0x9D, 0x7A, 0xCC, 0x12, 0xC8, 0x05, 0x53, 0xEC, 0xF5, 0x8C, 0xC6, 0xBC, 0xBB, 0x7C, 0xE3, 0xF7, 0xDB, 0x7C, 0xE9, 0xD9, 0x5B, 0x8C, 0x93, 0x77, 0xD0, 0x39, 0x3A, 0x1A, 0x5B, 0xAF, 0x92, 0x01, 0x39, 0xCC, 0xF1, 0x1B, 0x14, 0xE9, 0xAA, 0x60, 0x3C, 0x41, 0x21, 0x54, 0xD6, 0xFA, 0x08, 0x40, 0x51, 0x08, 0x4C, 0x57, 0x85, 0x00, 0xDE, 0xCF, 0xF3, 0x1F, 0xB6, 0x1E, 0x93, 0x22, 0xC6, 0xD6, 0x3A, 0xEE, 0x3A, 0x3A, 0xDB, 0xA7, 0x45, 0xA9, 0x1C, 0xFA, 0xC0, 0xCE, 0x21, 0x9E, 0x8C, 0x2F, 0xF9, 0x0C, 0x53, 0xE4, 0x23, 0xE2, 0x74, 0xC0, 0x41, 0xEC, 0x74, 0x12, 0xFA, 0xEE, 0x4F, 0x4C, 0xC1, 0x11, 0x6C, 0xDC, 0x97, 0x2A, 0x90, 0xA1, 0xE0, 0x9B, 0x1F, 0x48, 0x5F, 0xDA, 0x1C, 0x17, 0xC6, 0x68, 0x2A, 0xB2, 0x6B, 0x0B, 0x23, 0x11, 0xB4, 0x53, 0x7D, 0x92, 0x39, 0x46, 0x5B, 0x47, 0x00, 0x64, 0x25, 0xFC, 0x71, 0xB2, 0xB8, 0x55, 0x64, 0xE7, 0x37, 0xFD, 0x2B, 0x5C, 0x73, 0xAB, 0xB8, 0xFA, 0xD2, 0x0B, 0x83, 0xBF, 0x54, 0xE0, 0xBE, 0x2F, 0x6E, 0x2D, 0x71, 0xA5, 0x16, 0x32, 0x61, 0x15, 0x31, 0x6E, 0x84, 0x5B, 0xC6, 0xCA, 0x82, 0xE1, 0x51, 0xBA, 0x4F, 0x90, 0xA7, 0x51, 0x93, 0x0E, 0x2B, 0xF3, 0x06, 0xB2, 0x5C, 0xDB, 0x38, 0xC2, 0xDA, 0x27, 0xF9, 0x1E, 0xA1, 0xE9, 0x72, 0xB9, 0xB6, 0x61, 0x00, 0xD7, 0x52, 0x9D, 0x30, 0x2E, 0x88, 0xAF, 0x33, 0x15, 0xD6, 0xBB, 0xC8, 0x6D, 0x0E, 0x71, 0x98, 0xC1, 0x40, 0xD3, 0xFC, 0x41, 0xD5, 0x94, 0xFB, 0x5C, 0x22, 0x02, 0x10, 0x7A, 0xC8, 0xC6, 0x5D, 0xDB, 0xCC, 0x94, 0x86, 0x14, 0xF2, 0x37, 0xA3, 0x3A, 0x87, 0x88, 0x04, 0x10, 0x41, 0xE8, 0x88, 0x8E, 0xB3, 0xEC, 0x65, 0x6F, 0x01, 0xC6, 0x95, 0x7A, 0x87, 0x21, 0x54, 0xD3, 0x6A, 0xEF, 0x53, 0xC4, 0x39, 0xA8, 0x8F, 0x67, 0x5B, 0x5E, 0x4C, 0x12, 0x96, 0x30, 0xB2, 0x95, 0x4E, 0x7E, 0x53, 0x24, 0x72, 0x70, 0x07, 0x5D, 0x0D, 0x1E, 0xB6, 0xF0, 0x8B, 0xEA, 0x6A, 0xA1, 0xD6, 0x13, 0x20, 0xC9, 0x83, 0x3B, 0x65, 0x37, 0xF3, 0x6D, 0x8E, 0x81, 0x99, 0xB5, 0x36, 0xA2, 0xDD, 0xDB, 0x53, 0xD8, 0x12, 0xC2, 0x21, 0x31, 0x49, 0xF2, 0x57, 0xD2, 0x67, 0xCD, 0x6D, 0x07, 0xC0, 0xE6, 0xB1, 0x11, 0x88, 0x3B, 0xD8, 0x31, 0xB2, 0x5A, 0xAF, 0x7E, 0x39, 0xB8, 0x8B, 0x4F, 0xE9, 0x2D, 0x35, 0xE7, 0xC5, 0x3F, 0x65, 0xEE, 0xF9, 0x9C, 0xA7, 0x98, 0x68, 0xF3, 0x50, 0x66, 0xC8, 0x8A, 0xC9, 0x6D, 0xF8, 0x3E, 0xDC, 0xC4, 0x1D, 0x90, 0x43, 0x38, 0xD8, 0xD1, 0x0D, 0x33, 0x16, 0x0F, 0xBD, 0x1B, 0xB5, 0xF6, 0xD4, 0xC6, 0xB6, 0x99, 0x85, 0x4D, 0xDD, 0x50, 0x12, 0x89, 0x02, 0x8F, 0x68, 0xD6, 0xD1, 0xA0, 0xDB, 0x8E, 0xE6, 0x1F, 0xB1, 0x91, 0x12, 0xB3, 0x66, 0x98, 0x23, 0x82, 0x59, 0xB5, 0x2A, 0x32, 0xF4, 0x9E, 0xAD, 0x74, 0x50, 0x74, 0xFA, 0x37, 0xF1, 0xF6, 0x8B, 0x43, 0xA3, 0x31, 0x14, 0xD7, 0xBF, 0xC6, 0x7D, 0xBD, 0xDF, 0xD4, 0x61, 0x1D, 0x41, 0xDC, 0x52, 0x49, 0x81, 0xD6, 0xFE, 0x40, 0x04, 0x01, 0x4D, 0xB9, 0x32, 0x25, 0xA5, 0x38, 0xB5, 0xCB, 0xBA, 0x94, 0xA0, 0xFD, 0x79, 0xE9, 0x1D, 0x48, 0xBD, 0x90, 0xCC, 0x57, 0x28, 0x15, 0x20, 0xFE, 0xB6, 0x46, 0x32, 0x3C, 0x45, 0x27, 0x3B, 0xE9, 0xBD, 0xFB, 0xE9, 0xD9, 0x9A, 0xCB, 0x70, 0x4D, 0xFB, 0x24, 0x36, 0x0F, 0x0C, 0x2E, 0xA0, 0xE8, 0x14, 0xB8, 0x05, 0x6F, 0x77, 0x61, 0xBD, 0x4D, 0x4C, 0x00, 0xC5, 0xE2, 0xBC, 0x1D, 0x1F, 0x8A, 0x4E, 0xC7, 0x79, 0x1F, 0x6A, 0x23, 0xF2, 0xDA, 0xCB, 0x42, 0x3F, 0x29, 0xC8, 0x28, 0x02, 0xE0, 0xD1, 0xED, 0xBB, 0x6F, 0x98, 0x3B, 0x48, 0x99, 0x8B, 0xBB, 0xF4, 0xCF, 0x50, 0x5A, 0x17, 0x3D, 0x14, 0xA5, 0x85, 0xEB, 0xFF, 0xC8, 0x97, 0x7D, 0xBE, 0xE5, 0x99, 0xEC, 0x73, 0x56, 0xE8, 0x3D, 0x65, 0xA0, 0x64, 0x53, 0xA1, 0x52, 0xF1, 0x14, 0xE6, 0x63, 0xE2, 0x73, 0x50, 0x39, 0x35, 0xAA, 0x81, 0x34, 0x2B, 0x67, 0xC5, 0x52, 0x0B, 0x70, 0x84, 0x1B, 0xA1, 0xDF, 0x81, 0x10, 0x33, 0x0B, 0xE9, 0x21, 0x4A, 0x02, 0xCB, 0xB7, 0xAC, 0x17, 0x2F, 0x04, 0x07, 0x4F, 0x4B, 0x5C, 0x07, 0xCB, 0x8E, 0xB7, 0x2D, 0x50, 0xAA, 0xE6, 0x3D, 0x81, 0x56, 0xFF, 0x0A, 0xF3, 0xCC, 0xD5, 0xE5, 0x14, 0x64, 0x39, 0xFE, 0xE0, 0x54, 0x11, 0x20, 0xFA, 0x15, 0xCC, 0x6B, 0xEC, 0xE6, 0xA3, 0xC2, 0xC3, 0xB0, 0x79, 0x55, 0xA7, 0xF5, 0x4D, 0x08, 0x4C, 0x1E, 0x32, 0xA4, 0x55, 0x5E, 0x39, 0x7E, 0x44, 0x6D, 0x78, 0x99, 0x6E, 0xEB, 0xD9, 0x71, 0x15, 0xAF, 0x24, 0xEE, 0xEA, 0xCE, 0x15, 0x6B, 0x92, 0xF8, 0x66, 0xC4, 0xB1, 0xA7, 0x2C, 0x11, 0xBE, 0x1C, 0x50, 0x77, 0x10, 0x5A, 0x19, 0x46, 0xF4, 0x79, 0xA4, 0x08, 0x46, 0x3F, 0xCF, 0x33, 0xAB, 0xDA, 0x84, 0x10, 0x94, 0xD1, 0x6D, 0xEA, 0xB9, 0x97, 0xCA, 0x6D, 0xD4, 0x6E, 0x40, 0x94, 0x34, 0xBD, 0xE4, 0x73, 0x27, 0xA1, 0x35, 0x85, 0xB9, 0x74, 0xCF, 0xE9, 0x22, 0x8D, 0x8C, 0xBD, 0x73, 0x18, 0x5A, 0xDC, 0x02, 0xD0, 0x79, 0xCB, 0x41, 0x0F, 0x16, 0xB2, 0x32, 0x24, 0x85, 0x48, 0x66, 0x92, 0x08, 0x8D, 0x9C, 0xCD, 0x26, 0xAC, 0x9C, 0x6F, 0x30, 0xE9, 0x36, 0xBF, 0x9C, 0xA7, 0x61, 0x59, 0x52, 0x13, 0x57, 0xA8, 0x7A, 0x5B, 0xAA, 0xB1, 0x87, 0x23, 0x7F, 0x24, 0x05, 0x57, 0x2A, 0xD0, 0x06, 0x1A, 0xF6, 0xB6, 0xD8, 0xF8, 0xE3, 0xDD, 0x35, 0xBA, 0xB5, 0x8D, 0x92, 0xD1, 0xA1, 0xB1, 0x9A, 0xA2, 0xAB, 0xFE, 0x70, 0xEE, 0xB8, 0x49, 0xBA, 0xBE, 0x8B, 0x64, 0x46, 0x36, 0x0A, 0xB8, 0x88, 0x5C, 0x26, 0x1D, 0xAC, 0xEB, 0xFB, 0xC4, 0xB8, 0x8C, 0x82, 0x94, 0xE6, 0xFC, 0xA1, 0x40, 0xEA, 0x7B, 0x89, 0x72, 0x36, 0x97, 0x66, 0x65, 0x00, 0xD6, 0xC7, 0x67, 0x9D, 0x64, 0x54, 0x74, 0xC6, 0x77, 0x64, 0x2F, 0x39, 0x96, 0xB0, 0x93, 0xEB, 0xFB, 0xAD, 0xEB, 0x1E, 0x20, 0x06, 0xCA, 0x1B, 0x59, 0x3B, 0x03, 0xAC, 0x40, 0xF9, 0xC2, 0x6C, 0x6A, 0xEC, 0xFB, 0xB9, 0xC9, 0x1A, 0xFB, 0x8B, 0x16, 0xDD, 0x49, 0x67, 0x5A, 0xC5, 0xCD, 0xEB, 0x79, 0x93, 0xC4, 0x19, 0x15, 0xB8, 0x3C, 0x64, 0x5B, 0x59, 0x60, 0xA3, 0xE7, 0x6C, 0x8E, 0x01, 0xAD, 0xE5, 0xBA, 0xE9, 0xB7, 0xD8, 0x9E, 0x80, 0x53, 0x87, 0xF9, 0x39, 0x75, 0x86, 0x30, 0xC7, 0xC3, 0x99, 0xEC, 0xDE, 0x24, 0xF2, 0x15, 0xD1, 0x9D, 0xFE, 0xB3, 0xAC, 0xBA, 0xDB, 0x9E, 0x93, 0x00, 0x4B, 0xCF, 0x2B, 0xE6, 0x2E, 0x4B, 0x39, 0xDF, 0xAA, 0x23, 0xCA, 0x0C, 0x4D, 0xDC, 0x17, 0x6F, 0x20, 0x29, 0xB8, 0xFE, 0x67, 0x6F, 0xAA, 0x1E, 0xCF, 0x2A, 0x0C, 0x05, 0xF1, 0x4A, 0xEF, 0x7F, 0xF2, 0xE8, 0xC3, 0x48, 0xF3, 0xE2, 0x17, 0x91, 0xD1, 0xB5, 0x61, 0x69, 0xCF, 0x57, 0xC0, 0xFA, 0x20, 0x8A, 0xDA, 0x64, 0x2F, 0x9D, 0xCB, 0x69, 0x41, 0x2B, 0x70, 0x38, 0xAE, 0x59, 0x61, 0x5F, 0x49, 0x57, 0x9A, 0xDF, 0x85, 0xF9, 0xD2, 0x14, 0x7A, 0x48, 0x0D, 0xEE, 0x5B, 0xD1, 0x59, 0xBB, 0x71, 0x02, 0x37, 0x83, 0x24, 0xF0, 0xAB, 0xB0, 0xEB, 0x47, 0xAF, 0x6C, 0x0C, 0xDE, 0x08, 0xD8, 0xB2, 0x83, 0x58, 0x98, 0x05, 0x5F, 0x05, 0x3F, 0xD9, 0x93, 0x3E, 0x1D, 0x30, 0x67, 0x36, 0x45, 0xE7, 0x48, 0x8A, 0xEE, 0x87, 0x1B, 0xE3, 0x48, 0xC8, 0x51, 0xF0, 0x96, 0x9A, 0x15, 0x2B, 0xC7, 0x4D, 0x74, 0x4B, 0x2A, 0x09, 0x9E, 0x27, 0x07, 0x0B, 0x8F, 0x56, 0x41, 0x1C, 0x81, 0x67, 0x35, 0x0B, 0x50, 0x88, 0x47, 0x55, 0xBE, 0x80, 0x61, 0xCD, 0xFF, 0x54, 0x0D, 0x35, 0x2C, 0x3D, 0x46, 0xA1, 0x53, 0x45, 0x16, 0x8F, 0x37, 0xD4, 0x30, 0xD6, 0x86, 0x48, 0xF3, 0x27, 0xF2, 0x4B, 0x2B, 0xAD, 0xF5, 0xB4, 0x1C, 0x50, 0x10, 0xED, 0x2F, 0xC4, 0xA6, 0xC3, 0xCB, 0x72, 0x06, 0xF0, 0xDC, 0x2C, 0xDB, 0x84, 0x35, 0xAC, 0x44, 0x1B, 0xFD, 0x57, 0x2B, 0xA2, 0x53, 0xB2, 0x82, 0xFF, 0xEC, 0xD6, 0xB6, 0xD0, 0x83, 0x67, 0x32, 0xB1, 0xFA, 0x19, 0xAD, 0xAA, 0x0D, 0xDB, 0x07, 0x00, 0x6C, 0x4F, 0x2F, 0x6C, 0x12, 0x9B, 0xD9, 0x04, 0x1F, 0x0F, 0x38, 0xB0, 0xDC, 0x37, 0x60, 0x45, 0xAC, 0xD7, 0x96, 0x39, 0x0E, 0x52, 0xEA, 0x80, 0xDD, 0x19, 0x78, 0xC7, 0xD6, 0xD0, 0xD7, 0x9D, 0x53, 0x52, 0xE7, 0x48, 0x4E, 0xEE, 0x97, 0xF2, 0x50, 0xF2, 0xAA, 0xB4, 0xEC, 0x14, 0x0F, 0xCB, 0xC0, 0xB2, 0x45, 0xF4, 0x11, 0x03, 0xEB, 0x39, 0xE5, 0x6C, 0x8C, 0x52, 0x62, 0x0F, 0x3F, 0x84, 0x9D, 0x29, 0x03, 0x98, 0xB1, 0xF8, 0xBF, 0xBE, 0x4E, 0x42, 0xBB, 0x53, 0x71, 0x3C, 0x9F, 0x6E, 0x8D, 0xDA, 0x78, 0x9C, 0x53, 0x4F, 0xA2, 0x2A, 0xB3, 0xF3, 0xEC, 0x30, 0x70, 0x3D, 0x33, 0xB1, 0xDA, 0x70, 0x94, 0x5B, 0x8A, 0x58, 0xD9, 0xAA, 0x49, 0xB1, 0x09, 0x4B, 0x5D, 0xE6, 0x33, 0x5F, 0xF4, 0xB3, 0x26, 0xDC, 0x80, 0xC1, 0x0F, 0x94, 0xA3, 0x03, 0x66, 0x68, 0xB5, 0x7F, 0xEC, 0xB4, 0xFF, 0x7D, 0xC8, 0x53, 0xB3, 0x70, 0x10, 0xB0, 0xA2, 0x02, 0x61, 0x9E, 0x6A, 0x64, 0xDF, 0xFA, 0x17, 0x49, 0x82, 0x2D, 0x9D, 0xA5, 0x72, 0xC4, 0xC6, 0x0C, 0x3C, 0xB0, 0xAF, 0x34, 0xCC, 0x79, 0x13, 0xC5, 0x33, 0xF7, 0x3B, 0x01, 0x82, 0xE3, 0x03, 0x0B, 0x32, 0x07, 0xFA, 0xD2, 0x9C, 0x68, 0xD8, 0xF3, 0xE4, 0x4C, 0xE6, 0xA0, 0x3D, 0xD5, 0x1C, 0x49, 0x1E, 0xD2, 0xC6, 0x90, 0x32, 0x22, 0x61, 0xBF, 0xA8, 0xC5, 0x76, 0x88, 0xB8, 0x6A, 0xE8, 0x6E, 0xB0, 0xA2, 0x7C, 0x01, 0x7E, 0xCD, 0x67, 0xC5, 0xC0, 0x7B, 0xA3, 0x85, 0xDE, 0xDB, 0x8E, 0x5F, 0x3C, 0x80, 0x13, 0x7D, 0x2E, 0x5F, 0x29, 0xA5, 0x99, 0xC6, 0xD2, 0x2B, 0x97, 0x07, 0x96, 0xD6, 0x01, 0x0A, 0x47, 0x27, 0xE4, 0xB3, 0xA4, 0x01, 0xD1, 0x5A, 0xA4, 0x91, 0xDF, 0x9D, 0x30, 0x21, 0xEB, 0xFC, 0xE8, 0xD2, 0xEE, 0xDA, 0x07, 0xD2, 0xFC, 0xEF, 0x4B, 0x21, 0x48, 0x4F, 0x06, 0xB0, 0x6F, 0x4E, 0xC7, 0x9B, 0x7B, 0xFC, 0x05, 0x9E, 0xE7, 0x4E, 0x68, 0x1D, 0x01, 0x2D, 0xE3, 0xA7, 0x22, 0x85, 0x67, 0xCB, 0xA3, 0xF9, 0x7B, 0xCE, 0x91, 0x0D, 0xB0, 0x7F, 0x7C, 0xC0, 0xBE, 0xAF, 0x59, 0x3C, 0x15, 0x3B, 0x2E, 0x2B, 0xFF, 0xA4, 0xF4, 0x21, 0x2E, 0x23, 0x48, 0x2B, 0x16, 0xE8, 0x6B, 0x14, 0xC6, 0x5C, 0xF4, 0x0A, 0xA9, 0xBE, 0x23, 0xF3, 0xA2, 0x8E, 0x7D, 0x90, 0x83, 0xD5, 0x80, 0x41, 0x6C, 0x9B, 0xE5, 0x19, 0x73, 0xBE, 0x3D, 0x15, 0x86, 0xB7, 0x05, 0xCD, 0x1F, 0x1F, 0x9D, 0x1F, 0xF4, 0x1B, 0xEF, 0xDF, 0x1C, 0x0B, 0x58, 0xF7, 0xFB, 0x73, 0x23, 0x50, 0x4C, 0x7E, 0xA6, 0xD0, 0xF9, 0x1F, 0xD4, 0x5B, 0x06, 0x57, 0x3B, 0x8C, 0x93, 0x02, 0x8B, 0xF7, 0xF3, 0xCC, 0xD1, 0xC8, 0xDA, 0xA6, 0x43, 0xE5, 0x97, 0xAE, 0x21, 0x36, 0x0B, 0x97, 0x4D, 0x88, 0x9F, 0x84, 0x0E, 0x9E, 0xF7, 0x15, 0xDB, 0xD9, 0x16, 0x05, 0xE1, 0x81, 0xAE, 0x69, 0xEA, 0xBB, 0x46, 0x5F, 0xEA, 0x09, 0x55, 0xF7, 0xC6, 0x3E, 0xE3, 0x90, 0x95, 0xC1, 0x24, 0x76, 0xE9, 0x69, 0x14, 0x41, 0xBD, 0x5B, 0xB9, 0x92, 0xC2, 0x14, 0xCA, 0x4F, 0x22, 0xBF, 0x9F, 0xC7, 0x31, 0x74, 0xD5, 0x91, 0xD0, 0xA3, 0x5D, 0x4A, 0xA4, 0x89, 0xE6, 0xCC, 0x12, 0xEC, 0xFA, 0xBB, 0x8B, 0x21, 0xE7, 0x84, 0xB7, 0x8E, 0x97, 0x7B, 0xB8, 0x9D, 0x23, 0x80, 0x0A, 0x0F, 0x03, 0x1C, 0x5A, 0xFB, 0x23, 0x41, 0x75, 0xA5, 0xBB, 0x69, 0x8B, 0xA5, 0xD7, 0x98, 0x55, 0x5D, 0x7E, 0xF0, 0xFF, 0xF1, 0x1E, 0x9F, 0x41, 0xE6, 0xF8, 0x2B, 0x93, 0x89, 0xFC, 0x62, 0x05, 0x03, 0xF1, 0x08, 0x1E, 0x74, 0xE0, 0xF1, 0xFD, 0xC8, 0x3D, 0x76, 0xC8, 0xDD, 0x5C, 0xFD, 0x80, 0xD8, 0x2D, 0x29, 0x60, 0x38, 0x08, 0x4A, 0xBA, 0xA2, 0xAF, 0x68, 0xB4, 0xDE, 0xA3, 0xE7, 0x00, 0xED, 0x1A, 0x99, 0xD9, 0xEC, 0xB0, 0xFD, 0x11, 0x05, 0x26, 0x75, 0xBB, 0xDA, 0x90, 0x60, 0x2C, 0xA9, 0xE3, 0x96, 0x69, 0x91, 0x69, 0xC6, 0x22, 0xAC, 0x52, 0x94, 0x9B, 0xFC, 0x98, 0x76, 0xEF, 0xF3, 0xFC, 0xD2, 0xD2, 0x78, 0xAE, 0xA3, 0x27, 0x9E, 0x1A, 0x01, 0x90, 0x0C, 0xA5, 0x55, 0x0F, 0x95, 0x60, 0xD4, 0xE3, 0xD4, 0xFB, 0x5A, 0x7E, 0xF1, 0x16, 0xE0, 0xA0, 0x15, 0x68, 0x54, 0xE0, 0x05, 0xF7, 0x91, 0x35, 0x2F, 0xB6, 0x8D, 0xAC, 0x0D, 0xB0, 0x75, 0x3A, 0xA4, 0xE4, 0xB3, 0xB0, 0x19, 0x11, 0x9E, 0x5C, 0xE2, 0xDE, 0x4E, 0x73, 0x14, 0x28, 0x7E, 0xF3, 0x84, 0xA9, 0x2C, 0x30, 0xBE, 0x01, 0x20, 0x2A, 0x6A, 0x9A, 0xDE, 0x42, 0x62, 0x4A, 0x50, 0xEE, 0x29, 0xA1, 0x8F, 0xA2, 0x19, 0x92, 0xF1, 0x6C, 0xE0, 0x22, 0x66, 0x56, 0x9A, 0x6A, 0xE2, 0x56, 0x04, 0x1D, 0x05, 0x6A, 0xD8, 0xC7, 0x66, 0xA9, 0xA7, 0xCD, 0xF5, 0x1D, 0x90, 0x61, 0xC7, 0x46, 0x94, 0x72, 0xF2, 0x1D, 0x6D, 0x1F, 0x0A, 0x34, 0x6E, 0xC2, 0x80, 0x02, 0x5C, 0x13, 0x87, 0x81, 0x76, 0xD7, 0xE8, 0xF4, 0x55, 0x92, 0x95, 0xBF, 0x63, 0x07, 0x94, 0x67, 0x7D, 0x18, 0x07, 0x6C, 0x55, 0x6D, 0x1C, 0x9D, 0x51, 0x1F, 0xA6, 0xB6, 0xFC, 0x09, 0x2F, 0xC7, 0xA3, 0xEF, 0x8E, 0x0A, 0xE0, 0x2D, 0x65, 0xC9, 0x8C, 0x6D, 0xCE, 0x54, 0xFD, 0xC4, 0x52, 0x5C, 0xF0, 0xBC, 0xA4, 0xF9, 0xAA, 0x85, 0xF4, 0xFE, 0xCC, 0x7A, 0xCD, 0x83, 0x2E, 0xAC, 0xDA, 0xFE, 0x62, 0x40, 0xE8, 0xC7, 0x88, 0xB6, 0x5D, 0xAF, 0x79, 0xAA, 0x70, 0x58, 0x3A, 0x0C, 0x34, 0x15, 0x52, 0x2E, 0x3B, 0xFE, 0xA6, 0x1A, 0x29, 0x8D, 0xD3, 0x9E, 0x1D, 0x22, 0xCA, 0x61, 0xC5, 0x3E, 0xBF, 0x00, 0xDE, 0xC2, 0x73, 0x9B, 0x8E, 0x93, 0xAF, 0xF4, 0x21, 0x97, 0xDD, 0x43, 0x22, 0x7D, 0xEF, 0x25, 0x84, 0x64, 0x9A, 0xF7, 0xBC, 0x7A, 0x0A, 0x60, 0xA5, 0xC4, 0xA7, 0x72, 0x18, 0xB0, 0xBE, 0x6A, 0xE5, 0xAD, 0x84, 0x19, 0x4A, 0x49, 0x01, 0xCD, 0x9F, 0x73, 0xAD, 0xB7, 0x0A, 0xF6, 0x19, 0xC3, 0x8B, 0x71, 0x62, 0x79, 0xBA, 0x41, 0xEF, 0x99, 0xF4, 0x04, 0x40, 0xEE, 0x82, 0xEC, 0x45, 0xAC, 0xDE, 0xD3, 0x25, 0xC8, 0x36, 0xFE, 0x69, 0xB8, 0x65, 0xA5, 0xE5, 0xCD, 0x0F, 0xF8, 0x56, 0xA3, 0x0D, 0xE7, 0xF0, 0x27, 0xD8, 0xC1, 0x3B, 0x40, 0x7D, 0x5B, 0x31, 0x62, 0x9A, 0xC1, 0xA1, 0x62, 0x08, 0xBD, 0x6A, 0xF2, 0xB7, 0xCA, 0x94, 0xB1, 0x88, 0x24, 0x9E, 0x89, 0xDA, 0x3C, 0x0F, 0xBF, 0x18, 0xA4, 0x12, 0xA8, 0x69, 0xF5, 0xF4, 0x97, 0xAD, 0x6F, 0x72, 0xAC, 0xEE, 0xB4, 0xD0, 0x77, 0xA0, 0xB7, 0xEE, 0xDF, 0x30, 0x17, 0xD8, 0x6A, 0x79, 0x9E, 0x4A, 0x68, 0x9E, 0x43, 0x9E, 0xE5, 0x84, 0x17, 0x29, 0xE4, 0xD9, 0x57, 0x2F, 0x8C, 0x6F, 0xE7, 0x67, 0x6E, 0xF7, 0x0A, 0x9D, 0xC0, 0x2E, 0x39, 0x37, 0xF4, 0xDF, 0xB7, 0x9B, 0x3F, 0x53, 0x52, 0x45, 0x79, 0x31, 0x18, 0x07, 0x40, 0xEA, 0xB3, 0xA3, 0x34, 0x18, 0x23, 0x6A, 0x44, 0x29, 0x40, 0x36, 0x48, 0xA9, 0xAA, 0xD6, 0x70, 0x49, 0xE6, 0x33, 0xBD, 0x07, 0x2F, 0xFC, 0xC9, 0x71, 0xEF, 0x0F, 0xC9, 0xEE, 0x5F, 0xD2, 0xB5, 0xAE, 0xFD, 0xFE, 0xE6, 0xFC, 0xBE, 0x0B, 0x64, 0x41, 0x80, 0x6F, 0x48, 0x55, 0x50, 0x70, 0x9B, 0x2B, 0xC4, 0xC3, 0x06, 0xAC, 0x0A, 0xD5, 0x94, 0x84, 0x91, 0xB6, 0x4C, 0xDD, 0x47, 0x32, 0x02, 0x3B, 0xE8, 0x84, 0xAB, 0xBF, 0xBF, 0x57, 0xEA, 0xCF, 0xFF, 0x96, 0xE9, 0x35, 0x8B, 0xEE, 0x7D, 0xD6, 0x71, 0xFB, 0x15, 0xEB, 0xDF, 0x4E, 0xA6, 0x90, 0x2C, 0xB4, 0x91, 0xB5, 0x84, 0x74, 0xC3, 0x53, 0x3B, 0xA9, 0x61, 0x88, 0xA6, 0x0B, 0x5A, 0xE3, 0xC8, 0x33, 0x81, 0xB0, 0x3A, 0x93, 0x1A, 0x65, 0xB7, 0xD7, 0x40, 0x62, 0x6D, 0xCD, 0x9F, 0xC1, 0x9C, 0x75, 0x28, 0x1C, 0x18, 0x31, 0xC9, 0x78, 0xA3, 0xA7, 0x52, 0xF0, 0xE0, 0x0F, 0x0F, 0x90, 0xBB, 0x37, 0x0E, 0x49, 0xD4, 0xAD, 0xAE, 0xC9, 0xC6, 0x1A, 0x00, 0x8B, 0x39, 0x67, 0xC3, 0x5D, 0xE4, 0x7B, 0x27, 0x1C, 0x13, 0x4B, 0xD8, 0xFC, 0x7E, 0xF1, 0x81, 0x36, 0xBD, 0xD4, 0x15, 0x6A, 0xA3, 0xB2, 0x50, 0x34, 0x11, 0xAD, 0x4E, 0x22, 0xE4, 0x42, 0x63, 0x1C, 0x12, 0xE1, 0x60, 0xE8, 0xDD, 0xE9, 0x2B, 0xC4, 0x97, 0xCB, 0xE2, 0x40, 0x6D, 0x6C, 0xA0, 0xC0, 0x8F, 0x36, 0x9A, 0x04, 0x82, 0x6F, 0x27, 0x9E, 0xE2, 0x1C, 0x93, 0x7D, 0xED, 0xA2, 0xEC, 0x96, 0xF8, 0x8C, 0x34, 0x3C, 0xD4, 0xB6, 0xF9, 0x55, 0xA1, 0x4B, 0x27, 0xFF, 0x71, 0xF6, 0x91, 0xE2, 0xBD, 0x41, 0x10, 0x13, 0x1C, 0x16, 0xDA, 0xCB, 0xB5, 0xE4, 0x25, 0xF3, 0x2A, 0xD2, 0x3C, 0x5B, 0x57, 0x7C, 0x95, 0x0F, 0xD6, 0x06, 0x1C, 0xDF, 0x64, 0x06, 0xAA, 0xAF, 0x61, 0x72, 0xA1, 0xFD, 0xF1, 0x56, 0x29, 0x77, 0x8F, 0x7D, 0x0F, 0x8A, 0x2D, 0xF0, 0xE9, 0x79, 0x0E, 0x26, 0xD0, 0x2A, 0x4A, 0xFD, 0xB3, 0x84, 0xA1, 0xAA, 0x0B, 0x2A, 0xDC, 0x46, 0xDB, 0x6A, 0x90, 0xA3, 0xC7, 0x28, 0x14, 0x73, 0xFA, 0x6C, 0x6A, 0x0D, 0x92, 0xA0, 0xCB, 0xDB, 0x4D, 0xCF, 0x7C, 0x36, 0x15, 0xDA, 0x68, 0xA7, 0xCD, 0x84, 0x5A, 0x7F, 0x61, 0xCF, 0xA4, 0x9D, 0x0A, 0x2E, 0x55, 0x62, 0x5C, 0xE0, 0xE9, 0x8A, 0x6F, 0x2B, 0x0D, 0xC8, 0xED, 0xD8, 0xD2, 0xE9, 0x5B, 0x57, 0xDA, 0xCB, 0x4D, 0x6A, 0xFD, 0x17, 0xBA, 0x58, 0x32, 0x55, 0x51, 0x11, 0x50, 0x5A, 0x47, 0x4C, 0x69, 0x8E, 0xFE, 0xED, 0x89, 0x76, 0x6D, 0x14, 0xEE, 0xFD, 0xC3, 0x56, 0xA6, 0x9F, 0xF2, 0x25, 0x58, 0x4F, 0xE3, 0xB1, 0xE2, 0x19, 0x0E, 0xF8, 0x08, 0x43, 0x07, 0x93, 0xC4, 0x8B, 0x8F, 0xEC, 0xE9, 0x02, 0x85, 0xE0, 0x5B, 0xF3, 0x37, 0xAE, 0x0F, 0xF9, 0xF2, 0xA1, 0x91, 0x5C, 0x76, 0xB3, 0x06, 0x80, 0x95, 0xB3, 0x99, 0xFD, 0xA6, 0x2E, 0x11, 0x7D, 0x0B, 0xE9, 0xC3, 0xC8, 0xD5, 0x2C, 0xC1, 0x9D, 0x93, 0x91, 0xA6, 0xA7, 0x5D, 0xDB, 0x8E, 0x04, 0xD1, 0xDB, 0xAE, 0x6E, 0x73, 0x05, 0x0B, 0x5B, 0x7E, 0x9F, 0x72, 0x5E, 0x08, 0x05, 0x5C, 0xCB, 0xE1, 0xD9, 0x10, 0xFD, 0x8E, 0x81, 0xBC, 0x79, 0x07, 0xF6, 0x0B, 0xD1, 0x9F, 0x11, 0xEA, 0x79, 0x88, 0x87, 0xB3, 0xD8, 0x6A, 0x44, 0xC1, 0x57, 0x82, 0x5C, 0x81, 0xE4, 0x88, 0x38, 0xAC, 0x5D, 0x36, 0xB2, 0x5A, 0xBF, 0x6E, 0xB7, 0x2D, 0x3F, 0x32, 0x49, 0xED, 0xED, 0xBB, 0x24, 0xD0, 0xB9, 0xEF, 0xE3, 0x4E, 0x49, 0x1F, 0x9D, 0xD8, 0xC5, 0x12, 0xC1, 0x72, 0x6F, 0x1C, 0x55, 0x61, 0x24, 0xE6, 0xF8, 0x43, 0x00, 0xD7, 0x15, 0xDB, 0xC9, 0x22, 0x90, 0x99, 0x0D, 0x4A, 0xF4, 0x18, 0x22, 0xFE, 0xAD, 0xA6, 0x3B, 0x56, 0xA0, 0xD5, 0x0D, 0xAA, 0xB4, 0x1B, 0xFB, 0x5E, 0x21, 0xB9, 0x41, 0xD0, 0xCD, 0x33, 0x6D, 0xAC, 0xB4, 0xF5, 0x68, 0xE8, 0x2B, 0xB0, 0x44, 0xB4, 0x75, 0xBD, 0xD5, 0x0E, 0x04, 0xD4, 0x3D, 0xC6, 0xB3, 0xA7, 0x33, 0x91, 0x50, 0x10, 0x39, 0x96, 0x42, 0x4E, 0xB7, 0xB0, 0x64, 0x89, 0x6C, 0xFE, 0x2C, 0xDB, 0x6F, 0xFE, 0xE7, 0x30, 0x5F, 0xF5, 0x50, 0x50, 0x27, 0x94, 0xCE, 0x2C, 0x22, 0x4B, 0x6F, 0x1B, 0xD7, 0x3E, 0xD3, 0x79, 0x8B, 0xFC, 0xC0, 0xD7, 0xE5, 0x99, 0x23, 0x34, 0x17, 0x1F, 0x2D, 0xB9, 0xBC, 0x26, 0x79, 0xA5, 0x10, 0x09, 0x19, 0x0E, 0x75, 0x12, 0xDE, 0x95, 0xE4, 0xB1, 0xAC, 0x46, 0xF0, 0x25, 0x2F, 0x0B, 0x34, 0x09, 0xE2, 0x4F, 0x24, 0x47, 0x94, 0x2E, 0x23, 0xA4, 0x2C, 0xCC, 0xC0, 0x79, 0x5C, 0x06, 0x65, 0x1E, 0x18, 0xB3, 0x92, 0xC8, 0xB0, 0xCF, 0x07, 0x5C, 0x73, 0xB1, 0x29, 0xCC, 0x37, 0xDA, 0x9D, 0x81, 0x0A, 0xDE, 0x23, 0x7D, 0x62, 0x97, 0x19, 0xDC, 0x42, 0xAA, 0x7F, 0x33, 0x91, 0x4E, 0x37, 0x9D, 0x30, 0x4F, 0x6A, 0xCE, 0x9F, 0xC0, 0x99, 0xEF, 0x87, 0xA0, 0x0B, 0x63, 0xC2, 0x71, 0x6D, 0x13, 0x35, 0x8D, 0xE6, 0xA6, 0x05, 0xE1, 0xF5, 0xF7, 0x0B, 0x82, 0x85, 0x53, 0x5E, 0x7C, 0xDD, 0x3F, 0x5B, 0xBC, 0x87, 0xE1, 0x5B, 0x39, 0xB0, 0xEF, 0xAC, 0xC3, 0xB3, 0x73, 0xAD, 0x13, 0xD6, 0x9E, 0x0F, 0x56, 0xE5, 0xC1, 0x96, 0x07, 0x3E, 0x60, 0xBF, 0x9C, 0x72, 0xD7, 0x6F, 0xD9, 0x39, 0x51, 0x1E, 0xA2, 0x27, 0x6A, 0xDC, 0x66, 0x03, 0x1B, 0xAF, 0x09, 0xF5, 0x75, 0xA5, 0x10, 0x51, 0x53, 0xAD, 0xC2, 0x55, 0x0C, 0xA3, 0x5A, 0x48, 0xDB, 0x2E, 0x2F, 0xD6, 0x9B, 0x01, 0x3D, 0x20, 0x24, 0xDF, 0x16, 0x7A, 0xDF, 0xA1, 0x36, 0xA7, 0xDF, 0xD7, 0x3C, 0x01, 0xB4, 0x08, 0x7F, 0xEF, 0x30, 0x6F, 0x3C, 0x5B, 0xE5, 0x4A, 0x0F, 0x8A, 0xE9, 0xF1, 0xED, 0x8C, 0x71, 0x48, 0x02, 0x09, 0x25, 0x33, 0x60, 0x6B, 0x9C, 0xA5, 0xAC, 0xBA, 0xC6, 0xE0, 0x31, 0x3F, 0xBC, 0xC7, 0xD5, 0xE2, 0xF1, 0x7E, 0xB2, 0xDC, 0x53, 0x99, 0xE6, 0xF1, 0x12, 0x19, 0x1A, 0x41, 0x7D, 0x99, 0xA3, 0xA6, 0xAB, 0xEC, 0xF9, 0x1F, 0x33, 0xD9, 0xED, 0xFF, 0x05, 0x27, 0x93, 0xC1, 0xC6, 0xFC, 0xAF, 0xCE, 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, 0x13, 0x16, 0x1A, 0x25, 0x2A, 0x30, 0x32, }, }, }; #define DILITHIUM_TV_NUM sizeof(dilithium_tv)/sizeof(struct DILITHIUM_TEST_VECTOR) opencryptoki-opencryptoki-451d99c/testcases/crypto/dilithium_func.c000066400000000000000000000723571520105705100260270ustar00rootroot00000000000000/* * 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" #include "mechtable.h" #include "pqc_oids.h" /** * Experimental Support for Dilithium keys and signatures * with oid = 1.3.6.1.4.1.2.267.xxx * * 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; const _signVerifyParam signVerifyInput[] = { {CKM_IBM_DILITHIUM, 0}, {CKM_IBM_DILITHIUM, 1}, {CKM_IBM_DILITHIUM, 32}, {CKM_IBM_DILITHIUM, 59}, {CKM_IBM_DILITHIUM, 3000}, /* Not all variants support larger sizes */ }; const CK_BYTE dilithium_r2_65[] = OCK_DILITHIUM_R2_65; const CK_BYTE dilithium_r2_87[] = OCK_DILITHIUM_R2_87; const CK_BYTE dilithium_r3_44[] = OCK_DILITHIUM_R3_44; const CK_BYTE dilithium_r3_65[] = OCK_DILITHIUM_R3_65; const CK_BYTE dilithium_r3_87[] = OCK_DILITHIUM_R3_87; typedef struct variant_info { const char *name; CK_ULONG keyform; const CK_BYTE *oid; CK_ULONG oid_len; } _variant_info; const _variant_info variants[] = { { "DEFAULT (DILITHIUM_R2_65)", 0, NULL, 0 }, { "DILITHIUM_R2_65", CK_IBM_DILITHIUM_KEYFORM_ROUND2_65, dilithium_r2_65, sizeof(dilithium_r2_65) }, { "DILITHIUM_R2_87", CK_IBM_DILITHIUM_KEYFORM_ROUND2_87, dilithium_r2_87, sizeof(dilithium_r2_87) }, { "DILITHIUM_R3_44", CK_IBM_DILITHIUM_KEYFORM_ROUND3_44, dilithium_r3_44, sizeof(dilithium_r3_44) }, { "DILITHIUM_R3_65", CK_IBM_DILITHIUM_KEYFORM_ROUND3_65, dilithium_r3_65, sizeof(dilithium_r3_65) }, { "DILITHIUM_R3_87", CK_IBM_DILITHIUM_KEYFORM_ROUND3_87, dilithium_r3_87, sizeof(dilithium_r3_87) }, }; const CK_ULONG num_variants = sizeof(variants) / sizeof(_variant_info); 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_RV rc; mech.mechanism = mechType; mech.ulParameterLen = 0; mech.pParameter = NULL; /* Query the slot, check if this mech if supported */ if (!mech_supported(SLOT_ID, mech.mechanism)) { testcase_skip("Slot %u doesn't support %s", (unsigned int) SLOT_ID, p11_get_ckm(&mechtable_funcs, mech.mechanism)); rc = CKR_OK; goto testcase_cleanup; } data = calloc(inputlen > 0 ? inputlen : 1, sizeof(CK_BYTE)); 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(signaturelen, sizeof(CK_BYTE)); 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(siglen, sizeof(CK_BYTE)); 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 %lu does not match known length %lu.", siglen, dilithium_tv[index].sig_len); goto testcase_cleanup; } /* * The soft token uses randomized Dilithium signatures, thus no KAT checks * are possible. Verify the known answer signature with C_Verify instead. */ if (!is_soft_token(SLOT_ID)) { /* Check if signature matches with known signature */ if (memcmp(signature, dilithium_tv[index].sig, siglen) != 0) { testcase_error("Signature bad."); goto testcase_cleanup; } } else { /* Randomized signatures: Verify known answer signature with the key */ rc = funcs->C_VerifyInit(session, &mech, publ_key); if (rc != CKR_OK) { testcase_error("C_VerifyInit KAT-signature rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } rc = funcs->C_Verify(session, dilithium_tv[index].msg, dilithium_tv[index].msg_len, dilithium_tv[index].sig, dilithium_tv[index].sig_len); if (rc != CKR_OK) { testcase_error("C_Verify KAT-signature rc=%s", p11_get_ckr(rc)); 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(void) { 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, i; CK_FLAGS flags; 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 */ if (!mech_supported(SLOT_ID, mech.mechanism)) { testcase_skip("Slot %u doesn't support %s", (unsigned int) SLOT_ID, p11_get_ckm(&mechtable_funcs, mech.mechanism)); rc = CKR_OK; goto testcase_cleanup; } for (i = 0; i < 2 * num_variants; i++) { /* Setup attributes for public/private Dilithium key */ CK_BBOOL attr_sign = TRUE; CK_BBOOL attr_verify = TRUE; CK_ATTRIBUTE dilithium_attr_private_keyform[] = { {CKA_SIGN, &attr_sign, sizeof(CK_BBOOL)}, {CKA_IBM_DILITHIUM_KEYFORM, (CK_BYTE *)&variants[i % num_variants].keyform, sizeof(CK_ULONG)}, }; CK_ATTRIBUTE dilithium_attr_public_keyform[] = { {CKA_VERIFY, &attr_verify, sizeof(CK_BBOOL)}, {CKA_IBM_DILITHIUM_KEYFORM, (CK_BYTE *)&variants[i % num_variants].keyform, sizeof(CK_ULONG)}, }; CK_ATTRIBUTE dilithium_attr_private_mode[] = { {CKA_SIGN, &attr_sign, sizeof(CK_BBOOL)}, {CKA_IBM_DILITHIUM_MODE, (CK_BYTE *)variants[i % num_variants].oid, variants[i % num_variants].oid_len}, }; CK_ATTRIBUTE dilithium_attr_public_mode[] = { {CKA_VERIFY, &attr_verify, sizeof(CK_BBOOL)}, {CKA_IBM_DILITHIUM_MODE, (CK_BYTE *)variants[i % num_variants].oid, variants[i % num_variants].oid_len}, }; CK_ATTRIBUTE *dilithium_attr_private = i < num_variants ? dilithium_attr_private_keyform : dilithium_attr_private_mode; CK_ATTRIBUTE *dilithium_attr_public = i < num_variants ? dilithium_attr_public_keyform : dilithium_attr_public_mode; CK_ULONG num_dilithium_attrs = (variants[i % num_variants].oid == NULL) ? 1 : 2; /* Generate Dilithium key pair */ rc = funcs->C_GenerateKeyPair(session, &mech, dilithium_attr_public, num_dilithium_attrs, dilithium_attr_private, num_dilithium_attrs, &publ_key, &priv_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("C_GenerateKeyPair with %s (%s) not supported", variants[i % num_variants].name, i < num_variants ? "KEYFORM" : "MODE"); goto next; } else { testcase_new_assertion(); testcase_fail("C_GenerateKeyPair with %s (%s) and valid input failed, rc=%s", variants[i % num_variants].name, i < num_variants ? "KEYFORM" : "MODE", p11_get_ckr(rc)); goto testcase_cleanup; } } testcase_new_assertion(); testcase_pass("*Generate Dilithium key pair with %s (%s) passed.", variants[i % num_variants].name, i < num_variants ? "KEYFORM" : "MODE"); /* 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 with %s failed index=%lu.", variants[i % num_variants].name, j); goto next; } testcase_pass("*Sign & verify with %s j=%lu passed.", variants[i % num_variants].name, j); } next: if (publ_key != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, publ_key); publ_key = CK_INVALID_HANDLE; if (priv_key != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, priv_key); priv_key = CK_INVALID_HANDLE; } 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(void) { 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_RV rc; testcase_rw_session(); testcase_user_login(); /* query the slot, check if this mech is supported */ if (!mech_supported(SLOT_ID, CKM_IBM_DILITHIUM)) { testcase_skip("Slot %u doesn't support CKM_IBM_DILITHIUM", (unsigned int) SLOT_ID); rc = CKR_OK; goto testcase_cleanup; } for (i = 0; i < DILITHIUM_TV_NUM; i++) { testcase_begin("Starting Dilithium import key pair, Sign/Verify, %s index=%lu", dilithium_tv[i].name, i); /* Create Dilithium private key */ rc = create_DilithiumPrivateKey(session, dilithium_tv[i].pkcs8, dilithium_tv[i].pkcs8_len, dilithium_tv[i].keyform, 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); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("C_CreateObject with %s not supported", dilithium_tv[i].name); continue; } else if (rc == CKR_POLICY_VIOLATION) { testcase_skip("Dilithium key import is not allowed by policy"); continue; } testcase_new_assertion(); testcase_fail("C_CreateObject (Dilithium Private Key) failed at i=%lu, " "rc=%s", i, p11_get_ckr(rc)); goto testcase_cleanup; } testcase_new_assertion(); 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].spki, dilithium_tv[i].spki_len, dilithium_tv[i].keyform, dilithium_tv[i].rho, dilithium_tv[i].rho_len, dilithium_tv[i].t1, dilithium_tv[i].t1_len, &publ_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("C_CreateObject with %s not supported", dilithium_tv[i].name); goto testcase_cleanup; } else if (rc == CKR_POLICY_VIOLATION) { testcase_skip("Dilithium key import is not allowed by policy"); goto testcase_cleanup; } testcase_new_assertion(); testcase_fail("C_CreateObject (Dilithium Public Key) failed at i=%lu, " "rc=%s", i, p11_get_ckr(rc)); goto testcase_cleanup; } testcase_new_assertion(); 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(tmp_len, sizeof(CK_BYTE)); 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(void) { 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_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(); /* query the slot, check if this mech is supported */ if (!mech_supported(SLOT_ID, CKM_IBM_DILITHIUM)) { testcase_skip("Slot %u doesn't support CKM_IBM_DILITHIUM", (unsigned int) SLOT_ID); rc = CKR_OK; goto testcase_cleanup; } if (!mech_supported(SLOT_ID, CKM_AES_KEY_GEN)) { testcase_skip("Slot %u doesn't support CKM_AES_KEY_GEN", (unsigned int) SLOT_ID); rc = CKR_OK; goto testcase_cleanup; } if (!mech_supported_flags(SLOT_ID, CKM_AES_CBC_PAD, CKF_WRAP)) { testcase_skip("Slot %u doesn't support key wrapping with CKM_AES_CBC_PAD", (unsigned int) SLOT_ID); rc = CKR_OK; goto testcase_cleanup; } for (i = 0; i < DILITHIUM_TV_NUM; i++) { testcase_begin("Starting Dilithium transfer key pair, Sign/Verify %s index=%lu.", dilithium_tv[i].name, i); /* Create Dilithium private key */ rc = create_DilithiumPrivateKey(session, dilithium_tv[i].pkcs8, dilithium_tv[i].pkcs8_len, dilithium_tv[i].keyform, 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); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("C_CreateObject with %s not supported", dilithium_tv[i].name); continue; } else if (rc == CKR_POLICY_VIOLATION) { testcase_skip("Dilithium key import is not allowed by policy"); continue; } testcase_new_assertion(); testcase_fail ("C_CreateObject (Dilithium Private Key) failed at i=%lu, rc=%s", i, p11_get_ckr(rc)); goto testcase_cleanup; } testcase_new_assertion(); 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].spki, dilithium_tv[i].spki_len, dilithium_tv[i].keyform, dilithium_tv[i].rho, dilithium_tv[i].rho_len, dilithium_tv[i].t1, dilithium_tv[i].t1_len, &publ_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("C_CreateObject with %s not supported", dilithium_tv[i].name); goto testcase_cleanup; } else if (rc == CKR_POLICY_VIOLATION) { testcase_skip("Dilithium key import is not allowed by policy"); goto testcase_cleanup; } testcase_new_assertion(); testcase_fail ("C_CreateObject (Dilithium Public Key) failed at i=%lu, rc=%s", i, p11_get_ckr(rc)); goto testcase_cleanup; } testcase_new_assertion(); 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, CK_TRUE, &wkey_mech, &secret_key); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("AES key generation is not allowed by policy"); goto testcase_cleanup; } 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(); rv = run_GenerateDilithiumKeyPairSignVerify(); rv = run_ImportDilithiumKeyPairSignVerify(); rv = run_TransferDilithiumKeyPairSignVerify(); testcase_print_result(); funcs->C_Finalize(NULL); return testcase_return(rv); } opencryptoki-opencryptoki-451d99c/testcases/crypto/dsa_func.c000066400000000000000000000367541520105705100246070ustar00rootroot00000000000000/* * 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 = CK_INVALID_HANDLE, priv_key = CK_INVALID_HANDLE; 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) { if (is_rejected_by_policy(rc, session)) { testcase_skip("DSA key generation is not allowed by policy"); rc = CKR_OK; } else { testcase_fail("C_GenerateKeyPair rc=%s", p11_get_ckr(rc)); } } else { testcase_pass("GenerateDSAKeyPair passed"); } testcase_cleanup: funcs->C_DestroyObject(session, priv_key); funcs->C_DestroyObject(session, publ_key); 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 = CK_INVALID_HANDLE, priv_key = CK_INVALID_HANDLE; 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) { if (is_rejected_by_policy(rc, session)) { testcase_skip("DSA key generation is not allowed by policy"); goto testcase_cleanup; } 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: funcs->C_DestroyObject(session, priv_key); funcs->C_DestroyObject(session, publ_key); 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 = CK_INVALID_HANDLE, priv_key = CK_INVALID_HANDLE; 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) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("DSA key import is not allowed by policy"); goto testcase_cleanup; } 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) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("DSA key import is not allowed by policy"); goto testcase_cleanup; } 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: funcs->C_DestroyObject(session, priv_key); funcs->C_DestroyObject(session, publ_key); testcase_user_logout(); if (funcs->C_CloseAllSessions(slot_id) != CKR_OK) testcase_error("C_CloseAllSessions failed."); return rc; } CK_RV dsa_functions(void) { 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(); rv = dsa_functions(); testcase_print_result(); funcs->C_Finalize(NULL); return testcase_return(rv); } opencryptoki-opencryptoki-451d99c/testcases/crypto/ec.h000066400000000000000000003746751520105705100234300ustar00rootroot00000000000000/* * 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, CURVE_KOBLITZ = 5, CURVE_BLS12_381 = 6, }; 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, }, { // #23 [SECP256k1] .name = "SECP256k1", .curve_type = CURVE_KOBLITZ, .params = {0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x0A}, .params_len = 7, .privkey = {0x91, 0xe8, 0x29, 0x15, 0x57, 0x00, 0x40, 0x3e, 0x99, 0xb2, 0x55, 0x4c, 0xd4, 0x4c, 0x55, 0x3d, 0x63, 0xeb, 0x94, 0x77, 0x1d, 0x79, 0xe7, 0x24, 0x80, 0x49, 0x62, 0x54, 0xad, 0xe0, 0x52, 0xf4}, .privkey_len = 32, .pubkey = {0x04, 0x41, 0x04, 0xee, 0xb6, 0xe4, 0x76, 0xc7, 0x9b, 0x2c, 0x40, 0x5e, 0x20, 0x47, 0x0e, 0x72, 0x70, 0xf1, 0x9c, 0xa1, 0xef, 0x96, 0x15, 0x13, 0x13, 0xcf, 0x13, 0xb3, 0x66, 0xc3, 0xc8, 0x66, 0x10, 0x78, 0x81, 0x47, 0x2a, 0x28, 0x82, 0x26, 0x52, 0x8e, 0x7a, 0x48, 0x0c, 0xde, 0xfa, 0xe3, 0x30, 0xe3, 0xfb, 0xa9, 0xd1, 0xd8, 0x70, 0x08, 0xd4, 0xf6, 0xc3, 0x8e, 0x52, 0xa7, 0x02, 0x83, 0x68, 0x99, 0x8a}, .pubkey_len = 67, }, { // #24 [BLS 12 381] .name = "BLS12381", .curve_type = CURVE_BLS12_381, .params = { 0x06, 0x0C, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x02, 0x82, 0x0B, 0x87, 0x67, 0x03, 0x02 }, .params_len = 14, .privkey = {0x47, 0xb8, 0x19, 0x2d, 0x77, 0xbf, 0x87, 0x1b, 0x62, 0xe8, 0x78, 0x59, 0xd6, 0x53, 0x92, 0x27, 0x25, 0x72, 0x4a, 0x5c, 0x03, 0x1a, 0xfe, 0xab, 0xc6, 0x0b, 0xce, 0xf5, 0xff, 0x66, 0x51, 0x38}, .privkey_len = 32, .pubkey = {0x04, 0x61, 0x04, 0x13, 0x01, 0x80, 0x3f, 0x8b, 0x5a, 0xc4, 0xa1, 0x13, 0x35, 0x81, 0xfc, 0x67, 0x6d, 0xfe, 0xdc, 0x60, 0xd8, 0x91, 0xdd, 0x5f, 0xa9, 0x90, 0x28, 0x80, 0x5e, 0x5e, 0xa5, 0xb0, 0x8d, 0x34, 0x91, 0xaf, 0x75, 0xd0, 0x70, 0x7a, 0xda, 0xb3, 0xb7, 0x0c, 0x6a, 0x6a, 0x58, 0x02, 0x17, 0xbf, 0x81, 0x0e, 0x4e, 0xfa, 0x61, 0xb5, 0x58, 0xd0, 0x43, 0xcd, 0x3f, 0xed, 0x5c, 0x44, 0xac, 0x75, 0x41, 0x5d, 0xe0, 0xd0, 0x32, 0x58, 0x6f, 0xec, 0xb2, 0x2a, 0xcb, 0xb6, 0x7d, 0x50, 0x8c, 0xde, 0x9f, 0x95, 0x36, 0xa7, 0x60, 0x9d, 0x69, 0xc1, 0xd6, 0xe6, 0x04, 0x50, 0x84, 0x3e, 0x4e, 0xc5, 0x9a}, .pubkey_len = 99, }, }; #define EC_TV_NUM sizeof(ec_tv)/sizeof(struct EC_TEST_VECTOR) struct ED_TEST_VECTOR { CK_BYTE name[32]; enum curve_type curve_type; CK_BYTE params[64]; CK_ULONG params_len; CK_BYTE privkey[64]; CK_ULONG privkey_len; CK_BYTE pubkey[64]; CK_ULONG pubkey_len; CK_BYTE msg[1024]; CK_ULONG msg_len; CK_BBOOL mech_param; CK_BYTE ctx[1024]; CK_ULONG ctx_len; CK_BBOOL prehash; CK_BYTE signature[128]; CK_ULONG signature_len; }; /* Test vectors from RFC 8032 */ struct ED_TEST_VECTOR ed_tv[] = { { // #0 [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 = {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 = 32, .msg_len = 0, .mech_param = FALSE, .ctx_len = 0, .prehash = FALSE, .signature = {0xe5, 0x56, 0x43, 0x00, 0xc3, 0x60, 0xac, 0x72, 0x90, 0x86, 0xe2, 0xcc, 0x80, 0x6e, 0x82, 0x8a, 0x84, 0x87, 0x7f, 0x1e, 0xb8, 0xe5, 0xd9, 0x74, 0xd8, 0x73, 0xe0, 0x65, 0x22, 0x49, 0x01, 0x55, 0x5f, 0xb8, 0x82, 0x15, 0x90, 0xa3, 0x3b, 0xac, 0xc6, 0x1e, 0x39, 0x70, 0x1c, 0xf9, 0xb4, 0x6b, 0xd2, 0x5b, 0xf5, 0xf0, 0x59, 0x5b, 0xbe, 0x24, 0x65, 0x51, 0x41, 0x43, 0x8e, 0x7a, 0x10, 0x0b}, .signature_len = 64, }, { // #1 [Ed25519] .name = "Ed25519", .curve_type = CURVE_EDWARDS, .params = {0x06, 0x03, 0x2B, 0x65, 0x70}, .params_len = 5, .privkey = {0x4c, 0xcd, 0x08, 0x9b, 0x28, 0xff, 0x96, 0xda, 0x9d, 0xb6, 0xc3, 0x46, 0xec, 0x11, 0x4e, 0x0f, 0x5b, 0x8a, 0x31, 0x9f, 0x35, 0xab, 0xa6, 0x24, 0xda, 0x8c, 0xf6, 0xed, 0x4f, 0xb8, 0xa6, 0xfb}, .privkey_len = 32, .pubkey = {0x3d, 0x40, 0x17, 0xc3, 0xe8, 0x43, 0x89, 0x5a, 0x92, 0xb7, 0x0a, 0xa7, 0x4d, 0x1b, 0x7e, 0xbc, 0x9c, 0x98, 0x2c, 0xcf, 0x2e, 0xc4, 0x96, 0x8c, 0xc0, 0xcd, 0x55, 0xf1, 0x2a, 0xf4, 0x66, 0x0c}, .pubkey_len = 32, .msg = {0x72}, .msg_len = 1, .mech_param = FALSE, .ctx_len = 0, .prehash = FALSE, .signature = {0x92, 0xa0, 0x09, 0xa9, 0xf0, 0xd4, 0xca, 0xb8, 0x72, 0x0e, 0x82, 0x0b, 0x5f, 0x64, 0x25, 0x40, 0xa2, 0xb2, 0x7b, 0x54, 0x16, 0x50, 0x3f, 0x8f, 0xb3, 0x76, 0x22, 0x23, 0xeb, 0xdb, 0x69, 0xda, 0x08, 0x5a, 0xc1, 0xe4, 0x3e, 0x15, 0x99, 0x6e, 0x45, 0x8f, 0x36, 0x13, 0xd0, 0xf1, 0x1d, 0x8c, 0x38, 0x7b, 0x2e, 0xae, 0xb4, 0x30, 0x2a, 0xee, 0xb0, 0x0d, 0x29, 0x16, 0x12, 0xbb, 0x0c, 0x00}, .signature_len = 64, }, { // #2 [Ed25519] .name = "Ed25519", .curve_type = CURVE_EDWARDS, .params = {0x06, 0x03, 0x2B, 0x65, 0x70}, .params_len = 5, .privkey = {0xc5, 0xaa, 0x8d, 0xf4, 0x3f, 0x9f, 0x83, 0x7b, 0xed, 0xb7, 0x44, 0x2f, 0x31, 0xdc, 0xb7, 0xb1, 0x66, 0xd3, 0x85, 0x35, 0x07, 0x6f, 0x09, 0x4b, 0x85, 0xce, 0x3a, 0x2e, 0x0b, 0x44, 0x58, 0xf7}, .privkey_len = 32, .pubkey = {0xfc, 0x51, 0xcd, 0x8e, 0x62, 0x18, 0xa1, 0xa3, 0x8d, 0xa4, 0x7e, 0xd0, 0x02, 0x30, 0xf0, 0x58, 0x08, 0x16, 0xed, 0x13, 0xba, 0x33, 0x03, 0xac, 0x5d, 0xeb, 0x91, 0x15, 0x48, 0x90, 0x80, 0x25}, .pubkey_len = 32, .msg = {0xaf, 0x82}, .msg_len = 2, .mech_param = FALSE, .ctx_len = 0, .prehash = FALSE, .signature = {0x62, 0x91, 0xd6, 0x57, 0xde, 0xec, 0x24, 0x02, 0x48, 0x27, 0xe6, 0x9c, 0x3a, 0xbe, 0x01, 0xa3, 0x0c, 0xe5, 0x48, 0xa2, 0x84, 0x74, 0x3a, 0x44, 0x5e, 0x36, 0x80, 0xd7, 0xdb, 0x5a, 0xc3, 0xac, 0x18, 0xff, 0x9b, 0x53, 0x8d, 0x16, 0xf2, 0x90, 0xae, 0x67, 0xf7, 0x60, 0x98, 0x4d, 0xc6, 0x59, 0x4a, 0x7c, 0x15, 0xe9, 0x71, 0x6e, 0xd2, 0x8d, 0xc0, 0x27, 0xbe, 0xce, 0xea, 0x1e, 0xc4, 0x0a}, .signature_len = 64, }, { // #3 [Ed25519] .name = "Ed25519", .curve_type = CURVE_EDWARDS, .params = {0x06, 0x03, 0x2B, 0x65, 0x70}, .params_len = 5, .privkey = {0xf5, 0xe5, 0x76, 0x7c, 0xf1, 0x53, 0x31, 0x95, 0x17, 0x63, 0x0f, 0x22, 0x68, 0x76, 0xb8, 0x6c, 0x81, 0x60, 0xcc, 0x58, 0x3b, 0xc0, 0x13, 0x74, 0x4c, 0x6b, 0xf2, 0x55, 0xf5, 0xcc, 0x0e, 0xe5}, .privkey_len = 32, .pubkey = {0x27, 0x81, 0x17, 0xfc, 0x14, 0x4c, 0x72, 0x34, 0x0f, 0x67, 0xd0, 0xf2, 0x31, 0x6e, 0x83, 0x86, 0xce, 0xff, 0xbf, 0x2b, 0x24, 0x28, 0xc9, 0xc5, 0x1f, 0xef, 0x7c, 0x59, 0x7f, 0x1d, 0x42, 0x6e}, .pubkey_len = 32, .msg = {0x08, 0xb8, 0xb2, 0xb7, 0x33, 0x42, 0x42, 0x43, 0x76, 0x0f, 0xe4, 0x26, 0xa4, 0xb5, 0x49, 0x08, 0x63, 0x21, 0x10, 0xa6, 0x6c, 0x2f, 0x65, 0x91, 0xea, 0xbd, 0x33, 0x45, 0xe3, 0xe4, 0xeb, 0x98, 0xfa, 0x6e, 0x26, 0x4b, 0xf0, 0x9e, 0xfe, 0x12, 0xee, 0x50, 0xf8, 0xf5, 0x4e, 0x9f, 0x77, 0xb1, 0xe3, 0x55, 0xf6, 0xc5, 0x05, 0x44, 0xe2, 0x3f, 0xb1, 0x43, 0x3d, 0xdf, 0x73, 0xbe, 0x84, 0xd8, 0x79, 0xde, 0x7c, 0x00, 0x46, 0xdc, 0x49, 0x96, 0xd9, 0xe7, 0x73, 0xf4, 0xbc, 0x9e, 0xfe, 0x57, 0x38, 0x82, 0x9a, 0xdb, 0x26, 0xc8, 0x1b, 0x37, 0xc9, 0x3a, 0x1b, 0x27, 0x0b, 0x20, 0x32, 0x9d, 0x65, 0x86, 0x75, 0xfc, 0x6e, 0xa5, 0x34, 0xe0, 0x81, 0x0a, 0x44, 0x32, 0x82, 0x6b, 0xf5, 0x8c, 0x94, 0x1e, 0xfb, 0x65, 0xd5, 0x7a, 0x33, 0x8b, 0xbd, 0x2e, 0x26, 0x64, 0x0f, 0x89, 0xff, 0xbc, 0x1a, 0x85, 0x8e, 0xfc, 0xb8, 0x55, 0x0e, 0xe3, 0xa5, 0xe1, 0x99, 0x8b, 0xd1, 0x77, 0xe9, 0x3a, 0x73, 0x63, 0xc3, 0x44, 0xfe, 0x6b, 0x19, 0x9e, 0xe5, 0xd0, 0x2e, 0x82, 0xd5, 0x22, 0xc4, 0xfe, 0xba, 0x15, 0x45, 0x2f, 0x80, 0x28, 0x8a, 0x82, 0x1a, 0x57, 0x91, 0x16, 0xec, 0x6d, 0xad, 0x2b, 0x3b, 0x31, 0x0d, 0xa9, 0x03, 0x40, 0x1a, 0xa6, 0x21, 0x00, 0xab, 0x5d, 0x1a, 0x36, 0x55, 0x3e, 0x06, 0x20, 0x3b, 0x33, 0x89, 0x0c, 0xc9, 0xb8, 0x32, 0xf7, 0x9e, 0xf8, 0x05, 0x60, 0xcc, 0xb9, 0xa3, 0x9c, 0xe7, 0x67, 0x96, 0x7e, 0xd6, 0x28, 0xc6, 0xad, 0x57, 0x3c, 0xb1, 0x16, 0xdb, 0xef, 0xef, 0xd7, 0x54, 0x99, 0xda, 0x96, 0xbd, 0x68, 0xa8, 0xa9, 0x7b, 0x92, 0x8a, 0x8b, 0xbc, 0x10, 0x3b, 0x66, 0x21, 0xfc, 0xde, 0x2b, 0xec, 0xa1, 0x23, 0x1d, 0x20, 0x6b, 0xe6, 0xcd, 0x9e, 0xc7, 0xaf, 0xf6, 0xf6, 0xc9, 0x4f, 0xcd, 0x72, 0x04, 0xed, 0x34, 0x55, 0xc6, 0x8c, 0x83, 0xf4, 0xa4, 0x1d, 0xa4, 0xaf, 0x2b, 0x74, 0xef, 0x5c, 0x53, 0xf1, 0xd8, 0xac, 0x70, 0xbd, 0xcb, 0x7e, 0xd1, 0x85, 0xce, 0x81, 0xbd, 0x84, 0x35, 0x9d, 0x44, 0x25, 0x4d, 0x95, 0x62, 0x9e, 0x98, 0x55, 0xa9, 0x4a, 0x7c, 0x19, 0x58, 0xd1, 0xf8, 0xad, 0xa5, 0xd0, 0x53, 0x2e, 0xd8, 0xa5, 0xaa, 0x3f, 0xb2, 0xd1, 0x7b, 0xa7, 0x0e, 0xb6, 0x24, 0x8e, 0x59, 0x4e, 0x1a, 0x22, 0x97, 0xac, 0xbb, 0xb3, 0x9d, 0x50, 0x2f, 0x1a, 0x8c, 0x6e, 0xb6, 0xf1, 0xce, 0x22, 0xb3, 0xde, 0x1a, 0x1f, 0x40, 0xcc, 0x24, 0x55, 0x41, 0x19, 0xa8, 0x31, 0xa9, 0xaa, 0xd6, 0x07, 0x9c, 0xad, 0x88, 0x42, 0x5d, 0xe6, 0xbd, 0xe1, 0xa9, 0x18, 0x7e, 0xbb, 0x60, 0x92, 0xcf, 0x67, 0xbf, 0x2b, 0x13, 0xfd, 0x65, 0xf2, 0x70, 0x88, 0xd7, 0x8b, 0x7e, 0x88, 0x3c, 0x87, 0x59, 0xd2, 0xc4, 0xf5, 0xc6, 0x5a, 0xdb, 0x75, 0x53, 0x87, 0x8a, 0xd5, 0x75, 0xf9, 0xfa, 0xd8, 0x78, 0xe8, 0x0a, 0x0c, 0x9b, 0xa6, 0x3b, 0xcb, 0xcc, 0x27, 0x32, 0xe6, 0x94, 0x85, 0xbb, 0xc9, 0xc9, 0x0b, 0xfb, 0xd6, 0x24, 0x81, 0xd9, 0x08, 0x9b, 0xec, 0xcf, 0x80, 0xcf, 0xe2, 0xdf, 0x16, 0xa2, 0xcf, 0x65, 0xbd, 0x92, 0xdd, 0x59, 0x7b, 0x07, 0x07, 0xe0, 0x91, 0x7a, 0xf4, 0x8b, 0xbb, 0x75, 0xfe, 0xd4, 0x13, 0xd2, 0x38, 0xf5, 0x55, 0x5a, 0x7a, 0x56, 0x9d, 0x80, 0xc3, 0x41, 0x4a, 0x8d, 0x08, 0x59, 0xdc, 0x65, 0xa4, 0x61, 0x28, 0xba, 0xb2, 0x7a, 0xf8, 0x7a, 0x71, 0x31, 0x4f, 0x31, 0x8c, 0x78, 0x2b, 0x23, 0xeb, 0xfe, 0x80, 0x8b, 0x82, 0xb0, 0xce, 0x26, 0x40, 0x1d, 0x2e, 0x22, 0xf0, 0x4d, 0x83, 0xd1, 0x25, 0x5d, 0xc5, 0x1a, 0xdd, 0xd3, 0xb7, 0x5a, 0x2b, 0x1a, 0xe0, 0x78, 0x45, 0x04, 0xdf, 0x54, 0x3a, 0xf8, 0x96, 0x9b, 0xe3, 0xea, 0x70, 0x82, 0xff, 0x7f, 0xc9, 0x88, 0x8c, 0x14, 0x4d, 0xa2, 0xaf, 0x58, 0x42, 0x9e, 0xc9, 0x60, 0x31, 0xdb, 0xca, 0xd3, 0xda, 0xd9, 0xaf, 0x0d, 0xcb, 0xaa, 0xaf, 0x26, 0x8c, 0xb8, 0xfc, 0xff, 0xea, 0xd9, 0x4f, 0x3c, 0x7c, 0xa4, 0x95, 0xe0, 0x56, 0xa9, 0xb4, 0x7a, 0xcd, 0xb7, 0x51, 0xfb, 0x73, 0xe6, 0x66, 0xc6, 0xc6, 0x55, 0xad, 0xe8, 0x29, 0x72, 0x97, 0xd0, 0x7a, 0xd1, 0xba, 0x5e, 0x43, 0xf1, 0xbc, 0xa3, 0x23, 0x01, 0x65, 0x13, 0x39, 0xe2, 0x29, 0x04, 0xcc, 0x8c, 0x42, 0xf5, 0x8c, 0x30, 0xc0, 0x4a, 0xaf, 0xdb, 0x03, 0x8d, 0xda, 0x08, 0x47, 0xdd, 0x98, 0x8d, 0xcd, 0xa6, 0xf3, 0xbf, 0xd1, 0x5c, 0x4b, 0x4c, 0x45, 0x25, 0x00, 0x4a, 0xa0, 0x6e, 0xef, 0xf8, 0xca, 0x61, 0x78, 0x3a, 0xac, 0xec, 0x57, 0xfb, 0x3d, 0x1f, 0x92, 0xb0, 0xfe, 0x2f, 0xd1, 0xa8, 0x5f, 0x67, 0x24, 0x51, 0x7b, 0x65, 0xe6, 0x14, 0xad, 0x68, 0x08, 0xd6, 0xf6, 0xee, 0x34, 0xdf, 0xf7, 0x31, 0x0f, 0xdc, 0x82, 0xae, 0xbf, 0xd9, 0x04, 0xb0, 0x1e, 0x1d, 0xc5, 0x4b, 0x29, 0x27, 0x09, 0x4b, 0x2d, 0xb6, 0x8d, 0x6f, 0x90, 0x3b, 0x68, 0x40, 0x1a, 0xde, 0xbf, 0x5a, 0x7e, 0x08, 0xd7, 0x8f, 0xf4, 0xef, 0x5d, 0x63, 0x65, 0x3a, 0x65, 0x04, 0x0c, 0xf9, 0xbf, 0xd4, 0xac, 0xa7, 0x98, 0x4a, 0x74, 0xd3, 0x71, 0x45, 0x98, 0x67, 0x80, 0xfc, 0x0b, 0x16, 0xac, 0x45, 0x16, 0x49, 0xde, 0x61, 0x88, 0xa7, 0xdb, 0xdf, 0x19, 0x1f, 0x64, 0xb5, 0xfc, 0x5e, 0x2a, 0xb4, 0x7b, 0x57, 0xf7, 0xf7, 0x27, 0x6c, 0xd4, 0x19, 0xc1, 0x7a, 0x3c, 0xa8, 0xe1, 0xb9, 0x39, 0xae, 0x49, 0xe4, 0x88, 0xac, 0xba, 0x6b, 0x96, 0x56, 0x10, 0xb5, 0x48, 0x01, 0x09, 0xc8, 0xb1, 0x7b, 0x80, 0xe1, 0xb7, 0xb7, 0x50, 0xdf, 0xc7, 0x59, 0x8d, 0x5d, 0x50, 0x11, 0xfd, 0x2d, 0xcc, 0x56, 0x00, 0xa3, 0x2e, 0xf5, 0xb5, 0x2a, 0x1e, 0xcc, 0x82, 0x0e, 0x30, 0x8a, 0xa3, 0x42, 0x72, 0x1a, 0xac, 0x09, 0x43, 0xbf, 0x66, 0x86, 0xb6, 0x4b, 0x25, 0x79, 0x37, 0x65, 0x04, 0xcc, 0xc4, 0x93, 0xd9, 0x7e, 0x6a, 0xed, 0x3f, 0xb0, 0xf9, 0xcd, 0x71, 0xa4, 0x3d, 0xd4, 0x97, 0xf0, 0x1f, 0x17, 0xc0, 0xe2, 0xcb, 0x37, 0x97, 0xaa, 0x2a, 0x2f, 0x25, 0x66, 0x56, 0x16, 0x8e, 0x6c, 0x49, 0x6a, 0xfc, 0x5f, 0xb9, 0x32, 0x46, 0xf6, 0xb1, 0x11, 0x63, 0x98, 0xa3, 0x46, 0xf1, 0xa6, 0x41, 0xf3, 0xb0, 0x41, 0xe9, 0x89, 0xf7, 0x91, 0x4f, 0x90, 0xcc, 0x2c, 0x7f, 0xff, 0x35, 0x78, 0x76, 0xe5, 0x06, 0xb5, 0x0d, 0x33, 0x4b, 0xa7, 0x7c, 0x22, 0x5b, 0xc3, 0x07, 0xba, 0x53, 0x71, 0x52, 0xf3, 0xf1, 0x61, 0x0e, 0x4e, 0xaf, 0xe5, 0x95, 0xf6, 0xd9, 0xd9, 0x0d, 0x11, 0xfa, 0xa9, 0x33, 0xa1, 0x5e, 0xf1, 0x36, 0x95, 0x46, 0x86, 0x8a, 0x7f, 0x3a, 0x45, 0xa9, 0x67, 0x68, 0xd4, 0x0f, 0xd9, 0xd0, 0x34, 0x12, 0xc0, 0x91, 0xc6, 0x31, 0x5c, 0xf4, 0xfd, 0xe7, 0xcb, 0x68, 0x60, 0x69, 0x37, 0x38, 0x0d, 0xb2, 0xea, 0xaa, 0x70, 0x7b, 0x4c, 0x41, 0x85, 0xc3, 0x2e, 0xdd, 0xcd, 0xd3, 0x06, 0x70, 0x5e, 0x4d, 0xc1, 0xff, 0xc8, 0x72, 0xee, 0xee, 0x47, 0x5a, 0x64, 0xdf, 0xac, 0x86, 0xab, 0xa4, 0x1c, 0x06, 0x18, 0x98, 0x3f, 0x87, 0x41, 0xc5, 0xef, 0x68, 0xd3, 0xa1, 0x01, 0xe8, 0xa3, 0xb8, 0xca, 0xc6, 0x0c, 0x90, 0x5c, 0x15, 0xfc, 0x91, 0x08, 0x40, 0xb9, 0x4c, 0x00, 0xa0, 0xb9, 0xd0}, .msg_len = 1023, .mech_param = FALSE, .ctx_len = 0, .prehash = FALSE, .signature = {0x0a, 0xab, 0x4c, 0x90, 0x05, 0x01, 0xb3, 0xe2, 0x4d, 0x7c, 0xdf, 0x46, 0x63, 0x32, 0x6a, 0x3a, 0x87, 0xdf, 0x5e, 0x48, 0x43, 0xb2, 0xcb, 0xdb, 0x67, 0xcb, 0xf6, 0xe4, 0x60, 0xfe, 0xc3, 0x50, 0xaa, 0x53, 0x71, 0xb1, 0x50, 0x8f, 0x9f, 0x45, 0x28, 0xec, 0xea, 0x23, 0xc4, 0x36, 0xd9, 0x4b, 0x5e, 0x8f, 0xcd, 0x4f, 0x68, 0x1e, 0x30, 0xa6, 0xac, 0x00, 0xa9, 0x70, 0x4a, 0x18, 0x8a, 0x03}, .signature_len = 64, }, { // #4 [Ed25519] .name = "Ed25519", .curve_type = CURVE_EDWARDS, .params = {0x06, 0x03, 0x2B, 0x65, 0x70}, .params_len = 5, .privkey = {0x83, 0x3f, 0xe6, 0x24, 0x09, 0x23, 0x7b, 0x9d, 0x62, 0xec, 0x77, 0x58, 0x75, 0x20, 0x91, 0x1e, 0x9a, 0x75, 0x9c, 0xec, 0x1d, 0x19, 0x75, 0x5b, 0x7d, 0xa9, 0x01, 0xb9, 0x6d, 0xca, 0x3d, 0x42}, .privkey_len = 32, .pubkey = {0xec, 0x17, 0x2b, 0x93, 0xad, 0x5e, 0x56, 0x3b, 0xf4, 0x93, 0x2c, 0x70, 0xe1, 0x24, 0x50, 0x34, 0xc3, 0x54, 0x67, 0xef, 0x2e, 0xfd, 0x4d, 0x64, 0xeb, 0xf8, 0x19, 0x68, 0x34, 0x67, 0xe2, 0xbf}, .pubkey_len = 32, .msg = {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}, .msg_len = 64, .mech_param = FALSE, .ctx_len = 0, .prehash = FALSE, .signature = {0xdc, 0x2a, 0x44, 0x59, 0xe7, 0x36, 0x96, 0x33, 0xa5, 0x2b, 0x1b, 0xf2, 0x77, 0x83, 0x9a, 0x00, 0x20, 0x10, 0x09, 0xa3, 0xef, 0xbf, 0x3e, 0xcb, 0x69, 0xbe, 0xa2, 0x18, 0x6c, 0x26, 0xb5, 0x89, 0x09, 0x35, 0x1f, 0xc9, 0xac, 0x90, 0xb3, 0xec, 0xfd, 0xfb, 0xc7, 0xc6, 0x64, 0x31, 0xe0, 0x30, 0x3d, 0xca, 0x17, 0x9c, 0x13, 0x8a, 0xc1, 0x7a, 0xd9, 0xbe, 0xf1, 0x17, 0x73, 0x31, 0xa7, 0x04}, .signature_len = 64, }, { // #5 [Ed25519ctx] .name = "Ed25519ctx", .curve_type = CURVE_EDWARDS, .params = {0x06, 0x03, 0x2B, 0x65, 0x70}, .params_len = 5, .privkey = {0x03, 0x05, 0x33, 0x4e, 0x38, 0x1a, 0xf7, 0x8f, 0x14, 0x1c, 0xb6, 0x66, 0xf6, 0x19, 0x9f, 0x57, 0xbc, 0x34, 0x95, 0x33, 0x5a, 0x25, 0x6a, 0x95, 0xbd, 0x2a, 0x55, 0xbf, 0x54, 0x66, 0x63, 0xf6}, .privkey_len = 32, .pubkey = {0xdf, 0xc9, 0x42, 0x5e, 0x4f, 0x96, 0x8f, 0x7f, 0x0c, 0x29, 0xf0, 0x25, 0x9c, 0xf5, 0xf9, 0xae, 0xd6, 0x85, 0x1c, 0x2b, 0xb4, 0xad, 0x8b, 0xfb, 0x86, 0x0c, 0xfe, 0xe0, 0xab, 0x24, 0x82, 0x92}, .pubkey_len = 32, .msg = {0xf7, 0x26, 0x93, 0x6d, 0x19, 0xc8, 0x00, 0x49, 0x4e, 0x3f, 0xda, 0xff, 0x20, 0xb2, 0x76, 0xa8}, .msg_len = 16, .mech_param = TRUE, .ctx = {0x66, 0x6f, 0x6f}, .ctx_len = 3, .prehash = FALSE, .signature = {0x55, 0xa4, 0xcc, 0x2f, 0x70, 0xa5, 0x4e, 0x04, 0x28, 0x8c, 0x5f, 0x4c, 0xd1, 0xe4, 0x5a, 0x7b, 0xb5, 0x20, 0xb3, 0x62, 0x92, 0x91, 0x18, 0x76, 0xca, 0xda, 0x73, 0x23, 0x19, 0x8d, 0xd8, 0x7a, 0x8b, 0x36, 0x95, 0x0b, 0x95, 0x13, 0x00, 0x22, 0x90, 0x7a, 0x7f, 0xb7, 0xc4, 0xe9, 0xb2, 0xd5, 0xf6, 0xcc, 0xa6, 0x85, 0xa5, 0x87, 0xb4, 0xb2, 0x1f, 0x4b, 0x88, 0x8e, 0x4e, 0x7e, 0xdb, 0x0d}, .signature_len = 64, }, { // #6 [Ed25519ctx] .name = "Ed25519ctx", .curve_type = CURVE_EDWARDS, .params = {0x06, 0x03, 0x2B, 0x65, 0x70}, .params_len = 5, .privkey = {0x03, 0x05, 0x33, 0x4e, 0x38, 0x1a, 0xf7, 0x8f, 0x14, 0x1c, 0xb6, 0x66, 0xf6, 0x19, 0x9f, 0x57, 0xbc, 0x34, 0x95, 0x33, 0x5a, 0x25, 0x6a, 0x95, 0xbd, 0x2a, 0x55, 0xbf, 0x54, 0x66, 0x63, 0xf6}, .privkey_len = 32, .pubkey = {0xdf, 0xc9, 0x42, 0x5e, 0x4f, 0x96, 0x8f, 0x7f, 0x0c, 0x29, 0xf0, 0x25, 0x9c, 0xf5, 0xf9, 0xae, 0xd6, 0x85, 0x1c, 0x2b, 0xb4, 0xad, 0x8b, 0xfb, 0x86, 0x0c, 0xfe, 0xe0, 0xab, 0x24, 0x82, 0x92}, .pubkey_len = 32, .msg = {0xf7, 0x26, 0x93, 0x6d, 0x19, 0xc8, 0x00, 0x49, 0x4e, 0x3f, 0xda, 0xff, 0x20, 0xb2, 0x76, 0xa8}, .msg_len = 16, .mech_param = TRUE, .ctx = {0x62, 0x61, 0x72}, .ctx_len = 3, .prehash = FALSE, .signature = {0xfc, 0x60, 0xd5, 0x87, 0x2f, 0xc4, 0x6b, 0x3a, 0xa6, 0x9f, 0x8b, 0x5b, 0x43, 0x51, 0xd5, 0x80, 0x8f, 0x92, 0xbc, 0xc0, 0x44, 0x60, 0x6d, 0xb0, 0x97, 0xab, 0xab, 0x6d, 0xbc, 0xb1, 0xae, 0xe3, 0x21, 0x6c, 0x48, 0xe8, 0xb3, 0xb6, 0x64, 0x31, 0xb5, 0xb1, 0x86, 0xd1, 0xd2, 0x8f, 0x8e, 0xe1, 0x5a, 0x5c, 0xa2, 0xdf, 0x66, 0x68, 0x34, 0x62, 0x91, 0xc2, 0x04, 0x3d, 0x4e, 0xb3, 0xe9, 0x0d}, .signature_len = 64, }, { // #7 [Ed25519ctx] .name = "Ed25519ctx", .curve_type = CURVE_EDWARDS, .params = {0x06, 0x03, 0x2B, 0x65, 0x70}, .params_len = 5, .privkey = {0x03, 0x05, 0x33, 0x4e, 0x38, 0x1a, 0xf7, 0x8f, 0x14, 0x1c, 0xb6, 0x66, 0xf6, 0x19, 0x9f, 0x57, 0xbc, 0x34, 0x95, 0x33, 0x5a, 0x25, 0x6a, 0x95, 0xbd, 0x2a, 0x55, 0xbf, 0x54, 0x66, 0x63, 0xf6}, .privkey_len = 32, .pubkey = {0xdf, 0xc9, 0x42, 0x5e, 0x4f, 0x96, 0x8f, 0x7f, 0x0c, 0x29, 0xf0, 0x25, 0x9c, 0xf5, 0xf9, 0xae, 0xd6, 0x85, 0x1c, 0x2b, 0xb4, 0xad, 0x8b, 0xfb, 0x86, 0x0c, 0xfe, 0xe0, 0xab, 0x24, 0x82, 0x92}, .pubkey_len = 32, .msg = {0x50, 0x8e, 0x9e, 0x68, 0x82, 0xb9, 0x79, 0xfe, 0xa9, 0x00, 0xf6, 0x2a, 0xdc, 0xea, 0xca, 0x35}, .msg_len = 16, .mech_param = TRUE, .ctx = {0x66, 0x6f, 0x6f}, .ctx_len = 3, .prehash = FALSE, .signature = {0x8b, 0x70, 0xc1, 0xcc, 0x83, 0x10, 0xe1, 0xde, 0x20, 0xac, 0x53, 0xce, 0x28, 0xae, 0x6e, 0x72, 0x07, 0xf3, 0x3c, 0x32, 0x95, 0xe0, 0x3b, 0xb5, 0xc0, 0x73, 0x2a, 0x1d, 0x20, 0xdc, 0x64, 0x90, 0x89, 0x22, 0xa8, 0xb0, 0x52, 0xcf, 0x99, 0xb7, 0xc4, 0xfe, 0x10, 0x7a, 0x5a, 0xbb, 0x5b, 0x2c, 0x40, 0x85, 0xae, 0x75, 0x89, 0x0d, 0x02, 0xdf, 0x26, 0x26, 0x9d, 0x89, 0x45, 0xf8, 0x4b, 0x0b}, .signature_len = 64, }, { // #8 [Ed25519ctx] .name = "Ed25519ctx", .curve_type = CURVE_EDWARDS, .params = {0x06, 0x03, 0x2B, 0x65, 0x70}, .params_len = 5, .privkey = {0xab, 0x9c, 0x28, 0x53, 0xce, 0x29, 0x7d, 0xda, 0xb8, 0x5c, 0x99, 0x3b, 0x3a, 0xe1, 0x4b, 0xca, 0xd3, 0x9b, 0x2c, 0x68, 0x2b, 0xea, 0xbc, 0x27, 0xd6, 0xd4, 0xeb, 0x20, 0x71, 0x1d, 0x65, 0x60}, .privkey_len = 32, .pubkey = {0x0f, 0x1d, 0x12, 0x74, 0x94, 0x3b, 0x91, 0x41, 0x58, 0x89, 0x15, 0x2e, 0x89, 0x3d, 0x80, 0xe9, 0x32, 0x75, 0xa1, 0xfc, 0x0b, 0x65, 0xfd, 0x71, 0xb4, 0xb0, 0xdd, 0xa1, 0x0a, 0xd7, 0xd7, 0x72}, .pubkey_len = 32, .msg = {0xf7, 0x26, 0x93, 0x6d, 0x19, 0xc8, 0x00, 0x49, 0x4e, 0x3f, 0xda, 0xff, 0x20, 0xb2, 0x76, 0xa8}, .msg_len = 16, .mech_param = TRUE, .ctx = {0x66, 0x6f, 0x6f}, .ctx_len = 3, .prehash = FALSE, .signature = {0x21, 0x65, 0x5b, 0x5f, 0x1a, 0xa9, 0x65, 0x99, 0x6b, 0x3f, 0x97, 0xb3, 0xc8, 0x49, 0xea, 0xfb, 0xa9, 0x22, 0xa0, 0xa6, 0x29, 0x92, 0xf7, 0x3b, 0x3d, 0x1b, 0x73, 0x10, 0x6a, 0x84, 0xad, 0x85, 0xe9, 0xb8, 0x6a, 0x7b, 0x60, 0x05, 0xea, 0x86, 0x83, 0x37, 0xff, 0x2d, 0x20, 0xa7, 0xf5, 0xfb, 0xd4, 0xcd, 0x10, 0xb0, 0xbe, 0x49, 0xa6, 0x8d, 0xa2, 0xb2, 0xe0, 0xdc, 0x0a, 0xd8, 0x96, 0x0f}, .signature_len = 64, }, { // #9 [Ed25519ph] .name = "Ed25519ph", .curve_type = CURVE_EDWARDS, .params = {0x06, 0x03, 0x2B, 0x65, 0x70}, .params_len = 5, .privkey = {0x83, 0x3f, 0xe6, 0x24, 0x09, 0x23, 0x7b, 0x9d, 0x62, 0xec, 0x77, 0x58, 0x75, 0x20, 0x91, 0x1e, 0x9a, 0x75, 0x9c, 0xec, 0x1d, 0x19, 0x75, 0x5b, 0x7d, 0xa9, 0x01, 0xb9, 0x6d, 0xca, 0x3d, 0x42}, .privkey_len = 32, .pubkey = {0xec, 0x17, 0x2b, 0x93, 0xad, 0x5e, 0x56, 0x3b, 0xf4, 0x93, 0x2c, 0x70, 0xe1, 0x24, 0x50, 0x34, 0xc3, 0x54, 0x67, 0xef, 0x2e, 0xfd, 0x4d, 0x64, 0xeb, 0xf8, 0x19, 0x68, 0x34, 0x67, 0xe2, 0xbf}, .pubkey_len = 32, .msg = {0x61, 0x62, 0x63}, .msg_len = 3, .mech_param = TRUE, .ctx_len = 0, .prehash = TRUE, .signature = {0x98, 0xa7, 0x02, 0x22, 0xf0, 0xb8, 0x12, 0x1a, 0xa9, 0xd3, 0x0f, 0x81, 0x3d, 0x68, 0x3f, 0x80, 0x9e, 0x46, 0x2b, 0x46, 0x9c, 0x7f, 0xf8, 0x76, 0x39, 0x49, 0x9b, 0xb9, 0x4e, 0x6d, 0xae, 0x41, 0x31, 0xf8, 0x50, 0x42, 0x46, 0x3c, 0x2a, 0x35, 0x5a, 0x20, 0x03, 0xd0, 0x62, 0xad, 0xf5, 0xaa, 0xa1, 0x0b, 0x8c, 0x61, 0xe6, 0x36, 0x06, 0x2a, 0xaa, 0xd1, 0x1c, 0x2a, 0x26, 0x08, 0x34, 0x06}, .signature_len = 64, }, { // #10 [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 = {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 = 57, .msg_len = 0, .mech_param = TRUE, .ctx_len = 0, .prehash = FALSE, .signature = {0x53, 0x3a, 0x37, 0xf6, 0xbb, 0xe4, 0x57, 0x25, 0x1f, 0x02, 0x3c, 0x0d, 0x88, 0xf9, 0x76, 0xae, 0x2d, 0xfb, 0x50, 0x4a, 0x84, 0x3e, 0x34, 0xd2, 0x07, 0x4f, 0xd8, 0x23, 0xd4, 0x1a, 0x59, 0x1f, 0x2b, 0x23, 0x3f, 0x03, 0x4f, 0x62, 0x82, 0x81, 0xf2, 0xfd, 0x7a, 0x22, 0xdd, 0xd4, 0x7d, 0x78, 0x28, 0xc5, 0x9b, 0xd0, 0xa2, 0x1b, 0xfd, 0x39, 0x80, 0xff, 0x0d, 0x20, 0x28, 0xd4, 0xb1, 0x8a, 0x9d, 0xf6, 0x3e, 0x00, 0x6c, 0x5d, 0x1c, 0x2d, 0x34, 0x5b, 0x92, 0x5d, 0x8d, 0xc0, 0x0b, 0x41, 0x04, 0x85, 0x2d, 0xb9, 0x9a, 0xc5, 0xc7, 0xcd, 0xda, 0x85, 0x30, 0xa1, 0x13, 0xa0, 0xf4, 0xdb, 0xb6, 0x11, 0x49, 0xf0, 0x5a, 0x73, 0x63, 0x26, 0x8c, 0x71, 0xd9, 0x58, 0x08, 0xff, 0x2e, 0x65, 0x26, 0x00}, .signature_len = 114, }, { // #11 [Ed448] .name = "Ed448", .curve_type = CURVE_EDWARDS, .params = {0x06, 0x03, 0x2B, 0x65, 0x71}, .params_len = 5, .privkey = {0xc4, 0xea, 0xb0, 0x5d, 0x35, 0x70, 0x07, 0xc6, 0x32, 0xf3, 0xdb, 0xb4, 0x84, 0x89, 0x92, 0x4d, 0x55, 0x2b, 0x08, 0xfe, 0x0c, 0x35, 0x3a, 0x0d, 0x4a, 0x1f, 0x00, 0xac, 0xda, 0x2c, 0x46, 0x3a, 0xfb, 0xea, 0x67, 0xc5, 0xe8, 0xd2, 0x87, 0x7c, 0x5e, 0x3b, 0xc3, 0x97, 0xa6, 0x59, 0x94, 0x9e, 0xf8, 0x02, 0x1e, 0x95, 0x4e, 0x0a, 0x12, 0x27, 0x4e}, .privkey_len = 57, .pubkey = { 0x43, 0xba, 0x28, 0xf4, 0x30, 0xcd, 0xff, 0x45, 0x6a, 0xe5, 0x31, 0x54, 0x5f, 0x7e, 0xcd, 0x0a, 0xc8, 0x34, 0xa5, 0x5d, 0x93, 0x58, 0xc0, 0x37, 0x2b, 0xfa, 0x0c, 0x6c, 0x67, 0x98, 0xc0, 0x86, 0x6a, 0xea, 0x01, 0xeb, 0x00, 0x74, 0x28, 0x02, 0xb8, 0x43, 0x8e, 0xa4, 0xcb, 0x82, 0x16, 0x9c, 0x23, 0x51, 0x60, 0x62, 0x7b, 0x4c, 0x3a, 0x94, 0x80}, .pubkey_len = 57, .msg = {0x03}, .msg_len = 1, .mech_param = TRUE, .ctx_len = 0, .prehash = FALSE, .signature = {0x26, 0xb8, 0xf9, 0x17, 0x27, 0xbd, 0x62, 0x89, 0x7a, 0xf1, 0x5e, 0x41, 0xeb, 0x43, 0xc3, 0x77, 0xef, 0xb9, 0xc6, 0x10, 0xd4, 0x8f, 0x23, 0x35, 0xcb, 0x0b, 0xd0, 0x08, 0x78, 0x10, 0xf4, 0x35, 0x25, 0x41, 0xb1, 0x43, 0xc4, 0xb9, 0x81, 0xb7, 0xe1, 0x8f, 0x62, 0xde, 0x8c, 0xcd, 0xf6, 0x33, 0xfc, 0x1b, 0xf0, 0x37, 0xab, 0x7c, 0xd7, 0x79, 0x80, 0x5e, 0x0d, 0xbc, 0xc0, 0xaa, 0xe1, 0xcb, 0xce, 0xe1, 0xaf, 0xb2, 0xe0, 0x27, 0xdf, 0x36, 0xbc, 0x04, 0xdc, 0xec, 0xbf, 0x15, 0x43, 0x36, 0xc1, 0x9f, 0x0a, 0xf7, 0xe0, 0xa6, 0x47, 0x29, 0x05, 0xe7, 0x99, 0xf1, 0x95, 0x3d, 0x2a, 0x0f, 0xf3, 0x34, 0x8a, 0xb2, 0x1a, 0xa4, 0xad, 0xaf, 0xd1, 0xd2, 0x34, 0x44, 0x1c, 0xf8, 0x07, 0xc0, 0x3a, 0x00}, .signature_len = 114, }, { // #12 [Ed448] .name = "Ed448", .curve_type = CURVE_EDWARDS, .params = {0x06, 0x03, 0x2B, 0x65, 0x71}, .params_len = 5, .privkey = {0xc4, 0xea, 0xb0, 0x5d, 0x35, 0x70, 0x07, 0xc6, 0x32, 0xf3, 0xdb, 0xb4, 0x84, 0x89, 0x92, 0x4d, 0x55, 0x2b, 0x08, 0xfe, 0x0c, 0x35, 0x3a, 0x0d, 0x4a, 0x1f, 0x00, 0xac, 0xda, 0x2c, 0x46, 0x3a, 0xfb, 0xea, 0x67, 0xc5, 0xe8, 0xd2, 0x87, 0x7c, 0x5e, 0x3b, 0xc3, 0x97, 0xa6, 0x59, 0x94, 0x9e, 0xf8, 0x02, 0x1e, 0x95, 0x4e, 0x0a, 0x12, 0x27, 0x4e}, .privkey_len = 57, .pubkey = { 0x43, 0xba, 0x28, 0xf4, 0x30, 0xcd, 0xff, 0x45, 0x6a, 0xe5, 0x31, 0x54, 0x5f, 0x7e, 0xcd, 0x0a, 0xc8, 0x34, 0xa5, 0x5d, 0x93, 0x58, 0xc0, 0x37, 0x2b, 0xfa, 0x0c, 0x6c, 0x67, 0x98, 0xc0, 0x86, 0x6a, 0xea, 0x01, 0xeb, 0x00, 0x74, 0x28, 0x02, 0xb8, 0x43, 0x8e, 0xa4, 0xcb, 0x82, 0x16, 0x9c, 0x23, 0x51, 0x60, 0x62, 0x7b, 0x4c, 0x3a, 0x94, 0x80}, .pubkey_len = 57, .msg = {0x03}, .msg_len = 1, .mech_param = TRUE, .ctx = {0x66, 0x6f, 0x6f}, .ctx_len = 3, .prehash = FALSE, .signature = {0xd4, 0xf8, 0xf6, 0x13, 0x17, 0x70, 0xdd, 0x46, 0xf4, 0x08, 0x67, 0xd6, 0xfd, 0x5d, 0x50, 0x55, 0xde, 0x43, 0x54, 0x1f, 0x8c, 0x5e, 0x35, 0xab, 0xbc, 0xd0, 0x01, 0xb3, 0x2a, 0x89, 0xf7, 0xd2, 0x15, 0x1f, 0x76, 0x47, 0xf1, 0x1d, 0x8c, 0xa2, 0xae, 0x27, 0x9f, 0xb8, 0x42, 0xd6, 0x07, 0x21, 0x7f, 0xce, 0x6e, 0x04, 0x2f, 0x68, 0x15, 0xea, 0x00, 0x0c, 0x85, 0x74, 0x1d, 0xe5, 0xc8, 0xda, 0x11, 0x44, 0xa6, 0xa1, 0xab, 0xa7, 0xf9, 0x6d, 0xe4, 0x25, 0x05, 0xd7, 0xa7, 0x29, 0x85, 0x24, 0xfd, 0xa5, 0x38, 0xfc, 0xcb, 0xbb, 0x75, 0x4f, 0x57, 0x8c, 0x1c, 0xad, 0x10, 0xd5, 0x4d, 0x0d, 0x54, 0x28, 0x40, 0x7e, 0x85, 0xdc, 0xbc, 0x98, 0xa4, 0x91, 0x55, 0xc1, 0x37, 0x64, 0xe6, 0x6c, 0x3c, 0x00}, .signature_len = 114, }, { // #13 [Ed448] .name = "Ed448", .curve_type = CURVE_EDWARDS, .params = {0x06, 0x03, 0x2B, 0x65, 0x71}, .params_len = 5, .privkey = {0xcd, 0x23, 0xd2, 0x4f, 0x71, 0x42, 0x74, 0xe7, 0x44, 0x34, 0x32, 0x37, 0xb9, 0x32, 0x90, 0xf5, 0x11, 0xf6, 0x42, 0x5f, 0x98, 0xe6, 0x44, 0x59, 0xff, 0x20, 0x3e, 0x89, 0x85, 0x08, 0x3f, 0xfd, 0xf6, 0x05, 0x00, 0x55, 0x3a, 0xbc, 0x0e, 0x05, 0xcd, 0x02, 0x18, 0x4b, 0xdb, 0x89, 0xc4, 0xcc, 0xd6, 0x7e, 0x18, 0x79, 0x51, 0x26, 0x7e, 0xb3, 0x28}, .privkey_len = 57, .pubkey = { 0xdc, 0xea, 0x9e, 0x78, 0xf3, 0x5a, 0x1b, 0xf3, 0x49, 0x9a, 0x83, 0x1b, 0x10, 0xb8, 0x6c, 0x90, 0xaa, 0xc0, 0x1c, 0xd8, 0x4b, 0x67, 0xa0, 0x10, 0x9b, 0x55, 0xa3, 0x6e, 0x93, 0x28, 0xb1, 0xe3, 0x65, 0xfc, 0xe1, 0x61, 0xd7, 0x1c, 0xe7, 0x13, 0x1a, 0x54, 0x3e, 0xa4, 0xcb, 0x5f, 0x7e, 0x9f, 0x1d, 0x8b, 0x00, 0x69, 0x64, 0x47, 0x00, 0x14, 0x00}, .pubkey_len = 57, .msg = {0x0c, 0x3e, 0x54, 0x40, 0x74, 0xec, 0x63, 0xb0, 0x26, 0x5e, 0x0c}, .msg_len = 11, .mech_param = TRUE, .ctx_len = 0, .prehash = FALSE, .signature = {0x1f, 0x0a, 0x88, 0x88, 0xce, 0x25, 0xe8, 0xd4, 0x58, 0xa2, 0x11, 0x30, 0x87, 0x9b, 0x84, 0x0a, 0x90, 0x89, 0xd9, 0x99, 0xaa, 0xba, 0x03, 0x9e, 0xaf, 0x3e, 0x3a, 0xfa, 0x09, 0x0a, 0x09, 0xd3, 0x89, 0xdb, 0xa8, 0x2c, 0x4f, 0xf2, 0xae, 0x8a, 0xc5, 0xcd, 0xfb, 0x7c, 0x55, 0xe9, 0x4d, 0x5d, 0x96, 0x1a, 0x29, 0xfe, 0x01, 0x09, 0x94, 0x1e, 0x00, 0xb8, 0xdb, 0xde, 0xea, 0x6d, 0x3b, 0x05, 0x10, 0x68, 0xdf, 0x72, 0x54, 0xc0, 0xcd, 0xc1, 0x29, 0xcb, 0xe6, 0x2d, 0xb2, 0xdc, 0x95, 0x7d, 0xbb, 0x47, 0xb5, 0x1f, 0xd3, 0xf2, 0x13, 0xfb, 0x86, 0x98, 0xf0, 0x64, 0x77, 0x42, 0x50, 0xa5, 0x02, 0x89, 0x61, 0xc9, 0xbf, 0x8f, 0xfd, 0x97, 0x3f, 0xe5, 0xd5, 0xc2, 0x06, 0x49, 0x2b, 0x14, 0x0e, 0x00}, .signature_len = 114, }, { // #14 [Ed448] .name = "Ed448", .curve_type = CURVE_EDWARDS, .params = {0x06, 0x03, 0x2B, 0x65, 0x71}, .params_len = 5, .privkey = {0x87, 0x2d, 0x09, 0x37, 0x80, 0xf5, 0xd3, 0x73, 0x0d, 0xf7, 0xc2, 0x12, 0x66, 0x4b, 0x37, 0xb8, 0xa0, 0xf2, 0x4f, 0x56, 0x81, 0x0d, 0xaa, 0x83, 0x82, 0xcd, 0x4f, 0xa3, 0xf7, 0x76, 0x34, 0xec, 0x44, 0xdc, 0x54, 0xf1, 0xc2, 0xed, 0x9b, 0xea, 0x86, 0xfa, 0xfb, 0x76, 0x32, 0xd8, 0xbe, 0x19, 0x9e, 0xa1, 0x65, 0xf5, 0xad, 0x55, 0xdd, 0x9c, 0xe8}, .privkey_len = 57, .pubkey = { 0xa8, 0x1b, 0x2e, 0x8a, 0x70, 0xa5, 0xac, 0x94, 0xff, 0xdb, 0xcc, 0x9b, 0xad, 0xfc, 0x3f, 0xeb, 0x08, 0x01, 0xf2, 0x58, 0x57, 0x8b, 0xb1, 0x14, 0xad, 0x44, 0xec, 0xe1, 0xec, 0x0e, 0x79, 0x9d, 0xa0, 0x8e, 0xff, 0xb8, 0x1c, 0x5d, 0x68, 0x5c, 0x0c, 0x56, 0xf6, 0x4e, 0xec, 0xae, 0xf8, 0xcd, 0xf1, 0x1c, 0xc3, 0x87, 0x37, 0x83, 0x8c, 0xf4, 0x00}, .pubkey_len = 57, .msg = {0x6d, 0xdf, 0x80, 0x2e, 0x1a, 0xae, 0x49, 0x86, 0x93, 0x5f, 0x7f, 0x98, 0x1b, 0xa3, 0xf0, 0x35, 0x1d, 0x62, 0x73, 0xc0, 0xa0, 0xc2, 0x2c, 0x9c, 0x0e, 0x83, 0x39, 0x16, 0x8e, 0x67, 0x54, 0x12, 0xa3, 0xde, 0xbf, 0xaf, 0x43, 0x5e, 0xd6, 0x51, 0x55, 0x80, 0x07, 0xdb, 0x43, 0x84, 0xb6, 0x50, 0xfc, 0xc0, 0x7e, 0x3b, 0x58, 0x6a, 0x27, 0xa4, 0xf7, 0xa0, 0x0a, 0xc8, 0xa6, 0xfe, 0xc2, 0xcd, 0x86, 0xae, 0x4b, 0xf1, 0x57, 0x0c, 0x41, 0xe6, 0xa4, 0x0c, 0x93, 0x1d, 0xb2, 0x7b, 0x2f, 0xaa, 0x15, 0xa8, 0xce, 0xdd, 0x52, 0xcf, 0xf7, 0x36, 0x2c, 0x4e, 0x6e, 0x23, 0xda, 0xec, 0x0f, 0xbc, 0x3a, 0x79, 0xb6, 0x80, 0x6e, 0x31, 0x6e, 0xfc, 0xc7, 0xb6, 0x81, 0x19, 0xbf, 0x46, 0xbc, 0x76, 0xa2, 0x60, 0x67, 0xa5, 0x3f, 0x29, 0x6d, 0xaf, 0xdb, 0xdc, 0x11, 0xc7, 0x7f, 0x77, 0x77, 0xe9, 0x72, 0x66, 0x0c, 0xf4, 0xb6, 0xa9, 0xb3, 0x69, 0xa6, 0x66, 0x5f, 0x02, 0xe0, 0xcc, 0x9b, 0x6e, 0xdf, 0xad, 0x13, 0x6b, 0x4f, 0xab, 0xe7, 0x23, 0xd2, 0x81, 0x3d, 0xb3, 0x13, 0x6c, 0xfd, 0xe9, 0xb6, 0xd0, 0x44, 0x32, 0x2f, 0xee, 0x29, 0x47, 0x95, 0x2e, 0x03, 0x1b, 0x73, 0xab, 0x5c, 0x60, 0x33, 0x49, 0xb3, 0x07, 0xbd, 0xc2, 0x7b, 0xc6, 0xcb, 0x8b, 0x8b, 0xbd, 0x7b, 0xd3, 0x23, 0x21, 0x9b, 0x80, 0x33, 0xa5, 0x81, 0xb5, 0x9e, 0xad, 0xeb, 0xb0, 0x9b, 0x3c, 0x4f, 0x3d, 0x22, 0x77, 0xd4, 0xf0, 0x34, 0x36, 0x24, 0xac, 0xc8, 0x17, 0x80, 0x47, 0x28, 0xb2, 0x5a, 0xb7, 0x97, 0x17, 0x2b, 0x4c, 0x5c, 0x21, 0xa2, 0x2f, 0x9c, 0x78, 0x39, 0xd6, 0x43, 0x00, 0x23, 0x2e, 0xb6, 0x6e, 0x53, 0xf3, 0x1c, 0x72, 0x3f, 0xa3, 0x7f, 0xe3, 0x87, 0xc7, 0xd3, 0xe5, 0x0b, 0xdf, 0x98, 0x13, 0xa3, 0x0e, 0x5b, 0xb1, 0x2c, 0xf4, 0xcd, 0x93, 0x0c, 0x40, 0xcf, 0xb4, 0xe1, 0xfc, 0x62, 0x25, 0x92, 0xa4, 0x95, 0x88, 0x79, 0x44, 0x94, 0xd5, 0x6d, 0x24, 0xea, 0x4b, 0x40, 0xc8, 0x9f, 0xc0, 0x59, 0x6c, 0xc9, 0xeb, 0xb9, 0x61, 0xc8, 0xcb, 0x10, 0xad, 0xde, 0x97, 0x6a, 0x5d, 0x60, 0x2b, 0x1c, 0x3f, 0x85, 0xb9, 0xb9, 0xa0, 0x01, 0xed, 0x3c, 0x6a, 0x4d, 0x3b, 0x14, 0x37, 0xf5, 0x20, 0x96, 0xcd, 0x19, 0x56, 0xd0, 0x42, 0xa5, 0x97, 0xd5, 0x61, 0xa5, 0x96, 0xec, 0xd3, 0xd1, 0x73, 0x5a, 0x8d, 0x57, 0x0e, 0xa0, 0xec, 0x27, 0x22, 0x5a, 0x2c, 0x4a, 0xaf, 0xf2, 0x63, 0x06, 0xd1, 0x52, 0x6c, 0x1a, 0xf3, 0xca, 0x6d, 0x9c, 0xf5, 0xa2, 0xc9, 0x8f, 0x47, 0xe1, 0xc4, 0x6d, 0xb9, 0xa3, 0x32, 0x34, 0xcf, 0xd4, 0xd8, 0x1f, 0x2c, 0x98, 0x53, 0x8a, 0x09, 0xeb, 0xe7, 0x69, 0x98, 0xd0, 0xd8, 0xfd, 0x25, 0x99, 0x7c, 0x7d, 0x25, 0x5c, 0x6d, 0x66, 0xec, 0xe6, 0xfa, 0x56, 0xf1, 0x11, 0x44, 0x95, 0x0f, 0x02, 0x77, 0x95, 0xe6, 0x53, 0x00, 0x8f, 0x4b, 0xd7, 0xca, 0x2d, 0xee, 0x85, 0xd8, 0xe9, 0x0f, 0x3d, 0xc3, 0x15, 0x13, 0x0c, 0xe2, 0xa0, 0x03, 0x75, 0xa3, 0x18, 0xc7, 0xc3, 0xd9, 0x7b, 0xe2, 0xc8, 0xce, 0x5b, 0x6d, 0xb4, 0x1a, 0x62, 0x54, 0xff, 0x26, 0x4f, 0xa6, 0x15, 0x5b, 0xae, 0xe3, 0xb0, 0x77, 0x3c, 0x0f, 0x49, 0x7c, 0x57, 0x3f, 0x19, 0xbb, 0x4f, 0x42, 0x40, 0x28, 0x1f, 0x0b, 0x1f, 0x4f, 0x7b, 0xe8, 0x57, 0xa4, 0xe5, 0x9d, 0x41, 0x6c, 0x06, 0xb4, 0xc5, 0x0f, 0xa0, 0x9e, 0x18, 0x10, 0xdd, 0xc6, 0xb1, 0x46, 0x7b, 0xae, 0xac, 0x5a, 0x36, 0x68, 0xd1, 0x1b, 0x6e, 0xca, 0xa9, 0x01, 0x44, 0x00, 0x16, 0xf3, 0x89, 0xf8, 0x0a, 0xcc, 0x4d, 0xb9, 0x77, 0x02, 0x5e, 0x7f, 0x59, 0x24, 0x38, 0x8c, 0x7e, 0x34, 0x0a, 0x73, 0x2e, 0x55, 0x44, 0x40, 0xe7, 0x65, 0x70, 0xf8, 0xdd, 0x71, 0xb7, 0xd6, 0x40, 0xb3, 0x45, 0x0d, 0x1f, 0xd5, 0xf0, 0x41, 0x0a, 0x18, 0xf9, 0xa3, 0x49, 0x4f, 0x70, 0x7c, 0x71, 0x7b, 0x79, 0xb4, 0xbf, 0x75, 0xc9, 0x84, 0x00, 0xb0, 0x96, 0xb2, 0x16, 0x53, 0xb5, 0xd2, 0x17, 0xcf, 0x35, 0x65, 0xc9, 0x59, 0x74, 0x56, 0xf7, 0x07, 0x03, 0x49, 0x7a, 0x07, 0x87, 0x63, 0x82, 0x9b, 0xc0, 0x1b, 0xb1, 0xcb, 0xc8, 0xfa, 0x04, 0xea, 0xdc, 0x9a, 0x6e, 0x3f, 0x66, 0x99, 0x58, 0x7a, 0x9e, 0x75, 0xc9, 0x4e, 0x5b, 0xab, 0x00, 0x36, 0xe0, 0xb2, 0xe7, 0x11, 0x39, 0x2c, 0xff, 0x00, 0x47, 0xd0, 0xd6, 0xb0, 0x5b, 0xd2, 0xa5, 0x88, 0xbc, 0x10, 0x97, 0x18, 0x95, 0x42, 0x59, 0xf1, 0xd8, 0x66, 0x78, 0xa5, 0x79, 0xa3, 0x12, 0x0f, 0x19, 0xcf, 0xb2, 0x96, 0x3f, 0x17, 0x7a, 0xeb, 0x70, 0xf2, 0xd4, 0x84, 0x48, 0x26, 0x26, 0x2e, 0x51, 0xb8, 0x02, 0x71, 0x27, 0x20, 0x68, 0xef, 0x5b, 0x38, 0x56, 0xfa, 0x85, 0x35, 0xaa, 0x2a, 0x88, 0xb2, 0xd4, 0x1f, 0x2a, 0x0e, 0x2f, 0xda, 0x76, 0x24, 0xc2, 0x85, 0x02, 0x72, 0xac, 0x4a, 0x2f, 0x56, 0x1f, 0x8f, 0x2f, 0x7a, 0x31, 0x8b, 0xfd, 0x5c, 0xaf, 0x96, 0x96, 0x14, 0x9e, 0x4a, 0xc8, 0x24, 0xad, 0x34, 0x60, 0x53, 0x8f, 0xdc, 0x25, 0x42, 0x1b, 0xee, 0xc2, 0xcc, 0x68, 0x18, 0x16, 0x2d, 0x06, 0xbb, 0xed, 0x0c, 0x40, 0xa3, 0x87, 0x19, 0x23, 0x49, 0xdb, 0x67, 0xa1, 0x18, 0xba, 0xda, 0x6c, 0xd5, 0xab, 0x01, 0x40, 0xee, 0x27, 0x32, 0x04, 0xf6, 0x28, 0xaa, 0xd1, 0xc1, 0x35, 0xf7, 0x70, 0x27, 0x9a, 0x65, 0x1e, 0x24, 0xd8, 0xc1, 0x4d, 0x75, 0xa6, 0x05, 0x9d, 0x76, 0xb9, 0x6a, 0x6f, 0xd8, 0x57, 0xde, 0xf5, 0xe0, 0xb3, 0x54, 0xb2, 0x7a, 0xb9, 0x37, 0xa5, 0x81, 0x5d, 0x16, 0xb5, 0xfa, 0xe4, 0x07, 0xff, 0x18, 0x22, 0x2c, 0x6d, 0x1e, 0xd2, 0x63, 0xbe, 0x68, 0xc9, 0x5f, 0x32, 0xd9, 0x08, 0xbd, 0x89, 0x5c, 0xd7, 0x62, 0x07, 0xae, 0x72, 0x64, 0x87, 0x56, 0x7f, 0x9a, 0x67, 0xda, 0xd7, 0x9a, 0xbe, 0xc3, 0x16, 0xf6, 0x83, 0xb1, 0x7f, 0x2d, 0x02, 0xbf, 0x07, 0xe0, 0xac, 0x8b, 0x5b, 0xc6, 0x16, 0x2c, 0xf9, 0x46, 0x97, 0xb3, 0xc2, 0x7c, 0xd1, 0xfe, 0xa4, 0x9b, 0x27, 0xf2, 0x3b, 0xa2, 0x90, 0x18, 0x71, 0x96, 0x25, 0x06, 0x52, 0x0c, 0x39, 0x2d, 0xa8, 0xb6, 0xad, 0x0d, 0x99, 0xf7, 0x01, 0x3f, 0xbc, 0x06, 0xc2, 0xc1, 0x7a, 0x56, 0x95, 0x00, 0xc8, 0xa7, 0x69, 0x64, 0x81, 0xc1, 0xcd, 0x33, 0xe9, 0xb1, 0x4e, 0x40, 0xb8, 0x2e, 0x79, 0xa5, 0xf5, 0xdb, 0x82, 0x57, 0x1b, 0xa9, 0x7b, 0xae, 0x3a, 0xd3, 0xe0, 0x47, 0x95, 0x15, 0xbb, 0x0e, 0x2b, 0x0f, 0x3b, 0xfc, 0xd1, 0xfd, 0x33, 0x03, 0x4e, 0xfc, 0x62, 0x45, 0xed, 0xdd, 0x7e, 0xe2, 0x08, 0x6d, 0xda, 0xe2, 0x60, 0x0d, 0x8c, 0xa7, 0x3e, 0x21, 0x4e, 0x8c, 0x2b, 0x0b, 0xdb, 0x2b, 0x04, 0x7c, 0x6a, 0x46, 0x4a, 0x56, 0x2e, 0xd7, 0x7b, 0x73, 0xd2, 0xd8, 0x41, 0xc4, 0xb3, 0x49, 0x73, 0x55, 0x12, 0x57, 0x71, 0x3b, 0x75, 0x36, 0x32, 0xef, 0xba, 0x34, 0x81, 0x69, 0xab, 0xc9, 0x0a, 0x68, 0xf4, 0x26, 0x11, 0xa4, 0x01, 0x26, 0xd7, 0xcb, 0x21, 0xb5, 0x86, 0x95, 0x56, 0x81, 0x86, 0xf7, 0xe5, 0x69, 0xd2, 0xff, 0x0f, 0x9e, 0x74, 0x5d, 0x04, 0x87, 0xdd, 0x2e, 0xb9, 0x97, 0xca, 0xfc, 0x5a, 0xbf, 0x9d, 0xd1, 0x02, 0xe6, 0x2f, 0xf6, 0x6c, 0xba, 0x87}, .msg_len = 1023, .mech_param = TRUE, .ctx_len = 0, .prehash = FALSE, .signature = {0xe3, 0x01, 0x34, 0x5a, 0x41, 0xa3, 0x9a, 0x4d, 0x72, 0xff, 0xf8, 0xdf, 0x69, 0xc9, 0x80, 0x75, 0xa0, 0xcc, 0x08, 0x2b, 0x80, 0x2f, 0xc9, 0xb2, 0xb6, 0xbc, 0x50, 0x3f, 0x92, 0x6b, 0x65, 0xbd, 0xdf, 0x7f, 0x4c, 0x8f, 0x1c, 0xb4, 0x9f, 0x63, 0x96, 0xaf, 0xc8, 0xa7, 0x0a, 0xbe, 0x6d, 0x8a, 0xef, 0x0d, 0xb4, 0x78, 0xd4, 0xc6, 0xb2, 0x97, 0x00, 0x76, 0xc6, 0xa0, 0x48, 0x4f, 0xe7, 0x6d, 0x76, 0xb3, 0xa9, 0x76, 0x25, 0xd7, 0x9f, 0x1c, 0xe2, 0x40, 0xe7, 0xc5, 0x76, 0x75, 0x0d, 0x29, 0x55, 0x28, 0x28, 0x6f, 0x71, 0x9b, 0x41, 0x3d, 0xe9, 0xad, 0xa3, 0xe8, 0xeb, 0x78, 0xed, 0x57, 0x36, 0x03, 0xce, 0x30, 0xd8, 0xbb, 0x76, 0x17, 0x85, 0xdc, 0x30, 0xdb, 0xc3, 0x20, 0x86, 0x9e, 0x1a, 0x00}, .signature_len = 114, }, { // #15 [Ed448ph] .name = "Ed448ph", .curve_type = CURVE_EDWARDS, .params = {0x06, 0x03, 0x2B, 0x65, 0x71}, .params_len = 5, .privkey = {0x83, 0x3f, 0xe6, 0x24, 0x09, 0x23, 0x7b, 0x9d, 0x62, 0xec, 0x77, 0x58, 0x75, 0x20, 0x91, 0x1e, 0x9a, 0x75, 0x9c, 0xec, 0x1d, 0x19, 0x75, 0x5b, 0x7d, 0xa9, 0x01, 0xb9, 0x6d, 0xca, 0x3d, 0x42, 0xef, 0x78, 0x22, 0xe0, 0xd5, 0x10, 0x41, 0x27, 0xdc, 0x05, 0xd6, 0xdb, 0xef, 0xde, 0x69, 0xe3, 0xab, 0x2c, 0xec, 0x7c, 0x86, 0x7c, 0x6e, 0x2c, 0x49}, .privkey_len = 57, .pubkey = { 0x25, 0x9b, 0x71, 0xc1, 0x9f, 0x83, 0xef, 0x77, 0xa7, 0xab, 0xd2, 0x65, 0x24, 0xcb, 0xdb, 0x31, 0x61, 0xb5, 0x90, 0xa4, 0x8f, 0x7d, 0x17, 0xde, 0x3e, 0xe0, 0xba, 0x9c, 0x52, 0xbe, 0xb7, 0x43, 0xc0, 0x94, 0x28, 0xa1, 0x31, 0xd6, 0xb1, 0xb5, 0x73, 0x03, 0xd9, 0x0d, 0x81, 0x32, 0xc2, 0x76, 0xd5, 0xed, 0x3d, 0x5d, 0x01, 0xc0, 0xf5, 0x38, 0x80}, .pubkey_len = 57, .msg = {0x61, 0x62, 0x63}, .msg_len = 3, .mech_param = TRUE, .ctx_len = 0, .prehash = TRUE, .signature = {0x82, 0x2f, 0x69, 0x01, 0xf7, 0x48, 0x0f, 0x3d, 0x5f, 0x56, 0x2c, 0x59, 0x29, 0x94, 0xd9, 0x69, 0x36, 0x02, 0x87, 0x56, 0x14, 0x48, 0x32, 0x56, 0x50, 0x56, 0x00, 0xbb, 0xc2, 0x81, 0xae, 0x38, 0x1f, 0x54, 0xd6, 0xbc, 0xe2, 0xea, 0x91, 0x15, 0x74, 0x93, 0x2f, 0x52, 0xa4, 0xe6, 0xca, 0xdd, 0x78, 0x76, 0x93, 0x75, 0xec, 0x3f, 0xfd, 0x1b, 0x80, 0x1a, 0x0d, 0x9b, 0x3f, 0x40, 0x30, 0xcd, 0x43, 0x39, 0x64, 0xb6, 0x45, 0x7e, 0xa3, 0x94, 0x76, 0x51, 0x12, 0x14, 0xf9, 0x74, 0x69, 0xb5, 0x7d, 0xd3, 0x2d, 0xbc, 0x56, 0x0a, 0x9a, 0x94, 0xd0, 0x0b, 0xff, 0x07, 0x62, 0x04, 0x64, 0xa3, 0xad, 0x20, 0x3d, 0xf7, 0xdc, 0x7c, 0xe3, 0x60, 0xc3, 0xcd, 0x36, 0x96, 0xd9, 0xd9, 0xfa, 0xb9, 0x0f, 0x00}, .signature_len = 114, }, { // #16 [Ed448ph] .name = "Ed448ph", .curve_type = CURVE_EDWARDS, .params = {0x06, 0x03, 0x2B, 0x65, 0x71}, .params_len = 5, .privkey = {0x83, 0x3f, 0xe6, 0x24, 0x09, 0x23, 0x7b, 0x9d, 0x62, 0xec, 0x77, 0x58, 0x75, 0x20, 0x91, 0x1e, 0x9a, 0x75, 0x9c, 0xec, 0x1d, 0x19, 0x75, 0x5b, 0x7d, 0xa9, 0x01, 0xb9, 0x6d, 0xca, 0x3d, 0x42, 0xef, 0x78, 0x22, 0xe0, 0xd5, 0x10, 0x41, 0x27, 0xdc, 0x05, 0xd6, 0xdb, 0xef, 0xde, 0x69, 0xe3, 0xab, 0x2c, 0xec, 0x7c, 0x86, 0x7c, 0x6e, 0x2c, 0x49}, .privkey_len = 57, .pubkey = { 0x25, 0x9b, 0x71, 0xc1, 0x9f, 0x83, 0xef, 0x77, 0xa7, 0xab, 0xd2, 0x65, 0x24, 0xcb, 0xdb, 0x31, 0x61, 0xb5, 0x90, 0xa4, 0x8f, 0x7d, 0x17, 0xde, 0x3e, 0xe0, 0xba, 0x9c, 0x52, 0xbe, 0xb7, 0x43, 0xc0, 0x94, 0x28, 0xa1, 0x31, 0xd6, 0xb1, 0xb5, 0x73, 0x03, 0xd9, 0x0d, 0x81, 0x32, 0xc2, 0x76, 0xd5, 0xed, 0x3d, 0x5d, 0x01, 0xc0, 0xf5, 0x38, 0x80}, .pubkey_len = 57, .msg = {0x61, 0x62, 0x63}, .msg_len = 3, .mech_param = TRUE, .ctx = {0x66, 0x6f, 0x6f}, .ctx_len = 3, .prehash = TRUE, .signature = {0xc3, 0x22, 0x99, 0xd4, 0x6e, 0xc8, 0xff, 0x02, 0xb5, 0x45, 0x40, 0x98, 0x28, 0x14, 0xdc, 0xe9, 0xa0, 0x58, 0x12, 0xf8, 0x19, 0x62, 0xb6, 0x49, 0xd5, 0x28, 0x09, 0x59, 0x16, 0xa2, 0xaa, 0x48, 0x10, 0x65, 0xb1, 0x58, 0x04, 0x23, 0xef, 0x92, 0x7e, 0xcf, 0x0a, 0xf5, 0x88, 0x8f, 0x90, 0xda, 0x0f, 0x6a, 0x9a, 0x85, 0xad, 0x5d, 0xc3, 0xf2, 0x80, 0xd9, 0x12, 0x24, 0xba, 0x99, 0x11, 0xa3, 0x65, 0x3d, 0x00, 0xe4, 0x84, 0xe2, 0xce, 0x23, 0x25, 0x21, 0x48, 0x1c, 0x86, 0x58, 0xdf, 0x30, 0x4b, 0xb7, 0x74, 0x5a, 0x73, 0x51, 0x4c, 0xdb, 0x9b, 0xf3, 0xe1, 0x57, 0x84, 0xab, 0x71, 0x28, 0x4f, 0x8d, 0x07, 0x04, 0xa6, 0x08, 0xc5, 0x4a, 0x6b, 0x62, 0xd9, 0x7b, 0xeb, 0x51, 0x1d, 0x13, 0x21, 0x00}, .signature_len = 114, }, }; #define ED_TV_NUM sizeof(ed_tv)/sizeof(struct ED_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 CURVE448_LENGTH 0x01C0 #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[] = { 0, 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, }, { // #7 [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_SHA256_KDF_SP800, .shared_data = {0x70,0xE6,0xD8,0x9A,0x6D,0x75,0xD2,0x91,0xB6,0x99,0xAB}, .shared_data_len = 11, .derived_key = {0x5c,0xf5,0xcf,0xf6,0xbf,0x20,0x1b,0x73,0x6c,0x55,0x79,0x47,0x2d,0xe2,0x2c,0xae, 0x4c,0xba,0x0a,0x51,0x6c,0x63,0x53,0xe9,0xe7,0xb3,0x7f,0x36,0x12,}, .derived_key_len = 29, }, { // #8 [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_SHA3_256_KDF_SP800, .shared_data = {0x70,0xE6,0xD8,0x9A,0x6D,0x75,0xD2,0x91,0xB6,0x99,0xAB}, .shared_data_len = 11, .derived_key = {0xcb,0x28,0x61,0x63,0x29,0x0d,0xc0,0x9f,0xd3,0x00,0x5e,0xed,0x4e,0x0d,0x07,0x28, 0x4d,0x42,0xc8,0x5f,0x22,0x90,0x31,0xb1,0xaf,0xe8,0x20,0x1b,0x3b,}, .derived_key_len = 29, }, }; #define ECDH_TV_NUM sizeof(ecdh_tv)/sizeof(struct ECDH_TEST_VECTOR) /* Test vectors from RFC 7748 */ struct ECDH_TEST_VECTOR montgomery_ecdh_tv[] = { { // #0 [Curve25519] .name = "Curve25519", .params = {0x06, 0x03, 0x2B, 0x65, 0x6E}, .params_len = 5, .privkeyA = {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}, .pubkeyA = {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}, .privkeyB = {0x5d, 0xab, 0x08, 0x7e, 0x62, 0x4a, 0x8a, 0x4b, 0x79, 0xe1, 0x7f, 0x8b, 0x83, 0x80, 0x0e, 0xe6, 0x6f, 0x3b, 0xb1, 0x29, 0x26, 0x18, 0xb6, 0xfd, 0x1c, 0x2f, 0x8b, 0x27, 0xff, 0x88, 0xe0, 0xeb}, .pubkeyB = {0xde, 0x9e, 0xdb, 0x7d, 0x7b, 0x7d, 0xc1, 0xb4, 0xd3, 0x5b, 0x61, 0xc2, 0xec, 0xe4, 0x35, 0x37, 0x3f, 0x83, 0x43, 0xc8, 0x5b, 0x78, 0x67, 0x4d, 0xad, 0xfc, 0x7e, 0x14, 0x6f, 0x88, 0x2b, 0x4f}, .privkey_len = 32, .pubkey_len = 32, .kdf = CKD_SHA256_KDF, .shared_data_len = 0, .derived_key = {0x86, 0xca, 0x3c, 0x8a, 0x5e, 0x4a, 0x20, 0xd2, 0x5f, 0xad, 0x21, 0xac, 0x34, 0x6d, 0xdf, 0x51, 0xfa, 0xd2, 0x01, 0x9b, 0x93, 0x44, 0x28, 0x74, 0xa8, 0x6b, 0x1d, 0x34, 0x18, 0x54, 0xc3, 0x7f}, .derived_key_len = 32, }, { // #1 [Curve448] .name = "Curve448", .params = {0x06, 0x03, 0x2B, 0x65, 0x6F}, .params_len = 5, .privkeyA = {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, 0x6b}, .pubkeyA = {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}, .privkeyB = {0x1c, 0x30, 0x6a, 0x7a, 0xc2, 0xa0, 0xe2, 0xe0, 0x99, 0x0b, 0x29, 0x44, 0x70, 0xcb, 0xa3, 0x39, 0xe6, 0x45, 0x37, 0x72, 0xb0, 0x75, 0x81, 0x1d, 0x8f, 0xad, 0x0d, 0x1d, 0x69, 0x27, 0xc1, 0x20, 0xbb, 0x5e, 0xe8, 0x97, 0x2b, 0x0d, 0x3e, 0x21, 0x37, 0x4c, 0x9c, 0x92, 0x1b, 0x09, 0xd1, 0xb0, 0x36, 0x6f, 0x10, 0xb6, 0x51, 0x73, 0x99, 0x2d}, .pubkeyB = {0x3e, 0xb7, 0xa8, 0x29, 0xb0, 0xcd, 0x20, 0xf5, 0xbc, 0xfc, 0x0b, 0x59, 0x9b, 0x6f, 0xec, 0xcf, 0x6d, 0xa4, 0x62, 0x71, 0x07, 0xbd, 0xb0, 0xd4, 0xf3, 0x45, 0xb4, 0x30, 0x27, 0xd8, 0xb9, 0x72, 0xfc, 0x3e, 0x34, 0xfb, 0x42, 0x32, 0xa1, 0x3c, 0xa7, 0x06, 0xdc, 0xb5, 0x7a, 0xec, 0x3d, 0xae, 0x07, 0xbd, 0xc1, 0xc6, 0x7b, 0xf3, 0x36, 0x09}, .privkey_len = 56, .pubkey_len = 56, .kdf = CKD_SHA256_KDF, .shared_data_len = 0, .derived_key = {0xa4, 0xd4, 0xa3, 0xe2, 0x91, 0x35, 0x30, 0x2a, 0x88, 0x87, 0x01, 0xfa, 0xca, 0x8f, 0x45, 0x16, 0xba, 0x0b, 0xc3, 0x5f, 0x17, 0x2c, 0x4b, 0xe2, 0x4f, 0x8e, 0xb5, 0x48, 0x21, 0xbd, 0xa8, 0x3f}, .derived_key_len = 32, }, }; #define MONTGOMERY_ECDH_TV_NUM sizeof(montgomery_ecdh_tv)/sizeof(struct ECDH_TEST_VECTOR) opencryptoki-opencryptoki-451d99c/testcases/crypto/ec_func.c000066400000000000000000006461121520105705100244220ustar00rootroot00000000000000/* * 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 #include "pkcs11types.h" #include "regress.h" #include "common.c" #include "ec.h" #include "defs.h" #include "ec_curves.h" #include "mechtable.h" #include "mech_to_str.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 */ 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 25 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 CK_BYTE bls12_381[] = OCK_BLS12_381; 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_KOBLITZ, CURVE256_LENGTH, "secp256k1"}, {&curve25519, sizeof(curve25519), CK_FALSE, CURVE_MONTGOMERY, CURVE256_LENGTH, "curve25519"}, {&curve448, sizeof(curve448), CK_FALSE, CURVE_MONTGOMERY, CURVE448_LENGTH, "curve448"}, {&ed25519, sizeof(ed25519), CK_FALSE, CURVE_EDWARDS, CURVE256_LENGTH, "ed25519"}, {&ed448, sizeof(ed448), CK_FALSE, CURVE_EDWARDS, CURVE456_LENGTH, "ed448"}, {&bls12_381, sizeof(bls12_381), CK_TRUE, CURVE_BLS12_381, CURVE384_LENGTH, "bls12_381"}, }; /* 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 mech; 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 */ const char *name; } _signVerifyParam; CK_IBM_ECDSA_OTHER_PARAMS other_rand = { .submechanism = CKM_IBM_ECSDSA_RAND }; CK_IBM_ECDSA_OTHER_PARAMS other_compr_multi = { .submechanism = CKM_IBM_ECSDSA_COMPR_MULTI }; CK_IBM_ECDSA_OTHER_PARAMS other_bls = { .submechanism = CKM_IBM_BLS }; _signVerifyParam signVerifyInput[] = { {{CKM_ECDSA, NULL, 0}, 20, 0, ""}, {{CKM_ECDSA, NULL, 0}, 32, 0, ""}, {{CKM_ECDSA, NULL, 0}, 48, 0, ""}, {{CKM_ECDSA, NULL, 0}, 64, 0, ""}, {{CKM_ECDSA_SHA1, NULL, 0}, 100, 0, ""}, {{CKM_ECDSA_SHA1, NULL, 0}, 100, 4, ""}, {{CKM_ECDSA_SHA1, NULL, 0}, 0, 0, ""}, /* Empty Message via C_Sign */ {{CKM_ECDSA_SHA1, NULL, 0}, 0, 1, ""}, /* Empty Message via C_SignInit+C_SignFinal */ {{CKM_ECDSA_SHA224, NULL, 0}, 100, 0, ""}, {{CKM_ECDSA_SHA224, NULL, 0}, 100, 4, ""}, {{CKM_ECDSA_SHA224, NULL, 0}, 0, 0, ""}, /* Empty Message via C_Sign */ {{CKM_ECDSA_SHA224, NULL, 0}, 0, 1, ""}, /* Empty Message via C_SignInit+C_SignFinal */ {{CKM_ECDSA_SHA256, NULL, 0}, 100, 0, ""}, {{CKM_ECDSA_SHA256, NULL, 0}, 100, 4, ""}, {{CKM_ECDSA_SHA256, NULL, 0}, 0, 0, ""}, /* Empty Message via C_Sign */ {{CKM_ECDSA_SHA256, NULL, 0}, 0, 1, ""}, /* Empty Message via C_SignInit+C_SignFinal */ {{CKM_ECDSA_SHA384, NULL, 0}, 100, 0, ""}, {{CKM_ECDSA_SHA384, NULL, 0}, 100, 4, ""}, {{CKM_ECDSA_SHA384, NULL, 0}, 0, 0, ""}, /* Empty Message via C_Sign */ {{CKM_ECDSA_SHA384, NULL, 0}, 0, 1, ""}, /* Empty Message via C_SignInit+C_SignFinal */ {{CKM_ECDSA_SHA512, NULL, 0}, 100, 0, ""}, {{CKM_ECDSA_SHA512, NULL, 0}, 100, 4, ""}, {{CKM_ECDSA_SHA512, NULL, 0}, 0, 0, ""}, /* Empty Message via C_Sign */ {{CKM_ECDSA_SHA512, NULL, 0}, 0, 1, ""}, /* Empty Message via C_SignInit+C_SignFinal */ {{CKM_ECDSA_SHA3_224, NULL, 0}, 100, 0, ""}, {{CKM_ECDSA_SHA3_224, NULL, 0}, 100, 4, ""}, {{CKM_ECDSA_SHA3_224, NULL, 0}, 0, 0, ""}, /* Empty Message via C_Sign */ {{CKM_ECDSA_SHA3_224, NULL, 0}, 0, 1, ""}, /* Empty Message via C_SignInit+C_SignFinal */ {{CKM_ECDSA_SHA3_256, NULL, 0}, 100, 0, ""}, {{CKM_ECDSA_SHA3_256, NULL, 0}, 100, 4, ""}, {{CKM_ECDSA_SHA3_256, NULL, 0}, 0, 0, ""}, /* Empty Message via C_Sign */ {{CKM_ECDSA_SHA3_256, NULL, 0}, 0, 1, ""}, /* Empty Message via C_SignInit+C_SignFinal */ {{CKM_ECDSA_SHA3_384, NULL, 0}, 100, 0, ""}, {{CKM_ECDSA_SHA3_384, NULL, 0}, 100, 4, ""}, {{CKM_ECDSA_SHA3_384, NULL, 0}, 0, 0, ""}, /* Empty Message via C_Sign */ {{CKM_ECDSA_SHA3_384, NULL, 0}, 0, 1, ""}, /* Empty Message via C_SignInit+C_SignFinal */ {{CKM_ECDSA_SHA3_512, NULL, 0}, 100, 0, ""}, {{CKM_ECDSA_SHA3_512, NULL, 0}, 100, 4, ""}, {{CKM_ECDSA_SHA3_512, NULL, 0}, 0, 0, ""}, /* Empty Message via C_Sign */ {{CKM_ECDSA_SHA3_512, NULL, 0}, 0, 1, ""}, /* Empty Message via C_SignInit+C_SignFinal */ {{CKM_IBM_ED25519_SHA512, NULL, 0}, 100, 0, ""}, {{CKM_IBM_ED448_SHA3, NULL, 0}, 100, 0, ""}, {{CKM_IBM_ECDSA_OTHER, &other_rand, sizeof(other_rand)}, 20, 0, ""}, {{CKM_IBM_ECDSA_OTHER, &other_compr_multi, sizeof(other_compr_multi)}, 20, 0, ""}, {{CKM_IBM_ECDSA_OTHER, &other_bls, sizeof(other_bls)}, 20, 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, CKD_SHA3_224_KDF, CKD_SHA3_256_KDF, CKD_SHA3_384_KDF, CKD_SHA3_512_KDF, CKD_SHA1_KDF_SP800, CKD_SHA224_KDF_SP800, CKD_SHA256_KDF_SP800, CKD_SHA384_KDF_SP800, CKD_SHA512_KDF_SP800, CKD_SHA3_224_KDF_SP800, CKD_SHA3_256_KDF_SP800, CKD_SHA3_384_KDF_SP800, CKD_SHA3_512_KDF_SP800, }; 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"; case CKD_SHA3_224_KDF: return "CKD_SHA3_224_KDF"; case CKD_SHA3_256_KDF: return "CKD_SHA3_256_KDF"; case CKD_SHA3_384_KDF: return "CKD_SHA3_384_KDF"; case CKD_SHA3_512_KDF: return "CKD_SHA3_512_KDF"; case CKD_SHA1_KDF_SP800: return "CKD_SHA1_KDF_SP800"; case CKD_SHA224_KDF_SP800: return "CKD_SHA224_KDF_SP800"; case CKD_SHA256_KDF_SP800: return "CKD_SHA256_KDF_SP800"; case CKD_SHA384_KDF_SP800: return "CKD_SHA384_KDF_SP800"; case CKD_SHA512_KDF_SP800: return "CKD_SHA512_KDF_SP800"; case CKD_SHA3_224_KDF_SP800: return "CKD_SHA3_224_KDF_SP800"; case CKD_SHA3_256_KDF_SP800: return "CKD_SHA3_256_KDF_SP800"; case CKD_SHA3_384_KDF_SP800: return "CKD_SHA3_384_KDF_SP800"; case CKD_SHA3_512_KDF_SP800: return "CKD_SHA3_512_KDF_SP800"; 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' || name[strlen(name) - 2] == 'k') 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; } /* * Perform a HMAC sign to verify that the key is usable. */ CK_RV run_HMACSign(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE h_key, CK_ULONG key_len, CK_MECHANISM_TYPE hmac_mech, CK_BYTE *mac, CK_ULONG *mac_len) { CK_MECHANISM mech = { .mechanism = hmac_mech, .pParameter = NULL, .ulParameterLen = 0 }; CK_BYTE data[32] = { 0 }; CK_RV rc = CKR_OK; if (!mech_supported(SLOT_ID, mech.mechanism)) { testcase_notice("Mechanism %s is not supported with slot " "%lu. Skipping key check", p11_get_ckm(&mechtable_funcs, mech.mechanism), SLOT_ID); *mac_len = 0; return CKR_OK; } if (!check_supp_keysize(SLOT_ID, mech.mechanism, key_len * 8)) { testcase_notice("Mechanism %s can not be used with keys " "of size %lu. Skipping key check", p11_get_ckm(&mechtable_funcs, mech.mechanism), key_len); *mac_len = 0; return CKR_OK; } rc = funcs->C_SignInit(session, &mech, h_key); if (rc != CKR_OK) { testcase_notice("C_SignInit rc=%s", p11_get_ckr(rc)); goto error; } /** do signing **/ rc = funcs->C_Sign(session, data, sizeof(data), mac, mac_len); if (rc != CKR_OK) { testcase_notice("C_Sign rc=%s", p11_get_ckr(rc)); goto error; } error: return rc; } CK_RV run_AESEncrypt(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE h_key, CK_BYTE *enc, CK_ULONG *enc_len) { char aes_iv[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; CK_MECHANISM mech = { .mechanism = CKM_AES_CBC, .pParameter = &aes_iv, .ulParameterLen = AES_INIT_VECTOR_SIZE }; CK_BYTE data[AES_BLOCK_SIZE] = { 0 }; CK_RV rc = CKR_OK; if (!mech_supported(SLOT_ID, mech.mechanism)) { testcase_notice("Mechanism %s is not supported with slot " "%lu. Skipping key check", p11_get_ckm(&mechtable_funcs, mech.mechanism), SLOT_ID); *enc_len = 0; return CKR_OK; } rc = funcs->C_EncryptInit(session, &mech, h_key); if (rc != CKR_OK) { testcase_notice("C_EncryptInit rc=%s", p11_get_ckr(rc)); goto error; } /** do encrypting **/ rc = funcs->C_Encrypt(session, data, sizeof(data), enc, enc_len); if (rc != CKR_OK) { testcase_notice("C_Encrypt rc=%s", p11_get_ckr(rc)); goto error; } error: return rc; } /* * Perform a HMAC sign to verify that the key is usable. */ CK_RV run_HMACSign_OpenSSL(CK_BYTE *key, CK_ULONG key_len, CK_MECHANISM_TYPE hmac_mech, CK_BYTE *mac, CK_ULONG *mac_len) { CK_BYTE data[32] = { 0 }; const EVP_MD *md; unsigned int out_len; switch (hmac_mech) { case CKM_SHA_1_HMAC: md = EVP_sha1(); break; case CKM_SHA224_HMAC: md = EVP_sha224(); break; case CKM_SHA256_HMAC: md = EVP_sha256(); break; case CKM_SHA384_HMAC: md = EVP_sha384(); break; case CKM_SHA512_HMAC: md = EVP_sha512(); break; default: testcase_notice("Mechanism %s is not supported. Skipping key check", p11_get_ckm(&mechtable_funcs, hmac_mech)); *mac_len = 0; return CKR_OK; } out_len = *mac_len; if (HMAC(md, key, key_len, data, sizeof(data), mac, &out_len) == NULL) { testcase_notice("HMAC (OpenSSL) failed"); return CKR_OK; } *mac_len = out_len; return CKR_OK; } /* * 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_BBOOL cofactor_mode) { 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] = { 0 }; CK_BYTE pubkeyB_value[256] = { 0 }; CK_BYTE secretA_value[80000] = { 0 }; //enough space for lengths in secret_key_len[] CK_BYTE deriveB_value[80000] = { 0 }; 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 with pkey=%X ...", pkey); testcase_rw_session(); testcase_user_login(); /* Skip tests if pkey = true, but the slot doesn't support protected keys*/ if (pkey && !is_ep11_token(SLOT_ID) && !is_cca_token(SLOT_ID)) { testcase_skip("pkey test option is true, but slot %u doesn't support protected keys", (unsigned int) SLOT_ID); goto testcase_cleanup; } 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_gen, pub_attr_gen_len, prv_attr_gen, prv_attr_gen_len, &publ_keyA, &priv_keyA); if (rc != CKR_OK) { if (is_rejected_by_policy(rc, session)) { testcase_skip("EC key generation is not allowed by policy"); continue; } if (rc == CKR_MECHANISM_PARAM_INVALID || rc == CKR_ATTRIBUTE_VALUE_INVALID || rc == CKR_CURVE_NOT_SUPPORTED) { 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_gen, pub_attr_gen_len, prv_attr_gen, prv_attr_gen_len, &publ_keyB, &priv_keyB); if (rc != CKR_OK) { if (is_rejected_by_policy(rc, session)) { testcase_skip("EC key generation is not allowed by policy"); goto testcase_cleanup; } 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++) { switch (kdfs[j]) { case CKD_SHA1_KDF: case CKD_SHA1_KDF_SP800: if (!mech_supported(SLOT_ID, CKM_SHA_1)) { testcase_skip("Slot %u doesn't support %s\n", (unsigned int) SLOT_ID, p11_get_ckd(kdfs[j])); continue; } break; case CKD_SHA224_KDF: case CKD_SHA224_KDF_SP800: if (!mech_supported(SLOT_ID, CKM_SHA224)) { testcase_skip("Slot %u doesn't support %s\n", (unsigned int) SLOT_ID, p11_get_ckd(kdfs[j])); continue; } break; case CKD_SHA256_KDF: case CKD_SHA256_KDF_SP800: if (!mech_supported(SLOT_ID, CKM_SHA256)) { testcase_skip("Slot %u doesn't support %s\n", (unsigned int) SLOT_ID, p11_get_ckd(kdfs[j])); continue; } break; case CKD_SHA384_KDF: case CKD_SHA384_KDF_SP800: if (!mech_supported(SLOT_ID, CKM_SHA384)) { testcase_skip("Slot %u doesn't support %s\n", (unsigned int) SLOT_ID, p11_get_ckd(kdfs[j])); continue; } break; case CKD_SHA512_KDF: case CKD_SHA512_KDF_SP800: if (!mech_supported(SLOT_ID, CKM_SHA512)) { testcase_skip("Slot %u doesn't support %s\n", (unsigned int) SLOT_ID, p11_get_ckd(kdfs[j])); continue; } break; case CKD_SHA3_224_KDF: case CKD_SHA3_224_KDF_SP800: if (!mech_supported(SLOT_ID, CKM_SHA3_224)) { testcase_skip("Slot %u doesn't support %s\n", (unsigned int) SLOT_ID, p11_get_ckd(kdfs[j]));; continue; } break; case CKD_SHA3_256_KDF: case CKD_SHA3_256_KDF_SP800: if (!mech_supported(SLOT_ID, CKM_SHA3_256)) { testcase_skip("Slot %u doesn't support %s\n", (unsigned int) SLOT_ID, p11_get_ckd(kdfs[j])); continue; } break; case CKD_SHA3_384_KDF: case CKD_SHA3_384_KDF_SP800: if (!mech_supported(SLOT_ID, CKM_SHA3_384)) { testcase_skip("Slot %u doesn't support %s\n", (unsigned int) SLOT_ID, p11_get_ckd(kdfs[j])); continue; } break; case CKD_SHA3_512_KDF: case CKD_SHA3_512_KDF_SP800: if (!mech_supported(SLOT_ID, CKM_SHA3_512)) { testcase_skip("Slot %u doesn't support %s\n", (unsigned int) SLOT_ID, p11_get_ckd(kdfs[j])); continue; } break; default: break; } for (k=0; k 9) { testcase_skip("EP11 cannot provide %lu key bytes with " "curve %s\n", secret_key_len[k], der_ec_supported[i].name); continue; } if (is_ep11_token(SLOT_ID) && secret_key_len[k] > 0 && secret_key_len[k] < 10) { /* * EP11 can not derive keys less than 80 bits (10 bytes). * This was formerly dependent on control point * XCP_CPB_KEYSZ_BELOW80BIT, but this control point * is now always OFF. * */ testcase_skip("EP11 cannot provide %lu key bytes (%lu bits < 80 bits)\n", secret_key_len[k], secret_key_len[k] * 8); continue; } if (secret_key_len[k] == 0 && der_ec_supported[i].type == CURVE_MONTGOMERY) { /* * Curve can not be used without the derived key size * specified in CKA_VALUE_LEN. */ continue; } if (der_ec_supported[i].type == CURVE_BLS12_381) { /* * Skipping BLS 12 381 curve. */ continue; } if (is_icsf_token(SLOT_ID) && secret_key_len[k] == 0) { testcase_skip("ICSF token can not derive keys without CKA_VALUE_LEN\n"); continue; } if (is_icsf_token(SLOT_ID) && secret_key_len[k] > 256) { testcase_skip("ICSF token can not derive keys of that size\n"); continue; } if (is_cca_token(SLOT_ID)) { if (secret_key_len[k] == derive_value_len) { key_type = derive_key_type; /* CCA can only derive AES-256 keys */ } else if (secret_key_len[k] == 0 && der_ec_supported[i].bit_len == derive_value_len * 8) { key_type = derive_key_type; /* CCA can only derive AES-256 keys */ } else { testcase_skip("CCA token can not derive keys of size %lu\n", secret_key_len[k]); 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_SENSITIVE, &false, sizeof(false)}, {CKA_VALUE_LEN, &(secret_key_len[k]), sizeof(CK_ULONG)}, }; CK_ULONG secret_tmpl_len = sizeof(derive_tmpl) / sizeof(CK_ATTRIBUTE); CK_BYTE mac1[SHA1_HASH_SIZE] = { 0 }; CK_ULONG mac1_len = sizeof(mac1); CK_BYTE mac2[SHA1_HASH_SIZE] = { 0 }; CK_ULONG mac2_len = sizeof(mac2); CK_BYTE enc1[AES_BLOCK_SIZE] = { 0 }; CK_ULONG enc1_len = sizeof(enc1); CK_BYTE enc2[AES_BLOCK_SIZE] = { 0 }; CK_ULONG enc2_len = sizeof(enc2); if (secret_key_len[k] == 0) secret_tmpl_len--; for (m=0; m < (kdfs[j] == CKD_NULL ? 1 : NUM_SHARED_DATA); m++) { if (is_cca_token(SLOT_ID)) { switch (kdfs[j]) { case CKD_SHA224_KDF: case CKD_SHA256_KDF: case CKD_SHA384_KDF: case CKD_SHA512_KDF: break; default: continue; } } testcase_begin("Starting with curve=%s, kdf=%s, keylen=%lu, " "shared_data=%u, mech=%s, pkey=%X", der_ec_supported[i].name, p11_get_ckd(kdfs[j]), secret_key_len[k], shared_data[m].length, p11_get_ckm(&mechtable_funcs, derive_mech_type), pkey); // 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 KDF %s and/or " "shared data with older firmware " "versions\n", p11_get_ckd(kdfs[j])); continue; } if (is_rejected_by_policy(rc, session)) { testcase_skip("key derivation is not allowed by policy"); continue; } if (rc == CKR_FUNCTION_CANCELED) { testcase_skip("key derivation is not allowed by " "adapter control point"); continue; } if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("key derivation is not allowed " "because key to be generated is " "stronger than the input material."); continue; } testcase_fail("C_DeriveKey #1: rc = %s", p11_get_ckr(rc)); goto testcase_cleanup; } switch (key_type) { case CKK_GENERIC_SECRET: mac1_len = sizeof(mac1); rc = run_HMACSign(session, secret_keyA, secret_key_len[k] > 0 ? secret_key_len[k] : curve_len(i), CKM_SHA_1_HMAC, mac1, &mac1_len); if (rc != CKR_OK) { testcase_fail("Derived key #1 is not usable: %s", p11_get_ckr(rc)); goto testcase_cleanup; } break; case CKK_AES: enc1_len = sizeof(enc1); rc = run_AESEncrypt(session, secret_keyA, enc1, &enc1_len); if (rc != CKR_OK) { testcase_fail("Derived key #1 is not usable: %s", p11_get_ckr(rc)); goto testcase_cleanup; } break; } // 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 KDF %s and/or " "shared data with older firmware " "versions\n", p11_get_ckd(kdfs[j])); if (secret_keyA != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, secret_keyA); continue; } if (is_rejected_by_policy(rc, session)) { testcase_skip("key derivation is not allowed by policy"); if (secret_keyA != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, secret_keyA); continue; } if (rc == CKR_FUNCTION_CANCELED) { testcase_skip("key derivation is not allowed by " "adapter control point"); if (secret_keyA != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, secret_keyA); continue; } if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("key derivation is not allowed " "because key to be generated is " "stronger than the input material."); continue; } testcase_fail("C_DeriveKey #2: rc = %s", p11_get_ckr(rc)); goto testcase_cleanup; } testcase_new_assertion(); switch (key_type) { case CKK_GENERIC_SECRET: mac2_len = sizeof(mac2); rc = run_HMACSign(session, secret_keyB, secret_key_len[k] > 0 ? secret_key_len[k] : curve_len(i), CKM_SHA_1_HMAC, mac2, &mac2_len); if (rc != CKR_OK) { testcase_fail("Derived key #2 is not usable: %s", p11_get_ckr(rc)); goto testcase_cleanup; } if (mac1_len != mac2_len || memcmp(mac1, mac2, mac1_len) != 0) { testcase_fail("ERROR: derived keys do not produce the " "same HMAC"); goto testcase_cleanup; } break; case CKK_AES: enc2_len = sizeof(enc2); rc = run_AESEncrypt(session, secret_keyA, enc2, &enc2_len); if (rc != CKR_OK) { testcase_fail("Derived key #1 is not usable: %s", p11_get_ckr(rc)); goto testcase_cleanup; } if (enc1_len != enc2_len || memcmp(enc1, enc2, enc1_len) != 0) { testcase_fail("ERROR: derived keys do not produce the " "same encrypted cipher text"); goto testcase_cleanup; } break; } /* A secure key token won't reveal the key value in clear */ if (!is_ep11_token(SLOT_ID) && !is_cca_token(SLOT_ID)) { // 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 = %lu, " "derived key #2 length = %lu", 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(&mechtable_funcs, 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(void) { 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] = { 0 }; // enough space for key lengths in ecdh_tv[] CK_BYTE secretB_value[1000] = { 0 }; CK_BYTE mac1[SHA1_HASH_SIZE] = { 0 }; CK_ULONG mac1_len = sizeof(mac1); CK_BYTE mac2[SHA1_HASH_SIZE] = { 0 }; CK_ULONG mac2_len = sizeof(mac2); CK_BYTE macexpected[SHA1_HASH_SIZE] = { 0 }; CK_ULONG macexpected_len = sizeof(macexpected); CK_ULONG i; testcase_begin("starting run_DeriveECDHKeyKAT with pkey=%X ...", pkey); testcase_rw_session(); testcase_user_login(); /* Skip tests if pkey = true, but the slot doesn't support protected keys*/ if (pkey && !is_ep11_token(SLOT_ID) && !is_cca_token(SLOT_ID)) { testcase_skip("pkey test option is true, but slot %u doesn't support protected keys", (unsigned int) SLOT_ID); goto testcase_cleanup; } 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)) && !mech_supported(SLOT_ID, CKM_SHA_1_HMAC)) { testcase_skip("Slot %u doesn't support CKM_SHA_1_HMAC, correctness " "of derived keys can not be verified\n", (unsigned int) SLOT_ID); goto testcase_cleanup; } if (is_cca_token(SLOT_ID)) { testcase_skip("The CCA token in slot %u doesn't support ECDH with EC " "keys imported from clear, only with randomly generated " "keys. KATs not possible because of that\n", (unsigned int) SLOT_ID); goto testcase_cleanup; } for (i=0; i 256) { testcase_skip("EP11 cannot provide %lu key bytes with " "curve %s\n", ecdh_tv[i].derived_key_len, ecdh_tv[i].name); continue; } if ((is_ep11_token(SLOT_ID) || is_cca_token(SLOT_ID)) && !check_supp_keysize(SLOT_ID, CKM_SHA_1_HMAC, ecdh_tv[i].derived_key_len * 8)) { testcase_skip("Mechanism CKM_SHA_1_HMAC can not be used with " "keys of size %lu. Correctness of derived key " "can not be verified.", ecdh_tv[i].derived_key_len); continue; } // First, import the EC key pair for party A rc = create_ECPrivateKey(session, CKK_EC, ecdh_tv[i].params, ecdh_tv[i].params_len, ecdh_tv[i].privkeyA, ecdh_tv[i].privkey_len, &priv_keyA, !pkey, CK_TRUE); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("EC key import is not allowed by policy"); continue; } if (rc == CKR_CURVE_NOT_SUPPORTED) { testcase_skip("Slot %u doesn't support this curve: %s", (unsigned int) SLOT_ID, ecdh_tv[i].name); goto testcase_next; } testcase_fail("C_CreateObject (EC Private Key) failed at i=%lu, " "rc=%s", i, p11_get_ckr(rc)); goto testcase_cleanup; } rc = create_ECPublicKey(session, CKK_EC, ecdh_tv[i].params, ecdh_tv[i].params_len, ecdh_tv[i].pubkeyA, ecdh_tv[i].pubkey_len, &publ_keyA, !pkey); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("EC key import is not allowed by policy"); funcs->C_DestroyObject(session, priv_keyA); continue; } if (rc == CKR_CURVE_NOT_SUPPORTED) { testcase_skip("Slot %u doesn't support this curve: %s", (unsigned int) SLOT_ID, ecdh_tv[i].name); goto testcase_next; } testcase_fail("C_CreateObject (EC Public Key) failed at i=%lu, " "rc=%s", i, p11_get_ckr(rc)); goto testcase_cleanup; } // Now import the EC key pair for party B rc = create_ECPrivateKey(session, CKK_EC, ecdh_tv[i].params, ecdh_tv[i].params_len, ecdh_tv[i].privkeyB, ecdh_tv[i].privkey_len, &priv_keyB, !pkey, CK_TRUE); if (rc != CKR_OK) { if (rc == CKR_CURVE_NOT_SUPPORTED) { testcase_skip("Slot %u doesn't support this curve: %s", (unsigned int) SLOT_ID, ecdh_tv[i].name); goto testcase_next; } testcase_fail("C_CreateObject (EC Private Key) failed at i=%lu, " "rc=%s", i, p11_get_ckr(rc)); goto testcase_cleanup; } rc = create_ECPublicKey(session, CKK_EC, ecdh_tv[i].params, ecdh_tv[i].params_len, ecdh_tv[i].pubkeyB, ecdh_tv[i].pubkey_len, &publ_keyB, !pkey); if (rc != CKR_OK) { if (rc == CKR_CURVE_NOT_SUPPORTED) { testcase_skip("Slot %u doesn't support this curve: %s", (unsigned int) SLOT_ID, ecdh_tv[i].name); goto testcase_next; } testcase_fail("C_CreateObject (EC Public Key) failed at i=%lu, " "rc=%s", i, p11_get_ckr(rc)); goto testcase_cleanup; } // Now derive the secrets... 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, secretB_value, sizeof(secretB_value)} }; CK_ULONG secretB_tmpl_len = sizeof(secretB_tmpl) / sizeof(CK_ATTRIBUTE); CK_BBOOL extractable = !pkey; CK_ATTRIBUTE derive_tmpl[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &secret_key_type, sizeof(secret_key_type)}, {CKA_VALUE_LEN, &(ecdh_tv[i].derived_key_len), sizeof(CK_ULONG)}, {CKA_SENSITIVE, &false, sizeof(false)}, {CKA_EXTRACTABLE, &extractable, sizeof(CK_BBOOL)}, {CKA_IBM_PROTKEY_EXTRACTABLE, &pkey, sizeof(CK_BBOOL)}, }; CK_ULONG derive_tmpl_len = sizeof(derive_tmpl) / sizeof(CK_ATTRIBUTE); // Now, derive a generic secret key using party A's private key // and B's public key ecdh_parmA.kdf = ecdh_tv[i].kdf; ecdh_parmA.pPublicData = ecdh_tv[i].pubkeyB; ecdh_parmA.ulPublicDataLen = ecdh_tv[i].pubkey_len; ecdh_parmA.pSharedData = ecdh_tv[i].shared_data_len == 0 ? NULL : (CK_BYTE_PTR)&ecdh_tv[i].shared_data; ecdh_parmA.ulSharedDataLen = ecdh_tv[i].shared_data_len; if (ecdh_tv[i].kdf == CKD_NULL) { ecdh_parmA.pSharedData = NULL; ecdh_parmA.ulSharedDataLen = 0; } mech.mechanism = CKM_ECDH1_DERIVE; mech.ulParameterLen = sizeof(CK_ECDH1_DERIVE_PARAMS); mech.pParameter = &ecdh_parmA; rc = funcs->C_DeriveKey(session, &mech, priv_keyA, derive_tmpl, derive_tmpl_len, &secret_keyA); if (rc != CKR_OK) { if (rc == CKR_CURVE_NOT_SUPPORTED) { testcase_skip("Slot %u doesn't support this curve: %s", (unsigned int) SLOT_ID, ecdh_tv[i].name); goto testcase_next; } else 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 KDF %s and/or shared data " "with older firmware versions\n", p11_get_ckd(ecdh_tv[i].kdf)); 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 KDF %s and/or shared data " "with older firmware versions\n", p11_get_ckd(ecdh_tv[i].kdf)); 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; } testcase_new_assertion(); /* A secure key token won't reveal the key value in clear */ if (!is_ep11_token(SLOT_ID) && !is_cca_token(SLOT_ID)) { // 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 = %lu, " "derived key #2 length = %lu", 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 = %lu, derived key " "#2 length = %lu", 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; } } else { /* Secure key: * Calculate HMAC with derived keys and expected key and compare * the MAC. */ rc = run_HMACSign_OpenSSL(ecdh_tv[i].derived_key, ecdh_tv[i].derived_key_len, CKM_SHA_1_HMAC, macexpected, &macexpected_len); if (rc != CKR_OK) { testcase_fail("HMAC for expected key failed: %s", p11_get_ckr(rc)); goto testcase_cleanup; } rc = run_HMACSign(session, secret_keyA, ecdh_tv[i].derived_key_len, CKM_SHA_1_HMAC, mac1, &mac1_len); if (rc != CKR_OK) { testcase_fail("HMAC for derived key #1 failed: %s", p11_get_ckr(rc)); goto testcase_cleanup; } if (mac1_len != 0 && /* skip check if mac can't be calcualted */ (mac1_len != macexpected_len || memcmp(mac1, macexpected, mac1_len) != 0)) { testcase_fail("ERROR: derived key #1 does not produce the " "expected HMAC"); goto testcase_cleanup; } rc = run_HMACSign(session, secret_keyB, ecdh_tv[i].derived_key_len, CKM_SHA_1_HMAC, mac2, &mac2_len); if (rc != CKR_OK) { testcase_fail("HMAC for derived key #2 failed: %s", p11_get_ckr(rc)); goto testcase_cleanup; } if (mac2_len != 0 && /* skip check if mac can't be calcualted */ (mac2_len != macexpected_len || memcmp(mac2, macexpected, mac2_len) != 0)) { testcase_fail("ERROR: derived key #2 does not produce the " "expected HMAC"); goto testcase_cleanup; } } testcase_pass("*Derive shared secret i=%lu passed.", i); testcase_next: 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 *mech, CK_ULONG inputlen, CK_ULONG parts, CK_OBJECT_HANDLE priv_key, CK_OBJECT_HANDLE publ_key, enum curve_type curve_type, CK_BYTE *params, CK_ULONG params_len) { CK_BYTE_PTR data = NULL, signature = NULL; CK_ULONG i, signaturelen; CK_MECHANISM_INFO mech_info; CK_RV rc; if ((mech->mechanism == CKM_IBM_ED25519_SHA512 || mech->mechanism == CKM_IBM_ED448_SHA3)) { if (curve_type != CURVE_EDWARDS) { /* Mechanism does not match to curve type, skip */ rc = CKR_OK; goto testcase_cleanup; } if (mech->mechanism == CKM_IBM_ED25519_SHA512 && memcmp(params, ed25519, MIN(params_len, sizeof(ed25519))) != 0) { /* Mechanism does not match to curve, skip */ rc = CKR_OK; goto testcase_cleanup; } if (mech->mechanism == CKM_IBM_ED448_SHA3 && memcmp(params, ed448, MIN(params_len, sizeof(ed448))) != 0) { /* Mechanism does not match to curve, skip */ rc = CKR_OK; goto testcase_cleanup; } } else if (mech->mechanism == CKM_IBM_ECDSA_OTHER && memcmp(params, secp256k1, MIN(params_len, sizeof(secp256k1))) != 0 && memcmp(params, prime256v1, MIN(params_len, sizeof(prime256v1))) != 0 && memcmp(params, brainpoolP256r1, MIN(params_len, sizeof(brainpoolP256r1))) != 0 && memcmp(params, brainpoolP256t1, MIN(params_len, sizeof(brainpoolP256t1))) != 0 && memcmp(params, bls12_381, MIN(params_len, sizeof(bls12_381))) != 0) { /* CKM_IBM_ECDSA_OTHER can only be used with 256-bit or BLS EC curves, skip */ rc = CKR_OK; goto testcase_cleanup; } else if (mech->mechanism == CKM_IBM_ECDSA_OTHER && memcmp(params, bls12_381, MIN(params_len, sizeof(bls12_381))) == 0 && mech->pParameter != NULL && mech->ulParameterLen == sizeof(CK_IBM_ECDSA_OTHER_PARAMS) && ((CK_IBM_ECDSA_OTHER_PARAMS *)mech->pParameter)->submechanism != CKM_IBM_BLS) { /* ECDSA_OTHER: BLS curve can only be used with CKM_IBM_BLS sub mech, skip */ rc = CKR_OK; goto testcase_cleanup; } else if (mech->mechanism == CKM_IBM_ECDSA_OTHER && memcmp(params, bls12_381, MIN(params_len, sizeof(bls12_381))) != 0 && mech->pParameter != NULL && mech->ulParameterLen == sizeof(CK_IBM_ECDSA_OTHER_PARAMS) && ((CK_IBM_ECDSA_OTHER_PARAMS *)mech->pParameter)->submechanism == CKM_IBM_BLS) { /* ECDSA_OTHER: Non-BLS curve can not be used with CKM_IBM_BLS sub mech, skip */ rc = CKR_OK; goto testcase_cleanup; } else if (mech->mechanism == CKM_EDDSA) { if (curve_type != CURVE_EDWARDS) { /* Mechanism does not match to curve type, skip */ rc = CKR_OK; goto testcase_cleanup; } if (memcmp(params, ed448, MIN(params_len, sizeof(ed448))) == 0 && mech->pParameter == NULL) { /* Ed448 requires a mechanism parameter, skip */ rc = CKR_OK; goto testcase_cleanup; } } else if (mech->mechanism != CKM_IBM_ED25519_SHA512 && mech->mechanism != CKM_IBM_ED448_SHA3 && mech->mechanism != CKM_IBM_ECDSA_OTHER && mech->mechanism != CKM_EDDSA) { if (curve_type == CURVE_EDWARDS || curve_type == CURVE_MONTGOMERY || curve_type == CURVE_BLS12_381) { /* Mechanism does not match to curve type, skip */ rc = CKR_OK; goto testcase_cleanup; } } testcase_begin("Starting with mechtype='%s', inputlen=%lu parts=%lu, pkey=%X", p11_get_ckm(&mechtable_funcs, mech->mechanism), inputlen, parts, pkey); /* 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 EC key gen? skip */ testcase_skip("Slot %u doesn't support %s", (unsigned int) SLOT_ID, p11_get_ckm(&mechtable_funcs, mech->mechanism)); rc = CKR_OK; goto testcase_cleanup; } else { testcase_error("C_GetMechanismInfo() rc = %s", p11_get_ckr(rc)); goto testcase_cleanup; } } if (inputlen > 0) { data = calloc(inputlen, sizeof(CK_BYTE)); 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, mech, priv_key); if (rc != CKR_OK) { if (mech->mechanism == CKM_EDDSA && rc == CKR_MECHANISM_PARAM_INVALID) { testcase_skip("EdDSA mechanism parameter combination is not " "supported"); rc = CKR_OK; goto testcase_cleanup; } testcase_error("C_SignInit rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } if (parts > 0) { if (inputlen > 0) { for (i = 0; i < parts && inputlen > 0; 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; } } } else { rc = funcs->C_SignUpdate(session, NULL, 0); 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 != NULL ? data : (CK_BYTE *)"", inputlen, NULL, &signaturelen); if (rc != CKR_OK) { if (mech->mechanism == CKM_EDDSA && rc == CKR_MECHANISM_PARAM_INVALID) { testcase_skip("EdDSA mechanism parameter combination is not " "supported"); rc = CKR_OK; goto testcase_cleanup; } testcase_error("C_Sign rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } } signature = calloc(signaturelen, sizeof(CK_BYTE)); 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 != NULL ? data : (CK_BYTE *)"", inputlen, signature, &signaturelen); if (rc != CKR_OK) { if (mech->mechanism == CKM_EDDSA && rc == CKR_MECHANISM_PARAM_INVALID) { testcase_skip("EdDSA mechanism parameter combination is not " "supported"); rc = CKR_OK; goto testcase_cleanup; } 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; } if (parts > 0) { if (inputlen > 0) { for (i = 0; i < parts && inputlen > 0; 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; } } } else { rc = funcs->C_VerifyUpdate(session, NULL, 0); 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 != NULL ? data : (CK_BYTE *)"", 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; } if (parts > 0) { if (inputlen > 0) { for (i = 0; i < parts && inputlen > 0; 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; } } } else { rc = funcs->C_VerifyUpdate(session, NULL, 0); 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) { if (rc == CKR_FUNCTION_FAILED && is_ica_token(SLOT_ID)) { testcase_notice("C_VerifyFinal rc=%s temporarily accepted for ICA token", p11_get_ckr(rc)); } else { 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 != NULL ? data : (CK_BYTE *)"", inputlen, signature, signaturelen); if (rc != CKR_SIGNATURE_INVALID) { if (rc == CKR_FUNCTION_FAILED && is_ica_token(SLOT_ID)) { testcase_notice("C_Verify rc=%s temporarily accepted for ICA token", p11_get_ckr(rc)); } else { 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(void) { 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 with pkey=%X ...", pkey); testcase_rw_session(); testcase_user_login(); /* Skip tests if pkey = true, but the slot doesn't support protected keys*/ if (pkey && !is_ep11_token(SLOT_ID) && !is_cca_token(SLOT_ID)) { testcase_skip("pkey test option is true, but slot %u doesn't support protected keys", (unsigned int) SLOT_ID); goto testcase_cleanup; } 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) { /* Montgomery curves can not be used for sign/verify. */ continue; } if (is_cca_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].type != CURVE_BRAINPOOL && der_ec_supported[i].type != CURVE_PRIME && der_ec_supported[i].type != CURVE_KOBLITZ) { testcase_skip("Slot %u doesn't support this curve: %s", (unsigned int) SLOT_ID,der_ec_supported[i].name); continue; } } rc = generate_EC_KeyPair(session, CKM_EC_KEY_PAIR_GEN, (CK_BYTE *)der_ec_supported[i].curve, der_ec_supported[i].size, &publ_key, &priv_key, !pkey); if (rc != CKR_OK) { if (is_rejected_by_policy(rc, session)) { testcase_skip("EC key generation is not allowed by policy"); continue; } if (rc == CKR_MECHANISM_PARAM_INVALID || rc == CKR_ATTRIBUTE_VALUE_INVALID || rc == CKR_CURVE_NOT_SUPPORTED) { testcase_skip("Slot %u doesn't support this curve: %s", (unsigned int) SLOT_ID, der_ec_supported[i].name); continue; } testcase_fail ("generate_EC_KeyPair with valid input failed at i=%lu (%s), " "rc=%s", i, der_ec_supported[i].name, p11_get_ckr(rc)); goto testcase_cleanup; } testcase_new_assertion(); testcase_pass("*Generate supported key pair index=%lu (%s) passed.", i, der_ec_supported[i].name); for (j = 0; j < (sizeof(signVerifyInput) / sizeof(_signVerifyParam)); j++) { testcase_new_assertion(); rc = run_GenerateSignVerifyECC(session, &signVerifyInput[j].mech, signVerifyInput[j].inputlen, signVerifyInput[j].parts, priv_key, publ_key, der_ec_supported[i].type, (CK_BYTE *)der_ec_supported[i].curve, der_ec_supported[i].size); if (rc != 0) { testcase_fail("run_GenerateSignVerifyECC failed index=%lu. i=%lu.", j, i); goto testcase_cleanup; } testcase_pass("*Sign & verify i=%lu (%s), j=%lu passed.", i, der_ec_supported[i].name, j); } if (publ_key != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, publ_key); publ_key = CK_INVALID_HANDLE; if (priv_key != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, priv_key); priv_key = CK_INVALID_HANDLE; } for (i = 0; i < NUMECINVAL; i++) { rc = generate_EC_KeyPair(session, CKM_EC_KEY_PAIR_GEN, (CK_BYTE *)der_ec_notsupported[i].curve, der_ec_notsupported[i].size, &publ_key, &priv_key, !pkey); testcase_new_assertion(); if (rc == CKR_OK) { testcase_fail ("generate_EC_KeyPair with invalid input failed at i=%lu (%s)", i, der_ec_notsupported[i].name); goto testcase_cleanup; } testcase_pass("*Generate unsupported key pair curve=%s passed.", der_ec_notsupported[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_user_logout(); testcase_close_session(); return rc; } CK_RV run_ImportECCKeyPairSignVerify(void) { 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 with pkey=%X ...", pkey); testcase_rw_session(); testcase_user_login(); /* Skip tests if pkey = true, but the slot doesn't support protected keys*/ if (pkey && !is_ep11_token(SLOT_ID) && !is_cca_token(SLOT_ID)) { testcase_skip("pkey test option is true, but slot %u doesn't support protected keys", (unsigned int) SLOT_ID); goto testcase_cleanup; } 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) || is_icsf_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; } } if (ec_tv[i].curve_type == CURVE_MONTGOMERY) { /* Sign/verify not supported for the curve. */ continue; } if (ec_tv[i].curve_type == CURVE_EDWARDS) { if (memcmp(ec_tv[i].name, "ed25519", 7) == 0) { if (!mech_supported(SLOT_ID, CKM_IBM_ED25519_SHA512)) { testcase_skip("Slot %u doesn't support CKM_IBM_ED25519_SHA512\n", (unsigned int) SLOT_ID); continue; } } else if (memcmp(ec_tv[i].name, "ed448", 5) == 0) { if (!mech_supported(SLOT_ID, CKM_IBM_ED448_SHA3)) { testcase_skip("Slot %u doesn't support CKM_IBM_ED448_SHA3\n", (unsigned int) SLOT_ID); continue; } } } else { if (!mech_supported(SLOT_ID, CKM_ECDSA)) { testcase_skip("Slot %u doesn't support CKM_ECDSA\n", (unsigned int) SLOT_ID); continue; } } rc = create_ECPrivateKey(session, CKK_EC, ec_tv[i].params, ec_tv[i].params_len, ec_tv[i].privkey, ec_tv[i].privkey_len, &priv_key, !pkey, CK_FALSE); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("EC key import is not allowed by policy"); continue; } if (rc == CKR_CURVE_NOT_SUPPORTED) { testcase_skip("Slot %u doesn't support this curve: %s", (unsigned int) SLOT_ID, ec_tv[i].name); continue; } 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_new_assertion(); testcase_pass("*Import EC private key (%s) index=%lu passed.", ec_tv[i].name, i); rc = create_ECPublicKey(session, CKK_EC, ec_tv[i].params, ec_tv[i].params_len, ec_tv[i].pubkey, ec_tv[i].pubkey_len, &publ_key, !pkey); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("EC key import is not allowed by policy"); funcs->C_DestroyObject(session, priv_key); continue; } if (rc == CKR_CURVE_NOT_SUPPORTED) { testcase_skip("Slot %u doesn't support this curve: %s", (unsigned int) SLOT_ID, ec_tv[i].name); funcs->C_DestroyObject(session, priv_key); continue; } 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_new_assertion(); 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].mech, signVerifyInput[j].inputlen, signVerifyInput[j].parts, priv_key, publ_key, ec_tv[i].curve_type, ec_tv[i].params, ec_tv[i].params_len); 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(void) { 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 with pkey=%X ...", pkey); testcase_rw_session(); testcase_user_login(); /* Skip tests if pkey = true, but the slot doesn't support protected keys*/ if (pkey && !is_ep11_token(SLOT_ID) && !is_cca_token(SLOT_ID)) { testcase_skip("pkey test option is true, but slot %u doesn't support protected keys", (unsigned int) SLOT_ID); goto testcase_cleanup; } 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; } } rc = funcs->C_GetMechanismInfo(SLOT_ID, CKM_AES_KEY_GEN, &mech_info); if (rc != CKR_OK) { if (rc == CKR_MECHANISM_INVALID) { /* no support for AES key gen? skip */ testcase_skip("Slot %u doesn't support CKM_AES_KEY_GEN", (unsigned int) SLOT_ID); goto testcase_cleanup; } else { testcase_error("C_GetMechanismInfo() rc = %s", p11_get_ckr(rc)); goto testcase_cleanup; } } rc = funcs->C_GetMechanismInfo(SLOT_ID, CKM_AES_CBC_PAD, &mech_info); if (rc != CKR_OK) { if (rc == CKR_MECHANISM_INVALID) { /* no support for AES CBC wrap? skip */ testcase_skip("Slot %u doesn't support CKM_AES_CBC_PAD", (unsigned int) SLOT_ID); goto testcase_cleanup; } else { testcase_error("C_GetMechanismInfo() rc = %s", p11_get_ckr(rc)); goto testcase_cleanup; } } if ((mech_info.flags & CKF_WRAP) == 0 || (mech_info.flags & CKF_UNWRAP) == 0) { /* no support for AES CBC wrap? skip */ testcase_skip("Slot %u doesn't support CKM_AES_CBC_PAD for wrapping " "keys", (unsigned int) SLOT_ID); goto testcase_cleanup; } for (i = 0; i < EC_TV_NUM; i++) { if (is_cca_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; } } if (ec_tv[i].curve_type == CURVE_MONTGOMERY) { /* Sign/verify not supported for the curve. */ continue; } if (ec_tv[i].curve_type == CURVE_EDWARDS) { if (memcmp(ec_tv[i].name, "ed25519", 7) == 0) { if (!mech_supported(SLOT_ID, CKM_IBM_ED25519_SHA512)) { testcase_skip("Slot %u doesn't support CKM_IBM_ED25519_SHA512\n", (unsigned int) SLOT_ID); continue; } } else if (memcmp(ec_tv[i].name, "ed448", 5) == 0) { if (!mech_supported(SLOT_ID, CKM_IBM_ED448_SHA3)) { testcase_skip("Slot %u doesn't support CKM_IBM_ED448_SHA3\n", (unsigned int) SLOT_ID); continue; } } } else { if (!mech_supported(SLOT_ID, CKM_ECDSA)) { testcase_skip("Slot %u doesn't support CKM_ECDSA\n", (unsigned int) SLOT_ID); continue; } } rc = create_ECPrivateKey(session, CKK_EC, ec_tv[i].params, ec_tv[i].params_len, ec_tv[i].privkey, ec_tv[i].privkey_len, &priv_key, CK_TRUE, // key to be wrapped must be extractable CK_FALSE); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("EC key import is not allowed by policy"); continue; } if (rc == CKR_CURVE_NOT_SUPPORTED) { testcase_skip("Slot %u doesn't support this curve: %s", (unsigned int) SLOT_ID, ec_tv[i].name); continue; } 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_new_assertion(); testcase_pass("*Import EC private key (%s) index=%lu passed.", ec_tv[i].name, i); rc = create_ECPublicKey(session, CKK_EC, ec_tv[i].params, ec_tv[i].params_len, ec_tv[i].pubkey, ec_tv[i].pubkey_len, &publ_key, !pkey); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("EC key import is not allowed by policy"); funcs->C_DestroyObject(session, priv_key); continue; } if (rc == CKR_CURVE_NOT_SUPPORTED) { testcase_skip("Slot %u doesn't support this curve: %s", (unsigned int) SLOT_ID, ec_tv[i].name); funcs->C_DestroyObject(session, priv_key); continue; } 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_new_assertion(); 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_BBOOL false = FALSE; CK_BBOOL sign = TRUE; CK_BBOOL derive = TRUE; CK_BYTE wrap_key_label[] = "Wrap_Key"; CK_OBJECT_CLASS wclass = CKO_PRIVATE_KEY; CK_KEY_TYPE keyType = CKK_EC; CK_ATTRIBUTE cka_wrap_tmpl[] = { {CKA_PRIVATE, &true, sizeof(true)}, {CKA_CLASS, &wclass, sizeof(wclass)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, }; CK_ATTRIBUTE cka_unwrap_tmpl[] = { {CKA_DECRYPT, &true, sizeof(true)}, {CKA_SIGN, &sign, sizeof(sign)}, {CKA_DERIVE, &derive, sizeof(derive)}, {CKA_PRIVATE, &true, sizeof(true)}, {CKA_IBM_PROTKEY_EXTRACTABLE, &true, sizeof(true)}, {CKA_EXTRACTABLE, &false, sizeof(false)}, }; 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)}, {CKA_WRAP_TEMPLATE, &cka_wrap_tmpl, sizeof(cka_wrap_tmpl)}, {CKA_UNWRAP_TEMPLATE, &cka_unwrap_tmpl, sizeof(cka_unwrap_tmpl)}, }; CK_ULONG secret_tmpl_len = sizeof(secret_tmpl) / sizeof(CK_ATTRIBUTE); if (ec_tv[i].curve_type == CURVE_EDWARDS) derive = FALSE; if (ec_tv[i].curve_type == CURVE_MONTGOMERY) sign = FALSE; if (ec_tv[i].curve_type == CURVE_BLS12_381) { sign = TRUE; derive = TRUE; } if (is_icsf_token(SLOT_ID)) secret_tmpl_len -= 2; /* ICSF does not support array-attributes */ rc = funcs->C_GenerateKey(session, &aes_keygen_mech, secret_tmpl, secret_tmpl_len, &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(wrapped_keylen, sizeof(CK_BYTE)); 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 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_ID, id, sizeof(id)}, {CKA_SENSITIVE, &true, sizeof(true)}, {CKA_DERIVE, &derive, sizeof(derive)}, {CKA_SIGN, &sign, sizeof(sign)}, {CKA_EXTRACTABLE, &false, sizeof(false)}, {CKA_IBM_PROTKEY_EXTRACTABLE, &true, sizeof(true)}, }; CK_ULONG unwrap_tmpl_len = sizeof(unwrap_tmpl) / sizeof(CK_ATTRIBUTE); if (is_icsf_token(SLOT_ID)) unwrap_tmpl_len -= 1; /* ICSF does not supp. CKA_IBM_PROTKEY_... */ rc = funcs->C_UnwrapKey(session, &wrap_mech, secret_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 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].mech, signVerifyInput[j].inputlen, signVerifyInput[j].parts, unwrapped_key, publ_key, ec_tv[i].curve_type, ec_tv[i].params, ec_tv[i].params_len); 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; } /** * Tests the EP11 token protected key option. PKEY_MODE ENABLE4NONEXTR must be * set in ep11tok.conf in order to activate protected key support. With MSA9, * ECDSA with curves p256, p384, p521, and EDDSA with curves ed25519, and * ed448 are supported via CPACF. On older machines there is no CPACF support * for EC/ED at all and therefore all tests are performed only via the ep11 * card. So the actual behavior of this testcase heavily depends on the * machine and token config. */ CK_RV run_ImportSignVerify_Pkey(void) { 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; CK_FLAGS flags; CK_RV rc; CK_OBJECT_CLASS class; CK_KEY_TYPE keytype = CKK_EC; CK_BBOOL true = TRUE; CK_BBOOL extr_priv, pkey_extr_priv, pkey_extr_pub; CK_MECHANISM ec_mech = {CKM_ECDSA, NULL, 0}; CK_MECHANISM ed25519_mech = {CKM_IBM_ED25519_SHA512, NULL, 0}; CK_MECHANISM ed448_mech = {CKM_IBM_ED448_SHA3, NULL, 0}; CK_BYTE data[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, }; CK_BYTE *sig = NULL; CK_ULONG sig_len; unsigned int i, j; testcase_rw_session(); testcase_user_login(); /* Skip tests if pkey = true, but the slot doesn't support protected keys*/ if (pkey && !is_ep11_token(SLOT_ID) && !is_cca_token(SLOT_ID)) { testcase_skip("pkey test option is true, but slot %u doesn't support protected keys", (unsigned int) SLOT_ID); goto testcase_cleanup; } for (i = 0; i < EC_TV_NUM; i++) { CK_ATTRIBUTE priv_tmpl[] = { {CKA_CLASS, &class, sizeof(CK_OBJECT_CLASS)}, {CKA_KEY_TYPE, &keytype, sizeof(CK_KEY_TYPE)}, {CKA_PRIVATE, &true, sizeof(CK_BBOOL)}, {CKA_SIGN, &true, sizeof(CK_BBOOL)}, {CKA_EC_PARAMS, ec_tv[i].params, ec_tv[i].params_len}, {CKA_EC_POINT, ec_tv[i].pubkey, ec_tv[i].pubkey_len}, {CKA_VALUE, ec_tv[i].privkey, ec_tv[i].privkey_len}, {CKA_EXTRACTABLE, &extr_priv, sizeof(CK_BBOOL)}, {CKA_IBM_PROTKEY_EXTRACTABLE, &pkey_extr_priv, sizeof(CK_BBOOL)}, }; CK_ATTRIBUTE publ_tmpl[] = { {CKA_CLASS, &class, sizeof(CK_OBJECT_CLASS)}, {CKA_KEY_TYPE, &keytype, sizeof(CK_KEY_TYPE)}, {CKA_VERIFY, &true, sizeof(CK_BBOOL)}, {CKA_EC_PARAMS, ec_tv[i].params, ec_tv[i].params_len}, {CKA_EC_POINT, ec_tv[i].pubkey, ec_tv[i].pubkey_len}, {CKA_IBM_PROTKEY_EXTRACTABLE, &pkey_extr_pub, sizeof(CK_BBOOL)}, }; if (ec_tv[i].curve_type == CURVE_MONTGOMERY) { /* Sign/verify not supported for the curve. */ continue; } if (ec_tv[i].curve_type == CURVE_EDWARDS) { if (memcmp(ec_tv[i].name, "ed25519", 7) == 0) { if (!mech_supported(SLOT_ID, CKM_IBM_ED25519_SHA512)) { testcase_skip("Slot %u doesn't support CKM_IBM_ED25519_SHA512\n", (unsigned int) SLOT_ID); continue; } } else if (memcmp(ec_tv[i].name, "ed448", 5) == 0) { if (!mech_supported(SLOT_ID, CKM_IBM_ED448_SHA3)) { testcase_skip("Slot %u doesn't support CKM_IBM_ED448_SHA3\n", (unsigned int) SLOT_ID); continue; } } } else { if (!mech_supported(SLOT_ID, CKM_ECDSA)) { testcase_skip("Slot %u doesn't support CKM_ECDSA\n", (unsigned int) SLOT_ID); continue; } } for (j = 0; j < 2; j++) { if (ec_tv[i].curve_type == CURVE_BLS12_381) { /* BLS does not use protected keys, skip */ continue; } if (j == 0) testcase_begin("Starting Import EC private key (%s) index=%u sign via CPACF / verify via card", ec_tv[i].name, i); else testcase_begin("Starting Import EC private key (%s) index=%u sign via card / verify via CPACF", ec_tv[i].name, i); /* j toggles between sign via protected key / verify via card * and vice versa. */ if (j == 0) { extr_priv = FALSE; pkey_extr_priv = TRUE; pkey_extr_pub = FALSE; } else { extr_priv = TRUE; pkey_extr_priv = FALSE; pkey_extr_pub = TRUE; } class = CKO_PRIVATE_KEY; rc = funcs->C_CreateObject(session, priv_tmpl, sizeof(priv_tmpl) / sizeof(CK_ATTRIBUTE), &priv_key); if (rc != CKR_OK) { if (is_rejected_by_policy(rc, session)) { testcase_skip("EC key generation is not allowed by policy"); continue; } if (rc == CKR_CURVE_NOT_SUPPORTED) { testcase_skip("Slot %u doesn't support this curve: %s", (unsigned int) SLOT_ID, ec_tv[i].name); continue; } testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } class = CKO_PUBLIC_KEY; rc = funcs->C_CreateObject(session, publ_tmpl, sizeof(publ_tmpl) / sizeof(CK_ATTRIBUTE), &publ_key); if (rc != CKR_OK) { if (is_rejected_by_policy(rc, session)) { testcase_skip("EC key generation is not allowed by policy"); goto testcase_cleanup; } testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } if (ec_tv[i].curve_type != CURVE_EDWARDS && ec_tv[i].curve_type != CURVE_MONTGOMERY) rc = funcs->C_SignInit(session, &ec_mech, priv_key); else if (memcmp(ec_tv[i].name, "ed25519", 7) == 0) rc = funcs->C_SignInit(session, &ed25519_mech, priv_key); else if (memcmp(ec_tv[i].name, "ed448", 5) == 0) rc = funcs->C_SignInit(session, &ed448_mech, priv_key); else { /* Sign/verify not supported for the curve. */ continue; } if (rc != CKR_OK) { testcase_error("C_SignInit rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } testcase_new_assertion(); rc = funcs->C_Sign(session, data, sizeof(data), NULL, &sig_len); if (rc != CKR_OK) { testcase_error("C_Sign rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } sig = calloc(sig_len, sizeof(CK_BYTE)); if (sig == NULL) { testcase_error("Can't allocate memory for %lu bytes", sig_len); rc = CKR_HOST_MEMORY; goto testcase_cleanup; } rc = funcs->C_Sign(session, data, sizeof(data), sig, &sig_len); if (rc != CKR_OK) { testcase_error("C_Sign rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } if (ec_tv[i].curve_type != CURVE_EDWARDS && ec_tv[i].curve_type != CURVE_MONTGOMERY) rc = funcs->C_VerifyInit(session, &ec_mech, publ_key); else if (memcmp(ec_tv[i].name, "ed25519", 7) == 0) rc = funcs->C_VerifyInit(session, &ed25519_mech, publ_key); else rc = funcs->C_VerifyInit(session, &ed448_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, sizeof(data), sig, sig_len); if (rc != CKR_OK) { testcase_error("C_Verify rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } if (sig) { free(sig); sig = NULL; } if (j == 0) testcase_pass("*Import EC private key (%s) index=%u sign via CPACF / verify via card passed.", ec_tv[i].name, i); else testcase_pass("*Import EC private key (%s) index=%u sign via card / verify via CPACF passed.", ec_tv[i].name, i); } } 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); if (sig) free(sig); testcase_close_session(); return rc; } struct btc_test { const _ec_struct ec; CK_ULONG master_key_derive; CK_ULONG priv_to_pub; CK_ULONG priv_to_priv; CK_ULONG pub_to_pub; }; static const struct btc_test btc_tests[] = { { .ec = { &secp256k1, sizeof(secp256k1), CK_FALSE, CURVE_KOBLITZ, CURVE256_LENGTH, "secp256k1" }, .master_key_derive = CK_IBM_BTC_BIP0032_MASTERK, .priv_to_pub = CK_IBM_BTC_BIP0032_PRV2PUB, .priv_to_priv = CK_IBM_BTC_BIP0032_PRV2PRV, .pub_to_pub = CK_IBM_BTC_BIP0032_PUB2PUB, }, { .ec = { &secp256k1, sizeof(secp256k1), CK_FALSE, CURVE_KOBLITZ, CURVE256_LENGTH, "secp256k1" }, .master_key_derive = CK_IBM_BTC_SLIP0010_MASTERK, .priv_to_pub = CK_IBM_BTC_SLIP0010_PRV2PUB, .priv_to_priv = CK_IBM_BTC_SLIP0010_PRV2PRV, .pub_to_pub = CK_IBM_BTC_SLIP0010_PUB2PUB, }, { .ec = { &prime256v1, sizeof(prime256v1), CK_FALSE, CURVE_PRIME, CURVE256_LENGTH, "prime256v1" }, .master_key_derive = CK_IBM_BTC_SLIP0010_MASTERK, .priv_to_pub = CK_IBM_BTC_SLIP0010_PRV2PUB, .priv_to_priv = CK_IBM_BTC_SLIP0010_PRV2PRV, .pub_to_pub = CK_IBM_BTC_SLIP0010_PUB2PUB, }, { .ec = { &ed25519, sizeof(ed25519), CK_FALSE, CURVE_EDWARDS, CURVE256_LENGTH, "ed25519" }, .master_key_derive = CK_IBM_BTC_SLIP0010_MASTERK, .priv_to_pub = CK_IBM_BTC_SLIP0010_PRV2PUB, .priv_to_priv = CK_IBM_BTC_SLIP0010_PRV2PRV, .pub_to_pub = CK_IBM_BTC_SLIP0010_PUB2PUB, }, }; #define NUM_BTC_TESTS 4 static const CK_ULONG btc_child_key_index[] = { 0, 0x12, 0x3456, 0x987654, 0x7fffffff, 0 + CK_IBM_BTC_BIP0032_HARDENED, 0x12 + CK_IBM_BTC_BIP0032_HARDENED, 0x3456 + CK_IBM_BTC_BIP0032_HARDENED, 0x987654 + CK_IBM_BTC_BIP0032_HARDENED, 0x7fffffff + CK_IBM_BTC_BIP0032_HARDENED, }; #define NUM_BTC_CHILD_KEY_INDEXES 10 static const char *btc_type_to_str(CK_ULONG btc_type) { switch (btc_type) { case CK_IBM_BTC_BIP0032_PRV2PRV: return "CK_IBM_BTC_BIP0032_PRV2PRV"; case CK_IBM_BTC_BIP0032_PRV2PUB: return "CK_IBM_BTC_BIP0032_PRV2PUB"; case CK_IBM_BTC_BIP0032_PUB2PUB: return "CK_IBM_BTC_BIP0032_PUB2PUB"; case CK_IBM_BTC_BIP0032_MASTERK: return "CK_IBM_BTC_BIP0032_MASTERK"; case CK_IBM_BTC_SLIP0010_PRV2PRV: return "CK_IBM_BTC_SLIP0010_PRV2PRV"; case CK_IBM_BTC_SLIP0010_PRV2PUB: return "CK_IBM_BTC_SLIP0010_PRV2PUB"; case CK_IBM_BTC_SLIP0010_PUB2PUB: return "CK_IBM_BTC_SLIP0010_PUB2PUB"; case CK_IBM_BTC_SLIP0010_MASTERK: return "CK_IBM_BTC_SLIP0010_MASTERK"; default: return "UNKNOWN"; } } /* * Run Bitcoin Key Derivation tests: * Derive a BTC master key from a generic secret key. Then derive a number of * child keys (public and private, hardened and non hardened) from the master * key. */ CK_RV run_DeriveBTC(void) { CK_SESSION_HANDLE session; CK_MECHANISM mech; CK_FLAGS flags; CK_OBJECT_HANDLE secret = CK_INVALID_HANDLE, master = CK_INVALID_HANDLE; CK_OBJECT_HANDLE child_priv = CK_INVALID_HANDLE, child_pub = CK_INVALID_HANDLE; CK_OBJECT_HANDLE child_pub2 = CK_INVALID_HANDLE; CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; CK_ULONG user_pin_len; CK_RV rc = CKR_OK; CK_BBOOL true = CK_TRUE; CK_IBM_BTC_DERIVE_PARAMS btc_parms; CK_BYTE master_chain_code[CK_IBM_BTC_CHAINCODE_LENGTH]; CK_BYTE child_chain_code[CK_IBM_BTC_CHAINCODE_LENGTH]; CK_OBJECT_CLASS priv_class = CKO_PRIVATE_KEY; CK_OBJECT_CLASS pub_class = CKO_PUBLIC_KEY; CK_KEY_TYPE key_type = CKK_EC; CK_OBJECT_CLASS secret_class = CKO_SECRET_KEY; CK_ULONG secret_keylen = 32; CK_ULONG i, k; testsuite_begin("starting run_DeriveBTC with pkey=%X ...", pkey); testcase_rw_session(); testcase_user_login(); /* Skip tests if pkey = true, but the slot doesn't support protected keys*/ if (pkey && !is_ep11_token(SLOT_ID) && !is_cca_token(SLOT_ID)) { testcase_skip("pkey test option is true, but slot %u doesn't support protected keys", (unsigned int) SLOT_ID); goto testcase_cleanup; } if (!mech_supported(SLOT_ID, CKM_GENERIC_SECRET_KEY_GEN)) { testcase_skip("Slot %u doesn't support CKM_GENERIC_SECRET_KEY_GEN\n", (unsigned int) SLOT_ID); goto testcase_cleanup; } if (!mech_supported(SLOT_ID, CKM_IBM_BTC_DERIVE)) { testcase_skip("Slot %u doesn't support CKM_IBM_BTC_DERIVE\n", (unsigned int) SLOT_ID); goto testcase_cleanup; } for (i = 0; i < NUM_BTC_TESTS; i++) { CK_ATTRIBUTE secret_tmpl[] = { {CKA_CLASS, &secret_class, sizeof(secret_class)}, {CKA_VALUE_LEN, &secret_keylen, sizeof(secret_keylen)}, {CKA_IBM_USE_AS_DATA, &true, sizeof(true)}, }; CK_ULONG secret_tmpl_len = sizeof(secret_tmpl) / sizeof(CK_ATTRIBUTE); CK_ATTRIBUTE priv_derive_tmpl[] = { {CKA_CLASS, &priv_class, sizeof(priv_class)}, {CKA_KEY_TYPE, &key_type, sizeof(key_type)}, {CKA_DERIVE, &true, sizeof(true)}, {CKA_EC_PARAMS, (CK_VOID_PTR)btc_tests[i].ec.curve, btc_tests[i].ec.size}, {CKA_IBM_USE_AS_DATA, &true, sizeof(true)}, }; CK_ULONG priv_derive_tmpl_len = sizeof(priv_derive_tmpl) / sizeof(CK_ATTRIBUTE); CK_ATTRIBUTE pub_derive_tmpl[] = { {CKA_CLASS, &pub_class, sizeof(pub_class)}, {CKA_KEY_TYPE, &key_type, sizeof(key_type)}, {CKA_DERIVE, &true, sizeof(true)}, {CKA_EC_PARAMS, (CK_VOID_PTR)btc_tests[i].ec.curve, btc_tests[i].ec.size}, {CKA_IBM_USE_AS_DATA, &true, sizeof(true)}, }; CK_ULONG pub_derive_tmpl_len = sizeof(pub_derive_tmpl) / sizeof(CK_ATTRIBUTE); /* Testcase #1: Derive the BTC master key from a secret key */ testcase_new_assertion(); testcase_begin("BTC master key derive with curve=%s and type=%s, pkey=%X", btc_tests[i].ec.name, btc_type_to_str(btc_tests[i].master_key_derive), pkey); mech.mechanism = CKM_GENERIC_SECRET_KEY_GEN; mech.ulParameterLen = 0; mech.pParameter = NULL; rc = funcs->C_GenerateKey(session, &mech, secret_tmpl, secret_tmpl_len, &secret); if (rc != CKR_OK) { testcase_fail("C_GenerateKey, rc=%s", p11_get_ckr(rc)); goto run_cleanup; } mech.mechanism = CKM_IBM_BTC_DERIVE; mech.ulParameterLen = sizeof(CK_IBM_BTC_DERIVE_PARAMS); mech.pParameter = &btc_parms; memset(master_chain_code, 0, sizeof(master_chain_code)); memset(&btc_parms, 0, sizeof(btc_parms)); btc_parms.version = CK_IBM_BTC_DERIVE_PARAMS_VERSION_1; btc_parms.type = btc_tests[i].master_key_derive; btc_parms.childKeyIndex = 0; btc_parms.ulChainCodeLen = 0; btc_parms.pChainCode = master_chain_code; rc = funcs->C_DeriveKey(session, &mech, secret, priv_derive_tmpl, priv_derive_tmpl_len, &master); if (rc != CKR_OK) { testcase_fail("C_DeriveKey BTC master key: rc = %s", p11_get_ckr(rc)); goto run_cleanup; } testcase_pass("BTC master key derive with curve=%s and type=%s, pkey=%X", btc_tests[i].ec.name, btc_type_to_str(btc_tests[i].master_key_derive), pkey); /* Derive child keys from the master key */ for (k = 0; k < NUM_BTC_CHILD_KEY_INDEXES; k++) { /* Testcase #2: Derive private child key from private master key */ /* For ed25519 only hardened child keys are supported (SLIP0010) */ if (btc_tests[i].master_key_derive == CK_IBM_BTC_SLIP0010_MASTERK && btc_tests[i].ec.type == CURVE_EDWARDS && (btc_child_key_index[k] & CK_IBM_BTC_BIP0032_HARDENED) == 0) continue; testcase_new_assertion(); testcase_begin("BTC priv-to-priv child key derive with curve=%s child-key-index=0x%lx and type=%s, pkey=%X", btc_tests[i].ec.name, btc_child_key_index[k], btc_type_to_str(btc_tests[i].priv_to_priv), pkey); mech.mechanism = CKM_IBM_BTC_DERIVE; mech.ulParameterLen = sizeof(CK_IBM_BTC_DERIVE_PARAMS); mech.pParameter = &btc_parms; memcpy(child_chain_code, master_chain_code, sizeof(master_chain_code)); memset(&btc_parms, 0, sizeof(btc_parms)); btc_parms.version = CK_IBM_BTC_DERIVE_PARAMS_VERSION_1; btc_parms.type = btc_tests[i].priv_to_priv; btc_parms.childKeyIndex = btc_child_key_index[k]; btc_parms.ulChainCodeLen = sizeof(child_chain_code); btc_parms.pChainCode = child_chain_code; rc = funcs->C_DeriveKey(session, &mech, master, priv_derive_tmpl, priv_derive_tmpl_len, &child_priv); if (rc != CKR_OK) { testcase_fail("C_DeriveKey BTC child key (priv): rc = %s", p11_get_ckr(rc)); goto run_child_cleanup; } testcase_pass("BTC priv-to-priv child key derive with curve=%s child-key-index=0x%lx and type=%s, pkey=%X", btc_tests[i].ec.name, btc_child_key_index[k], btc_type_to_str(btc_tests[i].priv_to_priv), pkey); /* Testcase #3: Derive public child key from private master key */ testcase_new_assertion(); testcase_begin("BTC priv-to-pub child key derive with curve=%s child-key-index=0x%lx and type=%s, pkey=%X", btc_tests[i].ec.name, btc_child_key_index[k], btc_type_to_str(btc_tests[i].priv_to_pub), pkey); mech.mechanism = CKM_IBM_BTC_DERIVE; mech.ulParameterLen = sizeof(CK_IBM_BTC_DERIVE_PARAMS); mech.pParameter = &btc_parms; memcpy(child_chain_code, master_chain_code, sizeof(master_chain_code)); memset(&btc_parms, 0, sizeof(btc_parms)); btc_parms.version = CK_IBM_BTC_DERIVE_PARAMS_VERSION_1; btc_parms.type = btc_tests[i].priv_to_pub; btc_parms.childKeyIndex = btc_child_key_index[k]; btc_parms.ulChainCodeLen = sizeof(child_chain_code); btc_parms.pChainCode = child_chain_code; rc = funcs->C_DeriveKey(session, &mech, master, pub_derive_tmpl, pub_derive_tmpl_len, &child_pub); if (rc != CKR_OK) { testcase_fail("C_DeriveKey BTC child key (pub): rc = %s", p11_get_ckr(rc)); goto run_child_cleanup; } testcase_pass("BTC priv-to-pub child key derive with curve=%s child-key-index=0x%lx and type=%s, pkey=%X", btc_tests[i].ec.name, btc_child_key_index[k], btc_type_to_str(btc_tests[i].priv_to_pub), pkey); /* Testcase #4: Test if derived keys are usable */ testcase_new_assertion(); if (btc_tests[i].ec.type == CURVE_EDWARDS) mech.mechanism = CKM_IBM_ED25519_SHA512; else mech.mechanism = CKM_ECDSA; mech.ulParameterLen = 0; mech.pParameter = NULL; rc = run_GenerateSignVerifyECC(session, &mech, 20, 0, child_priv, child_pub, btc_tests[i].ec.type, (CK_BYTE *)btc_tests[i].ec.curve, btc_tests[i].ec.size); if (rc != 0) { testcase_fail("run_GenerateSignVerifyECC failed."); goto testcase_cleanup; } testcase_pass("BTC check derived keys with curve=%s child-key-index=0x%lx, pkey=%X", btc_tests[i].ec.name, btc_child_key_index[k], pkey); /* * Testcase #5: Derive public child key from public key * (non-hardened keys only, thus not supported for ed25519) */ if ((btc_child_key_index[k] & CK_IBM_BTC_BIP0032_HARDENED) != 0) goto run_child_cleanup; testcase_new_assertion(); testcase_begin("BTC pub-to-pub child key derive with curve=%s child-key-index=0x%lx and type=%s, pkey=%X", btc_tests[i].ec.name, btc_child_key_index[k], btc_type_to_str(btc_tests[i].pub_to_pub), pkey); mech.mechanism = CKM_IBM_BTC_DERIVE; mech.ulParameterLen = sizeof(CK_IBM_BTC_DERIVE_PARAMS); mech.pParameter = &btc_parms; memset(&btc_parms, 0, sizeof(btc_parms)); btc_parms.version = CK_IBM_BTC_DERIVE_PARAMS_VERSION_1; btc_parms.type = btc_tests[i].pub_to_pub; btc_parms.childKeyIndex = btc_child_key_index[k]; btc_parms.ulChainCodeLen = sizeof(child_chain_code); btc_parms.pChainCode = child_chain_code; rc = funcs->C_DeriveKey(session, &mech, child_pub, pub_derive_tmpl, pub_derive_tmpl_len, &child_pub2); if (rc != CKR_OK) { testcase_fail("C_DeriveKey BTC child key (pub): rc = %s", p11_get_ckr(rc)); goto run_child_cleanup; } testcase_pass("BTC pub-to-pub child key derive with curve=%s child-key-index=0x%lx and type=%s, pkey=%X", btc_tests[i].ec.name, btc_child_key_index[k], btc_type_to_str(btc_tests[i].pub_to_pub), pkey); run_child_cleanup: if (child_priv != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, child_priv); child_priv = CK_INVALID_HANDLE; if (child_pub != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, child_pub); child_pub = CK_INVALID_HANDLE; if (child_pub2 != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, child_pub2); child_pub2 = CK_INVALID_HANDLE; } run_cleanup: if (secret != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, secret); secret = CK_INVALID_HANDLE; if (master != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, master); master = CK_INVALID_HANDLE; } testcase_cleanup: if (secret != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, secret); if (master != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, master); testcase_user_logout(); testcase_close_session(); return rc; } /* end run_DeriveBTC() */ _ec_struct bls_test = {&bls12_381, sizeof(bls12_381), CK_TRUE, CURVE_BLS12_381, CURVE384_LENGTH, "bls12_381"}; _signVerifyParam bls_test_input = {{CKM_IBM_ECDSA_OTHER, &other_bls, sizeof(other_bls)}, 20, 0, ""}; /* * BLS test for Sign and derive */ CK_RV run_BLSAggregation(void) { CK_MECHANISM mech; CK_OBJECT_HANDLE priv_key[CK_IBM_BLS_MAX_AGGREGATIONS] = { CK_INVALID_HANDLE }, pub_key[CK_IBM_BLS_MAX_AGGREGATIONS] = { CK_INVALID_HANDLE }; CK_IBM_ECDSA_OTHER_BLS_PARAMS blsparam1, blsparam2; CK_OBJECT_HANDLE aggpubkey = CK_INVALID_HANDLE; CK_ULONG signatlen = CK_IBM_BLS12_381_SIGN_LEN; CK_BYTE aggsignature[1000]; CK_BYTE signature[CK_IBM_BLS_MAX_AGGREGATIONS][CK_IBM_BLS12_381_SIGN_LEN]; CK_ULONG aggsignaturelen = CK_IBM_BLS12_381_SIGN_LEN; CK_SESSION_HANDLE session; CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; CK_ULONG user_pin_len, k, numElements = 10; CK_FLAGS flags; CK_RV rc; CK_BYTE message[32]; CK_BBOOL lotrue = CK_TRUE; CK_IBM_ECDSA_OTHER_PARAMS *param; CK_ATTRIBUTE publicKeyTemplate[] = { { CKA_EC_PARAMS, (CK_BYTE *)bls_test.curve, bls_test.size }, { CKA_VERIFY, &lotrue, sizeof(lotrue) }, { CKA_DERIVE, &lotrue, sizeof(lotrue) }, }; CK_ULONG pub_derive_tmpl_len = sizeof(publicKeyTemplate) / sizeof(CK_ATTRIBUTE); testsuite_begin("Starting run_BLSAggregation"); testcase_rw_session(); testcase_user_login(); /* Skip tests if not EP11 token*/ if (!is_ep11_token(SLOT_ID)) { testcase_skip("Slot %u doesn't support BLS aggregation", (unsigned int) SLOT_ID); goto testcase_cleanup; } if (!mech_supported(SLOT_ID, bls_test_input.mech.mechanism)) { testcase_skip("Slot %u doesn't support %s\n", (unsigned int) SLOT_ID, mech_to_str(bls_test_input.mech.mechanism)); rc = CKR_OK; goto testcase_cleanup; } if (!mech_supported(SLOT_ID, CKM_IBM_EC_AGGREGATE)) { testcase_skip("Slot %u doesn't support %s\n", (unsigned int) SLOT_ID, mech_to_str(CKM_IBM_EC_AGGREGATE)); rc = CKR_OK; goto testcase_cleanup; } for (k = 0; k < numElements; k++) { testcase_new_assertion(); testcase_begin("Generate key pair with for index %lu", k); rc = generate_EC_KeyPair(session, CKM_EC_KEY_PAIR_GEN, (CK_BYTE *)bls_test.curve, bls_test.size, &pub_key[k], &priv_key[k], !pkey); if (rc != CKR_OK) { if (is_rejected_by_policy(rc, session)) { testcase_skip("EC key generation is not allowed by policy"); goto testcase_cleanup;; } if (rc == CKR_MECHANISM_PARAM_INVALID || rc == CKR_ATTRIBUTE_VALUE_INVALID || rc == CKR_CURVE_NOT_SUPPORTED) { testcase_skip("Slot %u doesn't support this curve: %s", (unsigned int) SLOT_ID, bls_test.name); goto testcase_cleanup;; } testcase_fail("generate_EC_KeyPair with valid input failed (%s), " "rc=%s", bls_test.name, p11_get_ckr(rc)); goto testcase_cleanup; } testcase_pass("*Generate supported key pair (%s) passed.", bls_test.name); blsparam1.pAggrElements[k] = (CK_OBJECT_HANDLE_PTR)&(pub_key[k]); } blsparam1.numElements = numElements; blsparam1.elementSize = sizeof(CK_OBJECT_HANDLE_PTR); blsparam2.numElements = numElements; blsparam2.elementSize = CK_IBM_BLS12_381_SIGN_LEN; for (k = 0; k < bls_test_input.inputlen; k++) { message[k] = (k + 1) % 255; } for (k = 0; k < blsparam1.numElements; k++) { testcase_new_assertion(); testcase_begin("Starting sign/verify with mechtype='%s', inputlen=%lu " "parts=%lu, index=%lu", p11_get_ckm(&mechtable_funcs, bls_test_input.mech.mechanism), bls_test_input.inputlen, bls_test_input.parts, k); param = (CK_IBM_ECDSA_OTHER_PARAMS *)bls_test_input.mech.pParameter; if (param->submechanism != CKM_IBM_BLS) { goto testcase_cleanup; } /****** Sign *******/ rc = funcs->C_SignInit(session, &bls_test_input.mech, priv_key[k]); if (rc != CKR_OK) { testcase_error("C_SignInit rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } rc = funcs->C_Sign(session, message, bls_test_input.inputlen, signature[k], &signatlen); if (rc != 0) { testcase_fail("C_Sign failed index=%lu.", k); goto testcase_cleanup; } /****** Verify *******/ rc = funcs->C_VerifyInit(session, &bls_test_input.mech, *(CK_OBJECT_HANDLE_PTR) blsparam1.pAggrElements[k]); if (rc != CKR_OK) { testcase_error("C_VerifyInit rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } rc = funcs->C_Verify(session, message, bls_test_input.inputlen, signature[k], signatlen); if (rc != CKR_OK) { testcase_error("C_Verify rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } testcase_pass("*Sign & verify k=%lu, passed.", k); blsparam2.pAggrElements[k] = (CK_BYTE_PTR)&(signature[k][0]); } mech.mechanism = CKM_IBM_EC_AGGREGATE; mech.pParameter = &blsparam2; mech.ulParameterLen = sizeof(blsparam2); testcase_new_assertion(); testcase_begin("Starting BLS signature aggregation "); rc = funcs->C_SignInit(session, &mech, CK_INVALID_HANDLE); if (rc != CKR_OK) { testcase_error("C_SignInit rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } rc = funcs->C_Sign(session, NULL, 0, NULL, &aggsignaturelen); if (rc != CKR_OK) { testcase_error("C_Sign rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } rc = funcs->C_Sign(session, NULL, 0, aggsignature, &aggsignaturelen); if (rc != CKR_OK) { testcase_error("C_Sign rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } testcase_pass("*BLS signature aggregation passed."); testcase_new_assertion(); testcase_begin("Starting BLS public key aggregation "); mech.mechanism = CKM_IBM_EC_AGGREGATE; mech.pParameter = &blsparam1; mech.ulParameterLen = sizeof(blsparam1); rc = funcs->C_DeriveKey(session, &mech, CK_INVALID_HANDLE, publicKeyTemplate, pub_derive_tmpl_len, &aggpubkey); if (rc != CKR_OK) { testcase_error("C_Derive rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } testcase_pass("*BLS Public key aggregation passed."); testcase_new_assertion(); testcase_begin("Starting BLS aggregation verification"); rc = funcs->C_VerifyInit(session, &bls_test_input.mech, aggpubkey); if (rc != CKR_OK) { testcase_error("C_VerifyInit rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } rc = funcs->C_Verify(session, message, bls_test_input.inputlen, &(aggsignature[0]), aggsignaturelen); if (rc != CKR_OK) { testcase_error("C_Verify rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } testcase_pass("*Verification aggregation passed."); testcase_cleanup: for (k = 0; k < numElements; k++) { if (pub_key[k] != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, pub_key[k]); if (priv_key[k] != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, priv_key[k]); } if (aggpubkey != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, aggpubkey); testcase_user_logout(); testcase_close_session(); return rc; } #define NUMED 4 const _ec_struct der_ec_edwards_supported[NUMED] = { {&curve25519, sizeof(curve25519), CK_FALSE, CURVE_MONTGOMERY, CURVE256_LENGTH, "curve25519"}, {&curve448, sizeof(curve448), CK_FALSE, CURVE_MONTGOMERY, CURVE448_LENGTH, "curve448"}, {&ed25519, sizeof(ed25519), CK_FALSE, CURVE_EDWARDS, CURVE256_LENGTH, "ed25519"}, {&ed448, sizeof(ed448), CK_FALSE, CURVE_EDWARDS, CURVE456_LENGTH, "ed448"}, }; CK_BYTE eddsa_ctx_data[] = { 0x01, 0x23, 0x45, 0x67, 0x89 }; CK_EDDSA_PARAMS eddsa_none = { FALSE, 0, NULL }; CK_EDDSA_PARAMS eddsa_ph = { TRUE, 0, NULL }; CK_EDDSA_PARAMS eddsa_ctx = { FALSE, sizeof(eddsa_ctx_data), eddsa_ctx_data }; CK_EDDSA_PARAMS eddsa_ph_ctx = { TRUE, sizeof(eddsa_ctx_data), eddsa_ctx_data }; _signVerifyParam edwardsSignVerifyInput[] = { {{CKM_EDDSA, NULL, 0}, 20, 0, ""}, {{CKM_EDDSA, NULL, 0}, 32, 0, ""}, {{CKM_EDDSA, NULL, 0}, 48, 0, ""}, {{CKM_EDDSA, NULL, 0}, 64, 0, ""}, {{CKM_EDDSA, &eddsa_none, sizeof(eddsa_none)}, 64, 0, "Neither Pre-Hash nor Context"}, {{CKM_EDDSA, &eddsa_ph, sizeof(eddsa_ph)}, 64, 0, "Pre-Hash"}, {{CKM_EDDSA, &eddsa_ctx, sizeof(eddsa_ctx)}, 64, 0, "Context"}, {{CKM_EDDSA, &eddsa_ph_ctx, sizeof(eddsa_ph_ctx)}, 64, 0, "Pre-Hash & Context"}, }; CK_RV run_GenerateEdwardsKeyPairSignVerify(void) { 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 = 0, j; CK_FLAGS flags; CK_MECHANISM_INFO mech_info; CK_RV rc; testcase_begin("Starting Edwards generate key pair with pkey=%X ...", pkey); testcase_rw_session(); testcase_user_login(); /* Skip tests if pkey = true, but the slot doesn't support protected keys*/ if (pkey && !is_ep11_token(SLOT_ID) && !is_cca_token(SLOT_ID)) { testcase_skip("pkey test option is true, but slot %u doesn't support " "protected keys", (unsigned int) SLOT_ID); goto done; } mech.mechanism = CKM_EC_EDWARDS_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_EDWARDS_KEY_PAIR_GEN", (unsigned int) SLOT_ID); rc = CKR_OK; goto done; } else { testcase_error("C_GetMechanismInfo() rc = %s", p11_get_ckr(rc)); goto done; } } for (i = 0; i < NUMED; i++) { if (der_ec_edwards_supported[i].type != CURVE_EDWARDS) continue; rc = generate_EC_KeyPair(session, CKM_EC_EDWARDS_KEY_PAIR_GEN, (CK_BYTE *)der_ec_edwards_supported[i].curve, der_ec_edwards_supported[i].size, &publ_key, &priv_key, !pkey); if (rc != CKR_OK) { if (is_rejected_by_policy(rc, session)) { testcase_skip("EC key generation is not allowed by policy"); continue; } if (rc == CKR_MECHANISM_PARAM_INVALID || rc == CKR_ATTRIBUTE_VALUE_INVALID || rc == CKR_CURVE_NOT_SUPPORTED) { testcase_skip("Slot %u doesn't support this curve: %s", (unsigned int) SLOT_ID, der_ec_edwards_supported[i].name); continue; } testcase_fail ("generate_EC_KeyPair with valid input failed at i=%lu (%s), " "rc=%s", i, der_ec_edwards_supported[i].name, p11_get_ckr(rc)); goto testcase_cleanup; } testcase_new_assertion(); testcase_pass("*Generate supported key pair index=%lu (%s) passed.", i, der_ec_edwards_supported[i].name); for (j = 0; j < (sizeof(edwardsSignVerifyInput) / sizeof(_signVerifyParam)); j++) { if (memcmp(der_ec_edwards_supported[i].curve, ed448, MIN(der_ec_edwards_supported[i].size, sizeof(ed448))) == 0 && edwardsSignVerifyInput[j].mech.pParameter == NULL) { /* Ed448 requires a mechanism parameter, skip */ continue; } testcase_new_assertion(); rc = run_GenerateSignVerifyECC(session, &edwardsSignVerifyInput[j].mech, edwardsSignVerifyInput[j].inputlen, edwardsSignVerifyInput[j].parts, priv_key, publ_key, der_ec_edwards_supported[i].type, (CK_BYTE *)der_ec_edwards_supported[i].curve, der_ec_edwards_supported[i].size); if (rc != 0) { testcase_fail("run_GenerateSignVerifyECC failed index=%lu (%s).", j, edwardsSignVerifyInput[j].name); goto testcase_cleanup; } testcase_pass("*Sign & verify %s i=%lu (%s), j=%lu passed.", edwardsSignVerifyInput[j].name, i, der_ec_edwards_supported[i].name, j); } testcase_cleanup: if (publ_key != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, publ_key); publ_key = CK_INVALID_HANDLE; if (priv_key != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, priv_key); priv_key = CK_INVALID_HANDLE; } rc = CKR_OK; 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_ImportEdwardsKeyPairSignVerifyKAT(void) { 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 = 0, signaturelen; CK_FLAGS flags; CK_MECHANISM_INFO mech_info; CK_EDDSA_PARAMS eddsa_param; CK_BYTE signature[128]; CK_RV rc; testcase_begin("Starting Edwards import key pair with pkey=%X ...", pkey); testcase_rw_session(); testcase_user_login(); /* Skip tests if pkey = true, but the slot doesn't support protected keys*/ if (pkey && !is_ep11_token(SLOT_ID) && !is_cca_token(SLOT_ID)) { testcase_skip("pkey test option is true, but slot %u doesn't support " "protected keys", (unsigned int) SLOT_ID); goto done; } mech.mechanism = CKM_EDDSA; 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_EDDSA", (unsigned int) SLOT_ID); goto done; } else { testcase_error("C_GetMechanismInfo() rc = %s", p11_get_ckr(rc)); goto done; } } for (i = 0; i < ED_TV_NUM; i++) { rc = create_ECPrivateKey(session, CKK_EC_EDWARDS, ed_tv[i].params, ed_tv[i].params_len, ed_tv[i].privkey, ed_tv[i].privkey_len, &priv_key, !pkey, CK_FALSE); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("EC-Edwards key import is not allowed by policy"); continue; } if (rc == CKR_CURVE_NOT_SUPPORTED) { testcase_skip("Slot %u doesn't support this curve: %s", (unsigned int) SLOT_ID, ed_tv[i].name); continue; } testcase_fail("C_CreateObject (EC-Edwards Private Key) failed at " "i=%lu (%s), rc=%s", i, ed_tv[i].name, p11_get_ckr(rc)); goto testcase_cleanup; } testcase_new_assertion(); testcase_pass("*Import EC-Edwards private key (%s) index=%lu passed.", ed_tv[i].name, i); rc = create_ECPublicKey(session, CKK_EC_EDWARDS, ed_tv[i].params, ed_tv[i].params_len, ed_tv[i].pubkey, ed_tv[i].pubkey_len, &publ_key, !pkey); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("EC-Edwards key import is not allowed by policy"); funcs->C_DestroyObject(session, priv_key); continue; } if (rc == CKR_CURVE_NOT_SUPPORTED) { testcase_skip("Slot %u doesn't support this curve: %s", (unsigned int) SLOT_ID, ed_tv[i].name); funcs->C_DestroyObject(session, priv_key); continue; } testcase_fail("C_CreateObject (EC-Edwards Public Key) failed at " "i=%lu (%s), rc=%s", i, ed_tv[i].name, p11_get_ckr(rc)); goto testcase_cleanup; } testcase_new_assertion(); testcase_pass("*Import EC-Edwards public key (%s) index=%lu passed.", ed_tv[i].name, i); if (ed_tv[i].mech_param) { eddsa_param.phFlag = ed_tv[i].prehash; eddsa_param.pContextData = ed_tv[i].ctx; eddsa_param.ulContextDataLen = ed_tv[i].ctx_len; mech.pParameter = &eddsa_param; mech.ulParameterLen = sizeof(eddsa_param); } else { mech.pParameter = NULL; mech.ulParameterLen = 0; } /* create signature with private key */ rc = funcs->C_SignInit(session, &mech, priv_key); if (rc != CKR_OK) { if (rc == CKR_MECHANISM_PARAM_INVALID) { testcase_skip("EdDSA mechanism parameter combination is not " "supported (%s)", ed_tv[i].name); rc = CKR_OK; goto testcase_cleanup; } testcase_error("C_SignInit rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } memset(signature, 0, sizeof(signature)); signaturelen = sizeof(signature); rc = funcs->C_Sign(session, ed_tv[i].msg, ed_tv[i].msg_len, signature, &signaturelen); if (rc != CKR_OK) { if (rc == CKR_MECHANISM_PARAM_INVALID) { testcase_skip("EdDSA mechanism parameter combination is not " "supported (%s)", ed_tv[i].name); rc = CKR_OK; goto testcase_cleanup; } testcase_error("C_Sign rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } /* Verify signature with public key */ 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, ed_tv[i].msg, ed_tv[i].msg_len, signature, signaturelen); if (rc != CKR_OK) { testcase_error("C_Verify rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } if (signaturelen != ed_tv[i].signature_len || memcmp(signature, ed_tv[i].signature, signaturelen) != 0) { testcase_fail("Signature is not the expected one at " "i=%lu (%s)", i, ed_tv[i].name); goto testcase_cleanup; } testcase_new_assertion(); testcase_pass("*Sign & Verify with expected result (%s) index=%lu passed.", ed_tv[i].name, i); // clean up testcase_cleanup: if (publ_key != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, publ_key); publ_key = CK_INVALID_HANDLE; if (priv_key != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, priv_key); priv_key = CK_INVALID_HANDLE; } 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_TransferEdwardsMontgomeryKeyPair(void) { 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 = 0; 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 Edwards/Montgomery transfer key pair with " "pkey=%X ...", pkey); testcase_rw_session(); testcase_user_login(); /* Skip tests if pkey = true, but the slot doesn't support protected keys*/ if (pkey && !is_ep11_token(SLOT_ID) && !is_cca_token(SLOT_ID)) { testcase_skip("pkey test option is true, but slot %u doesn't support " "protected keys", (unsigned int) SLOT_ID); goto done; } rc = funcs->C_GetMechanismInfo(SLOT_ID, CKM_AES_KEY_GEN, &mech_info); if (rc != CKR_OK) { if (rc == CKR_MECHANISM_INVALID) { /* no support for AES key gen? skip */ testcase_skip("Slot %u doesn't support CKM_AES_KEY_GEN", (unsigned int) SLOT_ID); goto done; } else { testcase_error("C_GetMechanismInfo() rc = %s", p11_get_ckr(rc)); goto done; } } rc = funcs->C_GetMechanismInfo(SLOT_ID, CKM_AES_CBC_PAD, &mech_info); if (rc != CKR_OK) { if (rc == CKR_MECHANISM_INVALID) { /* no support for AES CBC wrap? skip */ testcase_skip("Slot %u doesn't support CKM_AES_CBC_PAD", (unsigned int) SLOT_ID); goto done; } else { testcase_error("C_GetMechanismInfo() rc = %s", p11_get_ckr(rc)); goto done; } } if ((mech_info.flags & CKF_WRAP) == 0 || (mech_info.flags & CKF_UNWRAP) == 0) { /* no support for AES CBC wrap? skip */ testcase_skip("Slot %u doesn't support CKM_AES_CBC_PAD for wrapping " "keys", (unsigned int) SLOT_ID); goto done; } for (i = 0; i < NUMED; i++) { if (der_ec_edwards_supported[i].type == CURVE_EDWARDS) mech.mechanism = CKM_EC_EDWARDS_KEY_PAIR_GEN; else if (der_ec_edwards_supported[i].type == CURVE_MONTGOMERY) mech.mechanism = CKM_EC_MONTGOMERY_KEY_PAIR_GEN; else continue; /* 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 %s", (unsigned int) SLOT_ID, p11_get_ckm(&mechtable_funcs, mech.mechanism)); goto testcase_cleanup; } else { testcase_error("C_GetMechanismInfo() rc = %s", p11_get_ckr(rc)); goto testcase_cleanup; } } rc = generate_EC_KeyPair(session, mech.mechanism, (CK_BYTE *)der_ec_edwards_supported[i].curve, der_ec_edwards_supported[i].size, &publ_key, &priv_key, !pkey); if (rc != CKR_OK) { if (is_rejected_by_policy(rc, session)) { testcase_skip("EC key generation is not allowed by policy"); continue; } if (rc == CKR_MECHANISM_PARAM_INVALID || rc == CKR_ATTRIBUTE_VALUE_INVALID || rc == CKR_CURVE_NOT_SUPPORTED) { testcase_skip("Slot %u doesn't support this curve: %s", (unsigned int) SLOT_ID, der_ec_edwards_supported[i].name); continue; } testcase_fail ("generate_EC_KeyPair with valid input failed at i=%lu (%s), " "rc=%s", i, der_ec_edwards_supported[i].name, p11_get_ckr(rc)); goto testcase_cleanup; } testcase_new_assertion(); testcase_pass("*Generate supported key pair index=%lu (%s) passed.", i, der_ec_edwards_supported[i].name); /* 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_BBOOL false = FALSE; CK_BBOOL sign = TRUE; CK_BBOOL derive = TRUE; CK_BYTE wrap_key_label[] = "Wrap_Key"; CK_OBJECT_CLASS wclass = CKO_PRIVATE_KEY; CK_KEY_TYPE keyType = (mech.mechanism == CKM_EC_EDWARDS_KEY_PAIR_GEN ? CKK_EC_EDWARDS : CKK_EC_MONTGOMERY); CK_ATTRIBUTE cka_wrap_tmpl[] = { {CKA_PRIVATE, &true, sizeof(true)}, {CKA_CLASS, &wclass, sizeof(wclass)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, }; CK_ATTRIBUTE cka_unwrap_tmpl[] = { {CKA_DECRYPT, &true, sizeof(true)}, {CKA_SIGN, &sign, sizeof(sign)}, {CKA_DERIVE, &derive, sizeof(derive)}, {CKA_PRIVATE, &true, sizeof(true)}, {CKA_IBM_PROTKEY_EXTRACTABLE, &true, sizeof(true)}, {CKA_EXTRACTABLE, &false, sizeof(false)}, }; 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)}, {CKA_WRAP_TEMPLATE, &cka_wrap_tmpl, sizeof(cka_wrap_tmpl)}, {CKA_UNWRAP_TEMPLATE, &cka_unwrap_tmpl, sizeof(cka_unwrap_tmpl)}, }; CK_ULONG secret_tmpl_len = sizeof(secret_tmpl) / sizeof(CK_ATTRIBUTE); if (der_ec_edwards_supported[i].type == CURVE_EDWARDS) derive = FALSE; if (der_ec_edwards_supported[i].type == CURVE_MONTGOMERY) sign = FALSE; if (is_icsf_token(SLOT_ID)) secret_tmpl_len -= 2; /* ICSF does not support array-attributes */ rc = funcs->C_GenerateKey(session, &aes_keygen_mech, secret_tmpl, secret_tmpl_len, &secret_key); if (rc != CKR_OK) { testcase_error("C_GenerateKey, rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } /* wrap/unwrap private and public Edwards key with a transport key */ 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) { if (rc == CKR_KEY_NOT_WRAPPABLE) { testcase_skip("Slot %u doesn't support this to wrap keys of " "type 0x%lx", (unsigned int) SLOT_ID, keyType); } else { testcase_error("C_WrapKey(), rc=%s.", p11_get_ckr(rc)); } goto testcase_cleanup; } wrapped_key = calloc(wrapped_keylen, sizeof(CK_BYTE)); 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; } rc = funcs->C_WrapKey(session, &wrap_mech, secret_key, priv_key, wrapped_key, &wrapped_keylen); if (rc != CKR_OK) { if (rc == CKR_KEY_NOT_WRAPPABLE) { testcase_skip("Slot %u doesn't support this to wrap keys of " "type 0x%lx", (unsigned int) SLOT_ID, keyType); } else { testcase_error("C_WrapKey(), rc=%s.", p11_get_ckr(rc)); } goto testcase_cleanup; } CK_OBJECT_CLASS class = CKO_PRIVATE_KEY; CK_KEY_TYPE key_type = (mech.mechanism == CKM_EC_EDWARDS_KEY_PAIR_GEN ? CKK_EC_EDWARDS : CKK_EC_MONTGOMERY); CK_BYTE unwrap_label[] = "unwrapped_private_EC_Key"; 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_ID, id, sizeof(id)}, {CKA_SENSITIVE, &true, sizeof(true)}, {CKA_DERIVE, &derive, sizeof(derive)}, {CKA_SIGN, &sign, sizeof(sign)}, {CKA_EXTRACTABLE, &false, sizeof(false)}, {CKA_IBM_PROTKEY_EXTRACTABLE, &true, sizeof(true)}, }; CK_ULONG unwrap_tmpl_len = sizeof(unwrap_tmpl) / sizeof(CK_ATTRIBUTE); if (is_icsf_token(SLOT_ID)) unwrap_tmpl_len -= 1; /* ICSF does not supp. CKA_IBM_PROTKEY_... */ rc = funcs->C_UnwrapKey(session, &wrap_mech, secret_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 testcase_cleanup; } if (wrapped_key) { free(wrapped_key); wrapped_key = NULL; } if (mech.mechanism == CKM_EC_EDWARDS_KEY_PAIR_GEN) { /* * create signature with unwrapped private key and verify with * public key */ testcase_new_assertion(); rc = run_GenerateSignVerifyECC(session, &edwardsSignVerifyInput[0].mech, edwardsSignVerifyInput[0].inputlen, edwardsSignVerifyInput[0].parts, unwrapped_key, publ_key, der_ec_edwards_supported[i].type, (CK_BYTE *)der_ec_edwards_supported[i].curve, der_ec_edwards_supported[i].size); if (rc != 0) { testcase_fail("run_GenerateSignVerifyECC failed index=0 (%s).", edwardsSignVerifyInput[0].name); goto testcase_cleanup; } testcase_pass("*Sign & verify %s i=%lu (%s), passed.", edwardsSignVerifyInput[0].name, i, der_ec_edwards_supported[i].name); } else { CK_OBJECT_HANDLE secret_key = CK_INVALID_HANDLE; CK_ECDH1_DERIVE_PARAMS ecdh_parm; CK_BYTE ec_point[64]; CK_ATTRIBUTE ec_point_attr = { CKA_EC_POINT, ec_point, sizeof(ec_point) }; CK_BBOOL extractable = !pkey; CK_KEY_TYPE secret_key_type = CKK_GENERIC_SECRET; CK_ULONG secret_key_len = (der_ec_edwards_supported[i].bit_len + 7) / 8; CK_OBJECT_CLASS secret_key_class = CKO_SECRET_KEY; CK_ATTRIBUTE derive_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_len, sizeof(secret_key_len)}, {CKA_SENSITIVE, &false, sizeof(false)}, {CKA_EXTRACTABLE, &extractable, sizeof(CK_BBOOL)}, {CKA_IBM_PROTKEY_EXTRACTABLE, &pkey, sizeof(CK_BBOOL)}, }; CK_ULONG derive_tmpl_len = sizeof(derive_tmpl) / sizeof(CK_ATTRIBUTE); testcase_new_assertion(); /* Perform ECDH with unwrapped private key and public key */ rc = funcs->C_GetAttributeValue(session, publ_key, &ec_point_attr, 1); if (rc != CKR_OK) { testcase_fail("C_GetAttributeValue: rc = %s", p11_get_ckr(rc)); goto testcase_cleanup; } ecdh_parm.kdf = CKD_NULL; ecdh_parm.pPublicData = ec_point_attr.pValue; ecdh_parm.ulPublicDataLen = ec_point_attr.ulValueLen; ecdh_parm.pSharedData = NULL; ecdh_parm.ulSharedDataLen = 0; mech.mechanism = CKM_ECDH1_DERIVE; mech.ulParameterLen = sizeof(CK_ECDH1_DERIVE_PARAMS); mech.pParameter = &ecdh_parm; rc = funcs->C_DeriveKey(session, &mech, unwrapped_key, derive_tmpl, derive_tmpl_len, &secret_key); if (rc != CKR_OK) { if (rc == CKR_CURVE_NOT_SUPPORTED) { testcase_skip("Slot %u doesn't support this curve: %s", (unsigned int) SLOT_ID, der_ec_edwards_supported[i].name); goto testcase_cleanup; } testcase_fail("C_DeriveKey: rc = %s", p11_get_ckr(rc)); goto testcase_cleanup; } rc = funcs->C_DestroyObject(session, secret_key); if (rc != CKR_OK) { testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(rc)); } testcase_pass("*ECDH i=%lu (%s), passed.", i, der_ec_edwards_supported[i].name); } testcase_cleanup: if (publ_key != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, publ_key); publ_key = CK_INVALID_HANDLE; if (priv_key != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, priv_key); priv_key = CK_INVALID_HANDLE; if (secret_key != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, secret_key); secret_key = CK_INVALID_HANDLE; if (unwrapped_key != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, unwrapped_key); unwrapped_key = CK_INVALID_HANDLE; } 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; } CK_RV run_MontgomeryECDHKeyKAT(void) { 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] = { 0 }; // enough space for key lengths in ecdh_tv[] CK_BYTE secretB_value[1000] = { 0 }; CK_BYTE mac1[SHA1_HASH_SIZE] = { 0 }; CK_ULONG mac1_len = sizeof(mac1); CK_BYTE mac2[SHA1_HASH_SIZE] = { 0 }; CK_ULONG mac2_len = sizeof(mac2); CK_BYTE macexpected[SHA1_HASH_SIZE] = { 0 }; CK_ULONG macexpected_len = sizeof(macexpected); CK_ULONG i; testcase_begin("starting run_MontgomeryECDHKeyKAT with pkey=%X ...", pkey); testcase_rw_session(); testcase_user_login(); /* Skip tests if pkey = true, but the slot doesn't support protected keys*/ if (pkey && !is_ep11_token(SLOT_ID) && !is_cca_token(SLOT_ID)) { testcase_skip("pkey test option is true, but slot %u doesn't support " "protected keys", (unsigned int) SLOT_ID); goto testcase_cleanup; } if (!mech_supported(SLOT_ID, CKM_EC_MONTGOMERY_KEY_PAIR_GEN)) { testcase_skip("Slot %u doesn't support CKM_EC_MONTGOMERY_KEY_PAIR_GEN\n", (unsigned int) SLOT_ID); goto testcase_cleanup; } 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)) && !mech_supported(SLOT_ID, CKM_SHA_1_HMAC)) { testcase_skip("Slot %u doesn't support CKM_SHA_1_HMAC, correctness " "of derived keys can not be verified\n", (unsigned int) SLOT_ID); goto testcase_cleanup; } if (is_cca_token(SLOT_ID)) { testcase_skip("The CCA token in slot %u doesn't support ECDH with EC " "keys imported from clear, only with randomly generated " "keys. KATs not possible because of that\n", (unsigned int) SLOT_ID); goto testcase_cleanup; } for (i=0; i< MONTGOMERY_ECDH_TV_NUM; i++) { testcase_begin("Starting with shared secret i=%lu (%s), pkey=%X", i, montgomery_ecdh_tv[i].name, pkey); if ((is_ep11_token(SLOT_ID) || is_cca_token(SLOT_ID)) && !check_supp_keysize(SLOT_ID, CKM_SHA_1_HMAC, montgomery_ecdh_tv[i].derived_key_len * 8)) { testcase_skip("Mechanism CKM_SHA_1_HMAC can not be used with " "keys of size %lu. Correctness of derived key " "can not be verified.", montgomery_ecdh_tv[i].derived_key_len); continue; } // First, import the EC-Montgomery key pair for party A rc = create_ECPrivateKey(session, CKK_EC_MONTGOMERY, montgomery_ecdh_tv[i].params, montgomery_ecdh_tv[i].params_len, montgomery_ecdh_tv[i].privkeyA, montgomery_ecdh_tv[i].privkey_len, &priv_keyA, !pkey, CK_TRUE); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("EC key import is not allowed by policy"); continue; } if (rc == CKR_CURVE_NOT_SUPPORTED) { testcase_skip("Slot %u doesn't support this curve: %s", (unsigned int) SLOT_ID, montgomery_ecdh_tv[i].name); goto testcase_next; } testcase_fail("C_CreateObject (EC Private Key) failed at i=%lu, " "rc=%s", i, p11_get_ckr(rc)); goto testcase_next; } rc = create_ECPublicKey(session, CKK_EC_MONTGOMERY, montgomery_ecdh_tv[i].params, montgomery_ecdh_tv[i].params_len, montgomery_ecdh_tv[i].pubkeyA, montgomery_ecdh_tv[i].pubkey_len, &publ_keyA, !pkey); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("EC key import is not allowed by policy"); funcs->C_DestroyObject(session, priv_keyA); continue; } if (rc == CKR_CURVE_NOT_SUPPORTED) { testcase_skip("Slot %u doesn't support this curve: %s", (unsigned int) SLOT_ID, montgomery_ecdh_tv[i].name); goto testcase_next; } testcase_fail("C_CreateObject (EC Public Key) failed at i=%lu, " "rc=%s", i, p11_get_ckr(rc)); goto testcase_next; } // Now import the EC key pair for party B rc = create_ECPrivateKey(session, CKK_EC_MONTGOMERY, montgomery_ecdh_tv[i].params, montgomery_ecdh_tv[i].params_len, montgomery_ecdh_tv[i].privkeyB, montgomery_ecdh_tv[i].privkey_len, &priv_keyB, !pkey, CK_TRUE); if (rc != CKR_OK) { if (rc == CKR_CURVE_NOT_SUPPORTED) { testcase_skip("Slot %u doesn't support this curve: %s", (unsigned int) SLOT_ID, montgomery_ecdh_tv[i].name); goto testcase_next; } testcase_fail("C_CreateObject (EC Private Key) failed at i=%lu, " "rc=%s", i, p11_get_ckr(rc)); goto testcase_next; } rc = create_ECPublicKey(session, CKK_EC_MONTGOMERY, montgomery_ecdh_tv[i].params, montgomery_ecdh_tv[i].params_len, montgomery_ecdh_tv[i].pubkeyB, montgomery_ecdh_tv[i].pubkey_len, &publ_keyB, !pkey); if (rc != CKR_OK) { if (rc == CKR_CURVE_NOT_SUPPORTED) { testcase_skip("Slot %u doesn't support this curve: %s", (unsigned int) SLOT_ID, montgomery_ecdh_tv[i].name); goto testcase_next; } testcase_fail("C_CreateObject (EC Public Key) failed at i=%lu, " "rc=%s", i, p11_get_ckr(rc)); goto testcase_next; } // Now derive the secrets... 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, secretB_value, sizeof(secretB_value)} }; CK_ULONG secretB_tmpl_len = sizeof(secretB_tmpl) / sizeof(CK_ATTRIBUTE); CK_BBOOL extractable = !pkey; CK_ATTRIBUTE derive_tmpl[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &secret_key_type, sizeof(secret_key_type)}, {CKA_VALUE_LEN, &(montgomery_ecdh_tv[i].derived_key_len), sizeof(CK_ULONG)}, {CKA_SENSITIVE, &false, sizeof(false)}, {CKA_EXTRACTABLE, &extractable, sizeof(CK_BBOOL)}, {CKA_IBM_PROTKEY_EXTRACTABLE, &pkey, sizeof(CK_BBOOL)}, }; CK_ULONG derive_tmpl_len = sizeof(derive_tmpl) / sizeof(CK_ATTRIBUTE); // Now, derive a generic secret key using party A's private key // and B's public key ecdh_parmA.kdf = montgomery_ecdh_tv[i].kdf; ecdh_parmA.pPublicData = montgomery_ecdh_tv[i].pubkeyB; ecdh_parmA.ulPublicDataLen = montgomery_ecdh_tv[i].pubkey_len; ecdh_parmA.pSharedData = NULL; ecdh_parmA.ulSharedDataLen = 0; mech.mechanism = CKM_ECDH1_DERIVE; mech.ulParameterLen = sizeof(CK_ECDH1_DERIVE_PARAMS); mech.pParameter = &ecdh_parmA; rc = funcs->C_DeriveKey(session, &mech, priv_keyA, derive_tmpl, derive_tmpl_len, &secret_keyA); if (rc != CKR_OK) { if (rc == CKR_CURVE_NOT_SUPPORTED) { testcase_skip("Slot %u doesn't support this curve: %s", (unsigned int) SLOT_ID, montgomery_ecdh_tv[i].name); goto testcase_next; } testcase_fail("C_DeriveKey #1: rc = %s", p11_get_ckr(rc)); goto testcase_next; } // Now, derive a generic secret key using B's private key and // A's public key ecdh_parmB.kdf = montgomery_ecdh_tv[i].kdf; ecdh_parmB.pPublicData = montgomery_ecdh_tv[i].pubkeyA; ecdh_parmB.ulPublicDataLen = montgomery_ecdh_tv[i].pubkey_len; 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) { testcase_fail("C_DeriveKey #2: rc = %s", p11_get_ckr(rc)); goto testcase_next; } testcase_new_assertion(); /* A secure key token won't reveal the key value in clear */ if (!is_ep11_token(SLOT_ID) && !is_cca_token(SLOT_ID)) { // 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_next; } // Compare lengths of derived secret from key object if (montgomery_ecdh_tv[i].derived_key_len != secretA_tmpl[0].ulValueLen) { testcase_fail("ERROR: derived key #1 length = %lu, " "derived key #2 length = %lu", montgomery_ecdh_tv[i].derived_key_len, secretA_tmpl[0].ulValueLen); goto testcase_next; } // Compare with known value if (memcmp(secretA_tmpl[0].pValue, montgomery_ecdh_tv[i].derived_key, montgomery_ecdh_tv[i].derived_key_len) != 0) { testcase_fail("ERROR: derived key mismatch, i=%lu",i); goto testcase_next; } // 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_next; } // Compare lengths of derived secret from key object if (montgomery_ecdh_tv[i].derived_key_len != secretB_tmpl[0].ulValueLen) { testcase_fail("ERROR: derived key #1 length = %lu, " "derived key #2 length = %lu", montgomery_ecdh_tv[i].derived_key_len, secretB_tmpl[0].ulValueLen); goto testcase_next; } // Compare with known value if (memcmp(secretB_tmpl[0].pValue, montgomery_ecdh_tv[i].derived_key, montgomery_ecdh_tv[i].derived_key_len) != 0) { testcase_fail("ERROR: derived key mismatch, i=%lu",i); goto testcase_next; } } else { /* Secure key: * Calculate HMAC with derived keys and expected key and compare * the MAC. */ rc = run_HMACSign_OpenSSL(montgomery_ecdh_tv[i].derived_key, montgomery_ecdh_tv[i].derived_key_len, CKM_SHA_1_HMAC, macexpected, &macexpected_len); if (rc != CKR_OK) { testcase_fail("HMAC for expected key failed: %s", p11_get_ckr(rc)); goto testcase_next; } rc = run_HMACSign(session, secret_keyA, montgomery_ecdh_tv[i].derived_key_len, CKM_SHA_1_HMAC, mac1, &mac1_len); if (rc != CKR_OK) { testcase_fail("HMAC for derived key #1 failed: %s", p11_get_ckr(rc)); goto testcase_next; } if (mac1_len != 0 && /* skip check if mac can't be calculated */ (mac1_len != macexpected_len || memcmp(mac1, macexpected, mac1_len) != 0)) { testcase_fail("ERROR: derived key #1 does not produce the " "expected HMAC"); goto testcase_next; } rc = run_HMACSign(session, secret_keyB, montgomery_ecdh_tv[i].derived_key_len, CKM_SHA_1_HMAC, mac2, &mac2_len); if (rc != CKR_OK) { testcase_fail("HMAC for derived key #2 failed: %s", p11_get_ckr(rc)); goto testcase_next; } if (mac2_len != 0 && /* skip check if mac can't be calculated */ (mac2_len != macexpected_len || memcmp(mac2, macexpected, mac2_len) != 0)) { testcase_fail("ERROR: derived key #2 does not produce the " "expected HMAC"); goto testcase_next; } } testcase_pass("*Derive shared secret i=%lu (%s) passed.", i, montgomery_ecdh_tv[i].name); testcase_next: if (priv_keyA != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, priv_keyA); priv_keyA = CK_INVALID_HANDLE; if (publ_keyA != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, publ_keyA); publ_keyA = CK_INVALID_HANDLE; if (priv_keyB != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, priv_keyB); priv_keyB = CK_INVALID_HANDLE; if (publ_keyB != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, publ_keyB); publ_keyB = CK_INVALID_HANDLE; if (secret_keyA != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, secret_keyA); secret_keyA = CK_INVALID_HANDLE; if (secret_keyB != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, secret_keyB); secret_keyB = CK_INVALID_HANDLE; } 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; } typedef struct ecdh_encaps_decaps_params { _ec_struct curve; CK_KEY_TYPE sym_key_type; CK_ULONG sym_key_size; CK_EC_KDF_TYPE kdf; CK_BYTE *shared_data; CK_ULONG shared_data_len; } ecdh_encaps_decaps_params; const ecdh_encaps_decaps_params ecdh_encaps_decaps_tests[] = { { .curve = { &prime256v1, sizeof(prime256v1), CK_FALSE, CURVE_PRIME, CURVE256_LENGTH, "prime256v1" }, .sym_key_type = CKK_AES, .sym_key_size = 32, .kdf = CKD_NULL, .shared_data = NULL, .shared_data_len = 0, }, { .curve = { &prime256v1, sizeof(prime256v1), CK_FALSE, CURVE_PRIME, CURVE256_LENGTH, "prime256v1" }, .sym_key_type = CKK_AES, .sym_key_size = 32, .kdf = CKD_SHA256_KDF, .shared_data = (CK_BYTE *)"abcdefg", .shared_data_len = 6, }, { .curve = { &secp521r1, sizeof(secp521r1), CK_FALSE, CURVE_PRIME, CURVE521_LENGTH + 8, "secp521r1" }, .sym_key_type = CKK_AES, .sym_key_size = 32, .kdf = CKD_SHA256_KDF, .shared_data = (CK_BYTE *)"abcdefg", .shared_data_len = 6, }, { .curve = { &brainpoolP256r1, sizeof(brainpoolP256r1), CK_FALSE, CURVE_BRAINPOOL, CURVE256_LENGTH, "brainpoolP256r1" }, .sym_key_type = CKK_AES, .sym_key_size = 32, .kdf = CKD_SHA256_KDF, .shared_data = (CK_BYTE *)"abcdefg", .shared_data_len = 6, }, { .curve = { &brainpoolP512r1, sizeof(brainpoolP512r1), CK_FALSE, CURVE_BRAINPOOL, CURVE512_LENGTH, "brainpoolP512r1" }, .sym_key_type = CKK_AES, .sym_key_size = 32, .kdf = CKD_SHA256_KDF, .shared_data = (CK_BYTE *)"abcdefg", .shared_data_len = 6, }, { .curve = { &curve25519, sizeof(curve25519), CK_FALSE, CURVE_MONTGOMERY, CURVE256_LENGTH, "curve25519" }, .sym_key_type = CKK_AES, .sym_key_size = 32, .kdf = CKD_SHA256_KDF, .shared_data = (CK_BYTE *)"abcdefg", .shared_data_len = 6, }, { .curve = { &curve448, sizeof(curve448), CK_FALSE, CURVE_MONTGOMERY, CURVE448_LENGTH, "curve448" }, .sym_key_type = CKK_AES, .sym_key_size = 32, .kdf = CKD_SHA256_KDF, .shared_data = (CK_BYTE *)"abcdefg", .shared_data_len = 6, }, { .curve = { &prime256v1, sizeof(prime256v1), CK_FALSE, CURVE_PRIME, CURVE256_LENGTH, "prime256v1" }, .sym_key_type = CKK_AES, .sym_key_size = 16, .kdf = CKD_SHA256_KDF, .shared_data = (CK_BYTE *)"abcdefg", .shared_data_len = 6, }, { .curve = { &prime256v1, sizeof(prime256v1), CK_FALSE, CURVE_PRIME, CURVE256_LENGTH, "prime256v1" }, .sym_key_type = CKK_AES_XTS, .sym_key_size = 64, .kdf = CKD_SHA256_KDF, .shared_data = (CK_BYTE *)"abcdefg", .shared_data_len = 6, }, { .curve = { &prime256v1, sizeof(prime256v1), CK_FALSE, CURVE_PRIME, CURVE256_LENGTH, "prime256v1" }, .sym_key_type = CKK_GENERIC_SECRET, .sym_key_size = 32, .kdf = CKD_SHA256_KDF, .shared_data = (CK_BYTE *)"abcdefg", .shared_data_len = 6, }, { .curve = { &prime256v1, sizeof(prime256v1), CK_FALSE, CURVE_PRIME, CURVE256_LENGTH, "prime256v1" }, .sym_key_type = CKK_GENERIC_SECRET, .sym_key_size = 64, .kdf = CKD_SHA256_KDF, .shared_data = (CK_BYTE *)"abcdefg", .shared_data_len = 6, }, }; #define NUMENCAPSDECAPS sizeof(ecdh_encaps_decaps_tests) / \ sizeof(ecdh_encaps_decaps_params) CK_RV run_EncapsDecapsECDH(CK_BBOOL cofactor_mode) { CK_SESSION_HANDLE session; CK_MECHANISM mech; CK_FLAGS flags; CK_OBJECT_HANDLE publ_key = CK_INVALID_HANDLE, priv_key = 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_OBJECT_CLASS class = CKO_SECRET_KEY; CK_ECDH1_DERIVE_PARAMS ecdh_parm; CK_ULONG i; CK_BBOOL ck_true = CK_TRUE; CK_BBOOL ck_false = CK_FALSE; CK_BYTE *cipher = NULL; CK_ULONG cipher_len; CK_BYTE mac1[SHA256_HASH_SIZE] = { 0 }; CK_ULONG mac1_len = sizeof(mac1); CK_BYTE mac2[SHA256_HASH_SIZE] = { 0 }; CK_ULONG mac2_len = sizeof(mac2); CK_BYTE enc1[AES_BLOCK_SIZE] = { 0 }; CK_ULONG enc1_len = sizeof(enc1); CK_BYTE enc2[AES_BLOCK_SIZE] = { 0 }; CK_ULONG enc2_len = sizeof(enc2); testcase_begin("starting run_EncapsDecapsECDH %s with pkey=%X ...", cofactor_mode ? "in cofactor mode" : "", pkey); testcase_rw_session(); testcase_user_login(); /* Skip tests if pkey = true, but the slot doesn't support protected keys*/ if (pkey && !is_ep11_token(SLOT_ID) && !is_cca_token(SLOT_ID)) { testcase_skip("pkey test option is true, but slot %u doesn't support " "protected keys", (unsigned int)SLOT_ID); goto testcase_cleanup; } mech.mechanism = cofactor_mode ? CKM_ECDH1_COFACTOR_DERIVE : CKM_ECDH1_DERIVE; if (!mech_supported(SLOT_ID, mech.mechanism)) { testcase_skip("Slot %u doesn't support %s\n", (unsigned int)SLOT_ID, p11_get_ckm(&mechtable_funcs, mech.mechanism)); goto testcase_cleanup; } if (!encapsulate_supported(SLOT_ID, mech) || !decapsulate_supported(SLOT_ID, mech)) { testcase_skip("Slot %u doesn't support key encapsulation with %s", (unsigned int)SLOT_ID, p11_get_ckm(&mechtable_funcs, mech.mechanism)); goto testcase_cleanup; } for (i = 0; i < NUMENCAPSDECAPS; i++) { CK_ATTRIBUTE decaps_tmp[] = { {CKA_KEY_TYPE, (CK_VOID_PTR)&ecdh_encaps_decaps_tests[i].sym_key_type, sizeof(ecdh_encaps_decaps_tests[i].sym_key_type)}, {CKA_VALUE_LEN, (CK_VOID_PTR)&ecdh_encaps_decaps_tests[i].sym_key_size, sizeof(ecdh_encaps_decaps_tests[i].sym_key_size)}, }; CK_ATTRIBUTE prv_attr[] = { {CKA_SIGN, &ck_true, sizeof(ck_true)}, {CKA_EXTRACTABLE, &ck_true, sizeof(ck_true)}, {CKA_SENSITIVE, &ck_true, sizeof(ck_true)}, {CKA_DERIVE, &ck_false, sizeof(ck_false)}, {CKA_DECAPSULATE, &ck_true, sizeof(ck_true)}, {CKA_DECAPSULATE_TEMPLATE, &decaps_tmp, sizeof(decaps_tmp)}, }; CK_ULONG prv_attr_len = sizeof(prv_attr)/sizeof(CK_ATTRIBUTE); CK_ATTRIBUTE pub_attr[] = { {CKA_EC_PARAMS, (CK_VOID_PTR)ecdh_encaps_decaps_tests[i].curve.curve, ecdh_encaps_decaps_tests[i].curve.size}, {CKA_VERIFY, &ck_true, sizeof(ck_true)}, {CKA_DERIVE, &ck_false, sizeof(ck_false)}, {CKA_ENCAPSULATE, &ck_true, sizeof(ck_true)}, }; CK_ULONG pub_attr_len = sizeof(pub_attr)/sizeof(CK_ATTRIBUTE); CK_ATTRIBUTE encaps_decaps_tmpl[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, (CK_VOID_PTR)&ecdh_encaps_decaps_tests[i].sym_key_type, sizeof(ecdh_encaps_decaps_tests[i].sym_key_type)}, {CKA_EXTRACTABLE, &ck_false, sizeof(ck_false)}, {CKA_SENSITIVE, &ck_true, sizeof(ck_true)}, {CKA_VALUE_LEN, (CK_VOID_PTR)&ecdh_encaps_decaps_tests[i].sym_key_size, sizeof(ecdh_encaps_decaps_tests[i].sym_key_size)}, }; CK_ULONG encaps_decaps_tmpl_len = sizeof(encaps_decaps_tmpl) / sizeof(CK_ATTRIBUTE); mech.mechanism = cofactor_mode ? CKM_ECDH1_COFACTOR_DERIVE : CKM_ECDH1_DERIVE; testcase_begin("Starting with mech=%s, index=%lu, curve=%s, kdf=%s, " "keytype=0x%lx, keylen=%lu, shared_data=%lu, pkey=%X", p11_get_ckm(&mechtable_funcs, mech.mechanism), i, ecdh_encaps_decaps_tests[i].curve.name, p11_get_ckd(ecdh_encaps_decaps_tests[i].kdf), ecdh_encaps_decaps_tests[i].sym_key_type, ecdh_encaps_decaps_tests[i].sym_key_size, ecdh_encaps_decaps_tests[i].shared_data_len, pkey); /* Check the curve */ if (ecdh_encaps_decaps_tests[i].curve.type == CURVE_EDWARDS|| ecdh_encaps_decaps_tests[i].curve.type == CURVE_BLS12_381) { /* Edwards/BLS curves can not be used for ECDH encaps/decaps */ continue; } if (is_cca_token(SLOT_ID)) { if (ecdh_encaps_decaps_tests[i].curve.twisted) { testcase_skip("Slot %u doesn't support this curve: %s", (unsigned int) SLOT_ID, ecdh_encaps_decaps_tests[i].curve.name); continue; } } /* Check the KDF */ switch (ecdh_encaps_decaps_tests[i].kdf) { case CKD_SHA1_KDF: case CKD_SHA1_KDF_SP800: if (!mech_supported(SLOT_ID, CKM_SHA_1)) { testcase_skip("Slot %u doesn't support %s\n", (unsigned int) SLOT_ID, p11_get_ckd(ecdh_encaps_decaps_tests[i].kdf)); continue; } break; case CKD_SHA224_KDF: case CKD_SHA224_KDF_SP800: if (!mech_supported(SLOT_ID, CKM_SHA224)) { testcase_skip("Slot %u doesn't support %s\n", (unsigned int) SLOT_ID, p11_get_ckd(ecdh_encaps_decaps_tests[i].kdf)); continue; } break; case CKD_SHA256_KDF: case CKD_SHA256_KDF_SP800: if (!mech_supported(SLOT_ID, CKM_SHA256)) { testcase_skip("Slot %u doesn't support %s\n", (unsigned int) SLOT_ID, p11_get_ckd(ecdh_encaps_decaps_tests[i].kdf)); continue; } break; case CKD_SHA384_KDF: case CKD_SHA384_KDF_SP800: if (!mech_supported(SLOT_ID, CKM_SHA384)) { testcase_skip("Slot %u doesn't support %s\n", (unsigned int) SLOT_ID, p11_get_ckd(ecdh_encaps_decaps_tests[i].kdf)); continue; } break; case CKD_SHA512_KDF: case CKD_SHA512_KDF_SP800: if (!mech_supported(SLOT_ID, CKM_SHA512)) { testcase_skip("Slot %u doesn't support %s\n", (unsigned int) SLOT_ID, p11_get_ckd(ecdh_encaps_decaps_tests[i].kdf)); continue; } break; case CKD_SHA3_224_KDF: case CKD_SHA3_224_KDF_SP800: if (!mech_supported(SLOT_ID, CKM_SHA3_224)) { testcase_skip("Slot %u doesn't support %s\n", (unsigned int) SLOT_ID, p11_get_ckd(ecdh_encaps_decaps_tests[i].kdf));; continue; } break; case CKD_SHA3_256_KDF: case CKD_SHA3_256_KDF_SP800: if (!mech_supported(SLOT_ID, CKM_SHA3_256)) { testcase_skip("Slot %u doesn't support %s\n", (unsigned int) SLOT_ID, p11_get_ckd(ecdh_encaps_decaps_tests[i].kdf)); continue; } break; case CKD_SHA3_384_KDF: case CKD_SHA3_384_KDF_SP800: if (!mech_supported(SLOT_ID, CKM_SHA3_384)) { testcase_skip("Slot %u doesn't support %s\n", (unsigned int) SLOT_ID, p11_get_ckd(ecdh_encaps_decaps_tests[i].kdf)); continue; } break; case CKD_SHA3_512_KDF: case CKD_SHA3_512_KDF_SP800: if (!mech_supported(SLOT_ID, CKM_SHA3_512)) { testcase_skip("Slot %u doesn't support %s\n", (unsigned int) SLOT_ID, p11_get_ckd(ecdh_encaps_decaps_tests[i].kdf)); continue; } break; default: break; } if (is_cca_token(SLOT_ID)) { switch (ecdh_encaps_decaps_tests[i].kdf) { case CKD_SHA224_KDF: case CKD_SHA256_KDF: case CKD_SHA384_KDF: case CKD_SHA512_KDF: break; default: testcase_skip("CCA token can not en/decapsulate keys with " "this KDF %s", p11_get_ckd(ecdh_encaps_decaps_tests[i].kdf)); continue; } } /* Check the to be en/decapsulated key type and size */ if (is_cca_token(SLOT_ID)) { if (ecdh_encaps_decaps_tests[i].sym_key_type != CKK_AES) { testcase_skip("CCA token can not en/decapsulate keys other " "than AES\n"); continue; } } /* Generate the EC key pair for party A */ mech.mechanism = ecdh_encaps_decaps_tests[i].curve.type == CURVE_MONTGOMERY ? CKM_EC_MONTGOMERY_KEY_PAIR_GEN : CKM_EC_KEY_PAIR_GEN; mech.ulParameterLen = 0; mech.pParameter = NULL; if (!mech_supported(SLOT_ID, mech.mechanism)) { testcase_skip("Slot %u doesn't support %s\n", (unsigned int)SLOT_ID, p11_get_ckm(&mechtable_funcs, mech.mechanism)); continue; } rc = funcs->C_GenerateKeyPair(session, &mech, pub_attr, pub_attr_len, prv_attr, prv_attr_len, &publ_key, &priv_key); if (rc != CKR_OK) { if (is_rejected_by_policy(rc, session)) { testcase_skip("EC key generation is not allowed by policy"); goto testcase_next; } if (rc == CKR_MECHANISM_PARAM_INVALID || rc == CKR_ATTRIBUTE_VALUE_INVALID || rc == CKR_CURVE_NOT_SUPPORTED) { testcase_skip("Slot %u doesn't support this curve: %s", (unsigned int) SLOT_ID, ecdh_encaps_decaps_tests[i].curve.name); goto testcase_next; } testcase_new_assertion(); testcase_fail("C_GenerateKeyPair with valid input failed at i=%lu " "(%s), rc=%s", i, ecdh_encaps_decaps_tests[i].curve.name, p11_get_ckr(rc)); goto testcase_next; } /* Encapsulate on party B */ mech.mechanism = cofactor_mode ? CKM_ECDH1_COFACTOR_DERIVE : CKM_ECDH1_DERIVE; mech.ulParameterLen = sizeof(CK_ECDH1_DERIVE_PARAMS); mech.pParameter = &ecdh_parm; ecdh_parm.kdf = ecdh_encaps_decaps_tests[i].kdf; ecdh_parm.pSharedData = ecdh_encaps_decaps_tests[i].shared_data; ecdh_parm.ulSharedDataLen = ecdh_encaps_decaps_tests[i].shared_data_len; ecdh_parm.pPublicData = NULL; ecdh_parm.ulPublicDataLen = 0; rc = funcs3_2->C_EncapsulateKey(session, &mech, publ_key, encaps_decaps_tmpl, encaps_decaps_tmpl_len, NULL, &cipher_len, NULL); if (rc != CKR_OK) { if (is_ep11_token(SLOT_ID) && rc == CKR_MECHANISM_PARAM_INVALID && (ecdh_parm.kdf != CKD_NULL || ecdh_parm.ulSharedDataLen > 0)) { testcase_skip("EP11 does not support KDF %s and/or " "shared data with older firmware " "versions\n", p11_get_ckd(ecdh_parm.kdf)); goto testcase_next; } if (rc == CKR_KEY_TYPE_INCONSISTENT) { testcase_skip("Slot %u doesn't support to en/decaps key " "type 0x%lx", (unsigned int) SLOT_ID, ecdh_encaps_decaps_tests[i].sym_key_type); goto testcase_next; } if (is_rejected_by_policy(rc, session)) { testcase_skip("key derivation is not allowed by policy"); continue; } if (rc == CKR_FUNCTION_CANCELED) { testcase_skip("key derivation is not allowed by " "adapter control point"); goto testcase_next; } if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("key derivation is not allowed because key to be " "generated is stronger than the input material."); goto testcase_next; } testcase_new_assertion(); testcase_fail("C_EncapsulateKey #1: rc = %s", p11_get_ckr(rc)); goto testcase_next; } cipher = calloc(cipher_len, sizeof(CK_BYTE)); if (cipher == NULL) { testcase_error("Can't allocate memory for %lu bytes.", cipher_len); rc = CKR_HOST_MEMORY; goto testcase_cleanup; } rc = funcs3_2->C_EncapsulateKey(session, &mech, publ_key, encaps_decaps_tmpl, encaps_decaps_tmpl_len, cipher, &cipher_len, &secret_keyB); if (rc != CKR_OK) { if (is_ep11_token(SLOT_ID) && rc == CKR_MECHANISM_PARAM_INVALID && (ecdh_parm.kdf != CKD_NULL || ecdh_parm.ulSharedDataLen > 0)) { testcase_skip("EP11 does not support KDF %s and/or " "shared data with older firmware " "versions\n", p11_get_ckd(ecdh_parm.kdf)); goto testcase_next; } if (rc == CKR_KEY_TYPE_INCONSISTENT) { testcase_skip("Slot %u doesn't support to en/decaps key " "type 0x%lx", (unsigned int) SLOT_ID, ecdh_encaps_decaps_tests[i].sym_key_type); goto testcase_next; } if (is_rejected_by_policy(rc, session)) { testcase_skip("key derivation is not allowed by policy"); continue; } if (rc == CKR_FUNCTION_CANCELED) { testcase_skip("key derivation is not allowed by " "adapter control point"); goto testcase_next; } if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("key derivation is not allowed because key to be " "generated is stronger than the input material."); goto testcase_next; } testcase_new_assertion(); testcase_fail("C_EncapsulateKey #2: rc = %s", p11_get_ckr(rc)); goto testcase_next; } /* Decapsulate on party A */ rc = funcs3_2->C_DecapsulateKey(session, &mech, priv_key, encaps_decaps_tmpl, encaps_decaps_tmpl_len, cipher, cipher_len, &secret_keyA); if (rc != CKR_OK) { testcase_new_assertion(); testcase_fail("C_DecapsulateKey: rc = %s", p11_get_ckr(rc)); goto testcase_next; } /* Check if encapsulated key is the same as the decapsukated key */ testcase_new_assertion(); switch (ecdh_encaps_decaps_tests[i].sym_key_type) { case CKK_GENERIC_SECRET: mac1_len = sizeof(mac1); rc = run_HMACSign(session, secret_keyB, ecdh_encaps_decaps_tests[i].sym_key_size, CKM_SHA256_HMAC, mac1, &mac1_len); if (rc != CKR_OK) { testcase_fail("Encapsulated key #1 is not usable: %s", p11_get_ckr(rc)); goto testcase_next; } mac2_len = sizeof(mac2); rc = run_HMACSign(session, secret_keyA, ecdh_encaps_decaps_tests[i].sym_key_size, CKM_SHA256_HMAC, mac2, &mac2_len); if (rc != CKR_OK) { testcase_fail("Decapsulated key #2 is not usable: %s", p11_get_ckr(rc)); goto testcase_next; } if (mac1_len != mac2_len || memcmp(mac1, mac2, mac1_len) != 0) { testcase_fail("ERROR: en/Decapsulated keys do not produce the " "same HMAC"); goto testcase_next; } break; case CKK_AES: enc1_len = sizeof(enc1); rc = run_AESEncrypt(session, secret_keyB, enc1, &enc1_len); if (rc != CKR_OK) { testcase_fail("Encapsulated key #1 is not usable: %s", p11_get_ckr(rc)); goto testcase_next; } enc2_len = sizeof(enc2); rc = run_AESEncrypt(session, secret_keyA, enc2, &enc2_len); if (rc != CKR_OK) { testcase_fail("Decapsulated key #2 is not usable: %s", p11_get_ckr(rc)); goto testcase_next; } if (enc1_len != enc2_len || memcmp(enc1, enc2, enc1_len) != 0) { testcase_fail("ERROR: en/decapsulated keys do not produce the " "same encrypted cipher text"); goto testcase_next; } break; } testcase_pass("EnDecapsulate shared secret mech=%s, index=%lu, " "curve=%s, kdf=%s, keytype=ox%lx, keylen=%lu, " "shared_data=%lu passed.", p11_get_ckm(&mechtable_funcs, mech.mechanism), i, ecdh_encaps_decaps_tests[i].curve.name, p11_get_ckd(ecdh_encaps_decaps_tests[i].kdf), ecdh_encaps_decaps_tests[i].sym_key_type, ecdh_encaps_decaps_tests[i].sym_key_size, ecdh_encaps_decaps_tests[i].shared_data_len); testcase_next: if (cipher) free(cipher); cipher = NULL; if (secret_keyA != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, secret_keyA); secret_keyA = CK_INVALID_HANDLE; if (secret_keyB != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, secret_keyB); secret_keyB = CK_INVALID_HANDLE; if (publ_key != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, publ_key); publ_key = CK_INVALID_HANDLE; if (priv_key != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, priv_key); priv_key = CK_INVALID_HANDLE; } testcase_cleanup: if (cipher) free(cipher); if (secret_keyA != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, secret_keyA); secret_keyA = CK_INVALID_HANDLE; if (secret_keyB != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, secret_keyB); secret_keyB = CK_INVALID_HANDLE; if (publ_key != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, publ_key); publ_key = CK_INVALID_HANDLE; if (priv_key != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, priv_key); priv_key = CK_INVALID_HANDLE; 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 options: combined_extract: %d, nostop: %d\n", combined_extract, no_stop); if (combined_extract) printf("\n--------------------------------------------------------\n" "Caution: combined_extract does only work on systems with\n" "control point 75 (XCP_CPB_ALLOW_COMBINED_EXTRACT)='on'.\n" "--------------------------------------------------------\n\n"); 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(); pkey = CK_FALSE; rv = run_GenerateECCKeyPairSignVerify(); rv += run_ImportECCKeyPairSignVerify(); rv += run_TransferECCKeyPairSignVerify(); rv += run_DeriveECDHKey(FALSE); rv += run_DeriveECDHKey(TRUE); rv += run_DeriveECDHKeyKAT(); rv += run_DeriveBTC(); rv += run_BLSAggregation(); rv += run_GenerateEdwardsKeyPairSignVerify(); rv += run_ImportEdwardsKeyPairSignVerifyKAT(); rv += run_TransferEdwardsMontgomeryKeyPair(); rv += run_MontgomeryECDHKeyKAT(); rv += run_EncapsDecapsECDH(FALSE); rv += run_EncapsDecapsECDH(TRUE); #ifndef NO_PKEY if (is_ep11_token(SLOT_ID) || is_cca_token(SLOT_ID)) { pkey = CK_TRUE; rv += run_GenerateECCKeyPairSignVerify(); rv += run_ImportECCKeyPairSignVerify(); rv += run_TransferECCKeyPairSignVerify(); rv += run_DeriveECDHKey(FALSE); rv += run_DeriveECDHKeyKAT(); rv += run_ImportSignVerify_Pkey(); rv += run_GenerateEdwardsKeyPairSignVerify(); rv += run_ImportEdwardsKeyPairSignVerifyKAT(); rv += run_TransferEdwardsMontgomeryKeyPair(); rv += run_MontgomeryECDHKeyKAT(); rv += run_EncapsDecapsECDH(FALSE); } #endif testcase_print_result(); funcs->C_Finalize(NULL); return testcase_return(rv); } opencryptoki-opencryptoki-451d99c/testcases/crypto/ibm_ml_dsa.h000066400000000000000000007623071520105705100251200ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2025 * * 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 */ struct ML_DSA_TEST_VECTOR { char *name; CK_ULONG parameter_set; CK_ULONG rho_len; CK_BYTE rho[32]; CK_ULONG seed_len; CK_BYTE seed[32]; CK_ULONG tr_len; CK_BYTE tr[64]; CK_ULONG s1_len; CK_BYTE s1[672]; CK_ULONG s2_len; CK_BYTE s2[768]; CK_ULONG t0_len; CK_BYTE t0[3328]; CK_ULONG t1_len; CK_BYTE t1[2560]; CK_ULONG priv_seed_len; CK_BYTE priv_seed[32]; CK_BYTE pkcs8[8192]; CK_ULONG pkcs8_len; CK_BYTE spki[8192]; CK_ULONG spki_len; }; struct ML_DSA_TEST_VECTOR ml_dsa_tv[] = { { .name = "ML-DSA 44 (PKCS#8/SPKI - both)", .pkcs8 = { 0x30, 0x82, 0x0a, 0x3e, 0x02, 0x01, 0x00, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x11, 0x04, 0x82, 0x0a, 0x2a, 0x30, 0x82, 0x0a, 0x26, 0x04, 0x20, 0x4c, 0x6b, 0xf5, 0xa2, 0xc3, 0x87, 0xa6, 0x8f, 0x78, 0x28, 0xe3, 0xb3, 0x73, 0x33, 0xbb, 0xa3, 0xd5, 0x0f, 0x7f, 0x83, 0x89, 0xa5, 0x49, 0x3e, 0x69, 0x54, 0xd4, 0x15, 0x6e, 0x9d, 0xb9, 0x46, 0x04, 0x82, 0x0a, 0x00, 0x25, 0x1a, 0x4d, 0x38, 0xd4, 0xec, 0x99, 0xa5, 0x82, 0xba, 0x25, 0x3b, 0x5b, 0x21, 0x22, 0x1a, 0xd2, 0x91, 0x60, 0xd1, 0x30, 0xe9, 0xf6, 0xea, 0x2e, 0xb1, 0x59, 0x2e, 0xb9, 0x44, 0x6b, 0x37, 0xc9, 0xfb, 0xfc, 0xef, 0x11, 0x91, 0x47, 0xf1, 0x33, 0x40, 0xe2, 0x4f, 0x29, 0x99, 0x7e, 0x75, 0xf1, 0xd9, 0x44, 0x6d, 0x2a, 0xdd, 0xa6, 0xc8, 0x8a, 0xd8, 0x95, 0xb5, 0x49, 0xca, 0x32, 0x5f, 0x21, 0x86, 0xbf, 0x01, 0x1a, 0x1d, 0x6b, 0x75, 0x7d, 0x92, 0x6f, 0x0b, 0x80, 0x69, 0x00, 0xc6, 0xf0, 0x5f, 0x1d, 0x15, 0x41, 0x63, 0x99, 0x94, 0xf8, 0x71, 0x17, 0xd6, 0x28, 0x2a, 0x20, 0xa9, 0xf0, 0x4a, 0x1c, 0xa5, 0x6e, 0x41, 0x0e, 0xb3, 0x14, 0x21, 0x2c, 0x93, 0xea, 0x07, 0xed, 0xeb, 0xfb, 0x03, 0xd5, 0xfc, 0x54, 0x15, 0x1f, 0x9e, 0x54, 0xa7, 0x03, 0xb6, 0xba, 0x94, 0xdc, 0x69, 0x0a, 0x16, 0x4a, 0x4b, 0xc2, 0x69, 0x08, 0x41, 0x69, 0x12, 0xb2, 0x01, 0x92, 0xa2, 0x10, 0x5b, 0xb0, 0x01, 0x23, 0x86, 0x50, 0x21, 0xa4, 0x49, 0x4b, 0x28, 0x6a, 0x43, 0xc0, 0x10, 0x10, 0x14, 0x90, 0xa4, 0xa0, 0x24, 0xc9, 0x26, 0x42, 0xa2, 0x92, 0x30, 0x12, 0x86, 0x8c, 0xd2, 0x18, 0x0a, 0x42, 0x90, 0x40, 0xd2, 0xb2, 0x2d, 0xd4, 0x88, 0x91, 0xa0, 0x04, 0x52, 0x84, 0xc0, 0x08, 0x11, 0x81, 0x44, 0xe1, 0x40, 0x49, 0x81, 0x18, 0x86, 0xe1, 0x48, 0x09, 0xc2, 0x20, 0x90, 0x0c, 0x34, 0x29, 0x0a, 0x20, 0x65, 0xc9, 0x12, 0x42, 0x43, 0xa8, 0x60, 0xd3, 0x34, 0x8a, 0x44, 0x38, 0x91, 0x5c, 0xa4, 0x8d, 0x08, 0x36, 0x0c, 0x11, 0x17, 0x85, 0x09, 0x83, 0x20, 0x62, 0xa2, 0x65, 0x43, 0x12, 0x09, 0xc9, 0xc6, 0x88, 0xc4, 0x32, 0x02, 0x02, 0x14, 0x70, 0xd9, 0x86, 0x8d, 0x22, 0x37, 0x42, 0x88, 0xb6, 0x29, 0x1b, 0x08, 0x24, 0xc9, 0xb2, 0x68, 0x00, 0x33, 0x48, 0x40, 0x26, 0x91, 0x14, 0xc1, 0x81, 0x94, 0xc8, 0x01, 0xd4, 0xa2, 0x29, 0x0c, 0x11, 0x69, 0x54, 0x12, 0x24, 0x43, 0x22, 0x2d, 0x92, 0x38, 0x82, 0x02, 0xb9, 0x24, 0xd8, 0xc0, 0x21, 0x23, 0x92, 0x50, 0xcb, 0x26, 0x82, 0x53, 0x04, 0x0d, 0x62, 0x18, 0x29, 0x09, 0x20, 0x01, 0xe3, 0xb8, 0x91, 0xa0, 0x06, 0x09, 0xa0, 0xa6, 0x0c, 0x59, 0x32, 0x30, 0xda, 0x46, 0x20, 0x11, 0x35, 0x8a, 0x43, 0x04, 0x4d, 0x42, 0x22, 0x44, 0x22, 0x33, 0x41, 0xdc, 0x20, 0x65, 0x4a, 0x28, 0x52, 0x0c, 0xb7, 0x11, 0x5b, 0x90, 0x01, 0xa4, 0x32, 0x10, 0x08, 0xb9, 0x6c, 0x9a, 0x32, 0x6a, 0x84, 0x42, 0x90, 0xdb, 0xc2, 0x45, 0xd4, 0xb2, 0x10, 0x21, 0x12, 0x10, 0xa3, 0xc6, 0x8c, 0xd1, 0x30, 0x26, 0x8a, 0x86, 0x81, 0x14, 0xa2, 0x28, 0x1b, 0x27, 0x45, 0x92, 0x18, 0x41, 0x5b, 0xc8, 0x0d, 0xc9, 0x24, 0x42, 0x4b, 0x46, 0x82, 0x1c, 0xb1, 0x29, 0x0a, 0xc6, 0x68, 0x09, 0x19, 0x8a, 0x03, 0xc3, 0x11, 0x24, 0x02, 0x82, 0x44, 0x24, 0x51, 0xc0, 0x10, 0x41, 0x99, 0x26, 0x81, 0x03, 0x06, 0x11, 0xc4, 0xc2, 0x24, 0xd8, 0x30, 0x90, 0xc9, 0x26, 0x01, 0x9b, 0x28, 0x30, 0x20, 0x15, 0x26, 0x22, 0x24, 0x4d, 0xda, 0x90, 0x4c, 0x0b, 0x09, 0x25, 0x54, 0x32, 0x6d, 0x00, 0x02, 0x51, 0x8c, 0x40, 0x68, 0xa0, 0x36, 0x0c, 0xda, 0x06, 0x4c, 0x80, 0x00, 0x11, 0x03, 0xc6, 0x31, 0x93, 0x02, 0x86, 0x13, 0x18, 0x70, 0x23, 0x94, 0x84, 0xcb, 0x16, 0x64, 0xa1, 0xa4, 0x29, 0x93, 0x30, 0x70, 0x13, 0xa1, 0x31, 0x23, 0x83, 0x45, 0x89, 0xc0, 0x40, 0x13, 0x15, 0x0e, 0x8b, 0x42, 0x0a, 0x1b, 0x95, 0x28, 0xe1, 0x34, 0x24, 0x14, 0x16, 0x12, 0x01, 0x94, 0x6d, 0xa4, 0x32, 0x12, 0xc9, 0xc4, 0x64, 0x1a, 0xc3, 0x90, 0x1a, 0x05, 0x32, 0x99, 0x28, 0x28, 0x50, 0x08, 0x45, 0xa3, 0xc2, 0x49, 0xdc, 0x30, 0x92, 0x09, 0xc7, 0x2d, 0x99, 0x00, 0x0d, 0x89, 0x36, 0x09, 0xa1, 0x80, 0x81, 0xe1, 0x88, 0x20, 0x8b, 0xc0, 0x49, 0x22, 0xb5, 0x20, 0xa3, 0x20, 0x21, 0x1b, 0x29, 0x6d, 0xcb, 0x40, 0x6a, 0x23, 0x87, 0x11, 0x4a, 0x42, 0x31, 0xc9, 0x08, 0x24, 0x4c, 0x44, 0x90, 0x1c, 0x95, 0x69, 0xe2, 0x96, 0x84, 0x98, 0x12, 0x66, 0x9b, 0xc6, 0x08, 0xa2, 0x24, 0x09, 0x14, 0x82, 0x08, 0x83, 0x06, 0x64, 0x43, 0x48, 0x89, 0x99, 0x18, 0x65, 0xa2, 0x26, 0x6c, 0x48, 0x94, 0x0c, 0x13, 0x83, 0x20, 0x94, 0xc4, 0x8d, 0x13, 0x43, 0x6d, 0xe0, 0x14, 0x06, 0x18, 0x93, 0x8d, 0x5b, 0x38, 0x2c, 0x23, 0x38, 0x21, 0x94, 0x30, 0x60, 0x21, 0xb8, 0x60, 0x0c, 0xc2, 0x69, 0x19, 0x39, 0x60, 0x58, 0x34, 0x02, 0x18, 0xb3, 0x80, 0x21, 0x95, 0x4d, 0x9a, 0x14, 0x65, 0xdc, 0xa8, 0x49, 0xa0, 0x04, 0x4a, 0x1b, 0x99, 0x44, 0xdc, 0x16, 0x8d, 0x58, 0x92, 0x2d, 0x43, 0x12, 0x20, 0x61, 0x36, 0x00, 0x08, 0x93, 0x84, 0xa0, 0x00, 0x2e, 0x13, 0x46, 0x48, 0x8a, 0xa2, 0x65, 0x01, 0x25, 0x42, 0x02, 0x44, 0x8d, 0x01, 0x34, 0x61, 0xd9, 0x00, 0x24, 0xd8, 0x14, 0x01, 0xc9, 0x46, 0x6d, 0x14, 0x21, 0x71, 0xa0, 0x14, 0x04, 0x59, 0x44, 0x72, 0x01, 0xc0, 0x28, 0x92, 0xc0, 0x88, 0x9b, 0xa0, 0x80, 0x89, 0xa0, 0x70, 0xc4, 0x34, 0x2a, 0x09, 0xa6, 0x51, 0x88, 0x36, 0x42, 0x1a, 0x38, 0x2e, 0x24, 0x12, 0x28, 0x02, 0x23, 0x8c, 0x9a, 0x86, 0x50, 0x12, 0xa6, 0x65, 0xca, 0xc6, 0x85, 0x1c, 0x11, 0x61, 0x81, 0x48, 0x49, 0x02, 0x08, 0x6c, 0x51, 0x48, 0x52, 0x82, 0xc6, 0x09, 0xc3, 0x46, 0x2c, 0x54, 0xb6, 0x90, 0x58, 0x44, 0x8c, 0xdc, 0x30, 0x45, 0x48, 0x02, 0x52, 0x24, 0x35, 0x21, 0x8a, 0x40, 0x66, 0x02, 0x38, 0x02, 0xcb, 0xb6, 0x61, 0x50, 0x92, 0x60, 0x13, 0x12, 0x12, 0x50, 0x02, 0x01, 0x03, 0x88, 0x65, 0xdc, 0x82, 0x61, 0x8b, 0x40, 0x0d, 0xd3, 0x24, 0x31, 0x18, 0x16, 0x00, 0xd2, 0x44, 0x0e, 0xa2, 0x20, 0x71, 0x4c, 0x06, 0x02, 0x09, 0x05, 0x2c, 0xe2, 0x38, 0x51, 0x21, 0xb4, 0x90, 0x89, 0xc0, 0x6d, 0xe3, 0x34, 0x40, 0xe4, 0x26, 0x84, 0x4a, 0x32, 0x50, 0x03, 0x85, 0x51, 0x01, 0xb5, 0x0d, 0x5b, 0x06, 0x61, 0xdb, 0x34, 0x40, 0x98, 0x96, 0x48, 0x02, 0x32, 0x22, 0xe1, 0x34, 0x0d, 0x64, 0x20, 0x06, 0x12, 0xa9, 0x64, 0x14, 0x46, 0x69, 0x23, 0xc1, 0x40, 0x12, 0x21, 0x32, 0xa2, 0xa8, 0x24, 0x24, 0xe7, 0xe2, 0xc9, 0xe1, 0xae, 0x62, 0x76, 0xaa, 0x10, 0xee, 0xd6, 0x2c, 0xa9, 0x0b, 0x3d, 0x00, 0x5b, 0xef, 0x04, 0xbf, 0xad, 0x3c, 0xc7, 0xf7, 0xba, 0x87, 0x0f, 0xb5, 0x1e, 0x7c, 0xb8, 0x1d, 0x43, 0xf0, 0x92, 0x52, 0xb9, 0x48, 0x00, 0x01, 0x42, 0x1a, 0xa3, 0xfe, 0x57, 0x1e, 0x1f, 0x53, 0x43, 0x4f, 0x22, 0x08, 0xb1, 0x0a, 0x05, 0x8b, 0x7e, 0xcc, 0x97, 0x58, 0x0e, 0xaa, 0x22, 0x48, 0x67, 0xd6, 0x32, 0xe8, 0x26, 0x6a, 0x93, 0xd3, 0xa4, 0x44, 0xc8, 0x46, 0xe4, 0x0c, 0x7a, 0x9c, 0xb5, 0xce, 0xb4, 0xf4, 0x17, 0xd6, 0x45, 0xbd, 0xbd, 0x67, 0x32, 0x1c, 0x15, 0xf8, 0xd6, 0x2f, 0x3b, 0x44, 0xe9, 0x3c, 0xf9, 0x8d, 0xcd, 0x2e, 0xfb, 0xb6, 0x10, 0x35, 0xae, 0x9b, 0xe2, 0x36, 0x5c, 0xb9, 0x5c, 0xc0, 0xff, 0xa5, 0x43, 0x88, 0x2f, 0xce, 0xb6, 0x38, 0x91, 0xc0, 0xa8, 0x18, 0x8d, 0x4f, 0x6b, 0xaa, 0x7d, 0x8f, 0xcf, 0x92, 0x17, 0x36, 0x5c, 0xf0, 0xf6, 0x7f, 0x0b, 0x6e, 0x8c, 0x01, 0xa6, 0x80, 0xd1, 0xc7, 0x60, 0x0a, 0xc3, 0x70, 0x6b, 0xd1, 0xb7, 0xf2, 0xd2, 0xd1, 0xb6, 0x09, 0x26, 0x34, 0x6b, 0x50, 0x6d, 0xd0, 0x6e, 0xab, 0xd9, 0x42, 0x0a, 0xeb, 0xbc, 0xa9, 0xef, 0x18, 0x30, 0x21, 0xca, 0xcb, 0xe1, 0x58, 0x7d, 0xae, 0x5e, 0x2b, 0x2d, 0xee, 0x5e, 0xd8, 0x0f, 0xe7, 0xf4, 0xe2, 0x83, 0x1b, 0x1d, 0xbe, 0xf1, 0x4e, 0x01, 0x06, 0xb8, 0xb8, 0xff, 0xb8, 0xa7, 0xc5, 0x14, 0x12, 0x0f, 0x44, 0xa5, 0x94, 0x35, 0x23, 0xa0, 0x97, 0x3d, 0xfc, 0x98, 0x08, 0x9b, 0x60, 0xf1, 0x73, 0xda, 0xd6, 0xdb, 0xd4, 0x9e, 0x34, 0xf1, 0xf2, 0x15, 0xfb, 0x19, 0xdf, 0x73, 0xa3, 0x6a, 0xa3, 0x7f, 0x22, 0x9a, 0x91, 0xa5, 0xd7, 0x53, 0x97, 0x2d, 0xbe, 0x9d, 0x25, 0x64, 0x61, 0xfc, 0xd7, 0x73, 0x44, 0x2b, 0x01, 0x0a, 0x32, 0xc8, 0x56, 0x35, 0x71, 0x89, 0x0b, 0x74, 0xa6, 0xb3, 0x9a, 0x48, 0x5e, 0xd0, 0x78, 0x6f, 0x16, 0x13, 0xc2, 0x8d, 0xbb, 0x34, 0x54, 0xa6, 0x46, 0x6c, 0xf9, 0x2b, 0xaf, 0x24, 0xf9, 0xb7, 0x20, 0x83, 0x1a, 0xd8, 0x1a, 0x5c, 0x1a, 0x05, 0xc3, 0xeb, 0x8d, 0x7d, 0xa7, 0x71, 0xf6, 0x0b, 0x28, 0x17, 0xf8, 0xd9, 0xba, 0xce, 0x67, 0x82, 0x32, 0x75, 0xb3, 0xe1, 0x32, 0xca, 0x3d, 0x0c, 0x16, 0x23, 0x47, 0x36, 0x77, 0x2f, 0xe9, 0xd0, 0x5e, 0x47, 0xf6, 0xca, 0xc6, 0xe2, 0x36, 0xa6, 0xc6, 0x3c, 0xc4, 0x97, 0x2b, 0x76, 0xde, 0x2b, 0x54, 0xc5, 0x65, 0x96, 0x6a, 0xec, 0xd1, 0xbc, 0xf4, 0x24, 0x31, 0x59, 0x71, 0x4b, 0xed, 0x1c, 0x75, 0x8f, 0xe0, 0xca, 0x20, 0x82, 0x89, 0xa7, 0x16, 0x23, 0x24, 0xb0, 0xf4, 0xdf, 0xb0, 0x29, 0x75, 0x01, 0xb0, 0x28, 0xb9, 0x41, 0x48, 0xe5, 0xca, 0x5d, 0x02, 0x78, 0x83, 0x8d, 0x00, 0x49, 0x1d, 0xe9, 0x2a, 0x36, 0xa4, 0xb0, 0x29, 0x01, 0xd1, 0x1a, 0xda, 0x0b, 0xf4, 0xcf, 0x2f, 0xe3, 0xca, 0x2f, 0x5b, 0xa2, 0xc7, 0x2f, 0xec, 0xa2, 0x37, 0xfb, 0xcf, 0x3e, 0xc7, 0x34, 0xff, 0x7b, 0x41, 0x88, 0xbd, 0x75, 0x41, 0xe1, 0xe6, 0x08, 0xc1, 0x44, 0x19, 0x9b, 0x69, 0x39, 0x47, 0x72, 0x27, 0x82, 0xf1, 0x1e, 0x62, 0xcd, 0x70, 0x4a, 0x5a, 0xc1, 0x12, 0x2c, 0x30, 0x00, 0x4b, 0x27, 0x84, 0xbc, 0x0f, 0x69, 0x2f, 0xc5, 0x3d, 0x81, 0x92, 0x8a, 0x59, 0x65, 0xf3, 0x3d, 0x32, 0x10, 0x00, 0x55, 0x41, 0xa2, 0x0a, 0x6d, 0xd4, 0xe5, 0x6d, 0x52, 0x2e, 0xee, 0x6a, 0xf9, 0x4b, 0xfb, 0x50, 0xc9, 0x4c, 0xf9, 0x87, 0xd8, 0xc3, 0xb2, 0xf6, 0x30, 0x9d, 0x50, 0x0f, 0x40, 0x24, 0xf2, 0x82, 0x8d, 0x95, 0x64, 0x16, 0x12, 0xa9, 0x6b, 0x4a, 0xf6, 0xe3, 0x04, 0x9d, 0xc8, 0x4e, 0x8f, 0x10, 0x4c, 0x30, 0xfd, 0xe5, 0xa7, 0x07, 0xa8, 0x33, 0xcf, 0x25, 0xe6, 0xe8, 0xd8, 0x48, 0x72, 0xca, 0x5f, 0x8e, 0x39, 0xe7, 0x45, 0x7c, 0xfe, 0xe2, 0xa8, 0x09, 0x87, 0xc7, 0xd3, 0x28, 0x98, 0xbd, 0xb7, 0xaf, 0x67, 0x83, 0xb2, 0xd9, 0x0f, 0xf1, 0x47, 0x77, 0x6c, 0xd9, 0x3e, 0xcf, 0x48, 0xd3, 0xbe, 0x83, 0x8e, 0x93, 0xc9, 0x98, 0x49, 0x71, 0xe6, 0x1d, 0x07, 0xe8, 0x0e, 0xa8, 0x1d, 0x93, 0x85, 0x32, 0xcc, 0xd7, 0xcd, 0xde, 0xa9, 0x3b, 0x6e, 0x6a, 0x9d, 0xc3, 0xae, 0xde, 0x89, 0x10, 0xeb, 0x45, 0x7c, 0x2e, 0x75, 0x1a, 0xc3, 0xbf, 0x2f, 0x02, 0x78, 0x21, 0x7f, 0x4d, 0x94, 0x0b, 0x20, 0xc0, 0x60, 0x13, 0x4a, 0x5f, 0x6b, 0xbb, 0x22, 0x11, 0x3f, 0xc1, 0x87, 0xdf, 0x50, 0x16, 0x11, 0x40, 0x91, 0x99, 0x34, 0x5d, 0x2a, 0x4d, 0xa6, 0x5f, 0x30, 0x36, 0xde, 0x94, 0x5c, 0x4f, 0x5f, 0x27, 0x42, 0x23, 0xcf, 0xca, 0x87, 0xdc, 0x67, 0x26, 0x9a, 0xfc, 0xec, 0x5a, 0x46, 0xd4, 0xc0, 0x82, 0x14, 0xf8, 0x77, 0x54, 0x33, 0x5c, 0xb3, 0x24, 0x21, 0x5b, 0xe1, 0x04, 0xc4, 0xf0, 0xcb, 0xdf, 0x01, 0xef, 0x86, 0x16, 0x6b, 0x1c, 0x04, 0x07, 0xb0, 0x2b, 0xc7, 0x2a, 0x2c, 0x70, 0x77, 0xd9, 0x70, 0x43, 0xe2, 0xdb, 0xa5, 0xaf, 0xe7, 0x84, 0xde, 0x2c, 0x74, 0xb5, 0xe9, 0x08, 0xff, 0x00, 0xbc, 0x52, 0x9e, 0x92, 0x03, 0xc6, 0xda, 0x3d, 0x1d, 0xcf, 0xb6, 0xb3, 0x94, 0x60, 0x41, 0x60, 0x5f, 0xf1, 0xda, 0x5e, 0xe1, 0x09, 0xd5, 0xbd, 0x3c, 0xab, 0xa9, 0xc5, 0x6e, 0xce, 0x76, 0xc9, 0x0a, 0xff, 0x32, 0x87, 0x28, 0xeb, 0x4a, 0x73, 0x26, 0xec, 0x28, 0x63, 0x1f, 0x9b, 0xfe, 0x72, 0x84, 0x89, 0x5c, 0x7c, 0x36, 0xa2, 0xb6, 0xfa, 0x12, 0x41, 0x7e, 0x18, 0x94, 0xa6, 0x72, 0x4a, 0xd1, 0x1a, 0x86, 0x6b, 0xbb, 0xdc, 0x20, 0x57, 0x01, 0xaa, 0x05, 0xe4, 0x34, 0x2b, 0x4b, 0x9a, 0x8e, 0x62, 0x87, 0x0a, 0x42, 0x63, 0x68, 0x2c, 0xe3, 0x72, 0x11, 0x7a, 0x0a, 0x0f, 0x04, 0xe4, 0xe7, 0x6b, 0x43, 0xfe, 0x11, 0x48, 0xe0, 0x57, 0xfc, 0xb2, 0x39, 0x4d, 0x21, 0x63, 0x1c, 0xd3, 0x11, 0xbf, 0x24, 0x1a, 0x3e, 0x9f, 0x94, 0x03, 0x9a, 0xbf, 0x3d, 0x5f, 0x01, 0xa1, 0xc0, 0x23, 0x94, 0xb1, 0xc4, 0x5f, 0xf7, 0xb5, 0xb6, 0xbe, 0xeb, 0x6e, 0xfe, 0x10, 0xb8, 0x02, 0xee, 0x25, 0x88, 0xc2, 0x58, 0x32, 0x58, 0x94, 0xa3, 0x70, 0x02, 0x6f, 0x75, 0x23, 0xe0, 0x61, 0x37, 0xa6, 0x61, 0x59, 0x46, 0xb3, 0xca, 0xbb, 0x53, 0xd9, 0xa4, 0x07, 0x91, 0xb5, 0x88, 0xb6, 0xef, 0x31, 0x9c, 0xee, 0xa1, 0x56, 0x45, 0xf7, 0xf8, 0x03, 0x1c, 0xb7, 0xd4, 0x31, 0xee, 0x19, 0x7f, 0xcc, 0xdd, 0xff, 0x4f, 0x1a, 0xf0, 0x9e, 0x62, 0x57, 0x73, 0x59, 0x83, 0x5a, 0x28, 0xad, 0xb7, 0x52, 0xe2, 0x30, 0xf6, 0x21, 0x77, 0xeb, 0x31, 0x8c, 0xd1, 0x2f, 0x10, 0x40, 0x1f, 0x7f, 0xa6, 0x26, 0x77, 0x5a, 0x22, 0x31, 0xa6, 0xf4, 0x98, 0x3d, 0x37, 0x9a, 0xde, 0xaf, 0x75, 0x2f, 0xa4, 0x8d, 0x25, 0x3e, 0x35, 0xa4, 0xa3, 0x81, 0x93, 0x75, 0xe1, 0xd3, 0x27, 0xa4, 0xaf, 0xcf, 0x7a, 0x52, 0x2a, 0xf0, 0x03, 0x3d, 0x04, 0x0c, 0xdc, 0xff, 0xf6, 0x1a, 0xfe, 0xdf, 0x62, 0x9b, 0xeb, 0xd0, 0xde, 0x07, 0xd4, 0x67, 0xef, 0x43, 0x9c, 0x28, 0x3f, 0xa7, 0x42, 0xbc, 0x1a, 0xc8, 0x57, 0xe1, 0x01, 0x95, 0xa4, 0x66, 0x07, 0x21, 0xe9, 0xed, 0xaf, 0xf4, 0x77, 0x55, 0x8e, 0xaf, 0x96, 0xbb, 0x6c, 0x4e, 0x9b, 0x17, 0x45, 0x15, 0xb3, 0x53, 0x2d, 0xfa, 0x50, 0x6c, 0xfd, 0x32, 0xad, 0xb3, 0xca, 0x34, 0x2f, 0x3a, 0x91, 0x6c, 0x58, 0xf7, 0x07, 0x5f, 0xc4, 0xc0, 0x08, 0xd7, 0xb2, 0x15, 0xd7, 0xf4, 0xac, 0x1b, 0x68, 0x47, 0xd2, 0xdc, 0x54, 0x97, 0xd5, 0xb5, 0x0a, 0x92, 0xa3, 0x6c, 0xe7, 0x60, 0x9f, 0xab, 0x60, 0x38, 0xa8, 0xa1, 0x66, 0x37, 0xc6, 0x8d, 0x1c, 0xa6, 0x11, 0x17, 0x92, 0x34, 0xce, 0x28, 0x07, 0xaa, 0x98, 0xd3, 0x3a, 0x9a, 0x1a, 0xde, 0xb8, 0x35, 0x4d, 0xf2, 0x3e, 0x3b, 0xed, 0xfb, 0xbe, 0x97, 0xc8, 0xab, 0xd9, 0x1e, 0xcc, 0x4b, 0x6b, 0x0d, 0x79, 0x8f, 0x8c, 0xc2, 0x41, 0x03, 0xbb, 0x29, 0xc9, 0xeb, 0xd3, 0x92, 0x66, 0x65, 0xfc, 0x2e, 0x7e, 0x7b, 0x70, 0xd0, 0xa2, 0x1d, 0x80, 0x07, 0x35, 0xa5, 0xa7, 0xd4, 0xd5, 0x3e, 0xcf, 0x59, 0x53, 0x81, 0xf6, 0x8b, 0x5c, 0x0e, 0x76, 0xa5, 0xc9, 0xf1, 0x69, 0x4a, 0x1a, 0xf9, 0x6c, 0x49, 0xeb, 0x5d, 0x22, 0x42, 0xbe, 0x4d, 0xb6, 0x60, 0x83, 0xd2, 0x8e, 0xaa, 0xcf, 0x65, 0x27, 0x20, 0xfd, 0x80, 0x82, 0xd3, 0xeb, 0x4e, 0x13, 0x25, 0x5e, 0xab, 0x81, 0xdb, 0xf4, 0x4b, 0x86, 0xd3, 0xc3, 0x3d, 0x7e, 0xc6, 0x07, 0x97, 0x78, 0xca, 0x7f, 0xe4, 0x21, 0x04, 0x80, 0x04, 0x02, 0xb4, 0x0e, 0xb5, 0x1e, 0xbe, 0x1b, 0x4f, 0x7d, 0x00, 0xc2, 0x78, 0x3d, 0x50, 0x06, 0xe6, 0x27, 0x6d, 0x14, 0x2e, 0x3c, 0x7b, 0x80, 0x7c, 0xa4, 0x1b, 0x01, 0xb5, 0xd1, 0x74, 0x19, 0xc7, 0x8f, 0xf6, 0xcd, 0x7c, 0x4c, 0xce, 0xc4, 0x6b, 0xc6, 0xca, 0x5f, 0x9c, 0x22, 0xe3, 0x8e, 0x35, 0xe9, 0xd6, 0xda, 0xb5, 0x72, 0xee, 0x0d, 0x0d, 0xc1, 0xd7, 0x7f, 0xa6, 0xd9, 0x0d, 0x42, 0x23, 0xea, 0x1c, 0xd7, 0xb0, 0x62, 0x2e, 0xc5, 0x5c, 0xc7, 0x41, 0x2c, 0x4d, 0xa0, 0xf7, 0x46, 0x76, 0x9e, 0x29, 0xa9, 0x76, 0x00, 0x1d, 0x54, 0x0a, 0xfe, 0xd3, 0xc1, 0xb4, 0xf2, 0x6e, 0xa2, 0x01, 0x03, 0x65, 0x54, 0xbc, 0x0c, 0x01, 0xd8, 0x69, 0xa8, 0xf4, 0x0b, 0x47, 0xa6, 0xe7, 0xbe, 0xd9, 0x0f, 0x41, 0xbf, 0xcf, 0x19, 0x14, 0xd3, 0x98, 0x43, 0xe8, 0x9d, 0xe2, 0xb0, 0xd1, 0x5c, 0x24, 0x86, 0x8b, 0xc9, 0xee, 0xba, 0x12, 0xe6, 0xb9, 0xe6, 0xba, 0x84, 0x73, 0x6f, 0x70, 0x57, 0xa3, 0x5a, 0x67, 0x12, 0x62, 0x8d, 0xc5, 0x92, 0xf2, 0x9c, 0x70, 0xec, 0xbb, 0x04, 0xda, 0x6e, 0x8c, 0x88, 0x65, 0xad, 0xd5, 0x4a, 0x90, 0x19, 0x26, 0x07, 0x34, 0x75, 0x2d, 0xea, 0x70, 0xf7, 0x64, 0x22, 0x24, 0x00, 0x93, 0xc5, 0xa1, 0x9f, 0x0b, 0x53, 0x1c, 0x71, 0x6c, 0x84, 0xe0, 0xc4, 0xfa, 0x4e, 0xb4, 0xfa, 0x95, 0x33, 0x4c, 0xf4, 0x1c, 0x28, 0x98, 0x01, 0x3a, 0xed, 0xd2, 0xdd, 0xd2, 0x66, 0x09, 0x35, 0x43, 0x3d, 0x23, 0x09, 0x44, 0xee, 0xb5, 0x00, 0x33, 0xdf, 0xda, 0x22, 0xbe, 0x38, 0x5b, 0xa7, 0x2a, 0x7e, 0x12, 0xc9, 0x70, 0x98, 0x21, 0x06, 0x25, 0x73, 0x4c, 0x29, 0x0c, 0xa0, 0x3f, 0x95, 0xd1, 0x19, 0x2e, 0xec, 0xfa, 0x30, 0xf6, 0xe3, 0xe2, 0x7e, 0x21, 0xad, 0xe7, 0x5c, 0x60, 0x55, 0xa1, 0x2b, 0xef, 0x1e, 0x52, 0x15, 0xc3, 0x5d, 0x4c, 0xcd, 0x31, 0xd0, 0x07, 0x75, 0xf1, 0x09, 0x74, 0x1c, 0x79, 0xb2, 0x59, 0xdc, 0xe7, 0x55, 0x8e, 0xdf, 0x79, 0xb1, 0x6a, 0x58, 0x67, 0x47, 0x4d, 0x9c, 0x07, 0x01, 0xaf, 0x90, 0xba, 0xfe, 0x7a, 0x51, 0x66, 0xcd, 0x90, 0x58, 0x72, 0x78, 0x2a, 0x70, 0xcf, 0xb8, 0x74, 0xc6, 0x83, 0xd3, 0x85, 0x16, 0xb3, 0x57, 0x3f, 0xe4, 0x67, 0xeb, 0x9a, 0xe1, 0x32, 0x4a, 0xb7, 0x0e, 0xcf, 0x76, 0x86, 0xa8, 0xf8, 0x5a, 0x52, 0x09, 0x59, 0xa1, 0xaa, 0x20, 0x7d, 0x1d, 0x22, 0x04, 0x30, 0x28, 0xdc, 0xc9, 0x25, 0x75, 0xa1, 0x5c, 0xae, 0x0f, 0x7d, 0x28, 0x6e, 0xca, 0xe4, 0x0b, 0x80, 0xa3, 0x79, 0x06, 0xa0, 0x92, 0xeb, 0x59, 0x61, 0xcc, 0xb4, 0xe4, 0xc7, 0x0c, 0xf7, 0xa7, 0xf5, 0x08, 0x3b, 0xc2, 0x5e, 0x2d, 0x26, 0x86, 0x18, 0x9b, 0x16, 0x49, 0x66, 0x53, 0x51, 0xdb, 0x85, 0xe9, 0xd0, 0x4f, 0x03, 0x81, 0x6e, 0xfb, 0x8c, 0xc0, 0x38, 0x1d, 0x0d, 0x75, 0xaf, 0xc8, 0xa1, 0x2a, 0x06, 0xa7, 0x9a, 0x97, 0x55, 0x0d, 0xb5, 0x46, 0x9d, 0xde, 0xb2, 0x55, 0xfd, 0x69, 0x1d, 0xe1, 0xd7, 0x76, 0x59, 0x1e, 0xb7, 0x3e, 0x55, 0xe0, 0xc2, 0xee, 0xe1, 0x28, 0xf3, 0x4d, 0xb3, 0x6a, 0x76, 0x70, 0xaf, 0x8a }, .pkcs8_len = 2626, .spki = { 0x30, 0x82, 0x05, 0x32, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x11, 0x03, 0x82, 0x05, 0x21, 0x00, 0x25, 0x1a, 0x4d, 0x38, 0xd4, 0xec, 0x99, 0xa5, 0x82, 0xba, 0x25, 0x3b, 0x5b, 0x21, 0x22, 0x1a, 0xd2, 0x91, 0x60, 0xd1, 0x30, 0xe9, 0xf6, 0xea, 0x2e, 0xb1, 0x59, 0x2e, 0xb9, 0x44, 0x6b, 0x37, 0x6d, 0x23, 0x53, 0x4f, 0x8c, 0x80, 0x89, 0x93, 0x1e, 0x03, 0x46, 0xe6, 0x21, 0x1f, 0x11, 0xc7, 0x3c, 0x2c, 0x63, 0xfd, 0xe6, 0x7d, 0x96, 0x65, 0x47, 0xc9, 0xf0, 0xca, 0xe2, 0xd4, 0xea, 0x98, 0x53, 0xc3, 0xb5, 0x0a, 0x04, 0xf8, 0x2f, 0xf1, 0xb7, 0x7c, 0x65, 0x93, 0x0c, 0xa4, 0x80, 0xf4, 0x14, 0xf3, 0x4e, 0x0e, 0x35, 0xf4, 0x5a, 0xee, 0xa0, 0x8e, 0x7a, 0xe7, 0x1e, 0xe5, 0x12, 0xa9, 0xa7, 0x2d, 0xc2, 0xf3, 0x7b, 0x7b, 0x98, 0x7d, 0xcc, 0x29, 0xfa, 0x26, 0xa6, 0xcd, 0x07, 0xf8, 0xab, 0x17, 0x37, 0x06, 0x81, 0x01, 0x38, 0xeb, 0xc4, 0xc4, 0xba, 0xa7, 0x0c, 0xec, 0x5d, 0xd2, 0x6d, 0x58, 0x11, 0xd5, 0x61, 0xe0, 0x1e, 0xd5, 0xc8, 0x20, 0xc3, 0x56, 0x31, 0x55, 0x7d, 0x05, 0x3e, 0xcf, 0x9b, 0x6e, 0xde, 0x61, 0x9b, 0x0c, 0x33, 0xcb, 0x6d, 0xc6, 0x6e, 0xc8, 0x8b, 0xd8, 0xc5, 0x12, 0x77, 0x7f, 0x22, 0xe5, 0xf6, 0xbf, 0x14, 0xfa, 0x88, 0x53, 0x95, 0x62, 0xe5, 0x25, 0x44, 0x5d, 0x81, 0x4d, 0xc2, 0xa6, 0xda, 0x13, 0xd7, 0xa6, 0x01, 0xfd, 0x59, 0x45, 0x34, 0x4c, 0x21, 0x15, 0x14, 0xcd, 0x14, 0x28, 0x90, 0xb2, 0x82, 0x37, 0x53, 0xc7, 0x5f, 0xd5, 0x4e, 0x40, 0xc8, 0x94, 0x6a, 0x7f, 0x2e, 0x3b, 0xf1, 0x50, 0x07, 0xb2, 0x8e, 0xbd, 0x4e, 0x45, 0x12, 0xd7, 0xc0, 0xc3, 0x35, 0xfe, 0x0a, 0xb4, 0xcc, 0x98, 0xdc, 0x38, 0x1a, 0x04, 0xd0, 0x8b, 0x84, 0x87, 0x10, 0xc3, 0x4f, 0x40, 0x59, 0xa0, 0xf2, 0x91, 0xb3, 0xa1, 0x46, 0xc7, 0x7d, 0xab, 0xca, 0xd1, 0xb9, 0xc4, 0x1e, 0x49, 0x73, 0x8e, 0x7b, 0x77, 0x14, 0x66, 0x70, 0x20, 0x4c, 0xa8, 0xce, 0x60, 0x7d, 0xf1, 0x56, 0x40, 0xf5, 0x48, 0x73, 0xda, 0x86, 0xf5, 0x7b, 0xaa, 0x9a, 0xb8, 0x0b, 0x85, 0x4e, 0x94, 0x20, 0x8e, 0xe2, 0xe9, 0x0b, 0x72, 0x88, 0xcf, 0x3a, 0xd2, 0x61, 0x14, 0x24, 0x9e, 0xae, 0x09, 0xb5, 0xc6, 0xbf, 0x90, 0x79, 0xf9, 0x6a, 0x0e, 0x30, 0xb5, 0x0a, 0xbe, 0x47, 0x6a, 0x2c, 0xb0, 0xdc, 0x05, 0x92, 0x7e, 0x26, 0xab, 0x8c, 0x15, 0xab, 0x9b, 0x2b, 0x08, 0x44, 0xd7, 0xd2, 0x47, 0x09, 0xf6, 0xf5, 0x1e, 0x38, 0xdc, 0x7d, 0x65, 0xe4, 0xf3, 0x0f, 0x90, 0x62, 0xea, 0x76, 0x39, 0x2b, 0xd6, 0x42, 0xeb, 0x38, 0xca, 0xdb, 0x51, 0x03, 0xfa, 0xba, 0x2d, 0x72, 0xbf, 0xa3, 0xf4, 0x41, 0x37, 0x39, 0xdb, 0xeb, 0xc1, 0xb6, 0x22, 0xea, 0x60, 0x92, 0xe6, 0x4f, 0x2d, 0x2a, 0xbc, 0xde, 0xb9, 0x5e, 0xc3, 0xff, 0x39, 0xcd, 0x4a, 0xfc, 0xd7, 0x7e, 0xc0, 0xbe, 0xa3, 0x09, 0x72, 0xc4, 0x93, 0xe6, 0x05, 0x66, 0x8c, 0xe9, 0xfb, 0xde, 0x66, 0xb7, 0xbb, 0xb3, 0x17, 0x51, 0xd0, 0x2f, 0x75, 0x74, 0x35, 0x35, 0x5a, 0x6c, 0x03, 0xca, 0x3d, 0x26, 0xb2, 0x9f, 0x6f, 0xac, 0x76, 0x00, 0xfd, 0x6c, 0xf3, 0xc1, 0x57, 0x4c, 0xa9, 0xb4, 0x02, 0x18, 0xfd, 0xb1, 0x58, 0xb3, 0xf4, 0x1d, 0x79, 0x1f, 0x1d, 0xe1, 0x11, 0x96, 0x5e, 0xf6, 0x57, 0xc3, 0xa2, 0x5a, 0xf9, 0xa2, 0x39, 0x4d, 0x96, 0x19, 0xdc, 0xf2, 0x57, 0x0f, 0xfa, 0xc2, 0x4d, 0x58, 0xf2, 0xd2, 0xa2, 0x3a, 0x8e, 0x22, 0x0c, 0x2f, 0xb7, 0x04, 0x68, 0xbf, 0xd8, 0xeb, 0xbd, 0x61, 0x15, 0xe0, 0xfa, 0x45, 0xb7, 0x25, 0x0f, 0xb5, 0xb4, 0xda, 0x70, 0xdb, 0xe0, 0xd3, 0x09, 0xcc, 0x13, 0x0a, 0x32, 0xbb, 0x2c, 0x9c, 0x3d, 0x1b, 0xf5, 0x19, 0x5e, 0x1a, 0x1b, 0xf2, 0xe5, 0x20, 0x41, 0xd8, 0xe2, 0x1b, 0x97, 0xba, 0x97, 0x7b, 0xe3, 0xd1, 0x48, 0xa1, 0x47, 0x15, 0xea, 0xc1, 0x49, 0x63, 0x17, 0x27, 0x36, 0x6a, 0xb1, 0x47, 0x60, 0x54, 0xa0, 0x61, 0x6f, 0xd9, 0xd0, 0xbc, 0xd2, 0x24, 0x53, 0x93, 0x96, 0x26, 0xa6, 0x3c, 0xea, 0x94, 0x10, 0x06, 0xd9, 0x2e, 0x62, 0x11, 0xfe, 0xf7, 0xf5, 0x47, 0xb4, 0x24, 0xec, 0x24, 0xda, 0xc8, 0xe7, 0x32, 0x8d, 0xe2, 0x8d, 0x39, 0x50, 0xa6, 0xfa, 0xa9, 0xac, 0x85, 0xc1, 0xd9, 0x1a, 0xab, 0x25, 0x35, 0xc9, 0x3d, 0x37, 0xc6, 0x61, 0x28, 0x81, 0x67, 0x5c, 0x1f, 0x6f, 0xd5, 0x5e, 0x93, 0x98, 0xea, 0x85, 0x18, 0x48, 0xa8, 0x2d, 0x3e, 0x3f, 0x69, 0x21, 0xe6, 0x5e, 0xd6, 0x02, 0x0b, 0xd4, 0x7a, 0x79, 0x48, 0x4b, 0xdf, 0x37, 0x51, 0x4a, 0x5e, 0x7d, 0xda, 0x47, 0x9b, 0xd7, 0x13, 0x1a, 0x91, 0xec, 0x15, 0x4b, 0x1b, 0xe7, 0x83, 0x9a, 0x66, 0xe6, 0xc9, 0x2b, 0x4d, 0xbd, 0xc7, 0x43, 0xa0, 0x81, 0x7e, 0x86, 0xdf, 0x71, 0x27, 0xb3, 0x5c, 0x35, 0x99, 0x61, 0x86, 0xeb, 0x3c, 0xda, 0x52, 0xf2, 0x51, 0xe3, 0x33, 0x0e, 0x8c, 0xda, 0x09, 0xc1, 0x89, 0xfe, 0x55, 0x44, 0x91, 0xc2, 0x37, 0x85, 0x69, 0x9a, 0xe9, 0x41, 0x50, 0x9f, 0xf6, 0x84, 0x87, 0x90, 0x46, 0x86, 0xb0, 0xf5, 0x69, 0x2e, 0x7a, 0x93, 0x01, 0x7f, 0xce, 0x2f, 0xe0, 0x15, 0x88, 0x3f, 0xfb, 0xdb, 0xfa, 0xfe, 0x9c, 0x13, 0x0b, 0x63, 0xc9, 0x36, 0xdc, 0x4d, 0x42, 0x26, 0x57, 0xb5, 0xbd, 0xb8, 0x42, 0x1c, 0x7c, 0x5b, 0xa8, 0x33, 0x3c, 0xde, 0xe1, 0x7b, 0x07, 0x35, 0x11, 0xfd, 0x76, 0xb9, 0xad, 0x4d, 0x7e, 0x84, 0x36, 0xe6, 0x3c, 0x88, 0x2b, 0x1b, 0x71, 0x5b, 0x65, 0x2c, 0xd5, 0x3a, 0x6d, 0x44, 0xc4, 0x9e, 0x98, 0x62, 0xc5, 0xfa, 0xc1, 0x51, 0xa7, 0xdd, 0x7d, 0x5c, 0x04, 0x60, 0x9f, 0xf8, 0x27, 0x77, 0xc5, 0x01, 0x81, 0xbb, 0x01, 0xed, 0xbf, 0x17, 0xe5, 0x8d, 0x3e, 0x6c, 0x2f, 0xa8, 0x15, 0x2f, 0xb2, 0x59, 0xc3, 0x09, 0xfb, 0xa1, 0xa2, 0xf6, 0x75, 0xf9, 0x8d, 0x44, 0x6c, 0x5e, 0xda, 0xd4, 0xad, 0xe6, 0x9a, 0x57, 0x5b, 0x1a, 0x66, 0x9d, 0x39, 0x5f, 0x87, 0x75, 0x9e, 0x69, 0x57, 0xdb, 0xd9, 0xe3, 0xc5, 0x39, 0x59, 0xb8, 0x49, 0x59, 0xf4, 0xd0, 0x95, 0xc8, 0x01, 0x36, 0xfc, 0xb5, 0x8d, 0x45, 0x9d, 0x07, 0x69, 0xca, 0xf1, 0xf5, 0x27, 0xfd, 0x72, 0x4a, 0x0e, 0x51, 0xe6, 0x4c, 0x2a, 0xab, 0x00, 0xa9, 0x12, 0xab, 0x62, 0xec, 0x63, 0x3b, 0x1c, 0xbf, 0x87, 0x89, 0xf5, 0xe9, 0x27, 0x7d, 0x46, 0x45, 0x45, 0x62, 0x65, 0x65, 0x07, 0x10, 0x48, 0xa3, 0xe4, 0x5c, 0xcf, 0x2b, 0xa2, 0x09, 0xa3, 0x7c, 0x1c, 0x94, 0x02, 0xb7, 0x55, 0x6a, 0xd1, 0x6b, 0xba, 0x9d, 0x3c, 0x3f, 0x62, 0x0b, 0x68, 0xe6, 0x92, 0x96, 0xe7, 0xb2, 0x72, 0x7a, 0x3d, 0x25, 0x11, 0xd5, 0x77, 0x75, 0x67, 0xb8, 0x73, 0x56, 0xc1, 0xb6, 0x1a, 0xaf, 0x41, 0x7a, 0x03, 0xef, 0x05, 0x20, 0xa2, 0x1c, 0x42, 0x55, 0x22, 0xc7, 0x5f, 0x80, 0x05, 0x5e, 0xee, 0xec, 0x56, 0xa4, 0x24, 0xf8, 0x67, 0xe2, 0xf0, 0x93, 0xd5, 0x12, 0x30, 0xcd, 0x97, 0xca, 0xcb, 0xfe, 0x22, 0xb9, 0xaa, 0xe4, 0xdc, 0x56, 0x76, 0xd2, 0x4f, 0x12, 0xba, 0xbf, 0x8e, 0x39, 0x8c, 0x75, 0x65, 0xd2, 0xa6, 0xa4, 0x06, 0x0d, 0x27, 0x02, 0x58, 0x8a, 0x23, 0xc0, 0x9f, 0x3e, 0x18, 0xe9, 0xb5, 0x37, 0xc4, 0x70, 0xda, 0x96, 0x80, 0x1d, 0x93, 0x9b, 0xd2, 0x2b, 0x8f, 0xbb, 0x4e, 0x0a, 0xd0, 0xf0, 0xd2, 0x23, 0x3f, 0x31, 0xca, 0x56, 0x0a, 0xe5, 0x6f, 0xc1, 0x9c, 0x39, 0x39, 0x15, 0xb4, 0x2b, 0x6e, 0xa9, 0x30, 0x86, 0xf6, 0xa3, 0x9f, 0x30, 0x8f, 0x92, 0x2b, 0x37, 0x3f, 0x31, 0x29, 0x9c, 0xa7, 0x38, 0xa6, 0x7f, 0x25, 0xa3, 0xf8, 0x05, 0x68, 0x59, 0xcb, 0x3c, 0x71, 0x09, 0xbe, 0xc7, 0x71, 0x8b, 0x25, 0x2c, 0x8e, 0xe2, 0x7b, 0x96, 0xe5, 0xf1, 0x71, 0x0e, 0x0c, 0x7a, 0x00, 0xbd, 0xe5, 0x03, 0x77, 0xab, 0x08, 0x3f, 0xfb, 0xdd, 0xdb, 0x4c, 0xba, 0x0e, 0x4a, 0xad, 0x3e, 0x29, 0xce, 0xeb, 0x74, 0xbf, 0x44, 0xa2, 0xe0, 0x9e, 0x7f, 0xf6, 0x50, 0x5c, 0x22, 0xb8, 0x0e, 0x56, 0xab, 0x0f, 0x61, 0xef, 0xd2, 0x19, 0x8c, 0x17, 0x0c, 0xd9, 0xab, 0x4a, 0x19, 0x74, 0x86, 0x30, 0x92, 0x19, 0x49, 0xd8, 0xe1, 0x62, 0x01, 0x93, 0x54, 0xda, 0x87, 0x9b, 0xce, 0x31, 0xd8, 0x0a, 0x4e, 0x73, 0x94, 0xb9, 0x89, 0x98, 0x55, 0x60, 0xd2, 0x38, 0x24, 0xfa, 0xac, 0xf4, 0xbd, 0x73, 0xf1, 0xda, 0xbb, 0xfa, 0x7e, 0x74, 0x12, 0x93, 0x3f, 0x20, 0xee, 0xe8, 0x17, 0x31, 0x5f, 0x3f, 0xa0, 0xda, 0x1b, 0x71, 0x11, 0x89, 0x78, 0x36, 0xea, 0x16, 0xf9, 0x69, 0x11, 0xa7, 0xd0, 0xed, 0x9b, 0x71, 0x98, 0x8a, 0xf8, 0x5b, 0xd0, 0xb4, 0x86, 0x20, 0x0a, 0x51, 0xfe, 0xda, 0x45, 0x76, 0x4c, 0xc5, 0x5b, 0xaa, 0xea, 0xb5, 0xea, 0x1f, 0x26, 0x59, 0xc6, 0x5f, 0xd7, 0x87, 0x7a, 0xd5, 0x6f, 0xdc, 0x6f, 0x46, 0xbb, 0xd5, 0xbb, 0xba, 0x3b, 0xb9, 0x48, 0xc0, 0x4f, 0x17, 0xc2, 0x0c, 0x53, 0x2d, 0x05, 0xcf, 0x10, 0xfe, 0x27, 0x4d, 0x87, 0xe6, 0x63, 0x14, 0x44, 0x71, 0x76, 0x3e, 0xe9, 0x49, 0xa4, 0x2a, 0x9d, 0xfd, 0x78, 0xa0, 0xcb, 0xb0, 0x8e, 0x80, 0x46, 0x66, 0x89, 0x24, 0x49, 0x35, 0xca, 0x11, 0x49, 0x6b, 0x35, 0x95, 0x1b, 0xd0, 0xed, 0x1f, 0x79, 0xbc, 0xec, 0x4c, 0x72, 0x25, 0xfe, 0xce, 0xd7, 0x6d, 0x5b, 0x66, 0x8e, 0x7f }, .spki_len = 1334, }, { .name = "ML-DSA 44", .parameter_set = CKP_IBM_ML_DSA_44, .rho = { 0xbc, 0x5f, 0xf8, 0x10, 0xeb, 0x08, 0x90, 0x48, 0xb8, 0xab, 0x30, 0x20, 0xa7, 0xbd, 0x3b, 0x16, 0xc0, 0xe0, 0xca, 0x3d, 0x6b, 0x97, 0xe4, 0x64, 0x6c, 0x2c, 0xca, 0xe0, 0xbb, 0xf1, 0x9e, 0xf7, }, .rho_len = 32, .seed = { 0xba, 0x2b, 0x57, 0xc4, 0x46, 0x55, 0x6e, 0xe2, 0xb7, 0x2c, 0x78, 0xb9, 0x6b, 0xb7, 0xa8, 0x50, 0x3d, 0xe4, 0x0a, 0xfb, 0x54, 0x18, 0x4e, 0x3b, 0x54, 0x63, 0xc2, 0x1a, 0xf7, 0x48, 0x53, 0x23, }, .seed_len = 32, .tr = { 0xdf, 0x98, 0xf0, 0x16, 0x0a, 0xe5, 0xd1, 0x37, 0x51, 0x27, 0x25, 0xf8, 0x9d, 0x56, 0x3b, 0xc9, 0xa1, 0x89, 0xd3, 0x1d, 0x20, 0xb3, 0xb3, 0xc8, 0xff, 0xaa, 0xf5, 0xe4, 0x86, 0xe7, 0x90, 0x51, 0xf6, 0xf3, 0x60, 0x5c, 0xca, 0x25, 0x69, 0xfd, 0xb4, 0x6b, 0x33, 0x18, 0xd2, 0x38, 0x42, 0xce, 0x40, 0xd6, 0x43, 0x86, 0x13, 0xf6, 0x8b, 0x45, 0x5b, 0x0d, 0x3b, 0xca, 0x0e, 0x05, 0x0d, 0x4d, }, .tr_len = 64, .s1 = { 0x11, 0x99, 0x88, 0xa2, 0xc4, 0x80, 0x1b, 0x90, 0x84, 0xe0, 0xb0, 0x48, 0xc9, 0x28, 0x09, 0x22, 0x30, 0x90, 0x24, 0x06, 0x49, 0x98, 0x40, 0x65, 0x5a, 0x26, 0x8a, 0xda, 0x32, 0x90, 0xda, 0x48, 0x08, 0x22, 0x81, 0x90, 0xc8, 0x14, 0x61, 0xdc, 0x16, 0x6a, 0x21, 0x47, 0x8e, 0x08, 0xb2, 0x21, 0xe3, 0x08, 0x68, 0x1a, 0x02, 0x44, 0x14, 0xc6, 0x65, 0xe1, 0x98, 0x71, 0x90, 0xc6, 0x69, 0x0c, 0x15, 0x44, 0xc9, 0xa0, 0x11, 0xcc, 0x34, 0x71, 0x83, 0x40, 0x45, 0x00, 0x12, 0x4d, 0x91, 0x08, 0x00, 0x83, 0x36, 0x84, 0x12, 0x85, 0x4c, 0xcc, 0x00, 0x41, 0x09, 0x90, 0x70, 0x18, 0x95, 0x00, 0xa2, 0xb2, 0x85, 0x94, 0x26, 0x41, 0x0b, 0x00, 0x41, 0x0a, 0xb9, 0x80, 0xc0, 0xc6, 0x10, 0x0c, 0x33, 0x29, 0xa3, 0xa6, 0x28, 0x1c, 0x26, 0x10, 0x1a, 0x37, 0x49, 0x13, 0x35, 0x8a, 0x0b, 0x29, 0x2e, 0x82, 0xa2, 0x70, 0x8b, 0x38, 0x49, 0x94, 0x04, 0x80, 0x9b, 0x26, 0x10, 0xa4, 0x80, 0x30, 0x04, 0x37, 0x0c, 0x48, 0xb2, 0x60, 0x04, 0x17, 0x2e, 0x19, 0x49, 0x64, 0xc8, 0xc4, 0x64, 0x1a, 0x96, 0x60, 0x10, 0x83, 0x6d, 0x20, 0x38, 0x22, 0x49, 0x06, 0x08, 0x1b, 0xb7, 0x20, 0x01, 0x48, 0x4d, 0xe1, 0x10, 0x49, 0x08, 0x38, 0x44, 0x4c, 0x16, 0x8e, 0x04, 0xb2, 0x2c, 0x09, 0x91, 0x50, 0x83, 0x36, 0x06, 0x5c, 0x02, 0x8c, 0x8a, 0x38, 0x05, 0x1a, 0xb5, 0x81, 0x82, 0xc0, 0x09, 0x51, 0x12, 0x72, 0x22, 0x10, 0x0d, 0x04, 0x08, 0x2a, 0xa4, 0x84, 0x10, 0x58, 0x08, 0x52, 0x08, 0x26, 0x0a, 0x02, 0xb6, 0x2d, 0x8a, 0x12, 0x0e, 0x14, 0x22, 0x10, 0x48, 0x44, 0x0a, 0x14, 0x23, 0x91, 0x50, 0x40, 0x90, 0x0a, 0x27, 0x92, 0xa4, 0xb0, 0x60, 0x08, 0x84, 0x11, 0xc4, 0x40, 0x22, 0x63, 0x46, 0x2a, 0xda, 0xa6, 0x90, 0xc1, 0xb2, 0x30, 0x50, 0x10, 0x00, 0xa0, 0xb4, 0x6c, 0x53, 0xb4, 0x50, 0x13, 0x05, 0x8d, 0x02, 0x31, 0x0e, 0x08, 0x20, 0x10, 0x91, 0xc8, 0x4c, 0x22, 0xa7, 0x50, 0xc2, 0xa6, 0x70, 0x92, 0x46, 0x41, 0x63, 0x16, 0x8c, 0x84, 0x00, 0x11, 0x0b, 0x81, 0x90, 0x13, 0x83, 0x71, 0x21, 0x85, 0x30, 0x1b, 0x18, 0x46, 0xa3, 0x10, 0x84, 0x14, 0x43, 0x40, 0x80, 0x98, 0x25, 0x0c, 0x27, 0x2c, 0x94, 0x42, 0x41, 0xa2, 0x88, 0x45, 0x02, 0x13, 0x05, 0x44, 0xb6, 0x44, 0x52, 0x22, 0x92, 0xd0, 0x80, 0x50, 0x4b, 0xa6, 0x04, 0x84, 0x36, 0x70, 0x09, 0xb2, 0x4d, 0x19, 0xa8, 0x84, 0x24, 0x93, 0x49, 0x94, 0xa2, 0x80, 0x49, 0xb4, 0x48, 0x91, 0x28, 0x64, 0xa1, 0xc8, 0x65, 0x4b, 0x82, 0x85, 0x93, 0x30, 0x06, 0x63, 0x12, 0x66, 0x10, 0x37, 0x01, 0x4a, 0x40, 0x80, }, .s1_len = 384, .s2 = { 0x18, 0x18, 0x90, 0x44, 0xc4, 0x0d, 0x4b, 0x28, 0x81, 0xa2, 0x06, 0x40, 0xd4, 0x30, 0x2c, 0x1b, 0x96, 0x4c, 0xe1, 0xb2, 0x60, 0x44, 0x28, 0x41, 0xd8, 0x30, 0x65, 0x24, 0x09, 0x04, 0x64, 0x00, 0x89, 0x63, 0xc2, 0x24, 0xc0, 0x00, 0x49, 0x92, 0x16, 0x52, 0x23, 0xc1, 0x29, 0x42, 0x26, 0x91, 0xd0, 0x38, 0x31, 0x83, 0x28, 0x28, 0x4c, 0x28, 0x61, 0x1a, 0xb2, 0x88, 0x80, 0x26, 0x2d, 0x0c, 0x19, 0x52, 0x5b, 0x22, 0x60, 0x8a, 0x92, 0x28, 0xa2, 0x18, 0x90, 0xd9, 0x42, 0x52, 0xcb, 0x40, 0x8e, 0x9b, 0x16, 0x06, 0x4b, 0xc8, 0x05, 0xe0, 0x06, 0x6c, 0x49, 0xc2, 0x25, 0xd4, 0x22, 0x69, 0x14, 0x11, 0x69, 0x1c, 0x34, 0x90, 0x0c, 0x85, 0x8d, 0x1c, 0x84, 0x49, 0x63, 0x10, 0x85, 0x08, 0x34, 0x89, 0x58, 0x16, 0x66, 0xa0, 0x38, 0x68, 0x0b, 0xa2, 0x50, 0xe0, 0x84, 0x61, 0xc1, 0x26, 0x6e, 0xc9, 0x14, 0x6a, 0xc0, 0xc0, 0x31, 0x84, 0x18, 0x2e, 0xdc, 0x16, 0x52, 0x14, 0x18, 0x91, 0x0a, 0x39, 0x2c, 0x83, 0xa6, 0x8d, 0x12, 0x29, 0x62, 0x92, 0xa6, 0x60, 0x08, 0xa5, 0x10, 0xd9, 0xc8, 0x4d, 0x24, 0x48, 0x24, 0x83, 0x98, 0x24, 0x1a, 0x44, 0x42, 0x08, 0x08, 0x48, 0xc8, 0x96, 0x2d, 0xa1, 0x10, 0x20, 0x60, 0x24, 0x51, 0x9c, 0x30, 0x11, 0xdb, 0xc8, 0x04, 0x11, 0x22, 0x51, 0x18, 0x04, 0x68, 0xe2, 0x24, 0x4e, 0x10, 0xc4, 0x0d, 0x18, 0x37, 0x29, 0x11, 0xb7, 0x84, 0x43, 0x84, 0x8d, 0x54, 0x40, 0x70, 0x64, 0x80, 0x70, 0x21, 0xb0, 0x4d, 0x00, 0x26, 0x62, 0x00, 0x45, 0x25, 0x1b, 0x83, 0x84, 0x84, 0x80, 0x70, 0x19, 0xb0, 0x04, 0x0a, 0xc9, 0x28, 0xca, 0x80, 0x05, 0x1b, 0x21, 0x4e, 0xd4, 0xb0, 0x49, 0x8c, 0x96, 0x6c, 0xd0, 0x96, 0x25, 0x48, 0x32, 0x72, 0x54, 0x12, 0x05, 0x09, 0x98, 0x8c, 0x8a, 0x32, 0x6d, 0xc0, 0x04, 0x31, 0x63, 0xc8, 0x61, 0xc8, 0xc2, 0x68, 0x9b, 0xb4, 0x8c, 0x5b, 0xc0, 0x2d, 0xc3, 0xa8, 0x8d, 0x1b, 0x16, 0x6c, 0xd8, 0x96, 0x41, 0x98, 0x34, 0x02, 0x44, 0x14, 0x2c, 0xd3, 0x86, 0x44, 0x0a, 0x18, 0x8a, 0x1a, 0x46, 0x92, 0x1a, 0xb7, 0x08, 0x4c, 0x34, 0x24, 0x21, 0x91, 0x0d, 0x9a, 0x96, 0x2d, 0xcb, 0x24, 0x22, 0x92, 0x86, 0x08, 0x98, 0xa0, 0x50, 0xda, 0x44, 0x6a, 0x19, 0xb1, 0x05, 0x8b, 0x20, 0x6e, 0x24, 0xc4, 0x81, 0xc9, 0x98, 0x40, 0x22, 0x19, 0x32, 0x11, 0x05, 0x69, 0xd3, 0x94, 0x91, 0x08, 0xa7, 0x71, 0xdb, 0xc0, 0x70, 0x02, 0xb8, 0x28, 0x83, 0xb4, 0x49, 0xa0, 0x44, 0x8a, 0x0b, 0xb4, 0x10, 0x61, 0x02, 0x48, 0x1c, 0xa6, 0x11, 0xe3, 0x20, 0x66, 0x40, 0xb4, 0x70, 0x03, 0xb6, 0x04, 0x60, 0x48, 0x21, }, .s2_len = 384, .t0 = { 0x5b, 0x21, 0x83, 0x39, 0x88, 0xdb, 0x67, 0x4a, 0x61, 0xe7, 0xc2, 0x08, 0xde, 0xbe, 0x8d, 0xae, 0x41, 0x19, 0xaf, 0xb0, 0x26, 0x61, 0xa6, 0x9a, 0xbc, 0x8b, 0xdd, 0x24, 0x5b, 0x5d, 0x0f, 0xb1, 0xa2, 0x67, 0x01, 0xc9, 0xb9, 0xc9, 0xa8, 0xf7, 0xd9, 0xfc, 0xd4, 0xc2, 0x87, 0xff, 0x3d, 0x60, 0x8c, 0xf2, 0x58, 0x28, 0x2a, 0x1e, 0xb2, 0x9f, 0x93, 0x04, 0xe8, 0x9c, 0x14, 0xf3, 0xe1, 0xce, 0x56, 0x12, 0x89, 0x1c, 0x60, 0x29, 0x34, 0x52, 0x60, 0x06, 0xc9, 0x9b, 0x4a, 0xa2, 0x39, 0x9b, 0xf4, 0x94, 0xbc, 0xf8, 0xdf, 0x61, 0xd6, 0xdf, 0x4c, 0x69, 0xbc, 0x93, 0xe0, 0x2d, 0x49, 0x95, 0xe2, 0xf7, 0x6e, 0x9f, 0xda, 0x4e, 0xf6, 0x7e, 0xb7, 0x25, 0x6c, 0xa8, 0x9a, 0x3f, 0x38, 0xfe, 0xb2, 0xe9, 0xdf, 0x6a, 0x01, 0x0d, 0xc1, 0xc1, 0x50, 0x02, 0xfb, 0xd4, 0x56, 0xfa, 0xe8, 0x84, 0x82, 0x1a, 0x34, 0x16, 0x6b, 0x06, 0x58, 0xa2, 0x41, 0x25, 0x95, 0x71, 0x8e, 0x14, 0x9b, 0xbc, 0x6e, 0x22, 0x0a, 0xee, 0x26, 0x8d, 0x4d, 0x82, 0x18, 0xc2, 0x5f, 0x6a, 0x95, 0x7d, 0xe5, 0xb2, 0x6c, 0xea, 0x7b, 0x14, 0xcb, 0x32, 0x0d, 0x89, 0xe1, 0x69, 0x9a, 0xd9, 0xf2, 0xb3, 0x89, 0xc6, 0x7e, 0xf9, 0x33, 0x86, 0xa2, 0xc6, 0x5f, 0x2c, 0x32, 0x23, 0x33, 0x67, 0xd7, 0x6a, 0xe4, 0xab, 0x2a, 0xbb, 0xd4, 0x22, 0xe9, 0x8e, 0x49, 0x3d, 0xcc, 0x3c, 0xc5, 0xda, 0xf6, 0x89, 0xb6, 0x5c, 0xc4, 0xbc, 0x3f, 0xa5, 0x1c, 0x9c, 0x59, 0xee, 0xaf, 0x07, 0x55, 0x17, 0x0c, 0x24, 0x95, 0x80, 0x4d, 0x02, 0xa6, 0x07, 0xc5, 0xbf, 0x88, 0x7c, 0xd8, 0x6a, 0x03, 0x89, 0xf2, 0x8f, 0xc9, 0x72, 0x5e, 0xf4, 0x60, 0x03, 0xf1, 0x3b, 0x01, 0x87, 0x68, 0x4b, 0xea, 0xb1, 0xf2, 0x4a, 0x29, 0xf5, 0x31, 0x96, 0x01, 0xf3, 0x09, 0xc9, 0x1d, 0x2a, 0x33, 0x3d, 0x1b, 0x88, 0xdf, 0x20, 0x5a, 0x51, 0x20, 0xc4, 0xcf, 0xdc, 0x22, 0x38, 0x12, 0x4e, 0x4e, 0x2b, 0x47, 0xd0, 0xb5, 0xe6, 0x6a, 0x65, 0x4f, 0xe4, 0xcc, 0xcb, 0x07, 0x8f, 0x07, 0xcb, 0xd4, 0x55, 0xd1, 0x5d, 0x3e, 0xec, 0x7d, 0xa2, 0x74, 0xd2, 0x4a, 0x2e, 0x57, 0x18, 0x84, 0xde, 0x41, 0xc3, 0xa9, 0xa4, 0xfd, 0xb3, 0xf6, 0x09, 0x8a, 0x17, 0x2c, 0x30, 0x96, 0x80, 0x39, 0xbd, 0x0e, 0x4e, 0xb3, 0xe2, 0xfb, 0x6d, 0x6e, 0xee, 0xd3, 0x9e, 0x0b, 0x63, 0x62, 0xd5, 0x4e, 0x7b, 0x88, 0x95, 0x98, 0x69, 0xdd, 0xd5, 0xd8, 0x73, 0xd9, 0x65, 0x24, 0x01, 0xa2, 0x9f, 0x27, 0xa2, 0x8e, 0xa6, 0x6d, 0x32, 0xcc, 0xb0, 0xef, 0x3b, 0xf4, 0x60, 0x0f, 0x75, 0x57, 0xee, 0x8d, 0x54, 0xbf, 0x1d, 0xad, 0x18, 0xf4, 0x5d, 0xdc, 0xd4, 0xc9, 0xed, 0x57, 0xb1, 0x3e, 0x44, 0x5b, 0xf1, 0x22, 0xa4, 0x3f, 0x53, 0x94, 0x03, 0x89, 0xbf, 0x87, 0x14, 0xff, 0xac, 0x72, 0x1e, 0x59, 0x31, 0x7e, 0x4b, 0x70, 0x50, 0x0a, 0xd0, 0xd1, 0xb9, 0xa6, 0x27, 0x05, 0x4d, 0x31, 0x93, 0x20, 0x8c, 0x77, 0x4e, 0x0b, 0x20, 0xed, 0x04, 0x1a, 0x8c, 0x05, 0x5e, 0x75, 0xee, 0xcd, 0x37, 0x38, 0xf0, 0x07, 0x15, 0x8f, 0xad, 0xdf, 0xca, 0x5f, 0x43, 0x56, 0x2d, 0x63, 0x6a, 0x5a, 0xcf, 0x3a, 0x39, 0x83, 0xd3, 0xcf, 0xeb, 0xca, 0x10, 0xb8, 0x13, 0xf9, 0xf6, 0x52, 0x65, 0x19, 0x19, 0x9a, 0x03, 0x13, 0xcd, 0x1d, 0xe1, 0x3f, 0x06, 0xad, 0x53, 0x86, 0xe1, 0xe1, 0x20, 0x79, 0x5f, 0xd2, 0x67, 0xb7, 0xf4, 0x20, 0x19, 0xd8, 0x4d, 0xf6, 0xcd, 0x1b, 0xf9, 0x19, 0x30, 0xfc, 0xa7, 0xaf, 0xd5, 0x2e, 0x80, 0x70, 0x0f, 0x4c, 0xf5, 0xcd, 0xc3, 0x8a, 0x5f, 0x7a, 0x57, 0x49, 0x79, 0x1c, 0x2f, 0xdf, 0xfc, 0x4a, 0x10, 0x75, 0x3c, 0x24, 0xdb, 0x19, 0xe8, 0xeb, 0x65, 0x1c, 0x5b, 0x36, 0x32, 0x00, 0xf0, 0xb5, 0xd1, 0x69, 0x94, 0x70, 0x26, 0xe9, 0xf7, 0x4f, 0x01, 0x2d, 0xc7, 0xc5, 0xb3, 0x39, 0xdd, 0x49, 0xd2, 0x61, 0xca, 0x1d, 0x37, 0xf8, 0xf2, 0x83, 0x46, 0xe6, 0x19, 0x78, 0x05, 0x4f, 0x45, 0xae, 0xe4, 0x36, 0xdc, 0xcb, 0xe7, 0xbf, 0xaf, 0xe0, 0x7c, 0xe9, 0xa8, 0xb8, 0x3c, 0x90, 0xa2, 0x68, 0x6f, 0xa9, 0x54, 0x02, 0x85, 0x09, 0x25, 0xc8, 0x58, 0x2b, 0xc9, 0xb7, 0x34, 0xe4, 0xec, 0xa1, 0xf7, 0xb2, 0x0b, 0x08, 0x6f, 0x12, 0x9f, 0x27, 0x7a, 0x5c, 0xbd, 0xaa, 0x96, 0x3c, 0x92, 0x71, 0x7e, 0xf7, 0x0e, 0xc1, 0x9b, 0xf3, 0xdb, 0xc6, 0xda, 0x20, 0x3a, 0xd9, 0x0f, 0x3b, 0x13, 0xbb, 0xc2, 0x2f, 0xbd, 0x98, 0x0b, 0xb1, 0xb9, 0xd3, 0xa3, 0x44, 0x52, 0xb3, 0x35, 0x70, 0x21, 0xce, 0x36, 0x13, 0x58, 0x4e, 0x09, 0x36, 0xbf, 0x1d, 0x09, 0x42, 0x09, 0x37, 0x81, 0x5e, 0x11, 0xcc, 0x5d, 0x5d, 0xdb, 0x4b, 0xf1, 0xd8, 0x30, 0xc4, 0xf8, 0x3f, 0x30, 0xe5, 0x15, 0x92, 0x1c, 0x78, 0x4d, 0x87, 0xbb, 0x20, 0xc0, 0x9e, 0x3c, 0x64, 0xbd, 0xce, 0x9a, 0xb1, 0xc6, 0x9f, 0xd3, 0x07, 0xef, 0xe3, 0x59, 0xc7, 0xf9, 0x38, 0x56, 0x6c, 0x9f, 0x25, 0x17, 0xb0, 0x63, 0x38, 0x51, 0x67, 0xe2, 0x47, 0xf3, 0x10, 0x81, 0x11, 0x9b, 0xac, 0x6b, 0x55, 0xa0, 0xbd, 0xd7, 0x14, 0x25, 0x51, 0x0f, 0xfa, 0x2a, 0xbd, 0xfa, 0x88, 0x83, 0x76, 0xa3, 0x7f, 0x20, 0xc2, 0x48, 0x01, 0x52, 0xbb, 0x36, 0x16, 0x34, 0x52, 0x00, 0x07, 0xc5, 0xb3, 0x4b, 0xf2, 0x28, 0x17, 0xcb, 0x2e, 0x67, 0xac, 0x1a, 0x82, 0x67, 0x0b, 0x71, 0xf1, 0x96, 0xc8, 0x9f, 0x23, 0xba, 0x31, 0x4b, 0x16, 0xa9, 0x48, 0x49, 0x93, 0x04, 0xef, 0x5c, 0x03, 0xdc, 0xf5, 0x8e, 0x52, 0xbe, 0x31, 0x48, 0x63, 0xe7, 0x23, 0xc5, 0x6d, 0x3a, 0xeb, 0x34, 0x0b, 0xff, 0x18, 0xab, 0xfa, 0x20, 0xdc, 0x03, 0x44, 0x20, 0x30, 0x23, 0x05, 0x33, 0xd9, 0x12, 0x9b, 0x83, 0xed, 0x22, 0xc3, 0x51, 0xf2, 0x32, 0x81, 0x72, 0xe3, 0x63, 0x44, 0x74, 0x44, 0xae, 0x5c, 0x69, 0x02, 0xb7, 0x92, 0x79, 0x9f, 0x54, 0x44, 0x50, 0x78, 0x71, 0x19, 0x61, 0x2e, 0x9b, 0xb4, 0x13, 0x0a, 0x33, 0xa2, 0xa5, 0x96, 0x2a, 0xc0, 0x9d, 0x57, 0x7d, 0x6d, 0xdc, 0x88, 0x1f, 0xe6, 0x61, 0x61, 0x26, 0xd8, 0xa0, 0xa7, 0xdf, 0x2b, 0x22, 0x53, 0xbc, 0x8e, 0xc4, 0xe3, 0x53, 0x86, 0xea, 0x55, 0x11, 0xf0, 0xf1, 0x58, 0x87, 0x14, 0x5b, 0x6c, 0x23, 0xab, 0x3d, 0x40, 0x33, 0x39, 0xe4, 0x04, 0x07, 0x3e, 0xd9, 0xc6, 0xa8, 0x96, 0xa2, 0xf9, 0xec, 0x70, 0xc4, 0x4b, 0xd2, 0xae, 0xc1, 0x0f, 0xc4, 0x36, 0x0e, 0x87, 0x63, 0x6b, 0xe1, 0x55, 0xb6, 0xa6, 0x7b, 0x7e, 0xdf, 0x38, 0xcf, 0x73, 0x00, 0x48, 0x13, 0xc9, 0xe7, 0xd2, 0xc6, 0x54, 0xc2, 0x53, 0x0a, 0x71, 0xe5, 0xf8, 0xc1, 0x09, 0x42, 0xfb, 0x6d, 0x88, 0x41, 0x53, 0x5a, 0xb1, 0xda, 0x43, 0xe8, 0xcb, 0x0b, 0xb8, 0x9e, 0x78, 0xec, 0x91, 0xf8, 0xde, 0x15, 0x31, 0xa0, 0x36, 0x65, 0xcc, 0xd5, 0xa7, 0x5b, 0xda, 0x0e, 0xd0, 0xe5, 0x98, 0x64, 0xee, 0xef, 0x51, 0xa8, 0x3f, 0xa5, 0x53, 0xaf, 0x66, 0x2a, 0xee, 0x00, 0xd1, 0xf8, 0x36, 0x7b, 0x4d, 0x5d, 0xdd, 0xc3, 0x45, 0x54, 0x4c, 0x6b, 0xd5, 0x14, 0xf8, 0x88, 0xe6, 0x03, 0x3c, 0x25, 0x5d, 0xb6, 0x50, 0xda, 0x73, 0x4a, 0xd3, 0x3a, 0x3c, 0xf8, 0x4b, 0xd3, 0xf0, 0x6f, 0xa1, 0xa7, 0xca, 0x02, 0xe4, 0xb8, 0xe9, 0x93, 0xae, 0x7a, 0xe6, 0x34, 0x20, 0xa4, 0x6b, 0xa8, 0xa3, 0x81, 0x3d, 0x1e, 0x9d, 0x29, 0x66, 0xbb, 0x85, 0x60, 0xd7, 0x1c, 0x62, 0xa0, 0x44, 0xea, 0x94, 0x17, 0x9f, 0x4e, 0xb1, 0xb6, 0xed, 0x60, 0x71, 0x9d, 0x51, 0xe0, 0xee, 0xf6, 0xcd, 0x07, 0x91, 0x52, 0xf6, 0xbe, 0x48, 0x8e, 0xc9, 0x19, 0x11, 0xc6, 0xd3, 0xf1, 0xd1, 0x17, 0x3c, 0x54, 0x1f, 0x9d, 0x25, 0xbf, 0x34, 0x2f, 0xca, 0xa3, 0xff, 0x46, 0xc1, 0x8f, 0x2a, 0x04, 0x41, 0xd8, 0x3b, 0xde, 0x35, 0x46, 0xa9, 0x82, 0x6c, 0x34, 0x96, 0xe0, 0x6f, 0x2f, 0x2b, 0x0e, 0xeb, 0x9d, 0x5b, 0xe8, 0x73, 0x9f, 0x83, 0xa4, 0x2d, 0x3b, 0x30, 0x0e, 0x70, 0xee, 0x84, 0xdf, 0xff, 0xb2, 0x07, 0x64, 0xa0, 0x60, 0x21, 0x2f, 0x05, 0x8c, 0x8a, 0x5f, 0xfa, 0x9a, 0x34, 0xe9, 0x28, 0xd6, 0xa7, 0xe0, 0x77, 0x08, 0xfe, 0x53, 0x93, 0xe3, 0x01, 0x7c, 0xe4, 0x70, 0xeb, 0x96, 0x58, 0xa7, 0x4e, 0x49, 0x51, 0xe6, 0xfa, 0x48, 0x54, 0xc9, 0xe9, 0xc2, 0x89, 0x88, 0x81, 0x2e, 0x44, 0x18, 0xa2, 0xe8, 0x32, 0x58, 0x0b, 0x4a, 0x27, 0x03, 0x72, 0xbc, 0x69, 0x67, 0x68, 0x89, 0xd0, 0xcc, 0x43, 0x24, 0x0e, 0xda, 0xbc, 0x1d, 0x31, 0x14, 0xd8, 0xf3, 0x5a, 0xb2, 0xe9, 0xea, 0x95, 0x30, 0x82, 0xe9, 0x53, 0x62, 0x79, 0xac, 0xb3, 0xbe, 0x16, 0xd3, 0xa2, 0x05, 0xf4, 0x6c, 0xb6, 0x7b, 0x22, 0x14, 0x96, 0x93, 0x5a, 0xc0, 0x42, 0x92, 0xbb, 0xfb, 0x9a, 0x61, 0xc0, 0xa0, 0x3e, 0xf4, 0xc9, 0xb6, 0x82, 0x04, 0x95, 0xf3, 0xd8, 0x0e, 0x4a, 0x6f, 0xb7, 0xe1, 0xc6, 0x99, 0x03, 0xfa, 0x22, 0x6e, 0x02, 0x3e, 0x95, 0xba, 0x41, 0x6d, 0xf2, 0xe5, 0xe4, 0x54, 0x1e, 0x15, 0xdc, 0xc0, 0x00, 0xb5, 0xe6, 0x5c, 0x97, 0x20, 0xda, 0xf6, 0x96, 0x01, 0x2f, 0xa2, 0xa6, 0xcf, 0x75, 0x8e, 0xd6, 0xd2, 0x25, 0xa3, 0xe4, 0xfe, 0xe4, 0x5a, 0xc5, 0xfb, 0x48, 0x70, 0x7f, 0xae, 0x13, 0x3d, 0x59, 0x2c, 0xfd, 0x2e, 0x8c, 0x43, 0xc2, 0x12, 0x6f, 0x65, 0x2b, 0xee, 0x9b, 0xab, 0x43, 0xa1, 0xa1, 0x0b, 0xe2, 0x41, 0x1a, 0x67, 0x94, 0xb2, 0x6c, 0xb5, 0x5c, 0xc2, 0x17, 0xeb, 0x7b, 0x0b, 0x14, 0x6d, 0x23, 0xf7, 0x92, 0x2d, 0x32, 0x22, 0xae, 0x5e, 0xe8, 0xc6, 0xd3, 0x8e, 0x83, 0x99, 0xba, 0x51, 0xc6, 0x81, 0xb8, 0x38, 0x16, 0xfc, 0xf7, 0x44, 0x38, 0x82, 0x59, 0x20, 0xf9, 0xce, 0x8a, 0x20, 0x2a, 0x8f, 0x6d, 0x94, 0x2d, 0xa8, 0x62, 0x38, 0xfb, 0x4c, 0x9f, 0x21, 0x98, 0xea, 0x8d, 0xff, 0x81, 0xc1, 0x72, 0x86, 0xe0, 0x18, 0xdf, 0x4b, 0x7f, 0xe3, 0x88, 0x4d, 0x17, 0x59, 0xe4, 0xc5, 0x9b, 0xb5, 0x26, 0x17, 0xae, 0xd4, 0xe7, 0x8e, 0x4e, 0x7c, 0x4e, 0x9a, 0x36, 0xe4, 0xe9, 0x96, 0xd3, 0x23, 0x91, 0xa3, 0x4a, 0x0d, 0xaa, 0xab, 0x6b, 0x54, 0x08, 0x15, 0xa3, 0x4d, 0x20, 0x40, 0x7a, 0xef, 0x81, 0x94, 0x9b, 0xe6, 0x7b, 0x90, 0x69, 0x50, 0xd8, 0x9b, 0xe9, 0xf0, 0x85, 0xe9, 0x9e, 0xb5, 0x87, 0x26, 0x95, 0x17, 0x3b, 0x3e, 0xfa, 0xca, 0xe9, 0x45, 0x5d, 0x2b, 0x2c, 0xd4, 0xf7, 0x10, 0xb8, 0x72, 0xcf, 0x66, 0x2b, 0x73, 0x62, 0x16, 0xb1, 0xbb, 0xfb, 0x1f, 0x5f, 0x3d, 0x48, 0x6c, 0x7b, 0x4b, 0x87, 0x56, 0x12, 0x33, 0x3f, 0x8e, 0x4b, 0xa9, 0x33, 0xdc, 0x79, 0xf0, 0xed, 0xfd, 0x7b, 0xaa, 0xde, 0x2c, 0x16, 0xf2, 0x14, 0x6a, 0x49, 0x6f, 0x79, 0xc4, 0x2a, 0x4d, 0x6b, 0x52, 0x39, 0xa3, 0x0d, 0xd3, 0xc4, 0x8b, 0xeb, 0x09, 0x2c, 0xa0, 0x75, 0x00, 0x10, 0xf6, 0x9e, 0xd4, 0xb9, 0x23, 0x20, 0x14, 0x7d, 0xbb, 0xe2, 0x08, 0xf6, 0xe8, 0xeb, 0x1c, 0xf2, 0x47, 0xd2, 0x1a, 0x3a, 0x3b, 0x01, 0xdf, 0x58, 0xc0, 0xaa, 0x62, 0x94, 0x4d, 0xa0, 0xef, 0x04, 0x50, 0xe8, 0xce, 0x48, 0xaa, 0x13, 0x7e, 0x7e, 0x15, 0x16, 0xc1, 0xd5, 0xc8, 0x6e, 0xea, 0x17, 0xfd, 0xfa, 0xc1, 0x69, 0x07, 0x46, 0xe7, 0x26, 0x70, 0x45, 0xa3, 0xe9, 0x05, 0x96, 0xbd, 0xb7, 0x5d, 0x50, 0xb6, 0xdd, 0x5c, 0x34, 0xe5, 0xc8, 0xd8, 0x9d, 0xc6, 0xf2, 0xf1, 0xd2, 0x44, 0x40, 0xe5, 0x7b, 0x47, 0x59, 0xb8, 0x62, 0x5f, 0x72, 0xbc, 0x4a, 0x7b, 0x10, 0xd5, 0x19, 0xd3, 0x31, 0xf9, 0xc4, 0x00, 0xaa, 0xe1, 0xe5, 0x0d, 0x48, 0x0c, 0xaa, 0xe5, 0xa1, 0xc0, 0xfa, 0x99, 0xd7, 0x79, 0x24, 0xcf, 0x8d, 0xfe, 0x56, 0xcd, 0x70, 0x92, 0xe7, 0xb9, }, .t0_len = 1664, .t1 = { 0x23, 0x0a, 0x19, 0xd7, 0x5a, 0xdb, 0xde, 0xd5, 0x2d, 0xb8, 0x55, 0xe2, 0x52, 0xa7, 0x19, 0xfc, 0xbd, 0x14, 0x7b, 0xa6, 0x7b, 0x2f, 0xad, 0x14, 0xed, 0x0e, 0x68, 0xfd, 0xfe, 0x8c, 0x65, 0xba, 0xde, 0xac, 0xb0, 0x91, 0x11, 0x93, 0xad, 0xfa, 0x87, 0x94, 0xd7, 0x8f, 0x8e, 0x3d, 0x66, 0x2a, 0x1c, 0x49, 0xda, 0x81, 0x9f, 0xd9, 0x59, 0xe7, 0xf0, 0x78, 0xf2, 0x03, 0xc4, 0x56, 0xf8, 0xb6, 0xe7, 0xc9, 0x41, 0x58, 0x98, 0xe5, 0x41, 0xc7, 0x30, 0x32, 0xdb, 0xd6, 0x19, 0xea, 0xf6, 0x0f, 0x8d, 0x64, 0xf8, 0x68, 0x3d, 0xa9, 0x9e, 0xca, 0x51, 0x22, 0x0b, 0x0a, 0xca, 0x28, 0x46, 0x40, 0x99, 0xf5, 0x47, 0xc0, 0x27, 0x77, 0xbd, 0x37, 0xd8, 0x4a, 0x59, 0xbd, 0x37, 0xed, 0x7a, 0x8a, 0x92, 0x63, 0x3c, 0x75, 0xd0, 0x7c, 0x79, 0x3f, 0xe7, 0x25, 0x2b, 0x58, 0x4a, 0xbf, 0x6a, 0x15, 0xee, 0x14, 0x50, 0x7e, 0x5e, 0x19, 0x3f, 0x89, 0x86, 0x4d, 0x09, 0xac, 0x87, 0x27, 0xa6, 0xd0, 0x42, 0x1f, 0x0c, 0x19, 0xf0, 0xe2, 0xfb, 0xfc, 0x21, 0x3d, 0x3f, 0xbd, 0x70, 0xf4, 0xf9, 0x76, 0x2c, 0xec, 0xff, 0x23, 0x1e, 0x9c, 0x8a, 0x76, 0x28, 0xd3, 0xf8, 0xb0, 0x85, 0x7b, 0x03, 0x2d, 0x32, 0xde, 0x62, 0xff, 0x8e, 0xcb, 0xf4, 0x00, 0x82, 0x89, 0xbf, 0x34, 0x40, 0x36, 0x65, 0xf8, 0x1a, 0x08, 0x1a, 0xd5, 0xa8, 0x5a, 0x28, 0x2f, 0x99, 0xba, 0xb9, 0xe5, 0x38, 0x5a, 0xfb, 0xcc, 0xcf, 0x44, 0xb7, 0x4c, 0x01, 0x96, 0xc7, 0x54, 0x55, 0x27, 0xec, 0x30, 0x26, 0xda, 0x12, 0x80, 0xc4, 0xeb, 0x37, 0xd0, 0x9c, 0xfe, 0x3e, 0xc4, 0xb4, 0x91, 0x0b, 0x62, 0xeb, 0x98, 0x15, 0xa4, 0x25, 0xc6, 0x59, 0x0f, 0xc4, 0xad, 0x3f, 0xbb, 0x22, 0x57, 0x52, 0xcc, 0x1f, 0xc5, 0x69, 0x3f, 0x18, 0x7e, 0x7d, 0xec, 0x4e, 0xef, 0xbe, 0xb6, 0xb9, 0x1b, 0xd9, 0x1c, 0x5e, 0x2e, 0xa6, 0xa9, 0x1d, 0x14, 0xd0, 0x97, 0xbe, 0x20, 0x3f, 0xba, 0x0b, 0xf9, 0x37, 0xc9, 0x75, 0x07, 0xdc, 0x00, 0x7c, 0x4c, 0xaa, 0x9b, 0x07, 0x85, 0x89, 0x29, 0x66, 0xff, 0x15, 0x90, 0x09, 0x24, 0xe5, 0x79, 0xd4, 0xfb, 0xa0, 0x2b, 0xda, 0x87, 0x55, 0x5f, 0x07, 0x3d, 0xae, 0x00, 0x51, 0x3e, 0x70, 0x80, 0x9a, 0xbb, 0xc7, 0x11, 0xfb, 0xa2, 0xe7, 0x64, 0x95, 0x77, 0xc4, 0x2a, 0xfd, 0xc2, 0x4b, 0xf7, 0x41, 0x3e, 0x51, 0x26, 0x8a, 0xd6, 0xdb, 0x61, 0x13, 0xb7, 0xd9, 0x19, 0x1a, 0xf9, 0xd0, 0x61, 0xdb, 0xde, 0xd5, 0xd6, 0x30, 0x87, 0x76, 0x50, 0xc1, 0x24, 0xf1, 0x1b, 0xc4, 0xbd, 0xc3, 0xfd, 0xc6, 0xa9, 0x00, 0xf6, 0x31, 0x26, 0xf9, 0x21, 0xe8, 0x38, 0xad, 0x0c, 0x22, 0x75, 0xa3, 0x38, 0x9a, 0x39, 0xbd, 0x99, 0xa1, 0x34, 0x50, 0x45, 0x50, 0x10, 0x1c, 0xd3, 0xe9, 0x5e, 0x6d, 0x14, 0x96, 0xbe, 0x7d, 0xe6, 0x62, 0x7d, 0xf4, 0xfd, 0x6c, 0x28, 0xbb, 0xf4, 0x0b, 0x30, 0xef, 0xa9, 0xb5, 0xc3, 0xd5, 0xc8, 0x5a, 0xb1, 0x4a, 0x65, 0xc0, 0x2d, 0x6d, 0x47, 0x81, 0xff, 0x13, 0xd3, 0x28, 0x60, 0x85, 0x54, 0xb6, 0xd1, 0x5e, 0xd9, 0x12, 0x89, 0xa6, 0xd5, 0x5a, 0xac, 0x0c, 0x38, 0xe3, 0x77, 0x06, 0xf7, 0x35, 0x5e, 0x9a, 0x4f, 0xda, 0x61, 0x5b, 0x87, 0x59, 0x26, 0xbf, 0xe5, 0xa5, 0x9d, 0x9e, 0xf2, 0x73, 0xbf, 0x94, 0xa0, 0x7c, 0xfa, 0x57, 0x31, 0x78, 0xf0, 0xe0, 0x04, 0xb6, 0xe1, 0xef, 0x0a, 0x83, 0x49, 0xe9, 0xbc, 0xc0, 0x19, 0x81, 0xf2, 0x46, 0x0f, 0x0a, 0x27, 0x43, 0xc2, 0x8d, 0x1e, 0x13, 0x8f, 0xfb, 0x76, 0x5e, 0x7e, 0x33, 0x97, 0xb7, 0x91, 0x33, 0x35, 0xd4, 0x02, 0xfe, 0x91, 0x80, 0x6a, 0xa8, 0xfc, 0x81, 0x92, 0x53, 0xaf, 0x32, 0x69, 0x2f, 0xa6, 0x51, 0xe8, 0x67, 0xf5, 0x90, 0x7e, 0xf4, 0x6f, 0x00, 0x62, 0x5a, 0x03, 0x0e, 0xc9, 0x04, 0xed, 0xab, 0x21, 0x42, 0x6d, 0x59, 0x11, 0x9d, 0x2c, 0xaa, 0x43, 0xbd, 0x93, 0x5d, 0xec, 0x0a, 0x55, 0x0c, 0x61, 0xee, 0x4b, 0x27, 0x9c, 0x1c, 0xa3, 0xa7, 0x9c, 0x79, 0xa6, 0x6e, 0x3f, 0x2d, 0x2f, 0xad, 0xb0, 0x0f, 0x59, 0xa3, 0xa4, 0x38, 0xaa, 0x44, 0x57, 0x01, 0x06, 0x07, 0x30, 0x17, 0xfa, 0x1c, 0x87, 0x57, 0x50, 0x01, 0x09, 0x72, 0x0d, 0x12, 0x5b, 0xba, 0x23, 0x1a, 0x0c, 0x36, 0x35, 0x0c, 0x78, 0x08, 0x6d, 0xfd, 0xc8, 0xd6, 0x13, 0xae, 0xca, 0x88, 0xc4, 0xcc, 0xae, 0xb4, 0xa4, 0x4d, 0x13, 0xad, 0xb3, 0xc7, 0x17, 0xd6, 0x5c, 0x82, 0xa3, 0x51, 0xb9, 0xb6, 0xea, 0xbf, 0x6a, 0x10, 0xf4, 0xb4, 0xe9, 0x62, 0x3e, 0x3a, 0x95, 0xb4, 0xd4, 0x0a, 0x12, 0xa8, 0x18, 0xac, 0x6b, 0x38, 0x22, 0xdb, 0x82, 0xfb, 0x05, 0xdc, 0x42, 0x02, 0x64, 0x8b, 0x44, 0x54, 0x68, 0x9a, 0xeb, 0x69, 0xea, 0x32, 0x5f, 0x03, 0xe3, 0x5d, 0xef, 0xa5, 0x47, 0x08, 0x48, 0x14, 0x20, 0xc6, 0xd6, 0x97, 0xbb, 0x91, 0x2f, 0xca, 0x0d, 0x3f, 0x19, 0x2e, 0xf2, 0x97, 0xdf, 0xe7, 0x7f, 0xf3, 0x6b, 0x21, 0x03, 0xf1, 0xad, 0x1a, 0xee, 0xce, 0xd1, 0xc8, 0x14, 0xc2, 0xcd, 0x7e, 0xf1, 0x6b, 0xce, 0x47, 0x6a, 0xd0, 0x4f, 0x94, 0x1a, 0xfc, 0x79, 0xe3, 0x29, 0x54, 0x74, 0xa4, 0x10, 0x62, 0x51, 0x8c, 0x00, 0x37, 0x86, 0x09, 0x34, 0xf0, 0xe5, 0xe6, 0x52, 0xf7, 0x27, 0x49, 0xa6, 0x98, 0x63, 0x2a, 0x09, 0x91, 0xf6, 0x13, 0xf5, 0xcb, 0x96, 0xca, 0x11, 0x78, 0xf9, 0x74, 0xf2, 0xc4, 0xaa, 0x0c, 0xe6, 0x3d, 0xc2, 0x4e, 0x36, 0x4c, 0x92, 0xa6, 0x43, 0xb9, 0x0a, 0x5f, 0x85, 0xa6, 0x2f, 0xd4, 0xd8, 0xd2, 0xb1, 0x93, 0xd2, 0x9b, 0x18, 0xbe, 0xde, 0x26, 0x53, 0xfc, 0x5d, 0x3f, 0x24, 0xf5, 0xb2, 0xc0, 0x18, 0xdb, 0xbc, 0xb6, 0xef, 0x00, 0xf3, 0x05, 0xbf, 0x93, 0x66, 0x6b, 0xd4, 0x7f, 0xea, 0x91, 0x93, 0xbc, 0x23, 0x3d, 0xb3, 0x91, 0x21, 0x44, 0x2e, 0x93, 0x8d, 0xa5, 0xdd, 0x07, 0xee, 0x6e, 0x87, 0x9c, 0x5b, 0x9d, 0xff, 0x41, 0xec, 0xee, 0x5e, 0x05, 0x89, 0xae, 0x61, 0x75, 0xff, 0x5e, 0xc6, 0xf6, 0xd2, 0x62, 0x9f, 0x56, 0xb1, 0x8b, 0x4d, 0xe6, 0x6f, 0xcb, 0x13, 0xdf, 0x04, 0x00, 0xa7, 0x97, 0xc9, 0x22, 0x70, 0xf6, 0x9b, 0xde, 0xbd, 0xdc, 0xb8, 0x8c, 0x42, 0x48, 0x91, 0x9b, 0x56, 0xcd, 0xa7, 0x0b, 0x8a, 0xc4, 0xf9, 0x42, 0x9c, 0x29, 0x2d, 0xa9, 0x4d, 0x64, 0x78, 0x28, 0x07, 0x64, 0xfe, 0x23, 0x86, 0xfc, 0x38, 0xcb, 0x09, 0x31, 0x45, 0x88, 0x39, 0xef, 0x4e, 0x7d, 0xe8, 0xf0, 0x68, 0x9d, 0x99, 0x80, 0x59, 0x88, 0xc7, 0xf9, 0x61, 0x11, 0x85, 0x2c, 0x89, 0x29, 0xe5, 0xa5, 0x40, 0xd3, 0xb7, 0x8d, 0x71, 0x2d, 0xec, 0xc3, 0x96, 0xfe, 0xf3, 0xec, 0x34, 0x40, 0x21, 0x84, 0xe4, 0xfd, 0x29, 0xf3, 0x63, 0xea, 0x80, 0xf6, 0xfc, 0x50, 0xba, 0x9a, 0x11, 0x35, 0x1a, 0xce, 0xea, 0x8f, 0xe6, 0x8d, 0x54, 0x1e, 0x1a, 0xa5, 0x84, 0x8d, 0x9f, 0x6e, 0x61, 0xdf, 0xb6, 0x2b, 0x2f, 0x23, 0xbc, 0x50, 0x81, 0xe8, 0x2f, 0x76, 0x22, 0x6e, 0x03, 0x28, 0x49, 0x82, 0xec, 0x48, 0x48, 0x12, 0x09, 0xb1, 0xa7, 0xd4, 0xc8, 0x79, 0x7e, 0x44, 0xbf, 0xa8, 0x70, 0xb2, 0x20, 0x04, 0xdb, 0x74, 0xbd, 0x7d, 0x47, 0x8d, 0x5b, 0x36, 0x14, 0xd2, 0xb1, 0xda, 0x75, 0x02, 0xb3, 0x98, 0xeb, 0x9d, 0xa8, 0x0d, 0x06, 0x46, 0x1e, 0x90, 0xe0, 0x30, 0x60, 0x44, 0x6a, 0xb4, 0xa8, 0x23, 0x84, 0x32, 0xbf, 0xaf, 0x75, 0x2f, 0x39, 0x17, 0x91, 0x21, 0x4f, 0x1e, 0x6b, 0x63, 0x59, 0x0d, 0x53, 0x60, 0x60, 0xd1, 0xc2, 0x45, 0x30, 0x7b, 0xc5, 0xc1, 0xba, 0xc4, 0xaa, 0xa0, 0x99, 0xd3, 0x6b, 0xb6, 0xdc, 0xbc, 0x97, 0x3c, 0xf2, 0xe6, 0x9f, 0x27, 0x34, 0xd0, 0xf2, 0x9a, 0xee, 0xc4, 0x56, 0x7b, 0x99, 0xa1, 0x6b, 0xc1, 0x7c, 0x6c, 0xdd, 0xac, 0xef, 0xe4, 0x99, 0x27, 0xfb, 0x14, 0xe7, 0xd9, 0x8d, 0xd4, 0x26, 0x35, 0x19, 0x46, 0x9c, 0xca, 0x3d, 0xb4, 0x67, 0x9a, 0x68, 0xce, 0xed, 0xa9, 0x55, 0x59, 0x22, 0x10, 0xfc, 0x49, 0xaa, 0x5f, 0xbe, 0x93, 0x4c, 0xc7, 0x3d, 0x84, 0xe4, 0xba, 0x54, 0x78, 0x00, 0x2d, 0x68, 0x90, 0x98, 0x90, 0x68, 0xef, 0x8f, 0xc9, 0x8c, 0x25, 0x32, 0xb8, 0x3b, 0xf3, 0xcb, 0x9e, 0xf0, 0x28, 0x93, 0xc2, 0x15, 0x24, 0x26, 0xb9, 0xd1, 0xa9, 0x47, 0x34, 0xdf, 0xb4, 0xf9, 0x11, 0x35, 0x14, 0x3c, 0x9e, 0xed, 0x18, 0xfd, 0x51, 0xae, 0x87, 0x5d, 0x07, 0xa2, 0x37, 0x75, 0x60, 0x6a, 0x73, 0x4f, 0xba, 0x98, 0xc0, 0x63, 0xb4, 0xa1, 0x62, 0x2e, 0x7f, 0xf2, 0x1a, 0xa7, 0xe6, 0x52, 0xa3, 0xd6, 0xc1, 0x9f, 0xe0, 0xdc, 0x67, 0x61, 0xb7, 0xd3, 0x53, 0x02, 0xbf, 0x21, 0x4d, 0x30, 0x79, 0xf7, 0x60, 0x51, 0x08, 0x2a, 0x87, 0x59, 0x29, 0x92, 0x0d, 0xc3, 0xb3, 0xcb, 0x43, 0x21, 0x1a, 0x23, 0xa4, 0x3a, 0x50, 0x33, 0x2f, 0xaf, 0x1a, 0xc2, 0x19, 0x1e, 0x71, 0x71, 0x25, 0xf6, 0x3e, 0x25, 0x86, 0xc4, 0xd8, 0x6d, 0xca, 0x6b, 0xcd, 0x3d, 0x03, 0x8f, 0x9d, 0x3a, 0x7b, 0x66, 0xcb, 0xc7, 0xdf, 0x34, }, .t1_len = 1280, }, { .name = "ML-DSA 44 (seed only)", .parameter_set = CKP_IBM_ML_DSA_44, .priv_seed = { 0x4C, 0x6B, 0xF5, 0xA2, 0xC3, 0x87, 0xA6, 0x8F, 0x78, 0x28, 0xE3, 0xB3, 0x73, 0x33, 0xBB, 0xA3, 0xD5, 0x0F, 0x7F, 0x83, 0x89, 0xA5, 0x49, 0x3E, 0x69, 0x54, 0xD4, 0x15, 0x6E, 0x9D, 0xB9, 0x46, }, .priv_seed_len = 32, .spki = { 0x30, 0x82, 0x05, 0x32, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x11, 0x03, 0x82, 0x05, 0x21, 0x00, 0x25, 0x1a, 0x4d, 0x38, 0xd4, 0xec, 0x99, 0xa5, 0x82, 0xba, 0x25, 0x3b, 0x5b, 0x21, 0x22, 0x1a, 0xd2, 0x91, 0x60, 0xd1, 0x30, 0xe9, 0xf6, 0xea, 0x2e, 0xb1, 0x59, 0x2e, 0xb9, 0x44, 0x6b, 0x37, 0x6d, 0x23, 0x53, 0x4f, 0x8c, 0x80, 0x89, 0x93, 0x1e, 0x03, 0x46, 0xe6, 0x21, 0x1f, 0x11, 0xc7, 0x3c, 0x2c, 0x63, 0xfd, 0xe6, 0x7d, 0x96, 0x65, 0x47, 0xc9, 0xf0, 0xca, 0xe2, 0xd4, 0xea, 0x98, 0x53, 0xc3, 0xb5, 0x0a, 0x04, 0xf8, 0x2f, 0xf1, 0xb7, 0x7c, 0x65, 0x93, 0x0c, 0xa4, 0x80, 0xf4, 0x14, 0xf3, 0x4e, 0x0e, 0x35, 0xf4, 0x5a, 0xee, 0xa0, 0x8e, 0x7a, 0xe7, 0x1e, 0xe5, 0x12, 0xa9, 0xa7, 0x2d, 0xc2, 0xf3, 0x7b, 0x7b, 0x98, 0x7d, 0xcc, 0x29, 0xfa, 0x26, 0xa6, 0xcd, 0x07, 0xf8, 0xab, 0x17, 0x37, 0x06, 0x81, 0x01, 0x38, 0xeb, 0xc4, 0xc4, 0xba, 0xa7, 0x0c, 0xec, 0x5d, 0xd2, 0x6d, 0x58, 0x11, 0xd5, 0x61, 0xe0, 0x1e, 0xd5, 0xc8, 0x20, 0xc3, 0x56, 0x31, 0x55, 0x7d, 0x05, 0x3e, 0xcf, 0x9b, 0x6e, 0xde, 0x61, 0x9b, 0x0c, 0x33, 0xcb, 0x6d, 0xc6, 0x6e, 0xc8, 0x8b, 0xd8, 0xc5, 0x12, 0x77, 0x7f, 0x22, 0xe5, 0xf6, 0xbf, 0x14, 0xfa, 0x88, 0x53, 0x95, 0x62, 0xe5, 0x25, 0x44, 0x5d, 0x81, 0x4d, 0xc2, 0xa6, 0xda, 0x13, 0xd7, 0xa6, 0x01, 0xfd, 0x59, 0x45, 0x34, 0x4c, 0x21, 0x15, 0x14, 0xcd, 0x14, 0x28, 0x90, 0xb2, 0x82, 0x37, 0x53, 0xc7, 0x5f, 0xd5, 0x4e, 0x40, 0xc8, 0x94, 0x6a, 0x7f, 0x2e, 0x3b, 0xf1, 0x50, 0x07, 0xb2, 0x8e, 0xbd, 0x4e, 0x45, 0x12, 0xd7, 0xc0, 0xc3, 0x35, 0xfe, 0x0a, 0xb4, 0xcc, 0x98, 0xdc, 0x38, 0x1a, 0x04, 0xd0, 0x8b, 0x84, 0x87, 0x10, 0xc3, 0x4f, 0x40, 0x59, 0xa0, 0xf2, 0x91, 0xb3, 0xa1, 0x46, 0xc7, 0x7d, 0xab, 0xca, 0xd1, 0xb9, 0xc4, 0x1e, 0x49, 0x73, 0x8e, 0x7b, 0x77, 0x14, 0x66, 0x70, 0x20, 0x4c, 0xa8, 0xce, 0x60, 0x7d, 0xf1, 0x56, 0x40, 0xf5, 0x48, 0x73, 0xda, 0x86, 0xf5, 0x7b, 0xaa, 0x9a, 0xb8, 0x0b, 0x85, 0x4e, 0x94, 0x20, 0x8e, 0xe2, 0xe9, 0x0b, 0x72, 0x88, 0xcf, 0x3a, 0xd2, 0x61, 0x14, 0x24, 0x9e, 0xae, 0x09, 0xb5, 0xc6, 0xbf, 0x90, 0x79, 0xf9, 0x6a, 0x0e, 0x30, 0xb5, 0x0a, 0xbe, 0x47, 0x6a, 0x2c, 0xb0, 0xdc, 0x05, 0x92, 0x7e, 0x26, 0xab, 0x8c, 0x15, 0xab, 0x9b, 0x2b, 0x08, 0x44, 0xd7, 0xd2, 0x47, 0x09, 0xf6, 0xf5, 0x1e, 0x38, 0xdc, 0x7d, 0x65, 0xe4, 0xf3, 0x0f, 0x90, 0x62, 0xea, 0x76, 0x39, 0x2b, 0xd6, 0x42, 0xeb, 0x38, 0xca, 0xdb, 0x51, 0x03, 0xfa, 0xba, 0x2d, 0x72, 0xbf, 0xa3, 0xf4, 0x41, 0x37, 0x39, 0xdb, 0xeb, 0xc1, 0xb6, 0x22, 0xea, 0x60, 0x92, 0xe6, 0x4f, 0x2d, 0x2a, 0xbc, 0xde, 0xb9, 0x5e, 0xc3, 0xff, 0x39, 0xcd, 0x4a, 0xfc, 0xd7, 0x7e, 0xc0, 0xbe, 0xa3, 0x09, 0x72, 0xc4, 0x93, 0xe6, 0x05, 0x66, 0x8c, 0xe9, 0xfb, 0xde, 0x66, 0xb7, 0xbb, 0xb3, 0x17, 0x51, 0xd0, 0x2f, 0x75, 0x74, 0x35, 0x35, 0x5a, 0x6c, 0x03, 0xca, 0x3d, 0x26, 0xb2, 0x9f, 0x6f, 0xac, 0x76, 0x00, 0xfd, 0x6c, 0xf3, 0xc1, 0x57, 0x4c, 0xa9, 0xb4, 0x02, 0x18, 0xfd, 0xb1, 0x58, 0xb3, 0xf4, 0x1d, 0x79, 0x1f, 0x1d, 0xe1, 0x11, 0x96, 0x5e, 0xf6, 0x57, 0xc3, 0xa2, 0x5a, 0xf9, 0xa2, 0x39, 0x4d, 0x96, 0x19, 0xdc, 0xf2, 0x57, 0x0f, 0xfa, 0xc2, 0x4d, 0x58, 0xf2, 0xd2, 0xa2, 0x3a, 0x8e, 0x22, 0x0c, 0x2f, 0xb7, 0x04, 0x68, 0xbf, 0xd8, 0xeb, 0xbd, 0x61, 0x15, 0xe0, 0xfa, 0x45, 0xb7, 0x25, 0x0f, 0xb5, 0xb4, 0xda, 0x70, 0xdb, 0xe0, 0xd3, 0x09, 0xcc, 0x13, 0x0a, 0x32, 0xbb, 0x2c, 0x9c, 0x3d, 0x1b, 0xf5, 0x19, 0x5e, 0x1a, 0x1b, 0xf2, 0xe5, 0x20, 0x41, 0xd8, 0xe2, 0x1b, 0x97, 0xba, 0x97, 0x7b, 0xe3, 0xd1, 0x48, 0xa1, 0x47, 0x15, 0xea, 0xc1, 0x49, 0x63, 0x17, 0x27, 0x36, 0x6a, 0xb1, 0x47, 0x60, 0x54, 0xa0, 0x61, 0x6f, 0xd9, 0xd0, 0xbc, 0xd2, 0x24, 0x53, 0x93, 0x96, 0x26, 0xa6, 0x3c, 0xea, 0x94, 0x10, 0x06, 0xd9, 0x2e, 0x62, 0x11, 0xfe, 0xf7, 0xf5, 0x47, 0xb4, 0x24, 0xec, 0x24, 0xda, 0xc8, 0xe7, 0x32, 0x8d, 0xe2, 0x8d, 0x39, 0x50, 0xa6, 0xfa, 0xa9, 0xac, 0x85, 0xc1, 0xd9, 0x1a, 0xab, 0x25, 0x35, 0xc9, 0x3d, 0x37, 0xc6, 0x61, 0x28, 0x81, 0x67, 0x5c, 0x1f, 0x6f, 0xd5, 0x5e, 0x93, 0x98, 0xea, 0x85, 0x18, 0x48, 0xa8, 0x2d, 0x3e, 0x3f, 0x69, 0x21, 0xe6, 0x5e, 0xd6, 0x02, 0x0b, 0xd4, 0x7a, 0x79, 0x48, 0x4b, 0xdf, 0x37, 0x51, 0x4a, 0x5e, 0x7d, 0xda, 0x47, 0x9b, 0xd7, 0x13, 0x1a, 0x91, 0xec, 0x15, 0x4b, 0x1b, 0xe7, 0x83, 0x9a, 0x66, 0xe6, 0xc9, 0x2b, 0x4d, 0xbd, 0xc7, 0x43, 0xa0, 0x81, 0x7e, 0x86, 0xdf, 0x71, 0x27, 0xb3, 0x5c, 0x35, 0x99, 0x61, 0x86, 0xeb, 0x3c, 0xda, 0x52, 0xf2, 0x51, 0xe3, 0x33, 0x0e, 0x8c, 0xda, 0x09, 0xc1, 0x89, 0xfe, 0x55, 0x44, 0x91, 0xc2, 0x37, 0x85, 0x69, 0x9a, 0xe9, 0x41, 0x50, 0x9f, 0xf6, 0x84, 0x87, 0x90, 0x46, 0x86, 0xb0, 0xf5, 0x69, 0x2e, 0x7a, 0x93, 0x01, 0x7f, 0xce, 0x2f, 0xe0, 0x15, 0x88, 0x3f, 0xfb, 0xdb, 0xfa, 0xfe, 0x9c, 0x13, 0x0b, 0x63, 0xc9, 0x36, 0xdc, 0x4d, 0x42, 0x26, 0x57, 0xb5, 0xbd, 0xb8, 0x42, 0x1c, 0x7c, 0x5b, 0xa8, 0x33, 0x3c, 0xde, 0xe1, 0x7b, 0x07, 0x35, 0x11, 0xfd, 0x76, 0xb9, 0xad, 0x4d, 0x7e, 0x84, 0x36, 0xe6, 0x3c, 0x88, 0x2b, 0x1b, 0x71, 0x5b, 0x65, 0x2c, 0xd5, 0x3a, 0x6d, 0x44, 0xc4, 0x9e, 0x98, 0x62, 0xc5, 0xfa, 0xc1, 0x51, 0xa7, 0xdd, 0x7d, 0x5c, 0x04, 0x60, 0x9f, 0xf8, 0x27, 0x77, 0xc5, 0x01, 0x81, 0xbb, 0x01, 0xed, 0xbf, 0x17, 0xe5, 0x8d, 0x3e, 0x6c, 0x2f, 0xa8, 0x15, 0x2f, 0xb2, 0x59, 0xc3, 0x09, 0xfb, 0xa1, 0xa2, 0xf6, 0x75, 0xf9, 0x8d, 0x44, 0x6c, 0x5e, 0xda, 0xd4, 0xad, 0xe6, 0x9a, 0x57, 0x5b, 0x1a, 0x66, 0x9d, 0x39, 0x5f, 0x87, 0x75, 0x9e, 0x69, 0x57, 0xdb, 0xd9, 0xe3, 0xc5, 0x39, 0x59, 0xb8, 0x49, 0x59, 0xf4, 0xd0, 0x95, 0xc8, 0x01, 0x36, 0xfc, 0xb5, 0x8d, 0x45, 0x9d, 0x07, 0x69, 0xca, 0xf1, 0xf5, 0x27, 0xfd, 0x72, 0x4a, 0x0e, 0x51, 0xe6, 0x4c, 0x2a, 0xab, 0x00, 0xa9, 0x12, 0xab, 0x62, 0xec, 0x63, 0x3b, 0x1c, 0xbf, 0x87, 0x89, 0xf5, 0xe9, 0x27, 0x7d, 0x46, 0x45, 0x45, 0x62, 0x65, 0x65, 0x07, 0x10, 0x48, 0xa3, 0xe4, 0x5c, 0xcf, 0x2b, 0xa2, 0x09, 0xa3, 0x7c, 0x1c, 0x94, 0x02, 0xb7, 0x55, 0x6a, 0xd1, 0x6b, 0xba, 0x9d, 0x3c, 0x3f, 0x62, 0x0b, 0x68, 0xe6, 0x92, 0x96, 0xe7, 0xb2, 0x72, 0x7a, 0x3d, 0x25, 0x11, 0xd5, 0x77, 0x75, 0x67, 0xb8, 0x73, 0x56, 0xc1, 0xb6, 0x1a, 0xaf, 0x41, 0x7a, 0x03, 0xef, 0x05, 0x20, 0xa2, 0x1c, 0x42, 0x55, 0x22, 0xc7, 0x5f, 0x80, 0x05, 0x5e, 0xee, 0xec, 0x56, 0xa4, 0x24, 0xf8, 0x67, 0xe2, 0xf0, 0x93, 0xd5, 0x12, 0x30, 0xcd, 0x97, 0xca, 0xcb, 0xfe, 0x22, 0xb9, 0xaa, 0xe4, 0xdc, 0x56, 0x76, 0xd2, 0x4f, 0x12, 0xba, 0xbf, 0x8e, 0x39, 0x8c, 0x75, 0x65, 0xd2, 0xa6, 0xa4, 0x06, 0x0d, 0x27, 0x02, 0x58, 0x8a, 0x23, 0xc0, 0x9f, 0x3e, 0x18, 0xe9, 0xb5, 0x37, 0xc4, 0x70, 0xda, 0x96, 0x80, 0x1d, 0x93, 0x9b, 0xd2, 0x2b, 0x8f, 0xbb, 0x4e, 0x0a, 0xd0, 0xf0, 0xd2, 0x23, 0x3f, 0x31, 0xca, 0x56, 0x0a, 0xe5, 0x6f, 0xc1, 0x9c, 0x39, 0x39, 0x15, 0xb4, 0x2b, 0x6e, 0xa9, 0x30, 0x86, 0xf6, 0xa3, 0x9f, 0x30, 0x8f, 0x92, 0x2b, 0x37, 0x3f, 0x31, 0x29, 0x9c, 0xa7, 0x38, 0xa6, 0x7f, 0x25, 0xa3, 0xf8, 0x05, 0x68, 0x59, 0xcb, 0x3c, 0x71, 0x09, 0xbe, 0xc7, 0x71, 0x8b, 0x25, 0x2c, 0x8e, 0xe2, 0x7b, 0x96, 0xe5, 0xf1, 0x71, 0x0e, 0x0c, 0x7a, 0x00, 0xbd, 0xe5, 0x03, 0x77, 0xab, 0x08, 0x3f, 0xfb, 0xdd, 0xdb, 0x4c, 0xba, 0x0e, 0x4a, 0xad, 0x3e, 0x29, 0xce, 0xeb, 0x74, 0xbf, 0x44, 0xa2, 0xe0, 0x9e, 0x7f, 0xf6, 0x50, 0x5c, 0x22, 0xb8, 0x0e, 0x56, 0xab, 0x0f, 0x61, 0xef, 0xd2, 0x19, 0x8c, 0x17, 0x0c, 0xd9, 0xab, 0x4a, 0x19, 0x74, 0x86, 0x30, 0x92, 0x19, 0x49, 0xd8, 0xe1, 0x62, 0x01, 0x93, 0x54, 0xda, 0x87, 0x9b, 0xce, 0x31, 0xd8, 0x0a, 0x4e, 0x73, 0x94, 0xb9, 0x89, 0x98, 0x55, 0x60, 0xd2, 0x38, 0x24, 0xfa, 0xac, 0xf4, 0xbd, 0x73, 0xf1, 0xda, 0xbb, 0xfa, 0x7e, 0x74, 0x12, 0x93, 0x3f, 0x20, 0xee, 0xe8, 0x17, 0x31, 0x5f, 0x3f, 0xa0, 0xda, 0x1b, 0x71, 0x11, 0x89, 0x78, 0x36, 0xea, 0x16, 0xf9, 0x69, 0x11, 0xa7, 0xd0, 0xed, 0x9b, 0x71, 0x98, 0x8a, 0xf8, 0x5b, 0xd0, 0xb4, 0x86, 0x20, 0x0a, 0x51, 0xfe, 0xda, 0x45, 0x76, 0x4c, 0xc5, 0x5b, 0xaa, 0xea, 0xb5, 0xea, 0x1f, 0x26, 0x59, 0xc6, 0x5f, 0xd7, 0x87, 0x7a, 0xd5, 0x6f, 0xdc, 0x6f, 0x46, 0xbb, 0xd5, 0xbb, 0xba, 0x3b, 0xb9, 0x48, 0xc0, 0x4f, 0x17, 0xc2, 0x0c, 0x53, 0x2d, 0x05, 0xcf, 0x10, 0xfe, 0x27, 0x4d, 0x87, 0xe6, 0x63, 0x14, 0x44, 0x71, 0x76, 0x3e, 0xe9, 0x49, 0xa4, 0x2a, 0x9d, 0xfd, 0x78, 0xa0, 0xcb, 0xb0, 0x8e, 0x80, 0x46, 0x66, 0x89, 0x24, 0x49, 0x35, 0xca, 0x11, 0x49, 0x6b, 0x35, 0x95, 0x1b, 0xd0, 0xed, 0x1f, 0x79, 0xbc, 0xec, 0x4c, 0x72, 0x25, 0xfe, 0xce, 0xd7, 0x6d, 0x5b, 0x66, 0x8e, 0x7f }, .spki_len = 1334, }, { .name = "ML-DSA 65 (PKCS#8/SPKI - priv-only)", .pkcs8 = { 0x30, 0x82, 0x0f, 0xd8, 0x02, 0x01, 0x00, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x12, 0x04, 0x82, 0x0f, 0xc4, 0x04, 0x82, 0x0f, 0xc0, 0x30, 0x67, 0x01, 0xd0, 0xd5, 0xe2, 0xdc, 0x95, 0x82, 0x73, 0x87, 0x42, 0x05, 0x7a, 0x69, 0x0d, 0x7b, 0x97, 0xd3, 0x94, 0x02, 0x43, 0x98, 0xd4, 0xba, 0x7d, 0x80, 0x4a, 0x25, 0xa1, 0xfb, 0xab, 0x1b, 0x82, 0x6a, 0x94, 0x51, 0x8a, 0x56, 0x29, 0xbe, 0x9e, 0x61, 0x6b, 0x8d, 0x8e, 0x73, 0x62, 0xdf, 0x6c, 0xd4, 0x48, 0xc0, 0x42, 0x10, 0xd7, 0xdd, 0x88, 0x64, 0xce, 0x24, 0xb8, 0xa6, 0x68, 0x6b, 0x09, 0xa0, 0x7d, 0x85, 0x27, 0xb7, 0xc4, 0xea, 0x7b, 0xdf, 0x21, 0x1c, 0x63, 0xc0, 0x6a, 0x93, 0x0a, 0x76, 0x90, 0x33, 0xc2, 0x17, 0x53, 0xf0, 0xc1, 0xa4, 0x49, 0x6b, 0xd6, 0xb4, 0x7f, 0xd7, 0xeb, 0x50, 0x79, 0x99, 0x4e, 0xca, 0x19, 0xe0, 0xe9, 0x3f, 0x1e, 0x97, 0xcf, 0xb9, 0xf1, 0x12, 0x01, 0x80, 0xd4, 0xb2, 0x84, 0x93, 0x5b, 0xed, 0x6a, 0xbc, 0x06, 0x2d, 0x1d, 0xe4, 0x16, 0x36, 0x18, 0x40, 0x64, 0x57, 0x04, 0x72, 0x10, 0x24, 0x13, 0x57, 0x45, 0x48, 0x31, 0x50, 0x23, 0x14, 0x01, 0x34, 0x05, 0x04, 0x70, 0x86, 0x48, 0x04, 0x40, 0x21, 0x46, 0x01, 0x06, 0x34, 0x21, 0x45, 0x56, 0x17, 0x50, 0x23, 0x46, 0x28, 0x13, 0x04, 0x21, 0x40, 0x73, 0x12, 0x22, 0x40, 0x72, 0x05, 0x22, 0x15, 0x66, 0x22, 0x18, 0x13, 0x82, 0x45, 0x77, 0x06, 0x01, 0x27, 0x07, 0x57, 0x87, 0x35, 0x18, 0x54, 0x07, 0x04, 0x28, 0x62, 0x25, 0x04, 0x27, 0x11, 0x34, 0x51, 0x30, 0x43, 0x26, 0x73, 0x64, 0x76, 0x17, 0x14, 0x17, 0x23, 0x20, 0x25, 0x10, 0x15, 0x57, 0x32, 0x23, 0x38, 0x52, 0x70, 0x73, 0x16, 0x55, 0x36, 0x07, 0x13, 0x88, 0x28, 0x81, 0x70, 0x21, 0x03, 0x21, 0x27, 0x21, 0x33, 0x18, 0x87, 0x53, 0x38, 0x61, 0x56, 0x22, 0x11, 0x87, 0x41, 0x73, 0x12, 0x16, 0x76, 0x36, 0x21, 0x80, 0x62, 0x35, 0x80, 0x05, 0x41, 0x66, 0x62, 0x26, 0x75, 0x04, 0x37, 0x57, 0x21, 0x21, 0x85, 0x03, 0x40, 0x18, 0x71, 0x15, 0x48, 0x10, 0x47, 0x21, 0x54, 0x41, 0x67, 0x81, 0x32, 0x88, 0x78, 0x75, 0x70, 0x04, 0x22, 0x62, 0x01, 0x75, 0x72, 0x06, 0x30, 0x47, 0x34, 0x11, 0x77, 0x82, 0x20, 0x08, 0x50, 0x54, 0x87, 0x57, 0x57, 0x77, 0x02, 0x45, 0x77, 0x42, 0x17, 0x03, 0x80, 0x10, 0x77, 0x67, 0x14, 0x86, 0x78, 0x73, 0x22, 0x30, 0x71, 0x05, 0x56, 0x80, 0x36, 0x45, 0x34, 0x18, 0x15, 0x17, 0x44, 0x01, 0x86, 0x63, 0x87, 0x12, 0x22, 0x81, 0x70, 0x65, 0x87, 0x74, 0x24, 0x52, 0x03, 0x13, 0x60, 0x52, 0x04, 0x57, 0x30, 0x44, 0x25, 0x80, 0x68, 0x84, 0x71, 0x87, 0x50, 0x38, 0x31, 0x47, 0x18, 0x84, 0x66, 0x25, 0x13, 0x47, 0x16, 0x45, 0x30, 0x07, 0x53, 0x77, 0x56, 0x05, 0x35, 0x28, 0x55, 0x10, 0x05, 0x71, 0x40, 0x12, 0x50, 0x32, 0x51, 0x22, 0x23, 0x70, 0x83, 0x20, 0x68, 0x34, 0x78, 0x83, 0x10, 0x87, 0x11, 0x81, 0x08, 0x50, 0x76, 0x00, 0x88, 0x48, 0x50, 0x52, 0x54, 0x45, 0x17, 0x18, 0x26, 0x18, 0x67, 0x40, 0x13, 0x54, 0x10, 0x58, 0x43, 0x44, 0x85, 0x58, 0x65, 0x74, 0x47, 0x13, 0x27, 0x77, 0x27, 0x77, 0x77, 0x85, 0x77, 0x14, 0x75, 0x82, 0x86, 0x43, 0x45, 0x74, 0x54, 0x13, 0x28, 0x33, 0x71, 0x21, 0x50, 0x27, 0x56, 0x16, 0x15, 0x70, 0x32, 0x18, 0x33, 0x70, 0x32, 0x32, 0x64, 0x82, 0x66, 0x54, 0x83, 0x88, 0x11, 0x43, 0x03, 0x17, 0x25, 0x85, 0x23, 0x03, 0x07, 0x40, 0x48, 0x54, 0x17, 0x64, 0x13, 0x85, 0x48, 0x78, 0x75, 0x14, 0x02, 0x64, 0x22, 0x83, 0x34, 0x57, 0x38, 0x67, 0x77, 0x38, 0x77, 0x11, 0x31, 0x16, 0x55, 0x11, 0x73, 0x44, 0x54, 0x31, 0x78, 0x27, 0x35, 0x71, 0x46, 0x45, 0x87, 0x28, 0x46, 0x40, 0x32, 0x80, 0x01, 0x80, 0x08, 0x48, 0x77, 0x72, 0x86, 0x71, 0x86, 0x02, 0x18, 0x57, 0x18, 0x82, 0x44, 0x44, 0x02, 0x01, 0x23, 0x76, 0x73, 0x17, 0x65, 0x73, 0x67, 0x62, 0x21, 0x62, 0x67, 0x01, 0x27, 0x43, 0x01, 0x71, 0x53, 0x70, 0x62, 0x82, 0x33, 0x11, 0x11, 0x06, 0x67, 0x78, 0x08, 0x53, 0x25, 0x25, 0x41, 0x37, 0x28, 0x71, 0x83, 0x45, 0x68, 0x05, 0x47, 0x34, 0x56, 0x26, 0x48, 0x65, 0x13, 0x25, 0x35, 0x34, 0x06, 0x00, 0x83, 0x85, 0x82, 0x34, 0x68, 0x08, 0x82, 0x25, 0x00, 0x53, 0x60, 0x47, 0x68, 0x83, 0x68, 0x80, 0x85, 0x78, 0x68, 0x37, 0x30, 0x42, 0x57, 0x36, 0x44, 0x76, 0x85, 0x04, 0x03, 0x02, 0x30, 0x24, 0x02, 0x27, 0x50, 0x81, 0x22, 0x40, 0x40, 0x57, 0x44, 0x36, 0x64, 0x77, 0x85, 0x43, 0x38, 0x28, 0x64, 0x38, 0x65, 0x32, 0x82, 0x24, 0x24, 0x77, 0x60, 0x42, 0x77, 0x31, 0x11, 0x87, 0x20, 0x04, 0x03, 0x60, 0x40, 0x35, 0x73, 0x24, 0x47, 0x27, 0x50, 0x58, 0x42, 0x23, 0x42, 0x71, 0x46, 0x18, 0x04, 0x02, 0x55, 0x02, 0x13, 0x76, 0x38, 0x42, 0x22, 0x27, 0x36, 0x33, 0x15, 0x18, 0x08, 0x71, 0x47, 0x06, 0x06, 0x47, 0x71, 0x05, 0x64, 0x44, 0x77, 0x15, 0x14, 0x86, 0x28, 0x74, 0x22, 0x62, 0x58, 0x45, 0x75, 0x35, 0x61, 0x74, 0x07, 0x82, 0x37, 0x62, 0x46, 0x46, 0x05, 0x87, 0x31, 0x25, 0x50, 0x02, 0x72, 0x40, 0x32, 0x17, 0x08, 0x58, 0x85, 0x42, 0x56, 0x73, 0x14, 0x84, 0x02, 0x56, 0x03, 0x06, 0x24, 0x11, 0x33, 0x53, 0x30, 0x53, 0x00, 0x53, 0x77, 0x68, 0x11, 0x03, 0x71, 0x37, 0x53, 0x14, 0x58, 0x21, 0x55, 0x33, 0x85, 0x67, 0x81, 0x34, 0x24, 0x56, 0x54, 0x05, 0x20, 0x88, 0x60, 0x03, 0x46, 0x14, 0x77, 0x58, 0x75, 0x27, 0x35, 0x78, 0x21, 0x28, 0x37, 0x11, 0x60, 0x76, 0x75, 0x07, 0x23, 0x01, 0x77, 0x84, 0x63, 0x10, 0x14, 0x65, 0x36, 0x06, 0x48, 0x34, 0x65, 0x72, 0x11, 0x03, 0x21, 0x78, 0x85, 0x57, 0x64, 0x37, 0x67, 0x28, 0x70, 0x66, 0x00, 0x85, 0x18, 0x52, 0x03, 0x15, 0x52, 0x30, 0x62, 0x26, 0x05, 0x68, 0x81, 0x13, 0x54, 0x01, 0x60, 0x21, 0x27, 0x46, 0x53, 0x05, 0x54, 0x60, 0x17, 0x35, 0x80, 0x35, 0x42, 0x88, 0x30, 0x11, 0x48, 0x84, 0x47, 0x08, 0x26, 0x43, 0x06, 0x54, 0x55, 0x46, 0x08, 0x30, 0x56, 0x42, 0x44, 0x81, 0x82, 0x18, 0x83, 0x62, 0x14, 0x62, 0x68, 0x15, 0x18, 0x85, 0x31, 0x34, 0x44, 0x61, 0x68, 0x40, 0x55, 0x78, 0x64, 0x13, 0x52, 0x22, 0x41, 0x47, 0x31, 0x40, 0x14, 0x40, 0x84, 0x34, 0x25, 0x61, 0x53, 0x45, 0x65, 0x08, 0x62, 0x72, 0x38, 0x58, 0x25, 0x50, 0x03, 0x36, 0x14, 0x15, 0x72, 0x46, 0x38, 0x78, 0x45, 0x10, 0x66, 0x84, 0x60, 0x81, 0x72, 0x37, 0x87, 0x88, 0x77, 0x42, 0x76, 0x70, 0x12, 0x73, 0x73, 0x51, 0x40, 0x68, 0x03, 0x34, 0x74, 0x76, 0x64, 0x71, 0x12, 0x64, 0x85, 0x43, 0x00, 0x56, 0x71, 0x07, 0x42, 0x71, 0x16, 0x27, 0x65, 0x18, 0x83, 0x31, 0x48, 0x07, 0x32, 0x20, 0x61, 0x82, 0x86, 0x56, 0x45, 0x31, 0x27, 0x21, 0x60, 0x36, 0x52, 0x64, 0x05, 0x52, 0x45, 0x10, 0x86, 0x37, 0x50, 0x45, 0x85, 0x81, 0x51, 0x77, 0x00, 0x71, 0x76, 0x24, 0x34, 0x07, 0x85, 0x74, 0x77, 0x66, 0x34, 0x88, 0x67, 0x63, 0x28, 0x87, 0x52, 0x77, 0x57, 0x42, 0x80, 0x76, 0x50, 0x08, 0x76, 0x37, 0x60, 0x37, 0x07, 0x37, 0x83, 0x82, 0x08, 0x62, 0x80, 0x43, 0x54, 0x67, 0x46, 0x06, 0x73, 0x25, 0x45, 0x21, 0x44, 0x34, 0x77, 0x36, 0x70, 0x14, 0x61, 0x08, 0x72, 0x48, 0x05, 0x75, 0x44, 0x57, 0x21, 0x62, 0x02, 0x36, 0x68, 0x53, 0x73, 0x21, 0x58, 0x43, 0x83, 0x52, 0x23, 0x11, 0x85, 0x62, 0x55, 0x53, 0x07, 0x21, 0x67, 0x86, 0x38, 0x18, 0x45, 0x01, 0x36, 0x76, 0x56, 0x72, 0x38, 0x51, 0x45, 0x27, 0x54, 0x21, 0x54, 0x34, 0x51, 0x46, 0x34, 0x45, 0x53, 0x62, 0x84, 0x50, 0x05, 0x86, 0x26, 0x03, 0x33, 0x85, 0x62, 0x28, 0x25, 0x71, 0x03, 0x42, 0x62, 0x12, 0x75, 0x13, 0x12, 0x74, 0x87, 0x22, 0x53, 0x06, 0x71, 0x34, 0x20, 0x48, 0x18, 0x05, 0x87, 0x67, 0x17, 0x01, 0x46, 0x24, 0x35, 0x04, 0x01, 0x24, 0x04, 0x33, 0x85, 0x02, 0x82, 0x64, 0x25, 0x16, 0x30, 0x45, 0x61, 0x05, 0x08, 0x05, 0x47, 0x80, 0x18, 0x17, 0x65, 0x78, 0x38, 0x36, 0x26, 0x64, 0x63, 0x70, 0x70, 0x04, 0x82, 0x51, 0x30, 0x40, 0x57, 0x08, 0x00, 0x60, 0x66, 0x50, 0x68, 0x84, 0x60, 0x70, 0x58, 0x54, 0x71, 0x04, 0x75, 0x33, 0x70, 0x45, 0x02, 0x07, 0x38, 0x52, 0x71, 0x16, 0x28, 0x81, 0x56, 0x08, 0x04, 0x82, 0x83, 0x44, 0x50, 0x26, 0x06, 0x82, 0x66, 0x44, 0x45, 0x21, 0x13, 0x47, 0x70, 0x77, 0x02, 0x54, 0x81, 0x30, 0x86, 0x35, 0x45, 0x36, 0x84, 0x35, 0x10, 0x53, 0x32, 0x13, 0x73, 0x37, 0x53, 0x72, 0x12, 0x21, 0x83, 0x70, 0x78, 0x55, 0x82, 0x86, 0x38, 0x61, 0x68, 0x85, 0x32, 0x86, 0x08, 0x60, 0x06, 0x74, 0x43, 0x58, 0x13, 0x21, 0x36, 0x01, 0x24, 0x88, 0x17, 0x64, 0x03, 0x12, 0x58, 0x67, 0x37, 0x05, 0x25, 0x27, 0x43, 0x45, 0x37, 0x78, 0x63, 0x44, 0x87, 0x60, 0x14, 0x25, 0x65, 0x51, 0x85, 0x55, 0x65, 0x40, 0x62, 0x07, 0x61, 0x41, 0x34, 0x21, 0x40, 0x41, 0x31, 0x53, 0x44, 0x23, 0x77, 0x60, 0x38, 0x12, 0x28, 0x35, 0x80, 0x05, 0x53, 0x30, 0x83, 0x38, 0x56, 0x40, 0x40, 0x17, 0x61, 0x71, 0x67, 0x77, 0x52, 0x52, 0x10, 0x68, 0x82, 0x83, 0x88, 0x52, 0x24, 0x62, 0x48, 0x35, 0x58, 0x77, 0x28, 0x46, 0x38, 0x16, 0x87, 0x42, 0x63, 0x81, 0x80, 0x01, 0x42, 0x52, 0x13, 0x76, 0x13, 0x75, 0x68, 0x37, 0x08, 0x37, 0x33, 0x76, 0x66, 0x40, 0x28, 0x12, 0x04, 0x65, 0x70, 0x50, 0x42, 0x37, 0x62, 0x62, 0x43, 0x03, 0x32, 0x45, 0x67, 0x20, 0x86, 0x65, 0x24, 0x42, 0x25, 0x51, 0x40, 0x14, 0x45, 0x55, 0x11, 0x41, 0x52, 0x06, 0x50, 0x83, 0x68, 0x45, 0x60, 0x32, 0x31, 0x34, 0x70, 0x47, 0x38, 0x41, 0x33, 0x74, 0x84, 0x15, 0x14, 0x82, 0x88, 0x15, 0x54, 0x36, 0x41, 0x23, 0x67, 0x27, 0x54, 0x22, 0x26, 0x64, 0x42, 0x51, 0x53, 0x58, 0x13, 0x68, 0x06, 0x63, 0x85, 0x50, 0x60, 0x50, 0x12, 0x87, 0x57, 0x52, 0x88, 0x58, 0x87, 0x38, 0x50, 0x68, 0x54, 0x64, 0x73, 0x23, 0x72, 0x13, 0x57, 0x77, 0x25, 0x50, 0x67, 0x22, 0x77, 0x51, 0x77, 0x81, 0x73, 0x21, 0x10, 0x25, 0x72, 0x17, 0x37, 0x26, 0x08, 0x61, 0x66, 0x72, 0x07, 0x03, 0x52, 0x45, 0x30, 0x76, 0x16, 0x73, 0x42, 0x55, 0x71, 0x50, 0x65, 0x27, 0x52, 0x67, 0x35, 0x54, 0x03, 0x44, 0x74, 0x44, 0x38, 0x34, 0x45, 0x81, 0x33, 0x14, 0x24, 0x85, 0x68, 0x60, 0x26, 0x41, 0x87, 0x58, 0x40, 0x78, 0x20, 0x33, 0x60, 0x41, 0x34, 0x03, 0x54, 0x25, 0x75, 0x32, 0x15, 0x01, 0x10, 0x57, 0x77, 0x71, 0x48, 0x01, 0x51, 0x71, 0x64, 0x61, 0x84, 0x22, 0x74, 0x12, 0x11, 0x44, 0x10, 0x20, 0x74, 0x51, 0x12, 0x77, 0x83, 0x10, 0x18, 0x74, 0x27, 0x80, 0x78, 0x33, 0x30, 0x57, 0x61, 0x33, 0x66, 0x80, 0x9f, 0x3c, 0x9d, 0xfe, 0x57, 0x1f, 0x4c, 0xf3, 0xb0, 0x2a, 0xcb, 0x5a, 0x86, 0x5f, 0x27, 0xf7, 0x96, 0x18, 0x50, 0xb9, 0xf8, 0x1c, 0x35, 0x2c, 0xcc, 0xfb, 0x05, 0x8b, 0xb4, 0x96, 0xb1, 0xe5, 0x5a, 0xde, 0x79, 0x73, 0x37, 0xf3, 0x3f, 0x5a, 0x01, 0x60, 0x9a, 0xb7, 0x37, 0x6e, 0xe9, 0x08, 0x4d, 0xf8, 0x0a, 0x7f, 0x34, 0x5c, 0x16, 0x2a, 0xb0, 0x87, 0xc9, 0x16, 0x60, 0xed, 0x79, 0xfa, 0xef, 0xbb, 0x69, 0x4c, 0x09, 0x02, 0x5b, 0x7d, 0x4e, 0x00, 0x58, 0x31, 0x48, 0x60, 0xb3, 0x1d, 0xf1, 0x63, 0x73, 0xb6, 0x98, 0x78, 0x12, 0xb2, 0xb4, 0x37, 0x96, 0xd5, 0xc3, 0xc2, 0xa6, 0x59, 0x5b, 0x1a, 0xc3, 0x5e, 0xe5, 0xbe, 0x75, 0x19, 0xab, 0x3a, 0x89, 0x49, 0x29, 0x8b, 0xde, 0xe5, 0x33, 0x9e, 0x35, 0xb8, 0x44, 0x13, 0x1f, 0x8e, 0x0c, 0x59, 0x3c, 0x0e, 0xb6, 0xf0, 0x57, 0x8b, 0xb4, 0x4e, 0xe8, 0xa2, 0x5d, 0x4a, 0x7d, 0x5f, 0xcf, 0xa9, 0x78, 0xc9, 0xa6, 0xd9, 0xc6, 0x99, 0xba, 0x21, 0xdd, 0xc5, 0x9f, 0xf2, 0x04, 0xef, 0x4e, 0xaf, 0xd1, 0x2f, 0x2b, 0x56, 0xcc, 0x3e, 0x3a, 0x17, 0x8c, 0x0a, 0x2b, 0xdb, 0x26, 0xeb, 0xaf, 0xcb, 0xcc, 0x9b, 0x0f, 0x77, 0x43, 0xaa, 0x8c, 0x13, 0x15, 0x00, 0xd7, 0x35, 0xaf, 0xf9, 0xf1, 0x52, 0x0d, 0x9d, 0x13, 0x13, 0x7f, 0x0b, 0x65, 0x74, 0x0b, 0x9e, 0xd4, 0x35, 0xfe, 0xa0, 0xe9, 0xa9, 0x57, 0x9e, 0x30, 0x28, 0x49, 0xf3, 0x05, 0x9a, 0xd8, 0xbd, 0x88, 0xd7, 0xea, 0x56, 0xdb, 0x15, 0x59, 0xb5, 0x8e, 0xfd, 0xe5, 0xd9, 0x96, 0xcb, 0xa0, 0xe3, 0x29, 0x2b, 0x4a, 0x48, 0x27, 0x70, 0x44, 0x69, 0xc9, 0x9f, 0x6b, 0xb1, 0x85, 0x9e, 0x73, 0x68, 0x4d, 0xcd, 0x9e, 0xc8, 0xb3, 0x50, 0xa3, 0x77, 0xa4, 0x3b, 0xe0, 0xb6, 0x38, 0xb0, 0x1a, 0x97, 0x6d, 0xe2, 0x89, 0x38, 0xaf, 0xd2, 0x53, 0xed, 0x9e, 0x3b, 0x24, 0xaa, 0xc9, 0x93, 0x86, 0x9a, 0xdb, 0xcf, 0xc4, 0xf9, 0xde, 0x31, 0x4a, 0xde, 0xca, 0x7a, 0x6b, 0x5d, 0x4b, 0x27, 0xb1, 0xf8, 0xd2, 0xa0, 0x90, 0xce, 0x54, 0x79, 0x0f, 0x3a, 0xb6, 0xea, 0xa5, 0x8c, 0x47, 0x51, 0xc6, 0xef, 0xbf, 0x67, 0xfe, 0xbd, 0x48, 0x3c, 0x72, 0xf5, 0x68, 0x3d, 0x9c, 0xe6, 0xea, 0xe9, 0x36, 0x1f, 0xcd, 0x4d, 0x9c, 0x54, 0x9f, 0xcf, 0xe2, 0x7a, 0x4a, 0x20, 0x46, 0x48, 0x5e, 0x75, 0x6e, 0xf1, 0x25, 0x29, 0x5c, 0x32, 0xfd, 0x1a, 0x56, 0xe4, 0xfe, 0xad, 0x00, 0xa2, 0xfd, 0x28, 0xb8, 0xab, 0x85, 0x22, 0x23, 0x9f, 0xef, 0x92, 0x7b, 0xa4, 0xef, 0xb0, 0x8c, 0xc3, 0x97, 0x5c, 0x2d, 0xfd, 0xf4, 0x5f, 0xff, 0xf6, 0xb5, 0x2e, 0xbd, 0x9d, 0xc2, 0x6a, 0x6a, 0x31, 0xcd, 0x94, 0x87, 0x66, 0x6b, 0x4c, 0x3f, 0x0a, 0x70, 0x7a, 0x63, 0x00, 0x88, 0x1c, 0x4d, 0xb9, 0x22, 0x16, 0x1b, 0x8e, 0xd3, 0x46, 0x36, 0x07, 0xc5, 0x4d, 0x41, 0x81, 0x4c, 0x4c, 0x02, 0x94, 0x95, 0xa2, 0x1e, 0x08, 0xdc, 0x34, 0x9a, 0x0d, 0x4a, 0x15, 0x96, 0x88, 0xca, 0x7e, 0xf0, 0xab, 0x79, 0x24, 0x50, 0x7a, 0x2a, 0xf0, 0xc6, 0x63, 0xd4, 0xae, 0x54, 0x6a, 0x41, 0x4d, 0x78, 0xd3, 0xf6, 0x42, 0x7e, 0xa2, 0x59, 0x5c, 0x07, 0xf9, 0x20, 0x9c, 0x8a, 0xd9, 0x5b, 0x19, 0xe1, 0x7c, 0xab, 0xd2, 0x50, 0x5a, 0x91, 0xaa, 0xfc, 0x9b, 0x4d, 0x12, 0x1f, 0x5c, 0xb0, 0x5b, 0x4f, 0x9a, 0x35, 0x50, 0xf4, 0x5c, 0xa9, 0xc8, 0x1b, 0x70, 0x1d, 0xde, 0x3d, 0xb7, 0x48, 0x02, 0x6a, 0x0c, 0xa3, 0xae, 0xd3, 0x75, 0xdb, 0xd4, 0xd3, 0xb7, 0x28, 0x2c, 0x3c, 0x2b, 0x43, 0xcd, 0xde, 0x3f, 0xf0, 0xa6, 0x6d, 0x3a, 0x35, 0x75, 0xe1, 0x86, 0x03, 0x24, 0x46, 0xd7, 0xde, 0x2f, 0xdf, 0xf8, 0xce, 0x0b, 0x42, 0x87, 0x8f, 0x30, 0xcc, 0x43, 0xd5, 0x4d, 0x16, 0x0a, 0xce, 0x8c, 0x05, 0x02, 0xb2, 0x69, 0x3f, 0xf7, 0x51, 0x11, 0xc3, 0x00, 0x04, 0x24, 0x57, 0x62, 0x48, 0x8f, 0x6f, 0x14, 0xf2, 0x60, 0x14, 0xbe, 0xbb, 0xaa, 0x63, 0x67, 0x94, 0xb2, 0xf6, 0x55, 0x3f, 0x69, 0xf4, 0x03, 0xef, 0x04, 0xf6, 0xba, 0xf9, 0xeb, 0x93, 0xff, 0x0b, 0xa7, 0x16, 0xd8, 0x5b, 0xca, 0x7b, 0x8b, 0x41, 0xe4, 0xd5, 0x2e, 0x2d, 0x8a, 0xa8, 0xff, 0xab, 0xd7, 0xe4, 0x53, 0x6e, 0xa7, 0x09, 0xf3, 0x99, 0x56, 0x01, 0xe2, 0x5b, 0x9e, 0xd1, 0x38, 0x65, 0xf3, 0x2a, 0xca, 0xba, 0x33, 0x1d, 0x33, 0xef, 0x9d, 0x2f, 0x12, 0x28, 0xbf, 0x12, 0xca, 0x76, 0x3a, 0x3c, 0x01, 0x00, 0x5f, 0xb0, 0x0b, 0x88, 0xf7, 0x48, 0xc4, 0xb2, 0xd9, 0xe0, 0xc2, 0xe6, 0xea, 0x8a, 0x95, 0xfb, 0x82, 0x1f, 0xa6, 0xc1, 0xc3, 0xfc, 0x04, 0xe8, 0xfa, 0x22, 0x32, 0xb1, 0x75, 0x5c, 0x58, 0xb9, 0xb0, 0xe6, 0x50, 0x45, 0x88, 0x52, 0x1b, 0x7e, 0xa9, 0xb4, 0xd2, 0x87, 0x7a, 0x56, 0xf1, 0xda, 0x52, 0x09, 0x1c, 0xab, 0xf6, 0x71, 0xf0, 0x14, 0xaf, 0x33, 0x15, 0x53, 0xc2, 0x5f, 0xdb, 0x13, 0x45, 0xc3, 0xa3, 0x49, 0x43, 0x7d, 0x6b, 0xe8, 0x65, 0xd8, 0x98, 0xee, 0xa8, 0x98, 0x76, 0xbd, 0x73, 0xa9, 0x94, 0xe3, 0xd9, 0xd4, 0x2f, 0x90, 0x8b, 0xc3, 0x0a, 0x55, 0x8a, 0x5d, 0x39, 0xf6, 0x6f, 0xcf, 0x20, 0x88, 0x66, 0x37, 0xf8, 0x1d, 0x01, 0x38, 0xd5, 0x46, 0x92, 0xc4, 0x76, 0x88, 0x69, 0xdf, 0xd9, 0x39, 0xff, 0x3f, 0x06, 0x9b, 0xfb, 0x13, 0x74, 0x4f, 0xf6, 0xe1, 0x99, 0x17, 0xc7, 0xd6, 0xec, 0xc1, 0xef, 0xc3, 0x75, 0x28, 0x1e, 0x37, 0x65, 0x12, 0xe1, 0x9b, 0x42, 0x8d, 0x80, 0x19, 0xa4, 0xdd, 0x95, 0xc1, 0xe4, 0x06, 0xbd, 0x2a, 0x95, 0x10, 0x18, 0xc6, 0xda, 0x39, 0x9d, 0xd7, 0x4d, 0x22, 0x1a, 0x53, 0xc3, 0xc3, 0xbb, 0x50, 0x6b, 0xc3, 0xe4, 0xe4, 0xe4, 0x64, 0x8e, 0x2d, 0x03, 0xe1, 0x07, 0x2f, 0x01, 0x89, 0x6e, 0x14, 0x44, 0x8c, 0x4b, 0x7e, 0xb2, 0x94, 0xa3, 0x4e, 0xda, 0x9a, 0xc3, 0xf5, 0x10, 0xc0, 0x44, 0x18, 0xa1, 0x41, 0x77, 0x3c, 0x0c, 0xe4, 0x15, 0xa6, 0xf8, 0x3b, 0x5d, 0x76, 0xf0, 0xf0, 0xc1, 0x7f, 0x26, 0xc2, 0x2a, 0x81, 0xd1, 0x45, 0xb5, 0x60, 0x6e, 0x9f, 0x1c, 0x6e, 0x7f, 0xe8, 0xbf, 0xd2, 0x3b, 0x89, 0x4f, 0x3b, 0x1e, 0xb6, 0xe8, 0x44, 0xcc, 0x51, 0x91, 0x27, 0x82, 0x35, 0x21, 0x47, 0xf5, 0x28, 0x67, 0xef, 0x3f, 0x82, 0xca, 0xf5, 0x47, 0xd6, 0x2c, 0xf0, 0x47, 0x58, 0x53, 0xce, 0xe4, 0xd3, 0x46, 0x2d, 0xcf, 0xaa, 0xe2, 0x19, 0x68, 0xab, 0x4b, 0xb3, 0x9e, 0x90, 0x0f, 0xbf, 0x7c, 0x6f, 0x65, 0x88, 0x9a, 0xfb, 0xfe, 0xf2, 0x6b, 0xb6, 0x20, 0x00, 0x30, 0x52, 0xea, 0x45, 0x73, 0xa9, 0x07, 0xce, 0xcc, 0xca, 0x54, 0x36, 0x22, 0xaf, 0xdb, 0xd1, 0x51, 0x35, 0x10, 0x0e, 0xf5, 0x5f, 0xa2, 0xab, 0x2b, 0x92, 0x83, 0x80, 0x61, 0x4a, 0xa5, 0x9a, 0xc1, 0xcd, 0xa4, 0xc9, 0x2c, 0x35, 0x70, 0x78, 0xc5, 0x74, 0x04, 0x80, 0x6b, 0xce, 0xe5, 0x4d, 0x4c, 0x14, 0xac, 0x9e, 0x55, 0x63, 0xc0, 0x05, 0x71, 0xd0, 0x8e, 0x34, 0x51, 0x0d, 0x43, 0xb0, 0xa2, 0x5c, 0xb7, 0x63, 0xce, 0x4a, 0x62, 0x7a, 0x29, 0x20, 0xb5, 0xc7, 0x0b, 0x1c, 0x11, 0x68, 0x6a, 0xf8, 0x87, 0x8a, 0x8d, 0x2b, 0x74, 0x9d, 0xec, 0x09, 0x73, 0x22, 0x1b, 0x20, 0xc4, 0x87, 0x01, 0xbb, 0x4f, 0x0e, 0xbd, 0x96, 0xdc, 0x65, 0x02, 0x43, 0x87, 0xf2, 0x5a, 0xe9, 0xcf, 0x81, 0x67, 0x17, 0x16, 0xd0, 0x3f, 0x7c, 0x1f, 0x95, 0x2b, 0xd8, 0xf2, 0xa9, 0x0e, 0xfa, 0xf9, 0x23, 0xf7, 0x35, 0xd5, 0x82, 0xd4, 0xe8, 0x23, 0x29, 0xcb, 0xc8, 0x1c, 0x1d, 0xe6, 0x73, 0x3c, 0x36, 0x2f, 0x63, 0x77, 0x3e, 0x56, 0xde, 0x0c, 0x80, 0x25, 0x8f, 0xa5, 0xdb, 0xe7, 0x92, 0x2d, 0x04, 0xe7, 0xae, 0xe8, 0x01, 0x67, 0x28, 0x46, 0x28, 0x80, 0x3b, 0x72, 0xb2, 0xa8, 0xcc, 0xe2, 0xa7, 0x41, 0x1b, 0x07, 0x5e, 0xe1, 0x9e, 0x0d, 0x6f, 0x64, 0x2e, 0x2f, 0xb6, 0xa7, 0x7b, 0xf1, 0xce, 0x3a, 0x1a, 0x2c, 0x52, 0x74, 0x3d, 0xa4, 0x1e, 0x71, 0xf7, 0x4e, 0x0f, 0x1d, 0x6f, 0xb1, 0xf5, 0x68, 0x58, 0xa6, 0xfa, 0x94, 0x20, 0x91, 0x14, 0xa9, 0x72, 0x28, 0xe4, 0x09, 0xc3, 0x36, 0xea, 0x43, 0x4a, 0xbd, 0x2f, 0x25, 0x6a, 0xbf, 0xbf, 0x4f, 0xca, 0x8a, 0x81, 0xf7, 0xce, 0x26, 0x78, 0x2a, 0x35, 0x96, 0x89, 0xf8, 0xb1, 0x30, 0x54, 0x82, 0x1a, 0x87, 0xfe, 0xbf, 0x9b, 0x0e, 0xd2, 0x92, 0x41, 0x86, 0xf9, 0xe3, 0xc0, 0x15, 0x21, 0x10, 0x75, 0x43, 0x6c, 0x60, 0x4e, 0x01, 0x3f, 0x22, 0x36, 0xbd, 0x01, 0xb1, 0xf3, 0x1e, 0xd2, 0xdf, 0x75, 0xa0, 0x81, 0x5a, 0x9f, 0x20, 0x05, 0x95, 0x01, 0x71, 0xcb, 0x41, 0xd9, 0xe8, 0x1e, 0x37, 0x2a, 0x30, 0x29, 0x81, 0x78, 0x65, 0xce, 0x2e, 0x1d, 0x69, 0xef, 0x1c, 0xfe, 0xce, 0xac, 0x82, 0x91, 0xc5, 0xed, 0x03, 0x35, 0x86, 0xdc, 0xac, 0x2e, 0x77, 0x09, 0xc2, 0x65, 0x41, 0x8d, 0x61, 0x88, 0x8f, 0x9d, 0xa0, 0x53, 0x00, 0xc4, 0x9c, 0x43, 0xa1, 0xa8, 0xca, 0xab, 0xe5, 0x34, 0x0e, 0xe5, 0xef, 0xea, 0xe9, 0xae, 0x38, 0x40, 0x5c, 0x8b, 0xbe, 0x85, 0xd5, 0xd3, 0x72, 0x6b, 0xc7, 0xbe, 0xd3, 0x24, 0xc0, 0x1f, 0x8a, 0xfe, 0xc4, 0x2d, 0x73, 0xe2, 0xf1, 0x1e, 0xc1, 0x16, 0x9c, 0x0b, 0x2e, 0xe0, 0xe2, 0x25, 0x88, 0xb1, 0x91, 0x66, 0xcf, 0xd9, 0xbf, 0xbf, 0x9b, 0x25, 0xdd, 0xe1, 0xd5, 0x7c, 0xf7, 0x9b, 0x6e, 0x98, 0x79, 0x77, 0x64, 0xe7, 0x52, 0x9f, 0xab, 0x9c, 0x48, 0x88, 0xf5, 0xbe, 0x95, 0xc8, 0x3a, 0xb4, 0x38, 0xd2, 0xae, 0x32, 0x80, 0x51, 0xac, 0x9d, 0xc2, 0x0a, 0x40, 0x93, 0xa1, 0x69, 0x51, 0xe6, 0xa1, 0xcb, 0x12, 0xb2, 0x91, 0x45, 0xfd, 0xfc, 0xf6, 0x01, 0x49, 0xfa, 0xab, 0x4a, 0x32, 0x5d, 0x15, 0x55, 0xea, 0x38, 0x13, 0x92, 0x7b, 0xdb, 0x5d, 0x00, 0xeb, 0x3a, 0xd6, 0xf0, 0xd6, 0x84, 0xe1, 0x7b, 0x3f, 0xb2, 0x3a, 0xca, 0xe0, 0xd4, 0x9d, 0x5b, 0x31, 0xc2, 0x13, 0xe2, 0x06, 0x30, 0xfc, 0x5f, 0x0a, 0xf0, 0xef, 0x57, 0xf5, 0xf7, 0x2d, 0x1b, 0x4a, 0xaa, 0x3f, 0x29, 0x19, 0x45, 0x16, 0x40, 0x11, 0xd6, 0x7e, 0x51, 0x06, 0x1a, 0x40, 0x63, 0xe8, 0xa4, 0x6b, 0x23, 0x4a, 0xa8, 0xd8, 0x92, 0xa1, 0xf3, 0xc2, 0xb2, 0xfd, 0xb8, 0x8f, 0xa1, 0xd9, 0xf3, 0x74, 0x49, 0x0b, 0x99, 0x6a, 0xe3, 0xfa, 0x94, 0x2b, 0x40, 0x91, 0xf7, 0xac, 0x0a, 0x7a, 0x5d, 0x5f, 0xf5, 0xd2, 0x16, 0x50, 0x08, 0x33, 0xa7, 0xdd, 0xd4, 0xd0, 0x40, 0x57, 0xaf, 0x95, 0x33, 0xbf, 0xe0, 0x57, 0xf4, 0xee, 0x5e, 0x45, 0xcd, 0x7c, 0xb4, 0x18, 0xf8, 0x95, 0xa6, 0xcb, 0x60, 0xce, 0x8a, 0xed, 0x6d, 0x9d, 0xf1, 0xc1, 0xa2, 0xc7, 0xa1, 0x73, 0x74, 0xad, 0x47, 0x77, 0xae, 0x87, 0x3f, 0x07, 0x99, 0x50, 0xb8, 0xaa, 0x79, 0xbd, 0x66, 0x0a, 0xa8, 0x4a, 0x3d, 0x16, 0x99, 0xa6, 0x68, 0xab, 0x9a, 0x55, 0x7e, 0xe7, 0x90, 0xf7, 0x4b, 0x4f, 0x1a, 0xdc, 0x33, 0xd5, 0xf2, 0xcf, 0xd2, 0xeb, 0xf9, 0xcd, 0xae, 0x84, 0x1c, 0xa3, 0xbc, 0x95, 0xe1, 0xfd, 0xc4, 0x00, 0xbd, 0x78, 0xeb, 0x6f, 0xbc, 0xda, 0x13, 0x2d, 0x37, 0x6b, 0x6e, 0xa0, 0x40, 0x4d, 0x81, 0xde, 0x19, 0xdb, 0x69, 0x1a, 0x7d, 0xd7, 0xfd, 0x06, 0x20, 0x70, 0xc0, 0xab, 0xba, 0x7b, 0x1b, 0xa5, 0xf2, 0x55, 0x67, 0x15, 0x6d, 0xb7, 0xd9, 0x75, 0x50, 0x98, 0x49, 0x97, 0x54, 0xf6, 0xe1, 0xd8, 0x4c, 0xcb, 0x8b, 0xb8, 0xeb, 0x74, 0xb5, 0x79, 0xf7, 0xa5, 0x6f, 0xce, 0x7b, 0xb5, 0xb2, 0x62, 0xe3, 0x3b, 0x4e, 0xb3, 0xbb, 0x79, 0x57, 0x42, 0x68, 0x60, 0x56, 0x16, 0x67, 0x20, 0xe9, 0xea, 0x4d, 0xf7, 0xbf, 0x8c, 0xc3, 0x72, 0x83, 0x08, 0x02, 0xcd, 0xb2, 0x22, 0xa8, 0x70, 0x58, 0x70, 0x5f, 0x3e, 0xae, 0xf0, 0x39, 0xee, 0x4d, 0xcb, 0x42, 0x79, 0xe9, 0x13, 0x37, 0xb9, 0x37, 0x36, 0xca, 0xf9, 0x42, 0x6f, 0x5f, 0xbe, 0x5f, 0xea, 0x7e, 0xc2, 0xf5, 0x44, 0xc7, 0xf4, 0xf6, 0x2b, 0x28, 0xab, 0xf9, 0xaa, 0xc7, 0x2e, 0xa4, 0xc1, 0xee, 0x5b, 0xfe, 0x3f, 0xf9, 0xd4, 0x65, 0x6a, 0xaf, 0xf6, 0x57, 0x7c, 0xce, 0x59, 0x6f, 0xd9, 0x08, 0x3d, 0x26, 0xd3, 0xa3, 0xf0, 0x36, 0x29, 0x14, 0xca, 0x9a, 0x79, 0x24, 0x41, 0x84, 0xba, 0xb0, 0xc3, 0x36, 0x11, 0x8c, 0x08, 0x22, 0xb2, 0x6f, 0xe2, 0x7f, 0x84, 0x51, 0xe9, 0x52, 0xa0, 0x2d, 0xa4, 0xf7, 0x91, 0xef, 0xdd, 0x8a, 0x60, 0x34, 0xfe, 0xf3, 0xd0, 0xfe, 0x6a, 0x2b, 0xe6, 0x6a, 0x77, 0x79, 0x3c, 0xb7, 0x72, 0x0f, 0x4d, 0x8c, 0xe0, 0x8d, 0xc0, 0x6b, 0xe8, 0x8c, 0xea, 0xba, 0xad, 0x29, 0xaf, 0x80, 0xa5, 0x1e, 0x22, 0xda, 0xac, 0x38, 0x99, 0x34, 0x32, 0x94, 0xbd, 0xc0, 0xc3, 0x5e, 0xbe, 0x9b, 0xee, 0x2e, 0xa8, 0x0a, 0xe7, 0x25, 0xaa, 0x5e, 0x20, 0x8d, 0x6b, 0xa5, 0x5e, 0x25, 0xba, 0x2f, 0xaf, 0x2b, 0xb7, 0xe6, 0x4e, 0x8e, 0x6c, 0xfb, 0x80, 0x8b, 0xee, 0x00, 0xf4, 0x86, 0xa6, 0x42, 0x1d, 0x8d, 0xc6, 0x34, 0x43, 0x40, 0xd9, 0x83, 0xeb, 0x93, 0x22, 0x06, 0xb1, 0x98, 0x95, 0x6d, 0x89, 0x84, 0xf4, 0xf5, 0x3f, 0xda, 0x75, 0xd1, 0xfa, 0xc0, 0x41, 0xae, 0x4b, 0x74, 0x8e, 0x19, 0x41, 0x81, 0x83, 0x92, 0x91, 0x30, 0x7b, 0xec, 0x39, 0x97, 0x04, 0xd1, 0x5d, 0x37, 0x34, 0xf9, 0xe1, 0xa4, 0xa5, 0xe6, 0xfe, 0x5c, 0xfb, 0x59, 0x17, 0x5c, 0x2f, 0xa5, 0x31, 0x9c, 0xd2, 0x16, 0xfd, 0x7b, 0x23, 0x82, 0x02, 0x2f, 0x6c, 0xcb, 0x8d, 0x52, 0x33, 0x65, 0x1b, 0x2b, 0xcf, 0xf7, 0x1e, 0x13, 0xe0, 0xa8, 0x66, 0x22, 0xdb, 0x26, 0x38, 0xc8, 0x11, 0xe6, 0xe1, 0xb7, 0x7c, 0x9c, 0x2b, 0x7a, 0x36, 0x7d, 0x15, 0x93, 0xa6, 0x89, 0x4b, 0xb8, 0x42, 0xdf, 0x29, 0xcc, 0x0d, 0xcf, 0xef, 0x46, 0x21, 0x13, 0xfa, 0x6d, 0xe1, 0x75, 0x1c, 0x96, 0x4d, 0x65, 0x6a, 0x74, 0xbe, 0x2f, 0x0e, 0x1f, 0x06, 0xdf, 0x4f, 0x9d, 0xaa, 0xcc, 0x7b, 0x07, 0x23, 0x75, 0x3e, 0x98, 0x21, 0xd2, 0xae, 0x18, 0x9e, 0xe1, 0x93, 0x4b, 0x2a, 0xf8, 0x3a, 0xc3, 0x61, 0x88, 0xd9, 0x15, 0x03, 0x7e, 0x8b, 0x47, 0xdf, 0xef, 0x93, 0x60, 0xf1, 0x55, 0x8c, 0xbb, 0xdd, 0xfc, 0xb5, 0x68, 0x29, 0xd4, 0x43, 0x0e, 0x9e, 0x68, 0x13, 0xd9, 0x1b, 0x95, 0xc6, 0x7c, 0x6e, 0x20, 0xf2, 0xff, 0x37, 0xe1, 0xf1, 0xc2, 0xed, 0xed, 0x39, 0x6a, 0x17, 0xbc, 0x79, 0xba, 0x38, 0xb5, 0x9f, 0xb2, 0x36, 0xd7, 0xb0, 0x92, 0x17, 0xc8, 0x27, 0xe5, 0xb6, 0x1c, 0xb0, 0x34, 0x46, 0xa3, 0x6a, 0x49, 0xe1, 0xca, 0x2f, 0xb9, 0xb9, 0xe1, 0x75, 0x86, 0x78, 0x8b, 0xa6, 0xcc, 0x57, 0xdd, 0x63, 0x0e, 0x40, 0xab, 0xc4, 0x16, 0xa9, 0x99, 0x8d, 0xa4, 0x62, 0x83, 0xa3, 0xd8, 0xf7, 0xd5, 0xaf, 0x3f, 0x15, 0x79, 0x4a, 0xf4, 0xb3, 0x01, 0x48, 0xdc, 0xc4, 0x74, 0x55, 0x89, 0xb0, 0x89, 0x39, 0x29, 0x70, 0xd0, 0x74, 0x2f, 0xf5, 0xdd, 0x9d, 0x42, 0x34, 0xfb, 0x73, 0x0b, 0xac, 0x14, 0xa1, 0x36, 0x4e, 0x0d, 0x82, 0x65, 0x73, 0x94, 0xa2, 0x81, 0xb1, 0x84, 0x8f, 0x38, 0xba, 0x62, 0x3e, 0x7e, 0x5e, 0x19, 0xd0, 0x1e, 0x37, 0x85, 0xae, 0x16, 0xa2, 0xda, 0x8b, 0x77, 0x6c, 0x9a, 0xdc, 0xef, 0xb5, 0x8b, 0xb9, 0x01, 0xc0, 0x8e, 0x82, 0xc4, 0xd1, 0x48, 0x91, 0x26, 0xe6, 0xeb, 0x6d, 0xda, 0xb4, 0xe2, 0x41, 0x6d, 0x08, 0x82, 0x54, 0xf3, 0xe6, 0x51, 0xa3, 0x26, 0x9a, 0xaf, 0xe5, 0x7e, 0x74, 0xaf, 0x09, 0xb4, 0x8e, 0x5a, 0x51, 0xb6, 0x21, 0xa1, 0xc4, 0x94, 0x5d, 0x63, 0x64, 0x3f, 0xcf, 0x4b, 0x69, 0x4c, 0x39, 0xc8, 0x4f, 0x10, 0x04, 0xc8, 0x75, 0x43, 0x6e, 0x9d, 0xb9, 0x9b, 0xd1, 0xfc, 0x31, 0xc7, 0x54, 0xd6, 0x69, 0x59, 0xd2, 0x49, 0xe0, 0x71, 0x2e, 0x6d, 0xf0, 0x16, 0xce, 0x4e, 0xb4, 0x3d, 0xd4, 0xc5, 0x63, 0x91, 0xe7, 0xf8, 0xc3, 0xbb, 0xc3, 0xee, 0x6e, 0x46, 0x0b, 0xb7, 0xca, 0xbe, 0x57, 0x26, 0x2b, 0x3e, 0xfb, 0xc0, 0x2c, 0x4a, 0x04, 0x1b, 0x0e, 0x9a, 0x97, 0x73, 0x49, 0x64, 0x8b, 0xec, 0xf2, 0x5e, 0x9c, 0x46, 0xfe, 0x56, 0x12, 0xb8, 0x6f, 0xd2, 0x64, 0x91, 0x04, 0x4d, 0x09, 0x17, 0xb2, 0xac, 0x60, 0x31, 0x35, 0xd7, 0x0c, 0xc5, 0x7a, 0x42, 0x9d, 0x98, 0xef, 0x75, 0x0e, 0x0d, 0x39, 0x1c, 0xb4, 0x56, 0x52, 0x7a, 0xb5, 0xc4, 0xb8, 0x93, 0xca, 0xab, 0x36, 0x94, 0x34, 0xdb, 0xbe, 0xe4, 0xce, 0x54, 0x67, 0xe5, 0xc4, 0x24, 0xd0, 0x02, 0xe4, 0xb6, 0x0f, 0xdf, 0xfd, 0x08, 0xad, 0x48, 0x47, 0x05, 0x1a, 0x69, 0x38, 0x5b, 0x9e, 0xeb, 0x35, 0x0b, 0x3d, 0xf0, 0x97, 0xae, 0x67, 0x76, 0x19, 0x55, 0xb8, 0xdc, 0x89, 0xe3, 0x2d, 0xa6, 0x3f, 0x66, 0x11, 0x08, 0xf0, 0xdd, 0xe7, 0x5e, 0x2f, 0xaa, 0xf1, 0x68, 0x82, 0xe1, 0xb3, 0x4f, 0x8f, 0x25, 0x0f, 0x3e, 0x08, 0x4c, 0x19, 0xaa, 0x12, 0xfa, 0x4f, 0x79, 0x7a, 0xfe, 0x0a, 0x6b, 0x98, 0x3e, 0xf8, 0xe4, 0x64, 0x67, 0x2e, 0xe7, 0xc6, 0x43, 0x05, 0x45, 0x7e, 0x6d, 0xa2, 0x89, 0x14, 0x72, 0xe3, 0x4c, 0xa4, 0x1d, 0x4f, 0x92, 0x3b, 0x5c, 0x4c, 0x02, 0x9d, 0xcc, 0x2b, 0x12, 0x3a, 0xf1, 0xc7, 0x99, 0x6e, 0x1c, 0xa7, 0xf7, 0x00, 0xe7, 0x7e, 0x83, 0x12, 0x70, 0x99, 0xbf, 0xce, 0x6f, 0x33, 0x35, 0x29, 0x2c, 0x5d, 0x5d, 0x75, 0x48, 0x1b, 0xf9, 0xd9, 0xba, 0x43, 0x84, 0xea, 0x7f, 0x63, 0x60, 0x84, 0x87, 0x60, 0x49, 0x12, 0x1a, 0x4d, 0x0a, 0x0e, 0xba, 0x6c, 0x49, 0x96, 0xdd, 0x50, 0xbe, 0x42, 0x03, 0xbd, 0x69, 0x0a, 0xb0, 0x16, 0x6d, 0x9c, 0x2c, 0xb1, 0xe4, 0xb0, 0xa5, 0xec, 0xd5, 0xc6, 0xa2, 0xf5 }, .pkcs8_len = 4060, .spki = { 0x30, 0x82, 0x07, 0xb2, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x12, 0x03, 0x82, 0x07, 0xa1, 0x00, 0x30, 0x67, 0x01, 0xd0, 0xd5, 0xe2, 0xdc, 0x95, 0x82, 0x73, 0x87, 0x42, 0x05, 0x7a, 0x69, 0x0d, 0x7b, 0x97, 0xd3, 0x94, 0x02, 0x43, 0x98, 0xd4, 0xba, 0x7d, 0x80, 0x4a, 0x25, 0xa1, 0xfb, 0xab, 0x8e, 0xb8, 0xfb, 0x01, 0xfb, 0x12, 0x63, 0x47, 0xd1, 0x76, 0x51, 0x1c, 0x20, 0x21, 0x56, 0x00, 0x0f, 0x1b, 0xe1, 0x79, 0xf4, 0x00, 0x57, 0x10, 0x86, 0x3c, 0xc8, 0xbb, 0xa3, 0xfe, 0xc2, 0xc3, 0x41, 0xdc, 0x0d, 0xbf, 0xb2, 0x0f, 0x26, 0x2e, 0xb7, 0x40, 0x47, 0x3a, 0xbc, 0x14, 0x7c, 0x92, 0x55, 0x38, 0x4d, 0xc4, 0xc9, 0xe4, 0xf6, 0xa3, 0xa7, 0x2a, 0x94, 0x61, 0x9f, 0xbb, 0x25, 0x8a, 0xed, 0xfe, 0x57, 0xb7, 0x84, 0x6b, 0x7a, 0x3d, 0x2d, 0xe9, 0xa6, 0x4d, 0xda, 0x9b, 0x78, 0x0f, 0xc5, 0xf4, 0xd8, 0xb3, 0x67, 0x94, 0xcb, 0x21, 0x6b, 0x3f, 0x23, 0x6e, 0x1d, 0x5c, 0xb7, 0x13, 0xf9, 0xd2, 0x26, 0xd6, 0x6b, 0xd1, 0xa8, 0xd7, 0xc3, 0xad, 0xaf, 0xbe, 0xe7, 0x11, 0x38, 0x8f, 0x3c, 0x0d, 0x07, 0xb7, 0xcc, 0xb4, 0xea, 0x07, 0x48, 0x5a, 0x3b, 0xc5, 0x35, 0x09, 0x3d, 0x0c, 0x44, 0x57, 0x56, 0x3f, 0x63, 0x03, 0x7d, 0xde, 0xa6, 0x23, 0x89, 0x6a, 0x2a, 0x0b, 0x0c, 0xee, 0x8a, 0x7c, 0x44, 0x4f, 0xdc, 0xc3, 0x2c, 0xa5, 0x5f, 0xbc, 0xf0, 0x92, 0xf7, 0xf7, 0xbc, 0x62, 0x98, 0x91, 0x96, 0x00, 0x35, 0x45, 0x0f, 0x7a, 0xc3, 0x0c, 0x15, 0x49, 0x2f, 0xa4, 0xb4, 0xc2, 0xc2, 0x43, 0xb0, 0x8e, 0x97, 0x94, 0xcd, 0x6c, 0xc4, 0x90, 0x4b, 0x3f, 0x73, 0xbd, 0x69, 0x01, 0x91, 0x14, 0x13, 0xa7, 0xce, 0x22, 0xc4, 0xb0, 0xd8, 0xef, 0x31, 0x89, 0x98, 0x57, 0xc6, 0xac, 0x15, 0x1c, 0x39, 0xec, 0x5f, 0x4f, 0x3b, 0x22, 0x7e, 0xc7, 0x4d, 0x40, 0x31, 0x6f, 0x6b, 0xc9, 0xe7, 0xb4, 0x7a, 0xac, 0x16, 0xdd, 0xb0, 0x99, 0xa3, 0x4a, 0x33, 0x4a, 0xab, 0xfb, 0xa1, 0xa2, 0x36, 0x19, 0x50, 0x3a, 0x51, 0x0f, 0xc8, 0x64, 0x22, 0x34, 0x3b, 0x58, 0x1e, 0xc8, 0x00, 0x91, 0x02, 0xf8, 0xa3, 0xca, 0xd2, 0xe2, 0xb2, 0xd0, 0xf0, 0x0c, 0xcf, 0xb3, 0xeb, 0x8e, 0xa4, 0x61, 0x48, 0xd9, 0xec, 0x45, 0x0f, 0x52, 0xf4, 0xa9, 0x29, 0xf4, 0xde, 0x90, 0xb2, 0x8b, 0xa2, 0x31, 0xa3, 0x76, 0xcc, 0xaa, 0xea, 0xfd, 0xae, 0x4e, 0xfb, 0x24, 0x80, 0x0b, 0x45, 0xa9, 0x2b, 0xca, 0x9d, 0xa8, 0x27, 0x92, 0x64, 0x56, 0x5c, 0x77, 0x21, 0x5b, 0xd8, 0x02, 0x51, 0x6f, 0x63, 0x1d, 0x6f, 0x5b, 0x27, 0xf2, 0x11, 0x7a, 0xd5, 0xbd, 0x2f, 0x42, 0x5b, 0xac, 0xc5, 0x57, 0x1b, 0xe7, 0x04, 0xbc, 0x6f, 0xbf, 0xf6, 0xff, 0x60, 0x9f, 0xcb, 0x17, 0xb3, 0x33, 0x17, 0xc6, 0x7f, 0x31, 0x50, 0xed, 0xa9, 0x49, 0xf6, 0x26, 0x0e, 0x29, 0x4e, 0xe4, 0x13, 0x10, 0x13, 0xd4, 0x38, 0x46, 0x00, 0x9f, 0xd8, 0x8b, 0x6c, 0xe6, 0x15, 0x6c, 0xc5, 0xd3, 0xe1, 0xcb, 0xe6, 0x41, 0xc5, 0xd9, 0xc8, 0xeb, 0xa3, 0xf8, 0xa8, 0xd2, 0xa7, 0x77, 0x2c, 0x1b, 0xb3, 0x13, 0x70, 0x94, 0x06, 0x03, 0x2b, 0x1d, 0xf8, 0x58, 0x05, 0x5e, 0x2d, 0xd1, 0xca, 0xd3, 0x69, 0x65, 0x20, 0xf7, 0x80, 0xf3, 0xb4, 0xbc, 0x09, 0xfb, 0x28, 0x20, 0xd8, 0x16, 0x9b, 0x87, 0x0f, 0x41, 0x5a, 0x12, 0xc7, 0xdf, 0x92, 0x97, 0x5f, 0x47, 0xc0, 0x7e, 0xc8, 0x68, 0x82, 0x1e, 0xb9, 0xd4, 0x33, 0x34, 0x5a, 0xac, 0x3d, 0x2e, 0xc4, 0xe4, 0xfc, 0xe7, 0x97, 0xe0, 0x39, 0xf2, 0xe2, 0x1f, 0xb0, 0xfe, 0x7b, 0x95, 0x17, 0x8e, 0xab, 0xb0, 0xcf, 0x99, 0x98, 0xb2, 0xf0, 0xef, 0xa1, 0xf3, 0x14, 0xf1, 0x8c, 0xde, 0xcc, 0xcd, 0x25, 0xba, 0x1e, 0x5f, 0x7d, 0x17, 0x9f, 0x66, 0xf6, 0xea, 0xee, 0xe1, 0xe4, 0xac, 0xd5, 0xfa, 0x04, 0xe4, 0x24, 0xcc, 0x1d, 0x7d, 0x1f, 0xa1, 0xfb, 0x06, 0xd2, 0xa1, 0xae, 0x44, 0x5a, 0x41, 0x1d, 0x45, 0x9b, 0x8d, 0x39, 0xbb, 0xd9, 0xc7, 0x0a, 0x9f, 0xe7, 0x27, 0x39, 0xd9, 0xb1, 0xbd, 0x47, 0xc2, 0xb7, 0x7a, 0xad, 0x0c, 0x70, 0x7e, 0x86, 0x39, 0x7f, 0x1d, 0x98, 0x81, 0x4a, 0xa3, 0x84, 0x3f, 0x0f, 0xaa, 0x47, 0x18, 0x42, 0x1e, 0x4d, 0x05, 0x5e, 0x27, 0x85, 0x14, 0xb2, 0xb7, 0x49, 0x79, 0x89, 0xeb, 0x2c, 0xa6, 0x90, 0x94, 0xdd, 0x28, 0xf8, 0x06, 0x5c, 0x40, 0x0c, 0xa8, 0x8e, 0x23, 0x5b, 0x10, 0xaa, 0x0a, 0x1e, 0x29, 0xc8, 0x8b, 0x9a, 0x68, 0xa2, 0x60, 0x19, 0x07, 0xff, 0xe3, 0x4c, 0x67, 0x41, 0x8a, 0x23, 0xe0, 0xf1, 0xfd, 0xd4, 0x1a, 0x8a, 0xb1, 0x8b, 0x28, 0x54, 0x8b, 0x7e, 0x42, 0x26, 0xae, 0x0b, 0x8a, 0x4e, 0x57, 0xf0, 0xac, 0x94, 0x21, 0x90, 0x04, 0x8d, 0x7e, 0x12, 0xec, 0xc5, 0x43, 0x37, 0x6b, 0xf3, 0x4d, 0xf1, 0x72, 0x4e, 0x9a, 0xad, 0x65, 0x87, 0x73, 0x83, 0x91, 0x80, 0x06, 0x9e, 0x92, 0x4b, 0x74, 0x1f, 0x5c, 0xe9, 0x98, 0x0a, 0xa1, 0x4f, 0xfb, 0x19, 0x1a, 0x8d, 0xfc, 0xa7, 0x68, 0x8d, 0xcd, 0x08, 0xe5, 0x25, 0x02, 0x51, 0x8b, 0x8a, 0xec, 0x1f, 0x98, 0xa0, 0x46, 0x17, 0xfc, 0xb3, 0xb9, 0x59, 0xe2, 0x70, 0x52, 0xa1, 0x25, 0x8e, 0x8a, 0x84, 0x70, 0x3c, 0x60, 0x7e, 0x54, 0x78, 0x64, 0xce, 0x42, 0xdb, 0x2c, 0x71, 0xde, 0x65, 0x3a, 0xb5, 0x1a, 0x89, 0xc7, 0x17, 0x45, 0xa8, 0x7b, 0xea, 0xc5, 0x5e, 0x9d, 0x20, 0xab, 0x88, 0xef, 0xf3, 0x47, 0xbe, 0x62, 0x72, 0x96, 0x5c, 0x9e, 0x6b, 0xb4, 0x20, 0x8e, 0xab, 0x80, 0xc2, 0xa5, 0x4e, 0xc2, 0xf5, 0xc6, 0xc4, 0x46, 0xcd, 0x12, 0xac, 0x9f, 0x5f, 0x8a, 0xbf, 0xfb, 0xab, 0xdd, 0xb0, 0x5b, 0x5d, 0x56, 0x01, 0x3f, 0x37, 0x9f, 0x77, 0x61, 0x6e, 0xb0, 0x3b, 0x23, 0x95, 0xca, 0x13, 0x16, 0xeb, 0x77, 0x89, 0x30, 0xd8, 0x77, 0x05, 0xeb, 0x39, 0x92, 0x0d, 0xd5, 0x79, 0x87, 0xb7, 0xa2, 0xed, 0xd0, 0xf5, 0x56, 0x10, 0x28, 0x9e, 0x2c, 0xa9, 0x10, 0x30, 0x51, 0xec, 0x22, 0xff, 0xb3, 0x1e, 0x18, 0xe7, 0x49, 0x37, 0x32, 0xe5, 0x0a, 0x41, 0xc2, 0x39, 0x20, 0xfc, 0xf8, 0x30, 0x31, 0x9b, 0x77, 0xac, 0xdb, 0xee, 0xdc, 0x85, 0x96, 0xf1, 0x2e, 0x25, 0x4e, 0x5d, 0xbd, 0x18, 0x26, 0x25, 0x77, 0x06, 0xb9, 0xea, 0x9e, 0xb9, 0x2f, 0x67, 0x71, 0x2a, 0xb2, 0x73, 0x12, 0xf4, 0xe3, 0x35, 0x5a, 0x9a, 0x7f, 0x12, 0x57, 0x22, 0x8c, 0x2c, 0x37, 0x85, 0xb6, 0xb6, 0xfb, 0xe0, 0x6c, 0x1a, 0x41, 0x1f, 0xe9, 0xf5, 0x88, 0x4e, 0xda, 0x9f, 0x85, 0xc5, 0x84, 0x20, 0x90, 0x7b, 0xa4, 0x78, 0x59, 0x47, 0x4f, 0x6e, 0x6f, 0x14, 0x19, 0x87, 0xa7, 0x48, 0xbb, 0x21, 0x76, 0x26, 0xcb, 0xf1, 0x3c, 0x75, 0x4c, 0xa8, 0xcb, 0xed, 0x55, 0xd2, 0x39, 0x66, 0x42, 0xfa, 0x0c, 0xb3, 0xbf, 0xfc, 0x11, 0x56, 0xca, 0x48, 0x09, 0x70, 0xbe, 0x32, 0xc0, 0x94, 0xa7, 0x5f, 0x4a, 0xac, 0xb6, 0x14, 0x6b, 0x2a, 0x9b, 0xc8, 0x32, 0xfa, 0xd4, 0x87, 0x5f, 0x4b, 0xe8, 0x47, 0xe2, 0xfb, 0x74, 0xf6, 0xca, 0xfa, 0x77, 0x0e, 0x9b, 0x83, 0x0c, 0xae, 0xe8, 0x88, 0x32, 0xcd, 0x62, 0x68, 0x79, 0xc3, 0xf9, 0x06, 0x1e, 0xb8, 0x9c, 0xd1, 0xe1, 0xb0, 0x28, 0x45, 0xa8, 0xf7, 0x98, 0xde, 0xe6, 0xb8, 0xc7, 0xb2, 0x43, 0x8a, 0xd1, 0x27, 0xfd, 0x13, 0xdb, 0xb8, 0x56, 0xd3, 0x74, 0x3b, 0xc8, 0xad, 0x72, 0x14, 0x1f, 0x1f, 0x3f, 0x83, 0x68, 0x95, 0x82, 0xe2, 0x7f, 0x17, 0x0b, 0xd8, 0x67, 0x9a, 0xe5, 0x28, 0xa8, 0xb6, 0x2f, 0xfe, 0xb0, 0xf0, 0x5e, 0x02, 0x3e, 0x72, 0x0c, 0x69, 0x4b, 0x83, 0x06, 0xa3, 0x43, 0xbc, 0xba, 0x81, 0x29, 0x00, 0xd4, 0x5b, 0xeb, 0x19, 0x9b, 0x29, 0xd2, 0xc5, 0xa1, 0xc5, 0x2f, 0x59, 0xbe, 0x08, 0x8a, 0xf9, 0x5b, 0xfe, 0x1d, 0x57, 0xc0, 0x68, 0xd9, 0x6e, 0xce, 0x51, 0x07, 0x64, 0x58, 0x8d, 0x83, 0x77, 0xff, 0x3c, 0x5c, 0xf9, 0x96, 0x63, 0xc7, 0x5b, 0x9a, 0xdc, 0x26, 0x8e, 0xee, 0xe8, 0x3d, 0x1f, 0x41, 0x18, 0x44, 0x82, 0xe4, 0x7d, 0x43, 0xa1, 0xdb, 0x52, 0x50, 0xc5, 0x7d, 0x7e, 0x0a, 0xb5, 0xb7, 0x45, 0x7a, 0xb6, 0xd5, 0x5b, 0x69, 0xdd, 0x0a, 0xe2, 0x6d, 0xd1, 0x43, 0xbf, 0xe4, 0x7b, 0x3f, 0x1c, 0x4e, 0xae, 0x8a, 0x89, 0x51, 0xe9, 0x3d, 0x24, 0x27, 0xb9, 0x6b, 0xfa, 0xc4, 0x25, 0x17, 0x2c, 0xf0, 0xf3, 0x6a, 0x6a, 0xbe, 0x90, 0xeb, 0x98, 0x4f, 0xe9, 0xd2, 0xd1, 0x57, 0x01, 0x69, 0x6c, 0x86, 0x3e, 0x36, 0x07, 0xe4, 0x87, 0x16, 0xc7, 0xc6, 0xf3, 0x56, 0x7c, 0x3c, 0x3e, 0x12, 0x23, 0x76, 0x35, 0x8e, 0x29, 0x36, 0x3e, 0x0c, 0x1a, 0xff, 0xa7, 0xde, 0xc8, 0x23, 0x61, 0x96, 0x0d, 0x51, 0x13, 0x9b, 0xa9, 0xa9, 0xe4, 0x79, 0x3d, 0x70, 0x4c, 0x9f, 0x4c, 0xdb, 0xaa, 0xb9, 0x11, 0x8d, 0x9a, 0x6a, 0xac, 0x9c, 0xde, 0xcf, 0xa2, 0xda, 0x92, 0xde, 0x75, 0x8b, 0x9e, 0xb7, 0x5f, 0x97, 0x93, 0x78, 0x97, 0x89, 0x4f, 0x86, 0x1e, 0x2d, 0x56, 0xd5, 0x28, 0xeb, 0x5f, 0x4f, 0x1c, 0xc3, 0x30, 0x6b, 0xe5, 0xf5, 0x11, 0x62, 0x7f, 0xe3, 0xe4, 0xfb, 0x7e, 0xfe, 0xc7, 0xa7, 0xef, 0x30, 0xad, 0xd4, 0x62, 0x6b, 0xa9, 0x49, 0x75, 0xf7, 0x76, 0x5b, 0xc2, 0xb2, 0x2d, 0xaf, 0xa7, 0x26, 0xba, 0x14, 0x97, 0x2e, 0x97, 0xa2, 0xea, 0xb1, 0x7b, 0x42, 0x2d, 0x88, 0xd8, 0xc4, 0x70, 0x0c, 0x32, 0xea, 0x14, 0x74, 0x55, 0xd6, 0xaf, 0xcd, 0x6b, 0x59, 0xb0, 0x59, 0x9f, 0x7d, 0xa4, 0x83, 0x52, 0x85, 0x8a, 0x79, 0x8d, 0x3b, 0x4a, 0x3e, 0x29, 0x89, 0xd2, 0x40, 0x16, 0x3e, 0x09, 0x66, 0xdb, 0x9e, 0x63, 0xe3, 0x76, 0x92, 0x8b, 0x6b, 0x2f, 0x8f, 0x17, 0x9b, 0x4b, 0xea, 0x33, 0x04, 0x5a, 0xaf, 0xed, 0x47, 0x80, 0x95, 0x57, 0xae, 0x71, 0x7f, 0x8a, 0x7b, 0xf5, 0x0a, 0x8e, 0x93, 0xd0, 0x0e, 0x70, 0xf4, 0x51, 0x6c, 0x54, 0x96, 0xbf, 0xb2, 0xee, 0x5d, 0xca, 0xc0, 0x8b, 0xe1, 0xd3, 0x9a, 0x68, 0x11, 0x96, 0x37, 0x21, 0x7e, 0x56, 0x96, 0x3e, 0x6c, 0x66, 0x44, 0x57, 0xe9, 0x77, 0x2a, 0xcd, 0xc2, 0x72, 0x09, 0x71, 0x14, 0xfd, 0xe3, 0xff, 0xb1, 0xfd, 0x82, 0xf6, 0x15, 0xab, 0x55, 0xc3, 0xf2, 0x41, 0x41, 0x74, 0x68, 0xb6, 0xb0, 0xeb, 0x40, 0xfa, 0x60, 0xa8, 0x6c, 0x06, 0x3a, 0xc3, 0xe9, 0x71, 0x23, 0x85, 0x4d, 0x06, 0x44, 0xe8, 0x2b, 0xa7, 0xb2, 0x97, 0x78, 0x1c, 0x8d, 0x42, 0x36, 0xf8, 0xc5, 0x8a, 0x05, 0xa6, 0x02, 0xb4, 0x5e, 0xcd, 0x1a, 0x2a, 0xcd, 0x08, 0xa4, 0xa0, 0x15, 0x40, 0x81, 0x9a, 0x2f, 0xa5, 0x04, 0x50, 0xb0, 0xe1, 0xcc, 0x4b, 0x17, 0xed, 0xb3, 0xc4, 0x63, 0xf8, 0x15, 0x83, 0x05, 0x66, 0xa8, 0xc1, 0x00, 0x07, 0x36, 0x99, 0x83, 0x26, 0xf0, 0xc7, 0xb5, 0x3c, 0x67, 0xfb, 0xe6, 0x3a, 0x23, 0x13, 0x4b, 0xf2, 0xca, 0x13, 0x06, 0xc9, 0x8c, 0x85, 0xfe, 0xe7, 0xc5, 0xf2, 0x86, 0xd2, 0x65, 0xd4, 0x47, 0xd7, 0x5a, 0x87, 0xaa, 0xaa, 0xd9, 0xce, 0xbe, 0x6e, 0x3b, 0x38, 0x4a, 0xc7, 0x43, 0x7e, 0x14, 0x1b, 0x92, 0x2c, 0xf0, 0x70, 0x3d, 0xc6, 0x8e, 0xc3, 0x8b, 0xf3, 0x43, 0x66, 0xbb, 0xc0, 0xee, 0xf2, 0x5b, 0x34, 0xd8, 0x5a, 0xfb, 0xca, 0xb7, 0x3c, 0xd1, 0xc6, 0x85, 0xc0, 0x53, 0x80, 0x00, 0x19, 0x90, 0xde, 0xff, 0x29, 0x6f, 0x03, 0x6a, 0xc9, 0xc0, 0x37, 0x26, 0x5c, 0x4c, 0xf3, 0xda, 0x85, 0xeb, 0x90, 0x04, 0xb3, 0x3c, 0x84, 0x25, 0x98, 0xed, 0x67, 0xa2, 0x82, 0x39, 0xc5, 0x3e, 0x0d, 0xd9, 0x63, 0xc3, 0x9a, 0x70, 0xf2, 0x97, 0xe4, 0x97, 0x00, 0x2c, 0xbb, 0x08, 0xd4, 0xc1, 0x1c, 0xd9, 0x4e, 0xad, 0x37, 0xb0, 0x95, 0x57, 0x6e, 0x3e, 0x2c, 0x20, 0x61, 0xa8, 0x5f, 0xc6, 0xd5, 0x54, 0xc6, 0x67, 0xc1, 0x02, 0x2b, 0x4b, 0x29, 0x64, 0x8d, 0xcf, 0x78, 0x95, 0xe9, 0x7e, 0x59, 0xf2, 0xae, 0xb9, 0x88, 0xa5, 0xec, 0x8e, 0x78, 0x37, 0x31, 0x00, 0xe3, 0xe9, 0x61, 0x48, 0x2a, 0x52, 0x96, 0x5c, 0x6a, 0x42, 0xae, 0xee, 0x8d, 0x30, 0x89, 0x1b, 0xee, 0xd5, 0x25, 0x73, 0x8a, 0x6b, 0xd1, 0xbc, 0x01, 0xf1, 0x51, 0x7f, 0x55, 0x04, 0x8e, 0x0d, 0x7e, 0x05, 0xc0, 0xa7, 0x2e, 0xee, 0x4a, 0x32, 0x0c, 0x9c, 0x00, 0xd9, 0xb9, 0xd8, 0x62, 0x1b, 0x56, 0x49, 0x45, 0x0a, 0x8a, 0x20, 0x95, 0x7e, 0xe2, 0x98, 0x14, 0xd9, 0xe7, 0x81, 0x2d, 0xdd, 0x14, 0x18, 0x15, 0x23, 0x3d, 0x6c, 0xc4, 0x58, 0x19, 0x9b, 0xcb, 0xd4, 0x56, 0x23, 0x95, 0x3d, 0xc2, 0x77, 0xd4, 0x1a, 0xaa, 0x02, 0xcd, 0x88, 0xbd, 0x85, 0x28, 0xb6, 0x81, 0x51, 0x20, 0x8a, 0xba, 0x23, 0x64, 0x7a, 0x19, 0x87, 0x8a, 0x1d, 0x18, 0xff, 0x5c, 0x2c, 0x9e, 0x4e, 0x44, 0x83, 0xe1, 0x76, 0xd6, 0x96, 0xec, 0x44, 0xb3, 0xc4, 0x40, 0x13, 0xc1, 0x27, 0xcf, 0x19, 0x8c, 0x45, 0x86, 0xbf, 0x6c, 0xb6, 0x14, 0x0a, 0xfd, 0x59, 0x25, 0xff, 0xc0, 0x7d, 0x36, 0x9c, 0x47, 0x33, 0xdf, 0xd4, 0xe7, 0x7e, 0x3b, 0xab, 0x99, 0xc9, 0x47, 0x00, 0x91, 0x42, 0x42, 0x55, 0x87, 0xb7, 0x76, 0xf2, 0xee, 0xca, 0xa5, 0x2d, 0xe5, 0x95, 0xa0, 0x1b, 0xd0, 0x6c, 0xd6, 0xf2, 0x0d, 0x85, 0x60, 0x6a, 0x2a, 0xdd, 0x17, 0x45, 0x6f, 0x75, 0xa6, 0xf6, 0x31, 0xab, 0x63, 0x4f, 0x3f, 0x25, 0x2b, 0x98, 0xfc, 0xfb, 0xd0, 0x1a, 0x7e, 0xa0, 0x02, 0x9a, 0xdf, 0xb0, 0xe3, 0x3a, 0x00, 0x8c, 0x28, 0xf9, 0x34, 0x42, 0x4c, 0x93, 0x28, 0x89, 0x4f, 0x7b, 0xec, 0x23, 0x8a, 0x32, 0x61, 0xb6, 0x2c, 0x19, 0x23, 0x69, 0x3d, 0xfc, 0x70, 0xae, 0x4f, 0xb7, 0x82, 0x52, 0xa2, 0x5f, 0xb4, 0x1e, 0x16, 0xb5, 0x1f, 0xc4, 0x77, 0x3e, 0x20, 0xfa, 0x59, 0x12, 0xdd, 0x92, 0xb0, 0xeb, 0x0b, 0x17, 0x48, 0x2a, 0xcb, 0xde, 0x54, 0x7f, 0x4d, 0xab, 0xc3, 0x3a, 0x6a, 0xe0, 0x74, 0x8e, 0x8f, 0xc9, 0x31, 0xb1, 0x32, 0x75, 0xa5, 0x24 }, .spki_len = 1974, }, { .name = "ML-DSA 65", .parameter_set = CKP_IBM_ML_DSA_65, .rho = { 0xd2, 0xfd, 0x03, 0xf3, 0xa1, 0xb7, 0xf6, 0x35, 0xaf, 0x9f, 0x34, 0xd5, 0x80, 0xa9, 0x8f, 0x52, 0x4c, 0x73, 0x5b, 0xd5, 0xba, 0x23, 0x55, 0xdc, 0x6e, 0x03, 0x5b, 0xd2, 0x17, 0x65, 0x58, 0x0c, }, .rho_len = 32, .seed = { 0xe3, 0x8d, 0x1c, 0x14, 0xf6, 0x46, 0x7c, 0x35, 0xa9, 0xf3, 0x80, 0xd2, 0x7d, 0xe6, 0x1f, 0x7c, 0x75, 0x03, 0x15, 0x69, 0xea, 0x2e, 0xc8, 0x26, 0x0e, 0xee, 0x91, 0x05, 0x26, 0x1b, 0x7f, 0xe1, }, .seed_len = 32, .tr = { 0x60, 0xc9, 0x13, 0x44, 0xb0, 0xc6, 0x76, 0x4c, 0x20, 0x4e, 0x5b, 0x8d, 0x42, 0x46, 0x50, 0xbe, 0xc0, 0x6b, 0x9e, 0x2e, 0x62, 0x5a, 0xf0, 0x7e, 0x23, 0xf4, 0x95, 0x0c, 0xa2, 0x4f, 0xb4, 0xd6, 0xec, 0x2c, 0x8b, 0x3a, 0x71, 0x7c, 0x93, 0x11, 0xeb, 0x87, 0x27, 0x9f, 0xe2, 0x5e, 0x31, 0x1f, 0x48, 0xb8, 0x25, 0x65, 0x01, 0xf6, 0x46, 0x34, 0x12, 0xb5, 0x0d, 0xbc, 0x89, 0xa8, 0x69, 0xba, }, .tr_len = 64, .s1 = { 0x22, 0x41, 0x11, 0x26, 0x48, 0x40, 0x07, 0x38, 0x73, 0x02, 0x12, 0x44, 0x25, 0x44, 0x57, 0x54, 0x83, 0x72, 0x50, 0x33, 0x35, 0x62, 0x58, 0x42, 0x32, 0x01, 0x62, 0x11, 0x83, 0x61, 0x02, 0x45, 0x66, 0x56, 0x48, 0x35, 0x61, 0x20, 0x84, 0x52, 0x60, 0x68, 0x50, 0x45, 0x65, 0x55, 0x12, 0x72, 0x47, 0x47, 0x21, 0x21, 0x25, 0x40, 0x22, 0x21, 0x42, 0x81, 0x17, 0x65, 0x03, 0x06, 0x42, 0x61, 0x52, 0x13, 0x43, 0x25, 0x24, 0x33, 0x82, 0x12, 0x11, 0x35, 0x62, 0x33, 0x32, 0x07, 0x47, 0x86, 0x22, 0x31, 0x50, 0x83, 0x70, 0x84, 0x26, 0x43, 0x45, 0x64, 0x51, 0x48, 0x31, 0x14, 0x86, 0x24, 0x66, 0x86, 0x74, 0x33, 0x71, 0x36, 0x67, 0x26, 0x01, 0x47, 0x07, 0x72, 0x11, 0x61, 0x58, 0x85, 0x58, 0x38, 0x71, 0x83, 0x80, 0x67, 0x01, 0x65, 0x78, 0x70, 0x64, 0x77, 0x85, 0x60, 0x02, 0x88, 0x53, 0x48, 0x46, 0x62, 0x25, 0x83, 0x54, 0x88, 0x04, 0x74, 0x40, 0x12, 0x57, 0x43, 0x71, 0x07, 0x75, 0x44, 0x38, 0x71, 0x21, 0x14, 0x22, 0x08, 0x88, 0x72, 0x23, 0x58, 0x87, 0x46, 0x14, 0x85, 0x53, 0x71, 0x67, 0x73, 0x82, 0x28, 0x22, 0x74, 0x14, 0x03, 0x57, 0x73, 0x28, 0x71, 0x83, 0x80, 0x78, 0x14, 0x34, 0x87, 0x52, 0x07, 0x64, 0x74, 0x01, 0x60, 0x75, 0x61, 0x06, 0x08, 0x61, 0x32, 0x21, 0x46, 0x15, 0x65, 0x42, 0x67, 0x08, 0x20, 0x84, 0x10, 0x73, 0x13, 0x03, 0x61, 0x02, 0x86, 0x50, 0x45, 0x26, 0x12, 0x16, 0x68, 0x33, 0x55, 0x25, 0x84, 0x73, 0x53, 0x54, 0x52, 0x65, 0x17, 0x10, 0x60, 0x00, 0x38, 0x57, 0x77, 0x81, 0x24, 0x26, 0x80, 0x41, 0x46, 0x43, 0x26, 0x67, 0x41, 0x06, 0x03, 0x55, 0x41, 0x28, 0x33, 0x37, 0x25, 0x23, 0x06, 0x77, 0x82, 0x15, 0x16, 0x31, 0x73, 0x00, 0x08, 0x75, 0x26, 0x58, 0x46, 0x34, 0x63, 0x88, 0x08, 0x84, 0x64, 0x51, 0x11, 0x24, 0x05, 0x32, 0x10, 0x11, 0x18, 0x18, 0x64, 0x78, 0x22, 0x41, 0x00, 0x38, 0x55, 0x75, 0x42, 0x10, 0x46, 0x83, 0x43, 0x73, 0x38, 0x80, 0x07, 0x83, 0x43, 0x78, 0x74, 0x13, 0x57, 0x62, 0x32, 0x68, 0x80, 0x65, 0x86, 0x48, 0x53, 0x48, 0x35, 0x51, 0x58, 0x50, 0x74, 0x46, 0x05, 0x88, 0x70, 0x07, 0x72, 0x01, 0x31, 0x00, 0x87, 0x54, 0x88, 0x14, 0x20, 0x84, 0x16, 0x61, 0x15, 0x60, 0x56, 0x85, 0x11, 0x58, 0x08, 0x05, 0x88, 0x63, 0x01, 0x82, 0x86, 0x13, 0x14, 0x17, 0x22, 0x01, 0x68, 0x17, 0x17, 0x86, 0x58, 0x53, 0x10, 0x62, 0x28, 0x52, 0x82, 0x26, 0x15, 0x04, 0x31, 0x42, 0x88, 0x54, 0x31, 0x78, 0x05, 0x80, 0x11, 0x50, 0x45, 0x68, 0x82, 0x33, 0x66, 0x36, 0x36, 0x40, 0x65, 0x15, 0x24, 0x47, 0x67, 0x06, 0x45, 0x36, 0x42, 0x26, 0x86, 0x75, 0x06, 0x35, 0x41, 0x33, 0x47, 0x85, 0x12, 0x17, 0x80, 0x83, 0x87, 0x65, 0x51, 0x42, 0x31, 0x38, 0x87, 0x56, 0x62, 0x05, 0x17, 0x40, 0x85, 0x28, 0x14, 0x17, 0x21, 0x38, 0x12, 0x60, 0x81, 0x24, 0x41, 0x45, 0x75, 0x01, 0x82, 0x87, 0x10, 0x10, 0x02, 0x13, 0x25, 0x57, 0x04, 0x21, 0x72, 0x42, 0x78, 0x61, 0x11, 0x70, 0x05, 0x30, 0x47, 0x72, 0x13, 0x20, 0x30, 0x21, 0x67, 0x44, 0x31, 0x57, 0x71, 0x45, 0x57, 0x10, 0x54, 0x16, 0x65, 0x74, 0x15, 0x24, 0x02, 0x43, 0x71, 0x51, 0x20, 0x55, 0x11, 0x67, 0x83, 0x67, 0x82, 0x52, 0x53, 0x35, 0x66, 0x42, 0x46, 0x13, 0x70, 0x22, 0x32, 0x74, 0x00, 0x07, 0x06, 0x81, 0x87, 0x17, 0x57, 0x80, 0x28, 0x68, 0x01, 0x72, 0x10, 0x04, 0x27, 0x55, 0x22, 0x86, 0x42, 0x53, 0x15, 0x81, 0x76, 0x30, 0x86, 0x40, 0x83, 0x11, 0x43, 0x30, 0x53, 0x82, 0x73, 0x53, 0x03, 0x72, 0x35, 0x68, 0x70, 0x45, 0x41, 0x15, 0x73, 0x14, 0x12, 0x31, 0x64, 0x32, 0x66, 0x63, 0x56, 0x21, 0x51, 0x50, 0x82, 0x10, 0x30, 0x23, 0x38, 0x17, 0x21, 0x27, 0x10, 0x23, 0x14, 0x22, 0x75, 0x77, 0x28, 0x37, 0x71, 0x62, 0x75, 0x06, 0x88, 0x72, 0x14, 0x18, 0x73, 0x13, 0x03, 0x01, 0x50, 0x71, 0x58, 0x62, 0x86, 0x62, 0x88, 0x86, 0x86, 0x03, 0x27, 0x01, 0x46, 0x17, 0x22, 0x71, 0x38, 0x53, 0x81, 0x70, 0x33, 0x88, 0x68, 0x13, 0x78, 0x81, 0x04, 0x86, 0x57, 0x30, 0x16, 0x52, 0x31, 0x40, 0x83, 0x07, 0x56, 0x82, 0x10, 0x32, 0x31, 0x28, 0x50, 0x06, 0x50, 0x81, 0x63, 0x06, 0x75, 0x76, 0x65, 0x11, 0x60, 0x14, 0x17, 0x12, 0x12, 0x55, 0x56, 0x48, 0x11, 0x41, 0x13, 0x28, 0x82, 0x62, 0x07, 0x47, 0x64, }, .s1_len = 640, .s2 = { 0x24, 0x48, 0x23, 0x24, 0x77, 0x53, 0x26, 0x08, 0x17, 0x58, 0x11, 0x56, 0x37, 0x48, 0x35, 0x51, 0x47, 0x86, 0x85, 0x66, 0x66, 0x81, 0x73, 0x20, 0x21, 0x36, 0x75, 0x22, 0x74, 0x66, 0x83, 0x44, 0x57, 0x00, 0x66, 0x64, 0x77, 0x20, 0x47, 0x22, 0x28, 0x56, 0x87, 0x12, 0x47, 0x02, 0x48, 0x07, 0x02, 0x54, 0x23, 0x01, 0x25, 0x71, 0x37, 0x36, 0x75, 0x36, 0x00, 0x52, 0x68, 0x15, 0x33, 0x35, 0x82, 0x06, 0x13, 0x73, 0x24, 0x08, 0x71, 0x76, 0x15, 0x22, 0x42, 0x60, 0x18, 0x53, 0x43, 0x11, 0x64, 0x57, 0x76, 0x17, 0x61, 0x56, 0x68, 0x76, 0x60, 0x65, 0x54, 0x78, 0x10, 0x33, 0x63, 0x14, 0x21, 0x83, 0x21, 0x60, 0x15, 0x55, 0x80, 0x42, 0x38, 0x42, 0x03, 0x13, 0x12, 0x34, 0x36, 0x25, 0x27, 0x30, 0x82, 0x81, 0x25, 0x47, 0x51, 0x35, 0x44, 0x12, 0x67, 0x35, 0x00, 0x10, 0x01, 0x83, 0x85, 0x74, 0x42, 0x40, 0x13, 0x03, 0x61, 0x27, 0x81, 0x26, 0x26, 0x81, 0x18, 0x87, 0x43, 0x51, 0x20, 0x62, 0x71, 0x27, 0x51, 0x56, 0x10, 0x22, 0x22, 0x81, 0x11, 0x81, 0x41, 0x66, 0x66, 0x38, 0x20, 0x86, 0x75, 0x56, 0x12, 0x40, 0x06, 0x54, 0x61, 0x12, 0x74, 0x40, 0x34, 0x58, 0x58, 0x78, 0x10, 0x07, 0x85, 0x25, 0x72, 0x88, 0x57, 0x22, 0x22, 0x25, 0x50, 0x84, 0x00, 0x41, 0x26, 0x08, 0x36, 0x46, 0x28, 0x78, 0x46, 0x78, 0x05, 0x02, 0x28, 0x20, 0x77, 0x13, 0x60, 0x75, 0x14, 0x43, 0x68, 0x78, 0x64, 0x31, 0x38, 0x77, 0x73, 0x73, 0x55, 0x41, 0x27, 0x00, 0x54, 0x07, 0x08, 0x28, 0x68, 0x80, 0x04, 0x53, 0x83, 0x43, 0x22, 0x81, 0x00, 0x64, 0x35, 0x48, 0x67, 0x66, 0x50, 0x17, 0x75, 0x76, 0x12, 0x75, 0x43, 0x81, 0x62, 0x40, 0x33, 0x43, 0x45, 0x38, 0x87, 0x21, 0x66, 0x14, 0x70, 0x48, 0x41, 0x43, 0x14, 0x66, 0x58, 0x78, 0x45, 0x82, 0x02, 0x25, 0x45, 0x73, 0x15, 0x21, 0x32, 0x03, 0x02, 0x48, 0x80, 0x80, 0x13, 0x71, 0x25, 0x54, 0x32, 0x72, 0x05, 0x68, 0x65, 0x24, 0x68, 0x04, 0x06, 0x16, 0x83, 0x50, 0x54, 0x53, 0x37, 0x37, 0x27, 0x22, 0x20, 0x68, 0x08, 0x25, 0x50, 0x84, 0x72, 0x86, 0x74, 0x22, 0x36, 0x16, 0x80, 0x07, 0x55, 0x18, 0x12, 0x17, 0x84, 0x44, 0x81, 0x15, 0x64, 0x50, 0x71, 0x10, 0x58, 0x15, 0x51, 0x10, 0x10, 0x47, 0x16, 0x21, 0x07, 0x58, 0x61, 0x18, 0x78, 0x00, 0x52, 0x72, 0x64, 0x52, 0x17, 0x43, 0x23, 0x40, 0x76, 0x48, 0x67, 0x30, 0x77, 0x63, 0x64, 0x87, 0x51, 0x31, 0x63, 0x84, 0x68, 0x74, 0x53, 0x63, 0x84, 0x23, 0x54, 0x66, 0x10, 0x48, 0x36, 0x33, 0x85, 0x21, 0x48, 0x42, 0x03, 0x82, 0x51, 0x10, 0x33, 0x57, 0x46, 0x80, 0x16, 0x43, 0x34, 0x02, 0x07, 0x03, 0x53, 0x22, 0x12, 0x75, 0x73, 0x34, 0x65, 0x83, 0x33, 0x87, 0x43, 0x85, 0x17, 0x50, 0x36, 0x60, 0x88, 0x02, 0x58, 0x75, 0x80, 0x88, 0x31, 0x63, 0x60, 0x18, 0x21, 0x32, 0x26, 0x15, 0x68, 0x74, 0x11, 0x10, 0x33, 0x14, 0x13, 0x05, 0x34, 0x16, 0x72, 0x65, 0x35, 0x50, 0x13, 0x34, 0x80, 0x87, 0x10, 0x26, 0x48, 0x68, 0x84, 0x52, 0x71, 0x44, 0x23, 0x58, 0x80, 0x35, 0x57, 0x70, 0x54, 0x84, 0x28, 0x70, 0x55, 0x88, 0x86, 0x83, 0x86, 0x25, 0x21, 0x82, 0x72, 0x61, 0x17, 0x78, 0x85, 0x17, 0x67, 0x73, 0x00, 0x57, 0x71, 0x11, 0x78, 0x51, 0x10, 0x65, 0x63, 0x57, 0x02, 0x87, 0x40, 0x13, 0x40, 0x01, 0x26, 0x53, 0x45, 0x12, 0x05, 0x46, 0x75, 0x18, 0x80, 0x70, 0x33, 0x35, 0x66, 0x22, 0x62, 0x00, 0x70, 0x23, 0x26, 0x87, 0x72, 0x63, 0x11, 0x13, 0x33, 0x33, 0x81, 0x41, 0x70, 0x62, 0x28, 0x61, 0x51, 0x47, 0x31, 0x30, 0x25, 0x46, 0x51, 0x17, 0x61, 0x58, 0x07, 0x41, 0x61, 0x37, 0x37, 0x06, 0x14, 0x00, 0x54, 0x88, 0x77, 0x75, 0x67, 0x77, 0x66, 0x53, 0x16, 0x72, 0x66, 0x66, 0x88, 0x76, 0x43, 0x58, 0x31, 0x04, 0x87, 0x57, 0x06, 0x76, 0x47, 0x00, 0x43, 0x63, 0x58, 0x60, 0x52, 0x03, 0x44, 0x27, 0x36, 0x48, 0x61, 0x23, 0x72, 0x16, 0x10, 0x62, 0x42, 0x08, 0x60, 0x83, 0x23, 0x54, 0x03, 0x55, 0x55, 0x73, 0x00, 0x61, 0x03, 0x65, 0x34, 0x27, 0x14, 0x15, 0x86, 0x62, 0x55, 0x80, 0x16, 0x53, 0x10, 0x18, 0x26, 0x11, 0x35, 0x46, 0x82, 0x46, 0x13, 0x25, 0x83, 0x47, 0x70, 0x50, 0x06, 0x01, 0x56, 0x02, 0x11, 0x68, 0x54, 0x53, 0x03, 0x68, 0x73, 0x36, 0x41, 0x88, 0x86, 0x33, 0x42, 0x52, 0x01, 0x58, 0x33, 0x42, 0x32, 0x88, 0x56, 0x81, 0x77, 0x55, 0x51, 0x48, 0x48, 0x12, 0x01, 0x58, 0x13, 0x85, 0x04, 0x14, 0x71, 0x83, 0x57, 0x07, 0x54, 0x55, 0x54, 0x55, 0x28, 0x27, 0x31, 0x36, 0x02, 0x12, 0x32, 0x68, 0x32, 0x13, 0x82, 0x58, 0x70, 0x28, 0x58, 0x53, 0x44, 0x86, 0x72, 0x73, 0x42, 0x84, 0x18, 0x22, 0x08, 0x83, 0x61, 0x02, 0x14, 0x16, 0x17, 0x12, 0x41, 0x57, 0x48, 0x85, 0x25, 0x10, 0x26, 0x07, 0x36, 0x76, 0x12, 0x66, 0x17, 0x21, 0x32, 0x36, 0x03, 0x25, 0x41, 0x10, 0x11, 0x22, 0x66, 0x60, 0x16, 0x16, 0x32, 0x64, 0x26, 0x05, 0x18, 0x63, 0x51, 0x58, 0x51, 0x31, 0x42, 0x53, 0x84, 0x56, 0x66, 0x27, 0x83, 0x33, 0x54, 0x50, 0x76, 0x46, 0x50, 0x80, 0x25, 0x43, 0x41, 0x57, 0x35, 0x78, 0x25, 0x43, 0x02, 0x82, 0x38, 0x47, 0x45, 0x70, 0x15, 0x67, 0x51, 0x77, 0x47, 0x80, 0x31, 0x52, 0x75, 0x00, }, .s2_len = 768, .t0 = { 0x00, 0x94, 0x7b, 0xca, 0x93, 0xc2, 0x7d, 0x58, 0x4e, 0x2c, 0x66, 0xea, 0xc9, 0xc7, 0x64, 0x0c, 0x1c, 0xa2, 0x17, 0xee, 0xf6, 0x6d, 0xab, 0xbc, 0xb2, 0x60, 0xb4, 0xc3, 0x43, 0x00, 0xfa, 0x05, 0x13, 0x57, 0x82, 0x0f, 0x57, 0x39, 0x25, 0x44, 0x98, 0x2f, 0xd1, 0x10, 0x57, 0xde, 0x23, 0x3e, 0x6d, 0x2d, 0xd8, 0x49, 0x72, 0xa7, 0xe4, 0x7d, 0x4d, 0xba, 0x99, 0xbc, 0x30, 0xcf, 0x8f, 0x2a, 0xd5, 0xa2, 0xc0, 0x24, 0x31, 0x95, 0xed, 0x27, 0x30, 0xff, 0xa9, 0x2d, 0x22, 0x7d, 0x15, 0x30, 0x95, 0x97, 0x2d, 0x4b, 0x34, 0x47, 0xff, 0xac, 0x45, 0xa2, 0x3e, 0xb4, 0x1c, 0xbc, 0x87, 0xcd, 0xd1, 0x25, 0x0a, 0x8a, 0x47, 0x8b, 0x0f, 0x7a, 0x1d, 0x5b, 0x39, 0xaa, 0x22, 0x06, 0xe4, 0x86, 0x45, 0x58, 0x4f, 0xe7, 0xbf, 0x7a, 0x13, 0x16, 0x8f, 0x48, 0x27, 0x65, 0xe5, 0x7b, 0xb9, 0x24, 0xac, 0x6d, 0x9a, 0x11, 0x36, 0x9f, 0x4a, 0x6a, 0xff, 0xcd, 0x16, 0x9b, 0x7d, 0x75, 0x12, 0x9b, 0x35, 0xd5, 0x13, 0x4a, 0x31, 0x76, 0x1b, 0xb8, 0x35, 0x5a, 0xee, 0xed, 0x27, 0xe2, 0x01, 0xa0, 0x63, 0x13, 0x01, 0x3e, 0x30, 0x7a, 0x01, 0xa7, 0x3a, 0xea, 0x79, 0x55, 0xc0, 0x57, 0x8c, 0x8c, 0x5e, 0x5a, 0x1a, 0x2d, 0x2f, 0xa4, 0x59, 0x3f, 0xac, 0xd9, 0x04, 0xc6, 0x20, 0x40, 0xbd, 0xb9, 0xf3, 0x29, 0x93, 0x35, 0x36, 0xbf, 0x8d, 0x81, 0xc4, 0x25, 0x6b, 0xaa, 0xe8, 0x72, 0x3f, 0xd4, 0xdc, 0x66, 0xbb, 0x5e, 0x7f, 0x9c, 0xa4, 0x90, 0x31, 0xa1, 0x93, 0xec, 0xec, 0xbb, 0x5d, 0xc3, 0x90, 0xec, 0x6d, 0x55, 0x13, 0xc7, 0x9a, 0x05, 0x2b, 0x3f, 0xd4, 0x36, 0x12, 0xfb, 0x73, 0x75, 0x31, 0x5d, 0x80, 0x91, 0xf7, 0x9b, 0xab, 0x13, 0x18, 0xf1, 0x78, 0x54, 0x56, 0x1b, 0xc9, 0x3a, 0xe0, 0xe5, 0xcd, 0x6d, 0x13, 0x1e, 0x56, 0x2c, 0x81, 0x14, 0x81, 0x0c, 0x93, 0x9a, 0xe5, 0x63, 0xaa, 0x10, 0xb4, 0x7c, 0xe4, 0x48, 0x43, 0x17, 0xf3, 0x4a, 0xbd, 0x02, 0xd0, 0xcc, 0xad, 0x58, 0xdd, 0x29, 0xbc, 0xf6, 0x57, 0xbb, 0xd9, 0x25, 0x4b, 0x01, 0xca, 0x97, 0x26, 0x09, 0x19, 0x38, 0xed, 0x32, 0x05, 0x4b, 0x37, 0xdd, 0x61, 0x72, 0x40, 0xf4, 0x43, 0x4c, 0x1a, 0x4a, 0x87, 0x11, 0xaa, 0x3a, 0x39, 0x9a, 0x8a, 0x53, 0x88, 0x33, 0x0b, 0x70, 0x59, 0xec, 0xcb, 0xb6, 0xb1, 0xb9, 0xcf, 0x71, 0x87, 0xad, 0xf1, 0x0b, 0x0c, 0x91, 0x71, 0xd3, 0xc0, 0xf6, 0xe2, 0xd4, 0x60, 0xa4, 0x19, 0x24, 0x76, 0x72, 0xe3, 0xb9, 0xfe, 0xa2, 0xc9, 0x59, 0x10, 0xbf, 0x2f, 0xb6, 0xa5, 0xd6, 0x1f, 0x25, 0x74, 0x53, 0xb0, 0x7a, 0xfb, 0x64, 0xb0, 0xba, 0x27, 0x58, 0xbc, 0xd7, 0x35, 0x75, 0x1f, 0x2d, 0x53, 0x51, 0x5e, 0x23, 0x6f, 0xe8, 0xa5, 0xb4, 0x39, 0x3b, 0x80, 0xbf, 0x06, 0xdf, 0x97, 0xbd, 0xc6, 0x38, 0x00, 0x87, 0xe6, 0xaa, 0x8d, 0xde, 0x6e, 0x09, 0x81, 0x11, 0xa7, 0x34, 0x3f, 0xcd, 0xd1, 0xe9, 0x03, 0x70, 0x8e, 0x63, 0x7e, 0xbf, 0x28, 0x32, 0x3c, 0xda, 0x6b, 0x94, 0x05, 0x81, 0x0e, 0xdc, 0xfb, 0x36, 0x91, 0x14, 0x9e, 0xcf, 0x22, 0x4c, 0x50, 0xf8, 0xdf, 0x92, 0xa9, 0x4a, 0xa4, 0x77, 0x0a, 0x0e, 0x91, 0x46, 0x61, 0x94, 0xbb, 0x0e, 0x27, 0xbf, 0x1c, 0xab, 0xf1, 0x6a, 0xdf, 0xd3, 0x51, 0x22, 0x00, 0x33, 0xf7, 0x6f, 0x59, 0x25, 0x55, 0x7b, 0xcf, 0x96, 0x34, 0xe9, 0x46, 0x13, 0x59, 0x62, 0x1d, 0x80, 0xb4, 0xbb, 0xad, 0x7e, 0x2a, 0x6e, 0x43, 0x2d, 0xc4, 0x3b, 0x12, 0x6c, 0xa4, 0x2a, 0xb8, 0x8a, 0xa8, 0x8f, 0x0a, 0x84, 0xaf, 0x58, 0x02, 0x9c, 0x99, 0xa0, 0x24, 0x8f, 0x0c, 0x45, 0x40, 0x71, 0xf3, 0x5b, 0x83, 0x1f, 0xed, 0x12, 0x54, 0xd6, 0xf4, 0xe2, 0x72, 0x04, 0x85, 0x78, 0x62, 0x15, 0xf7, 0xc7, 0xf0, 0xc4, 0xed, 0x15, 0xfa, 0x85, 0x3c, 0xd3, 0xaa, 0x07, 0x25, 0x9b, 0x39, 0x24, 0x0a, 0x82, 0x13, 0x5c, 0x29, 0x23, 0xa7, 0x2b, 0x87, 0x6f, 0xab, 0xb3, 0xf0, 0xf2, 0xc0, 0x96, 0x13, 0xde, 0x39, 0xd4, 0x59, 0xa0, 0x7c, 0x14, 0xe7, 0xba, 0x43, 0x7d, 0x80, 0x41, 0x49, 0x1f, 0xce, 0xc1, 0x43, 0x34, 0x04, 0xba, 0xd1, 0xda, 0x9e, 0xe9, 0x47, 0x1e, 0x17, 0xcb, 0x69, 0x1b, 0x2a, 0x35, 0x37, 0x10, 0xc9, 0xff, 0xa4, 0xe5, 0x17, 0x81, 0x12, 0x02, 0x77, 0x64, 0xeb, 0x7d, 0xe8, 0x09, 0xc3, 0xe1, 0xf1, 0xfa, 0x41, 0x78, 0xa5, 0xd4, 0xdc, 0x9e, 0xe2, 0x78, 0x57, 0xef, 0xf2, 0x6b, 0x91, 0x71, 0x1f, 0xc1, 0x44, 0xd5, 0xa7, 0x75, 0xb8, 0xb5, 0x0d, 0x5d, 0xb9, 0x39, 0xba, 0x32, 0x07, 0x68, 0x0c, 0x24, 0x2f, 0xc8, 0x21, 0x94, 0x7f, 0x93, 0x4c, 0x8d, 0xae, 0xe2, 0x03, 0x56, 0x3d, 0x28, 0x60, 0x6b, 0xe6, 0x24, 0xa3, 0x29, 0x01, 0x93, 0x2d, 0xae, 0x85, 0x71, 0x2a, 0xf6, 0xc8, 0x01, 0x60, 0x26, 0x92, 0x7e, 0x9b, 0x81, 0x29, 0x57, 0x4b, 0xe3, 0xcb, 0x1e, 0x95, 0x33, 0x2b, 0x05, 0x27, 0x07, 0xac, 0x8a, 0xa8, 0xf4, 0x35, 0xe8, 0x8b, 0x7e, 0x56, 0x8d, 0x49, 0x87, 0xc6, 0xac, 0x0e, 0x90, 0x2b, 0x06, 0x09, 0xa0, 0x2d, 0x91, 0xb3, 0xf5, 0xfd, 0x3f, 0xd9, 0x01, 0xdd, 0xd0, 0xdb, 0x98, 0x73, 0xbd, 0x7c, 0x71, 0xed, 0x92, 0x1d, 0x45, 0x77, 0xa7, 0x8c, 0x4f, 0xcc, 0x9b, 0xf0, 0x75, 0x20, 0x3d, 0x38, 0xf5, 0xe7, 0x6e, 0x74, 0xf2, 0x77, 0x48, 0x4e, 0x05, 0x7b, 0x61, 0x89, 0x00, 0x41, 0x31, 0xb0, 0xc9, 0xb1, 0xa1, 0x55, 0x29, 0x4d, 0x1c, 0xd3, 0xd5, 0x20, 0x8e, 0x26, 0x69, 0x01, 0xd7, 0xd3, 0x14, 0xfa, 0xcc, 0xe7, 0xe2, 0xaa, 0x58, 0x45, 0x83, 0xa1, 0x1e, 0x4d, 0x7c, 0x21, 0xb9, 0x4a, 0x32, 0xe5, 0x08, 0xed, 0xdb, 0xbd, 0x7a, 0x65, 0xaa, 0x86, 0xb4, 0xfd, 0xfa, 0x6b, 0xc2, 0x85, 0xd4, 0xcf, 0xf5, 0x39, 0x26, 0xc7, 0x17, 0x3f, 0xbe, 0x1f, 0x89, 0xcc, 0x30, 0x32, 0x34, 0xb8, 0x78, 0xc6, 0xb8, 0x10, 0x1f, 0x58, 0xac, 0x8d, 0x3e, 0x5e, 0x1b, 0xf5, 0xab, 0x6b, 0x26, 0x29, 0x7c, 0xc9, 0x7b, 0x95, 0x95, 0x4a, 0xab, 0xdb, 0x25, 0xbe, 0x00, 0x8a, 0x3f, 0x47, 0xe5, 0x64, 0x87, 0xb0, 0x0d, 0x3d, 0xed, 0xa8, 0x90, 0xd9, 0x2c, 0x83, 0x95, 0x7f, 0xea, 0xc6, 0xb8, 0x29, 0x1a, 0xf6, 0x59, 0x59, 0xe1, 0xd1, 0xfc, 0xa3, 0xbd, 0x19, 0x6e, 0x9f, 0xc9, 0xe6, 0x7e, 0x06, 0x07, 0x09, 0x48, 0x22, 0xe5, 0xb4, 0x19, 0x1d, 0xb9, 0x68, 0x24, 0xb9, 0xf0, 0x3f, 0x2e, 0xf5, 0x7f, 0x52, 0x38, 0xba, 0x7e, 0x1e, 0x84, 0xed, 0x55, 0xb7, 0xdf, 0xf3, 0xd6, 0xc2, 0xc1, 0x27, 0x36, 0x92, 0xa9, 0xa1, 0x92, 0x72, 0x16, 0x61, 0x30, 0xdb, 0x89, 0xfc, 0x67, 0xdc, 0x94, 0xdb, 0x61, 0x4e, 0x3e, 0x82, 0xba, 0x3a, 0x35, 0x12, 0xb0, 0x12, 0xd5, 0x1f, 0xb4, 0x86, 0xb5, 0xa3, 0x15, 0x0b, 0x78, 0xe7, 0x24, 0xe2, 0xa1, 0x2d, 0xe0, 0x7d, 0x86, 0x71, 0xfb, 0xa2, 0xda, 0x7f, 0xd5, 0xd1, 0x47, 0x20, 0x8f, 0xc3, 0xaf, 0x65, 0x3e, 0x65, 0x20, 0xfc, 0x40, 0x87, 0x1a, 0xf2, 0x17, 0x7e, 0x65, 0xcb, 0xd0, 0xea, 0xf3, 0x04, 0x21, 0x7b, 0x36, 0x7a, 0x66, 0x5f, 0x22, 0x4c, 0xae, 0xdf, 0xe9, 0x30, 0x06, 0xac, 0x1e, 0x14, 0xbc, 0xd6, 0x7a, 0x88, 0xd1, 0x71, 0xf3, 0xd8, 0xf3, 0xe3, 0x58, 0xa7, 0x19, 0x26, 0xba, 0x3e, 0x5c, 0x23, 0x9a, 0x53, 0x12, 0x63, 0xec, 0x94, 0x37, 0xbf, 0x2a, 0x03, 0x3b, 0x8b, 0x55, 0xb2, 0xc0, 0xcb, 0x6e, 0x7e, 0x97, 0x31, 0x6e, 0x22, 0xdf, 0x77, 0xca, 0xd9, 0x10, 0xd2, 0x0e, 0xec, 0xe1, 0xc5, 0x09, 0x10, 0xa5, 0xcc, 0x32, 0xad, 0xab, 0x09, 0x37, 0x75, 0x50, 0xf9, 0x2d, 0x5b, 0xb1, 0xf4, 0xc0, 0x7f, 0x4a, 0x28, 0x22, 0x33, 0x8e, 0x2c, 0xff, 0x53, 0x48, 0xdf, 0x77, 0xcf, 0x8e, 0xf8, 0xe6, 0x65, 0x7d, 0xed, 0x1e, 0x0c, 0xe0, 0x58, 0xe3, 0xcc, 0xfb, 0xf3, 0x9b, 0x3f, 0x16, 0x6e, 0x30, 0x3d, 0x33, 0xc3, 0x55, 0x6c, 0x9a, 0xc8, 0xec, 0xb3, 0xdf, 0x7c, 0x74, 0xab, 0x36, 0xd0, 0xf2, 0x79, 0x44, 0x41, 0xba, 0x98, 0x08, 0x82, 0x7b, 0x57, 0x8f, 0xb5, 0xc2, 0x9e, 0x49, 0x4e, 0x21, 0x53, 0x9a, 0xd3, 0xab, 0x2b, 0x41, 0xbf, 0x16, 0x1d, 0x7f, 0x69, 0x58, 0x9d, 0x45, 0x24, 0xc5, 0x4c, 0x89, 0xb4, 0x86, 0xf7, 0x5d, 0x25, 0x2f, 0x54, 0x1c, 0xc6, 0x3b, 0x9e, 0x70, 0x6d, 0x64, 0xa1, 0x28, 0x9a, 0x23, 0x06, 0xc5, 0x95, 0x36, 0x3c, 0xb6, 0xfb, 0xef, 0x0a, 0x1b, 0x5b, 0x17, 0xab, 0x5b, 0x17, 0x94, 0xbf, 0x27, 0x03, 0x6f, 0x64, 0xea, 0xf0, 0xbd, 0x43, 0x0d, 0xd5, 0x8d, 0x80, 0x01, 0x0c, 0xcd, 0xad, 0xa4, 0xa5, 0xa3, 0xa1, 0xe4, 0x1a, 0x6f, 0xbf, 0x12, 0x9d, 0x73, 0x77, 0x9a, 0x37, 0xae, 0x5c, 0x8d, 0x68, 0x41, 0xa9, 0x99, 0x3c, 0x51, 0xe3, 0x64, 0xe0, 0x4f, 0xac, 0x8e, 0x25, 0xa4, 0xe6, 0x87, 0x2f, 0x6c, 0x86, 0x0f, 0xa2, 0x65, 0xc1, 0xc4, 0x42, 0x6a, 0xd9, 0xc2, 0x1d, 0x26, 0xda, 0x8c, 0x27, 0x85, 0x46, 0xad, 0xcd, 0x83, 0x1f, 0x2b, 0x8b, 0x26, 0xd4, 0xe1, 0xf6, 0x70, 0x62, 0x3d, 0x95, 0xc8, 0x36, 0x2d, 0xa6, 0x62, 0xd1, 0xff, 0x0a, 0xb6, 0x87, 0x50, 0x3f, 0x32, 0x8d, 0xe0, 0x95, 0x81, 0x0e, 0xde, 0x12, 0xb4, 0x9e, 0xad, 0x15, 0x33, 0x51, 0x95, 0x58, 0xc1, 0xe9, 0x40, 0xb4, 0x6e, 0x4e, 0xdb, 0x02, 0x7b, 0xe9, 0xda, 0x20, 0x39, 0xb2, 0x5d, 0xcf, 0x73, 0x57, 0xe1, 0x9e, 0x54, 0x16, 0xae, 0x26, 0x8c, 0x14, 0xfb, 0x3a, 0x8b, 0xab, 0xcb, 0x3d, 0x23, 0xf7, 0x0c, 0xc9, 0xd5, 0x96, 0x81, 0xc5, 0xd8, 0x33, 0xac, 0x22, 0xe6, 0x53, 0xd8, 0x6e, 0x22, 0xce, 0x82, 0x25, 0x40, 0x75, 0x5d, 0x8d, 0x24, 0x3c, 0x15, 0x21, 0x3d, 0x07, 0x6c, 0x6b, 0x26, 0x43, 0x6d, 0xdc, 0x07, 0xc7, 0xe0, 0x01, 0x34, 0x7b, 0x0c, 0xb8, 0x78, 0x3d, 0xfe, 0xfe, 0xdf, 0x27, 0x5f, 0xec, 0x47, 0x92, 0x68, 0x67, 0x34, 0x00, 0x7f, 0x0f, 0xf8, 0x54, 0x08, 0x11, 0xc2, 0xaf, 0xe6, 0xca, 0x15, 0x14, 0x20, 0x53, 0x2f, 0xa5, 0x52, 0x6a, 0x10, 0x74, 0xc3, 0xd7, 0x89, 0xf2, 0x93, 0x2d, 0xe4, 0x2e, 0x3a, 0xcf, 0xbf, 0x94, 0x76, 0x0f, 0x42, 0x6d, 0x96, 0xcf, 0x03, 0x3f, 0xa4, 0x9e, 0x2f, 0x45, 0x8f, 0x9a, 0x9c, 0x2e, 0x71, 0xda, 0xcf, 0xe0, 0x09, 0xdd, 0x9c, 0x3f, 0x3c, 0x8a, 0xb3, 0x28, 0x2d, 0x6f, 0x38, 0x3b, 0x98, 0x1c, 0x82, 0xd6, 0x36, 0x4f, 0x0e, 0x4b, 0xdb, 0x2a, 0xf6, 0xa9, 0x5b, 0xa6, 0x1f, 0x47, 0x41, 0x50, 0xca, 0xd7, 0x23, 0x3f, 0x89, 0x03, 0xdf, 0x97, 0x2d, 0xbb, 0x03, 0x28, 0xc0, 0xcb, 0x9d, 0x0c, 0xcb, 0xef, 0x88, 0x3d, 0x2e, 0x6a, 0xdd, 0x18, 0x0e, 0xca, 0x1b, 0x66, 0x2f, 0xc1, 0xd2, 0xdb, 0xbd, 0xdb, 0x36, 0x34, 0x21, 0x9e, 0x1e, 0xff, 0x38, 0xb1, 0xe5, 0x28, 0x75, 0x35, 0x6c, 0x03, 0xea, 0xde, 0x94, 0x20, 0x55, 0xf4, 0x83, 0x50, 0x4b, 0xbb, 0xcb, 0x43, 0x02, 0xa4, 0x17, 0xcf, 0x6d, 0x32, 0x8e, 0xd7, 0x93, 0xb1, 0xa3, 0xc0, 0x96, 0x9b, 0x7b, 0x34, 0x18, 0xf5, 0x0a, 0xb3, 0x9f, 0x83, 0xc5, 0x66, 0x6c, 0x90, 0xe3, 0x83, 0x56, 0xf7, 0xf9, 0xd4, 0x94, 0xa6, 0xdc, 0xb6, 0x3d, 0x67, 0xc3, 0x4e, 0x3d, 0x14, 0xa4, 0xe1, 0x55, 0x96, 0x49, 0x79, 0x26, 0xc8, 0x56, 0x8d, 0x8e, 0xc3, 0xdb, 0xd9, 0xc2, 0xe8, 0x2c, 0x38, 0x5b, 0xcf, 0xb8, 0xd9, 0x67, 0x48, 0x63, 0xbd, 0x4f, 0xbf, 0x17, 0x57, 0xdb, 0x44, 0x7b, 0xf8, 0x04, 0xae, 0x95, 0x01, 0x47, 0xc9, 0x1f, 0xbf, 0x9a, 0xa1, 0x78, 0x91, 0x04, 0x4c, 0xca, 0xa7, 0x3b, 0x45, 0x52, 0x85, 0x97, 0x46, 0x2c, 0xed, 0x75, 0x1d, 0x01, 0x5e, 0xbb, 0xa9, 0xe2, 0xb7, 0xcd, 0xcb, 0xe6, 0xdc, 0x05, 0xaa, 0x9e, 0xae, 0x0c, 0x86, 0x84, 0x8a, 0x34, 0x75, 0xbb, 0x1c, 0x57, 0x44, 0xf5, 0x90, 0x3e, 0xe4, 0xa8, 0x42, 0xa4, 0x69, 0xcc, 0x18, 0x12, 0x71, 0xf2, 0x45, 0xad, 0x70, 0xd0, 0x2a, 0x48, 0x37, 0x86, 0x3b, 0x29, 0x6b, 0x4a, 0xdb, 0x4e, 0x8d, 0x03, 0xd8, 0x2b, 0x64, 0xaa, 0x11, 0xdd, 0x31, 0xcd, 0xf2, 0x1e, 0xdf, 0x1d, 0xfe, 0x32, 0x76, 0xc4, 0xdb, 0xc8, 0x77, 0xe3, 0x5b, 0x15, 0xfb, 0x28, 0x35, 0xec, 0x3a, 0x1c, 0x45, 0x31, 0x68, 0xa3, 0x8c, 0xa8, 0xe5, 0x63, 0xcf, 0x3e, 0x9a, 0x00, 0x73, 0x6c, 0xd5, 0xcf, 0xbd, 0x28, 0x41, 0xd1, 0x0f, 0x94, 0xad, 0x55, 0x79, 0x9c, 0x29, 0x27, 0xe5, 0x46, 0x1b, 0x28, 0xba, 0xc5, 0x17, 0x4d, 0x0c, 0xe3, 0xf8, 0xf7, 0xcd, 0x76, 0x09, 0xfb, 0xc8, 0xda, 0x0c, 0x38, 0xcc, 0x21, 0x69, 0x5c, 0xed, 0xad, 0x12, 0xf8, 0xd2, 0xe6, 0x49, 0x51, 0xa8, 0x99, 0x6e, 0x51, 0x0d, 0x6d, 0x52, 0x79, 0x7c, 0x5b, 0xa0, 0xeb, 0x4a, 0xfa, 0x6b, 0xf2, 0xcc, 0x43, 0xda, 0x09, 0xde, 0x31, 0x79, 0xe8, 0x99, 0xbd, 0x71, 0x88, 0xb3, 0x2a, 0x98, 0xa4, 0x99, 0xd3, 0x72, 0xf3, 0x70, 0x7c, 0xed, 0x47, 0x9b, 0x09, 0x81, 0xcb, 0x50, 0xc0, 0xc0, 0x53, 0x9c, 0xf7, 0xe3, 0x10, 0x0b, 0x72, 0x0e, 0x46, 0x66, 0x52, 0xa4, 0xf4, 0x99, 0xc2, 0xba, 0x3a, 0x17, 0xf5, 0x23, 0x22, 0x68, 0x73, 0x0b, 0x96, 0x2b, 0xc5, 0x72, 0xc0, 0xde, 0x96, 0xe8, 0xc9, 0xe2, 0x8f, 0x7e, 0x35, 0x32, 0xc2, 0x22, 0x41, 0x96, 0xaa, 0x9e, 0x27, 0x68, 0x8d, 0xd0, 0x50, 0xd7, 0xcb, 0x78, 0x54, 0xfb, 0x3c, 0x35, 0xf9, 0xc6, 0x2e, 0xfb, 0x10, 0xda, 0x84, 0x83, 0x3f, 0x29, 0xbb, 0x1b, 0xe5, 0xef, 0x3b, 0x53, 0x36, 0x38, 0xee, 0xf7, 0x43, 0xd8, 0x11, 0x9d, 0xdc, 0x29, 0x0b, 0xdf, 0x08, 0xb6, 0xf0, 0xf9, 0xe4, 0xe1, 0xe1, 0x34, 0x46, 0xc5, 0x3e, 0xd6, 0x98, 0x05, 0xda, 0x26, 0x90, 0x8a, 0x15, 0xdf, 0x1c, 0x48, 0xe0, 0x09, 0xec, 0x12, 0x53, 0xbd, 0x5a, 0x58, 0x98, 0xeb, 0xb5, 0x12, 0x1c, 0xc2, 0x49, 0x04, 0xc8, 0xb1, 0x0e, 0x24, 0xe6, 0x80, 0xe5, 0x65, 0x98, 0x50, 0x76, 0xfd, 0xa1, 0x1d, 0x13, 0xff, 0xdf, 0xa4, 0xdb, 0x28, 0xac, 0x9f, 0x0a, 0xea, 0x2f, 0x81, 0xfd, 0x7e, 0xd4, 0xdc, 0xa8, 0xd3, 0xb2, 0xe3, 0x84, 0x8b, 0x4d, 0x60, 0x46, 0xf6, 0xe0, 0xde, 0x3a, 0x4f, 0x68, 0x3f, 0x25, 0xe0, 0x60, 0x5e, 0x84, 0xb3, 0x6f, 0x48, 0x3c, 0x40, 0x4e, 0xf8, 0x99, 0xcb, 0x3f, 0xcc, 0xbe, 0x8c, 0xb2, 0xa6, 0xf0, 0xa7, 0xe1, 0x0b, 0x19, 0x48, 0xcd, 0x4f, 0x93, 0xf1, 0x81, 0x55, 0x5f, 0x66, 0x1d, 0x31, 0xd4, 0x26, 0x80, 0x8b, 0xbf, 0x9f, 0x66, 0xfd, 0x60, 0xd6, 0x49, 0x26, 0x9c, 0xa3, 0xfe, 0x99, 0x1b, 0x22, 0x42, 0x8c, 0x37, 0xad, 0x2a, 0x08, 0x68, 0x0f, 0x74, 0x7c, 0xc0, 0x36, 0x0c, 0xcd, 0x37, 0x3d, 0xc6, 0xa9, 0xf4, 0x3a, 0x66, 0x47, 0x0e, 0x01, 0x4e, 0x72, 0xb3, 0xd8, 0xc3, 0x8e, 0x02, 0x04, 0x42, 0xd8, 0xaa, 0xb9, 0x74, 0xe6, 0x04, 0x93, 0x74, 0x14, 0x5b, 0x04, 0xcb, 0x7f, 0x30, 0x44, 0xaa, 0xc1, 0xef, 0xda, 0xb2, 0xa1, 0x8b, 0xb4, 0x64, 0xd4, 0xf2, 0xf2, 0xd8, 0x14, 0x39, 0x74, 0xc9, 0x5e, 0xee, 0x85, 0x6d, 0x59, 0xec, 0x00, 0x28, 0x8e, 0xd4, 0x3f, 0xf5, 0xcc, 0x88, 0x03, 0x00, 0x6c, 0x99, 0x55, 0x14, 0xa2, 0xcc, 0x9c, 0xa6, 0x22, 0xb6, 0x1b, 0xcd, 0x75, 0xec, 0x51, 0xc2, 0x02, 0xa9, 0x17, 0x10, 0x5b, 0x4a, 0x4b, 0xed, 0x1b, 0x80, 0x14, 0x68, 0x31, 0xdc, 0xed, 0x07, 0xef, 0xd2, 0xed, 0x25, 0x73, 0x9f, 0x54, 0x09, 0x69, 0x11, 0xb1, 0x50, 0xd3, 0x07, 0x7c, 0xcd, 0x73, 0x1a, 0x03, 0x61, 0x68, 0x27, 0x25, 0xd5, 0x38, 0x03, 0xf8, 0xfc, 0xea, 0xa8, 0x39, 0x19, 0x29, 0x1e, 0xdb, 0x44, 0x93, 0xec, 0x84, 0xcc, 0xe1, 0xd0, 0xf8, 0x2a, 0x67, 0x92, 0x36, 0xea, 0xd1, 0x00, 0x2a, 0xe8, 0x01, 0x8c, 0xac, 0x9f, 0xdb, 0xd2, 0x46, 0xff, 0x09, 0x3d, 0x80, 0x3c, 0x0d, 0xe3, 0x32, 0x6a, 0x57, 0x90, 0x7b, 0x0d, 0xd6, 0xb0, 0x1d, 0x08, 0x14, 0x58, 0xc7, 0x57, 0x28, 0xc6, 0x00, 0x82, 0x99, 0x28, 0x89, 0x0a, 0x56, 0xaa, 0xaf, 0xef, 0xcf, 0x74, 0x23, 0xb7, 0x0a, 0x6d, 0x86, 0xb4, 0x15, 0xb8, 0x35, 0x8d, 0xd0, 0x44, 0xab, 0xee, 0x00, 0xb9, 0xc9, 0x79, 0x5f, 0xc8, 0xf6, 0x1a, 0x64, 0x68, 0x6d, 0xf5, 0xf8, 0x76, 0xa8, 0xf3, 0x30, 0x61, 0x59, 0x9a, 0xe8, 0x30, 0xf7, 0xeb, 0x4c, 0x4b, 0xff, 0x87, 0x5f, 0x4a, 0x93, 0x6c, 0x40, 0x3c, 0x5d, 0x16, 0x0d, 0xe5, 0xd3, 0x3c, 0xae, 0xe4, 0x0f, 0xb7, 0x18, 0xdd, 0xa4, 0x47, 0x8a, 0xc6, 0xf5, 0x1c, 0x59, 0xc2, 0x15, 0x52, 0x54, 0xbd, 0x77, 0x67, 0x11, 0x18, 0x41, 0x1e, 0x26, 0x09, 0xd0, 0x00, 0x30, 0x6f, 0xc9, 0x50, 0x70, 0x04, 0xa3, 0x1e, 0x89, 0x57, 0xea, 0x40, 0xc2, 0x56, 0x4b, 0x83, 0xc3, 0xab, 0xb7, 0x1a, 0x87, 0xc1, 0x1b, 0xd1, 0x8d, 0x78, 0x91, 0xc4, 0x49, 0xdb, 0xbe, 0x79, 0xb4, 0xa4, 0xfb, 0x04, 0x83, 0x07, 0xce, 0x0e, 0x81, 0x2b, 0x2c, 0x68, 0xec, 0xab, 0x77, 0xfd, 0x11, 0x11, 0x52, 0x6a, 0xb0, 0x81, 0x73, 0x06, 0xce, 0xbc, 0xb0, 0x49, 0x7c, 0x55, 0x24, 0x31, 0xce, 0x15, 0xe4, 0xab, 0x52, 0x28, 0x3f, 0x67, 0x94, 0x80, 0xd6, 0x9d, 0xdd, 0xe1, 0xf2, 0x57, 0x9c, 0xfd, 0xbe, 0x0b, 0xca, 0x95, 0xfc, 0x5b, 0x2d, 0xb0, 0xc5, 0xcc, 0x76, 0xa3, 0x19, 0x50, 0xf5, 0x11, 0x6a, 0xae, 0x5f, 0x02, 0xd4, 0x67, 0x10, 0xe4, 0x25, 0x7a, 0x75, 0xfd, 0xed, 0xf2, 0xf4, 0x7c, 0xe3, 0x7c, 0x20, 0x3e, 0x7f, 0x24, 0xd3, 0xc9, 0x17, 0x97, 0x13, 0xc5, 0xd8, 0x07, 0xc2, 0x96, 0x14, 0x9a, 0x75, 0xcc, 0xb4, 0x44, 0xf0, 0xc6, 0xf6, 0xab, 0xdd, 0x2d, 0xbb, 0x29, 0x85, 0xfe, 0x26, 0x74, 0x82, 0x85, 0x8a, 0x1e, }, .t0_len = 2496, .t1 = { 0xbb, 0x11, 0x19, 0x23, 0xf1, 0x94, 0xa7, 0xcc, 0x8a, 0x7b, 0xb2, 0xeb, 0xc5, 0xc0, 0xe7, 0x1a, 0xa6, 0x37, 0xcc, 0x80, 0x0e, 0x61, 0x03, 0xb8, 0x50, 0xa5, 0x39, 0xb2, 0xa3, 0x9e, 0x1b, 0x6d, 0x71, 0x3e, 0x5d, 0xb8, 0x31, 0x4c, 0x9a, 0xe1, 0xf8, 0xbf, 0x8a, 0x38, 0xf0, 0x6a, 0xfb, 0x9d, 0x73, 0xb1, 0x61, 0xb0, 0xff, 0xe3, 0xa4, 0x89, 0x17, 0x06, 0xae, 0x26, 0xd5, 0x4f, 0xfb, 0x49, 0x6d, 0xf8, 0xdc, 0x0f, 0x19, 0x83, 0x50, 0x95, 0x00, 0xc9, 0xab, 0xbd, 0x28, 0xe5, 0x9b, 0x3f, 0xcd, 0xab, 0xbd, 0xad, 0xab, 0xd4, 0x5e, 0xc3, 0x14, 0x99, 0x37, 0x8b, 0xde, 0x84, 0x9e, 0x7c, 0x1f, 0x19, 0xb7, 0x04, 0x4d, 0x67, 0xe0, 0x51, 0x06, 0xd7, 0x13, 0x6d, 0x95, 0x38, 0x0d, 0x56, 0x05, 0xd4, 0x46, 0x5d, 0x87, 0x75, 0x57, 0x06, 0x5d, 0xf0, 0xa7, 0x5d, 0x3c, 0x28, 0x54, 0x2f, 0x40, 0xfe, 0xed, 0x42, 0xec, 0x7e, 0x28, 0x06, 0x37, 0xb0, 0x83, 0xd9, 0x88, 0xbc, 0xa5, 0xf6, 0x39, 0x4e, 0x02, 0x39, 0x6c, 0x46, 0x76, 0x18, 0x4f, 0xb6, 0x33, 0x18, 0xda, 0xfa, 0xf5, 0xbb, 0xdd, 0xe0, 0x0e, 0x30, 0x8f, 0xe8, 0x40, 0x19, 0xc2, 0x34, 0x0a, 0x3f, 0x3e, 0x1c, 0x08, 0x65, 0x62, 0x49, 0x70, 0x71, 0x12, 0x83, 0x35, 0x6a, 0xe1, 0x4b, 0xd6, 0xb9, 0x4d, 0x1c, 0x9a, 0xe1, 0x88, 0xde, 0x1a, 0x8a, 0x2c, 0xa8, 0x24, 0xa8, 0xea, 0xe2, 0xfe, 0x6a, 0xfb, 0x38, 0xd8, 0x3a, 0x2d, 0x99, 0x99, 0x6a, 0xb2, 0x1f, 0xe3, 0xe8, 0x4c, 0x0b, 0xe6, 0xb6, 0xda, 0x08, 0x87, 0x9b, 0x67, 0x73, 0x74, 0xfa, 0x7c, 0x69, 0x1b, 0x13, 0xd4, 0x0f, 0xa9, 0xd4, 0xcc, 0x26, 0xb2, 0x28, 0x8d, 0x5a, 0x8c, 0x9a, 0x43, 0x72, 0x43, 0x81, 0x00, 0x4d, 0x61, 0xb0, 0xd5, 0x7f, 0xf4, 0x00, 0x31, 0x4c, 0x8e, 0x30, 0xee, 0x79, 0x6a, 0xf1, 0x0f, 0x7e, 0xe2, 0x1b, 0xf1, 0x3d, 0x08, 0x18, 0x04, 0x65, 0xab, 0xc7, 0x2e, 0xdd, 0xb0, 0x80, 0xc6, 0xa0, 0x71, 0x84, 0xe3, 0xee, 0xdc, 0x47, 0xc1, 0x9a, 0xa7, 0xf0, 0x9d, 0x1f, 0x33, 0x09, 0xe1, 0x83, 0xa2, 0xbd, 0x9b, 0x05, 0x73, 0xdd, 0xe4, 0x74, 0xa8, 0x1b, 0xa4, 0xf7, 0x8d, 0x0c, 0x52, 0x3d, 0x0c, 0x04, 0xf9, 0x00, 0x60, 0xfd, 0x57, 0x1a, 0x35, 0xc0, 0x37, 0xe0, 0x79, 0xc5, 0xe2, 0x10, 0xd7, 0x39, 0x0d, 0xf5, 0x68, 0xf2, 0xe2, 0xf0, 0x3c, 0xe4, 0x44, 0x20, 0xc8, 0x2f, 0x3f, 0xe6, 0x9e, 0xb9, 0xb4, 0x8e, 0xe9, 0x09, 0x62, 0xd6, 0xb0, 0xf2, 0x44, 0x40, 0x64, 0x8f, 0x71, 0xed, 0xb2, 0x41, 0xee, 0x65, 0x66, 0xfc, 0x1a, 0x64, 0xca, 0xbf, 0x66, 0xbe, 0x6f, 0xec, 0xbc, 0xb1, 0x38, 0x7c, 0x82, 0xa7, 0xbc, 0x20, 0x2d, 0x9e, 0x36, 0x79, 0x98, 0xe2, 0xa2, 0x91, 0xaf, 0x0c, 0xd1, 0x57, 0x06, 0x77, 0xfe, 0x8d, 0x63, 0xa3, 0x28, 0x5a, 0x2e, 0xa6, 0xeb, 0x29, 0xaf, 0x9d, 0xc1, 0xae, 0xc1, 0xc3, 0x6c, 0x47, 0x06, 0xb1, 0x2b, 0xaa, 0x20, 0x83, 0x96, 0x92, 0xf2, 0x86, 0xa6, 0xe0, 0x32, 0x14, 0x68, 0xf7, 0x47, 0x93, 0x45, 0xc4, 0xd5, 0x2f, 0xbd, 0xb2, 0xf0, 0x67, 0x25, 0xb5, 0x54, 0xb8, 0x9e, 0x24, 0x92, 0x61, 0x26, 0x81, 0xac, 0xeb, 0xc6, 0xc7, 0xba, 0xda, 0x92, 0x25, 0x81, 0x8d, 0xbc, 0x35, 0xd6, 0x4c, 0x22, 0xc4, 0x8b, 0xff, 0x80, 0xa7, 0x30, 0xd0, 0x71, 0x6d, 0xfa, 0xc9, 0x9d, 0xfd, 0x5b, 0x89, 0x92, 0x61, 0x1d, 0x0c, 0x93, 0xee, 0x90, 0xbd, 0xb2, 0x60, 0x02, 0x2a, 0xfe, 0x25, 0xd9, 0x13, 0xe0, 0x6e, 0xff, 0xb5, 0x9c, 0xb1, 0xf8, 0xa6, 0x0c, 0xbf, 0xa5, 0xab, 0x2f, 0x45, 0x9a, 0x16, 0xf4, 0x67, 0xe9, 0x89, 0x52, 0x5e, 0x0a, 0x37, 0xeb, 0xe5, 0x6e, 0x83, 0x3f, 0xde, 0x55, 0xdb, 0x9d, 0x15, 0x30, 0xad, 0xcf, 0x45, 0x84, 0x6d, 0xf2, 0x81, 0xe4, 0x7c, 0xaa, 0x1e, 0x0a, 0x27, 0xef, 0xde, 0x21, 0x07, 0xd3, 0x54, 0xce, 0xa0, 0xf6, 0xa4, 0x54, 0x69, 0x2f, 0x04, 0xcd, 0x83, 0x8e, 0xbd, 0xd4, 0x6e, 0x19, 0x1e, 0x5d, 0x9c, 0x11, 0x83, 0x9a, 0x2c, 0x3f, 0x48, 0x8a, 0x4f, 0xc7, 0xcd, 0x26, 0x5a, 0x7b, 0x5d, 0x32, 0xb0, 0x8c, 0xbd, 0xbf, 0xab, 0x9d, 0x2c, 0xcd, 0x76, 0x22, 0x2c, 0x8e, 0xe3, 0x7d, 0xdc, 0xbd, 0x2a, 0xa0, 0x63, 0xed, 0x86, 0x14, 0x73, 0xa6, 0x45, 0x4c, 0xae, 0xa3, 0x77, 0x85, 0x0b, 0x1a, 0x2b, 0x9d, 0xdb, 0xbc, 0xb3, 0x74, 0xfa, 0xb5, 0xb1, 0x2f, 0x35, 0x1c, 0x8e, 0x58, 0x88, 0x87, 0x2e, 0x5c, 0xd1, 0xf6, 0x0a, 0x4f, 0xae, 0x1f, 0xf8, 0x37, 0xd1, 0x92, 0xc2, 0x2b, 0xeb, 0x41, 0xee, 0x6f, 0xa3, 0x92, 0xfc, 0xdf, 0x45, 0x50, 0xff, 0x46, 0xb5, 0xce, 0x90, 0x6d, 0x01, 0x7e, 0xf3, 0x07, 0x7d, 0xf1, 0x32, 0x30, 0x0d, 0x8b, 0xbf, 0xa9, 0xbb, 0x03, 0xc7, 0x5e, 0x79, 0xe2, 0xf0, 0x4c, 0x28, 0x4a, 0xd0, 0x6a, 0x44, 0x39, 0x96, 0x49, 0xc3, 0xe2, 0xa2, 0xa8, 0xd1, 0xef, 0xe9, 0xb7, 0xa4, 0xe0, 0xc2, 0x71, 0x04, 0x7a, 0xb7, 0x59, 0x08, 0xbf, 0xf7, 0xdf, 0x9e, 0x30, 0xec, 0xa5, 0x47, 0x74, 0x5b, 0xae, 0x23, 0xa8, 0x6f, 0xf9, 0xa8, 0xb5, 0x8c, 0x25, 0x38, 0xb8, 0x8b, 0x86, 0x64, 0x01, 0x07, 0x69, 0x02, 0xdc, 0x5f, 0x0b, 0xd7, 0x61, 0x68, 0x7b, 0x49, 0xea, 0xfe, 0x36, 0xd3, 0x50, 0xcb, 0xed, 0xfd, 0xd3, 0x6c, 0x12, 0x1c, 0xf2, 0x37, 0x86, 0xbf, 0xcf, 0x7e, 0x47, 0x07, 0x64, 0x96, 0xea, 0xb6, 0xbb, 0xda, 0x77, 0x40, 0x49, 0xc2, 0xeb, 0xab, 0xe2, 0xde, 0x99, 0xc4, 0xc2, 0x4f, 0x2d, 0xb7, 0x36, 0x84, 0x01, 0x5b, 0x37, 0x39, 0x77, 0x49, 0x67, 0x60, 0xcf, 0x9a, 0xc2, 0x3d, 0x8b, 0x62, 0x31, 0x33, 0xdb, 0x2d, 0xe1, 0x0d, 0x73, 0xfa, 0x6a, 0xd1, 0xc6, 0xda, 0xc8, 0x43, 0x4f, 0x28, 0xc6, 0xe2, 0x51, 0xce, 0x72, 0x93, 0xcf, 0xf3, 0xf3, 0xb6, 0x1e, 0xfc, 0xb5, 0xa4, 0x35, 0x12, 0x36, 0x70, 0xf2, 0x98, 0x46, 0xa1, 0x3d, 0xf3, 0xee, 0x71, 0x26, 0x04, 0x46, 0x1f, 0x1b, 0xab, 0x8f, 0x4e, 0xbc, 0x83, 0x6d, 0xe0, 0x58, 0x97, 0x8a, 0xe7, 0x34, 0x39, 0x6a, 0x98, 0x08, 0x1b, 0x35, 0xcc, 0x98, 0x18, 0x8a, 0x86, 0x94, 0x9c, 0x99, 0x27, 0x0d, 0x47, 0x09, 0x85, 0x4c, 0x5b, 0x35, 0xb1, 0x7f, 0x48, 0xa3, 0x73, 0x13, 0x4c, 0x81, 0x4c, 0xc8, 0xa0, 0xf3, 0xe2, 0xfa, 0x80, 0x7f, 0x2a, 0x91, 0x85, 0x30, 0x90, 0x78, 0x64, 0x77, 0x82, 0x82, 0xd7, 0x5e, 0x03, 0xa4, 0x1b, 0x25, 0x04, 0xee, 0xd8, 0x16, 0xa4, 0x17, 0xa3, 0xac, 0x6b, 0xa1, 0x60, 0x80, 0xc3, 0x9b, 0x73, 0x10, 0x19, 0x20, 0x02, 0xa7, 0x28, 0xf7, 0xf2, 0x03, 0x95, 0x00, 0x9a, 0x9e, 0x16, 0x76, 0x7c, 0xe1, 0x97, 0x1f, 0x5d, 0xe7, 0xd2, 0x29, 0xa5, 0x06, 0x13, 0x36, 0x9e, 0x43, 0x82, 0x04, 0x5a, 0x8e, 0x81, 0x90, 0x1f, 0x4d, 0xba, 0x81, 0x02, 0xf3, 0xd4, 0x13, 0xfe, 0x35, 0xb3, 0x26, 0xa8, 0x74, 0xf2, 0x33, 0xb7, 0x19, 0xa7, 0x13, 0x76, 0x00, 0xd3, 0x5d, 0x33, 0xae, 0xb6, 0xb7, 0x25, 0x96, 0x24, 0x08, 0x3a, 0xa9, 0x68, 0x73, 0x0c, 0x8f, 0x78, 0x29, 0x2a, 0xd2, 0x8f, 0x14, 0xee, 0xab, 0xe6, 0x60, 0x83, 0x59, 0x84, 0xfe, 0x69, 0xef, 0x23, 0xde, 0xc8, 0xc3, 0x27, 0xc0, 0xeb, 0x0b, 0x88, 0x2d, 0x58, 0x7e, 0x1e, 0xc4, 0x33, 0xda, 0x85, 0xc9, 0xfd, 0x1e, 0x0a, 0x34, 0x99, 0x4d, 0xea, 0x24, 0x0c, 0x85, 0x44, 0x52, 0xd1, 0x8c, 0x30, 0xf4, 0x96, 0xe4, 0x9e, 0xc9, 0x04, 0xb6, 0x02, 0xe0, 0xf5, 0x06, 0x2e, 0xdc, 0xda, 0x03, 0x28, 0x0a, 0x53, 0xb4, 0x31, 0x35, 0x74, 0xcc, 0x2c, 0x0d, 0x54, 0x71, 0xbc, 0x96, 0x13, 0xbd, 0xfd, 0x66, 0x41, 0xf5, 0xbd, 0x12, 0x7b, 0xab, 0x5b, 0x5e, 0xb3, 0xd4, 0x99, 0xa3, 0x31, 0x14, 0x04, 0x82, 0x20, 0xe8, 0x19, 0xf8, 0xee, 0x12, 0xca, 0x92, 0x2c, 0x8f, 0x17, 0xd9, 0xc9, 0xf5, 0x1a, 0xd5, 0xbd, 0x68, 0x83, 0xb1, 0x0e, 0x6a, 0xa2, 0x48, 0x3b, 0xa4, 0x9d, 0xc5, 0x47, 0xda, 0x76, 0x86, 0x15, 0x13, 0x44, 0xf4, 0xe9, 0x09, 0x9b, 0x38, 0xe4, 0x30, 0xb5, 0x22, 0x6b, 0x05, 0x98, 0x32, 0xcf, 0x03, 0xdb, 0x48, 0xfb, 0x02, 0xdb, 0xa4, 0xe6, 0x15, 0x93, 0xdc, 0x45, 0x76, 0x36, 0x04, 0x91, 0x89, 0x0e, 0x53, 0xec, 0x0e, 0x6a, 0xc7, 0x3c, 0xf3, 0x2b, 0x25, 0xd8, 0x23, 0xb3, 0x84, 0x56, 0xe2, 0x86, 0x50, 0x5a, 0x54, 0x1e, 0x5a, 0xee, 0xe9, 0x6b, 0x19, 0x14, 0xf5, 0xf7, 0x66, 0x87, 0xce, 0x2b, 0x01, 0x60, 0x22, 0x7a, 0xbe, 0xd7, 0x79, 0x93, 0x59, 0x4b, 0xcd, 0x83, 0x13, 0x66, 0x20, 0x6d, 0x75, 0x71, 0x40, 0x82, 0xf1, 0xc4, 0x6f, 0x1f, 0x44, 0x39, 0xac, 0x81, 0xa5, 0x7a, 0xf3, 0x1c, 0x81, 0xc5, 0x55, 0x30, 0x7a, 0x07, 0x0f, 0xfa, 0x94, 0xe0, 0x47, 0x9b, 0x78, 0x4b, 0xbd, 0x88, 0xa6, 0x0c, 0xd4, 0xc7, 0xcf, 0xd9, 0x4e, 0x6a, 0xfe, 0x02, 0xf6, 0xb2, 0x1f, 0x72, 0xaf, 0x0d, 0xcd, 0x66, 0x09, 0xd4, 0x0c, 0x96, 0x5c, 0x14, 0xe5, 0xf2, 0x38, 0x91, 0x83, 0xe5, 0x3d, 0xe9, 0x30, 0xf7, 0xde, 0x1d, 0x44, 0x21, 0x5c, 0xf4, 0x91, 0x44, 0x84, 0x4e, 0x8b, 0x87, 0xf7, 0x8a, 0x7f, 0x13, 0x2a, 0xef, 0xe2, 0x2b, 0xe8, 0x0b, 0x4e, 0x3a, 0x05, 0xee, 0x3a, 0x68, 0xcc, 0xf6, 0x09, 0xef, 0x44, 0x04, 0x74, 0x02, 0xe4, 0x49, 0x30, 0x46, 0xe6, 0xf9, 0xc7, 0x67, 0xff, 0x8a, 0x75, 0xe2, 0x8b, 0x3c, 0xe0, 0x77, 0xfd, 0xe7, 0xe7, 0xee, 0xd3, 0x13, 0xb5, 0xbf, 0x7e, 0x46, 0x01, 0x27, 0xca, 0x81, 0x82, 0xe9, 0xbc, 0x79, 0x4c, 0x0d, 0xfa, 0x73, 0x0f, 0xb9, 0x20, 0x08, 0x05, 0x75, 0xa7, 0x51, 0xb5, 0xca, 0xec, 0x85, 0xa1, 0x09, 0xb4, 0x42, 0x2b, 0xa2, 0x66, 0x74, 0x3f, 0x0d, 0x03, 0x2b, 0xda, 0x8f, 0x1c, 0xa6, 0x24, 0x8c, 0xdb, 0x91, 0x75, 0x30, 0xdf, 0x13, 0x02, 0xa5, 0xf8, 0xc1, 0x8d, 0xc6, 0x42, 0xd5, 0x24, 0x78, 0xc9, 0x8c, 0x12, 0xa3, 0xf1, 0x6e, 0xf2, 0xb6, 0x2b, 0x4f, 0x59, 0xea, 0x1b, 0xb5, 0x8d, 0xe7, 0xb6, 0x5b, 0x3c, 0x71, 0x53, 0xce, 0x6d, 0xa5, 0xe4, 0x95, 0x07, 0x46, 0xf8, 0x0e, 0x08, 0x7a, 0x0e, 0x35, 0x86, 0xd0, 0x97, 0x79, 0x1b, 0xf3, 0x6d, 0xef, 0x86, 0x5d, 0x68, 0x59, 0x1d, 0x39, 0xd0, 0x90, 0x37, 0x73, 0xee, 0xa9, 0x62, 0x14, 0x7f, 0x34, 0x70, 0x41, 0x38, 0xb5, 0x4d, 0xf7, 0x92, 0x4c, 0xdd, 0x8c, 0x33, 0x3d, 0xb5, 0xe1, 0xa4, 0x09, 0xcc, 0xb2, 0xb3, 0x4e, 0x2c, 0x3c, 0x8c, 0x7f, 0xdd, 0x3f, 0xd8, 0xd0, 0x12, 0xcb, 0xf3, 0x82, 0xaa, 0xa8, 0x5e, 0x83, 0xa1, 0x2f, 0x23, 0x5a, 0x2d, 0x14, 0x7d, 0x03, 0x5b, 0x7b, 0x28, 0xb3, 0x4b, 0x6f, 0x57, 0x94, 0x9f, 0x32, 0x24, 0x82, 0xa7, 0xd4, 0xd3, 0xb1, 0x50, 0x45, 0xc4, 0x20, 0xd5, 0xad, 0xdc, 0x7f, 0x0e, 0x69, 0xb4, 0xdc, 0x1c, 0xba, 0x58, 0xb0, 0x1d, 0x87, 0x24, 0x80, 0xb0, 0x6a, 0x26, 0x0d, 0x82, 0x7d, 0x89, 0x1b, 0x13, 0xc4, 0xc5, 0xca, 0x50, 0xc7, 0x48, 0xde, 0x3c, 0x77, 0x1b, 0xe6, 0x1e, 0x9a, 0xa1, 0x70, 0x16, 0x5c, 0xb0, 0x1f, 0x4b, 0xf5, 0xda, 0x27, 0xa7, 0x79, 0x1d, 0x3a, 0xd3, 0xf6, 0x26, 0x7b, 0x4c, 0xb4, 0xe6, 0x1b, 0x28, 0xfa, 0x17, 0x08, 0x41, 0x8d, 0x93, 0x2d, 0xfc, 0x41, 0x61, 0x88, 0x0c, 0x5d, 0x3b, 0x17, 0xa9, 0x66, 0x3a, 0x90, 0x61, 0xfa, 0x8f, 0x18, 0x04, 0x31, 0x58, 0x50, 0xfe, 0x4e, 0x73, 0x06, 0xc8, 0x82, 0xb3, 0x82, 0x27, 0xe8, 0x67, 0xf8, 0x08, 0x72, 0xcd, 0xc1, 0x94, 0x4d, 0x47, 0x26, 0x15, 0xea, 0x49, 0x00, 0xef, 0x7d, 0x27, 0x0b, 0x88, 0x1d, 0x41, 0x30, 0xf5, 0x6c, 0x5c, 0xc9, 0x80, 0xd9, 0x2a, 0x47, 0xad, 0xa6, 0x65, 0x7e, 0xb6, 0xf3, 0x7a, 0x38, 0x5d, 0x2d, 0x8c, 0xc9, 0x93, 0xe1, 0x44, 0x2e, 0xb0, 0x52, 0x81, 0x85, 0x36, 0x36, 0x99, 0x1e, 0x34, 0xaa, 0xdc, 0x68, 0x95, 0x4d, 0x04, 0xe7, 0xad, 0xef, 0x76, 0xbf, 0x88, 0x0f, 0x05, 0x9b, 0x0c, 0xbb, 0x55, 0xd9, 0x15, 0xa4, 0xb1, 0x23, 0xe2, 0xf1, 0x33, 0x9a, 0x07, 0x3c, 0xbf, 0xbc, 0x40, 0x9b, 0xef, 0xf6, 0x40, 0x0a, 0xe0, 0x96, 0xd5, 0xae, 0x18, 0xec, 0x42, 0xcf, 0xfa, 0xd5, 0xb4, 0x98, 0x0f, 0xa3, 0x5b, 0xf0, 0x34, 0x13, 0xad, 0xb5, 0xd7, 0xe6, 0x87, 0x6a, 0xc3, 0x55, 0xd1, 0xc9, 0xed, 0x70, 0xca, 0x2b, 0x97, 0x39, 0x54, 0xd1, 0x2b, 0x3c, 0xdd, 0x76, 0xac, 0x68, 0x35, 0xdb, 0x96, 0x00, 0x3e, 0xd8, 0xc4, 0xe2, 0x88, 0xb7, 0x1f, 0xd7, 0x7d, 0xba, 0xa7, 0x63, 0x57, 0x20, 0xe1, 0x2a, 0xe0, 0xa3, 0x17, 0xde, 0x80, 0x8c, 0x66, 0x4e, 0x31, 0x7f, 0x55, 0x27, 0x57, 0x91, 0xf3, 0x24, 0x5c, 0xa4, 0xfe, 0x5d, 0x4d, 0x41, 0x07, 0x7f, 0xc1, 0x50, 0xa6, 0xe4, 0x03, 0xd5, 0xa2, 0x08, 0xe4, 0x6e, 0xad, 0xbe, 0x8f, 0x2c, 0xfb, 0x8a, 0xf4, 0x72, 0xf4, 0xa0, 0xce, 0xac, 0x01, 0x52, 0x19, 0x47, 0x8e, 0x6b, 0x86, 0xc9, 0x58, 0xcf, 0x86, 0x52, 0x5b, 0x74, 0x85, 0xc1, 0x73, 0x4c, 0x7e, 0xf0, 0x0e, 0x90, 0x68, 0x3f, 0xff, 0x5d, 0xbd, 0x0a, 0x7d, 0x41, 0x3a, 0x85, 0x50, 0x21, 0x02, 0x6a, 0x1b, 0x32, 0x01, 0x3a, 0x46, 0x16, 0xcb, 0xcd, 0x37, 0x00, 0xac, 0xbc, 0x70, 0x5b, 0xe3, 0xef, 0xba, 0x62, 0x5c, 0x69, 0xa0, 0x25, 0x26, 0x7b, 0xce, 0x9d, 0x13, 0x5e, 0x3f, 0x5b, 0x5c, 0xc8, 0xc4, 0x39, 0x56, 0x40, 0x7e, 0x84, 0xb6, 0x66, 0x31, 0x03, 0xe2, 0x9c, 0x24, 0x20, 0x35, 0x55, 0x1a, 0xe7, 0x97, 0xf5, 0x6c, 0x63, 0x74, 0xbe, 0x0c, 0x79, 0x8c, 0x0c, 0xf3, 0x98, 0xf1, 0xed }, .t1_len = 1920, }, { .name = "ML-DSA 65 (seed only)", .parameter_set = CKP_IBM_ML_DSA_65, .priv_seed = { 0x6D, 0x85, 0x5D, 0xA3, 0xDD, 0x87, 0x50, 0x26, 0x3B, 0xC7, 0x43, 0xAB, 0x25, 0x34, 0xEB, 0x2A, 0xFD, 0x54, 0x4E, 0x35, 0xA7, 0x0D, 0xCB, 0x12, 0x86, 0x39, 0xB6, 0x8C, 0xFF, 0xCF, 0xAA, 0x5E, }, .priv_seed_len = 32, .spki = { 0x30, 0x82, 0x07, 0xb2, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x12, 0x03, 0x82, 0x07, 0xa1, 0x00, 0x30, 0x67, 0x01, 0xd0, 0xd5, 0xe2, 0xdc, 0x95, 0x82, 0x73, 0x87, 0x42, 0x05, 0x7a, 0x69, 0x0d, 0x7b, 0x97, 0xd3, 0x94, 0x02, 0x43, 0x98, 0xd4, 0xba, 0x7d, 0x80, 0x4a, 0x25, 0xa1, 0xfb, 0xab, 0x8e, 0xb8, 0xfb, 0x01, 0xfb, 0x12, 0x63, 0x47, 0xd1, 0x76, 0x51, 0x1c, 0x20, 0x21, 0x56, 0x00, 0x0f, 0x1b, 0xe1, 0x79, 0xf4, 0x00, 0x57, 0x10, 0x86, 0x3c, 0xc8, 0xbb, 0xa3, 0xfe, 0xc2, 0xc3, 0x41, 0xdc, 0x0d, 0xbf, 0xb2, 0x0f, 0x26, 0x2e, 0xb7, 0x40, 0x47, 0x3a, 0xbc, 0x14, 0x7c, 0x92, 0x55, 0x38, 0x4d, 0xc4, 0xc9, 0xe4, 0xf6, 0xa3, 0xa7, 0x2a, 0x94, 0x61, 0x9f, 0xbb, 0x25, 0x8a, 0xed, 0xfe, 0x57, 0xb7, 0x84, 0x6b, 0x7a, 0x3d, 0x2d, 0xe9, 0xa6, 0x4d, 0xda, 0x9b, 0x78, 0x0f, 0xc5, 0xf4, 0xd8, 0xb3, 0x67, 0x94, 0xcb, 0x21, 0x6b, 0x3f, 0x23, 0x6e, 0x1d, 0x5c, 0xb7, 0x13, 0xf9, 0xd2, 0x26, 0xd6, 0x6b, 0xd1, 0xa8, 0xd7, 0xc3, 0xad, 0xaf, 0xbe, 0xe7, 0x11, 0x38, 0x8f, 0x3c, 0x0d, 0x07, 0xb7, 0xcc, 0xb4, 0xea, 0x07, 0x48, 0x5a, 0x3b, 0xc5, 0x35, 0x09, 0x3d, 0x0c, 0x44, 0x57, 0x56, 0x3f, 0x63, 0x03, 0x7d, 0xde, 0xa6, 0x23, 0x89, 0x6a, 0x2a, 0x0b, 0x0c, 0xee, 0x8a, 0x7c, 0x44, 0x4f, 0xdc, 0xc3, 0x2c, 0xa5, 0x5f, 0xbc, 0xf0, 0x92, 0xf7, 0xf7, 0xbc, 0x62, 0x98, 0x91, 0x96, 0x00, 0x35, 0x45, 0x0f, 0x7a, 0xc3, 0x0c, 0x15, 0x49, 0x2f, 0xa4, 0xb4, 0xc2, 0xc2, 0x43, 0xb0, 0x8e, 0x97, 0x94, 0xcd, 0x6c, 0xc4, 0x90, 0x4b, 0x3f, 0x73, 0xbd, 0x69, 0x01, 0x91, 0x14, 0x13, 0xa7, 0xce, 0x22, 0xc4, 0xb0, 0xd8, 0xef, 0x31, 0x89, 0x98, 0x57, 0xc6, 0xac, 0x15, 0x1c, 0x39, 0xec, 0x5f, 0x4f, 0x3b, 0x22, 0x7e, 0xc7, 0x4d, 0x40, 0x31, 0x6f, 0x6b, 0xc9, 0xe7, 0xb4, 0x7a, 0xac, 0x16, 0xdd, 0xb0, 0x99, 0xa3, 0x4a, 0x33, 0x4a, 0xab, 0xfb, 0xa1, 0xa2, 0x36, 0x19, 0x50, 0x3a, 0x51, 0x0f, 0xc8, 0x64, 0x22, 0x34, 0x3b, 0x58, 0x1e, 0xc8, 0x00, 0x91, 0x02, 0xf8, 0xa3, 0xca, 0xd2, 0xe2, 0xb2, 0xd0, 0xf0, 0x0c, 0xcf, 0xb3, 0xeb, 0x8e, 0xa4, 0x61, 0x48, 0xd9, 0xec, 0x45, 0x0f, 0x52, 0xf4, 0xa9, 0x29, 0xf4, 0xde, 0x90, 0xb2, 0x8b, 0xa2, 0x31, 0xa3, 0x76, 0xcc, 0xaa, 0xea, 0xfd, 0xae, 0x4e, 0xfb, 0x24, 0x80, 0x0b, 0x45, 0xa9, 0x2b, 0xca, 0x9d, 0xa8, 0x27, 0x92, 0x64, 0x56, 0x5c, 0x77, 0x21, 0x5b, 0xd8, 0x02, 0x51, 0x6f, 0x63, 0x1d, 0x6f, 0x5b, 0x27, 0xf2, 0x11, 0x7a, 0xd5, 0xbd, 0x2f, 0x42, 0x5b, 0xac, 0xc5, 0x57, 0x1b, 0xe7, 0x04, 0xbc, 0x6f, 0xbf, 0xf6, 0xff, 0x60, 0x9f, 0xcb, 0x17, 0xb3, 0x33, 0x17, 0xc6, 0x7f, 0x31, 0x50, 0xed, 0xa9, 0x49, 0xf6, 0x26, 0x0e, 0x29, 0x4e, 0xe4, 0x13, 0x10, 0x13, 0xd4, 0x38, 0x46, 0x00, 0x9f, 0xd8, 0x8b, 0x6c, 0xe6, 0x15, 0x6c, 0xc5, 0xd3, 0xe1, 0xcb, 0xe6, 0x41, 0xc5, 0xd9, 0xc8, 0xeb, 0xa3, 0xf8, 0xa8, 0xd2, 0xa7, 0x77, 0x2c, 0x1b, 0xb3, 0x13, 0x70, 0x94, 0x06, 0x03, 0x2b, 0x1d, 0xf8, 0x58, 0x05, 0x5e, 0x2d, 0xd1, 0xca, 0xd3, 0x69, 0x65, 0x20, 0xf7, 0x80, 0xf3, 0xb4, 0xbc, 0x09, 0xfb, 0x28, 0x20, 0xd8, 0x16, 0x9b, 0x87, 0x0f, 0x41, 0x5a, 0x12, 0xc7, 0xdf, 0x92, 0x97, 0x5f, 0x47, 0xc0, 0x7e, 0xc8, 0x68, 0x82, 0x1e, 0xb9, 0xd4, 0x33, 0x34, 0x5a, 0xac, 0x3d, 0x2e, 0xc4, 0xe4, 0xfc, 0xe7, 0x97, 0xe0, 0x39, 0xf2, 0xe2, 0x1f, 0xb0, 0xfe, 0x7b, 0x95, 0x17, 0x8e, 0xab, 0xb0, 0xcf, 0x99, 0x98, 0xb2, 0xf0, 0xef, 0xa1, 0xf3, 0x14, 0xf1, 0x8c, 0xde, 0xcc, 0xcd, 0x25, 0xba, 0x1e, 0x5f, 0x7d, 0x17, 0x9f, 0x66, 0xf6, 0xea, 0xee, 0xe1, 0xe4, 0xac, 0xd5, 0xfa, 0x04, 0xe4, 0x24, 0xcc, 0x1d, 0x7d, 0x1f, 0xa1, 0xfb, 0x06, 0xd2, 0xa1, 0xae, 0x44, 0x5a, 0x41, 0x1d, 0x45, 0x9b, 0x8d, 0x39, 0xbb, 0xd9, 0xc7, 0x0a, 0x9f, 0xe7, 0x27, 0x39, 0xd9, 0xb1, 0xbd, 0x47, 0xc2, 0xb7, 0x7a, 0xad, 0x0c, 0x70, 0x7e, 0x86, 0x39, 0x7f, 0x1d, 0x98, 0x81, 0x4a, 0xa3, 0x84, 0x3f, 0x0f, 0xaa, 0x47, 0x18, 0x42, 0x1e, 0x4d, 0x05, 0x5e, 0x27, 0x85, 0x14, 0xb2, 0xb7, 0x49, 0x79, 0x89, 0xeb, 0x2c, 0xa6, 0x90, 0x94, 0xdd, 0x28, 0xf8, 0x06, 0x5c, 0x40, 0x0c, 0xa8, 0x8e, 0x23, 0x5b, 0x10, 0xaa, 0x0a, 0x1e, 0x29, 0xc8, 0x8b, 0x9a, 0x68, 0xa2, 0x60, 0x19, 0x07, 0xff, 0xe3, 0x4c, 0x67, 0x41, 0x8a, 0x23, 0xe0, 0xf1, 0xfd, 0xd4, 0x1a, 0x8a, 0xb1, 0x8b, 0x28, 0x54, 0x8b, 0x7e, 0x42, 0x26, 0xae, 0x0b, 0x8a, 0x4e, 0x57, 0xf0, 0xac, 0x94, 0x21, 0x90, 0x04, 0x8d, 0x7e, 0x12, 0xec, 0xc5, 0x43, 0x37, 0x6b, 0xf3, 0x4d, 0xf1, 0x72, 0x4e, 0x9a, 0xad, 0x65, 0x87, 0x73, 0x83, 0x91, 0x80, 0x06, 0x9e, 0x92, 0x4b, 0x74, 0x1f, 0x5c, 0xe9, 0x98, 0x0a, 0xa1, 0x4f, 0xfb, 0x19, 0x1a, 0x8d, 0xfc, 0xa7, 0x68, 0x8d, 0xcd, 0x08, 0xe5, 0x25, 0x02, 0x51, 0x8b, 0x8a, 0xec, 0x1f, 0x98, 0xa0, 0x46, 0x17, 0xfc, 0xb3, 0xb9, 0x59, 0xe2, 0x70, 0x52, 0xa1, 0x25, 0x8e, 0x8a, 0x84, 0x70, 0x3c, 0x60, 0x7e, 0x54, 0x78, 0x64, 0xce, 0x42, 0xdb, 0x2c, 0x71, 0xde, 0x65, 0x3a, 0xb5, 0x1a, 0x89, 0xc7, 0x17, 0x45, 0xa8, 0x7b, 0xea, 0xc5, 0x5e, 0x9d, 0x20, 0xab, 0x88, 0xef, 0xf3, 0x47, 0xbe, 0x62, 0x72, 0x96, 0x5c, 0x9e, 0x6b, 0xb4, 0x20, 0x8e, 0xab, 0x80, 0xc2, 0xa5, 0x4e, 0xc2, 0xf5, 0xc6, 0xc4, 0x46, 0xcd, 0x12, 0xac, 0x9f, 0x5f, 0x8a, 0xbf, 0xfb, 0xab, 0xdd, 0xb0, 0x5b, 0x5d, 0x56, 0x01, 0x3f, 0x37, 0x9f, 0x77, 0x61, 0x6e, 0xb0, 0x3b, 0x23, 0x95, 0xca, 0x13, 0x16, 0xeb, 0x77, 0x89, 0x30, 0xd8, 0x77, 0x05, 0xeb, 0x39, 0x92, 0x0d, 0xd5, 0x79, 0x87, 0xb7, 0xa2, 0xed, 0xd0, 0xf5, 0x56, 0x10, 0x28, 0x9e, 0x2c, 0xa9, 0x10, 0x30, 0x51, 0xec, 0x22, 0xff, 0xb3, 0x1e, 0x18, 0xe7, 0x49, 0x37, 0x32, 0xe5, 0x0a, 0x41, 0xc2, 0x39, 0x20, 0xfc, 0xf8, 0x30, 0x31, 0x9b, 0x77, 0xac, 0xdb, 0xee, 0xdc, 0x85, 0x96, 0xf1, 0x2e, 0x25, 0x4e, 0x5d, 0xbd, 0x18, 0x26, 0x25, 0x77, 0x06, 0xb9, 0xea, 0x9e, 0xb9, 0x2f, 0x67, 0x71, 0x2a, 0xb2, 0x73, 0x12, 0xf4, 0xe3, 0x35, 0x5a, 0x9a, 0x7f, 0x12, 0x57, 0x22, 0x8c, 0x2c, 0x37, 0x85, 0xb6, 0xb6, 0xfb, 0xe0, 0x6c, 0x1a, 0x41, 0x1f, 0xe9, 0xf5, 0x88, 0x4e, 0xda, 0x9f, 0x85, 0xc5, 0x84, 0x20, 0x90, 0x7b, 0xa4, 0x78, 0x59, 0x47, 0x4f, 0x6e, 0x6f, 0x14, 0x19, 0x87, 0xa7, 0x48, 0xbb, 0x21, 0x76, 0x26, 0xcb, 0xf1, 0x3c, 0x75, 0x4c, 0xa8, 0xcb, 0xed, 0x55, 0xd2, 0x39, 0x66, 0x42, 0xfa, 0x0c, 0xb3, 0xbf, 0xfc, 0x11, 0x56, 0xca, 0x48, 0x09, 0x70, 0xbe, 0x32, 0xc0, 0x94, 0xa7, 0x5f, 0x4a, 0xac, 0xb6, 0x14, 0x6b, 0x2a, 0x9b, 0xc8, 0x32, 0xfa, 0xd4, 0x87, 0x5f, 0x4b, 0xe8, 0x47, 0xe2, 0xfb, 0x74, 0xf6, 0xca, 0xfa, 0x77, 0x0e, 0x9b, 0x83, 0x0c, 0xae, 0xe8, 0x88, 0x32, 0xcd, 0x62, 0x68, 0x79, 0xc3, 0xf9, 0x06, 0x1e, 0xb8, 0x9c, 0xd1, 0xe1, 0xb0, 0x28, 0x45, 0xa8, 0xf7, 0x98, 0xde, 0xe6, 0xb8, 0xc7, 0xb2, 0x43, 0x8a, 0xd1, 0x27, 0xfd, 0x13, 0xdb, 0xb8, 0x56, 0xd3, 0x74, 0x3b, 0xc8, 0xad, 0x72, 0x14, 0x1f, 0x1f, 0x3f, 0x83, 0x68, 0x95, 0x82, 0xe2, 0x7f, 0x17, 0x0b, 0xd8, 0x67, 0x9a, 0xe5, 0x28, 0xa8, 0xb6, 0x2f, 0xfe, 0xb0, 0xf0, 0x5e, 0x02, 0x3e, 0x72, 0x0c, 0x69, 0x4b, 0x83, 0x06, 0xa3, 0x43, 0xbc, 0xba, 0x81, 0x29, 0x00, 0xd4, 0x5b, 0xeb, 0x19, 0x9b, 0x29, 0xd2, 0xc5, 0xa1, 0xc5, 0x2f, 0x59, 0xbe, 0x08, 0x8a, 0xf9, 0x5b, 0xfe, 0x1d, 0x57, 0xc0, 0x68, 0xd9, 0x6e, 0xce, 0x51, 0x07, 0x64, 0x58, 0x8d, 0x83, 0x77, 0xff, 0x3c, 0x5c, 0xf9, 0x96, 0x63, 0xc7, 0x5b, 0x9a, 0xdc, 0x26, 0x8e, 0xee, 0xe8, 0x3d, 0x1f, 0x41, 0x18, 0x44, 0x82, 0xe4, 0x7d, 0x43, 0xa1, 0xdb, 0x52, 0x50, 0xc5, 0x7d, 0x7e, 0x0a, 0xb5, 0xb7, 0x45, 0x7a, 0xb6, 0xd5, 0x5b, 0x69, 0xdd, 0x0a, 0xe2, 0x6d, 0xd1, 0x43, 0xbf, 0xe4, 0x7b, 0x3f, 0x1c, 0x4e, 0xae, 0x8a, 0x89, 0x51, 0xe9, 0x3d, 0x24, 0x27, 0xb9, 0x6b, 0xfa, 0xc4, 0x25, 0x17, 0x2c, 0xf0, 0xf3, 0x6a, 0x6a, 0xbe, 0x90, 0xeb, 0x98, 0x4f, 0xe9, 0xd2, 0xd1, 0x57, 0x01, 0x69, 0x6c, 0x86, 0x3e, 0x36, 0x07, 0xe4, 0x87, 0x16, 0xc7, 0xc6, 0xf3, 0x56, 0x7c, 0x3c, 0x3e, 0x12, 0x23, 0x76, 0x35, 0x8e, 0x29, 0x36, 0x3e, 0x0c, 0x1a, 0xff, 0xa7, 0xde, 0xc8, 0x23, 0x61, 0x96, 0x0d, 0x51, 0x13, 0x9b, 0xa9, 0xa9, 0xe4, 0x79, 0x3d, 0x70, 0x4c, 0x9f, 0x4c, 0xdb, 0xaa, 0xb9, 0x11, 0x8d, 0x9a, 0x6a, 0xac, 0x9c, 0xde, 0xcf, 0xa2, 0xda, 0x92, 0xde, 0x75, 0x8b, 0x9e, 0xb7, 0x5f, 0x97, 0x93, 0x78, 0x97, 0x89, 0x4f, 0x86, 0x1e, 0x2d, 0x56, 0xd5, 0x28, 0xeb, 0x5f, 0x4f, 0x1c, 0xc3, 0x30, 0x6b, 0xe5, 0xf5, 0x11, 0x62, 0x7f, 0xe3, 0xe4, 0xfb, 0x7e, 0xfe, 0xc7, 0xa7, 0xef, 0x30, 0xad, 0xd4, 0x62, 0x6b, 0xa9, 0x49, 0x75, 0xf7, 0x76, 0x5b, 0xc2, 0xb2, 0x2d, 0xaf, 0xa7, 0x26, 0xba, 0x14, 0x97, 0x2e, 0x97, 0xa2, 0xea, 0xb1, 0x7b, 0x42, 0x2d, 0x88, 0xd8, 0xc4, 0x70, 0x0c, 0x32, 0xea, 0x14, 0x74, 0x55, 0xd6, 0xaf, 0xcd, 0x6b, 0x59, 0xb0, 0x59, 0x9f, 0x7d, 0xa4, 0x83, 0x52, 0x85, 0x8a, 0x79, 0x8d, 0x3b, 0x4a, 0x3e, 0x29, 0x89, 0xd2, 0x40, 0x16, 0x3e, 0x09, 0x66, 0xdb, 0x9e, 0x63, 0xe3, 0x76, 0x92, 0x8b, 0x6b, 0x2f, 0x8f, 0x17, 0x9b, 0x4b, 0xea, 0x33, 0x04, 0x5a, 0xaf, 0xed, 0x47, 0x80, 0x95, 0x57, 0xae, 0x71, 0x7f, 0x8a, 0x7b, 0xf5, 0x0a, 0x8e, 0x93, 0xd0, 0x0e, 0x70, 0xf4, 0x51, 0x6c, 0x54, 0x96, 0xbf, 0xb2, 0xee, 0x5d, 0xca, 0xc0, 0x8b, 0xe1, 0xd3, 0x9a, 0x68, 0x11, 0x96, 0x37, 0x21, 0x7e, 0x56, 0x96, 0x3e, 0x6c, 0x66, 0x44, 0x57, 0xe9, 0x77, 0x2a, 0xcd, 0xc2, 0x72, 0x09, 0x71, 0x14, 0xfd, 0xe3, 0xff, 0xb1, 0xfd, 0x82, 0xf6, 0x15, 0xab, 0x55, 0xc3, 0xf2, 0x41, 0x41, 0x74, 0x68, 0xb6, 0xb0, 0xeb, 0x40, 0xfa, 0x60, 0xa8, 0x6c, 0x06, 0x3a, 0xc3, 0xe9, 0x71, 0x23, 0x85, 0x4d, 0x06, 0x44, 0xe8, 0x2b, 0xa7, 0xb2, 0x97, 0x78, 0x1c, 0x8d, 0x42, 0x36, 0xf8, 0xc5, 0x8a, 0x05, 0xa6, 0x02, 0xb4, 0x5e, 0xcd, 0x1a, 0x2a, 0xcd, 0x08, 0xa4, 0xa0, 0x15, 0x40, 0x81, 0x9a, 0x2f, 0xa5, 0x04, 0x50, 0xb0, 0xe1, 0xcc, 0x4b, 0x17, 0xed, 0xb3, 0xc4, 0x63, 0xf8, 0x15, 0x83, 0x05, 0x66, 0xa8, 0xc1, 0x00, 0x07, 0x36, 0x99, 0x83, 0x26, 0xf0, 0xc7, 0xb5, 0x3c, 0x67, 0xfb, 0xe6, 0x3a, 0x23, 0x13, 0x4b, 0xf2, 0xca, 0x13, 0x06, 0xc9, 0x8c, 0x85, 0xfe, 0xe7, 0xc5, 0xf2, 0x86, 0xd2, 0x65, 0xd4, 0x47, 0xd7, 0x5a, 0x87, 0xaa, 0xaa, 0xd9, 0xce, 0xbe, 0x6e, 0x3b, 0x38, 0x4a, 0xc7, 0x43, 0x7e, 0x14, 0x1b, 0x92, 0x2c, 0xf0, 0x70, 0x3d, 0xc6, 0x8e, 0xc3, 0x8b, 0xf3, 0x43, 0x66, 0xbb, 0xc0, 0xee, 0xf2, 0x5b, 0x34, 0xd8, 0x5a, 0xfb, 0xca, 0xb7, 0x3c, 0xd1, 0xc6, 0x85, 0xc0, 0x53, 0x80, 0x00, 0x19, 0x90, 0xde, 0xff, 0x29, 0x6f, 0x03, 0x6a, 0xc9, 0xc0, 0x37, 0x26, 0x5c, 0x4c, 0xf3, 0xda, 0x85, 0xeb, 0x90, 0x04, 0xb3, 0x3c, 0x84, 0x25, 0x98, 0xed, 0x67, 0xa2, 0x82, 0x39, 0xc5, 0x3e, 0x0d, 0xd9, 0x63, 0xc3, 0x9a, 0x70, 0xf2, 0x97, 0xe4, 0x97, 0x00, 0x2c, 0xbb, 0x08, 0xd4, 0xc1, 0x1c, 0xd9, 0x4e, 0xad, 0x37, 0xb0, 0x95, 0x57, 0x6e, 0x3e, 0x2c, 0x20, 0x61, 0xa8, 0x5f, 0xc6, 0xd5, 0x54, 0xc6, 0x67, 0xc1, 0x02, 0x2b, 0x4b, 0x29, 0x64, 0x8d, 0xcf, 0x78, 0x95, 0xe9, 0x7e, 0x59, 0xf2, 0xae, 0xb9, 0x88, 0xa5, 0xec, 0x8e, 0x78, 0x37, 0x31, 0x00, 0xe3, 0xe9, 0x61, 0x48, 0x2a, 0x52, 0x96, 0x5c, 0x6a, 0x42, 0xae, 0xee, 0x8d, 0x30, 0x89, 0x1b, 0xee, 0xd5, 0x25, 0x73, 0x8a, 0x6b, 0xd1, 0xbc, 0x01, 0xf1, 0x51, 0x7f, 0x55, 0x04, 0x8e, 0x0d, 0x7e, 0x05, 0xc0, 0xa7, 0x2e, 0xee, 0x4a, 0x32, 0x0c, 0x9c, 0x00, 0xd9, 0xb9, 0xd8, 0x62, 0x1b, 0x56, 0x49, 0x45, 0x0a, 0x8a, 0x20, 0x95, 0x7e, 0xe2, 0x98, 0x14, 0xd9, 0xe7, 0x81, 0x2d, 0xdd, 0x14, 0x18, 0x15, 0x23, 0x3d, 0x6c, 0xc4, 0x58, 0x19, 0x9b, 0xcb, 0xd4, 0x56, 0x23, 0x95, 0x3d, 0xc2, 0x77, 0xd4, 0x1a, 0xaa, 0x02, 0xcd, 0x88, 0xbd, 0x85, 0x28, 0xb6, 0x81, 0x51, 0x20, 0x8a, 0xba, 0x23, 0x64, 0x7a, 0x19, 0x87, 0x8a, 0x1d, 0x18, 0xff, 0x5c, 0x2c, 0x9e, 0x4e, 0x44, 0x83, 0xe1, 0x76, 0xd6, 0x96, 0xec, 0x44, 0xb3, 0xc4, 0x40, 0x13, 0xc1, 0x27, 0xcf, 0x19, 0x8c, 0x45, 0x86, 0xbf, 0x6c, 0xb6, 0x14, 0x0a, 0xfd, 0x59, 0x25, 0xff, 0xc0, 0x7d, 0x36, 0x9c, 0x47, 0x33, 0xdf, 0xd4, 0xe7, 0x7e, 0x3b, 0xab, 0x99, 0xc9, 0x47, 0x00, 0x91, 0x42, 0x42, 0x55, 0x87, 0xb7, 0x76, 0xf2, 0xee, 0xca, 0xa5, 0x2d, 0xe5, 0x95, 0xa0, 0x1b, 0xd0, 0x6c, 0xd6, 0xf2, 0x0d, 0x85, 0x60, 0x6a, 0x2a, 0xdd, 0x17, 0x45, 0x6f, 0x75, 0xa6, 0xf6, 0x31, 0xab, 0x63, 0x4f, 0x3f, 0x25, 0x2b, 0x98, 0xfc, 0xfb, 0xd0, 0x1a, 0x7e, 0xa0, 0x02, 0x9a, 0xdf, 0xb0, 0xe3, 0x3a, 0x00, 0x8c, 0x28, 0xf9, 0x34, 0x42, 0x4c, 0x93, 0x28, 0x89, 0x4f, 0x7b, 0xec, 0x23, 0x8a, 0x32, 0x61, 0xb6, 0x2c, 0x19, 0x23, 0x69, 0x3d, 0xfc, 0x70, 0xae, 0x4f, 0xb7, 0x82, 0x52, 0xa2, 0x5f, 0xb4, 0x1e, 0x16, 0xb5, 0x1f, 0xc4, 0x77, 0x3e, 0x20, 0xfa, 0x59, 0x12, 0xdd, 0x92, 0xb0, 0xeb, 0x0b, 0x17, 0x48, 0x2a, 0xcb, 0xde, 0x54, 0x7f, 0x4d, 0xab, 0xc3, 0x3a, 0x6a, 0xe0, 0x74, 0x8e, 0x8f, 0xc9, 0x31, 0xb1, 0x32, 0x75, 0xa5, 0x24 }, .spki_len = 1974, }, { .name = "ML-DSA 87 (PKCS#8/SPKI - seed only)", .pkcs8 = { 0x30, 0x34, 0x02, 0x01, 0x00, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x13, 0x04, 0x22, 0x80, 0x20, 0xad, 0xf8, 0xfa, 0x33, 0x6c, 0x59, 0xb7, 0x88, 0x6e, 0x1b, 0x00, 0xf2, 0x5c, 0x3d, 0xc7, 0x39, 0x47, 0x92, 0x78, 0x77, 0xe2, 0x71, 0x36, 0xfd, 0x6c, 0xdf, 0x68, 0xe5, 0x53, 0x1d, 0x33, 0xf4 }, .pkcs8_len = 54, .spki = { 0x30, 0x82, 0x0a, 0x32, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x13, 0x03, 0x82, 0x0a, 0x21, 0x00, 0x8e, 0xc7, 0xa1, 0x4b, 0x5a, 0x76, 0x94, 0x04, 0x4a, 0x48, 0x50, 0x3f, 0xca, 0xfe, 0x56, 0x27, 0xb9, 0x16, 0x34, 0x99, 0xaa, 0xd6, 0x98, 0xdd, 0x1a, 0xb1, 0x15, 0x58, 0xe0, 0xcb, 0xd0, 0x7c, 0x12, 0x8e, 0x94, 0x05, 0x91, 0x68, 0xb5, 0x5b, 0xb5, 0xf4, 0xc0, 0xd0, 0x17, 0xc0, 0x00, 0xf3, 0x21, 0x5b, 0xa0, 0x47, 0x95, 0x0f, 0x41, 0xaa, 0x7f, 0x48, 0x03, 0x7d, 0x84, 0xdb, 0x0d, 0x95, 0xf1, 0x2a, 0xc3, 0x61, 0xed, 0xa8, 0xf2, 0x70, 0x28, 0xef, 0x35, 0xc9, 0xf6, 0x84, 0x54, 0x6e, 0x36, 0x64, 0xef, 0x61, 0xbc, 0xd8, 0xf7, 0x63, 0x29, 0x7c, 0x18, 0x1c, 0x6f, 0x68, 0x26, 0x66, 0xb2, 0xa9, 0x00, 0x56, 0x78, 0x50, 0xf1, 0x6f, 0x41, 0x74, 0x6d, 0xd4, 0xeb, 0x99, 0x20, 0x61, 0x01, 0xd9, 0x76, 0xc8, 0x1f, 0x12, 0xc1, 0x0f, 0xbf, 0x19, 0x60, 0x31, 0x50, 0x2d, 0x64, 0xdb, 0xdf, 0x1e, 0x2b, 0x6d, 0x9c, 0x16, 0xc8, 0x09, 0x47, 0x64, 0xe8, 0x95, 0x3c, 0x20, 0xe1, 0x49, 0x05, 0xee, 0x52, 0x8a, 0xfa, 0x64, 0x72, 0x4d, 0x57, 0x60, 0x9b, 0xf1, 0xc5, 0x69, 0x0a, 0x3d, 0x21, 0xe2, 0x1b, 0x6d, 0xfb, 0xee, 0x99, 0xbb, 0x10, 0x9d, 0x07, 0xf3, 0x2a, 0x87, 0x04, 0x67, 0x9f, 0x19, 0xab, 0x27, 0x9e, 0x08, 0x5e, 0x8f, 0x8b, 0xa0, 0x34, 0x4b, 0x64, 0xad, 0x29, 0x8d, 0xa8, 0xc8, 0xdb, 0x97, 0xad, 0x87, 0xd6, 0x90, 0xf5, 0xc6, 0x0e, 0x0b, 0xdc, 0xe6, 0x8e, 0x07, 0x91, 0x3d, 0x9d, 0xee, 0xa0, 0xca, 0x68, 0x9e, 0x56, 0x12, 0xfe, 0x7a, 0x21, 0x8e, 0x82, 0xb3, 0x70, 0x64, 0xf7, 0xf4, 0x0d, 0x1b, 0xc4, 0x73, 0xc7, 0x83, 0xc2, 0x65, 0x8f, 0x58, 0x66, 0xc3, 0xb1, 0xb2, 0x46, 0x0c, 0xc6, 0x1a, 0xa8, 0x81, 0x36, 0x43, 0x9f, 0x18, 0x8f, 0x02, 0xc7, 0x36, 0xd4, 0xc7, 0xce, 0x83, 0xd0, 0xcf, 0x5a, 0x86, 0x56, 0x4b, 0xf5, 0x67, 0x03, 0xc9, 0x6b, 0x23, 0xaf, 0xae, 0x4a, 0xbc, 0x3d, 0x0c, 0xd4, 0x75, 0xcf, 0xed, 0x70, 0xbc, 0xa3, 0x6f, 0xd1, 0x9e, 0xf8, 0x41, 0xc1, 0x35, 0x25, 0x42, 0x2f, 0x00, 0x66, 0x02, 0x7d, 0x90, 0xbb, 0x39, 0xe9, 0x0a, 0x54, 0x0c, 0xc5, 0x4c, 0x83, 0x04, 0x45, 0x5c, 0xd5, 0xb5, 0xf1, 0x33, 0x5c, 0xe7, 0xe0, 0x34, 0x44, 0x6a, 0xb0, 0x78, 0xe7, 0xdb, 0xee, 0x8e, 0xe4, 0x56, 0xfc, 0x40, 0x9f, 0x9c, 0xbf, 0x50, 0xcf, 0x17, 0xee, 0x9a, 0xee, 0xf4, 0x98, 0x58, 0x79, 0xb6, 0xf0, 0x35, 0x60, 0x2f, 0x8c, 0x3c, 0x4c, 0x3c, 0x91, 0xb4, 0x7d, 0xf6, 0xd6, 0x8c, 0xb4, 0x19, 0xb5, 0x9f, 0xc2, 0x6d, 0x95, 0x5d, 0x85, 0x01, 0x7a, 0x51, 0x54, 0x51, 0x2e, 0x5c, 0x52, 0xbf, 0x76, 0xfd, 0xa9, 0x32, 0x84, 0x48, 0xf6, 0x5b, 0x3d, 0xf8, 0x73, 0xf7, 0x1d, 0x5a, 0xc0, 0xcf, 0xb7, 0x19, 0x57, 0x09, 0x85, 0x53, 0x42, 0xb8, 0x3f, 0x61, 0x80, 0x46, 0xcd, 0xa2, 0x7b, 0x24, 0xeb, 0x64, 0xef, 0xdd, 0x38, 0x4c, 0xf2, 0x81, 0x49, 0x55, 0xa8, 0x54, 0x22, 0x3a, 0x58, 0xad, 0x46, 0x6a, 0x0c, 0x1a, 0x0d, 0x8b, 0x2c, 0x11, 0xc4, 0x6c, 0x9e, 0xae, 0x5e, 0xe9, 0xaa, 0x61, 0x21, 0xb6, 0xc2, 0x57, 0xe6, 0x7f, 0x2f, 0x14, 0xbc, 0xff, 0x06, 0x7b, 0x57, 0x88, 0x16, 0x9d, 0x35, 0x87, 0xc1, 0x12, 0x2a, 0x10, 0x5e, 0xae, 0xd0, 0x81, 0xbb, 0x96, 0x57, 0x87, 0x11, 0xa3, 0x86, 0x07, 0x6f, 0x01, 0xa1, 0x3d, 0xb8, 0x31, 0x9a, 0x53, 0x5a, 0x5f, 0xbc, 0x3e, 0x63, 0xea, 0x24, 0x3e, 0x75, 0xd5, 0x06, 0xf4, 0xdf, 0x73, 0xdf, 0x7d, 0x90, 0x35, 0x9d, 0xc4, 0x4a, 0xfd, 0xee, 0xed, 0x3a, 0x7a, 0x39, 0xa7, 0x3e, 0x3d, 0xd0, 0x38, 0xad, 0xd8, 0xa2, 0x5c, 0x40, 0x31, 0x2f, 0xcb, 0x88, 0xa4, 0x83, 0xec, 0x23, 0xb5, 0xab, 0x8a, 0xad, 0x16, 0x79, 0x9d, 0x6c, 0x9b, 0x0f, 0x56, 0x64, 0xf2, 0xaa, 0x80, 0x26, 0x7a, 0x29, 0x96, 0xc6, 0x51, 0x1a, 0xb0, 0x0c, 0xab, 0x93, 0xe7, 0xc7, 0x61, 0xef, 0x1a, 0xd6, 0x87, 0xfe, 0x2f, 0x6b, 0x3b, 0x2a, 0x8f, 0xbe, 0x1e, 0x31, 0xb9, 0x98, 0x3f, 0x83, 0x46, 0xbd, 0xc6, 0x4f, 0xd5, 0xd9, 0xa9, 0x87, 0x69, 0x7a, 0x9b, 0x12, 0x07, 0xc2, 0xde, 0xfb, 0x11, 0x5c, 0x88, 0x97, 0xfa, 0xfb, 0xbe, 0x8e, 0xe7, 0x12, 0xb8, 0x95, 0x54, 0xc3, 0xf8, 0xba, 0x9e, 0x48, 0x90, 0x76, 0xef, 0x82, 0x06, 0x3f, 0x27, 0xad, 0x06, 0xb9, 0x46, 0xcc, 0xe5, 0x3a, 0x6d, 0x52, 0x10, 0x68, 0xb7, 0xf2, 0x55, 0xbc, 0xf2, 0xdc, 0x7a, 0xb9, 0x1c, 0xea, 0xeb, 0x4e, 0x20, 0x72, 0xe2, 0xd1, 0xd9, 0xe9, 0x8f, 0x44, 0x5d, 0xd4, 0xd3, 0x7c, 0x8e, 0x45, 0x16, 0x20, 0x2b, 0x6b, 0x01, 0xa0, 0x99, 0x26, 0x89, 0x72, 0xc3, 0xc0, 0x3d, 0x84, 0x1b, 0x9d, 0xfd, 0x4b, 0xd0, 0x60, 0x65, 0xe2, 0x8d, 0xcc, 0x97, 0x94, 0xf1, 0x67, 0x9e, 0xe5, 0xfb, 0xe3, 0xab, 0x24, 0x34, 0xa8, 0x33, 0xdb, 0x79, 0x39, 0xc2, 0x17, 0x17, 0x69, 0xd4, 0x18, 0xbf, 0xa2, 0x47, 0xcc, 0x51, 0xda, 0x94, 0x01, 0xa6, 0x28, 0xd9, 0x78, 0x8a, 0x90, 0x33, 0x26, 0x5f, 0x8f, 0x94, 0x32, 0x9b, 0xb7, 0x21, 0xd3, 0xc8, 0x1e, 0x96, 0x7e, 0x3a, 0x84, 0xce, 0x07, 0x04, 0x6c, 0x54, 0x2f, 0xc0, 0xf2, 0x26, 0x23, 0xc4, 0xfa, 0x0e, 0xc8, 0xb1, 0x1c, 0x79, 0x83, 0xdb, 0x04, 0xc0, 0x6e, 0xa2, 0x28, 0x10, 0x01, 0xa3, 0xfd, 0xc8, 0x1d, 0x1d, 0x70, 0x67, 0x3d, 0xc2, 0xe6, 0x0c, 0xb5, 0x97, 0x63, 0x4d, 0x97, 0x8f, 0x03, 0x68, 0xef, 0x5c, 0xe0, 0xf9, 0x42, 0xa0, 0x7d, 0x83, 0xe1, 0x97, 0xec, 0xe0, 0x12, 0x98, 0x7a, 0x4a, 0x90, 0x2b, 0xfb, 0x4b, 0x23, 0x3d, 0xa9, 0x96, 0x7c, 0x78, 0xec, 0x7a, 0xec, 0x57, 0x39, 0xc9, 0xa6, 0xc3, 0x76, 0xc2, 0x47, 0x89, 0x01, 0x9a, 0xd6, 0x4b, 0x65, 0x88, 0xa8, 0x78, 0x7f, 0x99, 0x87, 0xb9, 0xe9, 0x3a, 0xe6, 0xc9, 0xe2, 0xce, 0xc8, 0xe9, 0xc2, 0xcb, 0x5e, 0xf9, 0x9e, 0x77, 0xbf, 0x0e, 0x9f, 0x18, 0x6b, 0x89, 0xed, 0x1c, 0xe0, 0x14, 0x61, 0xb8, 0x44, 0xd7, 0xfe, 0xb2, 0x7b, 0x81, 0x90, 0xb0, 0x84, 0x0c, 0x4a, 0xaf, 0xbd, 0xef, 0x10, 0x6d, 0x1f, 0xf4, 0xc7, 0x18, 0x55, 0xbf, 0x03, 0x8c, 0x85, 0xeb, 0xd5, 0x1f, 0x48, 0x1d, 0x33, 0xe2, 0x0e, 0x44, 0x27, 0xcb, 0x4d, 0x0d, 0x11, 0xe4, 0x95, 0xb0, 0xec, 0x06, 0x1d, 0x18, 0x7d, 0x00, 0x3f, 0xe4, 0xbe, 0x64, 0x89, 0x07, 0xab, 0x65, 0xb7, 0x87, 0x34, 0xfa, 0x9f, 0x50, 0x96, 0x81, 0x7c, 0x69, 0xb8, 0xf5, 0x7c, 0xa7, 0xc5, 0x2f, 0xff, 0x94, 0x53, 0xfb, 0x8d, 0x07, 0xf6, 0xc5, 0x9c, 0x61, 0xb6, 0x28, 0xba, 0x72, 0x91, 0x35, 0x70, 0xc7, 0xc8, 0xc5, 0xd9, 0x7e, 0x6a, 0x5b, 0x22, 0x27, 0x07, 0x66, 0xfa, 0x44, 0x2c, 0x7a, 0x30, 0x76, 0xdb, 0xdb, 0x68, 0x10, 0xdc, 0x87, 0x1d, 0xa6, 0xab, 0x3f, 0x8e, 0xf7, 0xeb, 0x22, 0x85, 0x56, 0x95, 0x3e, 0xd3, 0xe4, 0xa0, 0x7f, 0xdc, 0x8e, 0x15, 0x3f, 0x99, 0xdc, 0x31, 0xe4, 0x17, 0x2a, 0x97, 0xd4, 0xaa, 0x64, 0x42, 0xaf, 0x98, 0x53, 0x5e, 0xf7, 0xf6, 0x70, 0xe0, 0xba, 0x57, 0xc3, 0x92, 0x3c, 0x42, 0x1f, 0x92, 0x0b, 0x89, 0x97, 0x13, 0x78, 0xc9, 0x49, 0xe4, 0xb5, 0xd8, 0x47, 0xcb, 0xd3, 0x37, 0x49, 0xc5, 0xee, 0x2b, 0x6f, 0x96, 0x84, 0x65, 0xda, 0xff, 0x76, 0xf4, 0x18, 0x6d, 0x6b, 0x79, 0xb4, 0xbd, 0x5b, 0x3f, 0x0e, 0xd0, 0xf0, 0xb8, 0xcf, 0xec, 0xc6, 0xe1, 0x9d, 0xa6, 0xe9, 0x2b, 0x3c, 0x70, 0xc7, 0xa6, 0x08, 0x0a, 0x64, 0xc0, 0x5c, 0xa8, 0xa2, 0x62, 0x4b, 0xcb, 0x19, 0x57, 0x55, 0xed, 0x75, 0x83, 0x6b, 0x70, 0x72, 0xf8, 0xb4, 0x88, 0xfa, 0x9f, 0x13, 0x47, 0x6a, 0x3b, 0x8e, 0xbf, 0x53, 0x84, 0x12, 0xe9, 0x41, 0x41, 0x6b, 0xcb, 0xb6, 0x62, 0xe4, 0x69, 0xe8, 0x15, 0xb9, 0x55, 0x70, 0x23, 0x69, 0xa5, 0xa5, 0x71, 0x52, 0xf0, 0x2d, 0x4e, 0x9d, 0x03, 0x05, 0x95, 0x3f, 0x31, 0x82, 0x92, 0x79, 0x38, 0xe0, 0xd8, 0xa9, 0x45, 0x8e, 0x6a, 0xbc, 0xf8, 0x08, 0xad, 0xf6, 0xb4, 0x85, 0xe4, 0x81, 0xdf, 0x97, 0xe4, 0x73, 0x67, 0xa2, 0x45, 0xf1, 0x5b, 0x40, 0x88, 0x38, 0xab, 0x6b, 0x4b, 0xb4, 0xce, 0x20, 0x63, 0x6e, 0x4f, 0x35, 0xf0, 0x83, 0xb4, 0x4d, 0xfe, 0xae, 0x51, 0xa0, 0x10, 0x12, 0xfa, 0x50, 0xfd, 0x6d, 0xec, 0x24, 0x49, 0x9b, 0x8e, 0x79, 0x51, 0xdf, 0xb9, 0xc2, 0x08, 0x71, 0x73, 0xad, 0xa4, 0x9e, 0x5a, 0x15, 0xcf, 0xfb, 0x26, 0xf7, 0xc6, 0xd5, 0xe8, 0x57, 0x1d, 0x03, 0xe7, 0xc1, 0xbd, 0x3b, 0xef, 0x90, 0x2c, 0xdb, 0xaf, 0xee, 0x31, 0x80, 0xf9, 0x5f, 0xc7, 0x26, 0xd0, 0xf3, 0x4a, 0x2f, 0x68, 0xd0, 0xfc, 0xa3, 0x7b, 0x42, 0x14, 0x6f, 0xcd, 0xa6, 0x5e, 0xc5, 0x38, 0x82, 0x7e, 0xf8, 0x87, 0xff, 0x74, 0x9a, 0x7a, 0x41, 0xab, 0x5c, 0x31, 0x60, 0x1f, 0xe0, 0xfb, 0x04, 0x5a, 0xa1, 0x2f, 0xd3, 0x45, 0x42, 0xea, 0x2b, 0xf2, 0x1a, 0xe4, 0x13, 0x20, 0xcd, 0xa7, 0x53, 0x53, 0x3f, 0x30, 0xc4, 0x8f, 0xd2, 0x3e, 0xc6, 0xc6, 0xbb, 0x0b, 0x14, 0x25, 0xe3, 0x61, 0x45, 0x8a, 0x9d, 0xc0, 0xf3, 0xfe, 0x7f, 0x7f, 0xd8, 0x42, 0x76, 0x41, 0x18, 0x06, 0x3c, 0x2c, 0x08, 0x2c, 0x20, 0x00, 0x62, 0xf7, 0xa7, 0x63, 0x01, 0xb6, 0x9f, 0x55, 0x40, 0xd3, 0x5a, 0xc3, 0x62, 0xed, 0xde, 0x64, 0x63, 0x7d, 0x15, 0x5f, 0x1d, 0x19, 0x52, 0x6e, 0xb1, 0xdc, 0x40, 0xd4, 0x6a, 0x66, 0x15, 0x47, 0x6d, 0x21, 0x16, 0x38, 0xd1, 0x1b, 0x96, 0x60, 0x32, 0x97, 0x35, 0x12, 0x28, 0xbc, 0x3d, 0x60, 0xa6, 0x53, 0x40, 0x73, 0x34, 0x98, 0x57, 0x61, 0x4c, 0x25, 0xbf, 0xa6, 0x73, 0xf8, 0x8b, 0xdf, 0xd5, 0xcc, 0x17, 0xd7, 0x3b, 0xf6, 0xd3, 0xda, 0x99, 0x73, 0x02, 0x0d, 0x32, 0xf6, 0x7b, 0x14, 0x18, 0xd7, 0xa2, 0x97, 0xa2, 0x0f, 0xaf, 0xec, 0x42, 0x60, 0xfb, 0x39, 0x71, 0x74, 0x20, 0xcf, 0xf9, 0x03, 0x03, 0xcf, 0x4d, 0xaa, 0x44, 0x26, 0xf0, 0x5c, 0x47, 0x24, 0x03, 0x5a, 0x42, 0x83, 0x12, 0x57, 0x0b, 0x64, 0x44, 0x6a, 0x56, 0x74, 0x7a, 0x69, 0xc6, 0x26, 0xbe, 0x42, 0xf8, 0x3d, 0x10, 0x4a, 0xdd, 0x14, 0x79, 0x8a, 0xea, 0x4c, 0x40, 0x9f, 0xdd, 0x84, 0xce, 0xce, 0xc3, 0x80, 0x60, 0xb4, 0xc5, 0x2d, 0xf5, 0x2f, 0x9f, 0x89, 0x1f, 0x16, 0x64, 0x75, 0xc5, 0x28, 0x11, 0xf7, 0x3a, 0x4f, 0xcf, 0x47, 0x7e, 0xa1, 0x8a, 0xa4, 0x40, 0x9a, 0x42, 0xdb, 0xa6, 0x11, 0x65, 0x6c, 0xa4, 0xfc, 0xa3, 0x5b, 0xe0, 0x1b, 0x5d, 0x41, 0x2d, 0x27, 0x43, 0xf2, 0xb0, 0x4f, 0xd8, 0x2d, 0xd4, 0x3d, 0x36, 0x74, 0x9a, 0xe6, 0xdb, 0x64, 0x05, 0x5d, 0x92, 0xdc, 0xaf, 0x18, 0xe0, 0xbc, 0x36, 0xca, 0xea, 0x13, 0x2c, 0xc9, 0x5c, 0x55, 0x20, 0xb9, 0xa0, 0xac, 0x44, 0x3e, 0xb2, 0x96, 0xa8, 0x78, 0x97, 0xaa, 0x58, 0x04, 0x3f, 0x68, 0x6b, 0x53, 0x00, 0x5e, 0xa1, 0x60, 0x2a, 0x4b, 0x45, 0x39, 0xdf, 0x25, 0xc3, 0x11, 0xb8, 0x75, 0x7e, 0x4b, 0x6d, 0xce, 0x84, 0x38, 0x0a, 0x79, 0x37, 0x8b, 0x5c, 0x3e, 0xb6, 0x0b, 0x71, 0x5a, 0x29, 0x58, 0xc7, 0x60, 0x17, 0x36, 0x04, 0xf6, 0xa3, 0x27, 0x05, 0xcd, 0x79, 0x2c, 0x00, 0xe3, 0x45, 0x85, 0x25, 0xc5, 0x04, 0xd3, 0x32, 0x7c, 0x60, 0x4b, 0xf3, 0x0b, 0x9d, 0xb5, 0x35, 0xee, 0x2e, 0x4d, 0xea, 0x89, 0xfc, 0x8c, 0xb6, 0x91, 0xaa, 0x61, 0xd5, 0x05, 0xfe, 0xcb, 0x60, 0x1d, 0x4e, 0x39, 0x1c, 0xf7, 0x05, 0x89, 0x5f, 0x20, 0x0a, 0xbb, 0xfd, 0x5a, 0xc2, 0x2f, 0x1f, 0x94, 0x6a, 0xa7, 0x9f, 0x53, 0xab, 0x1b, 0xf0, 0xb9, 0xe7, 0xff, 0xa0, 0x7a, 0x47, 0x3d, 0x84, 0x69, 0xf9, 0xeb, 0x7e, 0x09, 0xec, 0xbf, 0x6a, 0x34, 0xc2, 0x32, 0xf8, 0xf3, 0x31, 0x29, 0x92, 0xbe, 0x9e, 0x55, 0x4d, 0x3a, 0x3e, 0x2c, 0x32, 0x43, 0x02, 0x91, 0x6a, 0x76, 0x7c, 0x2e, 0x48, 0xd6, 0x4c, 0xbd, 0xde, 0xe9, 0x71, 0x20, 0xe8, 0x43, 0xaa, 0x40, 0xeb, 0x3f, 0xc5, 0xf4, 0xe8, 0xc9, 0x56, 0xbe, 0x2c, 0xf9, 0xa2, 0x7f, 0x77, 0xc5, 0x22, 0x0c, 0x3e, 0x71, 0xcb, 0xd9, 0x92, 0xed, 0x5a, 0x1f, 0x8d, 0x92, 0x7b, 0x4d, 0x30, 0x0f, 0x43, 0x41, 0xe1, 0xfa, 0xf8, 0x94, 0x88, 0x71, 0x1e, 0x0b, 0xfd, 0xe5, 0x5e, 0x8a, 0x2f, 0xc9, 0x57, 0x17, 0xb2, 0xb9, 0x94, 0x3a, 0xcf, 0x74, 0xa9, 0xb6, 0xb8, 0x52, 0xbc, 0xb8, 0x89, 0x35, 0x39, 0xae, 0x25, 0xa0, 0x81, 0xf9, 0xe0, 0xd7, 0x37, 0x39, 0x07, 0xab, 0xcc, 0x14, 0x2d, 0x84, 0x69, 0xbb, 0x55, 0xf9, 0xb0, 0xea, 0x51, 0x9f, 0xa6, 0xef, 0x3d, 0x7e, 0xd9, 0xdb, 0x1a, 0x81, 0x90, 0x8c, 0xe9, 0x27, 0xea, 0x29, 0x85, 0xe6, 0xcd, 0x4d, 0xa6, 0x4a, 0x10, 0x85, 0x78, 0x9b, 0x8a, 0x96, 0x07, 0x33, 0x52, 0x2d, 0xfc, 0xac, 0xd3, 0x3a, 0xb2, 0x4a, 0x22, 0xfd, 0x08, 0x33, 0x88, 0x45, 0x1c, 0xe5, 0x80, 0x32, 0xdd, 0xc3, 0x30, 0x6a, 0x5d, 0x66, 0xb8, 0x52, 0x91, 0x89, 0x4b, 0xa4, 0xa1, 0xe9, 0xb3, 0x76, 0x53, 0x7a, 0x03, 0x41, 0x7e, 0x87, 0xa8, 0x6a, 0x3a, 0x2f, 0xfc, 0xc4, 0xf1, 0x7c, 0xed, 0xa5, 0x4b, 0xd8, 0xc7, 0xa6, 0xc5, 0xaa, 0xa7, 0xb3, 0xb4, 0xf5, 0x17, 0x64, 0x43, 0x12, 0x0e, 0x3b, 0xde, 0x71, 0x57, 0xc6, 0xca, 0xd5, 0xfd, 0xf8, 0x8b, 0x42, 0x0d, 0xad, 0xb7, 0x43, 0x0c, 0x4b, 0x0e, 0xc7, 0xa8, 0x6a, 0xc3, 0x47, 0x38, 0x51, 0x8f, 0x6e, 0x14, 0xec, 0x7a, 0x92, 0xd4, 0x55, 0xfb, 0xa5, 0xc6, 0x28, 0x20, 0x6a, 0xee, 0x10, 0x37, 0x7d, 0xce, 0x60, 0x86, 0xb8, 0x35, 0xf9, 0x1a, 0xea, 0xfd, 0xe8, 0x0b, 0x18, 0xd6, 0xc7, 0xd9, 0xf2, 0xa6, 0x8a, 0xad, 0x16, 0x68, 0x4d, 0xe5, 0xdd, 0xb5, 0xf8, 0x5b, 0x1b, 0xa9, 0x1f, 0xdd, 0x46, 0xd1, 0xc6, 0x34, 0xea, 0x42, 0x04, 0x2b, 0x0e, 0xb7, 0x19, 0x87, 0xe0, 0x39, 0x8d, 0xb5, 0xd2, 0x4b, 0xf7, 0x1f, 0xed, 0xe0, 0x57, 0xf6, 0xb9, 0x9c, 0x9f, 0x9c, 0xea, 0xcc, 0x36, 0x4a, 0xdd, 0xef, 0x2c, 0x6a, 0x71, 0x66, 0x90, 0x60, 0x4a, 0x12, 0x7a, 0xb6, 0x5a, 0x8a, 0xb8, 0xfb, 0xf1, 0x2b, 0x68, 0x0d, 0x0d, 0x2c, 0xd4, 0xd0, 0x21, 0x09, 0x2f, 0x14, 0x2f, 0x5f, 0xa6, 0x42, 0x70, 0x48, 0xa2, 0xbc, 0x4d, 0x39, 0x21, 0x5c, 0x5a, 0x56, 0x70, 0xf4, 0x9c, 0x7c, 0x31, 0x6c, 0x6f, 0x7b, 0x3a, 0xa6, 0x3a, 0xf9, 0x28, 0x53, 0x0c, 0x85, 0x64, 0x4b, 0xde, 0x9c, 0x5a, 0x01, 0xd8, 0xea, 0x98, 0x19, 0x72, 0x17, 0xe0, 0x32, 0xca, 0x13, 0x1d, 0xac, 0xc7, 0x80, 0x49, 0x2b, 0xc7, 0x94, 0xe8, 0xb7, 0xb3, 0xae, 0x62, 0x82, 0xfd, 0x2f, 0xe4, 0x2a, 0x25, 0xf1, 0x96, 0xec, 0xb1, 0x2e, 0x7d, 0x9f, 0x31, 0x53, 0xbf, 0x32, 0x8f, 0x2a, 0xd5, 0xe0, 0xcb, 0xe9, 0xf3, 0xa4, 0x0e, 0x53, 0x48, 0xfb, 0x88, 0x6a, 0x23, 0x5d, 0x70, 0xa8, 0x18, 0x5f, 0x9f, 0xc4, 0xb4, 0xc7, 0x99, 0x47, 0xbc, 0xd3, 0x37, 0x2c, 0x38, 0xdf, 0xf9, 0x2d, 0x83, 0xfc, 0x41, 0xf7, 0x0f, 0x5b, 0xb3, 0xe9, 0x90, 0x58, 0xd5, 0xeb, 0xad, 0xc7, 0x69, 0xc9, 0xb5, 0x2f, 0x24, 0xa0, 0x2a, 0x98, 0x1c, 0x6a, 0xc9, 0x6f, 0x6a, 0x7a, 0xa3, 0x7a, 0x95, 0xc6, 0x7a, 0xc0, 0x23, 0xe6, 0xdf, 0xe2, 0xc2, 0x32, 0x7b, 0x67, 0xb3, 0xee, 0x1a, 0x04, 0xf0, 0x8d, 0x7f, 0x76, 0xac, 0x59, 0x1c, 0xca, 0x12, 0xeb, 0x59, 0xcf, 0xf6, 0x99, 0xba, 0xf0, 0xcc, 0x39, 0x87, 0x87, 0x91, 0xca, 0xcd, 0xa1, 0x52, 0x78, 0xfa, 0x50, 0x78, 0xac, 0xe0, 0xa6, 0x7a, 0x58, 0x53, 0x95, 0x84, 0x81, 0xa2, 0xef, 0x08, 0xe3, 0x4a, 0x2f, 0x36, 0x4a, 0x0d, 0x82, 0x1f, 0xba, 0xa0, 0x7e, 0x67, 0xdb, 0xb3, 0x29, 0x6a, 0x96, 0xf4, 0x98, 0xce, 0xe1, 0x68, 0xd4, 0xf9, 0x42, 0xb7, 0xea, 0xfb, 0x93, 0xb4, 0x46, 0x3b, 0x49, 0xbf, 0x91, 0xcc, 0xc9, 0x0c, 0xa9, 0xe1, 0xc8, 0x19, 0xae, 0xbe, 0x65, 0x84, 0xaf, 0x16, 0xb1, 0x6d, 0x7e, 0x32, 0x1b, 0xc0, 0x9d, 0x63, 0x0c, 0x84, 0x43, 0xb2, 0x67, 0x1e, 0xfb, 0x66, 0xe0, 0x57, 0xde, 0x12, 0x05, 0x0d, 0x14, 0x90, 0x87, 0x47, 0x72, 0xe9, 0x4f, 0xab, 0xa9, 0x9d, 0xc9, 0x48, 0x1c, 0x17, 0x16, 0x0b, 0x15, 0x75, 0x21, 0x6f, 0x87, 0xff, 0x2d, 0x80, 0x11, 0xd0, 0x04, 0xeb, 0x52, 0xa4, 0x96, 0xd8, 0x5a, 0xd7, 0x92, 0xe4, 0x2d, 0xa3, 0xd7, 0x0d, 0x45, 0xa2, 0x40, 0x9f, 0xfa, 0x41, 0x71, 0x57, 0x33, 0x32, 0xad, 0x1a, 0x51, 0x81, 0x0f, 0x17, 0xa1, 0xc6, 0xa9, 0xb5, 0x16, 0x5c, 0x9c, 0xfe, 0x1d, 0x39, 0x60, 0x13, 0x5f, 0x07, 0x54, 0x20, 0x7c, 0x77, 0x49, 0xcd, 0xc7, 0x17, 0x56, 0xce, 0xa6, 0xa3, 0xe5, 0xe1, 0xa0, 0xf7, 0xf1, 0x04, 0xfc, 0xab, 0x25, 0xea, 0x21, 0xf5, 0x87, 0x8e, 0x53, 0x5b, 0x1f, 0x9b, 0x71, 0x65, 0x77, 0xc2, 0x6b, 0xcd, 0x6a, 0x57, 0x5e, 0x48, 0xbb, 0x27, 0x73, 0xb3, 0xa7, 0x13, 0xcc, 0x1f, 0x15, 0x3e, 0x09, 0x2c, 0xdf, 0xdd, 0x96, 0x3e, 0x9b, 0xc1, 0xa8, 0xe2, 0x4e, 0xd0, 0x38, 0x7a, 0xf0, 0x03, 0x12, 0x82, 0xff, 0x08, 0x7c, 0xd8, 0x99, 0x12, 0x20, 0x6e, 0xa6, 0x35, 0xf4, 0xdc, 0x07, 0xb2, 0x3d, 0x04, 0x5c, 0x12, 0x5e, 0x64, 0x4a, 0x30, 0x1d, 0xe5, 0x05, 0x17, 0xae, 0x46, 0x83, 0xba, 0x44, 0xde, 0x8c, 0x23, 0x59, 0x12, 0x67, 0x77, 0xc0, 0x99, 0x80, 0x2b, 0xa8, 0x06, 0x83, 0x77, 0x82, 0x43, 0x5e, 0xf2, 0x37, 0xda, 0xc3, 0xe7, 0x83, 0x3b, 0xe4, 0xf0, 0xea, 0x3d, 0xff, 0x06, 0xbe, 0x2b, 0x40, 0x63, 0xad, 0x00, 0x23, 0x07, 0x1c, 0x17, 0x1d, 0x42, 0x08, 0x7c, 0x18, 0x99, 0xc6, 0x53, 0xc7, 0x39, 0xc8, 0xfc, 0x9d, 0x0a, 0xb2, 0x53, 0xfe, 0xc4, 0x80, 0x42, 0x33, 0xa5, 0xdb, 0x01, 0xbf, 0x24, 0x95, 0xe8, 0x2a, 0x7d, 0x32, 0x84, 0xfd, 0xab, 0x61, 0xc7, 0xe4, 0x07, 0x77, 0x1b, 0xc0, 0x64, 0x89, 0x7b, 0x17, 0x66, 0x47, 0x0e, 0xdf, 0x90, 0x11, 0x3a, 0x31, 0x42, 0x73, 0x71, 0xd3, 0x74, 0x56, 0xfd, 0xd4, 0x3c, 0x4c, 0xcb, 0xe2, 0x35, 0x3c, 0xa4, 0x6a, 0x86, 0x31, 0x01, 0xcf, 0x69, 0x18, 0x20, 0x01, 0xa3, 0x3b, 0x01, 0x45, 0x0f, 0x52, 0x79, 0x3f, 0xcc, 0x9f, 0xed, 0x56, 0xaa, 0xbb, 0x15, 0x13, 0xd5, 0x65, 0x3c, 0xff, 0x8c, 0x21, 0xd2, 0xf9, 0x92, 0x72, 0x71, 0x4b, 0xfb, 0x3d, 0x92, 0xc3, 0xf5, 0x2b }, .spki_len = 2614, }, { .name = "ML-DSA 87", .parameter_set = CKP_IBM_ML_DSA_87, .rho = { 0x69, 0x24, 0xbb, 0x42, 0x57, 0xa7, 0xb9, 0xaf, 0xf0, 0x95, 0xc3, 0x0b, 0xb3, 0x5c, 0x6a, 0xe4, 0x19, 0x82, 0x63, 0x12, 0x0f, 0x80, 0x39, 0xaa, 0x4e, 0x78, 0xe1, 0x74, 0xa7, 0x86, 0xce, 0x00, }, .rho_len = 32, .seed = { 0x3b, 0x9a, 0xc2, 0xc1, 0x42, 0x2a, 0x1a, 0xe8, 0x02, 0xdd, 0xd7, 0x46, 0x4d, 0x3f, 0x32, 0x72, 0x9a, 0x3c, 0x7d, 0xe8, 0x94, 0xd5, 0x06, 0xac, 0xad, 0x25, 0xce, 0xb3, 0x72, 0xea, 0x31, 0x49, }, .seed_len = 32, .tr = { 0xc9, 0x87, 0x80, 0xdc, 0xd1, 0x31, 0x4b, 0xaa, 0x29, 0xb9, 0xb8, 0x07, 0x75, 0x4c, 0x47, 0xde, 0x5d, 0xca, 0x95, 0x40, 0x64, 0xf2, 0x85, 0x28, 0xb8, 0x15, 0xfe, 0x27, 0xb7, 0x9a, 0xc5, 0x06, 0xb3, 0xad, 0x76, 0x29, 0xd2, 0xc9, 0x71, 0xab, 0x8f, 0x28, 0x2e, 0x0c, 0x6e, 0x7e, 0x55, 0x48, 0xee, 0x0e, 0x11, 0x32, 0x42, 0xb7, 0xa0, 0xe0, 0x64, 0xa6, 0xdb, 0xce, 0x30, 0xc5, 0x61, 0x9b, }, .tr_len = 64, .s1 = { 0x19, 0x80, 0x08, 0x89, 0xa0, 0x44, 0x04, 0xb5, 0x00, 0x13, 0xc0, 0x88, 0xc1, 0x30, 0x29, 0x62, 0x12, 0x4c, 0xd3, 0xb4, 0x91, 0x0a, 0x35, 0x2c, 0x43, 0x12, 0x31, 0x19, 0x99, 0x65, 0x22, 0x18, 0x52, 0x02, 0xc3, 0x85, 0x23, 0x44, 0x0d, 0x90, 0x24, 0x4a, 0x1a, 0x30, 0x22, 0x44, 0x28, 0x61, 0x81, 0x06, 0x29, 0x18, 0x97, 0x68, 0x0a, 0x20, 0x09, 0x08, 0x32, 0x6a, 0x44, 0xa4, 0x4c, 0x44, 0x90, 0x21, 0x8a, 0x16, 0x68, 0x9a, 0xa8, 0x51, 0x1a, 0xa5, 0x2c, 0x62, 0x46, 0x8d, 0x04, 0xc3, 0x40, 0xd3, 0x86, 0x28, 0x60, 0xa4, 0x60, 0x13, 0x18, 0x70, 0x84, 0x94, 0x8c, 0x63, 0xc0, 0x44, 0x04, 0xa9, 0x28, 0x20, 0x08, 0x20, 0x43, 0x16, 0x2a, 0x23, 0x29, 0x2d, 0x1a, 0xb1, 0x29, 0x48, 0xb6, 0x09, 0x21, 0x88, 0x31, 0x00, 0xc5, 0x30, 0x00, 0xc4, 0x8c, 0xd9, 0x82, 0x68, 0xe1, 0x30, 0x4c, 0x63, 0x32, 0x45, 0x0c, 0x32, 0x86, 0x18, 0x08, 0x31, 0x91, 0x98, 0x0d, 0x10, 0xb8, 0x70, 0x9b, 0x30, 0x22, 0x64, 0x04, 0x08, 0x93, 0xa4, 0x8c, 0x21, 0xc9, 0x70, 0x0c, 0x35, 0x71, 0x5b, 0x00, 0x0d, 0x14, 0x31, 0x22, 0xcc, 0x98, 0x10, 0x21, 0x04, 0x80, 0x9b, 0x28, 0x64, 0x1c, 0x30, 0x80, 0x21, 0x30, 0x71, 0x18, 0x33, 0x50, 0x24, 0x25, 0x44, 0x08, 0x17, 0x8c, 0xc0, 0x08, 0x48, 0x84, 0x44, 0x90, 0x48, 0x98, 0x30, 0xca, 0x44, 0x00, 0x09, 0x19, 0x51, 0x19, 0x23, 0x0c, 0x52, 0x20, 0x0e, 0x49, 0x06, 0x32, 0x1c, 0x15, 0x4e, 0x19, 0x48, 0x85, 0x13, 0x25, 0x49, 0xa3, 0x00, 0x04, 0x08, 0x15, 0x6d, 0x20, 0x41, 0x0c, 0xda, 0x42, 0x52, 0xc1, 0x34, 0x8c, 0x00, 0x31, 0x69, 0x43, 0x82, 0x24, 0x64, 0x94, 0x6d, 0x1c, 0x81, 0x11, 0x01, 0x96, 0x21, 0x4b, 0x02, 0x00, 0xca, 0x28, 0x84, 0xcc, 0x46, 0x64, 0x51, 0x18, 0x6a, 0x18, 0x10, 0x00, 0xa4, 0x98, 0x21, 0x60, 0xb0, 0x68, 0x03, 0x94, 0x6c, 0x94, 0x48, 0x51, 0x80, 0x40, 0x46, 0x92, 0x22, 0x2c, 0x23, 0x44, 0x69, 0x98, 0x26, 0x4d, 0x1c, 0x01, 0x08, 0x52, 0x02, 0x20, 0x8a, 0xa6, 0x08, 0x0a, 0x31, 0x61, 0x93, 0x40, 0x0e, 0x9c, 0xc8, 0x11, 0x81, 0x32, 0x2e, 0x21, 0x15, 0x84, 0x84, 0xc2, 0x41, 0x00, 0x22, 0x72, 0x54, 0x22, 0x62, 0x58, 0x06, 0x92, 0x48, 0x48, 0x44, 0x11, 0x27, 0x04, 0x04, 0xc0, 0x11, 0x92, 0x82, 0x45, 0xa1, 0xc6, 0x8c, 0xe3, 0x32, 0x66, 0xc1, 0x38, 0x72, 0x5a, 0x86, 0x01, 0x0c, 0xc9, 0x90, 0x84, 0x34, 0x08, 0x58, 0xa8, 0x60, 0x80, 0xc0, 0x70, 0xd0, 0x26, 0x62, 0x9b, 0x30, 0x2a, 0x04, 0x29, 0x69, 0x04, 0x10, 0x8d, 0x0b, 0xb9, 0x04, 0x50, 0x46, 0x28, 0x50, 0x48, 0x24, 0xd0, 0x48, 0x05, 0xa2, 0x48, 0x02, 0xc3, 0x20, 0x8c, 0xa0, 0x14, 0x00, 0x41, 0x38, 0x21, 0x4b, 0x24, 0x01, 0x04, 0xb5, 0x49, 0x42, 0x00, 0x00, 0x0c, 0x24, 0x28, 0x12, 0x40, 0x84, 0xa2, 0x20, 0x44, 0x9b, 0x06, 0x90, 0x63, 0xc0, 0x88, 0x8c, 0x14, 0x21, 0x49, 0x12, 0x10, 0x54, 0x16, 0x24, 0x20, 0x87, 0x44, 0x50, 0x10, 0x85, 0x0c, 0xb5, 0x64, 0xdb, 0x24, 0x41, 0xd0, 0x42, 0x29, 0x9a, 0x16, 0x8a, 0x21, 0xb4, 0x4c, 0x13, 0xb7, 0x70, 0x10, 0xc0, 0x85, 0x19, 0x02, 0x69, 0xcc, 0x40, 0x61, 0x1c, 0x48, 0x46, 0x98, 0x06, 0x25, 0x60, 0x14, 0x46, 0xe4, 0x22, 0x62, 0x24, 0x27, 0x22, 0x62, 0x24, 0x29, 0x44, 0xc6, 0x2d, 0x08, 0x31, 0x84, 0x20, 0x32, 0x21, 0x04, 0xb4, 0x61, 0x0a, 0x38, 0x12, 0xd9, 0x28, 0x44, 0xa4, 0x08, 0x20, 0xcc, 0xa8, 0x29, 0x0b, 0x21, 0x31, 0x0a, 0x34, 0x29, 0x03, 0x21, 0x40, 0xc1, 0xa2, 0x6c, 0x8a, 0x16, 0x12, 0x52, 0xa6, 0x64, 0xa3, 0xb2, 0x51, 0x04, 0x29, 0x51, 0xc4, 0x04, 0x91, 0x63, 0xb0, 0x2d, 0x14, 0x44, 0x30, 0x8c, 0x40, 0x66, 0x0c, 0x40, 0x0c, 0x01, 0xa5, 0x2c, 0x09, 0x94, 0x2d, 0x62, 0xc6, 0x11, 0x03, 0x98, 0x50, 0x19, 0x10, 0x4d, 0x19, 0xa8, 0x28, 0xd3, 0x86, 0x40, 0xc0, 0x30, 0x65, 0x54, 0xa6, 0x71, 0xe0, 0xb4, 0x85, 0x9b, 0x86, 0x10, 0x04, 0x36, 0x69, 0xd0, 0x46, 0x29, 0x18, 0xa3, 0x71, 0x40, 0x22, 0x49, 0x00, 0x43, 0x85, 0xcb, 0x40, 0x28, 0x89, 0x36, 0x66, 0x41, 0x22, 0x69, 0xa4, 0x28, 0x51, 0xd9, 0x80, 0x29, 0x14, 0x07, 0x21, 0xda, 0x80, 0x91, 0x1b, 0x26, 0x50, 0x5b, 0xa0, 0x60, 0x99, 0x42, 0x71, 0x50, 0x88, 0x49, 0x10, 0x23, 0x09, 0x5a, 0x90, 0x21, 0x22, 0x27, 0x8e, 0x43, 0xb2, 0x70, 0x0c, 0xc9, 0x4c, 0xa4, 0x02, 0x70, 0x92, 0x40, 0x10, 0x0a, 0x39, 0x70, 0x02, 0x36, 0x0e, 0x11, 0x30, 0x41, 0xd8, 0x40, 0x2d, 0x1b, 0x24, 0x6d, 0xc3, 0x92, 0x61, 0x4c, 0x86, 0x8d, 0x21, 0xb8, 0x00, }, .s1_len = 672, .s2 = { 0xd3, 0x24, 0x22, 0x12, 0xc8, 0x21, 0x12, 0x99, 0x85, 0x09, 0x16, 0x0c, 0x5a, 0xa2, 0x24, 0x09, 0x34, 0x42, 0x10, 0xa2, 0x24, 0x03, 0x42, 0x8c, 0xc0, 0xb2, 0x8d, 0x12, 0xb6, 0x69, 0x63, 0x34, 0x0d, 0xcc, 0xb0, 0x65, 0xa1, 0x12, 0x11, 0x4a, 0x38, 0x69, 0xcc, 0x14, 0x81, 0x58, 0x44, 0x09, 0x54, 0xa6, 0x80, 0x0c, 0xa8, 0x05, 0xc4, 0x38, 0x8a, 0x84, 0x06, 0x01, 0x9b, 0x32, 0x2d, 0x83, 0x12, 0x90, 0x09, 0x02, 0x60, 0xa1, 0x28, 0x88, 0x58, 0x10, 0x41, 0x24, 0x40, 0x02, 0x19, 0x34, 0x48, 0x18, 0xa0, 0x4d, 0x00, 0x10, 0x62, 0x13, 0x22, 0x50, 0xe3, 0x38, 0x21, 0x9a, 0x96, 0x21, 0x53, 0x08, 0x80, 0x51, 0x26, 0x01, 0x99, 0xc4, 0x28, 0x1b, 0xb9, 0x71, 0x04, 0x97, 0x84, 0x04, 0x05, 0x2c, 0xa0, 0xc2, 0x10, 0xd3, 0x42, 0x81, 0x81, 0x42, 0x4d, 0x61, 0x84, 0x6c, 0x5a, 0x30, 0x49, 0x1b, 0xc2, 0x24, 0xc0, 0x20, 0x28, 0xca, 0x92, 0x2d, 0x4a, 0x90, 0x10, 0x04, 0x27, 0x86, 0x4c, 0x96, 0x21, 0x09, 0x19, 0x45, 0x14, 0x82, 0x2c, 0x11, 0xa6, 0x91, 0x13, 0xb8, 0x04, 0x03, 0x18, 0x70, 0x01, 0xa2, 0x51, 0x52, 0x14, 0x49, 0x5a, 0x02, 0x30, 0xcb, 0x30, 0x2c, 0x94, 0x10, 0x2c, 0x00, 0x49, 0x86, 0x09, 0xa0, 0x25, 0xc2, 0x12, 0x4c, 0x1b, 0x02, 0x69, 0x40, 0xa4, 0x44, 0x41, 0x16, 0x62, 0x02, 0x25, 0x28, 0xdc, 0xa2, 0x2d, 0x00, 0x16, 0x42, 0x58, 0x30, 0x66, 0x5b, 0x86, 0x24, 0xd4, 0x24, 0x48, 0xdb, 0x26, 0x0c, 0x4c, 0x08, 0x85, 0x01, 0x90, 0x49, 0x21, 0x24, 0x41, 0x54, 0x06, 0x84, 0x02, 0x43, 0x4a, 0x24, 0x42, 0x05, 0x40, 0x14, 0x48, 0xca, 0x44, 0x84, 0xc0, 0x42, 0x0c, 0x98, 0x26, 0x04, 0x9c, 0xa2, 0x05, 0xd1, 0xc2, 0x51, 0x13, 0x01, 0x86, 0x1c, 0xa1, 0x50, 0xd9, 0x02, 0x50, 0x0c, 0x39, 0x86, 0x8c, 0x00, 0x31, 0x22, 0x05, 0x48, 0xd3, 0x10, 0x81, 0x12, 0x48, 0x05, 0xd1, 0x08, 0x69, 0x62, 0x38, 0x2c, 0x0a, 0x23, 0x70, 0x9b, 0x44, 0x72, 0xe3, 0x48, 0x6e, 0x22, 0x96, 0x70, 0x14, 0x33, 0x6c, 0xd8, 0x90, 0x29, 0x03, 0x00, 0x49, 0x63, 0x20, 0x8a, 0x03, 0x91, 0x25, 0x08, 0x89, 0x21, 0xc0, 0x82, 0x0c, 0x99, 0x40, 0x32, 0xc2, 0x34, 0x4e, 0x4b, 0x98, 0x69, 0x09, 0x80, 0x44, 0xe4, 0x04, 0x69, 0x94, 0x20, 0x09, 0x99, 0x24, 0x6d, 0x09, 0xa9, 0x60, 0x01, 0x29, 0x2d, 0xc8, 0x42, 0x28, 0x8a, 0x34, 0x02, 0xe4, 0x08, 0x70, 0x0c, 0x23, 0x6e, 0x0a, 0x05, 0x49, 0x64, 0x44, 0x2a, 0x82, 0xc8, 0x00, 0x02, 0x48, 0x31, 0xcb, 0x90, 0x50, 0x1c, 0x05, 0x68, 0x12, 0x12, 0x2c, 0xd0, 0x80, 0x0c, 0x59, 0x48, 0x61, 0xcb, 0xa6, 0x09, 0x9c, 0xc0, 0x81, 0x42, 0xb8, 0x00, 0x24, 0x41, 0x8a, 0x94, 0x20, 0x40, 0x42, 0x14, 0x4d, 0x19, 0x46, 0x62, 0x18, 0x05, 0x09, 0x24, 0x33, 0x6a, 0xd4, 0x00, 0x61, 0x12, 0x48, 0x32, 0x8a, 0x04, 0x72, 0x93, 0xb4, 0x69, 0x62, 0xc2, 0x71, 0x41, 0xa6, 0x89, 0x44, 0x96, 0x31, 0x62, 0x30, 0x46, 0x83, 0x42, 0x6c, 0x00, 0x19, 0x22, 0x09, 0x46, 0x4d, 0x8b, 0x06, 0x49, 0xe1, 0xb0, 0x70, 0x42, 0x44, 0x31, 0xc1, 0x80, 0x65, 0x9c, 0x00, 0x24, 0x11, 0xa8, 0x31, 0x13, 0x21, 0x2c, 0x4b, 0x46, 0x28, 0x1b, 0x18, 0x0d, 0x88, 0x42, 0x70, 0xd1, 0xb0, 0x0d, 0x90, 0xc8, 0x45, 0xda, 0xc2, 0x48, 0x59, 0x14, 0x26, 0x22, 0x44, 0x00, 0xc2, 0x94, 0x41, 0x50, 0xc8, 0x04, 0x18, 0x00, 0x00, 0xcb, 0xa6, 0x24, 0x19, 0x02, 0x10, 0x10, 0x89, 0x0c, 0x18, 0x22, 0x21, 0x62, 0xa8, 0x81, 0xc8, 0x92, 0x48, 0xd3, 0x94, 0x20, 0x82, 0x06, 0x72, 0x09, 0xa8, 0x90, 0x0c, 0x49, 0x8a, 0x41, 0x86, 0x28, 0x19, 0xc5, 0x80, 0x9a, 0x18, 0x4d, 0x14, 0x10, 0x2e, 0x22, 0x12, 0x52, 0x00, 0x08, 0x12, 0x0c, 0x33, 0x45, 0x63, 0xc6, 0x30, 0x10, 0x93, 0x4c, 0x60, 0xc6, 0x31, 0xdc, 0x40, 0x0e, 0x98, 0x82, 0x50, 0x60, 0x02, 0x2a, 0xd2, 0x22, 0x40, 0xe4, 0x06, 0x2d, 0xdb, 0x32, 0x0e, 0xca, 0x32, 0x4e, 0xd4, 0x18, 0x24, 0x08, 0xc3, 0x28, 0x4a, 0xc2, 0x68, 0xe2, 0x80, 0x40, 0xa1, 0xc8, 0x64, 0x51, 0xc2, 0x65, 0xcb, 0x16, 0x60, 0x23, 0x09, 0x4c, 0x82, 0x04, 0x68, 0xd9, 0x22, 0x2e, 0x1c, 0x49, 0x92, 0x42, 0x24, 0x21, 0x00, 0x37, 0x0e, 0xc8, 0x12, 0x72, 0x64, 0x08, 0x25, 0x0a, 0x20, 0x2a, 0x58, 0x24, 0x04, 0x59, 0x16, 0x4c, 0x08, 0x17, 0x30, 0x00, 0x46, 0x05, 0x12, 0x90, 0x40, 0x03, 0x07, 0x21, 0x52, 0xc0, 0x64, 0x1c, 0x83, 0x6d, 0x9c, 0x32, 0x2e, 0x11, 0x15, 0x8a, 0x10, 0x35, 0x88, 0x5a, 0xa0, 0x8d, 0xd9, 0x80, 0x48, 0x03, 0xb6, 0x4c, 0x01, 0x10, 0x65, 0x10, 0x86, 0x40, 0x11, 0x01, 0x42, 0x0a, 0xc1, 0x64, 0xdb, 0x22, 0x4d, 0x64, 0xb2, 0x51, 0x02, 0x36, 0x0d, 0x93, 0x46, 0x31, 0x14, 0xb6, 0x68, 0x63, 0x84, 0x29, 0xc8, 0x10, 0x24, 0x94, 0x30, 0x08, 0x19, 0x37, 0x02, 0x14, 0x82, 0x45, 0x88, 0x28, 0x40, 0x54, 0xa8, 0x29, 0x90, 0x14, 0x12, 0x61, 0x36, 0x12, 0x0b, 0x09, 0x8c, 0xa4, 0x98, 0x28, 0xc2, 0x92, 0x45, 0x4c, 0x00, 0x60, 0x63, 0xc4, 0x81, 0xc0, 0x36, 0x25, 0xca, 0x88, 0x2d, 0x24, 0x40, 0x30, 0xd3, 0xa8, 0x2d, 0xc9, 0xc8, 0x25, 0xd2, 0x84, 0x48, 0x00, 0x32, 0x92, 0x50, 0xa2, 0x71, 0xd3, 0x44, 0x0d, 0x22, 0x34, 0x60, 0x12, 0x13, 0x12, }, .s2_len = 768, .t0 = { 0x86, 0x8c, 0x5f, 0x86, 0x20, 0x79, 0x4a, 0x05, 0x0e, 0x20, 0xd0, 0xe1, 0x01, 0x17, 0x86, 0x24, 0x0e, 0xa6, 0x64, 0xf2, 0xf6, 0x9b, 0xb1, 0xb7, 0xe3, 0x0e, 0xc6, 0x6b, 0x1a, 0x4a, 0x0b, 0xe5, 0x9b, 0x79, 0xf2, 0x19, 0x8a, 0xd9, 0x80, 0x44, 0x83, 0xe4, 0x75, 0xe5, 0x3b, 0x3c, 0x49, 0xcb, 0x0c, 0xe5, 0xef, 0x92, 0x91, 0x2a, 0xf4, 0x40, 0xf2, 0x3b, 0x99, 0x58, 0x13, 0xd1, 0x1b, 0x59, 0xf7, 0x98, 0xe9, 0x3c, 0x9d, 0x13, 0x53, 0x98, 0x17, 0xc7, 0xac, 0x68, 0xca, 0xd1, 0xaa, 0x1a, 0xc2, 0x76, 0x56, 0xbd, 0x0c, 0x47, 0x97, 0xe9, 0xc8, 0xec, 0x17, 0x78, 0x4c, 0x1a, 0x32, 0x7a, 0x9d, 0xfe, 0xaf, 0x4d, 0x61, 0x91, 0xee, 0xcd, 0xaf, 0xe0, 0x49, 0xb7, 0x33, 0xfe, 0x39, 0xd5, 0xeb, 0x40, 0x00, 0x93, 0x6f, 0xee, 0xfc, 0xf8, 0x29, 0x28, 0xe9, 0xf9, 0x4c, 0xfd, 0x5c, 0xf4, 0xc1, 0xe3, 0xde, 0xb1, 0x43, 0x3a, 0x47, 0xf6, 0xd3, 0x28, 0xb5, 0xe8, 0x3d, 0xd1, 0x56, 0xd0, 0x18, 0x2d, 0xc6, 0x92, 0x34, 0x75, 0x91, 0xaa, 0x6f, 0x73, 0x2c, 0xfb, 0xe9, 0x82, 0x93, 0x5f, 0xd1, 0x84, 0x6c, 0xac, 0xf4, 0xcb, 0x85, 0x15, 0xc5, 0x5a, 0xb8, 0x5e, 0xe5, 0xad, 0x44, 0xcb, 0x09, 0xd3, 0x26, 0x9e, 0x2e, 0x6d, 0x11, 0x78, 0x09, 0x61, 0xfd, 0x13, 0x1d, 0x5e, 0x6f, 0xbf, 0x89, 0x84, 0x9f, 0x47, 0xf2, 0xb7, 0x1d, 0x82, 0x83, 0xff, 0x25, 0x38, 0x5e, 0x52, 0xb0, 0x7d, 0xbb, 0x26, 0x6c, 0x67, 0x4c, 0xee, 0x3d, 0x0b, 0x5d, 0xf5, 0xa5, 0x6d, 0x8b, 0xdc, 0xdc, 0xfa, 0xae, 0xe6, 0xa2, 0x48, 0xe7, 0x1d, 0xb1, 0x34, 0x5a, 0xfc, 0x59, 0x7c, 0xa8, 0x30, 0xa1, 0xa3, 0x5b, 0x43, 0x96, 0xef, 0x4c, 0x1a, 0xdf, 0x9e, 0xd0, 0x1b, 0xce, 0x9b, 0x6e, 0xb6, 0x37, 0xfa, 0x24, 0xaa, 0x16, 0x0b, 0x90, 0x76, 0xba, 0xe3, 0x05, 0x59, 0xf8, 0xb2, 0x9d, 0xed, 0xb3, 0xd2, 0x5b, 0x79, 0x06, 0x4a, 0xb0, 0xcf, 0x8b, 0x8d, 0x70, 0xad, 0xdd, 0xeb, 0x8b, 0x17, 0x42, 0x48, 0xd5, 0xae, 0xa4, 0xd1, 0x8d, 0xe4, 0x3b, 0x89, 0x38, 0xcd, 0xd2, 0xac, 0xba, 0x54, 0x77, 0xbd, 0x4a, 0xac, 0xc3, 0xce, 0x59, 0x5e, 0x5d, 0x26, 0x9f, 0xe6, 0x75, 0x21, 0x0d, 0x23, 0x15, 0x2b, 0x04, 0x71, 0x0f, 0x36, 0x84, 0x28, 0x79, 0x4a, 0x75, 0xf4, 0x9b, 0x68, 0x3e, 0xd2, 0x0d, 0xd6, 0x47, 0x51, 0x57, 0x77, 0x95, 0x5a, 0x8c, 0xb3, 0x8a, 0x36, 0xaf, 0xcd, 0x2c, 0xe0, 0xac, 0xec, 0x4f, 0x0d, 0xfe, 0x80, 0x77, 0x02, 0xd1, 0xeb, 0x3b, 0xde, 0x72, 0xe9, 0xe0, 0x85, 0xaa, 0x4e, 0x09, 0xeb, 0x1b, 0x09, 0x47, 0x41, 0x38, 0x52, 0xec, 0x3c, 0x0a, 0xc5, 0x2f, 0x06, 0xcb, 0x95, 0x9c, 0x85, 0x39, 0x4e, 0xb3, 0x74, 0x81, 0x19, 0xed, 0xbe, 0x6c, 0x80, 0xd2, 0xd8, 0xf7, 0x92, 0xce, 0x0d, 0x91, 0x5e, 0x4f, 0x4b, 0x15, 0x1e, 0xfb, 0x13, 0x5e, 0x7f, 0x4d, 0xc9, 0x7d, 0x85, 0x81, 0x41, 0xc5, 0x7f, 0x70, 0x41, 0x7b, 0x43, 0xa6, 0xa1, 0x26, 0x95, 0x69, 0x78, 0xd7, 0x8e, 0xfb, 0x9f, 0x03, 0x72, 0x43, 0xb4, 0xcb, 0x41, 0xdf, 0x96, 0x8b, 0x7e, 0xe5, 0xb5, 0x20, 0x87, 0xf0, 0x5a, 0xa9, 0xfe, 0x48, 0x7b, 0xd1, 0x6c, 0x03, 0x47, 0xcf, 0x13, 0x35, 0x76, 0x0b, 0xd2, 0x39, 0x8a, 0xd5, 0x4d, 0xda, 0x00, 0xa5, 0xaa, 0xc4, 0x46, 0xd8, 0x0b, 0x1c, 0x79, 0x98, 0xc6, 0x02, 0x19, 0x2a, 0xda, 0xfc, 0xb8, 0x09, 0xd1, 0x4e, 0xe3, 0x28, 0x64, 0x1b, 0xa3, 0xaa, 0x00, 0xf8, 0xd2, 0x9c, 0x3a, 0x84, 0x8a, 0xcb, 0xdc, 0x19, 0x46, 0xbc, 0x0d, 0x35, 0xe0, 0xbe, 0x0f, 0x8f, 0x7e, 0x3d, 0xa3, 0xf6, 0x8d, 0x9f, 0xa9, 0x76, 0x8f, 0x5c, 0xf2, 0x75, 0x53, 0x4a, 0x0e, 0xca, 0x9e, 0x60, 0xfc, 0xea, 0x38, 0xf1, 0xe0, 0x42, 0xc3, 0x16, 0x14, 0x3a, 0x76, 0x7b, 0x33, 0xac, 0xca, 0xd8, 0xc8, 0xd6, 0x6c, 0x70, 0xc7, 0x5f, 0xd1, 0xf0, 0xb2, 0x58, 0x6b, 0x65, 0x3a, 0xd4, 0xaf, 0x54, 0xe5, 0x6e, 0xf0, 0x69, 0x33, 0xea, 0xd3, 0x1d, 0xe3, 0x65, 0xd1, 0x10, 0xb9, 0xc4, 0xa2, 0xa9, 0x8b, 0xcb, 0xa1, 0x65, 0xca, 0xfe, 0x38, 0x6f, 0x88, 0x7c, 0x72, 0x15, 0x6e, 0xb1, 0x4f, 0xf0, 0xda, 0xd6, 0x65, 0x61, 0x6c, 0xe3, 0xce, 0x65, 0xc1, 0x90, 0x4f, 0x2c, 0x17, 0x47, 0xb2, 0xec, 0x2b, 0x5c, 0x9d, 0x67, 0x76, 0xbc, 0xd7, 0x9e, 0x5a, 0xc6, 0x4b, 0x79, 0x33, 0xbd, 0xde, 0xde, 0xdd, 0xbb, 0xc7, 0x25, 0xbf, 0xdb, 0xcc, 0xde, 0x2f, 0xb3, 0x75, 0xae, 0x2b, 0xe3, 0x53, 0x7b, 0xdf, 0x89, 0xbf, 0x4c, 0x25, 0xf8, 0x3a, 0x49, 0xd6, 0xa6, 0xa8, 0xd0, 0x76, 0x1c, 0xf3, 0x9d, 0x62, 0x0c, 0x53, 0xed, 0x83, 0x7d, 0x19, 0x82, 0x55, 0xcf, 0x5b, 0x91, 0x0a, 0x6d, 0xb5, 0x78, 0x77, 0xdf, 0x92, 0xd8, 0xbb, 0x6e, 0x9c, 0x52, 0x6b, 0x8c, 0x4e, 0xc9, 0x31, 0x00, 0xde, 0xe0, 0x50, 0x0a, 0x21, 0x0c, 0x98, 0x45, 0x83, 0xe1, 0x53, 0x81, 0x60, 0xed, 0xac, 0x2c, 0x6f, 0x86, 0x6e, 0x7f, 0x5d, 0x99, 0xd7, 0xb1, 0xb8, 0x15, 0x82, 0xf5, 0xd0, 0xeb, 0xbf, 0x27, 0x86, 0xe3, 0xf5, 0x56, 0x01, 0x3b, 0xa9, 0xb6, 0xf6, 0x56, 0xeb, 0x79, 0x88, 0x38, 0xea, 0x05, 0x79, 0x20, 0x1a, 0x95, 0xd5, 0x6b, 0xbc, 0x3b, 0xcd, 0xb9, 0x51, 0x1a, 0xfb, 0xd4, 0xd8, 0x12, 0x88, 0x89, 0x6f, 0x87, 0x10, 0x8c, 0x07, 0x7f, 0x1a, 0x81, 0xa3, 0xbd, 0x29, 0x7b, 0xb1, 0x24, 0xa8, 0x00, 0x86, 0x89, 0x02, 0x42, 0x99, 0x5e, 0x03, 0xcf, 0x42, 0xa0, 0xc2, 0x1e, 0x27, 0x2a, 0x9a, 0xfa, 0x1d, 0xc1, 0x03, 0x46, 0x3d, 0x2a, 0xb4, 0x94, 0xf7, 0xd0, 0x17, 0x68, 0x6d, 0x31, 0x89, 0x4d, 0xd2, 0xf6, 0xeb, 0xb0, 0xc3, 0xcb, 0x62, 0x23, 0xec, 0x79, 0xc6, 0x5d, 0x45, 0xc1, 0xb0, 0xd4, 0xef, 0x19, 0x61, 0xf1, 0x6d, 0x65, 0x3f, 0xcf, 0x25, 0x97, 0x7b, 0x65, 0x1e, 0xc5, 0x1a, 0x13, 0xae, 0x8d, 0x4a, 0x34, 0x72, 0xee, 0x71, 0x96, 0x9a, 0x7a, 0x93, 0x6f, 0x5d, 0xbb, 0xb9, 0x39, 0x6a, 0x46, 0xd9, 0x76, 0x42, 0x35, 0x8c, 0xaf, 0x48, 0x94, 0xc9, 0xa6, 0xdf, 0x84, 0xa5, 0x9c, 0x59, 0x62, 0xa6, 0x99, 0x0a, 0x76, 0xf0, 0x61, 0x48, 0x90, 0x16, 0x9f, 0x00, 0x18, 0x70, 0xd4, 0x9c, 0xf2, 0xe7, 0x50, 0x08, 0xcc, 0x4a, 0x5d, 0x85, 0xe7, 0x2d, 0xe2, 0xd6, 0xcf, 0x3f, 0xa7, 0x18, 0x52, 0x25, 0x35, 0x22, 0xfe, 0x8b, 0x0e, 0x42, 0x3c, 0xb4, 0x17, 0xa3, 0x8e, 0xb7, 0x8c, 0x87, 0x63, 0xc3, 0x72, 0x0c, 0x04, 0xe6, 0x7f, 0xf8, 0x89, 0x79, 0xeb, 0xa0, 0x9e, 0x34, 0x53, 0x8b, 0xb5, 0x23, 0xb9, 0x9b, 0x8e, 0x34, 0x16, 0x74, 0x12, 0xf7, 0x7a, 0xea, 0x89, 0x4d, 0x83, 0xac, 0xf9, 0x46, 0xfc, 0x05, 0x4d, 0x0a, 0xf4, 0x72, 0x95, 0xe5, 0x1e, 0xd8, 0x3f, 0x74, 0x86, 0x94, 0x0a, 0x4d, 0x41, 0xc0, 0x4a, 0xd7, 0xeb, 0xee, 0x61, 0x0b, 0xf1, 0xd0, 0x3f, 0xa5, 0x40, 0x71, 0xd5, 0x1a, 0x15, 0x09, 0xe4, 0xf4, 0x91, 0x63, 0xa2, 0x50, 0x81, 0xbe, 0x87, 0x90, 0xd0, 0x87, 0xf5, 0xf4, 0xf0, 0x5c, 0x88, 0x55, 0x0f, 0xca, 0x9b, 0xf9, 0x9c, 0x9b, 0xe5, 0x95, 0x3d, 0x51, 0xdd, 0x08, 0x45, 0xc9, 0x3e, 0x41, 0xee, 0xef, 0x62, 0xe0, 0x79, 0x4b, 0x29, 0x27, 0xc4, 0xf5, 0xed, 0x9b, 0xd3, 0xe3, 0x4e, 0xa9, 0x20, 0x0a, 0x79, 0xdd, 0xeb, 0x4b, 0x2d, 0x8f, 0x30, 0x5f, 0xe0, 0x5f, 0x82, 0x7c, 0x7e, 0x2e, 0xd1, 0x86, 0x34, 0x1c, 0xb5, 0xd1, 0x15, 0x2f, 0xc8, 0x01, 0x04, 0xe0, 0xe1, 0x36, 0x83, 0xd9, 0x41, 0x29, 0x4c, 0x77, 0x84, 0x17, 0x16, 0x4b, 0x68, 0x4a, 0x97, 0x6e, 0x56, 0xe7, 0x8d, 0xa4, 0xd1, 0x7c, 0x3c, 0x73, 0x22, 0x93, 0x14, 0x87, 0x0b, 0x85, 0xc4, 0x55, 0xc2, 0x3b, 0x83, 0x0b, 0x9a, 0x28, 0xa3, 0xd8, 0xc0, 0xb5, 0x66, 0x42, 0x6d, 0xc1, 0x69, 0xf3, 0x26, 0xab, 0xce, 0x2e, 0xff, 0xf3, 0x9e, 0x9b, 0x19, 0x9a, 0xe5, 0xc1, 0x29, 0x2b, 0x6f, 0x2e, 0xf3, 0x7a, 0xf1, 0xde, 0xa9, 0x27, 0x2c, 0x8d, 0x54, 0x23, 0xdf, 0x8a, 0x56, 0x32, 0xf9, 0x91, 0xe1, 0x4d, 0xca, 0x25, 0x14, 0x78, 0x8b, 0x62, 0xbe, 0x16, 0x48, 0x28, 0xe9, 0xac, 0xb8, 0x93, 0xdd, 0xa6, 0x02, 0xa5, 0xe2, 0xfb, 0x9e, 0xfc, 0xbe, 0xfd, 0x95, 0xab, 0xfb, 0x82, 0xd2, 0xb0, 0x2d, 0x49, 0xcc, 0x53, 0x08, 0x4a, 0x49, 0xab, 0x1b, 0xec, 0x23, 0xe5, 0xb4, 0xc8, 0xe7, 0x14, 0xcb, 0x03, 0x40, 0x5f, 0x1b, 0xcf, 0x7e, 0x11, 0xbb, 0x59, 0x72, 0x9d, 0xdc, 0x0b, 0x7b, 0xef, 0xb2, 0x91, 0x27, 0x6d, 0xce, 0xda, 0xca, 0xad, 0x39, 0xa2, 0xf0, 0x1c, 0x7d, 0xc9, 0x8b, 0x9e, 0x06, 0x5e, 0xaf, 0xed, 0x1c, 0xc8, 0xce, 0x3e, 0x84, 0x80, 0x80, 0xa2, 0xfc, 0x5b, 0x98, 0xc9, 0xf6, 0xbf, 0x50, 0x40, 0x27, 0x33, 0x42, 0xf0, 0x31, 0x2f, 0x8b, 0x98, 0x44, 0x59, 0x4a, 0x50, 0x3d, 0xd3, 0xe6, 0xaf, 0x1c, 0x9e, 0x35, 0xc1, 0x03, 0x2a, 0x4a, 0x8a, 0x5e, 0x7b, 0xf3, 0x3a, 0x82, 0xf3, 0x5e, 0x16, 0xed, 0xf8, 0xc6, 0x0c, 0x90, 0x02, 0x1d, 0x8c, 0x0b, 0xa4, 0xc3, 0x86, 0x24, 0x5d, 0xfe, 0xf0, 0x94, 0x48, 0x43, 0x1d, 0x8c, 0x00, 0xd1, 0xe2, 0x6e, 0xe4, 0xd8, 0xc7, 0x7d, 0xaa, 0x1a, 0x70, 0x5e, 0xd4, 0x79, 0x2a, 0xcb, 0x4e, 0xa2, 0x7c, 0x15, 0x66, 0xfb, 0x56, 0x68, 0x3c, 0x43, 0xbf, 0x67, 0x84, 0x2e, 0x67, 0x53, 0x4c, 0xb3, 0xf9, 0x67, 0x7c, 0x8a, 0xb9, 0xd0, 0xee, 0xe7, 0x82, 0x7c, 0xde, 0xfc, 0x22, 0x3a, 0xc9, 0x48, 0xb8, 0x80, 0xb5, 0xf1, 0xce, 0x95, 0x37, 0x27, 0x29, 0x32, 0x00, 0x2c, 0x1a, 0x4d, 0xd2, 0x18, 0xf5, 0x27, 0x16, 0x6e, 0xbf, 0xb2, 0xb2, 0xfa, 0x2b, 0xf3, 0x72, 0x46, 0xec, 0xdf, 0xdf, 0xa7, 0x2b, 0x6d, 0xa1, 0x1c, 0x30, 0xd1, 0xc7, 0xd2, 0x48, 0xad, 0x64, 0x81, 0x8f, 0x69, 0x1d, 0x59, 0xb7, 0x55, 0xda, 0xf7, 0x1b, 0xed, 0x9a, 0xb5, 0xfb, 0x52, 0xe0, 0x36, 0x22, 0xa9, 0x00, 0xd6, 0x6b, 0x4c, 0x63, 0x84, 0x16, 0x9b, 0xdf, 0x9e, 0xb6, 0x1c, 0x02, 0xdf, 0x45, 0xfb, 0x76, 0xb1, 0xa2, 0x6f, 0x34, 0xe9, 0x38, 0xb1, 0x90, 0x86, 0x17, 0x45, 0xc0, 0x21, 0xfa, 0x87, 0x62, 0x00, 0xc7, 0xfc, 0x8e, 0x22, 0x2d, 0xdb, 0xfa, 0xd8, 0xbe, 0x78, 0x1b, 0x18, 0x54, 0x24, 0xaa, 0xaf, 0xc6, 0x58, 0x62, 0xdb, 0x13, 0x2b, 0xec, 0x6d, 0x18, 0x83, 0x7a, 0x1f, 0x58, 0xa8, 0x76, 0xc9, 0x9e, 0x63, 0xf5, 0x14, 0x20, 0xb8, 0x3f, 0x45, 0x96, 0x75, 0x61, 0x2f, 0x7a, 0xcf, 0x80, 0xb4, 0xeb, 0x1d, 0xd0, 0x72, 0x1c, 0xaa, 0x1b, 0x49, 0x70, 0xda, 0x60, 0x86, 0x79, 0xc6, 0x38, 0x3e, 0x81, 0x7f, 0xe1, 0x6b, 0x66, 0xb1, 0x91, 0x81, 0xed, 0xfc, 0x39, 0x27, 0x0c, 0x7e, 0x91, 0x7b, 0x1f, 0x10, 0xeb, 0x7a, 0x01, 0x19, 0x97, 0xe9, 0x67, 0x85, 0x3b, 0x78, 0xe0, 0x0c, 0xfd, 0x58, 0xd2, 0x24, 0xd9, 0x33, 0xcc, 0x5a, 0x99, 0x55, 0x32, 0xdc, 0xd4, 0xe5, 0x32, 0xe4, 0x03, 0x05, 0x15, 0xf4, 0xa0, 0x5b, 0x33, 0x1d, 0x57, 0x5d, 0xda, 0xc2, 0x9b, 0xab, 0x06, 0x9f, 0x09, 0xaf, 0x0d, 0x17, 0x33, 0x73, 0xdb, 0x1e, 0xc2, 0xb6, 0x36, 0x6b, 0xb3, 0x71, 0x00, 0x8a, 0x23, 0x86, 0xfd, 0x88, 0xbe, 0x77, 0xf5, 0xed, 0x5e, 0x19, 0x8c, 0xbe, 0x88, 0xdf, 0x24, 0xbc, 0x6e, 0x39, 0x3f, 0xeb, 0xc1, 0x0c, 0x47, 0x0a, 0x72, 0xd4, 0x7c, 0x0f, 0x83, 0x46, 0x53, 0xc9, 0xae, 0x80, 0x0e, 0x89, 0x3c, 0x6b, 0xa6, 0x8e, 0xa2, 0x8a, 0x83, 0x8f, 0xcb, 0xb6, 0x9c, 0x3e, 0x96, 0x4a, 0x5f, 0xaf, 0xc2, 0x06, 0x7d, 0xd4, 0x06, 0xb2, 0x57, 0xc9, 0x8d, 0xd3, 0x97, 0x9e, 0xc7, 0xc7, 0xec, 0xbe, 0x96, 0xa3, 0x3d, 0x85, 0x51, 0x5d, 0xa2, 0xcb, 0x6a, 0xa5, 0xe1, 0xff, 0xf2, 0x04, 0xaf, 0x62, 0xdd, 0x41, 0x19, 0xa0, 0xe4, 0x8c, 0x04, 0xa3, 0xf2, 0xb3, 0x86, 0x60, 0xf5, 0x29, 0x64, 0xd8, 0xd4, 0xae, 0xe1, 0x46, 0xa9, 0xc5, 0x3c, 0x31, 0x90, 0x6d, 0xad, 0x0f, 0xd9, 0x0b, 0x5d, 0x83, 0xb3, 0xe3, 0x1b, 0x69, 0x0a, 0x4c, 0x49, 0x35, 0x24, 0x99, 0x81, 0xbe, 0x1f, 0x1a, 0x85, 0xec, 0x6e, 0x0f, 0xee, 0x4c, 0x88, 0xf2, 0xd8, 0x9e, 0x29, 0x69, 0xab, 0x8c, 0xbb, 0xeb, 0x50, 0x19, 0x16, 0x55, 0x8d, 0x29, 0xea, 0x7c, 0x3e, 0xcf, 0x1c, 0x9e, 0xf1, 0xa0, 0x43, 0x50, 0x63, 0x3b, 0x4c, 0xda, 0x73, 0x7d, 0xfb, 0x15, 0x1c, 0xb5, 0xe7, 0x36, 0x11, 0x73, 0xf3, 0xae, 0xdd, 0xdf, 0x52, 0x7d, 0x73, 0xf2, 0xf9, 0xd5, 0xb6, 0x21, 0x3a, 0xa6, 0x8f, 0x88, 0x3e, 0x9a, 0x26, 0x33, 0x78, 0x5e, 0xc6, 0xbe, 0x64, 0x2a, 0x9f, 0xd0, 0xf2, 0x1a, 0x42, 0xf6, 0xb9, 0xda, 0xab, 0xdc, 0xd1, 0xe6, 0xad, 0xbe, 0xf6, 0x48, 0x41, 0xb5, 0x96, 0x86, 0xea, 0xe3, 0xec, 0x88, 0xee, 0xf0, 0xa9, 0xcb, 0xc1, 0x2b, 0xc0, 0x12, 0x62, 0x2d, 0xf2, 0xdd, 0x93, 0xa8, 0x62, 0x29, 0x04, 0x4a, 0xf2, 0xf2, 0x60, 0xd2, 0x18, 0x3f, 0x51, 0xe8, 0x33, 0xee, 0x92, 0xd9, 0x8f, 0x02, 0x51, 0xe3, 0xf8, 0x5f, 0xab, 0x74, 0xce, 0x36, 0x7b, 0x8b, 0x7a, 0xa6, 0x3d, 0x3c, 0xf8, 0xc8, 0xbf, 0x4d, 0x78, 0x35, 0x8b, 0xae, 0x0a, 0x02, 0x41, 0xe2, 0x10, 0xac, 0x69, 0x35, 0x30, 0x87, 0xcc, 0x73, 0x31, 0x35, 0x7e, 0xb4, 0x45, 0x0f, 0x95, 0x09, 0xcf, 0xe5, 0x95, 0xf5, 0x40, 0x32, 0xee, 0x05, 0x77, 0x54, 0xa8, 0xed, 0xd7, 0x46, 0xcb, 0x92, 0x82, 0xe7, 0x68, 0xdc, 0x6b, 0x83, 0x0c, 0x5b, 0x4a, 0x21, 0x93, 0x43, 0xad, 0x12, 0x4e, 0xdb, 0x3b, 0xbc, 0x42, 0x50, 0x55, 0x66, 0xa7, 0x03, 0x8c, 0x95, 0x9b, 0xc3, 0x55, 0x85, 0xb6, 0x05, 0x5f, 0x19, 0x68, 0xda, 0x24, 0x3f, 0x77, 0x8f, 0x4e, 0x46, 0xdb, 0x46, 0x2a, 0xbe, 0xb9, 0x3b, 0x81, 0x24, 0x3c, 0x31, 0xeb, 0x59, 0x62, 0x2e, 0xdf, 0x81, 0xf0, 0x6c, 0xcc, 0x61, 0xd2, 0xa6, 0xea, 0x73, 0xe1, 0x09, 0xc3, 0x87, 0x91, 0x5f, 0x27, 0x7b, 0xcf, 0x1f, 0xc1, 0x11, 0x05, 0xbb, 0xa7, 0x02, 0x93, 0xc0, 0xfa, 0xb5, 0xc0, 0x65, 0xf2, 0x3b, 0xaa, 0x19, 0x29, 0x0a, 0x30, 0x2f, 0x08, 0x09, 0x11, 0x07, 0xa4, 0xb1, 0xd5, 0x68, 0x85, 0x26, 0x22, 0x09, 0x83, 0x83, 0x42, 0x77, 0x60, 0xef, 0x8f, 0x29, 0x28, 0x62, 0x5b, 0xdd, 0xa5, 0xf5, 0x14, 0xc5, 0xad, 0xe9, 0x59, 0x89, 0x1e, 0xf2, 0x95, 0x9f, 0x24, 0x8a, 0x35, 0x32, 0xbf, 0x9d, 0x30, 0xe7, 0x14, 0x05, 0x9e, 0xbd, 0xec, 0x95, 0x87, 0x08, 0xf8, 0xa8, 0x3c, 0x26, 0x8b, 0xef, 0x26, 0x82, 0xd6, 0x03, 0xca, 0x88, 0x63, 0x47, 0xe1, 0x98, 0xfd, 0x68, 0x23, 0x39, 0x99, 0xc7, 0x7d, 0x30, 0xd7, 0x45, 0x5d, 0xe6, 0xbc, 0xfd, 0x01, 0x44, 0x27, 0x70, 0x62, 0xb3, 0x04, 0xbe, 0xf0, 0xe3, 0x4c, 0x5a, 0x9d, 0x8d, 0x78, 0x0d, 0x29, 0xec, 0x23, 0x21, 0xe0, 0x73, 0x40, 0x77, 0x1c, 0x46, 0x36, 0x04, 0x83, 0xad, 0xca, 0xf1, 0x2d, 0x5b, 0x79, 0xfd, 0xbf, 0xe2, 0x85, 0x6a, 0xce, 0x88, 0x59, 0xf6, 0xb1, 0x24, 0x14, 0xb3, 0xf7, 0xe8, 0xbb, 0x58, 0x13, 0x49, 0x89, 0x60, 0xf3, 0x4f, 0xdc, 0x64, 0xfc, 0x84, 0x85, 0x79, 0xca, 0xf9, 0xdc, 0xcf, 0x19, 0xb4, 0xfb, 0x82, 0x5e, 0xd5, 0x71, 0x6d, 0xcc, 0xcd, 0x68, 0x72, 0xcb, 0xde, 0x38, 0x31, 0xd6, 0x73, 0x84, 0x94, 0x2c, 0xd8, 0xa9, 0xec, 0x4b, 0xbf, 0xef, 0x57, 0x06, 0xb8, 0xf9, 0xf0, 0x5f, 0xe1, 0xe8, 0xfe, 0x69, 0xd3, 0xea, 0x6a, 0x86, 0x21, 0xc2, 0x21, 0x44, 0x17, 0x7b, 0x1c, 0x12, 0x59, 0xe1, 0xa7, 0x9d, 0xfd, 0xf8, 0x97, 0x28, 0x88, 0x7b, 0xef, 0x1a, 0x70, 0x48, 0x25, 0x56, 0x83, 0x1b, 0x67, 0x24, 0x40, 0xe1, 0x3f, 0xe3, 0xe3, 0xfc, 0x82, 0x04, 0xa0, 0x2e, 0xa1, 0xef, 0xf1, 0x9d, 0x95, 0x25, 0x38, 0x87, 0x28, 0x5b, 0xfb, 0xea, 0x16, 0xa0, 0xf2, 0x19, 0xef, 0xbc, 0xec, 0x30, 0xa8, 0xae, 0x86, 0x58, 0x9a, 0x57, 0x03, 0x10, 0x3a, 0x8a, 0x39, 0x3f, 0xa6, 0xf6, 0xb6, 0x57, 0x70, 0x4a, 0xc6, 0x77, 0xc1, 0x4c, 0xd1, 0x0d, 0x3d, 0x62, 0xd1, 0x3f, 0xbd, 0x37, 0x8c, 0x2d, 0xda, 0x32, 0x5b, 0x61, 0xb8, 0x59, 0x52, 0xd5, 0x12, 0x93, 0x87, 0x1e, 0x1f, 0xcd, 0xc9, 0x48, 0xc7, 0x7b, 0xea, 0xe9, 0xa6, 0xf0, 0xe8, 0x7c, 0xe1, 0xa8, 0x05, 0x1c, 0x8f, 0x80, 0x87, 0x68, 0x5c, 0x12, 0x62, 0x4b, 0xdf, 0x58, 0x38, 0x0e, 0xd6, 0x6f, 0x55, 0xb4, 0x3d, 0xdd, 0x6d, 0x36, 0x21, 0x73, 0xa5, 0xbd, 0x38, 0x98, 0x59, 0xc1, 0x7d, 0x95, 0xec, 0xe3, 0xab, 0x73, 0x26, 0x39, 0xff, 0xe4, 0x51, 0xcd, 0x10, 0x3e, 0xe4, 0x85, 0x4d, 0xb2, 0xf3, 0x96, 0x14, 0xf6, 0x58, 0xba, 0xa3, 0x84, 0xbc, 0x99, 0x48, 0xd0, 0x71, 0x4e, 0xb4, 0x8a, 0x88, 0x71, 0x43, 0xe7, 0xa1, 0xfa, 0x4b, 0x69, 0x0c, 0x22, 0xb4, 0x92, 0xa7, 0x0c, 0x61, 0x2b, 0x59, 0xff, 0xd2, 0xd6, 0xb3, 0xb5, 0xe9, 0x9c, 0x20, 0x03, 0xe2, 0xc3, 0x59, 0xb1, 0xe6, 0x2d, 0xcb, 0x62, 0x0c, 0x7a, 0x24, 0x6a, 0x7b, 0x9b, 0x32, 0x46, 0x13, 0x15, 0x56, 0xf2, 0xf3, 0xd5, 0x13, 0xa2, 0x3c, 0x6a, 0x9f, 0xd2, 0x28, 0x0e, 0xd6, 0x86, 0xd7, 0x67, 0xcc, 0xd0, 0x17, 0x54, 0xeb, 0x4c, 0x99, 0x69, 0x2f, 0x2b, 0x38, 0x0c, 0x36, 0x08, 0x13, 0x44, 0xc1, 0xd3, 0x5e, 0xe1, 0x94, 0x97, 0x36, 0xb6, 0x97, 0x6f, 0x48, 0x52, 0xcf, 0xbe, 0x64, 0xfa, 0xbc, 0xf1, 0x1b, 0x9a, 0xfb, 0x82, 0x85, 0x76, 0xb4, 0xf9, 0x78, 0x7a, 0xa7, 0xd0, 0x3e, 0x84, 0x59, 0x8a, 0x71, 0x43, 0xef, 0x73, 0x11, 0xfa, 0xf2, 0x97, 0x0e, 0x23, 0xed, 0x4c, 0x17, 0x3f, 0x98, 0x5d, 0x64, 0x50, 0x16, 0x5a, 0xe3, 0xe2, 0x41, 0xa1, 0x82, 0x34, 0xe7, 0x4f, 0xf3, 0xdd, 0xb9, 0x21, 0xa5, 0x30, 0x0b, 0x1c, 0x4f, 0xb6, 0xe4, 0x32, 0xe6, 0x98, 0xf5, 0x3f, 0x66, 0xe3, 0x8c, 0x07, 0xbc, 0xd6, 0xe7, 0x76, 0x05, 0xdf, 0x46, 0x24, 0xd5, 0x79, 0x07, 0x62, 0x92, 0xde, 0x1c, 0xe6, 0xfc, 0x6f, 0x00, 0x81, 0xa3, 0x8b, 0xd9, 0x2d, 0x39, 0xb2, 0x4b, 0x73, 0xba, 0xc1, 0xc5, 0x2b, 0xd6, 0x8e, 0x91, 0x81, 0xd3, 0xdc, 0xd0, 0xac, 0x75, 0x34, 0xdb, 0x48, 0x90, 0x1e, 0x59, 0x84, 0xf9, 0x90, 0x25, 0x57, 0xbf, 0xa2, 0x31, 0xb2, 0xea, 0x28, 0xc3, 0x18, 0x32, 0x62, 0xa1, 0xb2, 0x22, 0x1f, 0x74, 0x26, 0xea, 0x88, 0xa5, 0x81, 0x60, 0x93, 0xa5, 0xca, 0xe2, 0xcd, 0x5d, 0x59, 0xa9, 0x39, 0x0f, 0xc9, 0x3a, 0x29, 0x56, 0x94, 0x4b, 0x06, 0x4c, 0xf0, 0x13, 0xbc, 0xdb, 0x67, 0xfb, 0x42, 0x3d, 0x13, 0x28, 0xd2, 0xc6, 0xd7, 0xba, 0x32, 0x90, 0x13, 0xfa, 0x2d, 0x30, 0xef, 0xd6, 0x9f, 0xdc, 0xa1, 0xa9, 0x5e, 0xa6, 0xd0, 0x6c, 0x73, 0x63, 0x53, 0x4b, 0x2f, 0x3f, 0x7d, 0xaa, 0xfa, 0x29, 0x6e, 0xaa, 0x09, 0xb3, 0x66, 0x8e, 0x9c, 0xf8, 0x2d, 0x9b, 0xa9, 0x59, 0xb3, 0x2f, 0x3c, 0xad, 0x3c, 0x10, 0xc6, 0xea, 0x48, 0x61, 0x15, 0x54, 0x53, 0x9c, 0x37, 0xdf, 0x6b, 0xca, 0x33, 0x85, 0xea, 0xd3, 0xfc, 0xff, 0x96, 0xd3, 0x72, 0xb4, 0x23, 0x93, 0xb7, 0x3c, 0x8d, 0xaa, 0xaa, 0x31, 0x50, 0x6e, 0xe0, 0x52, 0x7b, 0x7f, 0xb3, 0xe5, 0x93, 0xdc, 0xcc, 0xa5, 0x7c, 0x8f, 0xbb, 0xd4, 0xa3, 0xc7, 0xf8, 0xa5, 0x38, 0x99, 0x86, 0x91, 0x32, 0xfb, 0xc3, 0xe4, 0x05, 0x06, 0x07, 0xbb, 0xfe, 0x29, 0xc6, 0x75, 0xe3, 0x94, 0x5e, 0x74, 0xa3, 0x1c, 0xd5, 0x31, 0xba, 0x7a, 0xeb, 0x2e, 0x2f, 0x0c, 0xd9, 0x90, 0xb8, 0xf9, 0x83, 0xa9, 0x0d, 0xfe, 0xa0, 0x56, 0x8f, 0x06, 0x77, 0xea, 0x95, 0x63, 0xf7, 0xc4, 0x79, 0xde, 0x96, 0x89, 0x40, 0xcf, 0x24, 0x29, 0x92, 0x69, 0x28, 0x65, 0xcf, 0xda, 0x89, 0xfa, 0x07, 0x8b, 0xbe, 0xf4, 0x9c, 0xe4, 0x57, 0x5b, 0xdf, 0xb3, 0x80, 0x36, 0x60, 0x11, 0xc8, 0x43, 0x5f, 0x12, 0xb4, 0x2d, 0x9a, 0xb9, 0x9a, 0xb6, 0xa3, 0x19, 0x12, 0xc4, 0x35, 0x41, 0x49, 0xd7, 0x23, 0x10, 0x1d, 0x13, 0x65, 0xa6, 0x5e, 0x7c, 0xc6, 0x8d, 0x82, 0xe3, 0x05, 0x17, 0x77, 0x39, 0x02, 0xfb, 0x38, 0xdd, 0xa2, 0xb3, 0x24, 0xe7, 0x20, 0x8e, 0x98, 0x7e, 0xd2, 0x87, 0xd0, 0x92, 0xe7, 0x66, 0x2a, 0x43, 0x02, 0x41, 0xbf, 0xca, 0x55, 0x2d, 0x31, 0x41, 0x27, 0xe3, 0x8c, 0x85, 0x97, 0xa8, 0x95, 0x19, 0xd4, 0xf1, 0xe6, 0x2a, 0x79, 0x46, 0x5a, 0xd5, 0xf4, 0xea, 0xa3, 0xfa, 0x77, 0xcd, 0x98, 0x32, 0x6d, 0x2f, 0x92, 0xce, 0x98, 0x52, 0x05, 0x5c, 0xec, 0xcf, 0x62, 0xd6, 0x3c, 0xb9, 0xd7, 0xf1, 0x98, 0xae, 0x08, 0x5e, 0x4d, 0x45, 0xc8, 0xe4, 0x8f, 0xcf, 0xfe, 0x59, 0x3a, 0xd6, 0x52, 0xd9, 0x15, 0x41, 0x67, 0xbf, 0x3e, 0x61, 0x95, 0x81, 0x0a, 0x44, 0x5a, 0xe1, 0x58, 0xf1, 0xf9, 0xa6, 0x79, 0x33, 0x63, 0xaf, 0xc1, 0xf2, 0x2c, 0xa8, 0x82, 0xfe, 0xed, 0x3a, 0x5f, 0x57, 0x27, 0xca, 0x76, 0x47, 0x7c, 0x5f, 0x23, 0xf0, 0xfc, 0x87, 0x00, 0xcd, 0xc6, 0xa5, 0xbc, 0xb2, 0xb2, 0x0b, 0x4f, 0x92, 0x66, 0x35, 0x1d, 0x30, 0x4a, 0x96, 0xa8, 0x2b, 0xf5, 0xf3, 0x14, 0xaf, 0x68, 0x5c, 0x1c, 0x70, 0x7c, 0x92, 0xe3, 0xe8, 0x47, 0xb7, 0x04, 0x7d, 0x68, 0x9c, 0x70, 0xb2, 0x5e, 0x55, 0x01, 0xca, 0xec, 0x99, 0x19, 0x62, 0x6f, 0x4a, 0x0f, 0xc8, 0x15, 0x86, 0xaf, 0x1e, 0xc8, 0x88, 0x89, 0xb4, 0x23, 0x38, 0x7d, 0x5d, 0x95, 0x48, 0x26, 0x18, 0xa6, 0x50, 0xe8, 0x0b, 0x53, 0xb0, 0x7c, 0xac, 0xe3, 0x22, 0x89, 0x40, 0x60, 0x2e, 0x3d, 0xb4, 0x74, 0x66, 0xce, 0x9b, 0xcc, 0xb6, 0xe4, 0xd8, 0xaa, 0x61, 0xc8, 0x91, 0x25, 0x83, 0xe8, 0x10, 0xb3, 0xb2, 0xe7, 0xe9, 0xcb, 0x48, 0xbd, 0x40, 0x3e, 0xcf, 0x08, 0xd2, 0x8c, 0x70, 0xae, 0x0b, 0x62, 0x08, 0x59, 0xc1, 0xf0, 0x9b, 0x61, 0x13, 0x14, 0x04, 0xc3, 0xd5, 0xbf, 0xfc, 0xd8, 0x60, 0xe0, 0xf4, 0x2a, 0xb2, 0x99, 0x00, 0x62, 0x30, 0xb2, 0x87, 0x6d, 0x77, 0xdd, 0xa9, 0x1c, 0x8c, 0x62, 0xbd, 0x93, 0xa8, 0x44, 0xe4, 0xb3, 0x44, 0xe3, 0x25, 0x5e, 0xea, 0x53, 0x1c, 0x6c, 0x45, 0x8d, 0x04, 0xab, 0xdb, 0x0f, 0xae, 0xf2, 0xd1, 0xc0, 0xb4, 0xc5, 0x5f, 0x57, 0x0a, 0x5a, 0x51, 0x02, 0x3f, 0x4d, 0x4e, 0xff, 0xf5, 0x9f, 0x9a, 0xbe, 0x17, 0x92, 0x2f, 0xe7, 0x32, 0xca, 0x71, 0xbc, 0xd4, 0x34, 0xad, 0x77, 0x10, 0xb8, 0x4c, 0xd4, 0xac, 0x9f, 0x25, 0x07, 0xa0, 0x68, 0x26, 0x56, 0x2a, 0xd7, 0xf6, 0x47, 0x82, 0x6f, 0x9d, 0xbb, 0xe4, 0xed, 0xd2, 0x3f, 0x12, 0x43, 0x69, 0xdb, 0x85, 0x26, 0xfc, 0x2b, 0x4d, 0x52, 0xf0, 0x74, 0x14, 0x15, 0xf9, 0x72, 0xbe, 0xf6, 0xa9, 0x35, 0xbd, 0x81, 0x2a, 0x56, 0xc8, 0x22, 0x1b, 0x7d, 0xef, 0x0f, 0x51, 0x06, 0xbc, 0x01, 0xe9, 0x13, 0xe3, 0xd4, 0x3d, 0xb8, 0x6c, 0x2b, 0xb4, 0xc7, 0xe0, 0x76, 0x26, 0x63, 0xc6, 0xde, 0x78, 0x87, 0x21, 0xc2, 0xaa, 0x07, 0xf8, 0x95, 0x48, 0x87, 0xe2, 0x14, 0x2f, 0x2e, 0x91, 0x4a, 0x09, 0x9e, 0xfc, 0x0a, 0xee, 0x13, 0x39, 0x21, 0x0d, 0x3e, 0x53, 0xda, 0x3e, 0xcf, 0x88, 0x62, 0x4b, 0x11, 0x19, 0xbe, 0x34, 0x01, 0x0b, 0x88, 0x6c, 0x80, 0xf5, 0x1d, 0x18, 0x50, 0x83, 0x8f, 0x21, 0x50, 0xe7, 0x2b, 0x04, 0x2a, 0xf3, 0x28, 0x99, 0xc0, 0xd3, 0xd7, 0xb0, 0x2a, 0x57, 0xf8, 0xcf, 0x26, 0x3a, 0x36, 0x95, 0x62, 0xe4, 0xe9, 0x45, 0xa3, 0x12, 0x82, 0xa5, 0x02, 0xa9, 0x5e, 0xe9, 0xbb, 0x03, 0x16, 0xc6, 0x86, 0x10, 0x06, 0xda, 0xc1, 0x7f, 0x93, 0x6f, 0x54, 0xc4, 0xc7, }, .t0_len = 3328, .t1 = { 0x83, 0x01, 0xe6, 0x66, 0xf5, 0x9d, 0x3e, 0xc5, 0x04, 0x4d, 0xe4, 0x56, 0x78, 0x8f, 0xde, 0x19, 0xeb, 0x39, 0x67, 0x7b, 0x5f, 0x9f, 0xe1, 0x41, 0x50, 0xda, 0x46, 0x3a, 0x70, 0x6f, 0x3b, 0xaf, 0x71, 0x5b, 0x95, 0x33, 0x6b, 0x2d, 0x68, 0x5a, 0x7c, 0xd7, 0x88, 0x07, 0x13, 0xe4, 0x58, 0x7b, 0xf7, 0xd8, 0x57, 0xbf, 0x7e, 0x31, 0x56, 0x96, 0xb8, 0xd0, 0xd9, 0xd4, 0x9e, 0x14, 0x29, 0x18, 0xbf, 0x09, 0x74, 0xe7, 0xf4, 0x32, 0x37, 0xd4, 0xbe, 0x3a, 0xd3, 0x94, 0x59, 0x9e, 0x3d, 0x39, 0xbb, 0x76, 0x49, 0x93, 0x25, 0x53, 0x44, 0x7e, 0x5d, 0x5a, 0xcc, 0x34, 0x99, 0x93, 0x01, 0x76, 0xec, 0xd3, 0xa8, 0x44, 0xa4, 0x25, 0xf5, 0x0d, 0x05, 0x11, 0xc9, 0x22, 0x6c, 0x4b, 0x9a, 0x24, 0xf2, 0xa0, 0x11, 0xcd, 0x88, 0xd3, 0x23, 0x08, 0xe0, 0x31, 0x2a, 0x0c, 0x87, 0xcc, 0x34, 0xa9, 0x95, 0x82, 0x3c, 0x65, 0xf4, 0xf0, 0xf9, 0x8e, 0x50, 0xc3, 0x77, 0x88, 0xce, 0x38, 0xdc, 0x28, 0xfb, 0x8b, 0x9b, 0xfa, 0xaf, 0xa9, 0x04, 0xb5, 0x41, 0xee, 0x71, 0x2f, 0x6a, 0x04, 0x1e, 0x06, 0x11, 0x37, 0x4f, 0x6b, 0xf1, 0x7e, 0xac, 0x0b, 0xd5, 0x6f, 0x3b, 0x6b, 0xf3, 0x36, 0xda, 0x92, 0x42, 0x07, 0x0c, 0x24, 0x69, 0xa2, 0x0c, 0x4d, 0x16, 0x16, 0x14, 0x9a, 0x61, 0x59, 0x25, 0x20, 0x11, 0xd2, 0x99, 0xf9, 0x3f, 0x98, 0x6d, 0x87, 0x5d, 0xd3, 0x0b, 0x38, 0xa2, 0x25, 0x49, 0x17, 0x45, 0x70, 0x13, 0x8c, 0x2b, 0xb3, 0xaa, 0x9c, 0xbe, 0xa9, 0x19, 0x74, 0xf3, 0xd8, 0x9b, 0xf5, 0xae, 0x32, 0xbe, 0x9e, 0x58, 0xb8, 0x54, 0xa2, 0xf8, 0xe8, 0x6f, 0xf7, 0x67, 0x80, 0xc0, 0x34, 0x90, 0xf4, 0x67, 0xdb, 0x06, 0x51, 0xc2, 0x0b, 0x1d, 0xf6, 0x0e, 0xb9, 0x7a, 0x3c, 0x99, 0xd9, 0xbd, 0x66, 0x4b, 0xe6, 0xa5, 0xe4, 0xc8, 0xa8, 0xad, 0x4c, 0xc3, 0x63, 0x90, 0xd7, 0x00, 0x4e, 0x4b, 0xb4, 0x21, 0xda, 0xed, 0x65, 0x4c, 0x35, 0x7d, 0xa4, 0xd6, 0x84, 0x98, 0x93, 0x3e, 0xc7, 0x17, 0x77, 0xad, 0x64, 0xc2, 0xae, 0x01, 0x3c, 0x73, 0xeb, 0x45, 0x7c, 0x68, 0xef, 0x9a, 0x74, 0x5a, 0xde, 0xeb, 0x4f, 0xdf, 0xc8, 0x79, 0xe7, 0x74, 0xd0, 0x3f, 0xaf, 0x6b, 0x14, 0xaa, 0xb1, 0x07, 0x52, 0xe2, 0x4b, 0x52, 0xd0, 0xf2, 0xd9, 0x4d, 0x54, 0x0a, 0x1e, 0xbe, 0x10, 0xf5, 0x97, 0xe5, 0x14, 0x44, 0x2d, 0x6c, 0x13, 0xc2, 0xe2, 0x49, 0x8e, 0x8a, 0xf3, 0x01, 0x7c, 0x52, 0xdb, 0x23, 0x3a, 0x90, 0x71, 0x7d, 0xf2, 0x5b, 0x4d, 0x07, 0x2b, 0x7d, 0x88, 0xee, 0x87, 0x31, 0xd1, 0x68, 0x24, 0xc9, 0x5d, 0x1f, 0xb9, 0x83, 0xc4, 0x49, 0xde, 0xb4, 0x66, 0x27, 0x60, 0x60, 0xfe, 0xe4, 0xc7, 0xee, 0x38, 0x14, 0x51, 0xf2, 0x32, 0xc2, 0x9c, 0x7c, 0x32, 0x20, 0x85, 0x0c, 0x61, 0xd1, 0xc3, 0xc0, 0x0d, 0xb1, 0xcd, 0x97, 0x26, 0xa0, 0x2a, 0x56, 0x60, 0x9f, 0x3a, 0x65, 0xd3, 0xd1, 0x64, 0x60, 0x45, 0x88, 0xcd, 0x9b, 0x43, 0x14, 0x12, 0xf1, 0xad, 0xd9, 0x14, 0xc5, 0xc2, 0xda, 0xbb, 0xc9, 0x04, 0x67, 0xc0, 0xc4, 0xea, 0x5f, 0x76, 0xe2, 0x4a, 0xa6, 0x18, 0x76, 0x5f, 0x8b, 0x06, 0x36, 0xd7, 0xb0, 0x65, 0xe1, 0xf4, 0xe6, 0xf6, 0x22, 0xea, 0xe1, 0x71, 0x52, 0x45, 0x8c, 0x76, 0x65, 0x86, 0x77, 0x2d, 0x36, 0x3f, 0xa9, 0x92, 0x14, 0xf4, 0x72, 0xb0, 0xdb, 0x8a, 0x1e, 0x49, 0xd8, 0x2d, 0x02, 0x78, 0xf2, 0x95, 0x8b, 0x0a, 0xaa, 0x15, 0x86, 0xdb, 0x13, 0x4b, 0xdf, 0xd2, 0x43, 0x87, 0x42, 0x49, 0x50, 0x07, 0xe2, 0xfe, 0x5b, 0x60, 0xe2, 0x46, 0x39, 0x92, 0x26, 0x94, 0x7a, 0x12, 0xea, 0x17, 0x63, 0x1c, 0xaa, 0x53, 0x46, 0x87, 0xcb, 0x75, 0xc0, 0x60, 0xb4, 0x79, 0x7e, 0xab, 0x82, 0x77, 0xcc, 0x4f, 0x8a, 0x7a, 0x20, 0x38, 0x76, 0x06, 0xef, 0xe2, 0xdb, 0xd3, 0xe7, 0x36, 0x24, 0x92, 0x77, 0xd9, 0x0f, 0xca, 0xb9, 0x92, 0xa8, 0xc9, 0x9e, 0x85, 0xab, 0x03, 0xeb, 0x4c, 0xac, 0x5d, 0x88, 0x55, 0x39, 0x58, 0x52, 0x8a, 0xf9, 0x29, 0x74, 0x71, 0x81, 0x35, 0xf1, 0xd0, 0xc7, 0x93, 0xeb, 0x00, 0x0e, 0xa0, 0xae, 0xc3, 0xec, 0x18, 0x58, 0xfd, 0xd1, 0x86, 0x88, 0xd1, 0xda, 0x27, 0x27, 0x8d, 0xeb, 0xf2, 0xca, 0x81, 0x10, 0xba, 0x4a, 0x20, 0x4f, 0x79, 0x30, 0xe1, 0xc8, 0xce, 0xec, 0xaf, 0xb7, 0x3f, 0x75, 0xdd, 0xb3, 0x4c, 0x5c, 0x55, 0x96, 0x8a, 0x79, 0x33, 0x05, 0x84, 0x26, 0xb5, 0x5d, 0x03, 0x9f, 0x72, 0x92, 0xac, 0x43, 0xf6, 0x45, 0x84, 0xf6, 0xdf, 0x18, 0x7a, 0x1d, 0x6b, 0x00, 0x3f, 0x51, 0x4c, 0xc1, 0x3b, 0x26, 0xc2, 0xf3, 0x48, 0x19, 0x5a, 0xa3, 0x21, 0xde, 0x6a, 0x27, 0xec, 0x11, 0x34, 0x8d, 0xe5, 0x0d, 0x82, 0x5a, 0x29, 0x64, 0xc6, 0x31, 0x99, 0x2e, 0x4b, 0x0b, 0x42, 0x5b, 0x1b, 0xeb, 0x4f, 0x96, 0x00, 0xe3, 0xad, 0xc4, 0x43, 0x1c, 0xf2, 0xe8, 0x8b, 0x42, 0x23, 0xd2, 0xdb, 0x66, 0x3c, 0x3c, 0xe7, 0x0e, 0xf8, 0x5d, 0xdd, 0x56, 0xa9, 0xba, 0xf1, 0x38, 0xa9, 0xd7, 0xed, 0xd8, 0x94, 0x13, 0x1c, 0x3a, 0x8f, 0x41, 0xa0, 0x4e, 0xf9, 0xf8, 0x67, 0x52, 0xb7, 0x21, 0x81, 0xfa, 0xbb, 0x37, 0xc8, 0x6b, 0x87, 0x7e, 0x61, 0xd6, 0x0e, 0xed, 0x95, 0xee, 0xff, 0xab, 0xe6, 0x37, 0x6e, 0x14, 0xac, 0xa8, 0x17, 0xc5, 0xf4, 0x19, 0x61, 0xaf, 0x8a, 0x78, 0x49, 0xba, 0xc0, 0x94, 0x91, 0x7b, 0x2d, 0x13, 0x22, 0x76, 0xb6, 0xb3, 0x48, 0x6a, 0xff, 0x95, 0x0d, 0x23, 0xd4, 0xaa, 0xdc, 0x24, 0xce, 0x98, 0xa5, 0x26, 0x9e, 0x1c, 0x69, 0x91, 0x79, 0x60, 0xa3, 0x1e, 0xe0, 0x9a, 0x52, 0x7c, 0x35, 0x81, 0x75, 0xca, 0xa0, 0xcb, 0x1b, 0x01, 0x8e, 0x95, 0x26, 0xd9, 0x35, 0x34, 0xea, 0xdb, 0xac, 0xb5, 0x2b, 0x27, 0x3d, 0x73, 0x5e, 0x22, 0xdd, 0x0d, 0x5c, 0x28, 0xfa, 0x3e, 0x47, 0xcf, 0xe9, 0x0b, 0x52, 0x15, 0xae, 0x24, 0xf1, 0x46, 0xc3, 0x46, 0x4b, 0xfe, 0xaf, 0x01, 0xd2, 0x8d, 0xaa, 0x55, 0x3c, 0x1e, 0x94, 0x42, 0x8a, 0x10, 0x4a, 0x9d, 0x78, 0xae, 0xc7, 0x62, 0x59, 0x1e, 0x88, 0x79, 0xf7, 0x68, 0x51, 0xcf, 0xb4, 0x64, 0x85, 0x66, 0x72, 0x1b, 0x0c, 0xac, 0x1f, 0x14, 0xfe, 0x16, 0x14, 0x9a, 0x9d, 0x82, 0x10, 0xcc, 0x8f, 0x2f, 0x50, 0xde, 0xf7, 0xb4, 0x6c, 0x84, 0x3b, 0xe9, 0x3b, 0xd8, 0xd5, 0x56, 0x02, 0x49, 0x33, 0x50, 0xab, 0x56, 0x0e, 0xa5, 0xba, 0x17, 0x71, 0x64, 0x23, 0xbe, 0x0e, 0xb8, 0x36, 0x0a, 0xb1, 0x09, 0xd8, 0xfb, 0x18, 0xbf, 0xea, 0x04, 0x08, 0x47, 0xb7, 0x33, 0x51, 0x45, 0xd4, 0xf2, 0x00, 0xd1, 0x9c, 0xf6, 0xfe, 0x7b, 0xac, 0x91, 0x7f, 0x42, 0x6c, 0x9b, 0x3d, 0x39, 0xa9, 0xca, 0x43, 0x29, 0x81, 0x8f, 0x24, 0x0e, 0x7d, 0xa3, 0x82, 0x76, 0x10, 0x72, 0xf4, 0xa6, 0x50, 0x5e, 0xa8, 0xe7, 0x6c, 0x1e, 0x44, 0x6f, 0xeb, 0x66, 0x25, 0xe3, 0x8d, 0xdb, 0xcd, 0x3c, 0xda, 0x81, 0xe8, 0x3b, 0xf7, 0x68, 0xf3, 0xe0, 0x1d, 0x9d, 0x26, 0x3b, 0x36, 0x73, 0x03, 0xae, 0x15, 0x6c, 0x0b, 0x71, 0x83, 0x36, 0x4a, 0x1e, 0x79, 0x41, 0xa0, 0x92, 0x98, 0xa3, 0xad, 0xf7, 0xbd, 0x23, 0x1e, 0x61, 0x14, 0xb9, 0xdc, 0xe7, 0x95, 0x2b, 0x11, 0x3f, 0x78, 0x16, 0x31, 0x38, 0xb9, 0x26, 0x6f, 0x84, 0x3f, 0x1e, 0xd9, 0x7d, 0x9c, 0x2b, 0x16, 0x3a, 0x6e, 0x8b, 0xd4, 0xc1, 0xab, 0x4e, 0x17, 0x93, 0x67, 0xc5, 0xac, 0x96, 0xce, 0xcf, 0x50, 0x50, 0xfe, 0x82, 0x1f, 0xdf, 0xa4, 0x4e, 0x9e, 0x68, 0x0b, 0x61, 0xc6, 0x01, 0x89, 0x32, 0xdf, 0x71, 0x78, 0x11, 0x45, 0x9a, 0xf2, 0x54, 0x2e, 0x2c, 0xde, 0x77, 0x17, 0x8c, 0x2e, 0x98, 0x80, 0xf0, 0x11, 0xe4, 0x05, 0xea, 0xfa, 0x59, 0xc8, 0xcb, 0xbe, 0xd7, 0x6e, 0x5a, 0x19, 0x41, 0x10, 0x4b, 0x1b, 0x9d, 0x3a, 0x60, 0x49, 0x1c, 0x95, 0x47, 0x55, 0xe0, 0x2e, 0x89, 0x41, 0x03, 0xf1, 0xf4, 0x97, 0x74, 0x75, 0xe9, 0xea, 0x36, 0x60, 0x9f, 0xd6, 0x7c, 0x9d, 0xe3, 0x18, 0xed, 0xa2, 0x37, 0x0d, 0xcc, 0xdb, 0xb9, 0xce, 0xf7, 0xae, 0x63, 0x60, 0x90, 0x5e, 0xc2, 0x20, 0x83, 0x8c, 0x97, 0x69, 0x82, 0x34, 0x41, 0xcd, 0xd0, 0xda, 0x8e, 0xf0, 0xab, 0xe5, 0xf2, 0xd1, 0xd7, 0x6e, 0x2f, 0xe0, 0x8f, 0xef, 0x53, 0xde, 0x1d, 0x61, 0x66, 0xab, 0x1a, 0x92, 0xb1, 0xac, 0x09, 0x3e, 0x5a, 0xbf, 0x76, 0x58, 0xc4, 0xb5, 0x72, 0x87, 0xf2, 0xd1, 0xfd, 0x7b, 0x82, 0xde, 0xda, 0xf8, 0xd5, 0xa4, 0xfb, 0xac, 0x4b, 0x35, 0xd5, 0x82, 0x31, 0x69, 0x4e, 0x16, 0x24, 0x97, 0x57, 0x8a, 0xbd, 0x7a, 0xa7, 0xc8, 0xfe, 0x7b, 0x35, 0x41, 0xa7, 0xf1, 0x8e, 0x54, 0xe8, 0xb7, 0xf0, 0x87, 0x64, 0xc5, 0xe6, 0x84, 0x49, 0xdf, 0x65, 0x59, 0x01, 0x54, 0x98, 0x32, 0xd6, 0x28, 0xfa, 0x63, 0xd2, 0xb2, 0xc5, 0xa1, 0x50, 0x93, 0x39, 0x94, 0xa9, 0x86, 0x33, 0x17, 0xad, 0x40, 0xd7, 0x78, 0xd9, 0xd2, 0xc0, 0x5c, 0x78, 0x98, 0x85, 0x0b, 0x90, 0x17, 0x32, 0x23, 0xc7, 0xa0, 0xaf, 0x89, 0x0f, 0xd7, 0xe6, 0x62, 0x21, 0xb6, 0xf0, 0x63, 0x18, 0xb2, 0xed, 0x5e, 0x19, 0x9c, 0xb4, 0x24, 0x88, 0x5a, 0xb8, 0x41, 0xe7, 0xa4, 0x72, 0x6f, 0xab, 0xa2, 0xf9, 0xbb, 0x53, 0xbc, 0x32, 0x36, 0x43, 0x4c, 0x35, 0xfb, 0xbe, 0x4b, 0x1a, 0x0f, 0x93, 0xf5, 0x0c, 0x37, 0x89, 0x6c, 0x29, 0xf8, 0xe3, 0x02, 0xad, 0x31, 0xed, 0x33, 0x31, 0xd6, 0x20, 0xe3, 0xb6, 0x29, 0x45, 0x51, 0x01, 0xa1, 0xf1, 0xcc, 0x7b, 0xa5, 0xe4, 0x6e, 0x68, 0xed, 0x4a, 0x8c, 0xcc, 0x87, 0xb4, 0xdc, 0x75, 0xbc, 0x01, 0x62, 0xb6, 0x33, 0x0f, 0x83, 0x3f, 0xba, 0x25, 0x75, 0xdf, 0xaf, 0x5b, 0x5f, 0x28, 0xbc, 0x54, 0xff, 0x2b, 0xa8, 0x1e, 0x7a, 0x47, 0x31, 0x3c, 0x15, 0x48, 0x2b, 0x60, 0x5e, 0x66, 0xbb, 0x38, 0xc6, 0x19, 0x8f, 0x13, 0x92, 0x10, 0x40, 0x80, 0xfb, 0xe7, 0x8b, 0x86, 0xb1, 0xbc, 0x9a, 0x6f, 0xb8, 0x81, 0xf5, 0xc7, 0x82, 0x01, 0x47, 0xe6, 0xba, 0x14, 0xb8, 0x1a, 0xcc, 0xf2, 0x0c, 0xae, 0x96, 0x64, 0x10, 0x94, 0xc2, 0x16, 0x90, 0x2e, 0xa5, 0xc1, 0x25, 0xf6, 0xc9, 0x35, 0xa1, 0x50, 0xd7, 0xc9, 0xac, 0xc5, 0xd9, 0xe2, 0xe5, 0xd9, 0x0e, 0x38, 0xc0, 0x50, 0x3a, 0xa9, 0x42, 0x60, 0x17, 0xc7, 0x6a, 0xaf, 0xcd, 0x52, 0x61, 0xb5, 0x06, 0x27, 0x4e, 0xc1, 0x3a, 0x96, 0x79, 0xfb, 0x09, 0x79, 0x60, 0x27, 0xa4, 0xbb, 0x75, 0x9d, 0x92, 0x82, 0x79, 0xb9, 0x4d, 0x84, 0x1a, 0x09, 0x73, 0x93, 0xbf, 0x7e, 0x5b, 0xd6, 0x9a, 0x49, 0x6c, 0xc3, 0xde, 0xcd, 0x2b, 0x0f, 0x07, 0xf8, 0x33, 0x92, 0xaa, 0xde, 0x33, 0xdc, 0x51, 0xb2, 0xa8, 0x4f, 0x6a, 0x07, 0x63, 0x5d, 0xc0, 0xef, 0x57, 0xa9, 0xad, 0x59, 0x59, 0xb6, 0xa5, 0x0b, 0x7b, 0xa5, 0x09, 0xad, 0x5b, 0x11, 0xfa, 0xd2, 0x6b, 0x41, 0x9f, 0x9f, 0x1e, 0x3f, 0x9c, 0x73, 0x29, 0xb5, 0xa9, 0x53, 0xd7, 0xcc, 0x87, 0xb2, 0xde, 0x21, 0x06, 0x11, 0xcf, 0x52, 0xa6, 0x39, 0xef, 0x2b, 0x39, 0x08, 0x01, 0x2c, 0xb8, 0x8e, 0x1d, 0x6f, 0x57, 0x62, 0x50, 0x79, 0xcb, 0x10, 0x3d, 0x6c, 0x98, 0x10, 0x1a, 0x11, 0xbd, 0x22, 0x33, 0xb6, 0x56, 0x02, 0xca, 0x30, 0x49, 0xbd, 0x32, 0x05, 0x20, 0x41, 0x9f, 0x76, 0xb0, 0x61, 0xe3, 0x59, 0x8d, 0xe3, 0x81, 0x52, 0xc8, 0x87, 0x67, 0xd1, 0xa2, 0x4f, 0xbd, 0x02, 0xbb, 0x10, 0xc3, 0x8e, 0xac, 0xae, 0x31, 0x7d, 0xe6, 0xbb, 0x28, 0x7b, 0x4d, 0x2c, 0xae, 0x5d, 0xa0, 0x21, 0x49, 0x65, 0xd8, 0x77, 0x37, 0x78, 0x62, 0x6e, 0x9b, 0x97, 0x28, 0x59, 0xd8, 0x48, 0x2b, 0x8d, 0x05, 0x47, 0xe4, 0xf5, 0x6d, 0xff, 0x87, 0x68, 0x1d, 0x5b, 0xc5, 0x12, 0x0f, 0x61, 0x3f, 0xbb, 0xd9, 0x1e, 0x1f, 0x14, 0xe6, 0xde, 0xfe, 0x67, 0x2e, 0x2a, 0x7e, 0xab, 0xcb, 0xbb, 0x9b, 0x11, 0x08, 0x2c, 0x5e, 0x70, 0x0a, 0xa0, 0xb1, 0xf7, 0xc1, 0x78, 0x5f, 0xce, 0xd1, 0x9a, 0x93, 0xaf, 0xe7, 0xc5, 0x9f, 0xa2, 0x51, 0x9b, 0xcd, 0xeb, 0x49, 0x4c, 0x3d, 0x13, 0xb2, 0x12, 0x5f, 0x38, 0x53, 0x23, 0xb8, 0x16, 0xc6, 0x8f, 0x8f, 0x56, 0x28, 0xc7, 0xc2, 0xab, 0xfd, 0x02, 0x78, 0xa3, 0x37, 0x07, 0x3d, 0xa7, 0x4d, 0x16, 0x09, 0x96, 0x98, 0xc4, 0xb1, 0x14, 0xe8, 0xa8, 0xce, 0x34, 0x4e, 0x0a, 0x15, 0xd0, 0xfc, 0x7e, 0xd4, 0x97, 0xb0, 0x01, 0xd5, 0x3d, 0x4c, 0x96, 0xdc, 0x39, 0x54, 0xd3, 0xb4, 0xb9, 0x56, 0xcb, 0x9d, 0x2a, 0x27, 0x2c, 0x51, 0xf1, 0x55, 0x9b, 0x22, 0x90, 0x4b, 0x40, 0xcc, 0x85, 0x31, 0xe4, 0x0c, 0xc4, 0x12, 0xc6, 0x8c, 0xb6, 0xee, 0xa4, 0xa4, 0x09, 0x0b, 0x38, 0xe2, 0x79, 0x73, 0x29, 0x98, 0x54, 0x67, 0xe8, 0x18, 0xa5, 0x24, 0xd3, 0x22, 0x8e, 0xac, 0xae, 0x78, 0x25, 0xd3, 0xda, 0xd2, 0xea, 0xa4, 0x22, 0xfd, 0xc7, 0x7a, 0xed, 0x71, 0xa2, 0x05, 0xda, 0x78, 0x38, 0xd9, 0x45, 0xe7, 0xfe, 0xc3, 0x7e, 0x4d, 0xca, 0x67, 0xe5, 0x04, 0xce, 0x35, 0xe5, 0xb0, 0x45, 0xf5, 0x6f, 0x1e, 0x8d, 0x75, 0x29, 0xeb, 0xd6, 0xf1, 0xaf, 0x7b, 0x6e, 0x93, 0x9e, 0x2b, 0x7a, 0xb4, 0x02, 0x7d, 0x37, 0xa5, 0x13, 0x5d, 0x17, 0x2d, 0xa1, 0xaf, 0x9c, 0xa2, 0xf7, 0x28, 0xa6, 0xf3, 0x7d, 0xe6, 0x0d, 0xd2, 0x3d, 0x97, 0xd1, 0x1e, 0x75, 0xab, 0x1f, 0xd5, 0x1f, 0x8e, 0x9a, 0x13, 0x97, 0xe5, 0x82, 0x21, 0x59, 0xdb, 0x58, 0x38, 0x02, 0xb3, 0x2e, 0xeb, 0xb4, 0x56, 0x7e, 0xce, 0x37, 0x46, 0xd1, 0xae, 0x33, 0x31, 0x47, 0x85, 0x64, 0x3d, 0xd2, 0xa0, 0x74, 0x1e, 0x7f, 0x1b, 0xf2, 0xd2, 0x61, 0xf2, 0x21, 0x24, 0xe8, 0xdd, 0xd0, 0x8c, 0x64, 0x0a, 0x48, 0xb5, 0x47, 0x17, 0x51, 0x7c, 0x21, 0xcd, 0x32, 0x53, 0x28, 0xbc, 0x23, 0x9c, 0xa0, 0x28, 0xb2, 0x63, 0x0d, 0x06, 0x3c, 0x8c, 0xc2, 0x0b, 0xe9, 0xbd, 0xb4, 0x85, 0x02, 0xda, 0xdd, 0xe7, 0x3f, 0xfe, 0xd5, 0x96, 0x38, 0x16, 0x53, 0x3e, 0x02, 0x0a, 0xed, 0x12, 0x08, 0x53, 0x62, 0x55, 0xb1, 0xcc, 0xe9, 0x85, 0x43, 0x31, 0x27, 0xff, 0x4f, 0x04, 0xd5, 0xb1, 0xe2, 0xf2, 0x10, 0x87, 0x04, 0xb8, 0xb9, 0x66, 0x58, 0x8c, 0x01, 0x56, 0xaf, 0xc2, 0xae, 0x19, 0x29, 0x86, 0xfb, 0xec, 0x44, 0x3b, 0xae, 0xf6, 0xcb, 0x85, 0xa6, 0xf2, 0x9c, 0x77, 0x92, 0x40, 0x5a, 0x24, 0x11, 0x47, 0x10, 0xae, 0x1c, 0x74, 0x64, 0x44, 0xfd, 0xf5, 0xfb, 0x65, 0x9e, 0x5e, 0x34, 0x68, 0x26, 0x20, 0x7b, 0x8c, 0x54, 0x46, 0x3a, 0x06, 0x17, 0xce, 0x17, 0xff, 0x33, 0xe4, 0x0f, 0x93, 0x1f, 0xe5, 0x76, 0x71, 0x5c, 0x93, 0x2e, 0xf2, 0x9f, 0xd7, 0x6b, 0x04, 0xa6, 0x9b, 0x58, 0xe0, 0x30, 0x3d, 0x8e, 0xf2, 0x56, 0x78, 0xc8, 0xb7, 0x0a, 0xf1, 0x2e, 0x90, 0x45, 0x59, 0x1c, 0x04, 0xe8, 0xb7, 0x71, 0x06, 0x94, 0x04, 0x15, 0x17, 0x7e, 0x86, 0x85, 0x93, 0xa0, 0x9c, 0x7e, 0x14, 0x61, 0x9a, 0x4b, 0x33, 0x2f, 0x9a, 0xdc, 0x3a, 0x65, 0x8b, 0x86, 0x01, 0x7f, 0x32, 0x65, 0x6c, 0x54, 0x29, 0xc1, 0x15, 0xe1, 0x10, 0x03, 0x7a, 0x8c, 0xc7, 0xe5, 0x44, 0x67, 0x7d, 0x2d, 0xd2, 0x39, 0xa5, 0x9d, 0x54, 0xd0, 0xf3, 0xc7, 0x46, 0x0e, 0xc1, 0x52, 0x08, 0x34, 0x6b, 0xa5, 0x6d, 0xf5, 0x08, 0x6c, 0x5d, 0xbc, 0xc4, 0x1e, 0x0c, 0x95, 0xfc, 0xb6, 0x86, 0x1c, 0x2c, 0x0c, 0x32, 0xaa, 0xf3, 0x45, 0x4e, 0xfe, 0xe2, 0xff, 0xba, 0x21, 0x4b, 0x43, 0x0e, 0xf2, 0x48, 0xa5, 0x9b, 0x32, 0x44, 0x4d, 0x8d, 0x0d, 0x3d, 0xb8, 0x7c, 0x9d, 0x4b, 0x15, 0x36, 0xd1, 0x57, 0x72, 0x8e, 0xe7, 0x58, 0x5e, 0xf5, 0x32, 0x77, 0x6a, 0x00, 0x3a, 0x02, 0x3c, 0x0a, 0xb0, 0xe9, 0xff, 0x55, 0x71, 0x08, 0xc3, 0x90, 0x68, 0x4d, 0x56, 0x5a, 0x66, 0x50, 0x63, 0x26, 0x6a, 0xe6, 0x67, 0x0e, 0xd5, 0x3b, 0x0f, 0xaf, 0x8f, 0xf6, 0x78, 0x29, 0xbb, 0x73, 0x78, 0x25, 0xb1, 0x53, 0xa9, 0x33, 0x8c, 0xbe, 0x3d, 0xf1, 0xa4, 0x62, 0x84, 0x9b, 0x93, 0xa8, 0x1f, 0x84, 0xed, 0x07, 0xbe, 0x6d, 0x62, 0x40, 0x00, 0x32, 0x74, 0x73, 0x7f, 0x61, 0x8d, 0xcb, 0x26, 0xe4, 0x82, 0x52, 0xce, 0x42, 0x04, 0xdd, 0x31, 0x39, 0xff, 0x68, 0x76, 0xf4, 0x3b, 0x30, 0x5d, 0x83, 0x56, 0x20, 0xfe, 0xdf, 0x79, 0xaa, 0x67, 0x43, 0x3d, 0xc2, 0x52, 0x87, 0x32, 0x0e, 0x99, 0x17, 0x96, 0x7b, 0x70, 0xb2, 0xd8, 0x66, 0xd1, 0x7b, 0x69, 0x8b, 0xff, 0xf2, 0xb3, 0xab, 0x95, 0x14, 0x94, 0x9e, 0x58, 0xb5, 0x7c, 0x68, 0xa4, 0x54, 0x12, 0xc1, 0xfc, 0x42, 0x1c, 0x76, 0x8b, 0xf5, 0xee, 0x8a, 0x10, 0xc8, 0xae, 0xf5, 0x69, 0x26, 0xf5, 0x1e, 0xc6, 0x2c, 0x11, 0x56, 0x9f, 0x31, 0xaa, 0x51, 0x78, 0x68, 0xe5, 0xca, 0xd8, 0x9e, 0x95, 0x80, 0x66, 0xeb, 0x9e, 0xdd, 0x72, 0x71, 0xb3, 0x1c, 0xb4, 0xb1, 0xd6, 0xce, 0x21, 0x12, 0x25, 0xae, 0xb5, 0xb5, 0x7f, 0x74, 0x97, 0x19, 0xda, 0x07, 0xec, 0xbe, 0xfe, 0x03, 0x88, 0x1d, 0xde, 0x3d, 0x81, 0xe4, 0x13, 0x5f, 0x2d, 0xc8, 0x1a, 0xf7, 0x79, 0x77, 0x6c, 0x1b, 0x80, 0x57, 0x16, 0x2a, 0x6c, 0x98, 0x2f, 0xbb, 0x4d, 0xa6, 0xa9, 0xad, 0x28, 0x4a, 0xb1, 0x0c, 0x70, 0x02, 0x20, 0x44, 0xf4, 0x6d, 0x40, 0x0b, 0xf6, 0xad, 0x71, 0x82, 0xd1, 0x97, 0x78, 0x99, 0x83, 0xbe, 0x99, 0x22, 0x79, 0x79, 0xa1, 0x33, 0x4b, 0xa1, 0x49, 0xd8, 0x69, 0xba, 0x1c, 0x40, 0x88, 0x12, 0x34, 0x35, 0xbf, 0x97, 0x85, 0x41, 0x35, 0x6d, 0xaf, 0x17, 0x1f, 0x33, 0xad, 0xb1, 0xc9, 0x79, 0x07, 0xa0, 0xfb, 0x58, 0x45, 0x07, 0x4a, 0x85, 0xd2, 0x6f, 0x54, 0x61, 0x35, 0xae, 0xd0, 0xf9, 0x1b, 0xe4, 0x53, 0x9c, 0x12, 0xbf, 0x94, 0x11, 0xe4, 0xb5, 0x56, 0xf6, 0x87, 0xd0, 0x69, 0xdb, 0x6b, 0x21, 0xfe, 0x2b, 0x7f, 0x32, 0x18, 0x87, 0x44, 0x8c, 0xea, 0x55, 0xdb, 0x19, 0xfb, 0xb8, 0xb0, 0x48, 0x2a, 0x55, 0xae, 0xc1, 0x67, 0x38, 0xd7, 0x4c, 0xd2, 0x65, 0x09, 0x38, 0x36, 0xbe, 0x99, 0xd4, 0xfb, 0x53, 0xe9, 0xb0, 0x14, 0xb0, 0x37, 0xcd, 0xbf, 0xe9 }, .t1_len = 2560, }, { .name = "ML-DSA 87 (seed only)", .parameter_set = CKP_IBM_ML_DSA_87, .priv_seed = { 0xAD, 0xF8, 0xFA, 0x33, 0x6C, 0x59, 0xB7, 0x88, 0x6E, 0x1B, 0x00, 0xF2, 0x5C, 0x3D, 0xC7, 0x39, 0x47, 0x92, 0x78, 0x77, 0xE2, 0x71, 0x36, 0xFD, 0x6C, 0xDF, 0x68, 0xE5, 0x53, 0x1D, 0x33, 0xF4 }, .priv_seed_len = 32, .spki = { 0x30, 0x82, 0x0a, 0x32, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x13, 0x03, 0x82, 0x0a, 0x21, 0x00, 0x8e, 0xc7, 0xa1, 0x4b, 0x5a, 0x76, 0x94, 0x04, 0x4a, 0x48, 0x50, 0x3f, 0xca, 0xfe, 0x56, 0x27, 0xb9, 0x16, 0x34, 0x99, 0xaa, 0xd6, 0x98, 0xdd, 0x1a, 0xb1, 0x15, 0x58, 0xe0, 0xcb, 0xd0, 0x7c, 0x12, 0x8e, 0x94, 0x05, 0x91, 0x68, 0xb5, 0x5b, 0xb5, 0xf4, 0xc0, 0xd0, 0x17, 0xc0, 0x00, 0xf3, 0x21, 0x5b, 0xa0, 0x47, 0x95, 0x0f, 0x41, 0xaa, 0x7f, 0x48, 0x03, 0x7d, 0x84, 0xdb, 0x0d, 0x95, 0xf1, 0x2a, 0xc3, 0x61, 0xed, 0xa8, 0xf2, 0x70, 0x28, 0xef, 0x35, 0xc9, 0xf6, 0x84, 0x54, 0x6e, 0x36, 0x64, 0xef, 0x61, 0xbc, 0xd8, 0xf7, 0x63, 0x29, 0x7c, 0x18, 0x1c, 0x6f, 0x68, 0x26, 0x66, 0xb2, 0xa9, 0x00, 0x56, 0x78, 0x50, 0xf1, 0x6f, 0x41, 0x74, 0x6d, 0xd4, 0xeb, 0x99, 0x20, 0x61, 0x01, 0xd9, 0x76, 0xc8, 0x1f, 0x12, 0xc1, 0x0f, 0xbf, 0x19, 0x60, 0x31, 0x50, 0x2d, 0x64, 0xdb, 0xdf, 0x1e, 0x2b, 0x6d, 0x9c, 0x16, 0xc8, 0x09, 0x47, 0x64, 0xe8, 0x95, 0x3c, 0x20, 0xe1, 0x49, 0x05, 0xee, 0x52, 0x8a, 0xfa, 0x64, 0x72, 0x4d, 0x57, 0x60, 0x9b, 0xf1, 0xc5, 0x69, 0x0a, 0x3d, 0x21, 0xe2, 0x1b, 0x6d, 0xfb, 0xee, 0x99, 0xbb, 0x10, 0x9d, 0x07, 0xf3, 0x2a, 0x87, 0x04, 0x67, 0x9f, 0x19, 0xab, 0x27, 0x9e, 0x08, 0x5e, 0x8f, 0x8b, 0xa0, 0x34, 0x4b, 0x64, 0xad, 0x29, 0x8d, 0xa8, 0xc8, 0xdb, 0x97, 0xad, 0x87, 0xd6, 0x90, 0xf5, 0xc6, 0x0e, 0x0b, 0xdc, 0xe6, 0x8e, 0x07, 0x91, 0x3d, 0x9d, 0xee, 0xa0, 0xca, 0x68, 0x9e, 0x56, 0x12, 0xfe, 0x7a, 0x21, 0x8e, 0x82, 0xb3, 0x70, 0x64, 0xf7, 0xf4, 0x0d, 0x1b, 0xc4, 0x73, 0xc7, 0x83, 0xc2, 0x65, 0x8f, 0x58, 0x66, 0xc3, 0xb1, 0xb2, 0x46, 0x0c, 0xc6, 0x1a, 0xa8, 0x81, 0x36, 0x43, 0x9f, 0x18, 0x8f, 0x02, 0xc7, 0x36, 0xd4, 0xc7, 0xce, 0x83, 0xd0, 0xcf, 0x5a, 0x86, 0x56, 0x4b, 0xf5, 0x67, 0x03, 0xc9, 0x6b, 0x23, 0xaf, 0xae, 0x4a, 0xbc, 0x3d, 0x0c, 0xd4, 0x75, 0xcf, 0xed, 0x70, 0xbc, 0xa3, 0x6f, 0xd1, 0x9e, 0xf8, 0x41, 0xc1, 0x35, 0x25, 0x42, 0x2f, 0x00, 0x66, 0x02, 0x7d, 0x90, 0xbb, 0x39, 0xe9, 0x0a, 0x54, 0x0c, 0xc5, 0x4c, 0x83, 0x04, 0x45, 0x5c, 0xd5, 0xb5, 0xf1, 0x33, 0x5c, 0xe7, 0xe0, 0x34, 0x44, 0x6a, 0xb0, 0x78, 0xe7, 0xdb, 0xee, 0x8e, 0xe4, 0x56, 0xfc, 0x40, 0x9f, 0x9c, 0xbf, 0x50, 0xcf, 0x17, 0xee, 0x9a, 0xee, 0xf4, 0x98, 0x58, 0x79, 0xb6, 0xf0, 0x35, 0x60, 0x2f, 0x8c, 0x3c, 0x4c, 0x3c, 0x91, 0xb4, 0x7d, 0xf6, 0xd6, 0x8c, 0xb4, 0x19, 0xb5, 0x9f, 0xc2, 0x6d, 0x95, 0x5d, 0x85, 0x01, 0x7a, 0x51, 0x54, 0x51, 0x2e, 0x5c, 0x52, 0xbf, 0x76, 0xfd, 0xa9, 0x32, 0x84, 0x48, 0xf6, 0x5b, 0x3d, 0xf8, 0x73, 0xf7, 0x1d, 0x5a, 0xc0, 0xcf, 0xb7, 0x19, 0x57, 0x09, 0x85, 0x53, 0x42, 0xb8, 0x3f, 0x61, 0x80, 0x46, 0xcd, 0xa2, 0x7b, 0x24, 0xeb, 0x64, 0xef, 0xdd, 0x38, 0x4c, 0xf2, 0x81, 0x49, 0x55, 0xa8, 0x54, 0x22, 0x3a, 0x58, 0xad, 0x46, 0x6a, 0x0c, 0x1a, 0x0d, 0x8b, 0x2c, 0x11, 0xc4, 0x6c, 0x9e, 0xae, 0x5e, 0xe9, 0xaa, 0x61, 0x21, 0xb6, 0xc2, 0x57, 0xe6, 0x7f, 0x2f, 0x14, 0xbc, 0xff, 0x06, 0x7b, 0x57, 0x88, 0x16, 0x9d, 0x35, 0x87, 0xc1, 0x12, 0x2a, 0x10, 0x5e, 0xae, 0xd0, 0x81, 0xbb, 0x96, 0x57, 0x87, 0x11, 0xa3, 0x86, 0x07, 0x6f, 0x01, 0xa1, 0x3d, 0xb8, 0x31, 0x9a, 0x53, 0x5a, 0x5f, 0xbc, 0x3e, 0x63, 0xea, 0x24, 0x3e, 0x75, 0xd5, 0x06, 0xf4, 0xdf, 0x73, 0xdf, 0x7d, 0x90, 0x35, 0x9d, 0xc4, 0x4a, 0xfd, 0xee, 0xed, 0x3a, 0x7a, 0x39, 0xa7, 0x3e, 0x3d, 0xd0, 0x38, 0xad, 0xd8, 0xa2, 0x5c, 0x40, 0x31, 0x2f, 0xcb, 0x88, 0xa4, 0x83, 0xec, 0x23, 0xb5, 0xab, 0x8a, 0xad, 0x16, 0x79, 0x9d, 0x6c, 0x9b, 0x0f, 0x56, 0x64, 0xf2, 0xaa, 0x80, 0x26, 0x7a, 0x29, 0x96, 0xc6, 0x51, 0x1a, 0xb0, 0x0c, 0xab, 0x93, 0xe7, 0xc7, 0x61, 0xef, 0x1a, 0xd6, 0x87, 0xfe, 0x2f, 0x6b, 0x3b, 0x2a, 0x8f, 0xbe, 0x1e, 0x31, 0xb9, 0x98, 0x3f, 0x83, 0x46, 0xbd, 0xc6, 0x4f, 0xd5, 0xd9, 0xa9, 0x87, 0x69, 0x7a, 0x9b, 0x12, 0x07, 0xc2, 0xde, 0xfb, 0x11, 0x5c, 0x88, 0x97, 0xfa, 0xfb, 0xbe, 0x8e, 0xe7, 0x12, 0xb8, 0x95, 0x54, 0xc3, 0xf8, 0xba, 0x9e, 0x48, 0x90, 0x76, 0xef, 0x82, 0x06, 0x3f, 0x27, 0xad, 0x06, 0xb9, 0x46, 0xcc, 0xe5, 0x3a, 0x6d, 0x52, 0x10, 0x68, 0xb7, 0xf2, 0x55, 0xbc, 0xf2, 0xdc, 0x7a, 0xb9, 0x1c, 0xea, 0xeb, 0x4e, 0x20, 0x72, 0xe2, 0xd1, 0xd9, 0xe9, 0x8f, 0x44, 0x5d, 0xd4, 0xd3, 0x7c, 0x8e, 0x45, 0x16, 0x20, 0x2b, 0x6b, 0x01, 0xa0, 0x99, 0x26, 0x89, 0x72, 0xc3, 0xc0, 0x3d, 0x84, 0x1b, 0x9d, 0xfd, 0x4b, 0xd0, 0x60, 0x65, 0xe2, 0x8d, 0xcc, 0x97, 0x94, 0xf1, 0x67, 0x9e, 0xe5, 0xfb, 0xe3, 0xab, 0x24, 0x34, 0xa8, 0x33, 0xdb, 0x79, 0x39, 0xc2, 0x17, 0x17, 0x69, 0xd4, 0x18, 0xbf, 0xa2, 0x47, 0xcc, 0x51, 0xda, 0x94, 0x01, 0xa6, 0x28, 0xd9, 0x78, 0x8a, 0x90, 0x33, 0x26, 0x5f, 0x8f, 0x94, 0x32, 0x9b, 0xb7, 0x21, 0xd3, 0xc8, 0x1e, 0x96, 0x7e, 0x3a, 0x84, 0xce, 0x07, 0x04, 0x6c, 0x54, 0x2f, 0xc0, 0xf2, 0x26, 0x23, 0xc4, 0xfa, 0x0e, 0xc8, 0xb1, 0x1c, 0x79, 0x83, 0xdb, 0x04, 0xc0, 0x6e, 0xa2, 0x28, 0x10, 0x01, 0xa3, 0xfd, 0xc8, 0x1d, 0x1d, 0x70, 0x67, 0x3d, 0xc2, 0xe6, 0x0c, 0xb5, 0x97, 0x63, 0x4d, 0x97, 0x8f, 0x03, 0x68, 0xef, 0x5c, 0xe0, 0xf9, 0x42, 0xa0, 0x7d, 0x83, 0xe1, 0x97, 0xec, 0xe0, 0x12, 0x98, 0x7a, 0x4a, 0x90, 0x2b, 0xfb, 0x4b, 0x23, 0x3d, 0xa9, 0x96, 0x7c, 0x78, 0xec, 0x7a, 0xec, 0x57, 0x39, 0xc9, 0xa6, 0xc3, 0x76, 0xc2, 0x47, 0x89, 0x01, 0x9a, 0xd6, 0x4b, 0x65, 0x88, 0xa8, 0x78, 0x7f, 0x99, 0x87, 0xb9, 0xe9, 0x3a, 0xe6, 0xc9, 0xe2, 0xce, 0xc8, 0xe9, 0xc2, 0xcb, 0x5e, 0xf9, 0x9e, 0x77, 0xbf, 0x0e, 0x9f, 0x18, 0x6b, 0x89, 0xed, 0x1c, 0xe0, 0x14, 0x61, 0xb8, 0x44, 0xd7, 0xfe, 0xb2, 0x7b, 0x81, 0x90, 0xb0, 0x84, 0x0c, 0x4a, 0xaf, 0xbd, 0xef, 0x10, 0x6d, 0x1f, 0xf4, 0xc7, 0x18, 0x55, 0xbf, 0x03, 0x8c, 0x85, 0xeb, 0xd5, 0x1f, 0x48, 0x1d, 0x33, 0xe2, 0x0e, 0x44, 0x27, 0xcb, 0x4d, 0x0d, 0x11, 0xe4, 0x95, 0xb0, 0xec, 0x06, 0x1d, 0x18, 0x7d, 0x00, 0x3f, 0xe4, 0xbe, 0x64, 0x89, 0x07, 0xab, 0x65, 0xb7, 0x87, 0x34, 0xfa, 0x9f, 0x50, 0x96, 0x81, 0x7c, 0x69, 0xb8, 0xf5, 0x7c, 0xa7, 0xc5, 0x2f, 0xff, 0x94, 0x53, 0xfb, 0x8d, 0x07, 0xf6, 0xc5, 0x9c, 0x61, 0xb6, 0x28, 0xba, 0x72, 0x91, 0x35, 0x70, 0xc7, 0xc8, 0xc5, 0xd9, 0x7e, 0x6a, 0x5b, 0x22, 0x27, 0x07, 0x66, 0xfa, 0x44, 0x2c, 0x7a, 0x30, 0x76, 0xdb, 0xdb, 0x68, 0x10, 0xdc, 0x87, 0x1d, 0xa6, 0xab, 0x3f, 0x8e, 0xf7, 0xeb, 0x22, 0x85, 0x56, 0x95, 0x3e, 0xd3, 0xe4, 0xa0, 0x7f, 0xdc, 0x8e, 0x15, 0x3f, 0x99, 0xdc, 0x31, 0xe4, 0x17, 0x2a, 0x97, 0xd4, 0xaa, 0x64, 0x42, 0xaf, 0x98, 0x53, 0x5e, 0xf7, 0xf6, 0x70, 0xe0, 0xba, 0x57, 0xc3, 0x92, 0x3c, 0x42, 0x1f, 0x92, 0x0b, 0x89, 0x97, 0x13, 0x78, 0xc9, 0x49, 0xe4, 0xb5, 0xd8, 0x47, 0xcb, 0xd3, 0x37, 0x49, 0xc5, 0xee, 0x2b, 0x6f, 0x96, 0x84, 0x65, 0xda, 0xff, 0x76, 0xf4, 0x18, 0x6d, 0x6b, 0x79, 0xb4, 0xbd, 0x5b, 0x3f, 0x0e, 0xd0, 0xf0, 0xb8, 0xcf, 0xec, 0xc6, 0xe1, 0x9d, 0xa6, 0xe9, 0x2b, 0x3c, 0x70, 0xc7, 0xa6, 0x08, 0x0a, 0x64, 0xc0, 0x5c, 0xa8, 0xa2, 0x62, 0x4b, 0xcb, 0x19, 0x57, 0x55, 0xed, 0x75, 0x83, 0x6b, 0x70, 0x72, 0xf8, 0xb4, 0x88, 0xfa, 0x9f, 0x13, 0x47, 0x6a, 0x3b, 0x8e, 0xbf, 0x53, 0x84, 0x12, 0xe9, 0x41, 0x41, 0x6b, 0xcb, 0xb6, 0x62, 0xe4, 0x69, 0xe8, 0x15, 0xb9, 0x55, 0x70, 0x23, 0x69, 0xa5, 0xa5, 0x71, 0x52, 0xf0, 0x2d, 0x4e, 0x9d, 0x03, 0x05, 0x95, 0x3f, 0x31, 0x82, 0x92, 0x79, 0x38, 0xe0, 0xd8, 0xa9, 0x45, 0x8e, 0x6a, 0xbc, 0xf8, 0x08, 0xad, 0xf6, 0xb4, 0x85, 0xe4, 0x81, 0xdf, 0x97, 0xe4, 0x73, 0x67, 0xa2, 0x45, 0xf1, 0x5b, 0x40, 0x88, 0x38, 0xab, 0x6b, 0x4b, 0xb4, 0xce, 0x20, 0x63, 0x6e, 0x4f, 0x35, 0xf0, 0x83, 0xb4, 0x4d, 0xfe, 0xae, 0x51, 0xa0, 0x10, 0x12, 0xfa, 0x50, 0xfd, 0x6d, 0xec, 0x24, 0x49, 0x9b, 0x8e, 0x79, 0x51, 0xdf, 0xb9, 0xc2, 0x08, 0x71, 0x73, 0xad, 0xa4, 0x9e, 0x5a, 0x15, 0xcf, 0xfb, 0x26, 0xf7, 0xc6, 0xd5, 0xe8, 0x57, 0x1d, 0x03, 0xe7, 0xc1, 0xbd, 0x3b, 0xef, 0x90, 0x2c, 0xdb, 0xaf, 0xee, 0x31, 0x80, 0xf9, 0x5f, 0xc7, 0x26, 0xd0, 0xf3, 0x4a, 0x2f, 0x68, 0xd0, 0xfc, 0xa3, 0x7b, 0x42, 0x14, 0x6f, 0xcd, 0xa6, 0x5e, 0xc5, 0x38, 0x82, 0x7e, 0xf8, 0x87, 0xff, 0x74, 0x9a, 0x7a, 0x41, 0xab, 0x5c, 0x31, 0x60, 0x1f, 0xe0, 0xfb, 0x04, 0x5a, 0xa1, 0x2f, 0xd3, 0x45, 0x42, 0xea, 0x2b, 0xf2, 0x1a, 0xe4, 0x13, 0x20, 0xcd, 0xa7, 0x53, 0x53, 0x3f, 0x30, 0xc4, 0x8f, 0xd2, 0x3e, 0xc6, 0xc6, 0xbb, 0x0b, 0x14, 0x25, 0xe3, 0x61, 0x45, 0x8a, 0x9d, 0xc0, 0xf3, 0xfe, 0x7f, 0x7f, 0xd8, 0x42, 0x76, 0x41, 0x18, 0x06, 0x3c, 0x2c, 0x08, 0x2c, 0x20, 0x00, 0x62, 0xf7, 0xa7, 0x63, 0x01, 0xb6, 0x9f, 0x55, 0x40, 0xd3, 0x5a, 0xc3, 0x62, 0xed, 0xde, 0x64, 0x63, 0x7d, 0x15, 0x5f, 0x1d, 0x19, 0x52, 0x6e, 0xb1, 0xdc, 0x40, 0xd4, 0x6a, 0x66, 0x15, 0x47, 0x6d, 0x21, 0x16, 0x38, 0xd1, 0x1b, 0x96, 0x60, 0x32, 0x97, 0x35, 0x12, 0x28, 0xbc, 0x3d, 0x60, 0xa6, 0x53, 0x40, 0x73, 0x34, 0x98, 0x57, 0x61, 0x4c, 0x25, 0xbf, 0xa6, 0x73, 0xf8, 0x8b, 0xdf, 0xd5, 0xcc, 0x17, 0xd7, 0x3b, 0xf6, 0xd3, 0xda, 0x99, 0x73, 0x02, 0x0d, 0x32, 0xf6, 0x7b, 0x14, 0x18, 0xd7, 0xa2, 0x97, 0xa2, 0x0f, 0xaf, 0xec, 0x42, 0x60, 0xfb, 0x39, 0x71, 0x74, 0x20, 0xcf, 0xf9, 0x03, 0x03, 0xcf, 0x4d, 0xaa, 0x44, 0x26, 0xf0, 0x5c, 0x47, 0x24, 0x03, 0x5a, 0x42, 0x83, 0x12, 0x57, 0x0b, 0x64, 0x44, 0x6a, 0x56, 0x74, 0x7a, 0x69, 0xc6, 0x26, 0xbe, 0x42, 0xf8, 0x3d, 0x10, 0x4a, 0xdd, 0x14, 0x79, 0x8a, 0xea, 0x4c, 0x40, 0x9f, 0xdd, 0x84, 0xce, 0xce, 0xc3, 0x80, 0x60, 0xb4, 0xc5, 0x2d, 0xf5, 0x2f, 0x9f, 0x89, 0x1f, 0x16, 0x64, 0x75, 0xc5, 0x28, 0x11, 0xf7, 0x3a, 0x4f, 0xcf, 0x47, 0x7e, 0xa1, 0x8a, 0xa4, 0x40, 0x9a, 0x42, 0xdb, 0xa6, 0x11, 0x65, 0x6c, 0xa4, 0xfc, 0xa3, 0x5b, 0xe0, 0x1b, 0x5d, 0x41, 0x2d, 0x27, 0x43, 0xf2, 0xb0, 0x4f, 0xd8, 0x2d, 0xd4, 0x3d, 0x36, 0x74, 0x9a, 0xe6, 0xdb, 0x64, 0x05, 0x5d, 0x92, 0xdc, 0xaf, 0x18, 0xe0, 0xbc, 0x36, 0xca, 0xea, 0x13, 0x2c, 0xc9, 0x5c, 0x55, 0x20, 0xb9, 0xa0, 0xac, 0x44, 0x3e, 0xb2, 0x96, 0xa8, 0x78, 0x97, 0xaa, 0x58, 0x04, 0x3f, 0x68, 0x6b, 0x53, 0x00, 0x5e, 0xa1, 0x60, 0x2a, 0x4b, 0x45, 0x39, 0xdf, 0x25, 0xc3, 0x11, 0xb8, 0x75, 0x7e, 0x4b, 0x6d, 0xce, 0x84, 0x38, 0x0a, 0x79, 0x37, 0x8b, 0x5c, 0x3e, 0xb6, 0x0b, 0x71, 0x5a, 0x29, 0x58, 0xc7, 0x60, 0x17, 0x36, 0x04, 0xf6, 0xa3, 0x27, 0x05, 0xcd, 0x79, 0x2c, 0x00, 0xe3, 0x45, 0x85, 0x25, 0xc5, 0x04, 0xd3, 0x32, 0x7c, 0x60, 0x4b, 0xf3, 0x0b, 0x9d, 0xb5, 0x35, 0xee, 0x2e, 0x4d, 0xea, 0x89, 0xfc, 0x8c, 0xb6, 0x91, 0xaa, 0x61, 0xd5, 0x05, 0xfe, 0xcb, 0x60, 0x1d, 0x4e, 0x39, 0x1c, 0xf7, 0x05, 0x89, 0x5f, 0x20, 0x0a, 0xbb, 0xfd, 0x5a, 0xc2, 0x2f, 0x1f, 0x94, 0x6a, 0xa7, 0x9f, 0x53, 0xab, 0x1b, 0xf0, 0xb9, 0xe7, 0xff, 0xa0, 0x7a, 0x47, 0x3d, 0x84, 0x69, 0xf9, 0xeb, 0x7e, 0x09, 0xec, 0xbf, 0x6a, 0x34, 0xc2, 0x32, 0xf8, 0xf3, 0x31, 0x29, 0x92, 0xbe, 0x9e, 0x55, 0x4d, 0x3a, 0x3e, 0x2c, 0x32, 0x43, 0x02, 0x91, 0x6a, 0x76, 0x7c, 0x2e, 0x48, 0xd6, 0x4c, 0xbd, 0xde, 0xe9, 0x71, 0x20, 0xe8, 0x43, 0xaa, 0x40, 0xeb, 0x3f, 0xc5, 0xf4, 0xe8, 0xc9, 0x56, 0xbe, 0x2c, 0xf9, 0xa2, 0x7f, 0x77, 0xc5, 0x22, 0x0c, 0x3e, 0x71, 0xcb, 0xd9, 0x92, 0xed, 0x5a, 0x1f, 0x8d, 0x92, 0x7b, 0x4d, 0x30, 0x0f, 0x43, 0x41, 0xe1, 0xfa, 0xf8, 0x94, 0x88, 0x71, 0x1e, 0x0b, 0xfd, 0xe5, 0x5e, 0x8a, 0x2f, 0xc9, 0x57, 0x17, 0xb2, 0xb9, 0x94, 0x3a, 0xcf, 0x74, 0xa9, 0xb6, 0xb8, 0x52, 0xbc, 0xb8, 0x89, 0x35, 0x39, 0xae, 0x25, 0xa0, 0x81, 0xf9, 0xe0, 0xd7, 0x37, 0x39, 0x07, 0xab, 0xcc, 0x14, 0x2d, 0x84, 0x69, 0xbb, 0x55, 0xf9, 0xb0, 0xea, 0x51, 0x9f, 0xa6, 0xef, 0x3d, 0x7e, 0xd9, 0xdb, 0x1a, 0x81, 0x90, 0x8c, 0xe9, 0x27, 0xea, 0x29, 0x85, 0xe6, 0xcd, 0x4d, 0xa6, 0x4a, 0x10, 0x85, 0x78, 0x9b, 0x8a, 0x96, 0x07, 0x33, 0x52, 0x2d, 0xfc, 0xac, 0xd3, 0x3a, 0xb2, 0x4a, 0x22, 0xfd, 0x08, 0x33, 0x88, 0x45, 0x1c, 0xe5, 0x80, 0x32, 0xdd, 0xc3, 0x30, 0x6a, 0x5d, 0x66, 0xb8, 0x52, 0x91, 0x89, 0x4b, 0xa4, 0xa1, 0xe9, 0xb3, 0x76, 0x53, 0x7a, 0x03, 0x41, 0x7e, 0x87, 0xa8, 0x6a, 0x3a, 0x2f, 0xfc, 0xc4, 0xf1, 0x7c, 0xed, 0xa5, 0x4b, 0xd8, 0xc7, 0xa6, 0xc5, 0xaa, 0xa7, 0xb3, 0xb4, 0xf5, 0x17, 0x64, 0x43, 0x12, 0x0e, 0x3b, 0xde, 0x71, 0x57, 0xc6, 0xca, 0xd5, 0xfd, 0xf8, 0x8b, 0x42, 0x0d, 0xad, 0xb7, 0x43, 0x0c, 0x4b, 0x0e, 0xc7, 0xa8, 0x6a, 0xc3, 0x47, 0x38, 0x51, 0x8f, 0x6e, 0x14, 0xec, 0x7a, 0x92, 0xd4, 0x55, 0xfb, 0xa5, 0xc6, 0x28, 0x20, 0x6a, 0xee, 0x10, 0x37, 0x7d, 0xce, 0x60, 0x86, 0xb8, 0x35, 0xf9, 0x1a, 0xea, 0xfd, 0xe8, 0x0b, 0x18, 0xd6, 0xc7, 0xd9, 0xf2, 0xa6, 0x8a, 0xad, 0x16, 0x68, 0x4d, 0xe5, 0xdd, 0xb5, 0xf8, 0x5b, 0x1b, 0xa9, 0x1f, 0xdd, 0x46, 0xd1, 0xc6, 0x34, 0xea, 0x42, 0x04, 0x2b, 0x0e, 0xb7, 0x19, 0x87, 0xe0, 0x39, 0x8d, 0xb5, 0xd2, 0x4b, 0xf7, 0x1f, 0xed, 0xe0, 0x57, 0xf6, 0xb9, 0x9c, 0x9f, 0x9c, 0xea, 0xcc, 0x36, 0x4a, 0xdd, 0xef, 0x2c, 0x6a, 0x71, 0x66, 0x90, 0x60, 0x4a, 0x12, 0x7a, 0xb6, 0x5a, 0x8a, 0xb8, 0xfb, 0xf1, 0x2b, 0x68, 0x0d, 0x0d, 0x2c, 0xd4, 0xd0, 0x21, 0x09, 0x2f, 0x14, 0x2f, 0x5f, 0xa6, 0x42, 0x70, 0x48, 0xa2, 0xbc, 0x4d, 0x39, 0x21, 0x5c, 0x5a, 0x56, 0x70, 0xf4, 0x9c, 0x7c, 0x31, 0x6c, 0x6f, 0x7b, 0x3a, 0xa6, 0x3a, 0xf9, 0x28, 0x53, 0x0c, 0x85, 0x64, 0x4b, 0xde, 0x9c, 0x5a, 0x01, 0xd8, 0xea, 0x98, 0x19, 0x72, 0x17, 0xe0, 0x32, 0xca, 0x13, 0x1d, 0xac, 0xc7, 0x80, 0x49, 0x2b, 0xc7, 0x94, 0xe8, 0xb7, 0xb3, 0xae, 0x62, 0x82, 0xfd, 0x2f, 0xe4, 0x2a, 0x25, 0xf1, 0x96, 0xec, 0xb1, 0x2e, 0x7d, 0x9f, 0x31, 0x53, 0xbf, 0x32, 0x8f, 0x2a, 0xd5, 0xe0, 0xcb, 0xe9, 0xf3, 0xa4, 0x0e, 0x53, 0x48, 0xfb, 0x88, 0x6a, 0x23, 0x5d, 0x70, 0xa8, 0x18, 0x5f, 0x9f, 0xc4, 0xb4, 0xc7, 0x99, 0x47, 0xbc, 0xd3, 0x37, 0x2c, 0x38, 0xdf, 0xf9, 0x2d, 0x83, 0xfc, 0x41, 0xf7, 0x0f, 0x5b, 0xb3, 0xe9, 0x90, 0x58, 0xd5, 0xeb, 0xad, 0xc7, 0x69, 0xc9, 0xb5, 0x2f, 0x24, 0xa0, 0x2a, 0x98, 0x1c, 0x6a, 0xc9, 0x6f, 0x6a, 0x7a, 0xa3, 0x7a, 0x95, 0xc6, 0x7a, 0xc0, 0x23, 0xe6, 0xdf, 0xe2, 0xc2, 0x32, 0x7b, 0x67, 0xb3, 0xee, 0x1a, 0x04, 0xf0, 0x8d, 0x7f, 0x76, 0xac, 0x59, 0x1c, 0xca, 0x12, 0xeb, 0x59, 0xcf, 0xf6, 0x99, 0xba, 0xf0, 0xcc, 0x39, 0x87, 0x87, 0x91, 0xca, 0xcd, 0xa1, 0x52, 0x78, 0xfa, 0x50, 0x78, 0xac, 0xe0, 0xa6, 0x7a, 0x58, 0x53, 0x95, 0x84, 0x81, 0xa2, 0xef, 0x08, 0xe3, 0x4a, 0x2f, 0x36, 0x4a, 0x0d, 0x82, 0x1f, 0xba, 0xa0, 0x7e, 0x67, 0xdb, 0xb3, 0x29, 0x6a, 0x96, 0xf4, 0x98, 0xce, 0xe1, 0x68, 0xd4, 0xf9, 0x42, 0xb7, 0xea, 0xfb, 0x93, 0xb4, 0x46, 0x3b, 0x49, 0xbf, 0x91, 0xcc, 0xc9, 0x0c, 0xa9, 0xe1, 0xc8, 0x19, 0xae, 0xbe, 0x65, 0x84, 0xaf, 0x16, 0xb1, 0x6d, 0x7e, 0x32, 0x1b, 0xc0, 0x9d, 0x63, 0x0c, 0x84, 0x43, 0xb2, 0x67, 0x1e, 0xfb, 0x66, 0xe0, 0x57, 0xde, 0x12, 0x05, 0x0d, 0x14, 0x90, 0x87, 0x47, 0x72, 0xe9, 0x4f, 0xab, 0xa9, 0x9d, 0xc9, 0x48, 0x1c, 0x17, 0x16, 0x0b, 0x15, 0x75, 0x21, 0x6f, 0x87, 0xff, 0x2d, 0x80, 0x11, 0xd0, 0x04, 0xeb, 0x52, 0xa4, 0x96, 0xd8, 0x5a, 0xd7, 0x92, 0xe4, 0x2d, 0xa3, 0xd7, 0x0d, 0x45, 0xa2, 0x40, 0x9f, 0xfa, 0x41, 0x71, 0x57, 0x33, 0x32, 0xad, 0x1a, 0x51, 0x81, 0x0f, 0x17, 0xa1, 0xc6, 0xa9, 0xb5, 0x16, 0x5c, 0x9c, 0xfe, 0x1d, 0x39, 0x60, 0x13, 0x5f, 0x07, 0x54, 0x20, 0x7c, 0x77, 0x49, 0xcd, 0xc7, 0x17, 0x56, 0xce, 0xa6, 0xa3, 0xe5, 0xe1, 0xa0, 0xf7, 0xf1, 0x04, 0xfc, 0xab, 0x25, 0xea, 0x21, 0xf5, 0x87, 0x8e, 0x53, 0x5b, 0x1f, 0x9b, 0x71, 0x65, 0x77, 0xc2, 0x6b, 0xcd, 0x6a, 0x57, 0x5e, 0x48, 0xbb, 0x27, 0x73, 0xb3, 0xa7, 0x13, 0xcc, 0x1f, 0x15, 0x3e, 0x09, 0x2c, 0xdf, 0xdd, 0x96, 0x3e, 0x9b, 0xc1, 0xa8, 0xe2, 0x4e, 0xd0, 0x38, 0x7a, 0xf0, 0x03, 0x12, 0x82, 0xff, 0x08, 0x7c, 0xd8, 0x99, 0x12, 0x20, 0x6e, 0xa6, 0x35, 0xf4, 0xdc, 0x07, 0xb2, 0x3d, 0x04, 0x5c, 0x12, 0x5e, 0x64, 0x4a, 0x30, 0x1d, 0xe5, 0x05, 0x17, 0xae, 0x46, 0x83, 0xba, 0x44, 0xde, 0x8c, 0x23, 0x59, 0x12, 0x67, 0x77, 0xc0, 0x99, 0x80, 0x2b, 0xa8, 0x06, 0x83, 0x77, 0x82, 0x43, 0x5e, 0xf2, 0x37, 0xda, 0xc3, 0xe7, 0x83, 0x3b, 0xe4, 0xf0, 0xea, 0x3d, 0xff, 0x06, 0xbe, 0x2b, 0x40, 0x63, 0xad, 0x00, 0x23, 0x07, 0x1c, 0x17, 0x1d, 0x42, 0x08, 0x7c, 0x18, 0x99, 0xc6, 0x53, 0xc7, 0x39, 0xc8, 0xfc, 0x9d, 0x0a, 0xb2, 0x53, 0xfe, 0xc4, 0x80, 0x42, 0x33, 0xa5, 0xdb, 0x01, 0xbf, 0x24, 0x95, 0xe8, 0x2a, 0x7d, 0x32, 0x84, 0xfd, 0xab, 0x61, 0xc7, 0xe4, 0x07, 0x77, 0x1b, 0xc0, 0x64, 0x89, 0x7b, 0x17, 0x66, 0x47, 0x0e, 0xdf, 0x90, 0x11, 0x3a, 0x31, 0x42, 0x73, 0x71, 0xd3, 0x74, 0x56, 0xfd, 0xd4, 0x3c, 0x4c, 0xcb, 0xe2, 0x35, 0x3c, 0xa4, 0x6a, 0x86, 0x31, 0x01, 0xcf, 0x69, 0x18, 0x20, 0x01, 0xa3, 0x3b, 0x01, 0x45, 0x0f, 0x52, 0x79, 0x3f, 0xcc, 0x9f, 0xed, 0x56, 0xaa, 0xbb, 0x15, 0x13, 0xd5, 0x65, 0x3c, 0xff, 0x8c, 0x21, 0xd2, 0xf9, 0x92, 0x72, 0x71, 0x4b, 0xfb, 0x3d, 0x92, 0xc3, 0xf5, 0x2b }, .spki_len = 2614, }, }; #define ML_DSA_TV_NUM sizeof(ml_dsa_tv)/sizeof(struct ML_DSA_TEST_VECTOR) opencryptoki-opencryptoki-451d99c/testcases/crypto/ibm_ml_dsa_func.c000066400000000000000000000670401520105705100261160ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2025 * * 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 "mechtable.h" #include "ibm_ml_dsa.h" /** * Support for IBM ML-DSA keys and signatures * with oid = 2.16.840.1.101.3.4.3.xxx * * Only SignInit and Sign(Single) is supported with ML-DSA. * SignUpdate/SignFinal are not supported. Same with Verify. */ typedef struct signVerifyParam { CK_MECHANISM mech; CK_ULONG inputlen; } _signVerifyParam; CK_BYTE context[] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }; CK_IBM_SIGN_ADDITIONAL_CONTEXT no_ctx_preferred = { CKH_IBM_HEDGE_PREFERRED, NULL, 0 }; CK_IBM_SIGN_ADDITIONAL_CONTEXT no_ctx_required = { CKH_IBM_HEDGE_REQUIRED, NULL, 0 }; CK_IBM_SIGN_ADDITIONAL_CONTEXT no_ctx_deterministic = { CKH_IBM_DETERMINISTIC_REQUIRED, NULL, 0 }; CK_IBM_SIGN_ADDITIONAL_CONTEXT with_ctx_preferred = { CKH_IBM_HEDGE_PREFERRED, context, sizeof(context) }; const _signVerifyParam signVerifyInput[] = { {{CKM_IBM_ML_DSA, NULL, 0}, 0}, {{CKM_IBM_ML_DSA, NULL, 0}, 1}, {{CKM_IBM_ML_DSA, NULL, 0}, 32}, {{CKM_IBM_ML_DSA, NULL, 0}, 59}, {{CKM_IBM_ML_DSA, NULL, 0}, 3000}, /* Not all variants support larger sizes */ {{CKM_IBM_ML_DSA, &no_ctx_preferred, sizeof(no_ctx_preferred)}, 32}, {{CKM_IBM_ML_DSA, &no_ctx_required, sizeof(no_ctx_required)}, 32}, {{CKM_IBM_ML_DSA, &no_ctx_deterministic, sizeof(no_ctx_required)}, 32}, {{CKM_IBM_ML_DSA, &with_ctx_preferred, sizeof(with_ctx_preferred)}, 32}, }; typedef struct variant_info { const char *name; CK_IBM_ML_DSA_PARAMETER_SET_TYPE parameter_set; } _variant_info; const _variant_info variants[] = { { "ML_DSA_44", CKP_IBM_ML_DSA_44, }, { "ML_DSA_65", CKP_IBM_ML_DSA_65, }, { "ML_DSA_87", CKP_IBM_ML_DSA_87, }, }; const CK_ULONG num_variants = sizeof(variants) / sizeof(_variant_info); CK_RV run_SignVerifyMLDSA(CK_SESSION_HANDLE session, CK_MECHANISM *mech, CK_ULONG inputlen, CK_OBJECT_HANDLE priv_key, CK_OBJECT_HANDLE publ_key) { CK_BYTE_PTR data = NULL, signature = NULL; CK_ULONG i, signaturelen; CK_RV rc; /* Query the slot, check if this mech if supported */ if (!mech_supported(SLOT_ID, mech->mechanism)) { testcase_notice("Slot %u doesn't support %s", (unsigned int) SLOT_ID, p11_get_ckm(&mechtable_funcs, mech->mechanism)); rc = CKR_MECHANISM_PARAM_INVALID; goto testcase_cleanup; } data = calloc(inputlen > 0 ? inputlen : 1, sizeof(CK_BYTE)); 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) { if (rc == CKR_MECHANISM_PARAM_INVALID && mech->pParameter != NULL && ((CK_IBM_SIGN_ADDITIONAL_CONTEXT *)mech->pParameter)->hedgeVariant == CKH_IBM_DETERMINISTIC_REQUIRED) { testcase_skip("Sign with CKH_IBM_DETERMINISTIC_REQUIRED not supported"); rc = CKR_OK; goto testcase_cleanup; } if (rc == CKR_MECHANISM_PARAM_INVALID && mech->pParameter != NULL && ((CK_IBM_SIGN_ADDITIONAL_CONTEXT *)mech->pParameter)->ulContextLen > 0) { testcase_skip("Sign with Context not supported"); rc = CKR_OK; goto testcase_cleanup; } 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) { if (rc == CKR_MECHANISM_PARAM_INVALID && mech->pParameter != NULL && ((CK_IBM_SIGN_ADDITIONAL_CONTEXT *)mech->pParameter)->hedgeVariant == CKH_IBM_DETERMINISTIC_REQUIRED) { testcase_skip("Sign with hedge type CKH_IBM_DETERMINISTIC_REQUIRED is not supported"); rc = CKR_OK; goto testcase_cleanup; } if (rc == CKR_MECHANISM_PARAM_INVALID && mech->pParameter != NULL && ((CK_IBM_SIGN_ADDITIONAL_CONTEXT *)mech->pParameter)->ulContextLen > 0) { testcase_skip("Sign with non-empty context not supported"); rc = CKR_OK; goto testcase_cleanup; } testcase_error("C_Sign rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } signature = calloc(signaturelen, sizeof(CK_BYTE)); 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_GenerateMLDSAKeyPairSignVerify(void) { 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, i; CK_FLAGS flags; CK_RV rc; testcase_begin("Starting IBM ML-DSA generate key pair."); testcase_rw_session(); testcase_user_login(); mech.mechanism = CKM_IBM_ML_DSA_KEY_PAIR_GEN; mech.ulParameterLen = 0; mech.pParameter = NULL; /* query the slot, check if this mech is supported */ if (!mech_supported(SLOT_ID, mech.mechanism)) { testcase_skip("Slot %u doesn't support %s", (unsigned int) SLOT_ID, p11_get_ckm(&mechtable_funcs, mech.mechanism)); rc = CKR_OK; goto testcase_cleanup; } for (i = 0; i < num_variants; i++) { /* Setup attributes for public/private ML-DSA key */ CK_BBOOL attr_sign = TRUE; CK_BBOOL attr_verify = TRUE; CK_ATTRIBUTE ml_dsa_attr_private[] = { {CKA_SIGN, &attr_sign, sizeof(CK_BBOOL)}, {CKA_IBM_PARAMETER_SET, (CK_BYTE *)&variants[i].parameter_set, sizeof(CK_IBM_ML_DSA_PARAMETER_SET_TYPE)}, }; CK_ATTRIBUTE ml_dsa_attr_public[] = { {CKA_VERIFY, &attr_verify, sizeof(CK_BBOOL)}, {CKA_IBM_PARAMETER_SET, (CK_BYTE *)&variants[i].parameter_set, sizeof(CK_IBM_ML_DSA_PARAMETER_SET_TYPE)}, }; CK_ULONG num_ml_dsa_attrs = 2; /* Generate ML_DSA key pair */ rc = funcs->C_GenerateKeyPair(session, &mech, ml_dsa_attr_public, num_ml_dsa_attrs, ml_dsa_attr_private, num_ml_dsa_attrs, &publ_key, &priv_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("C_GenerateKeyPair with %s not supported", variants[i].name); goto next; } else { testcase_new_assertion(); testcase_fail("C_GenerateKeyPair with %s and valid input failed, rc=%s", variants[i].name, p11_get_ckr(rc)); goto testcase_cleanup; } } testcase_new_assertion(); testcase_pass("Generate ML-DSA key pair with %s passed.", variants[i].name); /* Sign/verify with this key pair */ for (j = 0; j < (sizeof(signVerifyInput) / sizeof(_signVerifyParam)); j++) { rc = run_SignVerifyMLDSA(session, (CK_MECHANISM *)&signVerifyInput[j].mech, signVerifyInput[j].inputlen, priv_key, publ_key); if (rc == CKR_MECHANISM_INVALID) { testcase_skip("run_SignVerifyMLDSA with %s index=%lu.", variants[i].name, j); } else if (rc != 0) { testcase_new_assertion(); testcase_fail("run_SignVerifyMLDSA with %s failed index=%lu.", variants[i].name, j); if (funcs3 != NULL) funcs3->C_SessionCancel(session, CKF_SIGN | CKF_VERIFY); continue; } else { testcase_new_assertion(); testcase_pass("*Sign & verify with %s j=%lu passed.", variants[i].name, j); } } next: if (publ_key != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, publ_key); publ_key = CK_INVALID_HANDLE; if (priv_key != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, priv_key); priv_key = CK_INVALID_HANDLE; } 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_ImportMLDSAKeyPairSignVerify(void) { 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 sign_mech = {CKM_IBM_ML_DSA, NULL, 0}; CK_RV rc; testcase_rw_session(); testcase_user_login(); /* query the slot, check if this mech is supported */ if (!mech_supported(SLOT_ID, CKM_IBM_ML_DSA)) { testcase_skip("Slot %u doesn't support CKM_IBM_ML_DSA", (unsigned int) SLOT_ID); rc = CKR_OK; goto testcase_cleanup; } for (i = 0; i < ML_DSA_TV_NUM; i++) { testcase_begin("Starting IBM ML-DSA import key pair, Sign/Verify, %s index=%lu", ml_dsa_tv[i].name, i); /* Create IBM ML-DSA private key */ rc = create_IBM_ML_DSA_PrivateKey(session, ml_dsa_tv[i].pkcs8, ml_dsa_tv[i].pkcs8_len, ml_dsa_tv[i].parameter_set, ml_dsa_tv[i].rho, ml_dsa_tv[i].rho_len, ml_dsa_tv[i].seed, ml_dsa_tv[i].seed_len, ml_dsa_tv[i].tr, ml_dsa_tv[i].tr_len, ml_dsa_tv[i].s1, ml_dsa_tv[i].s1_len, ml_dsa_tv[i].s2, ml_dsa_tv[i].s2_len, ml_dsa_tv[i].t0, ml_dsa_tv[i].t0_len, ml_dsa_tv[i].t1, ml_dsa_tv[i].t1_len, ml_dsa_tv[i].priv_seed, ml_dsa_tv[i].priv_seed_len, &priv_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("C_CreateObject with %s not supported", ml_dsa_tv[i].name); continue; } else if (rc == CKR_POLICY_VIOLATION) { testcase_skip("IBM ML-DSA key import is not allowed by policy"); continue; } testcase_new_assertion(); testcase_fail("C_CreateObject (IBM ML-DSA Private Key) failed at " "i=%lu, rc=%s", i, p11_get_ckr(rc)); goto testcase_cleanup; } testcase_new_assertion(); testcase_pass("*Import IBM ML-DSA private key (%s) index=%lu passed.", ml_dsa_tv[i].name, i); /* Create IBM ML-DSA public key */ rc = create_IBM_ML_DSA_PublicKey(session, ml_dsa_tv[i].spki, ml_dsa_tv[i].spki_len, ml_dsa_tv[i].parameter_set, ml_dsa_tv[i].rho, ml_dsa_tv[i].rho_len, ml_dsa_tv[i].t1, ml_dsa_tv[i].t1_len, &publ_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("C_CreateObject with %s not supported", ml_dsa_tv[i].name); goto testcase_cleanup; } else if (rc == CKR_POLICY_VIOLATION) { testcase_skip("IBM ML-DSA key import is not allowed by policy"); goto testcase_cleanup; } testcase_new_assertion(); testcase_fail("C_CreateObject (IBM ML-DSA Public Key) failed at " "i=%lu, rc=%s", i, p11_get_ckr(rc)); goto testcase_cleanup; } testcase_new_assertion(); testcase_pass("*Import IBM ML-DSA public key (%s) index=%lu passed.", ml_dsa_tv[i].name, i); /* Test sign/verify */ rc = run_SignVerifyMLDSA(session, &sign_mech, 32, priv_key, publ_key); if (rc == CKR_MECHANISM_INVALID) { testcase_skip("run_SignVerifyMLDSA index=%lu.", i); } else if (rc != 0) { testcase_new_assertion(); testcase_fail("run_SignVerifyMLDSA failed index=%lu.", i); goto testcase_cleanup; } else { testcase_new_assertion(); testcase_pass("*Sign & verify, 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(tmp_len, sizeof(CK_BYTE)); 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_ML_DSA; CK_OBJECT_HANDLE tmp_key = CK_INVALID_HANDLE; CK_BYTE unwrap_label[] = "unwrapped_private_IBM_ML_DSA_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_TransferMLDSAKeyPairSignVerify(void) { 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_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; CK_MECHANISM sign_mech = {CKM_IBM_ML_DSA, NULL, 0}; testcase_rw_session(); testcase_user_login(); /* query the slot, check if this mech is supported */ if (!mech_supported(SLOT_ID, CKM_IBM_ML_DSA)) { testcase_skip("Slot %u doesn't support CKM_IBM_ML_DSA", (unsigned int) SLOT_ID); rc = CKR_OK; goto testcase_cleanup; } if (!mech_supported(SLOT_ID, CKM_AES_KEY_GEN)) { testcase_skip("Slot %u doesn't support CKM_AES_KEY_GEN", (unsigned int) SLOT_ID); rc = CKR_OK; goto testcase_cleanup; } if (!mech_supported_flags(SLOT_ID, CKM_AES_CBC_PAD, CKF_WRAP)) { testcase_skip("Slot %u doesn't support key wrapping with CKM_AES_CBC_PAD", (unsigned int) SLOT_ID); rc = CKR_OK; goto testcase_cleanup; } for (i = 0; i < ML_DSA_TV_NUM; i++) { testcase_begin("Starting IBM ML-DSA transfer key pair, Sign/Verify %s index=%lu.", ml_dsa_tv[i].name, i); /* Create IBM ML-DSA private key */ rc = create_IBM_ML_DSA_PrivateKey(session, ml_dsa_tv[i].pkcs8, ml_dsa_tv[i].pkcs8_len, ml_dsa_tv[i].parameter_set, ml_dsa_tv[i].rho, ml_dsa_tv[i].rho_len, ml_dsa_tv[i].seed, ml_dsa_tv[i].seed_len, ml_dsa_tv[i].tr, ml_dsa_tv[i].tr_len, ml_dsa_tv[i].s1, ml_dsa_tv[i].s1_len, ml_dsa_tv[i].s2, ml_dsa_tv[i].s2_len, ml_dsa_tv[i].t0, ml_dsa_tv[i].t0_len, ml_dsa_tv[i].t1, ml_dsa_tv[i].t1_len, ml_dsa_tv[i].priv_seed, ml_dsa_tv[i].priv_seed_len, &priv_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("C_CreateObject with %s not supported", ml_dsa_tv[i].name); continue; } else if (rc == CKR_POLICY_VIOLATION) { testcase_skip("IBM ML-DSA key import is not allowed by policy"); continue; } testcase_new_assertion(); testcase_fail("C_CreateObject (IBM ML-DSA Private Key) failed at " "i=%lu, rc=%s", i, p11_get_ckr(rc)); goto testcase_cleanup; } testcase_new_assertion(); testcase_pass("*Import IBM ML-DSA private key (%s) index=%lu passed.", ml_dsa_tv[i].name, i); /* Create IBM ML-DSA public key */ rc = create_IBM_ML_DSA_PublicKey(session, ml_dsa_tv[i].spki, ml_dsa_tv[i].spki_len, ml_dsa_tv[i].parameter_set, ml_dsa_tv[i].rho, ml_dsa_tv[i].rho_len, ml_dsa_tv[i].t1, ml_dsa_tv[i].t1_len, &publ_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("C_CreateObject with %s not supported", ml_dsa_tv[i].name); goto testcase_cleanup; } else if (rc == CKR_POLICY_VIOLATION) { testcase_skip("IBM ML-DSA key import is not allowed by policy"); goto testcase_cleanup; } testcase_new_assertion(); testcase_fail("C_CreateObject (IBM ML-DSA Public Key) failed at " "i=%lu,rc=%s", i, p11_get_ckr(rc)); goto testcase_cleanup; } testcase_new_assertion(); testcase_pass("*Import IBM ML-DSA public key (%s) index=%lu passed.", ml_dsa_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, CK_TRUE, &wkey_mech, &secret_key); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("AES key generation is not allowed by policy"); goto testcase_cleanup; } 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 IBM ML-DSA 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 IBM ML-DSA private key (%s) index=%lu passed.", ml_dsa_tv[i].name, i); /* Unwrap IBM ML-DSA 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 IBM ML-DSA private key (%s) index=%lu passed.", ml_dsa_tv[i].name, i); free(wrapped_key); wrapped_key = NULL; /* Test sign/verify using unwrapped private key and untouched public key */ rc = run_SignVerifyMLDSA(session, &sign_mech, 32, unwrapped_key, publ_key); if (rc == CKR_MECHANISM_INVALID) { testcase_skip("run_SignVerifyMLDSA index=%lu.", i); } else if (rc != 0) { testcase_new_assertion(); testcase_fail("run_SignVerifyMLDSA failed index=%lu.", i); goto testcase_cleanup; } else { testcase_new_assertion(); testcase_pass("*Sign & verify, 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(); rv = run_GenerateMLDSAKeyPairSignVerify(); rv |= run_ImportMLDSAKeyPairSignVerify(); rv |= run_TransferMLDSAKeyPairSignVerify(); testcase_print_result(); funcs->C_Finalize(NULL); return testcase_return(rv); } opencryptoki-opencryptoki-451d99c/testcases/crypto/ibm_ml_kem.h000066400000000000000000004705471520105705100251270ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2025 * * 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 */ struct ML_KEM_TEST_VECTOR { char *name; CK_ULONG parameter_set; CK_ULONG sk_len; CK_BYTE sk[4096]; CK_ULONG pk_len; CK_BYTE pk[4096]; CK_ULONG priv_seed_len; CK_BYTE priv_seed[64]; CK_BYTE pkcs8[8192]; CK_ULONG pkcs8_len; CK_BYTE spki[8192]; CK_ULONG spki_len; }; struct ML_KEM_TEST_VECTOR ml_kem_tv[] = { { .name = "ML-KEM 512 (PKCS#8/SPKI - both)", .pkcs8 = { 0x30, 0x82, 0x06, 0xbe, 0x02, 0x01, 0x00, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x04, 0x01, 0x04, 0x82, 0x06, 0xaa, 0x30, 0x82, 0x06, 0xa6, 0x04, 0x40, 0x6c, 0xc8, 0x9e, 0x4c, 0xe5, 0x48, 0x9c, 0x76, 0x20, 0xd8, 0xbf, 0x00, 0x14, 0x0f, 0xc4, 0x24, 0x71, 0xa5, 0x80, 0x34, 0xfd, 0x9a, 0xc9, 0x53, 0xbd, 0x45, 0xe4, 0x4b, 0xfd, 0x79, 0xdf, 0x81, 0x28, 0x59, 0xd4, 0x98, 0xda, 0x66, 0xf3, 0x70, 0xa2, 0xd6, 0xa8, 0x5e, 0xaf, 0x45, 0x6d, 0xe0, 0xf4, 0x3d, 0x39, 0x08, 0x1d, 0xc7, 0xe3, 0xb1, 0x7b, 0x31, 0x0f, 0xfb, 0xa4, 0x34, 0x54, 0xd9, 0x04, 0x82, 0x06, 0x60, 0x50, 0x2c, 0x8c, 0xf8, 0x93, 0xbc, 0xeb, 0xa5, 0xb1, 0x8a, 0x43, 0xbc, 0x52, 0xa9, 0x52, 0x9f, 0x99, 0x6b, 0x86, 0x41, 0xb8, 0x66, 0x36, 0x12, 0x56, 0x69, 0x8b, 0xfe, 0xca, 0x75, 0xdb, 0x43, 0x4d, 0xf3, 0x4b, 0x88, 0x64, 0x71, 0xa7, 0x8b, 0xd8, 0x8f, 0x07, 0xc7, 0xaa, 0x8d, 0xf4, 0x9d, 0x78, 0xf4, 0x62, 0xe1, 0x78, 0x71, 0x8f, 0xca, 0xbd, 0xa3, 0x5a, 0x71, 0xcb, 0x95, 0xab, 0xf9, 0xd6, 0x8a, 0xa6, 0x76, 0x40, 0xba, 0x0a, 0x6e, 0xaf, 0xec, 0x4f, 0x67, 0xe5, 0x1d, 0x0a, 0xbc, 0x13, 0x9b, 0x35, 0x2b, 0x14, 0x24, 0x84, 0x67, 0xbc, 0x05, 0xfd, 0xe2, 0x0f, 0xb4, 0x5b, 0x03, 0x8c, 0xb0, 0x10, 0xd4, 0x69, 0x9f, 0x41, 0xc9, 0x6c, 0x4c, 0x51, 0x16, 0x22, 0x63, 0x5a, 0x5a, 0x8c, 0xb1, 0x89, 0x48, 0xc7, 0xc5, 0x31, 0x1f, 0x13, 0xac, 0xcf, 0x53, 0x0a, 0x09, 0xd6, 0x68, 0x7f, 0xc8, 0x87, 0x4c, 0x0e, 0xa4, 0xc1, 0x22, 0x63, 0x0f, 0xa2, 0xc9, 0x5a, 0xa8, 0x41, 0x87, 0xfd, 0x91, 0xae, 0xc4, 0x3a, 0xcb, 0xde, 0x66, 0xc8, 0xba, 0x50, 0x0c, 0x9e, 0xd4, 0x58, 0x59, 0x01, 0x5a, 0x6b, 0xa8, 0x93, 0xff, 0x27, 0xb6, 0x88, 0x84, 0xb7, 0xf8, 0x96, 0x59, 0x04, 0xb3, 0x65, 0xbe, 0x79, 0xb9, 0x94, 0x2c, 0xb1, 0xbd, 0x80, 0x47, 0x70, 0x49, 0x91, 0xde, 0xbc, 0xc2, 0x0d, 0xd5, 0x94, 0x81, 0x30, 0x9d, 0xd7, 0x36, 0x4e, 0xbc, 0xe1, 0x2b, 0x8d, 0x07, 0x9c, 0x56, 0x5a, 0x7e, 0x1b, 0x45, 0x1f, 0x07, 0xf5, 0x46, 0xa6, 0x87, 0x79, 0x6e, 0x5b, 0xb8, 0xf5, 0xc6, 0x32, 0x2b, 0x74, 0x06, 0xc3, 0x8a, 0x2f, 0xe4, 0xfb, 0x25, 0x80, 0xe7, 0xb0, 0x71, 0x59, 0xa4, 0x63, 0xa6, 0x84, 0x50, 0xb2, 0x80, 0xcd, 0xe9, 0xbd, 0x2e, 0x10, 0x69, 0x35, 0xeb, 0x22, 0x83, 0x58, 0x27, 0x75, 0x7b, 0xc5, 0xc4, 0x43, 0x68, 0xe2, 0x0a, 0xa3, 0x5e, 0x31, 0x90, 0xd8, 0xd8, 0x27, 0x54, 0x41, 0x83, 0xed, 0xe0, 0x3f, 0x44, 0x72, 0x25, 0x11, 0x16, 0x7a, 0x05, 0x96, 0x85, 0xc3, 0x0a, 0x84, 0x6d, 0xa9, 0x8c, 0xbc, 0xd9, 0x2c, 0x51, 0x2a, 0xa2, 0x69, 0xc0, 0xca, 0xd0, 0x3c, 0xa6, 0xb3, 0xb9, 0x1a, 0x8e, 0x81, 0x6b, 0x89, 0xcb, 0xce, 0x7f, 0x94, 0xa9, 0x06, 0x8b, 0x6a, 0x6f, 0x10, 0x8c, 0x27, 0x85, 0xa3, 0xe1, 0x86, 0x81, 0x79, 0x52, 0x1c, 0xd4, 0x29, 0x87, 0x6c, 0xd8, 0x8d, 0xa8, 0x58, 0x80, 0x52, 0xd0, 0xcb, 0x50, 0xf1, 0xc7, 0x3a, 0xc9, 0x09, 0xa3, 0x74, 0x92, 0xd1, 0x41, 0x24, 0x05, 0x75, 0x04, 0xd2, 0xf3, 0x59, 0x51, 0xb6, 0x15, 0x0f, 0x8b, 0x84, 0xe9, 0xc7, 0x29, 0xfb, 0xa2, 0x05, 0xbd, 0x42, 0x16, 0x59, 0x25, 0x80, 0xbb, 0xe9, 0xa7, 0x54, 0xf1, 0x90, 0xd2, 0xe2, 0xc9, 0x6d, 0x6c, 0x31, 0x6d, 0xa8, 0x97, 0xc2, 0x11, 0x09, 0x80, 0xcc, 0x0a, 0x05, 0xf7, 0x80, 0xf2, 0xa5, 0x2d, 0x48, 0x68, 0x1a, 0x73, 0xf8, 0x6e, 0x06, 0xc0, 0xa7, 0xf0, 0xc8, 0x33, 0x84, 0x32, 0xb4, 0x15, 0xc6, 0x0f, 0x00, 0x12, 0x65, 0xb4, 0x03, 0x14, 0xd5, 0x0a, 0x3b, 0x44, 0xb4, 0x4e, 0x3e, 0xc6, 0x64, 0x43, 0xb4, 0x63, 0x1d, 0x87, 0xc9, 0x8f, 0x4c, 0x4e, 0xd4, 0x93, 0x65, 0xd6, 0x15, 0x21, 0x85, 0xc2, 0x11, 0x0c, 0x29, 0x15, 0x74, 0x61, 0x9e, 0xa3, 0x11, 0x78, 0x98, 0x83, 0x18, 0x7b, 0x4b, 0x9e, 0x64, 0x94, 0x2f, 0xb9, 0xc5, 0x8f, 0x13, 0x40, 0xa0, 0x5e, 0x0c, 0x7d, 0xd0, 0x44, 0x54, 0xb5, 0xd5, 0x47, 0x80, 0x84, 0x8d, 0x9d, 0x50, 0x62, 0x8b, 0xf4, 0xb2, 0x72, 0x70, 0x7e, 0x98, 0x19, 0x13, 0x5f, 0x52, 0x84, 0x55, 0x35, 0x23, 0x8e, 0xd2, 0x23, 0xc1, 0x56, 0x36, 0x32, 0x45, 0xab, 0x77, 0xc4, 0x49, 0x09, 0x2c, 0x18, 0xda, 0x06, 0x0c, 0x13, 0xc8, 0x96, 0x44, 0x1a, 0xc8, 0x99, 0x96, 0x0e, 0x50, 0xe7, 0xc3, 0x6e, 0x61, 0x38, 0x48, 0x67, 0x55, 0x5f, 0xa7, 0x4d, 0xcc, 0x45, 0x35, 0x5c, 0x8a, 0xc0, 0xa2, 0xc7, 0xcd, 0xbb, 0x7c, 0x6d, 0xde, 0x41, 0xc1, 0xcc, 0x58, 0xcd, 0x05, 0x13, 0xa9, 0x3f, 0xa0, 0x4e, 0x05, 0xe0, 0xbe, 0xaa, 0xd4, 0x43, 0x52, 0x78, 0x7f, 0xd2, 0xf8, 0x89, 0x4b, 0x63, 0x27, 0xd8, 0x8c, 0x2b, 0xc1, 0x08, 0x5a, 0xaf, 0x5c, 0x7b, 0xea, 0x00, 0xb4, 0x1b, 0x72, 0x81, 0x44, 0x43, 0x29, 0x85, 0xd5, 0xa3, 0x17, 0x62, 0x61, 0x06, 0x3c, 0x08, 0x23, 0xd9, 0x61, 0x78, 0xab, 0x2f, 0x86, 0x08, 0x8f, 0xc3, 0x55, 0x84, 0xd8, 0xa8, 0x64, 0xc4, 0x50, 0x5f, 0x8b, 0x23, 0x2d, 0x4d, 0xc2, 0x9b, 0x7d, 0xf7, 0x56, 0xdd, 0x8b, 0x46, 0xda, 0xf4, 0x77, 0xd3, 0xe4, 0x01, 0x00, 0x2d, 0x27, 0x00, 0x62, 0x27, 0x85, 0x60, 0x28, 0xd6, 0x06, 0x96, 0xe3, 0x90, 0x29, 0x30, 0xd2, 0x17, 0x08, 0xda, 0x05, 0x07, 0x52, 0x07, 0xda, 0x52, 0x9c, 0xcf, 0x93, 0x85, 0x61, 0x19, 0x80, 0xaa, 0x29, 0xba, 0x59, 0xd5, 0xc9, 0x57, 0x79, 0x4d, 0xd4, 0x90, 0x17, 0x42, 0x97, 0x57, 0x6e, 0x96, 0x7a, 0xa2, 0xb8, 0xbc, 0x3c, 0xfc, 0x1f, 0x30, 0xb8, 0xa5, 0xd4, 0x39, 0x64, 0x29, 0xf9, 0x0c, 0x23, 0x74, 0x12, 0x23, 0xf3, 0x86, 0xdf, 0xf9, 0x4f, 0x13, 0x94, 0x77, 0x2e, 0xf3, 0x0a, 0xb2, 0x70, 0x8c, 0x13, 0xa0, 0x11, 0x6a, 0x30, 0x3c, 0x5c, 0x32, 0xa2, 0xb4, 0xc6, 0x2c, 0x91, 0x15, 0xa8, 0xb0, 0xd5, 0x5c, 0xb7, 0xd0, 0x11, 0x57, 0xc9, 0xc9, 0xc9, 0x39, 0x6a, 0x5f, 0x39, 0xc7, 0x0a, 0xb5, 0x96, 0xaf, 0x74, 0x36, 0x90, 0x1b, 0x31, 0x1d, 0x61, 0xc7, 0xb3, 0x14, 0x39, 0x55, 0xd7, 0x9b, 0xb2, 0x17, 0x52, 0xa1, 0x83, 0x2e, 0xcf, 0x35, 0x30, 0x86, 0x06, 0x49, 0x3e, 0x05, 0xc6, 0x75, 0x53, 0x54, 0xe4, 0x40, 0xc1, 0x21, 0xca, 0x05, 0x0d, 0x03, 0xce, 0x2c, 0x76, 0xcc, 0xa7, 0x7c, 0x8d, 0x0c, 0xac, 0xa0, 0x0a, 0x21, 0x03, 0x61, 0x2b, 0x90, 0x16, 0xd7, 0x90, 0x43, 0x80, 0xa6, 0x94, 0xc1, 0x42, 0x45, 0x38, 0xaf, 0x1c, 0xbb, 0x5b, 0x21, 0xbc, 0xc4, 0xae, 0xea, 0x58, 0xd8, 0x49, 0xa5, 0xf2, 0x07, 0x3d, 0x12, 0xa2, 0x82, 0x18, 0x49, 0xbf, 0xc4, 0x8c, 0x52, 0xe6, 0xb3, 0x45, 0x74, 0x65, 0x1c, 0xe1, 0x78, 0x72, 0x26, 0xd7, 0x0f, 0x11, 0x08, 0x0a, 0xd1, 0x34, 0xcf, 0x20, 0x00, 0x95, 0x94, 0x00, 0x86, 0x6b, 0xa0, 0x2c, 0xdc, 0xca, 0xae, 0x3e, 0xb2, 0x91, 0x23, 0x06, 0x99, 0xcc, 0xa3, 0xb6, 0x0b, 0xb6, 0xc4, 0xfc, 0x57, 0x09, 0xd8, 0x08, 0x8c, 0x0a, 0xc4, 0x62, 0x39, 0xb1, 0x32, 0x41, 0xf6, 0x94, 0xb0, 0x41, 0x2d, 0x2c, 0x92, 0xcc, 0x2b, 0xb1, 0xbc, 0xec, 0x5c, 0x6a, 0x32, 0x39, 0x98, 0xc6, 0xa4, 0x8a, 0x34, 0x0a, 0x89, 0xdf, 0x29, 0x79, 0xc5, 0x45, 0x81, 0xeb, 0x74, 0x44, 0x86, 0x00, 0x37, 0x9a, 0x36, 0x56, 0xbc, 0x9a, 0x8d, 0x7e, 0x39, 0x77, 0x02, 0xc4, 0x12, 0xf9, 0xc8, 0x03, 0x2b, 0xaa, 0x6e, 0x14, 0xbc, 0x8a, 0x34, 0xd5, 0x34, 0x59, 0x20, 0x7d, 0x15, 0x81, 0x4d, 0x8c, 0x0c, 0x71, 0x1c, 0xe0, 0xab, 0x3c, 0xd8, 0xcb, 0x38, 0xf0, 0x39, 0xbc, 0x38, 0x78, 0xde, 0x88, 0x8b, 0x73, 0xd7, 0x11, 0x8d, 0xe7, 0x82, 0x53, 0x26, 0x53, 0xe0, 0x29, 0xb5, 0xe8, 0x56, 0x77, 0xf3, 0xa8, 0x08, 0x9a, 0xab, 0xa9, 0xc0, 0xc8, 0x85, 0xd2, 0xc7, 0xcd, 0x57, 0x49, 0x86, 0xdb, 0x2c, 0xb9, 0xda, 0x78, 0x26, 0x32, 0xac, 0x79, 0x8e, 0x93, 0x5a, 0x50, 0x92, 0xc6, 0x95, 0xc1, 0x46, 0x02, 0x48, 0x59, 0x0b, 0xfb, 0x64, 0x40, 0x85, 0x65, 0xf3, 0x33, 0xb0, 0x3e, 0x4c, 0x3c, 0xae, 0x13, 0x92, 0x4d, 0x0a, 0x6c, 0x6a, 0x92, 0xb9, 0x5f, 0x47, 0x0d, 0xe6, 0xac, 0x52, 0xc0, 0x05, 0x8d, 0xe0, 0xe9, 0x82, 0x4d, 0x66, 0x83, 0xdf, 0xd0, 0x1d, 0x70, 0x39, 0x5a, 0x15, 0xe8, 0x24, 0xf2, 0xfa, 0xaf, 0xee, 0xc5, 0xac, 0x48, 0xe0, 0x99, 0x19, 0x46, 0x70, 0x7b, 0x34, 0xb1, 0xbd, 0x1c, 0x20, 0x77, 0x97, 0x0c, 0x20, 0x10, 0x24, 0xc8, 0x32, 0x67, 0xbd, 0x73, 0x24, 0x11, 0xc0, 0x95, 0xad, 0xa6, 0x2e, 0x0e, 0xdc, 0xc2, 0x9c, 0x4b, 0x60, 0xc3, 0x62, 0x7c, 0x95, 0x76, 0x73, 0xc8, 0xda, 0x74, 0x33, 0x42, 0x10, 0xe0, 0x4c, 0x72, 0x2b, 0x98, 0x74, 0x02, 0x88, 0x63, 0x26, 0x37, 0x42, 0x2b, 0x06, 0x5b, 0x34, 0xa0, 0x99, 0x93, 0xba, 0x54, 0x0f, 0x6b, 0x1f, 0x29, 0x91, 0x50, 0x13, 0x62, 0x5b, 0x3a, 0x5b, 0x6d, 0x9b, 0x83, 0x97, 0x01, 0x11, 0xc4, 0x9e, 0xe2, 0x01, 0xd5, 0x75, 0x85, 0x0a, 0x95, 0x50, 0x63, 0xf4, 0x48, 0x02, 0x9a, 0x96, 0xda, 0x25, 0xb3, 0x9a, 0x33, 0x29, 0xef, 0x30, 0xa6, 0x95, 0xb0, 0xb2, 0x50, 0x03, 0x47, 0x75, 0xe5, 0x97, 0xb3, 0xc1, 0x52, 0x2c, 0xb5, 0x47, 0x15, 0x77, 0xb4, 0x36, 0x67, 0xc9, 0x02, 0xf9, 0xa2, 0x81, 0x70, 0x42, 0xbd, 0x76, 0x2c, 0x8f, 0x8a, 0x31, 0x98, 0x77, 0x99, 0x3f, 0x20, 0x1d, 0xf1, 0xd1, 0x0a, 0x0a, 0x11, 0x07, 0xaf, 0x52, 0xaa, 0x84, 0xcb, 0x8d, 0x6f, 0xf9, 0xa9, 0x54, 0x7a, 0x68, 0xb3, 0x41, 0x40, 0xd0, 0x46, 0x76, 0x83, 0x19, 0x7c, 0x3a, 0x04, 0x07, 0xad, 0xe6, 0x74, 0x36, 0x26, 0x40, 0x68, 0x29, 0x47, 0x12, 0x22, 0x21, 0x26, 0x5b, 0xbe, 0x3a, 0x53, 0x99, 0x2b, 0xb0, 0x61, 0xf2, 0x27, 0x69, 0xd8, 0xe6, 0xb5, 0x63, 0x58, 0x93, 0xd4, 0x77, 0x0b, 0xeb, 0xc2, 0x84, 0x02, 0x93, 0x76, 0x77, 0xc6, 0xbd, 0xf1, 0x58, 0x9e, 0xb8, 0x72, 0x2a, 0x18, 0x4b, 0x01, 0x14, 0xd7, 0x3e, 0xc9, 0xe4, 0x85, 0xa0, 0x48, 0xc9, 0x7c, 0xc0, 0x25, 0x7c, 0x95, 0x0f, 0xa0, 0xdc, 0x59, 0x54, 0xa5, 0xbc, 0x61, 0xb5, 0x72, 0x22, 0x32, 0x6d, 0x9f, 0x2b, 0x00, 0x33, 0x25, 0x7d, 0x1e, 0xba, 0x27, 0xaa, 0x57, 0x41, 0x94, 0x21, 0x90, 0x0b, 0xb5, 0x1a, 0xd0, 0xe4, 0x14, 0x97, 0x89, 0x97, 0xfc, 0xfb, 0xba, 0x16, 0xb5, 0x96, 0xa8, 0x98, 0xb2, 0x1a, 0x3b, 0x96, 0x22, 0x57, 0xa8, 0x29, 0xd8, 0x48, 0x6b, 0xeb, 0x9c, 0x00, 0x30, 0x79, 0x1f, 0x06, 0x81, 0xde, 0x54, 0x26, 0xb4, 0xdc, 0x2e, 0x8b, 0x66, 0x7f, 0x47, 0x32, 0x9a, 0x6c, 0x73, 0x76, 0x80, 0xd8, 0xb9, 0xaa, 0xe4, 0xcd, 0xaf, 0xbc, 0x04, 0x6e, 0x05, 0xab, 0x55, 0x25, 0x42, 0x83, 0xf6, 0xca, 0x5c, 0xbb, 0xae, 0xa3, 0x15, 0xb4, 0x91, 0xb1, 0x28, 0x33, 0xfc, 0xcb, 0x94, 0x92, 0xaa, 0x95, 0x6b, 0x07, 0x1a, 0x71, 0x82, 0x29, 0xa3, 0x74, 0xff, 0x08, 0xa5, 0xe1, 0x87, 0x9b, 0x18, 0xa7, 0x38, 0x80, 0x9a, 0x7f, 0x43, 0xa4, 0xce, 0x13, 0x13, 0xb0, 0x6b, 0xd0, 0x55, 0x87, 0xb7, 0x6c, 0xee, 0xf1, 0xc6, 0x16, 0x30, 0x70, 0xfd, 0x98, 0x78, 0xb6, 0x23, 0x18, 0xb3, 0xc8, 0x9f, 0xc7, 0x17, 0x28, 0x9c, 0x45, 0x42, 0xb1, 0xb6, 0xcb, 0x96, 0x0c, 0xaf, 0x61, 0x42, 0x71, 0x6c, 0xd7, 0x6e, 0x8d, 0x39, 0xad, 0xb6, 0x7a, 0x42, 0x93, 0x91, 0x0a, 0x09, 0x91, 0x09, 0xfd, 0xfa, 0xc0, 0x11, 0xa9, 0xb9, 0x86, 0xc5, 0x09, 0x09, 0x16, 0xce, 0xd0, 0xc3, 0xb4, 0x8a, 0xc9, 0xb1, 0x2c, 0x7c, 0x5a, 0xfb, 0xa1, 0x6b, 0x5e, 0x80, 0x38, 0x51, 0x87, 0x34, 0x6b, 0x2a, 0x12, 0x90, 0x4b, 0x73, 0x8f, 0x76, 0x79, 0x91, 0x7d, 0x56, 0x7c, 0x6c, 0xa9, 0x44, 0x7f, 0xa5, 0x5d, 0xa8, 0x71, 0xc7, 0xa3, 0x30, 0x14, 0x3f, 0xa1, 0xf2, 0xdd, 0x43, 0x45, 0x28, 0x59, 0xd4, 0x98, 0xda, 0x66, 0xf3, 0x70, 0xa2, 0xd6, 0xa8, 0x5e, 0xaf, 0x45, 0x6d, 0xe0, 0xf4, 0x3d, 0x39, 0x08, 0x1d, 0xc7, 0xe3, 0xb1, 0x7b, 0x31, 0x0f, 0xfb, 0xa4, 0x34, 0x54, 0xd9 }, .pkcs8_len = 1730, .spki = { 0x30, 0x82, 0x03, 0x32, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x04, 0x01, 0x03, 0x82, 0x03, 0x21, 0x00, 0x0a, 0xb5, 0x96, 0xaf, 0x74, 0x36, 0x90, 0x1b, 0x31, 0x1d, 0x61, 0xc7, 0xb3, 0x14, 0x39, 0x55, 0xd7, 0x9b, 0xb2, 0x17, 0x52, 0xa1, 0x83, 0x2e, 0xcf, 0x35, 0x30, 0x86, 0x06, 0x49, 0x3e, 0x05, 0xc6, 0x75, 0x53, 0x54, 0xe4, 0x40, 0xc1, 0x21, 0xca, 0x05, 0x0d, 0x03, 0xce, 0x2c, 0x76, 0xcc, 0xa7, 0x7c, 0x8d, 0x0c, 0xac, 0xa0, 0x0a, 0x21, 0x03, 0x61, 0x2b, 0x90, 0x16, 0xd7, 0x90, 0x43, 0x80, 0xa6, 0x94, 0xc1, 0x42, 0x45, 0x38, 0xaf, 0x1c, 0xbb, 0x5b, 0x21, 0xbc, 0xc4, 0xae, 0xea, 0x58, 0xd8, 0x49, 0xa5, 0xf2, 0x07, 0x3d, 0x12, 0xa2, 0x82, 0x18, 0x49, 0xbf, 0xc4, 0x8c, 0x52, 0xe6, 0xb3, 0x45, 0x74, 0x65, 0x1c, 0xe1, 0x78, 0x72, 0x26, 0xd7, 0x0f, 0x11, 0x08, 0x0a, 0xd1, 0x34, 0xcf, 0x20, 0x00, 0x95, 0x94, 0x00, 0x86, 0x6b, 0xa0, 0x2c, 0xdc, 0xca, 0xae, 0x3e, 0xb2, 0x91, 0x23, 0x06, 0x99, 0xcc, 0xa3, 0xb6, 0x0b, 0xb6, 0xc4, 0xfc, 0x57, 0x09, 0xd8, 0x08, 0x8c, 0x0a, 0xc4, 0x62, 0x39, 0xb1, 0x32, 0x41, 0xf6, 0x94, 0xb0, 0x41, 0x2d, 0x2c, 0x92, 0xcc, 0x2b, 0xb1, 0xbc, 0xec, 0x5c, 0x6a, 0x32, 0x39, 0x98, 0xc6, 0xa4, 0x8a, 0x34, 0x0a, 0x89, 0xdf, 0x29, 0x79, 0xc5, 0x45, 0x81, 0xeb, 0x74, 0x44, 0x86, 0x00, 0x37, 0x9a, 0x36, 0x56, 0xbc, 0x9a, 0x8d, 0x7e, 0x39, 0x77, 0x02, 0xc4, 0x12, 0xf9, 0xc8, 0x03, 0x2b, 0xaa, 0x6e, 0x14, 0xbc, 0x8a, 0x34, 0xd5, 0x34, 0x59, 0x20, 0x7d, 0x15, 0x81, 0x4d, 0x8c, 0x0c, 0x71, 0x1c, 0xe0, 0xab, 0x3c, 0xd8, 0xcb, 0x38, 0xf0, 0x39, 0xbc, 0x38, 0x78, 0xde, 0x88, 0x8b, 0x73, 0xd7, 0x11, 0x8d, 0xe7, 0x82, 0x53, 0x26, 0x53, 0xe0, 0x29, 0xb5, 0xe8, 0x56, 0x77, 0xf3, 0xa8, 0x08, 0x9a, 0xab, 0xa9, 0xc0, 0xc8, 0x85, 0xd2, 0xc7, 0xcd, 0x57, 0x49, 0x86, 0xdb, 0x2c, 0xb9, 0xda, 0x78, 0x26, 0x32, 0xac, 0x79, 0x8e, 0x93, 0x5a, 0x50, 0x92, 0xc6, 0x95, 0xc1, 0x46, 0x02, 0x48, 0x59, 0x0b, 0xfb, 0x64, 0x40, 0x85, 0x65, 0xf3, 0x33, 0xb0, 0x3e, 0x4c, 0x3c, 0xae, 0x13, 0x92, 0x4d, 0x0a, 0x6c, 0x6a, 0x92, 0xb9, 0x5f, 0x47, 0x0d, 0xe6, 0xac, 0x52, 0xc0, 0x05, 0x8d, 0xe0, 0xe9, 0x82, 0x4d, 0x66, 0x83, 0xdf, 0xd0, 0x1d, 0x70, 0x39, 0x5a, 0x15, 0xe8, 0x24, 0xf2, 0xfa, 0xaf, 0xee, 0xc5, 0xac, 0x48, 0xe0, 0x99, 0x19, 0x46, 0x70, 0x7b, 0x34, 0xb1, 0xbd, 0x1c, 0x20, 0x77, 0x97, 0x0c, 0x20, 0x10, 0x24, 0xc8, 0x32, 0x67, 0xbd, 0x73, 0x24, 0x11, 0xc0, 0x95, 0xad, 0xa6, 0x2e, 0x0e, 0xdc, 0xc2, 0x9c, 0x4b, 0x60, 0xc3, 0x62, 0x7c, 0x95, 0x76, 0x73, 0xc8, 0xda, 0x74, 0x33, 0x42, 0x10, 0xe0, 0x4c, 0x72, 0x2b, 0x98, 0x74, 0x02, 0x88, 0x63, 0x26, 0x37, 0x42, 0x2b, 0x06, 0x5b, 0x34, 0xa0, 0x99, 0x93, 0xba, 0x54, 0x0f, 0x6b, 0x1f, 0x29, 0x91, 0x50, 0x13, 0x62, 0x5b, 0x3a, 0x5b, 0x6d, 0x9b, 0x83, 0x97, 0x01, 0x11, 0xc4, 0x9e, 0xe2, 0x01, 0xd5, 0x75, 0x85, 0x0a, 0x95, 0x50, 0x63, 0xf4, 0x48, 0x02, 0x9a, 0x96, 0xda, 0x25, 0xb3, 0x9a, 0x33, 0x29, 0xef, 0x30, 0xa6, 0x95, 0xb0, 0xb2, 0x50, 0x03, 0x47, 0x75, 0xe5, 0x97, 0xb3, 0xc1, 0x52, 0x2c, 0xb5, 0x47, 0x15, 0x77, 0xb4, 0x36, 0x67, 0xc9, 0x02, 0xf9, 0xa2, 0x81, 0x70, 0x42, 0xbd, 0x76, 0x2c, 0x8f, 0x8a, 0x31, 0x98, 0x77, 0x99, 0x3f, 0x20, 0x1d, 0xf1, 0xd1, 0x0a, 0x0a, 0x11, 0x07, 0xaf, 0x52, 0xaa, 0x84, 0xcb, 0x8d, 0x6f, 0xf9, 0xa9, 0x54, 0x7a, 0x68, 0xb3, 0x41, 0x40, 0xd0, 0x46, 0x76, 0x83, 0x19, 0x7c, 0x3a, 0x04, 0x07, 0xad, 0xe6, 0x74, 0x36, 0x26, 0x40, 0x68, 0x29, 0x47, 0x12, 0x22, 0x21, 0x26, 0x5b, 0xbe, 0x3a, 0x53, 0x99, 0x2b, 0xb0, 0x61, 0xf2, 0x27, 0x69, 0xd8, 0xe6, 0xb5, 0x63, 0x58, 0x93, 0xd4, 0x77, 0x0b, 0xeb, 0xc2, 0x84, 0x02, 0x93, 0x76, 0x77, 0xc6, 0xbd, 0xf1, 0x58, 0x9e, 0xb8, 0x72, 0x2a, 0x18, 0x4b, 0x01, 0x14, 0xd7, 0x3e, 0xc9, 0xe4, 0x85, 0xa0, 0x48, 0xc9, 0x7c, 0xc0, 0x25, 0x7c, 0x95, 0x0f, 0xa0, 0xdc, 0x59, 0x54, 0xa5, 0xbc, 0x61, 0xb5, 0x72, 0x22, 0x32, 0x6d, 0x9f, 0x2b, 0x00, 0x33, 0x25, 0x7d, 0x1e, 0xba, 0x27, 0xaa, 0x57, 0x41, 0x94, 0x21, 0x90, 0x0b, 0xb5, 0x1a, 0xd0, 0xe4, 0x14, 0x97, 0x89, 0x97, 0xfc, 0xfb, 0xba, 0x16, 0xb5, 0x96, 0xa8, 0x98, 0xb2, 0x1a, 0x3b, 0x96, 0x22, 0x57, 0xa8, 0x29, 0xd8, 0x48, 0x6b, 0xeb, 0x9c, 0x00, 0x30, 0x79, 0x1f, 0x06, 0x81, 0xde, 0x54, 0x26, 0xb4, 0xdc, 0x2e, 0x8b, 0x66, 0x7f, 0x47, 0x32, 0x9a, 0x6c, 0x73, 0x76, 0x80, 0xd8, 0xb9, 0xaa, 0xe4, 0xcd, 0xaf, 0xbc, 0x04, 0x6e, 0x05, 0xab, 0x55, 0x25, 0x42, 0x83, 0xf6, 0xca, 0x5c, 0xbb, 0xae, 0xa3, 0x15, 0xb4, 0x91, 0xb1, 0x28, 0x33, 0xfc, 0xcb, 0x94, 0x92, 0xaa, 0x95, 0x6b, 0x07, 0x1a, 0x71, 0x82, 0x29, 0xa3, 0x74, 0xff, 0x08, 0xa5, 0xe1, 0x87, 0x9b, 0x18, 0xa7, 0x38, 0x80, 0x9a, 0x7f, 0x43, 0xa4, 0xce, 0x13, 0x13, 0xb0, 0x6b, 0xd0, 0x55, 0x87, 0xb7, 0x6c, 0xee, 0xf1, 0xc6, 0x16, 0x30, 0x70, 0xfd, 0x98, 0x78, 0xb6, 0x23, 0x18, 0xb3, 0xc8, 0x9f, 0xc7, 0x17, 0x28, 0x9c, 0x45, 0x42, 0xb1, 0xb6, 0xcb, 0x96, 0x0c, 0xaf, 0x61, 0x42, 0x71, 0x6c, 0xd7, 0x6e, 0x8d, 0x39, 0xad, 0xb6, 0x7a, 0x42, 0x93, 0x91, 0x0a, 0x09, 0x91, 0x09, 0xfd, 0xfa, 0xc0, 0x11, 0xa9, 0xb9, 0x86, 0xc5, 0x09, 0x09, 0x16, 0xce, 0xd0, 0xc3, 0xb4, 0x8a, 0xc9, 0xb1, 0x2c, 0x7c, 0x5a, 0xfb, 0xa1, 0x6b, 0x5e, 0x80, 0x38, 0x51, 0x87 }, .spki_len = 822, }, { .name = "ML-KEM 512", .parameter_set = CKP_IBM_ML_KEM_512, .sk = { 0x3e, 0xd1, 0x88, 0xf8, 0x61, 0x25, 0x9f, 0x50, 0xb6, 0x21, 0x36, 0x0c, 0x66, 0x48, 0x20, 0x7d, 0xdc, 0x1e, 0x6a, 0x4a, 0xb0, 0xcc, 0x1c, 0x24, 0x8a, 0xc6, 0x9b, 0x69, 0xa9, 0x42, 0x46, 0x11, 0x2f, 0x5a, 0x72, 0x75, 0x09, 0xf3, 0x7c, 0xbb, 0xb7, 0x78, 0x25, 0x99, 0x2c, 0x9e, 0x56, 0x13, 0x4e, 0x43, 0xb8, 0xfc, 0xe6, 0x6b, 0x71, 0xaa, 0x7d, 0xc2, 0x68, 0x6c, 0x94, 0x34, 0x5e, 0xca, 0x82, 0x03, 0xc9, 0x86, 0x0a, 0x65, 0x48, 0x39, 0x3a, 0xec, 0x52, 0x3e, 0xa6, 0x94, 0x23, 0xf0, 0x8c, 0x8a, 0x39, 0xa6, 0x7f, 0xd9, 0x4e, 0xda, 0x22, 0x65, 0x47, 0x60, 0x02, 0xe1, 0xfc, 0x9d, 0xf8, 0xfa, 0x87, 0xc2, 0xf1, 0x9b, 0xa6, 0x14, 0x36, 0x2a, 0xfa, 0x0d, 0x41, 0x0b, 0x69, 0x69, 0xc4, 0x3b, 0xd2, 0x9c, 0x60, 0x17, 0xc1, 0x18, 0x10, 0x21, 0x6b, 0x80, 0xb7, 0x51, 0x0f, 0xeb, 0x42, 0x84, 0xe7, 0x05, 0x91, 0xc0, 0x1d, 0x61, 0xf3, 0x50, 0xdf, 0x3c, 0x26, 0xb7, 0x37, 0x18, 0xf5, 0x14, 0x56, 0x06, 0x28, 0x99, 0x84, 0x54, 0x97, 0x2d, 0xa0, 0x6f, 0xf9, 0x48, 0xc4, 0xdb, 0xcb, 0x35, 0xd4, 0x2b, 0x24, 0x8e, 0x63, 0x98, 0xbd, 0xc5, 0x45, 0x03, 0xf7, 0x68, 0x79, 0x24, 0x7d, 0xaa, 0x02, 0xa1, 0xe5, 0xc3, 0xb8, 0xd5, 0xd2, 0x41, 0xdd, 0xf5, 0x08, 0x82, 0x65, 0xa9, 0xf2, 0x08, 0x66, 0x22, 0x16, 0x03, 0xfa, 0xf7, 0x89, 0x28, 0xf9, 0x3a, 0x85, 0x44, 0x4d, 0x84, 0x26, 0x40, 0x00, 0xf7, 0x0c, 0x50, 0x62, 0x64, 0xb6, 0xb9, 0x8b, 0xee, 0x0c, 0x95, 0x28, 0x94, 0x44, 0xdf, 0x1a, 0x4c, 0xde, 0x7a, 0x03, 0xae, 0x5a, 0x46, 0xbe, 0xcb, 0x55, 0x7e, 0x9b, 0x78, 0x01, 0x3c, 0x7b, 0x8d, 0xa2, 0x0f, 0xce, 0x79, 0x2c, 0x2e, 0xd0, 0x20, 0xdf, 0x39, 0x13, 0xb7, 0xf7, 0x71, 0x4e, 0x28, 0x3d, 0xd0, 0x60, 0x95, 0x85, 0xe9, 0x68, 0x4a, 0x82, 0xa9, 0xf7, 0x54, 0xca, 0x5e, 0xe6, 0x97, 0xf7, 0xd7, 0xc0, 0x17, 0xb6, 0x61, 0xfe, 0x78, 0x96, 0xb3, 0xbb, 0x0b, 0x33, 0x62, 0x92, 0x77, 0x01, 0x9a, 0x15, 0x01, 0x2b, 0x50, 0xd6, 0x7e, 0x02, 0xdb, 0x4a, 0x3e, 0xf3, 0x7d, 0x32, 0xa4, 0x44, 0xdf, 0xe2, 0x5c, 0x75, 0xf8, 0x2e, 0x84, 0x2a, 0x6c, 0xb4, 0x51, 0x91, 0xf2, 0xe2, 0x9e, 0xbe, 0xd0, 0xc5, 0xeb, 0xc2, 0xa5, 0xee, 0x0c, 0x43, 0xcb, 0xdb, 0xa3, 0xec, 0x26, 0x5e, 0xa6, 0xe2, 0xca, 0x65, 0x99, 0x47, 0x78, 0x49, 0x64, 0x24, 0xf8, 0xb8, 0x04, 0x38, 0xaf, 0xa6, 0x71, 0x7f, 0x47, 0xd0, 0x56, 0x2d, 0x45, 0x17, 0x73, 0xf8, 0x54, 0xb4, 0xab, 0x50, 0x22, 0x07, 0x67, 0xf3, 0x02, 0x5b, 0x46, 0x79, 0x2e, 0xd5, 0x52, 0x43, 0xb6, 0x43, 0x6d, 0xc7, 0xf6, 0x7c, 0xc2, 0x44, 0x95, 0x53, 0xb9, 0x30, 0x5e, 0xf2, 0xcf, 0xff, 0x70, 0xbf, 0x76, 0x59, 0x3f, 0xad, 0x4b, 0x54, 0x58, 0xc5, 0xc8, 0xf7, 0xa1, 0x88, 0x04, 0xe7, 0x11, 0xec, 0x9a, 0x8e, 0xaf, 0x83, 0x46, 0xbb, 0x92, 0x8a, 0x92, 0xe4, 0x9e, 0xd4, 0x5a, 0x7c, 0x58, 0x17, 0xce, 0xd1, 0x84, 0xb7, 0x2c, 0xd6, 0x60, 0x32, 0xe7, 0xb7, 0x1c, 0xd1, 0x05, 0xa4, 0x46, 0x08, 0x01, 0xf3, 0x21, 0x65, 0x50, 0xa5, 0xf2, 0xa4, 0xa9, 0xb6, 0x18, 0x92, 0x1a, 0x6b, 0x88, 0xed, 0x76, 0x8c, 0xaa, 0x98, 0x13, 0xca, 0xb5, 0x2c, 0xa0, 0xf7, 0xb5, 0x06, 0xf5, 0x1b, 0x17, 0xb8, 0x61, 0x22, 0xb5, 0xbb, 0x8e, 0x07, 0x65, 0xaf, 0x53, 0x9d, 0x0a, 0xfa, 0xcc, 0xb7, 0x67, 0x72, 0x3e, 0x50, 0x37, 0xe2, 0x99, 0xbf, 0x0d, 0x77, 0x02, 0xf5, 0x33, 0xb1, 0x80, 0x65, 0x6b, 0x4d, 0xa1, 0x5d, 0x1f, 0xd1, 0xa3, 0x74, 0x48, 0x9d, 0x94, 0x07, 0x8c, 0x7a, 0x45, 0x91, 0xb7, 0x4a, 0x25, 0x8c, 0xe2, 0x86, 0x46, 0xd6, 0x2e, 0x37, 0xa2, 0xa7, 0x6c, 0x19, 0x89, 0x06, 0xe9, 0xa2, 0x69, 0x30, 0xb2, 0x0b, 0x46, 0x6b, 0xea, 0x17, 0x80, 0x26, 0x48, 0xb3, 0x6b, 0xda, 0x5c, 0xc6, 0x50, 0x06, 0x17, 0x56, 0xba, 0x28, 0xfb, 0x25, 0x55, 0x02, 0x7d, 0x2d, 0xcb, 0x91, 0x6d, 0x28, 0x48, 0x10, 0xb8, 0x11, 0x5e, 0x5c, 0xae, 0x59, 0x58, 0x5f, 0x3b, 0x18, 0x77, 0xea, 0x9c, 0xa9, 0x62, 0x4b, 0x82, 0x45, 0x4b, 0x52, 0x4d, 0x16, 0x5e, 0x9c, 0x6b, 0x7f, 0xf5, 0xe1, 0x45, 0x87, 0x72, 0x49, 0x2b, 0x60, 0x2d, 0x27, 0x75, 0xa9, 0x0b, 0x80, 0x45, 0xf9, 0xa6, 0x72, 0xee, 0xbb, 0x04, 0x5c, 0x00, 0x17, 0x85, 0x42, 0x67, 0xb5, 0x25, 0x03, 0x85, 0x67, 0xcc, 0x57, 0x15, 0x5c, 0xbc, 0x79, 0x0c, 0x6e, 0xd3, 0x02, 0x5b, 0x2a, 0x48, 0x56, 0x6a, 0x6b, 0xee, 0xa5, 0x69, 0xb2, 0x26, 0x21, 0x93, 0xf2, 0x65, 0x7e, 0x70, 0x7b, 0xd6, 0x30, 0x05, 0x88, 0x63, 0x07, 0x76, 0x95, 0x46, 0xbe, 0x57, 0x9e, 0xe1, 0xe0, 0x6c, 0x84, 0xb8, 0xce, 0x89, 0x53, 0x4d, 0x03, 0xb8, 0x31, 0x7e, 0x21, 0x3e, 0x1b, 0xbc, 0x39, 0xf6, 0xfc, 0x99, 0x19, 0x40, 0x55, 0xcd, 0xfc, 0x48, 0xdf, 0x8c, 0xc9, 0xa7, 0xe7, 0x34, 0x33, 0x62, 0xab, 0x63, 0x40, 0x90, 0x11, 0xa7, 0x35, 0x03, 0x06, 0x87, 0x02, 0xa1, 0xa7, 0x29, 0x52, 0xa1, 0x5d, 0xc9, 0x97, 0x2c, 0xcc, 0xad, 0xfb, 0x99, 0x9c, 0xd3, 0x68, 0x70, 0x94, 0x71, 0xaf, 0x5b, 0xb9, 0x2a, 0x76, 0xd6, 0x6e, 0x27, 0x0c, 0x72, 0x03, 0xc5, 0x39, 0x4f, 0x9b, 0x50, 0x7b, 0x00, 0xad, 0x9f, 0xdc, 0x0e, 0xbe, 0x63, 0x2a, 0xe7, 0xf2, 0x90, 0x50, 0x67, 0x97, 0xf7, 0xd5, 0x00, 0x11, 0x9a, 0x2a, 0xd1, 0xbb, 0x5d, 0x7f, 0xe6, 0x5e, 0x21, 0xa7, 0x0a, 0x49, 0xe9, 0x36, 0xa1, 0xbc, 0x92, 0x71, 0xc9, 0x8b, 0x2f, 0x16, 0x99, 0x06, 0x16, 0x9c, 0x44, 0x98, 0x24, 0x0d, 0x3b, 0x02, 0xa4, 0x3b, 0x48, 0x24, 0x86, 0x75, 0x4a, 0xc7, 0xa8, 0xae, 0x38, 0x13, 0xd7, 0x60, 0x4c, 0x23, 0xea, 0x17, 0xc2, 0x28, 0x17, 0x46, 0x38, 0x5a, 0xc5, 0x31, 0xa2, 0x2c, 0x24, 0x47, 0xac, 0x88, 0x7e, 0x7a, 0x8b, 0x67, 0xdd, 0x16, 0xc5, 0x2e, 0x02, 0xa1, 0xe6, 0x5c, 0x54, 0x0b, 0xa8, 0x46, 0xf4, 0x54, 0x80, 0xd2, 0xf2, 0x26, 0xed, 0x55, 0x16, 0xdd, 0x5a, 0x2d, 0x57, 0x0b, 0x70, 0x90, 0xaa, 0x05, 0xf0, 0xe5, 0x25, 0xf5, 0xe8, 0x82, 0xd6, 0xcb, 0xa2, 0x9a, 0x9b, 0x38, 0x9b, 0xd0, 0x89, 0xa6, 0x37, 0x28, 0xf8, 0x28, 0x2b, 0xd1, 0xdb, 0x66, 0xb9, 0xb7, 0x0f, 0xbc, 0x20, 0x9c, 0x0b, 0xa2, 0x3f, 0x97, 0x18, 0x1e, 0x8f, 0xd8, 0xb2, 0x76, 0x45, 0x44, 0x7d, 0x19, 0x93, 0x24, 0xb7, 0x28, 0x31, 0xf3, 0x74, 0x08, 0xfb, 0xb6, 0x64, 0x53, 0x70, 0x88, 0xa0, 0x3c, 0x7c, 0xcb, 0xaf, 0x42, 0x28, 0x0b, 0x87, 0xb8, 0x08, 0xe3, 0x0a, 0xb0, 0xad, 0xec, 0x14, 0x06, 0x9a, 0xc5, 0x4a, 0x31, 0xcc, 0xb7, 0xe9, 0x72, 0xa3, 0xac, 0xcb, 0x52, 0x7c, 0x6a, 0x33, 0xb6, 0x36, 0xf1, 0xe4, 0x57, 0xdf, 0x00, 0x62, 0x9f, 0xfa, 0x2c, 0x16, 0xc7, 0x93, 0xbf, 0xe2, 0x4a, 0x52, 0xb1, 0xc0, 0xf2, 0x89, 0x83, 0x1d, 0x19, 0x2a, 0xcb, 0xa9, 0x48, 0xde, 0x11, 0xaf, 0x08, 0x46, 0x65, 0x7a, 0x20, 0x0a, 0xc7, 0xa0, 0xaf, 0x22, 0xc5, 0x6c, 0x86, 0x31, 0x00, 0xef, 0xcb, 0x85, 0x95, 0x94, 0x7e, 0x61, 0xa3, 0xc9, 0xb2, 0x17, 0x22, 0x0c, 0x91, 0x40, 0x9a, 0x18, 0xc8, 0x3d, 0x62, 0x17, 0x41, 0xf8, 0x70, 0xed, 0x32, 0x4a, 0x5f, 0x8b, 0x7a, 0xb4, 0x66, 0x4c, 0x18, 0x12, 0x3e, 0xac, 0x31, 0xaf, 0x8e, 0xb3, 0x3a, 0xbb, 0x06, 0x8e, 0xaf, 0x79, 0x89, 0x01, 0x8a, 0x00, 0x26, 0x67, 0x52, 0xdd, 0x36, 0x4b, 0x64, 0xd3, 0x54, 0x00, 0xe4, 0xc5, 0xcc, 0x20, 0x37, 0xee, 0x7a, 0x54, 0x09, 0x08, 0x0a, 0x1a, 0x3a, 0x9f, 0xcd, 0x6a, 0xbc, 0xa4, 0x10, 0xa1, 0x7c, 0x1c, 0xbf, 0xe1, 0x98, 0x31, 0x05, 0xc9, 0x26, 0x91, 0xdb, 0x78, 0x24, 0xf1, 0xc9, 0x48, 0x73, 0x25, 0x00, 0x91, 0xcc, 0xd3, 0x93, 0xcc, 0x43, 0x94, 0x00, 0x16, 0x30, 0x68, 0xca, 0x37, 0x0b, 0xb1, 0x62, 0x9b, 0x55, 0x65, 0xad, 0x2e, 0x2b, 0x59, 0x25, 0xc6, 0x15, 0x43, 0xb9, 0x2d, 0xa4, 0x60, 0x83, 0x05, 0xb6, 0x1a, 0x01, 0xb2, 0x29, 0xca, 0x80, 0x8e, 0xc6, 0x91, 0x67, 0xb5, 0xa1, 0x82, 0x7d, 0xc9, 0x51, 0x15, 0x07, 0x2e, 0xa5, 0xac, 0x83, 0x45, 0x26, 0x64, 0xb5, 0xb2, 0x94, 0xf1, 0xe5, 0x0c, 0x26, 0x98, 0x1d, 0x61, 0x1a, 0x10, 0x41, 0xc3, 0x91, 0x11, 0x36, 0x28, 0xe9, 0xca, 0xcd, 0x51, 0xe3, 0x43, 0xf1, 0xc5, 0xab, 0x31, 0x13, 0x08, 0x2b, 0xa0, 0x39, 0xe4, 0x0a, 0x61, 0xb0, 0xb3, 0x99, 0x13, 0x2b, 0x32, 0x26, 0xd7, 0x5b, 0x65, 0xe3, 0x58, 0x14, 0x51, 0x2e, 0xc7, 0xc4, 0x85, 0x29, 0xdb, 0x65, 0x01, 0xa2, 0x47, 0xdf, 0x2b, 0x5c, 0x3a, 0x13, 0x19, 0x00, 0x12, 0x8b, 0x17, 0xd3, 0x1a, 0x90, 0xdc, 0x55, 0xf1, 0x38, 0x76, 0x5f, 0x04, 0x5f, 0xda, 0xd9, 0x5d, 0x86, 0xd1, 0xc1, 0x1f, 0xf2, 0x6a, 0xbd, 0xac, 0x40, 0xde, 0x8c, 0xb5, 0xdb, 0xf8, 0x87, 0x3c, 0x91, 0x9e, 0x39, 0xdb, 0x12, 0x5a, 0xe0, 0x98, 0xb7, 0xdb, 0x15, 0x12, 0x91, 0x2e, 0x0e, 0x99, 0x79, 0x6a, 0xfc, 0x67, 0x94, 0x72, 0x84, 0xa7, 0xa7, 0x13, 0xba, 0x28, 0x48, 0xfd, 0xcc, 0xc4, 0xfd, 0x82, 0x60, 0xf1, 0x5a, 0x69, 0x60, 0xf9, 0xad, 0x43, 0x21, 0xb9, 0xcf, 0xd2, 0xc9, 0xf7, 0x1b, 0x7a, 0x5b, 0x47, 0x87, 0x2b, 0x75, 0xbb, 0xce, 0x75, 0x7b, 0xda, 0x77, 0x14, 0x57, 0x38, 0x5a, 0xb9, 0x89, 0x9c, 0xb5, 0x6b, 0x01, 0x4d, 0x18, 0xc1, 0x24, 0x80, 0x56, 0xf8, 0x04, 0x5f, 0x64, 0xb3, 0xa6, 0xf9, 0x70, 0x04, 0x3f, 0x04, 0x3d, 0xaa, 0x50, 0x74, 0xfd, 0x14, 0x9b, 0xd2, 0x0b, 0x09, 0x82, 0x31, 0x94, 0x8f, 0x04, 0x47, 0x6c, 0x51, 0x1b, 0xc2, 0x09, 0x35, 0xce, 0xd5, 0x06, 0x30, 0x67, 0x7b, 0x79, 0x71, 0x85, 0x9e, 0x89, 0x6f, 0x7b, 0x73, 0x97, 0x89, 0xd4, 0x07, 0x76, 0x64, 0xb6, 0x36, 0x00, 0x2e, 0x80, 0x65, 0xbd, 0x59, 0xf4, 0x69, 0x84, 0xe2, 0x7b, 0xb7, 0xac, 0x27, 0x35, 0x33, 0x92, 0x36, 0xda, 0x36, 0xa0, 0x56, 0x3d, 0x80, 0x63, 0x0c, 0x86, 0x26, 0x68, 0x01, 0x12, 0x32, 0x09, 0xe1, 0x20, 0x80, 0x5a, 0x6f, 0xc4, 0x34, 0x22, 0x5e, 0x06, 0x96, 0xd6, 0x59, 0x98, 0x7e, 0xfa, 0x38, 0x5c, 0x25, 0x50, 0xfc, 0xcc, 0x92, 0x17, 0x15, 0x30, 0xff, 0x5c, 0x3f, 0xe8, 0xb5, 0x30, 0x19, 0x68, 0x4e, 0xd4, 0x5c, 0x91, 0x44, 0xc9, 0x1b, 0x07, 0x60, 0x08, 0x9a, 0xec, 0x3b, 0xc8, 0x74, 0x26, 0x42, 0xf7, 0xbc, 0xb5, 0x94, 0x10, 0x6f, 0x55, 0x84, 0xb1, 0xc9, 0x4a, 0xaa, 0x1b, 0x01, 0xdf, 0xc1, 0x4b, 0x99, 0xe0, 0x32, 0x23, 0xf3, 0x61, 0xd7, 0xc0, 0x33, 0x69, 0x37, 0x2b, 0xd7, 0x8a, 0x53, 0x92, 0xb5, 0x9d, 0x1a, 0xfb, 0x58, 0xd8, 0x44, 0xb8, 0x80, 0xf8, 0x39, 0xd6, 0x25, 0xa8, 0xbc, 0xb2, 0x02, 0xf3, 0x51, 0x1a, 0xc5, 0x84, 0x96, 0xc8, 0x57, 0x57, 0xa7, 0x64, 0xcc, 0x6f, 0x15, 0x30, 0xa0, 0xaf, 0x73, 0x9f, 0x4c, 0x0b, 0x33, 0x1e, 0x17, 0xdf, 0xc0, 0xb4, 0x2d, 0xe0, 0x6b, 0x47, 0x87, 0xa0, 0x8b, 0x06, 0x3d, 0xd6, 0x6a, 0x00, 0xf2, 0x1c, 0xa6, 0x9d, 0x4e, 0x8c, 0x20, 0x65, 0x2c, 0xda, 0x97, 0x58, 0x91, 0x6c, 0x20, 0xc3, 0xa2, 0x0d, 0xba, 0x06, 0x48, 0x83, 0x53, 0x61, 0x14, 0xd8, 0x1b, 0x61, 0xbf, 0x3b, 0x1b, 0x16, 0xbd, 0xc4, 0x26, 0x65, 0x81, 0x3f, 0x43, 0xd6, 0x9b, 0x29, 0x09, 0xa6, 0x8c, 0xf9, 0x68, 0x40, 0x65, 0x24, 0x6d, 0x7b, 0x19, 0x80, 0x2b, 0x5d, 0xc6, }, .sk_len = 1632, .pk = { 0x50, 0x67, 0x97, 0xf7, 0xd5, 0x00, 0x11, 0x9a, 0x2a, 0xd1, 0xbb, 0x5d, 0x7f, 0xe6, 0x5e, 0x21, 0xa7, 0x0a, 0x49, 0xe9, 0x36, 0xa1, 0xbc, 0x92, 0x71, 0xc9, 0x8b, 0x2f, 0x16, 0x99, 0x06, 0x16, 0x9c, 0x44, 0x98, 0x24, 0x0d, 0x3b, 0x02, 0xa4, 0x3b, 0x48, 0x24, 0x86, 0x75, 0x4a, 0xc7, 0xa8, 0xae, 0x38, 0x13, 0xd7, 0x60, 0x4c, 0x23, 0xea, 0x17, 0xc2, 0x28, 0x17, 0x46, 0x38, 0x5a, 0xc5, 0x31, 0xa2, 0x2c, 0x24, 0x47, 0xac, 0x88, 0x7e, 0x7a, 0x8b, 0x67, 0xdd, 0x16, 0xc5, 0x2e, 0x02, 0xa1, 0xe6, 0x5c, 0x54, 0x0b, 0xa8, 0x46, 0xf4, 0x54, 0x80, 0xd2, 0xf2, 0x26, 0xed, 0x55, 0x16, 0xdd, 0x5a, 0x2d, 0x57, 0x0b, 0x70, 0x90, 0xaa, 0x05, 0xf0, 0xe5, 0x25, 0xf5, 0xe8, 0x82, 0xd6, 0xcb, 0xa2, 0x9a, 0x9b, 0x38, 0x9b, 0xd0, 0x89, 0xa6, 0x37, 0x28, 0xf8, 0x28, 0x2b, 0xd1, 0xdb, 0x66, 0xb9, 0xb7, 0x0f, 0xbc, 0x20, 0x9c, 0x0b, 0xa2, 0x3f, 0x97, 0x18, 0x1e, 0x8f, 0xd8, 0xb2, 0x76, 0x45, 0x44, 0x7d, 0x19, 0x93, 0x24, 0xb7, 0x28, 0x31, 0xf3, 0x74, 0x08, 0xfb, 0xb6, 0x64, 0x53, 0x70, 0x88, 0xa0, 0x3c, 0x7c, 0xcb, 0xaf, 0x42, 0x28, 0x0b, 0x87, 0xb8, 0x08, 0xe3, 0x0a, 0xb0, 0xad, 0xec, 0x14, 0x06, 0x9a, 0xc5, 0x4a, 0x31, 0xcc, 0xb7, 0xe9, 0x72, 0xa3, 0xac, 0xcb, 0x52, 0x7c, 0x6a, 0x33, 0xb6, 0x36, 0xf1, 0xe4, 0x57, 0xdf, 0x00, 0x62, 0x9f, 0xfa, 0x2c, 0x16, 0xc7, 0x93, 0xbf, 0xe2, 0x4a, 0x52, 0xb1, 0xc0, 0xf2, 0x89, 0x83, 0x1d, 0x19, 0x2a, 0xcb, 0xa9, 0x48, 0xde, 0x11, 0xaf, 0x08, 0x46, 0x65, 0x7a, 0x20, 0x0a, 0xc7, 0xa0, 0xaf, 0x22, 0xc5, 0x6c, 0x86, 0x31, 0x00, 0xef, 0xcb, 0x85, 0x95, 0x94, 0x7e, 0x61, 0xa3, 0xc9, 0xb2, 0x17, 0x22, 0x0c, 0x91, 0x40, 0x9a, 0x18, 0xc8, 0x3d, 0x62, 0x17, 0x41, 0xf8, 0x70, 0xed, 0x32, 0x4a, 0x5f, 0x8b, 0x7a, 0xb4, 0x66, 0x4c, 0x18, 0x12, 0x3e, 0xac, 0x31, 0xaf, 0x8e, 0xb3, 0x3a, 0xbb, 0x06, 0x8e, 0xaf, 0x79, 0x89, 0x01, 0x8a, 0x00, 0x26, 0x67, 0x52, 0xdd, 0x36, 0x4b, 0x64, 0xd3, 0x54, 0x00, 0xe4, 0xc5, 0xcc, 0x20, 0x37, 0xee, 0x7a, 0x54, 0x09, 0x08, 0x0a, 0x1a, 0x3a, 0x9f, 0xcd, 0x6a, 0xbc, 0xa4, 0x10, 0xa1, 0x7c, 0x1c, 0xbf, 0xe1, 0x98, 0x31, 0x05, 0xc9, 0x26, 0x91, 0xdb, 0x78, 0x24, 0xf1, 0xc9, 0x48, 0x73, 0x25, 0x00, 0x91, 0xcc, 0xd3, 0x93, 0xcc, 0x43, 0x94, 0x00, 0x16, 0x30, 0x68, 0xca, 0x37, 0x0b, 0xb1, 0x62, 0x9b, 0x55, 0x65, 0xad, 0x2e, 0x2b, 0x59, 0x25, 0xc6, 0x15, 0x43, 0xb9, 0x2d, 0xa4, 0x60, 0x83, 0x05, 0xb6, 0x1a, 0x01, 0xb2, 0x29, 0xca, 0x80, 0x8e, 0xc6, 0x91, 0x67, 0xb5, 0xa1, 0x82, 0x7d, 0xc9, 0x51, 0x15, 0x07, 0x2e, 0xa5, 0xac, 0x83, 0x45, 0x26, 0x64, 0xb5, 0xb2, 0x94, 0xf1, 0xe5, 0x0c, 0x26, 0x98, 0x1d, 0x61, 0x1a, 0x10, 0x41, 0xc3, 0x91, 0x11, 0x36, 0x28, 0xe9, 0xca, 0xcd, 0x51, 0xe3, 0x43, 0xf1, 0xc5, 0xab, 0x31, 0x13, 0x08, 0x2b, 0xa0, 0x39, 0xe4, 0x0a, 0x61, 0xb0, 0xb3, 0x99, 0x13, 0x2b, 0x32, 0x26, 0xd7, 0x5b, 0x65, 0xe3, 0x58, 0x14, 0x51, 0x2e, 0xc7, 0xc4, 0x85, 0x29, 0xdb, 0x65, 0x01, 0xa2, 0x47, 0xdf, 0x2b, 0x5c, 0x3a, 0x13, 0x19, 0x00, 0x12, 0x8b, 0x17, 0xd3, 0x1a, 0x90, 0xdc, 0x55, 0xf1, 0x38, 0x76, 0x5f, 0x04, 0x5f, 0xda, 0xd9, 0x5d, 0x86, 0xd1, 0xc1, 0x1f, 0xf2, 0x6a, 0xbd, 0xac, 0x40, 0xde, 0x8c, 0xb5, 0xdb, 0xf8, 0x87, 0x3c, 0x91, 0x9e, 0x39, 0xdb, 0x12, 0x5a, 0xe0, 0x98, 0xb7, 0xdb, 0x15, 0x12, 0x91, 0x2e, 0x0e, 0x99, 0x79, 0x6a, 0xfc, 0x67, 0x94, 0x72, 0x84, 0xa7, 0xa7, 0x13, 0xba, 0x28, 0x48, 0xfd, 0xcc, 0xc4, 0xfd, 0x82, 0x60, 0xf1, 0x5a, 0x69, 0x60, 0xf9, 0xad, 0x43, 0x21, 0xb9, 0xcf, 0xd2, 0xc9, 0xf7, 0x1b, 0x7a, 0x5b, 0x47, 0x87, 0x2b, 0x75, 0xbb, 0xce, 0x75, 0x7b, 0xda, 0x77, 0x14, 0x57, 0x38, 0x5a, 0xb9, 0x89, 0x9c, 0xb5, 0x6b, 0x01, 0x4d, 0x18, 0xc1, 0x24, 0x80, 0x56, 0xf8, 0x04, 0x5f, 0x64, 0xb3, 0xa6, 0xf9, 0x70, 0x04, 0x3f, 0x04, 0x3d, 0xaa, 0x50, 0x74, 0xfd, 0x14, 0x9b, 0xd2, 0x0b, 0x09, 0x82, 0x31, 0x94, 0x8f, 0x04, 0x47, 0x6c, 0x51, 0x1b, 0xc2, 0x09, 0x35, 0xce, 0xd5, 0x06, 0x30, 0x67, 0x7b, 0x79, 0x71, 0x85, 0x9e, 0x89, 0x6f, 0x7b, 0x73, 0x97, 0x89, 0xd4, 0x07, 0x76, 0x64, 0xb6, 0x36, 0x00, 0x2e, 0x80, 0x65, 0xbd, 0x59, 0xf4, 0x69, 0x84, 0xe2, 0x7b, 0xb7, 0xac, 0x27, 0x35, 0x33, 0x92, 0x36, 0xda, 0x36, 0xa0, 0x56, 0x3d, 0x80, 0x63, 0x0c, 0x86, 0x26, 0x68, 0x01, 0x12, 0x32, 0x09, 0xe1, 0x20, 0x80, 0x5a, 0x6f, 0xc4, 0x34, 0x22, 0x5e, 0x06, 0x96, 0xd6, 0x59, 0x98, 0x7e, 0xfa, 0x38, 0x5c, 0x25, 0x50, 0xfc, 0xcc, 0x92, 0x17, 0x15, 0x30, 0xff, 0x5c, 0x3f, 0xe8, 0xb5, 0x30, 0x19, 0x68, 0x4e, 0xd4, 0x5c, 0x91, 0x44, 0xc9, 0x1b, 0x07, 0x60, 0x08, 0x9a, 0xec, 0x3b, 0xc8, 0x74, 0x26, 0x42, 0xf7, 0xbc, 0xb5, 0x94, 0x10, 0x6f, 0x55, 0x84, 0xb1, 0xc9, 0x4a, 0xaa, 0x1b, 0x01, 0xdf, 0xc1, 0x4b, 0x99, 0xe0, 0x32, 0x23, 0xf3, 0x61, 0xd7, 0xc0, 0x33, 0x69, 0x37, 0x2b, 0xd7, 0x8a, 0x53, 0x92, 0xb5, 0x9d, 0x1a, 0xfb, 0x58, 0xd8, 0x44, 0xb8, 0x80, 0xf8, 0x39, 0xd6, 0x25, 0xa8, 0xbc, 0xb2, 0x02, 0xf3, 0x51, 0x1a, 0xc5, 0x84, 0x96, 0xc8, 0x57, 0x57, 0xa7, 0x64, 0xcc, 0x6f, 0x15, 0x30, 0xa0, 0xaf, 0x73, 0x9f, 0x4c, 0x0b, 0x33, 0x1e, 0x17, 0xdf, 0xc0, 0xb4, 0x2d, 0xe0, 0x6b, 0x47, 0x87, }, .pk_len = 800, }, { .name = "ML-KEM 512 (seed only)", .parameter_set = CKP_IBM_ML_KEM_512, .priv_seed = { 0x6C, 0xC8, 0x9E, 0x4C, 0xE5, 0x48, 0x9C, 0x76, 0x20, 0xD8, 0xBF, 0x00, 0x14, 0x0F, 0xC4, 0x24, 0x71, 0xA5, 0x80, 0x34, 0xFD, 0x9A, 0xC9, 0x53, 0xBD, 0x45, 0xE4, 0x4B, 0xFD, 0x79, 0xDF, 0x81, 0x28, 0x59, 0xD4, 0x98, 0xDA, 0x66, 0xF3, 0x70, 0xA2, 0xD6, 0xA8, 0x5E, 0xAF, 0x45, 0x6D, 0xE0, 0xF4, 0x3D, 0x39, 0x08, 0x1D, 0xC7, 0xE3, 0xB1, 0x7B, 0x31, 0x0F, 0xFB, 0xA4, 0x34, 0x54, 0xD9 }, .priv_seed_len = 64, .spki = { 0x30, 0x82, 0x03, 0x32, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x04, 0x01, 0x03, 0x82, 0x03, 0x21, 0x00, 0x0a, 0xb5, 0x96, 0xaf, 0x74, 0x36, 0x90, 0x1b, 0x31, 0x1d, 0x61, 0xc7, 0xb3, 0x14, 0x39, 0x55, 0xd7, 0x9b, 0xb2, 0x17, 0x52, 0xa1, 0x83, 0x2e, 0xcf, 0x35, 0x30, 0x86, 0x06, 0x49, 0x3e, 0x05, 0xc6, 0x75, 0x53, 0x54, 0xe4, 0x40, 0xc1, 0x21, 0xca, 0x05, 0x0d, 0x03, 0xce, 0x2c, 0x76, 0xcc, 0xa7, 0x7c, 0x8d, 0x0c, 0xac, 0xa0, 0x0a, 0x21, 0x03, 0x61, 0x2b, 0x90, 0x16, 0xd7, 0x90, 0x43, 0x80, 0xa6, 0x94, 0xc1, 0x42, 0x45, 0x38, 0xaf, 0x1c, 0xbb, 0x5b, 0x21, 0xbc, 0xc4, 0xae, 0xea, 0x58, 0xd8, 0x49, 0xa5, 0xf2, 0x07, 0x3d, 0x12, 0xa2, 0x82, 0x18, 0x49, 0xbf, 0xc4, 0x8c, 0x52, 0xe6, 0xb3, 0x45, 0x74, 0x65, 0x1c, 0xe1, 0x78, 0x72, 0x26, 0xd7, 0x0f, 0x11, 0x08, 0x0a, 0xd1, 0x34, 0xcf, 0x20, 0x00, 0x95, 0x94, 0x00, 0x86, 0x6b, 0xa0, 0x2c, 0xdc, 0xca, 0xae, 0x3e, 0xb2, 0x91, 0x23, 0x06, 0x99, 0xcc, 0xa3, 0xb6, 0x0b, 0xb6, 0xc4, 0xfc, 0x57, 0x09, 0xd8, 0x08, 0x8c, 0x0a, 0xc4, 0x62, 0x39, 0xb1, 0x32, 0x41, 0xf6, 0x94, 0xb0, 0x41, 0x2d, 0x2c, 0x92, 0xcc, 0x2b, 0xb1, 0xbc, 0xec, 0x5c, 0x6a, 0x32, 0x39, 0x98, 0xc6, 0xa4, 0x8a, 0x34, 0x0a, 0x89, 0xdf, 0x29, 0x79, 0xc5, 0x45, 0x81, 0xeb, 0x74, 0x44, 0x86, 0x00, 0x37, 0x9a, 0x36, 0x56, 0xbc, 0x9a, 0x8d, 0x7e, 0x39, 0x77, 0x02, 0xc4, 0x12, 0xf9, 0xc8, 0x03, 0x2b, 0xaa, 0x6e, 0x14, 0xbc, 0x8a, 0x34, 0xd5, 0x34, 0x59, 0x20, 0x7d, 0x15, 0x81, 0x4d, 0x8c, 0x0c, 0x71, 0x1c, 0xe0, 0xab, 0x3c, 0xd8, 0xcb, 0x38, 0xf0, 0x39, 0xbc, 0x38, 0x78, 0xde, 0x88, 0x8b, 0x73, 0xd7, 0x11, 0x8d, 0xe7, 0x82, 0x53, 0x26, 0x53, 0xe0, 0x29, 0xb5, 0xe8, 0x56, 0x77, 0xf3, 0xa8, 0x08, 0x9a, 0xab, 0xa9, 0xc0, 0xc8, 0x85, 0xd2, 0xc7, 0xcd, 0x57, 0x49, 0x86, 0xdb, 0x2c, 0xb9, 0xda, 0x78, 0x26, 0x32, 0xac, 0x79, 0x8e, 0x93, 0x5a, 0x50, 0x92, 0xc6, 0x95, 0xc1, 0x46, 0x02, 0x48, 0x59, 0x0b, 0xfb, 0x64, 0x40, 0x85, 0x65, 0xf3, 0x33, 0xb0, 0x3e, 0x4c, 0x3c, 0xae, 0x13, 0x92, 0x4d, 0x0a, 0x6c, 0x6a, 0x92, 0xb9, 0x5f, 0x47, 0x0d, 0xe6, 0xac, 0x52, 0xc0, 0x05, 0x8d, 0xe0, 0xe9, 0x82, 0x4d, 0x66, 0x83, 0xdf, 0xd0, 0x1d, 0x70, 0x39, 0x5a, 0x15, 0xe8, 0x24, 0xf2, 0xfa, 0xaf, 0xee, 0xc5, 0xac, 0x48, 0xe0, 0x99, 0x19, 0x46, 0x70, 0x7b, 0x34, 0xb1, 0xbd, 0x1c, 0x20, 0x77, 0x97, 0x0c, 0x20, 0x10, 0x24, 0xc8, 0x32, 0x67, 0xbd, 0x73, 0x24, 0x11, 0xc0, 0x95, 0xad, 0xa6, 0x2e, 0x0e, 0xdc, 0xc2, 0x9c, 0x4b, 0x60, 0xc3, 0x62, 0x7c, 0x95, 0x76, 0x73, 0xc8, 0xda, 0x74, 0x33, 0x42, 0x10, 0xe0, 0x4c, 0x72, 0x2b, 0x98, 0x74, 0x02, 0x88, 0x63, 0x26, 0x37, 0x42, 0x2b, 0x06, 0x5b, 0x34, 0xa0, 0x99, 0x93, 0xba, 0x54, 0x0f, 0x6b, 0x1f, 0x29, 0x91, 0x50, 0x13, 0x62, 0x5b, 0x3a, 0x5b, 0x6d, 0x9b, 0x83, 0x97, 0x01, 0x11, 0xc4, 0x9e, 0xe2, 0x01, 0xd5, 0x75, 0x85, 0x0a, 0x95, 0x50, 0x63, 0xf4, 0x48, 0x02, 0x9a, 0x96, 0xda, 0x25, 0xb3, 0x9a, 0x33, 0x29, 0xef, 0x30, 0xa6, 0x95, 0xb0, 0xb2, 0x50, 0x03, 0x47, 0x75, 0xe5, 0x97, 0xb3, 0xc1, 0x52, 0x2c, 0xb5, 0x47, 0x15, 0x77, 0xb4, 0x36, 0x67, 0xc9, 0x02, 0xf9, 0xa2, 0x81, 0x70, 0x42, 0xbd, 0x76, 0x2c, 0x8f, 0x8a, 0x31, 0x98, 0x77, 0x99, 0x3f, 0x20, 0x1d, 0xf1, 0xd1, 0x0a, 0x0a, 0x11, 0x07, 0xaf, 0x52, 0xaa, 0x84, 0xcb, 0x8d, 0x6f, 0xf9, 0xa9, 0x54, 0x7a, 0x68, 0xb3, 0x41, 0x40, 0xd0, 0x46, 0x76, 0x83, 0x19, 0x7c, 0x3a, 0x04, 0x07, 0xad, 0xe6, 0x74, 0x36, 0x26, 0x40, 0x68, 0x29, 0x47, 0x12, 0x22, 0x21, 0x26, 0x5b, 0xbe, 0x3a, 0x53, 0x99, 0x2b, 0xb0, 0x61, 0xf2, 0x27, 0x69, 0xd8, 0xe6, 0xb5, 0x63, 0x58, 0x93, 0xd4, 0x77, 0x0b, 0xeb, 0xc2, 0x84, 0x02, 0x93, 0x76, 0x77, 0xc6, 0xbd, 0xf1, 0x58, 0x9e, 0xb8, 0x72, 0x2a, 0x18, 0x4b, 0x01, 0x14, 0xd7, 0x3e, 0xc9, 0xe4, 0x85, 0xa0, 0x48, 0xc9, 0x7c, 0xc0, 0x25, 0x7c, 0x95, 0x0f, 0xa0, 0xdc, 0x59, 0x54, 0xa5, 0xbc, 0x61, 0xb5, 0x72, 0x22, 0x32, 0x6d, 0x9f, 0x2b, 0x00, 0x33, 0x25, 0x7d, 0x1e, 0xba, 0x27, 0xaa, 0x57, 0x41, 0x94, 0x21, 0x90, 0x0b, 0xb5, 0x1a, 0xd0, 0xe4, 0x14, 0x97, 0x89, 0x97, 0xfc, 0xfb, 0xba, 0x16, 0xb5, 0x96, 0xa8, 0x98, 0xb2, 0x1a, 0x3b, 0x96, 0x22, 0x57, 0xa8, 0x29, 0xd8, 0x48, 0x6b, 0xeb, 0x9c, 0x00, 0x30, 0x79, 0x1f, 0x06, 0x81, 0xde, 0x54, 0x26, 0xb4, 0xdc, 0x2e, 0x8b, 0x66, 0x7f, 0x47, 0x32, 0x9a, 0x6c, 0x73, 0x76, 0x80, 0xd8, 0xb9, 0xaa, 0xe4, 0xcd, 0xaf, 0xbc, 0x04, 0x6e, 0x05, 0xab, 0x55, 0x25, 0x42, 0x83, 0xf6, 0xca, 0x5c, 0xbb, 0xae, 0xa3, 0x15, 0xb4, 0x91, 0xb1, 0x28, 0x33, 0xfc, 0xcb, 0x94, 0x92, 0xaa, 0x95, 0x6b, 0x07, 0x1a, 0x71, 0x82, 0x29, 0xa3, 0x74, 0xff, 0x08, 0xa5, 0xe1, 0x87, 0x9b, 0x18, 0xa7, 0x38, 0x80, 0x9a, 0x7f, 0x43, 0xa4, 0xce, 0x13, 0x13, 0xb0, 0x6b, 0xd0, 0x55, 0x87, 0xb7, 0x6c, 0xee, 0xf1, 0xc6, 0x16, 0x30, 0x70, 0xfd, 0x98, 0x78, 0xb6, 0x23, 0x18, 0xb3, 0xc8, 0x9f, 0xc7, 0x17, 0x28, 0x9c, 0x45, 0x42, 0xb1, 0xb6, 0xcb, 0x96, 0x0c, 0xaf, 0x61, 0x42, 0x71, 0x6c, 0xd7, 0x6e, 0x8d, 0x39, 0xad, 0xb6, 0x7a, 0x42, 0x93, 0x91, 0x0a, 0x09, 0x91, 0x09, 0xfd, 0xfa, 0xc0, 0x11, 0xa9, 0xb9, 0x86, 0xc5, 0x09, 0x09, 0x16, 0xce, 0xd0, 0xc3, 0xb4, 0x8a, 0xc9, 0xb1, 0x2c, 0x7c, 0x5a, 0xfb, 0xa1, 0x6b, 0x5e, 0x80, 0x38, 0x51, 0x87 }, .spki_len = 822, }, { .name = "ML-KEM 786 (PKCS#8/SPKI - priv only)", .pkcs8 = { 0x30, 0x82, 0x09, 0x78, 0x02, 0x01, 0x00, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x04, 0x02, 0x04, 0x82, 0x09, 0x64, 0x04, 0x82, 0x09, 0x60, 0x95, 0x47, 0x4e, 0x91, 0x50, 0x84, 0x3d, 0xac, 0x45, 0x2f, 0x8b, 0x98, 0x46, 0x2c, 0x57, 0xba, 0xc7, 0x02, 0xed, 0x93, 0x51, 0xba, 0x26, 0x71, 0x4a, 0x73, 0xaf, 0x66, 0xc4, 0x10, 0x90, 0x59, 0x50, 0xe3, 0xe7, 0x6c, 0x0d, 0x59, 0xcb, 0x7a, 0x19, 0x21, 0xa0, 0xb0, 0x05, 0x11, 0xa5, 0x29, 0x6a, 0x48, 0xbc, 0x03, 0x43, 0x1f, 0xd0, 0x0b, 0x88, 0x4f, 0x91, 0x3d, 0x5c, 0xc7, 0x72, 0x3a, 0x40, 0x44, 0xeb, 0x16, 0x74, 0x05, 0x00, 0x66, 0xca, 0x75, 0x3a, 0x22, 0x10, 0x3f, 0xe1, 0xfc, 0xae, 0x17, 0xba, 0x80, 0xc3, 0x91, 0x53, 0xe9, 0x59, 0x3d, 0x07, 0x66, 0xca, 0xc3, 0x07, 0x5e, 0x05, 0xbb, 0x19, 0xa3, 0x07, 0x72, 0x5a, 0x6b, 0x67, 0x57, 0x27, 0x43, 0xd2, 0x59, 0x3c, 0xc9, 0x63, 0x2c, 0x26, 0x8b, 0x74, 0xcc, 0x76, 0x32, 0xf5, 0x49, 0x76, 0x9e, 0xba, 0xa0, 0x30, 0x30, 0x4a, 0x72, 0x6a, 0xcf, 0x49, 0xc5, 0x6a, 0xf1, 0xca, 0x3a, 0xa4, 0x4a, 0x7a, 0xe7, 0xc9, 0xa0, 0x4c, 0x27, 0x79, 0xe3, 0x73, 0x6d, 0x80, 0x97, 0x14, 0xf6, 0x37, 0x94, 0x0d, 0xe5, 0x68, 0xa9, 0x13, 0x16, 0x3d, 0x53, 0xb2, 0xcb, 0x0a, 0x12, 0xb6, 0xd1, 0x01, 0x01, 0xb1, 0x0f, 0x11, 0x73, 0x3a, 0xc2, 0xb0, 0xb4, 0x80, 0xb4, 0x0c, 0x35, 0x01, 0x20, 0x88, 0x49, 0x86, 0xf8, 0x2c, 0xa4, 0x8d, 0xf7, 0xac, 0x52, 0xca, 0xb3, 0x7d, 0xdc, 0x96, 0xc3, 0x76, 0x81, 0x11, 0x06, 0x8d, 0x7e, 0xe3, 0x78, 0xb9, 0xd2, 0x2f, 0x86, 0x25, 0x83, 0xf5, 0x5c, 0x8d, 0xb1, 0x15, 0xb6, 0x35, 0x9c, 0x40, 0xad, 0x64, 0x23, 0x53, 0x97, 0xc2, 0xb2, 0x18, 0x93, 0x13, 0xb8, 0x38, 0xd7, 0x82, 0x20, 0x6f, 0x00, 0x85, 0xd1, 0x00, 0xc2, 0xe0, 0x54, 0xa3, 0x5d, 0x27, 0x92, 0xfc, 0x81, 0x6c, 0x60, 0x05, 0x41, 0xda, 0x65, 0x26, 0x01, 0xa7, 0x6f, 0x39, 0x14, 0x4a, 0x33, 0xd3, 0x8b, 0x12, 0xf0, 0x0b, 0x57, 0x70, 0x8a, 0x2d, 0x8a, 0x87, 0x19, 0xf2, 0x88, 0x0c, 0x6c, 0x65, 0x78, 0x69, 0xa9, 0x30, 0x87, 0x3c, 0x2d, 0x03, 0xa0, 0xfc, 0x96, 0x6e, 0xbb, 0x91, 0x07, 0x90, 0x90, 0xb4, 0x99, 0xd7, 0xbf, 0xeb, 0x53, 0x60, 0x8a, 0x23, 0x28, 0x72, 0x79, 0x8e, 0x7e, 0xa0, 0x3d, 0x11, 0x23, 0x12, 0x76, 0xe1, 0xbb, 0xc4, 0x2c, 0x01, 0x31, 0xbc, 0x87, 0x8e, 0x9c, 0x48, 0x92, 0x71, 0x2c, 0x84, 0xa1, 0x2b, 0xe6, 0xa7, 0x1d, 0x88, 0xa4, 0xc7, 0xa1, 0x80, 0x00, 0xc4, 0xe1, 0x9c, 0x80, 0xa9, 0x20, 0x1f, 0x7c, 0x87, 0xf0, 0xcc, 0x8b, 0x73, 0x93, 0x2d, 0xf8, 0x4b, 0x9d, 0x8e, 0xb4, 0x9c, 0xff, 0xb5, 0x8a, 0x9e, 0xa7, 0x45, 0xe9, 0x75, 0x48, 0xcc, 0xa0, 0x91, 0x16, 0x88, 0x51, 0xc3, 0x5c, 0xc6, 0x4c, 0xeb, 0x9f, 0x98, 0x93, 0x56, 0x68, 0x28, 0x36, 0x70, 0x66, 0x0e, 0x41, 0x78, 0xcc, 0x93, 0x1a, 0x3c, 0x2d, 0xd1, 0x01, 0x71, 0x4c, 0x95, 0xdc, 0x1b, 0xa9, 0x35, 0x01, 0x51, 0xba, 0xf4, 0xa4, 0x65, 0xe9, 0x5e, 0x0c, 0x12, 0x3b, 0x89, 0xa5, 0xc8, 0x5b, 0xd3, 0x89, 0x4a, 0xf7, 0xa7, 0xbc, 0xa7, 0x3e, 0x1f, 0x34, 0xbc, 0xc6, 0x16, 0x82, 0xeb, 0xf4, 0x99, 0x1e, 0xb8, 0x9e, 0xea, 0xd5, 0xae, 0x6a, 0x69, 0xbf, 0xec, 0x51, 0xcf, 0xc8, 0xe8, 0x9c, 0xad, 0x17, 0x06, 0x40, 0xe4, 0x5f, 0x22, 0x58, 0x56, 0x5b, 0x55, 0x42, 0xf1, 0x2b, 0x71, 0xe1, 0x82, 0xce, 0x7a, 0xd7, 0x83, 0x15, 0xe8, 0x3d, 0x68, 0x58, 0x41, 0x7c, 0xab, 0x73, 0x5d, 0x65, 0x58, 0x73, 0x60, 0xc9, 0xdf, 0x5c, 0x85, 0xef, 0x3c, 0x30, 0x2c, 0xb9, 0x72, 0xc3, 0xb1, 0xc9, 0x7f, 0xf1, 0x34, 0x7f, 0x08, 0x44, 0x2f, 0x16, 0x1a, 0x77, 0x85, 0x34, 0x79, 0x34, 0x55, 0xf1, 0xab, 0xbd, 0xe2, 0x8a, 0xb5, 0x3b, 0x60, 0xa2, 0xf1, 0x30, 0x72, 0x80, 0xf8, 0x9b, 0xd7, 0xb1, 0x7f, 0xe5, 0x44, 0x32, 0xf4, 0x54, 0xb5, 0x0e, 0x42, 0x7a, 0xc7, 0x8b, 0x54, 0x44, 0x67, 0x16, 0x96, 0x44, 0x6f, 0x3d, 0x92, 0x12, 0xf8, 0x32, 0x48, 0x7f, 0x7c, 0x7e, 0xd0, 0x66, 0xcb, 0xfa, 0x48, 0xa7, 0x00, 0x28, 0xb1, 0xd7, 0xb5, 0x1a, 0x0c, 0x53, 0x1a, 0x25, 0x72, 0x9d, 0x49, 0x06, 0xa3, 0x3f, 0x27, 0x04, 0xac, 0x11, 0x86, 0xff, 0x54, 0x86, 0x3b, 0xe9, 0x46, 0x7e, 0x40, 0xcb, 0xe1, 0xb0, 0x02, 0xaf, 0xf7, 0x28, 0x25, 0x42, 0xad, 0xb5, 0x96, 0x52, 0x4e, 0x8b, 0x9c, 0xee, 0x57, 0x47, 0x5c, 0x80, 0x55, 0xf8, 0xa2, 0x7e, 0xe7, 0x16, 0x95, 0x75, 0x42, 0x9e, 0x10, 0xf3, 0x24, 0xb4, 0x69, 0x9a, 0xcd, 0xb0, 0x34, 0x6e, 0x62, 0x54, 0xa1, 0x3b, 0x78, 0xde, 0xf7, 0xb0, 0xda, 0xcb, 0x2c, 0xd9, 0x07, 0x82, 0x55, 0x72, 0xc6, 0x27, 0x67, 0x19, 0x34, 0xe1, 0x0b, 0x39, 0xb5, 0xba, 0xf8, 0xe7, 0x5b, 0x3d, 0xc8, 0x0c, 0x22, 0xc5, 0x04, 0xa2, 0x62, 0x56, 0x24, 0xea, 0x7c, 0xb8, 0xec, 0x28, 0x34, 0xd7, 0xc2, 0x65, 0x89, 0x95, 0xfe, 0xdc, 0x41, 0xff, 0xe6, 0xbf, 0x7d, 0x17, 0x99, 0xb4, 0xc3, 0x1b, 0x64, 0x64, 0x2d, 0x77, 0x22, 0xb6, 0xa5, 0x69, 0x5b, 0xc7, 0xc5, 0xbf, 0x77, 0x84, 0x1e, 0x1f, 0xb6, 0x72, 0x0a, 0xfb, 0xca, 0x14, 0xc4, 0x89, 0x51, 0xc8, 0xa8, 0xf2, 0x40, 0xa1, 0x66, 0x93, 0x2c, 0x37, 0x60, 0x1d, 0x9c, 0xda, 0xc9, 0xa5, 0x20, 0x60, 0xa2, 0xc5, 0xb6, 0x5d, 0x59, 0x30, 0x35, 0xbc, 0xce, 0xec, 0xd7, 0x43, 0xcf, 0x75, 0x88, 0xf1, 0x02, 0xad, 0x30, 0x64, 0x19, 0x0b, 0xea, 0xa9, 0xbd, 0x3b, 0x55, 0xc5, 0xd4, 0x16, 0x58, 0xf1, 0x78, 0x79, 0xf2, 0xaa, 0x88, 0x52, 0x40, 0x41, 0xb5, 0x64, 0xae, 0x27, 0x1a, 0xbb, 0x21, 0x75, 0xe8, 0xa7, 0x75, 0x75, 0x90, 0x52, 0xe1, 0xfc, 0x3d, 0x21, 0x86, 0x35, 0x68, 0x5a, 0x77, 0xb1, 0x60, 0xcb, 0xa6, 0x82, 0x6a, 0xa5, 0xcb, 0x18, 0xf7, 0x36, 0xa2, 0xfd, 0x15, 0x2a, 0xe6, 0xb1, 0xa6, 0x29, 0x8c, 0xa4, 0x8d, 0xf5, 0x11, 0x84, 0xf7, 0xa7, 0x0c, 0x71, 0x0f, 0x3e, 0xea, 0x0c, 0xd0, 0x7b, 0x40, 0xdc, 0x60, 0x09, 0x19, 0x26, 0x06, 0x27, 0x75, 0x14, 0xe8, 0x06, 0x42, 0x02, 0x06, 0x27, 0xed, 0x12, 0x0f, 0xbf, 0xd3, 0x90, 0x99, 0x59, 0x4b, 0xfc, 0x80, 0x39, 0xa8, 0x9b, 0x9d, 0xa4, 0xd5, 0xae, 0xd6, 0x59, 0x30, 0xf5, 0x09, 0x50, 0xa3, 0xd3, 0x0e, 0x63, 0xe5, 0xa8, 0xd8, 0x86, 0xb2, 0x82, 0x26, 0xa6, 0xc7, 0x13, 0x8c, 0x44, 0x8c, 0x63, 0x3c, 0x30, 0x2f, 0x31, 0x1b, 0x35, 0x3c, 0x2c, 0x3d, 0x76, 0x88, 0xca, 0x50, 0x12, 0x2d, 0x49, 0x20, 0x5c, 0x2a, 0x61, 0x43, 0xd9, 0x91, 0xa9, 0xea, 0x19, 0xa0, 0x5d, 0x01, 0x7d, 0x5d, 0x88, 0x6b, 0xde, 0x34, 0x41, 0x84, 0x40, 0xc5, 0xf4, 0x61, 0x33, 0x24, 0xf1, 0xc3, 0x47, 0x22, 0x62, 0xc7, 0xea, 0xca, 0xda, 0x62, 0x97, 0xfa, 0x57, 0x9f, 0x80, 0xa4, 0xb6, 0xdc, 0x53, 0x3f, 0x53, 0x40, 0x36, 0xd4, 0x21, 0x39, 0x65, 0xbc, 0x86, 0xc6, 0x29, 0xbd, 0xee, 0x19, 0x1b, 0xbb, 0x66, 0x52, 0xcb, 0x1b, 0xc9, 0x79, 0x46, 0x03, 0x7e, 0x98, 0x71, 0x10, 0xac, 0x5a, 0x97, 0xf7, 0x75, 0x02, 0x70, 0x34, 0xc9, 0x8a, 0x00, 0x09, 0x06, 0x04, 0x17, 0x4b, 0x6c, 0x47, 0xaa, 0xb5, 0x09, 0x53, 0x3c, 0xa1, 0x99, 0x3a, 0x75, 0x11, 0x93, 0x96, 0x30, 0x4c, 0x8c, 0x47, 0x55, 0xa9, 0x7b, 0x59, 0x00, 0xad, 0xb4, 0x48, 0xd1, 0x2e, 0xeb, 0x78, 0xa6, 0xb0, 0x6a, 0xc6, 0x3b, 0x39, 0x50, 0x7d, 0x8c, 0x04, 0x92, 0xfc, 0xb4, 0xd1, 0xe4, 0x1f, 0xf1, 0x45, 0x27, 0x3c, 0x93, 0x58, 0x86, 0x96, 0x2d, 0x50, 0x43, 0x87, 0x71, 0x1a, 0x1c, 0xe3, 0xf1, 0xac, 0xf7, 0xa7, 0xb2, 0xfa, 0x56, 0x0d, 0x15, 0x09, 0x32, 0x69, 0xe7, 0x31, 0x0c, 0xc3, 0x0d, 0x71, 0xa9, 0xc9, 0x1c, 0xbc, 0xbc, 0xf3, 0x15, 0x2d, 0xe4, 0xb0, 0xbd, 0xdb, 0xec, 0x67, 0x23, 0x64, 0xc0, 0x1a, 0xd4, 0x3d, 0x81, 0x58, 0x80, 0x01, 0x45, 0x72, 0xa8, 0x81, 0x0c, 0x8a, 0x85, 0xb5, 0x4e, 0x96, 0xc8, 0x42, 0xa8, 0x05, 0xdb, 0x2a, 0x61, 0x6d, 0x0b, 0x82, 0xf6, 0xf2, 0xbc, 0x00, 0xcc, 0x94, 0x9c, 0xbc, 0x01, 0x52, 0x9b, 0x03, 0x73, 0x14, 0x01, 0x80, 0x3b, 0xa1, 0x95, 0x35, 0xca, 0xc5, 0xb6, 0x82, 0x7b, 0xfb, 0xb6, 0x0b, 0x8b, 0xa8, 0x96, 0xeb, 0x45, 0xbd, 0xf2, 0x06, 0xdc, 0x7b, 0x10, 0xdc, 0xe2, 0x6a, 0xe2, 0x09, 0x1f, 0xc8, 0x85, 0xbc, 0xb5, 0xb5, 0xa2, 0x5a, 0xf6, 0x54, 0x71, 0x27, 0x84, 0xf3, 0xac, 0xc3, 0xd7, 0x09, 0x7a, 0xf0, 0x77, 0x3e, 0xb5, 0x20, 0x68, 0xd8, 0x75, 0x74, 0xf9, 0x97, 0xa6, 0x2d, 0xdb, 0xca, 0xf8, 0xe0, 0xcf, 0x79, 0x3b, 0x74, 0xb1, 0x84, 0x28, 0x82, 0x31, 0x22, 0xf5, 0x99, 0x5d, 0x8b, 0x50, 0x5a, 0x7e, 0xb7, 0x92, 0x53, 0x89, 0x09, 0x6c, 0xbb, 0xcd, 0xb8, 0xb9, 0xcd, 0xa2, 0xa9, 0xa2, 0x48, 0xc3, 0x1d, 0x1c, 0xb1, 0xb5, 0x7b, 0x86, 0x63, 0x55, 0x53, 0x34, 0x37, 0xb9, 0xc3, 0xbf, 0xc3, 0x06, 0x6d, 0x09, 0x3c, 0x4b, 0xc8, 0xcf, 0xa1, 0x32, 0xcf, 0x0e, 0xb4, 0xb6, 0xbb, 0xb9, 0x40, 0x6b, 0x24, 0x43, 0xad, 0x13, 0x49, 0x0b, 0x32, 0xb5, 0xd1, 0xa7, 0x18, 0x13, 0x3b, 0x20, 0x60, 0x77, 0x8c, 0x9e, 0x03, 0x83, 0x50, 0xa1, 0xc0, 0x62, 0x24, 0x4c, 0x55, 0x2a, 0x33, 0xa9, 0x0a, 0x16, 0x53, 0xa1, 0x82, 0x5f, 0xec, 0xc9, 0xbf, 0xe1, 0xc7, 0x15, 0x16, 0x4b, 0xd4, 0x91, 0x94, 0x0c, 0x92, 0xb1, 0x62, 0x24, 0x57, 0x4d, 0x66, 0x98, 0x11, 0xe8, 0x1a, 0x9b, 0x44, 0x89, 0xd2, 0xf3, 0xbd, 0x97, 0x55, 0x55, 0x5f, 0x5b, 0x06, 0x07, 0xd8, 0x11, 0x49, 0xe1, 0x82, 0x5e, 0x51, 0x71, 0x3b, 0x78, 0x6c, 0x05, 0xe9, 0x28, 0x7f, 0xb5, 0xa2, 0x13, 0x75, 0x7a, 0xde, 0x22, 0x1b, 0x14, 0x77, 0x42, 0x9e, 0x9b, 0x9b, 0xe2, 0xb6, 0xc8, 0xb6, 0xa1, 0x66, 0x81, 0xa9, 0x5c, 0xa0, 0x43, 0xbb, 0xad, 0xe1, 0x7b, 0xbd, 0x7c, 0xa7, 0xb9, 0xf7, 0x07, 0x2c, 0xf1, 0x2c, 0x29, 0xf4, 0x59, 0xe0, 0x91, 0x62, 0x44, 0xca, 0x90, 0xb1, 0x4b, 0xb1, 0xae, 0xd1, 0xc8, 0xed, 0x35, 0x01, 0x68, 0xcc, 0x9b, 0xf8, 0x86, 0x22, 0xb8, 0x92, 0xc3, 0xb5, 0xf6, 0xc1, 0xed, 0xfa, 0x4e, 0x91, 0xd6, 0x92, 0xe2, 0x26, 0x0c, 0x40, 0xa7, 0xac, 0xed, 0x65, 0x12, 0xd4, 0x61, 0x1a, 0x00, 0xf0, 0x8d, 0xa7, 0x3c, 0x12, 0xec, 0x07, 0x50, 0x3b, 0xf8, 0xca, 0x5e, 0xa1, 0xb0, 0xed, 0xb8, 0x5b, 0x93, 0x01, 0x07, 0x26, 0x62, 0x60, 0x1b, 0xba, 0x88, 0xb6, 0xe7, 0xc3, 0x63, 0x97, 0x06, 0x66, 0xe2, 0x6e, 0x4d, 0x55, 0x60, 0x91, 0xa6, 0x8a, 0x44, 0x58, 0x28, 0xc6, 0x0b, 0xbf, 0x53, 0xd3, 0x38, 0x2b, 0x7c, 0x88, 0xe8, 0x6c, 0x44, 0x6f, 0xb5, 0xa4, 0x13, 0x6c, 0x79, 0x1c, 0xcb, 0x5d, 0xd7, 0x97, 0xc0, 0x68, 0xc2, 0xb0, 0x77, 0xc1, 0x5a, 0x51, 0xcb, 0x31, 0x8f, 0xa3, 0xa2, 0x23, 0xe5, 0x83, 0x12, 0x91, 0xc5, 0x03, 0x67, 0xb8, 0x8a, 0x32, 0x91, 0x0f, 0xca, 0x7a, 0x13, 0x00, 0x7d, 0x74, 0x01, 0x95, 0x0a, 0xaa, 0x2d, 0x42, 0x90, 0x9d, 0xed, 0xdb, 0x27, 0x47, 0xec, 0xb1, 0x87, 0x33, 0x62, 0x9e, 0x81, 0x10, 0xc7, 0x2b, 0x52, 0x65, 0xe3, 0xb2, 0xe8, 0x63, 0x71, 0x29, 0xe6, 0x28, 0x6f, 0xba, 0xb3, 0x0f, 0xd1, 0x50, 0xef, 0x66, 0xb5, 0x1c, 0x37, 0x28, 0x2a, 0x54, 0x88, 0x80, 0x78, 0x2d, 0xad, 0xbb, 0x73, 0x62, 0xfc, 0xa6, 0xb5, 0xc0, 0x87, 0x81, 0xe6, 0x9e, 0x82, 0xcc, 0xb5, 0x0e, 0x0a, 0x0c, 0xaf, 0xd0, 0x9c, 0xbf, 0x47, 0x80, 0x52, 0xa0, 0x30, 0x83, 0x28, 0xcb, 0x6a, 0xa1, 0xa2, 0x46, 0xf3, 0x34, 0x71, 0xc4, 0xb9, 0x39, 0xbc, 0x80, 0x8a, 0x97, 0x39, 0xa0, 0x09, 0x9e, 0x00, 0xb9, 0x68, 0xb4, 0xc2, 0x3f, 0x6d, 0x42, 0x09, 0x63, 0x26, 0xc4, 0x74, 0x5c, 0x57, 0x55, 0xd8, 0x1e, 0x0a, 0x39, 0xb7, 0xfe, 0x34, 0x49, 0x7b, 0x5b, 0xa2, 0xde, 0xaa, 0x10, 0xed, 0x60, 0x1e, 0x46, 0x28, 0x8d, 0xa4, 0x5a, 0xad, 0x8e, 0x63, 0x57, 0x37, 0xf0, 0x8c, 0xd4, 0x06, 0x2d, 0x2e, 0x66, 0x18, 0x69, 0xc5, 0x4c, 0xdb, 0xdb, 0xb2, 0xe0, 0x8b, 0x5b, 0x40, 0x4b, 0x18, 0x85, 0x71, 0xc8, 0x54, 0x84, 0xa9, 0xa2, 0xb3, 0x6f, 0x8b, 0xea, 0x7f, 0x4c, 0x2b, 0x6a, 0x78, 0xd9, 0x8d, 0x1d, 0x87, 0x25, 0x6e, 0xba, 0x06, 0xd0, 0x7a, 0x90, 0x4b, 0x57, 0x39, 0xf1, 0x16, 0x93, 0xfd, 0xc9, 0x35, 0x52, 0x76, 0x9f, 0xfd, 0x76, 0x87, 0x9a, 0xd3, 0x04, 0xbf, 0xb4, 0x0b, 0x37, 0x41, 0x29, 0x91, 0x0b, 0x1d, 0xf0, 0x60, 0x33, 0xde, 0x44, 0xab, 0x22, 0xa2, 0xce, 0xfa, 0x6a, 0xc0, 0x06, 0x04, 0xb0, 0x9e, 0x7a, 0x4c, 0x35, 0xdb, 0x26, 0x42, 0xd3, 0xaf, 0xd2, 0x01, 0xa3, 0xa9, 0xc4, 0xb8, 0x6f, 0x88, 0x15, 0xee, 0x23, 0x97, 0x02, 0x12, 0xc4, 0x8a, 0xab, 0x76, 0x5f, 0x31, 0x2e, 0xe2, 0xe9, 0x9b, 0x7d, 0x10, 0x6c, 0x9a, 0x70, 0xb6, 0x7b, 0xe5, 0x08, 0x13, 0x5a, 0x39, 0x0b, 0xcc, 0x65, 0x60, 0x02, 0xbd, 0x1c, 0x36, 0x0e, 0x27, 0xf2, 0x0d, 0xf8, 0x58, 0xbd, 0x3b, 0x5a, 0x62, 0x78, 0xa8, 0x95, 0xe5, 0xbc, 0x84, 0x7f, 0x72, 0x6f, 0x78, 0x67, 0x77, 0x8c, 0x71, 0x57, 0x1f, 0xcb, 0x2b, 0x82, 0x61, 0xa4, 0x6b, 0xf9, 0x60, 0x9f, 0x4b, 0x8d, 0x2a, 0x34, 0x93, 0x1d, 0x45, 0x84, 0x6a, 0xe4, 0xb6, 0x0d, 0x72, 0x6d, 0x2b, 0xc7, 0x72, 0x45, 0xb2, 0x2c, 0xe9, 0x8c, 0xac, 0x81, 0xa6, 0x18, 0xd2, 0xc7, 0xaa, 0x1e, 0x77, 0x76, 0xda, 0x27, 0x49, 0x02, 0xb5, 0x2e, 0x53, 0x25, 0xbb, 0x39, 0x06, 0x17, 0x4c, 0x87, 0x72, 0x85, 0x85, 0x10, 0xa3, 0x60, 0x4a, 0xe8, 0x9b, 0x69, 0x97, 0xab, 0x1e, 0x26, 0x67, 0x45, 0x98, 0xd8, 0x23, 0x6e, 0x6c, 0xb1, 0x18, 0x5b, 0x72, 0xfc, 0xd9, 0x25, 0x7d, 0x56, 0x73, 0xfb, 0x06, 0x1a, 0x37, 0x94, 0x19, 0x36, 0xc5, 0x43, 0xff, 0x37, 0x0c, 0x1d, 0xa3, 0xb1, 0xeb, 0xfc, 0x09, 0x94, 0xfa, 0x0e, 0x3d, 0xd6, 0x06, 0x2a, 0x8c, 0x9c, 0xa3, 0x75, 0x20, 0xd9, 0x53, 0x91, 0xd7, 0xeb, 0x47, 0xea, 0xe2, 0x50, 0x91, 0xfb, 0x42, 0x36, 0x94, 0x53, 0x0a, 0x05, 0xbc, 0xcb, 0x28, 0xb9, 0x54, 0xe7, 0x55, 0xd9, 0x28, 0x94, 0x02, 0x1b, 0x1d, 0x04, 0x10, 0xaf, 0x78, 0xc9, 0x0b, 0xc0, 0x02, 0xb6, 0x65, 0x29, 0x13, 0x32, 0x02, 0x3d, 0x76, 0x67, 0xab, 0x15, 0x07, 0xc8, 0x08, 0xfc, 0x73, 0x1d, 0x02, 0xb4, 0x1c, 0x73, 0x40, 0xe4, 0x51, 0x33, 0xe0, 0x30, 0x60, 0x5a, 0x91, 0x5e, 0x7c, 0x73, 0x07, 0xa4, 0x76, 0x60, 0x1c, 0xc9, 0x24, 0x19, 0x52, 0x6c, 0xaa, 0x14, 0xa7, 0x81, 0xa0, 0x76, 0xe0, 0xac, 0x1f, 0x5b, 0xe0, 0x70, 0x1b, 0xcb, 0xad, 0xe6, 0x28, 0x6e, 0x95, 0x62, 0xc7, 0x70, 0x84, 0x1a, 0x9c, 0x45, 0xa1, 0xd6, 0x60, 0x88, 0x22, 0xf2, 0x99, 0xd4, 0x92, 0x9f, 0xfe, 0x66, 0x1e, 0x89, 0xc0, 0xb7, 0x97, 0xf5, 0x9d, 0xd3, 0x94, 0xa3, 0x13, 0x75, 0x9f, 0x6b, 0x73, 0xb7, 0xac, 0x9c, 0x36, 0x27, 0xa4, 0x9b, 0x31, 0xb2, 0xc5, 0xf3, 0x7a, 0x68, 0x63, 0x26, 0x31, 0x25, 0x4a, 0x94, 0xa4, 0x71, 0x68, 0x94, 0x92, 0x6f, 0xbf, 0x90, 0xb4, 0x0b, 0x6c, 0x18, 0x53, 0xd9, 0x1f, 0x04, 0x09, 0x4a, 0x7f, 0xa5, 0x89, 0xd4, 0x10, 0xbd, 0x67, 0xe4, 0x35, 0xff, 0xe2, 0x9d, 0x07, 0x98, 0xc3, 0xae, 0x92, 0xca, 0x6d, 0x28, 0x78, 0x2a, 0x56, 0x2d, 0x19, 0x11, 0xb1, 0x59, 0x94, 0xb0, 0x99, 0xf0, 0x88, 0x39, 0xd8, 0xb4, 0x4b, 0x70, 0xc5, 0xde, 0xa7, 0x78, 0x46, 0x80, 0x5b, 0xf5, 0x57, 0x07, 0x26, 0x30, 0x7d, 0x64, 0xac, 0xbf, 0x5a, 0x86, 0x81, 0x9f, 0x71, 0x5e, 0xa0, 0x7b, 0x5b, 0x1b, 0x14, 0x09, 0x9c, 0xd7, 0x07, 0xc3, 0xc9, 0x15, 0xb4, 0x79, 0x9a, 0xc2, 0x81, 0x46, 0xc6, 0xc3, 0xad, 0x6b, 0x4a, 0x75, 0xa3, 0x5a, 0x51, 0xaa, 0x6c, 0x36, 0x1c, 0xe4, 0x6d, 0xec, 0x82, 0x75, 0x35, 0x69, 0x47, 0xef, 0x69, 0x18, 0xd6, 0x30, 0x85, 0xa5, 0x27, 0x5d, 0xee, 0x02, 0xa1, 0x72, 0x14, 0x48, 0xe9, 0xc1, 0x0e, 0x1a, 0x32, 0x6c, 0x0a, 0x38, 0x26, 0x49, 0x91, 0x2a, 0x36, 0xf3, 0x95, 0xa4, 0x68, 0x3c, 0xbe, 0xb2, 0x82, 0x50, 0xf5, 0x87, 0x06, 0xc2, 0x9c, 0x36, 0x0a, 0x24, 0x82, 0x81, 0x4f, 0x09, 0x5a, 0x6c, 0x90, 0xe5, 0x60, 0x0d, 0x9f, 0xbb, 0x1e, 0xaa, 0xc2, 0x3f, 0x15, 0x5e, 0xce, 0x53, 0x0e, 0xe2, 0xc7, 0x5b, 0xe8, 0x45, 0x9c, 0x89, 0xe4, 0x8c, 0x1f, 0x29, 0x25, 0x25, 0xe7, 0x6e, 0xc4, 0xb6, 0x83, 0x89, 0x25, 0x6e, 0x81, 0x5b, 0x36, 0xa2, 0x01, 0x93, 0x11, 0x53, 0x6e, 0x27, 0xb8, 0x25, 0xa6, 0x1c, 0xc1, 0x37, 0x00, 0xb7, 0x01, 0xf3, 0xae, 0xa2, 0x06, 0x89, 0x6b, 0xd5, 0xbd, 0xba, 0x5e, 0x2b, 0xec, 0x48, 0xc1, 0xe7, 0x78, 0xf3, 0x36, 0x6d, 0xb8, 0x80, 0x3e, 0xbe, 0x81, 0xf9, 0x53, 0xfd, 0x6e, 0xab, 0x6a, 0x8f, 0xc8, 0xd4, 0x1c, 0x09, 0xcf, 0x59, 0x62, 0x3b, 0x54, 0x03, 0x2b, 0x0d, 0xb0 }, .pkcs8_len = 2428, .spki = { 0x30, 0x82, 0x04, 0xb2, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x04, 0x02, 0x03, 0x82, 0x04, 0xa1, 0x00, 0x80, 0x3b, 0xa1, 0x95, 0x35, 0xca, 0xc5, 0xb6, 0x82, 0x7b, 0xfb, 0xb6, 0x0b, 0x8b, 0xa8, 0x96, 0xeb, 0x45, 0xbd, 0xf2, 0x06, 0xdc, 0x7b, 0x10, 0xdc, 0xe2, 0x6a, 0xe2, 0x09, 0x1f, 0xc8, 0x85, 0xbc, 0xb5, 0xb5, 0xa2, 0x5a, 0xf6, 0x54, 0x71, 0x27, 0x84, 0xf3, 0xac, 0xc3, 0xd7, 0x09, 0x7a, 0xf0, 0x77, 0x3e, 0xb5, 0x20, 0x68, 0xd8, 0x75, 0x74, 0xf9, 0x97, 0xa6, 0x2d, 0xdb, 0xca, 0xf8, 0xe0, 0xcf, 0x79, 0x3b, 0x74, 0xb1, 0x84, 0x28, 0x82, 0x31, 0x22, 0xf5, 0x99, 0x5d, 0x8b, 0x50, 0x5a, 0x7e, 0xb7, 0x92, 0x53, 0x89, 0x09, 0x6c, 0xbb, 0xcd, 0xb8, 0xb9, 0xcd, 0xa2, 0xa9, 0xa2, 0x48, 0xc3, 0x1d, 0x1c, 0xb1, 0xb5, 0x7b, 0x86, 0x63, 0x55, 0x53, 0x34, 0x37, 0xb9, 0xc3, 0xbf, 0xc3, 0x06, 0x6d, 0x09, 0x3c, 0x4b, 0xc8, 0xcf, 0xa1, 0x32, 0xcf, 0x0e, 0xb4, 0xb6, 0xbb, 0xb9, 0x40, 0x6b, 0x24, 0x43, 0xad, 0x13, 0x49, 0x0b, 0x32, 0xb5, 0xd1, 0xa7, 0x18, 0x13, 0x3b, 0x20, 0x60, 0x77, 0x8c, 0x9e, 0x03, 0x83, 0x50, 0xa1, 0xc0, 0x62, 0x24, 0x4c, 0x55, 0x2a, 0x33, 0xa9, 0x0a, 0x16, 0x53, 0xa1, 0x82, 0x5f, 0xec, 0xc9, 0xbf, 0xe1, 0xc7, 0x15, 0x16, 0x4b, 0xd4, 0x91, 0x94, 0x0c, 0x92, 0xb1, 0x62, 0x24, 0x57, 0x4d, 0x66, 0x98, 0x11, 0xe8, 0x1a, 0x9b, 0x44, 0x89, 0xd2, 0xf3, 0xbd, 0x97, 0x55, 0x55, 0x5f, 0x5b, 0x06, 0x07, 0xd8, 0x11, 0x49, 0xe1, 0x82, 0x5e, 0x51, 0x71, 0x3b, 0x78, 0x6c, 0x05, 0xe9, 0x28, 0x7f, 0xb5, 0xa2, 0x13, 0x75, 0x7a, 0xde, 0x22, 0x1b, 0x14, 0x77, 0x42, 0x9e, 0x9b, 0x9b, 0xe2, 0xb6, 0xc8, 0xb6, 0xa1, 0x66, 0x81, 0xa9, 0x5c, 0xa0, 0x43, 0xbb, 0xad, 0xe1, 0x7b, 0xbd, 0x7c, 0xa7, 0xb9, 0xf7, 0x07, 0x2c, 0xf1, 0x2c, 0x29, 0xf4, 0x59, 0xe0, 0x91, 0x62, 0x44, 0xca, 0x90, 0xb1, 0x4b, 0xb1, 0xae, 0xd1, 0xc8, 0xed, 0x35, 0x01, 0x68, 0xcc, 0x9b, 0xf8, 0x86, 0x22, 0xb8, 0x92, 0xc3, 0xb5, 0xf6, 0xc1, 0xed, 0xfa, 0x4e, 0x91, 0xd6, 0x92, 0xe2, 0x26, 0x0c, 0x40, 0xa7, 0xac, 0xed, 0x65, 0x12, 0xd4, 0x61, 0x1a, 0x00, 0xf0, 0x8d, 0xa7, 0x3c, 0x12, 0xec, 0x07, 0x50, 0x3b, 0xf8, 0xca, 0x5e, 0xa1, 0xb0, 0xed, 0xb8, 0x5b, 0x93, 0x01, 0x07, 0x26, 0x62, 0x60, 0x1b, 0xba, 0x88, 0xb6, 0xe7, 0xc3, 0x63, 0x97, 0x06, 0x66, 0xe2, 0x6e, 0x4d, 0x55, 0x60, 0x91, 0xa6, 0x8a, 0x44, 0x58, 0x28, 0xc6, 0x0b, 0xbf, 0x53, 0xd3, 0x38, 0x2b, 0x7c, 0x88, 0xe8, 0x6c, 0x44, 0x6f, 0xb5, 0xa4, 0x13, 0x6c, 0x79, 0x1c, 0xcb, 0x5d, 0xd7, 0x97, 0xc0, 0x68, 0xc2, 0xb0, 0x77, 0xc1, 0x5a, 0x51, 0xcb, 0x31, 0x8f, 0xa3, 0xa2, 0x23, 0xe5, 0x83, 0x12, 0x91, 0xc5, 0x03, 0x67, 0xb8, 0x8a, 0x32, 0x91, 0x0f, 0xca, 0x7a, 0x13, 0x00, 0x7d, 0x74, 0x01, 0x95, 0x0a, 0xaa, 0x2d, 0x42, 0x90, 0x9d, 0xed, 0xdb, 0x27, 0x47, 0xec, 0xb1, 0x87, 0x33, 0x62, 0x9e, 0x81, 0x10, 0xc7, 0x2b, 0x52, 0x65, 0xe3, 0xb2, 0xe8, 0x63, 0x71, 0x29, 0xe6, 0x28, 0x6f, 0xba, 0xb3, 0x0f, 0xd1, 0x50, 0xef, 0x66, 0xb5, 0x1c, 0x37, 0x28, 0x2a, 0x54, 0x88, 0x80, 0x78, 0x2d, 0xad, 0xbb, 0x73, 0x62, 0xfc, 0xa6, 0xb5, 0xc0, 0x87, 0x81, 0xe6, 0x9e, 0x82, 0xcc, 0xb5, 0x0e, 0x0a, 0x0c, 0xaf, 0xd0, 0x9c, 0xbf, 0x47, 0x80, 0x52, 0xa0, 0x30, 0x83, 0x28, 0xcb, 0x6a, 0xa1, 0xa2, 0x46, 0xf3, 0x34, 0x71, 0xc4, 0xb9, 0x39, 0xbc, 0x80, 0x8a, 0x97, 0x39, 0xa0, 0x09, 0x9e, 0x00, 0xb9, 0x68, 0xb4, 0xc2, 0x3f, 0x6d, 0x42, 0x09, 0x63, 0x26, 0xc4, 0x74, 0x5c, 0x57, 0x55, 0xd8, 0x1e, 0x0a, 0x39, 0xb7, 0xfe, 0x34, 0x49, 0x7b, 0x5b, 0xa2, 0xde, 0xaa, 0x10, 0xed, 0x60, 0x1e, 0x46, 0x28, 0x8d, 0xa4, 0x5a, 0xad, 0x8e, 0x63, 0x57, 0x37, 0xf0, 0x8c, 0xd4, 0x06, 0x2d, 0x2e, 0x66, 0x18, 0x69, 0xc5, 0x4c, 0xdb, 0xdb, 0xb2, 0xe0, 0x8b, 0x5b, 0x40, 0x4b, 0x18, 0x85, 0x71, 0xc8, 0x54, 0x84, 0xa9, 0xa2, 0xb3, 0x6f, 0x8b, 0xea, 0x7f, 0x4c, 0x2b, 0x6a, 0x78, 0xd9, 0x8d, 0x1d, 0x87, 0x25, 0x6e, 0xba, 0x06, 0xd0, 0x7a, 0x90, 0x4b, 0x57, 0x39, 0xf1, 0x16, 0x93, 0xfd, 0xc9, 0x35, 0x52, 0x76, 0x9f, 0xfd, 0x76, 0x87, 0x9a, 0xd3, 0x04, 0xbf, 0xb4, 0x0b, 0x37, 0x41, 0x29, 0x91, 0x0b, 0x1d, 0xf0, 0x60, 0x33, 0xde, 0x44, 0xab, 0x22, 0xa2, 0xce, 0xfa, 0x6a, 0xc0, 0x06, 0x04, 0xb0, 0x9e, 0x7a, 0x4c, 0x35, 0xdb, 0x26, 0x42, 0xd3, 0xaf, 0xd2, 0x01, 0xa3, 0xa9, 0xc4, 0xb8, 0x6f, 0x88, 0x15, 0xee, 0x23, 0x97, 0x02, 0x12, 0xc4, 0x8a, 0xab, 0x76, 0x5f, 0x31, 0x2e, 0xe2, 0xe9, 0x9b, 0x7d, 0x10, 0x6c, 0x9a, 0x70, 0xb6, 0x7b, 0xe5, 0x08, 0x13, 0x5a, 0x39, 0x0b, 0xcc, 0x65, 0x60, 0x02, 0xbd, 0x1c, 0x36, 0x0e, 0x27, 0xf2, 0x0d, 0xf8, 0x58, 0xbd, 0x3b, 0x5a, 0x62, 0x78, 0xa8, 0x95, 0xe5, 0xbc, 0x84, 0x7f, 0x72, 0x6f, 0x78, 0x67, 0x77, 0x8c, 0x71, 0x57, 0x1f, 0xcb, 0x2b, 0x82, 0x61, 0xa4, 0x6b, 0xf9, 0x60, 0x9f, 0x4b, 0x8d, 0x2a, 0x34, 0x93, 0x1d, 0x45, 0x84, 0x6a, 0xe4, 0xb6, 0x0d, 0x72, 0x6d, 0x2b, 0xc7, 0x72, 0x45, 0xb2, 0x2c, 0xe9, 0x8c, 0xac, 0x81, 0xa6, 0x18, 0xd2, 0xc7, 0xaa, 0x1e, 0x77, 0x76, 0xda, 0x27, 0x49, 0x02, 0xb5, 0x2e, 0x53, 0x25, 0xbb, 0x39, 0x06, 0x17, 0x4c, 0x87, 0x72, 0x85, 0x85, 0x10, 0xa3, 0x60, 0x4a, 0xe8, 0x9b, 0x69, 0x97, 0xab, 0x1e, 0x26, 0x67, 0x45, 0x98, 0xd8, 0x23, 0x6e, 0x6c, 0xb1, 0x18, 0x5b, 0x72, 0xfc, 0xd9, 0x25, 0x7d, 0x56, 0x73, 0xfb, 0x06, 0x1a, 0x37, 0x94, 0x19, 0x36, 0xc5, 0x43, 0xff, 0x37, 0x0c, 0x1d, 0xa3, 0xb1, 0xeb, 0xfc, 0x09, 0x94, 0xfa, 0x0e, 0x3d, 0xd6, 0x06, 0x2a, 0x8c, 0x9c, 0xa3, 0x75, 0x20, 0xd9, 0x53, 0x91, 0xd7, 0xeb, 0x47, 0xea, 0xe2, 0x50, 0x91, 0xfb, 0x42, 0x36, 0x94, 0x53, 0x0a, 0x05, 0xbc, 0xcb, 0x28, 0xb9, 0x54, 0xe7, 0x55, 0xd9, 0x28, 0x94, 0x02, 0x1b, 0x1d, 0x04, 0x10, 0xaf, 0x78, 0xc9, 0x0b, 0xc0, 0x02, 0xb6, 0x65, 0x29, 0x13, 0x32, 0x02, 0x3d, 0x76, 0x67, 0xab, 0x15, 0x07, 0xc8, 0x08, 0xfc, 0x73, 0x1d, 0x02, 0xb4, 0x1c, 0x73, 0x40, 0xe4, 0x51, 0x33, 0xe0, 0x30, 0x60, 0x5a, 0x91, 0x5e, 0x7c, 0x73, 0x07, 0xa4, 0x76, 0x60, 0x1c, 0xc9, 0x24, 0x19, 0x52, 0x6c, 0xaa, 0x14, 0xa7, 0x81, 0xa0, 0x76, 0xe0, 0xac, 0x1f, 0x5b, 0xe0, 0x70, 0x1b, 0xcb, 0xad, 0xe6, 0x28, 0x6e, 0x95, 0x62, 0xc7, 0x70, 0x84, 0x1a, 0x9c, 0x45, 0xa1, 0xd6, 0x60, 0x88, 0x22, 0xf2, 0x99, 0xd4, 0x92, 0x9f, 0xfe, 0x66, 0x1e, 0x89, 0xc0, 0xb7, 0x97, 0xf5, 0x9d, 0xd3, 0x94, 0xa3, 0x13, 0x75, 0x9f, 0x6b, 0x73, 0xb7, 0xac, 0x9c, 0x36, 0x27, 0xa4, 0x9b, 0x31, 0xb2, 0xc5, 0xf3, 0x7a, 0x68, 0x63, 0x26, 0x31, 0x25, 0x4a, 0x94, 0xa4, 0x71, 0x68, 0x94, 0x92, 0x6f, 0xbf, 0x90, 0xb4, 0x0b, 0x6c, 0x18, 0x53, 0xd9, 0x1f, 0x04, 0x09, 0x4a, 0x7f, 0xa5, 0x89, 0xd4, 0x10, 0xbd, 0x67, 0xe4, 0x35, 0xff, 0xe2, 0x9d, 0x07, 0x98, 0xc3, 0xae, 0x92, 0xca, 0x6d, 0x28, 0x78, 0x2a, 0x56, 0x2d, 0x19, 0x11, 0xb1, 0x59, 0x94, 0xb0, 0x99, 0xf0, 0x88, 0x39, 0xd8, 0xb4, 0x4b, 0x70, 0xc5, 0xde, 0xa7, 0x78, 0x46, 0x80, 0x5b, 0xf5, 0x57, 0x07, 0x26, 0x30, 0x7d, 0x64, 0xac, 0xbf, 0x5a, 0x86, 0x81, 0x9f, 0x71, 0x5e, 0xa0, 0x7b, 0x5b, 0x1b, 0x14, 0x09, 0x9c, 0xd7, 0x07, 0xc3, 0xc9, 0x15, 0xb4, 0x79, 0x9a, 0xc2, 0x81, 0x46, 0xc6, 0xc3, 0xad, 0x6b, 0x4a, 0x75, 0xa3, 0x5a, 0x51, 0xaa, 0x6c, 0x36, 0x1c, 0xe4, 0x6d, 0xec, 0x82, 0x75, 0x35, 0x69, 0x47, 0xef, 0x69, 0x18, 0xd6, 0x30, 0x85, 0xa5, 0x27, 0x5d, 0xee, 0x02, 0xa1, 0x72, 0x14, 0x48, 0xe9, 0xc1, 0x0e, 0x1a, 0x32, 0x6c, 0x0a, 0x38, 0x26, 0x49, 0x91, 0x2a, 0x36, 0xf3, 0x95, 0xa4, 0x68, 0x3c, 0xbe, 0xb2, 0x82, 0x50, 0xf5, 0x87, 0x06, 0xc2, 0x9c, 0x36, 0x0a, 0x24, 0x82, 0x81, 0x4f, 0x09, 0x5a, 0x6c, 0x90, 0xe5, 0x60, 0x0d, 0x9f, 0xbb, 0x1e, 0xaa, 0xc2, 0x3f, 0x15, 0x5e, 0xce, 0x53, 0x0e, 0xe2, 0xc7, 0x5b, 0xe8, 0x45, 0x9c, 0x89, 0xe4, 0x8c, 0x1f, 0x29, 0x25, 0x25, 0xe7, 0x6e, 0xc4, 0xb6, 0x83, 0x89, 0x25 }, .spki_len = 1206, }, { .name = "ML-KEM 786", .parameter_set = CKP_IBM_ML_KEM_768, .sk = { 0x98, 0xa1, 0xb2, 0xda, 0x4a, 0x65, 0xcf, 0xb5, 0x84, 0x5e, 0xa7, 0x31, 0x1e, 0x6a, 0x06, 0xdb, 0x73, 0x1f, 0x15, 0x90, 0xc4, 0x1e, 0xe7, 0x4b, 0xa1, 0x07, 0x82, 0x71, 0x5b, 0x35, 0xa3, 0x10, 0x2d, 0xf6, 0x37, 0x87, 0x2b, 0xe6, 0x5b, 0xab, 0x37, 0xa1, 0xde, 0x25, 0x11, 0xd7, 0x03, 0xc7, 0x02, 0x47, 0xb3, 0x5e, 0xf2, 0x74, 0x35, 0x48, 0x50, 0x24, 0xd9, 0x3f, 0xd9, 0xe7, 0x7c, 0x43, 0x80, 0x4f, 0x37, 0x17, 0x49, 0xba, 0x00, 0xb2, 0x0a, 0x8c, 0x5c, 0x58, 0x8b, 0xc9, 0xab, 0xe0, 0x68, 0xae, 0xaa, 0xa9, 0x38, 0x51, 0x7e, 0xbf, 0xe5, 0x3b, 0x6b, 0x66, 0x32, 0x82, 0x90, 0x3d, 0xcd, 0x18, 0x97, 0x36, 0xd7, 0x29, 0x68, 0x16, 0xc7, 0x33, 0xa1, 0xc7, 0x7c, 0x63, 0x75, 0xe5, 0x39, 0x7c, 0x0f, 0x18, 0x9b, 0xbf, 0xe4, 0x76, 0x43, 0xa6, 0x1f, 0x58, 0xf8, 0xa3, 0xc6, 0x91, 0x1b, 0xe4, 0x61, 0x1a, 0x8c, 0x7b, 0xc0, 0x50, 0x02, 0x11, 0x63, 0xd0, 0xa4, 0x04, 0xdc, 0x14, 0x06, 0x57, 0x48, 0xff, 0x29, 0xbe, 0x60, 0xd2, 0xb9, 0xfd, 0xcc, 0x8f, 0xfd, 0x98, 0xc5, 0x87, 0xf3, 0x8c, 0x67, 0x11, 0x57, 0x86, 0x46, 0x4b, 0xdb, 0x34, 0x2b, 0x17, 0xe8, 0x97, 0xd6, 0x46, 0x17, 0xcb, 0xfb, 0x11, 0x79, 0x73, 0xa5, 0x45, 0x89, 0x77, 0xa7, 0xd7, 0x61, 0x7a, 0x1b, 0x4d, 0x83, 0xba, 0x03, 0xc6, 0x11, 0x13, 0x8a, 0x46, 0x73, 0xb1, 0xeb, 0x34, 0xb0, 0x78, 0x03, 0x3f, 0x97, 0xcf, 0xfe, 0x80, 0xc1, 0x46, 0xa2, 0x69, 0x43, 0xf8, 0x42, 0xb9, 0x76, 0x32, 0x7b, 0xf1, 0xcb, 0xc6, 0x01, 0x19, 0x52, 0x5b, 0xb9, 0xa3, 0xc0, 0x34, 0x93, 0x34, 0x90, 0x00, 0xdd, 0x8f, 0x51, 0xba, 0x21, 0xa2, 0xe9, 0x23, 0x61, 0x76, 0x23, 0x24, 0x60, 0x0e, 0x0c, 0x13, 0xaa, 0xa6, 0xcb, 0x69, 0xbf, 0xb2, 0x42, 0x76, 0x48, 0x3f, 0x6b, 0x02, 0x42, 0x12, 0x59, 0xb7, 0x58, 0x52, 0x63, 0xc1, 0xa0, 0x28, 0xd6, 0x82, 0xc5, 0x08, 0xbb, 0xc2, 0x80, 0x1a, 0x56, 0xe9, 0x8b, 0x8f, 0x62, 0x0b, 0x04, 0x83, 0xd7, 0x9b, 0x5a, 0xd8, 0x58, 0x5a, 0xc0, 0xa4, 0x75, 0xba, 0xc7, 0x78, 0x65, 0x19, 0x41, 0x96, 0x33, 0x87, 0x91, 0xb7, 0x98, 0x5a, 0x05, 0xd1, 0x09, 0x39, 0x5c, 0xca, 0x89, 0x32, 0x72, 0x2a, 0x91, 0x95, 0x0d, 0x37, 0xe1, 0x2b, 0x89, 0x14, 0x20, 0xa5, 0x2b, 0x62, 0xcb, 0xfa, 0x81, 0x5d, 0xf6, 0x17, 0x4c, 0xe0, 0x0e, 0x68, 0xbc, 0xa7, 0x5d, 0x48, 0x38, 0xca, 0x28, 0x0f, 0x71, 0x3c, 0x7e, 0x69, 0x24, 0xaf, 0xd9, 0x5b, 0xaa, 0x0d, 0x01, 0xad, 0xa6, 0x37, 0xb1, 0x58, 0x34, 0x70, 0x34, 0xc0, 0xab, 0x1a, 0x71, 0x83, 0x33, 0x1a, 0x82, 0x0a, 0xcb, 0xcb, 0x83, 0x19, 0x3a, 0x1a, 0x94, 0xc8, 0xf7, 0xe3, 0x84, 0xae, 0xd0, 0xc3, 0x5e, 0xd3, 0xcb, 0x33, 0x97, 0xbb, 0x63, 0x80, 0x86, 0xe7, 0xa3, 0x5a, 0x64, 0x08, 0xa3, 0xa4, 0xb9, 0x0c, 0xe9, 0x53, 0x70, 0x7c, 0x19, 0xbc, 0x46, 0xc3, 0xb2, 0xda, 0x3b, 0x2e, 0xe3, 0x23, 0x19, 0xc5, 0x6b, 0x92, 0x80, 0x32, 0xb5, 0xed, 0x12, 0x56, 0xd0, 0x75, 0x3d, 0x34, 0x14, 0x23, 0xe9, 0xdb, 0x13, 0x9d, 0xe7, 0x71, 0x4f, 0xf0, 0x75, 0xca, 0xf5, 0x8f, 0xd9, 0xf5, 0x7d, 0x1a, 0x54, 0x01, 0x9b, 0x59, 0x26, 0x40, 0x68, 0x30, 0xda, 0xe2, 0x9a, 0x87, 0x53, 0x02, 0xa8, 0x12, 0x56, 0xf4, 0xd6, 0xcf, 0x5e, 0x74, 0x03, 0x4e, 0xa6, 0x14, 0xbf, 0x70, 0xc2, 0x76, 0x4b, 0x20, 0xc9, 0x58, 0x9c, 0xdb, 0x5c, 0x25, 0x76, 0x1a, 0x04, 0xe5, 0x82, 0x92, 0x90, 0x7c, 0x57, 0x8a, 0x94, 0xa3, 0x58, 0x36, 0xbe, 0xe3, 0x11, 0x2d, 0xc2, 0xc3, 0xae, 0x21, 0x92, 0xc9, 0xde, 0xaa, 0x30, 0x4b, 0x29, 0xc7, 0xfe, 0xa1, 0xbd, 0xf4, 0x7b, 0x3b, 0x6b, 0xcb, 0xa2, 0xc0, 0xe5, 0x5c, 0x9c, 0xdb, 0x6d, 0xe7, 0x14, 0x9e, 0x9c, 0xb1, 0x79, 0x17, 0x71, 0x8f, 0x12, 0xc8, 0x03, 0x2d, 0xe1, 0xad, 0xe0, 0x64, 0x8d, 0x40, 0x55, 0x19, 0xc7, 0x07, 0x19, 0xbe, 0xcc, 0x70, 0x18, 0x45, 0xcf, 0x9f, 0x4b, 0x91, 0x2f, 0xe7, 0x19, 0x83, 0xca, 0x34, 0xf9, 0x01, 0x8c, 0x7c, 0xa7, 0xbb, 0x2f, 0x6c, 0x5d, 0x7f, 0x8c, 0x5b, 0x29, 0x73, 0x59, 0xec, 0x75, 0x20, 0x9c, 0x25, 0x43, 0xff, 0x11, 0xc4, 0x24, 0x49, 0x77, 0xc5, 0x96, 0x95, 0x24, 0xec, 0x45, 0x4d, 0x44, 0xc3, 0x23, 0xfc, 0xca, 0x94, 0xac, 0xac, 0x27, 0x3a, 0x0e, 0xc4, 0x9b, 0x4a, 0x8a, 0x58, 0x5b, 0xce, 0x7a, 0x5b, 0x30, 0x5c, 0x04, 0xc3, 0x50, 0x64, 0x22, 0x58, 0x03, 0x57, 0x01, 0x6a, 0x85, 0x0c, 0x3f, 0x7e, 0xe1, 0x72, 0x05, 0xa7, 0x7b, 0x29, 0x1c, 0x77, 0x31, 0xc9, 0x83, 0x6c, 0x02, 0xae, 0xe5, 0x40, 0x6f, 0x63, 0xc6, 0xa0, 0x7a, 0x21, 0x43, 0x82, 0xaa, 0x15, 0x33, 0x6c, 0x05, 0xd1, 0x04, 0x55, 0x88, 0x10, 0x76, 0x45, 0xea, 0x7d, 0xe6, 0x87, 0x0f, 0xc0, 0xe5, 0x5e, 0x15, 0x40, 0x97, 0x43, 0x01, 0xc4, 0x2e, 0xc1, 0x41, 0x05, 0x51, 0x86, 0x80, 0xf6, 0x88, 0xab, 0xe4, 0xce, 0x45, 0x37, 0x38, 0xfe, 0x47, 0x1b, 0x87, 0xfc, 0x31, 0xf5, 0xc6, 0x8a, 0x39, 0xe6, 0x8a, 0xf5, 0x1b, 0x02, 0x40, 0xb9, 0x0e, 0x03, 0x64, 0xb0, 0x4b, 0xac, 0x43, 0xd6, 0xfb, 0x68, 0xab, 0x65, 0xae, 0x02, 0x8b, 0x62, 0xbd, 0x68, 0x3b, 0x7d, 0x28, 0xad, 0x38, 0x80, 0x6b, 0xee, 0x72, 0x5b, 0x5b, 0x24, 0x16, 0xa8, 0xd7, 0x9c, 0x16, 0xec, 0x2a, 0x99, 0xea, 0x4a, 0x8d, 0x92, 0xa2, 0xf5, 0x05, 0x2e, 0x67, 0xf9, 0x73, 0x52, 0x28, 0x97, 0x61, 0xc5, 0xc3, 0x9f, 0xc5, 0xc7, 0x42, 0xe9, 0xc0, 0xa7, 0x40, 0xca, 0x59, 0xfc, 0x01, 0x82, 0xf7, 0x09, 0xd0, 0x1b, 0x51, 0x87, 0xf0, 0x00, 0x63, 0xda, 0xab, 0x39, 0x75, 0x96, 0xee, 0xa4, 0xa3, 0x1b, 0xdb, 0xcb, 0xd4, 0xc1, 0xbb, 0x0c, 0x55, 0xbe, 0x7c, 0x68, 0x50, 0xfd, 0xa9, 0x32, 0x6b, 0x35, 0x3e, 0x28, 0x8c, 0x50, 0x13, 0x22, 0x6c, 0x3c, 0x39, 0x23, 0xa7, 0x91, 0x60, 0x9e, 0x80, 0x02, 0xe7, 0x3a, 0x5f, 0x7b, 0x6b, 0xb4, 0xa8, 0x77, 0xb1, 0xfd, 0xf5, 0x3b, 0xb2, 0xba, 0xb3, 0xdd, 0x42, 0x4d, 0x31, 0xbb, 0xb4, 0x48, 0xe6, 0x09, 0xa6, 0x6b, 0x0e, 0x34, 0x3c, 0x28, 0x6e, 0x87, 0x60, 0x31, 0x2b, 0x6d, 0x37, 0xaa, 0x52, 0x01, 0xd2, 0x1f, 0x53, 0x50, 0x3d, 0x88, 0x38, 0x9a, 0xdc, 0xa2, 0x1c, 0x70, 0xfb, 0x6c, 0x0f, 0xc9, 0xc6, 0x9d, 0x66, 0x16, 0xc9, 0xea, 0x37, 0x80, 0xe3, 0x55, 0x65, 0xc0, 0xc9, 0x7c, 0x15, 0x17, 0x9c, 0x95, 0x34, 0x3e, 0xcc, 0x5e, 0x1c, 0x2a, 0x24, 0xde, 0x46, 0x99, 0xf6, 0x87, 0x5e, 0xa2, 0xfa, 0x2d, 0xd3, 0xe3, 0x57, 0xbc, 0x43, 0x91, 0x47, 0x95, 0x20, 0x7e, 0x02, 0x6b, 0x85, 0x0a, 0x22, 0x37, 0x95, 0x0c, 0x10, 0x8a, 0x51, 0x2f, 0xc8, 0x8c, 0x22, 0x48, 0x81, 0x12, 0x60, 0x70, 0x88, 0x18, 0x5f, 0xb0, 0xe0, 0x9c, 0x2c, 0x41, 0x97, 0xa8, 0x36, 0x87, 0x26, 0x6b, 0xab, 0x2e, 0x58, 0x3e, 0x21, 0xc4, 0x0f, 0x4c, 0xc0, 0x08, 0xfe, 0x65, 0x28, 0x04, 0xd8, 0x22, 0x3f, 0x15, 0x20, 0xa9, 0x0b, 0x0d, 0x53, 0x85, 0xc7, 0x55, 0x3c, 0xc7, 0x67, 0xc5, 0x8d, 0x12, 0x0c, 0xcd, 0x3e, 0xf5, 0xb5, 0xd1, 0xa6, 0xcd, 0x7b, 0xc0, 0x0d, 0xff, 0x13, 0x21, 0xb2, 0xf2, 0xc4, 0x32, 0xb6, 0x4e, 0xfb, 0x8a, 0x3f, 0x5d, 0x00, 0x64, 0xb3, 0xf3, 0x42, 0x93, 0x02, 0x6c, 0x85, 0x1c, 0x2d, 0xed, 0x68, 0xb9, 0xdf, 0xf4, 0xa2, 0x8f, 0x6a, 0x8d, 0x22, 0x55, 0x35, 0xe0, 0x47, 0x70, 0x84, 0x43, 0x0c, 0xff, 0xda, 0x0a, 0xc0, 0x55, 0x2f, 0x9a, 0x21, 0x27, 0x85, 0xb7, 0x49, 0x91, 0x3a, 0x06, 0xfa, 0x22, 0x74, 0xc0, 0xd1, 0x5b, 0xad, 0x32, 0x54, 0x58, 0xd3, 0x23, 0xef, 0x6b, 0xae, 0x13, 0xc0, 0x01, 0x0d, 0x52, 0x5c, 0x1d, 0x52, 0x69, 0x97, 0x3a, 0xc2, 0x9b, 0xda, 0x7c, 0x98, 0x37, 0x46, 0x91, 0x8b, 0xa0, 0xe0, 0x02, 0x58, 0x8e, 0x30, 0x37, 0x5d, 0x78, 0x32, 0x9e, 0x6b, 0x8b, 0xa8, 0xc4, 0x46, 0x2a, 0x69, 0x2f, 0xb6, 0x08, 0x38, 0x42, 0xb8, 0xc8, 0xc9, 0x2c, 0x60, 0xf2, 0x52, 0x72, 0x6d, 0x14, 0xa0, 0x71, 0xf7, 0xcc, 0x45, 0x25, 0x58, 0xd5, 0xe7, 0x1a, 0x7b, 0x08, 0x70, 0x62, 0xec, 0xb1, 0x38, 0x68, 0x44, 0x58, 0x82, 0x46, 0x12, 0x64, 0x02, 0xb1, 0xfa, 0x16, 0x37, 0x73, 0x3c, 0xd5, 0xf6, 0x0c, 0xc8, 0x4b, 0xcb, 0x64, 0x6a, 0x78, 0x92, 0x61, 0x4d, 0x7c, 0x51, 0xb1, 0xc7, 0xf1, 0xa2, 0x79, 0x91, 0x32, 0xf1, 0x34, 0x27, 0xdc, 0x48, 0x21, 0x58, 0xda, 0x25, 0x44, 0x70, 0xa5, 0x9e, 0x00, 0xa4, 0xe4, 0x96, 0x86, 0xfd, 0xc0, 0x77, 0x55, 0x93, 0x67, 0x27, 0x0c, 0x21, 0x53, 0xf1, 0x10, 0x07, 0x59, 0x2c, 0x9c, 0x43, 0x10, 0xcf, 0x8a, 0x12, 0xc6, 0xa8, 0x71, 0x3b, 0xd6, 0xbb, 0x51, 0xf3, 0x12, 0x4f, 0x98, 0x9b, 0xa0, 0xd5, 0x40, 0x73, 0xcc, 0x24, 0x2e, 0x09, 0x68, 0x78, 0x0b, 0x87, 0x5a, 0x86, 0x9e, 0xfb, 0x85, 0x15, 0x86, 0xb9, 0xa8, 0x68, 0xa3, 0x84, 0xb9, 0xe6, 0x82, 0x1b, 0x20, 0x1b, 0x93, 0x2c, 0x45, 0x53, 0x69, 0xa7, 0x39, 0xec, 0x22, 0x56, 0x9c, 0x97, 0x7c, 0x21, 0x2b, 0x38, 0x18, 0x71, 0x81, 0x36, 0x56, 0xaf, 0x5b, 0x56, 0x7e, 0xf8, 0x93, 0xb5, 0x84, 0x62, 0x4c, 0x86, 0x3a, 0x25, 0x90, 0x00, 0xf1, 0x7b, 0x25, 0x4b, 0x98, 0xb1, 0x85, 0x09, 0x7c, 0x50, 0xeb, 0xb6, 0x8b, 0x24, 0x43, 0x42, 0xe0, 0x5d, 0x4d, 0xe5, 0x20, 0x12, 0x5b, 0x8e, 0x10, 0x33, 0xb1, 0x43, 0x60, 0x93, 0xac, 0xe7, 0xce, 0x8e, 0x71, 0xb4, 0x58, 0xd5, 0x25, 0x67, 0x33, 0x63, 0x04, 0x5a, 0x3b, 0x3e, 0xea, 0x94, 0x55, 0x42, 0x8a, 0x39, 0x87, 0x05, 0xa4, 0x23, 0x27, 0xad, 0xb3, 0x77, 0x4b, 0x70, 0x57, 0xf4, 0x2b, 0x01, 0x7e, 0xc0, 0x73, 0x9a, 0x98, 0x3f, 0x19, 0xe8, 0x21, 0x4d, 0x09, 0x19, 0x5f, 0xa2, 0x4d, 0x2d, 0x57, 0x1d, 0xb7, 0x3c, 0x19, 0xa6, 0xf8, 0x46, 0x0e, 0x50, 0x83, 0x0d, 0x41, 0x5f, 0x62, 0x7b, 0x88, 0xe9, 0x4a, 0x7b, 0x15, 0x37, 0x91, 0xa0, 0xc0, 0xc7, 0xe9, 0x48, 0x4c, 0x74, 0xd5, 0x3c, 0x71, 0x48, 0x89, 0xf0, 0xe3, 0x21, 0xb6, 0x66, 0x0a, 0x53, 0x2a, 0x5b, 0xc0, 0xe5, 0x57, 0xfb, 0xca, 0x35, 0xe2, 0x9b, 0xc6, 0x11, 0x20, 0x0e, 0xd3, 0xc6, 0x33, 0x07, 0x7a, 0x4d, 0x87, 0x3c, 0x5c, 0xc6, 0x70, 0x06, 0xb7, 0x53, 0xbf, 0x6d, 0x6b, 0x7a, 0xf6, 0xca, 0x40, 0x2a, 0xb6, 0x18, 0x23, 0x6c, 0x0a, 0xff, 0xbc, 0x80, 0x1f, 0x82, 0x22, 0xfb, 0xc3, 0x6c, 0xe0, 0x98, 0x4e, 0x2b, 0x18, 0xc9, 0x44, 0xbb, 0xcb, 0xef, 0x03, 0xb1, 0xe1, 0x36, 0x1c, 0x1f, 0x44, 0xb0, 0xd7, 0x34, 0xaf, 0xb1, 0x56, 0x6c, 0xff, 0x87, 0x44, 0xda, 0x8b, 0x99, 0x43, 0xd6, 0xb4, 0x5a, 0x3c, 0x09, 0x03, 0x07, 0x02, 0xca, 0x20, 0x1f, 0xfe, 0x20, 0xcb, 0x7e, 0xc5, 0xb0, 0xd4, 0x14, 0x9e, 0xe2, 0xc2, 0x8e, 0x8b, 0x23, 0x37, 0x4f, 0x47, 0x1b, 0x57, 0x15, 0x0d, 0x0e, 0xc9, 0x33, 0x62, 0x61, 0xa2, 0xd5, 0xcb, 0x84, 0xa3, 0xac, 0xac, 0xc4, 0x28, 0x94, 0x73, 0xa4, 0xc0, 0xab, 0xc6, 0x17, 0xc9, 0xab, 0xc1, 0x78, 0x73, 0x44, 0x34, 0xc8, 0x2e, 0x16, 0x85, 0x58, 0x8a, 0x5c, 0x2e, 0xa2, 0x67, 0x8f, 0x6b, 0x3c, 0x22, 0x28, 0x73, 0x31, 0x30, 0xc4, 0x66, 0xe5, 0xb8, 0x6e, 0xf4, 0x91, 0x15, 0x3e, 0x48, 0x66, 0x22, 0x47, 0xb8, 0x75, 0xd2, 0x01, 0x02, 0x0b, 0x56, 0x6b, 0x81, 0xb6, 0x4d, 0x83, 0x9a, 0xb4, 0x63, 0x3b, 0xaa, 0x8a, 0xce, 0x20, 0x2b, 0xaa, 0xb4, 0x49, 0x62, 0x97, 0xf9, 0x80, 0x7a, 0xdb, 0xbb, 0x1e, 0x33, 0x2c, 0x6f, 0x80, 0x22, 0xb2, 0xa1, 0x8c, 0xfd, 0xd4, 0xa8, 0x25, 0x30, 0xb6, 0xd3, 0xf0, 0x07, 0xc3, 0x35, 0x38, 0x98, 0xd9, 0x66, 0xcc, 0x2c, 0x21, 0xcb, 0x42, 0x44, 0xbd, 0x00, 0x44, 0x3f, 0x20, 0x98, 0x70, 0xac, 0xc4, 0x2b, 0xc3, 0x30, 0x68, 0xc7, 0x24, 0xec, 0x17, 0x22, 0x36, 0x19, 0xc1, 0x09, 0x3c, 0xca, 0x6a, 0xeb, 0x29, 0x50, 0x06, 0x64, 0xd1, 0x22, 0x50, 0x36, 0xb4, 0xb8, 0x10, 0x91, 0x90, 0x69, 0x69, 0x48, 0x1f, 0x1c, 0x72, 0x3c, 0x14, 0x0b, 0x9d, 0x6c, 0x16, 0x8f, 0x5b, 0x64, 0xbe, 0xa6, 0x9c, 0x5f, 0xd6, 0x38, 0x5d, 0xf7, 0x36, 0x4b, 0x87, 0x23, 0xbc, 0xc8, 0x5e, 0x03, 0x8c, 0x7e, 0x46, 0x4a, 0x90, 0x0d, 0x68, 0xa2, 0x12, 0x78, 0x18, 0x99, 0x42, 0x17, 0xae, 0xc8, 0xbd, 0xb3, 0x9a, 0x97, 0x0a, 0x99, 0x63, 0xde, 0x93, 0x68, 0x8e, 0x2a, 0xc8, 0x2a, 0xbc, 0xc2, 0x2f, 0xb9, 0x27, 0x7b, 0xa2, 0x20, 0x09, 0xe8, 0x78, 0x38, 0x1a, 0x38, 0x16, 0x39, 0x01, 0xc7, 0xd4, 0xc8, 0x50, 0x19, 0x53, 0x8d, 0x35, 0xca, 0xae, 0x9c, 0x41, 0xaf, 0x8c, 0x92, 0x9e, 0xe2, 0x0b, 0xb0, 0x8c, 0xa6, 0x19, 0xe7, 0x2c, 0x2f, 0x22, 0x62, 0xc1, 0xc9, 0x93, 0x85, 0x72, 0x55, 0x1a, 0xc0, 0x2d, 0xc9, 0x26, 0x8f, 0xbc, 0xc3, 0x5d, 0x79, 0x01, 0x1c, 0x3c, 0x09, 0x0a, 0xd4, 0x0a, 0x4f, 0x11, 0x1c, 0x9b, 0xe5, 0x5c, 0x42, 0x7e, 0xb7, 0x96, 0xc1, 0x93, 0x2d, 0x86, 0x73, 0x57, 0x9a, 0xf1, 0xb4, 0xc6, 0x38, 0xb0, 0x94, 0x44, 0x89, 0x01, 0x2a, 0x25, 0x59, 0xa3, 0xb0, 0x24, 0x81, 0xb0, 0x1a, 0xc3, 0x0b, 0xa8, 0x96, 0x0f, 0x80, 0xc0, 0xc2, 0xb3, 0x94, 0x7d, 0x36, 0xa1, 0x2c, 0x08, 0x04, 0x98, 0xbe, 0xe4, 0x48, 0x71, 0x6c, 0x97, 0x34, 0x16, 0xc8, 0x24, 0x28, 0x04, 0xa3, 0xda, 0x09, 0x9e, 0xe1, 0x37, 0xb0, 0xba, 0x90, 0xfe, 0x4a, 0x5c, 0x6a, 0x89, 0x20, 0x02, 0x76, 0xa0, 0xcf, 0xb6, 0x43, 0xec, 0x2c, 0x56, 0xa2, 0xd7, 0x08, 0xd7, 0xb4, 0x37, 0x3e, 0x44, 0xc1, 0x50, 0x2a, 0x76, 0x3a, 0x60, 0x05, 0x86, 0xe6, 0xcd, 0xa6, 0x27, 0x38, 0x97, 0xd4, 0x44, 0x48, 0x28, 0x7d, 0xc2, 0xe6, 0x02, 0xdc, 0x39, 0x20, 0x0b, 0xf6, 0x16, 0x62, 0x36, 0x55, 0x9f, 0xd1, 0x2a, 0x60, 0x89, 0x2a, 0xeb, 0x15, 0x3d, 0xd6, 0x51, 0xbb, 0x46, 0x99, 0x10, 0xb4, 0xb3, 0x46, 0x69, 0xf9, 0x1d, 0xa8, 0x65, 0x4d, 0x1e, 0xb7, 0x2e, 0xb6, 0xe0, 0x28, 0x00, 0xb3, 0xb0, 0xa7, 0xd0, 0xa4, 0x8c, 0x83, 0x68, 0x54, 0xd3, 0xa8, 0x3e, 0x65, 0x56, 0x9c, 0xb7, 0x23, 0x0b, 0xb4, 0x4f, 0x3f, 0x14, 0x3a, 0x6d, 0xec, 0x5f, 0x2c, 0x39, 0xab, 0x90, 0xf2, 0x74, 0xf2, 0x08, 0x8b, 0xd3, 0xd6, 0xa6, 0xfc, 0xa0, 0x07, 0x02, 0x73, 0xbe, 0xdc, 0x84, 0x77, 0x7f, 0xb5, 0x2e, 0x3c, 0x55, 0x8b, 0x0a, 0xe0, 0x61, 0x83, 0xd5, 0xa4, 0x8d, 0x45, 0x2f, 0x68, 0xe1, 0x52, 0x07, 0xf8, 0x61, 0x62, 0x7a, 0xca, 0x14, 0x27, 0x96, 0x30, 0xf8, 0x2e, 0xc3, 0xa0, 0xca, 0x07, 0x86, 0x33, 0xb6, 0x00, 0xaf, 0xa7, 0x97, 0x43, 0xa6, 0x00, 0x21, 0x5b, 0xe5, 0x63, 0x74, 0x58, 0xce, 0x2c, 0xe8, 0xaf, 0xf5, 0xa0, 0x8e, 0xb5, 0x01, 0x7b, 0x2c, 0x76, 0x65, 0x77, 0x47, 0x9f, 0x8d, 0xc6, 0xbf, 0x9f, 0x5c, 0xc7, 0x50, 0x89, 0x93, 0x21, 0x61, 0xb9, 0x6c, 0xea, 0x40, 0x66, 0x20, 0xae, 0xdb, 0x63, 0x04, 0x07, 0xf7, 0x68, 0x7e, 0xbb, 0xb4, 0x81, 0x4c, 0x79, 0x81, 0x63, 0x7a, 0x48, 0xa9, 0x0d, 0xe6, 0x80, 0x31, 0xe0, 0x62, 0xa7, 0xaf, 0x76, 0x12, 0xb4, 0xf5, 0xc7, 0xa6, 0xda, 0x86, 0xbd, 0x13, 0x65, 0x29, 0xe6, 0x42, 0x95, 0xa5, 0x61, 0x3e, 0xa7, 0x3b, 0xd3, 0xd4, 0x44, 0x8c, 0xb8, 0x1f, 0x24, 0x31, 0x35, 0xc0, 0xa6, 0x60, 0xbe, 0xb9, 0xc1, 0x7e, 0x65, 0x1d, 0xef, 0x46, 0x9a, 0x7d, 0x90, 0xa1, 0x5d, 0x34, 0x81, 0x09, 0x0b, 0xcb, 0xf2, 0x27, 0x01, 0x23, 0x28, 0x94, 0x1f, 0xa4, 0x6f, 0x39, 0xc5, 0x00, 0x6a, 0xd9, 0x3d, 0x45, 0x8a, 0xa6, 0xad, 0xd6, 0x55, 0x86, 0x2b, 0x41, 0x8c, 0x30, 0x94, 0xf5, 0x51, 0x46, 0x0d, 0xf2, 0x15, 0x3a, 0x58, 0x10, 0xa7, 0xda, 0x74, 0xf0, 0x61, 0x4c, 0x25, 0x88, 0xbe, 0x49, 0xdc, 0x6f, 0x5e, 0x88, 0x15, 0x46, 0x42, 0xbd, 0x1d, 0x37, 0x62, 0x56, 0x33, 0x26, 0x43, 0x35, 0x07, 0x15, 0x6a, 0x57, 0xc5, 0x76, 0x94, 0xbd, 0xd2, 0x6e, 0x7a, 0x24, 0x6f, 0xeb, 0x72, 0x3a, 0xed, 0x67, 0xb0, 0x48, 0x87, 0xc8, 0xe4, 0x76, 0xb4, 0x8c, 0xab, 0x59, 0xe5, 0x36, 0x2f, 0x26, 0xa9, 0xef, 0x50, 0xc2, 0xbc, 0x80, 0xba, 0x14, 0x62, 0x26, 0x21, 0x6f, 0xe6, 0x29, 0x68, 0xa6, 0x0d, 0x04, 0xe8, 0xc1, 0x70, 0xd7, 0x41, 0xc7, 0xa2, 0xb0, 0xe1, 0xab, 0xda, 0xc9, 0x68, 0xe2, 0x90, 0x20, 0x83, 0x9d, 0x05, 0x2f, 0xa3, 0x72, 0x58, 0x56, 0x27, 0xf8, 0xb5, 0x9e, 0xe3, 0x12, 0xae, 0x41, 0x4c, 0x97, 0x9d, 0x82, 0x5f, 0x06, 0xa6, 0x92, 0x9a, 0x79, 0x62, 0x57, 0x18, 0xa8, 0x57, 0x68, 0xf3, 0x48, 0x6b, 0xd3, 0x2a, 0x01, 0xbf, 0x9a, 0x8f, 0x21, 0xea, 0x93, 0x8e, 0x64, 0x8e, 0xae, 0x4e, 0x54, 0x48, 0xc3, 0x4c, 0x3e, 0xb8, 0x88, 0x20, 0xb1, 0x59, 0xee, 0xdd, }, .sk_len = 2400, .pk = { 0x6d, 0x14, 0xa0, 0x71, 0xf7, 0xcc, 0x45, 0x25, 0x58, 0xd5, 0xe7, 0x1a, 0x7b, 0x08, 0x70, 0x62, 0xec, 0xb1, 0x38, 0x68, 0x44, 0x58, 0x82, 0x46, 0x12, 0x64, 0x02, 0xb1, 0xfa, 0x16, 0x37, 0x73, 0x3c, 0xd5, 0xf6, 0x0c, 0xc8, 0x4b, 0xcb, 0x64, 0x6a, 0x78, 0x92, 0x61, 0x4d, 0x7c, 0x51, 0xb1, 0xc7, 0xf1, 0xa2, 0x79, 0x91, 0x32, 0xf1, 0x34, 0x27, 0xdc, 0x48, 0x21, 0x58, 0xda, 0x25, 0x44, 0x70, 0xa5, 0x9e, 0x00, 0xa4, 0xe4, 0x96, 0x86, 0xfd, 0xc0, 0x77, 0x55, 0x93, 0x67, 0x27, 0x0c, 0x21, 0x53, 0xf1, 0x10, 0x07, 0x59, 0x2c, 0x9c, 0x43, 0x10, 0xcf, 0x8a, 0x12, 0xc6, 0xa8, 0x71, 0x3b, 0xd6, 0xbb, 0x51, 0xf3, 0x12, 0x4f, 0x98, 0x9b, 0xa0, 0xd5, 0x40, 0x73, 0xcc, 0x24, 0x2e, 0x09, 0x68, 0x78, 0x0b, 0x87, 0x5a, 0x86, 0x9e, 0xfb, 0x85, 0x15, 0x86, 0xb9, 0xa8, 0x68, 0xa3, 0x84, 0xb9, 0xe6, 0x82, 0x1b, 0x20, 0x1b, 0x93, 0x2c, 0x45, 0x53, 0x69, 0xa7, 0x39, 0xec, 0x22, 0x56, 0x9c, 0x97, 0x7c, 0x21, 0x2b, 0x38, 0x18, 0x71, 0x81, 0x36, 0x56, 0xaf, 0x5b, 0x56, 0x7e, 0xf8, 0x93, 0xb5, 0x84, 0x62, 0x4c, 0x86, 0x3a, 0x25, 0x90, 0x00, 0xf1, 0x7b, 0x25, 0x4b, 0x98, 0xb1, 0x85, 0x09, 0x7c, 0x50, 0xeb, 0xb6, 0x8b, 0x24, 0x43, 0x42, 0xe0, 0x5d, 0x4d, 0xe5, 0x20, 0x12, 0x5b, 0x8e, 0x10, 0x33, 0xb1, 0x43, 0x60, 0x93, 0xac, 0xe7, 0xce, 0x8e, 0x71, 0xb4, 0x58, 0xd5, 0x25, 0x67, 0x33, 0x63, 0x04, 0x5a, 0x3b, 0x3e, 0xea, 0x94, 0x55, 0x42, 0x8a, 0x39, 0x87, 0x05, 0xa4, 0x23, 0x27, 0xad, 0xb3, 0x77, 0x4b, 0x70, 0x57, 0xf4, 0x2b, 0x01, 0x7e, 0xc0, 0x73, 0x9a, 0x98, 0x3f, 0x19, 0xe8, 0x21, 0x4d, 0x09, 0x19, 0x5f, 0xa2, 0x4d, 0x2d, 0x57, 0x1d, 0xb7, 0x3c, 0x19, 0xa6, 0xf8, 0x46, 0x0e, 0x50, 0x83, 0x0d, 0x41, 0x5f, 0x62, 0x7b, 0x88, 0xe9, 0x4a, 0x7b, 0x15, 0x37, 0x91, 0xa0, 0xc0, 0xc7, 0xe9, 0x48, 0x4c, 0x74, 0xd5, 0x3c, 0x71, 0x48, 0x89, 0xf0, 0xe3, 0x21, 0xb6, 0x66, 0x0a, 0x53, 0x2a, 0x5b, 0xc0, 0xe5, 0x57, 0xfb, 0xca, 0x35, 0xe2, 0x9b, 0xc6, 0x11, 0x20, 0x0e, 0xd3, 0xc6, 0x33, 0x07, 0x7a, 0x4d, 0x87, 0x3c, 0x5c, 0xc6, 0x70, 0x06, 0xb7, 0x53, 0xbf, 0x6d, 0x6b, 0x7a, 0xf6, 0xca, 0x40, 0x2a, 0xb6, 0x18, 0x23, 0x6c, 0x0a, 0xff, 0xbc, 0x80, 0x1f, 0x82, 0x22, 0xfb, 0xc3, 0x6c, 0xe0, 0x98, 0x4e, 0x2b, 0x18, 0xc9, 0x44, 0xbb, 0xcb, 0xef, 0x03, 0xb1, 0xe1, 0x36, 0x1c, 0x1f, 0x44, 0xb0, 0xd7, 0x34, 0xaf, 0xb1, 0x56, 0x6c, 0xff, 0x87, 0x44, 0xda, 0x8b, 0x99, 0x43, 0xd6, 0xb4, 0x5a, 0x3c, 0x09, 0x03, 0x07, 0x02, 0xca, 0x20, 0x1f, 0xfe, 0x20, 0xcb, 0x7e, 0xc5, 0xb0, 0xd4, 0x14, 0x9e, 0xe2, 0xc2, 0x8e, 0x8b, 0x23, 0x37, 0x4f, 0x47, 0x1b, 0x57, 0x15, 0x0d, 0x0e, 0xc9, 0x33, 0x62, 0x61, 0xa2, 0xd5, 0xcb, 0x84, 0xa3, 0xac, 0xac, 0xc4, 0x28, 0x94, 0x73, 0xa4, 0xc0, 0xab, 0xc6, 0x17, 0xc9, 0xab, 0xc1, 0x78, 0x73, 0x44, 0x34, 0xc8, 0x2e, 0x16, 0x85, 0x58, 0x8a, 0x5c, 0x2e, 0xa2, 0x67, 0x8f, 0x6b, 0x3c, 0x22, 0x28, 0x73, 0x31, 0x30, 0xc4, 0x66, 0xe5, 0xb8, 0x6e, 0xf4, 0x91, 0x15, 0x3e, 0x48, 0x66, 0x22, 0x47, 0xb8, 0x75, 0xd2, 0x01, 0x02, 0x0b, 0x56, 0x6b, 0x81, 0xb6, 0x4d, 0x83, 0x9a, 0xb4, 0x63, 0x3b, 0xaa, 0x8a, 0xce, 0x20, 0x2b, 0xaa, 0xb4, 0x49, 0x62, 0x97, 0xf9, 0x80, 0x7a, 0xdb, 0xbb, 0x1e, 0x33, 0x2c, 0x6f, 0x80, 0x22, 0xb2, 0xa1, 0x8c, 0xfd, 0xd4, 0xa8, 0x25, 0x30, 0xb6, 0xd3, 0xf0, 0x07, 0xc3, 0x35, 0x38, 0x98, 0xd9, 0x66, 0xcc, 0x2c, 0x21, 0xcb, 0x42, 0x44, 0xbd, 0x00, 0x44, 0x3f, 0x20, 0x98, 0x70, 0xac, 0xc4, 0x2b, 0xc3, 0x30, 0x68, 0xc7, 0x24, 0xec, 0x17, 0x22, 0x36, 0x19, 0xc1, 0x09, 0x3c, 0xca, 0x6a, 0xeb, 0x29, 0x50, 0x06, 0x64, 0xd1, 0x22, 0x50, 0x36, 0xb4, 0xb8, 0x10, 0x91, 0x90, 0x69, 0x69, 0x48, 0x1f, 0x1c, 0x72, 0x3c, 0x14, 0x0b, 0x9d, 0x6c, 0x16, 0x8f, 0x5b, 0x64, 0xbe, 0xa6, 0x9c, 0x5f, 0xd6, 0x38, 0x5d, 0xf7, 0x36, 0x4b, 0x87, 0x23, 0xbc, 0xc8, 0x5e, 0x03, 0x8c, 0x7e, 0x46, 0x4a, 0x90, 0x0d, 0x68, 0xa2, 0x12, 0x78, 0x18, 0x99, 0x42, 0x17, 0xae, 0xc8, 0xbd, 0xb3, 0x9a, 0x97, 0x0a, 0x99, 0x63, 0xde, 0x93, 0x68, 0x8e, 0x2a, 0xc8, 0x2a, 0xbc, 0xc2, 0x2f, 0xb9, 0x27, 0x7b, 0xa2, 0x20, 0x09, 0xe8, 0x78, 0x38, 0x1a, 0x38, 0x16, 0x39, 0x01, 0xc7, 0xd4, 0xc8, 0x50, 0x19, 0x53, 0x8d, 0x35, 0xca, 0xae, 0x9c, 0x41, 0xaf, 0x8c, 0x92, 0x9e, 0xe2, 0x0b, 0xb0, 0x8c, 0xa6, 0x19, 0xe7, 0x2c, 0x2f, 0x22, 0x62, 0xc1, 0xc9, 0x93, 0x85, 0x72, 0x55, 0x1a, 0xc0, 0x2d, 0xc9, 0x26, 0x8f, 0xbc, 0xc3, 0x5d, 0x79, 0x01, 0x1c, 0x3c, 0x09, 0x0a, 0xd4, 0x0a, 0x4f, 0x11, 0x1c, 0x9b, 0xe5, 0x5c, 0x42, 0x7e, 0xb7, 0x96, 0xc1, 0x93, 0x2d, 0x86, 0x73, 0x57, 0x9a, 0xf1, 0xb4, 0xc6, 0x38, 0xb0, 0x94, 0x44, 0x89, 0x01, 0x2a, 0x25, 0x59, 0xa3, 0xb0, 0x24, 0x81, 0xb0, 0x1a, 0xc3, 0x0b, 0xa8, 0x96, 0x0f, 0x80, 0xc0, 0xc2, 0xb3, 0x94, 0x7d, 0x36, 0xa1, 0x2c, 0x08, 0x04, 0x98, 0xbe, 0xe4, 0x48, 0x71, 0x6c, 0x97, 0x34, 0x16, 0xc8, 0x24, 0x28, 0x04, 0xa3, 0xda, 0x09, 0x9e, 0xe1, 0x37, 0xb0, 0xba, 0x90, 0xfe, 0x4a, 0x5c, 0x6a, 0x89, 0x20, 0x02, 0x76, 0xa0, 0xcf, 0xb6, 0x43, 0xec, 0x2c, 0x56, 0xa2, 0xd7, 0x08, 0xd7, 0xb4, 0x37, 0x3e, 0x44, 0xc1, 0x50, 0x2a, 0x76, 0x3a, 0x60, 0x05, 0x86, 0xe6, 0xcd, 0xa6, 0x27, 0x38, 0x97, 0xd4, 0x44, 0x48, 0x28, 0x7d, 0xc2, 0xe6, 0x02, 0xdc, 0x39, 0x20, 0x0b, 0xf6, 0x16, 0x62, 0x36, 0x55, 0x9f, 0xd1, 0x2a, 0x60, 0x89, 0x2a, 0xeb, 0x15, 0x3d, 0xd6, 0x51, 0xbb, 0x46, 0x99, 0x10, 0xb4, 0xb3, 0x46, 0x69, 0xf9, 0x1d, 0xa8, 0x65, 0x4d, 0x1e, 0xb7, 0x2e, 0xb6, 0xe0, 0x28, 0x00, 0xb3, 0xb0, 0xa7, 0xd0, 0xa4, 0x8c, 0x83, 0x68, 0x54, 0xd3, 0xa8, 0x3e, 0x65, 0x56, 0x9c, 0xb7, 0x23, 0x0b, 0xb4, 0x4f, 0x3f, 0x14, 0x3a, 0x6d, 0xec, 0x5f, 0x2c, 0x39, 0xab, 0x90, 0xf2, 0x74, 0xf2, 0x08, 0x8b, 0xd3, 0xd6, 0xa6, 0xfc, 0xa0, 0x07, 0x02, 0x73, 0xbe, 0xdc, 0x84, 0x77, 0x7f, 0xb5, 0x2e, 0x3c, 0x55, 0x8b, 0x0a, 0xe0, 0x61, 0x83, 0xd5, 0xa4, 0x8d, 0x45, 0x2f, 0x68, 0xe1, 0x52, 0x07, 0xf8, 0x61, 0x62, 0x7a, 0xca, 0x14, 0x27, 0x96, 0x30, 0xf8, 0x2e, 0xc3, 0xa0, 0xca, 0x07, 0x86, 0x33, 0xb6, 0x00, 0xaf, 0xa7, 0x97, 0x43, 0xa6, 0x00, 0x21, 0x5b, 0xe5, 0x63, 0x74, 0x58, 0xce, 0x2c, 0xe8, 0xaf, 0xf5, 0xa0, 0x8e, 0xb5, 0x01, 0x7b, 0x2c, 0x76, 0x65, 0x77, 0x47, 0x9f, 0x8d, 0xc6, 0xbf, 0x9f, 0x5c, 0xc7, 0x50, 0x89, 0x93, 0x21, 0x61, 0xb9, 0x6c, 0xea, 0x40, 0x66, 0x20, 0xae, 0xdb, 0x63, 0x04, 0x07, 0xf7, 0x68, 0x7e, 0xbb, 0xb4, 0x81, 0x4c, 0x79, 0x81, 0x63, 0x7a, 0x48, 0xa9, 0x0d, 0xe6, 0x80, 0x31, 0xe0, 0x62, 0xa7, 0xaf, 0x76, 0x12, 0xb4, 0xf5, 0xc7, 0xa6, 0xda, 0x86, 0xbd, 0x13, 0x65, 0x29, 0xe6, 0x42, 0x95, 0xa5, 0x61, 0x3e, 0xa7, 0x3b, 0xd3, 0xd4, 0x44, 0x8c, 0xb8, 0x1f, 0x24, 0x31, 0x35, 0xc0, 0xa6, 0x60, 0xbe, 0xb9, 0xc1, 0x7e, 0x65, 0x1d, 0xef, 0x46, 0x9a, 0x7d, 0x90, 0xa1, 0x5d, 0x34, 0x81, 0x09, 0x0b, 0xcb, 0xf2, 0x27, 0x01, 0x23, 0x28, 0x94, 0x1f, 0xa4, 0x6f, 0x39, 0xc5, 0x00, 0x6a, 0xd9, 0x3d, 0x45, 0x8a, 0xa6, 0xad, 0xd6, 0x55, 0x86, 0x2b, 0x41, 0x8c, 0x30, 0x94, 0xf5, 0x51, 0x46, 0x0d, 0xf2, 0x15, 0x3a, 0x58, 0x10, 0xa7, 0xda, 0x74, 0xf0, 0x61, 0x4c, 0x25, 0x88, 0xbe, 0x49, 0xdc, 0x6f, 0x5e, 0x88, 0x15, 0x46, 0x42, 0xbd, 0x1d, 0x37, 0x62, 0x56, 0x33, 0x26, 0x43, 0x35, 0x07, 0x15, 0x6a, 0x57, 0xc5, 0x76, 0x94, 0xbd, 0xd2, 0x6e, 0x7a, 0x24, 0x6f, 0xeb, 0x72, 0x3a, 0xed, 0x67, 0xb0, 0x48, 0x87, 0xc8, 0xe4, 0x76, 0xb4, 0x8c, 0xab, 0x59, 0xe5, 0x36, 0x2f, 0x26, 0xa9, 0xef, 0x50, 0xc2, 0xbc, 0x80, 0xba, 0x14, 0x62, 0x26, 0x21, 0x6f, 0xe6, 0x29, 0x68, 0xa6, 0x0d, 0x04, 0xe8, 0xc1, 0x70, 0xd7, 0x41, 0xc7, 0xa2, 0xb0, 0xe1, 0xab, 0xda, 0xc9, 0x68, 0xe2, 0x90, 0x20, 0x83, 0x9d, 0x05, 0x2f, 0xa3, 0x72, 0x58, 0x56, 0x27, 0xf8, 0xb5, 0x9e, 0xe3, 0x12, 0xae, 0x41, 0x4c, 0x97, 0x9d, 0x82, 0x5f, 0x06, 0xa6, 0x92, 0x9a, 0x79, 0x62, 0x57, 0x18, }, .pk_len = 1184, }, { .name = "ML-KEM 768 (seed only)", .parameter_set = CKP_IBM_ML_KEM_768, .priv_seed = { 0x48, 0xD3, 0x78, 0x9A, 0x21, 0x68, 0x6A, 0xE9, 0x63, 0x48, 0x63, 0x45, 0x64, 0x32, 0x83, 0xEB, 0x33, 0x69, 0x80, 0xC5, 0x50, 0x7A, 0xD5, 0x81, 0xF2, 0x49, 0xAB, 0x29, 0x45, 0x74, 0x75, 0x2F, 0x48, 0xC1, 0xE7, 0x78, 0xF3, 0x36, 0x6D, 0xB8, 0x80, 0x3E, 0xBE, 0x81, 0xF9, 0x53, 0xFD, 0x6E, 0xAB, 0x6A, 0x8F, 0xC8, 0xD4, 0x1C, 0x09, 0xCF, 0x59, 0x62, 0x3B, 0x54, 0x03, 0x2B, 0x0D, 0xB0 }, .priv_seed_len = 64, .spki = { 0x30, 0x82, 0x04, 0xb2, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x04, 0x02, 0x03, 0x82, 0x04, 0xa1, 0x00, 0x80, 0x3b, 0xa1, 0x95, 0x35, 0xca, 0xc5, 0xb6, 0x82, 0x7b, 0xfb, 0xb6, 0x0b, 0x8b, 0xa8, 0x96, 0xeb, 0x45, 0xbd, 0xf2, 0x06, 0xdc, 0x7b, 0x10, 0xdc, 0xe2, 0x6a, 0xe2, 0x09, 0x1f, 0xc8, 0x85, 0xbc, 0xb5, 0xb5, 0xa2, 0x5a, 0xf6, 0x54, 0x71, 0x27, 0x84, 0xf3, 0xac, 0xc3, 0xd7, 0x09, 0x7a, 0xf0, 0x77, 0x3e, 0xb5, 0x20, 0x68, 0xd8, 0x75, 0x74, 0xf9, 0x97, 0xa6, 0x2d, 0xdb, 0xca, 0xf8, 0xe0, 0xcf, 0x79, 0x3b, 0x74, 0xb1, 0x84, 0x28, 0x82, 0x31, 0x22, 0xf5, 0x99, 0x5d, 0x8b, 0x50, 0x5a, 0x7e, 0xb7, 0x92, 0x53, 0x89, 0x09, 0x6c, 0xbb, 0xcd, 0xb8, 0xb9, 0xcd, 0xa2, 0xa9, 0xa2, 0x48, 0xc3, 0x1d, 0x1c, 0xb1, 0xb5, 0x7b, 0x86, 0x63, 0x55, 0x53, 0x34, 0x37, 0xb9, 0xc3, 0xbf, 0xc3, 0x06, 0x6d, 0x09, 0x3c, 0x4b, 0xc8, 0xcf, 0xa1, 0x32, 0xcf, 0x0e, 0xb4, 0xb6, 0xbb, 0xb9, 0x40, 0x6b, 0x24, 0x43, 0xad, 0x13, 0x49, 0x0b, 0x32, 0xb5, 0xd1, 0xa7, 0x18, 0x13, 0x3b, 0x20, 0x60, 0x77, 0x8c, 0x9e, 0x03, 0x83, 0x50, 0xa1, 0xc0, 0x62, 0x24, 0x4c, 0x55, 0x2a, 0x33, 0xa9, 0x0a, 0x16, 0x53, 0xa1, 0x82, 0x5f, 0xec, 0xc9, 0xbf, 0xe1, 0xc7, 0x15, 0x16, 0x4b, 0xd4, 0x91, 0x94, 0x0c, 0x92, 0xb1, 0x62, 0x24, 0x57, 0x4d, 0x66, 0x98, 0x11, 0xe8, 0x1a, 0x9b, 0x44, 0x89, 0xd2, 0xf3, 0xbd, 0x97, 0x55, 0x55, 0x5f, 0x5b, 0x06, 0x07, 0xd8, 0x11, 0x49, 0xe1, 0x82, 0x5e, 0x51, 0x71, 0x3b, 0x78, 0x6c, 0x05, 0xe9, 0x28, 0x7f, 0xb5, 0xa2, 0x13, 0x75, 0x7a, 0xde, 0x22, 0x1b, 0x14, 0x77, 0x42, 0x9e, 0x9b, 0x9b, 0xe2, 0xb6, 0xc8, 0xb6, 0xa1, 0x66, 0x81, 0xa9, 0x5c, 0xa0, 0x43, 0xbb, 0xad, 0xe1, 0x7b, 0xbd, 0x7c, 0xa7, 0xb9, 0xf7, 0x07, 0x2c, 0xf1, 0x2c, 0x29, 0xf4, 0x59, 0xe0, 0x91, 0x62, 0x44, 0xca, 0x90, 0xb1, 0x4b, 0xb1, 0xae, 0xd1, 0xc8, 0xed, 0x35, 0x01, 0x68, 0xcc, 0x9b, 0xf8, 0x86, 0x22, 0xb8, 0x92, 0xc3, 0xb5, 0xf6, 0xc1, 0xed, 0xfa, 0x4e, 0x91, 0xd6, 0x92, 0xe2, 0x26, 0x0c, 0x40, 0xa7, 0xac, 0xed, 0x65, 0x12, 0xd4, 0x61, 0x1a, 0x00, 0xf0, 0x8d, 0xa7, 0x3c, 0x12, 0xec, 0x07, 0x50, 0x3b, 0xf8, 0xca, 0x5e, 0xa1, 0xb0, 0xed, 0xb8, 0x5b, 0x93, 0x01, 0x07, 0x26, 0x62, 0x60, 0x1b, 0xba, 0x88, 0xb6, 0xe7, 0xc3, 0x63, 0x97, 0x06, 0x66, 0xe2, 0x6e, 0x4d, 0x55, 0x60, 0x91, 0xa6, 0x8a, 0x44, 0x58, 0x28, 0xc6, 0x0b, 0xbf, 0x53, 0xd3, 0x38, 0x2b, 0x7c, 0x88, 0xe8, 0x6c, 0x44, 0x6f, 0xb5, 0xa4, 0x13, 0x6c, 0x79, 0x1c, 0xcb, 0x5d, 0xd7, 0x97, 0xc0, 0x68, 0xc2, 0xb0, 0x77, 0xc1, 0x5a, 0x51, 0xcb, 0x31, 0x8f, 0xa3, 0xa2, 0x23, 0xe5, 0x83, 0x12, 0x91, 0xc5, 0x03, 0x67, 0xb8, 0x8a, 0x32, 0x91, 0x0f, 0xca, 0x7a, 0x13, 0x00, 0x7d, 0x74, 0x01, 0x95, 0x0a, 0xaa, 0x2d, 0x42, 0x90, 0x9d, 0xed, 0xdb, 0x27, 0x47, 0xec, 0xb1, 0x87, 0x33, 0x62, 0x9e, 0x81, 0x10, 0xc7, 0x2b, 0x52, 0x65, 0xe3, 0xb2, 0xe8, 0x63, 0x71, 0x29, 0xe6, 0x28, 0x6f, 0xba, 0xb3, 0x0f, 0xd1, 0x50, 0xef, 0x66, 0xb5, 0x1c, 0x37, 0x28, 0x2a, 0x54, 0x88, 0x80, 0x78, 0x2d, 0xad, 0xbb, 0x73, 0x62, 0xfc, 0xa6, 0xb5, 0xc0, 0x87, 0x81, 0xe6, 0x9e, 0x82, 0xcc, 0xb5, 0x0e, 0x0a, 0x0c, 0xaf, 0xd0, 0x9c, 0xbf, 0x47, 0x80, 0x52, 0xa0, 0x30, 0x83, 0x28, 0xcb, 0x6a, 0xa1, 0xa2, 0x46, 0xf3, 0x34, 0x71, 0xc4, 0xb9, 0x39, 0xbc, 0x80, 0x8a, 0x97, 0x39, 0xa0, 0x09, 0x9e, 0x00, 0xb9, 0x68, 0xb4, 0xc2, 0x3f, 0x6d, 0x42, 0x09, 0x63, 0x26, 0xc4, 0x74, 0x5c, 0x57, 0x55, 0xd8, 0x1e, 0x0a, 0x39, 0xb7, 0xfe, 0x34, 0x49, 0x7b, 0x5b, 0xa2, 0xde, 0xaa, 0x10, 0xed, 0x60, 0x1e, 0x46, 0x28, 0x8d, 0xa4, 0x5a, 0xad, 0x8e, 0x63, 0x57, 0x37, 0xf0, 0x8c, 0xd4, 0x06, 0x2d, 0x2e, 0x66, 0x18, 0x69, 0xc5, 0x4c, 0xdb, 0xdb, 0xb2, 0xe0, 0x8b, 0x5b, 0x40, 0x4b, 0x18, 0x85, 0x71, 0xc8, 0x54, 0x84, 0xa9, 0xa2, 0xb3, 0x6f, 0x8b, 0xea, 0x7f, 0x4c, 0x2b, 0x6a, 0x78, 0xd9, 0x8d, 0x1d, 0x87, 0x25, 0x6e, 0xba, 0x06, 0xd0, 0x7a, 0x90, 0x4b, 0x57, 0x39, 0xf1, 0x16, 0x93, 0xfd, 0xc9, 0x35, 0x52, 0x76, 0x9f, 0xfd, 0x76, 0x87, 0x9a, 0xd3, 0x04, 0xbf, 0xb4, 0x0b, 0x37, 0x41, 0x29, 0x91, 0x0b, 0x1d, 0xf0, 0x60, 0x33, 0xde, 0x44, 0xab, 0x22, 0xa2, 0xce, 0xfa, 0x6a, 0xc0, 0x06, 0x04, 0xb0, 0x9e, 0x7a, 0x4c, 0x35, 0xdb, 0x26, 0x42, 0xd3, 0xaf, 0xd2, 0x01, 0xa3, 0xa9, 0xc4, 0xb8, 0x6f, 0x88, 0x15, 0xee, 0x23, 0x97, 0x02, 0x12, 0xc4, 0x8a, 0xab, 0x76, 0x5f, 0x31, 0x2e, 0xe2, 0xe9, 0x9b, 0x7d, 0x10, 0x6c, 0x9a, 0x70, 0xb6, 0x7b, 0xe5, 0x08, 0x13, 0x5a, 0x39, 0x0b, 0xcc, 0x65, 0x60, 0x02, 0xbd, 0x1c, 0x36, 0x0e, 0x27, 0xf2, 0x0d, 0xf8, 0x58, 0xbd, 0x3b, 0x5a, 0x62, 0x78, 0xa8, 0x95, 0xe5, 0xbc, 0x84, 0x7f, 0x72, 0x6f, 0x78, 0x67, 0x77, 0x8c, 0x71, 0x57, 0x1f, 0xcb, 0x2b, 0x82, 0x61, 0xa4, 0x6b, 0xf9, 0x60, 0x9f, 0x4b, 0x8d, 0x2a, 0x34, 0x93, 0x1d, 0x45, 0x84, 0x6a, 0xe4, 0xb6, 0x0d, 0x72, 0x6d, 0x2b, 0xc7, 0x72, 0x45, 0xb2, 0x2c, 0xe9, 0x8c, 0xac, 0x81, 0xa6, 0x18, 0xd2, 0xc7, 0xaa, 0x1e, 0x77, 0x76, 0xda, 0x27, 0x49, 0x02, 0xb5, 0x2e, 0x53, 0x25, 0xbb, 0x39, 0x06, 0x17, 0x4c, 0x87, 0x72, 0x85, 0x85, 0x10, 0xa3, 0x60, 0x4a, 0xe8, 0x9b, 0x69, 0x97, 0xab, 0x1e, 0x26, 0x67, 0x45, 0x98, 0xd8, 0x23, 0x6e, 0x6c, 0xb1, 0x18, 0x5b, 0x72, 0xfc, 0xd9, 0x25, 0x7d, 0x56, 0x73, 0xfb, 0x06, 0x1a, 0x37, 0x94, 0x19, 0x36, 0xc5, 0x43, 0xff, 0x37, 0x0c, 0x1d, 0xa3, 0xb1, 0xeb, 0xfc, 0x09, 0x94, 0xfa, 0x0e, 0x3d, 0xd6, 0x06, 0x2a, 0x8c, 0x9c, 0xa3, 0x75, 0x20, 0xd9, 0x53, 0x91, 0xd7, 0xeb, 0x47, 0xea, 0xe2, 0x50, 0x91, 0xfb, 0x42, 0x36, 0x94, 0x53, 0x0a, 0x05, 0xbc, 0xcb, 0x28, 0xb9, 0x54, 0xe7, 0x55, 0xd9, 0x28, 0x94, 0x02, 0x1b, 0x1d, 0x04, 0x10, 0xaf, 0x78, 0xc9, 0x0b, 0xc0, 0x02, 0xb6, 0x65, 0x29, 0x13, 0x32, 0x02, 0x3d, 0x76, 0x67, 0xab, 0x15, 0x07, 0xc8, 0x08, 0xfc, 0x73, 0x1d, 0x02, 0xb4, 0x1c, 0x73, 0x40, 0xe4, 0x51, 0x33, 0xe0, 0x30, 0x60, 0x5a, 0x91, 0x5e, 0x7c, 0x73, 0x07, 0xa4, 0x76, 0x60, 0x1c, 0xc9, 0x24, 0x19, 0x52, 0x6c, 0xaa, 0x14, 0xa7, 0x81, 0xa0, 0x76, 0xe0, 0xac, 0x1f, 0x5b, 0xe0, 0x70, 0x1b, 0xcb, 0xad, 0xe6, 0x28, 0x6e, 0x95, 0x62, 0xc7, 0x70, 0x84, 0x1a, 0x9c, 0x45, 0xa1, 0xd6, 0x60, 0x88, 0x22, 0xf2, 0x99, 0xd4, 0x92, 0x9f, 0xfe, 0x66, 0x1e, 0x89, 0xc0, 0xb7, 0x97, 0xf5, 0x9d, 0xd3, 0x94, 0xa3, 0x13, 0x75, 0x9f, 0x6b, 0x73, 0xb7, 0xac, 0x9c, 0x36, 0x27, 0xa4, 0x9b, 0x31, 0xb2, 0xc5, 0xf3, 0x7a, 0x68, 0x63, 0x26, 0x31, 0x25, 0x4a, 0x94, 0xa4, 0x71, 0x68, 0x94, 0x92, 0x6f, 0xbf, 0x90, 0xb4, 0x0b, 0x6c, 0x18, 0x53, 0xd9, 0x1f, 0x04, 0x09, 0x4a, 0x7f, 0xa5, 0x89, 0xd4, 0x10, 0xbd, 0x67, 0xe4, 0x35, 0xff, 0xe2, 0x9d, 0x07, 0x98, 0xc3, 0xae, 0x92, 0xca, 0x6d, 0x28, 0x78, 0x2a, 0x56, 0x2d, 0x19, 0x11, 0xb1, 0x59, 0x94, 0xb0, 0x99, 0xf0, 0x88, 0x39, 0xd8, 0xb4, 0x4b, 0x70, 0xc5, 0xde, 0xa7, 0x78, 0x46, 0x80, 0x5b, 0xf5, 0x57, 0x07, 0x26, 0x30, 0x7d, 0x64, 0xac, 0xbf, 0x5a, 0x86, 0x81, 0x9f, 0x71, 0x5e, 0xa0, 0x7b, 0x5b, 0x1b, 0x14, 0x09, 0x9c, 0xd7, 0x07, 0xc3, 0xc9, 0x15, 0xb4, 0x79, 0x9a, 0xc2, 0x81, 0x46, 0xc6, 0xc3, 0xad, 0x6b, 0x4a, 0x75, 0xa3, 0x5a, 0x51, 0xaa, 0x6c, 0x36, 0x1c, 0xe4, 0x6d, 0xec, 0x82, 0x75, 0x35, 0x69, 0x47, 0xef, 0x69, 0x18, 0xd6, 0x30, 0x85, 0xa5, 0x27, 0x5d, 0xee, 0x02, 0xa1, 0x72, 0x14, 0x48, 0xe9, 0xc1, 0x0e, 0x1a, 0x32, 0x6c, 0x0a, 0x38, 0x26, 0x49, 0x91, 0x2a, 0x36, 0xf3, 0x95, 0xa4, 0x68, 0x3c, 0xbe, 0xb2, 0x82, 0x50, 0xf5, 0x87, 0x06, 0xc2, 0x9c, 0x36, 0x0a, 0x24, 0x82, 0x81, 0x4f, 0x09, 0x5a, 0x6c, 0x90, 0xe5, 0x60, 0x0d, 0x9f, 0xbb, 0x1e, 0xaa, 0xc2, 0x3f, 0x15, 0x5e, 0xce, 0x53, 0x0e, 0xe2, 0xc7, 0x5b, 0xe8, 0x45, 0x9c, 0x89, 0xe4, 0x8c, 0x1f, 0x29, 0x25, 0x25, 0xe7, 0x6e, 0xc4, 0xb6, 0x83, 0x89, 0x25 }, .spki_len = 1206, }, { .name = "ML-KEM 1024 (PKCS#8/SPKI - seed only)", .pkcs8 = { 0x30, 0x54, 0x02, 0x01, 0x00, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x04, 0x03, 0x04, 0x42, 0x80, 0x40, 0xbe, 0xba, 0x64, 0x0e, 0x5e, 0x21, 0x4e, 0x2a, 0x2a, 0xf8, 0xd2, 0x61, 0xdc, 0xdc, 0x80, 0x34, 0xa3, 0x20, 0xf9, 0xd6, 0xe2, 0x17, 0x56, 0xec, 0x59, 0x22, 0xf9, 0x05, 0x62, 0x25, 0xd2, 0xb0, 0x0a, 0x28, 0x2c, 0x21, 0x49, 0xc5, 0x7b, 0xb8, 0xf9, 0x4b, 0x94, 0x82, 0x2a, 0x62, 0xcd, 0x01, 0x47, 0x1b, 0xaf, 0x25, 0xdd, 0xe5, 0x22, 0xa4, 0x26, 0x7c, 0x17, 0x34, 0x43, 0x54, 0xde, 0x67 }, .pkcs8_len = 86, .spki = { 0x30, 0x82, 0x06, 0x32, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x04, 0x03, 0x03, 0x82, 0x06, 0x21, 0x00, 0xc8, 0x27, 0xc8, 0xd4, 0x96, 0xb4, 0x0b, 0x85, 0xc6, 0xb8, 0xc6, 0xa8, 0x89, 0x81, 0x2b, 0xf3, 0x21, 0xcf, 0x0e, 0xe5, 0x42, 0x0a, 0xc1, 0xac, 0x99, 0x14, 0x8f, 0x7b, 0x15, 0x80, 0x4e, 0x06, 0xc9, 0xdd, 0x43, 0x3d, 0x51, 0xd9, 0x5e, 0xe3, 0x70, 0xb9, 0x8b, 0x38, 0x1a, 0xf3, 0x1c, 0x34, 0x6d, 0x73, 0x0a, 0x9e, 0x96, 0x9c, 0xa9, 0x23, 0xb9, 0x00, 0x76, 0xbb, 0xf8, 0x43, 0x26, 0x53, 0xa6, 0xcc, 0x96, 0x87, 0x5e, 0x0a, 0x9c, 0x1a, 0x11, 0xc4, 0x71, 0x6d, 0x14, 0xb8, 0xf4, 0xc7, 0x78, 0x34, 0xea, 0x57, 0x1b, 0xf3, 0x98, 0x7d, 0xf5, 0x1a, 0x74, 0x12, 0x15, 0xfe, 0x93, 0x72, 0xbc, 0xd5, 0x50, 0xdb, 0x91, 0x27, 0x83, 0x25, 0x8d, 0x52, 0xe3, 0x58, 0xfe, 0x48, 0x1d, 0xe8, 0x36, 0xcb, 0xc6, 0xd2, 0x62, 0x46, 0xb4, 0x05, 0x9d, 0x3c, 0xb4, 0x3d, 0x5a, 0x64, 0xb0, 0x20, 0xb3, 0xa0, 0xe7, 0x1d, 0x45, 0xe6, 0xb1, 0x76, 0x65, 0x04, 0xd1, 0x9a, 0x36, 0xc5, 0xc8, 0x46, 0x8e, 0xa1, 0x88, 0x97, 0x3a, 0x61, 0xde, 0x79, 0x4e, 0xcf, 0x94, 0x94, 0x14, 0x32, 0x8e, 0xd9, 0x60, 0x5e, 0x5a, 0xc1, 0x26, 0x7c, 0x37, 0x44, 0x15, 0x7b, 0x42, 0xe4, 0x26, 0x31, 0x70, 0x17, 0xc1, 0x40, 0xca, 0x7a, 0x9a, 0x6b, 0x40, 0x0f, 0xf0, 0x83, 0x7b, 0x52, 0xbe, 0x2d, 0xe0, 0x3e, 0xdb, 0xb1, 0xa1, 0x4d, 0xda, 0x05, 0xf0, 0xe2, 0x14, 0x38, 0xb3, 0xbb, 0xe5, 0x2b, 0x1f, 0xd2, 0x4c, 0xbc, 0xe9, 0x7b, 0xb6, 0xa2, 0x10, 0x6d, 0x51, 0xf4, 0x34, 0xc6, 0x13, 0xcd, 0xd6, 0xc7, 0xc8, 0x5c, 0x94, 0xb6, 0x8a, 0xe6, 0x73, 0xf4, 0x44, 0x30, 0x72, 0x41, 0x24, 0xb1, 0xa5, 0xcd, 0xa3, 0x07, 0xcd, 0x5d, 0xc6, 0x8a, 0xd3, 0x20, 0x1d, 0x2a, 0x76, 0x97, 0x85, 0xab, 0x2d, 0x2b, 0xd7, 0x06, 0xf1, 0x33, 0x14, 0x9f, 0xf7, 0xb8, 0x09, 0x7c, 0x30, 0xbe, 0x24, 0xcd, 0x87, 0x23, 0x8b, 0xb6, 0x11, 0xaa, 0x8e, 0xb9, 0x05, 0xe6, 0xb9, 0xb1, 0x97, 0xb2, 0x63, 0xb1, 0x92, 0x52, 0x2f, 0x9a, 0x3a, 0x41, 0x67, 0x8f, 0xc9, 0x00, 0x24, 0x00, 0x8d, 0xaf, 0x79, 0xb2, 0x9e, 0xfe, 0x8b, 0x24, 0xeb, 0xc5, 0x0d, 0x2a, 0x47, 0x22, 0x4a, 0x2c, 0x23, 0x34, 0x66, 0xcb, 0x81, 0x33, 0x02, 0xa9, 0x34, 0xb1, 0x96, 0x35, 0x93, 0x68, 0x95, 0x7f, 0xab, 0xec, 0x35, 0x1a, 0x05, 0xb7, 0x0d, 0x16, 0x30, 0x1f, 0xd5, 0x4e, 0x9b, 0x90, 0x02, 0x11, 0x28, 0x6b, 0xc9, 0x55, 0x92, 0x10, 0xf3, 0x8b, 0x08, 0x44, 0x09, 0x01, 0x38, 0x2c, 0x23, 0xf7, 0x41, 0x60, 0x47, 0xc7, 0x19, 0xc6, 0xab, 0x2b, 0xbc, 0x96, 0x35, 0x78, 0x83, 0xd0, 0x60, 0x34, 0x11, 0x58, 0xa5, 0x9b, 0xc8, 0x7c, 0xc8, 0x5c, 0x34, 0xbd, 0xac, 0x7f, 0xdd, 0xa8, 0xaf, 0x62, 0xe4, 0x27, 0x82, 0x29, 0x6e, 0x03, 0xb1, 0x61, 0x37, 0xc6, 0x39, 0x82, 0x78, 0x6e, 0x16, 0x05, 0xa4, 0x08, 0xa3, 0xcd, 0xa2, 0xc7, 0xc6, 0xab, 0xf0, 0x90, 0x6d, 0xa6, 0xac, 0x58, 0xe4, 0x31, 0xb7, 0x66, 0x57, 0xd4, 0x81, 0x20, 0xcb, 0x8a, 0x22, 0x58, 0xb0, 0xae, 0xf0, 0x50, 0x77, 0x08, 0x63, 0x6e, 0xc6, 0x21, 0x93, 0x03, 0x40, 0x84, 0x1e, 0xcb, 0x0b, 0x4d, 0xe1, 0x22, 0xa9, 0x8a, 0x47, 0xa5, 0xd1, 0x63, 0x5c, 0xc5, 0x7f, 0x6a, 0x45, 0xb8, 0x39, 0xb3, 0x31, 0x22, 0xe9, 0x79, 0xd9, 0x28, 0x9d, 0x04, 0xa4, 0xa3, 0x30, 0x12, 0x23, 0x10, 0x7b, 0x94, 0xb5, 0x66, 0x26, 0x88, 0x73, 0xa3, 0x61, 0x41, 0x4d, 0xc3, 0x84, 0x68, 0xd8, 0x98, 0x9d, 0x7f, 0xba, 0x31, 0xe0, 0x5a, 0x5d, 0x4b, 0x6b, 0xb2, 0x9a, 0x84, 0x12, 0x9e, 0x15, 0x58, 0x79, 0x09, 0x70, 0xcc, 0xe6, 0x5d, 0x61, 0x51, 0x70, 0xd4, 0x5c, 0x50, 0x6d, 0x95, 0x52, 0x14, 0x10, 0x95, 0x01, 0x81, 0xcd, 0x0c, 0xe8, 0x1a, 0x58, 0xa3, 0x9f, 0x01, 0xac, 0x8a, 0xbc, 0xc6, 0x88, 0x75, 0x35, 0x39, 0x69, 0x80, 0x54, 0xdd, 0x2b, 0x4b, 0xb0, 0x1b, 0x5d, 0xbd, 0x5c, 0x67, 0xb8, 0xfc, 0x3b, 0x0b, 0xf6, 0x32, 0x7e, 0x9c, 0x6d, 0x4d, 0x13, 0x81, 0xec, 0x15, 0x4c, 0xb1, 0x99, 0xbc, 0xe6, 0xdb, 0x58, 0x77, 0xf3, 0x83, 0x4a, 0xa8, 0x0f, 0x84, 0x14, 0x63, 0xa9, 0x70, 0x2d, 0xd7, 0x23, 0x3f, 0xc5, 0x91, 0x6b, 0x49, 0xc0, 0x00, 0x7c, 0x52, 0xa6, 0xc5, 0x3a, 0x88, 0xca, 0xfa, 0x49, 0xa3, 0x39, 0x3b, 0xa3, 0xd3, 0x21, 0xac, 0x52, 0xb4, 0xa0, 0xe9, 0xc0, 0xb1, 0x31, 0x35, 0xcf, 0x1c, 0x66, 0x38, 0x51, 0x60, 0x10, 0xdb, 0x3d, 0x80, 0x25, 0xa0, 0x29, 0x4c, 0xc7, 0x13, 0x5c, 0x7b, 0xa8, 0xb1, 0x46, 0x70, 0xa8, 0xbb, 0x9b, 0xdc, 0xc6, 0xb2, 0x9a, 0x51, 0x3b, 0x22, 0x35, 0xcf, 0x92, 0xaf, 0x27, 0x5b, 0x09, 0x1d, 0x24, 0x3c, 0x85, 0x16, 0xa5, 0xb9, 0xc4, 0x67, 0x3a, 0x47, 0x6b, 0x7f, 0x19, 0x40, 0xc3, 0x57, 0xb7, 0x1c, 0xe0, 0xc3, 0x80, 0xec, 0xbe, 0xe5, 0x74, 0x44, 0xdb, 0xd0, 0x8f, 0xe9, 0x12, 0x08, 0x1c, 0x44, 0xac, 0xa4, 0x32, 0xb4, 0xb0, 0x1a, 0x68, 0x10, 0x4c, 0x99, 0xe0, 0x97, 0xb5, 0x6c, 0x51, 0x9c, 0xac, 0x38, 0xaf, 0xa7, 0xf2, 0x5d, 0x68, 0xc9, 0x93, 0xd2, 0x46, 0x4a, 0xe1, 0x75, 0x4a, 0xf4, 0xd4, 0x12, 0xdf, 0xc4, 0x42, 0x4b, 0xb4, 0x6f, 0x35, 0x0c, 0x0b, 0xcc, 0xe6, 0x90, 0xad, 0x8b, 0xac, 0xce, 0xf4, 0x11, 0x63, 0x7c, 0x43, 0x00, 0x7b, 0x5c, 0xb9, 0x02, 0x2e, 0x2b, 0x46, 0xc2, 0x8b, 0x91, 0x9e, 0x26, 0xa9, 0xb7, 0xe8, 0xa1, 0xbb, 0x1c, 0xb7, 0xc4, 0x89, 0x43, 0x33, 0x16, 0x20, 0xb5, 0x84, 0xd4, 0xcb, 0x39, 0x98, 0x91, 0x2d, 0x47, 0x9e, 0xaf, 0x4c, 0x7f, 0x51, 0x82, 0x5f, 0x20, 0xf4, 0x63, 0xf4, 0x08, 0x76, 0xb2, 0x5c, 0x03, 0x1a, 0x07, 0xa3, 0x38, 0x39, 0x8e, 0x41, 0xa1, 0xa2, 0x20, 0x16, 0x99, 0x9d, 0xd3, 0x02, 0x83, 0x61, 0x4c, 0x48, 0x67, 0x6e, 0xef, 0x86, 0x75, 0x4f, 0x11, 0x3a, 0x31, 0x75, 0x45, 0x9f, 0x3b, 0xb3, 0x1e, 0x6c, 0x29, 0x1d, 0xe8, 0x9f, 0xd2, 0xa0, 0xbd, 0xbc, 0x14, 0xbb, 0x83, 0x55, 0x0c, 0x44, 0xd5, 0xbf, 0x56, 0xb6, 0xc1, 0x49, 0x8a, 0x94, 0xc1, 0x35, 0x34, 0x32, 0xba, 0x24, 0xcf, 0x36, 0x9c, 0x96, 0x84, 0x81, 0x21, 0xb1, 0x6d, 0x33, 0x5a, 0x62, 0x7e, 0x20, 0xba, 0xdb, 0xc5, 0x54, 0xda, 0x33, 0x26, 0xbc, 0x28, 0x1e, 0xa2, 0xba, 0x37, 0xa9, 0x64, 0x7d, 0x1d, 0xeb, 0x5b, 0x22, 0x53, 0x3e, 0x2a, 0xd3, 0xc3, 0xd2, 0xa3, 0xb1, 0x2f, 0xdb, 0x47, 0xb4, 0xba, 0x47, 0x67, 0x37, 0x26, 0x0d, 0x11, 0x6f, 0x80, 0x15, 0x54, 0x6c, 0x03, 0x19, 0xf4, 0xd8, 0x5a, 0x46, 0x55, 0x8c, 0x9f, 0xa5, 0x1c, 0xd4, 0xb7, 0x35, 0x6c, 0x96, 0x93, 0x61, 0x72, 0xa8, 0xa6, 0xa6, 0xb2, 0x30, 0x03, 0xc7, 0x91, 0xfc, 0xce, 0x3b, 0x7b, 0xac, 0x77, 0x69, 0xbc, 0x82, 0xf7, 0x7b, 0xfd, 0x68, 0x15, 0x01, 0xb2, 0x72, 0x84, 0xd9, 0xb0, 0x6f, 0x56, 0x6c, 0xe4, 0x2a, 0x95, 0x71, 0x12, 0x72, 0x2d, 0xf5, 0x77, 0x76, 0xa7, 0xba, 0xa7, 0x44, 0x78, 0xad, 0xba, 0x40, 0x6e, 0x85, 0x68, 0x5d, 0x66, 0x66, 0xfc, 0xba, 0xa7, 0x91, 0xc6, 0x7b, 0x38, 0xe4, 0x8a, 0x64, 0xb8, 0x7b, 0x1e, 0x71, 0x49, 0x23, 0x25, 0x66, 0x12, 0x71, 0x9f, 0x67, 0x21, 0x30, 0xe5, 0x41, 0x0a, 0x1b, 0x91, 0x2b, 0x10, 0xf9, 0xcd, 0xe8, 0xcc, 0x51, 0x50, 0x29, 0x1a, 0x94, 0x6c, 0x4b, 0x1c, 0x0b, 0xbc, 0x8d, 0xac, 0x49, 0x69, 0x57, 0x12, 0xa5, 0x76, 0x66, 0x4f, 0x57, 0xaf, 0xfb, 0x71, 0x90, 0x19, 0x58, 0x90, 0x8e, 0x0c, 0x1f, 0x17, 0x86, 0xaa, 0x00, 0x8a, 0xb9, 0xb8, 0x69, 0xa5, 0x1e, 0x1a, 0x8f, 0xf9, 0xb8, 0x6d, 0x33, 0xcc, 0x34, 0xb1, 0x95, 0x77, 0xcd, 0x1b, 0x7b, 0x29, 0xc3, 0xb6, 0xe5, 0xaa, 0x07, 0x46, 0x4a, 0x97, 0x57, 0x98, 0x8a, 0x28, 0x6a, 0x02, 0x42, 0xac, 0x50, 0x8c, 0x39, 0xce, 0xf1, 0x05, 0xa9, 0x02, 0x70, 0x78, 0xd3, 0x1c, 0x97, 0x04, 0x5b, 0xa4, 0x22, 0xa4, 0x2f, 0xf7, 0x06, 0x53, 0xca, 0x77, 0x8c, 0xe0, 0xd4, 0x07, 0x82, 0x12, 0xce, 0xbd, 0x99, 0x06, 0x22, 0x93, 0xc2, 0x1b, 0x76, 0x46, 0x90, 0xeb, 0x62, 0x09, 0xb9, 0x7d, 0x41, 0x63, 0x73, 0xb2, 0x83, 0x0d, 0x61, 0x34, 0x65, 0x24, 0x38, 0x1b, 0x47, 0xe2, 0xc3, 0xf9, 0x3b, 0x12, 0x70, 0xa7, 0x03, 0xe3, 0x21, 0x97, 0x52, 0xe8, 0x1c, 0xd7, 0xfb, 0xcf, 0x79, 0x09, 0x71, 0x29, 0x59, 0x12, 0x55, 0x52, 0x59, 0xc1, 0xdb, 0x9a, 0xaf, 0xb8, 0x8c, 0x01, 0x60, 0x51, 0xa7, 0xf0, 0x24, 0x10, 0xf6, 0x09, 0xe1, 0xb6, 0x58, 0x28, 0x16, 0x3d, 0xa4, 0x5c, 0x6c, 0x57, 0xd3, 0x0d, 0xa0, 0xda, 0x43, 0x43, 0xa8, 0xca, 0xd5, 0x4a, 0x98, 0xc4, 0xa6, 0x23, 0x63, 0x52, 0x88, 0x10, 0xd9, 0xb2, 0x75, 0xea, 0x16, 0xf0, 0x65, 0x27, 0x20, 0xb4, 0x9a, 0xe3, 0xf4, 0x9c, 0x0a, 0xf5, 0x07, 0x77, 0x77, 0x40, 0x31, 0x1a, 0xcc, 0xd8, 0x63, 0xcc, 0xa3, 0xd8, 0xad, 0x30, 0x33, 0x9a, 0x55, 0x97, 0x53, 0xac, 0xa6, 0xa9, 0xd8, 0x11, 0xb6, 0x30, 0xab, 0x3b, 0xd1, 0x75, 0x5d, 0xa3, 0x07, 0x44, 0xcf, 0xd7, 0x99, 0x4d, 0x97, 0x1b, 0x72, 0x43, 0xca, 0x7a, 0xc9, 0xaa, 0xaa, 0xf5, 0x7c, 0x82, 0x31, 0x21, 0xfa, 0x29, 0xb1, 0xd3, 0x42, 0xbd, 0xc6, 0xb9, 0x90, 0x1d, 0x32, 0xa9, 0xfc, 0x11, 0x4c, 0x04, 0xb8, 0x3f, 0x7e, 0x3c, 0x4d, 0xd9, 0x6c, 0x4a, 0xe5, 0x92, 0x47, 0x6c, 0xc9, 0x90, 0x02, 0xb1, 0x77, 0xa4, 0xab, 0x19, 0x97, 0x31, 0x3c, 0x7e, 0x37, 0x1a, 0x13, 0x82, 0xcf, 0x86, 0x73, 0x22, 0x1a, 0xfa, 0x80, 0x0a, 0x10, 0x40, 0x53, 0xe6, 0xcd, 0xf1, 0x89, 0x1e, 0xd1, 0xd4, 0x6a, 0x9f, 0x1b, 0x71, 0x55, 0x06, 0x0c, 0xe0, 0x81, 0x62, 0x3a, 0xd1, 0x8b, 0x8b, 0xe5, 0xa7, 0x1c, 0xb4, 0x6d, 0x10, 0x4c, 0x11, 0x58, 0xe7, 0x95, 0x9a, 0x1c, 0xbf, 0x0b, 0x57, 0x87, 0x18, 0x0b, 0x89, 0xad, 0x0b, 0x2c, 0x24, 0xf5, 0x18, 0x66, 0x0b, 0x6c, 0x32, 0xa4, 0x0a, 0xd9, 0xd1, 0x72, 0x25, 0x29, 0xc5, 0x7c, 0x59, 0x4c, 0xce, 0x48, 0x59, 0x6a, 0x41, 0x21, 0x7f, 0xf0, 0xb3, 0xe9, 0x4b, 0x6b, 0xa5, 0xe0, 0x72, 0x9d, 0x3c, 0xa1, 0xce, 0x88, 0x01, 0x81, 0xb8, 0x92, 0x98, 0x03, 0x47, 0x6c, 0x50, 0x5e, 0x43, 0x53, 0x1f, 0x6d, 0x01, 0xc4, 0x22, 0xd3, 0x5c, 0x93, 0x61, 0x2b, 0x0d, 0xe0, 0xb0, 0x0d, 0x38, 0x5b, 0xc3, 0x73, 0xa1, 0xa9, 0x99, 0x5a, 0x76, 0x3b, 0x6e, 0x5d, 0x5a, 0xa4, 0xd9, 0x86, 0x0e, 0x68, 0x66, 0xa4, 0xf5, 0x58, 0x8f, 0x88, 0xf4, 0xbb, 0x1c, 0x09, 0xa8, 0x6e, 0xf4, 0x94, 0x61, 0x70, 0x5f, 0x4f, 0x83, 0x49, 0x94, 0xf7, 0xb8, 0x41, 0xe8, 0x08, 0x1d, 0x75, 0x23, 0x16, 0x66, 0x3b, 0xc6, 0x49, 0x52, 0xdf, 0x51, 0x7d, 0xd5, 0x1c, 0x41, 0x35, 0x3a, 0x64, 0x2a, 0xe4, 0xcb, 0x6f, 0xe3, 0xb0, 0xb7, 0x9e, 0x36, 0xa1, 0xfd, 0xdf, 0xee, 0x17, 0x41, 0xe1, 0x6e, 0x88, 0xc3, 0xf1, 0x1c, 0x65, 0x61, 0x33, 0xfd, 0x50, 0x67, 0x25, 0xc2, 0x38, 0x07, 0x55, 0xac, 0x45, 0xdb }, .spki_len = 1590, }, { .name = "ML-KEM 1024", .parameter_set = CKP_IBM_ML_KEM_1024, .sk = { 0x8c, 0x8b, 0x37, 0x22, 0xa8, 0x2e, 0x55, 0x05, 0x65, 0x52, 0x16, 0x11, 0xeb, 0xbc, 0x63, 0x07, 0x99, 0x44, 0xc9, 0xb1, 0xab, 0xb3, 0xb0, 0x02, 0x0f, 0xf1, 0x2f, 0x63, 0x18, 0x91, 0xa9, 0xc4, 0x68, 0xd3, 0xa6, 0x7b, 0xf6, 0x27, 0x12, 0x80, 0xda, 0x58, 0xd0, 0x3c, 0xb0, 0x42, 0xb3, 0xa4, 0x61, 0x44, 0x16, 0x37, 0xf9, 0x29, 0xc2, 0x73, 0x46, 0x9a, 0xd1, 0x53, 0x11, 0xe9, 0x10, 0xde, 0x18, 0xcb, 0x95, 0x37, 0xba, 0x1b, 0xe4, 0x2e, 0x98, 0xbb, 0x59, 0xe4, 0x98, 0xa1, 0x3f, 0xd4, 0x40, 0xd0, 0xe6, 0x9e, 0xe8, 0x32, 0xb4, 0x5c, 0xd9, 0x5c, 0x38, 0x21, 0x77, 0xd6, 0x70, 0x96, 0xa1, 0x8c, 0x07, 0xf1, 0x78, 0x16, 0x63, 0x65, 0x1b, 0xdc, 0xac, 0x90, 0xde, 0xda, 0x3d, 0xdd, 0x14, 0x34, 0x85, 0x86, 0x41, 0x81, 0xc9, 0x1f, 0xa2, 0x08, 0x0f, 0x6d, 0xab, 0x3f, 0x86, 0x20, 0x4c, 0xeb, 0x64, 0xa7, 0xb4, 0x44, 0x68, 0x95, 0xc0, 0x39, 0x87, 0xa0, 0x31, 0xcb, 0x4b, 0x6d, 0x9e, 0x04, 0x62, 0xfd, 0xa8, 0x29, 0x17, 0x2b, 0x6c, 0x01, 0x2c, 0x63, 0x8b, 0x29, 0xb5, 0xcd, 0x75, 0xa2, 0xc9, 0x30, 0xa5, 0x59, 0x6a, 0x31, 0x81, 0xc3, 0x3a, 0x22, 0xd5, 0x74, 0xd3, 0x02, 0x61, 0x19, 0x6b, 0xc3, 0x50, 0x73, 0x8d, 0x4f, 0xd9, 0x18, 0x3a, 0x76, 0x33, 0x36, 0x24, 0x3a, 0xce, 0xd9, 0x9b, 0x32, 0x21, 0xc7, 0x1d, 0x88, 0x66, 0x89, 0x5c, 0x4e, 0x52, 0xc1, 0x19, 0xbf, 0x32, 0x80, 0xda, 0xf8, 0x0a, 0x95, 0xe1, 0x52, 0x09, 0xa7, 0x95, 0xc4, 0x43, 0x5f, 0xbb, 0x35, 0x70, 0xfd, 0xb8, 0xaa, 0x9b, 0xf9, 0xae, 0xfd, 0x43, 0xb0, 0x94, 0xb7, 0x81, 0xd5, 0xa8, 0x11, 0x36, 0xda, 0xb8, 0x8b, 0x87, 0x99, 0x69, 0x65, 0x56, 0xfe, 0xc6, 0xae, 0x14, 0xb0, 0xbb, 0x8b, 0xe4, 0x69, 0x5e, 0x9a, 0x12, 0x4c, 0x2a, 0xb8, 0xff, 0x4a, 0xb1, 0x22, 0x9b, 0x8a, 0xaa, 0x8c, 0x6f, 0x41, 0xa6, 0x0c, 0x34, 0xc7, 0xb5, 0x61, 0x82, 0xc5, 0x5c, 0x2c, 0x68, 0x5e, 0x73, 0x7c, 0x6c, 0xa0, 0x0a, 0x23, 0xfb, 0x8a, 0x68, 0xc1, 0xcd, 0x61, 0xf3, 0x0d, 0x39, 0x93, 0xa1, 0x65, 0x3c, 0x16, 0x75, 0xac, 0x5f, 0x09, 0x01, 0xa7, 0x16, 0x0a, 0x73, 0x96, 0x64, 0x08, 0xb8, 0x87, 0x6b, 0x71, 0x53, 0x96, 0xcf, 0xa4, 0x90, 0x3f, 0xc6, 0x9d, 0x60, 0x49, 0x1f, 0x81, 0x46, 0x80, 0x8c, 0x97, 0xcd, 0x5c, 0x53, 0x3e, 0x71, 0x01, 0x79, 0x09, 0xe9, 0x7b, 0x83, 0x5b, 0x86, 0xff, 0x84, 0x7b, 0x42, 0xa6, 0x96, 0x37, 0x54, 0x35, 0xe0, 0x06, 0x06, 0x1c, 0xf7, 0xa4, 0x79, 0x46, 0x32, 0x72, 0x11, 0x4a, 0x89, 0xeb, 0x3e, 0xaf, 0x22, 0x46, 0xf0, 0xf8, 0xc1, 0x04, 0xa1, 0x49, 0x86, 0x82, 0x8e, 0x0a, 0xd2, 0x04, 0x20, 0xc9, 0xb3, 0x7e, 0xa2, 0x3f, 0x5c, 0x51, 0x49, 0x49, 0xe7, 0x7a, 0xd9, 0xe9, 0xad, 0x12, 0x29, 0x0d, 0xd1, 0x21, 0x5e, 0x11, 0xda, 0x27, 0x44, 0x57, 0xac, 0x86, 0xb1, 0xce, 0x68, 0x64, 0xb1, 0x22, 0x67, 0x7f, 0x37, 0x18, 0xaa, 0x31, 0xb0, 0x25, 0x80, 0xe6, 0x43, 0x17, 0x17, 0x8d, 0x38, 0xf2, 0x5f, 0x60, 0x9b, 0xc6, 0xc5, 0x5b, 0xc3, 0x74, 0xa1, 0xbf, 0x78, 0xea, 0x8e, 0xcc, 0x21, 0x9b, 0x30, 0xb7, 0x4c, 0xbb, 0x32, 0x72, 0xa5, 0x99, 0x23, 0x8c, 0x93, 0x98, 0x51, 0x70, 0x04, 0x8f, 0x17, 0x67, 0x75, 0xfb, 0x19, 0x96, 0x2a, 0xc3, 0xb1, 0x35, 0xaa, 0x59, 0xdb, 0x10, 0x4f, 0x71, 0x14, 0xdb, 0xc2, 0xc2, 0xd4, 0x29, 0x49, 0xad, 0xec, 0xa6, 0xa8, 0x5b, 0x32, 0x3e, 0xe2, 0xb2, 0xb2, 0x3a, 0x77, 0xd9, 0xdb, 0x23, 0x59, 0x79, 0xa8, 0xe2, 0xd6, 0x7c, 0xf7, 0xd2, 0x13, 0x6b, 0xbb, 0xa7, 0x1f, 0x26, 0x95, 0x74, 0xb3, 0x88, 0x88, 0xe1, 0x54, 0x13, 0x40, 0xc1, 0x92, 0x84, 0x07, 0x4f, 0x9b, 0x7c, 0x8c, 0xf3, 0x7e, 0xb0, 0x13, 0x84, 0xe6, 0xe3, 0x82, 0x2e, 0xc4, 0x88, 0x2d, 0xfb, 0xbe, 0xc4, 0xe6, 0x09, 0x8e, 0xf2, 0xb2, 0xfc, 0x17, 0x7a, 0x1f, 0x0b, 0xcb, 0x65, 0xa5, 0x7f, 0xda, 0xa8, 0x93, 0x15, 0x46, 0x1b, 0xeb, 0x78, 0x85, 0xfb, 0x68, 0xb3, 0xcd, 0x09, 0x6e, 0xda, 0x59, 0x6a, 0xc0, 0xe6, 0x1d, 0xd7, 0xa9, 0xc5, 0x07, 0xbc, 0x63, 0x45, 0xe0, 0x82, 0x7d, 0xfc, 0xc8, 0xa3, 0xac, 0x2d, 0xce, 0x51, 0xad, 0x73, 0x1a, 0xa0, 0xeb, 0x93, 0x2a, 0x6d, 0x09, 0x83, 0x99, 0x23, 0x47, 0xcb, 0xeb, 0x3c, 0xd0, 0xd9, 0xc9, 0x71, 0x97, 0x97, 0xcc, 0x21, 0xcf, 0x00, 0x62, 0xb0, 0xad, 0x94, 0xca, 0xd7, 0x34, 0xc6, 0x3e, 0x6b, 0x5d, 0x85, 0x9c, 0xbe, 0x19, 0xf0, 0x36, 0x82, 0x45, 0x35, 0x1b, 0xf4, 0x64, 0xd7, 0x50, 0x55, 0x69, 0x79, 0x0d, 0x2b, 0xb7, 0x24, 0xd8, 0x65, 0x9a, 0x9f, 0xeb, 0x1c, 0x7c, 0x47, 0x3d, 0xc4, 0xd0, 0x61, 0xe2, 0x98, 0x63, 0xa2, 0x71, 0x4b, 0xac, 0x42, 0xad, 0xcd, 0x1a, 0x83, 0x72, 0x77, 0x65, 0x56, 0xf7, 0x92, 0x8a, 0x7a, 0x44, 0xe9, 0x4b, 0x6a, 0x25, 0x32, 0x2d, 0x03, 0xc0, 0xa1, 0x62, 0x2a, 0x7f, 0xd2, 0x61, 0x52, 0x2b, 0x73, 0x58, 0xf0, 0x85, 0xbd, 0xfb, 0x60, 0x75, 0x87, 0x62, 0xcb, 0x90, 0x10, 0x31, 0x90, 0x1b, 0x5e, 0xec, 0xf4, 0x92, 0x0c, 0x81, 0x02, 0x0a, 0x9b, 0x17, 0x81, 0xbc, 0xb9, 0xdd, 0x19, 0xa9, 0xdf, 0xb6, 0x64, 0x58, 0xe7, 0x75, 0x7c, 0x52, 0xce, 0xc7, 0x5b, 0x4b, 0xa7, 0x40, 0xa2, 0x40, 0x99, 0xcb, 0x56, 0xbb, 0x60, 0xa7, 0x6b, 0x69, 0x01, 0xaa, 0x3e, 0x01, 0x69, 0xc9, 0xe8, 0x34, 0x96, 0xd7, 0x3c, 0x4c, 0x99, 0x43, 0x5a, 0x28, 0xd6, 0x13, 0xe9, 0x7a, 0x11, 0x77, 0xf5, 0x8b, 0x6c, 0xc5, 0x95, 0xd3, 0xb2, 0x33, 0x1e, 0x9c, 0xa7, 0xb5, 0x7b, 0x74, 0xdc, 0x2c, 0x52, 0x77, 0xd2, 0x6f, 0x2f, 0xe1, 0x92, 0x40, 0xa5, 0x5c, 0x35, 0xd6, 0xcf, 0xca, 0x26, 0xc7, 0x3e, 0x9a, 0x2d, 0x7c, 0x98, 0x0d, 0x97, 0x96, 0x0a, 0xe1, 0xa0, 0x46, 0x98, 0xc1, 0x6b, 0x39, 0x8a, 0x5f, 0x20, 0xc3, 0x5a, 0x09, 0x14, 0x14, 0x5c, 0xe1, 0x67, 0x4b, 0x71, 0xab, 0xc6, 0x06, 0x6a, 0x90, 0x9a, 0x3e, 0x4b, 0x91, 0x1e, 0x69, 0xd5, 0xa8, 0x49, 0x43, 0x03, 0x61, 0xf7, 0x31, 0xb0, 0x72, 0x46, 0xa6, 0x32, 0x9b, 0x52, 0x36, 0x19, 0x04, 0x22, 0x50, 0x82, 0xd0, 0xaa, 0xc5, 0xb2, 0x1d, 0x6b, 0x34, 0x86, 0x24, 0x81, 0xa8, 0x90, 0xc3, 0xc3, 0x60, 0x76, 0x6f, 0x04, 0x26, 0x36, 0x03, 0xa6, 0xb7, 0x3e, 0x80, 0x2b, 0x1f, 0x70, 0xb2, 0xeb, 0x00, 0x04, 0x68, 0x36, 0xb8, 0xf4, 0x93, 0xbf, 0x10, 0xb9, 0x0b, 0x87, 0x37, 0xc6, 0xc5, 0x48, 0x44, 0x9b, 0x29, 0x4c, 0x47, 0x25, 0x3b, 0xe2, 0x6c, 0xa7, 0x23, 0x36, 0xa6, 0x32, 0x06, 0x3a, 0xd3, 0xd0, 0xb4, 0x8c, 0x8b, 0x0f, 0x4a, 0x34, 0x44, 0x7e, 0xf1, 0x3b, 0x76, 0x40, 0x20, 0xde, 0x73, 0x9e, 0xb7, 0x9a, 0xba, 0x20, 0xe2, 0xbe, 0x19, 0x51, 0x82, 0x5f, 0x29, 0x3b, 0xed, 0xd1, 0x08, 0x9f, 0xcb, 0x0a, 0x91, 0xf5, 0x60, 0xc8, 0xe1, 0x7c, 0xdf, 0x52, 0x54, 0x1d, 0xc2, 0xb8, 0x1f, 0x97, 0x2a, 0x73, 0x75, 0xb2, 0x01, 0xf1, 0x0c, 0x08, 0xd9, 0xb5, 0xbc, 0x8b, 0x95, 0x10, 0x00, 0x54, 0xa3, 0xd0, 0xaa, 0xff, 0x89, 0xbd, 0x08, 0xd6, 0xa0, 0xe7, 0xf2, 0x11, 0x5a, 0x43, 0x52, 0x31, 0x29, 0x04, 0x60, 0xc9, 0xad, 0x43, 0x5a, 0x3b, 0x3c, 0xf3, 0x5e, 0x52, 0x09, 0x1e, 0xdd, 0x18, 0x90, 0x04, 0x7b, 0xcc, 0x0a, 0xab, 0xb1, 0xac, 0xeb, 0xc7, 0x5f, 0x4a, 0x32, 0xbc, 0x14, 0x51, 0xac, 0xc4, 0x96, 0x99, 0x40, 0x78, 0x8e, 0x89, 0x41, 0x21, 0x88, 0x94, 0x6c, 0x91, 0x43, 0xc5, 0x04, 0x6b, 0xd1, 0xb4, 0x58, 0xdf, 0x61, 0x7c, 0x5d, 0xf5, 0x33, 0xb0, 0x52, 0xcd, 0x60, 0x38, 0xb7, 0x75, 0x40, 0x34, 0xa2, 0x3c, 0x2f, 0x77, 0x20, 0x13, 0x4c, 0x7b, 0x4e, 0xac, 0xe0, 0x1f, 0xac, 0x0a, 0x28, 0x53, 0xa9, 0x28, 0x58, 0x47, 0xab, 0xbd, 0x06, 0xa3, 0x34, 0x3a, 0x77, 0x8a, 0xc6, 0x06, 0x2e, 0x45, 0x8b, 0xc5, 0xe6, 0x1e, 0xce, 0x1c, 0x0d, 0xe0, 0x20, 0x6e, 0x6f, 0xe8, 0xa8, 0x40, 0x34, 0xa7, 0xc5, 0xf1, 0xb0, 0x05, 0xfb, 0x0a, 0x58, 0x40, 0x51, 0xd3, 0x22, 0x9b, 0x86, 0xc9, 0x09, 0xac, 0x56, 0x47, 0xb3, 0xd7, 0x55, 0x69, 0xe0, 0x5a, 0x88, 0x27, 0x9d, 0x80, 0xe5, 0xc3, 0x0f, 0x57, 0x4d, 0xc3, 0x27, 0x51, 0x2c, 0x6b, 0xbe, 0x81, 0x01, 0x23, 0x9e, 0xc6, 0x28, 0x61, 0xf4, 0xbe, 0x67, 0xb0, 0x5b, 0x9c, 0xda, 0x9c, 0x54, 0x5c, 0x13, 0xe7, 0xeb, 0x53, 0xcf, 0xf2, 0x60, 0xad, 0x98, 0x70, 0x19, 0x9c, 0x21, 0xf8, 0xc6, 0x3d, 0x64, 0xf0, 0x45, 0x8a, 0x71, 0x41, 0x28, 0x50, 0x23, 0xfe, 0xb8, 0x29, 0x29, 0x08, 0x72, 0x38, 0x96, 0x44, 0xb0, 0xc3, 0xb7, 0x3a, 0xc2, 0xc8, 0xe1, 0x21, 0xa2, 0x9b, 0xb1, 0xc4, 0x3c, 0x19, 0xa2, 0x33, 0xd5, 0x6b, 0xed, 0x82, 0x74, 0x0e, 0xb0, 0x21, 0xc9, 0x7b, 0x8e, 0xbb, 0xa4, 0x0f, 0xf3, 0x28, 0xb5, 0x41, 0x76, 0x0f, 0xcc, 0x37, 0x2b, 0x52, 0xd3, 0xbc, 0x4f, 0xcb, 0xc0, 0x6f, 0x42, 0x4e, 0xaf, 0x25, 0x38, 0x04, 0xd4, 0xcb, 0x46, 0xf4, 0x1f, 0xf2, 0x54, 0xc0, 0xc5, 0xba, 0x48, 0x3b, 0x44, 0xa8, 0x7c, 0x21, 0x96, 0x54, 0x55, 0x5e, 0xc7, 0xc1, 0x63, 0xc7, 0x9b, 0x9c, 0xb7, 0x60, 0xa2, 0xad, 0x9b, 0xb7, 0x22, 0xb9, 0x3e, 0x0c, 0x28, 0xbd, 0x4b, 0x16, 0x85, 0x94, 0x9c, 0x49, 0x6e, 0xab, 0x1a, 0xff, 0x90, 0x91, 0x9e, 0x37, 0x61, 0xb3, 0x46, 0x83, 0x8a, 0xbb, 0x2f, 0x01, 0xa9, 0x1e, 0x55, 0x43, 0x75, 0xaf, 0xda, 0xaa, 0xf3, 0x82, 0x6e, 0x6d, 0xb7, 0x9f, 0xe7, 0x35, 0x3a, 0x7a, 0x57, 0x8a, 0x7c, 0x05, 0x98, 0xce, 0x28, 0xb6, 0xd9, 0x91, 0x52, 0x14, 0x23, 0x6b, 0xbf, 0xfa, 0x6d, 0x45, 0xb6, 0x37, 0x6a, 0x07, 0x92, 0x4a, 0x39, 0xa7, 0xbe, 0x81, 0x82, 0x86, 0x71, 0x5c, 0x8a, 0x3c, 0x11, 0x0c, 0xd7, 0x6c, 0x02, 0xe0, 0x41, 0x7a, 0xf1, 0x38, 0xbd, 0xb9, 0x5c, 0x3c, 0xca, 0x79, 0x8a, 0xc8, 0x09, 0xed, 0x69, 0xcf, 0xb6, 0x72, 0xb6, 0xfd, 0xdc, 0x24, 0xd8, 0x9c, 0x06, 0xa6, 0x55, 0x88, 0x14, 0xab, 0x0c, 0x21, 0xc6, 0x2b, 0x2f, 0x84, 0xc0, 0xe3, 0xe0, 0x80, 0x3d, 0xb3, 0x37, 0xa4, 0xe0, 0xc7, 0x12, 0x7a, 0x6b, 0x4c, 0x8c, 0x08, 0xb1, 0xd1, 0xa7, 0x6b, 0xf0, 0x7e, 0xb6, 0xe5, 0xb5, 0xbb, 0x47, 0xa1, 0x6c, 0x74, 0xbc, 0x54, 0x83, 0x75, 0xfb, 0x29, 0xcd, 0x78, 0x9a, 0x5c, 0xff, 0x91, 0xbd, 0xbd, 0x07, 0x18, 0x59, 0xf4, 0x84, 0x6e, 0x35, 0x5b, 0xb0, 0xd2, 0x94, 0x84, 0xe2, 0x64, 0xdf, 0xf3, 0x6c, 0x91, 0x77, 0xa7, 0xac, 0xa7, 0x89, 0x08, 0x87, 0x96, 0x95, 0xca, 0x87, 0xf2, 0x54, 0x36, 0xbc, 0x12, 0x63, 0x07, 0x24, 0xbb, 0x22, 0xf0, 0xcb, 0x64, 0x89, 0x7f, 0xe5, 0xc4, 0x11, 0x95, 0x28, 0x0d, 0xa0, 0x41, 0x84, 0xd4, 0xbc, 0x7b, 0x53, 0x2a, 0x0f, 0x70, 0xa5, 0x4d, 0x77, 0x57, 0xcd, 0xe6, 0x17, 0x5a, 0x68, 0x43, 0xb8, 0x61, 0xcb, 0x2b, 0xc4, 0x83, 0x0c, 0x00, 0x12, 0x55, 0x4c, 0xfc, 0x5d, 0x2c, 0x8a, 0x20, 0x27, 0xaa, 0x3c, 0xd9, 0x67, 0x13, 0x0e, 0x9b, 0x96, 0x24, 0x1b, 0x11, 0xc4, 0x32, 0x0c, 0x76, 0x49, 0xcc, 0x23, 0xa7, 0x1b, 0xaf, 0xe6, 0x91, 0xaf, 0xc0, 0x8e, 0x68, 0x0b, 0xce, 0xf4, 0x29, 0x07, 0x00, 0x07, 0x18, 0xe4, 0xea, 0xce, 0x8d, 0xa2, 0x82, 0x14, 0x19, 0x7b, 0xe1, 0xc2, 0x69, 0xda, 0x9c, 0xb5, 0x41, 0xe1, 0xa3, 0xce, 0x97, 0xcf, 0xad, 0xf9, 0xc6, 0x05, 0x87, 0x80, 0xfe, 0x67, 0x93, 0xdb, 0xfa, 0x82, 0x18, 0xa2, 0x76, 0x0b, 0x80, 0x2b, 0x8d, 0xa2, 0xaa, 0x27, 0x1a, 0x38, 0x77, 0x25, 0x23, 0xa7, 0x67, 0x36, 0xa7, 0xa3, 0x1b, 0x9d, 0x30, 0x37, 0xad, 0x21, 0xce, 0xbb, 0x11, 0xa4, 0x72, 0xb8, 0x79, 0x2e, 0xb1, 0x75, 0x58, 0xb9, 0x40, 0xe7, 0x08, 0x83, 0xf2, 0x64, 0x59, 0x2c, 0x68, 0x9b, 0x24, 0x0b, 0xb4, 0x3d, 0x54, 0x08, 0xbf, 0x44, 0x64, 0x32, 0xf4, 0x12, 0xf4, 0xb9, 0xa5, 0xf6, 0x86, 0x5c, 0xc2, 0x52, 0xa4, 0x3c, 0xf4, 0x0a, 0x32, 0x03, 0x91, 0x55, 0x55, 0x91, 0xd6, 0x75, 0x61, 0xfd, 0xd0, 0x53, 0x53, 0xab, 0x6b, 0x01, 0x9b, 0x3a, 0x08, 0xa7, 0x33, 0x53, 0xd5, 0x1b, 0x61, 0x13, 0xab, 0x2f, 0xa5, 0x1d, 0x97, 0x56, 0x48, 0xee, 0x25, 0x4a, 0xf8, 0x9a, 0x23, 0x05, 0x04, 0xa2, 0x36, 0xa4, 0x65, 0x82, 0x57, 0x74, 0x0b, 0xdc, 0xbb, 0xe1, 0x70, 0x8a, 0xb0, 0x22, 0xc3, 0xc5, 0x88, 0xa4, 0x10, 0xdb, 0x3b, 0x9c, 0x30, 0x8a, 0x06, 0x27, 0x5b, 0xdf, 0x5b, 0x48, 0x59, 0xd3, 0xa2, 0x61, 0x7a, 0x29, 0x5e, 0x1a, 0x22, 0xf9, 0x01, 0x98, 0xba, 0xd0, 0x16, 0x6f, 0x4a, 0x94, 0x34, 0x17, 0xc5, 0xb8, 0x31, 0x73, 0x6c, 0xb2, 0xc8, 0x58, 0x0a, 0xbf, 0xde, 0x57, 0x14, 0xb5, 0x86, 0xab, 0xee, 0xc0, 0xa1, 0x75, 0xa0, 0x8b, 0xc7, 0x10, 0xc7, 0xa2, 0x89, 0x5d, 0xe9, 0x3a, 0xc4, 0x38, 0x06, 0x1b, 0xf7, 0x76, 0x5d, 0x0d, 0x21, 0xcd, 0x41, 0x81, 0x67, 0xca, 0xf8, 0x9d, 0x1e, 0xfc, 0x34, 0x48, 0xbc, 0xbb, 0x96, 0xd6, 0x9b, 0x3e, 0x01, 0x0c, 0x82, 0xd1, 0x5c, 0xab, 0x6c, 0xac, 0xc6, 0x79, 0x9d, 0x36, 0x39, 0x66, 0x9a, 0x5b, 0x21, 0xa6, 0x33, 0xc8, 0x65, 0xf8, 0x59, 0x3b, 0x5b, 0x7b, 0xc8, 0x00, 0x26, 0x2b, 0xb8, 0x37, 0xa9, 0x24, 0xa6, 0xc5, 0x44, 0x0e, 0x4f, 0xc7, 0x3b, 0x41, 0xb2, 0x30, 0x92, 0xc3, 0x91, 0x2f, 0x4c, 0x6b, 0xeb, 0xb4, 0xc7, 0xb4, 0xc6, 0x29, 0x08, 0xb0, 0x37, 0x75, 0x66, 0x6c, 0x22, 0x22, 0x0d, 0xf9, 0xc8, 0x88, 0x23, 0xe3, 0x44, 0xc7, 0x30, 0x83, 0x32, 0x34, 0x5c, 0x8b, 0x79, 0x5d, 0x34, 0xe8, 0xc0, 0x51, 0xf2, 0x1f, 0x5a, 0x21, 0xc2, 0x14, 0xb6, 0x98, 0x41, 0x35, 0x87, 0x09, 0xb1, 0xc3, 0x05, 0xb3, 0x2c, 0xc2, 0xc3, 0x80, 0x6a, 0xe9, 0xcc, 0xd3, 0x81, 0x9f, 0xff, 0x45, 0x07, 0xfe, 0x52, 0x0f, 0xbf, 0xc2, 0x71, 0x99, 0xbc, 0x23, 0xbe, 0x6b, 0x9b, 0x2d, 0x2a, 0xc1, 0x71, 0x75, 0x79, 0xac, 0x76, 0x92, 0x79, 0xe2, 0xa7, 0xaa, 0xc6, 0x8a, 0x37, 0x1a, 0x47, 0xba, 0x3a, 0x7d, 0xbe, 0x01, 0x6f, 0x14, 0xe1, 0xa7, 0x27, 0x33, 0x36, 0x63, 0xc4, 0xa5, 0xcd, 0x1a, 0x0f, 0x88, 0x36, 0xcf, 0x7b, 0x5c, 0x49, 0xac, 0x51, 0x48, 0x5c, 0xa6, 0x03, 0x45, 0xc9, 0x90, 0xe0, 0x68, 0x88, 0x72, 0x00, 0x03, 0x73, 0x13, 0x22, 0xc5, 0xb8, 0xcd, 0x5e, 0x69, 0x07, 0xfd, 0xa1, 0x15, 0x7f, 0x46, 0x8f, 0xd3, 0xfc, 0x20, 0xfa, 0x81, 0x75, 0xee, 0xc9, 0x5c, 0x29, 0x1a, 0x26, 0x2b, 0xa8, 0xc5, 0xbe, 0x99, 0x08, 0x72, 0x41, 0x89, 0x30, 0x85, 0x23, 0x39, 0xd8, 0x8a, 0x19, 0xb3, 0x7f, 0xef, 0xa3, 0xcf, 0xe8, 0x21, 0x75, 0xc2, 0x24, 0x40, 0x7c, 0xa4, 0x14, 0xba, 0xeb, 0x37, 0x92, 0x3b, 0x4d, 0x2d, 0x83, 0x13, 0x4a, 0xe1, 0x54, 0xe4, 0x90, 0xa9, 0xb4, 0x5a, 0x05, 0x63, 0xb0, 0x6c, 0x95, 0x3c, 0x33, 0x01, 0x45, 0x0a, 0x21, 0x76, 0xa0, 0x7c, 0x61, 0x4a, 0x74, 0xe3, 0x47, 0x8e, 0x48, 0x50, 0x9f, 0x9a, 0x60, 0xae, 0x94, 0x5a, 0x8e, 0xbc, 0x78, 0x15, 0x12, 0x1d, 0x90, 0xa3, 0xb0, 0xe0, 0x70, 0x91, 0xa0, 0x96, 0xcf, 0x02, 0xc5, 0x7b, 0x25, 0xbc, 0xa5, 0x81, 0x26, 0xad, 0x0c, 0x62, 0x9c, 0xe1, 0x66, 0xa7, 0xed, 0xb4, 0xb3, 0x32, 0x21, 0xa0, 0xd3, 0xf7, 0x2b, 0x85, 0xd5, 0x62, 0xec, 0x69, 0x8b, 0x7d, 0x0a, 0x91, 0x3d, 0x73, 0x80, 0x6f, 0x1c, 0x5c, 0x87, 0xb3, 0x8e, 0xc0, 0x03, 0xcb, 0x30, 0x3a, 0x3d, 0xc5, 0x1b, 0x4b, 0x35, 0x35, 0x6a, 0x67, 0x82, 0x6d, 0x6e, 0xda, 0xa8, 0xfe, 0xb9, 0x3b, 0x98, 0x49, 0x3b, 0x2d, 0x1c, 0x11, 0xb6, 0x76, 0xa6, 0xad, 0x95, 0x06, 0xa1, 0xaa, 0xae, 0x13, 0xa8, 0x24, 0xc7, 0xc0, 0x8d, 0x1c, 0x6c, 0x2c, 0x4d, 0xba, 0x96, 0x42, 0xc7, 0x6e, 0xa7, 0xf6, 0xc8, 0x26, 0x4b, 0x64, 0xa2, 0x3c, 0xcc, 0xa9, 0xa7, 0x46, 0x35, 0xfc, 0xbf, 0x03, 0xe0, 0x0f, 0x1b, 0x57, 0x22, 0xb2, 0x14, 0x37, 0x67, 0x90, 0x79, 0x3b, 0x2c, 0x4f, 0x0a, 0x13, 0xb5, 0xc4, 0x07, 0x60, 0xb4, 0x21, 0x8e, 0x1d, 0x25, 0x94, 0xdc, 0xb3, 0x0a, 0x70, 0xd9, 0xc1, 0x78, 0x2a, 0x5d, 0xd3, 0x05, 0x76, 0xfa, 0x41, 0x44, 0xbf, 0xc8, 0x41, 0x6e, 0xda, 0x81, 0x18, 0xfc, 0x64, 0x72, 0xf5, 0x6a, 0x97, 0x95, 0x86, 0xf3, 0x3b, 0xb0, 0x70, 0xfb, 0x0f, 0x1b, 0x0b, 0x10, 0xbc, 0x48, 0x97, 0xeb, 0xe0, 0x1b, 0xca, 0x38, 0x93, 0xd4, 0xe1, 0x6a, 0xdb, 0x25, 0x09, 0x3a, 0x74, 0x17, 0xd0, 0x70, 0x8c, 0x83, 0xa2, 0x63, 0x22, 0xe2, 0x2e, 0x63, 0x30, 0x09, 0x1e, 0x30, 0x15, 0x2b, 0xf8, 0x23, 0x59, 0x7c, 0x04, 0xcc, 0xf4, 0xcf, 0xc7, 0x33, 0x15, 0x78, 0xf4, 0x3a, 0x27, 0x26, 0xcc, 0xb4, 0x28, 0x28, 0x9a, 0x90, 0xc8, 0x63, 0x25, 0x9d, 0xd1, 0x80, 0xc5, 0xff, 0x14, 0x2b, 0xef, 0x41, 0xc7, 0x71, 0x70, 0x94, 0xbe, 0x07, 0x85, 0x6d, 0xa2, 0xb1, 0x40, 0xfa, 0x67, 0x71, 0x09, 0x67, 0x35, 0x6a, 0xa4, 0x7d, 0xfb, 0xc8, 0xd2, 0x55, 0xb4, 0x72, 0x2a, 0xb8, 0x6d, 0x43, 0x9b, 0x7e, 0x0a, 0x60, 0x90, 0x25, 0x1d, 0x2d, 0x4c, 0x1e, 0xd5, 0xf2, 0x0b, 0xbe, 0x68, 0x07, 0xbf, 0x65, 0xa9, 0x0b, 0x7c, 0xb2, 0xec, 0x01, 0x02, 0xaf, 0x02, 0x80, 0x9d, 0xc9, 0xac, 0x7d, 0x0a, 0x3a, 0xbc, 0x69, 0xc1, 0x83, 0x65, 0xbc, 0xff, 0x59, 0x18, 0x5f, 0x33, 0x99, 0x68, 0x87, 0x74, 0x61, 0x85, 0x90, 0x6c, 0x01, 0x91, 0xae, 0xd4, 0x40, 0x7e, 0x13, 0x94, 0x46, 0x45, 0x9b, 0xe2, 0x9c, 0x68, 0x22, 0x71, 0x76, 0x44, 0x35, 0x3d, 0x24, 0xab, 0x63, 0x39, 0x15, 0x6a, 0x9c, 0x42, 0x49, 0x09, 0xf0, 0xa9, 0x02, 0x5b, 0xb7, 0x47, 0x20, 0x77, 0x9b, 0xe4, 0x3f, 0x16, 0xd8, 0x1c, 0x8c, 0xc6, 0x66, 0xe9, 0x97, 0x10, 0xd8, 0xc6, 0x8b, 0xb5, 0xcc, 0x4e, 0x12, 0xf3, 0x14, 0xe9, 0x25, 0xa5, 0x51, 0xf0, 0x9c, 0xc5, 0x90, 0x03, 0xa1, 0xf8, 0x81, 0x03, 0xc2, 0x54, 0xbb, 0x97, 0x8d, 0x75, 0xf3, 0x94, 0xd3, 0x54, 0x0e, 0x31, 0xe7, 0x71, 0xcd, 0xa3, 0x6e, 0x39, 0xec, 0x54, 0xa6, 0x2b, 0x58, 0x32, 0x66, 0x4d, 0x82, 0x1a, 0x72, 0xf1, 0xe6, 0xaf, 0xbb, 0xa2, 0x7f, 0x84, 0x29, 0x5b, 0x26, 0x94, 0xc4, 0x98, 0x49, 0x8e, 0x81, 0x2b, 0xc8, 0xe9, 0x37, 0x8f, 0xe5, 0x41, 0xce, 0xc5, 0x89, 0x1b, 0x25, 0x06, 0x29, 0x01, 0xcb, 0x72, 0x12, 0xe3, 0xcd, 0xc4, 0x61, 0x79, 0xec, 0x5b, 0xce, 0xc1, 0x0b, 0xc0, 0xb9, 0x31, 0x1d, 0xe0, 0x50, 0x74, 0x29, 0x06, 0x87, 0xfd, 0x6a, 0x53, 0x92, 0x67, 0x16, 0x54, 0x28, 0x4c, 0xd9, 0xc8, 0xcc, 0x3e, 0xba, 0x80, 0xeb, 0x3b, 0x66, 0x2e, 0xb5, 0x3e, 0xb7, 0x51, 0x16, 0x70, 0x4a, 0x1f, 0xeb, 0x5c, 0x2d, 0x05, 0x63, 0x38, 0x53, 0x28, 0x68, 0xdd, 0xf2, 0x4e, 0xb8, 0x99, 0x2a, 0xb8, 0x56, 0x5d, 0x9e, 0x49, 0x0c, 0xad, 0xf1, 0x48, 0x04, 0x36, 0x0d, 0xaa, 0x90, 0x71, 0x8e, 0xab, 0x61, 0x6b, 0xab, 0x07, 0x65, 0xd3, 0x39, 0x87, 0xb4, 0x7e, 0xfb, 0x65, 0x99, 0xc5, 0x56, 0x32, 0x35, 0xe6, 0x1e, 0x4b, 0xe6, 0x70, 0xe9, 0x79, 0x55, 0xab, 0x29, 0x2d, 0x97, 0x32, 0xcb, 0x89, 0x30, 0x94, 0x8a, 0xc8, 0x2d, 0xf2, 0x30, 0xac, 0x72, 0x29, 0x7a, 0x23, 0x67, 0x9d, 0x6b, 0x94, 0xc1, 0x7f, 0x13, 0x59, 0x48, 0x32, 0x54, 0xfe, 0xdc, 0x2f, 0x05, 0x81, 0x9f, 0x0d, 0x06, 0x9a, 0x44, 0x3b, 0x78, 0xe3, 0xfc, 0x6c, 0x3e, 0xf4, 0x71, 0x4b, 0x05, 0xa3, 0xfc, 0xa8, 0x1c, 0xbb, 0xa6, 0x02, 0x42, 0xa7, 0x06, 0x0c, 0xd8, 0x85, 0xd8, 0xf3, 0x99, 0x81, 0xbb, 0x18, 0x09, 0x2b, 0x23, 0xda, 0xa5, 0x9f, 0xd9, 0x57, 0x83, 0x88, 0x68, 0x8a, 0x09, 0xbb, 0xa0, 0x79, 0xbc, 0x80, 0x9a, 0x54, 0x84, 0x3a, 0x60, 0x38, 0x5e, 0x23, 0x10, 0xbb, 0xcb, 0xcc, 0x02, 0x13, 0xce, 0x3d, 0xfa, 0xab, 0x33, 0xb4, 0x7f, 0x9d, 0x63, 0x05, 0xbc, 0x95, 0xc6, 0x10, 0x78, 0x13, 0xc5, 0x85, 0xc4, 0xb6, 0x57, 0xbf, 0x30, 0x54, 0x28, 0x33, 0xb1, 0x49, 0x49, 0xf5, 0x73, 0xc0, 0x61, 0x2a, 0xd5, 0x24, 0xba, 0xae, 0x69, 0x59, 0x0c, 0x12, 0x77, 0xb8, 0x6c, 0x28, 0x65, 0x71, 0xbf, 0x66, 0xb3, 0xcf, 0xf4, 0x6a, 0x38, 0x58, 0xc0, 0x99, 0x06, 0xa7, 0x94, 0xdf, 0x4a, 0x06, 0xe9, 0xd4, 0xb0, 0xa2, 0xe4, 0x3f, 0x10, 0xf7, 0x2a, 0x6c, 0x6c, 0x47, 0xe5, 0x64, 0x6e, 0x2c, 0x79, 0x9b, 0x71, 0xc3, 0x3e, 0xd2, 0xf0, 0x1e, 0xeb, 0x45, 0x93, 0x8e, 0xb7, 0xa4, 0xe2, 0xe2, 0x90, 0x8c, 0x53, 0x55, 0x8a, 0x54, 0x0d, 0x35, 0x03, 0x69, 0xfa, 0x18, 0x9c, 0x61, 0x69, 0x43, 0xf7, 0x98, 0x1d, 0x76, 0x18, 0xcf, 0x02, 0xa5, 0xb0, 0xa2, 0xbc, 0xc4, 0x22, 0xe8, 0x57, 0xd1, 0xa4, 0x78, 0x71, 0x25, 0x3d, 0x08, 0x29, 0x3c, 0x1c, 0x17, 0x9b, 0xcd, 0xc0, 0x43, 0x70, 0x69, 0x10, 0x74, 0x18, 0x20, 0x5f, 0xdb, 0x98, 0x56, 0x62, 0x3b, 0x8c, 0xa6, 0xb6, 0x94, 0xc9, 0x6c, 0x08, 0x4b, 0x17, 0xf1, 0x3b, 0xb6, 0xdf, 0x12, 0xb2, 0xcf, 0xbb, 0xc2, 0xb0, 0xe0, 0xc3, 0x4b, 0x00, 0xd0, 0xfc, 0xd0, 0xae, 0xcf, 0xb2, 0x79, 0x24, 0xf6, 0x98, 0x4e, 0x74, 0x7b, 0xe2, 0xa0, 0x9d, 0x83, 0xa8, 0x66, 0x45, 0x90, 0xa8, 0x07, 0x73, 0x31, 0x49, 0x1a, 0x4f, 0x7d, 0x72, 0x08, 0x43, 0xf2, 0x3e, 0x65, 0x2c, 0x6f, 0xa8, 0x40, 0x30, 0x8d, 0xb4, 0x02, 0x03, 0x37, 0xaa, 0xd3, 0x79, 0x67, 0x03, 0x4a, 0x9f, 0xb5, 0x23, 0xb6, 0x7c, 0xa7, 0x03, 0x30, 0xf0, 0x2d, 0x9e, 0xa2, 0x0c, 0x1e, 0x84, 0xcb, 0x8e, 0x57, 0x57, 0xc9, 0xe1, 0x89, 0x6b, 0x60, 0x58, 0x14, 0x41, 0xed, 0x61, 0x8a, 0xa5, 0xb2, 0x6d, 0xa5, 0x6c, 0x0a, 0x5a, 0x73, 0xc4, 0xdc, 0xfd, 0x75, 0x5e, 0x61, 0x0b, 0x4f, 0xc8, 0x1f, 0xf8, 0x4e, 0x21, 0xd2, 0xe5, 0x74, 0xdf, 0xd8, 0xcd, 0x0a, 0xe8, 0x93, 0xaa, 0x7e, 0x12, 0x5b, 0x44, 0xb9, 0x24, 0xf4, 0x52, 0x23, 0xec, 0x09, 0xf2, 0xad, 0x11, 0x41, 0xea, 0x93, 0xa6, 0x80, 0x50, 0xdb, 0xf6, 0x99, 0xe3, 0x24, 0x68, 0x84, 0x18, 0x1f, 0x8e, 0x1d, 0xd4, 0x4e, 0x0c, 0x76, 0x29, 0x09, 0x33, 0x30, 0x22, 0x1f, 0xd6, 0x7d, 0x9b, 0x7d, 0x6e, 0x15, 0x10, 0xb2, 0xdb, 0xad, 0x87, 0x62, 0xf7, }, .sk_len = 3168, .pk = { 0xa0, 0x41, 0x84, 0xd4, 0xbc, 0x7b, 0x53, 0x2a, 0x0f, 0x70, 0xa5, 0x4d, 0x77, 0x57, 0xcd, 0xe6, 0x17, 0x5a, 0x68, 0x43, 0xb8, 0x61, 0xcb, 0x2b, 0xc4, 0x83, 0x0c, 0x00, 0x12, 0x55, 0x4c, 0xfc, 0x5d, 0x2c, 0x8a, 0x20, 0x27, 0xaa, 0x3c, 0xd9, 0x67, 0x13, 0x0e, 0x9b, 0x96, 0x24, 0x1b, 0x11, 0xc4, 0x32, 0x0c, 0x76, 0x49, 0xcc, 0x23, 0xa7, 0x1b, 0xaf, 0xe6, 0x91, 0xaf, 0xc0, 0x8e, 0x68, 0x0b, 0xce, 0xf4, 0x29, 0x07, 0x00, 0x07, 0x18, 0xe4, 0xea, 0xce, 0x8d, 0xa2, 0x82, 0x14, 0x19, 0x7b, 0xe1, 0xc2, 0x69, 0xda, 0x9c, 0xb5, 0x41, 0xe1, 0xa3, 0xce, 0x97, 0xcf, 0xad, 0xf9, 0xc6, 0x05, 0x87, 0x80, 0xfe, 0x67, 0x93, 0xdb, 0xfa, 0x82, 0x18, 0xa2, 0x76, 0x0b, 0x80, 0x2b, 0x8d, 0xa2, 0xaa, 0x27, 0x1a, 0x38, 0x77, 0x25, 0x23, 0xa7, 0x67, 0x36, 0xa7, 0xa3, 0x1b, 0x9d, 0x30, 0x37, 0xad, 0x21, 0xce, 0xbb, 0x11, 0xa4, 0x72, 0xb8, 0x79, 0x2e, 0xb1, 0x75, 0x58, 0xb9, 0x40, 0xe7, 0x08, 0x83, 0xf2, 0x64, 0x59, 0x2c, 0x68, 0x9b, 0x24, 0x0b, 0xb4, 0x3d, 0x54, 0x08, 0xbf, 0x44, 0x64, 0x32, 0xf4, 0x12, 0xf4, 0xb9, 0xa5, 0xf6, 0x86, 0x5c, 0xc2, 0x52, 0xa4, 0x3c, 0xf4, 0x0a, 0x32, 0x03, 0x91, 0x55, 0x55, 0x91, 0xd6, 0x75, 0x61, 0xfd, 0xd0, 0x53, 0x53, 0xab, 0x6b, 0x01, 0x9b, 0x3a, 0x08, 0xa7, 0x33, 0x53, 0xd5, 0x1b, 0x61, 0x13, 0xab, 0x2f, 0xa5, 0x1d, 0x97, 0x56, 0x48, 0xee, 0x25, 0x4a, 0xf8, 0x9a, 0x23, 0x05, 0x04, 0xa2, 0x36, 0xa4, 0x65, 0x82, 0x57, 0x74, 0x0b, 0xdc, 0xbb, 0xe1, 0x70, 0x8a, 0xb0, 0x22, 0xc3, 0xc5, 0x88, 0xa4, 0x10, 0xdb, 0x3b, 0x9c, 0x30, 0x8a, 0x06, 0x27, 0x5b, 0xdf, 0x5b, 0x48, 0x59, 0xd3, 0xa2, 0x61, 0x7a, 0x29, 0x5e, 0x1a, 0x22, 0xf9, 0x01, 0x98, 0xba, 0xd0, 0x16, 0x6f, 0x4a, 0x94, 0x34, 0x17, 0xc5, 0xb8, 0x31, 0x73, 0x6c, 0xb2, 0xc8, 0x58, 0x0a, 0xbf, 0xde, 0x57, 0x14, 0xb5, 0x86, 0xab, 0xee, 0xc0, 0xa1, 0x75, 0xa0, 0x8b, 0xc7, 0x10, 0xc7, 0xa2, 0x89, 0x5d, 0xe9, 0x3a, 0xc4, 0x38, 0x06, 0x1b, 0xf7, 0x76, 0x5d, 0x0d, 0x21, 0xcd, 0x41, 0x81, 0x67, 0xca, 0xf8, 0x9d, 0x1e, 0xfc, 0x34, 0x48, 0xbc, 0xbb, 0x96, 0xd6, 0x9b, 0x3e, 0x01, 0x0c, 0x82, 0xd1, 0x5c, 0xab, 0x6c, 0xac, 0xc6, 0x79, 0x9d, 0x36, 0x39, 0x66, 0x9a, 0x5b, 0x21, 0xa6, 0x33, 0xc8, 0x65, 0xf8, 0x59, 0x3b, 0x5b, 0x7b, 0xc8, 0x00, 0x26, 0x2b, 0xb8, 0x37, 0xa9, 0x24, 0xa6, 0xc5, 0x44, 0x0e, 0x4f, 0xc7, 0x3b, 0x41, 0xb2, 0x30, 0x92, 0xc3, 0x91, 0x2f, 0x4c, 0x6b, 0xeb, 0xb4, 0xc7, 0xb4, 0xc6, 0x29, 0x08, 0xb0, 0x37, 0x75, 0x66, 0x6c, 0x22, 0x22, 0x0d, 0xf9, 0xc8, 0x88, 0x23, 0xe3, 0x44, 0xc7, 0x30, 0x83, 0x32, 0x34, 0x5c, 0x8b, 0x79, 0x5d, 0x34, 0xe8, 0xc0, 0x51, 0xf2, 0x1f, 0x5a, 0x21, 0xc2, 0x14, 0xb6, 0x98, 0x41, 0x35, 0x87, 0x09, 0xb1, 0xc3, 0x05, 0xb3, 0x2c, 0xc2, 0xc3, 0x80, 0x6a, 0xe9, 0xcc, 0xd3, 0x81, 0x9f, 0xff, 0x45, 0x07, 0xfe, 0x52, 0x0f, 0xbf, 0xc2, 0x71, 0x99, 0xbc, 0x23, 0xbe, 0x6b, 0x9b, 0x2d, 0x2a, 0xc1, 0x71, 0x75, 0x79, 0xac, 0x76, 0x92, 0x79, 0xe2, 0xa7, 0xaa, 0xc6, 0x8a, 0x37, 0x1a, 0x47, 0xba, 0x3a, 0x7d, 0xbe, 0x01, 0x6f, 0x14, 0xe1, 0xa7, 0x27, 0x33, 0x36, 0x63, 0xc4, 0xa5, 0xcd, 0x1a, 0x0f, 0x88, 0x36, 0xcf, 0x7b, 0x5c, 0x49, 0xac, 0x51, 0x48, 0x5c, 0xa6, 0x03, 0x45, 0xc9, 0x90, 0xe0, 0x68, 0x88, 0x72, 0x00, 0x03, 0x73, 0x13, 0x22, 0xc5, 0xb8, 0xcd, 0x5e, 0x69, 0x07, 0xfd, 0xa1, 0x15, 0x7f, 0x46, 0x8f, 0xd3, 0xfc, 0x20, 0xfa, 0x81, 0x75, 0xee, 0xc9, 0x5c, 0x29, 0x1a, 0x26, 0x2b, 0xa8, 0xc5, 0xbe, 0x99, 0x08, 0x72, 0x41, 0x89, 0x30, 0x85, 0x23, 0x39, 0xd8, 0x8a, 0x19, 0xb3, 0x7f, 0xef, 0xa3, 0xcf, 0xe8, 0x21, 0x75, 0xc2, 0x24, 0x40, 0x7c, 0xa4, 0x14, 0xba, 0xeb, 0x37, 0x92, 0x3b, 0x4d, 0x2d, 0x83, 0x13, 0x4a, 0xe1, 0x54, 0xe4, 0x90, 0xa9, 0xb4, 0x5a, 0x05, 0x63, 0xb0, 0x6c, 0x95, 0x3c, 0x33, 0x01, 0x45, 0x0a, 0x21, 0x76, 0xa0, 0x7c, 0x61, 0x4a, 0x74, 0xe3, 0x47, 0x8e, 0x48, 0x50, 0x9f, 0x9a, 0x60, 0xae, 0x94, 0x5a, 0x8e, 0xbc, 0x78, 0x15, 0x12, 0x1d, 0x90, 0xa3, 0xb0, 0xe0, 0x70, 0x91, 0xa0, 0x96, 0xcf, 0x02, 0xc5, 0x7b, 0x25, 0xbc, 0xa5, 0x81, 0x26, 0xad, 0x0c, 0x62, 0x9c, 0xe1, 0x66, 0xa7, 0xed, 0xb4, 0xb3, 0x32, 0x21, 0xa0, 0xd3, 0xf7, 0x2b, 0x85, 0xd5, 0x62, 0xec, 0x69, 0x8b, 0x7d, 0x0a, 0x91, 0x3d, 0x73, 0x80, 0x6f, 0x1c, 0x5c, 0x87, 0xb3, 0x8e, 0xc0, 0x03, 0xcb, 0x30, 0x3a, 0x3d, 0xc5, 0x1b, 0x4b, 0x35, 0x35, 0x6a, 0x67, 0x82, 0x6d, 0x6e, 0xda, 0xa8, 0xfe, 0xb9, 0x3b, 0x98, 0x49, 0x3b, 0x2d, 0x1c, 0x11, 0xb6, 0x76, 0xa6, 0xad, 0x95, 0x06, 0xa1, 0xaa, 0xae, 0x13, 0xa8, 0x24, 0xc7, 0xc0, 0x8d, 0x1c, 0x6c, 0x2c, 0x4d, 0xba, 0x96, 0x42, 0xc7, 0x6e, 0xa7, 0xf6, 0xc8, 0x26, 0x4b, 0x64, 0xa2, 0x3c, 0xcc, 0xa9, 0xa7, 0x46, 0x35, 0xfc, 0xbf, 0x03, 0xe0, 0x0f, 0x1b, 0x57, 0x22, 0xb2, 0x14, 0x37, 0x67, 0x90, 0x79, 0x3b, 0x2c, 0x4f, 0x0a, 0x13, 0xb5, 0xc4, 0x07, 0x60, 0xb4, 0x21, 0x8e, 0x1d, 0x25, 0x94, 0xdc, 0xb3, 0x0a, 0x70, 0xd9, 0xc1, 0x78, 0x2a, 0x5d, 0xd3, 0x05, 0x76, 0xfa, 0x41, 0x44, 0xbf, 0xc8, 0x41, 0x6e, 0xda, 0x81, 0x18, 0xfc, 0x64, 0x72, 0xf5, 0x6a, 0x97, 0x95, 0x86, 0xf3, 0x3b, 0xb0, 0x70, 0xfb, 0x0f, 0x1b, 0x0b, 0x10, 0xbc, 0x48, 0x97, 0xeb, 0xe0, 0x1b, 0xca, 0x38, 0x93, 0xd4, 0xe1, 0x6a, 0xdb, 0x25, 0x09, 0x3a, 0x74, 0x17, 0xd0, 0x70, 0x8c, 0x83, 0xa2, 0x63, 0x22, 0xe2, 0x2e, 0x63, 0x30, 0x09, 0x1e, 0x30, 0x15, 0x2b, 0xf8, 0x23, 0x59, 0x7c, 0x04, 0xcc, 0xf4, 0xcf, 0xc7, 0x33, 0x15, 0x78, 0xf4, 0x3a, 0x27, 0x26, 0xcc, 0xb4, 0x28, 0x28, 0x9a, 0x90, 0xc8, 0x63, 0x25, 0x9d, 0xd1, 0x80, 0xc5, 0xff, 0x14, 0x2b, 0xef, 0x41, 0xc7, 0x71, 0x70, 0x94, 0xbe, 0x07, 0x85, 0x6d, 0xa2, 0xb1, 0x40, 0xfa, 0x67, 0x71, 0x09, 0x67, 0x35, 0x6a, 0xa4, 0x7d, 0xfb, 0xc8, 0xd2, 0x55, 0xb4, 0x72, 0x2a, 0xb8, 0x6d, 0x43, 0x9b, 0x7e, 0x0a, 0x60, 0x90, 0x25, 0x1d, 0x2d, 0x4c, 0x1e, 0xd5, 0xf2, 0x0b, 0xbe, 0x68, 0x07, 0xbf, 0x65, 0xa9, 0x0b, 0x7c, 0xb2, 0xec, 0x01, 0x02, 0xaf, 0x02, 0x80, 0x9d, 0xc9, 0xac, 0x7d, 0x0a, 0x3a, 0xbc, 0x69, 0xc1, 0x83, 0x65, 0xbc, 0xff, 0x59, 0x18, 0x5f, 0x33, 0x99, 0x68, 0x87, 0x74, 0x61, 0x85, 0x90, 0x6c, 0x01, 0x91, 0xae, 0xd4, 0x40, 0x7e, 0x13, 0x94, 0x46, 0x45, 0x9b, 0xe2, 0x9c, 0x68, 0x22, 0x71, 0x76, 0x44, 0x35, 0x3d, 0x24, 0xab, 0x63, 0x39, 0x15, 0x6a, 0x9c, 0x42, 0x49, 0x09, 0xf0, 0xa9, 0x02, 0x5b, 0xb7, 0x47, 0x20, 0x77, 0x9b, 0xe4, 0x3f, 0x16, 0xd8, 0x1c, 0x8c, 0xc6, 0x66, 0xe9, 0x97, 0x10, 0xd8, 0xc6, 0x8b, 0xb5, 0xcc, 0x4e, 0x12, 0xf3, 0x14, 0xe9, 0x25, 0xa5, 0x51, 0xf0, 0x9c, 0xc5, 0x90, 0x03, 0xa1, 0xf8, 0x81, 0x03, 0xc2, 0x54, 0xbb, 0x97, 0x8d, 0x75, 0xf3, 0x94, 0xd3, 0x54, 0x0e, 0x31, 0xe7, 0x71, 0xcd, 0xa3, 0x6e, 0x39, 0xec, 0x54, 0xa6, 0x2b, 0x58, 0x32, 0x66, 0x4d, 0x82, 0x1a, 0x72, 0xf1, 0xe6, 0xaf, 0xbb, 0xa2, 0x7f, 0x84, 0x29, 0x5b, 0x26, 0x94, 0xc4, 0x98, 0x49, 0x8e, 0x81, 0x2b, 0xc8, 0xe9, 0x37, 0x8f, 0xe5, 0x41, 0xce, 0xc5, 0x89, 0x1b, 0x25, 0x06, 0x29, 0x01, 0xcb, 0x72, 0x12, 0xe3, 0xcd, 0xc4, 0x61, 0x79, 0xec, 0x5b, 0xce, 0xc1, 0x0b, 0xc0, 0xb9, 0x31, 0x1d, 0xe0, 0x50, 0x74, 0x29, 0x06, 0x87, 0xfd, 0x6a, 0x53, 0x92, 0x67, 0x16, 0x54, 0x28, 0x4c, 0xd9, 0xc8, 0xcc, 0x3e, 0xba, 0x80, 0xeb, 0x3b, 0x66, 0x2e, 0xb5, 0x3e, 0xb7, 0x51, 0x16, 0x70, 0x4a, 0x1f, 0xeb, 0x5c, 0x2d, 0x05, 0x63, 0x38, 0x53, 0x28, 0x68, 0xdd, 0xf2, 0x4e, 0xb8, 0x99, 0x2a, 0xb8, 0x56, 0x5d, 0x9e, 0x49, 0x0c, 0xad, 0xf1, 0x48, 0x04, 0x36, 0x0d, 0xaa, 0x90, 0x71, 0x8e, 0xab, 0x61, 0x6b, 0xab, 0x07, 0x65, 0xd3, 0x39, 0x87, 0xb4, 0x7e, 0xfb, 0x65, 0x99, 0xc5, 0x56, 0x32, 0x35, 0xe6, 0x1e, 0x4b, 0xe6, 0x70, 0xe9, 0x79, 0x55, 0xab, 0x29, 0x2d, 0x97, 0x32, 0xcb, 0x89, 0x30, 0x94, 0x8a, 0xc8, 0x2d, 0xf2, 0x30, 0xac, 0x72, 0x29, 0x7a, 0x23, 0x67, 0x9d, 0x6b, 0x94, 0xc1, 0x7f, 0x13, 0x59, 0x48, 0x32, 0x54, 0xfe, 0xdc, 0x2f, 0x05, 0x81, 0x9f, 0x0d, 0x06, 0x9a, 0x44, 0x3b, 0x78, 0xe3, 0xfc, 0x6c, 0x3e, 0xf4, 0x71, 0x4b, 0x05, 0xa3, 0xfc, 0xa8, 0x1c, 0xbb, 0xa6, 0x02, 0x42, 0xa7, 0x06, 0x0c, 0xd8, 0x85, 0xd8, 0xf3, 0x99, 0x81, 0xbb, 0x18, 0x09, 0x2b, 0x23, 0xda, 0xa5, 0x9f, 0xd9, 0x57, 0x83, 0x88, 0x68, 0x8a, 0x09, 0xbb, 0xa0, 0x79, 0xbc, 0x80, 0x9a, 0x54, 0x84, 0x3a, 0x60, 0x38, 0x5e, 0x23, 0x10, 0xbb, 0xcb, 0xcc, 0x02, 0x13, 0xce, 0x3d, 0xfa, 0xab, 0x33, 0xb4, 0x7f, 0x9d, 0x63, 0x05, 0xbc, 0x95, 0xc6, 0x10, 0x78, 0x13, 0xc5, 0x85, 0xc4, 0xb6, 0x57, 0xbf, 0x30, 0x54, 0x28, 0x33, 0xb1, 0x49, 0x49, 0xf5, 0x73, 0xc0, 0x61, 0x2a, 0xd5, 0x24, 0xba, 0xae, 0x69, 0x59, 0x0c, 0x12, 0x77, 0xb8, 0x6c, 0x28, 0x65, 0x71, 0xbf, 0x66, 0xb3, 0xcf, 0xf4, 0x6a, 0x38, 0x58, 0xc0, 0x99, 0x06, 0xa7, 0x94, 0xdf, 0x4a, 0x06, 0xe9, 0xd4, 0xb0, 0xa2, 0xe4, 0x3f, 0x10, 0xf7, 0x2a, 0x6c, 0x6c, 0x47, 0xe5, 0x64, 0x6e, 0x2c, 0x79, 0x9b, 0x71, 0xc3, 0x3e, 0xd2, 0xf0, 0x1e, 0xeb, 0x45, 0x93, 0x8e, 0xb7, 0xa4, 0xe2, 0xe2, 0x90, 0x8c, 0x53, 0x55, 0x8a, 0x54, 0x0d, 0x35, 0x03, 0x69, 0xfa, 0x18, 0x9c, 0x61, 0x69, 0x43, 0xf7, 0x98, 0x1d, 0x76, 0x18, 0xcf, 0x02, 0xa5, 0xb0, 0xa2, 0xbc, 0xc4, 0x22, 0xe8, 0x57, 0xd1, 0xa4, 0x78, 0x71, 0x25, 0x3d, 0x08, 0x29, 0x3c, 0x1c, 0x17, 0x9b, 0xcd, 0xc0, 0x43, 0x70, 0x69, 0x10, 0x74, 0x18, 0x20, 0x5f, 0xdb, 0x98, 0x56, 0x62, 0x3b, 0x8c, 0xa6, 0xb6, 0x94, 0xc9, 0x6c, 0x08, 0x4b, 0x17, 0xf1, 0x3b, 0xb6, 0xdf, 0x12, 0xb2, 0xcf, 0xbb, 0xc2, 0xb0, 0xe0, 0xc3, 0x4b, 0x00, 0xd0, 0xfc, 0xd0, 0xae, 0xcf, 0xb2, 0x79, 0x24, 0xf6, 0x98, 0x4e, 0x74, 0x7b, 0xe2, 0xa0, 0x9d, 0x83, 0xa8, 0x66, 0x45, 0x90, 0xa8, 0x07, 0x73, 0x31, 0x49, 0x1a, 0x4f, 0x7d, 0x72, 0x08, 0x43, 0xf2, 0x3e, 0x65, 0x2c, 0x6f, 0xa8, 0x40, 0x30, 0x8d, 0xb4, 0x02, 0x03, 0x37, 0xaa, 0xd3, 0x79, 0x67, 0x03, 0x4a, 0x9f, 0xb5, 0x23, 0xb6, 0x7c, 0xa7, 0x03, 0x30, 0xf0, 0x2d, 0x9e, 0xa2, 0x0c, 0x1e, 0x84, 0xcb, 0x8e, 0x57, 0x57, 0xc9, 0xe1, 0x89, 0x6b, 0x60, 0x58, 0x14, 0x41, 0xed, 0x61, 0x8a, 0xa5, 0xb2, 0x6d, 0xa5, 0x6c, 0x0a, 0x5a, 0x73, 0xc4, 0xdc, 0xfd, 0x75, 0x5e, 0x61, 0x0b, 0x4f, 0xc8, 0x1f, 0xf8, 0x4e, 0x21, 0xd2, 0xe5, 0x74, 0xdf, 0xd8, 0xcd, 0x0a, 0xe8, 0x93, 0xaa, 0x7e, 0x12, 0x5b, 0x44, 0xb9, 0x24, 0xf4, 0x52, 0x23, 0xec, 0x09, 0xf2, 0xad, 0x11, 0x41, 0xea, 0x93, 0xa6, 0x80, 0x50, 0xdb, 0xf6, }, .pk_len = 1568, }, { .name = "ML-KEM 1024 (seed only)", .parameter_set = CKP_IBM_ML_KEM_1024, .priv_seed = { 0xBE, 0xBA, 0x64, 0x0E, 0x5E, 0x21, 0x4E, 0x2A, 0x2A, 0xF8, 0xD2, 0x61, 0xDC, 0xDC, 0x80, 0x34, 0xA3, 0x20, 0xF9, 0xD6, 0xE2, 0x17, 0x56, 0xEC, 0x59, 0x22, 0xF9, 0x05, 0x62, 0x25, 0xD2, 0xB0, 0x0A, 0x28, 0x2C, 0x21, 0x49, 0xC5, 0x7B, 0xB8, 0xF9, 0x4B, 0x94, 0x82, 0x2A, 0x62, 0xCD, 0x01, 0x47, 0x1B, 0xAF, 0x25, 0xDD, 0xE5, 0x22, 0xA4, 0x26, 0x7C, 0x17, 0x34, 0x43, 0x54, 0xDE, 0x67 }, .priv_seed_len = 64, .spki = { 0x30, 0x82, 0x06, 0x32, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x04, 0x03, 0x03, 0x82, 0x06, 0x21, 0x00, 0xc8, 0x27, 0xc8, 0xd4, 0x96, 0xb4, 0x0b, 0x85, 0xc6, 0xb8, 0xc6, 0xa8, 0x89, 0x81, 0x2b, 0xf3, 0x21, 0xcf, 0x0e, 0xe5, 0x42, 0x0a, 0xc1, 0xac, 0x99, 0x14, 0x8f, 0x7b, 0x15, 0x80, 0x4e, 0x06, 0xc9, 0xdd, 0x43, 0x3d, 0x51, 0xd9, 0x5e, 0xe3, 0x70, 0xb9, 0x8b, 0x38, 0x1a, 0xf3, 0x1c, 0x34, 0x6d, 0x73, 0x0a, 0x9e, 0x96, 0x9c, 0xa9, 0x23, 0xb9, 0x00, 0x76, 0xbb, 0xf8, 0x43, 0x26, 0x53, 0xa6, 0xcc, 0x96, 0x87, 0x5e, 0x0a, 0x9c, 0x1a, 0x11, 0xc4, 0x71, 0x6d, 0x14, 0xb8, 0xf4, 0xc7, 0x78, 0x34, 0xea, 0x57, 0x1b, 0xf3, 0x98, 0x7d, 0xf5, 0x1a, 0x74, 0x12, 0x15, 0xfe, 0x93, 0x72, 0xbc, 0xd5, 0x50, 0xdb, 0x91, 0x27, 0x83, 0x25, 0x8d, 0x52, 0xe3, 0x58, 0xfe, 0x48, 0x1d, 0xe8, 0x36, 0xcb, 0xc6, 0xd2, 0x62, 0x46, 0xb4, 0x05, 0x9d, 0x3c, 0xb4, 0x3d, 0x5a, 0x64, 0xb0, 0x20, 0xb3, 0xa0, 0xe7, 0x1d, 0x45, 0xe6, 0xb1, 0x76, 0x65, 0x04, 0xd1, 0x9a, 0x36, 0xc5, 0xc8, 0x46, 0x8e, 0xa1, 0x88, 0x97, 0x3a, 0x61, 0xde, 0x79, 0x4e, 0xcf, 0x94, 0x94, 0x14, 0x32, 0x8e, 0xd9, 0x60, 0x5e, 0x5a, 0xc1, 0x26, 0x7c, 0x37, 0x44, 0x15, 0x7b, 0x42, 0xe4, 0x26, 0x31, 0x70, 0x17, 0xc1, 0x40, 0xca, 0x7a, 0x9a, 0x6b, 0x40, 0x0f, 0xf0, 0x83, 0x7b, 0x52, 0xbe, 0x2d, 0xe0, 0x3e, 0xdb, 0xb1, 0xa1, 0x4d, 0xda, 0x05, 0xf0, 0xe2, 0x14, 0x38, 0xb3, 0xbb, 0xe5, 0x2b, 0x1f, 0xd2, 0x4c, 0xbc, 0xe9, 0x7b, 0xb6, 0xa2, 0x10, 0x6d, 0x51, 0xf4, 0x34, 0xc6, 0x13, 0xcd, 0xd6, 0xc7, 0xc8, 0x5c, 0x94, 0xb6, 0x8a, 0xe6, 0x73, 0xf4, 0x44, 0x30, 0x72, 0x41, 0x24, 0xb1, 0xa5, 0xcd, 0xa3, 0x07, 0xcd, 0x5d, 0xc6, 0x8a, 0xd3, 0x20, 0x1d, 0x2a, 0x76, 0x97, 0x85, 0xab, 0x2d, 0x2b, 0xd7, 0x06, 0xf1, 0x33, 0x14, 0x9f, 0xf7, 0xb8, 0x09, 0x7c, 0x30, 0xbe, 0x24, 0xcd, 0x87, 0x23, 0x8b, 0xb6, 0x11, 0xaa, 0x8e, 0xb9, 0x05, 0xe6, 0xb9, 0xb1, 0x97, 0xb2, 0x63, 0xb1, 0x92, 0x52, 0x2f, 0x9a, 0x3a, 0x41, 0x67, 0x8f, 0xc9, 0x00, 0x24, 0x00, 0x8d, 0xaf, 0x79, 0xb2, 0x9e, 0xfe, 0x8b, 0x24, 0xeb, 0xc5, 0x0d, 0x2a, 0x47, 0x22, 0x4a, 0x2c, 0x23, 0x34, 0x66, 0xcb, 0x81, 0x33, 0x02, 0xa9, 0x34, 0xb1, 0x96, 0x35, 0x93, 0x68, 0x95, 0x7f, 0xab, 0xec, 0x35, 0x1a, 0x05, 0xb7, 0x0d, 0x16, 0x30, 0x1f, 0xd5, 0x4e, 0x9b, 0x90, 0x02, 0x11, 0x28, 0x6b, 0xc9, 0x55, 0x92, 0x10, 0xf3, 0x8b, 0x08, 0x44, 0x09, 0x01, 0x38, 0x2c, 0x23, 0xf7, 0x41, 0x60, 0x47, 0xc7, 0x19, 0xc6, 0xab, 0x2b, 0xbc, 0x96, 0x35, 0x78, 0x83, 0xd0, 0x60, 0x34, 0x11, 0x58, 0xa5, 0x9b, 0xc8, 0x7c, 0xc8, 0x5c, 0x34, 0xbd, 0xac, 0x7f, 0xdd, 0xa8, 0xaf, 0x62, 0xe4, 0x27, 0x82, 0x29, 0x6e, 0x03, 0xb1, 0x61, 0x37, 0xc6, 0x39, 0x82, 0x78, 0x6e, 0x16, 0x05, 0xa4, 0x08, 0xa3, 0xcd, 0xa2, 0xc7, 0xc6, 0xab, 0xf0, 0x90, 0x6d, 0xa6, 0xac, 0x58, 0xe4, 0x31, 0xb7, 0x66, 0x57, 0xd4, 0x81, 0x20, 0xcb, 0x8a, 0x22, 0x58, 0xb0, 0xae, 0xf0, 0x50, 0x77, 0x08, 0x63, 0x6e, 0xc6, 0x21, 0x93, 0x03, 0x40, 0x84, 0x1e, 0xcb, 0x0b, 0x4d, 0xe1, 0x22, 0xa9, 0x8a, 0x47, 0xa5, 0xd1, 0x63, 0x5c, 0xc5, 0x7f, 0x6a, 0x45, 0xb8, 0x39, 0xb3, 0x31, 0x22, 0xe9, 0x79, 0xd9, 0x28, 0x9d, 0x04, 0xa4, 0xa3, 0x30, 0x12, 0x23, 0x10, 0x7b, 0x94, 0xb5, 0x66, 0x26, 0x88, 0x73, 0xa3, 0x61, 0x41, 0x4d, 0xc3, 0x84, 0x68, 0xd8, 0x98, 0x9d, 0x7f, 0xba, 0x31, 0xe0, 0x5a, 0x5d, 0x4b, 0x6b, 0xb2, 0x9a, 0x84, 0x12, 0x9e, 0x15, 0x58, 0x79, 0x09, 0x70, 0xcc, 0xe6, 0x5d, 0x61, 0x51, 0x70, 0xd4, 0x5c, 0x50, 0x6d, 0x95, 0x52, 0x14, 0x10, 0x95, 0x01, 0x81, 0xcd, 0x0c, 0xe8, 0x1a, 0x58, 0xa3, 0x9f, 0x01, 0xac, 0x8a, 0xbc, 0xc6, 0x88, 0x75, 0x35, 0x39, 0x69, 0x80, 0x54, 0xdd, 0x2b, 0x4b, 0xb0, 0x1b, 0x5d, 0xbd, 0x5c, 0x67, 0xb8, 0xfc, 0x3b, 0x0b, 0xf6, 0x32, 0x7e, 0x9c, 0x6d, 0x4d, 0x13, 0x81, 0xec, 0x15, 0x4c, 0xb1, 0x99, 0xbc, 0xe6, 0xdb, 0x58, 0x77, 0xf3, 0x83, 0x4a, 0xa8, 0x0f, 0x84, 0x14, 0x63, 0xa9, 0x70, 0x2d, 0xd7, 0x23, 0x3f, 0xc5, 0x91, 0x6b, 0x49, 0xc0, 0x00, 0x7c, 0x52, 0xa6, 0xc5, 0x3a, 0x88, 0xca, 0xfa, 0x49, 0xa3, 0x39, 0x3b, 0xa3, 0xd3, 0x21, 0xac, 0x52, 0xb4, 0xa0, 0xe9, 0xc0, 0xb1, 0x31, 0x35, 0xcf, 0x1c, 0x66, 0x38, 0x51, 0x60, 0x10, 0xdb, 0x3d, 0x80, 0x25, 0xa0, 0x29, 0x4c, 0xc7, 0x13, 0x5c, 0x7b, 0xa8, 0xb1, 0x46, 0x70, 0xa8, 0xbb, 0x9b, 0xdc, 0xc6, 0xb2, 0x9a, 0x51, 0x3b, 0x22, 0x35, 0xcf, 0x92, 0xaf, 0x27, 0x5b, 0x09, 0x1d, 0x24, 0x3c, 0x85, 0x16, 0xa5, 0xb9, 0xc4, 0x67, 0x3a, 0x47, 0x6b, 0x7f, 0x19, 0x40, 0xc3, 0x57, 0xb7, 0x1c, 0xe0, 0xc3, 0x80, 0xec, 0xbe, 0xe5, 0x74, 0x44, 0xdb, 0xd0, 0x8f, 0xe9, 0x12, 0x08, 0x1c, 0x44, 0xac, 0xa4, 0x32, 0xb4, 0xb0, 0x1a, 0x68, 0x10, 0x4c, 0x99, 0xe0, 0x97, 0xb5, 0x6c, 0x51, 0x9c, 0xac, 0x38, 0xaf, 0xa7, 0xf2, 0x5d, 0x68, 0xc9, 0x93, 0xd2, 0x46, 0x4a, 0xe1, 0x75, 0x4a, 0xf4, 0xd4, 0x12, 0xdf, 0xc4, 0x42, 0x4b, 0xb4, 0x6f, 0x35, 0x0c, 0x0b, 0xcc, 0xe6, 0x90, 0xad, 0x8b, 0xac, 0xce, 0xf4, 0x11, 0x63, 0x7c, 0x43, 0x00, 0x7b, 0x5c, 0xb9, 0x02, 0x2e, 0x2b, 0x46, 0xc2, 0x8b, 0x91, 0x9e, 0x26, 0xa9, 0xb7, 0xe8, 0xa1, 0xbb, 0x1c, 0xb7, 0xc4, 0x89, 0x43, 0x33, 0x16, 0x20, 0xb5, 0x84, 0xd4, 0xcb, 0x39, 0x98, 0x91, 0x2d, 0x47, 0x9e, 0xaf, 0x4c, 0x7f, 0x51, 0x82, 0x5f, 0x20, 0xf4, 0x63, 0xf4, 0x08, 0x76, 0xb2, 0x5c, 0x03, 0x1a, 0x07, 0xa3, 0x38, 0x39, 0x8e, 0x41, 0xa1, 0xa2, 0x20, 0x16, 0x99, 0x9d, 0xd3, 0x02, 0x83, 0x61, 0x4c, 0x48, 0x67, 0x6e, 0xef, 0x86, 0x75, 0x4f, 0x11, 0x3a, 0x31, 0x75, 0x45, 0x9f, 0x3b, 0xb3, 0x1e, 0x6c, 0x29, 0x1d, 0xe8, 0x9f, 0xd2, 0xa0, 0xbd, 0xbc, 0x14, 0xbb, 0x83, 0x55, 0x0c, 0x44, 0xd5, 0xbf, 0x56, 0xb6, 0xc1, 0x49, 0x8a, 0x94, 0xc1, 0x35, 0x34, 0x32, 0xba, 0x24, 0xcf, 0x36, 0x9c, 0x96, 0x84, 0x81, 0x21, 0xb1, 0x6d, 0x33, 0x5a, 0x62, 0x7e, 0x20, 0xba, 0xdb, 0xc5, 0x54, 0xda, 0x33, 0x26, 0xbc, 0x28, 0x1e, 0xa2, 0xba, 0x37, 0xa9, 0x64, 0x7d, 0x1d, 0xeb, 0x5b, 0x22, 0x53, 0x3e, 0x2a, 0xd3, 0xc3, 0xd2, 0xa3, 0xb1, 0x2f, 0xdb, 0x47, 0xb4, 0xba, 0x47, 0x67, 0x37, 0x26, 0x0d, 0x11, 0x6f, 0x80, 0x15, 0x54, 0x6c, 0x03, 0x19, 0xf4, 0xd8, 0x5a, 0x46, 0x55, 0x8c, 0x9f, 0xa5, 0x1c, 0xd4, 0xb7, 0x35, 0x6c, 0x96, 0x93, 0x61, 0x72, 0xa8, 0xa6, 0xa6, 0xb2, 0x30, 0x03, 0xc7, 0x91, 0xfc, 0xce, 0x3b, 0x7b, 0xac, 0x77, 0x69, 0xbc, 0x82, 0xf7, 0x7b, 0xfd, 0x68, 0x15, 0x01, 0xb2, 0x72, 0x84, 0xd9, 0xb0, 0x6f, 0x56, 0x6c, 0xe4, 0x2a, 0x95, 0x71, 0x12, 0x72, 0x2d, 0xf5, 0x77, 0x76, 0xa7, 0xba, 0xa7, 0x44, 0x78, 0xad, 0xba, 0x40, 0x6e, 0x85, 0x68, 0x5d, 0x66, 0x66, 0xfc, 0xba, 0xa7, 0x91, 0xc6, 0x7b, 0x38, 0xe4, 0x8a, 0x64, 0xb8, 0x7b, 0x1e, 0x71, 0x49, 0x23, 0x25, 0x66, 0x12, 0x71, 0x9f, 0x67, 0x21, 0x30, 0xe5, 0x41, 0x0a, 0x1b, 0x91, 0x2b, 0x10, 0xf9, 0xcd, 0xe8, 0xcc, 0x51, 0x50, 0x29, 0x1a, 0x94, 0x6c, 0x4b, 0x1c, 0x0b, 0xbc, 0x8d, 0xac, 0x49, 0x69, 0x57, 0x12, 0xa5, 0x76, 0x66, 0x4f, 0x57, 0xaf, 0xfb, 0x71, 0x90, 0x19, 0x58, 0x90, 0x8e, 0x0c, 0x1f, 0x17, 0x86, 0xaa, 0x00, 0x8a, 0xb9, 0xb8, 0x69, 0xa5, 0x1e, 0x1a, 0x8f, 0xf9, 0xb8, 0x6d, 0x33, 0xcc, 0x34, 0xb1, 0x95, 0x77, 0xcd, 0x1b, 0x7b, 0x29, 0xc3, 0xb6, 0xe5, 0xaa, 0x07, 0x46, 0x4a, 0x97, 0x57, 0x98, 0x8a, 0x28, 0x6a, 0x02, 0x42, 0xac, 0x50, 0x8c, 0x39, 0xce, 0xf1, 0x05, 0xa9, 0x02, 0x70, 0x78, 0xd3, 0x1c, 0x97, 0x04, 0x5b, 0xa4, 0x22, 0xa4, 0x2f, 0xf7, 0x06, 0x53, 0xca, 0x77, 0x8c, 0xe0, 0xd4, 0x07, 0x82, 0x12, 0xce, 0xbd, 0x99, 0x06, 0x22, 0x93, 0xc2, 0x1b, 0x76, 0x46, 0x90, 0xeb, 0x62, 0x09, 0xb9, 0x7d, 0x41, 0x63, 0x73, 0xb2, 0x83, 0x0d, 0x61, 0x34, 0x65, 0x24, 0x38, 0x1b, 0x47, 0xe2, 0xc3, 0xf9, 0x3b, 0x12, 0x70, 0xa7, 0x03, 0xe3, 0x21, 0x97, 0x52, 0xe8, 0x1c, 0xd7, 0xfb, 0xcf, 0x79, 0x09, 0x71, 0x29, 0x59, 0x12, 0x55, 0x52, 0x59, 0xc1, 0xdb, 0x9a, 0xaf, 0xb8, 0x8c, 0x01, 0x60, 0x51, 0xa7, 0xf0, 0x24, 0x10, 0xf6, 0x09, 0xe1, 0xb6, 0x58, 0x28, 0x16, 0x3d, 0xa4, 0x5c, 0x6c, 0x57, 0xd3, 0x0d, 0xa0, 0xda, 0x43, 0x43, 0xa8, 0xca, 0xd5, 0x4a, 0x98, 0xc4, 0xa6, 0x23, 0x63, 0x52, 0x88, 0x10, 0xd9, 0xb2, 0x75, 0xea, 0x16, 0xf0, 0x65, 0x27, 0x20, 0xb4, 0x9a, 0xe3, 0xf4, 0x9c, 0x0a, 0xf5, 0x07, 0x77, 0x77, 0x40, 0x31, 0x1a, 0xcc, 0xd8, 0x63, 0xcc, 0xa3, 0xd8, 0xad, 0x30, 0x33, 0x9a, 0x55, 0x97, 0x53, 0xac, 0xa6, 0xa9, 0xd8, 0x11, 0xb6, 0x30, 0xab, 0x3b, 0xd1, 0x75, 0x5d, 0xa3, 0x07, 0x44, 0xcf, 0xd7, 0x99, 0x4d, 0x97, 0x1b, 0x72, 0x43, 0xca, 0x7a, 0xc9, 0xaa, 0xaa, 0xf5, 0x7c, 0x82, 0x31, 0x21, 0xfa, 0x29, 0xb1, 0xd3, 0x42, 0xbd, 0xc6, 0xb9, 0x90, 0x1d, 0x32, 0xa9, 0xfc, 0x11, 0x4c, 0x04, 0xb8, 0x3f, 0x7e, 0x3c, 0x4d, 0xd9, 0x6c, 0x4a, 0xe5, 0x92, 0x47, 0x6c, 0xc9, 0x90, 0x02, 0xb1, 0x77, 0xa4, 0xab, 0x19, 0x97, 0x31, 0x3c, 0x7e, 0x37, 0x1a, 0x13, 0x82, 0xcf, 0x86, 0x73, 0x22, 0x1a, 0xfa, 0x80, 0x0a, 0x10, 0x40, 0x53, 0xe6, 0xcd, 0xf1, 0x89, 0x1e, 0xd1, 0xd4, 0x6a, 0x9f, 0x1b, 0x71, 0x55, 0x06, 0x0c, 0xe0, 0x81, 0x62, 0x3a, 0xd1, 0x8b, 0x8b, 0xe5, 0xa7, 0x1c, 0xb4, 0x6d, 0x10, 0x4c, 0x11, 0x58, 0xe7, 0x95, 0x9a, 0x1c, 0xbf, 0x0b, 0x57, 0x87, 0x18, 0x0b, 0x89, 0xad, 0x0b, 0x2c, 0x24, 0xf5, 0x18, 0x66, 0x0b, 0x6c, 0x32, 0xa4, 0x0a, 0xd9, 0xd1, 0x72, 0x25, 0x29, 0xc5, 0x7c, 0x59, 0x4c, 0xce, 0x48, 0x59, 0x6a, 0x41, 0x21, 0x7f, 0xf0, 0xb3, 0xe9, 0x4b, 0x6b, 0xa5, 0xe0, 0x72, 0x9d, 0x3c, 0xa1, 0xce, 0x88, 0x01, 0x81, 0xb8, 0x92, 0x98, 0x03, 0x47, 0x6c, 0x50, 0x5e, 0x43, 0x53, 0x1f, 0x6d, 0x01, 0xc4, 0x22, 0xd3, 0x5c, 0x93, 0x61, 0x2b, 0x0d, 0xe0, 0xb0, 0x0d, 0x38, 0x5b, 0xc3, 0x73, 0xa1, 0xa9, 0x99, 0x5a, 0x76, 0x3b, 0x6e, 0x5d, 0x5a, 0xa4, 0xd9, 0x86, 0x0e, 0x68, 0x66, 0xa4, 0xf5, 0x58, 0x8f, 0x88, 0xf4, 0xbb, 0x1c, 0x09, 0xa8, 0x6e, 0xf4, 0x94, 0x61, 0x70, 0x5f, 0x4f, 0x83, 0x49, 0x94, 0xf7, 0xb8, 0x41, 0xe8, 0x08, 0x1d, 0x75, 0x23, 0x16, 0x66, 0x3b, 0xc6, 0x49, 0x52, 0xdf, 0x51, 0x7d, 0xd5, 0x1c, 0x41, 0x35, 0x3a, 0x64, 0x2a, 0xe4, 0xcb, 0x6f, 0xe3, 0xb0, 0xb7, 0x9e, 0x36, 0xa1, 0xfd, 0xdf, 0xee, 0x17, 0x41, 0xe1, 0x6e, 0x88, 0xc3, 0xf1, 0x1c, 0x65, 0x61, 0x33, 0xfd, 0x50, 0x67, 0x25, 0xc2, 0x38, 0x07, 0x55, 0xac, 0x45, 0xdb }, .spki_len = 1590, }, }; #define ML_KEM_TV_NUM sizeof(ml_kem_tv)/sizeof(struct ML_KEM_TEST_VECTOR) opencryptoki-opencryptoki-451d99c/testcases/crypto/ibm_ml_kem_func.c000066400000000000000000001402241520105705100261170ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2025 * * 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 "mechtable.h" #include "ec_curves.h" #include "ibm_ml_kem.h" /** * Support for IBM ML-KEM keys and KEM * with oid = 2.16.840.1.101.3.4.4.xxx */ const CK_BYTE prime256v1[] = OCK_PRIME256V1; typedef struct variant_info { const char *name; CK_IBM_ML_KEM_PARAMETER_SET_TYPE parameter_set; } _variant_info; const _variant_info variants[] = { { "ML_KEM_512", CKP_IBM_ML_KEM_512, }, { "ML_KEM_768", CKP_IBM_ML_KEM_768, }, { "ML_KEM_1024", CKP_IBM_ML_KEM_1024, }, }; const CK_ULONG num_variants = sizeof(variants) / sizeof(_variant_info); typedef struct kemParam { CK_IBM_ML_KEM_KDF_TYPE kdf; CK_KEY_TYPE secret_key_type; CK_ULONG secret_key_len; CK_ULONG shard_data_len; CK_BYTE shared_data[32]; CK_BBOOL hybrid; CK_BBOOL prepend; } _kemParam; const _kemParam kemInput[] = { { CKD_NULL, CKK_AES, 32, 0, {0x00}, CK_FALSE, CK_FALSE }, { CKD_IBM_HYBRID_SHA1_KDF, CKK_GENERIC_SECRET, 16, 0, {0x00}, CK_TRUE, CK_FALSE }, { CKD_IBM_HYBRID_SHA1_KDF, CKK_GENERIC_SECRET, 32, 16, { 0x32,0x3F,0xA3,0x16,0x9D,0x8E,0x9C,0x65,0x93,0xF5,0x94,0x76,0xBC,0x14,0x20,0x00 }, CK_TRUE, CK_TRUE }, { CKD_IBM_HYBRID_SHA224_KDF, CKK_GENERIC_SECRET, 16, 0, {0x00}, CK_TRUE, CK_FALSE }, { CKD_IBM_HYBRID_SHA224_KDF, CKK_GENERIC_SECRET, 32, 16, { 0x32,0x3F,0xA3,0x16,0x9D,0x8E,0x9C,0x65,0x93,0xF5,0x94,0x76,0xBC,0x14,0x20,0x00 }, CK_TRUE, CK_TRUE }, { CKD_IBM_HYBRID_SHA256_KDF, CKK_GENERIC_SECRET, 16, 0, {0x00}, CK_TRUE, CK_FALSE }, { CKD_IBM_HYBRID_SHA256_KDF, CKK_GENERIC_SECRET, 32, 16, { 0x32,0x3F,0xA3,0x16,0x9D,0x8E,0x9C,0x65,0x93,0xF5,0x94,0x76,0xBC,0x14,0x20,0x00 }, CK_TRUE, CK_TRUE }, { CKD_IBM_HYBRID_SHA384_KDF, CKK_GENERIC_SECRET, 16, 0, {0x00}, CK_TRUE, CK_FALSE }, { CKD_IBM_HYBRID_SHA384_KDF, CKK_GENERIC_SECRET, 32, 16, { 0x32,0x3F,0xA3,0x16,0x9D,0x8E,0x9C,0x65,0x93,0xF5,0x94,0x76,0xBC,0x14,0x20,0x00 }, CK_TRUE, CK_TRUE }, { CKD_IBM_HYBRID_SHA512_KDF, CKK_GENERIC_SECRET, 16, 0, {0x00}, CK_TRUE, CK_FALSE }, { CKD_IBM_HYBRID_SHA512_KDF, CKK_GENERIC_SECRET, 32, 16, { 0x32,0x3F,0xA3,0x16,0x9D,0x8E,0x9C,0x65,0x93,0xF5,0x94,0x76,0xBC,0x14,0x20,0x00 }, CK_TRUE, CK_TRUE }, { CKD_IBM_HYBRID_SHA224_KDF, CKK_AES, 32, 0, {0x00}, CK_TRUE, CK_FALSE }, { CKD_IBM_HYBRID_SHA224_KDF, CKK_AES, 32, 16, { 0x32,0x3F,0xA3,0x16,0x9D,0x8E,0x9C,0x65,0x93,0xF5,0x94,0x76,0xBC,0x14,0x20,0x00 }, CK_TRUE, CK_TRUE }, { CKD_IBM_HYBRID_SHA256_KDF, CKK_AES, 32, 0, {0x00}, CK_TRUE, CK_FALSE }, { CKD_IBM_HYBRID_SHA256_KDF, CKK_AES, 32, 16, { 0x32,0x3F,0xA3,0x16,0x9D,0x8E,0x9C,0x65,0x93,0xF5,0x94,0x76,0xBC,0x14,0x20,0x00 }, CK_TRUE, CK_TRUE }, { CKD_IBM_HYBRID_SHA384_KDF, CKK_AES, 32, 0, {0x00}, CK_TRUE, CK_FALSE }, { CKD_IBM_HYBRID_SHA384_KDF, CKK_AES, 32, 16, { 0x32,0x3F,0xA3,0x16,0x9D,0x8E,0x9C,0x65,0x93,0xF5,0x94,0x76,0xBC,0x14,0x20,0x00 }, CK_TRUE, CK_TRUE }, { CKD_IBM_HYBRID_SHA512_KDF, CKK_AES, 32, 0, {0x00}, CK_TRUE, CK_FALSE }, { CKD_IBM_HYBRID_SHA512_KDF, CKK_AES, 32, 16, { 0x32,0x3F,0xA3,0x16,0x9D,0x8E,0x9C,0x65,0x93,0xF5,0x94,0x76,0xBC,0x14,0x20,0x00 }, CK_TRUE, CK_TRUE }, }; 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"; case CKD_IBM_HYBRID_NULL: return "CKD_IBM_HYBRID_NULL"; case CKD_IBM_HYBRID_SHA1_KDF: return "CKD_IBM_HYBRID_SHA1_KDF"; case CKD_IBM_HYBRID_SHA224_KDF: return "CKD_IBM_HYBRID_SHA224_KDF"; case CKD_IBM_HYBRID_SHA256_KDF: return "CKD_IBM_HYBRID_SHA256_KDF"; case CKD_IBM_HYBRID_SHA384_KDF: return "CKD_IBM_HYBRID_SHA384_KDF"; case CKD_IBM_HYBRID_SHA512_KDF: return "CKD_IBM_HYBRID_SHA512_KDF"; default: return "UNKNOWN"; } } #define NUM_KEM_INPUTS sizeof(kemInput)/sizeof(_kemParam) /* * Perform a AES encrypt and decrypt that the key is usable. */ CK_RV run_AESCrypt(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE h_key1, CK_OBJECT_HANDLE h_key2) { CK_MECHANISM mech = { .mechanism = CKM_AES_ECB, .pParameter = NULL, .ulParameterLen = 0 }; CK_BYTE data[32] = { 0 }; CK_BYTE out[32] = { 0 }; CK_ULONG out_len = sizeof(out); CK_RV rc = CKR_OK; if (!mech_supported(SLOT_ID, CKM_AES_ECB)) { testcase_notice("Mechanism CKM_AES_ECB is not supported with slot " "%lu. Skipping key check", SLOT_ID); return CKR_OK; } rc = funcs->C_EncryptInit(session, &mech, h_key1); if (rc != CKR_OK) { testcase_notice("C_EncryptInit rc=%s", p11_get_ckr(rc)); goto error; } /** do encrypting **/ rc = funcs->C_Encrypt(session, data, sizeof(data), out, &out_len); if (rc != CKR_OK) { testcase_notice("C_Encrypt rc=%s", p11_get_ckr(rc)); goto error; } rc = funcs->C_DecryptInit(session, &mech, h_key2); if (rc != CKR_OK) { testcase_notice("C_DecryptInit rc=%s", p11_get_ckr(rc)); goto error; } /** do decrypt **/ rc = funcs->C_Decrypt(session, out, out_len, data, &out_len); if (rc != CKR_OK) { testcase_notice("C_Decrypt rc=%s", p11_get_ckr(rc)); goto error; } error: return rc; } /* * Perform a HMAC sign to verify that the key is usable. */ CK_RV run_HMACSign(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE h_key1, CK_OBJECT_HANDLE h_key2, CK_ULONG key_len) { CK_MECHANISM mech = { .mechanism = CKM_SHA_1_HMAC, .pParameter = NULL, .ulParameterLen = 0 }; CK_BYTE data[32] = { 0 }; CK_BYTE mac[SHA1_HASH_SIZE] = { 0 }; CK_ULONG mac_len = sizeof(mac); CK_RV rc = CKR_OK; if (!mech_supported(SLOT_ID, CKM_SHA_1_HMAC)) { testcase_notice("Mechanism CKM_SHA_1_HMAC is not supported with slot " "%lu. Skipping key check", SLOT_ID); return CKR_OK; } if (!check_supp_keysize(SLOT_ID, CKM_SHA_1_HMAC, key_len * 8)) { testcase_notice("Mechanism CKM_SHA_1_HMAC can not be used with keys " "of size %lu. Skipping key check", key_len); return CKR_OK; } rc = funcs->C_SignInit(session, &mech, h_key1); if (rc != CKR_OK) { testcase_notice("C_SignInit rc=%s", p11_get_ckr(rc)); goto error; } /** do signing **/ rc = funcs->C_Sign(session, data, sizeof(data), mac, &mac_len); if (rc != CKR_OK) { testcase_notice("C_Sign rc=%s", p11_get_ckr(rc)); goto error; } rc = funcs->C_VerifyInit(session, &mech, h_key2); if (rc != CKR_OK) { testcase_notice("C_VerifyInit rc=%s", p11_get_ckr(rc)); goto error; } /** do verify **/ rc = funcs->C_Verify(session, data, sizeof(data), mac, mac_len); if (rc != CKR_OK) { testcase_notice("C_Verify rc=%s", p11_get_ckr(rc)); goto error; } error: return rc; } CK_RV ecdh_derive_secret(CK_SESSION_HANDLE session, CK_ULONG secret_key_len, CK_EC_KDF_TYPE kdf, CK_OBJECT_HANDLE *hybrid_key) { CK_OBJECT_HANDLE publ_key = CK_INVALID_HANDLE; CK_OBJECT_HANDLE priv_key = CK_INVALID_HANDLE; CK_ECDH1_DERIVE_PARAMS ecda_params; CK_MECHANISM mech; CK_RV rc; CK_BYTE pubkey_value[256]; CK_ATTRIBUTE extr_tmpl[] = { {CKA_EC_POINT, pubkey_value, sizeof(pubkey_value)}, }; CK_ULONG extr_tmpl_len = sizeof(extr_tmpl)/sizeof(CK_ATTRIBUTE); CK_OBJECT_CLASS class = CKO_SECRET_KEY; CK_KEY_TYPE key_type = CKK_GENERIC_SECRET; CK_BBOOL true = CK_TRUE; CK_BBOOL false = CK_FALSE; CK_ATTRIBUTE derive_tmpl[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &key_type, sizeof(key_type)}, {CKA_SENSITIVE, &false, sizeof(false)}, {CKA_VALUE_LEN, &secret_key_len, sizeof(CK_ULONG)}, {CKA_IBM_USE_AS_DATA, &true, sizeof(true)}, }; CK_ULONG secret_tmpl_len = sizeof(derive_tmpl) / sizeof(CK_ATTRIBUTE); if (!mech_supported(SLOT_ID, CKM_EC_KEY_PAIR_GEN)) { testcase_notice("Slot %u doesn't support CKM_EC_KEY_PAIR_GEN\n", (unsigned int) SLOT_ID); return CKR_FUNCTION_NOT_SUPPORTED; } rc = generate_EC_KeyPair(session, CKM_EC_KEY_PAIR_GEN, (CK_BYTE *)prime256v1, sizeof(prime256v1), &publ_key, &priv_key, CK_FALSE); if (rc != CKR_OK) { testcase_notice("generate_EC_KeyPair rc=%s", p11_get_ckr(rc)); goto error; } rc = funcs->C_GetAttributeValue(session, publ_key, extr_tmpl, extr_tmpl_len); if (rc != CKR_OK) { testcase_notice("C_GetAttributeValue: rc = %s", p11_get_ckr(rc)); goto error; } mech.mechanism = CKM_ECDH1_DERIVE; mech.pParameter = &ecda_params; mech.ulParameterLen = sizeof(ecda_params); memset(&ecda_params, 0, sizeof(ecda_params)); ecda_params.kdf = kdf; ecda_params.pPublicData = extr_tmpl[0].pValue; ecda_params.ulPublicDataLen = extr_tmpl[0].ulValueLen; rc = funcs->C_DeriveKey(session, &mech, priv_key, derive_tmpl, secret_tmpl_len, hybrid_key); if (rc != CKR_OK) { testcase_notice("C_DeriveKey: rc = %s", p11_get_ckr(rc)); goto error; } error: if (publ_key != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, publ_key); if (priv_key != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, priv_key); return rc; } CK_RV run_EnDecapsulateMLKEM(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE priv_key, CK_OBJECT_HANDLE publ_key, CK_KEY_TYPE key_type, CK_ULONG secret_key_len, CK_IBM_ML_KEM_KDF_TYPE kdf, CK_BBOOL hybrid, CK_BBOOL prepend, const CK_BYTE *pSharedData, CK_ULONG ulSharedDataLen, const CK_BYTE *pCipher, CK_ULONG ulCipherLen, const CK_BYTE *pExpectedSecret, CK_ULONG ulExpectedSecret) { CK_MECHANISM mech; CK_IBM_ML_KEM_PARAMS ml_kem_params; CK_BYTE *cipher = NULL; CK_ULONG cipher_len = 0; CK_OBJECT_HANDLE secret_key1 = CK_INVALID_HANDLE; CK_OBJECT_HANDLE secret_key2 = CK_INVALID_HANDLE; CK_OBJECT_HANDLE hybrid_key = CK_INVALID_HANDLE; CK_OBJECT_HANDLE expected_secret_key = CK_INVALID_HANDLE; CK_RV rc; CK_OBJECT_CLASS class = CKO_SECRET_KEY; CK_BBOOL true = CK_TRUE; CK_BBOOL false = CK_FALSE; CK_ATTRIBUTE derive_tmpl[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &key_type, sizeof(key_type)}, {CKA_SENSITIVE, &false, sizeof(false)}, {CKA_VALUE_LEN, &secret_key_len, sizeof(secret_key_len)}, {CKA_SIGN, &true, sizeof(true)}, {CKA_VERIFY, &true, sizeof(true)}, }; CK_ULONG secret_tmpl_len = sizeof(derive_tmpl) / sizeof(CK_ATTRIBUTE); mech.mechanism = CKM_IBM_ML_KEM; mech.ulParameterLen = sizeof(ml_kem_params); mech.pParameter = &ml_kem_params; /* Query the slot, check if this mech if supported */ if (!mech_supported(SLOT_ID, mech.mechanism)) { testcase_notice("Slot %u doesn't support %s", (unsigned int) SLOT_ID, p11_get_ckm(&mechtable_funcs, mech.mechanism)); rc = CKR_MECHANISM_INVALID; goto testcase_cleanup; } if (hybrid) { rc = ecdh_derive_secret(session, 32, CKD_IBM_HYBRID_NULL, &hybrid_key); if (rc != CKR_OK) { testcase_error("ecdh_derive_secret() rc = %s", p11_get_ckr(rc)); goto testcase_cleanup; } } if (pCipher != NULL && ulCipherLen != 0) { cipher_len = ulCipherLen; cipher = (CK_BYTE *)pCipher; goto decapsulate; } /* Perform encapsulation with public key */ memset(&ml_kem_params, 0, sizeof(ml_kem_params)); ml_kem_params.ulVersion = CK_IBM_ML_KEM_VERSION; ml_kem_params.mode = CK_IBM_ML_KEM_ENCAPSULATE; ml_kem_params.kdf = kdf; ml_kem_params.pSharedData = (CK_BYTE *)pSharedData; ml_kem_params.ulSharedDataLen = ulSharedDataLen; ml_kem_params.bPrepend = prepend; ml_kem_params.hSecret = hybrid_key; /* Size query */ rc = funcs->C_DeriveKey(session, &mech, publ_key, derive_tmpl, secret_tmpl_len, &secret_key1); if (rc != CKR_BUFFER_TOO_SMALL) { testcase_error("C_DeriveKey (size query) rc=%s (expected CKR_BUFFER_TOO_SMALL)", p11_get_ckr(rc)); goto testcase_cleanup; } cipher_len = ml_kem_params.ulCipherLen; cipher = calloc(cipher_len, sizeof(CK_BYTE)); if (cipher == NULL) { testcase_error("Can't allocate memory for %lu bytes", sizeof(CK_BYTE) * cipher_len); rc = CKR_HOST_MEMORY; goto testcase_cleanup; } ml_kem_params.ulCipherLen = cipher_len; ml_kem_params.pCipher = cipher; /* Encapsulation */ rc = funcs->C_DeriveKey(session, &mech, publ_key, derive_tmpl, secret_tmpl_len, &secret_key1); if (rc != CKR_OK) { testcase_error("C_DeriveKey (encapsulation) rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } cipher_len = ml_kem_params.ulCipherLen; decapsulate: /* Perform Decapsulation with private key */ memset(&ml_kem_params, 0, sizeof(ml_kem_params)); ml_kem_params.ulVersion = CK_IBM_ML_KEM_VERSION; ml_kem_params.mode = CK_IBM_ML_KEM_DECAPSULATE; ml_kem_params.kdf = kdf; ml_kem_params.pSharedData = (CK_BYTE *)pSharedData; ml_kem_params.ulSharedDataLen = ulSharedDataLen; ml_kem_params.bPrepend = prepend; ml_kem_params.hSecret = hybrid_key; ml_kem_params.ulCipherLen = cipher_len; ml_kem_params.pCipher = cipher; rc = funcs->C_DeriveKey(session, &mech, priv_key, derive_tmpl, secret_tmpl_len, &secret_key2); if (rc != CKR_OK) { testcase_error("C_DeriveKey (decapsulation) rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } if (secret_key1 != CK_INVALID_HANDLE) { switch (key_type) { case CKK_AES: rc = run_AESCrypt(session, secret_key1, secret_key2); if (rc != CKR_OK) { testcase_fail("Derived keys are not usable or not the same: %s", p11_get_ckr(rc)); goto testcase_cleanup; } break; case CKK_GENERIC_SECRET: rc = run_HMACSign(session, secret_key1, secret_key2, secret_key_len); if (rc != CKR_OK) { testcase_fail("Derived keys are not usable or not the same: %s", p11_get_ckr(rc)); goto testcase_cleanup; } break; default: testcase_fail("Derived key type can not be tested"); rc = CKR_FUNCTION_FAILED; goto testcase_cleanup; } } if (pExpectedSecret != NULL && ulExpectedSecret != 0) { rc = create_GenericSecretKey(session, CKK_GENERIC_SECRET, (CK_BYTE *)pExpectedSecret, ulExpectedSecret, &expected_secret_key); if (rc != CKR_OK) { testcase_fail("create_GenericSecretKey failed: %s", p11_get_ckr(rc)); goto testcase_cleanup; } rc = run_HMACSign(session, expected_secret_key, secret_key2, secret_key_len); if (rc != CKR_OK) { testcase_fail("Derived secret key is not the expected one: %s", p11_get_ckr(rc)); goto testcase_cleanup; } } rc = CKR_OK; testcase_cleanup: if (cipher != NULL && cipher != pCipher) free(cipher); if (secret_key1 != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, secret_key1); if (secret_key2 != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, secret_key2); if (hybrid_key != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, hybrid_key); if (expected_secret_key != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, expected_secret_key); return rc; } CK_RV run_EnDecapsulateMLKEMwithECDH(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE priv_key, CK_OBJECT_HANDLE publ_key, CK_KEY_TYPE key_type, CK_ULONG secret_key_len, CK_IBM_ML_KEM_KDF_TYPE kdf, const CK_BYTE *pSharedData, CK_ULONG ulSharedDataLen) { CK_MECHANISM mech; CK_IBM_ML_KEM_WITH_ECDH_PARAMS ml_kem_params; CK_BYTE *cipher = NULL; CK_ULONG cipher_len = 0; CK_OBJECT_HANDLE secret_key1 = CK_INVALID_HANDLE; CK_OBJECT_HANDLE secret_key2 = CK_INVALID_HANDLE; CK_OBJECT_HANDLE ec_priv_key = CK_INVALID_HANDLE; CK_OBJECT_HANDLE ec_pub_key = CK_INVALID_HANDLE; CK_RV rc; CK_OBJECT_CLASS class = CKO_SECRET_KEY; CK_BBOOL true = CK_TRUE; CK_BBOOL false = CK_FALSE; CK_ATTRIBUTE derive_tmpl[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &key_type, sizeof(key_type)}, {CKA_SENSITIVE, &false, sizeof(false)}, {CKA_VALUE_LEN, &secret_key_len, sizeof(secret_key_len)}, {CKA_SIGN, &true, sizeof(true)}, {CKA_VERIFY, &true, sizeof(true)}, }; CK_ULONG secret_tmpl_len = sizeof(derive_tmpl) / sizeof(CK_ATTRIBUTE); CK_BYTE pubkey_value[256]; CK_ATTRIBUTE extr_tmpl[] = { {CKA_EC_POINT, pubkey_value, sizeof(pubkey_value)}, }; CK_ULONG extr_tmpl_len = sizeof(extr_tmpl)/sizeof(CK_ATTRIBUTE); mech.mechanism = CKM_IBM_ML_KEM_WITH_ECDH; mech.ulParameterLen = sizeof(ml_kem_params); mech.pParameter = &ml_kem_params; /* Query the slot, check if this mech if supported */ if (!mech_supported(SLOT_ID, mech.mechanism)) { testcase_notice("Slot %u doesn't support %s", (unsigned int) SLOT_ID, p11_get_ckm(&mechtable_funcs, mech.mechanism)); rc = CKR_MECHANISM_INVALID; goto testcase_cleanup; } if (!mech_supported(SLOT_ID, CKM_EC_KEY_PAIR_GEN)) { testcase_notice("Slot %u doesn't support CKM_EC_KEY_PAIR_GEN\n", (unsigned int) SLOT_ID); rc = CKR_MECHANISM_INVALID; goto testcase_cleanup; } if (is_cca_token(SLOT_ID)) { if (key_type != CKK_AES) { testcase_notice("CCA token in slot %u does only support to derive" " AES keys\n", (unsigned int) SLOT_ID); rc = CKR_MECHANISM_INVALID; goto testcase_cleanup; } switch (kdf) { case CKD_IBM_HYBRID_SHA224_KDF: case CKD_IBM_HYBRID_SHA256_KDF: case CKD_IBM_HYBRID_SHA384_KDF: case CKD_IBM_HYBRID_SHA512_KDF: break; default: testcase_skip("CCA token in slot %u doesn't support this kdf\n", (unsigned int) SLOT_ID); rc = CKR_MECHANISM_INVALID; goto testcase_cleanup; } } rc = generate_EC_KeyPair(session, CKM_EC_KEY_PAIR_GEN, (CK_BYTE *)prime256v1, sizeof(prime256v1), &ec_pub_key, &ec_priv_key, CK_FALSE); if (rc != CKR_OK) { testcase_notice("generate_EC_KeyPair rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } rc = funcs->C_GetAttributeValue(session, ec_pub_key, extr_tmpl, extr_tmpl_len); if (rc != CKR_OK) { testcase_notice("C_GetAttributeValue: rc = %s", p11_get_ckr(rc)); goto testcase_cleanup; } /* Perform encapsulation with public key */ memset(&ml_kem_params, 0, sizeof(ml_kem_params)); ml_kem_params.mode = CK_IBM_ML_KEM_ENCAPSULATE; ml_kem_params.kdf = kdf; ml_kem_params.pSharedData = (CK_BYTE *)pSharedData; ml_kem_params.ulSharedDataLen = ulSharedDataLen; ml_kem_params.hECPrivateKey = ec_priv_key; ml_kem_params.pPublicData = extr_tmpl[0].pValue; ml_kem_params.ulPublicDataLen = extr_tmpl[0].ulValueLen; /* Size query */ rc = funcs->C_DeriveKey(session, &mech, publ_key, derive_tmpl, secret_tmpl_len, &secret_key1); if (rc != CKR_BUFFER_TOO_SMALL) { testcase_error("C_DeriveKey (size query) rc=%s (expected CKR_BUFFER_TOO_SMALL)", p11_get_ckr(rc)); goto testcase_cleanup; } cipher_len = ml_kem_params.ulCipherLen; cipher = calloc(cipher_len, sizeof(CK_BYTE)); if (cipher == NULL) { testcase_error("Can't allocate memory for %lu bytes", sizeof(CK_BYTE) * cipher_len); rc = CKR_HOST_MEMORY; goto testcase_cleanup; } ml_kem_params.ulCipherLen = cipher_len; ml_kem_params.pCipher = cipher; /* Encapsulation */ rc = funcs->C_DeriveKey(session, &mech, publ_key, derive_tmpl, secret_tmpl_len, &secret_key1); if (rc != CKR_OK) { testcase_error("C_DeriveKey (encapsulation) rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } cipher_len = ml_kem_params.ulCipherLen; /* Perform Decapsulation with private key */ memset(&ml_kem_params, 0, sizeof(ml_kem_params)); ml_kem_params.mode = CK_IBM_ML_KEM_DECAPSULATE; ml_kem_params.kdf = kdf; ml_kem_params.pSharedData = (CK_BYTE *)pSharedData; ml_kem_params.ulSharedDataLen = ulSharedDataLen; ml_kem_params.hECPrivateKey = ec_priv_key; ml_kem_params.pPublicData = extr_tmpl[0].pValue; ml_kem_params.ulPublicDataLen = extr_tmpl[0].ulValueLen; ml_kem_params.ulCipherLen = cipher_len; ml_kem_params.pCipher = cipher; rc = funcs->C_DeriveKey(session, &mech, priv_key, derive_tmpl, secret_tmpl_len, &secret_key2); if (rc != CKR_OK) { testcase_error("C_DeriveKey (decapsulation) rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } if (secret_key1 != CK_INVALID_HANDLE) { switch (key_type) { case CKK_AES: rc = run_AESCrypt(session, secret_key1, secret_key2); if (rc != CKR_OK) { testcase_fail("Derived keys are not usable or not the same: %s", p11_get_ckr(rc)); goto testcase_cleanup; } break; case CKK_GENERIC_SECRET: rc = run_HMACSign(session, secret_key1, secret_key2, secret_key_len); if (rc != CKR_OK) { testcase_fail("Derived keys are not usable or not the same: %s", p11_get_ckr(rc)); goto testcase_cleanup; } break; default: testcase_fail("Derived key type can not be tested"); rc = CKR_FUNCTION_FAILED; goto testcase_cleanup; } } rc = CKR_OK; testcase_cleanup: if (cipher != NULL) free(cipher); if (secret_key1 != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, secret_key1); if (secret_key2 != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, secret_key2); if (ec_priv_key != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, ec_priv_key); if (ec_pub_key != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, ec_pub_key); return rc; } CK_RV run_GenerateMLKEMKeyPairKEM(void) { 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_RV rc; testcase_rw_session(); testcase_user_login(); mech.mechanism = CKM_IBM_ML_KEM_KEY_PAIR_GEN; mech.ulParameterLen = 0; mech.pParameter = NULL; /* query the slot, check if this mech is supported */ if (!mech_supported(SLOT_ID, mech.mechanism)) { testcase_skip("Slot %u doesn't support %s", (unsigned int) SLOT_ID, p11_get_ckm(&mechtable_funcs, mech.mechanism)); rc = CKR_OK; goto testcase_cleanup; } for (i = 0; i < num_variants; i++) { /* Setup attributes for public/private ML-KEM key */ CK_BBOOL attr_derive = TRUE; CK_ATTRIBUTE ml_kem_attr_private[] = { {CKA_DERIVE, &attr_derive, sizeof(CK_BBOOL)}, {CKA_IBM_PARAMETER_SET, (CK_BYTE *)&variants[i].parameter_set, sizeof(CK_IBM_ML_KEM_PARAMETER_SET_TYPE)}, }; CK_ATTRIBUTE ml_kem_attr_public[] = { {CKA_DERIVE, &attr_derive, sizeof(CK_BBOOL)}, {CKA_IBM_PARAMETER_SET, (CK_BYTE *)&variants[i].parameter_set, sizeof(CK_IBM_ML_KEM_PARAMETER_SET_TYPE)}, }; CK_ULONG num_ml_kem_attrs = 2; testcase_begin("Starting IBM ML-KEM generate key pair with %s.", variants[i].name); /* Generate ML-KEM key pair */ rc = funcs->C_GenerateKeyPair(session, &mech, ml_kem_attr_public, num_ml_kem_attrs, ml_kem_attr_private, num_ml_kem_attrs, &publ_key, &priv_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("C_GenerateKeyPair with %s not supported", variants[i].name); goto next; } else { testcase_new_assertion(); testcase_fail("C_GenerateKeyPair with %s failed, rc=%s", variants[i].name, p11_get_ckr(rc)); goto testcase_cleanup; } } testcase_new_assertion(); testcase_pass("Generate ML-KEM key pair with %s passed.", variants[i].name); for (j = 0; j < NUM_KEM_INPUTS; j++) { rc = run_EnDecapsulateMLKEM(session, priv_key, publ_key, kemInput[j].secret_key_type, kemInput[j].secret_key_len, kemInput[j].kdf, kemInput[j].hybrid, kemInput[j].prepend, kemInput[j].shared_data, kemInput[j].shard_data_len, NULL, 0, NULL, 0); if (rc == CKR_MECHANISM_INVALID) { testcase_skip("run_EnDecapsulateMLKEM with %s, %s, Shared data len %lu (index %lu).", variants[i].name, p11_get_ckd(kemInput[j].kdf), kemInput[j].shard_data_len, j); } else if (rc != 0) { testcase_new_assertion(); testcase_fail("run_EnDecapsulateMLKEM with %s, %s, Shared data len %lu (index %lu) failed.", variants[i].name, p11_get_ckd(kemInput[j].kdf), kemInput[j].shard_data_len, j); goto next; } else { testcase_new_assertion(); testcase_pass("*%sEncapsulate & Decapsulate (KEM) with %s, %s, Shared data len %lu (index %lu) passed.", kemInput[j].hybrid ? "Hybrid " : "", variants[i].name, p11_get_ckd(kemInput[j].kdf), kemInput[j].shard_data_len, j); } if (!kemInput[j].hybrid) continue; rc = run_EnDecapsulateMLKEMwithECDH(session, priv_key, publ_key, kemInput[j].secret_key_type, kemInput[j].secret_key_len, kemInput[j].kdf, kemInput[j].shared_data, kemInput[j].shard_data_len); if (rc == CKR_MECHANISM_INVALID || rc == CKR_FUNCTION_CANCELED) { testcase_skip("run_EnDecapsulateMLKEMwithECDH with %s, %s, Shared data len %lu (index %lu).", variants[i].name, p11_get_ckd(kemInput[j].kdf), kemInput[j].shard_data_len, j); } else if (rc != 0) { testcase_new_assertion(); testcase_fail("run_EnDecapsulateMLKEMwithECDH with %s, %s, Shared data len %lu (index %lu) failed.", variants[i].name, p11_get_ckd(kemInput[j].kdf), kemInput[j].shard_data_len, j); goto next; } else { testcase_new_assertion(); testcase_pass("*Combined Encapsulate & Decapsulate (KEM) with ECDH with %s, %s, Shared data len %lu (index %lu) passed.", variants[i].name, p11_get_ckd(kemInput[j].kdf), kemInput[j].shard_data_len, j); } } next: if (publ_key != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, publ_key); publ_key = CK_INVALID_HANDLE; if (priv_key != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, priv_key); priv_key = CK_INVALID_HANDLE; } 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_ImportMLKEMKeyPairSignVerify(void) { 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_RV rc; testcase_rw_session(); testcase_user_login(); /* query the slot, check if this mech is supported */ if (!mech_supported(SLOT_ID, CKM_IBM_ML_KEM) && !mech_supported(SLOT_ID, CKM_IBM_ML_KEM_WITH_ECDH)) { testcase_skip("Slot %u doesn't support CKM_IBM_ML_KEM nor " "CKM_IBM_ML_KEM_WITH_ECDH", (unsigned int) SLOT_ID); rc = CKR_OK; goto testcase_cleanup; } for (i = 0; i < ML_KEM_TV_NUM; i++) { testcase_begin("Starting IBM ML-KEM import key pair, %s index=%lu", ml_kem_tv[i].name, i); /* Create IBM ML-KEM private key */ rc = create_IBM_ML_KEM_PrivateKey(session, ml_kem_tv[i].pkcs8, ml_kem_tv[i].pkcs8_len, ml_kem_tv[i].parameter_set, ml_kem_tv[i].sk, ml_kem_tv[i].sk_len, ml_kem_tv[i].pk, ml_kem_tv[i].pk_len, ml_kem_tv[i].priv_seed, ml_kem_tv[i].priv_seed_len, &priv_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("C_CreateObject with %s not supported", ml_kem_tv[i].name); continue; } else if (rc == CKR_POLICY_VIOLATION) { testcase_skip("IBM ML-KEM key import is not allowed by policy"); continue; } testcase_new_assertion(); testcase_fail("C_CreateObject (IBM ML-KEM Private Key) failed at " "i=%lu, rc=%s", i, p11_get_ckr(rc)); goto testcase_cleanup; } testcase_new_assertion(); testcase_pass("*Import IBM ML-KEM private key (%s) index=%lu passed.", ml_kem_tv[i].name, i); /* Create IBM ML-KEM public key */ rc = create_IBM_ML_KEM_PublicKey(session, ml_kem_tv[i].spki, ml_kem_tv[i].spki_len, ml_kem_tv[i].parameter_set, ml_kem_tv[i].pk, ml_kem_tv[i].pk_len, &publ_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("C_CreateObject with %s not supported", ml_kem_tv[i].name); goto testcase_cleanup; } else if (rc == CKR_POLICY_VIOLATION) { testcase_skip("IBM ML-KEM key import is not allowed by policy"); goto testcase_cleanup; } testcase_new_assertion(); testcase_fail("C_CreateObject (IBM ML-KEM Public Key) failed at " "i=%lu, rc=%s", i, p11_get_ckr(rc)); goto testcase_cleanup; } testcase_new_assertion(); testcase_pass("*Import IBM ML-KEM public key (%s) index=%lu passed.", ml_kem_tv[i].name, i); /* Test Encapsulate/decapsulate (KEM) */ rc = run_EnDecapsulateMLKEM(session, priv_key, publ_key, CKK_AES, 32, CKD_NULL, CK_FALSE, CK_FALSE, NULL, 0, NULL, 0, NULL, 0); if (rc == CKR_MECHANISM_INVALID) { testcase_skip("run_EnDecapsulateMLKEM index=%lu.", i); } else if (rc != 0) { testcase_new_assertion(); testcase_fail("run_EnDecapsulateMLKEM failed index=%lu.", i); goto testcase_cleanup; } else { testcase_new_assertion(); testcase_pass("*Encapsulate & Decapsulate (KEM), i=%lu passed.", i); } rc = run_EnDecapsulateMLKEMwithECDH(session, priv_key, publ_key, CKK_AES, 32, CKD_IBM_HYBRID_SHA256_KDF, NULL, 0); if (rc == CKR_MECHANISM_INVALID || rc == CKR_FUNCTION_CANCELED) { testcase_skip("run_EnDecapsulateMLKEMwithECDH index=%lu.", i); } else if (rc != 0) { testcase_new_assertion(); testcase_fail("run_EnDecapsulateMLKEMwithECDH failed index=%lu.", i); goto testcase_cleanup; } else { testcase_new_assertion(); testcase_pass("*Combined Encapsulate & Decapsulate (KEM), 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(tmp_len, sizeof(CK_BYTE)); 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_ML_KEM; CK_OBJECT_HANDLE tmp_key = CK_INVALID_HANDLE; CK_BYTE unwrap_label[] = "unwrapped_private_IBM_ML_KEM_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)}, {CKA_DERIVE, &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_TransferMLKEMKeyPairSignVerify(void) { 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_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(); /* query the slot, check if this mech is supported */ if (!mech_supported(SLOT_ID, CKM_IBM_ML_KEM) && !mech_supported(SLOT_ID, CKM_IBM_ML_KEM_WITH_ECDH)) { testcase_skip("Slot %u doesn't support CKM_IBM_ML_KEM nor " "CKM_IBM_ML_KEM_WITH_ECDH", (unsigned int) SLOT_ID); rc = CKR_OK; goto testcase_cleanup; } if (!mech_supported(SLOT_ID, CKM_AES_KEY_GEN)) { testcase_skip("Slot %u doesn't support CKM_AES_KEY_GEN", (unsigned int) SLOT_ID); rc = CKR_OK; goto testcase_cleanup; } if (!mech_supported_flags(SLOT_ID, CKM_AES_CBC_PAD, CKF_WRAP)) { testcase_skip("Slot %u doesn't support key wrapping with CKM_AES_CBC_PAD", (unsigned int) SLOT_ID); rc = CKR_OK; goto testcase_cleanup; } for (i = 0; i < ML_KEM_TV_NUM; i++) { testcase_begin("Starting IBM ML-KEM transfer key pair, %s index=%lu.", ml_kem_tv[i].name, i); /* Create IBM ML-KEM private key */ rc = create_IBM_ML_KEM_PrivateKey(session, ml_kem_tv[i].pkcs8, ml_kem_tv[i].pkcs8_len, ml_kem_tv[i].parameter_set, ml_kem_tv[i].sk, ml_kem_tv[i].sk_len, ml_kem_tv[i].pk, ml_kem_tv[i].pk_len, ml_kem_tv[i].priv_seed, ml_kem_tv[i].priv_seed_len, &priv_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("C_CreateObject with %s not supported", ml_kem_tv[i].name); continue; } else if (rc == CKR_POLICY_VIOLATION) { testcase_skip("IBM ML-KEM key import is not allowed by policy"); continue; } testcase_new_assertion(); testcase_fail("C_CreateObject (IBM ML-KEM Private Key) failed at " "i=%lu, rc=%s", i, p11_get_ckr(rc)); goto testcase_cleanup; } testcase_new_assertion(); testcase_pass("*Import IBM ML-KEM private key (%s) index=%lu passed.", ml_kem_tv[i].name, i); /* Create IBM ML-KEM public key */ rc = create_IBM_ML_KEM_PublicKey(session, ml_kem_tv[i].spki, ml_kem_tv[i].spki_len, ml_kem_tv[i].parameter_set, ml_kem_tv[i].pk, ml_kem_tv[i].pk_len, &publ_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("C_CreateObject with %s not supported", ml_kem_tv[i].name); goto testcase_cleanup; } else if (rc == CKR_POLICY_VIOLATION) { testcase_skip("IBM ML-KEM key import is not allowed by policy"); goto testcase_cleanup; } testcase_new_assertion(); testcase_fail("C_CreateObject (IBM ML-KEM Public Key) failed at " "i=%lu,rc=%s", i, p11_get_ckr(rc)); goto testcase_cleanup; } testcase_new_assertion(); testcase_pass("*Import IBM ML-KEM public key (%s) index=%lu passed.", ml_kem_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, CK_TRUE, &wkey_mech, &secret_key); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("AES key generation is not allowed by policy"); goto testcase_cleanup; } 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 IBM ML-KEM 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 IBM ML-KEM private key (%s) index=%lu passed.", ml_kem_tv[i].name, i); /* Unwrap IBM ML-KEM 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 IBM ML-KEM private key (%s) index=%lu passed.", ml_kem_tv[i].name, i); free(wrapped_key); wrapped_key = NULL; /* Test Encapsulate/decapsulate (KEM) */ rc = run_EnDecapsulateMLKEM(session, unwrapped_key, publ_key, CKK_AES, 32, CKD_NULL, CK_FALSE, CK_FALSE, NULL, 0, NULL, 0, NULL, 0); if (rc == CKR_MECHANISM_INVALID) { testcase_skip("run_EnDecapsulateMLKEM index=%lu.", i); } else if (rc != 0) { testcase_new_assertion(); testcase_fail("run_EnDecapsulateMLKEM failed index=%lu.", i); goto testcase_cleanup; } else { testcase_new_assertion(); testcase_pass("*Encapsulate & Decapsulate (KEM), i=%lu passed.", i); } rc = run_EnDecapsulateMLKEMwithECDH(session, unwrapped_key, publ_key, CKK_AES, 32, CKD_IBM_HYBRID_SHA256_KDF, NULL, 0); if (rc == CKR_MECHANISM_INVALID || rc == CKR_FUNCTION_CANCELED) { testcase_skip("run_EnDecapsulateMLKEMwithECDH index=%lu.", i); } else if (rc != 0) { testcase_new_assertion(); testcase_fail("run_EnDecapsulateMLKEMwithECDH failed index=%lu.", i); goto testcase_cleanup; } else { testcase_new_assertion(); testcase_pass("*Combined Encapsulate & Decapsulate (KEM), 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(); rv = run_GenerateMLKEMKeyPairKEM(); rv |= run_ImportMLKEMKeyPairSignVerify(); rv |= run_TransferMLKEMKeyPairSignVerify(); testcase_print_result(); funcs->C_Finalize(NULL); return testcase_return(rv); } opencryptoki-opencryptoki-451d99c/testcases/crypto/kyber.h000066400000000000000000007664331520105705100241520ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2022 * * This program is provided under the terms of the Common Public License, * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this * software constitutes recipient's acceptance of CPL-1.0 terms which can be * found in the file LICENSE file or at * https://opensource.org/licenses/cpl1.0.php */ /** * Experimental Support for Kyber keys and KEM * with oid = 1.3.6.1.4.1.2.267.5.xxx * * Public-key encoding; raw public-key field. See RFC 3279 for * subjectPublicKeyInfo (SPKI) structures. * * KyberPublicKey ::= BIT STRING { * SEQUENCE { * pk BIT STRING -- public key * } * } * * Private-key encoding; see RFC 5959 for PKCS#8 structure definitions. * * KyberPrivateKey ::= SEQUENCE { * version INTEGER, -- v0; reserved 0 * sk BIT STRING, -- privet key * pk [0] IMPLICIT OPTIONAL { * pk BIT STRING -- public key * } * } */ struct KYBER_TEST_VECTOR { char *name; int version; CK_ULONG keyform; CK_ULONG sk_len; CK_BYTE sk[4096]; CK_ULONG pk_len; CK_BYTE pk[4096]; CK_BYTE pkcs8[8192]; CK_ULONG pkcs8_len; CK_BYTE spki[8192]; CK_ULONG spki_len; CK_BYTE secret[32]; CK_ULONG secret_len; CK_BYTE cipher[2048]; CK_ULONG cipher_len; }; /** * test vectors from: https://csrc.nist.gov/Projects/post-quantum-cryptography/round-2-submissions */ struct KYBER_TEST_VECTOR kyber_tv[] = { { .name = "Kyber Round 2, 786 KAT 0 (PKCS#8/SPKI)", .version = 0, .keyform = 0, .pk_len = 0, .sk_len = 0, .pkcs8_len = 3697, .pkcs8 = { 0x30, 0x82, 0x0e, 0x6d, 0x02, 0x01, 0x00, 0x30, 0x0f, 0x06, 0x0b, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x02, 0x82, 0x0b, 0x05, 0x03, 0x03, 0x05, 0x00, 0x04, 0x82, 0x0e, 0x55, 0x30, 0x82, 0x0e, 0x51, 0x02, 0x01, 0x00, 0x03, 0x82, 0x09, 0x61, 0x00, 0x07, 0x63, 0x8f, 0xb6, 0x98, 0x68, 0xf3, 0xd3, 0x20, 0xe5, 0x86, 0x2b, 0xd9, 0x69, 0x33, 0xfe, 0xb3, 0x11, 0xb3, 0x62, 0x09, 0x3c, 0x9b, 0x5d, 0x50, 0x17, 0x0b, 0xce, 0xd4, 0x3f, 0x1b, 0x53, 0x6d, 0x9a, 0x20, 0x4b, 0xb1, 0xf2, 0x26, 0x95, 0x95, 0x0b, 0xa1, 0xf2, 0xa9, 0xe8, 0xeb, 0x82, 0x8b, 0x28, 0x44, 0x88, 0x76, 0x0b, 0x3f, 0xc8, 0x4f, 0xab, 0xa0, 0x42, 0x75, 0xd5, 0x62, 0x8e, 0x39, 0xc5, 0xb2, 0x47, 0x13, 0x74, 0x28, 0x3c, 0x50, 0x32, 0x99, 0xc0, 0xab, 0x49, 0xb6, 0x6b, 0x8b, 0xbb, 0x56, 0xa4, 0x18, 0x66, 0x24, 0xf9, 0x19, 0xa2, 0xba, 0x59, 0xbb, 0x08, 0xd8, 0x55, 0x18, 0x80, 0xc2, 0xbe, 0xfc, 0x4f, 0x87, 0xf2, 0x5f, 0x59, 0xab, 0x58, 0x7a, 0x79, 0xc3, 0x27, 0xd7, 0x92, 0xd5, 0x4c, 0x97, 0x4a, 0x69, 0x26, 0x2f, 0xf8, 0xa7, 0x89, 0x38, 0x28, 0x9e, 0x9a, 0x87, 0xb6, 0x88, 0xb0, 0x83, 0xe0, 0x59, 0x5f, 0xe2, 0x18, 0xb6, 0xbb, 0x15, 0x05, 0x94, 0x1c, 0xe2, 0xe8, 0x1a, 0x5a, 0x64, 0xc5, 0xaa, 0xc6, 0x04, 0x17, 0x25, 0x69, 0x85, 0x34, 0x9e, 0xe4, 0x7a, 0x52, 0x42, 0x0a, 0x5f, 0x97, 0x47, 0x7b, 0x72, 0x36, 0xac, 0x76, 0xbc, 0x70, 0xe8, 0x28, 0x87, 0x29, 0x28, 0x7e, 0xe3, 0xe3, 0x4a, 0x3d, 0xbc, 0x36, 0x83, 0xc0, 0xb7, 0xb1, 0x00, 0x29, 0xfc, 0x20, 0x34, 0x18, 0x53, 0x7e, 0x74, 0x66, 0xba, 0x63, 0x85, 0xa8, 0xff, 0x30, 0x1e, 0xe1, 0x27, 0x08, 0xf8, 0x2a, 0xaa, 0x1e, 0x38, 0x0f, 0xc7, 0xa8, 0x8f, 0x8f, 0x20, 0x5a, 0xb7, 0xe8, 0x8d, 0x7e, 0x95, 0x95, 0x2a, 0x55, 0xba, 0x20, 0xd0, 0x9b, 0x79, 0xa4, 0x71, 0x41, 0xd6, 0x2b, 0xf6, 0xeb, 0x7d, 0xd3, 0x07, 0xb0, 0x8e, 0xca, 0x13, 0xa5, 0xbc, 0x5f, 0x6b, 0x68, 0x58, 0x1c, 0x68, 0x65, 0xb2, 0x7b, 0xbc, 0xdd, 0xab, 0x14, 0x2f, 0x4b, 0x2c, 0xbf, 0xf4, 0x88, 0xc8, 0xa2, 0x27, 0x05, 0xfa, 0xa9, 0x8a, 0x2b, 0x9e, 0xea, 0x35, 0x30, 0xc7, 0x66, 0x62, 0x33, 0x5c, 0xc7, 0xea, 0x3a, 0x00, 0x77, 0x77, 0x25, 0xeb, 0xcc, 0xcd, 0x2a, 0x46, 0x36, 0xb2, 0xd9, 0x12, 0x2f, 0xf3, 0xab, 0x77, 0x12, 0x3c, 0xe0, 0x88, 0x3c, 0x19, 0x11, 0x11, 0x5e, 0x50, 0xc9, 0xe8, 0xa9, 0x41, 0x94, 0xe4, 0x8d, 0xd0, 0xd0, 0x9c, 0xff, 0xb3, 0xad, 0xcd, 0x2c, 0x1e, 0x92, 0x43, 0x09, 0x03, 0xd0, 0x7a, 0xdb, 0xf0, 0x05, 0x32, 0x03, 0x15, 0x75, 0xaa, 0x7f, 0x9e, 0x7b, 0x5a, 0x1f, 0x33, 0x62, 0xde, 0xc9, 0x36, 0xd4, 0x04, 0x3c, 0x05, 0xf2, 0x47, 0x6c, 0x07, 0x57, 0x8b, 0xc9, 0xcb, 0xaf, 0x2a, 0xb4, 0xe3, 0x82, 0x72, 0x7a, 0xd4, 0x16, 0x86, 0xa9, 0x6b, 0x25, 0x48, 0x82, 0x0b, 0xb0, 0x3b, 0x32, 0xf1, 0x1b, 0x28, 0x11, 0xad, 0x62, 0xf4, 0x89, 0xe9, 0x51, 0x63, 0x2a, 0xba, 0x0d, 0x1d, 0xf8, 0x96, 0x80, 0xcc, 0x8a, 0x8b, 0x53, 0xb4, 0x81, 0xd9, 0x2a, 0x68, 0xd7, 0x0b, 0x4e, 0xa1, 0xc3, 0xa6, 0xa5, 0x61, 0xc0, 0x69, 0x28, 0x82, 0xb5, 0xca, 0x8c, 0xc9, 0x42, 0xa8, 0xd4, 0x95, 0xaf, 0xcb, 0x06, 0xde, 0x89, 0x49, 0x8f, 0xb9, 0x35, 0xb7, 0x75, 0x90, 0x8f, 0xe7, 0xa0, 0x3e, 0x32, 0x4d, 0x54, 0xcc, 0x19, 0xd4, 0xe1, 0xaa, 0xbd, 0x35, 0x93, 0xb3, 0x8b, 0x19, 0xee, 0x13, 0x88, 0xfe, 0x49, 0x2b, 0x43, 0x12, 0x7e, 0x5a, 0x50, 0x42, 0x53, 0x78, 0x6a, 0x0d, 0x69, 0xad, 0x32, 0x60, 0x1c, 0x28, 0xe2, 0xc8, 0x85, 0x04, 0xa5, 0xba, 0x59, 0x97, 0x06, 0x02, 0x3a, 0x61, 0x36, 0x3e, 0x17, 0xc6, 0xb9, 0xbb, 0x59, 0xbd, 0xc6, 0x97, 0x45, 0x2c, 0xd0, 0x59, 0x45, 0x19, 0x83, 0xd7, 0x38, 0xca, 0x3f, 0xd0, 0x34, 0xe3, 0xf5, 0x98, 0x88, 0x54, 0xca, 0x05, 0x03, 0x1d, 0xb0, 0x96, 0x11, 0x49, 0x89, 0x88, 0x19, 0x7c, 0x6b, 0x30, 0xd2, 0x58, 0xdf, 0xe2, 0x62, 0x65, 0x54, 0x1c, 0x89, 0xa4, 0xb3, 0x1d, 0x68, 0x64, 0xe9, 0x38, 0x9b, 0x03, 0xcb, 0x74, 0xf7, 0xec, 0x43, 0x23, 0xfb, 0x94, 0x21, 0xa4, 0xb9, 0x79, 0x0a, 0x26, 0xd1, 0x7b, 0x03, 0x98, 0xa2, 0x67, 0x67, 0x35, 0x09, 0x09, 0xf8, 0x4d, 0x57, 0xb6, 0x69, 0x4d, 0xf8, 0x30, 0x66, 0x4c, 0xa8, 0xb3, 0xc3, 0xc0, 0x3e, 0xd2, 0xae, 0x67, 0xb8, 0x90, 0x06, 0x86, 0x8a, 0x68, 0x52, 0x7c, 0xcd, 0x66, 0x64, 0x59, 0xab, 0x7f, 0x05, 0x66, 0x71, 0x00, 0x0c, 0x61, 0x64, 0xd3, 0xa7, 0xf2, 0x66, 0xa1, 0x4d, 0x97, 0xcb, 0xd7, 0x00, 0x4d, 0x6c, 0x92, 0xca, 0xca, 0x77, 0x0b, 0x84, 0x4a, 0x4f, 0xa9, 0xb1, 0x82, 0xe7, 0xb1, 0x8c, 0xa8, 0x85, 0x08, 0x2a, 0xc5, 0x64, 0x6f, 0xcb, 0x4a, 0x14, 0xe1, 0x68, 0x5f, 0xeb, 0x0c, 0x9c, 0xe3, 0x37, 0x2a, 0xb9, 0x53, 0x65, 0xc0, 0x4f, 0xd8, 0x30, 0x84, 0xf8, 0x0a, 0x23, 0xff, 0x10, 0xa0, 0x5b, 0xf1, 0x5f, 0x7f, 0xa5, 0xac, 0xc6, 0xc0, 0xcb, 0x46, 0x2c, 0x33, 0xca, 0x52, 0x4f, 0xa6, 0xb8, 0xbb, 0x35, 0x90, 0x43, 0xba, 0x68, 0x60, 0x9e, 0xaa, 0x25, 0x36, 0xe8, 0x1d, 0x08, 0x46, 0x3b, 0x19, 0x65, 0x3b, 0x54, 0x35, 0xba, 0x94, 0x6c, 0x9a, 0xdd, 0xeb, 0x20, 0x2b, 0x04, 0xb0, 0x31, 0xcc, 0x96, 0x0d, 0xcc, 0x12, 0xe4, 0x51, 0x8d, 0x42, 0x8b, 0x32, 0xb2, 0x57, 0xa4, 0xfc, 0x73, 0x13, 0xd3, 0xa7, 0x98, 0x0d, 0x80, 0x08, 0x2e, 0x93, 0x4f, 0x9d, 0x95, 0xc3, 0x2b, 0x0a, 0x01, 0x91, 0xa2, 0x36, 0x04, 0x38, 0x4d, 0xd9, 0xe0, 0x79, 0xbb, 0xba, 0xa2, 0x66, 0xd1, 0x4c, 0x3f, 0x75, 0x6b, 0x9f, 0x21, 0x33, 0x10, 0x74, 0x33, 0xa4, 0xe8, 0x3f, 0xa7, 0x18, 0x72, 0x82, 0xa8, 0x09, 0x20, 0x3a, 0x4f, 0xaf, 0x84, 0x18, 0x51, 0x83, 0x3d, 0x12, 0x1a, 0xc3, 0x83, 0x84, 0x3a, 0x5e, 0x55, 0xbc, 0x23, 0x81, 0x42, 0x5e, 0x16, 0xc7, 0xdb, 0x4c, 0xc9, 0xab, 0x5c, 0x1b, 0x0d, 0x91, 0xa4, 0x7e, 0x2b, 0x8d, 0xe0, 0xe5, 0x82, 0xc8, 0x6b, 0x6b, 0x0d, 0x90, 0x7b, 0xb3, 0x60, 0xb9, 0x7f, 0x40, 0xab, 0x5d, 0x03, 0x8f, 0x6b, 0x75, 0xc8, 0x14, 0xb2, 0x7d, 0x9b, 0x96, 0x8d, 0x41, 0x98, 0x32, 0xbc, 0x8c, 0x2b, 0xee, 0x60, 0x5e, 0xf6, 0xe5, 0x05, 0x9d, 0x33, 0x10, 0x0d, 0x90, 0x48, 0x5d, 0x37, 0x84, 0x50, 0x01, 0x42, 0x21, 0x73, 0x6c, 0x07, 0x40, 0x7c, 0xac, 0x26, 0x04, 0x08, 0xaa, 0x64, 0x92, 0x66, 0x19, 0x78, 0x8b, 0x86, 0x01, 0xc2, 0xa7, 0x52, 0xd1, 0xa6, 0xcb, 0xf8, 0x20, 0xd7, 0xc7, 0xa0, 0x47, 0x16, 0x20, 0x32, 0x25, 0xb3, 0x89, 0x5b, 0x93, 0x42, 0xd1, 0x47, 0xa8, 0x18, 0x5c, 0xfc, 0x1b, 0xb6, 0x5b, 0xa0, 0x6b, 0x41, 0x42, 0x33, 0x99, 0x03, 0xc0, 0xac, 0x46, 0x51, 0x38, 0x5b, 0x45, 0xd9, 0x8a, 0x8b, 0x19, 0xd2, 0x8c, 0xd6, 0xba, 0xb0, 0x88, 0x78, 0x7f, 0x7e, 0xe1, 0xb1, 0x24, 0x61, 0x76, 0x6b, 0x43, 0xcb, 0xcc, 0xb9, 0x64, 0x34, 0x42, 0x7d, 0x93, 0xc0, 0x65, 0x55, 0x06, 0x88, 0xf6, 0x94, 0x8e, 0xd1, 0xb5, 0x47, 0x5a, 0x42, 0x5f, 0x1b, 0x85, 0x20, 0x9d, 0x06, 0x1c, 0x08, 0xb5, 0x6c, 0x1c, 0xc0, 0x69, 0xf6, 0xc0, 0xa7, 0xc6, 0xf2, 0x93, 0x58, 0xca, 0xb9, 0x11, 0x08, 0x77, 0x32, 0xa6, 0x49, 0xd2, 0x7c, 0x9b, 0x98, 0xf9, 0xa4, 0x88, 0x79, 0x38, 0x7d, 0x9b, 0x00, 0xc2, 0x59, 0x59, 0xa7, 0x16, 0x54, 0xd6, 0xf6, 0xa9, 0x46, 0x16, 0x45, 0x13, 0xe4, 0x7a, 0x75, 0xd0, 0x05, 0x98, 0x6c, 0x23, 0x63, 0xc0, 0x9f, 0x6b, 0x53, 0x7e, 0xca, 0x78, 0xb9, 0x30, 0x3a, 0x5f, 0xa4, 0x57, 0x60, 0x8a, 0x58, 0x6a, 0x65, 0x3a, 0x34, 0x7d, 0xb0, 0x4d, 0xfc, 0xc1, 0x91, 0x75, 0xb3, 0xa3, 0x01, 0x17, 0x25, 0x36, 0x06, 0x2a, 0x65, 0x8a, 0x95, 0x27, 0x75, 0x70, 0xc8, 0x85, 0x2c, 0xa8, 0x97, 0x3f, 0x4a, 0xe1, 0x23, 0xa3, 0x34, 0x04, 0x7d, 0xd7, 0x11, 0xc8, 0x92, 0x7a, 0x63, 0x4a, 0x03, 0x38, 0x8a, 0x52, 0x7b, 0x03, 0x4b, 0xf7, 0xa8, 0x17, 0x0f, 0xa7, 0x02, 0xc1, 0xf7, 0xc2, 0x3e, 0xc3, 0x2d, 0x18, 0xa2, 0x37, 0x48, 0x90, 0xbe, 0x9c, 0x78, 0x7a, 0x94, 0x09, 0xc8, 0x2d, 0x19, 0x2c, 0x4b, 0xb7, 0x05, 0xa2, 0xf9, 0x96, 0xce, 0x40, 0x5d, 0xa0, 0xb7, 0x1f, 0x67, 0xc6, 0xce, 0xc0, 0xd3, 0x56, 0x86, 0xd5, 0x13, 0x42, 0x34, 0x32, 0xe5, 0x12, 0xac, 0x40, 0x44, 0x55, 0x7e, 0x86, 0x8a, 0x62, 0x48, 0x00, 0x10, 0x9a, 0x33, 0x55, 0xf9, 0x8f, 0x15, 0x14, 0x44, 0xe2, 0x85, 0x2e, 0x27, 0xea, 0x6e, 0xdb, 0x19, 0x92, 0xca, 0xd3, 0x97, 0x3c, 0x3a, 0x6f, 0xf7, 0x9a, 0x5a, 0x04, 0x9a, 0x25, 0x9e, 0xb5, 0x41, 0x5a, 0xa2, 0xa2, 0x62, 0x45, 0x6e, 0xc9, 0x49, 0x5b, 0xbb, 0x52, 0x00, 0xd8, 0xd3, 0x16, 0x3a, 0x5b, 0x10, 0x22, 0x62, 0x92, 0xec, 0xa0, 0x10, 0x21, 0x38, 0x9d, 0xa3, 0x78, 0x81, 0xe2, 0x76, 0x30, 0x65, 0x50, 0xc6, 0xef, 0xb6, 0x44, 0x0e, 0xc5, 0x1a, 0x2f, 0x73, 0x48, 0x34, 0x9b, 0x85, 0x1c, 0xd4, 0xaa, 0x01, 0x75, 0xa0, 0x55, 0x02, 0x13, 0xc4, 0x79, 0x1d, 0x91, 0x01, 0x12, 0x20, 0x82, 0x4b, 0x2b, 0x61, 0x65, 0x08, 0x13, 0xad, 0xfd, 0x2c, 0xb1, 0x05, 0x38, 0xbf, 0xab, 0x0a, 0x72, 0x6f, 0x81, 0x12, 0x9e, 0xd2, 0xc0, 0xf0, 0x6a, 0x16, 0xb7, 0x01, 0x09, 0x0b, 0xf0, 0x48, 0xc5, 0xa4, 0x01, 0x26, 0xd5, 0x72, 0xfc, 0xd4, 0x7a, 0xa1, 0x21, 0x8f, 0xb0, 0x15, 0x47, 0xd1, 0x50, 0x79, 0x2d, 0x23, 0x16, 0xcb, 0x32, 0x0d, 0x51, 0x44, 0xba, 0x35, 0x08, 0xa1, 0xeb, 0xbb, 0x5a, 0xc1, 0xc2, 0x29, 0x13, 0xe8, 0x29, 0x5f, 0xab, 0x59, 0xbf, 0x58, 0x37, 0xa7, 0x78, 0xcf, 0x28, 0x22, 0x7e, 0x07, 0xe1, 0x03, 0x2d, 0xab, 0x7d, 0x0e, 0x09, 0xa1, 0x5f, 0x13, 0x41, 0x48, 0xc1, 0x20, 0x09, 0xda, 0x53, 0x6b, 0x22, 0xcc, 0x62, 0x47, 0x4e, 0x69, 0xcc, 0x15, 0x54, 0xc0, 0x81, 0x4d, 0x6c, 0xa0, 0xb7, 0x22, 0x59, 0x43, 0x83, 0xa9, 0xd0, 0xa2, 0xc7, 0x7f, 0xd3, 0x65, 0xa5, 0x54, 0x42, 0x95, 0xfb, 0xb9, 0x73, 0xf9, 0x1e, 0xa5, 0x64, 0x90, 0xd6, 0xca, 0x68, 0x76, 0x49, 0x7b, 0x98, 0xb3, 0xcb, 0x12, 0x41, 0x7c, 0x25, 0x7b, 0x6d, 0x0f, 0x71, 0x83, 0xdb, 0xb6, 0x9e, 0x33, 0x07, 0x5b, 0xeb, 0x01, 0x17, 0xb6, 0x91, 0x4c, 0x69, 0xba, 0x38, 0x34, 0x94, 0x22, 0xf2, 0xf4, 0x33, 0x64, 0x82, 0x2a, 0x25, 0x70, 0x95, 0x2d, 0xd5, 0x07, 0x7b, 0x90, 0x75, 0x5f, 0x15, 0x74, 0x11, 0x5b, 0x8e, 0x22, 0x14, 0x27, 0x58, 0x59, 0x61, 0x91, 0x3a, 0x9b, 0xfa, 0x05, 0x02, 0xb5, 0xd7, 0x9a, 0xb7, 0x81, 0x17, 0x44, 0xe6, 0x56, 0x3c, 0x5b, 0x62, 0xc5, 0xcc, 0x4e, 0x93, 0x23, 0x9a, 0x0a, 0x8c, 0xc6, 0x0f, 0xe8, 0x48, 0xf8, 0x4a, 0x95, 0xf5, 0x90, 0x25, 0x99, 0xb5, 0x4a, 0x06, 0x62, 0x93, 0xa2, 0x02, 0x1d, 0xa1, 0x96, 0x76, 0x6c, 0x17, 0xc7, 0xe8, 0x63, 0xaf, 0x79, 0x0c, 0x27, 0x0b, 0x21, 0x6a, 0x25, 0x13, 0x8d, 0xda, 0x0c, 0x81, 0x26, 0xe0, 0x93, 0x77, 0x87, 0x98, 0x59, 0xdb, 0x35, 0x8f, 0x9b, 0x82, 0xb7, 0xc8, 0xa6, 0x79, 0x2a, 0xce, 0xe9, 0x2a, 0x4c, 0xbd, 0xe3, 0xce, 0xdd, 0x45, 0x00, 0xac, 0xbc, 0x55, 0x5c, 0x28, 0x8e, 0xff, 0x97, 0x95, 0x26, 0x5b, 0x90, 0x05, 0x35, 0x1c, 0x52, 0xe2, 0x65, 0x35, 0x54, 0xab, 0xaa, 0xf8, 0x72, 0xdf, 0x95, 0xca, 0x7f, 0x79, 0x59, 0x03, 0xf0, 0xb0, 0xa1, 0x82, 0xb1, 0x8a, 0xeb, 0x04, 0x75, 0xb2, 0x9f, 0x6e, 0x3a, 0xbf, 0x4c, 0x22, 0x50, 0xfe, 0x7b, 0x84, 0x2a, 0x73, 0x65, 0x50, 0x16, 0xa8, 0xfc, 0x72, 0x9f, 0x39, 0x05, 0x07, 0xac, 0xa9, 0x36, 0x82, 0x5a, 0x98, 0xb3, 0xa3, 0x2e, 0x6b, 0x25, 0x54, 0xce, 0x95, 0x28, 0x94, 0x1a, 0x3b, 0xb8, 0xc9, 0x09, 0x96, 0x00, 0x8d, 0x74, 0xfb, 0xcd, 0x02, 0x0a, 0x02, 0xe7, 0x06, 0xa6, 0xde, 0x7b, 0x02, 0xaf, 0x40, 0x4c, 0x10, 0xdb, 0x00, 0xfa, 0xec, 0x02, 0xd3, 0xea, 0xa6, 0xd9, 0x56, 0x1a, 0x15, 0x65, 0xa7, 0xb0, 0x5c, 0x63, 0x66, 0xd0, 0x9d, 0xa7, 0xa5, 0x37, 0xf2, 0x0c, 0x7b, 0x28, 0x59, 0xa8, 0x3e, 0x02, 0x9e, 0x13, 0xa9, 0xbd, 0x28, 0x91, 0x57, 0xc5, 0xb7, 0x4c, 0x84, 0xea, 0xa3, 0x07, 0x75, 0x3d, 0x43, 0x12, 0x02, 0xa3, 0xd9, 0xb6, 0x16, 0x22, 0x18, 0xbe, 0xc5, 0x34, 0x69, 0x45, 0xbf, 0xef, 0x55, 0xb6, 0x24, 0xc5, 0xc6, 0xe3, 0x73, 0x35, 0x9b, 0xb1, 0xc4, 0x79, 0x95, 0x2b, 0xba, 0xba, 0x4d, 0x65, 0x55, 0xc2, 0x76, 0x57, 0x3e, 0x51, 0x52, 0xb5, 0x53, 0x90, 0x19, 0x99, 0xf6, 0x94, 0x02, 0xd1, 0x50, 0xbe, 0xf7, 0x9d, 0x74, 0xfb, 0x29, 0x53, 0x01, 0x8f, 0xf4, 0x86, 0x66, 0x74, 0x6a, 0xce, 0x60, 0x78, 0x14, 0xa1, 0xfa, 0x33, 0x19, 0x57, 0x20, 0xf8, 0x38, 0x78, 0xd3, 0xb5, 0x75, 0xc7, 0x25, 0x74, 0x4a, 0x72, 0x07, 0x0d, 0xd0, 0x44, 0x01, 0x80, 0x42, 0xda, 0x25, 0x71, 0x4d, 0x17, 0x30, 0x90, 0x32, 0x3a, 0x51, 0xe6, 0xc0, 0x63, 0xd2, 0x03, 0x88, 0x13, 0x80, 0x91, 0x27, 0x61, 0xfc, 0x34, 0x10, 0x83, 0x90, 0x95, 0xf2, 0x6c, 0x0e, 0x68, 0x7a, 0x00, 0x70, 0x54, 0x95, 0xe1, 0x71, 0xb5, 0x71, 0x51, 0xac, 0xe0, 0x49, 0x8e, 0x30, 0xf1, 0x4c, 0xa9, 0xb0, 0x2f, 0x6e, 0x40, 0x83, 0x18, 0x54, 0xc2, 0xe0, 0xab, 0x1e, 0xcd, 0x0c, 0x21, 0xd8, 0xe4, 0xc7, 0xe6, 0x69, 0xcd, 0x72, 0x82, 0x30, 0xb9, 0xd1, 0x1f, 0x72, 0xc2, 0x66, 0xe3, 0x44, 0x66, 0xf9, 0xc0, 0x15, 0x9e, 0xf4, 0x24, 0xf8, 0xf3, 0x1d, 0x95, 0xa5, 0x7b, 0xa0, 0xe2, 0x10, 0x54, 0x3c, 0x10, 0xc6, 0x50, 0x3f, 0xb5, 0xc6, 0x3e, 0xd2, 0x3a, 0xa3, 0x6c, 0xd6, 0xa6, 0xf3, 0x78, 0x26, 0x1b, 0x0b, 0x1e, 0x79, 0x50, 0x9d, 0x8b, 0xeb, 0x36, 0xaa, 0x26, 0x3d, 0xc9, 0x15, 0x45, 0xe5, 0x33, 0x69, 0xdf, 0x26, 0x83, 0x7f, 0x39, 0x4c, 0x56, 0x77, 0x7c, 0x95, 0xb6, 0x48, 0xbd, 0x1a, 0x72, 0x92, 0x1a, 0xbf, 0x49, 0x56, 0x3f, 0x99, 0xcb, 0x9d, 0x98, 0xea, 0xb5, 0xc6, 0x66, 0x66, 0xf6, 0xb1, 0x6f, 0x74, 0x02, 0x24, 0x81, 0xfa, 0x21, 0x4e, 0x61, 0x76, 0x98, 0xd3, 0xbb, 0xd1, 0x3c, 0xb3, 0x08, 0x71, 0x3f, 0xdc, 0xc7, 0xcf, 0xd3, 0x97, 0xb9, 0xca, 0x39, 0xaf, 0xf4, 0xc7, 0x44, 0xd5, 0x71, 0x5d, 0x58, 0x96, 0x6f, 0x2c, 0xf9, 0x70, 0x70, 0x15, 0xc8, 0xf3, 0x54, 0x3e, 0xd2, 0x86, 0xa3, 0xd8, 0xd5, 0xcb, 0xf6, 0x4a, 0xce, 0xdf, 0xc0, 0x29, 0x71, 0xa9, 0x10, 0x72, 0xc6, 0x9d, 0x2e, 0xf4, 0x98, 0x29, 0xf1, 0x03, 0x7f, 0x05, 0x0c, 0x5b, 0x92, 0x22, 0x98, 0x56, 0xcb, 0x12, 0xb4, 0x56, 0xcc, 0x09, 0x52, 0x82, 0xa6, 0x26, 0x87, 0xea, 0x38, 0xc9, 0x77, 0x8a, 0xea, 0x49, 0x1d, 0xff, 0x06, 0x97, 0x11, 0xfb, 0xbe, 0x05, 0xe8, 0xcd, 0x9b, 0xf4, 0x4a, 0x8e, 0x71, 0x26, 0x19, 0x57, 0x3e, 0x12, 0xea, 0xa7, 0xb2, 0x38, 0x29, 0xdc, 0x67, 0x26, 0xbf, 0xe3, 0x3d, 0xa1, 0x36, 0xb8, 0x1e, 0x15, 0x32, 0x51, 0x50, 0x8f, 0x62, 0x85, 0xba, 0x15, 0xb2, 0xc1, 0x23, 0x76, 0x77, 0xfe, 0x5b, 0x14, 0xb4, 0xe3, 0x3f, 0x98, 0xc3, 0x26, 0xbc, 0x58, 0xb9, 0xd8, 0xe0, 0x75, 0xa2, 0x5b, 0x94, 0xc8, 0xa2, 0x32, 0x33, 0x02, 0x9d, 0xcc, 0x78, 0x6b, 0x13, 0x5c, 0x56, 0x16, 0x4b, 0xa3, 0xd1, 0x60, 0xcb, 0xce, 0xa8, 0x54, 0xb7, 0x97, 0x1f, 0x9c, 0xd7, 0x3a, 0x38, 0x3a, 0xac, 0x05, 0x0a, 0x30, 0x2a, 0xd8, 0x3b, 0x3e, 0x3a, 0xb9, 0x02, 0x46, 0xad, 0x16, 0x0a, 0x32, 0x1d, 0x33, 0x0a, 0xcd, 0xec, 0x7c, 0xa6, 0x64, 0x3d, 0x7e, 0xc0, 0x1f, 0x91, 0x69, 0x1f, 0x16, 0x32, 0x5b, 0xdf, 0x39, 0x69, 0x50, 0xb8, 0x8d, 0xaf, 0xe3, 0x69, 0xc6, 0x54, 0xb8, 0x52, 0x05, 0x5c, 0x97, 0x03, 0x62, 0xc6, 0x13, 0x80, 0x46, 0x07, 0x57, 0xc6, 0x58, 0x90, 0xf4, 0xe5, 0x92, 0x22, 0xe4, 0xa4, 0x06, 0x0b, 0x26, 0xc0, 0xeb, 0xc1, 0x01, 0x97, 0x59, 0x0d, 0xe3, 0xc8, 0xf0, 0x95, 0x5d, 0x65, 0x4b, 0x37, 0x1c, 0xcb, 0x90, 0xac, 0xa3, 0x71, 0xb2, 0x94, 0x47, 0x6c, 0x16, 0xa4, 0x59, 0x6a, 0x1d, 0xe8, 0x30, 0x9e, 0x2a, 0x36, 0x12, 0xc6, 0x9b, 0x71, 0x25, 0x31, 0x05, 0x01, 0xe0, 0xc0, 0x49, 0xb8, 0x74, 0x40, 0xd9, 0xa6, 0xd0, 0xec, 0xb9, 0x99, 0xc9, 0xa0, 0x94, 0x2a, 0xa3, 0x40, 0xf6, 0x03, 0x65, 0xea, 0xfd, 0x46, 0x5f, 0xc6, 0x4a, 0x0c, 0x5f, 0x8f, 0x3f, 0x90, 0x03, 0x48, 0x94, 0x15, 0x89, 0x9d, 0x59, 0xa5, 0x43, 0xd8, 0x20, 0x8c, 0x54, 0xa3, 0x16, 0x65, 0x29, 0xb5, 0x39, 0x22, 0xde, 0xe4, 0xab, 0xa0, 0x00, 0x38, 0x95, 0x81, 0x71, 0x7d, 0x36, 0xf5, 0x6f, 0x39, 0xaf, 0x73, 0x00, 0xb3, 0x1d, 0x83, 0x1a, 0x4d, 0x8c, 0x97, 0x61, 0x28, 0xe0, 0x9d, 0xed, 0xe7, 0x1a, 0x5a, 0x86, 0x26, 0xed, 0x79, 0xd4, 0x51, 0x14, 0x08, 0x00, 0xe0, 0x3b, 0x59, 0xb9, 0x56, 0xf8, 0x21, 0x0e, 0x55, 0x60, 0x67, 0x40, 0x7d, 0x13, 0xdc, 0x90, 0xfa, 0x9e, 0x8b, 0x87, 0x2b, 0xfb, 0x8f, 0xa0, 0x82, 0x04, 0xe5, 0x03, 0x82, 0x04, 0xe1, 0x00, 0xa0, 0xb7, 0x1f, 0x67, 0xc6, 0xce, 0xc0, 0xd3, 0x56, 0x86, 0xd5, 0x13, 0x42, 0x34, 0x32, 0xe5, 0x12, 0xac, 0x40, 0x44, 0x55, 0x7e, 0x86, 0x8a, 0x62, 0x48, 0x00, 0x10, 0x9a, 0x33, 0x55, 0xf9, 0x8f, 0x15, 0x14, 0x44, 0xe2, 0x85, 0x2e, 0x27, 0xea, 0x6e, 0xdb, 0x19, 0x92, 0xca, 0xd3, 0x97, 0x3c, 0x3a, 0x6f, 0xf7, 0x9a, 0x5a, 0x04, 0x9a, 0x25, 0x9e, 0xb5, 0x41, 0x5a, 0xa2, 0xa2, 0x62, 0x45, 0x6e, 0xc9, 0x49, 0x5b, 0xbb, 0x52, 0x00, 0xd8, 0xd3, 0x16, 0x3a, 0x5b, 0x10, 0x22, 0x62, 0x92, 0xec, 0xa0, 0x10, 0x21, 0x38, 0x9d, 0xa3, 0x78, 0x81, 0xe2, 0x76, 0x30, 0x65, 0x50, 0xc6, 0xef, 0xb6, 0x44, 0x0e, 0xc5, 0x1a, 0x2f, 0x73, 0x48, 0x34, 0x9b, 0x85, 0x1c, 0xd4, 0xaa, 0x01, 0x75, 0xa0, 0x55, 0x02, 0x13, 0xc4, 0x79, 0x1d, 0x91, 0x01, 0x12, 0x20, 0x82, 0x4b, 0x2b, 0x61, 0x65, 0x08, 0x13, 0xad, 0xfd, 0x2c, 0xb1, 0x05, 0x38, 0xbf, 0xab, 0x0a, 0x72, 0x6f, 0x81, 0x12, 0x9e, 0xd2, 0xc0, 0xf0, 0x6a, 0x16, 0xb7, 0x01, 0x09, 0x0b, 0xf0, 0x48, 0xc5, 0xa4, 0x01, 0x26, 0xd5, 0x72, 0xfc, 0xd4, 0x7a, 0xa1, 0x21, 0x8f, 0xb0, 0x15, 0x47, 0xd1, 0x50, 0x79, 0x2d, 0x23, 0x16, 0xcb, 0x32, 0x0d, 0x51, 0x44, 0xba, 0x35, 0x08, 0xa1, 0xeb, 0xbb, 0x5a, 0xc1, 0xc2, 0x29, 0x13, 0xe8, 0x29, 0x5f, 0xab, 0x59, 0xbf, 0x58, 0x37, 0xa7, 0x78, 0xcf, 0x28, 0x22, 0x7e, 0x07, 0xe1, 0x03, 0x2d, 0xab, 0x7d, 0x0e, 0x09, 0xa1, 0x5f, 0x13, 0x41, 0x48, 0xc1, 0x20, 0x09, 0xda, 0x53, 0x6b, 0x22, 0xcc, 0x62, 0x47, 0x4e, 0x69, 0xcc, 0x15, 0x54, 0xc0, 0x81, 0x4d, 0x6c, 0xa0, 0xb7, 0x22, 0x59, 0x43, 0x83, 0xa9, 0xd0, 0xa2, 0xc7, 0x7f, 0xd3, 0x65, 0xa5, 0x54, 0x42, 0x95, 0xfb, 0xb9, 0x73, 0xf9, 0x1e, 0xa5, 0x64, 0x90, 0xd6, 0xca, 0x68, 0x76, 0x49, 0x7b, 0x98, 0xb3, 0xcb, 0x12, 0x41, 0x7c, 0x25, 0x7b, 0x6d, 0x0f, 0x71, 0x83, 0xdb, 0xb6, 0x9e, 0x33, 0x07, 0x5b, 0xeb, 0x01, 0x17, 0xb6, 0x91, 0x4c, 0x69, 0xba, 0x38, 0x34, 0x94, 0x22, 0xf2, 0xf4, 0x33, 0x64, 0x82, 0x2a, 0x25, 0x70, 0x95, 0x2d, 0xd5, 0x07, 0x7b, 0x90, 0x75, 0x5f, 0x15, 0x74, 0x11, 0x5b, 0x8e, 0x22, 0x14, 0x27, 0x58, 0x59, 0x61, 0x91, 0x3a, 0x9b, 0xfa, 0x05, 0x02, 0xb5, 0xd7, 0x9a, 0xb7, 0x81, 0x17, 0x44, 0xe6, 0x56, 0x3c, 0x5b, 0x62, 0xc5, 0xcc, 0x4e, 0x93, 0x23, 0x9a, 0x0a, 0x8c, 0xc6, 0x0f, 0xe8, 0x48, 0xf8, 0x4a, 0x95, 0xf5, 0x90, 0x25, 0x99, 0xb5, 0x4a, 0x06, 0x62, 0x93, 0xa2, 0x02, 0x1d, 0xa1, 0x96, 0x76, 0x6c, 0x17, 0xc7, 0xe8, 0x63, 0xaf, 0x79, 0x0c, 0x27, 0x0b, 0x21, 0x6a, 0x25, 0x13, 0x8d, 0xda, 0x0c, 0x81, 0x26, 0xe0, 0x93, 0x77, 0x87, 0x98, 0x59, 0xdb, 0x35, 0x8f, 0x9b, 0x82, 0xb7, 0xc8, 0xa6, 0x79, 0x2a, 0xce, 0xe9, 0x2a, 0x4c, 0xbd, 0xe3, 0xce, 0xdd, 0x45, 0x00, 0xac, 0xbc, 0x55, 0x5c, 0x28, 0x8e, 0xff, 0x97, 0x95, 0x26, 0x5b, 0x90, 0x05, 0x35, 0x1c, 0x52, 0xe2, 0x65, 0x35, 0x54, 0xab, 0xaa, 0xf8, 0x72, 0xdf, 0x95, 0xca, 0x7f, 0x79, 0x59, 0x03, 0xf0, 0xb0, 0xa1, 0x82, 0xb1, 0x8a, 0xeb, 0x04, 0x75, 0xb2, 0x9f, 0x6e, 0x3a, 0xbf, 0x4c, 0x22, 0x50, 0xfe, 0x7b, 0x84, 0x2a, 0x73, 0x65, 0x50, 0x16, 0xa8, 0xfc, 0x72, 0x9f, 0x39, 0x05, 0x07, 0xac, 0xa9, 0x36, 0x82, 0x5a, 0x98, 0xb3, 0xa3, 0x2e, 0x6b, 0x25, 0x54, 0xce, 0x95, 0x28, 0x94, 0x1a, 0x3b, 0xb8, 0xc9, 0x09, 0x96, 0x00, 0x8d, 0x74, 0xfb, 0xcd, 0x02, 0x0a, 0x02, 0xe7, 0x06, 0xa6, 0xde, 0x7b, 0x02, 0xaf, 0x40, 0x4c, 0x10, 0xdb, 0x00, 0xfa, 0xec, 0x02, 0xd3, 0xea, 0xa6, 0xd9, 0x56, 0x1a, 0x15, 0x65, 0xa7, 0xb0, 0x5c, 0x63, 0x66, 0xd0, 0x9d, 0xa7, 0xa5, 0x37, 0xf2, 0x0c, 0x7b, 0x28, 0x59, 0xa8, 0x3e, 0x02, 0x9e, 0x13, 0xa9, 0xbd, 0x28, 0x91, 0x57, 0xc5, 0xb7, 0x4c, 0x84, 0xea, 0xa3, 0x07, 0x75, 0x3d, 0x43, 0x12, 0x02, 0xa3, 0xd9, 0xb6, 0x16, 0x22, 0x18, 0xbe, 0xc5, 0x34, 0x69, 0x45, 0xbf, 0xef, 0x55, 0xb6, 0x24, 0xc5, 0xc6, 0xe3, 0x73, 0x35, 0x9b, 0xb1, 0xc4, 0x79, 0x95, 0x2b, 0xba, 0xba, 0x4d, 0x65, 0x55, 0xc2, 0x76, 0x57, 0x3e, 0x51, 0x52, 0xb5, 0x53, 0x90, 0x19, 0x99, 0xf6, 0x94, 0x02, 0xd1, 0x50, 0xbe, 0xf7, 0x9d, 0x74, 0xfb, 0x29, 0x53, 0x01, 0x8f, 0xf4, 0x86, 0x66, 0x74, 0x6a, 0xce, 0x60, 0x78, 0x14, 0xa1, 0xfa, 0x33, 0x19, 0x57, 0x20, 0xf8, 0x38, 0x78, 0xd3, 0xb5, 0x75, 0xc7, 0x25, 0x74, 0x4a, 0x72, 0x07, 0x0d, 0xd0, 0x44, 0x01, 0x80, 0x42, 0xda, 0x25, 0x71, 0x4d, 0x17, 0x30, 0x90, 0x32, 0x3a, 0x51, 0xe6, 0xc0, 0x63, 0xd2, 0x03, 0x88, 0x13, 0x80, 0x91, 0x27, 0x61, 0xfc, 0x34, 0x10, 0x83, 0x90, 0x95, 0xf2, 0x6c, 0x0e, 0x68, 0x7a, 0x00, 0x70, 0x54, 0x95, 0xe1, 0x71, 0xb5, 0x71, 0x51, 0xac, 0xe0, 0x49, 0x8e, 0x30, 0xf1, 0x4c, 0xa9, 0xb0, 0x2f, 0x6e, 0x40, 0x83, 0x18, 0x54, 0xc2, 0xe0, 0xab, 0x1e, 0xcd, 0x0c, 0x21, 0xd8, 0xe4, 0xc7, 0xe6, 0x69, 0xcd, 0x72, 0x82, 0x30, 0xb9, 0xd1, 0x1f, 0x72, 0xc2, 0x66, 0xe3, 0x44, 0x66, 0xf9, 0xc0, 0x15, 0x9e, 0xf4, 0x24, 0xf8, 0xf3, 0x1d, 0x95, 0xa5, 0x7b, 0xa0, 0xe2, 0x10, 0x54, 0x3c, 0x10, 0xc6, 0x50, 0x3f, 0xb5, 0xc6, 0x3e, 0xd2, 0x3a, 0xa3, 0x6c, 0xd6, 0xa6, 0xf3, 0x78, 0x26, 0x1b, 0x0b, 0x1e, 0x79, 0x50, 0x9d, 0x8b, 0xeb, 0x36, 0xaa, 0x26, 0x3d, 0xc9, 0x15, 0x45, 0xe5, 0x33, 0x69, 0xdf, 0x26, 0x83, 0x7f, 0x39, 0x4c, 0x56, 0x77, 0x7c, 0x95, 0xb6, 0x48, 0xbd, 0x1a, 0x72, 0x92, 0x1a, 0xbf, 0x49, 0x56, 0x3f, 0x99, 0xcb, 0x9d, 0x98, 0xea, 0xb5, 0xc6, 0x66, 0x66, 0xf6, 0xb1, 0x6f, 0x74, 0x02, 0x24, 0x81, 0xfa, 0x21, 0x4e, 0x61, 0x76, 0x98, 0xd3, 0xbb, 0xd1, 0x3c, 0xb3, 0x08, 0x71, 0x3f, 0xdc, 0xc7, 0xcf, 0xd3, 0x97, 0xb9, 0xca, 0x39, 0xaf, 0xf4, 0xc7, 0x44, 0xd5, 0x71, 0x5d, 0x58, 0x96, 0x6f, 0x2c, 0xf9, 0x70, 0x70, 0x15, 0xc8, 0xf3, 0x54, 0x3e, 0xd2, 0x86, 0xa3, 0xd8, 0xd5, 0xcb, 0xf6, 0x4a, 0xce, 0xdf, 0xc0, 0x29, 0x71, 0xa9, 0x10, 0x72, 0xc6, 0x9d, 0x2e, 0xf4, 0x98, 0x29, 0xf1, 0x03, 0x7f, 0x05, 0x0c, 0x5b, 0x92, 0x22, 0x98, 0x56, 0xcb, 0x12, 0xb4, 0x56, 0xcc, 0x09, 0x52, 0x82, 0xa6, 0x26, 0x87, 0xea, 0x38, 0xc9, 0x77, 0x8a, 0xea, 0x49, 0x1d, 0xff, 0x06, 0x97, 0x11, 0xfb, 0xbe, 0x05, 0xe8, 0xcd, 0x9b, 0xf4, 0x4a, 0x8e, 0x71, 0x26, 0x19, 0x57, 0x3e, 0x12, 0xea, 0xa7, 0xb2, 0x38, 0x29, 0xdc, 0x67, 0x26, 0xbf, 0xe3, 0x3d, 0xa1, 0x36, 0xb8, 0x1e, 0x15, 0x32, 0x51, 0x50, 0x8f, 0x62, 0x85, 0xba, 0x15, 0xb2, 0xc1, 0x23, 0x76, 0x77, 0xfe, 0x5b, 0x14, 0xb4, 0xe3, 0x3f, 0x98, 0xc3, 0x26, 0xbc, 0x58, 0xb9, 0xd8, 0xe0, 0x75, 0xa2, 0x5b, 0x94, 0xc8, 0xa2, 0x32, 0x33, 0x02, 0x9d, 0xcc, 0x78, 0x6b, 0x13, 0x5c, 0x56, 0x16, 0x4b, 0xa3, 0xd1, 0x60, 0xcb, 0xce, 0xa8, 0x54, 0xb7, 0x97, 0x1f, 0x9c, 0xd7, 0x3a, 0x38, 0x3a, 0xac, 0x05, 0x0a, 0x30, 0x2a, 0xd8, 0x3b, 0x3e, 0x3a, 0xb9, 0x02, 0x46, 0xad, 0x16, 0x0a, 0x32, 0x1d, 0x33, 0x0a, 0xcd, 0xec, 0x7c, 0xa6, 0x64, 0x3d, 0x7e, 0xc0, 0x1f, 0x91, 0x69, 0x1f, 0x16, 0x32, 0x5b, 0xdf, 0x39, 0x69, 0x50, 0xb8, 0x8d, 0xaf, 0xe3, 0x69, 0xc6, 0x54, 0xb8, 0x52, 0x05, 0x5c, 0x97, 0x03, 0x62, 0xc6, 0x13, 0x80, 0x46, 0x07, 0x57, 0xc6, 0x58, 0x90, 0xf4, 0xe5, 0x92, 0x22, 0xe4, 0xa4, 0x06, 0x0b, 0x26, 0xc0, 0xeb, 0xc1, 0x01, 0x97, 0x59, 0x0d, 0xe3, 0xc8, 0xf0, 0x95, 0x5d, 0x65, 0x4b, 0x37, 0x1c, 0xcb, 0x90, 0xac, 0xa3, 0x71, 0xb2, 0x94, 0x47, 0x6c, 0x16, 0xa4, 0x59, 0x6a, 0x1d, 0xe8, 0x30, 0x9e, 0x2a, 0x36, 0x12, 0xc6, 0x9b, 0x71, 0x25, 0x31, 0x05, 0x01, 0xe0, 0xc0, 0x49, 0xb8, 0x74, 0x40, 0xd9, 0xa6, 0xd0, 0xec, 0xb9, 0x99, 0xc9, 0xa0, 0x94, 0x2a, 0xa3, 0x40, 0xf6, 0x03, 0x65, 0xea, 0xfd, 0x46, 0x5f, 0xc6, 0x4a, 0x0c, 0x5f, 0x8f, 0x3f, 0x90, 0x03, 0x48, 0x94, 0x15, 0x89, 0x9d, 0x59, 0xa5, 0x43, 0xd8, 0x20, 0x8c, 0x54, 0xa3, 0x16, 0x65, 0x29, 0xb5, 0x39, 0x22, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, }, .spki_len = 1219, .spki = { 0x30, 0x82, 0x04, 0xbf, 0x30, 0x0f, 0x06, 0x0b, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x02, 0x82, 0x0b, 0x05, 0x03, 0x03, 0x05, 0x00, 0x03, 0x82, 0x04, 0xaa, 0x00, 0x30, 0x82, 0x04, 0xa5, 0x03, 0x82, 0x04, 0xa1, 0x00, 0xa0, 0xb7, 0x1f, 0x67, 0xc6, 0xce, 0xc0, 0xd3, 0x56, 0x86, 0xd5, 0x13, 0x42, 0x34, 0x32, 0xe5, 0x12, 0xac, 0x40, 0x44, 0x55, 0x7e, 0x86, 0x8a, 0x62, 0x48, 0x00, 0x10, 0x9a, 0x33, 0x55, 0xf9, 0x8f, 0x15, 0x14, 0x44, 0xe2, 0x85, 0x2e, 0x27, 0xea, 0x6e, 0xdb, 0x19, 0x92, 0xca, 0xd3, 0x97, 0x3c, 0x3a, 0x6f, 0xf7, 0x9a, 0x5a, 0x04, 0x9a, 0x25, 0x9e, 0xb5, 0x41, 0x5a, 0xa2, 0xa2, 0x62, 0x45, 0x6e, 0xc9, 0x49, 0x5b, 0xbb, 0x52, 0x00, 0xd8, 0xd3, 0x16, 0x3a, 0x5b, 0x10, 0x22, 0x62, 0x92, 0xec, 0xa0, 0x10, 0x21, 0x38, 0x9d, 0xa3, 0x78, 0x81, 0xe2, 0x76, 0x30, 0x65, 0x50, 0xc6, 0xef, 0xb6, 0x44, 0x0e, 0xc5, 0x1a, 0x2f, 0x73, 0x48, 0x34, 0x9b, 0x85, 0x1c, 0xd4, 0xaa, 0x01, 0x75, 0xa0, 0x55, 0x02, 0x13, 0xc4, 0x79, 0x1d, 0x91, 0x01, 0x12, 0x20, 0x82, 0x4b, 0x2b, 0x61, 0x65, 0x08, 0x13, 0xad, 0xfd, 0x2c, 0xb1, 0x05, 0x38, 0xbf, 0xab, 0x0a, 0x72, 0x6f, 0x81, 0x12, 0x9e, 0xd2, 0xc0, 0xf0, 0x6a, 0x16, 0xb7, 0x01, 0x09, 0x0b, 0xf0, 0x48, 0xc5, 0xa4, 0x01, 0x26, 0xd5, 0x72, 0xfc, 0xd4, 0x7a, 0xa1, 0x21, 0x8f, 0xb0, 0x15, 0x47, 0xd1, 0x50, 0x79, 0x2d, 0x23, 0x16, 0xcb, 0x32, 0x0d, 0x51, 0x44, 0xba, 0x35, 0x08, 0xa1, 0xeb, 0xbb, 0x5a, 0xc1, 0xc2, 0x29, 0x13, 0xe8, 0x29, 0x5f, 0xab, 0x59, 0xbf, 0x58, 0x37, 0xa7, 0x78, 0xcf, 0x28, 0x22, 0x7e, 0x07, 0xe1, 0x03, 0x2d, 0xab, 0x7d, 0x0e, 0x09, 0xa1, 0x5f, 0x13, 0x41, 0x48, 0xc1, 0x20, 0x09, 0xda, 0x53, 0x6b, 0x22, 0xcc, 0x62, 0x47, 0x4e, 0x69, 0xcc, 0x15, 0x54, 0xc0, 0x81, 0x4d, 0x6c, 0xa0, 0xb7, 0x22, 0x59, 0x43, 0x83, 0xa9, 0xd0, 0xa2, 0xc7, 0x7f, 0xd3, 0x65, 0xa5, 0x54, 0x42, 0x95, 0xfb, 0xb9, 0x73, 0xf9, 0x1e, 0xa5, 0x64, 0x90, 0xd6, 0xca, 0x68, 0x76, 0x49, 0x7b, 0x98, 0xb3, 0xcb, 0x12, 0x41, 0x7c, 0x25, 0x7b, 0x6d, 0x0f, 0x71, 0x83, 0xdb, 0xb6, 0x9e, 0x33, 0x07, 0x5b, 0xeb, 0x01, 0x17, 0xb6, 0x91, 0x4c, 0x69, 0xba, 0x38, 0x34, 0x94, 0x22, 0xf2, 0xf4, 0x33, 0x64, 0x82, 0x2a, 0x25, 0x70, 0x95, 0x2d, 0xd5, 0x07, 0x7b, 0x90, 0x75, 0x5f, 0x15, 0x74, 0x11, 0x5b, 0x8e, 0x22, 0x14, 0x27, 0x58, 0x59, 0x61, 0x91, 0x3a, 0x9b, 0xfa, 0x05, 0x02, 0xb5, 0xd7, 0x9a, 0xb7, 0x81, 0x17, 0x44, 0xe6, 0x56, 0x3c, 0x5b, 0x62, 0xc5, 0xcc, 0x4e, 0x93, 0x23, 0x9a, 0x0a, 0x8c, 0xc6, 0x0f, 0xe8, 0x48, 0xf8, 0x4a, 0x95, 0xf5, 0x90, 0x25, 0x99, 0xb5, 0x4a, 0x06, 0x62, 0x93, 0xa2, 0x02, 0x1d, 0xa1, 0x96, 0x76, 0x6c, 0x17, 0xc7, 0xe8, 0x63, 0xaf, 0x79, 0x0c, 0x27, 0x0b, 0x21, 0x6a, 0x25, 0x13, 0x8d, 0xda, 0x0c, 0x81, 0x26, 0xe0, 0x93, 0x77, 0x87, 0x98, 0x59, 0xdb, 0x35, 0x8f, 0x9b, 0x82, 0xb7, 0xc8, 0xa6, 0x79, 0x2a, 0xce, 0xe9, 0x2a, 0x4c, 0xbd, 0xe3, 0xce, 0xdd, 0x45, 0x00, 0xac, 0xbc, 0x55, 0x5c, 0x28, 0x8e, 0xff, 0x97, 0x95, 0x26, 0x5b, 0x90, 0x05, 0x35, 0x1c, 0x52, 0xe2, 0x65, 0x35, 0x54, 0xab, 0xaa, 0xf8, 0x72, 0xdf, 0x95, 0xca, 0x7f, 0x79, 0x59, 0x03, 0xf0, 0xb0, 0xa1, 0x82, 0xb1, 0x8a, 0xeb, 0x04, 0x75, 0xb2, 0x9f, 0x6e, 0x3a, 0xbf, 0x4c, 0x22, 0x50, 0xfe, 0x7b, 0x84, 0x2a, 0x73, 0x65, 0x50, 0x16, 0xa8, 0xfc, 0x72, 0x9f, 0x39, 0x05, 0x07, 0xac, 0xa9, 0x36, 0x82, 0x5a, 0x98, 0xb3, 0xa3, 0x2e, 0x6b, 0x25, 0x54, 0xce, 0x95, 0x28, 0x94, 0x1a, 0x3b, 0xb8, 0xc9, 0x09, 0x96, 0x00, 0x8d, 0x74, 0xfb, 0xcd, 0x02, 0x0a, 0x02, 0xe7, 0x06, 0xa6, 0xde, 0x7b, 0x02, 0xaf, 0x40, 0x4c, 0x10, 0xdb, 0x00, 0xfa, 0xec, 0x02, 0xd3, 0xea, 0xa6, 0xd9, 0x56, 0x1a, 0x15, 0x65, 0xa7, 0xb0, 0x5c, 0x63, 0x66, 0xd0, 0x9d, 0xa7, 0xa5, 0x37, 0xf2, 0x0c, 0x7b, 0x28, 0x59, 0xa8, 0x3e, 0x02, 0x9e, 0x13, 0xa9, 0xbd, 0x28, 0x91, 0x57, 0xc5, 0xb7, 0x4c, 0x84, 0xea, 0xa3, 0x07, 0x75, 0x3d, 0x43, 0x12, 0x02, 0xa3, 0xd9, 0xb6, 0x16, 0x22, 0x18, 0xbe, 0xc5, 0x34, 0x69, 0x45, 0xbf, 0xef, 0x55, 0xb6, 0x24, 0xc5, 0xc6, 0xe3, 0x73, 0x35, 0x9b, 0xb1, 0xc4, 0x79, 0x95, 0x2b, 0xba, 0xba, 0x4d, 0x65, 0x55, 0xc2, 0x76, 0x57, 0x3e, 0x51, 0x52, 0xb5, 0x53, 0x90, 0x19, 0x99, 0xf6, 0x94, 0x02, 0xd1, 0x50, 0xbe, 0xf7, 0x9d, 0x74, 0xfb, 0x29, 0x53, 0x01, 0x8f, 0xf4, 0x86, 0x66, 0x74, 0x6a, 0xce, 0x60, 0x78, 0x14, 0xa1, 0xfa, 0x33, 0x19, 0x57, 0x20, 0xf8, 0x38, 0x78, 0xd3, 0xb5, 0x75, 0xc7, 0x25, 0x74, 0x4a, 0x72, 0x07, 0x0d, 0xd0, 0x44, 0x01, 0x80, 0x42, 0xda, 0x25, 0x71, 0x4d, 0x17, 0x30, 0x90, 0x32, 0x3a, 0x51, 0xe6, 0xc0, 0x63, 0xd2, 0x03, 0x88, 0x13, 0x80, 0x91, 0x27, 0x61, 0xfc, 0x34, 0x10, 0x83, 0x90, 0x95, 0xf2, 0x6c, 0x0e, 0x68, 0x7a, 0x00, 0x70, 0x54, 0x95, 0xe1, 0x71, 0xb5, 0x71, 0x51, 0xac, 0xe0, 0x49, 0x8e, 0x30, 0xf1, 0x4c, 0xa9, 0xb0, 0x2f, 0x6e, 0x40, 0x83, 0x18, 0x54, 0xc2, 0xe0, 0xab, 0x1e, 0xcd, 0x0c, 0x21, 0xd8, 0xe4, 0xc7, 0xe6, 0x69, 0xcd, 0x72, 0x82, 0x30, 0xb9, 0xd1, 0x1f, 0x72, 0xc2, 0x66, 0xe3, 0x44, 0x66, 0xf9, 0xc0, 0x15, 0x9e, 0xf4, 0x24, 0xf8, 0xf3, 0x1d, 0x95, 0xa5, 0x7b, 0xa0, 0xe2, 0x10, 0x54, 0x3c, 0x10, 0xc6, 0x50, 0x3f, 0xb5, 0xc6, 0x3e, 0xd2, 0x3a, 0xa3, 0x6c, 0xd6, 0xa6, 0xf3, 0x78, 0x26, 0x1b, 0x0b, 0x1e, 0x79, 0x50, 0x9d, 0x8b, 0xeb, 0x36, 0xaa, 0x26, 0x3d, 0xc9, 0x15, 0x45, 0xe5, 0x33, 0x69, 0xdf, 0x26, 0x83, 0x7f, 0x39, 0x4c, 0x56, 0x77, 0x7c, 0x95, 0xb6, 0x48, 0xbd, 0x1a, 0x72, 0x92, 0x1a, 0xbf, 0x49, 0x56, 0x3f, 0x99, 0xcb, 0x9d, 0x98, 0xea, 0xb5, 0xc6, 0x66, 0x66, 0xf6, 0xb1, 0x6f, 0x74, 0x02, 0x24, 0x81, 0xfa, 0x21, 0x4e, 0x61, 0x76, 0x98, 0xd3, 0xbb, 0xd1, 0x3c, 0xb3, 0x08, 0x71, 0x3f, 0xdc, 0xc7, 0xcf, 0xd3, 0x97, 0xb9, 0xca, 0x39, 0xaf, 0xf4, 0xc7, 0x44, 0xd5, 0x71, 0x5d, 0x58, 0x96, 0x6f, 0x2c, 0xf9, 0x70, 0x70, 0x15, 0xc8, 0xf3, 0x54, 0x3e, 0xd2, 0x86, 0xa3, 0xd8, 0xd5, 0xcb, 0xf6, 0x4a, 0xce, 0xdf, 0xc0, 0x29, 0x71, 0xa9, 0x10, 0x72, 0xc6, 0x9d, 0x2e, 0xf4, 0x98, 0x29, 0xf1, 0x03, 0x7f, 0x05, 0x0c, 0x5b, 0x92, 0x22, 0x98, 0x56, 0xcb, 0x12, 0xb4, 0x56, 0xcc, 0x09, 0x52, 0x82, 0xa6, 0x26, 0x87, 0xea, 0x38, 0xc9, 0x77, 0x8a, 0xea, 0x49, 0x1d, 0xff, 0x06, 0x97, 0x11, 0xfb, 0xbe, 0x05, 0xe8, 0xcd, 0x9b, 0xf4, 0x4a, 0x8e, 0x71, 0x26, 0x19, 0x57, 0x3e, 0x12, 0xea, 0xa7, 0xb2, 0x38, 0x29, 0xdc, 0x67, 0x26, 0xbf, 0xe3, 0x3d, 0xa1, 0x36, 0xb8, 0x1e, 0x15, 0x32, 0x51, 0x50, 0x8f, 0x62, 0x85, 0xba, 0x15, 0xb2, 0xc1, 0x23, 0x76, 0x77, 0xfe, 0x5b, 0x14, 0xb4, 0xe3, 0x3f, 0x98, 0xc3, 0x26, 0xbc, 0x58, 0xb9, 0xd8, 0xe0, 0x75, 0xa2, 0x5b, 0x94, 0xc8, 0xa2, 0x32, 0x33, 0x02, 0x9d, 0xcc, 0x78, 0x6b, 0x13, 0x5c, 0x56, 0x16, 0x4b, 0xa3, 0xd1, 0x60, 0xcb, 0xce, 0xa8, 0x54, 0xb7, 0x97, 0x1f, 0x9c, 0xd7, 0x3a, 0x38, 0x3a, 0xac, 0x05, 0x0a, 0x30, 0x2a, 0xd8, 0x3b, 0x3e, 0x3a, 0xb9, 0x02, 0x46, 0xad, 0x16, 0x0a, 0x32, 0x1d, 0x33, 0x0a, 0xcd, 0xec, 0x7c, 0xa6, 0x64, 0x3d, 0x7e, 0xc0, 0x1f, 0x91, 0x69, 0x1f, 0x16, 0x32, 0x5b, 0xdf, 0x39, 0x69, 0x50, 0xb8, 0x8d, 0xaf, 0xe3, 0x69, 0xc6, 0x54, 0xb8, 0x52, 0x05, 0x5c, 0x97, 0x03, 0x62, 0xc6, 0x13, 0x80, 0x46, 0x07, 0x57, 0xc6, 0x58, 0x90, 0xf4, 0xe5, 0x92, 0x22, 0xe4, 0xa4, 0x06, 0x0b, 0x26, 0xc0, 0xeb, 0xc1, 0x01, 0x97, 0x59, 0x0d, 0xe3, 0xc8, 0xf0, 0x95, 0x5d, 0x65, 0x4b, 0x37, 0x1c, 0xcb, 0x90, 0xac, 0xa3, 0x71, 0xb2, 0x94, 0x47, 0x6c, 0x16, 0xa4, 0x59, 0x6a, 0x1d, 0xe8, 0x30, 0x9e, 0x2a, 0x36, 0x12, 0xc6, 0x9b, 0x71, 0x25, 0x31, 0x05, 0x01, 0xe0, 0xc0, 0x49, 0xb8, 0x74, 0x40, 0xd9, 0xa6, 0xd0, 0xec, 0xb9, 0x99, 0xc9, 0xa0, 0x94, 0x2a, 0xa3, 0x40, 0xf6, 0x03, 0x65, 0xea, 0xfd, 0x46, 0x5f, 0xc6, 0x4a, 0x0c, 0x5f, 0x8f, 0x3f, 0x90, 0x03, 0x48, 0x94, 0x15, 0x89, 0x9d, 0x59, 0xa5, 0x43, 0xd8, 0x20, 0x8c, 0x54, 0xa3, 0x16, 0x65, 0x29, 0xb5, 0x39, 0x22, }, .secret_len = 32, .secret = { 0xed, 0x20, 0x14, 0x0c, 0x05, 0xd7, 0x8b, 0x15, 0xf2, 0xe4, 0x12, 0x67, 0x1a, 0x84, 0x15, 0x42, 0x17, 0xfd, 0x77, 0x61, 0x9a, 0x2c, 0x52, 0x2d, 0x3c, 0x3c, 0xb6, 0x88, 0xcb, 0x34, 0xc6, 0x8b, }, .cipher_len = 1088, .cipher = { 0xea, 0xdd, 0x5a, 0xda, 0x14, 0xda, 0x57, 0xf0, 0xae, 0xf3, 0x50, 0x5f, 0x1c, 0xaa, 0x64, 0x85, 0xd4, 0x23, 0x8d, 0x99, 0x9a, 0x3e, 0xf4, 0xb0, 0xa5, 0x9a, 0x1c, 0xdb, 0xe0, 0xa2, 0x7e, 0x47, 0x85, 0x47, 0xa3, 0xa9, 0x9d, 0x2a, 0xb0, 0x9a, 0xc7, 0xd7, 0xc8, 0xf5, 0xae, 0x3d, 0x64, 0x32, 0x04, 0x5c, 0xba, 0x3f, 0xa7, 0x78, 0x34, 0x58, 0x92, 0x54, 0x2b, 0xd8, 0x1c, 0x05, 0xbe, 0xfc, 0xd2, 0xe5, 0xcc, 0x9a, 0x57, 0x9b, 0xef, 0xb7, 0xc5, 0x8d, 0x02, 0xfb, 0x94, 0xf3, 0x33, 0x92, 0xfe, 0x17, 0xf4, 0xeb, 0xa2, 0xcb, 0x51, 0x0e, 0xc7, 0x4c, 0xc9, 0xd1, 0xd8, 0xa8, 0x7c, 0x10, 0x66, 0xa4, 0x86, 0x9a, 0x39, 0x83, 0xe6, 0x64, 0xbf, 0xe9, 0xde, 0xa5, 0xae, 0x4f, 0xdf, 0x31, 0x0c, 0x8f, 0x59, 0x81, 0x5a, 0x67, 0x8f, 0xa3, 0x25, 0xf3, 0x69, 0xaf, 0x84, 0xff, 0xeb, 0xc1, 0xd1, 0x50, 0x43, 0x1f, 0xe3, 0xbd, 0x27, 0x34, 0xf6, 0x36, 0xcf, 0x65, 0x8e, 0x6c, 0x1a, 0x6a, 0x6e, 0x2c, 0xbe, 0x07, 0x1f, 0x9a, 0x7c, 0x26, 0x11, 0x9a, 0xd1, 0x05, 0x09, 0x8e, 0xda, 0x62, 0x2c, 0xab, 0x8e, 0x17, 0x67, 0x62, 0x10, 0x98, 0x77, 0xd9, 0xae, 0x9d, 0x67, 0x29, 0xd4, 0x4a, 0x58, 0xe7, 0x07, 0xd6, 0xb8, 0xad, 0x6e, 0x69, 0x6a, 0x33, 0xc6, 0x72, 0xda, 0x9d, 0x08, 0xda, 0x2a, 0x7f, 0x9e, 0x3b, 0xf0, 0x22, 0x18, 0x23, 0x87, 0x22, 0xa4, 0x6b, 0x31, 0xd4, 0x9d, 0xaf, 0xf9, 0xaf, 0x00, 0xa6, 0x36, 0x3c, 0x3a, 0x42, 0x3b, 0x2e, 0x87, 0x3d, 0xef, 0xdd, 0xbc, 0xd9, 0x69, 0xb7, 0x5a, 0x81, 0x05, 0x3d, 0x9a, 0x97, 0xc0, 0x6d, 0xe2, 0xbf, 0xe3, 0xd0, 0xcf, 0xd3, 0xd3, 0xc7, 0x79, 0x83, 0xb1, 0x8d, 0xbd, 0xe2, 0x3c, 0x07, 0x28, 0x60, 0x4a, 0x71, 0x43, 0x5a, 0xd4, 0x0d, 0xf1, 0x57, 0x90, 0x96, 0xdd, 0xbe, 0x02, 0xe4, 0x61, 0x22, 0x10, 0xca, 0xa0, 0x34, 0xdc, 0xef, 0xb8, 0xb4, 0xd7, 0xb5, 0xe6, 0xd2, 0xeb, 0xa3, 0x7a, 0x79, 0xfb, 0x61, 0xf3, 0x4b, 0x5a, 0xf7, 0xd9, 0xb2, 0x7b, 0x13, 0xe4, 0x93, 0x62, 0x22, 0x41, 0x12, 0x49, 0xb7, 0xfb, 0xb6, 0x9e, 0x73, 0x46, 0x1d, 0xaf, 0x4a, 0xa6, 0xf3, 0xe2, 0xc7, 0x39, 0x44, 0xf1, 0x0c, 0xe6, 0x7c, 0x86, 0xfe, 0xd2, 0x60, 0xbd, 0xa7, 0xb4, 0x0d, 0xb3, 0x9b, 0x1d, 0xe3, 0xc7, 0xd8, 0xf0, 0x9a, 0x77, 0xf3, 0xc8, 0x4b, 0xc6, 0x29, 0x31, 0xd2, 0x28, 0xb2, 0x4a, 0x57, 0x4a, 0xc3, 0xf4, 0xeb, 0x74, 0x5c, 0xff, 0x7e, 0x03, 0x1a, 0x3f, 0xb2, 0xa0, 0x85, 0x95, 0xc1, 0x53, 0x70, 0xa3, 0xc8, 0x2d, 0xb7, 0xd9, 0xf4, 0x1b, 0xb1, 0xd8, 0xec, 0xc4, 0x29, 0xcf, 0xa3, 0xa6, 0x58, 0x33, 0x01, 0x6a, 0xb6, 0xea, 0x60, 0xc9, 0x39, 0x0c, 0xfa, 0x1b, 0x65, 0xcc, 0xea, 0xe5, 0x50, 0x94, 0x07, 0x95, 0x38, 0x6e, 0xd2, 0x41, 0x33, 0xfb, 0xae, 0x8b, 0x30, 0x17, 0x50, 0x2a, 0xf3, 0xcf, 0xe9, 0x51, 0xd7, 0x81, 0xd3, 0x6c, 0xfe, 0xff, 0x85, 0xbf, 0xdf, 0x5a, 0xf0, 0x40, 0xbe, 0x40, 0x65, 0x68, 0x1b, 0x3b, 0x0a, 0x63, 0xc2, 0x74, 0x7f, 0x08, 0x08, 0xcf, 0x3d, 0xa7, 0x25, 0x16, 0x9d, 0xde, 0xd1, 0x00, 0x3d, 0xa6, 0xcd, 0x5d, 0xe4, 0xcb, 0x04, 0x19, 0x42, 0x93, 0x8d, 0x0a, 0x7f, 0x88, 0x02, 0xd4, 0x8f, 0x2e, 0x3c, 0x6e, 0xeb, 0x45, 0xcd, 0x90, 0xaf, 0x6f, 0xc9, 0xf4, 0x50, 0x7e, 0x9f, 0x83, 0x80, 0xac, 0x33, 0xca, 0xca, 0x77, 0x51, 0x48, 0x7f, 0x65, 0x50, 0x04, 0x41, 0xd9, 0x20, 0xb9, 0x48, 0x80, 0xa4, 0x97, 0xd0, 0x1c, 0x08, 0x02, 0xbb, 0x08, 0xd7, 0x4c, 0x5d, 0x4c, 0x6b, 0xf2, 0xd8, 0x65, 0xee, 0x58, 0x22, 0xb3, 0x37, 0x5c, 0x75, 0x5d, 0x1a, 0x5e, 0x3d, 0x32, 0x44, 0xc3, 0x20, 0x51, 0x0a, 0x1e, 0x30, 0x35, 0x77, 0x02, 0xcd, 0x42, 0x52, 0x07, 0x2c, 0xf8, 0x64, 0x37, 0xf7, 0xa9, 0xde, 0x55, 0x61, 0xc7, 0xe5, 0x9b, 0x94, 0xb9, 0x58, 0x41, 0x00, 0x13, 0x1a, 0xc3, 0x99, 0xf4, 0xc1, 0xeb, 0x19, 0xfb, 0x4b, 0xdf, 0x65, 0xe6, 0x27, 0x85, 0xe9, 0x7c, 0x19, 0x4b, 0x87, 0x64, 0xcc, 0xf3, 0x2f, 0xd0, 0x5d, 0x80, 0x4c, 0x2e, 0x43, 0x9d, 0xda, 0x2a, 0x10, 0x92, 0x74, 0xfb, 0xff, 0xa8, 0x1a, 0x83, 0x7c, 0x51, 0xb2, 0x6d, 0x15, 0x4f, 0x97, 0x4b, 0x88, 0x2a, 0x5b, 0x17, 0x4b, 0x30, 0x8f, 0xc4, 0x87, 0x68, 0xd2, 0x22, 0x92, 0x25, 0x32, 0xb1, 0x83, 0xab, 0xdf, 0x6f, 0xbb, 0x0b, 0xc7, 0x49, 0x27, 0x66, 0x97, 0x4d, 0x32, 0x1e, 0xe6, 0xfb, 0x7c, 0x5f, 0x7b, 0x3e, 0xea, 0x23, 0x78, 0xdc, 0x6d, 0x6b, 0xb4, 0x80, 0x19, 0x25, 0x0b, 0x8d, 0x8d, 0x8d, 0xed, 0xb5, 0x22, 0x42, 0x1a, 0xee, 0xdb, 0x31, 0x86, 0x76, 0x98, 0x2a, 0x80, 0xe7, 0x96, 0x1e, 0xc4, 0x0e, 0x6d, 0x7f, 0x33, 0x39, 0x69, 0x42, 0x55, 0xba, 0xff, 0x51, 0xbe, 0x3a, 0x7e, 0xa7, 0xd8, 0x79, 0x3a, 0x10, 0x9b, 0xe3, 0xae, 0x44, 0x23, 0xbf, 0x08, 0x2e, 0x20, 0x6a, 0x57, 0x3b, 0x4f, 0x0f, 0x93, 0xfc, 0x16, 0xdd, 0xe8, 0x1b, 0xd5, 0xdc, 0x58, 0x3f, 0x52, 0x8c, 0x08, 0xa0, 0xa9, 0xab, 0x8e, 0x6c, 0xd5, 0x24, 0xe2, 0x97, 0xc9, 0xcf, 0x0f, 0x43, 0xc3, 0x44, 0x91, 0x38, 0x30, 0xec, 0xb1, 0x6f, 0x91, 0x44, 0x14, 0x77, 0xba, 0x78, 0x2e, 0xdd, 0x4e, 0x73, 0xe7, 0x32, 0x97, 0x9d, 0x3a, 0x66, 0x4e, 0xb9, 0x9e, 0xa5, 0xd2, 0x4b, 0x6c, 0x84, 0xaa, 0x69, 0xf3, 0x77, 0xcb, 0x0c, 0xad, 0x5a, 0xe4, 0xe6, 0x41, 0xe3, 0x8b, 0x19, 0x7a, 0x09, 0x94, 0xd5, 0x8b, 0x23, 0x87, 0xe9, 0x17, 0x60, 0xe9, 0xb6, 0xfe, 0xbc, 0xb4, 0x45, 0xcf, 0x85, 0xbb, 0xa2, 0x4a, 0x94, 0xcd, 0xa7, 0x5e, 0x33, 0x86, 0x74, 0x42, 0x82, 0x49, 0xfe, 0x6d, 0xe4, 0x69, 0x26, 0x01, 0xd1, 0xea, 0xe0, 0xea, 0x02, 0x1d, 0x9b, 0xc8, 0x07, 0x7b, 0xe8, 0x66, 0x5d, 0x07, 0x37, 0x74, 0x8f, 0xa3, 0x0f, 0xcf, 0x80, 0xf7, 0xe4, 0x82, 0x58, 0x46, 0x74, 0xf6, 0x33, 0xa5, 0x00, 0x6a, 0x53, 0x82, 0x67, 0x62, 0x7f, 0xd9, 0x18, 0x54, 0xe0, 0x87, 0x12, 0x68, 0xa6, 0xb0, 0xb0, 0x5d, 0xd5, 0x14, 0x95, 0x13, 0x5d, 0xef, 0xb9, 0x37, 0x6e, 0x9b, 0x84, 0x1b, 0x64, 0xe5, 0xdb, 0xf4, 0x3c, 0xe6, 0xc7, 0x4b, 0xcf, 0x3a, 0xe1, 0xfc, 0x42, 0x7e, 0x81, 0x0b, 0x7c, 0xbf, 0x69, 0x57, 0xdb, 0xf9, 0x04, 0x69, 0x0e, 0x87, 0x84, 0x25, 0x43, 0x89, 0x7d, 0xe7, 0x8f, 0x13, 0xd0, 0x8d, 0x92, 0xeb, 0xd2, 0x7f, 0xb2, 0xcf, 0xcc, 0x0c, 0x76, 0x54, 0x30, 0x58, 0x90, 0x57, 0xb1, 0x6b, 0x15, 0xf2, 0x07, 0xca, 0x1e, 0x6f, 0x08, 0xd5, 0x26, 0x16, 0xdd, 0x57, 0xad, 0x43, 0xef, 0xea, 0x6f, 0xdd, 0xaa, 0xea, 0x18, 0xd3, 0x37, 0x31, 0xfa, 0xc7, 0xec, 0xaa, 0xe9, 0x50, 0xe1, 0xdf, 0x3c, 0x5a, 0x4e, 0x6f, 0xcb, 0x22, 0x3d, 0xf5, 0xe8, 0x6b, 0x48, 0x7f, 0xd7, 0x09, 0x2d, 0x08, 0x22, 0xef, 0xfa, 0xec, 0x82, 0xc4, 0xbe, 0xc1, 0x0c, 0x60, 0x0f, 0xdb, 0x90, 0xe7, 0x74, 0x82, 0x91, 0x1b, 0x15, 0x95, 0x27, 0x77, 0x38, 0x84, 0x14, 0x09, 0xd0, 0xf8, 0xf1, 0x13, 0x19, 0x1d, 0x47, 0xf5, 0xe5, 0x6c, 0x11, 0x5a, 0x05, 0xde, 0xa7, 0x59, 0xaa, 0x6f, 0xb1, 0xd0, 0x47, 0xf9, 0xfc, 0xa4, 0xed, 0x51, 0x9e, 0xa5, 0xd2, 0x1f, 0xe3, 0xba, 0x5b, 0x94, 0x34, 0xfe, 0xa1, 0x28, 0x3d, 0xfa, 0xd6, 0x3d, 0x01, 0x58, 0x9b, 0x0e, 0xb6, 0x1f, 0x24, 0x43, 0x51, 0xd0, 0x33, 0x41, 0xdc, 0xd4, 0xdf, 0x62, 0x26, 0x5a, 0xfc, 0xae, 0xc6, 0x67, 0x6a, 0x87, 0x7d, 0x5c, 0xac, 0xb3, 0x59, 0xeb, 0xb5, 0x31, 0x96, 0x10, 0xdd, 0x44, 0x7d, 0xa9, 0x7e, 0x95, 0x0b, 0x0c, }, }, { .name = "Kyber Round 2, 786 KAT 0", .version = 0, .keyform = CK_IBM_KYBER_KEYFORM_ROUND2_768, .sk_len = 2400, .sk = { 0x07, 0x63, 0x8F, 0xB6, 0x98, 0x68, 0xF3, 0xD3, 0x20, 0xE5, 0x86, 0x2B, 0xD9, 0x69, 0x33, 0xFE, 0xB3, 0x11, 0xB3, 0x62, 0x09, 0x3C, 0x9B, 0x5D, 0x50, 0x17, 0x0B, 0xCE, 0xD4, 0x3F, 0x1B, 0x53, 0x6D, 0x9A, 0x20, 0x4B, 0xB1, 0xF2, 0x26, 0x95, 0x95, 0x0B, 0xA1, 0xF2, 0xA9, 0xE8, 0xEB, 0x82, 0x8B, 0x28, 0x44, 0x88, 0x76, 0x0B, 0x3F, 0xC8, 0x4F, 0xAB, 0xA0, 0x42, 0x75, 0xD5, 0x62, 0x8E, 0x39, 0xC5, 0xB2, 0x47, 0x13, 0x74, 0x28, 0x3C, 0x50, 0x32, 0x99, 0xC0, 0xAB, 0x49, 0xB6, 0x6B, 0x8B, 0xBB, 0x56, 0xA4, 0x18, 0x66, 0x24, 0xF9, 0x19, 0xA2, 0xBA, 0x59, 0xBB, 0x08, 0xD8, 0x55, 0x18, 0x80, 0xC2, 0xBE, 0xFC, 0x4F, 0x87, 0xF2, 0x5F, 0x59, 0xAB, 0x58, 0x7A, 0x79, 0xC3, 0x27, 0xD7, 0x92, 0xD5, 0x4C, 0x97, 0x4A, 0x69, 0x26, 0x2F, 0xF8, 0xA7, 0x89, 0x38, 0x28, 0x9E, 0x9A, 0x87, 0xB6, 0x88, 0xB0, 0x83, 0xE0, 0x59, 0x5F, 0xE2, 0x18, 0xB6, 0xBB, 0x15, 0x05, 0x94, 0x1C, 0xE2, 0xE8, 0x1A, 0x5A, 0x64, 0xC5, 0xAA, 0xC6, 0x04, 0x17, 0x25, 0x69, 0x85, 0x34, 0x9E, 0xE4, 0x7A, 0x52, 0x42, 0x0A, 0x5F, 0x97, 0x47, 0x7B, 0x72, 0x36, 0xAC, 0x76, 0xBC, 0x70, 0xE8, 0x28, 0x87, 0x29, 0x28, 0x7E, 0xE3, 0xE3, 0x4A, 0x3D, 0xBC, 0x36, 0x83, 0xC0, 0xB7, 0xB1, 0x00, 0x29, 0xFC, 0x20, 0x34, 0x18, 0x53, 0x7E, 0x74, 0x66, 0xBA, 0x63, 0x85, 0xA8, 0xFF, 0x30, 0x1E, 0xE1, 0x27, 0x08, 0xF8, 0x2A, 0xAA, 0x1E, 0x38, 0x0F, 0xC7, 0xA8, 0x8F, 0x8F, 0x20, 0x5A, 0xB7, 0xE8, 0x8D, 0x7E, 0x95, 0x95, 0x2A, 0x55, 0xBA, 0x20, 0xD0, 0x9B, 0x79, 0xA4, 0x71, 0x41, 0xD6, 0x2B, 0xF6, 0xEB, 0x7D, 0xD3, 0x07, 0xB0, 0x8E, 0xCA, 0x13, 0xA5, 0xBC, 0x5F, 0x6B, 0x68, 0x58, 0x1C, 0x68, 0x65, 0xB2, 0x7B, 0xBC, 0xDD, 0xAB, 0x14, 0x2F, 0x4B, 0x2C, 0xBF, 0xF4, 0x88, 0xC8, 0xA2, 0x27, 0x05, 0xFA, 0xA9, 0x8A, 0x2B, 0x9E, 0xEA, 0x35, 0x30, 0xC7, 0x66, 0x62, 0x33, 0x5C, 0xC7, 0xEA, 0x3A, 0x00, 0x77, 0x77, 0x25, 0xEB, 0xCC, 0xCD, 0x2A, 0x46, 0x36, 0xB2, 0xD9, 0x12, 0x2F, 0xF3, 0xAB, 0x77, 0x12, 0x3C, 0xE0, 0x88, 0x3C, 0x19, 0x11, 0x11, 0x5E, 0x50, 0xC9, 0xE8, 0xA9, 0x41, 0x94, 0xE4, 0x8D, 0xD0, 0xD0, 0x9C, 0xFF, 0xB3, 0xAD, 0xCD, 0x2C, 0x1E, 0x92, 0x43, 0x09, 0x03, 0xD0, 0x7A, 0xDB, 0xF0, 0x05, 0x32, 0x03, 0x15, 0x75, 0xAA, 0x7F, 0x9E, 0x7B, 0x5A, 0x1F, 0x33, 0x62, 0xDE, 0xC9, 0x36, 0xD4, 0x04, 0x3C, 0x05, 0xF2, 0x47, 0x6C, 0x07, 0x57, 0x8B, 0xC9, 0xCB, 0xAF, 0x2A, 0xB4, 0xE3, 0x82, 0x72, 0x7A, 0xD4, 0x16, 0x86, 0xA9, 0x6B, 0x25, 0x48, 0x82, 0x0B, 0xB0, 0x3B, 0x32, 0xF1, 0x1B, 0x28, 0x11, 0xAD, 0x62, 0xF4, 0x89, 0xE9, 0x51, 0x63, 0x2A, 0xBA, 0x0D, 0x1D, 0xF8, 0x96, 0x80, 0xCC, 0x8A, 0x8B, 0x53, 0xB4, 0x81, 0xD9, 0x2A, 0x68, 0xD7, 0x0B, 0x4E, 0xA1, 0xC3, 0xA6, 0xA5, 0x61, 0xC0, 0x69, 0x28, 0x82, 0xB5, 0xCA, 0x8C, 0xC9, 0x42, 0xA8, 0xD4, 0x95, 0xAF, 0xCB, 0x06, 0xDE, 0x89, 0x49, 0x8F, 0xB9, 0x35, 0xB7, 0x75, 0x90, 0x8F, 0xE7, 0xA0, 0x3E, 0x32, 0x4D, 0x54, 0xCC, 0x19, 0xD4, 0xE1, 0xAA, 0xBD, 0x35, 0x93, 0xB3, 0x8B, 0x19, 0xEE, 0x13, 0x88, 0xFE, 0x49, 0x2B, 0x43, 0x12, 0x7E, 0x5A, 0x50, 0x42, 0x53, 0x78, 0x6A, 0x0D, 0x69, 0xAD, 0x32, 0x60, 0x1C, 0x28, 0xE2, 0xC8, 0x85, 0x04, 0xA5, 0xBA, 0x59, 0x97, 0x06, 0x02, 0x3A, 0x61, 0x36, 0x3E, 0x17, 0xC6, 0xB9, 0xBB, 0x59, 0xBD, 0xC6, 0x97, 0x45, 0x2C, 0xD0, 0x59, 0x45, 0x19, 0x83, 0xD7, 0x38, 0xCA, 0x3F, 0xD0, 0x34, 0xE3, 0xF5, 0x98, 0x88, 0x54, 0xCA, 0x05, 0x03, 0x1D, 0xB0, 0x96, 0x11, 0x49, 0x89, 0x88, 0x19, 0x7C, 0x6B, 0x30, 0xD2, 0x58, 0xDF, 0xE2, 0x62, 0x65, 0x54, 0x1C, 0x89, 0xA4, 0xB3, 0x1D, 0x68, 0x64, 0xE9, 0x38, 0x9B, 0x03, 0xCB, 0x74, 0xF7, 0xEC, 0x43, 0x23, 0xFB, 0x94, 0x21, 0xA4, 0xB9, 0x79, 0x0A, 0x26, 0xD1, 0x7B, 0x03, 0x98, 0xA2, 0x67, 0x67, 0x35, 0x09, 0x09, 0xF8, 0x4D, 0x57, 0xB6, 0x69, 0x4D, 0xF8, 0x30, 0x66, 0x4C, 0xA8, 0xB3, 0xC3, 0xC0, 0x3E, 0xD2, 0xAE, 0x67, 0xB8, 0x90, 0x06, 0x86, 0x8A, 0x68, 0x52, 0x7C, 0xCD, 0x66, 0x64, 0x59, 0xAB, 0x7F, 0x05, 0x66, 0x71, 0x00, 0x0C, 0x61, 0x64, 0xD3, 0xA7, 0xF2, 0x66, 0xA1, 0x4D, 0x97, 0xCB, 0xD7, 0x00, 0x4D, 0x6C, 0x92, 0xCA, 0xCA, 0x77, 0x0B, 0x84, 0x4A, 0x4F, 0xA9, 0xB1, 0x82, 0xE7, 0xB1, 0x8C, 0xA8, 0x85, 0x08, 0x2A, 0xC5, 0x64, 0x6F, 0xCB, 0x4A, 0x14, 0xE1, 0x68, 0x5F, 0xEB, 0x0C, 0x9C, 0xE3, 0x37, 0x2A, 0xB9, 0x53, 0x65, 0xC0, 0x4F, 0xD8, 0x30, 0x84, 0xF8, 0x0A, 0x23, 0xFF, 0x10, 0xA0, 0x5B, 0xF1, 0x5F, 0x7F, 0xA5, 0xAC, 0xC6, 0xC0, 0xCB, 0x46, 0x2C, 0x33, 0xCA, 0x52, 0x4F, 0xA6, 0xB8, 0xBB, 0x35, 0x90, 0x43, 0xBA, 0x68, 0x60, 0x9E, 0xAA, 0x25, 0x36, 0xE8, 0x1D, 0x08, 0x46, 0x3B, 0x19, 0x65, 0x3B, 0x54, 0x35, 0xBA, 0x94, 0x6C, 0x9A, 0xDD, 0xEB, 0x20, 0x2B, 0x04, 0xB0, 0x31, 0xCC, 0x96, 0x0D, 0xCC, 0x12, 0xE4, 0x51, 0x8D, 0x42, 0x8B, 0x32, 0xB2, 0x57, 0xA4, 0xFC, 0x73, 0x13, 0xD3, 0xA7, 0x98, 0x0D, 0x80, 0x08, 0x2E, 0x93, 0x4F, 0x9D, 0x95, 0xC3, 0x2B, 0x0A, 0x01, 0x91, 0xA2, 0x36, 0x04, 0x38, 0x4D, 0xD9, 0xE0, 0x79, 0xBB, 0xBA, 0xA2, 0x66, 0xD1, 0x4C, 0x3F, 0x75, 0x6B, 0x9F, 0x21, 0x33, 0x10, 0x74, 0x33, 0xA4, 0xE8, 0x3F, 0xA7, 0x18, 0x72, 0x82, 0xA8, 0x09, 0x20, 0x3A, 0x4F, 0xAF, 0x84, 0x18, 0x51, 0x83, 0x3D, 0x12, 0x1A, 0xC3, 0x83, 0x84, 0x3A, 0x5E, 0x55, 0xBC, 0x23, 0x81, 0x42, 0x5E, 0x16, 0xC7, 0xDB, 0x4C, 0xC9, 0xAB, 0x5C, 0x1B, 0x0D, 0x91, 0xA4, 0x7E, 0x2B, 0x8D, 0xE0, 0xE5, 0x82, 0xC8, 0x6B, 0x6B, 0x0D, 0x90, 0x7B, 0xB3, 0x60, 0xB9, 0x7F, 0x40, 0xAB, 0x5D, 0x03, 0x8F, 0x6B, 0x75, 0xC8, 0x14, 0xB2, 0x7D, 0x9B, 0x96, 0x8D, 0x41, 0x98, 0x32, 0xBC, 0x8C, 0x2B, 0xEE, 0x60, 0x5E, 0xF6, 0xE5, 0x05, 0x9D, 0x33, 0x10, 0x0D, 0x90, 0x48, 0x5D, 0x37, 0x84, 0x50, 0x01, 0x42, 0x21, 0x73, 0x6C, 0x07, 0x40, 0x7C, 0xAC, 0x26, 0x04, 0x08, 0xAA, 0x64, 0x92, 0x66, 0x19, 0x78, 0x8B, 0x86, 0x01, 0xC2, 0xA7, 0x52, 0xD1, 0xA6, 0xCB, 0xF8, 0x20, 0xD7, 0xC7, 0xA0, 0x47, 0x16, 0x20, 0x32, 0x25, 0xB3, 0x89, 0x5B, 0x93, 0x42, 0xD1, 0x47, 0xA8, 0x18, 0x5C, 0xFC, 0x1B, 0xB6, 0x5B, 0xA0, 0x6B, 0x41, 0x42, 0x33, 0x99, 0x03, 0xC0, 0xAC, 0x46, 0x51, 0x38, 0x5B, 0x45, 0xD9, 0x8A, 0x8B, 0x19, 0xD2, 0x8C, 0xD6, 0xBA, 0xB0, 0x88, 0x78, 0x7F, 0x7E, 0xE1, 0xB1, 0x24, 0x61, 0x76, 0x6B, 0x43, 0xCB, 0xCC, 0xB9, 0x64, 0x34, 0x42, 0x7D, 0x93, 0xC0, 0x65, 0x55, 0x06, 0x88, 0xF6, 0x94, 0x8E, 0xD1, 0xB5, 0x47, 0x5A, 0x42, 0x5F, 0x1B, 0x85, 0x20, 0x9D, 0x06, 0x1C, 0x08, 0xB5, 0x6C, 0x1C, 0xC0, 0x69, 0xF6, 0xC0, 0xA7, 0xC6, 0xF2, 0x93, 0x58, 0xCA, 0xB9, 0x11, 0x08, 0x77, 0x32, 0xA6, 0x49, 0xD2, 0x7C, 0x9B, 0x98, 0xF9, 0xA4, 0x88, 0x79, 0x38, 0x7D, 0x9B, 0x00, 0xC2, 0x59, 0x59, 0xA7, 0x16, 0x54, 0xD6, 0xF6, 0xA9, 0x46, 0x16, 0x45, 0x13, 0xE4, 0x7A, 0x75, 0xD0, 0x05, 0x98, 0x6C, 0x23, 0x63, 0xC0, 0x9F, 0x6B, 0x53, 0x7E, 0xCA, 0x78, 0xB9, 0x30, 0x3A, 0x5F, 0xA4, 0x57, 0x60, 0x8A, 0x58, 0x6A, 0x65, 0x3A, 0x34, 0x7D, 0xB0, 0x4D, 0xFC, 0xC1, 0x91, 0x75, 0xB3, 0xA3, 0x01, 0x17, 0x25, 0x36, 0x06, 0x2A, 0x65, 0x8A, 0x95, 0x27, 0x75, 0x70, 0xC8, 0x85, 0x2C, 0xA8, 0x97, 0x3F, 0x4A, 0xE1, 0x23, 0xA3, 0x34, 0x04, 0x7D, 0xD7, 0x11, 0xC8, 0x92, 0x7A, 0x63, 0x4A, 0x03, 0x38, 0x8A, 0x52, 0x7B, 0x03, 0x4B, 0xF7, 0xA8, 0x17, 0x0F, 0xA7, 0x02, 0xC1, 0xF7, 0xC2, 0x3E, 0xC3, 0x2D, 0x18, 0xA2, 0x37, 0x48, 0x90, 0xBE, 0x9C, 0x78, 0x7A, 0x94, 0x09, 0xC8, 0x2D, 0x19, 0x2C, 0x4B, 0xB7, 0x05, 0xA2, 0xF9, 0x96, 0xCE, 0x40, 0x5D, 0xA0, 0xB7, 0x1F, 0x67, 0xC6, 0xCE, 0xC0, 0xD3, 0x56, 0x86, 0xD5, 0x13, 0x42, 0x34, 0x32, 0xE5, 0x12, 0xAC, 0x40, 0x44, 0x55, 0x7E, 0x86, 0x8A, 0x62, 0x48, 0x00, 0x10, 0x9A, 0x33, 0x55, 0xF9, 0x8F, 0x15, 0x14, 0x44, 0xE2, 0x85, 0x2E, 0x27, 0xEA, 0x6E, 0xDB, 0x19, 0x92, 0xCA, 0xD3, 0x97, 0x3C, 0x3A, 0x6F, 0xF7, 0x9A, 0x5A, 0x04, 0x9A, 0x25, 0x9E, 0xB5, 0x41, 0x5A, 0xA2, 0xA2, 0x62, 0x45, 0x6E, 0xC9, 0x49, 0x5B, 0xBB, 0x52, 0x00, 0xD8, 0xD3, 0x16, 0x3A, 0x5B, 0x10, 0x22, 0x62, 0x92, 0xEC, 0xA0, 0x10, 0x21, 0x38, 0x9D, 0xA3, 0x78, 0x81, 0xE2, 0x76, 0x30, 0x65, 0x50, 0xC6, 0xEF, 0xB6, 0x44, 0x0E, 0xC5, 0x1A, 0x2F, 0x73, 0x48, 0x34, 0x9B, 0x85, 0x1C, 0xD4, 0xAA, 0x01, 0x75, 0xA0, 0x55, 0x02, 0x13, 0xC4, 0x79, 0x1D, 0x91, 0x01, 0x12, 0x20, 0x82, 0x4B, 0x2B, 0x61, 0x65, 0x08, 0x13, 0xAD, 0xFD, 0x2C, 0xB1, 0x05, 0x38, 0xBF, 0xAB, 0x0A, 0x72, 0x6F, 0x81, 0x12, 0x9E, 0xD2, 0xC0, 0xF0, 0x6A, 0x16, 0xB7, 0x01, 0x09, 0x0B, 0xF0, 0x48, 0xC5, 0xA4, 0x01, 0x26, 0xD5, 0x72, 0xFC, 0xD4, 0x7A, 0xA1, 0x21, 0x8F, 0xB0, 0x15, 0x47, 0xD1, 0x50, 0x79, 0x2D, 0x23, 0x16, 0xCB, 0x32, 0x0D, 0x51, 0x44, 0xBA, 0x35, 0x08, 0xA1, 0xEB, 0xBB, 0x5A, 0xC1, 0xC2, 0x29, 0x13, 0xE8, 0x29, 0x5F, 0xAB, 0x59, 0xBF, 0x58, 0x37, 0xA7, 0x78, 0xCF, 0x28, 0x22, 0x7E, 0x07, 0xE1, 0x03, 0x2D, 0xAB, 0x7D, 0x0E, 0x09, 0xA1, 0x5F, 0x13, 0x41, 0x48, 0xC1, 0x20, 0x09, 0xDA, 0x53, 0x6B, 0x22, 0xCC, 0x62, 0x47, 0x4E, 0x69, 0xCC, 0x15, 0x54, 0xC0, 0x81, 0x4D, 0x6C, 0xA0, 0xB7, 0x22, 0x59, 0x43, 0x83, 0xA9, 0xD0, 0xA2, 0xC7, 0x7F, 0xD3, 0x65, 0xA5, 0x54, 0x42, 0x95, 0xFB, 0xB9, 0x73, 0xF9, 0x1E, 0xA5, 0x64, 0x90, 0xD6, 0xCA, 0x68, 0x76, 0x49, 0x7B, 0x98, 0xB3, 0xCB, 0x12, 0x41, 0x7C, 0x25, 0x7B, 0x6D, 0x0F, 0x71, 0x83, 0xDB, 0xB6, 0x9E, 0x33, 0x07, 0x5B, 0xEB, 0x01, 0x17, 0xB6, 0x91, 0x4C, 0x69, 0xBA, 0x38, 0x34, 0x94, 0x22, 0xF2, 0xF4, 0x33, 0x64, 0x82, 0x2A, 0x25, 0x70, 0x95, 0x2D, 0xD5, 0x07, 0x7B, 0x90, 0x75, 0x5F, 0x15, 0x74, 0x11, 0x5B, 0x8E, 0x22, 0x14, 0x27, 0x58, 0x59, 0x61, 0x91, 0x3A, 0x9B, 0xFA, 0x05, 0x02, 0xB5, 0xD7, 0x9A, 0xB7, 0x81, 0x17, 0x44, 0xE6, 0x56, 0x3C, 0x5B, 0x62, 0xC5, 0xCC, 0x4E, 0x93, 0x23, 0x9A, 0x0A, 0x8C, 0xC6, 0x0F, 0xE8, 0x48, 0xF8, 0x4A, 0x95, 0xF5, 0x90, 0x25, 0x99, 0xB5, 0x4A, 0x06, 0x62, 0x93, 0xA2, 0x02, 0x1D, 0xA1, 0x96, 0x76, 0x6C, 0x17, 0xC7, 0xE8, 0x63, 0xAF, 0x79, 0x0C, 0x27, 0x0B, 0x21, 0x6A, 0x25, 0x13, 0x8D, 0xDA, 0x0C, 0x81, 0x26, 0xE0, 0x93, 0x77, 0x87, 0x98, 0x59, 0xDB, 0x35, 0x8F, 0x9B, 0x82, 0xB7, 0xC8, 0xA6, 0x79, 0x2A, 0xCE, 0xE9, 0x2A, 0x4C, 0xBD, 0xE3, 0xCE, 0xDD, 0x45, 0x00, 0xAC, 0xBC, 0x55, 0x5C, 0x28, 0x8E, 0xFF, 0x97, 0x95, 0x26, 0x5B, 0x90, 0x05, 0x35, 0x1C, 0x52, 0xE2, 0x65, 0x35, 0x54, 0xAB, 0xAA, 0xF8, 0x72, 0xDF, 0x95, 0xCA, 0x7F, 0x79, 0x59, 0x03, 0xF0, 0xB0, 0xA1, 0x82, 0xB1, 0x8A, 0xEB, 0x04, 0x75, 0xB2, 0x9F, 0x6E, 0x3A, 0xBF, 0x4C, 0x22, 0x50, 0xFE, 0x7B, 0x84, 0x2A, 0x73, 0x65, 0x50, 0x16, 0xA8, 0xFC, 0x72, 0x9F, 0x39, 0x05, 0x07, 0xAC, 0xA9, 0x36, 0x82, 0x5A, 0x98, 0xB3, 0xA3, 0x2E, 0x6B, 0x25, 0x54, 0xCE, 0x95, 0x28, 0x94, 0x1A, 0x3B, 0xB8, 0xC9, 0x09, 0x96, 0x00, 0x8D, 0x74, 0xFB, 0xCD, 0x02, 0x0A, 0x02, 0xE7, 0x06, 0xA6, 0xDE, 0x7B, 0x02, 0xAF, 0x40, 0x4C, 0x10, 0xDB, 0x00, 0xFA, 0xEC, 0x02, 0xD3, 0xEA, 0xA6, 0xD9, 0x56, 0x1A, 0x15, 0x65, 0xA7, 0xB0, 0x5C, 0x63, 0x66, 0xD0, 0x9D, 0xA7, 0xA5, 0x37, 0xF2, 0x0C, 0x7B, 0x28, 0x59, 0xA8, 0x3E, 0x02, 0x9E, 0x13, 0xA9, 0xBD, 0x28, 0x91, 0x57, 0xC5, 0xB7, 0x4C, 0x84, 0xEA, 0xA3, 0x07, 0x75, 0x3D, 0x43, 0x12, 0x02, 0xA3, 0xD9, 0xB6, 0x16, 0x22, 0x18, 0xBE, 0xC5, 0x34, 0x69, 0x45, 0xBF, 0xEF, 0x55, 0xB6, 0x24, 0xC5, 0xC6, 0xE3, 0x73, 0x35, 0x9B, 0xB1, 0xC4, 0x79, 0x95, 0x2B, 0xBA, 0xBA, 0x4D, 0x65, 0x55, 0xC2, 0x76, 0x57, 0x3E, 0x51, 0x52, 0xB5, 0x53, 0x90, 0x19, 0x99, 0xF6, 0x94, 0x02, 0xD1, 0x50, 0xBE, 0xF7, 0x9D, 0x74, 0xFB, 0x29, 0x53, 0x01, 0x8F, 0xF4, 0x86, 0x66, 0x74, 0x6A, 0xCE, 0x60, 0x78, 0x14, 0xA1, 0xFA, 0x33, 0x19, 0x57, 0x20, 0xF8, 0x38, 0x78, 0xD3, 0xB5, 0x75, 0xC7, 0x25, 0x74, 0x4A, 0x72, 0x07, 0x0D, 0xD0, 0x44, 0x01, 0x80, 0x42, 0xDA, 0x25, 0x71, 0x4D, 0x17, 0x30, 0x90, 0x32, 0x3A, 0x51, 0xE6, 0xC0, 0x63, 0xD2, 0x03, 0x88, 0x13, 0x80, 0x91, 0x27, 0x61, 0xFC, 0x34, 0x10, 0x83, 0x90, 0x95, 0xF2, 0x6C, 0x0E, 0x68, 0x7A, 0x00, 0x70, 0x54, 0x95, 0xE1, 0x71, 0xB5, 0x71, 0x51, 0xAC, 0xE0, 0x49, 0x8E, 0x30, 0xF1, 0x4C, 0xA9, 0xB0, 0x2F, 0x6E, 0x40, 0x83, 0x18, 0x54, 0xC2, 0xE0, 0xAB, 0x1E, 0xCD, 0x0C, 0x21, 0xD8, 0xE4, 0xC7, 0xE6, 0x69, 0xCD, 0x72, 0x82, 0x30, 0xB9, 0xD1, 0x1F, 0x72, 0xC2, 0x66, 0xE3, 0x44, 0x66, 0xF9, 0xC0, 0x15, 0x9E, 0xF4, 0x24, 0xF8, 0xF3, 0x1D, 0x95, 0xA5, 0x7B, 0xA0, 0xE2, 0x10, 0x54, 0x3C, 0x10, 0xC6, 0x50, 0x3F, 0xB5, 0xC6, 0x3E, 0xD2, 0x3A, 0xA3, 0x6C, 0xD6, 0xA6, 0xF3, 0x78, 0x26, 0x1B, 0x0B, 0x1E, 0x79, 0x50, 0x9D, 0x8B, 0xEB, 0x36, 0xAA, 0x26, 0x3D, 0xC9, 0x15, 0x45, 0xE5, 0x33, 0x69, 0xDF, 0x26, 0x83, 0x7F, 0x39, 0x4C, 0x56, 0x77, 0x7C, 0x95, 0xB6, 0x48, 0xBD, 0x1A, 0x72, 0x92, 0x1A, 0xBF, 0x49, 0x56, 0x3F, 0x99, 0xCB, 0x9D, 0x98, 0xEA, 0xB5, 0xC6, 0x66, 0x66, 0xF6, 0xB1, 0x6F, 0x74, 0x02, 0x24, 0x81, 0xFA, 0x21, 0x4E, 0x61, 0x76, 0x98, 0xD3, 0xBB, 0xD1, 0x3C, 0xB3, 0x08, 0x71, 0x3F, 0xDC, 0xC7, 0xCF, 0xD3, 0x97, 0xB9, 0xCA, 0x39, 0xAF, 0xF4, 0xC7, 0x44, 0xD5, 0x71, 0x5D, 0x58, 0x96, 0x6F, 0x2C, 0xF9, 0x70, 0x70, 0x15, 0xC8, 0xF3, 0x54, 0x3E, 0xD2, 0x86, 0xA3, 0xD8, 0xD5, 0xCB, 0xF6, 0x4A, 0xCE, 0xDF, 0xC0, 0x29, 0x71, 0xA9, 0x10, 0x72, 0xC6, 0x9D, 0x2E, 0xF4, 0x98, 0x29, 0xF1, 0x03, 0x7F, 0x05, 0x0C, 0x5B, 0x92, 0x22, 0x98, 0x56, 0xCB, 0x12, 0xB4, 0x56, 0xCC, 0x09, 0x52, 0x82, 0xA6, 0x26, 0x87, 0xEA, 0x38, 0xC9, 0x77, 0x8A, 0xEA, 0x49, 0x1D, 0xFF, 0x06, 0x97, 0x11, 0xFB, 0xBE, 0x05, 0xE8, 0xCD, 0x9B, 0xF4, 0x4A, 0x8E, 0x71, 0x26, 0x19, 0x57, 0x3E, 0x12, 0xEA, 0xA7, 0xB2, 0x38, 0x29, 0xDC, 0x67, 0x26, 0xBF, 0xE3, 0x3D, 0xA1, 0x36, 0xB8, 0x1E, 0x15, 0x32, 0x51, 0x50, 0x8F, 0x62, 0x85, 0xBA, 0x15, 0xB2, 0xC1, 0x23, 0x76, 0x77, 0xFE, 0x5B, 0x14, 0xB4, 0xE3, 0x3F, 0x98, 0xC3, 0x26, 0xBC, 0x58, 0xB9, 0xD8, 0xE0, 0x75, 0xA2, 0x5B, 0x94, 0xC8, 0xA2, 0x32, 0x33, 0x02, 0x9D, 0xCC, 0x78, 0x6B, 0x13, 0x5C, 0x56, 0x16, 0x4B, 0xA3, 0xD1, 0x60, 0xCB, 0xCE, 0xA8, 0x54, 0xB7, 0x97, 0x1F, 0x9C, 0xD7, 0x3A, 0x38, 0x3A, 0xAC, 0x05, 0x0A, 0x30, 0x2A, 0xD8, 0x3B, 0x3E, 0x3A, 0xB9, 0x02, 0x46, 0xAD, 0x16, 0x0A, 0x32, 0x1D, 0x33, 0x0A, 0xCD, 0xEC, 0x7C, 0xA6, 0x64, 0x3D, 0x7E, 0xC0, 0x1F, 0x91, 0x69, 0x1F, 0x16, 0x32, 0x5B, 0xDF, 0x39, 0x69, 0x50, 0xB8, 0x8D, 0xAF, 0xE3, 0x69, 0xC6, 0x54, 0xB8, 0x52, 0x05, 0x5C, 0x97, 0x03, 0x62, 0xC6, 0x13, 0x80, 0x46, 0x07, 0x57, 0xC6, 0x58, 0x90, 0xF4, 0xE5, 0x92, 0x22, 0xE4, 0xA4, 0x06, 0x0B, 0x26, 0xC0, 0xEB, 0xC1, 0x01, 0x97, 0x59, 0x0D, 0xE3, 0xC8, 0xF0, 0x95, 0x5D, 0x65, 0x4B, 0x37, 0x1C, 0xCB, 0x90, 0xAC, 0xA3, 0x71, 0xB2, 0x94, 0x47, 0x6C, 0x16, 0xA4, 0x59, 0x6A, 0x1D, 0xE8, 0x30, 0x9E, 0x2A, 0x36, 0x12, 0xC6, 0x9B, 0x71, 0x25, 0x31, 0x05, 0x01, 0xE0, 0xC0, 0x49, 0xB8, 0x74, 0x40, 0xD9, 0xA6, 0xD0, 0xEC, 0xB9, 0x99, 0xC9, 0xA0, 0x94, 0x2A, 0xA3, 0x40, 0xF6, 0x03, 0x65, 0xEA, 0xFD, 0x46, 0x5F, 0xC6, 0x4A, 0x0C, 0x5F, 0x8F, 0x3F, 0x90, 0x03, 0x48, 0x94, 0x15, 0x89, 0x9D, 0x59, 0xA5, 0x43, 0xD8, 0x20, 0x8C, 0x54, 0xA3, 0x16, 0x65, 0x29, 0xB5, 0x39, 0x22, 0xDE, 0xE4, 0xAB, 0xA0, 0x00, 0x38, 0x95, 0x81, 0x71, 0x7D, 0x36, 0xF5, 0x6F, 0x39, 0xAF, 0x73, 0x00, 0xB3, 0x1D, 0x83, 0x1A, 0x4D, 0x8C, 0x97, 0x61, 0x28, 0xE0, 0x9D, 0xED, 0xE7, 0x1A, 0x5A, 0x86, 0x26, 0xED, 0x79, 0xD4, 0x51, 0x14, 0x08, 0x00, 0xE0, 0x3B, 0x59, 0xB9, 0x56, 0xF8, 0x21, 0x0E, 0x55, 0x60, 0x67, 0x40, 0x7D, 0x13, 0xDC, 0x90, 0xFA, 0x9E, 0x8B, 0x87, 0x2B, 0xFB, 0x8F, }, .pk_len = 1184, .pk = { 0xA0, 0xB7, 0x1F, 0x67, 0xC6, 0xCE, 0xC0, 0xD3, 0x56, 0x86, 0xD5, 0x13, 0x42, 0x34, 0x32, 0xE5, 0x12, 0xAC, 0x40, 0x44, 0x55, 0x7E, 0x86, 0x8A, 0x62, 0x48, 0x00, 0x10, 0x9A, 0x33, 0x55, 0xF9, 0x8F, 0x15, 0x14, 0x44, 0xE2, 0x85, 0x2E, 0x27, 0xEA, 0x6E, 0xDB, 0x19, 0x92, 0xCA, 0xD3, 0x97, 0x3C, 0x3A, 0x6F, 0xF7, 0x9A, 0x5A, 0x04, 0x9A, 0x25, 0x9E, 0xB5, 0x41, 0x5A, 0xA2, 0xA2, 0x62, 0x45, 0x6E, 0xC9, 0x49, 0x5B, 0xBB, 0x52, 0x00, 0xD8, 0xD3, 0x16, 0x3A, 0x5B, 0x10, 0x22, 0x62, 0x92, 0xEC, 0xA0, 0x10, 0x21, 0x38, 0x9D, 0xA3, 0x78, 0x81, 0xE2, 0x76, 0x30, 0x65, 0x50, 0xC6, 0xEF, 0xB6, 0x44, 0x0E, 0xC5, 0x1A, 0x2F, 0x73, 0x48, 0x34, 0x9B, 0x85, 0x1C, 0xD4, 0xAA, 0x01, 0x75, 0xA0, 0x55, 0x02, 0x13, 0xC4, 0x79, 0x1D, 0x91, 0x01, 0x12, 0x20, 0x82, 0x4B, 0x2B, 0x61, 0x65, 0x08, 0x13, 0xAD, 0xFD, 0x2C, 0xB1, 0x05, 0x38, 0xBF, 0xAB, 0x0A, 0x72, 0x6F, 0x81, 0x12, 0x9E, 0xD2, 0xC0, 0xF0, 0x6A, 0x16, 0xB7, 0x01, 0x09, 0x0B, 0xF0, 0x48, 0xC5, 0xA4, 0x01, 0x26, 0xD5, 0x72, 0xFC, 0xD4, 0x7A, 0xA1, 0x21, 0x8F, 0xB0, 0x15, 0x47, 0xD1, 0x50, 0x79, 0x2D, 0x23, 0x16, 0xCB, 0x32, 0x0D, 0x51, 0x44, 0xBA, 0x35, 0x08, 0xA1, 0xEB, 0xBB, 0x5A, 0xC1, 0xC2, 0x29, 0x13, 0xE8, 0x29, 0x5F, 0xAB, 0x59, 0xBF, 0x58, 0x37, 0xA7, 0x78, 0xCF, 0x28, 0x22, 0x7E, 0x07, 0xE1, 0x03, 0x2D, 0xAB, 0x7D, 0x0E, 0x09, 0xA1, 0x5F, 0x13, 0x41, 0x48, 0xC1, 0x20, 0x09, 0xDA, 0x53, 0x6B, 0x22, 0xCC, 0x62, 0x47, 0x4E, 0x69, 0xCC, 0x15, 0x54, 0xC0, 0x81, 0x4D, 0x6C, 0xA0, 0xB7, 0x22, 0x59, 0x43, 0x83, 0xA9, 0xD0, 0xA2, 0xC7, 0x7F, 0xD3, 0x65, 0xA5, 0x54, 0x42, 0x95, 0xFB, 0xB9, 0x73, 0xF9, 0x1E, 0xA5, 0x64, 0x90, 0xD6, 0xCA, 0x68, 0x76, 0x49, 0x7B, 0x98, 0xB3, 0xCB, 0x12, 0x41, 0x7C, 0x25, 0x7B, 0x6D, 0x0F, 0x71, 0x83, 0xDB, 0xB6, 0x9E, 0x33, 0x07, 0x5B, 0xEB, 0x01, 0x17, 0xB6, 0x91, 0x4C, 0x69, 0xBA, 0x38, 0x34, 0x94, 0x22, 0xF2, 0xF4, 0x33, 0x64, 0x82, 0x2A, 0x25, 0x70, 0x95, 0x2D, 0xD5, 0x07, 0x7B, 0x90, 0x75, 0x5F, 0x15, 0x74, 0x11, 0x5B, 0x8E, 0x22, 0x14, 0x27, 0x58, 0x59, 0x61, 0x91, 0x3A, 0x9B, 0xFA, 0x05, 0x02, 0xB5, 0xD7, 0x9A, 0xB7, 0x81, 0x17, 0x44, 0xE6, 0x56, 0x3C, 0x5B, 0x62, 0xC5, 0xCC, 0x4E, 0x93, 0x23, 0x9A, 0x0A, 0x8C, 0xC6, 0x0F, 0xE8, 0x48, 0xF8, 0x4A, 0x95, 0xF5, 0x90, 0x25, 0x99, 0xB5, 0x4A, 0x06, 0x62, 0x93, 0xA2, 0x02, 0x1D, 0xA1, 0x96, 0x76, 0x6C, 0x17, 0xC7, 0xE8, 0x63, 0xAF, 0x79, 0x0C, 0x27, 0x0B, 0x21, 0x6A, 0x25, 0x13, 0x8D, 0xDA, 0x0C, 0x81, 0x26, 0xE0, 0x93, 0x77, 0x87, 0x98, 0x59, 0xDB, 0x35, 0x8F, 0x9B, 0x82, 0xB7, 0xC8, 0xA6, 0x79, 0x2A, 0xCE, 0xE9, 0x2A, 0x4C, 0xBD, 0xE3, 0xCE, 0xDD, 0x45, 0x00, 0xAC, 0xBC, 0x55, 0x5C, 0x28, 0x8E, 0xFF, 0x97, 0x95, 0x26, 0x5B, 0x90, 0x05, 0x35, 0x1C, 0x52, 0xE2, 0x65, 0x35, 0x54, 0xAB, 0xAA, 0xF8, 0x72, 0xDF, 0x95, 0xCA, 0x7F, 0x79, 0x59, 0x03, 0xF0, 0xB0, 0xA1, 0x82, 0xB1, 0x8A, 0xEB, 0x04, 0x75, 0xB2, 0x9F, 0x6E, 0x3A, 0xBF, 0x4C, 0x22, 0x50, 0xFE, 0x7B, 0x84, 0x2A, 0x73, 0x65, 0x50, 0x16, 0xA8, 0xFC, 0x72, 0x9F, 0x39, 0x05, 0x07, 0xAC, 0xA9, 0x36, 0x82, 0x5A, 0x98, 0xB3, 0xA3, 0x2E, 0x6B, 0x25, 0x54, 0xCE, 0x95, 0x28, 0x94, 0x1A, 0x3B, 0xB8, 0xC9, 0x09, 0x96, 0x00, 0x8D, 0x74, 0xFB, 0xCD, 0x02, 0x0A, 0x02, 0xE7, 0x06, 0xA6, 0xDE, 0x7B, 0x02, 0xAF, 0x40, 0x4C, 0x10, 0xDB, 0x00, 0xFA, 0xEC, 0x02, 0xD3, 0xEA, 0xA6, 0xD9, 0x56, 0x1A, 0x15, 0x65, 0xA7, 0xB0, 0x5C, 0x63, 0x66, 0xD0, 0x9D, 0xA7, 0xA5, 0x37, 0xF2, 0x0C, 0x7B, 0x28, 0x59, 0xA8, 0x3E, 0x02, 0x9E, 0x13, 0xA9, 0xBD, 0x28, 0x91, 0x57, 0xC5, 0xB7, 0x4C, 0x84, 0xEA, 0xA3, 0x07, 0x75, 0x3D, 0x43, 0x12, 0x02, 0xA3, 0xD9, 0xB6, 0x16, 0x22, 0x18, 0xBE, 0xC5, 0x34, 0x69, 0x45, 0xBF, 0xEF, 0x55, 0xB6, 0x24, 0xC5, 0xC6, 0xE3, 0x73, 0x35, 0x9B, 0xB1, 0xC4, 0x79, 0x95, 0x2B, 0xBA, 0xBA, 0x4D, 0x65, 0x55, 0xC2, 0x76, 0x57, 0x3E, 0x51, 0x52, 0xB5, 0x53, 0x90, 0x19, 0x99, 0xF6, 0x94, 0x02, 0xD1, 0x50, 0xBE, 0xF7, 0x9D, 0x74, 0xFB, 0x29, 0x53, 0x01, 0x8F, 0xF4, 0x86, 0x66, 0x74, 0x6A, 0xCE, 0x60, 0x78, 0x14, 0xA1, 0xFA, 0x33, 0x19, 0x57, 0x20, 0xF8, 0x38, 0x78, 0xD3, 0xB5, 0x75, 0xC7, 0x25, 0x74, 0x4A, 0x72, 0x07, 0x0D, 0xD0, 0x44, 0x01, 0x80, 0x42, 0xDA, 0x25, 0x71, 0x4D, 0x17, 0x30, 0x90, 0x32, 0x3A, 0x51, 0xE6, 0xC0, 0x63, 0xD2, 0x03, 0x88, 0x13, 0x80, 0x91, 0x27, 0x61, 0xFC, 0x34, 0x10, 0x83, 0x90, 0x95, 0xF2, 0x6C, 0x0E, 0x68, 0x7A, 0x00, 0x70, 0x54, 0x95, 0xE1, 0x71, 0xB5, 0x71, 0x51, 0xAC, 0xE0, 0x49, 0x8E, 0x30, 0xF1, 0x4C, 0xA9, 0xB0, 0x2F, 0x6E, 0x40, 0x83, 0x18, 0x54, 0xC2, 0xE0, 0xAB, 0x1E, 0xCD, 0x0C, 0x21, 0xD8, 0xE4, 0xC7, 0xE6, 0x69, 0xCD, 0x72, 0x82, 0x30, 0xB9, 0xD1, 0x1F, 0x72, 0xC2, 0x66, 0xE3, 0x44, 0x66, 0xF9, 0xC0, 0x15, 0x9E, 0xF4, 0x24, 0xF8, 0xF3, 0x1D, 0x95, 0xA5, 0x7B, 0xA0, 0xE2, 0x10, 0x54, 0x3C, 0x10, 0xC6, 0x50, 0x3F, 0xB5, 0xC6, 0x3E, 0xD2, 0x3A, 0xA3, 0x6C, 0xD6, 0xA6, 0xF3, 0x78, 0x26, 0x1B, 0x0B, 0x1E, 0x79, 0x50, 0x9D, 0x8B, 0xEB, 0x36, 0xAA, 0x26, 0x3D, 0xC9, 0x15, 0x45, 0xE5, 0x33, 0x69, 0xDF, 0x26, 0x83, 0x7F, 0x39, 0x4C, 0x56, 0x77, 0x7C, 0x95, 0xB6, 0x48, 0xBD, 0x1A, 0x72, 0x92, 0x1A, 0xBF, 0x49, 0x56, 0x3F, 0x99, 0xCB, 0x9D, 0x98, 0xEA, 0xB5, 0xC6, 0x66, 0x66, 0xF6, 0xB1, 0x6F, 0x74, 0x02, 0x24, 0x81, 0xFA, 0x21, 0x4E, 0x61, 0x76, 0x98, 0xD3, 0xBB, 0xD1, 0x3C, 0xB3, 0x08, 0x71, 0x3F, 0xDC, 0xC7, 0xCF, 0xD3, 0x97, 0xB9, 0xCA, 0x39, 0xAF, 0xF4, 0xC7, 0x44, 0xD5, 0x71, 0x5D, 0x58, 0x96, 0x6F, 0x2C, 0xF9, 0x70, 0x70, 0x15, 0xC8, 0xF3, 0x54, 0x3E, 0xD2, 0x86, 0xA3, 0xD8, 0xD5, 0xCB, 0xF6, 0x4A, 0xCE, 0xDF, 0xC0, 0x29, 0x71, 0xA9, 0x10, 0x72, 0xC6, 0x9D, 0x2E, 0xF4, 0x98, 0x29, 0xF1, 0x03, 0x7F, 0x05, 0x0C, 0x5B, 0x92, 0x22, 0x98, 0x56, 0xCB, 0x12, 0xB4, 0x56, 0xCC, 0x09, 0x52, 0x82, 0xA6, 0x26, 0x87, 0xEA, 0x38, 0xC9, 0x77, 0x8A, 0xEA, 0x49, 0x1D, 0xFF, 0x06, 0x97, 0x11, 0xFB, 0xBE, 0x05, 0xE8, 0xCD, 0x9B, 0xF4, 0x4A, 0x8E, 0x71, 0x26, 0x19, 0x57, 0x3E, 0x12, 0xEA, 0xA7, 0xB2, 0x38, 0x29, 0xDC, 0x67, 0x26, 0xBF, 0xE3, 0x3D, 0xA1, 0x36, 0xB8, 0x1E, 0x15, 0x32, 0x51, 0x50, 0x8F, 0x62, 0x85, 0xBA, 0x15, 0xB2, 0xC1, 0x23, 0x76, 0x77, 0xFE, 0x5B, 0x14, 0xB4, 0xE3, 0x3F, 0x98, 0xC3, 0x26, 0xBC, 0x58, 0xB9, 0xD8, 0xE0, 0x75, 0xA2, 0x5B, 0x94, 0xC8, 0xA2, 0x32, 0x33, 0x02, 0x9D, 0xCC, 0x78, 0x6B, 0x13, 0x5C, 0x56, 0x16, 0x4B, 0xA3, 0xD1, 0x60, 0xCB, 0xCE, 0xA8, 0x54, 0xB7, 0x97, 0x1F, 0x9C, 0xD7, 0x3A, 0x38, 0x3A, 0xAC, 0x05, 0x0A, 0x30, 0x2A, 0xD8, 0x3B, 0x3E, 0x3A, 0xB9, 0x02, 0x46, 0xAD, 0x16, 0x0A, 0x32, 0x1D, 0x33, 0x0A, 0xCD, 0xEC, 0x7C, 0xA6, 0x64, 0x3D, 0x7E, 0xC0, 0x1F, 0x91, 0x69, 0x1F, 0x16, 0x32, 0x5B, 0xDF, 0x39, 0x69, 0x50, 0xB8, 0x8D, 0xAF, 0xE3, 0x69, 0xC6, 0x54, 0xB8, 0x52, 0x05, 0x5C, 0x97, 0x03, 0x62, 0xC6, 0x13, 0x80, 0x46, 0x07, 0x57, 0xC6, 0x58, 0x90, 0xF4, 0xE5, 0x92, 0x22, 0xE4, 0xA4, 0x06, 0x0B, 0x26, 0xC0, 0xEB, 0xC1, 0x01, 0x97, 0x59, 0x0D, 0xE3, 0xC8, 0xF0, 0x95, 0x5D, 0x65, 0x4B, 0x37, 0x1C, 0xCB, 0x90, 0xAC, 0xA3, 0x71, 0xB2, 0x94, 0x47, 0x6C, 0x16, 0xA4, 0x59, 0x6A, 0x1D, 0xE8, 0x30, 0x9E, 0x2A, 0x36, 0x12, 0xC6, 0x9B, 0x71, 0x25, 0x31, 0x05, 0x01, 0xE0, 0xC0, 0x49, 0xB8, 0x74, 0x40, 0xD9, 0xA6, 0xD0, 0xEC, 0xB9, 0x99, 0xC9, 0xA0, 0x94, 0x2A, 0xA3, 0x40, 0xF6, 0x03, 0x65, 0xEA, 0xFD, 0x46, 0x5F, 0xC6, 0x4A, 0x0C, 0x5F, 0x8F, 0x3F, 0x90, 0x03, 0x48, 0x94, 0x15, 0x89, 0x9D, 0x59, 0xA5, 0x43, 0xD8, 0x20, 0x8C, 0x54, 0xA3, 0x16, 0x65, 0x29, 0xB5, 0x39, 0x22, }, .pkcs8_len = 0, .spki_len = 0, .secret_len = 32, .secret = { 0xed, 0x20, 0x14, 0x0c, 0x05, 0xd7, 0x8b, 0x15, 0xf2, 0xe4, 0x12, 0x67, 0x1a, 0x84, 0x15, 0x42, 0x17, 0xfd, 0x77, 0x61, 0x9a, 0x2c, 0x52, 0x2d, 0x3c, 0x3c, 0xb6, 0x88, 0xcb, 0x34, 0xc6, 0x8b, }, .cipher_len = 1088, .cipher = { 0xea, 0xdd, 0x5a, 0xda, 0x14, 0xda, 0x57, 0xf0, 0xae, 0xf3, 0x50, 0x5f, 0x1c, 0xaa, 0x64, 0x85, 0xd4, 0x23, 0x8d, 0x99, 0x9a, 0x3e, 0xf4, 0xb0, 0xa5, 0x9a, 0x1c, 0xdb, 0xe0, 0xa2, 0x7e, 0x47, 0x85, 0x47, 0xa3, 0xa9, 0x9d, 0x2a, 0xb0, 0x9a, 0xc7, 0xd7, 0xc8, 0xf5, 0xae, 0x3d, 0x64, 0x32, 0x04, 0x5c, 0xba, 0x3f, 0xa7, 0x78, 0x34, 0x58, 0x92, 0x54, 0x2b, 0xd8, 0x1c, 0x05, 0xbe, 0xfc, 0xd2, 0xe5, 0xcc, 0x9a, 0x57, 0x9b, 0xef, 0xb7, 0xc5, 0x8d, 0x02, 0xfb, 0x94, 0xf3, 0x33, 0x92, 0xfe, 0x17, 0xf4, 0xeb, 0xa2, 0xcb, 0x51, 0x0e, 0xc7, 0x4c, 0xc9, 0xd1, 0xd8, 0xa8, 0x7c, 0x10, 0x66, 0xa4, 0x86, 0x9a, 0x39, 0x83, 0xe6, 0x64, 0xbf, 0xe9, 0xde, 0xa5, 0xae, 0x4f, 0xdf, 0x31, 0x0c, 0x8f, 0x59, 0x81, 0x5a, 0x67, 0x8f, 0xa3, 0x25, 0xf3, 0x69, 0xaf, 0x84, 0xff, 0xeb, 0xc1, 0xd1, 0x50, 0x43, 0x1f, 0xe3, 0xbd, 0x27, 0x34, 0xf6, 0x36, 0xcf, 0x65, 0x8e, 0x6c, 0x1a, 0x6a, 0x6e, 0x2c, 0xbe, 0x07, 0x1f, 0x9a, 0x7c, 0x26, 0x11, 0x9a, 0xd1, 0x05, 0x09, 0x8e, 0xda, 0x62, 0x2c, 0xab, 0x8e, 0x17, 0x67, 0x62, 0x10, 0x98, 0x77, 0xd9, 0xae, 0x9d, 0x67, 0x29, 0xd4, 0x4a, 0x58, 0xe7, 0x07, 0xd6, 0xb8, 0xad, 0x6e, 0x69, 0x6a, 0x33, 0xc6, 0x72, 0xda, 0x9d, 0x08, 0xda, 0x2a, 0x7f, 0x9e, 0x3b, 0xf0, 0x22, 0x18, 0x23, 0x87, 0x22, 0xa4, 0x6b, 0x31, 0xd4, 0x9d, 0xaf, 0xf9, 0xaf, 0x00, 0xa6, 0x36, 0x3c, 0x3a, 0x42, 0x3b, 0x2e, 0x87, 0x3d, 0xef, 0xdd, 0xbc, 0xd9, 0x69, 0xb7, 0x5a, 0x81, 0x05, 0x3d, 0x9a, 0x97, 0xc0, 0x6d, 0xe2, 0xbf, 0xe3, 0xd0, 0xcf, 0xd3, 0xd3, 0xc7, 0x79, 0x83, 0xb1, 0x8d, 0xbd, 0xe2, 0x3c, 0x07, 0x28, 0x60, 0x4a, 0x71, 0x43, 0x5a, 0xd4, 0x0d, 0xf1, 0x57, 0x90, 0x96, 0xdd, 0xbe, 0x02, 0xe4, 0x61, 0x22, 0x10, 0xca, 0xa0, 0x34, 0xdc, 0xef, 0xb8, 0xb4, 0xd7, 0xb5, 0xe6, 0xd2, 0xeb, 0xa3, 0x7a, 0x79, 0xfb, 0x61, 0xf3, 0x4b, 0x5a, 0xf7, 0xd9, 0xb2, 0x7b, 0x13, 0xe4, 0x93, 0x62, 0x22, 0x41, 0x12, 0x49, 0xb7, 0xfb, 0xb6, 0x9e, 0x73, 0x46, 0x1d, 0xaf, 0x4a, 0xa6, 0xf3, 0xe2, 0xc7, 0x39, 0x44, 0xf1, 0x0c, 0xe6, 0x7c, 0x86, 0xfe, 0xd2, 0x60, 0xbd, 0xa7, 0xb4, 0x0d, 0xb3, 0x9b, 0x1d, 0xe3, 0xc7, 0xd8, 0xf0, 0x9a, 0x77, 0xf3, 0xc8, 0x4b, 0xc6, 0x29, 0x31, 0xd2, 0x28, 0xb2, 0x4a, 0x57, 0x4a, 0xc3, 0xf4, 0xeb, 0x74, 0x5c, 0xff, 0x7e, 0x03, 0x1a, 0x3f, 0xb2, 0xa0, 0x85, 0x95, 0xc1, 0x53, 0x70, 0xa3, 0xc8, 0x2d, 0xb7, 0xd9, 0xf4, 0x1b, 0xb1, 0xd8, 0xec, 0xc4, 0x29, 0xcf, 0xa3, 0xa6, 0x58, 0x33, 0x01, 0x6a, 0xb6, 0xea, 0x60, 0xc9, 0x39, 0x0c, 0xfa, 0x1b, 0x65, 0xcc, 0xea, 0xe5, 0x50, 0x94, 0x07, 0x95, 0x38, 0x6e, 0xd2, 0x41, 0x33, 0xfb, 0xae, 0x8b, 0x30, 0x17, 0x50, 0x2a, 0xf3, 0xcf, 0xe9, 0x51, 0xd7, 0x81, 0xd3, 0x6c, 0xfe, 0xff, 0x85, 0xbf, 0xdf, 0x5a, 0xf0, 0x40, 0xbe, 0x40, 0x65, 0x68, 0x1b, 0x3b, 0x0a, 0x63, 0xc2, 0x74, 0x7f, 0x08, 0x08, 0xcf, 0x3d, 0xa7, 0x25, 0x16, 0x9d, 0xde, 0xd1, 0x00, 0x3d, 0xa6, 0xcd, 0x5d, 0xe4, 0xcb, 0x04, 0x19, 0x42, 0x93, 0x8d, 0x0a, 0x7f, 0x88, 0x02, 0xd4, 0x8f, 0x2e, 0x3c, 0x6e, 0xeb, 0x45, 0xcd, 0x90, 0xaf, 0x6f, 0xc9, 0xf4, 0x50, 0x7e, 0x9f, 0x83, 0x80, 0xac, 0x33, 0xca, 0xca, 0x77, 0x51, 0x48, 0x7f, 0x65, 0x50, 0x04, 0x41, 0xd9, 0x20, 0xb9, 0x48, 0x80, 0xa4, 0x97, 0xd0, 0x1c, 0x08, 0x02, 0xbb, 0x08, 0xd7, 0x4c, 0x5d, 0x4c, 0x6b, 0xf2, 0xd8, 0x65, 0xee, 0x58, 0x22, 0xb3, 0x37, 0x5c, 0x75, 0x5d, 0x1a, 0x5e, 0x3d, 0x32, 0x44, 0xc3, 0x20, 0x51, 0x0a, 0x1e, 0x30, 0x35, 0x77, 0x02, 0xcd, 0x42, 0x52, 0x07, 0x2c, 0xf8, 0x64, 0x37, 0xf7, 0xa9, 0xde, 0x55, 0x61, 0xc7, 0xe5, 0x9b, 0x94, 0xb9, 0x58, 0x41, 0x00, 0x13, 0x1a, 0xc3, 0x99, 0xf4, 0xc1, 0xeb, 0x19, 0xfb, 0x4b, 0xdf, 0x65, 0xe6, 0x27, 0x85, 0xe9, 0x7c, 0x19, 0x4b, 0x87, 0x64, 0xcc, 0xf3, 0x2f, 0xd0, 0x5d, 0x80, 0x4c, 0x2e, 0x43, 0x9d, 0xda, 0x2a, 0x10, 0x92, 0x74, 0xfb, 0xff, 0xa8, 0x1a, 0x83, 0x7c, 0x51, 0xb2, 0x6d, 0x15, 0x4f, 0x97, 0x4b, 0x88, 0x2a, 0x5b, 0x17, 0x4b, 0x30, 0x8f, 0xc4, 0x87, 0x68, 0xd2, 0x22, 0x92, 0x25, 0x32, 0xb1, 0x83, 0xab, 0xdf, 0x6f, 0xbb, 0x0b, 0xc7, 0x49, 0x27, 0x66, 0x97, 0x4d, 0x32, 0x1e, 0xe6, 0xfb, 0x7c, 0x5f, 0x7b, 0x3e, 0xea, 0x23, 0x78, 0xdc, 0x6d, 0x6b, 0xb4, 0x80, 0x19, 0x25, 0x0b, 0x8d, 0x8d, 0x8d, 0xed, 0xb5, 0x22, 0x42, 0x1a, 0xee, 0xdb, 0x31, 0x86, 0x76, 0x98, 0x2a, 0x80, 0xe7, 0x96, 0x1e, 0xc4, 0x0e, 0x6d, 0x7f, 0x33, 0x39, 0x69, 0x42, 0x55, 0xba, 0xff, 0x51, 0xbe, 0x3a, 0x7e, 0xa7, 0xd8, 0x79, 0x3a, 0x10, 0x9b, 0xe3, 0xae, 0x44, 0x23, 0xbf, 0x08, 0x2e, 0x20, 0x6a, 0x57, 0x3b, 0x4f, 0x0f, 0x93, 0xfc, 0x16, 0xdd, 0xe8, 0x1b, 0xd5, 0xdc, 0x58, 0x3f, 0x52, 0x8c, 0x08, 0xa0, 0xa9, 0xab, 0x8e, 0x6c, 0xd5, 0x24, 0xe2, 0x97, 0xc9, 0xcf, 0x0f, 0x43, 0xc3, 0x44, 0x91, 0x38, 0x30, 0xec, 0xb1, 0x6f, 0x91, 0x44, 0x14, 0x77, 0xba, 0x78, 0x2e, 0xdd, 0x4e, 0x73, 0xe7, 0x32, 0x97, 0x9d, 0x3a, 0x66, 0x4e, 0xb9, 0x9e, 0xa5, 0xd2, 0x4b, 0x6c, 0x84, 0xaa, 0x69, 0xf3, 0x77, 0xcb, 0x0c, 0xad, 0x5a, 0xe4, 0xe6, 0x41, 0xe3, 0x8b, 0x19, 0x7a, 0x09, 0x94, 0xd5, 0x8b, 0x23, 0x87, 0xe9, 0x17, 0x60, 0xe9, 0xb6, 0xfe, 0xbc, 0xb4, 0x45, 0xcf, 0x85, 0xbb, 0xa2, 0x4a, 0x94, 0xcd, 0xa7, 0x5e, 0x33, 0x86, 0x74, 0x42, 0x82, 0x49, 0xfe, 0x6d, 0xe4, 0x69, 0x26, 0x01, 0xd1, 0xea, 0xe0, 0xea, 0x02, 0x1d, 0x9b, 0xc8, 0x07, 0x7b, 0xe8, 0x66, 0x5d, 0x07, 0x37, 0x74, 0x8f, 0xa3, 0x0f, 0xcf, 0x80, 0xf7, 0xe4, 0x82, 0x58, 0x46, 0x74, 0xf6, 0x33, 0xa5, 0x00, 0x6a, 0x53, 0x82, 0x67, 0x62, 0x7f, 0xd9, 0x18, 0x54, 0xe0, 0x87, 0x12, 0x68, 0xa6, 0xb0, 0xb0, 0x5d, 0xd5, 0x14, 0x95, 0x13, 0x5d, 0xef, 0xb9, 0x37, 0x6e, 0x9b, 0x84, 0x1b, 0x64, 0xe5, 0xdb, 0xf4, 0x3c, 0xe6, 0xc7, 0x4b, 0xcf, 0x3a, 0xe1, 0xfc, 0x42, 0x7e, 0x81, 0x0b, 0x7c, 0xbf, 0x69, 0x57, 0xdb, 0xf9, 0x04, 0x69, 0x0e, 0x87, 0x84, 0x25, 0x43, 0x89, 0x7d, 0xe7, 0x8f, 0x13, 0xd0, 0x8d, 0x92, 0xeb, 0xd2, 0x7f, 0xb2, 0xcf, 0xcc, 0x0c, 0x76, 0x54, 0x30, 0x58, 0x90, 0x57, 0xb1, 0x6b, 0x15, 0xf2, 0x07, 0xca, 0x1e, 0x6f, 0x08, 0xd5, 0x26, 0x16, 0xdd, 0x57, 0xad, 0x43, 0xef, 0xea, 0x6f, 0xdd, 0xaa, 0xea, 0x18, 0xd3, 0x37, 0x31, 0xfa, 0xc7, 0xec, 0xaa, 0xe9, 0x50, 0xe1, 0xdf, 0x3c, 0x5a, 0x4e, 0x6f, 0xcb, 0x22, 0x3d, 0xf5, 0xe8, 0x6b, 0x48, 0x7f, 0xd7, 0x09, 0x2d, 0x08, 0x22, 0xef, 0xfa, 0xec, 0x82, 0xc4, 0xbe, 0xc1, 0x0c, 0x60, 0x0f, 0xdb, 0x90, 0xe7, 0x74, 0x82, 0x91, 0x1b, 0x15, 0x95, 0x27, 0x77, 0x38, 0x84, 0x14, 0x09, 0xd0, 0xf8, 0xf1, 0x13, 0x19, 0x1d, 0x47, 0xf5, 0xe5, 0x6c, 0x11, 0x5a, 0x05, 0xde, 0xa7, 0x59, 0xaa, 0x6f, 0xb1, 0xd0, 0x47, 0xf9, 0xfc, 0xa4, 0xed, 0x51, 0x9e, 0xa5, 0xd2, 0x1f, 0xe3, 0xba, 0x5b, 0x94, 0x34, 0xfe, 0xa1, 0x28, 0x3d, 0xfa, 0xd6, 0x3d, 0x01, 0x58, 0x9b, 0x0e, 0xb6, 0x1f, 0x24, 0x43, 0x51, 0xd0, 0x33, 0x41, 0xdc, 0xd4, 0xdf, 0x62, 0x26, 0x5a, 0xfc, 0xae, 0xc6, 0x67, 0x6a, 0x87, 0x7d, 0x5c, 0xac, 0xb3, 0x59, 0xeb, 0xb5, 0x31, 0x96, 0x10, 0xdd, 0x44, 0x7d, 0xa9, 0x7e, 0x95, 0x0b, 0x0c, }, }, { .name = "Kyber Round 2, 786 KAT 1 (PKCS#8/SPKI)", .version = 0, .keyform = 0, .pk_len = 0, .sk_len = 0, .pkcs8_len = 3697, .pkcs8 = { 0x30, 0x82, 0x0e, 0x6d, 0x02, 0x01, 0x00, 0x30, 0x0f, 0x06, 0x0b, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x02, 0x82, 0x0b, 0x05, 0x03, 0x03, 0x05, 0x00, 0x04, 0x82, 0x0e, 0x55, 0x30, 0x82, 0x0e, 0x51, 0x02, 0x01, 0x00, 0x03, 0x82, 0x09, 0x61, 0x00, 0x07, 0x63, 0x8f, 0xb6, 0x98, 0x68, 0xf3, 0xd3, 0x20, 0xe5, 0x86, 0x2b, 0xd9, 0x69, 0x33, 0xfe, 0xb3, 0x11, 0xb3, 0x62, 0x09, 0x3c, 0x9b, 0x5d, 0x50, 0x17, 0x0b, 0xce, 0xd4, 0x3f, 0x1b, 0x53, 0x6d, 0x9a, 0x20, 0x4b, 0xb1, 0xf2, 0x26, 0x95, 0x95, 0x0b, 0xa1, 0xf2, 0xa9, 0xe8, 0xeb, 0x82, 0x8b, 0x28, 0x44, 0x88, 0x76, 0x0b, 0x3f, 0xc8, 0x4f, 0xab, 0xa0, 0x42, 0x75, 0xd5, 0x62, 0x8e, 0x39, 0xc5, 0xb2, 0x47, 0x13, 0x74, 0x28, 0x3c, 0x50, 0x32, 0x99, 0xc0, 0xab, 0x49, 0xb6, 0x6b, 0x8b, 0xbb, 0x56, 0xa4, 0x18, 0x66, 0x24, 0xf9, 0x19, 0xa2, 0xba, 0x59, 0xbb, 0x08, 0xd8, 0x55, 0x18, 0x80, 0xc2, 0xbe, 0xfc, 0x4f, 0x87, 0xf2, 0x5f, 0x59, 0xab, 0x58, 0x7a, 0x79, 0xc3, 0x27, 0xd7, 0x92, 0xd5, 0x4c, 0x97, 0x4a, 0x69, 0x26, 0x2f, 0xf8, 0xa7, 0x89, 0x38, 0x28, 0x9e, 0x9a, 0x87, 0xb6, 0x88, 0xb0, 0x83, 0xe0, 0x59, 0x5f, 0xe2, 0x18, 0xb6, 0xbb, 0x15, 0x05, 0x94, 0x1c, 0xe2, 0xe8, 0x1a, 0x5a, 0x64, 0xc5, 0xaa, 0xc6, 0x04, 0x17, 0x25, 0x69, 0x85, 0x34, 0x9e, 0xe4, 0x7a, 0x52, 0x42, 0x0a, 0x5f, 0x97, 0x47, 0x7b, 0x72, 0x36, 0xac, 0x76, 0xbc, 0x70, 0xe8, 0x28, 0x87, 0x29, 0x28, 0x7e, 0xe3, 0xe3, 0x4a, 0x3d, 0xbc, 0x36, 0x83, 0xc0, 0xb7, 0xb1, 0x00, 0x29, 0xfc, 0x20, 0x34, 0x18, 0x53, 0x7e, 0x74, 0x66, 0xba, 0x63, 0x85, 0xa8, 0xff, 0x30, 0x1e, 0xe1, 0x27, 0x08, 0xf8, 0x2a, 0xaa, 0x1e, 0x38, 0x0f, 0xc7, 0xa8, 0x8f, 0x8f, 0x20, 0x5a, 0xb7, 0xe8, 0x8d, 0x7e, 0x95, 0x95, 0x2a, 0x55, 0xba, 0x20, 0xd0, 0x9b, 0x79, 0xa4, 0x71, 0x41, 0xd6, 0x2b, 0xf6, 0xeb, 0x7d, 0xd3, 0x07, 0xb0, 0x8e, 0xca, 0x13, 0xa5, 0xbc, 0x5f, 0x6b, 0x68, 0x58, 0x1c, 0x68, 0x65, 0xb2, 0x7b, 0xbc, 0xdd, 0xab, 0x14, 0x2f, 0x4b, 0x2c, 0xbf, 0xf4, 0x88, 0xc8, 0xa2, 0x27, 0x05, 0xfa, 0xa9, 0x8a, 0x2b, 0x9e, 0xea, 0x35, 0x30, 0xc7, 0x66, 0x62, 0x33, 0x5c, 0xc7, 0xea, 0x3a, 0x00, 0x77, 0x77, 0x25, 0xeb, 0xcc, 0xcd, 0x2a, 0x46, 0x36, 0xb2, 0xd9, 0x12, 0x2f, 0xf3, 0xab, 0x77, 0x12, 0x3c, 0xe0, 0x88, 0x3c, 0x19, 0x11, 0x11, 0x5e, 0x50, 0xc9, 0xe8, 0xa9, 0x41, 0x94, 0xe4, 0x8d, 0xd0, 0xd0, 0x9c, 0xff, 0xb3, 0xad, 0xcd, 0x2c, 0x1e, 0x92, 0x43, 0x09, 0x03, 0xd0, 0x7a, 0xdb, 0xf0, 0x05, 0x32, 0x03, 0x15, 0x75, 0xaa, 0x7f, 0x9e, 0x7b, 0x5a, 0x1f, 0x33, 0x62, 0xde, 0xc9, 0x36, 0xd4, 0x04, 0x3c, 0x05, 0xf2, 0x47, 0x6c, 0x07, 0x57, 0x8b, 0xc9, 0xcb, 0xaf, 0x2a, 0xb4, 0xe3, 0x82, 0x72, 0x7a, 0xd4, 0x16, 0x86, 0xa9, 0x6b, 0x25, 0x48, 0x82, 0x0b, 0xb0, 0x3b, 0x32, 0xf1, 0x1b, 0x28, 0x11, 0xad, 0x62, 0xf4, 0x89, 0xe9, 0x51, 0x63, 0x2a, 0xba, 0x0d, 0x1d, 0xf8, 0x96, 0x80, 0xcc, 0x8a, 0x8b, 0x53, 0xb4, 0x81, 0xd9, 0x2a, 0x68, 0xd7, 0x0b, 0x4e, 0xa1, 0xc3, 0xa6, 0xa5, 0x61, 0xc0, 0x69, 0x28, 0x82, 0xb5, 0xca, 0x8c, 0xc9, 0x42, 0xa8, 0xd4, 0x95, 0xaf, 0xcb, 0x06, 0xde, 0x89, 0x49, 0x8f, 0xb9, 0x35, 0xb7, 0x75, 0x90, 0x8f, 0xe7, 0xa0, 0x3e, 0x32, 0x4d, 0x54, 0xcc, 0x19, 0xd4, 0xe1, 0xaa, 0xbd, 0x35, 0x93, 0xb3, 0x8b, 0x19, 0xee, 0x13, 0x88, 0xfe, 0x49, 0x2b, 0x43, 0x12, 0x7e, 0x5a, 0x50, 0x42, 0x53, 0x78, 0x6a, 0x0d, 0x69, 0xad, 0x32, 0x60, 0x1c, 0x28, 0xe2, 0xc8, 0x85, 0x04, 0xa5, 0xba, 0x59, 0x97, 0x06, 0x02, 0x3a, 0x61, 0x36, 0x3e, 0x17, 0xc6, 0xb9, 0xbb, 0x59, 0xbd, 0xc6, 0x97, 0x45, 0x2c, 0xd0, 0x59, 0x45, 0x19, 0x83, 0xd7, 0x38, 0xca, 0x3f, 0xd0, 0x34, 0xe3, 0xf5, 0x98, 0x88, 0x54, 0xca, 0x05, 0x03, 0x1d, 0xb0, 0x96, 0x11, 0x49, 0x89, 0x88, 0x19, 0x7c, 0x6b, 0x30, 0xd2, 0x58, 0xdf, 0xe2, 0x62, 0x65, 0x54, 0x1c, 0x89, 0xa4, 0xb3, 0x1d, 0x68, 0x64, 0xe9, 0x38, 0x9b, 0x03, 0xcb, 0x74, 0xf7, 0xec, 0x43, 0x23, 0xfb, 0x94, 0x21, 0xa4, 0xb9, 0x79, 0x0a, 0x26, 0xd1, 0x7b, 0x03, 0x98, 0xa2, 0x67, 0x67, 0x35, 0x09, 0x09, 0xf8, 0x4d, 0x57, 0xb6, 0x69, 0x4d, 0xf8, 0x30, 0x66, 0x4c, 0xa8, 0xb3, 0xc3, 0xc0, 0x3e, 0xd2, 0xae, 0x67, 0xb8, 0x90, 0x06, 0x86, 0x8a, 0x68, 0x52, 0x7c, 0xcd, 0x66, 0x64, 0x59, 0xab, 0x7f, 0x05, 0x66, 0x71, 0x00, 0x0c, 0x61, 0x64, 0xd3, 0xa7, 0xf2, 0x66, 0xa1, 0x4d, 0x97, 0xcb, 0xd7, 0x00, 0x4d, 0x6c, 0x92, 0xca, 0xca, 0x77, 0x0b, 0x84, 0x4a, 0x4f, 0xa9, 0xb1, 0x82, 0xe7, 0xb1, 0x8c, 0xa8, 0x85, 0x08, 0x2a, 0xc5, 0x64, 0x6f, 0xcb, 0x4a, 0x14, 0xe1, 0x68, 0x5f, 0xeb, 0x0c, 0x9c, 0xe3, 0x37, 0x2a, 0xb9, 0x53, 0x65, 0xc0, 0x4f, 0xd8, 0x30, 0x84, 0xf8, 0x0a, 0x23, 0xff, 0x10, 0xa0, 0x5b, 0xf1, 0x5f, 0x7f, 0xa5, 0xac, 0xc6, 0xc0, 0xcb, 0x46, 0x2c, 0x33, 0xca, 0x52, 0x4f, 0xa6, 0xb8, 0xbb, 0x35, 0x90, 0x43, 0xba, 0x68, 0x60, 0x9e, 0xaa, 0x25, 0x36, 0xe8, 0x1d, 0x08, 0x46, 0x3b, 0x19, 0x65, 0x3b, 0x54, 0x35, 0xba, 0x94, 0x6c, 0x9a, 0xdd, 0xeb, 0x20, 0x2b, 0x04, 0xb0, 0x31, 0xcc, 0x96, 0x0d, 0xcc, 0x12, 0xe4, 0x51, 0x8d, 0x42, 0x8b, 0x32, 0xb2, 0x57, 0xa4, 0xfc, 0x73, 0x13, 0xd3, 0xa7, 0x98, 0x0d, 0x80, 0x08, 0x2e, 0x93, 0x4f, 0x9d, 0x95, 0xc3, 0x2b, 0x0a, 0x01, 0x91, 0xa2, 0x36, 0x04, 0x38, 0x4d, 0xd9, 0xe0, 0x79, 0xbb, 0xba, 0xa2, 0x66, 0xd1, 0x4c, 0x3f, 0x75, 0x6b, 0x9f, 0x21, 0x33, 0x10, 0x74, 0x33, 0xa4, 0xe8, 0x3f, 0xa7, 0x18, 0x72, 0x82, 0xa8, 0x09, 0x20, 0x3a, 0x4f, 0xaf, 0x84, 0x18, 0x51, 0x83, 0x3d, 0x12, 0x1a, 0xc3, 0x83, 0x84, 0x3a, 0x5e, 0x55, 0xbc, 0x23, 0x81, 0x42, 0x5e, 0x16, 0xc7, 0xdb, 0x4c, 0xc9, 0xab, 0x5c, 0x1b, 0x0d, 0x91, 0xa4, 0x7e, 0x2b, 0x8d, 0xe0, 0xe5, 0x82, 0xc8, 0x6b, 0x6b, 0x0d, 0x90, 0x7b, 0xb3, 0x60, 0xb9, 0x7f, 0x40, 0xab, 0x5d, 0x03, 0x8f, 0x6b, 0x75, 0xc8, 0x14, 0xb2, 0x7d, 0x9b, 0x96, 0x8d, 0x41, 0x98, 0x32, 0xbc, 0x8c, 0x2b, 0xee, 0x60, 0x5e, 0xf6, 0xe5, 0x05, 0x9d, 0x33, 0x10, 0x0d, 0x90, 0x48, 0x5d, 0x37, 0x84, 0x50, 0x01, 0x42, 0x21, 0x73, 0x6c, 0x07, 0x40, 0x7c, 0xac, 0x26, 0x04, 0x08, 0xaa, 0x64, 0x92, 0x66, 0x19, 0x78, 0x8b, 0x86, 0x01, 0xc2, 0xa7, 0x52, 0xd1, 0xa6, 0xcb, 0xf8, 0x20, 0xd7, 0xc7, 0xa0, 0x47, 0x16, 0x20, 0x32, 0x25, 0xb3, 0x89, 0x5b, 0x93, 0x42, 0xd1, 0x47, 0xa8, 0x18, 0x5c, 0xfc, 0x1b, 0xb6, 0x5b, 0xa0, 0x6b, 0x41, 0x42, 0x33, 0x99, 0x03, 0xc0, 0xac, 0x46, 0x51, 0x38, 0x5b, 0x45, 0xd9, 0x8a, 0x8b, 0x19, 0xd2, 0x8c, 0xd6, 0xba, 0xb0, 0x88, 0x78, 0x7f, 0x7e, 0xe1, 0xb1, 0x24, 0x61, 0x76, 0x6b, 0x43, 0xcb, 0xcc, 0xb9, 0x64, 0x34, 0x42, 0x7d, 0x93, 0xc0, 0x65, 0x55, 0x06, 0x88, 0xf6, 0x94, 0x8e, 0xd1, 0xb5, 0x47, 0x5a, 0x42, 0x5f, 0x1b, 0x85, 0x20, 0x9d, 0x06, 0x1c, 0x08, 0xb5, 0x6c, 0x1c, 0xc0, 0x69, 0xf6, 0xc0, 0xa7, 0xc6, 0xf2, 0x93, 0x58, 0xca, 0xb9, 0x11, 0x08, 0x77, 0x32, 0xa6, 0x49, 0xd2, 0x7c, 0x9b, 0x98, 0xf9, 0xa4, 0x88, 0x79, 0x38, 0x7d, 0x9b, 0x00, 0xc2, 0x59, 0x59, 0xa7, 0x16, 0x54, 0xd6, 0xf6, 0xa9, 0x46, 0x16, 0x45, 0x13, 0xe4, 0x7a, 0x75, 0xd0, 0x05, 0x98, 0x6c, 0x23, 0x63, 0xc0, 0x9f, 0x6b, 0x53, 0x7e, 0xca, 0x78, 0xb9, 0x30, 0x3a, 0x5f, 0xa4, 0x57, 0x60, 0x8a, 0x58, 0x6a, 0x65, 0x3a, 0x34, 0x7d, 0xb0, 0x4d, 0xfc, 0xc1, 0x91, 0x75, 0xb3, 0xa3, 0x01, 0x17, 0x25, 0x36, 0x06, 0x2a, 0x65, 0x8a, 0x95, 0x27, 0x75, 0x70, 0xc8, 0x85, 0x2c, 0xa8, 0x97, 0x3f, 0x4a, 0xe1, 0x23, 0xa3, 0x34, 0x04, 0x7d, 0xd7, 0x11, 0xc8, 0x92, 0x7a, 0x63, 0x4a, 0x03, 0x38, 0x8a, 0x52, 0x7b, 0x03, 0x4b, 0xf7, 0xa8, 0x17, 0x0f, 0xa7, 0x02, 0xc1, 0xf7, 0xc2, 0x3e, 0xc3, 0x2d, 0x18, 0xa2, 0x37, 0x48, 0x90, 0xbe, 0x9c, 0x78, 0x7a, 0x94, 0x09, 0xc8, 0x2d, 0x19, 0x2c, 0x4b, 0xb7, 0x05, 0xa2, 0xf9, 0x96, 0xce, 0x40, 0x5d, 0xa0, 0xb7, 0x1f, 0x67, 0xc6, 0xce, 0xc0, 0xd3, 0x56, 0x86, 0xd5, 0x13, 0x42, 0x34, 0x32, 0xe5, 0x12, 0xac, 0x40, 0x44, 0x55, 0x7e, 0x86, 0x8a, 0x62, 0x48, 0x00, 0x10, 0x9a, 0x33, 0x55, 0xf9, 0x8f, 0x15, 0x14, 0x44, 0xe2, 0x85, 0x2e, 0x27, 0xea, 0x6e, 0xdb, 0x19, 0x92, 0xca, 0xd3, 0x97, 0x3c, 0x3a, 0x6f, 0xf7, 0x9a, 0x5a, 0x04, 0x9a, 0x25, 0x9e, 0xb5, 0x41, 0x5a, 0xa2, 0xa2, 0x62, 0x45, 0x6e, 0xc9, 0x49, 0x5b, 0xbb, 0x52, 0x00, 0xd8, 0xd3, 0x16, 0x3a, 0x5b, 0x10, 0x22, 0x62, 0x92, 0xec, 0xa0, 0x10, 0x21, 0x38, 0x9d, 0xa3, 0x78, 0x81, 0xe2, 0x76, 0x30, 0x65, 0x50, 0xc6, 0xef, 0xb6, 0x44, 0x0e, 0xc5, 0x1a, 0x2f, 0x73, 0x48, 0x34, 0x9b, 0x85, 0x1c, 0xd4, 0xaa, 0x01, 0x75, 0xa0, 0x55, 0x02, 0x13, 0xc4, 0x79, 0x1d, 0x91, 0x01, 0x12, 0x20, 0x82, 0x4b, 0x2b, 0x61, 0x65, 0x08, 0x13, 0xad, 0xfd, 0x2c, 0xb1, 0x05, 0x38, 0xbf, 0xab, 0x0a, 0x72, 0x6f, 0x81, 0x12, 0x9e, 0xd2, 0xc0, 0xf0, 0x6a, 0x16, 0xb7, 0x01, 0x09, 0x0b, 0xf0, 0x48, 0xc5, 0xa4, 0x01, 0x26, 0xd5, 0x72, 0xfc, 0xd4, 0x7a, 0xa1, 0x21, 0x8f, 0xb0, 0x15, 0x47, 0xd1, 0x50, 0x79, 0x2d, 0x23, 0x16, 0xcb, 0x32, 0x0d, 0x51, 0x44, 0xba, 0x35, 0x08, 0xa1, 0xeb, 0xbb, 0x5a, 0xc1, 0xc2, 0x29, 0x13, 0xe8, 0x29, 0x5f, 0xab, 0x59, 0xbf, 0x58, 0x37, 0xa7, 0x78, 0xcf, 0x28, 0x22, 0x7e, 0x07, 0xe1, 0x03, 0x2d, 0xab, 0x7d, 0x0e, 0x09, 0xa1, 0x5f, 0x13, 0x41, 0x48, 0xc1, 0x20, 0x09, 0xda, 0x53, 0x6b, 0x22, 0xcc, 0x62, 0x47, 0x4e, 0x69, 0xcc, 0x15, 0x54, 0xc0, 0x81, 0x4d, 0x6c, 0xa0, 0xb7, 0x22, 0x59, 0x43, 0x83, 0xa9, 0xd0, 0xa2, 0xc7, 0x7f, 0xd3, 0x65, 0xa5, 0x54, 0x42, 0x95, 0xfb, 0xb9, 0x73, 0xf9, 0x1e, 0xa5, 0x64, 0x90, 0xd6, 0xca, 0x68, 0x76, 0x49, 0x7b, 0x98, 0xb3, 0xcb, 0x12, 0x41, 0x7c, 0x25, 0x7b, 0x6d, 0x0f, 0x71, 0x83, 0xdb, 0xb6, 0x9e, 0x33, 0x07, 0x5b, 0xeb, 0x01, 0x17, 0xb6, 0x91, 0x4c, 0x69, 0xba, 0x38, 0x34, 0x94, 0x22, 0xf2, 0xf4, 0x33, 0x64, 0x82, 0x2a, 0x25, 0x70, 0x95, 0x2d, 0xd5, 0x07, 0x7b, 0x90, 0x75, 0x5f, 0x15, 0x74, 0x11, 0x5b, 0x8e, 0x22, 0x14, 0x27, 0x58, 0x59, 0x61, 0x91, 0x3a, 0x9b, 0xfa, 0x05, 0x02, 0xb5, 0xd7, 0x9a, 0xb7, 0x81, 0x17, 0x44, 0xe6, 0x56, 0x3c, 0x5b, 0x62, 0xc5, 0xcc, 0x4e, 0x93, 0x23, 0x9a, 0x0a, 0x8c, 0xc6, 0x0f, 0xe8, 0x48, 0xf8, 0x4a, 0x95, 0xf5, 0x90, 0x25, 0x99, 0xb5, 0x4a, 0x06, 0x62, 0x93, 0xa2, 0x02, 0x1d, 0xa1, 0x96, 0x76, 0x6c, 0x17, 0xc7, 0xe8, 0x63, 0xaf, 0x79, 0x0c, 0x27, 0x0b, 0x21, 0x6a, 0x25, 0x13, 0x8d, 0xda, 0x0c, 0x81, 0x26, 0xe0, 0x93, 0x77, 0x87, 0x98, 0x59, 0xdb, 0x35, 0x8f, 0x9b, 0x82, 0xb7, 0xc8, 0xa6, 0x79, 0x2a, 0xce, 0xe9, 0x2a, 0x4c, 0xbd, 0xe3, 0xce, 0xdd, 0x45, 0x00, 0xac, 0xbc, 0x55, 0x5c, 0x28, 0x8e, 0xff, 0x97, 0x95, 0x26, 0x5b, 0x90, 0x05, 0x35, 0x1c, 0x52, 0xe2, 0x65, 0x35, 0x54, 0xab, 0xaa, 0xf8, 0x72, 0xdf, 0x95, 0xca, 0x7f, 0x79, 0x59, 0x03, 0xf0, 0xb0, 0xa1, 0x82, 0xb1, 0x8a, 0xeb, 0x04, 0x75, 0xb2, 0x9f, 0x6e, 0x3a, 0xbf, 0x4c, 0x22, 0x50, 0xfe, 0x7b, 0x84, 0x2a, 0x73, 0x65, 0x50, 0x16, 0xa8, 0xfc, 0x72, 0x9f, 0x39, 0x05, 0x07, 0xac, 0xa9, 0x36, 0x82, 0x5a, 0x98, 0xb3, 0xa3, 0x2e, 0x6b, 0x25, 0x54, 0xce, 0x95, 0x28, 0x94, 0x1a, 0x3b, 0xb8, 0xc9, 0x09, 0x96, 0x00, 0x8d, 0x74, 0xfb, 0xcd, 0x02, 0x0a, 0x02, 0xe7, 0x06, 0xa6, 0xde, 0x7b, 0x02, 0xaf, 0x40, 0x4c, 0x10, 0xdb, 0x00, 0xfa, 0xec, 0x02, 0xd3, 0xea, 0xa6, 0xd9, 0x56, 0x1a, 0x15, 0x65, 0xa7, 0xb0, 0x5c, 0x63, 0x66, 0xd0, 0x9d, 0xa7, 0xa5, 0x37, 0xf2, 0x0c, 0x7b, 0x28, 0x59, 0xa8, 0x3e, 0x02, 0x9e, 0x13, 0xa9, 0xbd, 0x28, 0x91, 0x57, 0xc5, 0xb7, 0x4c, 0x84, 0xea, 0xa3, 0x07, 0x75, 0x3d, 0x43, 0x12, 0x02, 0xa3, 0xd9, 0xb6, 0x16, 0x22, 0x18, 0xbe, 0xc5, 0x34, 0x69, 0x45, 0xbf, 0xef, 0x55, 0xb6, 0x24, 0xc5, 0xc6, 0xe3, 0x73, 0x35, 0x9b, 0xb1, 0xc4, 0x79, 0x95, 0x2b, 0xba, 0xba, 0x4d, 0x65, 0x55, 0xc2, 0x76, 0x57, 0x3e, 0x51, 0x52, 0xb5, 0x53, 0x90, 0x19, 0x99, 0xf6, 0x94, 0x02, 0xd1, 0x50, 0xbe, 0xf7, 0x9d, 0x74, 0xfb, 0x29, 0x53, 0x01, 0x8f, 0xf4, 0x86, 0x66, 0x74, 0x6a, 0xce, 0x60, 0x78, 0x14, 0xa1, 0xfa, 0x33, 0x19, 0x57, 0x20, 0xf8, 0x38, 0x78, 0xd3, 0xb5, 0x75, 0xc7, 0x25, 0x74, 0x4a, 0x72, 0x07, 0x0d, 0xd0, 0x44, 0x01, 0x80, 0x42, 0xda, 0x25, 0x71, 0x4d, 0x17, 0x30, 0x90, 0x32, 0x3a, 0x51, 0xe6, 0xc0, 0x63, 0xd2, 0x03, 0x88, 0x13, 0x80, 0x91, 0x27, 0x61, 0xfc, 0x34, 0x10, 0x83, 0x90, 0x95, 0xf2, 0x6c, 0x0e, 0x68, 0x7a, 0x00, 0x70, 0x54, 0x95, 0xe1, 0x71, 0xb5, 0x71, 0x51, 0xac, 0xe0, 0x49, 0x8e, 0x30, 0xf1, 0x4c, 0xa9, 0xb0, 0x2f, 0x6e, 0x40, 0x83, 0x18, 0x54, 0xc2, 0xe0, 0xab, 0x1e, 0xcd, 0x0c, 0x21, 0xd8, 0xe4, 0xc7, 0xe6, 0x69, 0xcd, 0x72, 0x82, 0x30, 0xb9, 0xd1, 0x1f, 0x72, 0xc2, 0x66, 0xe3, 0x44, 0x66, 0xf9, 0xc0, 0x15, 0x9e, 0xf4, 0x24, 0xf8, 0xf3, 0x1d, 0x95, 0xa5, 0x7b, 0xa0, 0xe2, 0x10, 0x54, 0x3c, 0x10, 0xc6, 0x50, 0x3f, 0xb5, 0xc6, 0x3e, 0xd2, 0x3a, 0xa3, 0x6c, 0xd6, 0xa6, 0xf3, 0x78, 0x26, 0x1b, 0x0b, 0x1e, 0x79, 0x50, 0x9d, 0x8b, 0xeb, 0x36, 0xaa, 0x26, 0x3d, 0xc9, 0x15, 0x45, 0xe5, 0x33, 0x69, 0xdf, 0x26, 0x83, 0x7f, 0x39, 0x4c, 0x56, 0x77, 0x7c, 0x95, 0xb6, 0x48, 0xbd, 0x1a, 0x72, 0x92, 0x1a, 0xbf, 0x49, 0x56, 0x3f, 0x99, 0xcb, 0x9d, 0x98, 0xea, 0xb5, 0xc6, 0x66, 0x66, 0xf6, 0xb1, 0x6f, 0x74, 0x02, 0x24, 0x81, 0xfa, 0x21, 0x4e, 0x61, 0x76, 0x98, 0xd3, 0xbb, 0xd1, 0x3c, 0xb3, 0x08, 0x71, 0x3f, 0xdc, 0xc7, 0xcf, 0xd3, 0x97, 0xb9, 0xca, 0x39, 0xaf, 0xf4, 0xc7, 0x44, 0xd5, 0x71, 0x5d, 0x58, 0x96, 0x6f, 0x2c, 0xf9, 0x70, 0x70, 0x15, 0xc8, 0xf3, 0x54, 0x3e, 0xd2, 0x86, 0xa3, 0xd8, 0xd5, 0xcb, 0xf6, 0x4a, 0xce, 0xdf, 0xc0, 0x29, 0x71, 0xa9, 0x10, 0x72, 0xc6, 0x9d, 0x2e, 0xf4, 0x98, 0x29, 0xf1, 0x03, 0x7f, 0x05, 0x0c, 0x5b, 0x92, 0x22, 0x98, 0x56, 0xcb, 0x12, 0xb4, 0x56, 0xcc, 0x09, 0x52, 0x82, 0xa6, 0x26, 0x87, 0xea, 0x38, 0xc9, 0x77, 0x8a, 0xea, 0x49, 0x1d, 0xff, 0x06, 0x97, 0x11, 0xfb, 0xbe, 0x05, 0xe8, 0xcd, 0x9b, 0xf4, 0x4a, 0x8e, 0x71, 0x26, 0x19, 0x57, 0x3e, 0x12, 0xea, 0xa7, 0xb2, 0x38, 0x29, 0xdc, 0x67, 0x26, 0xbf, 0xe3, 0x3d, 0xa1, 0x36, 0xb8, 0x1e, 0x15, 0x32, 0x51, 0x50, 0x8f, 0x62, 0x85, 0xba, 0x15, 0xb2, 0xc1, 0x23, 0x76, 0x77, 0xfe, 0x5b, 0x14, 0xb4, 0xe3, 0x3f, 0x98, 0xc3, 0x26, 0xbc, 0x58, 0xb9, 0xd8, 0xe0, 0x75, 0xa2, 0x5b, 0x94, 0xc8, 0xa2, 0x32, 0x33, 0x02, 0x9d, 0xcc, 0x78, 0x6b, 0x13, 0x5c, 0x56, 0x16, 0x4b, 0xa3, 0xd1, 0x60, 0xcb, 0xce, 0xa8, 0x54, 0xb7, 0x97, 0x1f, 0x9c, 0xd7, 0x3a, 0x38, 0x3a, 0xac, 0x05, 0x0a, 0x30, 0x2a, 0xd8, 0x3b, 0x3e, 0x3a, 0xb9, 0x02, 0x46, 0xad, 0x16, 0x0a, 0x32, 0x1d, 0x33, 0x0a, 0xcd, 0xec, 0x7c, 0xa6, 0x64, 0x3d, 0x7e, 0xc0, 0x1f, 0x91, 0x69, 0x1f, 0x16, 0x32, 0x5b, 0xdf, 0x39, 0x69, 0x50, 0xb8, 0x8d, 0xaf, 0xe3, 0x69, 0xc6, 0x54, 0xb8, 0x52, 0x05, 0x5c, 0x97, 0x03, 0x62, 0xc6, 0x13, 0x80, 0x46, 0x07, 0x57, 0xc6, 0x58, 0x90, 0xf4, 0xe5, 0x92, 0x22, 0xe4, 0xa4, 0x06, 0x0b, 0x26, 0xc0, 0xeb, 0xc1, 0x01, 0x97, 0x59, 0x0d, 0xe3, 0xc8, 0xf0, 0x95, 0x5d, 0x65, 0x4b, 0x37, 0x1c, 0xcb, 0x90, 0xac, 0xa3, 0x71, 0xb2, 0x94, 0x47, 0x6c, 0x16, 0xa4, 0x59, 0x6a, 0x1d, 0xe8, 0x30, 0x9e, 0x2a, 0x36, 0x12, 0xc6, 0x9b, 0x71, 0x25, 0x31, 0x05, 0x01, 0xe0, 0xc0, 0x49, 0xb8, 0x74, 0x40, 0xd9, 0xa6, 0xd0, 0xec, 0xb9, 0x99, 0xc9, 0xa0, 0x94, 0x2a, 0xa3, 0x40, 0xf6, 0x03, 0x65, 0xea, 0xfd, 0x46, 0x5f, 0xc6, 0x4a, 0x0c, 0x5f, 0x8f, 0x3f, 0x90, 0x03, 0x48, 0x94, 0x15, 0x89, 0x9d, 0x59, 0xa5, 0x43, 0xd8, 0x20, 0x8c, 0x54, 0xa3, 0x16, 0x65, 0x29, 0xb5, 0x39, 0x22, 0xde, 0xe4, 0xab, 0xa0, 0x00, 0x38, 0x95, 0x81, 0x71, 0x7d, 0x36, 0xf5, 0x6f, 0x39, 0xaf, 0x73, 0x00, 0xb3, 0x1d, 0x83, 0x1a, 0x4d, 0x8c, 0x97, 0x61, 0x28, 0xe0, 0x9d, 0xed, 0xe7, 0x1a, 0x5a, 0x86, 0x26, 0xed, 0x79, 0xd4, 0x51, 0x14, 0x08, 0x00, 0xe0, 0x3b, 0x59, 0xb9, 0x56, 0xf8, 0x21, 0x0e, 0x55, 0x60, 0x67, 0x40, 0x7d, 0x13, 0xdc, 0x90, 0xfa, 0x9e, 0x8b, 0x87, 0x2b, 0xfb, 0x8f, 0xa0, 0x82, 0x04, 0xe5, 0x03, 0x82, 0x04, 0xe1, 0x00, 0xa0, 0xb7, 0x1f, 0x67, 0xc6, 0xce, 0xc0, 0xd3, 0x56, 0x86, 0xd5, 0x13, 0x42, 0x34, 0x32, 0xe5, 0x12, 0xac, 0x40, 0x44, 0x55, 0x7e, 0x86, 0x8a, 0x62, 0x48, 0x00, 0x10, 0x9a, 0x33, 0x55, 0xf9, 0x8f, 0x15, 0x14, 0x44, 0xe2, 0x85, 0x2e, 0x27, 0xea, 0x6e, 0xdb, 0x19, 0x92, 0xca, 0xd3, 0x97, 0x3c, 0x3a, 0x6f, 0xf7, 0x9a, 0x5a, 0x04, 0x9a, 0x25, 0x9e, 0xb5, 0x41, 0x5a, 0xa2, 0xa2, 0x62, 0x45, 0x6e, 0xc9, 0x49, 0x5b, 0xbb, 0x52, 0x00, 0xd8, 0xd3, 0x16, 0x3a, 0x5b, 0x10, 0x22, 0x62, 0x92, 0xec, 0xa0, 0x10, 0x21, 0x38, 0x9d, 0xa3, 0x78, 0x81, 0xe2, 0x76, 0x30, 0x65, 0x50, 0xc6, 0xef, 0xb6, 0x44, 0x0e, 0xc5, 0x1a, 0x2f, 0x73, 0x48, 0x34, 0x9b, 0x85, 0x1c, 0xd4, 0xaa, 0x01, 0x75, 0xa0, 0x55, 0x02, 0x13, 0xc4, 0x79, 0x1d, 0x91, 0x01, 0x12, 0x20, 0x82, 0x4b, 0x2b, 0x61, 0x65, 0x08, 0x13, 0xad, 0xfd, 0x2c, 0xb1, 0x05, 0x38, 0xbf, 0xab, 0x0a, 0x72, 0x6f, 0x81, 0x12, 0x9e, 0xd2, 0xc0, 0xf0, 0x6a, 0x16, 0xb7, 0x01, 0x09, 0x0b, 0xf0, 0x48, 0xc5, 0xa4, 0x01, 0x26, 0xd5, 0x72, 0xfc, 0xd4, 0x7a, 0xa1, 0x21, 0x8f, 0xb0, 0x15, 0x47, 0xd1, 0x50, 0x79, 0x2d, 0x23, 0x16, 0xcb, 0x32, 0x0d, 0x51, 0x44, 0xba, 0x35, 0x08, 0xa1, 0xeb, 0xbb, 0x5a, 0xc1, 0xc2, 0x29, 0x13, 0xe8, 0x29, 0x5f, 0xab, 0x59, 0xbf, 0x58, 0x37, 0xa7, 0x78, 0xcf, 0x28, 0x22, 0x7e, 0x07, 0xe1, 0x03, 0x2d, 0xab, 0x7d, 0x0e, 0x09, 0xa1, 0x5f, 0x13, 0x41, 0x48, 0xc1, 0x20, 0x09, 0xda, 0x53, 0x6b, 0x22, 0xcc, 0x62, 0x47, 0x4e, 0x69, 0xcc, 0x15, 0x54, 0xc0, 0x81, 0x4d, 0x6c, 0xa0, 0xb7, 0x22, 0x59, 0x43, 0x83, 0xa9, 0xd0, 0xa2, 0xc7, 0x7f, 0xd3, 0x65, 0xa5, 0x54, 0x42, 0x95, 0xfb, 0xb9, 0x73, 0xf9, 0x1e, 0xa5, 0x64, 0x90, 0xd6, 0xca, 0x68, 0x76, 0x49, 0x7b, 0x98, 0xb3, 0xcb, 0x12, 0x41, 0x7c, 0x25, 0x7b, 0x6d, 0x0f, 0x71, 0x83, 0xdb, 0xb6, 0x9e, 0x33, 0x07, 0x5b, 0xeb, 0x01, 0x17, 0xb6, 0x91, 0x4c, 0x69, 0xba, 0x38, 0x34, 0x94, 0x22, 0xf2, 0xf4, 0x33, 0x64, 0x82, 0x2a, 0x25, 0x70, 0x95, 0x2d, 0xd5, 0x07, 0x7b, 0x90, 0x75, 0x5f, 0x15, 0x74, 0x11, 0x5b, 0x8e, 0x22, 0x14, 0x27, 0x58, 0x59, 0x61, 0x91, 0x3a, 0x9b, 0xfa, 0x05, 0x02, 0xb5, 0xd7, 0x9a, 0xb7, 0x81, 0x17, 0x44, 0xe6, 0x56, 0x3c, 0x5b, 0x62, 0xc5, 0xcc, 0x4e, 0x93, 0x23, 0x9a, 0x0a, 0x8c, 0xc6, 0x0f, 0xe8, 0x48, 0xf8, 0x4a, 0x95, 0xf5, 0x90, 0x25, 0x99, 0xb5, 0x4a, 0x06, 0x62, 0x93, 0xa2, 0x02, 0x1d, 0xa1, 0x96, 0x76, 0x6c, 0x17, 0xc7, 0xe8, 0x63, 0xaf, 0x79, 0x0c, 0x27, 0x0b, 0x21, 0x6a, 0x25, 0x13, 0x8d, 0xda, 0x0c, 0x81, 0x26, 0xe0, 0x93, 0x77, 0x87, 0x98, 0x59, 0xdb, 0x35, 0x8f, 0x9b, 0x82, 0xb7, 0xc8, 0xa6, 0x79, 0x2a, 0xce, 0xe9, 0x2a, 0x4c, 0xbd, 0xe3, 0xce, 0xdd, 0x45, 0x00, 0xac, 0xbc, 0x55, 0x5c, 0x28, 0x8e, 0xff, 0x97, 0x95, 0x26, 0x5b, 0x90, 0x05, 0x35, 0x1c, 0x52, 0xe2, 0x65, 0x35, 0x54, 0xab, 0xaa, 0xf8, 0x72, 0xdf, 0x95, 0xca, 0x7f, 0x79, 0x59, 0x03, 0xf0, 0xb0, 0xa1, 0x82, 0xb1, 0x8a, 0xeb, 0x04, 0x75, 0xb2, 0x9f, 0x6e, 0x3a, 0xbf, 0x4c, 0x22, 0x50, 0xfe, 0x7b, 0x84, 0x2a, 0x73, 0x65, 0x50, 0x16, 0xa8, 0xfc, 0x72, 0x9f, 0x39, 0x05, 0x07, 0xac, 0xa9, 0x36, 0x82, 0x5a, 0x98, 0xb3, 0xa3, 0x2e, 0x6b, 0x25, 0x54, 0xce, 0x95, 0x28, 0x94, 0x1a, 0x3b, 0xb8, 0xc9, 0x09, 0x96, 0x00, 0x8d, 0x74, 0xfb, 0xcd, 0x02, 0x0a, 0x02, 0xe7, 0x06, 0xa6, 0xde, 0x7b, 0x02, 0xaf, 0x40, 0x4c, 0x10, 0xdb, 0x00, 0xfa, 0xec, 0x02, 0xd3, 0xea, 0xa6, 0xd9, 0x56, 0x1a, 0x15, 0x65, 0xa7, 0xb0, 0x5c, 0x63, 0x66, 0xd0, 0x9d, 0xa7, 0xa5, 0x37, 0xf2, 0x0c, 0x7b, 0x28, 0x59, 0xa8, 0x3e, 0x02, 0x9e, 0x13, 0xa9, 0xbd, 0x28, 0x91, 0x57, 0xc5, 0xb7, 0x4c, 0x84, 0xea, 0xa3, 0x07, 0x75, 0x3d, 0x43, 0x12, 0x02, 0xa3, 0xd9, 0xb6, 0x16, 0x22, 0x18, 0xbe, 0xc5, 0x34, 0x69, 0x45, 0xbf, 0xef, 0x55, 0xb6, 0x24, 0xc5, 0xc6, 0xe3, 0x73, 0x35, 0x9b, 0xb1, 0xc4, 0x79, 0x95, 0x2b, 0xba, 0xba, 0x4d, 0x65, 0x55, 0xc2, 0x76, 0x57, 0x3e, 0x51, 0x52, 0xb5, 0x53, 0x90, 0x19, 0x99, 0xf6, 0x94, 0x02, 0xd1, 0x50, 0xbe, 0xf7, 0x9d, 0x74, 0xfb, 0x29, 0x53, 0x01, 0x8f, 0xf4, 0x86, 0x66, 0x74, 0x6a, 0xce, 0x60, 0x78, 0x14, 0xa1, 0xfa, 0x33, 0x19, 0x57, 0x20, 0xf8, 0x38, 0x78, 0xd3, 0xb5, 0x75, 0xc7, 0x25, 0x74, 0x4a, 0x72, 0x07, 0x0d, 0xd0, 0x44, 0x01, 0x80, 0x42, 0xda, 0x25, 0x71, 0x4d, 0x17, 0x30, 0x90, 0x32, 0x3a, 0x51, 0xe6, 0xc0, 0x63, 0xd2, 0x03, 0x88, 0x13, 0x80, 0x91, 0x27, 0x61, 0xfc, 0x34, 0x10, 0x83, 0x90, 0x95, 0xf2, 0x6c, 0x0e, 0x68, 0x7a, 0x00, 0x70, 0x54, 0x95, 0xe1, 0x71, 0xb5, 0x71, 0x51, 0xac, 0xe0, 0x49, 0x8e, 0x30, 0xf1, 0x4c, 0xa9, 0xb0, 0x2f, 0x6e, 0x40, 0x83, 0x18, 0x54, 0xc2, 0xe0, 0xab, 0x1e, 0xcd, 0x0c, 0x21, 0xd8, 0xe4, 0xc7, 0xe6, 0x69, 0xcd, 0x72, 0x82, 0x30, 0xb9, 0xd1, 0x1f, 0x72, 0xc2, 0x66, 0xe3, 0x44, 0x66, 0xf9, 0xc0, 0x15, 0x9e, 0xf4, 0x24, 0xf8, 0xf3, 0x1d, 0x95, 0xa5, 0x7b, 0xa0, 0xe2, 0x10, 0x54, 0x3c, 0x10, 0xc6, 0x50, 0x3f, 0xb5, 0xc6, 0x3e, 0xd2, 0x3a, 0xa3, 0x6c, 0xd6, 0xa6, 0xf3, 0x78, 0x26, 0x1b, 0x0b, 0x1e, 0x79, 0x50, 0x9d, 0x8b, 0xeb, 0x36, 0xaa, 0x26, 0x3d, 0xc9, 0x15, 0x45, 0xe5, 0x33, 0x69, 0xdf, 0x26, 0x83, 0x7f, 0x39, 0x4c, 0x56, 0x77, 0x7c, 0x95, 0xb6, 0x48, 0xbd, 0x1a, 0x72, 0x92, 0x1a, 0xbf, 0x49, 0x56, 0x3f, 0x99, 0xcb, 0x9d, 0x98, 0xea, 0xb5, 0xc6, 0x66, 0x66, 0xf6, 0xb1, 0x6f, 0x74, 0x02, 0x24, 0x81, 0xfa, 0x21, 0x4e, 0x61, 0x76, 0x98, 0xd3, 0xbb, 0xd1, 0x3c, 0xb3, 0x08, 0x71, 0x3f, 0xdc, 0xc7, 0xcf, 0xd3, 0x97, 0xb9, 0xca, 0x39, 0xaf, 0xf4, 0xc7, 0x44, 0xd5, 0x71, 0x5d, 0x58, 0x96, 0x6f, 0x2c, 0xf9, 0x70, 0x70, 0x15, 0xc8, 0xf3, 0x54, 0x3e, 0xd2, 0x86, 0xa3, 0xd8, 0xd5, 0xcb, 0xf6, 0x4a, 0xce, 0xdf, 0xc0, 0x29, 0x71, 0xa9, 0x10, 0x72, 0xc6, 0x9d, 0x2e, 0xf4, 0x98, 0x29, 0xf1, 0x03, 0x7f, 0x05, 0x0c, 0x5b, 0x92, 0x22, 0x98, 0x56, 0xcb, 0x12, 0xb4, 0x56, 0xcc, 0x09, 0x52, 0x82, 0xa6, 0x26, 0x87, 0xea, 0x38, 0xc9, 0x77, 0x8a, 0xea, 0x49, 0x1d, 0xff, 0x06, 0x97, 0x11, 0xfb, 0xbe, 0x05, 0xe8, 0xcd, 0x9b, 0xf4, 0x4a, 0x8e, 0x71, 0x26, 0x19, 0x57, 0x3e, 0x12, 0xea, 0xa7, 0xb2, 0x38, 0x29, 0xdc, 0x67, 0x26, 0xbf, 0xe3, 0x3d, 0xa1, 0x36, 0xb8, 0x1e, 0x15, 0x32, 0x51, 0x50, 0x8f, 0x62, 0x85, 0xba, 0x15, 0xb2, 0xc1, 0x23, 0x76, 0x77, 0xfe, 0x5b, 0x14, 0xb4, 0xe3, 0x3f, 0x98, 0xc3, 0x26, 0xbc, 0x58, 0xb9, 0xd8, 0xe0, 0x75, 0xa2, 0x5b, 0x94, 0xc8, 0xa2, 0x32, 0x33, 0x02, 0x9d, 0xcc, 0x78, 0x6b, 0x13, 0x5c, 0x56, 0x16, 0x4b, 0xa3, 0xd1, 0x60, 0xcb, 0xce, 0xa8, 0x54, 0xb7, 0x97, 0x1f, 0x9c, 0xd7, 0x3a, 0x38, 0x3a, 0xac, 0x05, 0x0a, 0x30, 0x2a, 0xd8, 0x3b, 0x3e, 0x3a, 0xb9, 0x02, 0x46, 0xad, 0x16, 0x0a, 0x32, 0x1d, 0x33, 0x0a, 0xcd, 0xec, 0x7c, 0xa6, 0x64, 0x3d, 0x7e, 0xc0, 0x1f, 0x91, 0x69, 0x1f, 0x16, 0x32, 0x5b, 0xdf, 0x39, 0x69, 0x50, 0xb8, 0x8d, 0xaf, 0xe3, 0x69, 0xc6, 0x54, 0xb8, 0x52, 0x05, 0x5c, 0x97, 0x03, 0x62, 0xc6, 0x13, 0x80, 0x46, 0x07, 0x57, 0xc6, 0x58, 0x90, 0xf4, 0xe5, 0x92, 0x22, 0xe4, 0xa4, 0x06, 0x0b, 0x26, 0xc0, 0xeb, 0xc1, 0x01, 0x97, 0x59, 0x0d, 0xe3, 0xc8, 0xf0, 0x95, 0x5d, 0x65, 0x4b, 0x37, 0x1c, 0xcb, 0x90, 0xac, 0xa3, 0x71, 0xb2, 0x94, 0x47, 0x6c, 0x16, 0xa4, 0x59, 0x6a, 0x1d, 0xe8, 0x30, 0x9e, 0x2a, 0x36, 0x12, 0xc6, 0x9b, 0x71, 0x25, 0x31, 0x05, 0x01, 0xe0, 0xc0, 0x49, 0xb8, 0x74, 0x40, 0xd9, 0xa6, 0xd0, 0xec, 0xb9, 0x99, 0xc9, 0xa0, 0x94, 0x2a, 0xa3, 0x40, 0xf6, 0x03, 0x65, 0xea, 0xfd, 0x46, 0x5f, 0xc6, 0x4a, 0x0c, 0x5f, 0x8f, 0x3f, 0x90, 0x03, 0x48, 0x94, 0x15, 0x89, 0x9d, 0x59, 0xa5, 0x43, 0xd8, 0x20, 0x8c, 0x54, 0xa3, 0x16, 0x65, 0x29, 0xb5, 0x39, 0x22, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, }, .spki_len = 1219, .spki = { 0x30, 0x82, 0x04, 0xbf, 0x30, 0x0f, 0x06, 0x0b, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x02, 0x82, 0x0b, 0x05, 0x03, 0x03, 0x05, 0x00, 0x03, 0x82, 0x04, 0xaa, 0x00, 0x30, 0x82, 0x04, 0xa5, 0x03, 0x82, 0x04, 0xa1, 0x00, 0xa0, 0xb7, 0x1f, 0x67, 0xc6, 0xce, 0xc0, 0xd3, 0x56, 0x86, 0xd5, 0x13, 0x42, 0x34, 0x32, 0xe5, 0x12, 0xac, 0x40, 0x44, 0x55, 0x7e, 0x86, 0x8a, 0x62, 0x48, 0x00, 0x10, 0x9a, 0x33, 0x55, 0xf9, 0x8f, 0x15, 0x14, 0x44, 0xe2, 0x85, 0x2e, 0x27, 0xea, 0x6e, 0xdb, 0x19, 0x92, 0xca, 0xd3, 0x97, 0x3c, 0x3a, 0x6f, 0xf7, 0x9a, 0x5a, 0x04, 0x9a, 0x25, 0x9e, 0xb5, 0x41, 0x5a, 0xa2, 0xa2, 0x62, 0x45, 0x6e, 0xc9, 0x49, 0x5b, 0xbb, 0x52, 0x00, 0xd8, 0xd3, 0x16, 0x3a, 0x5b, 0x10, 0x22, 0x62, 0x92, 0xec, 0xa0, 0x10, 0x21, 0x38, 0x9d, 0xa3, 0x78, 0x81, 0xe2, 0x76, 0x30, 0x65, 0x50, 0xc6, 0xef, 0xb6, 0x44, 0x0e, 0xc5, 0x1a, 0x2f, 0x73, 0x48, 0x34, 0x9b, 0x85, 0x1c, 0xd4, 0xaa, 0x01, 0x75, 0xa0, 0x55, 0x02, 0x13, 0xc4, 0x79, 0x1d, 0x91, 0x01, 0x12, 0x20, 0x82, 0x4b, 0x2b, 0x61, 0x65, 0x08, 0x13, 0xad, 0xfd, 0x2c, 0xb1, 0x05, 0x38, 0xbf, 0xab, 0x0a, 0x72, 0x6f, 0x81, 0x12, 0x9e, 0xd2, 0xc0, 0xf0, 0x6a, 0x16, 0xb7, 0x01, 0x09, 0x0b, 0xf0, 0x48, 0xc5, 0xa4, 0x01, 0x26, 0xd5, 0x72, 0xfc, 0xd4, 0x7a, 0xa1, 0x21, 0x8f, 0xb0, 0x15, 0x47, 0xd1, 0x50, 0x79, 0x2d, 0x23, 0x16, 0xcb, 0x32, 0x0d, 0x51, 0x44, 0xba, 0x35, 0x08, 0xa1, 0xeb, 0xbb, 0x5a, 0xc1, 0xc2, 0x29, 0x13, 0xe8, 0x29, 0x5f, 0xab, 0x59, 0xbf, 0x58, 0x37, 0xa7, 0x78, 0xcf, 0x28, 0x22, 0x7e, 0x07, 0xe1, 0x03, 0x2d, 0xab, 0x7d, 0x0e, 0x09, 0xa1, 0x5f, 0x13, 0x41, 0x48, 0xc1, 0x20, 0x09, 0xda, 0x53, 0x6b, 0x22, 0xcc, 0x62, 0x47, 0x4e, 0x69, 0xcc, 0x15, 0x54, 0xc0, 0x81, 0x4d, 0x6c, 0xa0, 0xb7, 0x22, 0x59, 0x43, 0x83, 0xa9, 0xd0, 0xa2, 0xc7, 0x7f, 0xd3, 0x65, 0xa5, 0x54, 0x42, 0x95, 0xfb, 0xb9, 0x73, 0xf9, 0x1e, 0xa5, 0x64, 0x90, 0xd6, 0xca, 0x68, 0x76, 0x49, 0x7b, 0x98, 0xb3, 0xcb, 0x12, 0x41, 0x7c, 0x25, 0x7b, 0x6d, 0x0f, 0x71, 0x83, 0xdb, 0xb6, 0x9e, 0x33, 0x07, 0x5b, 0xeb, 0x01, 0x17, 0xb6, 0x91, 0x4c, 0x69, 0xba, 0x38, 0x34, 0x94, 0x22, 0xf2, 0xf4, 0x33, 0x64, 0x82, 0x2a, 0x25, 0x70, 0x95, 0x2d, 0xd5, 0x07, 0x7b, 0x90, 0x75, 0x5f, 0x15, 0x74, 0x11, 0x5b, 0x8e, 0x22, 0x14, 0x27, 0x58, 0x59, 0x61, 0x91, 0x3a, 0x9b, 0xfa, 0x05, 0x02, 0xb5, 0xd7, 0x9a, 0xb7, 0x81, 0x17, 0x44, 0xe6, 0x56, 0x3c, 0x5b, 0x62, 0xc5, 0xcc, 0x4e, 0x93, 0x23, 0x9a, 0x0a, 0x8c, 0xc6, 0x0f, 0xe8, 0x48, 0xf8, 0x4a, 0x95, 0xf5, 0x90, 0x25, 0x99, 0xb5, 0x4a, 0x06, 0x62, 0x93, 0xa2, 0x02, 0x1d, 0xa1, 0x96, 0x76, 0x6c, 0x17, 0xc7, 0xe8, 0x63, 0xaf, 0x79, 0x0c, 0x27, 0x0b, 0x21, 0x6a, 0x25, 0x13, 0x8d, 0xda, 0x0c, 0x81, 0x26, 0xe0, 0x93, 0x77, 0x87, 0x98, 0x59, 0xdb, 0x35, 0x8f, 0x9b, 0x82, 0xb7, 0xc8, 0xa6, 0x79, 0x2a, 0xce, 0xe9, 0x2a, 0x4c, 0xbd, 0xe3, 0xce, 0xdd, 0x45, 0x00, 0xac, 0xbc, 0x55, 0x5c, 0x28, 0x8e, 0xff, 0x97, 0x95, 0x26, 0x5b, 0x90, 0x05, 0x35, 0x1c, 0x52, 0xe2, 0x65, 0x35, 0x54, 0xab, 0xaa, 0xf8, 0x72, 0xdf, 0x95, 0xca, 0x7f, 0x79, 0x59, 0x03, 0xf0, 0xb0, 0xa1, 0x82, 0xb1, 0x8a, 0xeb, 0x04, 0x75, 0xb2, 0x9f, 0x6e, 0x3a, 0xbf, 0x4c, 0x22, 0x50, 0xfe, 0x7b, 0x84, 0x2a, 0x73, 0x65, 0x50, 0x16, 0xa8, 0xfc, 0x72, 0x9f, 0x39, 0x05, 0x07, 0xac, 0xa9, 0x36, 0x82, 0x5a, 0x98, 0xb3, 0xa3, 0x2e, 0x6b, 0x25, 0x54, 0xce, 0x95, 0x28, 0x94, 0x1a, 0x3b, 0xb8, 0xc9, 0x09, 0x96, 0x00, 0x8d, 0x74, 0xfb, 0xcd, 0x02, 0x0a, 0x02, 0xe7, 0x06, 0xa6, 0xde, 0x7b, 0x02, 0xaf, 0x40, 0x4c, 0x10, 0xdb, 0x00, 0xfa, 0xec, 0x02, 0xd3, 0xea, 0xa6, 0xd9, 0x56, 0x1a, 0x15, 0x65, 0xa7, 0xb0, 0x5c, 0x63, 0x66, 0xd0, 0x9d, 0xa7, 0xa5, 0x37, 0xf2, 0x0c, 0x7b, 0x28, 0x59, 0xa8, 0x3e, 0x02, 0x9e, 0x13, 0xa9, 0xbd, 0x28, 0x91, 0x57, 0xc5, 0xb7, 0x4c, 0x84, 0xea, 0xa3, 0x07, 0x75, 0x3d, 0x43, 0x12, 0x02, 0xa3, 0xd9, 0xb6, 0x16, 0x22, 0x18, 0xbe, 0xc5, 0x34, 0x69, 0x45, 0xbf, 0xef, 0x55, 0xb6, 0x24, 0xc5, 0xc6, 0xe3, 0x73, 0x35, 0x9b, 0xb1, 0xc4, 0x79, 0x95, 0x2b, 0xba, 0xba, 0x4d, 0x65, 0x55, 0xc2, 0x76, 0x57, 0x3e, 0x51, 0x52, 0xb5, 0x53, 0x90, 0x19, 0x99, 0xf6, 0x94, 0x02, 0xd1, 0x50, 0xbe, 0xf7, 0x9d, 0x74, 0xfb, 0x29, 0x53, 0x01, 0x8f, 0xf4, 0x86, 0x66, 0x74, 0x6a, 0xce, 0x60, 0x78, 0x14, 0xa1, 0xfa, 0x33, 0x19, 0x57, 0x20, 0xf8, 0x38, 0x78, 0xd3, 0xb5, 0x75, 0xc7, 0x25, 0x74, 0x4a, 0x72, 0x07, 0x0d, 0xd0, 0x44, 0x01, 0x80, 0x42, 0xda, 0x25, 0x71, 0x4d, 0x17, 0x30, 0x90, 0x32, 0x3a, 0x51, 0xe6, 0xc0, 0x63, 0xd2, 0x03, 0x88, 0x13, 0x80, 0x91, 0x27, 0x61, 0xfc, 0x34, 0x10, 0x83, 0x90, 0x95, 0xf2, 0x6c, 0x0e, 0x68, 0x7a, 0x00, 0x70, 0x54, 0x95, 0xe1, 0x71, 0xb5, 0x71, 0x51, 0xac, 0xe0, 0x49, 0x8e, 0x30, 0xf1, 0x4c, 0xa9, 0xb0, 0x2f, 0x6e, 0x40, 0x83, 0x18, 0x54, 0xc2, 0xe0, 0xab, 0x1e, 0xcd, 0x0c, 0x21, 0xd8, 0xe4, 0xc7, 0xe6, 0x69, 0xcd, 0x72, 0x82, 0x30, 0xb9, 0xd1, 0x1f, 0x72, 0xc2, 0x66, 0xe3, 0x44, 0x66, 0xf9, 0xc0, 0x15, 0x9e, 0xf4, 0x24, 0xf8, 0xf3, 0x1d, 0x95, 0xa5, 0x7b, 0xa0, 0xe2, 0x10, 0x54, 0x3c, 0x10, 0xc6, 0x50, 0x3f, 0xb5, 0xc6, 0x3e, 0xd2, 0x3a, 0xa3, 0x6c, 0xd6, 0xa6, 0xf3, 0x78, 0x26, 0x1b, 0x0b, 0x1e, 0x79, 0x50, 0x9d, 0x8b, 0xeb, 0x36, 0xaa, 0x26, 0x3d, 0xc9, 0x15, 0x45, 0xe5, 0x33, 0x69, 0xdf, 0x26, 0x83, 0x7f, 0x39, 0x4c, 0x56, 0x77, 0x7c, 0x95, 0xb6, 0x48, 0xbd, 0x1a, 0x72, 0x92, 0x1a, 0xbf, 0x49, 0x56, 0x3f, 0x99, 0xcb, 0x9d, 0x98, 0xea, 0xb5, 0xc6, 0x66, 0x66, 0xf6, 0xb1, 0x6f, 0x74, 0x02, 0x24, 0x81, 0xfa, 0x21, 0x4e, 0x61, 0x76, 0x98, 0xd3, 0xbb, 0xd1, 0x3c, 0xb3, 0x08, 0x71, 0x3f, 0xdc, 0xc7, 0xcf, 0xd3, 0x97, 0xb9, 0xca, 0x39, 0xaf, 0xf4, 0xc7, 0x44, 0xd5, 0x71, 0x5d, 0x58, 0x96, 0x6f, 0x2c, 0xf9, 0x70, 0x70, 0x15, 0xc8, 0xf3, 0x54, 0x3e, 0xd2, 0x86, 0xa3, 0xd8, 0xd5, 0xcb, 0xf6, 0x4a, 0xce, 0xdf, 0xc0, 0x29, 0x71, 0xa9, 0x10, 0x72, 0xc6, 0x9d, 0x2e, 0xf4, 0x98, 0x29, 0xf1, 0x03, 0x7f, 0x05, 0x0c, 0x5b, 0x92, 0x22, 0x98, 0x56, 0xcb, 0x12, 0xb4, 0x56, 0xcc, 0x09, 0x52, 0x82, 0xa6, 0x26, 0x87, 0xea, 0x38, 0xc9, 0x77, 0x8a, 0xea, 0x49, 0x1d, 0xff, 0x06, 0x97, 0x11, 0xfb, 0xbe, 0x05, 0xe8, 0xcd, 0x9b, 0xf4, 0x4a, 0x8e, 0x71, 0x26, 0x19, 0x57, 0x3e, 0x12, 0xea, 0xa7, 0xb2, 0x38, 0x29, 0xdc, 0x67, 0x26, 0xbf, 0xe3, 0x3d, 0xa1, 0x36, 0xb8, 0x1e, 0x15, 0x32, 0x51, 0x50, 0x8f, 0x62, 0x85, 0xba, 0x15, 0xb2, 0xc1, 0x23, 0x76, 0x77, 0xfe, 0x5b, 0x14, 0xb4, 0xe3, 0x3f, 0x98, 0xc3, 0x26, 0xbc, 0x58, 0xb9, 0xd8, 0xe0, 0x75, 0xa2, 0x5b, 0x94, 0xc8, 0xa2, 0x32, 0x33, 0x02, 0x9d, 0xcc, 0x78, 0x6b, 0x13, 0x5c, 0x56, 0x16, 0x4b, 0xa3, 0xd1, 0x60, 0xcb, 0xce, 0xa8, 0x54, 0xb7, 0x97, 0x1f, 0x9c, 0xd7, 0x3a, 0x38, 0x3a, 0xac, 0x05, 0x0a, 0x30, 0x2a, 0xd8, 0x3b, 0x3e, 0x3a, 0xb9, 0x02, 0x46, 0xad, 0x16, 0x0a, 0x32, 0x1d, 0x33, 0x0a, 0xcd, 0xec, 0x7c, 0xa6, 0x64, 0x3d, 0x7e, 0xc0, 0x1f, 0x91, 0x69, 0x1f, 0x16, 0x32, 0x5b, 0xdf, 0x39, 0x69, 0x50, 0xb8, 0x8d, 0xaf, 0xe3, 0x69, 0xc6, 0x54, 0xb8, 0x52, 0x05, 0x5c, 0x97, 0x03, 0x62, 0xc6, 0x13, 0x80, 0x46, 0x07, 0x57, 0xc6, 0x58, 0x90, 0xf4, 0xe5, 0x92, 0x22, 0xe4, 0xa4, 0x06, 0x0b, 0x26, 0xc0, 0xeb, 0xc1, 0x01, 0x97, 0x59, 0x0d, 0xe3, 0xc8, 0xf0, 0x95, 0x5d, 0x65, 0x4b, 0x37, 0x1c, 0xcb, 0x90, 0xac, 0xa3, 0x71, 0xb2, 0x94, 0x47, 0x6c, 0x16, 0xa4, 0x59, 0x6a, 0x1d, 0xe8, 0x30, 0x9e, 0x2a, 0x36, 0x12, 0xc6, 0x9b, 0x71, 0x25, 0x31, 0x05, 0x01, 0xe0, 0xc0, 0x49, 0xb8, 0x74, 0x40, 0xd9, 0xa6, 0xd0, 0xec, 0xb9, 0x99, 0xc9, 0xa0, 0x94, 0x2a, 0xa3, 0x40, 0xf6, 0x03, 0x65, 0xea, 0xfd, 0x46, 0x5f, 0xc6, 0x4a, 0x0c, 0x5f, 0x8f, 0x3f, 0x90, 0x03, 0x48, 0x94, 0x15, 0x89, 0x9d, 0x59, 0xa5, 0x43, 0xd8, 0x20, 0x8c, 0x54, 0xa3, 0x16, 0x65, 0x29, 0xb5, 0x39, 0x22, }, .secret_len = 32, .secret = { 0xed, 0x20, 0x14, 0x0c, 0x05, 0xd7, 0x8b, 0x15, 0xf2, 0xe4, 0x12, 0x67, 0x1a, 0x84, 0x15, 0x42, 0x17, 0xfd, 0x77, 0x61, 0x9a, 0x2c, 0x52, 0x2d, 0x3c, 0x3c, 0xb6, 0x88, 0xcb, 0x34, 0xc6, 0x8b, }, .cipher_len = 1088, .cipher = { 0xea, 0xdd, 0x5a, 0xda, 0x14, 0xda, 0x57, 0xf0, 0xae, 0xf3, 0x50, 0x5f, 0x1c, 0xaa, 0x64, 0x85, 0xd4, 0x23, 0x8d, 0x99, 0x9a, 0x3e, 0xf4, 0xb0, 0xa5, 0x9a, 0x1c, 0xdb, 0xe0, 0xa2, 0x7e, 0x47, 0x85, 0x47, 0xa3, 0xa9, 0x9d, 0x2a, 0xb0, 0x9a, 0xc7, 0xd7, 0xc8, 0xf5, 0xae, 0x3d, 0x64, 0x32, 0x04, 0x5c, 0xba, 0x3f, 0xa7, 0x78, 0x34, 0x58, 0x92, 0x54, 0x2b, 0xd8, 0x1c, 0x05, 0xbe, 0xfc, 0xd2, 0xe5, 0xcc, 0x9a, 0x57, 0x9b, 0xef, 0xb7, 0xc5, 0x8d, 0x02, 0xfb, 0x94, 0xf3, 0x33, 0x92, 0xfe, 0x17, 0xf4, 0xeb, 0xa2, 0xcb, 0x51, 0x0e, 0xc7, 0x4c, 0xc9, 0xd1, 0xd8, 0xa8, 0x7c, 0x10, 0x66, 0xa4, 0x86, 0x9a, 0x39, 0x83, 0xe6, 0x64, 0xbf, 0xe9, 0xde, 0xa5, 0xae, 0x4f, 0xdf, 0x31, 0x0c, 0x8f, 0x59, 0x81, 0x5a, 0x67, 0x8f, 0xa3, 0x25, 0xf3, 0x69, 0xaf, 0x84, 0xff, 0xeb, 0xc1, 0xd1, 0x50, 0x43, 0x1f, 0xe3, 0xbd, 0x27, 0x34, 0xf6, 0x36, 0xcf, 0x65, 0x8e, 0x6c, 0x1a, 0x6a, 0x6e, 0x2c, 0xbe, 0x07, 0x1f, 0x9a, 0x7c, 0x26, 0x11, 0x9a, 0xd1, 0x05, 0x09, 0x8e, 0xda, 0x62, 0x2c, 0xab, 0x8e, 0x17, 0x67, 0x62, 0x10, 0x98, 0x77, 0xd9, 0xae, 0x9d, 0x67, 0x29, 0xd4, 0x4a, 0x58, 0xe7, 0x07, 0xd6, 0xb8, 0xad, 0x6e, 0x69, 0x6a, 0x33, 0xc6, 0x72, 0xda, 0x9d, 0x08, 0xda, 0x2a, 0x7f, 0x9e, 0x3b, 0xf0, 0x22, 0x18, 0x23, 0x87, 0x22, 0xa4, 0x6b, 0x31, 0xd4, 0x9d, 0xaf, 0xf9, 0xaf, 0x00, 0xa6, 0x36, 0x3c, 0x3a, 0x42, 0x3b, 0x2e, 0x87, 0x3d, 0xef, 0xdd, 0xbc, 0xd9, 0x69, 0xb7, 0x5a, 0x81, 0x05, 0x3d, 0x9a, 0x97, 0xc0, 0x6d, 0xe2, 0xbf, 0xe3, 0xd0, 0xcf, 0xd3, 0xd3, 0xc7, 0x79, 0x83, 0xb1, 0x8d, 0xbd, 0xe2, 0x3c, 0x07, 0x28, 0x60, 0x4a, 0x71, 0x43, 0x5a, 0xd4, 0x0d, 0xf1, 0x57, 0x90, 0x96, 0xdd, 0xbe, 0x02, 0xe4, 0x61, 0x22, 0x10, 0xca, 0xa0, 0x34, 0xdc, 0xef, 0xb8, 0xb4, 0xd7, 0xb5, 0xe6, 0xd2, 0xeb, 0xa3, 0x7a, 0x79, 0xfb, 0x61, 0xf3, 0x4b, 0x5a, 0xf7, 0xd9, 0xb2, 0x7b, 0x13, 0xe4, 0x93, 0x62, 0x22, 0x41, 0x12, 0x49, 0xb7, 0xfb, 0xb6, 0x9e, 0x73, 0x46, 0x1d, 0xaf, 0x4a, 0xa6, 0xf3, 0xe2, 0xc7, 0x39, 0x44, 0xf1, 0x0c, 0xe6, 0x7c, 0x86, 0xfe, 0xd2, 0x60, 0xbd, 0xa7, 0xb4, 0x0d, 0xb3, 0x9b, 0x1d, 0xe3, 0xc7, 0xd8, 0xf0, 0x9a, 0x77, 0xf3, 0xc8, 0x4b, 0xc6, 0x29, 0x31, 0xd2, 0x28, 0xb2, 0x4a, 0x57, 0x4a, 0xc3, 0xf4, 0xeb, 0x74, 0x5c, 0xff, 0x7e, 0x03, 0x1a, 0x3f, 0xb2, 0xa0, 0x85, 0x95, 0xc1, 0x53, 0x70, 0xa3, 0xc8, 0x2d, 0xb7, 0xd9, 0xf4, 0x1b, 0xb1, 0xd8, 0xec, 0xc4, 0x29, 0xcf, 0xa3, 0xa6, 0x58, 0x33, 0x01, 0x6a, 0xb6, 0xea, 0x60, 0xc9, 0x39, 0x0c, 0xfa, 0x1b, 0x65, 0xcc, 0xea, 0xe5, 0x50, 0x94, 0x07, 0x95, 0x38, 0x6e, 0xd2, 0x41, 0x33, 0xfb, 0xae, 0x8b, 0x30, 0x17, 0x50, 0x2a, 0xf3, 0xcf, 0xe9, 0x51, 0xd7, 0x81, 0xd3, 0x6c, 0xfe, 0xff, 0x85, 0xbf, 0xdf, 0x5a, 0xf0, 0x40, 0xbe, 0x40, 0x65, 0x68, 0x1b, 0x3b, 0x0a, 0x63, 0xc2, 0x74, 0x7f, 0x08, 0x08, 0xcf, 0x3d, 0xa7, 0x25, 0x16, 0x9d, 0xde, 0xd1, 0x00, 0x3d, 0xa6, 0xcd, 0x5d, 0xe4, 0xcb, 0x04, 0x19, 0x42, 0x93, 0x8d, 0x0a, 0x7f, 0x88, 0x02, 0xd4, 0x8f, 0x2e, 0x3c, 0x6e, 0xeb, 0x45, 0xcd, 0x90, 0xaf, 0x6f, 0xc9, 0xf4, 0x50, 0x7e, 0x9f, 0x83, 0x80, 0xac, 0x33, 0xca, 0xca, 0x77, 0x51, 0x48, 0x7f, 0x65, 0x50, 0x04, 0x41, 0xd9, 0x20, 0xb9, 0x48, 0x80, 0xa4, 0x97, 0xd0, 0x1c, 0x08, 0x02, 0xbb, 0x08, 0xd7, 0x4c, 0x5d, 0x4c, 0x6b, 0xf2, 0xd8, 0x65, 0xee, 0x58, 0x22, 0xb3, 0x37, 0x5c, 0x75, 0x5d, 0x1a, 0x5e, 0x3d, 0x32, 0x44, 0xc3, 0x20, 0x51, 0x0a, 0x1e, 0x30, 0x35, 0x77, 0x02, 0xcd, 0x42, 0x52, 0x07, 0x2c, 0xf8, 0x64, 0x37, 0xf7, 0xa9, 0xde, 0x55, 0x61, 0xc7, 0xe5, 0x9b, 0x94, 0xb9, 0x58, 0x41, 0x00, 0x13, 0x1a, 0xc3, 0x99, 0xf4, 0xc1, 0xeb, 0x19, 0xfb, 0x4b, 0xdf, 0x65, 0xe6, 0x27, 0x85, 0xe9, 0x7c, 0x19, 0x4b, 0x87, 0x64, 0xcc, 0xf3, 0x2f, 0xd0, 0x5d, 0x80, 0x4c, 0x2e, 0x43, 0x9d, 0xda, 0x2a, 0x10, 0x92, 0x74, 0xfb, 0xff, 0xa8, 0x1a, 0x83, 0x7c, 0x51, 0xb2, 0x6d, 0x15, 0x4f, 0x97, 0x4b, 0x88, 0x2a, 0x5b, 0x17, 0x4b, 0x30, 0x8f, 0xc4, 0x87, 0x68, 0xd2, 0x22, 0x92, 0x25, 0x32, 0xb1, 0x83, 0xab, 0xdf, 0x6f, 0xbb, 0x0b, 0xc7, 0x49, 0x27, 0x66, 0x97, 0x4d, 0x32, 0x1e, 0xe6, 0xfb, 0x7c, 0x5f, 0x7b, 0x3e, 0xea, 0x23, 0x78, 0xdc, 0x6d, 0x6b, 0xb4, 0x80, 0x19, 0x25, 0x0b, 0x8d, 0x8d, 0x8d, 0xed, 0xb5, 0x22, 0x42, 0x1a, 0xee, 0xdb, 0x31, 0x86, 0x76, 0x98, 0x2a, 0x80, 0xe7, 0x96, 0x1e, 0xc4, 0x0e, 0x6d, 0x7f, 0x33, 0x39, 0x69, 0x42, 0x55, 0xba, 0xff, 0x51, 0xbe, 0x3a, 0x7e, 0xa7, 0xd8, 0x79, 0x3a, 0x10, 0x9b, 0xe3, 0xae, 0x44, 0x23, 0xbf, 0x08, 0x2e, 0x20, 0x6a, 0x57, 0x3b, 0x4f, 0x0f, 0x93, 0xfc, 0x16, 0xdd, 0xe8, 0x1b, 0xd5, 0xdc, 0x58, 0x3f, 0x52, 0x8c, 0x08, 0xa0, 0xa9, 0xab, 0x8e, 0x6c, 0xd5, 0x24, 0xe2, 0x97, 0xc9, 0xcf, 0x0f, 0x43, 0xc3, 0x44, 0x91, 0x38, 0x30, 0xec, 0xb1, 0x6f, 0x91, 0x44, 0x14, 0x77, 0xba, 0x78, 0x2e, 0xdd, 0x4e, 0x73, 0xe7, 0x32, 0x97, 0x9d, 0x3a, 0x66, 0x4e, 0xb9, 0x9e, 0xa5, 0xd2, 0x4b, 0x6c, 0x84, 0xaa, 0x69, 0xf3, 0x77, 0xcb, 0x0c, 0xad, 0x5a, 0xe4, 0xe6, 0x41, 0xe3, 0x8b, 0x19, 0x7a, 0x09, 0x94, 0xd5, 0x8b, 0x23, 0x87, 0xe9, 0x17, 0x60, 0xe9, 0xb6, 0xfe, 0xbc, 0xb4, 0x45, 0xcf, 0x85, 0xbb, 0xa2, 0x4a, 0x94, 0xcd, 0xa7, 0x5e, 0x33, 0x86, 0x74, 0x42, 0x82, 0x49, 0xfe, 0x6d, 0xe4, 0x69, 0x26, 0x01, 0xd1, 0xea, 0xe0, 0xea, 0x02, 0x1d, 0x9b, 0xc8, 0x07, 0x7b, 0xe8, 0x66, 0x5d, 0x07, 0x37, 0x74, 0x8f, 0xa3, 0x0f, 0xcf, 0x80, 0xf7, 0xe4, 0x82, 0x58, 0x46, 0x74, 0xf6, 0x33, 0xa5, 0x00, 0x6a, 0x53, 0x82, 0x67, 0x62, 0x7f, 0xd9, 0x18, 0x54, 0xe0, 0x87, 0x12, 0x68, 0xa6, 0xb0, 0xb0, 0x5d, 0xd5, 0x14, 0x95, 0x13, 0x5d, 0xef, 0xb9, 0x37, 0x6e, 0x9b, 0x84, 0x1b, 0x64, 0xe5, 0xdb, 0xf4, 0x3c, 0xe6, 0xc7, 0x4b, 0xcf, 0x3a, 0xe1, 0xfc, 0x42, 0x7e, 0x81, 0x0b, 0x7c, 0xbf, 0x69, 0x57, 0xdb, 0xf9, 0x04, 0x69, 0x0e, 0x87, 0x84, 0x25, 0x43, 0x89, 0x7d, 0xe7, 0x8f, 0x13, 0xd0, 0x8d, 0x92, 0xeb, 0xd2, 0x7f, 0xb2, 0xcf, 0xcc, 0x0c, 0x76, 0x54, 0x30, 0x58, 0x90, 0x57, 0xb1, 0x6b, 0x15, 0xf2, 0x07, 0xca, 0x1e, 0x6f, 0x08, 0xd5, 0x26, 0x16, 0xdd, 0x57, 0xad, 0x43, 0xef, 0xea, 0x6f, 0xdd, 0xaa, 0xea, 0x18, 0xd3, 0x37, 0x31, 0xfa, 0xc7, 0xec, 0xaa, 0xe9, 0x50, 0xe1, 0xdf, 0x3c, 0x5a, 0x4e, 0x6f, 0xcb, 0x22, 0x3d, 0xf5, 0xe8, 0x6b, 0x48, 0x7f, 0xd7, 0x09, 0x2d, 0x08, 0x22, 0xef, 0xfa, 0xec, 0x82, 0xc4, 0xbe, 0xc1, 0x0c, 0x60, 0x0f, 0xdb, 0x90, 0xe7, 0x74, 0x82, 0x91, 0x1b, 0x15, 0x95, 0x27, 0x77, 0x38, 0x84, 0x14, 0x09, 0xd0, 0xf8, 0xf1, 0x13, 0x19, 0x1d, 0x47, 0xf5, 0xe5, 0x6c, 0x11, 0x5a, 0x05, 0xde, 0xa7, 0x59, 0xaa, 0x6f, 0xb1, 0xd0, 0x47, 0xf9, 0xfc, 0xa4, 0xed, 0x51, 0x9e, 0xa5, 0xd2, 0x1f, 0xe3, 0xba, 0x5b, 0x94, 0x34, 0xfe, 0xa1, 0x28, 0x3d, 0xfa, 0xd6, 0x3d, 0x01, 0x58, 0x9b, 0x0e, 0xb6, 0x1f, 0x24, 0x43, 0x51, 0xd0, 0x33, 0x41, 0xdc, 0xd4, 0xdf, 0x62, 0x26, 0x5a, 0xfc, 0xae, 0xc6, 0x67, 0x6a, 0x87, 0x7d, 0x5c, 0xac, 0xb3, 0x59, 0xeb, 0xb5, 0x31, 0x96, 0x10, 0xdd, 0x44, 0x7d, 0xa9, 0x7e, 0x95, 0x0b, 0x0c, }, }, { .name = "Kyber Round 2, 1024 KAT 0 (PKCS#8/SPKI)", .version = 0, .keyform = 0, .pk_len = 0, .sk_len = 0, .pkcs8_len = 4849, .pkcs8 = { 0x30, 0x82, 0x12, 0xed, 0x02, 0x01, 0x00, 0x30, 0x0f, 0x06, 0x0b, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x02, 0x82, 0x0b, 0x05, 0x04, 0x04, 0x05, 0x00, 0x04, 0x82, 0x12, 0xd5, 0x30, 0x82, 0x12, 0xd1, 0x02, 0x01, 0x00, 0x03, 0x82, 0x0c, 0x61, 0x00, 0x07, 0x63, 0x8f, 0xb6, 0x98, 0x68, 0xf3, 0xd3, 0x20, 0xe5, 0x86, 0x2b, 0xd9, 0x69, 0x33, 0xfe, 0xb3, 0x11, 0xb3, 0x62, 0x09, 0x3c, 0x9b, 0x5d, 0x50, 0x17, 0x0b, 0xce, 0xd4, 0x3f, 0x1b, 0x53, 0x6d, 0x9a, 0x20, 0x4b, 0xb1, 0xf2, 0x26, 0x95, 0x95, 0x0b, 0xa1, 0xf2, 0xa9, 0xe8, 0xeb, 0x82, 0x8b, 0x28, 0x44, 0x88, 0x76, 0x0b, 0x3f, 0xc8, 0x4f, 0xab, 0xa0, 0x42, 0x75, 0xd5, 0x62, 0x8e, 0x39, 0xc5, 0xb2, 0x47, 0x13, 0x74, 0x28, 0x3c, 0x50, 0x32, 0x99, 0xc0, 0xab, 0x49, 0xb6, 0x6b, 0x8b, 0xbb, 0x56, 0xa4, 0x18, 0x66, 0x24, 0xf9, 0x19, 0xa2, 0xba, 0x59, 0xbb, 0x08, 0xd8, 0x55, 0x18, 0x80, 0xc2, 0xbe, 0xfc, 0x4f, 0x87, 0xf2, 0x5f, 0x59, 0xab, 0x58, 0x7a, 0x79, 0xc3, 0x27, 0xd7, 0x92, 0xd5, 0x4c, 0x97, 0x4a, 0x69, 0x26, 0x2f, 0xf8, 0xa7, 0x89, 0x38, 0x28, 0x9e, 0x9a, 0x87, 0xb6, 0x88, 0xb0, 0x83, 0xe0, 0x59, 0x5f, 0xe2, 0x18, 0xb6, 0xbb, 0x15, 0x05, 0x94, 0x1c, 0xe2, 0xe8, 0x1a, 0x5a, 0x64, 0xc5, 0xaa, 0xc6, 0x04, 0x17, 0x25, 0x69, 0x85, 0x34, 0x9e, 0xe4, 0x7a, 0x52, 0x42, 0x0a, 0x5f, 0x97, 0x47, 0x7b, 0x72, 0x36, 0xac, 0x76, 0xbc, 0x70, 0xe8, 0x28, 0x87, 0x29, 0x28, 0x7e, 0xe3, 0xe3, 0x4a, 0x3d, 0xbc, 0x36, 0x83, 0xc0, 0xb7, 0xb1, 0x00, 0x29, 0xfc, 0x20, 0x34, 0x18, 0x53, 0x7e, 0x74, 0x66, 0xba, 0x63, 0x85, 0xa8, 0xff, 0x30, 0x1e, 0xe1, 0x27, 0x08, 0xf8, 0x2a, 0xaa, 0x1e, 0x38, 0x0f, 0xc7, 0xa8, 0x8f, 0x8f, 0x20, 0x5a, 0xb7, 0xe8, 0x8d, 0x7e, 0x95, 0x95, 0x2a, 0x55, 0xba, 0x20, 0xd0, 0x9b, 0x79, 0xa4, 0x71, 0x41, 0xd6, 0x2b, 0xf6, 0xeb, 0x7d, 0xd3, 0x07, 0xb0, 0x8e, 0xca, 0x13, 0xa5, 0xbc, 0x5f, 0x6b, 0x68, 0x58, 0x1c, 0x68, 0x65, 0xb2, 0x7b, 0xbc, 0xdd, 0xab, 0x14, 0x2f, 0x4b, 0x2c, 0xbf, 0xf4, 0x88, 0xc8, 0xa2, 0x27, 0x05, 0xfa, 0xa9, 0x8a, 0x2b, 0x9e, 0xea, 0x35, 0x30, 0xc7, 0x66, 0x62, 0x33, 0x5c, 0xc7, 0xea, 0x3a, 0x00, 0x77, 0x77, 0x25, 0xeb, 0xcc, 0xcd, 0x2a, 0x46, 0x36, 0xb2, 0xd9, 0x12, 0x2f, 0xf3, 0xab, 0x77, 0x12, 0x3c, 0xe0, 0x88, 0x3c, 0x19, 0x11, 0x11, 0x5e, 0x50, 0xc9, 0xe8, 0xa9, 0x41, 0x94, 0xe4, 0x8d, 0xd0, 0xd0, 0x9c, 0xff, 0xb3, 0xad, 0xcd, 0x2c, 0x1e, 0x92, 0x43, 0x09, 0x03, 0xd0, 0x7a, 0xdb, 0xf0, 0x05, 0x32, 0x03, 0x15, 0x75, 0xaa, 0x7f, 0x9e, 0x7b, 0x5a, 0x1f, 0x33, 0x62, 0xde, 0xc9, 0x36, 0xd4, 0x04, 0x3c, 0x05, 0xf2, 0x47, 0x6c, 0x07, 0x57, 0x8b, 0xc9, 0xcb, 0xaf, 0x2a, 0xb4, 0xe3, 0x82, 0x72, 0x7a, 0xd4, 0x16, 0x86, 0xa9, 0x6b, 0x25, 0x48, 0x82, 0x0b, 0xb0, 0x3b, 0x32, 0xf1, 0x1b, 0x28, 0x11, 0xad, 0x62, 0xf4, 0x89, 0xe9, 0x51, 0x63, 0x2a, 0xba, 0x0d, 0x1d, 0xf8, 0x96, 0x80, 0xcc, 0x8a, 0x8b, 0x53, 0xb4, 0x81, 0xd9, 0x2a, 0x68, 0xd7, 0x0b, 0x4e, 0xa1, 0xc3, 0xa6, 0xa5, 0x61, 0xc0, 0x69, 0x28, 0x82, 0xb5, 0xca, 0x8c, 0xc9, 0x42, 0xa8, 0xd4, 0x95, 0xaf, 0xcb, 0x06, 0xde, 0x89, 0x49, 0x8f, 0xb9, 0x35, 0xb7, 0x75, 0x90, 0x8f, 0xe7, 0xa0, 0x3e, 0x32, 0x4d, 0x54, 0xcc, 0x19, 0xd4, 0xe1, 0xaa, 0xbd, 0x35, 0x93, 0xb3, 0x8b, 0x19, 0xee, 0x13, 0x88, 0xfe, 0x49, 0x2b, 0x43, 0x12, 0x7e, 0x5a, 0x50, 0x42, 0x53, 0x78, 0x6a, 0x0d, 0x69, 0xad, 0x32, 0x60, 0x1c, 0x28, 0xe2, 0xc8, 0x85, 0x04, 0xa5, 0xba, 0x59, 0x97, 0x06, 0x02, 0x3a, 0x61, 0x36, 0x3e, 0x17, 0xc6, 0xb9, 0xbb, 0x59, 0xbd, 0xc6, 0x97, 0x45, 0x2c, 0xd0, 0x59, 0x45, 0x19, 0x83, 0xd7, 0x38, 0xca, 0x3f, 0xd0, 0x34, 0xe3, 0xf5, 0x98, 0x88, 0x54, 0xca, 0x05, 0x03, 0x1d, 0xb0, 0x96, 0x11, 0x49, 0x89, 0x88, 0x19, 0x7c, 0x6b, 0x30, 0xd2, 0x58, 0xdf, 0xe2, 0x62, 0x65, 0x54, 0x1c, 0x89, 0xa4, 0xb3, 0x1d, 0x68, 0x64, 0xe9, 0x38, 0x9b, 0x03, 0xcb, 0x74, 0xf7, 0xec, 0x43, 0x23, 0xfb, 0x94, 0x21, 0xa4, 0xb9, 0x79, 0x0a, 0x26, 0xd1, 0x7b, 0x03, 0x98, 0xa2, 0x67, 0x67, 0x35, 0x09, 0x09, 0xf8, 0x4d, 0x57, 0xb6, 0x69, 0x4d, 0xf8, 0x30, 0x66, 0x4c, 0xa8, 0xb3, 0xc3, 0xc0, 0x3e, 0xd2, 0xae, 0x67, 0xb8, 0x90, 0x06, 0x86, 0x8a, 0x68, 0x52, 0x7c, 0xcd, 0x66, 0x64, 0x59, 0xab, 0x7f, 0x05, 0x66, 0x71, 0x00, 0x0c, 0x61, 0x64, 0xd3, 0xa7, 0xf2, 0x66, 0xa1, 0x4d, 0x97, 0xcb, 0xd7, 0x00, 0x4d, 0x6c, 0x92, 0xca, 0xca, 0x77, 0x0b, 0x84, 0x4a, 0x4f, 0xa9, 0xb1, 0x82, 0xe7, 0xb1, 0x8c, 0xa8, 0x85, 0x08, 0x2a, 0xc5, 0x64, 0x6f, 0xcb, 0x4a, 0x14, 0xe1, 0x68, 0x5f, 0xeb, 0x0c, 0x9c, 0xe3, 0x37, 0x2a, 0xb9, 0x53, 0x65, 0xc0, 0x4f, 0xd8, 0x30, 0x84, 0xf8, 0x0a, 0x23, 0xff, 0x10, 0xa0, 0x5b, 0xf1, 0x5f, 0x7f, 0xa5, 0xac, 0xc6, 0xc0, 0xcb, 0x46, 0x2c, 0x33, 0xca, 0x52, 0x4f, 0xa6, 0xb8, 0xbb, 0x35, 0x90, 0x43, 0xba, 0x68, 0x60, 0x9e, 0xaa, 0x25, 0x36, 0xe8, 0x1d, 0x08, 0x46, 0x3b, 0x19, 0x65, 0x3b, 0x54, 0x35, 0xba, 0x94, 0x6c, 0x9a, 0xdd, 0xeb, 0x20, 0x2b, 0x04, 0xb0, 0x31, 0xcc, 0x96, 0x0d, 0xcc, 0x12, 0xe4, 0x51, 0x8d, 0x42, 0x8b, 0x32, 0xb2, 0x57, 0xa4, 0xfc, 0x73, 0x13, 0xd3, 0xa7, 0x98, 0x0d, 0x80, 0x08, 0x2e, 0x93, 0x4f, 0x9d, 0x95, 0xc3, 0x2b, 0x0a, 0x01, 0x91, 0xa2, 0x36, 0x04, 0x38, 0x4d, 0xd9, 0xe0, 0x79, 0xbb, 0xba, 0xa2, 0x66, 0xd1, 0x4c, 0x3f, 0x75, 0x6b, 0x9f, 0x21, 0x33, 0x10, 0x74, 0x33, 0xa4, 0xe8, 0x3f, 0xa7, 0x18, 0x72, 0x82, 0xa8, 0x09, 0x20, 0x3a, 0x4f, 0xaf, 0x84, 0x18, 0x51, 0x83, 0x3d, 0x12, 0x1a, 0xc3, 0x83, 0x84, 0x3a, 0x5e, 0x55, 0xbc, 0x23, 0x81, 0x42, 0x5e, 0x16, 0xc7, 0xdb, 0x4c, 0xc9, 0xab, 0x5c, 0x1b, 0x0d, 0x91, 0xa4, 0x7e, 0x2b, 0x8d, 0xe0, 0xe5, 0x82, 0xc8, 0x6b, 0x6b, 0x0d, 0x90, 0x7b, 0xb3, 0x60, 0xb9, 0x7f, 0x40, 0xab, 0x5d, 0x03, 0x8f, 0x6b, 0x75, 0xc8, 0x14, 0xb2, 0x7d, 0x9b, 0x96, 0x8d, 0x41, 0x98, 0x32, 0xbc, 0x8c, 0x2b, 0xee, 0x60, 0x5e, 0xf6, 0xe5, 0x05, 0x9d, 0x33, 0x10, 0x0d, 0x90, 0x48, 0x5d, 0x37, 0x84, 0x50, 0x01, 0x42, 0x21, 0x73, 0x6c, 0x07, 0x40, 0x7c, 0xac, 0x26, 0x04, 0x08, 0xaa, 0x64, 0x92, 0x66, 0x19, 0x78, 0x8b, 0x86, 0x01, 0xc2, 0xa7, 0x52, 0xd1, 0xa6, 0xcb, 0xf8, 0x20, 0xd7, 0xc7, 0xa0, 0x47, 0x16, 0x20, 0x32, 0x25, 0xb3, 0x89, 0x5b, 0x93, 0x42, 0xd1, 0x47, 0xa8, 0x18, 0x5c, 0xfc, 0x1b, 0xb6, 0x5b, 0xa0, 0x6b, 0x41, 0x42, 0x33, 0x99, 0x03, 0xc0, 0xac, 0x46, 0x51, 0x38, 0x5b, 0x45, 0xd9, 0x8a, 0x8b, 0x19, 0xd2, 0x8c, 0xd6, 0xba, 0xb0, 0x88, 0x78, 0x7f, 0x7e, 0xe1, 0xb1, 0x24, 0x61, 0x76, 0x6b, 0x43, 0xcb, 0xcc, 0xb9, 0x64, 0x34, 0x42, 0x7d, 0x93, 0xc0, 0x65, 0x55, 0x06, 0x88, 0xf6, 0x94, 0x8e, 0xd1, 0xb5, 0x47, 0x5a, 0x42, 0x5f, 0x1b, 0x85, 0x20, 0x9d, 0x06, 0x1c, 0x08, 0xb5, 0x6c, 0x1c, 0xc0, 0x69, 0xf6, 0xc0, 0xa7, 0xc6, 0xf2, 0x93, 0x58, 0xca, 0xb9, 0x11, 0x08, 0x77, 0x32, 0xa6, 0x49, 0xd2, 0x7c, 0x9b, 0x98, 0xf9, 0xa4, 0x88, 0x79, 0x38, 0x7d, 0x9b, 0x00, 0xc2, 0x59, 0x59, 0xa7, 0x16, 0x54, 0xd6, 0xf6, 0xa9, 0x46, 0x16, 0x45, 0x13, 0xe4, 0x7a, 0x75, 0xd0, 0x05, 0x98, 0x6c, 0x23, 0x63, 0xc0, 0x9f, 0x6b, 0x53, 0x7e, 0xca, 0x78, 0xb9, 0x30, 0x3a, 0x5f, 0xa4, 0x57, 0x60, 0x8a, 0x58, 0x6a, 0x65, 0x3a, 0x34, 0x7d, 0xb0, 0x4d, 0xfc, 0xc1, 0x91, 0x75, 0xb3, 0xa3, 0x01, 0x17, 0x25, 0x36, 0x06, 0x2a, 0x65, 0x8a, 0x95, 0x27, 0x75, 0x70, 0xc8, 0x85, 0x2c, 0xa8, 0x97, 0x3f, 0x4a, 0xe1, 0x23, 0xa3, 0x34, 0x04, 0x7d, 0xd7, 0x11, 0xc8, 0x92, 0x7a, 0x63, 0x4a, 0x03, 0x38, 0x8a, 0x52, 0x7b, 0x03, 0x4b, 0xf7, 0xa8, 0x17, 0x0f, 0xa7, 0x02, 0xc1, 0xf7, 0xc2, 0x3e, 0xc3, 0x2d, 0x18, 0xa2, 0x37, 0x48, 0x90, 0xbe, 0x9c, 0x78, 0x7a, 0x94, 0x09, 0xc8, 0x2d, 0x19, 0x2c, 0x4b, 0xb7, 0x05, 0xa2, 0xf9, 0x96, 0xce, 0x40, 0x5d, 0x85, 0xa4, 0xc1, 0xa1, 0xab, 0x9b, 0x6a, 0xeb, 0x49, 0xcc, 0xe1, 0xc2, 0xf8, 0xa9, 0x7c, 0x35, 0x16, 0xc7, 0x2a, 0x00, 0xa4, 0x62, 0x63, 0xba, 0xa6, 0x96, 0xbf, 0x25, 0x72, 0x77, 0x19, 0xc3, 0x21, 0x64, 0x23, 0x61, 0x8f, 0xf3, 0x33, 0x80, 0x93, 0x4a, 0x6c, 0x10, 0x54, 0x5c, 0x4c, 0x5c, 0x51, 0x55, 0xb1, 0x24, 0x86, 0x18, 0x1f, 0xc7, 0xa2, 0x31, 0x98, 0x73, 0x97, 0x8b, 0x6a, 0x2a, 0x67, 0x49, 0x0f, 0x82, 0x56, 0xbd, 0x21, 0x96, 0xfe, 0x17, 0x92, 0xa4, 0xc0, 0x00, 0x77, 0xb8, 0x12, 0xea, 0xe8, 0xbe, 0xd3, 0x57, 0x24, 0x99, 0x68, 0x4a, 0xb3, 0x37, 0x18, 0x76, 0x76, 0x1e, 0x45, 0x0c, 0x9f, 0x9d, 0x27, 0x68, 0xa3, 0x68, 0x06, 0xd7, 0xab, 0x20, 0x46, 0xc9, 0x1f, 0x17, 0x59, 0x9e, 0x9a, 0xc5, 0x92, 0x99, 0x08, 0x08, 0xdc, 0xd7, 0xb4, 0xd0, 0x91, 0x90, 0x72, 0xf1, 0x4e, 0xc3, 0x61, 0x77, 0x3b, 0x72, 0x52, 0x44, 0x4c, 0x32, 0x3c, 0x30, 0x83, 0x26, 0xf4, 0xa3, 0x0f, 0x86, 0x80, 0xd2, 0xf7, 0x48, 0xf5, 0x6a, 0x13, 0x2b, 0x82, 0x67, 0x4e, 0xd0, 0x18, 0x46, 0x20, 0xb8, 0x2a, 0xd2, 0xcb, 0x18, 0x2c, 0x97, 0xb4, 0x81, 0x62, 0x66, 0x47, 0x49, 0x12, 0x90, 0xa0, 0x11, 0xcc, 0x73, 0x82, 0x86, 0x85, 0xa8, 0xc3, 0x67, 0xa5, 0xb9, 0xcf, 0x8d, 0x62, 0x1b, 0x0d, 0x5c, 0x1e, 0xff, 0x03, 0x17, 0x27, 0x58, 0xbd, 0x00, 0x49, 0x78, 0xc2, 0x51, 0xcd, 0x51, 0x34, 0x22, 0x28, 0x98, 0x9c, 0xae, 0x63, 0x32, 0xac, 0x48, 0x64, 0x37, 0xcb, 0x5c, 0x57, 0xd4, 0x30, 0x74, 0x62, 0x86, 0x52, 0x53, 0xbe, 0x21, 0x7b, 0x35, 0x15, 0xc7, 0x3d, 0xf4, 0x05, 0xb7, 0xf2, 0x82, 0x17, 0xad, 0x0b, 0x8c, 0xf6, 0x0c, 0x2f, 0xff, 0xaa, 0x0a, 0x00, 0x48, 0xb1, 0xfb, 0x4a, 0xcd, 0xcd, 0xc3, 0x8b, 0x52, 0x50, 0xcf, 0xec, 0x35, 0x6a, 0x6d, 0xe2, 0x6c, 0xfa, 0x7a, 0x58, 0x8f, 0xdc, 0x86, 0xf9, 0x8c, 0x85, 0x4a, 0xc6, 0x4c, 0x7b, 0xfa, 0xa9, 0x6f, 0x5a, 0x32, 0xcc, 0x06, 0x10, 0x93, 0x4b, 0xaa, 0x6a, 0x58, 0x6b, 0x9a, 0x20, 0x54, 0xf1, 0x3b, 0xa2, 0x74, 0x17, 0x4a, 0xa0, 0xd2, 0xb3, 0xa8, 0x1b, 0x96, 0xa9, 0x40, 0x66, 0x6f, 0x78, 0x9b, 0x5a, 0x6b, 0xcd, 0xc0, 0xa6, 0xa0, 0x17, 0x8a, 0x0c, 0x9a, 0x02, 0x57, 0x8a, 0x49, 0x3f, 0x6e, 0xea, 0x0d, 0x2e, 0x6c, 0x13, 0x95, 0x1c, 0x9f, 0x24, 0x9a, 0x5e, 0x8d, 0xd7, 0x1d, 0xd4, 0x9a, 0x74, 0x2d, 0x45, 0x1f, 0x1a, 0xbb, 0xa1, 0x9a, 0xf8, 0xc5, 0x47, 0x85, 0x5e, 0x0a, 0xfc, 0x72, 0x8e, 0x90, 0xab, 0xb4, 0x99, 0xc9, 0xbe, 0xeb, 0x76, 0x6f, 0x47, 0x29, 0xcd, 0xa2, 0x22, 0x63, 0xe3, 0x24, 0xda, 0x18, 0x71, 0x2d, 0x31, 0x6e, 0x98, 0xdc, 0x7a, 0xc8, 0xc3, 0xca, 0x47, 0x37, 0x0e, 0xbd, 0x77, 0x0c, 0xe3, 0x2b, 0x3b, 0xd4, 0xb1, 0xa0, 0xc9, 0x52, 0x9a, 0xc6, 0xec, 0x8e, 0xe0, 0x28, 0xb1, 0xcd, 0xb2, 0x65, 0x1c, 0xb5, 0xa6, 0xbb, 0x3c, 0x0c, 0x6d, 0xf1, 0x24, 0x0a, 0x3b, 0x91, 0x4b, 0x56, 0x56, 0xc0, 0xdc, 0x51, 0xc2, 0xb9, 0x1b, 0xfc, 0xbc, 0x37, 0xa4, 0x66, 0x02, 0x87, 0xd4, 0x4f, 0x81, 0xf8, 0x53, 0xc7, 0xf4, 0x9a, 0x6d, 0x06, 0x03, 0xd6, 0xd7, 0x23, 0xcb, 0xec, 0x01, 0x5f, 0xbc, 0x43, 0x4a, 0x38, 0x24, 0x1c, 0x10, 0x9c, 0x7e, 0xd5, 0xb1, 0xcc, 0x46, 0x1a, 0x2c, 0xcb, 0x9a, 0xb7, 0x14, 0x0f, 0x19, 0xf3, 0x7a, 0x13, 0xbb, 0x70, 0x1e, 0x14, 0x2b, 0xd5, 0x4b, 0x64, 0xec, 0x6b, 0x76, 0xfe, 0xc3, 0x3b, 0x69, 0xc2, 0x91, 0x8c, 0xb0, 0x17, 0xc4, 0x14, 0x34, 0x23, 0x00, 0x9a, 0x3c, 0x07, 0xb5, 0xc1, 0x81, 0xb0, 0xc1, 0xeb, 0x49, 0x4a, 0x62, 0xab, 0xc8, 0x39, 0x13, 0x97, 0x08, 0x9e, 0xa6, 0x64, 0x09, 0x67, 0xc1, 0x20, 0x49, 0x84, 0xcd, 0x48, 0x4c, 0xcc, 0xb0, 0x0a, 0x9a, 0x17, 0xd0, 0x87, 0x21, 0x84, 0x28, 0xef, 0x3b, 0xb7, 0x08, 0x78, 0x3e, 0x12, 0x82, 0x71, 0x04, 0x41, 0x73, 0x75, 0xb6, 0x95, 0x6f, 0xb5, 0x00, 0x53, 0xd0, 0x48, 0xa4, 0x79, 0x14, 0x95, 0x82, 0x4a, 0x34, 0x80, 0xa5, 0xb7, 0x83, 0x02, 0x56, 0x09, 0x6f, 0xdd, 0x72, 0x5c, 0x30, 0x8b, 0x3b, 0xe8, 0x4a, 0x07, 0xf3, 0x63, 0x2e, 0x24, 0x95, 0xc6, 0x2e, 0x96, 0x39, 0x9d, 0x80, 0xbf, 0xa7, 0x45, 0xb9, 0x84, 0x1a, 0x18, 0x33, 0xbc, 0x1d, 0x27, 0xba, 0x45, 0xa5, 0x21, 0x68, 0xee, 0x59, 0x00, 0x6c, 0x3a, 0x3a, 0x8c, 0x4a, 0x5a, 0x4f, 0x50, 0x88, 0xfc, 0x73, 0x71, 0x81, 0xab, 0x51, 0x96, 0xf7, 0xb1, 0xb4, 0x9a, 0x2e, 0xd8, 0x13, 0x13, 0x4e, 0x11, 0x2f, 0x73, 0x0b, 0x99, 0x1c, 0x54, 0xa7, 0x19, 0x6b, 0xcf, 0x5f, 0xc7, 0x6e, 0x13, 0x4c, 0x58, 0x43, 0xe1, 0x69, 0x88, 0x51, 0xb2, 0xf8, 0x69, 0xaf, 0xaf, 0xb0, 0x27, 0x87, 0xd9, 0xc2, 0xf1, 0x36, 0x90, 0x2d, 0xc7, 0xa7, 0xf3, 0xd6, 0x21, 0x56, 0xd1, 0x5e, 0xc3, 0x09, 0x56, 0x40, 0x92, 0xc6, 0x1d, 0x83, 0xb0, 0x98, 0x6c, 0x48, 0x40, 0x99, 0x81, 0xf3, 0xc1, 0x86, 0x88, 0x0a, 0x2f, 0x63, 0xd5, 0x86, 0x0a, 0xb6, 0x01, 0xde, 0xac, 0x2b, 0x6b, 0xa1, 0xb4, 0x28, 0x17, 0x9d, 0x73, 0x53, 0x3e, 0xb7, 0xa3, 0xa5, 0x11, 0x3b, 0x85, 0x61, 0xf1, 0x0b, 0x45, 0xc3, 0xcd, 0xe2, 0x82, 0xb6, 0xea, 0xd6, 0xab, 0x6c, 0x60, 0x4f, 0x09, 0xc1, 0x7b, 0xfd, 0xa0, 0x83, 0x13, 0xa3, 0x26, 0x07, 0x67, 0x5a, 0xdf, 0x64, 0x31, 0xca, 0x87, 0x18, 0xe9, 0xc4, 0x3a, 0x73, 0x73, 0x32, 0x27, 0xe7, 0x3b, 0xc6, 0x1a, 0xc8, 0x45, 0xba, 0x90, 0x77, 0x55, 0xce, 0xc6, 0x89, 0x25, 0xe5, 0xe2, 0xbf, 0xe9, 0x12, 0x95, 0x9d, 0xb8, 0x6f, 0xbf, 0xe2, 0x15, 0x6f, 0xd5, 0xbb, 0xdb, 0xf0, 0xc9, 0xdf, 0x8b, 0x53, 0x02, 0xaa, 0x8d, 0x90, 0xa2, 0x2d, 0x12, 0x27, 0x0e, 0x00, 0x65, 0x51, 0xe4, 0x76, 0x7e, 0x45, 0x26, 0x8e, 0xd9, 0x69, 0x26, 0x54, 0x44, 0x78, 0x11, 0xea, 0xb8, 0x4f, 0x04, 0x99, 0xa8, 0xa5, 0x8c, 0xf7, 0xc0, 0x4a, 0x59, 0x56, 0x98, 0x52, 0x80, 0x45, 0xf2, 0x98, 0x97, 0xc8, 0xfa, 0x96, 0xd0, 0x6c, 0xce, 0x51, 0xe6, 0xaf, 0xea, 0xc4, 0x33, 0x95, 0x89, 0xc9, 0x41, 0xc8, 0x55, 0x63, 0xd7, 0x0f, 0xac, 0xe1, 0x92, 0x88, 0x94, 0xba, 0xc0, 0x36, 0x19, 0xdf, 0xf4, 0xbe, 0x3f, 0x43, 0x14, 0xa3, 0xf7, 0x35, 0x1a, 0x09, 0xa4, 0x86, 0xb5, 0x04, 0x1e, 0x7c, 0xb2, 0xda, 0x8b, 0x96, 0xbc, 0x66, 0x26, 0xa4, 0x93, 0x17, 0x35, 0x7c, 0x41, 0x52, 0xa5, 0x1b, 0xa3, 0xc2, 0x8c, 0x7e, 0x0c, 0x9d, 0xb4, 0x1a, 0x06, 0xa2, 0x82, 0x90, 0xf2, 0x18, 0x73, 0x11, 0x07, 0xc9, 0x54, 0xd8, 0xa6, 0x6f, 0x80, 0x1d, 0x7d, 0xe1, 0x2a, 0x03, 0x71, 0x16, 0x99, 0x0b, 0x6c, 0x53, 0xc1, 0x29, 0xf1, 0x85, 0xc3, 0x45, 0xf2, 0x7e, 0x51, 0x8b, 0x2d, 0x5a, 0x91, 0x25, 0xa0, 0x70, 0x76, 0xd9, 0x91, 0xb7, 0xda, 0xc7, 0xcc, 0x65, 0xa8, 0x56, 0x2e, 0xfb, 0xcc, 0x32, 0xa9, 0xca, 0x4a, 0xd9, 0x02, 0x63, 0xb0, 0x4a, 0x4f, 0x90, 0x36, 0x11, 0x6c, 0x7b, 0x97, 0x48, 0x04, 0x96, 0x31, 0x75, 0x75, 0x65, 0x0d, 0xcc, 0x21, 0x52, 0xb5, 0xbc, 0x0e, 0x74, 0x40, 0x7e, 0x12, 0xfa, 0x8e, 0x4f, 0xfc, 0xcc, 0xff, 0x76, 0xc0, 0x1a, 0x97, 0x4b, 0xd6, 0x11, 0x02, 0xe1, 0xf5, 0x29, 0x64, 0x96, 0xc7, 0x1d, 0x07, 0x64, 0xe1, 0x32, 0x29, 0xff, 0xe7, 0x84, 0x6f, 0x33, 0x6e, 0x34, 0xca, 0xc9, 0x04, 0xca, 0x56, 0x70, 0xf8, 0xcd, 0x50, 0x52, 0x42, 0x7a, 0x79, 0xc0, 0x91, 0xa9, 0x71, 0x21, 0x0c, 0x5c, 0xff, 0x66, 0x7a, 0xac, 0x24, 0x93, 0x66, 0xe1, 0x0d, 0x2b, 0x11, 0x37, 0x6c, 0xa3, 0x9d, 0x93, 0x52, 0x04, 0xb1, 0x2c, 0xc5, 0x85, 0xe9, 0x40, 0x54, 0x03, 0x62, 0x5f, 0xb3, 0x2c, 0xb5, 0xe5, 0xc3, 0x1b, 0x62, 0x34, 0x81, 0x60, 0x51, 0x5c, 0xcc, 0x4f, 0xda, 0xf5, 0x70, 0x2d, 0x6b, 0xab, 0x5c, 0x37, 0x3d, 0xb6, 0xf3, 0x50, 0xd3, 0xe6, 0x3a, 0x5c, 0xe3, 0xca, 0x54, 0x74, 0xa0, 0xcf, 0x15, 0x67, 0x04, 0x2c, 0xa3, 0x25, 0x89, 0x86, 0xff, 0x75, 0xbd, 0xfc, 0xd9, 0x29, 0xe6, 0x46, 0x2f, 0x36, 0xbc, 0xcc, 0x3f, 0x5a, 0x93, 0x35, 0x2a, 0x2b, 0x36, 0xcb, 0x16, 0x2e, 0x18, 0x74, 0xc7, 0x42, 0x87, 0x0a, 0x97, 0xb1, 0x67, 0xa0, 0x50, 0x37, 0x36, 0x24, 0xea, 0xeb, 0x7e, 0x50, 0x73, 0x25, 0x6b, 0x72, 0x11, 0xb2, 0xd9, 0x4b, 0x84, 0x06, 0xcd, 0x6c, 0x95, 0x33, 0xb1, 0x53, 0x64, 0x08, 0xab, 0x0a, 0x29, 0xe5, 0xb2, 0xf0, 0xc9, 0x54, 0xec, 0xe0, 0x0f, 0xbb, 0xeb, 0x17, 0x6d, 0x72, 0x4d, 0x4c, 0xf4, 0x43, 0xcf, 0x70, 0x20, 0xd5, 0xfa, 0x70, 0x94, 0xcc, 0x1b, 0x1b, 0xe6, 0x97, 0xba, 0xd3, 0x36, 0x74, 0xe4, 0x09, 0x9e, 0xc7, 0xbb, 0x18, 0xf4, 0x57, 0x71, 0x28, 0xcd, 0xd9, 0x7c, 0xcd, 0x6d, 0x44, 0x62, 0xe5, 0x60, 0x7c, 0x51, 0x2a, 0x3e, 0x36, 0x24, 0x8e, 0x3d, 0xda, 0xa2, 0xec, 0x08, 0x9a, 0xef, 0xc4, 0xce, 0x48, 0x5c, 0x49, 0xd7, 0xb0, 0x09, 0xc8, 0xd6, 0x31, 0x15, 0xfc, 0x81, 0xff, 0x3a, 0x62, 0xd1, 0x5a, 0x88, 0x44, 0x1c, 0x03, 0xea, 0x1c, 0x2e, 0x72, 0xc4, 0x88, 0x39, 0xfc, 0x6a, 0xd7, 0x3a, 0x30, 0x74, 0x4a, 0x62, 0xb7, 0xb2, 0x16, 0x45, 0xa6, 0xaf, 0x7d, 0x61, 0xb6, 0x38, 0x3b, 0x22, 0x1e, 0x21, 0x90, 0x55, 0x57, 0xcd, 0x29, 0xd9, 0x24, 0xa6, 0x09, 0x86, 0xc5, 0x11, 0xc1, 0xeb, 0xbc, 0x31, 0x6d, 0x56, 0x30, 0xa2, 0x41, 0x43, 0x23, 0xf5, 0x3a, 0xd5, 0x59, 0x94, 0xf6, 0xb3, 0x65, 0x39, 0xf9, 0xc4, 0x40, 0x75, 0xa5, 0x33, 0xe4, 0x81, 0xc0, 0x84, 0x45, 0xd9, 0xca, 0x9e, 0x9d, 0x38, 0x21, 0x19, 0x38, 0x8b, 0xd1, 0xd7, 0x50, 0x52, 0x21, 0x7a, 0x94, 0x4c, 0xcc, 0x7b, 0xe9, 0x09, 0xe2, 0x19, 0x71, 0x1f, 0xcc, 0x79, 0x24, 0x76, 0x92, 0x13, 0xa1, 0x92, 0x53, 0x4a, 0x55, 0x80, 0x08, 0x15, 0x7a, 0x39, 0x6e, 0xdf, 0xf4, 0x80, 0xcc, 0x3b, 0x52, 0x0f, 0xf8, 0x18, 0xb3, 0x8b, 0x13, 0x5c, 0x18, 0xa8, 0x0d, 0x51, 0x05, 0xe6, 0x78, 0x83, 0x6c, 0x39, 0x5c, 0x28, 0xe9, 0x2f, 0x7a, 0x3c, 0x4e, 0x93, 0xc0, 0x10, 0x35, 0xf3, 0x41, 0x11, 0xcc, 0x49, 0x02, 0xd0, 0xc0, 0x33, 0xa6, 0x3f, 0x23, 0x6a, 0x71, 0xda, 0x97, 0x4a, 0x6f, 0x40, 0x4f, 0x7a, 0xa7, 0xb5, 0xe5, 0x82, 0xc7, 0x58, 0x14, 0x2f, 0xc1, 0x82, 0x6b, 0xba, 0x98, 0xb2, 0x7d, 0x57, 0xc2, 0xe2, 0x10, 0x3e, 0x10, 0xe3, 0x0d, 0x32, 0x79, 0x7b, 0x96, 0x77, 0x14, 0xd1, 0x56, 0x61, 0x11, 0x13, 0x71, 0xa2, 0xd9, 0xc5, 0x39, 0x98, 0x12, 0x46, 0x46, 0x22, 0x63, 0x5b, 0x44, 0x21, 0x26, 0xb0, 0x98, 0x36, 0xb0, 0x81, 0x82, 0x72, 0x47, 0xd0, 0x54, 0x22, 0x97, 0x2b, 0xd0, 0x32, 0x0d, 0x8f, 0x42, 0xbf, 0x57, 0xe3, 0x49, 0x46, 0x12, 0x34, 0xe4, 0xd9, 0x4f, 0x01, 0x18, 0x50, 0xba, 0xb5, 0xc0, 0x49, 0xb6, 0x2a, 0x59, 0x43, 0x38, 0x66, 0xfc, 0xce, 0x69, 0x66, 0x49, 0x5c, 0x26, 0x5c, 0x47, 0x65, 0xa5, 0x6c, 0x06, 0xb9, 0xfc, 0x42, 0x76, 0x54, 0x87, 0x85, 0xf4, 0x68, 0x28, 0xca, 0x60, 0x2d, 0xc6, 0xd0, 0x54, 0x1f, 0x25, 0x07, 0x89, 0xc4, 0x9e, 0x8b, 0x06, 0x55, 0x9c, 0x43, 0x44, 0x60, 0xa8, 0x43, 0x80, 0x98, 0x54, 0xe5, 0xb4, 0x6e, 0x89, 0x38, 0x9f, 0x10, 0xf4, 0x89, 0x66, 0x74, 0x91, 0xc1, 0x93, 0x5e, 0x8a, 0xfb, 0x9e, 0xb4, 0x71, 0x8f, 0x86, 0xac, 0x45, 0x89, 0x32, 0xbc, 0xf3, 0x3c, 0x9a, 0xbe, 0xcb, 0x2d, 0xc0, 0xc0, 0x93, 0xa7, 0xe8, 0x1d, 0xa0, 0x32, 0x7b, 0xb6, 0x37, 0x52, 0x81, 0x05, 0xc3, 0x58, 0xeb, 0x76, 0x8d, 0x32, 0x3a, 0x37, 0xd4, 0x0a, 0x8c, 0x19, 0x9b, 0x7c, 0x4b, 0xb1, 0xd7, 0x2b, 0x72, 0xb6, 0x90, 0xb3, 0x6d, 0xd2, 0x7a, 0x93, 0x55, 0x19, 0x1b, 0x3c, 0x3a, 0xa6, 0x75, 0xa7, 0xe6, 0xf8, 0x55, 0xeb, 0x50, 0x5f, 0x57, 0x98, 0x65, 0xdb, 0xd8, 0x91, 0x05, 0x65, 0x50, 0x5e, 0x7c, 0x0f, 0xdd, 0x54, 0x5c, 0xbb, 0xb8, 0x71, 0xb0, 0xb2, 0xcc, 0x01, 0x25, 0xb7, 0x4f, 0x6b, 0x0c, 0x9b, 0x79, 0x67, 0x0a, 0x62, 0x02, 0xd1, 0xb9, 0x15, 0x4a, 0xc7, 0x76, 0x6b, 0x19, 0x19, 0xc4, 0x89, 0x58, 0x90, 0x86, 0xad, 0x8b, 0x45, 0xbe, 0x0d, 0x79, 0xc9, 0x76, 0xc3, 0xc3, 0x9d, 0x6b, 0x25, 0x21, 0x3b, 0xb0, 0xb7, 0x8a, 0x57, 0x50, 0xe6, 0xa8, 0xeb, 0x34, 0x33, 0x0b, 0xb3, 0xcf, 0xf2, 0xb1, 0xc0, 0x72, 0x2a, 0xc8, 0x83, 0xb0, 0x48, 0xf4, 0xb8, 0xcd, 0x06, 0x19, 0x6d, 0xa8, 0xaa, 0x8b, 0x05, 0xda, 0x42, 0x67, 0x55, 0x2b, 0xf8, 0x7a, 0xbc, 0xa5, 0x12, 0x4d, 0xc3, 0x58, 0xa8, 0x38, 0x10, 0x40, 0xe9, 0xb8, 0x1f, 0xb0, 0x84, 0x43, 0x15, 0x02, 0x15, 0xd6, 0x92, 0x23, 0x28, 0x00, 0x0a, 0xc0, 0xb7, 0x88, 0xb1, 0x21, 0x93, 0x1a, 0x26, 0x7d, 0x80, 0x61, 0x9c, 0xe7, 0xd2, 0x9c, 0xd7, 0x6b, 0x60, 0xcf, 0x65, 0x83, 0xdc, 0xe8, 0xce, 0xbc, 0x49, 0x01, 0x85, 0x73, 0x6c, 0x81, 0x8b, 0x25, 0xad, 0x26, 0x0b, 0x66, 0x7b, 0x1f, 0xfd, 0x46, 0x20, 0x6d, 0x01, 0x04, 0x55, 0x3a, 0xa9, 0xfb, 0x30, 0x45, 0x54, 0xa2, 0x1c, 0x32, 0x72, 0x44, 0xce, 0x78, 0xaf, 0xdb, 0xd3, 0xb4, 0x62, 0x36, 0x1b, 0xb0, 0x68, 0xa1, 0x55, 0x63, 0x64, 0x09, 0xf5, 0x74, 0xc5, 0x71, 0x65, 0x72, 0xe2, 0xa5, 0xf2, 0xa4, 0xb0, 0x4f, 0xb8, 0xaa, 0xd1, 0x23, 0x66, 0x84, 0x84, 0x17, 0x87, 0x56, 0x2a, 0xaf, 0x46, 0xc2, 0xc0, 0xda, 0x46, 0x65, 0xea, 0xfd, 0x46, 0x5f, 0xc6, 0x4a, 0x0c, 0x5f, 0x8f, 0x3f, 0x90, 0x03, 0x48, 0x94, 0x15, 0x89, 0x9d, 0x59, 0xa5, 0x43, 0xd8, 0x20, 0x8c, 0x54, 0xa3, 0x16, 0x65, 0x29, 0xb5, 0x39, 0x22, 0xa5, 0x89, 0x9a, 0x0b, 0xc4, 0x65, 0xee, 0x5f, 0xc2, 0xc0, 0x41, 0x55, 0x58, 0x2a, 0x40, 0xac, 0x70, 0x97, 0x61, 0xd2, 0xbe, 0x61, 0xfd, 0xc7, 0x6c, 0x59, 0x30, 0x44, 0xce, 0xbc, 0xc7, 0xf2, 0x86, 0x26, 0xed, 0x79, 0xd4, 0x51, 0x14, 0x08, 0x00, 0xe0, 0x3b, 0x59, 0xb9, 0x56, 0xf8, 0x21, 0x0e, 0x55, 0x60, 0x67, 0x40, 0x7d, 0x13, 0xdc, 0x90, 0xfa, 0x9e, 0x8b, 0x87, 0x2b, 0xfb, 0x8f, 0xa0, 0x82, 0x06, 0x65, 0x03, 0x82, 0x06, 0x61, 0x00, 0xda, 0x18, 0x71, 0x2d, 0x31, 0x6e, 0x98, 0xdc, 0x7a, 0xc8, 0xc3, 0xca, 0x47, 0x37, 0x0e, 0xbd, 0x77, 0x0c, 0xe3, 0x2b, 0x3b, 0xd4, 0xb1, 0xa0, 0xc9, 0x52, 0x9a, 0xc6, 0xec, 0x8e, 0xe0, 0x28, 0xb1, 0xcd, 0xb2, 0x65, 0x1c, 0xb5, 0xa6, 0xbb, 0x3c, 0x0c, 0x6d, 0xf1, 0x24, 0x0a, 0x3b, 0x91, 0x4b, 0x56, 0x56, 0xc0, 0xdc, 0x51, 0xc2, 0xb9, 0x1b, 0xfc, 0xbc, 0x37, 0xa4, 0x66, 0x02, 0x87, 0xd4, 0x4f, 0x81, 0xf8, 0x53, 0xc7, 0xf4, 0x9a, 0x6d, 0x06, 0x03, 0xd6, 0xd7, 0x23, 0xcb, 0xec, 0x01, 0x5f, 0xbc, 0x43, 0x4a, 0x38, 0x24, 0x1c, 0x10, 0x9c, 0x7e, 0xd5, 0xb1, 0xcc, 0x46, 0x1a, 0x2c, 0xcb, 0x9a, 0xb7, 0x14, 0x0f, 0x19, 0xf3, 0x7a, 0x13, 0xbb, 0x70, 0x1e, 0x14, 0x2b, 0xd5, 0x4b, 0x64, 0xec, 0x6b, 0x76, 0xfe, 0xc3, 0x3b, 0x69, 0xc2, 0x91, 0x8c, 0xb0, 0x17, 0xc4, 0x14, 0x34, 0x23, 0x00, 0x9a, 0x3c, 0x07, 0xb5, 0xc1, 0x81, 0xb0, 0xc1, 0xeb, 0x49, 0x4a, 0x62, 0xab, 0xc8, 0x39, 0x13, 0x97, 0x08, 0x9e, 0xa6, 0x64, 0x09, 0x67, 0xc1, 0x20, 0x49, 0x84, 0xcd, 0x48, 0x4c, 0xcc, 0xb0, 0x0a, 0x9a, 0x17, 0xd0, 0x87, 0x21, 0x84, 0x28, 0xef, 0x3b, 0xb7, 0x08, 0x78, 0x3e, 0x12, 0x82, 0x71, 0x04, 0x41, 0x73, 0x75, 0xb6, 0x95, 0x6f, 0xb5, 0x00, 0x53, 0xd0, 0x48, 0xa4, 0x79, 0x14, 0x95, 0x82, 0x4a, 0x34, 0x80, 0xa5, 0xb7, 0x83, 0x02, 0x56, 0x09, 0x6f, 0xdd, 0x72, 0x5c, 0x30, 0x8b, 0x3b, 0xe8, 0x4a, 0x07, 0xf3, 0x63, 0x2e, 0x24, 0x95, 0xc6, 0x2e, 0x96, 0x39, 0x9d, 0x80, 0xbf, 0xa7, 0x45, 0xb9, 0x84, 0x1a, 0x18, 0x33, 0xbc, 0x1d, 0x27, 0xba, 0x45, 0xa5, 0x21, 0x68, 0xee, 0x59, 0x00, 0x6c, 0x3a, 0x3a, 0x8c, 0x4a, 0x5a, 0x4f, 0x50, 0x88, 0xfc, 0x73, 0x71, 0x81, 0xab, 0x51, 0x96, 0xf7, 0xb1, 0xb4, 0x9a, 0x2e, 0xd8, 0x13, 0x13, 0x4e, 0x11, 0x2f, 0x73, 0x0b, 0x99, 0x1c, 0x54, 0xa7, 0x19, 0x6b, 0xcf, 0x5f, 0xc7, 0x6e, 0x13, 0x4c, 0x58, 0x43, 0xe1, 0x69, 0x88, 0x51, 0xb2, 0xf8, 0x69, 0xaf, 0xaf, 0xb0, 0x27, 0x87, 0xd9, 0xc2, 0xf1, 0x36, 0x90, 0x2d, 0xc7, 0xa7, 0xf3, 0xd6, 0x21, 0x56, 0xd1, 0x5e, 0xc3, 0x09, 0x56, 0x40, 0x92, 0xc6, 0x1d, 0x83, 0xb0, 0x98, 0x6c, 0x48, 0x40, 0x99, 0x81, 0xf3, 0xc1, 0x86, 0x88, 0x0a, 0x2f, 0x63, 0xd5, 0x86, 0x0a, 0xb6, 0x01, 0xde, 0xac, 0x2b, 0x6b, 0xa1, 0xb4, 0x28, 0x17, 0x9d, 0x73, 0x53, 0x3e, 0xb7, 0xa3, 0xa5, 0x11, 0x3b, 0x85, 0x61, 0xf1, 0x0b, 0x45, 0xc3, 0xcd, 0xe2, 0x82, 0xb6, 0xea, 0xd6, 0xab, 0x6c, 0x60, 0x4f, 0x09, 0xc1, 0x7b, 0xfd, 0xa0, 0x83, 0x13, 0xa3, 0x26, 0x07, 0x67, 0x5a, 0xdf, 0x64, 0x31, 0xca, 0x87, 0x18, 0xe9, 0xc4, 0x3a, 0x73, 0x73, 0x32, 0x27, 0xe7, 0x3b, 0xc6, 0x1a, 0xc8, 0x45, 0xba, 0x90, 0x77, 0x55, 0xce, 0xc6, 0x89, 0x25, 0xe5, 0xe2, 0xbf, 0xe9, 0x12, 0x95, 0x9d, 0xb8, 0x6f, 0xbf, 0xe2, 0x15, 0x6f, 0xd5, 0xbb, 0xdb, 0xf0, 0xc9, 0xdf, 0x8b, 0x53, 0x02, 0xaa, 0x8d, 0x90, 0xa2, 0x2d, 0x12, 0x27, 0x0e, 0x00, 0x65, 0x51, 0xe4, 0x76, 0x7e, 0x45, 0x26, 0x8e, 0xd9, 0x69, 0x26, 0x54, 0x44, 0x78, 0x11, 0xea, 0xb8, 0x4f, 0x04, 0x99, 0xa8, 0xa5, 0x8c, 0xf7, 0xc0, 0x4a, 0x59, 0x56, 0x98, 0x52, 0x80, 0x45, 0xf2, 0x98, 0x97, 0xc8, 0xfa, 0x96, 0xd0, 0x6c, 0xce, 0x51, 0xe6, 0xaf, 0xea, 0xc4, 0x33, 0x95, 0x89, 0xc9, 0x41, 0xc8, 0x55, 0x63, 0xd7, 0x0f, 0xac, 0xe1, 0x92, 0x88, 0x94, 0xba, 0xc0, 0x36, 0x19, 0xdf, 0xf4, 0xbe, 0x3f, 0x43, 0x14, 0xa3, 0xf7, 0x35, 0x1a, 0x09, 0xa4, 0x86, 0xb5, 0x04, 0x1e, 0x7c, 0xb2, 0xda, 0x8b, 0x96, 0xbc, 0x66, 0x26, 0xa4, 0x93, 0x17, 0x35, 0x7c, 0x41, 0x52, 0xa5, 0x1b, 0xa3, 0xc2, 0x8c, 0x7e, 0x0c, 0x9d, 0xb4, 0x1a, 0x06, 0xa2, 0x82, 0x90, 0xf2, 0x18, 0x73, 0x11, 0x07, 0xc9, 0x54, 0xd8, 0xa6, 0x6f, 0x80, 0x1d, 0x7d, 0xe1, 0x2a, 0x03, 0x71, 0x16, 0x99, 0x0b, 0x6c, 0x53, 0xc1, 0x29, 0xf1, 0x85, 0xc3, 0x45, 0xf2, 0x7e, 0x51, 0x8b, 0x2d, 0x5a, 0x91, 0x25, 0xa0, 0x70, 0x76, 0xd9, 0x91, 0xb7, 0xda, 0xc7, 0xcc, 0x65, 0xa8, 0x56, 0x2e, 0xfb, 0xcc, 0x32, 0xa9, 0xca, 0x4a, 0xd9, 0x02, 0x63, 0xb0, 0x4a, 0x4f, 0x90, 0x36, 0x11, 0x6c, 0x7b, 0x97, 0x48, 0x04, 0x96, 0x31, 0x75, 0x75, 0x65, 0x0d, 0xcc, 0x21, 0x52, 0xb5, 0xbc, 0x0e, 0x74, 0x40, 0x7e, 0x12, 0xfa, 0x8e, 0x4f, 0xfc, 0xcc, 0xff, 0x76, 0xc0, 0x1a, 0x97, 0x4b, 0xd6, 0x11, 0x02, 0xe1, 0xf5, 0x29, 0x64, 0x96, 0xc7, 0x1d, 0x07, 0x64, 0xe1, 0x32, 0x29, 0xff, 0xe7, 0x84, 0x6f, 0x33, 0x6e, 0x34, 0xca, 0xc9, 0x04, 0xca, 0x56, 0x70, 0xf8, 0xcd, 0x50, 0x52, 0x42, 0x7a, 0x79, 0xc0, 0x91, 0xa9, 0x71, 0x21, 0x0c, 0x5c, 0xff, 0x66, 0x7a, 0xac, 0x24, 0x93, 0x66, 0xe1, 0x0d, 0x2b, 0x11, 0x37, 0x6c, 0xa3, 0x9d, 0x93, 0x52, 0x04, 0xb1, 0x2c, 0xc5, 0x85, 0xe9, 0x40, 0x54, 0x03, 0x62, 0x5f, 0xb3, 0x2c, 0xb5, 0xe5, 0xc3, 0x1b, 0x62, 0x34, 0x81, 0x60, 0x51, 0x5c, 0xcc, 0x4f, 0xda, 0xf5, 0x70, 0x2d, 0x6b, 0xab, 0x5c, 0x37, 0x3d, 0xb6, 0xf3, 0x50, 0xd3, 0xe6, 0x3a, 0x5c, 0xe3, 0xca, 0x54, 0x74, 0xa0, 0xcf, 0x15, 0x67, 0x04, 0x2c, 0xa3, 0x25, 0x89, 0x86, 0xff, 0x75, 0xbd, 0xfc, 0xd9, 0x29, 0xe6, 0x46, 0x2f, 0x36, 0xbc, 0xcc, 0x3f, 0x5a, 0x93, 0x35, 0x2a, 0x2b, 0x36, 0xcb, 0x16, 0x2e, 0x18, 0x74, 0xc7, 0x42, 0x87, 0x0a, 0x97, 0xb1, 0x67, 0xa0, 0x50, 0x37, 0x36, 0x24, 0xea, 0xeb, 0x7e, 0x50, 0x73, 0x25, 0x6b, 0x72, 0x11, 0xb2, 0xd9, 0x4b, 0x84, 0x06, 0xcd, 0x6c, 0x95, 0x33, 0xb1, 0x53, 0x64, 0x08, 0xab, 0x0a, 0x29, 0xe5, 0xb2, 0xf0, 0xc9, 0x54, 0xec, 0xe0, 0x0f, 0xbb, 0xeb, 0x17, 0x6d, 0x72, 0x4d, 0x4c, 0xf4, 0x43, 0xcf, 0x70, 0x20, 0xd5, 0xfa, 0x70, 0x94, 0xcc, 0x1b, 0x1b, 0xe6, 0x97, 0xba, 0xd3, 0x36, 0x74, 0xe4, 0x09, 0x9e, 0xc7, 0xbb, 0x18, 0xf4, 0x57, 0x71, 0x28, 0xcd, 0xd9, 0x7c, 0xcd, 0x6d, 0x44, 0x62, 0xe5, 0x60, 0x7c, 0x51, 0x2a, 0x3e, 0x36, 0x24, 0x8e, 0x3d, 0xda, 0xa2, 0xec, 0x08, 0x9a, 0xef, 0xc4, 0xce, 0x48, 0x5c, 0x49, 0xd7, 0xb0, 0x09, 0xc8, 0xd6, 0x31, 0x15, 0xfc, 0x81, 0xff, 0x3a, 0x62, 0xd1, 0x5a, 0x88, 0x44, 0x1c, 0x03, 0xea, 0x1c, 0x2e, 0x72, 0xc4, 0x88, 0x39, 0xfc, 0x6a, 0xd7, 0x3a, 0x30, 0x74, 0x4a, 0x62, 0xb7, 0xb2, 0x16, 0x45, 0xa6, 0xaf, 0x7d, 0x61, 0xb6, 0x38, 0x3b, 0x22, 0x1e, 0x21, 0x90, 0x55, 0x57, 0xcd, 0x29, 0xd9, 0x24, 0xa6, 0x09, 0x86, 0xc5, 0x11, 0xc1, 0xeb, 0xbc, 0x31, 0x6d, 0x56, 0x30, 0xa2, 0x41, 0x43, 0x23, 0xf5, 0x3a, 0xd5, 0x59, 0x94, 0xf6, 0xb3, 0x65, 0x39, 0xf9, 0xc4, 0x40, 0x75, 0xa5, 0x33, 0xe4, 0x81, 0xc0, 0x84, 0x45, 0xd9, 0xca, 0x9e, 0x9d, 0x38, 0x21, 0x19, 0x38, 0x8b, 0xd1, 0xd7, 0x50, 0x52, 0x21, 0x7a, 0x94, 0x4c, 0xcc, 0x7b, 0xe9, 0x09, 0xe2, 0x19, 0x71, 0x1f, 0xcc, 0x79, 0x24, 0x76, 0x92, 0x13, 0xa1, 0x92, 0x53, 0x4a, 0x55, 0x80, 0x08, 0x15, 0x7a, 0x39, 0x6e, 0xdf, 0xf4, 0x80, 0xcc, 0x3b, 0x52, 0x0f, 0xf8, 0x18, 0xb3, 0x8b, 0x13, 0x5c, 0x18, 0xa8, 0x0d, 0x51, 0x05, 0xe6, 0x78, 0x83, 0x6c, 0x39, 0x5c, 0x28, 0xe9, 0x2f, 0x7a, 0x3c, 0x4e, 0x93, 0xc0, 0x10, 0x35, 0xf3, 0x41, 0x11, 0xcc, 0x49, 0x02, 0xd0, 0xc0, 0x33, 0xa6, 0x3f, 0x23, 0x6a, 0x71, 0xda, 0x97, 0x4a, 0x6f, 0x40, 0x4f, 0x7a, 0xa7, 0xb5, 0xe5, 0x82, 0xc7, 0x58, 0x14, 0x2f, 0xc1, 0x82, 0x6b, 0xba, 0x98, 0xb2, 0x7d, 0x57, 0xc2, 0xe2, 0x10, 0x3e, 0x10, 0xe3, 0x0d, 0x32, 0x79, 0x7b, 0x96, 0x77, 0x14, 0xd1, 0x56, 0x61, 0x11, 0x13, 0x71, 0xa2, 0xd9, 0xc5, 0x39, 0x98, 0x12, 0x46, 0x46, 0x22, 0x63, 0x5b, 0x44, 0x21, 0x26, 0xb0, 0x98, 0x36, 0xb0, 0x81, 0x82, 0x72, 0x47, 0xd0, 0x54, 0x22, 0x97, 0x2b, 0xd0, 0x32, 0x0d, 0x8f, 0x42, 0xbf, 0x57, 0xe3, 0x49, 0x46, 0x12, 0x34, 0xe4, 0xd9, 0x4f, 0x01, 0x18, 0x50, 0xba, 0xb5, 0xc0, 0x49, 0xb6, 0x2a, 0x59, 0x43, 0x38, 0x66, 0xfc, 0xce, 0x69, 0x66, 0x49, 0x5c, 0x26, 0x5c, 0x47, 0x65, 0xa5, 0x6c, 0x06, 0xb9, 0xfc, 0x42, 0x76, 0x54, 0x87, 0x85, 0xf4, 0x68, 0x28, 0xca, 0x60, 0x2d, 0xc6, 0xd0, 0x54, 0x1f, 0x25, 0x07, 0x89, 0xc4, 0x9e, 0x8b, 0x06, 0x55, 0x9c, 0x43, 0x44, 0x60, 0xa8, 0x43, 0x80, 0x98, 0x54, 0xe5, 0xb4, 0x6e, 0x89, 0x38, 0x9f, 0x10, 0xf4, 0x89, 0x66, 0x74, 0x91, 0xc1, 0x93, 0x5e, 0x8a, 0xfb, 0x9e, 0xb4, 0x71, 0x8f, 0x86, 0xac, 0x45, 0x89, 0x32, 0xbc, 0xf3, 0x3c, 0x9a, 0xbe, 0xcb, 0x2d, 0xc0, 0xc0, 0x93, 0xa7, 0xe8, 0x1d, 0xa0, 0x32, 0x7b, 0xb6, 0x37, 0x52, 0x81, 0x05, 0xc3, 0x58, 0xeb, 0x76, 0x8d, 0x32, 0x3a, 0x37, 0xd4, 0x0a, 0x8c, 0x19, 0x9b, 0x7c, 0x4b, 0xb1, 0xd7, 0x2b, 0x72, 0xb6, 0x90, 0xb3, 0x6d, 0xd2, 0x7a, 0x93, 0x55, 0x19, 0x1b, 0x3c, 0x3a, 0xa6, 0x75, 0xa7, 0xe6, 0xf8, 0x55, 0xeb, 0x50, 0x5f, 0x57, 0x98, 0x65, 0xdb, 0xd8, 0x91, 0x05, 0x65, 0x50, 0x5e, 0x7c, 0x0f, 0xdd, 0x54, 0x5c, 0xbb, 0xb8, 0x71, 0xb0, 0xb2, 0xcc, 0x01, 0x25, 0xb7, 0x4f, 0x6b, 0x0c, 0x9b, 0x79, 0x67, 0x0a, 0x62, 0x02, 0xd1, 0xb9, 0x15, 0x4a, 0xc7, 0x76, 0x6b, 0x19, 0x19, 0xc4, 0x89, 0x58, 0x90, 0x86, 0xad, 0x8b, 0x45, 0xbe, 0x0d, 0x79, 0xc9, 0x76, 0xc3, 0xc3, 0x9d, 0x6b, 0x25, 0x21, 0x3b, 0xb0, 0xb7, 0x8a, 0x57, 0x50, 0xe6, 0xa8, 0xeb, 0x34, 0x33, 0x0b, 0xb3, 0xcf, 0xf2, 0xb1, 0xc0, 0x72, 0x2a, 0xc8, 0x83, 0xb0, 0x48, 0xf4, 0xb8, 0xcd, 0x06, 0x19, 0x6d, 0xa8, 0xaa, 0x8b, 0x05, 0xda, 0x42, 0x67, 0x55, 0x2b, 0xf8, 0x7a, 0xbc, 0xa5, 0x12, 0x4d, 0xc3, 0x58, 0xa8, 0x38, 0x10, 0x40, 0xe9, 0xb8, 0x1f, 0xb0, 0x84, 0x43, 0x15, 0x02, 0x15, 0xd6, 0x92, 0x23, 0x28, 0x00, 0x0a, 0xc0, 0xb7, 0x88, 0xb1, 0x21, 0x93, 0x1a, 0x26, 0x7d, 0x80, 0x61, 0x9c, 0xe7, 0xd2, 0x9c, 0xd7, 0x6b, 0x60, 0xcf, 0x65, 0x83, 0xdc, 0xe8, 0xce, 0xbc, 0x49, 0x01, 0x85, 0x73, 0x6c, 0x81, 0x8b, 0x25, 0xad, 0x26, 0x0b, 0x66, 0x7b, 0x1f, 0xfd, 0x46, 0x20, 0x6d, 0x01, 0x04, 0x55, 0x3a, 0xa9, 0xfb, 0x30, 0x45, 0x54, 0xa2, 0x1c, 0x32, 0x72, 0x44, 0xce, 0x78, 0xaf, 0xdb, 0xd3, 0xb4, 0x62, 0x36, 0x1b, 0xb0, 0x68, 0xa1, 0x55, 0x63, 0x64, 0x09, 0xf5, 0x74, 0xc5, 0x71, 0x65, 0x72, 0xe2, 0xa5, 0xf2, 0xa4, 0xb0, 0x4f, 0xb8, 0xaa, 0xd1, 0x23, 0x66, 0x84, 0x84, 0x17, 0x87, 0x56, 0x2a, 0xaf, 0x46, 0xc2, 0xc0, 0xda, 0x46, 0x65, 0xea, 0xfd, 0x46, 0x5f, 0xc6, 0x4a, 0x0c, 0x5f, 0x8f, 0x3f, 0x90, 0x03, 0x48, 0x94, 0x15, 0x89, 0x9d, 0x59, 0xa5, 0x43, 0xd8, 0x20, 0x8c, 0x54, 0xa3, 0x16, 0x65, 0x29, 0xb5, 0x39, 0x22, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, }, .spki_len = 1603, .spki = { 0x30, 0x82, 0x06, 0x3f, 0x30, 0x0f, 0x06, 0x0b, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x02, 0x82, 0x0b, 0x05, 0x04, 0x04, 0x05, 0x00, 0x03, 0x82, 0x06, 0x2a, 0x00, 0x30, 0x82, 0x06, 0x25, 0x03, 0x82, 0x06, 0x21, 0x00, 0xda, 0x18, 0x71, 0x2d, 0x31, 0x6e, 0x98, 0xdc, 0x7a, 0xc8, 0xc3, 0xca, 0x47, 0x37, 0x0e, 0xbd, 0x77, 0x0c, 0xe3, 0x2b, 0x3b, 0xd4, 0xb1, 0xa0, 0xc9, 0x52, 0x9a, 0xc6, 0xec, 0x8e, 0xe0, 0x28, 0xb1, 0xcd, 0xb2, 0x65, 0x1c, 0xb5, 0xa6, 0xbb, 0x3c, 0x0c, 0x6d, 0xf1, 0x24, 0x0a, 0x3b, 0x91, 0x4b, 0x56, 0x56, 0xc0, 0xdc, 0x51, 0xc2, 0xb9, 0x1b, 0xfc, 0xbc, 0x37, 0xa4, 0x66, 0x02, 0x87, 0xd4, 0x4f, 0x81, 0xf8, 0x53, 0xc7, 0xf4, 0x9a, 0x6d, 0x06, 0x03, 0xd6, 0xd7, 0x23, 0xcb, 0xec, 0x01, 0x5f, 0xbc, 0x43, 0x4a, 0x38, 0x24, 0x1c, 0x10, 0x9c, 0x7e, 0xd5, 0xb1, 0xcc, 0x46, 0x1a, 0x2c, 0xcb, 0x9a, 0xb7, 0x14, 0x0f, 0x19, 0xf3, 0x7a, 0x13, 0xbb, 0x70, 0x1e, 0x14, 0x2b, 0xd5, 0x4b, 0x64, 0xec, 0x6b, 0x76, 0xfe, 0xc3, 0x3b, 0x69, 0xc2, 0x91, 0x8c, 0xb0, 0x17, 0xc4, 0x14, 0x34, 0x23, 0x00, 0x9a, 0x3c, 0x07, 0xb5, 0xc1, 0x81, 0xb0, 0xc1, 0xeb, 0x49, 0x4a, 0x62, 0xab, 0xc8, 0x39, 0x13, 0x97, 0x08, 0x9e, 0xa6, 0x64, 0x09, 0x67, 0xc1, 0x20, 0x49, 0x84, 0xcd, 0x48, 0x4c, 0xcc, 0xb0, 0x0a, 0x9a, 0x17, 0xd0, 0x87, 0x21, 0x84, 0x28, 0xef, 0x3b, 0xb7, 0x08, 0x78, 0x3e, 0x12, 0x82, 0x71, 0x04, 0x41, 0x73, 0x75, 0xb6, 0x95, 0x6f, 0xb5, 0x00, 0x53, 0xd0, 0x48, 0xa4, 0x79, 0x14, 0x95, 0x82, 0x4a, 0x34, 0x80, 0xa5, 0xb7, 0x83, 0x02, 0x56, 0x09, 0x6f, 0xdd, 0x72, 0x5c, 0x30, 0x8b, 0x3b, 0xe8, 0x4a, 0x07, 0xf3, 0x63, 0x2e, 0x24, 0x95, 0xc6, 0x2e, 0x96, 0x39, 0x9d, 0x80, 0xbf, 0xa7, 0x45, 0xb9, 0x84, 0x1a, 0x18, 0x33, 0xbc, 0x1d, 0x27, 0xba, 0x45, 0xa5, 0x21, 0x68, 0xee, 0x59, 0x00, 0x6c, 0x3a, 0x3a, 0x8c, 0x4a, 0x5a, 0x4f, 0x50, 0x88, 0xfc, 0x73, 0x71, 0x81, 0xab, 0x51, 0x96, 0xf7, 0xb1, 0xb4, 0x9a, 0x2e, 0xd8, 0x13, 0x13, 0x4e, 0x11, 0x2f, 0x73, 0x0b, 0x99, 0x1c, 0x54, 0xa7, 0x19, 0x6b, 0xcf, 0x5f, 0xc7, 0x6e, 0x13, 0x4c, 0x58, 0x43, 0xe1, 0x69, 0x88, 0x51, 0xb2, 0xf8, 0x69, 0xaf, 0xaf, 0xb0, 0x27, 0x87, 0xd9, 0xc2, 0xf1, 0x36, 0x90, 0x2d, 0xc7, 0xa7, 0xf3, 0xd6, 0x21, 0x56, 0xd1, 0x5e, 0xc3, 0x09, 0x56, 0x40, 0x92, 0xc6, 0x1d, 0x83, 0xb0, 0x98, 0x6c, 0x48, 0x40, 0x99, 0x81, 0xf3, 0xc1, 0x86, 0x88, 0x0a, 0x2f, 0x63, 0xd5, 0x86, 0x0a, 0xb6, 0x01, 0xde, 0xac, 0x2b, 0x6b, 0xa1, 0xb4, 0x28, 0x17, 0x9d, 0x73, 0x53, 0x3e, 0xb7, 0xa3, 0xa5, 0x11, 0x3b, 0x85, 0x61, 0xf1, 0x0b, 0x45, 0xc3, 0xcd, 0xe2, 0x82, 0xb6, 0xea, 0xd6, 0xab, 0x6c, 0x60, 0x4f, 0x09, 0xc1, 0x7b, 0xfd, 0xa0, 0x83, 0x13, 0xa3, 0x26, 0x07, 0x67, 0x5a, 0xdf, 0x64, 0x31, 0xca, 0x87, 0x18, 0xe9, 0xc4, 0x3a, 0x73, 0x73, 0x32, 0x27, 0xe7, 0x3b, 0xc6, 0x1a, 0xc8, 0x45, 0xba, 0x90, 0x77, 0x55, 0xce, 0xc6, 0x89, 0x25, 0xe5, 0xe2, 0xbf, 0xe9, 0x12, 0x95, 0x9d, 0xb8, 0x6f, 0xbf, 0xe2, 0x15, 0x6f, 0xd5, 0xbb, 0xdb, 0xf0, 0xc9, 0xdf, 0x8b, 0x53, 0x02, 0xaa, 0x8d, 0x90, 0xa2, 0x2d, 0x12, 0x27, 0x0e, 0x00, 0x65, 0x51, 0xe4, 0x76, 0x7e, 0x45, 0x26, 0x8e, 0xd9, 0x69, 0x26, 0x54, 0x44, 0x78, 0x11, 0xea, 0xb8, 0x4f, 0x04, 0x99, 0xa8, 0xa5, 0x8c, 0xf7, 0xc0, 0x4a, 0x59, 0x56, 0x98, 0x52, 0x80, 0x45, 0xf2, 0x98, 0x97, 0xc8, 0xfa, 0x96, 0xd0, 0x6c, 0xce, 0x51, 0xe6, 0xaf, 0xea, 0xc4, 0x33, 0x95, 0x89, 0xc9, 0x41, 0xc8, 0x55, 0x63, 0xd7, 0x0f, 0xac, 0xe1, 0x92, 0x88, 0x94, 0xba, 0xc0, 0x36, 0x19, 0xdf, 0xf4, 0xbe, 0x3f, 0x43, 0x14, 0xa3, 0xf7, 0x35, 0x1a, 0x09, 0xa4, 0x86, 0xb5, 0x04, 0x1e, 0x7c, 0xb2, 0xda, 0x8b, 0x96, 0xbc, 0x66, 0x26, 0xa4, 0x93, 0x17, 0x35, 0x7c, 0x41, 0x52, 0xa5, 0x1b, 0xa3, 0xc2, 0x8c, 0x7e, 0x0c, 0x9d, 0xb4, 0x1a, 0x06, 0xa2, 0x82, 0x90, 0xf2, 0x18, 0x73, 0x11, 0x07, 0xc9, 0x54, 0xd8, 0xa6, 0x6f, 0x80, 0x1d, 0x7d, 0xe1, 0x2a, 0x03, 0x71, 0x16, 0x99, 0x0b, 0x6c, 0x53, 0xc1, 0x29, 0xf1, 0x85, 0xc3, 0x45, 0xf2, 0x7e, 0x51, 0x8b, 0x2d, 0x5a, 0x91, 0x25, 0xa0, 0x70, 0x76, 0xd9, 0x91, 0xb7, 0xda, 0xc7, 0xcc, 0x65, 0xa8, 0x56, 0x2e, 0xfb, 0xcc, 0x32, 0xa9, 0xca, 0x4a, 0xd9, 0x02, 0x63, 0xb0, 0x4a, 0x4f, 0x90, 0x36, 0x11, 0x6c, 0x7b, 0x97, 0x48, 0x04, 0x96, 0x31, 0x75, 0x75, 0x65, 0x0d, 0xcc, 0x21, 0x52, 0xb5, 0xbc, 0x0e, 0x74, 0x40, 0x7e, 0x12, 0xfa, 0x8e, 0x4f, 0xfc, 0xcc, 0xff, 0x76, 0xc0, 0x1a, 0x97, 0x4b, 0xd6, 0x11, 0x02, 0xe1, 0xf5, 0x29, 0x64, 0x96, 0xc7, 0x1d, 0x07, 0x64, 0xe1, 0x32, 0x29, 0xff, 0xe7, 0x84, 0x6f, 0x33, 0x6e, 0x34, 0xca, 0xc9, 0x04, 0xca, 0x56, 0x70, 0xf8, 0xcd, 0x50, 0x52, 0x42, 0x7a, 0x79, 0xc0, 0x91, 0xa9, 0x71, 0x21, 0x0c, 0x5c, 0xff, 0x66, 0x7a, 0xac, 0x24, 0x93, 0x66, 0xe1, 0x0d, 0x2b, 0x11, 0x37, 0x6c, 0xa3, 0x9d, 0x93, 0x52, 0x04, 0xb1, 0x2c, 0xc5, 0x85, 0xe9, 0x40, 0x54, 0x03, 0x62, 0x5f, 0xb3, 0x2c, 0xb5, 0xe5, 0xc3, 0x1b, 0x62, 0x34, 0x81, 0x60, 0x51, 0x5c, 0xcc, 0x4f, 0xda, 0xf5, 0x70, 0x2d, 0x6b, 0xab, 0x5c, 0x37, 0x3d, 0xb6, 0xf3, 0x50, 0xd3, 0xe6, 0x3a, 0x5c, 0xe3, 0xca, 0x54, 0x74, 0xa0, 0xcf, 0x15, 0x67, 0x04, 0x2c, 0xa3, 0x25, 0x89, 0x86, 0xff, 0x75, 0xbd, 0xfc, 0xd9, 0x29, 0xe6, 0x46, 0x2f, 0x36, 0xbc, 0xcc, 0x3f, 0x5a, 0x93, 0x35, 0x2a, 0x2b, 0x36, 0xcb, 0x16, 0x2e, 0x18, 0x74, 0xc7, 0x42, 0x87, 0x0a, 0x97, 0xb1, 0x67, 0xa0, 0x50, 0x37, 0x36, 0x24, 0xea, 0xeb, 0x7e, 0x50, 0x73, 0x25, 0x6b, 0x72, 0x11, 0xb2, 0xd9, 0x4b, 0x84, 0x06, 0xcd, 0x6c, 0x95, 0x33, 0xb1, 0x53, 0x64, 0x08, 0xab, 0x0a, 0x29, 0xe5, 0xb2, 0xf0, 0xc9, 0x54, 0xec, 0xe0, 0x0f, 0xbb, 0xeb, 0x17, 0x6d, 0x72, 0x4d, 0x4c, 0xf4, 0x43, 0xcf, 0x70, 0x20, 0xd5, 0xfa, 0x70, 0x94, 0xcc, 0x1b, 0x1b, 0xe6, 0x97, 0xba, 0xd3, 0x36, 0x74, 0xe4, 0x09, 0x9e, 0xc7, 0xbb, 0x18, 0xf4, 0x57, 0x71, 0x28, 0xcd, 0xd9, 0x7c, 0xcd, 0x6d, 0x44, 0x62, 0xe5, 0x60, 0x7c, 0x51, 0x2a, 0x3e, 0x36, 0x24, 0x8e, 0x3d, 0xda, 0xa2, 0xec, 0x08, 0x9a, 0xef, 0xc4, 0xce, 0x48, 0x5c, 0x49, 0xd7, 0xb0, 0x09, 0xc8, 0xd6, 0x31, 0x15, 0xfc, 0x81, 0xff, 0x3a, 0x62, 0xd1, 0x5a, 0x88, 0x44, 0x1c, 0x03, 0xea, 0x1c, 0x2e, 0x72, 0xc4, 0x88, 0x39, 0xfc, 0x6a, 0xd7, 0x3a, 0x30, 0x74, 0x4a, 0x62, 0xb7, 0xb2, 0x16, 0x45, 0xa6, 0xaf, 0x7d, 0x61, 0xb6, 0x38, 0x3b, 0x22, 0x1e, 0x21, 0x90, 0x55, 0x57, 0xcd, 0x29, 0xd9, 0x24, 0xa6, 0x09, 0x86, 0xc5, 0x11, 0xc1, 0xeb, 0xbc, 0x31, 0x6d, 0x56, 0x30, 0xa2, 0x41, 0x43, 0x23, 0xf5, 0x3a, 0xd5, 0x59, 0x94, 0xf6, 0xb3, 0x65, 0x39, 0xf9, 0xc4, 0x40, 0x75, 0xa5, 0x33, 0xe4, 0x81, 0xc0, 0x84, 0x45, 0xd9, 0xca, 0x9e, 0x9d, 0x38, 0x21, 0x19, 0x38, 0x8b, 0xd1, 0xd7, 0x50, 0x52, 0x21, 0x7a, 0x94, 0x4c, 0xcc, 0x7b, 0xe9, 0x09, 0xe2, 0x19, 0x71, 0x1f, 0xcc, 0x79, 0x24, 0x76, 0x92, 0x13, 0xa1, 0x92, 0x53, 0x4a, 0x55, 0x80, 0x08, 0x15, 0x7a, 0x39, 0x6e, 0xdf, 0xf4, 0x80, 0xcc, 0x3b, 0x52, 0x0f, 0xf8, 0x18, 0xb3, 0x8b, 0x13, 0x5c, 0x18, 0xa8, 0x0d, 0x51, 0x05, 0xe6, 0x78, 0x83, 0x6c, 0x39, 0x5c, 0x28, 0xe9, 0x2f, 0x7a, 0x3c, 0x4e, 0x93, 0xc0, 0x10, 0x35, 0xf3, 0x41, 0x11, 0xcc, 0x49, 0x02, 0xd0, 0xc0, 0x33, 0xa6, 0x3f, 0x23, 0x6a, 0x71, 0xda, 0x97, 0x4a, 0x6f, 0x40, 0x4f, 0x7a, 0xa7, 0xb5, 0xe5, 0x82, 0xc7, 0x58, 0x14, 0x2f, 0xc1, 0x82, 0x6b, 0xba, 0x98, 0xb2, 0x7d, 0x57, 0xc2, 0xe2, 0x10, 0x3e, 0x10, 0xe3, 0x0d, 0x32, 0x79, 0x7b, 0x96, 0x77, 0x14, 0xd1, 0x56, 0x61, 0x11, 0x13, 0x71, 0xa2, 0xd9, 0xc5, 0x39, 0x98, 0x12, 0x46, 0x46, 0x22, 0x63, 0x5b, 0x44, 0x21, 0x26, 0xb0, 0x98, 0x36, 0xb0, 0x81, 0x82, 0x72, 0x47, 0xd0, 0x54, 0x22, 0x97, 0x2b, 0xd0, 0x32, 0x0d, 0x8f, 0x42, 0xbf, 0x57, 0xe3, 0x49, 0x46, 0x12, 0x34, 0xe4, 0xd9, 0x4f, 0x01, 0x18, 0x50, 0xba, 0xb5, 0xc0, 0x49, 0xb6, 0x2a, 0x59, 0x43, 0x38, 0x66, 0xfc, 0xce, 0x69, 0x66, 0x49, 0x5c, 0x26, 0x5c, 0x47, 0x65, 0xa5, 0x6c, 0x06, 0xb9, 0xfc, 0x42, 0x76, 0x54, 0x87, 0x85, 0xf4, 0x68, 0x28, 0xca, 0x60, 0x2d, 0xc6, 0xd0, 0x54, 0x1f, 0x25, 0x07, 0x89, 0xc4, 0x9e, 0x8b, 0x06, 0x55, 0x9c, 0x43, 0x44, 0x60, 0xa8, 0x43, 0x80, 0x98, 0x54, 0xe5, 0xb4, 0x6e, 0x89, 0x38, 0x9f, 0x10, 0xf4, 0x89, 0x66, 0x74, 0x91, 0xc1, 0x93, 0x5e, 0x8a, 0xfb, 0x9e, 0xb4, 0x71, 0x8f, 0x86, 0xac, 0x45, 0x89, 0x32, 0xbc, 0xf3, 0x3c, 0x9a, 0xbe, 0xcb, 0x2d, 0xc0, 0xc0, 0x93, 0xa7, 0xe8, 0x1d, 0xa0, 0x32, 0x7b, 0xb6, 0x37, 0x52, 0x81, 0x05, 0xc3, 0x58, 0xeb, 0x76, 0x8d, 0x32, 0x3a, 0x37, 0xd4, 0x0a, 0x8c, 0x19, 0x9b, 0x7c, 0x4b, 0xb1, 0xd7, 0x2b, 0x72, 0xb6, 0x90, 0xb3, 0x6d, 0xd2, 0x7a, 0x93, 0x55, 0x19, 0x1b, 0x3c, 0x3a, 0xa6, 0x75, 0xa7, 0xe6, 0xf8, 0x55, 0xeb, 0x50, 0x5f, 0x57, 0x98, 0x65, 0xdb, 0xd8, 0x91, 0x05, 0x65, 0x50, 0x5e, 0x7c, 0x0f, 0xdd, 0x54, 0x5c, 0xbb, 0xb8, 0x71, 0xb0, 0xb2, 0xcc, 0x01, 0x25, 0xb7, 0x4f, 0x6b, 0x0c, 0x9b, 0x79, 0x67, 0x0a, 0x62, 0x02, 0xd1, 0xb9, 0x15, 0x4a, 0xc7, 0x76, 0x6b, 0x19, 0x19, 0xc4, 0x89, 0x58, 0x90, 0x86, 0xad, 0x8b, 0x45, 0xbe, 0x0d, 0x79, 0xc9, 0x76, 0xc3, 0xc3, 0x9d, 0x6b, 0x25, 0x21, 0x3b, 0xb0, 0xb7, 0x8a, 0x57, 0x50, 0xe6, 0xa8, 0xeb, 0x34, 0x33, 0x0b, 0xb3, 0xcf, 0xf2, 0xb1, 0xc0, 0x72, 0x2a, 0xc8, 0x83, 0xb0, 0x48, 0xf4, 0xb8, 0xcd, 0x06, 0x19, 0x6d, 0xa8, 0xaa, 0x8b, 0x05, 0xda, 0x42, 0x67, 0x55, 0x2b, 0xf8, 0x7a, 0xbc, 0xa5, 0x12, 0x4d, 0xc3, 0x58, 0xa8, 0x38, 0x10, 0x40, 0xe9, 0xb8, 0x1f, 0xb0, 0x84, 0x43, 0x15, 0x02, 0x15, 0xd6, 0x92, 0x23, 0x28, 0x00, 0x0a, 0xc0, 0xb7, 0x88, 0xb1, 0x21, 0x93, 0x1a, 0x26, 0x7d, 0x80, 0x61, 0x9c, 0xe7, 0xd2, 0x9c, 0xd7, 0x6b, 0x60, 0xcf, 0x65, 0x83, 0xdc, 0xe8, 0xce, 0xbc, 0x49, 0x01, 0x85, 0x73, 0x6c, 0x81, 0x8b, 0x25, 0xad, 0x26, 0x0b, 0x66, 0x7b, 0x1f, 0xfd, 0x46, 0x20, 0x6d, 0x01, 0x04, 0x55, 0x3a, 0xa9, 0xfb, 0x30, 0x45, 0x54, 0xa2, 0x1c, 0x32, 0x72, 0x44, 0xce, 0x78, 0xaf, 0xdb, 0xd3, 0xb4, 0x62, 0x36, 0x1b, 0xb0, 0x68, 0xa1, 0x55, 0x63, 0x64, 0x09, 0xf5, 0x74, 0xc5, 0x71, 0x65, 0x72, 0xe2, 0xa5, 0xf2, 0xa4, 0xb0, 0x4f, 0xb8, 0xaa, 0xd1, 0x23, 0x66, 0x84, 0x84, 0x17, 0x87, 0x56, 0x2a, 0xaf, 0x46, 0xc2, 0xc0, 0xda, 0x46, 0x65, 0xea, 0xfd, 0x46, 0x5f, 0xc6, 0x4a, 0x0c, 0x5f, 0x8f, 0x3f, 0x90, 0x03, 0x48, 0x94, 0x15, 0x89, 0x9d, 0x59, 0xa5, 0x43, 0xd8, 0x20, 0x8c, 0x54, 0xa3, 0x16, 0x65, 0x29, 0xb5, 0x39, 0x22, }, .secret_len = 32, .secret = { 0xfb, 0xc4, 0xee, 0xa6, 0x91, 0xee, 0xf4, 0xc1, 0xb4, 0x76, 0xa2, 0x99, 0x36, 0x45, 0x3f, 0x4c, 0x3d, 0x48, 0x81, 0x79, 0x4e, 0xe3, 0x7b, 0xaf, 0x0f, 0xd7, 0x28, 0x40, 0x74, 0x3e, 0x7b, 0x7d, }, .cipher_len = 1568, .cipher = { 0xc2, 0x7f, 0x01, 0x24, 0x4d, 0x4b, 0x3f, 0xb2, 0x1d, 0x84, 0x37, 0xf8, 0x40, 0x01, 0x7c, 0xcc, 0xb7, 0xb7, 0xda, 0xd5, 0xfb, 0x2b, 0x47, 0xb9, 0xb5, 0x7e, 0xae, 0x4f, 0x77, 0xd0, 0xa4, 0x55, 0x5e, 0x50, 0x92, 0xa2, 0x49, 0x69, 0xf2, 0x27, 0x3e, 0x97, 0x02, 0x88, 0x4a, 0x08, 0x47, 0x7b, 0x56, 0x8d, 0x80, 0x17, 0xf1, 0x38, 0x75, 0xd1, 0xf5, 0xa6, 0xd4, 0x13, 0xbd, 0xd2, 0x28, 0xeb, 0xb1, 0x12, 0x60, 0xf7, 0xf4, 0x52, 0x9c, 0xbc, 0xeb, 0xf9, 0xb6, 0x86, 0x2e, 0x8a, 0x84, 0x12, 0x35, 0xf2, 0x9f, 0x60, 0xf8, 0xe8, 0x41, 0x74, 0x34, 0x18, 0x9d, 0x57, 0x99, 0x20, 0xfe, 0x6b, 0x98, 0xdb, 0xe7, 0x13, 0xec, 0x16, 0xc3, 0xfd, 0xdb, 0xb8, 0x1e, 0x73, 0x1d, 0x95, 0x6b, 0x06, 0xdb, 0x49, 0x80, 0xf4, 0x9c, 0x26, 0xf2, 0x86, 0x61, 0xff, 0x9c, 0xe6, 0xe9, 0xd8, 0x61, 0xec, 0x7a, 0x09, 0x84, 0x0c, 0x19, 0xde, 0x0e, 0xb6, 0x72, 0x20, 0x71, 0xf8, 0xaa, 0x48, 0x36, 0x2d, 0x2f, 0xf1, 0x27, 0xa4, 0xae, 0x46, 0xf9, 0x93, 0x37, 0x82, 0x68, 0x32, 0xad, 0xac, 0x23, 0x91, 0x65, 0xf2, 0x25, 0x85, 0xbb, 0x57, 0xa8, 0x89, 0xc9, 0xc6, 0xaf, 0x82, 0x36, 0x7e, 0xc7, 0xb0, 0x72, 0x37, 0xc0, 0x53, 0x5b, 0x31, 0xb3, 0x8c, 0x1c, 0xac, 0x40, 0xac, 0x1a, 0x0c, 0x95, 0x8a, 0x18, 0x87, 0xfe, 0x34, 0x71, 0x10, 0x83, 0xfd, 0x37, 0xaf, 0x4b, 0xc5, 0xb1, 0xb4, 0xe1, 0xe2, 0xee, 0x28, 0x43, 0x69, 0x3d, 0x57, 0xdd, 0x1e, 0x65, 0x7d, 0x4c, 0x24, 0xed, 0x20, 0x7e, 0xe7, 0x12, 0xad, 0x2a, 0x08, 0x91, 0x45, 0x81, 0x80, 0xe9, 0xe8, 0xbd, 0x36, 0xfc, 0x14, 0xd8, 0xd6, 0x33, 0xf5, 0xb7, 0x41, 0xce, 0xa1, 0x08, 0xd2, 0xd4, 0xfd, 0x75, 0x1c, 0x5a, 0x67, 0xb0, 0x5e, 0x30, 0x32, 0x4a, 0x67, 0xe9, 0xdd, 0x75, 0xc9, 0x93, 0xd4, 0xfe, 0x08, 0x54, 0xfb, 0x78, 0xdf, 0x6f, 0x3d, 0x45, 0xa2, 0xa9, 0xc8, 0xe4, 0x25, 0x10, 0xf0, 0xc3, 0xd8, 0x02, 0x03, 0x71, 0x2f, 0xb3, 0x9e, 0x36, 0xb5, 0xdd, 0x8b, 0x5c, 0xcd, 0x3d, 0x09, 0xce, 0xa9, 0x42, 0x03, 0xba, 0xf8, 0x72, 0x08, 0x45, 0x71, 0xec, 0xf9, 0x78, 0xbd, 0xb9, 0x54, 0x8a, 0x25, 0x0e, 0xe4, 0x90, 0x7b, 0x4a, 0xfc, 0x31, 0xb2, 0x1f, 0x31, 0x9a, 0xe4, 0xbf, 0x0a, 0xb1, 0x9c, 0xbd, 0x11, 0xeb, 0xe1, 0x33, 0x59, 0xd1, 0xaa, 0xf4, 0xfd, 0xb8, 0x3b, 0x65, 0x02, 0x50, 0x14, 0x22, 0xa5, 0xfe, 0x50, 0xa8, 0xa3, 0x8e, 0xf5, 0x3d, 0xeb, 0x60, 0x3c, 0xe2, 0x3f, 0xd9, 0x79, 0x2b, 0x04, 0xde, 0xb3, 0x78, 0x71, 0x9a, 0xb7, 0x69, 0xaa, 0x58, 0x97, 0xcc, 0x65, 0xe9, 0xb1, 0x63, 0x04, 0xce, 0xa5, 0x37, 0xe1, 0x76, 0x2b, 0xd8, 0xc9, 0xb1, 0x09, 0xda, 0x14, 0xa8, 0x29, 0xe6, 0x41, 0x9f, 0x1b, 0x9f, 0xf8, 0xa4, 0x66, 0xe2, 0xa6, 0xd6, 0xb3, 0x4d, 0x74, 0xff, 0xe1, 0xa5, 0x92, 0x99, 0x18, 0x17, 0x59, 0xd0, 0xd3, 0x87, 0xfc, 0xed, 0x1d, 0x90, 0x7f, 0x5f, 0xb5, 0xed, 0xb4, 0x26, 0xc0, 0x51, 0x30, 0xe6, 0xca, 0x59, 0x09, 0xb2, 0x76, 0xd1, 0xa4, 0x7e, 0x71, 0x3c, 0x30, 0xd9, 0x96, 0xda, 0x5e, 0x8e, 0x57, 0xe7, 0x12, 0xc7, 0x77, 0x38, 0xf2, 0x1b, 0xe7, 0x4b, 0x42, 0xb5, 0x18, 0x43, 0x2d, 0xad, 0x7e, 0xf7, 0x3e, 0x6a, 0x8c, 0x43, 0xaa, 0x9a, 0x62, 0x69, 0x94, 0xd7, 0x1a, 0x31, 0x81, 0x28, 0x51, 0x80, 0x6e, 0x9f, 0xbb, 0x1f, 0x2b, 0xd3, 0x56, 0xce, 0xa3, 0x9d, 0x95, 0xf2, 0xf8, 0x7c, 0xa3, 0x0d, 0xaf, 0x6f, 0x27, 0x33, 0xf7, 0xbc, 0xe7, 0x9f, 0x8d, 0xa9, 0x95, 0x05, 0x1e, 0x49, 0xa7, 0xfd, 0x22, 0x64, 0x37, 0x9c, 0x0a, 0x75, 0x2e, 0x55, 0x3e, 0xd6, 0x08, 0xeb, 0x93, 0x44, 0xc7, 0x94, 0x98, 0xf6, 0x91, 0x53, 0x85, 0x64, 0xc5, 0x4f, 0x82, 0x3b, 0xb7, 0x0b, 0x12, 0xb5, 0x9e, 0x88, 0x24, 0xb4, 0xa4, 0xbb, 0x1e, 0xea, 0xc6, 0x7c, 0x81, 0x0c, 0xcc, 0x2e, 0x23, 0x74, 0x47, 0x83, 0xce, 0x95, 0x80, 0x97, 0xf7, 0xa6, 0xbc, 0x6e, 0x1f, 0x17, 0x59, 0x75, 0x21, 0xb8, 0xc3, 0xd1, 0xee, 0x85, 0x96, 0xa2, 0x9f, 0xfe, 0xf1, 0x4e, 0xd9, 0x16, 0x32, 0x09, 0x7c, 0x16, 0xd5, 0x06, 0x5d, 0xb2, 0xa9, 0x63, 0xca, 0x73, 0x83, 0xac, 0x60, 0xad, 0x8f, 0x4e, 0xd0, 0xd4, 0x1b, 0xd0, 0xbc, 0x3b, 0xaf, 0x19, 0x8c, 0x51, 0x25, 0xae, 0x91, 0x15, 0x06, 0xc9, 0x26, 0xd4, 0xc1, 0x17, 0x85, 0xfd, 0x61, 0x82, 0x29, 0xbf, 0xf5, 0x4c, 0xb1, 0x16, 0x1a, 0xb8, 0xfc, 0x7b, 0x51, 0xda, 0xec, 0xcc, 0xd9, 0x13, 0x1e, 0xdf, 0x43, 0x7d, 0x8e, 0x52, 0x8e, 0x75, 0x81, 0xb8, 0x2c, 0x66, 0x0e, 0x8c, 0x5e, 0x25, 0x12, 0xd5, 0xf6, 0x38, 0x0a, 0x52, 0x8f, 0x2a, 0xe4, 0xae, 0xe2, 0x63, 0xdb, 0x96, 0x76, 0x02, 0x4b, 0xc7, 0xad, 0x39, 0x8b, 0xc9, 0xcd, 0xda, 0xd6, 0x07, 0x96, 0x8b, 0xba, 0xb2, 0x23, 0x29, 0xe0, 0x4d, 0x6e, 0x77, 0x1f, 0xe6, 0x47, 0x10, 0x7a, 0xc4, 0x66, 0x67, 0xa5, 0x1a, 0xd5, 0x58, 0xa6, 0x35, 0xf0, 0x26, 0x95, 0x1f, 0x4f, 0x48, 0xc8, 0x88, 0xd7, 0x01, 0xc2, 0xaf, 0xf4, 0xea, 0xb4, 0xe3, 0x4a, 0xdb, 0x15, 0x9a, 0xbb, 0xbf, 0xab, 0xe5, 0x9b, 0x3f, 0x4c, 0xf8, 0xaa, 0xb1, 0xdd, 0x66, 0x1e, 0x4d, 0xd0, 0xc5, 0x55, 0x8d, 0xc0, 0x59, 0x20, 0x2e, 0xe6, 0x46, 0x25, 0xa3, 0xb4, 0xb9, 0x2f, 0xf4, 0xd1, 0x56, 0x97, 0xf1, 0x6c, 0x18, 0xd4, 0xd2, 0x33, 0x8c, 0xfb, 0x49, 0x6e, 0x07, 0x03, 0x52, 0x68, 0x71, 0xc9, 0x78, 0x4b, 0xac, 0x8e, 0xba, 0xe8, 0x27, 0x9c, 0xf2, 0x71, 0x3a, 0xf3, 0xcc, 0x2d, 0x44, 0x0e, 0x8c, 0xd2, 0x00, 0x86, 0x7b, 0x85, 0x18, 0xaa, 0xd3, 0xb9, 0xe2, 0x85, 0x02, 0x7d, 0xa0, 0xad, 0xd9, 0xf0, 0x22, 0x9e, 0xd4, 0xe8, 0x42, 0xd0, 0x5e, 0x22, 0x6a, 0xda, 0xc1, 0x3a, 0x39, 0x52, 0xe3, 0x83, 0x5c, 0x8f, 0xb0, 0xa4, 0x28, 0x74, 0xc9, 0x4c, 0x66, 0x1b, 0x39, 0xdf, 0x7b, 0x72, 0x88, 0x7d, 0x22, 0x7d, 0x58, 0x3c, 0xe6, 0xb3, 0xbd, 0x65, 0xf7, 0x95, 0x10, 0x7b, 0xd0, 0x93, 0x38, 0x9b, 0xfe, 0xfd, 0x17, 0x68, 0xa5, 0x71, 0x6f, 0x68, 0x5b, 0x17, 0x4e, 0xd2, 0x3e, 0x94, 0xa5, 0x95, 0x6e, 0x29, 0xbb, 0x2d, 0xdb, 0x79, 0x21, 0x03, 0xe6, 0x2f, 0x68, 0x92, 0x8a, 0xcc, 0x60, 0x3e, 0xec, 0x2f, 0xf5, 0x6d, 0xb1, 0x4c, 0x08, 0xb7, 0xcb, 0xe4, 0xe2, 0xb4, 0xf2, 0xe0, 0xea, 0xee, 0x54, 0x16, 0x2e, 0x95, 0xbb, 0x35, 0xef, 0x36, 0x30, 0x3e, 0xe3, 0xe6, 0xcc, 0x61, 0x06, 0x13, 0x73, 0x87, 0x6f, 0x7a, 0x09, 0x6a, 0x8a, 0xf5, 0x7d, 0x78, 0x2f, 0x8c, 0x82, 0x03, 0xde, 0x93, 0x42, 0x3a, 0x37, 0x91, 0x22, 0xfe, 0x7d, 0xad, 0x77, 0x0c, 0x36, 0x90, 0xf9, 0x78, 0x22, 0x84, 0x60, 0xd0, 0x25, 0xce, 0x93, 0xb1, 0xb3, 0x36, 0xc5, 0x73, 0xe4, 0xe5, 0x58, 0x40, 0xea, 0x65, 0xcf, 0xdd, 0x61, 0x22, 0xc6, 0x72, 0xc9, 0x12, 0xf5, 0x29, 0x39, 0xd9, 0xea, 0x5b, 0xe0, 0x62, 0x10, 0xf5, 0xe7, 0xed, 0xb6, 0x5b, 0x66, 0x94, 0x5d, 0x70, 0x56, 0xf5, 0x59, 0xa7, 0xd6, 0x92, 0x53, 0xf4, 0xbd, 0xbc, 0x57, 0x9d, 0xe9, 0x64, 0xf3, 0xe9, 0x3a, 0x86, 0xfa, 0x38, 0xb6, 0xa2, 0xc0, 0xb5, 0x43, 0x38, 0xdc, 0xe0, 0x93, 0xf0, 0xb4, 0x68, 0x4e, 0xe3, 0x61, 0x44, 0x9f, 0x16, 0xc2, 0x79, 0xa7, 0x2b, 0x77, 0x31, 0xe4, 0x46, 0x00, 0xa7, 0x02, 0x77, 0x68, 0xfd, 0xd0, 0xf6, 0x43, 0xed, 0x10, 0x06, 0x4b, 0x98, 0xa9, 0xda, 0x03, 0x2f, 0x1f, 0x5d, 0xea, 0xd3, 0x11, 0xe1, 0x77, 0x33, 0x50, 0x94, 0xdb, 0x4e, 0x38, 0x51, 0x4e, 0xae, 0x15, 0xa8, 0xf8, 0xec, 0xf2, 0xf2, 0x41, 0x4e, 0x37, 0x8e, 0xfb, 0xf9, 0x97, 0xb1, 0x06, 0x6b, 0x6f, 0x69, 0xd6, 0x69, 0x09, 0xa4, 0x7e, 0x29, 0x8a, 0x7f, 0xec, 0x96, 0x1a, 0x83, 0x78, 0x2e, 0x0e, 0x47, 0x0f, 0xe0, 0x71, 0xde, 0xcf, 0x4b, 0x26, 0xac, 0xa6, 0xed, 0x68, 0x83, 0x59, 0xe1, 0x08, 0x50, 0x55, 0xfd, 0x2b, 0x5a, 0xe9, 0xf4, 0x91, 0x87, 0x49, 0x89, 0x7a, 0xf1, 0x33, 0x60, 0x60, 0x53, 0xd5, 0xf6, 0xa8, 0x52, 0x8c, 0xcb, 0x31, 0xab, 0x7f, 0x3f, 0x2d, 0x89, 0xa9, 0x5c, 0x5f, 0x05, 0xb1, 0x57, 0x00, 0xe5, 0x32, 0xad, 0x81, 0xd5, 0x9d, 0x9d, 0xb8, 0xa2, 0xc2, 0x9c, 0xac, 0x93, 0x6e, 0x3f, 0x33, 0xdf, 0xe2, 0x4b, 0x0b, 0x1b, 0x71, 0x90, 0x2d, 0xc9, 0xc3, 0x0e, 0xc8, 0xc7, 0x0b, 0xda, 0xba, 0x48, 0x4f, 0xcd, 0x2b, 0x94, 0x6d, 0x73, 0x5f, 0x16, 0xee, 0xad, 0x04, 0x03, 0x1c, 0xaf, 0xde, 0x9e, 0xe0, 0x16, 0x96, 0xec, 0x9f, 0x0a, 0x8d, 0x5f, 0x36, 0xb6, 0x9c, 0x64, 0x2f, 0xfd, 0x0a, 0xd0, 0xd2, 0x54, 0x4f, 0x5e, 0x7f, 0xd8, 0x9a, 0x80, 0x49, 0x8e, 0xf6, 0x8e, 0x18, 0x16, 0x17, 0xfa, 0xd4, 0x1e, 0x0b, 0xd5, 0x9b, 0xaa, 0xff, 0xee, 0xfe, 0x2f, 0x99, 0x72, 0x4c, 0x71, 0x9d, 0x47, 0xa2, 0xec, 0xba, 0x72, 0x1d, 0x76, 0xf2, 0x37, 0xeb, 0xa7, 0x3d, 0xb4, 0x7d, 0x88, 0xb6, 0x99, 0xe3, 0x58, 0x2b, 0x07, 0x3c, 0x7e, 0xad, 0x2a, 0x5b, 0x3c, 0xf0, 0x24, 0x46, 0x63, 0x96, 0xf9, 0xf2, 0x82, 0x6c, 0xb7, 0x54, 0xf6, 0x60, 0x18, 0xe9, 0x50, 0x3f, 0x4a, 0xd1, 0xf9, 0xd9, 0x21, 0x21, 0xaa, 0x99, 0x56, 0x50, 0x60, 0x51, 0xd5, 0x96, 0xff, 0xd4, 0x67, 0xe1, 0xaa, 0x8d, 0x96, 0x4c, 0x17, 0x67, 0xc9, 0x25, 0xb4, 0x68, 0xbb, 0xc9, 0x85, 0x06, 0x00, 0xc8, 0x43, 0x49, 0x05, 0x41, 0xe8, 0x55, 0x5a, 0x3d, 0x8b, 0xd9, 0xf1, 0x87, 0x91, 0xef, 0x9e, 0xbd, 0x35, 0x94, 0xe7, 0x4c, 0x1f, 0xe3, 0xd3, 0xb8, 0x09, 0x40, 0xa8, 0xa0, 0x79, 0xf8, 0xd2, 0xca, 0x8d, 0x30, 0x13, 0x4f, 0xc6, 0x6f, 0x87, 0x00, 0x81, 0x26, 0xe4, 0x3b, 0xd0, 0x6e, 0xb6, 0xe4, 0x1c, 0x3a, 0x70, 0xfa, 0x47, 0x39, 0x31, 0x9b, 0xf1, 0xa9, 0x32, 0xf0, 0x2c, 0x30, 0x64, 0x56, 0x56, 0x0c, 0xda, 0x44, 0xdd, 0xac, 0x43, 0xed, 0x6d, 0x90, 0x04, 0x45, 0xf5, 0xbf, 0x85, 0xbb, 0x0c, 0xe3, 0x25, 0x94, 0x74, 0x36, 0xe0, 0xd0, 0x68, 0x5e, 0x41, 0xb1, 0x6b, 0xc7, 0x16, 0x95, 0x18, 0x25, 0x9e, 0x57, 0x34, 0xfd, 0xce, 0x08, 0x0f, 0xfe, 0x85, 0x19, 0x1b, 0x1d, 0x8d, 0x8d, 0xe4, 0xdb, 0x48, 0x14, 0x3f, 0xb5, 0x64, 0x03, 0x8a, 0xce, 0x80, 0x10, 0x4d, 0x3a, 0x8d, 0x07, 0x12, 0x45, 0xe2, 0xaa, 0x56, 0xc7, 0x19, 0x33, 0xf4, 0xdc, 0xf9, 0x25, 0xee, 0xe8, 0x44, 0xc8, 0x0f, 0xdd, 0xf3, 0x25, 0x1f, 0x74, 0x00, 0x6a, 0x23, 0x41, 0x33, 0x18, 0xbb, 0xfd, 0x2e, 0xd9, 0xe0, 0x53, 0x51, 0xb5, 0xaa, 0xeb, 0xcc, 0x77, 0xcf, 0xac, 0x8d, 0x5f, 0x03, 0x64, 0x23, 0x1a, 0x50, 0xea, 0x86, 0x47, 0xc7, 0x2f, 0x71, 0x3e, 0x81, 0x7a, 0x20, 0x75, 0x32, 0x30, 0x29, 0xe3, 0xb8, 0x8b, 0x72, 0x44, 0x22, 0x64, 0xc5, 0x97, 0xb0, 0xf1, 0xfc, 0x09, 0xf9, 0x40, 0x1c, 0xe8, 0x8a, 0xc9, 0x7c, 0x55, 0x22, 0xa5, 0x63, 0x64, 0x52, 0x3c, 0x37, 0xfe, 0xa2, 0xd6, 0xbd, 0x06, 0xb2, }, }, { .name = "Kyber Round 2, 1024 KAT 0", .version = 0, .keyform = CK_IBM_KYBER_KEYFORM_ROUND2_1024, .sk_len = 3168, .sk = { 0x07, 0x63, 0x8F, 0xB6, 0x98, 0x68, 0xF3, 0xD3, 0x20, 0xE5, 0x86, 0x2B, 0xD9, 0x69, 0x33, 0xFE, 0xB3, 0x11, 0xB3, 0x62, 0x09, 0x3C, 0x9B, 0x5D, 0x50, 0x17, 0x0B, 0xCE, 0xD4, 0x3F, 0x1B, 0x53, 0x6D, 0x9A, 0x20, 0x4B, 0xB1, 0xF2, 0x26, 0x95, 0x95, 0x0B, 0xA1, 0xF2, 0xA9, 0xE8, 0xEB, 0x82, 0x8B, 0x28, 0x44, 0x88, 0x76, 0x0B, 0x3F, 0xC8, 0x4F, 0xAB, 0xA0, 0x42, 0x75, 0xD5, 0x62, 0x8E, 0x39, 0xC5, 0xB2, 0x47, 0x13, 0x74, 0x28, 0x3C, 0x50, 0x32, 0x99, 0xC0, 0xAB, 0x49, 0xB6, 0x6B, 0x8B, 0xBB, 0x56, 0xA4, 0x18, 0x66, 0x24, 0xF9, 0x19, 0xA2, 0xBA, 0x59, 0xBB, 0x08, 0xD8, 0x55, 0x18, 0x80, 0xC2, 0xBE, 0xFC, 0x4F, 0x87, 0xF2, 0x5F, 0x59, 0xAB, 0x58, 0x7A, 0x79, 0xC3, 0x27, 0xD7, 0x92, 0xD5, 0x4C, 0x97, 0x4A, 0x69, 0x26, 0x2F, 0xF8, 0xA7, 0x89, 0x38, 0x28, 0x9E, 0x9A, 0x87, 0xB6, 0x88, 0xB0, 0x83, 0xE0, 0x59, 0x5F, 0xE2, 0x18, 0xB6, 0xBB, 0x15, 0x05, 0x94, 0x1C, 0xE2, 0xE8, 0x1A, 0x5A, 0x64, 0xC5, 0xAA, 0xC6, 0x04, 0x17, 0x25, 0x69, 0x85, 0x34, 0x9E, 0xE4, 0x7A, 0x52, 0x42, 0x0A, 0x5F, 0x97, 0x47, 0x7B, 0x72, 0x36, 0xAC, 0x76, 0xBC, 0x70, 0xE8, 0x28, 0x87, 0x29, 0x28, 0x7E, 0xE3, 0xE3, 0x4A, 0x3D, 0xBC, 0x36, 0x83, 0xC0, 0xB7, 0xB1, 0x00, 0x29, 0xFC, 0x20, 0x34, 0x18, 0x53, 0x7E, 0x74, 0x66, 0xBA, 0x63, 0x85, 0xA8, 0xFF, 0x30, 0x1E, 0xE1, 0x27, 0x08, 0xF8, 0x2A, 0xAA, 0x1E, 0x38, 0x0F, 0xC7, 0xA8, 0x8F, 0x8F, 0x20, 0x5A, 0xB7, 0xE8, 0x8D, 0x7E, 0x95, 0x95, 0x2A, 0x55, 0xBA, 0x20, 0xD0, 0x9B, 0x79, 0xA4, 0x71, 0x41, 0xD6, 0x2B, 0xF6, 0xEB, 0x7D, 0xD3, 0x07, 0xB0, 0x8E, 0xCA, 0x13, 0xA5, 0xBC, 0x5F, 0x6B, 0x68, 0x58, 0x1C, 0x68, 0x65, 0xB2, 0x7B, 0xBC, 0xDD, 0xAB, 0x14, 0x2F, 0x4B, 0x2C, 0xBF, 0xF4, 0x88, 0xC8, 0xA2, 0x27, 0x05, 0xFA, 0xA9, 0x8A, 0x2B, 0x9E, 0xEA, 0x35, 0x30, 0xC7, 0x66, 0x62, 0x33, 0x5C, 0xC7, 0xEA, 0x3A, 0x00, 0x77, 0x77, 0x25, 0xEB, 0xCC, 0xCD, 0x2A, 0x46, 0x36, 0xB2, 0xD9, 0x12, 0x2F, 0xF3, 0xAB, 0x77, 0x12, 0x3C, 0xE0, 0x88, 0x3C, 0x19, 0x11, 0x11, 0x5E, 0x50, 0xC9, 0xE8, 0xA9, 0x41, 0x94, 0xE4, 0x8D, 0xD0, 0xD0, 0x9C, 0xFF, 0xB3, 0xAD, 0xCD, 0x2C, 0x1E, 0x92, 0x43, 0x09, 0x03, 0xD0, 0x7A, 0xDB, 0xF0, 0x05, 0x32, 0x03, 0x15, 0x75, 0xAA, 0x7F, 0x9E, 0x7B, 0x5A, 0x1F, 0x33, 0x62, 0xDE, 0xC9, 0x36, 0xD4, 0x04, 0x3C, 0x05, 0xF2, 0x47, 0x6C, 0x07, 0x57, 0x8B, 0xC9, 0xCB, 0xAF, 0x2A, 0xB4, 0xE3, 0x82, 0x72, 0x7A, 0xD4, 0x16, 0x86, 0xA9, 0x6B, 0x25, 0x48, 0x82, 0x0B, 0xB0, 0x3B, 0x32, 0xF1, 0x1B, 0x28, 0x11, 0xAD, 0x62, 0xF4, 0x89, 0xE9, 0x51, 0x63, 0x2A, 0xBA, 0x0D, 0x1D, 0xF8, 0x96, 0x80, 0xCC, 0x8A, 0x8B, 0x53, 0xB4, 0x81, 0xD9, 0x2A, 0x68, 0xD7, 0x0B, 0x4E, 0xA1, 0xC3, 0xA6, 0xA5, 0x61, 0xC0, 0x69, 0x28, 0x82, 0xB5, 0xCA, 0x8C, 0xC9, 0x42, 0xA8, 0xD4, 0x95, 0xAF, 0xCB, 0x06, 0xDE, 0x89, 0x49, 0x8F, 0xB9, 0x35, 0xB7, 0x75, 0x90, 0x8F, 0xE7, 0xA0, 0x3E, 0x32, 0x4D, 0x54, 0xCC, 0x19, 0xD4, 0xE1, 0xAA, 0xBD, 0x35, 0x93, 0xB3, 0x8B, 0x19, 0xEE, 0x13, 0x88, 0xFE, 0x49, 0x2B, 0x43, 0x12, 0x7E, 0x5A, 0x50, 0x42, 0x53, 0x78, 0x6A, 0x0D, 0x69, 0xAD, 0x32, 0x60, 0x1C, 0x28, 0xE2, 0xC8, 0x85, 0x04, 0xA5, 0xBA, 0x59, 0x97, 0x06, 0x02, 0x3A, 0x61, 0x36, 0x3E, 0x17, 0xC6, 0xB9, 0xBB, 0x59, 0xBD, 0xC6, 0x97, 0x45, 0x2C, 0xD0, 0x59, 0x45, 0x19, 0x83, 0xD7, 0x38, 0xCA, 0x3F, 0xD0, 0x34, 0xE3, 0xF5, 0x98, 0x88, 0x54, 0xCA, 0x05, 0x03, 0x1D, 0xB0, 0x96, 0x11, 0x49, 0x89, 0x88, 0x19, 0x7C, 0x6B, 0x30, 0xD2, 0x58, 0xDF, 0xE2, 0x62, 0x65, 0x54, 0x1C, 0x89, 0xA4, 0xB3, 0x1D, 0x68, 0x64, 0xE9, 0x38, 0x9B, 0x03, 0xCB, 0x74, 0xF7, 0xEC, 0x43, 0x23, 0xFB, 0x94, 0x21, 0xA4, 0xB9, 0x79, 0x0A, 0x26, 0xD1, 0x7B, 0x03, 0x98, 0xA2, 0x67, 0x67, 0x35, 0x09, 0x09, 0xF8, 0x4D, 0x57, 0xB6, 0x69, 0x4D, 0xF8, 0x30, 0x66, 0x4C, 0xA8, 0xB3, 0xC3, 0xC0, 0x3E, 0xD2, 0xAE, 0x67, 0xB8, 0x90, 0x06, 0x86, 0x8A, 0x68, 0x52, 0x7C, 0xCD, 0x66, 0x64, 0x59, 0xAB, 0x7F, 0x05, 0x66, 0x71, 0x00, 0x0C, 0x61, 0x64, 0xD3, 0xA7, 0xF2, 0x66, 0xA1, 0x4D, 0x97, 0xCB, 0xD7, 0x00, 0x4D, 0x6C, 0x92, 0xCA, 0xCA, 0x77, 0x0B, 0x84, 0x4A, 0x4F, 0xA9, 0xB1, 0x82, 0xE7, 0xB1, 0x8C, 0xA8, 0x85, 0x08, 0x2A, 0xC5, 0x64, 0x6F, 0xCB, 0x4A, 0x14, 0xE1, 0x68, 0x5F, 0xEB, 0x0C, 0x9C, 0xE3, 0x37, 0x2A, 0xB9, 0x53, 0x65, 0xC0, 0x4F, 0xD8, 0x30, 0x84, 0xF8, 0x0A, 0x23, 0xFF, 0x10, 0xA0, 0x5B, 0xF1, 0x5F, 0x7F, 0xA5, 0xAC, 0xC6, 0xC0, 0xCB, 0x46, 0x2C, 0x33, 0xCA, 0x52, 0x4F, 0xA6, 0xB8, 0xBB, 0x35, 0x90, 0x43, 0xBA, 0x68, 0x60, 0x9E, 0xAA, 0x25, 0x36, 0xE8, 0x1D, 0x08, 0x46, 0x3B, 0x19, 0x65, 0x3B, 0x54, 0x35, 0xBA, 0x94, 0x6C, 0x9A, 0xDD, 0xEB, 0x20, 0x2B, 0x04, 0xB0, 0x31, 0xCC, 0x96, 0x0D, 0xCC, 0x12, 0xE4, 0x51, 0x8D, 0x42, 0x8B, 0x32, 0xB2, 0x57, 0xA4, 0xFC, 0x73, 0x13, 0xD3, 0xA7, 0x98, 0x0D, 0x80, 0x08, 0x2E, 0x93, 0x4F, 0x9D, 0x95, 0xC3, 0x2B, 0x0A, 0x01, 0x91, 0xA2, 0x36, 0x04, 0x38, 0x4D, 0xD9, 0xE0, 0x79, 0xBB, 0xBA, 0xA2, 0x66, 0xD1, 0x4C, 0x3F, 0x75, 0x6B, 0x9F, 0x21, 0x33, 0x10, 0x74, 0x33, 0xA4, 0xE8, 0x3F, 0xA7, 0x18, 0x72, 0x82, 0xA8, 0x09, 0x20, 0x3A, 0x4F, 0xAF, 0x84, 0x18, 0x51, 0x83, 0x3D, 0x12, 0x1A, 0xC3, 0x83, 0x84, 0x3A, 0x5E, 0x55, 0xBC, 0x23, 0x81, 0x42, 0x5E, 0x16, 0xC7, 0xDB, 0x4C, 0xC9, 0xAB, 0x5C, 0x1B, 0x0D, 0x91, 0xA4, 0x7E, 0x2B, 0x8D, 0xE0, 0xE5, 0x82, 0xC8, 0x6B, 0x6B, 0x0D, 0x90, 0x7B, 0xB3, 0x60, 0xB9, 0x7F, 0x40, 0xAB, 0x5D, 0x03, 0x8F, 0x6B, 0x75, 0xC8, 0x14, 0xB2, 0x7D, 0x9B, 0x96, 0x8D, 0x41, 0x98, 0x32, 0xBC, 0x8C, 0x2B, 0xEE, 0x60, 0x5E, 0xF6, 0xE5, 0x05, 0x9D, 0x33, 0x10, 0x0D, 0x90, 0x48, 0x5D, 0x37, 0x84, 0x50, 0x01, 0x42, 0x21, 0x73, 0x6C, 0x07, 0x40, 0x7C, 0xAC, 0x26, 0x04, 0x08, 0xAA, 0x64, 0x92, 0x66, 0x19, 0x78, 0x8B, 0x86, 0x01, 0xC2, 0xA7, 0x52, 0xD1, 0xA6, 0xCB, 0xF8, 0x20, 0xD7, 0xC7, 0xA0, 0x47, 0x16, 0x20, 0x32, 0x25, 0xB3, 0x89, 0x5B, 0x93, 0x42, 0xD1, 0x47, 0xA8, 0x18, 0x5C, 0xFC, 0x1B, 0xB6, 0x5B, 0xA0, 0x6B, 0x41, 0x42, 0x33, 0x99, 0x03, 0xC0, 0xAC, 0x46, 0x51, 0x38, 0x5B, 0x45, 0xD9, 0x8A, 0x8B, 0x19, 0xD2, 0x8C, 0xD6, 0xBA, 0xB0, 0x88, 0x78, 0x7F, 0x7E, 0xE1, 0xB1, 0x24, 0x61, 0x76, 0x6B, 0x43, 0xCB, 0xCC, 0xB9, 0x64, 0x34, 0x42, 0x7D, 0x93, 0xC0, 0x65, 0x55, 0x06, 0x88, 0xF6, 0x94, 0x8E, 0xD1, 0xB5, 0x47, 0x5A, 0x42, 0x5F, 0x1B, 0x85, 0x20, 0x9D, 0x06, 0x1C, 0x08, 0xB5, 0x6C, 0x1C, 0xC0, 0x69, 0xF6, 0xC0, 0xA7, 0xC6, 0xF2, 0x93, 0x58, 0xCA, 0xB9, 0x11, 0x08, 0x77, 0x32, 0xA6, 0x49, 0xD2, 0x7C, 0x9B, 0x98, 0xF9, 0xA4, 0x88, 0x79, 0x38, 0x7D, 0x9B, 0x00, 0xC2, 0x59, 0x59, 0xA7, 0x16, 0x54, 0xD6, 0xF6, 0xA9, 0x46, 0x16, 0x45, 0x13, 0xE4, 0x7A, 0x75, 0xD0, 0x05, 0x98, 0x6C, 0x23, 0x63, 0xC0, 0x9F, 0x6B, 0x53, 0x7E, 0xCA, 0x78, 0xB9, 0x30, 0x3A, 0x5F, 0xA4, 0x57, 0x60, 0x8A, 0x58, 0x6A, 0x65, 0x3A, 0x34, 0x7D, 0xB0, 0x4D, 0xFC, 0xC1, 0x91, 0x75, 0xB3, 0xA3, 0x01, 0x17, 0x25, 0x36, 0x06, 0x2A, 0x65, 0x8A, 0x95, 0x27, 0x75, 0x70, 0xC8, 0x85, 0x2C, 0xA8, 0x97, 0x3F, 0x4A, 0xE1, 0x23, 0xA3, 0x34, 0x04, 0x7D, 0xD7, 0x11, 0xC8, 0x92, 0x7A, 0x63, 0x4A, 0x03, 0x38, 0x8A, 0x52, 0x7B, 0x03, 0x4B, 0xF7, 0xA8, 0x17, 0x0F, 0xA7, 0x02, 0xC1, 0xF7, 0xC2, 0x3E, 0xC3, 0x2D, 0x18, 0xA2, 0x37, 0x48, 0x90, 0xBE, 0x9C, 0x78, 0x7A, 0x94, 0x09, 0xC8, 0x2D, 0x19, 0x2C, 0x4B, 0xB7, 0x05, 0xA2, 0xF9, 0x96, 0xCE, 0x40, 0x5D, 0x85, 0xA4, 0xC1, 0xA1, 0xAB, 0x9B, 0x6A, 0xEB, 0x49, 0xCC, 0xE1, 0xC2, 0xF8, 0xA9, 0x7C, 0x35, 0x16, 0xC7, 0x2A, 0x00, 0xA4, 0x62, 0x63, 0xBA, 0xA6, 0x96, 0xBF, 0x25, 0x72, 0x77, 0x19, 0xC3, 0x21, 0x64, 0x23, 0x61, 0x8F, 0xF3, 0x33, 0x80, 0x93, 0x4A, 0x6C, 0x10, 0x54, 0x5C, 0x4C, 0x5C, 0x51, 0x55, 0xB1, 0x24, 0x86, 0x18, 0x1F, 0xC7, 0xA2, 0x31, 0x98, 0x73, 0x97, 0x8B, 0x6A, 0x2A, 0x67, 0x49, 0x0F, 0x82, 0x56, 0xBD, 0x21, 0x96, 0xFE, 0x17, 0x92, 0xA4, 0xC0, 0x00, 0x77, 0xB8, 0x12, 0xEA, 0xE8, 0xBE, 0xD3, 0x57, 0x24, 0x99, 0x68, 0x4A, 0xB3, 0x37, 0x18, 0x76, 0x76, 0x1E, 0x45, 0x0C, 0x9F, 0x9D, 0x27, 0x68, 0xA3, 0x68, 0x06, 0xD7, 0xAB, 0x20, 0x46, 0xC9, 0x1F, 0x17, 0x59, 0x9E, 0x9A, 0xC5, 0x92, 0x99, 0x08, 0x08, 0xDC, 0xD7, 0xB4, 0xD0, 0x91, 0x90, 0x72, 0xF1, 0x4E, 0xC3, 0x61, 0x77, 0x3B, 0x72, 0x52, 0x44, 0x4C, 0x32, 0x3C, 0x30, 0x83, 0x26, 0xF4, 0xA3, 0x0F, 0x86, 0x80, 0xD2, 0xF7, 0x48, 0xF5, 0x6A, 0x13, 0x2B, 0x82, 0x67, 0x4E, 0xD0, 0x18, 0x46, 0x20, 0xB8, 0x2A, 0xD2, 0xCB, 0x18, 0x2C, 0x97, 0xB4, 0x81, 0x62, 0x66, 0x47, 0x49, 0x12, 0x90, 0xA0, 0x11, 0xCC, 0x73, 0x82, 0x86, 0x85, 0xA8, 0xC3, 0x67, 0xA5, 0xB9, 0xCF, 0x8D, 0x62, 0x1B, 0x0D, 0x5C, 0x1E, 0xFF, 0x03, 0x17, 0x27, 0x58, 0xBD, 0x00, 0x49, 0x78, 0xC2, 0x51, 0xCD, 0x51, 0x34, 0x22, 0x28, 0x98, 0x9C, 0xAE, 0x63, 0x32, 0xAC, 0x48, 0x64, 0x37, 0xCB, 0x5C, 0x57, 0xD4, 0x30, 0x74, 0x62, 0x86, 0x52, 0x53, 0xBE, 0x21, 0x7B, 0x35, 0x15, 0xC7, 0x3D, 0xF4, 0x05, 0xB7, 0xF2, 0x82, 0x17, 0xAD, 0x0B, 0x8C, 0xF6, 0x0C, 0x2F, 0xFF, 0xAA, 0x0A, 0x00, 0x48, 0xB1, 0xFB, 0x4A, 0xCD, 0xCD, 0xC3, 0x8B, 0x52, 0x50, 0xCF, 0xEC, 0x35, 0x6A, 0x6D, 0xE2, 0x6C, 0xFA, 0x7A, 0x58, 0x8F, 0xDC, 0x86, 0xF9, 0x8C, 0x85, 0x4A, 0xC6, 0x4C, 0x7B, 0xFA, 0xA9, 0x6F, 0x5A, 0x32, 0xCC, 0x06, 0x10, 0x93, 0x4B, 0xAA, 0x6A, 0x58, 0x6B, 0x9A, 0x20, 0x54, 0xF1, 0x3B, 0xA2, 0x74, 0x17, 0x4A, 0xA0, 0xD2, 0xB3, 0xA8, 0x1B, 0x96, 0xA9, 0x40, 0x66, 0x6F, 0x78, 0x9B, 0x5A, 0x6B, 0xCD, 0xC0, 0xA6, 0xA0, 0x17, 0x8A, 0x0C, 0x9A, 0x02, 0x57, 0x8A, 0x49, 0x3F, 0x6E, 0xEA, 0x0D, 0x2E, 0x6C, 0x13, 0x95, 0x1C, 0x9F, 0x24, 0x9A, 0x5E, 0x8D, 0xD7, 0x1D, 0xD4, 0x9A, 0x74, 0x2D, 0x45, 0x1F, 0x1A, 0xBB, 0xA1, 0x9A, 0xF8, 0xC5, 0x47, 0x85, 0x5E, 0x0A, 0xFC, 0x72, 0x8E, 0x90, 0xAB, 0xB4, 0x99, 0xC9, 0xBE, 0xEB, 0x76, 0x6F, 0x47, 0x29, 0xCD, 0xA2, 0x22, 0x63, 0xE3, 0x24, 0xDA, 0x18, 0x71, 0x2D, 0x31, 0x6E, 0x98, 0xDC, 0x7A, 0xC8, 0xC3, 0xCA, 0x47, 0x37, 0x0E, 0xBD, 0x77, 0x0C, 0xE3, 0x2B, 0x3B, 0xD4, 0xB1, 0xA0, 0xC9, 0x52, 0x9A, 0xC6, 0xEC, 0x8E, 0xE0, 0x28, 0xB1, 0xCD, 0xB2, 0x65, 0x1C, 0xB5, 0xA6, 0xBB, 0x3C, 0x0C, 0x6D, 0xF1, 0x24, 0x0A, 0x3B, 0x91, 0x4B, 0x56, 0x56, 0xC0, 0xDC, 0x51, 0xC2, 0xB9, 0x1B, 0xFC, 0xBC, 0x37, 0xA4, 0x66, 0x02, 0x87, 0xD4, 0x4F, 0x81, 0xF8, 0x53, 0xC7, 0xF4, 0x9A, 0x6D, 0x06, 0x03, 0xD6, 0xD7, 0x23, 0xCB, 0xEC, 0x01, 0x5F, 0xBC, 0x43, 0x4A, 0x38, 0x24, 0x1C, 0x10, 0x9C, 0x7E, 0xD5, 0xB1, 0xCC, 0x46, 0x1A, 0x2C, 0xCB, 0x9A, 0xB7, 0x14, 0x0F, 0x19, 0xF3, 0x7A, 0x13, 0xBB, 0x70, 0x1E, 0x14, 0x2B, 0xD5, 0x4B, 0x64, 0xEC, 0x6B, 0x76, 0xFE, 0xC3, 0x3B, 0x69, 0xC2, 0x91, 0x8C, 0xB0, 0x17, 0xC4, 0x14, 0x34, 0x23, 0x00, 0x9A, 0x3C, 0x07, 0xB5, 0xC1, 0x81, 0xB0, 0xC1, 0xEB, 0x49, 0x4A, 0x62, 0xAB, 0xC8, 0x39, 0x13, 0x97, 0x08, 0x9E, 0xA6, 0x64, 0x09, 0x67, 0xC1, 0x20, 0x49, 0x84, 0xCD, 0x48, 0x4C, 0xCC, 0xB0, 0x0A, 0x9A, 0x17, 0xD0, 0x87, 0x21, 0x84, 0x28, 0xEF, 0x3B, 0xB7, 0x08, 0x78, 0x3E, 0x12, 0x82, 0x71, 0x04, 0x41, 0x73, 0x75, 0xB6, 0x95, 0x6F, 0xB5, 0x00, 0x53, 0xD0, 0x48, 0xA4, 0x79, 0x14, 0x95, 0x82, 0x4A, 0x34, 0x80, 0xA5, 0xB7, 0x83, 0x02, 0x56, 0x09, 0x6F, 0xDD, 0x72, 0x5C, 0x30, 0x8B, 0x3B, 0xE8, 0x4A, 0x07, 0xF3, 0x63, 0x2E, 0x24, 0x95, 0xC6, 0x2E, 0x96, 0x39, 0x9D, 0x80, 0xBF, 0xA7, 0x45, 0xB9, 0x84, 0x1A, 0x18, 0x33, 0xBC, 0x1D, 0x27, 0xBA, 0x45, 0xA5, 0x21, 0x68, 0xEE, 0x59, 0x00, 0x6C, 0x3A, 0x3A, 0x8C, 0x4A, 0x5A, 0x4F, 0x50, 0x88, 0xFC, 0x73, 0x71, 0x81, 0xAB, 0x51, 0x96, 0xF7, 0xB1, 0xB4, 0x9A, 0x2E, 0xD8, 0x13, 0x13, 0x4E, 0x11, 0x2F, 0x73, 0x0B, 0x99, 0x1C, 0x54, 0xA7, 0x19, 0x6B, 0xCF, 0x5F, 0xC7, 0x6E, 0x13, 0x4C, 0x58, 0x43, 0xE1, 0x69, 0x88, 0x51, 0xB2, 0xF8, 0x69, 0xAF, 0xAF, 0xB0, 0x27, 0x87, 0xD9, 0xC2, 0xF1, 0x36, 0x90, 0x2D, 0xC7, 0xA7, 0xF3, 0xD6, 0x21, 0x56, 0xD1, 0x5E, 0xC3, 0x09, 0x56, 0x40, 0x92, 0xC6, 0x1D, 0x83, 0xB0, 0x98, 0x6C, 0x48, 0x40, 0x99, 0x81, 0xF3, 0xC1, 0x86, 0x88, 0x0A, 0x2F, 0x63, 0xD5, 0x86, 0x0A, 0xB6, 0x01, 0xDE, 0xAC, 0x2B, 0x6B, 0xA1, 0xB4, 0x28, 0x17, 0x9D, 0x73, 0x53, 0x3E, 0xB7, 0xA3, 0xA5, 0x11, 0x3B, 0x85, 0x61, 0xF1, 0x0B, 0x45, 0xC3, 0xCD, 0xE2, 0x82, 0xB6, 0xEA, 0xD6, 0xAB, 0x6C, 0x60, 0x4F, 0x09, 0xC1, 0x7B, 0xFD, 0xA0, 0x83, 0x13, 0xA3, 0x26, 0x07, 0x67, 0x5A, 0xDF, 0x64, 0x31, 0xCA, 0x87, 0x18, 0xE9, 0xC4, 0x3A, 0x73, 0x73, 0x32, 0x27, 0xE7, 0x3B, 0xC6, 0x1A, 0xC8, 0x45, 0xBA, 0x90, 0x77, 0x55, 0xCE, 0xC6, 0x89, 0x25, 0xE5, 0xE2, 0xBF, 0xE9, 0x12, 0x95, 0x9D, 0xB8, 0x6F, 0xBF, 0xE2, 0x15, 0x6F, 0xD5, 0xBB, 0xDB, 0xF0, 0xC9, 0xDF, 0x8B, 0x53, 0x02, 0xAA, 0x8D, 0x90, 0xA2, 0x2D, 0x12, 0x27, 0x0E, 0x00, 0x65, 0x51, 0xE4, 0x76, 0x7E, 0x45, 0x26, 0x8E, 0xD9, 0x69, 0x26, 0x54, 0x44, 0x78, 0x11, 0xEA, 0xB8, 0x4F, 0x04, 0x99, 0xA8, 0xA5, 0x8C, 0xF7, 0xC0, 0x4A, 0x59, 0x56, 0x98, 0x52, 0x80, 0x45, 0xF2, 0x98, 0x97, 0xC8, 0xFA, 0x96, 0xD0, 0x6C, 0xCE, 0x51, 0xE6, 0xAF, 0xEA, 0xC4, 0x33, 0x95, 0x89, 0xC9, 0x41, 0xC8, 0x55, 0x63, 0xD7, 0x0F, 0xAC, 0xE1, 0x92, 0x88, 0x94, 0xBA, 0xC0, 0x36, 0x19, 0xDF, 0xF4, 0xBE, 0x3F, 0x43, 0x14, 0xA3, 0xF7, 0x35, 0x1A, 0x09, 0xA4, 0x86, 0xB5, 0x04, 0x1E, 0x7C, 0xB2, 0xDA, 0x8B, 0x96, 0xBC, 0x66, 0x26, 0xA4, 0x93, 0x17, 0x35, 0x7C, 0x41, 0x52, 0xA5, 0x1B, 0xA3, 0xC2, 0x8C, 0x7E, 0x0C, 0x9D, 0xB4, 0x1A, 0x06, 0xA2, 0x82, 0x90, 0xF2, 0x18, 0x73, 0x11, 0x07, 0xC9, 0x54, 0xD8, 0xA6, 0x6F, 0x80, 0x1D, 0x7D, 0xE1, 0x2A, 0x03, 0x71, 0x16, 0x99, 0x0B, 0x6C, 0x53, 0xC1, 0x29, 0xF1, 0x85, 0xC3, 0x45, 0xF2, 0x7E, 0x51, 0x8B, 0x2D, 0x5A, 0x91, 0x25, 0xA0, 0x70, 0x76, 0xD9, 0x91, 0xB7, 0xDA, 0xC7, 0xCC, 0x65, 0xA8, 0x56, 0x2E, 0xFB, 0xCC, 0x32, 0xA9, 0xCA, 0x4A, 0xD9, 0x02, 0x63, 0xB0, 0x4A, 0x4F, 0x90, 0x36, 0x11, 0x6C, 0x7B, 0x97, 0x48, 0x04, 0x96, 0x31, 0x75, 0x75, 0x65, 0x0D, 0xCC, 0x21, 0x52, 0xB5, 0xBC, 0x0E, 0x74, 0x40, 0x7E, 0x12, 0xFA, 0x8E, 0x4F, 0xFC, 0xCC, 0xFF, 0x76, 0xC0, 0x1A, 0x97, 0x4B, 0xD6, 0x11, 0x02, 0xE1, 0xF5, 0x29, 0x64, 0x96, 0xC7, 0x1D, 0x07, 0x64, 0xE1, 0x32, 0x29, 0xFF, 0xE7, 0x84, 0x6F, 0x33, 0x6E, 0x34, 0xCA, 0xC9, 0x04, 0xCA, 0x56, 0x70, 0xF8, 0xCD, 0x50, 0x52, 0x42, 0x7A, 0x79, 0xC0, 0x91, 0xA9, 0x71, 0x21, 0x0C, 0x5C, 0xFF, 0x66, 0x7A, 0xAC, 0x24, 0x93, 0x66, 0xE1, 0x0D, 0x2B, 0x11, 0x37, 0x6C, 0xA3, 0x9D, 0x93, 0x52, 0x04, 0xB1, 0x2C, 0xC5, 0x85, 0xE9, 0x40, 0x54, 0x03, 0x62, 0x5F, 0xB3, 0x2C, 0xB5, 0xE5, 0xC3, 0x1B, 0x62, 0x34, 0x81, 0x60, 0x51, 0x5C, 0xCC, 0x4F, 0xDA, 0xF5, 0x70, 0x2D, 0x6B, 0xAB, 0x5C, 0x37, 0x3D, 0xB6, 0xF3, 0x50, 0xD3, 0xE6, 0x3A, 0x5C, 0xE3, 0xCA, 0x54, 0x74, 0xA0, 0xCF, 0x15, 0x67, 0x04, 0x2C, 0xA3, 0x25, 0x89, 0x86, 0xFF, 0x75, 0xBD, 0xFC, 0xD9, 0x29, 0xE6, 0x46, 0x2F, 0x36, 0xBC, 0xCC, 0x3F, 0x5A, 0x93, 0x35, 0x2A, 0x2B, 0x36, 0xCB, 0x16, 0x2E, 0x18, 0x74, 0xC7, 0x42, 0x87, 0x0A, 0x97, 0xB1, 0x67, 0xA0, 0x50, 0x37, 0x36, 0x24, 0xEA, 0xEB, 0x7E, 0x50, 0x73, 0x25, 0x6B, 0x72, 0x11, 0xB2, 0xD9, 0x4B, 0x84, 0x06, 0xCD, 0x6C, 0x95, 0x33, 0xB1, 0x53, 0x64, 0x08, 0xAB, 0x0A, 0x29, 0xE5, 0xB2, 0xF0, 0xC9, 0x54, 0xEC, 0xE0, 0x0F, 0xBB, 0xEB, 0x17, 0x6D, 0x72, 0x4D, 0x4C, 0xF4, 0x43, 0xCF, 0x70, 0x20, 0xD5, 0xFA, 0x70, 0x94, 0xCC, 0x1B, 0x1B, 0xE6, 0x97, 0xBA, 0xD3, 0x36, 0x74, 0xE4, 0x09, 0x9E, 0xC7, 0xBB, 0x18, 0xF4, 0x57, 0x71, 0x28, 0xCD, 0xD9, 0x7C, 0xCD, 0x6D, 0x44, 0x62, 0xE5, 0x60, 0x7C, 0x51, 0x2A, 0x3E, 0x36, 0x24, 0x8E, 0x3D, 0xDA, 0xA2, 0xEC, 0x08, 0x9A, 0xEF, 0xC4, 0xCE, 0x48, 0x5C, 0x49, 0xD7, 0xB0, 0x09, 0xC8, 0xD6, 0x31, 0x15, 0xFC, 0x81, 0xFF, 0x3A, 0x62, 0xD1, 0x5A, 0x88, 0x44, 0x1C, 0x03, 0xEA, 0x1C, 0x2E, 0x72, 0xC4, 0x88, 0x39, 0xFC, 0x6A, 0xD7, 0x3A, 0x30, 0x74, 0x4A, 0x62, 0xB7, 0xB2, 0x16, 0x45, 0xA6, 0xAF, 0x7D, 0x61, 0xB6, 0x38, 0x3B, 0x22, 0x1E, 0x21, 0x90, 0x55, 0x57, 0xCD, 0x29, 0xD9, 0x24, 0xA6, 0x09, 0x86, 0xC5, 0x11, 0xC1, 0xEB, 0xBC, 0x31, 0x6D, 0x56, 0x30, 0xA2, 0x41, 0x43, 0x23, 0xF5, 0x3A, 0xD5, 0x59, 0x94, 0xF6, 0xB3, 0x65, 0x39, 0xF9, 0xC4, 0x40, 0x75, 0xA5, 0x33, 0xE4, 0x81, 0xC0, 0x84, 0x45, 0xD9, 0xCA, 0x9E, 0x9D, 0x38, 0x21, 0x19, 0x38, 0x8B, 0xD1, 0xD7, 0x50, 0x52, 0x21, 0x7A, 0x94, 0x4C, 0xCC, 0x7B, 0xE9, 0x09, 0xE2, 0x19, 0x71, 0x1F, 0xCC, 0x79, 0x24, 0x76, 0x92, 0x13, 0xA1, 0x92, 0x53, 0x4A, 0x55, 0x80, 0x08, 0x15, 0x7A, 0x39, 0x6E, 0xDF, 0xF4, 0x80, 0xCC, 0x3B, 0x52, 0x0F, 0xF8, 0x18, 0xB3, 0x8B, 0x13, 0x5C, 0x18, 0xA8, 0x0D, 0x51, 0x05, 0xE6, 0x78, 0x83, 0x6C, 0x39, 0x5C, 0x28, 0xE9, 0x2F, 0x7A, 0x3C, 0x4E, 0x93, 0xC0, 0x10, 0x35, 0xF3, 0x41, 0x11, 0xCC, 0x49, 0x02, 0xD0, 0xC0, 0x33, 0xA6, 0x3F, 0x23, 0x6A, 0x71, 0xDA, 0x97, 0x4A, 0x6F, 0x40, 0x4F, 0x7A, 0xA7, 0xB5, 0xE5, 0x82, 0xC7, 0x58, 0x14, 0x2F, 0xC1, 0x82, 0x6B, 0xBA, 0x98, 0xB2, 0x7D, 0x57, 0xC2, 0xE2, 0x10, 0x3E, 0x10, 0xE3, 0x0D, 0x32, 0x79, 0x7B, 0x96, 0x77, 0x14, 0xD1, 0x56, 0x61, 0x11, 0x13, 0x71, 0xA2, 0xD9, 0xC5, 0x39, 0x98, 0x12, 0x46, 0x46, 0x22, 0x63, 0x5B, 0x44, 0x21, 0x26, 0xB0, 0x98, 0x36, 0xB0, 0x81, 0x82, 0x72, 0x47, 0xD0, 0x54, 0x22, 0x97, 0x2B, 0xD0, 0x32, 0x0D, 0x8F, 0x42, 0xBF, 0x57, 0xE3, 0x49, 0x46, 0x12, 0x34, 0xE4, 0xD9, 0x4F, 0x01, 0x18, 0x50, 0xBA, 0xB5, 0xC0, 0x49, 0xB6, 0x2A, 0x59, 0x43, 0x38, 0x66, 0xFC, 0xCE, 0x69, 0x66, 0x49, 0x5C, 0x26, 0x5C, 0x47, 0x65, 0xA5, 0x6C, 0x06, 0xB9, 0xFC, 0x42, 0x76, 0x54, 0x87, 0x85, 0xF4, 0x68, 0x28, 0xCA, 0x60, 0x2D, 0xC6, 0xD0, 0x54, 0x1F, 0x25, 0x07, 0x89, 0xC4, 0x9E, 0x8B, 0x06, 0x55, 0x9C, 0x43, 0x44, 0x60, 0xA8, 0x43, 0x80, 0x98, 0x54, 0xE5, 0xB4, 0x6E, 0x89, 0x38, 0x9F, 0x10, 0xF4, 0x89, 0x66, 0x74, 0x91, 0xC1, 0x93, 0x5E, 0x8A, 0xFB, 0x9E, 0xB4, 0x71, 0x8F, 0x86, 0xAC, 0x45, 0x89, 0x32, 0xBC, 0xF3, 0x3C, 0x9A, 0xBE, 0xCB, 0x2D, 0xC0, 0xC0, 0x93, 0xA7, 0xE8, 0x1D, 0xA0, 0x32, 0x7B, 0xB6, 0x37, 0x52, 0x81, 0x05, 0xC3, 0x58, 0xEB, 0x76, 0x8D, 0x32, 0x3A, 0x37, 0xD4, 0x0A, 0x8C, 0x19, 0x9B, 0x7C, 0x4B, 0xB1, 0xD7, 0x2B, 0x72, 0xB6, 0x90, 0xB3, 0x6D, 0xD2, 0x7A, 0x93, 0x55, 0x19, 0x1B, 0x3C, 0x3A, 0xA6, 0x75, 0xA7, 0xE6, 0xF8, 0x55, 0xEB, 0x50, 0x5F, 0x57, 0x98, 0x65, 0xDB, 0xD8, 0x91, 0x05, 0x65, 0x50, 0x5E, 0x7C, 0x0F, 0xDD, 0x54, 0x5C, 0xBB, 0xB8, 0x71, 0xB0, 0xB2, 0xCC, 0x01, 0x25, 0xB7, 0x4F, 0x6B, 0x0C, 0x9B, 0x79, 0x67, 0x0A, 0x62, 0x02, 0xD1, 0xB9, 0x15, 0x4A, 0xC7, 0x76, 0x6B, 0x19, 0x19, 0xC4, 0x89, 0x58, 0x90, 0x86, 0xAD, 0x8B, 0x45, 0xBE, 0x0D, 0x79, 0xC9, 0x76, 0xC3, 0xC3, 0x9D, 0x6B, 0x25, 0x21, 0x3B, 0xB0, 0xB7, 0x8A, 0x57, 0x50, 0xE6, 0xA8, 0xEB, 0x34, 0x33, 0x0B, 0xB3, 0xCF, 0xF2, 0xB1, 0xC0, 0x72, 0x2A, 0xC8, 0x83, 0xB0, 0x48, 0xF4, 0xB8, 0xCD, 0x06, 0x19, 0x6D, 0xA8, 0xAA, 0x8B, 0x05, 0xDA, 0x42, 0x67, 0x55, 0x2B, 0xF8, 0x7A, 0xBC, 0xA5, 0x12, 0x4D, 0xC3, 0x58, 0xA8, 0x38, 0x10, 0x40, 0xE9, 0xB8, 0x1F, 0xB0, 0x84, 0x43, 0x15, 0x02, 0x15, 0xD6, 0x92, 0x23, 0x28, 0x00, 0x0A, 0xC0, 0xB7, 0x88, 0xB1, 0x21, 0x93, 0x1A, 0x26, 0x7D, 0x80, 0x61, 0x9C, 0xE7, 0xD2, 0x9C, 0xD7, 0x6B, 0x60, 0xCF, 0x65, 0x83, 0xDC, 0xE8, 0xCE, 0xBC, 0x49, 0x01, 0x85, 0x73, 0x6C, 0x81, 0x8B, 0x25, 0xAD, 0x26, 0x0B, 0x66, 0x7B, 0x1F, 0xFD, 0x46, 0x20, 0x6D, 0x01, 0x04, 0x55, 0x3A, 0xA9, 0xFB, 0x30, 0x45, 0x54, 0xA2, 0x1C, 0x32, 0x72, 0x44, 0xCE, 0x78, 0xAF, 0xDB, 0xD3, 0xB4, 0x62, 0x36, 0x1B, 0xB0, 0x68, 0xA1, 0x55, 0x63, 0x64, 0x09, 0xF5, 0x74, 0xC5, 0x71, 0x65, 0x72, 0xE2, 0xA5, 0xF2, 0xA4, 0xB0, 0x4F, 0xB8, 0xAA, 0xD1, 0x23, 0x66, 0x84, 0x84, 0x17, 0x87, 0x56, 0x2A, 0xAF, 0x46, 0xC2, 0xC0, 0xDA, 0x46, 0x65, 0xEA, 0xFD, 0x46, 0x5F, 0xC6, 0x4A, 0x0C, 0x5F, 0x8F, 0x3F, 0x90, 0x03, 0x48, 0x94, 0x15, 0x89, 0x9D, 0x59, 0xA5, 0x43, 0xD8, 0x20, 0x8C, 0x54, 0xA3, 0x16, 0x65, 0x29, 0xB5, 0x39, 0x22, 0xA5, 0x89, 0x9A, 0x0B, 0xC4, 0x65, 0xEE, 0x5F, 0xC2, 0xC0, 0x41, 0x55, 0x58, 0x2A, 0x40, 0xAC, 0x70, 0x97, 0x61, 0xD2, 0xBE, 0x61, 0xFD, 0xC7, 0x6C, 0x59, 0x30, 0x44, 0xCE, 0xBC, 0xC7, 0xF2, 0x86, 0x26, 0xED, 0x79, 0xD4, 0x51, 0x14, 0x08, 0x00, 0xE0, 0x3B, 0x59, 0xB9, 0x56, 0xF8, 0x21, 0x0E, 0x55, 0x60, 0x67, 0x40, 0x7D, 0x13, 0xDC, 0x90, 0xFA, 0x9E, 0x8B, 0x87, 0x2B, 0xFB, 0x8F, }, .pk_len = 1568, .pk = { 0xDA, 0x18, 0x71, 0x2D, 0x31, 0x6E, 0x98, 0xDC, 0x7A, 0xC8, 0xC3, 0xCA, 0x47, 0x37, 0x0E, 0xBD, 0x77, 0x0C, 0xE3, 0x2B, 0x3B, 0xD4, 0xB1, 0xA0, 0xC9, 0x52, 0x9A, 0xC6, 0xEC, 0x8E, 0xE0, 0x28, 0xB1, 0xCD, 0xB2, 0x65, 0x1C, 0xB5, 0xA6, 0xBB, 0x3C, 0x0C, 0x6D, 0xF1, 0x24, 0x0A, 0x3B, 0x91, 0x4B, 0x56, 0x56, 0xC0, 0xDC, 0x51, 0xC2, 0xB9, 0x1B, 0xFC, 0xBC, 0x37, 0xA4, 0x66, 0x02, 0x87, 0xD4, 0x4F, 0x81, 0xF8, 0x53, 0xC7, 0xF4, 0x9A, 0x6D, 0x06, 0x03, 0xD6, 0xD7, 0x23, 0xCB, 0xEC, 0x01, 0x5F, 0xBC, 0x43, 0x4A, 0x38, 0x24, 0x1C, 0x10, 0x9C, 0x7E, 0xD5, 0xB1, 0xCC, 0x46, 0x1A, 0x2C, 0xCB, 0x9A, 0xB7, 0x14, 0x0F, 0x19, 0xF3, 0x7A, 0x13, 0xBB, 0x70, 0x1E, 0x14, 0x2B, 0xD5, 0x4B, 0x64, 0xEC, 0x6B, 0x76, 0xFE, 0xC3, 0x3B, 0x69, 0xC2, 0x91, 0x8C, 0xB0, 0x17, 0xC4, 0x14, 0x34, 0x23, 0x00, 0x9A, 0x3C, 0x07, 0xB5, 0xC1, 0x81, 0xB0, 0xC1, 0xEB, 0x49, 0x4A, 0x62, 0xAB, 0xC8, 0x39, 0x13, 0x97, 0x08, 0x9E, 0xA6, 0x64, 0x09, 0x67, 0xC1, 0x20, 0x49, 0x84, 0xCD, 0x48, 0x4C, 0xCC, 0xB0, 0x0A, 0x9A, 0x17, 0xD0, 0x87, 0x21, 0x84, 0x28, 0xEF, 0x3B, 0xB7, 0x08, 0x78, 0x3E, 0x12, 0x82, 0x71, 0x04, 0x41, 0x73, 0x75, 0xB6, 0x95, 0x6F, 0xB5, 0x00, 0x53, 0xD0, 0x48, 0xA4, 0x79, 0x14, 0x95, 0x82, 0x4A, 0x34, 0x80, 0xA5, 0xB7, 0x83, 0x02, 0x56, 0x09, 0x6F, 0xDD, 0x72, 0x5C, 0x30, 0x8B, 0x3B, 0xE8, 0x4A, 0x07, 0xF3, 0x63, 0x2E, 0x24, 0x95, 0xC6, 0x2E, 0x96, 0x39, 0x9D, 0x80, 0xBF, 0xA7, 0x45, 0xB9, 0x84, 0x1A, 0x18, 0x33, 0xBC, 0x1D, 0x27, 0xBA, 0x45, 0xA5, 0x21, 0x68, 0xEE, 0x59, 0x00, 0x6C, 0x3A, 0x3A, 0x8C, 0x4A, 0x5A, 0x4F, 0x50, 0x88, 0xFC, 0x73, 0x71, 0x81, 0xAB, 0x51, 0x96, 0xF7, 0xB1, 0xB4, 0x9A, 0x2E, 0xD8, 0x13, 0x13, 0x4E, 0x11, 0x2F, 0x73, 0x0B, 0x99, 0x1C, 0x54, 0xA7, 0x19, 0x6B, 0xCF, 0x5F, 0xC7, 0x6E, 0x13, 0x4C, 0x58, 0x43, 0xE1, 0x69, 0x88, 0x51, 0xB2, 0xF8, 0x69, 0xAF, 0xAF, 0xB0, 0x27, 0x87, 0xD9, 0xC2, 0xF1, 0x36, 0x90, 0x2D, 0xC7, 0xA7, 0xF3, 0xD6, 0x21, 0x56, 0xD1, 0x5E, 0xC3, 0x09, 0x56, 0x40, 0x92, 0xC6, 0x1D, 0x83, 0xB0, 0x98, 0x6C, 0x48, 0x40, 0x99, 0x81, 0xF3, 0xC1, 0x86, 0x88, 0x0A, 0x2F, 0x63, 0xD5, 0x86, 0x0A, 0xB6, 0x01, 0xDE, 0xAC, 0x2B, 0x6B, 0xA1, 0xB4, 0x28, 0x17, 0x9D, 0x73, 0x53, 0x3E, 0xB7, 0xA3, 0xA5, 0x11, 0x3B, 0x85, 0x61, 0xF1, 0x0B, 0x45, 0xC3, 0xCD, 0xE2, 0x82, 0xB6, 0xEA, 0xD6, 0xAB, 0x6C, 0x60, 0x4F, 0x09, 0xC1, 0x7B, 0xFD, 0xA0, 0x83, 0x13, 0xA3, 0x26, 0x07, 0x67, 0x5A, 0xDF, 0x64, 0x31, 0xCA, 0x87, 0x18, 0xE9, 0xC4, 0x3A, 0x73, 0x73, 0x32, 0x27, 0xE7, 0x3B, 0xC6, 0x1A, 0xC8, 0x45, 0xBA, 0x90, 0x77, 0x55, 0xCE, 0xC6, 0x89, 0x25, 0xE5, 0xE2, 0xBF, 0xE9, 0x12, 0x95, 0x9D, 0xB8, 0x6F, 0xBF, 0xE2, 0x15, 0x6F, 0xD5, 0xBB, 0xDB, 0xF0, 0xC9, 0xDF, 0x8B, 0x53, 0x02, 0xAA, 0x8D, 0x90, 0xA2, 0x2D, 0x12, 0x27, 0x0E, 0x00, 0x65, 0x51, 0xE4, 0x76, 0x7E, 0x45, 0x26, 0x8E, 0xD9, 0x69, 0x26, 0x54, 0x44, 0x78, 0x11, 0xEA, 0xB8, 0x4F, 0x04, 0x99, 0xA8, 0xA5, 0x8C, 0xF7, 0xC0, 0x4A, 0x59, 0x56, 0x98, 0x52, 0x80, 0x45, 0xF2, 0x98, 0x97, 0xC8, 0xFA, 0x96, 0xD0, 0x6C, 0xCE, 0x51, 0xE6, 0xAF, 0xEA, 0xC4, 0x33, 0x95, 0x89, 0xC9, 0x41, 0xC8, 0x55, 0x63, 0xD7, 0x0F, 0xAC, 0xE1, 0x92, 0x88, 0x94, 0xBA, 0xC0, 0x36, 0x19, 0xDF, 0xF4, 0xBE, 0x3F, 0x43, 0x14, 0xA3, 0xF7, 0x35, 0x1A, 0x09, 0xA4, 0x86, 0xB5, 0x04, 0x1E, 0x7C, 0xB2, 0xDA, 0x8B, 0x96, 0xBC, 0x66, 0x26, 0xA4, 0x93, 0x17, 0x35, 0x7C, 0x41, 0x52, 0xA5, 0x1B, 0xA3, 0xC2, 0x8C, 0x7E, 0x0C, 0x9D, 0xB4, 0x1A, 0x06, 0xA2, 0x82, 0x90, 0xF2, 0x18, 0x73, 0x11, 0x07, 0xC9, 0x54, 0xD8, 0xA6, 0x6F, 0x80, 0x1D, 0x7D, 0xE1, 0x2A, 0x03, 0x71, 0x16, 0x99, 0x0B, 0x6C, 0x53, 0xC1, 0x29, 0xF1, 0x85, 0xC3, 0x45, 0xF2, 0x7E, 0x51, 0x8B, 0x2D, 0x5A, 0x91, 0x25, 0xA0, 0x70, 0x76, 0xD9, 0x91, 0xB7, 0xDA, 0xC7, 0xCC, 0x65, 0xA8, 0x56, 0x2E, 0xFB, 0xCC, 0x32, 0xA9, 0xCA, 0x4A, 0xD9, 0x02, 0x63, 0xB0, 0x4A, 0x4F, 0x90, 0x36, 0x11, 0x6C, 0x7B, 0x97, 0x48, 0x04, 0x96, 0x31, 0x75, 0x75, 0x65, 0x0D, 0xCC, 0x21, 0x52, 0xB5, 0xBC, 0x0E, 0x74, 0x40, 0x7E, 0x12, 0xFA, 0x8E, 0x4F, 0xFC, 0xCC, 0xFF, 0x76, 0xC0, 0x1A, 0x97, 0x4B, 0xD6, 0x11, 0x02, 0xE1, 0xF5, 0x29, 0x64, 0x96, 0xC7, 0x1D, 0x07, 0x64, 0xE1, 0x32, 0x29, 0xFF, 0xE7, 0x84, 0x6F, 0x33, 0x6E, 0x34, 0xCA, 0xC9, 0x04, 0xCA, 0x56, 0x70, 0xF8, 0xCD, 0x50, 0x52, 0x42, 0x7A, 0x79, 0xC0, 0x91, 0xA9, 0x71, 0x21, 0x0C, 0x5C, 0xFF, 0x66, 0x7A, 0xAC, 0x24, 0x93, 0x66, 0xE1, 0x0D, 0x2B, 0x11, 0x37, 0x6C, 0xA3, 0x9D, 0x93, 0x52, 0x04, 0xB1, 0x2C, 0xC5, 0x85, 0xE9, 0x40, 0x54, 0x03, 0x62, 0x5F, 0xB3, 0x2C, 0xB5, 0xE5, 0xC3, 0x1B, 0x62, 0x34, 0x81, 0x60, 0x51, 0x5C, 0xCC, 0x4F, 0xDA, 0xF5, 0x70, 0x2D, 0x6B, 0xAB, 0x5C, 0x37, 0x3D, 0xB6, 0xF3, 0x50, 0xD3, 0xE6, 0x3A, 0x5C, 0xE3, 0xCA, 0x54, 0x74, 0xA0, 0xCF, 0x15, 0x67, 0x04, 0x2C, 0xA3, 0x25, 0x89, 0x86, 0xFF, 0x75, 0xBD, 0xFC, 0xD9, 0x29, 0xE6, 0x46, 0x2F, 0x36, 0xBC, 0xCC, 0x3F, 0x5A, 0x93, 0x35, 0x2A, 0x2B, 0x36, 0xCB, 0x16, 0x2E, 0x18, 0x74, 0xC7, 0x42, 0x87, 0x0A, 0x97, 0xB1, 0x67, 0xA0, 0x50, 0x37, 0x36, 0x24, 0xEA, 0xEB, 0x7E, 0x50, 0x73, 0x25, 0x6B, 0x72, 0x11, 0xB2, 0xD9, 0x4B, 0x84, 0x06, 0xCD, 0x6C, 0x95, 0x33, 0xB1, 0x53, 0x64, 0x08, 0xAB, 0x0A, 0x29, 0xE5, 0xB2, 0xF0, 0xC9, 0x54, 0xEC, 0xE0, 0x0F, 0xBB, 0xEB, 0x17, 0x6D, 0x72, 0x4D, 0x4C, 0xF4, 0x43, 0xCF, 0x70, 0x20, 0xD5, 0xFA, 0x70, 0x94, 0xCC, 0x1B, 0x1B, 0xE6, 0x97, 0xBA, 0xD3, 0x36, 0x74, 0xE4, 0x09, 0x9E, 0xC7, 0xBB, 0x18, 0xF4, 0x57, 0x71, 0x28, 0xCD, 0xD9, 0x7C, 0xCD, 0x6D, 0x44, 0x62, 0xE5, 0x60, 0x7C, 0x51, 0x2A, 0x3E, 0x36, 0x24, 0x8E, 0x3D, 0xDA, 0xA2, 0xEC, 0x08, 0x9A, 0xEF, 0xC4, 0xCE, 0x48, 0x5C, 0x49, 0xD7, 0xB0, 0x09, 0xC8, 0xD6, 0x31, 0x15, 0xFC, 0x81, 0xFF, 0x3A, 0x62, 0xD1, 0x5A, 0x88, 0x44, 0x1C, 0x03, 0xEA, 0x1C, 0x2E, 0x72, 0xC4, 0x88, 0x39, 0xFC, 0x6A, 0xD7, 0x3A, 0x30, 0x74, 0x4A, 0x62, 0xB7, 0xB2, 0x16, 0x45, 0xA6, 0xAF, 0x7D, 0x61, 0xB6, 0x38, 0x3B, 0x22, 0x1E, 0x21, 0x90, 0x55, 0x57, 0xCD, 0x29, 0xD9, 0x24, 0xA6, 0x09, 0x86, 0xC5, 0x11, 0xC1, 0xEB, 0xBC, 0x31, 0x6D, 0x56, 0x30, 0xA2, 0x41, 0x43, 0x23, 0xF5, 0x3A, 0xD5, 0x59, 0x94, 0xF6, 0xB3, 0x65, 0x39, 0xF9, 0xC4, 0x40, 0x75, 0xA5, 0x33, 0xE4, 0x81, 0xC0, 0x84, 0x45, 0xD9, 0xCA, 0x9E, 0x9D, 0x38, 0x21, 0x19, 0x38, 0x8B, 0xD1, 0xD7, 0x50, 0x52, 0x21, 0x7A, 0x94, 0x4C, 0xCC, 0x7B, 0xE9, 0x09, 0xE2, 0x19, 0x71, 0x1F, 0xCC, 0x79, 0x24, 0x76, 0x92, 0x13, 0xA1, 0x92, 0x53, 0x4A, 0x55, 0x80, 0x08, 0x15, 0x7A, 0x39, 0x6E, 0xDF, 0xF4, 0x80, 0xCC, 0x3B, 0x52, 0x0F, 0xF8, 0x18, 0xB3, 0x8B, 0x13, 0x5C, 0x18, 0xA8, 0x0D, 0x51, 0x05, 0xE6, 0x78, 0x83, 0x6C, 0x39, 0x5C, 0x28, 0xE9, 0x2F, 0x7A, 0x3C, 0x4E, 0x93, 0xC0, 0x10, 0x35, 0xF3, 0x41, 0x11, 0xCC, 0x49, 0x02, 0xD0, 0xC0, 0x33, 0xA6, 0x3F, 0x23, 0x6A, 0x71, 0xDA, 0x97, 0x4A, 0x6F, 0x40, 0x4F, 0x7A, 0xA7, 0xB5, 0xE5, 0x82, 0xC7, 0x58, 0x14, 0x2F, 0xC1, 0x82, 0x6B, 0xBA, 0x98, 0xB2, 0x7D, 0x57, 0xC2, 0xE2, 0x10, 0x3E, 0x10, 0xE3, 0x0D, 0x32, 0x79, 0x7B, 0x96, 0x77, 0x14, 0xD1, 0x56, 0x61, 0x11, 0x13, 0x71, 0xA2, 0xD9, 0xC5, 0x39, 0x98, 0x12, 0x46, 0x46, 0x22, 0x63, 0x5B, 0x44, 0x21, 0x26, 0xB0, 0x98, 0x36, 0xB0, 0x81, 0x82, 0x72, 0x47, 0xD0, 0x54, 0x22, 0x97, 0x2B, 0xD0, 0x32, 0x0D, 0x8F, 0x42, 0xBF, 0x57, 0xE3, 0x49, 0x46, 0x12, 0x34, 0xE4, 0xD9, 0x4F, 0x01, 0x18, 0x50, 0xBA, 0xB5, 0xC0, 0x49, 0xB6, 0x2A, 0x59, 0x43, 0x38, 0x66, 0xFC, 0xCE, 0x69, 0x66, 0x49, 0x5C, 0x26, 0x5C, 0x47, 0x65, 0xA5, 0x6C, 0x06, 0xB9, 0xFC, 0x42, 0x76, 0x54, 0x87, 0x85, 0xF4, 0x68, 0x28, 0xCA, 0x60, 0x2D, 0xC6, 0xD0, 0x54, 0x1F, 0x25, 0x07, 0x89, 0xC4, 0x9E, 0x8B, 0x06, 0x55, 0x9C, 0x43, 0x44, 0x60, 0xA8, 0x43, 0x80, 0x98, 0x54, 0xE5, 0xB4, 0x6E, 0x89, 0x38, 0x9F, 0x10, 0xF4, 0x89, 0x66, 0x74, 0x91, 0xC1, 0x93, 0x5E, 0x8A, 0xFB, 0x9E, 0xB4, 0x71, 0x8F, 0x86, 0xAC, 0x45, 0x89, 0x32, 0xBC, 0xF3, 0x3C, 0x9A, 0xBE, 0xCB, 0x2D, 0xC0, 0xC0, 0x93, 0xA7, 0xE8, 0x1D, 0xA0, 0x32, 0x7B, 0xB6, 0x37, 0x52, 0x81, 0x05, 0xC3, 0x58, 0xEB, 0x76, 0x8D, 0x32, 0x3A, 0x37, 0xD4, 0x0A, 0x8C, 0x19, 0x9B, 0x7C, 0x4B, 0xB1, 0xD7, 0x2B, 0x72, 0xB6, 0x90, 0xB3, 0x6D, 0xD2, 0x7A, 0x93, 0x55, 0x19, 0x1B, 0x3C, 0x3A, 0xA6, 0x75, 0xA7, 0xE6, 0xF8, 0x55, 0xEB, 0x50, 0x5F, 0x57, 0x98, 0x65, 0xDB, 0xD8, 0x91, 0x05, 0x65, 0x50, 0x5E, 0x7C, 0x0F, 0xDD, 0x54, 0x5C, 0xBB, 0xB8, 0x71, 0xB0, 0xB2, 0xCC, 0x01, 0x25, 0xB7, 0x4F, 0x6B, 0x0C, 0x9B, 0x79, 0x67, 0x0A, 0x62, 0x02, 0xD1, 0xB9, 0x15, 0x4A, 0xC7, 0x76, 0x6B, 0x19, 0x19, 0xC4, 0x89, 0x58, 0x90, 0x86, 0xAD, 0x8B, 0x45, 0xBE, 0x0D, 0x79, 0xC9, 0x76, 0xC3, 0xC3, 0x9D, 0x6B, 0x25, 0x21, 0x3B, 0xB0, 0xB7, 0x8A, 0x57, 0x50, 0xE6, 0xA8, 0xEB, 0x34, 0x33, 0x0B, 0xB3, 0xCF, 0xF2, 0xB1, 0xC0, 0x72, 0x2A, 0xC8, 0x83, 0xB0, 0x48, 0xF4, 0xB8, 0xCD, 0x06, 0x19, 0x6D, 0xA8, 0xAA, 0x8B, 0x05, 0xDA, 0x42, 0x67, 0x55, 0x2B, 0xF8, 0x7A, 0xBC, 0xA5, 0x12, 0x4D, 0xC3, 0x58, 0xA8, 0x38, 0x10, 0x40, 0xE9, 0xB8, 0x1F, 0xB0, 0x84, 0x43, 0x15, 0x02, 0x15, 0xD6, 0x92, 0x23, 0x28, 0x00, 0x0A, 0xC0, 0xB7, 0x88, 0xB1, 0x21, 0x93, 0x1A, 0x26, 0x7D, 0x80, 0x61, 0x9C, 0xE7, 0xD2, 0x9C, 0xD7, 0x6B, 0x60, 0xCF, 0x65, 0x83, 0xDC, 0xE8, 0xCE, 0xBC, 0x49, 0x01, 0x85, 0x73, 0x6C, 0x81, 0x8B, 0x25, 0xAD, 0x26, 0x0B, 0x66, 0x7B, 0x1F, 0xFD, 0x46, 0x20, 0x6D, 0x01, 0x04, 0x55, 0x3A, 0xA9, 0xFB, 0x30, 0x45, 0x54, 0xA2, 0x1C, 0x32, 0x72, 0x44, 0xCE, 0x78, 0xAF, 0xDB, 0xD3, 0xB4, 0x62, 0x36, 0x1B, 0xB0, 0x68, 0xA1, 0x55, 0x63, 0x64, 0x09, 0xF5, 0x74, 0xC5, 0x71, 0x65, 0x72, 0xE2, 0xA5, 0xF2, 0xA4, 0xB0, 0x4F, 0xB8, 0xAA, 0xD1, 0x23, 0x66, 0x84, 0x84, 0x17, 0x87, 0x56, 0x2A, 0xAF, 0x46, 0xC2, 0xC0, 0xDA, 0x46, 0x65, 0xEA, 0xFD, 0x46, 0x5F, 0xC6, 0x4A, 0x0C, 0x5F, 0x8F, 0x3F, 0x90, 0x03, 0x48, 0x94, 0x15, 0x89, 0x9D, 0x59, 0xA5, 0x43, 0xD8, 0x20, 0x8C, 0x54, 0xA3, 0x16, 0x65, 0x29, 0xB5, 0x39, 0x22, }, .pkcs8_len = 0, .spki_len = 0, .secret_len = 32, .secret = { 0xfb, 0xc4, 0xee, 0xa6, 0x91, 0xee, 0xf4, 0xc1, 0xb4, 0x76, 0xa2, 0x99, 0x36, 0x45, 0x3f, 0x4c, 0x3d, 0x48, 0x81, 0x79, 0x4e, 0xe3, 0x7b, 0xaf, 0x0f, 0xd7, 0x28, 0x40, 0x74, 0x3e, 0x7b, 0x7d, }, .cipher_len = 1568, .cipher = { 0xc2, 0x7f, 0x01, 0x24, 0x4d, 0x4b, 0x3f, 0xb2, 0x1d, 0x84, 0x37, 0xf8, 0x40, 0x01, 0x7c, 0xcc, 0xb7, 0xb7, 0xda, 0xd5, 0xfb, 0x2b, 0x47, 0xb9, 0xb5, 0x7e, 0xae, 0x4f, 0x77, 0xd0, 0xa4, 0x55, 0x5e, 0x50, 0x92, 0xa2, 0x49, 0x69, 0xf2, 0x27, 0x3e, 0x97, 0x02, 0x88, 0x4a, 0x08, 0x47, 0x7b, 0x56, 0x8d, 0x80, 0x17, 0xf1, 0x38, 0x75, 0xd1, 0xf5, 0xa6, 0xd4, 0x13, 0xbd, 0xd2, 0x28, 0xeb, 0xb1, 0x12, 0x60, 0xf7, 0xf4, 0x52, 0x9c, 0xbc, 0xeb, 0xf9, 0xb6, 0x86, 0x2e, 0x8a, 0x84, 0x12, 0x35, 0xf2, 0x9f, 0x60, 0xf8, 0xe8, 0x41, 0x74, 0x34, 0x18, 0x9d, 0x57, 0x99, 0x20, 0xfe, 0x6b, 0x98, 0xdb, 0xe7, 0x13, 0xec, 0x16, 0xc3, 0xfd, 0xdb, 0xb8, 0x1e, 0x73, 0x1d, 0x95, 0x6b, 0x06, 0xdb, 0x49, 0x80, 0xf4, 0x9c, 0x26, 0xf2, 0x86, 0x61, 0xff, 0x9c, 0xe6, 0xe9, 0xd8, 0x61, 0xec, 0x7a, 0x09, 0x84, 0x0c, 0x19, 0xde, 0x0e, 0xb6, 0x72, 0x20, 0x71, 0xf8, 0xaa, 0x48, 0x36, 0x2d, 0x2f, 0xf1, 0x27, 0xa4, 0xae, 0x46, 0xf9, 0x93, 0x37, 0x82, 0x68, 0x32, 0xad, 0xac, 0x23, 0x91, 0x65, 0xf2, 0x25, 0x85, 0xbb, 0x57, 0xa8, 0x89, 0xc9, 0xc6, 0xaf, 0x82, 0x36, 0x7e, 0xc7, 0xb0, 0x72, 0x37, 0xc0, 0x53, 0x5b, 0x31, 0xb3, 0x8c, 0x1c, 0xac, 0x40, 0xac, 0x1a, 0x0c, 0x95, 0x8a, 0x18, 0x87, 0xfe, 0x34, 0x71, 0x10, 0x83, 0xfd, 0x37, 0xaf, 0x4b, 0xc5, 0xb1, 0xb4, 0xe1, 0xe2, 0xee, 0x28, 0x43, 0x69, 0x3d, 0x57, 0xdd, 0x1e, 0x65, 0x7d, 0x4c, 0x24, 0xed, 0x20, 0x7e, 0xe7, 0x12, 0xad, 0x2a, 0x08, 0x91, 0x45, 0x81, 0x80, 0xe9, 0xe8, 0xbd, 0x36, 0xfc, 0x14, 0xd8, 0xd6, 0x33, 0xf5, 0xb7, 0x41, 0xce, 0xa1, 0x08, 0xd2, 0xd4, 0xfd, 0x75, 0x1c, 0x5a, 0x67, 0xb0, 0x5e, 0x30, 0x32, 0x4a, 0x67, 0xe9, 0xdd, 0x75, 0xc9, 0x93, 0xd4, 0xfe, 0x08, 0x54, 0xfb, 0x78, 0xdf, 0x6f, 0x3d, 0x45, 0xa2, 0xa9, 0xc8, 0xe4, 0x25, 0x10, 0xf0, 0xc3, 0xd8, 0x02, 0x03, 0x71, 0x2f, 0xb3, 0x9e, 0x36, 0xb5, 0xdd, 0x8b, 0x5c, 0xcd, 0x3d, 0x09, 0xce, 0xa9, 0x42, 0x03, 0xba, 0xf8, 0x72, 0x08, 0x45, 0x71, 0xec, 0xf9, 0x78, 0xbd, 0xb9, 0x54, 0x8a, 0x25, 0x0e, 0xe4, 0x90, 0x7b, 0x4a, 0xfc, 0x31, 0xb2, 0x1f, 0x31, 0x9a, 0xe4, 0xbf, 0x0a, 0xb1, 0x9c, 0xbd, 0x11, 0xeb, 0xe1, 0x33, 0x59, 0xd1, 0xaa, 0xf4, 0xfd, 0xb8, 0x3b, 0x65, 0x02, 0x50, 0x14, 0x22, 0xa5, 0xfe, 0x50, 0xa8, 0xa3, 0x8e, 0xf5, 0x3d, 0xeb, 0x60, 0x3c, 0xe2, 0x3f, 0xd9, 0x79, 0x2b, 0x04, 0xde, 0xb3, 0x78, 0x71, 0x9a, 0xb7, 0x69, 0xaa, 0x58, 0x97, 0xcc, 0x65, 0xe9, 0xb1, 0x63, 0x04, 0xce, 0xa5, 0x37, 0xe1, 0x76, 0x2b, 0xd8, 0xc9, 0xb1, 0x09, 0xda, 0x14, 0xa8, 0x29, 0xe6, 0x41, 0x9f, 0x1b, 0x9f, 0xf8, 0xa4, 0x66, 0xe2, 0xa6, 0xd6, 0xb3, 0x4d, 0x74, 0xff, 0xe1, 0xa5, 0x92, 0x99, 0x18, 0x17, 0x59, 0xd0, 0xd3, 0x87, 0xfc, 0xed, 0x1d, 0x90, 0x7f, 0x5f, 0xb5, 0xed, 0xb4, 0x26, 0xc0, 0x51, 0x30, 0xe6, 0xca, 0x59, 0x09, 0xb2, 0x76, 0xd1, 0xa4, 0x7e, 0x71, 0x3c, 0x30, 0xd9, 0x96, 0xda, 0x5e, 0x8e, 0x57, 0xe7, 0x12, 0xc7, 0x77, 0x38, 0xf2, 0x1b, 0xe7, 0x4b, 0x42, 0xb5, 0x18, 0x43, 0x2d, 0xad, 0x7e, 0xf7, 0x3e, 0x6a, 0x8c, 0x43, 0xaa, 0x9a, 0x62, 0x69, 0x94, 0xd7, 0x1a, 0x31, 0x81, 0x28, 0x51, 0x80, 0x6e, 0x9f, 0xbb, 0x1f, 0x2b, 0xd3, 0x56, 0xce, 0xa3, 0x9d, 0x95, 0xf2, 0xf8, 0x7c, 0xa3, 0x0d, 0xaf, 0x6f, 0x27, 0x33, 0xf7, 0xbc, 0xe7, 0x9f, 0x8d, 0xa9, 0x95, 0x05, 0x1e, 0x49, 0xa7, 0xfd, 0x22, 0x64, 0x37, 0x9c, 0x0a, 0x75, 0x2e, 0x55, 0x3e, 0xd6, 0x08, 0xeb, 0x93, 0x44, 0xc7, 0x94, 0x98, 0xf6, 0x91, 0x53, 0x85, 0x64, 0xc5, 0x4f, 0x82, 0x3b, 0xb7, 0x0b, 0x12, 0xb5, 0x9e, 0x88, 0x24, 0xb4, 0xa4, 0xbb, 0x1e, 0xea, 0xc6, 0x7c, 0x81, 0x0c, 0xcc, 0x2e, 0x23, 0x74, 0x47, 0x83, 0xce, 0x95, 0x80, 0x97, 0xf7, 0xa6, 0xbc, 0x6e, 0x1f, 0x17, 0x59, 0x75, 0x21, 0xb8, 0xc3, 0xd1, 0xee, 0x85, 0x96, 0xa2, 0x9f, 0xfe, 0xf1, 0x4e, 0xd9, 0x16, 0x32, 0x09, 0x7c, 0x16, 0xd5, 0x06, 0x5d, 0xb2, 0xa9, 0x63, 0xca, 0x73, 0x83, 0xac, 0x60, 0xad, 0x8f, 0x4e, 0xd0, 0xd4, 0x1b, 0xd0, 0xbc, 0x3b, 0xaf, 0x19, 0x8c, 0x51, 0x25, 0xae, 0x91, 0x15, 0x06, 0xc9, 0x26, 0xd4, 0xc1, 0x17, 0x85, 0xfd, 0x61, 0x82, 0x29, 0xbf, 0xf5, 0x4c, 0xb1, 0x16, 0x1a, 0xb8, 0xfc, 0x7b, 0x51, 0xda, 0xec, 0xcc, 0xd9, 0x13, 0x1e, 0xdf, 0x43, 0x7d, 0x8e, 0x52, 0x8e, 0x75, 0x81, 0xb8, 0x2c, 0x66, 0x0e, 0x8c, 0x5e, 0x25, 0x12, 0xd5, 0xf6, 0x38, 0x0a, 0x52, 0x8f, 0x2a, 0xe4, 0xae, 0xe2, 0x63, 0xdb, 0x96, 0x76, 0x02, 0x4b, 0xc7, 0xad, 0x39, 0x8b, 0xc9, 0xcd, 0xda, 0xd6, 0x07, 0x96, 0x8b, 0xba, 0xb2, 0x23, 0x29, 0xe0, 0x4d, 0x6e, 0x77, 0x1f, 0xe6, 0x47, 0x10, 0x7a, 0xc4, 0x66, 0x67, 0xa5, 0x1a, 0xd5, 0x58, 0xa6, 0x35, 0xf0, 0x26, 0x95, 0x1f, 0x4f, 0x48, 0xc8, 0x88, 0xd7, 0x01, 0xc2, 0xaf, 0xf4, 0xea, 0xb4, 0xe3, 0x4a, 0xdb, 0x15, 0x9a, 0xbb, 0xbf, 0xab, 0xe5, 0x9b, 0x3f, 0x4c, 0xf8, 0xaa, 0xb1, 0xdd, 0x66, 0x1e, 0x4d, 0xd0, 0xc5, 0x55, 0x8d, 0xc0, 0x59, 0x20, 0x2e, 0xe6, 0x46, 0x25, 0xa3, 0xb4, 0xb9, 0x2f, 0xf4, 0xd1, 0x56, 0x97, 0xf1, 0x6c, 0x18, 0xd4, 0xd2, 0x33, 0x8c, 0xfb, 0x49, 0x6e, 0x07, 0x03, 0x52, 0x68, 0x71, 0xc9, 0x78, 0x4b, 0xac, 0x8e, 0xba, 0xe8, 0x27, 0x9c, 0xf2, 0x71, 0x3a, 0xf3, 0xcc, 0x2d, 0x44, 0x0e, 0x8c, 0xd2, 0x00, 0x86, 0x7b, 0x85, 0x18, 0xaa, 0xd3, 0xb9, 0xe2, 0x85, 0x02, 0x7d, 0xa0, 0xad, 0xd9, 0xf0, 0x22, 0x9e, 0xd4, 0xe8, 0x42, 0xd0, 0x5e, 0x22, 0x6a, 0xda, 0xc1, 0x3a, 0x39, 0x52, 0xe3, 0x83, 0x5c, 0x8f, 0xb0, 0xa4, 0x28, 0x74, 0xc9, 0x4c, 0x66, 0x1b, 0x39, 0xdf, 0x7b, 0x72, 0x88, 0x7d, 0x22, 0x7d, 0x58, 0x3c, 0xe6, 0xb3, 0xbd, 0x65, 0xf7, 0x95, 0x10, 0x7b, 0xd0, 0x93, 0x38, 0x9b, 0xfe, 0xfd, 0x17, 0x68, 0xa5, 0x71, 0x6f, 0x68, 0x5b, 0x17, 0x4e, 0xd2, 0x3e, 0x94, 0xa5, 0x95, 0x6e, 0x29, 0xbb, 0x2d, 0xdb, 0x79, 0x21, 0x03, 0xe6, 0x2f, 0x68, 0x92, 0x8a, 0xcc, 0x60, 0x3e, 0xec, 0x2f, 0xf5, 0x6d, 0xb1, 0x4c, 0x08, 0xb7, 0xcb, 0xe4, 0xe2, 0xb4, 0xf2, 0xe0, 0xea, 0xee, 0x54, 0x16, 0x2e, 0x95, 0xbb, 0x35, 0xef, 0x36, 0x30, 0x3e, 0xe3, 0xe6, 0xcc, 0x61, 0x06, 0x13, 0x73, 0x87, 0x6f, 0x7a, 0x09, 0x6a, 0x8a, 0xf5, 0x7d, 0x78, 0x2f, 0x8c, 0x82, 0x03, 0xde, 0x93, 0x42, 0x3a, 0x37, 0x91, 0x22, 0xfe, 0x7d, 0xad, 0x77, 0x0c, 0x36, 0x90, 0xf9, 0x78, 0x22, 0x84, 0x60, 0xd0, 0x25, 0xce, 0x93, 0xb1, 0xb3, 0x36, 0xc5, 0x73, 0xe4, 0xe5, 0x58, 0x40, 0xea, 0x65, 0xcf, 0xdd, 0x61, 0x22, 0xc6, 0x72, 0xc9, 0x12, 0xf5, 0x29, 0x39, 0xd9, 0xea, 0x5b, 0xe0, 0x62, 0x10, 0xf5, 0xe7, 0xed, 0xb6, 0x5b, 0x66, 0x94, 0x5d, 0x70, 0x56, 0xf5, 0x59, 0xa7, 0xd6, 0x92, 0x53, 0xf4, 0xbd, 0xbc, 0x57, 0x9d, 0xe9, 0x64, 0xf3, 0xe9, 0x3a, 0x86, 0xfa, 0x38, 0xb6, 0xa2, 0xc0, 0xb5, 0x43, 0x38, 0xdc, 0xe0, 0x93, 0xf0, 0xb4, 0x68, 0x4e, 0xe3, 0x61, 0x44, 0x9f, 0x16, 0xc2, 0x79, 0xa7, 0x2b, 0x77, 0x31, 0xe4, 0x46, 0x00, 0xa7, 0x02, 0x77, 0x68, 0xfd, 0xd0, 0xf6, 0x43, 0xed, 0x10, 0x06, 0x4b, 0x98, 0xa9, 0xda, 0x03, 0x2f, 0x1f, 0x5d, 0xea, 0xd3, 0x11, 0xe1, 0x77, 0x33, 0x50, 0x94, 0xdb, 0x4e, 0x38, 0x51, 0x4e, 0xae, 0x15, 0xa8, 0xf8, 0xec, 0xf2, 0xf2, 0x41, 0x4e, 0x37, 0x8e, 0xfb, 0xf9, 0x97, 0xb1, 0x06, 0x6b, 0x6f, 0x69, 0xd6, 0x69, 0x09, 0xa4, 0x7e, 0x29, 0x8a, 0x7f, 0xec, 0x96, 0x1a, 0x83, 0x78, 0x2e, 0x0e, 0x47, 0x0f, 0xe0, 0x71, 0xde, 0xcf, 0x4b, 0x26, 0xac, 0xa6, 0xed, 0x68, 0x83, 0x59, 0xe1, 0x08, 0x50, 0x55, 0xfd, 0x2b, 0x5a, 0xe9, 0xf4, 0x91, 0x87, 0x49, 0x89, 0x7a, 0xf1, 0x33, 0x60, 0x60, 0x53, 0xd5, 0xf6, 0xa8, 0x52, 0x8c, 0xcb, 0x31, 0xab, 0x7f, 0x3f, 0x2d, 0x89, 0xa9, 0x5c, 0x5f, 0x05, 0xb1, 0x57, 0x00, 0xe5, 0x32, 0xad, 0x81, 0xd5, 0x9d, 0x9d, 0xb8, 0xa2, 0xc2, 0x9c, 0xac, 0x93, 0x6e, 0x3f, 0x33, 0xdf, 0xe2, 0x4b, 0x0b, 0x1b, 0x71, 0x90, 0x2d, 0xc9, 0xc3, 0x0e, 0xc8, 0xc7, 0x0b, 0xda, 0xba, 0x48, 0x4f, 0xcd, 0x2b, 0x94, 0x6d, 0x73, 0x5f, 0x16, 0xee, 0xad, 0x04, 0x03, 0x1c, 0xaf, 0xde, 0x9e, 0xe0, 0x16, 0x96, 0xec, 0x9f, 0x0a, 0x8d, 0x5f, 0x36, 0xb6, 0x9c, 0x64, 0x2f, 0xfd, 0x0a, 0xd0, 0xd2, 0x54, 0x4f, 0x5e, 0x7f, 0xd8, 0x9a, 0x80, 0x49, 0x8e, 0xf6, 0x8e, 0x18, 0x16, 0x17, 0xfa, 0xd4, 0x1e, 0x0b, 0xd5, 0x9b, 0xaa, 0xff, 0xee, 0xfe, 0x2f, 0x99, 0x72, 0x4c, 0x71, 0x9d, 0x47, 0xa2, 0xec, 0xba, 0x72, 0x1d, 0x76, 0xf2, 0x37, 0xeb, 0xa7, 0x3d, 0xb4, 0x7d, 0x88, 0xb6, 0x99, 0xe3, 0x58, 0x2b, 0x07, 0x3c, 0x7e, 0xad, 0x2a, 0x5b, 0x3c, 0xf0, 0x24, 0x46, 0x63, 0x96, 0xf9, 0xf2, 0x82, 0x6c, 0xb7, 0x54, 0xf6, 0x60, 0x18, 0xe9, 0x50, 0x3f, 0x4a, 0xd1, 0xf9, 0xd9, 0x21, 0x21, 0xaa, 0x99, 0x56, 0x50, 0x60, 0x51, 0xd5, 0x96, 0xff, 0xd4, 0x67, 0xe1, 0xaa, 0x8d, 0x96, 0x4c, 0x17, 0x67, 0xc9, 0x25, 0xb4, 0x68, 0xbb, 0xc9, 0x85, 0x06, 0x00, 0xc8, 0x43, 0x49, 0x05, 0x41, 0xe8, 0x55, 0x5a, 0x3d, 0x8b, 0xd9, 0xf1, 0x87, 0x91, 0xef, 0x9e, 0xbd, 0x35, 0x94, 0xe7, 0x4c, 0x1f, 0xe3, 0xd3, 0xb8, 0x09, 0x40, 0xa8, 0xa0, 0x79, 0xf8, 0xd2, 0xca, 0x8d, 0x30, 0x13, 0x4f, 0xc6, 0x6f, 0x87, 0x00, 0x81, 0x26, 0xe4, 0x3b, 0xd0, 0x6e, 0xb6, 0xe4, 0x1c, 0x3a, 0x70, 0xfa, 0x47, 0x39, 0x31, 0x9b, 0xf1, 0xa9, 0x32, 0xf0, 0x2c, 0x30, 0x64, 0x56, 0x56, 0x0c, 0xda, 0x44, 0xdd, 0xac, 0x43, 0xed, 0x6d, 0x90, 0x04, 0x45, 0xf5, 0xbf, 0x85, 0xbb, 0x0c, 0xe3, 0x25, 0x94, 0x74, 0x36, 0xe0, 0xd0, 0x68, 0x5e, 0x41, 0xb1, 0x6b, 0xc7, 0x16, 0x95, 0x18, 0x25, 0x9e, 0x57, 0x34, 0xfd, 0xce, 0x08, 0x0f, 0xfe, 0x85, 0x19, 0x1b, 0x1d, 0x8d, 0x8d, 0xe4, 0xdb, 0x48, 0x14, 0x3f, 0xb5, 0x64, 0x03, 0x8a, 0xce, 0x80, 0x10, 0x4d, 0x3a, 0x8d, 0x07, 0x12, 0x45, 0xe2, 0xaa, 0x56, 0xc7, 0x19, 0x33, 0xf4, 0xdc, 0xf9, 0x25, 0xee, 0xe8, 0x44, 0xc8, 0x0f, 0xdd, 0xf3, 0x25, 0x1f, 0x74, 0x00, 0x6a, 0x23, 0x41, 0x33, 0x18, 0xbb, 0xfd, 0x2e, 0xd9, 0xe0, 0x53, 0x51, 0xb5, 0xaa, 0xeb, 0xcc, 0x77, 0xcf, 0xac, 0x8d, 0x5f, 0x03, 0x64, 0x23, 0x1a, 0x50, 0xea, 0x86, 0x47, 0xc7, 0x2f, 0x71, 0x3e, 0x81, 0x7a, 0x20, 0x75, 0x32, 0x30, 0x29, 0xe3, 0xb8, 0x8b, 0x72, 0x44, 0x22, 0x64, 0xc5, 0x97, 0xb0, 0xf1, 0xfc, 0x09, 0xf9, 0x40, 0x1c, 0xe8, 0x8a, 0xc9, 0x7c, 0x55, 0x22, 0xa5, 0x63, 0x64, 0x52, 0x3c, 0x37, 0xfe, 0xa2, 0xd6, 0xbd, 0x06, 0xb2, }, }, { .name = "Kyber Round 2, 1024 KAT 1 (PKCS#8/SPKI)", .version = 0, .keyform = 0, .pk_len = 0, .sk_len = 0, .pkcs8_len = 4849, .pkcs8 = { 0x30, 0x82, 0x12, 0xed, 0x02, 0x01, 0x00, 0x30, 0x0f, 0x06, 0x0b, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x02, 0x82, 0x0b, 0x05, 0x04, 0x04, 0x05, 0x00, 0x04, 0x82, 0x12, 0xd5, 0x30, 0x82, 0x12, 0xd1, 0x02, 0x01, 0x00, 0x03, 0x82, 0x0c, 0x61, 0x00, 0x07, 0x63, 0x8f, 0xb6, 0x98, 0x68, 0xf3, 0xd3, 0x20, 0xe5, 0x86, 0x2b, 0xd9, 0x69, 0x33, 0xfe, 0xb3, 0x11, 0xb3, 0x62, 0x09, 0x3c, 0x9b, 0x5d, 0x50, 0x17, 0x0b, 0xce, 0xd4, 0x3f, 0x1b, 0x53, 0x6d, 0x9a, 0x20, 0x4b, 0xb1, 0xf2, 0x26, 0x95, 0x95, 0x0b, 0xa1, 0xf2, 0xa9, 0xe8, 0xeb, 0x82, 0x8b, 0x28, 0x44, 0x88, 0x76, 0x0b, 0x3f, 0xc8, 0x4f, 0xab, 0xa0, 0x42, 0x75, 0xd5, 0x62, 0x8e, 0x39, 0xc5, 0xb2, 0x47, 0x13, 0x74, 0x28, 0x3c, 0x50, 0x32, 0x99, 0xc0, 0xab, 0x49, 0xb6, 0x6b, 0x8b, 0xbb, 0x56, 0xa4, 0x18, 0x66, 0x24, 0xf9, 0x19, 0xa2, 0xba, 0x59, 0xbb, 0x08, 0xd8, 0x55, 0x18, 0x80, 0xc2, 0xbe, 0xfc, 0x4f, 0x87, 0xf2, 0x5f, 0x59, 0xab, 0x58, 0x7a, 0x79, 0xc3, 0x27, 0xd7, 0x92, 0xd5, 0x4c, 0x97, 0x4a, 0x69, 0x26, 0x2f, 0xf8, 0xa7, 0x89, 0x38, 0x28, 0x9e, 0x9a, 0x87, 0xb6, 0x88, 0xb0, 0x83, 0xe0, 0x59, 0x5f, 0xe2, 0x18, 0xb6, 0xbb, 0x15, 0x05, 0x94, 0x1c, 0xe2, 0xe8, 0x1a, 0x5a, 0x64, 0xc5, 0xaa, 0xc6, 0x04, 0x17, 0x25, 0x69, 0x85, 0x34, 0x9e, 0xe4, 0x7a, 0x52, 0x42, 0x0a, 0x5f, 0x97, 0x47, 0x7b, 0x72, 0x36, 0xac, 0x76, 0xbc, 0x70, 0xe8, 0x28, 0x87, 0x29, 0x28, 0x7e, 0xe3, 0xe3, 0x4a, 0x3d, 0xbc, 0x36, 0x83, 0xc0, 0xb7, 0xb1, 0x00, 0x29, 0xfc, 0x20, 0x34, 0x18, 0x53, 0x7e, 0x74, 0x66, 0xba, 0x63, 0x85, 0xa8, 0xff, 0x30, 0x1e, 0xe1, 0x27, 0x08, 0xf8, 0x2a, 0xaa, 0x1e, 0x38, 0x0f, 0xc7, 0xa8, 0x8f, 0x8f, 0x20, 0x5a, 0xb7, 0xe8, 0x8d, 0x7e, 0x95, 0x95, 0x2a, 0x55, 0xba, 0x20, 0xd0, 0x9b, 0x79, 0xa4, 0x71, 0x41, 0xd6, 0x2b, 0xf6, 0xeb, 0x7d, 0xd3, 0x07, 0xb0, 0x8e, 0xca, 0x13, 0xa5, 0xbc, 0x5f, 0x6b, 0x68, 0x58, 0x1c, 0x68, 0x65, 0xb2, 0x7b, 0xbc, 0xdd, 0xab, 0x14, 0x2f, 0x4b, 0x2c, 0xbf, 0xf4, 0x88, 0xc8, 0xa2, 0x27, 0x05, 0xfa, 0xa9, 0x8a, 0x2b, 0x9e, 0xea, 0x35, 0x30, 0xc7, 0x66, 0x62, 0x33, 0x5c, 0xc7, 0xea, 0x3a, 0x00, 0x77, 0x77, 0x25, 0xeb, 0xcc, 0xcd, 0x2a, 0x46, 0x36, 0xb2, 0xd9, 0x12, 0x2f, 0xf3, 0xab, 0x77, 0x12, 0x3c, 0xe0, 0x88, 0x3c, 0x19, 0x11, 0x11, 0x5e, 0x50, 0xc9, 0xe8, 0xa9, 0x41, 0x94, 0xe4, 0x8d, 0xd0, 0xd0, 0x9c, 0xff, 0xb3, 0xad, 0xcd, 0x2c, 0x1e, 0x92, 0x43, 0x09, 0x03, 0xd0, 0x7a, 0xdb, 0xf0, 0x05, 0x32, 0x03, 0x15, 0x75, 0xaa, 0x7f, 0x9e, 0x7b, 0x5a, 0x1f, 0x33, 0x62, 0xde, 0xc9, 0x36, 0xd4, 0x04, 0x3c, 0x05, 0xf2, 0x47, 0x6c, 0x07, 0x57, 0x8b, 0xc9, 0xcb, 0xaf, 0x2a, 0xb4, 0xe3, 0x82, 0x72, 0x7a, 0xd4, 0x16, 0x86, 0xa9, 0x6b, 0x25, 0x48, 0x82, 0x0b, 0xb0, 0x3b, 0x32, 0xf1, 0x1b, 0x28, 0x11, 0xad, 0x62, 0xf4, 0x89, 0xe9, 0x51, 0x63, 0x2a, 0xba, 0x0d, 0x1d, 0xf8, 0x96, 0x80, 0xcc, 0x8a, 0x8b, 0x53, 0xb4, 0x81, 0xd9, 0x2a, 0x68, 0xd7, 0x0b, 0x4e, 0xa1, 0xc3, 0xa6, 0xa5, 0x61, 0xc0, 0x69, 0x28, 0x82, 0xb5, 0xca, 0x8c, 0xc9, 0x42, 0xa8, 0xd4, 0x95, 0xaf, 0xcb, 0x06, 0xde, 0x89, 0x49, 0x8f, 0xb9, 0x35, 0xb7, 0x75, 0x90, 0x8f, 0xe7, 0xa0, 0x3e, 0x32, 0x4d, 0x54, 0xcc, 0x19, 0xd4, 0xe1, 0xaa, 0xbd, 0x35, 0x93, 0xb3, 0x8b, 0x19, 0xee, 0x13, 0x88, 0xfe, 0x49, 0x2b, 0x43, 0x12, 0x7e, 0x5a, 0x50, 0x42, 0x53, 0x78, 0x6a, 0x0d, 0x69, 0xad, 0x32, 0x60, 0x1c, 0x28, 0xe2, 0xc8, 0x85, 0x04, 0xa5, 0xba, 0x59, 0x97, 0x06, 0x02, 0x3a, 0x61, 0x36, 0x3e, 0x17, 0xc6, 0xb9, 0xbb, 0x59, 0xbd, 0xc6, 0x97, 0x45, 0x2c, 0xd0, 0x59, 0x45, 0x19, 0x83, 0xd7, 0x38, 0xca, 0x3f, 0xd0, 0x34, 0xe3, 0xf5, 0x98, 0x88, 0x54, 0xca, 0x05, 0x03, 0x1d, 0xb0, 0x96, 0x11, 0x49, 0x89, 0x88, 0x19, 0x7c, 0x6b, 0x30, 0xd2, 0x58, 0xdf, 0xe2, 0x62, 0x65, 0x54, 0x1c, 0x89, 0xa4, 0xb3, 0x1d, 0x68, 0x64, 0xe9, 0x38, 0x9b, 0x03, 0xcb, 0x74, 0xf7, 0xec, 0x43, 0x23, 0xfb, 0x94, 0x21, 0xa4, 0xb9, 0x79, 0x0a, 0x26, 0xd1, 0x7b, 0x03, 0x98, 0xa2, 0x67, 0x67, 0x35, 0x09, 0x09, 0xf8, 0x4d, 0x57, 0xb6, 0x69, 0x4d, 0xf8, 0x30, 0x66, 0x4c, 0xa8, 0xb3, 0xc3, 0xc0, 0x3e, 0xd2, 0xae, 0x67, 0xb8, 0x90, 0x06, 0x86, 0x8a, 0x68, 0x52, 0x7c, 0xcd, 0x66, 0x64, 0x59, 0xab, 0x7f, 0x05, 0x66, 0x71, 0x00, 0x0c, 0x61, 0x64, 0xd3, 0xa7, 0xf2, 0x66, 0xa1, 0x4d, 0x97, 0xcb, 0xd7, 0x00, 0x4d, 0x6c, 0x92, 0xca, 0xca, 0x77, 0x0b, 0x84, 0x4a, 0x4f, 0xa9, 0xb1, 0x82, 0xe7, 0xb1, 0x8c, 0xa8, 0x85, 0x08, 0x2a, 0xc5, 0x64, 0x6f, 0xcb, 0x4a, 0x14, 0xe1, 0x68, 0x5f, 0xeb, 0x0c, 0x9c, 0xe3, 0x37, 0x2a, 0xb9, 0x53, 0x65, 0xc0, 0x4f, 0xd8, 0x30, 0x84, 0xf8, 0x0a, 0x23, 0xff, 0x10, 0xa0, 0x5b, 0xf1, 0x5f, 0x7f, 0xa5, 0xac, 0xc6, 0xc0, 0xcb, 0x46, 0x2c, 0x33, 0xca, 0x52, 0x4f, 0xa6, 0xb8, 0xbb, 0x35, 0x90, 0x43, 0xba, 0x68, 0x60, 0x9e, 0xaa, 0x25, 0x36, 0xe8, 0x1d, 0x08, 0x46, 0x3b, 0x19, 0x65, 0x3b, 0x54, 0x35, 0xba, 0x94, 0x6c, 0x9a, 0xdd, 0xeb, 0x20, 0x2b, 0x04, 0xb0, 0x31, 0xcc, 0x96, 0x0d, 0xcc, 0x12, 0xe4, 0x51, 0x8d, 0x42, 0x8b, 0x32, 0xb2, 0x57, 0xa4, 0xfc, 0x73, 0x13, 0xd3, 0xa7, 0x98, 0x0d, 0x80, 0x08, 0x2e, 0x93, 0x4f, 0x9d, 0x95, 0xc3, 0x2b, 0x0a, 0x01, 0x91, 0xa2, 0x36, 0x04, 0x38, 0x4d, 0xd9, 0xe0, 0x79, 0xbb, 0xba, 0xa2, 0x66, 0xd1, 0x4c, 0x3f, 0x75, 0x6b, 0x9f, 0x21, 0x33, 0x10, 0x74, 0x33, 0xa4, 0xe8, 0x3f, 0xa7, 0x18, 0x72, 0x82, 0xa8, 0x09, 0x20, 0x3a, 0x4f, 0xaf, 0x84, 0x18, 0x51, 0x83, 0x3d, 0x12, 0x1a, 0xc3, 0x83, 0x84, 0x3a, 0x5e, 0x55, 0xbc, 0x23, 0x81, 0x42, 0x5e, 0x16, 0xc7, 0xdb, 0x4c, 0xc9, 0xab, 0x5c, 0x1b, 0x0d, 0x91, 0xa4, 0x7e, 0x2b, 0x8d, 0xe0, 0xe5, 0x82, 0xc8, 0x6b, 0x6b, 0x0d, 0x90, 0x7b, 0xb3, 0x60, 0xb9, 0x7f, 0x40, 0xab, 0x5d, 0x03, 0x8f, 0x6b, 0x75, 0xc8, 0x14, 0xb2, 0x7d, 0x9b, 0x96, 0x8d, 0x41, 0x98, 0x32, 0xbc, 0x8c, 0x2b, 0xee, 0x60, 0x5e, 0xf6, 0xe5, 0x05, 0x9d, 0x33, 0x10, 0x0d, 0x90, 0x48, 0x5d, 0x37, 0x84, 0x50, 0x01, 0x42, 0x21, 0x73, 0x6c, 0x07, 0x40, 0x7c, 0xac, 0x26, 0x04, 0x08, 0xaa, 0x64, 0x92, 0x66, 0x19, 0x78, 0x8b, 0x86, 0x01, 0xc2, 0xa7, 0x52, 0xd1, 0xa6, 0xcb, 0xf8, 0x20, 0xd7, 0xc7, 0xa0, 0x47, 0x16, 0x20, 0x32, 0x25, 0xb3, 0x89, 0x5b, 0x93, 0x42, 0xd1, 0x47, 0xa8, 0x18, 0x5c, 0xfc, 0x1b, 0xb6, 0x5b, 0xa0, 0x6b, 0x41, 0x42, 0x33, 0x99, 0x03, 0xc0, 0xac, 0x46, 0x51, 0x38, 0x5b, 0x45, 0xd9, 0x8a, 0x8b, 0x19, 0xd2, 0x8c, 0xd6, 0xba, 0xb0, 0x88, 0x78, 0x7f, 0x7e, 0xe1, 0xb1, 0x24, 0x61, 0x76, 0x6b, 0x43, 0xcb, 0xcc, 0xb9, 0x64, 0x34, 0x42, 0x7d, 0x93, 0xc0, 0x65, 0x55, 0x06, 0x88, 0xf6, 0x94, 0x8e, 0xd1, 0xb5, 0x47, 0x5a, 0x42, 0x5f, 0x1b, 0x85, 0x20, 0x9d, 0x06, 0x1c, 0x08, 0xb5, 0x6c, 0x1c, 0xc0, 0x69, 0xf6, 0xc0, 0xa7, 0xc6, 0xf2, 0x93, 0x58, 0xca, 0xb9, 0x11, 0x08, 0x77, 0x32, 0xa6, 0x49, 0xd2, 0x7c, 0x9b, 0x98, 0xf9, 0xa4, 0x88, 0x79, 0x38, 0x7d, 0x9b, 0x00, 0xc2, 0x59, 0x59, 0xa7, 0x16, 0x54, 0xd6, 0xf6, 0xa9, 0x46, 0x16, 0x45, 0x13, 0xe4, 0x7a, 0x75, 0xd0, 0x05, 0x98, 0x6c, 0x23, 0x63, 0xc0, 0x9f, 0x6b, 0x53, 0x7e, 0xca, 0x78, 0xb9, 0x30, 0x3a, 0x5f, 0xa4, 0x57, 0x60, 0x8a, 0x58, 0x6a, 0x65, 0x3a, 0x34, 0x7d, 0xb0, 0x4d, 0xfc, 0xc1, 0x91, 0x75, 0xb3, 0xa3, 0x01, 0x17, 0x25, 0x36, 0x06, 0x2a, 0x65, 0x8a, 0x95, 0x27, 0x75, 0x70, 0xc8, 0x85, 0x2c, 0xa8, 0x97, 0x3f, 0x4a, 0xe1, 0x23, 0xa3, 0x34, 0x04, 0x7d, 0xd7, 0x11, 0xc8, 0x92, 0x7a, 0x63, 0x4a, 0x03, 0x38, 0x8a, 0x52, 0x7b, 0x03, 0x4b, 0xf7, 0xa8, 0x17, 0x0f, 0xa7, 0x02, 0xc1, 0xf7, 0xc2, 0x3e, 0xc3, 0x2d, 0x18, 0xa2, 0x37, 0x48, 0x90, 0xbe, 0x9c, 0x78, 0x7a, 0x94, 0x09, 0xc8, 0x2d, 0x19, 0x2c, 0x4b, 0xb7, 0x05, 0xa2, 0xf9, 0x96, 0xce, 0x40, 0x5d, 0x85, 0xa4, 0xc1, 0xa1, 0xab, 0x9b, 0x6a, 0xeb, 0x49, 0xcc, 0xe1, 0xc2, 0xf8, 0xa9, 0x7c, 0x35, 0x16, 0xc7, 0x2a, 0x00, 0xa4, 0x62, 0x63, 0xba, 0xa6, 0x96, 0xbf, 0x25, 0x72, 0x77, 0x19, 0xc3, 0x21, 0x64, 0x23, 0x61, 0x8f, 0xf3, 0x33, 0x80, 0x93, 0x4a, 0x6c, 0x10, 0x54, 0x5c, 0x4c, 0x5c, 0x51, 0x55, 0xb1, 0x24, 0x86, 0x18, 0x1f, 0xc7, 0xa2, 0x31, 0x98, 0x73, 0x97, 0x8b, 0x6a, 0x2a, 0x67, 0x49, 0x0f, 0x82, 0x56, 0xbd, 0x21, 0x96, 0xfe, 0x17, 0x92, 0xa4, 0xc0, 0x00, 0x77, 0xb8, 0x12, 0xea, 0xe8, 0xbe, 0xd3, 0x57, 0x24, 0x99, 0x68, 0x4a, 0xb3, 0x37, 0x18, 0x76, 0x76, 0x1e, 0x45, 0x0c, 0x9f, 0x9d, 0x27, 0x68, 0xa3, 0x68, 0x06, 0xd7, 0xab, 0x20, 0x46, 0xc9, 0x1f, 0x17, 0x59, 0x9e, 0x9a, 0xc5, 0x92, 0x99, 0x08, 0x08, 0xdc, 0xd7, 0xb4, 0xd0, 0x91, 0x90, 0x72, 0xf1, 0x4e, 0xc3, 0x61, 0x77, 0x3b, 0x72, 0x52, 0x44, 0x4c, 0x32, 0x3c, 0x30, 0x83, 0x26, 0xf4, 0xa3, 0x0f, 0x86, 0x80, 0xd2, 0xf7, 0x48, 0xf5, 0x6a, 0x13, 0x2b, 0x82, 0x67, 0x4e, 0xd0, 0x18, 0x46, 0x20, 0xb8, 0x2a, 0xd2, 0xcb, 0x18, 0x2c, 0x97, 0xb4, 0x81, 0x62, 0x66, 0x47, 0x49, 0x12, 0x90, 0xa0, 0x11, 0xcc, 0x73, 0x82, 0x86, 0x85, 0xa8, 0xc3, 0x67, 0xa5, 0xb9, 0xcf, 0x8d, 0x62, 0x1b, 0x0d, 0x5c, 0x1e, 0xff, 0x03, 0x17, 0x27, 0x58, 0xbd, 0x00, 0x49, 0x78, 0xc2, 0x51, 0xcd, 0x51, 0x34, 0x22, 0x28, 0x98, 0x9c, 0xae, 0x63, 0x32, 0xac, 0x48, 0x64, 0x37, 0xcb, 0x5c, 0x57, 0xd4, 0x30, 0x74, 0x62, 0x86, 0x52, 0x53, 0xbe, 0x21, 0x7b, 0x35, 0x15, 0xc7, 0x3d, 0xf4, 0x05, 0xb7, 0xf2, 0x82, 0x17, 0xad, 0x0b, 0x8c, 0xf6, 0x0c, 0x2f, 0xff, 0xaa, 0x0a, 0x00, 0x48, 0xb1, 0xfb, 0x4a, 0xcd, 0xcd, 0xc3, 0x8b, 0x52, 0x50, 0xcf, 0xec, 0x35, 0x6a, 0x6d, 0xe2, 0x6c, 0xfa, 0x7a, 0x58, 0x8f, 0xdc, 0x86, 0xf9, 0x8c, 0x85, 0x4a, 0xc6, 0x4c, 0x7b, 0xfa, 0xa9, 0x6f, 0x5a, 0x32, 0xcc, 0x06, 0x10, 0x93, 0x4b, 0xaa, 0x6a, 0x58, 0x6b, 0x9a, 0x20, 0x54, 0xf1, 0x3b, 0xa2, 0x74, 0x17, 0x4a, 0xa0, 0xd2, 0xb3, 0xa8, 0x1b, 0x96, 0xa9, 0x40, 0x66, 0x6f, 0x78, 0x9b, 0x5a, 0x6b, 0xcd, 0xc0, 0xa6, 0xa0, 0x17, 0x8a, 0x0c, 0x9a, 0x02, 0x57, 0x8a, 0x49, 0x3f, 0x6e, 0xea, 0x0d, 0x2e, 0x6c, 0x13, 0x95, 0x1c, 0x9f, 0x24, 0x9a, 0x5e, 0x8d, 0xd7, 0x1d, 0xd4, 0x9a, 0x74, 0x2d, 0x45, 0x1f, 0x1a, 0xbb, 0xa1, 0x9a, 0xf8, 0xc5, 0x47, 0x85, 0x5e, 0x0a, 0xfc, 0x72, 0x8e, 0x90, 0xab, 0xb4, 0x99, 0xc9, 0xbe, 0xeb, 0x76, 0x6f, 0x47, 0x29, 0xcd, 0xa2, 0x22, 0x63, 0xe3, 0x24, 0xda, 0x18, 0x71, 0x2d, 0x31, 0x6e, 0x98, 0xdc, 0x7a, 0xc8, 0xc3, 0xca, 0x47, 0x37, 0x0e, 0xbd, 0x77, 0x0c, 0xe3, 0x2b, 0x3b, 0xd4, 0xb1, 0xa0, 0xc9, 0x52, 0x9a, 0xc6, 0xec, 0x8e, 0xe0, 0x28, 0xb1, 0xcd, 0xb2, 0x65, 0x1c, 0xb5, 0xa6, 0xbb, 0x3c, 0x0c, 0x6d, 0xf1, 0x24, 0x0a, 0x3b, 0x91, 0x4b, 0x56, 0x56, 0xc0, 0xdc, 0x51, 0xc2, 0xb9, 0x1b, 0xfc, 0xbc, 0x37, 0xa4, 0x66, 0x02, 0x87, 0xd4, 0x4f, 0x81, 0xf8, 0x53, 0xc7, 0xf4, 0x9a, 0x6d, 0x06, 0x03, 0xd6, 0xd7, 0x23, 0xcb, 0xec, 0x01, 0x5f, 0xbc, 0x43, 0x4a, 0x38, 0x24, 0x1c, 0x10, 0x9c, 0x7e, 0xd5, 0xb1, 0xcc, 0x46, 0x1a, 0x2c, 0xcb, 0x9a, 0xb7, 0x14, 0x0f, 0x19, 0xf3, 0x7a, 0x13, 0xbb, 0x70, 0x1e, 0x14, 0x2b, 0xd5, 0x4b, 0x64, 0xec, 0x6b, 0x76, 0xfe, 0xc3, 0x3b, 0x69, 0xc2, 0x91, 0x8c, 0xb0, 0x17, 0xc4, 0x14, 0x34, 0x23, 0x00, 0x9a, 0x3c, 0x07, 0xb5, 0xc1, 0x81, 0xb0, 0xc1, 0xeb, 0x49, 0x4a, 0x62, 0xab, 0xc8, 0x39, 0x13, 0x97, 0x08, 0x9e, 0xa6, 0x64, 0x09, 0x67, 0xc1, 0x20, 0x49, 0x84, 0xcd, 0x48, 0x4c, 0xcc, 0xb0, 0x0a, 0x9a, 0x17, 0xd0, 0x87, 0x21, 0x84, 0x28, 0xef, 0x3b, 0xb7, 0x08, 0x78, 0x3e, 0x12, 0x82, 0x71, 0x04, 0x41, 0x73, 0x75, 0xb6, 0x95, 0x6f, 0xb5, 0x00, 0x53, 0xd0, 0x48, 0xa4, 0x79, 0x14, 0x95, 0x82, 0x4a, 0x34, 0x80, 0xa5, 0xb7, 0x83, 0x02, 0x56, 0x09, 0x6f, 0xdd, 0x72, 0x5c, 0x30, 0x8b, 0x3b, 0xe8, 0x4a, 0x07, 0xf3, 0x63, 0x2e, 0x24, 0x95, 0xc6, 0x2e, 0x96, 0x39, 0x9d, 0x80, 0xbf, 0xa7, 0x45, 0xb9, 0x84, 0x1a, 0x18, 0x33, 0xbc, 0x1d, 0x27, 0xba, 0x45, 0xa5, 0x21, 0x68, 0xee, 0x59, 0x00, 0x6c, 0x3a, 0x3a, 0x8c, 0x4a, 0x5a, 0x4f, 0x50, 0x88, 0xfc, 0x73, 0x71, 0x81, 0xab, 0x51, 0x96, 0xf7, 0xb1, 0xb4, 0x9a, 0x2e, 0xd8, 0x13, 0x13, 0x4e, 0x11, 0x2f, 0x73, 0x0b, 0x99, 0x1c, 0x54, 0xa7, 0x19, 0x6b, 0xcf, 0x5f, 0xc7, 0x6e, 0x13, 0x4c, 0x58, 0x43, 0xe1, 0x69, 0x88, 0x51, 0xb2, 0xf8, 0x69, 0xaf, 0xaf, 0xb0, 0x27, 0x87, 0xd9, 0xc2, 0xf1, 0x36, 0x90, 0x2d, 0xc7, 0xa7, 0xf3, 0xd6, 0x21, 0x56, 0xd1, 0x5e, 0xc3, 0x09, 0x56, 0x40, 0x92, 0xc6, 0x1d, 0x83, 0xb0, 0x98, 0x6c, 0x48, 0x40, 0x99, 0x81, 0xf3, 0xc1, 0x86, 0x88, 0x0a, 0x2f, 0x63, 0xd5, 0x86, 0x0a, 0xb6, 0x01, 0xde, 0xac, 0x2b, 0x6b, 0xa1, 0xb4, 0x28, 0x17, 0x9d, 0x73, 0x53, 0x3e, 0xb7, 0xa3, 0xa5, 0x11, 0x3b, 0x85, 0x61, 0xf1, 0x0b, 0x45, 0xc3, 0xcd, 0xe2, 0x82, 0xb6, 0xea, 0xd6, 0xab, 0x6c, 0x60, 0x4f, 0x09, 0xc1, 0x7b, 0xfd, 0xa0, 0x83, 0x13, 0xa3, 0x26, 0x07, 0x67, 0x5a, 0xdf, 0x64, 0x31, 0xca, 0x87, 0x18, 0xe9, 0xc4, 0x3a, 0x73, 0x73, 0x32, 0x27, 0xe7, 0x3b, 0xc6, 0x1a, 0xc8, 0x45, 0xba, 0x90, 0x77, 0x55, 0xce, 0xc6, 0x89, 0x25, 0xe5, 0xe2, 0xbf, 0xe9, 0x12, 0x95, 0x9d, 0xb8, 0x6f, 0xbf, 0xe2, 0x15, 0x6f, 0xd5, 0xbb, 0xdb, 0xf0, 0xc9, 0xdf, 0x8b, 0x53, 0x02, 0xaa, 0x8d, 0x90, 0xa2, 0x2d, 0x12, 0x27, 0x0e, 0x00, 0x65, 0x51, 0xe4, 0x76, 0x7e, 0x45, 0x26, 0x8e, 0xd9, 0x69, 0x26, 0x54, 0x44, 0x78, 0x11, 0xea, 0xb8, 0x4f, 0x04, 0x99, 0xa8, 0xa5, 0x8c, 0xf7, 0xc0, 0x4a, 0x59, 0x56, 0x98, 0x52, 0x80, 0x45, 0xf2, 0x98, 0x97, 0xc8, 0xfa, 0x96, 0xd0, 0x6c, 0xce, 0x51, 0xe6, 0xaf, 0xea, 0xc4, 0x33, 0x95, 0x89, 0xc9, 0x41, 0xc8, 0x55, 0x63, 0xd7, 0x0f, 0xac, 0xe1, 0x92, 0x88, 0x94, 0xba, 0xc0, 0x36, 0x19, 0xdf, 0xf4, 0xbe, 0x3f, 0x43, 0x14, 0xa3, 0xf7, 0x35, 0x1a, 0x09, 0xa4, 0x86, 0xb5, 0x04, 0x1e, 0x7c, 0xb2, 0xda, 0x8b, 0x96, 0xbc, 0x66, 0x26, 0xa4, 0x93, 0x17, 0x35, 0x7c, 0x41, 0x52, 0xa5, 0x1b, 0xa3, 0xc2, 0x8c, 0x7e, 0x0c, 0x9d, 0xb4, 0x1a, 0x06, 0xa2, 0x82, 0x90, 0xf2, 0x18, 0x73, 0x11, 0x07, 0xc9, 0x54, 0xd8, 0xa6, 0x6f, 0x80, 0x1d, 0x7d, 0xe1, 0x2a, 0x03, 0x71, 0x16, 0x99, 0x0b, 0x6c, 0x53, 0xc1, 0x29, 0xf1, 0x85, 0xc3, 0x45, 0xf2, 0x7e, 0x51, 0x8b, 0x2d, 0x5a, 0x91, 0x25, 0xa0, 0x70, 0x76, 0xd9, 0x91, 0xb7, 0xda, 0xc7, 0xcc, 0x65, 0xa8, 0x56, 0x2e, 0xfb, 0xcc, 0x32, 0xa9, 0xca, 0x4a, 0xd9, 0x02, 0x63, 0xb0, 0x4a, 0x4f, 0x90, 0x36, 0x11, 0x6c, 0x7b, 0x97, 0x48, 0x04, 0x96, 0x31, 0x75, 0x75, 0x65, 0x0d, 0xcc, 0x21, 0x52, 0xb5, 0xbc, 0x0e, 0x74, 0x40, 0x7e, 0x12, 0xfa, 0x8e, 0x4f, 0xfc, 0xcc, 0xff, 0x76, 0xc0, 0x1a, 0x97, 0x4b, 0xd6, 0x11, 0x02, 0xe1, 0xf5, 0x29, 0x64, 0x96, 0xc7, 0x1d, 0x07, 0x64, 0xe1, 0x32, 0x29, 0xff, 0xe7, 0x84, 0x6f, 0x33, 0x6e, 0x34, 0xca, 0xc9, 0x04, 0xca, 0x56, 0x70, 0xf8, 0xcd, 0x50, 0x52, 0x42, 0x7a, 0x79, 0xc0, 0x91, 0xa9, 0x71, 0x21, 0x0c, 0x5c, 0xff, 0x66, 0x7a, 0xac, 0x24, 0x93, 0x66, 0xe1, 0x0d, 0x2b, 0x11, 0x37, 0x6c, 0xa3, 0x9d, 0x93, 0x52, 0x04, 0xb1, 0x2c, 0xc5, 0x85, 0xe9, 0x40, 0x54, 0x03, 0x62, 0x5f, 0xb3, 0x2c, 0xb5, 0xe5, 0xc3, 0x1b, 0x62, 0x34, 0x81, 0x60, 0x51, 0x5c, 0xcc, 0x4f, 0xda, 0xf5, 0x70, 0x2d, 0x6b, 0xab, 0x5c, 0x37, 0x3d, 0xb6, 0xf3, 0x50, 0xd3, 0xe6, 0x3a, 0x5c, 0xe3, 0xca, 0x54, 0x74, 0xa0, 0xcf, 0x15, 0x67, 0x04, 0x2c, 0xa3, 0x25, 0x89, 0x86, 0xff, 0x75, 0xbd, 0xfc, 0xd9, 0x29, 0xe6, 0x46, 0x2f, 0x36, 0xbc, 0xcc, 0x3f, 0x5a, 0x93, 0x35, 0x2a, 0x2b, 0x36, 0xcb, 0x16, 0x2e, 0x18, 0x74, 0xc7, 0x42, 0x87, 0x0a, 0x97, 0xb1, 0x67, 0xa0, 0x50, 0x37, 0x36, 0x24, 0xea, 0xeb, 0x7e, 0x50, 0x73, 0x25, 0x6b, 0x72, 0x11, 0xb2, 0xd9, 0x4b, 0x84, 0x06, 0xcd, 0x6c, 0x95, 0x33, 0xb1, 0x53, 0x64, 0x08, 0xab, 0x0a, 0x29, 0xe5, 0xb2, 0xf0, 0xc9, 0x54, 0xec, 0xe0, 0x0f, 0xbb, 0xeb, 0x17, 0x6d, 0x72, 0x4d, 0x4c, 0xf4, 0x43, 0xcf, 0x70, 0x20, 0xd5, 0xfa, 0x70, 0x94, 0xcc, 0x1b, 0x1b, 0xe6, 0x97, 0xba, 0xd3, 0x36, 0x74, 0xe4, 0x09, 0x9e, 0xc7, 0xbb, 0x18, 0xf4, 0x57, 0x71, 0x28, 0xcd, 0xd9, 0x7c, 0xcd, 0x6d, 0x44, 0x62, 0xe5, 0x60, 0x7c, 0x51, 0x2a, 0x3e, 0x36, 0x24, 0x8e, 0x3d, 0xda, 0xa2, 0xec, 0x08, 0x9a, 0xef, 0xc4, 0xce, 0x48, 0x5c, 0x49, 0xd7, 0xb0, 0x09, 0xc8, 0xd6, 0x31, 0x15, 0xfc, 0x81, 0xff, 0x3a, 0x62, 0xd1, 0x5a, 0x88, 0x44, 0x1c, 0x03, 0xea, 0x1c, 0x2e, 0x72, 0xc4, 0x88, 0x39, 0xfc, 0x6a, 0xd7, 0x3a, 0x30, 0x74, 0x4a, 0x62, 0xb7, 0xb2, 0x16, 0x45, 0xa6, 0xaf, 0x7d, 0x61, 0xb6, 0x38, 0x3b, 0x22, 0x1e, 0x21, 0x90, 0x55, 0x57, 0xcd, 0x29, 0xd9, 0x24, 0xa6, 0x09, 0x86, 0xc5, 0x11, 0xc1, 0xeb, 0xbc, 0x31, 0x6d, 0x56, 0x30, 0xa2, 0x41, 0x43, 0x23, 0xf5, 0x3a, 0xd5, 0x59, 0x94, 0xf6, 0xb3, 0x65, 0x39, 0xf9, 0xc4, 0x40, 0x75, 0xa5, 0x33, 0xe4, 0x81, 0xc0, 0x84, 0x45, 0xd9, 0xca, 0x9e, 0x9d, 0x38, 0x21, 0x19, 0x38, 0x8b, 0xd1, 0xd7, 0x50, 0x52, 0x21, 0x7a, 0x94, 0x4c, 0xcc, 0x7b, 0xe9, 0x09, 0xe2, 0x19, 0x71, 0x1f, 0xcc, 0x79, 0x24, 0x76, 0x92, 0x13, 0xa1, 0x92, 0x53, 0x4a, 0x55, 0x80, 0x08, 0x15, 0x7a, 0x39, 0x6e, 0xdf, 0xf4, 0x80, 0xcc, 0x3b, 0x52, 0x0f, 0xf8, 0x18, 0xb3, 0x8b, 0x13, 0x5c, 0x18, 0xa8, 0x0d, 0x51, 0x05, 0xe6, 0x78, 0x83, 0x6c, 0x39, 0x5c, 0x28, 0xe9, 0x2f, 0x7a, 0x3c, 0x4e, 0x93, 0xc0, 0x10, 0x35, 0xf3, 0x41, 0x11, 0xcc, 0x49, 0x02, 0xd0, 0xc0, 0x33, 0xa6, 0x3f, 0x23, 0x6a, 0x71, 0xda, 0x97, 0x4a, 0x6f, 0x40, 0x4f, 0x7a, 0xa7, 0xb5, 0xe5, 0x82, 0xc7, 0x58, 0x14, 0x2f, 0xc1, 0x82, 0x6b, 0xba, 0x98, 0xb2, 0x7d, 0x57, 0xc2, 0xe2, 0x10, 0x3e, 0x10, 0xe3, 0x0d, 0x32, 0x79, 0x7b, 0x96, 0x77, 0x14, 0xd1, 0x56, 0x61, 0x11, 0x13, 0x71, 0xa2, 0xd9, 0xc5, 0x39, 0x98, 0x12, 0x46, 0x46, 0x22, 0x63, 0x5b, 0x44, 0x21, 0x26, 0xb0, 0x98, 0x36, 0xb0, 0x81, 0x82, 0x72, 0x47, 0xd0, 0x54, 0x22, 0x97, 0x2b, 0xd0, 0x32, 0x0d, 0x8f, 0x42, 0xbf, 0x57, 0xe3, 0x49, 0x46, 0x12, 0x34, 0xe4, 0xd9, 0x4f, 0x01, 0x18, 0x50, 0xba, 0xb5, 0xc0, 0x49, 0xb6, 0x2a, 0x59, 0x43, 0x38, 0x66, 0xfc, 0xce, 0x69, 0x66, 0x49, 0x5c, 0x26, 0x5c, 0x47, 0x65, 0xa5, 0x6c, 0x06, 0xb9, 0xfc, 0x42, 0x76, 0x54, 0x87, 0x85, 0xf4, 0x68, 0x28, 0xca, 0x60, 0x2d, 0xc6, 0xd0, 0x54, 0x1f, 0x25, 0x07, 0x89, 0xc4, 0x9e, 0x8b, 0x06, 0x55, 0x9c, 0x43, 0x44, 0x60, 0xa8, 0x43, 0x80, 0x98, 0x54, 0xe5, 0xb4, 0x6e, 0x89, 0x38, 0x9f, 0x10, 0xf4, 0x89, 0x66, 0x74, 0x91, 0xc1, 0x93, 0x5e, 0x8a, 0xfb, 0x9e, 0xb4, 0x71, 0x8f, 0x86, 0xac, 0x45, 0x89, 0x32, 0xbc, 0xf3, 0x3c, 0x9a, 0xbe, 0xcb, 0x2d, 0xc0, 0xc0, 0x93, 0xa7, 0xe8, 0x1d, 0xa0, 0x32, 0x7b, 0xb6, 0x37, 0x52, 0x81, 0x05, 0xc3, 0x58, 0xeb, 0x76, 0x8d, 0x32, 0x3a, 0x37, 0xd4, 0x0a, 0x8c, 0x19, 0x9b, 0x7c, 0x4b, 0xb1, 0xd7, 0x2b, 0x72, 0xb6, 0x90, 0xb3, 0x6d, 0xd2, 0x7a, 0x93, 0x55, 0x19, 0x1b, 0x3c, 0x3a, 0xa6, 0x75, 0xa7, 0xe6, 0xf8, 0x55, 0xeb, 0x50, 0x5f, 0x57, 0x98, 0x65, 0xdb, 0xd8, 0x91, 0x05, 0x65, 0x50, 0x5e, 0x7c, 0x0f, 0xdd, 0x54, 0x5c, 0xbb, 0xb8, 0x71, 0xb0, 0xb2, 0xcc, 0x01, 0x25, 0xb7, 0x4f, 0x6b, 0x0c, 0x9b, 0x79, 0x67, 0x0a, 0x62, 0x02, 0xd1, 0xb9, 0x15, 0x4a, 0xc7, 0x76, 0x6b, 0x19, 0x19, 0xc4, 0x89, 0x58, 0x90, 0x86, 0xad, 0x8b, 0x45, 0xbe, 0x0d, 0x79, 0xc9, 0x76, 0xc3, 0xc3, 0x9d, 0x6b, 0x25, 0x21, 0x3b, 0xb0, 0xb7, 0x8a, 0x57, 0x50, 0xe6, 0xa8, 0xeb, 0x34, 0x33, 0x0b, 0xb3, 0xcf, 0xf2, 0xb1, 0xc0, 0x72, 0x2a, 0xc8, 0x83, 0xb0, 0x48, 0xf4, 0xb8, 0xcd, 0x06, 0x19, 0x6d, 0xa8, 0xaa, 0x8b, 0x05, 0xda, 0x42, 0x67, 0x55, 0x2b, 0xf8, 0x7a, 0xbc, 0xa5, 0x12, 0x4d, 0xc3, 0x58, 0xa8, 0x38, 0x10, 0x40, 0xe9, 0xb8, 0x1f, 0xb0, 0x84, 0x43, 0x15, 0x02, 0x15, 0xd6, 0x92, 0x23, 0x28, 0x00, 0x0a, 0xc0, 0xb7, 0x88, 0xb1, 0x21, 0x93, 0x1a, 0x26, 0x7d, 0x80, 0x61, 0x9c, 0xe7, 0xd2, 0x9c, 0xd7, 0x6b, 0x60, 0xcf, 0x65, 0x83, 0xdc, 0xe8, 0xce, 0xbc, 0x49, 0x01, 0x85, 0x73, 0x6c, 0x81, 0x8b, 0x25, 0xad, 0x26, 0x0b, 0x66, 0x7b, 0x1f, 0xfd, 0x46, 0x20, 0x6d, 0x01, 0x04, 0x55, 0x3a, 0xa9, 0xfb, 0x30, 0x45, 0x54, 0xa2, 0x1c, 0x32, 0x72, 0x44, 0xce, 0x78, 0xaf, 0xdb, 0xd3, 0xb4, 0x62, 0x36, 0x1b, 0xb0, 0x68, 0xa1, 0x55, 0x63, 0x64, 0x09, 0xf5, 0x74, 0xc5, 0x71, 0x65, 0x72, 0xe2, 0xa5, 0xf2, 0xa4, 0xb0, 0x4f, 0xb8, 0xaa, 0xd1, 0x23, 0x66, 0x84, 0x84, 0x17, 0x87, 0x56, 0x2a, 0xaf, 0x46, 0xc2, 0xc0, 0xda, 0x46, 0x65, 0xea, 0xfd, 0x46, 0x5f, 0xc6, 0x4a, 0x0c, 0x5f, 0x8f, 0x3f, 0x90, 0x03, 0x48, 0x94, 0x15, 0x89, 0x9d, 0x59, 0xa5, 0x43, 0xd8, 0x20, 0x8c, 0x54, 0xa3, 0x16, 0x65, 0x29, 0xb5, 0x39, 0x22, 0xa5, 0x89, 0x9a, 0x0b, 0xc4, 0x65, 0xee, 0x5f, 0xc2, 0xc0, 0x41, 0x55, 0x58, 0x2a, 0x40, 0xac, 0x70, 0x97, 0x61, 0xd2, 0xbe, 0x61, 0xfd, 0xc7, 0x6c, 0x59, 0x30, 0x44, 0xce, 0xbc, 0xc7, 0xf2, 0x86, 0x26, 0xed, 0x79, 0xd4, 0x51, 0x14, 0x08, 0x00, 0xe0, 0x3b, 0x59, 0xb9, 0x56, 0xf8, 0x21, 0x0e, 0x55, 0x60, 0x67, 0x40, 0x7d, 0x13, 0xdc, 0x90, 0xfa, 0x9e, 0x8b, 0x87, 0x2b, 0xfb, 0x8f, 0xa0, 0x82, 0x06, 0x65, 0x03, 0x82, 0x06, 0x61, 0x00, 0xda, 0x18, 0x71, 0x2d, 0x31, 0x6e, 0x98, 0xdc, 0x7a, 0xc8, 0xc3, 0xca, 0x47, 0x37, 0x0e, 0xbd, 0x77, 0x0c, 0xe3, 0x2b, 0x3b, 0xd4, 0xb1, 0xa0, 0xc9, 0x52, 0x9a, 0xc6, 0xec, 0x8e, 0xe0, 0x28, 0xb1, 0xcd, 0xb2, 0x65, 0x1c, 0xb5, 0xa6, 0xbb, 0x3c, 0x0c, 0x6d, 0xf1, 0x24, 0x0a, 0x3b, 0x91, 0x4b, 0x56, 0x56, 0xc0, 0xdc, 0x51, 0xc2, 0xb9, 0x1b, 0xfc, 0xbc, 0x37, 0xa4, 0x66, 0x02, 0x87, 0xd4, 0x4f, 0x81, 0xf8, 0x53, 0xc7, 0xf4, 0x9a, 0x6d, 0x06, 0x03, 0xd6, 0xd7, 0x23, 0xcb, 0xec, 0x01, 0x5f, 0xbc, 0x43, 0x4a, 0x38, 0x24, 0x1c, 0x10, 0x9c, 0x7e, 0xd5, 0xb1, 0xcc, 0x46, 0x1a, 0x2c, 0xcb, 0x9a, 0xb7, 0x14, 0x0f, 0x19, 0xf3, 0x7a, 0x13, 0xbb, 0x70, 0x1e, 0x14, 0x2b, 0xd5, 0x4b, 0x64, 0xec, 0x6b, 0x76, 0xfe, 0xc3, 0x3b, 0x69, 0xc2, 0x91, 0x8c, 0xb0, 0x17, 0xc4, 0x14, 0x34, 0x23, 0x00, 0x9a, 0x3c, 0x07, 0xb5, 0xc1, 0x81, 0xb0, 0xc1, 0xeb, 0x49, 0x4a, 0x62, 0xab, 0xc8, 0x39, 0x13, 0x97, 0x08, 0x9e, 0xa6, 0x64, 0x09, 0x67, 0xc1, 0x20, 0x49, 0x84, 0xcd, 0x48, 0x4c, 0xcc, 0xb0, 0x0a, 0x9a, 0x17, 0xd0, 0x87, 0x21, 0x84, 0x28, 0xef, 0x3b, 0xb7, 0x08, 0x78, 0x3e, 0x12, 0x82, 0x71, 0x04, 0x41, 0x73, 0x75, 0xb6, 0x95, 0x6f, 0xb5, 0x00, 0x53, 0xd0, 0x48, 0xa4, 0x79, 0x14, 0x95, 0x82, 0x4a, 0x34, 0x80, 0xa5, 0xb7, 0x83, 0x02, 0x56, 0x09, 0x6f, 0xdd, 0x72, 0x5c, 0x30, 0x8b, 0x3b, 0xe8, 0x4a, 0x07, 0xf3, 0x63, 0x2e, 0x24, 0x95, 0xc6, 0x2e, 0x96, 0x39, 0x9d, 0x80, 0xbf, 0xa7, 0x45, 0xb9, 0x84, 0x1a, 0x18, 0x33, 0xbc, 0x1d, 0x27, 0xba, 0x45, 0xa5, 0x21, 0x68, 0xee, 0x59, 0x00, 0x6c, 0x3a, 0x3a, 0x8c, 0x4a, 0x5a, 0x4f, 0x50, 0x88, 0xfc, 0x73, 0x71, 0x81, 0xab, 0x51, 0x96, 0xf7, 0xb1, 0xb4, 0x9a, 0x2e, 0xd8, 0x13, 0x13, 0x4e, 0x11, 0x2f, 0x73, 0x0b, 0x99, 0x1c, 0x54, 0xa7, 0x19, 0x6b, 0xcf, 0x5f, 0xc7, 0x6e, 0x13, 0x4c, 0x58, 0x43, 0xe1, 0x69, 0x88, 0x51, 0xb2, 0xf8, 0x69, 0xaf, 0xaf, 0xb0, 0x27, 0x87, 0xd9, 0xc2, 0xf1, 0x36, 0x90, 0x2d, 0xc7, 0xa7, 0xf3, 0xd6, 0x21, 0x56, 0xd1, 0x5e, 0xc3, 0x09, 0x56, 0x40, 0x92, 0xc6, 0x1d, 0x83, 0xb0, 0x98, 0x6c, 0x48, 0x40, 0x99, 0x81, 0xf3, 0xc1, 0x86, 0x88, 0x0a, 0x2f, 0x63, 0xd5, 0x86, 0x0a, 0xb6, 0x01, 0xde, 0xac, 0x2b, 0x6b, 0xa1, 0xb4, 0x28, 0x17, 0x9d, 0x73, 0x53, 0x3e, 0xb7, 0xa3, 0xa5, 0x11, 0x3b, 0x85, 0x61, 0xf1, 0x0b, 0x45, 0xc3, 0xcd, 0xe2, 0x82, 0xb6, 0xea, 0xd6, 0xab, 0x6c, 0x60, 0x4f, 0x09, 0xc1, 0x7b, 0xfd, 0xa0, 0x83, 0x13, 0xa3, 0x26, 0x07, 0x67, 0x5a, 0xdf, 0x64, 0x31, 0xca, 0x87, 0x18, 0xe9, 0xc4, 0x3a, 0x73, 0x73, 0x32, 0x27, 0xe7, 0x3b, 0xc6, 0x1a, 0xc8, 0x45, 0xba, 0x90, 0x77, 0x55, 0xce, 0xc6, 0x89, 0x25, 0xe5, 0xe2, 0xbf, 0xe9, 0x12, 0x95, 0x9d, 0xb8, 0x6f, 0xbf, 0xe2, 0x15, 0x6f, 0xd5, 0xbb, 0xdb, 0xf0, 0xc9, 0xdf, 0x8b, 0x53, 0x02, 0xaa, 0x8d, 0x90, 0xa2, 0x2d, 0x12, 0x27, 0x0e, 0x00, 0x65, 0x51, 0xe4, 0x76, 0x7e, 0x45, 0x26, 0x8e, 0xd9, 0x69, 0x26, 0x54, 0x44, 0x78, 0x11, 0xea, 0xb8, 0x4f, 0x04, 0x99, 0xa8, 0xa5, 0x8c, 0xf7, 0xc0, 0x4a, 0x59, 0x56, 0x98, 0x52, 0x80, 0x45, 0xf2, 0x98, 0x97, 0xc8, 0xfa, 0x96, 0xd0, 0x6c, 0xce, 0x51, 0xe6, 0xaf, 0xea, 0xc4, 0x33, 0x95, 0x89, 0xc9, 0x41, 0xc8, 0x55, 0x63, 0xd7, 0x0f, 0xac, 0xe1, 0x92, 0x88, 0x94, 0xba, 0xc0, 0x36, 0x19, 0xdf, 0xf4, 0xbe, 0x3f, 0x43, 0x14, 0xa3, 0xf7, 0x35, 0x1a, 0x09, 0xa4, 0x86, 0xb5, 0x04, 0x1e, 0x7c, 0xb2, 0xda, 0x8b, 0x96, 0xbc, 0x66, 0x26, 0xa4, 0x93, 0x17, 0x35, 0x7c, 0x41, 0x52, 0xa5, 0x1b, 0xa3, 0xc2, 0x8c, 0x7e, 0x0c, 0x9d, 0xb4, 0x1a, 0x06, 0xa2, 0x82, 0x90, 0xf2, 0x18, 0x73, 0x11, 0x07, 0xc9, 0x54, 0xd8, 0xa6, 0x6f, 0x80, 0x1d, 0x7d, 0xe1, 0x2a, 0x03, 0x71, 0x16, 0x99, 0x0b, 0x6c, 0x53, 0xc1, 0x29, 0xf1, 0x85, 0xc3, 0x45, 0xf2, 0x7e, 0x51, 0x8b, 0x2d, 0x5a, 0x91, 0x25, 0xa0, 0x70, 0x76, 0xd9, 0x91, 0xb7, 0xda, 0xc7, 0xcc, 0x65, 0xa8, 0x56, 0x2e, 0xfb, 0xcc, 0x32, 0xa9, 0xca, 0x4a, 0xd9, 0x02, 0x63, 0xb0, 0x4a, 0x4f, 0x90, 0x36, 0x11, 0x6c, 0x7b, 0x97, 0x48, 0x04, 0x96, 0x31, 0x75, 0x75, 0x65, 0x0d, 0xcc, 0x21, 0x52, 0xb5, 0xbc, 0x0e, 0x74, 0x40, 0x7e, 0x12, 0xfa, 0x8e, 0x4f, 0xfc, 0xcc, 0xff, 0x76, 0xc0, 0x1a, 0x97, 0x4b, 0xd6, 0x11, 0x02, 0xe1, 0xf5, 0x29, 0x64, 0x96, 0xc7, 0x1d, 0x07, 0x64, 0xe1, 0x32, 0x29, 0xff, 0xe7, 0x84, 0x6f, 0x33, 0x6e, 0x34, 0xca, 0xc9, 0x04, 0xca, 0x56, 0x70, 0xf8, 0xcd, 0x50, 0x52, 0x42, 0x7a, 0x79, 0xc0, 0x91, 0xa9, 0x71, 0x21, 0x0c, 0x5c, 0xff, 0x66, 0x7a, 0xac, 0x24, 0x93, 0x66, 0xe1, 0x0d, 0x2b, 0x11, 0x37, 0x6c, 0xa3, 0x9d, 0x93, 0x52, 0x04, 0xb1, 0x2c, 0xc5, 0x85, 0xe9, 0x40, 0x54, 0x03, 0x62, 0x5f, 0xb3, 0x2c, 0xb5, 0xe5, 0xc3, 0x1b, 0x62, 0x34, 0x81, 0x60, 0x51, 0x5c, 0xcc, 0x4f, 0xda, 0xf5, 0x70, 0x2d, 0x6b, 0xab, 0x5c, 0x37, 0x3d, 0xb6, 0xf3, 0x50, 0xd3, 0xe6, 0x3a, 0x5c, 0xe3, 0xca, 0x54, 0x74, 0xa0, 0xcf, 0x15, 0x67, 0x04, 0x2c, 0xa3, 0x25, 0x89, 0x86, 0xff, 0x75, 0xbd, 0xfc, 0xd9, 0x29, 0xe6, 0x46, 0x2f, 0x36, 0xbc, 0xcc, 0x3f, 0x5a, 0x93, 0x35, 0x2a, 0x2b, 0x36, 0xcb, 0x16, 0x2e, 0x18, 0x74, 0xc7, 0x42, 0x87, 0x0a, 0x97, 0xb1, 0x67, 0xa0, 0x50, 0x37, 0x36, 0x24, 0xea, 0xeb, 0x7e, 0x50, 0x73, 0x25, 0x6b, 0x72, 0x11, 0xb2, 0xd9, 0x4b, 0x84, 0x06, 0xcd, 0x6c, 0x95, 0x33, 0xb1, 0x53, 0x64, 0x08, 0xab, 0x0a, 0x29, 0xe5, 0xb2, 0xf0, 0xc9, 0x54, 0xec, 0xe0, 0x0f, 0xbb, 0xeb, 0x17, 0x6d, 0x72, 0x4d, 0x4c, 0xf4, 0x43, 0xcf, 0x70, 0x20, 0xd5, 0xfa, 0x70, 0x94, 0xcc, 0x1b, 0x1b, 0xe6, 0x97, 0xba, 0xd3, 0x36, 0x74, 0xe4, 0x09, 0x9e, 0xc7, 0xbb, 0x18, 0xf4, 0x57, 0x71, 0x28, 0xcd, 0xd9, 0x7c, 0xcd, 0x6d, 0x44, 0x62, 0xe5, 0x60, 0x7c, 0x51, 0x2a, 0x3e, 0x36, 0x24, 0x8e, 0x3d, 0xda, 0xa2, 0xec, 0x08, 0x9a, 0xef, 0xc4, 0xce, 0x48, 0x5c, 0x49, 0xd7, 0xb0, 0x09, 0xc8, 0xd6, 0x31, 0x15, 0xfc, 0x81, 0xff, 0x3a, 0x62, 0xd1, 0x5a, 0x88, 0x44, 0x1c, 0x03, 0xea, 0x1c, 0x2e, 0x72, 0xc4, 0x88, 0x39, 0xfc, 0x6a, 0xd7, 0x3a, 0x30, 0x74, 0x4a, 0x62, 0xb7, 0xb2, 0x16, 0x45, 0xa6, 0xaf, 0x7d, 0x61, 0xb6, 0x38, 0x3b, 0x22, 0x1e, 0x21, 0x90, 0x55, 0x57, 0xcd, 0x29, 0xd9, 0x24, 0xa6, 0x09, 0x86, 0xc5, 0x11, 0xc1, 0xeb, 0xbc, 0x31, 0x6d, 0x56, 0x30, 0xa2, 0x41, 0x43, 0x23, 0xf5, 0x3a, 0xd5, 0x59, 0x94, 0xf6, 0xb3, 0x65, 0x39, 0xf9, 0xc4, 0x40, 0x75, 0xa5, 0x33, 0xe4, 0x81, 0xc0, 0x84, 0x45, 0xd9, 0xca, 0x9e, 0x9d, 0x38, 0x21, 0x19, 0x38, 0x8b, 0xd1, 0xd7, 0x50, 0x52, 0x21, 0x7a, 0x94, 0x4c, 0xcc, 0x7b, 0xe9, 0x09, 0xe2, 0x19, 0x71, 0x1f, 0xcc, 0x79, 0x24, 0x76, 0x92, 0x13, 0xa1, 0x92, 0x53, 0x4a, 0x55, 0x80, 0x08, 0x15, 0x7a, 0x39, 0x6e, 0xdf, 0xf4, 0x80, 0xcc, 0x3b, 0x52, 0x0f, 0xf8, 0x18, 0xb3, 0x8b, 0x13, 0x5c, 0x18, 0xa8, 0x0d, 0x51, 0x05, 0xe6, 0x78, 0x83, 0x6c, 0x39, 0x5c, 0x28, 0xe9, 0x2f, 0x7a, 0x3c, 0x4e, 0x93, 0xc0, 0x10, 0x35, 0xf3, 0x41, 0x11, 0xcc, 0x49, 0x02, 0xd0, 0xc0, 0x33, 0xa6, 0x3f, 0x23, 0x6a, 0x71, 0xda, 0x97, 0x4a, 0x6f, 0x40, 0x4f, 0x7a, 0xa7, 0xb5, 0xe5, 0x82, 0xc7, 0x58, 0x14, 0x2f, 0xc1, 0x82, 0x6b, 0xba, 0x98, 0xb2, 0x7d, 0x57, 0xc2, 0xe2, 0x10, 0x3e, 0x10, 0xe3, 0x0d, 0x32, 0x79, 0x7b, 0x96, 0x77, 0x14, 0xd1, 0x56, 0x61, 0x11, 0x13, 0x71, 0xa2, 0xd9, 0xc5, 0x39, 0x98, 0x12, 0x46, 0x46, 0x22, 0x63, 0x5b, 0x44, 0x21, 0x26, 0xb0, 0x98, 0x36, 0xb0, 0x81, 0x82, 0x72, 0x47, 0xd0, 0x54, 0x22, 0x97, 0x2b, 0xd0, 0x32, 0x0d, 0x8f, 0x42, 0xbf, 0x57, 0xe3, 0x49, 0x46, 0x12, 0x34, 0xe4, 0xd9, 0x4f, 0x01, 0x18, 0x50, 0xba, 0xb5, 0xc0, 0x49, 0xb6, 0x2a, 0x59, 0x43, 0x38, 0x66, 0xfc, 0xce, 0x69, 0x66, 0x49, 0x5c, 0x26, 0x5c, 0x47, 0x65, 0xa5, 0x6c, 0x06, 0xb9, 0xfc, 0x42, 0x76, 0x54, 0x87, 0x85, 0xf4, 0x68, 0x28, 0xca, 0x60, 0x2d, 0xc6, 0xd0, 0x54, 0x1f, 0x25, 0x07, 0x89, 0xc4, 0x9e, 0x8b, 0x06, 0x55, 0x9c, 0x43, 0x44, 0x60, 0xa8, 0x43, 0x80, 0x98, 0x54, 0xe5, 0xb4, 0x6e, 0x89, 0x38, 0x9f, 0x10, 0xf4, 0x89, 0x66, 0x74, 0x91, 0xc1, 0x93, 0x5e, 0x8a, 0xfb, 0x9e, 0xb4, 0x71, 0x8f, 0x86, 0xac, 0x45, 0x89, 0x32, 0xbc, 0xf3, 0x3c, 0x9a, 0xbe, 0xcb, 0x2d, 0xc0, 0xc0, 0x93, 0xa7, 0xe8, 0x1d, 0xa0, 0x32, 0x7b, 0xb6, 0x37, 0x52, 0x81, 0x05, 0xc3, 0x58, 0xeb, 0x76, 0x8d, 0x32, 0x3a, 0x37, 0xd4, 0x0a, 0x8c, 0x19, 0x9b, 0x7c, 0x4b, 0xb1, 0xd7, 0x2b, 0x72, 0xb6, 0x90, 0xb3, 0x6d, 0xd2, 0x7a, 0x93, 0x55, 0x19, 0x1b, 0x3c, 0x3a, 0xa6, 0x75, 0xa7, 0xe6, 0xf8, 0x55, 0xeb, 0x50, 0x5f, 0x57, 0x98, 0x65, 0xdb, 0xd8, 0x91, 0x05, 0x65, 0x50, 0x5e, 0x7c, 0x0f, 0xdd, 0x54, 0x5c, 0xbb, 0xb8, 0x71, 0xb0, 0xb2, 0xcc, 0x01, 0x25, 0xb7, 0x4f, 0x6b, 0x0c, 0x9b, 0x79, 0x67, 0x0a, 0x62, 0x02, 0xd1, 0xb9, 0x15, 0x4a, 0xc7, 0x76, 0x6b, 0x19, 0x19, 0xc4, 0x89, 0x58, 0x90, 0x86, 0xad, 0x8b, 0x45, 0xbe, 0x0d, 0x79, 0xc9, 0x76, 0xc3, 0xc3, 0x9d, 0x6b, 0x25, 0x21, 0x3b, 0xb0, 0xb7, 0x8a, 0x57, 0x50, 0xe6, 0xa8, 0xeb, 0x34, 0x33, 0x0b, 0xb3, 0xcf, 0xf2, 0xb1, 0xc0, 0x72, 0x2a, 0xc8, 0x83, 0xb0, 0x48, 0xf4, 0xb8, 0xcd, 0x06, 0x19, 0x6d, 0xa8, 0xaa, 0x8b, 0x05, 0xda, 0x42, 0x67, 0x55, 0x2b, 0xf8, 0x7a, 0xbc, 0xa5, 0x12, 0x4d, 0xc3, 0x58, 0xa8, 0x38, 0x10, 0x40, 0xe9, 0xb8, 0x1f, 0xb0, 0x84, 0x43, 0x15, 0x02, 0x15, 0xd6, 0x92, 0x23, 0x28, 0x00, 0x0a, 0xc0, 0xb7, 0x88, 0xb1, 0x21, 0x93, 0x1a, 0x26, 0x7d, 0x80, 0x61, 0x9c, 0xe7, 0xd2, 0x9c, 0xd7, 0x6b, 0x60, 0xcf, 0x65, 0x83, 0xdc, 0xe8, 0xce, 0xbc, 0x49, 0x01, 0x85, 0x73, 0x6c, 0x81, 0x8b, 0x25, 0xad, 0x26, 0x0b, 0x66, 0x7b, 0x1f, 0xfd, 0x46, 0x20, 0x6d, 0x01, 0x04, 0x55, 0x3a, 0xa9, 0xfb, 0x30, 0x45, 0x54, 0xa2, 0x1c, 0x32, 0x72, 0x44, 0xce, 0x78, 0xaf, 0xdb, 0xd3, 0xb4, 0x62, 0x36, 0x1b, 0xb0, 0x68, 0xa1, 0x55, 0x63, 0x64, 0x09, 0xf5, 0x74, 0xc5, 0x71, 0x65, 0x72, 0xe2, 0xa5, 0xf2, 0xa4, 0xb0, 0x4f, 0xb8, 0xaa, 0xd1, 0x23, 0x66, 0x84, 0x84, 0x17, 0x87, 0x56, 0x2a, 0xaf, 0x46, 0xc2, 0xc0, 0xda, 0x46, 0x65, 0xea, 0xfd, 0x46, 0x5f, 0xc6, 0x4a, 0x0c, 0x5f, 0x8f, 0x3f, 0x90, 0x03, 0x48, 0x94, 0x15, 0x89, 0x9d, 0x59, 0xa5, 0x43, 0xd8, 0x20, 0x8c, 0x54, 0xa3, 0x16, 0x65, 0x29, 0xb5, 0x39, 0x22, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, }, .spki_len = 1603, .spki = { 0x30, 0x82, 0x06, 0x3f, 0x30, 0x0f, 0x06, 0x0b, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x02, 0x82, 0x0b, 0x05, 0x04, 0x04, 0x05, 0x00, 0x03, 0x82, 0x06, 0x2a, 0x00, 0x30, 0x82, 0x06, 0x25, 0x03, 0x82, 0x06, 0x21, 0x00, 0xda, 0x18, 0x71, 0x2d, 0x31, 0x6e, 0x98, 0xdc, 0x7a, 0xc8, 0xc3, 0xca, 0x47, 0x37, 0x0e, 0xbd, 0x77, 0x0c, 0xe3, 0x2b, 0x3b, 0xd4, 0xb1, 0xa0, 0xc9, 0x52, 0x9a, 0xc6, 0xec, 0x8e, 0xe0, 0x28, 0xb1, 0xcd, 0xb2, 0x65, 0x1c, 0xb5, 0xa6, 0xbb, 0x3c, 0x0c, 0x6d, 0xf1, 0x24, 0x0a, 0x3b, 0x91, 0x4b, 0x56, 0x56, 0xc0, 0xdc, 0x51, 0xc2, 0xb9, 0x1b, 0xfc, 0xbc, 0x37, 0xa4, 0x66, 0x02, 0x87, 0xd4, 0x4f, 0x81, 0xf8, 0x53, 0xc7, 0xf4, 0x9a, 0x6d, 0x06, 0x03, 0xd6, 0xd7, 0x23, 0xcb, 0xec, 0x01, 0x5f, 0xbc, 0x43, 0x4a, 0x38, 0x24, 0x1c, 0x10, 0x9c, 0x7e, 0xd5, 0xb1, 0xcc, 0x46, 0x1a, 0x2c, 0xcb, 0x9a, 0xb7, 0x14, 0x0f, 0x19, 0xf3, 0x7a, 0x13, 0xbb, 0x70, 0x1e, 0x14, 0x2b, 0xd5, 0x4b, 0x64, 0xec, 0x6b, 0x76, 0xfe, 0xc3, 0x3b, 0x69, 0xc2, 0x91, 0x8c, 0xb0, 0x17, 0xc4, 0x14, 0x34, 0x23, 0x00, 0x9a, 0x3c, 0x07, 0xb5, 0xc1, 0x81, 0xb0, 0xc1, 0xeb, 0x49, 0x4a, 0x62, 0xab, 0xc8, 0x39, 0x13, 0x97, 0x08, 0x9e, 0xa6, 0x64, 0x09, 0x67, 0xc1, 0x20, 0x49, 0x84, 0xcd, 0x48, 0x4c, 0xcc, 0xb0, 0x0a, 0x9a, 0x17, 0xd0, 0x87, 0x21, 0x84, 0x28, 0xef, 0x3b, 0xb7, 0x08, 0x78, 0x3e, 0x12, 0x82, 0x71, 0x04, 0x41, 0x73, 0x75, 0xb6, 0x95, 0x6f, 0xb5, 0x00, 0x53, 0xd0, 0x48, 0xa4, 0x79, 0x14, 0x95, 0x82, 0x4a, 0x34, 0x80, 0xa5, 0xb7, 0x83, 0x02, 0x56, 0x09, 0x6f, 0xdd, 0x72, 0x5c, 0x30, 0x8b, 0x3b, 0xe8, 0x4a, 0x07, 0xf3, 0x63, 0x2e, 0x24, 0x95, 0xc6, 0x2e, 0x96, 0x39, 0x9d, 0x80, 0xbf, 0xa7, 0x45, 0xb9, 0x84, 0x1a, 0x18, 0x33, 0xbc, 0x1d, 0x27, 0xba, 0x45, 0xa5, 0x21, 0x68, 0xee, 0x59, 0x00, 0x6c, 0x3a, 0x3a, 0x8c, 0x4a, 0x5a, 0x4f, 0x50, 0x88, 0xfc, 0x73, 0x71, 0x81, 0xab, 0x51, 0x96, 0xf7, 0xb1, 0xb4, 0x9a, 0x2e, 0xd8, 0x13, 0x13, 0x4e, 0x11, 0x2f, 0x73, 0x0b, 0x99, 0x1c, 0x54, 0xa7, 0x19, 0x6b, 0xcf, 0x5f, 0xc7, 0x6e, 0x13, 0x4c, 0x58, 0x43, 0xe1, 0x69, 0x88, 0x51, 0xb2, 0xf8, 0x69, 0xaf, 0xaf, 0xb0, 0x27, 0x87, 0xd9, 0xc2, 0xf1, 0x36, 0x90, 0x2d, 0xc7, 0xa7, 0xf3, 0xd6, 0x21, 0x56, 0xd1, 0x5e, 0xc3, 0x09, 0x56, 0x40, 0x92, 0xc6, 0x1d, 0x83, 0xb0, 0x98, 0x6c, 0x48, 0x40, 0x99, 0x81, 0xf3, 0xc1, 0x86, 0x88, 0x0a, 0x2f, 0x63, 0xd5, 0x86, 0x0a, 0xb6, 0x01, 0xde, 0xac, 0x2b, 0x6b, 0xa1, 0xb4, 0x28, 0x17, 0x9d, 0x73, 0x53, 0x3e, 0xb7, 0xa3, 0xa5, 0x11, 0x3b, 0x85, 0x61, 0xf1, 0x0b, 0x45, 0xc3, 0xcd, 0xe2, 0x82, 0xb6, 0xea, 0xd6, 0xab, 0x6c, 0x60, 0x4f, 0x09, 0xc1, 0x7b, 0xfd, 0xa0, 0x83, 0x13, 0xa3, 0x26, 0x07, 0x67, 0x5a, 0xdf, 0x64, 0x31, 0xca, 0x87, 0x18, 0xe9, 0xc4, 0x3a, 0x73, 0x73, 0x32, 0x27, 0xe7, 0x3b, 0xc6, 0x1a, 0xc8, 0x45, 0xba, 0x90, 0x77, 0x55, 0xce, 0xc6, 0x89, 0x25, 0xe5, 0xe2, 0xbf, 0xe9, 0x12, 0x95, 0x9d, 0xb8, 0x6f, 0xbf, 0xe2, 0x15, 0x6f, 0xd5, 0xbb, 0xdb, 0xf0, 0xc9, 0xdf, 0x8b, 0x53, 0x02, 0xaa, 0x8d, 0x90, 0xa2, 0x2d, 0x12, 0x27, 0x0e, 0x00, 0x65, 0x51, 0xe4, 0x76, 0x7e, 0x45, 0x26, 0x8e, 0xd9, 0x69, 0x26, 0x54, 0x44, 0x78, 0x11, 0xea, 0xb8, 0x4f, 0x04, 0x99, 0xa8, 0xa5, 0x8c, 0xf7, 0xc0, 0x4a, 0x59, 0x56, 0x98, 0x52, 0x80, 0x45, 0xf2, 0x98, 0x97, 0xc8, 0xfa, 0x96, 0xd0, 0x6c, 0xce, 0x51, 0xe6, 0xaf, 0xea, 0xc4, 0x33, 0x95, 0x89, 0xc9, 0x41, 0xc8, 0x55, 0x63, 0xd7, 0x0f, 0xac, 0xe1, 0x92, 0x88, 0x94, 0xba, 0xc0, 0x36, 0x19, 0xdf, 0xf4, 0xbe, 0x3f, 0x43, 0x14, 0xa3, 0xf7, 0x35, 0x1a, 0x09, 0xa4, 0x86, 0xb5, 0x04, 0x1e, 0x7c, 0xb2, 0xda, 0x8b, 0x96, 0xbc, 0x66, 0x26, 0xa4, 0x93, 0x17, 0x35, 0x7c, 0x41, 0x52, 0xa5, 0x1b, 0xa3, 0xc2, 0x8c, 0x7e, 0x0c, 0x9d, 0xb4, 0x1a, 0x06, 0xa2, 0x82, 0x90, 0xf2, 0x18, 0x73, 0x11, 0x07, 0xc9, 0x54, 0xd8, 0xa6, 0x6f, 0x80, 0x1d, 0x7d, 0xe1, 0x2a, 0x03, 0x71, 0x16, 0x99, 0x0b, 0x6c, 0x53, 0xc1, 0x29, 0xf1, 0x85, 0xc3, 0x45, 0xf2, 0x7e, 0x51, 0x8b, 0x2d, 0x5a, 0x91, 0x25, 0xa0, 0x70, 0x76, 0xd9, 0x91, 0xb7, 0xda, 0xc7, 0xcc, 0x65, 0xa8, 0x56, 0x2e, 0xfb, 0xcc, 0x32, 0xa9, 0xca, 0x4a, 0xd9, 0x02, 0x63, 0xb0, 0x4a, 0x4f, 0x90, 0x36, 0x11, 0x6c, 0x7b, 0x97, 0x48, 0x04, 0x96, 0x31, 0x75, 0x75, 0x65, 0x0d, 0xcc, 0x21, 0x52, 0xb5, 0xbc, 0x0e, 0x74, 0x40, 0x7e, 0x12, 0xfa, 0x8e, 0x4f, 0xfc, 0xcc, 0xff, 0x76, 0xc0, 0x1a, 0x97, 0x4b, 0xd6, 0x11, 0x02, 0xe1, 0xf5, 0x29, 0x64, 0x96, 0xc7, 0x1d, 0x07, 0x64, 0xe1, 0x32, 0x29, 0xff, 0xe7, 0x84, 0x6f, 0x33, 0x6e, 0x34, 0xca, 0xc9, 0x04, 0xca, 0x56, 0x70, 0xf8, 0xcd, 0x50, 0x52, 0x42, 0x7a, 0x79, 0xc0, 0x91, 0xa9, 0x71, 0x21, 0x0c, 0x5c, 0xff, 0x66, 0x7a, 0xac, 0x24, 0x93, 0x66, 0xe1, 0x0d, 0x2b, 0x11, 0x37, 0x6c, 0xa3, 0x9d, 0x93, 0x52, 0x04, 0xb1, 0x2c, 0xc5, 0x85, 0xe9, 0x40, 0x54, 0x03, 0x62, 0x5f, 0xb3, 0x2c, 0xb5, 0xe5, 0xc3, 0x1b, 0x62, 0x34, 0x81, 0x60, 0x51, 0x5c, 0xcc, 0x4f, 0xda, 0xf5, 0x70, 0x2d, 0x6b, 0xab, 0x5c, 0x37, 0x3d, 0xb6, 0xf3, 0x50, 0xd3, 0xe6, 0x3a, 0x5c, 0xe3, 0xca, 0x54, 0x74, 0xa0, 0xcf, 0x15, 0x67, 0x04, 0x2c, 0xa3, 0x25, 0x89, 0x86, 0xff, 0x75, 0xbd, 0xfc, 0xd9, 0x29, 0xe6, 0x46, 0x2f, 0x36, 0xbc, 0xcc, 0x3f, 0x5a, 0x93, 0x35, 0x2a, 0x2b, 0x36, 0xcb, 0x16, 0x2e, 0x18, 0x74, 0xc7, 0x42, 0x87, 0x0a, 0x97, 0xb1, 0x67, 0xa0, 0x50, 0x37, 0x36, 0x24, 0xea, 0xeb, 0x7e, 0x50, 0x73, 0x25, 0x6b, 0x72, 0x11, 0xb2, 0xd9, 0x4b, 0x84, 0x06, 0xcd, 0x6c, 0x95, 0x33, 0xb1, 0x53, 0x64, 0x08, 0xab, 0x0a, 0x29, 0xe5, 0xb2, 0xf0, 0xc9, 0x54, 0xec, 0xe0, 0x0f, 0xbb, 0xeb, 0x17, 0x6d, 0x72, 0x4d, 0x4c, 0xf4, 0x43, 0xcf, 0x70, 0x20, 0xd5, 0xfa, 0x70, 0x94, 0xcc, 0x1b, 0x1b, 0xe6, 0x97, 0xba, 0xd3, 0x36, 0x74, 0xe4, 0x09, 0x9e, 0xc7, 0xbb, 0x18, 0xf4, 0x57, 0x71, 0x28, 0xcd, 0xd9, 0x7c, 0xcd, 0x6d, 0x44, 0x62, 0xe5, 0x60, 0x7c, 0x51, 0x2a, 0x3e, 0x36, 0x24, 0x8e, 0x3d, 0xda, 0xa2, 0xec, 0x08, 0x9a, 0xef, 0xc4, 0xce, 0x48, 0x5c, 0x49, 0xd7, 0xb0, 0x09, 0xc8, 0xd6, 0x31, 0x15, 0xfc, 0x81, 0xff, 0x3a, 0x62, 0xd1, 0x5a, 0x88, 0x44, 0x1c, 0x03, 0xea, 0x1c, 0x2e, 0x72, 0xc4, 0x88, 0x39, 0xfc, 0x6a, 0xd7, 0x3a, 0x30, 0x74, 0x4a, 0x62, 0xb7, 0xb2, 0x16, 0x45, 0xa6, 0xaf, 0x7d, 0x61, 0xb6, 0x38, 0x3b, 0x22, 0x1e, 0x21, 0x90, 0x55, 0x57, 0xcd, 0x29, 0xd9, 0x24, 0xa6, 0x09, 0x86, 0xc5, 0x11, 0xc1, 0xeb, 0xbc, 0x31, 0x6d, 0x56, 0x30, 0xa2, 0x41, 0x43, 0x23, 0xf5, 0x3a, 0xd5, 0x59, 0x94, 0xf6, 0xb3, 0x65, 0x39, 0xf9, 0xc4, 0x40, 0x75, 0xa5, 0x33, 0xe4, 0x81, 0xc0, 0x84, 0x45, 0xd9, 0xca, 0x9e, 0x9d, 0x38, 0x21, 0x19, 0x38, 0x8b, 0xd1, 0xd7, 0x50, 0x52, 0x21, 0x7a, 0x94, 0x4c, 0xcc, 0x7b, 0xe9, 0x09, 0xe2, 0x19, 0x71, 0x1f, 0xcc, 0x79, 0x24, 0x76, 0x92, 0x13, 0xa1, 0x92, 0x53, 0x4a, 0x55, 0x80, 0x08, 0x15, 0x7a, 0x39, 0x6e, 0xdf, 0xf4, 0x80, 0xcc, 0x3b, 0x52, 0x0f, 0xf8, 0x18, 0xb3, 0x8b, 0x13, 0x5c, 0x18, 0xa8, 0x0d, 0x51, 0x05, 0xe6, 0x78, 0x83, 0x6c, 0x39, 0x5c, 0x28, 0xe9, 0x2f, 0x7a, 0x3c, 0x4e, 0x93, 0xc0, 0x10, 0x35, 0xf3, 0x41, 0x11, 0xcc, 0x49, 0x02, 0xd0, 0xc0, 0x33, 0xa6, 0x3f, 0x23, 0x6a, 0x71, 0xda, 0x97, 0x4a, 0x6f, 0x40, 0x4f, 0x7a, 0xa7, 0xb5, 0xe5, 0x82, 0xc7, 0x58, 0x14, 0x2f, 0xc1, 0x82, 0x6b, 0xba, 0x98, 0xb2, 0x7d, 0x57, 0xc2, 0xe2, 0x10, 0x3e, 0x10, 0xe3, 0x0d, 0x32, 0x79, 0x7b, 0x96, 0x77, 0x14, 0xd1, 0x56, 0x61, 0x11, 0x13, 0x71, 0xa2, 0xd9, 0xc5, 0x39, 0x98, 0x12, 0x46, 0x46, 0x22, 0x63, 0x5b, 0x44, 0x21, 0x26, 0xb0, 0x98, 0x36, 0xb0, 0x81, 0x82, 0x72, 0x47, 0xd0, 0x54, 0x22, 0x97, 0x2b, 0xd0, 0x32, 0x0d, 0x8f, 0x42, 0xbf, 0x57, 0xe3, 0x49, 0x46, 0x12, 0x34, 0xe4, 0xd9, 0x4f, 0x01, 0x18, 0x50, 0xba, 0xb5, 0xc0, 0x49, 0xb6, 0x2a, 0x59, 0x43, 0x38, 0x66, 0xfc, 0xce, 0x69, 0x66, 0x49, 0x5c, 0x26, 0x5c, 0x47, 0x65, 0xa5, 0x6c, 0x06, 0xb9, 0xfc, 0x42, 0x76, 0x54, 0x87, 0x85, 0xf4, 0x68, 0x28, 0xca, 0x60, 0x2d, 0xc6, 0xd0, 0x54, 0x1f, 0x25, 0x07, 0x89, 0xc4, 0x9e, 0x8b, 0x06, 0x55, 0x9c, 0x43, 0x44, 0x60, 0xa8, 0x43, 0x80, 0x98, 0x54, 0xe5, 0xb4, 0x6e, 0x89, 0x38, 0x9f, 0x10, 0xf4, 0x89, 0x66, 0x74, 0x91, 0xc1, 0x93, 0x5e, 0x8a, 0xfb, 0x9e, 0xb4, 0x71, 0x8f, 0x86, 0xac, 0x45, 0x89, 0x32, 0xbc, 0xf3, 0x3c, 0x9a, 0xbe, 0xcb, 0x2d, 0xc0, 0xc0, 0x93, 0xa7, 0xe8, 0x1d, 0xa0, 0x32, 0x7b, 0xb6, 0x37, 0x52, 0x81, 0x05, 0xc3, 0x58, 0xeb, 0x76, 0x8d, 0x32, 0x3a, 0x37, 0xd4, 0x0a, 0x8c, 0x19, 0x9b, 0x7c, 0x4b, 0xb1, 0xd7, 0x2b, 0x72, 0xb6, 0x90, 0xb3, 0x6d, 0xd2, 0x7a, 0x93, 0x55, 0x19, 0x1b, 0x3c, 0x3a, 0xa6, 0x75, 0xa7, 0xe6, 0xf8, 0x55, 0xeb, 0x50, 0x5f, 0x57, 0x98, 0x65, 0xdb, 0xd8, 0x91, 0x05, 0x65, 0x50, 0x5e, 0x7c, 0x0f, 0xdd, 0x54, 0x5c, 0xbb, 0xb8, 0x71, 0xb0, 0xb2, 0xcc, 0x01, 0x25, 0xb7, 0x4f, 0x6b, 0x0c, 0x9b, 0x79, 0x67, 0x0a, 0x62, 0x02, 0xd1, 0xb9, 0x15, 0x4a, 0xc7, 0x76, 0x6b, 0x19, 0x19, 0xc4, 0x89, 0x58, 0x90, 0x86, 0xad, 0x8b, 0x45, 0xbe, 0x0d, 0x79, 0xc9, 0x76, 0xc3, 0xc3, 0x9d, 0x6b, 0x25, 0x21, 0x3b, 0xb0, 0xb7, 0x8a, 0x57, 0x50, 0xe6, 0xa8, 0xeb, 0x34, 0x33, 0x0b, 0xb3, 0xcf, 0xf2, 0xb1, 0xc0, 0x72, 0x2a, 0xc8, 0x83, 0xb0, 0x48, 0xf4, 0xb8, 0xcd, 0x06, 0x19, 0x6d, 0xa8, 0xaa, 0x8b, 0x05, 0xda, 0x42, 0x67, 0x55, 0x2b, 0xf8, 0x7a, 0xbc, 0xa5, 0x12, 0x4d, 0xc3, 0x58, 0xa8, 0x38, 0x10, 0x40, 0xe9, 0xb8, 0x1f, 0xb0, 0x84, 0x43, 0x15, 0x02, 0x15, 0xd6, 0x92, 0x23, 0x28, 0x00, 0x0a, 0xc0, 0xb7, 0x88, 0xb1, 0x21, 0x93, 0x1a, 0x26, 0x7d, 0x80, 0x61, 0x9c, 0xe7, 0xd2, 0x9c, 0xd7, 0x6b, 0x60, 0xcf, 0x65, 0x83, 0xdc, 0xe8, 0xce, 0xbc, 0x49, 0x01, 0x85, 0x73, 0x6c, 0x81, 0x8b, 0x25, 0xad, 0x26, 0x0b, 0x66, 0x7b, 0x1f, 0xfd, 0x46, 0x20, 0x6d, 0x01, 0x04, 0x55, 0x3a, 0xa9, 0xfb, 0x30, 0x45, 0x54, 0xa2, 0x1c, 0x32, 0x72, 0x44, 0xce, 0x78, 0xaf, 0xdb, 0xd3, 0xb4, 0x62, 0x36, 0x1b, 0xb0, 0x68, 0xa1, 0x55, 0x63, 0x64, 0x09, 0xf5, 0x74, 0xc5, 0x71, 0x65, 0x72, 0xe2, 0xa5, 0xf2, 0xa4, 0xb0, 0x4f, 0xb8, 0xaa, 0xd1, 0x23, 0x66, 0x84, 0x84, 0x17, 0x87, 0x56, 0x2a, 0xaf, 0x46, 0xc2, 0xc0, 0xda, 0x46, 0x65, 0xea, 0xfd, 0x46, 0x5f, 0xc6, 0x4a, 0x0c, 0x5f, 0x8f, 0x3f, 0x90, 0x03, 0x48, 0x94, 0x15, 0x89, 0x9d, 0x59, 0xa5, 0x43, 0xd8, 0x20, 0x8c, 0x54, 0xa3, 0x16, 0x65, 0x29, 0xb5, 0x39, 0x22, }, .secret_len = 32, .secret = { 0xfb, 0xc4, 0xee, 0xa6, 0x91, 0xee, 0xf4, 0xc1, 0xb4, 0x76, 0xa2, 0x99, 0x36, 0x45, 0x3f, 0x4c, 0x3d, 0x48, 0x81, 0x79, 0x4e, 0xe3, 0x7b, 0xaf, 0x0f, 0xd7, 0x28, 0x40, 0x74, 0x3e, 0x7b, 0x7d, }, .cipher_len = 1568, .cipher = { 0xc2, 0x7f, 0x01, 0x24, 0x4d, 0x4b, 0x3f, 0xb2, 0x1d, 0x84, 0x37, 0xf8, 0x40, 0x01, 0x7c, 0xcc, 0xb7, 0xb7, 0xda, 0xd5, 0xfb, 0x2b, 0x47, 0xb9, 0xb5, 0x7e, 0xae, 0x4f, 0x77, 0xd0, 0xa4, 0x55, 0x5e, 0x50, 0x92, 0xa2, 0x49, 0x69, 0xf2, 0x27, 0x3e, 0x97, 0x02, 0x88, 0x4a, 0x08, 0x47, 0x7b, 0x56, 0x8d, 0x80, 0x17, 0xf1, 0x38, 0x75, 0xd1, 0xf5, 0xa6, 0xd4, 0x13, 0xbd, 0xd2, 0x28, 0xeb, 0xb1, 0x12, 0x60, 0xf7, 0xf4, 0x52, 0x9c, 0xbc, 0xeb, 0xf9, 0xb6, 0x86, 0x2e, 0x8a, 0x84, 0x12, 0x35, 0xf2, 0x9f, 0x60, 0xf8, 0xe8, 0x41, 0x74, 0x34, 0x18, 0x9d, 0x57, 0x99, 0x20, 0xfe, 0x6b, 0x98, 0xdb, 0xe7, 0x13, 0xec, 0x16, 0xc3, 0xfd, 0xdb, 0xb8, 0x1e, 0x73, 0x1d, 0x95, 0x6b, 0x06, 0xdb, 0x49, 0x80, 0xf4, 0x9c, 0x26, 0xf2, 0x86, 0x61, 0xff, 0x9c, 0xe6, 0xe9, 0xd8, 0x61, 0xec, 0x7a, 0x09, 0x84, 0x0c, 0x19, 0xde, 0x0e, 0xb6, 0x72, 0x20, 0x71, 0xf8, 0xaa, 0x48, 0x36, 0x2d, 0x2f, 0xf1, 0x27, 0xa4, 0xae, 0x46, 0xf9, 0x93, 0x37, 0x82, 0x68, 0x32, 0xad, 0xac, 0x23, 0x91, 0x65, 0xf2, 0x25, 0x85, 0xbb, 0x57, 0xa8, 0x89, 0xc9, 0xc6, 0xaf, 0x82, 0x36, 0x7e, 0xc7, 0xb0, 0x72, 0x37, 0xc0, 0x53, 0x5b, 0x31, 0xb3, 0x8c, 0x1c, 0xac, 0x40, 0xac, 0x1a, 0x0c, 0x95, 0x8a, 0x18, 0x87, 0xfe, 0x34, 0x71, 0x10, 0x83, 0xfd, 0x37, 0xaf, 0x4b, 0xc5, 0xb1, 0xb4, 0xe1, 0xe2, 0xee, 0x28, 0x43, 0x69, 0x3d, 0x57, 0xdd, 0x1e, 0x65, 0x7d, 0x4c, 0x24, 0xed, 0x20, 0x7e, 0xe7, 0x12, 0xad, 0x2a, 0x08, 0x91, 0x45, 0x81, 0x80, 0xe9, 0xe8, 0xbd, 0x36, 0xfc, 0x14, 0xd8, 0xd6, 0x33, 0xf5, 0xb7, 0x41, 0xce, 0xa1, 0x08, 0xd2, 0xd4, 0xfd, 0x75, 0x1c, 0x5a, 0x67, 0xb0, 0x5e, 0x30, 0x32, 0x4a, 0x67, 0xe9, 0xdd, 0x75, 0xc9, 0x93, 0xd4, 0xfe, 0x08, 0x54, 0xfb, 0x78, 0xdf, 0x6f, 0x3d, 0x45, 0xa2, 0xa9, 0xc8, 0xe4, 0x25, 0x10, 0xf0, 0xc3, 0xd8, 0x02, 0x03, 0x71, 0x2f, 0xb3, 0x9e, 0x36, 0xb5, 0xdd, 0x8b, 0x5c, 0xcd, 0x3d, 0x09, 0xce, 0xa9, 0x42, 0x03, 0xba, 0xf8, 0x72, 0x08, 0x45, 0x71, 0xec, 0xf9, 0x78, 0xbd, 0xb9, 0x54, 0x8a, 0x25, 0x0e, 0xe4, 0x90, 0x7b, 0x4a, 0xfc, 0x31, 0xb2, 0x1f, 0x31, 0x9a, 0xe4, 0xbf, 0x0a, 0xb1, 0x9c, 0xbd, 0x11, 0xeb, 0xe1, 0x33, 0x59, 0xd1, 0xaa, 0xf4, 0xfd, 0xb8, 0x3b, 0x65, 0x02, 0x50, 0x14, 0x22, 0xa5, 0xfe, 0x50, 0xa8, 0xa3, 0x8e, 0xf5, 0x3d, 0xeb, 0x60, 0x3c, 0xe2, 0x3f, 0xd9, 0x79, 0x2b, 0x04, 0xde, 0xb3, 0x78, 0x71, 0x9a, 0xb7, 0x69, 0xaa, 0x58, 0x97, 0xcc, 0x65, 0xe9, 0xb1, 0x63, 0x04, 0xce, 0xa5, 0x37, 0xe1, 0x76, 0x2b, 0xd8, 0xc9, 0xb1, 0x09, 0xda, 0x14, 0xa8, 0x29, 0xe6, 0x41, 0x9f, 0x1b, 0x9f, 0xf8, 0xa4, 0x66, 0xe2, 0xa6, 0xd6, 0xb3, 0x4d, 0x74, 0xff, 0xe1, 0xa5, 0x92, 0x99, 0x18, 0x17, 0x59, 0xd0, 0xd3, 0x87, 0xfc, 0xed, 0x1d, 0x90, 0x7f, 0x5f, 0xb5, 0xed, 0xb4, 0x26, 0xc0, 0x51, 0x30, 0xe6, 0xca, 0x59, 0x09, 0xb2, 0x76, 0xd1, 0xa4, 0x7e, 0x71, 0x3c, 0x30, 0xd9, 0x96, 0xda, 0x5e, 0x8e, 0x57, 0xe7, 0x12, 0xc7, 0x77, 0x38, 0xf2, 0x1b, 0xe7, 0x4b, 0x42, 0xb5, 0x18, 0x43, 0x2d, 0xad, 0x7e, 0xf7, 0x3e, 0x6a, 0x8c, 0x43, 0xaa, 0x9a, 0x62, 0x69, 0x94, 0xd7, 0x1a, 0x31, 0x81, 0x28, 0x51, 0x80, 0x6e, 0x9f, 0xbb, 0x1f, 0x2b, 0xd3, 0x56, 0xce, 0xa3, 0x9d, 0x95, 0xf2, 0xf8, 0x7c, 0xa3, 0x0d, 0xaf, 0x6f, 0x27, 0x33, 0xf7, 0xbc, 0xe7, 0x9f, 0x8d, 0xa9, 0x95, 0x05, 0x1e, 0x49, 0xa7, 0xfd, 0x22, 0x64, 0x37, 0x9c, 0x0a, 0x75, 0x2e, 0x55, 0x3e, 0xd6, 0x08, 0xeb, 0x93, 0x44, 0xc7, 0x94, 0x98, 0xf6, 0x91, 0x53, 0x85, 0x64, 0xc5, 0x4f, 0x82, 0x3b, 0xb7, 0x0b, 0x12, 0xb5, 0x9e, 0x88, 0x24, 0xb4, 0xa4, 0xbb, 0x1e, 0xea, 0xc6, 0x7c, 0x81, 0x0c, 0xcc, 0x2e, 0x23, 0x74, 0x47, 0x83, 0xce, 0x95, 0x80, 0x97, 0xf7, 0xa6, 0xbc, 0x6e, 0x1f, 0x17, 0x59, 0x75, 0x21, 0xb8, 0xc3, 0xd1, 0xee, 0x85, 0x96, 0xa2, 0x9f, 0xfe, 0xf1, 0x4e, 0xd9, 0x16, 0x32, 0x09, 0x7c, 0x16, 0xd5, 0x06, 0x5d, 0xb2, 0xa9, 0x63, 0xca, 0x73, 0x83, 0xac, 0x60, 0xad, 0x8f, 0x4e, 0xd0, 0xd4, 0x1b, 0xd0, 0xbc, 0x3b, 0xaf, 0x19, 0x8c, 0x51, 0x25, 0xae, 0x91, 0x15, 0x06, 0xc9, 0x26, 0xd4, 0xc1, 0x17, 0x85, 0xfd, 0x61, 0x82, 0x29, 0xbf, 0xf5, 0x4c, 0xb1, 0x16, 0x1a, 0xb8, 0xfc, 0x7b, 0x51, 0xda, 0xec, 0xcc, 0xd9, 0x13, 0x1e, 0xdf, 0x43, 0x7d, 0x8e, 0x52, 0x8e, 0x75, 0x81, 0xb8, 0x2c, 0x66, 0x0e, 0x8c, 0x5e, 0x25, 0x12, 0xd5, 0xf6, 0x38, 0x0a, 0x52, 0x8f, 0x2a, 0xe4, 0xae, 0xe2, 0x63, 0xdb, 0x96, 0x76, 0x02, 0x4b, 0xc7, 0xad, 0x39, 0x8b, 0xc9, 0xcd, 0xda, 0xd6, 0x07, 0x96, 0x8b, 0xba, 0xb2, 0x23, 0x29, 0xe0, 0x4d, 0x6e, 0x77, 0x1f, 0xe6, 0x47, 0x10, 0x7a, 0xc4, 0x66, 0x67, 0xa5, 0x1a, 0xd5, 0x58, 0xa6, 0x35, 0xf0, 0x26, 0x95, 0x1f, 0x4f, 0x48, 0xc8, 0x88, 0xd7, 0x01, 0xc2, 0xaf, 0xf4, 0xea, 0xb4, 0xe3, 0x4a, 0xdb, 0x15, 0x9a, 0xbb, 0xbf, 0xab, 0xe5, 0x9b, 0x3f, 0x4c, 0xf8, 0xaa, 0xb1, 0xdd, 0x66, 0x1e, 0x4d, 0xd0, 0xc5, 0x55, 0x8d, 0xc0, 0x59, 0x20, 0x2e, 0xe6, 0x46, 0x25, 0xa3, 0xb4, 0xb9, 0x2f, 0xf4, 0xd1, 0x56, 0x97, 0xf1, 0x6c, 0x18, 0xd4, 0xd2, 0x33, 0x8c, 0xfb, 0x49, 0x6e, 0x07, 0x03, 0x52, 0x68, 0x71, 0xc9, 0x78, 0x4b, 0xac, 0x8e, 0xba, 0xe8, 0x27, 0x9c, 0xf2, 0x71, 0x3a, 0xf3, 0xcc, 0x2d, 0x44, 0x0e, 0x8c, 0xd2, 0x00, 0x86, 0x7b, 0x85, 0x18, 0xaa, 0xd3, 0xb9, 0xe2, 0x85, 0x02, 0x7d, 0xa0, 0xad, 0xd9, 0xf0, 0x22, 0x9e, 0xd4, 0xe8, 0x42, 0xd0, 0x5e, 0x22, 0x6a, 0xda, 0xc1, 0x3a, 0x39, 0x52, 0xe3, 0x83, 0x5c, 0x8f, 0xb0, 0xa4, 0x28, 0x74, 0xc9, 0x4c, 0x66, 0x1b, 0x39, 0xdf, 0x7b, 0x72, 0x88, 0x7d, 0x22, 0x7d, 0x58, 0x3c, 0xe6, 0xb3, 0xbd, 0x65, 0xf7, 0x95, 0x10, 0x7b, 0xd0, 0x93, 0x38, 0x9b, 0xfe, 0xfd, 0x17, 0x68, 0xa5, 0x71, 0x6f, 0x68, 0x5b, 0x17, 0x4e, 0xd2, 0x3e, 0x94, 0xa5, 0x95, 0x6e, 0x29, 0xbb, 0x2d, 0xdb, 0x79, 0x21, 0x03, 0xe6, 0x2f, 0x68, 0x92, 0x8a, 0xcc, 0x60, 0x3e, 0xec, 0x2f, 0xf5, 0x6d, 0xb1, 0x4c, 0x08, 0xb7, 0xcb, 0xe4, 0xe2, 0xb4, 0xf2, 0xe0, 0xea, 0xee, 0x54, 0x16, 0x2e, 0x95, 0xbb, 0x35, 0xef, 0x36, 0x30, 0x3e, 0xe3, 0xe6, 0xcc, 0x61, 0x06, 0x13, 0x73, 0x87, 0x6f, 0x7a, 0x09, 0x6a, 0x8a, 0xf5, 0x7d, 0x78, 0x2f, 0x8c, 0x82, 0x03, 0xde, 0x93, 0x42, 0x3a, 0x37, 0x91, 0x22, 0xfe, 0x7d, 0xad, 0x77, 0x0c, 0x36, 0x90, 0xf9, 0x78, 0x22, 0x84, 0x60, 0xd0, 0x25, 0xce, 0x93, 0xb1, 0xb3, 0x36, 0xc5, 0x73, 0xe4, 0xe5, 0x58, 0x40, 0xea, 0x65, 0xcf, 0xdd, 0x61, 0x22, 0xc6, 0x72, 0xc9, 0x12, 0xf5, 0x29, 0x39, 0xd9, 0xea, 0x5b, 0xe0, 0x62, 0x10, 0xf5, 0xe7, 0xed, 0xb6, 0x5b, 0x66, 0x94, 0x5d, 0x70, 0x56, 0xf5, 0x59, 0xa7, 0xd6, 0x92, 0x53, 0xf4, 0xbd, 0xbc, 0x57, 0x9d, 0xe9, 0x64, 0xf3, 0xe9, 0x3a, 0x86, 0xfa, 0x38, 0xb6, 0xa2, 0xc0, 0xb5, 0x43, 0x38, 0xdc, 0xe0, 0x93, 0xf0, 0xb4, 0x68, 0x4e, 0xe3, 0x61, 0x44, 0x9f, 0x16, 0xc2, 0x79, 0xa7, 0x2b, 0x77, 0x31, 0xe4, 0x46, 0x00, 0xa7, 0x02, 0x77, 0x68, 0xfd, 0xd0, 0xf6, 0x43, 0xed, 0x10, 0x06, 0x4b, 0x98, 0xa9, 0xda, 0x03, 0x2f, 0x1f, 0x5d, 0xea, 0xd3, 0x11, 0xe1, 0x77, 0x33, 0x50, 0x94, 0xdb, 0x4e, 0x38, 0x51, 0x4e, 0xae, 0x15, 0xa8, 0xf8, 0xec, 0xf2, 0xf2, 0x41, 0x4e, 0x37, 0x8e, 0xfb, 0xf9, 0x97, 0xb1, 0x06, 0x6b, 0x6f, 0x69, 0xd6, 0x69, 0x09, 0xa4, 0x7e, 0x29, 0x8a, 0x7f, 0xec, 0x96, 0x1a, 0x83, 0x78, 0x2e, 0x0e, 0x47, 0x0f, 0xe0, 0x71, 0xde, 0xcf, 0x4b, 0x26, 0xac, 0xa6, 0xed, 0x68, 0x83, 0x59, 0xe1, 0x08, 0x50, 0x55, 0xfd, 0x2b, 0x5a, 0xe9, 0xf4, 0x91, 0x87, 0x49, 0x89, 0x7a, 0xf1, 0x33, 0x60, 0x60, 0x53, 0xd5, 0xf6, 0xa8, 0x52, 0x8c, 0xcb, 0x31, 0xab, 0x7f, 0x3f, 0x2d, 0x89, 0xa9, 0x5c, 0x5f, 0x05, 0xb1, 0x57, 0x00, 0xe5, 0x32, 0xad, 0x81, 0xd5, 0x9d, 0x9d, 0xb8, 0xa2, 0xc2, 0x9c, 0xac, 0x93, 0x6e, 0x3f, 0x33, 0xdf, 0xe2, 0x4b, 0x0b, 0x1b, 0x71, 0x90, 0x2d, 0xc9, 0xc3, 0x0e, 0xc8, 0xc7, 0x0b, 0xda, 0xba, 0x48, 0x4f, 0xcd, 0x2b, 0x94, 0x6d, 0x73, 0x5f, 0x16, 0xee, 0xad, 0x04, 0x03, 0x1c, 0xaf, 0xde, 0x9e, 0xe0, 0x16, 0x96, 0xec, 0x9f, 0x0a, 0x8d, 0x5f, 0x36, 0xb6, 0x9c, 0x64, 0x2f, 0xfd, 0x0a, 0xd0, 0xd2, 0x54, 0x4f, 0x5e, 0x7f, 0xd8, 0x9a, 0x80, 0x49, 0x8e, 0xf6, 0x8e, 0x18, 0x16, 0x17, 0xfa, 0xd4, 0x1e, 0x0b, 0xd5, 0x9b, 0xaa, 0xff, 0xee, 0xfe, 0x2f, 0x99, 0x72, 0x4c, 0x71, 0x9d, 0x47, 0xa2, 0xec, 0xba, 0x72, 0x1d, 0x76, 0xf2, 0x37, 0xeb, 0xa7, 0x3d, 0xb4, 0x7d, 0x88, 0xb6, 0x99, 0xe3, 0x58, 0x2b, 0x07, 0x3c, 0x7e, 0xad, 0x2a, 0x5b, 0x3c, 0xf0, 0x24, 0x46, 0x63, 0x96, 0xf9, 0xf2, 0x82, 0x6c, 0xb7, 0x54, 0xf6, 0x60, 0x18, 0xe9, 0x50, 0x3f, 0x4a, 0xd1, 0xf9, 0xd9, 0x21, 0x21, 0xaa, 0x99, 0x56, 0x50, 0x60, 0x51, 0xd5, 0x96, 0xff, 0xd4, 0x67, 0xe1, 0xaa, 0x8d, 0x96, 0x4c, 0x17, 0x67, 0xc9, 0x25, 0xb4, 0x68, 0xbb, 0xc9, 0x85, 0x06, 0x00, 0xc8, 0x43, 0x49, 0x05, 0x41, 0xe8, 0x55, 0x5a, 0x3d, 0x8b, 0xd9, 0xf1, 0x87, 0x91, 0xef, 0x9e, 0xbd, 0x35, 0x94, 0xe7, 0x4c, 0x1f, 0xe3, 0xd3, 0xb8, 0x09, 0x40, 0xa8, 0xa0, 0x79, 0xf8, 0xd2, 0xca, 0x8d, 0x30, 0x13, 0x4f, 0xc6, 0x6f, 0x87, 0x00, 0x81, 0x26, 0xe4, 0x3b, 0xd0, 0x6e, 0xb6, 0xe4, 0x1c, 0x3a, 0x70, 0xfa, 0x47, 0x39, 0x31, 0x9b, 0xf1, 0xa9, 0x32, 0xf0, 0x2c, 0x30, 0x64, 0x56, 0x56, 0x0c, 0xda, 0x44, 0xdd, 0xac, 0x43, 0xed, 0x6d, 0x90, 0x04, 0x45, 0xf5, 0xbf, 0x85, 0xbb, 0x0c, 0xe3, 0x25, 0x94, 0x74, 0x36, 0xe0, 0xd0, 0x68, 0x5e, 0x41, 0xb1, 0x6b, 0xc7, 0x16, 0x95, 0x18, 0x25, 0x9e, 0x57, 0x34, 0xfd, 0xce, 0x08, 0x0f, 0xfe, 0x85, 0x19, 0x1b, 0x1d, 0x8d, 0x8d, 0xe4, 0xdb, 0x48, 0x14, 0x3f, 0xb5, 0x64, 0x03, 0x8a, 0xce, 0x80, 0x10, 0x4d, 0x3a, 0x8d, 0x07, 0x12, 0x45, 0xe2, 0xaa, 0x56, 0xc7, 0x19, 0x33, 0xf4, 0xdc, 0xf9, 0x25, 0xee, 0xe8, 0x44, 0xc8, 0x0f, 0xdd, 0xf3, 0x25, 0x1f, 0x74, 0x00, 0x6a, 0x23, 0x41, 0x33, 0x18, 0xbb, 0xfd, 0x2e, 0xd9, 0xe0, 0x53, 0x51, 0xb5, 0xaa, 0xeb, 0xcc, 0x77, 0xcf, 0xac, 0x8d, 0x5f, 0x03, 0x64, 0x23, 0x1a, 0x50, 0xea, 0x86, 0x47, 0xc7, 0x2f, 0x71, 0x3e, 0x81, 0x7a, 0x20, 0x75, 0x32, 0x30, 0x29, 0xe3, 0xb8, 0x8b, 0x72, 0x44, 0x22, 0x64, 0xc5, 0x97, 0xb0, 0xf1, 0xfc, 0x09, 0xf9, 0x40, 0x1c, 0xe8, 0x8a, 0xc9, 0x7c, 0x55, 0x22, 0xa5, 0x63, 0x64, 0x52, 0x3c, 0x37, 0xfe, 0xa2, 0xd6, 0xbd, 0x06, 0xb2, }, }, }; #define KYBER_TV_NUM sizeof(kyber_tv)/sizeof(struct KYBER_TEST_VECTOR) opencryptoki-opencryptoki-451d99c/testcases/crypto/kyber_func.c000066400000000000000000001157531520105705100251510ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2022 * * This program is provided under the terms of the Common Public License, * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this * software constitutes recipient's acceptance of CPL-1.0 terms which can be * found in the file LICENSE file or at * https://opensource.org/licenses/cpl1.0.php */ #include #include #include #include #include #include "pkcs11types.h" #include "regress.h" #include "common.c" #include "defs.h" #include "kyber.h" #include "mechtable.h" #include "pqc_oids.h" #include "ec_curves.h" /** * Experimental Support for Kyber keys and KEM * with oid = 1.3.6.1.4.1.2.267.5.xxx */ const CK_BYTE kyber_r2_768[] = OCK_KYBER_R2_768; const CK_BYTE kyber_r2_1024[] = OCK_KYBER_R2_1024; const CK_BYTE prime256v1[] = OCK_PRIME256V1; typedef struct variant_info { const char *name; CK_ULONG keyform; const CK_BYTE *oid; CK_ULONG oid_len; } _variant_info; const _variant_info variants[] = { { "DEFAULT (KYBER_R2_1024)", 0, NULL, 0 }, { "KYBER_R2_768", CK_IBM_KYBER_KEYFORM_ROUND2_768, kyber_r2_768, sizeof(kyber_r2_768) }, { "KYBER_R2_1024", CK_IBM_KYBER_KEYFORM_ROUND2_1024, kyber_r2_1024, sizeof(kyber_r2_1024) }, }; const CK_ULONG num_variants = sizeof(variants) / sizeof(_variant_info); typedef struct kemParam { CK_IBM_KYBER_KDF_TYPE kdf; CK_ULONG secret_key_len; CK_ULONG shard_data_len; CK_BYTE shared_data[32]; CK_BBOOL hybrid; CK_BBOOL prepend; } _kemParam; const _kemParam kemInput[] = { { CKD_NULL, 32, 0, {0x00}, CK_FALSE, CK_FALSE }, { CKD_IBM_HYBRID_SHA1_KDF, 16, 0, {0x00}, CK_TRUE, CK_FALSE }, { CKD_IBM_HYBRID_SHA1_KDF, 32, 16, { 0x32,0x3F,0xA3,0x16,0x9D,0x8E,0x9C,0x65,0x93,0xF5,0x94,0x76,0xBC,0x14,0x20,0x00 }, CK_TRUE, CK_TRUE }, { CKD_IBM_HYBRID_SHA224_KDF, 16, 0, {0x00}, CK_TRUE, CK_FALSE }, { CKD_IBM_HYBRID_SHA224_KDF, 32, 16, { 0x32,0x3F,0xA3,0x16,0x9D,0x8E,0x9C,0x65,0x93,0xF5,0x94,0x76,0xBC,0x14,0x20,0x00 }, CK_TRUE, CK_TRUE }, { CKD_IBM_HYBRID_SHA256_KDF, 16, 0, {0x00}, CK_TRUE, CK_FALSE }, { CKD_IBM_HYBRID_SHA256_KDF, 32, 16, { 0x32,0x3F,0xA3,0x16,0x9D,0x8E,0x9C,0x65,0x93,0xF5,0x94,0x76,0xBC,0x14,0x20,0x00 }, CK_TRUE, CK_TRUE }, { CKD_IBM_HYBRID_SHA384_KDF, 16, 0, {0x00}, CK_TRUE, CK_FALSE }, { CKD_IBM_HYBRID_SHA384_KDF, 32, 16, { 0x32,0x3F,0xA3,0x16,0x9D,0x8E,0x9C,0x65,0x93,0xF5,0x94,0x76,0xBC,0x14,0x20,0x00 }, CK_TRUE, CK_TRUE }, { CKD_IBM_HYBRID_SHA512_KDF, 16, 0, {0x00}, CK_TRUE, CK_FALSE }, { CKD_IBM_HYBRID_SHA512_KDF, 32, 16, { 0x32,0x3F,0xA3,0x16,0x9D,0x8E,0x9C,0x65,0x93,0xF5,0x94,0x76,0xBC,0x14,0x20,0x00 }, CK_TRUE, CK_TRUE }, }; 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"; case CKD_IBM_HYBRID_NULL: return "CKD_IBM_HYBRID_NULL"; case CKD_IBM_HYBRID_SHA1_KDF: return "CKD_IBM_HYBRID_SHA1_KDF"; case CKD_IBM_HYBRID_SHA224_KDF: return "CKD_IBM_HYBRID_SHA224_KDF"; case CKD_IBM_HYBRID_SHA256_KDF: return "CKD_IBM_HYBRID_SHA256_KDF"; case CKD_IBM_HYBRID_SHA384_KDF: return "CKD_IBM_HYBRID_SHA384_KDF"; case CKD_IBM_HYBRID_SHA512_KDF: return "CKD_IBM_HYBRID_SHA512_KDF"; default: return "UNKNOWN"; } } #define NUM_KEM_INPUTS sizeof(kemInput)/sizeof(_kemParam) /* * Perform a HMAC sign to verify that the key is usable. */ CK_RV run_HMACSign(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE h_key1, CK_OBJECT_HANDLE h_key2, CK_ULONG key_len) { CK_MECHANISM mech = { .mechanism = CKM_SHA_1_HMAC, .pParameter = NULL, .ulParameterLen = 0 }; CK_BYTE data[32] = { 0 }; CK_BYTE mac[SHA1_HASH_SIZE] = { 0 }; CK_ULONG mac_len = sizeof(mac); CK_RV rc = CKR_OK; if (!mech_supported(SLOT_ID, CKM_SHA_1_HMAC)) { testcase_notice("Mechanism CKM_SHA_1_HMAC is not supported with slot " "%lu. Skipping key check", SLOT_ID); return CKR_OK; } if (!check_supp_keysize(SLOT_ID, CKM_SHA_1_HMAC, key_len * 8)) { testcase_notice("Mechanism CKM_SHA_1_HMAC can not be used with keys " "of size %lu. Skipping key check", key_len); return CKR_OK; } rc = funcs->C_SignInit(session, &mech, h_key1); if (rc != CKR_OK) { testcase_notice("C_SignInit rc=%s", p11_get_ckr(rc)); goto error; } /** do signing **/ rc = funcs->C_Sign(session, data, sizeof(data), mac, &mac_len); if (rc != CKR_OK) { testcase_notice("C_Sign rc=%s", p11_get_ckr(rc)); goto error; } rc = funcs->C_VerifyInit(session, &mech, h_key2); if (rc != CKR_OK) { testcase_notice("C_VerifyInit rc=%s", p11_get_ckr(rc)); goto error; } /** do verify **/ rc = funcs->C_Verify(session, data, sizeof(data), mac, mac_len); if (rc != CKR_OK) { testcase_notice("C_Verify rc=%s", p11_get_ckr(rc)); goto error; } error: return rc; } CK_RV ecdh_derive_secret(CK_SESSION_HANDLE session, CK_ULONG secret_key_len, CK_EC_KDF_TYPE kdf, CK_OBJECT_HANDLE *hybrid_key) { CK_OBJECT_HANDLE publ_key = CK_INVALID_HANDLE; CK_OBJECT_HANDLE priv_key = CK_INVALID_HANDLE; CK_ECDH1_DERIVE_PARAMS ecda_params; CK_MECHANISM mech; CK_RV rc; CK_BYTE pubkey_value[256]; CK_ATTRIBUTE extr_tmpl[] = { {CKA_EC_POINT, pubkey_value, sizeof(pubkey_value)}, }; CK_ULONG extr_tmpl_len = sizeof(extr_tmpl)/sizeof(CK_ATTRIBUTE); CK_OBJECT_CLASS class = CKO_SECRET_KEY; CK_KEY_TYPE key_type = CKK_GENERIC_SECRET; CK_BBOOL true = CK_TRUE; CK_BBOOL false = CK_FALSE; CK_ATTRIBUTE derive_tmpl[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &key_type, sizeof(key_type)}, {CKA_SENSITIVE, &false, sizeof(false)}, {CKA_VALUE_LEN, &secret_key_len, sizeof(CK_ULONG)}, {CKA_IBM_USE_AS_DATA, &true, sizeof(true)}, }; CK_ULONG secret_tmpl_len = sizeof(derive_tmpl) / sizeof(CK_ATTRIBUTE); if (!mech_supported(SLOT_ID, CKM_EC_KEY_PAIR_GEN)) { testcase_notice("Slot %u doesn't support CKM_EC_KEY_PAIR_GEN\n", (unsigned int) SLOT_ID); return CKR_FUNCTION_NOT_SUPPORTED; } rc = generate_EC_KeyPair(session, CKM_EC_KEY_PAIR_GEN, (CK_BYTE *)prime256v1, sizeof(prime256v1), &publ_key, &priv_key, CK_FALSE); if (rc != CKR_OK) { testcase_notice("generate_EC_KeyPair rc=%s", p11_get_ckr(rc)); goto error; } rc = funcs->C_GetAttributeValue(session, publ_key, extr_tmpl, extr_tmpl_len); if (rc != CKR_OK) { testcase_notice("C_GetAttributeValue: rc = %s", p11_get_ckr(rc)); goto error; } mech.mechanism = CKM_ECDH1_DERIVE; mech.pParameter = &ecda_params; mech.ulParameterLen = sizeof(ecda_params); memset(&ecda_params, 0, sizeof(ecda_params)); ecda_params.kdf = kdf; ecda_params.pPublicData = extr_tmpl[0].pValue; ecda_params.ulPublicDataLen = extr_tmpl[0].ulValueLen; rc = funcs->C_DeriveKey(session, &mech, priv_key, derive_tmpl, secret_tmpl_len, hybrid_key); if (rc != CKR_OK) { testcase_notice("C_DeriveKey: rc = %s", p11_get_ckr(rc)); goto error; } error: if (publ_key != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, publ_key); if (priv_key != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, priv_key); return rc; } CK_RV run_EnDecapsulateKyber(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE priv_key, CK_OBJECT_HANDLE publ_key, CK_ULONG secret_key_len, CK_IBM_KYBER_KDF_TYPE kdf, CK_BBOOL hybrid, CK_BBOOL prepend, const CK_BYTE *pSharedData, CK_ULONG ulSharedDataLen, const CK_BYTE *pCipher, CK_ULONG ulCipherLen, const CK_BYTE *pExpectedSecret, CK_ULONG ulExpectedSecret) { CK_MECHANISM mech; CK_IBM_KYBER_PARAMS kyber_params; CK_BYTE *cipher = NULL; CK_ULONG cipher_len = 0; CK_OBJECT_HANDLE secret_key1 = CK_INVALID_HANDLE; CK_OBJECT_HANDLE secret_key2 = CK_INVALID_HANDLE; CK_OBJECT_HANDLE hybrid_key = CK_INVALID_HANDLE; CK_OBJECT_HANDLE expected_secret_key = CK_INVALID_HANDLE; CK_RV rc; CK_OBJECT_CLASS class = CKO_SECRET_KEY; CK_KEY_TYPE key_type = CKK_GENERIC_SECRET; CK_BBOOL true = CK_TRUE; CK_BBOOL false = CK_FALSE; CK_ATTRIBUTE derive_tmpl[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &key_type, sizeof(key_type)}, {CKA_SENSITIVE, &false, sizeof(false)}, {CKA_VALUE_LEN, &secret_key_len, sizeof(secret_key_len)}, {CKA_SIGN, &true, sizeof(true)}, {CKA_VERIFY, &true, sizeof(true)}, }; CK_ULONG secret_tmpl_len = sizeof(derive_tmpl) / sizeof(CK_ATTRIBUTE); mech.mechanism = CKM_IBM_KYBER; mech.ulParameterLen = sizeof(kyber_params); mech.pParameter = &kyber_params; /* Query the slot, check if this mech if supported */ if (!mech_supported(SLOT_ID, mech.mechanism)) { testcase_skip("Slot %u doesn't support %s", (unsigned int) SLOT_ID, p11_get_ckm(&mechtable_funcs, mech.mechanism)); rc = CKR_OK; goto testcase_cleanup; } if (hybrid) { rc = ecdh_derive_secret(session, 32, CKD_IBM_HYBRID_NULL, &hybrid_key); if (rc != CKR_OK) { testcase_error("ecdh_derive_secret() rc = %s", p11_get_ckr(rc)); goto testcase_cleanup; } } if (pCipher != NULL && ulCipherLen != 0) { cipher_len = ulCipherLen; cipher = (CK_BYTE *)pCipher; goto decapsulate; } /* Perform encapsulation with public key */ memset(&kyber_params, 0, sizeof(kyber_params)); kyber_params.ulVersion = CK_IBM_KYBER_KEM_VERSION; kyber_params.mode = CK_IBM_KYBER_KEM_ENCAPSULATE; kyber_params.kdf = kdf; kyber_params.pSharedData = (CK_BYTE *)pSharedData; kyber_params.ulSharedDataLen = ulSharedDataLen; kyber_params.bPrepend = prepend; kyber_params.hSecret = hybrid_key; /* Size query */ rc = funcs->C_DeriveKey(session, &mech, publ_key, derive_tmpl, secret_tmpl_len, &secret_key1); if (rc != CKR_BUFFER_TOO_SMALL) { testcase_error("C_DeriveKey (size query) rc=%s (expected CKR_BUFFER_TOO_SMALL)", p11_get_ckr(rc)); goto testcase_cleanup; } cipher_len = kyber_params.ulCipherLen; cipher = calloc(cipher_len, sizeof(CK_BYTE)); if (cipher == NULL) { testcase_error("Can't allocate memory for %lu bytes", sizeof(CK_BYTE) * cipher_len); rc = CKR_HOST_MEMORY; goto testcase_cleanup; } kyber_params.ulCipherLen = cipher_len; kyber_params.pCipher = cipher; /* Encapsulation */ rc = funcs->C_DeriveKey(session, &mech, publ_key, derive_tmpl, secret_tmpl_len, &secret_key1); if (rc != CKR_OK) { testcase_error("C_DeriveKey (encapsulation) rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } decapsulate: /* Perform Decapsulation with private key */ memset(&kyber_params, 0, sizeof(kyber_params)); kyber_params.ulVersion = CK_IBM_KYBER_KEM_VERSION; kyber_params.mode = CK_IBM_KYBER_KEM_DECAPSULATE; kyber_params.kdf = kdf; kyber_params.pSharedData = (CK_BYTE *)pSharedData; kyber_params.ulSharedDataLen = ulSharedDataLen; kyber_params.bPrepend = prepend; kyber_params.hSecret = hybrid_key; kyber_params.ulCipherLen = cipher_len; kyber_params.pCipher = cipher; rc = funcs->C_DeriveKey(session, &mech, priv_key, derive_tmpl, secret_tmpl_len, &secret_key2); if (rc != CKR_OK) { testcase_error("C_DeriveKey (decapsulation) rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } if (secret_key1 != CK_INVALID_HANDLE) { rc = run_HMACSign(session, secret_key1, secret_key2, secret_key_len); if (rc != CKR_OK) { testcase_fail("Derived keys are not usable or not the same: %s", p11_get_ckr(rc)); goto testcase_cleanup; } } if (pExpectedSecret != NULL && ulExpectedSecret != 0) { rc = create_GenericSecretKey(session, CKK_GENERIC_SECRET, (CK_BYTE *)pExpectedSecret, ulExpectedSecret, &expected_secret_key); if (rc != CKR_OK) { testcase_fail("create_GenericSecretKey failed: %s", p11_get_ckr(rc)); goto testcase_cleanup; } rc = run_HMACSign(session, expected_secret_key, secret_key2, secret_key_len); if (rc != CKR_OK) { testcase_fail("Derived secret key is not the expected one: %s", p11_get_ckr(rc)); goto testcase_cleanup; } } rc = CKR_OK; testcase_cleanup: if (cipher != NULL && cipher != pCipher) free(cipher); if (secret_key1 != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, secret_key1); if (secret_key2 != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, secret_key2); if (hybrid_key != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, hybrid_key); if (expected_secret_key != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, expected_secret_key); return rc; } CK_RV run_EncrypDecryptKyber(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE priv_key, CK_OBJECT_HANDLE publ_key) { CK_MECHANISM mech; CK_BYTE_PTR data = NULL, encrypted = NULL, decrypted = NULL; CK_ULONG i, datalen, encrypted_len, decrypted_len; CK_RV rc; mech.mechanism = CKM_IBM_KYBER; mech.ulParameterLen = 0; mech.pParameter = NULL; datalen = 32; /* Kyber can encrypt blocks of 32 bytes */ /* Query the slot, check if this mech if supported */ if (!mech_supported(SLOT_ID, mech.mechanism)) { testcase_skip("Slot %u doesn't support %s", (unsigned int) SLOT_ID, p11_get_ckm(&mechtable_funcs, mech.mechanism)); rc = CKR_OK; goto testcase_cleanup; } data = calloc(datalen, sizeof(CK_BYTE)); if (data == NULL) { testcase_error("Can't allocate memory for %lu bytes", sizeof(CK_BYTE) * datalen); rc = CKR_HOST_MEMORY; goto testcase_cleanup; } for (i = 0; i < datalen; i++) { data[i] = (i + 1) % 255; } /* Encrypt */ 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; } rc = funcs->C_Encrypt(session, data, datalen, NULL, &encrypted_len); if (rc != CKR_OK) { testcase_error("C_Encrypt rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } encrypted = calloc(encrypted_len, sizeof(CK_BYTE)); if (encrypted == NULL) { testcase_error("Can't allocate memory for %lu bytes", sizeof(CK_BYTE) * encrypted_len); rc = CKR_HOST_MEMORY; goto testcase_cleanup; } rc = funcs->C_Encrypt(session, data, datalen, encrypted, &encrypted_len); if (rc != CKR_OK) { testcase_error("C_Encrypt rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } /* Decrypt */ 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; } rc = funcs->C_Decrypt(session, encrypted, encrypted_len, NULL, &decrypted_len); if (rc != CKR_OK) { testcase_error("C_Decrypt rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } decrypted = calloc(decrypted_len, sizeof(CK_BYTE)); if (decrypted == NULL) { testcase_error("Can't allocate memory for %lu bytes", sizeof(CK_BYTE) * decrypted_len); rc = CKR_HOST_MEMORY; goto testcase_cleanup; } rc = funcs->C_Decrypt(session, encrypted, encrypted_len, decrypted, &decrypted_len); if (rc != CKR_OK) { testcase_error("C_Decrypt rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } if (decrypted_len != datalen || memcmp(decrypted, data, datalen) != 0) { testcase_error("Decrypted data (%lu bytes) does not match original data (%lu bytes)", decrypted_len, datalen); goto testcase_cleanup; } rc = CKR_OK; testcase_cleanup: if (data) free(data); if (encrypted) free(encrypted); if (decrypted) free(decrypted); return rc; } CK_RV run_GenerateKyberKeyPairEnDecryptKEM(void) { 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_RV rc; testcase_rw_session(); testcase_user_login(); mech.mechanism = CKM_IBM_KYBER; mech.ulParameterLen = 0; mech.pParameter = NULL; /* query the slot, check if this mech is supported */ if (!mech_supported(SLOT_ID, mech.mechanism)) { testcase_skip("Slot %u doesn't support %s", (unsigned int) SLOT_ID, p11_get_ckm(&mechtable_funcs, mech.mechanism)); rc = CKR_OK; goto testcase_cleanup; } for (i = 0; i < 2 * num_variants; i++) { /* Setup attributes for public/private Kyber key */ CK_BBOOL attr_enc = TRUE; CK_BBOOL attr_dec = TRUE; CK_BBOOL attr_derive = TRUE; CK_ATTRIBUTE kyber_attr_private_keyform[] = { {CKA_DECRYPT, &attr_dec, sizeof(CK_BBOOL)}, {CKA_DERIVE, &attr_derive, sizeof(CK_BBOOL)}, {CKA_IBM_KYBER_KEYFORM, (CK_BYTE *)&variants[i % num_variants].keyform, sizeof(CK_ULONG)}, }; CK_ATTRIBUTE kyber_attr_public_keyform[] = { {CKA_ENCRYPT, &attr_enc, sizeof(CK_BBOOL)}, {CKA_DERIVE, &attr_derive, sizeof(CK_BBOOL)}, {CKA_IBM_KYBER_KEYFORM, (CK_BYTE *)&variants[i % num_variants].keyform, sizeof(CK_ULONG)}, }; CK_ATTRIBUTE kyber_attr_private_mode[] = { {CKA_DECRYPT, &attr_dec, sizeof(CK_BBOOL)}, {CKA_DERIVE, &attr_derive, sizeof(CK_BBOOL)}, {CKA_IBM_KYBER_MODE, (CK_BYTE *)variants[i % num_variants].oid, variants[i % num_variants].oid_len}, }; CK_ATTRIBUTE kyber_attr_public_mode[] = { {CKA_ENCRYPT, &attr_enc, sizeof(CK_BBOOL)}, {CKA_DERIVE, &attr_derive, sizeof(CK_BBOOL)}, {CKA_IBM_KYBER_MODE, (CK_BYTE *)variants[i % num_variants].oid, variants[i % num_variants].oid_len}, }; CK_ATTRIBUTE *kyber_attr_private = i < num_variants ? kyber_attr_private_keyform : kyber_attr_private_mode; CK_ATTRIBUTE *kyber_attr_public = i < num_variants ? kyber_attr_public_keyform : kyber_attr_public_mode; CK_ULONG num_kyber_attrs = (variants[i % num_variants].oid == NULL) ? 2 : 3; testcase_begin("Starting Kyber generate key pair with %s.", variants[i % num_variants].name); /* Generate Kyber key pair */ rc = funcs->C_GenerateKeyPair(session, &mech, kyber_attr_public, num_kyber_attrs, kyber_attr_private, num_kyber_attrs, &publ_key, &priv_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("C_GenerateKeyPair with %s (%s) not supported", variants[i % num_variants].name, i < num_variants ? "KEYFORM" : "MODE"); goto next; } else { testcase_new_assertion(); testcase_fail("C_GenerateKeyPair with %s (%s) failed, rc=%s", variants[i % num_variants].name, i < num_variants ? "KEYFORM" : "MODE", p11_get_ckr(rc)); goto testcase_cleanup; } } testcase_new_assertion(); testcase_pass("*Generate Kyber key pair with %s (%s) passed.", variants[i % num_variants].name, i < num_variants ? "KEYFORM" : "MODE"); testcase_new_assertion(); rc = run_EncrypDecryptKyber(session, priv_key, publ_key); if (rc != 0) { testcase_fail("run_EncrypDecryptKyber with %s failed.", variants[i % num_variants].name); goto next; } testcase_pass("*Encrypt & decrypt with %s passed.", variants[i % num_variants].name); for (j = 0; j < NUM_KEM_INPUTS; j++) { testcase_new_assertion(); rc = run_EnDecapsulateKyber(session, priv_key, publ_key, kemInput[j].secret_key_len, kemInput[j].kdf, kemInput[j].hybrid, kemInput[j].prepend, kemInput[j].shared_data, kemInput[j].shard_data_len, NULL, 0, NULL, 0); if (rc != 0) { testcase_fail("run_EnDecapsulateKyber with %s, %s, Shared data len %lu (index %lu) failed.", variants[i % num_variants].name, p11_get_ckd(kemInput[j].kdf), kemInput[j].shard_data_len, j); goto next; } testcase_pass("*%sEncapsulate & Decapsulate (KEM) with %s, %s, Shared data len %lu (index %lu) passed.", kemInput[j].hybrid ? "Hybrid " : "", variants[i % num_variants].name, p11_get_ckd(kemInput[j].kdf), kemInput[j].shard_data_len, j); } next: if (publ_key != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, publ_key); publ_key = CK_INVALID_HANDLE; if (priv_key != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, priv_key); priv_key = CK_INVALID_HANDLE; } 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_ImportKyberKeyPairKEM(void) { 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_RV rc; testcase_rw_session(); testcase_user_login(); /* query the slot, check if this mech is supported */ if (!mech_supported(SLOT_ID, CKM_IBM_KYBER)) { testcase_skip("Slot %u doesn't support CKM_IBM_KYBER", (unsigned int) SLOT_ID); rc = CKR_OK; goto testcase_cleanup; } for (i = 0; i < KYBER_TV_NUM; i++) { testcase_begin("Starting Kyber import key pair, KEM, %s index=%lu", kyber_tv[i].name, i); /* Create Kyber private key */ rc = create_KyberPrivateKey(session, kyber_tv[i].pkcs8, kyber_tv[i].pkcs8_len, kyber_tv[i].keyform, kyber_tv[i].sk, kyber_tv[i].sk_len, kyber_tv[i].pk, kyber_tv[i].pk_len, &priv_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("C_CreateObject with key form %lu not supported", kyber_tv[i].keyform); continue; } if (rc == CKR_POLICY_VIOLATION) { testcase_skip("Kyber key import is not allowed by policy"); continue; } testcase_new_assertion(); testcase_fail("C_CreateObject (Kyber Private Key) failed at i=%lu, " "rc=%s", i, p11_get_ckr(rc)); goto next; } testcase_new_assertion(); testcase_pass("*Import Kyber private key (%s) index=%lu passed.", kyber_tv[i].name, i); /* Create Kyber public key */ rc = create_KyberPublicKey(session, kyber_tv[i].spki, kyber_tv[i].spki_len, kyber_tv[i].keyform, kyber_tv[i].pk, kyber_tv[i].pk_len, &publ_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("C_CreateObject with key form %lu not supported", kyber_tv[i].keyform); continue; } if (rc == CKR_POLICY_VIOLATION) { testcase_skip("Kyber key import is not allowed by policy"); goto testcase_cleanup; } testcase_new_assertion(); testcase_fail("C_CreateObject (Kyber Public Key) failed at i=%lu, " "rc=%s", i, p11_get_ckr(rc)); goto next; } testcase_new_assertion(); testcase_pass("*Import Kyber public key (%s) index=%lu passed.", kyber_tv[i].name, i); testcase_new_assertion(); rc = run_EnDecapsulateKyber(session, priv_key, publ_key, kyber_tv[i].secret_len, CKD_NULL, CK_FALSE, CK_FALSE, NULL, 0, kyber_tv[i].cipher, kyber_tv[i].cipher_len, kyber_tv[i].secret, kyber_tv[i].secret_len); if (rc != 0) { testcase_fail("run_EnDecapsulateKyber with %s failed.", variants[i % num_variants].name); goto next; } testcase_pass("*Encapsulate & Decapsulate (KEM) with %s index=%lu passed.", variants[i % num_variants].name, i); next: /* 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(tmp_len, sizeof(CK_BYTE)); 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_KYBER; CK_OBJECT_HANDLE tmp_key = CK_INVALID_HANDLE; CK_BYTE unwrap_label[] = "unwrapped_private_Kyber_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_DERIVE, &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_TransferKyberKeyPair(void) { 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_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(); /* query the slot, check if this mech is supported */ if (!mech_supported(SLOT_ID, CKM_IBM_KYBER)) { testcase_skip("Slot %u doesn't support CKM_IBM_KYBER", (unsigned int) SLOT_ID); rc = CKR_OK; goto testcase_cleanup; } if (!mech_supported(SLOT_ID, CKM_AES_KEY_GEN)) { testcase_skip("Slot %u doesn't support CKM_AES_KEY_GEN", (unsigned int) SLOT_ID); rc = CKR_OK; goto testcase_cleanup; } if (!mech_supported_flags(SLOT_ID, CKM_AES_CBC_PAD, CKF_WRAP)) { testcase_skip("Slot %u doesn't support key wrapping with CKM_AES_CBC_PAD", (unsigned int) SLOT_ID); rc = CKR_OK; goto testcase_cleanup; } for (i = 0; i < KYBER_TV_NUM; i++) { testcase_begin("Starting Kyber transfer key pair, Encrypt/Decrypt %s index=%lu.", kyber_tv[i].name, i); /* Create Kyber private key */ rc = create_KyberPrivateKey(session, kyber_tv[i].pkcs8, kyber_tv[i].pkcs8_len, kyber_tv[i].keyform, kyber_tv[i].sk, kyber_tv[i].sk_len, kyber_tv[i].pk, kyber_tv[i].pk_len, &priv_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("C_CreateObject with key form %lu not supported", kyber_tv[i].keyform); continue; } if (rc == CKR_POLICY_VIOLATION) { testcase_skip("Kyber key import is not allowed by policy"); continue; } testcase_new_assertion(); testcase_fail ("C_CreateObject (Kyber Private Key) failed at i=%lu, rc=%s", i, p11_get_ckr(rc)); goto next; } testcase_new_assertion(); testcase_pass("*Import Kyber private key (%s) index=%lu passed.", kyber_tv[i].name, i); /* Create Kyber public key */ rc = create_KyberPublicKey(session, kyber_tv[i].spki, kyber_tv[i].spki_len, kyber_tv[i].keyform, kyber_tv[i].pk, kyber_tv[i].pk_len, &publ_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("C_CreateObject with key form %lu not supported", kyber_tv[i].keyform); continue; } if (rc == CKR_POLICY_VIOLATION) { testcase_skip("Kyber key import is not allowed by policy"); goto testcase_cleanup; } testcase_new_assertion(); testcase_fail ("C_CreateObject (Kyber Public Key) failed at i=%lu, rc=%s", i, p11_get_ckr(rc)); goto next; } testcase_new_assertion(); testcase_pass("*Import Kyber public key (%s) index=%lu passed.", kyber_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, CK_TRUE, &wkey_mech, &secret_key); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("AES key generation is not allowed by policy"); goto testcase_cleanup; } testcase_error("generate_AESKey, rc=%s", p11_get_ckr(rc)); goto next; } /* Setup wrapping mechanism */ wrap_mech.mechanism = CKM_AES_CBC_PAD; wrap_mech.pParameter = "0123456789abcdef"; wrap_mech.ulParameterLen = 16; /* Wrap Kyber 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 next; } testcase_pass("*Wrap Kyber private key (%s) index=%lu passed.", kyber_tv[i].name, i); /* Unwrap Kyber 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 next; } testcase_pass("*Unwrap Kyber private key (%s) index=%lu passed.", kyber_tv[i].name, i); free(wrapped_key); wrapped_key = NULL; /* Encrypt/Decrypt with unwrapped key */ testcase_new_assertion(); rc = run_EncrypDecryptKyber(session, unwrapped_key, publ_key); if (rc != 0) { testcase_fail("run_EncrypDecryptKyber with %s failed.", kyber_tv[i].name); goto next; } testcase_pass("*Encrypt & decrypt with unwrapped private key with %s index=%lu passed.", kyber_tv[i].name, i); testcase_new_assertion(); rc = run_EnDecapsulateKyber(session, unwrapped_key, publ_key, kyber_tv[i].secret_len, CKD_NULL, CK_FALSE, CK_FALSE, NULL, 0, kyber_tv[i].cipher, kyber_tv[i].cipher_len, kyber_tv[i].secret, kyber_tv[i].secret_len); if (rc != 0) { testcase_fail("run_EnDecapsulateKyber with %s failed.", variants[i % num_variants].name); goto next; } testcase_pass("*Encapsulate & Decapsulate (KEM) with unwrapped private key with %s index=%lu passed.", variants[i % num_variants].name, i); next: /* 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(); rv = run_GenerateKyberKeyPairEnDecryptKEM(); rv = run_ImportKyberKeyPairKEM(); rv = run_TransferKyberKeyPair(); testcase_print_result(); funcs->C_Finalize(NULL); return testcase_return(rv); } opencryptoki-opencryptoki-451d99c/testcases/crypto/ml_dsa.h000066400000000000000000013452061520105705100242650ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2026 * * 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 */ struct ML_DSA_TEST_VECTOR { char *name; CK_ULONG parameter_set; CK_ULONG priv_len; CK_BYTE priv[8192]; CK_ULONG priv_seed_len; CK_BYTE priv_seed[32]; CK_BYTE pub[8192]; CK_ULONG pub_len; /* The following is for KATs only */ CK_MECHANISM mech; CK_BYTE msg[8192]; CK_ULONG msg_len; CK_BYTE sig[8192]; CK_ULONG sig_len; }; struct ML_DSA_TEST_VECTOR ml_dsa_tv[] = { { .name = "ML-DSA 44 (priv only)", .parameter_set = CKP_ML_DSA_44, .priv = { 0xFD, 0x33, 0x89, 0x37, 0xE3, 0x17, 0xAD, 0x38, 0xBA, 0xEC, 0xF5, 0xE0, 0x43, 0x58, 0x0C, 0x59, 0xC8, 0x63, 0xBB, 0xDC, 0xDF, 0xD7, 0x41, 0x9D, 0x59, 0xD3, 0xC7, 0x9F, 0xD0, 0xB3, 0x15, 0x54, 0x38, 0x48, 0x10, 0x9D, 0x09, 0x98, 0xDB, 0xE7, 0x94, 0x8F, 0x53, 0x2D, 0xFD, 0xC2, 0xAD, 0xEA, 0x5C, 0x94, 0xDF, 0xC1, 0x91, 0xC2, 0x1E, 0x4C, 0xE3, 0xA8, 0x6E, 0x7B, 0x29, 0x57, 0x5E, 0x5E, 0x1E, 0x00, 0x9E, 0x4C, 0xF4, 0x0F, 0xE6, 0xDC, 0x56, 0xF4, 0x4C, 0xA1, 0x43, 0x83, 0x99, 0x4D, 0x16, 0x6A, 0xFA, 0x2F, 0xA3, 0x6E, 0xDF, 0xDC, 0x88, 0xF7, 0x6A, 0xC8, 0x32, 0x7D, 0xB0, 0x0C, 0x34, 0x5D, 0x47, 0xE8, 0xBE, 0x69, 0x2F, 0xC6, 0xFE, 0xC4, 0x8B, 0x0C, 0xD2, 0xB3, 0x51, 0x32, 0xB6, 0x6C, 0x7D, 0x5F, 0x8B, 0x6A, 0x28, 0x34, 0x0B, 0x16, 0x45, 0x33, 0x5D, 0x36, 0x86, 0x68, 0xC1, 0xA0, 0x89, 0x60, 0x88, 0x69, 0x13, 0x11, 0x32, 0x1B, 0x39, 0x40, 0x02, 0xA1, 0x70, 0xDC, 0xB0, 0x80, 0x12, 0x08, 0x45, 0x21, 0xA7, 0x4C, 0x91, 0x36, 0x05, 0x12, 0x46, 0x31, 0x11, 0x32, 0x72, 0x23, 0x12, 0x44, 0xD1, 0x88, 0x49, 0x9B, 0xA2, 0x71, 0x01, 0xC0, 0x10, 0x01, 0x41, 0x12, 0x0C, 0xA2, 0x8C, 0xC1, 0xB2, 0x68, 0xD2, 0x22, 0x65, 0x20, 0x85, 0x8C, 0x24, 0xC8, 0x09, 0x19, 0x08, 0x06, 0x99, 0x22, 0x66, 0x5B, 0x42, 0x61, 0x5B, 0xB8, 0x40, 0x01, 0x44, 0x62, 0xE4, 0xA2, 0x00, 0x49, 0x24, 0x50, 0x01, 0x21, 0x10, 0x9C, 0x38, 0x80, 0xDB, 0xC6, 0x05, 0xA1, 0x16, 0x4A, 0xC8, 0x12, 0x6A, 0x19, 0x05, 0x00, 0x11, 0x06, 0x8E, 0x04, 0x95, 0x41, 0x9A, 0xC6, 0x85, 0x99, 0xB2, 0x28, 0x5C, 0xA8, 0x68, 0xA0, 0x42, 0x68, 0xD1, 0x28, 0x4C, 0x04, 0x85, 0x68, 0x0A, 0x34, 0x52, 0x21, 0x46, 0x4C, 0xE0, 0xA0, 0x70, 0x4B, 0x16, 0x80, 0x8B, 0x32, 0x72, 0xC2, 0xA6, 0x05, 0xDB, 0x92, 0x08, 0x03, 0x28, 0x21, 0xCC, 0x20, 0x72, 0x4A, 0xB4, 0x24, 0x23, 0x24, 0x49, 0x20, 0xC3, 0x41, 0x11, 0x24, 0x81, 0x5C, 0x48, 0x2E, 0x08, 0x14, 0x88, 0x99, 0x24, 0x2A, 0x18, 0xB5, 0x8D, 0xD3, 0x14, 0x90, 0x83, 0x08, 0x50, 0x0A, 0x32, 0x8D, 0x44, 0x34, 0x70, 0xE2, 0x44, 0x4D, 0x0B, 0xB6, 0x2C, 0xCB, 0xC2, 0x84, 0x23, 0xA8, 0x64, 0x0B, 0x49, 0x51, 0x1A, 0x06, 0x8A, 0x0B, 0x01, 0x44, 0xDB, 0x16, 0x42, 0x4A, 0xC4, 0x8C, 0x82, 0x38, 0x52, 0xD8, 0x02, 0x04, 0x21, 0x03, 0x90, 0x89, 0x88, 0x2C, 0x84, 0xC0, 0x40, 0xC8, 0x08, 0x8A, 0x93, 0x34, 0x4A, 0xE1, 0x42, 0x81, 0x98, 0x48, 0x31, 0xA3, 0x14, 0x6E, 0x20, 0xA8, 0x11, 0x9B, 0x90, 0x6C, 0x81, 0x86, 0x28, 0x98, 0x24, 0x21, 0x0B, 0xC0, 0x91, 0x64, 0x22, 0x2D, 0xA1, 0xB2, 0x71, 0x82, 0x30, 0x10, 0x8C, 0x28, 0x65, 0x90, 0xB6, 0x0D, 0x01, 0x90, 0x64, 0xE4, 0x80, 0x45, 0x51, 0x32, 0x11, 0x89, 0x94, 0x6D, 0x0C, 0x38, 0x32, 0xCA, 0xC4, 0x48, 0x1C, 0x46, 0x0C, 0x01, 0x18, 0x0A, 0xC1, 0x94, 0x0D, 0x80, 0x10, 0x22, 0x04, 0x34, 0x8D, 0x24, 0xB5, 0x40, 0x20, 0x42, 0x21, 0x24, 0x86, 0x2C, 0xD4, 0xC0, 0x90, 0x10, 0x01, 0x4E, 0x22, 0x29, 0x32, 0x99, 0x12, 0x6D, 0x5C, 0x90, 0x61, 0x01, 0x94, 0x64, 0x0B, 0xB3, 0x8D, 0x1A, 0x40, 0x05, 0xE1, 0x46, 0x41, 0x00, 0xC2, 0x85, 0x61, 0xC0, 0x08, 0x24, 0x34, 0x40, 0x14, 0x09, 0x30, 0x0C, 0x24, 0x01, 0x02, 0xC4, 0x80, 0x0C, 0x02, 0x88, 0xCB, 0x28, 0x30, 0xDA, 0x26, 0x8E, 0xC0, 0x08, 0x22, 0x24, 0x27, 0x4E, 0x01, 0x96, 0x20, 0x58, 0x40, 0x46, 0x9B, 0x84, 0x61, 0xC4, 0x42, 0x26, 0x24, 0x25, 0x89, 0x18, 0xB1, 0x88, 0x8C, 0x80, 0x70, 0xC2, 0x28, 0x61, 0x52, 0x16, 0x52, 0x61, 0x06, 0x11, 0x21, 0x83, 0x0D, 0x0C, 0x29, 0x04, 0x54, 0x46, 0x12, 0xE3, 0x28, 0x82, 0x01, 0x02, 0x31, 0x12, 0x90, 0x51, 0x53, 0x40, 0x41, 0xE2, 0x20, 0x41, 0x9A, 0xB4, 0x8C, 0xD0, 0x02, 0x44, 0x0A, 0x13, 0x10, 0x11, 0x99, 0x21, 0x09, 0x93, 0x8D, 0x94, 0x48, 0x66, 0x24, 0xC5, 0x48, 0xD8, 0x02, 0x05, 0xC9, 0x04, 0x66, 0xC0, 0x82, 0x88, 0x4C, 0x06, 0x11, 0x4B, 0x04, 0x0E, 0xA2, 0x40, 0x02, 0x22, 0xC0, 0x2D, 0x23, 0x49, 0x8A, 0x8B, 0x26, 0x72, 0x14, 0x96, 0x71, 0x14, 0x89, 0x65, 0xA1, 0x94, 0x31, 0xCA, 0x92, 0x2D, 0x1A, 0xC7, 0x6C, 0x22, 0x43, 0x40, 0x1C, 0x09, 0x4A, 0xD2, 0x04, 0x08, 0x88, 0x44, 0x68, 0xE0, 0x24, 0x80, 0xE3, 0xC8, 0x90, 0x18, 0xC5, 0x84, 0x08, 0xB2, 0x48, 0xA0, 0xC8, 0x70, 0x0C, 0x40, 0x44, 0xE4, 0x26, 0x24, 0x09, 0x03, 0x4E, 0x19, 0x95, 0x51, 0xC9, 0x36, 0x8A, 0x99, 0x40, 0x40, 0x9A, 0x38, 0x8A, 0x61, 0x16, 0x82, 0x20, 0x97, 0x48, 0xCA, 0x02, 0x31, 0x12, 0x91, 0x68, 0x00, 0x32, 0x20, 0x0B, 0x33, 0x81, 0x90, 0x26, 0x32, 0x1A, 0x00, 0x2C, 0x01, 0x07, 0x72, 0x61, 0xA6, 0x31, 0x0B, 0x30, 0x84, 0x91, 0x26, 0x10, 0x12, 0x42, 0x6D, 0x23, 0xA4, 0x84, 0xD1, 0x26, 0x61, 0x13, 0xA1, 0x8D, 0x23, 0xC1, 0x85, 0x01, 0xA6, 0x04, 0x09, 0xB9, 0x71, 0x8B, 0x04, 0x69, 0xC2, 0x32, 0x50, 0x14, 0xC3, 0x30, 0xC9, 0xB4, 0x61, 0xCB, 0x44, 0x09, 0x93, 0x10, 0x29, 0x13, 0x39, 0x62, 0xC1, 0x16, 0x88, 0x89, 0x02, 0x30, 0x09, 0x87, 0x81, 0x0A, 0x46, 0x0E, 0xA0, 0x02, 0x8E, 0xA4, 0x00, 0x2E, 0x12, 0x39, 0x02, 0x41, 0x48, 0x90, 0x23, 0x04, 0x8C, 0x61, 0x98, 0x89, 0xE2, 0x30, 0x65, 0x8A, 0x48, 0x25, 0x09, 0x16, 0x60, 0x04, 0x19, 0x04, 0xC3, 0x22, 0x8A, 0x0B, 0x84, 0x24, 0xDC, 0x46, 0x52, 0x00, 0xA6, 0x90, 0x10, 0x35, 0x06, 0xE3, 0x38, 0x22, 0x18, 0x41, 0x28, 0xD8, 0x18, 0x90, 0x91, 0x22, 0x80, 0x50, 0xC0, 0x71, 0x83, 0xC6, 0x50, 0x50, 0x28, 0x24, 0x64, 0x34, 0x44, 0x1C, 0x96, 0x28, 0xCB, 0x80, 0x80, 0x22, 0x13, 0x8D, 0x9A, 0x46, 0x31, 0x94, 0x44, 0x8A, 0x49, 0x36, 0x8D, 0xCC, 0x92, 0x68, 0x1B, 0x97, 0x90, 0x03, 0xA0, 0x4C, 0xC9, 0x24, 0x4C, 0x08, 0x35, 0x85, 0xA4, 0x26, 0x84, 0xDA, 0x34, 0x06, 0x00, 0x04, 0x69, 0x04, 0x41, 0x42, 0x98, 0x34, 0x71, 0x49, 0xA0, 0x60, 0x58, 0xC6, 0x11, 0x11, 0x35, 0x26, 0x01, 0x82, 0x50, 0x24, 0xC0, 0x70, 0x14, 0x20, 0x88, 0x75, 0xA6, 0xD6, 0xED, 0x67, 0x8C, 0x60, 0x85, 0x1A, 0x0D, 0x33, 0xDB, 0x75, 0xBD, 0xEB, 0x35, 0x9C, 0xFF, 0xC9, 0x41, 0xCE, 0x9A, 0xE3, 0xD5, 0x75, 0xE6, 0xCE, 0x47, 0x58, 0xD3, 0xE9, 0x8C, 0x2F, 0x36, 0xAE, 0xD6, 0x18, 0x0A, 0x64, 0xC3, 0x85, 0x9D, 0xC2, 0xD3, 0x79, 0x50, 0x18, 0x66, 0x5E, 0x98, 0x1D, 0x15, 0xE9, 0xFF, 0x6E, 0x00, 0x33, 0x9E, 0xFD, 0x97, 0x5B, 0x84, 0x3D, 0x1A, 0x00, 0x02, 0x49, 0x2A, 0x3D, 0xE1, 0x3D, 0x18, 0x9D, 0xF1, 0xE4, 0xD8, 0x35, 0x09, 0xFD, 0xFC, 0xC1, 0xC0, 0x10, 0x8C, 0x0D, 0x2F, 0xD1, 0x22, 0xDC, 0x46, 0x1D, 0x55, 0x76, 0x2F, 0x85, 0x1C, 0x02, 0x1B, 0x69, 0xB3, 0x56, 0x36, 0x5B, 0xF6, 0x4E, 0x11, 0x3E, 0xEB, 0xB3, 0xC0, 0x8B, 0xF3, 0x8A, 0x1F, 0xFC, 0xEE, 0x91, 0x6A, 0x96, 0xA9, 0xEA, 0x75, 0xE3, 0x15, 0x0A, 0xE3, 0x5B, 0xAC, 0x2F, 0xD3, 0x09, 0xE3, 0x80, 0xA4, 0x6E, 0xC3, 0x6C, 0x03, 0x8E, 0xC1, 0xA0, 0xCF, 0xF7, 0xF9, 0x11, 0xDC, 0x77, 0x2D, 0xBC, 0x81, 0x32, 0xE0, 0x34, 0xFE, 0xC9, 0x83, 0x96, 0xD6, 0x29, 0xCF, 0x6A, 0x72, 0xCA, 0xB2, 0x51, 0xC2, 0x17, 0xB4, 0xEA, 0x38, 0x8E, 0xCA, 0x94, 0xB7, 0x70, 0xBD, 0x7D, 0xBC, 0x28, 0xF0, 0xA9, 0x68, 0x41, 0xC7, 0x3C, 0x31, 0x97, 0xC3, 0x5B, 0x68, 0x9F, 0xC9, 0x68, 0x89, 0xB1, 0xA8, 0xF2, 0x07, 0x72, 0x20, 0xF6, 0xE2, 0x1E, 0x83, 0xF2, 0xDD, 0x02, 0xF9, 0xDD, 0x0C, 0x3D, 0x55, 0xF2, 0x8B, 0x86, 0xF0, 0x19, 0xC0, 0xAF, 0xC1, 0xB1, 0xA8, 0x83, 0xAE, 0x6F, 0xD7, 0xC3, 0x3D, 0xED, 0x4E, 0x9C, 0x4C, 0xA5, 0xF3, 0x11, 0x54, 0x85, 0x5B, 0x8E, 0xBD, 0x57, 0xBE, 0xBE, 0x76, 0x9D, 0x82, 0x0D, 0xFE, 0xCE, 0x09, 0xD9, 0xD7, 0x19, 0xB7, 0x76, 0xA9, 0xF6, 0x93, 0x8C, 0xDD, 0x9F, 0xA5, 0xE8, 0xC9, 0xFA, 0xB1, 0xBA, 0x35, 0x8E, 0x4E, 0x1C, 0x6B, 0x0C, 0x3F, 0x67, 0x4E, 0x37, 0x11, 0x00, 0x48, 0x3A, 0x24, 0xD0, 0x31, 0x1B, 0xAF, 0x66, 0xBB, 0x6C, 0xFB, 0x4A, 0x7E, 0xD2, 0xEC, 0x92, 0x91, 0x17, 0x54, 0xDD, 0xFB, 0xA4, 0xEA, 0x98, 0x53, 0x3D, 0x65, 0x87, 0xD9, 0x06, 0x99, 0x98, 0x62, 0xDB, 0xEB, 0xA2, 0x54, 0x54, 0x2E, 0x2E, 0x46, 0x54, 0x78, 0xBC, 0xE3, 0xC4, 0x08, 0x13, 0xDB, 0xD9, 0xD2, 0x49, 0x2E, 0x83, 0x5F, 0x22, 0x3A, 0x69, 0x02, 0x39, 0x68, 0x17, 0x50, 0x63, 0x09, 0xA5, 0x0A, 0xC5, 0xF0, 0x48, 0x9C, 0x9E, 0x75, 0x20, 0x01, 0x9A, 0x97, 0xF6, 0xB2, 0xDF, 0x7A, 0x5B, 0x10, 0xB6, 0xED, 0x96, 0xAE, 0x2C, 0xD4, 0xAB, 0x37, 0x7B, 0x0C, 0x3F, 0xFB, 0x56, 0x03, 0xD8, 0xB7, 0xFB, 0xCE, 0xE2, 0x04, 0x88, 0x22, 0xE2, 0x31, 0xA6, 0x65, 0xC4, 0x70, 0xB7, 0x6F, 0x63, 0xED, 0xD6, 0xC6, 0xFF, 0x67, 0x3A, 0x23, 0xA5, 0x95, 0x57, 0x3C, 0xE7, 0x67, 0x88, 0xAA, 0xA2, 0x11, 0x15, 0x4E, 0xDA, 0x10, 0x17, 0x0B, 0xE2, 0x77, 0x1C, 0xD9, 0x31, 0xB3, 0x31, 0xD9, 0x85, 0x43, 0xE4, 0x76, 0x27, 0xD2, 0x85, 0x94, 0xA0, 0xDE, 0x64, 0x40, 0xCB, 0x2B, 0x2B, 0x00, 0x58, 0x4D, 0xB9, 0x3A, 0x5C, 0x64, 0xB3, 0x2B, 0x1D, 0x9B, 0x1A, 0x9A, 0x8D, 0x3E, 0x24, 0x3D, 0x6C, 0x60, 0xF4, 0xCC, 0x61, 0x68, 0x40, 0xEE, 0x1F, 0xA2, 0xB1, 0x1C, 0x33, 0x80, 0x7F, 0x61, 0x05, 0xA0, 0x2E, 0x6C, 0x40, 0xAF, 0x4A, 0x0B, 0x7B, 0x10, 0x01, 0x28, 0x1E, 0xA7, 0x17, 0xBC, 0xEB, 0xA0, 0xE3, 0xF2, 0x3F, 0x98, 0xC0, 0x22, 0x1D, 0x30, 0xA5, 0xF3, 0x2F, 0x94, 0x62, 0x11, 0xB5, 0xC0, 0x9D, 0x84, 0x71, 0x40, 0xD1, 0xA8, 0xC8, 0x13, 0xEA, 0x58, 0x27, 0x38, 0x8C, 0x24, 0x85, 0xAB, 0x8C, 0x0D, 0x1F, 0x9D, 0x4A, 0x95, 0x23, 0x38, 0x72, 0x28, 0x64, 0xE9, 0x47, 0x68, 0xA4, 0x0C, 0xE0, 0x4C, 0xC9, 0x69, 0xA6, 0x3C, 0x2D, 0xCE, 0x16, 0x9B, 0xC4, 0x08, 0xEB, 0x1D, 0x30, 0x2E, 0x7E, 0xEE, 0x15, 0x05, 0x4A, 0x03, 0x86, 0xBF, 0x9E, 0x73, 0xFD, 0xA0, 0x9F, 0x78, 0xF2, 0x10, 0x1B, 0x9C, 0x6F, 0x09, 0xC2, 0x78, 0xF4, 0x35, 0x28, 0x0D, 0xC9, 0xE9, 0x5F, 0xBE, 0x74, 0xE7, 0xDD, 0x7C, 0xC6, 0xCA, 0x75, 0x9A, 0xB4, 0xF4, 0xC8, 0xFD, 0x42, 0xC6, 0xDD, 0x42, 0x6B, 0x6D, 0xDE, 0xB9, 0xEA, 0x8E, 0xD2, 0x49, 0xAE, 0x4F, 0x76, 0x9F, 0x9B, 0x06, 0x42, 0x6F, 0x20, 0x30, 0xF4, 0x05, 0x4D, 0x41, 0xAC, 0x08, 0xBF, 0x63, 0xDC, 0x5C, 0x3E, 0x5A, 0xBF, 0xE5, 0xCB, 0xBF, 0x01, 0x06, 0x26, 0x29, 0x59, 0x94, 0x44, 0xF3, 0x47, 0x4B, 0xDE, 0x57, 0x17, 0x10, 0x03, 0x01, 0x2B, 0x52, 0x3D, 0x63, 0x9C, 0x81, 0x25, 0xEF, 0x0F, 0x6A, 0x10, 0xDF, 0x67, 0xFA, 0x3D, 0xA8, 0x06, 0x53, 0x84, 0x43, 0x70, 0xA9, 0x32, 0x5A, 0xCD, 0xE8, 0xF8, 0xBF, 0xC5, 0x8E, 0xF3, 0x1B, 0xBA, 0xB4, 0x55, 0xB5, 0x1D, 0x9C, 0x07, 0x83, 0xA9, 0xA5, 0x8F, 0x3D, 0x42, 0xC6, 0xE1, 0x71, 0x6C, 0x6F, 0x93, 0xA7, 0x2F, 0x41, 0xF6, 0x9C, 0xDD, 0xFC, 0x28, 0x5D, 0x20, 0xD0, 0xE6, 0x9E, 0xF7, 0xC5, 0xB4, 0xBD, 0xDE, 0xF7, 0xF0, 0x7C, 0x02, 0xD9, 0xF7, 0x6E, 0x7F, 0xCB, 0xDC, 0x7F, 0x76, 0xC2, 0x82, 0xB9, 0x51, 0x4B, 0xD2, 0x0B, 0xA9, 0x53, 0x56, 0xF8, 0x86, 0xF3, 0x2E, 0x4E, 0xCB, 0x2B, 0xF2, 0xE4, 0x1B, 0xDA, 0x35, 0xD6, 0x0F, 0x1A, 0xD1, 0xD3, 0x9A, 0x2B, 0x2F, 0x94, 0x6C, 0x02, 0x25, 0x94, 0x71, 0x99, 0x40, 0x6F, 0x36, 0x2E, 0x08, 0x1E, 0x8F, 0xD4, 0x29, 0x02, 0x9B, 0x81, 0x3A, 0x1E, 0xC0, 0xEB, 0x75, 0xBD, 0xF7, 0x55, 0x7F, 0xE3, 0xDE, 0x82, 0xEF, 0xB1, 0x5F, 0x05, 0x9B, 0x8E, 0x5D, 0xA2, 0x63, 0x39, 0x78, 0x7C, 0x52, 0xA1, 0xCD, 0x2F, 0xDC, 0x8A, 0x3D, 0x21, 0x6D, 0xA1, 0xFC, 0xA2, 0xC4, 0x20, 0xD7, 0x72, 0xCC, 0xE5, 0x4A, 0x6F, 0x70, 0x72, 0x9D, 0xD0, 0xEC, 0x82, 0xBD, 0x55, 0xC0, 0x1C, 0x92, 0x4C, 0xAF, 0xBC, 0x82, 0xF8, 0x9A, 0xC3, 0x92, 0x3A, 0x04, 0x24, 0xD4, 0xF0, 0xCD, 0x6D, 0xA6, 0x6B, 0x2A, 0xA1, 0xA9, 0x41, 0xDB, 0xFF, 0x81, 0x96, 0x30, 0xF8, 0x39, 0xAE, 0x8A, 0xAA, 0x26, 0xC5, 0x74, 0xA0, 0x1F, 0x90, 0x12, 0x80, 0xF4, 0xBB, 0x6C, 0xC7, 0xC4, 0x3F, 0xD1, 0xF8, 0xA0, 0x8B, 0x88, 0x76, 0xEE, 0xB7, 0xCC, 0x25, 0xBF, 0xC2, 0x85, 0xE0, 0xBD, 0xC6, 0xDD, 0x3D, 0x2C, 0x8C, 0x7F, 0x5F, 0x2F, 0x5A, 0xC7, 0x9F, 0x86, 0xD3, 0x2F, 0xEA, 0xE2, 0x2C, 0x97, 0x17, 0x66, 0xAF, 0xD5, 0x33, 0x17, 0xEE, 0x36, 0xEB, 0x50, 0x72, 0x3D, 0xC8, 0x1A, 0xAE, 0x5A, 0x63, 0x85, 0x93, 0x83, 0x74, 0xFF, 0xEA, 0x94, 0xE0, 0x82, 0xE0, 0xB4, 0x83, 0x2D, 0x22, 0x32, 0x5D, 0x0F, 0x33, 0x8E, 0x1D, 0xAD, 0x67, 0x2E, 0x06, 0x07, 0xF7, 0xB7, 0x61, 0xD1, 0x3A, 0xEF, 0x54, 0x34, 0x22, 0x92, 0x3D, 0x78, 0xEC, 0x6B, 0x55, 0x6D, 0xBC, 0x4B, 0x13, 0x15, 0x37, 0xC7, 0x0C, 0xC8, 0xAF, 0x02, 0x7F, 0x7E, 0x28, 0xEC, 0xE2, 0x50, 0x9F, 0xDF, 0x8E, 0x90, 0x35, 0x16, 0xEF, 0x8A, 0x07, 0xF4, 0xA8, 0x53, 0x53, 0x96, 0xAC, 0x82, 0xBE, 0x6C, 0x03, 0x65, 0x7C, 0x94, 0x7E, 0xFF, 0x60, 0x18, 0x82, 0xC5, 0xF8, 0xDA, 0xCE, 0x9F, 0xE0, 0x0E, 0x08, 0xEA, 0xA2, 0x3B, 0xF8, 0xC9, 0x50, 0xB2, 0x1D, 0x9B, 0x07, 0xD0, 0xDE, 0x07, 0x23, 0x8D, 0x35, 0xD0, 0x8D, 0xD4, 0xB5, 0x92, 0xC1, 0x24, 0x8B, 0xF4, 0x4B, 0xAF, 0x14, 0xB7, 0x70, 0x74, 0xF0, 0x32, 0xB1, 0xC3, 0xE9, 0xB2, 0x78, 0x58, 0x4B, 0x09, 0x95, 0x3C, 0x18, 0xDB, 0x6E, 0x3E, 0x05, 0x79, 0xC5, 0xA4, 0x06, 0x5A, 0xBA, 0x43, 0xF9, 0x64, 0x0B, 0x79, 0x49, 0x15, 0xD3, 0xB1, 0xC5, 0x5E, 0xF4, 0x08, 0xF7, 0x86, 0x15, 0x6F, 0xEE, 0x50, 0x90, 0x9F, 0x98, 0x02, 0xD9, 0x36, 0x7D, 0x2E, 0x5F, 0xEF, 0xBF, 0xF2, 0x64, 0x38, 0xAF, 0x9D, 0xE2, 0xCF, 0x5B, 0x7B, 0x41, 0x08, 0x28, 0x0E, 0x33, 0x2A, 0x04, 0x4A, 0xA6, 0xC4, 0xDE, 0x75, 0x59, 0x61, 0x07, 0x64, 0xBB, 0x7C, 0x7A, 0x0C, 0x47, 0xF0, 0xD1, 0xC6, 0xD7, 0xA9, 0x47, 0x39, 0xEA, 0xA6, 0x4F, 0x5B, 0x67, 0xDA, 0x9A, 0xDB, 0x5E, 0x3B, 0x95, 0x5A, 0xD1, 0x7D, 0x57, 0x84, 0x10, 0xCB, 0x61, 0xC4, 0x50, 0xE1, 0xF6, 0x85, 0xCC, 0xEE, 0xDC, 0x66, 0x83, 0xEA, 0x88, 0x70, 0x56, 0xFE, 0x4F, 0x08, 0xBF, 0x0A, 0x19, 0x0F, 0x40, 0xEC, 0x65, 0x3D, 0xEC, 0x91, 0x26, 0x3D, 0x9B, 0x82, 0x9D, 0xAE, 0x23, 0x3D, 0xD8, 0xD4, 0x79, 0x0B, 0xD5, 0xC2, 0x79, 0x65, 0xA9, 0x53, 0x56, 0x96, 0xA0, 0xE0, 0x67, 0xA0, 0xF4, 0xE5, 0xFC, 0x44, 0x5D, 0x4D, 0xE1, 0x58, 0x92, 0x50, 0xEC, 0x1F, 0x82, 0xED, 0xA2, 0x95, 0x7B, 0xC7, 0x3A, 0x77, 0xA9, 0xE9, 0x90, 0xCA, 0x29, 0xD3, 0x08, 0xB3, 0x8D, 0xA6, 0x63, 0x68, 0x2B, 0xFF, 0xBB, 0x48, 0x12, 0x8D, 0xB7, 0x73, 0xA3, 0xD2, 0xC6, 0x5D, 0xE4, 0x29, 0xF3, 0x8E, 0x16, 0xCF, 0x98, 0xCB, 0x5C, 0xCD, 0x10, 0x3F, 0xAB, 0x0C, 0xF3, 0x58, 0x22, 0x72, 0x8C, 0x75, 0xF0, 0x26, 0x4E, 0x1D, 0x97, 0x06, 0xB6, 0xF2, 0x20, 0xA9, 0x9D, 0x65, 0xBD, 0xE9, 0xC8, 0x6F, 0x20, 0x32, 0x82, 0xC9, 0x1A, 0xE7, 0xD5, 0xB9, 0x33, 0xBA, 0x99, 0x29, 0xD5, 0x4C, 0x55, 0xDA, 0x7B, 0x15, 0xB7, 0xA5, 0x03, 0xAF, 0xD4, 0xD0, 0xB1, 0xDE, 0xA4, 0x17, 0x20, 0xAF, 0x20, 0x0C, 0x8E, 0xDB, 0x11, 0x79, 0xE5, 0x57, 0xB7, 0xA3, 0xA1, 0xD3, 0xFC, 0xB5, 0x07, 0x88, 0x10, 0x4E, 0x5E, 0xF3, 0xD7, 0x02, 0x97, 0xDE, 0x6F, 0xF5, 0xFD, 0x84, 0xB6, 0xA9, 0xB1, 0x41, 0x45, 0x17, 0xB9, 0x8A, 0x73, 0x14, 0xBE, 0xC5, 0x93, 0x36, 0x68, 0x68, 0xD2, 0xF2, 0x02, 0xBB, 0xBF, 0x42, 0x4F, 0x93, 0x3F, 0x23, 0x8D, 0xBF, 0x36, 0xCC, 0x58, 0x55, 0x11, 0x86, 0x1B, 0x81, 0x15, 0x24, 0x56, 0x1A, 0xF4, 0x96, 0xC9, 0xD6, 0x24, 0xB7, 0x9A, 0xA6, 0x51, 0xFC, 0xDD, 0xC5, 0xC4, 0x8D, 0x4E, 0xBE, 0x4B, 0xBD, 0x5F, 0xD4, 0xF1, 0x89, 0x5D, 0xD4, 0x0E, 0xA4, 0x65, 0x43, 0x69, 0x13, 0xD3, 0xFB, 0x74, 0x94, 0xF4, 0xBD, 0x88, 0xE2, 0x33, 0xA8, 0x09, 0x87, 0x87, 0x1A, 0xFF, 0xA9, 0xE1, 0x4F, 0x31, 0x55, 0x3E, 0x49, 0x21, 0xA1, 0xD1, 0xD2, 0x69, 0x4A, 0x81, 0xA1, 0xFA, 0x8C, 0xA9, 0xBF, 0xDF, 0x04, 0x03, 0xFD, 0x88, 0x50, 0xFA, 0x4B, 0x4F, 0xA2, 0x1A, 0x11, 0xB1, 0xF2, 0x00, 0xF9, 0x13, 0xC2, 0xE1, 0x7D, 0x9A, 0xF8, 0xC1, 0xD4, 0xAC, 0x8D, 0xAA, 0x7D, 0xD3, 0x0D, 0x38, 0xF1, 0x51, 0x33, 0x42, 0xA9, 0x6A, 0x54, 0x09, 0xF3, 0x2F, 0x4F, 0x24, 0xED, 0x63, 0xF2, 0xB8, 0xF9, 0x48, 0x77, 0xEB, 0xD1, 0xBD, 0xDD, 0x9A, 0xB5, 0x3F, 0xF7, 0x1F, 0x1A, 0xAB, 0xAD, 0xBF, 0xA3, 0x2A, 0xAF, 0x99, 0xEF, 0xC9, 0xAE, 0x57, 0x92, 0x4C, 0xAD, 0x4B, 0x1F, 0x5E, 0xB5, 0x57, 0xCB, 0x5B, 0xA9, 0xAE, 0x05, 0xD8, 0xA4, 0xB3, 0x22, 0x1B, 0xCC, 0x1B, 0xAA, 0xAA, 0x70, 0x4E, 0x0F, 0x0E, 0x00, 0x63, 0x9A, 0x44, 0x94, 0x0A, 0x79, 0x21, 0x24, 0xD1, 0x88, 0xA0, 0xA7, 0x28, 0x96, 0xF9, 0x06, 0x5A, 0x16, 0x5E, 0x98, 0x1A, 0x3A, 0x72, 0xF7, 0x5F, 0x9E, 0xAF, 0x69, 0x23, 0x2C, 0x8E, 0x0E, 0x61, 0xEC, 0xE4, 0x7E, 0xAD, 0xE6, 0xF0, 0x8A, 0x81, 0xAA, 0x8E, 0x2C, 0x86, 0xAC, 0xF6, 0x3D, 0xDE, 0xE3, 0x14, 0x6F, 0x3E, 0x37, 0xF5, 0xC0, 0x25, 0xD9, 0xDA, 0x36, 0x42, 0xBA, 0xDC, 0x8E, 0x67, 0x0E, 0xE0, 0xDB, 0xA9, 0x31, 0xD1, 0x9B, 0x5A, 0xB9, 0xA0, 0xD5, 0x28, 0x6C, 0x75, 0x2E, 0x21, 0x59, 0x8A, 0xB1, 0x16, 0x55, 0xD5, 0xA4, 0x98, 0xB4, 0x80, 0xB4, 0x91, 0x3A, 0x5A, 0x11, 0x5E, 0xCD, 0x8E, 0xB0, 0x5A, 0x37, 0x9F, 0x3E, 0x16, 0x93, 0x9D, 0xC6, 0x23, 0xBD, 0xDA, }, .priv_len = 2560, .pub = { 0xFD, 0x33, 0x89, 0x37, 0xE3, 0x17, 0xAD, 0x38, 0xBA, 0xEC, 0xF5, 0xE0, 0x43, 0x58, 0x0C, 0x59, 0xC8, 0x63, 0xBB, 0xDC, 0xDF, 0xD7, 0x41, 0x9D, 0x59, 0xD3, 0xC7, 0x9F, 0xD0, 0xB3, 0x15, 0x54, 0xB1, 0xF6, 0x3A, 0x92, 0x83, 0xA6, 0xF2, 0x1C, 0xD8, 0xB9, 0xD8, 0x51, 0xEA, 0x83, 0xF0, 0xE1, 0x64, 0x59, 0x58, 0x06, 0x0B, 0x4D, 0x3C, 0xEE, 0x2C, 0xA9, 0xC2, 0x6A, 0xD2, 0x80, 0xC7, 0x24, 0xFA, 0xD5, 0x79, 0xB1, 0x2C, 0x9B, 0x27, 0xD3, 0xEC, 0xC5, 0x8C, 0x1E, 0x23, 0x53, 0xB0, 0x70, 0x9D, 0xCC, 0x57, 0x82, 0xC0, 0x57, 0xE1, 0x40, 0xC6, 0xE3, 0x9A, 0x74, 0xC6, 0x57, 0x36, 0xBF, 0xA7, 0x0B, 0x04, 0x20, 0x8E, 0x21, 0x0F, 0x9D, 0x2B, 0x2D, 0x7F, 0xAF, 0xB8, 0xF9, 0x26, 0x58, 0xE9, 0xA5, 0xDC, 0x72, 0xB7, 0xD0, 0x8B, 0xF6, 0x93, 0xD7, 0x5D, 0x0B, 0x59, 0x8A, 0x16, 0xE3, 0x74, 0x3E, 0xAC, 0x6C, 0x59, 0xF6, 0x52, 0x76, 0xB9, 0x44, 0x35, 0xFB, 0x4F, 0x91, 0x65, 0xCA, 0xE5, 0xCD, 0x56, 0x1C, 0xE4, 0x75, 0x50, 0x1F, 0xA1, 0x3F, 0xEF, 0x41, 0x4A, 0x88, 0xA7, 0xA6, 0xB0, 0x1E, 0x87, 0xD9, 0x84, 0xFB, 0x3E, 0x9B, 0x6E, 0x7E, 0x2C, 0x17, 0x6F, 0x27, 0x06, 0xC0, 0x96, 0x4A, 0x49, 0xF8, 0xF8, 0x23, 0xE1, 0xD8, 0x69, 0xF8, 0x93, 0xFF, 0xF1, 0x0E, 0xB8, 0xC4, 0x12, 0x4B, 0x3F, 0x17, 0x1A, 0x76, 0x8B, 0x05, 0x21, 0xFB, 0x3C, 0xAA, 0x24, 0x68, 0x8E, 0x4C, 0xF1, 0xE6, 0xF6, 0x09, 0xCB, 0x3C, 0x9F, 0xA2, 0x24, 0x81, 0xA2, 0xF5, 0xB4, 0xDA, 0x1A, 0x6B, 0x71, 0x3A, 0x03, 0xB4, 0x41, 0xDE, 0xCC, 0x52, 0x28, 0x2F, 0xDB, 0xCC, 0xAC, 0x75, 0xA9, 0x93, 0x34, 0xB7, 0xAD, 0xBC, 0xD1, 0xEA, 0xBE, 0x16, 0x1D, 0x0D, 0x47, 0x05, 0x1E, 0xF1, 0x68, 0x70, 0xA3, 0xC5, 0xE2, 0x85, 0xCD, 0xD5, 0xCB, 0xF1, 0x06, 0xAA, 0xF1, 0xFA, 0x32, 0xB1, 0x69, 0x91, 0x08, 0xE2, 0x86, 0x45, 0xD8, 0x6C, 0xA1, 0x53, 0xCF, 0x0D, 0x86, 0xC6, 0xA4, 0x0A, 0x9F, 0x0F, 0xF1, 0x40, 0x6B, 0xD3, 0x58, 0xF3, 0xA8, 0x18, 0xFB, 0x61, 0xF6, 0xB2, 0x1D, 0x23, 0x2B, 0x9D, 0xAF, 0xA5, 0xFE, 0x77, 0xD3, 0x08, 0x01, 0x50, 0x95, 0x28, 0x80, 0xCD, 0xA2, 0xDC, 0x65, 0xC3, 0xCD, 0x9A, 0x57, 0x5F, 0x9A, 0x70, 0x2C, 0xF8, 0xCD, 0x18, 0x8C, 0x69, 0xEC, 0x30, 0x63, 0xDB, 0xAB, 0x12, 0x31, 0x13, 0x43, 0x96, 0x31, 0x37, 0x67, 0xB7, 0x75, 0x1C, 0xBE, 0xDF, 0xF6, 0xB9, 0xA3, 0xF2, 0xBF, 0x79, 0x94, 0x5A, 0x00, 0x8F, 0x54, 0xE4, 0x60, 0x92, 0x5B, 0x90, 0x24, 0x8B, 0xC1, 0x67, 0xB5, 0xE6, 0xA4, 0x30, 0x00, 0x49, 0x20, 0xFA, 0xFE, 0x18, 0x8B, 0xA7, 0x81, 0x3B, 0xD1, 0x8D, 0xDE, 0xDF, 0xD2, 0x75, 0x1B, 0xBC, 0x24, 0x67, 0x7D, 0x21, 0x58, 0x0A, 0x57, 0xDC, 0x90, 0xF5, 0x4D, 0x63, 0x07, 0xA7, 0x56, 0x8A, 0x88, 0xA4, 0x24, 0x13, 0x19, 0xC0, 0x5E, 0xE5, 0x1E, 0xAD, 0xDF, 0xB0, 0x7C, 0x07, 0x1F, 0x82, 0x4F, 0xFE, 0x5D, 0xE2, 0x0E, 0x67, 0xBF, 0x1D, 0x68, 0xF3, 0x08, 0xCA, 0x6C, 0xEB, 0x00, 0xDF, 0x49, 0x09, 0x77, 0xBC, 0x6E, 0xA1, 0xBF, 0x0C, 0x74, 0xC8, 0x88, 0x2F, 0x0D, 0xFC, 0x21, 0x9A, 0x41, 0x1B, 0x14, 0x7B, 0x0B, 0x62, 0x5F, 0x82, 0x76, 0xEC, 0x11, 0x6F, 0x08, 0xAE, 0x3C, 0x94, 0x5F, 0x1A, 0xDB, 0xBB, 0x86, 0x63, 0xE9, 0x4E, 0xA1, 0x6C, 0xF8, 0xED, 0x1A, 0x2F, 0xF4, 0x8F, 0x8E, 0x93, 0x1D, 0xF0, 0x16, 0xE9, 0xD4, 0xEA, 0xDA, 0xA8, 0x6F, 0xF0, 0xA3, 0x15, 0xA0, 0x05, 0x5F, 0x99, 0x42, 0x2C, 0x00, 0xB0, 0x7D, 0x5B, 0x6F, 0xF9, 0x9E, 0x95, 0xB4, 0xDD, 0x99, 0xCA, 0x76, 0x2C, 0xE3, 0x72, 0x70, 0x15, 0xEB, 0xA3, 0x4D, 0x66, 0x83, 0x50, 0x67, 0x5D, 0x6E, 0xF8, 0xF2, 0xA8, 0xB8, 0xFB, 0x35, 0x40, 0x11, 0x00, 0xC1, 0x54, 0x91, 0x11, 0xDC, 0xA2, 0xF5, 0x74, 0x29, 0xA8, 0x5A, 0xD4, 0xC3, 0x75, 0x9F, 0x11, 0x6F, 0x30, 0x29, 0x01, 0x97, 0x3C, 0xDD, 0xB4, 0x54, 0x68, 0xDE, 0x65, 0x03, 0x3C, 0xC0, 0x5F, 0xB0, 0x92, 0x5B, 0xE5, 0xC5, 0x31, 0xF0, 0x11, 0xCB, 0xD5, 0xD0, 0x82, 0xDD, 0xB9, 0x46, 0xCE, 0x7F, 0x89, 0x0A, 0x45, 0x44, 0xBC, 0x43, 0x5C, 0x9C, 0x0C, 0x69, 0x06, 0x4F, 0x82, 0x63, 0x38, 0x5C, 0x31, 0xFD, 0xD2, 0x33, 0xCC, 0x80, 0x19, 0x7D, 0x58, 0x03, 0x3B, 0x8D, 0x16, 0x36, 0x41, 0xBC, 0xE5, 0x85, 0x98, 0x43, 0xC1, 0x3D, 0xBD, 0x19, 0x1F, 0xF8, 0x0A, 0x65, 0x1A, 0x4D, 0xD7, 0x17, 0x95, 0xCF, 0x32, 0x23, 0x5B, 0x36, 0x7E, 0xEB, 0x7E, 0xB4, 0x65, 0x18, 0x9D, 0x4A, 0xD4, 0x83, 0xC8, 0xC5, 0x56, 0xF2, 0x53, 0xE2, 0x32, 0xB6, 0xAD, 0x22, 0x84, 0x79, 0x80, 0x1A, 0xCD, 0xEB, 0x1C, 0x40, 0xBF, 0xC5, 0x02, 0xEE, 0x3F, 0x02, 0x62, 0xF0, 0xA3, 0x5C, 0x01, 0xB1, 0xA5, 0x56, 0xE4, 0x6B, 0x49, 0x44, 0xBF, 0x1A, 0x2E, 0x8F, 0xE4, 0xAD, 0x9E, 0x7F, 0xA0, 0x04, 0xC0, 0xEF, 0x5D, 0x07, 0x5A, 0xB5, 0x73, 0x1F, 0x3D, 0x7D, 0xE1, 0xAF, 0x0D, 0x1E, 0x71, 0x92, 0xC8, 0xFE, 0x4C, 0xE8, 0x68, 0x77, 0x6C, 0xED, 0xE0, 0xC0, 0x1A, 0xB1, 0xA4, 0x20, 0xDF, 0xD1, 0x1C, 0x35, 0x1A, 0x9B, 0x8D, 0x9E, 0xBE, 0xBC, 0xF9, 0xB8, 0xA6, 0xB9, 0xBE, 0x1A, 0x91, 0xCB, 0xDB, 0x8E, 0x24, 0x9A, 0x73, 0xB3, 0xB5, 0xB5, 0xB1, 0x3D, 0x49, 0xC9, 0xD4, 0x68, 0x04, 0xA0, 0x27, 0x4A, 0xF2, 0x35, 0x1C, 0x71, 0x74, 0x20, 0xD7, 0x56, 0xC5, 0xFC, 0x3D, 0x80, 0x5E, 0x36, 0xB0, 0x91, 0xA2, 0x5D, 0x4D, 0x74, 0x38, 0xA5, 0x0B, 0x11, 0xE6, 0x15, 0x46, 0x7F, 0xC7, 0xEC, 0xE1, 0xA7, 0xE4, 0x67, 0x8B, 0x38, 0xE2, 0x71, 0xAD, 0x2A, 0xEA, 0xDA, 0xC9, 0x4A, 0x1D, 0x9B, 0xDA, 0x85, 0x85, 0x83, 0x75, 0xC0, 0x49, 0xB5, 0xE6, 0xC1, 0xD3, 0xAC, 0xCE, 0xA3, 0x13, 0x58, 0xD5, 0x19, 0x15, 0x14, 0x86, 0x8F, 0xB5, 0x95, 0xC7, 0xAB, 0x3E, 0xF1, 0xBA, 0x9B, 0x68, 0x91, 0x03, 0x53, 0xE2, 0x68, 0xB0, 0x87, 0x55, 0xA4, 0x72, 0xD0, 0x45, 0x6D, 0x5F, 0x53, 0x5B, 0x73, 0x4D, 0x39, 0x75, 0x5A, 0xE6, 0xBD, 0x66, 0x7E, 0x02, 0xC5, 0x87, 0xCA, 0xD7, 0xE7, 0xC3, 0x16, 0xD2, 0x36, 0x45, 0x39, 0xBA, 0x27, 0xB1, 0xDF, 0xFC, 0x09, 0x11, 0x39, 0xF0, 0x3F, 0x7C, 0xFC, 0xE8, 0x1A, 0xAF, 0x49, 0xD1, 0x9E, 0x2A, 0x9A, 0xD0, 0xB5, 0xF1, 0x22, 0xE3, 0x06, 0x14, 0x8C, 0xC3, 0x54, 0x94, 0x3E, 0xD2, 0x8A, 0xA4, 0x7F, 0x7D, 0x3D, 0x6D, 0xC8, 0x1F, 0x65, 0xFE, 0x26, 0xEB, 0x87, 0xB0, 0xAB, 0x15, 0xC8, 0x60, 0x00, 0xC9, 0x62, 0x68, 0x11, 0xDE, 0x5A, 0x6E, 0x8E, 0xD2, 0x95, 0xDF, 0x58, 0x1A, 0xB3, 0x41, 0x83, 0xC9, 0xB7, 0xA3, 0x8D, 0x01, 0x46, 0xE0, 0xC6, 0xF6, 0x48, 0x71, 0x32, 0x85, 0xB0, 0x7B, 0x7E, 0x45, 0x26, 0xE8, 0x5D, 0xEB, 0x54, 0xBA, 0x40, 0x37, 0xDB, 0x30, 0x19, 0x4F, 0xDF, 0x24, 0xD3, 0xB2, 0xD9, 0x60, 0x8E, 0xD8, 0x83, 0x67, 0xF6, 0x62, 0x02, 0xC4, 0x73, 0x98, 0x34, 0x74, 0xB6, 0xD3, 0x2E, 0xF1, 0xDF, 0x7B, 0x35, 0x03, 0xF8, 0x70, 0x56, 0xD3, 0x6B, 0x5F, 0x46, 0x47, 0x8B, 0xAE, 0x29, 0xF1, 0x6A, 0x2B, 0x67, 0xAE, 0x95, 0x07, 0x50, 0x23, 0x9A, 0xBF, 0x62, 0x45, 0x4D, 0xF7, 0x31, 0xF1, 0x2D, 0x97, 0x72, 0x34, 0x26, 0x43, 0xC2, 0x43, 0xF3, 0xD4, 0xE8, 0xA2, 0x9F, 0x87, 0xE1, 0x09, 0xCD, 0xCD, 0xB8, 0xCD, 0xA8, 0xE1, 0x55, 0xA5, 0xB6, 0xF1, 0x40, 0xE7, 0xE7, 0xC4, 0x64, 0xEA, 0x3B, 0x57, 0x79, 0xFC, 0x14, 0x4E, 0x74, 0x3D, 0x0D, 0x19, 0x22, 0x71, 0x5B, 0xFF, 0x75, 0x55, 0xC8, 0xE6, 0xDA, 0xB4, 0x95, 0x6B, 0xCA, 0x8D, 0x62, 0x3D, 0x86, 0x2E, 0x53, 0x72, 0x0E, 0x3D, 0xD5, 0xF4, 0x9F, 0x57, 0xD2, 0x31, 0xA2, 0x52, 0x2B, 0x55, 0x4F, 0xF7, 0x9F, 0xAF, 0x3D, 0xE3, 0x5A, 0x49, 0x18, 0x57, 0x65, 0xD9, 0x74, 0x5A, 0x16, 0xE3, 0xDB, 0xDB, 0x46, 0x01, 0x01, 0xC3, 0x7A, 0x9C, 0xF6, 0x47, 0x59, 0x81, 0x22, 0x3B, 0xCB, 0x07, 0x43, 0xA6, 0x21, 0xD7, 0x58, 0x8E, 0xF0, 0xB2, 0x24, 0x64, 0xA1, 0x3D, 0x50, 0x87, 0x63, 0x57, 0x34, 0x2E, 0x1D, 0x28, 0x6A, 0x35, 0x90, 0xF9, 0x30, 0xB0, 0xBF, 0xBC, 0x73, 0xED, 0x50, 0x94, 0xA7, 0x15, 0xA2, 0xD4, 0x72, 0xF6, 0x88, 0x89, 0x83, 0x6B, 0x09, 0xE1, 0x73, 0x8D, 0xF2, 0x09, 0x92, 0x66, 0x73, 0xF1, 0x21, 0x5B, 0xE0, 0xD0, 0x7F, 0x39, 0x38, 0x2A, 0x75, 0x20, 0x2B, 0x3A, 0x70, 0x08, 0x7D, 0xF0, 0x5E, 0xAE, 0x9A, 0xAC, 0x99, 0xB5, 0xEE, 0x1C, 0x82, 0x68, 0x21, 0x1C, 0xC5, 0x0D, 0xAB, 0x8D, 0x83, 0x49, 0x9E, 0x93, 0xB3, 0x6B, 0x09, 0x36, 0x5B, 0xE6, 0x7E, 0xC2, 0xF0, 0xE2, 0x86, 0x17, 0xA2, 0x03, 0x94, 0xD0, 0x44, 0xAE, 0xB4, 0x37, 0x92, 0x04, 0xA6, 0x77, 0x62, 0xD7, 0xC1, 0x1F, 0xF1, 0xC5, 0x10, 0xBF, 0x60, 0x88, 0xB1, 0x0F, 0x72, 0x41, 0x04, 0xF5, 0xDF, 0xA3, 0x3D, 0xE9, 0xFC, 0xA2, 0x20, 0xCC, 0x5A, 0x4A, 0xC8, 0x66, 0x6E, 0xF5, 0xBB, 0x21, 0xF4, 0xB9, 0xD7, 0x9B, 0xB3, 0x0C, 0xB4, 0x98, 0x7E, 0x24, 0x80, 0xBE, 0xF8, 0x39, 0xA6, 0xC9, 0xFF, 0x1A, 0x34, 0x30, 0xA9, 0xF4, 0xB7, 0x15, 0xA4, 0x25, 0xF0, 0x0C, }, .pub_len = 1312, }, { .name = "ML-DSA 44 (seed only)", .parameter_set = CKP_ML_DSA_44, .priv_seed = { 0xBB, 0x9C, 0x97, 0xC1, 0x9D, 0x5D, 0x11, 0x98, 0x52, 0xC2, 0x40, 0xA9, 0xBF, 0xD4, 0x43, 0x70, 0xD0, 0xF4, 0x2E, 0x3B, 0x56, 0xC6, 0xAF, 0x8C, 0x4A, 0x95, 0xDB, 0x8F, 0xAE, 0xDF, 0xDC, 0x6F, }, .priv_seed_len = 32, .pub = { 0xFD, 0x33, 0x89, 0x37, 0xE3, 0x17, 0xAD, 0x38, 0xBA, 0xEC, 0xF5, 0xE0, 0x43, 0x58, 0x0C, 0x59, 0xC8, 0x63, 0xBB, 0xDC, 0xDF, 0xD7, 0x41, 0x9D, 0x59, 0xD3, 0xC7, 0x9F, 0xD0, 0xB3, 0x15, 0x54, 0xB1, 0xF6, 0x3A, 0x92, 0x83, 0xA6, 0xF2, 0x1C, 0xD8, 0xB9, 0xD8, 0x51, 0xEA, 0x83, 0xF0, 0xE1, 0x64, 0x59, 0x58, 0x06, 0x0B, 0x4D, 0x3C, 0xEE, 0x2C, 0xA9, 0xC2, 0x6A, 0xD2, 0x80, 0xC7, 0x24, 0xFA, 0xD5, 0x79, 0xB1, 0x2C, 0x9B, 0x27, 0xD3, 0xEC, 0xC5, 0x8C, 0x1E, 0x23, 0x53, 0xB0, 0x70, 0x9D, 0xCC, 0x57, 0x82, 0xC0, 0x57, 0xE1, 0x40, 0xC6, 0xE3, 0x9A, 0x74, 0xC6, 0x57, 0x36, 0xBF, 0xA7, 0x0B, 0x04, 0x20, 0x8E, 0x21, 0x0F, 0x9D, 0x2B, 0x2D, 0x7F, 0xAF, 0xB8, 0xF9, 0x26, 0x58, 0xE9, 0xA5, 0xDC, 0x72, 0xB7, 0xD0, 0x8B, 0xF6, 0x93, 0xD7, 0x5D, 0x0B, 0x59, 0x8A, 0x16, 0xE3, 0x74, 0x3E, 0xAC, 0x6C, 0x59, 0xF6, 0x52, 0x76, 0xB9, 0x44, 0x35, 0xFB, 0x4F, 0x91, 0x65, 0xCA, 0xE5, 0xCD, 0x56, 0x1C, 0xE4, 0x75, 0x50, 0x1F, 0xA1, 0x3F, 0xEF, 0x41, 0x4A, 0x88, 0xA7, 0xA6, 0xB0, 0x1E, 0x87, 0xD9, 0x84, 0xFB, 0x3E, 0x9B, 0x6E, 0x7E, 0x2C, 0x17, 0x6F, 0x27, 0x06, 0xC0, 0x96, 0x4A, 0x49, 0xF8, 0xF8, 0x23, 0xE1, 0xD8, 0x69, 0xF8, 0x93, 0xFF, 0xF1, 0x0E, 0xB8, 0xC4, 0x12, 0x4B, 0x3F, 0x17, 0x1A, 0x76, 0x8B, 0x05, 0x21, 0xFB, 0x3C, 0xAA, 0x24, 0x68, 0x8E, 0x4C, 0xF1, 0xE6, 0xF6, 0x09, 0xCB, 0x3C, 0x9F, 0xA2, 0x24, 0x81, 0xA2, 0xF5, 0xB4, 0xDA, 0x1A, 0x6B, 0x71, 0x3A, 0x03, 0xB4, 0x41, 0xDE, 0xCC, 0x52, 0x28, 0x2F, 0xDB, 0xCC, 0xAC, 0x75, 0xA9, 0x93, 0x34, 0xB7, 0xAD, 0xBC, 0xD1, 0xEA, 0xBE, 0x16, 0x1D, 0x0D, 0x47, 0x05, 0x1E, 0xF1, 0x68, 0x70, 0xA3, 0xC5, 0xE2, 0x85, 0xCD, 0xD5, 0xCB, 0xF1, 0x06, 0xAA, 0xF1, 0xFA, 0x32, 0xB1, 0x69, 0x91, 0x08, 0xE2, 0x86, 0x45, 0xD8, 0x6C, 0xA1, 0x53, 0xCF, 0x0D, 0x86, 0xC6, 0xA4, 0x0A, 0x9F, 0x0F, 0xF1, 0x40, 0x6B, 0xD3, 0x58, 0xF3, 0xA8, 0x18, 0xFB, 0x61, 0xF6, 0xB2, 0x1D, 0x23, 0x2B, 0x9D, 0xAF, 0xA5, 0xFE, 0x77, 0xD3, 0x08, 0x01, 0x50, 0x95, 0x28, 0x80, 0xCD, 0xA2, 0xDC, 0x65, 0xC3, 0xCD, 0x9A, 0x57, 0x5F, 0x9A, 0x70, 0x2C, 0xF8, 0xCD, 0x18, 0x8C, 0x69, 0xEC, 0x30, 0x63, 0xDB, 0xAB, 0x12, 0x31, 0x13, 0x43, 0x96, 0x31, 0x37, 0x67, 0xB7, 0x75, 0x1C, 0xBE, 0xDF, 0xF6, 0xB9, 0xA3, 0xF2, 0xBF, 0x79, 0x94, 0x5A, 0x00, 0x8F, 0x54, 0xE4, 0x60, 0x92, 0x5B, 0x90, 0x24, 0x8B, 0xC1, 0x67, 0xB5, 0xE6, 0xA4, 0x30, 0x00, 0x49, 0x20, 0xFA, 0xFE, 0x18, 0x8B, 0xA7, 0x81, 0x3B, 0xD1, 0x8D, 0xDE, 0xDF, 0xD2, 0x75, 0x1B, 0xBC, 0x24, 0x67, 0x7D, 0x21, 0x58, 0x0A, 0x57, 0xDC, 0x90, 0xF5, 0x4D, 0x63, 0x07, 0xA7, 0x56, 0x8A, 0x88, 0xA4, 0x24, 0x13, 0x19, 0xC0, 0x5E, 0xE5, 0x1E, 0xAD, 0xDF, 0xB0, 0x7C, 0x07, 0x1F, 0x82, 0x4F, 0xFE, 0x5D, 0xE2, 0x0E, 0x67, 0xBF, 0x1D, 0x68, 0xF3, 0x08, 0xCA, 0x6C, 0xEB, 0x00, 0xDF, 0x49, 0x09, 0x77, 0xBC, 0x6E, 0xA1, 0xBF, 0x0C, 0x74, 0xC8, 0x88, 0x2F, 0x0D, 0xFC, 0x21, 0x9A, 0x41, 0x1B, 0x14, 0x7B, 0x0B, 0x62, 0x5F, 0x82, 0x76, 0xEC, 0x11, 0x6F, 0x08, 0xAE, 0x3C, 0x94, 0x5F, 0x1A, 0xDB, 0xBB, 0x86, 0x63, 0xE9, 0x4E, 0xA1, 0x6C, 0xF8, 0xED, 0x1A, 0x2F, 0xF4, 0x8F, 0x8E, 0x93, 0x1D, 0xF0, 0x16, 0xE9, 0xD4, 0xEA, 0xDA, 0xA8, 0x6F, 0xF0, 0xA3, 0x15, 0xA0, 0x05, 0x5F, 0x99, 0x42, 0x2C, 0x00, 0xB0, 0x7D, 0x5B, 0x6F, 0xF9, 0x9E, 0x95, 0xB4, 0xDD, 0x99, 0xCA, 0x76, 0x2C, 0xE3, 0x72, 0x70, 0x15, 0xEB, 0xA3, 0x4D, 0x66, 0x83, 0x50, 0x67, 0x5D, 0x6E, 0xF8, 0xF2, 0xA8, 0xB8, 0xFB, 0x35, 0x40, 0x11, 0x00, 0xC1, 0x54, 0x91, 0x11, 0xDC, 0xA2, 0xF5, 0x74, 0x29, 0xA8, 0x5A, 0xD4, 0xC3, 0x75, 0x9F, 0x11, 0x6F, 0x30, 0x29, 0x01, 0x97, 0x3C, 0xDD, 0xB4, 0x54, 0x68, 0xDE, 0x65, 0x03, 0x3C, 0xC0, 0x5F, 0xB0, 0x92, 0x5B, 0xE5, 0xC5, 0x31, 0xF0, 0x11, 0xCB, 0xD5, 0xD0, 0x82, 0xDD, 0xB9, 0x46, 0xCE, 0x7F, 0x89, 0x0A, 0x45, 0x44, 0xBC, 0x43, 0x5C, 0x9C, 0x0C, 0x69, 0x06, 0x4F, 0x82, 0x63, 0x38, 0x5C, 0x31, 0xFD, 0xD2, 0x33, 0xCC, 0x80, 0x19, 0x7D, 0x58, 0x03, 0x3B, 0x8D, 0x16, 0x36, 0x41, 0xBC, 0xE5, 0x85, 0x98, 0x43, 0xC1, 0x3D, 0xBD, 0x19, 0x1F, 0xF8, 0x0A, 0x65, 0x1A, 0x4D, 0xD7, 0x17, 0x95, 0xCF, 0x32, 0x23, 0x5B, 0x36, 0x7E, 0xEB, 0x7E, 0xB4, 0x65, 0x18, 0x9D, 0x4A, 0xD4, 0x83, 0xC8, 0xC5, 0x56, 0xF2, 0x53, 0xE2, 0x32, 0xB6, 0xAD, 0x22, 0x84, 0x79, 0x80, 0x1A, 0xCD, 0xEB, 0x1C, 0x40, 0xBF, 0xC5, 0x02, 0xEE, 0x3F, 0x02, 0x62, 0xF0, 0xA3, 0x5C, 0x01, 0xB1, 0xA5, 0x56, 0xE4, 0x6B, 0x49, 0x44, 0xBF, 0x1A, 0x2E, 0x8F, 0xE4, 0xAD, 0x9E, 0x7F, 0xA0, 0x04, 0xC0, 0xEF, 0x5D, 0x07, 0x5A, 0xB5, 0x73, 0x1F, 0x3D, 0x7D, 0xE1, 0xAF, 0x0D, 0x1E, 0x71, 0x92, 0xC8, 0xFE, 0x4C, 0xE8, 0x68, 0x77, 0x6C, 0xED, 0xE0, 0xC0, 0x1A, 0xB1, 0xA4, 0x20, 0xDF, 0xD1, 0x1C, 0x35, 0x1A, 0x9B, 0x8D, 0x9E, 0xBE, 0xBC, 0xF9, 0xB8, 0xA6, 0xB9, 0xBE, 0x1A, 0x91, 0xCB, 0xDB, 0x8E, 0x24, 0x9A, 0x73, 0xB3, 0xB5, 0xB5, 0xB1, 0x3D, 0x49, 0xC9, 0xD4, 0x68, 0x04, 0xA0, 0x27, 0x4A, 0xF2, 0x35, 0x1C, 0x71, 0x74, 0x20, 0xD7, 0x56, 0xC5, 0xFC, 0x3D, 0x80, 0x5E, 0x36, 0xB0, 0x91, 0xA2, 0x5D, 0x4D, 0x74, 0x38, 0xA5, 0x0B, 0x11, 0xE6, 0x15, 0x46, 0x7F, 0xC7, 0xEC, 0xE1, 0xA7, 0xE4, 0x67, 0x8B, 0x38, 0xE2, 0x71, 0xAD, 0x2A, 0xEA, 0xDA, 0xC9, 0x4A, 0x1D, 0x9B, 0xDA, 0x85, 0x85, 0x83, 0x75, 0xC0, 0x49, 0xB5, 0xE6, 0xC1, 0xD3, 0xAC, 0xCE, 0xA3, 0x13, 0x58, 0xD5, 0x19, 0x15, 0x14, 0x86, 0x8F, 0xB5, 0x95, 0xC7, 0xAB, 0x3E, 0xF1, 0xBA, 0x9B, 0x68, 0x91, 0x03, 0x53, 0xE2, 0x68, 0xB0, 0x87, 0x55, 0xA4, 0x72, 0xD0, 0x45, 0x6D, 0x5F, 0x53, 0x5B, 0x73, 0x4D, 0x39, 0x75, 0x5A, 0xE6, 0xBD, 0x66, 0x7E, 0x02, 0xC5, 0x87, 0xCA, 0xD7, 0xE7, 0xC3, 0x16, 0xD2, 0x36, 0x45, 0x39, 0xBA, 0x27, 0xB1, 0xDF, 0xFC, 0x09, 0x11, 0x39, 0xF0, 0x3F, 0x7C, 0xFC, 0xE8, 0x1A, 0xAF, 0x49, 0xD1, 0x9E, 0x2A, 0x9A, 0xD0, 0xB5, 0xF1, 0x22, 0xE3, 0x06, 0x14, 0x8C, 0xC3, 0x54, 0x94, 0x3E, 0xD2, 0x8A, 0xA4, 0x7F, 0x7D, 0x3D, 0x6D, 0xC8, 0x1F, 0x65, 0xFE, 0x26, 0xEB, 0x87, 0xB0, 0xAB, 0x15, 0xC8, 0x60, 0x00, 0xC9, 0x62, 0x68, 0x11, 0xDE, 0x5A, 0x6E, 0x8E, 0xD2, 0x95, 0xDF, 0x58, 0x1A, 0xB3, 0x41, 0x83, 0xC9, 0xB7, 0xA3, 0x8D, 0x01, 0x46, 0xE0, 0xC6, 0xF6, 0x48, 0x71, 0x32, 0x85, 0xB0, 0x7B, 0x7E, 0x45, 0x26, 0xE8, 0x5D, 0xEB, 0x54, 0xBA, 0x40, 0x37, 0xDB, 0x30, 0x19, 0x4F, 0xDF, 0x24, 0xD3, 0xB2, 0xD9, 0x60, 0x8E, 0xD8, 0x83, 0x67, 0xF6, 0x62, 0x02, 0xC4, 0x73, 0x98, 0x34, 0x74, 0xB6, 0xD3, 0x2E, 0xF1, 0xDF, 0x7B, 0x35, 0x03, 0xF8, 0x70, 0x56, 0xD3, 0x6B, 0x5F, 0x46, 0x47, 0x8B, 0xAE, 0x29, 0xF1, 0x6A, 0x2B, 0x67, 0xAE, 0x95, 0x07, 0x50, 0x23, 0x9A, 0xBF, 0x62, 0x45, 0x4D, 0xF7, 0x31, 0xF1, 0x2D, 0x97, 0x72, 0x34, 0x26, 0x43, 0xC2, 0x43, 0xF3, 0xD4, 0xE8, 0xA2, 0x9F, 0x87, 0xE1, 0x09, 0xCD, 0xCD, 0xB8, 0xCD, 0xA8, 0xE1, 0x55, 0xA5, 0xB6, 0xF1, 0x40, 0xE7, 0xE7, 0xC4, 0x64, 0xEA, 0x3B, 0x57, 0x79, 0xFC, 0x14, 0x4E, 0x74, 0x3D, 0x0D, 0x19, 0x22, 0x71, 0x5B, 0xFF, 0x75, 0x55, 0xC8, 0xE6, 0xDA, 0xB4, 0x95, 0x6B, 0xCA, 0x8D, 0x62, 0x3D, 0x86, 0x2E, 0x53, 0x72, 0x0E, 0x3D, 0xD5, 0xF4, 0x9F, 0x57, 0xD2, 0x31, 0xA2, 0x52, 0x2B, 0x55, 0x4F, 0xF7, 0x9F, 0xAF, 0x3D, 0xE3, 0x5A, 0x49, 0x18, 0x57, 0x65, 0xD9, 0x74, 0x5A, 0x16, 0xE3, 0xDB, 0xDB, 0x46, 0x01, 0x01, 0xC3, 0x7A, 0x9C, 0xF6, 0x47, 0x59, 0x81, 0x22, 0x3B, 0xCB, 0x07, 0x43, 0xA6, 0x21, 0xD7, 0x58, 0x8E, 0xF0, 0xB2, 0x24, 0x64, 0xA1, 0x3D, 0x50, 0x87, 0x63, 0x57, 0x34, 0x2E, 0x1D, 0x28, 0x6A, 0x35, 0x90, 0xF9, 0x30, 0xB0, 0xBF, 0xBC, 0x73, 0xED, 0x50, 0x94, 0xA7, 0x15, 0xA2, 0xD4, 0x72, 0xF6, 0x88, 0x89, 0x83, 0x6B, 0x09, 0xE1, 0x73, 0x8D, 0xF2, 0x09, 0x92, 0x66, 0x73, 0xF1, 0x21, 0x5B, 0xE0, 0xD0, 0x7F, 0x39, 0x38, 0x2A, 0x75, 0x20, 0x2B, 0x3A, 0x70, 0x08, 0x7D, 0xF0, 0x5E, 0xAE, 0x9A, 0xAC, 0x99, 0xB5, 0xEE, 0x1C, 0x82, 0x68, 0x21, 0x1C, 0xC5, 0x0D, 0xAB, 0x8D, 0x83, 0x49, 0x9E, 0x93, 0xB3, 0x6B, 0x09, 0x36, 0x5B, 0xE6, 0x7E, 0xC2, 0xF0, 0xE2, 0x86, 0x17, 0xA2, 0x03, 0x94, 0xD0, 0x44, 0xAE, 0xB4, 0x37, 0x92, 0x04, 0xA6, 0x77, 0x62, 0xD7, 0xC1, 0x1F, 0xF1, 0xC5, 0x10, 0xBF, 0x60, 0x88, 0xB1, 0x0F, 0x72, 0x41, 0x04, 0xF5, 0xDF, 0xA3, 0x3D, 0xE9, 0xFC, 0xA2, 0x20, 0xCC, 0x5A, 0x4A, 0xC8, 0x66, 0x6E, 0xF5, 0xBB, 0x21, 0xF4, 0xB9, 0xD7, 0x9B, 0xB3, 0x0C, 0xB4, 0x98, 0x7E, 0x24, 0x80, 0xBE, 0xF8, 0x39, 0xA6, 0xC9, 0xFF, 0x1A, 0x34, 0x30, 0xA9, 0xF4, 0xB7, 0x15, 0xA4, 0x25, 0xF0, 0x0C, }, .pub_len = 1312, }, { .name = "ML-DSA 44 (seed and priv)", .parameter_set = CKP_ML_DSA_44, .priv_seed = { 0xBB, 0x9C, 0x97, 0xC1, 0x9D, 0x5D, 0x11, 0x98, 0x52, 0xC2, 0x40, 0xA9, 0xBF, 0xD4, 0x43, 0x70, 0xD0, 0xF4, 0x2E, 0x3B, 0x56, 0xC6, 0xAF, 0x8C, 0x4A, 0x95, 0xDB, 0x8F, 0xAE, 0xDF, 0xDC, 0x6F, }, .priv_seed_len = 32, .priv = { 0xFD, 0x33, 0x89, 0x37, 0xE3, 0x17, 0xAD, 0x38, 0xBA, 0xEC, 0xF5, 0xE0, 0x43, 0x58, 0x0C, 0x59, 0xC8, 0x63, 0xBB, 0xDC, 0xDF, 0xD7, 0x41, 0x9D, 0x59, 0xD3, 0xC7, 0x9F, 0xD0, 0xB3, 0x15, 0x54, 0x38, 0x48, 0x10, 0x9D, 0x09, 0x98, 0xDB, 0xE7, 0x94, 0x8F, 0x53, 0x2D, 0xFD, 0xC2, 0xAD, 0xEA, 0x5C, 0x94, 0xDF, 0xC1, 0x91, 0xC2, 0x1E, 0x4C, 0xE3, 0xA8, 0x6E, 0x7B, 0x29, 0x57, 0x5E, 0x5E, 0x1E, 0x00, 0x9E, 0x4C, 0xF4, 0x0F, 0xE6, 0xDC, 0x56, 0xF4, 0x4C, 0xA1, 0x43, 0x83, 0x99, 0x4D, 0x16, 0x6A, 0xFA, 0x2F, 0xA3, 0x6E, 0xDF, 0xDC, 0x88, 0xF7, 0x6A, 0xC8, 0x32, 0x7D, 0xB0, 0x0C, 0x34, 0x5D, 0x47, 0xE8, 0xBE, 0x69, 0x2F, 0xC6, 0xFE, 0xC4, 0x8B, 0x0C, 0xD2, 0xB3, 0x51, 0x32, 0xB6, 0x6C, 0x7D, 0x5F, 0x8B, 0x6A, 0x28, 0x34, 0x0B, 0x16, 0x45, 0x33, 0x5D, 0x36, 0x86, 0x68, 0xC1, 0xA0, 0x89, 0x60, 0x88, 0x69, 0x13, 0x11, 0x32, 0x1B, 0x39, 0x40, 0x02, 0xA1, 0x70, 0xDC, 0xB0, 0x80, 0x12, 0x08, 0x45, 0x21, 0xA7, 0x4C, 0x91, 0x36, 0x05, 0x12, 0x46, 0x31, 0x11, 0x32, 0x72, 0x23, 0x12, 0x44, 0xD1, 0x88, 0x49, 0x9B, 0xA2, 0x71, 0x01, 0xC0, 0x10, 0x01, 0x41, 0x12, 0x0C, 0xA2, 0x8C, 0xC1, 0xB2, 0x68, 0xD2, 0x22, 0x65, 0x20, 0x85, 0x8C, 0x24, 0xC8, 0x09, 0x19, 0x08, 0x06, 0x99, 0x22, 0x66, 0x5B, 0x42, 0x61, 0x5B, 0xB8, 0x40, 0x01, 0x44, 0x62, 0xE4, 0xA2, 0x00, 0x49, 0x24, 0x50, 0x01, 0x21, 0x10, 0x9C, 0x38, 0x80, 0xDB, 0xC6, 0x05, 0xA1, 0x16, 0x4A, 0xC8, 0x12, 0x6A, 0x19, 0x05, 0x00, 0x11, 0x06, 0x8E, 0x04, 0x95, 0x41, 0x9A, 0xC6, 0x85, 0x99, 0xB2, 0x28, 0x5C, 0xA8, 0x68, 0xA0, 0x42, 0x68, 0xD1, 0x28, 0x4C, 0x04, 0x85, 0x68, 0x0A, 0x34, 0x52, 0x21, 0x46, 0x4C, 0xE0, 0xA0, 0x70, 0x4B, 0x16, 0x80, 0x8B, 0x32, 0x72, 0xC2, 0xA6, 0x05, 0xDB, 0x92, 0x08, 0x03, 0x28, 0x21, 0xCC, 0x20, 0x72, 0x4A, 0xB4, 0x24, 0x23, 0x24, 0x49, 0x20, 0xC3, 0x41, 0x11, 0x24, 0x81, 0x5C, 0x48, 0x2E, 0x08, 0x14, 0x88, 0x99, 0x24, 0x2A, 0x18, 0xB5, 0x8D, 0xD3, 0x14, 0x90, 0x83, 0x08, 0x50, 0x0A, 0x32, 0x8D, 0x44, 0x34, 0x70, 0xE2, 0x44, 0x4D, 0x0B, 0xB6, 0x2C, 0xCB, 0xC2, 0x84, 0x23, 0xA8, 0x64, 0x0B, 0x49, 0x51, 0x1A, 0x06, 0x8A, 0x0B, 0x01, 0x44, 0xDB, 0x16, 0x42, 0x4A, 0xC4, 0x8C, 0x82, 0x38, 0x52, 0xD8, 0x02, 0x04, 0x21, 0x03, 0x90, 0x89, 0x88, 0x2C, 0x84, 0xC0, 0x40, 0xC8, 0x08, 0x8A, 0x93, 0x34, 0x4A, 0xE1, 0x42, 0x81, 0x98, 0x48, 0x31, 0xA3, 0x14, 0x6E, 0x20, 0xA8, 0x11, 0x9B, 0x90, 0x6C, 0x81, 0x86, 0x28, 0x98, 0x24, 0x21, 0x0B, 0xC0, 0x91, 0x64, 0x22, 0x2D, 0xA1, 0xB2, 0x71, 0x82, 0x30, 0x10, 0x8C, 0x28, 0x65, 0x90, 0xB6, 0x0D, 0x01, 0x90, 0x64, 0xE4, 0x80, 0x45, 0x51, 0x32, 0x11, 0x89, 0x94, 0x6D, 0x0C, 0x38, 0x32, 0xCA, 0xC4, 0x48, 0x1C, 0x46, 0x0C, 0x01, 0x18, 0x0A, 0xC1, 0x94, 0x0D, 0x80, 0x10, 0x22, 0x04, 0x34, 0x8D, 0x24, 0xB5, 0x40, 0x20, 0x42, 0x21, 0x24, 0x86, 0x2C, 0xD4, 0xC0, 0x90, 0x10, 0x01, 0x4E, 0x22, 0x29, 0x32, 0x99, 0x12, 0x6D, 0x5C, 0x90, 0x61, 0x01, 0x94, 0x64, 0x0B, 0xB3, 0x8D, 0x1A, 0x40, 0x05, 0xE1, 0x46, 0x41, 0x00, 0xC2, 0x85, 0x61, 0xC0, 0x08, 0x24, 0x34, 0x40, 0x14, 0x09, 0x30, 0x0C, 0x24, 0x01, 0x02, 0xC4, 0x80, 0x0C, 0x02, 0x88, 0xCB, 0x28, 0x30, 0xDA, 0x26, 0x8E, 0xC0, 0x08, 0x22, 0x24, 0x27, 0x4E, 0x01, 0x96, 0x20, 0x58, 0x40, 0x46, 0x9B, 0x84, 0x61, 0xC4, 0x42, 0x26, 0x24, 0x25, 0x89, 0x18, 0xB1, 0x88, 0x8C, 0x80, 0x70, 0xC2, 0x28, 0x61, 0x52, 0x16, 0x52, 0x61, 0x06, 0x11, 0x21, 0x83, 0x0D, 0x0C, 0x29, 0x04, 0x54, 0x46, 0x12, 0xE3, 0x28, 0x82, 0x01, 0x02, 0x31, 0x12, 0x90, 0x51, 0x53, 0x40, 0x41, 0xE2, 0x20, 0x41, 0x9A, 0xB4, 0x8C, 0xD0, 0x02, 0x44, 0x0A, 0x13, 0x10, 0x11, 0x99, 0x21, 0x09, 0x93, 0x8D, 0x94, 0x48, 0x66, 0x24, 0xC5, 0x48, 0xD8, 0x02, 0x05, 0xC9, 0x04, 0x66, 0xC0, 0x82, 0x88, 0x4C, 0x06, 0x11, 0x4B, 0x04, 0x0E, 0xA2, 0x40, 0x02, 0x22, 0xC0, 0x2D, 0x23, 0x49, 0x8A, 0x8B, 0x26, 0x72, 0x14, 0x96, 0x71, 0x14, 0x89, 0x65, 0xA1, 0x94, 0x31, 0xCA, 0x92, 0x2D, 0x1A, 0xC7, 0x6C, 0x22, 0x43, 0x40, 0x1C, 0x09, 0x4A, 0xD2, 0x04, 0x08, 0x88, 0x44, 0x68, 0xE0, 0x24, 0x80, 0xE3, 0xC8, 0x90, 0x18, 0xC5, 0x84, 0x08, 0xB2, 0x48, 0xA0, 0xC8, 0x70, 0x0C, 0x40, 0x44, 0xE4, 0x26, 0x24, 0x09, 0x03, 0x4E, 0x19, 0x95, 0x51, 0xC9, 0x36, 0x8A, 0x99, 0x40, 0x40, 0x9A, 0x38, 0x8A, 0x61, 0x16, 0x82, 0x20, 0x97, 0x48, 0xCA, 0x02, 0x31, 0x12, 0x91, 0x68, 0x00, 0x32, 0x20, 0x0B, 0x33, 0x81, 0x90, 0x26, 0x32, 0x1A, 0x00, 0x2C, 0x01, 0x07, 0x72, 0x61, 0xA6, 0x31, 0x0B, 0x30, 0x84, 0x91, 0x26, 0x10, 0x12, 0x42, 0x6D, 0x23, 0xA4, 0x84, 0xD1, 0x26, 0x61, 0x13, 0xA1, 0x8D, 0x23, 0xC1, 0x85, 0x01, 0xA6, 0x04, 0x09, 0xB9, 0x71, 0x8B, 0x04, 0x69, 0xC2, 0x32, 0x50, 0x14, 0xC3, 0x30, 0xC9, 0xB4, 0x61, 0xCB, 0x44, 0x09, 0x93, 0x10, 0x29, 0x13, 0x39, 0x62, 0xC1, 0x16, 0x88, 0x89, 0x02, 0x30, 0x09, 0x87, 0x81, 0x0A, 0x46, 0x0E, 0xA0, 0x02, 0x8E, 0xA4, 0x00, 0x2E, 0x12, 0x39, 0x02, 0x41, 0x48, 0x90, 0x23, 0x04, 0x8C, 0x61, 0x98, 0x89, 0xE2, 0x30, 0x65, 0x8A, 0x48, 0x25, 0x09, 0x16, 0x60, 0x04, 0x19, 0x04, 0xC3, 0x22, 0x8A, 0x0B, 0x84, 0x24, 0xDC, 0x46, 0x52, 0x00, 0xA6, 0x90, 0x10, 0x35, 0x06, 0xE3, 0x38, 0x22, 0x18, 0x41, 0x28, 0xD8, 0x18, 0x90, 0x91, 0x22, 0x80, 0x50, 0xC0, 0x71, 0x83, 0xC6, 0x50, 0x50, 0x28, 0x24, 0x64, 0x34, 0x44, 0x1C, 0x96, 0x28, 0xCB, 0x80, 0x80, 0x22, 0x13, 0x8D, 0x9A, 0x46, 0x31, 0x94, 0x44, 0x8A, 0x49, 0x36, 0x8D, 0xCC, 0x92, 0x68, 0x1B, 0x97, 0x90, 0x03, 0xA0, 0x4C, 0xC9, 0x24, 0x4C, 0x08, 0x35, 0x85, 0xA4, 0x26, 0x84, 0xDA, 0x34, 0x06, 0x00, 0x04, 0x69, 0x04, 0x41, 0x42, 0x98, 0x34, 0x71, 0x49, 0xA0, 0x60, 0x58, 0xC6, 0x11, 0x11, 0x35, 0x26, 0x01, 0x82, 0x50, 0x24, 0xC0, 0x70, 0x14, 0x20, 0x88, 0x75, 0xA6, 0xD6, 0xED, 0x67, 0x8C, 0x60, 0x85, 0x1A, 0x0D, 0x33, 0xDB, 0x75, 0xBD, 0xEB, 0x35, 0x9C, 0xFF, 0xC9, 0x41, 0xCE, 0x9A, 0xE3, 0xD5, 0x75, 0xE6, 0xCE, 0x47, 0x58, 0xD3, 0xE9, 0x8C, 0x2F, 0x36, 0xAE, 0xD6, 0x18, 0x0A, 0x64, 0xC3, 0x85, 0x9D, 0xC2, 0xD3, 0x79, 0x50, 0x18, 0x66, 0x5E, 0x98, 0x1D, 0x15, 0xE9, 0xFF, 0x6E, 0x00, 0x33, 0x9E, 0xFD, 0x97, 0x5B, 0x84, 0x3D, 0x1A, 0x00, 0x02, 0x49, 0x2A, 0x3D, 0xE1, 0x3D, 0x18, 0x9D, 0xF1, 0xE4, 0xD8, 0x35, 0x09, 0xFD, 0xFC, 0xC1, 0xC0, 0x10, 0x8C, 0x0D, 0x2F, 0xD1, 0x22, 0xDC, 0x46, 0x1D, 0x55, 0x76, 0x2F, 0x85, 0x1C, 0x02, 0x1B, 0x69, 0xB3, 0x56, 0x36, 0x5B, 0xF6, 0x4E, 0x11, 0x3E, 0xEB, 0xB3, 0xC0, 0x8B, 0xF3, 0x8A, 0x1F, 0xFC, 0xEE, 0x91, 0x6A, 0x96, 0xA9, 0xEA, 0x75, 0xE3, 0x15, 0x0A, 0xE3, 0x5B, 0xAC, 0x2F, 0xD3, 0x09, 0xE3, 0x80, 0xA4, 0x6E, 0xC3, 0x6C, 0x03, 0x8E, 0xC1, 0xA0, 0xCF, 0xF7, 0xF9, 0x11, 0xDC, 0x77, 0x2D, 0xBC, 0x81, 0x32, 0xE0, 0x34, 0xFE, 0xC9, 0x83, 0x96, 0xD6, 0x29, 0xCF, 0x6A, 0x72, 0xCA, 0xB2, 0x51, 0xC2, 0x17, 0xB4, 0xEA, 0x38, 0x8E, 0xCA, 0x94, 0xB7, 0x70, 0xBD, 0x7D, 0xBC, 0x28, 0xF0, 0xA9, 0x68, 0x41, 0xC7, 0x3C, 0x31, 0x97, 0xC3, 0x5B, 0x68, 0x9F, 0xC9, 0x68, 0x89, 0xB1, 0xA8, 0xF2, 0x07, 0x72, 0x20, 0xF6, 0xE2, 0x1E, 0x83, 0xF2, 0xDD, 0x02, 0xF9, 0xDD, 0x0C, 0x3D, 0x55, 0xF2, 0x8B, 0x86, 0xF0, 0x19, 0xC0, 0xAF, 0xC1, 0xB1, 0xA8, 0x83, 0xAE, 0x6F, 0xD7, 0xC3, 0x3D, 0xED, 0x4E, 0x9C, 0x4C, 0xA5, 0xF3, 0x11, 0x54, 0x85, 0x5B, 0x8E, 0xBD, 0x57, 0xBE, 0xBE, 0x76, 0x9D, 0x82, 0x0D, 0xFE, 0xCE, 0x09, 0xD9, 0xD7, 0x19, 0xB7, 0x76, 0xA9, 0xF6, 0x93, 0x8C, 0xDD, 0x9F, 0xA5, 0xE8, 0xC9, 0xFA, 0xB1, 0xBA, 0x35, 0x8E, 0x4E, 0x1C, 0x6B, 0x0C, 0x3F, 0x67, 0x4E, 0x37, 0x11, 0x00, 0x48, 0x3A, 0x24, 0xD0, 0x31, 0x1B, 0xAF, 0x66, 0xBB, 0x6C, 0xFB, 0x4A, 0x7E, 0xD2, 0xEC, 0x92, 0x91, 0x17, 0x54, 0xDD, 0xFB, 0xA4, 0xEA, 0x98, 0x53, 0x3D, 0x65, 0x87, 0xD9, 0x06, 0x99, 0x98, 0x62, 0xDB, 0xEB, 0xA2, 0x54, 0x54, 0x2E, 0x2E, 0x46, 0x54, 0x78, 0xBC, 0xE3, 0xC4, 0x08, 0x13, 0xDB, 0xD9, 0xD2, 0x49, 0x2E, 0x83, 0x5F, 0x22, 0x3A, 0x69, 0x02, 0x39, 0x68, 0x17, 0x50, 0x63, 0x09, 0xA5, 0x0A, 0xC5, 0xF0, 0x48, 0x9C, 0x9E, 0x75, 0x20, 0x01, 0x9A, 0x97, 0xF6, 0xB2, 0xDF, 0x7A, 0x5B, 0x10, 0xB6, 0xED, 0x96, 0xAE, 0x2C, 0xD4, 0xAB, 0x37, 0x7B, 0x0C, 0x3F, 0xFB, 0x56, 0x03, 0xD8, 0xB7, 0xFB, 0xCE, 0xE2, 0x04, 0x88, 0x22, 0xE2, 0x31, 0xA6, 0x65, 0xC4, 0x70, 0xB7, 0x6F, 0x63, 0xED, 0xD6, 0xC6, 0xFF, 0x67, 0x3A, 0x23, 0xA5, 0x95, 0x57, 0x3C, 0xE7, 0x67, 0x88, 0xAA, 0xA2, 0x11, 0x15, 0x4E, 0xDA, 0x10, 0x17, 0x0B, 0xE2, 0x77, 0x1C, 0xD9, 0x31, 0xB3, 0x31, 0xD9, 0x85, 0x43, 0xE4, 0x76, 0x27, 0xD2, 0x85, 0x94, 0xA0, 0xDE, 0x64, 0x40, 0xCB, 0x2B, 0x2B, 0x00, 0x58, 0x4D, 0xB9, 0x3A, 0x5C, 0x64, 0xB3, 0x2B, 0x1D, 0x9B, 0x1A, 0x9A, 0x8D, 0x3E, 0x24, 0x3D, 0x6C, 0x60, 0xF4, 0xCC, 0x61, 0x68, 0x40, 0xEE, 0x1F, 0xA2, 0xB1, 0x1C, 0x33, 0x80, 0x7F, 0x61, 0x05, 0xA0, 0x2E, 0x6C, 0x40, 0xAF, 0x4A, 0x0B, 0x7B, 0x10, 0x01, 0x28, 0x1E, 0xA7, 0x17, 0xBC, 0xEB, 0xA0, 0xE3, 0xF2, 0x3F, 0x98, 0xC0, 0x22, 0x1D, 0x30, 0xA5, 0xF3, 0x2F, 0x94, 0x62, 0x11, 0xB5, 0xC0, 0x9D, 0x84, 0x71, 0x40, 0xD1, 0xA8, 0xC8, 0x13, 0xEA, 0x58, 0x27, 0x38, 0x8C, 0x24, 0x85, 0xAB, 0x8C, 0x0D, 0x1F, 0x9D, 0x4A, 0x95, 0x23, 0x38, 0x72, 0x28, 0x64, 0xE9, 0x47, 0x68, 0xA4, 0x0C, 0xE0, 0x4C, 0xC9, 0x69, 0xA6, 0x3C, 0x2D, 0xCE, 0x16, 0x9B, 0xC4, 0x08, 0xEB, 0x1D, 0x30, 0x2E, 0x7E, 0xEE, 0x15, 0x05, 0x4A, 0x03, 0x86, 0xBF, 0x9E, 0x73, 0xFD, 0xA0, 0x9F, 0x78, 0xF2, 0x10, 0x1B, 0x9C, 0x6F, 0x09, 0xC2, 0x78, 0xF4, 0x35, 0x28, 0x0D, 0xC9, 0xE9, 0x5F, 0xBE, 0x74, 0xE7, 0xDD, 0x7C, 0xC6, 0xCA, 0x75, 0x9A, 0xB4, 0xF4, 0xC8, 0xFD, 0x42, 0xC6, 0xDD, 0x42, 0x6B, 0x6D, 0xDE, 0xB9, 0xEA, 0x8E, 0xD2, 0x49, 0xAE, 0x4F, 0x76, 0x9F, 0x9B, 0x06, 0x42, 0x6F, 0x20, 0x30, 0xF4, 0x05, 0x4D, 0x41, 0xAC, 0x08, 0xBF, 0x63, 0xDC, 0x5C, 0x3E, 0x5A, 0xBF, 0xE5, 0xCB, 0xBF, 0x01, 0x06, 0x26, 0x29, 0x59, 0x94, 0x44, 0xF3, 0x47, 0x4B, 0xDE, 0x57, 0x17, 0x10, 0x03, 0x01, 0x2B, 0x52, 0x3D, 0x63, 0x9C, 0x81, 0x25, 0xEF, 0x0F, 0x6A, 0x10, 0xDF, 0x67, 0xFA, 0x3D, 0xA8, 0x06, 0x53, 0x84, 0x43, 0x70, 0xA9, 0x32, 0x5A, 0xCD, 0xE8, 0xF8, 0xBF, 0xC5, 0x8E, 0xF3, 0x1B, 0xBA, 0xB4, 0x55, 0xB5, 0x1D, 0x9C, 0x07, 0x83, 0xA9, 0xA5, 0x8F, 0x3D, 0x42, 0xC6, 0xE1, 0x71, 0x6C, 0x6F, 0x93, 0xA7, 0x2F, 0x41, 0xF6, 0x9C, 0xDD, 0xFC, 0x28, 0x5D, 0x20, 0xD0, 0xE6, 0x9E, 0xF7, 0xC5, 0xB4, 0xBD, 0xDE, 0xF7, 0xF0, 0x7C, 0x02, 0xD9, 0xF7, 0x6E, 0x7F, 0xCB, 0xDC, 0x7F, 0x76, 0xC2, 0x82, 0xB9, 0x51, 0x4B, 0xD2, 0x0B, 0xA9, 0x53, 0x56, 0xF8, 0x86, 0xF3, 0x2E, 0x4E, 0xCB, 0x2B, 0xF2, 0xE4, 0x1B, 0xDA, 0x35, 0xD6, 0x0F, 0x1A, 0xD1, 0xD3, 0x9A, 0x2B, 0x2F, 0x94, 0x6C, 0x02, 0x25, 0x94, 0x71, 0x99, 0x40, 0x6F, 0x36, 0x2E, 0x08, 0x1E, 0x8F, 0xD4, 0x29, 0x02, 0x9B, 0x81, 0x3A, 0x1E, 0xC0, 0xEB, 0x75, 0xBD, 0xF7, 0x55, 0x7F, 0xE3, 0xDE, 0x82, 0xEF, 0xB1, 0x5F, 0x05, 0x9B, 0x8E, 0x5D, 0xA2, 0x63, 0x39, 0x78, 0x7C, 0x52, 0xA1, 0xCD, 0x2F, 0xDC, 0x8A, 0x3D, 0x21, 0x6D, 0xA1, 0xFC, 0xA2, 0xC4, 0x20, 0xD7, 0x72, 0xCC, 0xE5, 0x4A, 0x6F, 0x70, 0x72, 0x9D, 0xD0, 0xEC, 0x82, 0xBD, 0x55, 0xC0, 0x1C, 0x92, 0x4C, 0xAF, 0xBC, 0x82, 0xF8, 0x9A, 0xC3, 0x92, 0x3A, 0x04, 0x24, 0xD4, 0xF0, 0xCD, 0x6D, 0xA6, 0x6B, 0x2A, 0xA1, 0xA9, 0x41, 0xDB, 0xFF, 0x81, 0x96, 0x30, 0xF8, 0x39, 0xAE, 0x8A, 0xAA, 0x26, 0xC5, 0x74, 0xA0, 0x1F, 0x90, 0x12, 0x80, 0xF4, 0xBB, 0x6C, 0xC7, 0xC4, 0x3F, 0xD1, 0xF8, 0xA0, 0x8B, 0x88, 0x76, 0xEE, 0xB7, 0xCC, 0x25, 0xBF, 0xC2, 0x85, 0xE0, 0xBD, 0xC6, 0xDD, 0x3D, 0x2C, 0x8C, 0x7F, 0x5F, 0x2F, 0x5A, 0xC7, 0x9F, 0x86, 0xD3, 0x2F, 0xEA, 0xE2, 0x2C, 0x97, 0x17, 0x66, 0xAF, 0xD5, 0x33, 0x17, 0xEE, 0x36, 0xEB, 0x50, 0x72, 0x3D, 0xC8, 0x1A, 0xAE, 0x5A, 0x63, 0x85, 0x93, 0x83, 0x74, 0xFF, 0xEA, 0x94, 0xE0, 0x82, 0xE0, 0xB4, 0x83, 0x2D, 0x22, 0x32, 0x5D, 0x0F, 0x33, 0x8E, 0x1D, 0xAD, 0x67, 0x2E, 0x06, 0x07, 0xF7, 0xB7, 0x61, 0xD1, 0x3A, 0xEF, 0x54, 0x34, 0x22, 0x92, 0x3D, 0x78, 0xEC, 0x6B, 0x55, 0x6D, 0xBC, 0x4B, 0x13, 0x15, 0x37, 0xC7, 0x0C, 0xC8, 0xAF, 0x02, 0x7F, 0x7E, 0x28, 0xEC, 0xE2, 0x50, 0x9F, 0xDF, 0x8E, 0x90, 0x35, 0x16, 0xEF, 0x8A, 0x07, 0xF4, 0xA8, 0x53, 0x53, 0x96, 0xAC, 0x82, 0xBE, 0x6C, 0x03, 0x65, 0x7C, 0x94, 0x7E, 0xFF, 0x60, 0x18, 0x82, 0xC5, 0xF8, 0xDA, 0xCE, 0x9F, 0xE0, 0x0E, 0x08, 0xEA, 0xA2, 0x3B, 0xF8, 0xC9, 0x50, 0xB2, 0x1D, 0x9B, 0x07, 0xD0, 0xDE, 0x07, 0x23, 0x8D, 0x35, 0xD0, 0x8D, 0xD4, 0xB5, 0x92, 0xC1, 0x24, 0x8B, 0xF4, 0x4B, 0xAF, 0x14, 0xB7, 0x70, 0x74, 0xF0, 0x32, 0xB1, 0xC3, 0xE9, 0xB2, 0x78, 0x58, 0x4B, 0x09, 0x95, 0x3C, 0x18, 0xDB, 0x6E, 0x3E, 0x05, 0x79, 0xC5, 0xA4, 0x06, 0x5A, 0xBA, 0x43, 0xF9, 0x64, 0x0B, 0x79, 0x49, 0x15, 0xD3, 0xB1, 0xC5, 0x5E, 0xF4, 0x08, 0xF7, 0x86, 0x15, 0x6F, 0xEE, 0x50, 0x90, 0x9F, 0x98, 0x02, 0xD9, 0x36, 0x7D, 0x2E, 0x5F, 0xEF, 0xBF, 0xF2, 0x64, 0x38, 0xAF, 0x9D, 0xE2, 0xCF, 0x5B, 0x7B, 0x41, 0x08, 0x28, 0x0E, 0x33, 0x2A, 0x04, 0x4A, 0xA6, 0xC4, 0xDE, 0x75, 0x59, 0x61, 0x07, 0x64, 0xBB, 0x7C, 0x7A, 0x0C, 0x47, 0xF0, 0xD1, 0xC6, 0xD7, 0xA9, 0x47, 0x39, 0xEA, 0xA6, 0x4F, 0x5B, 0x67, 0xDA, 0x9A, 0xDB, 0x5E, 0x3B, 0x95, 0x5A, 0xD1, 0x7D, 0x57, 0x84, 0x10, 0xCB, 0x61, 0xC4, 0x50, 0xE1, 0xF6, 0x85, 0xCC, 0xEE, 0xDC, 0x66, 0x83, 0xEA, 0x88, 0x70, 0x56, 0xFE, 0x4F, 0x08, 0xBF, 0x0A, 0x19, 0x0F, 0x40, 0xEC, 0x65, 0x3D, 0xEC, 0x91, 0x26, 0x3D, 0x9B, 0x82, 0x9D, 0xAE, 0x23, 0x3D, 0xD8, 0xD4, 0x79, 0x0B, 0xD5, 0xC2, 0x79, 0x65, 0xA9, 0x53, 0x56, 0x96, 0xA0, 0xE0, 0x67, 0xA0, 0xF4, 0xE5, 0xFC, 0x44, 0x5D, 0x4D, 0xE1, 0x58, 0x92, 0x50, 0xEC, 0x1F, 0x82, 0xED, 0xA2, 0x95, 0x7B, 0xC7, 0x3A, 0x77, 0xA9, 0xE9, 0x90, 0xCA, 0x29, 0xD3, 0x08, 0xB3, 0x8D, 0xA6, 0x63, 0x68, 0x2B, 0xFF, 0xBB, 0x48, 0x12, 0x8D, 0xB7, 0x73, 0xA3, 0xD2, 0xC6, 0x5D, 0xE4, 0x29, 0xF3, 0x8E, 0x16, 0xCF, 0x98, 0xCB, 0x5C, 0xCD, 0x10, 0x3F, 0xAB, 0x0C, 0xF3, 0x58, 0x22, 0x72, 0x8C, 0x75, 0xF0, 0x26, 0x4E, 0x1D, 0x97, 0x06, 0xB6, 0xF2, 0x20, 0xA9, 0x9D, 0x65, 0xBD, 0xE9, 0xC8, 0x6F, 0x20, 0x32, 0x82, 0xC9, 0x1A, 0xE7, 0xD5, 0xB9, 0x33, 0xBA, 0x99, 0x29, 0xD5, 0x4C, 0x55, 0xDA, 0x7B, 0x15, 0xB7, 0xA5, 0x03, 0xAF, 0xD4, 0xD0, 0xB1, 0xDE, 0xA4, 0x17, 0x20, 0xAF, 0x20, 0x0C, 0x8E, 0xDB, 0x11, 0x79, 0xE5, 0x57, 0xB7, 0xA3, 0xA1, 0xD3, 0xFC, 0xB5, 0x07, 0x88, 0x10, 0x4E, 0x5E, 0xF3, 0xD7, 0x02, 0x97, 0xDE, 0x6F, 0xF5, 0xFD, 0x84, 0xB6, 0xA9, 0xB1, 0x41, 0x45, 0x17, 0xB9, 0x8A, 0x73, 0x14, 0xBE, 0xC5, 0x93, 0x36, 0x68, 0x68, 0xD2, 0xF2, 0x02, 0xBB, 0xBF, 0x42, 0x4F, 0x93, 0x3F, 0x23, 0x8D, 0xBF, 0x36, 0xCC, 0x58, 0x55, 0x11, 0x86, 0x1B, 0x81, 0x15, 0x24, 0x56, 0x1A, 0xF4, 0x96, 0xC9, 0xD6, 0x24, 0xB7, 0x9A, 0xA6, 0x51, 0xFC, 0xDD, 0xC5, 0xC4, 0x8D, 0x4E, 0xBE, 0x4B, 0xBD, 0x5F, 0xD4, 0xF1, 0x89, 0x5D, 0xD4, 0x0E, 0xA4, 0x65, 0x43, 0x69, 0x13, 0xD3, 0xFB, 0x74, 0x94, 0xF4, 0xBD, 0x88, 0xE2, 0x33, 0xA8, 0x09, 0x87, 0x87, 0x1A, 0xFF, 0xA9, 0xE1, 0x4F, 0x31, 0x55, 0x3E, 0x49, 0x21, 0xA1, 0xD1, 0xD2, 0x69, 0x4A, 0x81, 0xA1, 0xFA, 0x8C, 0xA9, 0xBF, 0xDF, 0x04, 0x03, 0xFD, 0x88, 0x50, 0xFA, 0x4B, 0x4F, 0xA2, 0x1A, 0x11, 0xB1, 0xF2, 0x00, 0xF9, 0x13, 0xC2, 0xE1, 0x7D, 0x9A, 0xF8, 0xC1, 0xD4, 0xAC, 0x8D, 0xAA, 0x7D, 0xD3, 0x0D, 0x38, 0xF1, 0x51, 0x33, 0x42, 0xA9, 0x6A, 0x54, 0x09, 0xF3, 0x2F, 0x4F, 0x24, 0xED, 0x63, 0xF2, 0xB8, 0xF9, 0x48, 0x77, 0xEB, 0xD1, 0xBD, 0xDD, 0x9A, 0xB5, 0x3F, 0xF7, 0x1F, 0x1A, 0xAB, 0xAD, 0xBF, 0xA3, 0x2A, 0xAF, 0x99, 0xEF, 0xC9, 0xAE, 0x57, 0x92, 0x4C, 0xAD, 0x4B, 0x1F, 0x5E, 0xB5, 0x57, 0xCB, 0x5B, 0xA9, 0xAE, 0x05, 0xD8, 0xA4, 0xB3, 0x22, 0x1B, 0xCC, 0x1B, 0xAA, 0xAA, 0x70, 0x4E, 0x0F, 0x0E, 0x00, 0x63, 0x9A, 0x44, 0x94, 0x0A, 0x79, 0x21, 0x24, 0xD1, 0x88, 0xA0, 0xA7, 0x28, 0x96, 0xF9, 0x06, 0x5A, 0x16, 0x5E, 0x98, 0x1A, 0x3A, 0x72, 0xF7, 0x5F, 0x9E, 0xAF, 0x69, 0x23, 0x2C, 0x8E, 0x0E, 0x61, 0xEC, 0xE4, 0x7E, 0xAD, 0xE6, 0xF0, 0x8A, 0x81, 0xAA, 0x8E, 0x2C, 0x86, 0xAC, 0xF6, 0x3D, 0xDE, 0xE3, 0x14, 0x6F, 0x3E, 0x37, 0xF5, 0xC0, 0x25, 0xD9, 0xDA, 0x36, 0x42, 0xBA, 0xDC, 0x8E, 0x67, 0x0E, 0xE0, 0xDB, 0xA9, 0x31, 0xD1, 0x9B, 0x5A, 0xB9, 0xA0, 0xD5, 0x28, 0x6C, 0x75, 0x2E, 0x21, 0x59, 0x8A, 0xB1, 0x16, 0x55, 0xD5, 0xA4, 0x98, 0xB4, 0x80, 0xB4, 0x91, 0x3A, 0x5A, 0x11, 0x5E, 0xCD, 0x8E, 0xB0, 0x5A, 0x37, 0x9F, 0x3E, 0x16, 0x93, 0x9D, 0xC6, 0x23, 0xBD, 0xDA, }, .priv_len = 2560, .pub = { 0xFD, 0x33, 0x89, 0x37, 0xE3, 0x17, 0xAD, 0x38, 0xBA, 0xEC, 0xF5, 0xE0, 0x43, 0x58, 0x0C, 0x59, 0xC8, 0x63, 0xBB, 0xDC, 0xDF, 0xD7, 0x41, 0x9D, 0x59, 0xD3, 0xC7, 0x9F, 0xD0, 0xB3, 0x15, 0x54, 0xB1, 0xF6, 0x3A, 0x92, 0x83, 0xA6, 0xF2, 0x1C, 0xD8, 0xB9, 0xD8, 0x51, 0xEA, 0x83, 0xF0, 0xE1, 0x64, 0x59, 0x58, 0x06, 0x0B, 0x4D, 0x3C, 0xEE, 0x2C, 0xA9, 0xC2, 0x6A, 0xD2, 0x80, 0xC7, 0x24, 0xFA, 0xD5, 0x79, 0xB1, 0x2C, 0x9B, 0x27, 0xD3, 0xEC, 0xC5, 0x8C, 0x1E, 0x23, 0x53, 0xB0, 0x70, 0x9D, 0xCC, 0x57, 0x82, 0xC0, 0x57, 0xE1, 0x40, 0xC6, 0xE3, 0x9A, 0x74, 0xC6, 0x57, 0x36, 0xBF, 0xA7, 0x0B, 0x04, 0x20, 0x8E, 0x21, 0x0F, 0x9D, 0x2B, 0x2D, 0x7F, 0xAF, 0xB8, 0xF9, 0x26, 0x58, 0xE9, 0xA5, 0xDC, 0x72, 0xB7, 0xD0, 0x8B, 0xF6, 0x93, 0xD7, 0x5D, 0x0B, 0x59, 0x8A, 0x16, 0xE3, 0x74, 0x3E, 0xAC, 0x6C, 0x59, 0xF6, 0x52, 0x76, 0xB9, 0x44, 0x35, 0xFB, 0x4F, 0x91, 0x65, 0xCA, 0xE5, 0xCD, 0x56, 0x1C, 0xE4, 0x75, 0x50, 0x1F, 0xA1, 0x3F, 0xEF, 0x41, 0x4A, 0x88, 0xA7, 0xA6, 0xB0, 0x1E, 0x87, 0xD9, 0x84, 0xFB, 0x3E, 0x9B, 0x6E, 0x7E, 0x2C, 0x17, 0x6F, 0x27, 0x06, 0xC0, 0x96, 0x4A, 0x49, 0xF8, 0xF8, 0x23, 0xE1, 0xD8, 0x69, 0xF8, 0x93, 0xFF, 0xF1, 0x0E, 0xB8, 0xC4, 0x12, 0x4B, 0x3F, 0x17, 0x1A, 0x76, 0x8B, 0x05, 0x21, 0xFB, 0x3C, 0xAA, 0x24, 0x68, 0x8E, 0x4C, 0xF1, 0xE6, 0xF6, 0x09, 0xCB, 0x3C, 0x9F, 0xA2, 0x24, 0x81, 0xA2, 0xF5, 0xB4, 0xDA, 0x1A, 0x6B, 0x71, 0x3A, 0x03, 0xB4, 0x41, 0xDE, 0xCC, 0x52, 0x28, 0x2F, 0xDB, 0xCC, 0xAC, 0x75, 0xA9, 0x93, 0x34, 0xB7, 0xAD, 0xBC, 0xD1, 0xEA, 0xBE, 0x16, 0x1D, 0x0D, 0x47, 0x05, 0x1E, 0xF1, 0x68, 0x70, 0xA3, 0xC5, 0xE2, 0x85, 0xCD, 0xD5, 0xCB, 0xF1, 0x06, 0xAA, 0xF1, 0xFA, 0x32, 0xB1, 0x69, 0x91, 0x08, 0xE2, 0x86, 0x45, 0xD8, 0x6C, 0xA1, 0x53, 0xCF, 0x0D, 0x86, 0xC6, 0xA4, 0x0A, 0x9F, 0x0F, 0xF1, 0x40, 0x6B, 0xD3, 0x58, 0xF3, 0xA8, 0x18, 0xFB, 0x61, 0xF6, 0xB2, 0x1D, 0x23, 0x2B, 0x9D, 0xAF, 0xA5, 0xFE, 0x77, 0xD3, 0x08, 0x01, 0x50, 0x95, 0x28, 0x80, 0xCD, 0xA2, 0xDC, 0x65, 0xC3, 0xCD, 0x9A, 0x57, 0x5F, 0x9A, 0x70, 0x2C, 0xF8, 0xCD, 0x18, 0x8C, 0x69, 0xEC, 0x30, 0x63, 0xDB, 0xAB, 0x12, 0x31, 0x13, 0x43, 0x96, 0x31, 0x37, 0x67, 0xB7, 0x75, 0x1C, 0xBE, 0xDF, 0xF6, 0xB9, 0xA3, 0xF2, 0xBF, 0x79, 0x94, 0x5A, 0x00, 0x8F, 0x54, 0xE4, 0x60, 0x92, 0x5B, 0x90, 0x24, 0x8B, 0xC1, 0x67, 0xB5, 0xE6, 0xA4, 0x30, 0x00, 0x49, 0x20, 0xFA, 0xFE, 0x18, 0x8B, 0xA7, 0x81, 0x3B, 0xD1, 0x8D, 0xDE, 0xDF, 0xD2, 0x75, 0x1B, 0xBC, 0x24, 0x67, 0x7D, 0x21, 0x58, 0x0A, 0x57, 0xDC, 0x90, 0xF5, 0x4D, 0x63, 0x07, 0xA7, 0x56, 0x8A, 0x88, 0xA4, 0x24, 0x13, 0x19, 0xC0, 0x5E, 0xE5, 0x1E, 0xAD, 0xDF, 0xB0, 0x7C, 0x07, 0x1F, 0x82, 0x4F, 0xFE, 0x5D, 0xE2, 0x0E, 0x67, 0xBF, 0x1D, 0x68, 0xF3, 0x08, 0xCA, 0x6C, 0xEB, 0x00, 0xDF, 0x49, 0x09, 0x77, 0xBC, 0x6E, 0xA1, 0xBF, 0x0C, 0x74, 0xC8, 0x88, 0x2F, 0x0D, 0xFC, 0x21, 0x9A, 0x41, 0x1B, 0x14, 0x7B, 0x0B, 0x62, 0x5F, 0x82, 0x76, 0xEC, 0x11, 0x6F, 0x08, 0xAE, 0x3C, 0x94, 0x5F, 0x1A, 0xDB, 0xBB, 0x86, 0x63, 0xE9, 0x4E, 0xA1, 0x6C, 0xF8, 0xED, 0x1A, 0x2F, 0xF4, 0x8F, 0x8E, 0x93, 0x1D, 0xF0, 0x16, 0xE9, 0xD4, 0xEA, 0xDA, 0xA8, 0x6F, 0xF0, 0xA3, 0x15, 0xA0, 0x05, 0x5F, 0x99, 0x42, 0x2C, 0x00, 0xB0, 0x7D, 0x5B, 0x6F, 0xF9, 0x9E, 0x95, 0xB4, 0xDD, 0x99, 0xCA, 0x76, 0x2C, 0xE3, 0x72, 0x70, 0x15, 0xEB, 0xA3, 0x4D, 0x66, 0x83, 0x50, 0x67, 0x5D, 0x6E, 0xF8, 0xF2, 0xA8, 0xB8, 0xFB, 0x35, 0x40, 0x11, 0x00, 0xC1, 0x54, 0x91, 0x11, 0xDC, 0xA2, 0xF5, 0x74, 0x29, 0xA8, 0x5A, 0xD4, 0xC3, 0x75, 0x9F, 0x11, 0x6F, 0x30, 0x29, 0x01, 0x97, 0x3C, 0xDD, 0xB4, 0x54, 0x68, 0xDE, 0x65, 0x03, 0x3C, 0xC0, 0x5F, 0xB0, 0x92, 0x5B, 0xE5, 0xC5, 0x31, 0xF0, 0x11, 0xCB, 0xD5, 0xD0, 0x82, 0xDD, 0xB9, 0x46, 0xCE, 0x7F, 0x89, 0x0A, 0x45, 0x44, 0xBC, 0x43, 0x5C, 0x9C, 0x0C, 0x69, 0x06, 0x4F, 0x82, 0x63, 0x38, 0x5C, 0x31, 0xFD, 0xD2, 0x33, 0xCC, 0x80, 0x19, 0x7D, 0x58, 0x03, 0x3B, 0x8D, 0x16, 0x36, 0x41, 0xBC, 0xE5, 0x85, 0x98, 0x43, 0xC1, 0x3D, 0xBD, 0x19, 0x1F, 0xF8, 0x0A, 0x65, 0x1A, 0x4D, 0xD7, 0x17, 0x95, 0xCF, 0x32, 0x23, 0x5B, 0x36, 0x7E, 0xEB, 0x7E, 0xB4, 0x65, 0x18, 0x9D, 0x4A, 0xD4, 0x83, 0xC8, 0xC5, 0x56, 0xF2, 0x53, 0xE2, 0x32, 0xB6, 0xAD, 0x22, 0x84, 0x79, 0x80, 0x1A, 0xCD, 0xEB, 0x1C, 0x40, 0xBF, 0xC5, 0x02, 0xEE, 0x3F, 0x02, 0x62, 0xF0, 0xA3, 0x5C, 0x01, 0xB1, 0xA5, 0x56, 0xE4, 0x6B, 0x49, 0x44, 0xBF, 0x1A, 0x2E, 0x8F, 0xE4, 0xAD, 0x9E, 0x7F, 0xA0, 0x04, 0xC0, 0xEF, 0x5D, 0x07, 0x5A, 0xB5, 0x73, 0x1F, 0x3D, 0x7D, 0xE1, 0xAF, 0x0D, 0x1E, 0x71, 0x92, 0xC8, 0xFE, 0x4C, 0xE8, 0x68, 0x77, 0x6C, 0xED, 0xE0, 0xC0, 0x1A, 0xB1, 0xA4, 0x20, 0xDF, 0xD1, 0x1C, 0x35, 0x1A, 0x9B, 0x8D, 0x9E, 0xBE, 0xBC, 0xF9, 0xB8, 0xA6, 0xB9, 0xBE, 0x1A, 0x91, 0xCB, 0xDB, 0x8E, 0x24, 0x9A, 0x73, 0xB3, 0xB5, 0xB5, 0xB1, 0x3D, 0x49, 0xC9, 0xD4, 0x68, 0x04, 0xA0, 0x27, 0x4A, 0xF2, 0x35, 0x1C, 0x71, 0x74, 0x20, 0xD7, 0x56, 0xC5, 0xFC, 0x3D, 0x80, 0x5E, 0x36, 0xB0, 0x91, 0xA2, 0x5D, 0x4D, 0x74, 0x38, 0xA5, 0x0B, 0x11, 0xE6, 0x15, 0x46, 0x7F, 0xC7, 0xEC, 0xE1, 0xA7, 0xE4, 0x67, 0x8B, 0x38, 0xE2, 0x71, 0xAD, 0x2A, 0xEA, 0xDA, 0xC9, 0x4A, 0x1D, 0x9B, 0xDA, 0x85, 0x85, 0x83, 0x75, 0xC0, 0x49, 0xB5, 0xE6, 0xC1, 0xD3, 0xAC, 0xCE, 0xA3, 0x13, 0x58, 0xD5, 0x19, 0x15, 0x14, 0x86, 0x8F, 0xB5, 0x95, 0xC7, 0xAB, 0x3E, 0xF1, 0xBA, 0x9B, 0x68, 0x91, 0x03, 0x53, 0xE2, 0x68, 0xB0, 0x87, 0x55, 0xA4, 0x72, 0xD0, 0x45, 0x6D, 0x5F, 0x53, 0x5B, 0x73, 0x4D, 0x39, 0x75, 0x5A, 0xE6, 0xBD, 0x66, 0x7E, 0x02, 0xC5, 0x87, 0xCA, 0xD7, 0xE7, 0xC3, 0x16, 0xD2, 0x36, 0x45, 0x39, 0xBA, 0x27, 0xB1, 0xDF, 0xFC, 0x09, 0x11, 0x39, 0xF0, 0x3F, 0x7C, 0xFC, 0xE8, 0x1A, 0xAF, 0x49, 0xD1, 0x9E, 0x2A, 0x9A, 0xD0, 0xB5, 0xF1, 0x22, 0xE3, 0x06, 0x14, 0x8C, 0xC3, 0x54, 0x94, 0x3E, 0xD2, 0x8A, 0xA4, 0x7F, 0x7D, 0x3D, 0x6D, 0xC8, 0x1F, 0x65, 0xFE, 0x26, 0xEB, 0x87, 0xB0, 0xAB, 0x15, 0xC8, 0x60, 0x00, 0xC9, 0x62, 0x68, 0x11, 0xDE, 0x5A, 0x6E, 0x8E, 0xD2, 0x95, 0xDF, 0x58, 0x1A, 0xB3, 0x41, 0x83, 0xC9, 0xB7, 0xA3, 0x8D, 0x01, 0x46, 0xE0, 0xC6, 0xF6, 0x48, 0x71, 0x32, 0x85, 0xB0, 0x7B, 0x7E, 0x45, 0x26, 0xE8, 0x5D, 0xEB, 0x54, 0xBA, 0x40, 0x37, 0xDB, 0x30, 0x19, 0x4F, 0xDF, 0x24, 0xD3, 0xB2, 0xD9, 0x60, 0x8E, 0xD8, 0x83, 0x67, 0xF6, 0x62, 0x02, 0xC4, 0x73, 0x98, 0x34, 0x74, 0xB6, 0xD3, 0x2E, 0xF1, 0xDF, 0x7B, 0x35, 0x03, 0xF8, 0x70, 0x56, 0xD3, 0x6B, 0x5F, 0x46, 0x47, 0x8B, 0xAE, 0x29, 0xF1, 0x6A, 0x2B, 0x67, 0xAE, 0x95, 0x07, 0x50, 0x23, 0x9A, 0xBF, 0x62, 0x45, 0x4D, 0xF7, 0x31, 0xF1, 0x2D, 0x97, 0x72, 0x34, 0x26, 0x43, 0xC2, 0x43, 0xF3, 0xD4, 0xE8, 0xA2, 0x9F, 0x87, 0xE1, 0x09, 0xCD, 0xCD, 0xB8, 0xCD, 0xA8, 0xE1, 0x55, 0xA5, 0xB6, 0xF1, 0x40, 0xE7, 0xE7, 0xC4, 0x64, 0xEA, 0x3B, 0x57, 0x79, 0xFC, 0x14, 0x4E, 0x74, 0x3D, 0x0D, 0x19, 0x22, 0x71, 0x5B, 0xFF, 0x75, 0x55, 0xC8, 0xE6, 0xDA, 0xB4, 0x95, 0x6B, 0xCA, 0x8D, 0x62, 0x3D, 0x86, 0x2E, 0x53, 0x72, 0x0E, 0x3D, 0xD5, 0xF4, 0x9F, 0x57, 0xD2, 0x31, 0xA2, 0x52, 0x2B, 0x55, 0x4F, 0xF7, 0x9F, 0xAF, 0x3D, 0xE3, 0x5A, 0x49, 0x18, 0x57, 0x65, 0xD9, 0x74, 0x5A, 0x16, 0xE3, 0xDB, 0xDB, 0x46, 0x01, 0x01, 0xC3, 0x7A, 0x9C, 0xF6, 0x47, 0x59, 0x81, 0x22, 0x3B, 0xCB, 0x07, 0x43, 0xA6, 0x21, 0xD7, 0x58, 0x8E, 0xF0, 0xB2, 0x24, 0x64, 0xA1, 0x3D, 0x50, 0x87, 0x63, 0x57, 0x34, 0x2E, 0x1D, 0x28, 0x6A, 0x35, 0x90, 0xF9, 0x30, 0xB0, 0xBF, 0xBC, 0x73, 0xED, 0x50, 0x94, 0xA7, 0x15, 0xA2, 0xD4, 0x72, 0xF6, 0x88, 0x89, 0x83, 0x6B, 0x09, 0xE1, 0x73, 0x8D, 0xF2, 0x09, 0x92, 0x66, 0x73, 0xF1, 0x21, 0x5B, 0xE0, 0xD0, 0x7F, 0x39, 0x38, 0x2A, 0x75, 0x20, 0x2B, 0x3A, 0x70, 0x08, 0x7D, 0xF0, 0x5E, 0xAE, 0x9A, 0xAC, 0x99, 0xB5, 0xEE, 0x1C, 0x82, 0x68, 0x21, 0x1C, 0xC5, 0x0D, 0xAB, 0x8D, 0x83, 0x49, 0x9E, 0x93, 0xB3, 0x6B, 0x09, 0x36, 0x5B, 0xE6, 0x7E, 0xC2, 0xF0, 0xE2, 0x86, 0x17, 0xA2, 0x03, 0x94, 0xD0, 0x44, 0xAE, 0xB4, 0x37, 0x92, 0x04, 0xA6, 0x77, 0x62, 0xD7, 0xC1, 0x1F, 0xF1, 0xC5, 0x10, 0xBF, 0x60, 0x88, 0xB1, 0x0F, 0x72, 0x41, 0x04, 0xF5, 0xDF, 0xA3, 0x3D, 0xE9, 0xFC, 0xA2, 0x20, 0xCC, 0x5A, 0x4A, 0xC8, 0x66, 0x6E, 0xF5, 0xBB, 0x21, 0xF4, 0xB9, 0xD7, 0x9B, 0xB3, 0x0C, 0xB4, 0x98, 0x7E, 0x24, 0x80, 0xBE, 0xF8, 0x39, 0xA6, 0xC9, 0xFF, 0x1A, 0x34, 0x30, 0xA9, 0xF4, 0xB7, 0x15, 0xA4, 0x25, 0xF0, 0x0C, }, .pub_len = 1312, }, { .name = "ML-DSA 65 (priv only)", .parameter_set = CKP_ML_DSA_65, .priv = { 0x18, 0x48, 0xEE, 0xB1, 0x92, 0x17, 0x81, 0xEF, 0x07, 0x65, 0x62, 0x1A, 0x0A, 0x92, 0x50, 0x69, 0x42, 0x9E, 0xC4, 0xBC, 0x9D, 0xCD, 0x29, 0xFB, 0xD4, 0x84, 0x5E, 0x68, 0x2E, 0x41, 0x78, 0x7F, 0x43, 0x4E, 0xEC, 0x4D, 0x37, 0x52, 0xCA, 0xD0, 0x89, 0x6C, 0x90, 0xC8, 0xA2, 0x7B, 0x00, 0x20, 0x86, 0x59, 0xF5, 0x9C, 0x88, 0xB3, 0xC1, 0xBE, 0xFA, 0x74, 0x2C, 0x15, 0x5C, 0x9F, 0xF3, 0x72, 0x0E, 0x92, 0xA3, 0xB5, 0xDE, 0xDA, 0xEB, 0x0E, 0x97, 0x48, 0x07, 0xF1, 0xD3, 0x9E, 0xED, 0x7B, 0xFE, 0x33, 0x0A, 0xC0, 0x14, 0x0E, 0x1F, 0xD0, 0x0D, 0xF3, 0x10, 0x2E, 0xF5, 0x08, 0xC1, 0xBF, 0x95, 0xEE, 0xBA, 0xF5, 0x31, 0x1D, 0x76, 0x62, 0x96, 0x7B, 0xB2, 0x38, 0x9E, 0x97, 0x75, 0x76, 0x67, 0xAC, 0xCE, 0x85, 0x5A, 0x11, 0xCC, 0x92, 0x67, 0x1D, 0xCA, 0x28, 0x10, 0x9F, 0x66, 0xA1, 0x28, 0x50, 0x80, 0x61, 0x50, 0x62, 0x40, 0x11, 0x63, 0x58, 0x87, 0x88, 0x28, 0x23, 0x01, 0x84, 0x06, 0x82, 0x07, 0x24, 0x65, 0x32, 0x31, 0x35, 0x78, 0x34, 0x80, 0x21, 0x51, 0x45, 0x61, 0x56, 0x22, 0x16, 0x36, 0x36, 0x15, 0x83, 0x88, 0x02, 0x65, 0x62, 0x12, 0x26, 0x81, 0x58, 0x88, 0x36, 0x45, 0x85, 0x68, 0x27, 0x00, 0x33, 0x01, 0x05, 0x06, 0x70, 0x68, 0x50, 0x54, 0x54, 0x11, 0x20, 0x05, 0x68, 0x47, 0x88, 0x15, 0x50, 0x21, 0x07, 0x82, 0x60, 0x17, 0x66, 0x87, 0x22, 0x67, 0x81, 0x20, 0x18, 0x58, 0x33, 0x18, 0x44, 0x70, 0x64, 0x26, 0x24, 0x22, 0x63, 0x84, 0x13, 0x73, 0x26, 0x42, 0x43, 0x65, 0x03, 0x57, 0x71, 0x84, 0x60, 0x64, 0x75, 0x87, 0x34, 0x08, 0x10, 0x63, 0x78, 0x72, 0x85, 0x20, 0x13, 0x47, 0x50, 0x65, 0x61, 0x75, 0x16, 0x83, 0x80, 0x84, 0x48, 0x40, 0x86, 0x00, 0x47, 0x47, 0x27, 0x07, 0x02, 0x82, 0x22, 0x21, 0x40, 0x31, 0x37, 0x03, 0x40, 0x23, 0x02, 0x06, 0x08, 0x13, 0x03, 0x45, 0x03, 0x75, 0x62, 0x40, 0x80, 0x27, 0x68, 0x36, 0x36, 0x30, 0x73, 0x53, 0x78, 0x05, 0x36, 0x28, 0x18, 0x16, 0x67, 0x70, 0x71, 0x66, 0x38, 0x01, 0x18, 0x62, 0x46, 0x38, 0x66, 0x74, 0x87, 0x25, 0x87, 0x03, 0x01, 0x37, 0x83, 0x73, 0x74, 0x45, 0x78, 0x83, 0x53, 0x84, 0x25, 0x83, 0x15, 0x37, 0x68, 0x40, 0x43, 0x36, 0x35, 0x47, 0x65, 0x57, 0x32, 0x34, 0x31, 0x50, 0x55, 0x04, 0x58, 0x53, 0x30, 0x36, 0x04, 0x24, 0x74, 0x47, 0x85, 0x27, 0x85, 0x55, 0x54, 0x44, 0x85, 0x53, 0x71, 0x55, 0x64, 0x14, 0x30, 0x57, 0x01, 0x34, 0x07, 0x01, 0x44, 0x70, 0x58, 0x71, 0x71, 0x50, 0x75, 0x72, 0x32, 0x60, 0x61, 0x72, 0x30, 0x55, 0x21, 0x07, 0x21, 0x50, 0x07, 0x33, 0x50, 0x44, 0x34, 0x71, 0x68, 0x45, 0x85, 0x23, 0x00, 0x68, 0x66, 0x58, 0x28, 0x23, 0x11, 0x37, 0x87, 0x17, 0x45, 0x76, 0x66, 0x37, 0x33, 0x58, 0x33, 0x41, 0x56, 0x36, 0x55, 0x00, 0x86, 0x76, 0x32, 0x66, 0x11, 0x18, 0x41, 0x42, 0x43, 0x10, 0x21, 0x50, 0x41, 0x10, 0x47, 0x58, 0x43, 0x44, 0x53, 0x00, 0x38, 0x17, 0x08, 0x30, 0x67, 0x58, 0x25, 0x76, 0x34, 0x26, 0x00, 0x38, 0x55, 0x87, 0x68, 0x11, 0x43, 0x88, 0x68, 0x15, 0x56, 0x20, 0x47, 0x76, 0x74, 0x14, 0x35, 0x46, 0x50, 0x07, 0x28, 0x78, 0x68, 0x48, 0x76, 0x12, 0x30, 0x55, 0x82, 0x78, 0x82, 0x45, 0x80, 0x11, 0x62, 0x78, 0x48, 0x26, 0x61, 0x61, 0x68, 0x12, 0x12, 0x02, 0x38, 0x44, 0x63, 0x57, 0x18, 0x26, 0x28, 0x23, 0x10, 0x60, 0x17, 0x10, 0x74, 0x34, 0x65, 0x36, 0x88, 0x07, 0x42, 0x26, 0x72, 0x83, 0x26, 0x47, 0x75, 0x70, 0x15, 0x63, 0x18, 0x06, 0x63, 0x14, 0x28, 0x83, 0x20, 0x68, 0x41, 0x56, 0x00, 0x12, 0x68, 0x68, 0x43, 0x72, 0x23, 0x08, 0x12, 0x58, 0x01, 0x86, 0x87, 0x05, 0x44, 0x08, 0x45, 0x44, 0x36, 0x02, 0x08, 0x22, 0x78, 0x33, 0x52, 0x86, 0x18, 0x85, 0x57, 0x58, 0x03, 0x76, 0x25, 0x07, 0x32, 0x21, 0x07, 0x63, 0x07, 0x03, 0x24, 0x37, 0x50, 0x17, 0x03, 0x65, 0x05, 0x32, 0x28, 0x84, 0x07, 0x38, 0x65, 0x44, 0x52, 0x05, 0x60, 0x47, 0x84, 0x14, 0x38, 0x50, 0x83, 0x61, 0x85, 0x37, 0x06, 0x30, 0x18, 0x48, 0x44, 0x32, 0x81, 0x85, 0x11, 0x10, 0x84, 0x76, 0x87, 0x70, 0x51, 0x56, 0x58, 0x11, 0x50, 0x40, 0x66, 0x33, 0x05, 0x24, 0x57, 0x16, 0x65, 0x15, 0x45, 0x80, 0x20, 0x81, 0x05, 0x07, 0x32, 0x04, 0x80, 0x11, 0x33, 0x34, 0x15, 0x86, 0x35, 0x55, 0x64, 0x46, 0x62, 0x55, 0x87, 0x01, 0x30, 0x33, 0x23, 0x54, 0x87, 0x00, 0x58, 0x73, 0x71, 0x50, 0x88, 0x62, 0x43, 0x87, 0x60, 0x74, 0x72, 0x02, 0x10, 0x86, 0x03, 0x84, 0x16, 0x34, 0x78, 0x71, 0x11, 0x67, 0x47, 0x10, 0x60, 0x72, 0x85, 0x24, 0x23, 0x02, 0x14, 0x82, 0x48, 0x32, 0x25, 0x08, 0x28, 0x77, 0x23, 0x58, 0x85, 0x08, 0x77, 0x78, 0x15, 0x13, 0x37, 0x37, 0x64, 0x02, 0x21, 0x14, 0x58, 0x27, 0x53, 0x71, 0x12, 0x05, 0x15, 0x33, 0x66, 0x28, 0x81, 0x38, 0x12, 0x88, 0x64, 0x81, 0x13, 0x35, 0x15, 0x31, 0x46, 0x73, 0x61, 0x56, 0x52, 0x16, 0x03, 0x63, 0x37, 0x21, 0x11, 0x56, 0x61, 0x61, 0x07, 0x51, 0x17, 0x64, 0x48, 0x43, 0x05, 0x58, 0x48, 0x63, 0x70, 0x35, 0x87, 0x27, 0x23, 0x02, 0x60, 0x38, 0x54, 0x16, 0x27, 0x33, 0x41, 0x06, 0x28, 0x64, 0x11, 0x05, 0x51, 0x48, 0x74, 0x25, 0x42, 0x41, 0x58, 0x07, 0x73, 0x07, 0x42, 0x18, 0x67, 0x25, 0x17, 0x78, 0x34, 0x81, 0x33, 0x21, 0x75, 0x56, 0x66, 0x48, 0x58, 0x63, 0x11, 0x34, 0x55, 0x12, 0x37, 0x21, 0x08, 0x77, 0x46, 0x86, 0x04, 0x20, 0x28, 0x34, 0x76, 0x41, 0x23, 0x08, 0x46, 0x24, 0x88, 0x34, 0x58, 0x60, 0x54, 0x33, 0x83, 0x70, 0x72, 0x27, 0x24, 0x87, 0x22, 0x58, 0x43, 0x05, 0x41, 0x12, 0x41, 0x26, 0x68, 0x36, 0x05, 0x62, 0x34, 0x43, 0x58, 0x45, 0x81, 0x76, 0x55, 0x58, 0x17, 0x06, 0x46, 0x44, 0x80, 0x52, 0x42, 0x46, 0x27, 0x86, 0x06, 0x75, 0x67, 0x35, 0x84, 0x73, 0x30, 0x70, 0x28, 0x10, 0x78, 0x08, 0x70, 0x57, 0x34, 0x37, 0x80, 0x56, 0x70, 0x06, 0x60, 0x35, 0x11, 0x63, 0x52, 0x37, 0x21, 0x15, 0x58, 0x33, 0x71, 0x04, 0x86, 0x55, 0x15, 0x37, 0x78, 0x38, 0x34, 0x74, 0x37, 0x12, 0x14, 0x08, 0x65, 0x61, 0x08, 0x04, 0x54, 0x75, 0x56, 0x71, 0x56, 0x32, 0x64, 0x33, 0x26, 0x48, 0x47, 0x31, 0x00, 0x45, 0x18, 0x41, 0x67, 0x76, 0x14, 0x40, 0x08, 0x06, 0x05, 0x70, 0x64, 0x83, 0x30, 0x68, 0x67, 0x56, 0x26, 0x11, 0x83, 0x14, 0x23, 0x33, 0x41, 0x16, 0x34, 0x65, 0x64, 0x33, 0x73, 0x41, 0x74, 0x77, 0x68, 0x31, 0x75, 0x05, 0x18, 0x86, 0x84, 0x60, 0x68, 0x21, 0x22, 0x81, 0x43, 0x43, 0x23, 0x84, 0x88, 0x11, 0x35, 0x23, 0x04, 0x38, 0x16, 0x34, 0x62, 0x08, 0x31, 0x37, 0x73, 0x33, 0x14, 0x52, 0x24, 0x04, 0x11, 0x15, 0x84, 0x40, 0x73, 0x84, 0x32, 0x46, 0x28, 0x73, 0x56, 0x30, 0x16, 0x24, 0x64, 0x52, 0x17, 0x78, 0x28, 0x02, 0x21, 0x34, 0x72, 0x20, 0x53, 0x80, 0x27, 0x01, 0x77, 0x00, 0x57, 0x27, 0x81, 0x34, 0x51, 0x30, 0x55, 0x66, 0x08, 0x81, 0x67, 0x10, 0x48, 0x54, 0x26, 0x04, 0x53, 0x06, 0x16, 0x33, 0x75, 0x77, 0x70, 0x85, 0x70, 0x84, 0x44, 0x57, 0x81, 0x50, 0x41, 0x18, 0x37, 0x84, 0x36, 0x27, 0x52, 0x01, 0x24, 0x46, 0x37, 0x31, 0x16, 0x53, 0x58, 0x48, 0x01, 0x67, 0x76, 0x44, 0x73, 0x08, 0x66, 0x88, 0x60, 0x31, 0x14, 0x11, 0x60, 0x31, 0x80, 0x11, 0x36, 0x74, 0x21, 0x64, 0x65, 0x56, 0x15, 0x27, 0x81, 0x04, 0x35, 0x15, 0x14, 0x47, 0x05, 0x84, 0x86, 0x35, 0x11, 0x56, 0x62, 0x71, 0x50, 0x85, 0x00, 0x52, 0x20, 0x42, 0x77, 0x56, 0x64, 0x86, 0x44, 0x23, 0x23, 0x31, 0x78, 0x67, 0x58, 0x64, 0x83, 0x22, 0x62, 0x30, 0x30, 0x13, 0x23, 0x74, 0x45, 0x87, 0x00, 0x04, 0x26, 0x06, 0x08, 0x16, 0x83, 0x42, 0x16, 0x55, 0x15, 0x54, 0x67, 0x66, 0x32, 0x47, 0x80, 0x27, 0x65, 0x56, 0x10, 0x64, 0x21, 0x48, 0x75, 0x02, 0x84, 0x62, 0x00, 0x77, 0x07, 0x27, 0x76, 0x50, 0x43, 0x57, 0x05, 0x36, 0x46, 0x72, 0x03, 0x27, 0x70, 0x02, 0x82, 0x72, 0x12, 0x21, 0x06, 0x55, 0x11, 0x46, 0x27, 0x34, 0x80, 0x34, 0x16, 0x70, 0x30, 0x33, 0x26, 0x25, 0x42, 0x75, 0x48, 0x36, 0x16, 0x84, 0x08, 0x61, 0x33, 0x84, 0x43, 0x61, 0x02, 0x73, 0x50, 0x22, 0x84, 0x31, 0x23, 0x60, 0x01, 0x38, 0x51, 0x87, 0x36, 0x74, 0x16, 0x86, 0x71, 0x55, 0x02, 0x05, 0x28, 0x77, 0x46, 0x14, 0x53, 0x86, 0x67, 0x60, 0x03, 0x33, 0x81, 0x68, 0x56, 0x44, 0x83, 0x11, 0x13, 0x64, 0x81, 0x15, 0x16, 0x22, 0x32, 0x00, 0x64, 0x71, 0x83, 0x47, 0x22, 0x56, 0x82, 0x88, 0x58, 0x11, 0x55, 0x71, 0x37, 0x88, 0x17, 0x67, 0x35, 0x64, 0x62, 0x76, 0x73, 0x41, 0x15, 0x56, 0x80, 0x27, 0x12, 0x62, 0x00, 0x73, 0x27, 0x02, 0x66, 0x72, 0x06, 0x58, 0x61, 0x43, 0x24, 0x55, 0x44, 0x64, 0x67, 0x73, 0x10, 0x61, 0x42, 0x84, 0x17, 0x40, 0x22, 0x44, 0x15, 0x25, 0x44, 0x40, 0x78, 0x44, 0x06, 0x17, 0x55, 0x56, 0x43, 0x42, 0x63, 0x66, 0x84, 0x58, 0x15, 0x60, 0x75, 0x20, 0x80, 0x86, 0x46, 0x20, 0x84, 0x82, 0x11, 0x22, 0x73, 0x10, 0x63, 0x03, 0x60, 0x23, 0x02, 0x84, 0x34, 0x60, 0x51, 0x23, 0x30, 0x63, 0x45, 0x12, 0x57, 0x45, 0x56, 0x83, 0x51, 0x14, 0x17, 0x16, 0x12, 0x68, 0x77, 0x87, 0x82, 0x23, 0x40, 0x67, 0x76, 0x67, 0x36, 0x68, 0x80, 0x38, 0x68, 0x34, 0x11, 0x66, 0x21, 0x01, 0x82, 0x54, 0x23, 0x54, 0x75, 0x57, 0x52, 0x15, 0x31, 0x81, 0x73, 0x48, 0x85, 0x05, 0x73, 0x36, 0x51, 0x64, 0x08, 0x16, 0x68, 0x05, 0x28, 0x01, 0x86, 0x21, 0x21, 0x53, 0x02, 0x24, 0x56, 0x45, 0x67, 0x60, 0x48, 0x67, 0x37, 0x88, 0x67, 0x11, 0x54, 0x38, 0x83, 0x77, 0x55, 0x41, 0x70, 0x85, 0x81, 0x85, 0x36, 0x10, 0x32, 0x02, 0x25, 0x65, 0x13, 0x01, 0x21, 0x65, 0x35, 0x13, 0x54, 0x47, 0x41, 0x01, 0x44, 0x76, 0x84, 0x34, 0x05, 0x66, 0x00, 0x26, 0x74, 0x53, 0x73, 0x12, 0x28, 0x70, 0x75, 0x30, 0x88, 0x87, 0x04, 0x85, 0x72, 0x25, 0x53, 0x17, 0x42, 0x78, 0x25, 0x02, 0x52, 0x22, 0x26, 0x08, 0x42, 0x45, 0x18, 0x31, 0x05, 0x56, 0x23, 0x55, 0x86, 0x24, 0x47, 0x15, 0x56, 0x32, 0x67, 0x32, 0x58, 0x16, 0x78, 0x74, 0x42, 0x16, 0x73, 0x70, 0x24, 0x53, 0x00, 0x46, 0x40, 0x83, 0x50, 0x11, 0x73, 0x54, 0x24, 0x24, 0x53, 0x51, 0x81, 0x54, 0x84, 0x62, 0x03, 0x52, 0x27, 0x24, 0x33, 0x16, 0x04, 0x50, 0x05, 0x54, 0x76, 0x64, 0x42, 0x03, 0x32, 0x40, 0x45, 0x36, 0x00, 0x23, 0x30, 0x48, 0x75, 0x00, 0x28, 0x44, 0x45, 0x37, 0x07, 0x31, 0x47, 0x30, 0x17, 0x74, 0x6D, 0x24, 0x3F, 0xCC, 0x1C, 0x1F, 0x04, 0x2B, 0x78, 0xD4, 0x3D, 0x9E, 0xEB, 0xD6, 0xB3, 0xA6, 0x39, 0xB9, 0xAC, 0xF2, 0xEB, 0x77, 0x2E, 0x23, 0xAF, 0x4F, 0xA1, 0x7F, 0xA9, 0x31, 0x83, 0x92, 0xCD, 0xF1, 0x01, 0xD2, 0x51, 0x63, 0x31, 0xA8, 0xEB, 0xEE, 0x26, 0x82, 0x1F, 0xB4, 0x6A, 0x4D, 0xE0, 0x49, 0x86, 0xAE, 0xE1, 0x6B, 0x16, 0x2C, 0x35, 0x26, 0x4D, 0x4D, 0x73, 0x87, 0x0F, 0xE6, 0xF8, 0xAF, 0x6C, 0x1C, 0x9F, 0x76, 0xC0, 0xCA, 0x53, 0x47, 0x47, 0xAA, 0x4B, 0xE1, 0xE8, 0x9E, 0x7D, 0x42, 0x4F, 0x8C, 0x07, 0x20, 0x0D, 0x9D, 0xC5, 0x08, 0xF4, 0xF8, 0x00, 0x12, 0x73, 0x6B, 0xFF, 0xAA, 0x00, 0xA8, 0x2C, 0x83, 0x25, 0x5E, 0x22, 0x95, 0xAC, 0x17, 0xF5, 0xF4, 0xAD, 0xAF, 0x56, 0x0A, 0x4A, 0x6A, 0xA9, 0x2C, 0x89, 0xAF, 0x54, 0x53, 0x70, 0x05, 0x1F, 0x08, 0x76, 0xC9, 0x6E, 0xB8, 0x5A, 0x89, 0x47, 0x0D, 0xE8, 0x16, 0x49, 0x3A, 0xDF, 0x08, 0xFB, 0x9F, 0xE7, 0x3F, 0xA5, 0xC6, 0x5C, 0x06, 0x73, 0x81, 0x3F, 0x86, 0x3D, 0xA1, 0x6A, 0x32, 0xC2, 0xFA, 0x82, 0xDE, 0x76, 0x73, 0x4C, 0x43, 0x31, 0x74, 0x71, 0x2F, 0x55, 0x89, 0xD0, 0x45, 0x56, 0xFB, 0x29, 0x75, 0xCC, 0xA7, 0x28, 0x89, 0xF2, 0xA9, 0xCC, 0x3C, 0x8B, 0x94, 0xCC, 0x77, 0xB3, 0xE3, 0xB1, 0xBA, 0xB6, 0x8A, 0xD4, 0xDC, 0xA2, 0xCD, 0x54, 0xEC, 0x41, 0xAE, 0x56, 0x87, 0xA5, 0x24, 0x9F, 0x0C, 0x44, 0x84, 0xE4, 0x67, 0x07, 0xD8, 0x48, 0x76, 0xAA, 0x61, 0x3D, 0x9C, 0xFF, 0xC8, 0xA0, 0x05, 0x21, 0xFE, 0x7E, 0xC7, 0xBB, 0xF4, 0x5A, 0xA9, 0xA2, 0xFA, 0xAD, 0xD5, 0xEB, 0x9A, 0xBD, 0x4C, 0x13, 0xF5, 0x44, 0xB5, 0xEC, 0x87, 0x19, 0xB4, 0x99, 0xC4, 0x58, 0xD0, 0x28, 0x2A, 0x3C, 0x2C, 0x06, 0x82, 0x99, 0xF8, 0x05, 0x3B, 0xE0, 0x0B, 0xA6, 0x1F, 0x45, 0x1D, 0x5B, 0x4F, 0xEB, 0xD4, 0x3B, 0xB5, 0xFC, 0x7C, 0xC7, 0xE6, 0x6B, 0x41, 0x92, 0xA9, 0x95, 0x04, 0xBD, 0x14, 0x6E, 0x87, 0x3A, 0x74, 0x4D, 0x7B, 0x16, 0xA8, 0xCA, 0x9A, 0x4A, 0x1E, 0xD5, 0x28, 0xB0, 0xF3, 0x0D, 0xD8, 0x04, 0xCB, 0xDF, 0x57, 0x83, 0xFF, 0xC0, 0x9E, 0xA5, 0xA9, 0x09, 0x23, 0x02, 0x73, 0x3D, 0x60, 0x97, 0x79, 0x05, 0x42, 0xC7, 0x9E, 0xDA, 0xA0, 0xCC, 0x82, 0x97, 0x62, 0x2C, 0x9B, 0xCC, 0xDB, 0xF3, 0xC9, 0x75, 0x86, 0xED, 0x6C, 0x84, 0xE4, 0xE5, 0xA2, 0x59, 0x19, 0xB8, 0x5C, 0xE1, 0x10, 0x81, 0x4C, 0xDC, 0x05, 0x0C, 0x1E, 0xAB, 0x4E, 0xC8, 0x2F, 0xFC, 0xA4, 0xC2, 0x6F, 0xE6, 0x73, 0x8F, 0x30, 0x0B, 0xE8, 0x7C, 0xC7, 0xDF, 0x99, 0xEB, 0x54, 0x6E, 0x3C, 0xD8, 0x40, 0xF3, 0x51, 0x47, 0x39, 0x8E, 0xF2, 0x57, 0xAC, 0xDC, 0x6F, 0x51, 0xE4, 0x20, 0x5D, 0x9E, 0x85, 0xED, 0x88, 0x58, 0x31, 0xE9, 0x08, 0xDE, 0x81, 0xA5, 0xC5, 0xF7, 0x7A, 0x87, 0xA2, 0x13, 0xBB, 0xE6, 0x11, 0x66, 0x54, 0x01, 0x89, 0x22, 0x9A, 0x69, 0x48, 0x3C, 0x67, 0x74, 0xA6, 0xAE, 0xC4, 0xC7, 0x52, 0xA3, 0xCF, 0xEF, 0x0D, 0xB8, 0x96, 0xDE, 0x64, 0xA5, 0x7F, 0x41, 0xBC, 0x97, 0xBB, 0x45, 0x28, 0x69, 0x3C, 0xFE, 0x44, 0x13, 0xBF, 0x44, 0x55, 0xAC, 0x30, 0x1A, 0x74, 0x00, 0x70, 0xB0, 0x75, 0xEF, 0x53, 0x8D, 0x4F, 0x28, 0xD1, 0x44, 0xDE, 0x21, 0x6F, 0x4E, 0x83, 0xA9, 0x0F, 0x2B, 0x71, 0xE5, 0xFD, 0xD8, 0xD1, 0xAB, 0x3B, 0x50, 0x19, 0x0A, 0xB0, 0xFD, 0x64, 0xCF, 0x46, 0x37, 0x59, 0x22, 0x4F, 0x1B, 0x0D, 0xE9, 0x17, 0xFD, 0xC7, 0x0E, 0xAB, 0x3A, 0xF1, 0x8C, 0x19, 0x95, 0xC5, 0x78, 0x80, 0xD6, 0xEC, 0xC2, 0xCA, 0x9D, 0xA8, 0x14, 0x42, 0x4A, 0x22, 0xA2, 0x1C, 0x76, 0xD2, 0x59, 0x8C, 0xAB, 0xDD, 0x9E, 0xE1, 0x4C, 0x2A, 0xB3, 0x10, 0xCD, 0x5C, 0x17, 0x7F, 0xB4, 0x3F, 0x01, 0xFE, 0xC4, 0x0F, 0xE6, 0x0C, 0x1C, 0xD9, 0x17, 0xAF, 0x78, 0xBF, 0x1C, 0xB6, 0xD8, 0xDA, 0x3C, 0x61, 0x37, 0x55, 0x9D, 0xCE, 0xFB, 0xFE, 0xA6, 0xD0, 0xAA, 0xBD, 0xBB, 0xFB, 0xF1, 0x49, 0x1E, 0x17, 0x7D, 0x6F, 0x39, 0x6B, 0xC2, 0x02, 0xAD, 0xF5, 0xC7, 0x26, 0xE4, 0xD1, 0x69, 0x85, 0x8A, 0x7E, 0xFD, 0x13, 0x8D, 0x65, 0x00, 0x82, 0xB0, 0x79, 0xFD, 0xB7, 0x07, 0xE9, 0x08, 0xFB, 0x61, 0xCC, 0x1D, 0x73, 0x58, 0x0F, 0x9A, 0x1D, 0xA0, 0xAC, 0xFC, 0xCA, 0xE3, 0x13, 0x80, 0xA7, 0xAF, 0x47, 0x64, 0xA3, 0x8A, 0xEA, 0xA6, 0xA0, 0xFF, 0x72, 0x86, 0xA3, 0x9C, 0xDE, 0xE6, 0xDD, 0x33, 0x4A, 0xF2, 0x55, 0xA4, 0x99, 0xB6, 0xAA, 0xA5, 0x9D, 0x7C, 0x3D, 0x30, 0x15, 0xD4, 0xCD, 0xBC, 0x09, 0x5E, 0x1E, 0x32, 0xB9, 0xCD, 0xC4, 0x9F, 0x82, 0x1E, 0x10, 0xB3, 0x61, 0x36, 0xB3, 0x4B, 0xD3, 0x7C, 0x64, 0xFE, 0x41, 0x7E, 0xE5, 0x56, 0xEA, 0xC6, 0x57, 0x40, 0x9E, 0x68, 0xF9, 0x34, 0xA9, 0x37, 0xC8, 0x4B, 0x24, 0x9D, 0xA3, 0x96, 0xF5, 0x2F, 0x7F, 0x6F, 0x0A, 0xA5, 0x5E, 0x8C, 0xB9, 0x19, 0xE4, 0xD2, 0xC2, 0x0F, 0x41, 0x3A, 0xB6, 0x3E, 0x2F, 0xE1, 0xB6, 0xFD, 0xFE, 0x9A, 0x3A, 0x69, 0x9D, 0xBA, 0x0B, 0x1F, 0x61, 0x17, 0x06, 0xDF, 0x1E, 0x13, 0x38, 0xD1, 0x64, 0xF6, 0x21, 0x5D, 0x10, 0x8A, 0xFB, 0x53, 0x0D, 0x74, 0x3A, 0x15, 0xF5, 0x4F, 0x37, 0x44, 0x88, 0xB3, 0xED, 0xB3, 0x97, 0x51, 0xAD, 0x32, 0xC2, 0x2F, 0xD9, 0x1B, 0x35, 0xDD, 0x50, 0x8F, 0x01, 0x1F, 0x77, 0x80, 0x25, 0x30, 0x67, 0x0F, 0x15, 0xCE, 0x4F, 0x54, 0x28, 0x90, 0xA9, 0x22, 0x92, 0xA7, 0x86, 0xC4, 0x43, 0x05, 0x9C, 0x4D, 0xC5, 0xEA, 0xE9, 0xB5, 0xED, 0xAA, 0x82, 0x84, 0x0F, 0x03, 0x14, 0x5D, 0x33, 0x3F, 0x43, 0xDB, 0x79, 0x40, 0xC5, 0x5C, 0xC6, 0x72, 0x91, 0x5E, 0xF0, 0x7D, 0xB2, 0xB3, 0xF2, 0x99, 0xE6, 0x22, 0xA8, 0x1A, 0xFA, 0xA9, 0x79, 0x0D, 0xF6, 0x0C, 0x2B, 0x51, 0x4B, 0xA4, 0x91, 0x42, 0xA1, 0xCF, 0x4B, 0x17, 0x42, 0xC7, 0xED, 0x0C, 0x23, 0x6A, 0x2D, 0x84, 0x68, 0x94, 0xE5, 0xA8, 0x3C, 0xE2, 0x31, 0x07, 0xAD, 0xF7, 0x28, 0x6F, 0xF0, 0x8D, 0x73, 0x72, 0xB0, 0x53, 0xA2, 0xEC, 0x4C, 0x3E, 0x7D, 0xBB, 0x18, 0xA1, 0xE1, 0x8A, 0x74, 0x43, 0xD3, 0x7A, 0x2A, 0x18, 0x0D, 0xDA, 0x18, 0x3B, 0xD3, 0x3E, 0x78, 0x83, 0x0D, 0xF9, 0xEC, 0x50, 0xB1, 0xE8, 0x42, 0x65, 0x92, 0xF9, 0x74, 0xC4, 0xD3, 0x47, 0x3D, 0xA6, 0x0F, 0x9A, 0x42, 0x6C, 0xEB, 0x63, 0x51, 0xD3, 0xB7, 0x33, 0x40, 0xFC, 0x44, 0x08, 0x22, 0x7A, 0xE7, 0xD4, 0x6C, 0x42, 0x0C, 0x9B, 0xEE, 0x9C, 0x40, 0xE7, 0xDC, 0xE0, 0x4A, 0x3C, 0x19, 0x09, 0x6C, 0xB8, 0x98, 0x44, 0x64, 0x33, 0x8C, 0x8C, 0xE6, 0x01, 0x65, 0xE0, 0xA6, 0x3C, 0xE6, 0x31, 0xF6, 0x3C, 0xF4, 0x0C, 0xD1, 0x3F, 0xD9, 0x0E, 0x06, 0xFC, 0xB4, 0x8A, 0xC4, 0xA0, 0xD7, 0x60, 0x5D, 0x88, 0xC3, 0x1C, 0xBC, 0x8A, 0x63, 0xED, 0x6B, 0xD1, 0xA2, 0xF0, 0x4B, 0xB6, 0x61, 0xC7, 0x60, 0xDD, 0x54, 0x2D, 0xC6, 0x86, 0xA4, 0xC2, 0x5D, 0x15, 0x1A, 0xF1, 0x11, 0x7E, 0xCB, 0xBE, 0xC3, 0x10, 0x68, 0x63, 0x0F, 0x5B, 0xF2, 0x36, 0xF7, 0xAB, 0xC4, 0xCF, 0xC3, 0x51, 0xAA, 0x0A, 0x58, 0xC5, 0x6F, 0xD4, 0xD7, 0x1A, 0x3D, 0x0A, 0xE3, 0xDB, 0x06, 0x17, 0x27, 0xAD, 0x5F, 0xF3, 0x04, 0x1B, 0xDB, 0x68, 0x98, 0x7B, 0x71, 0x4D, 0x1E, 0x36, 0xB1, 0xC2, 0xCB, 0xBE, 0xC2, 0x82, 0xBC, 0xBD, 0x41, 0x3F, 0x39, 0x83, 0xF2, 0x98, 0xD1, 0xEF, 0xBC, 0x8B, 0x1B, 0x2A, 0xD8, 0x41, 0x26, 0xF7, 0xF7, 0x57, 0xFC, 0x27, 0x19, 0xBE, 0xE2, 0x09, 0x8D, 0x95, 0xD1, 0x43, 0x06, 0xCB, 0x79, 0x27, 0x3B, 0x36, 0xB9, 0x48, 0xF0, 0x29, 0x86, 0x7C, 0x2B, 0xC7, 0x01, 0x62, 0x4E, 0xE8, 0xCA, 0x08, 0x44, 0x81, 0xE6, 0x40, 0xB4, 0x62, 0x9D, 0x96, 0x5D, 0xBA, 0xE5, 0x09, 0x9E, 0x88, 0xBE, 0x95, 0x55, 0xA1, 0xAA, 0x69, 0xD5, 0x89, 0x08, 0x60, 0x9D, 0x95, 0xE3, 0xBD, 0x8C, 0xFE, 0xA0, 0x48, 0x4D, 0x7E, 0xF3, 0xFA, 0x3F, 0x84, 0x51, 0x62, 0x01, 0x2F, 0xEB, 0x59, 0xE4, 0x42, 0x91, 0x8D, 0x59, 0xF8, 0x24, 0x2C, 0xEC, 0x94, 0xFE, 0xD6, 0xC4, 0xFE, 0xBF, 0xB2, 0xE3, 0x37, 0x0D, 0x03, 0x30, 0x42, 0x10, 0x04, 0x1D, 0x7A, 0x30, 0x83, 0x85, 0xA9, 0x38, 0x56, 0x76, 0x90, 0x6B, 0x44, 0xE4, 0xED, 0x2B, 0xBF, 0xCD, 0xFD, 0xC9, 0x1C, 0x68, 0xAC, 0xFB, 0xA4, 0x91, 0xCD, 0xE9, 0xAB, 0x19, 0x86, 0x91, 0x20, 0x42, 0x0D, 0x00, 0x1E, 0x3B, 0x72, 0xD5, 0x21, 0xAC, 0x6E, 0x0A, 0xD1, 0x4F, 0xB3, 0xB3, 0xBA, 0x5A, 0xDF, 0x89, 0x0B, 0x8A, 0x88, 0xF2, 0xC8, 0xB8, 0x81, 0x44, 0xF7, 0xA5, 0x20, 0x5C, 0x85, 0x02, 0xB7, 0x03, 0x67, 0x8D, 0xCB, 0x4F, 0xCE, 0xF3, 0x4F, 0x7B, 0xAC, 0x03, 0xFD, 0xE7, 0x9A, 0x3A, 0x3A, 0x3F, 0xD9, 0x9D, 0x7C, 0x95, 0x6A, 0xF9, 0xC9, 0x93, 0x4D, 0x6D, 0xE6, 0x6F, 0xEA, 0x41, 0x28, 0xC3, 0x61, 0x19, 0xBA, 0x81, 0x6D, 0xBA, 0xA6, 0xD8, 0x18, 0xB3, 0xAE, 0xAA, 0x1B, 0x20, 0x62, 0xA6, 0x3A, 0xEE, 0x8B, 0x0D, 0x99, 0xBB, 0x6F, 0xC4, 0x9B, 0x3D, 0x0D, 0x21, 0x29, 0xBF, 0x1C, 0x57, 0xE1, 0x5E, 0x77, 0x88, 0xC3, 0x75, 0x8E, 0x6E, 0x72, 0x2C, 0x72, 0x47, 0x06, 0x9C, 0xFD, 0xD4, 0x4D, 0x49, 0x16, 0xEC, 0xFD, 0x8D, 0x8D, 0x85, 0xB5, 0x58, 0xF3, 0xE8, 0x8C, 0xCB, 0x4C, 0x17, 0x86, 0x9A, 0x94, 0x3D, 0xBE, 0x99, 0x1C, 0x4A, 0x0C, 0x1F, 0x5C, 0x83, 0xCA, 0x94, 0x2D, 0x21, 0x58, 0x1F, 0x32, 0xF1, 0x95, 0x14, 0x6A, 0x8E, 0x1D, 0xAF, 0xCF, 0xC3, 0x7B, 0x0C, 0x25, 0x58, 0x7F, 0xC9, 0xB0, 0x81, 0x88, 0x57, 0x72, 0x9B, 0x18, 0x6A, 0x5F, 0x38, 0x96, 0x1B, 0xD7, 0x19, 0x0C, 0x5C, 0x2E, 0x62, 0xB7, 0xEE, 0xAF, 0x58, 0xCE, 0xF7, 0x18, 0x7B, 0xE8, 0x46, 0x48, 0x85, 0x1F, 0x87, 0x03, 0xB3, 0xBF, 0x07, 0x7D, 0xD8, 0xA1, 0x91, 0xB2, 0x2F, 0x3B, 0xDE, 0xD0, 0xB4, 0xC0, 0x45, 0xD3, 0xD5, 0xAD, 0x11, 0x2D, 0x72, 0xF2, 0xE7, 0x46, 0xA0, 0x12, 0xCD, 0xEF, 0xA2, 0xF1, 0x63, 0x22, 0x0F, 0x1A, 0x4E, 0xC2, 0x9A, 0x44, 0xD7, 0xFF, 0x56, 0x5C, 0x5A, 0x14, 0x9B, 0xAA, 0xB0, 0xF3, 0xAA, 0x2A, 0xA6, 0xEE, 0xF9, 0xF5, 0x35, 0x20, 0x4D, 0x22, 0xE9, 0x3C, 0x07, 0x0E, 0x66, 0x9E, 0x81, 0xD7, 0x2F, 0x1D, 0xB1, 0x62, 0xF7, 0xA7, 0x3C, 0x73, 0x9D, 0xB6, 0x3A, 0x02, 0x47, 0xB8, 0xB8, 0x91, 0x3F, 0xD3, 0x3B, 0x46, 0xE1, 0xAF, 0xC8, 0x24, 0x49, 0xDC, 0x1B, 0x06, 0xE2, 0xB3, 0xD0, 0x5F, 0xEE, 0x98, 0x51, 0x59, 0x71, 0xE4, 0xA8, 0xB9, 0x9B, 0xC8, 0x6F, 0xCF, 0x25, 0x38, 0x96, 0x9C, 0x8B, 0xBA, 0x5D, 0x41, 0x93, 0x74, 0x1E, 0xDE, 0x0B, 0x60, 0x09, 0xB0, 0x06, 0xC8, 0x79, 0x31, 0xB2, 0x5E, 0x00, 0x7F, 0x4D, 0x4A, 0x5A, 0x71, 0xD1, 0x73, 0xED, 0x09, 0x71, 0xD4, 0x9D, 0x13, 0x01, 0xC6, 0x4B, 0x57, 0xDC, 0x08, 0x27, 0x3B, 0xBF, 0x53, 0x82, 0xC3, 0x2A, 0xBF, 0xA6, 0x65, 0xD8, 0x69, 0x27, 0x69, 0x37, 0x3D, 0x8D, 0x69, 0x90, 0xE4, 0x4A, 0x4C, 0x3B, 0x8E, 0x7D, 0xCD, 0x8C, 0x53, 0x03, 0x38, 0x28, 0xBB, 0x80, 0x4E, 0xD7, 0xAC, 0x5B, 0x8D, 0x09, 0x47, 0x45, 0xD3, 0xAB, 0xE4, 0x1D, 0x80, 0x38, 0x32, 0xFC, 0x52, 0x67, 0xC8, 0x66, 0xA1, 0x6C, 0xEF, 0x68, 0x48, 0x90, 0x10, 0x75, 0xAF, 0x85, 0x6C, 0xCC, 0x45, 0x6A, 0x2C, 0x14, 0x63, 0xAD, 0xBB, 0xF6, 0x7A, 0x82, 0x1F, 0x12, 0x9D, 0x9D, 0x41, 0xE0, 0xD1, 0x65, 0xB3, 0x3A, 0x38, 0x02, 0x44, 0xC2, 0xFB, 0x84, 0xD7, 0x0E, 0xCA, 0xFB, 0x85, 0x8C, 0xBF, 0x74, 0x85, 0x1D, 0x26, 0x82, 0x11, 0x93, 0x56, 0x94, 0x94, 0xA0, 0xB4, 0x90, 0xF8, 0xD6, 0xCF, 0xE7, 0xB0, 0x9A, 0x47, 0x26, 0xC9, 0xB1, 0x50, 0x4B, 0xD6, 0x8F, 0x6C, 0x5A, 0x35, 0x76, 0x33, 0x62, 0xD6, 0x76, 0xEF, 0x62, 0x41, 0xFF, 0xC5, 0xBE, 0x95, 0x91, 0x3F, 0x89, 0x1B, 0xFE, 0xA6, 0x78, 0xF8, 0xDE, 0x8E, 0xC7, 0xB8, 0x0D, 0xA4, 0x49, 0xEB, 0xEE, 0xF9, 0xB7, 0xC2, 0x18, 0x14, 0x0C, 0xB1, 0x4C, 0xD4, 0xC7, 0x3E, 0x7F, 0x10, 0x9B, 0xF8, 0x6B, 0xC0, 0x3E, 0x6D, 0x94, 0xD3, 0x7B, 0xC2, 0xB2, 0x95, 0x08, 0x25, 0xE3, 0x30, 0xF4, 0xEC, 0x5A, 0x98, 0xFB, 0x35, 0x8D, 0xB4, 0xDF, 0x71, 0xF2, 0x59, 0x0A, 0x6F, 0xFA, 0xA6, 0xD5, 0x4A, 0x37, 0x6E, 0x71, 0xE0, 0x57, 0x9B, 0x18, 0xDC, 0xCB, 0xB6, 0x00, 0x66, 0xD9, 0x2F, 0xFB, 0x11, 0xE6, 0x36, 0x56, 0x12, 0xE9, 0x27, 0x61, 0xE3, 0xAD, 0xFD, 0x57, 0xE1, 0xF7, 0xCF, 0x50, 0x80, 0xED, 0x36, 0x6E, 0x2B, 0xFE, 0x24, 0xB6, 0x19, 0x92, 0x90, 0x8F, 0x30, 0x7D, 0x28, 0xD1, 0x18, 0xFE, 0x53, 0xE6, 0x42, 0x86, 0x83, 0x41, 0xA1, 0x14, 0x04, 0x9D, 0x14, 0x86, 0x65, 0x3A, 0x85, 0x76, 0x26, 0x60, 0x66, 0x3B, 0x15, 0xD0, 0xA0, 0xA2, 0x13, 0x58, 0x82, 0x76, 0xF9, 0x09, 0x50, 0xEA, 0xC4, 0xD3, 0xC4, 0x46, 0x87, 0x05, 0x5D, 0xD1, 0xEE, 0x5B, 0xAA, 0xBA, 0x56, 0xD3, 0x34, 0xA7, 0x44, 0x7C, 0x39, 0xAB, 0x35, 0x3A, 0x3C, 0x7D, 0x5D, 0x8A, 0xBE, 0x7B, 0x47, 0xDE, 0xBC, 0x08, 0x14, 0xD9, 0x73, 0x8E, 0x38, 0xF6, 0xC1, 0x83, 0x58, 0xAE, 0x37, 0x2E, 0xEC, 0x3D, 0x73, 0x7F, 0xEB, 0x5E, 0x94, 0x4A, 0xC2, 0x0D, 0x0E, 0x39, 0x09, 0x2D, 0xA4, 0x04, 0x13, 0xE5, 0x94, 0x90, 0x76, 0xAD, 0x5D, 0xEB, 0xEC, 0x98, 0x76, 0x7B, 0xE4, 0xED, 0x4C, 0xA2, 0x3C, 0x2F, 0x84, 0xFB, 0xFF, 0xDC, 0x61, 0x5B, 0x37, 0x41, 0xE0, 0x0E, 0xBB, 0x1E, 0x34, 0x5A, 0x6E, 0xAA, 0x7B, 0x05, 0x61, 0x61, 0x5A, 0x87, 0x8D, 0x81, 0x54, 0x3A, 0x79, 0xF8, 0xCA, 0x99, 0xE1, 0xAB, 0xC4, 0xC1, 0x6B, 0x22, 0xB1, 0xCD, 0x17, 0x31, 0x92, 0x8A, 0x34, 0x9C, 0x25, 0xF1, 0xE3, 0xE1, 0x9D, 0xE9, 0xFB, 0x2F, 0x14, 0x15, 0x27, 0xAE, 0x83, 0xE8, 0x81, 0xCE, 0xE1, 0x2E, 0xE5, 0xAA, 0xC1, 0xA1, 0xD8, 0x41, 0xDD, 0x46, 0xCD, 0xE6, 0x3D, 0x69, 0x71, 0xFF, 0x5D, 0x19, 0xFA, 0xE1, 0x9E, 0x92, 0xF4, 0x26, 0xF2, 0xE3, 0xAC, 0x0D, 0x75, 0xFA, 0xCE, 0xC9, 0x33, 0xB4, 0x89, 0xE9, 0x10, 0x85, 0xB0, 0xB4, 0x7D, 0x50, 0xD8, 0xEE, 0x85, 0x9E, 0x5D, 0x35, 0x96, 0x88, 0x9A, 0xAF, 0x53, 0x5A, 0xD6, 0xC8, 0xC7, 0x35, 0x8E, 0x80, 0x77, 0x4D, 0x15, 0x63, 0x06, 0x51, 0xD0, 0x0F, 0x2D, 0x4A, 0x62, 0x4A, 0x53, 0xD9, 0x1C, 0x5C, 0x96, 0x29, 0xFC, 0xDA, 0xB0, 0xA5, 0x2B, 0x54, 0x88, 0x90, 0x50, 0x9B, 0x4D, 0x27, 0x40, 0x6A, 0x5A, 0x32, 0xD3, 0x59, 0xF0, 0x2A, 0xE4, 0x18, 0x74, 0x52, 0xFF, 0xBF, 0x33, 0x26, 0xAA, 0x4A, 0xF2, 0x22, 0x65, 0x97, 0xEE, 0x7D, 0x72, 0xC6, 0xD4, 0x7D, 0xA4, 0x67, 0x7F, 0x02, 0x06, 0x98, 0x0F, 0x86, 0x10, 0x42, 0x11, 0x1C, 0xA0, 0xEA, 0x12, 0xF7, 0xEF, 0x71, 0xC5, 0x0D, 0x8C, 0x7A, 0xC4, 0x51, 0xFF, 0x42, 0x84, 0x41, 0xE6, 0x32, 0x22, 0xEF, 0x82, 0xD1, 0x17, 0xE6, 0x26, 0xC8, 0x81, 0x36, 0x52, 0x80, 0xA0, 0x67, 0xA2, 0xB6, 0xE0, 0xE3, 0x91, 0xB0, 0x9D, 0x0E, 0x09, 0x7C, 0x56, 0x13, 0x2D, 0x80, 0xDA, 0xD7, 0x49, 0xDC, 0x1A, 0x9B, 0xCA, 0xF2, 0x21, 0x38, 0xC2, 0xDC, 0xFE, 0x2C, 0x1D, 0x1E, 0x87, 0xF3, 0xFD, 0xC4, 0xB8, 0xC7, 0x82, 0xCA, 0x18, 0x1A, 0x45, 0x72, 0x01, 0x77, 0xFC, 0x60, 0x6D, 0x7B, 0x6C, 0x33, 0x4F, 0xFF, 0x7E, 0x6D, 0x04, 0xF6, 0x7D, 0x1F, 0xA7, 0x5A, 0xC4, 0x9B, 0xB7, 0x0A, 0x45, 0xD3, 0x4E, 0x04, 0x94, 0xD2, 0x11, 0xE1, 0xCA, 0x71, 0x91, 0xDF, 0x84, 0x05, 0xCD, 0x15, 0x09, 0x70, 0x34, 0x93, 0xEC, 0xB4, 0xEB, 0x44, 0x8A, 0x57, 0xA3, 0x3B, 0x5E, 0x40, 0x78, 0x03, 0x40, 0x9D, 0x82, 0x94, 0xEF, 0xDB, 0x45, 0xA2, 0xDF, 0xF9, 0xBD, 0xCB, 0x48, 0x11, 0xB6, 0xCA, 0x8C, 0x5A, 0x6B, 0x84, 0xE4, 0xC8, 0xE6, 0xFB, 0x0E, 0x6F, 0xD1, 0x87, 0x80, 0x45, 0x32, 0x70, 0x1D, 0xE6, 0xC8, 0x0E, 0x3C, 0xBE, 0x22, 0xCE, 0x90, 0x06, 0xF4, 0x74, 0x6A, 0x61, 0x16, 0xED, 0x48, 0xCF, 0x7C, 0xE2, 0xD6, 0xC3, 0x3F, 0x70, 0x44, 0xCE, 0x2F, 0xBC, 0xC0, 0xE8, 0x9D, 0x60, 0xFC, 0x60, 0x5F, 0xBD, 0xC9, 0x7E, 0x10, 0xB4, 0xD2, 0xB6, 0xCD, 0x0A, 0x84, 0x15, 0xD6, 0x18, 0xE8, 0x43, 0x0C, 0xFF, 0x86, 0x6A, 0x8E, 0x56, 0x47, 0xA3, 0xC9, 0x77, 0x7C, 0xC7, 0x88, 0x5D, 0xAD, 0xCB, 0x67, 0x0B, 0x95, 0xCD, 0xBE, 0xAD, 0x7D, 0x85, 0x55, 0x61, 0xA6, 0x01, 0x48, 0x55, 0xB1, 0x18, 0xDF, 0xF9, 0x37, 0xA1, 0x7E, 0x9F, 0xB6, 0x2E, 0xC6, 0xE6, 0xDB, 0x42, 0x39, 0x4C, 0x04, 0x4E, 0x71, 0x94, 0x51, 0x1C, 0x1E, 0xA2, 0x06, 0x9D, 0xE9, 0x04, 0x50, 0xD1, 0xF8, 0x6E, 0xC0, 0xF0, 0xCD, 0xCD, 0x75, 0x8D, 0x38, 0xF3, 0xE5, 0xE6, 0x90, 0xB8, 0x22, 0x88, 0x56, 0x95, 0xFD, 0x5D, 0xFC, 0xC4, 0x18, 0xEC, 0x66, 0xA2, 0x67, 0x0C, 0xF2, 0x2C, 0xB8, 0xEA, 0x4E, 0x47, 0xA7, 0x16, 0x86, 0x9A, 0xC6, 0xB5, 0x4B, 0x74, 0x12, 0xF0, 0x9E, 0x4F, 0x58, 0x72, 0x3E, 0x98, 0x5E, 0x81, 0x36, 0x87, 0x84, 0x17, 0x27, 0xDC, 0x70, 0x2D, 0x22, 0x30, 0xA4, 0xED, 0xED, 0xE3, 0xFF, 0xC6, 0x83, 0x82, 0xA7, 0x55, 0x7F, 0x7D, 0x1B, 0x6F, 0x1C, 0x5A, 0xA2, 0x36, 0x7A, 0x04, 0xF8, 0xEE, 0x21, 0x71, 0xED, 0xE7, 0x9B, 0x67, 0x6A, 0x07, 0xD7, 0xBA, 0x32, 0x25, 0x78, 0x59, 0xCC, 0x7A, 0x26, 0xEA, 0xBE, 0xAB, 0x41, 0x72, 0xA5, 0x14, 0x46, 0xA7, 0xD8, 0x72, 0xBA, 0x39, 0xD9, 0x40, 0xD4, 0xB2, 0x56, 0x59, 0x22, }, .priv_len = 4032, .pub = { 0x18, 0x48, 0xEE, 0xB1, 0x92, 0x17, 0x81, 0xEF, 0x07, 0x65, 0x62, 0x1A, 0x0A, 0x92, 0x50, 0x69, 0x42, 0x9E, 0xC4, 0xBC, 0x9D, 0xCD, 0x29, 0xFB, 0xD4, 0x84, 0x5E, 0x68, 0x2E, 0x41, 0x78, 0x7F, 0xDF, 0x4C, 0x84, 0xFD, 0xAC, 0x7D, 0x56, 0x15, 0x41, 0x60, 0x17, 0x7A, 0x4D, 0xC9, 0x39, 0xBD, 0xF3, 0x66, 0xE8, 0x2D, 0x69, 0x5A, 0x50, 0x01, 0x79, 0xEC, 0x0C, 0x48, 0x7E, 0xF7, 0x36, 0x93, 0x3F, 0xEC, 0xD8, 0xC7, 0xCA, 0x91, 0x79, 0x83, 0x50, 0xC2, 0x2D, 0x8C, 0xB6, 0xB9, 0x1B, 0x10, 0x09, 0xA2, 0x80, 0x63, 0xA7, 0x84, 0x7D, 0x29, 0x06, 0x3D, 0x54, 0x21, 0x40, 0x50, 0xDD, 0xF3, 0x8F, 0xA6, 0x54, 0x4D, 0xB0, 0xF1, 0xD2, 0xC7, 0x94, 0x35, 0xFF, 0xC2, 0x30, 0x44, 0xB4, 0x24, 0xEA, 0xA1, 0xCE, 0x7D, 0xB3, 0xE3, 0xF9, 0x9C, 0x0D, 0x25, 0xAE, 0xB4, 0xDF, 0x4F, 0x85, 0xD4, 0xDA, 0xE7, 0xA0, 0xDC, 0x70, 0x7D, 0x07, 0x85, 0xB6, 0xDA, 0x5D, 0xE8, 0x1A, 0xD9, 0xBC, 0x0E, 0xB7, 0xDD, 0x94, 0xD4, 0xC7, 0x12, 0x41, 0x3F, 0x43, 0xB8, 0xBE, 0x6C, 0x55, 0x79, 0xC1, 0x38, 0x22, 0xBA, 0xE4, 0xB9, 0x66, 0xF7, 0x08, 0x8C, 0x42, 0xD7, 0xE1, 0xAF, 0xDE, 0x68, 0x24, 0xCD, 0x3B, 0x74, 0x24, 0x5A, 0xE5, 0x01, 0xA9, 0x89, 0x17, 0x6F, 0xD2, 0x46, 0xE8, 0x45, 0x2B, 0x43, 0x16, 0x6D, 0x2E, 0xC8, 0xE0, 0x8B, 0x09, 0x12, 0xD1, 0xD6, 0x84, 0x8C, 0xCB, 0xAA, 0x86, 0xE8, 0x10, 0x96, 0xE8, 0x0C, 0x0E, 0x1E, 0x78, 0x08, 0x8A, 0xA5, 0xF2, 0xA9, 0xD1, 0x6E, 0xB1, 0x1E, 0x6B, 0xC9, 0x30, 0x7A, 0x46, 0x8A, 0xB7, 0x4C, 0xBB, 0x4B, 0x34, 0x5F, 0x15, 0x09, 0x51, 0x3E, 0xEC, 0xDE, 0x94, 0x50, 0x64, 0xF9, 0xFD, 0x2E, 0x38, 0xF4, 0x8B, 0x0D, 0xD2, 0xDA, 0x10, 0x18, 0x92, 0xCA, 0x52, 0xDB, 0xF0, 0x47, 0x9A, 0x6A, 0x92, 0x29, 0x7B, 0x05, 0x84, 0xEF, 0x38, 0x03, 0x3E, 0x85, 0x18, 0x5C, 0xDF, 0x77, 0x10, 0x04, 0xD8, 0x23, 0xB0, 0x02, 0x06, 0xB5, 0x61, 0x58, 0x9E, 0x72, 0xC8, 0x49, 0x61, 0xBD, 0x21, 0xA2, 0xCC, 0xA5, 0x48, 0x85, 0x2D, 0xA8, 0x0D, 0xB1, 0xBB, 0x13, 0x5E, 0xAE, 0xA6, 0xCB, 0xA8, 0x71, 0x40, 0x32, 0x3E, 0x78, 0x84, 0x4D, 0x7B, 0xC2, 0x2C, 0x52, 0xDB, 0x77, 0x0A, 0x99, 0x24, 0x99, 0xF0, 0x7B, 0x56, 0x91, 0xBB, 0x27, 0x7C, 0xB7, 0x89, 0xD4, 0xE9, 0x31, 0xB7, 0x29, 0xC3, 0xC8, 0x4C, 0x88, 0x14, 0x3F, 0x80, 0x60, 0xAB, 0x30, 0xB6, 0x97, 0xA3, 0x66, 0xA7, 0x2A, 0x26, 0xF8, 0xD1, 0x47, 0x89, 0xAC, 0x56, 0x32, 0x6A, 0xC1, 0x95, 0xF9, 0x32, 0xCF, 0x3C, 0x25, 0xBD, 0xEB, 0xEF, 0x24, 0xB7, 0xDB, 0xC7, 0x6A, 0xE1, 0x9E, 0x39, 0x32, 0xE7, 0xF6, 0xF2, 0x14, 0x68, 0x00, 0xF4, 0xA1, 0xFE, 0x35, 0x93, 0xDF, 0x47, 0xE4, 0x09, 0x5E, 0xC8, 0x9A, 0x37, 0xF0, 0xAC, 0x4D, 0x86, 0x9B, 0x78, 0xDB, 0x64, 0x3A, 0xF1, 0x94, 0xE8, 0x28, 0x55, 0x28, 0xD3, 0x0B, 0x7A, 0x9D, 0x5E, 0xFA, 0x21, 0x2B, 0x01, 0xD6, 0x8B, 0x5E, 0x0C, 0x19, 0xDC, 0xE6, 0x05, 0x7A, 0xFF, 0x8C, 0x72, 0xAC, 0xA5, 0x70, 0x73, 0xC6, 0x0F, 0x15, 0xC8, 0x0F, 0xC1, 0xF7, 0x38, 0x70, 0xB6, 0xA0, 0x9F, 0x1A, 0x9D, 0x4E, 0xFB, 0x67, 0xFE, 0x84, 0x6C, 0x11, 0x32, 0xED, 0x8B, 0xB1, 0x60, 0xDC, 0x9D, 0x3F, 0x3E, 0x79, 0x2C, 0x2C, 0x21, 0xF7, 0x0D, 0x18, 0x77, 0x5E, 0x0D, 0x5B, 0xD5, 0xAE, 0x8C, 0xE8, 0xD7, 0x05, 0xA8, 0x88, 0xE0, 0xD0, 0x9F, 0xA0, 0x0A, 0xF6, 0x88, 0x29, 0xEF, 0xFF, 0x4F, 0x06, 0x07, 0xD2, 0x2B, 0x9A, 0x27, 0x12, 0xDA, 0xCE, 0x7A, 0x9C, 0x3A, 0x5A, 0x1A, 0x75, 0x06, 0x27, 0x95, 0x85, 0x7A, 0x0F, 0x48, 0x97, 0xF0, 0x32, 0xE9, 0x0D, 0x0B, 0x4F, 0x51, 0xCD, 0x93, 0x87, 0xF1, 0xE3, 0x91, 0xB5, 0x8E, 0x82, 0x68, 0xAA, 0xEE, 0x1D, 0xEC, 0x07, 0xCC, 0x21, 0x86, 0x35, 0xDF, 0xD2, 0xA5, 0xE0, 0xD4, 0xCC, 0x79, 0x89, 0x34, 0x73, 0x9E, 0xF2, 0x78, 0xEA, 0xBE, 0xC1, 0x21, 0xBF, 0x52, 0x46, 0xA7, 0x9B, 0x94, 0x70, 0x68, 0x2A, 0x3D, 0xBF, 0xE7, 0x2B, 0xCB, 0x66, 0x20, 0x8F, 0x56, 0x1D, 0x05, 0xC4, 0x84, 0xB2, 0xA7, 0x23, 0xAD, 0xF8, 0x1E, 0x61, 0x7F, 0x5E, 0xEE, 0xE9, 0x75, 0xCB, 0x53, 0x1B, 0x13, 0xD2, 0x51, 0x47, 0xB4, 0x3D, 0x21, 0xAE, 0x06, 0x96, 0x91, 0xEF, 0xD1, 0xAA, 0xDC, 0x48, 0xB2, 0xAE, 0xB7, 0x8F, 0xFD, 0x7B, 0x49, 0x98, 0xAB, 0xBD, 0x80, 0xD6, 0x1A, 0xF6, 0x6B, 0x94, 0x63, 0xF8, 0xA9, 0x37, 0x00, 0x53, 0xCD, 0x48, 0x90, 0x53, 0x27, 0x3F, 0x0A, 0x6F, 0x06, 0xD7, 0x72, 0x88, 0x11, 0x62, 0xB6, 0x82, 0x3F, 0x7B, 0x02, 0x1D, 0xC5, 0xA7, 0x75, 0x5D, 0x37, 0x13, 0xD9, 0x7C, 0xA9, 0x46, 0x7D, 0x72, 0x3E, 0x27, 0xCE, 0x84, 0xB4, 0x63, 0xFF, 0x88, 0x62, 0x9B, 0x0C, 0x92, 0xF3, 0xE1, 0xB5, 0x4D, 0xC8, 0xE6, 0xBA, 0xC3, 0x37, 0x44, 0xCF, 0xC3, 0xCC, 0xD8, 0xDB, 0xDC, 0x53, 0xDE, 0x87, 0x7E, 0x12, 0x7A, 0x50, 0x9F, 0xF2, 0x79, 0xA1, 0xBC, 0x67, 0xA8, 0x85, 0x23, 0xAF, 0x0D, 0x81, 0x5D, 0x33, 0xC3, 0x3F, 0x19, 0x18, 0xFB, 0xCC, 0x62, 0x95, 0xFF, 0x71, 0x16, 0xD2, 0xC7, 0xFB, 0x2D, 0x8E, 0xB0, 0xF7, 0x2F, 0x73, 0x09, 0xB2, 0xCB, 0xBA, 0xEE, 0xD1, 0x1B, 0xFC, 0xDD, 0xEB, 0xE5, 0x33, 0x59, 0x8B, 0xD4, 0xBF, 0x10, 0x95, 0x7A, 0x06, 0xB2, 0x32, 0xAD, 0x79, 0xF2, 0x36, 0xC3, 0x78, 0xA7, 0xE4, 0xA9, 0x17, 0x62, 0xB7, 0x69, 0x93, 0x5E, 0xA8, 0xD1, 0xB3, 0xD5, 0xBF, 0x32, 0x00, 0x55, 0x86, 0xA4, 0xED, 0xD5, 0x97, 0xA6, 0x41, 0x25, 0xA3, 0x72, 0x06, 0x16, 0x69, 0x5A, 0x5C, 0x4A, 0xEA, 0xD4, 0xC1, 0xA7, 0x79, 0x29, 0x5B, 0xB2, 0xE9, 0x7E, 0xD6, 0xAB, 0x7E, 0xC3, 0xF7, 0xF6, 0x39, 0xDA, 0x3F, 0x64, 0x30, 0x74, 0x0F, 0xF6, 0x13, 0x15, 0x09, 0xDF, 0x0B, 0xCC, 0xF9, 0xAC, 0xC0, 0x07, 0x3C, 0xB4, 0x06, 0x0C, 0x69, 0xF0, 0x56, 0xDE, 0x0D, 0x21, 0x7B, 0xCB, 0x49, 0xF6, 0x4C, 0x16, 0x6D, 0x34, 0x7E, 0x21, 0xD9, 0xF9, 0x19, 0x73, 0x57, 0x9F, 0x22, 0x15, 0x43, 0xFC, 0xAC, 0xE8, 0x33, 0xA1, 0xED, 0x23, 0x30, 0x86, 0x8E, 0x36, 0xF5, 0x67, 0xFB, 0x38, 0xDC, 0x6C, 0xF5, 0xBB, 0x79, 0x57, 0x0D, 0x4B, 0x24, 0x7B, 0x88, 0xBD, 0x8C, 0x71, 0x31, 0x90, 0x5D, 0xFD, 0xCB, 0xD6, 0x6B, 0x85, 0x9B, 0x27, 0xBA, 0x35, 0xAA, 0x07, 0x16, 0x0A, 0xAB, 0xB3, 0xBC, 0x14, 0xA1, 0x1C, 0x98, 0x2A, 0xAB, 0x5B, 0x86, 0xA2, 0x2E, 0x3D, 0x38, 0xB7, 0x49, 0x2C, 0x47, 0xD6, 0x9F, 0x90, 0x0D, 0xEE, 0x2B, 0x50, 0xC8, 0xAD, 0x31, 0x48, 0x17, 0xA4, 0x46, 0x18, 0x60, 0xF6, 0x54, 0x46, 0x46, 0x5A, 0x7B, 0xA7, 0x7F, 0xC1, 0xBD, 0x63, 0x37, 0x9D, 0x25, 0x42, 0xEF, 0xBF, 0x1B, 0x7C, 0x04, 0x2D, 0xEB, 0x0A, 0x3D, 0x49, 0x17, 0x2A, 0x71, 0xFD, 0x8B, 0x2E, 0xD7, 0x20, 0xD7, 0x8C, 0x7D, 0x12, 0xCC, 0x6C, 0x96, 0x5E, 0x3A, 0x94, 0x18, 0xA9, 0x66, 0xFF, 0x47, 0x0E, 0xF3, 0x06, 0xFD, 0x7E, 0xBB, 0xC8, 0xAB, 0x5D, 0xC7, 0xE8, 0xC4, 0xA3, 0x4E, 0x86, 0xA0, 0xD2, 0x50, 0xE7, 0x1D, 0x81, 0x51, 0x39, 0x20, 0x5F, 0xA9, 0xED, 0x6A, 0x0F, 0xD5, 0xED, 0xC5, 0xB8, 0x23, 0xBA, 0x25, 0x8F, 0xFF, 0x29, 0xFC, 0x92, 0xE9, 0xF0, 0xC3, 0x1B, 0x62, 0x75, 0x0F, 0xF2, 0x4F, 0x23, 0xF5, 0x21, 0xB5, 0x68, 0x7F, 0xB1, 0xA8, 0x12, 0x42, 0x61, 0x8F, 0x6D, 0x49, 0x86, 0xE6, 0xD2, 0x68, 0x41, 0x58, 0x17, 0x4E, 0xB5, 0x5B, 0x79, 0x1D, 0x06, 0x84, 0x68, 0x3B, 0x1C, 0xF1, 0xC6, 0x46, 0x02, 0x90, 0x49, 0xD0, 0x54, 0xBD, 0xF0, 0xE4, 0xDF, 0xC1, 0x99, 0x15, 0x61, 0x55, 0x9A, 0x7D, 0xF9, 0x0C, 0x7E, 0x9A, 0x6D, 0x74, 0xA2, 0xD4, 0xAC, 0x57, 0x7E, 0x81, 0x68, 0x96, 0x66, 0x16, 0xC8, 0xCD, 0x7C, 0xF5, 0xB2, 0x13, 0xBF, 0x88, 0x3F, 0x73, 0x22, 0x47, 0xB3, 0x1F, 0x32, 0x71, 0x5A, 0xB1, 0xE8, 0x88, 0x82, 0x86, 0xDE, 0x1F, 0xD6, 0x77, 0xCB, 0x17, 0x35, 0xCF, 0x49, 0x00, 0x88, 0xD6, 0x11, 0x47, 0x3A, 0x50, 0x00, 0x83, 0xF3, 0x0B, 0x49, 0x75, 0x56, 0x7C, 0xEC, 0x62, 0xF2, 0x91, 0x94, 0xE4, 0x62, 0xB0, 0xCB, 0x02, 0xBD, 0x2D, 0x78, 0x1D, 0x89, 0xFE, 0xA1, 0x78, 0xB5, 0xD2, 0xAD, 0xC9, 0x38, 0x89, 0x2E, 0xD6, 0xD5, 0xDA, 0x52, 0x0F, 0x99, 0xEE, 0x7A, 0xEC, 0x94, 0x2A, 0x88, 0x0C, 0x5A, 0x09, 0xA8, 0x85, 0xC5, 0xCF, 0xE1, 0x45, 0xEB, 0xE0, 0x73, 0xF1, 0xF7, 0x7F, 0x9A, 0xD1, 0x13, 0x17, 0xE7, 0x21, 0x13, 0x61, 0x7C, 0x31, 0xA1, 0x43, 0xED, 0x0A, 0x5B, 0xEC, 0x8E, 0x3F, 0xE8, 0xD4, 0x46, 0x9C, 0xBF, 0x34, 0xD6, 0x46, 0x4D, 0x05, 0xAD, 0xA9, 0x2C, 0xE0, 0x49, 0xC1, 0xB4, 0xAD, 0x58, 0xCE, 0xAE, 0x96, 0x9B, 0x8D, 0x2C, 0x7D, 0xF9, 0x5F, 0xF1, 0xD4, 0xF2, 0x69, 0x19, 0xFA, 0x3F, 0x52, 0xC6, 0x8A, 0xC3, 0xAF, 0xA9, 0x5B, 0x88, 0x48, 0x17, 0xFA, 0x55, 0xF1, 0xA7, 0x5A, 0xE1, 0x7E, 0xA4, 0xD5, 0x6C, 0x58, 0xAE, 0xAC, 0x65, 0x35, 0xDD, 0xBD, 0x16, 0xE8, 0xD3, 0xC1, 0xE5, 0x5B, 0xE7, 0x93, 0x39, 0xEC, 0x10, 0x79, 0xB6, 0xB2, 0x3A, 0x27, 0x0C, 0xE0, 0x01, 0xC5, 0xDA, 0x89, 0xD9, 0xED, 0x33, 0x5E, 0xD9, 0x52, 0x78, 0xAD, 0xFA, 0x65, 0x15, 0x23, 0xD9, 0x36, 0xDC, 0x9E, 0x1C, 0x05, 0x2B, 0xB1, 0x51, 0x07, 0xCF, 0x77, 0x6F, 0xFE, 0xE6, 0x26, 0xED, 0x92, 0x30, 0x3D, 0xE8, 0xE5, 0xCA, 0x94, 0x26, 0x53, 0x31, 0x91, 0x43, 0xE2, 0x06, 0xC7, 0x1A, 0x04, 0x29, 0x4E, 0x61, 0x32, 0xC0, 0xA1, 0x31, 0x2C, 0x1A, 0xAD, 0x62, 0xC1, 0x7E, 0xCA, 0x5A, 0x58, 0xCB, 0xC4, 0xC2, 0x6B, 0x83, 0x44, 0x03, 0x19, 0xA5, 0x46, 0x74, 0xD1, 0x58, 0x4D, 0x4B, 0x52, 0x83, 0x38, 0x38, 0xEA, 0x71, 0xCC, 0xDF, 0x10, 0x66, 0x9A, 0x97, 0x31, 0x33, 0x81, 0x43, 0x7F, 0xC6, 0xCF, 0xDD, 0x34, 0x24, 0x09, 0x00, 0x68, 0x20, 0xFD, 0x95, 0xFE, 0xF1, 0xE4, 0x58, 0x74, 0xC3, 0x5D, 0xFB, 0x57, 0x51, 0x97, 0x75, 0xE9, 0xBB, 0x60, 0x20, 0x66, 0x9D, 0x74, 0x15, 0x9D, 0x3F, 0xBB, 0xBD, 0x1C, 0xB8, 0x98, 0xD7, 0xFF, 0xB0, 0xF4, 0xAC, 0x45, 0x25, 0xE1, 0x4E, 0x8A, 0x8D, 0xBF, 0x50, 0x03, 0x02, 0x19, 0x23, 0x61, 0x02, 0x92, 0x4E, 0xA3, 0x27, 0xA9, 0xA8, 0xA8, 0x73, 0x89, 0x88, 0x72, 0x57, 0xDC, 0x53, 0xC4, 0x31, 0x9C, 0xC8, 0x84, 0x35, 0x95, 0x4B, 0x3E, 0x7E, 0x63, 0x92, 0x55, 0x0A, 0x2B, 0xE1, 0x68, 0x56, 0xB2, 0xF0, 0x03, 0x11, 0x08, 0xDC, 0x83, 0x66, 0xE5, 0x39, 0xD5, 0xCE, 0x9C, 0x91, 0x55, 0x57, 0xA7, 0x28, 0x9E, 0x85, 0x2F, 0x07, 0x45, 0x45, 0xF7, 0xE8, 0x9A, 0x59, 0xD6, 0x62, 0xED, 0x97, 0xF5, 0x55, 0xEA, 0xB7, 0x1A, 0xED, 0x03, 0x76, 0x90, 0x26, 0x94, 0x3B, 0x5D, 0x23, 0xB1, 0x18, 0xB2, 0xC9, 0x72, 0x5C, 0xC5, 0x61, 0x60, 0xB2, 0xD6, 0x50, 0x8E, 0x85, 0x01, 0x73, 0x1B, 0xAA, 0x63, 0xD7, 0x42, 0x17, 0x2F, 0xCD, 0x07, 0x0F, 0x97, 0xFC, 0xAF, 0x7E, 0x57, 0xB3, 0x03, 0xBD, 0xD0, 0xC8, 0x95, 0x91, 0xFB, 0xE7, 0xF3, 0x3D, 0xBD, 0xB5, 0x0C, 0x76, 0x4E, 0xDC, 0x59, 0x53, 0xC0, 0x77, 0x73, 0xB1, 0xAD, 0x05, 0x6C, 0x32, 0x58, 0x22, 0xF8, 0x1A, 0x3E, 0xD6, 0x5E, 0xA1, 0xF2, 0xFB, 0xC4, 0xCF, 0xC8, 0xBF, 0xF4, 0xA5, 0xC9, 0xCB, 0x13, 0xE8, 0x98, 0xC1, 0xBE, 0x3D, 0x8F, 0xD2, 0xEC, 0x8E, 0xA9, 0x63, 0x8F, 0x33, 0x0D, 0x39, 0x65, 0xBE, 0xE1, 0x7E, 0x72, 0x8B, 0xB4, 0x3B, 0x26, 0xCD, 0xFD, 0x22, 0xD5, 0x06, 0x8C, 0x6A, 0xB3, 0xBB, 0x13, 0x2B, 0x5E, 0x06, 0xE1, 0xEF, 0xE1, 0x29, 0xE8, 0x36, 0x80, 0x3A, 0xFA, 0x45, 0xEB, 0x6D, 0x55, 0xEF, 0xE2, 0xD9, 0x35, 0xCE, 0xB9, 0x8A, 0x07, 0xBA, 0x24, 0xD7, 0x0F, 0x88, 0x8B, 0x69, 0x76, 0x34, 0x34, 0x7A, 0xDD, 0x69, 0x91, 0xD4, 0x09, 0x93, 0x16, 0x4A, 0x20, 0x4E, 0xA7, 0x28, 0x6A, 0xC0, 0x19, 0x76, 0x53, 0x52, 0xC8, 0x01, 0xE3, 0xE3, 0x9C, 0x79, 0xEC, 0x00, 0x28, 0x38, 0x54, 0xFE, 0x13, 0x30, 0x69, 0x38, 0xBD, 0xEE, 0x3E, 0x4A, 0x04, 0x00, 0xE8, 0xA7, 0x97, 0x2B, 0x98, 0xB1, 0xB9, 0x3C, 0x8E, 0x6C, 0xBE, 0x33, 0x5C, 0x2F, 0x6A, 0x1B, 0xCA, 0x92, 0xC9, 0xEF, 0x4D, 0xE9, 0xE1, 0x35, 0x99, 0x6B, 0x84, 0x3F, 0xA3, 0xF0, 0x41, 0x84, 0xA8, 0x71, 0x26, 0x8C, 0xB1, 0x72, 0xDA, 0xC6, 0xD5, 0x4F, 0xEA, 0x1A, 0x63, 0x1D, 0x54, 0x71, 0x5B, 0xB6, 0x20, 0x7D, 0xB5, 0x9D, 0x5B, 0x4E, 0xF3, 0xFB, 0x95, 0x42, 0x6D, 0xA2, 0x29, 0x72, 0xF3, 0x5A, 0xF3, 0x3F, 0x62, 0xDD, 0xC1, 0x78, 0xDC, 0xA9, 0x59, 0x54, 0x22, 0x00, 0x7D, 0x32, 0xD8, 0x04, 0xCD, 0xEC, 0x6A, 0xE1, 0xC6, 0x64, 0x48, 0x90, 0x9D, 0x57, 0x4B, 0xE1, 0x8B, 0x05, 0xA8, 0x07, 0x06, 0xF4, 0x17, 0xB3, 0xC0, 0xF4, 0x5E, 0x16, 0x75, 0x1A, 0xCB, 0x45, 0xBB, 0xE0, 0x05, 0xC1, 0x1F, 0xD7, 0x73, 0x3D, 0xA3, 0xFC, 0xD5, 0x44, 0xB7, 0x57, 0xAA, 0x3F, 0x36, 0x08, 0x14, 0xE8, 0x55, 0x44, 0xE2, 0x9D, 0x09, 0x7E, 0x64, 0x33, 0xDC, 0x5C, 0xE2, 0x56, 0x1C, 0x6C, 0x51, 0x89, 0x8F, 0x24, 0x1C, 0xA6, 0x21, 0x08, 0xD8, 0x0A, 0x82, 0x9D, 0x66, 0xFB, 0x1E, 0xE7, 0x4E, 0xB8, 0x93, 0xD0, 0x92, 0x2C, 0x06, 0xBA, 0x5B, 0x87, 0xE0, 0x44, 0xBD, 0xFA, 0xA2, 0xE8, 0x41, 0xDB, 0x1F, 0xBE, 0x97, 0xF7, 0x66, 0x2A, 0x80, 0xE7, 0x95, 0x57, 0x95, 0x5D, 0xF1, 0x85, 0x54, 0xA3, 0x27, 0xB5, 0xFE, 0x2D, 0x28, 0x25, 0xA9, 0x89, 0x87, 0xB8, 0x78, 0x8F, 0x11, 0x5E, 0x0E, 0xE4, 0xD8, 0x30, 0x57, 0x07, 0x33, 0x71, 0x9B, 0xED, 0x51, 0xA3, 0xD6, 0x92, }, .pub_len = 1952, }, { .name = "ML-DSA 65 (seed only)", .parameter_set = CKP_ML_DSA_65, .priv_seed = { 0xCA, 0x65, 0x59, 0x2E, 0x96, 0x20, 0xFC, 0x39, 0xA0, 0x5D, 0xB6, 0xF4, 0x14, 0x9B, 0x62, 0x06, 0xDB, 0x54, 0x7C, 0x29, 0xBC, 0x5C, 0x0F, 0x4D, 0xC6, 0x96, 0xF2, 0xF0, 0x2D, 0xFC, 0x99, 0xE7, }, .priv_seed_len = 32, .pub = { 0x18, 0x48, 0xEE, 0xB1, 0x92, 0x17, 0x81, 0xEF, 0x07, 0x65, 0x62, 0x1A, 0x0A, 0x92, 0x50, 0x69, 0x42, 0x9E, 0xC4, 0xBC, 0x9D, 0xCD, 0x29, 0xFB, 0xD4, 0x84, 0x5E, 0x68, 0x2E, 0x41, 0x78, 0x7F, 0xDF, 0x4C, 0x84, 0xFD, 0xAC, 0x7D, 0x56, 0x15, 0x41, 0x60, 0x17, 0x7A, 0x4D, 0xC9, 0x39, 0xBD, 0xF3, 0x66, 0xE8, 0x2D, 0x69, 0x5A, 0x50, 0x01, 0x79, 0xEC, 0x0C, 0x48, 0x7E, 0xF7, 0x36, 0x93, 0x3F, 0xEC, 0xD8, 0xC7, 0xCA, 0x91, 0x79, 0x83, 0x50, 0xC2, 0x2D, 0x8C, 0xB6, 0xB9, 0x1B, 0x10, 0x09, 0xA2, 0x80, 0x63, 0xA7, 0x84, 0x7D, 0x29, 0x06, 0x3D, 0x54, 0x21, 0x40, 0x50, 0xDD, 0xF3, 0x8F, 0xA6, 0x54, 0x4D, 0xB0, 0xF1, 0xD2, 0xC7, 0x94, 0x35, 0xFF, 0xC2, 0x30, 0x44, 0xB4, 0x24, 0xEA, 0xA1, 0xCE, 0x7D, 0xB3, 0xE3, 0xF9, 0x9C, 0x0D, 0x25, 0xAE, 0xB4, 0xDF, 0x4F, 0x85, 0xD4, 0xDA, 0xE7, 0xA0, 0xDC, 0x70, 0x7D, 0x07, 0x85, 0xB6, 0xDA, 0x5D, 0xE8, 0x1A, 0xD9, 0xBC, 0x0E, 0xB7, 0xDD, 0x94, 0xD4, 0xC7, 0x12, 0x41, 0x3F, 0x43, 0xB8, 0xBE, 0x6C, 0x55, 0x79, 0xC1, 0x38, 0x22, 0xBA, 0xE4, 0xB9, 0x66, 0xF7, 0x08, 0x8C, 0x42, 0xD7, 0xE1, 0xAF, 0xDE, 0x68, 0x24, 0xCD, 0x3B, 0x74, 0x24, 0x5A, 0xE5, 0x01, 0xA9, 0x89, 0x17, 0x6F, 0xD2, 0x46, 0xE8, 0x45, 0x2B, 0x43, 0x16, 0x6D, 0x2E, 0xC8, 0xE0, 0x8B, 0x09, 0x12, 0xD1, 0xD6, 0x84, 0x8C, 0xCB, 0xAA, 0x86, 0xE8, 0x10, 0x96, 0xE8, 0x0C, 0x0E, 0x1E, 0x78, 0x08, 0x8A, 0xA5, 0xF2, 0xA9, 0xD1, 0x6E, 0xB1, 0x1E, 0x6B, 0xC9, 0x30, 0x7A, 0x46, 0x8A, 0xB7, 0x4C, 0xBB, 0x4B, 0x34, 0x5F, 0x15, 0x09, 0x51, 0x3E, 0xEC, 0xDE, 0x94, 0x50, 0x64, 0xF9, 0xFD, 0x2E, 0x38, 0xF4, 0x8B, 0x0D, 0xD2, 0xDA, 0x10, 0x18, 0x92, 0xCA, 0x52, 0xDB, 0xF0, 0x47, 0x9A, 0x6A, 0x92, 0x29, 0x7B, 0x05, 0x84, 0xEF, 0x38, 0x03, 0x3E, 0x85, 0x18, 0x5C, 0xDF, 0x77, 0x10, 0x04, 0xD8, 0x23, 0xB0, 0x02, 0x06, 0xB5, 0x61, 0x58, 0x9E, 0x72, 0xC8, 0x49, 0x61, 0xBD, 0x21, 0xA2, 0xCC, 0xA5, 0x48, 0x85, 0x2D, 0xA8, 0x0D, 0xB1, 0xBB, 0x13, 0x5E, 0xAE, 0xA6, 0xCB, 0xA8, 0x71, 0x40, 0x32, 0x3E, 0x78, 0x84, 0x4D, 0x7B, 0xC2, 0x2C, 0x52, 0xDB, 0x77, 0x0A, 0x99, 0x24, 0x99, 0xF0, 0x7B, 0x56, 0x91, 0xBB, 0x27, 0x7C, 0xB7, 0x89, 0xD4, 0xE9, 0x31, 0xB7, 0x29, 0xC3, 0xC8, 0x4C, 0x88, 0x14, 0x3F, 0x80, 0x60, 0xAB, 0x30, 0xB6, 0x97, 0xA3, 0x66, 0xA7, 0x2A, 0x26, 0xF8, 0xD1, 0x47, 0x89, 0xAC, 0x56, 0x32, 0x6A, 0xC1, 0x95, 0xF9, 0x32, 0xCF, 0x3C, 0x25, 0xBD, 0xEB, 0xEF, 0x24, 0xB7, 0xDB, 0xC7, 0x6A, 0xE1, 0x9E, 0x39, 0x32, 0xE7, 0xF6, 0xF2, 0x14, 0x68, 0x00, 0xF4, 0xA1, 0xFE, 0x35, 0x93, 0xDF, 0x47, 0xE4, 0x09, 0x5E, 0xC8, 0x9A, 0x37, 0xF0, 0xAC, 0x4D, 0x86, 0x9B, 0x78, 0xDB, 0x64, 0x3A, 0xF1, 0x94, 0xE8, 0x28, 0x55, 0x28, 0xD3, 0x0B, 0x7A, 0x9D, 0x5E, 0xFA, 0x21, 0x2B, 0x01, 0xD6, 0x8B, 0x5E, 0x0C, 0x19, 0xDC, 0xE6, 0x05, 0x7A, 0xFF, 0x8C, 0x72, 0xAC, 0xA5, 0x70, 0x73, 0xC6, 0x0F, 0x15, 0xC8, 0x0F, 0xC1, 0xF7, 0x38, 0x70, 0xB6, 0xA0, 0x9F, 0x1A, 0x9D, 0x4E, 0xFB, 0x67, 0xFE, 0x84, 0x6C, 0x11, 0x32, 0xED, 0x8B, 0xB1, 0x60, 0xDC, 0x9D, 0x3F, 0x3E, 0x79, 0x2C, 0x2C, 0x21, 0xF7, 0x0D, 0x18, 0x77, 0x5E, 0x0D, 0x5B, 0xD5, 0xAE, 0x8C, 0xE8, 0xD7, 0x05, 0xA8, 0x88, 0xE0, 0xD0, 0x9F, 0xA0, 0x0A, 0xF6, 0x88, 0x29, 0xEF, 0xFF, 0x4F, 0x06, 0x07, 0xD2, 0x2B, 0x9A, 0x27, 0x12, 0xDA, 0xCE, 0x7A, 0x9C, 0x3A, 0x5A, 0x1A, 0x75, 0x06, 0x27, 0x95, 0x85, 0x7A, 0x0F, 0x48, 0x97, 0xF0, 0x32, 0xE9, 0x0D, 0x0B, 0x4F, 0x51, 0xCD, 0x93, 0x87, 0xF1, 0xE3, 0x91, 0xB5, 0x8E, 0x82, 0x68, 0xAA, 0xEE, 0x1D, 0xEC, 0x07, 0xCC, 0x21, 0x86, 0x35, 0xDF, 0xD2, 0xA5, 0xE0, 0xD4, 0xCC, 0x79, 0x89, 0x34, 0x73, 0x9E, 0xF2, 0x78, 0xEA, 0xBE, 0xC1, 0x21, 0xBF, 0x52, 0x46, 0xA7, 0x9B, 0x94, 0x70, 0x68, 0x2A, 0x3D, 0xBF, 0xE7, 0x2B, 0xCB, 0x66, 0x20, 0x8F, 0x56, 0x1D, 0x05, 0xC4, 0x84, 0xB2, 0xA7, 0x23, 0xAD, 0xF8, 0x1E, 0x61, 0x7F, 0x5E, 0xEE, 0xE9, 0x75, 0xCB, 0x53, 0x1B, 0x13, 0xD2, 0x51, 0x47, 0xB4, 0x3D, 0x21, 0xAE, 0x06, 0x96, 0x91, 0xEF, 0xD1, 0xAA, 0xDC, 0x48, 0xB2, 0xAE, 0xB7, 0x8F, 0xFD, 0x7B, 0x49, 0x98, 0xAB, 0xBD, 0x80, 0xD6, 0x1A, 0xF6, 0x6B, 0x94, 0x63, 0xF8, 0xA9, 0x37, 0x00, 0x53, 0xCD, 0x48, 0x90, 0x53, 0x27, 0x3F, 0x0A, 0x6F, 0x06, 0xD7, 0x72, 0x88, 0x11, 0x62, 0xB6, 0x82, 0x3F, 0x7B, 0x02, 0x1D, 0xC5, 0xA7, 0x75, 0x5D, 0x37, 0x13, 0xD9, 0x7C, 0xA9, 0x46, 0x7D, 0x72, 0x3E, 0x27, 0xCE, 0x84, 0xB4, 0x63, 0xFF, 0x88, 0x62, 0x9B, 0x0C, 0x92, 0xF3, 0xE1, 0xB5, 0x4D, 0xC8, 0xE6, 0xBA, 0xC3, 0x37, 0x44, 0xCF, 0xC3, 0xCC, 0xD8, 0xDB, 0xDC, 0x53, 0xDE, 0x87, 0x7E, 0x12, 0x7A, 0x50, 0x9F, 0xF2, 0x79, 0xA1, 0xBC, 0x67, 0xA8, 0x85, 0x23, 0xAF, 0x0D, 0x81, 0x5D, 0x33, 0xC3, 0x3F, 0x19, 0x18, 0xFB, 0xCC, 0x62, 0x95, 0xFF, 0x71, 0x16, 0xD2, 0xC7, 0xFB, 0x2D, 0x8E, 0xB0, 0xF7, 0x2F, 0x73, 0x09, 0xB2, 0xCB, 0xBA, 0xEE, 0xD1, 0x1B, 0xFC, 0xDD, 0xEB, 0xE5, 0x33, 0x59, 0x8B, 0xD4, 0xBF, 0x10, 0x95, 0x7A, 0x06, 0xB2, 0x32, 0xAD, 0x79, 0xF2, 0x36, 0xC3, 0x78, 0xA7, 0xE4, 0xA9, 0x17, 0x62, 0xB7, 0x69, 0x93, 0x5E, 0xA8, 0xD1, 0xB3, 0xD5, 0xBF, 0x32, 0x00, 0x55, 0x86, 0xA4, 0xED, 0xD5, 0x97, 0xA6, 0x41, 0x25, 0xA3, 0x72, 0x06, 0x16, 0x69, 0x5A, 0x5C, 0x4A, 0xEA, 0xD4, 0xC1, 0xA7, 0x79, 0x29, 0x5B, 0xB2, 0xE9, 0x7E, 0xD6, 0xAB, 0x7E, 0xC3, 0xF7, 0xF6, 0x39, 0xDA, 0x3F, 0x64, 0x30, 0x74, 0x0F, 0xF6, 0x13, 0x15, 0x09, 0xDF, 0x0B, 0xCC, 0xF9, 0xAC, 0xC0, 0x07, 0x3C, 0xB4, 0x06, 0x0C, 0x69, 0xF0, 0x56, 0xDE, 0x0D, 0x21, 0x7B, 0xCB, 0x49, 0xF6, 0x4C, 0x16, 0x6D, 0x34, 0x7E, 0x21, 0xD9, 0xF9, 0x19, 0x73, 0x57, 0x9F, 0x22, 0x15, 0x43, 0xFC, 0xAC, 0xE8, 0x33, 0xA1, 0xED, 0x23, 0x30, 0x86, 0x8E, 0x36, 0xF5, 0x67, 0xFB, 0x38, 0xDC, 0x6C, 0xF5, 0xBB, 0x79, 0x57, 0x0D, 0x4B, 0x24, 0x7B, 0x88, 0xBD, 0x8C, 0x71, 0x31, 0x90, 0x5D, 0xFD, 0xCB, 0xD6, 0x6B, 0x85, 0x9B, 0x27, 0xBA, 0x35, 0xAA, 0x07, 0x16, 0x0A, 0xAB, 0xB3, 0xBC, 0x14, 0xA1, 0x1C, 0x98, 0x2A, 0xAB, 0x5B, 0x86, 0xA2, 0x2E, 0x3D, 0x38, 0xB7, 0x49, 0x2C, 0x47, 0xD6, 0x9F, 0x90, 0x0D, 0xEE, 0x2B, 0x50, 0xC8, 0xAD, 0x31, 0x48, 0x17, 0xA4, 0x46, 0x18, 0x60, 0xF6, 0x54, 0x46, 0x46, 0x5A, 0x7B, 0xA7, 0x7F, 0xC1, 0xBD, 0x63, 0x37, 0x9D, 0x25, 0x42, 0xEF, 0xBF, 0x1B, 0x7C, 0x04, 0x2D, 0xEB, 0x0A, 0x3D, 0x49, 0x17, 0x2A, 0x71, 0xFD, 0x8B, 0x2E, 0xD7, 0x20, 0xD7, 0x8C, 0x7D, 0x12, 0xCC, 0x6C, 0x96, 0x5E, 0x3A, 0x94, 0x18, 0xA9, 0x66, 0xFF, 0x47, 0x0E, 0xF3, 0x06, 0xFD, 0x7E, 0xBB, 0xC8, 0xAB, 0x5D, 0xC7, 0xE8, 0xC4, 0xA3, 0x4E, 0x86, 0xA0, 0xD2, 0x50, 0xE7, 0x1D, 0x81, 0x51, 0x39, 0x20, 0x5F, 0xA9, 0xED, 0x6A, 0x0F, 0xD5, 0xED, 0xC5, 0xB8, 0x23, 0xBA, 0x25, 0x8F, 0xFF, 0x29, 0xFC, 0x92, 0xE9, 0xF0, 0xC3, 0x1B, 0x62, 0x75, 0x0F, 0xF2, 0x4F, 0x23, 0xF5, 0x21, 0xB5, 0x68, 0x7F, 0xB1, 0xA8, 0x12, 0x42, 0x61, 0x8F, 0x6D, 0x49, 0x86, 0xE6, 0xD2, 0x68, 0x41, 0x58, 0x17, 0x4E, 0xB5, 0x5B, 0x79, 0x1D, 0x06, 0x84, 0x68, 0x3B, 0x1C, 0xF1, 0xC6, 0x46, 0x02, 0x90, 0x49, 0xD0, 0x54, 0xBD, 0xF0, 0xE4, 0xDF, 0xC1, 0x99, 0x15, 0x61, 0x55, 0x9A, 0x7D, 0xF9, 0x0C, 0x7E, 0x9A, 0x6D, 0x74, 0xA2, 0xD4, 0xAC, 0x57, 0x7E, 0x81, 0x68, 0x96, 0x66, 0x16, 0xC8, 0xCD, 0x7C, 0xF5, 0xB2, 0x13, 0xBF, 0x88, 0x3F, 0x73, 0x22, 0x47, 0xB3, 0x1F, 0x32, 0x71, 0x5A, 0xB1, 0xE8, 0x88, 0x82, 0x86, 0xDE, 0x1F, 0xD6, 0x77, 0xCB, 0x17, 0x35, 0xCF, 0x49, 0x00, 0x88, 0xD6, 0x11, 0x47, 0x3A, 0x50, 0x00, 0x83, 0xF3, 0x0B, 0x49, 0x75, 0x56, 0x7C, 0xEC, 0x62, 0xF2, 0x91, 0x94, 0xE4, 0x62, 0xB0, 0xCB, 0x02, 0xBD, 0x2D, 0x78, 0x1D, 0x89, 0xFE, 0xA1, 0x78, 0xB5, 0xD2, 0xAD, 0xC9, 0x38, 0x89, 0x2E, 0xD6, 0xD5, 0xDA, 0x52, 0x0F, 0x99, 0xEE, 0x7A, 0xEC, 0x94, 0x2A, 0x88, 0x0C, 0x5A, 0x09, 0xA8, 0x85, 0xC5, 0xCF, 0xE1, 0x45, 0xEB, 0xE0, 0x73, 0xF1, 0xF7, 0x7F, 0x9A, 0xD1, 0x13, 0x17, 0xE7, 0x21, 0x13, 0x61, 0x7C, 0x31, 0xA1, 0x43, 0xED, 0x0A, 0x5B, 0xEC, 0x8E, 0x3F, 0xE8, 0xD4, 0x46, 0x9C, 0xBF, 0x34, 0xD6, 0x46, 0x4D, 0x05, 0xAD, 0xA9, 0x2C, 0xE0, 0x49, 0xC1, 0xB4, 0xAD, 0x58, 0xCE, 0xAE, 0x96, 0x9B, 0x8D, 0x2C, 0x7D, 0xF9, 0x5F, 0xF1, 0xD4, 0xF2, 0x69, 0x19, 0xFA, 0x3F, 0x52, 0xC6, 0x8A, 0xC3, 0xAF, 0xA9, 0x5B, 0x88, 0x48, 0x17, 0xFA, 0x55, 0xF1, 0xA7, 0x5A, 0xE1, 0x7E, 0xA4, 0xD5, 0x6C, 0x58, 0xAE, 0xAC, 0x65, 0x35, 0xDD, 0xBD, 0x16, 0xE8, 0xD3, 0xC1, 0xE5, 0x5B, 0xE7, 0x93, 0x39, 0xEC, 0x10, 0x79, 0xB6, 0xB2, 0x3A, 0x27, 0x0C, 0xE0, 0x01, 0xC5, 0xDA, 0x89, 0xD9, 0xED, 0x33, 0x5E, 0xD9, 0x52, 0x78, 0xAD, 0xFA, 0x65, 0x15, 0x23, 0xD9, 0x36, 0xDC, 0x9E, 0x1C, 0x05, 0x2B, 0xB1, 0x51, 0x07, 0xCF, 0x77, 0x6F, 0xFE, 0xE6, 0x26, 0xED, 0x92, 0x30, 0x3D, 0xE8, 0xE5, 0xCA, 0x94, 0x26, 0x53, 0x31, 0x91, 0x43, 0xE2, 0x06, 0xC7, 0x1A, 0x04, 0x29, 0x4E, 0x61, 0x32, 0xC0, 0xA1, 0x31, 0x2C, 0x1A, 0xAD, 0x62, 0xC1, 0x7E, 0xCA, 0x5A, 0x58, 0xCB, 0xC4, 0xC2, 0x6B, 0x83, 0x44, 0x03, 0x19, 0xA5, 0x46, 0x74, 0xD1, 0x58, 0x4D, 0x4B, 0x52, 0x83, 0x38, 0x38, 0xEA, 0x71, 0xCC, 0xDF, 0x10, 0x66, 0x9A, 0x97, 0x31, 0x33, 0x81, 0x43, 0x7F, 0xC6, 0xCF, 0xDD, 0x34, 0x24, 0x09, 0x00, 0x68, 0x20, 0xFD, 0x95, 0xFE, 0xF1, 0xE4, 0x58, 0x74, 0xC3, 0x5D, 0xFB, 0x57, 0x51, 0x97, 0x75, 0xE9, 0xBB, 0x60, 0x20, 0x66, 0x9D, 0x74, 0x15, 0x9D, 0x3F, 0xBB, 0xBD, 0x1C, 0xB8, 0x98, 0xD7, 0xFF, 0xB0, 0xF4, 0xAC, 0x45, 0x25, 0xE1, 0x4E, 0x8A, 0x8D, 0xBF, 0x50, 0x03, 0x02, 0x19, 0x23, 0x61, 0x02, 0x92, 0x4E, 0xA3, 0x27, 0xA9, 0xA8, 0xA8, 0x73, 0x89, 0x88, 0x72, 0x57, 0xDC, 0x53, 0xC4, 0x31, 0x9C, 0xC8, 0x84, 0x35, 0x95, 0x4B, 0x3E, 0x7E, 0x63, 0x92, 0x55, 0x0A, 0x2B, 0xE1, 0x68, 0x56, 0xB2, 0xF0, 0x03, 0x11, 0x08, 0xDC, 0x83, 0x66, 0xE5, 0x39, 0xD5, 0xCE, 0x9C, 0x91, 0x55, 0x57, 0xA7, 0x28, 0x9E, 0x85, 0x2F, 0x07, 0x45, 0x45, 0xF7, 0xE8, 0x9A, 0x59, 0xD6, 0x62, 0xED, 0x97, 0xF5, 0x55, 0xEA, 0xB7, 0x1A, 0xED, 0x03, 0x76, 0x90, 0x26, 0x94, 0x3B, 0x5D, 0x23, 0xB1, 0x18, 0xB2, 0xC9, 0x72, 0x5C, 0xC5, 0x61, 0x60, 0xB2, 0xD6, 0x50, 0x8E, 0x85, 0x01, 0x73, 0x1B, 0xAA, 0x63, 0xD7, 0x42, 0x17, 0x2F, 0xCD, 0x07, 0x0F, 0x97, 0xFC, 0xAF, 0x7E, 0x57, 0xB3, 0x03, 0xBD, 0xD0, 0xC8, 0x95, 0x91, 0xFB, 0xE7, 0xF3, 0x3D, 0xBD, 0xB5, 0x0C, 0x76, 0x4E, 0xDC, 0x59, 0x53, 0xC0, 0x77, 0x73, 0xB1, 0xAD, 0x05, 0x6C, 0x32, 0x58, 0x22, 0xF8, 0x1A, 0x3E, 0xD6, 0x5E, 0xA1, 0xF2, 0xFB, 0xC4, 0xCF, 0xC8, 0xBF, 0xF4, 0xA5, 0xC9, 0xCB, 0x13, 0xE8, 0x98, 0xC1, 0xBE, 0x3D, 0x8F, 0xD2, 0xEC, 0x8E, 0xA9, 0x63, 0x8F, 0x33, 0x0D, 0x39, 0x65, 0xBE, 0xE1, 0x7E, 0x72, 0x8B, 0xB4, 0x3B, 0x26, 0xCD, 0xFD, 0x22, 0xD5, 0x06, 0x8C, 0x6A, 0xB3, 0xBB, 0x13, 0x2B, 0x5E, 0x06, 0xE1, 0xEF, 0xE1, 0x29, 0xE8, 0x36, 0x80, 0x3A, 0xFA, 0x45, 0xEB, 0x6D, 0x55, 0xEF, 0xE2, 0xD9, 0x35, 0xCE, 0xB9, 0x8A, 0x07, 0xBA, 0x24, 0xD7, 0x0F, 0x88, 0x8B, 0x69, 0x76, 0x34, 0x34, 0x7A, 0xDD, 0x69, 0x91, 0xD4, 0x09, 0x93, 0x16, 0x4A, 0x20, 0x4E, 0xA7, 0x28, 0x6A, 0xC0, 0x19, 0x76, 0x53, 0x52, 0xC8, 0x01, 0xE3, 0xE3, 0x9C, 0x79, 0xEC, 0x00, 0x28, 0x38, 0x54, 0xFE, 0x13, 0x30, 0x69, 0x38, 0xBD, 0xEE, 0x3E, 0x4A, 0x04, 0x00, 0xE8, 0xA7, 0x97, 0x2B, 0x98, 0xB1, 0xB9, 0x3C, 0x8E, 0x6C, 0xBE, 0x33, 0x5C, 0x2F, 0x6A, 0x1B, 0xCA, 0x92, 0xC9, 0xEF, 0x4D, 0xE9, 0xE1, 0x35, 0x99, 0x6B, 0x84, 0x3F, 0xA3, 0xF0, 0x41, 0x84, 0xA8, 0x71, 0x26, 0x8C, 0xB1, 0x72, 0xDA, 0xC6, 0xD5, 0x4F, 0xEA, 0x1A, 0x63, 0x1D, 0x54, 0x71, 0x5B, 0xB6, 0x20, 0x7D, 0xB5, 0x9D, 0x5B, 0x4E, 0xF3, 0xFB, 0x95, 0x42, 0x6D, 0xA2, 0x29, 0x72, 0xF3, 0x5A, 0xF3, 0x3F, 0x62, 0xDD, 0xC1, 0x78, 0xDC, 0xA9, 0x59, 0x54, 0x22, 0x00, 0x7D, 0x32, 0xD8, 0x04, 0xCD, 0xEC, 0x6A, 0xE1, 0xC6, 0x64, 0x48, 0x90, 0x9D, 0x57, 0x4B, 0xE1, 0x8B, 0x05, 0xA8, 0x07, 0x06, 0xF4, 0x17, 0xB3, 0xC0, 0xF4, 0x5E, 0x16, 0x75, 0x1A, 0xCB, 0x45, 0xBB, 0xE0, 0x05, 0xC1, 0x1F, 0xD7, 0x73, 0x3D, 0xA3, 0xFC, 0xD5, 0x44, 0xB7, 0x57, 0xAA, 0x3F, 0x36, 0x08, 0x14, 0xE8, 0x55, 0x44, 0xE2, 0x9D, 0x09, 0x7E, 0x64, 0x33, 0xDC, 0x5C, 0xE2, 0x56, 0x1C, 0x6C, 0x51, 0x89, 0x8F, 0x24, 0x1C, 0xA6, 0x21, 0x08, 0xD8, 0x0A, 0x82, 0x9D, 0x66, 0xFB, 0x1E, 0xE7, 0x4E, 0xB8, 0x93, 0xD0, 0x92, 0x2C, 0x06, 0xBA, 0x5B, 0x87, 0xE0, 0x44, 0xBD, 0xFA, 0xA2, 0xE8, 0x41, 0xDB, 0x1F, 0xBE, 0x97, 0xF7, 0x66, 0x2A, 0x80, 0xE7, 0x95, 0x57, 0x95, 0x5D, 0xF1, 0x85, 0x54, 0xA3, 0x27, 0xB5, 0xFE, 0x2D, 0x28, 0x25, 0xA9, 0x89, 0x87, 0xB8, 0x78, 0x8F, 0x11, 0x5E, 0x0E, 0xE4, 0xD8, 0x30, 0x57, 0x07, 0x33, 0x71, 0x9B, 0xED, 0x51, 0xA3, 0xD6, 0x92, }, .pub_len = 1952, }, { .name = "ML-DSA 65 (seed and priv)", .parameter_set = CKP_ML_DSA_65, .priv_seed = { 0xCA, 0x65, 0x59, 0x2E, 0x96, 0x20, 0xFC, 0x39, 0xA0, 0x5D, 0xB6, 0xF4, 0x14, 0x9B, 0x62, 0x06, 0xDB, 0x54, 0x7C, 0x29, 0xBC, 0x5C, 0x0F, 0x4D, 0xC6, 0x96, 0xF2, 0xF0, 0x2D, 0xFC, 0x99, 0xE7, }, .priv_seed_len = 32, .priv = { 0x18, 0x48, 0xEE, 0xB1, 0x92, 0x17, 0x81, 0xEF, 0x07, 0x65, 0x62, 0x1A, 0x0A, 0x92, 0x50, 0x69, 0x42, 0x9E, 0xC4, 0xBC, 0x9D, 0xCD, 0x29, 0xFB, 0xD4, 0x84, 0x5E, 0x68, 0x2E, 0x41, 0x78, 0x7F, 0x43, 0x4E, 0xEC, 0x4D, 0x37, 0x52, 0xCA, 0xD0, 0x89, 0x6C, 0x90, 0xC8, 0xA2, 0x7B, 0x00, 0x20, 0x86, 0x59, 0xF5, 0x9C, 0x88, 0xB3, 0xC1, 0xBE, 0xFA, 0x74, 0x2C, 0x15, 0x5C, 0x9F, 0xF3, 0x72, 0x0E, 0x92, 0xA3, 0xB5, 0xDE, 0xDA, 0xEB, 0x0E, 0x97, 0x48, 0x07, 0xF1, 0xD3, 0x9E, 0xED, 0x7B, 0xFE, 0x33, 0x0A, 0xC0, 0x14, 0x0E, 0x1F, 0xD0, 0x0D, 0xF3, 0x10, 0x2E, 0xF5, 0x08, 0xC1, 0xBF, 0x95, 0xEE, 0xBA, 0xF5, 0x31, 0x1D, 0x76, 0x62, 0x96, 0x7B, 0xB2, 0x38, 0x9E, 0x97, 0x75, 0x76, 0x67, 0xAC, 0xCE, 0x85, 0x5A, 0x11, 0xCC, 0x92, 0x67, 0x1D, 0xCA, 0x28, 0x10, 0x9F, 0x66, 0xA1, 0x28, 0x50, 0x80, 0x61, 0x50, 0x62, 0x40, 0x11, 0x63, 0x58, 0x87, 0x88, 0x28, 0x23, 0x01, 0x84, 0x06, 0x82, 0x07, 0x24, 0x65, 0x32, 0x31, 0x35, 0x78, 0x34, 0x80, 0x21, 0x51, 0x45, 0x61, 0x56, 0x22, 0x16, 0x36, 0x36, 0x15, 0x83, 0x88, 0x02, 0x65, 0x62, 0x12, 0x26, 0x81, 0x58, 0x88, 0x36, 0x45, 0x85, 0x68, 0x27, 0x00, 0x33, 0x01, 0x05, 0x06, 0x70, 0x68, 0x50, 0x54, 0x54, 0x11, 0x20, 0x05, 0x68, 0x47, 0x88, 0x15, 0x50, 0x21, 0x07, 0x82, 0x60, 0x17, 0x66, 0x87, 0x22, 0x67, 0x81, 0x20, 0x18, 0x58, 0x33, 0x18, 0x44, 0x70, 0x64, 0x26, 0x24, 0x22, 0x63, 0x84, 0x13, 0x73, 0x26, 0x42, 0x43, 0x65, 0x03, 0x57, 0x71, 0x84, 0x60, 0x64, 0x75, 0x87, 0x34, 0x08, 0x10, 0x63, 0x78, 0x72, 0x85, 0x20, 0x13, 0x47, 0x50, 0x65, 0x61, 0x75, 0x16, 0x83, 0x80, 0x84, 0x48, 0x40, 0x86, 0x00, 0x47, 0x47, 0x27, 0x07, 0x02, 0x82, 0x22, 0x21, 0x40, 0x31, 0x37, 0x03, 0x40, 0x23, 0x02, 0x06, 0x08, 0x13, 0x03, 0x45, 0x03, 0x75, 0x62, 0x40, 0x80, 0x27, 0x68, 0x36, 0x36, 0x30, 0x73, 0x53, 0x78, 0x05, 0x36, 0x28, 0x18, 0x16, 0x67, 0x70, 0x71, 0x66, 0x38, 0x01, 0x18, 0x62, 0x46, 0x38, 0x66, 0x74, 0x87, 0x25, 0x87, 0x03, 0x01, 0x37, 0x83, 0x73, 0x74, 0x45, 0x78, 0x83, 0x53, 0x84, 0x25, 0x83, 0x15, 0x37, 0x68, 0x40, 0x43, 0x36, 0x35, 0x47, 0x65, 0x57, 0x32, 0x34, 0x31, 0x50, 0x55, 0x04, 0x58, 0x53, 0x30, 0x36, 0x04, 0x24, 0x74, 0x47, 0x85, 0x27, 0x85, 0x55, 0x54, 0x44, 0x85, 0x53, 0x71, 0x55, 0x64, 0x14, 0x30, 0x57, 0x01, 0x34, 0x07, 0x01, 0x44, 0x70, 0x58, 0x71, 0x71, 0x50, 0x75, 0x72, 0x32, 0x60, 0x61, 0x72, 0x30, 0x55, 0x21, 0x07, 0x21, 0x50, 0x07, 0x33, 0x50, 0x44, 0x34, 0x71, 0x68, 0x45, 0x85, 0x23, 0x00, 0x68, 0x66, 0x58, 0x28, 0x23, 0x11, 0x37, 0x87, 0x17, 0x45, 0x76, 0x66, 0x37, 0x33, 0x58, 0x33, 0x41, 0x56, 0x36, 0x55, 0x00, 0x86, 0x76, 0x32, 0x66, 0x11, 0x18, 0x41, 0x42, 0x43, 0x10, 0x21, 0x50, 0x41, 0x10, 0x47, 0x58, 0x43, 0x44, 0x53, 0x00, 0x38, 0x17, 0x08, 0x30, 0x67, 0x58, 0x25, 0x76, 0x34, 0x26, 0x00, 0x38, 0x55, 0x87, 0x68, 0x11, 0x43, 0x88, 0x68, 0x15, 0x56, 0x20, 0x47, 0x76, 0x74, 0x14, 0x35, 0x46, 0x50, 0x07, 0x28, 0x78, 0x68, 0x48, 0x76, 0x12, 0x30, 0x55, 0x82, 0x78, 0x82, 0x45, 0x80, 0x11, 0x62, 0x78, 0x48, 0x26, 0x61, 0x61, 0x68, 0x12, 0x12, 0x02, 0x38, 0x44, 0x63, 0x57, 0x18, 0x26, 0x28, 0x23, 0x10, 0x60, 0x17, 0x10, 0x74, 0x34, 0x65, 0x36, 0x88, 0x07, 0x42, 0x26, 0x72, 0x83, 0x26, 0x47, 0x75, 0x70, 0x15, 0x63, 0x18, 0x06, 0x63, 0x14, 0x28, 0x83, 0x20, 0x68, 0x41, 0x56, 0x00, 0x12, 0x68, 0x68, 0x43, 0x72, 0x23, 0x08, 0x12, 0x58, 0x01, 0x86, 0x87, 0x05, 0x44, 0x08, 0x45, 0x44, 0x36, 0x02, 0x08, 0x22, 0x78, 0x33, 0x52, 0x86, 0x18, 0x85, 0x57, 0x58, 0x03, 0x76, 0x25, 0x07, 0x32, 0x21, 0x07, 0x63, 0x07, 0x03, 0x24, 0x37, 0x50, 0x17, 0x03, 0x65, 0x05, 0x32, 0x28, 0x84, 0x07, 0x38, 0x65, 0x44, 0x52, 0x05, 0x60, 0x47, 0x84, 0x14, 0x38, 0x50, 0x83, 0x61, 0x85, 0x37, 0x06, 0x30, 0x18, 0x48, 0x44, 0x32, 0x81, 0x85, 0x11, 0x10, 0x84, 0x76, 0x87, 0x70, 0x51, 0x56, 0x58, 0x11, 0x50, 0x40, 0x66, 0x33, 0x05, 0x24, 0x57, 0x16, 0x65, 0x15, 0x45, 0x80, 0x20, 0x81, 0x05, 0x07, 0x32, 0x04, 0x80, 0x11, 0x33, 0x34, 0x15, 0x86, 0x35, 0x55, 0x64, 0x46, 0x62, 0x55, 0x87, 0x01, 0x30, 0x33, 0x23, 0x54, 0x87, 0x00, 0x58, 0x73, 0x71, 0x50, 0x88, 0x62, 0x43, 0x87, 0x60, 0x74, 0x72, 0x02, 0x10, 0x86, 0x03, 0x84, 0x16, 0x34, 0x78, 0x71, 0x11, 0x67, 0x47, 0x10, 0x60, 0x72, 0x85, 0x24, 0x23, 0x02, 0x14, 0x82, 0x48, 0x32, 0x25, 0x08, 0x28, 0x77, 0x23, 0x58, 0x85, 0x08, 0x77, 0x78, 0x15, 0x13, 0x37, 0x37, 0x64, 0x02, 0x21, 0x14, 0x58, 0x27, 0x53, 0x71, 0x12, 0x05, 0x15, 0x33, 0x66, 0x28, 0x81, 0x38, 0x12, 0x88, 0x64, 0x81, 0x13, 0x35, 0x15, 0x31, 0x46, 0x73, 0x61, 0x56, 0x52, 0x16, 0x03, 0x63, 0x37, 0x21, 0x11, 0x56, 0x61, 0x61, 0x07, 0x51, 0x17, 0x64, 0x48, 0x43, 0x05, 0x58, 0x48, 0x63, 0x70, 0x35, 0x87, 0x27, 0x23, 0x02, 0x60, 0x38, 0x54, 0x16, 0x27, 0x33, 0x41, 0x06, 0x28, 0x64, 0x11, 0x05, 0x51, 0x48, 0x74, 0x25, 0x42, 0x41, 0x58, 0x07, 0x73, 0x07, 0x42, 0x18, 0x67, 0x25, 0x17, 0x78, 0x34, 0x81, 0x33, 0x21, 0x75, 0x56, 0x66, 0x48, 0x58, 0x63, 0x11, 0x34, 0x55, 0x12, 0x37, 0x21, 0x08, 0x77, 0x46, 0x86, 0x04, 0x20, 0x28, 0x34, 0x76, 0x41, 0x23, 0x08, 0x46, 0x24, 0x88, 0x34, 0x58, 0x60, 0x54, 0x33, 0x83, 0x70, 0x72, 0x27, 0x24, 0x87, 0x22, 0x58, 0x43, 0x05, 0x41, 0x12, 0x41, 0x26, 0x68, 0x36, 0x05, 0x62, 0x34, 0x43, 0x58, 0x45, 0x81, 0x76, 0x55, 0x58, 0x17, 0x06, 0x46, 0x44, 0x80, 0x52, 0x42, 0x46, 0x27, 0x86, 0x06, 0x75, 0x67, 0x35, 0x84, 0x73, 0x30, 0x70, 0x28, 0x10, 0x78, 0x08, 0x70, 0x57, 0x34, 0x37, 0x80, 0x56, 0x70, 0x06, 0x60, 0x35, 0x11, 0x63, 0x52, 0x37, 0x21, 0x15, 0x58, 0x33, 0x71, 0x04, 0x86, 0x55, 0x15, 0x37, 0x78, 0x38, 0x34, 0x74, 0x37, 0x12, 0x14, 0x08, 0x65, 0x61, 0x08, 0x04, 0x54, 0x75, 0x56, 0x71, 0x56, 0x32, 0x64, 0x33, 0x26, 0x48, 0x47, 0x31, 0x00, 0x45, 0x18, 0x41, 0x67, 0x76, 0x14, 0x40, 0x08, 0x06, 0x05, 0x70, 0x64, 0x83, 0x30, 0x68, 0x67, 0x56, 0x26, 0x11, 0x83, 0x14, 0x23, 0x33, 0x41, 0x16, 0x34, 0x65, 0x64, 0x33, 0x73, 0x41, 0x74, 0x77, 0x68, 0x31, 0x75, 0x05, 0x18, 0x86, 0x84, 0x60, 0x68, 0x21, 0x22, 0x81, 0x43, 0x43, 0x23, 0x84, 0x88, 0x11, 0x35, 0x23, 0x04, 0x38, 0x16, 0x34, 0x62, 0x08, 0x31, 0x37, 0x73, 0x33, 0x14, 0x52, 0x24, 0x04, 0x11, 0x15, 0x84, 0x40, 0x73, 0x84, 0x32, 0x46, 0x28, 0x73, 0x56, 0x30, 0x16, 0x24, 0x64, 0x52, 0x17, 0x78, 0x28, 0x02, 0x21, 0x34, 0x72, 0x20, 0x53, 0x80, 0x27, 0x01, 0x77, 0x00, 0x57, 0x27, 0x81, 0x34, 0x51, 0x30, 0x55, 0x66, 0x08, 0x81, 0x67, 0x10, 0x48, 0x54, 0x26, 0x04, 0x53, 0x06, 0x16, 0x33, 0x75, 0x77, 0x70, 0x85, 0x70, 0x84, 0x44, 0x57, 0x81, 0x50, 0x41, 0x18, 0x37, 0x84, 0x36, 0x27, 0x52, 0x01, 0x24, 0x46, 0x37, 0x31, 0x16, 0x53, 0x58, 0x48, 0x01, 0x67, 0x76, 0x44, 0x73, 0x08, 0x66, 0x88, 0x60, 0x31, 0x14, 0x11, 0x60, 0x31, 0x80, 0x11, 0x36, 0x74, 0x21, 0x64, 0x65, 0x56, 0x15, 0x27, 0x81, 0x04, 0x35, 0x15, 0x14, 0x47, 0x05, 0x84, 0x86, 0x35, 0x11, 0x56, 0x62, 0x71, 0x50, 0x85, 0x00, 0x52, 0x20, 0x42, 0x77, 0x56, 0x64, 0x86, 0x44, 0x23, 0x23, 0x31, 0x78, 0x67, 0x58, 0x64, 0x83, 0x22, 0x62, 0x30, 0x30, 0x13, 0x23, 0x74, 0x45, 0x87, 0x00, 0x04, 0x26, 0x06, 0x08, 0x16, 0x83, 0x42, 0x16, 0x55, 0x15, 0x54, 0x67, 0x66, 0x32, 0x47, 0x80, 0x27, 0x65, 0x56, 0x10, 0x64, 0x21, 0x48, 0x75, 0x02, 0x84, 0x62, 0x00, 0x77, 0x07, 0x27, 0x76, 0x50, 0x43, 0x57, 0x05, 0x36, 0x46, 0x72, 0x03, 0x27, 0x70, 0x02, 0x82, 0x72, 0x12, 0x21, 0x06, 0x55, 0x11, 0x46, 0x27, 0x34, 0x80, 0x34, 0x16, 0x70, 0x30, 0x33, 0x26, 0x25, 0x42, 0x75, 0x48, 0x36, 0x16, 0x84, 0x08, 0x61, 0x33, 0x84, 0x43, 0x61, 0x02, 0x73, 0x50, 0x22, 0x84, 0x31, 0x23, 0x60, 0x01, 0x38, 0x51, 0x87, 0x36, 0x74, 0x16, 0x86, 0x71, 0x55, 0x02, 0x05, 0x28, 0x77, 0x46, 0x14, 0x53, 0x86, 0x67, 0x60, 0x03, 0x33, 0x81, 0x68, 0x56, 0x44, 0x83, 0x11, 0x13, 0x64, 0x81, 0x15, 0x16, 0x22, 0x32, 0x00, 0x64, 0x71, 0x83, 0x47, 0x22, 0x56, 0x82, 0x88, 0x58, 0x11, 0x55, 0x71, 0x37, 0x88, 0x17, 0x67, 0x35, 0x64, 0x62, 0x76, 0x73, 0x41, 0x15, 0x56, 0x80, 0x27, 0x12, 0x62, 0x00, 0x73, 0x27, 0x02, 0x66, 0x72, 0x06, 0x58, 0x61, 0x43, 0x24, 0x55, 0x44, 0x64, 0x67, 0x73, 0x10, 0x61, 0x42, 0x84, 0x17, 0x40, 0x22, 0x44, 0x15, 0x25, 0x44, 0x40, 0x78, 0x44, 0x06, 0x17, 0x55, 0x56, 0x43, 0x42, 0x63, 0x66, 0x84, 0x58, 0x15, 0x60, 0x75, 0x20, 0x80, 0x86, 0x46, 0x20, 0x84, 0x82, 0x11, 0x22, 0x73, 0x10, 0x63, 0x03, 0x60, 0x23, 0x02, 0x84, 0x34, 0x60, 0x51, 0x23, 0x30, 0x63, 0x45, 0x12, 0x57, 0x45, 0x56, 0x83, 0x51, 0x14, 0x17, 0x16, 0x12, 0x68, 0x77, 0x87, 0x82, 0x23, 0x40, 0x67, 0x76, 0x67, 0x36, 0x68, 0x80, 0x38, 0x68, 0x34, 0x11, 0x66, 0x21, 0x01, 0x82, 0x54, 0x23, 0x54, 0x75, 0x57, 0x52, 0x15, 0x31, 0x81, 0x73, 0x48, 0x85, 0x05, 0x73, 0x36, 0x51, 0x64, 0x08, 0x16, 0x68, 0x05, 0x28, 0x01, 0x86, 0x21, 0x21, 0x53, 0x02, 0x24, 0x56, 0x45, 0x67, 0x60, 0x48, 0x67, 0x37, 0x88, 0x67, 0x11, 0x54, 0x38, 0x83, 0x77, 0x55, 0x41, 0x70, 0x85, 0x81, 0x85, 0x36, 0x10, 0x32, 0x02, 0x25, 0x65, 0x13, 0x01, 0x21, 0x65, 0x35, 0x13, 0x54, 0x47, 0x41, 0x01, 0x44, 0x76, 0x84, 0x34, 0x05, 0x66, 0x00, 0x26, 0x74, 0x53, 0x73, 0x12, 0x28, 0x70, 0x75, 0x30, 0x88, 0x87, 0x04, 0x85, 0x72, 0x25, 0x53, 0x17, 0x42, 0x78, 0x25, 0x02, 0x52, 0x22, 0x26, 0x08, 0x42, 0x45, 0x18, 0x31, 0x05, 0x56, 0x23, 0x55, 0x86, 0x24, 0x47, 0x15, 0x56, 0x32, 0x67, 0x32, 0x58, 0x16, 0x78, 0x74, 0x42, 0x16, 0x73, 0x70, 0x24, 0x53, 0x00, 0x46, 0x40, 0x83, 0x50, 0x11, 0x73, 0x54, 0x24, 0x24, 0x53, 0x51, 0x81, 0x54, 0x84, 0x62, 0x03, 0x52, 0x27, 0x24, 0x33, 0x16, 0x04, 0x50, 0x05, 0x54, 0x76, 0x64, 0x42, 0x03, 0x32, 0x40, 0x45, 0x36, 0x00, 0x23, 0x30, 0x48, 0x75, 0x00, 0x28, 0x44, 0x45, 0x37, 0x07, 0x31, 0x47, 0x30, 0x17, 0x74, 0x6D, 0x24, 0x3F, 0xCC, 0x1C, 0x1F, 0x04, 0x2B, 0x78, 0xD4, 0x3D, 0x9E, 0xEB, 0xD6, 0xB3, 0xA6, 0x39, 0xB9, 0xAC, 0xF2, 0xEB, 0x77, 0x2E, 0x23, 0xAF, 0x4F, 0xA1, 0x7F, 0xA9, 0x31, 0x83, 0x92, 0xCD, 0xF1, 0x01, 0xD2, 0x51, 0x63, 0x31, 0xA8, 0xEB, 0xEE, 0x26, 0x82, 0x1F, 0xB4, 0x6A, 0x4D, 0xE0, 0x49, 0x86, 0xAE, 0xE1, 0x6B, 0x16, 0x2C, 0x35, 0x26, 0x4D, 0x4D, 0x73, 0x87, 0x0F, 0xE6, 0xF8, 0xAF, 0x6C, 0x1C, 0x9F, 0x76, 0xC0, 0xCA, 0x53, 0x47, 0x47, 0xAA, 0x4B, 0xE1, 0xE8, 0x9E, 0x7D, 0x42, 0x4F, 0x8C, 0x07, 0x20, 0x0D, 0x9D, 0xC5, 0x08, 0xF4, 0xF8, 0x00, 0x12, 0x73, 0x6B, 0xFF, 0xAA, 0x00, 0xA8, 0x2C, 0x83, 0x25, 0x5E, 0x22, 0x95, 0xAC, 0x17, 0xF5, 0xF4, 0xAD, 0xAF, 0x56, 0x0A, 0x4A, 0x6A, 0xA9, 0x2C, 0x89, 0xAF, 0x54, 0x53, 0x70, 0x05, 0x1F, 0x08, 0x76, 0xC9, 0x6E, 0xB8, 0x5A, 0x89, 0x47, 0x0D, 0xE8, 0x16, 0x49, 0x3A, 0xDF, 0x08, 0xFB, 0x9F, 0xE7, 0x3F, 0xA5, 0xC6, 0x5C, 0x06, 0x73, 0x81, 0x3F, 0x86, 0x3D, 0xA1, 0x6A, 0x32, 0xC2, 0xFA, 0x82, 0xDE, 0x76, 0x73, 0x4C, 0x43, 0x31, 0x74, 0x71, 0x2F, 0x55, 0x89, 0xD0, 0x45, 0x56, 0xFB, 0x29, 0x75, 0xCC, 0xA7, 0x28, 0x89, 0xF2, 0xA9, 0xCC, 0x3C, 0x8B, 0x94, 0xCC, 0x77, 0xB3, 0xE3, 0xB1, 0xBA, 0xB6, 0x8A, 0xD4, 0xDC, 0xA2, 0xCD, 0x54, 0xEC, 0x41, 0xAE, 0x56, 0x87, 0xA5, 0x24, 0x9F, 0x0C, 0x44, 0x84, 0xE4, 0x67, 0x07, 0xD8, 0x48, 0x76, 0xAA, 0x61, 0x3D, 0x9C, 0xFF, 0xC8, 0xA0, 0x05, 0x21, 0xFE, 0x7E, 0xC7, 0xBB, 0xF4, 0x5A, 0xA9, 0xA2, 0xFA, 0xAD, 0xD5, 0xEB, 0x9A, 0xBD, 0x4C, 0x13, 0xF5, 0x44, 0xB5, 0xEC, 0x87, 0x19, 0xB4, 0x99, 0xC4, 0x58, 0xD0, 0x28, 0x2A, 0x3C, 0x2C, 0x06, 0x82, 0x99, 0xF8, 0x05, 0x3B, 0xE0, 0x0B, 0xA6, 0x1F, 0x45, 0x1D, 0x5B, 0x4F, 0xEB, 0xD4, 0x3B, 0xB5, 0xFC, 0x7C, 0xC7, 0xE6, 0x6B, 0x41, 0x92, 0xA9, 0x95, 0x04, 0xBD, 0x14, 0x6E, 0x87, 0x3A, 0x74, 0x4D, 0x7B, 0x16, 0xA8, 0xCA, 0x9A, 0x4A, 0x1E, 0xD5, 0x28, 0xB0, 0xF3, 0x0D, 0xD8, 0x04, 0xCB, 0xDF, 0x57, 0x83, 0xFF, 0xC0, 0x9E, 0xA5, 0xA9, 0x09, 0x23, 0x02, 0x73, 0x3D, 0x60, 0x97, 0x79, 0x05, 0x42, 0xC7, 0x9E, 0xDA, 0xA0, 0xCC, 0x82, 0x97, 0x62, 0x2C, 0x9B, 0xCC, 0xDB, 0xF3, 0xC9, 0x75, 0x86, 0xED, 0x6C, 0x84, 0xE4, 0xE5, 0xA2, 0x59, 0x19, 0xB8, 0x5C, 0xE1, 0x10, 0x81, 0x4C, 0xDC, 0x05, 0x0C, 0x1E, 0xAB, 0x4E, 0xC8, 0x2F, 0xFC, 0xA4, 0xC2, 0x6F, 0xE6, 0x73, 0x8F, 0x30, 0x0B, 0xE8, 0x7C, 0xC7, 0xDF, 0x99, 0xEB, 0x54, 0x6E, 0x3C, 0xD8, 0x40, 0xF3, 0x51, 0x47, 0x39, 0x8E, 0xF2, 0x57, 0xAC, 0xDC, 0x6F, 0x51, 0xE4, 0x20, 0x5D, 0x9E, 0x85, 0xED, 0x88, 0x58, 0x31, 0xE9, 0x08, 0xDE, 0x81, 0xA5, 0xC5, 0xF7, 0x7A, 0x87, 0xA2, 0x13, 0xBB, 0xE6, 0x11, 0x66, 0x54, 0x01, 0x89, 0x22, 0x9A, 0x69, 0x48, 0x3C, 0x67, 0x74, 0xA6, 0xAE, 0xC4, 0xC7, 0x52, 0xA3, 0xCF, 0xEF, 0x0D, 0xB8, 0x96, 0xDE, 0x64, 0xA5, 0x7F, 0x41, 0xBC, 0x97, 0xBB, 0x45, 0x28, 0x69, 0x3C, 0xFE, 0x44, 0x13, 0xBF, 0x44, 0x55, 0xAC, 0x30, 0x1A, 0x74, 0x00, 0x70, 0xB0, 0x75, 0xEF, 0x53, 0x8D, 0x4F, 0x28, 0xD1, 0x44, 0xDE, 0x21, 0x6F, 0x4E, 0x83, 0xA9, 0x0F, 0x2B, 0x71, 0xE5, 0xFD, 0xD8, 0xD1, 0xAB, 0x3B, 0x50, 0x19, 0x0A, 0xB0, 0xFD, 0x64, 0xCF, 0x46, 0x37, 0x59, 0x22, 0x4F, 0x1B, 0x0D, 0xE9, 0x17, 0xFD, 0xC7, 0x0E, 0xAB, 0x3A, 0xF1, 0x8C, 0x19, 0x95, 0xC5, 0x78, 0x80, 0xD6, 0xEC, 0xC2, 0xCA, 0x9D, 0xA8, 0x14, 0x42, 0x4A, 0x22, 0xA2, 0x1C, 0x76, 0xD2, 0x59, 0x8C, 0xAB, 0xDD, 0x9E, 0xE1, 0x4C, 0x2A, 0xB3, 0x10, 0xCD, 0x5C, 0x17, 0x7F, 0xB4, 0x3F, 0x01, 0xFE, 0xC4, 0x0F, 0xE6, 0x0C, 0x1C, 0xD9, 0x17, 0xAF, 0x78, 0xBF, 0x1C, 0xB6, 0xD8, 0xDA, 0x3C, 0x61, 0x37, 0x55, 0x9D, 0xCE, 0xFB, 0xFE, 0xA6, 0xD0, 0xAA, 0xBD, 0xBB, 0xFB, 0xF1, 0x49, 0x1E, 0x17, 0x7D, 0x6F, 0x39, 0x6B, 0xC2, 0x02, 0xAD, 0xF5, 0xC7, 0x26, 0xE4, 0xD1, 0x69, 0x85, 0x8A, 0x7E, 0xFD, 0x13, 0x8D, 0x65, 0x00, 0x82, 0xB0, 0x79, 0xFD, 0xB7, 0x07, 0xE9, 0x08, 0xFB, 0x61, 0xCC, 0x1D, 0x73, 0x58, 0x0F, 0x9A, 0x1D, 0xA0, 0xAC, 0xFC, 0xCA, 0xE3, 0x13, 0x80, 0xA7, 0xAF, 0x47, 0x64, 0xA3, 0x8A, 0xEA, 0xA6, 0xA0, 0xFF, 0x72, 0x86, 0xA3, 0x9C, 0xDE, 0xE6, 0xDD, 0x33, 0x4A, 0xF2, 0x55, 0xA4, 0x99, 0xB6, 0xAA, 0xA5, 0x9D, 0x7C, 0x3D, 0x30, 0x15, 0xD4, 0xCD, 0xBC, 0x09, 0x5E, 0x1E, 0x32, 0xB9, 0xCD, 0xC4, 0x9F, 0x82, 0x1E, 0x10, 0xB3, 0x61, 0x36, 0xB3, 0x4B, 0xD3, 0x7C, 0x64, 0xFE, 0x41, 0x7E, 0xE5, 0x56, 0xEA, 0xC6, 0x57, 0x40, 0x9E, 0x68, 0xF9, 0x34, 0xA9, 0x37, 0xC8, 0x4B, 0x24, 0x9D, 0xA3, 0x96, 0xF5, 0x2F, 0x7F, 0x6F, 0x0A, 0xA5, 0x5E, 0x8C, 0xB9, 0x19, 0xE4, 0xD2, 0xC2, 0x0F, 0x41, 0x3A, 0xB6, 0x3E, 0x2F, 0xE1, 0xB6, 0xFD, 0xFE, 0x9A, 0x3A, 0x69, 0x9D, 0xBA, 0x0B, 0x1F, 0x61, 0x17, 0x06, 0xDF, 0x1E, 0x13, 0x38, 0xD1, 0x64, 0xF6, 0x21, 0x5D, 0x10, 0x8A, 0xFB, 0x53, 0x0D, 0x74, 0x3A, 0x15, 0xF5, 0x4F, 0x37, 0x44, 0x88, 0xB3, 0xED, 0xB3, 0x97, 0x51, 0xAD, 0x32, 0xC2, 0x2F, 0xD9, 0x1B, 0x35, 0xDD, 0x50, 0x8F, 0x01, 0x1F, 0x77, 0x80, 0x25, 0x30, 0x67, 0x0F, 0x15, 0xCE, 0x4F, 0x54, 0x28, 0x90, 0xA9, 0x22, 0x92, 0xA7, 0x86, 0xC4, 0x43, 0x05, 0x9C, 0x4D, 0xC5, 0xEA, 0xE9, 0xB5, 0xED, 0xAA, 0x82, 0x84, 0x0F, 0x03, 0x14, 0x5D, 0x33, 0x3F, 0x43, 0xDB, 0x79, 0x40, 0xC5, 0x5C, 0xC6, 0x72, 0x91, 0x5E, 0xF0, 0x7D, 0xB2, 0xB3, 0xF2, 0x99, 0xE6, 0x22, 0xA8, 0x1A, 0xFA, 0xA9, 0x79, 0x0D, 0xF6, 0x0C, 0x2B, 0x51, 0x4B, 0xA4, 0x91, 0x42, 0xA1, 0xCF, 0x4B, 0x17, 0x42, 0xC7, 0xED, 0x0C, 0x23, 0x6A, 0x2D, 0x84, 0x68, 0x94, 0xE5, 0xA8, 0x3C, 0xE2, 0x31, 0x07, 0xAD, 0xF7, 0x28, 0x6F, 0xF0, 0x8D, 0x73, 0x72, 0xB0, 0x53, 0xA2, 0xEC, 0x4C, 0x3E, 0x7D, 0xBB, 0x18, 0xA1, 0xE1, 0x8A, 0x74, 0x43, 0xD3, 0x7A, 0x2A, 0x18, 0x0D, 0xDA, 0x18, 0x3B, 0xD3, 0x3E, 0x78, 0x83, 0x0D, 0xF9, 0xEC, 0x50, 0xB1, 0xE8, 0x42, 0x65, 0x92, 0xF9, 0x74, 0xC4, 0xD3, 0x47, 0x3D, 0xA6, 0x0F, 0x9A, 0x42, 0x6C, 0xEB, 0x63, 0x51, 0xD3, 0xB7, 0x33, 0x40, 0xFC, 0x44, 0x08, 0x22, 0x7A, 0xE7, 0xD4, 0x6C, 0x42, 0x0C, 0x9B, 0xEE, 0x9C, 0x40, 0xE7, 0xDC, 0xE0, 0x4A, 0x3C, 0x19, 0x09, 0x6C, 0xB8, 0x98, 0x44, 0x64, 0x33, 0x8C, 0x8C, 0xE6, 0x01, 0x65, 0xE0, 0xA6, 0x3C, 0xE6, 0x31, 0xF6, 0x3C, 0xF4, 0x0C, 0xD1, 0x3F, 0xD9, 0x0E, 0x06, 0xFC, 0xB4, 0x8A, 0xC4, 0xA0, 0xD7, 0x60, 0x5D, 0x88, 0xC3, 0x1C, 0xBC, 0x8A, 0x63, 0xED, 0x6B, 0xD1, 0xA2, 0xF0, 0x4B, 0xB6, 0x61, 0xC7, 0x60, 0xDD, 0x54, 0x2D, 0xC6, 0x86, 0xA4, 0xC2, 0x5D, 0x15, 0x1A, 0xF1, 0x11, 0x7E, 0xCB, 0xBE, 0xC3, 0x10, 0x68, 0x63, 0x0F, 0x5B, 0xF2, 0x36, 0xF7, 0xAB, 0xC4, 0xCF, 0xC3, 0x51, 0xAA, 0x0A, 0x58, 0xC5, 0x6F, 0xD4, 0xD7, 0x1A, 0x3D, 0x0A, 0xE3, 0xDB, 0x06, 0x17, 0x27, 0xAD, 0x5F, 0xF3, 0x04, 0x1B, 0xDB, 0x68, 0x98, 0x7B, 0x71, 0x4D, 0x1E, 0x36, 0xB1, 0xC2, 0xCB, 0xBE, 0xC2, 0x82, 0xBC, 0xBD, 0x41, 0x3F, 0x39, 0x83, 0xF2, 0x98, 0xD1, 0xEF, 0xBC, 0x8B, 0x1B, 0x2A, 0xD8, 0x41, 0x26, 0xF7, 0xF7, 0x57, 0xFC, 0x27, 0x19, 0xBE, 0xE2, 0x09, 0x8D, 0x95, 0xD1, 0x43, 0x06, 0xCB, 0x79, 0x27, 0x3B, 0x36, 0xB9, 0x48, 0xF0, 0x29, 0x86, 0x7C, 0x2B, 0xC7, 0x01, 0x62, 0x4E, 0xE8, 0xCA, 0x08, 0x44, 0x81, 0xE6, 0x40, 0xB4, 0x62, 0x9D, 0x96, 0x5D, 0xBA, 0xE5, 0x09, 0x9E, 0x88, 0xBE, 0x95, 0x55, 0xA1, 0xAA, 0x69, 0xD5, 0x89, 0x08, 0x60, 0x9D, 0x95, 0xE3, 0xBD, 0x8C, 0xFE, 0xA0, 0x48, 0x4D, 0x7E, 0xF3, 0xFA, 0x3F, 0x84, 0x51, 0x62, 0x01, 0x2F, 0xEB, 0x59, 0xE4, 0x42, 0x91, 0x8D, 0x59, 0xF8, 0x24, 0x2C, 0xEC, 0x94, 0xFE, 0xD6, 0xC4, 0xFE, 0xBF, 0xB2, 0xE3, 0x37, 0x0D, 0x03, 0x30, 0x42, 0x10, 0x04, 0x1D, 0x7A, 0x30, 0x83, 0x85, 0xA9, 0x38, 0x56, 0x76, 0x90, 0x6B, 0x44, 0xE4, 0xED, 0x2B, 0xBF, 0xCD, 0xFD, 0xC9, 0x1C, 0x68, 0xAC, 0xFB, 0xA4, 0x91, 0xCD, 0xE9, 0xAB, 0x19, 0x86, 0x91, 0x20, 0x42, 0x0D, 0x00, 0x1E, 0x3B, 0x72, 0xD5, 0x21, 0xAC, 0x6E, 0x0A, 0xD1, 0x4F, 0xB3, 0xB3, 0xBA, 0x5A, 0xDF, 0x89, 0x0B, 0x8A, 0x88, 0xF2, 0xC8, 0xB8, 0x81, 0x44, 0xF7, 0xA5, 0x20, 0x5C, 0x85, 0x02, 0xB7, 0x03, 0x67, 0x8D, 0xCB, 0x4F, 0xCE, 0xF3, 0x4F, 0x7B, 0xAC, 0x03, 0xFD, 0xE7, 0x9A, 0x3A, 0x3A, 0x3F, 0xD9, 0x9D, 0x7C, 0x95, 0x6A, 0xF9, 0xC9, 0x93, 0x4D, 0x6D, 0xE6, 0x6F, 0xEA, 0x41, 0x28, 0xC3, 0x61, 0x19, 0xBA, 0x81, 0x6D, 0xBA, 0xA6, 0xD8, 0x18, 0xB3, 0xAE, 0xAA, 0x1B, 0x20, 0x62, 0xA6, 0x3A, 0xEE, 0x8B, 0x0D, 0x99, 0xBB, 0x6F, 0xC4, 0x9B, 0x3D, 0x0D, 0x21, 0x29, 0xBF, 0x1C, 0x57, 0xE1, 0x5E, 0x77, 0x88, 0xC3, 0x75, 0x8E, 0x6E, 0x72, 0x2C, 0x72, 0x47, 0x06, 0x9C, 0xFD, 0xD4, 0x4D, 0x49, 0x16, 0xEC, 0xFD, 0x8D, 0x8D, 0x85, 0xB5, 0x58, 0xF3, 0xE8, 0x8C, 0xCB, 0x4C, 0x17, 0x86, 0x9A, 0x94, 0x3D, 0xBE, 0x99, 0x1C, 0x4A, 0x0C, 0x1F, 0x5C, 0x83, 0xCA, 0x94, 0x2D, 0x21, 0x58, 0x1F, 0x32, 0xF1, 0x95, 0x14, 0x6A, 0x8E, 0x1D, 0xAF, 0xCF, 0xC3, 0x7B, 0x0C, 0x25, 0x58, 0x7F, 0xC9, 0xB0, 0x81, 0x88, 0x57, 0x72, 0x9B, 0x18, 0x6A, 0x5F, 0x38, 0x96, 0x1B, 0xD7, 0x19, 0x0C, 0x5C, 0x2E, 0x62, 0xB7, 0xEE, 0xAF, 0x58, 0xCE, 0xF7, 0x18, 0x7B, 0xE8, 0x46, 0x48, 0x85, 0x1F, 0x87, 0x03, 0xB3, 0xBF, 0x07, 0x7D, 0xD8, 0xA1, 0x91, 0xB2, 0x2F, 0x3B, 0xDE, 0xD0, 0xB4, 0xC0, 0x45, 0xD3, 0xD5, 0xAD, 0x11, 0x2D, 0x72, 0xF2, 0xE7, 0x46, 0xA0, 0x12, 0xCD, 0xEF, 0xA2, 0xF1, 0x63, 0x22, 0x0F, 0x1A, 0x4E, 0xC2, 0x9A, 0x44, 0xD7, 0xFF, 0x56, 0x5C, 0x5A, 0x14, 0x9B, 0xAA, 0xB0, 0xF3, 0xAA, 0x2A, 0xA6, 0xEE, 0xF9, 0xF5, 0x35, 0x20, 0x4D, 0x22, 0xE9, 0x3C, 0x07, 0x0E, 0x66, 0x9E, 0x81, 0xD7, 0x2F, 0x1D, 0xB1, 0x62, 0xF7, 0xA7, 0x3C, 0x73, 0x9D, 0xB6, 0x3A, 0x02, 0x47, 0xB8, 0xB8, 0x91, 0x3F, 0xD3, 0x3B, 0x46, 0xE1, 0xAF, 0xC8, 0x24, 0x49, 0xDC, 0x1B, 0x06, 0xE2, 0xB3, 0xD0, 0x5F, 0xEE, 0x98, 0x51, 0x59, 0x71, 0xE4, 0xA8, 0xB9, 0x9B, 0xC8, 0x6F, 0xCF, 0x25, 0x38, 0x96, 0x9C, 0x8B, 0xBA, 0x5D, 0x41, 0x93, 0x74, 0x1E, 0xDE, 0x0B, 0x60, 0x09, 0xB0, 0x06, 0xC8, 0x79, 0x31, 0xB2, 0x5E, 0x00, 0x7F, 0x4D, 0x4A, 0x5A, 0x71, 0xD1, 0x73, 0xED, 0x09, 0x71, 0xD4, 0x9D, 0x13, 0x01, 0xC6, 0x4B, 0x57, 0xDC, 0x08, 0x27, 0x3B, 0xBF, 0x53, 0x82, 0xC3, 0x2A, 0xBF, 0xA6, 0x65, 0xD8, 0x69, 0x27, 0x69, 0x37, 0x3D, 0x8D, 0x69, 0x90, 0xE4, 0x4A, 0x4C, 0x3B, 0x8E, 0x7D, 0xCD, 0x8C, 0x53, 0x03, 0x38, 0x28, 0xBB, 0x80, 0x4E, 0xD7, 0xAC, 0x5B, 0x8D, 0x09, 0x47, 0x45, 0xD3, 0xAB, 0xE4, 0x1D, 0x80, 0x38, 0x32, 0xFC, 0x52, 0x67, 0xC8, 0x66, 0xA1, 0x6C, 0xEF, 0x68, 0x48, 0x90, 0x10, 0x75, 0xAF, 0x85, 0x6C, 0xCC, 0x45, 0x6A, 0x2C, 0x14, 0x63, 0xAD, 0xBB, 0xF6, 0x7A, 0x82, 0x1F, 0x12, 0x9D, 0x9D, 0x41, 0xE0, 0xD1, 0x65, 0xB3, 0x3A, 0x38, 0x02, 0x44, 0xC2, 0xFB, 0x84, 0xD7, 0x0E, 0xCA, 0xFB, 0x85, 0x8C, 0xBF, 0x74, 0x85, 0x1D, 0x26, 0x82, 0x11, 0x93, 0x56, 0x94, 0x94, 0xA0, 0xB4, 0x90, 0xF8, 0xD6, 0xCF, 0xE7, 0xB0, 0x9A, 0x47, 0x26, 0xC9, 0xB1, 0x50, 0x4B, 0xD6, 0x8F, 0x6C, 0x5A, 0x35, 0x76, 0x33, 0x62, 0xD6, 0x76, 0xEF, 0x62, 0x41, 0xFF, 0xC5, 0xBE, 0x95, 0x91, 0x3F, 0x89, 0x1B, 0xFE, 0xA6, 0x78, 0xF8, 0xDE, 0x8E, 0xC7, 0xB8, 0x0D, 0xA4, 0x49, 0xEB, 0xEE, 0xF9, 0xB7, 0xC2, 0x18, 0x14, 0x0C, 0xB1, 0x4C, 0xD4, 0xC7, 0x3E, 0x7F, 0x10, 0x9B, 0xF8, 0x6B, 0xC0, 0x3E, 0x6D, 0x94, 0xD3, 0x7B, 0xC2, 0xB2, 0x95, 0x08, 0x25, 0xE3, 0x30, 0xF4, 0xEC, 0x5A, 0x98, 0xFB, 0x35, 0x8D, 0xB4, 0xDF, 0x71, 0xF2, 0x59, 0x0A, 0x6F, 0xFA, 0xA6, 0xD5, 0x4A, 0x37, 0x6E, 0x71, 0xE0, 0x57, 0x9B, 0x18, 0xDC, 0xCB, 0xB6, 0x00, 0x66, 0xD9, 0x2F, 0xFB, 0x11, 0xE6, 0x36, 0x56, 0x12, 0xE9, 0x27, 0x61, 0xE3, 0xAD, 0xFD, 0x57, 0xE1, 0xF7, 0xCF, 0x50, 0x80, 0xED, 0x36, 0x6E, 0x2B, 0xFE, 0x24, 0xB6, 0x19, 0x92, 0x90, 0x8F, 0x30, 0x7D, 0x28, 0xD1, 0x18, 0xFE, 0x53, 0xE6, 0x42, 0x86, 0x83, 0x41, 0xA1, 0x14, 0x04, 0x9D, 0x14, 0x86, 0x65, 0x3A, 0x85, 0x76, 0x26, 0x60, 0x66, 0x3B, 0x15, 0xD0, 0xA0, 0xA2, 0x13, 0x58, 0x82, 0x76, 0xF9, 0x09, 0x50, 0xEA, 0xC4, 0xD3, 0xC4, 0x46, 0x87, 0x05, 0x5D, 0xD1, 0xEE, 0x5B, 0xAA, 0xBA, 0x56, 0xD3, 0x34, 0xA7, 0x44, 0x7C, 0x39, 0xAB, 0x35, 0x3A, 0x3C, 0x7D, 0x5D, 0x8A, 0xBE, 0x7B, 0x47, 0xDE, 0xBC, 0x08, 0x14, 0xD9, 0x73, 0x8E, 0x38, 0xF6, 0xC1, 0x83, 0x58, 0xAE, 0x37, 0x2E, 0xEC, 0x3D, 0x73, 0x7F, 0xEB, 0x5E, 0x94, 0x4A, 0xC2, 0x0D, 0x0E, 0x39, 0x09, 0x2D, 0xA4, 0x04, 0x13, 0xE5, 0x94, 0x90, 0x76, 0xAD, 0x5D, 0xEB, 0xEC, 0x98, 0x76, 0x7B, 0xE4, 0xED, 0x4C, 0xA2, 0x3C, 0x2F, 0x84, 0xFB, 0xFF, 0xDC, 0x61, 0x5B, 0x37, 0x41, 0xE0, 0x0E, 0xBB, 0x1E, 0x34, 0x5A, 0x6E, 0xAA, 0x7B, 0x05, 0x61, 0x61, 0x5A, 0x87, 0x8D, 0x81, 0x54, 0x3A, 0x79, 0xF8, 0xCA, 0x99, 0xE1, 0xAB, 0xC4, 0xC1, 0x6B, 0x22, 0xB1, 0xCD, 0x17, 0x31, 0x92, 0x8A, 0x34, 0x9C, 0x25, 0xF1, 0xE3, 0xE1, 0x9D, 0xE9, 0xFB, 0x2F, 0x14, 0x15, 0x27, 0xAE, 0x83, 0xE8, 0x81, 0xCE, 0xE1, 0x2E, 0xE5, 0xAA, 0xC1, 0xA1, 0xD8, 0x41, 0xDD, 0x46, 0xCD, 0xE6, 0x3D, 0x69, 0x71, 0xFF, 0x5D, 0x19, 0xFA, 0xE1, 0x9E, 0x92, 0xF4, 0x26, 0xF2, 0xE3, 0xAC, 0x0D, 0x75, 0xFA, 0xCE, 0xC9, 0x33, 0xB4, 0x89, 0xE9, 0x10, 0x85, 0xB0, 0xB4, 0x7D, 0x50, 0xD8, 0xEE, 0x85, 0x9E, 0x5D, 0x35, 0x96, 0x88, 0x9A, 0xAF, 0x53, 0x5A, 0xD6, 0xC8, 0xC7, 0x35, 0x8E, 0x80, 0x77, 0x4D, 0x15, 0x63, 0x06, 0x51, 0xD0, 0x0F, 0x2D, 0x4A, 0x62, 0x4A, 0x53, 0xD9, 0x1C, 0x5C, 0x96, 0x29, 0xFC, 0xDA, 0xB0, 0xA5, 0x2B, 0x54, 0x88, 0x90, 0x50, 0x9B, 0x4D, 0x27, 0x40, 0x6A, 0x5A, 0x32, 0xD3, 0x59, 0xF0, 0x2A, 0xE4, 0x18, 0x74, 0x52, 0xFF, 0xBF, 0x33, 0x26, 0xAA, 0x4A, 0xF2, 0x22, 0x65, 0x97, 0xEE, 0x7D, 0x72, 0xC6, 0xD4, 0x7D, 0xA4, 0x67, 0x7F, 0x02, 0x06, 0x98, 0x0F, 0x86, 0x10, 0x42, 0x11, 0x1C, 0xA0, 0xEA, 0x12, 0xF7, 0xEF, 0x71, 0xC5, 0x0D, 0x8C, 0x7A, 0xC4, 0x51, 0xFF, 0x42, 0x84, 0x41, 0xE6, 0x32, 0x22, 0xEF, 0x82, 0xD1, 0x17, 0xE6, 0x26, 0xC8, 0x81, 0x36, 0x52, 0x80, 0xA0, 0x67, 0xA2, 0xB6, 0xE0, 0xE3, 0x91, 0xB0, 0x9D, 0x0E, 0x09, 0x7C, 0x56, 0x13, 0x2D, 0x80, 0xDA, 0xD7, 0x49, 0xDC, 0x1A, 0x9B, 0xCA, 0xF2, 0x21, 0x38, 0xC2, 0xDC, 0xFE, 0x2C, 0x1D, 0x1E, 0x87, 0xF3, 0xFD, 0xC4, 0xB8, 0xC7, 0x82, 0xCA, 0x18, 0x1A, 0x45, 0x72, 0x01, 0x77, 0xFC, 0x60, 0x6D, 0x7B, 0x6C, 0x33, 0x4F, 0xFF, 0x7E, 0x6D, 0x04, 0xF6, 0x7D, 0x1F, 0xA7, 0x5A, 0xC4, 0x9B, 0xB7, 0x0A, 0x45, 0xD3, 0x4E, 0x04, 0x94, 0xD2, 0x11, 0xE1, 0xCA, 0x71, 0x91, 0xDF, 0x84, 0x05, 0xCD, 0x15, 0x09, 0x70, 0x34, 0x93, 0xEC, 0xB4, 0xEB, 0x44, 0x8A, 0x57, 0xA3, 0x3B, 0x5E, 0x40, 0x78, 0x03, 0x40, 0x9D, 0x82, 0x94, 0xEF, 0xDB, 0x45, 0xA2, 0xDF, 0xF9, 0xBD, 0xCB, 0x48, 0x11, 0xB6, 0xCA, 0x8C, 0x5A, 0x6B, 0x84, 0xE4, 0xC8, 0xE6, 0xFB, 0x0E, 0x6F, 0xD1, 0x87, 0x80, 0x45, 0x32, 0x70, 0x1D, 0xE6, 0xC8, 0x0E, 0x3C, 0xBE, 0x22, 0xCE, 0x90, 0x06, 0xF4, 0x74, 0x6A, 0x61, 0x16, 0xED, 0x48, 0xCF, 0x7C, 0xE2, 0xD6, 0xC3, 0x3F, 0x70, 0x44, 0xCE, 0x2F, 0xBC, 0xC0, 0xE8, 0x9D, 0x60, 0xFC, 0x60, 0x5F, 0xBD, 0xC9, 0x7E, 0x10, 0xB4, 0xD2, 0xB6, 0xCD, 0x0A, 0x84, 0x15, 0xD6, 0x18, 0xE8, 0x43, 0x0C, 0xFF, 0x86, 0x6A, 0x8E, 0x56, 0x47, 0xA3, 0xC9, 0x77, 0x7C, 0xC7, 0x88, 0x5D, 0xAD, 0xCB, 0x67, 0x0B, 0x95, 0xCD, 0xBE, 0xAD, 0x7D, 0x85, 0x55, 0x61, 0xA6, 0x01, 0x48, 0x55, 0xB1, 0x18, 0xDF, 0xF9, 0x37, 0xA1, 0x7E, 0x9F, 0xB6, 0x2E, 0xC6, 0xE6, 0xDB, 0x42, 0x39, 0x4C, 0x04, 0x4E, 0x71, 0x94, 0x51, 0x1C, 0x1E, 0xA2, 0x06, 0x9D, 0xE9, 0x04, 0x50, 0xD1, 0xF8, 0x6E, 0xC0, 0xF0, 0xCD, 0xCD, 0x75, 0x8D, 0x38, 0xF3, 0xE5, 0xE6, 0x90, 0xB8, 0x22, 0x88, 0x56, 0x95, 0xFD, 0x5D, 0xFC, 0xC4, 0x18, 0xEC, 0x66, 0xA2, 0x67, 0x0C, 0xF2, 0x2C, 0xB8, 0xEA, 0x4E, 0x47, 0xA7, 0x16, 0x86, 0x9A, 0xC6, 0xB5, 0x4B, 0x74, 0x12, 0xF0, 0x9E, 0x4F, 0x58, 0x72, 0x3E, 0x98, 0x5E, 0x81, 0x36, 0x87, 0x84, 0x17, 0x27, 0xDC, 0x70, 0x2D, 0x22, 0x30, 0xA4, 0xED, 0xED, 0xE3, 0xFF, 0xC6, 0x83, 0x82, 0xA7, 0x55, 0x7F, 0x7D, 0x1B, 0x6F, 0x1C, 0x5A, 0xA2, 0x36, 0x7A, 0x04, 0xF8, 0xEE, 0x21, 0x71, 0xED, 0xE7, 0x9B, 0x67, 0x6A, 0x07, 0xD7, 0xBA, 0x32, 0x25, 0x78, 0x59, 0xCC, 0x7A, 0x26, 0xEA, 0xBE, 0xAB, 0x41, 0x72, 0xA5, 0x14, 0x46, 0xA7, 0xD8, 0x72, 0xBA, 0x39, 0xD9, 0x40, 0xD4, 0xB2, 0x56, 0x59, 0x22, }, .priv_len = 4032, .pub = { 0x18, 0x48, 0xEE, 0xB1, 0x92, 0x17, 0x81, 0xEF, 0x07, 0x65, 0x62, 0x1A, 0x0A, 0x92, 0x50, 0x69, 0x42, 0x9E, 0xC4, 0xBC, 0x9D, 0xCD, 0x29, 0xFB, 0xD4, 0x84, 0x5E, 0x68, 0x2E, 0x41, 0x78, 0x7F, 0xDF, 0x4C, 0x84, 0xFD, 0xAC, 0x7D, 0x56, 0x15, 0x41, 0x60, 0x17, 0x7A, 0x4D, 0xC9, 0x39, 0xBD, 0xF3, 0x66, 0xE8, 0x2D, 0x69, 0x5A, 0x50, 0x01, 0x79, 0xEC, 0x0C, 0x48, 0x7E, 0xF7, 0x36, 0x93, 0x3F, 0xEC, 0xD8, 0xC7, 0xCA, 0x91, 0x79, 0x83, 0x50, 0xC2, 0x2D, 0x8C, 0xB6, 0xB9, 0x1B, 0x10, 0x09, 0xA2, 0x80, 0x63, 0xA7, 0x84, 0x7D, 0x29, 0x06, 0x3D, 0x54, 0x21, 0x40, 0x50, 0xDD, 0xF3, 0x8F, 0xA6, 0x54, 0x4D, 0xB0, 0xF1, 0xD2, 0xC7, 0x94, 0x35, 0xFF, 0xC2, 0x30, 0x44, 0xB4, 0x24, 0xEA, 0xA1, 0xCE, 0x7D, 0xB3, 0xE3, 0xF9, 0x9C, 0x0D, 0x25, 0xAE, 0xB4, 0xDF, 0x4F, 0x85, 0xD4, 0xDA, 0xE7, 0xA0, 0xDC, 0x70, 0x7D, 0x07, 0x85, 0xB6, 0xDA, 0x5D, 0xE8, 0x1A, 0xD9, 0xBC, 0x0E, 0xB7, 0xDD, 0x94, 0xD4, 0xC7, 0x12, 0x41, 0x3F, 0x43, 0xB8, 0xBE, 0x6C, 0x55, 0x79, 0xC1, 0x38, 0x22, 0xBA, 0xE4, 0xB9, 0x66, 0xF7, 0x08, 0x8C, 0x42, 0xD7, 0xE1, 0xAF, 0xDE, 0x68, 0x24, 0xCD, 0x3B, 0x74, 0x24, 0x5A, 0xE5, 0x01, 0xA9, 0x89, 0x17, 0x6F, 0xD2, 0x46, 0xE8, 0x45, 0x2B, 0x43, 0x16, 0x6D, 0x2E, 0xC8, 0xE0, 0x8B, 0x09, 0x12, 0xD1, 0xD6, 0x84, 0x8C, 0xCB, 0xAA, 0x86, 0xE8, 0x10, 0x96, 0xE8, 0x0C, 0x0E, 0x1E, 0x78, 0x08, 0x8A, 0xA5, 0xF2, 0xA9, 0xD1, 0x6E, 0xB1, 0x1E, 0x6B, 0xC9, 0x30, 0x7A, 0x46, 0x8A, 0xB7, 0x4C, 0xBB, 0x4B, 0x34, 0x5F, 0x15, 0x09, 0x51, 0x3E, 0xEC, 0xDE, 0x94, 0x50, 0x64, 0xF9, 0xFD, 0x2E, 0x38, 0xF4, 0x8B, 0x0D, 0xD2, 0xDA, 0x10, 0x18, 0x92, 0xCA, 0x52, 0xDB, 0xF0, 0x47, 0x9A, 0x6A, 0x92, 0x29, 0x7B, 0x05, 0x84, 0xEF, 0x38, 0x03, 0x3E, 0x85, 0x18, 0x5C, 0xDF, 0x77, 0x10, 0x04, 0xD8, 0x23, 0xB0, 0x02, 0x06, 0xB5, 0x61, 0x58, 0x9E, 0x72, 0xC8, 0x49, 0x61, 0xBD, 0x21, 0xA2, 0xCC, 0xA5, 0x48, 0x85, 0x2D, 0xA8, 0x0D, 0xB1, 0xBB, 0x13, 0x5E, 0xAE, 0xA6, 0xCB, 0xA8, 0x71, 0x40, 0x32, 0x3E, 0x78, 0x84, 0x4D, 0x7B, 0xC2, 0x2C, 0x52, 0xDB, 0x77, 0x0A, 0x99, 0x24, 0x99, 0xF0, 0x7B, 0x56, 0x91, 0xBB, 0x27, 0x7C, 0xB7, 0x89, 0xD4, 0xE9, 0x31, 0xB7, 0x29, 0xC3, 0xC8, 0x4C, 0x88, 0x14, 0x3F, 0x80, 0x60, 0xAB, 0x30, 0xB6, 0x97, 0xA3, 0x66, 0xA7, 0x2A, 0x26, 0xF8, 0xD1, 0x47, 0x89, 0xAC, 0x56, 0x32, 0x6A, 0xC1, 0x95, 0xF9, 0x32, 0xCF, 0x3C, 0x25, 0xBD, 0xEB, 0xEF, 0x24, 0xB7, 0xDB, 0xC7, 0x6A, 0xE1, 0x9E, 0x39, 0x32, 0xE7, 0xF6, 0xF2, 0x14, 0x68, 0x00, 0xF4, 0xA1, 0xFE, 0x35, 0x93, 0xDF, 0x47, 0xE4, 0x09, 0x5E, 0xC8, 0x9A, 0x37, 0xF0, 0xAC, 0x4D, 0x86, 0x9B, 0x78, 0xDB, 0x64, 0x3A, 0xF1, 0x94, 0xE8, 0x28, 0x55, 0x28, 0xD3, 0x0B, 0x7A, 0x9D, 0x5E, 0xFA, 0x21, 0x2B, 0x01, 0xD6, 0x8B, 0x5E, 0x0C, 0x19, 0xDC, 0xE6, 0x05, 0x7A, 0xFF, 0x8C, 0x72, 0xAC, 0xA5, 0x70, 0x73, 0xC6, 0x0F, 0x15, 0xC8, 0x0F, 0xC1, 0xF7, 0x38, 0x70, 0xB6, 0xA0, 0x9F, 0x1A, 0x9D, 0x4E, 0xFB, 0x67, 0xFE, 0x84, 0x6C, 0x11, 0x32, 0xED, 0x8B, 0xB1, 0x60, 0xDC, 0x9D, 0x3F, 0x3E, 0x79, 0x2C, 0x2C, 0x21, 0xF7, 0x0D, 0x18, 0x77, 0x5E, 0x0D, 0x5B, 0xD5, 0xAE, 0x8C, 0xE8, 0xD7, 0x05, 0xA8, 0x88, 0xE0, 0xD0, 0x9F, 0xA0, 0x0A, 0xF6, 0x88, 0x29, 0xEF, 0xFF, 0x4F, 0x06, 0x07, 0xD2, 0x2B, 0x9A, 0x27, 0x12, 0xDA, 0xCE, 0x7A, 0x9C, 0x3A, 0x5A, 0x1A, 0x75, 0x06, 0x27, 0x95, 0x85, 0x7A, 0x0F, 0x48, 0x97, 0xF0, 0x32, 0xE9, 0x0D, 0x0B, 0x4F, 0x51, 0xCD, 0x93, 0x87, 0xF1, 0xE3, 0x91, 0xB5, 0x8E, 0x82, 0x68, 0xAA, 0xEE, 0x1D, 0xEC, 0x07, 0xCC, 0x21, 0x86, 0x35, 0xDF, 0xD2, 0xA5, 0xE0, 0xD4, 0xCC, 0x79, 0x89, 0x34, 0x73, 0x9E, 0xF2, 0x78, 0xEA, 0xBE, 0xC1, 0x21, 0xBF, 0x52, 0x46, 0xA7, 0x9B, 0x94, 0x70, 0x68, 0x2A, 0x3D, 0xBF, 0xE7, 0x2B, 0xCB, 0x66, 0x20, 0x8F, 0x56, 0x1D, 0x05, 0xC4, 0x84, 0xB2, 0xA7, 0x23, 0xAD, 0xF8, 0x1E, 0x61, 0x7F, 0x5E, 0xEE, 0xE9, 0x75, 0xCB, 0x53, 0x1B, 0x13, 0xD2, 0x51, 0x47, 0xB4, 0x3D, 0x21, 0xAE, 0x06, 0x96, 0x91, 0xEF, 0xD1, 0xAA, 0xDC, 0x48, 0xB2, 0xAE, 0xB7, 0x8F, 0xFD, 0x7B, 0x49, 0x98, 0xAB, 0xBD, 0x80, 0xD6, 0x1A, 0xF6, 0x6B, 0x94, 0x63, 0xF8, 0xA9, 0x37, 0x00, 0x53, 0xCD, 0x48, 0x90, 0x53, 0x27, 0x3F, 0x0A, 0x6F, 0x06, 0xD7, 0x72, 0x88, 0x11, 0x62, 0xB6, 0x82, 0x3F, 0x7B, 0x02, 0x1D, 0xC5, 0xA7, 0x75, 0x5D, 0x37, 0x13, 0xD9, 0x7C, 0xA9, 0x46, 0x7D, 0x72, 0x3E, 0x27, 0xCE, 0x84, 0xB4, 0x63, 0xFF, 0x88, 0x62, 0x9B, 0x0C, 0x92, 0xF3, 0xE1, 0xB5, 0x4D, 0xC8, 0xE6, 0xBA, 0xC3, 0x37, 0x44, 0xCF, 0xC3, 0xCC, 0xD8, 0xDB, 0xDC, 0x53, 0xDE, 0x87, 0x7E, 0x12, 0x7A, 0x50, 0x9F, 0xF2, 0x79, 0xA1, 0xBC, 0x67, 0xA8, 0x85, 0x23, 0xAF, 0x0D, 0x81, 0x5D, 0x33, 0xC3, 0x3F, 0x19, 0x18, 0xFB, 0xCC, 0x62, 0x95, 0xFF, 0x71, 0x16, 0xD2, 0xC7, 0xFB, 0x2D, 0x8E, 0xB0, 0xF7, 0x2F, 0x73, 0x09, 0xB2, 0xCB, 0xBA, 0xEE, 0xD1, 0x1B, 0xFC, 0xDD, 0xEB, 0xE5, 0x33, 0x59, 0x8B, 0xD4, 0xBF, 0x10, 0x95, 0x7A, 0x06, 0xB2, 0x32, 0xAD, 0x79, 0xF2, 0x36, 0xC3, 0x78, 0xA7, 0xE4, 0xA9, 0x17, 0x62, 0xB7, 0x69, 0x93, 0x5E, 0xA8, 0xD1, 0xB3, 0xD5, 0xBF, 0x32, 0x00, 0x55, 0x86, 0xA4, 0xED, 0xD5, 0x97, 0xA6, 0x41, 0x25, 0xA3, 0x72, 0x06, 0x16, 0x69, 0x5A, 0x5C, 0x4A, 0xEA, 0xD4, 0xC1, 0xA7, 0x79, 0x29, 0x5B, 0xB2, 0xE9, 0x7E, 0xD6, 0xAB, 0x7E, 0xC3, 0xF7, 0xF6, 0x39, 0xDA, 0x3F, 0x64, 0x30, 0x74, 0x0F, 0xF6, 0x13, 0x15, 0x09, 0xDF, 0x0B, 0xCC, 0xF9, 0xAC, 0xC0, 0x07, 0x3C, 0xB4, 0x06, 0x0C, 0x69, 0xF0, 0x56, 0xDE, 0x0D, 0x21, 0x7B, 0xCB, 0x49, 0xF6, 0x4C, 0x16, 0x6D, 0x34, 0x7E, 0x21, 0xD9, 0xF9, 0x19, 0x73, 0x57, 0x9F, 0x22, 0x15, 0x43, 0xFC, 0xAC, 0xE8, 0x33, 0xA1, 0xED, 0x23, 0x30, 0x86, 0x8E, 0x36, 0xF5, 0x67, 0xFB, 0x38, 0xDC, 0x6C, 0xF5, 0xBB, 0x79, 0x57, 0x0D, 0x4B, 0x24, 0x7B, 0x88, 0xBD, 0x8C, 0x71, 0x31, 0x90, 0x5D, 0xFD, 0xCB, 0xD6, 0x6B, 0x85, 0x9B, 0x27, 0xBA, 0x35, 0xAA, 0x07, 0x16, 0x0A, 0xAB, 0xB3, 0xBC, 0x14, 0xA1, 0x1C, 0x98, 0x2A, 0xAB, 0x5B, 0x86, 0xA2, 0x2E, 0x3D, 0x38, 0xB7, 0x49, 0x2C, 0x47, 0xD6, 0x9F, 0x90, 0x0D, 0xEE, 0x2B, 0x50, 0xC8, 0xAD, 0x31, 0x48, 0x17, 0xA4, 0x46, 0x18, 0x60, 0xF6, 0x54, 0x46, 0x46, 0x5A, 0x7B, 0xA7, 0x7F, 0xC1, 0xBD, 0x63, 0x37, 0x9D, 0x25, 0x42, 0xEF, 0xBF, 0x1B, 0x7C, 0x04, 0x2D, 0xEB, 0x0A, 0x3D, 0x49, 0x17, 0x2A, 0x71, 0xFD, 0x8B, 0x2E, 0xD7, 0x20, 0xD7, 0x8C, 0x7D, 0x12, 0xCC, 0x6C, 0x96, 0x5E, 0x3A, 0x94, 0x18, 0xA9, 0x66, 0xFF, 0x47, 0x0E, 0xF3, 0x06, 0xFD, 0x7E, 0xBB, 0xC8, 0xAB, 0x5D, 0xC7, 0xE8, 0xC4, 0xA3, 0x4E, 0x86, 0xA0, 0xD2, 0x50, 0xE7, 0x1D, 0x81, 0x51, 0x39, 0x20, 0x5F, 0xA9, 0xED, 0x6A, 0x0F, 0xD5, 0xED, 0xC5, 0xB8, 0x23, 0xBA, 0x25, 0x8F, 0xFF, 0x29, 0xFC, 0x92, 0xE9, 0xF0, 0xC3, 0x1B, 0x62, 0x75, 0x0F, 0xF2, 0x4F, 0x23, 0xF5, 0x21, 0xB5, 0x68, 0x7F, 0xB1, 0xA8, 0x12, 0x42, 0x61, 0x8F, 0x6D, 0x49, 0x86, 0xE6, 0xD2, 0x68, 0x41, 0x58, 0x17, 0x4E, 0xB5, 0x5B, 0x79, 0x1D, 0x06, 0x84, 0x68, 0x3B, 0x1C, 0xF1, 0xC6, 0x46, 0x02, 0x90, 0x49, 0xD0, 0x54, 0xBD, 0xF0, 0xE4, 0xDF, 0xC1, 0x99, 0x15, 0x61, 0x55, 0x9A, 0x7D, 0xF9, 0x0C, 0x7E, 0x9A, 0x6D, 0x74, 0xA2, 0xD4, 0xAC, 0x57, 0x7E, 0x81, 0x68, 0x96, 0x66, 0x16, 0xC8, 0xCD, 0x7C, 0xF5, 0xB2, 0x13, 0xBF, 0x88, 0x3F, 0x73, 0x22, 0x47, 0xB3, 0x1F, 0x32, 0x71, 0x5A, 0xB1, 0xE8, 0x88, 0x82, 0x86, 0xDE, 0x1F, 0xD6, 0x77, 0xCB, 0x17, 0x35, 0xCF, 0x49, 0x00, 0x88, 0xD6, 0x11, 0x47, 0x3A, 0x50, 0x00, 0x83, 0xF3, 0x0B, 0x49, 0x75, 0x56, 0x7C, 0xEC, 0x62, 0xF2, 0x91, 0x94, 0xE4, 0x62, 0xB0, 0xCB, 0x02, 0xBD, 0x2D, 0x78, 0x1D, 0x89, 0xFE, 0xA1, 0x78, 0xB5, 0xD2, 0xAD, 0xC9, 0x38, 0x89, 0x2E, 0xD6, 0xD5, 0xDA, 0x52, 0x0F, 0x99, 0xEE, 0x7A, 0xEC, 0x94, 0x2A, 0x88, 0x0C, 0x5A, 0x09, 0xA8, 0x85, 0xC5, 0xCF, 0xE1, 0x45, 0xEB, 0xE0, 0x73, 0xF1, 0xF7, 0x7F, 0x9A, 0xD1, 0x13, 0x17, 0xE7, 0x21, 0x13, 0x61, 0x7C, 0x31, 0xA1, 0x43, 0xED, 0x0A, 0x5B, 0xEC, 0x8E, 0x3F, 0xE8, 0xD4, 0x46, 0x9C, 0xBF, 0x34, 0xD6, 0x46, 0x4D, 0x05, 0xAD, 0xA9, 0x2C, 0xE0, 0x49, 0xC1, 0xB4, 0xAD, 0x58, 0xCE, 0xAE, 0x96, 0x9B, 0x8D, 0x2C, 0x7D, 0xF9, 0x5F, 0xF1, 0xD4, 0xF2, 0x69, 0x19, 0xFA, 0x3F, 0x52, 0xC6, 0x8A, 0xC3, 0xAF, 0xA9, 0x5B, 0x88, 0x48, 0x17, 0xFA, 0x55, 0xF1, 0xA7, 0x5A, 0xE1, 0x7E, 0xA4, 0xD5, 0x6C, 0x58, 0xAE, 0xAC, 0x65, 0x35, 0xDD, 0xBD, 0x16, 0xE8, 0xD3, 0xC1, 0xE5, 0x5B, 0xE7, 0x93, 0x39, 0xEC, 0x10, 0x79, 0xB6, 0xB2, 0x3A, 0x27, 0x0C, 0xE0, 0x01, 0xC5, 0xDA, 0x89, 0xD9, 0xED, 0x33, 0x5E, 0xD9, 0x52, 0x78, 0xAD, 0xFA, 0x65, 0x15, 0x23, 0xD9, 0x36, 0xDC, 0x9E, 0x1C, 0x05, 0x2B, 0xB1, 0x51, 0x07, 0xCF, 0x77, 0x6F, 0xFE, 0xE6, 0x26, 0xED, 0x92, 0x30, 0x3D, 0xE8, 0xE5, 0xCA, 0x94, 0x26, 0x53, 0x31, 0x91, 0x43, 0xE2, 0x06, 0xC7, 0x1A, 0x04, 0x29, 0x4E, 0x61, 0x32, 0xC0, 0xA1, 0x31, 0x2C, 0x1A, 0xAD, 0x62, 0xC1, 0x7E, 0xCA, 0x5A, 0x58, 0xCB, 0xC4, 0xC2, 0x6B, 0x83, 0x44, 0x03, 0x19, 0xA5, 0x46, 0x74, 0xD1, 0x58, 0x4D, 0x4B, 0x52, 0x83, 0x38, 0x38, 0xEA, 0x71, 0xCC, 0xDF, 0x10, 0x66, 0x9A, 0x97, 0x31, 0x33, 0x81, 0x43, 0x7F, 0xC6, 0xCF, 0xDD, 0x34, 0x24, 0x09, 0x00, 0x68, 0x20, 0xFD, 0x95, 0xFE, 0xF1, 0xE4, 0x58, 0x74, 0xC3, 0x5D, 0xFB, 0x57, 0x51, 0x97, 0x75, 0xE9, 0xBB, 0x60, 0x20, 0x66, 0x9D, 0x74, 0x15, 0x9D, 0x3F, 0xBB, 0xBD, 0x1C, 0xB8, 0x98, 0xD7, 0xFF, 0xB0, 0xF4, 0xAC, 0x45, 0x25, 0xE1, 0x4E, 0x8A, 0x8D, 0xBF, 0x50, 0x03, 0x02, 0x19, 0x23, 0x61, 0x02, 0x92, 0x4E, 0xA3, 0x27, 0xA9, 0xA8, 0xA8, 0x73, 0x89, 0x88, 0x72, 0x57, 0xDC, 0x53, 0xC4, 0x31, 0x9C, 0xC8, 0x84, 0x35, 0x95, 0x4B, 0x3E, 0x7E, 0x63, 0x92, 0x55, 0x0A, 0x2B, 0xE1, 0x68, 0x56, 0xB2, 0xF0, 0x03, 0x11, 0x08, 0xDC, 0x83, 0x66, 0xE5, 0x39, 0xD5, 0xCE, 0x9C, 0x91, 0x55, 0x57, 0xA7, 0x28, 0x9E, 0x85, 0x2F, 0x07, 0x45, 0x45, 0xF7, 0xE8, 0x9A, 0x59, 0xD6, 0x62, 0xED, 0x97, 0xF5, 0x55, 0xEA, 0xB7, 0x1A, 0xED, 0x03, 0x76, 0x90, 0x26, 0x94, 0x3B, 0x5D, 0x23, 0xB1, 0x18, 0xB2, 0xC9, 0x72, 0x5C, 0xC5, 0x61, 0x60, 0xB2, 0xD6, 0x50, 0x8E, 0x85, 0x01, 0x73, 0x1B, 0xAA, 0x63, 0xD7, 0x42, 0x17, 0x2F, 0xCD, 0x07, 0x0F, 0x97, 0xFC, 0xAF, 0x7E, 0x57, 0xB3, 0x03, 0xBD, 0xD0, 0xC8, 0x95, 0x91, 0xFB, 0xE7, 0xF3, 0x3D, 0xBD, 0xB5, 0x0C, 0x76, 0x4E, 0xDC, 0x59, 0x53, 0xC0, 0x77, 0x73, 0xB1, 0xAD, 0x05, 0x6C, 0x32, 0x58, 0x22, 0xF8, 0x1A, 0x3E, 0xD6, 0x5E, 0xA1, 0xF2, 0xFB, 0xC4, 0xCF, 0xC8, 0xBF, 0xF4, 0xA5, 0xC9, 0xCB, 0x13, 0xE8, 0x98, 0xC1, 0xBE, 0x3D, 0x8F, 0xD2, 0xEC, 0x8E, 0xA9, 0x63, 0x8F, 0x33, 0x0D, 0x39, 0x65, 0xBE, 0xE1, 0x7E, 0x72, 0x8B, 0xB4, 0x3B, 0x26, 0xCD, 0xFD, 0x22, 0xD5, 0x06, 0x8C, 0x6A, 0xB3, 0xBB, 0x13, 0x2B, 0x5E, 0x06, 0xE1, 0xEF, 0xE1, 0x29, 0xE8, 0x36, 0x80, 0x3A, 0xFA, 0x45, 0xEB, 0x6D, 0x55, 0xEF, 0xE2, 0xD9, 0x35, 0xCE, 0xB9, 0x8A, 0x07, 0xBA, 0x24, 0xD7, 0x0F, 0x88, 0x8B, 0x69, 0x76, 0x34, 0x34, 0x7A, 0xDD, 0x69, 0x91, 0xD4, 0x09, 0x93, 0x16, 0x4A, 0x20, 0x4E, 0xA7, 0x28, 0x6A, 0xC0, 0x19, 0x76, 0x53, 0x52, 0xC8, 0x01, 0xE3, 0xE3, 0x9C, 0x79, 0xEC, 0x00, 0x28, 0x38, 0x54, 0xFE, 0x13, 0x30, 0x69, 0x38, 0xBD, 0xEE, 0x3E, 0x4A, 0x04, 0x00, 0xE8, 0xA7, 0x97, 0x2B, 0x98, 0xB1, 0xB9, 0x3C, 0x8E, 0x6C, 0xBE, 0x33, 0x5C, 0x2F, 0x6A, 0x1B, 0xCA, 0x92, 0xC9, 0xEF, 0x4D, 0xE9, 0xE1, 0x35, 0x99, 0x6B, 0x84, 0x3F, 0xA3, 0xF0, 0x41, 0x84, 0xA8, 0x71, 0x26, 0x8C, 0xB1, 0x72, 0xDA, 0xC6, 0xD5, 0x4F, 0xEA, 0x1A, 0x63, 0x1D, 0x54, 0x71, 0x5B, 0xB6, 0x20, 0x7D, 0xB5, 0x9D, 0x5B, 0x4E, 0xF3, 0xFB, 0x95, 0x42, 0x6D, 0xA2, 0x29, 0x72, 0xF3, 0x5A, 0xF3, 0x3F, 0x62, 0xDD, 0xC1, 0x78, 0xDC, 0xA9, 0x59, 0x54, 0x22, 0x00, 0x7D, 0x32, 0xD8, 0x04, 0xCD, 0xEC, 0x6A, 0xE1, 0xC6, 0x64, 0x48, 0x90, 0x9D, 0x57, 0x4B, 0xE1, 0x8B, 0x05, 0xA8, 0x07, 0x06, 0xF4, 0x17, 0xB3, 0xC0, 0xF4, 0x5E, 0x16, 0x75, 0x1A, 0xCB, 0x45, 0xBB, 0xE0, 0x05, 0xC1, 0x1F, 0xD7, 0x73, 0x3D, 0xA3, 0xFC, 0xD5, 0x44, 0xB7, 0x57, 0xAA, 0x3F, 0x36, 0x08, 0x14, 0xE8, 0x55, 0x44, 0xE2, 0x9D, 0x09, 0x7E, 0x64, 0x33, 0xDC, 0x5C, 0xE2, 0x56, 0x1C, 0x6C, 0x51, 0x89, 0x8F, 0x24, 0x1C, 0xA6, 0x21, 0x08, 0xD8, 0x0A, 0x82, 0x9D, 0x66, 0xFB, 0x1E, 0xE7, 0x4E, 0xB8, 0x93, 0xD0, 0x92, 0x2C, 0x06, 0xBA, 0x5B, 0x87, 0xE0, 0x44, 0xBD, 0xFA, 0xA2, 0xE8, 0x41, 0xDB, 0x1F, 0xBE, 0x97, 0xF7, 0x66, 0x2A, 0x80, 0xE7, 0x95, 0x57, 0x95, 0x5D, 0xF1, 0x85, 0x54, 0xA3, 0x27, 0xB5, 0xFE, 0x2D, 0x28, 0x25, 0xA9, 0x89, 0x87, 0xB8, 0x78, 0x8F, 0x11, 0x5E, 0x0E, 0xE4, 0xD8, 0x30, 0x57, 0x07, 0x33, 0x71, 0x9B, 0xED, 0x51, 0xA3, 0xD6, 0x92, }, .pub_len = 1952, }, { .name = "ML-DSA 87 (priv only)", .parameter_set = CKP_ML_DSA_87, .priv = { 0xCA, 0xDE, 0xD2, 0x24, 0xB8, 0xF0, 0xB4, 0xCE, 0x30, 0x19, 0x85, 0x30, 0x5F, 0x5E, 0xCF, 0xF5, 0x03, 0xDD, 0x4E, 0xCC, 0xF0, 0x69, 0xB9, 0xAB, 0x3C, 0xFA, 0x07, 0x4E, 0x89, 0x22, 0x41, 0xBB, 0x19, 0xC2, 0x85, 0xFD, 0xDC, 0xA7, 0xBE, 0x6F, 0xE7, 0xF2, 0xBF, 0xF3, 0xDB, 0x3E, 0xE7, 0x0F, 0x23, 0xC8, 0x7B, 0xA1, 0x4D, 0x20, 0x56, 0xC7, 0xC2, 0x41, 0x59, 0xC4, 0xA7, 0xC4, 0x5A, 0x50, 0x96, 0x62, 0x41, 0xFB, 0xBE, 0x3B, 0xF0, 0x79, 0x8A, 0x33, 0x91, 0x3C, 0x37, 0x08, 0x20, 0x25, 0x72, 0xE8, 0xAE, 0x51, 0x2A, 0xB5, 0xC9, 0x0D, 0xAC, 0xC8, 0x72, 0xAC, 0x0B, 0x08, 0x44, 0x20, 0x21, 0xE2, 0x8C, 0x4D, 0x03, 0x7A, 0x73, 0xA5, 0x1D, 0x48, 0xA4, 0xBB, 0xBC, 0x03, 0x3F, 0x9C, 0x4B, 0xF7, 0x3B, 0x48, 0xF8, 0x36, 0x0B, 0x29, 0xA8, 0xBF, 0x78, 0x58, 0xE8, 0x4D, 0x8B, 0x3C, 0x20, 0xB4, 0x09, 0x54, 0x14, 0x8E, 0x0A, 0x48, 0x8E, 0x1C, 0xB9, 0x6C, 0x12, 0xA8, 0x2C, 0x20, 0x09, 0x30, 0xCA, 0x98, 0x0C, 0x63, 0x80, 0x64, 0xE4, 0x20, 0x4C, 0x01, 0x03, 0x89, 0x1C, 0x04, 0x0C, 0xDC, 0x14, 0x50, 0x0B, 0x49, 0x09, 0xD3, 0x32, 0x6E, 0x9B, 0x18, 0x64, 0x4C, 0x44, 0x05, 0x13, 0xA5, 0x28, 0x18, 0x92, 0x90, 0x51, 0x90, 0x51, 0xC2, 0x16, 0x88, 0x42, 0x44, 0x01, 0x51, 0x10, 0x42, 0x23, 0xA6, 0x44, 0xA2, 0x18, 0x44, 0x8B, 0xB4, 0x88, 0x23, 0x44, 0x46, 0xCB, 0x10, 0x85, 0x5B, 0x18, 0x05, 0x13, 0x27, 0x4E, 0xC4, 0x98, 0x28, 0x11, 0x17, 0x42, 0x90, 0x24, 0x70, 0x0B, 0x11, 0x42, 0x8C, 0x40, 0x6A, 0x08, 0x08, 0x4A, 0x8B, 0x14, 0x66, 0xDB, 0x16, 0x50, 0x99, 0xB8, 0x0C, 0x58, 0x30, 0x0D, 0xC1, 0x12, 0x2D, 0x04, 0x19, 0x6C, 0x9A, 0x18, 0x21, 0xC3, 0x46, 0x86, 0xC0, 0x46, 0x85, 0x22, 0x05, 0x4C, 0xC8, 0x40, 0x85, 0x43, 0xA6, 0x60, 0xE4, 0x24, 0x4A, 0xC1, 0x00, 0x02, 0x02, 0x08, 0x61, 0x04, 0x20, 0x41, 0x12, 0x91, 0x80, 0x03, 0x80, 0x4C, 0xDA, 0xA0, 0x4C, 0x40, 0x46, 0x02, 0x5C, 0x08, 0x40, 0x44, 0x30, 0x4D, 0x21, 0xC1, 0x28, 0x83, 0xA2, 0x11, 0x13, 0x49, 0x6E, 0x19, 0x80, 0x49, 0x64, 0x48, 0x4E, 0x4B, 0x34, 0x4C, 0x52, 0x98, 0x4C, 0xC2, 0x48, 0x26, 0x09, 0xA8, 0x4C, 0xA4, 0x16, 0x26, 0x22, 0x00, 0x66, 0x0A, 0x19, 0x05, 0x14, 0xC6, 0x09, 0xA0, 0x90, 0x49, 0x53, 0x08, 0x82, 0x94, 0x44, 0x44, 0x80, 0x44, 0x88, 0x91, 0x14, 0x6D, 0x82, 0x96, 0x81, 0x0C, 0x49, 0x21, 0x19, 0xB0, 0x49, 0x00, 0x15, 0x52, 0x92, 0xC8, 0x4D, 0x09, 0x08, 0x89, 0xA2, 0x94, 0x48, 0xE0, 0x08, 0x2C, 0x60, 0x42, 0x70, 0x1B, 0x24, 0x6E, 0xA4, 0x24, 0x31, 0x1B, 0x00, 0x2E, 0xD9, 0xA2, 0x00, 0xC0, 0x24, 0x60, 0x8A, 0xC6, 0x09, 0xCC, 0x42, 0x8A, 0xC3, 0x84, 0x09, 0x12, 0x00, 0x6E, 0x49, 0x86, 0x31, 0x0A, 0xC6, 0x00, 0x82, 0x28, 0x08, 0xA3, 0xB8, 0x44, 0x8C, 0x14, 0x2A, 0x10, 0x30, 0x8C, 0x93, 0x16, 0x6E, 0xE2, 0x96, 0x41, 0x08, 0x31, 0x02, 0xD8, 0xC2, 0x28, 0x41, 0x20, 0x20, 0x22, 0x48, 0x0C, 0x1B, 0x89, 0x31, 0x4B, 0xC4, 0x64, 0x20, 0x09, 0x32, 0x14, 0x91, 0x85, 0xD2, 0x00, 0x0C, 0x0C, 0x93, 0x48, 0xD0, 0xB0, 0x2D, 0x93, 0x24, 0x69, 0xE0, 0x96, 0x2C, 0x18, 0xC3, 0x51, 0xD1, 0x38, 0x44, 0x9B, 0x36, 0x01, 0xDA, 0x16, 0x64, 0x10, 0xC4, 0x48, 0x9B, 0xC0, 0x30, 0x91, 0x08, 0x69, 0xDA, 0x28, 0x0C, 0xD8, 0x42, 0x49, 0x90, 0x02, 0x40, 0xC2, 0x02, 0x12, 0x08, 0x40, 0x81, 0xA4, 0xA6, 0x50, 0x60, 0x20, 0x41, 0x83, 0x82, 0x71, 0x22, 0x06, 0x09, 0x51, 0x44, 0x41, 0x08, 0x07, 0x44, 0xC4, 0xC6, 0x30, 0xA2, 0x42, 0x86, 0x12, 0x18, 0x44, 0x82, 0xA6, 0x49, 0x20, 0x23, 0x84, 0x0B, 0x41, 0x20, 0x11, 0x31, 0x89, 0x24, 0xB3, 0x40, 0xC4, 0x04, 0x8A, 0xC4, 0x26, 0x52, 0xA2, 0x28, 0x71, 0x51, 0x44, 0x12, 0xD2, 0xA0, 0x04, 0x0B, 0x97, 0x70, 0x84, 0xC6, 0x6C, 0xC2, 0xA2, 0x08, 0xD4, 0x08, 0x44, 0x0A, 0x32, 0x66, 0x4C, 0x46, 0x68, 0xA1, 0x34, 0x02, 0x49, 0x06, 0x91, 0x48, 0x10, 0x4D, 0x51, 0xC2, 0x68, 0x82, 0xC0, 0x88, 0x48, 0x00, 0x49, 0x0A, 0x42, 0x45, 0x19, 0x31, 0x25, 0x04, 0x16, 0x48, 0x13, 0x05, 0x84, 0x92, 0x26, 0x11, 0x44, 0x12, 0x68, 0x01, 0xA7, 0x69, 0x03, 0x43, 0x26, 0x54, 0x06, 0x6C, 0xD8, 0x12, 0x11, 0x01, 0x83, 0x8C, 0x08, 0x39, 0x2D, 0x94, 0xC6, 0x48, 0x80, 0x06, 0x50, 0x52, 0x08, 0x85, 0xE4, 0x92, 0x65, 0x60, 0xA0, 0x81, 0x0C, 0xB7, 0x81, 0x63, 0x10, 0x8E, 0x13, 0x14, 0x44, 0x12, 0x89, 0x09, 0x9B, 0x40, 0x72, 0xD3, 0x28, 0x09, 0x21, 0x01, 0x6C, 0xD0, 0xA0, 0x49, 0x21, 0x10, 0x6E, 0xE4, 0x14, 0x06, 0x00, 0x39, 0x8A, 0x20, 0xC9, 0x09, 0x5A, 0x86, 0x81, 0x1A, 0x48, 0x28, 0x51, 0x96, 0x89, 0x82, 0x96, 0x71, 0x14, 0x88, 0x89, 0xC4, 0x38, 0x09, 0x00, 0x29, 0x6D, 0xE4, 0x22, 0x01, 0xDA, 0x28, 0x8A, 0x01, 0x15, 0x20, 0x0A, 0x32, 0x8D, 0xE4, 0x46, 0x6D, 0x50, 0x48, 0x26, 0xA0, 0xA0, 0x00, 0x4A, 0x42, 0x12, 0xE2, 0x18, 0x00, 0x63, 0x02, 0x61, 0x18, 0x44, 0x92, 0x02, 0x90, 0x29, 0x81, 0xB4, 0x44, 0x1C, 0x09, 0x8D, 0x60, 0x48, 0x85, 0x59, 0x00, 0x4E, 0xD0, 0x38, 0x66, 0x40, 0x96, 0x61, 0x18, 0x34, 0x81, 0x80, 0x94, 0x00, 0x90, 0x06, 0x0C, 0xD4, 0x32, 0x82, 0x49, 0x20, 0x8E, 0x13, 0xC7, 0x80, 0x0C, 0x16, 0x10, 0x1C, 0x03, 0x42, 0x0C, 0xC8, 0x31, 0xC0, 0x38, 0x0C, 0xCC, 0x98, 0x6D, 0x42, 0x02, 0x29, 0x91, 0x42, 0x65, 0x4A, 0x34, 0x30, 0x4A, 0x98, 0x4D, 0x8C, 0x26, 0x26, 0x19, 0x46, 0x31, 0x82, 0x92, 0x4C, 0x21, 0x41, 0x8D, 0x03, 0x37, 0x66, 0x23, 0x02, 0x21, 0x08, 0x35, 0x61, 0xA0, 0x02, 0x26, 0xCB, 0x88, 0x68, 0x90, 0x44, 0x81, 0x49, 0x96, 0x6C, 0xDA, 0xB0, 0x65, 0x24, 0xB8, 0x6C, 0x1C, 0xA1, 0x6D, 0xDA, 0x80, 0x29, 0xD9, 0xB2, 0x90, 0x09, 0xA3, 0x69, 0x52, 0xA0, 0x30, 0x02, 0x93, 0x28, 0x1C, 0x09, 0x84, 0x0C, 0xA4, 0x90, 0xC3, 0x82, 0x88, 0x24, 0x95, 0x68, 0xA4, 0x20, 0x68, 0x88, 0x98, 0x44, 0x0B, 0x95, 0x61, 0xC8, 0xA6, 0x68, 0x08, 0x07, 0x06, 0x23, 0xC4, 0x91, 0xE4, 0x38, 0x72, 0x10, 0x09, 0x40, 0x98, 0x92, 0x81, 0xA4, 0xB6, 0x4D, 0x1C, 0x11, 0x6C, 0x4C, 0x40, 0x2E, 0xDC, 0x18, 0x48, 0xA2, 0xC8, 0x44, 0xD9, 0x00, 0x00, 0x01, 0x44, 0x2C, 0x02, 0x04, 0x81, 0x49, 0xC0, 0x50, 0xE3, 0x46, 0x48, 0x49, 0x88, 0x40, 0x03, 0xB8, 0x85, 0x22, 0x03, 0x28, 0x9C, 0x12, 0x72, 0xE3, 0xA2, 0x10, 0x50, 0x94, 0x69, 0x1A, 0x20, 0x8E, 0x00, 0xA1, 0x05, 0xD1, 0x86, 0x11, 0x94, 0x04, 0x05, 0xA4, 0x26, 0x2C, 0x4B, 0x84, 0x44, 0xD3, 0xA2, 0x10, 0x98, 0x20, 0x65, 0x03, 0x19, 0x64, 0x58, 0xC8, 0x70, 0xA3, 0xB2, 0x68, 0x22, 0x38, 0x51, 0x8B, 0x80, 0x89, 0x18, 0xA6, 0x40, 0x4C, 0x90, 0x20, 0xC2, 0x18, 0x31, 0xC8, 0x12, 0x08, 0xD8, 0x44, 0x52, 0x1A, 0x01, 0x40, 0xC2, 0x06, 0x90, 0x12, 0x06, 0x22, 0x21, 0xC2, 0x40, 0x51, 0x84, 0x04, 0x94, 0xB4, 0x24, 0x89, 0x48, 0x91, 0xC2, 0xC6, 0x44, 0x04, 0x99, 0x6C, 0x09, 0x25, 0x09, 0x0B, 0x23, 0x92, 0x60, 0xC0, 0x4C, 0x12, 0x13, 0x8E, 0x64, 0xC2, 0x81, 0xD1, 0x38, 0x01, 0xC8, 0x10, 0x6C, 0x94, 0x00, 0x06, 0x1A, 0x94, 0x8C, 0x4C, 0x18, 0x40, 0x63, 0xB0, 0x29, 0x0C, 0x40, 0x68, 0x02, 0x15, 0x6A, 0x42, 0x42, 0x0C, 0x01, 0xC4, 0x71, 0x8C, 0x26, 0x21, 0xD0, 0x38, 0x2C, 0x44, 0x42, 0x6A, 0x14, 0xC0, 0x48, 0x0A, 0xA6, 0x80, 0x1A, 0x36, 0x4D, 0x9A, 0x48, 0x8A, 0x21, 0x03, 0x08, 0x8A, 0x20, 0x84, 0x98, 0x28, 0x86, 0xE0, 0x98, 0x25, 0x21, 0xB4, 0x2D, 0x80, 0x02, 0x10, 0x14, 0xA3, 0x00, 0x8A, 0x06, 0x64, 0xD9, 0xB0, 0x25, 0xCB, 0x06, 0x41, 0x23, 0x88, 0x2D, 0x24, 0xB4, 0x50, 0xC8, 0xB4, 0x25, 0x20, 0x04, 0x70, 0x90, 0x30, 0x6C, 0x41, 0x28, 0x2E, 0x5A, 0x30, 0x8D, 0x23, 0x03, 0x32, 0x02, 0x49, 0x80, 0xC1, 0x00, 0x52, 0x80, 0xC2, 0x49, 0x82, 0xA8, 0x21, 0xD9, 0x14, 0x04, 0x08, 0x01, 0x82, 0x0C, 0x96, 0x8C, 0x51, 0xA4, 0x85, 0x00, 0x06, 0x20, 0xCA, 0x48, 0x85, 0x02, 0xB2, 0x69, 0x23, 0x00, 0x8D, 0xC8, 0xB0, 0x28, 0x14, 0x87, 0x61, 0x50, 0x14, 0x82, 0xE3, 0x34, 0x4D, 0xD4, 0x80, 0x0C, 0x8B, 0x98, 0x05, 0x53, 0xA6, 0x4D, 0x02, 0x48, 0x86, 0x0B, 0x85, 0x81, 0x08, 0xA6, 0x51, 0xD4, 0x98, 0x84, 0x1C, 0xC7, 0x71, 0x98, 0x96, 0x89, 0x51, 0x36, 0x65, 0x0B, 0x49, 0x71, 0x48, 0x32, 0x88, 0x60, 0x10, 0x12, 0xE4, 0x20, 0x62, 0x5C, 0x28, 0x26, 0x44, 0x00, 0x2A, 0xCC, 0x90, 0x81, 0x50, 0x90, 0x65, 0x09, 0xC8, 0x65, 0x43, 0x98, 0x81, 0xCC, 0x90, 0x24, 0x0B, 0x98, 0x85, 0x9B, 0x02, 0x2C, 0x02, 0x32, 0x66, 0x89, 0x12, 0x6D, 0x0C, 0x31, 0x49, 0x24, 0x28, 0x81, 0x5B, 0xC0, 0x89, 0x18, 0x16, 0x52, 0xA2, 0x88, 0x6C, 0xA1, 0x04, 0x04, 0x22, 0x88, 0x29, 0x5B, 0x40, 0x41, 0x19, 0xB7, 0x71, 0x00, 0x45, 0x89, 0x00, 0xA8, 0x51, 0x14, 0xB5, 0x65, 0xC2, 0xB6, 0x05, 0x88, 0x30, 0x70, 0x99, 0x26, 0x0A, 0x12, 0x11, 0x44, 0x09, 0x19, 0x2C, 0x4A, 0x30, 0x10, 0x44, 0x10, 0x86, 0xCC, 0xC2, 0x08, 0xCB, 0x24, 0x25, 0xCB, 0x20, 0x48, 0x10, 0xA5, 0x01, 0x52, 0x34, 0x84, 0x11, 0x95, 0x64, 0x63, 0x90, 0x80, 0xD3, 0x86, 0x40, 0xA0, 0x26, 0x64, 0xE1, 0xA4, 0x61, 0x10, 0x24, 0x69, 0x84, 0x48, 0x8C, 0x11, 0xC2, 0x45, 0x9C, 0x14, 0x85, 0xCC, 0xA4, 0x44, 0xC4, 0x10, 0x4C, 0x1B, 0x95, 0x8C, 0x12, 0x34, 0x44, 0x14, 0xC1, 0x30, 0xE4, 0x90, 0x91, 0x89, 0xA0, 0x69, 0xD0, 0x06, 0x45, 0x11, 0x43, 0x52, 0xD8, 0x84, 0x60, 0x8C, 0x16, 0x61, 0xA0, 0x40, 0x8E, 0x41, 0xB0, 0x30, 0x19, 0x98, 0x60, 0x18, 0x28, 0x8C, 0x4B, 0x94, 0x4C, 0xE3, 0x06, 0x0A, 0x20, 0x23, 0x42, 0xD4, 0xC2, 0x29, 0x53, 0xB6, 0x41, 0x60, 0x32, 0x28, 0x91, 0x40, 0x26, 0x0B, 0x14, 0x90, 0x11, 0xB4, 0x00, 0x09, 0xB8, 0x08, 0xDA, 0x14, 0x80, 0x01, 0xB0, 0x05, 0x51, 0x36, 0x25, 0xA0, 0x16, 0x06, 0x13, 0x26, 0x68, 0xDB, 0x94, 0x69, 0x5B, 0x44, 0x8E, 0xA0, 0x22, 0x65, 0x13, 0x28, 0x86, 0x02, 0xC5, 0x25, 0x23, 0x01, 0x01, 0x21, 0x27, 0x01, 0xE3, 0x80, 0x04, 0x54, 0xB6, 0x10, 0x49, 0x86, 0x01, 0xA0, 0xB6, 0x30, 0x01, 0x87, 0x44, 0x01, 0x26, 0x85, 0x8C, 0x84, 0x8D, 0x84, 0xC4, 0x21, 0x0C, 0x96, 0x4D, 0x20, 0xA2, 0x01, 0xDC, 0xB8, 0x69, 0xC9, 0x42, 0x42, 0x0C, 0x39, 0x50, 0xC3, 0xC6, 0x80, 0xC1, 0x18, 0x32, 0xA1, 0x24, 0x85, 0x84, 0x04, 0x00, 0x42, 0xC2, 0x6C, 0x13, 0x09, 0x80, 0x0A, 0x26, 0x68, 0xA0, 0xA0, 0x29, 0x09, 0x41, 0x05, 0xE3, 0x20, 0x01, 0x41, 0xA8, 0x24, 0xE4, 0x00, 0x85, 0x14, 0x46, 0x26, 0xA4, 0x18, 0x0E, 0x13, 0x02, 0x60, 0x55, 0x17, 0x75, 0xAA, 0xB0, 0x7E, 0x59, 0x33, 0xEA, 0xD1, 0x2A, 0x55, 0xDD, 0xC7, 0x2C, 0x48, 0xA2, 0x1F, 0x4A, 0x70, 0xE9, 0x3C, 0xD3, 0x26, 0x51, 0xB2, 0x26, 0x24, 0x0A, 0x03, 0xB1, 0x67, 0x13, 0x19, 0x74, 0x55, 0x1A, 0xB0, 0x72, 0x48, 0xE8, 0x95, 0x37, 0xFE, 0xEE, 0xFF, 0x77, 0x19, 0xF9, 0x7B, 0x90, 0x2D, 0x46, 0x88, 0x23, 0x75, 0xB6, 0x6A, 0x4A, 0x85, 0xA5, 0x98, 0x36, 0x40, 0x04, 0x67, 0x3B, 0xDE, 0x25, 0xB4, 0x05, 0x56, 0x60, 0x33, 0x58, 0xC0, 0xBB, 0xF7, 0xE0, 0x29, 0x71, 0x63, 0x62, 0x8D, 0x25, 0x3C, 0x93, 0x81, 0xDA, 0x69, 0xEF, 0xFE, 0xE9, 0xFA, 0x42, 0x5F, 0x47, 0xAE, 0xF3, 0xBC, 0xA4, 0xC4, 0xCB, 0x6D, 0xE2, 0xF5, 0xB9, 0x33, 0x06, 0xC4, 0xF6, 0x0A, 0xD8, 0x99, 0x87, 0x08, 0xAA, 0x06, 0x97, 0x5C, 0x30, 0xDF, 0xB6, 0x64, 0xB0, 0x23, 0xF7, 0x27, 0x05, 0x1E, 0xC4, 0xD9, 0xE7, 0xD7, 0x0C, 0xA7, 0x4E, 0xD3, 0x4E, 0x98, 0xAE, 0x46, 0xE2, 0xD0, 0x04, 0xF1, 0x99, 0xB5, 0x3E, 0xF0, 0xE2, 0x3E, 0xC4, 0x1C, 0xE0, 0xAF, 0x6E, 0x5F, 0x43, 0x9E, 0xB5, 0x0A, 0xB7, 0x64, 0x83, 0x57, 0x0F, 0xCF, 0x5F, 0x5B, 0xD1, 0x58, 0x9C, 0x55, 0xFD, 0x9A, 0xCE, 0x8A, 0x4B, 0x3E, 0x11, 0x77, 0xE1, 0xAD, 0x5E, 0xDB, 0x4A, 0x38, 0x27, 0x54, 0x01, 0x16, 0x32, 0x61, 0x0C, 0x4A, 0x26, 0xD0, 0x07, 0x42, 0xD5, 0xBF, 0xD4, 0xFB, 0xDA, 0x50, 0x7B, 0x9C, 0x51, 0x69, 0x7A, 0x92, 0x40, 0x65, 0xE7, 0x39, 0x97, 0x88, 0x96, 0x6C, 0x39, 0xCA, 0x51, 0xFD, 0xF7, 0x46, 0x28, 0xE9, 0xB4, 0x85, 0x35, 0xF9, 0xC5, 0x2F, 0x75, 0xC4, 0x33, 0x68, 0x3B, 0xB5, 0x37, 0x0D, 0x9E, 0xE5, 0x9B, 0x20, 0x49, 0x13, 0xE7, 0x10, 0xE2, 0xF8, 0x33, 0x5A, 0xF7, 0x4D, 0x30, 0x66, 0xA7, 0x1B, 0xDF, 0xC6, 0x12, 0x46, 0xE2, 0xD7, 0xA2, 0x6E, 0x32, 0x7A, 0x71, 0x48, 0x27, 0x9A, 0x64, 0xC5, 0x14, 0x78, 0x2C, 0x3E, 0xEA, 0x9F, 0x5B, 0xAC, 0xBE, 0xCF, 0x30, 0x95, 0x79, 0x74, 0x9E, 0x1D, 0xC8, 0x05, 0x6F, 0x78, 0x3F, 0x77, 0xAE, 0x43, 0x6A, 0xA3, 0xAB, 0x0A, 0xAB, 0x50, 0x77, 0xB5, 0xE3, 0x2F, 0xE7, 0xA4, 0xCC, 0xD7, 0x30, 0xC3, 0x6A, 0x3B, 0x93, 0x85, 0xBC, 0xE9, 0x98, 0x94, 0xE4, 0xAF, 0x87, 0x4F, 0xF4, 0x27, 0xE6, 0xD4, 0x6A, 0x81, 0x43, 0x85, 0xF8, 0x62, 0x39, 0xA2, 0x0A, 0x3F, 0x88, 0x27, 0xF8, 0xAB, 0x91, 0xD3, 0x96, 0xA5, 0x3B, 0x9D, 0x6A, 0x15, 0x05, 0x3E, 0x4E, 0x1D, 0x41, 0x4B, 0x57, 0xBD, 0x6E, 0xF3, 0xBE, 0xD9, 0x7B, 0x3F, 0xAA, 0xC7, 0x2A, 0x4A, 0x8B, 0xAD, 0x9E, 0x0E, 0x81, 0x90, 0x18, 0xE6, 0x1D, 0x63, 0xA2, 0xA2, 0x93, 0x57, 0x38, 0xE3, 0x43, 0x05, 0xD0, 0xAA, 0x07, 0x30, 0x8A, 0xB4, 0x66, 0x78, 0xA1, 0x91, 0xE6, 0xFD, 0x27, 0x1D, 0x1C, 0x9E, 0x11, 0x5C, 0x63, 0x91, 0x27, 0xAF, 0x5D, 0x0F, 0x1E, 0x06, 0x7A, 0x04, 0x0B, 0xC9, 0xE6, 0x44, 0x4B, 0x05, 0xD9, 0x5D, 0xB5, 0xAB, 0x1D, 0x16, 0xE1, 0x42, 0x0B, 0xAC, 0xF2, 0x4C, 0x05, 0xA9, 0x43, 0xF5, 0x52, 0x19, 0x19, 0xF2, 0xDD, 0x22, 0x14, 0x10, 0xAB, 0x3B, 0xE6, 0xD9, 0x92, 0x35, 0xAF, 0xC8, 0x01, 0x9C, 0x1C, 0x07, 0x49, 0x41, 0x8F, 0x0B, 0x8E, 0x42, 0x3C, 0xF8, 0xE8, 0x02, 0xA1, 0x1B, 0x21, 0x69, 0xEE, 0x10, 0xA6, 0x73, 0x47, 0x30, 0x09, 0x1F, 0xE9, 0x31, 0x88, 0xCC, 0x7A, 0x50, 0x16, 0xAD, 0x69, 0xCC, 0xA6, 0x4E, 0x87, 0x71, 0x69, 0xFA, 0xBB, 0xBC, 0x73, 0xA2, 0x3A, 0x67, 0x85, 0xA0, 0x71, 0x38, 0x1D, 0x8D, 0x7B, 0x1B, 0x92, 0xC3, 0xF7, 0xDD, 0x17, 0x3A, 0x1D, 0x4B, 0x1A, 0x2E, 0xF9, 0xF8, 0xBA, 0x53, 0xE0, 0x0C, 0x9A, 0x40, 0x6E, 0x15, 0xB6, 0x5C, 0xEB, 0x3A, 0xDF, 0xDC, 0xA3, 0xD2, 0x96, 0xE4, 0x48, 0xC5, 0xB3, 0x22, 0xF2, 0x45, 0xDA, 0x6F, 0x94, 0x68, 0x5B, 0x18, 0x76, 0xD6, 0x92, 0xDC, 0xB7, 0x9E, 0x2F, 0xF9, 0x12, 0x0E, 0x11, 0x82, 0xBD, 0xDF, 0xBD, 0xA7, 0xEA, 0xD5, 0xA2, 0xCA, 0x9E, 0xD5, 0xB7, 0x3A, 0x60, 0xEA, 0x05, 0x4D, 0x43, 0x1B, 0x30, 0x42, 0x6D, 0x99, 0x32, 0xF2, 0x16, 0x98, 0x48, 0xB9, 0xF5, 0xA9, 0x32, 0xF0, 0xA2, 0x89, 0x5D, 0x6C, 0x87, 0x8C, 0x01, 0x5F, 0xD3, 0xF5, 0x37, 0x25, 0x45, 0x0F, 0xE0, 0x2B, 0xE2, 0x81, 0x5F, 0x99, 0x35, 0x4B, 0xFB, 0x36, 0x2A, 0xCC, 0x5F, 0x83, 0xF7, 0x36, 0x1A, 0xD5, 0x13, 0x1B, 0xD5, 0xB0, 0x4C, 0xDA, 0xEE, 0xB7, 0xA8, 0x8B, 0xE7, 0x4C, 0xDF, 0x64, 0x75, 0x8C, 0x8E, 0xF5, 0x8B, 0xC3, 0xB7, 0x50, 0xEB, 0xEF, 0xF0, 0xAD, 0x4F, 0xAF, 0xF4, 0x80, 0x5A, 0x00, 0x80, 0x50, 0x13, 0xEB, 0x96, 0x49, 0xE9, 0xAF, 0xEB, 0x68, 0xA3, 0x7E, 0x2F, 0x87, 0xC5, 0x3F, 0xAD, 0x67, 0x6B, 0x7B, 0x53, 0xFE, 0x64, 0xD4, 0x4D, 0x9D, 0xB5, 0xF2, 0xB8, 0xE9, 0x30, 0x13, 0x22, 0xBB, 0xFF, 0x2F, 0xD5, 0x64, 0xC3, 0xBA, 0xF7, 0x0B, 0x09, 0x0A, 0xC4, 0x32, 0x9C, 0x14, 0xD5, 0x93, 0xAC, 0xC6, 0x95, 0xCD, 0x5D, 0x4B, 0x3A, 0xC0, 0x53, 0xB2, 0x94, 0xAA, 0xB1, 0x52, 0x8A, 0x9C, 0x07, 0xA0, 0x63, 0x2E, 0xB4, 0xE1, 0x83, 0x73, 0x00, 0x5C, 0x8B, 0x23, 0x4C, 0x14, 0x2F, 0xB6, 0x9B, 0xC8, 0x8D, 0x58, 0xF6, 0xDC, 0xEC, 0xDA, 0xB1, 0x4B, 0x6E, 0x2D, 0xAC, 0x5D, 0xD7, 0x76, 0xA3, 0xEC, 0x26, 0xA9, 0x3A, 0x71, 0x04, 0x80, 0xE4, 0x25, 0xEF, 0xD9, 0x7F, 0x13, 0xDB, 0x14, 0x82, 0x2C, 0x7A, 0x66, 0x36, 0x06, 0x63, 0xE2, 0x39, 0x9A, 0x64, 0x34, 0x68, 0x85, 0xD4, 0x79, 0xE7, 0x4C, 0xB2, 0xCB, 0x29, 0x51, 0x47, 0x68, 0x2B, 0xB5, 0x5C, 0x99, 0x92, 0x16, 0x0A, 0xC8, 0x4D, 0x9C, 0xDA, 0x72, 0xE8, 0x37, 0xA1, 0x53, 0x27, 0xD3, 0x9A, 0xB3, 0x5D, 0xC4, 0x57, 0x66, 0x0A, 0x6C, 0xCD, 0x02, 0x2B, 0xDC, 0xBA, 0xB4, 0x63, 0x55, 0x83, 0x81, 0xB4, 0x0B, 0xDF, 0x2A, 0x5D, 0x6F, 0x98, 0x61, 0x9B, 0xC7, 0xF6, 0x69, 0x2F, 0xDF, 0x42, 0xF1, 0x8F, 0x16, 0x5D, 0x89, 0x75, 0xF8, 0xD3, 0x18, 0xD5, 0x7F, 0x6A, 0x90, 0x21, 0xA8, 0xD5, 0x40, 0xE8, 0xE2, 0xA0, 0x56, 0x7A, 0xBA, 0x15, 0x4E, 0x8A, 0xC4, 0x6D, 0x54, 0xB0, 0x40, 0x5F, 0xB7, 0x71, 0x34, 0x75, 0x32, 0x39, 0xFF, 0x50, 0x10, 0xFE, 0x25, 0xFF, 0x77, 0x6F, 0x4C, 0x29, 0x8A, 0xB3, 0xDB, 0x71, 0xF2, 0xD1, 0xA4, 0xAA, 0x2B, 0x53, 0xAB, 0xA1, 0x58, 0x8D, 0x41, 0x34, 0x9D, 0x36, 0xAB, 0xA7, 0x13, 0xD0, 0x4A, 0xAE, 0x2F, 0x52, 0x1E, 0xEC, 0x78, 0xAC, 0xC6, 0x8A, 0x20, 0x58, 0xD4, 0x0C, 0xFE, 0xF4, 0x50, 0x95, 0x63, 0xF4, 0x73, 0x3D, 0xC5, 0xFE, 0x5D, 0xF4, 0xF4, 0xB7, 0x3A, 0x50, 0x1A, 0xFA, 0x09, 0x92, 0x82, 0xEA, 0xE9, 0x1F, 0x04, 0xE8, 0xEE, 0xD2, 0x23, 0xCA, 0x2D, 0x3A, 0x8A, 0xD1, 0xA2, 0xD0, 0xE0, 0x9B, 0x3C, 0xCD, 0xC1, 0xF0, 0xD4, 0x60, 0x8C, 0xD3, 0x3C, 0x1B, 0xFA, 0x39, 0xF0, 0x54, 0xFA, 0x2C, 0x27, 0xEA, 0xE5, 0xAC, 0x26, 0x75, 0xBF, 0xF6, 0x96, 0x75, 0x26, 0x9B, 0xBE, 0x05, 0x4D, 0x08, 0xC3, 0x2F, 0xDA, 0x89, 0xFF, 0xDC, 0xEE, 0xC9, 0xA9, 0x83, 0xBB, 0xE8, 0x61, 0xD1, 0x81, 0xB5, 0xEF, 0xAC, 0x68, 0x64, 0x1B, 0x13, 0xFC, 0xD4, 0x30, 0xCD, 0xFE, 0x10, 0xC2, 0xCA, 0x14, 0x09, 0x6F, 0xAB, 0x40, 0x65, 0xC6, 0xF6, 0x59, 0xCC, 0x7F, 0x61, 0xB2, 0x4B, 0x7C, 0x92, 0xF4, 0x90, 0xE6, 0xD8, 0x4D, 0x45, 0x8A, 0xC0, 0xC5, 0xE7, 0x08, 0x38, 0xAF, 0x82, 0x17, 0xF0, 0xC7, 0x50, 0x9B, 0x31, 0x60, 0xC5, 0xC1, 0x2B, 0x50, 0xE0, 0xF9, 0xF6, 0x2D, 0xBF, 0x8E, 0x95, 0x79, 0x9D, 0x54, 0x26, 0xC7, 0xE2, 0xAC, 0xEC, 0x4A, 0xD3, 0x78, 0xE9, 0x65, 0x64, 0xBA, 0x87, 0xE3, 0xF4, 0x0C, 0x91, 0xA2, 0x74, 0x18, 0x3F, 0xB4, 0x56, 0x6C, 0xF1, 0x1F, 0xB6, 0xE7, 0x92, 0x25, 0xC3, 0x59, 0xDF, 0xBE, 0x92, 0xD8, 0x59, 0xFC, 0x04, 0x45, 0x13, 0xBF, 0xE0, 0x0C, 0x9C, 0x9D, 0x61, 0xF7, 0x6E, 0x91, 0xE6, 0x85, 0xD3, 0x2F, 0xE7, 0xC6, 0xF5, 0x55, 0xD6, 0x66, 0x82, 0x6F, 0x30, 0x0E, 0xB0, 0x4A, 0x9A, 0x17, 0x00, 0x57, 0xE1, 0x14, 0xF7, 0xCA, 0xEE, 0x9F, 0xB9, 0x4F, 0xD4, 0xDF, 0x7D, 0x20, 0x99, 0xF5, 0x95, 0x29, 0x65, 0xA2, 0x00, 0x6D, 0x99, 0x17, 0x72, 0x75, 0x37, 0x73, 0x71, 0x04, 0x50, 0x4C, 0x55, 0x63, 0xC6, 0x7C, 0x9D, 0xB1, 0x7A, 0xA4, 0xCE, 0xDB, 0x36, 0xD3, 0xA1, 0x0C, 0x1F, 0x49, 0x30, 0xF3, 0x1A, 0x1A, 0xBE, 0x17, 0x30, 0x5F, 0x8B, 0x0B, 0x30, 0x90, 0x02, 0x89, 0x08, 0x12, 0x3B, 0xE8, 0xFB, 0x64, 0x6D, 0x50, 0x2E, 0xCD, 0xFD, 0x5C, 0x4D, 0x78, 0xD0, 0x1F, 0xBB, 0x58, 0xD6, 0xB3, 0xFC, 0x88, 0xFC, 0xAC, 0xDF, 0xC0, 0xE8, 0xA2, 0x19, 0x30, 0x6A, 0x5C, 0xD8, 0xB9, 0x85, 0xB4, 0x9B, 0x2F, 0x0F, 0x0E, 0xC2, 0x6C, 0xE7, 0xEB, 0xD2, 0xB4, 0x82, 0xED, 0xDC, 0x76, 0x2C, 0x4F, 0x97, 0x8C, 0x17, 0xE1, 0x7D, 0x66, 0xE2, 0x2D, 0x3E, 0x21, 0x7C, 0xC4, 0x41, 0x10, 0xE9, 0xFC, 0xDD, 0x74, 0x24, 0xB1, 0x51, 0xC2, 0xC3, 0xB4, 0x07, 0x59, 0x20, 0xE2, 0x65, 0x41, 0xDB, 0x1E, 0x72, 0x52, 0x8F, 0x28, 0x18, 0x6E, 0x2C, 0x57, 0x32, 0x55, 0xAA, 0xCF, 0xA8, 0x52, 0x34, 0x7F, 0x89, 0x3D, 0x56, 0x02, 0x87, 0x19, 0x15, 0xDD, 0xD2, 0x87, 0xEC, 0x39, 0x12, 0xDB, 0x03, 0x7B, 0x04, 0x47, 0x2D, 0xD0, 0x5A, 0x4B, 0x17, 0x3F, 0x84, 0xB7, 0xC9, 0x72, 0x07, 0x11, 0x86, 0x25, 0xD6, 0xB1, 0x03, 0x7D, 0x27, 0x00, 0x8B, 0x5D, 0xA7, 0xA6, 0x36, 0x54, 0x20, 0x10, 0x9E, 0x14, 0x2D, 0xC5, 0xA0, 0x5A, 0x19, 0x6A, 0xFF, 0xF4, 0x80, 0xFD, 0x38, 0x1A, 0x6A, 0x4D, 0xE6, 0x08, 0x34, 0xCD, 0x2C, 0xAD, 0x4D, 0x3E, 0xE2, 0xC3, 0x46, 0xDA, 0x95, 0xF2, 0x33, 0x41, 0x86, 0x26, 0xA9, 0xB8, 0xAA, 0xF4, 0x50, 0x10, 0x01, 0xE9, 0xA7, 0xCF, 0x58, 0x94, 0xA7, 0xA8, 0xA6, 0xAB, 0x2D, 0x81, 0x78, 0x16, 0x82, 0xA8, 0x8F, 0xCD, 0x0A, 0x9A, 0x6C, 0x0F, 0xFD, 0x76, 0x8F, 0xC4, 0xAA, 0x2A, 0x33, 0x8E, 0x7D, 0xDE, 0x04, 0xE8, 0x86, 0x8A, 0xBC, 0x7A, 0xA3, 0x02, 0x9F, 0x2C, 0xB6, 0x3C, 0xDC, 0x02, 0xBD, 0xC7, 0x51, 0xE1, 0x55, 0xDB, 0x2A, 0x72, 0xAD, 0x1D, 0x2C, 0x81, 0x6C, 0x30, 0x9D, 0x4A, 0xCC, 0x4D, 0x11, 0x3E, 0xE0, 0x8F, 0x6D, 0x63, 0xCF, 0x3D, 0x71, 0xF2, 0x0B, 0x8B, 0x44, 0x14, 0x6A, 0xDB, 0x61, 0x07, 0xC4, 0x8D, 0xEF, 0x34, 0x5A, 0x21, 0x79, 0xD7, 0xA8, 0xE6, 0xD8, 0xD0, 0x87, 0xEF, 0x40, 0x65, 0xC4, 0xFF, 0xB7, 0xDD, 0xBE, 0xC8, 0xFC, 0x8A, 0xBB, 0x59, 0x96, 0x6E, 0x37, 0xE4, 0x10, 0x4B, 0xEE, 0xFF, 0x6E, 0x4A, 0x22, 0xBD, 0xC7, 0x13, 0xA2, 0xF5, 0xC6, 0x5D, 0x21, 0xD6, 0x1C, 0xE4, 0xCD, 0x76, 0x68, 0xAA, 0x96, 0x2E, 0x37, 0x21, 0x01, 0x8F, 0x8B, 0xC6, 0x22, 0x97, 0xE7, 0x1D, 0x1B, 0x75, 0xEC, 0xAB, 0x3B, 0x91, 0x32, 0x6B, 0x17, 0x92, 0xCC, 0xC0, 0x7A, 0xFC, 0x8D, 0x54, 0xBA, 0xA8, 0x03, 0x87, 0x95, 0x2D, 0xE4, 0x2A, 0xA8, 0x3A, 0xD2, 0x71, 0x6A, 0x3F, 0x98, 0xA5, 0xAF, 0x17, 0x62, 0x45, 0xE8, 0x4D, 0x41, 0x7C, 0x3C, 0xD2, 0x4F, 0x89, 0x81, 0xFE, 0xC8, 0x2A, 0x91, 0x7A, 0xFE, 0x98, 0x3F, 0x50, 0x5A, 0x31, 0xAA, 0xD0, 0xAA, 0x2F, 0x5D, 0x36, 0x78, 0x2A, 0xA8, 0x46, 0xF2, 0x4C, 0xA8, 0x55, 0x81, 0xF8, 0xE0, 0xB1, 0x15, 0xDE, 0x9F, 0x68, 0x76, 0x4D, 0x89, 0x0E, 0x7D, 0xF9, 0x43, 0xCD, 0x67, 0x82, 0xCB, 0x2A, 0x30, 0xCE, 0xB7, 0xF6, 0xD8, 0xDA, 0x9D, 0xBA, 0xFE, 0xDA, 0x2C, 0x48, 0x0C, 0xBE, 0xF0, 0xC0, 0xEB, 0x4E, 0x55, 0xE5, 0x63, 0x4A, 0x3A, 0x17, 0x60, 0x32, 0x64, 0x5D, 0x9A, 0xC5, 0x6B, 0x02, 0xE2, 0xDD, 0x96, 0x24, 0x4B, 0xC1, 0xBC, 0xD1, 0x93, 0x73, 0x35, 0x17, 0x07, 0xBB, 0xDA, 0x32, 0x7E, 0x28, 0x49, 0xFD, 0x07, 0xBA, 0xA5, 0xED, 0x5E, 0x9D, 0xDD, 0x2E, 0xD2, 0x67, 0x45, 0x54, 0xFA, 0x9C, 0x0A, 0x9E, 0xDE, 0x2B, 0x87, 0xB4, 0x4E, 0xDF, 0xF4, 0x11, 0x16, 0x6F, 0xE5, 0x27, 0x59, 0x73, 0x69, 0xED, 0x1C, 0x83, 0xB9, 0x83, 0x24, 0x7C, 0xE0, 0x45, 0x92, 0x72, 0xE0, 0x13, 0xE6, 0xE7, 0x1A, 0x11, 0x53, 0xAA, 0xAC, 0x0A, 0x62, 0x79, 0x43, 0x1A, 0x2A, 0x54, 0x5D, 0x4A, 0x06, 0xA7, 0x46, 0xD0, 0xCC, 0xA8, 0x2A, 0x95, 0xDB, 0x0B, 0x73, 0x50, 0x46, 0xBB, 0x46, 0x61, 0x2F, 0x7D, 0x34, 0x95, 0xB7, 0x74, 0x40, 0x30, 0x38, 0x72, 0x0E, 0x17, 0xEC, 0x9B, 0x7B, 0xD8, 0x50, 0xD4, 0x1B, 0x4F, 0xAA, 0x60, 0x67, 0x2E, 0x1C, 0x25, 0xBB, 0x04, 0x21, 0x43, 0xF8, 0xDA, 0x1D, 0x98, 0x50, 0xB4, 0x35, 0x87, 0x8F, 0xB2, 0xAC, 0x55, 0xCC, 0x0B, 0x7B, 0x28, 0x7A, 0x5E, 0x89, 0xE3, 0x7B, 0x0C, 0x66, 0x3A, 0x48, 0xD1, 0x5A, 0xCA, 0x1B, 0x91, 0xDF, 0xC3, 0x79, 0x89, 0x02, 0xF7, 0xA5, 0x57, 0xB4, 0x9F, 0xA5, 0xB8, 0x61, 0x7D, 0xDA, 0x2A, 0xAC, 0x54, 0xB4, 0x12, 0xC4, 0x7A, 0x3A, 0xB8, 0xB9, 0x5D, 0xDD, 0xE6, 0x58, 0x3A, 0xEA, 0xEC, 0xF8, 0xEE, 0xD9, 0xAA, 0xA7, 0xF9, 0xA2, 0xEE, 0xD7, 0x31, 0x74, 0xEF, 0x94, 0x66, 0x8F, 0x23, 0xD8, 0xF1, 0x8F, 0x81, 0xF3, 0xEE, 0x39, 0x2D, 0x40, 0x3E, 0x4E, 0xE8, 0x04, 0x01, 0xFE, 0x69, 0x04, 0x05, 0xD0, 0x20, 0x3B, 0x35, 0xE8, 0xE3, 0xF4, 0x59, 0x99, 0x12, 0x59, 0x85, 0xE4, 0x9F, 0xCE, 0xC7, 0x3B, 0x8B, 0x76, 0xF5, 0xF1, 0xFF, 0xFE, 0x36, 0x8E, 0xD6, 0x3A, 0x39, 0x86, 0xB4, 0x12, 0x09, 0xF7, 0xA5, 0xFA, 0x16, 0x80, 0x7E, 0x1C, 0x3D, 0xD4, 0xDD, 0x71, 0xBC, 0x64, 0x8E, 0x8B, 0xF8, 0x95, 0x65, 0xD2, 0xE6, 0x53, 0x79, 0x94, 0xB8, 0x1B, 0xCD, 0xDA, 0xE1, 0xB3, 0xE5, 0x5B, 0x0F, 0xD4, 0x57, 0x7A, 0x66, 0x6A, 0xD0, 0xCE, 0x45, 0xA8, 0xC2, 0xB6, 0x81, 0x7A, 0xD5, 0x59, 0xD1, 0x08, 0x4C, 0x77, 0xAD, 0xDE, 0xD5, 0xA8, 0xF0, 0x33, 0x1A, 0xB5, 0x58, 0x71, 0x56, 0x23, 0x19, 0xA1, 0x20, 0x68, 0xA5, 0xF5, 0x89, 0x29, 0x86, 0x56, 0xFF, 0x74, 0x8F, 0x81, 0xAA, 0xF4, 0x53, 0xC0, 0x92, 0x97, 0xDB, 0x08, 0x7C, 0xCE, 0xED, 0xA5, 0xB8, 0x9B, 0x80, 0xBF, 0x79, 0xFE, 0x7C, 0xD8, 0x64, 0xB4, 0x7B, 0x8D, 0x42, 0xC1, 0x64, 0x6B, 0x00, 0x29, 0xF2, 0x89, 0x87, 0x5C, 0x50, 0xFA, 0x16, 0x8A, 0xAD, 0xA5, 0x51, 0x95, 0x08, 0x1A, 0x42, 0xA9, 0x7D, 0xC1, 0xE2, 0x9E, 0x52, 0xE5, 0x3B, 0x00, 0xC2, 0x23, 0x26, 0x59, 0x1D, 0xF9, 0xC2, 0x39, 0x7B, 0x03, 0x24, 0x9A, 0xF3, 0x52, 0xC1, 0xEF, 0x0C, 0x5A, 0x65, 0x69, 0x89, 0xC5, 0x2F, 0xE3, 0xCF, 0x93, 0x4A, 0xE8, 0xA5, 0x74, 0x87, 0x9F, 0x33, 0x2B, 0x32, 0xD6, 0xE4, 0x6D, 0xF2, 0x1E, 0x92, 0xC3, 0x01, 0x48, 0xA9, 0xF4, 0x65, 0xD8, 0x26, 0x1D, 0xE6, 0x20, 0xCB, 0xD2, 0xE9, 0xEE, 0x15, 0x1C, 0xB6, 0x43, 0x05, 0xF2, 0x43, 0x6C, 0x56, 0xA4, 0x01, 0xC0, 0x9A, 0x49, 0xC7, 0xDB, 0x05, 0xC9, 0xE6, 0x78, 0x56, 0xD6, 0xC9, 0x56, 0x86, 0x4A, 0x31, 0xE4, 0x5B, 0x52, 0x6F, 0xC4, 0x66, 0x03, 0x92, 0x1D, 0x1D, 0xDC, 0xA0, 0xBF, 0x7F, 0x75, 0xD0, 0xE3, 0x8D, 0xBE, 0xC2, 0xD7, 0x41, 0x3B, 0xDC, 0xB9, 0x4D, 0xFF, 0x64, 0x80, 0x64, 0x48, 0x34, 0xEA, 0x2B, 0xF4, 0xBC, 0xA0, 0x0A, 0xC9, 0xC1, 0xEF, 0x13, 0x2E, 0x31, 0xA1, 0x79, 0xE5, 0x71, 0x41, 0x68, 0xB1, 0x0C, 0x50, 0x3A, 0x63, 0xD0, 0xB1, 0x64, 0x0C, 0x68, 0xB8, 0x99, 0xD4, 0x78, 0x2B, 0x41, 0xDC, 0xA1, 0x2C, 0xD6, 0xC2, 0x29, 0xF9, 0x65, 0xA5, 0x1F, 0x25, 0xCE, 0xE3, 0x9E, 0xCF, 0xE7, 0xED, 0x4B, 0xF5, 0x7A, 0xAB, 0x7A, 0x9B, 0x78, 0x4C, 0x35, 0x46, 0x98, 0x56, 0xF0, 0x9A, 0xD4, 0xBF, 0xD9, 0x1F, 0x7C, 0xD6, 0xB8, 0x28, 0x3A, 0x48, 0x55, 0xA1, 0x7F, 0xFC, 0xC7, 0x96, 0x84, 0x1A, 0x02, 0xF4, 0x51, 0x50, 0xBD, 0xC9, 0xCF, 0x50, 0x93, 0x5C, 0xCD, 0x9B, 0x28, 0xD8, 0x57, 0x5F, 0xA4, 0xB2, 0xEC, 0xC6, 0x66, 0x3B, 0xB7, 0xBA, 0xF6, 0x2C, 0xE7, 0x4D, 0x9E, 0xAF, 0xFC, 0x17, 0x5C, 0x86, 0x29, 0xD4, 0xD9, 0x25, 0x2C, 0x7E, 0x5C, 0xDA, 0xB0, 0x6D, 0xA1, 0x1C, 0x46, 0xE9, 0x50, 0xA2, 0xCD, 0x4C, 0x06, 0x74, 0xC0, 0xC6, 0xE2, 0x97, 0xF0, 0xE6, 0xFD, 0xE9, 0x6F, 0xA0, 0x72, 0x8E, 0x32, 0x31, 0x40, 0x30, 0x03, 0x98, 0x4B, 0x5A, 0x7F, 0x97, 0x52, 0x63, 0xB2, 0xA5, 0xAD, 0xD7, 0x33, 0x59, 0x31, 0xEA, 0x85, 0x02, 0x19, 0x58, 0xE1, 0xC4, 0x97, 0xDB, 0x73, 0xB9, 0x11, 0xF2, 0xD4, 0x93, 0xEA, 0xD3, 0xAA, 0xBA, 0x2A, 0xA8, 0xD2, 0x9F, 0x5D, 0xAE, 0xCA, 0xD5, 0x32, 0xA3, 0xD3, 0x1D, 0xB8, 0xA3, 0x47, 0xD1, 0x45, 0x40, 0xA3, 0xCE, 0x92, 0x76, 0x9A, 0x05, 0x19, 0x76, 0xDD, 0x73, 0x54, 0x70, 0x6E, 0x46, 0x8E, 0xDE, 0x7B, 0x39, 0x6A, 0x09, 0x88, 0xF2, 0x8E, 0x3C, 0x8C, 0x34, 0x74, 0x1B, 0x98, 0xDA, 0x58, 0x5E, 0xA3, 0x11, 0x67, 0x67, 0xD7, 0x63, 0xC5, 0xBF, 0x5F, 0x13, 0x0D, 0x7F, 0xDC, 0xAD, 0x96, 0xB4, 0xDC, 0xD8, 0xD6, 0xED, 0x7E, 0x42, 0xC3, 0x68, 0x17, 0xDD, 0x34, 0x9B, 0x08, 0x7F, 0x6E, 0xD7, 0xBA, 0x6D, 0x88, 0xC9, 0x97, 0x3B, 0x3F, 0x42, 0x8A, 0x78, 0x35, 0x8B, 0x00, 0x27, 0x8F, 0xE6, 0x20, 0xC4, 0x88, 0x62, 0x4C, 0x0F, 0x79, 0xE9, 0x7E, 0x6D, 0x48, 0x54, 0xC7, 0x56, 0x95, 0x79, 0xBD, 0x33, 0xBF, 0xD2, 0x6F, 0x55, 0x77, 0x2B, 0x48, 0xEC, 0x6C, 0x06, 0xF1, 0x97, 0x02, 0xB1, 0x11, 0x22, 0x04, 0x0C, 0x7A, 0x94, 0xE9, 0xDF, 0x85, 0x48, 0x36, 0xFF, 0x1E, 0xF2, 0x6B, 0x08, 0x36, 0x87, 0xAB, 0x0C, 0xD5, 0x60, 0x0A, 0xFC, 0x5C, 0x0D, 0xD0, 0x4D, 0xC3, 0x33, 0x4A, 0x4C, 0xAE, 0x2F, 0xF0, 0x7C, 0xA7, 0x43, 0x76, 0x28, 0xCE, 0x7D, 0xB1, 0x2D, 0x7C, 0x80, 0xA1, 0x4C, 0x0E, 0xF4, 0xB2, 0x42, 0xB7, 0x47, 0xF5, 0x65, 0x16, 0x9E, 0x60, 0xB1, 0x79, 0x89, 0xE8, 0x19, 0x78, 0x19, 0x30, 0xAD, 0x5D, 0x13, 0x36, 0x3B, 0x19, 0x69, 0xB6, 0x72, 0x5C, 0xB5, 0x27, 0xDA, 0xA1, 0x59, 0x1A, 0x0A, 0x58, 0x69, 0xF3, 0x56, 0x55, 0x42, 0x26, 0x09, 0xF9, 0x8B, 0xF0, 0xDB, 0xF4, 0x4B, 0x2D, 0x21, 0x81, 0xA6, 0x48, 0xCA, 0xB0, 0x20, 0xE3, 0xE5, 0xA7, 0xCD, 0xD0, 0x1F, 0x38, 0x0C, 0xEB, 0xC8, 0x90, 0x1D, 0x08, 0xEE, 0xB1, 0x13, 0x19, 0x75, 0x57, 0x22, 0xA9, 0x84, 0xCE, 0x2E, 0x30, 0x61, 0x58, 0x4F, 0x23, 0x9C, 0x3C, 0xF5, 0x50, 0xE3, 0xE2, 0x7E, 0x6A, 0x31, 0x9E, 0x19, 0xD9, 0xFE, 0x6E, 0x6F, 0x9E, 0x4C, 0x77, 0x05, 0xCF, 0x06, 0x12, 0xB2, 0x50, 0x56, 0x41, 0xDA, 0x74, 0xCE, 0x6D, 0x11, 0x05, 0xCA, 0x90, 0xD5, 0xAD, 0x5B, 0xAA, 0x9D, 0x56, 0xF6, 0x35, 0x39, 0x8D, 0x25, 0xA7, 0x5E, 0x14, 0x75, 0x3B, 0xC3, 0x7A, 0x58, 0x42, 0xE4, 0xCA, 0x84, 0xFC, 0x2A, 0xE7, 0xB2, 0x94, 0xD9, 0xB9, 0xC5, 0x77, 0x3A, 0x20, 0xD9, 0x0A, 0x48, 0x3D, 0x43, 0x83, 0x7B, 0xB0, 0x97, 0x1B, 0x3A, 0x56, 0xF4, 0x86, 0xFB, 0xC6, 0x90, 0xB3, 0x39, 0x7A, 0xA0, 0x18, 0x77, 0x4C, 0xA2, 0x41, 0x9B, 0x0C, 0xE4, 0x35, 0xAA, 0x68, 0xCF, 0xA7, 0xD6, 0x86, 0xEB, 0x08, 0xF3, 0x44, 0x6A, 0x53, 0x86, 0x8F, 0xDE, 0x20, 0x47, 0x9A, 0x6B, 0x9E, 0xD8, 0x57, 0x4D, 0xA4, 0xB3, 0x65, 0xD8, 0x53, 0x1D, 0xCC, 0x20, 0xEF, 0x22, 0x74, 0x22, 0x48, 0x8B, 0xF2, 0xC1, 0xE1, 0x51, 0x78, 0x11, 0x65, 0x79, 0x87, 0x1A, 0xC1, 0xED, 0xDD, 0xCC, 0x4A, 0xC0, 0xDF, 0x60, 0xCC, 0xC1, 0x9E, 0xD3, 0xB0, 0x77, 0xA5, 0x76, 0x3B, 0x04, 0xEB, 0x59, 0x71, 0xBD, 0x1F, 0x56, 0x83, 0x92, 0x60, 0x58, 0x1D, 0x63, 0x4D, 0x18, 0x5B, 0xA8, 0xC3, 0x4A, 0xF7, 0xE2, 0xEC, 0x78, 0x91, 0xC3, 0x12, 0xB9, 0xD9, 0x3C, 0x95, 0x27, 0xAB, 0x54, 0x3E, 0xCB, 0x0D, 0x9C, 0xA9, 0x0F, 0xF8, 0x27, 0x83, 0x09, 0x85, 0xB0, 0xFE, 0x39, 0x08, 0x35, 0xA1, 0xD9, 0x89, 0xA4, 0x56, 0xCC, 0x90, 0xBD, 0x07, 0x58, 0x8B, 0x5A, 0x05, 0x72, 0x62, 0x15, 0x30, 0x71, 0xCE, 0x90, 0x63, 0x66, 0x7D, 0x6B, 0x27, 0x74, 0x41, 0x67, 0x5F, 0x07, 0xA6, 0xCA, 0xF8, 0x55, 0x2C, 0x0D, 0x00, 0x47, 0x4E, 0xD2, 0xC3, 0x67, 0x93, 0x0F, 0xF5, 0xE5, 0xFD, 0x95, 0x31, 0x9F, 0xF8, 0x08, 0xEE, 0x3B, 0xC2, 0x44, 0x89, 0xEF, 0x9B, 0xEB, 0xF8, 0x09, 0x7A, 0x3F, 0xE7, 0x46, 0xC0, 0x65, 0x02, 0x11, 0xD4, 0x29, 0xC0, 0x6E, 0xBC, 0x8F, 0x44, 0xDA, 0x33, 0x3D, 0x25, 0xB9, 0xFE, 0x74, 0xA0, 0x92, 0x1F, 0xB8, 0xAA, 0x76, 0x6E, 0xF2, 0x00, 0x87, 0xAE, 0xA4, 0xEC, 0xD7, 0x1B, 0xA4, 0x27, 0xF1, 0xB3, 0x29, 0x2B, 0x85, 0xB3, 0xF8, 0x6F, 0xDF, 0x21, 0x44, 0x69, 0x13, 0x77, 0xFE, 0x97, 0xCA, 0x67, 0xD2, 0xD4, 0x73, 0x4F, 0xB2, 0x36, 0x80, 0xCA, 0x96, 0xDB, 0xBA, 0x64, 0x32, 0x1C, 0x5E, 0x07, 0xA6, 0x8C, 0xA8, 0x96, 0x01, 0xE9, 0xE5, 0x18, 0x34, 0x4C, 0x1B, 0xB1, 0x86, 0x3F, 0xC1, 0xAE, 0xBD, 0xBE, 0xAF, 0xE0, 0x38, 0x95, 0x57, 0x8D, 0x56, 0x99, 0x33, 0xA2, 0xC5, 0x7A, 0xA3, 0x4E, 0xB0, 0x5B, 0xB3, 0xC1, 0x8C, 0xF3, 0x6C, 0x00, 0x19, 0xCF, 0xE5, 0x69, 0x19, 0x29, 0xE1, 0x30, 0x40, 0x78, 0x47, 0xBC, 0x12, 0xA1, 0x1B, 0x89, 0xAF, 0x49, 0xC1, 0x7C, 0x79, 0x99, 0x36, 0x19, 0x99, 0xED, 0xAB, 0x50, 0xDF, 0x3C, 0x4B, 0xE1, 0x5A, 0x6C, 0x5C, 0x8E, 0x6B, 0xC2, 0x98, 0xCF, 0xC4, 0x63, 0xB5, 0xB3, 0xBE, 0xD7, 0x5A, 0x86, 0x50, 0x1D, 0x6B, 0x88, 0x19, 0xDA, 0xA1, 0xE1, 0x3F, 0xAD, 0xA5, 0x44, 0x64, 0xCB, 0xBD, 0x39, 0x74, 0x94, 0x1C, 0x02, 0x25, 0x71, 0x00, 0x17, 0x43, 0x69, 0x6E, 0x89, 0x99, 0x4E, 0xE3, 0x28, 0xCB, 0x98, 0x19, 0x2D, 0x91, 0x32, 0x60, 0x84, 0x86, 0x1B, 0x01, 0xA7, 0x52, 0x41, 0x3A, 0xA4, 0xD4, 0x75, 0xC3, 0x28, 0x2B, 0x7E, 0xFB, 0xED, 0xFC, 0x3F, 0x62, 0x68, 0x4F, 0x29, 0x29, 0x72, 0x99, 0x5A, 0x04, 0xDE, 0x24, 0x2A, 0x26, 0x7F, 0x75, 0x05, 0x0D, 0x3A, 0x6F, 0xFC, 0x34, 0x72, 0xB6, 0x6B, 0x3E, 0x64, 0xB7, 0x17, 0x74, 0x81, 0xF1, 0x56, 0x8F, 0xF8, 0x9C, 0xC0, 0x41, 0x15, 0xC9, 0xF7, 0x8A, 0x0F, 0x49, 0xAC, 0x3C, 0x0A, 0x00, 0x5A, 0x8E, 0x46, 0x28, 0xFD, 0xB6, 0x2E, 0xD6, 0x25, 0xA7, 0x6C, 0xEF, 0x53, 0x27, 0x90, 0x5B, 0x54, 0x48, 0x85, 0xB3, 0xEC, 0x9E, 0x52, 0x0D, 0x2E, 0x32, 0x8A, 0xF5, 0xF3, 0x1C, 0xFF, 0x7E, 0x0C, 0xDD, 0x89, 0x5A, 0xD0, 0x8D, 0xCD, 0x9F, 0x59, 0xB8, 0x4F, 0x22, 0x58, 0x81, 0xFD, 0x83, 0xFD, 0xDC, 0x58, 0x26, 0xB4, 0xB9, 0x70, 0x23, 0xC5, 0x91, 0x4F, 0x17, 0x00, 0x1D, 0xB1, 0x70, 0x6A, 0x66, 0x58, 0xB5, 0x47, 0x3F, 0x16, 0xBF, 0x6E, 0xB3, 0xC4, 0x7D, 0x11, 0x1A, 0xE9, 0x2E, 0x39, 0x12, 0x39, 0xA9, 0x45, 0xD5, 0x98, 0x8C, 0x5F, 0x05, 0xE2, 0x99, 0xE6, 0x9F, 0xE1, 0xDA, 0x1B, 0x31, 0x58, 0x55, 0x90, 0xB2, 0x6D, 0x7C, 0x55, 0x94, 0x7C, 0x00, 0xEB, 0x32, 0x42, 0x07, 0x8B, 0x39, 0x24, 0x9E, 0xB2, 0xC6, 0x00, 0xFA, 0xDE, 0xE8, 0x06, 0x86, 0xDF, 0x5B, 0x37, 0xD2, 0xD1, 0x5E, 0x44, 0x49, 0x56, 0x65, 0x2C, 0x72, 0x4F, 0x1D, 0x5D, 0x13, 0x9D, 0x1D, 0xFB, 0x4D, 0x6B, 0xE4, 0x4E, 0x3C, 0x57, 0x3B, 0x60, 0xB8, 0x32, 0x98, 0x34, 0xF2, 0xF5, 0xDD, 0xC3, 0x68, 0x81, 0x6C, 0x52, 0x8D, 0x88, 0x28, 0xED, }, .priv_len = 4896, .pub = { 0xCA, 0xDE, 0xD2, 0x24, 0xB8, 0xF0, 0xB4, 0xCE, 0x30, 0x19, 0x85, 0x30, 0x5F, 0x5E, 0xCF, 0xF5, 0x03, 0xDD, 0x4E, 0xCC, 0xF0, 0x69, 0xB9, 0xAB, 0x3C, 0xFA, 0x07, 0x4E, 0x89, 0x22, 0x41, 0xBB, 0x66, 0x7F, 0x74, 0x0D, 0xF1, 0x71, 0xE4, 0x95, 0x5A, 0x29, 0xF6, 0x96, 0x53, 0x19, 0x2F, 0xDB, 0x7E, 0x65, 0xAB, 0x5C, 0x64, 0xCC, 0xDD, 0xBC, 0x4B, 0x91, 0xAB, 0x36, 0x3F, 0x5A, 0xA9, 0x8B, 0x3D, 0xAF, 0xAB, 0xFF, 0x8A, 0xFC, 0x6C, 0x71, 0x1A, 0x74, 0xB7, 0x4C, 0x9C, 0xBD, 0x6D, 0xA2, 0x33, 0xE9, 0x08, 0x39, 0x80, 0x28, 0xA0, 0x6A, 0xF0, 0xA1, 0x0E, 0x79, 0x4B, 0xA5, 0xC5, 0xE0, 0x06, 0xA1, 0x0A, 0x4D, 0xA9, 0x64, 0xC1, 0x55, 0xFC, 0xBE, 0x68, 0x2A, 0x61, 0xEA, 0x77, 0xC6, 0x59, 0xB5, 0xF8, 0xFD, 0x8A, 0xFC, 0xFA, 0xFA, 0xDA, 0x4F, 0xDC, 0x01, 0x45, 0x19, 0x85, 0x90, 0x63, 0x1C, 0x76, 0x87, 0x5B, 0xBE, 0xC7, 0x67, 0x88, 0x9F, 0xAB, 0xD0, 0xC7, 0x30, 0x20, 0x90, 0x6B, 0x86, 0x3A, 0x38, 0xFE, 0x83, 0x14, 0xAB, 0xE7, 0xE7, 0x31, 0x5F, 0xB9, 0x54, 0x21, 0x57, 0x2C, 0x32, 0x55, 0x20, 0xEE, 0x55, 0x45, 0xD8, 0x9B, 0x70, 0xFA, 0x4F, 0x70, 0x6A, 0xEF, 0x39, 0x78, 0x30, 0x36, 0x4B, 0x23, 0x1E, 0x18, 0xDB, 0xE0, 0x1E, 0x49, 0xDD, 0x80, 0x39, 0x69, 0x95, 0x4E, 0x02, 0x43, 0x8C, 0x5D, 0xA3, 0xA4, 0xCC, 0x61, 0x4B, 0x37, 0x26, 0xD2, 0x9C, 0xF6, 0xEF, 0x4B, 0x64, 0x49, 0xBE, 0x9E, 0x6A, 0x95, 0x0F, 0x18, 0xEE, 0xAA, 0xEF, 0xFF, 0xA5, 0x8C, 0xF6, 0x0D, 0x98, 0x6F, 0x01, 0x73, 0x2B, 0x47, 0x56, 0x3D, 0x2C, 0x84, 0xA6, 0x82, 0x17, 0xE3, 0x56, 0x52, 0x17, 0x7D, 0x1C, 0x9D, 0x11, 0x17, 0x5F, 0xE4, 0xDA, 0x61, 0x22, 0x64, 0x1B, 0x53, 0x59, 0x8F, 0xB6, 0x45, 0x8A, 0x9B, 0x99, 0x3D, 0x5A, 0xB4, 0xB8, 0x5A, 0xFA, 0x4F, 0x7E, 0x99, 0x03, 0x78, 0x05, 0x13, 0xF4, 0x99, 0x32, 0x55, 0xF8, 0xE2, 0xEA, 0xA8, 0x72, 0xA8, 0x4F, 0xDC, 0x50, 0x92, 0x49, 0x60, 0x39, 0x19, 0x15, 0xB1, 0x1B, 0xA6, 0x11, 0x17, 0x10, 0x35, 0xD3, 0x43, 0x2F, 0x9E, 0xC3, 0xE7, 0xC4, 0x7C, 0x94, 0xA6, 0x6B, 0xF3, 0xE4, 0x2F, 0x65, 0xC3, 0x55, 0x21, 0x3A, 0xFE, 0x02, 0xDC, 0x76, 0xCC, 0xD9, 0xCD, 0x8D, 0xA5, 0xDD, 0x00, 0x88, 0xEF, 0xC8, 0x48, 0x0E, 0xE6, 0x05, 0x13, 0x44, 0xEC, 0x8E, 0x0B, 0x0C, 0xCD, 0x36, 0x96, 0xF2, 0xEF, 0xF4, 0x66, 0x45, 0x11, 0xC7, 0x95, 0x1C, 0x01, 0x60, 0xA3, 0xB2, 0x6D, 0x8A, 0x36, 0xBA, 0x57, 0xC5, 0x5A, 0x99, 0x2F, 0xA2, 0x01, 0x70, 0x9D, 0x20, 0x63, 0xEF, 0x86, 0x79, 0x6C, 0xD3, 0xCA, 0xAA, 0x10, 0x14, 0x18, 0xDA, 0xE9, 0xA8, 0x66, 0xD1, 0x54, 0x22, 0xC3, 0xA9, 0x70, 0x20, 0x82, 0xD6, 0x73, 0x50, 0x6B, 0xA9, 0x7C, 0xA6, 0x51, 0x2B, 0xCC, 0x86, 0x55, 0x95, 0xFF, 0x99, 0x97, 0xA5, 0x89, 0xFB, 0x60, 0x5A, 0x9A, 0x52, 0xFD, 0xCA, 0xB3, 0xF4, 0x21, 0x59, 0x28, 0xE9, 0x47, 0x8A, 0x46, 0xD0, 0x8E, 0x22, 0xFD, 0x87, 0x74, 0xB2, 0x7A, 0x5A, 0xCB, 0x39, 0x4B, 0x6A, 0x47, 0x54, 0x13, 0x8D, 0xBE, 0x48, 0x1D, 0x6B, 0x8F, 0x2C, 0xE4, 0x37, 0x51, 0xF3, 0x7C, 0xF6, 0x25, 0xB4, 0x7B, 0x40, 0xE9, 0x45, 0xEB, 0xD2, 0x08, 0x36, 0xCD, 0x38, 0xA1, 0x80, 0xAE, 0x64, 0x54, 0xF8, 0x6A, 0xF7, 0xEC, 0x41, 0x52, 0xBD, 0x66, 0x0E, 0xB2, 0x25, 0x49, 0xE1, 0x78, 0xD2, 0x36, 0x39, 0xF0, 0x00, 0x17, 0x1B, 0x33, 0x62, 0x8C, 0x02, 0x5C, 0x73, 0x7A, 0x42, 0x62, 0x47, 0x92, 0xD5, 0x10, 0xEB, 0x32, 0x95, 0x96, 0x55, 0x99, 0xEA, 0x2A, 0x35, 0x13, 0xE0, 0x79, 0x08, 0x2E, 0x1E, 0x55, 0xA9, 0xE7, 0xC1, 0xC7, 0x75, 0x6E, 0xA2, 0xE2, 0x95, 0x71, 0x85, 0x54, 0x0C, 0xFF, 0xB5, 0x67, 0xF7, 0x4A, 0x60, 0x6D, 0xD2, 0x1F, 0x4D, 0xC3, 0xB1, 0xDD, 0x1D, 0xB7, 0x67, 0x5E, 0xFE, 0x0A, 0xE4, 0x17, 0x0F, 0xE5, 0x9B, 0x7F, 0x8F, 0x55, 0x76, 0xEA, 0x0B, 0x1D, 0xEF, 0x1D, 0x29, 0x14, 0xE2, 0x25, 0x92, 0x79, 0xE8, 0x2D, 0xA6, 0x3C, 0x06, 0xD1, 0x7A, 0x46, 0x27, 0xE6, 0x42, 0x2F, 0x5B, 0x4A, 0x0C, 0xFF, 0x30, 0x29, 0x4D, 0x5D, 0x10, 0xD3, 0xF2, 0x6C, 0x51, 0x58, 0x01, 0x4F, 0xDC, 0xAF, 0x7D, 0x60, 0x53, 0xE9, 0xF1, 0x9D, 0x7D, 0x68, 0xEF, 0xB7, 0x04, 0xD9, 0xC2, 0x1E, 0x52, 0x95, 0x51, 0x58, 0x2E, 0x29, 0x64, 0xD1, 0x59, 0x2E, 0x97, 0x4F, 0x6C, 0xE0, 0x67, 0x3E, 0x67, 0xFB, 0xE0, 0xB3, 0xBD, 0x21, 0xD6, 0x65, 0x20, 0x2C, 0xF2, 0x28, 0x3B, 0xA9, 0xA4, 0x93, 0x7F, 0x22, 0x99, 0xE5, 0xFB, 0x1A, 0xA7, 0x5A, 0xE2, 0x25, 0xA5, 0xAE, 0x4E, 0xEB, 0xCE, 0x61, 0x54, 0xBA, 0x69, 0xDC, 0x90, 0x6D, 0xC0, 0xD4, 0xE8, 0x14, 0x74, 0x82, 0x13, 0x50, 0x13, 0x60, 0xB0, 0x41, 0xD3, 0xDF, 0x81, 0x1E, 0x13, 0xB3, 0x10, 0x3F, 0x3B, 0x71, 0x7B, 0x60, 0x11, 0x3C, 0xE9, 0x6C, 0x26, 0x7D, 0xD0, 0x92, 0xA8, 0xF6, 0x54, 0x68, 0xBD, 0x88, 0xF8, 0x54, 0x11, 0x34, 0x77, 0x58, 0xF5, 0x40, 0xE8, 0x61, 0xE0, 0x96, 0x10, 0x8E, 0xEB, 0x00, 0x2C, 0x8D, 0x81, 0xB0, 0xC6, 0xF5, 0xAD, 0x86, 0x67, 0xE4, 0xE1, 0x15, 0x06, 0x64, 0x9D, 0x82, 0x98, 0xCD, 0x5C, 0xB3, 0x2B, 0x3B, 0x98, 0x10, 0x92, 0x67, 0x8F, 0xEC, 0x40, 0xE0, 0x5B, 0x95, 0xA6, 0x64, 0x1E, 0xE5, 0x86, 0xE7, 0x01, 0x07, 0xC1, 0xDF, 0x9A, 0x7F, 0xD3, 0x05, 0x4D, 0x6A, 0xDD, 0xE8, 0x57, 0xA7, 0x02, 0x8A, 0x4F, 0xF9, 0x54, 0x16, 0x6F, 0x02, 0x59, 0x14, 0x43, 0x2E, 0x9D, 0x4B, 0x2E, 0x02, 0x69, 0x6D, 0x85, 0x5B, 0xC3, 0x7A, 0x49, 0x0B, 0xC4, 0x49, 0xBE, 0x6F, 0x91, 0x75, 0xDE, 0x94, 0xA8, 0x40, 0x6E, 0xB6, 0x25, 0x2F, 0xF4, 0x79, 0xB2, 0x53, 0xBC, 0x8E, 0x1C, 0x7A, 0xE3, 0x46, 0x29, 0xA1, 0x30, 0xF8, 0x53, 0x27, 0xB0, 0x18, 0x6D, 0x01, 0xCA, 0xBD, 0x68, 0xD8, 0x3C, 0x8B, 0x15, 0xD9, 0xEE, 0x64, 0xD5, 0x4D, 0xC3, 0xE7, 0xA5, 0xD1, 0xA2, 0x13, 0x9C, 0xC8, 0xCB, 0x26, 0x72, 0xB0, 0x68, 0xDE, 0x8B, 0xE0, 0x4C, 0x85, 0xCF, 0xC5, 0x02, 0x14, 0xA2, 0x2F, 0xFE, 0x05, 0xA6, 0x0A, 0x82, 0xC7, 0xFD, 0x8D, 0x86, 0xA8, 0x02, 0x19, 0x96, 0x91, 0x8B, 0x98, 0x12, 0x79, 0xCA, 0xB2, 0x74, 0x93, 0xC6, 0x89, 0x7A, 0x55, 0xDF, 0xEB, 0x22, 0xDF, 0x89, 0x61, 0x4D, 0x07, 0x8C, 0x39, 0x24, 0x87, 0x98, 0xBB, 0x8F, 0x2A, 0xDD, 0x1D, 0x6F, 0x8B, 0x06, 0xEF, 0xAB, 0x57, 0xC6, 0xEF, 0x1C, 0xE0, 0xA9, 0x07, 0xE2, 0xE7, 0x23, 0xF5, 0x5E, 0xB3, 0x68, 0xCD, 0xAF, 0x8B, 0xFA, 0x6B, 0x8E, 0x74, 0xDE, 0xDE, 0x8B, 0xA4, 0x85, 0x0E, 0x69, 0x6B, 0x1A, 0x3A, 0x39, 0x08, 0xE2, 0x9F, 0x03, 0xC2, 0x22, 0xCC, 0x2F, 0x97, 0x98, 0x73, 0x6C, 0x31, 0xC8, 0x6D, 0x2A, 0x47, 0x3B, 0xA6, 0xB5, 0x0F, 0x32, 0x87, 0xDF, 0x4C, 0x4F, 0x82, 0xD8, 0x83, 0x72, 0x95, 0x1B, 0x5C, 0x06, 0xC0, 0x63, 0x27, 0x6A, 0x19, 0x4D, 0x4D, 0x1C, 0xAA, 0x21, 0xD5, 0xFF, 0x1A, 0xB2, 0x7F, 0xC9, 0xC1, 0x79, 0x54, 0x55, 0xFB, 0x5B, 0xF9, 0x3F, 0x0B, 0x89, 0x4C, 0x5A, 0x9B, 0xF4, 0x2E, 0x55, 0xAE, 0x5B, 0xBF, 0x07, 0xE0, 0x13, 0x9A, 0xDE, 0x1A, 0xF2, 0xD4, 0x10, 0x12, 0x75, 0x31, 0x5D, 0xBE, 0xAD, 0x21, 0x9D, 0x6F, 0xF6, 0xC3, 0xC9, 0xC5, 0xAF, 0x6B, 0x14, 0x9B, 0xA7, 0x1E, 0x6D, 0xD3, 0x45, 0x3C, 0xCA, 0xC0, 0xC9, 0xCE, 0x85, 0x7E, 0x3A, 0x0A, 0x0B, 0x3E, 0x7B, 0x9C, 0xAD, 0x9D, 0x2C, 0xBE, 0xA1, 0x6D, 0xA5, 0x68, 0x00, 0x63, 0xD3, 0x2B, 0x03, 0x15, 0xDD, 0x2C, 0x76, 0xD4, 0x9D, 0x48, 0xBE, 0xE2, 0x57, 0xA6, 0xAD, 0xB4, 0xF4, 0x43, 0x80, 0x70, 0x27, 0xC8, 0xC9, 0x29, 0x59, 0x9E, 0x7F, 0x12, 0x39, 0x05, 0x28, 0x37, 0xB0, 0x69, 0xAE, 0xC6, 0xB6, 0x2F, 0x6F, 0x7C, 0x91, 0x3C, 0x0A, 0x3A, 0xCA, 0x73, 0xDA, 0x26, 0x97, 0xFF, 0x1A, 0x5C, 0x48, 0x06, 0x90, 0x83, 0x70, 0x8B, 0x86, 0xAF, 0x96, 0x90, 0x6F, 0x28, 0x74, 0xFA, 0x69, 0x14, 0xB7, 0x29, 0x1B, 0x02, 0xCC, 0x52, 0x50, 0xFD, 0xCD, 0x6C, 0xBD, 0x61, 0xF1, 0x12, 0x48, 0x4D, 0x61, 0x81, 0xEF, 0xBE, 0xA2, 0x28, 0xA0, 0xA5, 0x80, 0xB4, 0xB7, 0xE6, 0xF8, 0xF0, 0x80, 0x6F, 0x2B, 0xA7, 0x64, 0x55, 0x8F, 0x4B, 0x52, 0x1F, 0x93, 0x3D, 0x8D, 0xD5, 0x56, 0xA7, 0xA2, 0x55, 0x60, 0x09, 0x4F, 0xD7, 0xBC, 0x5A, 0x0F, 0x82, 0x10, 0x44, 0x60, 0x36, 0x2D, 0xBC, 0x92, 0xCC, 0x0E, 0x7D, 0xF9, 0xE4, 0x38, 0x49, 0xDB, 0xC9, 0x0E, 0x67, 0xE2, 0x03, 0xB4, 0x39, 0xE8, 0xC6, 0xDC, 0x3C, 0xF2, 0x3C, 0xDE, 0x5F, 0x91, 0x38, 0x86, 0xD9, 0x44, 0x5D, 0x6A, 0xC6, 0x8B, 0x0B, 0x80, 0xBA, 0xE5, 0x4F, 0x35, 0x24, 0x59, 0x0A, 0xBD, 0x52, 0xB6, 0x7D, 0x91, 0x01, 0x24, 0x75, 0xB8, 0x16, 0xDB, 0x73, 0x4E, 0x13, 0x94, 0x0F, 0x16, 0x9F, 0xCE, 0xDD, 0xC5, 0x2C, 0xD9, 0xA0, 0xAE, 0x23, 0xD0, 0x2A, 0x94, 0x9A, 0x28, 0x42, 0xA0, 0x2A, 0x76, 0xF1, 0xA4, 0x85, 0x00, 0x7A, 0xD5, 0x70, 0xFC, 0xC0, 0x37, 0xB0, 0x02, 0xFE, 0x37, 0x9D, 0x45, 0xD9, 0x05, 0xA6, 0x86, 0xD4, 0xBF, 0x26, 0x41, 0x2E, 0x9E, 0x50, 0x82, 0xE7, 0x51, 0x93, 0x34, 0x26, 0xEA, 0xE7, 0x07, 0x2D, 0xA4, 0x82, 0xEA, 0x11, 0x5B, 0x73, 0xB5, 0xDB, 0xFE, 0xD8, 0x12, 0x81, 0xE2, 0xA2, 0x89, 0x60, 0x44, 0x4A, 0x12, 0xBD, 0x9C, 0xE6, 0x8F, 0x7B, 0x8B, 0xC4, 0x8A, 0x7F, 0x83, 0xD9, 0x52, 0xA3, 0xBD, 0xF6, 0x3C, 0xDA, 0x94, 0xB1, 0xB7, 0x3D, 0x15, 0x8A, 0xB1, 0x6F, 0x9E, 0x7F, 0x53, 0x60, 0xE5, 0x84, 0x9D, 0x55, 0x4B, 0x92, 0xB3, 0x47, 0x89, 0x70, 0x68, 0xF4, 0xBC, 0xDD, 0xBC, 0x91, 0x6F, 0x7E, 0xF1, 0xB9, 0x93, 0xD9, 0xD3, 0xEB, 0x4A, 0xA7, 0x5E, 0x31, 0x82, 0x31, 0x74, 0xFC, 0x63, 0xA7, 0x0D, 0xF1, 0x80, 0x6E, 0xFF, 0x2D, 0xEC, 0x98, 0x82, 0x72, 0x2A, 0x30, 0xB4, 0x91, 0x5E, 0x67, 0x9D, 0x94, 0xF6, 0x99, 0x95, 0x97, 0xB6, 0x09, 0x5F, 0xEC, 0x48, 0xC6, 0x4D, 0xA0, 0x0F, 0x61, 0x58, 0x46, 0x26, 0xF5, 0x0D, 0x9B, 0x54, 0xCC, 0x94, 0xED, 0xF3, 0xD4, 0xDC, 0x85, 0x7C, 0x50, 0x71, 0x2F, 0x8A, 0xB8, 0x22, 0xA8, 0x7F, 0x4F, 0xFC, 0x7E, 0x50, 0x9A, 0x46, 0x69, 0xA7, 0x75, 0x4C, 0x56, 0x10, 0x22, 0xC0, 0x63, 0x75, 0xC7, 0x88, 0xF5, 0x4D, 0x58, 0xDC, 0x25, 0x1C, 0xAF, 0xD6, 0x23, 0xAC, 0x83, 0xCA, 0x9E, 0xBB, 0xE3, 0x92, 0x87, 0xE4, 0xFB, 0x54, 0xE6, 0x2E, 0x3C, 0x48, 0xCF, 0x8A, 0x2C, 0xC2, 0xE5, 0xC0, 0x5F, 0x27, 0x14, 0x1E, 0xA7, 0x2B, 0x72, 0x88, 0x59, 0xBF, 0x62, 0xCF, 0xCE, 0xBC, 0x55, 0x07, 0xA3, 0x71, 0x38, 0x33, 0x63, 0x2B, 0xEF, 0x4C, 0xEA, 0x24, 0x8D, 0x35, 0x0A, 0x24, 0x78, 0x02, 0xE3, 0xAA, 0xC6, 0xF2, 0x83, 0x83, 0x49, 0x00, 0x73, 0xBC, 0xF5, 0xFF, 0x95, 0x25, 0x05, 0xE3, 0x76, 0x41, 0xDE, 0x1E, 0xB0, 0x78, 0xB5, 0x18, 0x37, 0xAA, 0x61, 0xFB, 0x40, 0xB6, 0x8A, 0x78, 0x25, 0xF2, 0x08, 0xF9, 0x04, 0xC4, 0x11, 0xD1, 0xA0, 0x07, 0xC1, 0x59, 0x3A, 0x6B, 0x0D, 0x8C, 0x93, 0xFB, 0x99, 0x99, 0x05, 0x3D, 0xA7, 0x89, 0xA0, 0xB6, 0xCC, 0xB9, 0xBE, 0xE2, 0xB2, 0x75, 0x2A, 0x26, 0x63, 0x73, 0x10, 0x3E, 0x4C, 0x04, 0x36, 0xA1, 0x7D, 0x38, 0x63, 0x91, 0xC6, 0x25, 0x06, 0x0A, 0xE6, 0x88, 0x5A, 0xC2, 0x3C, 0xB0, 0x91, 0x19, 0x1E, 0x8D, 0x64, 0x34, 0xEC, 0x70, 0x39, 0x6F, 0x8C, 0xFE, 0x83, 0x6C, 0xF9, 0x8F, 0x90, 0xE3, 0x2C, 0x0F, 0x12, 0xFF, 0x4F, 0xBC, 0xBE, 0xD7, 0xF6, 0x8E, 0xC9, 0x37, 0xB7, 0x43, 0xD5, 0x03, 0xC6, 0x3F, 0xF3, 0x7C, 0x8C, 0x79, 0x60, 0xA7, 0xB4, 0x39, 0xFB, 0x10, 0xA2, 0x00, 0x03, 0x42, 0x4E, 0x8F, 0xA8, 0xC0, 0xDB, 0x5E, 0xEA, 0x97, 0x66, 0x8B, 0xC2, 0xE3, 0x81, 0xC6, 0xB3, 0x23, 0x73, 0x95, 0xAE, 0xF0, 0x9C, 0x56, 0xAF, 0xB7, 0x9F, 0x65, 0x88, 0x16, 0xB2, 0x2E, 0xDB, 0x68, 0xFE, 0x6E, 0xF3, 0x45, 0x9A, 0xD8, 0xB5, 0xE1, 0x1F, 0x22, 0x5A, 0x6C, 0xE4, 0x17, 0x8D, 0x22, 0x42, 0x00, 0x10, 0x6F, 0x20, 0x52, 0xC1, 0x29, 0x77, 0xC0, 0x40, 0x97, 0x19, 0xFE, 0x41, 0x08, 0xCD, 0xF6, 0xBC, 0x5E, 0x79, 0x04, 0x4C, 0x2E, 0xAE, 0x03, 0xCD, 0xCB, 0x54, 0xC3, 0x1C, 0xC0, 0x44, 0xC3, 0xDD, 0x86, 0x61, 0xDC, 0xA6, 0x16, 0x0E, 0x39, 0xAB, 0x1A, 0x86, 0xE4, 0xA8, 0x4B, 0xC4, 0x62, 0xC5, 0x7E, 0x57, 0xD1, 0xF4, 0x39, 0x96, 0xCA, 0x9F, 0x8F, 0xA6, 0x03, 0x06, 0x8D, 0x7A, 0x0F, 0xF7, 0xCF, 0x86, 0x08, 0x0D, 0xB8, 0x28, 0x87, 0x70, 0x82, 0x33, 0x71, 0xE8, 0x5B, 0xF0, 0x6A, 0x27, 0xE6, 0x90, 0xC0, 0x4D, 0x9E, 0x97, 0x1E, 0x69, 0x0D, 0xFA, 0x5A, 0xD0, 0x37, 0x3E, 0xB3, 0x69, 0x14, 0xC8, 0x46, 0xE5, 0x9C, 0xA4, 0x30, 0x01, 0xEF, 0xE9, 0x87, 0x94, 0xBB, 0x8D, 0xBA, 0x52, 0x9A, 0x7A, 0x53, 0x29, 0x5D, 0xCC, 0x95, 0xE8, 0xE6, 0xD2, 0x9E, 0x32, 0x29, 0xA6, 0x21, 0xC1, 0x88, 0x9F, 0x10, 0x0C, 0xF9, 0x8C, 0x31, 0x94, 0xBE, 0xA9, 0xD2, 0x39, 0xD3, 0xA5, 0xFB, 0xAD, 0xEC, 0x2E, 0x41, 0x34, 0x37, 0x9B, 0x1A, 0x29, 0xDC, 0x24, 0x03, 0x08, 0x12, 0xE9, 0xDD, 0x7C, 0x53, 0x8B, 0xBD, 0xC7, 0x00, 0x6E, 0xB3, 0xB0, 0xAC, 0x11, 0x65, 0xBA, 0xDA, 0x96, 0x5C, 0x57, 0x14, 0x10, 0xED, 0xF1, 0x7C, 0x86, 0x60, 0x75, 0x3B, 0xB2, 0x59, 0x83, 0xBC, 0x08, 0xC0, 0x3F, 0x6D, 0xE0, 0xA6, 0x2C, 0x21, 0x08, 0xEF, 0x16, 0x16, 0x0E, 0x8D, 0xE2, 0x9B, 0xD3, 0xC1, 0xE5, 0x51, 0xD0, 0x66, 0xDC, 0xCE, 0xCA, 0x31, 0x4A, 0x5A, 0x29, 0x40, 0x34, 0xEC, 0x85, 0x8B, 0xA5, 0x62, 0xBC, 0x49, 0xA3, 0x88, 0x76, 0xED, 0xAE, 0x78, 0xF2, 0xC8, 0x30, 0x5C, 0x95, 0x8D, 0xDA, 0x18, 0xC4, 0x8F, 0x45, 0x70, 0xF4, 0x7D, 0x0E, 0x2F, 0xF6, 0xB4, 0x2A, 0xE8, 0xF8, 0x7C, 0x2A, 0xFC, 0x4B, 0xE6, 0xB3, 0x9B, 0xAA, 0x85, 0x49, 0x73, 0x2A, 0x9C, 0x7A, 0x42, 0x12, 0x21, 0xBE, 0x15, 0xD4, 0xCC, 0x79, 0xD2, 0xF0, 0x8C, 0xD1, 0x40, 0x52, 0xC9, 0x29, 0xF6, 0x75, 0x2C, 0x88, 0xE6, 0xFA, 0x8D, 0x37, 0x3A, 0x1F, 0xD1, 0x58, 0x51, 0xE3, 0x65, 0x6B, 0x30, 0x9F, 0x28, 0x20, 0x98, 0x7C, 0xA6, 0xE3, 0x73, 0xB5, 0x0B, 0x73, 0x36, 0xA1, 0xFE, 0x1A, 0xFF, 0xDC, 0xC8, 0x62, 0xC3, 0x9A, 0x15, 0x9B, 0x97, 0x69, 0x41, 0xA7, 0x3A, 0x2F, 0xE0, 0x70, 0xD4, 0x3B, 0x5D, 0x0B, 0xBE, 0x84, 0xFE, 0xDD, 0x3B, 0x1E, 0x54, 0xFA, 0x47, 0x83, 0x7A, 0x5D, 0xC1, 0x87, 0x4D, 0x79, 0x72, 0x9C, 0xDC, 0x00, 0x66, 0xAA, 0x45, 0x53, 0x26, 0x88, 0x77, 0xA8, 0x78, 0x05, 0xCA, 0x8E, 0x9F, 0x34, 0x3A, 0x18, 0xBE, 0x07, 0xCA, 0x58, 0xCE, 0xA0, 0x8A, 0x50, 0xE5, 0x7E, 0x9B, 0x90, 0xC4, 0x8E, 0x4C, 0xB7, 0x00, 0x31, 0x5D, 0xCA, 0x83, 0xA4, 0xE3, 0x5C, 0xFD, 0x62, 0x6E, 0x5E, 0xB1, 0x4F, 0x19, 0x45, 0x43, 0xAA, 0x60, 0xB2, 0x55, 0x04, 0xA3, 0x05, 0x08, 0xAB, 0x48, 0xE3, 0xD5, 0x7E, 0x48, 0x6D, 0x57, 0x3D, 0xDA, 0x9D, 0x51, 0x1C, 0x66, 0x00, 0x65, 0x3E, 0xE3, 0xDD, 0xF7, 0x16, 0x69, 0xA3, 0xCB, 0x3E, 0xE7, 0x5B, 0xAA, 0x96, 0xB5, 0xB7, 0x7C, 0xB6, 0xC7, 0x83, 0x11, 0x83, 0x04, 0xFB, 0xEA, 0xFD, 0x6D, 0xE2, 0x4C, 0x83, 0x1D, 0x82, 0x67, 0x2B, 0xF8, 0xC7, 0xA7, 0x0E, 0x63, 0xC1, 0xD5, 0x0A, 0x1C, 0xA9, 0x5D, 0x05, 0xCE, 0x0A, 0xB6, 0x4B, 0x26, 0x01, 0x81, 0xFD, 0xF0, 0xDA, 0x73, 0x9F, 0xC8, 0x45, 0xAA, 0x0D, 0x4B, 0x70, 0x53, 0x18, 0xF7, 0x65, 0xEA, 0x24, 0x8A, 0xBF, 0x1A, 0x5F, 0x6C, 0x24, 0x68, 0x15, 0x98, 0xB8, 0x31, 0xEA, 0x86, 0x3C, 0xB5, 0xC9, 0xEF, 0xA1, 0xD6, 0x0C, 0x49, 0x44, 0xA8, 0xCF, 0x53, 0x54, 0x13, 0x21, 0x27, 0x32, 0x5A, 0xAE, 0xD0, 0xBB, 0x0D, 0x82, 0x22, 0xDD, 0x38, 0xD2, 0xA8, 0xA9, 0x73, 0xC1, 0x0D, 0xC8, 0x34, 0xF3, 0xA1, 0x1F, 0xCE, 0x0C, 0xDD, 0x24, 0xBE, 0x7A, 0xB8, 0x38, 0x7E, 0xC5, 0xCA, 0xEC, 0x5E, 0xDF, 0x86, 0x36, 0xC9, 0xE7, 0xB3, 0xD4, 0xF8, 0x9B, 0xC2, 0xCF, 0x80, 0x27, 0xBD, 0xBC, 0x9A, 0x94, 0xF2, 0xF8, 0xB8, 0x95, 0xAF, 0x17, 0xFE, 0x35, 0xCB, 0xC1, 0x6F, 0xFB, 0x34, 0x31, 0xE3, 0xDD, 0x44, 0x62, 0x2D, 0x9C, 0xF2, 0x6D, 0xB2, 0x7D, 0x96, 0x8F, 0x8E, 0xD1, 0x8D, 0xF5, 0x74, 0xAE, 0xC8, 0x25, 0x30, 0x64, 0x69, 0x76, 0x23, 0x24, 0x31, 0xF3, 0x00, 0x87, 0xDD, 0x6D, 0xB5, 0x79, 0xDB, 0x21, 0xB4, 0x5C, 0x07, 0xAD, 0xC1, 0x3C, 0x86, 0x88, 0xB1, 0x3D, 0xB6, 0xA6, 0x6E, 0x89, 0x7A, 0x32, 0x27, 0xB3, 0x2B, 0xF2, 0x93, 0xE5, 0xC1, 0x48, 0x77, 0xE8, 0xFF, 0xB2, 0x3D, 0x4E, 0xFE, 0x52, 0x62, 0xD7, 0x61, 0xD4, 0x46, 0xEC, 0x5E, 0xAD, 0x05, 0xBB, 0xDC, 0xAA, 0x45, 0xB2, 0xA0, 0x81, 0x9E, 0x78, 0xE5, 0x89, 0x46, 0xCF, 0xAB, 0x8E, 0x08, 0xE6, 0xAB, 0xA0, 0x28, 0x47, 0x0C, 0xD3, 0x4E, 0x81, 0x42, 0x51, 0xE4, 0x63, 0xEC, 0xF1, 0x50, 0x5D, 0xB6, 0xAC, 0xE2, 0xFC, 0x8D, 0x05, 0x01, 0x2A, 0x08, 0xFB, 0x96, 0xEA, 0x0C, 0xDC, 0x0F, 0x43, 0x63, 0x21, 0x69, 0x2C, 0xB9, 0x3B, 0xC7, 0xDB, 0xBE, 0xA7, 0xB6, 0xFF, 0x80, 0xB2, 0x0B, 0xE9, 0x95, 0xD1, 0x4E, 0xB0, 0xD0, 0xEA, 0x9F, 0x7D, 0xB2, 0x06, 0xCB, 0xDC, 0x18, 0xC1, 0x82, 0xB3, 0xF7, 0x58, 0xF3, 0x17, 0x9D, 0x28, 0x89, 0x64, 0x0D, 0x7B, 0xFF, 0x9C, 0xEF, 0xE6, 0xBE, 0x1B, 0xCB, 0x03, 0x38, 0x9A, 0x8A, 0x47, 0x68, 0x4B, 0x8C, 0xA6, 0x6D, 0xD4, 0x8B, 0xF9, 0x04, 0x21, 0xF1, 0x72, 0xBA, 0x39, 0xEB, 0x2E, 0xB0, 0xF5, 0x97, 0x92, 0xAA, 0x86, 0x43, 0x1A, 0x62, 0x10, 0x4C, 0x98, 0xA0, 0x90, 0x26, 0xD1, 0xFC, 0x6E, 0xC3, 0x5F, 0x46, 0x36, 0x22, 0xA9, 0x58, 0xBE, 0x4A, 0x4F, 0x6F, 0x1A, 0x2D, 0xA8, 0x4B, 0x74, 0x3D, 0x58, 0x68, 0x55, 0x69, 0x5E, 0xDD, 0x79, 0xB0, 0xC2, 0xAC, 0x0E, 0xDA, 0xB4, 0xCF, 0x19, 0x4F, 0xD7, 0xB4, 0x3C, 0x1A, 0xB0, 0xFE, 0x13, 0x3A, 0x8B, 0x89, 0x0D, 0xB9, 0x4B, 0x24, 0x5A, 0xB3, 0x8E, 0xB7, 0xE3, 0x77, 0xCF, 0x15, }, .pub_len = 2592, }, { .name = "ML-DSA 87 (seed only)", .parameter_set = CKP_ML_DSA_87, .priv_seed = { 0x4F, 0x3B, 0x00, 0x56, 0x2F, 0xC0, 0xF8, 0x5E, 0xAF, 0x8C, 0x7B, 0xC2, 0x33, 0xA5, 0xAC, 0xF7, 0x88, 0xD9, 0x06, 0x87, 0x39, 0xF7, 0xFA, 0xF4, 0x0D, 0xBC, 0x76, 0xA4, 0xF0, 0xA2, 0x8C, 0x74, }, .priv_seed_len = 32, .pub = { 0xCA, 0xDE, 0xD2, 0x24, 0xB8, 0xF0, 0xB4, 0xCE, 0x30, 0x19, 0x85, 0x30, 0x5F, 0x5E, 0xCF, 0xF5, 0x03, 0xDD, 0x4E, 0xCC, 0xF0, 0x69, 0xB9, 0xAB, 0x3C, 0xFA, 0x07, 0x4E, 0x89, 0x22, 0x41, 0xBB, 0x66, 0x7F, 0x74, 0x0D, 0xF1, 0x71, 0xE4, 0x95, 0x5A, 0x29, 0xF6, 0x96, 0x53, 0x19, 0x2F, 0xDB, 0x7E, 0x65, 0xAB, 0x5C, 0x64, 0xCC, 0xDD, 0xBC, 0x4B, 0x91, 0xAB, 0x36, 0x3F, 0x5A, 0xA9, 0x8B, 0x3D, 0xAF, 0xAB, 0xFF, 0x8A, 0xFC, 0x6C, 0x71, 0x1A, 0x74, 0xB7, 0x4C, 0x9C, 0xBD, 0x6D, 0xA2, 0x33, 0xE9, 0x08, 0x39, 0x80, 0x28, 0xA0, 0x6A, 0xF0, 0xA1, 0x0E, 0x79, 0x4B, 0xA5, 0xC5, 0xE0, 0x06, 0xA1, 0x0A, 0x4D, 0xA9, 0x64, 0xC1, 0x55, 0xFC, 0xBE, 0x68, 0x2A, 0x61, 0xEA, 0x77, 0xC6, 0x59, 0xB5, 0xF8, 0xFD, 0x8A, 0xFC, 0xFA, 0xFA, 0xDA, 0x4F, 0xDC, 0x01, 0x45, 0x19, 0x85, 0x90, 0x63, 0x1C, 0x76, 0x87, 0x5B, 0xBE, 0xC7, 0x67, 0x88, 0x9F, 0xAB, 0xD0, 0xC7, 0x30, 0x20, 0x90, 0x6B, 0x86, 0x3A, 0x38, 0xFE, 0x83, 0x14, 0xAB, 0xE7, 0xE7, 0x31, 0x5F, 0xB9, 0x54, 0x21, 0x57, 0x2C, 0x32, 0x55, 0x20, 0xEE, 0x55, 0x45, 0xD8, 0x9B, 0x70, 0xFA, 0x4F, 0x70, 0x6A, 0xEF, 0x39, 0x78, 0x30, 0x36, 0x4B, 0x23, 0x1E, 0x18, 0xDB, 0xE0, 0x1E, 0x49, 0xDD, 0x80, 0x39, 0x69, 0x95, 0x4E, 0x02, 0x43, 0x8C, 0x5D, 0xA3, 0xA4, 0xCC, 0x61, 0x4B, 0x37, 0x26, 0xD2, 0x9C, 0xF6, 0xEF, 0x4B, 0x64, 0x49, 0xBE, 0x9E, 0x6A, 0x95, 0x0F, 0x18, 0xEE, 0xAA, 0xEF, 0xFF, 0xA5, 0x8C, 0xF6, 0x0D, 0x98, 0x6F, 0x01, 0x73, 0x2B, 0x47, 0x56, 0x3D, 0x2C, 0x84, 0xA6, 0x82, 0x17, 0xE3, 0x56, 0x52, 0x17, 0x7D, 0x1C, 0x9D, 0x11, 0x17, 0x5F, 0xE4, 0xDA, 0x61, 0x22, 0x64, 0x1B, 0x53, 0x59, 0x8F, 0xB6, 0x45, 0x8A, 0x9B, 0x99, 0x3D, 0x5A, 0xB4, 0xB8, 0x5A, 0xFA, 0x4F, 0x7E, 0x99, 0x03, 0x78, 0x05, 0x13, 0xF4, 0x99, 0x32, 0x55, 0xF8, 0xE2, 0xEA, 0xA8, 0x72, 0xA8, 0x4F, 0xDC, 0x50, 0x92, 0x49, 0x60, 0x39, 0x19, 0x15, 0xB1, 0x1B, 0xA6, 0x11, 0x17, 0x10, 0x35, 0xD3, 0x43, 0x2F, 0x9E, 0xC3, 0xE7, 0xC4, 0x7C, 0x94, 0xA6, 0x6B, 0xF3, 0xE4, 0x2F, 0x65, 0xC3, 0x55, 0x21, 0x3A, 0xFE, 0x02, 0xDC, 0x76, 0xCC, 0xD9, 0xCD, 0x8D, 0xA5, 0xDD, 0x00, 0x88, 0xEF, 0xC8, 0x48, 0x0E, 0xE6, 0x05, 0x13, 0x44, 0xEC, 0x8E, 0x0B, 0x0C, 0xCD, 0x36, 0x96, 0xF2, 0xEF, 0xF4, 0x66, 0x45, 0x11, 0xC7, 0x95, 0x1C, 0x01, 0x60, 0xA3, 0xB2, 0x6D, 0x8A, 0x36, 0xBA, 0x57, 0xC5, 0x5A, 0x99, 0x2F, 0xA2, 0x01, 0x70, 0x9D, 0x20, 0x63, 0xEF, 0x86, 0x79, 0x6C, 0xD3, 0xCA, 0xAA, 0x10, 0x14, 0x18, 0xDA, 0xE9, 0xA8, 0x66, 0xD1, 0x54, 0x22, 0xC3, 0xA9, 0x70, 0x20, 0x82, 0xD6, 0x73, 0x50, 0x6B, 0xA9, 0x7C, 0xA6, 0x51, 0x2B, 0xCC, 0x86, 0x55, 0x95, 0xFF, 0x99, 0x97, 0xA5, 0x89, 0xFB, 0x60, 0x5A, 0x9A, 0x52, 0xFD, 0xCA, 0xB3, 0xF4, 0x21, 0x59, 0x28, 0xE9, 0x47, 0x8A, 0x46, 0xD0, 0x8E, 0x22, 0xFD, 0x87, 0x74, 0xB2, 0x7A, 0x5A, 0xCB, 0x39, 0x4B, 0x6A, 0x47, 0x54, 0x13, 0x8D, 0xBE, 0x48, 0x1D, 0x6B, 0x8F, 0x2C, 0xE4, 0x37, 0x51, 0xF3, 0x7C, 0xF6, 0x25, 0xB4, 0x7B, 0x40, 0xE9, 0x45, 0xEB, 0xD2, 0x08, 0x36, 0xCD, 0x38, 0xA1, 0x80, 0xAE, 0x64, 0x54, 0xF8, 0x6A, 0xF7, 0xEC, 0x41, 0x52, 0xBD, 0x66, 0x0E, 0xB2, 0x25, 0x49, 0xE1, 0x78, 0xD2, 0x36, 0x39, 0xF0, 0x00, 0x17, 0x1B, 0x33, 0x62, 0x8C, 0x02, 0x5C, 0x73, 0x7A, 0x42, 0x62, 0x47, 0x92, 0xD5, 0x10, 0xEB, 0x32, 0x95, 0x96, 0x55, 0x99, 0xEA, 0x2A, 0x35, 0x13, 0xE0, 0x79, 0x08, 0x2E, 0x1E, 0x55, 0xA9, 0xE7, 0xC1, 0xC7, 0x75, 0x6E, 0xA2, 0xE2, 0x95, 0x71, 0x85, 0x54, 0x0C, 0xFF, 0xB5, 0x67, 0xF7, 0x4A, 0x60, 0x6D, 0xD2, 0x1F, 0x4D, 0xC3, 0xB1, 0xDD, 0x1D, 0xB7, 0x67, 0x5E, 0xFE, 0x0A, 0xE4, 0x17, 0x0F, 0xE5, 0x9B, 0x7F, 0x8F, 0x55, 0x76, 0xEA, 0x0B, 0x1D, 0xEF, 0x1D, 0x29, 0x14, 0xE2, 0x25, 0x92, 0x79, 0xE8, 0x2D, 0xA6, 0x3C, 0x06, 0xD1, 0x7A, 0x46, 0x27, 0xE6, 0x42, 0x2F, 0x5B, 0x4A, 0x0C, 0xFF, 0x30, 0x29, 0x4D, 0x5D, 0x10, 0xD3, 0xF2, 0x6C, 0x51, 0x58, 0x01, 0x4F, 0xDC, 0xAF, 0x7D, 0x60, 0x53, 0xE9, 0xF1, 0x9D, 0x7D, 0x68, 0xEF, 0xB7, 0x04, 0xD9, 0xC2, 0x1E, 0x52, 0x95, 0x51, 0x58, 0x2E, 0x29, 0x64, 0xD1, 0x59, 0x2E, 0x97, 0x4F, 0x6C, 0xE0, 0x67, 0x3E, 0x67, 0xFB, 0xE0, 0xB3, 0xBD, 0x21, 0xD6, 0x65, 0x20, 0x2C, 0xF2, 0x28, 0x3B, 0xA9, 0xA4, 0x93, 0x7F, 0x22, 0x99, 0xE5, 0xFB, 0x1A, 0xA7, 0x5A, 0xE2, 0x25, 0xA5, 0xAE, 0x4E, 0xEB, 0xCE, 0x61, 0x54, 0xBA, 0x69, 0xDC, 0x90, 0x6D, 0xC0, 0xD4, 0xE8, 0x14, 0x74, 0x82, 0x13, 0x50, 0x13, 0x60, 0xB0, 0x41, 0xD3, 0xDF, 0x81, 0x1E, 0x13, 0xB3, 0x10, 0x3F, 0x3B, 0x71, 0x7B, 0x60, 0x11, 0x3C, 0xE9, 0x6C, 0x26, 0x7D, 0xD0, 0x92, 0xA8, 0xF6, 0x54, 0x68, 0xBD, 0x88, 0xF8, 0x54, 0x11, 0x34, 0x77, 0x58, 0xF5, 0x40, 0xE8, 0x61, 0xE0, 0x96, 0x10, 0x8E, 0xEB, 0x00, 0x2C, 0x8D, 0x81, 0xB0, 0xC6, 0xF5, 0xAD, 0x86, 0x67, 0xE4, 0xE1, 0x15, 0x06, 0x64, 0x9D, 0x82, 0x98, 0xCD, 0x5C, 0xB3, 0x2B, 0x3B, 0x98, 0x10, 0x92, 0x67, 0x8F, 0xEC, 0x40, 0xE0, 0x5B, 0x95, 0xA6, 0x64, 0x1E, 0xE5, 0x86, 0xE7, 0x01, 0x07, 0xC1, 0xDF, 0x9A, 0x7F, 0xD3, 0x05, 0x4D, 0x6A, 0xDD, 0xE8, 0x57, 0xA7, 0x02, 0x8A, 0x4F, 0xF9, 0x54, 0x16, 0x6F, 0x02, 0x59, 0x14, 0x43, 0x2E, 0x9D, 0x4B, 0x2E, 0x02, 0x69, 0x6D, 0x85, 0x5B, 0xC3, 0x7A, 0x49, 0x0B, 0xC4, 0x49, 0xBE, 0x6F, 0x91, 0x75, 0xDE, 0x94, 0xA8, 0x40, 0x6E, 0xB6, 0x25, 0x2F, 0xF4, 0x79, 0xB2, 0x53, 0xBC, 0x8E, 0x1C, 0x7A, 0xE3, 0x46, 0x29, 0xA1, 0x30, 0xF8, 0x53, 0x27, 0xB0, 0x18, 0x6D, 0x01, 0xCA, 0xBD, 0x68, 0xD8, 0x3C, 0x8B, 0x15, 0xD9, 0xEE, 0x64, 0xD5, 0x4D, 0xC3, 0xE7, 0xA5, 0xD1, 0xA2, 0x13, 0x9C, 0xC8, 0xCB, 0x26, 0x72, 0xB0, 0x68, 0xDE, 0x8B, 0xE0, 0x4C, 0x85, 0xCF, 0xC5, 0x02, 0x14, 0xA2, 0x2F, 0xFE, 0x05, 0xA6, 0x0A, 0x82, 0xC7, 0xFD, 0x8D, 0x86, 0xA8, 0x02, 0x19, 0x96, 0x91, 0x8B, 0x98, 0x12, 0x79, 0xCA, 0xB2, 0x74, 0x93, 0xC6, 0x89, 0x7A, 0x55, 0xDF, 0xEB, 0x22, 0xDF, 0x89, 0x61, 0x4D, 0x07, 0x8C, 0x39, 0x24, 0x87, 0x98, 0xBB, 0x8F, 0x2A, 0xDD, 0x1D, 0x6F, 0x8B, 0x06, 0xEF, 0xAB, 0x57, 0xC6, 0xEF, 0x1C, 0xE0, 0xA9, 0x07, 0xE2, 0xE7, 0x23, 0xF5, 0x5E, 0xB3, 0x68, 0xCD, 0xAF, 0x8B, 0xFA, 0x6B, 0x8E, 0x74, 0xDE, 0xDE, 0x8B, 0xA4, 0x85, 0x0E, 0x69, 0x6B, 0x1A, 0x3A, 0x39, 0x08, 0xE2, 0x9F, 0x03, 0xC2, 0x22, 0xCC, 0x2F, 0x97, 0x98, 0x73, 0x6C, 0x31, 0xC8, 0x6D, 0x2A, 0x47, 0x3B, 0xA6, 0xB5, 0x0F, 0x32, 0x87, 0xDF, 0x4C, 0x4F, 0x82, 0xD8, 0x83, 0x72, 0x95, 0x1B, 0x5C, 0x06, 0xC0, 0x63, 0x27, 0x6A, 0x19, 0x4D, 0x4D, 0x1C, 0xAA, 0x21, 0xD5, 0xFF, 0x1A, 0xB2, 0x7F, 0xC9, 0xC1, 0x79, 0x54, 0x55, 0xFB, 0x5B, 0xF9, 0x3F, 0x0B, 0x89, 0x4C, 0x5A, 0x9B, 0xF4, 0x2E, 0x55, 0xAE, 0x5B, 0xBF, 0x07, 0xE0, 0x13, 0x9A, 0xDE, 0x1A, 0xF2, 0xD4, 0x10, 0x12, 0x75, 0x31, 0x5D, 0xBE, 0xAD, 0x21, 0x9D, 0x6F, 0xF6, 0xC3, 0xC9, 0xC5, 0xAF, 0x6B, 0x14, 0x9B, 0xA7, 0x1E, 0x6D, 0xD3, 0x45, 0x3C, 0xCA, 0xC0, 0xC9, 0xCE, 0x85, 0x7E, 0x3A, 0x0A, 0x0B, 0x3E, 0x7B, 0x9C, 0xAD, 0x9D, 0x2C, 0xBE, 0xA1, 0x6D, 0xA5, 0x68, 0x00, 0x63, 0xD3, 0x2B, 0x03, 0x15, 0xDD, 0x2C, 0x76, 0xD4, 0x9D, 0x48, 0xBE, 0xE2, 0x57, 0xA6, 0xAD, 0xB4, 0xF4, 0x43, 0x80, 0x70, 0x27, 0xC8, 0xC9, 0x29, 0x59, 0x9E, 0x7F, 0x12, 0x39, 0x05, 0x28, 0x37, 0xB0, 0x69, 0xAE, 0xC6, 0xB6, 0x2F, 0x6F, 0x7C, 0x91, 0x3C, 0x0A, 0x3A, 0xCA, 0x73, 0xDA, 0x26, 0x97, 0xFF, 0x1A, 0x5C, 0x48, 0x06, 0x90, 0x83, 0x70, 0x8B, 0x86, 0xAF, 0x96, 0x90, 0x6F, 0x28, 0x74, 0xFA, 0x69, 0x14, 0xB7, 0x29, 0x1B, 0x02, 0xCC, 0x52, 0x50, 0xFD, 0xCD, 0x6C, 0xBD, 0x61, 0xF1, 0x12, 0x48, 0x4D, 0x61, 0x81, 0xEF, 0xBE, 0xA2, 0x28, 0xA0, 0xA5, 0x80, 0xB4, 0xB7, 0xE6, 0xF8, 0xF0, 0x80, 0x6F, 0x2B, 0xA7, 0x64, 0x55, 0x8F, 0x4B, 0x52, 0x1F, 0x93, 0x3D, 0x8D, 0xD5, 0x56, 0xA7, 0xA2, 0x55, 0x60, 0x09, 0x4F, 0xD7, 0xBC, 0x5A, 0x0F, 0x82, 0x10, 0x44, 0x60, 0x36, 0x2D, 0xBC, 0x92, 0xCC, 0x0E, 0x7D, 0xF9, 0xE4, 0x38, 0x49, 0xDB, 0xC9, 0x0E, 0x67, 0xE2, 0x03, 0xB4, 0x39, 0xE8, 0xC6, 0xDC, 0x3C, 0xF2, 0x3C, 0xDE, 0x5F, 0x91, 0x38, 0x86, 0xD9, 0x44, 0x5D, 0x6A, 0xC6, 0x8B, 0x0B, 0x80, 0xBA, 0xE5, 0x4F, 0x35, 0x24, 0x59, 0x0A, 0xBD, 0x52, 0xB6, 0x7D, 0x91, 0x01, 0x24, 0x75, 0xB8, 0x16, 0xDB, 0x73, 0x4E, 0x13, 0x94, 0x0F, 0x16, 0x9F, 0xCE, 0xDD, 0xC5, 0x2C, 0xD9, 0xA0, 0xAE, 0x23, 0xD0, 0x2A, 0x94, 0x9A, 0x28, 0x42, 0xA0, 0x2A, 0x76, 0xF1, 0xA4, 0x85, 0x00, 0x7A, 0xD5, 0x70, 0xFC, 0xC0, 0x37, 0xB0, 0x02, 0xFE, 0x37, 0x9D, 0x45, 0xD9, 0x05, 0xA6, 0x86, 0xD4, 0xBF, 0x26, 0x41, 0x2E, 0x9E, 0x50, 0x82, 0xE7, 0x51, 0x93, 0x34, 0x26, 0xEA, 0xE7, 0x07, 0x2D, 0xA4, 0x82, 0xEA, 0x11, 0x5B, 0x73, 0xB5, 0xDB, 0xFE, 0xD8, 0x12, 0x81, 0xE2, 0xA2, 0x89, 0x60, 0x44, 0x4A, 0x12, 0xBD, 0x9C, 0xE6, 0x8F, 0x7B, 0x8B, 0xC4, 0x8A, 0x7F, 0x83, 0xD9, 0x52, 0xA3, 0xBD, 0xF6, 0x3C, 0xDA, 0x94, 0xB1, 0xB7, 0x3D, 0x15, 0x8A, 0xB1, 0x6F, 0x9E, 0x7F, 0x53, 0x60, 0xE5, 0x84, 0x9D, 0x55, 0x4B, 0x92, 0xB3, 0x47, 0x89, 0x70, 0x68, 0xF4, 0xBC, 0xDD, 0xBC, 0x91, 0x6F, 0x7E, 0xF1, 0xB9, 0x93, 0xD9, 0xD3, 0xEB, 0x4A, 0xA7, 0x5E, 0x31, 0x82, 0x31, 0x74, 0xFC, 0x63, 0xA7, 0x0D, 0xF1, 0x80, 0x6E, 0xFF, 0x2D, 0xEC, 0x98, 0x82, 0x72, 0x2A, 0x30, 0xB4, 0x91, 0x5E, 0x67, 0x9D, 0x94, 0xF6, 0x99, 0x95, 0x97, 0xB6, 0x09, 0x5F, 0xEC, 0x48, 0xC6, 0x4D, 0xA0, 0x0F, 0x61, 0x58, 0x46, 0x26, 0xF5, 0x0D, 0x9B, 0x54, 0xCC, 0x94, 0xED, 0xF3, 0xD4, 0xDC, 0x85, 0x7C, 0x50, 0x71, 0x2F, 0x8A, 0xB8, 0x22, 0xA8, 0x7F, 0x4F, 0xFC, 0x7E, 0x50, 0x9A, 0x46, 0x69, 0xA7, 0x75, 0x4C, 0x56, 0x10, 0x22, 0xC0, 0x63, 0x75, 0xC7, 0x88, 0xF5, 0x4D, 0x58, 0xDC, 0x25, 0x1C, 0xAF, 0xD6, 0x23, 0xAC, 0x83, 0xCA, 0x9E, 0xBB, 0xE3, 0x92, 0x87, 0xE4, 0xFB, 0x54, 0xE6, 0x2E, 0x3C, 0x48, 0xCF, 0x8A, 0x2C, 0xC2, 0xE5, 0xC0, 0x5F, 0x27, 0x14, 0x1E, 0xA7, 0x2B, 0x72, 0x88, 0x59, 0xBF, 0x62, 0xCF, 0xCE, 0xBC, 0x55, 0x07, 0xA3, 0x71, 0x38, 0x33, 0x63, 0x2B, 0xEF, 0x4C, 0xEA, 0x24, 0x8D, 0x35, 0x0A, 0x24, 0x78, 0x02, 0xE3, 0xAA, 0xC6, 0xF2, 0x83, 0x83, 0x49, 0x00, 0x73, 0xBC, 0xF5, 0xFF, 0x95, 0x25, 0x05, 0xE3, 0x76, 0x41, 0xDE, 0x1E, 0xB0, 0x78, 0xB5, 0x18, 0x37, 0xAA, 0x61, 0xFB, 0x40, 0xB6, 0x8A, 0x78, 0x25, 0xF2, 0x08, 0xF9, 0x04, 0xC4, 0x11, 0xD1, 0xA0, 0x07, 0xC1, 0x59, 0x3A, 0x6B, 0x0D, 0x8C, 0x93, 0xFB, 0x99, 0x99, 0x05, 0x3D, 0xA7, 0x89, 0xA0, 0xB6, 0xCC, 0xB9, 0xBE, 0xE2, 0xB2, 0x75, 0x2A, 0x26, 0x63, 0x73, 0x10, 0x3E, 0x4C, 0x04, 0x36, 0xA1, 0x7D, 0x38, 0x63, 0x91, 0xC6, 0x25, 0x06, 0x0A, 0xE6, 0x88, 0x5A, 0xC2, 0x3C, 0xB0, 0x91, 0x19, 0x1E, 0x8D, 0x64, 0x34, 0xEC, 0x70, 0x39, 0x6F, 0x8C, 0xFE, 0x83, 0x6C, 0xF9, 0x8F, 0x90, 0xE3, 0x2C, 0x0F, 0x12, 0xFF, 0x4F, 0xBC, 0xBE, 0xD7, 0xF6, 0x8E, 0xC9, 0x37, 0xB7, 0x43, 0xD5, 0x03, 0xC6, 0x3F, 0xF3, 0x7C, 0x8C, 0x79, 0x60, 0xA7, 0xB4, 0x39, 0xFB, 0x10, 0xA2, 0x00, 0x03, 0x42, 0x4E, 0x8F, 0xA8, 0xC0, 0xDB, 0x5E, 0xEA, 0x97, 0x66, 0x8B, 0xC2, 0xE3, 0x81, 0xC6, 0xB3, 0x23, 0x73, 0x95, 0xAE, 0xF0, 0x9C, 0x56, 0xAF, 0xB7, 0x9F, 0x65, 0x88, 0x16, 0xB2, 0x2E, 0xDB, 0x68, 0xFE, 0x6E, 0xF3, 0x45, 0x9A, 0xD8, 0xB5, 0xE1, 0x1F, 0x22, 0x5A, 0x6C, 0xE4, 0x17, 0x8D, 0x22, 0x42, 0x00, 0x10, 0x6F, 0x20, 0x52, 0xC1, 0x29, 0x77, 0xC0, 0x40, 0x97, 0x19, 0xFE, 0x41, 0x08, 0xCD, 0xF6, 0xBC, 0x5E, 0x79, 0x04, 0x4C, 0x2E, 0xAE, 0x03, 0xCD, 0xCB, 0x54, 0xC3, 0x1C, 0xC0, 0x44, 0xC3, 0xDD, 0x86, 0x61, 0xDC, 0xA6, 0x16, 0x0E, 0x39, 0xAB, 0x1A, 0x86, 0xE4, 0xA8, 0x4B, 0xC4, 0x62, 0xC5, 0x7E, 0x57, 0xD1, 0xF4, 0x39, 0x96, 0xCA, 0x9F, 0x8F, 0xA6, 0x03, 0x06, 0x8D, 0x7A, 0x0F, 0xF7, 0xCF, 0x86, 0x08, 0x0D, 0xB8, 0x28, 0x87, 0x70, 0x82, 0x33, 0x71, 0xE8, 0x5B, 0xF0, 0x6A, 0x27, 0xE6, 0x90, 0xC0, 0x4D, 0x9E, 0x97, 0x1E, 0x69, 0x0D, 0xFA, 0x5A, 0xD0, 0x37, 0x3E, 0xB3, 0x69, 0x14, 0xC8, 0x46, 0xE5, 0x9C, 0xA4, 0x30, 0x01, 0xEF, 0xE9, 0x87, 0x94, 0xBB, 0x8D, 0xBA, 0x52, 0x9A, 0x7A, 0x53, 0x29, 0x5D, 0xCC, 0x95, 0xE8, 0xE6, 0xD2, 0x9E, 0x32, 0x29, 0xA6, 0x21, 0xC1, 0x88, 0x9F, 0x10, 0x0C, 0xF9, 0x8C, 0x31, 0x94, 0xBE, 0xA9, 0xD2, 0x39, 0xD3, 0xA5, 0xFB, 0xAD, 0xEC, 0x2E, 0x41, 0x34, 0x37, 0x9B, 0x1A, 0x29, 0xDC, 0x24, 0x03, 0x08, 0x12, 0xE9, 0xDD, 0x7C, 0x53, 0x8B, 0xBD, 0xC7, 0x00, 0x6E, 0xB3, 0xB0, 0xAC, 0x11, 0x65, 0xBA, 0xDA, 0x96, 0x5C, 0x57, 0x14, 0x10, 0xED, 0xF1, 0x7C, 0x86, 0x60, 0x75, 0x3B, 0xB2, 0x59, 0x83, 0xBC, 0x08, 0xC0, 0x3F, 0x6D, 0xE0, 0xA6, 0x2C, 0x21, 0x08, 0xEF, 0x16, 0x16, 0x0E, 0x8D, 0xE2, 0x9B, 0xD3, 0xC1, 0xE5, 0x51, 0xD0, 0x66, 0xDC, 0xCE, 0xCA, 0x31, 0x4A, 0x5A, 0x29, 0x40, 0x34, 0xEC, 0x85, 0x8B, 0xA5, 0x62, 0xBC, 0x49, 0xA3, 0x88, 0x76, 0xED, 0xAE, 0x78, 0xF2, 0xC8, 0x30, 0x5C, 0x95, 0x8D, 0xDA, 0x18, 0xC4, 0x8F, 0x45, 0x70, 0xF4, 0x7D, 0x0E, 0x2F, 0xF6, 0xB4, 0x2A, 0xE8, 0xF8, 0x7C, 0x2A, 0xFC, 0x4B, 0xE6, 0xB3, 0x9B, 0xAA, 0x85, 0x49, 0x73, 0x2A, 0x9C, 0x7A, 0x42, 0x12, 0x21, 0xBE, 0x15, 0xD4, 0xCC, 0x79, 0xD2, 0xF0, 0x8C, 0xD1, 0x40, 0x52, 0xC9, 0x29, 0xF6, 0x75, 0x2C, 0x88, 0xE6, 0xFA, 0x8D, 0x37, 0x3A, 0x1F, 0xD1, 0x58, 0x51, 0xE3, 0x65, 0x6B, 0x30, 0x9F, 0x28, 0x20, 0x98, 0x7C, 0xA6, 0xE3, 0x73, 0xB5, 0x0B, 0x73, 0x36, 0xA1, 0xFE, 0x1A, 0xFF, 0xDC, 0xC8, 0x62, 0xC3, 0x9A, 0x15, 0x9B, 0x97, 0x69, 0x41, 0xA7, 0x3A, 0x2F, 0xE0, 0x70, 0xD4, 0x3B, 0x5D, 0x0B, 0xBE, 0x84, 0xFE, 0xDD, 0x3B, 0x1E, 0x54, 0xFA, 0x47, 0x83, 0x7A, 0x5D, 0xC1, 0x87, 0x4D, 0x79, 0x72, 0x9C, 0xDC, 0x00, 0x66, 0xAA, 0x45, 0x53, 0x26, 0x88, 0x77, 0xA8, 0x78, 0x05, 0xCA, 0x8E, 0x9F, 0x34, 0x3A, 0x18, 0xBE, 0x07, 0xCA, 0x58, 0xCE, 0xA0, 0x8A, 0x50, 0xE5, 0x7E, 0x9B, 0x90, 0xC4, 0x8E, 0x4C, 0xB7, 0x00, 0x31, 0x5D, 0xCA, 0x83, 0xA4, 0xE3, 0x5C, 0xFD, 0x62, 0x6E, 0x5E, 0xB1, 0x4F, 0x19, 0x45, 0x43, 0xAA, 0x60, 0xB2, 0x55, 0x04, 0xA3, 0x05, 0x08, 0xAB, 0x48, 0xE3, 0xD5, 0x7E, 0x48, 0x6D, 0x57, 0x3D, 0xDA, 0x9D, 0x51, 0x1C, 0x66, 0x00, 0x65, 0x3E, 0xE3, 0xDD, 0xF7, 0x16, 0x69, 0xA3, 0xCB, 0x3E, 0xE7, 0x5B, 0xAA, 0x96, 0xB5, 0xB7, 0x7C, 0xB6, 0xC7, 0x83, 0x11, 0x83, 0x04, 0xFB, 0xEA, 0xFD, 0x6D, 0xE2, 0x4C, 0x83, 0x1D, 0x82, 0x67, 0x2B, 0xF8, 0xC7, 0xA7, 0x0E, 0x63, 0xC1, 0xD5, 0x0A, 0x1C, 0xA9, 0x5D, 0x05, 0xCE, 0x0A, 0xB6, 0x4B, 0x26, 0x01, 0x81, 0xFD, 0xF0, 0xDA, 0x73, 0x9F, 0xC8, 0x45, 0xAA, 0x0D, 0x4B, 0x70, 0x53, 0x18, 0xF7, 0x65, 0xEA, 0x24, 0x8A, 0xBF, 0x1A, 0x5F, 0x6C, 0x24, 0x68, 0x15, 0x98, 0xB8, 0x31, 0xEA, 0x86, 0x3C, 0xB5, 0xC9, 0xEF, 0xA1, 0xD6, 0x0C, 0x49, 0x44, 0xA8, 0xCF, 0x53, 0x54, 0x13, 0x21, 0x27, 0x32, 0x5A, 0xAE, 0xD0, 0xBB, 0x0D, 0x82, 0x22, 0xDD, 0x38, 0xD2, 0xA8, 0xA9, 0x73, 0xC1, 0x0D, 0xC8, 0x34, 0xF3, 0xA1, 0x1F, 0xCE, 0x0C, 0xDD, 0x24, 0xBE, 0x7A, 0xB8, 0x38, 0x7E, 0xC5, 0xCA, 0xEC, 0x5E, 0xDF, 0x86, 0x36, 0xC9, 0xE7, 0xB3, 0xD4, 0xF8, 0x9B, 0xC2, 0xCF, 0x80, 0x27, 0xBD, 0xBC, 0x9A, 0x94, 0xF2, 0xF8, 0xB8, 0x95, 0xAF, 0x17, 0xFE, 0x35, 0xCB, 0xC1, 0x6F, 0xFB, 0x34, 0x31, 0xE3, 0xDD, 0x44, 0x62, 0x2D, 0x9C, 0xF2, 0x6D, 0xB2, 0x7D, 0x96, 0x8F, 0x8E, 0xD1, 0x8D, 0xF5, 0x74, 0xAE, 0xC8, 0x25, 0x30, 0x64, 0x69, 0x76, 0x23, 0x24, 0x31, 0xF3, 0x00, 0x87, 0xDD, 0x6D, 0xB5, 0x79, 0xDB, 0x21, 0xB4, 0x5C, 0x07, 0xAD, 0xC1, 0x3C, 0x86, 0x88, 0xB1, 0x3D, 0xB6, 0xA6, 0x6E, 0x89, 0x7A, 0x32, 0x27, 0xB3, 0x2B, 0xF2, 0x93, 0xE5, 0xC1, 0x48, 0x77, 0xE8, 0xFF, 0xB2, 0x3D, 0x4E, 0xFE, 0x52, 0x62, 0xD7, 0x61, 0xD4, 0x46, 0xEC, 0x5E, 0xAD, 0x05, 0xBB, 0xDC, 0xAA, 0x45, 0xB2, 0xA0, 0x81, 0x9E, 0x78, 0xE5, 0x89, 0x46, 0xCF, 0xAB, 0x8E, 0x08, 0xE6, 0xAB, 0xA0, 0x28, 0x47, 0x0C, 0xD3, 0x4E, 0x81, 0x42, 0x51, 0xE4, 0x63, 0xEC, 0xF1, 0x50, 0x5D, 0xB6, 0xAC, 0xE2, 0xFC, 0x8D, 0x05, 0x01, 0x2A, 0x08, 0xFB, 0x96, 0xEA, 0x0C, 0xDC, 0x0F, 0x43, 0x63, 0x21, 0x69, 0x2C, 0xB9, 0x3B, 0xC7, 0xDB, 0xBE, 0xA7, 0xB6, 0xFF, 0x80, 0xB2, 0x0B, 0xE9, 0x95, 0xD1, 0x4E, 0xB0, 0xD0, 0xEA, 0x9F, 0x7D, 0xB2, 0x06, 0xCB, 0xDC, 0x18, 0xC1, 0x82, 0xB3, 0xF7, 0x58, 0xF3, 0x17, 0x9D, 0x28, 0x89, 0x64, 0x0D, 0x7B, 0xFF, 0x9C, 0xEF, 0xE6, 0xBE, 0x1B, 0xCB, 0x03, 0x38, 0x9A, 0x8A, 0x47, 0x68, 0x4B, 0x8C, 0xA6, 0x6D, 0xD4, 0x8B, 0xF9, 0x04, 0x21, 0xF1, 0x72, 0xBA, 0x39, 0xEB, 0x2E, 0xB0, 0xF5, 0x97, 0x92, 0xAA, 0x86, 0x43, 0x1A, 0x62, 0x10, 0x4C, 0x98, 0xA0, 0x90, 0x26, 0xD1, 0xFC, 0x6E, 0xC3, 0x5F, 0x46, 0x36, 0x22, 0xA9, 0x58, 0xBE, 0x4A, 0x4F, 0x6F, 0x1A, 0x2D, 0xA8, 0x4B, 0x74, 0x3D, 0x58, 0x68, 0x55, 0x69, 0x5E, 0xDD, 0x79, 0xB0, 0xC2, 0xAC, 0x0E, 0xDA, 0xB4, 0xCF, 0x19, 0x4F, 0xD7, 0xB4, 0x3C, 0x1A, 0xB0, 0xFE, 0x13, 0x3A, 0x8B, 0x89, 0x0D, 0xB9, 0x4B, 0x24, 0x5A, 0xB3, 0x8E, 0xB7, 0xE3, 0x77, 0xCF, 0x15, }, .pub_len = 2592, }, { .name = "ML-DSA 87 (seed and priv)", .parameter_set = CKP_ML_DSA_87, .priv_seed = { 0x4F, 0x3B, 0x00, 0x56, 0x2F, 0xC0, 0xF8, 0x5E, 0xAF, 0x8C, 0x7B, 0xC2, 0x33, 0xA5, 0xAC, 0xF7, 0x88, 0xD9, 0x06, 0x87, 0x39, 0xF7, 0xFA, 0xF4, 0x0D, 0xBC, 0x76, 0xA4, 0xF0, 0xA2, 0x8C, 0x74, }, .priv_seed_len = 32, .priv = { 0xCA, 0xDE, 0xD2, 0x24, 0xB8, 0xF0, 0xB4, 0xCE, 0x30, 0x19, 0x85, 0x30, 0x5F, 0x5E, 0xCF, 0xF5, 0x03, 0xDD, 0x4E, 0xCC, 0xF0, 0x69, 0xB9, 0xAB, 0x3C, 0xFA, 0x07, 0x4E, 0x89, 0x22, 0x41, 0xBB, 0x19, 0xC2, 0x85, 0xFD, 0xDC, 0xA7, 0xBE, 0x6F, 0xE7, 0xF2, 0xBF, 0xF3, 0xDB, 0x3E, 0xE7, 0x0F, 0x23, 0xC8, 0x7B, 0xA1, 0x4D, 0x20, 0x56, 0xC7, 0xC2, 0x41, 0x59, 0xC4, 0xA7, 0xC4, 0x5A, 0x50, 0x96, 0x62, 0x41, 0xFB, 0xBE, 0x3B, 0xF0, 0x79, 0x8A, 0x33, 0x91, 0x3C, 0x37, 0x08, 0x20, 0x25, 0x72, 0xE8, 0xAE, 0x51, 0x2A, 0xB5, 0xC9, 0x0D, 0xAC, 0xC8, 0x72, 0xAC, 0x0B, 0x08, 0x44, 0x20, 0x21, 0xE2, 0x8C, 0x4D, 0x03, 0x7A, 0x73, 0xA5, 0x1D, 0x48, 0xA4, 0xBB, 0xBC, 0x03, 0x3F, 0x9C, 0x4B, 0xF7, 0x3B, 0x48, 0xF8, 0x36, 0x0B, 0x29, 0xA8, 0xBF, 0x78, 0x58, 0xE8, 0x4D, 0x8B, 0x3C, 0x20, 0xB4, 0x09, 0x54, 0x14, 0x8E, 0x0A, 0x48, 0x8E, 0x1C, 0xB9, 0x6C, 0x12, 0xA8, 0x2C, 0x20, 0x09, 0x30, 0xCA, 0x98, 0x0C, 0x63, 0x80, 0x64, 0xE4, 0x20, 0x4C, 0x01, 0x03, 0x89, 0x1C, 0x04, 0x0C, 0xDC, 0x14, 0x50, 0x0B, 0x49, 0x09, 0xD3, 0x32, 0x6E, 0x9B, 0x18, 0x64, 0x4C, 0x44, 0x05, 0x13, 0xA5, 0x28, 0x18, 0x92, 0x90, 0x51, 0x90, 0x51, 0xC2, 0x16, 0x88, 0x42, 0x44, 0x01, 0x51, 0x10, 0x42, 0x23, 0xA6, 0x44, 0xA2, 0x18, 0x44, 0x8B, 0xB4, 0x88, 0x23, 0x44, 0x46, 0xCB, 0x10, 0x85, 0x5B, 0x18, 0x05, 0x13, 0x27, 0x4E, 0xC4, 0x98, 0x28, 0x11, 0x17, 0x42, 0x90, 0x24, 0x70, 0x0B, 0x11, 0x42, 0x8C, 0x40, 0x6A, 0x08, 0x08, 0x4A, 0x8B, 0x14, 0x66, 0xDB, 0x16, 0x50, 0x99, 0xB8, 0x0C, 0x58, 0x30, 0x0D, 0xC1, 0x12, 0x2D, 0x04, 0x19, 0x6C, 0x9A, 0x18, 0x21, 0xC3, 0x46, 0x86, 0xC0, 0x46, 0x85, 0x22, 0x05, 0x4C, 0xC8, 0x40, 0x85, 0x43, 0xA6, 0x60, 0xE4, 0x24, 0x4A, 0xC1, 0x00, 0x02, 0x02, 0x08, 0x61, 0x04, 0x20, 0x41, 0x12, 0x91, 0x80, 0x03, 0x80, 0x4C, 0xDA, 0xA0, 0x4C, 0x40, 0x46, 0x02, 0x5C, 0x08, 0x40, 0x44, 0x30, 0x4D, 0x21, 0xC1, 0x28, 0x83, 0xA2, 0x11, 0x13, 0x49, 0x6E, 0x19, 0x80, 0x49, 0x64, 0x48, 0x4E, 0x4B, 0x34, 0x4C, 0x52, 0x98, 0x4C, 0xC2, 0x48, 0x26, 0x09, 0xA8, 0x4C, 0xA4, 0x16, 0x26, 0x22, 0x00, 0x66, 0x0A, 0x19, 0x05, 0x14, 0xC6, 0x09, 0xA0, 0x90, 0x49, 0x53, 0x08, 0x82, 0x94, 0x44, 0x44, 0x80, 0x44, 0x88, 0x91, 0x14, 0x6D, 0x82, 0x96, 0x81, 0x0C, 0x49, 0x21, 0x19, 0xB0, 0x49, 0x00, 0x15, 0x52, 0x92, 0xC8, 0x4D, 0x09, 0x08, 0x89, 0xA2, 0x94, 0x48, 0xE0, 0x08, 0x2C, 0x60, 0x42, 0x70, 0x1B, 0x24, 0x6E, 0xA4, 0x24, 0x31, 0x1B, 0x00, 0x2E, 0xD9, 0xA2, 0x00, 0xC0, 0x24, 0x60, 0x8A, 0xC6, 0x09, 0xCC, 0x42, 0x8A, 0xC3, 0x84, 0x09, 0x12, 0x00, 0x6E, 0x49, 0x86, 0x31, 0x0A, 0xC6, 0x00, 0x82, 0x28, 0x08, 0xA3, 0xB8, 0x44, 0x8C, 0x14, 0x2A, 0x10, 0x30, 0x8C, 0x93, 0x16, 0x6E, 0xE2, 0x96, 0x41, 0x08, 0x31, 0x02, 0xD8, 0xC2, 0x28, 0x41, 0x20, 0x20, 0x22, 0x48, 0x0C, 0x1B, 0x89, 0x31, 0x4B, 0xC4, 0x64, 0x20, 0x09, 0x32, 0x14, 0x91, 0x85, 0xD2, 0x00, 0x0C, 0x0C, 0x93, 0x48, 0xD0, 0xB0, 0x2D, 0x93, 0x24, 0x69, 0xE0, 0x96, 0x2C, 0x18, 0xC3, 0x51, 0xD1, 0x38, 0x44, 0x9B, 0x36, 0x01, 0xDA, 0x16, 0x64, 0x10, 0xC4, 0x48, 0x9B, 0xC0, 0x30, 0x91, 0x08, 0x69, 0xDA, 0x28, 0x0C, 0xD8, 0x42, 0x49, 0x90, 0x02, 0x40, 0xC2, 0x02, 0x12, 0x08, 0x40, 0x81, 0xA4, 0xA6, 0x50, 0x60, 0x20, 0x41, 0x83, 0x82, 0x71, 0x22, 0x06, 0x09, 0x51, 0x44, 0x41, 0x08, 0x07, 0x44, 0xC4, 0xC6, 0x30, 0xA2, 0x42, 0x86, 0x12, 0x18, 0x44, 0x82, 0xA6, 0x49, 0x20, 0x23, 0x84, 0x0B, 0x41, 0x20, 0x11, 0x31, 0x89, 0x24, 0xB3, 0x40, 0xC4, 0x04, 0x8A, 0xC4, 0x26, 0x52, 0xA2, 0x28, 0x71, 0x51, 0x44, 0x12, 0xD2, 0xA0, 0x04, 0x0B, 0x97, 0x70, 0x84, 0xC6, 0x6C, 0xC2, 0xA2, 0x08, 0xD4, 0x08, 0x44, 0x0A, 0x32, 0x66, 0x4C, 0x46, 0x68, 0xA1, 0x34, 0x02, 0x49, 0x06, 0x91, 0x48, 0x10, 0x4D, 0x51, 0xC2, 0x68, 0x82, 0xC0, 0x88, 0x48, 0x00, 0x49, 0x0A, 0x42, 0x45, 0x19, 0x31, 0x25, 0x04, 0x16, 0x48, 0x13, 0x05, 0x84, 0x92, 0x26, 0x11, 0x44, 0x12, 0x68, 0x01, 0xA7, 0x69, 0x03, 0x43, 0x26, 0x54, 0x06, 0x6C, 0xD8, 0x12, 0x11, 0x01, 0x83, 0x8C, 0x08, 0x39, 0x2D, 0x94, 0xC6, 0x48, 0x80, 0x06, 0x50, 0x52, 0x08, 0x85, 0xE4, 0x92, 0x65, 0x60, 0xA0, 0x81, 0x0C, 0xB7, 0x81, 0x63, 0x10, 0x8E, 0x13, 0x14, 0x44, 0x12, 0x89, 0x09, 0x9B, 0x40, 0x72, 0xD3, 0x28, 0x09, 0x21, 0x01, 0x6C, 0xD0, 0xA0, 0x49, 0x21, 0x10, 0x6E, 0xE4, 0x14, 0x06, 0x00, 0x39, 0x8A, 0x20, 0xC9, 0x09, 0x5A, 0x86, 0x81, 0x1A, 0x48, 0x28, 0x51, 0x96, 0x89, 0x82, 0x96, 0x71, 0x14, 0x88, 0x89, 0xC4, 0x38, 0x09, 0x00, 0x29, 0x6D, 0xE4, 0x22, 0x01, 0xDA, 0x28, 0x8A, 0x01, 0x15, 0x20, 0x0A, 0x32, 0x8D, 0xE4, 0x46, 0x6D, 0x50, 0x48, 0x26, 0xA0, 0xA0, 0x00, 0x4A, 0x42, 0x12, 0xE2, 0x18, 0x00, 0x63, 0x02, 0x61, 0x18, 0x44, 0x92, 0x02, 0x90, 0x29, 0x81, 0xB4, 0x44, 0x1C, 0x09, 0x8D, 0x60, 0x48, 0x85, 0x59, 0x00, 0x4E, 0xD0, 0x38, 0x66, 0x40, 0x96, 0x61, 0x18, 0x34, 0x81, 0x80, 0x94, 0x00, 0x90, 0x06, 0x0C, 0xD4, 0x32, 0x82, 0x49, 0x20, 0x8E, 0x13, 0xC7, 0x80, 0x0C, 0x16, 0x10, 0x1C, 0x03, 0x42, 0x0C, 0xC8, 0x31, 0xC0, 0x38, 0x0C, 0xCC, 0x98, 0x6D, 0x42, 0x02, 0x29, 0x91, 0x42, 0x65, 0x4A, 0x34, 0x30, 0x4A, 0x98, 0x4D, 0x8C, 0x26, 0x26, 0x19, 0x46, 0x31, 0x82, 0x92, 0x4C, 0x21, 0x41, 0x8D, 0x03, 0x37, 0x66, 0x23, 0x02, 0x21, 0x08, 0x35, 0x61, 0xA0, 0x02, 0x26, 0xCB, 0x88, 0x68, 0x90, 0x44, 0x81, 0x49, 0x96, 0x6C, 0xDA, 0xB0, 0x65, 0x24, 0xB8, 0x6C, 0x1C, 0xA1, 0x6D, 0xDA, 0x80, 0x29, 0xD9, 0xB2, 0x90, 0x09, 0xA3, 0x69, 0x52, 0xA0, 0x30, 0x02, 0x93, 0x28, 0x1C, 0x09, 0x84, 0x0C, 0xA4, 0x90, 0xC3, 0x82, 0x88, 0x24, 0x95, 0x68, 0xA4, 0x20, 0x68, 0x88, 0x98, 0x44, 0x0B, 0x95, 0x61, 0xC8, 0xA6, 0x68, 0x08, 0x07, 0x06, 0x23, 0xC4, 0x91, 0xE4, 0x38, 0x72, 0x10, 0x09, 0x40, 0x98, 0x92, 0x81, 0xA4, 0xB6, 0x4D, 0x1C, 0x11, 0x6C, 0x4C, 0x40, 0x2E, 0xDC, 0x18, 0x48, 0xA2, 0xC8, 0x44, 0xD9, 0x00, 0x00, 0x01, 0x44, 0x2C, 0x02, 0x04, 0x81, 0x49, 0xC0, 0x50, 0xE3, 0x46, 0x48, 0x49, 0x88, 0x40, 0x03, 0xB8, 0x85, 0x22, 0x03, 0x28, 0x9C, 0x12, 0x72, 0xE3, 0xA2, 0x10, 0x50, 0x94, 0x69, 0x1A, 0x20, 0x8E, 0x00, 0xA1, 0x05, 0xD1, 0x86, 0x11, 0x94, 0x04, 0x05, 0xA4, 0x26, 0x2C, 0x4B, 0x84, 0x44, 0xD3, 0xA2, 0x10, 0x98, 0x20, 0x65, 0x03, 0x19, 0x64, 0x58, 0xC8, 0x70, 0xA3, 0xB2, 0x68, 0x22, 0x38, 0x51, 0x8B, 0x80, 0x89, 0x18, 0xA6, 0x40, 0x4C, 0x90, 0x20, 0xC2, 0x18, 0x31, 0xC8, 0x12, 0x08, 0xD8, 0x44, 0x52, 0x1A, 0x01, 0x40, 0xC2, 0x06, 0x90, 0x12, 0x06, 0x22, 0x21, 0xC2, 0x40, 0x51, 0x84, 0x04, 0x94, 0xB4, 0x24, 0x89, 0x48, 0x91, 0xC2, 0xC6, 0x44, 0x04, 0x99, 0x6C, 0x09, 0x25, 0x09, 0x0B, 0x23, 0x92, 0x60, 0xC0, 0x4C, 0x12, 0x13, 0x8E, 0x64, 0xC2, 0x81, 0xD1, 0x38, 0x01, 0xC8, 0x10, 0x6C, 0x94, 0x00, 0x06, 0x1A, 0x94, 0x8C, 0x4C, 0x18, 0x40, 0x63, 0xB0, 0x29, 0x0C, 0x40, 0x68, 0x02, 0x15, 0x6A, 0x42, 0x42, 0x0C, 0x01, 0xC4, 0x71, 0x8C, 0x26, 0x21, 0xD0, 0x38, 0x2C, 0x44, 0x42, 0x6A, 0x14, 0xC0, 0x48, 0x0A, 0xA6, 0x80, 0x1A, 0x36, 0x4D, 0x9A, 0x48, 0x8A, 0x21, 0x03, 0x08, 0x8A, 0x20, 0x84, 0x98, 0x28, 0x86, 0xE0, 0x98, 0x25, 0x21, 0xB4, 0x2D, 0x80, 0x02, 0x10, 0x14, 0xA3, 0x00, 0x8A, 0x06, 0x64, 0xD9, 0xB0, 0x25, 0xCB, 0x06, 0x41, 0x23, 0x88, 0x2D, 0x24, 0xB4, 0x50, 0xC8, 0xB4, 0x25, 0x20, 0x04, 0x70, 0x90, 0x30, 0x6C, 0x41, 0x28, 0x2E, 0x5A, 0x30, 0x8D, 0x23, 0x03, 0x32, 0x02, 0x49, 0x80, 0xC1, 0x00, 0x52, 0x80, 0xC2, 0x49, 0x82, 0xA8, 0x21, 0xD9, 0x14, 0x04, 0x08, 0x01, 0x82, 0x0C, 0x96, 0x8C, 0x51, 0xA4, 0x85, 0x00, 0x06, 0x20, 0xCA, 0x48, 0x85, 0x02, 0xB2, 0x69, 0x23, 0x00, 0x8D, 0xC8, 0xB0, 0x28, 0x14, 0x87, 0x61, 0x50, 0x14, 0x82, 0xE3, 0x34, 0x4D, 0xD4, 0x80, 0x0C, 0x8B, 0x98, 0x05, 0x53, 0xA6, 0x4D, 0x02, 0x48, 0x86, 0x0B, 0x85, 0x81, 0x08, 0xA6, 0x51, 0xD4, 0x98, 0x84, 0x1C, 0xC7, 0x71, 0x98, 0x96, 0x89, 0x51, 0x36, 0x65, 0x0B, 0x49, 0x71, 0x48, 0x32, 0x88, 0x60, 0x10, 0x12, 0xE4, 0x20, 0x62, 0x5C, 0x28, 0x26, 0x44, 0x00, 0x2A, 0xCC, 0x90, 0x81, 0x50, 0x90, 0x65, 0x09, 0xC8, 0x65, 0x43, 0x98, 0x81, 0xCC, 0x90, 0x24, 0x0B, 0x98, 0x85, 0x9B, 0x02, 0x2C, 0x02, 0x32, 0x66, 0x89, 0x12, 0x6D, 0x0C, 0x31, 0x49, 0x24, 0x28, 0x81, 0x5B, 0xC0, 0x89, 0x18, 0x16, 0x52, 0xA2, 0x88, 0x6C, 0xA1, 0x04, 0x04, 0x22, 0x88, 0x29, 0x5B, 0x40, 0x41, 0x19, 0xB7, 0x71, 0x00, 0x45, 0x89, 0x00, 0xA8, 0x51, 0x14, 0xB5, 0x65, 0xC2, 0xB6, 0x05, 0x88, 0x30, 0x70, 0x99, 0x26, 0x0A, 0x12, 0x11, 0x44, 0x09, 0x19, 0x2C, 0x4A, 0x30, 0x10, 0x44, 0x10, 0x86, 0xCC, 0xC2, 0x08, 0xCB, 0x24, 0x25, 0xCB, 0x20, 0x48, 0x10, 0xA5, 0x01, 0x52, 0x34, 0x84, 0x11, 0x95, 0x64, 0x63, 0x90, 0x80, 0xD3, 0x86, 0x40, 0xA0, 0x26, 0x64, 0xE1, 0xA4, 0x61, 0x10, 0x24, 0x69, 0x84, 0x48, 0x8C, 0x11, 0xC2, 0x45, 0x9C, 0x14, 0x85, 0xCC, 0xA4, 0x44, 0xC4, 0x10, 0x4C, 0x1B, 0x95, 0x8C, 0x12, 0x34, 0x44, 0x14, 0xC1, 0x30, 0xE4, 0x90, 0x91, 0x89, 0xA0, 0x69, 0xD0, 0x06, 0x45, 0x11, 0x43, 0x52, 0xD8, 0x84, 0x60, 0x8C, 0x16, 0x61, 0xA0, 0x40, 0x8E, 0x41, 0xB0, 0x30, 0x19, 0x98, 0x60, 0x18, 0x28, 0x8C, 0x4B, 0x94, 0x4C, 0xE3, 0x06, 0x0A, 0x20, 0x23, 0x42, 0xD4, 0xC2, 0x29, 0x53, 0xB6, 0x41, 0x60, 0x32, 0x28, 0x91, 0x40, 0x26, 0x0B, 0x14, 0x90, 0x11, 0xB4, 0x00, 0x09, 0xB8, 0x08, 0xDA, 0x14, 0x80, 0x01, 0xB0, 0x05, 0x51, 0x36, 0x25, 0xA0, 0x16, 0x06, 0x13, 0x26, 0x68, 0xDB, 0x94, 0x69, 0x5B, 0x44, 0x8E, 0xA0, 0x22, 0x65, 0x13, 0x28, 0x86, 0x02, 0xC5, 0x25, 0x23, 0x01, 0x01, 0x21, 0x27, 0x01, 0xE3, 0x80, 0x04, 0x54, 0xB6, 0x10, 0x49, 0x86, 0x01, 0xA0, 0xB6, 0x30, 0x01, 0x87, 0x44, 0x01, 0x26, 0x85, 0x8C, 0x84, 0x8D, 0x84, 0xC4, 0x21, 0x0C, 0x96, 0x4D, 0x20, 0xA2, 0x01, 0xDC, 0xB8, 0x69, 0xC9, 0x42, 0x42, 0x0C, 0x39, 0x50, 0xC3, 0xC6, 0x80, 0xC1, 0x18, 0x32, 0xA1, 0x24, 0x85, 0x84, 0x04, 0x00, 0x42, 0xC2, 0x6C, 0x13, 0x09, 0x80, 0x0A, 0x26, 0x68, 0xA0, 0xA0, 0x29, 0x09, 0x41, 0x05, 0xE3, 0x20, 0x01, 0x41, 0xA8, 0x24, 0xE4, 0x00, 0x85, 0x14, 0x46, 0x26, 0xA4, 0x18, 0x0E, 0x13, 0x02, 0x60, 0x55, 0x17, 0x75, 0xAA, 0xB0, 0x7E, 0x59, 0x33, 0xEA, 0xD1, 0x2A, 0x55, 0xDD, 0xC7, 0x2C, 0x48, 0xA2, 0x1F, 0x4A, 0x70, 0xE9, 0x3C, 0xD3, 0x26, 0x51, 0xB2, 0x26, 0x24, 0x0A, 0x03, 0xB1, 0x67, 0x13, 0x19, 0x74, 0x55, 0x1A, 0xB0, 0x72, 0x48, 0xE8, 0x95, 0x37, 0xFE, 0xEE, 0xFF, 0x77, 0x19, 0xF9, 0x7B, 0x90, 0x2D, 0x46, 0x88, 0x23, 0x75, 0xB6, 0x6A, 0x4A, 0x85, 0xA5, 0x98, 0x36, 0x40, 0x04, 0x67, 0x3B, 0xDE, 0x25, 0xB4, 0x05, 0x56, 0x60, 0x33, 0x58, 0xC0, 0xBB, 0xF7, 0xE0, 0x29, 0x71, 0x63, 0x62, 0x8D, 0x25, 0x3C, 0x93, 0x81, 0xDA, 0x69, 0xEF, 0xFE, 0xE9, 0xFA, 0x42, 0x5F, 0x47, 0xAE, 0xF3, 0xBC, 0xA4, 0xC4, 0xCB, 0x6D, 0xE2, 0xF5, 0xB9, 0x33, 0x06, 0xC4, 0xF6, 0x0A, 0xD8, 0x99, 0x87, 0x08, 0xAA, 0x06, 0x97, 0x5C, 0x30, 0xDF, 0xB6, 0x64, 0xB0, 0x23, 0xF7, 0x27, 0x05, 0x1E, 0xC4, 0xD9, 0xE7, 0xD7, 0x0C, 0xA7, 0x4E, 0xD3, 0x4E, 0x98, 0xAE, 0x46, 0xE2, 0xD0, 0x04, 0xF1, 0x99, 0xB5, 0x3E, 0xF0, 0xE2, 0x3E, 0xC4, 0x1C, 0xE0, 0xAF, 0x6E, 0x5F, 0x43, 0x9E, 0xB5, 0x0A, 0xB7, 0x64, 0x83, 0x57, 0x0F, 0xCF, 0x5F, 0x5B, 0xD1, 0x58, 0x9C, 0x55, 0xFD, 0x9A, 0xCE, 0x8A, 0x4B, 0x3E, 0x11, 0x77, 0xE1, 0xAD, 0x5E, 0xDB, 0x4A, 0x38, 0x27, 0x54, 0x01, 0x16, 0x32, 0x61, 0x0C, 0x4A, 0x26, 0xD0, 0x07, 0x42, 0xD5, 0xBF, 0xD4, 0xFB, 0xDA, 0x50, 0x7B, 0x9C, 0x51, 0x69, 0x7A, 0x92, 0x40, 0x65, 0xE7, 0x39, 0x97, 0x88, 0x96, 0x6C, 0x39, 0xCA, 0x51, 0xFD, 0xF7, 0x46, 0x28, 0xE9, 0xB4, 0x85, 0x35, 0xF9, 0xC5, 0x2F, 0x75, 0xC4, 0x33, 0x68, 0x3B, 0xB5, 0x37, 0x0D, 0x9E, 0xE5, 0x9B, 0x20, 0x49, 0x13, 0xE7, 0x10, 0xE2, 0xF8, 0x33, 0x5A, 0xF7, 0x4D, 0x30, 0x66, 0xA7, 0x1B, 0xDF, 0xC6, 0x12, 0x46, 0xE2, 0xD7, 0xA2, 0x6E, 0x32, 0x7A, 0x71, 0x48, 0x27, 0x9A, 0x64, 0xC5, 0x14, 0x78, 0x2C, 0x3E, 0xEA, 0x9F, 0x5B, 0xAC, 0xBE, 0xCF, 0x30, 0x95, 0x79, 0x74, 0x9E, 0x1D, 0xC8, 0x05, 0x6F, 0x78, 0x3F, 0x77, 0xAE, 0x43, 0x6A, 0xA3, 0xAB, 0x0A, 0xAB, 0x50, 0x77, 0xB5, 0xE3, 0x2F, 0xE7, 0xA4, 0xCC, 0xD7, 0x30, 0xC3, 0x6A, 0x3B, 0x93, 0x85, 0xBC, 0xE9, 0x98, 0x94, 0xE4, 0xAF, 0x87, 0x4F, 0xF4, 0x27, 0xE6, 0xD4, 0x6A, 0x81, 0x43, 0x85, 0xF8, 0x62, 0x39, 0xA2, 0x0A, 0x3F, 0x88, 0x27, 0xF8, 0xAB, 0x91, 0xD3, 0x96, 0xA5, 0x3B, 0x9D, 0x6A, 0x15, 0x05, 0x3E, 0x4E, 0x1D, 0x41, 0x4B, 0x57, 0xBD, 0x6E, 0xF3, 0xBE, 0xD9, 0x7B, 0x3F, 0xAA, 0xC7, 0x2A, 0x4A, 0x8B, 0xAD, 0x9E, 0x0E, 0x81, 0x90, 0x18, 0xE6, 0x1D, 0x63, 0xA2, 0xA2, 0x93, 0x57, 0x38, 0xE3, 0x43, 0x05, 0xD0, 0xAA, 0x07, 0x30, 0x8A, 0xB4, 0x66, 0x78, 0xA1, 0x91, 0xE6, 0xFD, 0x27, 0x1D, 0x1C, 0x9E, 0x11, 0x5C, 0x63, 0x91, 0x27, 0xAF, 0x5D, 0x0F, 0x1E, 0x06, 0x7A, 0x04, 0x0B, 0xC9, 0xE6, 0x44, 0x4B, 0x05, 0xD9, 0x5D, 0xB5, 0xAB, 0x1D, 0x16, 0xE1, 0x42, 0x0B, 0xAC, 0xF2, 0x4C, 0x05, 0xA9, 0x43, 0xF5, 0x52, 0x19, 0x19, 0xF2, 0xDD, 0x22, 0x14, 0x10, 0xAB, 0x3B, 0xE6, 0xD9, 0x92, 0x35, 0xAF, 0xC8, 0x01, 0x9C, 0x1C, 0x07, 0x49, 0x41, 0x8F, 0x0B, 0x8E, 0x42, 0x3C, 0xF8, 0xE8, 0x02, 0xA1, 0x1B, 0x21, 0x69, 0xEE, 0x10, 0xA6, 0x73, 0x47, 0x30, 0x09, 0x1F, 0xE9, 0x31, 0x88, 0xCC, 0x7A, 0x50, 0x16, 0xAD, 0x69, 0xCC, 0xA6, 0x4E, 0x87, 0x71, 0x69, 0xFA, 0xBB, 0xBC, 0x73, 0xA2, 0x3A, 0x67, 0x85, 0xA0, 0x71, 0x38, 0x1D, 0x8D, 0x7B, 0x1B, 0x92, 0xC3, 0xF7, 0xDD, 0x17, 0x3A, 0x1D, 0x4B, 0x1A, 0x2E, 0xF9, 0xF8, 0xBA, 0x53, 0xE0, 0x0C, 0x9A, 0x40, 0x6E, 0x15, 0xB6, 0x5C, 0xEB, 0x3A, 0xDF, 0xDC, 0xA3, 0xD2, 0x96, 0xE4, 0x48, 0xC5, 0xB3, 0x22, 0xF2, 0x45, 0xDA, 0x6F, 0x94, 0x68, 0x5B, 0x18, 0x76, 0xD6, 0x92, 0xDC, 0xB7, 0x9E, 0x2F, 0xF9, 0x12, 0x0E, 0x11, 0x82, 0xBD, 0xDF, 0xBD, 0xA7, 0xEA, 0xD5, 0xA2, 0xCA, 0x9E, 0xD5, 0xB7, 0x3A, 0x60, 0xEA, 0x05, 0x4D, 0x43, 0x1B, 0x30, 0x42, 0x6D, 0x99, 0x32, 0xF2, 0x16, 0x98, 0x48, 0xB9, 0xF5, 0xA9, 0x32, 0xF0, 0xA2, 0x89, 0x5D, 0x6C, 0x87, 0x8C, 0x01, 0x5F, 0xD3, 0xF5, 0x37, 0x25, 0x45, 0x0F, 0xE0, 0x2B, 0xE2, 0x81, 0x5F, 0x99, 0x35, 0x4B, 0xFB, 0x36, 0x2A, 0xCC, 0x5F, 0x83, 0xF7, 0x36, 0x1A, 0xD5, 0x13, 0x1B, 0xD5, 0xB0, 0x4C, 0xDA, 0xEE, 0xB7, 0xA8, 0x8B, 0xE7, 0x4C, 0xDF, 0x64, 0x75, 0x8C, 0x8E, 0xF5, 0x8B, 0xC3, 0xB7, 0x50, 0xEB, 0xEF, 0xF0, 0xAD, 0x4F, 0xAF, 0xF4, 0x80, 0x5A, 0x00, 0x80, 0x50, 0x13, 0xEB, 0x96, 0x49, 0xE9, 0xAF, 0xEB, 0x68, 0xA3, 0x7E, 0x2F, 0x87, 0xC5, 0x3F, 0xAD, 0x67, 0x6B, 0x7B, 0x53, 0xFE, 0x64, 0xD4, 0x4D, 0x9D, 0xB5, 0xF2, 0xB8, 0xE9, 0x30, 0x13, 0x22, 0xBB, 0xFF, 0x2F, 0xD5, 0x64, 0xC3, 0xBA, 0xF7, 0x0B, 0x09, 0x0A, 0xC4, 0x32, 0x9C, 0x14, 0xD5, 0x93, 0xAC, 0xC6, 0x95, 0xCD, 0x5D, 0x4B, 0x3A, 0xC0, 0x53, 0xB2, 0x94, 0xAA, 0xB1, 0x52, 0x8A, 0x9C, 0x07, 0xA0, 0x63, 0x2E, 0xB4, 0xE1, 0x83, 0x73, 0x00, 0x5C, 0x8B, 0x23, 0x4C, 0x14, 0x2F, 0xB6, 0x9B, 0xC8, 0x8D, 0x58, 0xF6, 0xDC, 0xEC, 0xDA, 0xB1, 0x4B, 0x6E, 0x2D, 0xAC, 0x5D, 0xD7, 0x76, 0xA3, 0xEC, 0x26, 0xA9, 0x3A, 0x71, 0x04, 0x80, 0xE4, 0x25, 0xEF, 0xD9, 0x7F, 0x13, 0xDB, 0x14, 0x82, 0x2C, 0x7A, 0x66, 0x36, 0x06, 0x63, 0xE2, 0x39, 0x9A, 0x64, 0x34, 0x68, 0x85, 0xD4, 0x79, 0xE7, 0x4C, 0xB2, 0xCB, 0x29, 0x51, 0x47, 0x68, 0x2B, 0xB5, 0x5C, 0x99, 0x92, 0x16, 0x0A, 0xC8, 0x4D, 0x9C, 0xDA, 0x72, 0xE8, 0x37, 0xA1, 0x53, 0x27, 0xD3, 0x9A, 0xB3, 0x5D, 0xC4, 0x57, 0x66, 0x0A, 0x6C, 0xCD, 0x02, 0x2B, 0xDC, 0xBA, 0xB4, 0x63, 0x55, 0x83, 0x81, 0xB4, 0x0B, 0xDF, 0x2A, 0x5D, 0x6F, 0x98, 0x61, 0x9B, 0xC7, 0xF6, 0x69, 0x2F, 0xDF, 0x42, 0xF1, 0x8F, 0x16, 0x5D, 0x89, 0x75, 0xF8, 0xD3, 0x18, 0xD5, 0x7F, 0x6A, 0x90, 0x21, 0xA8, 0xD5, 0x40, 0xE8, 0xE2, 0xA0, 0x56, 0x7A, 0xBA, 0x15, 0x4E, 0x8A, 0xC4, 0x6D, 0x54, 0xB0, 0x40, 0x5F, 0xB7, 0x71, 0x34, 0x75, 0x32, 0x39, 0xFF, 0x50, 0x10, 0xFE, 0x25, 0xFF, 0x77, 0x6F, 0x4C, 0x29, 0x8A, 0xB3, 0xDB, 0x71, 0xF2, 0xD1, 0xA4, 0xAA, 0x2B, 0x53, 0xAB, 0xA1, 0x58, 0x8D, 0x41, 0x34, 0x9D, 0x36, 0xAB, 0xA7, 0x13, 0xD0, 0x4A, 0xAE, 0x2F, 0x52, 0x1E, 0xEC, 0x78, 0xAC, 0xC6, 0x8A, 0x20, 0x58, 0xD4, 0x0C, 0xFE, 0xF4, 0x50, 0x95, 0x63, 0xF4, 0x73, 0x3D, 0xC5, 0xFE, 0x5D, 0xF4, 0xF4, 0xB7, 0x3A, 0x50, 0x1A, 0xFA, 0x09, 0x92, 0x82, 0xEA, 0xE9, 0x1F, 0x04, 0xE8, 0xEE, 0xD2, 0x23, 0xCA, 0x2D, 0x3A, 0x8A, 0xD1, 0xA2, 0xD0, 0xE0, 0x9B, 0x3C, 0xCD, 0xC1, 0xF0, 0xD4, 0x60, 0x8C, 0xD3, 0x3C, 0x1B, 0xFA, 0x39, 0xF0, 0x54, 0xFA, 0x2C, 0x27, 0xEA, 0xE5, 0xAC, 0x26, 0x75, 0xBF, 0xF6, 0x96, 0x75, 0x26, 0x9B, 0xBE, 0x05, 0x4D, 0x08, 0xC3, 0x2F, 0xDA, 0x89, 0xFF, 0xDC, 0xEE, 0xC9, 0xA9, 0x83, 0xBB, 0xE8, 0x61, 0xD1, 0x81, 0xB5, 0xEF, 0xAC, 0x68, 0x64, 0x1B, 0x13, 0xFC, 0xD4, 0x30, 0xCD, 0xFE, 0x10, 0xC2, 0xCA, 0x14, 0x09, 0x6F, 0xAB, 0x40, 0x65, 0xC6, 0xF6, 0x59, 0xCC, 0x7F, 0x61, 0xB2, 0x4B, 0x7C, 0x92, 0xF4, 0x90, 0xE6, 0xD8, 0x4D, 0x45, 0x8A, 0xC0, 0xC5, 0xE7, 0x08, 0x38, 0xAF, 0x82, 0x17, 0xF0, 0xC7, 0x50, 0x9B, 0x31, 0x60, 0xC5, 0xC1, 0x2B, 0x50, 0xE0, 0xF9, 0xF6, 0x2D, 0xBF, 0x8E, 0x95, 0x79, 0x9D, 0x54, 0x26, 0xC7, 0xE2, 0xAC, 0xEC, 0x4A, 0xD3, 0x78, 0xE9, 0x65, 0x64, 0xBA, 0x87, 0xE3, 0xF4, 0x0C, 0x91, 0xA2, 0x74, 0x18, 0x3F, 0xB4, 0x56, 0x6C, 0xF1, 0x1F, 0xB6, 0xE7, 0x92, 0x25, 0xC3, 0x59, 0xDF, 0xBE, 0x92, 0xD8, 0x59, 0xFC, 0x04, 0x45, 0x13, 0xBF, 0xE0, 0x0C, 0x9C, 0x9D, 0x61, 0xF7, 0x6E, 0x91, 0xE6, 0x85, 0xD3, 0x2F, 0xE7, 0xC6, 0xF5, 0x55, 0xD6, 0x66, 0x82, 0x6F, 0x30, 0x0E, 0xB0, 0x4A, 0x9A, 0x17, 0x00, 0x57, 0xE1, 0x14, 0xF7, 0xCA, 0xEE, 0x9F, 0xB9, 0x4F, 0xD4, 0xDF, 0x7D, 0x20, 0x99, 0xF5, 0x95, 0x29, 0x65, 0xA2, 0x00, 0x6D, 0x99, 0x17, 0x72, 0x75, 0x37, 0x73, 0x71, 0x04, 0x50, 0x4C, 0x55, 0x63, 0xC6, 0x7C, 0x9D, 0xB1, 0x7A, 0xA4, 0xCE, 0xDB, 0x36, 0xD3, 0xA1, 0x0C, 0x1F, 0x49, 0x30, 0xF3, 0x1A, 0x1A, 0xBE, 0x17, 0x30, 0x5F, 0x8B, 0x0B, 0x30, 0x90, 0x02, 0x89, 0x08, 0x12, 0x3B, 0xE8, 0xFB, 0x64, 0x6D, 0x50, 0x2E, 0xCD, 0xFD, 0x5C, 0x4D, 0x78, 0xD0, 0x1F, 0xBB, 0x58, 0xD6, 0xB3, 0xFC, 0x88, 0xFC, 0xAC, 0xDF, 0xC0, 0xE8, 0xA2, 0x19, 0x30, 0x6A, 0x5C, 0xD8, 0xB9, 0x85, 0xB4, 0x9B, 0x2F, 0x0F, 0x0E, 0xC2, 0x6C, 0xE7, 0xEB, 0xD2, 0xB4, 0x82, 0xED, 0xDC, 0x76, 0x2C, 0x4F, 0x97, 0x8C, 0x17, 0xE1, 0x7D, 0x66, 0xE2, 0x2D, 0x3E, 0x21, 0x7C, 0xC4, 0x41, 0x10, 0xE9, 0xFC, 0xDD, 0x74, 0x24, 0xB1, 0x51, 0xC2, 0xC3, 0xB4, 0x07, 0x59, 0x20, 0xE2, 0x65, 0x41, 0xDB, 0x1E, 0x72, 0x52, 0x8F, 0x28, 0x18, 0x6E, 0x2C, 0x57, 0x32, 0x55, 0xAA, 0xCF, 0xA8, 0x52, 0x34, 0x7F, 0x89, 0x3D, 0x56, 0x02, 0x87, 0x19, 0x15, 0xDD, 0xD2, 0x87, 0xEC, 0x39, 0x12, 0xDB, 0x03, 0x7B, 0x04, 0x47, 0x2D, 0xD0, 0x5A, 0x4B, 0x17, 0x3F, 0x84, 0xB7, 0xC9, 0x72, 0x07, 0x11, 0x86, 0x25, 0xD6, 0xB1, 0x03, 0x7D, 0x27, 0x00, 0x8B, 0x5D, 0xA7, 0xA6, 0x36, 0x54, 0x20, 0x10, 0x9E, 0x14, 0x2D, 0xC5, 0xA0, 0x5A, 0x19, 0x6A, 0xFF, 0xF4, 0x80, 0xFD, 0x38, 0x1A, 0x6A, 0x4D, 0xE6, 0x08, 0x34, 0xCD, 0x2C, 0xAD, 0x4D, 0x3E, 0xE2, 0xC3, 0x46, 0xDA, 0x95, 0xF2, 0x33, 0x41, 0x86, 0x26, 0xA9, 0xB8, 0xAA, 0xF4, 0x50, 0x10, 0x01, 0xE9, 0xA7, 0xCF, 0x58, 0x94, 0xA7, 0xA8, 0xA6, 0xAB, 0x2D, 0x81, 0x78, 0x16, 0x82, 0xA8, 0x8F, 0xCD, 0x0A, 0x9A, 0x6C, 0x0F, 0xFD, 0x76, 0x8F, 0xC4, 0xAA, 0x2A, 0x33, 0x8E, 0x7D, 0xDE, 0x04, 0xE8, 0x86, 0x8A, 0xBC, 0x7A, 0xA3, 0x02, 0x9F, 0x2C, 0xB6, 0x3C, 0xDC, 0x02, 0xBD, 0xC7, 0x51, 0xE1, 0x55, 0xDB, 0x2A, 0x72, 0xAD, 0x1D, 0x2C, 0x81, 0x6C, 0x30, 0x9D, 0x4A, 0xCC, 0x4D, 0x11, 0x3E, 0xE0, 0x8F, 0x6D, 0x63, 0xCF, 0x3D, 0x71, 0xF2, 0x0B, 0x8B, 0x44, 0x14, 0x6A, 0xDB, 0x61, 0x07, 0xC4, 0x8D, 0xEF, 0x34, 0x5A, 0x21, 0x79, 0xD7, 0xA8, 0xE6, 0xD8, 0xD0, 0x87, 0xEF, 0x40, 0x65, 0xC4, 0xFF, 0xB7, 0xDD, 0xBE, 0xC8, 0xFC, 0x8A, 0xBB, 0x59, 0x96, 0x6E, 0x37, 0xE4, 0x10, 0x4B, 0xEE, 0xFF, 0x6E, 0x4A, 0x22, 0xBD, 0xC7, 0x13, 0xA2, 0xF5, 0xC6, 0x5D, 0x21, 0xD6, 0x1C, 0xE4, 0xCD, 0x76, 0x68, 0xAA, 0x96, 0x2E, 0x37, 0x21, 0x01, 0x8F, 0x8B, 0xC6, 0x22, 0x97, 0xE7, 0x1D, 0x1B, 0x75, 0xEC, 0xAB, 0x3B, 0x91, 0x32, 0x6B, 0x17, 0x92, 0xCC, 0xC0, 0x7A, 0xFC, 0x8D, 0x54, 0xBA, 0xA8, 0x03, 0x87, 0x95, 0x2D, 0xE4, 0x2A, 0xA8, 0x3A, 0xD2, 0x71, 0x6A, 0x3F, 0x98, 0xA5, 0xAF, 0x17, 0x62, 0x45, 0xE8, 0x4D, 0x41, 0x7C, 0x3C, 0xD2, 0x4F, 0x89, 0x81, 0xFE, 0xC8, 0x2A, 0x91, 0x7A, 0xFE, 0x98, 0x3F, 0x50, 0x5A, 0x31, 0xAA, 0xD0, 0xAA, 0x2F, 0x5D, 0x36, 0x78, 0x2A, 0xA8, 0x46, 0xF2, 0x4C, 0xA8, 0x55, 0x81, 0xF8, 0xE0, 0xB1, 0x15, 0xDE, 0x9F, 0x68, 0x76, 0x4D, 0x89, 0x0E, 0x7D, 0xF9, 0x43, 0xCD, 0x67, 0x82, 0xCB, 0x2A, 0x30, 0xCE, 0xB7, 0xF6, 0xD8, 0xDA, 0x9D, 0xBA, 0xFE, 0xDA, 0x2C, 0x48, 0x0C, 0xBE, 0xF0, 0xC0, 0xEB, 0x4E, 0x55, 0xE5, 0x63, 0x4A, 0x3A, 0x17, 0x60, 0x32, 0x64, 0x5D, 0x9A, 0xC5, 0x6B, 0x02, 0xE2, 0xDD, 0x96, 0x24, 0x4B, 0xC1, 0xBC, 0xD1, 0x93, 0x73, 0x35, 0x17, 0x07, 0xBB, 0xDA, 0x32, 0x7E, 0x28, 0x49, 0xFD, 0x07, 0xBA, 0xA5, 0xED, 0x5E, 0x9D, 0xDD, 0x2E, 0xD2, 0x67, 0x45, 0x54, 0xFA, 0x9C, 0x0A, 0x9E, 0xDE, 0x2B, 0x87, 0xB4, 0x4E, 0xDF, 0xF4, 0x11, 0x16, 0x6F, 0xE5, 0x27, 0x59, 0x73, 0x69, 0xED, 0x1C, 0x83, 0xB9, 0x83, 0x24, 0x7C, 0xE0, 0x45, 0x92, 0x72, 0xE0, 0x13, 0xE6, 0xE7, 0x1A, 0x11, 0x53, 0xAA, 0xAC, 0x0A, 0x62, 0x79, 0x43, 0x1A, 0x2A, 0x54, 0x5D, 0x4A, 0x06, 0xA7, 0x46, 0xD0, 0xCC, 0xA8, 0x2A, 0x95, 0xDB, 0x0B, 0x73, 0x50, 0x46, 0xBB, 0x46, 0x61, 0x2F, 0x7D, 0x34, 0x95, 0xB7, 0x74, 0x40, 0x30, 0x38, 0x72, 0x0E, 0x17, 0xEC, 0x9B, 0x7B, 0xD8, 0x50, 0xD4, 0x1B, 0x4F, 0xAA, 0x60, 0x67, 0x2E, 0x1C, 0x25, 0xBB, 0x04, 0x21, 0x43, 0xF8, 0xDA, 0x1D, 0x98, 0x50, 0xB4, 0x35, 0x87, 0x8F, 0xB2, 0xAC, 0x55, 0xCC, 0x0B, 0x7B, 0x28, 0x7A, 0x5E, 0x89, 0xE3, 0x7B, 0x0C, 0x66, 0x3A, 0x48, 0xD1, 0x5A, 0xCA, 0x1B, 0x91, 0xDF, 0xC3, 0x79, 0x89, 0x02, 0xF7, 0xA5, 0x57, 0xB4, 0x9F, 0xA5, 0xB8, 0x61, 0x7D, 0xDA, 0x2A, 0xAC, 0x54, 0xB4, 0x12, 0xC4, 0x7A, 0x3A, 0xB8, 0xB9, 0x5D, 0xDD, 0xE6, 0x58, 0x3A, 0xEA, 0xEC, 0xF8, 0xEE, 0xD9, 0xAA, 0xA7, 0xF9, 0xA2, 0xEE, 0xD7, 0x31, 0x74, 0xEF, 0x94, 0x66, 0x8F, 0x23, 0xD8, 0xF1, 0x8F, 0x81, 0xF3, 0xEE, 0x39, 0x2D, 0x40, 0x3E, 0x4E, 0xE8, 0x04, 0x01, 0xFE, 0x69, 0x04, 0x05, 0xD0, 0x20, 0x3B, 0x35, 0xE8, 0xE3, 0xF4, 0x59, 0x99, 0x12, 0x59, 0x85, 0xE4, 0x9F, 0xCE, 0xC7, 0x3B, 0x8B, 0x76, 0xF5, 0xF1, 0xFF, 0xFE, 0x36, 0x8E, 0xD6, 0x3A, 0x39, 0x86, 0xB4, 0x12, 0x09, 0xF7, 0xA5, 0xFA, 0x16, 0x80, 0x7E, 0x1C, 0x3D, 0xD4, 0xDD, 0x71, 0xBC, 0x64, 0x8E, 0x8B, 0xF8, 0x95, 0x65, 0xD2, 0xE6, 0x53, 0x79, 0x94, 0xB8, 0x1B, 0xCD, 0xDA, 0xE1, 0xB3, 0xE5, 0x5B, 0x0F, 0xD4, 0x57, 0x7A, 0x66, 0x6A, 0xD0, 0xCE, 0x45, 0xA8, 0xC2, 0xB6, 0x81, 0x7A, 0xD5, 0x59, 0xD1, 0x08, 0x4C, 0x77, 0xAD, 0xDE, 0xD5, 0xA8, 0xF0, 0x33, 0x1A, 0xB5, 0x58, 0x71, 0x56, 0x23, 0x19, 0xA1, 0x20, 0x68, 0xA5, 0xF5, 0x89, 0x29, 0x86, 0x56, 0xFF, 0x74, 0x8F, 0x81, 0xAA, 0xF4, 0x53, 0xC0, 0x92, 0x97, 0xDB, 0x08, 0x7C, 0xCE, 0xED, 0xA5, 0xB8, 0x9B, 0x80, 0xBF, 0x79, 0xFE, 0x7C, 0xD8, 0x64, 0xB4, 0x7B, 0x8D, 0x42, 0xC1, 0x64, 0x6B, 0x00, 0x29, 0xF2, 0x89, 0x87, 0x5C, 0x50, 0xFA, 0x16, 0x8A, 0xAD, 0xA5, 0x51, 0x95, 0x08, 0x1A, 0x42, 0xA9, 0x7D, 0xC1, 0xE2, 0x9E, 0x52, 0xE5, 0x3B, 0x00, 0xC2, 0x23, 0x26, 0x59, 0x1D, 0xF9, 0xC2, 0x39, 0x7B, 0x03, 0x24, 0x9A, 0xF3, 0x52, 0xC1, 0xEF, 0x0C, 0x5A, 0x65, 0x69, 0x89, 0xC5, 0x2F, 0xE3, 0xCF, 0x93, 0x4A, 0xE8, 0xA5, 0x74, 0x87, 0x9F, 0x33, 0x2B, 0x32, 0xD6, 0xE4, 0x6D, 0xF2, 0x1E, 0x92, 0xC3, 0x01, 0x48, 0xA9, 0xF4, 0x65, 0xD8, 0x26, 0x1D, 0xE6, 0x20, 0xCB, 0xD2, 0xE9, 0xEE, 0x15, 0x1C, 0xB6, 0x43, 0x05, 0xF2, 0x43, 0x6C, 0x56, 0xA4, 0x01, 0xC0, 0x9A, 0x49, 0xC7, 0xDB, 0x05, 0xC9, 0xE6, 0x78, 0x56, 0xD6, 0xC9, 0x56, 0x86, 0x4A, 0x31, 0xE4, 0x5B, 0x52, 0x6F, 0xC4, 0x66, 0x03, 0x92, 0x1D, 0x1D, 0xDC, 0xA0, 0xBF, 0x7F, 0x75, 0xD0, 0xE3, 0x8D, 0xBE, 0xC2, 0xD7, 0x41, 0x3B, 0xDC, 0xB9, 0x4D, 0xFF, 0x64, 0x80, 0x64, 0x48, 0x34, 0xEA, 0x2B, 0xF4, 0xBC, 0xA0, 0x0A, 0xC9, 0xC1, 0xEF, 0x13, 0x2E, 0x31, 0xA1, 0x79, 0xE5, 0x71, 0x41, 0x68, 0xB1, 0x0C, 0x50, 0x3A, 0x63, 0xD0, 0xB1, 0x64, 0x0C, 0x68, 0xB8, 0x99, 0xD4, 0x78, 0x2B, 0x41, 0xDC, 0xA1, 0x2C, 0xD6, 0xC2, 0x29, 0xF9, 0x65, 0xA5, 0x1F, 0x25, 0xCE, 0xE3, 0x9E, 0xCF, 0xE7, 0xED, 0x4B, 0xF5, 0x7A, 0xAB, 0x7A, 0x9B, 0x78, 0x4C, 0x35, 0x46, 0x98, 0x56, 0xF0, 0x9A, 0xD4, 0xBF, 0xD9, 0x1F, 0x7C, 0xD6, 0xB8, 0x28, 0x3A, 0x48, 0x55, 0xA1, 0x7F, 0xFC, 0xC7, 0x96, 0x84, 0x1A, 0x02, 0xF4, 0x51, 0x50, 0xBD, 0xC9, 0xCF, 0x50, 0x93, 0x5C, 0xCD, 0x9B, 0x28, 0xD8, 0x57, 0x5F, 0xA4, 0xB2, 0xEC, 0xC6, 0x66, 0x3B, 0xB7, 0xBA, 0xF6, 0x2C, 0xE7, 0x4D, 0x9E, 0xAF, 0xFC, 0x17, 0x5C, 0x86, 0x29, 0xD4, 0xD9, 0x25, 0x2C, 0x7E, 0x5C, 0xDA, 0xB0, 0x6D, 0xA1, 0x1C, 0x46, 0xE9, 0x50, 0xA2, 0xCD, 0x4C, 0x06, 0x74, 0xC0, 0xC6, 0xE2, 0x97, 0xF0, 0xE6, 0xFD, 0xE9, 0x6F, 0xA0, 0x72, 0x8E, 0x32, 0x31, 0x40, 0x30, 0x03, 0x98, 0x4B, 0x5A, 0x7F, 0x97, 0x52, 0x63, 0xB2, 0xA5, 0xAD, 0xD7, 0x33, 0x59, 0x31, 0xEA, 0x85, 0x02, 0x19, 0x58, 0xE1, 0xC4, 0x97, 0xDB, 0x73, 0xB9, 0x11, 0xF2, 0xD4, 0x93, 0xEA, 0xD3, 0xAA, 0xBA, 0x2A, 0xA8, 0xD2, 0x9F, 0x5D, 0xAE, 0xCA, 0xD5, 0x32, 0xA3, 0xD3, 0x1D, 0xB8, 0xA3, 0x47, 0xD1, 0x45, 0x40, 0xA3, 0xCE, 0x92, 0x76, 0x9A, 0x05, 0x19, 0x76, 0xDD, 0x73, 0x54, 0x70, 0x6E, 0x46, 0x8E, 0xDE, 0x7B, 0x39, 0x6A, 0x09, 0x88, 0xF2, 0x8E, 0x3C, 0x8C, 0x34, 0x74, 0x1B, 0x98, 0xDA, 0x58, 0x5E, 0xA3, 0x11, 0x67, 0x67, 0xD7, 0x63, 0xC5, 0xBF, 0x5F, 0x13, 0x0D, 0x7F, 0xDC, 0xAD, 0x96, 0xB4, 0xDC, 0xD8, 0xD6, 0xED, 0x7E, 0x42, 0xC3, 0x68, 0x17, 0xDD, 0x34, 0x9B, 0x08, 0x7F, 0x6E, 0xD7, 0xBA, 0x6D, 0x88, 0xC9, 0x97, 0x3B, 0x3F, 0x42, 0x8A, 0x78, 0x35, 0x8B, 0x00, 0x27, 0x8F, 0xE6, 0x20, 0xC4, 0x88, 0x62, 0x4C, 0x0F, 0x79, 0xE9, 0x7E, 0x6D, 0x48, 0x54, 0xC7, 0x56, 0x95, 0x79, 0xBD, 0x33, 0xBF, 0xD2, 0x6F, 0x55, 0x77, 0x2B, 0x48, 0xEC, 0x6C, 0x06, 0xF1, 0x97, 0x02, 0xB1, 0x11, 0x22, 0x04, 0x0C, 0x7A, 0x94, 0xE9, 0xDF, 0x85, 0x48, 0x36, 0xFF, 0x1E, 0xF2, 0x6B, 0x08, 0x36, 0x87, 0xAB, 0x0C, 0xD5, 0x60, 0x0A, 0xFC, 0x5C, 0x0D, 0xD0, 0x4D, 0xC3, 0x33, 0x4A, 0x4C, 0xAE, 0x2F, 0xF0, 0x7C, 0xA7, 0x43, 0x76, 0x28, 0xCE, 0x7D, 0xB1, 0x2D, 0x7C, 0x80, 0xA1, 0x4C, 0x0E, 0xF4, 0xB2, 0x42, 0xB7, 0x47, 0xF5, 0x65, 0x16, 0x9E, 0x60, 0xB1, 0x79, 0x89, 0xE8, 0x19, 0x78, 0x19, 0x30, 0xAD, 0x5D, 0x13, 0x36, 0x3B, 0x19, 0x69, 0xB6, 0x72, 0x5C, 0xB5, 0x27, 0xDA, 0xA1, 0x59, 0x1A, 0x0A, 0x58, 0x69, 0xF3, 0x56, 0x55, 0x42, 0x26, 0x09, 0xF9, 0x8B, 0xF0, 0xDB, 0xF4, 0x4B, 0x2D, 0x21, 0x81, 0xA6, 0x48, 0xCA, 0xB0, 0x20, 0xE3, 0xE5, 0xA7, 0xCD, 0xD0, 0x1F, 0x38, 0x0C, 0xEB, 0xC8, 0x90, 0x1D, 0x08, 0xEE, 0xB1, 0x13, 0x19, 0x75, 0x57, 0x22, 0xA9, 0x84, 0xCE, 0x2E, 0x30, 0x61, 0x58, 0x4F, 0x23, 0x9C, 0x3C, 0xF5, 0x50, 0xE3, 0xE2, 0x7E, 0x6A, 0x31, 0x9E, 0x19, 0xD9, 0xFE, 0x6E, 0x6F, 0x9E, 0x4C, 0x77, 0x05, 0xCF, 0x06, 0x12, 0xB2, 0x50, 0x56, 0x41, 0xDA, 0x74, 0xCE, 0x6D, 0x11, 0x05, 0xCA, 0x90, 0xD5, 0xAD, 0x5B, 0xAA, 0x9D, 0x56, 0xF6, 0x35, 0x39, 0x8D, 0x25, 0xA7, 0x5E, 0x14, 0x75, 0x3B, 0xC3, 0x7A, 0x58, 0x42, 0xE4, 0xCA, 0x84, 0xFC, 0x2A, 0xE7, 0xB2, 0x94, 0xD9, 0xB9, 0xC5, 0x77, 0x3A, 0x20, 0xD9, 0x0A, 0x48, 0x3D, 0x43, 0x83, 0x7B, 0xB0, 0x97, 0x1B, 0x3A, 0x56, 0xF4, 0x86, 0xFB, 0xC6, 0x90, 0xB3, 0x39, 0x7A, 0xA0, 0x18, 0x77, 0x4C, 0xA2, 0x41, 0x9B, 0x0C, 0xE4, 0x35, 0xAA, 0x68, 0xCF, 0xA7, 0xD6, 0x86, 0xEB, 0x08, 0xF3, 0x44, 0x6A, 0x53, 0x86, 0x8F, 0xDE, 0x20, 0x47, 0x9A, 0x6B, 0x9E, 0xD8, 0x57, 0x4D, 0xA4, 0xB3, 0x65, 0xD8, 0x53, 0x1D, 0xCC, 0x20, 0xEF, 0x22, 0x74, 0x22, 0x48, 0x8B, 0xF2, 0xC1, 0xE1, 0x51, 0x78, 0x11, 0x65, 0x79, 0x87, 0x1A, 0xC1, 0xED, 0xDD, 0xCC, 0x4A, 0xC0, 0xDF, 0x60, 0xCC, 0xC1, 0x9E, 0xD3, 0xB0, 0x77, 0xA5, 0x76, 0x3B, 0x04, 0xEB, 0x59, 0x71, 0xBD, 0x1F, 0x56, 0x83, 0x92, 0x60, 0x58, 0x1D, 0x63, 0x4D, 0x18, 0x5B, 0xA8, 0xC3, 0x4A, 0xF7, 0xE2, 0xEC, 0x78, 0x91, 0xC3, 0x12, 0xB9, 0xD9, 0x3C, 0x95, 0x27, 0xAB, 0x54, 0x3E, 0xCB, 0x0D, 0x9C, 0xA9, 0x0F, 0xF8, 0x27, 0x83, 0x09, 0x85, 0xB0, 0xFE, 0x39, 0x08, 0x35, 0xA1, 0xD9, 0x89, 0xA4, 0x56, 0xCC, 0x90, 0xBD, 0x07, 0x58, 0x8B, 0x5A, 0x05, 0x72, 0x62, 0x15, 0x30, 0x71, 0xCE, 0x90, 0x63, 0x66, 0x7D, 0x6B, 0x27, 0x74, 0x41, 0x67, 0x5F, 0x07, 0xA6, 0xCA, 0xF8, 0x55, 0x2C, 0x0D, 0x00, 0x47, 0x4E, 0xD2, 0xC3, 0x67, 0x93, 0x0F, 0xF5, 0xE5, 0xFD, 0x95, 0x31, 0x9F, 0xF8, 0x08, 0xEE, 0x3B, 0xC2, 0x44, 0x89, 0xEF, 0x9B, 0xEB, 0xF8, 0x09, 0x7A, 0x3F, 0xE7, 0x46, 0xC0, 0x65, 0x02, 0x11, 0xD4, 0x29, 0xC0, 0x6E, 0xBC, 0x8F, 0x44, 0xDA, 0x33, 0x3D, 0x25, 0xB9, 0xFE, 0x74, 0xA0, 0x92, 0x1F, 0xB8, 0xAA, 0x76, 0x6E, 0xF2, 0x00, 0x87, 0xAE, 0xA4, 0xEC, 0xD7, 0x1B, 0xA4, 0x27, 0xF1, 0xB3, 0x29, 0x2B, 0x85, 0xB3, 0xF8, 0x6F, 0xDF, 0x21, 0x44, 0x69, 0x13, 0x77, 0xFE, 0x97, 0xCA, 0x67, 0xD2, 0xD4, 0x73, 0x4F, 0xB2, 0x36, 0x80, 0xCA, 0x96, 0xDB, 0xBA, 0x64, 0x32, 0x1C, 0x5E, 0x07, 0xA6, 0x8C, 0xA8, 0x96, 0x01, 0xE9, 0xE5, 0x18, 0x34, 0x4C, 0x1B, 0xB1, 0x86, 0x3F, 0xC1, 0xAE, 0xBD, 0xBE, 0xAF, 0xE0, 0x38, 0x95, 0x57, 0x8D, 0x56, 0x99, 0x33, 0xA2, 0xC5, 0x7A, 0xA3, 0x4E, 0xB0, 0x5B, 0xB3, 0xC1, 0x8C, 0xF3, 0x6C, 0x00, 0x19, 0xCF, 0xE5, 0x69, 0x19, 0x29, 0xE1, 0x30, 0x40, 0x78, 0x47, 0xBC, 0x12, 0xA1, 0x1B, 0x89, 0xAF, 0x49, 0xC1, 0x7C, 0x79, 0x99, 0x36, 0x19, 0x99, 0xED, 0xAB, 0x50, 0xDF, 0x3C, 0x4B, 0xE1, 0x5A, 0x6C, 0x5C, 0x8E, 0x6B, 0xC2, 0x98, 0xCF, 0xC4, 0x63, 0xB5, 0xB3, 0xBE, 0xD7, 0x5A, 0x86, 0x50, 0x1D, 0x6B, 0x88, 0x19, 0xDA, 0xA1, 0xE1, 0x3F, 0xAD, 0xA5, 0x44, 0x64, 0xCB, 0xBD, 0x39, 0x74, 0x94, 0x1C, 0x02, 0x25, 0x71, 0x00, 0x17, 0x43, 0x69, 0x6E, 0x89, 0x99, 0x4E, 0xE3, 0x28, 0xCB, 0x98, 0x19, 0x2D, 0x91, 0x32, 0x60, 0x84, 0x86, 0x1B, 0x01, 0xA7, 0x52, 0x41, 0x3A, 0xA4, 0xD4, 0x75, 0xC3, 0x28, 0x2B, 0x7E, 0xFB, 0xED, 0xFC, 0x3F, 0x62, 0x68, 0x4F, 0x29, 0x29, 0x72, 0x99, 0x5A, 0x04, 0xDE, 0x24, 0x2A, 0x26, 0x7F, 0x75, 0x05, 0x0D, 0x3A, 0x6F, 0xFC, 0x34, 0x72, 0xB6, 0x6B, 0x3E, 0x64, 0xB7, 0x17, 0x74, 0x81, 0xF1, 0x56, 0x8F, 0xF8, 0x9C, 0xC0, 0x41, 0x15, 0xC9, 0xF7, 0x8A, 0x0F, 0x49, 0xAC, 0x3C, 0x0A, 0x00, 0x5A, 0x8E, 0x46, 0x28, 0xFD, 0xB6, 0x2E, 0xD6, 0x25, 0xA7, 0x6C, 0xEF, 0x53, 0x27, 0x90, 0x5B, 0x54, 0x48, 0x85, 0xB3, 0xEC, 0x9E, 0x52, 0x0D, 0x2E, 0x32, 0x8A, 0xF5, 0xF3, 0x1C, 0xFF, 0x7E, 0x0C, 0xDD, 0x89, 0x5A, 0xD0, 0x8D, 0xCD, 0x9F, 0x59, 0xB8, 0x4F, 0x22, 0x58, 0x81, 0xFD, 0x83, 0xFD, 0xDC, 0x58, 0x26, 0xB4, 0xB9, 0x70, 0x23, 0xC5, 0x91, 0x4F, 0x17, 0x00, 0x1D, 0xB1, 0x70, 0x6A, 0x66, 0x58, 0xB5, 0x47, 0x3F, 0x16, 0xBF, 0x6E, 0xB3, 0xC4, 0x7D, 0x11, 0x1A, 0xE9, 0x2E, 0x39, 0x12, 0x39, 0xA9, 0x45, 0xD5, 0x98, 0x8C, 0x5F, 0x05, 0xE2, 0x99, 0xE6, 0x9F, 0xE1, 0xDA, 0x1B, 0x31, 0x58, 0x55, 0x90, 0xB2, 0x6D, 0x7C, 0x55, 0x94, 0x7C, 0x00, 0xEB, 0x32, 0x42, 0x07, 0x8B, 0x39, 0x24, 0x9E, 0xB2, 0xC6, 0x00, 0xFA, 0xDE, 0xE8, 0x06, 0x86, 0xDF, 0x5B, 0x37, 0xD2, 0xD1, 0x5E, 0x44, 0x49, 0x56, 0x65, 0x2C, 0x72, 0x4F, 0x1D, 0x5D, 0x13, 0x9D, 0x1D, 0xFB, 0x4D, 0x6B, 0xE4, 0x4E, 0x3C, 0x57, 0x3B, 0x60, 0xB8, 0x32, 0x98, 0x34, 0xF2, 0xF5, 0xDD, 0xC3, 0x68, 0x81, 0x6C, 0x52, 0x8D, 0x88, 0x28, 0xED, }, .priv_len = 4896, .pub = { 0xCA, 0xDE, 0xD2, 0x24, 0xB8, 0xF0, 0xB4, 0xCE, 0x30, 0x19, 0x85, 0x30, 0x5F, 0x5E, 0xCF, 0xF5, 0x03, 0xDD, 0x4E, 0xCC, 0xF0, 0x69, 0xB9, 0xAB, 0x3C, 0xFA, 0x07, 0x4E, 0x89, 0x22, 0x41, 0xBB, 0x66, 0x7F, 0x74, 0x0D, 0xF1, 0x71, 0xE4, 0x95, 0x5A, 0x29, 0xF6, 0x96, 0x53, 0x19, 0x2F, 0xDB, 0x7E, 0x65, 0xAB, 0x5C, 0x64, 0xCC, 0xDD, 0xBC, 0x4B, 0x91, 0xAB, 0x36, 0x3F, 0x5A, 0xA9, 0x8B, 0x3D, 0xAF, 0xAB, 0xFF, 0x8A, 0xFC, 0x6C, 0x71, 0x1A, 0x74, 0xB7, 0x4C, 0x9C, 0xBD, 0x6D, 0xA2, 0x33, 0xE9, 0x08, 0x39, 0x80, 0x28, 0xA0, 0x6A, 0xF0, 0xA1, 0x0E, 0x79, 0x4B, 0xA5, 0xC5, 0xE0, 0x06, 0xA1, 0x0A, 0x4D, 0xA9, 0x64, 0xC1, 0x55, 0xFC, 0xBE, 0x68, 0x2A, 0x61, 0xEA, 0x77, 0xC6, 0x59, 0xB5, 0xF8, 0xFD, 0x8A, 0xFC, 0xFA, 0xFA, 0xDA, 0x4F, 0xDC, 0x01, 0x45, 0x19, 0x85, 0x90, 0x63, 0x1C, 0x76, 0x87, 0x5B, 0xBE, 0xC7, 0x67, 0x88, 0x9F, 0xAB, 0xD0, 0xC7, 0x30, 0x20, 0x90, 0x6B, 0x86, 0x3A, 0x38, 0xFE, 0x83, 0x14, 0xAB, 0xE7, 0xE7, 0x31, 0x5F, 0xB9, 0x54, 0x21, 0x57, 0x2C, 0x32, 0x55, 0x20, 0xEE, 0x55, 0x45, 0xD8, 0x9B, 0x70, 0xFA, 0x4F, 0x70, 0x6A, 0xEF, 0x39, 0x78, 0x30, 0x36, 0x4B, 0x23, 0x1E, 0x18, 0xDB, 0xE0, 0x1E, 0x49, 0xDD, 0x80, 0x39, 0x69, 0x95, 0x4E, 0x02, 0x43, 0x8C, 0x5D, 0xA3, 0xA4, 0xCC, 0x61, 0x4B, 0x37, 0x26, 0xD2, 0x9C, 0xF6, 0xEF, 0x4B, 0x64, 0x49, 0xBE, 0x9E, 0x6A, 0x95, 0x0F, 0x18, 0xEE, 0xAA, 0xEF, 0xFF, 0xA5, 0x8C, 0xF6, 0x0D, 0x98, 0x6F, 0x01, 0x73, 0x2B, 0x47, 0x56, 0x3D, 0x2C, 0x84, 0xA6, 0x82, 0x17, 0xE3, 0x56, 0x52, 0x17, 0x7D, 0x1C, 0x9D, 0x11, 0x17, 0x5F, 0xE4, 0xDA, 0x61, 0x22, 0x64, 0x1B, 0x53, 0x59, 0x8F, 0xB6, 0x45, 0x8A, 0x9B, 0x99, 0x3D, 0x5A, 0xB4, 0xB8, 0x5A, 0xFA, 0x4F, 0x7E, 0x99, 0x03, 0x78, 0x05, 0x13, 0xF4, 0x99, 0x32, 0x55, 0xF8, 0xE2, 0xEA, 0xA8, 0x72, 0xA8, 0x4F, 0xDC, 0x50, 0x92, 0x49, 0x60, 0x39, 0x19, 0x15, 0xB1, 0x1B, 0xA6, 0x11, 0x17, 0x10, 0x35, 0xD3, 0x43, 0x2F, 0x9E, 0xC3, 0xE7, 0xC4, 0x7C, 0x94, 0xA6, 0x6B, 0xF3, 0xE4, 0x2F, 0x65, 0xC3, 0x55, 0x21, 0x3A, 0xFE, 0x02, 0xDC, 0x76, 0xCC, 0xD9, 0xCD, 0x8D, 0xA5, 0xDD, 0x00, 0x88, 0xEF, 0xC8, 0x48, 0x0E, 0xE6, 0x05, 0x13, 0x44, 0xEC, 0x8E, 0x0B, 0x0C, 0xCD, 0x36, 0x96, 0xF2, 0xEF, 0xF4, 0x66, 0x45, 0x11, 0xC7, 0x95, 0x1C, 0x01, 0x60, 0xA3, 0xB2, 0x6D, 0x8A, 0x36, 0xBA, 0x57, 0xC5, 0x5A, 0x99, 0x2F, 0xA2, 0x01, 0x70, 0x9D, 0x20, 0x63, 0xEF, 0x86, 0x79, 0x6C, 0xD3, 0xCA, 0xAA, 0x10, 0x14, 0x18, 0xDA, 0xE9, 0xA8, 0x66, 0xD1, 0x54, 0x22, 0xC3, 0xA9, 0x70, 0x20, 0x82, 0xD6, 0x73, 0x50, 0x6B, 0xA9, 0x7C, 0xA6, 0x51, 0x2B, 0xCC, 0x86, 0x55, 0x95, 0xFF, 0x99, 0x97, 0xA5, 0x89, 0xFB, 0x60, 0x5A, 0x9A, 0x52, 0xFD, 0xCA, 0xB3, 0xF4, 0x21, 0x59, 0x28, 0xE9, 0x47, 0x8A, 0x46, 0xD0, 0x8E, 0x22, 0xFD, 0x87, 0x74, 0xB2, 0x7A, 0x5A, 0xCB, 0x39, 0x4B, 0x6A, 0x47, 0x54, 0x13, 0x8D, 0xBE, 0x48, 0x1D, 0x6B, 0x8F, 0x2C, 0xE4, 0x37, 0x51, 0xF3, 0x7C, 0xF6, 0x25, 0xB4, 0x7B, 0x40, 0xE9, 0x45, 0xEB, 0xD2, 0x08, 0x36, 0xCD, 0x38, 0xA1, 0x80, 0xAE, 0x64, 0x54, 0xF8, 0x6A, 0xF7, 0xEC, 0x41, 0x52, 0xBD, 0x66, 0x0E, 0xB2, 0x25, 0x49, 0xE1, 0x78, 0xD2, 0x36, 0x39, 0xF0, 0x00, 0x17, 0x1B, 0x33, 0x62, 0x8C, 0x02, 0x5C, 0x73, 0x7A, 0x42, 0x62, 0x47, 0x92, 0xD5, 0x10, 0xEB, 0x32, 0x95, 0x96, 0x55, 0x99, 0xEA, 0x2A, 0x35, 0x13, 0xE0, 0x79, 0x08, 0x2E, 0x1E, 0x55, 0xA9, 0xE7, 0xC1, 0xC7, 0x75, 0x6E, 0xA2, 0xE2, 0x95, 0x71, 0x85, 0x54, 0x0C, 0xFF, 0xB5, 0x67, 0xF7, 0x4A, 0x60, 0x6D, 0xD2, 0x1F, 0x4D, 0xC3, 0xB1, 0xDD, 0x1D, 0xB7, 0x67, 0x5E, 0xFE, 0x0A, 0xE4, 0x17, 0x0F, 0xE5, 0x9B, 0x7F, 0x8F, 0x55, 0x76, 0xEA, 0x0B, 0x1D, 0xEF, 0x1D, 0x29, 0x14, 0xE2, 0x25, 0x92, 0x79, 0xE8, 0x2D, 0xA6, 0x3C, 0x06, 0xD1, 0x7A, 0x46, 0x27, 0xE6, 0x42, 0x2F, 0x5B, 0x4A, 0x0C, 0xFF, 0x30, 0x29, 0x4D, 0x5D, 0x10, 0xD3, 0xF2, 0x6C, 0x51, 0x58, 0x01, 0x4F, 0xDC, 0xAF, 0x7D, 0x60, 0x53, 0xE9, 0xF1, 0x9D, 0x7D, 0x68, 0xEF, 0xB7, 0x04, 0xD9, 0xC2, 0x1E, 0x52, 0x95, 0x51, 0x58, 0x2E, 0x29, 0x64, 0xD1, 0x59, 0x2E, 0x97, 0x4F, 0x6C, 0xE0, 0x67, 0x3E, 0x67, 0xFB, 0xE0, 0xB3, 0xBD, 0x21, 0xD6, 0x65, 0x20, 0x2C, 0xF2, 0x28, 0x3B, 0xA9, 0xA4, 0x93, 0x7F, 0x22, 0x99, 0xE5, 0xFB, 0x1A, 0xA7, 0x5A, 0xE2, 0x25, 0xA5, 0xAE, 0x4E, 0xEB, 0xCE, 0x61, 0x54, 0xBA, 0x69, 0xDC, 0x90, 0x6D, 0xC0, 0xD4, 0xE8, 0x14, 0x74, 0x82, 0x13, 0x50, 0x13, 0x60, 0xB0, 0x41, 0xD3, 0xDF, 0x81, 0x1E, 0x13, 0xB3, 0x10, 0x3F, 0x3B, 0x71, 0x7B, 0x60, 0x11, 0x3C, 0xE9, 0x6C, 0x26, 0x7D, 0xD0, 0x92, 0xA8, 0xF6, 0x54, 0x68, 0xBD, 0x88, 0xF8, 0x54, 0x11, 0x34, 0x77, 0x58, 0xF5, 0x40, 0xE8, 0x61, 0xE0, 0x96, 0x10, 0x8E, 0xEB, 0x00, 0x2C, 0x8D, 0x81, 0xB0, 0xC6, 0xF5, 0xAD, 0x86, 0x67, 0xE4, 0xE1, 0x15, 0x06, 0x64, 0x9D, 0x82, 0x98, 0xCD, 0x5C, 0xB3, 0x2B, 0x3B, 0x98, 0x10, 0x92, 0x67, 0x8F, 0xEC, 0x40, 0xE0, 0x5B, 0x95, 0xA6, 0x64, 0x1E, 0xE5, 0x86, 0xE7, 0x01, 0x07, 0xC1, 0xDF, 0x9A, 0x7F, 0xD3, 0x05, 0x4D, 0x6A, 0xDD, 0xE8, 0x57, 0xA7, 0x02, 0x8A, 0x4F, 0xF9, 0x54, 0x16, 0x6F, 0x02, 0x59, 0x14, 0x43, 0x2E, 0x9D, 0x4B, 0x2E, 0x02, 0x69, 0x6D, 0x85, 0x5B, 0xC3, 0x7A, 0x49, 0x0B, 0xC4, 0x49, 0xBE, 0x6F, 0x91, 0x75, 0xDE, 0x94, 0xA8, 0x40, 0x6E, 0xB6, 0x25, 0x2F, 0xF4, 0x79, 0xB2, 0x53, 0xBC, 0x8E, 0x1C, 0x7A, 0xE3, 0x46, 0x29, 0xA1, 0x30, 0xF8, 0x53, 0x27, 0xB0, 0x18, 0x6D, 0x01, 0xCA, 0xBD, 0x68, 0xD8, 0x3C, 0x8B, 0x15, 0xD9, 0xEE, 0x64, 0xD5, 0x4D, 0xC3, 0xE7, 0xA5, 0xD1, 0xA2, 0x13, 0x9C, 0xC8, 0xCB, 0x26, 0x72, 0xB0, 0x68, 0xDE, 0x8B, 0xE0, 0x4C, 0x85, 0xCF, 0xC5, 0x02, 0x14, 0xA2, 0x2F, 0xFE, 0x05, 0xA6, 0x0A, 0x82, 0xC7, 0xFD, 0x8D, 0x86, 0xA8, 0x02, 0x19, 0x96, 0x91, 0x8B, 0x98, 0x12, 0x79, 0xCA, 0xB2, 0x74, 0x93, 0xC6, 0x89, 0x7A, 0x55, 0xDF, 0xEB, 0x22, 0xDF, 0x89, 0x61, 0x4D, 0x07, 0x8C, 0x39, 0x24, 0x87, 0x98, 0xBB, 0x8F, 0x2A, 0xDD, 0x1D, 0x6F, 0x8B, 0x06, 0xEF, 0xAB, 0x57, 0xC6, 0xEF, 0x1C, 0xE0, 0xA9, 0x07, 0xE2, 0xE7, 0x23, 0xF5, 0x5E, 0xB3, 0x68, 0xCD, 0xAF, 0x8B, 0xFA, 0x6B, 0x8E, 0x74, 0xDE, 0xDE, 0x8B, 0xA4, 0x85, 0x0E, 0x69, 0x6B, 0x1A, 0x3A, 0x39, 0x08, 0xE2, 0x9F, 0x03, 0xC2, 0x22, 0xCC, 0x2F, 0x97, 0x98, 0x73, 0x6C, 0x31, 0xC8, 0x6D, 0x2A, 0x47, 0x3B, 0xA6, 0xB5, 0x0F, 0x32, 0x87, 0xDF, 0x4C, 0x4F, 0x82, 0xD8, 0x83, 0x72, 0x95, 0x1B, 0x5C, 0x06, 0xC0, 0x63, 0x27, 0x6A, 0x19, 0x4D, 0x4D, 0x1C, 0xAA, 0x21, 0xD5, 0xFF, 0x1A, 0xB2, 0x7F, 0xC9, 0xC1, 0x79, 0x54, 0x55, 0xFB, 0x5B, 0xF9, 0x3F, 0x0B, 0x89, 0x4C, 0x5A, 0x9B, 0xF4, 0x2E, 0x55, 0xAE, 0x5B, 0xBF, 0x07, 0xE0, 0x13, 0x9A, 0xDE, 0x1A, 0xF2, 0xD4, 0x10, 0x12, 0x75, 0x31, 0x5D, 0xBE, 0xAD, 0x21, 0x9D, 0x6F, 0xF6, 0xC3, 0xC9, 0xC5, 0xAF, 0x6B, 0x14, 0x9B, 0xA7, 0x1E, 0x6D, 0xD3, 0x45, 0x3C, 0xCA, 0xC0, 0xC9, 0xCE, 0x85, 0x7E, 0x3A, 0x0A, 0x0B, 0x3E, 0x7B, 0x9C, 0xAD, 0x9D, 0x2C, 0xBE, 0xA1, 0x6D, 0xA5, 0x68, 0x00, 0x63, 0xD3, 0x2B, 0x03, 0x15, 0xDD, 0x2C, 0x76, 0xD4, 0x9D, 0x48, 0xBE, 0xE2, 0x57, 0xA6, 0xAD, 0xB4, 0xF4, 0x43, 0x80, 0x70, 0x27, 0xC8, 0xC9, 0x29, 0x59, 0x9E, 0x7F, 0x12, 0x39, 0x05, 0x28, 0x37, 0xB0, 0x69, 0xAE, 0xC6, 0xB6, 0x2F, 0x6F, 0x7C, 0x91, 0x3C, 0x0A, 0x3A, 0xCA, 0x73, 0xDA, 0x26, 0x97, 0xFF, 0x1A, 0x5C, 0x48, 0x06, 0x90, 0x83, 0x70, 0x8B, 0x86, 0xAF, 0x96, 0x90, 0x6F, 0x28, 0x74, 0xFA, 0x69, 0x14, 0xB7, 0x29, 0x1B, 0x02, 0xCC, 0x52, 0x50, 0xFD, 0xCD, 0x6C, 0xBD, 0x61, 0xF1, 0x12, 0x48, 0x4D, 0x61, 0x81, 0xEF, 0xBE, 0xA2, 0x28, 0xA0, 0xA5, 0x80, 0xB4, 0xB7, 0xE6, 0xF8, 0xF0, 0x80, 0x6F, 0x2B, 0xA7, 0x64, 0x55, 0x8F, 0x4B, 0x52, 0x1F, 0x93, 0x3D, 0x8D, 0xD5, 0x56, 0xA7, 0xA2, 0x55, 0x60, 0x09, 0x4F, 0xD7, 0xBC, 0x5A, 0x0F, 0x82, 0x10, 0x44, 0x60, 0x36, 0x2D, 0xBC, 0x92, 0xCC, 0x0E, 0x7D, 0xF9, 0xE4, 0x38, 0x49, 0xDB, 0xC9, 0x0E, 0x67, 0xE2, 0x03, 0xB4, 0x39, 0xE8, 0xC6, 0xDC, 0x3C, 0xF2, 0x3C, 0xDE, 0x5F, 0x91, 0x38, 0x86, 0xD9, 0x44, 0x5D, 0x6A, 0xC6, 0x8B, 0x0B, 0x80, 0xBA, 0xE5, 0x4F, 0x35, 0x24, 0x59, 0x0A, 0xBD, 0x52, 0xB6, 0x7D, 0x91, 0x01, 0x24, 0x75, 0xB8, 0x16, 0xDB, 0x73, 0x4E, 0x13, 0x94, 0x0F, 0x16, 0x9F, 0xCE, 0xDD, 0xC5, 0x2C, 0xD9, 0xA0, 0xAE, 0x23, 0xD0, 0x2A, 0x94, 0x9A, 0x28, 0x42, 0xA0, 0x2A, 0x76, 0xF1, 0xA4, 0x85, 0x00, 0x7A, 0xD5, 0x70, 0xFC, 0xC0, 0x37, 0xB0, 0x02, 0xFE, 0x37, 0x9D, 0x45, 0xD9, 0x05, 0xA6, 0x86, 0xD4, 0xBF, 0x26, 0x41, 0x2E, 0x9E, 0x50, 0x82, 0xE7, 0x51, 0x93, 0x34, 0x26, 0xEA, 0xE7, 0x07, 0x2D, 0xA4, 0x82, 0xEA, 0x11, 0x5B, 0x73, 0xB5, 0xDB, 0xFE, 0xD8, 0x12, 0x81, 0xE2, 0xA2, 0x89, 0x60, 0x44, 0x4A, 0x12, 0xBD, 0x9C, 0xE6, 0x8F, 0x7B, 0x8B, 0xC4, 0x8A, 0x7F, 0x83, 0xD9, 0x52, 0xA3, 0xBD, 0xF6, 0x3C, 0xDA, 0x94, 0xB1, 0xB7, 0x3D, 0x15, 0x8A, 0xB1, 0x6F, 0x9E, 0x7F, 0x53, 0x60, 0xE5, 0x84, 0x9D, 0x55, 0x4B, 0x92, 0xB3, 0x47, 0x89, 0x70, 0x68, 0xF4, 0xBC, 0xDD, 0xBC, 0x91, 0x6F, 0x7E, 0xF1, 0xB9, 0x93, 0xD9, 0xD3, 0xEB, 0x4A, 0xA7, 0x5E, 0x31, 0x82, 0x31, 0x74, 0xFC, 0x63, 0xA7, 0x0D, 0xF1, 0x80, 0x6E, 0xFF, 0x2D, 0xEC, 0x98, 0x82, 0x72, 0x2A, 0x30, 0xB4, 0x91, 0x5E, 0x67, 0x9D, 0x94, 0xF6, 0x99, 0x95, 0x97, 0xB6, 0x09, 0x5F, 0xEC, 0x48, 0xC6, 0x4D, 0xA0, 0x0F, 0x61, 0x58, 0x46, 0x26, 0xF5, 0x0D, 0x9B, 0x54, 0xCC, 0x94, 0xED, 0xF3, 0xD4, 0xDC, 0x85, 0x7C, 0x50, 0x71, 0x2F, 0x8A, 0xB8, 0x22, 0xA8, 0x7F, 0x4F, 0xFC, 0x7E, 0x50, 0x9A, 0x46, 0x69, 0xA7, 0x75, 0x4C, 0x56, 0x10, 0x22, 0xC0, 0x63, 0x75, 0xC7, 0x88, 0xF5, 0x4D, 0x58, 0xDC, 0x25, 0x1C, 0xAF, 0xD6, 0x23, 0xAC, 0x83, 0xCA, 0x9E, 0xBB, 0xE3, 0x92, 0x87, 0xE4, 0xFB, 0x54, 0xE6, 0x2E, 0x3C, 0x48, 0xCF, 0x8A, 0x2C, 0xC2, 0xE5, 0xC0, 0x5F, 0x27, 0x14, 0x1E, 0xA7, 0x2B, 0x72, 0x88, 0x59, 0xBF, 0x62, 0xCF, 0xCE, 0xBC, 0x55, 0x07, 0xA3, 0x71, 0x38, 0x33, 0x63, 0x2B, 0xEF, 0x4C, 0xEA, 0x24, 0x8D, 0x35, 0x0A, 0x24, 0x78, 0x02, 0xE3, 0xAA, 0xC6, 0xF2, 0x83, 0x83, 0x49, 0x00, 0x73, 0xBC, 0xF5, 0xFF, 0x95, 0x25, 0x05, 0xE3, 0x76, 0x41, 0xDE, 0x1E, 0xB0, 0x78, 0xB5, 0x18, 0x37, 0xAA, 0x61, 0xFB, 0x40, 0xB6, 0x8A, 0x78, 0x25, 0xF2, 0x08, 0xF9, 0x04, 0xC4, 0x11, 0xD1, 0xA0, 0x07, 0xC1, 0x59, 0x3A, 0x6B, 0x0D, 0x8C, 0x93, 0xFB, 0x99, 0x99, 0x05, 0x3D, 0xA7, 0x89, 0xA0, 0xB6, 0xCC, 0xB9, 0xBE, 0xE2, 0xB2, 0x75, 0x2A, 0x26, 0x63, 0x73, 0x10, 0x3E, 0x4C, 0x04, 0x36, 0xA1, 0x7D, 0x38, 0x63, 0x91, 0xC6, 0x25, 0x06, 0x0A, 0xE6, 0x88, 0x5A, 0xC2, 0x3C, 0xB0, 0x91, 0x19, 0x1E, 0x8D, 0x64, 0x34, 0xEC, 0x70, 0x39, 0x6F, 0x8C, 0xFE, 0x83, 0x6C, 0xF9, 0x8F, 0x90, 0xE3, 0x2C, 0x0F, 0x12, 0xFF, 0x4F, 0xBC, 0xBE, 0xD7, 0xF6, 0x8E, 0xC9, 0x37, 0xB7, 0x43, 0xD5, 0x03, 0xC6, 0x3F, 0xF3, 0x7C, 0x8C, 0x79, 0x60, 0xA7, 0xB4, 0x39, 0xFB, 0x10, 0xA2, 0x00, 0x03, 0x42, 0x4E, 0x8F, 0xA8, 0xC0, 0xDB, 0x5E, 0xEA, 0x97, 0x66, 0x8B, 0xC2, 0xE3, 0x81, 0xC6, 0xB3, 0x23, 0x73, 0x95, 0xAE, 0xF0, 0x9C, 0x56, 0xAF, 0xB7, 0x9F, 0x65, 0x88, 0x16, 0xB2, 0x2E, 0xDB, 0x68, 0xFE, 0x6E, 0xF3, 0x45, 0x9A, 0xD8, 0xB5, 0xE1, 0x1F, 0x22, 0x5A, 0x6C, 0xE4, 0x17, 0x8D, 0x22, 0x42, 0x00, 0x10, 0x6F, 0x20, 0x52, 0xC1, 0x29, 0x77, 0xC0, 0x40, 0x97, 0x19, 0xFE, 0x41, 0x08, 0xCD, 0xF6, 0xBC, 0x5E, 0x79, 0x04, 0x4C, 0x2E, 0xAE, 0x03, 0xCD, 0xCB, 0x54, 0xC3, 0x1C, 0xC0, 0x44, 0xC3, 0xDD, 0x86, 0x61, 0xDC, 0xA6, 0x16, 0x0E, 0x39, 0xAB, 0x1A, 0x86, 0xE4, 0xA8, 0x4B, 0xC4, 0x62, 0xC5, 0x7E, 0x57, 0xD1, 0xF4, 0x39, 0x96, 0xCA, 0x9F, 0x8F, 0xA6, 0x03, 0x06, 0x8D, 0x7A, 0x0F, 0xF7, 0xCF, 0x86, 0x08, 0x0D, 0xB8, 0x28, 0x87, 0x70, 0x82, 0x33, 0x71, 0xE8, 0x5B, 0xF0, 0x6A, 0x27, 0xE6, 0x90, 0xC0, 0x4D, 0x9E, 0x97, 0x1E, 0x69, 0x0D, 0xFA, 0x5A, 0xD0, 0x37, 0x3E, 0xB3, 0x69, 0x14, 0xC8, 0x46, 0xE5, 0x9C, 0xA4, 0x30, 0x01, 0xEF, 0xE9, 0x87, 0x94, 0xBB, 0x8D, 0xBA, 0x52, 0x9A, 0x7A, 0x53, 0x29, 0x5D, 0xCC, 0x95, 0xE8, 0xE6, 0xD2, 0x9E, 0x32, 0x29, 0xA6, 0x21, 0xC1, 0x88, 0x9F, 0x10, 0x0C, 0xF9, 0x8C, 0x31, 0x94, 0xBE, 0xA9, 0xD2, 0x39, 0xD3, 0xA5, 0xFB, 0xAD, 0xEC, 0x2E, 0x41, 0x34, 0x37, 0x9B, 0x1A, 0x29, 0xDC, 0x24, 0x03, 0x08, 0x12, 0xE9, 0xDD, 0x7C, 0x53, 0x8B, 0xBD, 0xC7, 0x00, 0x6E, 0xB3, 0xB0, 0xAC, 0x11, 0x65, 0xBA, 0xDA, 0x96, 0x5C, 0x57, 0x14, 0x10, 0xED, 0xF1, 0x7C, 0x86, 0x60, 0x75, 0x3B, 0xB2, 0x59, 0x83, 0xBC, 0x08, 0xC0, 0x3F, 0x6D, 0xE0, 0xA6, 0x2C, 0x21, 0x08, 0xEF, 0x16, 0x16, 0x0E, 0x8D, 0xE2, 0x9B, 0xD3, 0xC1, 0xE5, 0x51, 0xD0, 0x66, 0xDC, 0xCE, 0xCA, 0x31, 0x4A, 0x5A, 0x29, 0x40, 0x34, 0xEC, 0x85, 0x8B, 0xA5, 0x62, 0xBC, 0x49, 0xA3, 0x88, 0x76, 0xED, 0xAE, 0x78, 0xF2, 0xC8, 0x30, 0x5C, 0x95, 0x8D, 0xDA, 0x18, 0xC4, 0x8F, 0x45, 0x70, 0xF4, 0x7D, 0x0E, 0x2F, 0xF6, 0xB4, 0x2A, 0xE8, 0xF8, 0x7C, 0x2A, 0xFC, 0x4B, 0xE6, 0xB3, 0x9B, 0xAA, 0x85, 0x49, 0x73, 0x2A, 0x9C, 0x7A, 0x42, 0x12, 0x21, 0xBE, 0x15, 0xD4, 0xCC, 0x79, 0xD2, 0xF0, 0x8C, 0xD1, 0x40, 0x52, 0xC9, 0x29, 0xF6, 0x75, 0x2C, 0x88, 0xE6, 0xFA, 0x8D, 0x37, 0x3A, 0x1F, 0xD1, 0x58, 0x51, 0xE3, 0x65, 0x6B, 0x30, 0x9F, 0x28, 0x20, 0x98, 0x7C, 0xA6, 0xE3, 0x73, 0xB5, 0x0B, 0x73, 0x36, 0xA1, 0xFE, 0x1A, 0xFF, 0xDC, 0xC8, 0x62, 0xC3, 0x9A, 0x15, 0x9B, 0x97, 0x69, 0x41, 0xA7, 0x3A, 0x2F, 0xE0, 0x70, 0xD4, 0x3B, 0x5D, 0x0B, 0xBE, 0x84, 0xFE, 0xDD, 0x3B, 0x1E, 0x54, 0xFA, 0x47, 0x83, 0x7A, 0x5D, 0xC1, 0x87, 0x4D, 0x79, 0x72, 0x9C, 0xDC, 0x00, 0x66, 0xAA, 0x45, 0x53, 0x26, 0x88, 0x77, 0xA8, 0x78, 0x05, 0xCA, 0x8E, 0x9F, 0x34, 0x3A, 0x18, 0xBE, 0x07, 0xCA, 0x58, 0xCE, 0xA0, 0x8A, 0x50, 0xE5, 0x7E, 0x9B, 0x90, 0xC4, 0x8E, 0x4C, 0xB7, 0x00, 0x31, 0x5D, 0xCA, 0x83, 0xA4, 0xE3, 0x5C, 0xFD, 0x62, 0x6E, 0x5E, 0xB1, 0x4F, 0x19, 0x45, 0x43, 0xAA, 0x60, 0xB2, 0x55, 0x04, 0xA3, 0x05, 0x08, 0xAB, 0x48, 0xE3, 0xD5, 0x7E, 0x48, 0x6D, 0x57, 0x3D, 0xDA, 0x9D, 0x51, 0x1C, 0x66, 0x00, 0x65, 0x3E, 0xE3, 0xDD, 0xF7, 0x16, 0x69, 0xA3, 0xCB, 0x3E, 0xE7, 0x5B, 0xAA, 0x96, 0xB5, 0xB7, 0x7C, 0xB6, 0xC7, 0x83, 0x11, 0x83, 0x04, 0xFB, 0xEA, 0xFD, 0x6D, 0xE2, 0x4C, 0x83, 0x1D, 0x82, 0x67, 0x2B, 0xF8, 0xC7, 0xA7, 0x0E, 0x63, 0xC1, 0xD5, 0x0A, 0x1C, 0xA9, 0x5D, 0x05, 0xCE, 0x0A, 0xB6, 0x4B, 0x26, 0x01, 0x81, 0xFD, 0xF0, 0xDA, 0x73, 0x9F, 0xC8, 0x45, 0xAA, 0x0D, 0x4B, 0x70, 0x53, 0x18, 0xF7, 0x65, 0xEA, 0x24, 0x8A, 0xBF, 0x1A, 0x5F, 0x6C, 0x24, 0x68, 0x15, 0x98, 0xB8, 0x31, 0xEA, 0x86, 0x3C, 0xB5, 0xC9, 0xEF, 0xA1, 0xD6, 0x0C, 0x49, 0x44, 0xA8, 0xCF, 0x53, 0x54, 0x13, 0x21, 0x27, 0x32, 0x5A, 0xAE, 0xD0, 0xBB, 0x0D, 0x82, 0x22, 0xDD, 0x38, 0xD2, 0xA8, 0xA9, 0x73, 0xC1, 0x0D, 0xC8, 0x34, 0xF3, 0xA1, 0x1F, 0xCE, 0x0C, 0xDD, 0x24, 0xBE, 0x7A, 0xB8, 0x38, 0x7E, 0xC5, 0xCA, 0xEC, 0x5E, 0xDF, 0x86, 0x36, 0xC9, 0xE7, 0xB3, 0xD4, 0xF8, 0x9B, 0xC2, 0xCF, 0x80, 0x27, 0xBD, 0xBC, 0x9A, 0x94, 0xF2, 0xF8, 0xB8, 0x95, 0xAF, 0x17, 0xFE, 0x35, 0xCB, 0xC1, 0x6F, 0xFB, 0x34, 0x31, 0xE3, 0xDD, 0x44, 0x62, 0x2D, 0x9C, 0xF2, 0x6D, 0xB2, 0x7D, 0x96, 0x8F, 0x8E, 0xD1, 0x8D, 0xF5, 0x74, 0xAE, 0xC8, 0x25, 0x30, 0x64, 0x69, 0x76, 0x23, 0x24, 0x31, 0xF3, 0x00, 0x87, 0xDD, 0x6D, 0xB5, 0x79, 0xDB, 0x21, 0xB4, 0x5C, 0x07, 0xAD, 0xC1, 0x3C, 0x86, 0x88, 0xB1, 0x3D, 0xB6, 0xA6, 0x6E, 0x89, 0x7A, 0x32, 0x27, 0xB3, 0x2B, 0xF2, 0x93, 0xE5, 0xC1, 0x48, 0x77, 0xE8, 0xFF, 0xB2, 0x3D, 0x4E, 0xFE, 0x52, 0x62, 0xD7, 0x61, 0xD4, 0x46, 0xEC, 0x5E, 0xAD, 0x05, 0xBB, 0xDC, 0xAA, 0x45, 0xB2, 0xA0, 0x81, 0x9E, 0x78, 0xE5, 0x89, 0x46, 0xCF, 0xAB, 0x8E, 0x08, 0xE6, 0xAB, 0xA0, 0x28, 0x47, 0x0C, 0xD3, 0x4E, 0x81, 0x42, 0x51, 0xE4, 0x63, 0xEC, 0xF1, 0x50, 0x5D, 0xB6, 0xAC, 0xE2, 0xFC, 0x8D, 0x05, 0x01, 0x2A, 0x08, 0xFB, 0x96, 0xEA, 0x0C, 0xDC, 0x0F, 0x43, 0x63, 0x21, 0x69, 0x2C, 0xB9, 0x3B, 0xC7, 0xDB, 0xBE, 0xA7, 0xB6, 0xFF, 0x80, 0xB2, 0x0B, 0xE9, 0x95, 0xD1, 0x4E, 0xB0, 0xD0, 0xEA, 0x9F, 0x7D, 0xB2, 0x06, 0xCB, 0xDC, 0x18, 0xC1, 0x82, 0xB3, 0xF7, 0x58, 0xF3, 0x17, 0x9D, 0x28, 0x89, 0x64, 0x0D, 0x7B, 0xFF, 0x9C, 0xEF, 0xE6, 0xBE, 0x1B, 0xCB, 0x03, 0x38, 0x9A, 0x8A, 0x47, 0x68, 0x4B, 0x8C, 0xA6, 0x6D, 0xD4, 0x8B, 0xF9, 0x04, 0x21, 0xF1, 0x72, 0xBA, 0x39, 0xEB, 0x2E, 0xB0, 0xF5, 0x97, 0x92, 0xAA, 0x86, 0x43, 0x1A, 0x62, 0x10, 0x4C, 0x98, 0xA0, 0x90, 0x26, 0xD1, 0xFC, 0x6E, 0xC3, 0x5F, 0x46, 0x36, 0x22, 0xA9, 0x58, 0xBE, 0x4A, 0x4F, 0x6F, 0x1A, 0x2D, 0xA8, 0x4B, 0x74, 0x3D, 0x58, 0x68, 0x55, 0x69, 0x5E, 0xDD, 0x79, 0xB0, 0xC2, 0xAC, 0x0E, 0xDA, 0xB4, 0xCF, 0x19, 0x4F, 0xD7, 0xB4, 0x3C, 0x1A, 0xB0, 0xFE, 0x13, 0x3A, 0x8B, 0x89, 0x0D, 0xB9, 0x4B, 0x24, 0x5A, 0xB3, 0x8E, 0xB7, 0xE3, 0x77, 0xCF, 0x15, }, .pub_len = 2592, }, }; #define ML_DSA_TV_NUM sizeof(ml_dsa_tv)/sizeof(struct ML_DSA_TEST_VECTOR) /* NIST Test vectors from * https://github.com/usnistgov/ACVP-Server/tree/master/gen-val/json-files/ML-DSA-sigGen-FIPS204 */ CK_BYTE kat0_context[] = { 0x9b, 0x13, 0xbf, 0x38, 0x1d, 0x9d, 0xc5, 0xdb, 0x51, 0xf7, 0xdf, 0x25, 0x20, 0xe4, 0x1b, 0xdb, 0xd6, 0x0c, 0xde, 0x6c, 0x2f, 0x17, 0x5f, 0xd9, 0x28, 0x37, 0x22, 0x68, 0x43, 0xd0, 0x4f, 0xb2, 0x5d, 0x20, 0x84, 0xbd, 0x3d, 0xdf, 0xf2, 0xc5, 0x3a, 0xf8, 0x72, 0xd7, 0xe3, 0xa1, 0xcc, 0x86, 0x39, 0x73, 0xf0, 0x60, 0xb3, 0xa4, 0x39, 0x1f, 0xd0, 0xfc, 0x18, 0x0f, 0x63, 0x00, 0xd4, 0xc3, 0xce, 0xc2, 0xc6, 0xed, 0x6b, 0x55, 0x4e, 0xc6, 0x6d, 0x92, 0x11, 0x68, 0x37, 0x2f, 0xd6, 0x41, 0x47, 0x85, 0x68, 0x18, 0x93, 0x1d, 0x74, 0x24, 0x0d, 0xef, 0x12, 0x8b, 0xa6, 0x5f, 0x58, 0x4b, 0x60, 0xa9, 0x06, 0xba, 0xe2, 0x13, 0x0c, 0xa2, 0x8b, 0x84, 0x7e, 0x28, 0xc8, 0x46, 0x0e, }; CK_SIGN_ADDITIONAL_CONTEXT kat0_param = { .hedgeVariant = CKH_DETERMINISTIC_REQUIRED, .pContext = kat0_context, .ulContextLen = sizeof(kat0_context), }; CK_BYTE kat1_context[] = { 0x26, 0xe6, 0x3f, 0x05, 0xf7, 0xa0, 0xbc, 0x6d, 0x78, 0xa6, 0xe5, 0x5f, 0x0c, 0x74, 0x64, 0xb7, 0xa7, 0x33, 0xe3, 0xc8, 0x47, 0x47, 0x84, 0xb7, 0x77, 0x82, 0x20, 0x88, 0xf3, 0x06, 0xb6, 0x05, 0xba, 0x40, 0x19, 0xf7, 0xc6, 0x8b, 0x23, 0x49, 0x27, 0x2f, 0xde, 0x67, 0xbc, 0xcd, 0x9b, 0x42, 0xd1, 0x0e, 0xc2, 0xeb, 0x31, 0xbc, 0x2d, 0x3f, 0xde, 0x06, 0x90, 0x1a, 0xea, 0xe4, 0x9c, 0x56, 0x0e, 0xa2, 0x2c, 0xa7, 0xb6, 0x36, 0xc6, 0x69, 0x1f, 0x14, 0x84, 0x75, 0x87, 0x63, 0xbe, 0x08, 0x9c, 0x0a, 0x6d, 0x8f, 0x5c, 0xc4, 0xa7, 0xe6, 0xe7, 0xd0, 0x2d, 0x8d, 0xf5, 0x42, 0x5d, 0xac, 0xa4, 0x65, 0xca, 0x7b, 0xd5, 0x38, 0x4d, 0x3e, 0x9e, 0x1f, 0xb0, 0xd8, 0xa2, 0x15, 0x0f, 0x0c, 0x93, 0x85, 0x5c, 0x47, 0x90, 0x40, 0xbc, 0xd9, 0x1e, 0x02, 0xdf, 0x04, 0x74, 0x64, 0x88, 0xcf, 0xed, 0x27, 0x8a, 0x96, 0x6f, 0x52, 0x8e, 0xf9, 0x52, 0xfe, 0xd0, 0x18, 0x9e, 0xc5, 0xe9, 0xc7, 0xd4, 0xa2, 0xf2, 0x7e, 0x11, 0x4a, 0xd4, 0x2e, 0xfb, 0x3a, 0xcd, 0x63, 0x32, 0xa0, 0x3c, 0x6e, 0x37, 0x4e, 0x9e, 0x8c, 0xdd, 0xe3, 0xae, 0x86, 0x03, 0x6e, 0x92, 0x65, 0x6f, 0xb8, 0x13, 0xec, 0x66, 0x12, 0xa4, 0xb1, 0xd3, 0xc0, 0x1e, 0x8c, 0xb3, 0x68, 0x7a, 0x1d, 0xd8, 0x91, 0x68, 0xe4, 0x63, 0x40, 0xd0, 0xb1, 0xb2, 0x4f, 0xd9, 0x78, 0x53, 0xc5, 0x3e, 0x30, 0xd6, 0x88, 0x97, 0x76, 0x58, 0xa6, 0xf5, 0x9a, 0x84, 0x9f, 0xae, 0x08, 0x00, 0x51, 0xdb, 0xb7, 0x5c, 0x01, 0x4c, 0x42, 0x9f, 0x68, 0xed, 0x06, 0x2e, 0x6b, 0x92, 0x5b, 0xac, 0x29, 0x50, 0x82, 0xc9, 0x1f, 0xdd, 0x8f, 0x1f, 0xd6, 0x1f, 0x24, 0xd4, 0x07, 0x4d, 0x50, 0x46, 0xfe, 0x1d, 0x44, 0xaa, 0x86 }; CK_SIGN_ADDITIONAL_CONTEXT kat1_param = { .hedgeVariant = CKH_DETERMINISTIC_REQUIRED, .pContext = kat1_context, .ulContextLen = sizeof(kat1_context), }; struct ML_DSA_TEST_VECTOR ml_dsa_kat_tv[] = { { .name = "ML-DSA 44 deterministic, pure", .parameter_set = CKP_ML_DSA_44, .mech = { CKM_ML_DSA, &kat0_param, sizeof(kat0_param) }, .priv = { 0x60, 0xfc, 0x30, 0x30, 0xc9, 0xcc, 0x67, 0xc4, 0x4c, 0x0e, 0xfd, 0x47, 0xc6, 0x0d, 0x02, 0x29, 0x6d, 0x0f, 0x73, 0xb2, 0x5a, 0xe1, 0xb5, 0xf5, 0x06, 0xeb, 0x95, 0x21, 0xd5, 0x9a, 0x6a, 0x50, 0x07, 0x17, 0xcb, 0x32, 0xf9, 0xbd, 0x04, 0x9a, 0x77, 0xb2, 0xc5, 0x51, 0x1b, 0x77, 0x7b, 0x74, 0x22, 0xb6, 0xfe, 0x1e, 0xde, 0x80, 0x98, 0x59, 0x51, 0xf3, 0xf2, 0x2b, 0xdc, 0xa5, 0xf6, 0xad, 0x72, 0x08, 0x42, 0xc1, 0x7f, 0x42, 0x01, 0x7d, 0xab, 0x38, 0xe4, 0x31, 0xfa, 0xa7, 0x87, 0x8e, 0x93, 0x6c, 0x1f, 0x23, 0xfa, 0x61, 0xcf, 0x1e, 0xb7, 0xcc, 0xdc, 0xbd, 0xf8, 0x16, 0xf8, 0x62, 0x8c, 0x60, 0x98, 0x3c, 0x78, 0xa7, 0x0d, 0x51, 0x2b, 0xa3, 0x7e, 0xa4, 0x69, 0xcd, 0x9e, 0x7d, 0x0c, 0x53, 0xf6, 0xf0, 0xb9, 0x19, 0x66, 0x14, 0x22, 0x3f, 0xb3, 0x1b, 0x42, 0x9a, 0x6a, 0x3b, 0x03, 0x23, 0x2c, 0x4c, 0x00, 0x11, 0x1c, 0xc4, 0x85, 0x43, 0x46, 0x8a, 0x13, 0x09, 0x0a, 0xe0, 0x98, 0x81, 0x04, 0x31, 0x6d, 0xca, 0x34, 0x24, 0x80, 0x90, 0x81, 0x23, 0x01, 0x20, 0x14, 0x25, 0x22, 0x9b, 0x40, 0x2e, 0x92, 0xb6, 0x91, 0x14, 0x81, 0x25, 0x98, 0x46, 0x86, 0x03, 0x80, 0x24, 0x82, 0x08, 0x52, 0x0a, 0xb9, 0x29, 0xa3, 0x22, 0x45, 0x11, 0x15, 0x86, 0x02, 0x06, 0x48, 0xa3, 0x98, 0x40, 0x1a, 0x19, 0x0e, 0x90, 0xc8, 0x29, 0x13, 0x41, 0x11, 0x1a, 0xc3, 0x65, 0x14, 0x80, 0x64, 0x84, 0x48, 0x4d, 0x5a, 0x80, 0x31, 0x88, 0x10, 0x50, 0xda, 0x14, 0x12, 0xcb, 0x18, 0x0a, 0x22, 0xc8, 0x2d, 0xd3, 0xc8, 0x40, 0x4a, 0x82, 0x80, 0x94, 0xc4, 0x49, 0x92, 0x28, 0x8e, 0x58, 0x98, 0x49, 0x19, 0x03, 0x80, 0x62, 0xc4, 0x08, 0x1c, 0xc8, 0x10, 0x10, 0x25, 0x49, 0xd3, 0x20, 0x62, 0x09, 0x04, 0x45, 0x1b, 0x03, 0x26, 0x14, 0x91, 0x60, 0x91, 0x16, 0x48, 0x5c, 0xa6, 0x4c, 0x51, 0x42, 0x2a, 0xca, 0x10, 0x86, 0x11, 0x21, 0x82, 0x1b, 0x21, 0x0a, 0x53, 0xb8, 0x10, 0x49, 0x04, 0x51, 0xd4, 0x14, 0x72, 0x80, 0x80, 0x2c, 0x0a, 0x25, 0x2e, 0x21, 0x40, 0x65, 0xa1, 0x28, 0x06, 0xc3, 0x92, 0x70, 0x01, 0x41, 0x00, 0x02, 0x41, 0x6e, 0x80, 0xa0, 0x88, 0x84, 0x46, 0x90, 0x0b, 0x45, 0x92, 0x9c, 0x84, 0x69, 0x5c, 0x30, 0x05, 0x11, 0x07, 0x6d, 0xd0, 0x32, 0x8d, 0x01, 0x03, 0x21, 0x09, 0x00, 0x26, 0xc1, 0x98, 0x44, 0x42, 0x14, 0x72, 0x0a, 0x01, 0x28, 0x1b, 0x83, 0x69, 0x41, 0xa6, 0x31, 0x10, 0x42, 0x72, 0x9b, 0x12, 0x08, 0x24, 0x85, 0x2d, 0x8a, 0x14, 0x41, 0x08, 0xc3, 0x10, 0x08, 0xa5, 0x85, 0x0c, 0xb5, 0x10, 0x02, 0x33, 0x51, 0xd1, 0x30, 0x24, 0x1a, 0x81, 0x10, 0x14, 0x90, 0x2d, 0x40, 0x96, 0x0d, 0xcc, 0x82, 0x20, 0x43, 0x18, 0x85, 0x19, 0x49, 0x52, 0xd0, 0xa6, 0x05, 0x4a, 0x38, 0x41, 0x11, 0x26, 0x0e, 0xe2, 0x28, 0x50, 0x24, 0x47, 0x20, 0x63, 0x82, 0x08, 0x22, 0xa7, 0x2d, 0x4c, 0x32, 0x41, 0x59, 0x46, 0x0d, 0x4a, 0xc4, 0x2d, 0x90, 0x22, 0x46, 0x14, 0xb1, 0x64, 0x19, 0x20, 0x52, 0x92, 0x04, 0x06, 0x11, 0xc3, 0x65, 0x00, 0x98, 0x09, 0x1b, 0x46, 0x0e, 0x4b, 0xc6, 0x30, 0x1a, 0x01, 0x4c, 0x60, 0x20, 0x08, 0x11, 0x37, 0x04, 0x44, 0x44, 0x70, 0x64, 0x24, 0x00, 0x1a, 0x36, 0x02, 0xd9, 0xa4, 0x25, 0x10, 0x93, 0x81, 0x0c, 0xb9, 0x30, 0xe0, 0x02, 0x29, 0x00, 0x86, 0x8c, 0x0c, 0xc3, 0x45, 0x14, 0x28, 0x42, 0x5b, 0x30, 0x2c, 0x03, 0xb9, 0x85, 0x81, 0xc6, 0x29, 0x63, 0x46, 0x49, 0x1c, 0x16, 0x00, 0xcb, 0xb0, 0x71, 0xc1, 0x22, 0x8a, 0xe4, 0xa4, 0x91, 0x51, 0x44, 0x8a, 0x93, 0x42, 0x91, 0xc9, 0x00, 0x2d, 0x12, 0x40, 0x11, 0x8b, 0x22, 0x01, 0x1b, 0x20, 0x44, 0x02, 0x00, 0x44, 0xd0, 0xb6, 0x20, 0x50, 0x08, 0x06, 0x5a, 0x90, 0x45, 0x5b, 0x04, 0x22, 0x09, 0xc0, 0x00, 0x82, 0x88, 0x51, 0x54, 0x82, 0x48, 0x5b, 0x00, 0x81, 0xdc, 0x90, 0x01, 0xc8, 0x96, 0x4c, 0x18, 0x10, 0x50, 0xda, 0x24, 0x71, 0x20, 0x22, 0x30, 0x52, 0xa0, 0x44, 0x61, 0x96, 0x0c, 0x52, 0x80, 0x25, 0xd8, 0xb8, 0x88, 0xca, 0xc8, 0x41, 0xd8, 0x08, 0x6d, 0x12, 0x31, 0x4d, 0x49, 0xa6, 0x80, 0x0b, 0xc1, 0x50, 0x80, 0x06, 0x85, 0xa4, 0x88, 0x51, 0x12, 0x34, 0x42, 0x41, 0x08, 0x32, 0xd8, 0x02, 0x62, 0x00, 0x28, 0x84, 0x5a, 0x82, 0x69, 0x61, 0x34, 0x62, 0xe1, 0xb6, 0x48, 0x23, 0x49, 0x0c, 0x5c, 0x26, 0x41, 0x1c, 0x08, 0x90, 0x10, 0x46, 0x62, 0xa2, 0x04, 0x89, 0x02, 0xa7, 0x09, 0x03, 0x15, 0x4e, 0x00, 0xb5, 0x00, 0xd1, 0x04, 0x8c, 0x5a, 0xc2, 0x6c, 0x1b, 0x45, 0x6c, 0x89, 0x30, 0x0a, 0x24, 0xc5, 0x05, 0x91, 0x20, 0x28, 0xc8, 0xb0, 0x00, 0xc1, 0x96, 0x48, 0x1a, 0x39, 0x6c, 0x80, 0xb8, 0x49, 0x82, 0x00, 0x69, 0xdb, 0x40, 0x68, 0x50, 0x42, 0x05, 0x02, 0x44, 0x0c, 0xa1, 0x84, 0x41, 0x19, 0x40, 0x05, 0x50, 0x06, 0x89, 0x01, 0x17, 0x6a, 0x09, 0xa7, 0x24, 0xa4, 0xc2, 0x10, 0x60, 0x14, 0x90, 0x03, 0x08, 0x31, 0x00, 0x45, 0x0e, 0xd8, 0x42, 0x2e, 0x10, 0x24, 0x30, 0x52, 0x20, 0x66, 0xd2, 0x94, 0x6d, 0x40, 0x12, 0x41, 0x13, 0xc1, 0x64, 0x40, 0x30, 0x64, 0xa0, 0x96, 0x20, 0x18, 0x49, 0x05, 0xd2, 0x12, 0x2a, 0x1a, 0x47, 0x6e, 0xcb, 0x16, 0x4e, 0xe3, 0x08, 0x41, 0xe3, 0xa0, 0x71, 0x18, 0xb0, 0x04, 0x19, 0xa4, 0x80, 0x9a, 0x82, 0x61, 0x09, 0xb9, 0x68, 0x42, 0x20, 0x6a, 0x41, 0x18, 0x64, 0x00, 0x14, 0x8e, 0x80, 0x24, 0x05, 0xc4, 0x80, 0x88, 0x8c, 0xb4, 0x09, 0x40, 0xa8, 0x60, 0x58, 0x40, 0x45, 0x8c, 0x02, 0x12, 0xdc, 0xc8, 0x24, 0xd4, 0xb8, 0x29, 0x12, 0xc9, 0x85, 0x40, 0x42, 0x20, 0xe4, 0xc4, 0x30, 0x20, 0x82, 0x11, 0x8b, 0x88, 0x28, 0x53, 0xc8, 0x24, 0xca, 0x06, 0x05, 0x0c, 0x07, 0x2d, 0xc8, 0xa2, 0x2c, 0x09, 0x38, 0x00, 0x8c, 0x20, 0x49, 0xe0, 0x80, 0x50, 0x53, 0x00, 0x22, 0xca, 0x94, 0x49, 0x1b, 0xa4, 0x09, 0x11, 0x98, 0x49, 0x23, 0x17, 0x91, 0x52, 0x04, 0x29, 0x03, 0x45, 0x6e, 0x0a, 0xa8, 0x24, 0x1a, 0x32, 0x2c, 0xd0, 0x14, 0x4c, 0x10, 0xb6, 0x30, 0x8c, 0x02, 0x22, 0x20, 0x11, 0x72, 0xda, 0xb8, 0x20, 0xca, 0x84, 0x81, 0x14, 0x92, 0x44, 0x8a, 0x3b, 0xa3, 0xc9, 0x8a, 0x60, 0x7f, 0x8d, 0xad, 0xc1, 0x36, 0xab, 0x48, 0x91, 0xdb, 0x9e, 0x86, 0xbd, 0x5e, 0x76, 0x77, 0x3b, 0x77, 0x7c, 0x31, 0x14, 0xba, 0xb4, 0x0c, 0x5c, 0xac, 0xa9, 0x5e, 0x84, 0x0c, 0x73, 0xbb, 0x3e, 0x7b, 0x1f, 0xe1, 0x6e, 0x85, 0x12, 0xdf, 0xb5, 0xa7, 0x24, 0x91, 0xca, 0x15, 0xfd, 0xe8, 0xbf, 0xbf, 0xb1, 0xf7, 0x2a, 0x73, 0xeb, 0x11, 0xd3, 0xfd, 0x6c, 0x88, 0x7d, 0x3f, 0x9e, 0x71, 0x22, 0xce, 0xd0, 0x67, 0xf0, 0xaf, 0xc4, 0x52, 0x72, 0x33, 0xb1, 0x13, 0x18, 0x52, 0x7f, 0xb2, 0x36, 0xc3, 0x70, 0x4f, 0xa5, 0xfc, 0x16, 0x30, 0x1b, 0xb7, 0x50, 0xb6, 0xdd, 0x79, 0xf8, 0x48, 0x65, 0xcc, 0xd1, 0xef, 0x8f, 0x11, 0x80, 0x51, 0x0d, 0x4b, 0x56, 0x94, 0x7e, 0x3d, 0x99, 0x3a, 0xd9, 0x20, 0x00, 0x93, 0x61, 0x0e, 0x58, 0x14, 0xf9, 0x26, 0x90, 0x6c, 0x84, 0xf9, 0xd2, 0x27, 0x87, 0x50, 0x3a, 0x58, 0x86, 0xc7, 0x89, 0x52, 0xdd, 0xec, 0xfd, 0x3d, 0x78, 0x93, 0x25, 0x8c, 0x44, 0xa5, 0x9d, 0x89, 0x94, 0x20, 0xf1, 0x2a, 0x9f, 0x40, 0x5b, 0x89, 0x7a, 0x93, 0x5f, 0x42, 0x3d, 0x70, 0x41, 0x77, 0x83, 0x40, 0xa4, 0xf4, 0x1f, 0x07, 0x93, 0x51, 0x29, 0xf4, 0xe8, 0xb1, 0x50, 0x51, 0x92, 0x41, 0x48, 0xea, 0xb0, 0x54, 0x8a, 0x88, 0x0f, 0xba, 0x22, 0x3f, 0x75, 0x03, 0x1e, 0x33, 0x70, 0x6f, 0x04, 0x89, 0x6a, 0x60, 0x0e, 0xa0, 0x2b, 0xfc, 0x12, 0xd9, 0x7a, 0xc3, 0xbc, 0xd6, 0x26, 0xb3, 0xde, 0xd6, 0xf3, 0xb2, 0xba, 0x46, 0xf4, 0x74, 0xdf, 0xc1, 0x26, 0x6c, 0x4c, 0x1c, 0x91, 0x57, 0x63, 0xc1, 0xbb, 0x4d, 0x71, 0xd3, 0x37, 0x4c, 0x01, 0xcc, 0x5e, 0x09, 0x40, 0x7f, 0x8c, 0x77, 0xf5, 0x75, 0xbc, 0x39, 0xb2, 0x58, 0x71, 0x8c, 0x4d, 0x85, 0xca, 0x42, 0xc9, 0x2a, 0x6b, 0x3d, 0xee, 0x6c, 0x7d, 0x52, 0xd0, 0x98, 0x5b, 0x1e, 0xec, 0xd8, 0x3a, 0xc6, 0x7c, 0x42, 0xb2, 0xa7, 0x17, 0x10, 0x19, 0x3d, 0x95, 0xc8, 0x4e, 0xae, 0x2d, 0x2c, 0xd5, 0xdc, 0x9a, 0x3c, 0x9f, 0xd3, 0xed, 0x22, 0x14, 0x0d, 0x8a, 0xee, 0x53, 0xc6, 0x9d, 0xb3, 0x06, 0x53, 0xaf, 0x6d, 0x14, 0x30, 0x1c, 0x8e, 0x87, 0x21, 0xae, 0x00, 0x2a, 0xa6, 0x7f, 0x8c, 0xec, 0x7c, 0x9c, 0xda, 0x60, 0x50, 0xb4, 0xcf, 0xdd, 0xe3, 0xd5, 0xd1, 0x5e, 0xb8, 0xb2, 0x87, 0x11, 0xf4, 0xb3, 0x87, 0x62, 0xa6, 0xfb, 0x68, 0x8b, 0xa9, 0x52, 0x29, 0x9a, 0xc8, 0x33, 0x74, 0xeb, 0x6d, 0x03, 0x55, 0x3f, 0x24, 0x3e, 0xb3, 0xa5, 0x37, 0xc5, 0xde, 0xb2, 0xc0, 0x99, 0xcc, 0x3b, 0x5e, 0xdf, 0x79, 0x80, 0x31, 0xd9, 0xdd, 0x13, 0x1f, 0x95, 0x63, 0x01, 0x5f, 0xc4, 0xd2, 0xed, 0x25, 0xfe, 0x74, 0x90, 0x7a, 0xb6, 0x1e, 0x61, 0x63, 0x79, 0x5d, 0x45, 0xa4, 0x65, 0xe9, 0xca, 0xcd, 0xb9, 0xed, 0x89, 0x67, 0x50, 0xf5, 0xa0, 0x3a, 0x77, 0xe8, 0x5f, 0xfa, 0xb2, 0x80, 0xf2, 0x25, 0x25, 0xbc, 0x8d, 0xc9, 0xa2, 0x91, 0x75, 0x65, 0x0d, 0x26, 0x51, 0x79, 0x38, 0xec, 0x3a, 0x47, 0x07, 0xae, 0xdd, 0xaa, 0xf6, 0xc6, 0x7c, 0xdd, 0x49, 0x9b, 0x16, 0x92, 0x7e, 0xe3, 0xb4, 0xb4, 0x35, 0xe5, 0xff, 0xc2, 0x9a, 0xdb, 0xd6, 0xfb, 0x4f, 0x7e, 0x73, 0xb6, 0x20, 0x58, 0xbb, 0x5e, 0xed, 0x6e, 0xdf, 0x9f, 0x7f, 0xed, 0xf1, 0x49, 0x51, 0x93, 0xa6, 0xa7, 0x6c, 0x8d, 0x47, 0x5e, 0xf5, 0xb6, 0x60, 0x59, 0x15, 0xb0, 0x7f, 0x40, 0xe7, 0xc1, 0x0e, 0xdd, 0x60, 0xaf, 0xd7, 0x13, 0x84, 0x80, 0x9c, 0xbb, 0xf9, 0x45, 0x77, 0xc6, 0xd5, 0xe5, 0x1f, 0x83, 0x95, 0xbb, 0x22, 0x77, 0xa8, 0x86, 0x18, 0x86, 0x80, 0x89, 0x28, 0x01, 0xb5, 0xd7, 0x18, 0xfc, 0x4d, 0xf9, 0x15, 0xd3, 0x77, 0x88, 0x72, 0xe4, 0x4c, 0x42, 0xba, 0x7e, 0x0d, 0x6e, 0x2d, 0x76, 0x28, 0x10, 0x5c, 0x96, 0x30, 0x97, 0x6c, 0x50, 0xdc, 0xd9, 0xfc, 0x02, 0x39, 0xf2, 0x25, 0x6f, 0x06, 0x65, 0x6e, 0x9f, 0x44, 0xbf, 0x8c, 0x99, 0x3a, 0xb9, 0xed, 0xdd, 0xfe, 0x61, 0xf0, 0xc0, 0xbd, 0x4c, 0xc7, 0xe7, 0xff, 0x3e, 0xa3, 0xef, 0x08, 0x63, 0xeb, 0xf2, 0x2b, 0x5b, 0x5f, 0xc0, 0x69, 0x60, 0x00, 0xba, 0x2a, 0x18, 0x74, 0xc8, 0xcd, 0xf4, 0xd9, 0x01, 0xd8, 0x31, 0x53, 0x71, 0x58, 0xbf, 0x0e, 0x74, 0x7f, 0xc3, 0x65, 0xe8, 0x3f, 0x49, 0x06, 0x40, 0xee, 0xb3, 0x09, 0xc1, 0x07, 0x9c, 0xac, 0xb4, 0xd9, 0xb4, 0xd7, 0xfa, 0x46, 0x32, 0x1c, 0xaf, 0xb2, 0xd1, 0x3d, 0x10, 0x1e, 0x98, 0x8d, 0x52, 0x84, 0x78, 0x54, 0xc0, 0x99, 0x34, 0x65, 0x9b, 0x62, 0xfa, 0x1f, 0x72, 0x30, 0xdc, 0x94, 0x16, 0x10, 0x60, 0xb2, 0x42, 0xc0, 0x7c, 0x1d, 0xa0, 0xb1, 0xf1, 0xac, 0x9f, 0xba, 0xa2, 0xba, 0x62, 0x76, 0x72, 0x9d, 0xd0, 0x66, 0x0c, 0x05, 0x7c, 0xbb, 0x15, 0x44, 0xaf, 0xf5, 0xfb, 0xa7, 0x4b, 0x0e, 0xa7, 0xaf, 0x37, 0x5b, 0xd6, 0x7b, 0xc4, 0x69, 0x72, 0x7b, 0xa9, 0xd3, 0x5b, 0xdc, 0x22, 0x33, 0xe8, 0x7e, 0x40, 0x5e, 0xde, 0x5c, 0x97, 0xb1, 0x20, 0x4b, 0xfb, 0xad, 0xcb, 0xee, 0x03, 0x7e, 0xe6, 0xc6, 0xc5, 0x50, 0x24, 0x32, 0x48, 0x52, 0x2b, 0x2a, 0xb1, 0xf1, 0x95, 0x05, 0x9c, 0x0e, 0x81, 0xab, 0xd0, 0x2a, 0xb5, 0x79, 0xc7, 0xbc, 0x94, 0x00, 0x69, 0x1d, 0x71, 0x52, 0x88, 0xb2, 0x2f, 0xab, 0xa9, 0x98, 0xcc, 0x02, 0xf7, 0x64, 0x0b, 0x32, 0xf9, 0x83, 0x60, 0x69, 0xa8, 0x88, 0xc1, 0x3a, 0x96, 0x76, 0xc8, 0xe1, 0xb2, 0x52, 0x77, 0x9d, 0x0b, 0x4d, 0xe6, 0xe4, 0xf2, 0xd6, 0x8c, 0xbd, 0xcc, 0xbc, 0x15, 0xe5, 0x34, 0x51, 0x88, 0x09, 0x47, 0x56, 0xb1, 0xcc, 0xd4, 0xce, 0x0d, 0x10, 0xf1, 0x1e, 0xe8, 0x9e, 0x3d, 0x73, 0x77, 0xf5, 0xc9, 0x64, 0x45, 0xbe, 0x86, 0x76, 0xd9, 0xfe, 0x7c, 0xde, 0x9c, 0xe4, 0x97, 0xd1, 0x28, 0xf1, 0xba, 0x42, 0xf4, 0x0c, 0x38, 0xc1, 0xe0, 0x93, 0x14, 0x97, 0xba, 0x8b, 0x28, 0xea, 0xfe, 0xa4, 0x1a, 0x5c, 0xe2, 0x03, 0xd1, 0x9e, 0x1f, 0x44, 0xbe, 0x11, 0xdb, 0xb0, 0xb2, 0x87, 0x60, 0x51, 0x72, 0x69, 0x0f, 0x09, 0x88, 0xb7, 0x42, 0x7f, 0x90, 0x83, 0xb9, 0xd5, 0x83, 0xfa, 0xee, 0x34, 0x87, 0xf6, 0xb7, 0x5f, 0x2c, 0xed, 0x99, 0xde, 0x2e, 0x67, 0xf8, 0xd9, 0x98, 0x7e, 0xee, 0xf9, 0x1e, 0x51, 0x82, 0x8f, 0xbc, 0x31, 0x28, 0x43, 0x2b, 0xad, 0x5b, 0xd9, 0xb3, 0xff, 0x38, 0x58, 0x58, 0xb6, 0x5c, 0xcf, 0x1c, 0x79, 0x90, 0x5b, 0xeb, 0x65, 0x5e, 0x46, 0xdd, 0x92, 0x10, 0xf8, 0x7c, 0x7d, 0x43, 0xfd, 0xe1, 0x00, 0x35, 0x69, 0x84, 0xdb, 0xd5, 0x59, 0x56, 0x63, 0x26, 0x65, 0x86, 0x43, 0x80, 0xed, 0xe7, 0xe1, 0xcf, 0x44, 0x50, 0xdd, 0x24, 0xa4, 0x63, 0xbe, 0x1b, 0xa9, 0x34, 0x87, 0x8c, 0x68, 0x72, 0xf6, 0x0e, 0x4a, 0xb9, 0x6a, 0xcc, 0x44, 0xb1, 0x57, 0xa7, 0x28, 0xf0, 0xec, 0x32, 0xfc, 0x6a, 0x7f, 0x0f, 0x1c, 0x43, 0x48, 0x91, 0x1b, 0xb7, 0x15, 0xac, 0x36, 0xf8, 0x8d, 0x68, 0x55, 0x5c, 0xbc, 0xed, 0x2b, 0x4b, 0x1e, 0xdc, 0x33, 0x9d, 0xc6, 0xfd, 0x36, 0xbc, 0xaf, 0x72, 0xff, 0xd8, 0x08, 0x03, 0x81, 0x46, 0x24, 0x99, 0x64, 0xff, 0x8c, 0x5f, 0x18, 0x23, 0xc3, 0x2a, 0x0e, 0xc4, 0x4f, 0x3f, 0x97, 0x19, 0x25, 0x73, 0xbc, 0x79, 0xd7, 0xdf, 0x1a, 0x47, 0x3e, 0x8d, 0x94, 0x5d, 0x8f, 0x4d, 0x72, 0x46, 0x53, 0x07, 0xa0, 0x1f, 0xb6, 0xb1, 0x65, 0x72, 0x9c, 0xf5, 0x6f, 0xac, 0xb0, 0x3f, 0x11, 0x06, 0x2b, 0x1a, 0x6c, 0xbd, 0x9b, 0x30, 0x0b, 0xd0, 0xf4, 0xfb, 0x6a, 0x54, 0xce, 0x36, 0x0f, 0x52, 0xc3, 0x78, 0xe6, 0xe1, 0x50, 0xd8, 0xbb, 0xe3, 0xec, 0xb7, 0xde, 0xa6, 0x54, 0x57, 0xcd, 0x31, 0x21, 0x91, 0x42, 0x83, 0x48, 0x1d, 0x38, 0x0d, 0xe6, 0xb5, 0x27, 0x74, 0x4e, 0xae, 0x2b, 0xf4, 0x5f, 0xb0, 0x9e, 0xd5, 0xfd, 0xb7, 0xc0, 0xf7, 0xcd, 0x45, 0x42, 0x75, 0x40, 0xe6, 0x74, 0x30, 0x6e, 0x7b, 0x43, 0x03, 0xcf, 0x08, 0x25, 0x58, 0x8f, 0x60, 0x6e, 0xdd, 0x79, 0x5c, 0x31, 0x21, 0x12, 0x59, 0x86, 0x0f, 0x29, 0x13, 0xe0, 0x50, 0x61, 0xe9, 0xe8, 0xd7, 0x8b, 0x15, 0xda, 0x97, 0xa5, 0x49, 0x25, 0x32, 0xb4, 0xed, 0xeb, 0xf6, 0x3c, 0x90, 0x1f, 0x62, 0x0a, 0xaf, 0x9e, 0xcc, 0x9f, 0x2b, 0xe5, 0xb5, 0xe2, 0xf0, 0x28, 0x64, 0xad, 0xf1, 0xb6, 0xa2, 0x66, 0x3e, 0x9d, 0x65, 0x4f, 0x20, 0xed, 0x0f, 0xe1, 0x4b, 0xda, 0x10, 0x63, 0x36, 0xac, 0x76, 0x68, 0x2e, 0x84, 0xd6, 0x6a, 0xdc, 0x68, 0x26, 0x17, 0x62, 0x40, 0xc3, 0xba, 0x7a, 0x8d, 0x08, 0x95, 0xad, 0xd5, 0x57, 0x06, 0x06, 0x9b, 0x37, 0x83, 0x04, 0xfb, 0x6a, 0x45, 0xad, 0x9a, 0x03, 0x54, 0xc4, 0xd0, 0xdf, 0xa1, 0x3a, 0x2f, 0x97, 0x24, 0x4a, 0xf6, 0xc1, 0xf0, 0x3b, 0x91, 0xa6, 0xdf, 0x0d, 0xcd, 0x93, 0x8b, 0xc2, 0xde, 0xbc, 0x27, 0x5a, 0xdf, 0x1b, 0x9d, 0x70, 0x66, 0x72, 0xc0, 0x2e, 0x12, 0xb1, 0xd2, 0xfb, 0x12, 0x9b, 0xa4, 0xd5, 0x8f, 0xf2, 0xf8, 0x69, 0xab, 0x92, 0x90, 0x71, 0xe5, 0xbc, 0x4b, 0xc4, 0x20, 0xe2, 0xb3, 0x46, 0xf5, 0x64, 0x24, 0xfa, 0xba, 0x5c, 0x80, 0xe1, 0x41, 0x8c, 0xde, 0x65, 0x42, 0xf7, 0x42, 0x97, 0xd6, 0x2f, 0x34, 0xd0, 0xe8, 0x4f, 0xc8, 0xc6, 0x29, 0x7b, 0xd9, 0x5b, 0x1b, 0x5a, 0xb5, 0xae, 0xb3, 0x11, 0x3b, 0x6b, 0x3a, 0x27, 0xbb, 0x98, 0x66, 0x65, 0x6b, 0xe9, 0x57, 0x2a, 0x86, 0x4a, 0x14, 0xb2, 0xdf, 0x21, 0x85, 0xaf, 0xef, 0x09, 0xc7, 0x0e, 0xba, 0x43, 0x04, 0x6e, 0x45, 0x36, 0xcf, 0x79, 0x38, 0xba, 0x7e, 0x45, 0xbe, 0xd3, 0xa5, 0x80, 0xd5, 0xae, 0x98, 0x07, 0x4f, 0x25, 0x4d, 0x3e, 0x1d, 0xdb, 0x15, 0xeb, 0x70, 0x5d, 0x8a, 0x34, 0x82, 0x31, 0x6b, 0xaf, 0x5a, 0x02, 0x03, 0x8d, 0x41, 0x86, 0xea, 0x9f, 0xf4, 0x0a, 0xd3, 0x5d, 0x3c, 0xa9, 0x55, 0xf5, 0x72, 0x09, 0x32, 0xdb, 0xef, 0x69, 0x01, 0x67, 0x73, 0xc5, 0xaf, 0x8b, 0xe1, 0xd7, 0x27, 0x8b, 0xfb, 0xc5, 0x8d, 0x4d, 0x50, 0x0f, 0xcb, 0x6a, 0xd9, 0xd7, 0xac, 0xc9, 0xc6, 0xeb, 0x0f, 0x33, 0xcd, 0xd0, 0xd0, 0xf4, 0x9d, 0x40, 0x50, 0x5d, 0x90, 0x20, 0xc0, 0x33, 0x27, 0x56, 0xd3, 0x5c, 0xc5, 0xae, 0xb9, 0xc8, 0x73, 0x44, 0x7c, 0x90, 0xc2, 0x5b, 0x22, 0x0a, 0x3f, 0xc1, 0x88, 0x85, 0x57, 0x69, 0x2b, 0x9f, 0x33, 0xd1, 0xa1, 0x13, 0xc5, 0x6d, 0xbb, 0xfb, 0x01, 0x86, 0x91, 0xb9, 0x69, 0x61, 0xb7, 0x38, 0x26, 0xf5, 0x8d, 0xb0, 0xc4, 0x11, 0xf5, 0x48, 0x39, 0x5d, 0xd3, 0xf5, 0xbd, 0xbe, 0x77, 0x7b, 0xba, 0x14, 0x15, 0x2c, 0x69, 0x10, 0xf0, 0x7e, 0x25, 0x77, 0xb0, 0x82, 0x47, 0x64, 0x5d, 0x4b, 0xed, 0xf0, 0xa1, 0x3a, 0x87, 0xf7, 0x85, 0x5c, 0xba, 0x4d, 0xf7, 0xd8, 0x68, 0x7a, 0xc0, 0xdd, 0x12, 0x41, 0xeb, 0xf3, 0xb3, 0xea, 0x93, 0x98, 0xe7, 0xcf, 0xd4, 0xcc, 0xf1, 0xa2, 0x37, 0xaa, 0x03, 0xd8, 0x40, 0x03, 0x02, 0x06, 0xfa, 0x7d, 0xe3, 0xfb, 0x35, 0xa4, 0xca, 0xb4, 0xa2, 0xa3, 0x82, 0x88, 0xf7, 0x10, 0xa1, 0x6f, 0xb0, 0xe2, 0x4b, 0x95, 0x85, 0x1a, 0x18, 0xf1, 0x1a, 0x1c, 0x65, 0xde, 0xca, 0x9a, 0x66, 0xb9, 0xc3, 0xb9, 0xbf, 0x18, 0x63, 0x43, 0x6e, 0x49, 0x4e, 0xcc, 0x82, 0xe5, 0xa0, 0x42, 0x09, 0xf0, 0x0f, 0xb0, 0x3e, 0x0b, 0x6b, 0x09, 0x40, 0x13, 0xab, 0xa5, 0x5e, 0xb3, 0xfa, 0x9b, 0x32, 0x55, 0x21, 0xc5, 0x0d, 0xb1, 0x84, 0x44, 0x79, 0x00, 0x6e, 0xf6, 0x5b, 0x08, 0x8e, 0xd1, 0xad, 0x9c, 0xa6, 0x2f, 0x4a, 0x8a, 0x03, 0xd3, 0xd3, 0xee, 0x04, 0x1d, 0x3c, 0x44, 0xd9, 0xb2, 0xd1, 0x52, 0x16, 0xcf, 0x8d, 0x0d, 0xce, 0x2a, 0x92, 0xc6, 0xbf, }, .priv_len = 2560, .pub = { 0x60, 0xfc, 0x30, 0x30, 0xc9, 0xcc, 0x67, 0xc4, 0x4c, 0x0e, 0xfd, 0x47, 0xc6, 0x0d, 0x02, 0x29, 0x6d, 0x0f, 0x73, 0xb2, 0x5a, 0xe1, 0xb5, 0xf5, 0x06, 0xeb, 0x95, 0x21, 0xd5, 0x9a, 0x6a, 0x50, 0xaf, 0x94, 0xd2, 0xfb, 0x6c, 0x3f, 0x81, 0xd8, 0xc4, 0xf6, 0xd0, 0xe7, 0x37, 0x82, 0x87, 0x47, 0xfd, 0x25, 0xbc, 0xaf, 0xbc, 0xc4, 0x48, 0xe3, 0x14, 0x6b, 0x98, 0x97, 0xff, 0xfb, 0x30, 0x55, 0xd3, 0x06, 0x04, 0xc5, 0x5b, 0x63, 0x3d, 0x1f, 0x67, 0xd4, 0x9b, 0x11, 0xc1, 0x03, 0x79, 0x2d, 0xfa, 0xcc, 0x11, 0x95, 0x15, 0x4f, 0x5c, 0x77, 0x0d, 0x50, 0x32, 0x9f, 0x52, 0x44, 0x9b, 0x7c, 0x0d, 0x67, 0x88, 0x17, 0x40, 0xa7, 0x23, 0xbd, 0x3e, 0xf7, 0xb4, 0x19, 0xb7, 0x4f, 0x82, 0x3f, 0x84, 0x3a, 0x09, 0xc1, 0x23, 0xda, 0xb6, 0x5c, 0xea, 0x4f, 0xfe, 0x95, 0xd2, 0xa1, 0x4f, 0x99, 0x15, 0x86, 0x23, 0x20, 0x30, 0xa4, 0x76, 0xd6, 0xb0, 0x94, 0x8a, 0x78, 0x55, 0xdc, 0x55, 0x11, 0x04, 0xbd, 0x97, 0x54, 0x5b, 0xd6, 0x8e, 0x51, 0x24, 0x01, 0x3e, 0x31, 0xf9, 0xeb, 0x36, 0x04, 0xad, 0x2e, 0x2f, 0x13, 0x7e, 0xf7, 0x82, 0x6c, 0x62, 0xd6, 0xb0, 0x85, 0x5d, 0x5c, 0x92, 0x0d, 0xe6, 0x16, 0x3c, 0x0a, 0x76, 0xad, 0x52, 0x74, 0xcc, 0xd5, 0x2f, 0xcc, 0x87, 0x2e, 0x64, 0x7c, 0x1e, 0x33, 0xd4, 0xe7, 0x2b, 0x25, 0x80, 0x20, 0x88, 0xf8, 0x16, 0x7c, 0x68, 0xa2, 0x38, 0xa7, 0x11, 0x3b, 0xd6, 0xcb, 0x42, 0x5d, 0x30, 0xf5, 0x56, 0x74, 0x88, 0xb9, 0xf7, 0x98, 0x50, 0x63, 0x34, 0x83, 0x9f, 0xda, 0x32, 0x42, 0x4e, 0x09, 0x1a, 0x6e, 0x22, 0xe3, 0xb0, 0x11, 0xc4, 0x8d, 0xba, 0x40, 0x42, 0x1f, 0x88, 0xcb, 0xbd, 0x68, 0x1f, 0x1a, 0xc5, 0x48, 0x9c, 0xc3, 0xac, 0x9f, 0x7e, 0x35, 0x2b, 0x1a, 0x5e, 0xc7, 0x06, 0x5f, 0xe3, 0xab, 0xad, 0x7b, 0x29, 0x89, 0x4b, 0xde, 0xa3, 0xca, 0x06, 0xec, 0xb2, 0x29, 0xb3, 0xf3, 0x52, 0xa8, 0xfc, 0xd6, 0x94, 0x59, 0xc9, 0x2c, 0x13, 0x26, 0x0d, 0x31, 0xda, 0x33, 0x47, 0xcf, 0xa9, 0x7b, 0x80, 0x69, 0xb5, 0xf4, 0x00, 0x6d, 0x9d, 0xc4, 0x08, 0x76, 0xfd, 0x6d, 0x6b, 0x33, 0xc9, 0x0a, 0x07, 0x82, 0x7d, 0x77, 0xfd, 0x42, 0xec, 0xee, 0x78, 0x02, 0xbb, 0xeb, 0x38, 0x92, 0x5e, 0xdc, 0x8c, 0x24, 0xdc, 0xcf, 0x46, 0x4f, 0x6a, 0xf5, 0xe8, 0x43, 0x87, 0x73, 0x2d, 0x61, 0xf0, 0x2f, 0x9f, 0x24, 0x06, 0x2e, 0x62, 0xa5, 0xc3, 0x17, 0x65, 0x85, 0xcb, 0x63, 0x33, 0xd0, 0x13, 0xa7, 0xb0, 0x30, 0x73, 0x69, 0x0f, 0xbf, 0x5f, 0xa5, 0x94, 0x3c, 0xe6, 0x5e, 0x10, 0x6c, 0x66, 0x4c, 0x82, 0xcd, 0x03, 0x38, 0xad, 0x06, 0x96, 0x72, 0x03, 0x5f, 0xe9, 0xfd, 0xfa, 0x66, 0x6f, 0x11, 0xb9, 0xc6, 0x8b, 0x04, 0xbe, 0x2d, 0x4a, 0xdb, 0x53, 0x1b, 0xb8, 0x1f, 0x6d, 0xdb, 0x81, 0x7f, 0x5f, 0x5e, 0x52, 0xc0, 0xd6, 0x1c, 0xc0, 0xec, 0xc4, 0xf6, 0x46, 0x8d, 0xc6, 0x71, 0x85, 0x36, 0x85, 0x11, 0xd8, 0x7c, 0x61, 0x4e, 0x33, 0x1c, 0x83, 0x06, 0x6b, 0xb8, 0x9a, 0xbf, 0x76, 0x3f, 0x28, 0x4c, 0x4b, 0xdf, 0xcc, 0x86, 0x97, 0xf1, 0x2a, 0xcf, 0xd4, 0x4a, 0xb6, 0x13, 0x47, 0x2a, 0xdd, 0x8f, 0x25, 0x10, 0xd5, 0xf6, 0x64, 0xcc, 0x0e, 0xb6, 0xd9, 0xf8, 0xea, 0x7d, 0x11, 0x06, 0xd3, 0x34, 0x69, 0x38, 0xc7, 0x0e, 0x55, 0x13, 0xf8, 0x04, 0x1f, 0x55, 0x43, 0xc7, 0x49, 0xc6, 0xc3, 0x96, 0x65, 0x13, 0xed, 0x34, 0x67, 0x80, 0x56, 0x8f, 0x99, 0xe2, 0x32, 0xe7, 0x5b, 0x7e, 0x9c, 0x34, 0x89, 0xb5, 0xb1, 0x02, 0x2a, 0xf8, 0x5d, 0xfb, 0x44, 0xd4, 0x95, 0x7c, 0xc4, 0x36, 0xa1, 0x81, 0xf2, 0x2a, 0x0a, 0xe0, 0x3f, 0xf2, 0x22, 0xde, 0x0c, 0x54, 0xc7, 0x27, 0xea, 0xcb, 0x9f, 0x59, 0x0c, 0x78, 0xe2, 0x13, 0x93, 0xea, 0xa1, 0x2e, 0x2f, 0xfa, 0xb6, 0xa0, 0xee, 0x34, 0x6c, 0xcf, 0x9b, 0x23, 0x6d, 0xb9, 0xe7, 0x11, 0x03, 0x05, 0xa1, 0x50, 0xcb, 0x2b, 0x82, 0xa6, 0x39, 0xf3, 0xe3, 0xf8, 0x95, 0x6e, 0x0b, 0xf2, 0x96, 0x91, 0xdb, 0x7c, 0x11, 0xba, 0x94, 0xd7, 0x48, 0x3e, 0x00, 0x0b, 0x78, 0xd0, 0x39, 0xdb, 0x58, 0xa8, 0x73, 0x10, 0x8b, 0xba, 0x46, 0xa9, 0x81, 0xe5, 0xf4, 0xe3, 0xb4, 0x91, 0x5d, 0x4b, 0xa1, 0x03, 0x91, 0xc3, 0x0d, 0x8c, 0xac, 0xe5, 0xdc, 0x11, 0x76, 0x4c, 0x3f, 0x47, 0xb1, 0x44, 0x75, 0x08, 0x5b, 0x90, 0xe9, 0x1b, 0x00, 0xc7, 0x9d, 0x37, 0xfb, 0xa3, 0x1a, 0x1e, 0x1e, 0x1d, 0x9b, 0x83, 0x00, 0xd2, 0xc3, 0x0f, 0x52, 0xeb, 0xc8, 0xfb, 0x05, 0x0a, 0xca, 0xc3, 0xdb, 0x7a, 0x14, 0xa0, 0x5a, 0xbb, 0x86, 0xfa, 0xfc, 0xc9, 0x16, 0x49, 0x15, 0xdc, 0x7f, 0x0e, 0x79, 0x0a, 0xe8, 0x44, 0x7a, 0xce, 0x8a, 0x9d, 0x38, 0x0e, 0x59, 0x05, 0xa9, 0x14, 0xd0, 0x13, 0x56, 0x12, 0xa6, 0x9a, 0xa8, 0xf1, 0x08, 0xf3, 0x22, 0x01, 0x03, 0xf0, 0x72, 0xf3, 0x62, 0xb9, 0x24, 0x3b, 0x21, 0x6f, 0x76, 0xe1, 0xe0, 0xab, 0xf9, 0xc9, 0xa0, 0x54, 0xc0, 0x04, 0x04, 0xd5, 0x9f, 0x8f, 0x80, 0x4a, 0x07, 0x48, 0x4c, 0x7f, 0xa8, 0xef, 0x71, 0x58, 0x8d, 0xe2, 0x0b, 0x7f, 0x04, 0x69, 0xba, 0xb3, 0x2e, 0xa0, 0xbe, 0x3c, 0x72, 0xa1, 0x60, 0x7c, 0x60, 0x51, 0xf4, 0xb0, 0xb4, 0x0b, 0xe9, 0xa1, 0xcc, 0x28, 0xb8, 0x6b, 0x08, 0x73, 0x19, 0xec, 0x1c, 0x82, 0x23, 0xb9, 0x83, 0xda, 0x3c, 0x20, 0x1f, 0x39, 0x53, 0x00, 0x4e, 0x51, 0xdf, 0x30, 0x96, 0xd8, 0x75, 0x17, 0xb0, 0x3e, 0xc8, 0x31, 0xda, 0xfb, 0xb8, 0x43, 0x45, 0xa2, 0xee, 0xd2, 0xaa, 0xb1, 0x2f, 0xff, 0x19, 0x03, 0x84, 0xec, 0x74, 0x42, 0x00, 0x99, 0x97, 0x85, 0x57, 0xaa, 0xe0, 0xa3, 0xdf, 0x55, 0x54, 0xbf, 0x8d, 0xb4, 0xcf, 0x3f, 0x3f, 0xcb, 0x4c, 0x33, 0x7e, 0x12, 0xf9, 0xf7, 0x56, 0xe9, 0xcf, 0xe6, 0x81, 0xdf, 0x34, 0x5e, 0xcf, 0x90, 0xdf, 0xf5, 0x30, 0x1a, 0x80, 0xed, 0x88, 0x69, 0xa5, 0xbb, 0x70, 0xe5, 0x33, 0x57, 0x6a, 0x3c, 0x8d, 0x48, 0xbb, 0x9f, 0x75, 0x71, 0x8e, 0xd1, 0x0a, 0xbc, 0x6e, 0x18, 0x65, 0x4f, 0xfc, 0x44, 0x38, 0x0a, 0xb4, 0xce, 0xbb, 0xe0, 0x2b, 0xf7, 0xee, 0x66, 0x54, 0xba, 0xd6, 0x3a, 0xc5, 0xa3, 0xc5, 0x80, 0xb6, 0x8e, 0x58, 0x59, 0x13, 0x7a, 0xd8, 0xbf, 0xb5, 0xc5, 0x7a, 0x04, 0x0c, 0x23, 0xf6, 0x78, 0x64, 0xdb, 0xa7, 0x8a, 0x77, 0xf5, 0xa1, 0x7d, 0xb4, 0xa7, 0xbc, 0xc1, 0x75, 0xcb, 0xc6, 0x24, 0xe7, 0xe6, 0xcf, 0xa4, 0x97, 0xec, 0xe4, 0x91, 0x4c, 0x91, 0x59, 0xe1, 0x1b, 0x06, 0x72, 0x29, 0xae, 0x8a, 0x38, 0xea, 0x46, 0x8f, 0xc0, 0x43, 0xe2, 0x29, 0xd3, 0x43, 0xd1, 0x43, 0xcb, 0x2b, 0xb3, 0x8a, 0x51, 0xcf, 0xe4, 0x92, 0xc2, 0xd5, 0x06, 0xd9, 0xb5, 0x7c, 0xdd, 0xb3, 0x47, 0xa7, 0xfe, 0x0f, 0xe9, 0x52, 0x25, 0x45, 0x6f, 0xc5, 0xfe, 0xb7, 0x99, 0xb5, 0x0c, 0x89, 0x57, 0x37, 0xa6, 0xbe, 0xb5, 0x81, 0xad, 0x04, 0x04, 0xcd, 0xb9, 0xd8, 0xfb, 0x77, 0xae, 0x8c, 0x39, 0xc1, 0xd9, 0x36, 0x40, 0x18, 0x57, 0x6a, 0x75, 0x0e, 0x25, 0x4b, 0x35, 0x46, 0x2d, 0x34, 0xd4, 0x64, 0x7a, 0xe5, 0xe6, 0x08, 0xde, 0x6c, 0x89, 0x9a, 0x8a, 0x38, 0xa4, 0x62, 0xaf, 0xad, 0x63, 0x17, 0xa5, 0x26, 0x66, 0x38, 0x2c, 0x8f, 0x77, 0x70, 0xe3, 0xa9, 0x45, 0xb1, 0x4a, 0x97, 0x63, 0xa7, 0x85, 0x9e, 0x56, 0x49, 0x74, 0xb4, 0x42, 0xae, 0x6c, 0xe5, 0xc2, 0x2b, 0xcf, 0x5c, 0xeb, 0x78, 0xa4, 0xb7, 0x9d, 0xd9, 0x4d, 0xe1, 0x7d, 0x0c, 0x31, 0xac, 0x58, 0x90, 0x5b, 0x68, 0x50, 0xd8, 0x84, 0x28, 0x1e, 0xff, 0xc8, 0x6a, 0x1d, 0x64, 0xfc, 0x72, 0x54, 0x0b, 0xf9, 0x2b, 0xa8, 0x8b, 0x1f, 0xfb, 0x78, 0xb1, 0x95, 0x14, 0x50, 0x5d, 0xa0, 0xed, 0x88, 0x6f, 0x72, 0x73, 0x8a, 0xae, 0xae, 0x5f, 0x77, 0x40, 0xe8, 0xd7, 0xf7, 0x60, 0xa9, 0x5f, 0x22, 0x16, 0x1b, 0xf6, 0x6f, 0xf6, 0x4c, 0xf2, 0x1f, 0x9d, 0xb3, 0x3e, 0x04, 0x88, 0x07, 0xec, 0x3b, 0x98, 0x8d, 0x2c, 0xb5, 0xda, 0x7e, 0x4a, 0x97, 0x46, 0x36, 0xcc, 0x44, 0xf9, 0x71, 0x29, 0x37, 0x9b, 0x45, 0x7b, 0x97, 0x6e, 0xde, 0xde, 0xf8, 0x23, 0x38, 0x21, 0x9e, 0x16, 0xf6, 0x64, 0x25, 0xf6, 0x90, 0x37, 0x1a, 0xee, 0x0c, 0x73, 0x30, 0xfe, 0x04, 0x1e, 0xaa, 0xea, 0x1f, 0x2f, 0x58, 0xc2, 0x05, 0x17, 0x81, 0x15, 0xe6, 0x8d, 0xc1, 0xf7, 0xb1, 0xdd, 0xd2, 0xe8, 0x84, 0xc3, 0xa8, 0x77, 0x2d, 0x29, 0xe6, 0xa7, 0x0a, 0xee, 0x30, 0x24, 0x1d, 0x69, 0xdf, 0xbe, 0x4d, 0x64, 0xc0, 0x0c, 0x31, 0xff, 0xb7, 0xdb, 0x9b, 0x61, 0x8f, 0x41, 0x2a, 0xad, 0x76, 0x62, 0xab, 0x81, 0x24, 0xfc, 0xcd, 0xd1, 0xaa, 0xb2, 0x73, 0x68, 0x3a, 0xc7, 0x78, 0xb9, 0x92, 0xbe, 0xd4, 0x5a, 0x8a, 0x34, 0xf4, 0xef, 0x08, 0xff, 0x14, 0x74, 0x9b, 0x26, 0xa5, 0x7c, 0xa1, 0x4f, 0x17, 0x71, 0xd1, 0xc5, 0x03, 0x82, 0x17, 0xea, 0x79, 0x09, 0x05, 0x07, 0x06, 0xc0, 0xa0, 0x84, 0xde, 0x28, 0x0c, 0xd7, 0x34, 0xd9, 0x0e, 0xec, 0x8b, 0x56, 0xa5, 0x79, 0xfa, 0x72, 0x0c, 0x72, 0xca, 0x98, 0xf7, 0x78, 0xc0, 0x36, 0x9f, 0x50, 0x1f, 0xce, 0xdd, 0xa1, 0x12, 0x77, }, .pub_len = 1312, .msg = { 0x96, 0x8d, 0xcb, 0xc5, 0x4e, 0xb2, 0xcf, 0x5c, 0xd3, 0x6f, 0x04, 0xbb, 0x00, 0x4e, 0xb1, 0x70, 0x0e, 0x24, 0x91, 0x5c, 0xe0, 0x88, 0x5b, 0xda, 0x2c, 0x58, 0x18, 0xc1, 0xa7, 0xe6, 0x94, 0x14, 0xaa, 0x19, 0x68, 0x94, 0x3a, 0x5c, 0x7a, 0x6a, 0xe1, 0x52, 0xa2, 0xf1, 0x30, 0xa2, 0x46, 0x06, 0x71, 0x62, 0xb3, 0x04, 0x59, 0x06, 0x07, 0xff, 0x21, 0x06, 0x21, 0xc8, 0x1c, 0xb0, 0xae, 0x76, 0x61, 0x34, 0x5d, 0x46, 0x55, 0x22, 0xd2, 0xc2, 0x29, 0xea, 0x62, 0xe8, 0x88, 0x7d, 0xe1, 0x4e, 0x21, 0x34, 0x71, 0x56, 0x5c, 0xf6, 0x49, 0x08, 0x60, 0xbd, 0xb7, 0x0d, 0x1e, 0xa3, 0x55, 0x43, 0x3a, 0x2a, 0x6e, 0x11, 0xf0, 0x68, 0x3b, 0xe3, 0xb8, 0x0f, 0xfb, 0xa2, 0x0e, 0x67, 0xbd, 0xd9, 0x14, 0x40, 0x6c, 0x71, 0xf4, 0xe9, 0xa0, 0xd0, 0x46, 0x4e, 0xaf, 0x91, 0x06, 0x8b, 0xd2, 0x24, 0x8d, 0x71, 0x50, 0x45, 0x56, 0xf5, 0x8e, 0x8e, 0xa6, 0x66, 0x3f, 0xfc, 0xc7, 0x8f, 0x57, 0x0f, 0x4e, 0xbe, 0x98, 0xf0, 0xc8, 0xe2, 0xb4, 0x8a, 0x6f, 0xc5, 0x07, 0x7f, 0xf7, 0xe2, 0x49, 0xf8, 0x0c, 0xc2, 0x32, 0x65, 0x76, 0x0c, 0x97, 0xad, 0x30, 0x34, 0x54, 0xa9, 0x73, 0x10, 0x96, 0x4d, 0xce, 0xa6, 0x73, 0x50, 0x83, 0xde, 0xe6, 0xbf, 0xd6, 0xc6, 0x51, 0xee, 0xa2, 0xbf, 0xc3, 0xfb, 0x0f, 0xb3, 0x0c, 0x5d, 0xdd, 0x25, 0xb5, 0xc2, 0x0e, 0x1c, 0xce, 0xae, 0xa2, 0x8b, 0x51, 0xc1, 0xb4, 0xaa, 0x3e, 0xba, 0xdd, 0x59, 0xab, 0x19, 0x1f, 0x10, 0x8a, 0x2c, 0xcf, 0xa6, 0xc9, 0xff, 0xe3, 0xf6, 0x35, 0xc5, 0xd2, 0x4a, 0xf8, 0x0c, 0x60, 0x51, 0xa9, 0x2f, 0xf7, 0x06, 0xcf, 0x61, 0xf3, 0x21, 0x94, 0x6c, 0xbf, 0xa6, 0xf2, 0x44, 0x78, 0xde, 0xa7, 0xd5, 0x31, 0x16, 0x14, 0xb8, 0x4c, 0xc6, 0xb4, 0x72, 0xed, 0x44, 0xe2, 0x48, 0x16, 0xfd, 0x60, 0xd0, 0x9e, 0x24, 0xf7, 0xc7, 0xe6, 0xbc, 0x42, 0xe3, 0x5e, 0x16, 0xc6, 0x97, 0x68, 0x22, 0x0a, 0xb4, 0x92, 0x0e, 0x0a, 0xc1, 0x21, 0x47, 0x54, 0xef, 0xcd, 0xb6, 0x1e, 0x36, 0x04, 0xf2, 0x82, 0x85, 0x3e, 0x5a, 0x67, 0x83, 0x93, 0x3a, 0xe4, 0x3c, 0xd7, 0x36, 0xff, 0xa0, 0xb5, 0x82, 0x28, 0x0c, 0x7b, 0xe7, 0x3a, 0x99, 0x83, 0x9e, 0x2a, 0x05, 0xa7, 0x8b, 0x02, 0xcb, 0xf9, 0x1a, 0x19, 0x5e, 0xb6, 0x7b, 0x1a, 0x91, 0x2f, 0x85, 0x9c, 0xcd, 0xa8, 0x8d, 0x5f, 0x4c, 0x4d, 0xfc, 0x7a, 0xd0, 0x81, 0x18, 0x50, 0x1e, 0x50, 0x39, 0x01, 0x58, 0xeb, 0x96, 0x08, 0x30, 0x08, 0x8d, 0xca, 0x36, 0x82, 0x4d, 0x9d, 0x30, 0x52, 0xa9, 0x25, 0xcb, 0x05, 0x8b, 0xd3, 0x84, 0xf6, 0x16, 0x9c, 0xb0, 0xbb, 0x0b, 0x58, 0xc3, 0x50, 0x9c, 0xab, 0x54, 0xac, 0x6c, 0x3a, 0x54, 0x50, 0xa2, 0x59, 0x7b, 0x11, 0x56, 0x63, 0xe9, 0xac, 0x36, 0xdb, 0xda, 0xdc, 0xa1, 0xba, 0xfb, 0x8d, 0xad, 0xc4, 0x26, 0xeb, 0x59, 0xd2, 0x62, 0x09, 0xdb, 0x8d, 0xe6, 0x36, 0x4a, 0x67, 0x2d, 0x83, 0x01, 0x6c, 0xc0, 0x87, 0x61, 0x31, 0xbb, 0x3d, 0x87, 0x09, 0x8e, 0x6d, 0x62, 0x9f, 0xde, 0x82, 0xe2, 0x9e, 0x13, 0x99, 0xbe, 0x55, 0xbd, 0x62, 0xe1, 0xdc, 0x43, 0x12, 0xa1, 0x70, 0xb6, 0xc4, 0x48, 0x3c, 0x7b, 0x7f, 0x3d, 0xde, 0x2c, 0xc1, 0x5e, 0xe5, 0x40, 0x16, 0x35, 0x43, 0xe6, 0x1f, 0x9f, 0x87, 0xa7, 0x00, 0x2b, 0x75, 0xc0, 0x7c, 0xec, 0xfd, 0x65, 0x8d, 0xf3, 0x1a, 0x23, 0xc7, 0x20, 0xc3, 0xb0, 0x48, 0xbf, 0x7e, 0x0a, 0x89, 0x9f, 0x3f, 0x0f, 0x7e, 0xd2, 0xa9, 0x60, 0x46, 0x69, 0x36, 0x2c, 0xc4, 0x38, 0xd7, 0x87, 0xf8, 0x85, 0x3b, 0xfd, 0x47, 0x67, 0xcb, 0x00, 0x6e, 0x64, 0x12, 0xc0, 0x95, 0x89, 0x50, 0x56, 0xcc, 0x4b, 0xe0, 0xd7, 0xb3, 0x6e, 0x45, 0xb7, 0xe9, 0x45, 0xcd, 0x58, 0xf3, 0x88, 0x87, 0xda, 0xe0, 0x58, 0x3a, 0x99, 0x15, 0x4a, 0x55, 0x6a, 0x76, 0xf2, 0x7d, 0xc4, 0x8a, 0x92, 0xa6, 0x13, 0xc2, 0x2a, 0xb5, 0x4b, 0x13, 0xb7, 0xe0, 0x32, 0x1e, 0x51, 0x48, 0x9d, 0xd1, 0x42, 0xf3, 0xeb, 0x28, 0x9d, 0x52, 0x3b, 0x9d, 0x12, 0x80, 0x82, 0x97, 0xf4, 0x8f, 0x94, 0xa0, 0x63, 0x08, 0x31, 0xe3, 0x9f, 0x9a, 0xe6, 0x74, 0xb0, 0x77, 0x33, 0x94, 0xd7, 0xab, 0x96, 0xcd, 0xed, 0x5e, 0x06, 0x87, 0x1e, 0x28, 0x93, 0xc4, 0x89, 0xb3, 0x5c, 0x10, 0x2a, 0xfb, 0x8b, 0xea, 0x75, 0x0a, 0xc9, 0xe7, 0x15, 0x8a, 0x30, 0x48, 0x7a, 0x0a, 0x50, 0x30, 0x17, 0xc5, 0x50, 0x6e, 0x91, 0xad, 0x92, 0x7f, 0x79, 0x09, 0xab, 0x2d, 0xf0, 0x47, 0x6e, 0xcf, 0xe2, 0x60, 0x7e, 0x00, 0xa8, 0x4a, 0x59, 0x28, 0x1a, 0x27, 0x7a, 0x80, 0xdd, 0x80, 0x90, 0xc9, 0x55, 0x83, 0x0b, 0xf7, 0x82, 0x3e, 0x71, 0xa9, 0xfc, 0x33, 0x35, 0xcf, 0x33, 0xe3, 0x0f, 0x8f, 0x0a, 0x0d, 0xc8, 0x0b, 0xd3, 0xa6, 0xb3, 0x23, 0xbd, 0xd3, 0xad, 0x02, 0x56, 0x8f, 0xb2, 0xaf, 0xd8, 0xde, 0x11, 0xff, 0xd7, 0x79, 0xdd, 0xaa, 0x6b, 0x52, 0xa6, 0x5c, 0x6d, 0x17, 0xfc, 0xc7, 0x2a, 0xd1, 0x0f, 0x90, 0x2f, 0x69, 0xa7, 0x66, 0x83, 0xe2, 0x70, 0x5f, 0xe9, 0xdd, 0xfc, 0xa3, 0x8f, 0xa3, 0xe6, 0x2f, 0xaa, 0x39, 0x61, 0x1a, 0x9e, 0xf7, 0x74, 0x7a, 0x0c, 0x37, 0x05, 0x2e, 0x32, 0x96, 0xdf, 0x52, 0x32, 0x42, 0x52, 0xbe, 0x0d, 0xbc, 0x38, 0x38, 0x93, 0x7b, 0xa2, 0xe0, 0xcc, 0xb3, 0x93, 0x73, 0x45, 0x2f, 0x5d, 0x09, 0x24, 0x42, 0xd2, 0x82, 0x28, 0xb4, 0x22, 0xbb, 0x1a, 0x04, 0xda, 0x8b, 0xbd, 0xc8, 0x57, 0x22, 0x16, 0x2b, 0x5e, 0x08, 0x43, 0x85, 0x5c, 0x70, 0x7a, 0x9c, 0x2e, 0x2f, 0xf2, 0x20, 0x32, 0x0d, 0x21, 0x9d, 0x1b, 0x89, 0x64, 0x69, 0xea, 0x6b, 0xc4, 0x7b, 0xbd, 0xef, 0xeb, 0x1c, 0x7d, 0xfb, 0xe2, 0x85, 0x94, 0x77, 0x3c, 0x7e, 0xa7, 0x40, 0xcc, 0x37, 0xec, 0x12, 0x1f, 0xe7, 0x37, 0xd8, 0xf4, 0xc6, 0xa8, 0x3a, 0xc4, 0x39, 0xa8, 0xab, 0xa2, 0x9a, 0x87, 0xea, 0xc5, 0x28, 0xa8, 0x66, 0xaf, 0x4e, 0x16, 0x2a, 0xf9, 0x26, 0xd4, 0xc9, 0xd8, 0xe0, 0xc3, 0x0d, 0x15, 0x8d, 0x06, 0x4b, 0x65, 0x82, 0x18, 0x94, 0x83, 0x2c, 0x4a, 0xf9, 0xb0, 0x8d, 0x9e, 0x10, 0x48, 0x7f, 0x20, 0x8f, 0x45, 0x01, 0x9f, 0x25, 0x32, 0x9d, 0x5b, 0x0c, 0x5b, 0x2b, 0x67, 0x0f, 0x32, 0x58, 0x38, 0x41, 0xab, 0xd0, 0x69, 0xe6, 0xb8, 0xed, 0x67, 0x4f, 0x74, 0x48, 0xc7, 0x54, 0x33, 0x2f, 0xf5, 0x3f, 0xef, 0xf6, 0x66, 0x4d, 0xce, 0xb1, 0x1b, 0xcf, 0x69, 0xd0, 0x82, 0xeb, 0x7c, 0xbe, 0x41, 0x77, 0xe1, 0xd1, 0x40, 0x3e, 0xbe, 0x10, 0x86, 0xab, 0x4e, 0x6e, 0xd7, 0x4e, 0x6c, 0xc4, 0xdd, 0xdd, 0x17, 0xe3, 0xcd, 0x74, 0xd0, 0x1a, 0x13, }, .msg_len = 952, .sig = { 0x04, 0x76, 0xb8, 0xda, 0x70, 0x15, 0x37, 0x26, 0xe1, 0x15, 0x87, 0x7b, 0xc4, 0x56, 0x07, 0xce, 0x80, 0xde, 0x0b, 0x02, 0xc4, 0x99, 0xd2, 0x54, 0xca, 0x45, 0xe0, 0x95, 0xd6, 0x27, 0x92, 0x8e, 0x0e, 0x9c, 0x38, 0xa9, 0xbb, 0xdc, 0xf4, 0xd9, 0xfb, 0xfb, 0x18, 0x69, 0xbb, 0x4d, 0x40, 0x03, 0xcb, 0x70, 0xc4, 0x6f, 0x5b, 0x22, 0x5a, 0x6c, 0xde, 0xef, 0xcd, 0xf9, 0x66, 0x11, 0x94, 0x1a, 0x67, 0x6f, 0xa0, 0xaf, 0xb6, 0xc6, 0xf9, 0xb3, 0x9c, 0x00, 0x83, 0x94, 0x8f, 0xc9, 0x0d, 0x99, 0xbd, 0xa6, 0xfa, 0xdd, 0x9f, 0x50, 0x8d, 0x21, 0x3b, 0xd7, 0xd0, 0xba, 0xfc, 0xd3, 0x99, 0xe2, 0x09, 0x27, 0xe7, 0xe3, 0x34, 0xb0, 0x06, 0xa5, 0x21, 0x39, 0x86, 0x5c, 0x18, 0x72, 0x7e, 0xe0, 0xcf, 0x72, 0x65, 0x78, 0xcd, 0xf8, 0x2e, 0xff, 0xc8, 0x65, 0x9d, 0x2c, 0xc6, 0xe6, 0x8e, 0xef, 0x3e, 0xa0, 0x37, 0xf9, 0xf6, 0xb4, 0x11, 0xbd, 0x88, 0xba, 0xe3, 0xfa, 0x4c, 0x28, 0xb3, 0xdc, 0xe9, 0x01, 0xf7, 0x3f, 0x68, 0x1f, 0x9e, 0x5f, 0x10, 0x6c, 0x84, 0x3f, 0x20, 0xdb, 0x42, 0xfb, 0x7d, 0xc9, 0xd9, 0xa4, 0xcd, 0x7a, 0xd5, 0xbe, 0x7c, 0x04, 0x42, 0x5f, 0xd5, 0xee, 0xb5, 0x3b, 0x98, 0x24, 0x1e, 0xef, 0xa3, 0x0a, 0x63, 0x45, 0x5b, 0x10, 0xc8, 0x45, 0x91, 0xc3, 0xaa, 0xb9, 0x38, 0xc4, 0xb5, 0xef, 0xb8, 0xa1, 0x2d, 0x09, 0x80, 0x5e, 0xa5, 0x71, 0x0d, 0xa1, 0xe2, 0x0d, 0xbf, 0x06, 0x70, 0xf5, 0x79, 0x97, 0x48, 0x2f, 0x95, 0xcb, 0xec, 0xac, 0x3c, 0x4a, 0xe9, 0xa6, 0xe2, 0x60, 0x2c, 0xd4, 0x69, 0x50, 0xd2, 0xf4, 0x33, 0x9c, 0x7c, 0xdd, 0xe3, 0x08, 0x5f, 0x3d, 0x38, 0xbb, 0x0c, 0x43, 0xb2, 0xc5, 0xb7, 0x67, 0xc1, 0xde, 0xec, 0x2a, 0x6e, 0x31, 0x99, 0x73, 0x0e, 0xed, 0xcc, 0x6b, 0x2d, 0xf1, 0x0c, 0x03, 0x6c, 0x2e, 0x7a, 0xb3, 0x99, 0xd8, 0x93, 0xb3, 0x67, 0x5f, 0x23, 0x60, 0x85, 0x18, 0x3e, 0x4e, 0x3a, 0x85, 0x95, 0x33, 0xfa, 0x7b, 0xff, 0x97, 0xdb, 0xd1, 0x27, 0x10, 0xab, 0xe4, 0xc8, 0x13, 0x47, 0x9a, 0xec, 0x23, 0xaf, 0x04, 0x2f, 0x6c, 0x6a, 0xcc, 0xb0, 0x59, 0x2d, 0x73, 0xe2, 0xa5, 0x6c, 0xb8, 0xa6, 0x1f, 0x19, 0x77, 0xf2, 0x9a, 0x93, 0xf0, 0x5b, 0x59, 0x2d, 0x7e, 0x7a, 0xee, 0x89, 0x11, 0xb2, 0xd9, 0x36, 0x45, 0xc3, 0xa4, 0x3e, 0x6a, 0xed, 0x6f, 0x6f, 0xfd, 0x84, 0xdc, 0x49, 0xe5, 0xde, 0x46, 0x8c, 0x48, 0x0d, 0xdb, 0x49, 0x3e, 0x9c, 0x8e, 0x3d, 0xd9, 0x2e, 0x18, 0x8e, 0x39, 0xe6, 0x37, 0xf9, 0x33, 0x77, 0xf4, 0xf0, 0xaa, 0x2f, 0xd6, 0xd3, 0x0b, 0xd1, 0xdf, 0x4d, 0xff, 0x3a, 0xa0, 0x28, 0x49, 0xd2, 0x05, 0x09, 0xc3, 0xf6, 0xc6, 0xf2, 0x30, 0x85, 0xa7, 0x92, 0xfe, 0xa8, 0xd4, 0xf3, 0xed, 0x25, 0x4e, 0xbe, 0xb1, 0x0c, 0xf1, 0xa2, 0xc3, 0x42, 0x06, 0xab, 0xf5, 0x08, 0x86, 0x6c, 0xec, 0x99, 0x53, 0xfb, 0xfd, 0xa7, 0xb9, 0xb6, 0xbd, 0xeb, 0x08, 0xb5, 0x30, 0x9f, 0x68, 0xb7, 0x57, 0xbe, 0x8a, 0xcc, 0x22, 0xd2, 0x2e, 0x19, 0x76, 0xde, 0x4c, 0x8a, 0x97, 0xfa, 0x62, 0x00, 0xda, 0xb2, 0x92, 0xe7, 0x93, 0x5c, 0x7c, 0xc6, 0x90, 0x0b, 0x3f, 0x1e, 0xd8, 0xb8, 0x99, 0x0f, 0x9f, 0x2f, 0x18, 0xfb, 0x23, 0xf5, 0xfd, 0x2a, 0xcd, 0xed, 0x09, 0x94, 0xd6, 0x81, 0xae, 0x24, 0x16, 0xd2, 0x63, 0x51, 0x59, 0x62, 0x2e, 0xbe, 0x00, 0x91, 0x37, 0xc9, 0xc8, 0xac, 0xad, 0xd4, 0x15, 0x63, 0xe8, 0x50, 0x52, 0x7e, 0xf4, 0xdd, 0x5d, 0x0e, 0x12, 0x86, 0x67, 0x32, 0xb1, 0x3e, 0xec, 0xed, 0x11, 0xfb, 0x8a, 0xc3, 0xcb, 0x4b, 0x65, 0x7a, 0x19, 0x80, 0xeb, 0x8c, 0x0e, 0xe3, 0xa9, 0xfa, 0x92, 0xba, 0x5c, 0x82, 0x61, 0x8e, 0xc8, 0xcf, 0x5b, 0x2d, 0x65, 0x14, 0xb1, 0xc3, 0x38, 0x6a, 0x27, 0xa6, 0xdc, 0x0f, 0x2d, 0x9a, 0xa7, 0xaf, 0xdd, 0x4d, 0x93, 0x29, 0x6c, 0x77, 0x2d, 0x0c, 0x91, 0x91, 0xe2, 0x6b, 0x02, 0xdb, 0x13, 0x7d, 0xf2, 0xab, 0xa4, 0x73, 0xe9, 0x3c, 0x04, 0x00, 0x1e, 0xef, 0xf6, 0x10, 0xbe, 0x56, 0xfc, 0xc8, 0xdb, 0x9e, 0x4d, 0x71, 0x7b, 0xf2, 0xf1, 0xec, 0xc3, 0xff, 0x9a, 0x66, 0x3f, 0x95, 0x33, 0x18, 0x82, 0xf7, 0x17, 0x65, 0x90, 0xaf, 0xda, 0x22, 0xbc, 0x69, 0x7d, 0x23, 0xcd, 0xbe, 0x1f, 0xc6, 0xdc, 0x96, 0x09, 0x30, 0x22, 0x0c, 0xa0, 0x63, 0xad, 0xbe, 0xdc, 0xce, 0xa4, 0xd6, 0x38, 0x8e, 0x4b, 0xf0, 0x5f, 0xe3, 0x43, 0xf2, 0x9f, 0x55, 0x26, 0xae, 0x7d, 0xd3, 0x52, 0x52, 0xdd, 0x2b, 0xb6, 0x7a, 0xe0, 0xff, 0x9a, 0x50, 0x9d, 0x85, 0x07, 0x5a, 0x7b, 0x8a, 0x07, 0x3d, 0xd5, 0xd6, 0xa7, 0x37, 0x07, 0xac, 0x22, 0xac, 0x74, 0x88, 0xa0, 0x3f, 0x04, 0xdc, 0x6f, 0x33, 0x34, 0xb8, 0x08, 0xba, 0xee, 0x98, 0xca, 0x19, 0x93, 0xcb, 0x4b, 0xbc, 0x21, 0xe7, 0xcf, 0xc5, 0x40, 0x6b, 0x27, 0x30, 0xe6, 0xbb, 0x31, 0xd1, 0xe2, 0xd2, 0x13, 0x45, 0x64, 0xc0, 0x98, 0xda, 0xfd, 0x15, 0x8b, 0x14, 0x06, 0x70, 0x47, 0x24, 0x40, 0xd3, 0x40, 0x89, 0x48, 0xce, 0x34, 0x57, 0xb2, 0x34, 0x3c, 0xf9, 0x35, 0x9b, 0x39, 0x49, 0xbd, 0xf1, 0x48, 0xfd, 0xb3, 0xbc, 0x49, 0x15, 0x06, 0x3f, 0xce, 0x99, 0xdd, 0xd9, 0x46, 0x77, 0x56, 0xc8, 0xf8, 0x83, 0xd8, 0x3c, 0x8c, 0xb3, 0x57, 0x55, 0x06, 0x8b, 0x1f, 0x9e, 0xd9, 0x9d, 0xbb, 0xd5, 0x28, 0x42, 0xd2, 0x77, 0xca, 0xa5, 0xf5, 0x5e, 0x88, 0xf4, 0xda, 0x87, 0x63, 0xb4, 0xc1, 0xd7, 0x33, 0xfd, 0x0f, 0x81, 0x99, 0x9d, 0x85, 0x8b, 0x98, 0xbd, 0xc2, 0xee, 0x8d, 0xf9, 0xe8, 0xf4, 0x6f, 0x7a, 0x0c, 0x73, 0x91, 0x5a, 0xe1, 0xc8, 0xfa, 0xbf, 0x70, 0x73, 0x35, 0x45, 0x7f, 0xc6, 0x19, 0x37, 0x99, 0x3d, 0xc9, 0x98, 0x77, 0xab, 0x4d, 0xf1, 0x22, 0xa8, 0x72, 0x3d, 0xaf, 0x4b, 0x88, 0xb1, 0xda, 0x92, 0xe3, 0x98, 0xfc, 0x7f, 0xed, 0x20, 0x84, 0xab, 0xf5, 0xad, 0x37, 0x05, 0x38, 0x00, 0x12, 0x39, 0xbf, 0x46, 0x05, 0x8d, 0xe8, 0x9a, 0x7b, 0x90, 0x71, 0x76, 0x27, 0xa0, 0xea, 0xe7, 0xc6, 0x2e, 0xa1, 0x83, 0x2e, 0xc0, 0x65, 0xa6, 0x94, 0x84, 0x9a, 0xd9, 0x92, 0xb0, 0xc2, 0x7b, 0x31, 0x0a, 0x55, 0xd6, 0xe9, 0x50, 0xf6, 0xbc, 0x47, 0x0e, 0x58, 0x18, 0xfc, 0x01, 0x94, 0xf0, 0xb1, 0x55, 0x2a, 0x92, 0x11, 0xd9, 0xa8, 0xef, 0x5c, 0x94, 0x0d, 0x17, 0x19, 0xac, 0x31, 0x5e, 0xa9, 0x25, 0xec, 0xcd, 0x10, 0x76, 0x74, 0x1a, 0x2a, 0x1a, 0x33, 0x33, 0xe0, 0x02, 0x1f, 0xb5, 0xb1, 0x6f, 0x65, 0xf5, 0x81, 0x81, 0xba, 0x64, 0x90, 0x4f, 0x65, 0x50, 0x94, 0x5f, 0xcb, 0xb8, 0x55, 0xd6, 0xae, 0xf1, 0x2b, 0xc1, 0xe3, 0xc9, 0xda, 0xc6, 0xd6, 0xe3, 0xe5, 0xf3, 0xb5, 0xca, 0xf2, 0xd0, 0xf2, 0x7d, 0xaf, 0xaa, 0x97, 0xc1, 0x42, 0x6b, 0xc3, 0xa7, 0x40, 0xb1, 0x76, 0x53, 0xdc, 0x80, 0x9f, 0x2c, 0x0c, 0xfb, 0xd6, 0x40, 0x9e, 0x69, 0x95, 0xfe, 0x90, 0x51, 0x98, 0xcd, 0xbf, 0xe8, 0x98, 0x7b, 0x45, 0xe6, 0x83, 0x9b, 0x72, 0x36, 0x5f, 0xf1, 0x6e, 0x46, 0x5d, 0xcf, 0x5e, 0x13, 0x9f, 0x02, 0xa9, 0x53, 0x87, 0x22, 0xda, 0xc7, 0xe0, 0xdd, 0x1c, 0xbd, 0xd4, 0x62, 0x44, 0x2f, 0xd1, 0x20, 0x09, 0x28, 0xce, 0x29, 0x1f, 0x65, 0x16, 0x17, 0xd4, 0x05, 0x97, 0x8a, 0x8a, 0x94, 0x6f, 0xe3, 0x78, 0x21, 0xc9, 0x56, 0x3d, 0x2d, 0xd2, 0x4a, 0xcc, 0x28, 0x2c, 0xc9, 0xfc, 0xf7, 0x73, 0x6e, 0x22, 0x84, 0x36, 0x58, 0x6f, 0x35, 0x2d, 0x85, 0x6b, 0x90, 0x09, 0xbd, 0xc3, 0x3a, 0x83, 0x4a, 0x62, 0x6b, 0x58, 0x0f, 0x8a, 0x91, 0x00, 0x3a, 0x12, 0xc2, 0xd3, 0x0e, 0x5b, 0x7d, 0x49, 0x88, 0x3e, 0xa3, 0x59, 0x4d, 0xa8, 0x19, 0xce, 0xe2, 0xd3, 0x9d, 0x8c, 0x3c, 0xf6, 0x91, 0xe4, 0x2e, 0x65, 0x54, 0xb4, 0x56, 0x2f, 0xea, 0xa3, 0x00, 0xbe, 0x39, 0x50, 0xc8, 0x26, 0x4e, 0x3f, 0x43, 0x1d, 0xa1, 0x73, 0x81, 0xb1, 0x19, 0x36, 0x97, 0x2c, 0x16, 0x50, 0x21, 0x28, 0x56, 0x08, 0x41, 0x28, 0x36, 0x08, 0x51, 0x94, 0xac, 0x26, 0xa5, 0xc5, 0x86, 0x8d, 0xd2, 0xbb, 0x9b, 0xfd, 0x7b, 0x56, 0x1e, 0x74, 0x54, 0xab, 0x63, 0xda, 0xc7, 0x3c, 0x5b, 0x1b, 0x72, 0x7b, 0x8e, 0x1d, 0xea, 0x47, 0x9e, 0x47, 0xab, 0xa6, 0xba, 0x3f, 0xe5, 0xfa, 0xb0, 0x99, 0xcd, 0x3e, 0x85, 0x6d, 0x06, 0x54, 0xf0, 0x1e, 0x72, 0xfb, 0x65, 0xc5, 0xe8, 0x5e, 0xa4, 0x8e, 0x92, 0xb8, 0x24, 0xf5, 0x50, 0xaa, 0x0b, 0x93, 0x29, 0x00, 0x7f, 0xf6, 0x54, 0x3c, 0x0a, 0x51, 0x60, 0xaf, 0xd2, 0xc3, 0x7f, 0x3d, 0x79, 0x75, 0x97, 0x21, 0x27, 0x61, 0x04, 0x66, 0x30, 0x3e, 0x5b, 0x8e, 0x73, 0xce, 0x4e, 0x97, 0x38, 0x75, 0xdd, 0x68, 0x41, 0x1b, 0x2d, 0xba, 0xa0, 0xcb, 0x23, 0x59, 0x03, 0xbd, 0x5c, 0x95, 0xab, 0xf5, 0x85, 0x62, 0x56, 0x4e, 0x37, 0xb7, 0x6b, 0xe2, 0x2c, 0xc2, 0x05, 0xea, 0x48, 0x65, 0x27, 0x20, 0xf1, 0xb8, 0x2c, 0x43, 0x37, 0x62, 0xc3, 0x0d, 0x61, 0x15, 0xa6, 0xa9, 0x58, 0xc5, 0x20, 0x7b, 0x0f, 0x2f, 0x4d, 0x1b, 0x6f, 0xe3, 0x4e, 0x48, 0x7d, 0x88, 0xe8, 0xc8, 0x15, 0xbf, 0xff, 0x1c, 0x43, 0x44, 0x22, 0x84, 0xf3, 0x46, 0x52, 0x58, 0x63, 0x19, 0x8f, 0x4b, 0x7b, 0x3e, 0x0b, 0x6e, 0x33, 0x26, 0x82, 0x9f, 0xd1, 0x35, 0x7d, 0xed, 0x65, 0x6d, 0xeb, 0xde, 0x0b, 0xd5, 0x90, 0xe7, 0x37, 0x33, 0x7c, 0x83, 0x9c, 0x2c, 0x95, 0x6a, 0x86, 0x3e, 0x61, 0x4f, 0xd6, 0xb4, 0xaa, 0x68, 0xfe, 0xc9, 0x9f, 0x2f, 0x34, 0xbc, 0xce, 0x58, 0x5f, 0xb1, 0x52, 0xf7, 0xa5, 0x6f, 0xa9, 0x6f, 0xad, 0x64, 0x54, 0x40, 0x97, 0xe7, 0x71, 0x6e, 0x3e, 0xb3, 0x76, 0x14, 0x1a, 0x43, 0xe5, 0x77, 0xf8, 0xa2, 0xe8, 0x86, 0xdb, 0x86, 0x8b, 0x19, 0x52, 0x10, 0x54, 0xe3, 0x40, 0xea, 0x2d, 0x65, 0xd6, 0x3f, 0x9c, 0xab, 0x10, 0x2d, 0x68, 0xc3, 0x79, 0x62, 0xed, 0x14, 0x60, 0xf3, 0xa4, 0xfa, 0xb5, 0x61, 0x21, 0x0f, 0x74, 0x24, 0x24, 0xf7, 0xe6, 0x3b, 0xbe, 0x06, 0xc3, 0xd0, 0x50, 0x1b, 0xb8, 0xef, 0x30, 0x70, 0x83, 0x76, 0x14, 0x2e, 0xa5, 0xfd, 0xe7, 0x5d, 0x0d, 0xa7, 0x8e, 0x75, 0x7c, 0x86, 0x5a, 0xc2, 0x4e, 0xb5, 0xf0, 0xa8, 0x63, 0xdb, 0x8d, 0x68, 0x1c, 0xe2, 0xaa, 0x1a, 0x64, 0x57, 0x56, 0x68, 0x7f, 0x32, 0x30, 0x46, 0xe5, 0xdb, 0x2f, 0xdf, 0x93, 0x63, 0xea, 0x80, 0x91, 0x33, 0x71, 0x1a, 0x45, 0x09, 0xfa, 0xfe, 0xdd, 0x4a, 0x80, 0x20, 0xea, 0xfd, 0x02, 0x14, 0x67, 0x71, 0x32, 0xb1, 0xc6, 0x04, 0x92, 0x7b, 0xff, 0x5f, 0xd5, 0xbd, 0xb5, 0x7a, 0xb8, 0xf0, 0x4d, 0x00, 0x97, 0x47, 0x6c, 0x4b, 0x1c, 0xb5, 0x5b, 0x2e, 0xd0, 0xb1, 0x96, 0x07, 0xbd, 0x95, 0xa7, 0xf7, 0x1b, 0xd5, 0x9d, 0x93, 0x70, 0xe4, 0xab, 0xfa, 0x72, 0xaa, 0x38, 0x3a, 0xcd, 0xb3, 0x0b, 0x96, 0x68, 0x38, 0x8f, 0x6f, 0x92, 0x44, 0x32, 0x5e, 0x9a, 0x6d, 0x6f, 0x77, 0x2c, 0x54, 0x7a, 0x8d, 0x9b, 0x36, 0xa4, 0x86, 0xf6, 0x83, 0x2c, 0x54, 0x7b, 0x27, 0x29, 0xce, 0x65, 0x64, 0xb5, 0x32, 0xb2, 0x32, 0x17, 0x0f, 0xb2, 0xb4, 0x52, 0xe3, 0xc7, 0xce, 0xc8, 0x1b, 0xd3, 0x7d, 0x0b, 0x5d, 0xd4, 0x4f, 0xa0, 0x5e, 0xbe, 0x35, 0xf0, 0x3c, 0x5e, 0xf4, 0x61, 0x43, 0xad, 0x2d, 0xeb, 0xb8, 0xea, 0x0e, 0x85, 0x6c, 0xdb, 0xdf, 0x43, 0xc9, 0x73, 0x98, 0x81, 0x9f, 0x7e, 0x49, 0x30, 0x36, 0x32, 0xd9, 0x6a, 0xc7, 0xf8, 0xce, 0x3b, 0xe4, 0x21, 0x73, 0x07, 0xca, 0x28, 0x50, 0x4e, 0xaf, 0x1d, 0xf7, 0xf2, 0xa1, 0x62, 0x24, 0x0b, 0x3d, 0xe7, 0xd8, 0x5b, 0xab, 0xf5, 0xb6, 0xcf, 0xe6, 0x07, 0xda, 0xa4, 0x39, 0xe9, 0x77, 0x3d, 0x59, 0x6a, 0x81, 0xc6, 0x06, 0x24, 0xae, 0x14, 0x60, 0xa9, 0xe4, 0x1a, 0x28, 0x43, 0xf8, 0xbd, 0xbc, 0x5b, 0x7a, 0x18, 0x1a, 0x4c, 0x59, 0x98, 0x2c, 0xc2, 0xcb, 0x58, 0xba, 0x5c, 0x94, 0x47, 0xa4, 0xb6, 0xe5, 0x8c, 0x75, 0xa0, 0xb4, 0x1a, 0x6d, 0x2a, 0x13, 0x65, 0xf6, 0xb4, 0x4e, 0x92, 0x71, 0xaf, 0x42, 0x3a, 0x38, 0x88, 0xf3, 0xa1, 0x61, 0x3d, 0xf6, 0xe8, 0x4a, 0x7e, 0xf0, 0x5b, 0xe5, 0x0d, 0x01, 0x8a, 0x51, 0x7b, 0xb7, 0xb3, 0x12, 0xa0, 0x4d, 0x18, 0xf6, 0x98, 0x0b, 0x28, 0x1a, 0x58, 0x2b, 0x2d, 0x78, 0xf3, 0xfb, 0xd8, 0x92, 0x05, 0x86, 0x21, 0x71, 0xdd, 0xa8, 0x98, 0xea, 0x90, 0x6a, 0x0d, 0x6b, 0x08, 0xd3, 0x3e, 0x9b, 0x84, 0x3e, 0x75, 0xf5, 0x93, 0xe5, 0x24, 0x79, 0x6e, 0x32, 0x1b, 0x4f, 0xe6, 0xf3, 0x65, 0x9f, 0xb0, 0x01, 0xa8, 0x95, 0xd7, 0x03, 0x9b, 0x62, 0xd5, 0x4c, 0x3a, 0x99, 0x9f, 0xea, 0x79, 0x8a, 0x42, 0x45, 0xf2, 0x9f, 0x6e, 0x99, 0x2d, 0xe1, 0xb0, 0xcb, 0x88, 0x2c, 0x1c, 0x5a, 0xdf, 0xe5, 0xfd, 0xaf, 0xb5, 0x7c, 0xc6, 0xee, 0x52, 0x37, 0x1a, 0x76, 0xf6, 0x5f, 0x63, 0x2c, 0x6d, 0x0a, 0x76, 0x99, 0x27, 0x49, 0x26, 0x8f, 0x0a, 0x59, 0xb4, 0x95, 0x1a, 0xc1, 0xaf, 0x7d, 0x1c, 0xbe, 0x3e, 0x48, 0x41, 0x61, 0xb5, 0x94, 0x0b, 0xe0, 0x65, 0x95, 0x2c, 0xce, 0xf3, 0x41, 0xd8, 0x8f, 0xc2, 0x5a, 0xa9, 0x06, 0xff, 0x11, 0xc6, 0x45, 0x95, 0xcc, 0x56, 0xed, 0xb0, 0x29, 0x39, 0x48, 0xee, 0x18, 0x98, 0x04, 0x1f, 0x26, 0xff, 0xb9, 0xbb, 0x03, 0xac, 0xd7, 0x12, 0x07, 0x15, 0x6e, 0xbc, 0x07, 0x2b, 0x1e, 0x0f, 0x54, 0xe7, 0xe6, 0x8e, 0x15, 0x3f, 0xa8, 0x03, 0x6f, 0xaa, 0xe2, 0xbb, 0x0d, 0x19, 0x04, 0x55, 0x2a, 0x96, 0xce, 0x16, 0x7c, 0x00, 0xe2, 0xa5, 0x12, 0x3f, 0x76, 0xfb, 0x76, 0x2b, 0x4a, 0x2e, 0x66, 0xe8, 0x1c, 0x35, 0xcd, 0x66, 0x7a, 0x44, 0x2b, 0x36, 0xa0, 0x9c, 0x2a, 0x29, 0x81, 0x2e, 0x3d, 0x7e, 0x99, 0xd8, 0x50, 0x1e, 0x42, 0x59, 0x69, 0x0f, 0xaf, 0xa1, 0x38, 0xae, 0xf0, 0x89, 0x02, 0xe3, 0xae, 0xe8, 0xf5, 0x7c, 0xdc, 0xb8, 0xf3, 0x9b, 0x20, 0x89, 0x41, 0x49, 0xeb, 0x8e, 0x72, 0xf9, 0x19, 0x88, 0x0e, 0xfa, 0x74, 0x6c, 0x46, 0x6c, 0x01, 0xd6, 0x4a, 0x04, 0xf1, 0xf3, 0x37, 0x9c, 0x8e, 0xb9, 0x5a, 0x02, 0xc5, 0xe5, 0x18, 0x01, 0x04, 0xbf, 0x62, 0x22, 0xfb, 0xdf, 0x81, 0x10, 0xac, 0x0e, 0xc3, 0x16, 0xf8, 0x9d, 0xc2, 0x24, 0xff, 0xa6, 0x97, 0x3f, 0x37, 0xda, 0x97, 0xdb, 0x05, 0xd9, 0x4e, 0x50, 0x3d, 0x08, 0xdd, 0x31, 0x8c, 0x30, 0x18, 0x6b, 0xda, 0x26, 0x86, 0xf4, 0x6f, 0x5b, 0x18, 0x51, 0xce, 0x79, 0x22, 0x17, 0xf6, 0x3e, 0x03, 0xc6, 0xea, 0xd5, 0x24, 0x13, 0x65, 0xe4, 0x1a, 0x88, 0x54, 0xe6, 0x33, 0xa4, 0x3c, 0x26, 0x71, 0xc3, 0x65, 0x0f, 0x62, 0x87, 0x4e, 0xd7, 0x63, 0x95, 0xfc, 0x0c, 0x62, 0x78, 0x30, 0x29, 0x0b, 0xec, 0xed, 0x03, 0x44, 0x7f, 0xa9, 0x99, 0xfb, 0x93, 0xbd, 0x75, 0xb0, 0xde, 0xcd, 0x96, 0x3e, 0x30, 0x76, 0xaa, 0xb4, 0x89, 0xd0, 0x41, 0xb4, 0x4e, 0x9f, 0x4f, 0x4c, 0x10, 0xad, 0x80, 0xfc, 0x34, 0xb7, 0xf3, 0xfb, 0x89, 0x66, 0x5e, 0x39, 0x89, 0x73, 0x77, 0x50, 0xd1, 0xe5, 0x31, 0x7b, 0x07, 0x76, 0x5d, 0x00, 0xb7, 0x51, 0x85, 0xc2, 0x53, 0xc2, 0x6d, 0xfa, 0x8f, 0xac, 0xb0, 0x04, 0x0b, 0x65, 0x6f, 0x44, 0x9f, 0x35, 0xb3, 0xe8, 0x4a, 0x49, 0x49, 0xaf, 0xf4, 0x14, 0xf3, 0xf5, 0x59, 0x35, 0x7a, 0x91, 0x3c, 0x01, 0x68, 0xe8, 0xe6, 0xd7, 0x93, 0x0a, 0x2e, 0x9c, 0x6b, 0x5c, 0x9a, 0x78, 0x03, 0x27, 0x0d, 0x32, 0xdc, 0x85, 0xef, 0x4d, 0xee, 0x3b, 0xd7, 0xe9, 0x0d, 0xfc, 0xc5, 0x16, 0x90, 0x13, 0x8b, 0x75, 0x2a, 0x9b, 0xc2, 0xa8, 0xcb, 0x37, 0xa9, 0xbe, 0x25, 0xdc, 0xfa, 0x16, 0xc4, 0x09, 0x51, 0x9d, 0x53, 0xfb, 0x57, 0x1c, 0xac, 0x6b, 0xdb, 0x0a, 0x19, 0x69, 0xb6, 0xa2, 0xf9, 0xfa, 0x95, 0x1d, 0xae, 0x00, 0x14, 0x01, 0xef, 0x30, 0x72, 0xd3, 0xc2, 0xba, 0xab, 0x1d, 0xaa, 0x64, 0x87, 0x27, 0x5d, 0x51, 0x50, 0x63, 0x96, 0x52, 0xda, 0xf7, 0xcf, 0xbd, 0xaf, 0x62, 0xf6, 0xe4, 0xf5, 0xba, 0xa4, 0xa2, 0x39, 0x09, 0x48, 0x47, 0x13, 0x81, 0x02, 0xdc, 0xef, 0x4f, 0x9c, 0xe8, 0x4a, 0xef, 0x72, 0xac, 0x7e, 0xbd, 0x6e, 0x8d, 0x24, 0xe8, 0xa5, 0xd3, 0x32, 0x7f, 0xb8, 0xf3, 0x43, 0xf1, 0x4c, 0xe0, 0xd9, 0xcb, 0x66, 0xcf, 0x29, 0x5e, 0x13, 0x48, 0x3c, 0x70, 0x34, 0xec, 0x8a, 0x7c, 0x74, 0x39, 0xa9, 0x91, 0x8c, 0xc1, 0xeb, 0x1a, 0xdd, 0x16, 0xc4, 0x16, 0xe3, 0x26, 0x17, 0x2b, 0x3e, 0x6a, 0x6f, 0x77, 0x85, 0x88, 0x8b, 0x98, 0x9a, 0x9d, 0xa7, 0xad, 0xae, 0xb4, 0xc0, 0xd2, 0xfe, 0x32, 0x3b, 0x54, 0x56, 0x5f, 0x88, 0xa4, 0xd1, 0x0b, 0x12, 0x20, 0x28, 0x33, 0x35, 0x55, 0x5c, 0x7d, 0x83, 0xa5, 0xb2, 0xb4, 0xbd, 0xbe, 0xf2, 0x18, 0x1d, 0x3f, 0x43, 0x4d, 0x50, 0x55, 0x57, 0x7e, 0x86, 0x8c, 0x9d, 0xb8, 0xcb, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x1b, 0x2b, 0x3a, }, .sig_len = 2420, }, { .name = "ML-DSA 44 deterministic, prehash SHA512", .parameter_set = CKP_ML_DSA_44, .mech = { CKM_HASH_ML_DSA_SHA512, &kat1_param, sizeof(kat1_param) }, .priv = { 0x8e, 0x35, 0x94, 0xb6, 0xc4, 0x7f, 0xd8, 0x62, 0x55, 0x82, 0xa9, 0x07, 0x1c, 0xee, 0x0b, 0x14, 0xec, 0x7b, 0x88, 0xe4, 0xec, 0x3b, 0x91, 0x95, 0x60, 0x71, 0xd2, 0x71, 0xa1, 0x23, 0xd4, 0xf1, 0xdb, 0xf1, 0x86, 0xe5, 0x60, 0x87, 0xfb, 0x96, 0xa2, 0x70, 0x6b, 0x7c, 0x1c, 0x0c, 0xb1, 0x4b, 0xbb, 0x1b, 0xd3, 0x70, 0xb1, 0xc6, 0x14, 0x06, 0x0b, 0x87, 0x1f, 0x83, 0x9d, 0x67, 0x07, 0x29, 0xd1, 0x56, 0xe6, 0x4e, 0xc9, 0xeb, 0x03, 0x65, 0x62, 0x41, 0x0b, 0x91, 0xfb, 0x0c, 0x53, 0x56, 0x18, 0x60, 0x6c, 0x0e, 0x8b, 0x7b, 0xa6, 0xd7, 0x96, 0x86, 0x63, 0xf0, 0xc0, 0x5a, 0x27, 0x8c, 0x92, 0x8f, 0x37, 0x11, 0x3d, 0xc5, 0xce, 0xc3, 0xa0, 0xb4, 0x64, 0xe6, 0x95, 0x53, 0xc8, 0xf6, 0x05, 0xf0, 0xff, 0x4b, 0xd8, 0xaa, 0xaa, 0x24, 0xf7, 0x2f, 0xd1, 0x55, 0x6b, 0x3a, 0x38, 0x9e, 0x93, 0x04, 0x6e, 0x43, 0xb0, 0x09, 0x1c, 0x47, 0x44, 0x00, 0x37, 0x22, 0x41, 0xc8, 0x69, 0x88, 0xc2, 0x84, 0xdc, 0xa4, 0x91, 0x04, 0x42, 0x4d, 0x0c, 0x38, 0x45, 0x50, 0x24, 0x4d, 0x08, 0x42, 0x6a, 0x40, 0xc4, 0x68, 0x23, 0x42, 0x4c, 0x41, 0x06, 0x89, 0x83, 0x02, 0x40, 0x84, 0xc4, 0x8d, 0x21, 0x97, 0x90, 0x58, 0x94, 0x85, 0xd8, 0x88, 0x01, 0xca, 0x46, 0x92, 0xd1, 0xb2, 0x4d, 0x94, 0xc8, 0x28, 0xe4, 0x36, 0x65, 0xe4, 0x46, 0x32, 0xdb, 0x00, 0x4c, 0x92, 0x10, 0x0c, 0x43, 0x08, 0x29, 0x19, 0x15, 0x6d, 0xc9, 0x80, 0x69, 0x01, 0x01, 0x45, 0x13, 0xa7, 0x61, 0x23, 0x46, 0x20, 0x02, 0xb6, 0x6d, 0x04, 0xc3, 0x89, 0x9c, 0x86, 0x64, 0x0c, 0x45, 0x62, 0x94, 0x08, 0x28, 0x1c, 0x18, 0x64, 0xd3, 0x46, 0x0a, 0x04, 0x27, 0x29, 0xd8, 0x22, 0x22, 0xe4, 0x06, 0x05, 0x88, 0xc8, 0x88, 0x03, 0xb8, 0x2c, 0x98, 0xb0, 0x4c, 0x09, 0xb4, 0x50, 0x90, 0x28, 0x64, 0x19, 0xb2, 0x4d, 0x8a, 0x20, 0x61, 0x22, 0x41, 0x80, 0x13, 0x15, 0x69, 0x41, 0x28, 0x04, 0x80, 0x30, 0x29, 0x1a, 0x48, 0x60, 0x18, 0xc1, 0x8d, 0x20, 0x82, 0x24, 0xd3, 0x44, 0x68, 0x94, 0x02, 0x41, 0x1c, 0xc5, 0x24, 0x21, 0x46, 0x72, 0xda, 0x48, 0x6d, 0x1b, 0x98, 0x10, 0x5c, 0x40, 0x4e, 0x92, 0x92, 0x31, 0xa2, 0xc6, 0x60, 0x64, 0x82, 0x29, 0x12, 0x15, 0x4a, 0x02, 0x00, 0x42, 0x50, 0x20, 0x90, 0x09, 0x19, 0x09, 0x53, 0xa6, 0x80, 0x82, 0xa0, 0x2c, 0x10, 0x21, 0x06, 0x93, 0x10, 0x46, 0x5b, 0xc8, 0x68, 0x01, 0x19, 0x49, 0x18, 0x39, 0x29, 0x14, 0xc0, 0x25, 0x60, 0x44, 0x44, 0x48, 0x44, 0x10, 0x5c, 0x06, 0x0d, 0x5b, 0xc0, 0x88, 0x9a, 0x88, 0x21, 0x04, 0x19, 0x90, 0x21, 0xc8, 0x64, 0x10, 0x03, 0x41, 0xc9, 0x22, 0x21, 0x18, 0x46, 0x2d, 0x4b, 0x46, 0x02, 0x21, 0x33, 0x0d, 0x8c, 0x80, 0x05, 0xca, 0x16, 0x65, 0x04, 0x15, 0x82, 0x23, 0xc6, 0x71, 0x02, 0x03, 0x68, 0x92, 0x00, 0x91, 0x0c, 0xb2, 0x8c, 0x52, 0x44, 0x29, 0x19, 0x07, 0x11, 0x20, 0x49, 0x09, 0x90, 0x08, 0x90, 0x5c, 0x22, 0x02, 0xc2, 0xa0, 0x88, 0xd8, 0xc2, 0x48, 0x9c, 0x84, 0x4c, 0x94, 0xb0, 0x04, 0xa0, 0x00, 0x71, 0x8a, 0xa4, 0x51, 0xcc, 0x40, 0x0e, 0x04, 0x94, 0x10, 0x10, 0x22, 0x40, 0x58, 0x00, 0x2a, 0x0a, 0x20, 0x84, 0x8a, 0x86, 0x25, 0x90, 0xc8, 0x44, 0x82, 0x14, 0x2d, 0x02, 0x01, 0x4a, 0x0a, 0x17, 0x92, 0x01, 0x27, 0x41, 0x91, 0x20, 0x52, 0xa1, 0x08, 0x91, 0x8b, 0x44, 0x92, 0x20, 0x13, 0x4a, 0x61, 0xa4, 0x28, 0xd1, 0xc8, 0x05, 0x01, 0xc3, 0x41, 0x94, 0x20, 0x31, 0x60, 0xb0, 0x51, 0x1c, 0x06, 0x24, 0x9a, 0xa6, 0x11, 0xc1, 0xc6, 0x01, 0x88, 0x28, 0x4e, 0xd0, 0x26, 0x4a, 0x23, 0x95, 0x2d, 0x18, 0x22, 0x41, 0xa2, 0x32, 0x09, 0x8b, 0x06, 0x08, 0x13, 0x31, 0x30, 0x0c, 0x97, 0x91, 0xd2, 0x46, 0x05, 0x64, 0x02, 0x21, 0x0a, 0x87, 0x44, 0xd3, 0x48, 0x00, 0x64, 0xa4, 0x71, 0x01, 0x18, 0x72, 0x1a, 0xc5, 0x2d, 0x43, 0x46, 0x80, 0xe2, 0xa6, 0x81, 0x0a, 0xa2, 0x64, 0x02, 0xa3, 0x65, 0x9b, 0x32, 0x25, 0x02, 0xb3, 0x08, 0x1c, 0xb9, 0x8d, 0x21, 0x90, 0x81, 0x82, 0xb2, 0x71, 0xcb, 0x32, 0x0d, 0x42, 0x40, 0x24, 0xdc, 0x02, 0x2d, 0xd0, 0x16, 0x85, 0xdc, 0xb4, 0x48, 0x08, 0x12, 0x6d, 0x23, 0xc4, 0x71, 0xd4, 0x18, 0x2c, 0x60, 0x84, 0x30, 0xc2, 0x82, 0x71, 0x82, 0x26, 0x64, 0x84, 0xa6, 0x44, 0x12, 0xc3, 0x0c, 0xd4, 0x34, 0x0c, 0x0b, 0x90, 0x48, 0x0b, 0x00, 0x51, 0xe0, 0xa4, 0x4d, 0x13, 0x04, 0x81, 0x58, 0x82, 0x28, 0x01, 0x37, 0x8e, 0x19, 0x95, 0x71, 0x12, 0x38, 0x28, 0x20, 0x95, 0x51, 0x02, 0x45, 0x6c, 0xd4, 0xc6, 0x60, 0x01, 0x00, 0x32, 0x53, 0x30, 0x40, 0xdb, 0x80, 0x64, 0x5b, 0x12, 0x70, 0x02, 0x24, 0x6a, 0x0a, 0x12, 0x32, 0x8c, 0x02, 0x6a, 0x08, 0x45, 0x41, 0x50, 0x94, 0x45, 0x94, 0x30, 0x02, 0xa1, 0xc2, 0x71, 0x1b, 0x18, 0x12, 0x1a, 0x35, 0x52, 0x10, 0x04, 0x2a, 0x01, 0x40, 0x05, 0x1b, 0x03, 0x89, 0x49, 0x42, 0x0d, 0xe1, 0xb0, 0x49, 0xc3, 0xb6, 0x71, 0x58, 0x34, 0x69, 0x01, 0x20, 0x04, 0x80, 0x16, 0x72, 0x4c, 0x80, 0x85, 0x82, 0x80, 0x08, 0x9b, 0x16, 0x20, 0x19, 0x24, 0x25, 0xda, 0xa6, 0x0c, 0xc2, 0x26, 0x09, 0xa1, 0x44, 0x04, 0x98, 0xc4, 0x8c, 0x09, 0xa2, 0x01, 0x13, 0x39, 0x11, 0x5a, 0x06, 0x82, 0xa3, 0x16, 0x0a, 0xc4, 0x02, 0x44, 0x12, 0x80, 0x68, 0x9a, 0x10, 0x20, 0xe0, 0x94, 0x25, 0x03, 0x22, 0x4d, 0x04, 0x24, 0x8e, 0x12, 0xb2, 0x69, 0x9b, 0x44, 0x8e, 0x89, 0xc0, 0x31, 0x21, 0x14, 0x42, 0x10, 0x31, 0x05, 0x08, 0x99, 0x68, 0xc2, 0x44, 0x4c, 0x12, 0xb1, 0x08, 0x12, 0xc3, 0x4c, 0x24, 0x04, 0x40, 0x89, 0x38, 0x41, 0x43, 0xc0, 0x84, 0x23, 0xc6, 0x89, 0x03, 0xb5, 0x6c, 0x01, 0x80, 0x48, 0xc4, 0x06, 0x42, 0x1b, 0x04, 0x46, 0x89, 0x36, 0x8a, 0x9a, 0x48, 0x6a, 0xd3, 0x28, 0x10, 0x23, 0x44, 0x89, 0x0b, 0x37, 0x65, 0x21, 0xc9, 0x41, 0x48, 0xa8, 0x2d, 0x88, 0xb4, 0x2c, 0x44, 0x44, 0x02, 0x03, 0x09, 0x12, 0xc8, 0x30, 0x65, 0x13, 0x08, 0x46, 0x0b, 0x12, 0x08, 0x50, 0x02, 0x0c, 0x0c, 0x07, 0x11, 0xda, 0xc2, 0x90, 0x0b, 0x87, 0x89, 0xc8, 0x46, 0x41, 0x60, 0xc8, 0x71, 0xe3, 0xf3, 0x6e, 0xf9, 0x45, 0x2f, 0x87, 0xfc, 0x17, 0x6f, 0x11, 0xbd, 0xc5, 0xaf, 0x9b, 0x3f, 0x97, 0x60, 0x31, 0xea, 0xb2, 0x55, 0x3d, 0xf2, 0xc2, 0xe9, 0x74, 0x8a, 0xb9, 0x0b, 0x7a, 0xfc, 0xc1, 0xd8, 0x87, 0x64, 0x55, 0xc0, 0x7a, 0xbd, 0x21, 0x12, 0xe5, 0x75, 0x8b, 0x88, 0x58, 0xb6, 0x77, 0x8c, 0x5b, 0xa3, 0xa3, 0x56, 0x95, 0x32, 0x12, 0xb9, 0xfa, 0xa7, 0x6b, 0xfa, 0x25, 0xb9, 0xf7, 0xda, 0x9f, 0x8f, 0x99, 0x29, 0xf4, 0xc3, 0xe8, 0x06, 0x6a, 0x98, 0xd8, 0x14, 0xfa, 0x63, 0x40, 0x4c, 0x94, 0xec, 0x60, 0xf9, 0xe4, 0x1f, 0xa2, 0x20, 0x5e, 0x0c, 0x06, 0x56, 0xd6, 0x9c, 0x71, 0x20, 0xd2, 0x28, 0x2f, 0x71, 0x21, 0x92, 0x90, 0x5e, 0xe7, 0xc6, 0x13, 0x2f, 0xad, 0xef, 0x94, 0xfa, 0x0d, 0x8c, 0x0f, 0xb6, 0x04, 0xc3, 0x89, 0xd5, 0xb3, 0x96, 0x73, 0x68, 0x90, 0x1d, 0xfb, 0x2e, 0xdb, 0x0c, 0x42, 0x0b, 0xca, 0xd6, 0xb1, 0x4b, 0xba, 0xd7, 0x7a, 0x57, 0x96, 0x29, 0xe9, 0x21, 0x7b, 0xf9, 0x6e, 0xb3, 0x99, 0x59, 0x24, 0x95, 0xe3, 0x8e, 0x4e, 0x41, 0x47, 0xab, 0x30, 0x53, 0x00, 0x3d, 0xf0, 0x46, 0x7c, 0x0b, 0xee, 0x5e, 0xcb, 0x13, 0x63, 0xb3, 0x1b, 0xed, 0x3f, 0x2a, 0xfd, 0x87, 0x0a, 0x19, 0x0d, 0xea, 0x48, 0x22, 0xbc, 0xe0, 0x55, 0x62, 0x67, 0xf0, 0xa1, 0x4c, 0x57, 0x6a, 0xa9, 0x1a, 0x71, 0xd1, 0xd9, 0x9e, 0xad, 0xde, 0xc3, 0xaf, 0x91, 0x02, 0xa1, 0xb0, 0x4e, 0x8d, 0x8c, 0x7b, 0xb3, 0xb2, 0x7a, 0xbb, 0xe4, 0x51, 0x46, 0x51, 0x57, 0x2f, 0xda, 0x56, 0x98, 0xb6, 0xce, 0x2d, 0x84, 0x09, 0x06, 0x9a, 0xfc, 0x37, 0xec, 0x0a, 0xe0, 0x40, 0x00, 0x6a, 0xc0, 0xa3, 0x72, 0x50, 0x30, 0xcb, 0x43, 0x23, 0x8e, 0x04, 0x2e, 0x94, 0x84, 0xba, 0xdf, 0x65, 0xd3, 0xad, 0x82, 0xa4, 0x94, 0x4c, 0xf7, 0xd5, 0xdc, 0xf4, 0x36, 0x20, 0xa7, 0x94, 0xb7, 0x3d, 0x73, 0x0e, 0x7c, 0xc3, 0x9c, 0x00, 0x1e, 0xdd, 0xaf, 0x54, 0xd3, 0x66, 0x6c, 0xb2, 0x7c, 0x50, 0xfa, 0x17, 0xe2, 0xd6, 0xaa, 0xc8, 0xa1, 0x57, 0x85, 0x21, 0x64, 0x2c, 0xab, 0x79, 0x29, 0x81, 0xe1, 0x9f, 0xaf, 0x57, 0x03, 0x90, 0x72, 0x74, 0x07, 0xe6, 0xe5, 0xd3, 0x38, 0xec, 0xeb, 0x51, 0xcf, 0x7e, 0xe8, 0x69, 0x52, 0xfc, 0x25, 0x6a, 0x1e, 0xd4, 0xb4, 0x2c, 0x57, 0xfc, 0xc0, 0x0d, 0xa3, 0x20, 0x5b, 0xaf, 0x2b, 0xb5, 0x44, 0x5d, 0x85, 0xa4, 0xc6, 0x44, 0x9c, 0xb2, 0x27, 0x4d, 0xd8, 0x70, 0x82, 0xac, 0xed, 0x08, 0x66, 0xe0, 0x79, 0x0e, 0x5b, 0x92, 0xe0, 0x43, 0xde, 0x3b, 0x8a, 0x4e, 0x99, 0x02, 0xc0, 0x04, 0x42, 0x15, 0x32, 0xaa, 0x61, 0xfd, 0xb4, 0x5a, 0xc9, 0xa6, 0x33, 0x13, 0x86, 0x63, 0x1f, 0x48, 0x0c, 0xef, 0x47, 0xa5, 0xf4, 0x2e, 0x14, 0xb9, 0xa1, 0x85, 0x46, 0xeb, 0x3d, 0x63, 0xe0, 0x71, 0xf4, 0x24, 0x15, 0xf0, 0x19, 0x1f, 0x5f, 0x28, 0xba, 0xf4, 0x4c, 0xd4, 0xd4, 0xff, 0x6c, 0x54, 0xac, 0x50, 0x44, 0xa2, 0x44, 0x92, 0xfc, 0x89, 0x13, 0xf2, 0x5f, 0x6e, 0xb5, 0xfa, 0x9b, 0xbf, 0x6c, 0xf2, 0x9f, 0x6b, 0xea, 0xf5, 0xc4, 0xaa, 0xda, 0x96, 0x7a, 0x76, 0xf2, 0x8a, 0x01, 0xbf, 0x04, 0x5b, 0xcc, 0x98, 0x9c, 0x86, 0xb6, 0xfc, 0x08, 0x09, 0xcc, 0x56, 0x7c, 0x5b, 0x15, 0xd5, 0x1a, 0x74, 0x03, 0xfb, 0x50, 0xbb, 0x88, 0x08, 0x1e, 0x11, 0x1b, 0x07, 0xa0, 0x37, 0x58, 0x89, 0xcc, 0xdc, 0x3f, 0x80, 0xc7, 0x68, 0xb3, 0x10, 0x2f, 0x55, 0xe9, 0x43, 0x87, 0xec, 0xaf, 0x47, 0xf3, 0x14, 0x3b, 0xdb, 0x63, 0x78, 0x51, 0x91, 0x91, 0x0d, 0xcb, 0x1c, 0x88, 0xa9, 0x84, 0xf7, 0xcd, 0x33, 0xc8, 0x2b, 0xc9, 0xf0, 0x13, 0x9e, 0x12, 0xbc, 0xa9, 0xaa, 0x1c, 0x03, 0x53, 0x66, 0x18, 0x9b, 0x8b, 0x96, 0x1d, 0x47, 0x25, 0x64, 0x8c, 0x80, 0x08, 0xcb, 0x1a, 0x5b, 0xe6, 0xed, 0x37, 0x5d, 0x8d, 0x44, 0x09, 0xa6, 0x10, 0xec, 0x8b, 0x34, 0x06, 0x48, 0x04, 0xca, 0xc5, 0xdf, 0x72, 0xbf, 0xf6, 0xb1, 0xb1, 0x73, 0xea, 0xd3, 0x54, 0xe2, 0xf1, 0x64, 0xfd, 0x17, 0xb0, 0x5a, 0x0b, 0xd0, 0x90, 0xd3, 0x9e, 0x46, 0x2e, 0x89, 0x0d, 0xcd, 0x81, 0x91, 0x72, 0x89, 0xd4, 0xfc, 0x3e, 0x28, 0xfd, 0xe0, 0x96, 0xd7, 0x13, 0x5c, 0xa7, 0xe7, 0xa5, 0x19, 0x10, 0x39, 0xd1, 0xa3, 0x9f, 0xb7, 0x5f, 0xd9, 0x51, 0x8b, 0xcf, 0x29, 0x25, 0x82, 0x4e, 0x39, 0x20, 0xd6, 0x3e, 0x44, 0xcd, 0xfa, 0x10, 0x7b, 0x8c, 0xa7, 0xfb, 0xa5, 0x50, 0x54, 0xc2, 0x21, 0x44, 0x33, 0xfb, 0xaf, 0x42, 0xc5, 0x61, 0xa2, 0x48, 0xfa, 0x38, 0x37, 0x9e, 0xba, 0xa2, 0x72, 0x5a, 0x0a, 0x12, 0x29, 0x5a, 0xb2, 0xd7, 0x54, 0xa2, 0x7f, 0xcc, 0xa0, 0x7a, 0x02, 0x06, 0x8c, 0x91, 0x76, 0x9a, 0xf3, 0x24, 0x72, 0x14, 0x74, 0x71, 0x2c, 0x7a, 0xd5, 0xf6, 0xc9, 0xd9, 0x4d, 0x60, 0x28, 0x95, 0xc5, 0x53, 0xdb, 0x93, 0x9e, 0xb2, 0xc8, 0x2e, 0x15, 0xf7, 0x29, 0x82, 0x2b, 0x30, 0x89, 0x92, 0x2b, 0xba, 0x3f, 0xfd, 0xe2, 0xd7, 0x0d, 0x3f, 0x5c, 0x83, 0x0c, 0x58, 0xdf, 0xbe, 0x8d, 0x1b, 0xfb, 0xb9, 0x35, 0x2d, 0xd3, 0x24, 0x2f, 0x87, 0x41, 0xba, 0x78, 0x74, 0x1b, 0x59, 0xcd, 0xa0, 0x4e, 0x38, 0x2e, 0xd3, 0x86, 0x10, 0xbc, 0xe9, 0x75, 0xa4, 0x09, 0xa3, 0xba, 0x46, 0xad, 0xc2, 0xa2, 0x12, 0x6f, 0x46, 0xb5, 0x12, 0x27, 0x53, 0xb8, 0x3d, 0x2c, 0x8f, 0xb8, 0x72, 0x07, 0x6e, 0x98, 0xea, 0x16, 0x08, 0xea, 0x70, 0x7a, 0xb4, 0xba, 0x13, 0x6e, 0x24, 0xb6, 0xfe, 0x5c, 0x89, 0x1d, 0xf1, 0x80, 0xeb, 0xd7, 0xff, 0x02, 0xcf, 0xa1, 0x50, 0x77, 0x28, 0xfb, 0x26, 0x19, 0x78, 0x63, 0xce, 0x28, 0x66, 0xb2, 0x72, 0x2d, 0x50, 0xc5, 0x80, 0x97, 0xd5, 0x44, 0x82, 0x53, 0xf6, 0x6e, 0x86, 0xd6, 0x3e, 0xc2, 0xe7, 0xe6, 0x44, 0x3a, 0xb0, 0xee, 0xc5, 0xfe, 0xbc, 0x4a, 0x64, 0x2b, 0x5b, 0xca, 0xe2, 0xa8, 0x7b, 0x28, 0xb3, 0x72, 0x84, 0x7c, 0xf0, 0x0b, 0x5a, 0x58, 0x47, 0x0b, 0xf6, 0xcd, 0x95, 0x4d, 0xfb, 0x90, 0x3a, 0x58, 0xf1, 0x0a, 0x39, 0x71, 0x13, 0x8d, 0xa7, 0xbf, 0x7c, 0xde, 0xaf, 0x9e, 0x85, 0x5c, 0x03, 0x5d, 0x8f, 0xb5, 0xd7, 0x28, 0xa1, 0xcd, 0x4f, 0x64, 0xfc, 0x88, 0x59, 0x00, 0xdc, 0xc1, 0x09, 0x38, 0x5b, 0x1e, 0xaf, 0x79, 0x34, 0x76, 0x36, 0xf1, 0x64, 0x87, 0x7a, 0xb8, 0x44, 0xc3, 0x71, 0x39, 0x09, 0x97, 0x2d, 0x16, 0x64, 0x07, 0xa4, 0x95, 0xd3, 0xa9, 0x5e, 0x3c, 0x13, 0x25, 0x75, 0xc3, 0x20, 0xd2, 0x7d, 0xae, 0x92, 0x60, 0x62, 0x66, 0x89, 0xa1, 0xa7, 0x89, 0x0a, 0x71, 0xa4, 0x31, 0x1e, 0x0f, 0xdd, 0xd3, 0x1d, 0xd2, 0x18, 0xe1, 0xff, 0x15, 0x8a, 0xf1, 0xa4, 0x08, 0xd4, 0x48, 0xe9, 0x87, 0x00, 0xc7, 0xb5, 0xef, 0xf4, 0x9e, 0x24, 0x98, 0xc1, 0x0c, 0x7f, 0x66, 0x03, 0xd2, 0xab, 0xa8, 0xd6, 0x50, 0x13, 0xdd, 0x52, 0x66, 0x7b, 0x98, 0x27, 0x30, 0xed, 0x48, 0xa4, 0x58, 0x78, 0x77, 0xb2, 0x3b, 0x26, 0xf7, 0x07, 0x68, 0xdc, 0xf6, 0xe9, 0x1a, 0x40, 0x91, 0xa7, 0xcc, 0x0b, 0xbe, 0x16, 0xd1, 0x2a, 0x6f, 0x5f, 0x07, 0xee, 0xcd, 0xf2, 0x34, 0xb2, 0x53, 0xf2, 0xc3, 0x36, 0x50, 0x4d, 0x39, 0xe4, 0x4a, 0xa3, 0x2f, 0x2b, 0x4c, 0xde, 0x0c, 0xed, 0x97, 0x15, 0x62, 0x17, 0x4b, 0x61, 0x28, 0xd5, 0xe3, 0x25, 0xe0, 0x21, 0xaf, 0x68, 0x8d, 0x21, 0xff, 0xe8, 0x1b, 0x5f, 0x58, 0xb4, 0x15, 0x78, 0x00, 0xc8, 0x80, 0xd5, 0xa0, 0xd2, 0x69, 0xbe, 0xbb, 0x19, 0x13, 0x8d, 0x7c, 0x99, 0x48, 0x6a, 0x91, 0x59, 0x77, 0xcb, 0xd4, 0xe7, 0xc1, 0x47, 0xb0, 0xb4, 0x8b, 0xc5, 0xe7, 0x46, 0x59, 0xcd, 0x6b, 0x77, 0xf2, 0x49, 0xc1, 0x61, 0xdc, 0x52, 0x7c, 0xc1, 0x81, 0xd7, 0x67, 0x64, 0xf3, 0x12, 0x33, 0x0b, 0x34, 0xca, 0xac, 0x33, 0x30, 0x12, 0x62, 0x10, 0x67, 0x85, 0x12, 0xa6, 0x6a, 0xd3, 0x97, 0x4d, 0x33, 0x2e, 0xc0, 0x3f, 0xb0, 0x36, 0x10, 0x04, 0xae, 0x3a, 0x5c, 0xa2, 0xb8, 0xf0, 0xb0, 0xb6, 0x43, 0xff, 0x03, 0xc8, 0xaa, 0x0f, 0x44, 0x7a, 0x80, 0x2b, 0x93, 0x7b, 0xab, 0x5b, 0xa8, 0x00, 0xf5, 0xfd, 0x69, 0xb2, 0xeb, 0x0f, 0x70, 0x43, 0xa3, 0x95, 0x89, 0xc2, 0x56, 0x55, 0xe4, 0x17, 0xbd, 0x50, 0x61, 0xc8, 0xe9, 0xc8, 0xdc, 0x42, 0x8b, 0x07, 0x79, 0xb9, 0x02, 0x0e, 0x16, 0x05, 0x9b, 0xbb, 0x7a, 0x4f, 0x45, 0x1a, 0x4e, 0x4f, 0x07, 0x26, 0x21, 0x3b, 0x6a, 0xfb, 0x49, 0x19, 0xd3, 0x8d, 0x64, 0xa5, 0xcd, 0xd3, 0x67, 0x8a, 0x55, 0x45, 0x74, 0xb5, 0x34, 0x77, 0xd7, 0x7e, 0x15, 0xc5, 0x31, 0x16, 0x85, 0xae, 0x6e, 0x38, 0x16, 0x86, 0x4a, 0x16, 0xa7, 0x55, 0x16, 0xf8, 0x6a, 0x44, 0x22, 0x61, 0x0a, 0xbd, 0x46, 0x2d, 0x1e, 0x86, 0x87, 0xfb, 0x5b, 0x4b, 0xda, 0xa5, 0xaf, 0x79, 0xf4, 0xe7, 0xd6, 0x78, 0x32, 0x48, 0xd0, 0x24, 0x81, 0x6f, 0x93, 0x20, 0x66, 0x11, 0xba, 0x8c, 0x34, 0x50, 0xce, 0x5e, 0xdc, 0xa8, 0xd0, 0x57, 0x75, 0x01, 0xa8, 0xf3, 0x23, 0x6f, 0x57, 0xe1, 0x4e, 0x7b, 0x8a, 0xa2, 0x33, 0x97, 0xf2, 0x59, 0x89, 0x6e, 0xb7, 0x7a, 0x30, 0x82, 0xa7, 0x91, 0xfb, 0xdf, 0xe0, 0x57, 0x4d, 0x57, 0x81, 0x6e, 0x82, 0x78, 0x6b, 0x4d, 0x3e, 0x47, 0xf0, 0xa6, 0x55, 0x69, 0x7e, 0xad, 0xe2, 0xd9, 0x47, 0x0c, 0xa1, 0xd4, 0x3e, 0x38, 0x35, 0x4a, 0x38, 0x4e, 0xc0, 0x3f, 0x9f, 0x43, 0x83, 0xae, 0x6d, 0xfc, 0xfe, 0x30, 0x70, 0xa0, 0x2f, 0x66, 0x95, 0xce, 0x07, 0x4e, 0xb7, 0x3f, 0x85, 0x48, 0xce, 0x84, 0x46, 0xb0, 0xef, 0xc8, 0xa8, 0x30, 0x39, 0x0a, 0xfc, 0x01, 0xfa, 0xda, 0x35, 0x08, 0xac, 0x43, 0x17, 0xca, 0xd4, 0x80, 0xea, 0x1c, 0xb9, 0xba, 0xdf, 0xb1, 0xdc, 0xf0, 0xb7, 0x48, 0x2a, 0x43, 0xd5, 0xe9, 0xcd, 0xc5, 0x58, 0xcb, 0xdd, 0xac, 0x68, 0xbd, 0xc6, 0xd5, 0x72, 0x20, 0xd8, 0x12, 0xb5, 0xe4, 0x34, 0x7d, 0xca, 0x54, 0x2c, 0xbe, 0xb7, 0x7d, 0x54, 0x21, 0x8c, 0x08, 0xf8, 0x7d, 0x6e, 0xd3, 0x68, 0x0a, 0x76, 0xb2, 0x58, 0xe4, 0x30, 0x90, 0x0b, 0x85, 0x8f, 0xa5, 0x3a, 0x3b, 0xff, 0x5b, 0xec, 0x5e, 0x4a, 0x87, 0x8c, 0xe2, 0x34, 0xa0, 0x02, 0x9e, 0x27, 0xde, 0xe9, 0x26, 0x32, 0x3f, 0xa3, 0x24, 0xca, 0xd9, 0xe6, 0x15, 0xca, 0xa5, 0xa9, 0x8d, 0x75, 0x08, 0xbd, 0xbc, 0xd6, 0xd6, 0xc2, 0xe9, 0x38, 0x3d, 0x1a, 0x03, 0x13, 0x04, 0xb6, 0x82, 0xa6, 0x51, 0x4e, 0xc7, 0x64, 0x4f, 0x51, 0x2b, 0x28, 0x78, 0xa2, 0x95, 0xb2, 0x95, 0x80, 0xe6, 0x38, 0x48, 0x38, 0xd1, 0x8c, 0x99, 0x2e, 0xed, 0x1b, 0x79, 0x9f, 0x41, 0xf8, 0x24, 0xed, 0xb3, 0x43, 0x52, 0xa4, 0x5a, 0xd7, 0xc7, 0xb0, 0x10, 0x02, 0xd6, 0x7f, 0x51, 0xb4, 0x54, 0x48, 0xbe, 0x29, 0x85, 0xec, 0x71, 0x7f, 0xdd, 0xbc, 0x6e, 0x0f, 0x0a, 0xab, 0xc1, 0xd0, 0x3d, 0xbf, 0x46, 0x4e, 0x0c, 0x33, 0x3a, 0x27, 0x24, 0x89, 0xd5, 0xbb, 0xf9, 0xe9, 0xdc, 0x11, 0x6a, 0x64, 0x53, 0x52, 0x76, 0xf8, 0xe0, 0xe6, 0xbb, 0xbd, 0xad, 0xbd, 0x05, 0xcd, 0x98, 0xd8, 0xfd, 0x59, 0x28, 0x8c, 0xb9, 0xed, 0xa0, 0x27, 0xfb, 0x64, 0x46, 0x1b, 0x35, 0xea, 0x86, 0x6a, 0x66, 0x65, 0xc8, 0x6f, 0x87, 0xb6, 0x50, 0x01, 0xed, 0x3f, 0xfe, 0x2e, 0xa2, 0xa2, 0x34, 0x54, 0x98, 0x49, 0x87, 0xc8, 0x26, 0x45, 0x7b, 0xe5, 0xb1, 0xd6, 0xac, 0x85, 0xa5, 0xcb, 0x1f, 0x4f, 0xb4, 0xbb, 0x36, 0x1f, 0x31, 0xd5, 0x11, 0x75, 0xbf, 0x89, 0xc2, 0xf4, 0x34, 0xd3, 0x27, 0x3e, 0xc2, 0x0f, 0x12, 0xc5, 0x51, 0xe8, 0x20, 0x42, 0x06, 0xee, 0x46, 0x33, 0xd3, 0x5f, 0x27, 0x29, 0xc9, 0x8b, 0xfc, 0xe1, 0xa6, 0x8f, }, .priv_len = 2560, .pub = { 0x8e, 0x35, 0x94, 0xb6, 0xc4, 0x7f, 0xd8, 0x62, 0x55, 0x82, 0xa9, 0x07, 0x1c, 0xee, 0x0b, 0x14, 0xec, 0x7b, 0x88, 0xe4, 0xec, 0x3b, 0x91, 0x95, 0x60, 0x71, 0xd2, 0x71, 0xa1, 0x23, 0xd4, 0xf1, 0x80, 0x47, 0xae, 0xd3, 0x9b, 0x88, 0xdb, 0x69, 0xb6, 0xbc, 0x9c, 0x20, 0x10, 0xb1, 0x75, 0x2f, 0x1a, 0x7a, 0x11, 0x4d, 0x73, 0xfa, 0x31, 0x99, 0x24, 0x3a, 0x43, 0x0c, 0xcf, 0xc3, 0x96, 0xca, 0x49, 0x8c, 0x8e, 0xa5, 0x2f, 0xc3, 0xb5, 0xb6, 0x6a, 0xf5, 0x9b, 0x20, 0xb9, 0xf5, 0x96, 0x0b, 0x0d, 0x2b, 0x65, 0x63, 0x85, 0x26, 0x36, 0x7b, 0xb8, 0x9b, 0x92, 0x71, 0x90, 0x90, 0x46, 0x05, 0x1e, 0x2a, 0x35, 0x38, 0xcd, 0x80, 0x1b, 0x85, 0x8a, 0x82, 0x61, 0x09, 0xce, 0xb5, 0x73, 0xb7, 0x7b, 0x2e, 0xac, 0x03, 0x06, 0x04, 0xf1, 0xd8, 0x7b, 0x7e, 0x58, 0x17, 0x85, 0xb9, 0xc5, 0x03, 0x64, 0x31, 0xbe, 0x49, 0xb0, 0xf7, 0xd7, 0xbc, 0xba, 0xef, 0x67, 0x29, 0x9b, 0xfe, 0x06, 0x4a, 0x22, 0xf0, 0x7b, 0x63, 0x6b, 0xf9, 0x60, 0x5a, 0x3d, 0xe4, 0xc2, 0xdb, 0xe1, 0x6d, 0x0a, 0xa3, 0x19, 0x7b, 0x6f, 0xcc, 0x1c, 0x1b, 0x60, 0x4d, 0x43, 0xbd, 0x12, 0x8b, 0x98, 0x2d, 0x14, 0x56, 0x60, 0xdf, 0x59, 0xe1, 0xa3, 0xc1, 0xc2, 0xc3, 0x67, 0x94, 0xdd, 0x93, 0x8e, 0xd7, 0x78, 0x82, 0xa1, 0xd2, 0xef, 0x3f, 0xd7, 0xdb, 0xe8, 0xd6, 0x41, 0x1d, 0xcc, 0xb6, 0xd8, 0x2c, 0xa0, 0xf1, 0xd9, 0xc3, 0xd3, 0x30, 0xd3, 0xf5, 0x8d, 0xc1, 0xad, 0x93, 0x9a, 0x92, 0xb4, 0x10, 0x3c, 0x10, 0x82, 0x94, 0xe8, 0x2e, 0xe2, 0x4d, 0x53, 0x30, 0x86, 0x9b, 0x50, 0x9d, 0xfc, 0xbd, 0xa8, 0x1b, 0x56, 0xc8, 0x38, 0x91, 0x58, 0xed, 0x1b, 0x4b, 0x64, 0xfd, 0xbb, 0x21, 0x8e, 0x9b, 0xce, 0xfa, 0xeb, 0x75, 0x5b, 0xcd, 0x67, 0xa4, 0x3d, 0xbb, 0x33, 0xbf, 0x38, 0xff, 0x3c, 0xe0, 0xc6, 0x6d, 0x24, 0x8c, 0xad, 0xee, 0x3c, 0xba, 0x94, 0xe5, 0x4d, 0x9e, 0x98, 0xa5, 0x34, 0xdc, 0x4f, 0x35, 0xaa, 0x0d, 0x54, 0xbe, 0x38, 0x49, 0x70, 0xe5, 0xd5, 0x5b, 0x02, 0xd5, 0x3d, 0x6c, 0xd0, 0x2f, 0x6c, 0x76, 0xbc, 0xf4, 0x8d, 0x5f, 0x5a, 0xe3, 0x11, 0x46, 0xcb, 0xb1, 0xa0, 0x7a, 0x07, 0x82, 0xe5, 0x75, 0x3a, 0x44, 0xcd, 0xf4, 0x67, 0x38, 0xe8, 0x4e, 0xf9, 0xc6, 0x02, 0xfc, 0x9b, 0xb4, 0xcf, 0xcc, 0xa4, 0x54, 0x4a, 0xb6, 0xf9, 0x52, 0x3a, 0x84, 0x76, 0x57, 0x78, 0xb0, 0x93, 0xdd, 0x37, 0x70, 0x45, 0x99, 0x6c, 0xe4, 0xa0, 0x77, 0x2e, 0xfa, 0x5a, 0xd7, 0x83, 0x6d, 0x65, 0x9e, 0x10, 0x06, 0x3b, 0x8b, 0xbe, 0x33, 0x68, 0x3c, 0x29, 0x95, 0x0d, 0xbc, 0x04, 0x22, 0x4d, 0x49, 0x50, 0x6e, 0xe7, 0x5a, 0x98, 0x5b, 0xfd, 0x52, 0x52, 0xe7, 0x6a, 0x90, 0x36, 0x3c, 0x3c, 0x98, 0x02, 0xc3, 0x57, 0x19, 0x6f, 0xe0, 0x67, 0x6d, 0xdb, 0x1b, 0x48, 0x02, 0x74, 0x94, 0x02, 0xf2, 0x87, 0x46, 0x15, 0x61, 0xbd, 0x54, 0x3a, 0x15, 0xc3, 0x84, 0xe0, 0x92, 0xa9, 0x88, 0x3f, 0x43, 0x31, 0x24, 0xa3, 0x0f, 0x03, 0x0d, 0xca, 0x38, 0xd0, 0xfd, 0x20, 0x59, 0x5f, 0xc3, 0xda, 0x04, 0x7b, 0x9c, 0x7c, 0xad, 0x49, 0xac, 0x5a, 0xfc, 0xc3, 0x5e, 0xed, 0xba, 0x07, 0x88, 0xa9, 0x11, 0xac, 0x14, 0xc5, 0x4b, 0x6f, 0xb7, 0x56, 0x48, 0x66, 0x69, 0x2c, 0x12, 0xc1, 0x7d, 0xc9, 0x47, 0x10, 0xc1, 0xb5, 0x4f, 0x7d, 0xb7, 0x75, 0x61, 0x59, 0x55, 0x0c, 0x4f, 0x37, 0xfe, 0xf4, 0x44, 0x18, 0x45, 0x89, 0x19, 0x23, 0x9b, 0x5f, 0xe6, 0x17, 0x19, 0x77, 0xcf, 0x73, 0xf3, 0xd1, 0xd1, 0x12, 0xcf, 0x2f, 0x32, 0x35, 0xab, 0x91, 0xc6, 0xe2, 0xbd, 0x4b, 0x11, 0x77, 0x2b, 0x52, 0x2b, 0x6d, 0x3b, 0x31, 0x6f, 0x00, 0x07, 0x99, 0xb4, 0x3a, 0xff, 0xbe, 0x4b, 0x52, 0x0d, 0x4f, 0xa8, 0xda, 0x33, 0x4c, 0x59, 0x3a, 0x3e, 0x1b, 0x3e, 0xef, 0xee, 0x1a, 0x8e, 0x9b, 0x98, 0x02, 0xec, 0x8c, 0x84, 0x7d, 0x30, 0xd2, 0x27, 0xdf, 0x55, 0xa5, 0x95, 0x0d, 0x0f, 0x80, 0xd5, 0x95, 0xaf, 0xb0, 0x3d, 0x30, 0xb2, 0x86, 0xd5, 0x45, 0x09, 0x9c, 0xd6, 0xad, 0x32, 0xfa, 0x6f, 0x4f, 0xf2, 0xf1, 0x4d, 0xd4, 0xe0, 0x0f, 0x4e, 0x7b, 0x64, 0x17, 0x90, 0x3e, 0x99, 0xaf, 0x1e, 0xe2, 0x35, 0x0f, 0xb2, 0x15, 0xce, 0x23, 0x3d, 0x9b, 0xcf, 0x52, 0xc1, 0x2f, 0x3e, 0x18, 0xed, 0xf1, 0xb2, 0x81, 0x95, 0x37, 0xb6, 0x60, 0xf7, 0xe7, 0xb3, 0xed, 0xaa, 0x30, 0x3c, 0xf1, 0x66, 0x9d, 0x62, 0x64, 0xf3, 0x5d, 0xb7, 0x42, 0x4f, 0xad, 0x94, 0xb6, 0x51, 0x25, 0x01, 0x3b, 0xcd, 0x29, 0xf4, 0x79, 0xb8, 0xf6, 0xd3, 0x77, 0x92, 0x26, 0x2b, 0x5f, 0x08, 0xbf, 0x76, 0xa4, 0x86, 0xbc, 0x58, 0x72, 0xef, 0x14, 0x3c, 0xf9, 0xa7, 0x23, 0xb9, 0x55, 0x93, 0xa3, 0x90, 0xa7, 0x40, 0xac, 0xdd, 0x18, 0x36, 0x59, 0x97, 0x4a, 0x0b, 0x19, 0x5f, 0x5b, 0x51, 0x07, 0x76, 0x4c, 0x85, 0x6f, 0xbc, 0x2b, 0x81, 0xc7, 0x3b, 0xfb, 0xff, 0x7f, 0xc0, 0x0a, 0xf4, 0xef, 0x13, 0x84, 0x65, 0xa3, 0x0b, 0xc4, 0x5a, 0xd4, 0x4e, 0x77, 0xc5, 0x1d, 0x14, 0x52, 0xf2, 0x96, 0x35, 0x78, 0x10, 0xf6, 0x84, 0x5a, 0x7d, 0xdd, 0xa2, 0xb4, 0x08, 0xdf, 0x40, 0x32, 0x4d, 0xca, 0x16, 0x7e, 0x8e, 0xaa, 0xaa, 0x2d, 0xf7, 0x12, 0xc9, 0xe5, 0x6e, 0x26, 0xc9, 0x4e, 0xc2, 0xcb, 0x4e, 0xe7, 0xb3, 0xed, 0x15, 0x61, 0xb1, 0x8e, 0x85, 0x81, 0x73, 0x65, 0x52, 0x36, 0x25, 0x87, 0xa4, 0xa6, 0xd6, 0xc8, 0x7c, 0xa9, 0x9c, 0xdf, 0xa5, 0x83, 0x35, 0xf6, 0x1a, 0x38, 0x6e, 0x4d, 0x2e, 0x76, 0x96, 0x12, 0x1c, 0x02, 0x8a, 0x9d, 0x53, 0xe8, 0xc4, 0xa3, 0x5d, 0x90, 0x99, 0x74, 0xdf, 0x6c, 0x56, 0xe6, 0x69, 0xaf, 0xad, 0x69, 0xb3, 0x09, 0x18, 0xa4, 0x0a, 0x4d, 0xcf, 0x31, 0x5e, 0x25, 0x90, 0xba, 0x11, 0xcb, 0xc9, 0x26, 0x8e, 0x5e, 0x4f, 0xa1, 0x3a, 0xdb, 0xb7, 0x4c, 0xa4, 0x11, 0xda, 0xc4, 0x88, 0x7a, 0xbd, 0x5b, 0x21, 0x4f, 0x1a, 0xbe, 0xc7, 0xda, 0xc4, 0x29, 0xbc, 0x26, 0xe8, 0xfa, 0xe5, 0x8f, 0x02, 0x0b, 0x72, 0xd9, 0x79, 0x19, 0x28, 0x1f, 0x12, 0x59, 0x94, 0x82, 0x92, 0x53, 0xc0, 0xcc, 0x7c, 0x19, 0x72, 0xcd, 0x56, 0x4c, 0x70, 0x05, 0xc8, 0x59, 0x62, 0xf5, 0xcb, 0xc5, 0xda, 0x27, 0xc9, 0xcf, 0xfb, 0x45, 0x73, 0x4c, 0x53, 0x3a, 0x72, 0x30, 0x28, 0xef, 0x40, 0xa1, 0xee, 0x97, 0xd8, 0xdc, 0xb3, 0x9a, 0x00, 0x6a, 0x24, 0x43, 0xc6, 0xc7, 0x5b, 0x3a, 0xef, 0x8e, 0xef, 0x57, 0x9e, 0x21, 0xf0, 0x04, 0xb4, 0xca, 0xa1, 0xe1, 0x1d, 0x16, 0x68, 0x0d, 0x5c, 0xf9, 0x33, 0x59, 0xf4, 0x10, 0x42, 0xfb, 0x63, 0xde, 0x34, 0x87, 0xce, 0xcf, 0x64, 0xdd, 0x13, 0xff, 0xe5, 0x4b, 0xdf, 0xaf, 0x98, 0x76, 0x22, 0x3b, 0xfb, 0xbc, 0x1e, 0x92, 0xbe, 0xc1, 0x0f, 0xb6, 0x4a, 0xb8, 0xc6, 0x75, 0x15, 0x5e, 0x1a, 0xb2, 0x98, 0x1c, 0x97, 0xde, 0x03, 0xb8, 0xa4, 0xe8, 0x39, 0x15, 0x8b, 0xc5, 0x74, 0x41, 0xb5, 0x90, 0xdd, 0xbe, 0x77, 0x13, 0x41, 0x40, 0x80, 0xda, 0x7f, 0xe9, 0x9a, 0x20, 0x77, 0xed, 0x49, 0xf7, 0x46, 0xc4, 0x62, 0x7b, 0x84, 0x24, 0x99, 0xc0, 0x33, 0x74, 0x00, 0x0e, 0x5a, 0x33, 0xe2, 0x19, 0x07, 0xe7, 0x4a, 0x6e, 0x03, 0x23, 0x2a, 0x5f, 0xdc, 0x24, 0xb9, 0x51, 0x05, 0xd9, 0xd4, 0x2d, 0x81, 0x1d, 0xd8, 0x9b, 0x9e, 0xe0, 0x34, 0xdd, 0x7f, 0xc4, 0xcb, 0x1d, 0xef, 0xbf, 0xdc, 0x53, 0xd2, 0x67, 0x37, 0x37, 0xd4, 0x13, 0x5b, 0xb5, 0x25, 0x91, 0xb1, 0x1c, 0x64, 0xf4, 0xda, 0x8b, 0x77, 0x1d, 0xde, 0xe5, 0x3e, 0x60, 0x46, 0xa5, 0x41, 0xd1, 0x36, 0xd5, 0x6e, 0xc0, 0xdf, 0x1d, 0xd8, 0xb7, 0xb7, 0x12, 0xf8, 0x8c, 0x5f, 0x94, 0x75, 0x9e, 0x5a, 0x21, 0x02, 0x94, 0xfa, 0x63, 0x74, 0xff, 0x39, 0x0e, 0x15, 0xd9, 0xf1, 0xdc, 0x6f, 0x34, 0x6b, 0xaf, 0x02, 0xc0, 0xae, 0xa6, 0xbd, 0xa6, 0x7a, 0xd6, 0xea, 0xd9, 0x2a, 0x99, 0xd7, 0x45, 0x9e, 0x8e, 0x89, 0x4f, 0x6d, 0xb0, 0xe0, 0xb6, 0xa0, 0xd2, 0x7f, 0xe3, 0xca, 0xb5, 0x71, 0xc9, 0x7b, 0x65, 0x45, 0x49, 0x1f, 0x2b, 0xcd, 0xe3, 0x98, 0xed, 0x58, 0x14, 0xf4, 0x5e, 0x49, 0x20, 0x3c, 0x8e, 0xec, 0x65, 0xdb, 0x67, 0x58, 0x93, 0x5a, 0xab, 0xef, 0xa8, 0x2b, 0x03, 0x57, 0xc1, 0x0a, 0xff, 0xf7, 0xf2, 0x94, 0x08, 0xea, 0xfa, 0xa2, 0xa5, 0x5b, 0xd8, 0x6b, 0x9e, 0xd4, 0x3c, 0x9f, 0x8a, 0xe5, 0x1a, 0x17, 0x39, 0xa4, 0x18, 0x15, 0x5f, 0x4b, 0x8d, 0x14, 0x07, 0xf5, 0x37, 0x23, 0x6a, 0x82, 0x4a, 0x81, 0x73, 0x55, 0xf9, 0x86, 0xbc, 0x55, 0x8e, 0xe5, 0x16, 0xb1, 0x6e, 0x61, 0x73, 0x13, 0x94, 0x6d, 0x5b, 0xf8, 0xb8, 0xe1, 0x51, 0xf5, 0x00, 0x78, 0x0c, 0x62, 0x33, 0xbb, 0xc3, 0x18, 0x58, 0x9f, 0xb1, 0x04, 0x93, 0x97, 0x25, 0x2c, 0x95, 0xf2, 0x09, 0x01, 0x26, 0x6a, 0x99, 0x7c, 0x5a, 0xd8, 0x1a, 0x02, 0x46, 0xc4, 0xd3, 0xb0, 0xf3, 0x41, 0x04, 0x35, 0x79, 0x54, 0x95, 0x0d, 0x21, 0xde, 0x9f, 0x44, 0xd8, 0xbf, 0x86, 0x33, 0xa3, 0xfd, 0x97, 0x37, 0x73, 0x26, 0x31, 0x7c, 0x57, 0x04, 0x0f, 0x23, 0x91, 0xb8, 0xe1, 0xbf, 0xfe, 0x85, 0xf6, 0xfe, }, .pub_len = 1312, .msg = { 0x3d, 0x84, 0xe8, 0x98, 0x3d, 0x45, 0xfa, 0x81, 0x1f, 0x39, 0x56, 0x13, 0x9c, 0x8b, 0x55, 0x22, 0x7b, 0x44, 0x31, 0xd2, 0x9c, 0x21, 0xe3, 0x0e, 0xe7, 0x39, 0x86, 0x72, 0x51, 0x5d, 0xac, 0x6b, 0x71, 0x72, 0x50, 0x0e, 0x41, 0x72, 0xae, 0x86, 0xd7, 0x16, 0x23, 0x86, 0xde, 0xbd, 0xd7, 0x6b, 0x33, 0x2a, 0xea, 0xd3, 0x98, 0x85, 0x94, 0x8e, 0x93, 0x2a, 0x0b, 0xec, 0xcb, 0xd1, 0x97, 0x43, 0xc0, 0x34, 0xd0, 0x74, 0xf6, 0x88, 0x4d, 0x65, 0x18, 0xc9, 0x58, 0x31, 0xaf, 0x76, 0x39, 0xf2, 0x25, 0x52, 0x44, 0xe9, 0xa0, 0x6d, 0xa0, 0x41, 0xe6, 0x47, 0x96, 0x8e, 0xd8, 0xc6, 0x4f, 0x2f, 0x47, 0xd3, 0xfd, 0x17, 0xaf, 0xfc, 0xbd, 0x77, 0x13, 0x8a, 0x41, 0x38, 0xc7, 0x7a, 0xd5, 0x2a, 0xb9, 0xe3, 0xb2, 0x1b, 0x00, 0xdf, 0x16, 0xbe, 0x4c, 0x80, 0x70, 0xb4, 0xff, 0x60, 0xf0, 0x59, 0x02, 0x1f, 0xac, 0x85, 0xa1, 0xf2, 0xd6, 0xd8, 0x6d, 0x45, 0xc8, 0xb6, 0x2b, 0xed, 0xc2, 0x57, 0xfc, 0x96, 0xef, 0xc8, 0x1f, 0x51, 0x4f, 0xf4, 0x59, 0x9f, 0x0a, 0x86, 0xd4, 0x2b, 0xbc, 0xdc, 0x41, 0x6c, 0x26, 0x89, 0xd1, 0xd2, 0xc0, 0xa9, 0xac, 0xd2, 0x6c, 0x50, 0xd3, 0x6f, 0x5d, 0x57, 0x06, 0x45, 0xe0, 0xbc, 0x3c, 0x31, 0xc5, 0x28, 0xa9, 0x7e, 0x57, 0x62, 0x9c, 0x82, 0xaa, 0xda, 0x95, 0x9c, 0x26, 0x88, 0x45, 0xc8, 0x9c, 0xdc, 0x52, 0x2b, 0xf9, 0xe5, 0x7a, 0xf9, 0x72, 0xb0, 0x01, 0xa6, 0x08, 0x7f, 0x05, 0x51, 0x78, 0x67, 0xf5, 0x6b, 0x52, 0x6e, 0xae, 0x13, 0xd4, 0xa5, 0xb8, 0xe7, 0x49, 0x46, 0x20, 0x5e, 0xfe, 0x0f, 0xc4, 0xe5, 0x0e, 0xb5, 0x99, 0xba, 0x93, 0xfc, 0xec, 0x06, 0x75, 0x70, 0x28, 0x63, 0xc1, 0xde, 0xe2, 0x47, 0xe7, 0x43, 0xd8, 0x60, 0xc1, 0x60, 0xe1, 0x92, 0xa0, 0x0e, 0xf5, 0x5e, 0xb7, 0x76, 0x17, 0x30, 0xe2, 0xc6, 0x30, 0x5b, 0xae, 0xdc, 0xaf, 0x2b, 0xce, 0x70, 0x74, 0xb6, 0x38, 0x59, 0xf5, 0x3f, 0xa4, 0xd7, 0xd5, 0x16, 0x40, 0xa7, 0xac, 0x3e, 0x11, 0x48, 0x97, 0x43, 0x27, 0xbb, 0x76, 0xea, 0x27, 0x61, 0xbc, 0xb6, 0x1d, 0x87, 0x1e, 0xbd, 0x5a, 0x18, 0x07, 0x6d, 0x9f, 0xf2, 0xdb, 0x38, 0x51, 0x1d, 0x19, 0x2d, 0x61, 0x3f, 0x91, 0x9e, 0x7d, 0x4e, 0xe3, 0xcd, 0x99, 0x09, 0x43, 0xd6, 0xde, 0x14, 0xa9, 0x13, 0x91, 0x46, 0x5c, 0xbe, 0x05, 0x36, 0x55, 0xd1, 0x45, 0x29, 0x8d, 0xf4, 0x15, 0x31, 0x4c, 0x6a, 0x91, 0x54, 0xfe, 0xd0, 0x75, 0x4d, 0xfd, 0x7a, 0x45, 0x23, 0xf3, 0xaf, 0xea, 0x4d, 0x97, 0x2d, 0xe7, 0xf1, 0x69, 0x9d, 0x88, 0xab, 0x81, 0x5f, 0x0f, 0x06, 0xec, 0x7a, 0xc8, 0x28, 0xf1, 0x8d, 0xb9, 0x2d, 0x24, 0x75, 0x41, 0x90, 0x04, 0xfa, 0xe4, 0xe4, 0x69, 0x86, 0x96, 0x65, 0xd8, 0x32, 0xa4, 0x56, 0x1c, 0x07, 0xbe, 0x05, 0x98, 0xb5, 0xc9, 0x40, 0x60, 0x79, 0x47, 0xe1, 0x5e, 0xaf, 0xaa, 0x8a, 0x15, 0xc3, 0x7f, 0x3c, 0x84, 0x04, 0xf8, 0x27, 0xa3, 0x20, 0x60, 0x4b, 0xa0, 0x70, 0x80, 0x34, 0x5c, 0x27, 0xd7, 0x9c, 0x17, 0xce, 0xf0, 0xa4, 0xb1, 0xc6, 0x94, 0xfd, 0x22, 0x87, 0x05, 0xca, 0xd2, 0x36, 0xd5, 0x59, 0x66, 0x00, 0x7e, 0xf4, 0xa4, 0xd6, 0xd3, 0x89, 0x59, 0x7b, 0x06, 0xf5, 0x77, 0x6a, 0x69, 0x64, 0x79, 0x7c, 0xc1, 0xea, 0x1c, 0xe6, 0x3c, 0x02, 0xf8, 0x9c, 0xfe, 0x77, 0xaa, 0xba, 0xc7, 0xa6, 0x65, 0xf8, 0x9e, 0xc6, 0x8c, 0x51, 0x18, 0xd8, 0xb9, 0x0d, 0x8a, 0xee, 0xc8, 0x8c, 0x9a, 0x20, 0xff, 0xaf, 0x85, 0x99, 0xdd, 0x3b, 0x52, 0x04, 0xc7, 0x0a, 0x45, 0xbc, 0xaf, 0x8d, 0x97, 0xe4, 0x6a, 0xce, 0x81, 0x12, 0x8b, 0x69, 0x13, 0xfe, 0x15, 0x9e, 0x26, 0x6f, 0xeb, 0x03, 0x0c, 0x3e, 0x59, 0xad, 0x04, 0x41, 0x9f, 0x31, 0x75, 0xe7, 0x0a, 0x29, 0x2f, 0xa0, 0x4f, 0x2e, 0x77, 0xdf, 0x7c, 0x75, 0xf2, 0xd5, 0xcb, 0xf4, 0xce, 0x04, 0xf0, 0x24, 0xca, 0x53, 0x22, 0x5d, 0x2e, 0xf6, 0xaa, 0x95, 0xeb, 0x27, 0x6c, 0x13, 0x59, 0x5c, 0xa4, 0x4d, 0x06, 0x59, 0x6d, 0x04, 0x23, 0xdf, 0xf2, 0x49, 0xcc, 0x19, 0xfa, 0xb7, 0xd4, 0x45, 0xd4, 0x71, 0x55, 0xf8, 0x8d, 0x1a, 0x34, 0x11, 0x82, 0x9c, 0xa4, 0x73, 0x0e, 0x6a, 0x28, 0x49, 0x8e, 0xed, 0x8d, 0x9f, 0x39, 0xa3, 0x75, 0x45, 0x1d, 0x58, 0x6d, 0x57, 0x6e, 0xb1, 0x93, 0x4f, 0x08, 0xf9, 0x91, 0x95, 0x5d, 0xe8, 0x49, 0x31, 0xed, 0x40, 0xfd, 0xe3, 0x4a, 0x40, 0x37, 0x5f, 0xa1, 0x3b, 0xca, 0x8d, 0x07, 0xdc, 0x3e, 0x66, 0x07, 0xb2, 0xe1, 0xd7, 0x4b, 0x22, 0x51, 0x80, 0x80, 0xef, 0xb3, 0x46, 0xc9, 0xc9, 0x84, 0x58, 0x7b, 0x94, 0x7c, 0x78, 0x09, 0x7c, 0xf8, 0xfe, 0x2f, 0xb9, 0x79, 0xc0, 0x31, 0x13, 0x3f, 0xbc, 0x3f, 0x5b, 0x5f, 0xe1, 0x41, 0xc4, 0xc5, 0x69, 0xb8, 0x07, 0x60, 0x43, 0x3f, 0x67, 0x19, 0x1a, 0xfb, 0xfb, 0xa1, 0x46, 0x99, 0x7e, 0xc1, 0x66, 0x94, 0x22, 0x9c, 0x11, 0x8b, 0x0a, 0x87, 0xe0, 0x32, 0xf2, 0xad, 0xe3, 0xe4, 0x80, 0x54, 0x1c, 0xdb, 0x15, 0xf6, 0xcb, 0xe3, 0x8c, 0x20, 0xcc, 0xca, 0x05, 0xca, 0xb8, 0xf3, 0x71, 0xae, 0xed, 0x3e, 0x44, 0x62, 0x95, 0xe1, 0xa0, 0x7f, 0xaf, 0xd2, 0x43, 0xcf, 0x5f, 0x33, 0xe3, 0x20, 0xc6, 0xb4, 0x94, 0xb8, 0x48, 0x6b, 0xff, 0xaa, 0xf6, 0xb7, 0x7d, 0xb2, 0x0b, 0xb9, 0x59, 0x23, 0x02, 0x52, 0xe1, 0xc6, 0x05, 0x47, 0x08, 0xb1, 0x93, 0x5d, 0x62, 0xca, 0x8e, 0x83, 0xd8, 0x49, 0x7d, 0x10, 0x84, 0x12, 0x17, 0x74, 0x01, 0xcf, 0x05, 0x49, 0xa9, 0x9d, 0x92, 0x34, 0xdd, 0x11, 0x9d, 0xd2, 0x53, 0x38, 0x7d, 0x60, 0x31, 0x4a, 0xc6, 0xac, 0x2d, 0x49, 0x3b, 0x04, 0xf4, 0xa0, 0x54, 0x0f, 0xe7, 0xe8, 0xca, 0xf6, 0xf6, 0x56, 0x8a, 0x5e, 0x27, 0x36, 0x91, 0xce, 0x5d, 0xc0, 0xa7, 0x9d, 0xcf, 0x82, 0x24, 0x2d, 0x59, 0x64, 0xf9, 0x4f, 0x08, 0x0d, 0xca, 0x8c, 0x2d, 0x2d, 0x80, 0x3b, 0x6b, 0xf0, 0xf5, 0x85, 0xaf, 0x6c, 0x54, 0x77, 0x65, 0xd6, 0xc5, 0x2b, 0x99, 0xce, 0xba, 0xf8, 0xd5, 0x68, 0x32, 0x74, 0xdb, 0xc0, 0x00, 0xdc, 0x6d, 0x7a, 0x63, 0x4a, 0xce, 0xf0, 0x35, 0xec, 0x62, 0x2b, 0x9d, 0x18, 0xb8, 0x7c, 0x06, 0x01, 0xf6, 0xff, 0xed, 0x59, 0x40, 0x67, 0xc9, 0x6c, 0x58, 0x99, 0x7c, 0x63, 0x1a, 0xe2, 0x67, 0x08, 0x08, 0xae, 0x02, 0xb6, 0x6e, 0x4b, 0x77, 0x52, 0x30, 0x05, 0x93, 0x63, 0x3b, 0x12, 0x91, 0x51, 0xcc, 0x4c, 0x56, 0x43, 0xc9, 0x09, 0x8a, 0x6f, 0x30, 0xd2, 0x96, 0x46, 0x42, 0x65, 0xf2, 0xf5, 0x8f, 0xd8, 0x2b, 0x4a, 0xce, 0xd2, 0x4e, 0x4c, 0x42, 0xb6, 0x62, 0xcb, 0xd7, 0xf9, 0x3e, 0xee, 0xdf, 0xbe, 0xc8, 0x0c, 0xd7, 0xf6, 0xe0, 0x33, 0xf8, 0xd0, 0x88, 0xbd, 0x98, 0xba, 0x09, }, .msg_len = 964, .sig = { 0x26, 0xbd, 0x90, 0xa9, 0x98, 0x00, 0x2d, 0x9a, 0xe7, 0xe3, 0x7e, 0x61, 0x91, 0xd6, 0x56, 0xea, 0x56, 0x8b, 0xfe, 0x90, 0x1b, 0x12, 0x78, 0x62, 0x40, 0xaa, 0x32, 0x07, 0x08, 0x32, 0x23, 0xfb, 0x42, 0xdd, 0x25, 0x51, 0x3d, 0xd3, 0xea, 0x10, 0xd2, 0xdd, 0x72, 0xa3, 0x8e, 0xf3, 0x49, 0x31, 0x49, 0xf9, 0x15, 0x14, 0xd4, 0xc8, 0x22, 0x4c, 0x4a, 0xfc, 0xf5, 0xb0, 0xcc, 0x5d, 0xff, 0x95, 0x01, 0x3c, 0x52, 0x1e, 0x1a, 0x80, 0x99, 0x12, 0x0c, 0x30, 0xea, 0x9b, 0x39, 0xf3, 0xec, 0xad, 0xee, 0xa1, 0x8a, 0xbe, 0x10, 0xa9, 0x51, 0x07, 0xc0, 0x4d, 0x92, 0xff, 0xe8, 0x22, 0xd9, 0x70, 0x7a, 0xea, 0x24, 0xac, 0x8c, 0x6c, 0x73, 0xa7, 0x3c, 0x03, 0x83, 0x74, 0x8d, 0x8a, 0xcf, 0xeb, 0x5f, 0xb5, 0xc1, 0x7c, 0x0e, 0x29, 0x8a, 0x92, 0xdd, 0x34, 0xe1, 0x41, 0x3e, 0x1b, 0x9d, 0x56, 0x0c, 0x98, 0xcc, 0x54, 0x6f, 0x95, 0x42, 0x22, 0x3e, 0x45, 0x46, 0x06, 0x1a, 0x58, 0x71, 0xf7, 0xde, 0x47, 0xe4, 0x77, 0x63, 0x3d, 0xeb, 0x86, 0x13, 0x9e, 0x28, 0xf5, 0x45, 0xa2, 0x4c, 0x61, 0x54, 0x32, 0x35, 0x4c, 0xa5, 0x60, 0xbc, 0x93, 0x8b, 0x13, 0xb5, 0xfa, 0xb8, 0x50, 0x02, 0xb7, 0x63, 0xfb, 0xfa, 0x84, 0x8a, 0xc8, 0x1e, 0x63, 0xb6, 0xea, 0x06, 0xdb, 0x4e, 0xf7, 0x0d, 0xa0, 0x9d, 0x9e, 0xab, 0xeb, 0xa5, 0xc5, 0xaa, 0xa8, 0xc5, 0xb0, 0x53, 0xae, 0xe5, 0x21, 0x32, 0x64, 0xb8, 0xa2, 0x74, 0xc5, 0x9d, 0xac, 0xa2, 0xd3, 0xf8, 0xa8, 0xf3, 0xa1, 0xf4, 0xdd, 0x0e, 0x43, 0x08, 0x37, 0x8b, 0x72, 0x80, 0x24, 0xf0, 0xd5, 0x7c, 0x74, 0x80, 0x96, 0x48, 0x0b, 0x3b, 0xc8, 0x75, 0x4c, 0xd0, 0x76, 0x1c, 0x6c, 0x10, 0x8d, 0x35, 0x01, 0x64, 0xb2, 0x6a, 0x1c, 0x4d, 0xfe, 0xcb, 0x61, 0x9c, 0x29, 0xee, 0x85, 0xc5, 0xa4, 0x1a, 0x3b, 0x9c, 0xa4, 0x14, 0xdf, 0x26, 0xf9, 0x50, 0x58, 0x1d, 0xf4, 0xf7, 0x54, 0xeb, 0x21, 0xed, 0xfd, 0x16, 0xd0, 0x39, 0xd9, 0x36, 0x90, 0x83, 0x5e, 0x36, 0x5c, 0x3a, 0xcf, 0x6f, 0x68, 0x2d, 0x1b, 0x14, 0x22, 0xc3, 0x86, 0x12, 0xcd, 0x98, 0xab, 0xbf, 0xd6, 0xef, 0xba, 0x51, 0x29, 0xd1, 0xf2, 0xc4, 0xab, 0x91, 0xae, 0x3d, 0x92, 0xb7, 0x9b, 0x9a, 0x21, 0xd6, 0xcb, 0xe0, 0x96, 0x72, 0xeb, 0x51, 0xd2, 0x7f, 0x8b, 0x34, 0xc9, 0x0b, 0xad, 0x8a, 0x69, 0x22, 0xd4, 0x9d, 0x12, 0x69, 0x9d, 0xdf, 0x56, 0x8a, 0x09, 0xae, 0x04, 0xe4, 0x88, 0xe3, 0x9d, 0xa5, 0xdc, 0xf4, 0x16, 0xd5, 0x86, 0x9d, 0xeb, 0xec, 0x4f, 0xa8, 0xc8, 0x2b, 0x8c, 0xcd, 0x1b, 0x2c, 0x65, 0x9f, 0xec, 0x6e, 0xb3, 0xbb, 0xca, 0xfb, 0xf0, 0xd8, 0xd7, 0xf1, 0x83, 0x5a, 0x8e, 0xa3, 0x69, 0x19, 0xad, 0xe8, 0xa2, 0x22, 0x02, 0xe8, 0x44, 0x15, 0xb9, 0x2f, 0x65, 0x53, 0x36, 0x04, 0x8f, 0xa7, 0x80, 0x5c, 0x6b, 0x1e, 0x63, 0x72, 0x7e, 0xc9, 0xdb, 0xd2, 0xc2, 0x0a, 0x8e, 0xb3, 0x16, 0x1e, 0xef, 0x02, 0xb9, 0x85, 0xda, 0xa6, 0x9f, 0x06, 0x40, 0x1a, 0x5a, 0x51, 0xf9, 0xab, 0x74, 0x9a, 0x22, 0x68, 0x99, 0xe8, 0x0b, 0x68, 0x90, 0xc2, 0xb6, 0x03, 0x4b, 0x07, 0x83, 0xb5, 0xce, 0x9c, 0x92, 0xd9, 0xff, 0x46, 0x68, 0xe8, 0x55, 0xb1, 0xfd, 0x3d, 0x01, 0xe4, 0xb5, 0x3a, 0x83, 0x0d, 0xa0, 0xa2, 0xcc, 0x66, 0x1c, 0xde, 0x0e, 0xd0, 0xcf, 0x10, 0xfc, 0x20, 0xce, 0xee, 0xae, 0x57, 0xde, 0x3e, 0xb6, 0x0c, 0xe3, 0xe2, 0x93, 0xee, 0x33, 0x44, 0xde, 0xa6, 0xcb, 0xd5, 0xfd, 0x6b, 0xbe, 0x08, 0x21, 0xf7, 0x99, 0xdd, 0x22, 0x11, 0x61, 0x5c, 0xb9, 0xdf, 0x5b, 0x7c, 0xf6, 0x17, 0x3a, 0x68, 0xdb, 0x2e, 0x61, 0x34, 0x91, 0x4c, 0xc1, 0x01, 0x8a, 0x7e, 0xb0, 0xf7, 0xf7, 0x2a, 0x91, 0x8f, 0xf0, 0xf6, 0x11, 0x66, 0xa8, 0x29, 0xbb, 0xa1, 0xf2, 0x29, 0x67, 0x6b, 0xed, 0x4a, 0x16, 0xde, 0xfa, 0x05, 0x55, 0xa1, 0x94, 0x94, 0xd9, 0x91, 0xc9, 0x81, 0xb5, 0x4d, 0x8a, 0x7a, 0xcb, 0x2d, 0x2b, 0x23, 0x66, 0x70, 0x16, 0x92, 0x52, 0x91, 0xed, 0x37, 0x5f, 0xf4, 0xed, 0xe5, 0x7f, 0x77, 0x1a, 0xd6, 0x8f, 0x29, 0x5f, 0xdd, 0x7b, 0xc4, 0xeb, 0x4e, 0x3d, 0x1f, 0x48, 0x60, 0xbe, 0x76, 0xbe, 0xfc, 0x0a, 0xc6, 0xaa, 0x7b, 0x59, 0x3d, 0xa6, 0x11, 0x55, 0x74, 0xcd, 0xdf, 0x4d, 0x04, 0x30, 0x4f, 0xcf, 0x3f, 0xd9, 0xcc, 0x14, 0xbb, 0x5f, 0xf7, 0x9d, 0xb3, 0x21, 0x1c, 0xb1, 0x98, 0xc2, 0xa7, 0x8a, 0xd3, 0xa2, 0x3d, 0x0d, 0x49, 0x91, 0x32, 0xbf, 0x5f, 0x65, 0x65, 0x29, 0x05, 0x68, 0x43, 0x33, 0x0c, 0x89, 0xad, 0xd3, 0x09, 0x72, 0x03, 0x04, 0xfb, 0xdb, 0xb2, 0x53, 0xa0, 0xff, 0x53, 0x1f, 0x82, 0xf2, 0x06, 0x8b, 0x22, 0x99, 0x0e, 0x91, 0xa3, 0xd5, 0x34, 0xcf, 0xe5, 0x8b, 0xc9, 0x78, 0xa8, 0xd3, 0x30, 0xba, 0x73, 0x9d, 0xa1, 0xc0, 0x0d, 0x85, 0xe8, 0xae, 0xaa, 0x34, 0xcb, 0x6e, 0x7b, 0x0a, 0x5a, 0xc6, 0x7a, 0xd3, 0x6a, 0xc8, 0x44, 0x57, 0xaa, 0x14, 0xc8, 0xf8, 0x64, 0xac, 0x8b, 0x82, 0x48, 0xa0, 0x7e, 0x1d, 0xe2, 0xd2, 0x7c, 0x80, 0xa7, 0x70, 0x2b, 0xb5, 0x09, 0x60, 0xf7, 0xae, 0x1d, 0xa8, 0x2b, 0xd5, 0xdb, 0xad, 0xd0, 0x3d, 0xa0, 0x90, 0x71, 0x79, 0xed, 0xa7, 0x32, 0x94, 0x72, 0x34, 0x0d, 0xc7, 0xc8, 0x05, 0xb7, 0x31, 0x0b, 0xce, 0x2d, 0xca, 0xba, 0x40, 0x40, 0x3c, 0xd9, 0x17, 0xa0, 0x47, 0x87, 0x31, 0xab, 0x9f, 0xed, 0xff, 0x54, 0x60, 0xec, 0x66, 0x1f, 0xab, 0xe3, 0x06, 0x1d, 0xd6, 0xb8, 0xa3, 0xf1, 0x4b, 0xa9, 0xd5, 0xb3, 0x74, 0xd1, 0x55, 0xbb, 0x95, 0xf9, 0x3e, 0xd8, 0xc9, 0xdc, 0x19, 0xb6, 0x32, 0xe9, 0xb5, 0x90, 0x12, 0x15, 0x3a, 0x4b, 0x27, 0x71, 0x28, 0x99, 0xa2, 0x62, 0xde, 0xdd, 0x80, 0x2c, 0x6b, 0x23, 0x42, 0x34, 0xbc, 0xc0, 0xcd, 0xd5, 0x7e, 0x40, 0x94, 0xa6, 0xae, 0xe9, 0x58, 0x67, 0x43, 0x4d, 0xd8, 0xce, 0x8f, 0xb9, 0xa8, 0xdd, 0x34, 0x62, 0x9c, 0x4a, 0x68, 0xd1, 0xfa, 0x33, 0x03, 0x0d, 0xfc, 0x61, 0x80, 0xa1, 0x5f, 0x55, 0x08, 0xec, 0x07, 0xf5, 0x06, 0x7a, 0x30, 0x17, 0x20, 0xad, 0xad, 0x2f, 0x61, 0xdb, 0xcc, 0xfb, 0x6e, 0x2e, 0x12, 0x12, 0x0a, 0x48, 0x4a, 0xe2, 0x00, 0x0d, 0xcd, 0x34, 0x8f, 0xb8, 0xd6, 0x7e, 0x1a, 0xf1, 0x68, 0x10, 0x1b, 0xe5, 0xb4, 0xf7, 0xd1, 0x6f, 0x0b, 0xe4, 0xf1, 0x9d, 0xc8, 0x99, 0x6f, 0xbe, 0xb1, 0x66, 0xf5, 0x1f, 0x78, 0xe1, 0x36, 0xd9, 0xfc, 0x9b, 0xbf, 0x72, 0x89, 0xcb, 0x11, 0x04, 0x34, 0x9f, 0xc3, 0xef, 0x82, 0xae, 0x76, 0xa0, 0x06, 0xb9, 0x91, 0xc3, 0xde, 0x40, 0xa2, 0xc5, 0xeb, 0x97, 0x16, 0x18, 0xf0, 0xe2, 0x2c, 0xfa, 0xa0, 0x07, 0x0b, 0x19, 0x22, 0x95, 0x60, 0xb4, 0xa8, 0xb1, 0xa8, 0x27, 0x7a, 0xf7, 0x3c, 0x49, 0x40, 0xec, 0x5c, 0xcd, 0xdd, 0xc2, 0x8f, 0xb1, 0xf5, 0xc0, 0x36, 0xe1, 0x95, 0xc5, 0xe4, 0x2b, 0x2c, 0x6e, 0xba, 0x5c, 0x9e, 0xf3, 0x45, 0x22, 0xe0, 0x55, 0xa2, 0x77, 0x81, 0x4d, 0x85, 0xeb, 0xbe, 0x16, 0xd4, 0xfd, 0xf6, 0x63, 0xb0, 0x3a, 0x1d, 0x24, 0x43, 0x8b, 0x2f, 0x2a, 0xa1, 0xc2, 0xf5, 0xbd, 0xb9, 0x8f, 0x45, 0xec, 0x5d, 0x1c, 0xcc, 0x8b, 0x22, 0xc3, 0xdf, 0x5d, 0x90, 0xaf, 0x6e, 0x84, 0xbc, 0x0d, 0x25, 0xf7, 0x20, 0x17, 0x21, 0x8e, 0x9e, 0xaa, 0x3e, 0xd0, 0xaf, 0xf6, 0x0f, 0x49, 0x02, 0x11, 0x65, 0xeb, 0xbf, 0x4d, 0x22, 0xa1, 0xcc, 0x6d, 0x52, 0x8b, 0xa9, 0x1c, 0x32, 0x00, 0x5d, 0xe5, 0x54, 0xa5, 0x63, 0x83, 0x5e, 0xe1, 0x52, 0xec, 0xa1, 0x3a, 0x35, 0x3e, 0xb3, 0x51, 0xe2, 0x34, 0x82, 0x78, 0x01, 0x00, 0x96, 0x0b, 0x63, 0x3e, 0x03, 0x8a, 0x71, 0xc9, 0x1a, 0xe5, 0x1c, 0x01, 0xf8, 0x57, 0x5f, 0xd2, 0xe8, 0xc6, 0xff, 0x31, 0x65, 0x7c, 0xb5, 0x5d, 0x7e, 0x82, 0xd5, 0x5d, 0x06, 0x71, 0xfc, 0xf5, 0x14, 0xf5, 0xac, 0x0b, 0xbb, 0x9c, 0x98, 0x87, 0x32, 0xb0, 0xf2, 0xfa, 0x5e, 0xb9, 0x20, 0x1a, 0xd1, 0x32, 0xb3, 0xae, 0x32, 0x3c, 0x7b, 0xc0, 0x80, 0x53, 0x96, 0xa0, 0xce, 0x4c, 0x82, 0xa9, 0xe2, 0x86, 0x95, 0x6d, 0x1e, 0x6c, 0x1a, 0xda, 0xe9, 0x11, 0xd8, 0xd6, 0x04, 0xc7, 0xd8, 0x7e, 0xe2, 0xed, 0xae, 0xd2, 0x21, 0xc8, 0x97, 0xdb, 0x1a, 0x80, 0x71, 0xfc, 0x70, 0x14, 0xb0, 0x1a, 0xdb, 0x81, 0xa7, 0x98, 0x1e, 0xb7, 0xd8, 0x59, 0xe0, 0x8b, 0xc0, 0x6d, 0xad, 0x1c, 0x13, 0x0d, 0xba, 0xae, 0xd2, 0xf0, 0x7a, 0xea, 0xb0, 0x13, 0x7b, 0xd0, 0x7a, 0xd1, 0x0c, 0xa5, 0x88, 0x1e, 0xff, 0xa6, 0x07, 0x22, 0xba, 0xf5, 0xa1, 0x53, 0x79, 0xeb, 0x5c, 0xce, 0x33, 0x93, 0xba, 0xf1, 0x67, 0x90, 0x54, 0xeb, 0x2d, 0x05, 0x1a, 0x5e, 0x5e, 0xd0, 0x97, 0x18, 0x77, 0x84, 0x24, 0x9d, 0x86, 0x6e, 0x7c, 0x3c, 0x1b, 0x8a, 0xe7, 0x5c, 0x44, 0x26, 0x51, 0x6e, 0xbe, 0x73, 0xd7, 0x52, 0x2c, 0xe6, 0x91, 0xa2, 0xe1, 0xd5, 0xd8, 0x45, 0x91, 0xf1, 0xb9, 0xbf, 0xf4, 0x53, 0x17, 0x21, 0xf6, 0xa2, 0x92, 0xe0, 0x96, 0xae, 0xa0, 0x77, 0x4c, 0x90, 0xf9, 0x09, 0xca, 0x74, 0x03, 0x50, 0x21, 0xe7, 0xbb, 0x6f, 0x36, 0x7a, 0x70, 0x8e, 0x60, 0x67, 0x73, 0xb5, 0xbe, 0xb5, 0xdb, 0xd7, 0x53, 0x4c, 0x68, 0x5a, 0xa1, 0xff, 0x44, 0xc0, 0xf3, 0xb1, 0x58, 0x73, 0x75, 0xf3, 0x85, 0xd8, 0xc1, 0xe6, 0x46, 0x74, 0x32, 0x79, 0x6f, 0xc5, 0x4a, 0x00, 0xe6, 0xc3, 0x08, 0x0a, 0xfe, 0x41, 0x0f, 0xe8, 0xec, 0x66, 0x42, 0xd1, 0x3f, 0xf8, 0x01, 0xe7, 0xe1, 0x7b, 0x15, 0x0c, 0x19, 0xf7, 0x68, 0xc6, 0xd8, 0xe2, 0x82, 0x59, 0xc3, 0xc3, 0x68, 0x09, 0x78, 0x68, 0x53, 0xe2, 0x5b, 0xcf, 0xc8, 0xfd, 0x67, 0xe0, 0x0c, 0x72, 0x07, 0xf9, 0x2e, 0x16, 0xf6, 0xf5, 0x96, 0x8b, 0x38, 0x1f, 0xb9, 0x11, 0x43, 0x5f, 0x86, 0x17, 0x4f, 0x12, 0x12, 0x32, 0x95, 0xac, 0xb1, 0x97, 0x90, 0x0d, 0x14, 0x9a, 0x6d, 0x5f, 0x76, 0xf4, 0x50, 0x19, 0x6e, 0xb5, 0x83, 0x22, 0xc7, 0xb8, 0x60, 0xfd, 0x08, 0x79, 0x1c, 0xd3, 0x77, 0xf8, 0x7f, 0x83, 0x2c, 0x23, 0x39, 0xe0, 0x08, 0x78, 0x7f, 0xe9, 0x8e, 0x13, 0x42, 0x9b, 0x9f, 0xfd, 0xd5, 0x3e, 0x3f, 0x45, 0x86, 0xa4, 0x05, 0x1e, 0x99, 0xaf, 0x76, 0x17, 0xe3, 0xf9, 0x79, 0x68, 0xaa, 0x14, 0xb7, 0x8e, 0xa7, 0x28, 0x91, 0x75, 0x1f, 0x2a, 0xd2, 0xc1, 0x69, 0x67, 0x1d, 0x75, 0xf7, 0x1d, 0xa4, 0x9f, 0xfd, 0x08, 0x25, 0x37, 0xa4, 0x6b, 0x79, 0x31, 0x39, 0x53, 0x68, 0x13, 0x91, 0x1b, 0x4c, 0x39, 0xfb, 0x2d, 0x67, 0x33, 0x28, 0x81, 0x14, 0x5b, 0xce, 0xeb, 0xa9, 0x37, 0x53, 0x76, 0x17, 0x94, 0xc7, 0xdd, 0x05, 0xdc, 0x6c, 0x19, 0xe5, 0x34, 0x90, 0xa2, 0x11, 0x2e, 0xb1, 0x8d, 0x5f, 0x72, 0x3e, 0xcb, 0xb1, 0x55, 0x9d, 0xa9, 0xc3, 0x48, 0x28, 0x47, 0x4e, 0x54, 0x12, 0x65, 0x08, 0xb9, 0x4e, 0x31, 0xf2, 0x3f, 0x05, 0xa6, 0x57, 0xdd, 0xe3, 0x79, 0x5d, 0x95, 0x01, 0xdb, 0xb4, 0x67, 0x61, 0x9e, 0x8c, 0x35, 0x31, 0x28, 0x63, 0xdd, 0xa7, 0xee, 0xbd, 0x8b, 0xf8, 0xda, 0x65, 0xb9, 0x5a, 0x49, 0x65, 0x41, 0xa4, 0x5f, 0xf7, 0x63, 0xcf, 0xdb, 0x5a, 0xcd, 0x0b, 0xfb, 0x80, 0x17, 0x5d, 0xe0, 0x15, 0x16, 0xbd, 0x19, 0x63, 0xd0, 0x2a, 0x57, 0x94, 0x16, 0x3a, 0xf5, 0x3f, 0x35, 0x33, 0x5c, 0xed, 0xcf, 0x35, 0x6d, 0x15, 0x6d, 0x35, 0x27, 0xf6, 0xe4, 0xb4, 0xa2, 0x81, 0x86, 0xb5, 0xc2, 0xc4, 0x50, 0x31, 0x64, 0xe9, 0x2e, 0xfe, 0xde, 0xbb, 0xf2, 0xf1, 0x59, 0x8f, 0x30, 0x11, 0x4d, 0xdb, 0x38, 0xec, 0xee, 0x29, 0x24, 0xe7, 0x39, 0xb8, 0x8b, 0x70, 0xc9, 0x9a, 0x4f, 0x72, 0xef, 0x11, 0xe8, 0x95, 0x4f, 0x15, 0xe4, 0xfd, 0xf9, 0x23, 0x22, 0xfe, 0x80, 0x15, 0x28, 0x93, 0x4b, 0x65, 0x6b, 0x9d, 0x88, 0xa8, 0x34, 0x1a, 0x60, 0x61, 0xcf, 0xbd, 0x4c, 0xfe, 0xbf, 0xa3, 0x33, 0x83, 0x0f, 0xdc, 0x48, 0xad, 0x7f, 0x6c, 0xc6, 0x66, 0x59, 0x25, 0x33, 0x20, 0x88, 0xd9, 0xa6, 0x99, 0xfc, 0x0e, 0xde, 0x28, 0x26, 0x6b, 0xcf, 0x1b, 0xd9, 0xfc, 0x13, 0x81, 0x2e, 0x18, 0x12, 0x67, 0x5d, 0xf3, 0x4d, 0xdf, 0x3e, 0x79, 0x3a, 0x3c, 0xe9, 0x74, 0xab, 0x57, 0xff, 0xf5, 0xe9, 0xe1, 0x4f, 0x46, 0xe5, 0x1b, 0x03, 0xb3, 0xe1, 0x28, 0x05, 0x1d, 0x1e, 0x08, 0x1b, 0x46, 0xf1, 0x23, 0xa1, 0xb5, 0x68, 0x1e, 0x78, 0x1a, 0xb5, 0xfd, 0x6d, 0x66, 0x74, 0x8e, 0x06, 0x47, 0xbf, 0xa4, 0xc4, 0xbd, 0x19, 0x61, 0xa9, 0x2a, 0xe5, 0xc0, 0x3e, 0xbe, 0x80, 0x4f, 0x41, 0x07, 0x23, 0x82, 0x10, 0x61, 0x9e, 0xf4, 0x84, 0x52, 0x63, 0xa9, 0x21, 0x4f, 0x2a, 0x1f, 0xc4, 0xc6, 0x9f, 0xf5, 0xd7, 0x9c, 0xbe, 0x89, 0x5b, 0xa7, 0xf5, 0x29, 0xe0, 0xf6, 0xea, 0x67, 0x6d, 0x9f, 0x1d, 0xe5, 0x5f, 0x1a, 0x45, 0x5e, 0x41, 0xd4, 0x75, 0xef, 0xd7, 0xa8, 0x74, 0xf3, 0xb0, 0xf1, 0x6b, 0xb1, 0xf0, 0x78, 0xcf, 0xe0, 0x6f, 0xe7, 0xf6, 0xb2, 0xec, 0x78, 0x3f, 0xc4, 0x79, 0x77, 0xb6, 0x78, 0x62, 0x59, 0xd7, 0x37, 0xf9, 0xb2, 0x19, 0xd0, 0x4d, 0x26, 0x88, 0x99, 0xce, 0xbc, 0xcf, 0xb6, 0x3e, 0x5c, 0x0d, 0x4f, 0x08, 0x88, 0x3e, 0xaf, 0xf3, 0xe1, 0x4c, 0xb6, 0xcc, 0x9e, 0xe7, 0xbc, 0x45, 0xec, 0xfe, 0x97, 0x27, 0x1d, 0xd8, 0xeb, 0x2c, 0x01, 0xfd, 0xac, 0x9d, 0x8a, 0x14, 0x2d, 0x95, 0x27, 0x6e, 0x80, 0x30, 0x8d, 0xc6, 0xc2, 0xe4, 0xeb, 0xeb, 0x4e, 0x41, 0xd0, 0x16, 0x34, 0x15, 0xf9, 0x69, 0xc5, 0x20, 0x78, 0x21, 0x0d, 0x5f, 0x03, 0x1c, 0x54, 0x45, 0x6f, 0x66, 0x6b, 0xa5, 0x88, 0xb6, 0xef, 0x85, 0xa9, 0xc9, 0x72, 0xb4, 0x9a, 0x67, 0xc8, 0x4f, 0x39, 0x4f, 0xe3, 0xac, 0x50, 0x2d, 0x98, 0xd2, 0x1a, 0xce, 0x5d, 0xa0, 0xbb, 0x1b, 0x80, 0x0b, 0xe7, 0x87, 0x9b, 0xed, 0x1d, 0x21, 0x06, 0xe4, 0x4a, 0xe6, 0x42, 0x67, 0x3e, 0x8f, 0x3c, 0x4d, 0x1a, 0x50, 0x23, 0xeb, 0x4f, 0x13, 0x05, 0x38, 0x9e, 0x90, 0xe6, 0x6d, 0xa0, 0x57, 0x48, 0xb6, 0x07, 0x09, 0x0c, 0x54, 0xd7, 0x27, 0x7a, 0x05, 0x64, 0xe9, 0x6a, 0x69, 0x11, 0x9e, 0xa0, 0x81, 0xe0, 0xac, 0x21, 0xda, 0xaf, 0xd6, 0xa4, 0x25, 0x3a, 0x25, 0xb7, 0xcd, 0xbb, 0xe0, 0x4f, 0x1d, 0xf6, 0x85, 0x2b, 0xb6, 0x8f, 0x78, 0x49, 0xc0, 0xa5, 0xcc, 0x95, 0x4b, 0x64, 0x75, 0x1f, 0xc5, 0x3d, 0xb7, 0xa2, 0x59, 0x98, 0xa5, 0x35, 0xaf, 0x98, 0x96, 0x0c, 0xbf, 0x11, 0xe1, 0xa5, 0xc4, 0xc1, 0xba, 0x20, 0xc3, 0xff, 0x75, 0xd3, 0x4c, 0x4e, 0xb3, 0x1c, 0x3f, 0x8f, 0xd4, 0xb2, 0xe4, 0x63, 0x9b, 0x73, 0xe6, 0x2b, 0xee, 0x73, 0xc8, 0x90, 0xd3, 0x2d, 0xac, 0x77, 0x70, 0x06, 0xe1, 0x74, 0x27, 0x57, 0xa6, 0x6c, 0xa6, 0x79, 0x0d, 0xb3, 0x8a, 0x7e, 0xea, 0x49, 0x09, 0xfb, 0xda, 0xa6, 0x33, 0xa9, 0x7f, 0xb1, 0x70, 0xce, 0x1f, 0xc1, 0x00, 0x7a, 0xc0, 0xad, 0x63, 0x5b, 0x52, 0x88, 0xae, 0xc0, 0x85, 0x19, 0xf7, 0x5b, 0x39, 0x1b, 0x93, 0x79, 0xda, 0x59, 0xaa, 0xdd, 0xd1, 0x91, 0xd6, 0x1f, 0xc7, 0x66, 0x86, 0x21, 0xd3, 0xf3, 0xd3, 0x33, 0x2b, 0xa5, 0x08, 0x73, 0x78, 0x84, 0x67, 0x8b, 0xa6, 0x13, 0x63, 0x6c, 0xe0, 0x0c, 0xc5, 0x25, 0x5c, 0x17, 0xa7, 0x1f, 0x2d, 0x5f, 0x3a, 0x1a, 0xe0, 0x23, 0x98, 0xf7, 0x5d, 0x73, 0xba, 0x03, 0xdb, 0x09, 0x1c, 0x24, 0xc3, 0xf3, 0x37, 0x3f, 0x9c, 0xc6, 0xf9, 0x0d, 0x4b, 0x07, 0x9d, 0xfa, 0xe9, 0x1c, 0x86, 0x09, 0xd2, 0x59, 0x0d, 0x55, 0x75, 0xf8, 0xbf, 0xe4, 0x1e, 0x69, 0x58, 0xe8, 0x43, 0xca, 0xaf, 0x02, 0x78, 0x41, 0x96, 0xdb, 0xc0, 0x0c, 0xeb, 0x1c, 0x16, 0xff, 0x9a, 0x71, 0xda, 0xa3, 0x3e, 0x6b, 0xee, 0xb5, 0x61, 0x4f, 0x60, 0xf6, 0x77, 0xc1, 0x01, 0xdc, 0x8c, 0x53, 0x62, 0xdf, 0xf3, 0x16, 0xa9, 0x97, 0x19, 0xe4, 0xb7, 0x7a, 0x39, 0xf7, 0x7b, 0x9f, 0x96, 0x62, 0xd8, 0x8e, 0x25, 0x23, 0x09, 0xbd, 0x0f, 0x0a, 0x2e, 0x0f, 0x9a, 0xc7, 0xa5, 0x89, 0x30, 0x60, 0xde, 0xfc, 0x49, 0x85, 0x7d, 0x0c, 0xd7, 0x13, 0x2f, 0x6d, 0x11, 0x0f, 0xd4, 0x25, 0xe9, 0xa9, 0xc7, 0x48, 0x47, 0x7e, 0x31, 0x47, 0x74, 0x6f, 0xaf, 0xd3, 0x63, 0x6b, 0x79, 0x8d, 0xaa, 0x4c, 0x94, 0x4b, 0x66, 0xd4, 0x70, 0x98, 0x05, 0x12, 0xe5, 0xef, 0x12, 0x8c, 0x7a, 0x2f, 0x95, 0x65, 0x99, 0xd1, 0x92, 0x1e, 0x20, 0x5d, 0x0e, 0xa7, 0x3c, 0xd7, 0x05, 0x27, 0x31, 0x3e, 0x4a, 0x5b, 0x5e, 0x6c, 0x8b, 0x9f, 0xae, 0xd4, 0xd8, 0x0d, 0x0f, 0x1d, 0x1e, 0x24, 0x2a, 0x2e, 0x4a, 0x4d, 0x50, 0x5e, 0x68, 0x85, 0x8f, 0x93, 0x94, 0xa6, 0xc3, 0xf3, 0xf4, 0x06, 0x29, 0x2d, 0x41, 0x49, 0x71, 0x8b, 0xba, 0xbf, 0xc7, 0xd5, 0x01, 0x0b, 0x19, 0x2c, 0x4d, 0x5d, 0x8f, 0xbc, 0xc5, 0xda, 0xdc, 0xeb, 0xf4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x21, 0x2c, 0x39, }, .sig_len = 2420, }, }; #define ML_DSA_KAT_TV_NUM sizeof(ml_dsa_kat_tv)/sizeof(struct ML_DSA_TEST_VECTOR) opencryptoki-opencryptoki-451d99c/testcases/crypto/ml_dsa_func.c000066400000000000000000001347741520105705100253000ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2026 * * 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 "mechtable.h" #include "ml_dsa.h" /** * Support for ML-DSA keys and signatures * with oid = 2.16.840.1.101.3.4.3.xxx * * Only SignInit and Sign(Single) is supported with ML-DSA. * SignUpdate/SignFinal are only supported with Hash-ML-DSA. Same with Verify. */ typedef struct signVerifyParam { const char *name; CK_MECHANISM mech; CK_ULONG inputlen; CK_ULONG chunks; CK_ULONG chunklen[10]; } _signVerifyParam; CK_BYTE context[] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }; CK_SIGN_ADDITIONAL_CONTEXT no_ctx_preferred = { CKH_HEDGE_PREFERRED, NULL, 0 }; CK_SIGN_ADDITIONAL_CONTEXT no_ctx_required = { CKH_HEDGE_REQUIRED, NULL, 0 }; CK_SIGN_ADDITIONAL_CONTEXT no_ctx_deterministic = { CKH_DETERMINISTIC_REQUIRED, NULL, 0 }; CK_SIGN_ADDITIONAL_CONTEXT with_ctx_preferred = { CKH_HEDGE_PREFERRED, context, sizeof(context) }; CK_HASH_SIGN_ADDITIONAL_CONTEXT hash_no_ctx_preferred_sha512 = { CKH_HEDGE_PREFERRED, NULL, 0, CKM_SHA512 }; CK_HASH_SIGN_ADDITIONAL_CONTEXT hash_ctx_preferred_sha3_256 = { CKH_HEDGE_PREFERRED, context, sizeof(context), CKM_SHA3_256 }; const _signVerifyParam signVerifyInput[] = { {"CKM_ML_DSA empty message", {CKM_ML_DSA, NULL, 0}, 0, 0, { 0, }}, {"CKM_ML_DSA 1 byte message", {CKM_ML_DSA, NULL, 0}, 1, 0, { 0, }}, {"CKM_ML_DSA 32 bytes message", {CKM_ML_DSA, NULL, 0}, 32, 0, { 0, }}, {"CKM_ML_DSA 59 bytes message", {CKM_ML_DSA, NULL, 0}, 59, 0, { 0, }}, {"CKM_ML_DSA 100 bytes message (multi-part)", {CKM_ML_DSA, NULL, 0}, 100, 3, { 25, 50, 25, }}, {"CKM_ML_DSA 3000 bytes message (multi-part)", {CKM_ML_DSA, NULL, 0}, 3000, 3, { 1000, 1000, 1000, }}, {"CKM_ML_DSA no context, hedge=preferred", {CKM_ML_DSA, &no_ctx_preferred, sizeof(no_ctx_preferred)}, 32, 0, { 0, }}, {"CKM_ML_DSA no context, hedge=required", {CKM_ML_DSA, &no_ctx_required, sizeof(no_ctx_required)}, 32, 0, { 0, }}, {"CKM_ML_DSA no context, hedge=deterministic", {CKM_ML_DSA, &no_ctx_deterministic, sizeof(no_ctx_required)}, 32, 0, { 0, }}, {"CKM_ML_DSA with context, hedge=preferred", {CKM_ML_DSA, &with_ctx_preferred, sizeof(with_ctx_preferred)}, 32, 0, { 0, }}, {"CKM_HASH_ML_DSA 64 bytes prehashed message (SHA512)", {CKM_HASH_ML_DSA, &hash_no_ctx_preferred_sha512, sizeof(hash_no_ctx_preferred_sha512)}, 64, 0, { 0, }}, {"CKM_HASH_ML_DSA 32 bytes prehashed message (SHA3-256) with context", {CKM_HASH_ML_DSA, &hash_ctx_preferred_sha3_256, sizeof(hash_ctx_preferred_sha3_256)}, 32, 0, { 0, }}, {"CKM_HASH_ML_DSA_SHA224 100 bytes message single", {CKM_HASH_ML_DSA_SHA224, NULL, 0}, 100, 0, { 0, }}, {"CKM_HASH_ML_DSA_SHA265 100 bytes message single", {CKM_HASH_ML_DSA_SHA256, NULL, 0}, 100, 0, { 0, }}, {"CKM_HASH_ML_DSA_SHA384 100 bytes message single", {CKM_HASH_ML_DSA_SHA384, NULL, 0}, 100, 0, { 0, }}, {"CKM_HASH_ML_DSA_SHA512 100 bytes message single", {CKM_HASH_ML_DSA_SHA512, NULL, 0}, 100, 0, { 0, }}, {"CKM_HASH_ML_DSA_SHA3_224 100 bytes message single", {CKM_HASH_ML_DSA_SHA3_224, NULL, 0}, 100, 0, { 0, }}, {"CKM_HASH_ML_DSA_SHA3_256 100 bytes message single", {CKM_HASH_ML_DSA_SHA3_256, NULL, 0}, 100, 0, { 0, }}, {"CKM_HASH_ML_DSA_SHA3_384 100 bytes message single", {CKM_HASH_ML_DSA_SHA3_384, NULL, 0}, 100, 0, { 0, }}, {"CKM_HASH_ML_DSA_SHA3_512 100 bytes message single", {CKM_HASH_ML_DSA_SHA3_512, NULL, 0}, 100, 0, { 0, }}, {"CKM_HASH_ML_DSA_SHAKE128 100 bytes message single", {CKM_HASH_ML_DSA_SHAKE128, NULL, 0}, 100, 0, { 0, }}, {"CKM_HASH_ML_DSA_SHAKE256 100 bytes message single", {CKM_HASH_ML_DSA_SHAKE256, NULL, 0}, 100, 0, { 0, }}, {"CKM_HASH_ML_DSA_SHA224 100 bytes message multi", {CKM_HASH_ML_DSA_SHA224, NULL, 0}, 100, 3, { 20, 50, 30, }}, {"CKM_HASH_ML_DSA_SHA265 100 bytes message multi", {CKM_HASH_ML_DSA_SHA256, NULL, 0}, 100, 3, { 20, 50, 30, }}, {"CKM_HASH_ML_DSA_SHA384 100 bytes message multi", {CKM_HASH_ML_DSA_SHA384, NULL, 0}, 100, 3, { 20, 50, 30, }}, {"CKM_HASH_ML_DSA_SHA512 100 bytes message multi", {CKM_HASH_ML_DSA_SHA512, NULL, 0}, 100, 3, { 20, 50, 30, }}, {"CKM_HASH_ML_DSA_SHA3_224 100 bytes message multi", {CKM_HASH_ML_DSA_SHA3_224, NULL, 0}, 100, 3, { 20, 50, 30, }}, {"CKM_HASH_ML_DSA_SHA3_256 100 bytes message multi", {CKM_HASH_ML_DSA_SHA3_256, NULL, 0}, 100, 3, { 20, 50, 30, }}, {"CKM_HASH_ML_DSA_SHA3_384 100 bytes message multi", {CKM_HASH_ML_DSA_SHA3_384, NULL, 0}, 100, 3, { 20, 50, 30, }}, {"CKM_HASH_ML_DSA_SHA3_512 100 bytes message multi", {CKM_HASH_ML_DSA_SHA3_512, NULL, 0}, 100, 3, { 20, 50, 30, }}, {"CKM_HASH_ML_DSA_SHAKE128 100 bytes message multi", {CKM_HASH_ML_DSA_SHAKE128, NULL, 0}, 100, 3, { 20, 50, 30, }}, {"CKM_HASH_ML_DSA_SHAKE256 100 bytes message multi", {CKM_HASH_ML_DSA_SHAKE256, NULL, 0}, 100, 3, { 20, 50, 30, }}, }; typedef struct variant_info { const char *name; CK_ML_DSA_PARAMETER_SET_TYPE parameter_set; } _variant_info; const _variant_info variants[] = { { "ML_DSA_44", CKP_ML_DSA_44, }, { "ML_DSA_65", CKP_ML_DSA_65, }, { "ML_DSA_87", CKP_ML_DSA_87, }, }; const CK_ULONG num_variants = sizeof(variants) / sizeof(_variant_info); static CK_BBOOL chech_for_skip(CK_MECHANISM *mech, CK_RV rc) { switch (rc) { case CKR_MECHANISM_PARAM_INVALID: switch (mech->mechanism) { case CKM_HASH_ML_DSA: if (is_cca_token(SLOT_ID) && mech->pParameter != NULL && mech->pParameter != NULL && ((CK_HASH_SIGN_ADDITIONAL_CONTEXT *) mech->pParameter)->hash != CKM_SHA512) { testcase_skip("Pre-hash sign with %s is not supported by the " "CCA token", p11_get_ckm(&mechtable_funcs, ((CK_HASH_SIGN_ADDITIONAL_CONTEXT *) mech->pParameter)->hash)); return TRUE; } if (mech->pParameter != NULL && ((CK_HASH_SIGN_ADDITIONAL_CONTEXT *) mech->pParameter)->hedgeVariant == CKH_DETERMINISTIC_REQUIRED) { testcase_skip("Sign with CKH_DETERMINISTIC_REQUIRED is not " "supported"); return TRUE; } if (mech->pParameter != NULL && ((CK_HASH_SIGN_ADDITIONAL_CONTEXT *) mech->pParameter)->ulContextLen > 0) { testcase_skip("Sign with Context not supported"); return TRUE; } break; default: if (mech->pParameter != NULL && ((CK_SIGN_ADDITIONAL_CONTEXT *) mech->pParameter)->hedgeVariant == CKH_DETERMINISTIC_REQUIRED) { testcase_skip("Sign with CKH_DETERMINISTIC_REQUIRED is not " "supported"); return TRUE; } if (mech->pParameter != NULL && ((CK_SIGN_ADDITIONAL_CONTEXT *) mech->pParameter)->ulContextLen > 0) { testcase_skip("Sign with Context not supported"); return TRUE; } break; } break; case CKR_MECHANISM_INVALID: if (mech->mechanism == CKM_ML_DSA) { testcase_skip("Multi-part sign/verify with CKM_ML_DSA is not " "supported by slot %u", (unsigned int) SLOT_ID); return TRUE; } break; case CKR_KEY_SIZE_RANGE: testcase_skip("Key size of form is not supported by slot %u", (unsigned int) SLOT_ID); return TRUE; default: break; } return FALSE; } CK_RV run_SignVerifyMLDSA(CK_SESSION_HANDLE session, CK_MECHANISM *mech, CK_ULONG inputlen, CK_ULONG chunks, const CK_ULONG chunklen[], CK_OBJECT_HANDLE priv_key, CK_OBJECT_HANDLE publ_key) { CK_BYTE_PTR data = NULL, signature = NULL; CK_ULONG i, signaturelen, ofs; CK_RV rc; /* Query the slot, check if this mech if supported */ if (!mech_supported(SLOT_ID, mech->mechanism)) { testcase_notice("Slot %u doesn't support %s", (unsigned int) SLOT_ID, p11_get_ckm(&mechtable_funcs, mech->mechanism)); rc = CKR_MECHANISM_PARAM_INVALID; goto testcase_cleanup; } data = calloc(inputlen > 0 ? inputlen : 1, sizeof(CK_BYTE)); 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) { if (chech_for_skip(mech, rc)) { rc = CKR_OK; goto testcase_cleanup; } testcase_error("C_SignInit rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } if (chunks == 0) { /* Single part sign */ rc = funcs->C_Sign(session, data, inputlen, NULL, &signaturelen); if (rc != CKR_OK) { if (chech_for_skip(mech, rc)) { rc = CKR_OK; goto testcase_cleanup; } testcase_error("C_Sign rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } signature = calloc(signaturelen, sizeof(CK_BYTE)); 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; } } else { /* Multi part sign */ for (i = 0, ofs = 0; i < chunks; i++) { rc = funcs->C_SignUpdate(session, data + ofs, chunklen[i]); if (rc != CKR_OK) { if (chech_for_skip(mech, rc)) { rc = CKR_OK; goto testcase_cleanup; } testcase_error("C_SignUpdate rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } ofs += chunklen[i]; } rc = funcs->C_SignFinal(session, NULL, &signaturelen); if (rc != CKR_OK) { if (chech_for_skip(mech, rc)) { rc = CKR_OK; goto testcase_cleanup; } testcase_error("C_SignFinal rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } signature = calloc(signaturelen, sizeof(CK_BYTE)); if (signature == NULL) { testcase_error("Can't allocate memory for %lu bytes", sizeof(CK_BYTE) * signaturelen); rc = -1; goto testcase_cleanup; } rc = funcs->C_SignFinal(session, signature, &signaturelen); if (rc != CKR_OK) { testcase_error("C_SignFinal 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; } if (chunks == 0) { /* Single part verify */ 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; } } else { /* Multi part verify */ for (i = 0, ofs = 0; i < chunks; i++) { rc = funcs->C_VerifyUpdate(session, data + ofs, chunklen[i]); if (rc != CKR_OK) { testcase_error("C_VerifyUpdate rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } ofs += chunklen[i]; } rc = funcs->C_VerifyFinal(session, signature, signaturelen); if (rc != CKR_OK) { testcase_error("C_VerifyFinal 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; } for (i = 0, ofs = 0; i < chunks; i++) { rc = funcs->C_VerifyUpdate(session, data + ofs, chunklen[i]); if (rc != CKR_OK) { testcase_error("C_VerifyUpdate rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } ofs += chunklen[i]; } 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; } } rc = CKR_OK; testcase_cleanup: if (data) free(data); if (signature) free(signature); return rc; } CK_RV run_GenerateMLDSAKeyPairSignVerify( CK_IBM_CCA_ML_DSA_KEY_MODE_TYPE cca_ml_dsa_mode) { 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, i; CK_FLAGS flags; CK_RV rc; if (!is_cca_token(SLOT_ID) && cca_ml_dsa_mode == CK_IBM_CCA_ML_DSA_PREHASH_KEY) return CKR_OK; if (is_cca_token(SLOT_ID)) testcase_begin("Starting ML-DSA generate key pair (CCA %s-ML-DSA).", cca_ml_dsa_mode == CK_IBM_CCA_ML_DSA_PURE_KEY ? "Pure" : "Prehash"); else testcase_begin("Starting ML-DSA generate key pair."); testcase_rw_session(); testcase_user_login(); mech.mechanism = CKM_ML_DSA_KEY_PAIR_GEN; mech.ulParameterLen = 0; mech.pParameter = NULL; /* query the slot, check if this mech is supported */ if (!mech_supported(SLOT_ID, mech.mechanism)) { testcase_skip("Slot %u doesn't support %s", (unsigned int) SLOT_ID, p11_get_ckm(&mechtable_funcs, mech.mechanism)); rc = CKR_OK; goto testcase_cleanup; } for (i = 0; i < num_variants; i++) { /* Setup attributes for public/private ML-DSA key */ CK_BBOOL attr_sign = TRUE; CK_BBOOL attr_verify = TRUE; CK_ATTRIBUTE ml_dsa_attr_private[] = { {CKA_SIGN, &attr_sign, sizeof(CK_BBOOL)}, {CKA_PARAMETER_SET, (CK_BYTE *)&variants[i].parameter_set, sizeof(CK_ML_DSA_PARAMETER_SET_TYPE)}, {CKA_IBM_CCA_ML_DSA_KEY_MODE, &cca_ml_dsa_mode, sizeof(cca_ml_dsa_mode)}, }; CK_ATTRIBUTE ml_dsa_attr_public[] = { {CKA_VERIFY, &attr_verify, sizeof(CK_BBOOL)}, {CKA_PARAMETER_SET, (CK_BYTE *)&variants[i].parameter_set, sizeof(CK_ML_DSA_PARAMETER_SET_TYPE)}, }; CK_ULONG num_ml_dsa_attrs_private = sizeof(ml_dsa_attr_private) / sizeof(CK_ATTRIBUTE); CK_ULONG num_ml_dsa_attrs_public = sizeof(ml_dsa_attr_public) / sizeof(CK_ATTRIBUTE); if (!is_cca_token(SLOT_ID)) num_ml_dsa_attrs_private--; /* Generate ML_DSA key pair */ rc = funcs->C_GenerateKeyPair(session, &mech, ml_dsa_attr_public, num_ml_dsa_attrs_public, ml_dsa_attr_private, num_ml_dsa_attrs_private, &publ_key, &priv_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("C_GenerateKeyPair with %s not supported", variants[i].name); goto next; } else { testcase_new_assertion(); testcase_fail("C_GenerateKeyPair with %s and valid input " "failed, rc=%s", variants[i].name, p11_get_ckr(rc)); goto testcase_cleanup; } } testcase_new_assertion(); testcase_pass("Generate ML-DSA key pair with %s passed.", variants[i].name); /* Sign/verify with this key pair */ for (j = 0; j < (sizeof(signVerifyInput) / sizeof(_signVerifyParam)); j++) { /* Skip mechanisms that do not fit to the CCA ML-DSA key mode */ if (is_cca_token(SLOT_ID) && cca_ml_dsa_mode == CK_IBM_CCA_ML_DSA_PURE_KEY && signVerifyInput[j].mech.mechanism != CKM_ML_DSA) continue; if (is_cca_token(SLOT_ID) && cca_ml_dsa_mode == CK_IBM_CCA_ML_DSA_PREHASH_KEY && signVerifyInput[j].mech.mechanism == CKM_ML_DSA) continue; if (!mech_supported(SLOT_ID, signVerifyInput[j].mech.mechanism)) { testcase_skip("Slot %u doesn't support %s", (unsigned int) SLOT_ID, p11_get_ckm(&mechtable_funcs, signVerifyInput[j].mech.mechanism)); continue; } rc = run_SignVerifyMLDSA(session, (CK_MECHANISM *)&signVerifyInput[j].mech, signVerifyInput[j].inputlen, signVerifyInput[j].chunks, signVerifyInput[j].chunklen, priv_key, publ_key); if (rc == CKR_MECHANISM_INVALID) { testcase_skip("run_SignVerifyMLDSA with %s index=%lu %s.", variants[i].name, j, signVerifyInput[j].name); } else if (rc != 0) { testcase_new_assertion(); testcase_fail("run_SignVerifyMLDSA with %s failed index=%lu %s.", variants[i].name, j, signVerifyInput[j].name); if (funcs3 != NULL) funcs3->C_SessionCancel(session, CKF_SIGN | CKF_VERIFY); continue; } else { testcase_new_assertion(); testcase_pass("*Sign & verify with %s j=%lu %s passed.", variants[i].name, j, signVerifyInput[j].name); } } next: if (publ_key != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, publ_key); publ_key = CK_INVALID_HANDLE; if (priv_key != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, priv_key); priv_key = CK_INVALID_HANDLE; } 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_ImportMLDSAKeyPairSignVerify(void) { 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 sign_mech = {CKM_ML_DSA, NULL, 0}; CK_RV rc; testcase_rw_session(); testcase_user_login(); /* query the slot, check if this mech is supported */ if (!mech_supported(SLOT_ID, CKM_ML_DSA)) { testcase_skip("Slot %u doesn't support CKM_ML_DSA", (unsigned int) SLOT_ID); rc = CKR_OK; goto testcase_cleanup; } for (i = 0; i < ML_DSA_TV_NUM; i++) { testcase_begin("Starting ML-DSA import key pair, Sign/Verify, %s " "index=%lu", ml_dsa_tv[i].name, i); /* Create ML-DSA private key */ rc = create_ML_DSA_PrivateKey(session, ml_dsa_tv[i].parameter_set, ml_dsa_tv[i].priv, ml_dsa_tv[i].priv_len, ml_dsa_tv[i].priv_seed, ml_dsa_tv[i].priv_seed_len, &priv_key, is_cca_token(SLOT_ID), CK_IBM_CCA_ML_DSA_PURE_KEY); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) { if (is_cca_token(SLOT_ID) && ml_dsa_tv[i].priv_seed_len == 0) testcase_skip("CCA does not support private key import " "without seed"); else testcase_skip("C_CreateObject with %s not supported", ml_dsa_tv[i].name); continue; } else if (rc == CKR_POLICY_VIOLATION) { testcase_skip("ML-DSA key import is not allowed by policy"); continue; } testcase_new_assertion(); testcase_fail("C_CreateObject (ML-DSA Private Key) failed at " "i=%lu, rc=%s", i, p11_get_ckr(rc)); goto testcase_cleanup; } testcase_new_assertion(); testcase_pass("*Import ML-DSA private key (%s) index=%lu passed.", ml_dsa_tv[i].name, i); /* Create ML-DSA public key */ rc = create_ML_DSA_PublicKey(session, ml_dsa_tv[i].parameter_set, ml_dsa_tv[i].pub, ml_dsa_tv[i].pub_len, &publ_key, is_cca_token(SLOT_ID), CK_IBM_CCA_ML_DSA_PURE_KEY); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("C_CreateObject with %s not supported", ml_dsa_tv[i].name); goto testcase_cleanup; } else if (rc == CKR_POLICY_VIOLATION) { testcase_skip("ML-DSA key import is not allowed by policy"); goto testcase_cleanup; } testcase_new_assertion(); testcase_fail("C_CreateObject (ML-DSA Public Key) failed at " "i=%lu, rc=%s", i, p11_get_ckr(rc)); goto testcase_cleanup; } testcase_new_assertion(); testcase_pass("*Import ML-DSA public key (%s) index=%lu passed.", ml_dsa_tv[i].name, i); /* Test sign/verify */ rc = run_SignVerifyMLDSA(session, &sign_mech, 32, 0, NULL, priv_key, publ_key); if (rc == CKR_MECHANISM_INVALID) { testcase_skip("run_SignVerifyMLDSA index=%lu.", i); } else if (rc != 0) { testcase_new_assertion(); testcase_fail("run_SignVerifyMLDSA failed index=%lu.", i); goto testcase_cleanup; } else { testcase_new_assertion(); testcase_pass("*Sign & verify, 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(tmp_len, sizeof(CK_BYTE)); 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_ML_DSA; CK_OBJECT_HANDLE tmp_key = CK_INVALID_HANDLE; CK_BYTE unwrap_label[] = "unwrapped_private_ML_DSA_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_TransferMLDSAKeyPairSignVerify(void) { 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_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; CK_MECHANISM sign_mech = {CKM_ML_DSA, NULL, 0}; testcase_rw_session(); testcase_user_login(); /* query the slot, check if this mech is supported */ if (!mech_supported(SLOT_ID, CKM_ML_DSA)) { testcase_skip("Slot %u doesn't support CKM_ML_DSA", (unsigned int) SLOT_ID); rc = CKR_OK; goto testcase_cleanup; } if (!mech_supported(SLOT_ID, CKM_AES_KEY_GEN)) { testcase_skip("Slot %u doesn't support CKM_AES_KEY_GEN", (unsigned int) SLOT_ID); rc = CKR_OK; goto testcase_cleanup; } if (!mech_supported_flags(SLOT_ID, CKM_AES_CBC_PAD, CKF_WRAP)) { testcase_skip("Slot %u doesn't support key wrapping with " "CKM_AES_CBC_PAD", (unsigned int) SLOT_ID); rc = CKR_OK; goto testcase_cleanup; } for (i = 0; i < ML_DSA_TV_NUM; i++) { testcase_begin("Starting ML-DSA transfer key pair, Sign/Verify %s " "index=%lu.", ml_dsa_tv[i].name, i); /* Create ML-DSA private key */ rc = create_ML_DSA_PrivateKey(session, ml_dsa_tv[i].parameter_set, ml_dsa_tv[i].priv, ml_dsa_tv[i].priv_len, ml_dsa_tv[i].priv_seed, ml_dsa_tv[i].priv_seed_len, &priv_key, is_cca_token(SLOT_ID), CK_IBM_CCA_ML_DSA_PURE_KEY); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) { if (is_cca_token(SLOT_ID) && ml_dsa_tv[i].priv_seed_len == 0) testcase_skip("CCA does not support private key import " "without seed"); else testcase_skip("C_CreateObject with %s not supported", ml_dsa_tv[i].name); continue; } else if (rc == CKR_POLICY_VIOLATION) { testcase_skip("ML-DSA key import is not allowed by policy"); continue; } testcase_new_assertion(); testcase_fail("C_CreateObject (ML-DSA Private Key) failed at " "i=%lu, rc=%s", i, p11_get_ckr(rc)); goto testcase_cleanup; } testcase_new_assertion(); testcase_pass("*Import ML-DSA private key (%s) index=%lu passed.", ml_dsa_tv[i].name, i); /* Create ML-DSA public key */ rc = create_ML_DSA_PublicKey(session, ml_dsa_tv[i].parameter_set, ml_dsa_tv[i].pub, ml_dsa_tv[i].pub_len, &publ_key, is_cca_token(SLOT_ID), CK_IBM_CCA_ML_DSA_PURE_KEY); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("C_CreateObject with %s not supported", ml_dsa_tv[i].name); goto testcase_cleanup; } else if (rc == CKR_POLICY_VIOLATION) { testcase_skip("ML-DSA key import is not allowed by policy"); goto testcase_cleanup; } testcase_new_assertion(); testcase_fail("C_CreateObject (ML-DSA Public Key) failed at " "i=%lu,rc=%s", i, p11_get_ckr(rc)); goto testcase_cleanup; } testcase_new_assertion(); testcase_pass("*Import ML-DSA public key (%s) index=%lu passed.", ml_dsa_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, CK_TRUE, &wkey_mech, &secret_key); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("AES key generation is not allowed by policy"); goto testcase_cleanup; } 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 ML-DSA 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 ML-DSA private key (%s) index=%lu passed.", ml_dsa_tv[i].name, i); /* Unwrap ML-DSA private key */ rc = unwrapKey(session, &wrap_mech, wrapped_key, wrapped_keylen, secret_key, &unwrapped_key); testcase_new_assertion(); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("Key size or form is not supported by slot %lu", SLOT_ID); goto testcase_cleanup; } testcase_error("unwrapKey, rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } testcase_pass("*Unwrap ML-DSA private key (%s) index=%lu passed.", ml_dsa_tv[i].name, i); free(wrapped_key); wrapped_key = NULL; /* * Test sign/verify using unwrapped private key and untouched public * key */ rc = run_SignVerifyMLDSA(session, &sign_mech, 32, 0, NULL, unwrapped_key, publ_key); if (rc == CKR_MECHANISM_INVALID) { testcase_skip("run_SignVerifyMLDSA index=%lu.", i); } else if (rc != 0) { testcase_new_assertion(); testcase_fail("run_SignVerifyMLDSA failed index=%lu.", i); goto testcase_cleanup; } else { testcase_new_assertion(); testcase_pass("*Sign & verify, 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; } CK_RV run_KATMLDSAKeyPairSignVerify(void) { 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_BYTE_PTR signature = NULL; CK_ULONG signaturelen; CK_RV rc; testcase_rw_session(); testcase_user_login(); for (i = 0; i < ML_DSA_KAT_TV_NUM; i++) { testcase_begin("Starting ML-DSA KAT, %s index=%lu", ml_dsa_kat_tv[i].name, i); /* query the slot, check if this mech is supported */ if (!mech_supported(SLOT_ID, ml_dsa_kat_tv[i].mech.mechanism)) { testcase_skip("Slot %u doesn't support %s", (unsigned int) SLOT_ID, p11_get_ckm(&mechtable_funcs, ml_dsa_kat_tv[i].mech.mechanism)); rc = CKR_OK; goto testcase_cleanup; } /* Create ML-DSA private key */ rc = create_ML_DSA_PrivateKey(session, ml_dsa_kat_tv[i].parameter_set, ml_dsa_kat_tv[i].priv, ml_dsa_kat_tv[i].priv_len, ml_dsa_kat_tv[i].priv_seed, ml_dsa_kat_tv[i].priv_seed_len, &priv_key, is_cca_token(SLOT_ID), ml_dsa_kat_tv[i].mech.mechanism == CKM_ML_DSA ? CK_IBM_CCA_ML_DSA_PURE_KEY : CK_IBM_CCA_ML_DSA_PREHASH_KEY); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) { if (is_cca_token(SLOT_ID) && ml_dsa_kat_tv[i].priv_seed_len == 0) testcase_skip("CCA does not support private key import " "without seed"); else testcase_skip("C_CreateObject with %s not supported", ml_dsa_tv[i].name); continue; } else if (rc == CKR_POLICY_VIOLATION) { testcase_skip("ML-DSA key import is not allowed by policy"); continue; } testcase_new_assertion(); testcase_fail("C_CreateObject (ML-DSA Private Key) failed at " "i=%lu, rc=%s", i, p11_get_ckr(rc)); goto testcase_cleanup; } testcase_new_assertion(); testcase_pass("*Import ML-DSA private key (%s) index=%lu passed.", ml_dsa_kat_tv[i].name, i); /* Create ML-DSA public key */ rc = create_ML_DSA_PublicKey(session, ml_dsa_kat_tv[i].parameter_set, ml_dsa_kat_tv[i].pub, ml_dsa_kat_tv[i].pub_len, &publ_key, is_cca_token(SLOT_ID), ml_dsa_kat_tv[i].mech.mechanism == CKM_ML_DSA ? CK_IBM_CCA_ML_DSA_PURE_KEY : CK_IBM_CCA_ML_DSA_PREHASH_KEY); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("C_CreateObject with %s not supported", ml_dsa_kat_tv[i].name); goto testcase_cleanup; } else if (rc == CKR_POLICY_VIOLATION) { testcase_skip("ML-DSA key import is not allowed by policy"); goto testcase_cleanup; } testcase_new_assertion(); testcase_fail("C_CreateObject (ML-DSA Public Key) failed at " "i=%lu, rc=%s", i, p11_get_ckr(rc)); goto testcase_cleanup; } testcase_new_assertion(); testcase_pass("*Import ML-DSA public key (%s) index=%lu passed.", ml_dsa_kat_tv[i].name, i); /* Sign with known message */ rc = funcs->C_SignInit(session, &ml_dsa_kat_tv[i].mech, priv_key); if (rc != CKR_OK) { if (rc == CKR_MECHANISM_PARAM_INVALID && ml_dsa_kat_tv[i].mech.pParameter != NULL && ((CK_SIGN_ADDITIONAL_CONTEXT *) ml_dsa_kat_tv[i].mech.pParameter)->hedgeVariant == CKH_DETERMINISTIC_REQUIRED) { testcase_skip("Sign with CKH_DETERMINISTIC_REQUIRED not " "supported"); rc = CKR_OK; goto testcase_cleanup; } if (rc == CKR_MECHANISM_PARAM_INVALID && ml_dsa_kat_tv[i].mech.pParameter != NULL && ((CK_SIGN_ADDITIONAL_CONTEXT *) ml_dsa_kat_tv[i].mech.pParameter)->ulContextLen > 0) { testcase_skip("Sign with Context not supported"); rc = CKR_OK; goto testcase_cleanup; } testcase_error("C_SignInit rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } rc = funcs->C_Sign(session, ml_dsa_kat_tv[i].msg, ml_dsa_kat_tv[i].msg_len, NULL, &signaturelen); if (rc != CKR_OK) { if (rc == CKR_MECHANISM_PARAM_INVALID && ml_dsa_kat_tv[i].mech.pParameter != NULL && ((CK_SIGN_ADDITIONAL_CONTEXT *) ml_dsa_kat_tv[i].mech.pParameter)->hedgeVariant == CKH_DETERMINISTIC_REQUIRED) { testcase_skip("Sign with hedge type " "CKH_DETERMINISTIC_REQUIRED is not " "supported"); rc = CKR_OK; goto testcase_cleanup; } if (rc == CKR_MECHANISM_PARAM_INVALID && ml_dsa_kat_tv[i].mech.pParameter != NULL && ((CK_SIGN_ADDITIONAL_CONTEXT *) ml_dsa_kat_tv[i].mech.pParameter)->ulContextLen > 0) { testcase_skip("Sign with non-empty context not supported"); rc = CKR_OK; goto testcase_cleanup; } testcase_error("C_Sign rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } signature = calloc(signaturelen, sizeof(CK_BYTE)); 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, ml_dsa_kat_tv[i].msg, ml_dsa_kat_tv[i].msg_len, 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, &ml_dsa_kat_tv[i].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, ml_dsa_kat_tv[i].msg, ml_dsa_kat_tv[i].msg_len, signature, signaturelen); if (rc != CKR_OK) { testcase_error("C_Verify rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } /* Check if known signature is produced */ testcase_new_assertion(); if (ml_dsa_kat_tv[i].sig_len != signaturelen || memcmp(ml_dsa_kat_tv[i].sig, signature, signaturelen) != 0) { testcase_fail("ERROR: The signature does not match the " "expected one (%s) index=%lu", ml_dsa_kat_tv[i].name, i); } else { testcase_pass("*KAT (%s) index=%lu passed.", ml_dsa_kat_tv[i].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)); } rc = funcs->C_DestroyObject(session, priv_key); if (rc != CKR_OK) { testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(rc)); } if (signature != NULL) free(signature); signature = NULL; } 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 (signature != NULL) free(signature); signature = NULL; 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(); rv = run_GenerateMLDSAKeyPairSignVerify(CK_IBM_CCA_ML_DSA_PURE_KEY); rv |= run_GenerateMLDSAKeyPairSignVerify(CK_IBM_CCA_ML_DSA_PREHASH_KEY); rv |= run_ImportMLDSAKeyPairSignVerify(); rv |= run_TransferMLDSAKeyPairSignVerify(); rv |= run_KATMLDSAKeyPairSignVerify(); testcase_print_result(); funcs->C_Finalize(NULL); return testcase_return(rv); } opencryptoki-opencryptoki-451d99c/testcases/crypto/ml_kem.h000066400000000000000000005271471520105705100242770ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2026 * * 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 */ struct ML_KEM_TEST_VECTOR { char *name; CK_ULONG parameter_set; CK_ULONG priv_len; CK_BYTE priv[8192]; CK_ULONG priv_seed_len; CK_BYTE priv_seed[64]; CK_BYTE pub[8192]; CK_ULONG pub_len; }; struct ML_KEM_TEST_VECTOR ml_kem_tv[] = { { .name = "ML-KEM 512 (priv only)", .parameter_set = CKP_ML_KEM_512, .priv = { 0x71, 0x4a, 0x39, 0x62, 0x00, 0xb3, 0x55, 0xa2, 0x01, 0x5d, 0x74, 0x70, 0x64, 0x9a, 0x8a, 0xe2, 0xb3, 0x90, 0xa1, 0x21, 0x3c, 0xc4, 0xca, 0x51, 0x0f, 0x86, 0x14, 0x0b, 0x31, 0x36, 0xcb, 0xbc, 0x0f, 0x97, 0x3c, 0x74, 0xa7, 0x40, 0x85, 0xe4, 0x85, 0x94, 0x68, 0x78, 0x1b, 0xc6, 0xa9, 0x6b, 0xbf, 0x43, 0x03, 0xc5, 0x40, 0x68, 0xbf, 0xc8, 0xab, 0x66, 0x58, 0x6e, 0xfa, 0xca, 0x34, 0x54, 0xd5, 0xa5, 0xec, 0x88, 0x4b, 0x8f, 0x77, 0xbb, 0x8b, 0x30, 0x80, 0x28, 0x3a, 0x88, 0x67, 0x35, 0x0e, 0x9d, 0x56, 0xa7, 0x1b, 0x75, 0xcf, 0xef, 0x71, 0x97, 0x0a, 0xfa, 0x29, 0x8c, 0x4c, 0x36, 0x5b, 0x37, 0x4a, 0x58, 0x86, 0x55, 0x8a, 0xa2, 0x44, 0x5a, 0x35, 0x67, 0xa3, 0x63, 0x9e, 0x32, 0x01, 0x6f, 0x7d, 0x76, 0xcd, 0xb9, 0xb7, 0x96, 0xd2, 0x56, 0xc4, 0x95, 0x09, 0x2f, 0x74, 0xc4, 0x48, 0xbd, 0xb6, 0x7c, 0x8d, 0x70, 0xb9, 0xd8, 0x27, 0x52, 0x4d, 0x45, 0xba, 0x43, 0x61, 0x2e, 0x1d, 0x5b, 0x39, 0x2e, 0x14, 0x0e, 0x8a, 0x77, 0x38, 0xf6, 0xbc, 0x33, 0xa5, 0x05, 0xc1, 0xec, 0xe0, 0x86, 0x65, 0x8c, 0x5a, 0x4e, 0x88, 0x20, 0x40, 0x6a, 0x6d, 0x6e, 0xa4, 0x08, 0x51, 0xc3, 0x31, 0x22, 0xc8, 0x54, 0x8f, 0xa3, 0x33, 0x48, 0x16, 0x36, 0x79, 0x29, 0x61, 0x80, 0x69, 0x91, 0x7a, 0x27, 0x75, 0x83, 0x0c, 0xb7, 0xa5, 0xf8, 0xbd, 0x71, 0xba, 0x13, 0x6a, 0x26, 0x0c, 0x5e, 0x37, 0xab, 0x08, 0xc2, 0xb8, 0x4f, 0xe0, 0xc2, 0xcb, 0x78, 0x8a, 0xe8, 0xba, 0xac, 0xae, 0x5a, 0x26, 0x62, 0x8b, 0x3e, 0x3a, 0xf4, 0x4b, 0x35, 0x18, 0xa4, 0x44, 0xac, 0x5e, 0x29, 0x14, 0x65, 0x3d, 0x71, 0x25, 0xa3, 0xb8, 0x67, 0x02, 0x74, 0xc0, 0xb1, 0x68, 0x39, 0x60, 0xa0, 0x68, 0x0a, 0x7a, 0x44, 0xf3, 0x36, 0x77, 0x71, 0x98, 0x4f, 0x8b, 0x82, 0x77, 0xc1, 0xe8, 0x3b, 0xc7, 0xd0, 0x84, 0xac, 0xf9, 0x6c, 0x9f, 0x61, 0x73, 0x74, 0x36, 0x81, 0x8f, 0x28, 0x4f, 0x91, 0x4a, 0x20, 0xea, 0x26, 0xb4, 0x82, 0x67, 0x39, 0x31, 0x33, 0x5d, 0xd4, 0x8a, 0xbc, 0xe4, 0xd9, 0x15, 0x51, 0x3b, 0x91, 0x23, 0x48, 0xbb, 0x45, 0xe0, 0x76, 0x69, 0xbb, 0x57, 0x4e, 0xfa, 0x01, 0xda, 0x61, 0x79, 0x6a, 0x03, 0x43, 0x78, 0x8b, 0xbf, 0x36, 0x34, 0xa3, 0x75, 0x6a, 0x47, 0x00, 0x50, 0x04, 0x52, 0x74, 0x29, 0x5b, 0x2a, 0x72, 0xb9, 0x49, 0x0d, 0xc7, 0x49, 0x53, 0xd2, 0x22, 0x85, 0x3f, 0x17, 0x99, 0x05, 0x18, 0x7f, 0x14, 0x0b, 0xa3, 0x3f, 0x67, 0x1c, 0x47, 0x9a, 0x63, 0x3d, 0xf1, 0x7a, 0x37, 0xa6, 0x3b, 0xce, 0x51, 0x10, 0x9a, 0x97, 0x6b, 0x80, 0x29, 0x64, 0x5c, 0x77, 0x5c, 0xdf, 0x58, 0x10, 0x14, 0x2b, 0x7a, 0xd6, 0x4c, 0x20, 0x18, 0xe9, 0x30, 0x3f, 0x26, 0x73, 0x6c, 0xe3, 0xa5, 0xad, 0x70, 0xb3, 0xde, 0x8c, 0xb2, 0x52, 0x67, 0x06, 0x28, 0xe0, 0xb5, 0x16, 0x13, 0x7d, 0xf3, 0xdb, 0x4f, 0x32, 0x2a, 0x9a, 0xce, 0x05, 0x8b, 0x8e, 0xc2, 0xae, 0xed, 0x99, 0x73, 0xbb, 0x97, 0xa2, 0x5f, 0x86, 0x28, 0x66, 0xd4, 0x04, 0x14, 0xb5, 0x8a, 0xce, 0x90, 0x59, 0x4a, 0xc3, 0xb4, 0x7c, 0x81, 0xa5, 0x24, 0x11, 0x26, 0x79, 0x25, 0x84, 0x65, 0xd8, 0xb9, 0x6d, 0xaa, 0xcd, 0x7b, 0x9c, 0xad, 0xdc, 0x3c, 0xac, 0xa0, 0x03, 0x5b, 0x26, 0x09, 0xb8, 0x1f, 0xb5, 0x42, 0x55, 0xc4, 0x46, 0x5f, 0x2a, 0x97, 0xaf, 0x58, 0xc1, 0xfb, 0x65, 0x51, 0x7e, 0x70, 0x6d, 0xa9, 0x79, 0xcd, 0xed, 0x55, 0x91, 0x59, 0x84, 0xcb, 0xa6, 0x92, 0x15, 0x28, 0x1b, 0xa2, 0x83, 0xc1, 0x76, 0x3a, 0x3a, 0x59, 0x0d, 0x65, 0x38, 0xb7, 0x66, 0x47, 0x4b, 0x6a, 0xc4, 0x3f, 0xe1, 0x1e, 0x6c, 0x0c, 0x6f, 0xe9, 0xf7, 0x99, 0x43, 0xa3, 0x84, 0x0b, 0x78, 0x92, 0x98, 0x5a, 0x7e, 0x7c, 0x89, 0x72, 0xd3, 0xf7, 0xcc, 0x4a, 0x46, 0x9d, 0xaa, 0x57, 0x21, 0xa4, 0xd6, 0x4d, 0x0a, 0x9b, 0x80, 0x9c, 0xac, 0x01, 0xd2, 0x51, 0x12, 0x2d, 0x3a, 0x74, 0x7c, 0x84, 0x8a, 0xd0, 0x92, 0x6d, 0x8d, 0xd6, 0x1e, 0x41, 0xb9, 0x70, 0x0f, 0xb7, 0x33, 0xcf, 0x7c, 0x5f, 0xad, 0x68, 0x0c, 0xde, 0x24, 0x6c, 0x37, 0x6c, 0xc8, 0xe6, 0x86, 0x3e, 0xfa, 0x54, 0x9f, 0x27, 0xfa, 0x7b, 0x64, 0x43, 0x38, 0xe2, 0xf4, 0x3b, 0x3b, 0xb9, 0x88, 0x27, 0x02, 0x49, 0x0b, 0xa1, 0x8f, 0xf9, 0xe5, 0x25, 0x07, 0x99, 0xa7, 0x02, 0x25, 0xbd, 0xda, 0xa4, 0x34, 0xd9, 0x54, 0x6e, 0xcf, 0x40, 0x0d, 0xfa, 0xab, 0xbe, 0xe3, 0x2b, 0x11, 0x87, 0x7c, 0x36, 0x55, 0xdc, 0x91, 0xf4, 0x8c, 0x13, 0x19, 0x36, 0x1a, 0x7e, 0x50, 0xbf, 0x76, 0x21, 0xcf, 0x22, 0x30, 0x8b, 0xb7, 0x66, 0x72, 0xd3, 0x8b, 0x8f, 0x34, 0x94, 0x16, 0xd0, 0x03, 0x6c, 0x18, 0xe8, 0x7e, 0xfa, 0x6b, 0x53, 0x1a, 0x54, 0x47, 0xd8, 0xe9, 0xcc, 0x37, 0xd8, 0x54, 0xd1, 0xc7, 0x40, 0x07, 0x07, 0xa0, 0xbd, 0xe4, 0x3d, 0xfd, 0x64, 0x03, 0x8d, 0x49, 0x06, 0x2e, 0xcc, 0x3f, 0x58, 0x11, 0x6d, 0x84, 0xa1, 0x3d, 0xc8, 0x61, 0x41, 0xe8, 0x8c, 0x87, 0x92, 0x4c, 0x7c, 0xae, 0x08, 0x29, 0xae, 0xd6, 0x25, 0x99, 0x59, 0x6f, 0x71, 0x36, 0x89, 0x4d, 0x46, 0x49, 0x1d, 0x92, 0x25, 0xa1, 0xa3, 0x75, 0x7a, 0x53, 0xb8, 0x0b, 0x56, 0xc0, 0x98, 0x44, 0x7e, 0x21, 0x17, 0x11, 0xb8, 0x88, 0x1b, 0x11, 0xd8, 0x96, 0xf0, 0xa4, 0x89, 0x78, 0x5b, 0x59, 0x05, 0xa9, 0x87, 0xff, 0x61, 0x9e, 0x77, 0xb4, 0x88, 0x37, 0x9b, 0xa2, 0x96, 0x50, 0x02, 0x94, 0x69, 0x01, 0x20, 0x38, 0x9c, 0x87, 0x94, 0x1d, 0x86, 0x30, 0x14, 0x1f, 0xb1, 0x4b, 0x38, 0x67, 0x85, 0x65, 0x4c, 0x0c, 0xe5, 0xb3, 0x5b, 0x85, 0x49, 0x30, 0x4f, 0x8b, 0x69, 0x67, 0xa0, 0x4b, 0xee, 0x89, 0x0d, 0xbb, 0x04, 0x7a, 0xfe, 0x96, 0x3f, 0x40, 0xf4, 0x69, 0xfe, 0x70, 0x42, 0x76, 0x95, 0xb8, 0xb2, 0xc2, 0xc7, 0xf0, 0x84, 0xc7, 0x42, 0x7b, 0x15, 0x26, 0x02, 0xad, 0x97, 0x86, 0x9c, 0x36, 0x39, 0x40, 0x83, 0xb7, 0x12, 0xa6, 0x66, 0xae, 0x42, 0xf3, 0x18, 0x2c, 0x49, 0xb8, 0x3f, 0x84, 0x6e, 0xe1, 0x5b, 0xca, 0x43, 0xa0, 0x42, 0xc3, 0xb5, 0x0a, 0x87, 0x31, 0x5a, 0x26, 0xe7, 0xc9, 0x26, 0xe0, 0x96, 0x98, 0x06, 0x15, 0xcd, 0x57, 0xc5, 0x60, 0x7c, 0x6e, 0xff, 0xb3, 0x13, 0xec, 0x02, 0xaf, 0xec, 0x13, 0x87, 0x36, 0x75, 0x9a, 0xec, 0x77, 0x2d, 0x0b, 0x5b, 0xbf, 0x8f, 0x87, 0x9c, 0x59, 0x44, 0xc5, 0x08, 0xe6, 0xc8, 0xa3, 0x94, 0xcc, 0xe8, 0x78, 0xb7, 0x7c, 0x96, 0xa2, 0xe4, 0xc1, 0xc0, 0x91, 0x34, 0xb2, 0x2d, 0x51, 0x7f, 0xc1, 0xf1, 0xc2, 0x6b, 0x43, 0xa4, 0xef, 0x8a, 0x5f, 0x7c, 0xa9, 0xc8, 0x0f, 0xea, 0xa2, 0xe1, 0x54, 0x0d, 0xeb, 0x18, 0x04, 0x1f, 0xc7, 0xaa, 0xbe, 0x4c, 0xa6, 0x55, 0x0c, 0x0a, 0x26, 0xab, 0xca, 0xed, 0x58, 0x4c, 0x76, 0x24, 0xbe, 0x7d, 0x31, 0x54, 0xd0, 0xfb, 0x78, 0x98, 0x4b, 0x39, 0x74, 0x91, 0xb2, 0x7e, 0x36, 0x96, 0x6f, 0x08, 0x04, 0x2c, 0x62, 0x14, 0xca, 0x2a, 0xb9, 0xbb, 0xf6, 0x4a, 0x9a, 0xc2, 0x2e, 0xb3, 0x4b, 0xa0, 0x0a, 0xba, 0x57, 0xee, 0xbc, 0xbc, 0x01, 0x98, 0x61, 0xda, 0x5c, 0x19, 0x53, 0x92, 0x4c, 0xb8, 0x67, 0x21, 0x85, 0x14, 0x1c, 0xe1, 0x41, 0x43, 0xd0, 0x58, 0x1e, 0x1f, 0xd9, 0x86, 0x1d, 0xe8, 0xa2, 0xf2, 0xaa, 0x32, 0x72, 0x85, 0x9b, 0xff, 0xc7, 0x24, 0x0c, 0x24, 0x0b, 0xdb, 0x8a, 0x65, 0x2e, 0xfb, 0x6b, 0x70, 0x94, 0xc5, 0xe5, 0x68, 0x5f, 0x53, 0xc4, 0x91, 0x42, 0x94, 0x0e, 0xc6, 0xa0, 0x5b, 0xc2, 0xb7, 0xbc, 0xea, 0xfa, 0x21, 0xfe, 0x21, 0xa9, 0x73, 0xf1, 0x8c, 0xac, 0xdb, 0x14, 0x99, 0x0b, 0x43, 0x4b, 0x59, 0x52, 0x1d, 0xb1, 0x4c, 0x63, 0x78, 0xb6, 0x16, 0x0a, 0xca, 0xc7, 0xd9, 0x2d, 0x0e, 0x16, 0x91, 0x3f, 0xd5, 0x28, 0x5f, 0xb4, 0x26, 0x49, 0xcc, 0xc8, 0xe2, 0xa1, 0x8c, 0x63, 0x70, 0x00, 0x4e, 0xc4, 0x44, 0x3d, 0x4b, 0xac, 0x7c, 0x42, 0xc8, 0x53, 0xf2, 0x2a, 0xe2, 0x34, 0x42, 0x9a, 0xfc, 0x0a, 0x9f, 0x30, 0x40, 0xaf, 0xac, 0xb3, 0x88, 0x22, 0x1b, 0x26, 0x80, 0xc9, 0x9f, 0xb0, 0x4a, 0x30, 0x2c, 0x14, 0xbd, 0x16, 0x26, 0x11, 0x30, 0xad, 0x8b, 0xf9, 0x0e, 0x00, 0x46, 0xc4, 0x32, 0xb9, 0x03, 0x43, 0xf5, 0x90, 0xf8, 0xa6, 0x43, 0xfc, 0xa5, 0x46, 0x40, 0x1a, 0xc6, 0x41, 0xdb, 0xb3, 0x53, 0x11, 0x5c, 0xb7, 0x2a, 0x32, 0x5c, 0x34, 0x1c, 0x72, 0xd2, 0x95, 0x68, 0xf3, 0xb0, 0x1e, 0x17, 0x07, 0xd0, 0xeb, 0x7f, 0x49, 0xf7, 0x21, 0xac, 0xa0, 0x51, 0x3c, 0x81, 0x28, 0x5d, 0x6c, 0x0d, 0x7c, 0x83, 0x27, 0x08, 0x44, 0x19, 0xc8, 0xa1, 0xcb, 0x00, 0xf0, 0xc8, 0x10, 0x96, 0x31, 0x50, 0x10, 0xa6, 0x2e, 0x39, 0x72, 0x78, 0xcb, 0x02, 0x4c, 0x35, 0x26, 0xc1, 0x4b, 0x53, 0xbe, 0xe3, 0x44, 0x6c, 0x22, 0xb1, 0xca, 0x46, 0x97, 0xee, 0xe5, 0x72, 0x4d, 0x83, 0x42, 0x5a, 0x89, 0x80, 0xcd, 0x74, 0x73, 0x7d, 0x45, 0x1f, 0x1c, 0x02, 0xa7, 0x07, 0xa9, 0x9c, 0x60, 0x47, 0x2a, 0x35, 0xc9, 0xa8, 0xae, 0x1c, 0x2d, 0x7b, 0x68, 0x07, 0x31, 0x89, 0x3b, 0xa8, 0x29, 0x86, 0xaf, 0x27, 0x0f, 0xff, 0xb4, 0x00, 0x2d, 0x50, 0xc7, 0xc3, 0xc0, 0x6d, 0xc4, 0xb1, 0x1e, 0xd2, 0xe6, 0xb0, 0x2e, 0x42, 0x7c, 0xc8, 0xb7, 0xce, 0x19, 0x58, 0x6c, 0x4f, 0x71, 0x8f, 0x55, 0x06, 0x2f, 0xa8, 0xb3, 0x1c, 0x37, 0x4c, 0x2d, 0x48, 0x3b, 0x7f, 0x87, 0xe1, 0x8b, 0x3a, 0x86, 0x9a, 0xb7, 0xc2, 0x4a, 0xfe, 0x38, 0x73, 0x24, 0x31, 0x0f, 0x32, 0xb7, 0x75, 0xcf, 0xf7, 0xba, 0x77, 0x88, 0x47, 0xc8, 0x82, 0x61, 0xaf, 0x43, 0x88, 0xe4, 0x6a, 0x34, 0x01, 0x9c, 0x9b, 0xc2, 0x51, 0x4d, 0xa8, 0x10, 0x8d, 0x37, 0x31, 0x67, 0x61, 0x28, 0x04, 0xe1, 0xe2, 0xc1, 0xab, 0xa3, 0x48, 0x9c, 0x70, 0x84, 0x4a, 0x94, 0xc3, 0xfb, 0x73, 0x8f, 0x33, 0x79, 0x67, 0x95, 0xc1, 0x92, 0x1e, 0x6b, 0x81, 0xec, 0x64, 0x19, 0x79, 0xaa, 0x0f, 0xa1, 0x06, 0xa9, 0x37, 0x9c, 0xc5, 0x3a, 0xd6, 0x2d, 0x6b, 0xc5, 0x84, 0x12, 0x71, 0xb9, 0xb6, 0x6a, 0x64, 0xfd, 0x08, 0x86, 0x68, 0xa0, 0x62, 0x1e, 0xd5, 0xae, 0x4f, 0x79, 0x2e, 0x24, 0x1c, 0x43, 0xd2, 0xd3, 0x2e, 0xbb, 0xe5, 0xb7, 0x0f, 0xf5, 0x3d, 0xe2, 0xeb, 0x7f, 0x45, 0x29, 0x1a, 0x85, 0x05, 0x49, 0xaf, 0xcc, 0x59, 0xa8, 0x30, 0xa2, 0xa8, 0x31, 0x83, 0x29, 0xb5, 0x4f, 0xbd, 0xe1, 0x7e, 0xf7, 0xb2, 0xae, 0xeb, 0x43, 0xb6, 0xf5, 0xc5, 0xa1, 0x91, 0x69, 0x1a, 0x8c, 0x08, 0x4e, 0x8f, 0xd6, 0x35, 0x6a, 0x82, 0x54, 0xfb, 0x44, 0xcc, 0x6d, 0xb4, 0x27, 0xaf, 0xac, 0x2f, 0x5d, 0xc8, 0x15, 0xa7, 0xe7, 0x93, 0x79, 0xe0, 0x4c, 0x75, 0xf3, 0x68, 0x18, 0xe0, 0x7f, 0x85, 0x30, 0x8a, 0x30, 0x5a, 0x1e, 0xbc, 0x20, 0x69, 0xa2, 0x4e, 0xf5, 0x16, 0x90, 0x3d, 0x42, 0x80, 0xb1, 0x40, 0xdb, 0xdc, 0x3b, 0x7e, 0x11, 0x82, 0x75, 0x1a, 0x69, 0xef, 0xe9, 0x6e, 0x47, 0x33, 0xd0, 0x97, 0xd8, 0x32, 0x8d, 0xf5, 0xc2, 0x17, 0xbd, 0x15, 0x64, 0x2e, 0xc8, 0xee, 0xba, 0x21, 0x4e, 0x09, 0x68, 0xb0, 0xad, 0xa7, 0x87, 0x78, 0xc6, 0x48, 0xc3, 0x3a, 0x29, 0x58, 0x34, 0x8d, 0xcf, 0xd9, 0xb9, 0x57, 0x50, 0xc0, 0xa9, 0xe2, 0x40, 0x53, 0xed, 0x3c, 0x7b, 0x86, 0x16, 0xd9, 0xcf, 0xd4, 0x8a, 0x28, 0xed, 0xfe, 0x4e, 0xe1, 0x4b, 0x97, 0x19, 0xec }, .priv_len = 1632, .pub = { 0x78, 0x5b, 0x59, 0x05, 0xa9, 0x87, 0xff, 0x61, 0x9e, 0x77, 0xb4, 0x88, 0x37, 0x9b, 0xa2, 0x96, 0x50, 0x02, 0x94, 0x69, 0x01, 0x20, 0x38, 0x9c, 0x87, 0x94, 0x1d, 0x86, 0x30, 0x14, 0x1f, 0xb1, 0x4b, 0x38, 0x67, 0x85, 0x65, 0x4c, 0x0c, 0xe5, 0xb3, 0x5b, 0x85, 0x49, 0x30, 0x4f, 0x8b, 0x69, 0x67, 0xa0, 0x4b, 0xee, 0x89, 0x0d, 0xbb, 0x04, 0x7a, 0xfe, 0x96, 0x3f, 0x40, 0xf4, 0x69, 0xfe, 0x70, 0x42, 0x76, 0x95, 0xb8, 0xb2, 0xc2, 0xc7, 0xf0, 0x84, 0xc7, 0x42, 0x7b, 0x15, 0x26, 0x02, 0xad, 0x97, 0x86, 0x9c, 0x36, 0x39, 0x40, 0x83, 0xb7, 0x12, 0xa6, 0x66, 0xae, 0x42, 0xf3, 0x18, 0x2c, 0x49, 0xb8, 0x3f, 0x84, 0x6e, 0xe1, 0x5b, 0xca, 0x43, 0xa0, 0x42, 0xc3, 0xb5, 0x0a, 0x87, 0x31, 0x5a, 0x26, 0xe7, 0xc9, 0x26, 0xe0, 0x96, 0x98, 0x06, 0x15, 0xcd, 0x57, 0xc5, 0x60, 0x7c, 0x6e, 0xff, 0xb3, 0x13, 0xec, 0x02, 0xaf, 0xec, 0x13, 0x87, 0x36, 0x75, 0x9a, 0xec, 0x77, 0x2d, 0x0b, 0x5b, 0xbf, 0x8f, 0x87, 0x9c, 0x59, 0x44, 0xc5, 0x08, 0xe6, 0xc8, 0xa3, 0x94, 0xcc, 0xe8, 0x78, 0xb7, 0x7c, 0x96, 0xa2, 0xe4, 0xc1, 0xc0, 0x91, 0x34, 0xb2, 0x2d, 0x51, 0x7f, 0xc1, 0xf1, 0xc2, 0x6b, 0x43, 0xa4, 0xef, 0x8a, 0x5f, 0x7c, 0xa9, 0xc8, 0x0f, 0xea, 0xa2, 0xe1, 0x54, 0x0d, 0xeb, 0x18, 0x04, 0x1f, 0xc7, 0xaa, 0xbe, 0x4c, 0xa6, 0x55, 0x0c, 0x0a, 0x26, 0xab, 0xca, 0xed, 0x58, 0x4c, 0x76, 0x24, 0xbe, 0x7d, 0x31, 0x54, 0xd0, 0xfb, 0x78, 0x98, 0x4b, 0x39, 0x74, 0x91, 0xb2, 0x7e, 0x36, 0x96, 0x6f, 0x08, 0x04, 0x2c, 0x62, 0x14, 0xca, 0x2a, 0xb9, 0xbb, 0xf6, 0x4a, 0x9a, 0xc2, 0x2e, 0xb3, 0x4b, 0xa0, 0x0a, 0xba, 0x57, 0xee, 0xbc, 0xbc, 0x01, 0x98, 0x61, 0xda, 0x5c, 0x19, 0x53, 0x92, 0x4c, 0xb8, 0x67, 0x21, 0x85, 0x14, 0x1c, 0xe1, 0x41, 0x43, 0xd0, 0x58, 0x1e, 0x1f, 0xd9, 0x86, 0x1d, 0xe8, 0xa2, 0xf2, 0xaa, 0x32, 0x72, 0x85, 0x9b, 0xff, 0xc7, 0x24, 0x0c, 0x24, 0x0b, 0xdb, 0x8a, 0x65, 0x2e, 0xfb, 0x6b, 0x70, 0x94, 0xc5, 0xe5, 0x68, 0x5f, 0x53, 0xc4, 0x91, 0x42, 0x94, 0x0e, 0xc6, 0xa0, 0x5b, 0xc2, 0xb7, 0xbc, 0xea, 0xfa, 0x21, 0xfe, 0x21, 0xa9, 0x73, 0xf1, 0x8c, 0xac, 0xdb, 0x14, 0x99, 0x0b, 0x43, 0x4b, 0x59, 0x52, 0x1d, 0xb1, 0x4c, 0x63, 0x78, 0xb6, 0x16, 0x0a, 0xca, 0xc7, 0xd9, 0x2d, 0x0e, 0x16, 0x91, 0x3f, 0xd5, 0x28, 0x5f, 0xb4, 0x26, 0x49, 0xcc, 0xc8, 0xe2, 0xa1, 0x8c, 0x63, 0x70, 0x00, 0x4e, 0xc4, 0x44, 0x3d, 0x4b, 0xac, 0x7c, 0x42, 0xc8, 0x53, 0xf2, 0x2a, 0xe2, 0x34, 0x42, 0x9a, 0xfc, 0x0a, 0x9f, 0x30, 0x40, 0xaf, 0xac, 0xb3, 0x88, 0x22, 0x1b, 0x26, 0x80, 0xc9, 0x9f, 0xb0, 0x4a, 0x30, 0x2c, 0x14, 0xbd, 0x16, 0x26, 0x11, 0x30, 0xad, 0x8b, 0xf9, 0x0e, 0x00, 0x46, 0xc4, 0x32, 0xb9, 0x03, 0x43, 0xf5, 0x90, 0xf8, 0xa6, 0x43, 0xfc, 0xa5, 0x46, 0x40, 0x1a, 0xc6, 0x41, 0xdb, 0xb3, 0x53, 0x11, 0x5c, 0xb7, 0x2a, 0x32, 0x5c, 0x34, 0x1c, 0x72, 0xd2, 0x95, 0x68, 0xf3, 0xb0, 0x1e, 0x17, 0x07, 0xd0, 0xeb, 0x7f, 0x49, 0xf7, 0x21, 0xac, 0xa0, 0x51, 0x3c, 0x81, 0x28, 0x5d, 0x6c, 0x0d, 0x7c, 0x83, 0x27, 0x08, 0x44, 0x19, 0xc8, 0xa1, 0xcb, 0x00, 0xf0, 0xc8, 0x10, 0x96, 0x31, 0x50, 0x10, 0xa6, 0x2e, 0x39, 0x72, 0x78, 0xcb, 0x02, 0x4c, 0x35, 0x26, 0xc1, 0x4b, 0x53, 0xbe, 0xe3, 0x44, 0x6c, 0x22, 0xb1, 0xca, 0x46, 0x97, 0xee, 0xe5, 0x72, 0x4d, 0x83, 0x42, 0x5a, 0x89, 0x80, 0xcd, 0x74, 0x73, 0x7d, 0x45, 0x1f, 0x1c, 0x02, 0xa7, 0x07, 0xa9, 0x9c, 0x60, 0x47, 0x2a, 0x35, 0xc9, 0xa8, 0xae, 0x1c, 0x2d, 0x7b, 0x68, 0x07, 0x31, 0x89, 0x3b, 0xa8, 0x29, 0x86, 0xaf, 0x27, 0x0f, 0xff, 0xb4, 0x00, 0x2d, 0x50, 0xc7, 0xc3, 0xc0, 0x6d, 0xc4, 0xb1, 0x1e, 0xd2, 0xe6, 0xb0, 0x2e, 0x42, 0x7c, 0xc8, 0xb7, 0xce, 0x19, 0x58, 0x6c, 0x4f, 0x71, 0x8f, 0x55, 0x06, 0x2f, 0xa8, 0xb3, 0x1c, 0x37, 0x4c, 0x2d, 0x48, 0x3b, 0x7f, 0x87, 0xe1, 0x8b, 0x3a, 0x86, 0x9a, 0xb7, 0xc2, 0x4a, 0xfe, 0x38, 0x73, 0x24, 0x31, 0x0f, 0x32, 0xb7, 0x75, 0xcf, 0xf7, 0xba, 0x77, 0x88, 0x47, 0xc8, 0x82, 0x61, 0xaf, 0x43, 0x88, 0xe4, 0x6a, 0x34, 0x01, 0x9c, 0x9b, 0xc2, 0x51, 0x4d, 0xa8, 0x10, 0x8d, 0x37, 0x31, 0x67, 0x61, 0x28, 0x04, 0xe1, 0xe2, 0xc1, 0xab, 0xa3, 0x48, 0x9c, 0x70, 0x84, 0x4a, 0x94, 0xc3, 0xfb, 0x73, 0x8f, 0x33, 0x79, 0x67, 0x95, 0xc1, 0x92, 0x1e, 0x6b, 0x81, 0xec, 0x64, 0x19, 0x79, 0xaa, 0x0f, 0xa1, 0x06, 0xa9, 0x37, 0x9c, 0xc5, 0x3a, 0xd6, 0x2d, 0x6b, 0xc5, 0x84, 0x12, 0x71, 0xb9, 0xb6, 0x6a, 0x64, 0xfd, 0x08, 0x86, 0x68, 0xa0, 0x62, 0x1e, 0xd5, 0xae, 0x4f, 0x79, 0x2e, 0x24, 0x1c, 0x43, 0xd2, 0xd3, 0x2e, 0xbb, 0xe5, 0xb7, 0x0f, 0xf5, 0x3d, 0xe2, 0xeb, 0x7f, 0x45, 0x29, 0x1a, 0x85, 0x05, 0x49, 0xaf, 0xcc, 0x59, 0xa8, 0x30, 0xa2, 0xa8, 0x31, 0x83, 0x29, 0xb5, 0x4f, 0xbd, 0xe1, 0x7e, 0xf7, 0xb2, 0xae, 0xeb, 0x43, 0xb6, 0xf5, 0xc5, 0xa1, 0x91, 0x69, 0x1a, 0x8c, 0x08, 0x4e, 0x8f, 0xd6, 0x35, 0x6a, 0x82, 0x54, 0xfb, 0x44, 0xcc, 0x6d, 0xb4, 0x27, 0xaf, 0xac, 0x2f, 0x5d, 0xc8, 0x15, 0xa7, 0xe7, 0x93, 0x79, 0xe0, 0x4c, 0x75, 0xf3, 0x68, 0x18, 0xe0, 0x7f, 0x85, 0x30, 0x8a, 0x30, 0x5a, 0x1e, 0xbc, 0x20, 0x69, 0xa2, 0x4e, 0xf5, 0x16, 0x90, 0x3d, 0x42, 0x80, 0xb1, 0x40, 0xdb, 0xdc, 0x3b, 0x7e, 0x11, 0x82, 0x75, 0x1a, 0x69, 0xef }, .pub_len = 800, }, { .name = "ML-KEM 512 (seed only)", .parameter_set = CKP_ML_KEM_512, .priv_seed = { 0xe4, 0xe6, 0x2c, 0xd8, 0x66, 0xd7, 0xa0, 0xe8, 0x8d, 0xc6, 0x9f, 0x5c, 0xa7, 0x21, 0x7c, 0xb9, 0x5c, 0x5f, 0x59, 0x60, 0xf8, 0xa8, 0xe1, 0xab, 0x7a, 0x2a, 0xdd, 0x2b, 0xa8, 0xc7, 0x17, 0x5d, 0x29, 0x58, 0x34, 0x8d, 0xcf, 0xd9, 0xb9, 0x57, 0x50, 0xc0, 0xa9, 0xe2, 0x40, 0x53, 0xed, 0x3c, 0x7b, 0x86, 0x16, 0xd9, 0xcf, 0xd4, 0x8a, 0x28, 0xed, 0xfe, 0x4e, 0xe1, 0x4b, 0x97, 0x19, 0xec }, .priv_seed_len = 64, .pub = { 0x78, 0x5b, 0x59, 0x05, 0xa9, 0x87, 0xff, 0x61, 0x9e, 0x77, 0xb4, 0x88, 0x37, 0x9b, 0xa2, 0x96, 0x50, 0x02, 0x94, 0x69, 0x01, 0x20, 0x38, 0x9c, 0x87, 0x94, 0x1d, 0x86, 0x30, 0x14, 0x1f, 0xb1, 0x4b, 0x38, 0x67, 0x85, 0x65, 0x4c, 0x0c, 0xe5, 0xb3, 0x5b, 0x85, 0x49, 0x30, 0x4f, 0x8b, 0x69, 0x67, 0xa0, 0x4b, 0xee, 0x89, 0x0d, 0xbb, 0x04, 0x7a, 0xfe, 0x96, 0x3f, 0x40, 0xf4, 0x69, 0xfe, 0x70, 0x42, 0x76, 0x95, 0xb8, 0xb2, 0xc2, 0xc7, 0xf0, 0x84, 0xc7, 0x42, 0x7b, 0x15, 0x26, 0x02, 0xad, 0x97, 0x86, 0x9c, 0x36, 0x39, 0x40, 0x83, 0xb7, 0x12, 0xa6, 0x66, 0xae, 0x42, 0xf3, 0x18, 0x2c, 0x49, 0xb8, 0x3f, 0x84, 0x6e, 0xe1, 0x5b, 0xca, 0x43, 0xa0, 0x42, 0xc3, 0xb5, 0x0a, 0x87, 0x31, 0x5a, 0x26, 0xe7, 0xc9, 0x26, 0xe0, 0x96, 0x98, 0x06, 0x15, 0xcd, 0x57, 0xc5, 0x60, 0x7c, 0x6e, 0xff, 0xb3, 0x13, 0xec, 0x02, 0xaf, 0xec, 0x13, 0x87, 0x36, 0x75, 0x9a, 0xec, 0x77, 0x2d, 0x0b, 0x5b, 0xbf, 0x8f, 0x87, 0x9c, 0x59, 0x44, 0xc5, 0x08, 0xe6, 0xc8, 0xa3, 0x94, 0xcc, 0xe8, 0x78, 0xb7, 0x7c, 0x96, 0xa2, 0xe4, 0xc1, 0xc0, 0x91, 0x34, 0xb2, 0x2d, 0x51, 0x7f, 0xc1, 0xf1, 0xc2, 0x6b, 0x43, 0xa4, 0xef, 0x8a, 0x5f, 0x7c, 0xa9, 0xc8, 0x0f, 0xea, 0xa2, 0xe1, 0x54, 0x0d, 0xeb, 0x18, 0x04, 0x1f, 0xc7, 0xaa, 0xbe, 0x4c, 0xa6, 0x55, 0x0c, 0x0a, 0x26, 0xab, 0xca, 0xed, 0x58, 0x4c, 0x76, 0x24, 0xbe, 0x7d, 0x31, 0x54, 0xd0, 0xfb, 0x78, 0x98, 0x4b, 0x39, 0x74, 0x91, 0xb2, 0x7e, 0x36, 0x96, 0x6f, 0x08, 0x04, 0x2c, 0x62, 0x14, 0xca, 0x2a, 0xb9, 0xbb, 0xf6, 0x4a, 0x9a, 0xc2, 0x2e, 0xb3, 0x4b, 0xa0, 0x0a, 0xba, 0x57, 0xee, 0xbc, 0xbc, 0x01, 0x98, 0x61, 0xda, 0x5c, 0x19, 0x53, 0x92, 0x4c, 0xb8, 0x67, 0x21, 0x85, 0x14, 0x1c, 0xe1, 0x41, 0x43, 0xd0, 0x58, 0x1e, 0x1f, 0xd9, 0x86, 0x1d, 0xe8, 0xa2, 0xf2, 0xaa, 0x32, 0x72, 0x85, 0x9b, 0xff, 0xc7, 0x24, 0x0c, 0x24, 0x0b, 0xdb, 0x8a, 0x65, 0x2e, 0xfb, 0x6b, 0x70, 0x94, 0xc5, 0xe5, 0x68, 0x5f, 0x53, 0xc4, 0x91, 0x42, 0x94, 0x0e, 0xc6, 0xa0, 0x5b, 0xc2, 0xb7, 0xbc, 0xea, 0xfa, 0x21, 0xfe, 0x21, 0xa9, 0x73, 0xf1, 0x8c, 0xac, 0xdb, 0x14, 0x99, 0x0b, 0x43, 0x4b, 0x59, 0x52, 0x1d, 0xb1, 0x4c, 0x63, 0x78, 0xb6, 0x16, 0x0a, 0xca, 0xc7, 0xd9, 0x2d, 0x0e, 0x16, 0x91, 0x3f, 0xd5, 0x28, 0x5f, 0xb4, 0x26, 0x49, 0xcc, 0xc8, 0xe2, 0xa1, 0x8c, 0x63, 0x70, 0x00, 0x4e, 0xc4, 0x44, 0x3d, 0x4b, 0xac, 0x7c, 0x42, 0xc8, 0x53, 0xf2, 0x2a, 0xe2, 0x34, 0x42, 0x9a, 0xfc, 0x0a, 0x9f, 0x30, 0x40, 0xaf, 0xac, 0xb3, 0x88, 0x22, 0x1b, 0x26, 0x80, 0xc9, 0x9f, 0xb0, 0x4a, 0x30, 0x2c, 0x14, 0xbd, 0x16, 0x26, 0x11, 0x30, 0xad, 0x8b, 0xf9, 0x0e, 0x00, 0x46, 0xc4, 0x32, 0xb9, 0x03, 0x43, 0xf5, 0x90, 0xf8, 0xa6, 0x43, 0xfc, 0xa5, 0x46, 0x40, 0x1a, 0xc6, 0x41, 0xdb, 0xb3, 0x53, 0x11, 0x5c, 0xb7, 0x2a, 0x32, 0x5c, 0x34, 0x1c, 0x72, 0xd2, 0x95, 0x68, 0xf3, 0xb0, 0x1e, 0x17, 0x07, 0xd0, 0xeb, 0x7f, 0x49, 0xf7, 0x21, 0xac, 0xa0, 0x51, 0x3c, 0x81, 0x28, 0x5d, 0x6c, 0x0d, 0x7c, 0x83, 0x27, 0x08, 0x44, 0x19, 0xc8, 0xa1, 0xcb, 0x00, 0xf0, 0xc8, 0x10, 0x96, 0x31, 0x50, 0x10, 0xa6, 0x2e, 0x39, 0x72, 0x78, 0xcb, 0x02, 0x4c, 0x35, 0x26, 0xc1, 0x4b, 0x53, 0xbe, 0xe3, 0x44, 0x6c, 0x22, 0xb1, 0xca, 0x46, 0x97, 0xee, 0xe5, 0x72, 0x4d, 0x83, 0x42, 0x5a, 0x89, 0x80, 0xcd, 0x74, 0x73, 0x7d, 0x45, 0x1f, 0x1c, 0x02, 0xa7, 0x07, 0xa9, 0x9c, 0x60, 0x47, 0x2a, 0x35, 0xc9, 0xa8, 0xae, 0x1c, 0x2d, 0x7b, 0x68, 0x07, 0x31, 0x89, 0x3b, 0xa8, 0x29, 0x86, 0xaf, 0x27, 0x0f, 0xff, 0xb4, 0x00, 0x2d, 0x50, 0xc7, 0xc3, 0xc0, 0x6d, 0xc4, 0xb1, 0x1e, 0xd2, 0xe6, 0xb0, 0x2e, 0x42, 0x7c, 0xc8, 0xb7, 0xce, 0x19, 0x58, 0x6c, 0x4f, 0x71, 0x8f, 0x55, 0x06, 0x2f, 0xa8, 0xb3, 0x1c, 0x37, 0x4c, 0x2d, 0x48, 0x3b, 0x7f, 0x87, 0xe1, 0x8b, 0x3a, 0x86, 0x9a, 0xb7, 0xc2, 0x4a, 0xfe, 0x38, 0x73, 0x24, 0x31, 0x0f, 0x32, 0xb7, 0x75, 0xcf, 0xf7, 0xba, 0x77, 0x88, 0x47, 0xc8, 0x82, 0x61, 0xaf, 0x43, 0x88, 0xe4, 0x6a, 0x34, 0x01, 0x9c, 0x9b, 0xc2, 0x51, 0x4d, 0xa8, 0x10, 0x8d, 0x37, 0x31, 0x67, 0x61, 0x28, 0x04, 0xe1, 0xe2, 0xc1, 0xab, 0xa3, 0x48, 0x9c, 0x70, 0x84, 0x4a, 0x94, 0xc3, 0xfb, 0x73, 0x8f, 0x33, 0x79, 0x67, 0x95, 0xc1, 0x92, 0x1e, 0x6b, 0x81, 0xec, 0x64, 0x19, 0x79, 0xaa, 0x0f, 0xa1, 0x06, 0xa9, 0x37, 0x9c, 0xc5, 0x3a, 0xd6, 0x2d, 0x6b, 0xc5, 0x84, 0x12, 0x71, 0xb9, 0xb6, 0x6a, 0x64, 0xfd, 0x08, 0x86, 0x68, 0xa0, 0x62, 0x1e, 0xd5, 0xae, 0x4f, 0x79, 0x2e, 0x24, 0x1c, 0x43, 0xd2, 0xd3, 0x2e, 0xbb, 0xe5, 0xb7, 0x0f, 0xf5, 0x3d, 0xe2, 0xeb, 0x7f, 0x45, 0x29, 0x1a, 0x85, 0x05, 0x49, 0xaf, 0xcc, 0x59, 0xa8, 0x30, 0xa2, 0xa8, 0x31, 0x83, 0x29, 0xb5, 0x4f, 0xbd, 0xe1, 0x7e, 0xf7, 0xb2, 0xae, 0xeb, 0x43, 0xb6, 0xf5, 0xc5, 0xa1, 0x91, 0x69, 0x1a, 0x8c, 0x08, 0x4e, 0x8f, 0xd6, 0x35, 0x6a, 0x82, 0x54, 0xfb, 0x44, 0xcc, 0x6d, 0xb4, 0x27, 0xaf, 0xac, 0x2f, 0x5d, 0xc8, 0x15, 0xa7, 0xe7, 0x93, 0x79, 0xe0, 0x4c, 0x75, 0xf3, 0x68, 0x18, 0xe0, 0x7f, 0x85, 0x30, 0x8a, 0x30, 0x5a, 0x1e, 0xbc, 0x20, 0x69, 0xa2, 0x4e, 0xf5, 0x16, 0x90, 0x3d, 0x42, 0x80, 0xb1, 0x40, 0xdb, 0xdc, 0x3b, 0x7e, 0x11, 0x82, 0x75, 0x1a, 0x69, 0xef }, .pub_len = 800, }, { .name = "ML-KEM 512 (seed and priv)", .parameter_set = CKP_ML_KEM_512, .priv_seed = { 0xe4, 0xe6, 0x2c, 0xd8, 0x66, 0xd7, 0xa0, 0xe8, 0x8d, 0xc6, 0x9f, 0x5c, 0xa7, 0x21, 0x7c, 0xb9, 0x5c, 0x5f, 0x59, 0x60, 0xf8, 0xa8, 0xe1, 0xab, 0x7a, 0x2a, 0xdd, 0x2b, 0xa8, 0xc7, 0x17, 0x5d, 0x29, 0x58, 0x34, 0x8d, 0xcf, 0xd9, 0xb9, 0x57, 0x50, 0xc0, 0xa9, 0xe2, 0x40, 0x53, 0xed, 0x3c, 0x7b, 0x86, 0x16, 0xd9, 0xcf, 0xd4, 0x8a, 0x28, 0xed, 0xfe, 0x4e, 0xe1, 0x4b, 0x97, 0x19, 0xec }, .priv_seed_len = 64, .priv = { 0x71, 0x4a, 0x39, 0x62, 0x00, 0xb3, 0x55, 0xa2, 0x01, 0x5d, 0x74, 0x70, 0x64, 0x9a, 0x8a, 0xe2, 0xb3, 0x90, 0xa1, 0x21, 0x3c, 0xc4, 0xca, 0x51, 0x0f, 0x86, 0x14, 0x0b, 0x31, 0x36, 0xcb, 0xbc, 0x0f, 0x97, 0x3c, 0x74, 0xa7, 0x40, 0x85, 0xe4, 0x85, 0x94, 0x68, 0x78, 0x1b, 0xc6, 0xa9, 0x6b, 0xbf, 0x43, 0x03, 0xc5, 0x40, 0x68, 0xbf, 0xc8, 0xab, 0x66, 0x58, 0x6e, 0xfa, 0xca, 0x34, 0x54, 0xd5, 0xa5, 0xec, 0x88, 0x4b, 0x8f, 0x77, 0xbb, 0x8b, 0x30, 0x80, 0x28, 0x3a, 0x88, 0x67, 0x35, 0x0e, 0x9d, 0x56, 0xa7, 0x1b, 0x75, 0xcf, 0xef, 0x71, 0x97, 0x0a, 0xfa, 0x29, 0x8c, 0x4c, 0x36, 0x5b, 0x37, 0x4a, 0x58, 0x86, 0x55, 0x8a, 0xa2, 0x44, 0x5a, 0x35, 0x67, 0xa3, 0x63, 0x9e, 0x32, 0x01, 0x6f, 0x7d, 0x76, 0xcd, 0xb9, 0xb7, 0x96, 0xd2, 0x56, 0xc4, 0x95, 0x09, 0x2f, 0x74, 0xc4, 0x48, 0xbd, 0xb6, 0x7c, 0x8d, 0x70, 0xb9, 0xd8, 0x27, 0x52, 0x4d, 0x45, 0xba, 0x43, 0x61, 0x2e, 0x1d, 0x5b, 0x39, 0x2e, 0x14, 0x0e, 0x8a, 0x77, 0x38, 0xf6, 0xbc, 0x33, 0xa5, 0x05, 0xc1, 0xec, 0xe0, 0x86, 0x65, 0x8c, 0x5a, 0x4e, 0x88, 0x20, 0x40, 0x6a, 0x6d, 0x6e, 0xa4, 0x08, 0x51, 0xc3, 0x31, 0x22, 0xc8, 0x54, 0x8f, 0xa3, 0x33, 0x48, 0x16, 0x36, 0x79, 0x29, 0x61, 0x80, 0x69, 0x91, 0x7a, 0x27, 0x75, 0x83, 0x0c, 0xb7, 0xa5, 0xf8, 0xbd, 0x71, 0xba, 0x13, 0x6a, 0x26, 0x0c, 0x5e, 0x37, 0xab, 0x08, 0xc2, 0xb8, 0x4f, 0xe0, 0xc2, 0xcb, 0x78, 0x8a, 0xe8, 0xba, 0xac, 0xae, 0x5a, 0x26, 0x62, 0x8b, 0x3e, 0x3a, 0xf4, 0x4b, 0x35, 0x18, 0xa4, 0x44, 0xac, 0x5e, 0x29, 0x14, 0x65, 0x3d, 0x71, 0x25, 0xa3, 0xb8, 0x67, 0x02, 0x74, 0xc0, 0xb1, 0x68, 0x39, 0x60, 0xa0, 0x68, 0x0a, 0x7a, 0x44, 0xf3, 0x36, 0x77, 0x71, 0x98, 0x4f, 0x8b, 0x82, 0x77, 0xc1, 0xe8, 0x3b, 0xc7, 0xd0, 0x84, 0xac, 0xf9, 0x6c, 0x9f, 0x61, 0x73, 0x74, 0x36, 0x81, 0x8f, 0x28, 0x4f, 0x91, 0x4a, 0x20, 0xea, 0x26, 0xb4, 0x82, 0x67, 0x39, 0x31, 0x33, 0x5d, 0xd4, 0x8a, 0xbc, 0xe4, 0xd9, 0x15, 0x51, 0x3b, 0x91, 0x23, 0x48, 0xbb, 0x45, 0xe0, 0x76, 0x69, 0xbb, 0x57, 0x4e, 0xfa, 0x01, 0xda, 0x61, 0x79, 0x6a, 0x03, 0x43, 0x78, 0x8b, 0xbf, 0x36, 0x34, 0xa3, 0x75, 0x6a, 0x47, 0x00, 0x50, 0x04, 0x52, 0x74, 0x29, 0x5b, 0x2a, 0x72, 0xb9, 0x49, 0x0d, 0xc7, 0x49, 0x53, 0xd2, 0x22, 0x85, 0x3f, 0x17, 0x99, 0x05, 0x18, 0x7f, 0x14, 0x0b, 0xa3, 0x3f, 0x67, 0x1c, 0x47, 0x9a, 0x63, 0x3d, 0xf1, 0x7a, 0x37, 0xa6, 0x3b, 0xce, 0x51, 0x10, 0x9a, 0x97, 0x6b, 0x80, 0x29, 0x64, 0x5c, 0x77, 0x5c, 0xdf, 0x58, 0x10, 0x14, 0x2b, 0x7a, 0xd6, 0x4c, 0x20, 0x18, 0xe9, 0x30, 0x3f, 0x26, 0x73, 0x6c, 0xe3, 0xa5, 0xad, 0x70, 0xb3, 0xde, 0x8c, 0xb2, 0x52, 0x67, 0x06, 0x28, 0xe0, 0xb5, 0x16, 0x13, 0x7d, 0xf3, 0xdb, 0x4f, 0x32, 0x2a, 0x9a, 0xce, 0x05, 0x8b, 0x8e, 0xc2, 0xae, 0xed, 0x99, 0x73, 0xbb, 0x97, 0xa2, 0x5f, 0x86, 0x28, 0x66, 0xd4, 0x04, 0x14, 0xb5, 0x8a, 0xce, 0x90, 0x59, 0x4a, 0xc3, 0xb4, 0x7c, 0x81, 0xa5, 0x24, 0x11, 0x26, 0x79, 0x25, 0x84, 0x65, 0xd8, 0xb9, 0x6d, 0xaa, 0xcd, 0x7b, 0x9c, 0xad, 0xdc, 0x3c, 0xac, 0xa0, 0x03, 0x5b, 0x26, 0x09, 0xb8, 0x1f, 0xb5, 0x42, 0x55, 0xc4, 0x46, 0x5f, 0x2a, 0x97, 0xaf, 0x58, 0xc1, 0xfb, 0x65, 0x51, 0x7e, 0x70, 0x6d, 0xa9, 0x79, 0xcd, 0xed, 0x55, 0x91, 0x59, 0x84, 0xcb, 0xa6, 0x92, 0x15, 0x28, 0x1b, 0xa2, 0x83, 0xc1, 0x76, 0x3a, 0x3a, 0x59, 0x0d, 0x65, 0x38, 0xb7, 0x66, 0x47, 0x4b, 0x6a, 0xc4, 0x3f, 0xe1, 0x1e, 0x6c, 0x0c, 0x6f, 0xe9, 0xf7, 0x99, 0x43, 0xa3, 0x84, 0x0b, 0x78, 0x92, 0x98, 0x5a, 0x7e, 0x7c, 0x89, 0x72, 0xd3, 0xf7, 0xcc, 0x4a, 0x46, 0x9d, 0xaa, 0x57, 0x21, 0xa4, 0xd6, 0x4d, 0x0a, 0x9b, 0x80, 0x9c, 0xac, 0x01, 0xd2, 0x51, 0x12, 0x2d, 0x3a, 0x74, 0x7c, 0x84, 0x8a, 0xd0, 0x92, 0x6d, 0x8d, 0xd6, 0x1e, 0x41, 0xb9, 0x70, 0x0f, 0xb7, 0x33, 0xcf, 0x7c, 0x5f, 0xad, 0x68, 0x0c, 0xde, 0x24, 0x6c, 0x37, 0x6c, 0xc8, 0xe6, 0x86, 0x3e, 0xfa, 0x54, 0x9f, 0x27, 0xfa, 0x7b, 0x64, 0x43, 0x38, 0xe2, 0xf4, 0x3b, 0x3b, 0xb9, 0x88, 0x27, 0x02, 0x49, 0x0b, 0xa1, 0x8f, 0xf9, 0xe5, 0x25, 0x07, 0x99, 0xa7, 0x02, 0x25, 0xbd, 0xda, 0xa4, 0x34, 0xd9, 0x54, 0x6e, 0xcf, 0x40, 0x0d, 0xfa, 0xab, 0xbe, 0xe3, 0x2b, 0x11, 0x87, 0x7c, 0x36, 0x55, 0xdc, 0x91, 0xf4, 0x8c, 0x13, 0x19, 0x36, 0x1a, 0x7e, 0x50, 0xbf, 0x76, 0x21, 0xcf, 0x22, 0x30, 0x8b, 0xb7, 0x66, 0x72, 0xd3, 0x8b, 0x8f, 0x34, 0x94, 0x16, 0xd0, 0x03, 0x6c, 0x18, 0xe8, 0x7e, 0xfa, 0x6b, 0x53, 0x1a, 0x54, 0x47, 0xd8, 0xe9, 0xcc, 0x37, 0xd8, 0x54, 0xd1, 0xc7, 0x40, 0x07, 0x07, 0xa0, 0xbd, 0xe4, 0x3d, 0xfd, 0x64, 0x03, 0x8d, 0x49, 0x06, 0x2e, 0xcc, 0x3f, 0x58, 0x11, 0x6d, 0x84, 0xa1, 0x3d, 0xc8, 0x61, 0x41, 0xe8, 0x8c, 0x87, 0x92, 0x4c, 0x7c, 0xae, 0x08, 0x29, 0xae, 0xd6, 0x25, 0x99, 0x59, 0x6f, 0x71, 0x36, 0x89, 0x4d, 0x46, 0x49, 0x1d, 0x92, 0x25, 0xa1, 0xa3, 0x75, 0x7a, 0x53, 0xb8, 0x0b, 0x56, 0xc0, 0x98, 0x44, 0x7e, 0x21, 0x17, 0x11, 0xb8, 0x88, 0x1b, 0x11, 0xd8, 0x96, 0xf0, 0xa4, 0x89, 0x78, 0x5b, 0x59, 0x05, 0xa9, 0x87, 0xff, 0x61, 0x9e, 0x77, 0xb4, 0x88, 0x37, 0x9b, 0xa2, 0x96, 0x50, 0x02, 0x94, 0x69, 0x01, 0x20, 0x38, 0x9c, 0x87, 0x94, 0x1d, 0x86, 0x30, 0x14, 0x1f, 0xb1, 0x4b, 0x38, 0x67, 0x85, 0x65, 0x4c, 0x0c, 0xe5, 0xb3, 0x5b, 0x85, 0x49, 0x30, 0x4f, 0x8b, 0x69, 0x67, 0xa0, 0x4b, 0xee, 0x89, 0x0d, 0xbb, 0x04, 0x7a, 0xfe, 0x96, 0x3f, 0x40, 0xf4, 0x69, 0xfe, 0x70, 0x42, 0x76, 0x95, 0xb8, 0xb2, 0xc2, 0xc7, 0xf0, 0x84, 0xc7, 0x42, 0x7b, 0x15, 0x26, 0x02, 0xad, 0x97, 0x86, 0x9c, 0x36, 0x39, 0x40, 0x83, 0xb7, 0x12, 0xa6, 0x66, 0xae, 0x42, 0xf3, 0x18, 0x2c, 0x49, 0xb8, 0x3f, 0x84, 0x6e, 0xe1, 0x5b, 0xca, 0x43, 0xa0, 0x42, 0xc3, 0xb5, 0x0a, 0x87, 0x31, 0x5a, 0x26, 0xe7, 0xc9, 0x26, 0xe0, 0x96, 0x98, 0x06, 0x15, 0xcd, 0x57, 0xc5, 0x60, 0x7c, 0x6e, 0xff, 0xb3, 0x13, 0xec, 0x02, 0xaf, 0xec, 0x13, 0x87, 0x36, 0x75, 0x9a, 0xec, 0x77, 0x2d, 0x0b, 0x5b, 0xbf, 0x8f, 0x87, 0x9c, 0x59, 0x44, 0xc5, 0x08, 0xe6, 0xc8, 0xa3, 0x94, 0xcc, 0xe8, 0x78, 0xb7, 0x7c, 0x96, 0xa2, 0xe4, 0xc1, 0xc0, 0x91, 0x34, 0xb2, 0x2d, 0x51, 0x7f, 0xc1, 0xf1, 0xc2, 0x6b, 0x43, 0xa4, 0xef, 0x8a, 0x5f, 0x7c, 0xa9, 0xc8, 0x0f, 0xea, 0xa2, 0xe1, 0x54, 0x0d, 0xeb, 0x18, 0x04, 0x1f, 0xc7, 0xaa, 0xbe, 0x4c, 0xa6, 0x55, 0x0c, 0x0a, 0x26, 0xab, 0xca, 0xed, 0x58, 0x4c, 0x76, 0x24, 0xbe, 0x7d, 0x31, 0x54, 0xd0, 0xfb, 0x78, 0x98, 0x4b, 0x39, 0x74, 0x91, 0xb2, 0x7e, 0x36, 0x96, 0x6f, 0x08, 0x04, 0x2c, 0x62, 0x14, 0xca, 0x2a, 0xb9, 0xbb, 0xf6, 0x4a, 0x9a, 0xc2, 0x2e, 0xb3, 0x4b, 0xa0, 0x0a, 0xba, 0x57, 0xee, 0xbc, 0xbc, 0x01, 0x98, 0x61, 0xda, 0x5c, 0x19, 0x53, 0x92, 0x4c, 0xb8, 0x67, 0x21, 0x85, 0x14, 0x1c, 0xe1, 0x41, 0x43, 0xd0, 0x58, 0x1e, 0x1f, 0xd9, 0x86, 0x1d, 0xe8, 0xa2, 0xf2, 0xaa, 0x32, 0x72, 0x85, 0x9b, 0xff, 0xc7, 0x24, 0x0c, 0x24, 0x0b, 0xdb, 0x8a, 0x65, 0x2e, 0xfb, 0x6b, 0x70, 0x94, 0xc5, 0xe5, 0x68, 0x5f, 0x53, 0xc4, 0x91, 0x42, 0x94, 0x0e, 0xc6, 0xa0, 0x5b, 0xc2, 0xb7, 0xbc, 0xea, 0xfa, 0x21, 0xfe, 0x21, 0xa9, 0x73, 0xf1, 0x8c, 0xac, 0xdb, 0x14, 0x99, 0x0b, 0x43, 0x4b, 0x59, 0x52, 0x1d, 0xb1, 0x4c, 0x63, 0x78, 0xb6, 0x16, 0x0a, 0xca, 0xc7, 0xd9, 0x2d, 0x0e, 0x16, 0x91, 0x3f, 0xd5, 0x28, 0x5f, 0xb4, 0x26, 0x49, 0xcc, 0xc8, 0xe2, 0xa1, 0x8c, 0x63, 0x70, 0x00, 0x4e, 0xc4, 0x44, 0x3d, 0x4b, 0xac, 0x7c, 0x42, 0xc8, 0x53, 0xf2, 0x2a, 0xe2, 0x34, 0x42, 0x9a, 0xfc, 0x0a, 0x9f, 0x30, 0x40, 0xaf, 0xac, 0xb3, 0x88, 0x22, 0x1b, 0x26, 0x80, 0xc9, 0x9f, 0xb0, 0x4a, 0x30, 0x2c, 0x14, 0xbd, 0x16, 0x26, 0x11, 0x30, 0xad, 0x8b, 0xf9, 0x0e, 0x00, 0x46, 0xc4, 0x32, 0xb9, 0x03, 0x43, 0xf5, 0x90, 0xf8, 0xa6, 0x43, 0xfc, 0xa5, 0x46, 0x40, 0x1a, 0xc6, 0x41, 0xdb, 0xb3, 0x53, 0x11, 0x5c, 0xb7, 0x2a, 0x32, 0x5c, 0x34, 0x1c, 0x72, 0xd2, 0x95, 0x68, 0xf3, 0xb0, 0x1e, 0x17, 0x07, 0xd0, 0xeb, 0x7f, 0x49, 0xf7, 0x21, 0xac, 0xa0, 0x51, 0x3c, 0x81, 0x28, 0x5d, 0x6c, 0x0d, 0x7c, 0x83, 0x27, 0x08, 0x44, 0x19, 0xc8, 0xa1, 0xcb, 0x00, 0xf0, 0xc8, 0x10, 0x96, 0x31, 0x50, 0x10, 0xa6, 0x2e, 0x39, 0x72, 0x78, 0xcb, 0x02, 0x4c, 0x35, 0x26, 0xc1, 0x4b, 0x53, 0xbe, 0xe3, 0x44, 0x6c, 0x22, 0xb1, 0xca, 0x46, 0x97, 0xee, 0xe5, 0x72, 0x4d, 0x83, 0x42, 0x5a, 0x89, 0x80, 0xcd, 0x74, 0x73, 0x7d, 0x45, 0x1f, 0x1c, 0x02, 0xa7, 0x07, 0xa9, 0x9c, 0x60, 0x47, 0x2a, 0x35, 0xc9, 0xa8, 0xae, 0x1c, 0x2d, 0x7b, 0x68, 0x07, 0x31, 0x89, 0x3b, 0xa8, 0x29, 0x86, 0xaf, 0x27, 0x0f, 0xff, 0xb4, 0x00, 0x2d, 0x50, 0xc7, 0xc3, 0xc0, 0x6d, 0xc4, 0xb1, 0x1e, 0xd2, 0xe6, 0xb0, 0x2e, 0x42, 0x7c, 0xc8, 0xb7, 0xce, 0x19, 0x58, 0x6c, 0x4f, 0x71, 0x8f, 0x55, 0x06, 0x2f, 0xa8, 0xb3, 0x1c, 0x37, 0x4c, 0x2d, 0x48, 0x3b, 0x7f, 0x87, 0xe1, 0x8b, 0x3a, 0x86, 0x9a, 0xb7, 0xc2, 0x4a, 0xfe, 0x38, 0x73, 0x24, 0x31, 0x0f, 0x32, 0xb7, 0x75, 0xcf, 0xf7, 0xba, 0x77, 0x88, 0x47, 0xc8, 0x82, 0x61, 0xaf, 0x43, 0x88, 0xe4, 0x6a, 0x34, 0x01, 0x9c, 0x9b, 0xc2, 0x51, 0x4d, 0xa8, 0x10, 0x8d, 0x37, 0x31, 0x67, 0x61, 0x28, 0x04, 0xe1, 0xe2, 0xc1, 0xab, 0xa3, 0x48, 0x9c, 0x70, 0x84, 0x4a, 0x94, 0xc3, 0xfb, 0x73, 0x8f, 0x33, 0x79, 0x67, 0x95, 0xc1, 0x92, 0x1e, 0x6b, 0x81, 0xec, 0x64, 0x19, 0x79, 0xaa, 0x0f, 0xa1, 0x06, 0xa9, 0x37, 0x9c, 0xc5, 0x3a, 0xd6, 0x2d, 0x6b, 0xc5, 0x84, 0x12, 0x71, 0xb9, 0xb6, 0x6a, 0x64, 0xfd, 0x08, 0x86, 0x68, 0xa0, 0x62, 0x1e, 0xd5, 0xae, 0x4f, 0x79, 0x2e, 0x24, 0x1c, 0x43, 0xd2, 0xd3, 0x2e, 0xbb, 0xe5, 0xb7, 0x0f, 0xf5, 0x3d, 0xe2, 0xeb, 0x7f, 0x45, 0x29, 0x1a, 0x85, 0x05, 0x49, 0xaf, 0xcc, 0x59, 0xa8, 0x30, 0xa2, 0xa8, 0x31, 0x83, 0x29, 0xb5, 0x4f, 0xbd, 0xe1, 0x7e, 0xf7, 0xb2, 0xae, 0xeb, 0x43, 0xb6, 0xf5, 0xc5, 0xa1, 0x91, 0x69, 0x1a, 0x8c, 0x08, 0x4e, 0x8f, 0xd6, 0x35, 0x6a, 0x82, 0x54, 0xfb, 0x44, 0xcc, 0x6d, 0xb4, 0x27, 0xaf, 0xac, 0x2f, 0x5d, 0xc8, 0x15, 0xa7, 0xe7, 0x93, 0x79, 0xe0, 0x4c, 0x75, 0xf3, 0x68, 0x18, 0xe0, 0x7f, 0x85, 0x30, 0x8a, 0x30, 0x5a, 0x1e, 0xbc, 0x20, 0x69, 0xa2, 0x4e, 0xf5, 0x16, 0x90, 0x3d, 0x42, 0x80, 0xb1, 0x40, 0xdb, 0xdc, 0x3b, 0x7e, 0x11, 0x82, 0x75, 0x1a, 0x69, 0xef, 0xe9, 0x6e, 0x47, 0x33, 0xd0, 0x97, 0xd8, 0x32, 0x8d, 0xf5, 0xc2, 0x17, 0xbd, 0x15, 0x64, 0x2e, 0xc8, 0xee, 0xba, 0x21, 0x4e, 0x09, 0x68, 0xb0, 0xad, 0xa7, 0x87, 0x78, 0xc6, 0x48, 0xc3, 0x3a, 0x29, 0x58, 0x34, 0x8d, 0xcf, 0xd9, 0xb9, 0x57, 0x50, 0xc0, 0xa9, 0xe2, 0x40, 0x53, 0xed, 0x3c, 0x7b, 0x86, 0x16, 0xd9, 0xcf, 0xd4, 0x8a, 0x28, 0xed, 0xfe, 0x4e, 0xe1, 0x4b, 0x97, 0x19, 0xec }, .priv_len = 1632, .pub = { 0x78, 0x5b, 0x59, 0x05, 0xa9, 0x87, 0xff, 0x61, 0x9e, 0x77, 0xb4, 0x88, 0x37, 0x9b, 0xa2, 0x96, 0x50, 0x02, 0x94, 0x69, 0x01, 0x20, 0x38, 0x9c, 0x87, 0x94, 0x1d, 0x86, 0x30, 0x14, 0x1f, 0xb1, 0x4b, 0x38, 0x67, 0x85, 0x65, 0x4c, 0x0c, 0xe5, 0xb3, 0x5b, 0x85, 0x49, 0x30, 0x4f, 0x8b, 0x69, 0x67, 0xa0, 0x4b, 0xee, 0x89, 0x0d, 0xbb, 0x04, 0x7a, 0xfe, 0x96, 0x3f, 0x40, 0xf4, 0x69, 0xfe, 0x70, 0x42, 0x76, 0x95, 0xb8, 0xb2, 0xc2, 0xc7, 0xf0, 0x84, 0xc7, 0x42, 0x7b, 0x15, 0x26, 0x02, 0xad, 0x97, 0x86, 0x9c, 0x36, 0x39, 0x40, 0x83, 0xb7, 0x12, 0xa6, 0x66, 0xae, 0x42, 0xf3, 0x18, 0x2c, 0x49, 0xb8, 0x3f, 0x84, 0x6e, 0xe1, 0x5b, 0xca, 0x43, 0xa0, 0x42, 0xc3, 0xb5, 0x0a, 0x87, 0x31, 0x5a, 0x26, 0xe7, 0xc9, 0x26, 0xe0, 0x96, 0x98, 0x06, 0x15, 0xcd, 0x57, 0xc5, 0x60, 0x7c, 0x6e, 0xff, 0xb3, 0x13, 0xec, 0x02, 0xaf, 0xec, 0x13, 0x87, 0x36, 0x75, 0x9a, 0xec, 0x77, 0x2d, 0x0b, 0x5b, 0xbf, 0x8f, 0x87, 0x9c, 0x59, 0x44, 0xc5, 0x08, 0xe6, 0xc8, 0xa3, 0x94, 0xcc, 0xe8, 0x78, 0xb7, 0x7c, 0x96, 0xa2, 0xe4, 0xc1, 0xc0, 0x91, 0x34, 0xb2, 0x2d, 0x51, 0x7f, 0xc1, 0xf1, 0xc2, 0x6b, 0x43, 0xa4, 0xef, 0x8a, 0x5f, 0x7c, 0xa9, 0xc8, 0x0f, 0xea, 0xa2, 0xe1, 0x54, 0x0d, 0xeb, 0x18, 0x04, 0x1f, 0xc7, 0xaa, 0xbe, 0x4c, 0xa6, 0x55, 0x0c, 0x0a, 0x26, 0xab, 0xca, 0xed, 0x58, 0x4c, 0x76, 0x24, 0xbe, 0x7d, 0x31, 0x54, 0xd0, 0xfb, 0x78, 0x98, 0x4b, 0x39, 0x74, 0x91, 0xb2, 0x7e, 0x36, 0x96, 0x6f, 0x08, 0x04, 0x2c, 0x62, 0x14, 0xca, 0x2a, 0xb9, 0xbb, 0xf6, 0x4a, 0x9a, 0xc2, 0x2e, 0xb3, 0x4b, 0xa0, 0x0a, 0xba, 0x57, 0xee, 0xbc, 0xbc, 0x01, 0x98, 0x61, 0xda, 0x5c, 0x19, 0x53, 0x92, 0x4c, 0xb8, 0x67, 0x21, 0x85, 0x14, 0x1c, 0xe1, 0x41, 0x43, 0xd0, 0x58, 0x1e, 0x1f, 0xd9, 0x86, 0x1d, 0xe8, 0xa2, 0xf2, 0xaa, 0x32, 0x72, 0x85, 0x9b, 0xff, 0xc7, 0x24, 0x0c, 0x24, 0x0b, 0xdb, 0x8a, 0x65, 0x2e, 0xfb, 0x6b, 0x70, 0x94, 0xc5, 0xe5, 0x68, 0x5f, 0x53, 0xc4, 0x91, 0x42, 0x94, 0x0e, 0xc6, 0xa0, 0x5b, 0xc2, 0xb7, 0xbc, 0xea, 0xfa, 0x21, 0xfe, 0x21, 0xa9, 0x73, 0xf1, 0x8c, 0xac, 0xdb, 0x14, 0x99, 0x0b, 0x43, 0x4b, 0x59, 0x52, 0x1d, 0xb1, 0x4c, 0x63, 0x78, 0xb6, 0x16, 0x0a, 0xca, 0xc7, 0xd9, 0x2d, 0x0e, 0x16, 0x91, 0x3f, 0xd5, 0x28, 0x5f, 0xb4, 0x26, 0x49, 0xcc, 0xc8, 0xe2, 0xa1, 0x8c, 0x63, 0x70, 0x00, 0x4e, 0xc4, 0x44, 0x3d, 0x4b, 0xac, 0x7c, 0x42, 0xc8, 0x53, 0xf2, 0x2a, 0xe2, 0x34, 0x42, 0x9a, 0xfc, 0x0a, 0x9f, 0x30, 0x40, 0xaf, 0xac, 0xb3, 0x88, 0x22, 0x1b, 0x26, 0x80, 0xc9, 0x9f, 0xb0, 0x4a, 0x30, 0x2c, 0x14, 0xbd, 0x16, 0x26, 0x11, 0x30, 0xad, 0x8b, 0xf9, 0x0e, 0x00, 0x46, 0xc4, 0x32, 0xb9, 0x03, 0x43, 0xf5, 0x90, 0xf8, 0xa6, 0x43, 0xfc, 0xa5, 0x46, 0x40, 0x1a, 0xc6, 0x41, 0xdb, 0xb3, 0x53, 0x11, 0x5c, 0xb7, 0x2a, 0x32, 0x5c, 0x34, 0x1c, 0x72, 0xd2, 0x95, 0x68, 0xf3, 0xb0, 0x1e, 0x17, 0x07, 0xd0, 0xeb, 0x7f, 0x49, 0xf7, 0x21, 0xac, 0xa0, 0x51, 0x3c, 0x81, 0x28, 0x5d, 0x6c, 0x0d, 0x7c, 0x83, 0x27, 0x08, 0x44, 0x19, 0xc8, 0xa1, 0xcb, 0x00, 0xf0, 0xc8, 0x10, 0x96, 0x31, 0x50, 0x10, 0xa6, 0x2e, 0x39, 0x72, 0x78, 0xcb, 0x02, 0x4c, 0x35, 0x26, 0xc1, 0x4b, 0x53, 0xbe, 0xe3, 0x44, 0x6c, 0x22, 0xb1, 0xca, 0x46, 0x97, 0xee, 0xe5, 0x72, 0x4d, 0x83, 0x42, 0x5a, 0x89, 0x80, 0xcd, 0x74, 0x73, 0x7d, 0x45, 0x1f, 0x1c, 0x02, 0xa7, 0x07, 0xa9, 0x9c, 0x60, 0x47, 0x2a, 0x35, 0xc9, 0xa8, 0xae, 0x1c, 0x2d, 0x7b, 0x68, 0x07, 0x31, 0x89, 0x3b, 0xa8, 0x29, 0x86, 0xaf, 0x27, 0x0f, 0xff, 0xb4, 0x00, 0x2d, 0x50, 0xc7, 0xc3, 0xc0, 0x6d, 0xc4, 0xb1, 0x1e, 0xd2, 0xe6, 0xb0, 0x2e, 0x42, 0x7c, 0xc8, 0xb7, 0xce, 0x19, 0x58, 0x6c, 0x4f, 0x71, 0x8f, 0x55, 0x06, 0x2f, 0xa8, 0xb3, 0x1c, 0x37, 0x4c, 0x2d, 0x48, 0x3b, 0x7f, 0x87, 0xe1, 0x8b, 0x3a, 0x86, 0x9a, 0xb7, 0xc2, 0x4a, 0xfe, 0x38, 0x73, 0x24, 0x31, 0x0f, 0x32, 0xb7, 0x75, 0xcf, 0xf7, 0xba, 0x77, 0x88, 0x47, 0xc8, 0x82, 0x61, 0xaf, 0x43, 0x88, 0xe4, 0x6a, 0x34, 0x01, 0x9c, 0x9b, 0xc2, 0x51, 0x4d, 0xa8, 0x10, 0x8d, 0x37, 0x31, 0x67, 0x61, 0x28, 0x04, 0xe1, 0xe2, 0xc1, 0xab, 0xa3, 0x48, 0x9c, 0x70, 0x84, 0x4a, 0x94, 0xc3, 0xfb, 0x73, 0x8f, 0x33, 0x79, 0x67, 0x95, 0xc1, 0x92, 0x1e, 0x6b, 0x81, 0xec, 0x64, 0x19, 0x79, 0xaa, 0x0f, 0xa1, 0x06, 0xa9, 0x37, 0x9c, 0xc5, 0x3a, 0xd6, 0x2d, 0x6b, 0xc5, 0x84, 0x12, 0x71, 0xb9, 0xb6, 0x6a, 0x64, 0xfd, 0x08, 0x86, 0x68, 0xa0, 0x62, 0x1e, 0xd5, 0xae, 0x4f, 0x79, 0x2e, 0x24, 0x1c, 0x43, 0xd2, 0xd3, 0x2e, 0xbb, 0xe5, 0xb7, 0x0f, 0xf5, 0x3d, 0xe2, 0xeb, 0x7f, 0x45, 0x29, 0x1a, 0x85, 0x05, 0x49, 0xaf, 0xcc, 0x59, 0xa8, 0x30, 0xa2, 0xa8, 0x31, 0x83, 0x29, 0xb5, 0x4f, 0xbd, 0xe1, 0x7e, 0xf7, 0xb2, 0xae, 0xeb, 0x43, 0xb6, 0xf5, 0xc5, 0xa1, 0x91, 0x69, 0x1a, 0x8c, 0x08, 0x4e, 0x8f, 0xd6, 0x35, 0x6a, 0x82, 0x54, 0xfb, 0x44, 0xcc, 0x6d, 0xb4, 0x27, 0xaf, 0xac, 0x2f, 0x5d, 0xc8, 0x15, 0xa7, 0xe7, 0x93, 0x79, 0xe0, 0x4c, 0x75, 0xf3, 0x68, 0x18, 0xe0, 0x7f, 0x85, 0x30, 0x8a, 0x30, 0x5a, 0x1e, 0xbc, 0x20, 0x69, 0xa2, 0x4e, 0xf5, 0x16, 0x90, 0x3d, 0x42, 0x80, 0xb1, 0x40, 0xdb, 0xdc, 0x3b, 0x7e, 0x11, 0x82, 0x75, 0x1a, 0x69, 0xef }, .pub_len = 800, }, { .name = "ML-KEM 786 (priv only)", .parameter_set = CKP_ML_KEM_768, .priv = { 0x50, 0x75, 0x81, 0xed, 0x26, 0x8a, 0xd2, 0x85, 0x86, 0x5d, 0x31, 0x4e, 0x54, 0x34, 0x20, 0xd9, 0x54, 0xb6, 0xde, 0xc2, 0xb2, 0x3b, 0xca, 0x32, 0x32, 0x60, 0x9c, 0x85, 0x50, 0x04, 0x48, 0x59, 0x42, 0xa1, 0xb5, 0x3b, 0x44, 0x13, 0x61, 0x99, 0xe5, 0x5c, 0xf1, 0xf1, 0x5d, 0x9e, 0xf8, 0x33, 0x45, 0x80, 0xc5, 0x48, 0xd0, 0x3d, 0x68, 0x30, 0x99, 0x0d, 0x27, 0x9a, 0x19, 0x10, 0x66, 0x00, 0xb1, 0x8b, 0xbd, 0xcb, 0x85, 0x45, 0xf0, 0x5f, 0xee, 0xb9, 0x8c, 0x81, 0x57, 0x4b, 0x64, 0x60, 0xbf, 0x3e, 0x98, 0x2e, 0xa6, 0x3b, 0xa5, 0xc6, 0xe6, 0x81, 0xd7, 0x46, 0x99, 0x34, 0x12, 0x36, 0x2a, 0x1c, 0x55, 0x28, 0x14, 0x24, 0xe4, 0xfa, 0xc2, 0x4c, 0x44, 0xb3, 0x78, 0x09, 0x12, 0x25, 0xc4, 0x91, 0x4e, 0x39, 0x3a, 0xef, 0x2a, 0xa8, 0x56, 0xec, 0x3b, 0x80, 0x6a, 0x9f, 0xa7, 0x4c, 0x43, 0x9e, 0x95, 0x70, 0x12, 0xab, 0x89, 0xac, 0x8a, 0x67, 0x70, 0x69, 0x85, 0x83, 0x1a, 0x04, 0x75, 0x05, 0x02, 0x76, 0xbc, 0x8a, 0xa8, 0xc7, 0x29, 0xe4, 0x90, 0x30, 0xea, 0x55, 0x41, 0x9d, 0x02, 0xbc, 0xfb, 0x8b, 0x75, 0x7d, 0xb4, 0xa9, 0x42, 0xf1, 0xa7, 0x74, 0x56, 0xcc, 0xdc, 0xd1, 0x3b, 0x32, 0x8c, 0x1c, 0xc1, 0xc9, 0xa6, 0xdd, 0xb7, 0x6f, 0xc9, 0x5a, 0x8d, 0xd2, 0x14, 0x3c, 0xc6, 0x01, 0x78, 0x4c, 0xb6, 0x51, 0x98, 0xc6, 0x9f, 0x54, 0x49, 0x78, 0x59, 0xa8, 0xbc, 0x6e, 0xe7, 0x33, 0xd1, 0xf0, 0xbf, 0x77, 0xa2, 0xa4, 0x89, 0x76, 0xab, 0x7c, 0xe7, 0xc1, 0x28, 0x97, 0x03, 0x58, 0x22, 0x59, 0x2f, 0x90, 0x0e, 0xdc, 0x02, 0x40, 0xd2, 0xb8, 0x61, 0x01, 0x41, 0xa9, 0xae, 0x9a, 0x3b, 0xa1, 0x8c, 0x6b, 0xec, 0xc9, 0x06, 0x1a, 0x14, 0x97, 0x8e, 0x00, 0x28, 0xd7, 0xb6, 0x1e, 0xd4, 0x67, 0x53, 0xdc, 0x63, 0x4c, 0x92, 0xe6, 0x0e, 0xe2, 0x48, 0x3e, 0x7e, 0x07, 0xa5, 0x5d, 0x93, 0x66, 0x54, 0xb3, 0x0b, 0xde, 0xab, 0x94, 0x77, 0xdc, 0xc6, 0xdd, 0x9c, 0x0a, 0x4f, 0x12, 0x53, 0xc4, 0x2c, 0x24, 0x75, 0xab, 0x69, 0x73, 0x00, 0x1a, 0x3c, 0x28, 0x26, 0xcb, 0xa4, 0x4f, 0xfd, 0xf1, 0x07, 0x00, 0x49, 0x01, 0xe1, 0x5b, 0x26, 0xbf, 0x0c, 0x2c, 0x1c, 0x3b, 0xc5, 0xd5, 0x22, 0xcb, 0x6c, 0xa9, 0x32, 0x6e, 0xa2, 0xb1, 0xc7, 0x48, 0x73, 0x78, 0xe8, 0xaa, 0x49, 0x20, 0x64, 0xbc, 0xc4, 0x0f, 0xed, 0x48, 0x07, 0xee, 0x1c, 0xa9, 0xc8, 0xcb, 0x85, 0x44, 0xa2, 0x93, 0xe8, 0xa8, 0x6c, 0x65, 0x46, 0xad, 0x68, 0x06, 0x9d, 0x43, 0xc5, 0xa4, 0x09, 0xd8, 0x85, 0x12, 0xa9, 0x9f, 0xec, 0x1b, 0x37, 0x8f, 0x30, 0xcd, 0xf8, 0x68, 0x8b, 0xf9, 0x1a, 0x03, 0x09, 0x8c, 0x08, 0x3f, 0xd1, 0x56, 0xbe, 0x05, 0x9b, 0x24, 0xf2, 0x19, 0x34, 0xa3, 0x50, 0xa9, 0x7c, 0x0e, 0x6f, 0x38, 0x3e, 0xea, 0xba, 0x03, 0x01, 0x80, 0x6a, 0x35, 0x78, 0x67, 0xdc, 0x02, 0x53, 0x1f, 0x9c, 0xba, 0xb7, 0xd1, 0xb3, 0xa2, 0x96, 0x22, 0xaf, 0x15, 0x10, 0x30, 0xa5, 0x0b, 0xeb, 0x47, 0x3d, 0xa7, 0x60, 0x5d, 0xb3, 0xe2, 0x4c, 0x45, 0x1b, 0x39, 0x32, 0xfb, 0xa4, 0xb1, 0x94, 0x84, 0xf2, 0x3c, 0x28, 0x47, 0xf8, 0x0b, 0xaf, 0x96, 0x87, 0xe4, 0xd0, 0x49, 0xa0, 0x49, 0x67, 0x29, 0x8c, 0xc7, 0xd7, 0x72, 0x4c, 0x0f, 0x1a, 0x69, 0xac, 0x3c, 0xc7, 0x93, 0x3a, 0xaf, 0x0a, 0x71, 0x4a, 0x73, 0x73, 0x39, 0x70, 0x81, 0x86, 0xff, 0xc2, 0xc6, 0xf5, 0x10, 0x3d, 0x1e, 0xb3, 0x0b, 0x67, 0xdb, 0x7b, 0xf1, 0x5b, 0x4a, 0xbb, 0x33, 0x8f, 0x48, 0x8b, 0x48, 0xed, 0xc3, 0x24, 0x4d, 0x94, 0x8e, 0x17, 0x32, 0xa9, 0x96, 0xd0, 0x60, 0x61, 0x56, 0x70, 0xc3, 0x2a, 0x25, 0x0f, 0x23, 0xa1, 0x49, 0x22, 0x16, 0x32, 0x54, 0x33, 0x47, 0x1c, 0xce, 0x85, 0xbb, 0xcc, 0x8b, 0xe3, 0x4c, 0x13, 0xb9, 0xc9, 0xc3, 0x63, 0x45, 0x68, 0x22, 0x6a, 0xd3, 0x50, 0x5c, 0x77, 0xf9, 0xc3, 0xb1, 0x09, 0x1c, 0x2e, 0x6b, 0x2c, 0x17, 0x92, 0x0e, 0xe3, 0x18, 0x1b, 0x46, 0xfb, 0x18, 0xfd, 0x1a, 0xa5, 0x60, 0x87, 0x53, 0xc1, 0x80, 0x19, 0xe4, 0xd6, 0x9a, 0x22, 0x73, 0x14, 0x41, 0x0c, 0x1a, 0x4e, 0x5a, 0xbe, 0x69, 0x29, 0xb3, 0xd1, 0x64, 0x45, 0xa1, 0x3a, 0xa5, 0xc2, 0x16, 0x87, 0x92, 0x08, 0x58, 0x77, 0xa5, 0x16, 0x7c, 0xe6, 0x18, 0x7b, 0xe3, 0x84, 0xfe, 0x79, 0x10, 0x1b, 0x39, 0xc7, 0xf0, 0x7a, 0x35, 0x18, 0x00, 0xbd, 0x6c, 0x50, 0x89, 0x2a, 0x4b, 0x4b, 0xec, 0x91, 0x76, 0x8f, 0xb0, 0x56, 0x1f, 0x61, 0x37, 0x61, 0x39, 0xce, 0x65, 0xe3, 0x2c, 0xd6, 0x8c, 0x4e, 0x4e, 0x49, 0x32, 0x17, 0xa0, 0x5d, 0x6a, 0x77, 0x92, 0x7a, 0x91, 0x3f, 0x2b, 0x78, 0x4b, 0x0e, 0x7b, 0x29, 0x87, 0xe4, 0x7c, 0x97, 0xf3, 0x5b, 0x94, 0x05, 0x88, 0x7a, 0xb4, 0x96, 0x24, 0x90, 0x65, 0xf9, 0xa2, 0x04, 0x3c, 0x55, 0x7c, 0x7d, 0xe7, 0xa9, 0xde, 0x8c, 0x1f, 0xd0, 0x53, 0x3e, 0x6a, 0x12, 0xa4, 0x6f, 0xec, 0x21, 0x34, 0xd4, 0x43, 0xd0, 0xf4, 0x92, 0x7a, 0x17, 0x71, 0xfa, 0xc0, 0x30, 0xa5, 0xe5, 0x42, 0x7d, 0x36, 0x5c, 0x05, 0x19, 0x42, 0x81, 0x53, 0x25, 0xaf, 0x16, 0xc3, 0x16, 0xac, 0x22, 0x11, 0xfc, 0xaf, 0x5a, 0x54, 0x65, 0x9f, 0x06, 0xbf, 0x6c, 0xea, 0x12, 0x52, 0xd4, 0x20, 0x58, 0x73, 0xac, 0x77, 0x7a, 0xa0, 0x60, 0x85, 0xa7, 0x3e, 0xda, 0x2e, 0xbe, 0x78, 0x10, 0x0e, 0x69, 0x4e, 0x53, 0x0c, 0x77, 0xbb, 0x81, 0x36, 0x78, 0x47, 0x5d, 0x9a, 0x24, 0x6a, 0x2b, 0x2c, 0x96, 0xea, 0xc3, 0x8e, 0x35, 0x42, 0x26, 0x37, 0xb2, 0x02, 0x2a, 0x77, 0xad, 0x4d, 0x17, 0x32, 0x3c, 0xca, 0x9a, 0x05, 0x85, 0xad, 0xc6, 0x09, 0x3e, 0xce, 0xd0, 0x77, 0x08, 0x2a, 0x2d, 0x9e, 0x40, 0x58, 0xb3, 0xbc, 0x42, 0xaf, 0x8a, 0x6d, 0xeb, 0x66, 0x37, 0x88, 0xf1, 0x8e, 0x5d, 0x6c, 0x79, 0xd7, 0xc3, 0x5e, 0x58, 0x21, 0x04, 0x17, 0xc8, 0x3f, 0x62, 0x71, 0x6a, 0x05, 0x88, 0x02, 0xbf, 0xc2, 0x08, 0x34, 0xdc, 0x6a, 0xc0, 0x46, 0xae, 0xb8, 0xb6, 0x99, 0xf1, 0x35, 0x79, 0x3d, 0x4a, 0x88, 0x20, 0xc4, 0xc5, 0x5c, 0x64, 0x8c, 0xb8, 0x81, 0xb7, 0xab, 0x9a, 0x9f, 0xab, 0x41, 0x2a, 0xb4, 0x9a, 0xb1, 0xae, 0x0b, 0xa6, 0x9e, 0x77, 0x49, 0x13, 0xbb, 0x0b, 0xaa, 0x7b, 0xc6, 0x4e, 0xb6, 0xcb, 0xe1, 0xfc, 0x7e, 0x0c, 0x30, 0x3b, 0x3d, 0xe1, 0xad, 0x27, 0x21, 0x40, 0xc5, 0xd0, 0x9e, 0xa4, 0xa5, 0xab, 0xc3, 0x76, 0x41, 0x59, 0x5c, 0x43, 0x76, 0x87, 0x42, 0xd3, 0x69, 0x3d, 0x13, 0x01, 0xb9, 0xd4, 0xfb, 0xce, 0xef, 0xf2, 0x9d, 0xe2, 0x65, 0x8c, 0xdf, 0x08, 0x3e, 0x4c, 0x40, 0xa8, 0x87, 0x32, 0xa2, 0xb6, 0xc9, 0x28, 0x75, 0x56, 0x5e, 0x43, 0x33, 0x88, 0xcc, 0xec, 0x1b, 0xe2, 0x89, 0x1f, 0xb1, 0xe9, 0xce, 0x26, 0x93, 0x59, 0x43, 0x14, 0xb8, 0x0f, 0xca, 0x4b, 0x27, 0xdc, 0x34, 0xfa, 0xd2, 0x22, 0x8c, 0x78, 0x92, 0xd3, 0x00, 0xcd, 0x08, 0x79, 0xbb, 0x9b, 0x46, 0xb9, 0x36, 0x8b, 0x1b, 0x83, 0xe8, 0xc6, 0xc6, 0x45, 0xac, 0x12, 0x63, 0x8d, 0x41, 0xe5, 0xce, 0xc2, 0x43, 0x94, 0xf8, 0x34, 0xb2, 0xf9, 0xb6, 0x4b, 0xbb, 0xf5, 0x4b, 0xff, 0xd5, 0xb0, 0xcb, 0x66, 0x3a, 0xcf, 0x45, 0x7d, 0xcc, 0x7b, 0x88, 0x54, 0x7b, 0x1a, 0xfe, 0x37, 0x95, 0x73, 0xf4, 0x0b, 0x2c, 0x33, 0x1f, 0x6d, 0xa9, 0xc6, 0xd1, 0x7a, 0xcd, 0x4a, 0x8b, 0x9b, 0x31, 0xfc, 0x40, 0xe8, 0xd5, 0x3b, 0x2a, 0x63, 0xb1, 0xc7, 0x48, 0xb9, 0x43, 0xc3, 0xc5, 0x26, 0x0a, 0x62, 0x80, 0x6c, 0xb2, 0x15, 0x3a, 0x29, 0xf0, 0x33, 0x71, 0xa0, 0x98, 0x72, 0xb3, 0xa5, 0x7d, 0xff, 0x95, 0x6b, 0x7c, 0x44, 0x78, 0xab, 0x10, 0x7f, 0xf9, 0xfb, 0x31, 0x90, 0xb4, 0x0c, 0x94, 0x9c, 0x43, 0x23, 0x39, 0x28, 0xa2, 0xa8, 0xa3, 0x6c, 0xc4, 0x82, 0x35, 0x8a, 0xa5, 0x62, 0xdc, 0x1b, 0x77, 0x6a, 0xbd, 0xbe, 0xa4, 0x9f, 0x4f, 0x32, 0x30, 0xc9, 0x1c, 0x8d, 0x44, 0x59, 0x72, 0x98, 0x61, 0x67, 0x4a, 0x34, 0x74, 0x89, 0x81, 0x6d, 0x76, 0x01, 0x22, 0x38, 0x03, 0x12, 0xc3, 0x86, 0x01, 0xa5, 0x50, 0xcc, 0xa9, 0x46, 0x8c, 0x08, 0x58, 0x77, 0x35, 0xd1, 0x5a, 0x6b, 0xf9, 0x6a, 0x33, 0x95, 0x1a, 0x50, 0xe9, 0x03, 0x63, 0x1c, 0xce, 0xc7, 0x81, 0x30, 0xbd, 0xa0, 0x96, 0x63, 0xb0, 0x8c, 0xfc, 0xa2, 0x9c, 0xa2, 0xb8, 0xbb, 0x1c, 0x40, 0x04, 0x26, 0x05, 0x0e, 0xa6, 0x32, 0x99, 0x2e, 0xfa, 0xa0, 0x60, 0x61, 0x98, 0x17, 0x18, 0x14, 0xd9, 0x17, 0x07, 0xae, 0x7a, 0x9e, 0x81, 0x01, 0x1a, 0x8c, 0xc9, 0x17, 0xc2, 0x87, 0xb6, 0x3e, 0xe0, 0x35, 0x7b, 0xc6, 0x7a, 0x05, 0x16, 0x30, 0xcc, 0xc2, 0x4d, 0x90, 0xf6, 0x95, 0x61, 0xe5, 0x29, 0xfe, 0xa0, 0xb3, 0xc2, 0x28, 0x25, 0x22, 0x98, 0x2d, 0x62, 0x4a, 0x7b, 0x68, 0x29, 0xac, 0x79, 0x34, 0x05, 0xe0, 0x65, 0xa4, 0x10, 0x2b, 0x8a, 0xb4, 0x99, 0xab, 0xb3, 0xa2, 0x7f, 0x92, 0x81, 0xa9, 0xc7, 0x40, 0x40, 0xde, 0x2a, 0x9a, 0xf1, 0x20, 0x01, 0x40, 0xc3, 0xa5, 0xef, 0x0a, 0x10, 0x63, 0xfb, 0x2a, 0x8e, 0x96, 0x39, 0x9c, 0x33, 0x53, 0xd0, 0xeb, 0xa6, 0xa2, 0x1c, 0x65, 0x9b, 0xda, 0x3a, 0x17, 0x94, 0x32, 0xf8, 0xc0, 0x25, 0x4b, 0x23, 0x31, 0x90, 0xf5, 0x51, 0x93, 0x15, 0x22, 0xdc, 0xab, 0x51, 0x1c, 0xe4, 0x97, 0x70, 0x81, 0x6c, 0xb9, 0x00, 0x86, 0x86, 0xc5, 0x54, 0xfa, 0xbb, 0xc7, 0x2c, 0x48, 0x65, 0x4c, 0x65, 0xc5, 0x60, 0x20, 0x7c, 0xcc, 0x59, 0x3a, 0x1a, 0xe4, 0x4c, 0x0d, 0x79, 0x31, 0x91, 0x27, 0xcb, 0xbc, 0x00, 0x59, 0x9e, 0x37, 0xa1, 0x5b, 0xaa, 0x8d, 0x9f, 0xc8, 0x6f, 0x58, 0x4b, 0x10, 0x4a, 0x74, 0x8a, 0xfe, 0xd7, 0x69, 0xd2, 0x4c, 0x26, 0x4e, 0xec, 0x02, 0xba, 0xb3, 0xb1, 0x8d, 0x92, 0x2a, 0x2d, 0x2a, 0x24, 0x27, 0x95, 0x65, 0xc1, 0x7c, 0x65, 0x8b, 0x08, 0xd0, 0x68, 0xf4, 0x28, 0x28, 0x55, 0x93, 0x0d, 0xd8, 0xbe, 0xf7, 0x05, 0x93, 0x9b, 0x2b, 0x03, 0xc1, 0x73, 0x9b, 0x96, 0x19, 0x7e, 0xab, 0x9b, 0x30, 0x44, 0xa9, 0x5f, 0x43, 0x08, 0x52, 0x7d, 0x3b, 0xb1, 0x43, 0xf3, 0x9a, 0x92, 0x20, 0x6c, 0xe1, 0x84, 0xaa, 0x99, 0x73, 0x70, 0x75, 0x4b, 0x2a, 0xf5, 0xa6, 0x1e, 0x46, 0xdb, 0x06, 0xc8, 0x3b, 0x07, 0x8b, 0x37, 0x28, 0x49, 0x81, 0x6b, 0x18, 0xaa, 0x4d, 0x3b, 0xc6, 0xac, 0x53, 0x05, 0x2f, 0x3d, 0xc3, 0x28, 0x7b, 0xfa, 0x85, 0xb9, 0x96, 0x35, 0x44, 0x07, 0x25, 0x61, 0xa4, 0x24, 0x88, 0xdb, 0xbb, 0x36, 0x80, 0x1b, 0x20, 0xa9, 0x01, 0x55, 0x6a, 0x83, 0x63, 0xc9, 0x2b, 0x35, 0x96, 0x70, 0xee, 0xd9, 0x26, 0x0e, 0x16, 0xc7, 0xcb, 0x4a, 0x0a, 0x36, 0x8b, 0xbb, 0x89, 0xb3, 0x0e, 0x16, 0x95, 0x30, 0xbc, 0x9b, 0x94, 0xa5, 0x56, 0x2a, 0xed, 0x38, 0x25, 0x1f, 0xb7, 0x20, 0x99, 0x14, 0x72, 0x87, 0xdb, 0x83, 0x9f, 0xab, 0x98, 0x8d, 0x8a, 0x8b, 0x89, 0xab, 0x1a, 0x83, 0xe5, 0x8c, 0x4b, 0x9b, 0x5e, 0x65, 0x9c, 0x9e, 0xac, 0xc1, 0x4d, 0x92, 0x31, 0x8c, 0x32, 0x32, 0x3f, 0x08, 0xc5, 0x3f, 0x3b, 0xb1, 0x8d, 0xdd, 0xa7, 0x8b, 0x94, 0x31, 0x2e, 0x98, 0xa7, 0x9d, 0x36, 0x2b, 0xae, 0x73, 0x6a, 0xb9, 0x51, 0x57, 0x72, 0x4c, 0xc1, 0x17, 0x52, 0x42, 0x81, 0xfe, 0x3c, 0x0a, 0x33, 0x66, 0x7a, 0x9e, 0x24, 0x35, 0x33, 0x24, 0x64, 0xe4, 0xc0, 0xc6, 0x7c, 0x87, 0xb2, 0x6d, 0x7b, 0x07, 0x8e, 0xfc, 0x62, 0xb2, 0x4b, 0x33, 0xfe, 0x05, 0x28, 0x60, 0xe9, 0xa5, 0xc9, 0x04, 0x37, 0x8d, 0x4a, 0x30, 0x42, 0xbb, 0x1d, 0xf8, 0x45, 0x69, 0x74, 0xa2, 0x91, 0x61, 0xf0, 0x4d, 0xec, 0xc7, 0x18, 0x39, 0x18, 0xa6, 0x91, 0xb8, 0x26, 0x11, 0xba, 0xc5, 0x4e, 0xca, 0x1a, 0xf1, 0xe8, 0xa1, 0x4a, 0x30, 0x6b, 0x53, 0x45, 0x0f, 0xad, 0x06, 0x99, 0x3e, 0xdb, 0x0d, 0xbf, 0xf8, 0x5b, 0x4f, 0x35, 0x90, 0x36, 0xd4, 0x57, 0xba, 0xe9, 0x30, 0xf4, 0xf0, 0x41, 0x7d, 0x9a, 0xa5, 0xed, 0x89, 0xa8, 0xea, 0xb3, 0x1a, 0x7f, 0x55, 0x08, 0x14, 0xb0, 0x8c, 0x7e, 0x22, 0x8b, 0x4a, 0x92, 0x14, 0x26, 0x84, 0xb6, 0xa6, 0xf7, 0x7a, 0x59, 0xe0, 0x87, 0x94, 0x0a, 0xa5, 0x6e, 0x7b, 0xb4, 0x99, 0xa9, 0x6a, 0xff, 0xa8, 0x9a, 0xb4, 0x9c, 0x70, 0xed, 0x0a, 0x9e, 0xad, 0x37, 0xa1, 0xa6, 0x60, 0x2f, 0x51, 0x87, 0x6f, 0x37, 0x33, 0x28, 0xf4, 0xba, 0x8e, 0x14, 0xdc, 0x39, 0x17, 0x30, 0x9d, 0xf5, 0x17, 0xac, 0x3e, 0x68, 0x85, 0x01, 0x58, 0x9d, 0xbc, 0x71, 0xb2, 0xeb, 0x11, 0xc0, 0xf8, 0x74, 0x50, 0x1e, 0x09, 0x8b, 0xcb, 0x78, 0x3d, 0x17, 0x46, 0x81, 0xdc, 0x71, 0x68, 0xd6, 0x20, 0x38, 0xd8, 0x7b, 0x31, 0x5c, 0xbb, 0x9c, 0x84, 0xc9, 0x48, 0x19, 0x68, 0xb0, 0x15, 0xb2, 0x76, 0x3b, 0x59, 0x1a, 0x1e, 0x03, 0x02, 0x4f, 0x49, 0x83, 0xa1, 0x35, 0x30, 0xfa, 0x74, 0xae, 0xea, 0x53, 0x8a, 0xd2, 0x3c, 0xc2, 0xf0, 0xa7, 0xb8, 0xb8, 0x78, 0x5a, 0x58, 0x17, 0x6f, 0xa8, 0x4c, 0x1b, 0x58, 0x5a, 0xa1, 0xc3, 0x8b, 0x32, 0xc0, 0xf3, 0x6a, 0x03, 0x89, 0x20, 0xa7, 0x63, 0x3b, 0x47, 0x72, 0x8e, 0x93, 0xe7, 0xb5, 0x56, 0xa6, 0x0e, 0xbc, 0x7b, 0x61, 0xe3, 0x3a, 0xa7, 0x2a, 0x08, 0x81, 0x41, 0xb7, 0x05, 0xa4, 0x5a, 0x30, 0xd5, 0x76, 0x6d, 0x75, 0x9b, 0x64, 0x47, 0x5c, 0xb6, 0xf8, 0x04, 0x37, 0x06, 0x47, 0x55, 0x90, 0x05, 0x84, 0xdc, 0x4a, 0xc3, 0x6a, 0x19, 0x23, 0x48, 0x80, 0x76, 0x57, 0xaa, 0x5b, 0xc1, 0x11, 0x7b, 0x70, 0x13, 0xc8, 0x01, 0xa8, 0x0f, 0x94, 0x90, 0xce, 0xc1, 0x7b, 0x10, 0x10, 0x99, 0x27, 0x9c, 0xd0, 0x14, 0x5a, 0xa8, 0xce, 0x3e, 0x33, 0x7d, 0xc4, 0xe4, 0x50, 0x62, 0x56, 0x83, 0x50, 0xb1, 0x73, 0x8e, 0x67, 0x81, 0x32, 0x8b, 0x90, 0xa4, 0xa5, 0xc1, 0xc8, 0xf4, 0xa3, 0x0f, 0xb5, 0xa9, 0x34, 0xa6, 0x1b, 0x3e, 0x89, 0x36, 0x3c, 0x6a, 0x8b, 0xbd, 0x28, 0x19, 0x5a, 0x04, 0xc3, 0x40, 0xc6, 0xb9, 0xa8, 0x88, 0x4b, 0x9b, 0x4b, 0xac, 0x0d, 0x3a, 0x59, 0x38, 0x19, 0x6c, 0x71, 0x10, 0xab, 0x15, 0x82, 0x2e, 0x5c, 0xec, 0x9c, 0x8a, 0x53, 0x1d, 0x21, 0x2c, 0x0b, 0xd7, 0xc9, 0xba, 0x74, 0xca, 0x1c, 0x7c, 0x29, 0x37, 0xa5, 0x59, 0x38, 0x27, 0x75, 0x17, 0x91, 0xc1, 0x6f, 0x87, 0xe7, 0x78, 0x43, 0x68, 0xc5, 0x5b, 0xe3, 0x18, 0x41, 0x27, 0x52, 0x9c, 0x8b, 0x8c, 0x75, 0xfa, 0x0e, 0xca, 0xe4, 0x95, 0x3e, 0xc1, 0x41, 0x54, 0x31, 0x42, 0xf6, 0x13, 0x4b, 0xac, 0xcb, 0x10, 0x06, 0x61, 0x18, 0xdd, 0x8c, 0x3f, 0x87, 0x8c, 0x94, 0x40, 0x49, 0x49, 0x43, 0xfb, 0x80, 0x4b, 0xeb, 0x56, 0x08, 0x06, 0x93, 0x07, 0xb2, 0x07, 0xb7, 0x32, 0x93, 0xf2, 0x52, 0x0a, 0x20, 0xd8, 0x11, 0x33, 0x54, 0x9f, 0x19, 0x1a, 0x11, 0xc0, 0x28, 0x26, 0x9d, 0xf3, 0x59, 0x47, 0x11, 0xc1, 0xa4, 0x21, 0xc0, 0x34, 0x04, 0x78, 0xeb, 0x1b, 0xcc, 0x6d, 0xa9, 0xa1, 0x1d, 0xc0, 0x5e, 0xaf, 0x07, 0x6c, 0x0d, 0x06, 0xb6, 0xd0, 0x79, 0x61, 0xf0, 0xe9, 0xb9, 0x34, 0x10, 0xa4, 0xb5, 0x2a, 0x2a, 0xf0, 0xbc, 0x60, 0x1d, 0xc2, 0x09, 0x5d, 0x74, 0xba, 0x25, 0x9b, 0x9d, 0x27, 0xf2, 0xb6, 0x2e, 0xb7, 0x83, 0xa3, 0xeb, 0xa8, 0x9c, 0xe0, 0x62, 0x26, 0x8b, 0x0b, 0xfd, 0x49, 0x95, 0x3c, 0x2b, 0x30, 0xe6, 0x9b, 0x14, 0xfe, 0x75, 0x19, 0xf3, 0x09, 0xa1, 0x1c, 0x5a, 0x14, 0x8a, 0x60, 0x3c, 0x6d, 0x1b, 0x0b, 0xf5, 0xdb, 0x9a, 0xf0, 0x84, 0xab, 0x9e, 0x97, 0xab, 0x37, 0xc6, 0x43, 0x8f, 0x87, 0xa2, 0x37, 0x46, 0x09, 0xe5, 0xe1, 0x6b, 0x23, 0x33, 0x18, 0x24, 0xab, 0x33, 0x41, 0x50, 0x81, 0xbf, 0xa0, 0x53, 0x76, 0x24, 0x4f, 0x04, 0x62, 0x32, 0x1b, 0x3a, 0xc4, 0x5a, 0x96, 0x10, 0xe0, 0x29, 0xc0, 0xc4, 0x5c, 0x3b, 0x87, 0xb3, 0x9b, 0xfc, 0x40, 0xcc, 0x18, 0xd8, 0x11, 0xd9, 0x21, 0xca, 0xfe, 0xf3, 0xa8, 0x35, 0x68, 0x2e, 0xde, 0x7c, 0x9b, 0x1c, 0xf1, 0x5b, 0x0b, 0x77, 0x1f, 0xac, 0x5c, 0xcd, 0x93, 0xa1, 0xb2, 0xac, 0x42, 0x9a, 0x92, 0x00, 0x16, 0xa2, 0xf8, 0x41, 0x80, 0xb7, 0xbb, 0x23, 0x11, 0x97, 0x2f, 0x67, 0xda, 0x4a, 0x46, 0xf8, 0x5d, 0x7c, 0xc4, 0xa0, 0xfb, 0xf3, 0x13, 0xed, 0x0a, 0xbf, 0x1d, 0x91, 0xb3, 0xb4, 0x5e, 0xf7, 0x8b, 0xb9, 0xaa, 0xed, 0x85, 0x59, 0x2a, 0xf8, 0xab, 0x48, 0xc2, 0x63, 0x7a, 0x9e, 0x78, 0x4b, 0xaf, 0xa1, 0xe4, 0x54, 0x6c, 0x0c, 0xc5, 0x8b, 0x38, 0x4b, 0x13, 0xd8, 0xa6, 0xa3, 0x3f, 0x62, 0x19, 0xac, 0xc1, 0xb0, 0x48, 0x67, 0xba, 0xbd, 0x91, 0x3b, 0x3e, 0xfd, 0xd5, 0x3d, 0xc3, 0x2d, 0xd7, 0xd5, 0x27, 0x53, 0xf1, 0x99, 0x25, 0xcc, 0xc8, 0x60, 0x56, 0x0e, 0xf8, 0x37, 0xb2, 0x22, 0x59, 0x7b, 0xaa, 0x9f, 0x3b, 0x67, 0xf1, 0xe3, 0xdf, 0x7a }, .priv_len = 2400, .pub = { 0x38, 0x03, 0x12, 0xc3, 0x86, 0x01, 0xa5, 0x50, 0xcc, 0xa9, 0x46, 0x8c, 0x08, 0x58, 0x77, 0x35, 0xd1, 0x5a, 0x6b, 0xf9, 0x6a, 0x33, 0x95, 0x1a, 0x50, 0xe9, 0x03, 0x63, 0x1c, 0xce, 0xc7, 0x81, 0x30, 0xbd, 0xa0, 0x96, 0x63, 0xb0, 0x8c, 0xfc, 0xa2, 0x9c, 0xa2, 0xb8, 0xbb, 0x1c, 0x40, 0x04, 0x26, 0x05, 0x0e, 0xa6, 0x32, 0x99, 0x2e, 0xfa, 0xa0, 0x60, 0x61, 0x98, 0x17, 0x18, 0x14, 0xd9, 0x17, 0x07, 0xae, 0x7a, 0x9e, 0x81, 0x01, 0x1a, 0x8c, 0xc9, 0x17, 0xc2, 0x87, 0xb6, 0x3e, 0xe0, 0x35, 0x7b, 0xc6, 0x7a, 0x05, 0x16, 0x30, 0xcc, 0xc2, 0x4d, 0x90, 0xf6, 0x95, 0x61, 0xe5, 0x29, 0xfe, 0xa0, 0xb3, 0xc2, 0x28, 0x25, 0x22, 0x98, 0x2d, 0x62, 0x4a, 0x7b, 0x68, 0x29, 0xac, 0x79, 0x34, 0x05, 0xe0, 0x65, 0xa4, 0x10, 0x2b, 0x8a, 0xb4, 0x99, 0xab, 0xb3, 0xa2, 0x7f, 0x92, 0x81, 0xa9, 0xc7, 0x40, 0x40, 0xde, 0x2a, 0x9a, 0xf1, 0x20, 0x01, 0x40, 0xc3, 0xa5, 0xef, 0x0a, 0x10, 0x63, 0xfb, 0x2a, 0x8e, 0x96, 0x39, 0x9c, 0x33, 0x53, 0xd0, 0xeb, 0xa6, 0xa2, 0x1c, 0x65, 0x9b, 0xda, 0x3a, 0x17, 0x94, 0x32, 0xf8, 0xc0, 0x25, 0x4b, 0x23, 0x31, 0x90, 0xf5, 0x51, 0x93, 0x15, 0x22, 0xdc, 0xab, 0x51, 0x1c, 0xe4, 0x97, 0x70, 0x81, 0x6c, 0xb9, 0x00, 0x86, 0x86, 0xc5, 0x54, 0xfa, 0xbb, 0xc7, 0x2c, 0x48, 0x65, 0x4c, 0x65, 0xc5, 0x60, 0x20, 0x7c, 0xcc, 0x59, 0x3a, 0x1a, 0xe4, 0x4c, 0x0d, 0x79, 0x31, 0x91, 0x27, 0xcb, 0xbc, 0x00, 0x59, 0x9e, 0x37, 0xa1, 0x5b, 0xaa, 0x8d, 0x9f, 0xc8, 0x6f, 0x58, 0x4b, 0x10, 0x4a, 0x74, 0x8a, 0xfe, 0xd7, 0x69, 0xd2, 0x4c, 0x26, 0x4e, 0xec, 0x02, 0xba, 0xb3, 0xb1, 0x8d, 0x92, 0x2a, 0x2d, 0x2a, 0x24, 0x27, 0x95, 0x65, 0xc1, 0x7c, 0x65, 0x8b, 0x08, 0xd0, 0x68, 0xf4, 0x28, 0x28, 0x55, 0x93, 0x0d, 0xd8, 0xbe, 0xf7, 0x05, 0x93, 0x9b, 0x2b, 0x03, 0xc1, 0x73, 0x9b, 0x96, 0x19, 0x7e, 0xab, 0x9b, 0x30, 0x44, 0xa9, 0x5f, 0x43, 0x08, 0x52, 0x7d, 0x3b, 0xb1, 0x43, 0xf3, 0x9a, 0x92, 0x20, 0x6c, 0xe1, 0x84, 0xaa, 0x99, 0x73, 0x70, 0x75, 0x4b, 0x2a, 0xf5, 0xa6, 0x1e, 0x46, 0xdb, 0x06, 0xc8, 0x3b, 0x07, 0x8b, 0x37, 0x28, 0x49, 0x81, 0x6b, 0x18, 0xaa, 0x4d, 0x3b, 0xc6, 0xac, 0x53, 0x05, 0x2f, 0x3d, 0xc3, 0x28, 0x7b, 0xfa, 0x85, 0xb9, 0x96, 0x35, 0x44, 0x07, 0x25, 0x61, 0xa4, 0x24, 0x88, 0xdb, 0xbb, 0x36, 0x80, 0x1b, 0x20, 0xa9, 0x01, 0x55, 0x6a, 0x83, 0x63, 0xc9, 0x2b, 0x35, 0x96, 0x70, 0xee, 0xd9, 0x26, 0x0e, 0x16, 0xc7, 0xcb, 0x4a, 0x0a, 0x36, 0x8b, 0xbb, 0x89, 0xb3, 0x0e, 0x16, 0x95, 0x30, 0xbc, 0x9b, 0x94, 0xa5, 0x56, 0x2a, 0xed, 0x38, 0x25, 0x1f, 0xb7, 0x20, 0x99, 0x14, 0x72, 0x87, 0xdb, 0x83, 0x9f, 0xab, 0x98, 0x8d, 0x8a, 0x8b, 0x89, 0xab, 0x1a, 0x83, 0xe5, 0x8c, 0x4b, 0x9b, 0x5e, 0x65, 0x9c, 0x9e, 0xac, 0xc1, 0x4d, 0x92, 0x31, 0x8c, 0x32, 0x32, 0x3f, 0x08, 0xc5, 0x3f, 0x3b, 0xb1, 0x8d, 0xdd, 0xa7, 0x8b, 0x94, 0x31, 0x2e, 0x98, 0xa7, 0x9d, 0x36, 0x2b, 0xae, 0x73, 0x6a, 0xb9, 0x51, 0x57, 0x72, 0x4c, 0xc1, 0x17, 0x52, 0x42, 0x81, 0xfe, 0x3c, 0x0a, 0x33, 0x66, 0x7a, 0x9e, 0x24, 0x35, 0x33, 0x24, 0x64, 0xe4, 0xc0, 0xc6, 0x7c, 0x87, 0xb2, 0x6d, 0x7b, 0x07, 0x8e, 0xfc, 0x62, 0xb2, 0x4b, 0x33, 0xfe, 0x05, 0x28, 0x60, 0xe9, 0xa5, 0xc9, 0x04, 0x37, 0x8d, 0x4a, 0x30, 0x42, 0xbb, 0x1d, 0xf8, 0x45, 0x69, 0x74, 0xa2, 0x91, 0x61, 0xf0, 0x4d, 0xec, 0xc7, 0x18, 0x39, 0x18, 0xa6, 0x91, 0xb8, 0x26, 0x11, 0xba, 0xc5, 0x4e, 0xca, 0x1a, 0xf1, 0xe8, 0xa1, 0x4a, 0x30, 0x6b, 0x53, 0x45, 0x0f, 0xad, 0x06, 0x99, 0x3e, 0xdb, 0x0d, 0xbf, 0xf8, 0x5b, 0x4f, 0x35, 0x90, 0x36, 0xd4, 0x57, 0xba, 0xe9, 0x30, 0xf4, 0xf0, 0x41, 0x7d, 0x9a, 0xa5, 0xed, 0x89, 0xa8, 0xea, 0xb3, 0x1a, 0x7f, 0x55, 0x08, 0x14, 0xb0, 0x8c, 0x7e, 0x22, 0x8b, 0x4a, 0x92, 0x14, 0x26, 0x84, 0xb6, 0xa6, 0xf7, 0x7a, 0x59, 0xe0, 0x87, 0x94, 0x0a, 0xa5, 0x6e, 0x7b, 0xb4, 0x99, 0xa9, 0x6a, 0xff, 0xa8, 0x9a, 0xb4, 0x9c, 0x70, 0xed, 0x0a, 0x9e, 0xad, 0x37, 0xa1, 0xa6, 0x60, 0x2f, 0x51, 0x87, 0x6f, 0x37, 0x33, 0x28, 0xf4, 0xba, 0x8e, 0x14, 0xdc, 0x39, 0x17, 0x30, 0x9d, 0xf5, 0x17, 0xac, 0x3e, 0x68, 0x85, 0x01, 0x58, 0x9d, 0xbc, 0x71, 0xb2, 0xeb, 0x11, 0xc0, 0xf8, 0x74, 0x50, 0x1e, 0x09, 0x8b, 0xcb, 0x78, 0x3d, 0x17, 0x46, 0x81, 0xdc, 0x71, 0x68, 0xd6, 0x20, 0x38, 0xd8, 0x7b, 0x31, 0x5c, 0xbb, 0x9c, 0x84, 0xc9, 0x48, 0x19, 0x68, 0xb0, 0x15, 0xb2, 0x76, 0x3b, 0x59, 0x1a, 0x1e, 0x03, 0x02, 0x4f, 0x49, 0x83, 0xa1, 0x35, 0x30, 0xfa, 0x74, 0xae, 0xea, 0x53, 0x8a, 0xd2, 0x3c, 0xc2, 0xf0, 0xa7, 0xb8, 0xb8, 0x78, 0x5a, 0x58, 0x17, 0x6f, 0xa8, 0x4c, 0x1b, 0x58, 0x5a, 0xa1, 0xc3, 0x8b, 0x32, 0xc0, 0xf3, 0x6a, 0x03, 0x89, 0x20, 0xa7, 0x63, 0x3b, 0x47, 0x72, 0x8e, 0x93, 0xe7, 0xb5, 0x56, 0xa6, 0x0e, 0xbc, 0x7b, 0x61, 0xe3, 0x3a, 0xa7, 0x2a, 0x08, 0x81, 0x41, 0xb7, 0x05, 0xa4, 0x5a, 0x30, 0xd5, 0x76, 0x6d, 0x75, 0x9b, 0x64, 0x47, 0x5c, 0xb6, 0xf8, 0x04, 0x37, 0x06, 0x47, 0x55, 0x90, 0x05, 0x84, 0xdc, 0x4a, 0xc3, 0x6a, 0x19, 0x23, 0x48, 0x80, 0x76, 0x57, 0xaa, 0x5b, 0xc1, 0x11, 0x7b, 0x70, 0x13, 0xc8, 0x01, 0xa8, 0x0f, 0x94, 0x90, 0xce, 0xc1, 0x7b, 0x10, 0x10, 0x99, 0x27, 0x9c, 0xd0, 0x14, 0x5a, 0xa8, 0xce, 0x3e, 0x33, 0x7d, 0xc4, 0xe4, 0x50, 0x62, 0x56, 0x83, 0x50, 0xb1, 0x73, 0x8e, 0x67, 0x81, 0x32, 0x8b, 0x90, 0xa4, 0xa5, 0xc1, 0xc8, 0xf4, 0xa3, 0x0f, 0xb5, 0xa9, 0x34, 0xa6, 0x1b, 0x3e, 0x89, 0x36, 0x3c, 0x6a, 0x8b, 0xbd, 0x28, 0x19, 0x5a, 0x04, 0xc3, 0x40, 0xc6, 0xb9, 0xa8, 0x88, 0x4b, 0x9b, 0x4b, 0xac, 0x0d, 0x3a, 0x59, 0x38, 0x19, 0x6c, 0x71, 0x10, 0xab, 0x15, 0x82, 0x2e, 0x5c, 0xec, 0x9c, 0x8a, 0x53, 0x1d, 0x21, 0x2c, 0x0b, 0xd7, 0xc9, 0xba, 0x74, 0xca, 0x1c, 0x7c, 0x29, 0x37, 0xa5, 0x59, 0x38, 0x27, 0x75, 0x17, 0x91, 0xc1, 0x6f, 0x87, 0xe7, 0x78, 0x43, 0x68, 0xc5, 0x5b, 0xe3, 0x18, 0x41, 0x27, 0x52, 0x9c, 0x8b, 0x8c, 0x75, 0xfa, 0x0e, 0xca, 0xe4, 0x95, 0x3e, 0xc1, 0x41, 0x54, 0x31, 0x42, 0xf6, 0x13, 0x4b, 0xac, 0xcb, 0x10, 0x06, 0x61, 0x18, 0xdd, 0x8c, 0x3f, 0x87, 0x8c, 0x94, 0x40, 0x49, 0x49, 0x43, 0xfb, 0x80, 0x4b, 0xeb, 0x56, 0x08, 0x06, 0x93, 0x07, 0xb2, 0x07, 0xb7, 0x32, 0x93, 0xf2, 0x52, 0x0a, 0x20, 0xd8, 0x11, 0x33, 0x54, 0x9f, 0x19, 0x1a, 0x11, 0xc0, 0x28, 0x26, 0x9d, 0xf3, 0x59, 0x47, 0x11, 0xc1, 0xa4, 0x21, 0xc0, 0x34, 0x04, 0x78, 0xeb, 0x1b, 0xcc, 0x6d, 0xa9, 0xa1, 0x1d, 0xc0, 0x5e, 0xaf, 0x07, 0x6c, 0x0d, 0x06, 0xb6, 0xd0, 0x79, 0x61, 0xf0, 0xe9, 0xb9, 0x34, 0x10, 0xa4, 0xb5, 0x2a, 0x2a, 0xf0, 0xbc, 0x60, 0x1d, 0xc2, 0x09, 0x5d, 0x74, 0xba, 0x25, 0x9b, 0x9d, 0x27, 0xf2, 0xb6, 0x2e, 0xb7, 0x83, 0xa3, 0xeb, 0xa8, 0x9c, 0xe0, 0x62, 0x26, 0x8b, 0x0b, 0xfd, 0x49, 0x95, 0x3c, 0x2b, 0x30, 0xe6, 0x9b, 0x14, 0xfe, 0x75, 0x19, 0xf3, 0x09, 0xa1, 0x1c, 0x5a, 0x14, 0x8a, 0x60, 0x3c, 0x6d, 0x1b, 0x0b, 0xf5, 0xdb, 0x9a, 0xf0, 0x84, 0xab, 0x9e, 0x97, 0xab, 0x37, 0xc6, 0x43, 0x8f, 0x87, 0xa2, 0x37, 0x46, 0x09, 0xe5, 0xe1, 0x6b, 0x23, 0x33, 0x18, 0x24, 0xab, 0x33, 0x41, 0x50, 0x81, 0xbf, 0xa0, 0x53, 0x76, 0x24, 0x4f, 0x04, 0x62, 0x32, 0x1b, 0x3a, 0xc4, 0x5a, 0x96, 0x10, 0xe0, 0x29, 0xc0, 0xc4, 0x5c, 0x3b, 0x87, 0xb3, 0x9b, 0xfc, 0x40, 0xcc, 0x18, 0xd8, 0x11, 0xd9, 0x21, 0xca, 0xfe, 0xf3, 0xa8, 0x35, 0x68, 0x2e, 0xde, 0x7c, 0x9b, 0x1c, 0xf1, 0x5b, 0x0b, 0x77, 0x1f, 0xac, 0x5c, 0xcd, 0x93, 0xa1, 0xb2, 0xac, 0x42, 0x9a, 0x92, 0x00, 0x16, 0xa2, 0xf8, 0x41, 0x80, 0xb7, 0xbb, 0x23, 0x11, 0x97, 0x2f, 0x67, 0xda, 0x4a, 0x46, 0xf8, 0x5d, 0x7c, 0xc4, 0xa0, 0xfb, 0xf3, 0x13, 0xed, 0x0a, 0xbf, 0x1d, 0x91, 0xb3, 0xb4, 0x5e, 0xf7, 0x8b, 0xb9, 0xaa, 0xed, 0x85, 0x59, 0x2a, 0xf8, 0xab, 0x48 }, .pub_len = 1184, }, { .name = "ML-KEM 768 (seed only)", .parameter_set = CKP_ML_KEM_768, .priv_seed = { 0x66, 0x0a, 0xdc, 0x95, 0xc9, 0xc3, 0x1f, 0x0f, 0x91, 0xb6, 0xbd, 0x8b, 0x96, 0x46, 0x98, 0xc6, 0x43, 0x4d, 0x5e, 0x24, 0xaa, 0xf9, 0xb5, 0x53, 0xd6, 0xa3, 0x44, 0x2a, 0xa9, 0x40, 0x5b, 0xa7, 0x3e, 0xfd, 0xd5, 0x3d, 0xc3, 0x2d, 0xd7, 0xd5, 0x27, 0x53, 0xf1, 0x99, 0x25, 0xcc, 0xc8, 0x60, 0x56, 0x0e, 0xf8, 0x37, 0xb2, 0x22, 0x59, 0x7b, 0xaa, 0x9f, 0x3b, 0x67, 0xf1, 0xe3, 0xdf, 0x7a }, .priv_seed_len = 64, .pub = { 0x38, 0x03, 0x12, 0xc3, 0x86, 0x01, 0xa5, 0x50, 0xcc, 0xa9, 0x46, 0x8c, 0x08, 0x58, 0x77, 0x35, 0xd1, 0x5a, 0x6b, 0xf9, 0x6a, 0x33, 0x95, 0x1a, 0x50, 0xe9, 0x03, 0x63, 0x1c, 0xce, 0xc7, 0x81, 0x30, 0xbd, 0xa0, 0x96, 0x63, 0xb0, 0x8c, 0xfc, 0xa2, 0x9c, 0xa2, 0xb8, 0xbb, 0x1c, 0x40, 0x04, 0x26, 0x05, 0x0e, 0xa6, 0x32, 0x99, 0x2e, 0xfa, 0xa0, 0x60, 0x61, 0x98, 0x17, 0x18, 0x14, 0xd9, 0x17, 0x07, 0xae, 0x7a, 0x9e, 0x81, 0x01, 0x1a, 0x8c, 0xc9, 0x17, 0xc2, 0x87, 0xb6, 0x3e, 0xe0, 0x35, 0x7b, 0xc6, 0x7a, 0x05, 0x16, 0x30, 0xcc, 0xc2, 0x4d, 0x90, 0xf6, 0x95, 0x61, 0xe5, 0x29, 0xfe, 0xa0, 0xb3, 0xc2, 0x28, 0x25, 0x22, 0x98, 0x2d, 0x62, 0x4a, 0x7b, 0x68, 0x29, 0xac, 0x79, 0x34, 0x05, 0xe0, 0x65, 0xa4, 0x10, 0x2b, 0x8a, 0xb4, 0x99, 0xab, 0xb3, 0xa2, 0x7f, 0x92, 0x81, 0xa9, 0xc7, 0x40, 0x40, 0xde, 0x2a, 0x9a, 0xf1, 0x20, 0x01, 0x40, 0xc3, 0xa5, 0xef, 0x0a, 0x10, 0x63, 0xfb, 0x2a, 0x8e, 0x96, 0x39, 0x9c, 0x33, 0x53, 0xd0, 0xeb, 0xa6, 0xa2, 0x1c, 0x65, 0x9b, 0xda, 0x3a, 0x17, 0x94, 0x32, 0xf8, 0xc0, 0x25, 0x4b, 0x23, 0x31, 0x90, 0xf5, 0x51, 0x93, 0x15, 0x22, 0xdc, 0xab, 0x51, 0x1c, 0xe4, 0x97, 0x70, 0x81, 0x6c, 0xb9, 0x00, 0x86, 0x86, 0xc5, 0x54, 0xfa, 0xbb, 0xc7, 0x2c, 0x48, 0x65, 0x4c, 0x65, 0xc5, 0x60, 0x20, 0x7c, 0xcc, 0x59, 0x3a, 0x1a, 0xe4, 0x4c, 0x0d, 0x79, 0x31, 0x91, 0x27, 0xcb, 0xbc, 0x00, 0x59, 0x9e, 0x37, 0xa1, 0x5b, 0xaa, 0x8d, 0x9f, 0xc8, 0x6f, 0x58, 0x4b, 0x10, 0x4a, 0x74, 0x8a, 0xfe, 0xd7, 0x69, 0xd2, 0x4c, 0x26, 0x4e, 0xec, 0x02, 0xba, 0xb3, 0xb1, 0x8d, 0x92, 0x2a, 0x2d, 0x2a, 0x24, 0x27, 0x95, 0x65, 0xc1, 0x7c, 0x65, 0x8b, 0x08, 0xd0, 0x68, 0xf4, 0x28, 0x28, 0x55, 0x93, 0x0d, 0xd8, 0xbe, 0xf7, 0x05, 0x93, 0x9b, 0x2b, 0x03, 0xc1, 0x73, 0x9b, 0x96, 0x19, 0x7e, 0xab, 0x9b, 0x30, 0x44, 0xa9, 0x5f, 0x43, 0x08, 0x52, 0x7d, 0x3b, 0xb1, 0x43, 0xf3, 0x9a, 0x92, 0x20, 0x6c, 0xe1, 0x84, 0xaa, 0x99, 0x73, 0x70, 0x75, 0x4b, 0x2a, 0xf5, 0xa6, 0x1e, 0x46, 0xdb, 0x06, 0xc8, 0x3b, 0x07, 0x8b, 0x37, 0x28, 0x49, 0x81, 0x6b, 0x18, 0xaa, 0x4d, 0x3b, 0xc6, 0xac, 0x53, 0x05, 0x2f, 0x3d, 0xc3, 0x28, 0x7b, 0xfa, 0x85, 0xb9, 0x96, 0x35, 0x44, 0x07, 0x25, 0x61, 0xa4, 0x24, 0x88, 0xdb, 0xbb, 0x36, 0x80, 0x1b, 0x20, 0xa9, 0x01, 0x55, 0x6a, 0x83, 0x63, 0xc9, 0x2b, 0x35, 0x96, 0x70, 0xee, 0xd9, 0x26, 0x0e, 0x16, 0xc7, 0xcb, 0x4a, 0x0a, 0x36, 0x8b, 0xbb, 0x89, 0xb3, 0x0e, 0x16, 0x95, 0x30, 0xbc, 0x9b, 0x94, 0xa5, 0x56, 0x2a, 0xed, 0x38, 0x25, 0x1f, 0xb7, 0x20, 0x99, 0x14, 0x72, 0x87, 0xdb, 0x83, 0x9f, 0xab, 0x98, 0x8d, 0x8a, 0x8b, 0x89, 0xab, 0x1a, 0x83, 0xe5, 0x8c, 0x4b, 0x9b, 0x5e, 0x65, 0x9c, 0x9e, 0xac, 0xc1, 0x4d, 0x92, 0x31, 0x8c, 0x32, 0x32, 0x3f, 0x08, 0xc5, 0x3f, 0x3b, 0xb1, 0x8d, 0xdd, 0xa7, 0x8b, 0x94, 0x31, 0x2e, 0x98, 0xa7, 0x9d, 0x36, 0x2b, 0xae, 0x73, 0x6a, 0xb9, 0x51, 0x57, 0x72, 0x4c, 0xc1, 0x17, 0x52, 0x42, 0x81, 0xfe, 0x3c, 0x0a, 0x33, 0x66, 0x7a, 0x9e, 0x24, 0x35, 0x33, 0x24, 0x64, 0xe4, 0xc0, 0xc6, 0x7c, 0x87, 0xb2, 0x6d, 0x7b, 0x07, 0x8e, 0xfc, 0x62, 0xb2, 0x4b, 0x33, 0xfe, 0x05, 0x28, 0x60, 0xe9, 0xa5, 0xc9, 0x04, 0x37, 0x8d, 0x4a, 0x30, 0x42, 0xbb, 0x1d, 0xf8, 0x45, 0x69, 0x74, 0xa2, 0x91, 0x61, 0xf0, 0x4d, 0xec, 0xc7, 0x18, 0x39, 0x18, 0xa6, 0x91, 0xb8, 0x26, 0x11, 0xba, 0xc5, 0x4e, 0xca, 0x1a, 0xf1, 0xe8, 0xa1, 0x4a, 0x30, 0x6b, 0x53, 0x45, 0x0f, 0xad, 0x06, 0x99, 0x3e, 0xdb, 0x0d, 0xbf, 0xf8, 0x5b, 0x4f, 0x35, 0x90, 0x36, 0xd4, 0x57, 0xba, 0xe9, 0x30, 0xf4, 0xf0, 0x41, 0x7d, 0x9a, 0xa5, 0xed, 0x89, 0xa8, 0xea, 0xb3, 0x1a, 0x7f, 0x55, 0x08, 0x14, 0xb0, 0x8c, 0x7e, 0x22, 0x8b, 0x4a, 0x92, 0x14, 0x26, 0x84, 0xb6, 0xa6, 0xf7, 0x7a, 0x59, 0xe0, 0x87, 0x94, 0x0a, 0xa5, 0x6e, 0x7b, 0xb4, 0x99, 0xa9, 0x6a, 0xff, 0xa8, 0x9a, 0xb4, 0x9c, 0x70, 0xed, 0x0a, 0x9e, 0xad, 0x37, 0xa1, 0xa6, 0x60, 0x2f, 0x51, 0x87, 0x6f, 0x37, 0x33, 0x28, 0xf4, 0xba, 0x8e, 0x14, 0xdc, 0x39, 0x17, 0x30, 0x9d, 0xf5, 0x17, 0xac, 0x3e, 0x68, 0x85, 0x01, 0x58, 0x9d, 0xbc, 0x71, 0xb2, 0xeb, 0x11, 0xc0, 0xf8, 0x74, 0x50, 0x1e, 0x09, 0x8b, 0xcb, 0x78, 0x3d, 0x17, 0x46, 0x81, 0xdc, 0x71, 0x68, 0xd6, 0x20, 0x38, 0xd8, 0x7b, 0x31, 0x5c, 0xbb, 0x9c, 0x84, 0xc9, 0x48, 0x19, 0x68, 0xb0, 0x15, 0xb2, 0x76, 0x3b, 0x59, 0x1a, 0x1e, 0x03, 0x02, 0x4f, 0x49, 0x83, 0xa1, 0x35, 0x30, 0xfa, 0x74, 0xae, 0xea, 0x53, 0x8a, 0xd2, 0x3c, 0xc2, 0xf0, 0xa7, 0xb8, 0xb8, 0x78, 0x5a, 0x58, 0x17, 0x6f, 0xa8, 0x4c, 0x1b, 0x58, 0x5a, 0xa1, 0xc3, 0x8b, 0x32, 0xc0, 0xf3, 0x6a, 0x03, 0x89, 0x20, 0xa7, 0x63, 0x3b, 0x47, 0x72, 0x8e, 0x93, 0xe7, 0xb5, 0x56, 0xa6, 0x0e, 0xbc, 0x7b, 0x61, 0xe3, 0x3a, 0xa7, 0x2a, 0x08, 0x81, 0x41, 0xb7, 0x05, 0xa4, 0x5a, 0x30, 0xd5, 0x76, 0x6d, 0x75, 0x9b, 0x64, 0x47, 0x5c, 0xb6, 0xf8, 0x04, 0x37, 0x06, 0x47, 0x55, 0x90, 0x05, 0x84, 0xdc, 0x4a, 0xc3, 0x6a, 0x19, 0x23, 0x48, 0x80, 0x76, 0x57, 0xaa, 0x5b, 0xc1, 0x11, 0x7b, 0x70, 0x13, 0xc8, 0x01, 0xa8, 0x0f, 0x94, 0x90, 0xce, 0xc1, 0x7b, 0x10, 0x10, 0x99, 0x27, 0x9c, 0xd0, 0x14, 0x5a, 0xa8, 0xce, 0x3e, 0x33, 0x7d, 0xc4, 0xe4, 0x50, 0x62, 0x56, 0x83, 0x50, 0xb1, 0x73, 0x8e, 0x67, 0x81, 0x32, 0x8b, 0x90, 0xa4, 0xa5, 0xc1, 0xc8, 0xf4, 0xa3, 0x0f, 0xb5, 0xa9, 0x34, 0xa6, 0x1b, 0x3e, 0x89, 0x36, 0x3c, 0x6a, 0x8b, 0xbd, 0x28, 0x19, 0x5a, 0x04, 0xc3, 0x40, 0xc6, 0xb9, 0xa8, 0x88, 0x4b, 0x9b, 0x4b, 0xac, 0x0d, 0x3a, 0x59, 0x38, 0x19, 0x6c, 0x71, 0x10, 0xab, 0x15, 0x82, 0x2e, 0x5c, 0xec, 0x9c, 0x8a, 0x53, 0x1d, 0x21, 0x2c, 0x0b, 0xd7, 0xc9, 0xba, 0x74, 0xca, 0x1c, 0x7c, 0x29, 0x37, 0xa5, 0x59, 0x38, 0x27, 0x75, 0x17, 0x91, 0xc1, 0x6f, 0x87, 0xe7, 0x78, 0x43, 0x68, 0xc5, 0x5b, 0xe3, 0x18, 0x41, 0x27, 0x52, 0x9c, 0x8b, 0x8c, 0x75, 0xfa, 0x0e, 0xca, 0xe4, 0x95, 0x3e, 0xc1, 0x41, 0x54, 0x31, 0x42, 0xf6, 0x13, 0x4b, 0xac, 0xcb, 0x10, 0x06, 0x61, 0x18, 0xdd, 0x8c, 0x3f, 0x87, 0x8c, 0x94, 0x40, 0x49, 0x49, 0x43, 0xfb, 0x80, 0x4b, 0xeb, 0x56, 0x08, 0x06, 0x93, 0x07, 0xb2, 0x07, 0xb7, 0x32, 0x93, 0xf2, 0x52, 0x0a, 0x20, 0xd8, 0x11, 0x33, 0x54, 0x9f, 0x19, 0x1a, 0x11, 0xc0, 0x28, 0x26, 0x9d, 0xf3, 0x59, 0x47, 0x11, 0xc1, 0xa4, 0x21, 0xc0, 0x34, 0x04, 0x78, 0xeb, 0x1b, 0xcc, 0x6d, 0xa9, 0xa1, 0x1d, 0xc0, 0x5e, 0xaf, 0x07, 0x6c, 0x0d, 0x06, 0xb6, 0xd0, 0x79, 0x61, 0xf0, 0xe9, 0xb9, 0x34, 0x10, 0xa4, 0xb5, 0x2a, 0x2a, 0xf0, 0xbc, 0x60, 0x1d, 0xc2, 0x09, 0x5d, 0x74, 0xba, 0x25, 0x9b, 0x9d, 0x27, 0xf2, 0xb6, 0x2e, 0xb7, 0x83, 0xa3, 0xeb, 0xa8, 0x9c, 0xe0, 0x62, 0x26, 0x8b, 0x0b, 0xfd, 0x49, 0x95, 0x3c, 0x2b, 0x30, 0xe6, 0x9b, 0x14, 0xfe, 0x75, 0x19, 0xf3, 0x09, 0xa1, 0x1c, 0x5a, 0x14, 0x8a, 0x60, 0x3c, 0x6d, 0x1b, 0x0b, 0xf5, 0xdb, 0x9a, 0xf0, 0x84, 0xab, 0x9e, 0x97, 0xab, 0x37, 0xc6, 0x43, 0x8f, 0x87, 0xa2, 0x37, 0x46, 0x09, 0xe5, 0xe1, 0x6b, 0x23, 0x33, 0x18, 0x24, 0xab, 0x33, 0x41, 0x50, 0x81, 0xbf, 0xa0, 0x53, 0x76, 0x24, 0x4f, 0x04, 0x62, 0x32, 0x1b, 0x3a, 0xc4, 0x5a, 0x96, 0x10, 0xe0, 0x29, 0xc0, 0xc4, 0x5c, 0x3b, 0x87, 0xb3, 0x9b, 0xfc, 0x40, 0xcc, 0x18, 0xd8, 0x11, 0xd9, 0x21, 0xca, 0xfe, 0xf3, 0xa8, 0x35, 0x68, 0x2e, 0xde, 0x7c, 0x9b, 0x1c, 0xf1, 0x5b, 0x0b, 0x77, 0x1f, 0xac, 0x5c, 0xcd, 0x93, 0xa1, 0xb2, 0xac, 0x42, 0x9a, 0x92, 0x00, 0x16, 0xa2, 0xf8, 0x41, 0x80, 0xb7, 0xbb, 0x23, 0x11, 0x97, 0x2f, 0x67, 0xda, 0x4a, 0x46, 0xf8, 0x5d, 0x7c, 0xc4, 0xa0, 0xfb, 0xf3, 0x13, 0xed, 0x0a, 0xbf, 0x1d, 0x91, 0xb3, 0xb4, 0x5e, 0xf7, 0x8b, 0xb9, 0xaa, 0xed, 0x85, 0x59, 0x2a, 0xf8, 0xab, 0x48 }, .pub_len = 1184, }, { .name = "ML-KEM 768 (priv and seed)", .parameter_set = CKP_ML_KEM_768, .priv_seed = { 0x66, 0x0a, 0xdc, 0x95, 0xc9, 0xc3, 0x1f, 0x0f, 0x91, 0xb6, 0xbd, 0x8b, 0x96, 0x46, 0x98, 0xc6, 0x43, 0x4d, 0x5e, 0x24, 0xaa, 0xf9, 0xb5, 0x53, 0xd6, 0xa3, 0x44, 0x2a, 0xa9, 0x40, 0x5b, 0xa7, 0x3e, 0xfd, 0xd5, 0x3d, 0xc3, 0x2d, 0xd7, 0xd5, 0x27, 0x53, 0xf1, 0x99, 0x25, 0xcc, 0xc8, 0x60, 0x56, 0x0e, 0xf8, 0x37, 0xb2, 0x22, 0x59, 0x7b, 0xaa, 0x9f, 0x3b, 0x67, 0xf1, 0xe3, 0xdf, 0x7a }, .priv_seed_len = 64, .priv = { 0x50, 0x75, 0x81, 0xed, 0x26, 0x8a, 0xd2, 0x85, 0x86, 0x5d, 0x31, 0x4e, 0x54, 0x34, 0x20, 0xd9, 0x54, 0xb6, 0xde, 0xc2, 0xb2, 0x3b, 0xca, 0x32, 0x32, 0x60, 0x9c, 0x85, 0x50, 0x04, 0x48, 0x59, 0x42, 0xa1, 0xb5, 0x3b, 0x44, 0x13, 0x61, 0x99, 0xe5, 0x5c, 0xf1, 0xf1, 0x5d, 0x9e, 0xf8, 0x33, 0x45, 0x80, 0xc5, 0x48, 0xd0, 0x3d, 0x68, 0x30, 0x99, 0x0d, 0x27, 0x9a, 0x19, 0x10, 0x66, 0x00, 0xb1, 0x8b, 0xbd, 0xcb, 0x85, 0x45, 0xf0, 0x5f, 0xee, 0xb9, 0x8c, 0x81, 0x57, 0x4b, 0x64, 0x60, 0xbf, 0x3e, 0x98, 0x2e, 0xa6, 0x3b, 0xa5, 0xc6, 0xe6, 0x81, 0xd7, 0x46, 0x99, 0x34, 0x12, 0x36, 0x2a, 0x1c, 0x55, 0x28, 0x14, 0x24, 0xe4, 0xfa, 0xc2, 0x4c, 0x44, 0xb3, 0x78, 0x09, 0x12, 0x25, 0xc4, 0x91, 0x4e, 0x39, 0x3a, 0xef, 0x2a, 0xa8, 0x56, 0xec, 0x3b, 0x80, 0x6a, 0x9f, 0xa7, 0x4c, 0x43, 0x9e, 0x95, 0x70, 0x12, 0xab, 0x89, 0xac, 0x8a, 0x67, 0x70, 0x69, 0x85, 0x83, 0x1a, 0x04, 0x75, 0x05, 0x02, 0x76, 0xbc, 0x8a, 0xa8, 0xc7, 0x29, 0xe4, 0x90, 0x30, 0xea, 0x55, 0x41, 0x9d, 0x02, 0xbc, 0xfb, 0x8b, 0x75, 0x7d, 0xb4, 0xa9, 0x42, 0xf1, 0xa7, 0x74, 0x56, 0xcc, 0xdc, 0xd1, 0x3b, 0x32, 0x8c, 0x1c, 0xc1, 0xc9, 0xa6, 0xdd, 0xb7, 0x6f, 0xc9, 0x5a, 0x8d, 0xd2, 0x14, 0x3c, 0xc6, 0x01, 0x78, 0x4c, 0xb6, 0x51, 0x98, 0xc6, 0x9f, 0x54, 0x49, 0x78, 0x59, 0xa8, 0xbc, 0x6e, 0xe7, 0x33, 0xd1, 0xf0, 0xbf, 0x77, 0xa2, 0xa4, 0x89, 0x76, 0xab, 0x7c, 0xe7, 0xc1, 0x28, 0x97, 0x03, 0x58, 0x22, 0x59, 0x2f, 0x90, 0x0e, 0xdc, 0x02, 0x40, 0xd2, 0xb8, 0x61, 0x01, 0x41, 0xa9, 0xae, 0x9a, 0x3b, 0xa1, 0x8c, 0x6b, 0xec, 0xc9, 0x06, 0x1a, 0x14, 0x97, 0x8e, 0x00, 0x28, 0xd7, 0xb6, 0x1e, 0xd4, 0x67, 0x53, 0xdc, 0x63, 0x4c, 0x92, 0xe6, 0x0e, 0xe2, 0x48, 0x3e, 0x7e, 0x07, 0xa5, 0x5d, 0x93, 0x66, 0x54, 0xb3, 0x0b, 0xde, 0xab, 0x94, 0x77, 0xdc, 0xc6, 0xdd, 0x9c, 0x0a, 0x4f, 0x12, 0x53, 0xc4, 0x2c, 0x24, 0x75, 0xab, 0x69, 0x73, 0x00, 0x1a, 0x3c, 0x28, 0x26, 0xcb, 0xa4, 0x4f, 0xfd, 0xf1, 0x07, 0x00, 0x49, 0x01, 0xe1, 0x5b, 0x26, 0xbf, 0x0c, 0x2c, 0x1c, 0x3b, 0xc5, 0xd5, 0x22, 0xcb, 0x6c, 0xa9, 0x32, 0x6e, 0xa2, 0xb1, 0xc7, 0x48, 0x73, 0x78, 0xe8, 0xaa, 0x49, 0x20, 0x64, 0xbc, 0xc4, 0x0f, 0xed, 0x48, 0x07, 0xee, 0x1c, 0xa9, 0xc8, 0xcb, 0x85, 0x44, 0xa2, 0x93, 0xe8, 0xa8, 0x6c, 0x65, 0x46, 0xad, 0x68, 0x06, 0x9d, 0x43, 0xc5, 0xa4, 0x09, 0xd8, 0x85, 0x12, 0xa9, 0x9f, 0xec, 0x1b, 0x37, 0x8f, 0x30, 0xcd, 0xf8, 0x68, 0x8b, 0xf9, 0x1a, 0x03, 0x09, 0x8c, 0x08, 0x3f, 0xd1, 0x56, 0xbe, 0x05, 0x9b, 0x24, 0xf2, 0x19, 0x34, 0xa3, 0x50, 0xa9, 0x7c, 0x0e, 0x6f, 0x38, 0x3e, 0xea, 0xba, 0x03, 0x01, 0x80, 0x6a, 0x35, 0x78, 0x67, 0xdc, 0x02, 0x53, 0x1f, 0x9c, 0xba, 0xb7, 0xd1, 0xb3, 0xa2, 0x96, 0x22, 0xaf, 0x15, 0x10, 0x30, 0xa5, 0x0b, 0xeb, 0x47, 0x3d, 0xa7, 0x60, 0x5d, 0xb3, 0xe2, 0x4c, 0x45, 0x1b, 0x39, 0x32, 0xfb, 0xa4, 0xb1, 0x94, 0x84, 0xf2, 0x3c, 0x28, 0x47, 0xf8, 0x0b, 0xaf, 0x96, 0x87, 0xe4, 0xd0, 0x49, 0xa0, 0x49, 0x67, 0x29, 0x8c, 0xc7, 0xd7, 0x72, 0x4c, 0x0f, 0x1a, 0x69, 0xac, 0x3c, 0xc7, 0x93, 0x3a, 0xaf, 0x0a, 0x71, 0x4a, 0x73, 0x73, 0x39, 0x70, 0x81, 0x86, 0xff, 0xc2, 0xc6, 0xf5, 0x10, 0x3d, 0x1e, 0xb3, 0x0b, 0x67, 0xdb, 0x7b, 0xf1, 0x5b, 0x4a, 0xbb, 0x33, 0x8f, 0x48, 0x8b, 0x48, 0xed, 0xc3, 0x24, 0x4d, 0x94, 0x8e, 0x17, 0x32, 0xa9, 0x96, 0xd0, 0x60, 0x61, 0x56, 0x70, 0xc3, 0x2a, 0x25, 0x0f, 0x23, 0xa1, 0x49, 0x22, 0x16, 0x32, 0x54, 0x33, 0x47, 0x1c, 0xce, 0x85, 0xbb, 0xcc, 0x8b, 0xe3, 0x4c, 0x13, 0xb9, 0xc9, 0xc3, 0x63, 0x45, 0x68, 0x22, 0x6a, 0xd3, 0x50, 0x5c, 0x77, 0xf9, 0xc3, 0xb1, 0x09, 0x1c, 0x2e, 0x6b, 0x2c, 0x17, 0x92, 0x0e, 0xe3, 0x18, 0x1b, 0x46, 0xfb, 0x18, 0xfd, 0x1a, 0xa5, 0x60, 0x87, 0x53, 0xc1, 0x80, 0x19, 0xe4, 0xd6, 0x9a, 0x22, 0x73, 0x14, 0x41, 0x0c, 0x1a, 0x4e, 0x5a, 0xbe, 0x69, 0x29, 0xb3, 0xd1, 0x64, 0x45, 0xa1, 0x3a, 0xa5, 0xc2, 0x16, 0x87, 0x92, 0x08, 0x58, 0x77, 0xa5, 0x16, 0x7c, 0xe6, 0x18, 0x7b, 0xe3, 0x84, 0xfe, 0x79, 0x10, 0x1b, 0x39, 0xc7, 0xf0, 0x7a, 0x35, 0x18, 0x00, 0xbd, 0x6c, 0x50, 0x89, 0x2a, 0x4b, 0x4b, 0xec, 0x91, 0x76, 0x8f, 0xb0, 0x56, 0x1f, 0x61, 0x37, 0x61, 0x39, 0xce, 0x65, 0xe3, 0x2c, 0xd6, 0x8c, 0x4e, 0x4e, 0x49, 0x32, 0x17, 0xa0, 0x5d, 0x6a, 0x77, 0x92, 0x7a, 0x91, 0x3f, 0x2b, 0x78, 0x4b, 0x0e, 0x7b, 0x29, 0x87, 0xe4, 0x7c, 0x97, 0xf3, 0x5b, 0x94, 0x05, 0x88, 0x7a, 0xb4, 0x96, 0x24, 0x90, 0x65, 0xf9, 0xa2, 0x04, 0x3c, 0x55, 0x7c, 0x7d, 0xe7, 0xa9, 0xde, 0x8c, 0x1f, 0xd0, 0x53, 0x3e, 0x6a, 0x12, 0xa4, 0x6f, 0xec, 0x21, 0x34, 0xd4, 0x43, 0xd0, 0xf4, 0x92, 0x7a, 0x17, 0x71, 0xfa, 0xc0, 0x30, 0xa5, 0xe5, 0x42, 0x7d, 0x36, 0x5c, 0x05, 0x19, 0x42, 0x81, 0x53, 0x25, 0xaf, 0x16, 0xc3, 0x16, 0xac, 0x22, 0x11, 0xfc, 0xaf, 0x5a, 0x54, 0x65, 0x9f, 0x06, 0xbf, 0x6c, 0xea, 0x12, 0x52, 0xd4, 0x20, 0x58, 0x73, 0xac, 0x77, 0x7a, 0xa0, 0x60, 0x85, 0xa7, 0x3e, 0xda, 0x2e, 0xbe, 0x78, 0x10, 0x0e, 0x69, 0x4e, 0x53, 0x0c, 0x77, 0xbb, 0x81, 0x36, 0x78, 0x47, 0x5d, 0x9a, 0x24, 0x6a, 0x2b, 0x2c, 0x96, 0xea, 0xc3, 0x8e, 0x35, 0x42, 0x26, 0x37, 0xb2, 0x02, 0x2a, 0x77, 0xad, 0x4d, 0x17, 0x32, 0x3c, 0xca, 0x9a, 0x05, 0x85, 0xad, 0xc6, 0x09, 0x3e, 0xce, 0xd0, 0x77, 0x08, 0x2a, 0x2d, 0x9e, 0x40, 0x58, 0xb3, 0xbc, 0x42, 0xaf, 0x8a, 0x6d, 0xeb, 0x66, 0x37, 0x88, 0xf1, 0x8e, 0x5d, 0x6c, 0x79, 0xd7, 0xc3, 0x5e, 0x58, 0x21, 0x04, 0x17, 0xc8, 0x3f, 0x62, 0x71, 0x6a, 0x05, 0x88, 0x02, 0xbf, 0xc2, 0x08, 0x34, 0xdc, 0x6a, 0xc0, 0x46, 0xae, 0xb8, 0xb6, 0x99, 0xf1, 0x35, 0x79, 0x3d, 0x4a, 0x88, 0x20, 0xc4, 0xc5, 0x5c, 0x64, 0x8c, 0xb8, 0x81, 0xb7, 0xab, 0x9a, 0x9f, 0xab, 0x41, 0x2a, 0xb4, 0x9a, 0xb1, 0xae, 0x0b, 0xa6, 0x9e, 0x77, 0x49, 0x13, 0xbb, 0x0b, 0xaa, 0x7b, 0xc6, 0x4e, 0xb6, 0xcb, 0xe1, 0xfc, 0x7e, 0x0c, 0x30, 0x3b, 0x3d, 0xe1, 0xad, 0x27, 0x21, 0x40, 0xc5, 0xd0, 0x9e, 0xa4, 0xa5, 0xab, 0xc3, 0x76, 0x41, 0x59, 0x5c, 0x43, 0x76, 0x87, 0x42, 0xd3, 0x69, 0x3d, 0x13, 0x01, 0xb9, 0xd4, 0xfb, 0xce, 0xef, 0xf2, 0x9d, 0xe2, 0x65, 0x8c, 0xdf, 0x08, 0x3e, 0x4c, 0x40, 0xa8, 0x87, 0x32, 0xa2, 0xb6, 0xc9, 0x28, 0x75, 0x56, 0x5e, 0x43, 0x33, 0x88, 0xcc, 0xec, 0x1b, 0xe2, 0x89, 0x1f, 0xb1, 0xe9, 0xce, 0x26, 0x93, 0x59, 0x43, 0x14, 0xb8, 0x0f, 0xca, 0x4b, 0x27, 0xdc, 0x34, 0xfa, 0xd2, 0x22, 0x8c, 0x78, 0x92, 0xd3, 0x00, 0xcd, 0x08, 0x79, 0xbb, 0x9b, 0x46, 0xb9, 0x36, 0x8b, 0x1b, 0x83, 0xe8, 0xc6, 0xc6, 0x45, 0xac, 0x12, 0x63, 0x8d, 0x41, 0xe5, 0xce, 0xc2, 0x43, 0x94, 0xf8, 0x34, 0xb2, 0xf9, 0xb6, 0x4b, 0xbb, 0xf5, 0x4b, 0xff, 0xd5, 0xb0, 0xcb, 0x66, 0x3a, 0xcf, 0x45, 0x7d, 0xcc, 0x7b, 0x88, 0x54, 0x7b, 0x1a, 0xfe, 0x37, 0x95, 0x73, 0xf4, 0x0b, 0x2c, 0x33, 0x1f, 0x6d, 0xa9, 0xc6, 0xd1, 0x7a, 0xcd, 0x4a, 0x8b, 0x9b, 0x31, 0xfc, 0x40, 0xe8, 0xd5, 0x3b, 0x2a, 0x63, 0xb1, 0xc7, 0x48, 0xb9, 0x43, 0xc3, 0xc5, 0x26, 0x0a, 0x62, 0x80, 0x6c, 0xb2, 0x15, 0x3a, 0x29, 0xf0, 0x33, 0x71, 0xa0, 0x98, 0x72, 0xb3, 0xa5, 0x7d, 0xff, 0x95, 0x6b, 0x7c, 0x44, 0x78, 0xab, 0x10, 0x7f, 0xf9, 0xfb, 0x31, 0x90, 0xb4, 0x0c, 0x94, 0x9c, 0x43, 0x23, 0x39, 0x28, 0xa2, 0xa8, 0xa3, 0x6c, 0xc4, 0x82, 0x35, 0x8a, 0xa5, 0x62, 0xdc, 0x1b, 0x77, 0x6a, 0xbd, 0xbe, 0xa4, 0x9f, 0x4f, 0x32, 0x30, 0xc9, 0x1c, 0x8d, 0x44, 0x59, 0x72, 0x98, 0x61, 0x67, 0x4a, 0x34, 0x74, 0x89, 0x81, 0x6d, 0x76, 0x01, 0x22, 0x38, 0x03, 0x12, 0xc3, 0x86, 0x01, 0xa5, 0x50, 0xcc, 0xa9, 0x46, 0x8c, 0x08, 0x58, 0x77, 0x35, 0xd1, 0x5a, 0x6b, 0xf9, 0x6a, 0x33, 0x95, 0x1a, 0x50, 0xe9, 0x03, 0x63, 0x1c, 0xce, 0xc7, 0x81, 0x30, 0xbd, 0xa0, 0x96, 0x63, 0xb0, 0x8c, 0xfc, 0xa2, 0x9c, 0xa2, 0xb8, 0xbb, 0x1c, 0x40, 0x04, 0x26, 0x05, 0x0e, 0xa6, 0x32, 0x99, 0x2e, 0xfa, 0xa0, 0x60, 0x61, 0x98, 0x17, 0x18, 0x14, 0xd9, 0x17, 0x07, 0xae, 0x7a, 0x9e, 0x81, 0x01, 0x1a, 0x8c, 0xc9, 0x17, 0xc2, 0x87, 0xb6, 0x3e, 0xe0, 0x35, 0x7b, 0xc6, 0x7a, 0x05, 0x16, 0x30, 0xcc, 0xc2, 0x4d, 0x90, 0xf6, 0x95, 0x61, 0xe5, 0x29, 0xfe, 0xa0, 0xb3, 0xc2, 0x28, 0x25, 0x22, 0x98, 0x2d, 0x62, 0x4a, 0x7b, 0x68, 0x29, 0xac, 0x79, 0x34, 0x05, 0xe0, 0x65, 0xa4, 0x10, 0x2b, 0x8a, 0xb4, 0x99, 0xab, 0xb3, 0xa2, 0x7f, 0x92, 0x81, 0xa9, 0xc7, 0x40, 0x40, 0xde, 0x2a, 0x9a, 0xf1, 0x20, 0x01, 0x40, 0xc3, 0xa5, 0xef, 0x0a, 0x10, 0x63, 0xfb, 0x2a, 0x8e, 0x96, 0x39, 0x9c, 0x33, 0x53, 0xd0, 0xeb, 0xa6, 0xa2, 0x1c, 0x65, 0x9b, 0xda, 0x3a, 0x17, 0x94, 0x32, 0xf8, 0xc0, 0x25, 0x4b, 0x23, 0x31, 0x90, 0xf5, 0x51, 0x93, 0x15, 0x22, 0xdc, 0xab, 0x51, 0x1c, 0xe4, 0x97, 0x70, 0x81, 0x6c, 0xb9, 0x00, 0x86, 0x86, 0xc5, 0x54, 0xfa, 0xbb, 0xc7, 0x2c, 0x48, 0x65, 0x4c, 0x65, 0xc5, 0x60, 0x20, 0x7c, 0xcc, 0x59, 0x3a, 0x1a, 0xe4, 0x4c, 0x0d, 0x79, 0x31, 0x91, 0x27, 0xcb, 0xbc, 0x00, 0x59, 0x9e, 0x37, 0xa1, 0x5b, 0xaa, 0x8d, 0x9f, 0xc8, 0x6f, 0x58, 0x4b, 0x10, 0x4a, 0x74, 0x8a, 0xfe, 0xd7, 0x69, 0xd2, 0x4c, 0x26, 0x4e, 0xec, 0x02, 0xba, 0xb3, 0xb1, 0x8d, 0x92, 0x2a, 0x2d, 0x2a, 0x24, 0x27, 0x95, 0x65, 0xc1, 0x7c, 0x65, 0x8b, 0x08, 0xd0, 0x68, 0xf4, 0x28, 0x28, 0x55, 0x93, 0x0d, 0xd8, 0xbe, 0xf7, 0x05, 0x93, 0x9b, 0x2b, 0x03, 0xc1, 0x73, 0x9b, 0x96, 0x19, 0x7e, 0xab, 0x9b, 0x30, 0x44, 0xa9, 0x5f, 0x43, 0x08, 0x52, 0x7d, 0x3b, 0xb1, 0x43, 0xf3, 0x9a, 0x92, 0x20, 0x6c, 0xe1, 0x84, 0xaa, 0x99, 0x73, 0x70, 0x75, 0x4b, 0x2a, 0xf5, 0xa6, 0x1e, 0x46, 0xdb, 0x06, 0xc8, 0x3b, 0x07, 0x8b, 0x37, 0x28, 0x49, 0x81, 0x6b, 0x18, 0xaa, 0x4d, 0x3b, 0xc6, 0xac, 0x53, 0x05, 0x2f, 0x3d, 0xc3, 0x28, 0x7b, 0xfa, 0x85, 0xb9, 0x96, 0x35, 0x44, 0x07, 0x25, 0x61, 0xa4, 0x24, 0x88, 0xdb, 0xbb, 0x36, 0x80, 0x1b, 0x20, 0xa9, 0x01, 0x55, 0x6a, 0x83, 0x63, 0xc9, 0x2b, 0x35, 0x96, 0x70, 0xee, 0xd9, 0x26, 0x0e, 0x16, 0xc7, 0xcb, 0x4a, 0x0a, 0x36, 0x8b, 0xbb, 0x89, 0xb3, 0x0e, 0x16, 0x95, 0x30, 0xbc, 0x9b, 0x94, 0xa5, 0x56, 0x2a, 0xed, 0x38, 0x25, 0x1f, 0xb7, 0x20, 0x99, 0x14, 0x72, 0x87, 0xdb, 0x83, 0x9f, 0xab, 0x98, 0x8d, 0x8a, 0x8b, 0x89, 0xab, 0x1a, 0x83, 0xe5, 0x8c, 0x4b, 0x9b, 0x5e, 0x65, 0x9c, 0x9e, 0xac, 0xc1, 0x4d, 0x92, 0x31, 0x8c, 0x32, 0x32, 0x3f, 0x08, 0xc5, 0x3f, 0x3b, 0xb1, 0x8d, 0xdd, 0xa7, 0x8b, 0x94, 0x31, 0x2e, 0x98, 0xa7, 0x9d, 0x36, 0x2b, 0xae, 0x73, 0x6a, 0xb9, 0x51, 0x57, 0x72, 0x4c, 0xc1, 0x17, 0x52, 0x42, 0x81, 0xfe, 0x3c, 0x0a, 0x33, 0x66, 0x7a, 0x9e, 0x24, 0x35, 0x33, 0x24, 0x64, 0xe4, 0xc0, 0xc6, 0x7c, 0x87, 0xb2, 0x6d, 0x7b, 0x07, 0x8e, 0xfc, 0x62, 0xb2, 0x4b, 0x33, 0xfe, 0x05, 0x28, 0x60, 0xe9, 0xa5, 0xc9, 0x04, 0x37, 0x8d, 0x4a, 0x30, 0x42, 0xbb, 0x1d, 0xf8, 0x45, 0x69, 0x74, 0xa2, 0x91, 0x61, 0xf0, 0x4d, 0xec, 0xc7, 0x18, 0x39, 0x18, 0xa6, 0x91, 0xb8, 0x26, 0x11, 0xba, 0xc5, 0x4e, 0xca, 0x1a, 0xf1, 0xe8, 0xa1, 0x4a, 0x30, 0x6b, 0x53, 0x45, 0x0f, 0xad, 0x06, 0x99, 0x3e, 0xdb, 0x0d, 0xbf, 0xf8, 0x5b, 0x4f, 0x35, 0x90, 0x36, 0xd4, 0x57, 0xba, 0xe9, 0x30, 0xf4, 0xf0, 0x41, 0x7d, 0x9a, 0xa5, 0xed, 0x89, 0xa8, 0xea, 0xb3, 0x1a, 0x7f, 0x55, 0x08, 0x14, 0xb0, 0x8c, 0x7e, 0x22, 0x8b, 0x4a, 0x92, 0x14, 0x26, 0x84, 0xb6, 0xa6, 0xf7, 0x7a, 0x59, 0xe0, 0x87, 0x94, 0x0a, 0xa5, 0x6e, 0x7b, 0xb4, 0x99, 0xa9, 0x6a, 0xff, 0xa8, 0x9a, 0xb4, 0x9c, 0x70, 0xed, 0x0a, 0x9e, 0xad, 0x37, 0xa1, 0xa6, 0x60, 0x2f, 0x51, 0x87, 0x6f, 0x37, 0x33, 0x28, 0xf4, 0xba, 0x8e, 0x14, 0xdc, 0x39, 0x17, 0x30, 0x9d, 0xf5, 0x17, 0xac, 0x3e, 0x68, 0x85, 0x01, 0x58, 0x9d, 0xbc, 0x71, 0xb2, 0xeb, 0x11, 0xc0, 0xf8, 0x74, 0x50, 0x1e, 0x09, 0x8b, 0xcb, 0x78, 0x3d, 0x17, 0x46, 0x81, 0xdc, 0x71, 0x68, 0xd6, 0x20, 0x38, 0xd8, 0x7b, 0x31, 0x5c, 0xbb, 0x9c, 0x84, 0xc9, 0x48, 0x19, 0x68, 0xb0, 0x15, 0xb2, 0x76, 0x3b, 0x59, 0x1a, 0x1e, 0x03, 0x02, 0x4f, 0x49, 0x83, 0xa1, 0x35, 0x30, 0xfa, 0x74, 0xae, 0xea, 0x53, 0x8a, 0xd2, 0x3c, 0xc2, 0xf0, 0xa7, 0xb8, 0xb8, 0x78, 0x5a, 0x58, 0x17, 0x6f, 0xa8, 0x4c, 0x1b, 0x58, 0x5a, 0xa1, 0xc3, 0x8b, 0x32, 0xc0, 0xf3, 0x6a, 0x03, 0x89, 0x20, 0xa7, 0x63, 0x3b, 0x47, 0x72, 0x8e, 0x93, 0xe7, 0xb5, 0x56, 0xa6, 0x0e, 0xbc, 0x7b, 0x61, 0xe3, 0x3a, 0xa7, 0x2a, 0x08, 0x81, 0x41, 0xb7, 0x05, 0xa4, 0x5a, 0x30, 0xd5, 0x76, 0x6d, 0x75, 0x9b, 0x64, 0x47, 0x5c, 0xb6, 0xf8, 0x04, 0x37, 0x06, 0x47, 0x55, 0x90, 0x05, 0x84, 0xdc, 0x4a, 0xc3, 0x6a, 0x19, 0x23, 0x48, 0x80, 0x76, 0x57, 0xaa, 0x5b, 0xc1, 0x11, 0x7b, 0x70, 0x13, 0xc8, 0x01, 0xa8, 0x0f, 0x94, 0x90, 0xce, 0xc1, 0x7b, 0x10, 0x10, 0x99, 0x27, 0x9c, 0xd0, 0x14, 0x5a, 0xa8, 0xce, 0x3e, 0x33, 0x7d, 0xc4, 0xe4, 0x50, 0x62, 0x56, 0x83, 0x50, 0xb1, 0x73, 0x8e, 0x67, 0x81, 0x32, 0x8b, 0x90, 0xa4, 0xa5, 0xc1, 0xc8, 0xf4, 0xa3, 0x0f, 0xb5, 0xa9, 0x34, 0xa6, 0x1b, 0x3e, 0x89, 0x36, 0x3c, 0x6a, 0x8b, 0xbd, 0x28, 0x19, 0x5a, 0x04, 0xc3, 0x40, 0xc6, 0xb9, 0xa8, 0x88, 0x4b, 0x9b, 0x4b, 0xac, 0x0d, 0x3a, 0x59, 0x38, 0x19, 0x6c, 0x71, 0x10, 0xab, 0x15, 0x82, 0x2e, 0x5c, 0xec, 0x9c, 0x8a, 0x53, 0x1d, 0x21, 0x2c, 0x0b, 0xd7, 0xc9, 0xba, 0x74, 0xca, 0x1c, 0x7c, 0x29, 0x37, 0xa5, 0x59, 0x38, 0x27, 0x75, 0x17, 0x91, 0xc1, 0x6f, 0x87, 0xe7, 0x78, 0x43, 0x68, 0xc5, 0x5b, 0xe3, 0x18, 0x41, 0x27, 0x52, 0x9c, 0x8b, 0x8c, 0x75, 0xfa, 0x0e, 0xca, 0xe4, 0x95, 0x3e, 0xc1, 0x41, 0x54, 0x31, 0x42, 0xf6, 0x13, 0x4b, 0xac, 0xcb, 0x10, 0x06, 0x61, 0x18, 0xdd, 0x8c, 0x3f, 0x87, 0x8c, 0x94, 0x40, 0x49, 0x49, 0x43, 0xfb, 0x80, 0x4b, 0xeb, 0x56, 0x08, 0x06, 0x93, 0x07, 0xb2, 0x07, 0xb7, 0x32, 0x93, 0xf2, 0x52, 0x0a, 0x20, 0xd8, 0x11, 0x33, 0x54, 0x9f, 0x19, 0x1a, 0x11, 0xc0, 0x28, 0x26, 0x9d, 0xf3, 0x59, 0x47, 0x11, 0xc1, 0xa4, 0x21, 0xc0, 0x34, 0x04, 0x78, 0xeb, 0x1b, 0xcc, 0x6d, 0xa9, 0xa1, 0x1d, 0xc0, 0x5e, 0xaf, 0x07, 0x6c, 0x0d, 0x06, 0xb6, 0xd0, 0x79, 0x61, 0xf0, 0xe9, 0xb9, 0x34, 0x10, 0xa4, 0xb5, 0x2a, 0x2a, 0xf0, 0xbc, 0x60, 0x1d, 0xc2, 0x09, 0x5d, 0x74, 0xba, 0x25, 0x9b, 0x9d, 0x27, 0xf2, 0xb6, 0x2e, 0xb7, 0x83, 0xa3, 0xeb, 0xa8, 0x9c, 0xe0, 0x62, 0x26, 0x8b, 0x0b, 0xfd, 0x49, 0x95, 0x3c, 0x2b, 0x30, 0xe6, 0x9b, 0x14, 0xfe, 0x75, 0x19, 0xf3, 0x09, 0xa1, 0x1c, 0x5a, 0x14, 0x8a, 0x60, 0x3c, 0x6d, 0x1b, 0x0b, 0xf5, 0xdb, 0x9a, 0xf0, 0x84, 0xab, 0x9e, 0x97, 0xab, 0x37, 0xc6, 0x43, 0x8f, 0x87, 0xa2, 0x37, 0x46, 0x09, 0xe5, 0xe1, 0x6b, 0x23, 0x33, 0x18, 0x24, 0xab, 0x33, 0x41, 0x50, 0x81, 0xbf, 0xa0, 0x53, 0x76, 0x24, 0x4f, 0x04, 0x62, 0x32, 0x1b, 0x3a, 0xc4, 0x5a, 0x96, 0x10, 0xe0, 0x29, 0xc0, 0xc4, 0x5c, 0x3b, 0x87, 0xb3, 0x9b, 0xfc, 0x40, 0xcc, 0x18, 0xd8, 0x11, 0xd9, 0x21, 0xca, 0xfe, 0xf3, 0xa8, 0x35, 0x68, 0x2e, 0xde, 0x7c, 0x9b, 0x1c, 0xf1, 0x5b, 0x0b, 0x77, 0x1f, 0xac, 0x5c, 0xcd, 0x93, 0xa1, 0xb2, 0xac, 0x42, 0x9a, 0x92, 0x00, 0x16, 0xa2, 0xf8, 0x41, 0x80, 0xb7, 0xbb, 0x23, 0x11, 0x97, 0x2f, 0x67, 0xda, 0x4a, 0x46, 0xf8, 0x5d, 0x7c, 0xc4, 0xa0, 0xfb, 0xf3, 0x13, 0xed, 0x0a, 0xbf, 0x1d, 0x91, 0xb3, 0xb4, 0x5e, 0xf7, 0x8b, 0xb9, 0xaa, 0xed, 0x85, 0x59, 0x2a, 0xf8, 0xab, 0x48, 0xc2, 0x63, 0x7a, 0x9e, 0x78, 0x4b, 0xaf, 0xa1, 0xe4, 0x54, 0x6c, 0x0c, 0xc5, 0x8b, 0x38, 0x4b, 0x13, 0xd8, 0xa6, 0xa3, 0x3f, 0x62, 0x19, 0xac, 0xc1, 0xb0, 0x48, 0x67, 0xba, 0xbd, 0x91, 0x3b, 0x3e, 0xfd, 0xd5, 0x3d, 0xc3, 0x2d, 0xd7, 0xd5, 0x27, 0x53, 0xf1, 0x99, 0x25, 0xcc, 0xc8, 0x60, 0x56, 0x0e, 0xf8, 0x37, 0xb2, 0x22, 0x59, 0x7b, 0xaa, 0x9f, 0x3b, 0x67, 0xf1, 0xe3, 0xdf, 0x7a }, .priv_len = 2400, .pub = { 0x38, 0x03, 0x12, 0xc3, 0x86, 0x01, 0xa5, 0x50, 0xcc, 0xa9, 0x46, 0x8c, 0x08, 0x58, 0x77, 0x35, 0xd1, 0x5a, 0x6b, 0xf9, 0x6a, 0x33, 0x95, 0x1a, 0x50, 0xe9, 0x03, 0x63, 0x1c, 0xce, 0xc7, 0x81, 0x30, 0xbd, 0xa0, 0x96, 0x63, 0xb0, 0x8c, 0xfc, 0xa2, 0x9c, 0xa2, 0xb8, 0xbb, 0x1c, 0x40, 0x04, 0x26, 0x05, 0x0e, 0xa6, 0x32, 0x99, 0x2e, 0xfa, 0xa0, 0x60, 0x61, 0x98, 0x17, 0x18, 0x14, 0xd9, 0x17, 0x07, 0xae, 0x7a, 0x9e, 0x81, 0x01, 0x1a, 0x8c, 0xc9, 0x17, 0xc2, 0x87, 0xb6, 0x3e, 0xe0, 0x35, 0x7b, 0xc6, 0x7a, 0x05, 0x16, 0x30, 0xcc, 0xc2, 0x4d, 0x90, 0xf6, 0x95, 0x61, 0xe5, 0x29, 0xfe, 0xa0, 0xb3, 0xc2, 0x28, 0x25, 0x22, 0x98, 0x2d, 0x62, 0x4a, 0x7b, 0x68, 0x29, 0xac, 0x79, 0x34, 0x05, 0xe0, 0x65, 0xa4, 0x10, 0x2b, 0x8a, 0xb4, 0x99, 0xab, 0xb3, 0xa2, 0x7f, 0x92, 0x81, 0xa9, 0xc7, 0x40, 0x40, 0xde, 0x2a, 0x9a, 0xf1, 0x20, 0x01, 0x40, 0xc3, 0xa5, 0xef, 0x0a, 0x10, 0x63, 0xfb, 0x2a, 0x8e, 0x96, 0x39, 0x9c, 0x33, 0x53, 0xd0, 0xeb, 0xa6, 0xa2, 0x1c, 0x65, 0x9b, 0xda, 0x3a, 0x17, 0x94, 0x32, 0xf8, 0xc0, 0x25, 0x4b, 0x23, 0x31, 0x90, 0xf5, 0x51, 0x93, 0x15, 0x22, 0xdc, 0xab, 0x51, 0x1c, 0xe4, 0x97, 0x70, 0x81, 0x6c, 0xb9, 0x00, 0x86, 0x86, 0xc5, 0x54, 0xfa, 0xbb, 0xc7, 0x2c, 0x48, 0x65, 0x4c, 0x65, 0xc5, 0x60, 0x20, 0x7c, 0xcc, 0x59, 0x3a, 0x1a, 0xe4, 0x4c, 0x0d, 0x79, 0x31, 0x91, 0x27, 0xcb, 0xbc, 0x00, 0x59, 0x9e, 0x37, 0xa1, 0x5b, 0xaa, 0x8d, 0x9f, 0xc8, 0x6f, 0x58, 0x4b, 0x10, 0x4a, 0x74, 0x8a, 0xfe, 0xd7, 0x69, 0xd2, 0x4c, 0x26, 0x4e, 0xec, 0x02, 0xba, 0xb3, 0xb1, 0x8d, 0x92, 0x2a, 0x2d, 0x2a, 0x24, 0x27, 0x95, 0x65, 0xc1, 0x7c, 0x65, 0x8b, 0x08, 0xd0, 0x68, 0xf4, 0x28, 0x28, 0x55, 0x93, 0x0d, 0xd8, 0xbe, 0xf7, 0x05, 0x93, 0x9b, 0x2b, 0x03, 0xc1, 0x73, 0x9b, 0x96, 0x19, 0x7e, 0xab, 0x9b, 0x30, 0x44, 0xa9, 0x5f, 0x43, 0x08, 0x52, 0x7d, 0x3b, 0xb1, 0x43, 0xf3, 0x9a, 0x92, 0x20, 0x6c, 0xe1, 0x84, 0xaa, 0x99, 0x73, 0x70, 0x75, 0x4b, 0x2a, 0xf5, 0xa6, 0x1e, 0x46, 0xdb, 0x06, 0xc8, 0x3b, 0x07, 0x8b, 0x37, 0x28, 0x49, 0x81, 0x6b, 0x18, 0xaa, 0x4d, 0x3b, 0xc6, 0xac, 0x53, 0x05, 0x2f, 0x3d, 0xc3, 0x28, 0x7b, 0xfa, 0x85, 0xb9, 0x96, 0x35, 0x44, 0x07, 0x25, 0x61, 0xa4, 0x24, 0x88, 0xdb, 0xbb, 0x36, 0x80, 0x1b, 0x20, 0xa9, 0x01, 0x55, 0x6a, 0x83, 0x63, 0xc9, 0x2b, 0x35, 0x96, 0x70, 0xee, 0xd9, 0x26, 0x0e, 0x16, 0xc7, 0xcb, 0x4a, 0x0a, 0x36, 0x8b, 0xbb, 0x89, 0xb3, 0x0e, 0x16, 0x95, 0x30, 0xbc, 0x9b, 0x94, 0xa5, 0x56, 0x2a, 0xed, 0x38, 0x25, 0x1f, 0xb7, 0x20, 0x99, 0x14, 0x72, 0x87, 0xdb, 0x83, 0x9f, 0xab, 0x98, 0x8d, 0x8a, 0x8b, 0x89, 0xab, 0x1a, 0x83, 0xe5, 0x8c, 0x4b, 0x9b, 0x5e, 0x65, 0x9c, 0x9e, 0xac, 0xc1, 0x4d, 0x92, 0x31, 0x8c, 0x32, 0x32, 0x3f, 0x08, 0xc5, 0x3f, 0x3b, 0xb1, 0x8d, 0xdd, 0xa7, 0x8b, 0x94, 0x31, 0x2e, 0x98, 0xa7, 0x9d, 0x36, 0x2b, 0xae, 0x73, 0x6a, 0xb9, 0x51, 0x57, 0x72, 0x4c, 0xc1, 0x17, 0x52, 0x42, 0x81, 0xfe, 0x3c, 0x0a, 0x33, 0x66, 0x7a, 0x9e, 0x24, 0x35, 0x33, 0x24, 0x64, 0xe4, 0xc0, 0xc6, 0x7c, 0x87, 0xb2, 0x6d, 0x7b, 0x07, 0x8e, 0xfc, 0x62, 0xb2, 0x4b, 0x33, 0xfe, 0x05, 0x28, 0x60, 0xe9, 0xa5, 0xc9, 0x04, 0x37, 0x8d, 0x4a, 0x30, 0x42, 0xbb, 0x1d, 0xf8, 0x45, 0x69, 0x74, 0xa2, 0x91, 0x61, 0xf0, 0x4d, 0xec, 0xc7, 0x18, 0x39, 0x18, 0xa6, 0x91, 0xb8, 0x26, 0x11, 0xba, 0xc5, 0x4e, 0xca, 0x1a, 0xf1, 0xe8, 0xa1, 0x4a, 0x30, 0x6b, 0x53, 0x45, 0x0f, 0xad, 0x06, 0x99, 0x3e, 0xdb, 0x0d, 0xbf, 0xf8, 0x5b, 0x4f, 0x35, 0x90, 0x36, 0xd4, 0x57, 0xba, 0xe9, 0x30, 0xf4, 0xf0, 0x41, 0x7d, 0x9a, 0xa5, 0xed, 0x89, 0xa8, 0xea, 0xb3, 0x1a, 0x7f, 0x55, 0x08, 0x14, 0xb0, 0x8c, 0x7e, 0x22, 0x8b, 0x4a, 0x92, 0x14, 0x26, 0x84, 0xb6, 0xa6, 0xf7, 0x7a, 0x59, 0xe0, 0x87, 0x94, 0x0a, 0xa5, 0x6e, 0x7b, 0xb4, 0x99, 0xa9, 0x6a, 0xff, 0xa8, 0x9a, 0xb4, 0x9c, 0x70, 0xed, 0x0a, 0x9e, 0xad, 0x37, 0xa1, 0xa6, 0x60, 0x2f, 0x51, 0x87, 0x6f, 0x37, 0x33, 0x28, 0xf4, 0xba, 0x8e, 0x14, 0xdc, 0x39, 0x17, 0x30, 0x9d, 0xf5, 0x17, 0xac, 0x3e, 0x68, 0x85, 0x01, 0x58, 0x9d, 0xbc, 0x71, 0xb2, 0xeb, 0x11, 0xc0, 0xf8, 0x74, 0x50, 0x1e, 0x09, 0x8b, 0xcb, 0x78, 0x3d, 0x17, 0x46, 0x81, 0xdc, 0x71, 0x68, 0xd6, 0x20, 0x38, 0xd8, 0x7b, 0x31, 0x5c, 0xbb, 0x9c, 0x84, 0xc9, 0x48, 0x19, 0x68, 0xb0, 0x15, 0xb2, 0x76, 0x3b, 0x59, 0x1a, 0x1e, 0x03, 0x02, 0x4f, 0x49, 0x83, 0xa1, 0x35, 0x30, 0xfa, 0x74, 0xae, 0xea, 0x53, 0x8a, 0xd2, 0x3c, 0xc2, 0xf0, 0xa7, 0xb8, 0xb8, 0x78, 0x5a, 0x58, 0x17, 0x6f, 0xa8, 0x4c, 0x1b, 0x58, 0x5a, 0xa1, 0xc3, 0x8b, 0x32, 0xc0, 0xf3, 0x6a, 0x03, 0x89, 0x20, 0xa7, 0x63, 0x3b, 0x47, 0x72, 0x8e, 0x93, 0xe7, 0xb5, 0x56, 0xa6, 0x0e, 0xbc, 0x7b, 0x61, 0xe3, 0x3a, 0xa7, 0x2a, 0x08, 0x81, 0x41, 0xb7, 0x05, 0xa4, 0x5a, 0x30, 0xd5, 0x76, 0x6d, 0x75, 0x9b, 0x64, 0x47, 0x5c, 0xb6, 0xf8, 0x04, 0x37, 0x06, 0x47, 0x55, 0x90, 0x05, 0x84, 0xdc, 0x4a, 0xc3, 0x6a, 0x19, 0x23, 0x48, 0x80, 0x76, 0x57, 0xaa, 0x5b, 0xc1, 0x11, 0x7b, 0x70, 0x13, 0xc8, 0x01, 0xa8, 0x0f, 0x94, 0x90, 0xce, 0xc1, 0x7b, 0x10, 0x10, 0x99, 0x27, 0x9c, 0xd0, 0x14, 0x5a, 0xa8, 0xce, 0x3e, 0x33, 0x7d, 0xc4, 0xe4, 0x50, 0x62, 0x56, 0x83, 0x50, 0xb1, 0x73, 0x8e, 0x67, 0x81, 0x32, 0x8b, 0x90, 0xa4, 0xa5, 0xc1, 0xc8, 0xf4, 0xa3, 0x0f, 0xb5, 0xa9, 0x34, 0xa6, 0x1b, 0x3e, 0x89, 0x36, 0x3c, 0x6a, 0x8b, 0xbd, 0x28, 0x19, 0x5a, 0x04, 0xc3, 0x40, 0xc6, 0xb9, 0xa8, 0x88, 0x4b, 0x9b, 0x4b, 0xac, 0x0d, 0x3a, 0x59, 0x38, 0x19, 0x6c, 0x71, 0x10, 0xab, 0x15, 0x82, 0x2e, 0x5c, 0xec, 0x9c, 0x8a, 0x53, 0x1d, 0x21, 0x2c, 0x0b, 0xd7, 0xc9, 0xba, 0x74, 0xca, 0x1c, 0x7c, 0x29, 0x37, 0xa5, 0x59, 0x38, 0x27, 0x75, 0x17, 0x91, 0xc1, 0x6f, 0x87, 0xe7, 0x78, 0x43, 0x68, 0xc5, 0x5b, 0xe3, 0x18, 0x41, 0x27, 0x52, 0x9c, 0x8b, 0x8c, 0x75, 0xfa, 0x0e, 0xca, 0xe4, 0x95, 0x3e, 0xc1, 0x41, 0x54, 0x31, 0x42, 0xf6, 0x13, 0x4b, 0xac, 0xcb, 0x10, 0x06, 0x61, 0x18, 0xdd, 0x8c, 0x3f, 0x87, 0x8c, 0x94, 0x40, 0x49, 0x49, 0x43, 0xfb, 0x80, 0x4b, 0xeb, 0x56, 0x08, 0x06, 0x93, 0x07, 0xb2, 0x07, 0xb7, 0x32, 0x93, 0xf2, 0x52, 0x0a, 0x20, 0xd8, 0x11, 0x33, 0x54, 0x9f, 0x19, 0x1a, 0x11, 0xc0, 0x28, 0x26, 0x9d, 0xf3, 0x59, 0x47, 0x11, 0xc1, 0xa4, 0x21, 0xc0, 0x34, 0x04, 0x78, 0xeb, 0x1b, 0xcc, 0x6d, 0xa9, 0xa1, 0x1d, 0xc0, 0x5e, 0xaf, 0x07, 0x6c, 0x0d, 0x06, 0xb6, 0xd0, 0x79, 0x61, 0xf0, 0xe9, 0xb9, 0x34, 0x10, 0xa4, 0xb5, 0x2a, 0x2a, 0xf0, 0xbc, 0x60, 0x1d, 0xc2, 0x09, 0x5d, 0x74, 0xba, 0x25, 0x9b, 0x9d, 0x27, 0xf2, 0xb6, 0x2e, 0xb7, 0x83, 0xa3, 0xeb, 0xa8, 0x9c, 0xe0, 0x62, 0x26, 0x8b, 0x0b, 0xfd, 0x49, 0x95, 0x3c, 0x2b, 0x30, 0xe6, 0x9b, 0x14, 0xfe, 0x75, 0x19, 0xf3, 0x09, 0xa1, 0x1c, 0x5a, 0x14, 0x8a, 0x60, 0x3c, 0x6d, 0x1b, 0x0b, 0xf5, 0xdb, 0x9a, 0xf0, 0x84, 0xab, 0x9e, 0x97, 0xab, 0x37, 0xc6, 0x43, 0x8f, 0x87, 0xa2, 0x37, 0x46, 0x09, 0xe5, 0xe1, 0x6b, 0x23, 0x33, 0x18, 0x24, 0xab, 0x33, 0x41, 0x50, 0x81, 0xbf, 0xa0, 0x53, 0x76, 0x24, 0x4f, 0x04, 0x62, 0x32, 0x1b, 0x3a, 0xc4, 0x5a, 0x96, 0x10, 0xe0, 0x29, 0xc0, 0xc4, 0x5c, 0x3b, 0x87, 0xb3, 0x9b, 0xfc, 0x40, 0xcc, 0x18, 0xd8, 0x11, 0xd9, 0x21, 0xca, 0xfe, 0xf3, 0xa8, 0x35, 0x68, 0x2e, 0xde, 0x7c, 0x9b, 0x1c, 0xf1, 0x5b, 0x0b, 0x77, 0x1f, 0xac, 0x5c, 0xcd, 0x93, 0xa1, 0xb2, 0xac, 0x42, 0x9a, 0x92, 0x00, 0x16, 0xa2, 0xf8, 0x41, 0x80, 0xb7, 0xbb, 0x23, 0x11, 0x97, 0x2f, 0x67, 0xda, 0x4a, 0x46, 0xf8, 0x5d, 0x7c, 0xc4, 0xa0, 0xfb, 0xf3, 0x13, 0xed, 0x0a, 0xbf, 0x1d, 0x91, 0xb3, 0xb4, 0x5e, 0xf7, 0x8b, 0xb9, 0xaa, 0xed, 0x85, 0x59, 0x2a, 0xf8, 0xab, 0x48 }, .pub_len = 1184, }, { .name = "ML-KEM 1024 (priv only)", .parameter_set = CKP_ML_KEM_1024, .priv = { 0x92, 0xdb, 0x21, 0x87, 0xb1, 0x4d, 0x40, 0x31, 0x5c, 0x1b, 0xc0, 0xa1, 0xee, 0x02, 0x18, 0xa3, 0xeb, 0x9d, 0x6d, 0x72, 0x44, 0xdd, 0x56, 0x2e, 0x6e, 0x46, 0xba, 0x67, 0x62, 0x05, 0x83, 0xb7, 0x11, 0xf6, 0xfa, 0x8a, 0x04, 0xfb, 0xaa, 0xc8, 0xda, 0x73, 0x5e, 0x9b, 0x82, 0x73, 0x07, 0x32, 0x6f, 0xb2, 0x6f, 0x4c, 0xe2, 0x8f, 0x78, 0x25, 0x45, 0xb7, 0xdc, 0x22, 0xc4, 0xa6, 0x60, 0x0b, 0x73, 0xbd, 0xc7, 0xb3, 0x09, 0x8f, 0x6c, 0x3c, 0x27, 0x16, 0x1a, 0x03, 0x71, 0x69, 0xb9, 0x21, 0xa9, 0xaa, 0x58, 0x9b, 0x47, 0xd6, 0x2f, 0x24, 0xa0, 0x6c, 0x5c, 0x96, 0x53, 0xa9, 0x23, 0x1f, 0x1d, 0x79, 0xb4, 0xdd, 0x48, 0xaf, 0xf1, 0xf4, 0x85, 0xdd, 0xea, 0x95, 0x7d, 0x62, 0xbc, 0xf4, 0xd1, 0x39, 0x7a, 0xd5, 0x50, 0x01, 0xeb, 0x9e, 0x66, 0xac, 0x0c, 0x1d, 0xeb, 0x28, 0x20, 0xda, 0x82, 0x2c, 0x17, 0x20, 0xf2, 0xb7, 0xc0, 0x13, 0x8a, 0x03, 0xe4, 0x00, 0x95, 0xba, 0x64, 0x58, 0x4f, 0x62, 0xbc, 0xa7, 0xfb, 0x6c, 0xe3, 0xc6, 0x12, 0x16, 0xe3, 0x1b, 0x96, 0xe6, 0xaf, 0x23, 0x8a, 0x73, 0x34, 0xd9, 0xce, 0x0c, 0x20, 0xaf, 0x0a, 0x42, 0xba, 0x56, 0x44, 0xc9, 0x5a, 0x7b, 0x9a, 0x3e, 0xeb, 0x5d, 0x79, 0x2a, 0x64, 0x0d, 0x92, 0x0f, 0x1e, 0x4b, 0x3a, 0xd1, 0x51, 0xb9, 0x5e, 0xb0, 0x2d, 0x92, 0xc8, 0x19, 0xbd, 0x16, 0x18, 0xd0, 0x96, 0x0c, 0x41, 0x01, 0x31, 0xd0, 0x19, 0x8f, 0xe7, 0xf4, 0x60, 0xf5, 0x9a, 0x3b, 0x68, 0x22, 0x96, 0x58, 0xba, 0x48, 0x84, 0x11, 0x6a, 0x91, 0x8a, 0x8d, 0x5f, 0x94, 0x2a, 0xf7, 0x76, 0xc7, 0x46, 0x53, 0x3d, 0x41, 0xb4, 0x76, 0x06, 0xda, 0xb9, 0x6c, 0xa7, 0x55, 0x12, 0xa7, 0x8a, 0x84, 0x30, 0x9b, 0xd0, 0x42, 0xac, 0x39, 0xa8, 0x03, 0xde, 0x6c, 0xbf, 0xaf, 0xa2, 0x92, 0xb2, 0x6b, 0xca, 0x79, 0x96, 0x5d, 0x23, 0xdb, 0x12, 0x10, 0xa3, 0x91, 0x07, 0x2b, 0xb2, 0x43, 0x3c, 0x0d, 0xc4, 0xc1, 0x1a, 0x73, 0xfb, 0xb3, 0x09, 0xb9, 0x1c, 0xb6, 0x96, 0x7a, 0xa1, 0xb3, 0x92, 0x67, 0xa8, 0x0d, 0x73, 0xa0, 0x2e, 0xf6, 0x1c, 0x4b, 0x99, 0xe6, 0x43, 0x1f, 0xc6, 0xbc, 0x32, 0x6a, 0x33, 0x3b, 0xd6, 0x41, 0x12, 0x39, 0xa2, 0xc4, 0x2b, 0xc7, 0x53, 0x0a, 0x00, 0x23, 0x59, 0x10, 0xa8, 0xc3, 0x38, 0xd8, 0x7b, 0xbb, 0xda, 0x09, 0x83, 0x07, 0xe9, 0x6f, 0xc1, 0x45, 0x0e, 0xe6, 0xb0, 0x08, 0x3d, 0x80, 0x26, 0x6c, 0x79, 0x81, 0xe6, 0x95, 0x3d, 0x3b, 0x79, 0x5d, 0x3e, 0x95, 0x08, 0x4a, 0xb2, 0x16, 0xe6, 0xf0, 0x9c, 0x5f, 0x90, 0xc7, 0x0b, 0x02, 0xb0, 0x5a, 0x60, 0x18, 0xa4, 0x8a, 0x70, 0x1d, 0x37, 0xbb, 0x51, 0xdb, 0x52, 0xe0, 0x01, 0x36, 0x3f, 0x61, 0x97, 0x0f, 0x19, 0x56, 0x3b, 0xe6, 0xbd, 0x63, 0x99, 0xc7, 0x9c, 0x5a, 0x96, 0x75, 0xa9, 0x92, 0xe1, 0x69, 0x31, 0xc7, 0x99, 0x02, 0x84, 0x84, 0xb0, 0x0a, 0xf9, 0x0b, 0x83, 0x1c, 0xc1, 0x18, 0x12, 0x2c, 0x75, 0x27, 0xb8, 0x33, 0xe6, 0x5e, 0xd2, 0xca, 0x1b, 0xf0, 0x5c, 0x62, 0x14, 0x87, 0x0b, 0x3c, 0xac, 0x38, 0x86, 0x9c, 0x2c, 0x59, 0x29, 0x98, 0x1c, 0xf6, 0x5c, 0xbf, 0xab, 0xb8, 0xf9, 0x77, 0x45, 0x0d, 0x79, 0x3f, 0xb0, 0xac, 0x88, 0x9e, 0x55, 0x16, 0xa8, 0x96, 0x59, 0x97, 0x56, 0x85, 0xcb, 0xbb, 0x96, 0x0c, 0x37, 0xb5, 0xad, 0x64, 0xae, 0xa3, 0xd5, 0x20, 0xe3, 0xd4, 0x29, 0x97, 0x94, 0x17, 0xc5, 0x35, 0x45, 0x6c, 0xe5, 0x5e, 0x3a, 0x4c, 0x2c, 0xfc, 0xe4, 0x5a, 0x1a, 0x46, 0xa7, 0x95, 0xe7, 0x16, 0xd6, 0xa0, 0x15, 0x92, 0x3c, 0xc4, 0x19, 0x57, 0x86, 0x7d, 0xf6, 0xb4, 0xa6, 0x30, 0xca, 0x9c, 0x61, 0x1a, 0x34, 0x95, 0x53, 0x06, 0x4a, 0xa4, 0xbf, 0x27, 0x91, 0x7c, 0x83, 0x18, 0xf9, 0xa5, 0x15, 0x82, 0x01, 0x35, 0xad, 0x06, 0x4c, 0xd8, 0x30, 0x3e, 0xd1, 0x01, 0x16, 0x6c, 0xb3, 0xbb, 0x4e, 0xd0, 0xa2, 0x9f, 0xa1, 0x21, 0xf4, 0xdc, 0x20, 0xed, 0x85, 0x41, 0xc1, 0xcc, 0xce, 0x43, 0xd3, 0x2c, 0xa2, 0xf6, 0x7a, 0x31, 0x08, 0xa0, 0x86, 0xe4, 0x5f, 0x57, 0xc7, 0x6f, 0x50, 0xd2, 0xb7, 0x41, 0x84, 0x53, 0xe9, 0xca, 0xa5, 0x16, 0x97, 0x87, 0x60, 0x2c, 0xa3, 0x7e, 0x2b, 0x79, 0x1b, 0x43, 0x22, 0x70, 0x21, 0x78, 0x33, 0xd6, 0x2b, 0x13, 0x88, 0xa1, 0x66, 0x09, 0x1e, 0x99, 0x53, 0x67, 0x19, 0xc2, 0x6d, 0x30, 0x79, 0x97, 0x2b, 0x12, 0x99, 0x94, 0x54, 0x9c, 0x63, 0xb8, 0x1f, 0x00, 0xcd, 0x0f, 0x13, 0x43, 0x34, 0x27, 0xb7, 0x24, 0x48, 0x40, 0x91, 0x1e, 0xb2, 0x99, 0xa5, 0xb2, 0x1f, 0xbf, 0x98, 0xb9, 0xa7, 0x94, 0x90, 0x34, 0x0c, 0x3f, 0x3c, 0xaa, 0x05, 0xac, 0xb7, 0xae, 0x45, 0x26, 0x3d, 0xf3, 0xe7, 0x17, 0x6e, 0x39, 0x73, 0x09, 0xe9, 0x2e, 0x6c, 0x20, 0x2d, 0xa7, 0xb9, 0x77, 0x37, 0xa2, 0x40, 0xf2, 0xb4, 0x5d, 0x40, 0x55, 0x20, 0xdc, 0x22, 0x65, 0x01, 0x78, 0x92, 0x81, 0xfb, 0x04, 0x71, 0x4b, 0xbd, 0x6a, 0xb8, 0x67, 0x62, 0xbb, 0x55, 0x1f, 0xcb, 0x63, 0x5b, 0xca, 0x2f, 0x86, 0x72, 0x36, 0xac, 0x35, 0x12, 0xed, 0xca, 0xa8, 0x58, 0xdc, 0x00, 0x82, 0x54, 0x04, 0xec, 0xd2, 0x9b, 0xe6, 0xfb, 0x1e, 0xd5, 0xbb, 0x5d, 0xb6, 0x97, 0x3f, 0x85, 0x60, 0x28, 0x0a, 0xa8, 0x9f, 0xf1, 0x70, 0x01, 0xe1, 0x24, 0x18, 0x32, 0xc1, 0x21, 0xf9, 0x64, 0x93, 0x4f, 0x22, 0x60, 0x42, 0x0c, 0x2c, 0x69, 0xd2, 0x3e, 0x3d, 0x94, 0xc1, 0x59, 0xfb, 0x26, 0xfe, 0x49, 0x90, 0x4a, 0x30, 0x9f, 0x2e, 0x40, 0xc1, 0x66, 0xc3, 0x27, 0x4e, 0x74, 0x16, 0x32, 0x24, 0x7b, 0xaf, 0x1c, 0x00, 0x62, 0x81, 0x3b, 0x75, 0x47, 0xa6, 0x39, 0x69, 0x84, 0x6c, 0xa1, 0xca, 0xf8, 0xf5, 0x97, 0xe1, 0x59, 0x38, 0xcf, 0x76, 0xb4, 0x72, 0x8b, 0x49, 0x13, 0x0b, 0x27, 0x5c, 0xda, 0x47, 0x3b, 0xa9, 0x4e, 0x76, 0xe4, 0x78, 0x49, 0x74, 0x09, 0xaa, 0x97, 0xc0, 0x2f, 0xbb, 0x68, 0x0e, 0x19, 0x37, 0x76, 0x98, 0x30, 0x63, 0x40, 0x21, 0x48, 0xa8, 0x1f, 0x07, 0x8a, 0x6c, 0xc7, 0x22, 0x8c, 0xf7, 0x72, 0x90, 0x96, 0x47, 0x94, 0xdd, 0xc4, 0x73, 0xfd, 0x83, 0xba, 0x66, 0xf4, 0x0c, 0x75, 0x39, 0x76, 0x78, 0x76, 0x1b, 0x37, 0x4b, 0x17, 0x0f, 0xf5, 0x1d, 0x89, 0x36, 0x35, 0xcd, 0x8c, 0x71, 0x6d, 0x62, 0x22, 0xd8, 0x74, 0x68, 0x28, 0x28, 0xa4, 0xaa, 0xa7, 0x0e, 0x8d, 0x33, 0x6b, 0x56, 0x23, 0x94, 0x6f, 0x85, 0x41, 0x73, 0x32, 0x00, 0x2c, 0x53, 0x02, 0x43, 0xf1, 0x79, 0xcb, 0x9c, 0x56, 0x1d, 0x0b, 0x8d, 0xe5, 0x53, 0xac, 0xe7, 0xc0, 0x60, 0xbe, 0x4a, 0x6a, 0xd2, 0x7c, 0x93, 0xa0, 0xb0, 0x93, 0xc7, 0x82, 0x51, 0x18, 0x81, 0x20, 0x4b, 0x1a, 0x6f, 0x53, 0x10, 0x68, 0xa5, 0x12, 0xa9, 0xe7, 0x25, 0x41, 0x1a, 0xa1, 0x4a, 0x34, 0x92, 0x3b, 0xd8, 0x45, 0x64, 0x20, 0xbb, 0xad, 0xe3, 0x95, 0x09, 0xa1, 0x42, 0x55, 0x9f, 0x53, 0xc4, 0x6f, 0xf7, 0xad, 0xf7, 0x2c, 0x81, 0x03, 0x48, 0x39, 0x99, 0x60, 0x43, 0xa2, 0x8b, 0xae, 0xc3, 0xf3, 0xb4, 0xa5, 0x46, 0x11, 0xb4, 0xc3, 0x51, 0x3c, 0x1c, 0x35, 0x91, 0xe2, 0xa1, 0xce, 0xfb, 0x91, 0x2d, 0x87, 0x8f, 0x68, 0xb7, 0x15, 0x2b, 0x99, 0xb4, 0xfd, 0x40, 0x44, 0x44, 0x2c, 0x27, 0x62, 0x03, 0x06, 0x8c, 0x36, 0x37, 0xa5, 0x05, 0x4b, 0x1b, 0x25, 0xa4, 0xc9, 0x36, 0x33, 0x8c, 0x62, 0x9d, 0xc0, 0xb2, 0x3f, 0x06, 0x34, 0x7e, 0x12, 0xf9, 0x89, 0x1e, 0x52, 0x76, 0x35, 0x1c, 0x79, 0x89, 0x82, 0xc7, 0xc1, 0x89, 0x34, 0x81, 0x21, 0x1f, 0xf8, 0xea, 0xa2, 0xe6, 0x32, 0x6c, 0x1c, 0x0a, 0xa5, 0x9f, 0x27, 0x30, 0x3d, 0xdc, 0xcb, 0x67, 0x6a, 0x98, 0xb7, 0xe8, 0x83, 0x01, 0x10, 0x35, 0x7a, 0xf7, 0x54, 0xfd, 0xb4, 0x49, 0x29, 0x73, 0x2a, 0x82, 0xa8, 0xa1, 0xe6, 0xa1, 0x4c, 0x41, 0x25, 0x84, 0x03, 0x16, 0x3a, 0x97, 0x6a, 0x98, 0xf7, 0x89, 0xcd, 0xf5, 0x61, 0x75, 0x7f, 0xa1, 0x4c, 0x67, 0x30, 0x6e, 0x61, 0x30, 0x21, 0x3f, 0x29, 0xc0, 0x9c, 0x13, 0x12, 0x9a, 0xf5, 0x04, 0x15, 0x91, 0x5c, 0x2e, 0x99, 0x03, 0xbd, 0x50, 0x22, 0xb3, 0x98, 0x54, 0x87, 0xf2, 0x50, 0x5a, 0x33, 0x93, 0xf3, 0x62, 0x6b, 0xf1, 0x8b, 0x72, 0x6a, 0xc9, 0x28, 0x71, 0xd6, 0x98, 0x69, 0x28, 0xcb, 0xb7, 0x64, 0x6e, 0x17, 0x27, 0x6e, 0x33, 0xc0, 0x8c, 0x27, 0xc9, 0x5c, 0x76, 0x91, 0x5b, 0xe1, 0xeb, 0x88, 0x53, 0x6c, 0x51, 0xa6, 0xa7, 0x89, 0xcb, 0xda, 0x76, 0x81, 0xd5, 0x22, 0x43, 0x7c, 0x7a, 0x5c, 0x28, 0xa0, 0x38, 0x93, 0xa7, 0x36, 0xba, 0x59, 0x85, 0xd5, 0xb1, 0xfb, 0xd6, 0x32, 0xfb, 0x35, 0x4c, 0x5e, 0xd2, 0x52, 0x48, 0xb6, 0x0d, 0x0d, 0x17, 0x9f, 0xcd, 0x86, 0x94, 0xa8, 0x46, 0x4b, 0xbd, 0x11, 0xce, 0xee, 0xc6, 0x69, 0x23, 0x1a, 0x73, 0x60, 0xfb, 0xc9, 0x50, 0xe6, 0x5c, 0xe3, 0xc0, 0x6f, 0x45, 0x70, 0x8d, 0xfd, 0x9b, 0x31, 0x26, 0xe8, 0x44, 0xcc, 0x57, 0x66, 0xfd, 0xd7, 0x06, 0xec, 0xd6, 0x1d, 0xcb, 0x48, 0x20, 0x12, 0xdc, 0x40, 0xb1, 0xcb, 0x12, 0x7b, 0xab, 0xc7, 0xf0, 0x78, 0x93, 0x84, 0x89, 0x71, 0xb9, 0x74, 0x60, 0x72, 0xc7, 0x9f, 0x54, 0x7b, 0x0b, 0x64, 0xd2, 0x87, 0x1c, 0xb3, 0xc6, 0x4f, 0x27, 0x8b, 0xea, 0x23, 0x04, 0xe6, 0x39, 0x34, 0xab, 0xa4, 0x23, 0xf7, 0x79, 0x28, 0x1a, 0x9c, 0x82, 0xdc, 0x4b, 0x8f, 0x63, 0x33, 0x31, 0x30, 0x34, 0x4b, 0x8d, 0xc6, 0xc3, 0xcb, 0xd3, 0x4f, 0xac, 0x35, 0x4e, 0xb8, 0xa9, 0x9e, 0xb3, 0xb9, 0xb8, 0xa8, 0x90, 0x5a, 0x7b, 0xb8, 0x90, 0x82, 0x75, 0x1a, 0xdc, 0x30, 0x79, 0x90, 0x55, 0xbd, 0xc4, 0x27, 0x25, 0x10, 0xc8, 0x9f, 0x42, 0xb2, 0xc6, 0x08, 0x76, 0xc5, 0xfb, 0x18, 0x77, 0x70, 0x57, 0x8b, 0xeb, 0x69, 0x90, 0x85, 0x49, 0x51, 0x99, 0x1a, 0x05, 0x2e, 0x7b, 0x47, 0x75, 0x4b, 0x36, 0x29, 0x54, 0x0a, 0xb0, 0x3c, 0x81, 0x6b, 0x35, 0x41, 0x70, 0x5c, 0x59, 0x1b, 0xb3, 0x1d, 0xf1, 0x9c, 0xac, 0x89, 0x0c, 0x19, 0xd7, 0x0a, 0xa5, 0x3c, 0xb6, 0x9e, 0x01, 0x83, 0x63, 0x81, 0xf9, 0x71, 0x9f, 0x7c, 0x13, 0x1d, 0xa2, 0x5d, 0xb7, 0x52, 0x09, 0x8b, 0x48, 0x17, 0xc9, 0xdc, 0x8a, 0x93, 0x43, 0x19, 0x46, 0x98, 0x84, 0xc2, 0xa2, 0x2c, 0x40, 0xb1, 0xc0, 0xca, 0xcb, 0x45, 0xf9, 0x85, 0x7b, 0xd3, 0x02, 0x64, 0x56, 0x33, 0x73, 0xc7, 0xa2, 0x96, 0xb2, 0x4b, 0x78, 0x35, 0x0b, 0x7b, 0xf8, 0x42, 0x34, 0x4f, 0xa7, 0x66, 0x61, 0xa8, 0x2d, 0x04, 0x14, 0x06, 0x73, 0x9a, 0x2c, 0xac, 0x60, 0xc3, 0xc0, 0x14, 0x8d, 0x67, 0xbc, 0xbf, 0xe3, 0x14, 0x66, 0x16, 0xc0, 0x62, 0x5e, 0x04, 0x58, 0xe5, 0x19, 0x50, 0x16, 0xf4, 0x8f, 0xd4, 0x88, 0x83, 0x6a, 0x0b, 0x8a, 0xac, 0x62, 0x48, 0x7e, 0xc9, 0x94, 0x62, 0xf2, 0x8a, 0x73, 0x53, 0xba, 0x54, 0xcc, 0x79, 0xe0, 0xfa, 0x69, 0x8c, 0x79, 0xb8, 0xa7, 0x34, 0x29, 0x8f, 0x35, 0x1c, 0x7d, 0x43, 0x5e, 0x4f, 0xca, 0xac, 0xbd, 0xa8, 0x77, 0xda, 0xe9, 0x5a, 0xea, 0xa9, 0x6f, 0xce, 0xa1, 0x9c, 0xb8, 0x62, 0xcd, 0xba, 0x2b, 0x67, 0xab, 0x75, 0x2c, 0x3e, 0x86, 0x92, 0xbe, 0x5b, 0x14, 0x01, 0x1b, 0x54, 0x5e, 0x24, 0xa3, 0xad, 0x33, 0x8b, 0xbb, 0x4c, 0x09, 0xf4, 0x76, 0x4e, 0x47, 0x9c, 0x44, 0x5f, 0x52, 0x62, 0x6e, 0x65, 0x16, 0x6a, 0x21, 0x87, 0x0e, 0xaa, 0xa0, 0xf1, 0x33, 0xc1, 0x3c, 0xc2, 0x27, 0x61, 0xa3, 0x2f, 0xf9, 0xb8, 0x13, 0x0a, 0x91, 0x56, 0x34, 0xa2, 0x75, 0xfc, 0x7c, 0x4d, 0x35, 0x38, 0x1b, 0x0f, 0x54, 0xbc, 0x28, 0x50, 0x46, 0xcf, 0x91, 0x8c, 0x71, 0x4c, 0x40, 0x2d, 0x35, 0x28, 0x2a, 0x3b, 0xc7, 0x58, 0x64, 0x9e, 0x95, 0xeb, 0x3b, 0x67, 0xb3, 0x2e, 0x71, 0xf3, 0x88, 0xe6, 0xe0, 0x37, 0x26, 0xd2, 0x36, 0x89, 0x24, 0x21, 0x4e, 0xcb, 0x60, 0xa9, 0x82, 0xc1, 0x96, 0x11, 0x9f, 0x78, 0xf4, 0x10, 0x10, 0x42, 0x4a, 0x72, 0x3a, 0xaa, 0x04, 0x68, 0x6d, 0x20, 0x05, 0x02, 0x3e, 0xfa, 0x9b, 0x5a, 0x24, 0x8a, 0x24, 0x91, 0xb7, 0xa5, 0x88, 0x80, 0xff, 0xc9, 0x74, 0xba, 0x64, 0x71, 0xf4, 0x42, 0x8f, 0x83, 0x12, 0x27, 0x8b, 0xc3, 0x89, 0xac, 0x72, 0x77, 0x80, 0x32, 0xc1, 0x65, 0x0b, 0x98, 0xa1, 0x6c, 0x48, 0x05, 0x5c, 0x63, 0x83, 0x2b, 0x06, 0x35, 0x57, 0x41, 0xfa, 0xdb, 0x7f, 0xb1, 0x86, 0xa6, 0x35, 0x15, 0x66, 0x23, 0xf3, 0x04, 0x76, 0x20, 0x4d, 0x00, 0x40, 0xb3, 0xb3, 0xd1, 0xbb, 0x1e, 0x7c, 0xb5, 0x2a, 0xd2, 0x9d, 0xf2, 0x1b, 0x96, 0x85, 0x41, 0x78, 0x9b, 0x91, 0x73, 0x40, 0x4c, 0xbb, 0x37, 0x57, 0x27, 0xbe, 0xe7, 0x50, 0x6f, 0x75, 0xa0, 0x37, 0x47, 0x8e, 0x11, 0x72, 0xb7, 0xd2, 0xdc, 0xba, 0x7e, 0x34, 0x23, 0x66, 0x6c, 0x49, 0x87, 0x5a, 0x48, 0xed, 0xe2, 0x12, 0x0d, 0x73, 0x6d, 0xd4, 0x7a, 0x8c, 0x65, 0xa2, 0x77, 0x53, 0x47, 0xbe, 0x72, 0x17, 0x09, 0x7e, 0xca, 0x27, 0x79, 0xfa, 0x9e, 0x01, 0xe5, 0x78, 0x7c, 0x02, 0x99, 0x35, 0x61, 0x58, 0xea, 0xa2, 0x3e, 0x45, 0x48, 0x2a, 0xba, 0x13, 0x43, 0x1c, 0x26, 0xbc, 0x9a, 0x97, 0xcc, 0x19, 0x5b, 0x49, 0xc0, 0x59, 0x3a, 0x73, 0x88, 0x72, 0xa2, 0xba, 0x15, 0x52, 0x17, 0xaf, 0x82, 0x07, 0xc9, 0x3b, 0x85, 0xc8, 0x31, 0x46, 0x70, 0xf4, 0x3c, 0x62, 0xa1, 0xf1, 0xa7, 0x7f, 0xc3, 0x8f, 0xed, 0x13, 0xca, 0x1a, 0xe6, 0xa0, 0x0e, 0x66, 0xc6, 0xd8, 0xf5, 0x75, 0x13, 0x3b, 0x8f, 0x77, 0x0b, 0x33, 0x1a, 0xd4, 0xad, 0x2f, 0x35, 0xb6, 0xca, 0xcb, 0xcb, 0xa1, 0xe5, 0xb0, 0xcf, 0xc3, 0xa0, 0xf4, 0x19, 0x6e, 0x66, 0x39, 0x1f, 0x5b, 0x54, 0x7c, 0xa1, 0x58, 0x47, 0x5e, 0xd0, 0x8a, 0xd8, 0xe7, 0x68, 0x65, 0x5b, 0x6e, 0x17, 0xb5, 0x90, 0x4a, 0x8c, 0x4b, 0x88, 0x53, 0xcb, 0x91, 0xc4, 0x88, 0xa0, 0x10, 0xb6, 0xd5, 0x45, 0x46, 0xea, 0x6b, 0x8e, 0x87, 0x44, 0x00, 0xc5, 0xe7, 0xa1, 0x83, 0xdc, 0x66, 0xd5, 0xd9, 0x2b, 0x88, 0xba, 0x29, 0x96, 0x72, 0xc1, 0x0a, 0x19, 0xb3, 0xb6, 0x07, 0x04, 0xa6, 0x85, 0x33, 0xa5, 0x41, 0x8d, 0xf5, 0xd3, 0x4a, 0x38, 0xf4, 0xb2, 0xad, 0xb4, 0x89, 0x26, 0x84, 0x42, 0x78, 0x2a, 0xa0, 0x06, 0x6c, 0x54, 0x1e, 0x58, 0x0b, 0x80, 0x69, 0xa1, 0xc0, 0x34, 0x17, 0xef, 0xda, 0x7c, 0x78, 0x03, 0xc9, 0x16, 0x9b, 0x0f, 0x2b, 0x3c, 0x92, 0x01, 0xf0, 0x1e, 0xe1, 0xc1, 0x22, 0xf4, 0xa5, 0x12, 0x54, 0x8a, 0x2b, 0x29, 0x27, 0x96, 0x04, 0x95, 0xc2, 0x1c, 0x07, 0xb3, 0x19, 0xa1, 0x48, 0x23, 0x23, 0x9e, 0xa1, 0xc4, 0x3b, 0x7f, 0x0a, 0x59, 0x57, 0x82, 0x02, 0x47, 0x00, 0x4e, 0x53, 0x78, 0x65, 0xb9, 0xfc, 0x11, 0x9e, 0x4b, 0x64, 0x7e, 0xa5, 0x0a, 0x43, 0x67, 0x24, 0x9f, 0xaa, 0x3b, 0xb1, 0xd6, 0x0c, 0xef, 0x9b, 0x04, 0xb3, 0xf5, 0xca, 0x5f, 0x53, 0xbb, 0xfc, 0xf6, 0x6c, 0xe9, 0x02, 0x36, 0x42, 0xb6, 0x08, 0xdb, 0x04, 0xa7, 0x65, 0xe6, 0x3e, 0x1f, 0x72, 0xa8, 0xf8, 0xc2, 0xc0, 0xdb, 0x5c, 0x7b, 0x4a, 0x71, 0x74, 0x25, 0xb0, 0x47, 0x87, 0x15, 0x7a, 0x20, 0xc4, 0x13, 0xfb, 0x1a, 0x9a, 0x6d, 0x17, 0x88, 0x2b, 0xf5, 0xc0, 0x98, 0xf8, 0x72, 0x40, 0xea, 0x90, 0x89, 0xd4, 0x79, 0x3a, 0xb7, 0xc5, 0xdc, 0xec, 0x82, 0x41, 0x02, 0xc7, 0x0a, 0x9c, 0xad, 0x24, 0xf3, 0x1b, 0xcf, 0x95, 0xbe, 0x08, 0x0b, 0x2e, 0x25, 0x06, 0x84, 0x05, 0x18, 0x91, 0x7a, 0x92, 0x6c, 0x54, 0xe1, 0xa0, 0xcd, 0x70, 0x6a, 0xe9, 0xd7, 0x95, 0x67, 0xcc, 0x2f, 0xa5, 0xfb, 0x56, 0x94, 0x21, 0xb7, 0x32, 0x19, 0xbb, 0x2c, 0x25, 0x94, 0x6d, 0xe2, 0xa6, 0x12, 0x35, 0x29, 0x63, 0x1a, 0x3a, 0x2f, 0xb4, 0x03, 0x4f, 0xab, 0x27, 0x45, 0x82, 0x01, 0x70, 0x67, 0x0f, 0x2e, 0xcc, 0xb7, 0xf2, 0x78, 0x55, 0x4d, 0x8a, 0x2e, 0x86, 0xf8, 0xbe, 0xde, 0xc1, 0x1b, 0xa3, 0x61, 0xad, 0x8e, 0x50, 0xbc, 0x83, 0x6b, 0x50, 0x85, 0x2c, 0x2a, 0x4e, 0x51, 0x51, 0x2b, 0x66, 0x65, 0x12, 0xf8, 0xc9, 0xd0, 0x4b, 0x5a, 0xff, 0x9a, 0x3e, 0x86, 0x47, 0x01, 0x76, 0xc0, 0x65, 0x0b, 0xc3, 0x5c, 0x35, 0x01, 0x0c, 0x1e, 0x27, 0x29, 0xd7, 0x66, 0xc6, 0xed, 0x92, 0x23, 0x32, 0xc7, 0x7a, 0x45, 0x67, 0xa7, 0x31, 0xc9, 0xab, 0x27, 0xa2, 0xab, 0xb3, 0x66, 0xb2, 0x99, 0x98, 0x49, 0xff, 0x2b, 0x66, 0xaf, 0x58, 0xc7, 0xec, 0xa5, 0x71, 0x3e, 0x21, 0x7f, 0x1e, 0x90, 0x19, 0x5d, 0xa5, 0x0e, 0x14, 0x38, 0x80, 0x14, 0x6b, 0xad, 0x9b, 0xcc, 0x07, 0xff, 0x18, 0x6d, 0x5d, 0xa4, 0xb7, 0x7c, 0x34, 0x93, 0x54, 0xf7, 0x9b, 0x6f, 0x35, 0x06, 0x67, 0xb1, 0x3c, 0xea, 0xa2, 0x30, 0x6f, 0xea, 0x97, 0x43, 0x36, 0xab, 0x7b, 0x45, 0xc4, 0x4b, 0x09, 0x46, 0x7b, 0xd8, 0x39, 0x1e, 0x13, 0xc9, 0x99, 0x02, 0x22, 0xbc, 0xf0, 0x48, 0x4b, 0x70, 0x66, 0x96, 0xb9, 0x02, 0x5f, 0x42, 0x45, 0x5f, 0x75, 0xb4, 0x7d, 0xba, 0x61, 0xe1, 0x33, 0x45, 0x11, 0xb9, 0xa9, 0x84, 0xc6, 0xae, 0xf2, 0x58, 0x64, 0x1f, 0xe6, 0x43, 0xd3, 0x87, 0x18, 0x9d, 0x13, 0xab, 0x87, 0xa9, 0xaf, 0x4c, 0x67, 0x98, 0xfc, 0x36, 0xc6, 0xb8, 0xa2, 0x6b, 0x72, 0xa3, 0xa8, 0x03, 0x25, 0x2c, 0xaa, 0x80, 0xbe, 0x5b, 0xaa, 0x7c, 0x2d, 0x12, 0xc8, 0xa9, 0x3b, 0xcf, 0xae, 0x05, 0x29, 0x52, 0x20, 0x7c, 0x5e, 0x1a, 0x93, 0x9a, 0x46, 0x95, 0x96, 0xd5, 0x0b, 0xe1, 0x3a, 0x9a, 0xf4, 0xe0, 0x8f, 0xd4, 0xc7, 0x16, 0x44, 0x03, 0x8f, 0xf1, 0x59, 0x4c, 0x20, 0xf2, 0x82, 0x6a, 0x70, 0x12, 0x8c, 0x24, 0x4c, 0x65, 0x37, 0x55, 0xe3, 0xa5, 0x19, 0xe9, 0x26, 0x14, 0x81, 0x21, 0x3a, 0x3b, 0x07, 0x60, 0x0b, 0xc0, 0xc6, 0x07, 0x10, 0x95, 0xf7, 0xb6, 0x6f, 0x24, 0x89, 0xce, 0x16, 0x33, 0x52, 0xb3, 0x9c, 0x33, 0xa0, 0xe4, 0x1e, 0xc6, 0x8b, 0xc0, 0x4e, 0x61, 0x8e, 0xfe, 0x75, 0xbb, 0x66, 0x92, 0x44, 0xb5, 0xd8, 0x0b, 0xf0, 0x4c, 0x8b, 0x1b, 0xf7, 0xcb, 0x60, 0x81, 0xa3, 0x08, 0x99, 0x96, 0xfb, 0xb8, 0x09, 0x36, 0x62, 0x85, 0x80, 0x54, 0x07, 0x62, 0xd0, 0xa1, 0x03, 0x1c, 0x16, 0xe2, 0x6a, 0x4b, 0x2f, 0x67, 0x4a, 0xd7, 0x71, 0x3e, 0x68, 0x41, 0x5c, 0x56, 0x09, 0xa3, 0xab, 0x13, 0x5d, 0x92, 0x81, 0xc0, 0xe7, 0xc7, 0x48, 0x4d, 0x08, 0x12, 0xea, 0xb2, 0xa5, 0x78, 0x30, 0x5f, 0x88, 0xd5, 0x2c, 0xa6, 0x5a, 0xc2, 0x70, 0x26, 0x85, 0x5b, 0xd8, 0x44, 0xd9, 0xf6, 0x7f, 0x47, 0x66, 0x66, 0x2d, 0x36, 0x4d, 0x8e, 0x3b, 0xa9, 0xda, 0xb6, 0x69, 0xcf, 0x0a, 0xa2, 0x91, 0x1a, 0x9b, 0xe8, 0xf9, 0x8c, 0xf5, 0xcb, 0xae, 0xa6, 0x40, 0xb2, 0x2d, 0xc5, 0x5f, 0x76, 0x4b, 0x2b, 0x23, 0x2c, 0x95, 0xf2, 0x28, 0x90, 0xbe, 0xdc, 0x0b, 0x57, 0x19, 0xb5, 0x3d, 0xbc, 0x6f, 0xb8, 0xf4, 0xc7, 0xf4, 0x12, 0x11, 0xf4, 0xa8, 0x41, 0x92, 0x71, 0x41, 0xb1, 0x4c, 0x25, 0xb7, 0x5b, 0xc3, 0x2a, 0x53, 0x10, 0x41, 0x13, 0xb6, 0x5b, 0x8a, 0x68, 0x23, 0x33, 0x2b, 0x37, 0x50, 0x8a, 0xea, 0xb7, 0x33, 0x8e, 0x24, 0x5c, 0x71, 0xe6, 0x33, 0x16, 0x8a, 0x55, 0x94, 0x10, 0x5c, 0x1c, 0x64, 0x3a, 0x77, 0x48, 0x9c, 0xd1, 0x63, 0x98, 0x34, 0x97, 0x30, 0x53, 0x8a, 0x3e, 0x44, 0x83, 0x66, 0x7f, 0xa5, 0x83, 0x08, 0x7b, 0x93, 0x61, 0x2a, 0x1b, 0xda, 0x6c, 0x0b, 0xb2, 0x36, 0xbf, 0x16, 0x58, 0xa5, 0x0d, 0xc2, 0x80, 0x5f, 0x3c, 0xb8, 0xe6, 0x47, 0x4f, 0x7c, 0x9c, 0x7c, 0xe5, 0xb5, 0x74, 0x5b, 0xe9, 0x97, 0xe7, 0xd6, 0x75, 0xef, 0x16, 0x54, 0x55, 0x6a, 0xb3, 0x94, 0xcb, 0x5e, 0x5d, 0x41, 0xa9, 0x48, 0x37, 0xaa, 0xb2, 0x22, 0x36, 0xaf, 0xc1, 0xa7, 0x13, 0x7c, 0x5a, 0x3b, 0x60, 0x63, 0x3c, 0x53, 0x3f, 0xc7, 0x14, 0x13, 0x73, 0xc1, 0xb1, 0xd6, 0x77, 0xae, 0xe3, 0x10, 0xc9, 0xcd, 0x3a, 0xa4, 0x5a, 0xb1, 0xb2, 0xb2, 0xab, 0x0d, 0x2c, 0x92, 0x31, 0xca, 0x79, 0x9a, 0x2d, 0x6a, 0x85, 0xb4, 0x95, 0x45, 0xb4, 0x10, 0x36, 0xfb, 0x21, 0x2c, 0x23, 0x71, 0x50, 0x7d, 0xb7, 0x43, 0x1e, 0xeb, 0x87, 0x4e, 0x11, 0x4d, 0x22, 0xf9, 0x1e, 0xe4, 0xbb, 0x60, 0xe4, 0xea, 0x0c, 0xd6, 0x9a, 0x0a, 0x71, 0x21, 0x9a, 0xa2, 0xd9, 0xb5, 0x6c, 0xcb, 0x38, 0x2c, 0x66, 0xc2, 0x6c, 0xd4, 0xa6, 0x23, 0x20, 0xbe, 0x35, 0x99, 0x0e, 0x23, 0xa9, 0x72, 0x5e, 0x2c, 0x60, 0x27, 0x40, 0x5a, 0x47, 0x22, 0x59, 0xe9, 0x3a, 0x8a, 0x5d, 0x69, 0x8d, 0x7c, 0x78, 0x49, 0x22, 0x13, 0x5d, 0xba, 0xf4, 0x94, 0xe1, 0x9c, 0x4e, 0x8b, 0x62, 0x09, 0x08, 0x14, 0x86, 0xd9, 0x43, 0x99, 0xe2, 0xb5, 0x9c, 0x47, 0xf9, 0x3e, 0xc6, 0xc0, 0x95, 0x7b, 0x18, 0xb6, 0x97, 0x08, 0x6a, 0x75, 0x71, 0xb4, 0x15, 0x8c, 0x0b, 0x93, 0xd9, 0xc8, 0xe1, 0xb3, 0x55, 0x3e, 0xb6, 0x5d, 0xca, 0x77, 0x75, 0xba, 0xa6, 0x34, 0xdd, 0x6b, 0xcf, 0x91, 0xa4, 0x96, 0xc4, 0x18, 0x81, 0xd5, 0xb2, 0x27, 0x39, 0xb3, 0x2c, 0xf2, 0xc4, 0x67, 0xce, 0x3b, 0x6f, 0xe7, 0x78, 0xc7, 0x69, 0x12, 0xa7, 0xd6, 0xf9, 0x1e, 0x21, 0xd8, 0x30, 0xd0, 0x2a, 0x24, 0x91, 0x77, 0x8f, 0xba, 0x65, 0x2e, 0x2a, 0x88, 0x6d, 0x2d, 0x25, 0x8f, 0x54, 0xb7, 0x58, 0x8f, 0x06, 0x4c, 0xe3, 0xa3, 0x35, 0x29, 0x69, 0x9f, 0x3f, 0x43, 0x43, 0x5d, 0x76, 0x61, 0x45, 0xf7, 0x2f, 0xf0, 0x98, 0x16, 0x13, 0x47, 0xb3, 0x3d, 0x43, 0x25, 0x82, 0xf7, 0xbe, 0xb2, 0xc2, 0xbf, 0x24, 0x95, 0xbd, 0x4f, 0x46, 0x69, 0x02, 0x61, 0x0b, 0xc0, 0xf1, 0x3c, 0x8b, 0x41, 0x5f, 0xc7, 0xb0, 0x8b, 0xcd, 0x01, 0x83, 0x6d, 0x7d, 0xbc, 0xd7, 0x02, 0x28, 0x21, 0xae, 0x8c, 0xdf, 0x31, 0x77, 0x28, 0xe7, 0xa3, 0xf4, 0x61, 0x0d, 0xe2, 0x7f, 0x2f, 0x21, 0xf4, 0x94, 0x14, 0x1a, 0x73, 0xce, 0x9d, 0x00, 0x9d, 0x4e, 0xf1, 0x54, 0xe2, 0x87, 0xcf, 0x6e, 0xee, 0xf8, 0x29, 0x62, 0x2c, 0xaf, 0xc3, 0x3e, 0x73, 0xed, 0xb4, 0x7b, 0xdb, 0x2d, 0xaa, 0xe7, 0x60, 0x20, 0x70, 0x1b, 0x63, 0x39, 0x37, 0x5b, 0xda, 0x2b, 0x67, 0x5a, 0x7c, 0x26, 0x2b, 0xfd, 0x0c, 0x1c, 0x93, 0xa5, 0x02, 0x1f, 0xd8, 0xcc, 0xf5, 0x31, 0x4d, 0x86, 0x44, 0x5a, 0x50, 0x30, 0x27 }, .priv_len = 3168, .pub = { 0xac, 0x62, 0x48, 0x7e, 0xc9, 0x94, 0x62, 0xf2, 0x8a, 0x73, 0x53, 0xba, 0x54, 0xcc, 0x79, 0xe0, 0xfa, 0x69, 0x8c, 0x79, 0xb8, 0xa7, 0x34, 0x29, 0x8f, 0x35, 0x1c, 0x7d, 0x43, 0x5e, 0x4f, 0xca, 0xac, 0xbd, 0xa8, 0x77, 0xda, 0xe9, 0x5a, 0xea, 0xa9, 0x6f, 0xce, 0xa1, 0x9c, 0xb8, 0x62, 0xcd, 0xba, 0x2b, 0x67, 0xab, 0x75, 0x2c, 0x3e, 0x86, 0x92, 0xbe, 0x5b, 0x14, 0x01, 0x1b, 0x54, 0x5e, 0x24, 0xa3, 0xad, 0x33, 0x8b, 0xbb, 0x4c, 0x09, 0xf4, 0x76, 0x4e, 0x47, 0x9c, 0x44, 0x5f, 0x52, 0x62, 0x6e, 0x65, 0x16, 0x6a, 0x21, 0x87, 0x0e, 0xaa, 0xa0, 0xf1, 0x33, 0xc1, 0x3c, 0xc2, 0x27, 0x61, 0xa3, 0x2f, 0xf9, 0xb8, 0x13, 0x0a, 0x91, 0x56, 0x34, 0xa2, 0x75, 0xfc, 0x7c, 0x4d, 0x35, 0x38, 0x1b, 0x0f, 0x54, 0xbc, 0x28, 0x50, 0x46, 0xcf, 0x91, 0x8c, 0x71, 0x4c, 0x40, 0x2d, 0x35, 0x28, 0x2a, 0x3b, 0xc7, 0x58, 0x64, 0x9e, 0x95, 0xeb, 0x3b, 0x67, 0xb3, 0x2e, 0x71, 0xf3, 0x88, 0xe6, 0xe0, 0x37, 0x26, 0xd2, 0x36, 0x89, 0x24, 0x21, 0x4e, 0xcb, 0x60, 0xa9, 0x82, 0xc1, 0x96, 0x11, 0x9f, 0x78, 0xf4, 0x10, 0x10, 0x42, 0x4a, 0x72, 0x3a, 0xaa, 0x04, 0x68, 0x6d, 0x20, 0x05, 0x02, 0x3e, 0xfa, 0x9b, 0x5a, 0x24, 0x8a, 0x24, 0x91, 0xb7, 0xa5, 0x88, 0x80, 0xff, 0xc9, 0x74, 0xba, 0x64, 0x71, 0xf4, 0x42, 0x8f, 0x83, 0x12, 0x27, 0x8b, 0xc3, 0x89, 0xac, 0x72, 0x77, 0x80, 0x32, 0xc1, 0x65, 0x0b, 0x98, 0xa1, 0x6c, 0x48, 0x05, 0x5c, 0x63, 0x83, 0x2b, 0x06, 0x35, 0x57, 0x41, 0xfa, 0xdb, 0x7f, 0xb1, 0x86, 0xa6, 0x35, 0x15, 0x66, 0x23, 0xf3, 0x04, 0x76, 0x20, 0x4d, 0x00, 0x40, 0xb3, 0xb3, 0xd1, 0xbb, 0x1e, 0x7c, 0xb5, 0x2a, 0xd2, 0x9d, 0xf2, 0x1b, 0x96, 0x85, 0x41, 0x78, 0x9b, 0x91, 0x73, 0x40, 0x4c, 0xbb, 0x37, 0x57, 0x27, 0xbe, 0xe7, 0x50, 0x6f, 0x75, 0xa0, 0x37, 0x47, 0x8e, 0x11, 0x72, 0xb7, 0xd2, 0xdc, 0xba, 0x7e, 0x34, 0x23, 0x66, 0x6c, 0x49, 0x87, 0x5a, 0x48, 0xed, 0xe2, 0x12, 0x0d, 0x73, 0x6d, 0xd4, 0x7a, 0x8c, 0x65, 0xa2, 0x77, 0x53, 0x47, 0xbe, 0x72, 0x17, 0x09, 0x7e, 0xca, 0x27, 0x79, 0xfa, 0x9e, 0x01, 0xe5, 0x78, 0x7c, 0x02, 0x99, 0x35, 0x61, 0x58, 0xea, 0xa2, 0x3e, 0x45, 0x48, 0x2a, 0xba, 0x13, 0x43, 0x1c, 0x26, 0xbc, 0x9a, 0x97, 0xcc, 0x19, 0x5b, 0x49, 0xc0, 0x59, 0x3a, 0x73, 0x88, 0x72, 0xa2, 0xba, 0x15, 0x52, 0x17, 0xaf, 0x82, 0x07, 0xc9, 0x3b, 0x85, 0xc8, 0x31, 0x46, 0x70, 0xf4, 0x3c, 0x62, 0xa1, 0xf1, 0xa7, 0x7f, 0xc3, 0x8f, 0xed, 0x13, 0xca, 0x1a, 0xe6, 0xa0, 0x0e, 0x66, 0xc6, 0xd8, 0xf5, 0x75, 0x13, 0x3b, 0x8f, 0x77, 0x0b, 0x33, 0x1a, 0xd4, 0xad, 0x2f, 0x35, 0xb6, 0xca, 0xcb, 0xcb, 0xa1, 0xe5, 0xb0, 0xcf, 0xc3, 0xa0, 0xf4, 0x19, 0x6e, 0x66, 0x39, 0x1f, 0x5b, 0x54, 0x7c, 0xa1, 0x58, 0x47, 0x5e, 0xd0, 0x8a, 0xd8, 0xe7, 0x68, 0x65, 0x5b, 0x6e, 0x17, 0xb5, 0x90, 0x4a, 0x8c, 0x4b, 0x88, 0x53, 0xcb, 0x91, 0xc4, 0x88, 0xa0, 0x10, 0xb6, 0xd5, 0x45, 0x46, 0xea, 0x6b, 0x8e, 0x87, 0x44, 0x00, 0xc5, 0xe7, 0xa1, 0x83, 0xdc, 0x66, 0xd5, 0xd9, 0x2b, 0x88, 0xba, 0x29, 0x96, 0x72, 0xc1, 0x0a, 0x19, 0xb3, 0xb6, 0x07, 0x04, 0xa6, 0x85, 0x33, 0xa5, 0x41, 0x8d, 0xf5, 0xd3, 0x4a, 0x38, 0xf4, 0xb2, 0xad, 0xb4, 0x89, 0x26, 0x84, 0x42, 0x78, 0x2a, 0xa0, 0x06, 0x6c, 0x54, 0x1e, 0x58, 0x0b, 0x80, 0x69, 0xa1, 0xc0, 0x34, 0x17, 0xef, 0xda, 0x7c, 0x78, 0x03, 0xc9, 0x16, 0x9b, 0x0f, 0x2b, 0x3c, 0x92, 0x01, 0xf0, 0x1e, 0xe1, 0xc1, 0x22, 0xf4, 0xa5, 0x12, 0x54, 0x8a, 0x2b, 0x29, 0x27, 0x96, 0x04, 0x95, 0xc2, 0x1c, 0x07, 0xb3, 0x19, 0xa1, 0x48, 0x23, 0x23, 0x9e, 0xa1, 0xc4, 0x3b, 0x7f, 0x0a, 0x59, 0x57, 0x82, 0x02, 0x47, 0x00, 0x4e, 0x53, 0x78, 0x65, 0xb9, 0xfc, 0x11, 0x9e, 0x4b, 0x64, 0x7e, 0xa5, 0x0a, 0x43, 0x67, 0x24, 0x9f, 0xaa, 0x3b, 0xb1, 0xd6, 0x0c, 0xef, 0x9b, 0x04, 0xb3, 0xf5, 0xca, 0x5f, 0x53, 0xbb, 0xfc, 0xf6, 0x6c, 0xe9, 0x02, 0x36, 0x42, 0xb6, 0x08, 0xdb, 0x04, 0xa7, 0x65, 0xe6, 0x3e, 0x1f, 0x72, 0xa8, 0xf8, 0xc2, 0xc0, 0xdb, 0x5c, 0x7b, 0x4a, 0x71, 0x74, 0x25, 0xb0, 0x47, 0x87, 0x15, 0x7a, 0x20, 0xc4, 0x13, 0xfb, 0x1a, 0x9a, 0x6d, 0x17, 0x88, 0x2b, 0xf5, 0xc0, 0x98, 0xf8, 0x72, 0x40, 0xea, 0x90, 0x89, 0xd4, 0x79, 0x3a, 0xb7, 0xc5, 0xdc, 0xec, 0x82, 0x41, 0x02, 0xc7, 0x0a, 0x9c, 0xad, 0x24, 0xf3, 0x1b, 0xcf, 0x95, 0xbe, 0x08, 0x0b, 0x2e, 0x25, 0x06, 0x84, 0x05, 0x18, 0x91, 0x7a, 0x92, 0x6c, 0x54, 0xe1, 0xa0, 0xcd, 0x70, 0x6a, 0xe9, 0xd7, 0x95, 0x67, 0xcc, 0x2f, 0xa5, 0xfb, 0x56, 0x94, 0x21, 0xb7, 0x32, 0x19, 0xbb, 0x2c, 0x25, 0x94, 0x6d, 0xe2, 0xa6, 0x12, 0x35, 0x29, 0x63, 0x1a, 0x3a, 0x2f, 0xb4, 0x03, 0x4f, 0xab, 0x27, 0x45, 0x82, 0x01, 0x70, 0x67, 0x0f, 0x2e, 0xcc, 0xb7, 0xf2, 0x78, 0x55, 0x4d, 0x8a, 0x2e, 0x86, 0xf8, 0xbe, 0xde, 0xc1, 0x1b, 0xa3, 0x61, 0xad, 0x8e, 0x50, 0xbc, 0x83, 0x6b, 0x50, 0x85, 0x2c, 0x2a, 0x4e, 0x51, 0x51, 0x2b, 0x66, 0x65, 0x12, 0xf8, 0xc9, 0xd0, 0x4b, 0x5a, 0xff, 0x9a, 0x3e, 0x86, 0x47, 0x01, 0x76, 0xc0, 0x65, 0x0b, 0xc3, 0x5c, 0x35, 0x01, 0x0c, 0x1e, 0x27, 0x29, 0xd7, 0x66, 0xc6, 0xed, 0x92, 0x23, 0x32, 0xc7, 0x7a, 0x45, 0x67, 0xa7, 0x31, 0xc9, 0xab, 0x27, 0xa2, 0xab, 0xb3, 0x66, 0xb2, 0x99, 0x98, 0x49, 0xff, 0x2b, 0x66, 0xaf, 0x58, 0xc7, 0xec, 0xa5, 0x71, 0x3e, 0x21, 0x7f, 0x1e, 0x90, 0x19, 0x5d, 0xa5, 0x0e, 0x14, 0x38, 0x80, 0x14, 0x6b, 0xad, 0x9b, 0xcc, 0x07, 0xff, 0x18, 0x6d, 0x5d, 0xa4, 0xb7, 0x7c, 0x34, 0x93, 0x54, 0xf7, 0x9b, 0x6f, 0x35, 0x06, 0x67, 0xb1, 0x3c, 0xea, 0xa2, 0x30, 0x6f, 0xea, 0x97, 0x43, 0x36, 0xab, 0x7b, 0x45, 0xc4, 0x4b, 0x09, 0x46, 0x7b, 0xd8, 0x39, 0x1e, 0x13, 0xc9, 0x99, 0x02, 0x22, 0xbc, 0xf0, 0x48, 0x4b, 0x70, 0x66, 0x96, 0xb9, 0x02, 0x5f, 0x42, 0x45, 0x5f, 0x75, 0xb4, 0x7d, 0xba, 0x61, 0xe1, 0x33, 0x45, 0x11, 0xb9, 0xa9, 0x84, 0xc6, 0xae, 0xf2, 0x58, 0x64, 0x1f, 0xe6, 0x43, 0xd3, 0x87, 0x18, 0x9d, 0x13, 0xab, 0x87, 0xa9, 0xaf, 0x4c, 0x67, 0x98, 0xfc, 0x36, 0xc6, 0xb8, 0xa2, 0x6b, 0x72, 0xa3, 0xa8, 0x03, 0x25, 0x2c, 0xaa, 0x80, 0xbe, 0x5b, 0xaa, 0x7c, 0x2d, 0x12, 0xc8, 0xa9, 0x3b, 0xcf, 0xae, 0x05, 0x29, 0x52, 0x20, 0x7c, 0x5e, 0x1a, 0x93, 0x9a, 0x46, 0x95, 0x96, 0xd5, 0x0b, 0xe1, 0x3a, 0x9a, 0xf4, 0xe0, 0x8f, 0xd4, 0xc7, 0x16, 0x44, 0x03, 0x8f, 0xf1, 0x59, 0x4c, 0x20, 0xf2, 0x82, 0x6a, 0x70, 0x12, 0x8c, 0x24, 0x4c, 0x65, 0x37, 0x55, 0xe3, 0xa5, 0x19, 0xe9, 0x26, 0x14, 0x81, 0x21, 0x3a, 0x3b, 0x07, 0x60, 0x0b, 0xc0, 0xc6, 0x07, 0x10, 0x95, 0xf7, 0xb6, 0x6f, 0x24, 0x89, 0xce, 0x16, 0x33, 0x52, 0xb3, 0x9c, 0x33, 0xa0, 0xe4, 0x1e, 0xc6, 0x8b, 0xc0, 0x4e, 0x61, 0x8e, 0xfe, 0x75, 0xbb, 0x66, 0x92, 0x44, 0xb5, 0xd8, 0x0b, 0xf0, 0x4c, 0x8b, 0x1b, 0xf7, 0xcb, 0x60, 0x81, 0xa3, 0x08, 0x99, 0x96, 0xfb, 0xb8, 0x09, 0x36, 0x62, 0x85, 0x80, 0x54, 0x07, 0x62, 0xd0, 0xa1, 0x03, 0x1c, 0x16, 0xe2, 0x6a, 0x4b, 0x2f, 0x67, 0x4a, 0xd7, 0x71, 0x3e, 0x68, 0x41, 0x5c, 0x56, 0x09, 0xa3, 0xab, 0x13, 0x5d, 0x92, 0x81, 0xc0, 0xe7, 0xc7, 0x48, 0x4d, 0x08, 0x12, 0xea, 0xb2, 0xa5, 0x78, 0x30, 0x5f, 0x88, 0xd5, 0x2c, 0xa6, 0x5a, 0xc2, 0x70, 0x26, 0x85, 0x5b, 0xd8, 0x44, 0xd9, 0xf6, 0x7f, 0x47, 0x66, 0x66, 0x2d, 0x36, 0x4d, 0x8e, 0x3b, 0xa9, 0xda, 0xb6, 0x69, 0xcf, 0x0a, 0xa2, 0x91, 0x1a, 0x9b, 0xe8, 0xf9, 0x8c, 0xf5, 0xcb, 0xae, 0xa6, 0x40, 0xb2, 0x2d, 0xc5, 0x5f, 0x76, 0x4b, 0x2b, 0x23, 0x2c, 0x95, 0xf2, 0x28, 0x90, 0xbe, 0xdc, 0x0b, 0x57, 0x19, 0xb5, 0x3d, 0xbc, 0x6f, 0xb8, 0xf4, 0xc7, 0xf4, 0x12, 0x11, 0xf4, 0xa8, 0x41, 0x92, 0x71, 0x41, 0xb1, 0x4c, 0x25, 0xb7, 0x5b, 0xc3, 0x2a, 0x53, 0x10, 0x41, 0x13, 0xb6, 0x5b, 0x8a, 0x68, 0x23, 0x33, 0x2b, 0x37, 0x50, 0x8a, 0xea, 0xb7, 0x33, 0x8e, 0x24, 0x5c, 0x71, 0xe6, 0x33, 0x16, 0x8a, 0x55, 0x94, 0x10, 0x5c, 0x1c, 0x64, 0x3a, 0x77, 0x48, 0x9c, 0xd1, 0x63, 0x98, 0x34, 0x97, 0x30, 0x53, 0x8a, 0x3e, 0x44, 0x83, 0x66, 0x7f, 0xa5, 0x83, 0x08, 0x7b, 0x93, 0x61, 0x2a, 0x1b, 0xda, 0x6c, 0x0b, 0xb2, 0x36, 0xbf, 0x16, 0x58, 0xa5, 0x0d, 0xc2, 0x80, 0x5f, 0x3c, 0xb8, 0xe6, 0x47, 0x4f, 0x7c, 0x9c, 0x7c, 0xe5, 0xb5, 0x74, 0x5b, 0xe9, 0x97, 0xe7, 0xd6, 0x75, 0xef, 0x16, 0x54, 0x55, 0x6a, 0xb3, 0x94, 0xcb, 0x5e, 0x5d, 0x41, 0xa9, 0x48, 0x37, 0xaa, 0xb2, 0x22, 0x36, 0xaf, 0xc1, 0xa7, 0x13, 0x7c, 0x5a, 0x3b, 0x60, 0x63, 0x3c, 0x53, 0x3f, 0xc7, 0x14, 0x13, 0x73, 0xc1, 0xb1, 0xd6, 0x77, 0xae, 0xe3, 0x10, 0xc9, 0xcd, 0x3a, 0xa4, 0x5a, 0xb1, 0xb2, 0xb2, 0xab, 0x0d, 0x2c, 0x92, 0x31, 0xca, 0x79, 0x9a, 0x2d, 0x6a, 0x85, 0xb4, 0x95, 0x45, 0xb4, 0x10, 0x36, 0xfb, 0x21, 0x2c, 0x23, 0x71, 0x50, 0x7d, 0xb7, 0x43, 0x1e, 0xeb, 0x87, 0x4e, 0x11, 0x4d, 0x22, 0xf9, 0x1e, 0xe4, 0xbb, 0x60, 0xe4, 0xea, 0x0c, 0xd6, 0x9a, 0x0a, 0x71, 0x21, 0x9a, 0xa2, 0xd9, 0xb5, 0x6c, 0xcb, 0x38, 0x2c, 0x66, 0xc2, 0x6c, 0xd4, 0xa6, 0x23, 0x20, 0xbe, 0x35, 0x99, 0x0e, 0x23, 0xa9, 0x72, 0x5e, 0x2c, 0x60, 0x27, 0x40, 0x5a, 0x47, 0x22, 0x59, 0xe9, 0x3a, 0x8a, 0x5d, 0x69, 0x8d, 0x7c, 0x78, 0x49, 0x22, 0x13, 0x5d, 0xba, 0xf4, 0x94, 0xe1, 0x9c, 0x4e, 0x8b, 0x62, 0x09, 0x08, 0x14, 0x86, 0xd9, 0x43, 0x99, 0xe2, 0xb5, 0x9c, 0x47, 0xf9, 0x3e, 0xc6, 0xc0, 0x95, 0x7b, 0x18, 0xb6, 0x97, 0x08, 0x6a, 0x75, 0x71, 0xb4, 0x15, 0x8c, 0x0b, 0x93, 0xd9, 0xc8, 0xe1, 0xb3, 0x55, 0x3e, 0xb6, 0x5d, 0xca, 0x77, 0x75, 0xba, 0xa6, 0x34, 0xdd, 0x6b, 0xcf, 0x91, 0xa4, 0x96, 0xc4, 0x18, 0x81, 0xd5, 0xb2, 0x27, 0x39, 0xb3, 0x2c, 0xf2, 0xc4, 0x67, 0xce, 0x3b, 0x6f, 0xe7, 0x78, 0xc7, 0x69, 0x12, 0xa7, 0xd6, 0xf9, 0x1e, 0x21, 0xd8, 0x30, 0xd0, 0x2a, 0x24, 0x91, 0x77, 0x8f, 0xba, 0x65, 0x2e, 0x2a, 0x88, 0x6d, 0x2d, 0x25, 0x8f, 0x54, 0xb7, 0x58, 0x8f, 0x06, 0x4c, 0xe3, 0xa3, 0x35, 0x29, 0x69, 0x9f, 0x3f, 0x43, 0x43, 0x5d, 0x76, 0x61, 0x45, 0xf7, 0x2f, 0xf0, 0x98, 0x16, 0x13, 0x47, 0xb3, 0x3d, 0x43, 0x25, 0x82, 0xf7, 0xbe, 0xb2, 0xc2, 0xbf, 0x24, 0x95, 0xbd, 0x4f, 0x46, 0x69, 0x02, 0x61, 0x0b, 0xc0, 0xf1, 0x3c, 0x8b, 0x41, 0x5f, 0xc7, 0xb0, 0x8b, 0xcd, 0x01, 0x83, 0x6d, 0x7d, 0xbc, 0xd7, 0x02, 0x28, 0x21, 0xae, 0x8c, 0xdf, 0x31, 0x77, 0x28, 0xe7, 0xa3, 0xf4, 0x61, 0x0d, 0xe2, 0x7f, 0x2f, 0x21, 0xf4 }, .pub_len = 1568, }, { .name = "ML-KEM 1024 (seed only)", .parameter_set = CKP_ML_KEM_1024, .priv_seed = { 0xe3, 0xdf, 0x2c, 0xd8, 0x5c, 0x9d, 0xa6, 0xff, 0x5a, 0xbb, 0xd5, 0xd4, 0x03, 0x3b, 0xb8, 0xfc, 0x6a, 0xf9, 0xd8, 0x8e, 0x42, 0x35, 0xbd, 0x7f, 0x41, 0x29, 0x70, 0x6c, 0x1e, 0xff, 0x69, 0x6f, 0x20, 0x70, 0x1b, 0x63, 0x39, 0x37, 0x5b, 0xda, 0x2b, 0x67, 0x5a, 0x7c, 0x26, 0x2b, 0xfd, 0x0c, 0x1c, 0x93, 0xa5, 0x02, 0x1f, 0xd8, 0xcc, 0xf5, 0x31, 0x4d, 0x86, 0x44, 0x5a, 0x50, 0x30, 0x27 }, .priv_seed_len = 64, .pub = { 0xac, 0x62, 0x48, 0x7e, 0xc9, 0x94, 0x62, 0xf2, 0x8a, 0x73, 0x53, 0xba, 0x54, 0xcc, 0x79, 0xe0, 0xfa, 0x69, 0x8c, 0x79, 0xb8, 0xa7, 0x34, 0x29, 0x8f, 0x35, 0x1c, 0x7d, 0x43, 0x5e, 0x4f, 0xca, 0xac, 0xbd, 0xa8, 0x77, 0xda, 0xe9, 0x5a, 0xea, 0xa9, 0x6f, 0xce, 0xa1, 0x9c, 0xb8, 0x62, 0xcd, 0xba, 0x2b, 0x67, 0xab, 0x75, 0x2c, 0x3e, 0x86, 0x92, 0xbe, 0x5b, 0x14, 0x01, 0x1b, 0x54, 0x5e, 0x24, 0xa3, 0xad, 0x33, 0x8b, 0xbb, 0x4c, 0x09, 0xf4, 0x76, 0x4e, 0x47, 0x9c, 0x44, 0x5f, 0x52, 0x62, 0x6e, 0x65, 0x16, 0x6a, 0x21, 0x87, 0x0e, 0xaa, 0xa0, 0xf1, 0x33, 0xc1, 0x3c, 0xc2, 0x27, 0x61, 0xa3, 0x2f, 0xf9, 0xb8, 0x13, 0x0a, 0x91, 0x56, 0x34, 0xa2, 0x75, 0xfc, 0x7c, 0x4d, 0x35, 0x38, 0x1b, 0x0f, 0x54, 0xbc, 0x28, 0x50, 0x46, 0xcf, 0x91, 0x8c, 0x71, 0x4c, 0x40, 0x2d, 0x35, 0x28, 0x2a, 0x3b, 0xc7, 0x58, 0x64, 0x9e, 0x95, 0xeb, 0x3b, 0x67, 0xb3, 0x2e, 0x71, 0xf3, 0x88, 0xe6, 0xe0, 0x37, 0x26, 0xd2, 0x36, 0x89, 0x24, 0x21, 0x4e, 0xcb, 0x60, 0xa9, 0x82, 0xc1, 0x96, 0x11, 0x9f, 0x78, 0xf4, 0x10, 0x10, 0x42, 0x4a, 0x72, 0x3a, 0xaa, 0x04, 0x68, 0x6d, 0x20, 0x05, 0x02, 0x3e, 0xfa, 0x9b, 0x5a, 0x24, 0x8a, 0x24, 0x91, 0xb7, 0xa5, 0x88, 0x80, 0xff, 0xc9, 0x74, 0xba, 0x64, 0x71, 0xf4, 0x42, 0x8f, 0x83, 0x12, 0x27, 0x8b, 0xc3, 0x89, 0xac, 0x72, 0x77, 0x80, 0x32, 0xc1, 0x65, 0x0b, 0x98, 0xa1, 0x6c, 0x48, 0x05, 0x5c, 0x63, 0x83, 0x2b, 0x06, 0x35, 0x57, 0x41, 0xfa, 0xdb, 0x7f, 0xb1, 0x86, 0xa6, 0x35, 0x15, 0x66, 0x23, 0xf3, 0x04, 0x76, 0x20, 0x4d, 0x00, 0x40, 0xb3, 0xb3, 0xd1, 0xbb, 0x1e, 0x7c, 0xb5, 0x2a, 0xd2, 0x9d, 0xf2, 0x1b, 0x96, 0x85, 0x41, 0x78, 0x9b, 0x91, 0x73, 0x40, 0x4c, 0xbb, 0x37, 0x57, 0x27, 0xbe, 0xe7, 0x50, 0x6f, 0x75, 0xa0, 0x37, 0x47, 0x8e, 0x11, 0x72, 0xb7, 0xd2, 0xdc, 0xba, 0x7e, 0x34, 0x23, 0x66, 0x6c, 0x49, 0x87, 0x5a, 0x48, 0xed, 0xe2, 0x12, 0x0d, 0x73, 0x6d, 0xd4, 0x7a, 0x8c, 0x65, 0xa2, 0x77, 0x53, 0x47, 0xbe, 0x72, 0x17, 0x09, 0x7e, 0xca, 0x27, 0x79, 0xfa, 0x9e, 0x01, 0xe5, 0x78, 0x7c, 0x02, 0x99, 0x35, 0x61, 0x58, 0xea, 0xa2, 0x3e, 0x45, 0x48, 0x2a, 0xba, 0x13, 0x43, 0x1c, 0x26, 0xbc, 0x9a, 0x97, 0xcc, 0x19, 0x5b, 0x49, 0xc0, 0x59, 0x3a, 0x73, 0x88, 0x72, 0xa2, 0xba, 0x15, 0x52, 0x17, 0xaf, 0x82, 0x07, 0xc9, 0x3b, 0x85, 0xc8, 0x31, 0x46, 0x70, 0xf4, 0x3c, 0x62, 0xa1, 0xf1, 0xa7, 0x7f, 0xc3, 0x8f, 0xed, 0x13, 0xca, 0x1a, 0xe6, 0xa0, 0x0e, 0x66, 0xc6, 0xd8, 0xf5, 0x75, 0x13, 0x3b, 0x8f, 0x77, 0x0b, 0x33, 0x1a, 0xd4, 0xad, 0x2f, 0x35, 0xb6, 0xca, 0xcb, 0xcb, 0xa1, 0xe5, 0xb0, 0xcf, 0xc3, 0xa0, 0xf4, 0x19, 0x6e, 0x66, 0x39, 0x1f, 0x5b, 0x54, 0x7c, 0xa1, 0x58, 0x47, 0x5e, 0xd0, 0x8a, 0xd8, 0xe7, 0x68, 0x65, 0x5b, 0x6e, 0x17, 0xb5, 0x90, 0x4a, 0x8c, 0x4b, 0x88, 0x53, 0xcb, 0x91, 0xc4, 0x88, 0xa0, 0x10, 0xb6, 0xd5, 0x45, 0x46, 0xea, 0x6b, 0x8e, 0x87, 0x44, 0x00, 0xc5, 0xe7, 0xa1, 0x83, 0xdc, 0x66, 0xd5, 0xd9, 0x2b, 0x88, 0xba, 0x29, 0x96, 0x72, 0xc1, 0x0a, 0x19, 0xb3, 0xb6, 0x07, 0x04, 0xa6, 0x85, 0x33, 0xa5, 0x41, 0x8d, 0xf5, 0xd3, 0x4a, 0x38, 0xf4, 0xb2, 0xad, 0xb4, 0x89, 0x26, 0x84, 0x42, 0x78, 0x2a, 0xa0, 0x06, 0x6c, 0x54, 0x1e, 0x58, 0x0b, 0x80, 0x69, 0xa1, 0xc0, 0x34, 0x17, 0xef, 0xda, 0x7c, 0x78, 0x03, 0xc9, 0x16, 0x9b, 0x0f, 0x2b, 0x3c, 0x92, 0x01, 0xf0, 0x1e, 0xe1, 0xc1, 0x22, 0xf4, 0xa5, 0x12, 0x54, 0x8a, 0x2b, 0x29, 0x27, 0x96, 0x04, 0x95, 0xc2, 0x1c, 0x07, 0xb3, 0x19, 0xa1, 0x48, 0x23, 0x23, 0x9e, 0xa1, 0xc4, 0x3b, 0x7f, 0x0a, 0x59, 0x57, 0x82, 0x02, 0x47, 0x00, 0x4e, 0x53, 0x78, 0x65, 0xb9, 0xfc, 0x11, 0x9e, 0x4b, 0x64, 0x7e, 0xa5, 0x0a, 0x43, 0x67, 0x24, 0x9f, 0xaa, 0x3b, 0xb1, 0xd6, 0x0c, 0xef, 0x9b, 0x04, 0xb3, 0xf5, 0xca, 0x5f, 0x53, 0xbb, 0xfc, 0xf6, 0x6c, 0xe9, 0x02, 0x36, 0x42, 0xb6, 0x08, 0xdb, 0x04, 0xa7, 0x65, 0xe6, 0x3e, 0x1f, 0x72, 0xa8, 0xf8, 0xc2, 0xc0, 0xdb, 0x5c, 0x7b, 0x4a, 0x71, 0x74, 0x25, 0xb0, 0x47, 0x87, 0x15, 0x7a, 0x20, 0xc4, 0x13, 0xfb, 0x1a, 0x9a, 0x6d, 0x17, 0x88, 0x2b, 0xf5, 0xc0, 0x98, 0xf8, 0x72, 0x40, 0xea, 0x90, 0x89, 0xd4, 0x79, 0x3a, 0xb7, 0xc5, 0xdc, 0xec, 0x82, 0x41, 0x02, 0xc7, 0x0a, 0x9c, 0xad, 0x24, 0xf3, 0x1b, 0xcf, 0x95, 0xbe, 0x08, 0x0b, 0x2e, 0x25, 0x06, 0x84, 0x05, 0x18, 0x91, 0x7a, 0x92, 0x6c, 0x54, 0xe1, 0xa0, 0xcd, 0x70, 0x6a, 0xe9, 0xd7, 0x95, 0x67, 0xcc, 0x2f, 0xa5, 0xfb, 0x56, 0x94, 0x21, 0xb7, 0x32, 0x19, 0xbb, 0x2c, 0x25, 0x94, 0x6d, 0xe2, 0xa6, 0x12, 0x35, 0x29, 0x63, 0x1a, 0x3a, 0x2f, 0xb4, 0x03, 0x4f, 0xab, 0x27, 0x45, 0x82, 0x01, 0x70, 0x67, 0x0f, 0x2e, 0xcc, 0xb7, 0xf2, 0x78, 0x55, 0x4d, 0x8a, 0x2e, 0x86, 0xf8, 0xbe, 0xde, 0xc1, 0x1b, 0xa3, 0x61, 0xad, 0x8e, 0x50, 0xbc, 0x83, 0x6b, 0x50, 0x85, 0x2c, 0x2a, 0x4e, 0x51, 0x51, 0x2b, 0x66, 0x65, 0x12, 0xf8, 0xc9, 0xd0, 0x4b, 0x5a, 0xff, 0x9a, 0x3e, 0x86, 0x47, 0x01, 0x76, 0xc0, 0x65, 0x0b, 0xc3, 0x5c, 0x35, 0x01, 0x0c, 0x1e, 0x27, 0x29, 0xd7, 0x66, 0xc6, 0xed, 0x92, 0x23, 0x32, 0xc7, 0x7a, 0x45, 0x67, 0xa7, 0x31, 0xc9, 0xab, 0x27, 0xa2, 0xab, 0xb3, 0x66, 0xb2, 0x99, 0x98, 0x49, 0xff, 0x2b, 0x66, 0xaf, 0x58, 0xc7, 0xec, 0xa5, 0x71, 0x3e, 0x21, 0x7f, 0x1e, 0x90, 0x19, 0x5d, 0xa5, 0x0e, 0x14, 0x38, 0x80, 0x14, 0x6b, 0xad, 0x9b, 0xcc, 0x07, 0xff, 0x18, 0x6d, 0x5d, 0xa4, 0xb7, 0x7c, 0x34, 0x93, 0x54, 0xf7, 0x9b, 0x6f, 0x35, 0x06, 0x67, 0xb1, 0x3c, 0xea, 0xa2, 0x30, 0x6f, 0xea, 0x97, 0x43, 0x36, 0xab, 0x7b, 0x45, 0xc4, 0x4b, 0x09, 0x46, 0x7b, 0xd8, 0x39, 0x1e, 0x13, 0xc9, 0x99, 0x02, 0x22, 0xbc, 0xf0, 0x48, 0x4b, 0x70, 0x66, 0x96, 0xb9, 0x02, 0x5f, 0x42, 0x45, 0x5f, 0x75, 0xb4, 0x7d, 0xba, 0x61, 0xe1, 0x33, 0x45, 0x11, 0xb9, 0xa9, 0x84, 0xc6, 0xae, 0xf2, 0x58, 0x64, 0x1f, 0xe6, 0x43, 0xd3, 0x87, 0x18, 0x9d, 0x13, 0xab, 0x87, 0xa9, 0xaf, 0x4c, 0x67, 0x98, 0xfc, 0x36, 0xc6, 0xb8, 0xa2, 0x6b, 0x72, 0xa3, 0xa8, 0x03, 0x25, 0x2c, 0xaa, 0x80, 0xbe, 0x5b, 0xaa, 0x7c, 0x2d, 0x12, 0xc8, 0xa9, 0x3b, 0xcf, 0xae, 0x05, 0x29, 0x52, 0x20, 0x7c, 0x5e, 0x1a, 0x93, 0x9a, 0x46, 0x95, 0x96, 0xd5, 0x0b, 0xe1, 0x3a, 0x9a, 0xf4, 0xe0, 0x8f, 0xd4, 0xc7, 0x16, 0x44, 0x03, 0x8f, 0xf1, 0x59, 0x4c, 0x20, 0xf2, 0x82, 0x6a, 0x70, 0x12, 0x8c, 0x24, 0x4c, 0x65, 0x37, 0x55, 0xe3, 0xa5, 0x19, 0xe9, 0x26, 0x14, 0x81, 0x21, 0x3a, 0x3b, 0x07, 0x60, 0x0b, 0xc0, 0xc6, 0x07, 0x10, 0x95, 0xf7, 0xb6, 0x6f, 0x24, 0x89, 0xce, 0x16, 0x33, 0x52, 0xb3, 0x9c, 0x33, 0xa0, 0xe4, 0x1e, 0xc6, 0x8b, 0xc0, 0x4e, 0x61, 0x8e, 0xfe, 0x75, 0xbb, 0x66, 0x92, 0x44, 0xb5, 0xd8, 0x0b, 0xf0, 0x4c, 0x8b, 0x1b, 0xf7, 0xcb, 0x60, 0x81, 0xa3, 0x08, 0x99, 0x96, 0xfb, 0xb8, 0x09, 0x36, 0x62, 0x85, 0x80, 0x54, 0x07, 0x62, 0xd0, 0xa1, 0x03, 0x1c, 0x16, 0xe2, 0x6a, 0x4b, 0x2f, 0x67, 0x4a, 0xd7, 0x71, 0x3e, 0x68, 0x41, 0x5c, 0x56, 0x09, 0xa3, 0xab, 0x13, 0x5d, 0x92, 0x81, 0xc0, 0xe7, 0xc7, 0x48, 0x4d, 0x08, 0x12, 0xea, 0xb2, 0xa5, 0x78, 0x30, 0x5f, 0x88, 0xd5, 0x2c, 0xa6, 0x5a, 0xc2, 0x70, 0x26, 0x85, 0x5b, 0xd8, 0x44, 0xd9, 0xf6, 0x7f, 0x47, 0x66, 0x66, 0x2d, 0x36, 0x4d, 0x8e, 0x3b, 0xa9, 0xda, 0xb6, 0x69, 0xcf, 0x0a, 0xa2, 0x91, 0x1a, 0x9b, 0xe8, 0xf9, 0x8c, 0xf5, 0xcb, 0xae, 0xa6, 0x40, 0xb2, 0x2d, 0xc5, 0x5f, 0x76, 0x4b, 0x2b, 0x23, 0x2c, 0x95, 0xf2, 0x28, 0x90, 0xbe, 0xdc, 0x0b, 0x57, 0x19, 0xb5, 0x3d, 0xbc, 0x6f, 0xb8, 0xf4, 0xc7, 0xf4, 0x12, 0x11, 0xf4, 0xa8, 0x41, 0x92, 0x71, 0x41, 0xb1, 0x4c, 0x25, 0xb7, 0x5b, 0xc3, 0x2a, 0x53, 0x10, 0x41, 0x13, 0xb6, 0x5b, 0x8a, 0x68, 0x23, 0x33, 0x2b, 0x37, 0x50, 0x8a, 0xea, 0xb7, 0x33, 0x8e, 0x24, 0x5c, 0x71, 0xe6, 0x33, 0x16, 0x8a, 0x55, 0x94, 0x10, 0x5c, 0x1c, 0x64, 0x3a, 0x77, 0x48, 0x9c, 0xd1, 0x63, 0x98, 0x34, 0x97, 0x30, 0x53, 0x8a, 0x3e, 0x44, 0x83, 0x66, 0x7f, 0xa5, 0x83, 0x08, 0x7b, 0x93, 0x61, 0x2a, 0x1b, 0xda, 0x6c, 0x0b, 0xb2, 0x36, 0xbf, 0x16, 0x58, 0xa5, 0x0d, 0xc2, 0x80, 0x5f, 0x3c, 0xb8, 0xe6, 0x47, 0x4f, 0x7c, 0x9c, 0x7c, 0xe5, 0xb5, 0x74, 0x5b, 0xe9, 0x97, 0xe7, 0xd6, 0x75, 0xef, 0x16, 0x54, 0x55, 0x6a, 0xb3, 0x94, 0xcb, 0x5e, 0x5d, 0x41, 0xa9, 0x48, 0x37, 0xaa, 0xb2, 0x22, 0x36, 0xaf, 0xc1, 0xa7, 0x13, 0x7c, 0x5a, 0x3b, 0x60, 0x63, 0x3c, 0x53, 0x3f, 0xc7, 0x14, 0x13, 0x73, 0xc1, 0xb1, 0xd6, 0x77, 0xae, 0xe3, 0x10, 0xc9, 0xcd, 0x3a, 0xa4, 0x5a, 0xb1, 0xb2, 0xb2, 0xab, 0x0d, 0x2c, 0x92, 0x31, 0xca, 0x79, 0x9a, 0x2d, 0x6a, 0x85, 0xb4, 0x95, 0x45, 0xb4, 0x10, 0x36, 0xfb, 0x21, 0x2c, 0x23, 0x71, 0x50, 0x7d, 0xb7, 0x43, 0x1e, 0xeb, 0x87, 0x4e, 0x11, 0x4d, 0x22, 0xf9, 0x1e, 0xe4, 0xbb, 0x60, 0xe4, 0xea, 0x0c, 0xd6, 0x9a, 0x0a, 0x71, 0x21, 0x9a, 0xa2, 0xd9, 0xb5, 0x6c, 0xcb, 0x38, 0x2c, 0x66, 0xc2, 0x6c, 0xd4, 0xa6, 0x23, 0x20, 0xbe, 0x35, 0x99, 0x0e, 0x23, 0xa9, 0x72, 0x5e, 0x2c, 0x60, 0x27, 0x40, 0x5a, 0x47, 0x22, 0x59, 0xe9, 0x3a, 0x8a, 0x5d, 0x69, 0x8d, 0x7c, 0x78, 0x49, 0x22, 0x13, 0x5d, 0xba, 0xf4, 0x94, 0xe1, 0x9c, 0x4e, 0x8b, 0x62, 0x09, 0x08, 0x14, 0x86, 0xd9, 0x43, 0x99, 0xe2, 0xb5, 0x9c, 0x47, 0xf9, 0x3e, 0xc6, 0xc0, 0x95, 0x7b, 0x18, 0xb6, 0x97, 0x08, 0x6a, 0x75, 0x71, 0xb4, 0x15, 0x8c, 0x0b, 0x93, 0xd9, 0xc8, 0xe1, 0xb3, 0x55, 0x3e, 0xb6, 0x5d, 0xca, 0x77, 0x75, 0xba, 0xa6, 0x34, 0xdd, 0x6b, 0xcf, 0x91, 0xa4, 0x96, 0xc4, 0x18, 0x81, 0xd5, 0xb2, 0x27, 0x39, 0xb3, 0x2c, 0xf2, 0xc4, 0x67, 0xce, 0x3b, 0x6f, 0xe7, 0x78, 0xc7, 0x69, 0x12, 0xa7, 0xd6, 0xf9, 0x1e, 0x21, 0xd8, 0x30, 0xd0, 0x2a, 0x24, 0x91, 0x77, 0x8f, 0xba, 0x65, 0x2e, 0x2a, 0x88, 0x6d, 0x2d, 0x25, 0x8f, 0x54, 0xb7, 0x58, 0x8f, 0x06, 0x4c, 0xe3, 0xa3, 0x35, 0x29, 0x69, 0x9f, 0x3f, 0x43, 0x43, 0x5d, 0x76, 0x61, 0x45, 0xf7, 0x2f, 0xf0, 0x98, 0x16, 0x13, 0x47, 0xb3, 0x3d, 0x43, 0x25, 0x82, 0xf7, 0xbe, 0xb2, 0xc2, 0xbf, 0x24, 0x95, 0xbd, 0x4f, 0x46, 0x69, 0x02, 0x61, 0x0b, 0xc0, 0xf1, 0x3c, 0x8b, 0x41, 0x5f, 0xc7, 0xb0, 0x8b, 0xcd, 0x01, 0x83, 0x6d, 0x7d, 0xbc, 0xd7, 0x02, 0x28, 0x21, 0xae, 0x8c, 0xdf, 0x31, 0x77, 0x28, 0xe7, 0xa3, 0xf4, 0x61, 0x0d, 0xe2, 0x7f, 0x2f, 0x21, 0xf4 }, .pub_len = 1568, }, { .name = "ML-KEM 1024 (priv and seed)", .parameter_set = CKP_ML_KEM_1024, .priv_seed = { 0xe3, 0xdf, 0x2c, 0xd8, 0x5c, 0x9d, 0xa6, 0xff, 0x5a, 0xbb, 0xd5, 0xd4, 0x03, 0x3b, 0xb8, 0xfc, 0x6a, 0xf9, 0xd8, 0x8e, 0x42, 0x35, 0xbd, 0x7f, 0x41, 0x29, 0x70, 0x6c, 0x1e, 0xff, 0x69, 0x6f, 0x20, 0x70, 0x1b, 0x63, 0x39, 0x37, 0x5b, 0xda, 0x2b, 0x67, 0x5a, 0x7c, 0x26, 0x2b, 0xfd, 0x0c, 0x1c, 0x93, 0xa5, 0x02, 0x1f, 0xd8, 0xcc, 0xf5, 0x31, 0x4d, 0x86, 0x44, 0x5a, 0x50, 0x30, 0x27 }, .priv_seed_len = 64, .priv = { 0x92, 0xdb, 0x21, 0x87, 0xb1, 0x4d, 0x40, 0x31, 0x5c, 0x1b, 0xc0, 0xa1, 0xee, 0x02, 0x18, 0xa3, 0xeb, 0x9d, 0x6d, 0x72, 0x44, 0xdd, 0x56, 0x2e, 0x6e, 0x46, 0xba, 0x67, 0x62, 0x05, 0x83, 0xb7, 0x11, 0xf6, 0xfa, 0x8a, 0x04, 0xfb, 0xaa, 0xc8, 0xda, 0x73, 0x5e, 0x9b, 0x82, 0x73, 0x07, 0x32, 0x6f, 0xb2, 0x6f, 0x4c, 0xe2, 0x8f, 0x78, 0x25, 0x45, 0xb7, 0xdc, 0x22, 0xc4, 0xa6, 0x60, 0x0b, 0x73, 0xbd, 0xc7, 0xb3, 0x09, 0x8f, 0x6c, 0x3c, 0x27, 0x16, 0x1a, 0x03, 0x71, 0x69, 0xb9, 0x21, 0xa9, 0xaa, 0x58, 0x9b, 0x47, 0xd6, 0x2f, 0x24, 0xa0, 0x6c, 0x5c, 0x96, 0x53, 0xa9, 0x23, 0x1f, 0x1d, 0x79, 0xb4, 0xdd, 0x48, 0xaf, 0xf1, 0xf4, 0x85, 0xdd, 0xea, 0x95, 0x7d, 0x62, 0xbc, 0xf4, 0xd1, 0x39, 0x7a, 0xd5, 0x50, 0x01, 0xeb, 0x9e, 0x66, 0xac, 0x0c, 0x1d, 0xeb, 0x28, 0x20, 0xda, 0x82, 0x2c, 0x17, 0x20, 0xf2, 0xb7, 0xc0, 0x13, 0x8a, 0x03, 0xe4, 0x00, 0x95, 0xba, 0x64, 0x58, 0x4f, 0x62, 0xbc, 0xa7, 0xfb, 0x6c, 0xe3, 0xc6, 0x12, 0x16, 0xe3, 0x1b, 0x96, 0xe6, 0xaf, 0x23, 0x8a, 0x73, 0x34, 0xd9, 0xce, 0x0c, 0x20, 0xaf, 0x0a, 0x42, 0xba, 0x56, 0x44, 0xc9, 0x5a, 0x7b, 0x9a, 0x3e, 0xeb, 0x5d, 0x79, 0x2a, 0x64, 0x0d, 0x92, 0x0f, 0x1e, 0x4b, 0x3a, 0xd1, 0x51, 0xb9, 0x5e, 0xb0, 0x2d, 0x92, 0xc8, 0x19, 0xbd, 0x16, 0x18, 0xd0, 0x96, 0x0c, 0x41, 0x01, 0x31, 0xd0, 0x19, 0x8f, 0xe7, 0xf4, 0x60, 0xf5, 0x9a, 0x3b, 0x68, 0x22, 0x96, 0x58, 0xba, 0x48, 0x84, 0x11, 0x6a, 0x91, 0x8a, 0x8d, 0x5f, 0x94, 0x2a, 0xf7, 0x76, 0xc7, 0x46, 0x53, 0x3d, 0x41, 0xb4, 0x76, 0x06, 0xda, 0xb9, 0x6c, 0xa7, 0x55, 0x12, 0xa7, 0x8a, 0x84, 0x30, 0x9b, 0xd0, 0x42, 0xac, 0x39, 0xa8, 0x03, 0xde, 0x6c, 0xbf, 0xaf, 0xa2, 0x92, 0xb2, 0x6b, 0xca, 0x79, 0x96, 0x5d, 0x23, 0xdb, 0x12, 0x10, 0xa3, 0x91, 0x07, 0x2b, 0xb2, 0x43, 0x3c, 0x0d, 0xc4, 0xc1, 0x1a, 0x73, 0xfb, 0xb3, 0x09, 0xb9, 0x1c, 0xb6, 0x96, 0x7a, 0xa1, 0xb3, 0x92, 0x67, 0xa8, 0x0d, 0x73, 0xa0, 0x2e, 0xf6, 0x1c, 0x4b, 0x99, 0xe6, 0x43, 0x1f, 0xc6, 0xbc, 0x32, 0x6a, 0x33, 0x3b, 0xd6, 0x41, 0x12, 0x39, 0xa2, 0xc4, 0x2b, 0xc7, 0x53, 0x0a, 0x00, 0x23, 0x59, 0x10, 0xa8, 0xc3, 0x38, 0xd8, 0x7b, 0xbb, 0xda, 0x09, 0x83, 0x07, 0xe9, 0x6f, 0xc1, 0x45, 0x0e, 0xe6, 0xb0, 0x08, 0x3d, 0x80, 0x26, 0x6c, 0x79, 0x81, 0xe6, 0x95, 0x3d, 0x3b, 0x79, 0x5d, 0x3e, 0x95, 0x08, 0x4a, 0xb2, 0x16, 0xe6, 0xf0, 0x9c, 0x5f, 0x90, 0xc7, 0x0b, 0x02, 0xb0, 0x5a, 0x60, 0x18, 0xa4, 0x8a, 0x70, 0x1d, 0x37, 0xbb, 0x51, 0xdb, 0x52, 0xe0, 0x01, 0x36, 0x3f, 0x61, 0x97, 0x0f, 0x19, 0x56, 0x3b, 0xe6, 0xbd, 0x63, 0x99, 0xc7, 0x9c, 0x5a, 0x96, 0x75, 0xa9, 0x92, 0xe1, 0x69, 0x31, 0xc7, 0x99, 0x02, 0x84, 0x84, 0xb0, 0x0a, 0xf9, 0x0b, 0x83, 0x1c, 0xc1, 0x18, 0x12, 0x2c, 0x75, 0x27, 0xb8, 0x33, 0xe6, 0x5e, 0xd2, 0xca, 0x1b, 0xf0, 0x5c, 0x62, 0x14, 0x87, 0x0b, 0x3c, 0xac, 0x38, 0x86, 0x9c, 0x2c, 0x59, 0x29, 0x98, 0x1c, 0xf6, 0x5c, 0xbf, 0xab, 0xb8, 0xf9, 0x77, 0x45, 0x0d, 0x79, 0x3f, 0xb0, 0xac, 0x88, 0x9e, 0x55, 0x16, 0xa8, 0x96, 0x59, 0x97, 0x56, 0x85, 0xcb, 0xbb, 0x96, 0x0c, 0x37, 0xb5, 0xad, 0x64, 0xae, 0xa3, 0xd5, 0x20, 0xe3, 0xd4, 0x29, 0x97, 0x94, 0x17, 0xc5, 0x35, 0x45, 0x6c, 0xe5, 0x5e, 0x3a, 0x4c, 0x2c, 0xfc, 0xe4, 0x5a, 0x1a, 0x46, 0xa7, 0x95, 0xe7, 0x16, 0xd6, 0xa0, 0x15, 0x92, 0x3c, 0xc4, 0x19, 0x57, 0x86, 0x7d, 0xf6, 0xb4, 0xa6, 0x30, 0xca, 0x9c, 0x61, 0x1a, 0x34, 0x95, 0x53, 0x06, 0x4a, 0xa4, 0xbf, 0x27, 0x91, 0x7c, 0x83, 0x18, 0xf9, 0xa5, 0x15, 0x82, 0x01, 0x35, 0xad, 0x06, 0x4c, 0xd8, 0x30, 0x3e, 0xd1, 0x01, 0x16, 0x6c, 0xb3, 0xbb, 0x4e, 0xd0, 0xa2, 0x9f, 0xa1, 0x21, 0xf4, 0xdc, 0x20, 0xed, 0x85, 0x41, 0xc1, 0xcc, 0xce, 0x43, 0xd3, 0x2c, 0xa2, 0xf6, 0x7a, 0x31, 0x08, 0xa0, 0x86, 0xe4, 0x5f, 0x57, 0xc7, 0x6f, 0x50, 0xd2, 0xb7, 0x41, 0x84, 0x53, 0xe9, 0xca, 0xa5, 0x16, 0x97, 0x87, 0x60, 0x2c, 0xa3, 0x7e, 0x2b, 0x79, 0x1b, 0x43, 0x22, 0x70, 0x21, 0x78, 0x33, 0xd6, 0x2b, 0x13, 0x88, 0xa1, 0x66, 0x09, 0x1e, 0x99, 0x53, 0x67, 0x19, 0xc2, 0x6d, 0x30, 0x79, 0x97, 0x2b, 0x12, 0x99, 0x94, 0x54, 0x9c, 0x63, 0xb8, 0x1f, 0x00, 0xcd, 0x0f, 0x13, 0x43, 0x34, 0x27, 0xb7, 0x24, 0x48, 0x40, 0x91, 0x1e, 0xb2, 0x99, 0xa5, 0xb2, 0x1f, 0xbf, 0x98, 0xb9, 0xa7, 0x94, 0x90, 0x34, 0x0c, 0x3f, 0x3c, 0xaa, 0x05, 0xac, 0xb7, 0xae, 0x45, 0x26, 0x3d, 0xf3, 0xe7, 0x17, 0x6e, 0x39, 0x73, 0x09, 0xe9, 0x2e, 0x6c, 0x20, 0x2d, 0xa7, 0xb9, 0x77, 0x37, 0xa2, 0x40, 0xf2, 0xb4, 0x5d, 0x40, 0x55, 0x20, 0xdc, 0x22, 0x65, 0x01, 0x78, 0x92, 0x81, 0xfb, 0x04, 0x71, 0x4b, 0xbd, 0x6a, 0xb8, 0x67, 0x62, 0xbb, 0x55, 0x1f, 0xcb, 0x63, 0x5b, 0xca, 0x2f, 0x86, 0x72, 0x36, 0xac, 0x35, 0x12, 0xed, 0xca, 0xa8, 0x58, 0xdc, 0x00, 0x82, 0x54, 0x04, 0xec, 0xd2, 0x9b, 0xe6, 0xfb, 0x1e, 0xd5, 0xbb, 0x5d, 0xb6, 0x97, 0x3f, 0x85, 0x60, 0x28, 0x0a, 0xa8, 0x9f, 0xf1, 0x70, 0x01, 0xe1, 0x24, 0x18, 0x32, 0xc1, 0x21, 0xf9, 0x64, 0x93, 0x4f, 0x22, 0x60, 0x42, 0x0c, 0x2c, 0x69, 0xd2, 0x3e, 0x3d, 0x94, 0xc1, 0x59, 0xfb, 0x26, 0xfe, 0x49, 0x90, 0x4a, 0x30, 0x9f, 0x2e, 0x40, 0xc1, 0x66, 0xc3, 0x27, 0x4e, 0x74, 0x16, 0x32, 0x24, 0x7b, 0xaf, 0x1c, 0x00, 0x62, 0x81, 0x3b, 0x75, 0x47, 0xa6, 0x39, 0x69, 0x84, 0x6c, 0xa1, 0xca, 0xf8, 0xf5, 0x97, 0xe1, 0x59, 0x38, 0xcf, 0x76, 0xb4, 0x72, 0x8b, 0x49, 0x13, 0x0b, 0x27, 0x5c, 0xda, 0x47, 0x3b, 0xa9, 0x4e, 0x76, 0xe4, 0x78, 0x49, 0x74, 0x09, 0xaa, 0x97, 0xc0, 0x2f, 0xbb, 0x68, 0x0e, 0x19, 0x37, 0x76, 0x98, 0x30, 0x63, 0x40, 0x21, 0x48, 0xa8, 0x1f, 0x07, 0x8a, 0x6c, 0xc7, 0x22, 0x8c, 0xf7, 0x72, 0x90, 0x96, 0x47, 0x94, 0xdd, 0xc4, 0x73, 0xfd, 0x83, 0xba, 0x66, 0xf4, 0x0c, 0x75, 0x39, 0x76, 0x78, 0x76, 0x1b, 0x37, 0x4b, 0x17, 0x0f, 0xf5, 0x1d, 0x89, 0x36, 0x35, 0xcd, 0x8c, 0x71, 0x6d, 0x62, 0x22, 0xd8, 0x74, 0x68, 0x28, 0x28, 0xa4, 0xaa, 0xa7, 0x0e, 0x8d, 0x33, 0x6b, 0x56, 0x23, 0x94, 0x6f, 0x85, 0x41, 0x73, 0x32, 0x00, 0x2c, 0x53, 0x02, 0x43, 0xf1, 0x79, 0xcb, 0x9c, 0x56, 0x1d, 0x0b, 0x8d, 0xe5, 0x53, 0xac, 0xe7, 0xc0, 0x60, 0xbe, 0x4a, 0x6a, 0xd2, 0x7c, 0x93, 0xa0, 0xb0, 0x93, 0xc7, 0x82, 0x51, 0x18, 0x81, 0x20, 0x4b, 0x1a, 0x6f, 0x53, 0x10, 0x68, 0xa5, 0x12, 0xa9, 0xe7, 0x25, 0x41, 0x1a, 0xa1, 0x4a, 0x34, 0x92, 0x3b, 0xd8, 0x45, 0x64, 0x20, 0xbb, 0xad, 0xe3, 0x95, 0x09, 0xa1, 0x42, 0x55, 0x9f, 0x53, 0xc4, 0x6f, 0xf7, 0xad, 0xf7, 0x2c, 0x81, 0x03, 0x48, 0x39, 0x99, 0x60, 0x43, 0xa2, 0x8b, 0xae, 0xc3, 0xf3, 0xb4, 0xa5, 0x46, 0x11, 0xb4, 0xc3, 0x51, 0x3c, 0x1c, 0x35, 0x91, 0xe2, 0xa1, 0xce, 0xfb, 0x91, 0x2d, 0x87, 0x8f, 0x68, 0xb7, 0x15, 0x2b, 0x99, 0xb4, 0xfd, 0x40, 0x44, 0x44, 0x2c, 0x27, 0x62, 0x03, 0x06, 0x8c, 0x36, 0x37, 0xa5, 0x05, 0x4b, 0x1b, 0x25, 0xa4, 0xc9, 0x36, 0x33, 0x8c, 0x62, 0x9d, 0xc0, 0xb2, 0x3f, 0x06, 0x34, 0x7e, 0x12, 0xf9, 0x89, 0x1e, 0x52, 0x76, 0x35, 0x1c, 0x79, 0x89, 0x82, 0xc7, 0xc1, 0x89, 0x34, 0x81, 0x21, 0x1f, 0xf8, 0xea, 0xa2, 0xe6, 0x32, 0x6c, 0x1c, 0x0a, 0xa5, 0x9f, 0x27, 0x30, 0x3d, 0xdc, 0xcb, 0x67, 0x6a, 0x98, 0xb7, 0xe8, 0x83, 0x01, 0x10, 0x35, 0x7a, 0xf7, 0x54, 0xfd, 0xb4, 0x49, 0x29, 0x73, 0x2a, 0x82, 0xa8, 0xa1, 0xe6, 0xa1, 0x4c, 0x41, 0x25, 0x84, 0x03, 0x16, 0x3a, 0x97, 0x6a, 0x98, 0xf7, 0x89, 0xcd, 0xf5, 0x61, 0x75, 0x7f, 0xa1, 0x4c, 0x67, 0x30, 0x6e, 0x61, 0x30, 0x21, 0x3f, 0x29, 0xc0, 0x9c, 0x13, 0x12, 0x9a, 0xf5, 0x04, 0x15, 0x91, 0x5c, 0x2e, 0x99, 0x03, 0xbd, 0x50, 0x22, 0xb3, 0x98, 0x54, 0x87, 0xf2, 0x50, 0x5a, 0x33, 0x93, 0xf3, 0x62, 0x6b, 0xf1, 0x8b, 0x72, 0x6a, 0xc9, 0x28, 0x71, 0xd6, 0x98, 0x69, 0x28, 0xcb, 0xb7, 0x64, 0x6e, 0x17, 0x27, 0x6e, 0x33, 0xc0, 0x8c, 0x27, 0xc9, 0x5c, 0x76, 0x91, 0x5b, 0xe1, 0xeb, 0x88, 0x53, 0x6c, 0x51, 0xa6, 0xa7, 0x89, 0xcb, 0xda, 0x76, 0x81, 0xd5, 0x22, 0x43, 0x7c, 0x7a, 0x5c, 0x28, 0xa0, 0x38, 0x93, 0xa7, 0x36, 0xba, 0x59, 0x85, 0xd5, 0xb1, 0xfb, 0xd6, 0x32, 0xfb, 0x35, 0x4c, 0x5e, 0xd2, 0x52, 0x48, 0xb6, 0x0d, 0x0d, 0x17, 0x9f, 0xcd, 0x86, 0x94, 0xa8, 0x46, 0x4b, 0xbd, 0x11, 0xce, 0xee, 0xc6, 0x69, 0x23, 0x1a, 0x73, 0x60, 0xfb, 0xc9, 0x50, 0xe6, 0x5c, 0xe3, 0xc0, 0x6f, 0x45, 0x70, 0x8d, 0xfd, 0x9b, 0x31, 0x26, 0xe8, 0x44, 0xcc, 0x57, 0x66, 0xfd, 0xd7, 0x06, 0xec, 0xd6, 0x1d, 0xcb, 0x48, 0x20, 0x12, 0xdc, 0x40, 0xb1, 0xcb, 0x12, 0x7b, 0xab, 0xc7, 0xf0, 0x78, 0x93, 0x84, 0x89, 0x71, 0xb9, 0x74, 0x60, 0x72, 0xc7, 0x9f, 0x54, 0x7b, 0x0b, 0x64, 0xd2, 0x87, 0x1c, 0xb3, 0xc6, 0x4f, 0x27, 0x8b, 0xea, 0x23, 0x04, 0xe6, 0x39, 0x34, 0xab, 0xa4, 0x23, 0xf7, 0x79, 0x28, 0x1a, 0x9c, 0x82, 0xdc, 0x4b, 0x8f, 0x63, 0x33, 0x31, 0x30, 0x34, 0x4b, 0x8d, 0xc6, 0xc3, 0xcb, 0xd3, 0x4f, 0xac, 0x35, 0x4e, 0xb8, 0xa9, 0x9e, 0xb3, 0xb9, 0xb8, 0xa8, 0x90, 0x5a, 0x7b, 0xb8, 0x90, 0x82, 0x75, 0x1a, 0xdc, 0x30, 0x79, 0x90, 0x55, 0xbd, 0xc4, 0x27, 0x25, 0x10, 0xc8, 0x9f, 0x42, 0xb2, 0xc6, 0x08, 0x76, 0xc5, 0xfb, 0x18, 0x77, 0x70, 0x57, 0x8b, 0xeb, 0x69, 0x90, 0x85, 0x49, 0x51, 0x99, 0x1a, 0x05, 0x2e, 0x7b, 0x47, 0x75, 0x4b, 0x36, 0x29, 0x54, 0x0a, 0xb0, 0x3c, 0x81, 0x6b, 0x35, 0x41, 0x70, 0x5c, 0x59, 0x1b, 0xb3, 0x1d, 0xf1, 0x9c, 0xac, 0x89, 0x0c, 0x19, 0xd7, 0x0a, 0xa5, 0x3c, 0xb6, 0x9e, 0x01, 0x83, 0x63, 0x81, 0xf9, 0x71, 0x9f, 0x7c, 0x13, 0x1d, 0xa2, 0x5d, 0xb7, 0x52, 0x09, 0x8b, 0x48, 0x17, 0xc9, 0xdc, 0x8a, 0x93, 0x43, 0x19, 0x46, 0x98, 0x84, 0xc2, 0xa2, 0x2c, 0x40, 0xb1, 0xc0, 0xca, 0xcb, 0x45, 0xf9, 0x85, 0x7b, 0xd3, 0x02, 0x64, 0x56, 0x33, 0x73, 0xc7, 0xa2, 0x96, 0xb2, 0x4b, 0x78, 0x35, 0x0b, 0x7b, 0xf8, 0x42, 0x34, 0x4f, 0xa7, 0x66, 0x61, 0xa8, 0x2d, 0x04, 0x14, 0x06, 0x73, 0x9a, 0x2c, 0xac, 0x60, 0xc3, 0xc0, 0x14, 0x8d, 0x67, 0xbc, 0xbf, 0xe3, 0x14, 0x66, 0x16, 0xc0, 0x62, 0x5e, 0x04, 0x58, 0xe5, 0x19, 0x50, 0x16, 0xf4, 0x8f, 0xd4, 0x88, 0x83, 0x6a, 0x0b, 0x8a, 0xac, 0x62, 0x48, 0x7e, 0xc9, 0x94, 0x62, 0xf2, 0x8a, 0x73, 0x53, 0xba, 0x54, 0xcc, 0x79, 0xe0, 0xfa, 0x69, 0x8c, 0x79, 0xb8, 0xa7, 0x34, 0x29, 0x8f, 0x35, 0x1c, 0x7d, 0x43, 0x5e, 0x4f, 0xca, 0xac, 0xbd, 0xa8, 0x77, 0xda, 0xe9, 0x5a, 0xea, 0xa9, 0x6f, 0xce, 0xa1, 0x9c, 0xb8, 0x62, 0xcd, 0xba, 0x2b, 0x67, 0xab, 0x75, 0x2c, 0x3e, 0x86, 0x92, 0xbe, 0x5b, 0x14, 0x01, 0x1b, 0x54, 0x5e, 0x24, 0xa3, 0xad, 0x33, 0x8b, 0xbb, 0x4c, 0x09, 0xf4, 0x76, 0x4e, 0x47, 0x9c, 0x44, 0x5f, 0x52, 0x62, 0x6e, 0x65, 0x16, 0x6a, 0x21, 0x87, 0x0e, 0xaa, 0xa0, 0xf1, 0x33, 0xc1, 0x3c, 0xc2, 0x27, 0x61, 0xa3, 0x2f, 0xf9, 0xb8, 0x13, 0x0a, 0x91, 0x56, 0x34, 0xa2, 0x75, 0xfc, 0x7c, 0x4d, 0x35, 0x38, 0x1b, 0x0f, 0x54, 0xbc, 0x28, 0x50, 0x46, 0xcf, 0x91, 0x8c, 0x71, 0x4c, 0x40, 0x2d, 0x35, 0x28, 0x2a, 0x3b, 0xc7, 0x58, 0x64, 0x9e, 0x95, 0xeb, 0x3b, 0x67, 0xb3, 0x2e, 0x71, 0xf3, 0x88, 0xe6, 0xe0, 0x37, 0x26, 0xd2, 0x36, 0x89, 0x24, 0x21, 0x4e, 0xcb, 0x60, 0xa9, 0x82, 0xc1, 0x96, 0x11, 0x9f, 0x78, 0xf4, 0x10, 0x10, 0x42, 0x4a, 0x72, 0x3a, 0xaa, 0x04, 0x68, 0x6d, 0x20, 0x05, 0x02, 0x3e, 0xfa, 0x9b, 0x5a, 0x24, 0x8a, 0x24, 0x91, 0xb7, 0xa5, 0x88, 0x80, 0xff, 0xc9, 0x74, 0xba, 0x64, 0x71, 0xf4, 0x42, 0x8f, 0x83, 0x12, 0x27, 0x8b, 0xc3, 0x89, 0xac, 0x72, 0x77, 0x80, 0x32, 0xc1, 0x65, 0x0b, 0x98, 0xa1, 0x6c, 0x48, 0x05, 0x5c, 0x63, 0x83, 0x2b, 0x06, 0x35, 0x57, 0x41, 0xfa, 0xdb, 0x7f, 0xb1, 0x86, 0xa6, 0x35, 0x15, 0x66, 0x23, 0xf3, 0x04, 0x76, 0x20, 0x4d, 0x00, 0x40, 0xb3, 0xb3, 0xd1, 0xbb, 0x1e, 0x7c, 0xb5, 0x2a, 0xd2, 0x9d, 0xf2, 0x1b, 0x96, 0x85, 0x41, 0x78, 0x9b, 0x91, 0x73, 0x40, 0x4c, 0xbb, 0x37, 0x57, 0x27, 0xbe, 0xe7, 0x50, 0x6f, 0x75, 0xa0, 0x37, 0x47, 0x8e, 0x11, 0x72, 0xb7, 0xd2, 0xdc, 0xba, 0x7e, 0x34, 0x23, 0x66, 0x6c, 0x49, 0x87, 0x5a, 0x48, 0xed, 0xe2, 0x12, 0x0d, 0x73, 0x6d, 0xd4, 0x7a, 0x8c, 0x65, 0xa2, 0x77, 0x53, 0x47, 0xbe, 0x72, 0x17, 0x09, 0x7e, 0xca, 0x27, 0x79, 0xfa, 0x9e, 0x01, 0xe5, 0x78, 0x7c, 0x02, 0x99, 0x35, 0x61, 0x58, 0xea, 0xa2, 0x3e, 0x45, 0x48, 0x2a, 0xba, 0x13, 0x43, 0x1c, 0x26, 0xbc, 0x9a, 0x97, 0xcc, 0x19, 0x5b, 0x49, 0xc0, 0x59, 0x3a, 0x73, 0x88, 0x72, 0xa2, 0xba, 0x15, 0x52, 0x17, 0xaf, 0x82, 0x07, 0xc9, 0x3b, 0x85, 0xc8, 0x31, 0x46, 0x70, 0xf4, 0x3c, 0x62, 0xa1, 0xf1, 0xa7, 0x7f, 0xc3, 0x8f, 0xed, 0x13, 0xca, 0x1a, 0xe6, 0xa0, 0x0e, 0x66, 0xc6, 0xd8, 0xf5, 0x75, 0x13, 0x3b, 0x8f, 0x77, 0x0b, 0x33, 0x1a, 0xd4, 0xad, 0x2f, 0x35, 0xb6, 0xca, 0xcb, 0xcb, 0xa1, 0xe5, 0xb0, 0xcf, 0xc3, 0xa0, 0xf4, 0x19, 0x6e, 0x66, 0x39, 0x1f, 0x5b, 0x54, 0x7c, 0xa1, 0x58, 0x47, 0x5e, 0xd0, 0x8a, 0xd8, 0xe7, 0x68, 0x65, 0x5b, 0x6e, 0x17, 0xb5, 0x90, 0x4a, 0x8c, 0x4b, 0x88, 0x53, 0xcb, 0x91, 0xc4, 0x88, 0xa0, 0x10, 0xb6, 0xd5, 0x45, 0x46, 0xea, 0x6b, 0x8e, 0x87, 0x44, 0x00, 0xc5, 0xe7, 0xa1, 0x83, 0xdc, 0x66, 0xd5, 0xd9, 0x2b, 0x88, 0xba, 0x29, 0x96, 0x72, 0xc1, 0x0a, 0x19, 0xb3, 0xb6, 0x07, 0x04, 0xa6, 0x85, 0x33, 0xa5, 0x41, 0x8d, 0xf5, 0xd3, 0x4a, 0x38, 0xf4, 0xb2, 0xad, 0xb4, 0x89, 0x26, 0x84, 0x42, 0x78, 0x2a, 0xa0, 0x06, 0x6c, 0x54, 0x1e, 0x58, 0x0b, 0x80, 0x69, 0xa1, 0xc0, 0x34, 0x17, 0xef, 0xda, 0x7c, 0x78, 0x03, 0xc9, 0x16, 0x9b, 0x0f, 0x2b, 0x3c, 0x92, 0x01, 0xf0, 0x1e, 0xe1, 0xc1, 0x22, 0xf4, 0xa5, 0x12, 0x54, 0x8a, 0x2b, 0x29, 0x27, 0x96, 0x04, 0x95, 0xc2, 0x1c, 0x07, 0xb3, 0x19, 0xa1, 0x48, 0x23, 0x23, 0x9e, 0xa1, 0xc4, 0x3b, 0x7f, 0x0a, 0x59, 0x57, 0x82, 0x02, 0x47, 0x00, 0x4e, 0x53, 0x78, 0x65, 0xb9, 0xfc, 0x11, 0x9e, 0x4b, 0x64, 0x7e, 0xa5, 0x0a, 0x43, 0x67, 0x24, 0x9f, 0xaa, 0x3b, 0xb1, 0xd6, 0x0c, 0xef, 0x9b, 0x04, 0xb3, 0xf5, 0xca, 0x5f, 0x53, 0xbb, 0xfc, 0xf6, 0x6c, 0xe9, 0x02, 0x36, 0x42, 0xb6, 0x08, 0xdb, 0x04, 0xa7, 0x65, 0xe6, 0x3e, 0x1f, 0x72, 0xa8, 0xf8, 0xc2, 0xc0, 0xdb, 0x5c, 0x7b, 0x4a, 0x71, 0x74, 0x25, 0xb0, 0x47, 0x87, 0x15, 0x7a, 0x20, 0xc4, 0x13, 0xfb, 0x1a, 0x9a, 0x6d, 0x17, 0x88, 0x2b, 0xf5, 0xc0, 0x98, 0xf8, 0x72, 0x40, 0xea, 0x90, 0x89, 0xd4, 0x79, 0x3a, 0xb7, 0xc5, 0xdc, 0xec, 0x82, 0x41, 0x02, 0xc7, 0x0a, 0x9c, 0xad, 0x24, 0xf3, 0x1b, 0xcf, 0x95, 0xbe, 0x08, 0x0b, 0x2e, 0x25, 0x06, 0x84, 0x05, 0x18, 0x91, 0x7a, 0x92, 0x6c, 0x54, 0xe1, 0xa0, 0xcd, 0x70, 0x6a, 0xe9, 0xd7, 0x95, 0x67, 0xcc, 0x2f, 0xa5, 0xfb, 0x56, 0x94, 0x21, 0xb7, 0x32, 0x19, 0xbb, 0x2c, 0x25, 0x94, 0x6d, 0xe2, 0xa6, 0x12, 0x35, 0x29, 0x63, 0x1a, 0x3a, 0x2f, 0xb4, 0x03, 0x4f, 0xab, 0x27, 0x45, 0x82, 0x01, 0x70, 0x67, 0x0f, 0x2e, 0xcc, 0xb7, 0xf2, 0x78, 0x55, 0x4d, 0x8a, 0x2e, 0x86, 0xf8, 0xbe, 0xde, 0xc1, 0x1b, 0xa3, 0x61, 0xad, 0x8e, 0x50, 0xbc, 0x83, 0x6b, 0x50, 0x85, 0x2c, 0x2a, 0x4e, 0x51, 0x51, 0x2b, 0x66, 0x65, 0x12, 0xf8, 0xc9, 0xd0, 0x4b, 0x5a, 0xff, 0x9a, 0x3e, 0x86, 0x47, 0x01, 0x76, 0xc0, 0x65, 0x0b, 0xc3, 0x5c, 0x35, 0x01, 0x0c, 0x1e, 0x27, 0x29, 0xd7, 0x66, 0xc6, 0xed, 0x92, 0x23, 0x32, 0xc7, 0x7a, 0x45, 0x67, 0xa7, 0x31, 0xc9, 0xab, 0x27, 0xa2, 0xab, 0xb3, 0x66, 0xb2, 0x99, 0x98, 0x49, 0xff, 0x2b, 0x66, 0xaf, 0x58, 0xc7, 0xec, 0xa5, 0x71, 0x3e, 0x21, 0x7f, 0x1e, 0x90, 0x19, 0x5d, 0xa5, 0x0e, 0x14, 0x38, 0x80, 0x14, 0x6b, 0xad, 0x9b, 0xcc, 0x07, 0xff, 0x18, 0x6d, 0x5d, 0xa4, 0xb7, 0x7c, 0x34, 0x93, 0x54, 0xf7, 0x9b, 0x6f, 0x35, 0x06, 0x67, 0xb1, 0x3c, 0xea, 0xa2, 0x30, 0x6f, 0xea, 0x97, 0x43, 0x36, 0xab, 0x7b, 0x45, 0xc4, 0x4b, 0x09, 0x46, 0x7b, 0xd8, 0x39, 0x1e, 0x13, 0xc9, 0x99, 0x02, 0x22, 0xbc, 0xf0, 0x48, 0x4b, 0x70, 0x66, 0x96, 0xb9, 0x02, 0x5f, 0x42, 0x45, 0x5f, 0x75, 0xb4, 0x7d, 0xba, 0x61, 0xe1, 0x33, 0x45, 0x11, 0xb9, 0xa9, 0x84, 0xc6, 0xae, 0xf2, 0x58, 0x64, 0x1f, 0xe6, 0x43, 0xd3, 0x87, 0x18, 0x9d, 0x13, 0xab, 0x87, 0xa9, 0xaf, 0x4c, 0x67, 0x98, 0xfc, 0x36, 0xc6, 0xb8, 0xa2, 0x6b, 0x72, 0xa3, 0xa8, 0x03, 0x25, 0x2c, 0xaa, 0x80, 0xbe, 0x5b, 0xaa, 0x7c, 0x2d, 0x12, 0xc8, 0xa9, 0x3b, 0xcf, 0xae, 0x05, 0x29, 0x52, 0x20, 0x7c, 0x5e, 0x1a, 0x93, 0x9a, 0x46, 0x95, 0x96, 0xd5, 0x0b, 0xe1, 0x3a, 0x9a, 0xf4, 0xe0, 0x8f, 0xd4, 0xc7, 0x16, 0x44, 0x03, 0x8f, 0xf1, 0x59, 0x4c, 0x20, 0xf2, 0x82, 0x6a, 0x70, 0x12, 0x8c, 0x24, 0x4c, 0x65, 0x37, 0x55, 0xe3, 0xa5, 0x19, 0xe9, 0x26, 0x14, 0x81, 0x21, 0x3a, 0x3b, 0x07, 0x60, 0x0b, 0xc0, 0xc6, 0x07, 0x10, 0x95, 0xf7, 0xb6, 0x6f, 0x24, 0x89, 0xce, 0x16, 0x33, 0x52, 0xb3, 0x9c, 0x33, 0xa0, 0xe4, 0x1e, 0xc6, 0x8b, 0xc0, 0x4e, 0x61, 0x8e, 0xfe, 0x75, 0xbb, 0x66, 0x92, 0x44, 0xb5, 0xd8, 0x0b, 0xf0, 0x4c, 0x8b, 0x1b, 0xf7, 0xcb, 0x60, 0x81, 0xa3, 0x08, 0x99, 0x96, 0xfb, 0xb8, 0x09, 0x36, 0x62, 0x85, 0x80, 0x54, 0x07, 0x62, 0xd0, 0xa1, 0x03, 0x1c, 0x16, 0xe2, 0x6a, 0x4b, 0x2f, 0x67, 0x4a, 0xd7, 0x71, 0x3e, 0x68, 0x41, 0x5c, 0x56, 0x09, 0xa3, 0xab, 0x13, 0x5d, 0x92, 0x81, 0xc0, 0xe7, 0xc7, 0x48, 0x4d, 0x08, 0x12, 0xea, 0xb2, 0xa5, 0x78, 0x30, 0x5f, 0x88, 0xd5, 0x2c, 0xa6, 0x5a, 0xc2, 0x70, 0x26, 0x85, 0x5b, 0xd8, 0x44, 0xd9, 0xf6, 0x7f, 0x47, 0x66, 0x66, 0x2d, 0x36, 0x4d, 0x8e, 0x3b, 0xa9, 0xda, 0xb6, 0x69, 0xcf, 0x0a, 0xa2, 0x91, 0x1a, 0x9b, 0xe8, 0xf9, 0x8c, 0xf5, 0xcb, 0xae, 0xa6, 0x40, 0xb2, 0x2d, 0xc5, 0x5f, 0x76, 0x4b, 0x2b, 0x23, 0x2c, 0x95, 0xf2, 0x28, 0x90, 0xbe, 0xdc, 0x0b, 0x57, 0x19, 0xb5, 0x3d, 0xbc, 0x6f, 0xb8, 0xf4, 0xc7, 0xf4, 0x12, 0x11, 0xf4, 0xa8, 0x41, 0x92, 0x71, 0x41, 0xb1, 0x4c, 0x25, 0xb7, 0x5b, 0xc3, 0x2a, 0x53, 0x10, 0x41, 0x13, 0xb6, 0x5b, 0x8a, 0x68, 0x23, 0x33, 0x2b, 0x37, 0x50, 0x8a, 0xea, 0xb7, 0x33, 0x8e, 0x24, 0x5c, 0x71, 0xe6, 0x33, 0x16, 0x8a, 0x55, 0x94, 0x10, 0x5c, 0x1c, 0x64, 0x3a, 0x77, 0x48, 0x9c, 0xd1, 0x63, 0x98, 0x34, 0x97, 0x30, 0x53, 0x8a, 0x3e, 0x44, 0x83, 0x66, 0x7f, 0xa5, 0x83, 0x08, 0x7b, 0x93, 0x61, 0x2a, 0x1b, 0xda, 0x6c, 0x0b, 0xb2, 0x36, 0xbf, 0x16, 0x58, 0xa5, 0x0d, 0xc2, 0x80, 0x5f, 0x3c, 0xb8, 0xe6, 0x47, 0x4f, 0x7c, 0x9c, 0x7c, 0xe5, 0xb5, 0x74, 0x5b, 0xe9, 0x97, 0xe7, 0xd6, 0x75, 0xef, 0x16, 0x54, 0x55, 0x6a, 0xb3, 0x94, 0xcb, 0x5e, 0x5d, 0x41, 0xa9, 0x48, 0x37, 0xaa, 0xb2, 0x22, 0x36, 0xaf, 0xc1, 0xa7, 0x13, 0x7c, 0x5a, 0x3b, 0x60, 0x63, 0x3c, 0x53, 0x3f, 0xc7, 0x14, 0x13, 0x73, 0xc1, 0xb1, 0xd6, 0x77, 0xae, 0xe3, 0x10, 0xc9, 0xcd, 0x3a, 0xa4, 0x5a, 0xb1, 0xb2, 0xb2, 0xab, 0x0d, 0x2c, 0x92, 0x31, 0xca, 0x79, 0x9a, 0x2d, 0x6a, 0x85, 0xb4, 0x95, 0x45, 0xb4, 0x10, 0x36, 0xfb, 0x21, 0x2c, 0x23, 0x71, 0x50, 0x7d, 0xb7, 0x43, 0x1e, 0xeb, 0x87, 0x4e, 0x11, 0x4d, 0x22, 0xf9, 0x1e, 0xe4, 0xbb, 0x60, 0xe4, 0xea, 0x0c, 0xd6, 0x9a, 0x0a, 0x71, 0x21, 0x9a, 0xa2, 0xd9, 0xb5, 0x6c, 0xcb, 0x38, 0x2c, 0x66, 0xc2, 0x6c, 0xd4, 0xa6, 0x23, 0x20, 0xbe, 0x35, 0x99, 0x0e, 0x23, 0xa9, 0x72, 0x5e, 0x2c, 0x60, 0x27, 0x40, 0x5a, 0x47, 0x22, 0x59, 0xe9, 0x3a, 0x8a, 0x5d, 0x69, 0x8d, 0x7c, 0x78, 0x49, 0x22, 0x13, 0x5d, 0xba, 0xf4, 0x94, 0xe1, 0x9c, 0x4e, 0x8b, 0x62, 0x09, 0x08, 0x14, 0x86, 0xd9, 0x43, 0x99, 0xe2, 0xb5, 0x9c, 0x47, 0xf9, 0x3e, 0xc6, 0xc0, 0x95, 0x7b, 0x18, 0xb6, 0x97, 0x08, 0x6a, 0x75, 0x71, 0xb4, 0x15, 0x8c, 0x0b, 0x93, 0xd9, 0xc8, 0xe1, 0xb3, 0x55, 0x3e, 0xb6, 0x5d, 0xca, 0x77, 0x75, 0xba, 0xa6, 0x34, 0xdd, 0x6b, 0xcf, 0x91, 0xa4, 0x96, 0xc4, 0x18, 0x81, 0xd5, 0xb2, 0x27, 0x39, 0xb3, 0x2c, 0xf2, 0xc4, 0x67, 0xce, 0x3b, 0x6f, 0xe7, 0x78, 0xc7, 0x69, 0x12, 0xa7, 0xd6, 0xf9, 0x1e, 0x21, 0xd8, 0x30, 0xd0, 0x2a, 0x24, 0x91, 0x77, 0x8f, 0xba, 0x65, 0x2e, 0x2a, 0x88, 0x6d, 0x2d, 0x25, 0x8f, 0x54, 0xb7, 0x58, 0x8f, 0x06, 0x4c, 0xe3, 0xa3, 0x35, 0x29, 0x69, 0x9f, 0x3f, 0x43, 0x43, 0x5d, 0x76, 0x61, 0x45, 0xf7, 0x2f, 0xf0, 0x98, 0x16, 0x13, 0x47, 0xb3, 0x3d, 0x43, 0x25, 0x82, 0xf7, 0xbe, 0xb2, 0xc2, 0xbf, 0x24, 0x95, 0xbd, 0x4f, 0x46, 0x69, 0x02, 0x61, 0x0b, 0xc0, 0xf1, 0x3c, 0x8b, 0x41, 0x5f, 0xc7, 0xb0, 0x8b, 0xcd, 0x01, 0x83, 0x6d, 0x7d, 0xbc, 0xd7, 0x02, 0x28, 0x21, 0xae, 0x8c, 0xdf, 0x31, 0x77, 0x28, 0xe7, 0xa3, 0xf4, 0x61, 0x0d, 0xe2, 0x7f, 0x2f, 0x21, 0xf4, 0x94, 0x14, 0x1a, 0x73, 0xce, 0x9d, 0x00, 0x9d, 0x4e, 0xf1, 0x54, 0xe2, 0x87, 0xcf, 0x6e, 0xee, 0xf8, 0x29, 0x62, 0x2c, 0xaf, 0xc3, 0x3e, 0x73, 0xed, 0xb4, 0x7b, 0xdb, 0x2d, 0xaa, 0xe7, 0x60, 0x20, 0x70, 0x1b, 0x63, 0x39, 0x37, 0x5b, 0xda, 0x2b, 0x67, 0x5a, 0x7c, 0x26, 0x2b, 0xfd, 0x0c, 0x1c, 0x93, 0xa5, 0x02, 0x1f, 0xd8, 0xcc, 0xf5, 0x31, 0x4d, 0x86, 0x44, 0x5a, 0x50, 0x30, 0x27 }, .priv_len = 3168, .pub = { 0xac, 0x62, 0x48, 0x7e, 0xc9, 0x94, 0x62, 0xf2, 0x8a, 0x73, 0x53, 0xba, 0x54, 0xcc, 0x79, 0xe0, 0xfa, 0x69, 0x8c, 0x79, 0xb8, 0xa7, 0x34, 0x29, 0x8f, 0x35, 0x1c, 0x7d, 0x43, 0x5e, 0x4f, 0xca, 0xac, 0xbd, 0xa8, 0x77, 0xda, 0xe9, 0x5a, 0xea, 0xa9, 0x6f, 0xce, 0xa1, 0x9c, 0xb8, 0x62, 0xcd, 0xba, 0x2b, 0x67, 0xab, 0x75, 0x2c, 0x3e, 0x86, 0x92, 0xbe, 0x5b, 0x14, 0x01, 0x1b, 0x54, 0x5e, 0x24, 0xa3, 0xad, 0x33, 0x8b, 0xbb, 0x4c, 0x09, 0xf4, 0x76, 0x4e, 0x47, 0x9c, 0x44, 0x5f, 0x52, 0x62, 0x6e, 0x65, 0x16, 0x6a, 0x21, 0x87, 0x0e, 0xaa, 0xa0, 0xf1, 0x33, 0xc1, 0x3c, 0xc2, 0x27, 0x61, 0xa3, 0x2f, 0xf9, 0xb8, 0x13, 0x0a, 0x91, 0x56, 0x34, 0xa2, 0x75, 0xfc, 0x7c, 0x4d, 0x35, 0x38, 0x1b, 0x0f, 0x54, 0xbc, 0x28, 0x50, 0x46, 0xcf, 0x91, 0x8c, 0x71, 0x4c, 0x40, 0x2d, 0x35, 0x28, 0x2a, 0x3b, 0xc7, 0x58, 0x64, 0x9e, 0x95, 0xeb, 0x3b, 0x67, 0xb3, 0x2e, 0x71, 0xf3, 0x88, 0xe6, 0xe0, 0x37, 0x26, 0xd2, 0x36, 0x89, 0x24, 0x21, 0x4e, 0xcb, 0x60, 0xa9, 0x82, 0xc1, 0x96, 0x11, 0x9f, 0x78, 0xf4, 0x10, 0x10, 0x42, 0x4a, 0x72, 0x3a, 0xaa, 0x04, 0x68, 0x6d, 0x20, 0x05, 0x02, 0x3e, 0xfa, 0x9b, 0x5a, 0x24, 0x8a, 0x24, 0x91, 0xb7, 0xa5, 0x88, 0x80, 0xff, 0xc9, 0x74, 0xba, 0x64, 0x71, 0xf4, 0x42, 0x8f, 0x83, 0x12, 0x27, 0x8b, 0xc3, 0x89, 0xac, 0x72, 0x77, 0x80, 0x32, 0xc1, 0x65, 0x0b, 0x98, 0xa1, 0x6c, 0x48, 0x05, 0x5c, 0x63, 0x83, 0x2b, 0x06, 0x35, 0x57, 0x41, 0xfa, 0xdb, 0x7f, 0xb1, 0x86, 0xa6, 0x35, 0x15, 0x66, 0x23, 0xf3, 0x04, 0x76, 0x20, 0x4d, 0x00, 0x40, 0xb3, 0xb3, 0xd1, 0xbb, 0x1e, 0x7c, 0xb5, 0x2a, 0xd2, 0x9d, 0xf2, 0x1b, 0x96, 0x85, 0x41, 0x78, 0x9b, 0x91, 0x73, 0x40, 0x4c, 0xbb, 0x37, 0x57, 0x27, 0xbe, 0xe7, 0x50, 0x6f, 0x75, 0xa0, 0x37, 0x47, 0x8e, 0x11, 0x72, 0xb7, 0xd2, 0xdc, 0xba, 0x7e, 0x34, 0x23, 0x66, 0x6c, 0x49, 0x87, 0x5a, 0x48, 0xed, 0xe2, 0x12, 0x0d, 0x73, 0x6d, 0xd4, 0x7a, 0x8c, 0x65, 0xa2, 0x77, 0x53, 0x47, 0xbe, 0x72, 0x17, 0x09, 0x7e, 0xca, 0x27, 0x79, 0xfa, 0x9e, 0x01, 0xe5, 0x78, 0x7c, 0x02, 0x99, 0x35, 0x61, 0x58, 0xea, 0xa2, 0x3e, 0x45, 0x48, 0x2a, 0xba, 0x13, 0x43, 0x1c, 0x26, 0xbc, 0x9a, 0x97, 0xcc, 0x19, 0x5b, 0x49, 0xc0, 0x59, 0x3a, 0x73, 0x88, 0x72, 0xa2, 0xba, 0x15, 0x52, 0x17, 0xaf, 0x82, 0x07, 0xc9, 0x3b, 0x85, 0xc8, 0x31, 0x46, 0x70, 0xf4, 0x3c, 0x62, 0xa1, 0xf1, 0xa7, 0x7f, 0xc3, 0x8f, 0xed, 0x13, 0xca, 0x1a, 0xe6, 0xa0, 0x0e, 0x66, 0xc6, 0xd8, 0xf5, 0x75, 0x13, 0x3b, 0x8f, 0x77, 0x0b, 0x33, 0x1a, 0xd4, 0xad, 0x2f, 0x35, 0xb6, 0xca, 0xcb, 0xcb, 0xa1, 0xe5, 0xb0, 0xcf, 0xc3, 0xa0, 0xf4, 0x19, 0x6e, 0x66, 0x39, 0x1f, 0x5b, 0x54, 0x7c, 0xa1, 0x58, 0x47, 0x5e, 0xd0, 0x8a, 0xd8, 0xe7, 0x68, 0x65, 0x5b, 0x6e, 0x17, 0xb5, 0x90, 0x4a, 0x8c, 0x4b, 0x88, 0x53, 0xcb, 0x91, 0xc4, 0x88, 0xa0, 0x10, 0xb6, 0xd5, 0x45, 0x46, 0xea, 0x6b, 0x8e, 0x87, 0x44, 0x00, 0xc5, 0xe7, 0xa1, 0x83, 0xdc, 0x66, 0xd5, 0xd9, 0x2b, 0x88, 0xba, 0x29, 0x96, 0x72, 0xc1, 0x0a, 0x19, 0xb3, 0xb6, 0x07, 0x04, 0xa6, 0x85, 0x33, 0xa5, 0x41, 0x8d, 0xf5, 0xd3, 0x4a, 0x38, 0xf4, 0xb2, 0xad, 0xb4, 0x89, 0x26, 0x84, 0x42, 0x78, 0x2a, 0xa0, 0x06, 0x6c, 0x54, 0x1e, 0x58, 0x0b, 0x80, 0x69, 0xa1, 0xc0, 0x34, 0x17, 0xef, 0xda, 0x7c, 0x78, 0x03, 0xc9, 0x16, 0x9b, 0x0f, 0x2b, 0x3c, 0x92, 0x01, 0xf0, 0x1e, 0xe1, 0xc1, 0x22, 0xf4, 0xa5, 0x12, 0x54, 0x8a, 0x2b, 0x29, 0x27, 0x96, 0x04, 0x95, 0xc2, 0x1c, 0x07, 0xb3, 0x19, 0xa1, 0x48, 0x23, 0x23, 0x9e, 0xa1, 0xc4, 0x3b, 0x7f, 0x0a, 0x59, 0x57, 0x82, 0x02, 0x47, 0x00, 0x4e, 0x53, 0x78, 0x65, 0xb9, 0xfc, 0x11, 0x9e, 0x4b, 0x64, 0x7e, 0xa5, 0x0a, 0x43, 0x67, 0x24, 0x9f, 0xaa, 0x3b, 0xb1, 0xd6, 0x0c, 0xef, 0x9b, 0x04, 0xb3, 0xf5, 0xca, 0x5f, 0x53, 0xbb, 0xfc, 0xf6, 0x6c, 0xe9, 0x02, 0x36, 0x42, 0xb6, 0x08, 0xdb, 0x04, 0xa7, 0x65, 0xe6, 0x3e, 0x1f, 0x72, 0xa8, 0xf8, 0xc2, 0xc0, 0xdb, 0x5c, 0x7b, 0x4a, 0x71, 0x74, 0x25, 0xb0, 0x47, 0x87, 0x15, 0x7a, 0x20, 0xc4, 0x13, 0xfb, 0x1a, 0x9a, 0x6d, 0x17, 0x88, 0x2b, 0xf5, 0xc0, 0x98, 0xf8, 0x72, 0x40, 0xea, 0x90, 0x89, 0xd4, 0x79, 0x3a, 0xb7, 0xc5, 0xdc, 0xec, 0x82, 0x41, 0x02, 0xc7, 0x0a, 0x9c, 0xad, 0x24, 0xf3, 0x1b, 0xcf, 0x95, 0xbe, 0x08, 0x0b, 0x2e, 0x25, 0x06, 0x84, 0x05, 0x18, 0x91, 0x7a, 0x92, 0x6c, 0x54, 0xe1, 0xa0, 0xcd, 0x70, 0x6a, 0xe9, 0xd7, 0x95, 0x67, 0xcc, 0x2f, 0xa5, 0xfb, 0x56, 0x94, 0x21, 0xb7, 0x32, 0x19, 0xbb, 0x2c, 0x25, 0x94, 0x6d, 0xe2, 0xa6, 0x12, 0x35, 0x29, 0x63, 0x1a, 0x3a, 0x2f, 0xb4, 0x03, 0x4f, 0xab, 0x27, 0x45, 0x82, 0x01, 0x70, 0x67, 0x0f, 0x2e, 0xcc, 0xb7, 0xf2, 0x78, 0x55, 0x4d, 0x8a, 0x2e, 0x86, 0xf8, 0xbe, 0xde, 0xc1, 0x1b, 0xa3, 0x61, 0xad, 0x8e, 0x50, 0xbc, 0x83, 0x6b, 0x50, 0x85, 0x2c, 0x2a, 0x4e, 0x51, 0x51, 0x2b, 0x66, 0x65, 0x12, 0xf8, 0xc9, 0xd0, 0x4b, 0x5a, 0xff, 0x9a, 0x3e, 0x86, 0x47, 0x01, 0x76, 0xc0, 0x65, 0x0b, 0xc3, 0x5c, 0x35, 0x01, 0x0c, 0x1e, 0x27, 0x29, 0xd7, 0x66, 0xc6, 0xed, 0x92, 0x23, 0x32, 0xc7, 0x7a, 0x45, 0x67, 0xa7, 0x31, 0xc9, 0xab, 0x27, 0xa2, 0xab, 0xb3, 0x66, 0xb2, 0x99, 0x98, 0x49, 0xff, 0x2b, 0x66, 0xaf, 0x58, 0xc7, 0xec, 0xa5, 0x71, 0x3e, 0x21, 0x7f, 0x1e, 0x90, 0x19, 0x5d, 0xa5, 0x0e, 0x14, 0x38, 0x80, 0x14, 0x6b, 0xad, 0x9b, 0xcc, 0x07, 0xff, 0x18, 0x6d, 0x5d, 0xa4, 0xb7, 0x7c, 0x34, 0x93, 0x54, 0xf7, 0x9b, 0x6f, 0x35, 0x06, 0x67, 0xb1, 0x3c, 0xea, 0xa2, 0x30, 0x6f, 0xea, 0x97, 0x43, 0x36, 0xab, 0x7b, 0x45, 0xc4, 0x4b, 0x09, 0x46, 0x7b, 0xd8, 0x39, 0x1e, 0x13, 0xc9, 0x99, 0x02, 0x22, 0xbc, 0xf0, 0x48, 0x4b, 0x70, 0x66, 0x96, 0xb9, 0x02, 0x5f, 0x42, 0x45, 0x5f, 0x75, 0xb4, 0x7d, 0xba, 0x61, 0xe1, 0x33, 0x45, 0x11, 0xb9, 0xa9, 0x84, 0xc6, 0xae, 0xf2, 0x58, 0x64, 0x1f, 0xe6, 0x43, 0xd3, 0x87, 0x18, 0x9d, 0x13, 0xab, 0x87, 0xa9, 0xaf, 0x4c, 0x67, 0x98, 0xfc, 0x36, 0xc6, 0xb8, 0xa2, 0x6b, 0x72, 0xa3, 0xa8, 0x03, 0x25, 0x2c, 0xaa, 0x80, 0xbe, 0x5b, 0xaa, 0x7c, 0x2d, 0x12, 0xc8, 0xa9, 0x3b, 0xcf, 0xae, 0x05, 0x29, 0x52, 0x20, 0x7c, 0x5e, 0x1a, 0x93, 0x9a, 0x46, 0x95, 0x96, 0xd5, 0x0b, 0xe1, 0x3a, 0x9a, 0xf4, 0xe0, 0x8f, 0xd4, 0xc7, 0x16, 0x44, 0x03, 0x8f, 0xf1, 0x59, 0x4c, 0x20, 0xf2, 0x82, 0x6a, 0x70, 0x12, 0x8c, 0x24, 0x4c, 0x65, 0x37, 0x55, 0xe3, 0xa5, 0x19, 0xe9, 0x26, 0x14, 0x81, 0x21, 0x3a, 0x3b, 0x07, 0x60, 0x0b, 0xc0, 0xc6, 0x07, 0x10, 0x95, 0xf7, 0xb6, 0x6f, 0x24, 0x89, 0xce, 0x16, 0x33, 0x52, 0xb3, 0x9c, 0x33, 0xa0, 0xe4, 0x1e, 0xc6, 0x8b, 0xc0, 0x4e, 0x61, 0x8e, 0xfe, 0x75, 0xbb, 0x66, 0x92, 0x44, 0xb5, 0xd8, 0x0b, 0xf0, 0x4c, 0x8b, 0x1b, 0xf7, 0xcb, 0x60, 0x81, 0xa3, 0x08, 0x99, 0x96, 0xfb, 0xb8, 0x09, 0x36, 0x62, 0x85, 0x80, 0x54, 0x07, 0x62, 0xd0, 0xa1, 0x03, 0x1c, 0x16, 0xe2, 0x6a, 0x4b, 0x2f, 0x67, 0x4a, 0xd7, 0x71, 0x3e, 0x68, 0x41, 0x5c, 0x56, 0x09, 0xa3, 0xab, 0x13, 0x5d, 0x92, 0x81, 0xc0, 0xe7, 0xc7, 0x48, 0x4d, 0x08, 0x12, 0xea, 0xb2, 0xa5, 0x78, 0x30, 0x5f, 0x88, 0xd5, 0x2c, 0xa6, 0x5a, 0xc2, 0x70, 0x26, 0x85, 0x5b, 0xd8, 0x44, 0xd9, 0xf6, 0x7f, 0x47, 0x66, 0x66, 0x2d, 0x36, 0x4d, 0x8e, 0x3b, 0xa9, 0xda, 0xb6, 0x69, 0xcf, 0x0a, 0xa2, 0x91, 0x1a, 0x9b, 0xe8, 0xf9, 0x8c, 0xf5, 0xcb, 0xae, 0xa6, 0x40, 0xb2, 0x2d, 0xc5, 0x5f, 0x76, 0x4b, 0x2b, 0x23, 0x2c, 0x95, 0xf2, 0x28, 0x90, 0xbe, 0xdc, 0x0b, 0x57, 0x19, 0xb5, 0x3d, 0xbc, 0x6f, 0xb8, 0xf4, 0xc7, 0xf4, 0x12, 0x11, 0xf4, 0xa8, 0x41, 0x92, 0x71, 0x41, 0xb1, 0x4c, 0x25, 0xb7, 0x5b, 0xc3, 0x2a, 0x53, 0x10, 0x41, 0x13, 0xb6, 0x5b, 0x8a, 0x68, 0x23, 0x33, 0x2b, 0x37, 0x50, 0x8a, 0xea, 0xb7, 0x33, 0x8e, 0x24, 0x5c, 0x71, 0xe6, 0x33, 0x16, 0x8a, 0x55, 0x94, 0x10, 0x5c, 0x1c, 0x64, 0x3a, 0x77, 0x48, 0x9c, 0xd1, 0x63, 0x98, 0x34, 0x97, 0x30, 0x53, 0x8a, 0x3e, 0x44, 0x83, 0x66, 0x7f, 0xa5, 0x83, 0x08, 0x7b, 0x93, 0x61, 0x2a, 0x1b, 0xda, 0x6c, 0x0b, 0xb2, 0x36, 0xbf, 0x16, 0x58, 0xa5, 0x0d, 0xc2, 0x80, 0x5f, 0x3c, 0xb8, 0xe6, 0x47, 0x4f, 0x7c, 0x9c, 0x7c, 0xe5, 0xb5, 0x74, 0x5b, 0xe9, 0x97, 0xe7, 0xd6, 0x75, 0xef, 0x16, 0x54, 0x55, 0x6a, 0xb3, 0x94, 0xcb, 0x5e, 0x5d, 0x41, 0xa9, 0x48, 0x37, 0xaa, 0xb2, 0x22, 0x36, 0xaf, 0xc1, 0xa7, 0x13, 0x7c, 0x5a, 0x3b, 0x60, 0x63, 0x3c, 0x53, 0x3f, 0xc7, 0x14, 0x13, 0x73, 0xc1, 0xb1, 0xd6, 0x77, 0xae, 0xe3, 0x10, 0xc9, 0xcd, 0x3a, 0xa4, 0x5a, 0xb1, 0xb2, 0xb2, 0xab, 0x0d, 0x2c, 0x92, 0x31, 0xca, 0x79, 0x9a, 0x2d, 0x6a, 0x85, 0xb4, 0x95, 0x45, 0xb4, 0x10, 0x36, 0xfb, 0x21, 0x2c, 0x23, 0x71, 0x50, 0x7d, 0xb7, 0x43, 0x1e, 0xeb, 0x87, 0x4e, 0x11, 0x4d, 0x22, 0xf9, 0x1e, 0xe4, 0xbb, 0x60, 0xe4, 0xea, 0x0c, 0xd6, 0x9a, 0x0a, 0x71, 0x21, 0x9a, 0xa2, 0xd9, 0xb5, 0x6c, 0xcb, 0x38, 0x2c, 0x66, 0xc2, 0x6c, 0xd4, 0xa6, 0x23, 0x20, 0xbe, 0x35, 0x99, 0x0e, 0x23, 0xa9, 0x72, 0x5e, 0x2c, 0x60, 0x27, 0x40, 0x5a, 0x47, 0x22, 0x59, 0xe9, 0x3a, 0x8a, 0x5d, 0x69, 0x8d, 0x7c, 0x78, 0x49, 0x22, 0x13, 0x5d, 0xba, 0xf4, 0x94, 0xe1, 0x9c, 0x4e, 0x8b, 0x62, 0x09, 0x08, 0x14, 0x86, 0xd9, 0x43, 0x99, 0xe2, 0xb5, 0x9c, 0x47, 0xf9, 0x3e, 0xc6, 0xc0, 0x95, 0x7b, 0x18, 0xb6, 0x97, 0x08, 0x6a, 0x75, 0x71, 0xb4, 0x15, 0x8c, 0x0b, 0x93, 0xd9, 0xc8, 0xe1, 0xb3, 0x55, 0x3e, 0xb6, 0x5d, 0xca, 0x77, 0x75, 0xba, 0xa6, 0x34, 0xdd, 0x6b, 0xcf, 0x91, 0xa4, 0x96, 0xc4, 0x18, 0x81, 0xd5, 0xb2, 0x27, 0x39, 0xb3, 0x2c, 0xf2, 0xc4, 0x67, 0xce, 0x3b, 0x6f, 0xe7, 0x78, 0xc7, 0x69, 0x12, 0xa7, 0xd6, 0xf9, 0x1e, 0x21, 0xd8, 0x30, 0xd0, 0x2a, 0x24, 0x91, 0x77, 0x8f, 0xba, 0x65, 0x2e, 0x2a, 0x88, 0x6d, 0x2d, 0x25, 0x8f, 0x54, 0xb7, 0x58, 0x8f, 0x06, 0x4c, 0xe3, 0xa3, 0x35, 0x29, 0x69, 0x9f, 0x3f, 0x43, 0x43, 0x5d, 0x76, 0x61, 0x45, 0xf7, 0x2f, 0xf0, 0x98, 0x16, 0x13, 0x47, 0xb3, 0x3d, 0x43, 0x25, 0x82, 0xf7, 0xbe, 0xb2, 0xc2, 0xbf, 0x24, 0x95, 0xbd, 0x4f, 0x46, 0x69, 0x02, 0x61, 0x0b, 0xc0, 0xf1, 0x3c, 0x8b, 0x41, 0x5f, 0xc7, 0xb0, 0x8b, 0xcd, 0x01, 0x83, 0x6d, 0x7d, 0xbc, 0xd7, 0x02, 0x28, 0x21, 0xae, 0x8c, 0xdf, 0x31, 0x77, 0x28, 0xe7, 0xa3, 0xf4, 0x61, 0x0d, 0xe2, 0x7f, 0x2f, 0x21, 0xf4 }, .pub_len = 1568, }, }; #define ML_KEM_TV_NUM sizeof(ml_kem_tv)/sizeof(struct ML_KEM_TEST_VECTOR) opencryptoki-opencryptoki-451d99c/testcases/crypto/ml_kem_func.c000066400000000000000000000676741520105705100253110ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2026 * * 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 "mechtable.h" #include "ec_curves.h" #include "ml_kem.h" /** * Support for ML-KEM keys and KEM * with oid = 2.16.840.1.101.3.4.4.xxx */ typedef struct variant_info { const char *name; CK_ML_KEM_PARAMETER_SET_TYPE parameter_set; } _variant_info; const _variant_info variants[] = { { "ML_KEM_512", CKP_ML_KEM_512, }, { "ML_KEM_768", CKP_ML_KEM_768, }, { "ML_KEM_1024", CKP_ML_KEM_1024, }, }; const CK_ULONG num_variants = sizeof(variants) / sizeof(_variant_info); typedef struct kemParam { CK_KEY_TYPE secret_key_type; CK_ULONG secret_key_len; } _kemParam; const _kemParam kemInput[] = { { CKK_AES, 32 }, { CKK_AES, 24 }, { CKK_AES, 16 }, { CKK_GENERIC_SECRET, 16 }, { CKK_GENERIC_SECRET, 32 }, }; const CK_ULONG num_kem_inputs = sizeof(kemInput) / sizeof(_kemParam); /* * Perform a AES encrypt and decrypt that the key is usable. */ CK_RV run_AESCrypt(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE h_key1, CK_OBJECT_HANDLE h_key2) { CK_MECHANISM mech = { .mechanism = CKM_AES_ECB, .pParameter = NULL, .ulParameterLen = 0 }; CK_BYTE data[32] = { 0 }; CK_BYTE out[32] = { 0 }; CK_ULONG out_len = sizeof(out); CK_RV rc = CKR_OK; if (!mech_supported(SLOT_ID, CKM_AES_ECB)) { testcase_notice("Mechanism CKM_AES_ECB is not supported with slot " "%lu. Skipping key check", SLOT_ID); return CKR_OK; } rc = funcs->C_EncryptInit(session, &mech, h_key1); if (rc != CKR_OK) { testcase_notice("C_EncryptInit rc=%s", p11_get_ckr(rc)); goto error; } /** do encrypting **/ rc = funcs->C_Encrypt(session, data, sizeof(data), out, &out_len); if (rc != CKR_OK) { testcase_notice("C_Encrypt rc=%s", p11_get_ckr(rc)); goto error; } rc = funcs->C_DecryptInit(session, &mech, h_key2); if (rc != CKR_OK) { testcase_notice("C_DecryptInit rc=%s", p11_get_ckr(rc)); goto error; } /** do decrypt **/ rc = funcs->C_Decrypt(session, out, out_len, data, &out_len); if (rc != CKR_OK) { testcase_notice("C_Decrypt rc=%s", p11_get_ckr(rc)); goto error; } error: return rc; } /* * Perform a HMAC sign to verify that the key is usable. */ CK_RV run_HMACSign(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE h_key1, CK_OBJECT_HANDLE h_key2, CK_ULONG key_len) { CK_MECHANISM mech = { .mechanism = CKM_SHA_1_HMAC, .pParameter = NULL, .ulParameterLen = 0 }; CK_BYTE data[32] = { 0 }; CK_BYTE mac[SHA1_HASH_SIZE] = { 0 }; CK_ULONG mac_len = sizeof(mac); CK_RV rc = CKR_OK; if (!mech_supported(SLOT_ID, CKM_SHA_1_HMAC)) { testcase_notice("Mechanism CKM_SHA_1_HMAC is not supported with slot " "%lu. Skipping key check", SLOT_ID); return CKR_OK; } if (!check_supp_keysize(SLOT_ID, CKM_SHA_1_HMAC, key_len * 8)) { testcase_notice("Mechanism CKM_SHA_1_HMAC can not be used with keys " "of size %lu. Skipping key check", key_len); return CKR_OK; } rc = funcs->C_SignInit(session, &mech, h_key1); if (rc != CKR_OK) { testcase_notice("C_SignInit rc=%s", p11_get_ckr(rc)); goto error; } /** do signing **/ rc = funcs->C_Sign(session, data, sizeof(data), mac, &mac_len); if (rc != CKR_OK) { testcase_notice("C_Sign rc=%s", p11_get_ckr(rc)); goto error; } rc = funcs->C_VerifyInit(session, &mech, h_key2); if (rc != CKR_OK) { testcase_notice("C_VerifyInit rc=%s", p11_get_ckr(rc)); goto error; } /** do verify **/ rc = funcs->C_Verify(session, data, sizeof(data), mac, mac_len); if (rc != CKR_OK) { testcase_notice("C_Verify rc=%s", p11_get_ckr(rc)); goto error; } error: return rc; } CK_RV run_EnDecapsulateMLKEM(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE priv_key, CK_OBJECT_HANDLE publ_key, CK_KEY_TYPE key_type, CK_ULONG secret_key_len) { CK_MECHANISM mech; CK_BYTE *cipher = NULL; CK_ULONG cipher_len = 0; CK_OBJECT_HANDLE secret_key1 = CK_INVALID_HANDLE; CK_OBJECT_HANDLE secret_key2 = CK_INVALID_HANDLE; CK_RV rc; CK_OBJECT_CLASS class = CKO_SECRET_KEY; CK_BBOOL ck_true = CK_TRUE; CK_BBOOL ck_false = CK_FALSE; CK_ATTRIBUTE sym_key_tmpl[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &key_type, sizeof(key_type)}, {CKA_SENSITIVE, &ck_false, sizeof(ck_false)}, {CKA_VALUE_LEN, &secret_key_len, sizeof(secret_key_len)}, {CKA_SIGN, &ck_true, sizeof(ck_true)}, {CKA_VERIFY, &ck_true, sizeof(ck_true)}, }; CK_ULONG sym_key_tmpl_len = sizeof(sym_key_tmpl) / sizeof(CK_ATTRIBUTE); mech.mechanism = CKM_ML_KEM; mech.ulParameterLen = 0; mech.pParameter = NULL; /* Query the slot, check if this mech if supported */ if (!mech_supported(SLOT_ID, mech.mechanism)) { testcase_notice("Slot %u doesn't support %s", (unsigned int) SLOT_ID, p11_get_ckm(&mechtable_funcs, mech.mechanism)); rc = CKR_MECHANISM_INVALID; goto testcase_cleanup; } /* Perform encapsulation with public key */ /* Size query */ rc = funcs3_2->C_EncapsulateKey(session, &mech, publ_key, sym_key_tmpl, sym_key_tmpl_len, cipher, &cipher_len, NULL); if (rc != CKR_OK) { if (rc == CKR_KEY_TYPE_INCONSISTENT) { testcase_notice("Slot %u does not support en-/decapsulating " "keys of type 0x%lx", (unsigned int)SLOT_ID, key_type); goto testcase_cleanup; } testcase_error("C_EncapsulateKey (size query) rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } cipher = calloc(cipher_len, sizeof(CK_BYTE)); if (cipher == NULL) { testcase_error("Can't allocate memory for %lu bytes", sizeof(CK_BYTE) * cipher_len); rc = CKR_HOST_MEMORY; goto testcase_cleanup; } /* Encapsulation */ rc = funcs3_2->C_EncapsulateKey(session, &mech, publ_key, sym_key_tmpl, sym_key_tmpl_len, cipher, &cipher_len, &secret_key1); if (rc != CKR_OK) { testcase_error("C_EncapsulateKey rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } /* Perform Decapsulation with private key */ rc = funcs3_2->C_DecapsulateKey(session, &mech, priv_key, sym_key_tmpl, sym_key_tmpl_len, cipher, cipher_len, &secret_key2); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("Key size or form is not supported by slot %lu", SLOT_ID); goto testcase_cleanup; } testcase_error("C_DecapsulateKey rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } if (secret_key1 != CK_INVALID_HANDLE) { switch (key_type) { case CKK_AES: rc = run_AESCrypt(session, secret_key1, secret_key2); if (rc != CKR_OK) { testcase_fail("Derived keys are not usable or not the same: %s", p11_get_ckr(rc)); goto testcase_cleanup; } break; case CKK_GENERIC_SECRET: rc = run_HMACSign(session, secret_key1, secret_key2, secret_key_len); if (rc != CKR_OK) { testcase_fail("Derived keys are not usable or not the same: %s", p11_get_ckr(rc)); goto testcase_cleanup; } break; default: testcase_fail("Derived key type can not be tested"); rc = CKR_FUNCTION_FAILED; goto testcase_cleanup; } } rc = CKR_OK; testcase_cleanup: if (cipher != NULL) free(cipher); if (secret_key1 != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, secret_key1); if (secret_key2 != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, secret_key2); return rc; } CK_RV run_GenerateMLKEMKeyPairKEM(void) { 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_RV rc; testcase_rw_session(); testcase_user_login(); mech.mechanism = CKM_ML_KEM_KEY_PAIR_GEN; mech.ulParameterLen = 0; mech.pParameter = NULL; /* query the slot, check if this mech is supported */ if (!mech_supported(SLOT_ID, mech.mechanism)) { testcase_skip("Slot %u doesn't support %s", (unsigned int) SLOT_ID, p11_get_ckm(&mechtable_funcs, mech.mechanism)); rc = CKR_OK; goto testcase_cleanup; } for (i = 0; i < num_variants; i++) { /* Setup attributes for public/private ML-KEM key */ CK_BBOOL ck_true = TRUE; CK_ATTRIBUTE ml_kem_attr_private[] = { {CKA_DECAPSULATE, &ck_true, sizeof(CK_BBOOL)}, {CKA_PARAMETER_SET, (CK_BYTE *)&variants[i].parameter_set, sizeof(CK_ML_KEM_PARAMETER_SET_TYPE)}, }; CK_ATTRIBUTE ml_kem_attr_public[] = { {CKA_ENCAPSULATE, &ck_true, sizeof(CK_BBOOL)}, {CKA_PARAMETER_SET, (CK_BYTE *)&variants[i].parameter_set, sizeof(CK_ML_KEM_PARAMETER_SET_TYPE)}, }; CK_ULONG num_ml_kem_attrs = 2; testcase_begin("Starting ML-KEM generate key pair with %s.", variants[i].name); /* Generate ML-KEM key pair */ rc = funcs->C_GenerateKeyPair(session, &mech, ml_kem_attr_public, num_ml_kem_attrs, ml_kem_attr_private, num_ml_kem_attrs, &publ_key, &priv_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("C_GenerateKeyPair with %s not supported", variants[i].name); goto next; } else { testcase_new_assertion(); testcase_fail("C_GenerateKeyPair with %s failed, rc=%s", variants[i].name, p11_get_ckr(rc)); goto testcase_cleanup; } } testcase_new_assertion(); testcase_pass("Generate ML-KEM key pair with %s passed.", variants[i].name); for (j = 0; j < num_kem_inputs; j++) { rc = run_EnDecapsulateMLKEM(session, priv_key, publ_key, kemInput[j].secret_key_type, kemInput[j].secret_key_len); if (rc == CKR_MECHANISM_INVALID || rc == CKR_KEY_TYPE_INCONSISTENT) { testcase_skip("run_EnDecapsulateMLKEM with %s (index %lu).", variants[i].name, j); } else if (rc != 0) { testcase_new_assertion(); testcase_fail("run_EnDecapsulateMLKEM with %s (index %lu) " "failed.", variants[i].name, j); goto next; } else { testcase_new_assertion(); testcase_pass("Encapsulate & Decapsulate (KEM) with %s " "(index %lu) passed.", variants[i].name, j); } } next: if (publ_key != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, publ_key); publ_key = CK_INVALID_HANDLE; if (priv_key != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, priv_key); priv_key = CK_INVALID_HANDLE; } 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_ImportMLKEMKeyPairSignVerify(void) { 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_RV rc; testcase_rw_session(); testcase_user_login(); /* query the slot, check if this mech is supported */ if (!mech_supported(SLOT_ID, CKM_ML_KEM)) { testcase_skip("Slot %u doesn't support CKM_ML_KEM", (unsigned int) SLOT_ID); rc = CKR_OK; goto testcase_cleanup; } for (i = 0; i < ML_KEM_TV_NUM; i++) { testcase_begin("Starting ML-KEM import key pair, %s index=%lu", ml_kem_tv[i].name, i); /* Create ML-KEM private key */ rc = create_ML_KEM_PrivateKey(session, ml_kem_tv[i].parameter_set, ml_kem_tv[i].priv, ml_kem_tv[i].priv_len, ml_kem_tv[i].priv_seed, ml_kem_tv[i].priv_seed_len, &priv_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("C_CreateObject with %s not supported", ml_kem_tv[i].name); continue; } else if (rc == CKR_POLICY_VIOLATION) { testcase_skip("ML-KEM key import is not allowed by policy"); continue; } testcase_new_assertion(); testcase_fail("C_CreateObject (ML-KEM Private Key) failed at " "i=%lu, rc=%s", i, p11_get_ckr(rc)); goto testcase_cleanup; } testcase_new_assertion(); testcase_pass("*Import ML-KEM private key (%s) index=%lu passed.", ml_kem_tv[i].name, i); /* Create ML-KEM public key */ rc = create_ML_KEM_PublicKey(session, ml_kem_tv[i].parameter_set, ml_kem_tv[i].pub, ml_kem_tv[i].pub_len, &publ_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("C_CreateObject with %s not supported", ml_kem_tv[i].name); goto testcase_cleanup; } else if (rc == CKR_POLICY_VIOLATION) { testcase_skip("ML-KEM key import is not allowed by policy"); goto testcase_cleanup; } testcase_new_assertion(); testcase_fail("C_CreateObject (ML-KEM Public Key) failed at " "i=%lu, rc=%s", i, p11_get_ckr(rc)); goto testcase_cleanup; } testcase_new_assertion(); testcase_pass("*Import ML-KEM public key (%s) index=%lu passed.", ml_kem_tv[i].name, i); /* Test Encapsulate/decapsulate (KEM) */ rc = run_EnDecapsulateMLKEM(session, priv_key, publ_key, CKK_AES, 32); if (rc == CKR_MECHANISM_INVALID || rc == CKR_KEY_SIZE_RANGE) { testcase_skip("run_EnDecapsulateMLKEM index=%lu.", i); } else if (rc != 0) { testcase_new_assertion(); testcase_fail("run_EnDecapsulateMLKEM failed index=%lu.", i); goto testcase_cleanup; } else { testcase_new_assertion(); testcase_pass("*Encapsulate & Decapsulate (KEM), 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(tmp_len, sizeof(CK_BYTE)); 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_ML_KEM; CK_OBJECT_HANDLE tmp_key = CK_INVALID_HANDLE; CK_BYTE unwrap_label[] = "unwrapped_private_ML_KEM_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)}, {CKA_DECAPSULATE, &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_TransferMLKEMKeyPairSignVerify(void) { 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_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(); /* query the slot, check if this mech is supported */ if (!mech_supported(SLOT_ID, CKM_ML_KEM)) { testcase_skip("Slot %u doesn't support CKM_ML_KEM", (unsigned int) SLOT_ID); rc = CKR_OK; goto testcase_cleanup; } if (!mech_supported(SLOT_ID, CKM_AES_KEY_GEN)) { testcase_skip("Slot %u doesn't support CKM_AES_KEY_GEN", (unsigned int) SLOT_ID); rc = CKR_OK; goto testcase_cleanup; } if (!mech_supported_flags(SLOT_ID, CKM_AES_CBC_PAD, CKF_WRAP)) { testcase_skip("Slot %u doesn't support key wrapping with " "CKM_AES_CBC_PAD", (unsigned int) SLOT_ID); rc = CKR_OK; goto testcase_cleanup; } for (i = 0; i < ML_KEM_TV_NUM; i++) { testcase_begin("Starting ML-KEM transfer key pair, %s index=%lu.", ml_kem_tv[i].name, i); /* Create ML-KEM private key */ rc = create_ML_KEM_PrivateKey(session, ml_kem_tv[i].parameter_set, ml_kem_tv[i].priv, ml_kem_tv[i].priv_len, ml_kem_tv[i].priv_seed, ml_kem_tv[i].priv_seed_len, &priv_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("C_CreateObject with %s not supported", ml_kem_tv[i].name); continue; } else if (rc == CKR_POLICY_VIOLATION) { testcase_skip("ML-KEM key import is not allowed by policy"); continue; } testcase_new_assertion(); testcase_fail("C_CreateObject (ML-KEM Private Key) failed at " "i=%lu, rc=%s", i, p11_get_ckr(rc)); goto testcase_cleanup; } testcase_new_assertion(); testcase_pass("*Import I ML-KEM private key (%s) index=%lu passed.", ml_kem_tv[i].name, i); /* Create ML-KEM public key */ rc = create_ML_KEM_PublicKey(session, ml_kem_tv[i].parameter_set, ml_kem_tv[i].pub, ml_kem_tv[i].pub_len, &publ_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("C_CreateObject with %s not supported", ml_kem_tv[i].name); goto testcase_cleanup; } else if (rc == CKR_POLICY_VIOLATION) { testcase_skip("ML-KEM key import is not allowed by policy"); goto testcase_cleanup; } testcase_new_assertion(); testcase_fail("C_CreateObject (ML-KEM Public Key) failed at " "i=%lu,rc=%s", i, p11_get_ckr(rc)); goto testcase_cleanup; } testcase_new_assertion(); testcase_pass("*Import ML-KEM public key (%s) index=%lu passed.", ml_kem_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, CK_TRUE, &wkey_mech, &secret_key); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("AES key generation is not allowed by policy"); goto testcase_cleanup; } 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 ML-KEM 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 ML-KEM private key (%s) index=%lu passed.", ml_kem_tv[i].name, i); /* Unwrap ML-KEM private key */ rc = unwrapKey(session, &wrap_mech, wrapped_key, wrapped_keylen, secret_key, &unwrapped_key); testcase_new_assertion(); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("Key size or form is not supported by slot %lu", SLOT_ID); goto testcase_cleanup; } testcase_error("unwrapKey, rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } testcase_pass("*Unwrap ML-KEM private key (%s) index=%lu passed.", ml_kem_tv[i].name, i); free(wrapped_key); wrapped_key = NULL; /* Test Encapsulate/decapsulate (KEM) */ rc = run_EnDecapsulateMLKEM(session, unwrapped_key, publ_key, CKK_AES, 32); if (rc == CKR_MECHANISM_INVALID) { testcase_skip("run_EnDecapsulateMLKEM index=%lu.", i); } else if (rc != 0) { testcase_new_assertion(); testcase_fail("run_EnDecapsulateMLKEM failed index=%lu.", i); goto testcase_cleanup; } else { testcase_new_assertion(); testcase_pass("*Encapsulate & Decapsulate (KEM), 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(); rv = run_GenerateMLKEMKeyPairKEM(); rv |= run_ImportMLKEMKeyPairSignVerify(); rv |= run_TransferMLKEMKeyPairSignVerify(); testcase_print_result(); funcs->C_Finalize(NULL); return testcase_return(rv); } opencryptoki-opencryptoki-451d99c/testcases/crypto/rsa.h000066400000000000000000030516211520105705100236100ustar00rootroot00000000000000/* * 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 #include "pkcs11types.h" #define MAX_MODULUS_SIZE (OPENSSL_RSA_MAX_MODULUS_BITS / 8) #define MAX_EXPONENT_SIZE MAX_MODULUS_SIZE #define MAX_MESSAGE_SIZE MAX_MODULUS_SIZE #define MAX_SIGNATURE_SIZE MAX_MODULUS_SIZE #define MAX_PRIME_SIZE (MAX_MODULUS_SIZE / 2) #define MAX_COEFFICIENT_SIZE (MAX_MODULUS_SIZE / 2) #define PKCS11_MAX_KEY_LEN 512 #define MAX_CHUNKS 8 #define DES_IV_SIZE 8 #define AES_IV_SIZE 16 char aes_iv[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; unsigned char des_iv[] = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef }; 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; CK_MECHANISM keygen_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 = 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} }, { // #14 .modbits = 1024, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .inputlen = 28, .oaep_params = {CKM_SHA3_224, CKG_MGF1_SHA3_224, CKZ_DATA_SPECIFIED, NULL, 0}, .keylen = 24, .keytype = {CKM_AES_KEY_GEN, 0, 0} }, { // #15 .modbits = 2048, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .inputlen = 16, .oaep_params = {CKM_SHA3_224, CKG_MGF1_SHA3_224, CKZ_DATA_SPECIFIED, "abcdefghijkl", 12}, .keylen = 32, .keytype = {CKM_AES_KEY_GEN, 0, 0} }, { // #16 .modbits = 4096, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .inputlen = 36, .oaep_params = {CKM_SHA3_224, CKG_MGF1_SHA3_224, CKZ_DATA_SPECIFIED, "abcdefghijklmnopqrstuvwxyz", 26}, .keylen = 32, .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0} }, { // #17 .modbits = 1024, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .inputlen = 28, .oaep_params = {CKM_SHA3_256, CKG_MGF1_SHA3_256, CKZ_DATA_SPECIFIED, NULL, 0}, .keylen = 24, .keytype = {CKM_AES_KEY_GEN, 0, 0} }, { // #18 .modbits = 2048, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .inputlen = 16, .oaep_params = {CKM_SHA3_256, CKG_MGF1_SHA3_256, CKZ_DATA_SPECIFIED, "abcdefghijkl", 12}, .keylen = 32, .keytype = {CKM_AES_KEY_GEN, 0, 0} }, { // #19 .modbits = 4096, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .inputlen = 36, .oaep_params = {CKM_SHA3_256, CKG_MGF1_SHA3_256, CKZ_DATA_SPECIFIED, "abcdefghijklmnopqrstuvwxyz", 26}, .keylen = 32, .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0} }, { // #20 .modbits = 1024, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .inputlen = 28, .oaep_params = {CKM_SHA3_384, CKG_MGF1_SHA3_384, CKZ_DATA_SPECIFIED, NULL, 0}, .keylen = 24, .keytype = {CKM_DES3_KEY_GEN, 0, 0} }, { // #21 .modbits = 2048, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .inputlen = 16, .oaep_params = {CKM_SHA3_384, CKG_MGF1_SHA3_384, CKZ_DATA_SPECIFIED, "abcdefghijkl", 12}, .keylen = 16, .keytype = {CKM_AES_KEY_GEN, 0, 0} }, { // #22 .modbits = 4096, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .inputlen = 36, .oaep_params = {CKM_SHA3_384, CKG_MGF1_SHA3_384, CKZ_DATA_SPECIFIED, "abcdefghijklmnopqrstuvwxyz", 26}, .keylen = 24, .keytype = {CKM_AES_KEY_GEN, 0, 0} }, { // #23 .modbits = 2048, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .inputlen = 28, .oaep_params = {CKM_SHA3_512, CKG_MGF1_SHA3_512, CKZ_DATA_SPECIFIED, NULL, 0}, .keylen = 32, .keytype = {CKM_AES_KEY_GEN, 0, 0} }, { // #24 .modbits = 4096, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .inputlen = 36, .oaep_params = {CKM_SHA3_512, CKG_MGF1_SHA3_512, CKZ_DATA_SPECIFIED, "abcdefghijklmnopqrstuvwxyz", 26}, .keylen = 32, .keytype = {CKM_AES_KEY_GEN, 0, 0} }, { // #25 .modbits = 2048, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .inputlen = 36, .oaep_params = {CKM_SHA_1, CKG_MGF1_SHA1, CKZ_DATA_SPECIFIED, NULL, 0 }, .keylen = 24, .keytype = {CKM_AES_KEY_GEN, 0, 0} }, { // #26 .modbits = 2048, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .inputlen = 36, .oaep_params = {CKM_SHA_1, CKG_MGF1_SHA1, CKZ_DATA_SPECIFIED, NULL, 0 }, .keylen = 16, .keytype = {CKM_AES_KEY_GEN, 0, 0} }, { // #27 .modbits = 2048, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .inputlen = 36, .oaep_params = {CKM_SHA_1, CKG_MGF1_SHA1, CKZ_DATA_SPECIFIED, NULL, 0 }, .keylen = 32, .keytype = {CKM_AES_KEY_GEN, 0, 0} }, { // #28 .modbits = 8192, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .inputlen = 36, .oaep_params = {CKM_SHA256, CKG_MGF1_SHA256, CKZ_DATA_SPECIFIED, NULL, 0 }, .keylen = 32, .keytype = {CKM_AES_KEY_GEN, 0, 0} }, }; #define NUM_OF_GENERATED_OAEP_TESTSUITES 2 struct GENERATED_TEST_SUITE_INFO generated_oaep_test_suites[] = { { .name = "RSA PKCS OAEP", .tvcount = 29, .tv = rsa_oaep_generated_tv, .mech = {CKM_RSA_PKCS_OAEP, 0, 0}, .keygen_mech = {CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0}, }, { .name = "RSA AES KEY WRAP", .tvcount = 29, .tv = rsa_oaep_generated_tv, .mech = {CKM_RSA_AES_KEY_WRAP, 0, 0}, .keygen_mech = {CKM_RSA_PKCS_KEY_PAIR_GEN, 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} }, { // #15 .modbits = 8192, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .inputlen = 185, .pss_params = {CKM_SHA256, CKG_MGF1_SHA256, 32} } }; 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} }, { // #3 .modbits = 8192, .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} }, { // #3 .modbits = 8192, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .inputlen = 65, .chunks = {15, 30, 0, 20}, .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} }, { // #3 .modbits = 8192, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .inputlen = 65, .chunks = {15, 30, 0, 20}, .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} }, { // #3 .modbits = 8192, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .inputlen = 65, .chunks = {15, 30, 0, 20}, .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} }, { // #3 .modbits = 8192, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .inputlen = 65, .chunks = {15, 30, 0, 20}, .num_chunks = 4, .pss_params = {CKM_SHA512, CKG_MGF1_SHA512, 64} } }; struct RSA_GENERATED_TEST_VECTOR sha3_224_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_SHA3_224, CKG_MGF1_SHA3_224, 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_SHA3_224, CKG_MGF1_SHA3_224, 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_SHA3_224, CKG_MGF1_SHA3_224, 28} }, { // #3 .modbits = 8192, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .inputlen = 65, .chunks = {15, 30, 0, 20}, .num_chunks = 4, .pss_params = {CKM_SHA3_224, CKG_MGF1_SHA3_224, 28} } }; struct RSA_GENERATED_TEST_VECTOR sha3_256_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_SHA3_256, CKG_MGF1_SHA3_256, 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_SHA3_256, CKG_MGF1_SHA3_256, 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_SHA3_256, CKG_MGF1_SHA3_256, 32} }, { // #3 .modbits = 8192, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .inputlen = 65, .chunks = {15, 30, 0, 20}, .num_chunks = 4, .pss_params = {CKM_SHA3_256, CKG_MGF1_SHA3_256, 32} } }; struct RSA_GENERATED_TEST_VECTOR sha3_384_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_SHA3_384, CKG_MGF1_SHA3_384, 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_SHA3_384, CKG_MGF1_SHA3_384, 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_SHA3_384, CKG_MGF1_SHA3_384, 48} }, { // #3 .modbits = 8192, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .inputlen = 65, .chunks = {15, 30, 0, 20}, .num_chunks = 4, .pss_params = {CKM_SHA3_384, CKG_MGF1_SHA3_384, 48} } }; struct RSA_GENERATED_TEST_VECTOR sha3_512_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_SHA3_512, CKG_MGF1_SHA3_512, 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_SHA3_512, CKG_MGF1_SHA3_512, 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_SHA3_512, CKG_MGF1_SHA3_512, 64} }, { // #3 .modbits = 8192, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .inputlen = 65, .chunks = {15, 30, 0, 20}, .num_chunks = 4, .pss_params = {CKM_SHA3_512, CKG_MGF1_SHA3_512, 64} } }; #define NUM_OF_GENERATED_PSS_TESTSUITES 10 struct GENERATED_TEST_SUITE_INFO generated_pss_test_suites[] = { { .name = "RSA PKCS PSS", .tvcount = 16, .tv = rsa_pss_generated_tv, .mech = {CKM_RSA_PKCS_PSS, 0, 0}, .keygen_mech = {CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0}, }, { .name = "SHA1 RSA PKCS PSS", .tvcount = 4, .tv = sha1_rsa_pss_generated_tv, .mech = {CKM_SHA1_RSA_PKCS_PSS, 0, 0}, .keygen_mech = {CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0}, }, { .name = "SHA224 RSA PKCS PSS", .tvcount = 4, .tv = sha224_rsa_pss_generated_tv, .mech = {CKM_SHA224_RSA_PKCS_PSS, 0, 0}, .keygen_mech = {CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0}, }, { .name = "SHA256 RSA PKCS PSS", .tvcount = 4, .tv = sha256_rsa_pss_generated_tv, .mech = {CKM_SHA256_RSA_PKCS_PSS, 0, 0}, .keygen_mech = {CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0}, }, { .name = "SHA384 RSA PKCS PSS", .tvcount = 4, .tv = sha384_rsa_pss_generated_tv, .mech = {CKM_SHA384_RSA_PKCS_PSS, 0, 0}, .keygen_mech = {CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0}, }, { .name = "SHA512 RSA PKCS PSS", .tvcount = 4, .tv = sha512_rsa_pss_generated_tv, .mech = {CKM_SHA512_RSA_PKCS_PSS, 0, 0}, .keygen_mech = {CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0}, }, { .name = "SHA3-224 RSA PKCS PSS", .tvcount = 4, .tv = sha3_224_rsa_pss_generated_tv, .mech = {CKM_SHA3_224_RSA_PKCS_PSS, 0, 0}, .keygen_mech = {CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0}, }, { .name = "SHA3-256 RSA PKCS PSS", .tvcount = 4, .tv = sha3_256_rsa_pss_generated_tv, .mech = {CKM_SHA3_256_RSA_PKCS_PSS, 0, 0}, .keygen_mech = {CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0}, }, { .name = "SHA3-384 RSA PKCS PSS", .tvcount = 4, .tv = sha3_384_rsa_pss_generated_tv, .mech = {CKM_SHA3_384_RSA_PKCS_PSS, 0, 0}, .keygen_mech = {CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0}, }, { .name = "SHA3-512 RSA PKCS PSS", .tvcount = 4, .tv = sha3_512_rsa_pss_generated_tv, .mech = {CKM_SHA3_512_RSA_PKCS_PSS, 0, 0}, .keygen_mech = {CKM_RSA_PKCS_KEY_PAIR_GEN, 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 = 4, .tv = sha1_rsa_pss_generated_tv, .mech = {CKM_SHA1_RSA_PKCS_PSS, 0, 0}, .keygen_mech = {CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0}, }, { .name = "SHA224 RSA PKCS PSS", .tvcount = 4, .tv = sha224_rsa_pss_generated_tv, .mech = {CKM_SHA224_RSA_PKCS_PSS, 0, 0}, .keygen_mech = {CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0}, }, { .name = "SHA256 RSA PKCS PSS", .tvcount = 4, .tv = sha256_rsa_pss_generated_tv, .mech = {CKM_SHA256_RSA_PKCS_PSS, 0, 0}, .keygen_mech = {CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0}, }, { .name = "SHA384 RSA PKCS PSS", .tvcount = 4, .tv = sha384_rsa_pss_generated_tv, .mech = {CKM_SHA384_RSA_PKCS_PSS, 0, 0}, .keygen_mech = {CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0}, }, { .name = "SHA512 RSA PKCS PSS", .tvcount = 4, .tv = sha512_rsa_pss_generated_tv, .mech = {CKM_SHA512_RSA_PKCS_PSS, 0, 0}, .keygen_mech = {CKM_RSA_PKCS_KEY_PAIR_GEN, 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_DES_KEY_GEN, 0, 0}, }, { // 2 .modbits = 512, .publ_exp_len = 1, .publ_exp = {0x03}, .keylen = 24, .keytype = {CKM_DES3_KEY_GEN, 0, 0}, }, { // 3 .modbits = 512, .publ_exp_len = 1, .publ_exp = {0x03}, .keylen = 16, .keytype = {CKM_AES_KEY_GEN, 0, 0}, }, { // 4 .modbits = 512, .publ_exp_len = 1, .publ_exp = {0x03}, .keylen = 32, .keytype = {CKM_AES_KEY_GEN, 0, 0}, }, { // 5 .modbits = 512, .publ_exp_len = 2, .publ_exp = {0x00, 0x11}, .keylen = 32, .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, }, { // 6 .modbits = 512, .publ_exp_len = 2, .publ_exp = {0x00, 0x11}, .keylen = 8, .keytype = {CKM_DES_KEY_GEN, 0, 0}, }, { // 7 .modbits = 512, .publ_exp_len = 2, .publ_exp = {0x00, 0x11}, .keylen = 24, .keytype = {CKM_DES3_KEY_GEN, 0, 0}, }, { // 8 .modbits = 512, .publ_exp_len = 2, .publ_exp = {0x00, 0x11}, .keylen = 16, .keytype = {CKM_AES_KEY_GEN, 0, 0}, }, { // 9 .modbits = 512, .publ_exp_len = 2, .publ_exp = {0x00, 0x11}, .keylen = 32, .keytype = {CKM_AES_KEY_GEN, 0, 0}, }, { // 10 .modbits = 512, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .keylen = 10, .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, }, { // 11 .modbits = 512, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .keylen = 8, .keytype = {CKM_DES_KEY_GEN, 0, 0}, }, { // 12 .modbits = 512, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .keylen = 24, .keytype = {CKM_DES3_KEY_GEN, 0, 0}, }, { // 13 .modbits = 512, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .keylen = 16, .keytype = {CKM_AES_KEY_GEN, 0, 0}, }, { // 14 .modbits = 512, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .keylen = 32, .keytype = {CKM_AES_KEY_GEN, 0, 0}, }, { // 15 .modbits = 1024, .publ_exp_len = 1, .publ_exp = {0x03}, .keylen = 10, .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, }, { // 16 .modbits = 1024, .publ_exp_len = 1, .publ_exp = {0x03}, .keylen = 8, .keytype = {CKM_DES_KEY_GEN, 0, 0}, }, { // 17 .modbits = 1024, .publ_exp_len = 1, .publ_exp = {0x03}, .keylen = 24, .keytype = {CKM_DES3_KEY_GEN, 0, 0}, }, { // 18 .modbits = 1024, .publ_exp_len = 1, .publ_exp = {0x03}, .keylen = 16, .keytype = {CKM_AES_KEY_GEN, 0, 0}, }, { // 19 .modbits = 1024, .publ_exp_len = 1, .publ_exp = {0x03}, .keylen = 32, .keytype = {CKM_AES_KEY_GEN, 0, 0}, }, { // 20 .modbits = 1024, .publ_exp_len = 1, .publ_exp = {0x03}, .keylen = 96, .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, }, { // 21 .modbits = 1024, .publ_exp_len = 2, .publ_exp = {0x00, 0x11}, .keylen = 10, .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, }, { // 22 .modbits = 1024, .publ_exp_len = 2, .publ_exp = {0x00, 0x11}, .keylen = 8, .keytype = {CKM_DES_KEY_GEN, 0, 0}, }, { // 23 .modbits = 1024, .publ_exp_len = 2, .publ_exp = {0x00, 0x11}, .keylen = 24, .keytype = {CKM_DES3_KEY_GEN, 0, 0}, }, { // 24 .modbits = 1024, .publ_exp_len = 2, .publ_exp = {0x00, 0x11}, .keylen = 16, .keytype = {CKM_AES_KEY_GEN, 0, 0}, }, { // 25 .modbits = 1024, .publ_exp_len = 2, .publ_exp = {0x00, 0x11}, .keylen = 32, .keytype = {CKM_AES_KEY_GEN, 0, 0}, }, { // 26 .modbits = 1024, .publ_exp_len = 2, .publ_exp = {0x00, 0x11}, .keylen = 64, .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, }, { // 27 .modbits = 1024, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .keylen = 10, .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, }, { // 28 .modbits = 1024, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .keylen = 8, .keytype = {CKM_DES_KEY_GEN, 0, 0}, }, { // 29 .modbits = 1024, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .keylen = 24, .keytype = {CKM_DES3_KEY_GEN, 0, 0}, }, { // 30 .modbits = 1024, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .keylen = 16, .keytype = {CKM_AES_KEY_GEN, 0, 0}, }, { // 31 .modbits = 1024, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .keylen = 32, .keytype = {CKM_AES_KEY_GEN, 0, 0}, }, { // 32 .modbits = 1024, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .keylen = 32, .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, }, { // 33 .modbits = 2048, .publ_exp_len = 1, .publ_exp = {0x03}, .keylen = 10, .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, }, { // 34 .modbits = 2048, .publ_exp_len = 1, .publ_exp = {0x03}, .keylen = 8, .keytype = {CKM_DES_KEY_GEN, 0, 0}, }, { // 35 .modbits = 2048, .publ_exp_len = 1, .publ_exp = {0x03}, .keylen = 24, .keytype = {CKM_DES3_KEY_GEN, 0, 0}, }, { // 36 .modbits = 2048, .publ_exp_len = 1, .publ_exp = {0x03}, .keylen = 16, .keytype = {CKM_AES_KEY_GEN, 0, 0}, }, { // 37 .modbits = 2048, .publ_exp_len = 1, .publ_exp = {0x03}, .keylen = 32, .keytype = {CKM_AES_KEY_GEN, 0, 0}, }, { // 38 .modbits = 2048, .publ_exp_len = 1, .publ_exp = {0x03}, .keylen = 64, .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, }, { // 39 .modbits = 2048, .publ_exp_len = 2, .publ_exp = {0x00, 0x11}, .keylen = 10, .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, }, { // 40 .modbits = 2048, .publ_exp_len = 2, .publ_exp = {0x00, 0x11}, .keylen = 8, .keytype = {CKM_DES_KEY_GEN, 0, 0}, }, { // 41 .modbits = 2048, .publ_exp_len = 2, .publ_exp = {0x00, 0x11}, .keylen = 24, .keytype = {CKM_DES3_KEY_GEN, 0, 0}, }, { // 42 .modbits = 2048, .publ_exp_len = 2, .publ_exp = {0x00, 0x11}, .keylen = 16, .keytype = {CKM_AES_KEY_GEN, 0, 0}, }, { // 43 .modbits = 2048, .publ_exp_len = 2, .publ_exp = {0x00, 0x11}, .keylen = 32, .keytype = {CKM_AES_KEY_GEN, 0, 0}, }, { // 44 .modbits = 2048, .publ_exp_len = 2, .publ_exp = {0x00, 0x11}, .keylen = 128, .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, }, { // 45 .modbits = 2048, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .keylen = 10, .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, }, { // 46 .modbits = 2048, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .keylen = 8, .keytype = {CKM_DES_KEY_GEN, 0, 0}, }, { // 47 .modbits = 2048, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .keylen = 24, .keytype = {CKM_DES3_KEY_GEN, 0, 0}, }, { // 48 .modbits = 2048, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .keylen = 16, .keytype = {CKM_AES_KEY_GEN, 0, 0}, }, { // 49 .modbits = 2048, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .keylen = 32, .keytype = {CKM_AES_KEY_GEN, 0, 0}, }, { // 50 .modbits = 4096, .publ_exp_len = 1, .publ_exp = {0x03}, .keylen = 10, .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, }, { // 51 .modbits = 4096, .publ_exp_len = 1, .publ_exp = {0x03}, .keylen = 8, .keytype = {CKM_DES_KEY_GEN, 0, 0}, }, { // 52 .modbits = 4096, .publ_exp_len = 1, .publ_exp = {0x03}, .keylen = 24, .keytype = {CKM_DES3_KEY_GEN, 0, 0}, }, { // 53 .modbits = 4096, .publ_exp_len = 1, .publ_exp = {0x03}, .keylen = 16, .keytype = {CKM_AES_KEY_GEN, 0, 0}, }, { // 54 .modbits = 4096, .publ_exp_len = 1, .publ_exp = {0x03}, .keylen = 32, .keytype = {CKM_AES_KEY_GEN, 0, 0}, }, { // 55 .modbits = 4096, .publ_exp_len = 2, .publ_exp = {0x00, 0x11}, .keylen = 10, .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, }, { // 56 .modbits = 4096, .publ_exp_len = 2, .publ_exp = {0x00, 0x11}, .keylen = 8, .keytype = {CKM_DES_KEY_GEN, 0, 0}, }, { // 57 .modbits = 4096, .publ_exp_len = 2, .publ_exp = {0x00, 0x11}, .keylen = 24, .keytype = {CKM_DES3_KEY_GEN, 0, 0}, }, { // 58 .modbits = 4096, .publ_exp_len = 2, .publ_exp = {0x00, 0x11}, .keylen = 16, .keytype = {CKM_AES_KEY_GEN, 0, 0}, }, { // 59 .modbits = 4096, .publ_exp_len = 2, .publ_exp = {0x00, 0x11}, .keylen = 32, .keytype = {CKM_AES_KEY_GEN, 0, 0}, }, { // 60 .modbits = 4096, .publ_exp_len = 2, .publ_exp = {0x00, 0x11}, .keylen = 256, .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, }, { // 61 .modbits = 4096, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .keylen = 10, .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, }, { // 62 .modbits = 4096, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .keylen = 8, .keytype = {CKM_DES_KEY_GEN, 0, 0}, }, { // 63 .modbits = 4096, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .keylen = 24, .keytype = {CKM_DES3_KEY_GEN, 0, 0}, }, { // 64 .modbits = 4096, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .keylen = 16, .keytype = {CKM_AES_KEY_GEN, 0, 0}, }, { // 65 .modbits = 4096, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .keylen = 32, .keytype = {CKM_AES_KEY_GEN, 0, 0}, }, { // 66 .modbits = 4096, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .keylen = 256, .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, }, { // 67 .modbits = 1024, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .keylen = 32, .keytype = {CKM_AES_XTS_KEY_GEN, 0, 0}, }, { // 68 .modbits = 1024, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .keylen = 64, .keytype = {CKM_AES_XTS_KEY_GEN, 0, 0}, }, { // 69 .modbits = 2048, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .keylen = 32, .keytype = {CKM_AES_XTS_KEY_GEN, 0, 0}, }, { // 70 .modbits = 2048, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .keylen = 64, .keytype = {CKM_AES_XTS_KEY_GEN, 0, 0}, }, { // 71 .modbits = 4096, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .keylen = 32, .keytype = {CKM_AES_XTS_KEY_GEN, 0, 0}, }, { // 72 .modbits = 4096, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .keylen = 64, .keytype = {CKM_AES_XTS_KEY_GEN, 0, 0}, }, { // 73 .modbits = 8192, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .keylen = 32, .keytype = {CKM_AES_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 = 1024, .publ_exp_len = 1, .publ_exp = {0x03}, .inputlen = 1, }, { //tv[7] .modbits = 1024, .publ_exp_len = 1, .publ_exp = {0x03}, .inputlen = 117, .chunks = {30, 17, 30, 0, 30, 10}, .num_chunks = 6, }, { //tv[8] .modbits = 1024, .publ_exp_len = 2, .publ_exp = {0x00, 0x11}, .inputlen = 1, }, { //tv[9] .modbits = 1024, .publ_exp_len = 2, .publ_exp = {0x00, 0x11}, .inputlen = 117, .chunks = {30, 17, 30, 0, 30, 10}, .num_chunks = 6, }, { //tv[10] .modbits = 1024, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .inputlen = 1, }, { //tv[11] .modbits = 1024, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .inputlen = 117, .chunks = {30, 17, 30, 0, 30, 10}, .num_chunks = 6, }, { //tv[12] .modbits = 2048, .publ_exp_len = 1, .publ_exp = {0x03}, .inputlen = 1, }, { //tv[13] .modbits = 2048, .publ_exp_len = 1, .publ_exp = {0x03}, .inputlen = 245, .chunks = {100, 145}, .num_chunks = 2 }, { //tv[14] .modbits = 2048, .publ_exp_len = 2, .publ_exp = {0x00, 0x11}, .inputlen = 1, }, { //tv[15] .modbits = 2048, .publ_exp_len = 2, .publ_exp = {0x00, 0x11}, .inputlen = 245, .chunks = {100, 145}, .num_chunks = 2 }, { //tv[16] .modbits = 2048, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .inputlen = 1, }, { //tv[17] .modbits = 2048, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .inputlen = 245, .chunks = {100, 145}, .num_chunks = 2 }, { //tv[18] .modbits = 4096, .publ_exp_len = 1, .publ_exp = {0x03}, .inputlen = 1, }, { //tv[19] .modbits = 4096, .publ_exp_len = 1, .publ_exp = {0x03}, .inputlen = 501, .chunks = {125, 125, 125, 125, 1}, .num_chunks = 5, }, { //tv[20] .modbits = 4096, .publ_exp_len = 2, .publ_exp = {0x00, 0x11}, .inputlen = 1, }, { //tv[21] .modbits = 4096, .publ_exp_len = 2, .publ_exp = {0x00, 0x11}, .inputlen = 501, .chunks = {125, 125, 125, 125, 1}, .num_chunks = 5, }, { //tv[22] .modbits = 4096, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .inputlen = 1, }, { //tv[23] .modbits = 4096, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .inputlen = 501, .chunks = {125, 125, 125, 125, 1}, .num_chunks = 5, }, { //tv[24] .modbits = 8192, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .inputlen = 1, }, { //tv[25] .modbits = 8192, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .inputlen = 501, .chunks = {125, 125, 125, 125, 1}, .num_chunks = 5, }, { //tv[26] .modbits = 512, .publ_exp_len = 3, .publ_exp = {0x03, 0x00, 0x01}, .inputlen = 0, .num_chunks = 0, }, { //tv[27] .modbits = 1024, .publ_exp_len = 3, .publ_exp = {0x03, 0x00, 0x01}, .inputlen = 0, .num_chunks = 0, }, { //tv[28] .modbits = 2048, .publ_exp_len = 3, .publ_exp = {0x03, 0x00, 0x01}, .inputlen = 0, .num_chunks = 0, }, { //tv[29] .modbits = 4096, .publ_exp_len = 3, .publ_exp = {0x03, 0x00, 0x01}, .inputlen = 0, .num_chunks = 0, }, }; 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 = 1024, .publ_exp_len = 1, .publ_exp = {0x03}, .inputlen = 1 }, { // tv[7] .modbits = 1024, .publ_exp_len = 1, .publ_exp = {0x03}, .inputlen = 128, }, { // tv[8] .modbits = 1024, .publ_exp_len = 2, .publ_exp = {0x00, 0x11}, .inputlen = 1, }, { // tv[9] .modbits = 1024, .publ_exp_len = 2, .publ_exp = {0x00, 0x11}, .inputlen = 128, }, { // tv[10] .modbits = 1024, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .inputlen = 1 }, { // tv[11] .modbits = 1024, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .inputlen = 128, }, { // tv[12] .modbits = 2048, .publ_exp_len = 1, .publ_exp = {0x03}, .inputlen = 1 }, { // tv[13] .modbits = 2048, .publ_exp_len = 1, .publ_exp = {0x03}, .inputlen = 256, }, { // tv[14] .modbits = 2048, .publ_exp_len = 2, .publ_exp = {0x00, 0x11}, .inputlen = 1, }, { // tv[15] .modbits = 2048, .publ_exp_len = 2, .publ_exp = {0x00, 0x11}, .inputlen = 256, }, { // tv[16] .modbits = 2048, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .inputlen = 1 }, { // tv[17] .modbits = 2048, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .inputlen = 256, }, { // tv[18] .modbits = 4096, .publ_exp_len = 1, .publ_exp = {0x03}, .inputlen = 1 }, { // tv[19] .modbits = 4096, .publ_exp_len = 1, .publ_exp = {0x03}, .inputlen = 512, }, { // tv[20] .modbits = 4096, .publ_exp_len = 2, .publ_exp = {0x00, 0x11}, .inputlen = 1, }, { // tv[21] .modbits = 4096, .publ_exp_len = 2, .publ_exp = {0x00, 0x11}, .inputlen = 512, }, { // tv[22] .modbits = 4096, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .inputlen = 1 }, { // tv[23] .modbits = 4096, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .inputlen = 512, }, { //tv[24] .modbits = 8192, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .inputlen = 1, }, { //tv[25] .modbits = 8192, .publ_exp_len = 3, .publ_exp = {0x01, 0x00, 0x01}, .inputlen = 501, .chunks = {125, 125, 125, 125, 1}, .num_chunks = 5, }, { //tv[26] .modbits = 512, .publ_exp_len = 3, .publ_exp = {0x03, 0x00, 0x01}, .inputlen = 0, }, { //tv[27] .modbits = 1024, .publ_exp_len = 3, .publ_exp = {0x03, 0x00, 0x01}, .inputlen = 0, }, { //tv[28] .modbits = 2048, .publ_exp_len = 3, .publ_exp = {0x03, 0x00, 0x01}, .inputlen = 0, }, { //tv[29] .modbits = 4096, .publ_exp_len = 3, .publ_exp = {0x03, 0x00, 0x01}, .inputlen = 0, }, }; #define NUM_OF_GENERATED_KEYWRAP_TESTSUITES 2 struct GENERATED_TEST_SUITE_INFO generated_keywrap_test_suites[] = { { .name = "RSA PKCS", .tvcount = 74, .tv = rsa_keywrap_generated_tv, .mech = {CKM_RSA_PKCS, 0, 0}, .keygen_mech = {CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0}, }, { .name = "RSA X.509", .tvcount = 74, .tv = rsa_keywrap_generated_tv, .mech = {CKM_RSA_X_509, 0, 0}, .keygen_mech = {CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0}, } }; #define NUM_OF_GENERATED_SIGVER_TESTSUITES 13 struct GENERATED_TEST_SUITE_INFO generated_sigver_test_suites[] = { { .name = "RSA PKCS", .tvcount = 30, .tv = rsa_generated_tv, .mech = {CKM_RSA_PKCS, 0, 0}, .keygen_mech = {CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0}, }, { .name = "RSA SHA1 PKCS", .tvcount = 30, .tv = rsa_generated_tv, .mech = {CKM_SHA1_RSA_PKCS, 0, 0}, .keygen_mech = {CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0}, }, { .name = "RSA SHA224 PKCS", .tvcount = 30, .tv = rsa_generated_tv, .mech = {CKM_SHA224_RSA_PKCS, 0, 0}, .keygen_mech = {CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0}, }, { .name = "RSA SHA256 PKCS", .tvcount = 30, .tv = rsa_generated_tv, .mech = {CKM_SHA256_RSA_PKCS, 0, 0}, .keygen_mech = {CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0}, }, { .name = "RSA SHA384 PKCS", .tvcount = 30, .tv = rsa_generated_tv, .mech = {CKM_SHA384_RSA_PKCS, 0, 0}, .keygen_mech = {CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0}, }, { .name = "RSA SHA512 PKCS", .tvcount = 30, .tv = rsa_generated_tv, .mech = {CKM_SHA512_RSA_PKCS, 0, 0}, .keygen_mech = {CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0}, }, { .name = "RSA SHA3-224 PKCS", .tvcount = 30, .tv = rsa_generated_tv, .mech = {CKM_SHA3_224_RSA_PKCS, 0, 0}, .keygen_mech = {CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0}, }, { .name = "RSA SHA3-256 PKCS", .tvcount = 30, .tv = rsa_generated_tv, .mech = {CKM_SHA3_256_RSA_PKCS, 0, 0}, .keygen_mech = {CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0}, }, { .name = "RSA SHA3-384 PKCS", .tvcount = 30, .tv = rsa_generated_tv, .mech = {CKM_SHA3_384_RSA_PKCS, 0, 0}, .keygen_mech = {CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0}, }, { .name = "RSA SHA3-512 PKCS", .tvcount = 30, .tv = rsa_generated_tv, .mech = {CKM_SHA3_512_RSA_PKCS, 0, 0}, .keygen_mech = {CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0}, }, { .name = "RSA MD2 PKCS", .tvcount = 30, .tv = rsa_generated_tv, .mech = {CKM_MD2_RSA_PKCS, 0, 0}, .keygen_mech = {CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0}, }, { .name = "RSA MD5 PKCS", .tvcount = 30, .tv = rsa_generated_tv, .mech = {CKM_MD5_RSA_PKCS, 0, 0}, .keygen_mech = {CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0}, }, { .name = "RSA X.509", .tvcount = 30, .tv = rsa_x509_generated_tv, .mech = {CKM_RSA_X_509, 0, 0}, .keygen_mech = {CKM_RSA_PKCS_KEY_PAIR_GEN, 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}, .keygen_mech = {CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0}, }, { .name = "RSA SHA224 PKCS", .tvcount = 30, .tv = rsa_generated_tv, .mech = {CKM_SHA224_RSA_PKCS, 0, 0}, .keygen_mech = {CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0}, }, { .name = "RSA SHA256 PKCS", .tvcount = 30, .tv = rsa_generated_tv, .mech = {CKM_SHA256_RSA_PKCS, 0, 0}, .keygen_mech = {CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0}, }, { .name = "RSA MD2 PKCS", .tvcount = 30, .tv = rsa_generated_tv, .mech = {CKM_MD2_RSA_PKCS, 0, 0}, .keygen_mech = {CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0}, }, { .name = "RSA MD5 PKCS", .tvcount = 30, .tv = rsa_generated_tv, .mech = {CKM_MD5_RSA_PKCS, 0, 0}, .keygen_mech = {CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0}, } }; #define NUM_OF_GENERATED_CRYPTO_TESTSUITES 3 struct GENERATED_TEST_SUITE_INFO generated_crypto_test_suites[] = { { .name = "RSA PKCS", .tvcount = 30 - 4, /* Last 4: zero bytes data, not poss. for encrypt */ .tv = rsa_generated_tv, .mech = {CKM_RSA_PKCS, 0, 0}, .keygen_mech = {CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0}, }, { .name = "RSA X.509", .tvcount = 30 - 4, /* Last 4: zero bytes data, not poss. for encrypt */ .tv = rsa_x509_generated_tv, .mech = {CKM_RSA_X_509, 0, 0}, .keygen_mech = {CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0}, }, { .name = "RSA PKCS (X9.31 KeyGen)", .tvcount = 30 - 4, /* Last 4: zero bytes data, not poss. for encrypt */ .tv = rsa_generated_tv, .mech = {CKM_RSA_PKCS, 0, 0}, .keygen_mech = {CKM_RSA_X9_31_KEY_PAIR_GEN, 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, }, { // 45 (p */ #include #include #include #include #include "pkcs11types.h" #include "common.c" #include "regress.h" #include "mechtable.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_flags(slot_id, tsuite->mech.mechanism, CKF_ENCRYPT | CKF_DECRYPT)) { testsuite_skip(tsuite->tvcount, "Slot %u doesn't support %s (0x%x)", (unsigned int) slot_id, mech_to_str(tsuite->mech.mechanism), (unsigned int) tsuite->mech.mechanism); goto testcase_cleanup; } if (!mech_supported(slot_id, tsuite->keygen_mech.mechanism)) { testsuite_skip(tsuite->tvcount, "Slot %u doesn't support %s (0x%x)", (unsigned int) slot_id, mech_to_str(tsuite->keygen_mech.mechanism), (unsigned int) tsuite->keygen_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 %u." "\npubl_exp='%s', modbits=%lu, publ_exp_len=%lu, " "inputlen=%lu.", tsuite->name, i, s, tsuite->tv[i].modbits, tsuite->tv[i].publ_exp_len, tsuite->tv[i].inputlen); rc = CKR_OK; // set rc if (tsuite->tv[i].modbits > 4096 && !rsa8k) { testcase_skip("Tests with modbits='%lu' are not enabled", tsuite->tv[i].modbits); free(s); continue; } if (!keysize_supported(slot_id, tsuite->mech.mechanism, tsuite->tv[i].modbits)) { testcase_skip("Token in slot %lu cannot be used with modbits='%lu'", SLOT_ID, tsuite->tv[i].modbits); free(s); 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); free(s); continue; } } // cca special cases: // cca token can only use a few public exponents // 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); free(s); continue; } if (tsuite->mech.mechanism == CKM_RSA_PKCS_OAEP && tsuite->tv[i].oaep_params.hashAlg != CKM_SHA_1 && tsuite->tv[i].oaep_params.hashAlg != CKM_SHA224 && tsuite->tv[i].oaep_params.hashAlg != CKM_SHA256 && tsuite->tv[i].oaep_params.hashAlg != CKM_SHA384 && tsuite->tv[i].oaep_params.hashAlg != CKM_SHA512) { testcase_skip("CCA Token cannot use RSA OAEP with a hash " "algorithm other than SHA1 and SHA2: %s", mech_to_str(tsuite->tv[i].oaep_params.hashAlg)); free(s); continue; } if (tsuite->mech.mechanism == CKM_RSA_PKCS_OAEP && tsuite->tv[i].oaep_params.source == CKZ_DATA_SPECIFIED && tsuite->tv[i].oaep_params.ulSourceDataLen > 0) { testcase_skip("CCA Token cannot use RSA OAEP with non empty " "source data"); free(s); continue; } } if (is_soft_token(slot_id)) { if (!is_valid_soft_pubexp(tsuite->tv[i].publ_exp, tsuite->tv[i].publ_exp_len)) { testcase_skip("Soft Token cannot be used with publ_exp.='%s'", s); free(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); free(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); free(s); continue; } } if (tsuite->mech.mechanism == CKM_RSA_PKCS_OAEP) { if (!mech_supported(slot_id, tsuite->tv[i].oaep_params.hashAlg)) { testcase_skip("Slot %u doesn't support OAEP hash alg %s (0x%x)", (unsigned int)slot_id, mech_to_str(tsuite->tv[i].oaep_params.hashAlg), (unsigned int)tsuite->tv[i].oaep_params.hashAlg); free(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_cached(session, tsuite->keygen_mech.mechanism, tsuite->tv[i].modbits, tsuite->tv[i].publ_exp, tsuite->tv[i].publ_exp_len, &publ_key, &priv_key); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("RSA key generation is not allowed by policy"); continue; } if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("RSA key size is not in supported range"); continue; } testcase_error("generate_RSA_PKCS_KeyPair_cached(), " "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"); continue; } if (rc == CKR_MECHANISM_PARAM_INVALID && mech.mechanism == CKM_RSA_PKCS_OAEP && is_cca_token(slot_id) && ((oaep_params.hashAlg != CKM_SHA_1 && oaep_params.hashAlg != CKM_SHA256) || (oaep_params.mgf != CKG_MGF1_SHA1 && oaep_params.mgf != CKG_MGF1_SHA256))) { testcase_skip("CCA Token does only support RSA OAEP with hash " "and/or MGF other than SHA-1/SHA256 with " "CCA 8.1 or later"); continue; } testcase_error("C_EncryptInit, rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } // do (public key) encryption rc = funcs->C_Encrypt(session, original, original_len, crypt, &crypt_len); if (rc != CKR_OK) { if (rc == CKR_MECHANISM_PARAM_INVALID && mech.mechanism == CKM_RSA_PKCS_OAEP && is_cca_token(slot_id) && ((oaep_params.hashAlg != CKM_SHA_1 && oaep_params.hashAlg != CKM_SHA256) || (oaep_params.mgf != CKG_MGF1_SHA1 && oaep_params.mgf != CKG_MGF1_SHA256))) { testcase_skip("CCA Token does only support RSA OAEP with hash " "and/or MGF other than SHA-1/SHA256 with " "CCA 8.1 or later"); continue; } testcase_error("C_Encrypt, rc=%s", p11_get_ckr(rc)); goto testcase_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 testcase_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 testcase_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 = %lu," "but found length=%lu.\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."); } } goto testcase_cleanup; testcase_cleanup: free_rsa_key_cache(session); 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, CK_BBOOL me_only) { 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 = CK_INVALID_HANDLE, priv_key = CK_INVALID_HANDLE; 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%s.", tsuite->name, me_only ? " (ME-format)" : ""); 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 (0x%x)", (unsigned int) slot_id, mech_to_str(tsuite->mech.mechanism), (unsigned int) tsuite->mech.mechanism); goto testcase_cleanup; } if (is_cca_token(slot_id) && tsuite->mech.mechanism == CKM_RSA_PKCS_OAEP) { if (((CK_RSA_PKCS_OAEP_PARAMS *)tsuite->mech.pParameter)->hashAlg != CKM_SHA_1 && ((CK_RSA_PKCS_OAEP_PARAMS *)tsuite->mech.pParameter)->hashAlg != CKM_SHA224 && ((CK_RSA_PKCS_OAEP_PARAMS *)tsuite->mech.pParameter)->hashAlg != CKM_SHA256 && ((CK_RSA_PKCS_OAEP_PARAMS *)tsuite->mech.pParameter)->hashAlg != CKM_SHA384 && ((CK_RSA_PKCS_OAEP_PARAMS *)tsuite->mech.pParameter)->hashAlg != CKM_SHA512) { testcase_skip("CCA Token cannot use RSA OAEP with a hash " "algorithm other than SHA1 and SHA2: %s", mech_to_str(((CK_RSA_PKCS_OAEP_PARAMS *) tsuite->mech.pParameter)->hashAlg)); goto testcase_cleanup; } if (((CK_RSA_PKCS_OAEP_PARAMS *)tsuite->mech.pParameter)->source == CKZ_DATA_SPECIFIED && ((CK_RSA_PKCS_OAEP_PARAMS *)tsuite->mech.pParameter)->ulSourceDataLen > 0) { testcase_skip("CCA Token cannot use RSA OAEP with non empty " "source data"); 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 %u%s." "\npubl_exp='%s', modbits=%lu, publ_exp_len=%lu.", tsuite->name, i, me_only ? " (ME-format)" : "", s, tsuite->tv[i].mod_len * 8, tsuite->tv[i].pubexp_len); rc = CKR_OK; // set rc if (tsuite->tv[i].mod_len * 8 > 4096 && !rsa8k) { testcase_skip("Tests with modbits='%lu' are not enabled", tsuite->tv[i].mod_len * 8); free(s); continue; } if (!keysize_supported(slot_id, tsuite->mech.mechanism, tsuite->tv[i].mod_len * 8)) { testcase_skip("Token in slot %lu cannot be used with modbits='%lu'", SLOT_ID, tsuite->tv[i].mod_len * 8); free(s); continue; } if (tsuite->mech.mechanism == CKM_RSA_PKCS_OAEP && ((CK_RSA_PKCS_OAEP_PARAMS *)tsuite->mech.pParameter)->hashAlg == CKM_SHA512 && tsuite->tv[i].mod_len * 8 <= 1024) { testcase_skip("OAEP with SHA512 cannot be used with modbits='%lu'", tsuite->tv[i].mod_len * 8); free(s); continue; } if (is_ep11_token(slot_id) || is_icsf_token(slot_id)) { if (!is_valid_ep11_pubexp(tsuite->tv[i].pub_exp, tsuite->tv[i].pubexp_len)) { testcase_skip("EP11/ICSF Token cannot be used with publ_exp.='%s'", s); free(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/ICSF Token cannot be used with this test vector."); free(s); 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."); free(s); continue; } } // cca special cases: // cca token can only use a few public exponents // 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); free(s); continue; } } if (is_soft_token(slot_id)) { if (!is_valid_soft_pubexp(tsuite->tv[i].pub_exp, tsuite->tv[i].pubexp_len)) { testcase_skip("Soft Token cannot be used with publ_exp.='%s'", s); free(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); free(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); free(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, me_only ? NULL : tsuite->tv[i].prime1, me_only ? NULL : tsuite->tv[i].prime2, me_only ? NULL : tsuite->tv[i].exp1, me_only ? NULL : tsuite->tv[i].exp2, me_only ? NULL : tsuite->tv[i].coef, tsuite->tv[i].mod_len, tsuite->tv[i].pubexp_len, tsuite->tv[i].privexp_len, me_only ? 0 : tsuite->tv[i].prime1_len, me_only ? 0 : tsuite->tv[i].prime2_len, me_only ? 0 : tsuite->tv[i].exp1_len, me_only ? 0 : tsuite->tv[i].exp2_len, me_only ? 0 : tsuite->tv[i].coef_len, &priv_key); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("RSA key import is not allowed by policy"); continue; } if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("RSA key size is not in supported range"); continue; } 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) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("RSA key import is not allowed by policy"); funcs->C_DestroyObject(session, priv_key); continue; } if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("RSA key size is not in supported range"); continue; } 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; } if (rc == CKR_MECHANISM_PARAM_INVALID && mech.mechanism == CKM_RSA_PKCS_OAEP && is_cca_token(slot_id) && ((((CK_RSA_PKCS_OAEP_PARAMS *)mech.pParameter)->hashAlg != CKM_SHA_1 && ((CK_RSA_PKCS_OAEP_PARAMS *)mech.pParameter)->hashAlg != CKM_SHA256) || (((CK_RSA_PKCS_OAEP_PARAMS *)mech.pParameter)->mgf != CKG_MGF1_SHA1 && ((CK_RSA_PKCS_OAEP_PARAMS *)mech.pParameter)->mgf != CKG_MGF1_SHA256))) { testcase_skip("CCA Token does only support RSA OAEP with hash " "and/or MGF other than SHA-1/SHA256 with " "CCA 8.1 or later"); 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) { if (rc == CKR_MECHANISM_PARAM_INVALID && mech.mechanism == CKM_RSA_PKCS_OAEP && is_cca_token(slot_id) && ((((CK_RSA_PKCS_OAEP_PARAMS *)mech.pParameter)->hashAlg != CKM_SHA_1 && ((CK_RSA_PKCS_OAEP_PARAMS *)mech.pParameter)->hashAlg != CKM_SHA256) || (((CK_RSA_PKCS_OAEP_PARAMS *)mech.pParameter)->mgf != CKG_MGF1_SHA1 && ((CK_RSA_PKCS_OAEP_PARAMS *)mech.pParameter)->mgf != CKG_MGF1_SHA256))) { testcase_skip("CCA Token does only support RSA OAEP with hash " "and/or MGF other than SHA-1/SHA256 with " "CCA 8.1 or later"); goto tv_cleanup; } else if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("RSA key size is not in supported range"); continue; } 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 = %lu," "but found length=%lu.\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%s.", me_only ? " (ME-format)" : ""); } // 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; 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 (0x%x)", (unsigned int) slot_id, mech_to_str(tsuite->mech.mechanism), (unsigned int) tsuite->mech.mechanism); goto testcase_cleanup; } if (!mech_supported(slot_id, tsuite->keygen_mech.mechanism)) { testsuite_skip(tsuite->tvcount, "Slot %u doesn't support %s (0x%x)", (unsigned int) slot_id, mech_to_str(tsuite->keygen_mech.mechanism), (unsigned int) tsuite->keygen_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 (0x%x)", (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 %u, " "\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 (tsuite->tv[i].modbits > 4096 && !rsa8k) { testcase_skip("Tests with modbits='%lu' are not enabled", tsuite->tv[i].modbits); free(s); continue; } if (!keysize_supported(slot_id, tsuite->mech.mechanism, tsuite->tv[i].modbits)) { testcase_skip("Token in slot %lu cannot be used with modbits='%lu'", SLOT_ID, tsuite->tv[i].modbits); free(s); 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); free(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); free(s); continue; } } if (is_soft_token(slot_id)) { if (!is_valid_soft_pubexp(tsuite->tv[i].publ_exp, tsuite->tv[i].publ_exp_len)) { testcase_skip("Soft Token cannot be used with publ_exp='%s'.", s); free(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); free(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); free(s); continue; } } if (tsuite->tv[i].modbits <= 512 && (tsuite->mech.mechanism == CKM_SHA384_RSA_PKCS || tsuite->mech.mechanism == CKM_SHA512_RSA_PKCS || tsuite->mech.mechanism == CKM_SHA3_384_RSA_PKCS || tsuite->mech.mechanism == CKM_SHA3_512_RSA_PKCS)) { testcase_skip("Mechanism %s can not be used with a key with mod_bits='%lu'.", mech_to_str(tsuite->mech.mechanism), tsuite->tv[i].modbits); free(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_cached(session, tsuite->keygen_mech.mechanism, tsuite->tv[i].modbits, tsuite->tv[i].publ_exp, tsuite->tv[i].publ_exp_len, &publ_key, &priv_key); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("RSA key generation is not allowed by policy"); continue; } if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("RSA key size is not in supported range"); continue; } testcase_error("generate_RSA_PKCS_KeyPair_cached(), " "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 testcase_cleanup; } // 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=%lu", recover_mode ? "Recover" : "", p11_get_ckr(rc), signature_len); goto testcase_cleanup; } // 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 testcase_cleanup; } // 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)); } } testcase_cleanup: free_rsa_key_cache(session); 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; 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 (0x%x)", (unsigned int) slot_id, mech_to_str(tsuite->mech.mechanism), (unsigned int) tsuite->mech.mechanism); goto testcase_cleanup; } if (!mech_supported(slot_id, tsuite->keygen_mech.mechanism)) { testsuite_skip(tsuite->tvcount, "Slot %u doesn't support %s (0x%x)", (unsigned int) slot_id, mech_to_str(tsuite->keygen_mech.mechanism), (unsigned int) tsuite->keygen_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 %u, " "\npubl_exp='%s', mod_bits='%lu', keylen='%lu'.", tsuite->name, i, s, tsuite->tv[i].modbits, tsuite->tv[i].keylen); if (tsuite->tv[i].modbits > 4096 && !rsa8k) { testcase_skip("Tests with modbits='%lu' are not enabled", tsuite->tv[i].modbits); free(s); continue; } if (!keysize_supported(slot_id, tsuite->mech.mechanism, tsuite->tv[i].modbits)) { testcase_skip("Token in slot %lu cannot be used with modbits='%lu'", SLOT_ID, tsuite->tv[i].modbits); free(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); free(s); continue; } } if (is_soft_token(slot_id)) { if (!is_valid_soft_pubexp(tsuite->tv[i].publ_exp, tsuite->tv[i].publ_exp_len)) { testcase_skip("Soft Token cannot be used with publ_exp='%s'.", s); free(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_cached(session, tsuite->keygen_mech.mechanism, tsuite->tv[i].modbits, tsuite->tv[i].publ_exp, tsuite->tv[i].publ_exp_len, &publ_key, &priv_key); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("RSA key generation is not allowed by policy"); continue; } if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("RSA key size is not in supported range"); continue; } testcase_error("generate_RSA_PKCS_KeyPair_cached(), " "rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } // 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; if (!mech_supported(slot_id, mech.mechanism)) { testcase_skip("Slot %u doesn't support %s (0x%x)", (unsigned int)slot_id, mech_to_str(mech.mechanism), (unsigned int)mech.mechanism); continue; } 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 testcase_cleanup; } // 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=%lu", p11_get_ckr(rc), signature_len); goto testcase_cleanup; } // 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)); } testcase_cleanup: free_rsa_key_cache(session); 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_RSA_AES_KEY_WRAP_PARAMS rsa_aeskw_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 (0x%x)", (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; } if (!mech_supported(slot_id, tsuite->keygen_mech.mechanism)) { testsuite_skip(tsuite->tvcount, "Slot %u doesn't support %s (0x%x)", (unsigned int) slot_id, mech_to_str(tsuite->keygen_mech.mechanism), (unsigned int) tsuite->keygen_mech.mechanism); 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 (0x%x)", (unsigned int) slot_id, mech_to_str(tsuite->tv[i].keytype.mechanism), (unsigned int) tsuite->tv[i].keytype.mechanism); continue; } if (tsuite->tv[i].modbits > 4096 && !rsa8k) { testcase_skip("Tests with modbits='%lu' are not enabled", tsuite->tv[i].modbits); continue; } if (!keysize_supported(slot_id, tsuite->mech.mechanism, tsuite->tv[i].modbits)) { testcase_skip("Token in slot %lu cannot be used with modbits='%lu'", 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); free(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); free(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); free(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); free(s); continue; } if (tsuite->tv[i].keytype.mechanism == CKM_GENERIC_SECRET_KEY_GEN) { testcase_skip("CCA Token cannot wrap CKK_GENERIC_SECRET keys"); free(s); continue; } if (tsuite->mech.mechanism == CKM_RSA_PKCS_OAEP && tsuite->tv[i].oaep_params.hashAlg != CKM_SHA_1 && tsuite->tv[i].oaep_params.hashAlg != CKM_SHA256) { testcase_skip("CCA Token cannot use RSA OAEP with a hash " "algorithm other than SHA1 and SHA256: %s", mech_to_str(tsuite->tv[i].oaep_params.hashAlg)); free(s); continue; } if (tsuite->mech.mechanism == CKM_RSA_PKCS_OAEP && tsuite->tv[i].oaep_params.source == CKZ_DATA_SPECIFIED && tsuite->tv[i].oaep_params.ulSourceDataLen > 0) { testcase_skip("CCA Token cannot use RSA OAEP with non empty " "source data"); free(s); continue; } if (tsuite->mech.mechanism == CKM_RSA_AES_KEY_WRAP && (tsuite->tv[i].keytype.mechanism != CKM_AES_KEY_GEN || tsuite->tv[i].oaep_params.hashAlg != CKM_SHA_1 || tsuite->tv[i].oaep_params.mgf != CKG_MGF1_SHA1 || (tsuite->tv[i].oaep_params.source == CKZ_DATA_SPECIFIED && tsuite->tv[i].oaep_params.ulSourceDataLen > 0))) { testcase_skip("CCA Token cannot use RSA AES keywrap with " "OAEP params other than SHA-1 and empty source " "data"); free(s); continue; } } if (is_soft_token(slot_id)) { if (!is_valid_soft_pubexp(tsuite->tv[i].publ_exp, tsuite->tv[i].publ_exp_len)) { testcase_skip("Soft Token cannot be used with publ_exp='%s'.", s); free(s); continue; } } if (tsuite->mech.mechanism == CKM_RSA_PKCS_OAEP) { if (!mech_supported(slot_id, tsuite->tv[i].oaep_params.hashAlg)) { testcase_skip("Slot %u doesn't support OAEP hash alg %s (0x%x)", (unsigned int)slot_id, mech_to_str(tsuite->tv[i].oaep_params.hashAlg), (unsigned int)tsuite->tv[i].oaep_params.hashAlg); free(s); continue; } } // begin test testcase_begin("%s Wrap Unwrap with test vector %u, " "\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(&mechtable_funcs, tsuite->tv[i].keytype.mechanism)); // free memory if (s) free(s); // get key gen mechanism keygen_mech = tsuite->tv[i].keytype; if (!mech_supported(slot_id, keygen_mech.mechanism)) { testcase_skip("Slot %u doesn't support %s (0x%x)", (unsigned int)slot_id, mech_to_str(keygen_mech.mechanism), (unsigned int)keygen_mech.mechanism); continue; } if (keygen_mech.mechanism == CKM_AES_XTS_KEY_GEN && (is_ep11_token(slot_id) || is_cca_token(slot_id))) { testcase_skip("Skip test as CKM_AES_XTS_KEY_GEN is supported " \ "only for protected keys in EP11 and CCA token"); continue; } // 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); } else if (wrap_mech.mechanism == CKM_RSA_AES_KEY_WRAP) { rsa_aeskw_params.ulAESKeyBits = 256; rsa_aeskw_params.pOAEPParams = &tsuite->tv[i].oaep_params; wrap_mech.pParameter = &rsa_aeskw_params; wrap_mech.ulParameterLen = sizeof(CK_RSA_AES_KEY_WRAP_PARAMS); } if (!mech_supported(slot_id, wrap_mech.mechanism)) { testcase_skip("Slot %u doesn't support %s (0x%x)", (unsigned int)slot_id, mech_to_str(wrap_mech.mechanism), (unsigned int)wrap_mech.mechanism); continue; } // clear out buffers memset(cipher, 0, sizeof(cipher)); memset(re_cipher, 0, sizeof(re_cipher)); // initialize buffer lengths wrapped_keylen = 0; // generate RSA key pair rc = generate_RSA_PKCS_KeyPair_cached(session, tsuite->keygen_mech.mechanism, tsuite->tv[i].modbits, tsuite->tv[i].publ_exp, tsuite->tv[i].publ_exp_len, &publ_key, &priv_key); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("RSA key generation is not allowed by policy"); continue; } if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("RSA key size is not in supported range"); continue; } 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) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("Generic secret key generation is not allowed by policy"); funcs->C_DestroyObject(session, priv_key); continue; } 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. */ mech.ulParameterLen = 0; mech.pParameter = NULL; if (keygen_mech.mechanism != CKM_GENERIC_SECRET_KEY_GEN) { switch (keygen_mech.mechanism) { case CKM_AES_KEY_GEN: mech.mechanism = CKM_AES_CBC; mech.ulParameterLen = AES_IV_SIZE; mech.pParameter = &aes_iv; key_type = CKK_AES; break; case CKM_AES_XTS_KEY_GEN: mech.mechanism = CKM_AES_XTS; mech.ulParameterLen = AES_IV_SIZE; mech.pParameter = &aes_iv; key_type = CKK_AES_XTS; break; case CKM_DES3_KEY_GEN: mech.mechanism = CKM_DES3_CBC; mech.ulParameterLen = DES_IV_SIZE; mech.pParameter = &des_iv; key_type = CKK_DES3; break; case CKM_DES_KEY_GEN: mech.mechanism = CKM_DES_CBC; mech.ulParameterLen = DES_IV_SIZE; mech.pParameter = &des_iv; key_type = CKK_DES; break; default: testcase_error("unknown mech"); goto error; } if (!mech_supported(slot_id, mech.mechanism)) { testcase_skip("Slot %u doesn't support %s (0x%x)", (unsigned int) slot_id, mech_to_str(mech.mechanism), (unsigned int)mech.mechanism); goto tv_cleanup; } 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; } // 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; } if (rc == CKR_KEY_NOT_WRAPPABLE && is_cca_token(slot_id)) { testcase_skip("CCA Token does not support to wrap %s keys " "with %s", wrap_mech.mechanism == CKM_RSA_AES_KEY_WRAP ? "DATA" : "CIPHER", mech_to_str(wrap_mech.mechanism)); goto tv_cleanup; } if (rc == CKR_WRAPPING_KEY_SIZE_RANGE && wrap_mech.mechanism == CKM_RSA_AES_KEY_WRAP) { testcase_skip("%s: Cannot wrap a temporary AES key of size %lu " "with the given RSA key size and OAEP parameters", mech_to_str(wrap_mech.mechanism), rsa_aeskw_params.ulAESKeyBits); goto tv_cleanup; } testcase_error("C_WrapKey(), rc=%s.", p11_get_ckr(rc)); goto error; } testcase_new_assertion(); /* assertion #1 */ // allocate memory for wrapped_key wrapped_key = calloc(wrapped_keylen, sizeof(CK_BYTE)); 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_AES_XTS_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; } switch (wrap_mech.mechanism) { case CKM_RSA_X_509: case CKM_AES_ECB: case CKM_AES_CBC: case CKM_DES_ECB: case CKM_DES_CBC: case CKM_DES3_ECB: case CKM_DES3_CBC: break; default: unwrap_tmpl_len = 2; break; } // 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)); } goto testcase_cleanup; error: if (wrapped_key) { free(wrapped_key); wrapped_key = NULL; } funcs->C_DestroyObject(session, secret_key); testcase_cleanup: free_rsa_key_cache(session); 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, CK_BBOOL me_only) { 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%s. ", tsuite->name, me_only ? " (ME-format)" : ""); 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 (0x%x)", (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%s with test vector %u.", tsuite->name, me_only ? " (ME-format)" : "", i); rc = CKR_OK; // set return value if (tsuite->tv[i].mod_len * 8 > 4096 && !rsa8k) { testcase_skip("Tests with modbits='%lu' are not enabled", tsuite->tv[i].mod_len * 8); continue; } if (!keysize_supported(slot_id, tsuite->mech.mechanism, tsuite->tv[i].mod_len * 8)) { testcase_skip("Token in slot %lu cannot be used with modbits='%lu'", SLOT_ID, tsuite->tv[i].mod_len * 8); 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; } } // special case for EP11 + ICSF // modulus length must be multiple of 128 byte // skip test if modulus length has unsuported size if (is_ep11_token(slot_id) || is_icsf_token(slot_id)) { if ((tsuite->tv[i].mod_len % 128) != 0) { testcase_skip("EP11/ICSF 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; } } 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 this test vector."); continue; } } if (is_soft_token(slot_id)) { if (!is_valid_soft_pubexp(tsuite->tv[i].pub_exp, tsuite->tv[i].pubexp_len)) { testcase_skip("Soft 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, me_only ? NULL : tsuite->tv[i].prime1, me_only ? NULL : tsuite->tv[i].prime2, me_only ? NULL : tsuite->tv[i].exp1, me_only ? NULL : tsuite->tv[i].exp2, me_only ? NULL : tsuite->tv[i].coef, tsuite->tv[i].mod_len, tsuite->tv[i].pubexp_len, tsuite->tv[i].privexp_len, me_only ? 0 : tsuite->tv[i].prime1_len, me_only ? 0 : tsuite->tv[i].prime2_len, me_only ? 0 : tsuite->tv[i].exp1_len, me_only ? 0 : tsuite->tv[i].exp2_len, me_only ? 0 : tsuite->tv[i].coef_len, &priv_key); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("RSA key import is not allowed by policy"); continue; } if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("RSA key size is not in supported range"); continue; } 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 %u failed. " "Expected len=%lu, found len=%lu.", tsuite->name, i, expected_len, actual_len); } else if (memcmp(actual, expected, expected_len)) { testcase_fail("%s Sign with test vector %u failed. " "Signature data does not match test vector " "signature.", tsuite->name, i); } else { testcase_pass("C_Sign%s.", me_only ? " (ME-format)" : ""); } 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 (0x%x)", (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 %u.", tsuite->name, i); rc = CKR_OK; // set return value if (tsuite->tv[i].mod_len * 8 > 4096 && !rsa8k) { testcase_skip("Tests with modbits='%lu' are not enabled", tsuite->tv[i].mod_len * 8); continue; } if (!keysize_supported(slot_id, tsuite->mech.mechanism, tsuite->tv[i].mod_len * 8)) { testcase_skip("Token in slot %lu cannot be used with modbits='%lu'", SLOT_ID, tsuite->tv[i].mod_len * 8); continue; } // special case for EP11 + ICSF // modulus length must be multiple of 128 byte // skip test if modulus length has unsuported size if (is_ep11_token(slot_id) || is_icsf_token(slot_id)) { if ((tsuite->tv[i].mod_len % 128) != 0) { testcase_skip("EP11/ICSF 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; } } 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 this test vector."); continue; } } if (is_soft_token(slot_id)) { if (!is_valid_soft_pubexp(tsuite->tv[i].pub_exp, tsuite->tv[i].pubexp_len)) { testcase_skip("Soft 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) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("RSA key import is not allowed by policy"); continue; } if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("RSA key size is not in supported range"); continue; } 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 if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("RSA key size is not in supported range"); } else { testcase_fail("%s Sign Verify with test vector %u " "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 do_RSAImplicitRejection(struct PUBLISHED_TEST_SUITE_INFO *tsuite) { unsigned int i; CK_BYTE decrypt[BIG_REQUEST]; CK_ULONG decrypt_len; CK_MECHANISM mech; CK_OBJECT_HANDLE priv_key = CK_INVALID_HANDLE; 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 Implicit Rejection.", tsuite->name); testcase_rw_session(); testcase_user_login(); if (!is_ica_token(slot_id) && !is_soft_token(slot_id)) { testsuite_skip(tsuite->tvcount, "Slot %u doesn't support Implicit Rejection", (unsigned int) slot_id); goto testcase_cleanup; } // 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 (0x%x)", (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 Implicit Rejection with test vector %u." "\npubl_exp='%s', modbits=%lu, publ_exp_len=%lu.", tsuite->name, i, s, tsuite->tv[i].mod_len * 8, tsuite->tv[i].pubexp_len); rc = CKR_OK; if (tsuite->tv[i].mod_len * 8 > 4096 && !rsa8k) { testcase_skip("Tests with modbits='%lu' are not enabled", tsuite->tv[i].mod_len * 8); continue; } if (!keysize_supported(slot_id, tsuite->mech.mechanism, tsuite->tv[i].mod_len * 8)) { testcase_skip("Token in slot %lu cannot be used with modbits='%lu'", SLOT_ID, tsuite->tv[i].mod_len * 8); free(s); continue; } free(s); // clear buffers memset(decrypt, 0, BIG_REQUEST); // 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) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("RSA key import is not allowed by policy"); continue; } if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("RSA key size is not in supported range"); continue; } testcase_error("create_RSAPrivateKey(), rc=%s", p11_get_ckr(rc)); goto error; } // set cipher buffer length decrypt_len = BIG_REQUEST; // get mech mech = tsuite->mech; // 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, tsuite->tv[i].msg, tsuite->tv[i].msg_len, decrypt, &decrypt_len); if (rc != CKR_OK) { testcase_error("C_Decrypt, rc=%s", p11_get_ckr(rc)); goto tv_cleanup; } // check results testcase_new_assertion(); if (decrypt_len != tsuite->tv[i].sig_len) { testcase_fail("decrypted length does not match" "expected data length.\n expected length = %lu, " "but found length=%lu.\n", tsuite->tv[i].sig_len, decrypt_len); } else if (memcmp(decrypt, tsuite->tv[i].sig, tsuite->tv[i].sig_len)) { testcase_fail("decrypted data does not match expected data."); } else { testcase_pass("Implicit Rejection."); } // clean up tv_cleanup: 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, 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 do_EncapsDecapsRSA(struct GENERATED_TEST_SUITE_INFO * tsuite) { unsigned int i = 0; char *s = NULL; CK_OBJECT_HANDLE publ_key, priv_key; CK_OBJECT_HANDLE secret_key1 = CK_INVALID_HANDLE; CK_OBJECT_HANDLE secret_key2 = CK_INVALID_HANDLE; CK_BYTE_PTR cipher = NULL; CK_ULONG cipher_len; CK_MECHANISM encaps_mech, mech; CK_RSA_PKCS_OAEP_PARAMS oaep_params; CK_BYTE clear[32], encypted[32], re_cipher[32]; CK_ULONG encrypted_len = 32, re_cipher_len = 32; 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_ULONG keylen = 0; CK_BBOOL ck_false = CK_FALSE; CK_ATTRIBUTE encaps_decaps_tmpl[] = { {CKA_CLASS, &key_class, sizeof(CK_OBJECT_CLASS)}, {CKA_KEY_TYPE, &key_type, sizeof(CK_KEY_TYPE)}, {CKA_EXTRACTABLE, &ck_false, sizeof(CK_BBOOL)}, {CKA_VALUE_LEN, &keylen, sizeof(CK_ULONG)} }; CK_ULONG encaps_decaps_tmpl_len; // begin test suite testsuite_begin("%s Ecapsulate Decapsulate.", tsuite->name); testcase_rw_session(); testcase_user_login(); // 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 (0x%x)", (unsigned int) slot_id, mech_to_str(tsuite->mech.mechanism), (unsigned int) tsuite->mech.mechanism); goto testcase_cleanup; } else if (!encapsulate_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 encapsulation", (unsigned int) slot_id); goto testcase_cleanup; } if (!mech_supported(slot_id, tsuite->keygen_mech.mechanism)) { testsuite_skip(tsuite->tvcount, "Slot %u doesn't support %s (0x%x)", (unsigned int) slot_id, mech_to_str(tsuite->keygen_mech.mechanism), (unsigned int) tsuite->keygen_mech.mechanism); 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 (0x%x)", (unsigned int) slot_id, mech_to_str(tsuite->tv[i].keytype.mechanism), (unsigned int) tsuite->tv[i].keytype.mechanism); continue; } if (tsuite->tv[i].modbits > 4096 && !rsa8k) { testcase_skip("Tests with modbits='%lu' are not enabled", tsuite->tv[i].modbits); continue; } if (!keysize_supported(slot_id, tsuite->mech.mechanism, tsuite->tv[i].modbits)) { testcase_skip("Token in slot %lu cannot be used with modbits='%lu'", 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); free(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); free(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); free(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); free(s); continue; } if (tsuite->tv[i].keytype.mechanism == CKM_GENERIC_SECRET_KEY_GEN) { testcase_skip("CCA Token cannot wrap CKK_GENERIC_SECRET keys"); free(s); continue; } if (tsuite->mech.mechanism == CKM_RSA_PKCS_OAEP && tsuite->tv[i].oaep_params.hashAlg != CKM_SHA_1 && tsuite->tv[i].oaep_params.hashAlg != CKM_SHA256) { testcase_skip("CCA Token cannot use RSA OAEP with a hash " "algorithm other than SHA1 and SHA256: %s", mech_to_str(tsuite->tv[i].oaep_params.hashAlg)); free(s); continue; } if (tsuite->mech.mechanism == CKM_RSA_PKCS_OAEP && tsuite->tv[i].oaep_params.source == CKZ_DATA_SPECIFIED && tsuite->tv[i].oaep_params.ulSourceDataLen > 0) { testcase_skip("CCA Token cannot use RSA OAEP with non empty " "source data"); free(s); continue; } if (tsuite->mech.mechanism == CKM_RSA_AES_KEY_WRAP && (tsuite->tv[i].keytype.mechanism != CKM_AES_KEY_GEN || tsuite->tv[i].oaep_params.hashAlg != CKM_SHA_1 || tsuite->tv[i].oaep_params.mgf != CKG_MGF1_SHA1 || (tsuite->tv[i].oaep_params.source == CKZ_DATA_SPECIFIED && tsuite->tv[i].oaep_params.ulSourceDataLen > 0))) { testcase_skip("CCA Token cannot use RSA AES keywrap with " "OAEP params other than SHA-1 and empty source " "data"); free(s); continue; } } if (is_soft_token(slot_id)) { if (!is_valid_soft_pubexp(tsuite->tv[i].publ_exp, tsuite->tv[i].publ_exp_len)) { testcase_skip("Soft Token cannot be used with publ_exp='%s'.", s); free(s); continue; } } if (tsuite->mech.mechanism == CKM_RSA_PKCS_OAEP) { if (!mech_supported(slot_id, tsuite->tv[i].oaep_params.hashAlg)) { testcase_skip("Slot %u doesn't support OAEP hash alg %s (0x%x)", (unsigned int)slot_id, mech_to_str(tsuite->tv[i].oaep_params.hashAlg), (unsigned int)tsuite->tv[i].oaep_params.hashAlg); free(s); continue; } } // begin test testcase_begin("%s Encapsulate Decapsulate with test vector %u, " "\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(&mechtable_funcs, tsuite->tv[i].keytype.mechanism)); // free memory if (s) free(s); encaps_decaps_tmpl_len = sizeof(encaps_decaps_tmpl) / sizeof(CK_ATTRIBUTE); // get wrapping mechanism encaps_mech = tsuite->mech; if (encaps_mech.mechanism == CKM_RSA_PKCS_OAEP) { oaep_params = tsuite->tv[i].oaep_params; encaps_mech.pParameter = &oaep_params; encaps_mech.ulParameterLen = sizeof(CK_RSA_PKCS_OAEP_PARAMS); } if (tsuite->tv[i].keytype.mechanism == CKM_AES_XTS_KEY_GEN && (is_ep11_token(slot_id) || is_cca_token(slot_id))) { testcase_skip("Skip test as CKM_AES_XTS_KEY_GEN is supported " \ "only for protected keys in EP11 and CCA token"); continue; } if (!mech_supported(slot_id, encaps_mech.mechanism)) { testcase_skip("Slot %u doesn't support %s (0x%x)", (unsigned int)slot_id, mech_to_str(encaps_mech.mechanism), (unsigned int)encaps_mech.mechanism); continue; } // generate RSA key pair rc = generate_RSA_PKCS_KeyPair_cached(session, tsuite->keygen_mech.mechanism, tsuite->tv[i].modbits, tsuite->tv[i].publ_exp, tsuite->tv[i].publ_exp_len, &publ_key, &priv_key); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("RSA key generation is not allowed by policy"); continue; } if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("RSA key size is not in supported range"); continue; } testcase_error("C_GenerateKeyPair() rc = %s", p11_get_ckr(rc)); goto testcase_cleanup; } mech.ulParameterLen = 0; mech.pParameter = NULL; // get encaps key type and length + key check mech switch (tsuite->tv[i].keytype.mechanism) { case CKM_AES_KEY_GEN: key_type = CKK_AES; mech.mechanism = CKM_AES_CBC; mech.ulParameterLen = AES_IV_SIZE; mech.pParameter = &aes_iv; break; case CKM_AES_XTS_KEY_GEN: key_type = CKK_AES_XTS; mech.mechanism = CKM_AES_XTS; mech.ulParameterLen = AES_IV_SIZE; mech.pParameter = &aes_iv; break; case CKM_DES3_KEY_GEN: key_type = CKK_DES3; encaps_decaps_tmpl_len = sizeof(encaps_decaps_tmpl) / sizeof(CK_ATTRIBUTE) - 1; mech.mechanism = CKM_DES3_CBC; mech.ulParameterLen = DES_IV_SIZE; mech.pParameter = &des_iv; break; case CKM_DES_KEY_GEN: key_type = CKK_DES; encaps_decaps_tmpl_len = sizeof(encaps_decaps_tmpl) / sizeof(CK_ATTRIBUTE) - 1; mech.mechanism = CKM_DES_CBC; mech.ulParameterLen = DES_IV_SIZE; mech.pParameter = &des_iv; break; case CKM_GENERIC_SECRET_KEY_GEN: key_type = CKK_GENERIC_SECRET; break; default: testcase_error("unknown mech"); goto error; } keylen = tsuite->tv[i].keylen; // encapsulate key (length only) rc = funcs3_2->C_EncapsulateKey(session, &encaps_mech, publ_key, encaps_decaps_tmpl, encaps_decaps_tmpl_len, NULL, &cipher_len, NULL); if (rc != CKR_OK) { if (rc == CKR_MECHANISM_PARAM_INVALID && encaps_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; } if (rc == CKR_KEY_NOT_WRAPPABLE && is_cca_token(slot_id)) { testcase_skip("CCA Token does not support to encapsulate %s " "keys with %s", encaps_mech.mechanism == CKM_RSA_AES_KEY_WRAP ? "DATA" : "CIPHER", mech_to_str(encaps_mech.mechanism)); goto tv_cleanup; } testcase_error("C_EncapsulateKey(), rc=%s.", p11_get_ckr(rc)); goto error; } testcase_new_assertion(); /* assertion #1 */ // allocate memory for wrapped_key cipher = calloc(cipher_len, sizeof(CK_BYTE)); if (cipher == NULL) { testcase_error("Can't allocate memory for %lu bytes.", sizeof(CK_BYTE) * cipher_len); rc = CKR_HOST_MEMORY; goto error; } // encapsulate key rc = funcs3_2->C_EncapsulateKey(session, &encaps_mech, publ_key, encaps_decaps_tmpl, encaps_decaps_tmpl_len, cipher, &cipher_len, &secret_key1); if (rc != CKR_OK) { testcase_fail("C_EncapsulateKey, rc=%s", p11_get_ckr(rc)); goto error; } // Decaps does not allow CKA_VALUE_LEN, RSA can recover the key size encaps_decaps_tmpl_len = sizeof(encaps_decaps_tmpl) / sizeof(CK_ATTRIBUTE) - 1; // decapsulate key rc = funcs3_2->C_DecapsulateKey(session, &encaps_mech, priv_key, encaps_decaps_tmpl, encaps_decaps_tmpl_len, cipher, cipher_len, &secret_key2); if (rc != CKR_OK) { testcase_fail("C_DecapsulateKey, rc=%s", p11_get_ckr(rc)); goto error; } else { testcase_pass("encapsulate and decapsulate key successful."); } if (tsuite->tv[i].keytype.mechanism != CKM_GENERIC_SECRET_KEY_GEN) { if (!mech_supported(slot_id, mech.mechanism)) { testcase_skip("Slot %u doesn't support %s (0x%x)", (unsigned int) slot_id, mech_to_str(mech.mechanism), (unsigned int)mech.mechanism); goto tv_cleanup; } rc = funcs->C_EncryptInit(session, &mech, secret_key1); if (rc != CKR_OK) { testcase_error("C_EncryptInit with encapsulated key " ": rc = %s", p11_get_ckr(rc)); goto error; } rc = funcs->C_Encrypt(session, clear, sizeof(clear), encypted, &encrypted_len); if (rc != CKR_OK) { testcase_error("C_Encrypt secret_key: rc = %s", p11_get_ckr(rc)); goto error; } rc = funcs->C_DecryptInit(session, &mech, secret_key2); if (rc != CKR_OK) { testcase_error("C_DecryptInit with decapsulated key: " " rc = %s", p11_get_ckr(rc)); goto error; } rc = funcs->C_Decrypt(session, encypted, encrypted_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 (cipher) { free(cipher); cipher = NULL; } if (secret_key1 != CK_INVALID_HANDLE) { rc = funcs->C_DestroyObject(session, secret_key1); if (rc != CKR_OK) testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(rc)); secret_key1 = CK_INVALID_HANDLE; } if (secret_key2 != CK_INVALID_HANDLE) { rc = funcs->C_DestroyObject(session, secret_key2); if (rc != CKR_OK) testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(rc)); secret_key2 = CK_INVALID_HANDLE; } } goto testcase_cleanup; error: if (cipher) { free(cipher); cipher = NULL; } funcs->C_DestroyObject(session, secret_key1); funcs->C_DestroyObject(session, secret_key2); testcase_cleanup: free_rsa_key_cache(session); 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(void) { 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], FALSE); if (rv != CKR_OK && (!no_stop)) break; rv = do_SignRSA(&published_test_suites[i], TRUE); 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], FALSE); if (rv != CKR_OK && (!no_stop)) break; } for (i = 0; i < NUM_OF_ENCDEC_IMPORT_TESTSUITES; i++) { rv = do_EncryptDecryptImportRSA(&rsa_encdec_import_test_suites[i], TRUE); if (rv != CKR_OK && (!no_stop)) break; } // Implicit rejection tests for (i = 0; i < NUM_OF_IMPLICIT_REJECTION_TESTSUITES; i++) { rv = do_RSAImplicitRejection(&rsa_implicit_rejection_test_suites[i]); if (rv != CKR_OK && (!no_stop)) break; } // Encapsulate/Decapsulate tests for (i = 0; i < NUM_OF_GENERATED_KEYWRAP_TESTSUITES; i++) { rv = do_EncapsDecapsRSA(&generated_keywrap_test_suites[i]); if (rv != CKR_OK && (!no_stop)) break; } for (i = 0; i < NUM_OF_GENERATED_OAEP_TESTSUITES; i++) { rv = do_EncapsDecapsRSA(&generated_oaep_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(); rv = rsa_funcs(); testcase_print_result(); free_rsa_key_cache(CK_INVALID_HANDLE); funcs->C_Finalize(NULL); return testcase_return(rv); } opencryptoki-opencryptoki-451d99c/testcases/crypto/rsaupdate_func.c000066400000000000000000001167541520105705100260270ustar00rootroot00000000000000/* * 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; 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 (0x%x)", (unsigned int) slot_id, mech_to_str(tsuite->mech.mechanism), (unsigned int) tsuite->mech.mechanism); goto testcase_cleanup; } if (!mech_supported(slot_id, tsuite->keygen_mech.mechanism)) { testsuite_skip(tsuite->tvcount, "Slot %u doesn't support %s (0x%x)", (unsigned int) slot_id, mech_to_str(tsuite->keygen_mech.mechanism), (unsigned int) tsuite->keygen_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 %u, " "\npubl_exp='%s', mod_bits='%lu', keylen='%lu'.", tsuite->name, i, s, tsuite->tv[i].modbits, tsuite->tv[i].keylen); if (tsuite->tv[i].modbits > 4096 && !rsa8k) { testcase_skip("Tests with modbits='%lu' are not enabled", tsuite->tv[i].modbits); free(s); continue; } if (!keysize_supported(slot_id, tsuite->mech.mechanism, tsuite->tv[i].modbits)) { testcase_skip("Token in slot %lu cannot be used with modbits='%lu'", SLOT_ID, tsuite->tv[i].modbits); free(s); 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); free(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); free(s); continue; } } if (is_soft_token(slot_id)) { if (!is_valid_soft_pubexp(tsuite->tv[i].publ_exp, tsuite->tv[i].publ_exp_len)) { testcase_skip("Soft Token cannot be used with publ_exp='%s'.", s); free(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); free(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); free(s); continue; } } if (tsuite->tv[i].modbits <= 512 && (tsuite->mech.mechanism == CKM_SHA384_RSA_PKCS || tsuite->mech.mechanism == CKM_SHA512_RSA_PKCS || tsuite->mech.mechanism == CKM_SHA3_384_RSA_PKCS || tsuite->mech.mechanism == CKM_SHA3_512_RSA_PKCS)) { testcase_skip("Mechanism %s can not be used with a key with mod_bits='%lu'.", mech_to_str(tsuite->mech.mechanism), tsuite->tv[i].modbits); free(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_cached(session, tsuite->keygen_mech.mechanism, tsuite->tv[i].modbits, tsuite->tv[i].publ_exp, tsuite->tv[i].publ_exp_len, &publ_key, &priv_key); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("RSA key generation is not allowed by policy"); continue; } if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("RSA key size is not in supported range"); continue; } testcase_error("generate_RSA_PKCS_KeyPair_cached(), 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 testcase_cleanup; } // set buffer size signature_len = 0; // do SignUpdate if (message_len > 0) { 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 testcase_cleanup; } len -= inc; } } else { rc = funcs->C_SignUpdate(session, NULL, 0); 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 testcase_cleanup; } 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 %lu, got %lu.", signature_len, tsuite->tv[i].modbits / 8); goto testcase_cleanup; } rc = funcs->C_SignFinal(session, signature, &signature_len); if (rc != CKR_OK) { testcase_error("C_SignFinal(),rc=%s.", p11_get_ckr(rc)); goto testcase_cleanup; } // 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 testcase_cleanup; } // do VerifyUpdate len = message_len; if (message_len > 0) { 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 testcase_cleanup; } len -= inc; } } else { rc = funcs->C_VerifyUpdate(session, NULL, 0); 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)); } } testcase_cleanup: free_rsa_key_cache(session); 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; 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 (0x%x)", (unsigned int) slot_id, mech_to_str(tsuite->mech.mechanism), (unsigned int) tsuite->mech.mechanism); goto testcase_cleanup; } if (!mech_supported(slot_id, tsuite->keygen_mech.mechanism)) { testsuite_skip(tsuite->tvcount, "Slot %u doesn't support %s (0x%x)", (unsigned int) slot_id, mech_to_str(tsuite->keygen_mech.mechanism), (unsigned int) tsuite->keygen_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 %u, " "\npubl_exp='%s', mod_bits='%lu', keylen='%lu'.", tsuite->name, i, s, tsuite->tv[i].modbits, tsuite->tv[i].keylen); if (tsuite->tv[i].modbits > 4096 && !rsa8k) { testcase_skip("Tests with modbits='%lu' are not enabled", tsuite->tv[i].modbits); free(s); continue; } if (!keysize_supported(slot_id, tsuite->mech.mechanism, tsuite->tv[i].modbits)) { testcase_skip("Token in slot %lu cannot be used with modbits='%lu'", SLOT_ID, tsuite->tv[i].modbits); free(s); 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); free(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); free(s); continue; } } if (is_soft_token(slot_id)) { if (!is_valid_soft_pubexp(tsuite->tv[i].publ_exp, tsuite->tv[i].publ_exp_len)) { testcase_skip("Soft Token cannot be used with publ_exp='%s'.", s); free(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_cached(session, tsuite->keygen_mech.mechanism, tsuite->tv[i].modbits, tsuite->tv[i].publ_exp, tsuite->tv[i].publ_exp_len, &publ_key, &priv_key); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("RSA key generation is not allowed by policy"); continue; } if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("RSA key size is not in supported range"); continue; } testcase_error("generate_RSA_PKCS_KeyPair_cached(), rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } // 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 testcase_cleanup; } // 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 testcase_cleanup; } 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 %lu, got %lu.", signature_len, tsuite->tv[i].modbits / 8); goto testcase_cleanup; } rc = funcs->C_SignFinal(session, signature, &signature_len); if (rc != CKR_OK) { testcase_error("C_SignFinal(),rc=%s.", p11_get_ckr(rc)); goto testcase_cleanup; } // 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 testcase_cleanup; } // 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)); } } testcase_cleanup: free_rsa_key_cache(session); 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 (0x%x)", (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 %u.", tsuite->name, i); if (tsuite->tv[i].mod_len * 8 > 4096 && !rsa8k) { testcase_skip("Tests with modbits='%lu' are not enabled", tsuite->tv[i].mod_len * 8); free(s); continue; } if (!keysize_supported(slot_id, tsuite->mech.mechanism, tsuite->tv[i].mod_len * 8)) { testcase_skip("Token in slot %lu cannot be used with modbits='%lu'", SLOT_ID, tsuite->tv[i].mod_len * 8); free(s); 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)."); free(s); 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); free(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); free(s); continue; } } 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); free(s); continue; } } if (is_soft_token(slot_id)) { if (!is_valid_soft_pubexp(tsuite->tv[i].pub_exp, tsuite->tv[i].pubexp_len)) { testcase_skip("Soft Token cannot be used with publ_exp='%s'.", s); free(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) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("RSA key import is not allowed by policy"); continue; } if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("RSA key size is not in supported range"); continue; } 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 %u " "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 (0x%x)", (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 %u.", tsuite->name, i); if (tsuite->tv[i].mod_len * 8 > 4096 && !rsa8k) { testcase_skip("Tests with modbits='%lu' are not enabled", tsuite->tv[i].mod_len * 8); free(s); continue; } if (!keysize_supported(slot_id, tsuite->mech.mechanism, tsuite->tv[i].mod_len * 8)) { testcase_skip("Token in slot %lu cannot be used with modbits='%lu'", SLOT_ID, tsuite->tv[i].mod_len * 8); free(s); 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."); free(s); 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)."); free(s); 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); free(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); free(s); continue; } } 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); free(s); continue; } } if (is_soft_token(slot_id)) { if (!is_valid_soft_pubexp(tsuite->tv[i].pub_exp, tsuite->tv[i].pubexp_len)) { testcase_skip("Soft Token cannot be used with publ_exp='%s'.", s); free(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) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("RSA key import is not allowed by policy"); continue; } if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("RSA key size is not in supported range"); continue; } 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 %lu, got %lu.", 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 %u failed. " "Expected len=%lu, found len=%lu.", tsuite->name, i, expected_len, actual_len); } else if (memcmp(actual, expected, expected_len)) { testcase_fail("%s Sign with test vector %u 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(void) { 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(); rv = rsa_funcs(); testcase_print_result(); funcs->C_Finalize(NULL); return testcase_return(rv); } opencryptoki-opencryptoki-451d99c/testcases/crypto/ssl3_func.c000066400000000000000000000700661520105705100247160ustar00rootroot00000000000000/* * 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 (0x%x)", (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) { if (is_rejected_by_policy(rc, session)) { testcase_skip("key import is not allowed by policy"); return 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 #%lu, 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 #%lu, 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 (0x%x)", (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) { if (is_rejected_by_policy(rc, session)) { testcase_skip("key import is not allowed by policy"); return 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 (0x%x)", (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) { if (is_rejected_by_policy(rc, session)) { testcase_skip("key generation is not allowed by policy"); return 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 (0x%x)", (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) { if (is_rejected_by_policy(rc, session)) { testcase_skip("key generation is not allowed by policy"); return 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) { if (is_rejected_by_policy(rc, session)) { testcase_skip("Key derivation is not allowed by policy"); goto done; } 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 (0x%x)", (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) { if (is_rejected_by_policy(rc, session)) { testcase_skip("Key generation is not allowed by policy"); goto done; } 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 (is_rejected_by_policy(rc, session)) { testcase_skip("key derivation is not allowed by policy"); goto done; } 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) { if (is_rejected_by_policy(rc, session)) { testcase_skip("key derivation is not allowed by policy"); goto done; } 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 do_TLS_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_TLS_PreMasterKeyGen...\n"); version.major = 3; version.minor = 3; mech.mechanism = CKM_TLS_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 (0x%x)", (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) { if (is_rejected_by_policy(rc, session)) { testcase_skip("key generation is not allowed by policy"); return 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_TLS_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, 3 }; 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_TLS_MultipleKeysDerive...\n"); // generate the pre-master secret key // mech.mechanism = CKM_TLS_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 (0x%x)", (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) { if (is_rejected_by_policy(rc, session)) { testcase_skip("Key generation is not allowed by policy"); goto done; } 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_TLS_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 (is_rejected_by_policy(rc, session)) { testcase_skip("key derivation is not allowed by policy"); goto done; } 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) { if (is_rejected_by_policy(rc, session)) { testcase_skip("key derivation is not allowed by policy"); goto done; } 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(void) { 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); GetSystemTime(&t1); rc = do_TLS_PreMasterKeyGen(session); if (rc && !no_stop) goto testcase_cleanup; GetSystemTime(&t2); process_time(t1, t2); GetSystemTime(&t1); rc = do_TLS_MultipleKeysDerive(session); if (rc && !no_stop) goto testcase_cleanup; 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(); rv = ssl3_functions(); testcase_print_result(); funcs->C_Finalize(NULL); return testcase_return(rv); } opencryptoki-opencryptoki-451d99c/testcases/include/000077500000000000000000000000001520105705100227455ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/testcases/include/include.mk000066400000000000000000000002221520105705100247150ustar00rootroot00000000000000noinst_HEADERS += \ testcases/include/mech_to_str.h testcases/include/regress.h \ testcases/include/rsadump.h testcases/include/windows.h opencryptoki-opencryptoki-451d99c/testcases/include/mech_to_str.h000066400000000000000000000012431520105705100254240ustar00rootroot00000000000000/* * 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" #include static inline const char *mech_to_str(CK_ULONG mech) { const struct mechrow *row = mechrow_from_numeric(mech); if (row) return row->string; return "(unknown mech)"; } #endif opencryptoki-opencryptoki-451d99c/testcases/include/regress.h000066400000000000000000000350111520105705100245700ustar00rootroot00000000000000/* * 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 timeval #define GetSystemTime(x) gettimeofday((x), NULL) #include #if !defined(_AIX) #pragma GCC system_header #endif 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); CK_BBOOL 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_FUNCTION_LIST_3_0 *funcs3; extern CK_INTERFACE *ifs; 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() \ 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) #define testcase_return(rc) \ (((rc) != 0 || t_failed != 0 || t_errors != 0) ? 1 : 0) #endif opencryptoki-opencryptoki-451d99c/testcases/include/rsadump.h000066400000000000000000001120001520105705100245630ustar00rootroot00000000000000/* * 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 }; opencryptoki-opencryptoki-451d99c/testcases/include/windows.h000066400000000000000000000000211520105705100246010ustar00rootroot00000000000000// // dummy file opencryptoki-opencryptoki-451d99c/testcases/init_cca.sh000077500000000000000000000016071520105705100234360ustar00rootroot00000000000000#!/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 opencryptoki-opencryptoki-451d99c/testcases/init_token.sh.in000077500000000000000000000076531520105705100244440ustar00rootroot00000000000000#!/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 30 spawn @sbindir@/pkcsconf -c [lindex $argv 0] -I expect { "Enter the SO PIN: " { sleep .1; send "87654321\r"; } timeout { send_user "Timeout when sending SO PIN during initialization\n"; exit 1 } default { send_user "Error sending SO PIN during initialization\n"; exit 1 } } expect { "label: " { sleep .1; send "ibmtest\r"; } timeout { send_user "Timeout when sending label during initialization\n"; exit 1 } default { send_user "Error sending label during initialization\n"; exit 1 } } expect { eof {} "Incorrect PIN Entered." { exit 1 } timeout { send_user "Timeout during initialization\n"; exit 1 } } spawn @sbindir@/pkcsconf -c [lindex $argv 0] -P expect { "Enter the SO PIN: " { sleep .1; send "87654321\r"; } timeout { send_user "Timeout when sending SO PIN during SO PIN setting\n"; exit 1 } default { send_user "Error sending SO PIN during SO PIN setting\n"; exit 1 } } expect { "Enter the new SO PIN: " { sleep .1; send $env(PKCS11_SO_PIN); send "\r"; } timeout { send_user "Timeout when sending new SO PIN during SO PIN setting\n"; exit 1 } default { send_user "Error sending new SO PIN during SO PIN setting\n"; exit 1 } } expect { "Re-enter the new SO PIN: " { sleep .1; send $env(PKCS11_SO_PIN); send "\r"; } timeout { send_user "Timeout when resending new SO PIN during SO PIN setting\n"; exit 1 } default { send_user "Error resending new SO PIN during SO PIN setting\n"; exit 1 } } expect { eof {} "Incorrect PIN Entered." { exit 1 } timeout { send_user "Timeout during SO PIN setting\n"; exit 1 } } spawn @sbindir@/pkcsconf -c [lindex $argv 0] -u expect { "Enter the SO PIN: " { sleep .1; send $env(PKCS11_SO_PIN); send "\r"; } timeout { send_user "Timeout when sending SO PIN during user PIN initialization\n"; exit 1 } default { send_user "Error sending SO PIN during user PIN initialization\n"; exit 1 } } expect { "Enter the new user PIN: " { sleep .1; send "12345678\r"; } timeout { send_user "Timeout when sending new user PIN during user PIN initialization\n"; exit 1 } default { send_user "Error sending new user PIN during user PIN initialization\n"; exit 1 } } expect { "Re-enter the new user PIN: " { sleep .1; send "12345678\r"; } timeout { send_user "Timeout when resending new user during user PIN initialization\n"; exit 1 } default { send_user "Error resending new user during user PIN initialization\n"; exit 1 } } expect { eof {} "Incorrect PIN Entered." { exit 1 } timeout { send_user "Timeout during user PIN initialization\n"; exit 1 } } spawn @sbindir@/pkcsconf -c [lindex $argv 0] -p expect { "Enter user PIN: " { sleep .1; send "12345678\r"; } timeout { send_user "Timeout when sending user PIN during user PIN setting\n"; exit 1 } default { send_user "Error sending user PIN during user PIN setting\n"; exit 1 } } expect { "Enter the new user PIN: " { sleep .1; send $env(PKCS11_USER_PIN); send "\r"; } timeout { send_user "Timeout when sending new user PIN during user PIN setting\n"; exit 1 } default { send_user "Error sending new user PIN during user PIN setting\n"; exit 1 } } expect { "Re-enter the new user PIN: " { sleep .1; send $env(PKCS11_USER_PIN); send "\r"; } timeout { send_user "Timeout when resending new user PIN during user PIN setting\n"; exit 1 } default { send_user "Error resending new user PIN during user PIN setting\n"; exit 1 } } expect { eof {} "Incorrect PIN Entered." { exit 1 } timeout { send_user "Timeout during user PIN setting\n"; exit 1 } } opencryptoki-opencryptoki-451d99c/testcases/init_tpmtoken.sh000077500000000000000000000014301520105705100245430ustar00rootroot00000000000000#!/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" } } opencryptoki-opencryptoki-451d99c/testcases/init_vhsm.exp.in000066400000000000000000000025221520105705100244460ustar00rootroot00000000000000#!/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 # spawn @sbindir@/pkcsep11_session vhsmpin -slot [lindex $argv 0] expect { "Enter the USER PIN:" { sleep .1; send $env(PKCS11_USER_PIN); send "\r"; } eof { send_user "Unexpected EOF on user pin\n"; exit 1 } timeout { send_user "Timeout on user pin\n"; exit 1 } } expect { "Enter the new VHSM PIN:" { sleep .1; send $env(PKCS11_VHSM_PIN); send "\r"; } eof { send_user "Unexpected EOF on VHSM pin\n"; exit 1 } timeout { send_user "Timeout on VHSM pin\n"; exit 1 } } expect { "Re-enter the new VHSM PIN:" { sleep .1; send $env(PKCS11_VHSM_PIN); send "\r"; } eof { send_user "Unexpected EOF on VHSM pin\n"; exit 1 } timeout { send_user "Timeout on VHSM pin\n"; exit 1 } } expect { "VHSM-pin successfully set." {} eof { send_user "Unexpected EOF at the end\n"; exit 1 } timeout { send_user "Unexpected timeout at the end\n"; exit 1 } } expect { eof {} timeout { send_user "Unexpected timeout at the end\n"; exit 1 } } opencryptoki-opencryptoki-451d99c/testcases/login/000077500000000000000000000000001520105705100224325ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/testcases/login/README000066400000000000000000000001141520105705100233060ustar00rootroot00000000000000login_tests.sh TODO: To be tested. login_flags_tests TODO: To be tested. opencryptoki-opencryptoki-451d99c/testcases/login/digest_init.c000066400000000000000000000066151520105705100251100ustar00rootroot00000000000000/* * 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" 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; if (i >= argc) { printf("PIN argument missing\n"); return -1; } pass = argv[i]; } else if (strcmp(argv[i], "-slot") == 0) { ++i; if (i >= argc) { printf("Slot number missing\n"); return -1; } 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; } opencryptoki-opencryptoki-451d99c/testcases/login/init_pin.c000066400000000000000000000066731520105705100244230ustar00rootroot00000000000000/* * 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" 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; if (i >= argc) { printf("PIN argument missing\n"); return -1; } sopass = argv[i]; } else if (strcmp(argv[i], "-userpass") == 0) { ++i; if (i >= argc) { printf("PIN argument missing\n"); return -1; } userpass = argv[i]; } else if (strcmp(argv[i], "-slot") == 0) { ++i; if (i >= argc) { printf("Slot number missing\n"); return -1; } 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; } opencryptoki-opencryptoki-451d99c/testcases/login/init_tok.c000066400000000000000000000055561520105705100244310ustar00rootroot00000000000000/* * 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 **); CK_BBOOL 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) { if (i + 1 >= argc) { printf("Slot number missing\n"); return -1; } SLOT_ID = atoi(argv[i + 1]); i++; } else if (strcmp(argv[i], "-pass") == 0) { if (i + 1 >= argc) { printf("PIN argument missing\n"); return -1; } 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; } opencryptoki-opencryptoki-451d99c/testcases/login/login.c000066400000000000000000000064251520105705100237150ustar00rootroot00000000000000/* * 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" 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 (pass == NULL) { printf("No PIN specified. Use -pass option to specify the PIN\n"); return -1; } 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; if (i >= argc) { printf("PIN argument missing\n"); return -1; } pass = argv[i]; } else if (strcmp(argv[i], "-slot") == 0) { ++i; if (i >= argc) { printf("Slot number missing\n"); return -1; } 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; } opencryptoki-opencryptoki-451d99c/testcases/login/login.mk000066400000000000000000000025541520105705100241010ustar00rootroot00000000000000noinst_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 EXTRA_DIST += testcases/login/login_test.sh 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 opencryptoki-opencryptoki-451d99c/testcases/login/login_flags.c000066400000000000000000000227661520105705100250770ustar00rootroot00000000000000/* * 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 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) { if (i + 1 >= argc) { printf("Slot number missing\n"); return -1; } slot_id = atoi(argv[i + 1]); i++; break; } } printf("Using slot %lu...\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 %lu, expected %lu\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 %lu.\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 %lu 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 %lu.\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 */ #ifndef WITH_SANITIZER dlclose(dl_handle); #endif return rc; } opencryptoki-opencryptoki-451d99c/testcases/login/login_test.sh000077500000000000000000000075601520105705100251500ustar00rootroot00000000000000#!/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 opencryptoki-opencryptoki-451d99c/testcases/login/set_pin.c000066400000000000000000000071351520105705100242450ustar00rootroot00000000000000/* * 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" 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; if (i >= argc) { printf("PIN argument missing\n"); return -1; } old = argv[i]; } else if (strcmp(argv[i], "-new") == 0) { ++i; if (i >= argc) { printf("PIN argument missing\n"); return -1; } new = argv[i]; } else if (strcmp(argv[i], "-slot") == 0) { ++i; if (i >= argc) { printf("Slot number missing\n"); return -1; } 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; } opencryptoki-opencryptoki-451d99c/testcases/misc_tests/000077500000000000000000000000001520105705100234775ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/testcases/misc_tests/README000066400000000000000000000075501520105705100243660ustar00rootroot00000000000000Miscellaneous 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 tok2tok_transport This testcase open sessions on two different tokens within one process. It then generates a keys in the first token, and transports them via various Wrap/Unwrap mechanisms to the other token. It is checked that the transported key can still be used in the receiving token. Usage: tok2tok_transport -slot1 -slot2 opencryptoki-opencryptoki-451d99c/testcases/misc_tests/aes-128.key000066400000000000000000000000201520105705100252610ustar00rootroot000000000000000123456789012345opencryptoki-opencryptoki-451d99c/testcases/misc_tests/aes-192.key000066400000000000000000000000301520105705100252630ustar00rootroot00000000000000012345678901234501234567opencryptoki-opencryptoki-451d99c/testcases/misc_tests/aes.key000066400000000000000000000000401520105705100247530ustar00rootroot0000000000000001234567890123456789012345678901opencryptoki-opencryptoki-451d99c/testcases/misc_tests/always_auth.c000066400000000000000000000370401520105705100261700ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2024 * * 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: always_auth.c * * Test driver. In-depth regression test for PKCS #11 */ #include #include #include #include #include #include "pkcs11types.h" #include "regress.h" #include "common.c" #include "mechtable.h" #include "mech_to_str.h" CK_MECHANISM rsakeygen_mech = { CKM_RSA_PKCS_KEY_PAIR_GEN, NULL, 0 }; CK_MECHANISM signver_mech = { CKM_SHA256_RSA_PKCS, NULL, 0 }; CK_MECHANISM endecrypt_mech = { CKM_RSA_PKCS, NULL, 0 }; CK_RV do_auth_sign(void) { CK_SESSION_HANDLE session; CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; CK_ULONG user_pin_len; CK_RV rc = CKR_OK, loc_rc; CK_FLAGS flags; CK_OBJECT_HANDLE rsa_pub_key = CK_INVALID_HANDLE; CK_OBJECT_HANDLE rsa_priv_key = CK_INVALID_HANDLE; CK_BYTE subject[] = {0}; CK_BYTE id[] = { 123 }; CK_BBOOL true = TRUE; CK_ULONG modulusBits = 2048; CK_BYTE publicExponent[] = { 0x01, 0x00, 0x01 }; CK_BYTE data[20] = { 0x00 }; CK_BYTE signature[256] = { 0x00 }; CK_ULONG signature_len = sizeof(signature); 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, sizeof(publicExponent)} }; CK_ULONG publicKeyTemplate_len = sizeof(publicKeyTemplate) / sizeof(CK_ATTRIBUTE); 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)}, {CKA_ALWAYS_AUTHENTICATE, &true, sizeof(true)}, }; CK_ULONG privateKeyTemplate_len = sizeof(privateKeyTemplate) / sizeof(CK_ATTRIBUTE); testcase_begin("C_Sign with %s and CKA_ALWAYS_AUTHENTICATE=TRUE", mech_to_str(signver_mech.mechanism)); testcase_rw_session(); testcase_user_login(); if (!mech_supported(SLOT_ID, signver_mech.mechanism)) { testcase_skip("Slot %u doesn't support %s (0x%x)", (unsigned int)SLOT_ID, mech_to_str(signver_mech.mechanism), (unsigned int)signver_mech.mechanism); goto testcase_cleanup; } if (!mech_supported(SLOT_ID, rsakeygen_mech.mechanism)) { testcase_skip("Slot %u doesn't support %s (0x%x)", (unsigned int)SLOT_ID, mech_to_str(rsakeygen_mech.mechanism), (unsigned int)rsakeygen_mech.mechanism); goto testcase_cleanup; } testcase_new_assertion(); /* generate an RSA key */ rc = funcs->C_GenerateKeyPair(session, &rsakeygen_mech, publicKeyTemplate, publicKeyTemplate_len, privateKeyTemplate, privateKeyTemplate_len, &rsa_pub_key, &rsa_priv_key); if (is_rejected_by_policy(rc, session)) { testcase_skip("generate key with mech %s (%u) in slot %lu " "is not allowed by policy", mech_to_str(rsakeygen_mech.mechanism), (unsigned int)rsakeygen_mech.mechanism, SLOT_ID); rc = CKR_OK; goto testcase_cleanup; } if (rc != CKR_OK) { testcase_error("generate key with mech %s (%u) in slot %lu failed, rc=%s", mech_to_str(rsakeygen_mech.mechanism), (unsigned int)rsakeygen_mech.mechanism, SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } /* Initialize operation */ rc = funcs->C_SignInit(session, &signver_mech, rsa_priv_key); if (rc != CKR_OK) { testcase_error("C_SignInit with mech %s (%u) in slot %lu failed, rc=%s", mech_to_str(signver_mech.mechanism), (unsigned int)signver_mech.mechanism, SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } /* Perform C_Sign without doing a C_Login first, expected to fail */ rc = funcs->C_Sign(session, data, sizeof(data), signature, &signature_len); if (rc != CKR_USER_NOT_LOGGED_IN) { testcase_fail("C_Sign without C_Login returned rc=%s, expected %s", p11_get_ckr(rc), p11_get_ckr(CKR_USER_NOT_LOGGED_IN)); goto testcase_cleanup; } /* Initialize the operation again, CKR_USER_NOT_LOGGED_IN terminated it */ rc = funcs->C_SignInit(session, &signver_mech, rsa_priv_key); if (rc != CKR_OK) { testcase_error("C_SignInit with mech %s (%u) in slot %lu failed, rc=%s", mech_to_str(signver_mech.mechanism), (unsigned int)signver_mech.mechanism, SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } /* Perform C_Login with CKU_CONTEXT_SPECIFIC and USER pin */ rc = funcs->C_Login(session, CKU_CONTEXT_SPECIFIC, user_pin, user_pin_len); if (rc != CKR_OK) { testcase_error("C_Login with type CKU_CONTEXT_SPECIFIC failed, rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } /* Perform C_Sign after doing a C_Login */ rc = funcs->C_Sign(session, data, sizeof(data), signature, &signature_len); if (rc != CKR_OK) { testcase_error("C_Sign after C_Login failed, rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } /* Perform C_Login after operation is complete, expected to fail */ rc = funcs->C_Login(session, CKU_CONTEXT_SPECIFIC, user_pin, user_pin_len); if (rc != CKR_OPERATION_NOT_INITIALIZED) { testcase_fail("C_Login after op is complete returned rc=%s, expected %s", p11_get_ckr(rc), p11_get_ckr(CKR_OPERATION_NOT_INITIALIZED)); goto testcase_cleanup; } testcase_pass("C_Sign with %s and CKA_ALWAYS_AUTHENTICATE=TRUE", mech_to_str(signver_mech.mechanism)); testcase_cleanup: if (rsa_pub_key != CK_INVALID_HANDLE) { loc_rc = funcs->C_DestroyObject(session, rsa_pub_key); if (loc_rc != CKR_OK) testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(loc_rc)); } if (rsa_priv_key != CK_INVALID_HANDLE) { loc_rc = funcs->C_DestroyObject(session, rsa_priv_key); if (loc_rc != CKR_OK) testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(loc_rc)); } 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_auth_decrypt(void) { CK_SESSION_HANDLE session; CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; CK_ULONG user_pin_len; CK_RV rc = CKR_OK, loc_rc; CK_FLAGS flags; CK_OBJECT_HANDLE rsa_pub_key = CK_INVALID_HANDLE; CK_OBJECT_HANDLE rsa_priv_key = CK_INVALID_HANDLE; CK_BYTE subject[] = {0}; CK_BYTE id[] = { 123 }; CK_BBOOL true = TRUE; CK_ULONG modulusBits = 2048; CK_BYTE publicExponent[] = { 0x01, 0x00, 0x01 }; CK_BYTE data[20] = { 0x00 }; CK_BYTE cipher[256] = { 0x00 }; CK_ULONG cipher_len = sizeof(cipher); CK_BYTE clear[256] = { 0x00 }; CK_ULONG clear_len = sizeof(clear); 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, sizeof(publicExponent)} }; CK_ULONG publicKeyTemplate_len = sizeof(publicKeyTemplate) / sizeof(CK_ATTRIBUTE); 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)}, {CKA_ALWAYS_AUTHENTICATE, &true, sizeof(true)}, }; CK_ULONG privateKeyTemplate_len = sizeof(privateKeyTemplate) / sizeof(CK_ATTRIBUTE); testcase_begin("C_Decrypt with %s and CKA_ALWAYS_AUTHENTICATE=TRUE", mech_to_str(endecrypt_mech.mechanism)); testcase_rw_session(); testcase_user_login(); if (!mech_supported(SLOT_ID, endecrypt_mech.mechanism)) { testcase_skip("Slot %u doesn't support %s (0x%x)", (unsigned int)SLOT_ID, mech_to_str(endecrypt_mech.mechanism), (unsigned int)endecrypt_mech.mechanism); goto testcase_cleanup; } if (!mech_supported(SLOT_ID, rsakeygen_mech.mechanism)) { testcase_skip("Slot %u doesn't support %s (0x%x)", (unsigned int)SLOT_ID, mech_to_str(rsakeygen_mech.mechanism), (unsigned int)rsakeygen_mech.mechanism); goto testcase_cleanup; } testcase_new_assertion(); /* generate an RSA key */ rc = funcs->C_GenerateKeyPair(session, &rsakeygen_mech, publicKeyTemplate, publicKeyTemplate_len, privateKeyTemplate, privateKeyTemplate_len, &rsa_pub_key, &rsa_priv_key); if (is_rejected_by_policy(rc, session)) { testcase_skip("generate key with mech %s (%u) in slot %lu " "is not allowed by policy", mech_to_str(rsakeygen_mech.mechanism), (unsigned int)rsakeygen_mech.mechanism, SLOT_ID); rc = CKR_OK; goto testcase_cleanup; } if (rc != CKR_OK) { testcase_error("generate key with mech %s (%u) in slot %lu failed, rc=%s", mech_to_str(rsakeygen_mech.mechanism), (unsigned int)rsakeygen_mech.mechanism, SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } /* Encrypt some data */ rc = funcs->C_EncryptInit(session, &endecrypt_mech, rsa_pub_key); if (rc != CKR_OK) { testcase_error("C_EncryptInit with mech %s (%u) in slot %lu failed, rc=%s", mech_to_str(endecrypt_mech.mechanism), (unsigned int)endecrypt_mech.mechanism, SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } rc = funcs->C_Encrypt(session, data, sizeof(data), cipher, &cipher_len); if (rc != CKR_OK) { testcase_fail("C_Encrypt failedrc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } /* Initialize operation */ rc = funcs->C_DecryptInit(session, &endecrypt_mech, rsa_priv_key); if (rc != CKR_OK) { testcase_error("C_DecryptInit with mech %s (%u) in slot %lu failed, rc=%s", mech_to_str(endecrypt_mech.mechanism), (unsigned int)endecrypt_mech.mechanism, SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } /* Perform C_Decrypt without doing a C_Login first, expected to fail */ rc = funcs->C_Decrypt(session, cipher, cipher_len, clear, &clear_len); if (rc != CKR_USER_NOT_LOGGED_IN) { testcase_fail("C_Decrypt without C_Login returned rc=%s, expected %s", p11_get_ckr(rc), p11_get_ckr(CKR_USER_NOT_LOGGED_IN)); goto testcase_cleanup; } /* Initialize the operation again, CKR_USER_NOT_LOGGED_IN terminated it */ rc = funcs->C_DecryptInit(session, &endecrypt_mech, rsa_priv_key); if (rc != CKR_OK) { testcase_error("C_DecryptInit with mech %s (%u) in slot %lu failed, rc=%s", mech_to_str(endecrypt_mech.mechanism), (unsigned int)endecrypt_mech.mechanism, SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } /* Perform C_Login with CKU_CONTEXT_SPECIFIC and USER pin */ rc = funcs->C_Login(session, CKU_CONTEXT_SPECIFIC, user_pin, user_pin_len); if (rc != CKR_OK) { testcase_error("C_Login with type CKU_CONTEXT_SPECIFIC failed, rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } /* Perform C_Decrypt after doing a C_Login */ rc = funcs->C_Decrypt(session, cipher, cipher_len, clear, &clear_len); if (rc != CKR_OK) { testcase_error("C_Decrypt after C_Login failed, rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } /* Perform C_Login after operation is complete, expected to fail */ rc = funcs->C_Login(session, CKU_CONTEXT_SPECIFIC, user_pin, user_pin_len); if (rc != CKR_OPERATION_NOT_INITIALIZED) { testcase_fail("C_Login after op is complete returned rc=%s, expected %s", p11_get_ckr(rc), p11_get_ckr(CKR_OPERATION_NOT_INITIALIZED)); goto testcase_cleanup; } testcase_pass("C_Decrypt with %s and CKA_ALWAYS_AUTHENTICATE=TRUE", mech_to_str(endecrypt_mech.mechanism)); testcase_cleanup: if (rsa_pub_key != CK_INVALID_HANDLE) { loc_rc = funcs->C_DestroyObject(session, rsa_pub_key); if (loc_rc != CKR_OK) testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(loc_rc)); } if (rsa_priv_key != CK_INVALID_HANDLE) { loc_rc = funcs->C_DestroyObject(session, rsa_priv_key); if (loc_rc != CKR_OK) testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(loc_rc)); } 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_always_auth_tests(void) { CK_RV rc = CKR_OK; if (is_icsf_token(SLOT_ID)) { testcase_skip("ICSF token does not support CKA_ALWAYS_AUTHENTICATE"); return rc; } rc |= do_auth_sign(); rc |= do_auth_decrypt(); 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); testcase_setup(); rv = do_always_auth_tests(); if (rv != CKR_OK) goto finalize; rv = funcs->C_Finalize(NULL); if (rv != CKR_OK) { testcase_fail("C_Finalize rc = %s", p11_get_ckr(rv)); goto out; } rv = 0; goto out; finalize: rv = funcs->C_Finalize(NULL); if (rv != CKR_OK) { testcase_fail("C_Finalize rc = %s", p11_get_ckr(rv)); rv = 1; } out: testcase_print_result(); return testcase_return(rv); } opencryptoki-opencryptoki-451d99c/testcases/misc_tests/cca_ep11_export_import_test.c000066400000000000000000004022731520105705100312610ustar00rootroot00000000000000/* * 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 * * import/export test for the CCA and EP11 token * by Harald Freudenberger */ #include #include #include #include #include #include "platform.h" #include "pkcs11types.h" #include "ec_curves.h" #include "mechtable.h" #include "mech_to_str.h" #include "regress.h" #include "common.c" /** Create an AES key handle with given value **/ CK_RV create_cca_ep11_AESKey(CK_SESSION_HANDLE session, CK_BBOOL extractable, unsigned char key[], unsigned char key_len, CK_KEY_TYPE keyType, CK_IBM_CCA_AES_KEY_MODE_TYPE mode, CK_OBJECT_HANDLE * h_key, int is_cca) { CK_RV rc; CK_BBOOL true = TRUE; CK_BBOOL false = FALSE; CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY; CK_BBOOL pkeyextractable = !extractable; CK_ATTRIBUTE keyTemplate[] = { {CKA_EXTRACTABLE, &extractable, sizeof(CK_BBOOL)}, {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}, {CKA_IBM_PROTKEY_EXTRACTABLE, &pkeyextractable, sizeof(CK_BBOOL)}, {CKA_IBM_CCA_AES_KEY_MODE, &mode, sizeof(mode)}, }; CK_ULONG keyTemplate_len = sizeof(keyTemplate) / sizeof(CK_ATTRIBUTE); if (!is_cca) keyTemplate_len--; if (combined_extract) pkeyextractable = CK_TRUE; rc = funcs->C_CreateObject(session, keyTemplate, keyTemplate_len, h_key); if (rc != CKR_OK) { if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); } return rc; } static CK_RV extract_restrict(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE handle) { CK_RV rc; CK_BBOOL ck_false = FALSE; CK_ATTRIBUTE a_extract = { CKA_EXTRACTABLE, &ck_false, sizeof(ck_false) }; rc = funcs->C_SetAttributeValue(session, handle, &a_extract, 1); if (rc != CKR_OK) { testcase_error("C_SetAttributeValue() rc=%s", p11_get_ckr(rc)); return rc; } return CKR_OK; } static CK_RV convert_to_cipher_key(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE handle) { CK_RV rc; CK_IBM_CCA_AES_KEY_MODE_TYPE mode = CK_IBM_CCA_AES_CIPHER_KEY; CK_ATTRIBUTE a_extract = { CKA_IBM_CCA_AES_KEY_MODE, &mode, sizeof(mode) }; rc = funcs->C_SetAttributeValue(session, handle, &a_extract, 1); if (rc != CKR_OK) { testcase_error("C_SetAttributeValue() rc=%s", p11_get_ckr(rc)); return rc; } return CKR_OK; } static CK_RV export_ibm_opaque(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE handle, CK_BYTE **buf, CK_ULONG *buflen) { CK_RV rc; CK_ULONG len; CK_ATTRIBUTE a_opaque = { CKA_IBM_OPAQUE, NULL_PTR, 0 }; rc = funcs->C_GetAttributeValue(session, handle, &a_opaque, 1); if (rc != CKR_OK) { testcase_error("C_GetAttributeValue() rc=%s", p11_get_ckr(rc)); return rc; } len = a_opaque.ulValueLen; if (!len) { testcase_error("opaque attribute len is 0"); return CKR_ATTRIBUTE_VALUE_INVALID; } a_opaque.pValue = malloc(len); if (!a_opaque.pValue) { testcase_error("malloc(%lu) failed", len); return CKR_HOST_MEMORY; } rc = funcs->C_GetAttributeValue(session, handle, &a_opaque, 1); if (rc != CKR_OK) { testcase_error("C_GetAttributeValue() rc=%s", p11_get_ckr(rc)); return rc; } *buf = a_opaque.pValue; *buflen = len; return CKR_OK; } static CK_RV import_des_key(CK_SESSION_HANDLE session, const char *label, CK_BYTE *blob, CK_ULONG bloblen, CK_OBJECT_HANDLE *handle) { CK_RV rc; CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY; CK_KEY_TYPE keyType = CKK_DES; CK_BBOOL true = TRUE; CK_BBOOL false = FALSE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &keyClass, sizeof(keyClass)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_LABEL, (char *) label, strlen(label) + 1}, {CKA_ENCRYPT, &true, sizeof(true)}, {CKA_TOKEN, &false, sizeof(false)}, {CKA_IBM_OPAQUE, blob, bloblen} }; CK_ULONG nattr = sizeof(template) / sizeof(CK_ATTRIBUTE); rc = funcs->C_CreateObject(session, template, nattr, handle); if (rc != CKR_OK) { testcase_error("C_CreateObject() rc=%s", p11_get_ckr(rc)); } return rc; } static CK_RV import_des3_key(CK_SESSION_HANDLE session, const char *label, CK_BYTE *blob, CK_ULONG bloblen, CK_OBJECT_HANDLE *handle) { CK_RV rc; CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY; CK_KEY_TYPE keyType = CKK_DES3; CK_BBOOL true = TRUE; CK_BBOOL false = FALSE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &keyClass, sizeof(keyClass)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_LABEL, (char *) label, strlen(label) + 1}, {CKA_ENCRYPT, &true, sizeof(true)}, {CKA_TOKEN, &false, sizeof(false)}, {CKA_IBM_OPAQUE, blob, bloblen} }; CK_ULONG nattr = sizeof(template) / sizeof(CK_ATTRIBUTE); rc = funcs->C_CreateObject(session, template, nattr, handle); if (rc != CKR_OK) { testcase_error("C_CreateObject() rc=%s", p11_get_ckr(rc)); } return rc; } static CK_RV import_aes_key(CK_SESSION_HANDLE session, const char *label, CK_BYTE *blob, CK_ULONG bloblen, CK_OBJECT_HANDLE *handle, CK_KEY_TYPE keyType, CK_IBM_CCA_AES_KEY_MODE_TYPE exp_mode, int is_cca) { CK_RV rc; CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY; CK_BBOOL true = TRUE; CK_BBOOL false = FALSE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &keyClass, sizeof(keyClass)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_LABEL, (char *) label, strlen(label) + 1}, {CKA_ENCRYPT, &true, sizeof(true)}, {CKA_TOKEN, &false, sizeof(false)}, {CKA_IBM_OPAQUE, blob, bloblen}, }; CK_ULONG nattr = sizeof(template) / sizeof(CK_ATTRIBUTE); CK_IBM_CCA_AES_KEY_MODE_TYPE mode; CK_ATTRIBUTE a_mode = { CKA_IBM_CCA_AES_KEY_MODE, &mode, sizeof(mode) }; rc = funcs->C_CreateObject(session, template, nattr, handle); if (rc != CKR_OK) { testcase_error("C_CreateObject() rc=%s", p11_get_ckr(rc)); goto out; } if (is_cca) { rc = funcs->C_GetAttributeValue(session, *handle, &a_mode, 1); if (rc != CKR_OK) { testcase_error("C_GetAttributeValue() rc=%s", p11_get_ckr(rc)); goto out; } if (mode != exp_mode) { testcase_error("CCA key mode not as expected (%lu != %lu)", mode, exp_mode); rc = CKR_ATTRIBUTE_VALUE_INVALID; goto out; } } out: return rc; } static CK_RV import_gen_sec_key(CK_SESSION_HANDLE session, const char *label, CK_KEY_TYPE keyType, CK_BYTE *blob, CK_ULONG bloblen, unsigned int keybitsize, CK_OBJECT_HANDLE *handle, int is_cca) { CK_RV rc; CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY; CK_BYTE value[512]; CK_BBOOL true = TRUE; CK_BBOOL false = FALSE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &keyClass, sizeof(keyClass)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_LABEL, (char *) label, strlen(label) + 1}, {CKA_SIGN, &true, sizeof(true)}, {CKA_VERIFY, &true, sizeof(true)}, {CKA_TOKEN, &false, sizeof(false)}, {CKA_IBM_OPAQUE, blob, bloblen}, {CKA_VALUE, value, sizeof(value)}, }; CK_ULONG nattr = sizeof(template) / sizeof(CK_ATTRIBUTE); unsigned pl, calc_pl; memset(value, 0, sizeof(value)); // CCA/EP11 only supports hmac key in range 80...2048 if (keybitsize < 80 || keybitsize > 2048) { testcase_error("invalid keybitsize %u", keybitsize); return CKR_ATTRIBUTE_VALUE_INVALID; } if (is_cca) { // calculate expected payloadbitsize based on keybitsize calc_pl = (((keybitsize + 32) + 63) & (~63)) + 320; // pull payloadbitsize from the cca hmac blob pl = be16toh(*((uint16_t *)(blob + 38))); if (calc_pl != pl) { testcase_error("mismatch keybitsize %u - expected pl bitsize %u / cca pl bitsize %u", keybitsize, calc_pl, pl); return CKR_ATTRIBUTE_VALUE_INVALID; } template[7].ulValueLen = (keybitsize + 7) / 8; } else { nattr--; } rc = funcs->C_CreateObject(session, template, nattr, handle); if (rc != CKR_OK) { testcase_error("C_CreateObject() rc=%s", p11_get_ckr(rc)); } return rc; } static CK_RV import_rsa_priv_key(CK_SESSION_HANDLE session, const char *label, CK_BYTE *blob, CK_ULONG bloblen, CK_OBJECT_HANDLE *handle) { CK_RV rc; CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY; CK_KEY_TYPE keyType = CKK_RSA; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &keyClass, sizeof(keyClass)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_LABEL, (char *) label, strlen(label) + 1}, {CKA_SIGN, &true, sizeof(true)}, {CKA_DECRYPT, &true, sizeof(true)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_PRIVATE, &true, sizeof(true)}, {CKA_IBM_OPAQUE, blob, bloblen} }; CK_ULONG nattr = sizeof(template) / sizeof(CK_ATTRIBUTE); rc = funcs->C_CreateObject(session, template, nattr, handle); if (rc != CKR_OK && rc != CKR_PUBLIC_KEY_INVALID) { testcase_error("C_CreateObject() rc=%s", p11_get_ckr(rc)); } return rc; } static CK_RV import_rsa_publ_key(CK_SESSION_HANDLE session, const char *label, CK_BYTE *blob, CK_ULONG bloblen, CK_OBJECT_HANDLE *handle) { CK_RV rc; CK_OBJECT_CLASS keyClass = CKO_PUBLIC_KEY; CK_KEY_TYPE keyType = CKK_RSA; CK_BBOOL true = TRUE; CK_BBOOL false = FALSE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &keyClass, sizeof(keyClass)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_LABEL, (char *) label, strlen(label) + 1}, {CKA_VERIFY, &true, sizeof(true)}, {CKA_ENCRYPT, &true, sizeof(true)}, {CKA_TOKEN, &false, sizeof(false)}, {CKA_PRIVATE, &false, sizeof(false)}, {CKA_IBM_OPAQUE, blob, bloblen} }; CK_ULONG nattr = sizeof(template) / sizeof(CK_ATTRIBUTE); rc = funcs->C_CreateObject(session, template, nattr, handle); if (rc != CKR_OK && rc != CKR_PUBLIC_KEY_INVALID) { testcase_error("C_CreateObject() rc=%s", p11_get_ckr(rc)); } return rc; } static CK_RV import_ecc_priv_key(CK_SESSION_HANDLE session, CK_KEY_TYPE keyType,const char *label, CK_BYTE *blob, CK_ULONG bloblen, CK_OBJECT_HANDLE *handle) { CK_RV rc; CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &keyClass, sizeof(keyClass)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_LABEL, (char *) label, strlen(label) + 1}, {CKA_SIGN, &true, sizeof(true)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_PRIVATE, &true, sizeof(true)}, {CKA_IBM_OPAQUE, blob, bloblen} }; CK_ULONG nattr = sizeof(template) / sizeof(CK_ATTRIBUTE); rc = funcs->C_CreateObject(session, template, nattr, handle); if (rc != CKR_OK && rc != CKR_PUBLIC_KEY_INVALID) { testcase_error("C_CreateObject() rc=%s", p11_get_ckr(rc)); } return rc; } static CK_RV import_ecc_publ_key(CK_SESSION_HANDLE session, CK_KEY_TYPE keyType, const char *label, CK_BYTE *blob, CK_ULONG bloblen, CK_OBJECT_HANDLE *handle) { CK_RV rc; CK_OBJECT_CLASS keyClass = CKO_PUBLIC_KEY; CK_BBOOL true = TRUE; CK_BBOOL false = FALSE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &keyClass, sizeof(keyClass)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_LABEL, (char *) label, strlen(label) + 1}, {CKA_VERIFY, &true, sizeof(true)}, {CKA_TOKEN, &false, sizeof(false)}, {CKA_PRIVATE, &false, sizeof(false)}, {CKA_IBM_OPAQUE, blob, bloblen} }; CK_ULONG nattr = sizeof(template) / sizeof(CK_ATTRIBUTE); rc = funcs->C_CreateObject(session, template, nattr, handle); if (rc != CKR_OK && rc != CKR_PUBLIC_KEY_INVALID) { testcase_error("C_CreateObject() rc=%s", p11_get_ckr(rc)); } return rc; } static CK_RV import_ml_dsa_priv_key(CK_SESSION_HANDLE session, CK_KEY_TYPE keyType, const char *label, CK_BYTE *blob, CK_ULONG bloblen, CK_OBJECT_HANDLE *handle) { CK_RV rc; CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &keyClass, sizeof(keyClass)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_LABEL, (char *) label, strlen(label) + 1}, {CKA_SIGN, &true, sizeof(true)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_PRIVATE, &true, sizeof(true)}, {CKA_IBM_OPAQUE, blob, bloblen} }; CK_ULONG nattr = sizeof(template) / sizeof(CK_ATTRIBUTE); rc = funcs->C_CreateObject(session, template, nattr, handle); if (rc != CKR_OK && rc != CKR_PUBLIC_KEY_INVALID) { testcase_error("C_CreateObject() rc=%s", p11_get_ckr(rc)); } return rc; } static CK_RV import_ml_dsa_publ_key(CK_SESSION_HANDLE session, CK_KEY_TYPE keyType, const char *label, CK_BYTE *blob, CK_ULONG bloblen, CK_OBJECT_HANDLE *handle) { CK_RV rc; CK_OBJECT_CLASS keyClass = CKO_PUBLIC_KEY; CK_BBOOL true = TRUE; CK_BBOOL false = FALSE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &keyClass, sizeof(keyClass)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_LABEL, (char *) label, strlen(label) + 1}, {CKA_VERIFY, &true, sizeof(true)}, {CKA_TOKEN, &false, sizeof(false)}, {CKA_PRIVATE, &false, sizeof(false)}, {CKA_IBM_OPAQUE, blob, bloblen} }; CK_ULONG nattr = sizeof(template) / sizeof(CK_ATTRIBUTE); rc = funcs->C_CreateObject(session, template, nattr, handle); if (rc != CKR_OK && rc != CKR_PUBLIC_KEY_INVALID) { testcase_error("C_CreateObject() rc=%s", p11_get_ckr(rc)); } return rc; } static CK_RV import_ml_kem_priv_key(CK_SESSION_HANDLE session, CK_KEY_TYPE keyType, const char *label, CK_BYTE *blob, CK_ULONG bloblen, CK_OBJECT_HANDLE *handle) { CK_RV rc; CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &keyClass, sizeof(keyClass)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_LABEL, (char *) label, strlen(label) + 1}, {keyType == CKK_ML_KEM ? CKA_DECAPSULATE : CKA_DERIVE, &true, sizeof(true)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_PRIVATE, &true, sizeof(true)}, {CKA_IBM_OPAQUE, blob, bloblen} }; CK_ULONG nattr = sizeof(template) / sizeof(CK_ATTRIBUTE); rc = funcs->C_CreateObject(session, template, nattr, handle); if (rc != CKR_OK && rc != CKR_PUBLIC_KEY_INVALID) { testcase_error("C_CreateObject() rc=%s", p11_get_ckr(rc)); } return rc; } static CK_RV import_ml_kem_publ_key(CK_SESSION_HANDLE session, CK_KEY_TYPE keyType, const char *label, CK_BYTE *blob, CK_ULONG bloblen, CK_OBJECT_HANDLE *handle) { CK_RV rc; CK_OBJECT_CLASS keyClass = CKO_PUBLIC_KEY; CK_BBOOL true = TRUE; CK_BBOOL false = FALSE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &keyClass, sizeof(keyClass)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_LABEL, (char *) label, strlen(label) + 1}, {keyType == CKK_ML_KEM ? CKA_ENCAPSULATE : CKA_DERIVE, &true, sizeof(true)}, {CKA_TOKEN, &false, sizeof(false)}, {CKA_PRIVATE, &false, sizeof(false)}, {CKA_IBM_OPAQUE, blob, bloblen} }; CK_ULONG nattr = sizeof(template) / sizeof(CK_ATTRIBUTE); rc = funcs->C_CreateObject(session, template, nattr, handle); if (rc != CKR_OK && rc != CKR_PUBLIC_KEY_INVALID) { testcase_error("C_CreateObject() rc=%s", p11_get_ckr(rc)); } return rc; } static CK_RV des_export_import_tests(void) { const char *tstr = "CCA/EP11 export/import test with DES key"; CK_RV rc = CKR_OK; CK_FLAGS flags; CK_SESSION_HANDLE session; CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; CK_ULONG user_pin_len; CK_BYTE key[] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }; CK_BYTE iv[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }; CK_MECHANISM mech = { CKM_DES_CBC, iv, sizeof(iv) }; CK_OBJECT_HANDLE hkey = CK_INVALID_HANDLE, hikey = CK_INVALID_HANDLE; CK_BYTE data[80], encdata1[80], encdata2[80]; CK_ULONG ilen, len; CK_BYTE *opaquekey = NULL; CK_ULONG opaquekeylen; char label[80]; testcase_begin("%s", tstr); if (!is_cca_token(SLOT_ID) && !is_ep11_token(SLOT_ID)) { testcase_skip("%s: this slot is not a CCA or EP11 token", tstr); goto out; } if (!mech_supported(SLOT_ID, CKM_DES_KEY_GEN)) { testcase_skip("this slot does not support CKM_DES_KEY_GEN"); goto out; } testcase_rw_session(); testcase_user_login(); // create ock des key rc = create_DESKey(session, key, sizeof(key), &hkey); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("DES key generation is not allowed by policy"); goto testcase_cleanup; } testcase_error("create_DESKey() rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } // encrypt some data with this key rc = funcs->C_EncryptInit(session, &mech, hkey); if (rc != CKR_OK) { testcase_error("C_EncryptInit rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } ilen = len = sizeof(data); rc = funcs->C_Encrypt(session, data, ilen, encdata1, &len); if (rc != CKR_OK) { testcase_error("C_Encrypt rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } if (ilen != len) { testcase_fail("plain and encrypted data len does not match"); goto testcase_cleanup; } testcase_new_assertion(); // export this key's CCA/EP11 blob rc = export_ibm_opaque(session, hkey, &opaquekey, &opaquekeylen); if (rc != CKR_OK) { testcase_fail("export_ibm_opaque rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } // re-import this CCA/EP11 blob as a new key object snprintf(label, sizeof(label), "re-imported_des_key"); rc = import_des_key(session, label, opaquekey, opaquekeylen, &hikey); if (rc != CKR_OK) { testcase_fail("import_des_key rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } // encrypt same data with this re-imported key rc = funcs->C_EncryptInit(session, &mech, hikey); if (rc != CKR_OK) { testcase_error("C_EncryptInit rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } ilen = len = sizeof(data); rc = funcs->C_Encrypt(session, data, ilen, encdata2, &len); if (rc != CKR_OK) { testcase_error("C_Encrypt rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } if (ilen != len) { testcase_fail("plain and encrypted data len does not match"); goto testcase_cleanup; } // and check the encrypted data to be equal if (memcmp(encdata1, encdata2, len) != 0) { testcase_fail("encrypted data from original and exported/imported key is NOT the same"); goto testcase_cleanup; } testcase_pass("%s: ok", tstr); testcase_cleanup: if (hkey != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, hkey); if (hikey != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, hikey); testcase_close_session(); free(opaquekey); out: return rc; } static CK_RV des3_export_import_tests(void) { const char *tstr = "CCA/EP11 export/import test with DES3 data key"; CK_RV rc = CKR_OK; CK_FLAGS flags; CK_SESSION_HANDLE session; CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; CK_ULONG user_pin_len; CK_BYTE 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 }; CK_BYTE iv[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }; CK_MECHANISM mech = { CKM_DES3_CBC, iv, sizeof(iv) }; CK_OBJECT_HANDLE hkey = CK_INVALID_HANDLE, hikey = CK_INVALID_HANDLE; CK_BYTE data[80], encdata1[80], encdata2[80]; CK_ULONG ilen, len; CK_BYTE *opaquekey = NULL; CK_ULONG opaquekeylen; char label[80]; testcase_begin("%s", tstr); if (!is_cca_token(SLOT_ID) && !is_ep11_token(SLOT_ID)) { testcase_skip("%s: this slot is not a CCA or EP11 token", tstr); goto out; } if (!mech_supported(SLOT_ID, CKM_DES3_KEY_GEN)) { testcase_skip("this slot does not support CKM_DES3_KEY_GEN"); goto out; } testcase_rw_session(); testcase_user_login(); // create ock 3des key rc = create_DES3Key(session, key, sizeof(key), &hkey); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("DES3 key generation is not allowed by policy"); goto testcase_cleanup; } testcase_error("create_DES3Key() rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } // encrypt some data with this key rc = funcs->C_EncryptInit(session, &mech, hkey); if (rc != CKR_OK) { testcase_error("C_EncryptInit rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } ilen = len = sizeof(data); rc = funcs->C_Encrypt(session, data, ilen, encdata1, &len); if (rc != CKR_OK) { testcase_error("C_Encrypt rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } if (ilen != len) { testcase_fail("plain and encrypted data len does not match"); goto testcase_cleanup; } testcase_new_assertion(); // export this key's CCA/EP11 blob rc = export_ibm_opaque(session, hkey, &opaquekey, &opaquekeylen); if (rc != CKR_OK) { testcase_fail("export_ibm_opaque rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } // re-import this CCA/EP11 blob as a new key object snprintf(label, sizeof(label), "re-imported_des3_key"); rc = import_des3_key(session, label, opaquekey, opaquekeylen, &hikey); if (rc != CKR_OK) { testcase_fail("import_des3_key rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } // encrypt same data with this re-imported key rc = funcs->C_EncryptInit(session, &mech, hikey); if (rc != CKR_OK) { testcase_error("C_EncryptInit rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } ilen = len = sizeof(data); rc = funcs->C_Encrypt(session, data, ilen, encdata2, &len); if (rc != CKR_OK) { testcase_error("C_Encrypt rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } if (ilen != len) { testcase_fail("plain and encrypted data len does not match"); goto testcase_cleanup; } // and check the encrypted data to be equal if (memcmp(encdata1, encdata2, len) != 0) { testcase_fail("encrypted data from original and exported/imported key is NOT the same"); goto testcase_cleanup; } testcase_pass("%s: ok", tstr); testcase_cleanup: if (hkey != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, hkey); if (hikey != CK_INVALID_HANDLE) funcs->C_DestroyObject(session, hikey); testcase_close_session(); free(opaquekey); out: return rc; } static CK_RV aes_export_import_tests(CK_IBM_CCA_AES_KEY_MODE_TYPE mode) { CK_RV rc = CKR_OK; CK_FLAGS flags; CK_SESSION_HANDLE session; CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; CK_ULONG user_pin_len; CK_BYTE 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 }; CK_BYTE iv[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; CK_MECHANISM mech = { CKM_AES_CBC, iv, sizeof(iv) }; CK_OBJECT_HANDLE hkey = CK_INVALID_HANDLE, hikey = CK_INVALID_HANDLE; CK_BYTE data[160], encdata1[160], encdata2[160], encdata3[160];; CK_ULONG ilen, len; CK_BYTE *opaquekey = NULL; CK_ULONG opaquekeylen; unsigned int keylen; char label[80]; int is_cca = is_cca_token(SLOT_ID); if (!is_cca && !is_ep11_token(SLOT_ID)) { testcase_skip("this slot is not a CCA or EP11 token"); goto out; } if (!mech_supported(SLOT_ID, CKM_AES_KEY_GEN)) { testcase_skip("this slot does not support CKM_AES_KEY_GEN"); goto out; } if (!is_cca && mode != CK_IBM_CCA_AES_DATA_KEY) goto out; testcase_rw_session(); testcase_user_login(); for (keylen = 16; keylen <= 32; keylen += 8) { testcase_begin("CCA/EP11 export/import test with AES-%u %s key", 8 * keylen, is_cca ? (mode == CK_IBM_CCA_AES_DATA_KEY ? "DATA" : "CIPHER") : "EP11"); // create ock aes key rc = create_cca_ep11_AESKey(session, CK_TRUE, key, keylen, CKK_AES, mode, &hkey, is_cca); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("AES key generation is not allowed by policy"); continue; } testcase_error("create_cca_ep11_AESKey() rc=%s", p11_get_ckr(rc)); goto error; } // encrypt some data with this key rc = funcs->C_EncryptInit(session, &mech, hkey); if (rc != CKR_OK) { testcase_error("C_EncryptInit rc=%s", p11_get_ckr(rc)); goto error; } ilen = len = sizeof(data); rc = funcs->C_Encrypt(session, data, ilen, encdata1, &len); if (rc != CKR_OK) { testcase_error("C_Encrypt rc=%s", p11_get_ckr(rc)); goto error; } if (ilen != len) { testcase_fail("plain and encrypted data len does not match"); goto error; } testcase_new_assertion(); // export this key's CCA/EP11 blob rc = export_ibm_opaque(session, hkey, &opaquekey, &opaquekeylen); if (rc != CKR_OK) { testcase_fail("export_ibm_opaque rc=%s", p11_get_ckr(rc)); goto error; } // re-import this CCA/EP11 blob as a new key object snprintf(label, sizeof(label), "re-imported_aes%u_key", 8 * keylen); rc = import_aes_key(session, label, opaquekey, opaquekeylen, &hikey, CKK_AES, mode, is_cca); if (rc != CKR_OK) { testcase_fail("import_aes_key rc=%s", p11_get_ckr(rc)); goto error; } // encrypt same data with this re-imported key rc = funcs->C_EncryptInit(session, &mech, hikey); if (rc != CKR_OK) { testcase_error("C_EncryptInit rc=%s", p11_get_ckr(rc)); goto error; } ilen = len = sizeof(data); rc = funcs->C_Encrypt(session, data, ilen, encdata2, &len); if (rc != CKR_OK) { testcase_error("C_Encrypt rc=%s", p11_get_ckr(rc)); goto error; } if (ilen != len) { testcase_fail("plain and encrypted data len does not match"); goto error; } // and check the encrypted data to be equal if (memcmp(encdata1, encdata2, len) != 0) { testcase_fail("encrypted data from original and exported/imported key is NOT the same"); goto error; } if (is_cca) { /* Set extractable to FALSE on original key */ rc = extract_restrict(session, hkey); if (rc != CKR_OK) { testcase_fail("extract_restrict rc=%s", p11_get_ckr(rc)); goto error; } /* Convert to CIPHER key */ rc = convert_to_cipher_key(session, hkey); if (rc != CKR_OK) { testcase_fail("convert_to_cipher_key rc=%s", p11_get_ckr(rc)); goto error; } /* encrypt some data with this converted key */ rc = funcs->C_EncryptInit(session, &mech, hkey); if (rc != CKR_OK) { testcase_error("C_EncryptInit rc=%s", p11_get_ckr(rc)); goto error; } ilen = len = sizeof(data); rc = funcs->C_Encrypt(session, data, ilen, encdata3, &len); if (rc != CKR_OK) { testcase_error("C_Encrypt rc=%s", p11_get_ckr(rc)); goto error; } if (ilen != len) { testcase_fail("plain and encrypted data len does not match"); goto error; } /* and check the encrypted data to be equal */ if (memcmp(encdata1, encdata3, len) != 0) { testcase_fail("encrypted data from original and converted key is NOT the same"); goto error; } } testcase_pass("CCA/EP11 export/import test with AES-%u %s key: ok", 8 * keylen, is_cca ? (mode == CK_IBM_CCA_AES_DATA_KEY ? "DATA" : "CIPHER") : "EP11"); error: free(opaquekey); opaquekey = NULL; if (hkey != CK_INVALID_HANDLE) { funcs->C_DestroyObject(session, hkey); hkey = CK_INVALID_HANDLE; } if (hikey != CK_INVALID_HANDLE) { funcs->C_DestroyObject(session, hikey); hikey = CK_INVALID_HANDLE; } } testcase_cleanup: testcase_close_session(); out: return rc; } static CK_RV aes_xts_export_import_tests(CK_IBM_CCA_AES_KEY_MODE_TYPE mode) { CK_RV rc = CKR_OK; CK_FLAGS flags; CK_SESSION_HANDLE session; CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; CK_ULONG user_pin_len; CK_BYTE 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, 0x61, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2c, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, 0x1e, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2e, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4 }; CK_BYTE iv[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; CK_MECHANISM mech = { CKM_AES_XTS, iv, sizeof(iv) }; CK_OBJECT_HANDLE hkey = CK_INVALID_HANDLE, hikey = CK_INVALID_HANDLE; CK_BYTE data[160], encdata1[160], encdata2[160], encdata3[160];; CK_ULONG ilen, len; CK_BYTE *opaquekey = NULL; CK_ULONG opaquekeylen; unsigned int keylen; char label[80]; int is_cca = is_cca_token(SLOT_ID); if (!is_cca && !is_ep11_token(SLOT_ID)) { testcase_skip("this slot is not a CCA or EP11 token"); goto out; } if (!mech_supported(SLOT_ID, CKM_AES_XTS_KEY_GEN)) { testcase_skip("this slot does not support AES-XTS"); goto out; } if (!is_cca && mode != CK_IBM_CCA_AES_DATA_KEY) goto out; testcase_rw_session(); testcase_user_login(); for (keylen = 32; keylen <= 64; keylen += 32) { testcase_begin("CCA export/import test with AES-XTS-%u %s key", 8 * keylen / 2, is_cca ? (mode == CK_IBM_CCA_AES_DATA_KEY ? "DATA" : "CIPHER") : "EP11"); // create ock aes key rc = create_cca_ep11_AESKey(session, CK_FALSE, key, keylen, CKK_AES_XTS, mode, &hkey, is_cca); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("AES-XTS key generation is not allowed by policy"); continue; } testcase_error("create_cca_ep11_AESKey() rc=%s", p11_get_ckr(rc)); goto error; } // encrypt some data with this key rc = funcs->C_EncryptInit(session, &mech, hkey); if (rc != CKR_OK) { testcase_error("C_EncryptInit rc=%s", p11_get_ckr(rc)); goto error; } ilen = len = sizeof(data); rc = funcs->C_Encrypt(session, data, ilen, encdata1, &len); if (rc != CKR_OK) { testcase_error("C_Encrypt rc=%s", p11_get_ckr(rc)); goto error; } if (ilen != len) { testcase_fail("plain and encrypted data len does not match"); goto error; } testcase_new_assertion(); // export this key's CCA/EP11 blob rc = export_ibm_opaque(session, hkey, &opaquekey, &opaquekeylen); if (rc != CKR_OK) { testcase_fail("export_ibm_opaque rc=%s", p11_get_ckr(rc)); goto error; } // re-import this CCA/EP11 blob as a new key object snprintf(label, sizeof(label), "re-imported_aes-xts-%u_key", 8 * keylen / 8); rc = import_aes_key(session, label, opaquekey, opaquekeylen, &hikey, CKK_AES_XTS, mode, is_cca); if (rc != CKR_OK) { testcase_fail("import_aes_key rc=%s", p11_get_ckr(rc)); goto error; } // encrypt same data with this re-imported key rc = funcs->C_EncryptInit(session, &mech, hikey); if (rc != CKR_OK) { testcase_error("C_EncryptInit rc=%s", p11_get_ckr(rc)); goto error; } ilen = len = sizeof(data); rc = funcs->C_Encrypt(session, data, ilen, encdata2, &len); if (rc != CKR_OK) { testcase_error("C_Encrypt rc=%s", p11_get_ckr(rc)); goto error; } if (ilen != len) { testcase_fail("plain and encrypted data len does not match"); goto error; } // and check the encrypted data to be equal if (memcmp(encdata1, encdata2, len) != 0) { testcase_fail("encrypted data from original and exported/imported key is NOT the same"); goto error; } if (is_cca) { /* Set extractable to FALSE on original key */ rc = extract_restrict(session, hkey); if (rc != CKR_OK) { testcase_fail("extract_restrict rc=%s", p11_get_ckr(rc)); goto error; } /* Convert to CIPHER key */ rc = convert_to_cipher_key(session, hkey); if (rc != CKR_OK) { testcase_fail("extract_restrict rc=%s", p11_get_ckr(rc)); goto error; } /* encrypt some data with this converted key */ rc = funcs->C_EncryptInit(session, &mech, hkey); if (rc != CKR_OK) { testcase_error("C_EncryptInit rc=%s", p11_get_ckr(rc)); goto error; } ilen = len = sizeof(data); rc = funcs->C_Encrypt(session, data, ilen, encdata3, &len); if (rc != CKR_OK) { testcase_error("C_Encrypt rc=%s", p11_get_ckr(rc)); goto error; } if (ilen != len) { testcase_fail("plain and encrypted data len does not match"); goto error; } /* and check the encrypted data to be equal */ if (memcmp(encdata1, encdata3, len) != 0) { testcase_fail("encrypted data from original and converted key is NOT the same"); goto error; } } testcase_pass("CCA/EP11 export/import test with AES-XTS-%u %s key: ok", 8 * keylen / 2, is_cca ? (mode == CK_IBM_CCA_AES_DATA_KEY ? "DATA" : "CIPHER") : "EP11"); error: free(opaquekey); opaquekey = NULL; if (hkey != CK_INVALID_HANDLE) { funcs->C_DestroyObject(session, hkey); hkey = CK_INVALID_HANDLE; } if (hikey != CK_INVALID_HANDLE) { funcs->C_DestroyObject(session, hikey); hikey = CK_INVALID_HANDLE; } } testcase_cleanup: testcase_close_session(); out: return rc; } static CK_RV generic_secret_export_import_tests(void) { CK_RV rc = CKR_OK; CK_FLAGS flags; CK_SESSION_HANDLE session; CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; CK_ULONG user_pin_len; CK_BYTE key[512] = { 0x00 }; CK_OBJECT_HANDLE hkey = CK_INVALID_HANDLE, hikey = CK_INVALID_HANDLE; CK_BYTE data[4096], mac1[4096], mac2[4096]; CK_BYTE *opaquekey = NULL; CK_ULONG mac1len, mac2len, opaquekeylen; unsigned int i, k, keybits[] = { 80, 160, 320, 640, 1024, 2048, 0 }; char label[80]; int is_cca = is_cca_token(SLOT_ID); static struct hmac_mech_info { const char *name; CK_KEY_TYPE keytype; CK_MECHANISM_TYPE keygen_mech; CK_ULONG min_key_size; CK_MECHANISM hmac_mech; } hmac_mechs[] = { { "generic secret", CKK_GENERIC_SECRET, CKM_GENERIC_SECRET_KEY_GEN, 20, { CKM_SHA_1_HMAC, 0, 0 } }, { "sha-1-hmac", CKK_SHA_1_HMAC, CKM_SHA_1_KEY_GEN, 20, { CKM_SHA_1_HMAC, 0, 0 } }, { "sha256-hmac", CKK_SHA256_HMAC, CKM_SHA256_KEY_GEN, 32, { CKM_SHA256_HMAC, 0, 0 } }, { "sha3-256-hmac", CKK_SHA3_256_HMAC, CKM_SHA3_256_KEY_GEN, 32, { CKM_SHA3_256_HMAC, 0, 0 } }, }; if (!is_cca && !is_ep11_token(SLOT_ID)) { testcase_skip("this slot is not a CCA or EP11 token"); goto out; } testcase_rw_session(); testcase_user_login(); for (k = 0; k < sizeof(hmac_mechs) / sizeof(struct hmac_mech_info); k++) { for (i = 0; keybits[i]; i++) { if (keybits[i] < hmac_mechs[k].min_key_size * 8) continue; if (!mech_supported(SLOT_ID, hmac_mechs[k].hmac_mech.mechanism)) { testcase_skip("this slot does not support %s", mech_to_str(hmac_mechs[k].hmac_mech.mechanism)); continue; } if (!mech_supported(SLOT_ID, hmac_mechs[k].keygen_mech)) { testcase_skip("this slot does not support %s", mech_to_str(hmac_mechs[k].keygen_mech)); continue; } testcase_begin("CCA/EP11 export/import test with %s key %u", hmac_mechs[k].name, keybits[i]); // create hmac key rc = create_GenericSecretKey(session, hmac_mechs[k].keytype, key, keybits[i] / 8, &hkey); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("%s key import is not allowed by policy", hmac_mechs[k].name); continue; } testcase_error("create_GenericSecretKey() rc=%s", p11_get_ckr(rc)); goto error; } // sign data with original hmac key rc = funcs->C_SignInit(session, &hmac_mechs[k].hmac_mech, hkey); if (rc != CKR_OK) { testcase_error("C_SignInit rc=%s", p11_get_ckr(rc)); goto error; } mac1len = sizeof(mac1); rc = funcs->C_Sign(session, data, sizeof(data), mac1, &mac1len); if (rc != CKR_OK) { testcase_error("C_Sign rc=%s", p11_get_ckr(rc)); goto error; } testcase_new_assertion(); // export this key's CCA/EP11 blob rc = export_ibm_opaque(session, hkey, &opaquekey, &opaquekeylen); if (rc != CKR_OK) { testcase_fail("export_ibm_opaque rc=%s", p11_get_ckr(rc)); goto error; } if (is_cca) { /* Set extractable to FALSE */ rc = extract_restrict(session, hkey); if (rc != CKR_OK) { testcase_fail("extract_restrict rc=%s", p11_get_ckr(rc)); goto error; } } // re-import this CCA/EP11 blob as a new key object snprintf(label, sizeof(label), "re-imported_hmac%u_key", keybits[i]); rc = import_gen_sec_key(session, label, hmac_mechs[k].keytype, opaquekey, opaquekeylen, keybits[i], &hikey, is_cca); if (rc != CKR_OK) { testcase_fail("import_gen_sec_key rc=%s", p11_get_ckr(rc)); goto error; } // sign data with re-imported hmac key rc = funcs->C_SignInit(session, &hmac_mechs[k].hmac_mech, hikey); if (rc != CKR_OK) { testcase_error("C_SignInit with re-imported key failed, rc=%s", p11_get_ckr(rc)); goto error; } mac2len = sizeof(mac2); rc = funcs->C_Sign(session, data, sizeof(data), mac2, &mac2len); if (rc != CKR_OK) { testcase_error("C_Sign with re-imported key failed, rc=%s", p11_get_ckr(rc)); goto error; } // compare the two signatures if (mac1len != mac2len) { testcase_fail("mac len with orig key %lu differs from mac len " "with re-imported key %lu", mac1len, mac2len); goto error; } if (memcmp(mac1, mac2, mac1len) != 0) { testcase_fail("signature with orig key differs from signature " "with re-imported key"); goto error; } testcase_pass("CCA/EP11 export/import test with %st key %u: ok", hmac_mechs[k].name, keybits[i]); error: free(opaquekey); opaquekey = NULL; if (hkey != CK_INVALID_HANDLE) { funcs->C_DestroyObject(session, hkey); hkey = CK_INVALID_HANDLE; } if (hikey != CK_INVALID_HANDLE) { funcs->C_DestroyObject(session, hikey); hikey = CK_INVALID_HANDLE; } } } testcase_cleanup: testcase_close_session(); out: return rc; } static CK_RV rsa_export_import_tests(void) { CK_RV rc = CKR_OK; CK_FLAGS flags; CK_SESSION_HANDLE session; CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; CK_ULONG user_pin_len; CK_BYTE exp[] = { 0x01, 0x00, 0x01 }; CK_OBJECT_HANDLE publ_key = CK_INVALID_HANDLE, priv_key = CK_INVALID_HANDLE; CK_OBJECT_HANDLE imp_priv_key = CK_INVALID_HANDLE, imp_publ_key = CK_INVALID_HANDLE; CK_BYTE msg[1024], sig[1024]; CK_ULONG msglen, siglen; CK_MECHANISM mech = {CKM_RSA_PKCS, 0, 0}; unsigned int keybitlen; CK_BYTE *priv_opaquekey = NULL, *publ_opaquekey = NULL; CK_ULONG priv_opaquekeylen, publ_opaquekeylen; char label[80]; if (!is_cca_token(SLOT_ID) && !is_ep11_token(SLOT_ID)) { testcase_skip("this slot is not a CCA or EP11 token"); goto out; } if (!mech_supported(SLOT_ID, CKM_RSA_PKCS_KEY_PAIR_GEN)) { testcase_skip("this slot does not support CKM_RSA_PKCS_KEY_PAIR_GEN"); goto out; } if (!mech_supported(SLOT_ID, mech.mechanism)) { testcase_skip("this slot does not support CKM_RSA_PKCS"); goto out; } testcase_rw_session(); testcase_user_login(); for (keybitlen = 512; keybitlen <= 8192; keybitlen = 2 * keybitlen) { if (!keysize_supported(SLOT_ID, CKM_RSA_PKCS_KEY_PAIR_GEN, keybitlen) || (keybitlen > 4096 && !rsa8k)) continue; testcase_begin("CCA/EP11 export/import test with RSA %u key", keybitlen); // create ock rsa keypair rc = generate_RSA_PKCS_KeyPair(session, CKM_RSA_PKCS_KEY_PAIR_GEN, keybitlen, exp, sizeof(exp), &publ_key, &priv_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("RSA key generation with key size %u is not supported", keybitlen); goto error; } if (rc == CKR_POLICY_VIOLATION) { testcase_skip("RSA key generation is not allowed by policy"); goto error; } testcase_error("generate_RSA_PKCS_KeyPair() rc=%s", p11_get_ckr(rc)); goto error; } testcase_new_assertion(); // sign with original private key rc = funcs->C_SignInit(session, &mech, priv_key); if (rc != CKR_OK) { testcase_error("C_SignInit() rc=%s", p11_get_ckr(rc)); goto error; } msglen = (keybitlen / 8) / 2; siglen = sizeof(sig); rc = funcs->C_Sign(session, msg, msglen, sig, &siglen); if (rc != CKR_OK) { testcase_error("C_Sign() rc=%s", p11_get_ckr(rc)); goto error; } // verify with original public key rc = funcs->C_VerifyInit(session, &mech, publ_key); if (rc != CKR_OK) { testcase_error("C_VerifyInit() rc=%s", p11_get_ckr(rc)); goto error; } rc = funcs->C_Verify(session, msg, msglen, sig, siglen); if (rc == CKR_OK) { ; } else if (rc == CKR_SIGNATURE_INVALID || rc == CKR_SIGNATURE_LEN_RANGE) { testcase_fail("signature verify failed"); goto error; } else { testcase_error("C_Verify() rc=%s", p11_get_ckr(rc)); goto error; } // export original public key's CCA/EP11 blob rc = export_ibm_opaque(session, publ_key, &publ_opaquekey, &publ_opaquekeylen); if (rc != CKR_OK) { testcase_fail("export_ibm_opaque on public key failed rc=%s", p11_get_ckr(rc)); goto error; } // re-import this CCA/EP11 public rsa key blob as new public rsa key snprintf(label, sizeof(label), "re-imported_rsa%u_public_key", keybitlen); rc = import_rsa_publ_key(session, label, publ_opaquekey, publ_opaquekeylen, &imp_publ_key); if (rc != CKR_OK) { if (rc == CKR_PUBLIC_KEY_INVALID && is_ep11_token(SLOT_ID)) { testcase_skip("import_rsa_publ_key on exported CCA/EP11 rsa key blob failed due to missing EP11 FW fix"); } else { testcase_fail("import_rsa_publ_key on exported CCA/EP11 rsa key blob failed rc=%s", p11_get_ckr(rc)); } goto error; } // export original private key's CCA/EP11 blob rc = export_ibm_opaque(session, priv_key, &priv_opaquekey, &priv_opaquekeylen); if (rc != CKR_OK) { testcase_fail("export_ibm_opaque on private key failed rc=%s", p11_get_ckr(rc)); goto error; } // re-import this CCA/EP11 private rsa key blob as new private rsa key snprintf(label, sizeof(label), "re-imported_rsa%u_private_key", keybitlen); rc = import_rsa_priv_key(session, label, priv_opaquekey, priv_opaquekeylen, &imp_priv_key); if (rc != CKR_OK) { if (rc == CKR_PUBLIC_KEY_INVALID && is_ep11_token(SLOT_ID)) { testcase_skip("import_rsa_priv_key on exported CCA/EP11 rsa key blob failed due to missing EP11 FW fix"); } else { testcase_fail("import_rsa_priv_key on exported CCA/EP11 rsa key blob failed rc=%s", p11_get_ckr(rc)); } goto error; } // sign with re-imported private key rc = funcs->C_SignInit(session, &mech, imp_priv_key); if (rc != CKR_OK) { testcase_error("C_SignInit() with re-imported priv key failed, rc=%s", p11_get_ckr(rc)); goto error; } siglen = sizeof(sig); rc = funcs->C_Sign(session, msg, msglen, sig, &siglen); if (rc != CKR_OK) { testcase_error("C_Sign() with re-imported priv key failed, rc=%s", p11_get_ckr(rc)); goto error; } // verify with original public key rc = funcs->C_VerifyInit(session, &mech, publ_key); if (rc != CKR_OK) { testcase_error("C_VerifyInit() rc=%s", p11_get_ckr(rc)); goto error; } rc = funcs->C_Verify(session, msg, msglen, sig, siglen); if (rc == CKR_OK) { ; } else if (rc == CKR_SIGNATURE_INVALID || rc == CKR_SIGNATURE_LEN_RANGE) { testcase_fail("signature verify on signature generated with re-imported priv key failed, rc=%s", p11_get_ckr(rc)); goto error; } else { testcase_error("C_Verify() on signature generated with re-imported priv key failed, rc=%s", p11_get_ckr(rc)); goto error; } // sign with original private key rc = funcs->C_SignInit(session, &mech, priv_key); if (rc != CKR_OK) { testcase_error("C_SignInit() rc=%s", p11_get_ckr(rc)); goto error; } msglen = (keybitlen / 8) / 2; siglen = sizeof(sig); rc = funcs->C_Sign(session, msg, msglen, sig, &siglen); if (rc != CKR_OK) { testcase_error("C_Sign() rc=%s", p11_get_ckr(rc)); goto error; } // verify with re-imported public key rc = funcs->C_VerifyInit(session, &mech, imp_publ_key); if (rc != CKR_OK) { testcase_error("C_VerifyInit() with re-imported pub key failed, rc=%s", p11_get_ckr(rc)); goto error; } rc = funcs->C_Verify(session, msg, msglen, sig, siglen); if (rc == CKR_OK) { ; } else if (rc == CKR_SIGNATURE_INVALID || rc == CKR_SIGNATURE_LEN_RANGE) { testcase_fail("signature verify with re-imported pub key on signature failed"); goto error; } else { testcase_error("C_Verify() with re-imported pub key on signature failed, rc=%s", p11_get_ckr(rc)); goto error; } testcase_pass("CCA/EP11 export/import test with RSA %u key: ok", keybitlen); error: free(priv_opaquekey); priv_opaquekey = NULL; free(publ_opaquekey); publ_opaquekey = NULL; if (publ_key != CK_INVALID_HANDLE) { funcs->C_DestroyObject(session, publ_key); publ_key = CK_INVALID_HANDLE; } if (priv_key != CK_INVALID_HANDLE) { funcs->C_DestroyObject(session, priv_key); priv_key = CK_INVALID_HANDLE; } if (imp_publ_key != CK_INVALID_HANDLE) { funcs->C_DestroyObject(session, imp_publ_key); imp_publ_key = CK_INVALID_HANDLE; } if (imp_priv_key != CK_INVALID_HANDLE) { funcs->C_DestroyObject(session, imp_priv_key); imp_priv_key = CK_INVALID_HANDLE; } } testcase_cleanup: testcase_close_session(); out: return rc; } static CK_BYTE brainpoolP160r1[] = OCK_BRAINPOOL_P160R1; static CK_BYTE brainpoolP160t1[] = OCK_BRAINPOOL_P160T1; static CK_BYTE brainpoolP192r1[] = OCK_BRAINPOOL_P192R1; static CK_BYTE brainpoolP192t1[] = OCK_BRAINPOOL_P192T1; static CK_BYTE brainpoolP224r1[] = OCK_BRAINPOOL_P224R1; static CK_BYTE brainpoolP224t1[] = OCK_BRAINPOOL_P224T1; static CK_BYTE brainpoolP256r1[] = OCK_BRAINPOOL_P256R1; static CK_BYTE brainpoolP256t1[] = OCK_BRAINPOOL_P256T1; static CK_BYTE brainpoolP320r1[] = OCK_BRAINPOOL_P320R1; static CK_BYTE brainpoolP320t1[] = OCK_BRAINPOOL_P320T1; static CK_BYTE brainpoolP384r1[] = OCK_BRAINPOOL_P384R1; static CK_BYTE brainpoolP384t1[] = OCK_BRAINPOOL_P384T1; static CK_BYTE brainpoolP512r1[] = OCK_BRAINPOOL_P512R1; static CK_BYTE brainpoolP512t1[] = OCK_BRAINPOOL_P512T1; static CK_BYTE prime192v1[] = OCK_PRIME192V1; static CK_BYTE secp224r1[] = OCK_SECP224R1; static CK_BYTE prime256v1[] = OCK_PRIME256V1; static CK_BYTE secp384r1[] = OCK_SECP384R1; static CK_BYTE secp521r1[] = OCK_SECP521R1; static CK_BYTE secp256k1[] = OCK_SECP256K1; static CK_BYTE ed25519[] = OCK_ED25519; static CK_BYTE ed448[] = OCK_ED448; static CK_EDDSA_PARAMS eddsa_params = { FALSE, 0, NULL }; static struct { CK_BYTE *curve; CK_ULONG size; const char *name; CK_MECHANISM keygen_mech; CK_MECHANISM sign_mech; CK_KEY_TYPE key_type; } ec_curves[] = { {brainpoolP160r1, sizeof(brainpoolP160r1), "brainpoolP160r1", {CKM_EC_KEY_PAIR_GEN, NULL, 0}, {CKM_ECDSA, NULL, 0}, CKK_EC}, {brainpoolP160t1, sizeof(brainpoolP160t1), "brainpoolP160t1", {CKM_EC_KEY_PAIR_GEN, NULL, 0}, {CKM_ECDSA, NULL, 0}, CKK_EC}, {brainpoolP192r1, sizeof(brainpoolP192r1), "brainpoolP192r1", {CKM_EC_KEY_PAIR_GEN, NULL, 0}, {CKM_ECDSA, NULL, 0}, CKK_EC}, {brainpoolP192t1, sizeof(brainpoolP192t1), "brainpoolP192t1", {CKM_EC_KEY_PAIR_GEN, NULL, 0}, {CKM_ECDSA, NULL, 0}, CKK_EC}, {brainpoolP224r1, sizeof(brainpoolP224r1), "brainpoolP224r1", {CKM_EC_KEY_PAIR_GEN, NULL, 0}, {CKM_ECDSA, NULL, 0}, CKK_EC}, {brainpoolP224t1, sizeof(brainpoolP224t1), "brainpoolP224t1", {CKM_EC_KEY_PAIR_GEN, NULL, 0}, {CKM_ECDSA, NULL, 0}, CKK_EC}, {brainpoolP256r1, sizeof(brainpoolP256r1), "brainpoolP256r1", {CKM_EC_KEY_PAIR_GEN, NULL, 0}, {CKM_ECDSA, NULL, 0}, CKK_EC}, {brainpoolP256t1, sizeof(brainpoolP256t1), "brainpoolP256t1", {CKM_EC_KEY_PAIR_GEN, NULL, 0}, {CKM_ECDSA, NULL, 0}, CKK_EC}, {brainpoolP320r1, sizeof(brainpoolP320r1), "brainpoolP320r1", {CKM_EC_KEY_PAIR_GEN, NULL, 0}, {CKM_ECDSA, NULL, 0}, CKK_EC}, {brainpoolP320t1, sizeof(brainpoolP320t1), "brainpoolP320t1", {CKM_EC_KEY_PAIR_GEN, NULL, 0}, {CKM_ECDSA, NULL, 0}, CKK_EC}, {brainpoolP384r1, sizeof(brainpoolP384r1), "brainpoolP384r1", {CKM_EC_KEY_PAIR_GEN, NULL, 0}, {CKM_ECDSA, NULL, 0}, CKK_EC}, {brainpoolP384t1, sizeof(brainpoolP384t1), "brainpoolP384t1", {CKM_EC_KEY_PAIR_GEN, NULL, 0}, {CKM_ECDSA, NULL, 0}, CKK_EC}, {brainpoolP512r1, sizeof(brainpoolP512r1), "brainpoolP512r1", {CKM_EC_KEY_PAIR_GEN, NULL, 0}, {CKM_ECDSA, NULL, 0}, CKK_EC}, {brainpoolP512t1, sizeof(brainpoolP512t1), "brainpoolP512t1", {CKM_EC_KEY_PAIR_GEN, NULL, 0}, {CKM_ECDSA, NULL, 0}, CKK_EC}, {prime192v1, sizeof(prime192v1), "prime192v1", {CKM_EC_KEY_PAIR_GEN, NULL, 0}, {CKM_ECDSA, NULL, 0}, CKK_EC}, {secp224r1, sizeof(secp224r1), "secp224r1", {CKM_EC_KEY_PAIR_GEN, NULL, 0}, {CKM_ECDSA, NULL, 0}, CKK_EC}, {prime256v1, sizeof(prime256v1), "prime256v1", {CKM_EC_KEY_PAIR_GEN, NULL, 0}, {CKM_ECDSA, NULL, 0}, CKK_EC}, {secp384r1, sizeof(secp384r1), "secp384r1", {CKM_EC_KEY_PAIR_GEN, NULL, 0}, {CKM_ECDSA, NULL, 0}, CKK_EC}, {secp521r1, sizeof(secp521r1), "secp521r1", {CKM_EC_KEY_PAIR_GEN, NULL, 0}, {CKM_ECDSA, NULL, 0}, CKK_EC}, {secp256k1, sizeof(secp256k1), "secp256k1", {CKM_EC_KEY_PAIR_GEN, NULL, 0}, {CKM_ECDSA, NULL, 0}, CKK_EC}, {ed25519, sizeof(ed25519), "ed25519", {CKM_EC_KEY_PAIR_GEN, NULL, 0}, {CKM_IBM_ED25519_SHA512, NULL, 0}, CKK_EC}, {ed448, sizeof(ed448), "ed448", {CKM_EC_KEY_PAIR_GEN, NULL, 0}, {CKM_IBM_ED448_SHA3, NULL, 0}, CKK_EC}, {ed25519, sizeof(ed25519), "ed25519", {CKM_EC_EDWARDS_KEY_PAIR_GEN, NULL, 0}, {CKM_EDDSA, &eddsa_params, sizeof(eddsa_params)}, CKK_EC_EDWARDS}, {ed448, sizeof(ed448), "ed448", {CKM_EC_EDWARDS_KEY_PAIR_GEN, NULL, 0}, {CKM_EDDSA, &eddsa_params, sizeof(eddsa_params)}, CKK_EC_EDWARDS}, {0, 0, 0, {0, NULL, 0}, {0, NULL, 0}, 0} }; static CK_RV ecc_export_import_tests(void) { CK_RV rc = CKR_OK; CK_FLAGS flags; CK_SESSION_HANDLE session; CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; CK_ULONG user_pin_len; CK_OBJECT_HANDLE publ_key = CK_INVALID_HANDLE, priv_key = CK_INVALID_HANDLE; CK_OBJECT_HANDLE imp_priv_key = CK_INVALID_HANDLE, imp_publ_key = CK_INVALID_HANDLE; CK_BYTE msg[32], sig[256]; CK_ULONG msglen, siglen; CK_BYTE *priv_opaquekey = NULL, *publ_opaquekey = NULL; CK_ULONG priv_opaquekeylen, publ_opaquekeylen; CK_BBOOL ck_true = TRUE; CK_ATTRIBUTE tmpl_derive[] = { { CKA_DERIVE, &ck_true, sizeof(ck_true)} }; CK_ULONG tmpl_derive_len = sizeof(tmpl_derive) / sizeof(CK_ATTRIBUTE); char label[80]; int i; int is_cca = is_cca_token(SLOT_ID); if (!is_cca && !is_ep11_token(SLOT_ID)) { testcase_skip("this slot is not a CCA or EP11 token"); goto out; } testcase_rw_session(); testcase_user_login(); for (i = 0; ec_curves[i].curve; i++) { testcase_begin("CCA/EP11 export/import test with public/private ECC " "curve %s keys and %s", ec_curves[i].name, p11_get_ckm(&mechtable_funcs, ec_curves[i].sign_mech.mechanism)); if (!mech_supported(SLOT_ID, ec_curves[i].keygen_mech.mechanism)) { testcase_skip("this slot does not support %s", p11_get_ckm(&mechtable_funcs, ec_curves[i].keygen_mech.mechanism)); goto error; } if (!mech_supported(SLOT_ID, ec_curves[i].sign_mech.mechanism)) { testcase_skip("this slot does not support %s", p11_get_ckm(&mechtable_funcs, ec_curves[i].sign_mech.mechanism)); goto error; } rc = generate_EC_KeyPair(session, ec_curves[i].keygen_mech.mechanism, ec_curves[i].curve, ec_curves[i].size, &publ_key, &priv_key, CK_FALSE); if (rc == CKR_CURVE_NOT_SUPPORTED) { testcase_skip("ECC curve %s not supported yet by CCA/EP11 token", ec_curves[i].name); goto error; } if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("ECC key generation is not allowed by policy"); goto error; } testcase_error("generate_EC_KeyPair() rc=%s", p11_get_ckr(rc)); goto error; } testcase_new_assertion(); // sign with original private key rc = funcs->C_SignInit(session, &ec_curves[i].sign_mech, priv_key); if (rc != CKR_OK) { testcase_error("C_SignInit() rc=%s", p11_get_ckr(rc)); goto error; } msglen = sizeof(msg); siglen = sizeof(sig); rc = funcs->C_Sign(session, msg, msglen, sig, &siglen); if (rc != CKR_OK) { testcase_error("C_Sign() rc=%s", p11_get_ckr(rc)); goto error; } // verify with original public key rc = funcs->C_VerifyInit(session, &ec_curves[i].sign_mech, publ_key); if (rc != CKR_OK) { testcase_error("C_VerifyInit() rc=%s", p11_get_ckr(rc)); goto error; } rc = funcs->C_Verify(session, msg, msglen, sig, siglen); if (rc == CKR_OK) { ; } else if (rc == CKR_SIGNATURE_INVALID || rc == CKR_SIGNATURE_LEN_RANGE) { testcase_fail("signature verify failed"); goto error; } else { testcase_error("C_Verify() rc=%s", p11_get_ckr(rc)); goto error; } // export original public key's CCA/EP11 blob rc = export_ibm_opaque(session, publ_key, &publ_opaquekey, &publ_opaquekeylen); if (rc != CKR_OK) { testcase_fail("export_ibm_opaque on public key failed rc=%s", p11_get_ckr(rc)); goto error; } // re-import this CCA/EP11 public ecc key blob as new public ecc key snprintf(label, sizeof(label), "re-imported_ecc_%s_public_key", ec_curves[i].name); rc = import_ecc_publ_key(session, ec_curves[i].key_type, label, publ_opaquekey, publ_opaquekeylen, &imp_publ_key); if (rc != CKR_OK) { if (rc == CKR_PUBLIC_KEY_INVALID && is_ep11_token(SLOT_ID)) { testcase_skip("import_ecc_publ_key on exported CCA/EP11 ecc key blob failed due to missing EP11 FW fix"); } else { testcase_fail("import_ecc_publ_key on exported CCA/EP11 ecc key blob failed rc=%s", p11_get_ckr(rc)); } goto error; } // export original private key's CCA/EP11 blob rc = export_ibm_opaque(session, priv_key, &priv_opaquekey, &priv_opaquekeylen); if (rc != CKR_OK) { testcase_fail("export_ibm_opaque on private key failed rc=%s", p11_get_ckr(rc)); goto error; } // re-import this CCA/EP11 private ecc key blob as new private ecc key snprintf(label, sizeof(label), "re-imported_ecc_%s_private_key", ec_curves[i].name); rc = import_ecc_priv_key(session, ec_curves[i].key_type, label, priv_opaquekey, priv_opaquekeylen, &imp_priv_key); if (rc != CKR_OK) { if (rc == CKR_PUBLIC_KEY_INVALID && is_ep11_token(SLOT_ID)) { testcase_skip("import_ecc_priv_key on exported CCA/EP11 ecc key blob failed due to missing EP11 FW fix"); } else { testcase_fail("import_ecc_priv_key on exported CCA/EP11 ecc key blob failed rc=%s", p11_get_ckr(rc)); } goto error; } // sign with re-imported private key rc = funcs->C_SignInit(session, &ec_curves[i].sign_mech, imp_priv_key); if (rc != CKR_OK) { testcase_error("C_SignInit() with re-imported priv key failed, rc=%s", p11_get_ckr(rc)); goto error; } msglen = sizeof(msg); siglen = sizeof(sig); rc = funcs->C_Sign(session, msg, msglen, sig, &siglen); if (rc != CKR_OK) { testcase_error("C_Sign() with re-imported priv key failed, rc=%s", p11_get_ckr(rc)); goto error; } // verify with original public key rc = funcs->C_VerifyInit(session, &ec_curves[i].sign_mech, publ_key); if (rc != CKR_OK) { testcase_error("C_VerifyInit() rc=%s", p11_get_ckr(rc)); goto error; } rc = funcs->C_Verify(session, msg, msglen, sig, siglen); if (rc == CKR_OK) { ; } else if (rc == CKR_SIGNATURE_INVALID || rc == CKR_SIGNATURE_LEN_RANGE) { testcase_fail("signature verify on signature generated with re-imported priv key failed, rc=%s", p11_get_ckr(rc)); goto error; } else { testcase_error("C_Verify() on signature generated with re-imported priv key failed, rc=%s", p11_get_ckr(rc)); goto error; } // sign with original private key rc = funcs->C_SignInit(session, &ec_curves[i].sign_mech, priv_key); if (rc != CKR_OK) { testcase_error("C_SignInit() rc=%s", p11_get_ckr(rc)); goto error; } msglen = sizeof(msg); siglen = sizeof(sig); rc = funcs->C_Sign(session, msg, msglen, sig, &siglen); if (rc != CKR_OK) { testcase_error("C_Sign() rc=%s", p11_get_ckr(rc)); goto error; } // verify with re-imported public key rc = funcs->C_VerifyInit(session, &ec_curves[i].sign_mech, imp_publ_key); if (rc != CKR_OK) { testcase_error("C_VerifyInit() with re-imported pub key failed, rc=%s", p11_get_ckr(rc)); goto error; } rc = funcs->C_Verify(session, msg, msglen, sig, siglen); if (rc == CKR_OK) { ; } else if (rc == CKR_SIGNATURE_INVALID || rc == CKR_SIGNATURE_LEN_RANGE) { testcase_fail("signature verify with re-imported pub key on signature failed"); goto error; } else { testcase_error("C_Verify() with re-imported pub key on signature failed, rc=%s", p11_get_ckr(rc)); goto error; } if (is_cca) { /* Try to change CKA_DERIVE to TRUE of private key */ rc = funcs->C_SetAttributeValue(session, priv_key, tmpl_derive, tmpl_derive_len); if (rc != CKR_OK) { testcase_error("C_SetAttributeValue() with CKA_DERIVE=TRUE failed, rc=%s", p11_get_ckr(rc)); goto error; } } testcase_pass("CCA/EP11 export/import test with public/private ECC " "curve %s keys and %s: ok", ec_curves[i].name, p11_get_ckm(&mechtable_funcs, ec_curves[i].sign_mech.mechanism)); error: free(priv_opaquekey); priv_opaquekey = NULL; free(publ_opaquekey); publ_opaquekey = NULL; if (publ_key != CK_INVALID_HANDLE) { funcs->C_DestroyObject(session, publ_key); publ_key = CK_INVALID_HANDLE; } if (priv_key != CK_INVALID_HANDLE) { funcs->C_DestroyObject(session, priv_key); priv_key = CK_INVALID_HANDLE; } if (imp_publ_key != CK_INVALID_HANDLE) { funcs->C_DestroyObject(session, imp_publ_key); imp_publ_key = CK_INVALID_HANDLE; } if (imp_priv_key != CK_INVALID_HANDLE) { funcs->C_DestroyObject(session, imp_priv_key); imp_priv_key = CK_INVALID_HANDLE; } } testcase_cleanup: testcase_close_session(); out: return rc; } static struct { CK_ULONG keyform; const char *name; } dilithium_variants[] = { {CK_IBM_DILITHIUM_KEYFORM_ROUND2_65, "Round 2 (6,5)"}, {CK_IBM_DILITHIUM_KEYFORM_ROUND2_87, "Round 2 (8,7)"}, {CK_IBM_DILITHIUM_KEYFORM_ROUND3_44, "Round 3 (4,4)"}, {CK_IBM_DILITHIUM_KEYFORM_ROUND3_65, "Round 3 (6,5)"}, {CK_IBM_DILITHIUM_KEYFORM_ROUND3_87, "Round 3 (8,7)"}, {0, NULL} }; static CK_RV ibm_dilithium_export_import_tests(void) { CK_RV rc = CKR_OK; CK_FLAGS flags; CK_SESSION_HANDLE session; CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; CK_ULONG user_pin_len; CK_BBOOL attr_sign = TRUE; CK_BBOOL attr_verify = TRUE; CK_BBOOL true = CK_TRUE; CK_BBOOL false = CK_FALSE; CK_OBJECT_HANDLE publ_key = CK_INVALID_HANDLE, priv_key = CK_INVALID_HANDLE; CK_OBJECT_HANDLE imp_priv_key = CK_INVALID_HANDLE, imp_publ_key = CK_INVALID_HANDLE; CK_BYTE msg[32], sig[5000]; CK_ULONG msglen, siglen; CK_MECHANISM mech = { CKM_IBM_DILITHIUM, 0, 0}; CK_BYTE *priv_opaquekey = NULL, *publ_opaquekey = NULL; CK_ULONG priv_opaquekeylen, publ_opaquekeylen; char label[80]; int i; if (!is_cca_token(SLOT_ID) && !is_ep11_token(SLOT_ID)) { testcase_skip("this slot is not a CCA or EP11 token"); goto out; } if (!mech_supported(SLOT_ID, CKM_IBM_DILITHIUM)) { testcase_skip("this slot does not support CKM_IBM_DILITHIUM"); goto out; } testcase_rw_session(); testcase_user_login(); for (i = 0; dilithium_variants[i].keyform != 0; i++) { CK_ATTRIBUTE dilithium_attr_private[] = { {CKA_SIGN, &attr_sign, sizeof(CK_BBOOL)}, {CKA_IBM_DILITHIUM_KEYFORM, (CK_BYTE *)&dilithium_variants[i].keyform, sizeof(CK_ULONG)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_PRIVATE, &true, sizeof(true)}, }; CK_ATTRIBUTE dilithium_attr_public[] = { {CKA_VERIFY, &attr_verify, sizeof(CK_BBOOL)}, {CKA_IBM_DILITHIUM_KEYFORM, (CK_BYTE *)&dilithium_variants[i].keyform, sizeof(CK_ULONG)}, {CKA_TOKEN, &false, sizeof(false)}, {CKA_PRIVATE, &false, sizeof(false)}, }; CK_ULONG num_dilithium_attrs = sizeof(dilithium_attr_public) / sizeof(CK_ATTRIBUTE); testcase_begin("CCA/EP11 export/import test with public/private IBM Dilithium %s keys", dilithium_variants[i].name); /* Generate Dilithium key pair */ rc = funcs->C_GenerateKeyPair(session, &mech, dilithium_attr_public, num_dilithium_attrs, dilithium_attr_private, num_dilithium_attrs, &publ_key, &priv_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("IBM Dilithium variant %s is not supported", dilithium_variants[i].name); goto error; } else if (rc == CKR_POLICY_VIOLATION) { testcase_skip("IBM Dilithium key generation is not allowed by policy"); goto error; } else { testcase_new_assertion(); testcase_fail("C_GenerateKeyPair with %s failed, rc=%s", dilithium_variants[i].name, p11_get_ckr(rc)); goto error; } } testcase_new_assertion(); // sign with original private key rc = funcs->C_SignInit(session, &mech, priv_key); if (rc != CKR_OK) { testcase_error("C_SignInit() rc=%s", p11_get_ckr(rc)); goto error; } msglen = sizeof(msg); siglen = sizeof(sig); rc = funcs->C_Sign(session, msg, msglen, sig, &siglen); if (rc != CKR_OK) { testcase_error("C_Sign() rc=%s", p11_get_ckr(rc)); goto error; } // verify with original public key rc = funcs->C_VerifyInit(session, &mech, publ_key); if (rc != CKR_OK) { testcase_error("C_VerifyInit() rc=%s", p11_get_ckr(rc)); goto error; } rc = funcs->C_Verify(session, msg, msglen, sig, siglen); if (rc == CKR_OK) { ; } else if (rc == CKR_SIGNATURE_INVALID || rc == CKR_SIGNATURE_LEN_RANGE) { testcase_fail("signature verify failed"); goto error; } else { testcase_error("C_Verify() rc=%s", p11_get_ckr(rc)); goto error; } // export original public key's CCA/EP11 blob rc = export_ibm_opaque(session, publ_key, &publ_opaquekey, &publ_opaquekeylen); if (rc != CKR_OK) { testcase_fail("export_ibm_opaque on public key failed rc=%s", p11_get_ckr(rc)); goto error; } // re-import this CCA/EP11 public Dilithium key blob as new public ecc key snprintf(label, sizeof(label), "re-imported_dilithium_%s_public_key", dilithium_variants[i].name); rc = import_ml_dsa_publ_key(session, CKK_IBM_PQC_DILITHIUM, label, publ_opaquekey, publ_opaquekeylen, &imp_publ_key); if (rc != CKR_OK) { if (rc == CKR_PUBLIC_KEY_INVALID && is_ep11_token(SLOT_ID)) { testcase_skip("import_ml_dsa_publ_key on exported CCA/EP11 Dilithium key blob failed due to missing EP11 FW fix"); } else { testcase_fail("import_ml_dsa_publ_key on exported CCA/EP11 Dilithium key blob failed rc=%s", p11_get_ckr(rc)); } goto error; } // export original private key's CCA/EP11 blob rc = export_ibm_opaque(session, priv_key, &priv_opaquekey, &priv_opaquekeylen); if (rc != CKR_OK) { testcase_fail("export_ibm_opaque on private key failed rc=%s", p11_get_ckr(rc)); goto error; } // re-import this CCA/EP11 private Dilithium key blob as new private ecc key snprintf(label, sizeof(label), "re-imported_dilithium_%s_private_key", dilithium_variants[i].name); rc = import_ml_dsa_priv_key(session, CKK_IBM_PQC_DILITHIUM, label, priv_opaquekey, priv_opaquekeylen, &imp_priv_key); if (rc != CKR_OK) { if (rc == CKR_PUBLIC_KEY_INVALID && is_ep11_token(SLOT_ID)) { testcase_skip("import_ibm_ml_dsa_priv_key on exported CCA/EP11 Dilithium key blob failed due to missing EP11 FW fix"); } else { testcase_fail("import_ibm_ml_dsa_priv_key on exported CCA/EP11 Dilithium key blob failed rc=%s", p11_get_ckr(rc)); } goto error; } // sign with re-imported private key rc = funcs->C_SignInit(session, &mech, imp_priv_key); if (rc != CKR_OK) { testcase_error("C_SignInit() with re-imported priv key failed, rc=%s", p11_get_ckr(rc)); goto error; } msglen = sizeof(msg); siglen = sizeof(sig); rc = funcs->C_Sign(session, msg, msglen, sig, &siglen); if (rc != CKR_OK) { testcase_error("C_Sign() with re-imported priv key failed, rc=%s", p11_get_ckr(rc)); goto error; } // verify with original public key rc = funcs->C_VerifyInit(session, &mech, publ_key); if (rc != CKR_OK) { testcase_error("C_VerifyInit() rc=%s", p11_get_ckr(rc)); goto error; } rc = funcs->C_Verify(session, msg, msglen, sig, siglen); if (rc == CKR_OK) { ; } else if (rc == CKR_SIGNATURE_INVALID || rc == CKR_SIGNATURE_LEN_RANGE) { testcase_fail("signature verify on signature generated with re-imported priv key failed, rc=%s", p11_get_ckr(rc)); goto error; } else { testcase_error("C_Verify() on signature generated with re-imported priv key failed, rc=%s", p11_get_ckr(rc)); goto error; } // sign with original private key rc = funcs->C_SignInit(session, &mech, priv_key); if (rc != CKR_OK) { testcase_error("C_SignInit() rc=%s", p11_get_ckr(rc)); goto error; } msglen = sizeof(msg); siglen = sizeof(sig); rc = funcs->C_Sign(session, msg, msglen, sig, &siglen); if (rc != CKR_OK) { testcase_error("C_Sign() rc=%s", p11_get_ckr(rc)); goto error; } // verify with re-imported public key rc = funcs->C_VerifyInit(session, &mech, imp_publ_key); if (rc != CKR_OK) { testcase_error("C_VerifyInit() with re-imported pub key failed, rc=%s", p11_get_ckr(rc)); goto error; } rc = funcs->C_Verify(session, msg, msglen, sig, siglen); if (rc == CKR_OK) { ; } else if (rc == CKR_SIGNATURE_INVALID || rc == CKR_SIGNATURE_LEN_RANGE) { testcase_fail("signature verify with re-imported pub key on signature failed"); goto error; } else { testcase_error("C_Verify() with re-imported pub key on signature failed, rc=%s", p11_get_ckr(rc)); goto error; } testcase_pass("CCA/EP11 export/import test with public/private IBM Dilithium %s keys", dilithium_variants[i].name); error: free(priv_opaquekey); priv_opaquekey = NULL; free(publ_opaquekey); publ_opaquekey = NULL; if (publ_key != CK_INVALID_HANDLE) { funcs->C_DestroyObject(session, publ_key); publ_key = CK_INVALID_HANDLE; } if (priv_key != CK_INVALID_HANDLE) { funcs->C_DestroyObject(session, priv_key); priv_key = CK_INVALID_HANDLE; } if (imp_publ_key != CK_INVALID_HANDLE) { funcs->C_DestroyObject(session, imp_publ_key); imp_publ_key = CK_INVALID_HANDLE; } if (imp_priv_key != CK_INVALID_HANDLE) { funcs->C_DestroyObject(session, imp_priv_key); imp_priv_key = CK_INVALID_HANDLE; } } testcase_cleanup: testcase_close_session(); out: return rc; } static struct { CK_ULONG parameter_set; const char *name; } ml_dsa_variants[] = { {CKP_ML_DSA_44, "ML-DSA (4,4)"}, {CKP_ML_DSA_65, "ML-DSA (6,5)"}, {CKP_ML_DSA_87, "ML-DSA (8,7)"}, {0, NULL} }; static CK_RV ibm_ml_dsa_export_import_tests(void) { CK_RV rc = CKR_OK; CK_FLAGS flags; CK_SESSION_HANDLE session; CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; CK_ULONG user_pin_len; CK_BBOOL attr_sign = TRUE; CK_BBOOL attr_verify = TRUE; CK_BBOOL true = CK_TRUE; CK_BBOOL false = CK_FALSE; CK_OBJECT_HANDLE publ_key = CK_INVALID_HANDLE, priv_key = CK_INVALID_HANDLE; CK_OBJECT_HANDLE imp_priv_key = CK_INVALID_HANDLE, imp_publ_key = CK_INVALID_HANDLE; CK_BYTE msg[32], sig[5000]; CK_ULONG msglen, siglen; CK_MECHANISM mech = { CKM_IBM_ML_DSA, 0, 0}; CK_MECHANISM keygen_mech = { CKM_IBM_ML_DSA_KEY_PAIR_GEN, 0, 0}; CK_BYTE *priv_opaquekey = NULL, *publ_opaquekey = NULL; CK_ULONG priv_opaquekeylen, publ_opaquekeylen; char label[80]; int i; if (!is_cca_token(SLOT_ID) && !is_ep11_token(SLOT_ID)) { testcase_skip("this slot is not a CCA or EP11 token"); goto out; } if (!mech_supported(SLOT_ID, CKM_IBM_ML_DSA_KEY_PAIR_GEN)) { testcase_skip("this slot does not support CKM_IBM_ML_DSA_KEY_PAIR_GEN"); goto out; } if (!mech_supported(SLOT_ID, CKM_IBM_ML_DSA)) { testcase_skip("this slot does not support CKM_IBM_ML_DSA"); goto out; } testcase_rw_session(); testcase_user_login(); for (i = 0; ml_dsa_variants[i].parameter_set != 0; i++) { CK_ATTRIBUTE ibm_ml_dsa_attr_private[] = { {CKA_SIGN, &attr_sign, sizeof(CK_BBOOL)}, {CKA_IBM_PARAMETER_SET, (CK_BYTE *)&ml_dsa_variants[i].parameter_set, sizeof(CK_ULONG)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_PRIVATE, &true, sizeof(true)}, }; CK_ATTRIBUTE ibm_ml_dsa_attr_public[] = { {CKA_VERIFY, &attr_verify, sizeof(CK_BBOOL)}, {CKA_IBM_PARAMETER_SET, (CK_BYTE *)&ml_dsa_variants[i].parameter_set, sizeof(CK_ULONG)}, {CKA_TOKEN, &false, sizeof(false)}, {CKA_PRIVATE, &false, sizeof(false)}, }; CK_ULONG num_ibm_ml_dsa_attrs = sizeof(ibm_ml_dsa_attr_public) / sizeof(CK_ATTRIBUTE); testcase_begin("CCA/EP11 export/import test with public/private IBM ML-DSA %s keys", ml_dsa_variants[i].name); /* Generate IBM-ML-DSA key pair */ rc = funcs->C_GenerateKeyPair(session, &keygen_mech, ibm_ml_dsa_attr_public, num_ibm_ml_dsa_attrs, ibm_ml_dsa_attr_private, num_ibm_ml_dsa_attrs, &publ_key, &priv_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("IBM ML-DSA variant %s is not supported", ml_dsa_variants[i].name); goto error; } else if (rc == CKR_POLICY_VIOLATION) { testcase_skip("IBM ML-DSA key generation is not allowed by policy"); goto error; } else { testcase_new_assertion(); testcase_fail("C_GenerateKeyPair with %s failed, rc=%s", ml_dsa_variants[i].name, p11_get_ckr(rc)); goto error; } } testcase_new_assertion(); // sign with original private key rc = funcs->C_SignInit(session, &mech, priv_key); if (rc != CKR_OK) { testcase_error("C_SignInit() rc=%s", p11_get_ckr(rc)); goto error; } msglen = sizeof(msg); siglen = sizeof(sig); rc = funcs->C_Sign(session, msg, msglen, sig, &siglen); if (rc != CKR_OK) { testcase_error("C_Sign() rc=%s", p11_get_ckr(rc)); goto error; } // verify with original public key rc = funcs->C_VerifyInit(session, &mech, publ_key); if (rc != CKR_OK) { testcase_error("C_VerifyInit() rc=%s", p11_get_ckr(rc)); goto error; } rc = funcs->C_Verify(session, msg, msglen, sig, siglen); if (rc == CKR_OK) { ; } else if (rc == CKR_SIGNATURE_INVALID || rc == CKR_SIGNATURE_LEN_RANGE) { testcase_fail("signature verify failed"); goto error; } else { testcase_error("C_Verify() rc=%s", p11_get_ckr(rc)); goto error; } // export original public key's CCA/EP11 blob rc = export_ibm_opaque(session, publ_key, &publ_opaquekey, &publ_opaquekeylen); if (rc != CKR_OK) { testcase_fail("export_ibm_opaque on public key failed rc=%s", p11_get_ckr(rc)); goto error; } // re-import this CCA/EP11 public ML-DSA key blob as new public ML-DSA key snprintf(label, sizeof(label), "re-imported_ml_dsa_%s_public_key", ml_dsa_variants[i].name); rc = import_ml_dsa_publ_key(session, CKK_IBM_ML_DSA, label, publ_opaquekey, publ_opaquekeylen, &imp_publ_key); if (rc != CKR_OK) { if (rc == CKR_PUBLIC_KEY_INVALID && is_ep11_token(SLOT_ID)) { testcase_skip("import_ml_dsa_publ_key on exported CCA/EP11 ML-DSA key blob failed due to missing EP11 FW fix"); } else { testcase_fail("import_ml_dsa_publ_key on exported CCA/EP11 ML-DSA key blob failed rc=%s", p11_get_ckr(rc)); } goto error; } // export original private key's CCA/EP11 blob rc = export_ibm_opaque(session, priv_key, &priv_opaquekey, &priv_opaquekeylen); if (rc != CKR_OK) { testcase_fail("export_ibm_opaque on private key failed rc=%s", p11_get_ckr(rc)); goto error; } // re-import this CCA/EP11 private ML-DSA key blob as new private ML-DSA key snprintf(label, sizeof(label), "re-imported_ml_dsa_%s_private_key", ml_dsa_variants[i].name); rc = import_ml_dsa_priv_key(session, CKK_IBM_ML_DSA, label, priv_opaquekey, priv_opaquekeylen, &imp_priv_key); if (rc != CKR_OK) { if (rc == CKR_PUBLIC_KEY_INVALID && is_ep11_token(SLOT_ID)) { testcase_skip("import_ibm_ml_dsa_priv_key on exported CCA/EP11 ML-DSA key blob failed due to missing EP11 FW fix"); } else { testcase_fail("import_ibm_ml_dsa_priv_key on exported CCA/EP11 ML-DSA key blob failed rc=%s", p11_get_ckr(rc)); } goto error; } // sign with re-imported private key rc = funcs->C_SignInit(session, &mech, imp_priv_key); if (rc != CKR_OK) { testcase_error("C_SignInit() with re-imported priv key failed, rc=%s", p11_get_ckr(rc)); goto error; } msglen = sizeof(msg); siglen = sizeof(sig); rc = funcs->C_Sign(session, msg, msglen, sig, &siglen); if (rc != CKR_OK) { testcase_error("C_Sign() with re-imported priv key failed, rc=%s", p11_get_ckr(rc)); goto error; } // verify with original public key rc = funcs->C_VerifyInit(session, &mech, publ_key); if (rc != CKR_OK) { testcase_error("C_VerifyInit() rc=%s", p11_get_ckr(rc)); goto error; } rc = funcs->C_Verify(session, msg, msglen, sig, siglen); if (rc == CKR_OK) { ; } else if (rc == CKR_SIGNATURE_INVALID || rc == CKR_SIGNATURE_LEN_RANGE) { testcase_fail("signature verify on signature generated with re-imported priv key failed, rc=%s", p11_get_ckr(rc)); goto error; } else { testcase_error("C_Verify() on signature generated with re-imported priv key failed, rc=%s", p11_get_ckr(rc)); goto error; } // sign with original private key rc = funcs->C_SignInit(session, &mech, priv_key); if (rc != CKR_OK) { testcase_error("C_SignInit() rc=%s", p11_get_ckr(rc)); goto error; } msglen = sizeof(msg); siglen = sizeof(sig); rc = funcs->C_Sign(session, msg, msglen, sig, &siglen); if (rc != CKR_OK) { testcase_error("C_Sign() rc=%s", p11_get_ckr(rc)); goto error; } // verify with re-imported public key rc = funcs->C_VerifyInit(session, &mech, imp_publ_key); if (rc != CKR_OK) { testcase_error("C_VerifyInit() with re-imported pub key failed, rc=%s", p11_get_ckr(rc)); goto error; } rc = funcs->C_Verify(session, msg, msglen, sig, siglen); if (rc == CKR_OK) { ; } else if (rc == CKR_SIGNATURE_INVALID || rc == CKR_SIGNATURE_LEN_RANGE) { testcase_fail("signature verify with re-imported pub key on signature failed"); goto error; } else { testcase_error("C_Verify() with re-imported pub key on signature failed, rc=%s", p11_get_ckr(rc)); goto error; } testcase_pass("CCA/EP11 export/import test with public/private IBM ML-DSA %s keys", ml_dsa_variants[i].name); error: free(priv_opaquekey); priv_opaquekey = NULL; free(publ_opaquekey); publ_opaquekey = NULL; if (publ_key != CK_INVALID_HANDLE) { funcs->C_DestroyObject(session, publ_key); publ_key = CK_INVALID_HANDLE; } if (priv_key != CK_INVALID_HANDLE) { funcs->C_DestroyObject(session, priv_key); priv_key = CK_INVALID_HANDLE; } if (imp_publ_key != CK_INVALID_HANDLE) { funcs->C_DestroyObject(session, imp_publ_key); imp_publ_key = CK_INVALID_HANDLE; } if (imp_priv_key != CK_INVALID_HANDLE) { funcs->C_DestroyObject(session, imp_priv_key); imp_priv_key = CK_INVALID_HANDLE; } } testcase_cleanup: testcase_close_session(); out: return rc; } static struct { CK_ULONG parameter_set; const char *name; } ml_kem_variants[] = { {CKP_IBM_ML_KEM_512, "ML-KEM 512"}, {CKP_IBM_ML_KEM_768, "ML-KEM 768"}, {CKP_IBM_ML_KEM_1024, "ML-KEM 1024"}, {0, NULL} }; static CK_RV ibm_ml_kem_export_import_tests(void) { CK_RV rc = CKR_OK; CK_FLAGS flags; CK_SESSION_HANDLE session; CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; CK_ULONG user_pin_len; CK_BBOOL attr_derive = TRUE; CK_BBOOL true = CK_TRUE; CK_BBOOL false = CK_FALSE; CK_OBJECT_HANDLE publ_key = CK_INVALID_HANDLE, priv_key = CK_INVALID_HANDLE; CK_OBJECT_HANDLE imp_priv_key = CK_INVALID_HANDLE, imp_publ_key = CK_INVALID_HANDLE; CK_BYTE output_data[8192]; CK_ULONG outlen; CK_IBM_ML_KEM_PARAMS ml_kem_params; CK_MECHANISM mech = { CKM_IBM_ML_KEM, &ml_kem_params, sizeof(ml_kem_params)}; CK_MECHANISM keygen_mech = { CKM_IBM_ML_KEM_KEY_PAIR_GEN, 0, 0}; CK_BYTE *priv_opaquekey = NULL, *publ_opaquekey = NULL; CK_ULONG priv_opaquekeylen, publ_opaquekeylen; char label[80]; int i; if (!is_cca_token(SLOT_ID) && !is_ep11_token(SLOT_ID)) { testcase_skip("this slot is not a CCA or EP11 token"); goto out; } if (!mech_supported(SLOT_ID, CKM_IBM_ML_KEM_KEY_PAIR_GEN)) { testcase_skip("this slot does not support CKM_IBM_ML_KEM_KEY_PAIR_GEN"); goto out; } if (!mech_supported(SLOT_ID, CKM_IBM_ML_KEM)) { testcase_skip("this slot does not support CKM_IBM_ML_KEM"); goto out; } testcase_rw_session(); testcase_user_login(); for (i = 0; ml_kem_variants[i].parameter_set != 0; i++) { CK_ATTRIBUTE ibm_ml_kem_attr_private[] = { {CKA_DERIVE, &attr_derive, sizeof(CK_BBOOL)}, {CKA_IBM_PARAMETER_SET, (CK_BYTE *)&ml_kem_variants[i].parameter_set, sizeof(CK_ULONG)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_PRIVATE, &true, sizeof(true)}, }; CK_ATTRIBUTE ibm_ml_kem_attr_public[] = { {CKA_DERIVE, &attr_derive, sizeof(CK_BBOOL)}, {CKA_IBM_PARAMETER_SET, (CK_BYTE *)&ml_kem_variants[i].parameter_set, sizeof(CK_ULONG)}, {CKA_TOKEN, &false, sizeof(false)}, {CKA_PRIVATE, &false, sizeof(false)}, }; CK_ULONG num_ibm_ml_kem_attrs = sizeof(ibm_ml_kem_attr_public) / sizeof(CK_ATTRIBUTE); CK_OBJECT_CLASS class = CKO_SECRET_KEY; CK_KEY_TYPE key_type = CKK_AES; CK_ULONG secret_key_len = 32; CK_ATTRIBUTE derive_tmpl[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &key_type, sizeof(key_type)}, {CKA_SENSITIVE, &false, sizeof(false)}, {CKA_VALUE_LEN, &secret_key_len, sizeof(secret_key_len)}, {CKA_SIGN, &true, sizeof(true)}, {CKA_VERIFY, &true, sizeof(true)}, }; CK_ULONG derive_tmpl_len = sizeof(derive_tmpl) / sizeof(CK_ATTRIBUTE); CK_OBJECT_HANDLE key1 = CK_INVALID_HANDLE; CK_OBJECT_HANDLE key2 = CK_INVALID_HANDLE; CK_OBJECT_HANDLE key3 = CK_INVALID_HANDLE; CK_OBJECT_HANDLE key4 = CK_INVALID_HANDLE; testcase_begin("CCA/EP11 export/import test with public/private IBM ML-KEM %s keys", ml_kem_variants[i].name); /* Generate IBM-ML-KEM key pair */ rc = funcs->C_GenerateKeyPair(session, &keygen_mech, ibm_ml_kem_attr_public, num_ibm_ml_kem_attrs, ibm_ml_kem_attr_private, num_ibm_ml_kem_attrs, &publ_key, &priv_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("IBM ML-KEM variant %s is not supported", ml_kem_variants[i].name); goto error; } else if (rc == CKR_POLICY_VIOLATION) { testcase_skip("IBM ML-KEM key generation is not allowed by policy"); goto error; } else { testcase_new_assertion(); testcase_fail("C_GenerateKeyPair with %s failed, rc=%s", ml_kem_variants[i].name, p11_get_ckr(rc)); goto error; } } testcase_new_assertion(); // Encapsulate with original public key memset(&ml_kem_params, 0, sizeof(ml_kem_params)); ml_kem_params.ulVersion = CK_IBM_ML_KEM_VERSION; ml_kem_params.mode = CK_IBM_ML_KEM_ENCAPSULATE; ml_kem_params.ulCipherLen = sizeof(output_data); ml_kem_params.pCipher = output_data; ml_kem_params.kdf = CKD_NULL; ml_kem_params.pSharedData = NULL;; ml_kem_params.ulSharedDataLen = 0; ml_kem_params.bPrepend = CK_FALSE; ml_kem_params.hSecret = CK_INVALID_HANDLE; rc = funcs->C_DeriveKey(session, &mech, publ_key, derive_tmpl, derive_tmpl_len, &key1); if (rc != CKR_OK) { testcase_fail("C_DeriveKey (encapsulate) with %s failed, rc=%s", ml_kem_variants[i].name, p11_get_ckr(rc)); goto error; } outlen = ml_kem_params.ulCipherLen; // Decapsulate with original private key memset(&ml_kem_params, 0, sizeof(ml_kem_params)); ml_kem_params.ulVersion = CK_IBM_ML_KEM_VERSION; ml_kem_params.mode = CK_IBM_ML_KEM_DECAPSULATE; ml_kem_params.ulCipherLen = outlen; ml_kem_params.kdf = CKD_NULL; ml_kem_params.pCipher = output_data; ml_kem_params.pSharedData = NULL;; ml_kem_params.ulSharedDataLen = 0; ml_kem_params.bPrepend = CK_FALSE; ml_kem_params.hSecret = CK_INVALID_HANDLE; rc = funcs->C_DeriveKey(session, &mech, priv_key, derive_tmpl, derive_tmpl_len, &key2); if (rc != CKR_OK) { testcase_fail("C_DeriveKey (decapsulate) with %s failed, rc=%s", ml_kem_variants[i].name, p11_get_ckr(rc)); goto error; } // export original public key's CCA/EP11 blob rc = export_ibm_opaque(session, publ_key, &publ_opaquekey, &publ_opaquekeylen); if (rc != CKR_OK) { testcase_fail("export_ibm_opaque on public key failed rc=%s", p11_get_ckr(rc)); goto error; } // re-import this CCA/EP11 public ML-KEM key blob as new public ML-KEM key snprintf(label, sizeof(label), "re-imported_ml_kem_%s_public_key", ml_kem_variants[i].name); rc = import_ml_kem_publ_key(session, CKK_IBM_ML_KEM, label, publ_opaquekey, publ_opaquekeylen, &imp_publ_key); if (rc != CKR_OK) { if (rc == CKR_PUBLIC_KEY_INVALID && is_ep11_token(SLOT_ID)) { testcase_skip("import_ibm_ml_kem_publ_key on exported CCA/EP11 ML-KEM key blob failed due to missing EP11 FW fix"); } else { testcase_fail("import_ibm_ml_kem_publ_key on exported CCA/EP11 ML-KEM key blob failed rc=%s", p11_get_ckr(rc)); } goto error; } // export original private key's CCA/EP11 blob rc = export_ibm_opaque(session, priv_key, &priv_opaquekey, &priv_opaquekeylen); if (rc != CKR_OK) { testcase_fail("export_ibm_opaque on private key failed rc=%s", p11_get_ckr(rc)); goto error; } // re-import this CCA/EP11 private ML-KEM key blob as new private ML-KEM key snprintf(label, sizeof(label), "re-imported_ml_kem_%s_private_key", ml_kem_variants[i].name); rc = import_ml_kem_priv_key(session, CKK_IBM_ML_KEM, label, priv_opaquekey, priv_opaquekeylen, &imp_priv_key); if (rc != CKR_OK) { if (rc == CKR_PUBLIC_KEY_INVALID && is_ep11_token(SLOT_ID)) { testcase_skip("import_ibm_ml_kem_priv_key on exported CCA/EP11 ML-KEM key blob failed due to missing EP11 FW fix"); } else { testcase_fail("import_ibm_ml_kem_priv_key on exported CCA/EP11 ML-KEM key blob failed rc=%s", p11_get_ckr(rc)); } goto error; } // Decapsulate with imported private key memset(&ml_kem_params, 0, sizeof(ml_kem_params)); ml_kem_params.ulVersion = CK_IBM_ML_KEM_VERSION; ml_kem_params.mode = CK_IBM_ML_KEM_DECAPSULATE; ml_kem_params.ulCipherLen = outlen; ml_kem_params.kdf = CKD_NULL; ml_kem_params.pCipher = output_data; ml_kem_params.pSharedData = NULL;; ml_kem_params.ulSharedDataLen = 0; ml_kem_params.bPrepend = CK_FALSE; ml_kem_params.hSecret = CK_INVALID_HANDLE; rc = funcs->C_DeriveKey(session, &mech, imp_priv_key, derive_tmpl, derive_tmpl_len, &key3); if (rc != CKR_OK) { testcase_fail("C_DeriveKey (decapsulate) with %s failed, rc=%s", ml_kem_variants[i].name, p11_get_ckr(rc)); goto error; } // Encapsulate with imported public key memset(&ml_kem_params, 0, sizeof(ml_kem_params)); ml_kem_params.ulVersion = CK_IBM_ML_KEM_VERSION; ml_kem_params.mode = CK_IBM_ML_KEM_ENCAPSULATE; ml_kem_params.ulCipherLen = sizeof(output_data); ml_kem_params.pCipher = output_data; ml_kem_params.kdf = CKD_NULL; ml_kem_params.pSharedData = NULL;; ml_kem_params.ulSharedDataLen = 0; ml_kem_params.bPrepend = CK_FALSE; ml_kem_params.hSecret = CK_INVALID_HANDLE; rc = funcs->C_DeriveKey(session, &mech, imp_publ_key, derive_tmpl, derive_tmpl_len, &key4); if (rc != CKR_OK) { testcase_fail("C_DeriveKey (encapsulate) with %s failed, rc=%s", ml_kem_variants[i].name, p11_get_ckr(rc)); goto error; } outlen = ml_kem_params.ulCipherLen; testcase_pass("CCA/EP11 export/import test with public/private IBM ML-KEM %s keys", ml_kem_variants[i].name); error: free(priv_opaquekey); priv_opaquekey = NULL; free(publ_opaquekey); publ_opaquekey = NULL; if (publ_key != CK_INVALID_HANDLE) { funcs->C_DestroyObject(session, publ_key); publ_key = CK_INVALID_HANDLE; } if (priv_key != CK_INVALID_HANDLE) { funcs->C_DestroyObject(session, priv_key); priv_key = CK_INVALID_HANDLE; } if (imp_publ_key != CK_INVALID_HANDLE) { funcs->C_DestroyObject(session, imp_publ_key); imp_publ_key = CK_INVALID_HANDLE; } if (imp_priv_key != CK_INVALID_HANDLE) { funcs->C_DestroyObject(session, imp_priv_key); imp_priv_key = CK_INVALID_HANDLE; } if (key1 != CK_INVALID_HANDLE) { funcs->C_DestroyObject(session, key1); key1 = CK_INVALID_HANDLE; } if (key2 != CK_INVALID_HANDLE) { funcs->C_DestroyObject(session, key2); key2 = CK_INVALID_HANDLE; } if (key3 != CK_INVALID_HANDLE) { funcs->C_DestroyObject(session, key3); key3 = CK_INVALID_HANDLE; } if (key4 != CK_INVALID_HANDLE) { funcs->C_DestroyObject(session, key4); key4 = CK_INVALID_HANDLE; } } testcase_cleanup: testcase_close_session(); out: return rc; } static CK_RV ml_dsa_export_import_tests(CK_BBOOL prehash) { CK_RV rc = CKR_OK; CK_FLAGS flags; CK_SESSION_HANDLE session; CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; CK_ULONG user_pin_len; CK_BBOOL attr_sign = TRUE; CK_BBOOL attr_verify = TRUE; CK_BBOOL true = CK_TRUE; CK_BBOOL false = CK_FALSE; CK_OBJECT_HANDLE publ_key = CK_INVALID_HANDLE, priv_key = CK_INVALID_HANDLE; CK_OBJECT_HANDLE imp_priv_key = CK_INVALID_HANDLE, imp_publ_key = CK_INVALID_HANDLE; CK_BYTE msg[32], sig[5000]; CK_ULONG msglen, siglen; CK_MECHANISM mech = { prehash ? CKM_HASH_ML_DSA_SHA512 : CKM_ML_DSA, 0, 0}; CK_MECHANISM keygen_mech = { CKM_ML_DSA_KEY_PAIR_GEN, 0, 0}; CK_BYTE *priv_opaquekey = NULL, *publ_opaquekey = NULL; CK_ULONG priv_opaquekeylen, publ_opaquekeylen; CK_IBM_CCA_ML_DSA_KEY_MODE_TYPE cca_key_mode = prehash ? CK_IBM_CCA_ML_DSA_PREHASH_KEY : CK_IBM_CCA_ML_DSA_PURE_KEY; char label[80]; int i; if (!is_cca_token(SLOT_ID) && !is_ep11_token(SLOT_ID)) { testcase_skip("this slot is not a CCA or EP11 token"); goto out; } if (!mech_supported(SLOT_ID, CKM_ML_DSA_KEY_PAIR_GEN)) { testcase_skip("this slot does not support CKM_ML_DSA_KEY_PAIR_GEN"); goto out; } if (!mech_supported(SLOT_ID, prehash ? CKM_HASH_ML_DSA_SHA512 : CKM_ML_DSA)) { testcase_skip("this slot does not support %s", prehash ? "CKM_HASH_ML_DSA_SHA512" : "CKM_ML_DSA"); goto out; } testcase_rw_session(); testcase_user_login(); for (i = 0; ml_dsa_variants[i].parameter_set != 0; i++) { CK_ATTRIBUTE ml_dsa_attr_private[] = { {CKA_SIGN, &attr_sign, sizeof(CK_BBOOL)}, {CKA_PARAMETER_SET, (CK_BYTE *)&ml_dsa_variants[i].parameter_set, sizeof(CK_ULONG)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_PRIVATE, &true, sizeof(true)}, {CKA_IBM_CCA_ML_DSA_KEY_MODE, &cca_key_mode, sizeof(cca_key_mode)}, }; CK_ATTRIBUTE ml_dsa_attr_public[] = { {CKA_VERIFY, &attr_verify, sizeof(CK_BBOOL)}, {CKA_PARAMETER_SET, (CK_BYTE *)&ml_dsa_variants[i].parameter_set, sizeof(CK_ULONG)}, {CKA_TOKEN, &false, sizeof(false)}, {CKA_PRIVATE, &false, sizeof(false)}, }; CK_ULONG num_ml_dsa_attrs = sizeof(ml_dsa_attr_public) / sizeof(CK_ATTRIBUTE); testcase_begin("CCA/EP11 export/import test with public/private ML-DSA %s keys (%s)", ml_dsa_variants[i].name, prehash ? "Pre-hash" : "Pure"); /* Generate ML-DSA key pair */ rc = funcs->C_GenerateKeyPair(session, &keygen_mech, ml_dsa_attr_public, num_ml_dsa_attrs, ml_dsa_attr_private, num_ml_dsa_attrs + (is_cca_token(SLOT_ID) ? 1 : 0), &publ_key, &priv_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("ML-DSA variant %s is not supported", ml_dsa_variants[i].name); goto error; } else if (rc == CKR_POLICY_VIOLATION) { testcase_skip("ML-DSA key generation is not allowed by policy"); goto error; } else { testcase_new_assertion(); testcase_fail("C_GenerateKeyPair with %s failed, rc=%s", ml_dsa_variants[i].name, p11_get_ckr(rc)); goto error; } } testcase_new_assertion(); // sign with original private key rc = funcs->C_SignInit(session, &mech, priv_key); if (rc != CKR_OK) { testcase_error("C_SignInit() rc=%s", p11_get_ckr(rc)); goto error; } msglen = sizeof(msg); siglen = sizeof(sig); rc = funcs->C_Sign(session, msg, msglen, sig, &siglen); if (rc != CKR_OK) { testcase_error("C_Sign() rc=%s", p11_get_ckr(rc)); goto error; } // verify with original public key rc = funcs->C_VerifyInit(session, &mech, publ_key); if (rc != CKR_OK) { testcase_error("C_VerifyInit() rc=%s", p11_get_ckr(rc)); goto error; } rc = funcs->C_Verify(session, msg, msglen, sig, siglen); if (rc == CKR_OK) { ; } else if (rc == CKR_SIGNATURE_INVALID || rc == CKR_SIGNATURE_LEN_RANGE) { testcase_fail("signature verify failed"); goto error; } else { testcase_error("C_Verify() rc=%s", p11_get_ckr(rc)); goto error; } // export original public key's CCA/EP11 blob rc = export_ibm_opaque(session, publ_key, &publ_opaquekey, &publ_opaquekeylen); if (rc != CKR_OK) { testcase_fail("export_ibm_opaque on public key failed rc=%s", p11_get_ckr(rc)); goto error; } // re-import this CCA/EP11 public ML-DSA key blob as new public ML-DSA key snprintf(label, sizeof(label), "re-imported_ml_dsa_%s_public_key", ml_dsa_variants[i].name); rc = import_ml_dsa_publ_key(session, CKK_ML_DSA, label, publ_opaquekey, publ_opaquekeylen, &imp_publ_key); if (rc != CKR_OK) { if (rc == CKR_PUBLIC_KEY_INVALID && is_ep11_token(SLOT_ID)) { testcase_skip("import_ml_dsa_publ_key on exported CCA/EP11 ML-DSA key blob failed due to missing EP11 FW fix"); } else { testcase_fail("import_ml_dsa_publ_key on exported CCA/EP11 ML-DSA key blob failed rc=%s", p11_get_ckr(rc)); } goto error; } // export original private key's CCA/EP11 blob rc = export_ibm_opaque(session, priv_key, &priv_opaquekey, &priv_opaquekeylen); if (rc != CKR_OK) { testcase_fail("export_ibm_opaque on private key failed rc=%s", p11_get_ckr(rc)); goto error; } // re-import this CCA/EP11 private ML-DSA key blob as new private ML-DSA key snprintf(label, sizeof(label), "re-imported_ml_dsa_%s_private_key", ml_dsa_variants[i].name); rc = import_ml_dsa_priv_key(session, CKK_ML_DSA, label, priv_opaquekey, priv_opaquekeylen, &imp_priv_key); if (rc != CKR_OK) { if (rc == CKR_PUBLIC_KEY_INVALID && is_ep11_token(SLOT_ID)) { testcase_skip("import_ml_dsa_priv_key on exported CCA/EP11 ML-DSA key blob failed due to missing EP11 FW fix"); } else { testcase_fail("import_ml_dsa_priv_key on exported CCA/EP11 ML-DSA key blob failed rc=%s", p11_get_ckr(rc)); } goto error; } // sign with re-imported private key rc = funcs->C_SignInit(session, &mech, imp_priv_key); if (rc != CKR_OK) { testcase_error("C_SignInit() with re-imported priv key failed, rc=%s", p11_get_ckr(rc)); goto error; } msglen = sizeof(msg); siglen = sizeof(sig); rc = funcs->C_Sign(session, msg, msglen, sig, &siglen); if (rc != CKR_OK) { testcase_error("C_Sign() with re-imported priv key failed, rc=%s", p11_get_ckr(rc)); goto error; } // verify with original public key rc = funcs->C_VerifyInit(session, &mech, publ_key); if (rc != CKR_OK) { testcase_error("C_VerifyInit() rc=%s", p11_get_ckr(rc)); goto error; } rc = funcs->C_Verify(session, msg, msglen, sig, siglen); if (rc == CKR_OK) { ; } else if (rc == CKR_SIGNATURE_INVALID || rc == CKR_SIGNATURE_LEN_RANGE) { testcase_fail("signature verify on signature generated with re-imported priv key failed, rc=%s", p11_get_ckr(rc)); goto error; } else { testcase_error("C_Verify() on signature generated with re-imported priv key failed, rc=%s", p11_get_ckr(rc)); goto error; } // sign with original private key rc = funcs->C_SignInit(session, &mech, priv_key); if (rc != CKR_OK) { testcase_error("C_SignInit() rc=%s", p11_get_ckr(rc)); goto error; } msglen = sizeof(msg); siglen = sizeof(sig); rc = funcs->C_Sign(session, msg, msglen, sig, &siglen); if (rc != CKR_OK) { testcase_error("C_Sign() rc=%s", p11_get_ckr(rc)); goto error; } // verify with re-imported public key rc = funcs->C_VerifyInit(session, &mech, imp_publ_key); if (rc != CKR_OK) { testcase_error("C_VerifyInit() with re-imported pub key failed, rc=%s", p11_get_ckr(rc)); goto error; } rc = funcs->C_Verify(session, msg, msglen, sig, siglen); if (rc == CKR_OK) { ; } else if (rc == CKR_SIGNATURE_INVALID || rc == CKR_SIGNATURE_LEN_RANGE) { testcase_fail("signature verify with re-imported pub key on signature failed"); goto error; } else { testcase_error("C_Verify() with re-imported pub key on signature failed, rc=%s", p11_get_ckr(rc)); goto error; } testcase_pass("CCA/EP11 export/import test with public/private ML-DSA %s keys (%s)", ml_dsa_variants[i].name, prehash ? "Pre-hash" : "Pure"); error: free(priv_opaquekey); priv_opaquekey = NULL; free(publ_opaquekey); publ_opaquekey = NULL; if (publ_key != CK_INVALID_HANDLE) { funcs->C_DestroyObject(session, publ_key); publ_key = CK_INVALID_HANDLE; } if (priv_key != CK_INVALID_HANDLE) { funcs->C_DestroyObject(session, priv_key); priv_key = CK_INVALID_HANDLE; } if (imp_publ_key != CK_INVALID_HANDLE) { funcs->C_DestroyObject(session, imp_publ_key); imp_publ_key = CK_INVALID_HANDLE; } if (imp_priv_key != CK_INVALID_HANDLE) { funcs->C_DestroyObject(session, imp_priv_key); imp_priv_key = CK_INVALID_HANDLE; } } testcase_cleanup: testcase_close_session(); out: return rc; } static CK_RV ml_kem_export_import_tests(void) { CK_RV rc = CKR_OK; CK_FLAGS flags; CK_SESSION_HANDLE session; CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; CK_ULONG user_pin_len; CK_BBOOL attr_encaps = TRUE; CK_BBOOL attr_decaps = TRUE; CK_BBOOL true = CK_TRUE; CK_BBOOL false = CK_FALSE; CK_OBJECT_HANDLE publ_key = CK_INVALID_HANDLE, priv_key = CK_INVALID_HANDLE; CK_OBJECT_HANDLE imp_priv_key = CK_INVALID_HANDLE, imp_publ_key = CK_INVALID_HANDLE; CK_MECHANISM mech = { CKM_ML_KEM, 0, 0}; CK_MECHANISM keygen_mech = { CKM_ML_KEM_KEY_PAIR_GEN, 0, 0}; CK_BYTE *priv_opaquekey = NULL, *publ_opaquekey = NULL; CK_ULONG priv_opaquekeylen, publ_opaquekeylen; CK_BYTE *cipher = NULL; CK_ULONG cipher_len = 0; CK_OBJECT_HANDLE secret_key1 = CK_INVALID_HANDLE; CK_OBJECT_HANDLE secret_key2 = CK_INVALID_HANDLE; CK_OBJECT_HANDLE secret_key3 = CK_INVALID_HANDLE; CK_OBJECT_HANDLE secret_key4 = CK_INVALID_HANDLE; CK_OBJECT_HANDLE secret_key5 = CK_INVALID_HANDLE; CK_BYTE iv[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; CK_MECHANISM aes_mech = { CKM_AES_CBC, iv, sizeof(iv) }; CK_BYTE data[160], encdata1[160], encdata2[160], encdata3[160]; CK_BYTE encdata4[160], encdata5[160]; CK_ULONG ilen, len; char label[80]; int i; if (!is_cca_token(SLOT_ID) && !is_ep11_token(SLOT_ID)) { testcase_skip("this slot is not a CCA or EP11 token"); goto out; } if (!mech_supported(SLOT_ID, CKM_ML_KEM_KEY_PAIR_GEN)) { testcase_skip("this slot does not support CKM_ML_KEM_KEY_PAIR_GEN"); goto out; } if (!mech_supported(SLOT_ID, CKM_ML_KEM)) { testcase_skip("this slot does not support CKM_ML_KEM"); goto out; } testcase_rw_session(); testcase_user_login(); for (i = 0; ml_kem_variants[i].parameter_set != 0; i++) { CK_ATTRIBUTE ml_kem_attr_private[] = { {CKA_DECAPSULATE, &attr_decaps, sizeof(CK_BBOOL)}, {CKA_PARAMETER_SET, (CK_BYTE *)&ml_kem_variants[i].parameter_set, sizeof(CK_ULONG)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_PRIVATE, &true, sizeof(true)}, }; CK_ATTRIBUTE ml_kem_attr_public[] = { {CKA_ENCAPSULATE, &attr_encaps, sizeof(CK_BBOOL)}, {CKA_PARAMETER_SET, (CK_BYTE *)&ml_kem_variants[i].parameter_set, sizeof(CK_ULONG)}, {CKA_TOKEN, &false, sizeof(false)}, {CKA_PRIVATE, &false, sizeof(false)}, }; CK_ULONG num_ml_kem_attrs = sizeof(ml_kem_attr_public) / sizeof(CK_ATTRIBUTE); CK_OBJECT_CLASS class = CKO_SECRET_KEY; CK_KEY_TYPE key_type = CKK_AES; CK_ULONG key_len = 32; CK_BBOOL ck_true = CK_TRUE; CK_BBOOL ck_false = CK_FALSE; CK_ATTRIBUTE sym_key_tmpl[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &key_type, sizeof(key_type)}, {CKA_SENSITIVE, &ck_false, sizeof(ck_false)}, {CKA_VALUE_LEN, &key_len, sizeof(key_len)}, {CKA_SIGN, &ck_true, sizeof(ck_true)}, {CKA_VERIFY, &ck_true, sizeof(ck_true)}, }; CK_ULONG sym_key_tmpl_len = sizeof(sym_key_tmpl) / sizeof(CK_ATTRIBUTE); testcase_begin("CCA/EP11 export/import test with public/private ML-KEM %s keys", ml_kem_variants[i].name); /* Generate ML-DSA key pair */ rc = funcs->C_GenerateKeyPair(session, &keygen_mech, ml_kem_attr_public, num_ml_kem_attrs, ml_kem_attr_private, num_ml_kem_attrs, &publ_key, &priv_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("ML-KEM variant %s is not supported", ml_kem_variants[i].name); goto error; } else if (rc == CKR_POLICY_VIOLATION) { testcase_skip("ML-KEM key generation is not allowed by policy"); goto error; } else { testcase_new_assertion(); testcase_fail("C_GenerateKeyPair with %s failed, rc=%s", ml_kem_variants[i].name, p11_get_ckr(rc)); goto error; } } testcase_new_assertion(); // encapsulate with original public key rc = funcs3_2->C_EncapsulateKey(session, &mech, publ_key, sym_key_tmpl, sym_key_tmpl_len, cipher, &cipher_len, NULL); if (rc != CKR_OK) { testcase_error("C_EncapsulateKey (size query) rc=%s", p11_get_ckr(rc)); goto error; } cipher = calloc(cipher_len, sizeof(CK_BYTE)); if (cipher == NULL) { testcase_error("Can't allocate memory for %lu bytes", sizeof(CK_BYTE) * cipher_len); rc = CKR_HOST_MEMORY; goto error; } rc = funcs3_2->C_EncapsulateKey(session, &mech, publ_key, sym_key_tmpl, sym_key_tmpl_len, cipher, &cipher_len, &secret_key1); if (rc != CKR_OK) { testcase_error("C_EncapsulateKey rc=%s", p11_get_ckr(rc)); goto error; } // Decapsulate with original private key rc = funcs3_2->C_DecapsulateKey(session, &mech, priv_key, sym_key_tmpl, sym_key_tmpl_len, cipher, cipher_len, &secret_key2); if (rc != CKR_OK) { testcase_error("C_DecapsulateKey rc=%s", p11_get_ckr(rc)); goto error; } // encrypt some data with secret key 1 rc = funcs->C_EncryptInit(session, &aes_mech, secret_key1); if (rc != CKR_OK) { testcase_error("C_EncryptInit rc=%s", p11_get_ckr(rc)); goto error; } ilen = len = sizeof(data); rc = funcs->C_Encrypt(session, data, ilen, encdata1, &len); if (rc != CKR_OK) { testcase_error("C_Encrypt rc=%s", p11_get_ckr(rc)); goto error; } if (ilen != len) { testcase_fail("plain and encrypted data len does not match"); goto error; } // encrypt some data with secret key 2 rc = funcs->C_EncryptInit(session, &aes_mech, secret_key2); if (rc != CKR_OK) { testcase_error("C_EncryptInit rc=%s", p11_get_ckr(rc)); goto error; } ilen = len = sizeof(data); rc = funcs->C_Encrypt(session, data, ilen, encdata2, &len); if (rc != CKR_OK) { testcase_error("C_Encrypt rc=%s", p11_get_ckr(rc)); goto error; } if (ilen != len) { testcase_fail("plain and encrypted data len does not match"); goto error; } // and check the encrypted data to be equal if (memcmp(encdata1, encdata2, len) != 0) { testcase_fail("encrypted data from en/decapsulate with original keys is NOT the same"); goto error; } // export original public key's CCA/EP11 blob rc = export_ibm_opaque(session, publ_key, &publ_opaquekey, &publ_opaquekeylen); if (rc != CKR_OK) { testcase_fail("export_ibm_opaque on public key failed rc=%s", p11_get_ckr(rc)); goto error; } // re-import this CCA/EP11 public ML-KEM key blob as new public ML-KEM key snprintf(label, sizeof(label), "re-imported_ml_kem_%s_public_key", ml_kem_variants[i].name); rc = import_ml_kem_publ_key(session, CKK_ML_KEM, label, publ_opaquekey, publ_opaquekeylen, &imp_publ_key); if (rc != CKR_OK) { if (rc == CKR_PUBLIC_KEY_INVALID && is_ep11_token(SLOT_ID)) { testcase_skip("import_ml_kem_publ_key on exported CCA/EP11 ML-KEM key blob failed due to missing EP11 FW fix"); } else { testcase_fail("import_ml_kem_publ_key on exported CCA/EP11 ML-KEM key blob failed rc=%s", p11_get_ckr(rc)); } goto error; } // export original private key's CCA/EP11 blob rc = export_ibm_opaque(session, priv_key, &priv_opaquekey, &priv_opaquekeylen); if (rc != CKR_OK) { testcase_fail("export_ibm_opaque on private key failed rc=%s", p11_get_ckr(rc)); goto error; } // re-import this CCA/EP11 private ML-KEM key blob as new private ML-KEM key snprintf(label, sizeof(label), "re-imported_ml_kem_%s_private_key", ml_kem_variants[i].name); rc = import_ml_kem_priv_key(session, CKK_ML_KEM, label, priv_opaquekey, priv_opaquekeylen, &imp_priv_key); if (rc != CKR_OK) { if (rc == CKR_PUBLIC_KEY_INVALID && is_ep11_token(SLOT_ID)) { testcase_skip("import_ml_kem_priv_key on exported CCA/EP11 ML-KEM key blob failed due to missing EP11 FW fix"); } else { testcase_fail("import_ml_kem_priv_key on exported CCA/EP11 ML-KEM key blob failed rc=%s", p11_get_ckr(rc)); } goto error; } // Decapsulate with re-imported private key rc = funcs3_2->C_DecapsulateKey(session, &mech, imp_priv_key, sym_key_tmpl, sym_key_tmpl_len, cipher, cipher_len, &secret_key3); if (rc != CKR_OK) { testcase_error("C_DecapsulateKey rc=%s", p11_get_ckr(rc)); goto error; } // encrypt some data with secret key 3 rc = funcs->C_EncryptInit(session, &aes_mech, secret_key3); if (rc != CKR_OK) { testcase_error("C_EncryptInit rc=%s", p11_get_ckr(rc)); goto error; } ilen = len = sizeof(data); rc = funcs->C_Encrypt(session, data, ilen, encdata3, &len); if (rc != CKR_OK) { testcase_error("C_Encrypt rc=%s", p11_get_ckr(rc)); goto error; } if (ilen != len) { testcase_fail("plain and encrypted data len does not match"); goto error; } // and check the encrypted data to be equal if (memcmp(encdata1, encdata3, len) != 0) { testcase_fail("encrypted data from en/decapsulate with original and exported/imported key is NOT the same"); goto error; } free(cipher); cipher = NULL; cipher_len = 0; // encapsulate with re-imported public key rc = funcs3_2->C_EncapsulateKey(session, &mech, imp_publ_key, sym_key_tmpl, sym_key_tmpl_len, cipher, &cipher_len, NULL); if (rc != CKR_OK) { testcase_error("C_EncapsulateKey (size query) rc=%s", p11_get_ckr(rc)); goto error; } cipher = calloc(cipher_len, sizeof(CK_BYTE)); if (cipher == NULL) { testcase_error("Can't allocate memory for %lu bytes", sizeof(CK_BYTE) * cipher_len); rc = CKR_HOST_MEMORY; goto error; } rc = funcs3_2->C_EncapsulateKey(session, &mech, imp_publ_key, sym_key_tmpl, sym_key_tmpl_len, cipher, &cipher_len, &secret_key4); if (rc != CKR_OK) { testcase_error("C_EncapsulateKey rc=%s", p11_get_ckr(rc)); goto error; } // Decapsulate with re-imported private key rc = funcs3_2->C_DecapsulateKey(session, &mech, imp_priv_key, sym_key_tmpl, sym_key_tmpl_len, cipher, cipher_len, &secret_key5); if (rc != CKR_OK) { testcase_error("C_DecapsulateKey rc=%s", p11_get_ckr(rc)); goto error; } free(cipher); cipher = NULL; cipher_len = 0; // encrypt some data with secret key 4 rc = funcs->C_EncryptInit(session, &aes_mech, secret_key4); if (rc != CKR_OK) { testcase_error("C_EncryptInit rc=%s", p11_get_ckr(rc)); goto error; } ilen = len = sizeof(data); rc = funcs->C_Encrypt(session, data, ilen, encdata4, &len); if (rc != CKR_OK) { testcase_error("C_Encrypt rc=%s", p11_get_ckr(rc)); goto error; } if (ilen != len) { testcase_fail("plain and encrypted data len does not match"); goto error; } // encrypt some data with secret key 5 rc = funcs->C_EncryptInit(session, &aes_mech, secret_key5); if (rc != CKR_OK) { testcase_error("C_EncryptInit rc=%s", p11_get_ckr(rc)); goto error; } ilen = len = sizeof(data); rc = funcs->C_Encrypt(session, data, ilen, encdata5, &len); if (rc != CKR_OK) { testcase_error("C_Encrypt rc=%s", p11_get_ckr(rc)); goto error; } if (ilen != len) { testcase_fail("plain and encrypted data len does not match"); goto error; } // and check the encrypted data to be equal if (memcmp(encdata4, encdata5, len) != 0) { testcase_fail("encrypted data from en/decapsulate with original and exported/imported key is NOT the same"); goto error; } testcase_pass("CCA/EP11 export/import test with public/private ML-DSA %s keys", ml_kem_variants[i].name); error: free(priv_opaquekey); priv_opaquekey = NULL; free(publ_opaquekey); publ_opaquekey = NULL; free(cipher); cipher = NULL; cipher_len = 0; if (publ_key != CK_INVALID_HANDLE) { funcs->C_DestroyObject(session, publ_key); publ_key = CK_INVALID_HANDLE; } if (priv_key != CK_INVALID_HANDLE) { funcs->C_DestroyObject(session, priv_key); priv_key = CK_INVALID_HANDLE; } if (imp_publ_key != CK_INVALID_HANDLE) { funcs->C_DestroyObject(session, imp_publ_key); imp_publ_key = CK_INVALID_HANDLE; } if (imp_priv_key != CK_INVALID_HANDLE) { funcs->C_DestroyObject(session, imp_priv_key); imp_priv_key = CK_INVALID_HANDLE; } if (secret_key1 != CK_INVALID_HANDLE) { funcs->C_DestroyObject(session, secret_key1); secret_key1 = CK_INVALID_HANDLE; } if (secret_key2 != CK_INVALID_HANDLE) { funcs->C_DestroyObject(session, secret_key2); secret_key2 = CK_INVALID_HANDLE; } if (secret_key3 != CK_INVALID_HANDLE) { funcs->C_DestroyObject(session, secret_key3); secret_key3 = CK_INVALID_HANDLE; } if (secret_key4 != CK_INVALID_HANDLE) { funcs->C_DestroyObject(session, secret_key4); secret_key4 = CK_INVALID_HANDLE; } if (secret_key5 != CK_INVALID_HANDLE) { funcs->C_DestroyObject(session, secret_key5); secret_key5 = CK_INVALID_HANDLE; } } testcase_cleanup: testcase_close_session(); out: return rc; } static CK_RV cca_ep11_export_import_tests(void) { CK_RV rc = CKR_OK, rv = CKR_OK; testsuite_begin("CCA/EP11 export/import tests"); rc = des_export_import_tests(); if (rc != CKR_OK && rv == CKR_OK) rv = rc; rc = des3_export_import_tests(); if (rc != CKR_OK && rv == CKR_OK) rv = rc; rc = aes_export_import_tests(CK_IBM_CCA_AES_DATA_KEY); if (rc != CKR_OK && rv == CKR_OK) rv = rc; rc = aes_xts_export_import_tests(CK_IBM_CCA_AES_DATA_KEY); if (rc != CKR_OK && rv == CKR_OK) rv = rc; rc = aes_export_import_tests(CK_IBM_CCA_AES_CIPHER_KEY); if (rc != CKR_OK && rv == CKR_OK) rv = rc; rc = aes_xts_export_import_tests(CK_IBM_CCA_AES_CIPHER_KEY); if (rc != CKR_OK && rv == CKR_OK) rv = rc; rc = generic_secret_export_import_tests(); if (rc != CKR_OK && rv == CKR_OK) rv = rc; rc = rsa_export_import_tests(); if (rc != CKR_OK && rv == CKR_OK) rv = rc; rc = ecc_export_import_tests(); if (rc != CKR_OK && rv == CKR_OK) rv = rc; rc = ibm_dilithium_export_import_tests(); if (rc != CKR_OK && rv == CKR_OK) rv = rc; rc = ibm_ml_dsa_export_import_tests(); if (rc != CKR_OK && rv == CKR_OK) rv = rc; rc = ibm_ml_kem_export_import_tests(); if (rc != CKR_OK && rv == CKR_OK) rv = rc; rc = ml_dsa_export_import_tests(FALSE); if (rc != CKR_OK && rv == CKR_OK) rv = rc; rc = ml_dsa_export_import_tests(TRUE); if (rc != CKR_OK && rv == CKR_OK) rv = rc; rc = ml_kem_export_import_tests(); if (rc != CKR_OK && rv == CKR_OK) rv = rc; 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", 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; // 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(); rv = cca_ep11_export_import_tests(); testcase_print_result(); funcs->C_Finalize(NULL); return testcase_return(rv); } opencryptoki-opencryptoki-451d99c/testcases/misc_tests/dh-key.pem000066400000000000000000000031121520105705100253600ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MIICJgIBADCCARcGCSqGSIb3DQEDATCCAQgCggEBAJT8c8rEOoVm3iBw8x+ucYb9 XVNEbYRewPJc82hzDH0jFVSnlrgq4Z0F77kONf7mBzL+37CA8o/3F3fYFqpCt/0c diNGCvgMMxbOD+fkCcz9OetDVJLev2UFHloxIUU30MSEZkYKIR0bhaC7bPnoTplP cdUPT9r0gl2Q+RTfRpBpFhp8hLb7boj4W+7xiAxoFxwHbfSWK+ng2Go6BtYyE7UM xIxqD4LaEi0r0XlCUle6oa0GixL/PXZk7YC4WN0JSfnrjC4ipnK2iqkOGuW9HG0+ O8tbPhHAv9r+gQMoE/KR/dtpe2oVY4oeo/bc18r4tdalbZ1O3brIRcGPtAVBdpsC AQIEggEEAoIBAFHMjHVZ5F0bF8HIs7K/akQRqX6XVHY7iRl1ml1nxue8bymUDUMa vK8HiAahxX1puaBsa9xnwkYmZhmEwz3Zk4/mTnL08ukyeE9rr17aKzRX6KqejXrn argeLSayxXgtDiZZ3rDu0+rvfqr53V5K5VjlNAn3hhMA5ADHX9qZWrF8eTi7vzW9 fJPSnUosGH24uXm9IvMGL9atkG+9gajypH3wjxWjrUNb5bi73GJYU8ZHiDKlJoWF s6VFkDX9OOLUAxzA+Y55TnEQhWfuN3MqtPs7PsjoLLWAxnQz9AGMIa8vbUvcJ6RT h0MNk8A1UqDbpAjVtt5kMrIWhRMT/8tCQfY= -----END PRIVATE KEY----- -----BEGIN PUBLIC KEY----- MIICJTCCARcGCSqGSIb3DQEDATCCAQgCggEBAJT8c8rEOoVm3iBw8x+ucYb9XVNE bYRewPJc82hzDH0jFVSnlrgq4Z0F77kONf7mBzL+37CA8o/3F3fYFqpCt/0cdiNG CvgMMxbOD+fkCcz9OetDVJLev2UFHloxIUU30MSEZkYKIR0bhaC7bPnoTplPcdUP T9r0gl2Q+RTfRpBpFhp8hLb7boj4W+7xiAxoFxwHbfSWK+ng2Go6BtYyE7UMxIxq D4LaEi0r0XlCUle6oa0GixL/PXZk7YC4WN0JSfnrjC4ipnK2iqkOGuW9HG0+O8tb PhHAv9r+gQMoE/KR/dtpe2oVY4oeo/bc18r4tdalbZ1O3brIRcGPtAVBdpsCAQID ggEGAAKCAQEAiGvIQMqZepZZ6pDDu+5GQrE4oXw/wFadEZrF+Y8RdOECR+200lZ8 0qtkZc7Zrg/5byg/lo34OfuEVzIQqTBb1VoMU9YhqTF7SXlH8+z6NXsgtNdbU4X4 LNujmFbBDVVAcBaWwUAHFGPNbzZUaRP22SiU3Iptg9fRinEfN5PKR/HJtbZtiGpT iTxFW+NTRhI2+JAWacggBJDzgRv3IaqaXh1NGJ8Zo6ZeKZTvMOs2dNsuIcObkHcB hQ/UTsYiVAuaFVJr7q0eaon1CTNLm+zMksmIv2CPl64RDSV++AsoLBgUjJUghe/I fWtDBbmLxcshmt3Hy2n5ZUAqOftgwT+rBQ== -----END PUBLIC KEY----- opencryptoki-opencryptoki-451d99c/testcases/misc_tests/dsa-key.pem000066400000000000000000000024521520105705100255420ustar00rootroot00000000000000-----BEGIN DSA PRIVATE KEY----- MIIBuwIBAAKBgQDFgWs8TAoM70nvJhMLcNkwUIvDpXIFrFlnw/ocFRRBhzNtKexR 3NLm1xVzgg7518ekN+4YNCzhZjH1Oh6vFCcFMtIN8dHcAE0MX/9aTg6GZVRwtsT+ jTOuHcS5CMxuzkWyz7Jcus70ARcyV5KQNvoOZXt9tOajyG8tegkE4dsFMwIVANjj ypjypZbIOJetXmIjw2sWA8mLAoGBAMH+9AULtz2n6BPWpXQiQEzIR45s+/sgY9DK 5zxCF4T9ElUzF53lxUVrZGnlXVJ8PSGFRa0xgG4EtFRp7G5GKWam12fdyO0cOO2c 9gZyFffQwx+qVRNW6V+5TmWgPWLI3XdmOw36oo5CzXOrmFstvtrd4zLTUo+S4pqc F+Z0U/rBAoGACspriIP0aI8R9qFOo16Y1oNBMZYMZKIRxOvo5cW8x4eNgJmGRuSc RQV6/iLf6vlCm2PeFJksKxjH6qImN7FMjuUSFW5rt1YD9rlEUNmbJImWVScL/rNj 4zWTZ8KVbJzNu+9MhcuamHIl/XlriDde3kyI2LPcxPX3nBicL+L/EjMCFHtL1HvE WHrIQow7Jh38J+jhzfcJ -----END DSA PRIVATE KEY----- -----BEGIN PUBLIC KEY----- MIIBtzCCASwGByqGSM44BAEwggEfAoGBAMWBazxMCgzvSe8mEwtw2TBQi8OlcgWs WWfD+hwVFEGHM20p7FHc0ubXFXOCDvnXx6Q37hg0LOFmMfU6Hq8UJwUy0g3x0dwA TQxf/1pODoZlVHC2xP6NM64dxLkIzG7ORbLPsly6zvQBFzJXkpA2+g5le3205qPI by16CQTh2wUzAhUA2OPKmPKllsg4l61eYiPDaxYDyYsCgYEAwf70BQu3PafoE9al dCJATMhHjmz7+yBj0MrnPEIXhP0SVTMXneXFRWtkaeVdUnw9IYVFrTGAbgS0VGns bkYpZqbXZ93I7Rw47Zz2BnIV99DDH6pVE1bpX7lOZaA9Ysjdd2Y7DfqijkLNc6uY Wy2+2t3jMtNSj5LimpwX5nRT+sEDgYQAAoGACspriIP0aI8R9qFOo16Y1oNBMZYM ZKIRxOvo5cW8x4eNgJmGRuScRQV6/iLf6vlCm2PeFJksKxjH6qImN7FMjuUSFW5r t1YD9rlEUNmbJImWVScL/rNj4zWTZ8KVbJzNu+9MhcuamHIl/XlriDde3kyI2LPc xPX3nBicL+L/EjM= -----END PUBLIC KEY----- opencryptoki-opencryptoki-451d99c/testcases/misc_tests/dsa-param.pem000066400000000000000000000007071520105705100260530ustar00rootroot00000000000000-----BEGIN DSA PARAMETERS----- MIIBHwKBgQDFgWs8TAoM70nvJhMLcNkwUIvDpXIFrFlnw/ocFRRBhzNtKexR3NLm 1xVzgg7518ekN+4YNCzhZjH1Oh6vFCcFMtIN8dHcAE0MX/9aTg6GZVRwtsT+jTOu HcS5CMxuzkWyz7Jcus70ARcyV5KQNvoOZXt9tOajyG8tegkE4dsFMwIVANjjypjy pZbIOJetXmIjw2sWA8mLAoGBAMH+9AULtz2n6BPWpXQiQEzIR45s+/sgY9DK5zxC F4T9ElUzF53lxUVrZGnlXVJ8PSGFRa0xgG4EtFRp7G5GKWam12fdyO0cOO2c9gZy FffQwx+qVRNW6V+5TmWgPWLI3XdmOw36oo5CzXOrmFstvtrd4zLTUo+S4pqcF+Z0 U/rB -----END DSA PARAMETERS----- opencryptoki-opencryptoki-451d99c/testcases/misc_tests/dual_functions.c000066400000000000000000001100131520105705100266540ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2022 * * This program is provided under the terms of the Common Public License, * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this * software constitutes recipient's acceptance of CPL-1.0 terms which can be * found in the file LICENSE file or at * https://opensource.org/licenses/cpl1.0.php */ /* File: dual_functions.c * * Test driver. In-depth regression test for PKCS #11 */ #include #include #include #include #include #include "pkcs11types.h" #include "regress.h" #include "common.c" #include "mechtable.h" #include "mech_to_str.h" CK_BYTE aes_iv[16] = { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f }; CK_MECHANISM aeskeygen_mech = { CKM_AES_KEY_GEN, NULL, 0 }; CK_MECHANISM endecrypt_mech = { CKM_AES_CBC, aes_iv, sizeof(aes_iv) }; CK_MECHANISM signver_mech = { CKM_SHA256_HMAC, NULL, 0 }; CK_MECHANISM mackeygen_mech = { CKM_GENERIC_SECRET_KEY_GEN, NULL, 0 }; CK_MECHANISM digest_mech = { CKM_SHA256, NULL, 0 }; CK_BYTE data1[512]; CK_BYTE data2[512]; CK_RV do_digest_encrypt_decrypt_digest(void) { CK_SESSION_HANDLE session; CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; CK_ULONG user_pin_len; CK_RV rc = CKR_OK, loc_rc; CK_FLAGS flags; CK_OBJECT_HANDLE aes_key = CK_INVALID_HANDLE; CK_BYTE encrypted1[sizeof(data1) + 16]; CK_ULONG encrypted1_len; CK_BYTE encrypted2[sizeof(data2) + 16]; CK_ULONG encrypted2_len; CK_BYTE encrypted3[16]; CK_ULONG encrypted3_len; CK_BYTE clear[sizeof(data1) + 16]; CK_ULONG clear_len; CK_BYTE digest1[32]; CK_ULONG digest1_len; CK_BYTE digest2[32]; CK_ULONG digest2_len; testcase_begin("C_DigestEncryptUpdate with %s/%s", mech_to_str(digest_mech.mechanism), mech_to_str(endecrypt_mech.mechanism)); testcase_rw_session(); testcase_user_login(); if (!mech_supported(SLOT_ID, digest_mech.mechanism)) { testcase_skip("Slot %u doesn't support %s (0x%x)", (unsigned int)SLOT_ID, mech_to_str(digest_mech.mechanism), (unsigned int)digest_mech.mechanism); goto testcase_cleanup; } if (!mech_supported(SLOT_ID, endecrypt_mech.mechanism)) { testcase_skip("Slot %u doesn't support %s (0x%x)", (unsigned int)SLOT_ID, mech_to_str(endecrypt_mech.mechanism), (unsigned int)endecrypt_mech.mechanism); goto testcase_cleanup; } if (!mech_supported(SLOT_ID, aeskeygen_mech.mechanism)) { testcase_skip("Slot %u doesn't support %s (0x%x)", (unsigned int)SLOT_ID, mech_to_str(aeskeygen_mech.mechanism), (unsigned int)aeskeygen_mech.mechanism); goto testcase_cleanup; } /* generate an AES key */ rc = generate_AESKey(session, 256 / 8, CK_TRUE, &aeskeygen_mech, &aes_key); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("generate key with mech %s (%u) in slot %lu " "is not allowed by policy", mech_to_str(aeskeygen_mech.mechanism), (unsigned int)aeskeygen_mech.mechanism, SLOT_ID); rc = CKR_OK; goto testcase_cleanup; } testcase_error("generate key with mech %s (%u) in slot %lu failed, rc=%s", mech_to_str(aeskeygen_mech.mechanism), (unsigned int)aeskeygen_mech.mechanism, SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } testcase_new_assertion(); /* Initialize operations */ rc = funcs->C_EncryptInit(session, &endecrypt_mech, aes_key); if (rc != CKR_OK) { testcase_error("C_EncryptInit with mech %s (%u) in slot %lu failed, rc=%s", mech_to_str(endecrypt_mech.mechanism), (unsigned int)endecrypt_mech.mechanism, SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } rc = funcs->C_DigestInit(session, &digest_mech); if (rc != CKR_OK) { testcase_error("C_DigestInit with mech %s (%u) in slot %lu failed, rc=%s", mech_to_str(digest_mech.mechanism), (unsigned int)digest_mech.mechanism, SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } /* First chunk */ encrypted1_len = 0; rc = funcs->C_DigestEncryptUpdate(session, data1, sizeof(data1), NULL, &encrypted1_len); if (rc != CKR_OK) { testcase_error("C_DigestEncryptUpdate (1) in slot %lu failed, rc=%s", SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } if (encrypted1_len < sizeof(data1)) { testcase_error("Wrong encrypted length from C_DigestEncryptUpdate (1): %lu", encrypted1_len); rc = CKR_FUNCTION_FAILED; goto testcase_cleanup; } encrypted1_len = sizeof(encrypted1); rc = funcs->C_DigestEncryptUpdate(session, data1, sizeof(data1), encrypted1, &encrypted1_len); if (rc != CKR_OK) { testcase_error("C_DigestEncryptUpdate (2) in slot %lu failed, rc=%s", SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } if (encrypted1_len != sizeof(data1)) { testcase_error("Wrong encrypted length from C_DigestEncryptUpdate (2): %lu", encrypted1_len); rc = CKR_FUNCTION_FAILED; goto testcase_cleanup; } /* Second chunk */ encrypted2_len = 0; rc = funcs->C_DigestEncryptUpdate(session, data2, sizeof(data2), NULL, &encrypted2_len); if (rc != CKR_OK) { testcase_error("C_DigestEncryptUpdate (3) in slot %lu failed, rc=%s", SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } if (encrypted2_len < sizeof(data2)) { testcase_error("Wrong encrypted length from C_DigestEncryptUpdate (3): %lu", encrypted2_len); rc = CKR_FUNCTION_FAILED; goto testcase_cleanup; } encrypted2_len = sizeof(encrypted2); rc = funcs->C_DigestEncryptUpdate(session, data2, sizeof(data2), encrypted2, &encrypted2_len); if (rc != CKR_OK) { testcase_error("C_DigestEncryptUpdate (4) in slot %lu failed, rc=%s", SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } if (encrypted2_len != sizeof(data2)) { testcase_error("Wrong encrypted length from C_DigestEncryptUpdate (4): %lu", encrypted2_len); rc = CKR_FUNCTION_FAILED; goto testcase_cleanup; } /* Finalize operations */ encrypted3_len = sizeof(encrypted3); rc = funcs->C_EncryptFinal(session, encrypted3, &encrypted3_len); if (rc != CKR_OK) { testcase_error("C_EncryptFinal in slot %lu failed, rc=%s", SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } if (encrypted3_len != 0) { testcase_error("Wrong encrypted length from C_EncryptFinal: %lu", encrypted3_len); rc = CKR_FUNCTION_FAILED; goto testcase_cleanup; } digest1_len = sizeof(digest1); rc = funcs->C_DigestFinal(session, digest1, &digest1_len); if (rc != CKR_OK) { testcase_error("C_DigestFinal in slot %lu failed, rc=%s", SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } testcase_pass("C_DigestEncryptUpdate with %s/%s", mech_to_str(digest_mech.mechanism), mech_to_str(endecrypt_mech.mechanism)); testcase_begin("C_DecryptDigestUpdate with %s/%s", mech_to_str(endecrypt_mech.mechanism), mech_to_str(digest_mech.mechanism)); testcase_new_assertion(); /* Initialize operations */ rc = funcs->C_DecryptInit(session, &endecrypt_mech, aes_key); if (rc != CKR_OK) { testcase_error("C_DecryptInit with mech %s (%u) in slot %lu failed, rc=%s", mech_to_str(endecrypt_mech.mechanism), (unsigned int)endecrypt_mech.mechanism, SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } rc = funcs->C_DigestInit(session, &digest_mech); if (rc != CKR_OK) { testcase_error("C_DigestInit with mech %s (%u) in slot %lu failed, rc=%s", mech_to_str(digest_mech.mechanism), (unsigned int)digest_mech.mechanism, SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } /* First chunk */ clear_len = 0; rc = funcs->C_DecryptDigestUpdate(session, encrypted1, encrypted1_len, NULL, &clear_len); if (rc != CKR_OK) { testcase_error("C_DecryptDigestUpdate (1) in slot %lu failed, rc=%s", SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } if (clear_len < sizeof(data1)) { testcase_error("Wrong encrypted length from C_DecryptDigestUpdate (1): %lu", clear_len); rc = CKR_FUNCTION_FAILED; goto testcase_cleanup; } clear_len = sizeof(clear); rc = funcs->C_DecryptDigestUpdate(session, encrypted1, encrypted1_len, clear, &clear_len); if (rc != CKR_OK) { testcase_error("C_DecryptDigestUpdate (2) in slot %lu failed, rc=%s", SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } if (clear_len != sizeof(data1)) { testcase_error("Wrong encrypted length from C_DecryptDigestUpdate (2): %lu", encrypted1_len); rc = CKR_FUNCTION_FAILED; goto testcase_cleanup; } if (memcmp(clear, data1, clear_len) != 0) { testcase_error("Wrong decrypted data from C_DecryptDigestUpdate (2)"); rc = CKR_FUNCTION_FAILED; goto testcase_cleanup; } /* Second chunk */ clear_len = 0; rc = funcs->C_DecryptDigestUpdate(session, encrypted2, encrypted2_len, NULL, &clear_len); if (rc != CKR_OK) { testcase_error("C_DecryptDigestUpdate (3) in slot %lu failed, rc=%s", SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } if (clear_len < sizeof(data2)) { testcase_error("Wrong encrypted length from C_DecryptDigestUpdate (3): %lu", clear_len); rc = CKR_FUNCTION_FAILED; goto testcase_cleanup; } clear_len = sizeof(clear); rc = funcs->C_DecryptDigestUpdate(session, encrypted2, encrypted2_len, clear, &clear_len); if (rc != CKR_OK) { testcase_error("C_DecryptDigestUpdate (4) in slot %lu failed, rc=%s", SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } if (clear_len != sizeof(data2)) { testcase_error("Wrong encrypted length from C_DecryptDigestUpdate (4): %lu", encrypted1_len); rc = CKR_FUNCTION_FAILED; goto testcase_cleanup; } if (memcmp(clear, data2, clear_len) != 0) { testcase_error("Wrong decrypted data from C_DecryptDigestUpdate (4)"); rc = CKR_FUNCTION_FAILED; goto testcase_cleanup; } /* Finalize operations */ clear_len = sizeof(clear); rc = funcs->C_DecryptFinal(session, clear, &clear_len); if (rc != CKR_OK) { testcase_error("C_DecryptFinal in slot %lu failed, rc=%s", SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } if (clear_len != 0) { testcase_error("Wrong encrypted length from C_DecryptFinal: %lu", clear_len); rc = CKR_FUNCTION_FAILED; goto testcase_cleanup; } digest2_len = sizeof(digest2); rc = funcs->C_DigestFinal(session, digest2, &digest2_len); if (rc != CKR_OK) { testcase_error("C_DigestFinal in slot %lu failed, rc=%s", SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } if (digest1_len != digest2_len) { testcase_error("Wrong encrypted length from C_DigestFinal: %lu", digest2_len); rc = CKR_FUNCTION_FAILED; goto testcase_cleanup; } if (memcmp(digest1, digest2, digest1_len) != 0) { testcase_error("Wrong digest from C_DigestFinal"); rc = CKR_FUNCTION_FAILED; goto testcase_cleanup; } testcase_pass("C_DecryptDigestUpdate with %s/%s", mech_to_str(endecrypt_mech.mechanism), mech_to_str(digest_mech.mechanism)); testcase_cleanup: if (aes_key != CK_INVALID_HANDLE) { loc_rc = funcs->C_DestroyObject(session, aes_key); if (loc_rc != CKR_OK) testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(loc_rc)); } 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_sign_encrypt_decrypt_verify(void) { CK_SESSION_HANDLE session; CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; CK_ULONG user_pin_len; CK_RV rc = CKR_OK, loc_rc; CK_FLAGS flags; CK_OBJECT_HANDLE aes_key = CK_INVALID_HANDLE; CK_OBJECT_HANDLE mac_key = CK_INVALID_HANDLE; CK_BYTE encrypted1[sizeof(data1) + 16]; CK_ULONG encrypted1_len; CK_BYTE encrypted2[sizeof(data2) + 16]; CK_ULONG encrypted2_len; CK_BYTE encrypted3[16]; CK_ULONG encrypted3_len; CK_BYTE clear[sizeof(data1) + 16]; CK_ULONG clear_len; CK_BYTE signature[32]; CK_ULONG signature_len; testcase_begin("C_SignEncryptUpdate with %s/%s", mech_to_str(signver_mech.mechanism), mech_to_str(endecrypt_mech.mechanism)); testcase_rw_session(); testcase_user_login(); if (!mech_supported(SLOT_ID, signver_mech.mechanism)) { testcase_skip("Slot %u doesn't support %s (0x%x)", (unsigned int)SLOT_ID, mech_to_str(signver_mech.mechanism), (unsigned int)signver_mech.mechanism); goto testcase_cleanup; } if (!mech_supported(SLOT_ID, endecrypt_mech.mechanism)) { testcase_skip("Slot %u doesn't support %s (0x%x)", (unsigned int)SLOT_ID, mech_to_str(endecrypt_mech.mechanism), (unsigned int)endecrypt_mech.mechanism); goto testcase_cleanup; } if (!mech_supported(SLOT_ID, aeskeygen_mech.mechanism)) { testcase_skip("Slot %u doesn't support %s (0x%x)", (unsigned int)SLOT_ID, mech_to_str(aeskeygen_mech.mechanism), (unsigned int)aeskeygen_mech.mechanism); goto testcase_cleanup; } if (!mech_supported(SLOT_ID, mackeygen_mech.mechanism)) { testcase_skip("Slot %u doesn't support %s (0x%x)", (unsigned int)SLOT_ID, mech_to_str(mackeygen_mech.mechanism), (unsigned int)mackeygen_mech.mechanism); goto testcase_cleanup; } /* generate an AES key */ rc = generate_AESKey(session, 256 / 8, CK_TRUE, &aeskeygen_mech, &aes_key); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("generate key with mech %s (%u) in slot %lu " "is not allowed by policy", mech_to_str(aeskeygen_mech.mechanism), (unsigned int)aeskeygen_mech.mechanism, SLOT_ID); rc = CKR_OK; goto testcase_cleanup; } testcase_error("generate key with mech %s (%u) in slot %lu failed, rc=%s", mech_to_str(aeskeygen_mech.mechanism), (unsigned int)aeskeygen_mech.mechanism, SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } /* generate a MAC key */ rc = generate_SecretKey(session, 256, &mackeygen_mech, &mac_key); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("generate key with mech %s (%u) in slot %lu " "is not allowed by policy", mech_to_str(mackeygen_mech.mechanism), (unsigned int)mackeygen_mech.mechanism, SLOT_ID); rc = CKR_OK; goto testcase_cleanup; } testcase_error("generate key with mech %s (%u) in slot %lu failed, rc=%s", mech_to_str(mackeygen_mech.mechanism), (unsigned int)mackeygen_mech.mechanism, SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } testcase_new_assertion(); /* Initialize operations */ rc = funcs->C_EncryptInit(session, &endecrypt_mech, aes_key); if (rc != CKR_OK) { testcase_error("C_EncryptInit with mech %s (%u) in slot %lu failed, rc=%s", mech_to_str(endecrypt_mech.mechanism), (unsigned int)endecrypt_mech.mechanism, SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } rc = funcs->C_SignInit(session, &signver_mech, mac_key); if (rc != CKR_OK) { testcase_error("C_SignInit with mech %s (%u) in slot %lu failed, rc=%s", mech_to_str(signver_mech.mechanism), (unsigned int)signver_mech.mechanism, SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } /* First chunk */ encrypted1_len = 0; rc = funcs->C_SignEncryptUpdate(session, data1, sizeof(data1), NULL, &encrypted1_len); if (rc != CKR_OK) { testcase_error("C_SignEncryptUpdate (1) in slot %lu failed, rc=%s", SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } if (encrypted1_len < sizeof(data1)) { testcase_error("Wrong encrypted length from C_SignEncryptUpdate (1): %lu", encrypted1_len); rc = CKR_FUNCTION_FAILED; goto testcase_cleanup; } encrypted1_len = sizeof(encrypted1); rc = funcs->C_SignEncryptUpdate(session, data1, sizeof(data1), encrypted1, &encrypted1_len); if (rc != CKR_OK) { testcase_error("C_SignEncryptUpdate (2) in slot %lu failed, rc=%s", SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } if (encrypted1_len != sizeof(data1)) { testcase_error("Wrong encrypted length from C_SignEncryptUpdate (2): %lu", encrypted1_len); rc = CKR_FUNCTION_FAILED; goto testcase_cleanup; } /* Second chunk */ encrypted2_len = 0; rc = funcs->C_SignEncryptUpdate(session, data2, sizeof(data2), NULL, &encrypted2_len); if (rc != CKR_OK) { testcase_error("C_SignEncryptUpdate (3) in slot %lu failed, rc=%s", SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } if (encrypted2_len < sizeof(data2)) { testcase_error("Wrong encrypted length from C_SignEncryptUpdate (3): %lu", encrypted2_len); rc = CKR_FUNCTION_FAILED; goto testcase_cleanup; } encrypted2_len = sizeof(encrypted2); rc = funcs->C_SignEncryptUpdate(session, data2, sizeof(data2), encrypted2, &encrypted2_len); if (rc != CKR_OK) { testcase_error("C_SignEncryptUpdate (4) in slot %lu failed, rc=%s", SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } if (encrypted2_len != sizeof(data2)) { testcase_error("Wrong encrypted length from C_SignEncryptUpdate (4): %lu", encrypted2_len); rc = CKR_FUNCTION_FAILED; goto testcase_cleanup; } /* Finalize operations */ encrypted3_len = sizeof(encrypted3); rc = funcs->C_EncryptFinal(session, encrypted3, &encrypted3_len); if (rc != CKR_OK) { testcase_error("C_EncryptFinal in slot %lu failed, rc=%s", SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } if (encrypted3_len != 0) { testcase_error("Wrong encrypted length from C_EncryptFinal: %lu", encrypted3_len); rc = CKR_FUNCTION_FAILED; goto testcase_cleanup; } signature_len = sizeof(signature); rc = funcs->C_SignFinal(session, signature, &signature_len); if (rc != CKR_OK) { testcase_error("C_SignFinal in slot %lu failed, rc=%s", SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } testcase_pass("C_SignEncryptUpdate with %s/%s", mech_to_str(signver_mech.mechanism), mech_to_str(endecrypt_mech.mechanism)); testcase_begin("C_DecryptVerifyUpdate with %s/%s", mech_to_str(endecrypt_mech.mechanism), mech_to_str(signver_mech.mechanism)); testcase_new_assertion(); /* Initialize operations */ rc = funcs->C_DecryptInit(session, &endecrypt_mech, aes_key); if (rc != CKR_OK) { testcase_error("C_DecryptInit with mech %s (%u) in slot %lu failed, rc=%s", mech_to_str(endecrypt_mech.mechanism), (unsigned int)endecrypt_mech.mechanism, SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } rc = funcs->C_VerifyInit(session, &signver_mech, mac_key); if (rc != CKR_OK) { testcase_error("C_VerifyInit with mech %s (%u) in slot %lu failed, rc=%s", mech_to_str(digest_mech.mechanism), (unsigned int)signver_mech.mechanism, SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } /* First chunk */ clear_len = 0; rc = funcs->C_DecryptVerifyUpdate(session, encrypted1, encrypted1_len, NULL, &clear_len); if (rc != CKR_OK) { testcase_error("C_DecryptVerifyUpdate (1) in slot %lu failed, rc=%s", SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } if (clear_len < sizeof(data1)) { testcase_error("Wrong encrypted length from C_DecryptVerifyUpdate (1): %lu", clear_len); rc = CKR_FUNCTION_FAILED; goto testcase_cleanup; } clear_len = sizeof(clear); rc = funcs->C_DecryptVerifyUpdate(session, encrypted1, encrypted1_len, clear, &clear_len); if (rc != CKR_OK) { testcase_error("C_DecryptVerifyUpdate (2) in slot %lu failed, rc=%s", SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } if (clear_len != sizeof(data1)) { testcase_error("Wrong encrypted length from C_DecryptVerifyUpdate (2): %lu", encrypted1_len); rc = CKR_FUNCTION_FAILED; goto testcase_cleanup; } if (memcmp(clear, data1, clear_len) != 0) { testcase_error("Wrong decrypted data from C_DecryptVerifyUpdate (2)"); rc = CKR_FUNCTION_FAILED; goto testcase_cleanup; } /* Second chunk */ clear_len = 0; rc = funcs->C_DecryptVerifyUpdate(session, encrypted2, encrypted2_len, NULL, &clear_len); if (rc != CKR_OK) { testcase_error("C_DecryptVerifyUpdate (3) in slot %lu failed, rc=%s", SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } if (clear_len < sizeof(data2)) { testcase_error("Wrong encrypted length from C_DecryptVerifyUpdate (3): %lu", clear_len); rc = CKR_FUNCTION_FAILED; goto testcase_cleanup; } clear_len = sizeof(clear); rc = funcs->C_DecryptVerifyUpdate(session, encrypted2, encrypted2_len, clear, &clear_len); if (rc != CKR_OK) { testcase_error("C_DecryptVerifyUpdate (4) in slot %lu failed, rc=%s", SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } if (clear_len != sizeof(data2)) { testcase_error("Wrong encrypted length from C_DecryptVerifyUpdate (4): %lu", encrypted1_len); rc = CKR_FUNCTION_FAILED; goto testcase_cleanup; } if (memcmp(clear, data2, clear_len) != 0) { testcase_error("Wrong decrypted data from C_DecryptVerifyUpdate (4)"); rc = CKR_FUNCTION_FAILED; goto testcase_cleanup; } /* Finalize operations */ clear_len = sizeof(clear); rc = funcs->C_DecryptFinal(session, clear, &clear_len); if (rc != CKR_OK) { testcase_error("C_DecryptFinal in slot %lu failed, rc=%s", SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } if (clear_len != 0) { testcase_error("Wrong encrypted length from C_DecryptFinal: %lu", clear_len); rc = CKR_FUNCTION_FAILED; goto testcase_cleanup; } rc = funcs->C_VerifyFinal(session, signature, signature_len); if (rc != CKR_OK) { testcase_error("C_VerifyFinal in slot %lu failed, rc=%s", SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } testcase_pass("C_DecryptVerifyUpdate with %s/%s", mech_to_str(endecrypt_mech.mechanism), mech_to_str(signver_mech.mechanism)); testcase_cleanup: if (aes_key != CK_INVALID_HANDLE) { loc_rc = funcs->C_DestroyObject(session, aes_key); if (loc_rc != CKR_OK) testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(loc_rc)); } if (mac_key != CK_INVALID_HANDLE) { loc_rc = funcs->C_DestroyObject(session, mac_key); if (loc_rc != CKR_OK) testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(loc_rc)); } 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_save_restore_dual_state(void) { CK_SESSION_HANDLE session; CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; CK_ULONG user_pin_len; CK_RV rc = CKR_OK, loc_rc; CK_FLAGS flags; CK_OBJECT_HANDLE aes_key = CK_INVALID_HANDLE; CK_BYTE encrypted1[sizeof(data1) + 16]; CK_ULONG encrypted1_len; CK_BYTE encrypted2[sizeof(data2) + 16]; CK_ULONG encrypted2_len; CK_BYTE encrypted2a[sizeof(data2) + 16]; CK_ULONG encrypted2a_len; CK_BYTE encrypted3[16]; CK_ULONG encrypted3_len; CK_BYTE digest1[32]; CK_ULONG digest1_len; CK_BYTE digest2[32]; CK_ULONG digest2_len; CK_BYTE *state = NULL; CK_ULONG state_len; testcase_begin("Save/Restore state with 2 active operations"); testcase_rw_session(); testcase_user_login(); if (!mech_supported(SLOT_ID, digest_mech.mechanism)) { testcase_skip("Slot %u doesn't support %s (0x%x)", (unsigned int)SLOT_ID, mech_to_str(digest_mech.mechanism), (unsigned int)digest_mech.mechanism); goto testcase_cleanup; } if (!mech_supported(SLOT_ID, endecrypt_mech.mechanism)) { testcase_skip("Slot %u doesn't support %s (0x%x)", (unsigned int)SLOT_ID, mech_to_str(endecrypt_mech.mechanism), (unsigned int)endecrypt_mech.mechanism); goto testcase_cleanup; } if (!mech_supported(SLOT_ID, aeskeygen_mech.mechanism)) { testcase_skip("Slot %u doesn't support %s (0x%x)", (unsigned int)SLOT_ID, mech_to_str(aeskeygen_mech.mechanism), (unsigned int)aeskeygen_mech.mechanism); goto testcase_cleanup; } /* generate an AES key */ rc = generate_AESKey(session, 256 / 8, CK_TRUE, &aeskeygen_mech, &aes_key); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("generate key with mech %s (%u) in slot %lu " "is not allowed by policy", mech_to_str(aeskeygen_mech.mechanism), (unsigned int)aeskeygen_mech.mechanism, SLOT_ID); rc = CKR_OK; goto testcase_cleanup; } testcase_error("generate key with mech %s (%u) in slot %lu failed, rc=%s", mech_to_str(aeskeygen_mech.mechanism), (unsigned int)aeskeygen_mech.mechanism, SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } /* Initialize operations */ rc = funcs->C_EncryptInit(session, &endecrypt_mech, aes_key); if (rc != CKR_OK) { testcase_error("C_EncryptInit with mech %s (%u) in slot %lu failed, rc=%s", mech_to_str(endecrypt_mech.mechanism), (unsigned int)endecrypt_mech.mechanism, SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } rc = funcs->C_DigestInit(session, &digest_mech); if (rc != CKR_OK) { testcase_error("C_DigestInit with mech %s (%u) in slot %lu failed, rc=%s", mech_to_str(digest_mech.mechanism), (unsigned int)digest_mech.mechanism, SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } /* First chunk */ encrypted1_len = sizeof(encrypted1); rc = funcs->C_DigestEncryptUpdate(session, data1, sizeof(data1), encrypted1, &encrypted1_len); if (rc != CKR_OK) { testcase_error("C_DigestEncryptUpdate (2) in slot %lu failed, rc=%s", SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } /* Save state of both operations */ rc = funcs->C_GetOperationState(session, NULL, &state_len); if (rc != CKR_OK) { if (rc == CKR_STATE_UNSAVEABLE) { testcase_skip("Operation state is not savable"); goto testcase_cleanup; } testcase_error("C_GetOperationState (1) in slot %lu failed, rc=%s", SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } state = calloc(1, state_len); if (state == NULL) { testcase_fail("malloc for state buffer of size %lu failed", state_len); rc = CKR_HOST_MEMORY; goto testcase_cleanup; } rc = funcs->C_GetOperationState(session, state, &state_len); if (rc != CKR_OK) { if (rc == CKR_STATE_UNSAVEABLE) { testcase_skip("Operation state is not savable"); goto testcase_cleanup; } testcase_error("C_GetOperationState (2) in slot %lu failed, rc=%s", SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } /* Second chunk */ encrypted2_len = sizeof(encrypted2); rc = funcs->C_DigestEncryptUpdate(session, data2, sizeof(data2), encrypted2, &encrypted2_len); if (rc != CKR_OK) { testcase_error("C_DigestEncryptUpdate (4) in slot %lu failed, rc=%s", SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } /* Finalize operations */ encrypted3_len = sizeof(encrypted3); rc = funcs->C_EncryptFinal(session, encrypted3, &encrypted3_len); if (rc != CKR_OK) { testcase_error("C_EncryptFinal in slot %lu failed, rc=%s", SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } digest1_len = sizeof(digest1); rc = funcs->C_DigestFinal(session, digest1, &digest1_len); if (rc != CKR_OK) { testcase_error("C_DigestFinal in slot %lu failed, rc=%s", SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } testcase_new_assertion(); /* restore state from after first chunk */ rc = funcs->C_SetOperationState(session, state, state_len, aes_key, CK_INVALID_HANDLE); if (rc != CKR_OK) { testcase_error("C_SetOperationState in slot %lu failed, rc=%s", SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } /* Second chunk again */ encrypted2a_len = sizeof(encrypted2a); rc = funcs->C_DigestEncryptUpdate(session, data2, sizeof(data2), encrypted2a, &encrypted2a_len); if (rc != CKR_OK) { testcase_error("C_DigestEncryptUpdate (5) in slot %lu failed, rc=%s", SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } if (encrypted2a_len != encrypted2_len) { testcase_error("Wrong encrypted length from C_DigestEncryptUpdate (5): %lu", encrypted2a_len); rc = CKR_FUNCTION_FAILED; goto testcase_cleanup; } if (memcmp(encrypted2, encrypted2a, encrypted2_len) != 0) { testcase_error("Wrong encrypted data from C_DigestEncryptUpdate (5)"); rc = CKR_FUNCTION_FAILED; goto testcase_cleanup; } /* Finalize operations again */ encrypted3_len = sizeof(encrypted3); rc = funcs->C_EncryptFinal(session, encrypted3, &encrypted3_len); if (rc != CKR_OK) { testcase_error("C_EncryptFinal in slot %lu failed, rc=%s", SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } digest2_len = sizeof(digest2); rc = funcs->C_DigestFinal(session, digest2, &digest2_len); if (rc != CKR_OK) { testcase_error("C_DigestFinal (2) in slot %lu failed, rc=%s", SLOT_ID, p11_get_ckr(rc)); goto testcase_cleanup; } if (digest1_len != digest2_len) { testcase_error("Wrong encrypted length from C_DigestFinal (2): %lu", digest2_len); rc = CKR_FUNCTION_FAILED; goto testcase_cleanup; } if (memcmp(digest1, digest2, digest1_len) != 0) { testcase_error("Wrong digest from C_DigestFinal (2)"); rc = CKR_FUNCTION_FAILED; goto testcase_cleanup; } testcase_pass("Save/Restore state with 2 active operations"); testcase_cleanup: if (aes_key != CK_INVALID_HANDLE) { loc_rc = funcs->C_DestroyObject(session, aes_key); if (loc_rc != CKR_OK) testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(loc_rc)); } testcase_user_logout(); rc = funcs->C_CloseAllSessions(SLOT_ID); if (rc != CKR_OK) { testcase_error("C_CloseAllSessions rc=%s", p11_get_ckr(rc)); } if (state != NULL) free(state); return rc; } CK_RV do_dual_functions_tests(void) { CK_RV rc = CKR_OK; rc |= do_digest_encrypt_decrypt_digest(); rc |= do_sign_encrypt_decrypt_verify(); rc |= do_save_restore_dual_state(); return rc; } int main(int argc, char **argv) { int rc; CK_C_INITIALIZE_ARGS cinit_args; CK_RV rv = 0; CK_ULONG i; 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); testcase_setup(); for (i = 0; i < sizeof(data1); i++) data1[i] = i; for (i = 0; i < sizeof(data1); i++) data2[i] = 255 - i; rv = do_dual_functions_tests(); if (rv != CKR_OK) goto finalize; rv = funcs->C_Finalize(NULL); if (rv != CKR_OK) { testcase_fail("C_Finalize rc = %s", p11_get_ckr(rv)); goto out; } rv = 0; goto out; finalize: rv = funcs->C_Finalize(NULL); if (rv != CKR_OK) { testcase_fail("C_Finalize rc = %s", p11_get_ckr(rv)); rv = 1; } out: testcase_print_result(); return testcase_return(rv); } opencryptoki-opencryptoki-451d99c/testcases/misc_tests/ec-key-prime256v1.pem000066400000000000000000000006251520105705100272000ustar00rootroot00000000000000-----BEGIN EC PRIVATE KEY----- MHcCAQEEIGkupN5Fb2L3dWAdAgEJl7zEEqT/jmPv0p5xfm9fxH8JoAoGCCqGSM49 AwEHoUQDQgAEJrNOXH2xRTdtd/jPxcdH4as5iXZR6zBVvu+8TBHz7198NgAj5djj BfQ/Gmrt6Z5UhXid6YKt7pTJbLhJG9lljA== -----END EC PRIVATE KEY----- -----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEJrNOXH2xRTdtd/jPxcdH4as5iXZR 6zBVvu+8TBHz7198NgAj5djjBfQ/Gmrt6Z5UhXid6YKt7pTJbLhJG9lljA== -----END PUBLIC KEY----- opencryptoki-opencryptoki-451d99c/testcases/misc_tests/ec-key-secp521r1.pem000066400000000000000000000011711520105705100270020ustar00rootroot00000000000000-----BEGIN EC PRIVATE KEY----- MIHcAgEBBEIB+l3KAQzAUjcNFVH0Mhy4WNHsicaCIQiOmPsboRcydXgDRtanRV9a Jj/l+5R2v6P75IUBAi6zsqsxstjmhv1queGgBwYFK4EEACOhgYkDgYYABACnAK+0 bMka2hMHgKN0A1PmqXSWgC7EPRs88Be2ricdXBTiF3RxKJv/JMn9ZTZ63eeAtbPd 5h2XrLjTkOBUqEW9ZQHQRszuHE4okXDCBlyT3lGyI1RbOGhJdRznyy9khhnkhaTr g6oRGRXtPJnvTAt0C99cKeyXTElzV0c2vqLETfKbUg== -----END EC PRIVATE KEY----- -----BEGIN PUBLIC KEY----- MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQApwCvtGzJGtoTB4CjdANT5ql0loAu xD0bPPAXtq4nHVwU4hd0cSib/yTJ/WU2et3ngLWz3eYdl6y405DgVKhFvWUB0EbM 7hxOKJFwwgZck95RsiNUWzhoSXUc58svZIYZ5IWk64OqERkV7TyZ70wLdAvfXCns l0xJc1dHNr6ixE3ym1I= -----END PUBLIC KEY----- opencryptoki-opencryptoki-451d99c/testcases/misc_tests/ed25519-private-key.pem000066400000000000000000000001671520105705100274420ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MC4CAQAwBQYDK2VwBCIEIPgmCXXeMT/iGHmwBjGGhbRFy/5GtKdxoHAgifNjWLAJ -----END PRIVATE KEY----- opencryptoki-opencryptoki-451d99c/testcases/misc_tests/ed25519-public-key.pem000066400000000000000000000001611520105705100272400ustar00rootroot00000000000000-----BEGIN PUBLIC KEY----- MCowBQYDK2VwAyEA5BaYy5nhJv07L6G1XhjmxObE+igLw+mTg0p+r6haamY= -----END PUBLIC KEY----- opencryptoki-opencryptoki-451d99c/testcases/misc_tests/ed448-private-key.pem000066400000000000000000000002341520105705100272670ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MEcCAQAwBQYDK2VxBDsEOTxst3Y2UYqXeElLCYKeXMISgfLC4KE8ojYbaBgzAsU9 31T8aQ4ruptlw8CftwrX0NIog6ytb9XDtA== -----END PRIVATE KEY----- opencryptoki-opencryptoki-451d99c/testcases/misc_tests/ed448-public-key.pem000066400000000000000000000002221520105705100270700ustar00rootroot00000000000000-----BEGIN PUBLIC KEY----- MEMwBQYDK2VxAzoAV4oO9lm2eDmEoUuGqwMyxKrWmUzRapmvdrCa2P1MlGZmuOQB yoRULsOJdDWRYXqVx3m6bKyEYM2A -----END PUBLIC KEY----- opencryptoki-opencryptoki-451d99c/testcases/misc_tests/events.c000066400000000000000000000141351520105705100251530ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021 * * 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 "event_client.h" #include "regress.h" #include "defs.h" const char payload[20 + 1] = "12345678901234567890"; static inline void init_event_destination(struct event_destination *dest, unsigned int token_type, const char *label, pid_t process_id) { size_t len; dest->token_type = token_type; dest->process_id = process_id; memset(dest->token_label, ' ', sizeof(dest->token_label)); if (label != NULL) { len = strlen(label); memcpy(dest->token_label, label, len > sizeof(dest->token_label) ? sizeof(dest->token_label) : len); } } int main(int argc, char **argv) { CK_C_INITIALIZE_ARGS cinit_args; int rc, fd = -1, ret = 1; struct event_destination dest; struct event_reply reply; UNUSED(argc); UNUSED(argv); rc = do_GetFunctionList(); if (!rc) { testcase_error("do_getFunctionList(), rc=%s", p11_get_ckr(rc)); return rc; } /* * Initialize Opencryptoki in this process, so that at least one * process is receiving the events. */ memset(&cinit_args, 0x0, sizeof(cinit_args)); cinit_args.flags = CKF_OS_LOCKING_OK; funcs->C_Initialize(&cinit_args); testcase_setup(); testcase_begin("Starting event tests"); // Test fork before C_Initialize testcase_new_assertion(); rc = send_event(-1, 0x12345, EVENT_FLAGS_NONE, 0, NULL, NULL, NULL); if (rc != 0) { testcase_fail("send_event (simple, one-shot) rc = %d (%s)", rc, strerror(-rc)); goto out; } testcase_pass("send_event (simple, one-shot)"); testcase_new_assertion(); rc = send_event(-1, 0x12345, EVENT_FLAGS_NONE, sizeof(payload), payload, NULL, NULL); if (rc != 0) { testcase_fail("send_event (payload, one-shot) rc = %d (%s)", rc, strerror(-rc)); goto out; } testcase_pass("send_event (payload, one-shot)"); testcase_new_assertion(); init_event_destination(&dest, EVENT_TOK_TYPE_CCA, NULL, 0); rc = send_event(-1, 0x12345, EVENT_FLAGS_NONE, 0, NULL, &dest, NULL); if (rc != 0) { testcase_fail("send_event (token-type, one-shot) rc = %d (%s)", rc, strerror(-rc)); goto out; } testcase_pass("send_event (token-type, one-shot)"); testcase_new_assertion(); init_event_destination(&dest, EVENT_TOK_TYPE_ALL, "cca", 0); rc = send_event(-1, 0x12345, EVENT_FLAGS_NONE, 0, NULL, &dest, NULL); if (rc != 0) { testcase_fail("send_event (token-label, one-shot) rc = %d (%s)", rc, strerror(-rc)); goto out; } testcase_pass("send_event (token-label, one-shot)"); testcase_new_assertion(); init_event_destination(&dest, EVENT_TOK_TYPE_ALL, NULL, 12345); rc = send_event(-1, 0x12345, EVENT_FLAGS_NONE, 0, NULL, &dest, NULL); if (rc != 0) { testcase_fail("send_event (pid, one-shot) rc = %d (%s)", rc, strerror(-rc)); goto out; } testcase_pass("send_event (pid, one-shot)"); testcase_new_assertion(); memset(&reply, 0, sizeof(reply)); rc = send_event(-1, 0x12345, EVENT_FLAGS_REPLY_REQ, 0, NULL, NULL, &reply); if (rc != 0) { testcase_fail("send_event (reply, one-shot) rc = %d (%s)", rc, strerror(-rc)); goto out; } printf("Reply: positive_replies: %lu\n", reply.positive_replies); printf(" negative_replies: %lu\n", reply.negative_replies); printf(" nothandled_replies: %lu\n", reply.nothandled_replies); if (reply.positive_replies + reply.negative_replies + reply.nothandled_replies == 0) { testcase_fail("send_event (reply, one-shot) replies all zero"); goto out; } testcase_pass("send_event (reply, one-shot)"); testcase_new_assertion(); fd = init_event_client(); if (fd < 0) { testcase_fail("init_event_client rc = %d (%s)", fd, strerror(-fd)); goto out; } testcase_pass("init_event_client()"); testcase_new_assertion(); rc = send_event(fd, 0x12345, EVENT_FLAGS_NONE, 0, NULL, NULL, NULL); if (rc != 0) { testcase_fail("send_event (simple) rc = %d (%s)", rc, strerror(-rc)); goto out; } testcase_pass("send_event (simple)"); testcase_new_assertion(); rc = send_event(fd, 0x12345, EVENT_FLAGS_NONE, sizeof(payload), payload, NULL, NULL); if (rc != 0) { testcase_fail("send_event (payload) rc = %d (%s)", rc, strerror(-rc)); goto out; } testcase_pass("send_event (payload)"); testcase_new_assertion(); memset(&reply, 0, sizeof(reply)); rc = send_event(-1, 0x12345, EVENT_FLAGS_REPLY_REQ, 0, NULL, NULL, &reply); if (rc != 0) { testcase_fail("send_event (reply) rc = %d (%s)", rc, strerror(-rc)); goto out; } printf("Reply: positive_replies: %lu\n", reply.positive_replies); printf(" negative_replies: %lu\n", reply.negative_replies); printf(" nothandled_replies: %lu\n", reply.nothandled_replies); if (reply.positive_replies + reply.negative_replies + reply.nothandled_replies == 0) { testcase_fail("send_event (reply) replies all zero"); goto out; } testcase_pass("send_event (reply)"); term_event_client(fd); fd = -1; ret = 0; out: if (fd >= 0) term_event_client(fd); funcs->C_Finalize(NULL); testcase_print_result(); return testcase_return(ret); } opencryptoki-opencryptoki-451d99c/testcases/misc_tests/fork.c000066400000000000000000000263711520105705100246150ustar00rootroot00000000000000/* * 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 "pkcs11types.h" #include "regress.h" #include "common.c" CK_BYTE user_pin[128]; CK_ULONG user_pin_len; CK_SLOT_ID slot_id = 0; 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) { if (rv == CKR_MECHANISM_INVALID) { testcase_skip("Mechanism CKM_RSA_PKCS_KEY_PAIR_GEN not supported"); return CKR_POLICY_VIOLATION; } 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) { if (is_rejected_by_policy(rv, sess)) { testcase_skip("Key generation is not allowed by policy"); return CKR_POLICY_VIOLATION; } 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(); 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-2048-CLIENT", 2048, &hPubKey, &hPrivKey); if (rv != CKR_OK) { if (rv == CKR_POLICY_VIOLATION) { rv = 0; goto close_session; } 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(testcase_return(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; if (i >= argc) { printf("Slot number missing\n"); return -1; } 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(); 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-2048-PARENT", 2048, &hPubKey, &hPrivKey); if (rv != CKR_OK) { if (rv == CKR_POLICY_VIOLATION) { ret = 0; goto close_session; } 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 testcase_return(ret); } opencryptoki-opencryptoki-451d99c/testcases/misc_tests/ibm-dilithium-r2-65-key.pem000066400000000000000000000237671520105705100303150ustar00rootroot00000000000000-----BEGIN IBM-DILITHIUM PRIVATE KEY----- MIIWEAIBADAPBgsrBgEEAQKCCwEGBQUABIIV+DCCFfQCAQADIQB8mTWgsHaUqgxtEOTbaxrdL9g aJcyxSAMtzXOZNnN/LQMhAD54TMt+vNz9RVQrf2r3eHQuD0R5F1CEqkiLO3Q0BniqAzEAc/1eP+ b7gPqEccCMaIL3HYYhhMNfVXbAZZfY3Po2qAssJVpZmlWwdK826Nt5I/doA4IB4QCRtHkJxRVOE LINEg2YZgsIq2zo6gmmNhSs4MBBOBMRydUUanHA2kGiSZFubRLywmrSTFWMhmFiAdgyEsMEJCZL sqKt5touNqnoKI4s081dIm1mxroCDDEZaUPkBG5xZ4kTFHRKR7BQw2GNASIqWmtqNGAmAAFopok NlRAgBIIMa3CUiVBzJtS1C0BIgjESwgIN4njQIC5KB0FYLEecuxUujSRzENboZgGzHKV1udTVhE 4IuclGxIQm6ZquazOUIHk1FpBY1LJeRscpCUegGbAWKsbhwEJwBGJD4c1uUiWGyooVUSxpsWISi cmJFSyNsQEsHLIUBVsblcxBKSfDSshRzGUZUhNeOESAjDIrVs8aaA2A09ptsdX1mFCFODBCanOa S81QNQ1bS4aQIthOVagjnRUlUDUIkTHaCM8qsxVDM8hdQVlD1JkwlEXUPGAWshRFq9HVFHuFyIo bbGZASQJpqkWDsmZ0gWiVLVEZa5CrIoRVyXGqRAAcQ6liR5MOptKixjilFy9KJToEt1SROAdClE XzokXoNsZIigiCTZcb3TasQ4XW0k1diGmb1E6MDMOlVrNUCiZsIWtdPVKeXQ2aABRNMghYCdPZO DUd0LFpKVcaQ8ky04WokAxtGit0OrkDggJBABanZVUcER6VbJAweYtnjgo2cspQJ5jlRmyiFBYz AhEsw6lto4aprqEQJ1AI2bO5wFEdE55aZuAMdnaFpgsSj5PQSAIoLB6djFsBFHRgZkPCDUIbo4p EJZJEkEEGiqkkQaaB1QU61GyTRV2MGIjUWiA9qs2gpqxURbMLE7FhGghWbW2NptrAjQ0zzpmWtI vbjciMhW4DssEsqkNgJ2DBlVTKLo0CGYOAOkMdzNGCOYGQ0cJAxihstYxqFerIGEJqawEFk7FTF arNls3EeQBkiiS2LsYQsDI4umaiatkSLHTJFVhE0UXUyYRtl1VcOdxAwoPaRoJIMxQCprFYeKNl U40lB9wUW3M5sii20bZUAoWcAJU30Wu0qTK51QtEtANqDKkhToGVNgzAcmVZxAlCOZNI0gNEm6V CpNmaGeRsGqrEERtBLfOwzKw5pRkFR6BRVlFXjFvt1mLaWnVQbBMRYzRSIyVGeCyTxSAggFkqwq Tmek6ccM6kjoZdc2HK0RPSxfbqlSq4bJBpI6vVWQBSk1FZNzQrurC0FJPhqqggCA6pyjBRsWCqq EDBOlrFsAIarh4sm2zXDjI5BlCSqXGSVgImzpxBblAclkygehNhmQELcoFFRVIaCmwxVxNqcUKN kuVgyJmSQpqRpulKlKJYM46KqoDIiSMxO24zdkQbVxIQN62mNg5D1hm7WO3ikYMaEAq3uQvTKkN cTzQYU+TilN7kwYqlCqWRTkW5bOTGTKpkAGPdGjPcgULHDUuAglgpkwOCCoEAeIGWLyPmW1xC3c 4LfZfTU2uj2Quzb0fbP7E4oDqNzgeQcWWLu/JVflTW/XyI+729c3EDPIZfJIIctobHJKB18jTrr zerfNxXq/vjeqYKRCkcZgCPIk47Gg5eF8Xz7OMRI0RJkDGyH1DtW7X/hAwTFkVr3IJeuQOaj2J+ gaO8OVT0pP/1c3G0axf1toRTLP36ZHxzJCyCwSRMwUHTlyssrYgU/mHsgPB4PODEGbZzbqbX+rI YlQH/N3gRVgPZSr//XWHigdjBrzMrY/nKE0zQC7lPazNnLpLUIe/acG5HBNOJduM5Ekp7/CGFYd O5MlwJaeoND9g8ONj5hBbbWFvxbKoeEdjPK5qRR6EUNC1qQK81yxRc9ihVrTGWvmypuIyI4wNrM wB7gxBn7kYI/TjxHxAqyzCQ/nwRJPgWT5nnX/l+oNuqIHj1kFjdn00Vc/6g5yhgCrtjqbmZ0dkV JxznWxIFpiAlaR+k+K2Kg3SUZSWBNBMcAb89Q2qCnqT/NqQGqJEqtgQTy2fhJ+ah87bPPYxw8rV v5FeBbhcwjGAFNyTQlw9/Qc1MtPRAv+TmDfaItTbKV8jwFdj9jf3EVkvxeUBxHackqbmGUwBYxC E31c5SQBwm+lmSk5Zg3GUt8d2RmVnH0RXNGWSwTvA8MNHqKUfcLpRduHi01zAnmK+5PybqmpW/I O8Fg3323MDZYkvw1N8o4LavnZjCIZYa/h5yjDWvfGtCzBhwrCeukNt4y0iFB+hWHhPVsXKy3ghm RLOcGURxXSYxjnLzIZF5GGqf4C5B/mSpVcoETR3Hl9SKj3Tf9Bd1OQIOUiB/AY0Hpe2I1y3G8ek rNnJZSu7zfq5e9eG/yH9KmDayZCpMit7cxRzwcOpP+L/YEhtdQ63l4X6vLGCyDTYR/cPf/zIU48 ZUrLl+DucvQWpQg6NMRLbmxEvBDpJfYTcPGAbfd8/GjUCAKFIpCHq2sRFcq96YLxFjoLJAr2pbl FfM7XXSG3LHKLqQTQc5QZPdWW114yEz3z6vidporYrRFsAPVNVRvnYpgqIqPermLTTSBNLLBsGo TrR6yUlVE8FyYCDYghNQnMjwEvpwTS/75vy42A2UfPvSD+8pCtYnGFQ30CSpoV5DZiSWELt1LUq G9UcsI0Z4lfOtefI3F9Evoa/haU1qS1GOfgMKIUTYLKxlA75TVgZI1urDqhlHAXZbK9numyqqU2 K8eaAsK/c6pUEcvQS5FrE4/HsNVQ5wXlA6QtMLIg1gjIPPLu9ieVC4Kd8zRKapV7KXGEumacIlC tQpOOT5IpJfIoh9956VQzajwLdGIoS084ARXOfDJTdkR4n0KjHbXIR8wGWj3wNUeJouGEl1FR37 lqlZJpfeyfmo3d6JUWO8+kgxSF0smP2lyDx+6u3BuxwDgSfnkpFaxT1HYorzizD8O7kU/XpMKYM 8lJ7xwKxf8788dsn2WTWWUhRavL7Ue8871U/2gkUu11HimGKTZNhjPSSLMACWfHWEfGF2U8tExX zPNPTZ7tg/0oehGrhv+0ygH9grBJbm/O2NxtH2x90eKo/zwxo2HHed528AnRjvGXQ/H/+mBJK+H QFG5q0Tw4GHDmzb3n5ecRIaiSYm4uu4n28MVcBPm8uvs/kF1G0FRBCMWEl9RMZAvL/jkdzf7u49 gVnpc1P+G0L41wmeFtc6RPOnB9BIsZxvhLNwRBMUVvbPUmlMXzke4939fL42C3KZvJn63/aSvq2 7MTlDM8H6jetJD7ZU6gwOqcp5jfKGVu1MYPa9DLJBm4epFJ/I6iNtsI1ctbfcbmGp7LAABgKvA7 RJ56vZKp32QgwEkSTXZITJIpJokQVxdPze6gcvfeOOo8+rUKxb1KrXysNYl3KhMrJRC2J6nuFgr LejVSTe6UmLcf9l6WKTBpOrjNJUhKUIQ/7khNa2wcqdhfl9gH3+njliwfDu/AAXB2RL4lIs+gQm c3OTk20v4eKJdXmgaP4pZd5AIUuUpRYI//bfLRXc6aWzChEBTtkMREZv3+BcCEw8ckffLHJ08Ye fOREfYbuYu9sDRY36un3rx0TbBM2E6Hm7sMBw5UtilqtI1RF/kXABKMeGsByJHMCBiW1Av4dqXR gi3cPwa8qULUbYSTiWVcjewqrC6vYdEcf3FSM2ftRWTA+Y1bA4ZmGMPeN9Vm6MD496VmVohzmGH 3hCkleLcoA/ekuNAxgw4O+URwCcg5/WlOtPK0kIuE0RzC30R6HHtISmFCU01WI+hub60Xikpg1M j+Ee4VOFrHkbaQhIlsHxUNUMJPUHj4D+rZtPUYZJtrQJUCs44HvvWHc16Mup/02WhQdjpHQ3stq PQHJexkbexyeogR1OZo6pe8Ajf05KJaL6GYw6d0tXkXtyB1pCGnOQC3Vh7kNvB3UxCfkiwFUfWR +1RqiBsRyMg2v4PsQv90Ub8+DLyHyXKX2P0R5TRB5LdEr+5KoLcjuAbDSFu/tnMQaSBRAc/8ws4 mPz7P6Nkwv0mtKKfmzqdcVpkGtfk1WXHfQDPQCGZd3QYogRmQsTBHprLuzhjGJVgtYOCHsTRze7 ySYDnPqcq6uOO9YxkHozHxsIwJ3KBc6xSaDfDppDBqBJyQZHwO7nv4TK+Rwb5x30oyNpiW34uz2 o6FRN1cHVy6E0C1a2tRiqYvmDonG6OJIE4ZU2rJiGh6LcDF3swfAUM7cBzie1ynAnOCL8ij9Y5S Lui4vQt1ZCcp2dTO7b4+j5AGkayglsknrDTpTix7hdGHReQmOhYPzHhzaB8NzANsGN0A9SGouI1 I9x0sXnadbkRDVw6YyM9nDGr5dGqMKH91zCa9M2vuxa2Mo10Wdwzwk/rHiB6CKvLa23J3mrPti8 eZmVfA2KvXGyBPD9u6xlghfog8q7arrIDPS6CQsFcRuzexQNuzdNoonXqTQ0SX2p+BZxNFcE7AO 7hoJSiTc/cjyDgxPIeHwfrVcpueZt2nEN2f64tbokGgvEAt2cMABo9Q+UR17y9K3WZxGSB1rSQg L413NmXNp9KXllbvxIlBj9Z5kp1etYSmwYTf/j+Z8mcdVOw0gyL6GuxGf1V5EinwMDU68PYzo0W W7ATOxYwlDgmUDUie9LtUc092RpmkU8Q3ZNHP1KYY/J7enjRWY+myCJVLWRjGENt/W60cXbikvM odZDksc4BTbwnArMYarEYplE3GRC4jCMWtdCbh+udeijoLu380+0D0FKx5fgtw9pZfzT4O0H2ot 1L5ktPNLAWIeEhXegKBJyKGlKjdVXOnNup/h1BvkysvFLU4a9BxcEMFSCgTzxGtQlDsV56P9zTg eVxQO2LW5Ee+390UNE4Y3T+5Xwcuz3wOVRfBjApjUm2t3JvK+Li2omdVgbnUZWOtock6on96Lyx LXuiu09klxqZUf2ZywFjl2Vm2ueMmr8NuicFOaBK1zdqzhrE/XRRBp4mHvRnr7qke/kcsL4wg3i EXOttar5F8YDdsJ3bdDGWOlI80bCyit33GuLhMOWeH5i30cOlNirh8pFN85lBw2lobpNIk0hB/9 gSx0UJUWVjBGj/+82hVRpTyv6a/9X9UmYjKkeh8nfxHR2oIIGxQOCBsEAaFn2TGY5FnlenUKmKP ehH7bK1r5aIpIG847D6H50h8ZRJ0X+1tC2T2BVB8BD4l0QPRlnNJNzBHPNwO94CoPyOlxsOHW8E LagU7E6rW/X/x7Pj3JfRgGBRgxcdeBQUv6g28SZLuBDIrshryXXhMvUNN8qh6pIaucFf6BCh9pf wNAIjBaC4J5Hq/MINsOCQsikulj6S3oXLTsAMlFlY/5Gty5J36zQAz5ET1zvD/SX1NnZ5bmIb0t HKZ1jUkGm3PBp8e0cgVpRpvfHVdP7LPDWGfhIw1xaYUGaU8ulGTCXQ4OCja1mfEuJAfffaPSff6 IGnyqlx/3IXTfQZjVlcR3RxeZTVt3740pnXG9VoYXL7Gl0fT8kjMgdH7fUvG4/eFrQIXABfSqYX FzJ4QXLXfuHhtRXgBPnk7CvBXVltfqk9Bw+pxDAGfh9fjm7vAkyAfduyxm05L4UkIY55EbD0bE1 BIty04Ywk5Ic5gxRxwgT9ujwsGk4tK+nltFvtl8MG+byFaTj8IRvw5vW0sM7yt//Kp7NlkDcPL/ ubyUfxTpTUL8bvBLJSyY81Ym1au6K7YkdNCt2vWIV2TIR7+18Soa67He74RjKx025ukJB8Rn7fx EV3QrqRlqDv7B9f1lbZqfrJXs5XoBFgcJYhUv3ZD8rvErC0hEgcMPme6sNQGdZ6ubrkL5U75In1 LFmrSiDQiJoV2VxGHengnsr29f1+PIZkkrdVMwwJJJBgsVCyBARAh2FGzlyhvUhHILe+bUg9WRk gFrWXb2MYDm+lIbAcsBDCAUTG+HB6kPMCOa+nOuUq+tIyN05qd4L8KMyzCXvGzajawb4DVWbRuJ NAwLoK4HxrdSISe7YfD477nr1y8yWAX4y6L4MPrxvGYdDWM5wyFGtprqGhTksabkGLPdNs8U8u+ jneCvnngkQDeMhHfKlcggxS2Mu2HmeQib3vQh5Aqv9HzvnKfhghRMybz9BQtWpzzwZYYCiPLu9N 94BxgZKdcusXcdzFXY2bzxwbsKeDhW+w0imB+LP1Co5KvDoxJ1Lic4FedGG8MIthMUGbxo99g7t Zj369qNadEDUx2hT10T+GG2YnycfFccK16hgkbd4Z90sT+XirYQ9fJmmC3B2jzhE9cw1VfgZG1b ItcYtVNPee+2YATTxUdfizpgvGSwBCEK9SrRA7umDbocsiu9eK4ZXizaM3hWWhhTq3szt5yF51M wScuo1u3ywklCMci1tuOjMnlLA5wfkSqAjcVOuIN6dftV5gMG4GfezqFlAKxzd/QxJGEuaEgSh0 9tj/51qt5sYz+0L23bMqiSj97bnfKc9Y/FbLphnZdhoVbzvXUU96tpIww9IvTPo4TURJ5j+x0Tq 2DOKd4f+WeO5CIntiWNQn2gCD0NhkulUQRJ+A/dkMoRUdv8oTubxYowP7GXrvZtI8gJfFDTloiN fj86HPYzK75TDuusgCggApgubH/5yeP1aOuMMiTQ2ya9X1+DWJYDUXy2ndw5JlKEDHnuh8zyqLi Dsg5ZgX71MezKh1GC4e73Bk0aY5/Vx2lYI3B2lgFS6oLmD4DSEz7wy0BzKE7zwygzvt0gDuf2+y kxwQrco0rez9DxHsKQq0MbVJivDmOcWRIu2j65UKg1fRoIL14phw+gz/XvuPjmPfJG4n4nl6xIp jsx7ymT5nwpfSPU/FnfuE6Hh83wajdKFWBZFmz8UoQyuPX8Z4EEq7qU7QwXw0CKIUGDaXytGZS3 i9a+ov35s5abkBGbHktMXUK0oQGUaRCtnNTenbvRfodOP935HBSF3OZLVaZQSbsnseARzoP1afs nzz3gSVvTxqWkwFSIZP9jLjM1flBJPLDnK5FV0dhvXb2QVOTS9IgtI+9D8tdc5gzsgPVVDV8ixk ZpG/YT6OWQ/XgWet00T+LnQ53MoX+nbXZhWwU124oXPt/HgDLIWz9qpH2hE3AgT8+y1NjGxzZQZ SmkmsBs1oxYWmmcry5bz01BMqvTAgTLBd/1HOFEoI4SRRxl8hz3zxt0qy8zSVX3ZZDRKoRXJRy8 4vZiWSkIm75E7ZLVAXe/KHwCMus7eP2Mmv0NmPt235fzKjq2ohryd9C7eTMFCnNf/TJ7tsqIQvC iuc9YjP29lcHOaDFNybDLi6V/KjDTjYJNyaocBOjUS2I6pKmuVe/EKau5ul2q8yVwUqO/mCiwa8 Ku+a/eJ1PaXOAkq4+Yq8Xc+1qQvGqq8+5hzHOJwH0Lkup4Si2cmHFmNMYnQYCTwHiU1TWAyf7ZX C/fhY/oEMksy5+v4t4rC7Po9NrE6WaOnJwKb -----END IBM-DILITHIUM PRIVATE KEY----- -----BEGIN IBM-DILITHIUM PUBLIC KEY----- MIIHAjAPBgsrBgEEAQKCCwEGBQUAA4IG7QAwggboAyEAfJk1oLB2lKoMbRDk22sa3S/YGiXMsUg DLc1zmTZzfy0DggbBAGhZ9kxmORZ5Xp1Cpij3oR+2yta+WiKSBvOOw+h+dIfGUSdF/tbQtk9gVQ fAQ+JdED0ZZzSTcwRzzcDveAqD8jpcbDh1vBC2oFOxOq1v1/8ez49yX0YBgUYMXHXgUFL+oNvEm S7gQyK7Ia8l14TL1DTfKoeqSGrnBX+gQofaX8DQCIwWguCeR6vzCDbDgkLIpLpY+kt6Fy07ADJR ZWP+RrcuSd+s0AM+RE9c7w/0l9TZ2eW5iG9LRymdY1JBptzwafHtHIFaUab3x1XT+yzw1hn4SMN cWmFBmlPLpRkwl0ODgo2tZnxLiQH332j0n3+iBp8qpcf9yF030GY1ZXEd0cXmU1bd++NKZ1xvVa GFy+xpdH0/JIzIHR+31LxuP3ha0CFwAX0qmFxcyeEFy137h4bUV4AT55OwrwV1ZbX6pPQcPqcQw Bn4fX45u7wJMgH3bssZtOS+FJCGOeRGw9GxNQSLctOGMJOSHOYMUccIE/bo8LBpOLSvp5bRb7Zf DBvm8hWk4/CEb8Ob1tLDO8rf/yqezZZA3Dy/7m8lH8U6U1C/G7wSyUsmPNWJtWruiu2JHTQrdr1 iFdkyEe/tfEqGuux3u+EYysdNubpCQfEZ+38RFd0K6kZag7+wfX9ZW2an6yV7OV6ARYHCWIVL92 Q/K7xKwtIRIHDD5nurDUBnWerm65C+VO+SJ9SxZq0og0IiaFdlcRh3p4J7K9vX9fjyGZJK3VTMM CSSQYLFQsgQEQIdhRs5cob1IRyC3vm1IPVkZIBa1l29jGA5vpSGwHLAQwgFExvhwepDzAjmvpzr lKvrSMjdOaneC/CjMswl7xs2o2sG+A1Vm0biTQMC6CuB8a3UiEnu2Hw+O+569cvMlgF+Mui+DD6 8bxmHQ1jOcMhRraa6hoU5LGm5Biz3TbPFPLvo53gr554JEA3jIR3ypXIIMUtjLth5nkIm970IeQ Kr/R875yn4YIUTMm8/QULVqc88GWGAojy7vTfeAcYGSnXLrF3HcxV2Nm88cG7Cng4VvsNIpgfiz 9QqOSrw6MSdS4nOBXnRhvDCLYTFBm8aPfYO7WY9+vajWnRA1MdoU9dE/hhtmJ8nHxXHCteoYJG3 eGfdLE/l4q2EPXyZpgtwdo84RPXMNVX4GRtWyLXGLVTT3nvtmAE08VHX4s6YLxksAQhCvUq0QO7 pg26HLIrvXiuGV4s2jN4VloYU6t7M7echedTMEnLqNbt8sJJQjHItbbjozJ5SwOcH5EqgI3FTri DenX7VeYDBuBn3s6hZQCsc3f0MSRhLmhIEodPbY/+darebGM/tC9t2zKoko/e253ynPWPxWy6YZ 2XYaFW8711FPeraSMMPSL0z6OE1ESeY/sdE6tgzineH/lnjuQiJ7YljUJ9oAg9DYZLpVEESfgP3 ZDKEVHb/KE7m8WKMD+xl672bSPICXxQ05aIjX4/Ohz2Myu+Uw7rrIAoIAKYLmx/+cnj9WjrjDIk 0NsmvV9fg1iWA1F8tp3cOSZShAx57ofM8qi4g7IOWYF+9THsyodRguHu9wZNGmOf1cdpWCNwdpY BUuqC5g+A0hM+8MtAcyhO88MoM77dIA7n9vspMcEK3KNK3s/Q8R7CkKtDG1SYrw5jnFkSLto+uV CoNX0aCC9eKYcPoM/177j45j3yRuJ+J5esSKY7Me8pk+Z8KX0j1PxZ37hOh4fN8Go3ShVgWRZs/ FKEMrj1/GeBBKu6lO0MF8NAiiFBg2l8rRmUt4vWvqL9+bOWm5ARmx5LTF1CtKEBlGkQrZzU3p27 0X6HTj/d+RwUhdzmS1WmUEm7J7HgEc6D9Wn7J8894Elb08alpMBUiGT/Yy4zNX5QSTyw5yuRVdH Yb129kFTk0vSILSPvQ/LXXOYM7ID1VQ1fIsZGaRv2E+jlkP14FnrdNE/i50OdzKF/p212YVsFNd uKFz7fx4AyyFs/aqR9oRNwIE/PstTYxsc2UGUppJrAbNaMWFppnK8uW89NQTKr0wIEywXf9RzhR KCOEkUcZfIc988bdKsvM0lV92WQ0SqEVyUcvOL2YlkpCJu+RO2S1QF3vyh8AjLrO3j9jJr9DZj7 dt+X8yo6tqIa8nfQu3kzBQpzX/0ye7bKiELwornPWIz9vZXBzmgxTcmwy4ulfyow042CTcmqHAT o1EtiOqSprlXvxCmrubpdqvMlcFKjv5gosGvCrvmv3idT2lzgJKuPmKvF3PtakLxqqvPuYcxzic B9C5LqeEotnJhxZjTGJ0GAk8B4lNU1gMn+2Vwv34WP6BDJLMufr+LeKwuz6PTaxOlmjpycCmw== -----END IBM-DILITHIUM PUBLIC KEY----- opencryptoki-opencryptoki-451d99c/testcases/misc_tests/ibm-dilithium-r3-65-key.pem000066400000000000000000000253311520105705100303030ustar00rootroot00000000000000-----BEGIN IBM-DILITHIUM PRIVATE KEY----- MIIXYAIBADAPBgsrBgEEAQKCCwcGBQUABIIXSDCCF0QCAQADIQA23fu2TyDtycCt JV2d/X3icWZlL+txE8R+k5eyPW38YwMhAB1y37Z0kbbij6kqImv45QOE/4DqXgfd SKNLRyEjdEu3AyEA1moG/0IwHu+cpVQbEtVYkx4tiS+GoIPmKCfe4oLcqLwDggKB ACAoJoJEBiBQdQVRURhmaAFQEFJQY1Yxc0hwABQXRTAgeDOEUFFFRTZgJBdHAlYX dkR4gjNyEwZwFTJDY2MVBmcnR2VnFiWGMjMTFHQDRUA4BQUndlBXBjAVGHIwBViH ImaIUxExgIUYUEAlBCODVDEURGAiaBZYeFZyBAhlQ4ZCEoVIKCJ4CBYjYhUEQxGE ZFRXMjBCVFdTglUBcVNyWIMYdAGIcCRHFIBoKGMVhzdEYYQgY1UHiGNVOFc0VDF1 YEFzJ1ExRzciEXIFFCaIQSQRQlNSUBdxFXhzN2hReDMBYURnBmcFNCBkFzBnNGKA cBhXEVdHhHJXBXJSJDJRE2VyUCBkMEhIYHAWBiYHSEAzZVVmVnWChjgENGMGCChB ICUyYzcDBzGEg3ZSI0cjEiZmVnOEAiBxYFQCAkcocDRmAzNDYxA1AoGHQhZTRnJY AHNCYyKCSINkFXdnVnJYAGIxWEZQNGF1dlhUKAUQNDNnGHRnCHQDBBQDVHgDY0hw GDRDV4UEMCM4RUM1NYhSCHR0AiIgVzASVBQ3ETWHcEFIZHdBcyQ1cjElFWaER4Fx iFR3UIAYhxU3cYgjZYInBHASQSAXEhBSFBJRVBAIaBI4AhFxVVODUFE3ETKAUgAS RlUjUURhBQRnFGNYODVRdUQhAANQNnKDJwUnZYcXg4iHRQhVdVJFh1h1FkKEdmU3 QFFCYHFgcUFyERJUFiSIB1WANIAgIkKHFBQlCAcVYVJzF3aGQiJBSHBVNkSEQYZB cHVhiBQQNRAhFhchZiNnBUIEZjVoRWMGYWVFBiV0KAZCEwiHZ2JEBVMDImWHUBQD RhEYCDJGN4GGFCFhNAV2VVgDggMBAIQ4ZXQmVGBoMyFWVHUWYABAEmclMwV3g3AG I2djQYc1EjiFhwY0J0JISAFzGAcVZ2OFdodhYFcxGFRWGDJxgUaGF1VQEgIlJTAo ADIwggeBRQRlV1hyR4g4CIRicVMIEyFzg2RlR1GBGABmZnRXNxY0UEh2M4Z1QURy ZoVIQSYSFVVYBSIYIhUQJkgnMGRGd1FIVoeFAygnNTMiMihQAGJyRnBjI2BRUxUy NRNQVmaHViQFAnABYjgkESCGcldDMgBEgEFTJyFQQIclgEYQNCR1E4JmFRdgBwEU IGAjdxQAI3Z3VmEwgxYUM2FAUgABFABgJSEAdgEhEFeEEHeHVSEIUQNhcWIgIIUU JSGCEmdVVVdmcWRWEBJAA1cSEhVRgmEWZQhlNWKDAyUzh3hVCBATNFYFQiRIUSh4 dlgzNzJ3V4BUQRZlNSd0VWBlUoCFhAFAglKFZwNUhQVUiAFRIEdGeDRwNwaIMAgh EyaDVRUwNickMlGIQ1JDFWQ1F0gUQnVUNTc3KAJhMUMCYIFAYERBREUSdCEFFUZm FIJRZkZ0JXAwBIcBc2NVdiVGFIhzQgZQWGMEUAEFhSNzARJTN1c1EkMRFVUDMGcH c0NXVEI2YxUxdlEEhzKDQWhWGHETEDMGKHZUcHeBEwIgFXAUM1JUIwFYAkdFAFeB dDVXhAFWdnOCSBUAVzgXZicBcFCCERiIIiM1ATRghgRTcUIyQGhleIMkdhhxM4Yk IoU4UydENCcmNxVihRBWh1YEgFIXg1d4NUNVUEURM1NURwFmcyFCZnh2chVUMXGF QIRYFQhFAgeGJlU2cicYVWVzEnR1dwRSJGZEERCCRTZVhWAoZwR2R4dHBRBoRoQH UYF4JTZXNWRSNVEEh0JyeDQiMmcVQ1V0JwMWB0UUI0hmQxKDBoQmZDcEREEDd1A4 BiVleDUFQTBGiIaFFAFAglEzI2QVR1ITVxOCAkJYMzc0cDYmZhY0gWaBEzIANVZx M2IgaEGDgQExWGAhFDUROBVGAwBhBgOCCcEAldn4OpXOMcsu3ViLF3jUqDQx6DHn 1XazQj3lHm50TpWGD6a7czh0LUPetBGrhXFfl/voN3OfrKwTbYy121l5xI75z5f9 OUOQcVkku2xL82fcI7Nb3+YHGGStxwwU3tVhcFJWo/oH+Ke7gvC/+Jwu5GyoFaRR 0IqvS86uvk9xZnOt2lvdxjOwhT3kfBPNJ66zvChNalXnOgTkDTwkfE6O35SBazm0 l8NxjZNgaiuZ+/LZ1V/qeUJU+iGx+hpLMWuX0nVE3vkiNYoWGDm/oFyT7pv8vE/3 GcMEGoHBDrSJAZqhpn6nffU9K6lIuQXOaHgVrhVpcMbobK4a0iVjLarIk+bdWmcR pyLLq5DGicvdFvjAdrvKMYiZtAvJ7vnjZBV3vw1Gb95p8ZcbcrPoNaGMm5KrvLVT lVmvyK9ZnfPoZI6TNqyV4FlH3lQIInerLnQrERJUif+hVD3KeQ2jZuYIXsm6mpZL M1pI+G8FhbIa3+uoLFpPszDEY7AE76gqGDVrLSUSur6dP2KnW1G3IMeUHGuADmVN zrevP3niEjVo6VpPVaCur/0/OH40T587BmmSaSak9VqJnHI2pNkv0l2N5Kk9oME1 3KCYQnhof8m+vdT+ETWtOvUKVtCN84sePy+GkDm18KMFe/t5lqu8Vr5tZgXbMeBS 6cgIV770IqymtCPH1m0aw/Hmbs39X6OX19uPUEuvOb4/sYeYEeilRdEqw1ygt+Eg LjL/eHgzztjCHJvERsk0F4C8AGiNhx5D3PytozbuWnCwQnkPrFJP9hQ3cFqJ9Jhc il/Mp8SQLhM9RvMRCX0YvjyWMh1ho8m2Bze+iIkzs0RJz1K828U22uekRhYD8zCL pIS2IORwPr+OjGQ0MBmksXrr5ZE0PixCljQDHwW55r2y80uf81OTuQvWoQO/9C+r 1mrcXmHx/rfNgrmHOURSL7vtbkkF7p4x/vMSRAoZLf+Np1Xb8qjcoIxbzg9SeI6y twmlaVbTWVOJOr0/HNveo1wUCETZ7yDllk47KwPg4eJHiM7PnarsW8j4VnkMgeOY faaj9v0waEhMAHQcW5/xrClNBIhYqIsgA0mIFbr5J3NKxrRJXs8xFaHdPnvQOVfO JC9z/pKtlEjnBuGJ5zRIq8q1ASzX8lseHB/mYzvsFgK8CA58EVas6WDIYgD2KeIw kg3+Q8J9KuzUvruZzIF97wDIz5/Tgz+CcHNp9zdK9UxsJpPv19+oLTE+eNtDaBSa IWSDxyxCIxAdysGSWr3roz85zgg2+VQGWy0t/dRmyKY7W6ThAQ++zS+KZyDRxSIc 3xcjLynPf2CRalxbWfcWbKYDPkbcnf0YEz0RZa+wsuecAIRWCguuy0lBbmXBX/98 4iWkyRFzNYqZ8ZcLU8nYiwwutDoKnx3dFEGJCZFA0L/tiSoFqCYmWxjRJ0f4MdVm eLHo7LpO30f2GkjljbxZ1PkpeVRTZoaZZLTx5S26ooiQBvTVIJMHs7r8BnLgduZB NDMq9JNXVTuwOdukCq37GSmUmgVNFy7zaosLPeJ1UUJC3J+QYZ+XgujyeZHT1Rc/ /t46Ap0pomVyyWmLn5EFuh/0lrYCEJ5v7nGN4i+wmM/14KCcAafhb6/RqtyLQ2rs lnYGwQk/e8PsWdfN+d5qBJYEwnzJwM1xGvK6LQSUH3ZlFy96u/TaxmOvvdE24Aqu Ko7FQX4caMyBhSkaP/vpeOVF9JtiLVOlATMB2J1RncSv2MizXspa+aR9lRZKg/b1 LZKZNpuRq2vVb5flf0kixL+S47w1hz2lIxwJAJWM+NLc8WlXU720ZHYQrxCuHJFC WUhYzu8OeOayTP+xTZzYhvavFNcB+LPu9O2b+78rk1UlLIiPdDy4mCAgrF+NzTw7 SqJhAtuFAl1R8pyG/U4yWxWHiEiIjMHnVnaId+BIrfqXwGaW6EGpDVP/695DgSKT inp+kqmUw1S0J6j1+tt/39t+athNORemtCYigfjkYBWoGirEuXsJsD8lRZMxGetb Kqjgf8l3MEzFhjDu00a9jWX/tD4Qnp8LaKZ0nX/1nZGgQhlViLgv7er8b1JOmheC 3tftuVSEfyvSGeVVGIRblICPfCndAxbVpuQdHkPxKdEEuK1e2OLxCqNcc0ygWDYI bROyxFAle+axUiPN9zcy/YZdXwaafY1LcJF1NUbbxRKGBU+PXBYMB71SrFdgawD7 pVOXLRvQn8qABnpH51zQCqgLf2hlyg9eMKDg8BvxZ3EjVLidw4dmhaV39sB3v0V8 +gZ8Becn8cdPZMKpXShZpjx21sh0TWrWl1RSwmmPY6L6gLsctD/+K3ut9gaeIHIM GJdfrErXlmVgVlHCcylPkTUI3RAv7e0nUP9jkd1ZcH826sV3FRFEsLl2ZZ1Msr5B gl1nQV1a9mfi6e9DNS+T9ArDLtowdXR42Rag8H4qjV/uQDsgVzvdTCCGBnT2high RLWwM/EXaAKlq4QTW7IT9bGDWBdTsSSGBRK+CITLcL3YZEo61T5juwk8nFRsfIoh y2PbJmuGKrkHQR1wxXtDYWYhIxhph3vmSE5iDHzEQ9hzR9khuY67L7oAXqdL0cHj O3DLXUklu4CCt3tbpSEvHZuuKsq711A/7fpPjINl4RKyA9fp8B90pq4GT/bF9fav GNd+Hf2vG60MzKBPyp9wfVVXUeaDFnMKzsjyte4rEX6KqQ/fv0fZGwoug4onqBgK gC6prTCK3Z3/Ibyfxtl2S4Novp4J/WIP3Jfg0CTzvktOxy0hmetIiUIUvt/LBbPg Cg0cXjswcrrAvaIl49vBcXyOYJFJ9bl5zxy1A+zcxu0u+Z7MVCAlyIDKcOcD/hC2 wLubb6f1dbpFW7vMD9tOLLc9hLx5TzOrWNaYzwIICCu8sKMJAn3Hq3PNXfXplPAU cNmI3pJa97z2uLwqd//ZMXEVaDCCYmsFdRzwrF2LTEf8vgFAwoAnM5i9qbdivKr2 OG50yzlTHM01wQsI0jWOP3Gkt8Vn75S2ctZD9fJGYJyFRjo6xBWgrS7pMFHbSdc/ ZkJU04Rwrn/LZ1Tn2B6m+raJT+yzwAUycZiWaGGnBpoQSkclS0Cq6b3wKytOqlab qteeoR0J85p1venEZGAe4B8EvSgr16ynm8tvJXm2WcbpQ0z1OVbrzAir6ZaZKrIN W9yyJdDddxLmtzUp50/LnIFBOoBe3/9cpdUNlxISiHWankrZ32/cwhXKRVULDTph G3nhqTNhh7IJF+aokzWPjl9ieH21BchydUSDlYdUmRK7b2wi24IfwTqGub0gEOt8 3CRKnhfj9J65Kosd/pURU9FQqPGV0tahVUwUoIIHhQOCB4EAHEYm17H1FGXlGzl4 3wECRIWy+ZU8XejKGoTrMg1IjeOmmt7s5FXMjMeZ7zmwUFcGf6mjNzG6Q0vcQoyB cDglsgZvKIltmT/xYgnxzsPJZoU1CcAWvDPMXoGgKp8ruMyCktc7sSr4CnDf8cLV AtUyzhByJh6SXjDBOVRSHpmJVTiwtimg+IwQrKbLp0k1KTnAeMCZ2O1xCzmB4si+ NQW8eAyhqwqvzYR/9PJ3QMVxzISsjmihMWuAc9e0lX5MJyfr3aefvwXvN5p/ozmp 9yGnaOLjBrv9X+sILWXLW8GY37p60Hga5ZBQMmniYbKeBr+0Qh6e2YXq9m13snNG zYLJen3l0b02QEA3otmtVcBQBvGafU9MnBZHd02HdLN7qTZqhYMZ+tMqCsS/0BIG yOGbU0Ax50nNdxwMGuZr5Civb/cRzZXZnYsrN3fRvNaciDUgt+ByEAXxRSXpSbgz vjGpkqzKUW3Z9+Hj4hyV6L/0nVtii84b5nMG/XopLSof164n3IYKebZbwblxLWF/ tMi/7MD3z+r/z49f6akZBH3Z29bF5CM+IwCcnI5fNlOpGCpum1M5zT4OJrwHdg+y ul/EXAql4HCnOl2yAfs9DMbbSD1AbZLlGvHukV3BdPdYaUQgPOpk8IC04uhK2Afz +4DnbQb1PFsDd0xzloRrJUcfXcN22ghPWdCPKMI3YyTJzm2VYEPhVb3wGpztEaNK bUj0eDV6JXSOjvtiyW7HmrYaJWe0QHbAx09zQRLA59gE7MqCI5MAjInNE4sToiR/ Y6/65WaemFVYinMFad4LZaYKYjr014wTNqRTtaUflzJTsBerxkvdgs/WLMBWiFZh zMaYf2XLc/c3bJ4K00GxW2b//NU4rZQZlJIh5OhvU0DPY0xLG2Tsaz0AP36UJyPE xStUOPHSemPA/exAK1+9mTKU9XF31KbE3EFROqWswPWX1tgtfK2i4lp94IBaDNut /ajgstkOPRHtUpMgr6GO7su4aU2iMyqDP3Ys/7ty6cnjsFOgUZLMtSjcHOXeVBU+ YprDsTR6kRfsVVRb1oBjK9iLm7kpPDRE06PqZpB8Cv26ajAPvLnVCp6qrMm7RR9H WupsGHfnCPtgWIsXZvEWARg+crPx1qk3gQSK74358bNkDL9HcLCVhykOfWYjyRnl Lgl29AEd/cHHjgc2hqNQ4wew7WME8MPYJq+JmKxQTuI5vH/IoxR/194g+hNJWubs usAIYrA5DKk212wyRKgM8hrteMLB+5cLXSHHy/0KpGAqjV4H1YNLUyqoX5L8Hz0w FHNLctuVUvA64L0jDPRXp5ex/tflTVd8JYbYj6NbnvtGeM/dHH4Y5PVY21U1BQ99 x9TLt3hM9Q2kCubOE2SQtpzCDwwxuFQGfQukGrCCBNY0VjHHnBJg6SHLikHGOgNi KXuT6j7/kbtNKHRl5otlrEgeSZpu8Mr03n0fsCeDpp29stb+TDjlE5sD6NaXI9PE 9TOHKXQ/wK1fqSloZqifcHZsePlwnBoFThNkFgfjYD17dx/mT/gk2G5Bi5lfq7OO pUMBJdCZHlN3UVLTaaRlQWvcDB3CyyHkUI0S8/BDbWMhXMu28iIldBhjh8cfYHf9 mfi5WLbM8n+XMVhHMPdg6IrBAWWo+ygAoK7fFBWNxfKpLS1mDD89t1dO0uLXMpkg QoKyIfZ6kZxxyjYAz/FN7tet2mqY2bVgTyvV/LbN4GeZ8TRYY6wlrUUUR46vY4Om JBPMTCq4WQw4mHdosR2+heVXlDgedw2G6uKt5kmOgTbxTBO0EyvDtZ7mBAftkxdB wCDP7JnMWofPE2gIrlij+0QHiBktczblOmZzPMADD/Lx96v0VoS/CSfn7Qrvhpx1 yymkfd2lsuU7eF5jhZj8x1aSqRJD7gRTFuyNOGQLmiwrWeES13Y0sdPOhkUyBHXC 4darVQBc6l8oiiUCUQzL1ylYPY71jvW3WdnS7fsBFuNeLrVyfYupWah65+vIEvaY BaAPvIUBZg+KEwsnsDyoPadkWFVQ6fC0Iqt/ITmUiQ+COgjdGg1VJupVegDLIDaY alqH0W9Dfc6Gc4QXfOcbi5w0CZrqy4zQnHKE87OP8FjZ6psjBlQQtr1+aYmZIat5 6moIx8cqqhtZi6XIS51/LZx/zbBOMXo7xovQE1fq70Q6NQffLUIlzFd9rA5FVc/J HK1pU1iIHCVR67LiP92DKNP0X13G/e9ipDwT3kmvVC5wlHuoOzrIsu0y2AlpioCo 4t2Hs+4M/6mud++iSE7T9QNaLMgA5RJeM4WqjsvnaHd9wnrX+rK+d7LsN+udMXdz vErrV7r4we1cmq8et4SzAzuYXK1NaGHoLpOpUydz5L6b1f5l9lUQjoKUWEolnfHg jFrp044becUWajUHdyVzC48s+e2i0DnEzeu1zpQvtx2Nc2+/8efCZ3k4AU+Al0VK HBmh1m1UK99BGxHsMNlxan0IlUZ7v8sScnej0VgABUpESwiCtsebHjgzwNngQ2KG EJJ4gMVFMNj4tLdQABRSe3iuU7BEgNknC+ZoSoOsgnhtnvup -----END IBM-DILITHIUM PRIVATE KEY----- -----BEGIN IBM-DILITHIUM PUBLIC KEY----- MIIHwjAPBgsrBgEEAQKCCwcGBQUAA4IHrQAwggeoAyEANt37tk8g7cnArSVdnf19 4nFmZS/rcRPEfpOXsj1t/GMDggeBABxGJtex9RRl5Rs5eN8BAkSFsvmVPF3oyhqE 6zINSI3jppre7ORVzIzHme85sFBXBn+pozcxukNL3EKMgXA4JbIGbyiJbZk/8WIJ 8c7DyWaFNQnAFrwzzF6BoCqfK7jMgpLXO7Eq+Apw3/HC1QLVMs4QciYekl4wwTlU Uh6ZiVU4sLYpoPiMEKymy6dJNSk5wHjAmdjtcQs5geLIvjUFvHgMoasKr82Ef/Ty d0DFccyErI5ooTFrgHPXtJV+TCcn692nn78F7zeaf6M5qfchp2ji4wa7/V/rCC1l y1vBmN+6etB4GuWQUDJp4mGynga/tEIentmF6vZtd7JzRs2CyXp95dG9NkBAN6LZ rVXAUAbxmn1PTJwWR3dNh3Sze6k2aoWDGfrTKgrEv9ASBsjhm1NAMedJzXccDBrm a+Qor2/3Ec2V2Z2LKzd30bzWnIg1ILfgchAF8UUl6Um4M74xqZKsylFt2ffh4+Ic lei/9J1bYovOG+ZzBv16KS0qH9euJ9yGCnm2W8G5cS1hf7TIv+zA98/q/8+PX+mp GQR92dvWxeQjPiMAnJyOXzZTqRgqbptTOc0+Dia8B3YPsrpfxFwKpeBwpzpdsgH7 PQzG20g9QG2S5Rrx7pFdwXT3WGlEIDzqZPCAtOLoStgH8/uA520G9TxbA3dMc5aE ayVHH13DdtoIT1nQjyjCN2Mkyc5tlWBD4VW98Bqc7RGjSm1I9Hg1eiV0jo77Yslu x5q2GiVntEB2wMdPc0ESwOfYBOzKgiOTAIyJzROLE6Ikf2Ov+uVmnphVWIpzBWne C2WmCmI69NeMEzakU7WlH5cyU7AXq8ZL3YLP1izAVohWYczGmH9ly3P3N2yeCtNB sVtm//zVOK2UGZSSIeTob1NAz2NMSxtk7Gs9AD9+lCcjxMUrVDjx0npjwP3sQCtf vZkylPVxd9SmxNxBUTqlrMD1l9bYLXytouJafeCAWgzbrf2o4LLZDj0R7VKTIK+h ju7LuGlNojMqgz92LP+7cunJ47BToFGSzLUo3Bzl3lQVPmKaw7E0epEX7FVUW9aA YyvYi5u5KTw0RNOj6maQfAr9umowD7y51QqeqqzJu0UfR1rqbBh35wj7YFiLF2bx FgEYPnKz8dapN4EEiu+N+fGzZAy/R3CwlYcpDn1mI8kZ5S4JdvQBHf3Bx44HNoaj UOMHsO1jBPDD2CaviZisUE7iObx/yKMUf9feIPoTSVrm7LrACGKwOQypNtdsMkSo DPIa7XjCwfuXC10hx8v9CqRgKo1eB9WDS1MqqF+S/B89MBRzS3LblVLwOuC9Iwz0 V6eXsf7X5U1XfCWG2I+jW577RnjP3Rx+GOT1WNtVNQUPfcfUy7d4TPUNpArmzhNk kLacwg8MMbhUBn0LpBqwggTWNFYxx5wSYOkhy4pBxjoDYil7k+o+/5G7TSh0ZeaL ZaxIHkmabvDK9N59H7Ang6advbLW/kw45RObA+jWlyPTxPUzhyl0P8CtX6kpaGao n3B2bHj5cJwaBU4TZBYH42A9e3cf5k/4JNhuQYuZX6uzjqVDASXQmR5Td1FS02mk ZUFr3Awdwssh5FCNEvPwQ21jIVzLtvIiJXQYY4fHH2B3/Zn4uVi2zPJ/lzFYRzD3 YOiKwQFlqPsoAKCu3xQVjcXyqS0tZgw/PbdXTtLi1zKZIEKCsiH2epGccco2AM/x Te7XrdpqmNm1YE8r1fy2zeBnmfE0WGOsJa1FFEeOr2ODpiQTzEwquFkMOJh3aLEd voXlV5Q4HncNhurireZJjoE28UwTtBMrw7We5gQH7ZMXQcAgz+yZzFqHzxNoCK5Y o/tEB4gZLXM25TpmczzAAw/y8fer9FaEvwkn5+0K74acdcsppH3dpbLlO3heY4WY /MdWkqkSQ+4EUxbsjThkC5osK1nhEtd2NLHTzoZFMgR1wuHWq1UAXOpfKIolAlEM y9cpWD2O9Y71t1nZ0u37ARbjXi61cn2LqVmoeufryBL2mAWgD7yFAWYPihMLJ7A8 qD2nZFhVUOnwtCKrfyE5lIkPgjoI3RoNVSbqVXoAyyA2mGpah9FvQ33OhnOEF3zn G4ucNAma6suM0JxyhPOzj/BY2eqbIwZUELa9fmmJmSGreepqCMfHKqobWYulyEud fy2cf82wTjF6O8aL0BNX6u9EOjUH3y1CJcxXfawORVXPyRytaVNYiBwlUeuy4j/d gyjT9F9dxv3vYqQ8E95Jr1QucJR7qDs6yLLtMtgJaYqAqOLdh7PuDP+prnfvokhO 0/UDWizIAOUSXjOFqo7L52h3fcJ61/qyvney7DfrnTF3c7xK61e6+MHtXJqvHreE swM7mFytTWhh6C6TqVMnc+S+m9X+ZfZVEI6ClFhKJZ3x4Ixa6dOOG3nFFmo1B3cl cwuPLPntotA5xM3rtc6UL7cdjXNvv/Hnwmd5OAFPgJdFShwZodZtVCvfQRsR7DDZ cWp9CJVGe7/LEnJ3o9FYAAVKREsIgrbHmx44M8DZ4ENihhCSeIDFRTDY+LS3UAAU Unt4rlOwRIDZJwvmaEqDrIJ4bZ77qQ== -----END IBM-DILITHIUM PUBLIC KEY----- opencryptoki-opencryptoki-451d99c/testcases/misc_tests/ibm-kyber-r2-768-key.pem000066400000000000000000000152121520105705100275150ustar00rootroot00000000000000-----BEGIN IBM-KYBER PRIVATE KEY----- MIIObQIBADAPBgsrBgEEAQKCCwUDAwUABIIOVTCCDlECAQADgglhAAdjj7aYaPPTIOWGK9lpM/6 zEbNiCTybXVAXC87UPxtTbZogS7HyJpWVC6HyqejrgosoRIh2Cz/IT6ugQnXVYo45xbJHE3QoPF AymcCrSbZri7tWpBhmJPkZorpZuwjYVRiAwr78T4fyX1mrWHp5wyfXktVMl0ppJi/4p4k4KJ6ah 7aIsIPgWV/iGLa7FQWUHOLoGlpkxarGBBclaYU0nuR6UkIKX5dHe3I2rHa8cOgohykofuPjSj28 NoPAt7EAKfwgNBhTfnRmumOFqP8wHuEnCPgqqh44D8eoj48gWrfojX6VlSpVuiDQm3mkcUHWK/b rfdMHsI7KE6W8X2toWBxoZbJ7vN2rFC9LLL/0iMiiJwX6qYornuo1MMdmYjNcx+o6AHd3JevMzS pGNrLZEi/zq3cSPOCIPBkREV5QyeipQZTkjdDQnP+zrc0sHpJDCQPQetvwBTIDFXWqf557Wh8zY t7JNtQEPAXyR2wHV4vJy68qtOOCcnrUFoapayVIgguwOzLxGygRrWL0ielRYyq6DR34loDMiotT tIHZKmjXC06hw6alYcBpKIK1yozJQqjUla/LBt6JSY+5Nbd1kI/noD4yTVTMGdThqr01k7OLGe4 TiP5JK0MSflpQQlN4ag1prTJgHCjiyIUEpbpZlwYCOmE2PhfGubtZvcaXRSzQWUUZg9c4yj/QNO P1mIhUygUDHbCWEUmJiBl8azDSWN/iYmVUHImksx1oZOk4mwPLdPfsQyP7lCGkuXkKJtF7A5iiZ 2c1CQn4TVe2aU34MGZMqLPDwD7Srme4kAaGimhSfM1mZFmrfwVmcQAMYWTTp/JmoU2Xy9cATWyS ysp3C4RKT6mxguexjKiFCCrFZG/LShThaF/rDJzjNyq5U2XAT9gwhPgKI/8QoFvxX3+lrMbAy0Y sM8pST6a4uzWQQ7poYJ6qJTboHQhGOxllO1Q1upRsmt3rICsEsDHMlg3MEuRRjUKLMrJXpPxzE9 OnmA2ACC6TT52VwysKAZGiNgQ4Tdngebu6ombRTD91a58hMxB0M6ToP6cYcoKoCSA6T6+EGFGDP RIaw4OEOl5VvCOBQl4Wx9tMyatcGw2RpH4rjeDlgshraw2Qe7NguX9Aq10Dj2t1yBSyfZuWjUGY MryMK+5gXvblBZ0zEA2QSF03hFABQiFzbAdAfKwmBAiqZJJmGXiLhgHCp1LRpsv4INfHoEcWIDI ls4lbk0LRR6gYXPwbtluga0FCM5kDwKxGUThbRdmKixnSjNa6sIh4f37hsSRhdmtDy8y5ZDRCfZ PAZVUGiPaUjtG1R1pCXxuFIJ0GHAi1bBzAafbAp8byk1jKuREIdzKmSdJ8m5j5pIh5OH2bAMJZW acWVNb2qUYWRRPkenXQBZhsI2PAn2tTfsp4uTA6X6RXYIpYamU6NH2wTfzBkXWzowEXJTYGKmWK lSd1cMiFLKiXP0rhI6M0BH3XEciSemNKAziKUnsDS/eoFw+nAsH3wj7DLRiiN0iQvpx4epQJyC0 ZLEu3BaL5ls5AXaC3H2fGzsDTVobVE0I0MuUSrEBEVX6GimJIABCaM1X5jxUUROKFLifqbtsZks rTlzw6b/eaWgSaJZ61QVqiomJFbslJW7tSANjTFjpbECJikuygECE4naN4geJ2MGVQxu+2RA7FG i9zSDSbhRzUqgF1oFUCE8R5HZEBEiCCSythZQgTrf0ssQU4v6sKcm+BEp7SwPBqFrcBCQvwSMWk ASbVcvzUeqEhj7AVR9FQeS0jFssyDVFEujUIoeu7WsHCKRPoKV+rWb9YN6d4zygifgfhAy2rfQ4 JoV8TQUjBIAnaU2sizGJHTmnMFVTAgU1soLciWUODqdCix3/TZaVUQpX7uXP5HqVkkNbKaHZJe5 izyxJBfCV7bQ9xg9u2njMHW+sBF7aRTGm6ODSUIvL0M2SCKiVwlS3VB3uQdV8VdBFbjiIUJ1hZY ZE6m/oFArXXmreBF0TmVjxbYsXMTpMjmgqMxg/oSPhKlfWQJZm1SgZik6ICHaGWdmwXx+hjr3kM JwshaiUTjdoMgSbgk3eHmFnbNY+bgrfIpnkqzukqTL3jzt1FAKy8VVwojv+XlSZbkAU1HFLiZTV Uq6r4ct+Vyn95WQPwsKGCsYrrBHWyn246v0wiUP57hCpzZVAWqPxynzkFB6ypNoJamLOjLmslVM 6VKJQaO7jJCZYAjXT7zQIKAucGpt57Aq9ATBDbAPrsAtPqptlWGhVlp7BcY2bQnaelN/IMeyhZq D4CnhOpvSiRV8W3TITqowd1PUMSAqPZthYiGL7FNGlFv+9VtiTFxuNzNZuxxHmVK7q6TWVVwnZX PlFStVOQGZn2lALRUL73nXT7KVMBj/SGZnRqzmB4FKH6MxlXIPg4eNO1dccldEpyBw3QRAGAQto lcU0XMJAyOlHmwGPSA4gTgJEnYfw0EIOQlfJsDmh6AHBUleFxtXFRrOBJjjDxTKmwL25AgxhUwu CrHs0MIdjkx+ZpzXKCMLnRH3LCZuNEZvnAFZ70JPjzHZWle6DiEFQ8EMZQP7XGPtI6o2zWpvN4J hsLHnlQnYvrNqomPckVReUzad8mg385TFZ3fJW2SL0acpIav0lWP5nLnZjqtcZmZvaxb3QCJIH6 IU5hdpjTu9E8swhxP9zHz9OXuco5r/THRNVxXViWbyz5cHAVyPNUPtKGo9jVy/ZKzt/AKXGpEHL GnS70mCnxA38FDFuSIphWyxK0VswJUoKmJofqOMl3iupJHf8GlxH7vgXozZv0So5xJhlXPhLqp7 I4KdxnJr/jPaE2uB4VMlFQj2KFuhWywSN2d/5bFLTjP5jDJrxYudjgdaJblMiiMjMCncx4axNcV hZLo9Fgy86oVLeXH5zXOjg6rAUKMCrYOz46uQJGrRYKMh0zCs3sfKZkPX7AH5FpHxYyW985aVC4 ja/jacZUuFIFXJcDYsYTgEYHV8ZYkPTlkiLkpAYLJsDrwQGXWQ3jyPCVXWVLNxzLkKyjcbKUR2w WpFlqHegwnio2EsabcSUxBQHgwEm4dEDZptDsuZnJoJQqo0D2A2Xq/UZfxkoMX48/kANIlBWJnV mlQ9ggjFSjFmUptTki3uSroAA4lYFxfTb1bzmvcwCzHYMaTYyXYSjgne3nGlqGJu151FEUCADgO 1m5VvghDlVgZ0B9E9yQ+p6Lhyv7j6CCBOUDggThAKC3H2fGzsDTVobVE0I0MuUSrEBEVX6GimJI ABCaM1X5jxUUROKFLifqbtsZksrTlzw6b/eaWgSaJZ61QVqiomJFbslJW7tSANjTFjpbECJikuy gECE4naN4geJ2MGVQxu+2RA7FGi9zSDSbhRzUqgF1oFUCE8R5HZEBEiCCSythZQgTrf0ssQU4v6 sKcm+BEp7SwPBqFrcBCQvwSMWkASbVcvzUeqEhj7AVR9FQeS0jFssyDVFEujUIoeu7WsHCKRPoK V+rWb9YN6d4zygifgfhAy2rfQ4JoV8TQUjBIAnaU2sizGJHTmnMFVTAgU1soLciWUODqdCix3/T ZaVUQpX7uXP5HqVkkNbKaHZJe5izyxJBfCV7bQ9xg9u2njMHW+sBF7aRTGm6ODSUIvL0M2SCKiV wlS3VB3uQdV8VdBFbjiIUJ1hZYZE6m/oFArXXmreBF0TmVjxbYsXMTpMjmgqMxg/oSPhKlfWQJZ m1SgZik6ICHaGWdmwXx+hjr3kMJwshaiUTjdoMgSbgk3eHmFnbNY+bgrfIpnkqzukqTL3jzt1FA Ky8VVwojv+XlSZbkAU1HFLiZTVUq6r4ct+Vyn95WQPwsKGCsYrrBHWyn246v0wiUP57hCpzZVAW qPxynzkFB6ypNoJamLOjLmslVM6VKJQaO7jJCZYAjXT7zQIKAucGpt57Aq9ATBDbAPrsAtPqptl WGhVlp7BcY2bQnaelN/IMeyhZqD4CnhOpvSiRV8W3TITqowd1PUMSAqPZthYiGL7FNGlFv+9Vti TFxuNzNZuxxHmVK7q6TWVVwnZXPlFStVOQGZn2lALRUL73nXT7KVMBj/SGZnRqzmB4FKH6MxlXI Pg4eNO1dccldEpyBw3QRAGAQtolcU0XMJAyOlHmwGPSA4gTgJEnYfw0EIOQlfJsDmh6AHBUleFx tXFRrOBJjjDxTKmwL25AgxhUwuCrHs0MIdjkx+ZpzXKCMLnRH3LCZuNEZvnAFZ70JPjzHZWle6D iEFQ8EMZQP7XGPtI6o2zWpvN4JhsLHnlQnYvrNqomPckVReUzad8mg385TFZ3fJW2SL0acpIav0 lWP5nLnZjqtcZmZvaxb3QCJIH6IU5hdpjTu9E8swhxP9zHz9OXuco5r/THRNVxXViWbyz5cHAVy PNUPtKGo9jVy/ZKzt/AKXGpEHLGnS70mCnxA38FDFuSIphWyxK0VswJUoKmJofqOMl3iupJHf8G lxH7vgXozZv0So5xJhlXPhLqp7I4KdxnJr/jPaE2uB4VMlFQj2KFuhWywSN2d/5bFLTjP5jDJrx YudjgdaJblMiiMjMCncx4axNcVhZLo9Fgy86oVLeXH5zXOjg6rAUKMCrYOz46uQJGrRYKMh0zCs 3sfKZkPX7AH5FpHxYyW985aVC4ja/jacZUuFIFXJcDYsYTgEYHV8ZYkPTlkiLkpAYLJsDrwQGXW Q3jyPCVXWVLNxzLkKyjcbKUR2wWpFlqHegwnio2EsabcSUxBQHgwEm4dEDZptDsuZnJoJQqo0D2 A2Xq/UZfxkoMX48/kANIlBWJnVmlQ9ggjFSjFmUptTkiMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA wMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMA== -----END IBM-KYBER PRIVATE KEY----- -----BEGIN IBM-KYBER PUBLIC KEY----- MIIEvzAPBgsrBgEEAQKCCwUDAwUAA4IEqgAwggSlA4IEoQCgtx9nxs7A01aG1RNCNDLlEqxARFV +hopiSAAQmjNV+Y8VFETihS4n6m7bGZLK05c8Om/3mloEmiWetUFaoqJiRW7JSVu7UgDY0xY6Wx AiYpLsoBAhOJ2jeIHidjBlUMbvtkQOxRovc0g0m4Uc1KoBdaBVAhPEeR2RARIggksrYWUIE639L LEFOL+rCnJvgRKe0sDwaha3AQkL8EjFpAEm1XL81HqhIY+wFUfRUHktIxbLMg1RRLo1CKHru1rB wikT6Clfq1m/WDeneM8oIn4H4QMtq30OCaFfE0FIwSAJ2lNrIsxiR05pzBVUwIFNbKC3IllDg6n Qosd/02WlVEKV+7lz+R6lZJDWymh2SXuYs8sSQXwle20PcYPbtp4zB1vrARe2kUxpujg0lCLy9D NkgiolcJUt1Qd7kHVfFXQRW44iFCdYWWGROpv6BQK115q3gRdE5lY8W2LFzE6TI5oKjMYP6Ej4S pX1kCWZtUoGYpOiAh2hlnZsF8foY695DCcLIWolE43aDIEm4JN3h5hZ2zWPm4K3yKZ5Ks7pKky9 487dRQCsvFVcKI7/l5UmW5AFNRxS4mU1VKuq+HLflcp/eVkD8LChgrGK6wR1sp9uOr9MIlD+e4Q qc2VQFqj8cp85BQesqTaCWpizoy5rJVTOlSiUGju4yQmWAI10+80CCgLnBqbeewKvQEwQ2wD67A LT6qbZVhoVZaewXGNm0J2npTfyDHsoWag+Ap4Tqb0okVfFt0yE6qMHdT1DEgKj2bYWIhi+xTRpR b/vVbYkxcbjczWbscR5lSu6uk1lVcJ2Vz5RUrVTkBmZ9pQC0VC+9510+ylTAY/0hmZ0as5geBSh +jMZVyD4OHjTtXXHJXRKcgcN0EQBgELaJXFNFzCQMjpR5sBj0gOIE4CRJ2H8NBCDkJXybA5oegB wVJXhcbVxUazgSY4w8UypsC9uQIMYVMLgqx7NDCHY5Mfmac1ygjC50R9ywmbjRGb5wBWe9CT48x 2VpXug4hBUPBDGUD+1xj7SOqNs1qbzeCYbCx55UJ2L6zaqJj3JFUXlM2nfJoN/OUxWd3yVtki9G nKSGr9JVj+Zy52Y6rXGZmb2sW90AiSB+iFOYXaY07vRPLMIcT/cx8/Tl7nKOa/0x0TVcV1Ylm8s +XBwFcjzVD7ShqPY1cv2Ss7fwClxqRByxp0u9Jgp8QN/BQxbkiKYVssStFbMCVKCpiaH6jjJd4r qSR3/BpcR+74F6M2b9EqOcSYZVz4S6qeyOCncZya/4z2hNrgeFTJRUI9ihboVssEjdnf+WxS04z +Ywya8WLnY4HWiW5TIojIzAp3MeGsTXFYWS6PRYMvOqFS3lx+c1zo4OqwFCjAq2Ds+OrkCRq0WC jIdMwrN7HymZD1+wB+RaR8WMlvfOWlQuI2v42nGVLhSBVyXA2LGE4BGB1fGWJD05ZIi5KQGCybA 68EBl1kN48jwlV1lSzccy5Cso3GylEdsFqRZah3oMJ4qNhLGm3ElMQUB4MBJuHRA2abQ7LmZyaC UKqNA9gNl6v1GX8ZKDF+PP5ADSJQViZ1ZpUPYIIxUoxZlKbU5Ig== -----END IBM-KYBER PUBLIC KEY----- opencryptoki-opencryptoki-451d99c/testcases/misc_tests/migration.sh000077500000000000000000000065721520105705100260410ustar00rootroot00000000000000#!/bin/bash # # 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 # - Requires p11tool (gnutls) and pkcs11-tool (opensc). # - The PKCSLIB environment must point to your system's libopencryptoki.so. # - The PKCS11_SO_PIN environment variable must hold the SO pin. # - The PKCS11_USER_PIN environment variable must hold the user pin. # - The OCK_CONFDIR environment variable must point to your system's openCryptoki configuration directory. # - The OCK_DATASTORE environment variable must point to the token's datastore directory. # - The SLOT environment variable must hold the slot id of the token under test. # - The PKCS11_TOKEN_URL environment variable must hold the the token url of the token under test. # # sodo -E ./migrate.sh set -x # tmp files PKCSCONF_PRE=pkcsconf-pre.out PKCSCONF_POST=pkcsconf-post.out P11TOOL_PRE=p11tool-pre.out P11TOOL_POST=p11tool-post.out PKCS11_TOOL_PRE=pkcs11-tool-pre.out PKCS11_TOOL_POST=pkcs11-tool-post.out P11SAK_PRE=p11sak-pre.out P11SAK_POST=p11sak-post.out # set p11tool env vars export GNUTLS_SO_PIN=$PKCS11_SO_PIN export GNUTLS_PIN=$PKCS11_USER_PIN # generate objects p11tool --provider=$PKCSLIB --login --generate-rsa --bits 2048 --label p11tool-rsa "$PKCS11_TOKEN_URL" pkcs11-tool --module=$PKCSLIB --slot $SLOT --login --pin $PKCS11_USER_PIN --keypairgen --key-type rsa:2048 --label pkcs11-tool-rsa p11sak generate-key rsa 2048 --slot $SLOT --pin $PKCS11_USER_PIN --label p11sak-rsa # list slots/tokens pkcsconf -i &>> $PKCSCONF_PRE pkcsconf -s &>> $PKCSCONF_PRE pkcsconf -t &>> $PKCSCONF_PRE p11tool --provider=$PKCSLIB --list-tokens &>> $P11TOOL_PRE pkcs11-tool --module=$PKCSLIB --list-slots &>> $PKCS11_TOOL_PRE # list objects p11tool --provider=$PKCSLIB --list-all "$PKCS11_TOKEN_URL" &>> $P11TOOL_PRE p11tool --provider=$PKCSLIB --list-all --login "$PKCS11_TOKEN_URL" &>> $P11TOOL_PRE pkcs11-tool --module=$PKCSLIB --slot $SLOT -list-objects &>> $PKCS11_TOOL_PRE pkcs11-tool --module=$PKCSLIB --slot $SLOT --login --pin $PKCS11_USER_PIN --list-objects &>> $PKCS11_TOOL_PRE p11sak list-key rsa --slot $SLOT --pin $PKCS11_USER_PIN &>> $P11SAK_PRE # migrate killall pkcsslotd echo -e "y\n" | pkcstok_migrate --verbose debug --slot $SLOT --sopin $PKCS11_SO_PIN --userpin $PKCS11_USER_PIN --confdir $OCK_CONFDIR --datastore $OCK_DATASTORE pkcsslotd # list slots/tokens pkcsconf -i &>> $PKCSCONF_POST pkcsconf -s &>> $PKCSCONF_POST pkcsconf -t &>> $PKCSCONF_POST p11tool --provider=$PKCSLIB --list-tokens &>> p11tool-post.out pkcs11-tool --module=$PKCSLIB --list-slots &>> pkcs11-tool-post.out # list objects p11tool --provider=$PKCSLIB --list-all "$PKCS11_TOKEN_URL" &>> $P11TOOL_POST p11tool --provider=$PKCSLIB --list-all --login "$PKCS11_TOKEN_URL" &>> $P11TOOL_POST pkcs11-tool --module=$PKCSLIB --slot $SLOT -list-objects &>> $PKCS11_TOOL_POST pkcs11-tool --module=$PKCSLIB --slot $SLOT --login --pin $PKCS11_USER_PIN --list-objects &>> $PKCS11_TOOL_POST p11sak list-key rsa --slot $SLOT --pin $PKCS11_USER_PIN &>> $P11SAK_POST # compare cmp $PKCSCONF_PRE $PKCSCONF_POST cmp $P11TOOL_PRE $P11TOOL_POST cmp $PKCS11_TOOL_PRE $PKCS11_TOOL_POST cmp $P11SAK_PRE $P11SAK_POST opencryptoki-opencryptoki-451d99c/testcases/misc_tests/misc_tests.mk000066400000000000000000000137361520105705100262170ustar00rootroot00000000000000noinst_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/tok2tok_transport \ testcases/misc_tests/obj_lock testcases/misc_tests/reencrypt \ testcases/misc_tests/cca_ep11_export_import_test \ testcases/misc_tests/events testcases/misc_tests/dual_functions \ testcases/misc_tests/always_auth EXTRA_DIST += testcases/misc_tests/dh-key.pem \ testcases/misc_tests/dsa-key.pem \ testcases/misc_tests/dsa-param.pem \ testcases/misc_tests/ec-key-prime256v1.pem \ testcases/misc_tests/ec-key-secp521r1.pem \ testcases/misc_tests/ed25519-private-key.pem \ testcases/misc_tests/ed25519-public-key.pem \ testcases/misc_tests/ed448-private-key.pem \ testcases/misc_tests/ed448-public-key.pem \ testcases/misc_tests/x25519-private-key.pem \ testcases/misc_tests/x25519-public-key.pem \ testcases/misc_tests/x448-private-key.pem \ testcases/misc_tests/x448-public-key.pem \ testcases/misc_tests/ibm-dilithium-r2-65-key.pem \ testcases/misc_tests/ibm-dilithium-r3-65-key.pem \ testcases/misc_tests/ibm-kyber-r2-768-key.pem \ testcases/misc_tests/p11sak_dsa3072cert.pem \ testcases/misc_tests/p11sak_dsa4096cert.pem \ testcases/misc_tests/p11sak_ecp256cert.pem \ testcases/misc_tests/p11sak_ecp384cert.pem \ testcases/misc_tests/p11sak_ecp521cert.pem \ testcases/misc_tests/p11sak_rsa2048cert.pem \ testcases/misc_tests/p11sak_rsa4096cert.pem \ testcases/misc_tests/p11sak_ed25519cert.pem \ testcases/misc_tests/p11sak_ed448cert.pem \ testcases/misc_tests/rsa-key.pem \ testcases/misc_tests/aes.key \ testcases/misc_tests/p11sak_dsa3072cert.crt \ testcases/misc_tests/p11sak_dsa4096cert.crt \ testcases/misc_tests/p11sak_ecp256cert.crt \ testcases/misc_tests/p11sak_ecp384cert.crt \ testcases/misc_tests/p11sak_ecp521cert.crt \ testcases/misc_tests/p11sak_rsa2048cert.crt \ testcases/misc_tests/p11sak_rsa4096cert.crt \ testcases/misc_tests/p11sak_ed25519cert.crt \ testcases/misc_tests/p11sak_ed448cert.crt \ testcases/misc_tests/migration.sh \ testcases/misc_tests/p11sak_test.sh \ testcases/misc_tests/pkcsconf_test.sh \ testcases/misc_tests/spinlock_tests.sh \ testcases/misc_tests/spinlock_child.sh 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 testcases_misc_tests_tok2tok_transport_CFLAGS = ${testcases_inc} testcases_misc_tests_tok2tok_transport_LDADD = testcases/common/libcommon.la testcases_misc_tests_tok2tok_transport_SOURCES = \ testcases/misc_tests/tok2tok_transport.c testcases_misc_tests_reencrypt_CFLAGS = ${testcases_inc} testcases_misc_tests_reencrypt_LDADD = testcases/common/libcommon.la testcases_misc_tests_reencrypt_SOURCES = \ testcases/misc_tests/reencrypt.c testcases_misc_tests_cca_ep11_export_import_test_CFLAGS = ${testcases_inc} testcases_misc_tests_cca_ep11_export_import_test_LDADD = \ testcases/common/libcommon.la testcases_misc_tests_cca_ep11_export_import_test_SOURCES = \ testcases/misc_tests/cca_ep11_export_import_test.c testcases_misc_tests_events_CFLAGS = ${testcases_inc} testcases_misc_tests_events_LDADD = testcases/common/libcommon.la testcases_misc_tests_events_SOURCES = testcases/misc_tests/events.c \ usr/lib/common/event_client.c testcases_misc_tests_dual_functions_CFLAGS = ${testcases_inc} testcases_misc_tests_dual_functions_LDADD = testcases/common/libcommon.la testcases_misc_tests_dual_functions_SOURCES = \ testcases/misc_tests/dual_functions.c testcases_misc_tests_always_auth_CFLAGS = ${testcases_inc} testcases_misc_tests_always_auth_LDADD = testcases/common/libcommon.la testcases_misc_tests_always_auth_SOURCES = \ testcases/misc_tests/always_auth.c opencryptoki-opencryptoki-451d99c/testcases/misc_tests/multi_instance.c000066400000000000000000000351531520105705100266700ustar00rootroot00000000000000/* * 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 "pkcs11types.h" #include "regress.h" 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; if (i >= argc) { printf("Slot number missing\n"); return -1; } slot_id1 = atoi(argv[i]); } else if (strcmp(argv[i], "-slot2") == 0) { ++i; if (i >= argc) { printf("Slot number missing\n"); return -1; } 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(); 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-2048-SLOT1", 2048, &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-2048-SLOT2", 2048, &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-2048-SLOT1") == 0) { testcase_pass("C_GetAttributeValue for hPubKey2 on slot %lu got our object", slot_id1); } else if (strcmp((char *)label, "RSA-2048-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-2048-SLOT2") == 0) { testcase_pass("C_GetAttributeValue for hPubKey2 on slot %lu got our object", slot_id2); } else if (strcmp((char *)label, "RSA-2048-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-2048-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-2048-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 testcase_return(ret); } opencryptoki-opencryptoki-451d99c/testcases/misc_tests/obj_lock.c000066400000000000000000000310071520105705100254260ustar00rootroot00000000000000/* * 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 "pkcs11types.h" #include "regress.h" #include "common.c" 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_notice("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_notice("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_BBOOL extractable) { CK_CHAR label[] = "OBJ_LOCK_TEST_KEY"; CK_BYTE id[100] = { 0 }; CK_ATTRIBUTE key_gen_tmpl[] = { {CKA_EXTRACTABLE, &extractable, sizeof(CK_BBOOL)}, {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, 5, 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; } else if (strcmp(argv[k], "-pkey") == 0) { pkey = TRUE; } if (strcmp(argv[k], "-h") == 0) { printf("usage: %s [-slot ] [-usage-threads ] [-alter-threads ] [-token_obj] [-reuse_obj] [-keep_obj] [-pkey] [-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(); 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"); if (pkey) { /* * The pkey parm makes the test key non-extractable and therefore * eligible for protected key support in tokens supporting protected * keys (currently only ep11). Protected key support heavily depends * on the PKEY_MODE token option, so check your token config file * before using this test option. */ if (!is_ep11_token(SLOT_ID)) { testcase_notice("Slot %lu doesn't support protected keys.", SLOT_ID); goto close_session; } else { testcase_notice("Check your token config file."); testcase_notice("Protected key support depends on the PKEY_MODE token option."); } } 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, !pkey); 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 for (i = 0; i < num_usage_threads; i++) { testcase_new_assertion(); pthread_create(&id[i], NULL, (void *(*)(void *)) usage_thread_func, (void *)&h_key); testcase_pass("Creating usage thread %lu\n", i); } // create the alter threads for (i = 0; i < num_alter_threads; i++) { testcase_new_assertion(); pthread_create(&id[num_usage_threads + i], NULL, (void *(*)(void *)) alter_thread_func, (void *)&h_key); testcase_pass("Creating alter thread %lu\n", i); } // wait for all threads to end for (i = 0; i < num_usage_threads + num_alter_threads; i++) { pthread_join(id[i], NULL); } testcase_notice("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 testcase_return(rv); } opencryptoki-opencryptoki-451d99c/testcases/misc_tests/obj_mgmt.c000066400000000000000000001601101520105705100254400ustar00rootroot00000000000000/* * 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..."); testcase_new_assertion(); 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) { if (is_rejected_by_policy(rc, h_session)) { testcase_skip("Key import is not allowed by policy"); funcs->C_CloseAllSessions(slot_id); return 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) { if (is_rejected_by_policy(rc, h_session)) { testcase_skip("Key import is not allowed by policy"); funcs->C_CloseAllSessions(slot_id); return 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) { if (is_rejected_by_policy(rc, h_session)) { testcase_skip("Key import is not allowed by policy"); funcs->C_CloseAllSessions(slot_id); return 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, h_data2; CK_OBJECT_CLASS data_class = CKO_DATA; CK_BYTE data_label[] = "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)} }; /* Invalid: coannot set CKA_UNIQUE_ID */ CK_ATTRIBUTE data_attribs2[] = { {CKA_CLASS, &data_class, sizeof(data_class)}, {CKA_TOKEN, &false, sizeof(false)}, {CKA_VALUE, &data_value, sizeof(data_value)}, {CKA_UNIQUE_ID, &data_value, sizeof(data_value)} }; CK_OBJECT_HANDLE h_copy; CK_ATTRIBUTE copy_attribs[] = { {CKA_LABEL, &data_label, sizeof(data_label)} }; CK_BYTE buf1[100]; CK_ATTRIBUTE verify_attribs[] = { {CKA_LABEL, &buf1, sizeof(buf1)} }; CK_BYTE buf2[100]; CK_ATTRIBUTE prime_attribs[] = { {CKA_PRIME, &buf2, sizeof(buf2)} }; CK_BYTE buf3[100]; CK_ATTRIBUTE unique_id_attribs[] = { {CKA_UNIQUE_ID, &buf3, sizeof(buf3)} }; CK_BYTE buf4[100]; CK_ATTRIBUTE unique_id_attribs2[] = { {CKA_UNIQUE_ID, &buf4, sizeof(buf4)} }; testcase_begin("starting..."); testcase_new_assertion(); if (get_user_pin(user_pin)) { testcase_fail("Cannot get 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) { if (is_rejected_by_policy(rc, h_session)) { testcase_skip("Key import is not allowed by policy"); return CKR_OK; } testcase_fail("C_CreateObject() rc = %s", p11_get_ckr(rc)); return rc; } /* try to create invalid object */ rc = funcs->C_CreateObject(h_session, data_attribs2, 4, &h_data2); if (rc != CKR_ATTRIBUTE_READ_ONLY) { if (is_rejected_by_policy(rc, h_session)) { testcase_skip("Key import is not allowed by policy"); return 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_label, verify_attribs[0].pValue, sizeof(data_label)) != 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; } /* try to extract the CKA_UNIQUE_ID attribute from the original */ unique_id_attribs[0].ulValueLen = sizeof(buf3); rc = funcs->C_GetAttributeValue(h_session, h_data, unique_id_attribs, 1); if (rc != CKR_OK) { testcase_fail("C_GetAttributeValue() rc=%s", p11_get_ckr(rc)); return rc; } /* now, try to extract the CKA_UNIQUE_IDattribute from the copy */ unique_id_attribs2[0].ulValueLen = sizeof(buf4); rc = funcs->C_GetAttributeValue(h_session, h_copy, unique_id_attribs2, 1); if (rc != CKR_OK) { testcase_fail("C_GetAttributeValue() rc=%s", p11_get_ckr(rc)); return rc; } if (memcmp(unique_id_attribs[0].pValue, unique_id_attribs2[0].pValue, 64) == 0) { testcase_fail("unique id attributes match"); return -1; } /* 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_BYTE unique_id[] = "deadbeef"; 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)} }; /* Invalid: update CKA_UNIQUE_ID */ CK_ATTRIBUTE update_attr2[] = { {CKA_UNIQUE_ID, &unique_id, sizeof(unique_id)} }; 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..."); testcase_new_assertion(); if (get_user_pin(user_pin)) { testcase_fail("Cannot get 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) { if (is_rejected_by_policy(rc, h_session)) { testcase_skip("Key import is not allowed by policy"); return CKR_OK; } testcase_fail("C_CreateObject() rc = %s", p11_get_ckr(rc)); return rc; } /* Try to change the CKA_UNIQUE_ID */ rc = funcs->C_SetAttributeValue(h_session, h_cert, update_attr2, 1); if (rc != CKR_ATTRIBUTE_READ_ONLY) { testcase_fail("C_SetAttributeValue() 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..."); testcase_new_assertion(); if (get_user_pin(user_pin)) { testcase_fail("Cannot get 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) { if (is_rejected_by_policy(rc, h_session)) { testcase_skip("Key import is not allowed by policy"); return 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) { if (is_rejected_by_policy(rc, h_session)) { testcase_skip("Key import is not allowed by policy"); return 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) { if (is_rejected_by_policy(rc, h_session)) { testcase_skip("Key import is not allowed by policy"); return 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 %lu 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 %lu 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 %lu instead of %lu 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_skip("Skipping tests that create token objects"); return CKR_OK; } testcase_new_assertion(); if (get_user_pin(user_pin)) { testcase_fail("Cannot get 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) { if (is_rejected_by_policy(rc, h_session)) { testcase_skip("Key import is not allowed by policy"); return 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) { if (is_rejected_by_policy(rc, h_session)) { testcase_skip("Key import is not allowed by policy"); return 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) { if (is_rejected_by_policy(rc, h_session)) { testcase_skip("Key import is not allowed by policy"); return 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 %lu 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 %lu 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 %lu 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 %lu 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 %lu 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 %lu 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 %lu 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_skip("Skipping tests that create token objects"); return CKR_OK; } slot_id = SLOT_ID; testcase_begin("starting..."); testcase_new_assertion(); if (get_user_pin(user_pin)) { testcase_fail("Cannot get 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) { if (is_rejected_by_policy(rc, h_session)) { testcase_skip("Key import is not allowed by policy"); return 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) { if (is_rejected_by_policy(rc, h_session)) { testcase_skip("Key import is not allowed by policy"); return 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) { if (is_rejected_by_policy(rc, h_session)) { testcase_skip("Key import is not allowed by policy"); return CKR_OK; } 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) { if (is_rejected_by_policy(rc, h_session)) { testcase_skip("Key import is not allowed by policy"); return 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 %lu 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 %lu 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) { rc = -1; testcase_fail("found the wrong object handles"); 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: /* 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 */ loc_rc = funcs->C_CloseSession(h_session); if (loc_rc != CKR_OK) testcase_error("C_CloseSession() rc = %s", p11_get_ckr(loc_rc)); done: return rc; } /* * do_ProfileSearch Test: */ CK_RV do_ProfileSearch(void) { unsigned int i; CK_RV rc, loc_rc; CK_ULONG find_count; CK_SLOT_ID slot_id; CK_SESSION_HANDLE h_session = CK_INVALID_HANDLE; CK_BYTE user_pin[PKCS11_MAX_PIN_LEN] = {0}; CK_ULONG user_pin_len = 0; /* profile object 1 */ CK_OBJECT_CLASS profile1_class = CKO_PROFILE; CK_PROFILE_ID profile1_profile_id = CKP_BASELINE_PROVIDER; CK_ATTRIBUTE profile1_template[] = { {CKA_CLASS, &profile1_class, sizeof(profile1_class)}, {CKA_PROFILE_ID, &profile1_profile_id, sizeof(profile1_profile_id)}, }; /* profile object 2 */ CK_OBJECT_CLASS profile2_class = CKO_PROFILE; CK_ATTRIBUTE profile2_template[] = { {CKA_CLASS, &profile2_class, sizeof(profile2_class)}, }; CK_OBJECT_HANDLE h_obj1 = 0, h_obj2 = 0, obj_list[10] = {0}; CK_ATTRIBUTE find_tmpl[] = { {CKA_CLASS, &profile1_class, sizeof(profile1_class)} }; CK_ATTRIBUTE find_tmpl2[] = { {CKA_CLASS, &profile1_class, sizeof(profile1_class)}, {CKA_PROFILE_ID, &profile1_profile_id, sizeof(profile1_profile_id)} }; if (skip_token_obj == TRUE) { testcase_skip("Skipping tests that create token objects"); return CKR_OK; } slot_id = SLOT_ID; testcase_begin("starting..."); testcase_new_assertion(); 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 2 test objects */ rc = funcs->C_CreateObject(h_session, profile1_template, 2, &h_obj1); if (rc != CKR_OK) { if (is_rejected_by_policy(rc, h_session)) { testcase_skip("Key import is not allowed by policy"); return CKR_OK; } testcase_fail("C_CreateObject() rc = %s", p11_get_ckr(rc)); return rc; } rc = funcs->C_CreateObject(h_session, profile2_template, 1, &h_obj2); if (rc != CKR_OK) { if (is_rejected_by_policy(rc, h_session)) { testcase_skip("Key import is not allowed by policy"); return CKR_OK; } testcase_fail("C_CreateObject() rc = %s", p11_get_ckr(rc)); goto destroy_1; } // Now find the profile 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 != 2) { testcase_fail("found %lu 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_obj1 && obj_list[i] != h_obj2) { 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)); } // Now find only the first profile object rc = funcs->C_FindObjectsInit(h_session, find_tmpl2, 2); 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 %lu 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_obj1) { 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: 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(void) { 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_ProfileSearch(); 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; } testcase_setup(); rv = obj_mgmt_functions(); testcase_print_result(); return testcase_return(rv); } opencryptoki-opencryptoki-451d99c/testcases/misc_tests/obj_mgmt_lock.c000066400000000000000000001235521520105705100264610ustar00rootroot00000000000000/* * 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..."); testcase_new_assertion(); 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) { if (is_rejected_by_policy(rc, h_session)) { testcase_skip("Key import is not allowed by policy"); rc = CKR_OK; goto done; } 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) { if (is_rejected_by_policy(rc, h_session)) { testcase_skip("Key import is not allowed by policy"); rc = CKR_OK; goto done; } 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_label[] = "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_LABEL, &data_label, sizeof(data_label)} }; CK_BYTE buf1[100]; CK_ATTRIBUTE verify_attribs[] = { {CKA_LABEL, &buf1, sizeof(buf1)} }; CK_BYTE buf2[100]; CK_ATTRIBUTE prime_attribs[] = { {CKA_PRIME, &buf2, sizeof(buf2)} }; testcase_begin("starting..."); testcase_new_assertion(); 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) { if (is_rejected_by_policy(rc, h_session)) { testcase_skip("Key import is not allowed by policy"); rc = CKR_OK; goto done; } 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_label, verify_attribs[0].pValue, sizeof(data_label)) != 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..."); testcase_new_assertion(); 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) { if (is_rejected_by_policy(rc, h_session)) { testcase_skip("Key import is not allowed by policy"); rc = CKR_OK; goto done; } 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..."); testcase_new_assertion(); 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) { if (is_rejected_by_policy(rc, h_session)) { testcase_skip("Key import is not allowed by policy"); rc = CKR_OK; goto done; } 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) { if (is_rejected_by_policy(rc, h_session)) { testcase_skip("Key import is not allowed by policy"); rc = CKR_OK; goto done; } 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) { if (is_rejected_by_policy(rc, h_session)) { testcase_skip("Key import is not allowed by policy"); rc = CKR_OK; goto done; } 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 %lu 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..."); testcase_new_assertion(); 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) { if (is_rejected_by_policy(rc, h_session)) { testcase_skip("Key import is not allowed by policy"); rc = CKR_OK; goto done; } 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) { if (is_rejected_by_policy(rc, h_session)) { testcase_skip("Key import is not allowed by policy"); rc = CKR_OK; goto done; } 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) { if (is_rejected_by_policy(rc, h_session)) { testcase_skip("Key import is not allowed by policy"); rc = CKR_OK; goto done; } 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 %lu 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 %lu 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..."); testcase_new_assertion(); 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) { if (is_rejected_by_policy(rc, h_session)) { testcase_skip("Key import is not allowed by policy"); rc = CKR_OK; goto session_close; } 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) { if (is_rejected_by_policy(rc, h_session)) { testcase_skip("Key import is not allowed by policy"); rc = CKR_OK; goto destroy_1; } 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) { if (is_rejected_by_policy(rc, h_session)) { testcase_skip("Key import is not allowed by policy"); rc = CKR_OK; goto destroy_2; } 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) { if (is_rejected_by_policy(rc, h_session)) { testcase_skip("Key import is not allowed by policy"); rc = CKR_OK; goto destroy_2; } 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 correct 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(void) { 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; } testcase_setup(); rv = obj_mgmt_functions(); testcase_print_result(); return testcase_return(rv); } opencryptoki-opencryptoki-451d99c/testcases/misc_tests/p11kmip_test.sh000077500000000000000000001033631520105705100263650ustar00rootroot00000000000000#!/bin/bash # # 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 # sudo -E ./p11kmip_test.sh # In order to invoke this test script, the following required environment variables # must be specified: # - PKCS11_USER_PIN : the user PIN number for the chosen PKCS#11 slot (default slot 30) # - PKCSLIB : path to the PKCS#11 library # - KMIP_IP : the IP address of the KMIP server to use for testing # - KMIP_REST_USER : the username to use for authenticating to the # KMIP server REST interface # - KMIP_REST_PASSWORD : the password to use for authenticating to the # KMIP server REST inferface # # Additionally, the following optional environment variables may be specified to # override certain default values: # - PKCS11_SLOT_ID : the PKCS#11 slot number to use for testing. Defaults to 30. # - KMIP_REST_URL : the fully-qualified URL to use for the KMIP server REST # interface. Defaults to https://${KMIP_IP}:19443 # - KMIP_HOSTNAME : the hostname to be used for the KMIP protocol connection. # Defaults to ${KMIP_IP}:5696 DIR=$(dirname "$0") status=0 # Validate required environment variables if [[ -z "${PKCS11_USER_PIN}" ]]; then echo "Please set the PKCS11_USER_PIN environment variable" exit 1 fi if [[ -z "${PKCSLIB}" ]]; then echo "Please set the PKCSLIB environment variable" exit 1 fi if [[ -z "${KMIP_IP}" ]]; then echo "Please set the KMIP_IP environment variable" exit 1 fi if [[ -z "${KMIP_REST_USER}" ]]; then echo "Please set the KMIP_REST_USER environment variable" exit 1 fi if [[ -z "${KMIP_REST_PASSWORD}" ]]; then echo "Please set the KMIP_REST_PASSWORD environment variable" exit 1 fi echo "** Now executing 'p11kmip_test.sh'" P11KMIP_TMP="/tmp/p11kmip" P11KMIP_UNIQUE_NAME="$(uname -n)-$(date +%s)" P11KMIP_UNIQUE_NAME="${P11KMIP_UNIQUE_NAME^^}" KMIP_CLIENT_NAME="$(echo ${P11KMIP_UNIQUE_NAME^^} | sed -r 's/[ .,;:#+*$%-]+/_/g')_CLIENT" KMIP_CERT_ALIAS="$(echo ${P11KMIP_UNIQUE_NAME^^} | sed -r 's/[ .,;:#+*$%-]+/_/g')_CERT" KMIP_SECRET_KEY_LABEL="remote-secret-key-${P11KMIP_UNIQUE_NAME}" PKCS11_SECRET_KEY_LABEL="local-secret-key-${P11KMIP_UNIQUE_NAME}" PKCS11_PUBLIC_KEY_LABEL="local-public-key-${P11KMIP_UNIQUE_NAME}" PKCS11_PRIVATE_KEY_LABEL="local-private-key-${P11KMIP_UNIQUE_NAME}" P11KMIP_CONF_FILE="${P11KMIP_TMP}/p11kmip.conf" # Prepare PKCS11 variables echo "** Setting SLOT=30 to the Softtoken unless otherwise set - 'p11kmip_test.sh'" PKCS11_SLOT_ID=${PKCS11_SLOT_ID:-30} echo "** Using Slot $PKCS11_SLOT_ID with PKCS11_USER_PIN $PKCS11_USER_PIN and PKCSLIB $PKCSLIB - 'p11kmip_test.sh'" # Prepare KMIP variables echo "** Setting KMIP_REST_URL=https://\${KMIP_IP}:19443 unless otherwise set - 'p11kmip_test.sh'" echo "** Setting KMIP_SERVER=\${KMIP_IP}:5696 unless otherwise set - 'p11kmip_test.sh'" KMIP_REST_URL="${KMIP_REST_URL:-https://${KMIP_IP}:19443}" KMIP_HOSTNAME="${KMIP_SERVER:-${KMIP_IP}:5696}" echo "Dirpath: $DIR" KMIP_CLIENT_CERT=$P11KMIP_TMP/${P11KMIP_UNIQUE_NAME}_p11kmip_client_cert.pem KMIP_CLIENT_KEY=$P11KMIP_TMP/${P11KMIP_UNIQUE_NAME}_p11kmip_client_key.pem echo "** Using KMIP server $KMIP_REST_URL with KMIP_REST_USER $KMIP_REST_USER and KMIP_REST_PASSWORD ************" mkdir -p $P11KMIP_TMP generate_certificates() { openssl req -x509 -newkey rsa:4096 -keyout "$KMIP_CLIENT_KEY" -out "$KMIP_CLIENT_CERT" -nodes -days 3650 -subj '/CN=www.mydom.com/O=My Company Name LTD./C=US' } setup_kmip_client() { RETRY_COUNT=0 UPLOAD_CERT_DONE=0 CREATE_CLIENT_DONE=0 ASSIGN_CERT_DONE=0 while true; do if [[ $RETRY_COUNT -gt 100 ]] ; then RC=1 echo "error: Too many login retries" break fi RETRY_COUNT=$((RETRY_COUNT+1)) # Get a login authorization ID from SKLM curl --fail-with-body --location --request POST "$KMIP_REST_URL/SKLM/rest/v1/ckms/login" \ --header "Content-Type: application/json" \ --data "{\"userid\":\"$KMIP_REST_USER\", \"password\":\"$KMIP_REST_PASSWORD\"}" \ --insecure --silent --show-error >$P11KMIP_TMP/curl_get_login_authid_stdout 2>$P11KMIP_TMP/curl_get_login_authid_stderr RC=$? echo "rc:" $RC if [[ $RC -ne 0 ]] ; then RC=1 cat $P11KMIP_TMP/curl_get_login_authid_stdout cat $P11KMIP_TMP/curl_get_login_authid_stderr break fi # Parse the response data and extract the authorization id token # Expected to return: {"UserAuthId":"xxxxxx"} AUTHID=`jq .UserAuthId $P11KMIP_TMP/curl_get_login_authid_stdout -r` echo "AuthID:" $AUTHID echo "succeeded: curl_get_login_authid" # Upload the client certificate to SKLM if [[ $UPLOAD_CERT_DONE -eq 0 ]] ; then curl --fail-with-body --location --request POST "$KMIP_REST_URL/SKLM/rest/v1/filetransfer/upload/objectfiles" \ --header "accept: application/json" --header "Content-Type: multipart/form-data" \ --form "fileToUpload=@$KMIP_CLIENT_CERT" --form "destination=" --header "Authorization:SKLMAuth userAuthId=$AUTHID" \ --insecure --silent --show-error >$P11KMIP_TMP/curl_upload_cert_stdout 2>$P11KMIP_TMP/curl_upload_cert_stderr RC=$? echo "rc:" $RC # Expected to return: {"code":"0","status":"CTGKM3465I File xxxx is uploaded.","messageId":"CTGKM3465I"} RSN=`jq .code $P11KMIP_TMP/curl_upload_cert_stdout -r` MSG=`jq .status $P11KMIP_TMP/curl_upload_cert_stdout -r` if [[ "$RSN" == "CTGKM6004E" ]]; then echo "warning: Login token expired, re-login and retry" continue fi if [[ "$MSG" == "CTGKM3466E Cannot upload the file $(basename $KMIP_CLIENT_CERT) because a file with the same name already exists on the server." ]]; then RC=1 echo "info: Client certificate already uploaded to server" break fi if [[ "$MSG" != "CTGKM3465I File $(basename $KMIP_CLIENT_CERT) is uploaded." ]]; then RC=1 echo "error: Status not as expected" cat $P11KMIP_TMP/curl_upload_cert_stdout cat $P11KMIP_TMP/curl_upload_cert_stderr break fi UPLOAD_CERT_DONE=1 echo "succeeded: curl_upload_cert" fi # Create a client in SKLM if [[ $CREATE_CLIENT_DONE -eq 0 ]] ; then echo "clientname:" $KMIP_CLIENT_NAME curl --fail-with-body --location --request POST "$KMIP_REST_URL/SKLM/rest/v1/clients" \ --header "Content-Type: application/json" \ --data "{\"clientName\":\"$KMIP_CLIENT_NAME\"}" \ --header "Authorization:SKLMAuth userAuthId=$AUTHID" \ --insecure --silent --show-error >$P11KMIP_TMP/curl_create_client_stdout 2>$P11KMIP_TMP/curl_create_client_stderr RC=$? echo "rc:" $RC # Expected to return: {"message":"CTGKM3411I Successfully created client xxxx .","messageId":"CTGKM3411I"} MSG=`jq .message $P11KMIP_TMP/curl_create_client_stdout -r` if [[ "$MSG" == "CTGKM6004E User is not authenticated or has already logged out." ]]; then echo "warning: Login token expired, re-login and retry" continue fi if [[ "$MSG" != "CTGKM3411I Successfully created client $KMIP_CLIENT_NAME ." ]]; then RC=1 echo "error: Message not as expected" cat $P11KMIP_TMP/curl_create_client_stdout cat $P11KMIP_TMP/curl_create_client_stderr break fi CREATE_CLIENT_DONE=1 echo "succeeded: curl_create_client" fi # Assign the certificate with the client if [[ $ASSIGN_CERT_DONE -eq 0 ]] ; then curl --fail-with-body --location --request PUT "$KMIP_REST_URL/SKLM/rest/v1/clients/$KMIP_CLIENT_NAME/assignCertificate" \ --header "Content-Type: application/json" \ --data "{\"certUseOption\":\"IMPORT_CERT\",\"certAlias\":\"$KMIP_CERT_ALIAS\",\"importPath\":\"$(basename $KMIP_CLIENT_CERT)\"}" \ --header "Authorization:SKLMAuth userAuthId=$AUTHID" \ --insecure --silent --show-error >$P11KMIP_TMP/curl_assign_cert_stdout 2>$P11KMIP_TMP/curl_assign_cert_stderr RC=$? echo "rc:" $RC # Expected to return: {"message":"CTGKM3409I Successfully assigned certificate to client.","messageId":"CTGKM3409I"} MSG=`jq .message $P11KMIP_TMP/curl_assign_cert_stdout -r` if [[ "$MSG" == "CTGKM6004E User is not authenticated or has already logged out." ]]; then echo "warning: Login token expired, re-login and retry" continue fi if [[ "$MSG" != "CTGKM3409I Successfully assigned certificate to client." ]]; then RC=1 echo "error: Message not as expected" cat $P11KMIP_TMP/curl_assign_cert_stdout cat $P11KMIP_TMP/curl_assign_cert_stderr break fi ASSIGN_CERT_DONE=1 echo "succeeded: curl_assign_cert" fi break done } setup_pkcs11_keys() { # AES key for exporting p11sak import-key aes --slot $PKCS11_SLOT_ID --pin $PKCS11_USER_PIN --label "$PKCS11_SECRET_KEY_LABEL-conf" --file $DIR/aes.key --attr sX RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) p11sak import-key aes --slot $PKCS11_SLOT_ID --pin $PKCS11_USER_PIN --label "$PKCS11_SECRET_KEY_LABEL-conf.2" --file $DIR/aes-128.key --attr sX RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) p11sak import-key aes --slot $PKCS11_SLOT_ID --pin $PKCS11_USER_PIN --label "$PKCS11_SECRET_KEY_LABEL-conf.3" --file $DIR/aes-192.key --attr sX RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) p11sak import-key aes --slot $PKCS11_SLOT_ID --pin $PKCS11_USER_PIN --label "$PKCS11_SECRET_KEY_LABEL-env" --file $DIR/aes.key --attr sX RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) p11sak import-key aes --slot $PKCS11_SLOT_ID --pin $PKCS11_USER_PIN --label "$PKCS11_SECRET_KEY_LABEL-opt" --file $DIR/aes.key --attr sX RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) # RSA keys for wrapping and importing p11sak import-key rsa private --slot $PKCS11_SLOT_ID --pin $PKCS11_USER_PIN --label $PKCS11_PRIVATE_KEY_LABEL --file $DIR/rsa-key.pem --attr sX RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) p11sak import-key rsa public --slot $PKCS11_SLOT_ID --pin $PKCS11_USER_PIN --label $PKCS11_PUBLIC_KEY_LABEL --file $DIR/rsa-key.pem --attr sX RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) echo "*** pkcs11 keys after import" p11sak list-key --slot $PKCS11_SLOT_ID --pin $PKCS11_USER_PIN } cleanup_pkcs11_keys() { # AES key for exporting p11sak remove-key aes --force --slot $PKCS11_SLOT_ID --pin $PKCS11_USER_PIN --label "$PKCS11_SECRET_KEY_LABEL-conf" RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) p11sak remove-key aes --force --slot $PKCS11_SLOT_ID --pin $PKCS11_USER_PIN --label "$PKCS11_SECRET_KEY_LABEL-conf.2" RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) p11sak remove-key aes --force --slot $PKCS11_SLOT_ID --pin $PKCS11_USER_PIN --label "$PKCS11_SECRET_KEY_LABEL-conf.3" RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) p11sak remove-key aes --force --slot $PKCS11_SLOT_ID --pin $PKCS11_USER_PIN --label "$PKCS11_SECRET_KEY_LABEL-env" RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) p11sak remove-key aes --force --slot $PKCS11_SLOT_ID --pin $PKCS11_USER_PIN --label "$PKCS11_SECRET_KEY_LABEL-opt" RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) # RSA keys for wrapping and importing p11sak remove-key rsa --force --slot $PKCS11_SLOT_ID --pin $PKCS11_USER_PIN --label $PKCS11_PRIVATE_KEY_LABEL RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) p11sak remove-key rsa --force --slot $PKCS11_SLOT_ID --pin $PKCS11_USER_PIN --label $PKCS11_PUBLIC_KEY_LABEL RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) # Keys imported during test p11sak remove-key aes --force --slot $PKCS11_SLOT_ID --pin $PKCS11_USER_PIN --label $KMIP_SECRET_KEY_LABEL RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) p11sak remove-key aes --force --slot $PKCS11_SLOT_ID --pin $PKCS11_USER_PIN --label "$KMIP_SECRET_KEY_LABEL.2" RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) p11sak remove-key aes --force --slot $PKCS11_SLOT_ID --pin $PKCS11_USER_PIN --label "$KMIP_SECRET_KEY_LABEL.3" RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) p11sak remove-key rsa --force --slot $PKCS11_SLOT_ID --pin $PKCS11_USER_PIN --label $KMIP_PUBLIC_KEY_LABEL RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) } setup_kmip_keys() { RETRY_COUNT=0 GET_LOGIN_TOKEN_DONE=1 GEN_ASYM_KEY_DONE=0 GEN_SYM_KEY_DONE=0 GET_PUB_KEY_DONE=0 while true; do if [[ $RETRY_COUNT -gt 100 ]] ; then RC_PKMIP_GENERATE=1 echo "error: Too many login retries" break fi RETRY_COUNT=$((RETRY_COUNT+1)) if [[ $GET_LOGIN_TOKEN_DONE -eq 0 ]] ; then # Get a login authorization ID from SKLM curl --fail-with-body --location --request POST "$KMIP_REST_URL/SKLM/rest/v1/ckms/login" \ --header "Content-Type: application/json" \ --data "{\"userid\":\"$KMIP_REST_USER\", \"password\":\"$KMIP_REST_PASSWORD\"}" \ --insecure --silent --show-error >$P11KMIP_TMP/curl_get_login_authid_stdout 2>$P11KMIP_TMP/curl_get_login_authid_stderr RC=$? echo "rc:" $RC if [[ $RC -ne 0 ]] ; then RC_PKMIP_GENERATE=1 cat $P11KMIP_TMP/curl_get_login_authid_stdout cat $P11KMIP_TMP/curl_get_login_authid_stderr break fi # Parse the response data and extract the authorization id token # Expected to return: {"UserAuthId":"xxxxxx"} AUTHID=`jq .UserAuthId $P11KMIP_TMP/curl_get_login_authid_stdout -r` echo "AuthID:" $AUTHID echo "succeeded: curl_get_login_authid" GET_LOGIN_TOKEN_DONE=1 fi if [[ $GEN_ASYM_KEY_DONE -eq 0 ]] ; then curl --fail-with-body --location --request POST "$KMIP_REST_URL/SKLM/rest/v1/objects/keypair" \ --header "accept: application/json" --header "Content-Type: application/json" \ --data "{\"clientName\":\"$KMIP_CLIENT_NAME\", \"prefixName\":\"tst\", \"numberOfObjects\": \"1\", \"publicKeyCryptoUsageMask\":\"Wrap_Unwrap\", \"privateKeyCryptoUsageMask\":\"Wrap_Unwrap\"}" \ --header "Authorization:SKLMAuth userAuthId=$AUTHID" \ --insecure --silent --show-error >$P11KMIP_TMP/curl_generate_asym_keys_stdout 2>$P11KMIP_TMP/curl_generate_asym_keys_stderr RC=$? echo "rc:" $RC RSN=`jq .code $P11KMIP_TMP/curl_generate_asym_keys_stdout -r` if [[ "$RSN" == "CTGKM6004E" ]]; then echo "warning: Login token expired, re-login and retry" GET_LOGIN_TOKEN_DONE=0 continue fi if [[ $RC -ne 0 ]] ; then RC_PKMIP_GENERATE=1 cat $P11KMIP_TMP/curl_generate_asym_keys_stdout cat $P11KMIP_TMP/curl_generate_asym_keys_stderr break fi KMIP_PUBLIC_KEY_ID=`jq .publicKeyId $P11KMIP_TMP/curl_generate_asym_keys_stdout -r` KMIP_PRIVATE_KEY_ID=`jq .privateKeyId $P11KMIP_TMP/curl_generate_asym_keys_stdout -r` echo "succeeded: curl_generate_asym_keys" GEN_ASYM_KEY_DONE=1 fi if [[ $GEN_SYM_KEY_DONE -eq 0 ]] ; then curl --fail-with-body --location --request POST "$KMIP_REST_URL/SKLM/rest/v1/objects/symmetrickey" \ --header "accept: application/json" --header "Content-Type: application/json" \ --data "{\"clientName\":\"$KMIP_CLIENT_NAME\", \"prefixName\":\"tst\", \"numberOfObjects\": \"1\", \"cryptoUsageMask\":\"Encrypt_Decrypt\"}" \ --header "Authorization:SKLMAuth userAuthId=$AUTHID" \ --insecure --silent --show-error >$P11KMIP_TMP/curl_generate_sym_key_stdout 2>$P11KMIP_TMP/curl_generate_sym_key_stderr RC=$? echo "rc:" $RC RSN=`jq .code $P11KMIP_TMP/curl_generate_sym_key_stdout -r` if [[ "$RSN" == "CTGKM6004E" ]]; then echo "warning: Login token expired, re-login and retry" GET_LOGIN_TOKEN_DONE=0 continue fi if [[ $RC -ne 0 ]] ; then RC_PKMIP_GENERATE=1 cat $P11KMIP_TMP/curl_generate_sym_key_stdout cat $P11KMIP_TMP/curl_generate_sym_key_stderr break fi KMIP_SECKEY_ID=`jq .id $P11KMIP_TMP/curl_generate_sym_key_stdout -r` echo "succeeded: curl_generate_sym_keys" GEN_SYM_KEY_DONE=1 fi if [[ $GET_PUB_KEY_DONE -eq 0 ]] ; then curl --fail-with-body --location --request GET "$KMIP_REST_URL/SKLM/rest/v1/objects/$KMIP_PUBLIC_KEY_ID" \ --header "accept: application/json" --header "Content-Type: application/json" \ --header "Authorization:SKLMAuth userAuthId=$AUTHID" \ --insecure --silent --show-error >$P11KMIP_TMP/curl_get_pubkey_stdout 2>$P11KMIP_TMP/curl_get_pubkey_stderr RC=$? echo "rc:" $RC RSN=`jq .code $P11KMIP_TMP/curl_get_pubkey_stdout -r` if [[ "$RSN" == "CTGKM6004E" ]]; then echo "warning: Login token expired, re-login and retry" GET_LOGIN_TOKEN_DONE=0 continue fi if [[ $RC -ne 0 ]] ; then RC_PKMIP_GENERATE=1 cat $P11KMIP_TMP/curl_get_pubkey_stdout cat $P11KMIP_TMP/curl_get_pubkey_stderr break fi KMIP_PUBLIC_KEY_LABEL=`jq .managedObject.alias $P11KMIP_TMP/curl_get_pubkey_stdout -r` KMIP_PUBLIC_KEY_LABEL=${KMIP_PUBLIC_KEY_LABEL:1:21} echo "succeeded: curl_get_pubkey_stdout" GET_PUB_KEY_DONE=1 fi echo "*** kmip keys after creation" echo "**** kmip pubkey id: ${KMIP_PUBLIC_KEY_ID}" echo "**** kmip privkey id: ${KMIP_PRIVATE_KEY_ID}" echo "**** kmip pubkey label: ${KMIP_PUBLIC_KEY_LABEL}" break done } compare_digests() { TEST_BASE="$1" TEST_STDOUT="${TEST_BASE}_stdout" cat "$TEST_STDOUT" | grep -A 5 "Secret Key" | grep "PKCS#11 Digest" | cut -c 22- > "${TEST_BASE}_pkcs_digest" cat "$TEST_STDOUT" | grep -A 5 "Secret Key" | grep "KMIP Digest" | cut -c 22- > "${TEST_BASE}_kmip_digest" diff -q "${TEST_BASE}_pkcs_digest" "${TEST_BASE}_kmip_digest" return $? } key_import_tests() { ################################################################ # Using configuration file options # ################################################################ # Build a standard configuration [[ -f $P11KMIP_CONF_FILE ]] && rm $P11KMIP_CONF_FILE echo "kmip { " >> $P11KMIP_CONF_FILE echo " host = \"${KMIP_HOSTNAME}\" " >> $P11KMIP_CONF_FILE echo " tls_client_cert = \"${KMIP_CLIENT_CERT}\" " >> $P11KMIP_CONF_FILE echo " tls_client_key = \"${KMIP_CLIENT_KEY}\" " >> $P11KMIP_CONF_FILE echo " " >> $P11KMIP_CONF_FILE echo " wrap_key_format = \"PKCS1\" " >> $P11KMIP_CONF_FILE echo " wrap_key_algorithm = \"RSA\" " >> $P11KMIP_CONF_FILE echo " wrap_key_size = 2048 " >> $P11KMIP_CONF_FILE echo " wrap_padding_method = \"PKCS1.5\" " >> $P11KMIP_CONF_FILE echo "} " >> $P11KMIP_CONF_FILE echo "pkcs11 { " >> $P11KMIP_CONF_FILE echo " slot = ${PKCS11_SLOT_ID} " >> $P11KMIP_CONF_FILE echo "} " >> $P11KMIP_CONF_FILE echo "*** Running test using configuration options" TEST_BASE="$P11KMIP_TMP/p11kmip_import_key_conf_test" P11KMIP_CONF_FILE="$P11KMIP_CONF_FILE" \ p11kmip import-key \ --send-wrapkey \ --gen-targkey \ --pin $PKCS11_USER_PIN \ --targkey-label $KMIP_SECRET_KEY_LABEL \ --targkey-id "012345678" \ --targkey-attrs "sX" \ --wrapkey-label $PKCS11_PUBLIC_KEY_LABEL \ --unwrapkey-label $PKCS11_PRIVATE_KEY_LABEL \ --tls-no-verify-server-cert \ --tls-trust-server-cert \ >"${TEST_BASE}_stdout" 2>"${TEST_BASE}_stderr" RC=$? echo "rc = $RC" echo "stdout:" cat ${TEST_BASE}_stdout if [[ $RC -ne 0 ]] ; then echo "stderr:" cat "${TEST_BASE}_stderr" echo "* TESTCASE p11kmip_test import-key-conf FAIL Failed to import keys using config file" return fi echo "* TESTCASE p11kmip_test import-key-conf PASS Sucessfully imported keys using config file" # Store the UID of the KMIP public and secret key just created KMIP_GEND_TARGKEY_UID=$(cat $P11KMIP_TMP/p11kmip_import_key_conf_test_stdout | grep -A 2 "Secret Key" | tail -n 1 | cut -d . -f 9) KMIP_SENT_WRAPKEY_UID=$(cat $P11KMIP_TMP/p11kmip_import_key_conf_test_stdout | grep -A 2 "Public Key" | tail -n 1 | cut -d . -f 9) echo "*** Running import test using configuration options with 128-bit key" TEST_BASE="$P11KMIP_TMP/p11kmip_import_key_conf_test_128" P11KMIP_CONF_FILE="$P11KMIP_CONF_FILE" \ p11kmip import-key \ --gen-targkey \ --targkey-length 128 \ --pin $PKCS11_USER_PIN \ --targkey-label "$KMIP_SECRET_KEY_LABEL.2" \ --wrapkey-label $PKCS11_PUBLIC_KEY_LABEL \ --unwrapkey-label $PKCS11_PRIVATE_KEY_LABEL \ --tls-no-verify-server-cert \ --tls-trust-server-cert \ >"${TEST_BASE}_stdout" 2>"${TEST_BASE}_stderr" RC=$? echo "rc = $RC" echo "stdout:" cat "${TEST_BASE}_stdout" if [[ $RC -ne 0 ]] ; then echo "stderr:" cat "${TEST_BASE}_stderr" echo "* TESTCASE p11kmip_test import-key-conf-128 FAIL Failed to import AES-128 keys using config file" return fi echo "* TESTCASE p11kmip_test import-key-conf-128 PASS Sucessfully imported AES-128 keys using config file" # Store the UID of the KMIP public and secret key just created KMIP_GEND_TARGKEY2_UID=$(cat "${TEST_BASE}_stdout" | grep -A 2 "Secret Key" | tail -n 1 | cut -d . -f 9) echo "*** Running import test using configuration options with 192-bit key" TEST_BASE="$P11KMIP_TMP/p11kmip_import_key_conf_test_192" P11KMIP_CONF_FILE="$P11KMIP_CONF_FILE" \ p11kmip import-key \ --gen-targkey \ --targkey-length 192 \ --pin $PKCS11_USER_PIN \ --targkey-label "$KMIP_SECRET_KEY_LABEL.3" \ --wrapkey-label $PKCS11_PUBLIC_KEY_LABEL \ --unwrapkey-label $PKCS11_PRIVATE_KEY_LABEL \ --tls-no-verify-server-cert \ --tls-trust-server-cert \ >"${TEST_BASE}_stdout" 2>"${TEST_BASE}_stderr" RC=$? echo "rc = $RC" echo "stdout:" cat "${TEST_BASE}_stdout" if [[ $RC -ne 0 ]] ; then echo "stderr:" cat "${TEST_BASE}_stderr" echo "* TESTCASE p11kmip_test import-key-conf-192 FAIL Failed to import AES-192 keys using config file" return fi echo "* TESTCASE p11kmip_test import-key-conf-196 PASS Sucessfully imported AES-196 keys using config file" # Store the UID of the KMIP public and secret key just created KMIP_GEND_TARGKEY3_UID=$(cat "${TEST_BASE}_stdout" | grep -A 2 "Secret Key" | tail -n 1 | cut -d . -f 9) ################################################################ # Using environment variables # ################################################################ # Fill the configuration file with bogus values [[ -f $P11KMIP_CONF_FILE ]] && rm $P11KMIP_CONF_FILE echo "kmip { " >> $P11KMIP_CONF_FILE echo " host = \"255.255.255.255:0\" " >> $P11KMIP_CONF_FILE echo " tls_client_cert = \"/dev/null\" " >> $P11KMIP_CONF_FILE echo " tls_client_key = \"/dev/null\" " >> $P11KMIP_CONF_FILE echo " " >> $P11KMIP_CONF_FILE echo " wrap_key_format = \"PKCS1\" " >> $P11KMIP_CONF_FILE echo " wrap_key_algorithm = \"RSA\" " >> $P11KMIP_CONF_FILE echo " wrap_key_size = 2048 " >> $P11KMIP_CONF_FILE echo " wrap_padding_method = \"PKCS1.5\" " >> $P11KMIP_CONF_FILE echo " wrap_hashing_algorithm = \"SHA-1\" " >> $P11KMIP_CONF_FILE echo "} " >> $P11KMIP_CONF_FILE echo "pkcs11 { " >> $P11KMIP_CONF_FILE echo " slot = 0 " >> $P11KMIP_CONF_FILE echo "} " >> $P11KMIP_CONF_FILE echo "*** Running test using environment variables" TEST_BASE="$P11KMIP_TMP/p11kmip_import_key_env_test" P11KMIP_CONF_FILE="$P11KMIP_CONF_FILE" \ PKCS11_USER_PIN="$PKCS11_USER_PIN" \ PKCS11_SLOT_ID="$PKCS11_SLOT_ID" \ KMIP_HOSTNAME="$KMIP_HOSTNAME" \ KMIP_CLIENT_CERT="$KMIP_CLIENT_CERT" \ KMIP_CLIENT_KEY="$KMIP_CLIENT_KEY" p11kmip import-key \ --targkey-label $KMIP_SECRET_KEY_LABEL \ --wrapkey-label $PKCS11_PUBLIC_KEY_LABEL \ --unwrapkey-label $PKCS11_PRIVATE_KEY_LABEL \ --tls-no-verify-server-cert \ --tls-trust-server-cert \ >"${TEST_BASE}_stdout" 2>"${TEST_BASE}_stderr" RC=$? echo "rc = $RC" echo "stdout:" cat "${TEST_BASE}_stdout" if [[ $RC -ne 0 ]] ; then echo "stderr:" cat "${TEST_BASE}_stderr" echo "* TESTCASE p11kmip_test import-key-env FAIL Failed to import keys using env var" return fi echo "* TESTCASE p11kmip_test import-key-env PASS Sucessfully imported keys using env var" ################################################################ # Using only commandline options # ################################################################ echo "*** Running test using command line options" TEST_BASE="$P11KMIP_TMP/p11kmip_import_key_opt_test" p11kmip import-key \ --slot $PKCS11_SLOT_ID \ --pin $PKCS11_USER_PIN \ --kmip-host $KMIP_HOSTNAME \ --kmip-client-cert $KMIP_CLIENT_CERT \ --kmip-client-key $KMIP_CLIENT_KEY \ --targkey-label $KMIP_SECRET_KEY_LABEL \ --wrapkey-label $PKCS11_PUBLIC_KEY_LABEL \ --unwrapkey-label $PKCS11_PRIVATE_KEY_LABEL \ --tls-no-verify-server-cert \ --tls-trust-server-cert \ >"${TEST_BASE}_stdout" 2>"${TEST_BASE}_stderr" RC=$? echo "rc = $RC" echo "stdout:" cat "${TEST_BASE}_stdout" if [[ $RC -ne 0 ]] ; then echo "stderr:" cat "${TEST_BASE}_stderr" echo "* TESTCASE p11kmip_test import-key-arg FAIL FAiled to import keys using command line arguments" return fi echo "* TESTCASE p11kmip_test import-key-arg PASS Sucessfully imported keys using command line arguments" } key_export_tests() { ################################################################ # Using configuration file options # ################################################################ # Build a standard configuration [[ -f $P11KMIP_CONF_FILE ]] && rm $P11KMIP_CONF_FILE echo "kmip { " >> $P11KMIP_CONF_FILE echo " host = \"${KMIP_HOSTNAME}\" " >> $P11KMIP_CONF_FILE echo " tls_client_cert = \"${KMIP_CLIENT_CERT}\" " >> $P11KMIP_CONF_FILE echo " tls_client_key = \"${KMIP_CLIENT_KEY}\" " >> $P11KMIP_CONF_FILE echo " " >> $P11KMIP_CONF_FILE echo " wrap_key_format = \"PKCS1\" " >> $P11KMIP_CONF_FILE echo " wrap_key_algorithm = \"RSA\" " >> $P11KMIP_CONF_FILE echo " wrap_key_size = 2048 " >> $P11KMIP_CONF_FILE echo " wrap_padding_method = \"PKCS1.5\" " >> $P11KMIP_CONF_FILE echo " wrap_hashing_algorithm = \"SHA-1\" " >> $P11KMIP_CONF_FILE echo "} " >> $P11KMIP_CONF_FILE echo "pkcs11 { " >> $P11KMIP_CONF_FILE echo " slot = ${PKCS11_SLOT_ID} " >> $P11KMIP_CONF_FILE echo "} " >> $P11KMIP_CONF_FILE echo "*** Running test using configuration options" TEST_BASE="$P11KMIP_TMP/p11kmip_export_key_conf_test" P11KMIP_CONF_FILE="$P11KMIP_CONF_FILE" p11kmip export-key \ --retr-wrapkey \ --pin $PKCS11_USER_PIN \ --targkey-label "$PKCS11_SECRET_KEY_LABEL-conf" \ --wrapkey-label $KMIP_PUBLIC_KEY_LABEL \ --wrapkey-id "012345678" \ --wrapkey-attrs "H" \ --tls-no-verify-server-cert \ --tls-trust-server-cert \ >"${TEST_BASE}_stdout" 2>"${TEST_BASE}_stderr" RC=$? echo "rc = $RC" echo "stdout:" cat "${TEST_BASE}_stdout" if [[ $RC -ne 0 ]] ; then echo "stderr:" cat "${TEST_BASE}_stderr" echo "* TESTCASE p11kmip_test export-key-conf FAIL Failed to export keys using config file" return fi echo "* TESTCASE p11kmip_test export-key-conf PASS Sucessfully exported keys using config file" # Store the UID of the PKCS#11 public key just retrieved KMIP_RETR_WRAPKEY_UID=$(cat $P11KMIP_TMP/p11kmip_export_key_conf_test_stdout | grep -A 2 "Public Key" | tail -n 1 | cut -d . -f 9) echo "*** Running test using configuration options with 128-bit key" TEST_BASE="$P11KMIP_TMP/p11kmip_export_key_conf_test_128" P11KMIP_CONF_FILE="$P11KMIP_CONF_FILE" p11kmip export-key \ --pin $PKCS11_USER_PIN \ --targkey-label "$PKCS11_SECRET_KEY_LABEL-conf.2" \ --wrapkey-label $KMIP_PUBLIC_KEY_LABEL \ --tls-no-verify-server-cert \ --tls-trust-server-cert \ >"${TEST_BASE}_stdout" 2>"${TEST_BASE}_stderr" RC=$? echo "rc = $RC" echo "stdout:" cat "${TEST_BASE}_stdout" if [[ $RC -ne 0 ]] ; then echo "stderr:" cat "${TEST_BASE}_stderr" echo "* TESTCASE p11kmip_test export-key-conf-128 FAIL FAiled to export AES-128 keys using config file" return fi echo "* TESTCASE p11kmip_test export-key-conf-128 PASS Sucessfully exported AES-128 keys using config file" echo "*** Running test using configuration options with 192-bit key" TEST_BASE="$P11KMIP_TMP/p11kmip_export_key_conf_test_192" P11KMIP_CONF_FILE="$P11KMIP_CONF_FILE" p11kmip export-key \ --pin $PKCS11_USER_PIN \ --targkey-label "$PKCS11_SECRET_KEY_LABEL-conf.3" \ --wrapkey-label $KMIP_PUBLIC_KEY_LABEL \ --tls-no-verify-server-cert \ --tls-trust-server-cert \ >"${TEST_BASE}_stdout" 2>"${TEST_BASE}_stderr" RC=$? echo "rc = $RC" echo "stdout:" cat "${TEST_BASE}_stdout" if [[ $RC -ne 0 ]] ; then echo "stderr:" cat "${TEST_BASE}_stderr" echo "* TESTCASE p11kmip_test export-key-conf-192 FAIL FAiled to export AES-192 keys using config file" return fi echo "* TESTCASE p11kmip_test export-key-conf-192 PASS Sucessfully exported AES-192 keys using config file" ################################################################ # Using environment variables # ################################################################ # Fill the configuration file with bogus values [[ -f $P11KMIP_CONF_FILE ]] && rm $P11KMIP_CONF_FILE echo "kmip { " >> $P11KMIP_CONF_FILE echo " host = \"255.255.255.255:0\" " >> $P11KMIP_CONF_FILE echo " tls_client_cert = \"/dev/null\" " >> $P11KMIP_CONF_FILE echo " tls_client_key = \"/dev/null\" " >> $P11KMIP_CONF_FILE echo " " >> $P11KMIP_CONF_FILE echo " wrap_key_format = \"PKCS1\" " >> $P11KMIP_CONF_FILE echo " wrap_key_algorithm = \"RSA\" " >> $P11KMIP_CONF_FILE echo " wrap_key_size = 2048 " >> $P11KMIP_CONF_FILE echo " wrap_padding_method = \"PKCS1.5\" " >> $P11KMIP_CONF_FILE echo " wrap_hashing_algorithm = \"SHA-1\" " >> $P11KMIP_CONF_FILE echo "} " >> $P11KMIP_CONF_FILE echo "pkcs11 { " >> $P11KMIP_CONF_FILE echo " slot = 0 " >> $P11KMIP_CONF_FILE echo "} " >> $P11KMIP_CONF_FILE echo "*** Running test using environment variables" TEST_BASE="$P11KMIP_TMP/p11kmip_export_key_env_test" P11KMIP_CONF_FILE="$P11KMIP_CONF_FILE" \ PKCS11_USER_PIN="$PKCS11_USER_PIN" \ PKCS11_SLOT_ID="$PKCS11_SLOT_ID" \ KMIP_HOSTNAME="$KMIP_HOSTNAME" \ KMIP_CLIENT_CERT="$KMIP_CLIENT_CERT" \ KMIP_CLIENT_KEY="$KMIP_CLIENT_KEY" \ p11kmip export-key \ --targkey-label "$PKCS11_SECRET_KEY_LABEL-env" \ --wrapkey-label $KMIP_PUBLIC_KEY_LABEL \ --tls-no-verify-server-cert \ --tls-trust-server-cert \ >"${TEST_BASE}_stdout" 2>"${TEST_BASE}_stderr" RC=$? echo "rc = $RC" echo "stdout:" cat "${TEST_BASE}_stdout" if [[ $RC -ne 0 ]] ; then echo "stderr:" cat "${TEST_BASE}_stderr" echo "* TESTCASE p11kmip_test export-key-env FAIL Failed to export keys using env vars" return fi echo "* TESTCASE p11kmip_test export-key-env PASS Sucessfully exported keys using env vars" ################################################################ # Using only commandline options # ################################################################ echo "*** Running test using command line options" TEST_BASE="$P11KMIP_TMP/p11kmip_export_key_opt_test" p11kmip export-key \ --slot $PKCS11_SLOT_ID \ --pin $PKCS11_USER_PIN \ --kmip-host $KMIP_HOSTNAME \ --kmip-client-cert $KMIP_CLIENT_CERT \ --kmip-client-key $KMIP_CLIENT_KEY \ --targkey-label "$PKCS11_SECRET_KEY_LABEL-opt" \ --wrapkey-label $KMIP_PUBLIC_KEY_LABEL \ --tls-no-verify-server-cert \ --tls-trust-server-cert \ >"${TEST_BASE}_stdout" 2>"${TEST_BASE}_stderr" RC=$? echo "rc = $RC" echo "stdout:" cat "${TEST_BASE}_stdout" if [[ $RC -ne 0 ]] ; then echo "stderr:" cat "${TEST_BASE}_stderr" echo "* TESTCASE p11kmip_test export-key-arg FAIL Failed to export keys using comand line arguments" return fi echo "* TESTCASE p11kmip_test export-key-arg PASS Sucessfully exported keys using comand line arguments" } echo "** Generating test certificates - 'p11kmip_test.sh'" generate_certificates echo "** Setting up KMIP client on KMIP server - 'p11kmip_test.sh'" setup_kmip_client if [[ $RC -ne 0 ]] ; then echo "* TESTCASE p11kmip_test setup-client FAIL Failed to setup KMIP client on KMIP server" exit $RC fi echo "* TESTCASE p11kmip_test setup-client PASS Sucessfully setup up KMIP client on KMIP server" echo "** Setting up remote and local test keys - 'p11kmip_test.sh'" setup_kmip_keys if [[ $RC_PKMIP_GENERATE -ne 0 ]]; then echo "* TESTCASE p11kmip_test setup-kmip-keys FAIL Failed to setup up KMIP remote and local keys" exit $RC_PKMIP_GENERATE fi echo "* TESTCASE p11kmip_test setup-kmip-keys PASS Sucessfully setup up KMIP remote and local keys" setup_pkcs11_keys if [[ $RC_P11SAK_IMPORT -ne 0 ]]; then echo "* TESTCASE p11kmip_test setup-pkcs11-keys FAIL Failed to setup up PKCS#11 keys" exit $RC_PKMIP_GENERATE fi echo "* TESTCASE p11kmip_test setup-pkcs11-keys PASS Sucessfully setup up PKCS#11 keys" echo "** Running key import tests - 'p11kmip_test.sh'" key_import_tests echo "** Running key export tests - 'p11kmip_test.sh'" key_export_tests echo "** Cleaning up remote and local test keys - 'p11kmip_test.sh'" cleanup_pkcs11_keys if [[ $RC_P11SAK_REMOVE -ne 0 ]]; then echo "* TESTCASE p11kmip_test remove-keys FAIL Failed to remove PKCS#11 keys" exit $RC_P11SAK_REMOVE fi echo "* TESTCASE p11kmip_test remove-keys PASS Sucessfully removed PKCS#11 keys" exit $RCopencryptoki-opencryptoki-451d99c/testcases/misc_tests/p11sak_dsa3072cert.crt000066400000000000000000000031111520105705100273260ustar00rootroot000000000000000‚E0‚é9z*.‘Ơ_»®#–èư³Ơ‘c0  `†He0l1 0 UDE1 0 U BW10U Boeblingen10U IBM R&D10U Linux on Z10U dsa3072cert0 230614090447Z 230714090447Z0l1 0 UDE1 0 U BW10U Boeblingen10U IBM R&D10U Linux on Z10U dsa3072cert0‚Æ0‚9*†HÎ80‚,‚͵|éáwä¡ï›Å‘†Z5¾©÷¥đ%Đ)Có>>=8eÎß„˜̃Ûà`¿DÊY´H'‘hx‡g½7ôĂ7v„ú KŒ¼ÁĂơbä\é“ û>Ù́÷Ràq^ầuÂf[$†l¡+(ÎøĐÎcW¹W¦ m̀³UĂ+lF:À‡œ¾Ñ1–PÚjE“ƯÍûàÏóÀá2•á„Óö_ºÿ ­ÏsLZb£9[QûĐí øtúÛ’¢Úù{ P@̉^¢°0¢Ñ.v`ÙÁyRO*¬ƠFe^Á0P5Û(¯RƠ1Ûb0îSê$(bc¸fæ?@ô¢©ùE$̀êÆŸ¤ĂPvo‰j«̀ ï'ùßÅ₫¹`ƒ¼~uµrẁ k¹q0j²:¶¡ø@ÿ>ƒ¿8~åM4™¾H–ëÏGp¬D}éÊkÎ! ^Bz¢#Úp (¼Ư]rÔáàç *ér‘“'Å"•­&Wïƒ}tVÁŸ?_ÜŸ!Ôđû„́H8‹ÿp’ŒbÿÁ{J\`‡.̣ -Ÿ‚€+ÙÇÍÑy·œW.µ§ø™J̀=ZDC´«÷‹Ÿ„è·ëï‚¢„éü®/ç€5œ•H«¼~¤ÍN©"-[ו'c6½Àă#U#ßÛÇf§êô±ØäF¦'ªXt!ø¼]δö5Ă@î;­në̃€ufRªø%̀W[8T­fÎѰ·7÷•ĂF!ˆÇ¶ ÷ Ú"Ë[Q‘Ó¿LÔr™5@H.‰Đ0}zW½aÙâ₫º•ïđ#”_u€d ”–Í ‘4™éÜúñ!Y/Á´™[¦”ccS]Ưáß­,•ªË…¡V—œ=²Ü[yIz† ´fđåÁ.¿wÊO &ưÁsÆçjÛ²y';†ñjL˜ïXˆPk^QÆïà€’†4Eô&}Ä JÚú4A“̀enˆé’‘!gôœ'ưë0`G;H”f̃ 笔̀é¹ç|(_ ;Hl^¿Ú EÎÍÂ`,zƠ<²³'x₫”E&"æ̉éä÷¶ô¾5ú¡́ˆ9Ư$ôÔgdboÁ¾ơTM¸-*#=ºúk¬ù§¦¨+}¥2‚å1>a‚°Pë§Ă!ê|}IóË哃7ÛH`ØöEnHgEëk!'3‘¶3vz 0éå†ƠĂ:¶;¶«¼•Y 炲O 9ÛÚưÍe¤5/ñ„+‹()€t̃ăĂQ3Đ0m½¥|lz_K™C3̣UƯ¯7KTÎ’Á’”Í=<$ é̀;$E¨”̀s…Øq4¦pŸÊß’bßwícûª–˜ëbø‡“º ÙïÍri¡£ŒÈØVè«M:×đ¥đ(tà¶Ơ¥[TDî́µE”úƯ=m {D­)ß*,q{ø̉ßSưƠgmÿöf ă r‚ ¢z>œÊ©ä 6W(´vÔ=•4ú-Æv—xJ˜*"ø¾ÊÇ€?ôHs¼ƒ%2ÓœĂm¯¶—˜Q.ê\îÀ´éå07GAk<0 ”û˜]û µ*Où”xI@»låöçM)£«úJ&1A$ØĂKƯáª{¾o©̣wû§\Ây³†V–1²<|²¯~ñĐ ®È…íVNØ+.Ö²K80«›¢t|-,G̉{Ëö¡‹mi‹.uè¦₫ÊmÇ+Đ…[lôÊ@4ç¯=w„FMâ~PÄ‘UR*̣éZêfWˆíÙÛ•́A₫[ØƯ‹ơ­̉`¯1Ùéê¥ _pÍBàm}{s ₫Ÿ¿F˜Mö@ Œ™ .ˆ^>멯Ië•=kádzăµ6ÏK™©OïïDVEúeX-÷b7'̉9Çfh¦ƒÉ̃Ÿ*Û»xÿơw~jÿ° ‚‚=¶/ÚÈü…ĐNçÍE :ù r‰0>,›f-l-8"Ü=̀ßáÍ*Û>"99ĂSë̉U >d1—.uÉu~ôt¤HGŒt8ĂÉ›÷P•™˜Af)à®H#“*`˜îÈl”Wິœ@uSC÷\¤‚ư£C¬[{­ëºÑÀ˜¿U¢Zr\Ë*mP^¯p’£Ă.·{~'¥ĂÏœrëË\*º¤V’ôÏÈ»*6g“nƠƒ¤g¬HîªiÛMÖ*ú'9=vUvCX.¡Â§:̉;₫̉2 U~`œ̃vœp$e:Ü5˜ËE&µ´1‹ÄÂ~0€ w3êṣñÈß#ÈÊb9Û÷¢Ä̀íBT€\8Ăü •jIĂeM8‡‡>§hÎ 0¦\C±„·ÀQù¬pÚ¶ÿLkl0}€j`£jm¦Vd÷ú×’ŸÚ%¾ wœ¡xøÅŸ>ơZí_9ăi×bYJ"̀Ÿ Ëä¬.ËnVFư`ÅÎËKؾ“_%̣P‹®§â/Œ  î~hv¹¾æ^k¥»€6·ŸxÚBoᢀz)øB|z‘8ÔÛ8;{€4äụ́زƠeµ¿sBzùZ»`̣¤èr'Ï’wJiK³ÿ,¤‚¼@YÓFWÉ�  `†HeG0D BŸl hÅDäó^!´F¢Û̀*ô  ß™ FXiË ‡ïU²nQ2qaj6lϤM‚É Ừa;Ú ØCopencryptoki-opencryptoki-451d99c/testcases/misc_tests/p11sak_dsa4096cert.pem000066400000000000000000000053001520105705100273300ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIHxDCCB2oCFCDXB86vrZZzJdouMpVSitCEY2htMAsGCWCGSAFlAwQDAjBsMQsw CQYDVQQGEwJERTELMAkGA1UECAwCQlcxEzARBgNVBAcMCkJvZWJsaW5nZW4xEDAO BgNVBAoMB0lCTSBSJkQxEzARBgNVBAsMCkxpbnV4IG9uIFoxFDASBgNVBAMMC2Rz YTQwOTZjZXJ0MB4XDTIzMDYxNDA5MDQ1N1oXDTIzMDcxNDA5MDQ1N1owbDELMAkG A1UEBhMCREUxCzAJBgNVBAgMAkJXMRMwEQYDVQQHDApCb2VibGluZ2VuMRAwDgYD VQQKDAdJQk0gUiZEMRMwEQYDVQQLDApMaW51eCBvbiBaMRQwEgYDVQQDDAtkc2E0 MDk2Y2VydDCCBkcwggQ6BgcqhkjOOAQBMIIELQKCAgEA2f0UCOKY/Z0CfQI1pKl9 UG1P4S+l5l15eZdBj+cH/FZ7eZifdJtaa9kdMGl2NqL3xJ6FLLn6xQB2yCmxJ3Kh 3nyw31bIngD24R1wQlZRA/GkIy6u6Sh4ZIHETni0/Oz5FqXkArDv9bg0m4gk7mZ2 DkvCdcssj8g/qL+u7dUM6RUBXvm6lnz32On3TlaVZVFiWaxQQy6fruj4nM/ijY0/ n1WBkgucge8hXI8ZCKwVkHGtwUr3gUD89e1AJabtLi2KOll2liSNrkJiycntYsFP Jnwekk/b/UgEcUjzKItMT9K43icSwkZaQFgP+GLddv3+miTaFjMYfLTlUqifnOWp de1ECI1C0zUNQJbpLj4DrSyVqsuFoVaXnD2y3Ft5SYF6hg+gtGbw5ZrBLr93yk+g Jv3Bc8OG52rbsnknO4bxnWobTJjvWIhQa15Rxu/gjYCShjSPRfQmfcQMStr6NEGT zGVuiOmSkSFnj/ScJ/3rMGBHEgM7SJQEZt6gBueslMzpued8kChfCjtIbF6/2g1F zs3CYCx61TyyArMneP6URSYi5tLp5Pe2kPS+Nfqh7Ig5Et0k9NRnZGJvE8G+9VRN uC0qHg8UIz26+mus+aemqJArfaUyBp2C5Z4xPmGCsI2PUOsCEafDIep8fUnzy+WT gzfbSGDYgfZFbpCQSGdF62sCIQCKJzORtjMWHXZ6DDDp5YbVmsM6BbY7tqu8lY5Z AiCe5wKCAgEAsk8MOdvaBP3NZaQ1L/GEK4soKRiAdN7jw1EzA9CBMBNtvaV8bJ4c el9LmUMz8lXdrzdLVM6SwZKUzQgPPTwkDenMBzskGkWolMxzhdiacTSmcJ/K35Ji 33ftYx77qoqWmOti+IcDk7oL2RTvzXJpoaOMyNhW6KtNOtfwpfAodOC21aVbVETu 7LVFlPrdPW0XCpB7E0StKd8qLHGKe/jS31Md/dVnbf/2ZgvjDSByggqiej6cyqnk DTZXKLR21AQ9lTT6LX/GdpeBeEqYKiL4vsrHgD/0SHO8gxslmjIR05zDba+2B5eY US7qXO7AtOkY5TA3R0FrPDAKlPsWmF37CbUqT/mUEHhJEAVAu2zl9udNKaOr+kom HTFBJNjDS93hqnu+bwWp8nf7p1zCEXmzhlaWMbI8fLKvfvHQIK7Ihe1WTg8EFtgr LtaySzgwqwSbG6J0fC0sR9J7y/ahi21piy516Kb+ym3HK9CFilts9MpANOevPXeE Ro5N4g9+UMSRVQNSKvLpWupmV4jt2X8e24GV7EH+W9jdi/Wt0h1grzHZ6eqlC19w zUKd4G19e5pzBQ3+nx+/RphN9kAKjJmgLohegT7rqa9J65UFET1r4WR64xK1Ns9L malP7+9EH1ZF+mVYLfdiNyfSOcdmaKaDyd6fKgfbu3j/9Xd+imr/sA0DggIFAAKC AgA9FbYv2jx1QZcs8D7InfyF0E7nzUUKOvkJcokDBjA+LJtmLWwtOCLcPYrM3+HN Kts+Ijk5w1Pr0lUgPmQSMZcudcl1fgP0dKRIR4x0OMPJm/cUUJ2VBJmYQWYp4K5I I5MqkGCY7shslFfgurScikB1U0P3XKSC/aNDrFt7reu6AtHAmAKBv1WiWnIYXMsq bVBena9wA5Kjwy63e34npcPPnpxy65rLFQRcKhqQuqQPVhEYkvQeD8/Iuyo2Z5Nu 1YOkHmesSO6qadtN1ir6Jzk9dlV2Q1guocKnOtI7/gXSMgtVfmCOipzedpxwJH9l Otx/NZjLRR0mtbQxi8TCF4F+ATCAoHcPM+pz8vECyN8jHMjKYjnb96LEzO1CVIBc OAfDEfwQDZVqScNlTTiHhz6naM4LMACmXEOxHIS3wFH5rHDaH7b/TGtsFzB9gGpg o2ptplZk9xr615Kf2oobJb4gd5yheJr4xZ8+9VoFFe1fOeNp1x5iWY0USiLMnwrL 5Kwuy25WRv1gxc7LS9i+k18l8lCLrginihHiL4ygHwvufmh2ub7mXmsCpRUenruA NrefmnjaQm/hooCajXop+IpCfHqRnTjU2w8VODt7gDTkB/ryEdiy1WW1v3OBQnr5 Wrtg8qTocifPkgZ3SmlLnrMI/yykGYK8QBMeWdNGV8kmIzALBglghkgBZQMEAwID RwAwRAIgHxye4eykLGh7l1biITHc/8ppRPhMz5uGekXxER27xnQCIGahLm6IL06s mPFs6sHYpm5eLUAo3lz5apGOPNA8/ztH -----END CERTIFICATE----- opencryptoki-opencryptoki-451d99c/testcases/misc_tests/p11sak_ecp256cert.crt000066400000000000000000000007251520105705100272570ustar00rootroot000000000000000‚Ñ0‚wL“/"ô½ VË©l ;³ưª0 *†HÎ=0k1 0 UDE1 0 U BW10U Boeblingen10U IBM R&D10U Linux on Z10U ecp256cert0 230614090441Z 240613090441Z0k1 0 UDE1 0 U BW10U Boeblingen10U IBM R&D10U Linux on Z10U ecp256cert0Y0*†HÎ=*†HÎ=B„ó/©]‚àÇÈR%",¡ #^HpBî—)§»RW3Y0²¹¾Ù1¸'Ë»£îª³²ă í|g_0 *†HÎ=H0E v ñëÙ{w9À|gáç¥_Íä³ÍEÅ€·/̉!Ó”H¬K¸ºtĐơú~™yoµ‚â # ß1µo :olopencryptoki-opencryptoki-451d99c/testcases/misc_tests/p11sak_ecp256cert.pem000066400000000000000000000012601520105705100272430ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIB0DCCAXcCFFClvGAQ6pgLfAsXWUYvt/6Tw9rNMAoGCCqGSM49BAMEMGsxCzAJ BgNVBAYTAkRFMQswCQYDVQQIDAJCVzETMBEGA1UEBwwKQm9lYmxpbmdlbjEQMA4G A1UECgwHSUJNIFImRDETMBEGA1UECwwKTGludXggb24gWjETMBEGA1UEAwwKZWNw MjU2Y2VydDAeFw0yMzA2MTQwOTA0NDFaFw0yNDA2MTMwOTA0NDFaMGsxCzAJBgNV BAYTAkRFMQswCQYDVQQIDAJCVzETMBEGA1UEBwwKQm9lYmxpbmdlbjEQMA4GA1UE CgwHSUJNIFImRDETMBEGA1UECwwKTGludXggb24gWjETMBEGA1UEAwwKZWNwMjU2 Y2VydDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABITzL6ldguDHD8hSJSIsoRYH A4EMI15IcEKK7oGXKae7UhpXM1kwsrmevtkxuCfLA7ujkO4OqrMTsuOg7XweZ18w CgYIKoZIzj0EAwQDRwAwRAIgdMD4ahW/Ajt42+STIrsl1MS/T7BI2cZF2GDDP+M0 PmkCIGZbOuo+LV2IycVs8j9RBQsk8CiLdCItkVVpNwyePSLp -----END CERTIFICATE----- opencryptoki-opencryptoki-451d99c/testcases/misc_tests/p11sak_ecp384cert.crt000066400000000000000000000010211520105705100272470ustar00rootroot000000000000000‚ 0‚”.rnzb[@ê}×m–½MZS¢…Œ0 *†HÎ=0k1 0 UDE1 0 U BW10U Boeblingen10U IBM R&D10U Linux on Z10U ecp384cert0 230614090441Z 240613090441Z0k1 0 UDE1 0 U BW10U Boeblingen10U IBM R&D10U Linux on Z10U ecp384cert0v0*†HÎ=+"bfs¬5¼ÍÜíKƒéQjÖ¬wà>¿!CÅ1¼æW&j=4+TJFÉ­ưA/‹x«ÀÛ3æÉ­•m-úÉÇGûÓºÙă RwïéP'đĆ_IûÖQ~#é—!¿0 *†HÎ=g0d0B ¦÷m®QVK¹˜hÊçô¢„)ËƯé½ûĂ_[JE@5đ4 9w ;ˆ(´Q°02đÇ:§j[…N'/j añPx³Ö̃a:åị„ÏÈ{±©‰É*;]Nopencryptoki-opencryptoki-451d99c/testcases/misc_tests/p11sak_ecp384cert.pem000066400000000000000000000014061520105705100272470ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIICDzCCAZQCFBxeSeaQPlGw6x06dXq+15B+SWZkMAoGCCqGSM49BAMEMGsxCzAJ BgNVBAYTAkRFMQswCQYDVQQIDAJCVzETMBEGA1UEBwwKQm9lYmxpbmdlbjEQMA4G A1UECgwHSUJNIFImRDETMBEGA1UECwwKTGludXggb24gWjETMBEGA1UEAwwKZWNw Mzg0Y2VydDAeFw0yMzA2MTQwOTA0NDFaFw0yNDA2MTMwOTA0NDFaMGsxCzAJBgNV BAYTAkRFMQswCQYDVQQIDAJCVzETMBEGA1UEBwwKQm9lYmxpbmdlbjEQMA4GA1UE CgwHSUJNIFImRDETMBEGA1UECwwKTGludXggb24gWjETMBEGA1UEAwwKZWNwMzg0 Y2VydDB2MBAGByqGSM49AgEGBSuBBAAiA2IABGZzrDW8zdztS42D6VFqHdasd+A+ CL8hQ8UxnbzmVxomaj00K1QfSh1GFcmt/UEvi3irwNsz5smtlW2NLRT6ycdH+9O6 2eMgUncX7+lQJ/DEhl9JjQSa+9ZRfiPplyG/GzAKBggqhkjOPQQDBANpADBmAjEA turBDf2P0ci5tUYDfL+/dFCRFwzlLQQGG9C35rwXIF8zHCNlQzr1DtxSiT+85JkQ AjEAxrBUxWqoaN62xQ4bmdaA9LSS9oMleM2l4I63sgIyb8A5zha+8W1eQr7+N2vf gMY5 -----END CERTIFICATE----- opencryptoki-opencryptoki-451d99c/testcases/misc_tests/p11sak_ecp521cert.crt000066400000000000000000000011351520105705100272460ustar00rootroot000000000000000‚Y0‚º•(îÀ<ÚL(Oùz>ü•ù’-Í0 *†HÎ=0k1 0 UDE1 0 U BW10U Boeblingen10U IBM R&D10U Linux on Z10U ecp521cert0 230614090441Z 240613090441Z0k1 0 UDE1 0 U BW10U Boeblingen10U IBM R&D10U Linux on Z10U ecp521cert0›0*†HÎ=+#†}Œ_–±‡¹(eTơn•ù–Vrà^Ç„0? ă®2_̀±ôfçNpE;;c¿Ùîj6f»È»â®—_m u£_…Z^;l¬*8KYƯ2Û?6̓‰%‹Ôä»<̉“•_n”A‡BƒÏáÙ„v@=|ˆƯË̉Ws³c:†AưP0 *†HÎ=Œ0ˆB±2çqà‰ áÙUèé$Q¡~ôK–%IƠ+ôu å4l;+1S—M«¿D~4ZPŸlsFÁ5kw r¬OBóñỚ"›Đ›åúhpGg÷ơ¦,×H#e¯V_§̃n jrØ¿Ơ³¼ˆ«¢¹«ß]Y—Of…ü|¶Ÿ}¾…opencryptoki-opencryptoki-451d99c/testcases/misc_tests/p11sak_ecp521cert.pem000066400000000000000000000015531520105705100272430ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIICWTCCAboCFAdza9QZq6CfPqfzSNxSzZ11vT28MAoGCCqGSM49BAMEMGsxCzAJ BgNVBAYTAkRFMQswCQYDVQQIDAJCVzETMBEGA1UEBwwKQm9lYmxpbmdlbjEQMA4G A1UECgwHSUJNIFImRDETMBEGA1UECwwKTGludXggb24gWjETMBEGA1UEAwwKZWNw NTIxY2VydDAeFw0yMzA2MTQwOTA0NDFaFw0yNDA2MTMwOTA0NDFaMGsxCzAJBgNV BAYTAkRFMQswCQYDVQQIDAJCVzETMBEGA1UEBwwKQm9lYmxpbmdlbjEQMA4GA1UE CgwHSUJNIFImRDETMBEGA1UECwwKTGludXggb24gWjETMBEGA1UEAwwKZWNwNTIx Y2VydDCBmzAQBgcqhkjOPQIBBgUrgQQAIwOBhgAEAX2PjF+WBLGHuShlDlQY9Rlu lfmWVnLgil7HhDA/CuOuMl8TzLH0ZudOH3BFOztjv9nuajZmu4HIu40G4q6XX20M AHWjCF+FWl47bKwqOEtZF90y2z82zYOJJYvU5LsOPNKTlX9fbpRBh0KDzwHh2YR2 QI0dPXyI3cvSV3OzYzqGQf1QMAoGCCqGSM49BAMEA4GMADCBiAJCAQQRcnx0HLtV tne3c/yvQXbj5Vyi6w9m7Xfxwcz9atZnMQRPCwnx+etwIZwI6GpmhWNNcfSXnNgd zaXqe6z3KVOkAkIBQgEQw6tLjkFeI4KrQtxiA0B66yW+KXr6kcpxs3WRp5+ThqEB NrGP+MNWooLUt5XsP949ogMNasyAlb8LoJcSB0c= -----END CERTIFICATE----- opencryptoki-opencryptoki-451d99c/testcases/misc_tests/p11sak_ed25519cert.crt000066400000000000000000000007611520105705100272510ustar00rootroot000000000000000‚í0‚Ÿ 'Œ³yóçÈï_?©{Ͻ:˜ÅÍ€0+ep0l1 0 UDE1 0 U BW10U Boeblingen10U IBM R&D10U Linux on z10U ed25519cert0 250708115044Z 260708115044Z0l1 0 UDE1 0 U BW10U Boeblingen10U IBM R&D10U Linux on z10U ed25519cert0*0+ep!ä˜Ë™á&ư;/¡µ^æÄæÄú( Ă铃J~¯¨Zjf£S0Q0Uhâ’¢Ùk[ºâeiàè:í¯r0U#0€hâ’¢Ùk[ºâeiàè:í¯r0Uÿ0ÿ0+epAÙÀ´ ÅKÿûá¹; Nü®̃€E€X³Mă¸́ÚA=¼1—:ê—O0(=³-»A '¾ÓÇåopencryptoki-opencryptoki-451d99c/testcases/misc_tests/p11sak_ed25519cert.pem000066400000000000000000000013311520105705100272340ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIB7TCCAZ+gAwIBAgIUJ4yzD3nz58jvXz+pe8+9OpjFzYAwBQYDK2VwMGwxCzAJ BgNVBAYTAkRFMQswCQYDVQQIDAJCVzETMBEGA1UEBwwKQm9lYmxpbmdlbjEQMA4G A1UECgwHSUJNIFImRDETMBEGA1UECwwKTGludXggb24gejEUMBIGA1UEAwwLZWQy NTUxOWNlcnQwHhcNMjUwNzA4MTE1MDQ0WhcNMjYwNzA4MTE1MDQ0WjBsMQswCQYD VQQGEwJERTELMAkGA1UECAwCQlcxEzARBgNVBAcMCkJvZWJsaW5nZW4xEDAOBgNV BAoMB0lCTSBSJkQxEzARBgNVBAsMCkxpbnV4IG9uIHoxFDASBgNVBAMMC2VkMjU1 MTljZXJ0MCowBQYDK2VwAyEA5BaYy5nhJv07L6G1XhjmxObE+igLw+mTg0p+r6ha amajUzBRMB0GA1UdDgQWBBRo4gGSotkQa1u64mVp4Og6f+2vcjAfBgNVHSMEGDAW gBRo4gGSotkQa1u64mVp4Og6f+2vcjAPBgNVHRMBAf8EBTADAQH/MAUGAytlcANB ANnAtA3FDkv/+xcQ4bk7j5AbIE78rt6ARYCdWBazTeOduBXs2kE9vDGXOuqXngFP MCg9D7Mtu0HCDCcOvtPH5Qc= -----END CERTIFICATE----- opencryptoki-opencryptoki-451d99c/testcases/misc_tests/p11sak_ed448cert.crt000066400000000000000000000010701520105705100270750ustar00rootroot000000000000000‚40‚´ "ˆÎíq#ÿ Û5Zv[ G´²C0+eq0j1 0 UDE1 0 U BW10U Boeblingen10U IBM R&D10U Linux on z10U ed448cert0 250708115244Z 260708115244Z0j1 0 UDE1 0 U BW10U Boeblingen10U IBM R&D10U Linux on z10U ed448cert0C0+eq:WöY¶x9„¡K†«2Ī֙LÑj™¯v°ØưL”ff¸äÊ„T.Ét5‘az•Çyºl¬„`Í€£S0Q0UE!ưËú́ ±»„|r4ÈÉ ơ·7-0U#0€E!ưËú́ ±»„|r4ÈÉ ơ·7-0Uÿ0ÿ0+eqs]•³£°™{Q8dtéÄ}E¶càÄ®Rñrq:Ñ• ÙùçE?e÷ê$>#lƠĐLhqÉ‘g€N°gdw}z 38¡·e™¢NôK]Yh¾%n3æä+Æ̀£{Ÿ?ă¦¡ÜăZb>+#}ˆkµLkopencryptoki-opencryptoki-451d99c/testcases/misc_tests/p11sak_ed448cert.pem000066400000000000000000000014721520105705100270740ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIICNDCCAbSgAwIBAgIUIojOFO1xI/8L2zVadluOCUe0skMwBQYDK2VxMGoxCzAJ BgNVBAYTAkRFMQswCQYDVQQIDAJCVzETMBEGA1UEBwwKQm9lYmxpbmdlbjEQMA4G A1UECgwHSUJNIFImRDETMBEGA1UECwwKTGludXggb24gejESMBAGA1UEAwwJZWQ0 NDhjZXJ0MB4XDTI1MDcwODExNTI0NFoXDTI2MDcwODExNTI0NFowajELMAkGA1UE BhMCREUxCzAJBgNVBAgMAkJXMRMwEQYDVQQHDApCb2VibGluZ2VuMRAwDgYDVQQK DAdJQk0gUiZEMRMwEQYDVQQLDApMaW51eCBvbiB6MRIwEAYDVQQDDAllZDQ0OGNl cnQwQzAFBgMrZXEDOgBXig72WbZ4OYShS4arAzLEqtaZTNFqma92sJrY/UyUZma4 5AHKhFQuw4l0NZFhepXHebpsrIRgzYCjUzBRMB0GA1UdDgQWBBRFIf3L+uwJsbuE fHI0yMkL9bc3LTAfBgNVHSMEGDAWgBRFIf3L+uwJsbuEfHI0yMkL9bc3LTAPBgNV HRMBAf8EBTADAQH/MAUGAytlcQNzAF2Vs6OwmXtROGR06cR9gUWatmPgxK5SH/Fy cY860ZUKEtn5HudFP2X36iQ+IwZs1dBMaA5xyZFngBVOsGdkd316DTM4obdlmaKN TvRLXVloAL4lbjPm5CvGzKN7nz/jpheh3ONaYj6BKyN9iGu1TGsBAA== -----END CERTIFICATE----- opencryptoki-opencryptoki-451d99c/testcases/misc_tests/p11sak_rsa2048cert.crt000066400000000000000000000015431520105705100273550ustar00rootroot000000000000000‚_0‚GF®©¿l\›µ›Çé…óÔ¦s0  *†H†÷  0l1 0 UDE1 0 U BW10U Boeblingen10U IBM R&D10U Linux on Z10U rsa2048cert0 230614090440Z 240613090440Z0l1 0 UDE1 0 U BW10U Boeblingen10U IBM R&D10U Linux on Z10U rsa2048cert0‚"0  *†H†÷ ‚0‚ ‚Ô;Êwöù$ÍÂjLÄØÀe•$T6JRI[™zM­/ ĂR?6Ö¶7ơƠäIŸßơ~ w88£…ĐAtAâwV»8:*ÄŸU+`ưũÇÀàY9Ơɲ3éê₫((£ H‹[ÆjœD .\m˜)(̣-]̃û˜ß đ d’ÉV›Ơwz5ëô.ÅĬ²¦¯¯'ál¯% ™B-'gy¿‹ûÿ[®Û4ŒÂ›m½L̃|%ƒWO*¯SĐ`lµPc:¹!w“äéä꣖ëû÷"Ơʼnơ-©‡i9#“E¯Ú€¥;rêGäb¾a%]…íe"\“Ù0  *†H†÷  ‚Wœ[gĂÑi·YoIf~3剽¸ưmh¤w™Ôñ8ưu³Ñc›«éÁÖ­¿₫q½dR—á¢1µ̣>N4.€±¯yæzº„½¿ÿ»w{¸£Éé[O7¼Óh«¨HXS«"ÜÄCû;º}¤<|˜#y8ăăÅ bgPÓsüˆÛ¢2ƠPùJÁ† ]ç»…Đ‚èàg^¬…€s†[Ïm™Ûopencryptoki-opencryptoki-451d99c/testcases/misc_tests/p11sak_rsa2048cert.pem000066400000000000000000000023151520105705100273440ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDXzCCAkcCFAbBwznR4r5i39pagbUReBGDoBaWMA0GCSqGSIb3DQEBCwUAMGwx CzAJBgNVBAYTAkRFMQswCQYDVQQIDAJCVzETMBEGA1UEBwwKQm9lYmxpbmdlbjEQ MA4GA1UECgwHSUJNIFImRDETMBEGA1UECwwKTGludXggb24gWjEUMBIGA1UEAwwL cnNhMjA0OGNlcnQwHhcNMjMwNjE0MDkwNDQwWhcNMjQwNjEzMDkwNDQwWjBsMQsw CQYDVQQGEwJERTELMAkGA1UECAwCQlcxEzARBgNVBAcMCkJvZWJsaW5nZW4xEDAO BgNVBAoMB0lCTSBSJkQxEzARBgNVBAsMCkxpbnV4IG9uIFoxFDASBgNVBAMMC3Jz YTIwNDhjZXJ0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1DvKd/b5 JIqOzcJqTMR/gQTYEMBllQgkHhVUNkpSEUlbmXoZTa0vIMNSPzbWtjf11eRJwp/f 9X4JgXc4OKOF0EF0QeJ3Vrs4OirEn1UrYP113sfA4FmQgTkV1cmyMxvp6v4oKKOg SItbxhJqnESQCy5cbZgpKPItXd4AkPuY3wvwHAtkkslWm9V3ejXrGfQuFMXErLKm r68ZJ+FsrxYlDJlCLScFZ3m/i/v/W67bNIzCm229TN6efCUTg1dPKq9T0ACaYA9s tVCaYzq5IXeT5Oke5Oqjluv79yLVxYn1LamHaTkjk0Wv2oClO3IC6ppHGAHkYr5h JV2F7WUiXJPZAwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQCl/QSfiruMq7FogogS Y2FYXqqof66/Vsz+SLsxDW8gB3N2+KTD/tf038HR52eE5TLv7B9vAtbA4RJAVF/e 6VFgxKPkMM7xIvq9mXGS0nsH80NrXZs4zhYKCoTOQ/JHddCgd5OBWVoX0/l9eI/P Teqw5RdfI7li9aIFL48jqRBa6+3WcKrS4Ue+mz6deJxYfLPvJI4bI6o1D8fZilfe D8KS2YkBkCjt8d8jzoDQKizjaJXA67pddVBLIHkb/Ho0COMH5NBzo1vc9WZJkNEO NTpJ6LRqxBIh8qEytd+d7+RGklrIkDGD5YQM591BocaeUTdfHfQdhWi17q6StN+y 4X6w -----END CERTIFICATE----- opencryptoki-opencryptoki-451d99c/testcases/misc_tests/p11sak_rsa4096cert.crt000066400000000000000000000025431520105705100273630ustar00rootroot000000000000000‚_0‚GzW)>…ÅŸ̉ÔE˜ß®[à0  *†H†÷  0l1 0 UDE1 0 U BW10U Boeblingen10U IBM R&D10U Linux on Z10U rsa4096cert0 230614090441Z 240613090441Z0l1 0 UDE1 0 U BW10U Boeblingen10U IBM R&D10U Linux on Z10U rsa4096cert0‚"0  *†H†÷ ‚0‚ ‚¢Ë“lo¨AxnKw}×&9|Dk#ÅNA‹Sí¦,»j&ốêÍÈé‡ÍCw¾í+ÀÙÏo˜a ü¯R€¸ÛË«€­®#@)]÷`F|Ó’f?ß-Ơ&4Ưqç€mABÜ_É)N@¡ƒù‰>Gy¼C…7´¶g-÷/đ5đ&ó+|N,Á hßÂ0õúIwkÉ̃XBcD–jÚ^ a®]¶± QK8/¬ÏOdR,̃zdPT½'’„–r†ÿJ°̃ôS/œÛ1̀À[Ï|-ẽ´Ës(„o#̣.XƒaƠ‹˜ÏM Ă—C˜ẴV0Jè9öbÿÛúAJÿ¤184K¯ A₫ ê1ÇE¶|éfU:¯—©,¸Æá¨nU¸B)IÇd^·ƯIöƠX‹ßL¨}»„Û Ü_ŵ}(kµ¡¹.3mhFçÇ ½–Ëîl3©¡-ù ÜÁFÔÉĐ` ùQ¶·$p’xk̀÷Ȉ¾“†¥Å»"²¿’Qhª̀°ˆ­,>ÿư-kV“è.C=‘¼{¾)]¸̉!DˆÚÏR§!F>úM“ú¨M¹T~a¿™°CøÂ¿‚ØÙ§¤°Pû‡(È>hŸØ˜"v«·ùÜ$K#)ļü*2/$ÛEqÇ›¦Ï/]§±ªC‹íI8âÖÀ•!oëUL6sJ< ¿ô x!U½Vz‚Lt}D Åns—Ë1÷ïM1ß«±ÛÉ]Úª¥/“µÛ5|½…Ođ¤¬¡"îư#/tqܾ́péƯrÎV> @îo0Ù{b‹Vy¨Äopencryptoki-opencryptoki-451d99c/testcases/misc_tests/p11sak_rsa4096cert.pem000066400000000000000000000036031520105705100273520ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIFXzCCA0cCFHFYf+MzQnELrLEhPD4Es7JlpqsbMA0GCSqGSIb3DQEBCwUAMGwx CzAJBgNVBAYTAkRFMQswCQYDVQQIDAJCVzETMBEGA1UEBwwKQm9lYmxpbmdlbjEQ MA4GA1UECgwHSUJNIFImRDETMBEGA1UECwwKTGludXggb24gWjEUMBIGA1UEAwwL cnNhNDA5NmNlcnQwHhcNMjMwNjE0MDkwNDQxWhcNMjQwNjEzMDkwNDQxWjBsMQsw CQYDVQQGEwJERTELMAkGA1UECAwCQlcxEzARBgNVBAcMCkJvZWJsaW5nZW4xEDAO BgNVBAoMB0lCTSBSJkQxEzARBgNVBAsMCkxpbnV4IG9uIFoxFDASBgNVBAMMC3Jz YTQwOTZjZXJ0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAosuPk2xv qEEHeG5Ld33XJjl8RGsjxU5Bi1PtGqYHLLtqJvTs6g/NyOmHzUN3vu0rAMDZz49v mGGgEfyvUoC4f9vLq4CtriNAKV33YAJGfNOSZj/fLdUmNN1x54BtQULcX8kpTkCh g/mJPhNHebxDhTe0tmct9y/wjzXwJvMrfE4swaBo38Iww7X6SXdryd5YQmNEA42W atpeDWGuXbaxCVFLOC+sFM9PHmRSLN4WehxkUFSOvSeShJZyhv+KSrDeEfRTL5zb MczAW898LWXetMtzKBqECJ1vniPyLgJYg2HVi5jPE02gw5dDmMPef1YwSug5BfZi /9v6QUoC/8IapDE4ATQWS68KQR7+Ceoxx0W2fOlmVTqvl6ksuMbhqI1uVbhCKUnH ZF633RhJ9tUdWIvfTKh9uxmE2w3cX4/FtX0oa7WhuS4zbWhG58egvZYCy+5sFzOp oS35DQQY3MGKRtTJ0GAM+VG2tyRwknhrzBn3yIi+k4alxbsQIrK/klFoqsywiK0s Pv/9LWtWk+gVLkM9kY+8e74pXbjSIQREiNrPUqchkEY++o1Nk/qoTZoIuVR+Yb+Z sEMO+MK/gtjZp6SwUPuHKMg+aJ/YmCIcdqu3+dwkSyMpxLz8KjIvPG4iH7rLCf0O OWNs7Rp3txGeXf58oV7LObc3IM/DTPTHMYUCAwEAATANBgkqhkiG9w0BAQsFAAOC AgEARhVXoHfwrQI0EWdE1g4niy9QB2nFbE+ISzLcI87S0/fCEk9L5jOlCzJpOrmG 5bUqVCjVTA/MOFZPZ6a1awVbkBZyPsxbxrw6fGcAGIXIGJ77haZrcNSv8O4WlpeJ bDbGksXEr4dljoamuArUVlQyDtPlCT8Qi8oi+HlqDaZJ+OYJWSiw2v1KBb/gbPLf i2J3LT80oDd+McobjpJowg+xO2vJ0dFdfzYYdV716vsSpt1xOZWYtDE0edFEJDmn pYZtOlqTqPxagrQ6j+sc+xcTLSVNt6XMwdgpcF7kzCr63gHjWUSTUqjBCgtA3jaK DK/V1sbo5BOYOeZKvlfTPNw2oA9MbyKuurpjfpinSwUG/s/ankR7URbx7Qh4QTz/ QaQ7sGWPX7jK997G1nPYqjELjhLRK8I4cMOV5ilQSeyN+77KVI9b6ZW5ARdV1acb ThUikHGFmbc665X1fy6ex0iSY0Juocn2IR5zFk3e63q+6TTONf1EEaq3uczn/9J6 iykYvscTowoiKFc45DZEdEFgu62P3Jy66Ef9kKswBYs40n1KqxSVJyam8asuIdCL 2g0+Tb2dXvc6hpX19pZbosC4sUHeoTL194XzowGd8s++dzltAIwIFHcBOnUJcPai /5/5DSR2eclqwoYNCNc4SPSDPV76jKNFTbuQhlIBvcn6ejQ= -----END CERTIFICATE----- opencryptoki-opencryptoki-451d99c/testcases/misc_tests/p11sak_test.sh000077500000000000000000004450741520105705100262130ustar00rootroot00000000000000#!/bin/bash # # 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 # - The PKCS11_USER_PIN environment variable must hold the user pin. # - The SLOT environment variable must hold the slot id of the token under test. # # sudo -E ./p11sak_test.sh DIR=$(dirname "$0") status=0 echo "** Now executing 'p11sak_test.sh'" # tmp files P11SAK_DES_PRE=p11sak-des-pre.out P11SAK_DES_LONG=p11sak-des-long.out P11SAK_DES_POST=p11sak-des-post.out P11SAK_3DES_PRE=p11sak-3des-pre.out P11SAK_3DES_LONG=p11sak-3des-long.out P11SAK_3DES_POST=p11sak-3des-post.out P11SAK_GENERIC_PRE=p11sak-generic-pre.out P11SAK_GENERIC_LONG=p11sak-generic-long.out P11SAK_GENERIC_POST=p11sak-generic-post.out P11SAK_AES_PRE=p11sak-aes-pre.out P11SAK_AES_LONG=p11sak-aes-long.out P11SAK_AES_POST=p11sak-aes-post.out P11SAK_AES_XTS_PRE=p11sak-aes-xts-pre.out P11SAK_AES_XTS_LONG=p11sak-aes-xts-long.out P11SAK_AES_XTS_POST=p11sak-aes-xts-post.out P11SAK_RSA_PRE=p11sak-rsa-pre.out P11SAK_RSA_LONG=p11sak-rsa-long.out P11SAK_RSA_POST=p11sak-rsa-post.out P11SAK_DH_PRE=p11sak-dh-pre.out P11SAK_DH_LONG=p11sak-dh-long.out P11SAK_DH_POST=p11sak-dh-post.out P11SAK_DSA_PRE=p11sak-dsa-pre.out P11SAK_DSA_LONG=p11sak-dsa-long.out P11SAK_DSA_POST=p11sak-dsa-post.out P11SAK_EC_PRE=p11sak-ec-pre.out P11SAK_EC_LONG=p11sak-ec-long.out P11SAK_EC_POST=p11sak-ec-post.out P11SAK_EC_EDWARDS_PRE=p11sak-ec-edwards-pre.out P11SAK_EC_EDWARDS_LONG=p11sak-ec-edwards-long.out P11SAK_EC_EDWARDS_POST=p11sak-ec-edwards-post.out P11SAK_EC_MONTGOMERY_PRE=p11sak-ec-montgomery-pre.out P11SAK_EC_MONTGOMERY_LONG=p11sak-ec-montgomery-long.out P11SAK_EC_MONTGOMERY_POST=p11sak-ec-montgomery-post.out P11SAK_IBM_DILITHIUM_PRE=p11sak-ibm-dilithium-pre.out P11SAK_IBM_DILITHIUM_LONG=p11sak-ibm-dilithium-long.out P11SAK_IBM_DILITHIUM_POST=p11sak-ibm-dilithium-post.out P11SAK_IBM_KYBER_PRE=p11sak-ibm-kyber-pre.out P11SAK_IBM_KYBER_LONG=p11sak-ibm-kyber-long.out P11SAK_IBM_KYBER_POST=p11sak-ibm-kyber-post.out P11SAK_IBM_ML_DSA_PRE=p11sak-ibm-ml-dsa-pre.out P11SAK_IBM_ML_DSA_LONG=p11sak-ibm-ml-dsa-long.out P11SAK_IBM_ML_DSA_POST=p11sak-ibm-ml-dsa-post.out P11SAK_IBM_ML_KEM_PRE=p11sak-ibm-ml-kem-pre.out P11SAK_IBM_ML_KEM_LONG=p11sak-ibm-ml-kem-long.out P11SAK_IBM_ML_KEM_POST=p11sak-ibm-ml-kem-post.out P11SAK_ML_DSA_PRE=p11sak-ml-dsa-pre.out P11SAK_ML_DSA_LONG=p11sak-ml-dsa-long.out P11SAK_ML_DSA_POST=p11sak-ml-dsa-post.out P11SAK_ML_KEM_PRE=p11sak-ml-kem-pre.out P11SAK_ML_KEM_LONG=p11sak-ml-kem-long.out P11SAK_ML_KEM_POST=p11sak-ml-kem-post.out P11SAK_ALL_PINOPT=p11sak-all-pinopt P11SAK_ALL_PINENV=p11sak-all-pinenv P11SAK_ALL_PINCON=p11sak-all-pincon P11SAK_ALL_NOLOGIN=p11sak-all-nologin P11SAK_ALL_SO=p11sak-all-so P11SAK_X509_PRE=p11sak-x509-pre.out P11SAK_X509_LONG=p11sak-x509-long.out P11SAK_X509_POST=p11sak-x509-post.out echo "** Setting SLOT=30 to the Softtoken unless otherwise set - 'p11sak_test.sh'" # Validate required environment variables if [[ -z "${PKCS11_USER_PIN}" ]]; then echo "Please set the PKCS11_USER_PIN environment variable" exit 1 fi # setting SLOT=30 to the Softtoken SLOT=${SLOT:-30} # check if p11sak is available in the current $PATH - if it isn't, ask for # SBINDIR to be defined before this script executes. # The assumption here is that p11sak and pkcsconf are installed in the same # directory - if one is found, the other is assumed to be available as well. if [[ -n "$(command -v pkcsconf)" ]]; then PKCSCONF=pkcsconf P11SAK=p11sak elif [[ -z "$SBINDIR" ]]; then echo "pkcsconf and/or p11sak were not found in \$PATH." echo "Define \$SBINDIR to the appropriate path and try again." exit 1 else PKCSCONF=${SBINDIR}/pkcsconf P11SAK=${SBINDIR}/p11sak fi echo "** Using Slot $SLOT with PKCS11_USER_PIN $PKCS11_USER_PIN and PKCSLIB $PKCSLIB - 'p11sak_test.sh'" echo "** Now generating keys - 'p11sak_test.sh'" # generate objects RC_P11SAK_GENERATE=0 # des if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_DES_KEY_GEN) ]]; then ${P11SAK} generate-key des --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-des" RC_P11SAK_GENERATE=$((RC_P11SAK_GENERATE + $?)) else echo "Skip generating des keys, slot does not support CKM_DES_KEY_GEN" fi # 3des ${P11SAK} generate-key 3des --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-3des" RC_P11SAK_GENERATE=$((RC_P11SAK_GENERATE + $?)) # generic ${P11SAK} generate-key generic 256 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-generic" RC_P11SAK_GENERATE=$((RC_P11SAK_GENERATE + $?)) # aes [128 | 192 | 256] ${P11SAK} generate-key aes 128 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-aes-128" RC_P11SAK_GENERATE=$((RC_P11SAK_GENERATE + $?)) ${P11SAK} generate-key aes 192 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-aes-192" RC_P11SAK_GENERATE=$((RC_P11SAK_GENERATE + $?)) ${P11SAK} generate-key aes 256 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-aes-256" RC_P11SAK_GENERATE=$((RC_P11SAK_GENERATE + $?)) # aes-xts [128 | 256] if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_AES_XTS_KEY_GEN) ]]; then if [[ -n $( ${PKCSCONF} -t -c $SLOT | grep "Model: EP11") || -n $( ${PKCSCONF} -t -c $SLOT | grep "Model: CCA") ]]; then # EP11 needs CKA_IBM_PROTKEY_EXTRACTABLE=TRUE and CKA_EXTRACTABLE=FALSE for AES-XTS keys # CCA needs CKA_IBM_PROTKEY_EXTRACTABLE=TRUE for AES-XTS keys P11SAK_ATTR="--attr xK" else P11SAK_ATTR="" fi ${P11SAK} generate-key aes-xts 128 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-aes-xts-128" $P11SAK_ATTR RC_P11SAK_GENERATE=$((RC_P11SAK_GENERATE + $?)) ${P11SAK} generate-key aes-xts 256 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-aes-xts-256" $P11SAK_ATTR RC_P11SAK_GENERATE=$((RC_P11SAK_GENERATE + $?)) else echo "Skip generating aes-xts keys, slot does not support CKM_AES_XTS_KEY_GEN" fi # rsa [1024 | 2048 | 4096] ${P11SAK} generate-key rsa 1024 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-rsa-1024" RC_P11SAK_GENERATE=$((RC_P11SAK_GENERATE + $?)) ${P11SAK} generate-key rsa 2048 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-rsa-2048" RC_P11SAK_GENERATE=$((RC_P11SAK_GENERATE + $?)) ${P11SAK} generate-key rsa 4096 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-rsa-4096" RC_P11SAK_GENERATE=$((RC_P11SAK_GENERATE + $?)) # dh ffdhe2048 if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_DH_PKCS_KEY_PAIR_GEN) ]]; then ${P11SAK} generate-key dh ffdhe2048 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-dh" RC_P11SAK_GENERATE=$((RC_P11SAK_GENERATE + $?)) else echo "Skip generating dh keys, slot does not support CKM_DH_PKCS_KEY_PAIR_GEN" fi # dsa dsa-param.pem if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_DSA_KEY_PAIR_GEN) ]]; then ${P11SAK} generate-key dsa $DIR/dsa-param.pem --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-dsa" RC_P11SAK_GENERATE=$((RC_P11SAK_GENERATE + $?)) else echo "Skip generating dsa keys, slot does not support CKM_DSA_KEY_PAIR_GEN" fi # ec [prime256v1 | secp384r1 | secp521r1] ${P11SAK} generate-key ec prime256v1 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ec-prime256v1" RC_P11SAK_GENERATE=$((RC_P11SAK_GENERATE + $?)) ${P11SAK} generate-key ec secp384r1 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ec-secp384r1" RC_P11SAK_GENERATE=$((RC_P11SAK_GENERATE + $?)) ${P11SAK} generate-key ec secp521r1 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ec-secp521r1" RC_P11SAK_GENERATE=$((RC_P11SAK_GENERATE + $?)) # ec-edwards [ed25519 | ed448] if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_EC_EDWARDS_KEY_PAIR_GEN) ]]; then ${P11SAK} generate-key ec-edwards ed25519 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ec-edwards-ed25519" RC_P11SAK_GENERATE=$((RC_P11SAK_GENERATE + $?)) ${P11SAK} generate-key ec-edwards ed448 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ec-edwards-ed448" RC_P11SAK_GENERATE=$((RC_P11SAK_GENERATE + $?)) else echo "Skip generating ec-edwards keys, slot does not support CKM_EC_EDWARDS_KEY_PAIR_GEN" fi # ec-montgomery [curve25519 | curve448] if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_EC_MONTGOMERY_KEY_PAIR_GEN) ]]; then ${P11SAK} generate-key ec-montgomery curve25519 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ec-montgomery-x25519" RC_P11SAK_GENERATE=$((RC_P11SAK_GENERATE + $?)) ${P11SAK} generate-key ec-montgomery curve448 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ec-montgomery-x448" RC_P11SAK_GENERATE=$((RC_P11SAK_GENERATE + $?)) else echo "Skip generating ec-montgomery keys, slot does not support CKM_EC_MONTGOMERY_KEY_PAIR_GEN" fi # ibm-dilithium if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_IBM_DILITHIUM) ]]; then if [[ -z $( ${PKCSCONF} -t -c $SLOT | grep "Model: Soft") ]]; then ${P11SAK} generate-key ibm-dilithium r2_65 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ibm-dilithium" RC_P11SAK_GENERATE=$((RC_P11SAK_GENERATE + $?)) else ${P11SAK} generate-key ibm-dilithium r3_65 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ibm-dilithium" RC_P11SAK_GENERATE=$((RC_P11SAK_GENERATE + $?)) fi else echo "Skip generating ibm-dilithium keys, slot does not support CKM_IBM_DILITHIUM" fi # ibm-kyber if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_IBM_KYBER) ]]; then ${P11SAK} generate-key ibm-kyber r2_1024 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ibm-kyber" RC_P11SAK_GENERATE=$((RC_P11SAK_GENERATE + $?)) else echo "Skip generating ibm-kyber keys, slot does not support CKM_IBM_KYBER" fi # ibm-ml-dsa if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_IBM_ML_DSA) ]]; then ${P11SAK} generate-key ibm-ml-dsa 65 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ibm-ml-dsa" RC_P11SAK_GENERATE=$((RC_P11SAK_GENERATE + $?)) else echo "Skip generating ibm-ml-dsa keys, slot does not support CKM_IBM_ML_DSA" fi # ibm-ml-kem if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_IBM_ML_KEM) ]]; then ${P11SAK} generate-key ibm-ml-kem 1024 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ibm-ml-kem" RC_P11SAK_GENERATE=$((RC_P11SAK_GENERATE + $?)) else echo "Skip generating ibm-ml-kem keys, slot does not support CKM_IBM_ML_KEM" fi # ml-dsa if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_ML_DSA) ]]; then ${P11SAK} generate-key ml-dsa 65 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ml-dsa" RC_P11SAK_GENERATE=$((RC_P11SAK_GENERATE + $?)) else echo "Skip generating ml-dsa keys, slot does not support CKM_ML_DSA" fi # ml-kem if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_ML_KEM) ]]; then ${P11SAK} generate-key ml-kem 1024 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ml-kem" RC_P11SAK_GENERATE=$((RC_P11SAK_GENERATE + $?)) else echo "Skip generating ml-kem keys, slot does not support CKM_IBM_ML_KEM" fi echo "** Now list keys and redirect output to pre-files - 'p11sak_test.sh'" # list objects RC_P11SAK_LIST=0 ${P11SAK} list-key des --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-des" &> $P11SAK_DES_PRE RC_P11SAK_LIST=$((RC_P11SAK_LIST + $?)) ${P11SAK} list-key 3des --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-3des" &> $P11SAK_3DES_PRE RC_P11SAK_LIST=$((RC_P11SAK_LIST + $?)) ${P11SAK} list-key generic --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-generic" &> $P11SAK_GENERIC_PRE RC_P11SAK_LIST=$((RC_P11SAK_LIST + $?)) ${P11SAK} list-key aes --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-aes-*" &> $P11SAK_AES_PRE RC_P11SAK_LIST=$((RC_P11SAK_LIST + $?)) ${P11SAK} list-key aes-xts --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-aes-xts-*" &> $P11SAK_AES_XTS_PRE RC_P11SAK_LIST=$((RC_P11SAK_LIST + $?)) ${P11SAK} list-key rsa --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-rsa-*" &> $P11SAK_RSA_PRE RC_P11SAK_LIST=$((RC_P11SAK_LIST + $?)) ${P11SAK} list-key dh --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-dh*" &> $P11SAK_DH_PRE RC_P11SAK_LIST=$((RC_P11SAK_LIST + $?)) ${P11SAK} list-key dsa --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-dsa*" &> $P11SAK_DSA_PRE RC_P11SAK_LIST=$((RC_P11SAK_LIST + $?)) ${P11SAK} list-key ec --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ec-*" &> $P11SAK_EC_PRE RC_P11SAK_LIST=$((RC_P11SAK_LIST + $?)) ${P11SAK} list-key ec-edwards --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ec-edwards-*" &> $P11SAK_EC_EDWARDS_PRE RC_P11SAK_LIST=$((RC_P11SAK_LIST + $?)) ${P11SAK} list-key ec-montgomery --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ec-*" &> $P11SAK_EC_MONTGOMERY_PRE RC_P11SAK_LIST=$((RC_P11SAK_LIST + $?)) ${P11SAK} list-key ibm-dilithium --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ibm-dilithium*" &> $P11SAK_IBM_DILITHIUM_PRE RC_P11SAK_LIST=$((RC_P11SAK_LIST + $?)) ${P11SAK} list-key ibm-kyber --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ibm-kyber*" &> $P11SAK_IBM_KYBER_PRE RC_P11SAK_LIST=$((RC_P11SAK_LIST + $?)) ${P11SAK} list-key ibm-ml-dsa --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ibm-ml-dsa*" &> $P11SAK_IBM_ML_DSA_PRE RC_P11SAK_LIST=$((RC_P11SAK_LIST + $?)) ${P11SAK} list-key ibm-ml-kem --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ibm-ml-kem*" &> $P11SAK_IBM_ML_KEM_PRE RC_P11SAK_LIST=$((RC_P11SAK_LIST + $?)) ${P11SAK} list-key ml-dsa --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ml-dsa*" &> $P11SAK_ML_DSA_PRE RC_P11SAK_LIST=$((RC_P11SAK_LIST + $?)) ${P11SAK} list-key ml-kem --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ml-kem*" &> $P11SAK_ML_KEM_PRE RC_P11SAK_LIST=$((RC_P11SAK_LIST + $?)) RC_P11SAK_LIST_LONG=0 ${P11SAK} list-key des --slot $SLOT --pin $PKCS11_USER_PIN --long --label "p11sak-des" &> $P11SAK_DES_LONG RC_P11SAK_LIST_LONG=$((RC_P11SAK_LIST_LONG + $?)) ${P11SAK} list-key 3des --slot $SLOT --pin $PKCS11_USER_PIN --long --label "p11sak-3des" &> $P11SAK_3DES_LONG RC_P11SAK_LIST_LONG=$((RC_P11SAK_LIST_LONG + $?)) ${P11SAK} list-key generic --slot $SLOT --pin $PKCS11_USER_PIN --long --label "p11sak-generic" &> $P11SAK_GENERIC_LONG RC_P11SAK_LIST_LONG=$((RC_P11SAK_LIST_LONG + $?)) ${P11SAK} list-key aes --slot $SLOT --pin $PKCS11_USER_PIN --long --label "p11sak-aes-*" &> $P11SAK_AES_LONG RC_P11SAK_LIST_LONG=$((RC_P11SAK_LIST_LONG + $?)) ${P11SAK} list-key aes-xts --slot $SLOT --pin $PKCS11_USER_PIN --long --label "p11sak-aes-xts-*" &> $P11SAK_AES_XTS_LONG RC_P11SAK_LIST_LONG=$((RC_P11SAK_LIST_LONG + $?)) ${P11SAK} list-key rsa --slot $SLOT --pin $PKCS11_USER_PIN --long --label "p11sak-rsa-*" &> $P11SAK_RSA_LONG RC_P11SAK_LIST_LONG=$((RC_P11SAK_LIST_LONG + $?)) ${P11SAK} list-key dh --slot $SLOT --pin $PKCS11_USER_PIN --long --label "p11sak-dh*" &> $P11SAK_DH_LONG RC_P11SAK_LIST_LONG=$((RC_P11SAK_LIST_LONG + $?)) ${P11SAK} list-key dsa --slot $SLOT --pin $PKCS11_USER_PIN --long --label "p11sak-dsa*" &> $P11SAK_DSA_LONG RC_P11SAK_LIST_LONG=$((RC_P11SAK_LIST_LONG + $?)) ${P11SAK} list-key ec --slot $SLOT --pin $PKCS11_USER_PIN --long --label "p11sak-ec-*" &> $P11SAK_EC_LONG RC_P11SAK_LIST_LONG=$((RC_P11SAK_LIST_LONG + $?)) ${P11SAK} list-key ec-edwards --slot $SLOT --pin $PKCS11_USER_PIN --long --label "p11sak-ec-edwards*" &> $P11SAK_EC_EDWARDS_LONG RC_P11SAK_LIST_LONG=$((RC_P11SAK_LIST_LONG + $?)) ${P11SAK} list-key ec-montgomery --slot $SLOT --pin $PKCS11_USER_PIN --long --label "p11sak-ec-montgomery*" &> $P11SAK_EC_MONTGOMERY_LONG RC_P11SAK_LIST_LONG=$((RC_P11SAK_LIST_LONG + $?)) ${P11SAK} list-key ibm-dilithium --slot $SLOT --pin $PKCS11_USER_PIN --long --label "p11sak-ibm-dilithium*" &> $P11SAK_IBM_DILITHIUM_LONG RC_P11SAK_LIST_LONG=$((RC_P11SAK_LIST_LONG + $?)) ${P11SAK} list-key ibm-kyber --slot $SLOT --pin $PKCS11_USER_PIN --long --label "p11sak-ibm-kyber*" &> $P11SAK_IBM_KYBER_LONG RC_P11SAK_LIST_LONG=$((RC_P11SAK_LIST_LONG + $?)) ${P11SAK} list-key ibm-ml-dsa --slot $SLOT --pin $PKCS11_USER_PIN --long --label "p11sak-ibm-ml-dsa*" &> $P11SAK_IBM_ML_DSA_LONG RC_P11SAK_LIST_LONG=$((RC_P11SAK_LIST_LONG + $?)) ${P11SAK} list-key ibm-ml-kem --slot $SLOT --pin $PKCS11_USER_PIN --long --label "p11sak-ibm-ml-kem*" &> $P11SAK_IBM_ML_KEM_LONG RC_P11SAK_LIST_LONG=$((RC_P11SAK_LIST_LONG + $?)) ${P11SAK} list-key ml-dsa --slot $SLOT --pin $PKCS11_USER_PIN --long --label "p11sak-ml-dsa*" &> $P11SAK_ML_DSA_LONG RC_P11SAK_LIST_LONG=$((RC_P11SAK_LIST_LONG + $?)) ${P11SAK} list-key ml-kem --slot $SLOT --pin $PKCS11_USER_PIN --long --label "p11sak-ml-kem*" &> $P11SAK_ML_KEM_LONG RC_P11SAK_LIST_LONG=$((RC_P11SAK_LIST_LONG + $?)) ${P11SAK} list-key all --slot $SLOT --pin $PKCS11_USER_PIN &> $P11SAK_ALL_PINOPT RC_P11SAK_PINOPT=$? ${P11SAK} list-key all --slot $SLOT &> $P11SAK_ALL_PINENV RC_P11SAK_PINENV=$? printf "${PKCS11_USER_PIN}\n" | ${P11SAK} list-key all --slot $SLOT --force-pin-prompt | tail -n +2 &> $P11SAK_ALL_PINCON RC_P11SAK_PINCON=$? ${P11SAK} list-key all --slot $SLOT --no-login &> $P11SAK_ALL_NOLOGIN RC_P11SAK_NOLOGIN=$? if [[ -n $PKCS11_SO_PIN ]]; then ${P11SAK} list-key all --slot $SLOT --pin $PKCS11_SO_PIN --so &> $P11SAK_ALL_SO RC_P11SAK_SO=$? else echo "Skip login as SO, PKCS11_SO_PIN is not set" fi echo "** Now updating keys - 'p11sak_test.sh'" RC_P11SAK_UPDATE=0 ${P11SAK} set-key-attr aes --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-aes-*" --new-attr "ed" --force RC_P11SAK_UPDATE=$((RC_P11SAK_UPDATE + $?)) ${P11SAK} set-key-attr rsa --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-rsa-*" --new-id "012345" --force RC_P11SAK_UPDATE=$((RC_P11SAK_UPDATE + $?)) echo "** Now copying keys - 'p11sak_test.sh'" RC_P11SAK_COPY=0 ${P11SAK} copy-key aes --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-aes-*" --new-label "p11sak-aes-copied" --new-attr "ED" --force RC_P11SAK_COPY=$((RC_P11SAK_COPY + $?)) echo "** Now extracting public keys - 'p11sak_test.sh'" RC_P11SAK_KEY_EXTRACT=0 ${P11SAK} extract-pubkey private --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-rsa-*" --new-label "p11sak-pubkey-extracted" --force RC_P11SAK_KEY_EXTRACT=$((RC_P11SAK_KEY_EXTRACT + $?)) ${P11SAK} extract-pubkey private --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-dh*" --new-label "p11sak-pubkey-extracted" --force RC_P11SAK_KEY_EXTRACT=$((RC_P11SAK_KEY_EXTRACT + $?)) ${P11SAK} extract-pubkey private --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-dsa*" --new-label "p11sak-pubkey-extracted" --force RC_P11SAK_KEY_EXTRACT=$((RC_P11SAK_KEY_EXTRACT + $?)) ${P11SAK} extract-pubkey private --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ec-prime256v1*" --new-label "p11sak-pubkey-extracted" --force RC_P11SAK_KEY_EXTRACT=$((RC_P11SAK_KEY_EXTRACT + $?)) ${P11SAK} extract-pubkey private --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ec-edwards-ed25519*" --new-label "p11sak-pubkey-extracted" --force RC_P11SAK_KEY_EXTRACT=$((RC_P11SAK_KEY_EXTRACT + $?)) ${P11SAK} extract-pubkey private --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ec-montgomery-curve448*" --new-label "p11sak-pubkey-extracted" --force RC_P11SAK_KEY_EXTRACT=$((RC_P11SAK_KEY_EXTRACT + $?)) ${P11SAK} extract-pubkey private --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ibm-dilithium*" --new-label "p11sak-pubkey-extracted" --force RC_P11SAK_KEY_EXTRACT=$((RC_P11SAK_KEY_EXTRACT + $?)) ${P11SAK} extract-pubkey private --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ibm-kyber*" --new-label "p11sak-pubkey-extracted" --force RC_P11SAK_KEY_EXTRACT=$((RC_P11SAK_KEY_EXTRACT + $?)) ${P11SAK} extract-pubkey private --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ibm-ml-dsa*" --new-label "p11sak-pubkey-extracted" --force RC_P11SAK_KEY_EXTRACT=$((RC_P11SAK_KEY_EXTRACT + $?)) ${P11SAK} extract-pubkey private --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ibm-ml-kem*" --new-label "p11sak-pubkey-extracted" --force RC_P11SAK_KEY_EXTRACT=$((RC_P11SAK_KEY_EXTRACT + $?)) ${P11SAK} extract-pubkey private --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ml-dsa*" --new-label "p11sak-pubkey-extracted" --force RC_P11SAK_KEY_EXTRACT=$((RC_P11SAK_KEY_EXTRACT + $?)) ${P11SAK} extract-pubkey private --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ml-kem*" --new-label "p11sak-pubkey-extracted" --force RC_P11SAK_KEY_EXTRACT=$((RC_P11SAK_KEY_EXTRACT + $?)) echo "** Now importing keys - 'p11sak_test.sh'" RC_P11SAK_IMPORT=0 # aes ${P11SAK} import-key aes --slot $SLOT --pin $PKCS11_USER_PIN --label "import-aes" --file $DIR/aes.key --attr sX RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) # rsa ${P11SAK} import-key rsa private --slot $SLOT --pin $PKCS11_USER_PIN --label "import-rsa-private" --file $DIR/rsa-key.pem --attr sX RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) ${P11SAK} import-key rsa public --slot $SLOT --pin $PKCS11_USER_PIN --label "import-rsa-public" --file $DIR/rsa-key.pem --attr sX RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) # dsa if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_DSA) ]]; then ${P11SAK} import-key dsa private --slot $SLOT --pin $PKCS11_USER_PIN --label "import-dsa-private" --file $DIR/dsa-key.pem --attr sX RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) ${P11SAK} import-key dsa public --slot $SLOT --pin $PKCS11_USER_PIN --label "import-dsa-public" --file $DIR/dsa-key.pem --attr sX RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) else echo "Skip importing dsa keys, slot does not support CKM_DSA" fi # dh if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_DH_PKCS_DERIVE) ]]; then ${P11SAK} import-key dh private --slot $SLOT --pin $PKCS11_USER_PIN --label "import-dh-private" --file $DIR/dh-key.pem --attr sX RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) ${P11SAK} import-key dh public --slot $SLOT --pin $PKCS11_USER_PIN --label "import-dh-public" --file $DIR/dh-key.pem --attr sX RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) else echo "Skip importing dh keys, slot does not support CKM_DH_PKCS_DERIVE" fi # ec ${P11SAK} import-key ec private --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ec-prime256v1-private" --file $DIR/ec-key-prime256v1.pem --attr sX RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) ${P11SAK} import-key ec public --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ec-prime256v1-public" --file $DIR/ec-key-prime256v1.pem --attr sX RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) ${P11SAK} import-key ec private --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ec-secp521r1-private" --file $DIR/ec-key-secp521r1.pem --attr sX RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) ${P11SAK} import-key ec public --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ec-secp521r1-public" --file $DIR/ec-key-secp521r1.pem --attr sX RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) # edwards/montgomery if [[ -n $(openssl version | grep "OpenSSL 3.") && -n $( ${PKCSCONF} -t -c $SLOT | grep "Model: EP11") ]]; then ${P11SAK} import-key ec private --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ec-ed25519-private" --file $DIR/ed25519-private-key.pem --attr sX RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) ${P11SAK} import-key ec public --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ec-ed25519-public" --file $DIR/ed25519-public-key.pem --attr sX RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) else echo "Skip importing edwards/montgomery keys, OpenSSL version not supporting it or not EP11 token" fi # ec-edwards if [[ -n $(openssl version | grep "OpenSSL 3.") && -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_EC_EDWARDS_KEY_PAIR_GEN) ]]; then ${P11SAK} import-key ec-edwards private --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ec-edwards-ed25519-private" --file $DIR/ed25519-private-key.pem --attr sX RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) ${P11SAK} import-key ec-edwards public --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ec-edwards-ed25519-public" --file $DIR/ed25519-public-key.pem --attr sX RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) ${P11SAK} import-key ec-edwards private --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ec-edwards-ed448-private" --file $DIR/ed448-private-key.pem --attr sX RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) ${P11SAK} import-key ec-edwards public --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ec-edwards-ed448-public" --file $DIR/ed448-public-key.pem --attr sX RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) else echo "Skip importing ec-edwards keys, OpenSSL version not supporting it or the token does nt support it" fi # ec-montgomery if [[ -n $(openssl version | grep "OpenSSL 3.") && -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_EC_MONTGOMERY_KEY_PAIR_GEN) ]]; then ${P11SAK} import-key ec-montgomery private --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ec-montgomery-x25519-private" --file $DIR/x25519-private-key.pem --attr sX RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) ${P11SAK} import-key ec-montgomery public --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ec-montgomery-x25519-public" --file $DIR/x25519-public-key.pem --attr sX RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) ${P11SAK} import-key ec-montgomery private --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ec-montgomery-x448-private" --file $DIR/x448-private-key.pem --attr sX RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) ${P11SAK} import-key ec-montgomery public --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ec-montgomery-x448-public" --file $DIR/x448-public-key.pem --attr sX RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) else echo "Skip importing ec-montgomery keys, OpenSSL version not supporting it or the token does nt support it" fi # ibm-dilithium if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_IBM_DILITHIUM) ]]; then if [[ -z $( ${PKCSCONF} -t -c $SLOT | grep "Model: Soft") ]]; then ${P11SAK} import-key ibm-dilithium private --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ibm-dilithium-private" --file $DIR/ibm-dilithium-r2-65-key.pem --attr sX RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) ${P11SAK} import-key ibm-dilithium public --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ibm-dilithium-public" --file $DIR/ibm-dilithium-r2-65-key.pem --attr sX RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) else ${P11SAK} import-key ibm-dilithium private --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ibm-dilithium-private" --file $DIR/ibm-dilithium-r3-65-key.pem --attr sX RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) ${P11SAK} import-key ibm-dilithium public --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ibm-dilithium-public" --file $DIR/ibm-dilithium-r3-65-key.pem --attr sX RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) fi if [[ -n $(openssl list -providers | grep oqsprovider) && -n $(openssl list -key-managers | grep "dilithium3 @ oqsprovider") ]]; then openssl genpkey -algorithm dilithium3 -out oqs-dil3-priv-key.pem RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) openssl pkey -in oqs-dil3-priv-key.pem -pubout -out oqs-dil3-pub-key.pem RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) ${P11SAK} import-key ibm-dilithium private --slot $SLOT --pin $PKCS11_USER_PIN --label "import-oqs-dilithium-private" --file oqs-dil3-priv-key.pem --oqsprovider-pem --attr sX RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) ${P11SAK} import-key ibm-dilithium public --slot $SLOT --pin $PKCS11_USER_PIN --label "import-oqs-dilithium-public" --file oqs-dil3-pub-key.pem --oqsprovider-pem --attr sX RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) else echo "Skip importing oqs-dilithium keys, the oqsprovider is not available or does not support dilithium3" fi else echo "Skip importing ibm-dilithium keys, slot does not support CKM_IBM_DILITHIUM" fi # ibm-kyber if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_IBM_KYBER) ]]; then ${P11SAK} import-key ibm-kyber private --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ibm-kyber-private" --file $DIR/ibm-kyber-r2-768-key.pem --attr sX RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) ${P11SAK} import-key ibm-kyber public --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ibm-kyber-public" --file $DIR/ibm-kyber-r2-768-key.pem --attr sX RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) else echo "Skip importing ibm-kyber keys, slot does not support CKM_IBM_KYBER" fi # ibm-ml-dsa if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_IBM_ML_DSA) ]]; then if [[ -n $(openssl list -key-managers | grep -i "MLDSA65") ]]; then openssl genpkey -algorithm mldsa65 -out mldsa65-priv-key.pem RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) openssl pkey -in mldsa65-priv-key.pem -pubout -out mldsa65-pub-key.pem RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) ${P11SAK} import-key ibm-ml-dsa private --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ml-dsa-private" --file mldsa65-priv-key.pem --attr sX RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) ${P11SAK} import-key ibm-ml-dsa public --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ml-dsa-public" --file mldsa65-pub-key.pem --attr sX RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) else echo "Skip importing ml-dsa keys, neither OpenSSL 3.5, nor the oqsprovider is available or does not support mldsa65" fi else echo "Skip importing ibm-ml-dsa keys, slot does not support CKM_IBM_ML_DSA" fi # ibm-ml-kem if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_IBM_ML_KEM) ]]; then if [[ -n $(openssl list -key-managers | grep -i "MLKEM1024") ]]; then openssl genpkey -algorithm mlkem1024 -out mlkem1024-priv-key.pem RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) openssl pkey -in mlkem1024-priv-key.pem -pubout -out mlkem1024-pub-key.pem RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) ${P11SAK} import-key ibm-ml-kem private --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ml-kem-private" --file mlkem1024-priv-key.pem --attr sX RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) ${P11SAK} import-key ibm-ml-kem public --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ml-kem-public" --file mlkem1024-pub-key.pem --attr sX RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) else echo "Skip importing ml-kem keys, neither OpenSSL 3.5, nor the oqsprovider is available or does not support mlkem1024" fi else echo "Skip importing ibm-ml-kem keys, slot does not support CKM_IBM_ML_KEM" fi # ml-dsa if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_ML_DSA) ]]; then if [[ -n $(openssl list -key-managers | grep -i "MLDSA65") ]]; then openssl genpkey -algorithm mldsa65 -out mldsa65-priv-key.pem RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) openssl pkey -in mldsa65-priv-key.pem -pubout -out mldsa65-pub-key.pem RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) ${P11SAK} import-key ml-dsa private --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ml-dsa-private" --file mldsa65-priv-key.pem --attr sX RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) ${P11SAK} import-key ml-dsa public --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ml-dsa-public" --file mldsa65-pub-key.pem --attr sX RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) else echo "Skip importing ml-dsa keys, neither OpenSSL 3.5, nor the oqsprovider is available or does not support mldsa65" fi else echo "Skip importing ml-dsa keys, slot does not support CKM_ML_DSA" fi # ml-kem if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_ML_KEM) ]]; then if [[ -n $(openssl list -key-managers | grep -i "MLKEM1024") ]]; then openssl genpkey -algorithm mlkem1024 -out mlkem1024-priv-key.pem RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) openssl pkey -in mlkem1024-priv-key.pem -pubout -out mlkem1024-pub-key.pem RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) ${P11SAK} import-key ml-kem private --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ml-kem-private" --file mlkem1024-priv-key.pem --attr sX RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) ${P11SAK} import-key ml-kem public --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ml-kem-public" --file mlkem1024-pub-key.pem --attr sX RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) else echo "Skip importing ml-kem keys, neither OpenSSL 3.5, nor the oqsprovider is available or does not support mlkem1024" fi else echo "Skip importing ml-kem, slot does not support CKM_IBM_ML_KEM" fi echo "** Now exporting keys - 'p11sak_test.sh'" RC_P11SAK_EXPORT=0 # aes if [[ -n $( ${PKCSCONF} -t -c $SLOT | grep "Model: EP11") || -n $( ${PKCSCONF} -t -c $SLOT | grep "Model: CCA") ]]; then ${P11SAK} export-key aes --slot $SLOT --pin $PKCS11_USER_PIN --label "import-aes" --file export-aes.opaque --force --opaque RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) else ${P11SAK} export-key aes --slot $SLOT --pin $PKCS11_USER_PIN --label "import-aes" --file export-aes.key --force RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) diff export-aes.key $DIR/aes.key > /dev/null RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) fi # rsa if [[ -n $( ${PKCSCONF} -t -c $SLOT | grep "Model: EP11") || -n $( ${PKCSCONF} -t -c $SLOT | grep "Model: CCA") ]]; then ${P11SAK} export-key rsa --slot $SLOT --pin $PKCS11_USER_PIN --label "import-rsa-public" --file export-rsa-key.pem --force RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) ${P11SAK} export-key rsa --slot $SLOT --pin $PKCS11_USER_PIN --label "import-rsa-private" --file export-rsa-key.opaque --force --opaque RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) else ${P11SAK} export-key rsa --slot $SLOT --pin $PKCS11_USER_PIN --label "import-rsa-*" --file export-rsa-key.pem --force RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) openssl pkey -in export-rsa-key.pem -check -text > /dev/null RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) fi openssl pkey -in export-rsa-key.pem -pubin -text > /dev/null RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) # dsa if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_DSA) ]]; then if [[ -n $( ${PKCSCONF} -t -c $SLOT | grep "Model: EP11") || -n $( ${PKCSCONF} -t -c $SLOT | grep "Model: CCA") ]]; then ${P11SAK} export-key dsa --slot $SLOT --pin $PKCS11_USER_PIN --label "import-dsa-public" --file export-dsa-key.pem --force RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) ${P11SAK} export-key dsa --slot $SLOT --pin $PKCS11_USER_PIN --label "import-dsa-private" --file export-dsa-key.opaque --force --opaque RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) else ${P11SAK} export-key dsa --slot $SLOT --pin $PKCS11_USER_PIN --label "import-dsa-*" --file export-dsa-key.pem --force RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) openssl pkey -in export-dsa-key.pem -text > /dev/null RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) fi openssl pkey -in export-dsa-key.pem -pubin -text > /dev/null RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) else echo "Skip exporting dsa keys, slot does not support CKM_DSA" fi # dh if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_DH_PKCS_DERIVE) ]]; then if [[ -n $( ${PKCSCONF} -t -c $SLOT | grep "Model: EP11") || -n $( ${PKCSCONF} -t -c $SLOT | grep "Model: CCA") ]]; then ${P11SAK} export-key dh --slot $SLOT --pin $PKCS11_USER_PIN --label "import-dh-public" --file export-dh-key.pem --force RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) ${P11SAK} export-key dh --slot $SLOT --pin $PKCS11_USER_PIN --label "import-dh-private" --file export-dh-key.opaque --force --opaque RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) else ${P11SAK} export-key dh --slot $SLOT --pin $PKCS11_USER_PIN --label "import-dh-*" --file export-dh-key.pem --force RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) openssl pkey -in export-dh-key.pem -text > /dev/null RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) fi openssl pkey -in export-dh-key.pem -pubin -text > /dev/null RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) else echo "Skip exporting dh keys, slot does not support CKM_DH_PKCS_DERIVE" fi # ec if [[ -n $( ${PKCSCONF} -t -c $SLOT | grep "Model: EP11") || -n $( ${PKCSCONF} -t -c $SLOT | grep "Model: CCA") ]]; then ${P11SAK} export-key ec --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ec-prime256v1-public" --file export-ec-prime256v1-key.pem --force RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) ${P11SAK} export-key ec --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ec-prime256v1-private" --file export-ec-prime256v1-key.opaque --force --opaque RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) ${P11SAK} export-key ec --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ec-secp521r1-public" --file export-ec-secp521r1-key.pem --force RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) ${P11SAK} export-key ec --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ec-secp521r1-private" --file export-ec-secp521r1-key.opaque --force --opaque RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) if [[ -n $(openssl version | grep "OpenSSL 3.") && -n $( ${PKCSCONF} -t -c $SLOT | grep "Model: EP11") ]]; then ${P11SAK} export-key ec --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ec-ed25519-public" --file export-ec-ed25519-key.pem --force RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) ${P11SAK} export-key ec --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ec-ed25519-private" --file export-ec-ed25519-key.opaque --force --opaque RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) else echo "Skip exporting edwards/montgomery keys, OpenSSL version not supporting it or not EP11 token" fi else ${P11SAK} export-key ec --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ec-prime256v1-*" --file export-ec-prime256v1-key.pem --force RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) openssl pkey -in export-ec-prime256v1-key.pem -check -text > /dev/null RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) ${P11SAK} export-key ec --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ec-secp521r1-*" --file export-ec-secp521r1-key.pem --force RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) openssl pkey -in export-ec-secp521r1-key.pem -check -text > /dev/null RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) fi openssl pkey -in export-ec-prime256v1-key.pem -pubin -text > /dev/null RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) openssl pkey -in export-ec-secp521r1-key.pem -pubin -text > /dev/null RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) if [[ -n $(openssl version | grep "OpenSSL 3.") && -n $( ${PKCSCONF} -t -c $SLOT | grep "Model: EP11") ]]; then openssl pkey -in export-ec-ed25519-key.pem -pubin -text > /dev/null RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) fi # ec-edwards if [[ -n $(openssl version | grep "OpenSSL 3.") && -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_EC_EDWARDS_KEY_PAIR_GEN) ]]; then if [[ -n $( ${PKCSCONF} -t -c $SLOT | grep "Model: EP11") || -n $( ${PKCSCONF} -t -c $SLOT | grep "Model: CCA") ]]; then ${P11SAK} export-key ec-edwards --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ec-edwards-ed25519-public" --file export-ec-edwards-ed25519-key.pem --force RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) ${P11SAK} export-key ec-edwards --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ec-edwards-ed25519-private" --file export-ec-edwards-ed25519-key.opaque --force --opaque RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) ${P11SAK} export-key ec-edwards --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ec-edwards-ed448-public" --file export-ec-edwards-ed448-key.pem --force RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) ${P11SAK} export-key ec-edwards --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ec-edwards-ed448-private" --file export-ec-edwards-ed448-key.opaque --force --opaque RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) else ${P11SAK} export-key ec-edwards --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ec-edwards-ed25519-*" --file export-ec-edwards-ed25519-key.pem --force RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) openssl pkey -in export-ec-edwards-ed25519-key.pem -check -text > /dev/null RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) ${P11SAK} export-key ec-edwards --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ec-edwards-ed448-*" --file export-ec-edwards-ed448-key.pem --force RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) openssl pkey -in export-ec-edwards-ed448-key.pem -check -text > /dev/null RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) fi openssl pkey -in export-ec-edwards-ed25519-key.pem -pubin -text > /dev/null RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) openssl pkey -in export-ec-edwards-ed448-key.pem -pubin -text > /dev/null RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) else echo "Skip exporting ec-edwards keys, OpenSSL version not supporting it or token does not support it" fi # ec-montgomery if [[ -n $(openssl version | grep "OpenSSL 3.") && -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_EC_MONTGOMERY_KEY_PAIR_GEN) ]]; then if [[ -n $( ${PKCSCONF} -t -c $SLOT | grep "Model: EP11") || -n $( ${PKCSCONF} -t -c $SLOT | grep "Model: CCA") ]]; then ${P11SAK} export-key ec-montgomery --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ec-montgomery-x25519-public" --file export-ec-montgomery-x25519-key.pem --force RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) ${P11SAK} export-key ec-montgomery --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ec-montgomery-x25519-private" --file export-ec-montgomery-x25519-key.opaque --force --opaque RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) ${P11SAK} export-key ec-montgomery --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ec-montgomery-x448-public" --file export-ec-montgomery-x448-key.pem --force RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) ${P11SAK} export-key ec-montgomery --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ec-montgomery-x448-private" --file export-ec-montgomery-x448-key.opaque --force --opaque RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) else ${P11SAK} export-key ec-montgomery --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ec-montgomery-x25519-*" --file export-ec-montgomery-x25519-key.pem --force RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) openssl pkey -in export-ec-montgomery-x25519-key.pem -check -text > /dev/null RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) ${P11SAK} export-key ec-montgomery --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ec-montgomery-x448-*" --file export-ec-montgomery-x448-key.pem --force RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) openssl pkey -in export-ec-montgomery-x448-key.pem -check -text > /dev/null RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) fi openssl pkey -in export-ec-montgomery-x25519-key.pem -pubin -text > /dev/null RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) openssl pkey -in export-ec-montgomery-x448-key.pem -pubin -text > /dev/null RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) else echo "Skip exporting ec-montgomery keys, OpenSSL version not supporting it or token does not support it" fi # ibm-dilithium if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_IBM_DILITHIUM) ]]; then if [[ -n $( ${PKCSCONF} -t -c $SLOT | grep "Model: EP11") || -n $( ${PKCSCONF} -t -c $SLOT | grep "Model: CCA") ]]; then ${P11SAK} export-key ibm-dilithium --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ibm-dilithium-public" --file export-ibm-dilithium-key.pem --force RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) ${P11SAK} export-key ibm-dilithium --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ibm-dilithium-private" --file export-ibm-dilithium-key.opaque --force --opaque RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) if [[ -n $(openssl list -providers | grep oqsprovider) && -n $(openssl list -key-managers | grep "dilithium3 @ oqsprovider") ]]; then ${P11SAK} export-key ibm-dilithium --slot $SLOT --pin $PKCS11_USER_PIN --label "import-oqs-dilithium-public" --file export-oqs-dilithium-key.pem --oqsprovider-pem --force RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) ${P11SAK} export-key ibm-dilithium --slot $SLOT --pin $PKCS11_USER_PIN --label "import-oqs-dilithium-private" --file export-oqs-dilithium-key.opaque --force --opaque RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) else echo "Skip exporting oqs-dilithium keys, the oqsprovider is not available or does not support dilithium3" fi else ${P11SAK} export-key ibm-dilithium --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ibm-dilithium-*" --file export-ibm-dilithium-key.pem --force RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) if [[ -n $(openssl list -providers | grep oqsprovider) && -n $(openssl list -key-managers | grep "dilithium3 @ oqsprovider") ]]; then ${P11SAK} export-key ibm-dilithium --slot $SLOT --pin $PKCS11_USER_PIN --label "import-oqs-dilithium-*" --file export-oqs-dilithium-key.pem --oqsprovider-pem --force RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) else echo "Skip exporting oqs-dilithium keys, the oqsprovider is not available or does not support dilithium3" fi fi else echo "Skip exporting ibm-dilithium keys, slot does not support CKM_IBM_DILITHIUM" fi # ibm-kyber if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_IBM_KYBER) ]]; then if [[ -n $( ${PKCSCONF} -t -c $SLOT | grep "Model: EP11") || -n $( ${PKCSCONF} -t -c $SLOT | grep "Model: CCA") ]]; then ${P11SAK} export-key ibm-kyber --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ibm-kyber-public" --file export-ibm-kyber-key.pem --force RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) ${P11SAK} export-key ibm-kyber --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ibm-kyber-private" --file export-ibm-kyber-key.opaque --force --opaque RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) else ${P11SAK} export-key ibm-kyber --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ibm-kyber-*" --file export-ibm-kyber-key.pem --force RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) fi else echo "Skip exporting ibm-kyber keys, slot does not support CKM_IBM_KYBER" fi # ibm-ml-dsa if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_IBM_ML_DSA) ]]; then if [[ -n $(openssl list -key-managers | grep -i "MLDSA65") ]]; then if [[ -n $( ${PKCSCONF} -t -c $SLOT | grep "Model: EP11") || -n $( ${PKCSCONF} -t -c $SLOT | grep "Model: CCA") ]]; then ${P11SAK} export-key ibm-ml-dsa --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ml-dsa-public" --file export-ml-dsa-key.pem --force RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) ${P11SAK} export-key ibm-ml-dsa --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ml-dsa-private" --file export-ml-dsa-key.opaque --force --opaque RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) else ${P11SAK} export-key ibm-ml-dsa --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ml-dsa-*" --file export-ml-dsa-key.pem --force RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) fi else echo "Skip exporting ml-dsa keys, neither OpeNSSL 3.5, nor the oqsprovider is available or does not support mldsa65" fi else echo "Skip exporting ibm-ml-dsa keys, slot does not support CKM_IBM_ML_DSA" fi # ibm-ml-kem if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_IBM_ML_KEM) ]]; then if [[ -n $(openssl list -key-managers | grep -i "MLKEM1024") ]]; then if [[ -n $( ${PKCSCONF} -t -c $SLOT | grep "Model: EP11") || -n $( ${PKCSCONF} -t -c $SLOT | grep "Model: CCA") ]]; then ${P11SAK} export-key ibm-ml-kem --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ml-kem-public" --file export-ml-kem-key.pem --force RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) ${P11SAK} export-key ibm-ml-kem --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ml-kem-private" --file export-ml-kem-key.opaque --force --opaque RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) else ${P11SAK} export-key ibm-ml-kem --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ml-kem-*" --file export-mlkem-key.pem --force RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) fi else echo "Skip exporting ml-kem keys, neither OpenSSL 3.5, nor the oqsprovider is available or does not support mlkem1024" fi else echo "Skip exporting ibm-ml-kem keys, slot does not support CKM_IBM_ML_KEM" fi # ml-dsa if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_ML_DSA) ]]; then if [[ -n $(openssl list -key-managers | grep -i "MLDSA65") ]]; then if [[ -n $( ${PKCSCONF} -t -c $SLOT | grep "Model: EP11") || -n $( ${PKCSCONF} -t -c $SLOT | grep "Model: CCA") ]]; then ${P11SAK} export-key ml-dsa --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ml-dsa-public" --file export-ml-dsa-key.pem --force RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) ${P11SAK} export-key ml-dsa --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ml-dsa-private" --file export-ml-dsa-key.opaque --force --opaque RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) else ${P11SAK} export-key ml-dsa --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ml-dsa-*" --file export-ml-dsa-key.pem --force RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) fi else echo "Skip exporting ml-dsa keys, neither OpeNSSL 3.5, nor the oqsprovider is available or does not support mldsa65" fi else echo "Skip exporting ml-dsa keys, slot does not support CKM_ML_DSA" fi # ml-kem if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_ML_KEM) ]]; then if [[ -n $(openssl list -key-managers | grep -i "MLKEM1024") ]]; then if [[ -n $( ${PKCSCONF} -t -c $SLOT | grep "Model: EP11") || -n $( ${PKCSCONF} -t -c $SLOT | grep "Model: CCA") ]]; then ${P11SAK} export-key ml-kem --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ml-kem-public" --file export-ml-kem-key.pem --force RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) ${P11SAK} export-key ml-kem --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ml-kem-private" --file export-ml-kem-key.opaque --force --opaque RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) else ${P11SAK} export-key ml-kem --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ml-kem-*" --file export-mlkem-key.pem --force RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) fi else echo "Skip exporting ml-kem keys, neither OpenSSL 3.5, nor the oqsprovider is available or does not support mlkem1024" fi else echo "Skip exporting ml-kem keys, slot does not support CKM_IBM_ML_KEM" fi # export to URI-PEM p11sak export-key aes --slot $SLOT --pin $PKCS11_USER_PIN --label "import-aes" --file export-uri-pem1.pem --force --uri-pem RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) openssl asn1parse -i -in export-uri-pem1.pem > /dev/null RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) p11sak export-key aes --slot $SLOT --pin $PKCS11_USER_PIN --label "import-aes" --file export-uri-pem2.pem --force --uri-pem --uri-pin-value RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) openssl asn1parse -i -in export-uri-pem2.pem > /dev/null RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) p11sak export-key aes --slot $SLOT --pin $PKCS11_USER_PIN --label "import-aes" --file export-uri-pem3.pem --force --uri-pem --uri-pin-source pin1.txt RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) openssl asn1parse -i -in export-uri-pem3.pem > /dev/null RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) if [[ $(cat pin1.txt) != $PKCS11_USER_PIN ]]; then echo "Pin file does not contain the PKCS#11 user pin" RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + 1)) fi echo "** Wrap/Unwrap tests - 'p11sak_test.sh'" RC_P11SAK_WRAP=0 ${P11SAK} generate-key RSA 2048 --slot $SLOT --pin $PKCS11_USER_PIN --id 123 --label "p11sak-keywrap-rsa-kek" --attr WU RC_P11SAK_WRAP=$((RC_P11SAK_WRAP + $?)) ${P11SAK} generate-key AES 256 --slot $SLOT --pin $PKCS11_USER_PIN --id 123 --label "p11sak-keywrap-aes-to-be-wrapped" --attr XS RC_P11SAK_WRAP=$((RC_P11SAK_WRAP + $?)) if [[ -n $( ${PKCSCONF} -t -c $SLOT | grep "Model: CCA") && -n $( ${P11SAK} list-key AES --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-keywrap-aes-to-be-wrapped" --long | grep " CKA_IBM_CCA_AES_KEY_MODE: 1") ]]; then # CCA can only wrap AES-DATA keys with RSA-PKCS. For AES-CIPHER keys RSA-AESKW must be used. if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_RSA_AES_KEY_WRAP) ]]; then ${P11SAK} wrap-key RSA-AESKW AES --aes-key-size 256 --hash-alg SHA-1 --mgf-alg SHA-1 --slot $SLOT --pin $PKCS11_USER_PIN --kek-label "p11sak-keywrap-rsa-kek:pub" --label "p11sak-keywrap-aes-to-be-wrapped" --file wrapped-key.pem --force RC_P11SAK_WRAP=$((RC_P11SAK_WRAP + $?)) ${P11SAK} unwrap-key --slot $SLOT --pin $PKCS11_USER_PIN --kek-label "p11sak-keywrap-rsa-kek:prv" --label "p11sak-keywrap-aes-unwrapped" --file wrapped-key.pem --force RC_P11SAK_WRAP=$((RC_P11SAK_WRAP + $?)) else echo "Skip wrapping AES-CIPHER keys with CCA token, slot does not support CKM_RSA_AES_KEY_WRAP" fi else ${P11SAK} wrap-key RSA-PKCS AES --slot $SLOT --pin $PKCS11_USER_PIN --kek-label "p11sak-keywrap-rsa-kek:pub" --label "p11sak-keywrap-aes-to-be-wrapped" --file wrapped-key.pem --force RC_P11SAK_WRAP=$((RC_P11SAK_WRAP + $?)) ${P11SAK} unwrap-key --slot $SLOT --pin $PKCS11_USER_PIN --kek-label "p11sak-keywrap-rsa-kek:prv" --label "p11sak-keywrap-aes-unwrapped" --file wrapped-key.pem --force RC_P11SAK_WRAP=$((RC_P11SAK_WRAP + $?)) fi echo "** Now remove keys - 'p11sak_test.sh'" # remove objects RC_P11SAK_REMOVE=0 # des ${P11SAK} remove-key des --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-des" -f RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) # 3des ${P11SAK} remove-key 3des --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-3des" -f RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) # generic ${P11SAK} remove-key generic --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-generic" -f RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) # aes [128 | 192 | 256 | copied] ${P11SAK} remove-key aes --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-aes-128" -f RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) ${P11SAK} remove-key aes --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-aes-192" -f RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) ${P11SAK} remove-key aes --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-aes-256" -f RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) ${P11SAK} remove-key aes --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-aes-copied" -f RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) # aes-xts [128 | 256] ${P11SAK} remove-key aes-xts --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-aes-xts-128" -f RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) ${P11SAK} remove-key aes-xts --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-aes-xts-256" -f RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) # rsa [1024 | 2048 | 4096] # remove public key ${P11SAK} remove-key rsa --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-rsa-1024:pub" -f RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) ${P11SAK} remove-key rsa --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-rsa-2048:pub" -f RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) ${P11SAK} remove-key rsa --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-rsa-4096:pub" -f RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) # remove private key ${P11SAK} remove-key rsa --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-rsa-1024:prv" -f RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) ${P11SAK} remove-key rsa --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-rsa-2048:prv" -f RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) ${P11SAK} remove-key rsa --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-rsa-4096:prv" -f RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) # dh # remove public key ${P11SAK} remove-key dh --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-dh:pub" -f RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) # remove private key ${P11SAK} remove-key dh --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-dh:prv" -f RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) # dsa # remove public key ${P11SAK} remove-key dsa --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-dsa:pub" -f RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) # remove private key ${P11SAK} remove-key dsa --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-dsa:prv" -f RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) # ec [prime256v1 | secp384r1 | secp521r1] #remove public key ${P11SAK} remove-key ec --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ec-prime256v1:pub" -f RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) ${P11SAK} remove-key ec --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ec-secp384r1:pub" -f RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) ${P11SAK} remove-key ec --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ec-secp521r1:pub" -f RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) # remove private key ${P11SAK} remove-key ec --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ec-prime256v1:prv" -f RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) ${P11SAK} remove-key ec --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ec-secp384r1:prv" -f RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) ${P11SAK} remove-key ec --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ec-secp521r1:prv" -f RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) # ec-edwards [ed25519 | ed448] #remove public key ${P11SAK} remove-key ec-edwards --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ec-edwards-ed25519:pub" -f RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) ${P11SAK} remove-key ec-edwards --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ec-edwards-ed448:pub" -f RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) # remove private key ${P11SAK} remove-key ec-edwards --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ec-edwards-ed25519:prv" -f RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) ${P11SAK} remove-key ec-edwards --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ec-edwards-ed448:prv" -f RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) # ec-montgomery [curve25519 | curve448] #remove public key ${P11SAK} remove-key ec-montgomery --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ec-montgomery-x25519:pub" -f RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) ${P11SAK} remove-key ec-montgomery --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ec-montgomery-x448:pub" -f RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) # remove private key ${P11SAK} remove-key ec-montgomery --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ec-montgomery-x25519:prv" -f RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) ${P11SAK} remove-key ec-montgomery --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ec-montgomery-x448:prv" -f RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) # remove ibm-dilithium keys ${P11SAK} remove-key ibm-dilithium --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ibm-dilithium:pub" -f RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) ${P11SAK} remove-key ibm-dilithium --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ibm-dilithium:prv" -f RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) # remove ibm-kyber keys ${P11SAK} remove-key ibm-kyber --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ibm-kyber:pub" -f RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) ${P11SAK} remove-key ibm-kyber --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ibm-kyber:prv" -f RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) # remove ibm-ml-dsa keys ${P11SAK} remove-key ibm-ml-dsa --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ibm-ml-dsa:pub" -f RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) ${P11SAK} remove-key ibm-ml-dsa --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ibm-ml-dsa:prv" -f RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) # remove ibm-ml-kem keys ${P11SAK} remove-key ibm-ml-kem --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ibm-ml-kem:pub" -f RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) ${P11SAK} remove-key ibm-ml-kem --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ibm-ml-kem:prv" -f RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) # remove ml-dsa keys ${P11SAK} remove-key ml-dsa --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ml-dsa:pub" -f RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) ${P11SAK} remove-key ml-dsa --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ml-dsa:prv" -f RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) # remove ml-kem keys ${P11SAK} remove-key ml-kem --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ml-kem:pub" -f RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) ${P11SAK} remove-key ml-kem --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ml-kem:prv" -f RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) # remove imported and extracted keys ${P11SAK} remove-key --slot $SLOT --pin $PKCS11_USER_PIN --label "import*" -f RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) ${P11SAK} remove-key --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-pubkey-extracted" -f RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) ${P11SAK} remove-key --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-keywrap*" -f RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) echo "** Now list keys and redirect to post-files - 'p11sak_test.sh'" # list objects RC_P11SAK_LIST_POST=0 ${P11SAK} list-key des --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-des" &> $P11SAK_DES_POST RC_P11SAK_LIST_POST=$((RC_P11SAK_LIST_POST + $?)) ${P11SAK} list-key 3des --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-3des" &> $P11SAK_3DES_POST RC_P11SAK_LIST_POST=$((RC_P11SAK_LIST_POST + $?)) ${P11SAK} list-key generic --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-generic" &> $P11SAK_GENERIC_POST RC_P11SAK_LIST_POST=$((RC_P11SAK_LIST_POST + $?)) ${P11SAK} list-key aes --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-aes-*" &> $P11SAK_AES_POST RC_P11SAK_LIST_POST=$((RC_P11SAK_LIST_POST + $?)) ${P11SAK} list-key aes-xts --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-aes-xts-*" &> $P11SAK_AES_XTS_POST RC_P11SAK_LIST_POST=$((RC_P11SAK_LIST_POST + $?)) ${P11SAK} list-key rsa --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-rsa-*" &> $P11SAK_RSA_POST RC_P11SAK_LIST_POST=$((RC_P11SAK_LIST_POST + $?)) ${P11SAK} list-key dh --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-dh*" &> $P11SAK_DH_POST RC_P11SAK_LIST_POST=$((RC_P11SAK_LIST_POST + $?)) ${P11SAK} list-key dsa --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-dsa*" &> $P11SAK_DSA_POST RC_P11SAK_LIST_POST=$((RC_P11SAK_LIST_POST + $?)) ${P11SAK} list-key ec --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ec-*" &> $P11SAK_EC_POST RC_P11SAK_LIST_POST=$((RC_P11SAK_LIST_POST + $?)) ${P11SAK} list-key ec-edwards --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ec-edwards-*" &> $P11SAK_EC_EDWARDS_POST RC_P11SAK_LIST_POST=$((RC_P11SAK_LIST_POST + $?)) ${P11SAK} list-key ec-montgomery --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ec-montgomery-*" &> $P11SAK_EC_MONTGOMERY_POST RC_P11SAK_LIST_POST=$((RC_P11SAK_LIST_POST + $?)) ${P11SAK} list-key ibm-dilithium --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ibm-dilithium*" &> $P11SAK_IBM_DILITHIUM_POST RC_P11SAK_LIST_POST=$((RC_P11SAK_LIST_POST + $?)) ${P11SAK} list-key ibm-kyber --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ibm-kyber*" &> $P11SAK_IBM_KYBER_POST RC_P11SAK_LIST_POST=$((RC_P11SAK_LIST_POST + $?)) ${P11SAK} list-key ibm-ml-dsa --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ibm-ml-dsa*" &> $P11SAK_IBM_ML_DSA_POST RC_P11SAK_LIST_POST=$((RC_P11SAK_LIST_POST + $?)) ${P11SAK} list-key ibm-ml-kem --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ibm-ml-kem*" &> $P11SAK_IBM_ML_KEM_POST RC_P11SAK_LIST_POST=$((RC_P11SAK_LIST_POST + $?)) ${P11SAK} list-key ml-dsa --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ml-dsa*" &> $P11SAK_ML_DSA_POST RC_P11SAK_LIST_POST=$((RC_P11SAK_LIST_POST + $?)) ${P11SAK} list-key ml-kem --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ml-kem*" &> $P11SAK_ML_KEM_POST RC_P11SAK_LIST_POST=$((RC_P11SAK_LIST_POST + $?)) echo "** Now checking output files to determine PASS/FAIL of tests - 'p11sak_test.sh'" if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_DES_KEY_GEN) ]]; then # check DES grep -q "p11sak-des" $P11SAK_DES_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key des PASS Generated random DES key" else echo "* TESTCASE generate-key des FAIL Failed to generate DES key" status=1 fi grep -v -q "p11sak-des" $P11SAK_DES_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key des PASS Deleted generated DES key" else echo "* TESTCASE remove-key des FAIL Failed to delete generated DES key" status=1 fi else echo "* TESTCASE generate-key des SKIP Generated random DES key" echo "* TESTCASE remove-key des SKIP Deleted generated DES key" fi if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_DES_KEY_GEN) ]]; then # CK_BBOOL if [[ $(grep -c "CKA_ENCRYPT: CK_TRUE" $P11SAK_DES_LONG) == "1" ]]; then echo "* TESTCASE list-key des PASS Listed random des keys CK_BBOOL attribute" else echo "* TESTCASE list-key des FAIL Failed to list des keys CK_BBOOL attribute" status=1 fi # CK_ULONG if [[ $(grep -c "CKA_MODULUS_BITS:" $P11SAK_DES_LONG) == "0" ]]; then echo "* TESTCASE list-key des PASS Listed random des keys CK_ULONG attribute" else echo "* TESTCASE list-key des FAIL Failed to list des keys CK_ULONG attribute" status=1 fi # CK_BYTE if [[ $(grep -c "CKA_VALUE:" $P11SAK_DES_LONG) == "1" ]]; then echo "* TESTCASE list-key des PASS Listed random des keys CK_BYTE attribute" else echo "* TESTCASE list-key des FAIL Failed to list des keys CK_BYTE attribute" status=1 fi # URI if [[ $(grep -c "URI: pkcs11:.*type=secret-key" $P11SAK_DES_LONG) == "1" ]]; then echo "* TESTCASE list-key des PASS list des key pkcs#11 URI" else echo "* TESTCASE list-key des FAIL list des key pkcs#11 URI" status=1 fi else echo "* TESTCASE list-key des SKIP Listed random des keys CK_BBOOL attribute" echo "* TESTCASE list-key des SKIP Listed random des keys CK_ULONG attribute" echo "* TESTCASE list-key des SKIP Listed random des keys CK_BYTE attribute" echo "* TESTCASE list-key des SKIP list des key pkcs#11 URI" fi # check 3DES grep -q "p11sak-3des" $P11SAK_3DES_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key 3des PASS Generated random 3DES key" else echo "* TESTCASE generate-key 3des FAIL Failed to generate 3DES key" status=1 fi grep -v -q "p11sak-3des" $P11SAK_3DES_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key 3des PASS Deleted generated 3DES key" else echo "* TESTCASE remove-key 3des FAIL Failed to delete generated 3DES key" status=1 fi # CK_BBOOL if [[ $(grep -c "CKA_ENCRYPT: CK_TRUE" $P11SAK_3DES_LONG) == "1" ]]; then echo "* TESTCASE list-key 3des PASS Listed random 3des keys CK_BBOOL attribute" else echo "* TESTCASE list-key 3des FAIL Failed to list 3des keys CK_BBOOL attribute" status=1 fi # CK_ULONG if [[ $(grep -c "CKA_MODULUS_BITS:" $P11SAK_3DES_LONG) == "0" ]]; then echo "* TESTCASE list-key 3des PASS Listed random 3des keys CK_ULONG attribute" else echo "* TESTCASE list-key 3des FAIL Failed to list 3des keys CK_ULONG attribute" status=1 fi # CK_BYTE if [[ $(grep -c "CKA_VALUE:" $P11SAK_3DES_LONG) == "1" ]]; then echo "* TESTCASE list-key 3des PASS Listed random 3des keys CK_BYTE attribute" else echo "* TESTCASE list-key 3des FAIL Failed to list 3des keys CK_BYTE attribute" status=1 fi # URI if [[ $(grep -c "URI: pkcs11:.*type=secret-key" $P11SAK_3DES_LONG) == "1" ]]; then echo "* TESTCASE list-key 3des PASS list 3des key pkcs#11 URI" else echo "* TESTCASE list-key 3des FAIL list 3des key pkcs#11 URI" status=1 fi # check generic grep -q "p11sak-generic" $P11SAK_GENERIC_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key generic PASS Generated random GENERIC key" else echo "* TESTCASE generate-key generic FAIL Failed to generate GENERIC key" status=1 fi grep -v -q "p11sak-generic" $P11SAK_GENERIC_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key generic PASS Deleted generated GENERIC key" else echo "* TESTCASE remove-key generic FAIL Failed to delete generated GENERIC key" status=1 fi # CK_BBOOL if [[ $(grep -c "CKA_SIGN: CK_TRUE" $P11SAK_GENERIC_LONG) == "1" ]]; then echo "* TESTCASE list-key generic PASS Listed random generic keys CK_BBOOL attribute" else echo "* TESTCASE list-key generic FAIL Failed to list generic keys CK_BBOOL attribute" status=1 fi # CK_ULONG if [[ $(grep -c "CKA_MODULUS_BITS:" $P11SAK_GENERIC_LONG) == "0" ]]; then echo "* TESTCASE list-key generic PASS Listed random generic keys CK_ULONG attribute" else echo "* TESTCASE list-key generic FAIL Failed to list generic keys CK_ULONG attribute" status=1 fi # CK_BYTE if [[ $(grep -c "CKA_VALUE:" $P11SAK_GENERIC_LONG) == "1" ]]; then echo "* TESTCASE list-key generic PASS Listed random generic keys CK_BYTE attribute" else echo "* TESTCASE list-key generic FAIL Failed to list generic keys CK_BYTE attribute" status=1 fi # URI if [[ $(grep -c "URI: pkcs11:.*type=secret-key" $P11SAK_GENERIC_LONG) == "1" ]]; then echo "* TESTCASE list-key generic PASS list generic key pkcs#11 URI" else echo "* TESTCASE list-key generic FAIL list generic key pkcs#11 URI" status=1 fi # check AES 128 grep -q "p11sak-aes-128" $P11SAK_AES_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key aes-128 PASS Generated random AES 128 key" else echo "* TESTCASE generate-key aes-128 FAIL Failed to generate AES 128 key" status=1 fi grep -v -q "p11sak-aes-128" $P11SAK_AES_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key aes-128 PASS Deleted generated AES 128 key" else echo "* TESTCASE remove-key aes-128 FAIL Failed to delete generated AES 128 key" status=1 fi # check AES 192 grep -q "p11sak-aes-192" $P11SAK_AES_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key aes-192 PASS Generated random AES 192 key" else echo "* TESTCASE generate-key aes-192 FAIL Failed to generate AES 192 key" status=1 fi grep -v -q "p11sak-aes-192" $P11SAK_AES_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key aes-192 PASS Deleted generated AES 192 key" else echo "* TESTCASE remove-key aes-192 FAIL Failed to delete generated AES 192 key" status=1 fi # check AES 256 grep -q "p11sak-aes-256" $P11SAK_AES_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key aes-256 PASS Generated random AES 256 key" else echo "* TESTCASE generate-key aes-256 FAIL Failed to generate AES 256 key" status=1 fi grep -v -q "p11sak-aes-256" $P11SAK_AES_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key aes-256 PASS Deleted generated AES 256 key" else echo "* TESTCASE remove-key aes-256 FAIL Failed to delete generated AES 256 key" status=1 fi # CK_BBOOL if [[ $(grep -c "CKA_ENCRYPT: CK_TRUE" $P11SAK_AES_LONG) == "3" ]]; then echo "* TESTCASE list-key aes PASS Listed random aes keys CK_BBOOL attribute" else echo "* TESTCASE list-key aes FAIL Failed to list aes keys CK_BBOOL attribute" status=1 fi # CK_ULONG if [[ $(grep -c "CKA_VALUE_LEN:" $P11SAK_AES_LONG) == "3" ]]; then echo "* TESTCASE list-key aes PASS Listed random aes keys CK_ULONG attribute" else echo "* TESTCASE list-key aes FAIL Failed to list aes keys CK_ULONG attribute" status=1 fi # CK_BYTE if [[ $(grep -c "CKA_VALUE:" $P11SAK_AES_LONG) == "3" ]]; then echo "* TESTCASE list-key aes PASS Listed random aes keys CK_BYTE attribute" else echo "* TESTCASE list-key aes FAIL Failed to list aes keys CK_BYTE attribute" status=1 fi # URI if [[ $(grep -c "URI: pkcs11:.*type=secret-key" $P11SAK_AES_LONG) == "3" ]]; then echo "* TESTCASE list-key aes PASS list aes key pkcs#11 URI" else echo "* TESTCASE list-key aes FAIL list aes key pkcs#11 URI" status=1 fi if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_AES_XTS_KEY_GEN) ]]; then # check AES-XTS 128 grep -q "p11sak-aes-xts-128" $P11SAK_AES_XTS_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key aes-xts-128 PASS Generated random AES-XTS 128 key" else echo "* TESTCASE generate-key aes-xts-128 FAIL Failed to generate AES-XTS 128 key" status=1 fi grep -v -q "p11sak-aes-xts-128" $P11SAK_AES_XTS_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key aes-xts-128 PASS Deleted generated AES-XTS 128 key" else echo "* TESTCASE remove-key aes-xts-128 FAIL Failed to delete generated AES-XTS 128 key" status=1 fi # check AES-XTS 256 grep -q "p11sak-aes-xts-256" $P11SAK_AES_XTS_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key aes-xts-256 PASS Generated random AES-XTS 256 key" else echo "* TESTCASE generate-key aes-xts-256 FAIL Failed to generate AES-XTS 256 key" status=1 fi grep -v -q "p11sak-aes-xts-256" $P11SAK_AES_XTS_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key aes-xts-256 PASS Deleted generated AES-XTS 256 key" else echo "* TESTCASE remove-key aes-xts-256 FAIL Failed to delete generated AES-XTS 256 key" status=1 fi # CK_BBOOL if [[ $(grep -c "CKA_ENCRYPT: CK_TRUE" $P11SAK_AES_XTS_LONG) == "2" ]]; then echo "* TESTCASE list-key aes-xts PASS Listed random aes-xts keys CK_BBOOL attribute" else echo "* TESTCASE list-key aes-xts FAIL Failed to list aes-xts keys CK_BBOOL attribute" status=1 fi # CK_ULONG if [[ $(grep -c "CKA_VALUE_LEN:" $P11SAK_AES_XTS_LONG) == "2" ]]; then echo "* TESTCASE list-key aes-xts PASS Listed random aes-xts keys CK_ULONG attribute" else echo "* TESTCASE list-key aes-xts FAIL Failed to list aes-xts keys CK_ULONG attribute" status=1 fi # CK_BYTE if [[ $(grep -c "CKA_VALUE:" $P11SAK_AES_XTS_LONG) == "2" ]]; then echo "* TESTCASE list-key aes-xts PASS Listed random aes-xts keys CK_BYTE attribute" else echo "* TESTCASE list-key aes-xts FAIL Failed to list aes-xts keys CK_BYTE attribute" status=1 fi # URI if [[ $(grep -c "URI: pkcs11:.*type=secret-key" $P11SAK_AES_XTS_LONG) == "2" ]]; then echo "* TESTCASE list-key aes-xts PASS list aes-xts key pkcs#11 URI" else echo "* TESTCASE list-key aes-xts FAIL list aes-xts key pkcs#11 URI" status=1 fi else echo "* TESTCASE generate-key aes-xts-128 SKIP Generated random AES-XTS 128 key" echo "* TESTCASE remove-key aes-xts-128 SKIP Deleted generated AES-XTS 128 key" echo "* TESTCASE generate-key aes-xts-256 SKIP Generated random AES-XTS 256 key" echo "* TESTCASE remove-key aes-xts-256 SKIP Deleted generated AES-XTS 256 key" echo "* TESTCASE list-key aes-xts SKIP Listed random aes-xts keys CK_BBOOL attribute" echo "* TESTCASE list-key aes-xts SKIP Listed random aes-xts keys CK_ULONG attribute" echo "* TESTCASE list-key aes-xts SKIP Listed random aes-xts keys CK_BYTE attribute" echo "* TESTCASE list-key aes-xts SKIP list aes-xts key pkcs#11 URI" fi # check RSA 1024 public key grep -q "p11sak-rsa-1024:pub" $P11SAK_RSA_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key rsa 1024 PASS Generated random rsa 1024 public key" else echo "* TESTCASE generate-key rsa 1024 FAIL Failed to generate rsa 1024 public key" status=1 fi grep -v -q "p11sak-rsa-1024:pub" $P11SAK_RSA_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key rsa PASS Deleted generated rsa 1024 public key" else echo "* TESTCASE remove-key rsa FAIL Failed to delete generated rsa 1024 public key" status=1 fi # check RSA 2048 public key grep -q "p11sak-rsa-2048:pub" $P11SAK_RSA_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key rsa 2048 PASS Generated random rsa 2048 public key" else echo "* TESTCASE generate-key rsa 2048 FAIL Failed to generate rsa 2048 public key" status=1 fi grep -v -q "p11sak-rsa-2048:pub" $P11SAK_RSA_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key rsa PASS Deleted generated rsa 2048 public key" else echo "* TESTCASE remove-key rsa FAIL Failed to delete generated rsa 2048 public key" status=1 fi # check RSA 4096 public key grep -q "p11sak-rsa-4096:pub" $P11SAK_RSA_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key rsa 4096 PASS Generated random rsa 4096 public key" else echo "* TESTCASE generate-key rsa 4096 FAIL Failed to generate rsa 4096 public key" status=1 fi grep -v -q "p11sak-rsa-4096:pub" $P11SAK_RSA_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key rsa PASS Deleted generated rsa 4096 public key" else echo "* TESTCASE remove-key rsa FAIL Failed to delete generated rsa 4096 public key" status=1 fi # check RSA 1024 private key grep -q "p11sak-rsa-1024:prv" $P11SAK_RSA_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key rsa 1024 PASS Generated random rsa 1024 private key" else echo "* TESTCASE generate-key rsa 1024 FAIL Failed to generate rsa 1024 private key" status=1 fi grep -v -q "p11sak-rsa-1024:prv" $P11SAK_RSA_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key rsa PASS Deleted generated rsa 1024 private key" else echo "* TESTCASE remove-key rsa FAIL Failed to delete generated rsa 1024 private key" status=1 fi # check RSA 2048 private key grep -q "p11sak-rsa-2048:prv" $P11SAK_RSA_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key rsa 2048 PASS Generated random rsa 2048 private key" else echo "* TESTCASE generate-key rsa 2048 FAIL Failed to generate rsa 2048 private key" status=1 fi grep -v -q "p11sak-rsa-2048:prv" $P11SAK_RSA_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key rsa PASS Deleted generated rsa 2048 private key" else echo "* TESTCASE remove-key rsa FAIL Failed to delete generated rsa 2048 private key" status=1 fi # check RSA 4096 private key grep -q "p11sak-rsa-4096:prv" $P11SAK_RSA_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key rsa 4096 PASS Generated random rsa 4096 private key" else echo "* TESTCASE generate-key rsa 4096 FAIL Failed to generate rsa 4096 private key" status=1 fi grep -v -q "p11sak-rsa-4096:prv" $P11SAK_RSA_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key rsa PASS Deleted generated rsa 4096 private key" else echo "* TESTCASE remove-key rsa FAIL Failed to delete generated rsa 4096 private key" status=1 fi # CK_BBOOL if [[ $(grep -c "CKA_MODIFIABLE: CK_TRUE" $P11SAK_RSA_LONG) == "6" ]]; then echo "* TESTCASE list-key rsa PASS Listed random rsa keys CK_BBOOL attribute" else echo "* TESTCASE list-key rsa FAIL Failed to list rsa keys CK_BBOOL attribute" status=1 fi # CK_ULONG if [[ $(grep -c "CKA_MODULUS_BITS:" $P11SAK_RSA_LONG) == "3" ]]; then echo "* TESTCASE list-key rsa PASS Listed random rsa keys CK_ULONG attribute" else echo "* TESTCASE list-key rsa FAIL Failed to list rsa keys CK_ULONG attribute" status=1 fi # CK_BYTE if [[ $(grep -c "CKA_MODULUS:" $P11SAK_RSA_LONG) == "6" ]]; then echo "* TESTCASE list-key rsa PASS Listed random rsa keys CK_BYTE attribute" else echo "* TESTCASE list-key rsa FAIL Failed to list rsa keys CK_BYTE attribute" status=1 fi # URI if [[ $(grep -c "URI: pkcs11:.*type=public" $P11SAK_RSA_LONG) == "3" ]]; then echo "* TESTCASE list-key rsa PASS list rsa public key pkcs#11 URI" else echo "* TESTCASE list-key rsa FAIL list rsa public key pkcs#11 URI" status=1 fi if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_DH_PKCS_KEY_PAIR_GEN) ]]; then # check DH public key grep -q "p11sak-dh:pub" $P11SAK_DH_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key dh PASS Generated random dh public key" else echo "* TESTCASE generate-key dh FAIL Failed to generate dh public key" status=1 fi grep -v -q "p11sak-dh:pub" $P11SAK_DH_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key dh PASS Deleted generated dh public key" else echo "* TESTCASE remove-key dh FAIL Failed to delete generated dh public key" status=1 fi # check DH private key grep -q "p11sak-dh:prv" $P11SAK_DH_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key dh PASS Generated random dh private key" else echo "* TESTCASE generate-key dh FAIL Failed to generate dh private key" status=1 fi grep -v -q "p11sak-dh:prv" $P11SAK_DH_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key dh PASS Deleted generated dh private key" else echo "* TESTCASE remove-key dh FAIL Failed to delete generated dh private key" status=1 fi # CK_BBOOL if [[ $(grep -c "CKA_MODIFIABLE: CK_TRUE" $P11SAK_DH_LONG) == "2" ]]; then echo "* TESTCASE list-key dh PASS Listed random dh keys CK_BBOOL attribute" else echo "* TESTCASE list-key dh FAIL Failed to list dh keys CK_BBOOL attribute" status=1 fi # CK_ULONG if [[ $(grep -c "CKA_VALUE_BITS:" $P11SAK_DH_LONG) == "1" ]]; then echo "* TESTCASE list-key dh PASS Listed random dh keys CK_ULONG attribute" else echo "* TESTCASE list-key dh FAIL Failed to list dh keys CK_ULONG attribute" status=1 fi # CK_BYTE if [[ $(grep -c "CKA_PRIME:" $P11SAK_DH_LONG) == "2" ]]; then echo "* TESTCASE list-key dh PASS Listed random dh keys CK_BYTE attribute" else echo "* TESTCASE list-key dh FAIL Failed to list dh keys CK_BYTE attribute" status=1 fi # URI if [[ $(grep -c "URI: pkcs11:.*type=public" $P11SAK_DH_LONG) == "1" ]]; then echo "* TESTCASE list-key dh PASS list dh public key pkcs#11 URI" else echo "* TESTCASE list-key dh FAIL list dh public key pkcs#11 URI" status=1 fi else echo "* TESTCASE generate-key dh SKIP generate dh public key" echo "* TESTCASE remove-key dh SKIP delete generated dh public key" echo "* TESTCASE generate-key dh SKIP generate dh private key" echo "* TESTCASE remove-key dh SKIP delete generated dh private key" echo "* TESTCASE list-key dh SKIP list dh keys CK_BBOOL attribute" echo "* TESTCASE list-key dh SKIP list dh keys CK_ULONG attribute" echo "* TESTCASE list-key dh SKIP list dh keys CK_BYTE attribute" echo "* TESTCASE list-key dh SKIP list dh public key pkcs#11 URI" fi if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_DSA_KEY_PAIR_GEN) ]]; then # check DSA public key grep -q "p11sak-dsa:pub" $P11SAK_DSA_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key dsa PASS Generated random dsa public key" else echo "* TESTCASE generate-key dsa FAIL Failed to generate dsa public key" status=1 fi grep -v -q "p11sak-dsa:pub" $P11SAK_DSA_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key dsa PASS Deleted generated dsa public key" else echo "* TESTCASE remove-key dsa FAIL Failed to delete generated dsa public key" status=1 fi # check DSA private key grep -q "p11sak-dsa:prv" $P11SAK_DSA_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key dsa PASS Generated random dsa private key" else echo "* TESTCASE generate-key dsa FAIL Failed to generate dsa private key" status=1 fi grep -v -q "p11sak-dsa:prv" $P11SAK_DSA_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key dsa PASS Deleted generated dsa private key" else echo "* TESTCASE remove-key dsa FAIL Failed to delete generated dsa private key" status=1 fi # CK_BBOOL if [[ $(grep -c "CKA_MODIFIABLE: CK_TRUE" $P11SAK_DSA_LONG) == "2" ]]; then echo "* TESTCASE list-key dsa PASS Listed random dsa keys CK_BBOOL attribute" else echo "* TESTCASE list-key dsa FAIL Failed to list dsa keys CK_BBOOL attribute" status=1 fi # CK_ULONG if [[ $(grep -c "CKA_VALUE_BITS:" $P11SAK_DSA_LONG) == "0" ]]; then echo "* TESTCASE list-key dsa PASS Listed random dsa keys CK_ULONG attribute" else echo "* TESTCASE list-key dsa FAIL Failed to list dsa keys CK_ULONG attribute" status=1 fi # CK_BYTE if [[ $(grep -c "CKA_PRIME:" $P11SAK_DSA_LONG) == "2" ]]; then echo "* TESTCASE list-key dsa PASS Listed random dsa keys CK_BYTE attribute" else echo "* TESTCASE list-key dsa FAIL Failed to list dsa keys CK_BYTE attribute" status=1 fi # URI if [[ $(grep -c "URI: pkcs11:.*type=public" $P11SAK_DSA_LONG) == "1" ]]; then echo "* TESTCASE list-key dsa PASS list dsa public key pkcs#11 URI" else echo "* TESTCASE list-key dsa FAIL list dsa public key pkcs#11 URI" status=1 fi else echo "* TESTCASE generate-key dsa SKIP generate dsa public key" echo "* TESTCASE remove-key dsa SKIP delete generated dsa public key" echo "* TESTCASE generate-key dsa SKIP generate dsa private key" echo "* TESTCASE remove-key dsa SKIP delete generated dsa private key" echo "* TESTCASE list-key dsa SKIP list dsa keys CK_BBOOL attribute" echo "* TESTCASE list-key dsa SKIP list dsa keys CK_ULONG attribute" echo "* TESTCASE list-key dsa SKIP list dsa keys CK_BYTE attribute" echo "* TESTCASE list-key dsa SKIP list dsa public key pkcs#11 URI" fi # check EC prime256v1 public key grep -q "p11sak-ec-prime256v1:pub" $P11SAK_EC_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key ec prime256v1 PASS Generated random ec prime256v1 public key" else echo "* TESTCASE generate-key ec prime256v1 FAIL Failed to generate ec prime256v1 public key" status=1 fi grep -v -q "p11sak-ec-prime256v1:pub" $P11SAK_EC_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key ec prime256v1 PASS Deleted generated ec prime256v1 public key" else echo "* TESTCASE remove-key ec prime256v1 FAIL Failed to delete generated ec prime256v1 public key" status=1 fi # check EC secp384r1 public key grep -q "p11sak-ec-secp384r1:pub" $P11SAK_EC_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key ec secp384r1 PASS Generated random ec secp384r1 public key" else echo "* TESTCASE generate-key ec secp384r1 FAIL Failed to generate ec secp384r1 public key" status=1 fi grep -v -q "p11sak-ec-secp384r1:pub" $P11SAK_EC_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key ec secp384r1 PASS Deleted generated ec secp384r1 public key" else echo "* TESTCASE remove-key ec secp384r1 FAIL Failed to delete generated ec secp384r1 public key" status=1 fi # check EC secp521r1 public key grep -q "p11sak-ec-secp521r1:pub" $P11SAK_EC_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key ec secp521r1 PASS Generated random ec secp521r1 public key" else echo "* TESTCASE generate-key ec secp521r1 FAIL Failed to generate ec secp521r1 public key" status=1 fi grep -v -q "p11sak-ec-secp521r1:pub" $P11SAK_EC_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key ec secp521r1 PASS Deleted generated ec secp521r1 public key" else echo "* TESTCASE remove-key ec secp521r1 FAIL Failed to delete generated ec secp521r1 public key" status=1 fi # check EC prime256v1 private key grep -q "p11sak-ec-prime256v1:prv" $P11SAK_EC_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key ec prime256v1 PASS Generated random ec prime256v1 private key" else echo "* TESTCASE generate-key ec prime256v1 FAIL Failed to generate ec prime256v1 private key" status=1 fi grep -v -q "p11sak-ec-prime256v1:prv" $P11SAK_EC_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key ec prime256v1 PASS Deleted generated ec prime256v1 private key" else echo "* TESTCASE remove-key ec prime256v1 FAIL Failed to delete generated ec prime256v1 private key" status=1 fi # check EC secp384r1 private key grep -q "p11sak-ec-secp384r1:prv" $P11SAK_EC_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key ec secp384r1 PASS Generated random ec secp384r1 private key" else echo "* TESTCASE generate-key ec secp384r1 FAIL Failed to generate ec secp384r1 private key" status=1 fi grep -v -q "p11sak-ec-secp384r1:prv" $P11SAK_EC_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key ec secp384r1 PASS Deleted generated ec secp384r1 private key" else echo "* TESTCASE remove-key ec secp384r1 FAIL Failed to delete generated ec secp384r1 private key" status=1 fi # check EC secp521r1 private key grep -q "p11sak-ec-secp521r1:prv" $P11SAK_EC_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key ec secp521r1 PASS Generated random ec secp521r1 private key" else echo "* TESTCASE generate-key ec secp521r1 FAIL Failed to generate ec secp521r1 private key" status=1 fi grep -v -q "p11sak-ec-secp521r1:prv" $P11SAK_EC_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key ec secp521r1 PASS Deleted generated ec secp521r1 private key" else echo "* TESTCASE remove-key ec secp521r1 FAIL Failed to delete generated ec secp521r1 private key" status=1 fi # CK_BBOOL if [[ $(grep -c "CKA_MODIFIABLE: CK_TRUE" $P11SAK_EC_LONG) == "6" ]]; then echo "* TESTCASE list-key ec PASS Listed random ec keys CK_BBOOL attribute" else echo "* TESTCASE list-key ec FAIL Failed to list ec keys CK_BBOOL attribute" status=1 fi # CK_ULONG if [[ $(grep -c "CKA_MODULUS_BITS:" $P11SAK_EC_LONG) == "0" ]]; then echo "* TESTCASE list-key ec PASS Listed random ec keys CK_ULONG attribute" else echo "* TESTCASE list-key ec FAIL Failed to list ec keys CK_ULONG attribute" status=1 fi # CK_BYTE if [[ $(grep -c "CKA_EC_POINT:" $P11SAK_EC_LONG) == "3" ]]; then echo "* TESTCASE list-key ec PASS Listed random ec keys CK_BYTE attribute" else echo "* TESTCASE list-key ec FAIL Failed to list ec keys CK_BYTE attribute" status=1 fi # URI if [[ $(grep -c "URI: pkcs11:.*type=public" $P11SAK_EC_LONG) == "3" ]]; then echo "* TESTCASE list-key ec PASS list ec public key pkcs#11 URI" else echo "* TESTCASE list-key ec FAIL list ec public key pkcs#11 URI" status=1 fi if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_EC_EDWARDS_KEY_PAIR_GEN) ]]; then # check ec-edwards ed25519 public key grep -q "p11sak-ec-edwards-ed25519:pub" $P11SAK_EC_EDWARDS_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key ec-edwards ed25519 PASS Generated random ec-edwards ed25519 public key" else echo "* TESTCASE generate-key ec-edwards ed25519 FAIL Failed to generate ec-edwards ed25519 public key" status=1 fi grep -v -q "p11sak-ec-edwards-ed25519:pub" $P11SAK_EC_EDWARDS_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key ec-edwards ed25519 PASS Delete generated ec-edwards ed25519 public key" else echo "* TESTCASE remove-key ec-edwards ed25519 FAIL Failed to delete generated ec-edwards ed25519 public key" status=1 fi # check ec-edwards ed448 public key grep -q "p11sak-ec-edwards-ed448:pub" $P11SAK_EC_EDWARDS_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key ec-edwards ed448 PASS Generated random ec-edwards ed448 public key" else echo "* TESTCASE generate-key ec-edwards ed448 FAIL Failed to generate ec-edwards ed448 public key" status=1 fi grep -v -q "p11sak-ec-edwards-ed448:pub" $P11SAK_EC_EDWARDS_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key ec-edwards ed448 PASS Delete generated ec-edwards ed448 public key" else echo "* TESTCASE remove-key ec-edwards ed448 FAIL Failed to delete generated ec-edwards ed448 public key" status=1 fi # check ec-edwards ed25519 private key grep -q "p11sak-ec-edwards-ed25519:prv" $P11SAK_EC_EDWARDS_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key ec-edwards ed25519 PASS Generated random ec-edwards ed25519 private key" else echo "* TESTCASE generate-key ec-edwards ed25519 FAIL Failed to generate ec-edwards ed25519 private key" status=1 fi grep -v -q "p11sak-ec-edwards-ed25519:prv" $P11SAK_EC_EDWARDS_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key ec-edwards ed25519 PASS Delete generated ec-edwards ed25519 private key" else echo "* TESTCASE remove-key ec-edwards ed25519 FAIL Failed to delete generated ec-edwards ed25519 private key" status=1 fi # check ec-edwards ed448 private key grep -q "p11sak-ec-edwards-ed448:prv" $P11SAK_EC_EDWARDS_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key ec-edwards ed448 PASS Generated random ec-edwards ed448 private key" else echo "* TESTCASE generate-key ec-edwards ed448 FAIL Failed to generate ec-edwards ed448 private key" status=1 fi grep -v -q "p11sak-ec-edwards-ed448:prv" $P11SAK_EC_EDWARDS_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key ec-edwards ed448 PASS Delete generated ec-edwards ed448 private key" else echo "* TESTCASE remove-key ec-edwards ed448 FAIL Failed to delete generated ec-edwards ed448 private key" status=1 fi # CK_BBOOL if [[ $(grep -c "CKA_MODIFIABLE: CK_TRUE" $P11SAK_EC_EDWARDS_LONG) == "4" ]]; then echo "* TESTCASE list-key ec-edwards PASS Listed random ec-edwards keys CK_BBOOL attribute" else echo "* TESTCASE list-key ec-edwards FAIL Failed to list ec-edwards keys CK_BBOOL attribute" status=1 fi # CK_ULONG if [[ $(grep -c "CKA_MODULUS_BITS:" $P11SAK_EC_EDWARDS_LONG) == "0" ]]; then echo "* TESTCASE list-key ec-edwards PASS Listed random ec-edwards keys CK_ULONG attribute" else echo "* TESTCASE list-key ec-edwards FAIL Failed to list ec-edwards keys CK_ULONG attribute" status=1 fi # CK_BYTE if [[ $(grep -c "CKA_EC_POINT:" $P11SAK_EC_EDWARDS_LONG) == "2" ]]; then echo "* TESTCASE list-key ec-edwards PASS Listed random ec-edwards keys CK_BYTE attribute" else echo "* TESTCASE list-key ec-edwards FAIL Failed to list ec-edwards keys CK_BYTE attribute" status=1 fi # URI if [[ $(grep -c "URI: pkcs11:.*type=public" $P11SAK_EC_EDWARDS_LONG) == "2" ]]; then echo "* TESTCASE list-key ec-edwards PASS list ec-edwards public key pkcs#11 URI" else echo "* TESTCASE list-key ec-edwards FAIL list ec-edwards public key pkcs#11 URI" status=1 fi else echo "* TESTCASE generate-key ec-edwards ed25519 SKIP Generated random ec-edwards ed25519 public key" echo "* TESTCASE remove-key ec-edwards ed25519 SKIP Delete generated ec-edwards ed25519 public key" echo "* TESTCASE generate-key ec-edwards ed448 SKIP Generated random ec-edwards ed448 public key" echo "* TESTCASE remove-key ec-edwards ed448 SKIP Delete generated ec-edwards ed448 public key" echo "* TESTCASE generate-key ec-edwards ed25519 SKIP Generated random ec-edwards ed25519 private key" echo "* TESTCASE remove-key ec-edwards ed25519 SKIP Delete generated ec-edwards ed25519 private key" echo "* TESTCASE generate-key ec-edwards ed448 SKIP Generated random ec-edwards ed448 private key" echo "* TESTCASE remove-key ec-edwards ed448 SKIP Delete generated ec-edwards ed448 private key" echo "* TESTCASE list-key ec-edwards SKIP Listed random ec-edwards keys CK_BBOOL attribute" echo "* TESTCASE list-key ec-edwards SKIP Listed random ec-edwards keys CK_ULONG attribute" echo "* TESTCASE list-key ec-edwards SKIP Listed random ec-edwards keys CK_BYTE attribute" echo "* TESTCASE list-key ec-edwards SKIP Listed random ec-edwards public key pkcs#11 URI" fi if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_EC_MONTGOMERY_KEY_PAIR_GEN) ]]; then # check ec-montgomery x25519 public key grep -q "p11sak-ec-montgomery-x25519:pub" $P11SAK_EC_MONTGOMERY_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key ec-montgomery x25519 PASS Generated random ec-montgomery x25519 public key" else echo "* TESTCASE generate-key ec-montgomery x25519 FAIL Failed to generate ec-montgomery x25519 public key" status=1 fi grep -v -q "p11sak-ec-montgomery-x25519:pub" $P11SAK_EC_MONTGOMERY_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key ec-montgomery x25519 PASS Delete generated ec-montgomery x25519 public key" else echo "* TESTCASE remove-key ec-montgomery x25519 FAIL Failed to delete generated ec-montgomery x25519 public key" status=1 fi # check ec-montgomery x448 public key grep -q "p11sak-ec-montgomery-x448:pub" $P11SAK_EC_MONTGOMERY_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key ec-montgomery x448 PASS Generated random ec-montgomery x448 public key" else echo "* TESTCASE generate-key ec-montgomery x448 FAIL Failed to generate ec-montgomery x448 public key" status=1 fi grep -v -q "p11sak-ec-montgomery-x448:pub" $P11SAK_EC_MONTGOMERY_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key ec-montgomery x448 PASS Delete generated ec-montgomery x448 public key" else echo "* TESTCASE remove-key ec-montgomery x448 FAIL Failed to delete generated ec-montgomery x448 public key" status=1 fi # check ec-montgomery x25519 private key grep -q "p11sak-ec-montgomery-x25519:prv" $P11SAK_EC_MONTGOMERY_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key ec-montgomery x25519 PASS Generated random ec-montgomery x25519 private key" else echo "* TESTCASE generate-key ec-montgomery x25519 FAIL Failed to generate ec-montgomery x25519 private key" status=1 fi grep -v -q "p11sak-ec-montgomery-x25519:prv" $P11SAK_EC_MONTGOMERY_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key ec-montgomery x25519 PASS Delete generated ec-montgomery x25519 private key" else echo "* TESTCASE remove-key ec-montgomery x25519 FAIL Failed to delete generated ec-montgomery x25519 private key" status=1 fi # check ec-montgomery x448 private key grep -q "p11sak-ec-montgomery-x448:prv" $P11SAK_EC_MONTGOMERY_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key ec-montgomery x448 PASS Generated random ec-montgomery x448 private key" else echo "* TESTCASE generate-key ec-montgomery x448 FAIL Failed to generate ec-montgomery x448 private key" status=1 fi grep -v -q "p11sak-ec-montgomery-x448:prv" $P11SAK_EC_MONTGOMERY_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key ec-montgomery x448 PASS Delete generated ec-montgomery x448 private key" else echo "* TESTCASE remove-key ec-montgomery x448 FAIL Failed to delete generated ec-montgomery x448 private key" status=1 fi # CK_BBOOL if [[ $(grep -c "CKA_MODIFIABLE: CK_TRUE" $P11SAK_EC_MONTGOMERY_LONG) == "4" ]]; then echo "* TESTCASE list-key ec-montgomery PASS Listed random ec-montgomery keys CK_BBOOL attribute" else echo "* TESTCASE list-key ec-montgomery FAIL Failed to list ec-montgomery keys CK_BBOOL attribute" status=1 fi # CK_ULONG if [[ $(grep -c "CKA_MODULUS_BITS:" $P11SAK_EC_MONTGOMERY_LONG) == "0" ]]; then echo "* TESTCASE list-key ec-montgomery PASS Listed random ec-montgomery keys CK_ULONG attribute" else echo "* TESTCASE list-key ec-montgomery FAIL Failed to list ec-montgomery keys CK_ULONG attribute" status=1 fi # CK_BYTE if [[ $(grep -c "CKA_EC_POINT:" $P11SAK_EC_MONTGOMERY_LONG) == "2" ]]; then echo "* TESTCASE list-key ec-montgomery PASS Listed random ec-montgomery keys CK_BYTE attribute" else echo "* TESTCASE list-key ec-montgomery FAIL Failed to list ec-montgomery keys CK_BYTE attribute" status=1 fi # URI if [[ $(grep -c "URI: pkcs11:.*type=public" $P11SAK_EC_MONTGOMERY_LONG) == "2" ]]; then echo "* TESTCASE list-key ec-montgomery PASS list ec-montgomery public key pkcs#11 URI" else echo "* TESTCASE list-key ec-montgomery FAIL list ec-montgomery public key pkcs#11 URI" status=1 fi else echo "* TESTCASE generate-key ec-montgomery x25519 SKIP Generated random ec-montgomery x25519 public key" echo "* TESTCASE remove-key ec-montgomery x25519 SKIP Delete generated ec-montgomery x25519 public key" echo "* TESTCASE generate-key ec-montgomery x448 SKIP Generated random ec-montgomery x448 public key" echo "* TESTCASE remove-key ec-montgomery x448 SKIP Delete generated ec-montgomery x448 public key" echo "* TESTCASE generate-key ec-montgomery x25519 SKIP Generated random ec-montgomery x25519 private key" echo "* TESTCASE remove-key ec-montgomery x25519 SKIP Delete generated ec-montgomery x25519 private key" echo "* TESTCASE generate-key ec-montgomery x448 SKIP Generated random ec-montgomery x448 private key" echo "* TESTCASE remove-key ec-montgomery x448 SKIP Delete generated ec-montgomery x448 private key" echo "* TESTCASE list-key ec-montgomery SKIP Listed random ec-montgomery keys CK_BBOOL attribute" echo "* TESTCASE list-key ec-montgomery SKIP Listed random ec-montgomery keys CK_ULONG attribute" echo "* TESTCASE list-key ec-montgomery SKIP Listed random ec-montgomery keys CK_BYTE attribute" echo "* TESTCASE list-key ec-montgomery SKIP Listed random ec-montgomery public key pkcs#11 URI" fi if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_IBM_DILITHIUM) ]]; then # CK_BBOOL if [[ $(grep -c "CKA_MODIFIABLE: CK_TRUE" $P11SAK_IBM_DILITHIUM_LONG) == "2" ]]; then echo "* TESTCASE list-key ibm-dilithium PASS Listed random ibm-dilithium keys CK_BBOOL attribute" else echo "* TESTCASE list-key ibm-dilithium FAIL Failed to list ibm-dilithium keys CK_BBOOL attribute" status=1 fi # CK_ULONG if [[ $(grep -c "CKA_IBM_DILITHIUM_KEYFORM:" $P11SAK_IBM_DILITHIUM_LONG) == "2" ]]; then echo "* TESTCASE list-key ibm-dilithium PASS Listed random ibm-dilithium keys CK_ULONG attribute" else echo "* TESTCASE list-key ibm-dilithium FAIL Failed to list ibm-dilithium keys CK_ULONG attribute" status=1 fi # CK_BYTE if [[ $(grep -c "CKA_IBM_DILITHIUM_RHO:" $P11SAK_IBM_DILITHIUM_LONG) == "2" ]]; then echo "* TESTCASE list-key ibm-dilithium PASS Listed random ibm-dilithium keys CK_BYTE attribute" else echo "* TESTCASE list-key ibm-dilithium FAIL Failed to list ibm-dilithium keys CK_BYTE attribute" status=1 fi else echo "* TESTCASE list-key ibm-dilithium SKIP Listed random ibm-dilithium keys CK_BBOOL attribute" echo "* TESTCASE list-key ibm-dilithium SKIP Listed random ibm-dilithium keys CK_ULONG attribute" echo "* TESTCASE list-key ibm-dilithium SKIP Listed random ibm-dilithium keys CK_BYTE attribute" fi if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_IBM_KYBER) ]]; then # CK_BBOOL if [[ $(grep -c "CKA_MODIFIABLE: CK_TRUE" $P11SAK_IBM_KYBER_LONG) == "2" ]]; then echo "* TESTCASE list-key ibm-kyber PASS Listed random ibm-kyber keys CK_BBOOL attribute" else echo "* TESTCASE list-key ibm-kyber FAIL Failed to list ibm-kyber keys CK_BBOOL attribute" status=1 fi # CK_ULONG if [[ $(grep -c "CKA_IBM_KYBER_KEYFORM:" $P11SAK_IBM_KYBER_LONG) == "2" ]]; then echo "* TESTCASE list-key ibm-kyber PASS Listed random ibm-kyber keys CK_ULONG attribute" else echo "* TESTCASE list-key ibm-kyber FAIL Failed to list ibm-kyber keys CK_ULONG attribute" status=1 fi # CK_BYTE if [[ $(grep -c "CKA_IBM_KYBER_PK:" $P11SAK_IBM_KYBER_LONG) == "2" ]]; then echo "* TESTCASE list-key ibm-kyber PASS Listed random ibm-kyber keys CK_BYTE attribute" else echo "* TESTCASE list-key ibm-kyber FAIL Failed to list ibm-kyber keys CK_BYTE attribute" status=1 fi else echo "* TESTCASE list-key ibm-kyber SKIP Listed random ibm-kyber keys CK_BBOOL attribute" echo "* TESTCASE list-key ibm-kyber SKIP Listed random ibm-kyber keys CK_ULONG attribute" echo "* TESTCASE list-key ibm-kyber SKIP Listed random ibm-kyber keys CK_BYTE attribute" fi if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_IBM_ML_DSA) ]]; then # CK_BBOOL if [[ $(grep -c "CKA_MODIFIABLE: CK_TRUE" $P11SAK_IBM_ML_DSA_LONG) == "2" ]]; then echo "* TESTCASE list-key ibm-ml-dsa PASS Listed random ibm-ml-dsa keys CK_BBOOL attribute" else echo "* TESTCASE list-key ibm-ml-dsa FAIL Failed to list ibm-ml-dsa keys CK_BBOOL attribute" status=1 fi # CK_ULONG if [[ $(grep -c "CKA_IBM_PARAMETER_SET:" $P11SAK_IBM_ML_DSA_LONG) == "2" ]]; then echo "* TESTCASE list-key ibm-ml-dsa PASS Listed random ibm-ml-dsa keys CK_ULONG attribute" else echo "* TESTCASE list-key ibm-ml-dsa FAIL Failed to list ibm-ml-dsa keys CK_ULONG attribute" status=1 fi # CK_BYTE if [[ $(grep -c "CKA_VALUE:" $P11SAK_IBM_ML_DSA_LONG) == "2" ]]; then echo "* TESTCASE list-key ibm-ml-dsa PASS Listed random ibm-ml-dsa keys CK_BYTE attribute" else echo "* TESTCASE list-key ibm-ml-dsa FAIL Failed to list ibm-ml-dsa keys CK_BYTE attribute" status=1 fi else echo "* TESTCASE list-key ibm-ml-dsa SKIP Listed random ibm-ml-dsa keys CK_BBOOL attribute" echo "* TESTCASE list-key ibm-ml-dsa SKIP Listed random ibm-ml-dsa keys CK_ULONG attribute" echo "* TESTCASE list-key ibm-ml-dsa SKIP Listed random ibm-ml-dsa keys CK_BYTE attribute" fi if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_IBM_ML_KEM) ]]; then # CK_BBOOL if [[ $(grep -c "CKA_MODIFIABLE: CK_TRUE" $P11SAK_IBM_ML_KEM_LONG) == "2" ]]; then echo "* TESTCASE list-key ibm-ml-kem PASS Listed random ibm-ml-kem keys CK_BBOOL attribute" else echo "* TESTCASE list-key ibm-ml-kem FAIL Failed to list ibm-ml-kem keys CK_BBOOL attribute" status=1 fi # CK_ULONG if [[ $(grep -c "CKA_IBM_PARAMETER_SET:" $P11SAK_IBM_ML_KEM_LONG) == "2" ]]; then echo "* TESTCASE list-key ibm-ml-kem PASS Listed random ibm-ml-kem keys CK_ULONG attribute" else echo "* TESTCASE list-key ibm-ml-kem FAIL Failed to list ibm-ml-kem keys CK_ULONG attribute" status=1 fi # CK_BYTE if [[ $(grep -c "CKA_VALUE:" $P11SAK_IBM_ML_KEM_LONG) == "2" ]]; then echo "* TESTCASE list-key ibm-ml-kem PASS Listed random ibm-ml-kem keys CK_BYTE attribute" else echo "* TESTCASE list-key ibm-ml-kem FAIL Failed to list ibm-ml-kem keys CK_BYTE attribute" status=1 fi else echo "* TESTCASE list-key ibm-ml-kem SKIP Listed random ibm-ml-kem keys CK_BBOOL attribute" echo "* TESTCASE list-key ibm-ml-kem SKIP Listed random ibm-ml-kem keys CK_ULONG attribute" echo "* TESTCASE list-key ibm-ml-kem SKIP Listed random ibm-ml-kem keys CK_BYTE attribute" fi if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_ML_DSA) ]]; then # CK_BBOOL if [[ $(grep -c "CKA_MODIFIABLE: CK_TRUE" $P11SAK_ML_DSA_LONG) == "2" ]]; then echo "* TESTCASE list-key ml-dsa PASS Listed random ml-dsa keys CK_BBOOL attribute" else echo "* TESTCASE list-key ml-dsa FAIL Failed to list ml-dsa keys CK_BBOOL attribute" status=1 fi # CK_ULONG if [[ $(grep -c "CKA_PARAMETER_SET:" $P11SAK_ML_DSA_LONG) == "2" ]]; then echo "* TESTCASE list-key ml-dsa PASS Listed random ml-dsa keys CK_ULONG attribute" else echo "* TESTCASE list-key ml-dsa FAIL Failed to list ml-dsa keys CK_ULONG attribute" status=1 fi # CK_BYTE if [[ $(grep -c "CKA_VALUE:" $P11SAK_ML_DSA_LONG) == "2" ]]; then echo "* TESTCASE list-key ml-dsa PASS Listed random ml-dsa keys CK_BYTE attribute" else echo "* TESTCASE list-key ml-dsa FAIL Failed to list ml-dsa keys CK_BYTE attribute" status=1 fi else echo "* TESTCASE list-key ml-dsa SKIP Listed random ml-dsa keys CK_BBOOL attribute" echo "* TESTCASE list-key ml-dsa SKIP Listed random ml-dsa keys CK_ULONG attribute" echo "* TESTCASE list-key ml-dsa SKIP Listed random ml-dsa keys CK_BYTE attribute" fi if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_ML_KEM) ]]; then # CK_BBOOL if [[ $(grep -c "CKA_MODIFIABLE: CK_TRUE" $P11SAK_ML_KEM_LONG) == "2" ]]; then echo "* TESTCASE list-key ml-kem PASS Listed random ml-kem keys CK_BBOOL attribute" else echo "* TESTCASE list-key ml-kem FAIL Failed to list ml-kem keys CK_BBOOL attribute" status=1 fi # CK_ULONG if [[ $(grep -c "CKA_PARAMETER_SET:" $P11SAK_ML_KEM_LONG) == "2" ]]; then echo "* TESTCASE list-key ml-kem PASS Listed random ml-kem keys CK_ULONG attribute" else echo "* TESTCASE list-key ml-kem FAIL Failed to list ml-kem keys CK_ULONG attribute" status=1 fi # CK_BYTE if [[ $(grep -c "CKA_VALUE:" $P11SAK_ML_KEM_LONG) == "2" ]]; then echo "* TESTCASE list-key ml-kem PASS Listed random ml-kem keys CK_BYTE attribute" else echo "* TESTCASE list-key ml-kem FAIL Failed to list ml-kem keys CK_BYTE attribute" status=1 fi else echo "* TESTCASE list-key ml-kem SKIP Listed random ml-kem keys CK_BBOOL attribute" echo "* TESTCASE list-key ml-kem SKIP Listed random ml-kem keys CK_ULONG attribute" echo "* TESTCASE list-key ml-kem SKIP Listed random ml-kem keys CK_BYTE attribute" fi echo "** Import the sample x.509 certificates - 'p11sak_test.sh'" RC_P11SAK_X509_IMPORT=0 ${P11SAK} import-cert x509 --slot $SLOT --pin $PKCS11_USER_PIN --id 123 --label "p11sak-x509-rsa2048crt" --file $DIR/p11sak_rsa2048cert.crt RC_P11SAK_X509_IMPORT=$((RC_P11SAK_X509_IMPORT + $?)) ${P11SAK} import-cert x509 --slot $SLOT --pin $PKCS11_USER_PIN --id 234 --label "p11sak-x509-rsa2048pem" --file $DIR/p11sak_rsa2048cert.pem RC_P11SAK_X509_IMPORT=$((RC_P11SAK_X509_IMPORT + $?)) ${P11SAK} import-cert x509 --slot $SLOT --pin $PKCS11_USER_PIN --id 345 --label "p11sak-x509-rsa4096crt" --file $DIR/p11sak_rsa4096cert.crt RC_P11SAK_X509_IMPORT=$((RC_P11SAK_X509_IMPORT + $?)) ${P11SAK} import-cert x509 --slot $SLOT --pin $PKCS11_USER_PIN --id 456 --label "p11sak-x509-rsa4096pem" --file $DIR/p11sak_rsa4096cert.pem RC_P11SAK_X509_IMPORT=$((RC_P11SAK_X509_IMPORT + $?)) ${P11SAK} import-cert x509 --slot $SLOT --pin $PKCS11_USER_PIN --id 567 --label "p11sak-x509-ecp256crt" --file $DIR/p11sak_ecp256cert.crt RC_P11SAK_X509_IMPORT=$((RC_P11SAK_X509_IMPORT + $?)) ${P11SAK} import-cert x509 --slot $SLOT --pin $PKCS11_USER_PIN --id 678 --label "p11sak-x509-ecp256pem" --file $DIR/p11sak_ecp256cert.pem RC_P11SAK_X509_IMPORT=$((RC_P11SAK_X509_IMPORT + $?)) ${P11SAK} import-cert x509 --slot $SLOT --pin $PKCS11_USER_PIN --id 789 --label "p11sak-x509-ecp384crt" --file $DIR/p11sak_ecp384cert.crt RC_P11SAK_X509_IMPORT=$((RC_P11SAK_X509_IMPORT + $?)) ${P11SAK} import-cert x509 --slot $SLOT --pin $PKCS11_USER_PIN --id 89A --label "p11sak-x509-ecp384pem" --file $DIR/p11sak_ecp384cert.pem RC_P11SAK_X509_IMPORT=$((RC_P11SAK_X509_IMPORT + $?)) ${P11SAK} import-cert x509 --slot $SLOT --pin $PKCS11_USER_PIN --id 789 --label "p11sak-x509-ecp521crt" --file $DIR/p11sak_ecp521cert.crt RC_P11SAK_X509_IMPORT=$((RC_P11SAK_X509_IMPORT + $?)) ${P11SAK} import-cert x509 --slot $SLOT --pin $PKCS11_USER_PIN --id 89A --label "p11sak-x509-ecp521pem" --file $DIR/p11sak_ecp521cert.pem RC_P11SAK_X509_IMPORT=$((RC_P11SAK_X509_IMPORT + $?)) if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_EDDSA) ]]; then ${P11SAK} import-cert x509 --slot $SLOT --pin $PKCS11_USER_PIN --id 9AB --label "p11sak-x509-ed25519crt" --file $DIR/p11sak_ed25519cert.crt RC_P11SAK_X509_IMPORT=$((RC_P11SAK_X509_IMPORT + $?)) ${P11SAK} import-cert x509 --slot $SLOT --pin $PKCS11_USER_PIN --id ABC --label "p11sak-x509-ed25519pem" --file $DIR/p11sak_ed25519cert.pem RC_P11SAK_X509_IMPORT=$((RC_P11SAK_X509_IMPORT + $?)) ${P11SAK} import-cert x509 --slot $SLOT --pin $PKCS11_USER_PIN --id 9AB --label "p11sak-x509-ed448crt" --file $DIR/p11sak_ed448cert.crt RC_P11SAK_X509_IMPORT=$((RC_P11SAK_X509_IMPORT + $?)) ${P11SAK} import-cert x509 --slot $SLOT --pin $PKCS11_USER_PIN --id ABC --label "p11sak-x509-ed448pem" --file $DIR/p11sak_ed448cert.pem RC_P11SAK_X509_IMPORT=$((RC_P11SAK_X509_IMPORT + $?)) else echo "Skip importing x.509 certs with ec-edwards key, slot does not support CKM_EDDSA" fi if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_DSA) ]]; then ${P11SAK} import-cert x509 --slot $SLOT --pin $PKCS11_USER_PIN --id 9AB --label "p11sak-x509-dsa3072crt" --file $DIR/p11sak_dsa3072cert.crt RC_P11SAK_X509_IMPORT=$((RC_P11SAK_X509_IMPORT + $?)) ${P11SAK} import-cert x509 --slot $SLOT --pin $PKCS11_USER_PIN --id ABC --label "p11sak-x509-dsa3072pem" --file $DIR/p11sak_dsa3072cert.pem RC_P11SAK_X509_IMPORT=$((RC_P11SAK_X509_IMPORT + $?)) ${P11SAK} import-cert x509 --slot $SLOT --pin $PKCS11_USER_PIN --id 9AB --label "p11sak-x509-dsa4096crt" --file $DIR/p11sak_dsa4096cert.crt RC_P11SAK_X509_IMPORT=$((RC_P11SAK_X509_IMPORT + $?)) ${P11SAK} import-cert x509 --slot $SLOT --pin $PKCS11_USER_PIN --id ABC --label "p11sak-x509-dsa4096pem" --file $DIR/p11sak_dsa4096cert.pem RC_P11SAK_X509_IMPORT=$((RC_P11SAK_X509_IMPORT + $?)) else echo "Skip importing x.509 certs with DSA key, slot does not support CKM_DSA" fi if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_IBM_DILITHIUM) && -n $(openssl list -providers | grep oqsprovider) && -n $(openssl list -key-managers | grep "dilithium3 @ oqsprovider") ]]; then openssl req -x509 -new -newkey dilithium3 -keyout dilithium3_CA.key -out dilithium3_CA.crt -nodes -subj "/CN=test CA" -days 365 2>/dev/null RC_P11SAK_X509_IMPORT=$((RC_P11SAK_X509_IMPORT + $?)) openssl genpkey -algorithm dilithium3 -out dilithium3_srv.key RC_P11SAK_X509_IMPORT=$((RC_P11SAK_X509_IMPORT + $?)) openssl req -new -newkey dilithium3 -keyout dilithium3_srv.key -out dilithium3_srv.csr -nodes -subj "/CN=test server" 2>/dev/null RC_P11SAK_X509_IMPORT=$((RC_P11SAK_X509_IMPORT + $?)) openssl x509 -req -in dilithium3_srv.csr -out dilithium3_srv.crt -CA dilithium3_CA.crt -CAkey dilithium3_CA.key -CAcreateserial -days 365 2>/dev/null RC_P11SAK_X509_IMPORT=$((RC_P11SAK_X509_IMPORT + $?)) ${P11SAK} import-cert x509 --slot $SLOT --pin $PKCS11_USER_PIN --id ABC --label "p11sak-x509-dilithium3" --file dilithium3_srv.crt RC_P11SAK_X509_IMPORT=$((RC_P11SAK_X509_IMPORT + $?)) else echo "Skip importing x.509 certs with IBM Dilithum key, slot does not support CKM_IBM_DILITHIUM or oqsprovider not available or does not support dilithium3" fi if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_ML_DSA) && -n $(openssl list -key-managers | grep -i "MLDSA65") ]]; then openssl req -x509 -new -newkey mldsa65 -keyout mldsa65_CA.key -out mldsa65_CA.crt -nodes -subj "/CN=test CA" -days 365 2>/dev/null RC_P11SAK_X509_IMPORT=$((RC_P11SAK_X509_IMPORT + $?)) openssl genpkey -algorithm mldsa65 -out mldsa65_srv.key RC_P11SAK_X509_IMPORT=$((RC_P11SAK_X509_IMPORT + $?)) openssl req -new -newkey mldsa65 -keyout mldsa65_srv.key -out mldsa65_srv.csr -nodes -subj "/CN=test server" 2>/dev/null RC_P11SAK_X509_IMPORT=$((RC_P11SAK_X509_IMPORT + $?)) openssl x509 -req -in mldsa65_srv.csr -out mldsa65_srv.crt -CA mldsa65_CA.crt -CAkey mldsa65_CA.key -CAcreateserial -days 365 2>/dev/null RC_P11SAK_X509_IMPORT=$((RC_P11SAK_X509_IMPORT + $?)) ${P11SAK} import-cert x509 --slot $SLOT --pin $PKCS11_USER_PIN --id ABC --label "p11sak-x509-mldsa65" --file mldsa65_srv.crt RC_P11SAK_X509_IMPORT=$((RC_P11SAK_X509_IMPORT + $?)) else echo "Skip importing x.509 certs with ML-DSA key, slot does not support CKM_ML_DSA or neither OpenSSL 3.5, nor oqsprovider not available or does not support mldsa65" fi echo "** Now exporting x.509 certificates - 'p11sak_test.sh'" RC_P11SAK_X509_EXPORT=0 # x.509 ${P11SAK} export-cert x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-rsa2048crt" --file p11sak_rsa2048cert_exported.crt --der --force RC_P11SAK_X509_EXPORT=$((RC_P11SAK_X509_EXPORT + $?)) ${P11SAK} export-cert x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-rsa2048pem" --file p11sak_rsa2048cert_exported.pem --force RC_P11SAK_X509_EXPORT=$((RC_P11SAK_X509_EXPORT + $?)) ${P11SAK} export-cert x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-rsa4096crt" --file p11sak_rsa4096cert_exported.crt --der --force RC_P11SAK_X509_EXPORT=$((RC_P11SAK_X509_EXPORT + $?)) ${P11SAK} export-cert x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-rsa4096pem" --file p11sak_rsa4096cert_exported.pem --force RC_P11SAK_X509_EXPORT=$((RC_P11SAK_X509_EXPORT + $?)) ${P11SAK} export-cert x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-ecp256crt" --file p11sak_ecp256cert_exported.crt --der --force RC_P11SAK_X509_EXPORT=$((RC_P11SAK_X509_EXPORT + $?)) ${P11SAK} export-cert x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-ecp256pem" --file p11sak_ecp256cert_exported.pem --force RC_P11SAK_X509_EXPORT=$((RC_P11SAK_X509_EXPORT + $?)) ${P11SAK} export-cert x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-ecp384crt" --file p11sak_ecp384cert_exported.crt --der --force RC_P11SAK_X509_EXPORT=$((RC_P11SAK_X509_EXPORT + $?)) ${P11SAK} export-cert x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-ecp384pem" --file p11sak_ecp384cert_exported.pem --force RC_P11SAK_X509_EXPORT=$((RC_P11SAK_X509_EXPORT + $?)) ${P11SAK} export-cert x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-ecp521crt" --file p11sak_ecp521cert_exported.crt --der --force RC_P11SAK_X509_EXPORT=$((RC_P11SAK_X509_EXPORT + $?)) ${P11SAK} export-cert x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-ecp521pem" --file p11sak_ecp521cert_exported.pem --force RC_P11SAK_X509_EXPORT=$((RC_P11SAK_X509_EXPORT + $?)) if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_EDDSA) ]]; then ${P11SAK} export-cert x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-ed25519crt" --file p11sak_ed25519cert_exported.crt --der --force RC_P11SAK_X509_EXPORT=$((RC_P11SAK_X509_EXPORT + $?)) ${P11SAK} export-cert x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-ed25519pem" --file p11sak_ed25519cert_exported.pem --force RC_P11SAK_X509_EXPORT=$((RC_P11SAK_X509_EXPORT + $?)) ${P11SAK} export-cert x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-ed448crt" --file p11sak_ed448cert_exported.crt --der --force RC_P11SAK_X509_EXPORT=$((RC_P11SAK_X509_EXPORT + $?)) ${P11SAK} export-cert x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-ed448pem" --file p11sak_ed448cert_exported.pem --force RC_P11SAK_X509_EXPORT=$((RC_P11SAK_X509_EXPORT + $?)) else echo "Skip exporting x.509 certs with ec-edwards key, slot does not support CKM_EDDSA" fi if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_DSA) ]]; then ${P11SAK} export-cert x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-dsa3072crt" --file p11sak_dsa3072cert_exported.crt --der --force RC_P11SAK_X509_EXPORT=$((RC_P11SAK_X509_EXPORT + $?)) ${P11SAK} export-cert x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-dsa3072pem" --file p11sak_dsa3072cert_exported.pem --force RC_P11SAK_X509_EXPORT=$((RC_P11SAK_X509_EXPORT + $?)) ${P11SAK} export-cert x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-dsa4096crt" --file p11sak_dsa4096cert_exported.crt --der --force RC_P11SAK_X509_EXPORT=$((RC_P11SAK_X509_EXPORT + $?)) ${P11SAK} export-cert x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-dsa4096pem" --file p11sak_dsa4096cert_exported.pem --force RC_P11SAK_X509_EXPORT=$((RC_P11SAK_X509_EXPORT + $?)) else echo "Skip exporting x.509 certs with DSA key, slot does not support CKM_DSA" fi if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_IBM_DILITHIUM) && -n $(openssl list -providers | grep oqsprovider) && -n $(openssl list -key-managers | grep "dilithium3 @ oqsprovider") ]]; then ${P11SAK} export-cert x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-dilithium3" --file p11sak_dil3cert_exported.pem --force RC_P11SAK_X509_EXPORT=$((RC_P11SAK_X509_EXPORT + $?)) else echo "Skip exporting x.509 certs with IBM Dilithum key, slot does not support CKM_IBM_DILITHIUM or the oqsprovider not available or does not support dilithium3" fi if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_ML_DSA) && -n $(openssl list -key-managers | grep -i "MLDSA65") ]]; then ${P11SAK} export-cert x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-mldsa65" --file p11sak_mldsa65cert_exported.pem --force RC_P11SAK_X509_EXPORT=$((RC_P11SAK_X509_EXPORT + $?)) else echo "Skip exporting x.509 certs with ML-DSA key, slot does not support CKM_ML_DSA or neither OpenSSL 3.5, nor the oqsprovider not available or does not support mldsa65" fi # export to URI-PEM p11sak export-cert x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-rsa2048crt" --file export-uri-pem4.pem --force --uri-pem RC_P11SAK_X509_EXPORT=$((RC_P11SAK_X509_EXPORT + $?)) openssl asn1parse -i -in export-uri-pem4.pem > /dev/null RC_P11SAK_X509_EXPORT=$((RC_P11SAK_X509_EXPORT + $?)) p11sak export-cert x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-rsa2048crt" --file export-uri-pem5.pem --force --uri-pem --uri-pin-value RC_P11SAK_X509_EXPORT=$((RC_P11SAK_X509_EXPORT + $?)) openssl asn1parse -i -in export-uri-pem5.pem > /dev/null RC_P11SAK_X509_EXPORT=$((RC_P11SAK_X509_EXPORT + $?)) p11sak export-cert x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-rsa2048crt" --file export-uri-pem6.pem --force --uri-pem --uri-pin-source pin2.txt RC_P11SAK_X509_EXPORT=$((RC_P11SAK_X509_EXPORT + $?)) openssl asn1parse -i -in export-uri-pem6.pem > /dev/null RC_P11SAK_X509_EXPORT=$((RC_P11SAK_X509_EXPORT + $?)) if [[ $(cat pin2.txt) != $PKCS11_USER_PIN ]]; then echo "Pin file does not contain the PKCS#11 user pin" RC_P11SAK_X509_EXPORT=$((RC_P11SAK_X509_EXPORT + 1)) fi echo "** Now extracting public keys from x.509 certificates - 'p11sak_test.sh'" RC_P11SAK_X509_EXTRACT=0 ${P11SAK} extract-cert-pubkey x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-rsa2048crt" --force RC_P11SAK_X509_EXTRACT=$((RC_P11SAK_X509_EXTRACT + $?)) ${P11SAK} extract-cert-pubkey x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-rsa2048pem" --force RC_P11SAK_X509_EXTRACT=$((RC_P11SAK_X509_EXTRACT + $?)) ${P11SAK} extract-cert-pubkey x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-rsa4096crt" --force RC_P11SAK_X509_EXTRACT=$((RC_P11SAK_X509_EXTRACT + $?)) ${P11SAK} extract-cert-pubkey x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-rsa4096pem" --force RC_P11SAK_X509_EXTRACT=$((RC_P11SAK_X509_EXTRACT + $?)) ${P11SAK} extract-cert-pubkey x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-ecp256crt" --force RC_P11SAK_X509_EXTRACT=$((RC_P11SAK_X509_EXTRACT + $?)) ${P11SAK} extract-cert-pubkey x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-ecp256pem" --force RC_P11SAK_X509_EXTRACT=$((RC_P11SAK_X509_EXTRACT + $?)) ${P11SAK} extract-cert-pubkey x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-ecp384crt" --force RC_P11SAK_X509_EXTRACT=$((RC_P11SAK_X509_EXTRACT + $?)) ${P11SAK} extract-cert-pubkey x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-ecp384pem" --force RC_P11SAK_X509_EXTRACT=$((RC_P11SAK_X509_EXTRACT + $?)) ${P11SAK} extract-cert-pubkey x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-ecp521crt" --force RC_P11SAK_X509_EXTRACT=$((RC_P11SAK_X509_EXTRACT + $?)) ${P11SAK} extract-cert-pubkey x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-ecp521pem" --force RC_P11SAK_X509_EXTRACT=$((RC_P11SAK_X509_EXTRACT + $?)) if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_EDDSA) ]]; then ${P11SAK} extract-cert-pubkey x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-ed25519crt" --force RC_P11SAK_X509_EXTRACT=$((RC_P11SAK_X509_EXTRACT + $?)) ${P11SAK} extract-cert-pubkey x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-ed25519pem" --force RC_P11SAK_X509_EXTRACT=$((RC_P11SAK_X509_EXTRACT + $?)) ${P11SAK} extract-cert-pubkey x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-ed448crt" --force RC_P11SAK_X509_EXTRACT=$((RC_P11SAK_X509_EXTRACT + $?)) ${P11SAK} extract-cert-pubkey x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-ed448pem" --force RC_P11SAK_X509_EXTRACT=$((RC_P11SAK_X509_EXTRACT + $?)) else echo "Skip extracting pubkeys from x.509 certs with ec-edwards key, slot does not support CKM_EDDSA" fi if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_DSA) ]]; then ${P11SAK} extract-cert-pubkey x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-dsa3072crt" --force RC_P11SAK_X509_EXTRACT=$((RC_P11SAK_X509_EXTRACT + $?)) ${P11SAK} extract-cert-pubkey x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-dsa3072pem" --force RC_P11SAK_X509_EXTRACT=$((RC_P11SAK_X509_EXTRACT + $?)) ${P11SAK} extract-cert-pubkey x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-dsa4096crt" --force RC_P11SAK_X509_EXTRACT=$((RC_P11SAK_X509_EXTRACT + $?)) ${P11SAK} extract-cert-pubkey x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-dsa4096pem" --force RC_P11SAK_X509_EXTRACT=$((RC_P11SAK_X509_EXTRACT + $?)) else echo "Skip extracting pubkeys from x.509 certs with DSA key, slot does not support CKM_DSA" fi if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_IBM_DILITHIUM) && -n $(openssl list -providers | grep oqsprovider) && -n $(openssl list -key-managers | grep "dilithium3 @ oqsprovider") ]]; then ${P11SAK} extract-cert-pubkey x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-dilithium3" --force RC_P11SAK_X509_EXTRACT=$((RC_P11SAK_X509_EXTRACT + $?)) else echo "Skip extracting pubkeys from x.509 certs with IBM Dilithum key, slot does not support CKM_IBM_DILITHIUM or oqsprovider not available or does not support dilithium3" fi if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_ML_DSA) && -n $(openssl list -key-managers | grep -i "MLDSA65") ]]; then ${P11SAK} extract-cert-pubkey x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-mldsa65" --force RC_P11SAK_X509_EXTRACT=$((RC_P11SAK_X509_EXTRACT + $?)) else echo "Skip extracting pubkeys from x.509 certs with ML-DSA key, slot does not support CKM_ML_DSA or neither OpenSSL 3.5, not the oqsprovider not available or does not support mldsa65" fi echo "** Now copying x.509 certificates to new token objects - 'p11sak_test.sh'" RC_P11SAK_X509_COPY=0 ${P11SAK} copy-cert x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-*" --new-label "p11sak-x509-copied" --force RC_P11SAK_X509_COPY=$((RC_P11SAK_X509_COPY + $?)) echo "** Now updating x.509 certs - 'p11sak_test.sh'" RC_P11SAK_X509_UPDATE=0 ${P11SAK} set-cert-attr x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-*" --new-attr "Yt" --force RC_P11SAK_X509_UPDATE=$((RC_P11SAK_X509_UPDATE + $?)) ${P11SAK} set-cert-attr x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-*" --new-id "012345" --force RC_P11SAK_X509_UPDATE=$((RC_P11SAK_X509_UPDATE + $?)) echo "** Now list x509 certificates and extracted pubkeys and redirect output to pre-files - 'p11sak_test.sh'" RC_P11SAK_X509_LIST=0 ${P11SAK} list-cert x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-*" --sort n:a &> $P11SAK_X509_PRE RC_P11SAK_X509_LIST=$((RC_P11SAK_X509_LIST + $?)) ${P11SAK} list-key all --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-*" &>> $P11SAK_X509_PRE RC_P11SAK_X509_LIST=$((RC_P11SAK_X509_LIST + $?)) RC_P11SAK_X509_LIST_LONG=0 ${P11SAK} list-cert x509 --slot $SLOT --pin $PKCS11_USER_PIN --long --label "p11sak-x509-*" --sort l:d,n:a &> $P11SAK_X509_LONG RC_P11SAK_X509_LIST_LONG=$((RC_P11SAK_X509_LIST_LONG + $?)) ${P11SAK} list-key all --slot $SLOT --pin $PKCS11_USER_PIN --long --label "p11sak-x509-*" &>> $P11SAK_X509_LONG RC_P11SAK_X509_LIST_LONG=$((RC_P11SAK_X509_LIST_LONG + $?)) echo "** Now removing x.509 certificates and extracted public keys - 'p11sak_test.sh'" # x.509 RC_P11SAK_X509_REMOVE=0 ${P11SAK} remove-cert x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-*" -f RC_P11SAK_X509_REMOVE=$((RC_P11SAK_X509_REMOVE + $?)) ${P11SAK} remove-key --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-*" -f RC_P11SAK_X509_REMOVE=$((RC_P11SAK_X509_REMOVE + $?)) echo "** Now list certificates and extracted keys and redirect to post-files - 'p11sak_test.sh'" # list objects: if remove was successful above, no certs and extracted keys are left RC_P11SAK_X509_LIST_POST=0 ${P11SAK} list-cert x509 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-*" --sort n:d,l:a &> $P11SAK_X509_POST RC_P11SAK_X509_LIST_POST=$((RC_P11SAK_X509_LIST_POST + $?)) ${P11SAK} list-key all --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-x509-*" &> $P11SAK_X509_POST RC_P11SAK_X509_LIST_POST=$((RC_P11SAK_X509_LIST_POST + $?)) echo "** Now checking output files to determine PASS/FAIL of tests - 'p11sak_test.sh'" # check if exported X509 certificates are equal to original ones RC_P11SAK_X509_DIFF=0 diff $DIR/p11sak_rsa2048cert.crt p11sak_rsa2048cert_exported.crt > /dev/null RC_P11SAK_X509_DIFF=$((RC_P11SAK_X509_DIFF + $?)) diff $DIR/p11sak_rsa2048cert.pem p11sak_rsa2048cert_exported.pem > /dev/null RC_P11SAK_X509_DIFF=$((RC_P11SAK_X509_DIFF + $?)) diff $DIR/p11sak_rsa4096cert.crt p11sak_rsa4096cert_exported.crt > /dev/null RC_P11SAK_X509_DIFF=$((RC_P11SAK_X509_DIFF + $?)) diff $DIR/p11sak_rsa4096cert.pem p11sak_rsa4096cert_exported.pem > /dev/null RC_P11SAK_X509_DIFF=$((RC_P11SAK_X509_DIFF + $?)) diff $DIR/p11sak_ecp256cert.crt p11sak_ecp256cert_exported.crt > /dev/null RC_P11SAK_X509_DIFF=$((RC_P11SAK_X509_DIFF + $?)) diff $DIR/p11sak_ecp256cert.pem p11sak_ecp256cert_exported.pem > /dev/null RC_P11SAK_X509_DIFF=$((RC_P11SAK_X509_DIFF + $?)) diff $DIR/p11sak_ecp384cert.crt p11sak_ecp384cert_exported.crt > /dev/null RC_P11SAK_X509_DIFF=$((RC_P11SAK_X509_DIFF + $?)) diff $DIR/p11sak_ecp384cert.pem p11sak_ecp384cert_exported.pem > /dev/null RC_P11SAK_X509_DIFF=$((RC_P11SAK_X509_DIFF + $?)) diff $DIR/p11sak_ecp521cert.crt p11sak_ecp521cert_exported.crt > /dev/null RC_P11SAK_X509_DIFF=$((RC_P11SAK_X509_DIFF + $?)) diff $DIR/p11sak_ecp521cert.pem p11sak_ecp521cert_exported.pem > /dev/null RC_P11SAK_X509_DIFF=$((RC_P11SAK_X509_DIFF + $?)) if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_EDDSA) ]]; then diff $DIR/p11sak_ed25519cert.crt p11sak_ed25519cert_exported.crt > /dev/null RC_P11SAK_X509_DIFF=$((RC_P11SAK_X509_DIFF + $?)) diff $DIR/p11sak_ed25519cert.pem p11sak_ed25519cert_exported.pem > /dev/null RC_P11SAK_X509_DIFF=$((RC_P11SAK_X509_DIFF + $?)) diff $DIR/p11sak_ed448cert.crt p11sak_ed448cert_exported.crt > /dev/null RC_P11SAK_X509_DIFF=$((RC_P11SAK_X509_DIFF + $?)) diff $DIR/p11sak_ed448cert.pem p11sak_ed448cert_exported.pem > /dev/null RC_P11SAK_X509_DIFF=$((RC_P11SAK_X509_DIFF + $?)) else echo "Skip comparing exported ec-edwards x.509 certs with original certs, slot does not support CKM_EDDSA" fi if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_DSA) ]]; then diff $DIR/p11sak_dsa3072cert.crt p11sak_dsa3072cert_exported.crt > /dev/null RC_P11SAK_X509_DIFF=$((RC_P11SAK_X509_DIFF + $?)) diff $DIR/p11sak_dsa3072cert.pem p11sak_dsa3072cert_exported.pem > /dev/null RC_P11SAK_X509_DIFF=$((RC_P11SAK_X509_DIFF + $?)) diff $DIR/p11sak_dsa4096cert.crt p11sak_dsa4096cert_exported.crt > /dev/null RC_P11SAK_X509_DIFF=$((RC_P11SAK_X509_DIFF + $?)) diff $DIR/p11sak_dsa4096cert.pem p11sak_dsa4096cert_exported.pem > /dev/null RC_P11SAK_X509_DIFF=$((RC_P11SAK_X509_DIFF + $?)) else echo "Skip comparing exported DSA x.509 certs with original certs, slot does not support CKM_DSA" fi # check X509 certificate listings for completeness # copied certs grep -q "p11sak-x509-copied" $P11SAK_X509_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE copy-cert x509 PASS Copied x509 certs" else echo "* TESTCASE copy-cert x509 FAIL Failed to copy x509 certs" status=1 fi grep -v -q "p11sak-x509-copied" $P11SAK_X509_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-cert x509 PASS Deleted copied x509 certs" else echo "* TESTCASE remove-cert x509 FAIL Failed to delete copied x509 certs" status=1 fi # rsa-2048 grep -q "p11sak-x509-rsa2048crt" $P11SAK_X509_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE import-cert x509 PASS Imported binary x509 cert with random rsa 2048 key" else echo "* TESTCASE import-cert x509 FAIL Failed to import binary x509 certs with random rsa 2048 key" status=1 fi grep -v -q "p11sak-x509-rsa2048crt" $P11SAK_X509_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-cert x509 PASS Deleted imported binary x509 cert with rsa 2048 public key" else echo "* TESTCASE remove-cert x509 FAIL Failed to delete imported binary x509 cert with rsa 2048 public key" status=1 fi grep -q "p11sak-x509-rsa2048pem" $P11SAK_X509_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE import-cert x509 PASS Imported base64-encoded x509 cert with random rsa 2048 key" else echo "* TESTCASE import-cert x509 FAIL Failed to import base64-encoded x509 certs with random rsa 2048 key" status=1 fi grep -v -q "p11sak-x509-rsa2048pem" $P11SAK_X509_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-cert x509 PASS Deleted imported base64-encoded x509 cert with rsa 2048 public key" else echo "* TESTCASE remove-cert x509 FAIL Failed to delete imported base64-encoded x509 cert with rsa 2048 public key" status=1 fi # rsa-4096 grep -q "p11sak-x509-rsa4096crt" $P11SAK_X509_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE import-cert x509 PASS Imported binary x509 cert with random rsa 4096 key" else echo "* TESTCASE import-cert x509 FAIL Failed to import binary x509 certs with random rsa 4096 key" status=1 fi grep -v -q "p11sak-x509-rsa4096crt" $P11SAK_X509_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-cert x509 PASS Deleted imported binary x509 cert with rsa 4096 public key" else echo "* TESTCASE remove-cert x509 FAIL Failed to delete imported binary x509 cert with rsa 4096 public key" status=1 fi grep -q "p11sak-x509-rsa4096pem" $P11SAK_X509_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE import-cert x509 PASS Imported base64-encoded x509 cert with random rsa 4096 key" else echo "* TESTCASE import-cert x509 FAIL Failed to import base64-encoded x509 certs with random rsa 4096 key" status=1 fi grep -v -q "p11sak-x509-rsa4096pem" $P11SAK_X509_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-cert x509 PASS Deleted imported base64-encoded x509 cert with rsa 4096 public key" else echo "* TESTCASE remove-cert x509 FAIL Failed to delete imported base64-encoded x509 cert with rsa 4096 public key" status=1 fi # EC-p256 grep -q "p11sak-x509-ecp256crt" $P11SAK_X509_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE import-cert x509 PASS Imported binary x509 cert with random EC-p256 key" else echo "* TESTCASE import-cert x509 FAIL Failed to import binary x509 certs with random EC-p256 key" status=1 fi grep -v -q "p11sak-x509-ecp256crt" $P11SAK_X509_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-cert x509 PASS Deleted imported binary x509 cert with EC-p256 public key" else echo "* TESTCASE remove-cert x509 FAIL Failed to delete imported binary x509 cert with EC-p256 public key" status=1 fi grep -q "p11sak-x509-ecp256pem" $P11SAK_X509_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE import-cert x509 PASS Imported base64-encoded x509 cert with random EC-p256 key" else echo "* TESTCASE import-cert x509 FAIL Failed to import base64-encoded x509 certs with random EC-p256 key" status=1 fi grep -v -q "p11sak-x509-ecp256pem" $P11SAK_X509_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-cert x509 PASS Deleted imported base64-encoded x509 cert with EC-p256 public key" else echo "* TESTCASE remove-cert x509 FAIL Failed to delete imported base64-encoded x509 cert with EC-p256 public key" status=1 fi # EC-p384 grep -q "p11sak-x509-ecp384crt" $P11SAK_X509_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE import-cert x509 PASS Imported binary x509 cert with random EC-p384 key" else echo "* TESTCASE import-cert x509 FAIL Failed to import binary x509 certs with random EC-p384 key" status=1 fi grep -v -q "p11sak-x509-ecp384crt" $P11SAK_X509_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-cert x509 PASS Deleted imported binary x509 cert with EC-p384 public key" else echo "* TESTCASE remove-cert x509 FAIL Failed to delete imported binary x509 cert with EC-p384 public key" status=1 fi grep -q "p11sak-x509-ecp384pem" $P11SAK_X509_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE import-cert x509 PASS Imported base64-encoded x509 cert with random EC-p384 key" else echo "* TESTCASE import-cert x509 FAIL Failed to import base64-encoded x509 certs with random EC-p384 key" status=1 fi grep -v -q "p11sak-x509-ecp384pem" $P11SAK_X509_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-cert x509 PASS Deleted imported base64-encoded x509 cert with EC-p384 public key" else echo "* TESTCASE remove-cert x509 FAIL Failed to delete imported base64-encoded x509 cert with EC-p384 public key" status=1 fi # EC-p521 grep -q "p11sak-x509-ecp521crt" $P11SAK_X509_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE import-cert x509 PASS Imported binary x509 cert with random EC-p521 key" else echo "* TESTCASE import-cert x509 FAIL Failed to import binary x509 certs with random EC-p521 key" status=1 fi grep -v -q "p11sak-x509-ecp521crt" $P11SAK_X509_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-cert x509 PASS Deleted imported binary x509 cert with EC-p521 public key" else echo "* TESTCASE remove-cert x509 FAIL Failed to delete imported binary x509 cert with EC-p521 public key" status=1 fi grep -q "p11sak-x509-ecp521pem" $P11SAK_X509_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE import-cert x509 PASS Imported base64-encoded x509 cert with random EC-p521 key" else echo "* TESTCASE import-cert x509 FAIL Failed to import base64-encoded x509 certs with random EC-p521 key" status=1 fi grep -v -q "p11sak-x509-ecp521pem" $P11SAK_X509_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-cert x509 PASS Deleted imported base64-encoded x509 cert with EC-p521 public key" else echo "* TESTCASE remove-cert x509 FAIL Failed to delete imported base64-encoded x509 cert with EC-p521 public key" status=1 fi # ec-edwards if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_EDDSA) ]]; then grep -q "p11sak-x509-ed25519crt" $P11SAK_X509_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE import-cert x509 PASS Imported binary x509 cert with random ed25519 key" else echo "* TESTCASE import-cert x509 FAIL Failed to import binary x509 certs with random ed25519 key" status=1 fi grep -v -q "p11sak-x509-ed25519crt" $P11SAK_X509_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-cert x509 PASS Deleted imported binary x509 cert with ed25519 public key" else echo "* TESTCASE remove-cert x509 FAIL Failed to delete imported binary x509 cert with ed25519 public key" status=1 fi grep -q "p11sak-x509-ed25519pem" $P11SAK_X509_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE import-cert x509 PASS Imported base64-encoded x509 cert with random ed255192 key" else echo "* TESTCASE import-cert x509 FAIL Failed to import base64-encoded x509 certs with random ed25519 key" status=1 fi grep -v -q "p11sak-x509-ed25519pem" $P11SAK_X509_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-cert x509 PASS Deleted imported base64-encoded x509 cert with ed25519 public key" else echo "* TESTCASE remove-cert x509 FAIL Failed to delete imported base64-encoded x509 cert with ed25519 public key" status=1 fi grep -q "p11sak-x509-ed448crt" $P11SAK_X509_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE import-cert x509 PASS Imported binary x509 cert with random ed448 key" else echo "* TESTCASE import-cert x509 FAIL Failed to import binary x509 certs with random ed448 key" status=1 fi grep -v -q "p11sak-x509-ed448crt" $P11SAK_X509_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-cert x509 PASS Deleted imported binary x509 cert with ed448 public key" else echo "* TESTCASE remove-cert x509 FAIL Failed to delete imported binary x509 cert with ed448 public key" status=1 fi grep -q "p11sak-x509-ed448pem" $P11SAK_X509_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE import-cert x509 PASS Imported base64-encoded x509 cert with random ed4482 key" else echo "* TESTCASE import-cert x509 FAIL Failed to import base64-encoded x509 certs with random ed448 key" status=1 fi grep -v -q "p11sak-x509-ed448pem" $P11SAK_X509_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-cert x509 PASS Deleted imported base64-encoded x509 cert with ed448 public key" else echo "* TESTCASE remove-cert x509 FAIL Failed to delete imported base64-encoded x509 cert with ed448 public key" status=1 fi else echo "* TESTCASE import-cert x509 SKIP Import binary x509 cert with random ed25519 key. Slot does not support EdDSA." echo "* TESTCASE remove-cert x509 SKIP Delete imported binary x509 cert with ed25519 public key. Slot does not support EdDSA." echo "* TESTCASE import-cert x509 SKIP Import base64-encoded x509 cert with random ed25519 key. Slot does not support EdDSA." echo "* TESTCASE remove-cert x509 SKIP Delete imported base64-encoded x509 cert with ed25519 public key. Slot does not support EdDSA." echo "* TESTCASE import-cert x509 SKIP Import binary x509 cert with random ed448 key. Slot does not support EdDSA." echo "* TESTCASE remove-cert x509 SKIP Delete imported binary x509 cert with ed448 public key. Slot does not support EdDSA." echo "* TESTCASE import-cert x509 SKIP Import base64-encoded x509 cert with random ed448 key. Slot does not support EdDSA." echo "* TESTCASE remove-cert x509 SKIP Delete imported base64-encoded x509 cert with ed448 public key. Slot does not support EdDSA." fi # DSA-3072 if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_DSA) ]]; then grep -q "p11sak-x509-dsa3072crt" $P11SAK_X509_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE import-cert x509 PASS Imported binary x509 cert with random DSA-3072 key" else echo "* TESTCASE import-cert x509 FAIL Failed to import binary x509 certs with random DSA-3072 key" status=1 fi grep -v -q "p11sak-x509-dsa3072crt" $P11SAK_X509_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-cert x509 PASS Deleted imported binary x509 cert with DSA-3072 public key" else echo "* TESTCASE remove-cert x509 FAIL Failed to delete imported binary x509 cert with DSA-3072 public key" status=1 fi grep -q "p11sak-x509-dsa3072pem" $P11SAK_X509_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE import-cert x509 PASS Imported base64-encoded x509 cert with random DSA-3072 key" else echo "* TESTCASE import-cert x509 FAIL Failed to import base64-encoded x509 certs with random DSA-3072 key" status=1 fi grep -v -q "p11sak-x509-dsa3072pem" $P11SAK_X509_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-cert x509 PASS Deleted imported base64-encoded x509 cert with DSA-3072 public key" else echo "* TESTCASE remove-cert x509 FAIL Failed to delete imported base64-encoded x509 cert with DSA-3072 public key" status=1 fi else echo "* TESTCASE import-cert x509 SKIP Import binary x509 cert with random DSA-3072 key. Slot does not support DSA." echo "* TESTCASE remove-cert x509 SKIP Delete imported binary x509 cert with DSA-3072 public key. Slot does not support DSA." echo "* TESTCASE import-cert x509 SKIP Import base64-encoded x509 cert with random DSA-3072 key. Slot does not support DSA." echo "* TESTCASE remove-cert x509 SKIP Delete imported base64-encoded x509 cert with DSA-3072 public key. Slot does not support DSA." fi # DSA-4096 if [[ -n $( ${PKCSCONF} -m -c $SLOT | grep CKM_DSA) ]]; then grep -q "p11sak-x509-dsa4096crt" $P11SAK_X509_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE import-cert x509 PASS Imported binary x509 cert with random DSA-4096 key" else echo "* TESTCASE import-cert x509 FAIL Failed to import binary x509 certs with random DSA-4096 key" status=1 fi grep -v -q "p11sak-x509-dsa4096crt" $P11SAK_X509_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-cert x509 PASS Deleted imported binary x509 cert with DSA-4096 public key" else echo "* TESTCASE remove-cert x509 FAIL Failed to delete imported binary x509 cert with DSA-4096 public key" status=1 fi grep -q "p11sak-x509-dsa4096pem" $P11SAK_X509_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE import-cert x509 PASS Imported base64-encoded x509 cert with random DSA-4096 key" else echo "* TESTCASE import-cert x509 FAIL Failed to import base64-encoded x509 certs with random DSA-4096 key" status=1 fi grep -v -q "p11sak-x509-dsa4096pem" $P11SAK_X509_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-cert x509 PASS Deleted imported base64-encoded x509 cert with DSA-4096 public key" else echo "* TESTCASE remove-cert x509 FAIL Failed to delete imported base64-encoded x509 cert with DSA-4096 public key" status=1 fi else echo "* TESTCASE import-cert x509 SKIP Import binary x509 cert with random DSA-4096 key. Slot does not support DSA." echo "* TESTCASE remove-cert x509 SKIP Delete imported binary x509 cert with DSA-4096 public key. Slot does not support DSA." echo "* TESTCASE import-cert x509 SKIP Import base64-encoded x509 cert with random DSA-4096 key. Slot does not support DSA." echo "* TESTCASE remove-cert x509 SKIP Delete imported base64-encoded x509 cert with DSA-4096 public key. Slot does not support DSA." fi # check return codes if [ $RC_P11SAK_GENERATE = 0 ]; then echo "* TESTCASE generate-key PASS return code check" else echo "* TESTCASE generate-key FAIL return code check" status=1 fi if [ $RC_P11SAK_LIST = 0 ]; then echo "* TESTCASE list-key short PASS return code check" else echo "* TESTCASE list-key short FAIL return code check" status=1 fi if [ $RC_P11SAK_LIST_LONG = 0 ]; then echo "* TESTCASE list-key long PASS return code check" else echo "* TESTCASE list-key long FAIL return code check" status=1 fi if [ $RC_P11SAK_LIST_POST = 0 ]; then echo "* TESTCASE list-key post PASS return code check" else echo "* TESTCASE list-key post FAIL return code check" status=1 fi if [ $RC_P11SAK_UPDATE = 0 ]; then echo "* TESTCASE set-key-attr PASS return code check" else echo "* TESTCASE set-key-attr FAIL return code check" status=1 fi if [ $RC_P11SAK_COPY = 0 ]; then echo "* TESTCASE copy-key PASS return code check" else echo "* TESTCASE copy-key FAIL return code check" status=1 fi if [ $RC_P11SAK_KEY_EXTRACT = 0 ]; then echo "* TESTCASE extract-pubkey PASS return code check" else echo "* TESTCASE extract-pubkey FAIL return code check" status=1 fi if [ $RC_P11SAK_IMPORT = 0 ]; then echo "* TESTCASE import-key PASS return code check" else echo "* TESTCASE import-key FAIL return code check" status=1 fi if [ $RC_P11SAK_EXPORT = 0 ]; then echo "* TESTCASE export-key PASS return code check" else echo "* TESTCASE export-key FAIL return code check" status=1 fi if [ $RC_P11SAK_REMOVE = 0 ]; then echo "* TESTCASE remove-key PASS return code check" else echo "* TESTCASE remove-key FAIL return code check" status=1 fi # check return codes from key wrap tests if [ $RC_P11SAK_WRAP = 0 ]; then echo "* TESTCASE wrap-key PASS return code check" else echo "* TESTCASE wrap-key FAIL return code check" status=1 fi # check return codes from certificate tests if [ $RC_P11SAK_X509_IMPORT = 0 ]; then echo "* TESTCASE import-cert PASS return code check" else echo "* TESTCASE import-cert FAIL return code check" status=1 fi if [ $RC_P11SAK_X509_LIST = 0 ]; then echo "* TESTCASE list-cert short PASS return code check" else echo "* TESTCASE list-cert short FAIL return code check" status=1 fi if [ $RC_P11SAK_X509_LIST_LONG = 0 ]; then echo "* TESTCASE list-cert long PASS return code check" else echo "* TESTCASE list-cert long FAIL return code check" status=1 fi if [ $RC_P11SAK_X509_EXPORT = 0 ]; then echo "* TESTCASE export-cert PASS return code check" else echo "* TESTCASE export-cert FAIL return code check" status=1 fi if [ $RC_P11SAK_X509_COPY = 0 ]; then echo "* TESTCASE copy-cert PASS return code check" else echo "* TESTCASE copy-cert FAIL return code check" status=1 fi if [ $RC_P11SAK_X509_UPDATE = 0 ]; then echo "* TESTCASE set-cert-attr PASS return code check" else echo "* TESTCASE set-cert-attr FAIL return code check" status=1 fi if [ $RC_P11SAK_X509_REMOVE = 0 ]; then echo "* TESTCASE remove-cert PASS return code check" else echo "* TESTCASE remove-cert FAIL return code check" status=1 fi if [ $RC_P11SAK_X509_EXTRACT = 0 ]; then echo "* TESTCASE extract-cert-pubkey PASS return code check" else echo "* TESTCASE extract-cert-pubkey FAIL return code check" status=1 fi if [ $RC_P11SAK_X509_DIFF = 0 ]; then echo "* TESTCASE diff exported certs PASS return code check" else echo "* TESTCASE diff exported certs FAIL return code check" status=1 fi # check token pin handling if [ $RC_P11SAK_PINOPT = 0 ]; then echo "* TESTCASE list-key pin-opt PASS Token pin handling (opt)" else echo "* TESTCASE list-key pin-opt FAIL Token pin handling (opt)" status=1 fi if [ $RC_P11SAK_PINENV = 0 ]; then echo "* TESTCASE list-key pin-env PASS Token pin handling (env)" else echo "* TESTCASE list-key pin-env FAIL Token pin handling (env)" status=1 fi if [ $RC_P11SAK_PINCON = 0 ]; then echo "* TESTCASE list-key pin-prompt PASS Token pin handling (prompt)" else echo "* TESTCASE list-key pin-prompt FAIL Token pin handling (prompt)" status=1 fi if [ $RC_P11SAK_NOLOGIN = 0 ]; then echo "* TESTCASE list-key no-login PASS public session" else echo "* TESTCASE list-key no-login FAIL public session" status=1 fi if [[ -z $PKCS11_SO_PIN ]]; then echo "* TESTCASE list-key so-login SKIP SO session" elif [ $RC_P11SAK_SO = 0 ]; then echo "* TESTCASE list-key so-login PASS SO session" else echo "* TESTCASE list-key so-login FAIL SO session" status=1 fi if diff -q $P11SAK_ALL_PINOPT $P11SAK_ALL_PINENV ; then echo "* TESTCASE list-key pin-opt-env PASS Token pin opt/env output compare" else echo "* TESTCASE list-key pin-opt-env FAIL Token pin opt/env output compare" status=1 fi if diff -q $P11SAK_ALL_PINOPT $P11SAK_ALL_PINCON ; then echo "* TESTCASE list-key pin-opt-prompt PASS Token pin opt/prompt output compare" else echo "* TESTCASE list-key pin-opt-prompt FAIL Token pin opt/prompt output compare" status=1 fi echo "** Now remove temporary output files - "p11sak_test.sh"" rm -f $P11SAK_DES_PRE rm -f $P11SAK_DES_LONG rm -f $P11SAK_DES_POST rm -f $P11SAK_3DES_PRE rm -f $P11SAK_3DES_LONG rm -f $P11SAK_3DES_POST rm -f $P11SAK_GENERIC_PRE rm -f $P11SAK_GENERIC_LONG rm -f $P11SAK_GENERIC_POST rm -f $P11SAK_AES_PRE rm -f $P11SAK_AES_LONG rm -f $P11SAK_AES_POST rm -f $P11SAK_AES_XTS_PRE rm -f $P11SAK_AES_XTS_LONG rm -f $P11SAK_AES_XTS_POST rm -f $P11SAK_RSA_PRE rm -f $P11SAK_RSA_LONG rm -f $P11SAK_RSA_POST rm -f $P11SAK_DH_PRE rm -f $P11SAK_DH_LONG rm -f $P11SAK_DH_POST rm -f $P11SAK_DSA_PRE rm -f $P11SAK_DSA_LONG rm -f $P11SAK_DSA_POST rm -f $P11SAK_EC_PRE rm -f $P11SAK_EC_LONG rm -f $P11SAK_EC_POST rm -f $P11SAK_EC_EDWARDS_PRE rm -f $P11SAK_EC_EDWARDS_LONG rm -f $P11SAK_EC_EDWARDS_POST rm -f $P11SAK_EC_MONTGOMERY_PRE rm -f $P11SAK_EC_MONTGOMERY_LONG rm -f $P11SAK_EC_MONTGOMERY_POST rm -f $P11SAK_IBM_DILITHIUM_PRE rm -f $P11SAK_IBM_DILITHIUM_LONG rm -f $P11SAK_IBM_DILITHIUM_POST rm -f $P11SAK_IBM_KYBER_PRE rm -f $P11SAK_IBM_KYBER_LONG rm -f $P11SAK_IBM_KYBER_POST rm -f $P11SAK_IBM_ML_DSA_PRE rm -f $P11SAK_IBM_ML_DSA_LONG rm -f $P11SAK_IBM_ML_DSA_POST rm -f $P11SAK_IBM_ML_KEM_PRE rm -f $P11SAK_IBM_ML_KEM_LONG rm -f $P11SAK_IBM_ML_KEM_POST rm -f $P11SAK_ML_DSA_PRE rm -f $P11SAK_ML_DSA_LONG rm -f $P11SAK_ML_DSA_POST rm -f $P11SAK_ML_KEM_PRE rm -f $P11SAK_ML_KEM_LONG rm -f $P11SAK_ML_KEM_POST rm -f $P11SAK_X509_PRE rm -f $P11SAK_X509_LONG rm -f $P11SAK_X509_POST rm -f $P11SAK_ALL_PINOPT rm -f $P11SAK_ALL_PINENV rm -f $P11SAK_ALL_PINCON rm -f $P11SAK_ALL_NOLOGIN rm -f $P11SAK_ALL_SO rm -f export-aes.key rm -f export-*.pem rm -f export-*.opaque rm -f pin*.txt rm -f oqs-*.pem rm -f mldsa65-*.pem rm -f mlkem1024-*.pem rm -f dilithium3_CA.* rm -f dilithium3_srv.* rm -f mldsa65_CA.* rm -f mldsa65_srv.* rm -f wrapped-key.pem echo "** Now remove temporary openssl files from x509 tests - "p11sak_test.sh"" rm -f p11sak_*cert_exported.crt rm -f p11sak_*cert_exported.pem echo "** Now DONE testing - 'p11sak_test.sh' - rc = $status" exit $status opencryptoki-opencryptoki-451d99c/testcases/misc_tests/pkcsconf_test.sh000077500000000000000000000124211520105705100267030ustar00rootroot00000000000000#!/bin/bash # # COPYRIGHT (c) International Business Machines Corp. 2022 # # This program is provided under the terms of the Common Public License, # version 1.0 (CPL-1.0). Any use, reproduction or distribution for this software # constitutes recipient's acceptance of CPL-1.0 terms which can be found # in the file LICENSE file or at https://opensource.org/licenses/cpl1.0.php # functions print_test_result() { local rc=$1 local name=$2 local subn=$3 local mesg=$4 if [ ${rc} = 0 ]; then echo "* TESTCASE ${name} ${subn} PASS ${mesg}" else echo "* TESTCASE ${name} ${subn} FAIL ${mesg}" fi } echo "** Now executing 'pkcsconf_test.sh'" # create temporary directory TMP=$(mktemp -d) # define output files PKCSCONF_INFO=${TMP}/pkcsconf-info.out PKCSCONF_SLOT=${TMP}/pkcsconf-slot.out PKCSCONF_TOKEN=${TMP}/pkcsconf-token.out # check if pkcsconf is available in the current $PATH - if it isn't, ask for # SBINDIR to be defined before this script executes. if [[ -n "$(command -v pkcsconf)" ]]; then PKCSCONF=pkcsconf elif [[ -z "$SBINDIR" ]]; then echo "pkcsconf was not found in \$PATH." echo "Define \$SBINDIR to the appropriate path and try again." exit 1 else PKCSCONF=${SBINDIR}/pkcsconf fi # list info/slots/tokens ${PKCSCONF} -i &> $PKCSCONF_INFO ${PKCSCONF} -s &> $PKCSCONF_SLOT ${PKCSCONF} -t &> $PKCSCONF_TOKEN # extract information elements INFO_LIBVERS=$(cat ${PKCSCONF_INFO} | grep -Po 'Library Version:\s+\K[0-9]+.[0-9]+') INFO_LIBMANU=$(cat ${PKCSCONF_INFO} | grep -Po 'Manufacturer:\s+\K\S*') INFO_LIBDESC=$(cat ${PKCSCONF_INFO} | grep -Po 'Library Description:\s+\K\S*') # extract information URI elements URI_INFO_LIBVERS=$(cat ${PKCSCONF_INFO} | grep -Po 'URI:\s*pkcs11:.*library-version=\K[^;]*') URI_INFO_LIBMANU=$(cat ${PKCSCONF_INFO} | grep -Po 'URI:\s*pkcs11:.*library-manufacturer=\K[^;]*') URI_INFO_LIBDESC=$(cat ${PKCSCONF_INFO} | grep -Po 'URI:\s*pkcs11:.*library-description=\K[^;]*') # extract slot elements (only first slot) SLOT_ID=$( cat ${PKCSCONF_SLOT} | grep -Po '^Slot #\K[0-9]+' | head -n1) SLOT_MANU=$(cat ${PKCSCONF_SLOT} | grep -Po 'Manufacturer:\s+\K\S*' | head -n1) SLOT_DESC=$(cat ${PKCSCONF_SLOT} | grep -Po 'Description:\s+\K\S*' | head -n1) # extract slot URI elements (only first slot) URI_SLOT_ID=$( cat ${PKCSCONF_SLOT} | grep -Po 'URI:\s*pkcs11:.*slot-id=\K[^;]*' | head -n1) URI_SLOT_MANU=$(cat ${PKCSCONF_SLOT} | grep -Po 'URI:\s*pkcs11:.*slot-manufacturer=\K[^;]*' | head -n1) URI_SLOT_DESC=$(cat ${PKCSCONF_SLOT} | grep -Po 'URI:\s*pkcs11:.*slot-description=\K[^;]*' | head -n1) # extract token elements (only first token) TOKEN_LABL=$(cat ${PKCSCONF_TOKEN} | grep -Po 'Label:\s+\K\S*' | head -n1) TOKEN_MANU=$(cat ${PKCSCONF_TOKEN} | grep -Po 'Manufacturer:\s+\K\S*' | head -n1) TOKEN_MODL=$(cat ${PKCSCONF_TOKEN} | grep -Po 'Model:\s+\K\S*' | head -n1) # extract token URI elements (only first token) URI_TOKEN_LABL=$(cat ${PKCSCONF_TOKEN} | grep -Po 'URI:\s*pkcs11:.*token=\K[^;]*' | head -n1) URI_TOKEN_MANU=$(cat ${PKCSCONF_TOKEN} | grep -Po 'URI:\s*pkcs11:.*manufacturer=\K[^;]*' | head -n1) URI_TOKEN_MODL=$(cat ${PKCSCONF_TOKEN} | grep -Po 'URI:\s*pkcs11:.*model=\K[^;]*' | head -n1) # information test cases test -n "${INFO_LIBVERS}" -o \ -n "${INFO_LIBMANU}" -o \ -n "${INFO_LIBDESC}" print_test_result $? "pkcsconf" "info" "check output for all required library fields" test -n "${URI_INFO_LIBVERS}" -o \ -n "${URI_INFO_LIBMANU}" -o \ -n "${URI_INFO_LIBDESC}" print_test_result $? "pkcsconf" "info" "check URI for all required library fields" test "${INFO_LIBVERS}" = "${URI_INFO_LIBVERS}" print_test_result $? "pkcsconf" "info" "check library version in URI" test "${INFO_LIBMANU}" = "${URI_INFO_LIBMANU}" print_test_result $? "pkcsconf" "info" "check library manufacturer in URI" test "${INFO_LIBDESC}" = "${URI_INFO_LIBDESC}" print_test_result $? "pkcsconf" "info" "check library description in URI" # slot test cases test -n "${SLOT_ID}" -o \ -n "${SLOT_MANU}" -o \ -n "${SLOT_DESC}" print_test_result $? "pkcsconf" "slot" "check output for all required slot fields" test -n "${URI_SLOT_ID}" -o \ -n "${URI_SLOT_MANU}" -o \ -n "${URI_SLOT_DESC}" print_test_result $? "pkcsconf" "slot" "check URI for all required slot fields" test "${SLOT_ID}" = "${URI_SLOT_ID}" print_test_result $? "pkcsconf" "slot" "check slot id in URI" test "${SLOT_MANU}" = "${URI_SLOT_MANU}" print_test_result $? "pkcsconf" "slot" "check slot manufacturer in URI" test "${SLOT_DESC}" = "${URI_SLOT_DESC}" print_test_result $? "pkcsconf" "slot" "check slot description in URI" # token test cases test -n "${TOKEN_LABL}" -o \ -n "${TOKEN_MANU}" -o \ -n "${TOKEN_MODL}" print_test_result $? "pkcsconf" "token" "check output for all required token fields" test -n "${URI_TOKEN_LABL}" -o \ -n "${URI_TOKEN_MANU}" -o \ -n "${URI_TOKEN_MODL}" print_test_result $? "pkcsconf" "token" "check URI for all required token fields" test "${TOKEN_LABL}" = "${URI_TOKEN_LABL}" print_test_result $? "pkcsconf" "token" "check token label in URI" test "${TOKEN_MANU}" = "${URI_TOKEN_MANU}" print_test_result $? "pkcsconf" "token" "check token manufacturer in URI" test "${TOKEN_MODL}" = "${URI_TOKEN_MODL}" print_test_result $? "pkcsconf" "token" "check token model in URI" # remove tmp rm -rf ${TMP} &> /dev/null opencryptoki-opencryptoki-451d99c/testcases/misc_tests/reencrypt.c000066400000000000000000000723301520105705100256630ustar00rootroot00000000000000/* * 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: reencrypt.c * * Test driver. In-depth regression test for PKCS #11 */ #include #include #include #include #include #include #include #include #include "pkcs11types.h" #include "regress.h" #include "mech_to_str.h" #include "common.c" CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; CK_ULONG user_pin_len; CK_SLOT_ID slot_id = 1; CK_SESSION_HANDLE session; CK_OBJECT_HANDLE sym_key1 = CK_INVALID_HANDLE; CK_OBJECT_HANDLE sym_key2 = CK_INVALID_HANDLE; CK_OBJECT_HANDLE publ_key1 = CK_INVALID_HANDLE; CK_OBJECT_HANDLE priv_key1 = CK_INVALID_HANDLE; CK_OBJECT_HANDLE publ_key2 = CK_INVALID_HANDLE; CK_OBJECT_HANDLE priv_key2 = CK_INVALID_HANDLE; CK_C_IBM_ReencryptSingle _C_IBM_ReencryptSingle; CK_RSA_PKCS_OAEP_PARAMS oaep_params_sha1 = { .hashAlg = CKM_SHA_1, .mgf = CKG_MGF1_SHA1, .source = 0, .pSourceData = NULL, .ulSourceDataLen = 0, }; CK_RSA_PKCS_OAEP_PARAMS oaep_params_sha1_source = { .hashAlg = CKM_SHA_1, .mgf = CKG_MGF1_SHA1, .source = CKZ_DATA_SPECIFIED, .pSourceData = "abc", .ulSourceDataLen = 3, }; CK_RSA_PKCS_OAEP_PARAMS oaep_params_sha256 = { .hashAlg = CKM_SHA256, .mgf = CKG_MGF1_SHA256, .source = 0, .pSourceData = NULL, .ulSourceDataLen = 0, }; CK_RSA_PKCS_OAEP_PARAMS oaep_params_sha256_source = { .hashAlg = CKM_SHA256, .mgf = CKG_MGF1_SHA256, .source = CKZ_DATA_SPECIFIED, .pSourceData = "abc", .ulSourceDataLen = 3, }; CK_BYTE aes_iv[16] = { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f }; CK_BYTE des_iv[8] = { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07 }; CK_BYTE clear_data[32]; CK_BYTE encrypted_data1[2048]; CK_ULONG encrypted_data1_len = sizeof(encrypted_data1); CK_BYTE encrypted_data2[2048]; CK_ULONG encrypted_data2_len = sizeof(encrypted_data2); CK_BYTE decrypted_data[1024]; CK_ULONG decrypted_data_len = sizeof(decrypted_data); struct mech_info { char *name; CK_MECHANISM mech; CK_MECHANISM key_gen_mech; CK_ULONG rsa_modbits; CK_ULONG rsa_publ_exp_len; CK_BYTE rsa_publ_exp[4]; CK_ULONG sym_keylen; CK_ULONG clear_data_len; }; struct mech_info reencrypt_tests[] = { { .name = "AES 128 ECB", .mech = { CKM_AES_ECB, 0, 0 }, .key_gen_mech = { CKM_AES_KEY_GEN, 0, 0 }, .sym_keylen = 16, .clear_data_len = 32, }, { .name = "AES 192 ECB", .mech = { CKM_AES_ECB, 0, 0 }, .key_gen_mech = { CKM_AES_KEY_GEN, 0, 0 }, .sym_keylen = 24, .clear_data_len = 32, }, { .name = "AES 256 ECB", .mech = { CKM_AES_ECB, 0, 0 }, .key_gen_mech = { CKM_AES_KEY_GEN, 0, 0 }, .sym_keylen = 32, .clear_data_len = 32, }, { .name = "AES 128 CBC", .mech = { CKM_AES_CBC, aes_iv, sizeof(aes_iv) }, .key_gen_mech = { CKM_AES_KEY_GEN, 0, 0 }, .sym_keylen = 16, .clear_data_len = 32, }, { .name = "AES 192 CBC", .mech = { CKM_AES_CBC, aes_iv, sizeof(aes_iv) }, .key_gen_mech = { CKM_AES_KEY_GEN, 0, 0 }, .sym_keylen = 24, .clear_data_len = 32, }, { .name = "AES 256 CBC", .mech = { CKM_AES_CBC, aes_iv, sizeof(aes_iv) }, .key_gen_mech = { CKM_AES_KEY_GEN, 0, 0 }, .sym_keylen = 32, .clear_data_len = 32, }, { .name = "AES 128 CBC PAD", .mech = { CKM_AES_CBC_PAD, aes_iv, sizeof(aes_iv) }, .key_gen_mech = { CKM_AES_KEY_GEN, 0, 0 }, .sym_keylen = 16, .clear_data_len = 30, }, { .name = "AES 192 CBC PAD", .mech = { CKM_AES_CBC_PAD, aes_iv, sizeof(aes_iv) }, .key_gen_mech = { CKM_AES_KEY_GEN, 0, 0 }, .sym_keylen = 24, .clear_data_len = 30, }, { .name = "AES 256 CBC PAD", .mech = { CKM_AES_CBC_PAD, aes_iv, sizeof(aes_iv) }, .key_gen_mech = { CKM_AES_KEY_GEN, 0, 0 }, .sym_keylen = 32, .clear_data_len = 30, }, { .name = "DES ECB", .mech = { CKM_DES_ECB, 0, 0 }, .key_gen_mech = { CKM_DES_KEY_GEN, 0, 0 }, .clear_data_len = 32, }, { .name = "DES CCB", .mech = { CKM_DES_CBC, des_iv, sizeof(des_iv) }, .key_gen_mech = { CKM_DES_KEY_GEN, 0, 0 }, .clear_data_len = 32, }, { .name = "DES CBC PAD", .mech = { CKM_DES_CBC_PAD, des_iv, sizeof(des_iv) }, .key_gen_mech = { CKM_DES_KEY_GEN, 0, 0 }, .clear_data_len = 30, }, { .name = "DES3 ECB", .mech = { CKM_DES3_ECB, 0, 0 }, .key_gen_mech = { CKM_DES3_KEY_GEN, 0, 0 }, .clear_data_len = 32, }, { .name = "DES3 CCB", .mech = { CKM_DES3_CBC, des_iv, sizeof(des_iv) }, .key_gen_mech = { CKM_DES3_KEY_GEN, 0, 0 }, .clear_data_len = 32, }, { .name = "DES3 CBC PAD", .mech = { CKM_DES3_CBC_PAD, des_iv, sizeof(des_iv) }, .key_gen_mech = { CKM_DES3_KEY_GEN, 0, 0 }, .clear_data_len = 30, }, { .name = "RSA 512 PKCS", .mech = { CKM_RSA_PKCS, 0, 0 }, .key_gen_mech = { CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0 }, .rsa_modbits = 512, .rsa_publ_exp_len = 3, .rsa_publ_exp = {0x01, 0x00, 0x01}, .clear_data_len = 30, }, { .name = "RSA 1024 PKCS", .mech = { CKM_RSA_PKCS, 0, 0 }, .key_gen_mech = { CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0 }, .rsa_modbits = 1024, .rsa_publ_exp_len = 3, .rsa_publ_exp = {0x01, 0x00, 0x01}, .clear_data_len = 30, }, { .name = "RSA 2048 PKCS", .mech = { CKM_RSA_PKCS, 0, 0 }, .key_gen_mech = { CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0 }, .rsa_modbits = 2048, .rsa_publ_exp_len = 3, .rsa_publ_exp = {0x01, 0x00, 0x01}, .clear_data_len = 30, }, { .name = "RSA 1024 PKCS OAEP (SHA1)", .mech = { CKM_RSA_PKCS_OAEP, &oaep_params_sha1, sizeof(CK_RSA_PKCS_OAEP_PARAMS) }, .key_gen_mech = { CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0 }, .rsa_modbits = 1024, .rsa_publ_exp_len = 3, .rsa_publ_exp = {0x01, 0x00, 0x01}, .clear_data_len = 30, }, { .name = "RSA 1024 PKCS OAEP (SHA1, source data)", .mech = { CKM_RSA_PKCS_OAEP, &oaep_params_sha1_source, sizeof(CK_RSA_PKCS_OAEP_PARAMS) }, .key_gen_mech = { CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0 }, .rsa_modbits = 1024, .rsa_publ_exp_len = 3, .rsa_publ_exp = {0x01, 0x00, 0x01}, .clear_data_len = 30, }, { .name = "RSA 1024 PKCS OAEP (SHA256)", .mech = { CKM_RSA_PKCS_OAEP, &oaep_params_sha256, sizeof(CK_RSA_PKCS_OAEP_PARAMS) }, .key_gen_mech = { CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0 }, .rsa_modbits = 1024, .rsa_publ_exp_len = 3, .rsa_publ_exp = {0x01, 0x00, 0x01}, .clear_data_len = 30, }, { .name = "RSA 1024 PKCS OAEP (SHA256, source data)", .mech = { CKM_RSA_PKCS_OAEP, &oaep_params_sha256_source, sizeof(CK_RSA_PKCS_OAEP_PARAMS) }, .key_gen_mech = { CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0 }, .rsa_modbits = 1024, .rsa_publ_exp_len = 3, .rsa_publ_exp = {0x01, 0x00, 0x01}, .clear_data_len = 30, }, }; #define NUM_REENCRYPT_TESTS sizeof(reencrypt_tests) / \ sizeof(struct mech_info) CK_RV do_reencrypt(struct mech_info *mech1, struct mech_info *mech2) { CK_RSA_PKCS_OAEP_PARAMS *oaep; CK_RV loc_rc, rc = CKR_OK; char *s = NULL; testcase_begin("Reencrypt from '%s' to '%s'", mech1->name, mech2->name); if (!mech_supported(slot_id, mech2->key_gen_mech.mechanism)) { testcase_skip("Slot %u doesn't support %s (0x%x)", (unsigned int)slot_id, mech_to_str(mech2->key_gen_mech.mechanism), (unsigned int)mech2->key_gen_mech.mechanism); goto testcase_cleanup; } if (!mech_supported(slot_id, mech2->mech.mechanism)) { testcase_skip("Slot %u doesn't support %s (0x%x)", (unsigned int)slot_id, mech_to_str(mech2->mech.mechanism), (unsigned int)mech2->mech.mechanism); goto testcase_cleanup; } switch (mech2->mech.mechanism) { case CKM_DES_ECB: case CKM_DES_CBC: case CKM_DES_CBC_PAD: if (is_cca_token(slot_id)) { testcase_skip("CCA does not support DES with reencrypt"); goto testcase_cleanup; } break; case CKM_DES3_CBC_PAD: if (is_cca_token(slot_id)) { testcase_skip("CCA does not support DES3 CBC PAD with reencrypt"); goto testcase_cleanup; } break; case CKM_RSA_PKCS: case CKM_RSA_PKCS_OAEP: if (is_cca_token(slot_id)) { testcase_skip("CCA does not support RSA with reencrypt"); goto testcase_cleanup; } break; default: break; } switch (mech1->mech.mechanism) { case CKM_AES_CBC_PAD: case CKM_DES_CBC_PAD: case CKM_DES3_CBC_PAD: case CKM_RSA_PKCS: case CKM_RSA_PKCS_OAEP: switch (mech2->mech.mechanism) { case CKM_AES_CBC_PAD: case CKM_DES_CBC_PAD: case CKM_DES3_CBC_PAD: case CKM_RSA_PKCS: case CKM_RSA_PKCS_OAEP: break; default: testcase_skip("Cannot reencrypt from %s (%u) to %s (%u), because " "the target mechanism does not pad.", mech_to_str(mech1->mech.mechanism), (unsigned int)mech1->mech.mechanism, mech_to_str(mech2->mech.mechanism), (unsigned int)mech2->mech.mechanism); goto testcase_cleanup; } break; default: break; } /* * Generate the key 1 */ switch (mech2->key_gen_mech.mechanism) { case CKM_RSA_PKCS_KEY_PAIR_GEN: if (p11_ahex_dump(&s, mech2->rsa_publ_exp, mech2->rsa_publ_exp_len) == NULL) { testcase_error("p11_ahex_dump() failed"); rc = CKR_FUNCTION_FAILED; goto testcase_cleanup; } if (!keysize_supported(slot_id, mech2->key_gen_mech.mechanism, mech2->rsa_modbits)) { testcase_skip("Token in slot %lu cannot be used with modbits='%lu'", slot_id, mech2->rsa_modbits); goto testcase_cleanup; } if (is_ep11_token(slot_id)) { if (!is_valid_ep11_pubexp(mech2->rsa_publ_exp, mech2->rsa_publ_exp_len)) { testcase_skip("EP11 Token in cannot be used with publ_exp.='%s'", s); goto testcase_cleanup; } } if (is_cca_token(slot_id)) { if (!is_valid_cca_pubexp(mech2->rsa_publ_exp, mech2->rsa_publ_exp_len)) { testcase_skip("CCA Token in cannot be used with publ_exp.='%s'", s); goto testcase_cleanup; } } if (is_soft_token(slot_id)) { if (!is_valid_soft_pubexp(mech2->rsa_publ_exp, mech2->rsa_publ_exp_len)) { testcase_skip("Soft Token in cannot be used with publ_exp.='%s'", s); goto testcase_cleanup; } } if (is_tpm_token(slot_id) ) { if (!is_valid_tpm_pubexp(mech2->rsa_publ_exp, mech2->rsa_publ_exp_len) || !is_valid_tpm_modbits(mech2->rsa_modbits)) { testcase_skip("TPM Token cannot be used with publ_exp.='%s'", s); goto testcase_cleanup; } } if (is_icsf_token(slot_id)) { if (!is_valid_icsf_pubexp(mech2->rsa_publ_exp, mech2->rsa_publ_exp_len) || mech2->rsa_modbits < 1024) { testcase_skip("ICSF Token cannot be used with publ_exp='%s'.", s); goto testcase_cleanup; } } rc = generate_RSA_PKCS_KeyPair(session, CKM_RSA_PKCS_KEY_PAIR_GEN, mech2->rsa_modbits, mech2->rsa_publ_exp, mech2->rsa_publ_exp_len, &publ_key2, &priv_key2); break; case CKM_AES_KEY_GEN: rc = generate_AESKey(session, mech2->sym_keylen, CK_TRUE, &mech2->key_gen_mech, &sym_key2); break; case CKM_DES3_KEY_GEN: case CKM_DES2_KEY_GEN: case CKM_DES_KEY_GEN: rc = funcs->C_GenerateKey(session, &mech2->key_gen_mech, NULL, 0, &sym_key2); break; default: testcase_error("Testcase does not support %s (%u)", mech_to_str(mech2->key_gen_mech.mechanism), (unsigned int)mech2->key_gen_mech.mechanism); goto testcase_cleanup; } if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("generate key-2 with mech %s (%u) in slot %lu " "is not allowed by policy", mech_to_str(mech2->key_gen_mech.mechanism), (unsigned int)mech2->key_gen_mech.mechanism, slot_id); goto testcase_cleanup; } testcase_error("generate key-2 with mech %s (%u) in slot %lu " "failed, rc=%s", mech_to_str(mech2->key_gen_mech.mechanism), (unsigned int)mech2->key_gen_mech.mechanism, slot_id, p11_get_ckr(rc)); goto testcase_cleanup; } encrypted_data2_len = sizeof(encrypted_data2); rc = _C_IBM_ReencryptSingle(session, &mech1->mech, sym_key1 != CK_INVALID_HANDLE ? sym_key1 : priv_key1, &mech2->mech, sym_key2 != CK_INVALID_HANDLE ? sym_key2 : publ_key2, encrypted_data1, encrypted_data1_len, encrypted_data2, &encrypted_data2_len); if (rc != CKR_OK) { oaep = (CK_RSA_PKCS_OAEP_PARAMS *)mech2->mech.pParameter; if (rc == CKR_MECHANISM_PARAM_INVALID && mech2->mech.mechanism == CKM_RSA_PKCS_OAEP && is_ep11_token(slot_id) && (oaep->hashAlg != CKM_SHA_1 || oaep->mgf != CKG_MGF1_SHA1)) { testcase_skip("EP11 Token does not support RSA OAEP with hash " "and/or MGF other than SHA-1"); goto testcase_cleanup; } if (rc == CKR_FUNCTION_NOT_SUPPORTED) { testcase_skip("Slot %lu does not support C_IBM_ReencryptSingle", slot_id); goto testcase_cleanup; } testcase_error("C_IBM_ReencryptSingle with decr-mech %s (%u) and " "encr-mech %s (%u) failed, rc=%s", mech_to_str(mech1->mech.mechanism), (unsigned int)mech1->mech.mechanism, mech_to_str(mech2->mech.mechanism), (unsigned int)mech2->mech.mechanism, p11_get_ckr(rc)); goto testcase_cleanup; } rc = funcs->C_DecryptInit(session, &mech2->mech, sym_key2 != CK_INVALID_HANDLE ? sym_key2 : priv_key2); if (rc != CKR_OK) { testcase_error("C_DecryptInit rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } decrypted_data_len = sizeof(decrypted_data); rc = funcs->C_Decrypt(session, encrypted_data2, encrypted_data2_len, decrypted_data, &decrypted_data_len); if (rc != CKR_OK) { testcase_error("C_Decrypt rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } if (decrypted_data_len != mech1->clear_data_len) { testcase_error("The decrypted data length differs from the original " "clear data: original: %lu, decrypted: %lu", mech1->clear_data_len, decrypted_data_len); rc = CKR_FUNCTION_FAILED; goto testcase_cleanup; } if (memcmp(clear_data, decrypted_data, mech1->clear_data_len) != 0) { testcase_error("The decrypted data differs from the original " "clear data."); rc = CKR_FUNCTION_FAILED; goto testcase_cleanup; } testcase_new_assertion(); testcase_pass("Reencrypt from '%s' to '%s'", mech1->name, mech2->name); testcase_cleanup: if (sym_key2 != CK_INVALID_HANDLE) { loc_rc = funcs->C_DestroyObject(session, sym_key2); if (loc_rc != CKR_OK) testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(loc_rc)); } sym_key2 = CK_INVALID_HANDLE; if (publ_key2 != CK_INVALID_HANDLE) { loc_rc = funcs->C_DestroyObject(session, publ_key2); if (loc_rc != CKR_OK) testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(loc_rc)); } publ_key2 = CK_INVALID_HANDLE; if (priv_key2 != CK_INVALID_HANDLE) { loc_rc = funcs->C_DestroyObject(session, priv_key2); if (loc_rc != CKR_OK) testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(loc_rc)); } priv_key2 = CK_INVALID_HANDLE; if (s != NULL) free(s); return rc; } CK_RV do_encrypt_reencrypt(struct mech_info *mech1) { CK_RSA_PKCS_OAEP_PARAMS *oaep; CK_RV loc_rc, rc = CKR_OK; char *s = NULL; CK_ULONG i; testsuite_begin("with '%s'", mech1->name); if (!mech_supported(slot_id, mech1->key_gen_mech.mechanism)) { testsuite_skip(NUM_REENCRYPT_TESTS, "Slot %u doesn't support %s (0x%x)", (unsigned int)slot_id, mech_to_str(mech1->key_gen_mech.mechanism), (unsigned int)mech1->key_gen_mech.mechanism); goto testcase_cleanup; } if (!mech_supported(slot_id, mech1->mech.mechanism)) { testsuite_skip(NUM_REENCRYPT_TESTS, "Slot %u doesn't support %s (0x%x)", (unsigned int)slot_id, mech_to_str(mech1->mech.mechanism), (unsigned int)mech1->mech.mechanism); goto testcase_cleanup; } switch (mech1->mech.mechanism) { case CKM_DES_ECB: case CKM_DES_CBC: case CKM_DES_CBC_PAD: if (is_cca_token(slot_id)) { testsuite_skip(NUM_REENCRYPT_TESTS, "CCA does not support DES " "with reencrypt"); goto testcase_cleanup; } break; case CKM_DES3_CBC_PAD: if (is_cca_token(slot_id)) { testsuite_skip(NUM_REENCRYPT_TESTS, "CCA does not support DES3 " "CBC PAD with reencrypt"); goto testcase_cleanup; } break; case CKM_RSA_PKCS: case CKM_RSA_PKCS_OAEP: if (is_cca_token(slot_id)) { testsuite_skip(NUM_REENCRYPT_TESTS, "CCA does not support RSA " "with reencrypt"); goto testcase_cleanup; } break; default: break; } /* * Generate the key 1 */ switch (mech1->key_gen_mech.mechanism) { case CKM_RSA_PKCS_KEY_PAIR_GEN: if (p11_ahex_dump(&s, mech1->rsa_publ_exp, mech1->rsa_publ_exp_len) == NULL) { testcase_error("p11_ahex_dump() failed"); rc = CKR_FUNCTION_FAILED; goto testcase_cleanup; } if (!keysize_supported(slot_id, mech1->key_gen_mech.mechanism, mech1->rsa_modbits)) { testsuite_skip(NUM_REENCRYPT_TESTS, "Token in slot %lu cannot be " "used with modbits='%lu'", slot_id, mech1->rsa_modbits); goto testcase_cleanup; } if (is_ep11_token(slot_id)) { if (!is_valid_ep11_pubexp(mech1->rsa_publ_exp, mech1->rsa_publ_exp_len)) { testsuite_skip(NUM_REENCRYPT_TESTS, "EP11 Token cannot be " "used with publ_exp.='%s'", s); goto testcase_cleanup; } } if (is_cca_token(slot_id)) { if (!is_valid_cca_pubexp(mech1->rsa_publ_exp, mech1->rsa_publ_exp_len)) { testsuite_skip(NUM_REENCRYPT_TESTS, "CCA Token cannot be " "used with publ_exp.='%s'", s); goto testcase_cleanup; } } if (is_soft_token(slot_id)) { if (!is_valid_soft_pubexp(mech1->rsa_publ_exp, mech1->rsa_publ_exp_len)) { testsuite_skip(NUM_REENCRYPT_TESTS, "Soft Token cannot be " "used with publ_exp.='%s'", s); goto testcase_cleanup; } } if (is_tpm_token(slot_id) ) { if (!is_valid_tpm_pubexp(mech1->rsa_publ_exp, mech1->rsa_publ_exp_len) || !is_valid_tpm_modbits(mech1->rsa_modbits)) { testsuite_skip(NUM_REENCRYPT_TESTS, "TPM Token cannot be used " "with publ_exp.='%s'", s); goto testcase_cleanup; } } if (is_icsf_token(slot_id)) { if (!is_valid_icsf_pubexp(mech1->rsa_publ_exp, mech1->rsa_publ_exp_len) || mech1->rsa_modbits < 1024) { testsuite_skip(NUM_REENCRYPT_TESTS, "ICSF Token cannot be " "used with publ_exp='%s'.", s); goto testcase_cleanup; } } rc = generate_RSA_PKCS_KeyPair(session, CKM_RSA_PKCS_KEY_PAIR_GEN, mech1->rsa_modbits, mech1->rsa_publ_exp, mech1->rsa_publ_exp_len, &publ_key1, &priv_key1); break; case CKM_AES_KEY_GEN: rc = generate_AESKey(session, mech1->sym_keylen, CK_TRUE, &mech1->key_gen_mech, &sym_key1); break; case CKM_DES3_KEY_GEN: case CKM_DES2_KEY_GEN: case CKM_DES_KEY_GEN: rc = funcs->C_GenerateKey(session, &mech1->key_gen_mech, NULL, 0, &sym_key1); break; default: testcase_error("Testcase does not support %s (%u)", mech_to_str(mech1->key_gen_mech.mechanism), (unsigned int)mech1->key_gen_mech.mechanism); goto testcase_cleanup; } if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("generate key-1 with mech %s (%u) in slot %lu " "is not allowed by policy", mech_to_str(mech1->key_gen_mech.mechanism), (unsigned int)mech1->key_gen_mech.mechanism, slot_id); goto testcase_cleanup; } testcase_error("generate key-1 with mech %s (%u) in slot %lu " "failed, rc=%s", mech_to_str(mech1->key_gen_mech.mechanism), (unsigned int)mech1->key_gen_mech.mechanism, slot_id, p11_get_ckr(rc)); goto testcase_cleanup; } rc = funcs->C_EncryptInit(session, &mech1->mech, sym_key1 != CK_INVALID_HANDLE ? sym_key1 : publ_key1); if (rc != CKR_OK) { oaep = (CK_RSA_PKCS_OAEP_PARAMS *)mech1->mech.pParameter; if (rc == CKR_MECHANISM_PARAM_INVALID && mech1->mech.mechanism == CKM_RSA_PKCS_OAEP && is_ep11_token(slot_id) && (oaep->hashAlg != CKM_SHA_1 || oaep->mgf != CKG_MGF1_SHA1)) { testsuite_skip(NUM_REENCRYPT_TESTS, "EP11 Token does not support " "RSA OAEP with hash and/or MGF other than SHA-1"); goto testcase_cleanup; } testcase_error("C_EncryptInit rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } encrypted_data1_len = sizeof(encrypted_data1); rc = funcs->C_Encrypt(session, clear_data, mech1->clear_data_len, encrypted_data1, &encrypted_data1_len); if (rc != CKR_OK) { testcase_error("C_Encrypt rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } for (i = 0; i < NUM_REENCRYPT_TESTS; i++) { rc = do_reencrypt(mech1, &reencrypt_tests[i]); if (rc != CKR_OK) break; } testcase_cleanup: if (sym_key1 != CK_INVALID_HANDLE) { loc_rc = funcs->C_DestroyObject(session, sym_key1); if (loc_rc != CKR_OK) testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(loc_rc)); } sym_key1 = CK_INVALID_HANDLE; if (publ_key1 != CK_INVALID_HANDLE) { loc_rc = funcs->C_DestroyObject(session, publ_key1); if (loc_rc != CKR_OK) testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(loc_rc)); } publ_key1 = CK_INVALID_HANDLE; if (priv_key1 != CK_INVALID_HANDLE) { loc_rc = funcs->C_DestroyObject(session, priv_key1); if (loc_rc != CKR_OK) testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(loc_rc)); } priv_key1 = CK_INVALID_HANDLE; if (s != NULL) free(s); return rc; } CK_RV do_reencrypt_tests(void) { CK_ULONG i; CK_RV rc; for (i = 0; i < sizeof(clear_data); i++) clear_data[i] = (CK_BYTE)i; for (i = 0; i < NUM_REENCRYPT_TESTS; i++) { rc = do_encrypt_reencrypt(&reencrypt_tests[i]); if (rc != CKR_OK) break; } return CKR_OK; } int main(int argc, char **argv) { CK_C_INITIALIZE_ARGS cinit_args; int i, ret = 1; CK_RV rv; CK_FLAGS flags; for (i = 1; i < argc; i++) { if (strcmp(argv[i], "-slot") == 0) { ++i; if (i >= argc) { printf("Slot number missing\n"); return -1; } 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; } *(void **)(&_C_IBM_ReencryptSingle) = dlsym(pkcs11lib, "C_IBM_ReencryptSingle"); if (_C_IBM_ReencryptSingle == NULL) { testcase_skip("C_IBM_ReencryptSingle not supported"); goto out; } testcase_setup(); 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; } 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; } 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; } rv = do_reencrypt_tests(); if (rv != CKR_OK) goto close_session; rv = funcs->C_CloseSession(session); if (rv != CKR_OK) { testcase_fail("C_CloseSession rc = %s", p11_get_ckr(rv)); goto finalize; } rv = funcs->C_Finalize(NULL); if (rv != CKR_OK) { testcase_fail("C_Finalize rc = %s", p11_get_ckr(rv)); goto out; } ret = 0; goto out; close_session: rv = funcs->C_CloseSession(session); if (rv != CKR_OK) { testcase_fail("C_CloseSession rc = %s", p11_get_ckr(rv)); ret = 1; } finalize: rv = funcs->C_Finalize(NULL); if (rv != CKR_OK) { testcase_fail("C_Finalize rc = %s", p11_get_ckr(rv)); ret = 1; } out: testcase_print_result(); return testcase_return(ret); } opencryptoki-opencryptoki-451d99c/testcases/misc_tests/rsa-key.pem000066400000000000000000000041161520105705100255570ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEAt7QmlNEerbJO19BfRF9oZ4AL7D9p+U60vj1Vs9N9UrA5RBGm n4+EdCqrLyIKtCqCplyXIY2AScB6axLWCh0+9g/kkQDkgD3JQDi/7TMyRwZAUrdG 4d5IfLPNkzIiaahyP1IbedhU9xYNRPx3jMfFc5S+XyZIY2f0xxeYFCLMC3OtM/8D Pr7QSZskKLiyGfP26G9ZbEHKJcmMcswuW0HxE6ReLI6v57OxqR/Tqpb1uLNC4KC/ 7VkggyUF2N/w7pssVb+bZSvix3flBTUaJ3XwrGyydgAVOI1GLq219KlcmPLo4d/j XDz41eQKFlMi8etqr5b32uVfoj+W5ukLz5H+kQIDAQABAoIBAALTUoSXctFZHL1V ByIWFZUB8yz/DLI48665YsgRSKws6bSSUO3DV1YyEc/3xhJfVQMaCXkKpB5+R2O+ NmyRZpaCSBGy4dDXInFKbilH0E4nWnXrO7vdn1/LpC3PZ5gYbylqKeIF4cirHikh ePVBXVgZwZPVEuf0gV9OjZhBsMG8Tw4p4u5WDx00LmL5I9Iy1ozH9VrYGQ6lUl/1 K3KdKynx5L0cQDad6jgOfNojHUHqH98TwyMNsGl4UHp8wQ0iHOGw0hyzEL8bB2e3 jM1hX2kzEIKyyA8QxW12tIsmeg8Ijmzk2CsbHEEffFQTqMaaQtiLxLuL1rnQ6GBC qk0GjMECgYEA57QSVnjf+waLbPdfzxTw+GEm3YmzANTSSniVSK/8RlCs0tLWIGgQ q6oSztVhUn2+IXLhbmsCl0ni+lZvRYEW2vg2gxuwVhaMloyLYdL1VBt49EtgCYtr s5jmPjFGGtUgSqnQaWBGGAfthlGLNUcz3bbIvAt+vTAY5VDNmbjAhSsCgYEAyveO 78OWVncMxaE2p0BF2g3B2KIwVdNoxrtYkmwhqPR56RBTpya3IOyV7lMvsjUE7lRx jLsEYtWEmQUsuSuyiUnNNVx8Mr4uu3z959b/ZQ5KrHLulV2up1nPFcSnA2nDAmwO MNqfrO+Ngt0qQGTdyTYcIZJNrTNClNhh6AJI5TMCgYA0OrYrgeHTXx1MudKCBpFv G887/w83r8GbgeT81pbCbusWNuqHsY2YdKT6tMTUaH3UYmYIktypp8Efdx5sB3ZU c8Et+q7cKQcV5KaCraAZjnvMbbU/UYs8l8nG2SqZX9OAoRjWuBn0zsyvC3Ca2OsL HmnPYbP3B4GFJ5rA/RGAswKBgQCcK+38yNcVwta9/nTqLkdRKAK+6NUeROQ6/g6B 49fmg+6GCX0EgYKpP8GBttpdWfRoWethKMmQLtCvWU73UAs5HeNbKsWZ2cJlmyBX UpQDMwL8PBceMQ5hUHZKPp1vv+JAK9qjdqUkUNLnHbwT/ki1OQBeSI+iNG4Hz5NO DOwABwKBgBqqyBRVNN9qZIzdI2PVmLeRTKMm5QJUrs5xZ+WAqMSUq5SlwJ0WtHLF ngpHzzaCvTwLmhk/CZgX6BAFDWBXOhBvFzoBtEveojTRgncJK3go1lvto1OOnK5g qXOL4QhACnthj0rmE6lLzwyu3jYSxp/0M6G4u8zIqM0yQGabhCj1 -----END RSA PRIVATE KEY----- -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt7QmlNEerbJO19BfRF9o Z4AL7D9p+U60vj1Vs9N9UrA5RBGmn4+EdCqrLyIKtCqCplyXIY2AScB6axLWCh0+ 9g/kkQDkgD3JQDi/7TMyRwZAUrdG4d5IfLPNkzIiaahyP1IbedhU9xYNRPx3jMfF c5S+XyZIY2f0xxeYFCLMC3OtM/8DPr7QSZskKLiyGfP26G9ZbEHKJcmMcswuW0Hx E6ReLI6v57OxqR/Tqpb1uLNC4KC/7VkggyUF2N/w7pssVb+bZSvix3flBTUaJ3Xw rGyydgAVOI1GLq219KlcmPLo4d/jXDz41eQKFlMi8etqr5b32uVfoj+W5ukLz5H+ kQIDAQAB -----END PUBLIC KEY----- opencryptoki-opencryptoki-451d99c/testcases/misc_tests/speed.c000066400000000000000000001011671520105705100247510ustar00rootroot00000000000000/* * 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 "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 } // keylength: 512, 1024, 2048, 4096 int do_RSA_PKCS_EncryptDecrypt(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 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=%lu", keylength, sizeof(data1)); if (!mech_supported(SLOT_ID, CKM_RSA_PKCS_KEY_PAIR_GEN)) { testcase_skip("Slot %lu doesn't support CKM_RSA_PKCS_KEY_PAIR_GEN (0x%x)", SLOT_ID, CKM_RSA_PKCS_KEY_PAIR_GEN); return TRUE; } if (!mech_supported(SLOT_ID, CKM_RSA_PKCS)) { testcase_skip("Slot %lu doesn't support CKM_RSA_PKCS (0x%x)", SLOT_ID, CKM_RSA_PKCS); return TRUE; } testcase_new_assertion(); 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("%lu iterations: total=%lums min=%lums max=%lums avg=%lums " "op/s=%.3f\n", iterations, tot_time, min_time, max_time, avg_time, (double) (iterations * 1000) / (double) tot_time); testcase_pass("RSA PKCS Encrypt with keylen=%d datalen=%lu", keylength, sizeof(data1)); testcase_begin("RSA PKCS Decrypt with keylen=%d datalen=%lu", keylength, encdata_len); testcase_new_assertion(); 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("%lu iterations: total=%lums min=%lums max=%lums avg=%lums " "op/s=%.3f\n", iterations, tot_time, min_time, max_time, avg_time, (double) (iterations * 1000) / (double) tot_time); testcase_pass("RSA PKCS Decrypt with keylen=%d datalen=%lu", keylength, encdata_len); testcase_cleanup: testcase_closeall_session(); if (rc != CKR_OK) 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 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); if (!mech_supported(SLOT_ID, CKM_RSA_PKCS_KEY_PAIR_GEN)) { testcase_skip("Slot %lu doesn't support CKM_RSA_PKCS_KEY_PAIR_GEN (0x%x)", SLOT_ID, CKM_RSA_PKCS_KEY_PAIR_GEN); return TRUE; } testcase_new_assertion(); 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("%lu iterations: total=%lums min=%lums max=%lums avg=%lums " "op/s=%.3f\n", iterations, tot_time, min_time, max_time, avg_time, (double) (iterations * 1000) / (double) tot_time); testcase_pass("RSA KeyGen with keylen=%d", keylength); testcase_cleanup: testcase_closeall_session(); if (rc != CKR_OK) return FALSE; return TRUE; } // keylength: 512, 1024, 2048, 4096 int do_RSA_PKCS_SignVerify(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 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)} }; testcase_begin("RSA PKCS Sign with keylen=%d datalen=%lu", keylength, sizeof(data1)); if (!mech_supported(SLOT_ID, CKM_RSA_PKCS_KEY_PAIR_GEN)) { testcase_skip("Slot %lu doesn't support CKM_RSA_PKCS_KEY_PAIR_GEN (0x%x)", SLOT_ID, CKM_RSA_PKCS_KEY_PAIR_GEN); return TRUE; } if (!mech_supported(SLOT_ID, CKM_RSA_PKCS)) { testcase_skip("Slot %lu doesn't support CKM_RSA_PKCS (0x%x)", SLOT_ID, CKM_RSA_PKCS); return TRUE; } testcase_new_assertion(); 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("%lu iterations: total=%lums min=%lums max=%lums avg=%lums " "op/s=%.3f\n", iterations, tot_time, min_time, max_time, avg_time, (double) (iterations * 1000) / (double) tot_time); testcase_pass("RSA PKCS Sign with keylen=%d datalen=%lu", keylength, sizeof(data1)); testcase_begin("RSA PKCS Verify with keylen=%d datalen=%lu", keylength, sizeof(data1)); testcase_new_assertion(); 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("%lu iterations: total=%lums min=%lums max=%lums avg=%lums " "op/s=%.3f\n", iterations, tot_time, min_time, max_time, avg_time, (double) (iterations * 1000) / (double) tot_time); testcase_pass("RSA PKCS Verify with keylen=%d datalen=%lu", keylength, sizeof(data1)); testcase_cleanup: testcase_closeall_session(); if (rc != CKR_OK) return FALSE; return TRUE; } // mode: ECB CBC int do_DES3_EncrDecr(const char *mode) { 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 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; testcase_begin("DES3 Encrypt with mode=%s datalen=%d", mode, BIG_REQUEST); if (!mech_supported(SLOT_ID, CKM_DES3_KEY_GEN)) { testcase_skip("Slot %lu doesn't support CKM_DES3_KEY_GEN (0x%x)", SLOT_ID, CKM_DES3_KEY_GEN); return TRUE; } if (strcmp(mode, "ECB") == 0 && !mech_supported(SLOT_ID, CKM_DES3_ECB)) { testcase_skip("Slot %lu doesn't support CKM_DES3_ECB (0x%x)", SLOT_ID, CKM_DES3_ECB); return TRUE; } if (strcmp(mode, "CBC") == 0 && !mech_supported(SLOT_ID, CKM_DES3_CBC)) { testcase_skip("Slot %lu doesn't support CKM_DES3_CBC (0x%x)", SLOT_ID, CKM_DES3_CBC); return TRUE; } testcase_new_assertion(); 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("%lu iterations: total=%lums min=%luus max=%luus avg=%luus " "op/s=%.3f %.3fMB/s\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_pass("DES3 Encrypt with mode=%s datalen=%d", mode, BIG_REQUEST); testcase_begin("DES3 Decrypt with mode=%s datalen=%d", mode, BIG_REQUEST); testcase_new_assertion(); 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("%lu iterations: total=%lums min=%luus max=%luus avg=%luus " "op/s=%.3f %.3fMB/s\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_pass("DES3 Decrypt with mode=%s datalen=%d", mode, BIG_REQUEST); testcase_cleanup: testcase_closeall_session(); if (rc != CKR_OK) return FALSE; return TRUE; } // keylength: 128...256 // mode: ECB CBC int do_AES_EncrDecr(int keylength, const char *mode) { 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 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=%lu datalen=%d", mode, key_len * 8, BIG_REQUEST); if (!mech_supported(SLOT_ID, CKM_AES_KEY_GEN)) { testcase_skip("Slot %lu doesn't support CKM_AES_KEY_GEN (0x%x)", SLOT_ID, CKM_AES_KEY_GEN); return TRUE; } if (strcmp(mode, "ECB") == 0 && !mech_supported(SLOT_ID, CKM_AES_ECB)) { testcase_skip("Slot %lu doesn't support CKM_AES_ECB (0x%x)", SLOT_ID, CKM_AES_ECB); return TRUE; } if (strcmp(mode, "CBC") == 0 && !mech_supported(SLOT_ID, CKM_AES_CBC)) { testcase_skip("Slot %lu doesn't support CKM_AES_CBC (0x%x)", SLOT_ID, CKM_AES_CBC); return TRUE; } testcase_new_assertion(); testcase_rw_session(); testcase_user_login(); mech.mechanism = CKM_AES_KEY_GEN; mech.ulParameterLen = 0; mech.pParameter = NULL; rc = generate_AESKey(session, key_len, CK_TRUE, &mech, &h_key); if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("AES key generation is not allowed by policy"); goto testcase_cleanup; } 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("%lu iterations: total=%lums min=%luus max=%luus avg=%luus " "op/s=%.3f %.3fMB/s\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_pass("AES Encrypt with mode=%s keylen=%lu datalen=%d", mode, key_len * 8, BIG_REQUEST); testcase_begin("AES Decrypt with mode=%s keylen=%lu datalen=%d", mode, key_len * 8, BIG_REQUEST); testcase_new_assertion(); 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("%lu iterations: total=%lums min=%luus max=%luus avg=%luus " "op/s=%.3f %.3fMB/s\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_pass("AES Decrypt with mode=%s keylen=%lu datalen=%d", mode, key_len * 8, BIG_REQUEST); testcase_cleanup: testcase_closeall_session(); if (rc != CKR_OK) return FALSE; return TRUE; } int do_SHA(const char *mode) { CK_SESSION_HANDLE session; CK_MECHANISM mech; CK_FLAGS flags; CK_RV rc; 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; testcase_begin("SHA (%s) with datalen=%d", mode, BIG_REQUEST); if (strcmp(mode, "SHA1") == 0 && !mech_supported(SLOT_ID, CKM_SHA_1)) { testcase_skip("Slot %lu doesn't support CKM_SHA_1 (0x%x)", SLOT_ID, CKM_SHA_1); return TRUE; } if (strcmp(mode, "SHA256") == 0 && !mech_supported(SLOT_ID, CKM_SHA256)) { testcase_skip("Slot %lu doesn't support CKM_SHA256 (0x%x)", SLOT_ID, CKM_SHA256); return TRUE; } if (strcmp(mode, "SHA512") == 0 && !mech_supported(SLOT_ID, CKM_SHA512)) { testcase_skip("Slot %lu doesn't support CKM_SHA512 (0x%x)", SLOT_ID, CKM_SHA512); return TRUE; } testcase_new_assertion(); 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 %lu doesn't match to expected len %lu\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("%lu iterations: total=%lums min=%luus max=%luus avg=%luus " "op/s=%.3f %.3fMB/s\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_pass("SHA (%s) with datalen=%d", mode, BIG_REQUEST); testcase_cleanup: testcase_closeall_session(); if (rc != CKR_OK) return FALSE; 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) { if (i + 1 >= argc) { printf("Slot number missing\n"); return -1; } 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); testcase_setup(); if (do_rsa_keygen) { testsuite_begin("RSA Keygen."); rc = do_RSA_KeyGen(1024); if (!rc) goto out; rc = do_RSA_KeyGen(2048); if (!rc) goto out; rc = do_RSA_KeyGen(4096); if (!rc) goto out; } if (do_rsa_signverify) { testsuite_begin("RSA Sign/Verify."); rc = do_RSA_PKCS_SignVerify(1024); if (!rc) goto out; rc = do_RSA_PKCS_SignVerify(2048); if (!rc) goto out; rc = do_RSA_PKCS_SignVerify(4096); if (!rc) goto out; } if (do_rsa_endecrypt) { testsuite_begin("RSA Encrypt/Decrypt."); rc = do_RSA_PKCS_EncryptDecrypt(1024); if (!rc) goto out; rc = do_RSA_PKCS_EncryptDecrypt(2048); if (!rc) goto out; rc = do_RSA_PKCS_EncryptDecrypt(4096); if (!rc) goto out; } if (do_des3_endecrypt) { testsuite_begin("DES3 Encrypt/Decrypt."); rc = do_DES3_EncrDecr("ECB"); if (!rc) goto out; rc = do_DES3_EncrDecr("CBC"); if (!rc) goto out; } if (do_aes_endecrypt) { testsuite_begin("AES Encrypt/Decrypt."); rc = do_AES_EncrDecr(128, "ECB"); if (!rc) goto out; rc = do_AES_EncrDecr(128, "CBC"); if (!rc) goto out; rc = do_AES_EncrDecr(192, "ECB"); if (!rc) goto out; rc = do_AES_EncrDecr(192, "CBC"); if (!rc) goto out; rc = do_AES_EncrDecr(256, "ECB"); if (!rc) goto out; rc = do_AES_EncrDecr(256, "CBC"); if (!rc) goto out; } if (do_sha) { testsuite_begin("SHA Digest."); rc = do_SHA("SHA1"); if (!rc) goto out; rc = do_SHA("SHA256"); if (!rc) goto out; rc = do_SHA("SHA512"); if (!rc) goto out; } out: testcase_print_result(); funcs->C_Finalize(NULL); return testcase_return(!rc); } opencryptoki-opencryptoki-451d99c/testcases/misc_tests/spinlock_child.sh000077500000000000000000000012131520105705100270200ustar00rootroot00000000000000#!/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 opencryptoki-opencryptoki-451d99c/testcases/misc_tests/spinlock_tests.sh000077500000000000000000000016421520105705100271050ustar00rootroot00000000000000#!/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" opencryptoki-opencryptoki-451d99c/testcases/misc_tests/threadmkobj.c000066400000000000000000000102541520105705100261370ustar00rootroot00000000000000/* * 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); 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) { if (i + 1 >= argc) { printf("Slot number missing\n"); return -1; } 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; } opencryptoki-opencryptoki-451d99c/testcases/misc_tests/tok2tok_transport.c000066400000000000000000002672041520105705100273670ustar00rootroot00000000000000/* * 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: tok2tok_transport.c * * Test driver. In-depth regression test for PKCS #11 */ #include #include #include #include #include #include #include #include #include "pkcs11types.h" #include "regress.h" #include "mech_to_str.h" #include "ec_curves.h" #include "common.c" #include CK_RSA_PKCS_OAEP_PARAMS oaep_params_sha1 = { .hashAlg = CKM_SHA_1, .mgf = CKG_MGF1_SHA1, .source = 0, .pSourceData = NULL, .ulSourceDataLen = 0, }; CK_RSA_PKCS_OAEP_PARAMS oaep_params_sha1_source = { .hashAlg = CKM_SHA_1, .mgf = CKG_MGF1_SHA1, .source = CKZ_DATA_SPECIFIED, .pSourceData = "abc", .ulSourceDataLen = 3, }; CK_RSA_PKCS_OAEP_PARAMS oaep_params_sha256 = { .hashAlg = CKM_SHA256, .mgf = CKG_MGF1_SHA256, .source = 0, .pSourceData = NULL, .ulSourceDataLen = 0, }; CK_RSA_PKCS_OAEP_PARAMS oaep_params_sha256_source = { .hashAlg = CKM_SHA256, .mgf = CKG_MGF1_SHA256, .source = CKZ_DATA_SPECIFIED, .pSourceData = "abc", .ulSourceDataLen = 3, }; CK_RSA_AES_KEY_WRAP_PARAMS rsa_aeskw_aes_256_oaep_sha1_params = { .ulAESKeyBits = 256, .pOAEPParams = &oaep_params_sha1, }; CK_BYTE aes_iv[16] = { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f }; CK_BYTE des_iv[8] = { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07 }; CK_ECDH_AES_KEY_WRAP_PARAMS ecdh_aeskw_aes_256__params = { .ulAESKeyBits = 256, .kdf = CKD_SHA256_KDF, .ulSharedDataLen = 3, .pSharedData = (CK_BYTE *)"abc", }; CK_BYTE gcm_aad[8] = { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07 }; CK_GCM_PARAMS aes_gcm_param = { .pIv = aes_iv, .ulIvLen = sizeof(aes_iv), .pAAD = gcm_aad, .ulAADLen = sizeof(gcm_aad), .ulTagBits = 32, }; CK_EDDSA_PARAMS eddsa_param = { .phFlag = FALSE, .ulContextDataLen = 0, .pContextData = NULL, }; CK_ECDH1_DERIVE_PARAMS ecdh_param = { .kdf = CKD_NULL, .ulSharedDataLen = 0, .pSharedData = NULL, .ulPublicDataLen = 0, .pPublicData = NULL, }; CK_BYTE prime256v1[] = OCK_PRIME256V1; CK_BYTE ed25519[] = OCK_ED25519; CK_BYTE ed448[] = OCK_ED448; CK_BYTE curve25519[] = OCK_CURVE25519; CK_BYTE curve448[] = OCK_CURVE448; struct wrapping_mech_info { char *name; CK_MECHANISM wrapping_mech; CK_MECHANISM wrapping_key_gen_mech; CK_ULONG rsa_modbits; CK_ULONG rsa_publ_exp_len; CK_BYTE rsa_publ_exp[4]; CK_ULONG sym_keylen; CK_BYTE ec_parms_len; CK_BYTE *ec_parms; }; struct wrapping_mech_info wrapping_tests[] = { { .name = "Wrap/Unwrap with RSA 512 PKCS", .wrapping_mech = { CKM_RSA_PKCS, 0, 0 }, .wrapping_key_gen_mech = { CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0 }, .rsa_modbits = 512, .rsa_publ_exp_len = 3, .rsa_publ_exp = {0x01, 0x00, 0x01}, }, { .name = "Wrap/Unwrap with RSA 1024 PKCS", .wrapping_mech = { CKM_RSA_PKCS, 0, 0 }, .wrapping_key_gen_mech = { CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0 }, .rsa_modbits = 1024, .rsa_publ_exp_len = 3, .rsa_publ_exp = {0x01, 0x00, 0x01}, }, { .name = "Wrap/Unwrap with RSA 2048 PKCS", .wrapping_mech = { CKM_RSA_PKCS, 0, 0 }, .wrapping_key_gen_mech = { CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0 }, .rsa_modbits = 2048, .rsa_publ_exp_len = 3, .rsa_publ_exp = {0x01, 0x00, 0x01}, }, { .name = "Wrap/Unwrap with RSA 8192 PKCS", .wrapping_mech = { CKM_RSA_PKCS, 0, 0 }, .wrapping_key_gen_mech = { CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0 }, .rsa_modbits = 8192, .rsa_publ_exp_len = 3, .rsa_publ_exp = {0x01, 0x00, 0x01}, }, { .name = "Wrap/Unwrap with RSA 1024 PKCS OAEP (SHA1)", .wrapping_mech = { CKM_RSA_PKCS_OAEP, &oaep_params_sha1, sizeof(CK_RSA_PKCS_OAEP_PARAMS) }, .wrapping_key_gen_mech = { CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0 }, .rsa_modbits = 1024, .rsa_publ_exp_len = 3, .rsa_publ_exp = {0x01, 0x00, 0x01}, }, { .name = "Wrap/Unwrap with RSA 1024 PKCS OAEP (SHA1, source data)", .wrapping_mech = { CKM_RSA_PKCS_OAEP, &oaep_params_sha1_source, sizeof(CK_RSA_PKCS_OAEP_PARAMS) }, .wrapping_key_gen_mech = { CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0 }, .rsa_modbits = 1024, .rsa_publ_exp_len = 3, .rsa_publ_exp = {0x01, 0x00, 0x01}, }, { .name = "Wrap/Unwrap with RSA 1024 PKCS OAEP (SHA256)", .wrapping_mech = { CKM_RSA_PKCS_OAEP, &oaep_params_sha256, sizeof(CK_RSA_PKCS_OAEP_PARAMS) }, .wrapping_key_gen_mech = { CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0 }, .rsa_modbits = 1024, .rsa_publ_exp_len = 3, .rsa_publ_exp = {0x01, 0x00, 0x01}, }, { .name = "Wrap/Unwrap with RSA 1024 PKCS OAEP (SHA256, source data)", .wrapping_mech = { CKM_RSA_PKCS_OAEP, &oaep_params_sha256_source, sizeof(CK_RSA_PKCS_OAEP_PARAMS) }, .wrapping_key_gen_mech = { CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0 }, .rsa_modbits = 1024, .rsa_publ_exp_len = 3, .rsa_publ_exp = {0x01, 0x00, 0x01}, }, { .name = "Wrap/Unwrap with AES 128 ECB", .wrapping_mech = { CKM_AES_ECB, 0, 0 }, .wrapping_key_gen_mech = { CKM_AES_KEY_GEN, 0, 0 }, .sym_keylen = 16, }, { .name = "Wrap/Unwrap with AES 192 ECB", .wrapping_mech = { CKM_AES_ECB, 0, 0 }, .wrapping_key_gen_mech = { CKM_AES_KEY_GEN, 0, 0 }, .sym_keylen = 24, }, { .name = "Wrap/Unwrap with AES 256 ECB", .wrapping_mech = { CKM_AES_ECB, 0, 0 }, .wrapping_key_gen_mech = { CKM_AES_KEY_GEN, 0, 0 }, .sym_keylen = 32, }, { .name = "Wrap/Unwrap with AES 128 CBC", .wrapping_mech = { CKM_AES_CBC, aes_iv, sizeof(aes_iv) }, .wrapping_key_gen_mech = { CKM_AES_KEY_GEN, 0, 0 }, .sym_keylen = 16, }, { .name = "Wrap/Unwrap with AES 192 CBC", .wrapping_mech = { CKM_AES_CBC, aes_iv, sizeof(aes_iv) }, .wrapping_key_gen_mech = { CKM_AES_KEY_GEN, 0, 0 }, .sym_keylen = 24, }, { .name = "Wrap/Unwrap with AES 256 CBC", .wrapping_mech = { CKM_AES_CBC, aes_iv, sizeof(aes_iv) }, .wrapping_key_gen_mech = { CKM_AES_KEY_GEN, 0, 0 }, .sym_keylen = 32, }, { .name = "Wrap/Unwrap with AES 128 CBC PAD", .wrapping_mech = { CKM_AES_CBC_PAD, aes_iv, sizeof(aes_iv) }, .wrapping_key_gen_mech = { CKM_AES_KEY_GEN, 0, 0 }, .sym_keylen = 16, }, { .name = "Wrap/Unwrap with AES 192 CBC PAD", .wrapping_mech = { CKM_AES_CBC_PAD, aes_iv, sizeof(aes_iv) }, .wrapping_key_gen_mech = { CKM_AES_KEY_GEN, 0, 0 }, .sym_keylen = 24, }, { .name = "Wrap/Unwrap with AES 256 CBC PAD", .wrapping_mech = { CKM_AES_CBC_PAD, aes_iv, sizeof(aes_iv) }, .wrapping_key_gen_mech = { CKM_AES_KEY_GEN, 0, 0 }, .sym_keylen = 32, }, { .name = "Wrap/Unwrap with AES 128 GCM", .wrapping_mech = { CKM_AES_GCM, &aes_gcm_param, sizeof(aes_gcm_param) }, .wrapping_key_gen_mech = { CKM_AES_KEY_GEN, 0, 0 }, .sym_keylen = 16, }, { .name = "Wrap/Unwrap with AES 192 GCM", .wrapping_mech = { CKM_AES_GCM, &aes_gcm_param, sizeof(aes_gcm_param) }, .wrapping_key_gen_mech = { CKM_AES_KEY_GEN, 0, 0 }, .sym_keylen = 24, }, { .name = "Wrap/Unwrap with AES 256 GCM", .wrapping_mech = { CKM_AES_GCM, &aes_gcm_param, sizeof(aes_gcm_param) }, .wrapping_key_gen_mech = { CKM_AES_KEY_GEN, 0, 0 }, .sym_keylen = 32, }, { .name = "Wrap/Unwrap with AES 128 XTS", .wrapping_mech = { CKM_AES_XTS, aes_iv, sizeof(aes_iv) }, .wrapping_key_gen_mech = { CKM_AES_XTS_KEY_GEN, 0, 0 }, .sym_keylen = 32, }, { .name = "Wrap/Unwrap with AES 256 XTS", .wrapping_mech = { CKM_AES_XTS, aes_iv, sizeof(aes_iv) }, .wrapping_key_gen_mech = { CKM_AES_XTS_KEY_GEN, 0, 0 }, .sym_keylen = 64, }, { .name = "Wrap/Unwrap with AES 128 KEY WRAP", .wrapping_mech = { CKM_AES_KEY_WRAP, NULL, 0 }, .wrapping_key_gen_mech = { CKM_AES_KEY_GEN, 0, 0 }, .sym_keylen = 16, }, { .name = "Wrap/Unwrap with AES 192 KEY WRAP", .wrapping_mech = { CKM_AES_KEY_WRAP, NULL, 0 }, .wrapping_key_gen_mech = { CKM_AES_KEY_GEN, 0, 0 }, .sym_keylen = 24, }, { .name = "Wrap/Unwrap with AES 256 KEY WRAP", .wrapping_mech = { CKM_AES_KEY_WRAP, NULL, 0 }, .wrapping_key_gen_mech = { CKM_AES_KEY_GEN, 0, 0 }, .sym_keylen = 32, }, { .name = "Wrap/Unwrap with AES 128 KEY WRAP PAD", .wrapping_mech = { CKM_AES_KEY_WRAP_PAD, NULL, 0 }, .wrapping_key_gen_mech = { CKM_AES_KEY_GEN, 0, 0 }, .sym_keylen = 16, }, { .name = "Wrap/Unwrap with AES 192 KEY WRAP PAD", .wrapping_mech = { CKM_AES_KEY_WRAP_PAD, NULL, 0 }, .wrapping_key_gen_mech = { CKM_AES_KEY_GEN, 0, 0 }, .sym_keylen = 24, }, { .name = "Wrap/Unwrap with AES 256 KEY WRAP PAD", .wrapping_mech = { CKM_AES_KEY_WRAP_PAD, NULL, 0 }, .wrapping_key_gen_mech = { CKM_AES_KEY_GEN, 0, 0 }, .sym_keylen = 32, }, { .name = "Wrap/Unwrap with AES 128 KEY WRAP KWP", .wrapping_mech = { CKM_AES_KEY_WRAP_KWP, NULL, 0 }, .wrapping_key_gen_mech = { CKM_AES_KEY_GEN, 0, 0 }, .sym_keylen = 16, }, { .name = "Wrap/Unwrap with AES 192 KEY WRAP KWP", .wrapping_mech = { CKM_AES_KEY_WRAP_KWP, NULL, 0 }, .wrapping_key_gen_mech = { CKM_AES_KEY_GEN, 0, 0 }, .sym_keylen = 24, }, { .name = "Wrap/Unwrap with AES 256 KEY WRAP KWP", .wrapping_mech = { CKM_AES_KEY_WRAP_KWP, NULL, 0 }, .wrapping_key_gen_mech = { CKM_AES_KEY_GEN, 0, 0 }, .sym_keylen = 32, }, { .name = "Wrap/Unwrap with AES 128 KEY WRAP PKCS7", .wrapping_mech = { CKM_AES_KEY_WRAP_PKCS7, NULL, 0 }, .wrapping_key_gen_mech = { CKM_AES_KEY_GEN, 0, 0 }, .sym_keylen = 16, }, { .name = "Wrap/Unwrap with AES 192 KEY WRAP PKCS7", .wrapping_mech = { CKM_AES_KEY_WRAP_PKCS7, NULL, 0 }, .wrapping_key_gen_mech = { CKM_AES_KEY_GEN, 0, 0 }, .sym_keylen = 24, }, { .name = "Wrap/Unwrap with AES 256 KEY WRAP PKCS7", .wrapping_mech = { CKM_AES_KEY_WRAP_PKCS7, NULL, 0 }, .wrapping_key_gen_mech = { CKM_AES_KEY_GEN, 0, 0 }, .sym_keylen = 32, }, { .name = "Wrap/Unwrap with RSA 2048 AES KEY WRAP (AES 256, OAEP SHA-1)", .wrapping_mech = { CKM_RSA_AES_KEY_WRAP, &rsa_aeskw_aes_256_oaep_sha1_params, sizeof(CK_RSA_AES_KEY_WRAP_PARAMS) }, .wrapping_key_gen_mech = { CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0 }, .rsa_modbits = 2048, .rsa_publ_exp_len = 3, .rsa_publ_exp = {0x01, 0x00, 0x01}, }, { .name = "Wrap/Unwrap with RSA 4096 AES KEY WRAP (AES 256, OAEP SHA-1)", .wrapping_mech = { CKM_RSA_AES_KEY_WRAP, &rsa_aeskw_aes_256_oaep_sha1_params, sizeof(CK_RSA_AES_KEY_WRAP_PARAMS) }, .wrapping_key_gen_mech = { CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0 }, .rsa_modbits = 4096, .rsa_publ_exp_len = 3, .rsa_publ_exp = {0x01, 0x00, 0x01}, }, { .name = "Wrap/Unwrap with RSA 8192 AES KEY WRAP (AES 256, OAEP SHA-1)", .wrapping_mech = { CKM_RSA_AES_KEY_WRAP, &rsa_aeskw_aes_256_oaep_sha1_params, sizeof(CK_RSA_AES_KEY_WRAP_PARAMS) }, .wrapping_key_gen_mech = { CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0 }, .rsa_modbits = 8192, .rsa_publ_exp_len = 3, .rsa_publ_exp = {0x01, 0x00, 0x01}, }, { .name = "Wrap/Unwrap with ECDH AES KEY WRAP (AES 256, P-256)", .wrapping_mech = { CKM_ECDH_AES_KEY_WRAP, &ecdh_aeskw_aes_256__params, sizeof(CK_ECDH_AES_KEY_WRAP_PARAMS) }, .wrapping_key_gen_mech = { CKM_EC_KEY_PAIR_GEN, 0, 0 }, .ec_parms = prime256v1, .ec_parms_len = sizeof(prime256v1), }, { .name = "Wrap/Unwrap with ECDH AES KEY WRAP (AES 256, X25519)", .wrapping_mech = { CKM_ECDH_AES_KEY_WRAP, &ecdh_aeskw_aes_256__params, sizeof(CK_ECDH_AES_KEY_WRAP_PARAMS) }, .wrapping_key_gen_mech = { CKM_EC_MONTGOMERY_KEY_PAIR_GEN, 0, 0 }, .ec_parms = curve25519, .ec_parms_len = sizeof(curve25519), }, { .name = "Wrap/Unwrap with ECDH-COF AES KEY WRAP (AES 256, P-256)", .wrapping_mech = { CKM_ECDH_COF_AES_KEY_WRAP, &ecdh_aeskw_aes_256__params, sizeof(CK_ECDH_AES_KEY_WRAP_PARAMS) }, .wrapping_key_gen_mech = { CKM_EC_KEY_PAIR_GEN, 0, 0 }, .ec_parms = prime256v1, .ec_parms_len = sizeof(prime256v1), }, { .name = "Wrap/Unwrap with ECDH-X AES KEY WRAP (AES 256, X25519)", .wrapping_mech = { CKM_ECDH_X_AES_KEY_WRAP, &ecdh_aeskw_aes_256__params, sizeof(CK_ECDH_AES_KEY_WRAP_PARAMS) }, .wrapping_key_gen_mech = { CKM_EC_MONTGOMERY_KEY_PAIR_GEN, 0, 0 }, .ec_parms = curve25519, .ec_parms_len = sizeof(curve25519), }, { .name = "Wrap/Unwrap with DES ECB", .wrapping_mech = { CKM_DES_ECB, 0, 0 }, .wrapping_key_gen_mech = { CKM_DES_KEY_GEN, 0, 0 }, }, { .name = "Wrap/Unwrap with DES CBC", .wrapping_mech = { CKM_DES_CBC, des_iv, sizeof(des_iv) }, .wrapping_key_gen_mech = { CKM_DES_KEY_GEN, 0, 0 }, }, { .name = "Wrap/Unwrap with DES CBC PAD", .wrapping_mech = { CKM_DES_CBC_PAD, des_iv, sizeof(des_iv) }, .wrapping_key_gen_mech = { CKM_DES_KEY_GEN, 0, 0 }, }, { .name = "Wrap/Unwrap with DES2 ECB", .wrapping_mech = { CKM_DES3_ECB, 0, 0 }, .wrapping_key_gen_mech = { CKM_DES2_KEY_GEN, 0, 0 }, }, { .name = "Wrap/Unwrap with DES2 CBC", .wrapping_mech = { CKM_DES3_CBC, des_iv, sizeof(des_iv) }, .wrapping_key_gen_mech = { CKM_DES2_KEY_GEN, 0, 0 }, }, { .name = "Wrap/Unwrap with DES2 CBC PAD", .wrapping_mech = { CKM_DES3_CBC_PAD, des_iv, sizeof(des_iv) }, .wrapping_key_gen_mech = { CKM_DES2_KEY_GEN, 0, 0 }, }, { .name = "Wrap/Unwrap with DES3 ECB", .wrapping_mech = { CKM_DES3_ECB, 0, 0 }, .wrapping_key_gen_mech = { CKM_DES3_KEY_GEN, 0, 0 }, }, { .name = "Wrap/Unwrap with DES3 CBC", .wrapping_mech = { CKM_DES3_CBC, des_iv, sizeof(des_iv) }, .wrapping_key_gen_mech = { CKM_DES3_KEY_GEN, 0, 0 }, }, { .name = "Wrap/Unwrap with DES3 CBC PAD", .wrapping_mech = { CKM_DES3_CBC_PAD, des_iv, sizeof(des_iv) }, .wrapping_key_gen_mech = { CKM_DES3_KEY_GEN, 0, 0 }, }, }; #define NUM_WRAPPING_TESTS sizeof(wrapping_tests) / \ sizeof(struct wrapping_mech_info) struct wrapped_mech_info { char *name; CK_MECHANISM wrapped_key_gen_mech; CK_ULONG rsa_modbits; CK_ULONG rsa_publ_exp_len; CK_BYTE rsa_publ_exp[4]; CK_ULONG sym_keylen; CK_BYTE *ec_params; CK_ULONG ec_params_len; CK_ULONG pqc_keyform; CK_MECHANISM operation_mech; }; struct wrapped_mech_info wrapped_key_tests[] = { { .name = "key type AES 128", .wrapped_key_gen_mech = { CKM_AES_KEY_GEN, 0, 0 }, .operation_mech = { CKM_AES_ECB, 0, 0 }, .sym_keylen = 16, }, { .name = "key type AES 192", .wrapped_key_gen_mech = { CKM_AES_KEY_GEN, 0, 0 }, .operation_mech = { CKM_AES_ECB, 0, 0 }, .sym_keylen = 24, }, { .name = "key type AES 256", .wrapped_key_gen_mech = { CKM_AES_KEY_GEN, 0, 0 }, .operation_mech = { CKM_AES_ECB, 0, 0 }, .sym_keylen = 32, }, { .name = "key type AES-XTS 128", .wrapped_key_gen_mech = { CKM_AES_XTS_KEY_GEN, 0, 0 }, .operation_mech = { CKM_AES_XTS, aes_iv, sizeof(aes_iv) }, .sym_keylen = 32, }, { .name = "key type AES-XTS 256", .wrapped_key_gen_mech = { CKM_AES_XTS_KEY_GEN, 0, 0 }, .operation_mech = { CKM_AES_XTS, aes_iv, sizeof(aes_iv) }, .sym_keylen = 64, }, { .name = "key type DES3", .wrapped_key_gen_mech = { CKM_DES3_KEY_GEN, 0, 0 }, .operation_mech = { CKM_DES3_ECB, 0, 0 }, }, { .name = "key type DES2", .wrapped_key_gen_mech = { CKM_DES2_KEY_GEN, 0, 0 }, .operation_mech = { CKM_DES3_ECB, 0, 0 }, }, { .name = "key type DES", .wrapped_key_gen_mech = { CKM_DES_KEY_GEN, 0, 0 }, .operation_mech = { CKM_DES_ECB, 0, 0 }, }, { .name = "key type GENERIC SECRET", .wrapped_key_gen_mech = { CKM_GENERIC_SECRET_KEY_GEN, 0, 0 }, .operation_mech = { CKM_SHA_1_HMAC, 0, 0 }, .sym_keylen = 32, }, { .name = "key type SHA-1 HMAC", .wrapped_key_gen_mech = { CKM_SHA_1_KEY_GEN, 0, 0 }, .operation_mech = { CKM_SHA_1_HMAC, 0, 0 }, .sym_keylen = 32, }, { .name = "key type RSA PKCS 512", .wrapped_key_gen_mech = { CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0 }, .operation_mech = { CKM_RSA_PKCS, 0, 0 }, .rsa_modbits = 512, .rsa_publ_exp_len = 3, .rsa_publ_exp = {0x01, 0x00, 0x01}, }, { .name = "key type RSA PKCS 1024", .wrapped_key_gen_mech = { CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0 }, .operation_mech = { CKM_RSA_PKCS, 0, 0 }, .rsa_modbits = 1024, .rsa_publ_exp_len = 3, .rsa_publ_exp = {0x01, 0x00, 0x01}, }, { .name = "key type RSA PKCS 2048", .wrapped_key_gen_mech = { CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0 }, .operation_mech = { CKM_RSA_PKCS, 0, 0 }, .rsa_modbits = 2048, .rsa_publ_exp_len = 3, .rsa_publ_exp = {0x01, 0x00, 0x01}, }, { .name = "key type EC", .wrapped_key_gen_mech = { CKM_EC_KEY_PAIR_GEN, 0, 0 }, .operation_mech = { CKM_ECDSA, 0, 0 }, .ec_params = prime256v1, .ec_params_len = sizeof(prime256v1), }, { .name = "key type EC-Edwards 25519", .wrapped_key_gen_mech = { CKM_EC_EDWARDS_KEY_PAIR_GEN, 0, 0 }, .operation_mech = { CKM_EDDSA, NULL, 0 }, .ec_params = ed25519, .ec_params_len = sizeof(ed25519), }, { .name = "key type EC-Edwards 448", .wrapped_key_gen_mech = { CKM_EC_EDWARDS_KEY_PAIR_GEN, 0, 0 }, .operation_mech = { CKM_EDDSA, &eddsa_param, sizeof(eddsa_param) }, .ec_params = ed448, .ec_params_len = sizeof(ed448), }, { .name = "key type EC-Montgomery 25519", .wrapped_key_gen_mech = { CKM_EC_MONTGOMERY_KEY_PAIR_GEN, 0, 0 }, .operation_mech = { CKM_ECDH1_DERIVE, &ecdh_param, sizeof(ecdh_param) }, .ec_params = curve25519, .ec_params_len = sizeof(curve25519), }, { .name = "key type EC-Edwards 448", .wrapped_key_gen_mech = { CKM_EC_MONTGOMERY_KEY_PAIR_GEN, 0, 0 }, .operation_mech = { CKM_ECDH1_DERIVE, &ecdh_param, sizeof(ecdh_param) }, .ec_params = curve448, .ec_params_len = sizeof(curve448), }, { .name = "key type IBM Dilithium R2 6-5", .wrapped_key_gen_mech = { CKM_IBM_DILITHIUM, 0, 0 }, .operation_mech = { CKM_IBM_DILITHIUM, 0, 0 }, .pqc_keyform = CK_IBM_DILITHIUM_KEYFORM_ROUND2_65, }, { .name = "key type IBM Dilithium R3 6-5", .wrapped_key_gen_mech = { CKM_IBM_DILITHIUM, 0, 0 }, .operation_mech = { CKM_IBM_DILITHIUM, 0, 0 }, .pqc_keyform = CK_IBM_DILITHIUM_KEYFORM_ROUND3_65, }, { .name = "key type IBM ML-DSA 44", .wrapped_key_gen_mech = { CKM_IBM_ML_DSA_KEY_PAIR_GEN, 0, 0 }, .operation_mech = { CKM_IBM_ML_DSA, 0, 0 }, .pqc_keyform = CKP_IBM_ML_DSA_44, }, { .name = "key type IBM ML-DSA 65", .wrapped_key_gen_mech = { CKM_IBM_ML_DSA_KEY_PAIR_GEN, 0, 0 }, .operation_mech = { CKM_IBM_ML_DSA, 0, 0 }, .pqc_keyform = CKP_IBM_ML_DSA_65, }, { .name = "key type IBM ML-DSA 87", .wrapped_key_gen_mech = { CKM_IBM_ML_DSA_KEY_PAIR_GEN, 0, 0 }, .operation_mech = { CKM_IBM_ML_DSA, 0, 0 }, .pqc_keyform = CKP_IBM_ML_DSA_87, }, { .name = "key type IBM ML-KEM 512 (using CKM_IBM_ML_KEM)", .wrapped_key_gen_mech = { CKM_IBM_ML_KEM_KEY_PAIR_GEN, 0, 0 }, .operation_mech = { CKM_IBM_ML_KEM, 0, 0 }, .pqc_keyform = CKP_IBM_ML_KEM_512, }, { .name = "key type IBM ML-KEM 768 (using CKM_IBM_ML_KEM)", .wrapped_key_gen_mech = { CKM_IBM_ML_KEM_KEY_PAIR_GEN, 0, 0 }, .operation_mech = { CKM_IBM_ML_KEM, 0, 0 }, .pqc_keyform = CKP_IBM_ML_KEM_768, }, { .name = "key type IBM ML-KEM 1024 (using CKM_IBM_ML_KEM)", .wrapped_key_gen_mech = { CKM_IBM_ML_KEM_KEY_PAIR_GEN, 0, 0 }, .operation_mech = { CKM_IBM_ML_KEM, 0, 0 }, .pqc_keyform = CKP_IBM_ML_KEM_1024, }, { .name = "key type IBM ML-KEM 512 (using CKM_IBM_ML_KEM_WITH_ECDH)", .wrapped_key_gen_mech = { CKM_IBM_ML_KEM_KEY_PAIR_GEN, 0, 0 }, .operation_mech = { CKM_IBM_ML_KEM_WITH_ECDH, 0, 0 }, .pqc_keyform = CKP_IBM_ML_KEM_512, }, { .name = "key type IBM ML-KEM 768 (using CKM_IBM_ML_KEM_WITH_ECDH)", .wrapped_key_gen_mech = { CKM_IBM_ML_KEM_KEY_PAIR_GEN, 0, 0 }, .operation_mech = { CKM_IBM_ML_KEM_WITH_ECDH, 0, 0 }, .pqc_keyform = CKP_IBM_ML_KEM_768, }, { .name = "key type IBM ML-KEM 1024 (using CKM_IBM_ML_KEM_WITH_ECDH)", .wrapped_key_gen_mech = { CKM_IBM_ML_KEM_KEY_PAIR_GEN, 0, 0 }, .operation_mech = { CKM_IBM_ML_KEM_WITH_ECDH, 0, 0 }, .pqc_keyform = CKP_IBM_ML_KEM_1024, }, { .name = "key type ML-DSA 44", .wrapped_key_gen_mech = { CKM_ML_DSA_KEY_PAIR_GEN, 0, 0 }, .operation_mech = { CKM_ML_DSA, 0, 0 }, .pqc_keyform = CKP_ML_DSA_44, }, { .name = "key type ML-DSA 65", .wrapped_key_gen_mech = { CKM_ML_DSA_KEY_PAIR_GEN, 0, 0 }, .operation_mech = { CKM_ML_DSA, 0, 0 }, .pqc_keyform = CKP_ML_DSA_65, }, { .name = "key type ML-DSA 87", .wrapped_key_gen_mech = { CKM_ML_DSA_KEY_PAIR_GEN, 0, 0 }, .operation_mech = { CKM_ML_DSA, 0, 0 }, .pqc_keyform = CKP_ML_DSA_87, }, { .name = "key type ML-KEM 512", .wrapped_key_gen_mech = { CKM_ML_KEM_KEY_PAIR_GEN, 0, 0 }, .operation_mech = { CKM_ML_KEM, 0, 0 }, .pqc_keyform = CKP_ML_KEM_512, }, { .name = "key type ML-KEM 768", .wrapped_key_gen_mech = { CKM_ML_KEM_KEY_PAIR_GEN, 0, 0 }, .operation_mech = { CKM_ML_KEM, 0, 0 }, .pqc_keyform = CKP_ML_KEM_768, }, { .name = "key type ML-KEM 1024", .wrapped_key_gen_mech = { CKM_ML_KEM_KEY_PAIR_GEN, 0, 0 }, .operation_mech = { CKM_ML_KEM, 0, 0 }, .pqc_keyform = CKP_ML_KEM_1024, }, }; #define NUM_WRAPPED_KEY_TESTS sizeof(wrapped_key_tests) / \ sizeof(struct wrapped_mech_info) CK_SLOT_ID slot_id1 = 1, slot_id2 = 2; CK_SESSION_HANDLE session1 = CK_INVALID_HANDLE; CK_SESSION_HANDLE session2 = CK_INVALID_HANDLE; CK_OBJECT_HANDLE sym_wrap_key1 = CK_INVALID_HANDLE; CK_OBJECT_HANDLE sym_wrap_key2 = CK_INVALID_HANDLE; CK_OBJECT_HANDLE publ_wrap_key1 = CK_INVALID_HANDLE; CK_OBJECT_HANDLE publ_wrap_key2 = CK_INVALID_HANDLE; CK_OBJECT_HANDLE priv_wrap_key2 = CK_INVALID_HANDLE; CK_RV do_perform_operation(CK_MECHANISM *mech, CK_SLOT_ID slot1, CK_SESSION_HANDLE sess1, CK_OBJECT_HANDLE sym_key1, CK_OBJECT_HANDLE publ_key1, CK_OBJECT_HANDLE priv_key1, CK_SLOT_ID slot2, CK_SESSION_HANDLE sess2, CK_OBJECT_HANDLE sym_key2, CK_OBJECT_HANDLE priv_key2) { CK_RV rc; CK_MECHANISM_INFO mech_info; CK_BBOOL encr = FALSE, decr = FALSE, sign = FALSE, verify = FALSE; CK_BBOOL encaps = FALSE, decaps = FALSE; CK_BBOOL derive = FALSE; CK_ULONG input_size, cipher_size, output_size; CK_BYTE input_data[32] = { 0x00,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}; CK_BYTE cipher_data[OPENSSL_RSA_MAX_MODULUS_BITS / 8]; CK_BYTE output_data[8192]; CK_OBJECT_HANDLE encr_key, decr_key, sign_key, verify_key; CK_IBM_ML_KEM_PARAMS ml_kem_params; CK_IBM_ML_KEM_WITH_ECDH_PARAMS ml_kem_ecdh_params; CK_ECDH1_DERIVE_PARAMS derive_params; CK_OBJECT_CLASS class = CKO_SECRET_KEY; CK_KEY_TYPE key_type = CKK_AES; CK_BBOOL true = CK_TRUE; CK_BBOOL false = CK_FALSE; CK_ULONG secret_key_len = 32; CK_ATTRIBUTE derive_tmpl[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &key_type, sizeof(key_type)}, {CKA_SENSITIVE, &false, sizeof(false)}, {CKA_VALUE_LEN, &secret_key_len, sizeof(secret_key_len)}, {CKA_ENCRYPT, &true, sizeof(true)}, {CKA_DECRYPT, &true, sizeof(true)}, {CKA_SIGN, &true, sizeof(true)}, {CKA_VERIFY, &true, sizeof(true)}, }; CK_ULONG derive_tmpl_len = sizeof(derive_tmpl) / sizeof(CK_ATTRIBUTE); CK_OBJECT_HANDLE key1 = CK_INVALID_HANDLE; CK_OBJECT_HANDLE key2 = CK_INVALID_HANDLE; CK_MECHANISM kem_mech; CK_MECHANISM ecdh_mech; CK_BYTE ec_point[64]; CK_ATTRIBUTE ec_point_attr = { CKA_EC_POINT, ec_point, sizeof(ec_point) }; CK_MECHANISM aes_ebc_mech = { CKM_AES_ECB, NULL, 0 }; CK_OBJECT_HANDLE ec_publ_key1 = CK_INVALID_HANDLE; CK_OBJECT_HANDLE ec_priv_key1 = CK_INVALID_HANDLE; CK_OBJECT_HANDLE ec_publ_key2 = CK_INVALID_HANDLE; CK_OBJECT_HANDLE ec_priv_key2 = CK_INVALID_HANDLE; CK_BYTE pubkey1_value[256]; CK_BYTE pubkey2_value[256]; CK_ATTRIBUTE extr_tmpl1[] = { {CKA_EC_POINT, pubkey1_value, sizeof(pubkey1_value)}, }; CK_ULONG extr_tmpl1_len = sizeof(extr_tmpl1)/sizeof(CK_ATTRIBUTE); CK_ATTRIBUTE extr_tmpl2[] = { {CKA_EC_POINT, pubkey2_value, sizeof(pubkey2_value)}, }; CK_ULONG extr_tmpl2_len = sizeof(extr_tmpl2)/sizeof(CK_ATTRIBUTE); /* Check if Encrypt/Decrypt or Sign/Verify is supported */ rc = funcs->C_GetMechanismInfo(slot1, mech->mechanism, &mech_info); if (rc != CKR_OK) { testcase_error("C_GetMechanismInfo on slot %lu, rc=%s", slot1, p11_get_ckr(rc)); return rc; } encr = (mech_info.flags & CKF_ENCRYPT) != 0; sign = (mech_info.flags & CKF_SIGN) != 0; derive = (mech_info.flags & CKF_DERIVE) != 0; encaps = (mech_info.flags & CKF_ENCAPSULATE) != 0; rc = funcs->C_GetMechanismInfo(slot2, mech->mechanism, &mech_info); if (rc != CKR_OK) { testcase_error("C_GetMechanismInfo on slot %lu, rc=%s", slot2, p11_get_ckr(rc)); return rc; } decr = (mech_info.flags & CKF_DECRYPT) != 0; verify = (mech_info.flags & CKF_VERIFY) != 0; derive &= ((mech_info.flags & CKF_DERIVE) != 0); decaps = (mech_info.flags & CKF_DECAPSULATE) != 0; if (encr && decr) { /* Perform Encrypt/Decrypt operation */ switch (mech->mechanism) { case CKM_AES_ECB: case CKM_AES_XTS: input_size = 16; encr_key = sym_key1; decr_key = sym_key2; break; case CKM_DES_ECB: case CKM_DES3_ECB: input_size = 8; encr_key = sym_key1; decr_key = sym_key2; break; case CKM_RSA_PKCS: input_size = 16; encr_key = publ_key1; decr_key = priv_key2; break; default: testcase_error("Operation not supported by testcase"); return CKR_FUNCTION_NOT_SUPPORTED; } rc = funcs->C_EncryptInit(sess1, mech, encr_key); if (rc != CKR_OK) { testcase_error("C_EncryptInit on slot %lu rc=%s", slot1, p11_get_ckr(rc)); return rc; } cipher_size = sizeof(cipher_data); rc = funcs->C_Encrypt(sess1, input_data, input_size, cipher_data, &cipher_size); if (rc != CKR_OK) { testcase_error("C_Encrypt on slot %lu rc=%s", slot1, p11_get_ckr(rc)); return rc; } rc = funcs->C_DecryptInit(sess2, mech, decr_key); if (rc != CKR_OK) { testcase_error("C_DecryptInit on slot %lu rc=%s", slot2, p11_get_ckr(rc)); return rc; } output_size = sizeof(output_data); rc = funcs->C_Decrypt(sess2, cipher_data, cipher_size, output_data, &output_size); if (rc != CKR_OK) { testcase_error("C_Decrypt on slot %lu rc=%s", slot2, p11_get_ckr(rc)); return rc; } if (output_size != input_size) { testcase_error("Decrypted data has different size than original " "data: orig: %lu decr: %lu", input_size, output_size); return CKR_FUNCTION_FAILED; } if (memcmp(input_data, output_data, input_size) != 0) { testcase_error("Decrypted data is different than original data"); return CKR_FUNCTION_FAILED; } } else if (sign && verify) { /* Perform Sign/Verify operation */ switch (mech->mechanism) { case CKM_SHA_1_HMAC: sign_key = sym_key2; verify_key = sym_key1; input_size = 20; break; case CKM_RSA_PKCS: case CKM_ECDSA: case CKM_EDDSA: case CKM_IBM_DILITHIUM: case CKM_IBM_ML_DSA: case CKM_ML_DSA: sign_key = priv_key2; verify_key = publ_key1; input_size = 20; break; default: testcase_error("Operation not supported by testcase"); return CKR_FUNCTION_NOT_SUPPORTED; } rc = funcs->C_SignInit(sess2, mech, sign_key); if (rc != CKR_OK) { testcase_error("C_SignInit on slot %lu rc=%s", slot2, p11_get_ckr(rc)); return rc; } output_size = sizeof(output_data); rc = funcs->C_Sign(sess2, input_data, input_size, output_data, &output_size); if (rc != CKR_OK) { if ((mech->mechanism == CKM_IBM_DILITHIUM || mech->mechanism == CKM_IBM_ML_DSA || mech->mechanism == CKM_ML_DSA) && rc == CKR_KEY_SIZE_RANGE) { testcase_skip("IBM Dilithium/ML-DSA key form not supported by slot %lu", slot2); return CKR_OK; } testcase_error("C_Sign on slot %lu rc=%s", slot2, p11_get_ckr(rc)); return rc; } rc = funcs->C_VerifyInit(sess1, mech, verify_key); if (rc != CKR_OK) { testcase_error("C_VerifyInit on slot %lu rc=%s", slot1, p11_get_ckr(rc)); return rc; } rc = funcs->C_Verify(sess1, input_data, input_size, output_data, output_size); if (rc != CKR_OK) { testcase_error("C_Verify on slot %lu rc=%s", slot1, p11_get_ckr(rc)); return rc; } } else if (derive) { /* Perform Derive/KEM operation */ switch (mech->mechanism) { case CKM_IBM_ML_KEM: kem_mech.mechanism = mech->mechanism; kem_mech.pParameter = &ml_kem_params; kem_mech.ulParameterLen = sizeof(ml_kem_params); /* Perform encapsulation with public key */ memset(&ml_kem_params, 0, sizeof(ml_kem_params)); ml_kem_params.ulVersion = CK_IBM_ML_KEM_VERSION; ml_kem_params.mode = CK_IBM_ML_KEM_ENCAPSULATE; ml_kem_params.ulCipherLen = sizeof(output_data); ml_kem_params.pCipher = output_data; ml_kem_params.kdf = CKD_NULL; ml_kem_params.pSharedData = NULL;; ml_kem_params.ulSharedDataLen = 0; ml_kem_params.bPrepend = CK_FALSE; ml_kem_params.hSecret = CK_INVALID_HANDLE; /* Encapsulation */ rc = funcs->C_DeriveKey(sess1, &kem_mech, publ_key1, derive_tmpl, derive_tmpl_len, &key1); if (rc != CKR_OK) { testcase_error("C_DeriveKey (encapsulation) on slot %lu rc=%s", slot1, p11_get_ckr(rc)); return rc; } output_size = ml_kem_params.ulCipherLen; /* Perform Decapsulation with private key */ memset(&ml_kem_params, 0, sizeof(ml_kem_params)); ml_kem_params.ulVersion = CK_IBM_ML_KEM_VERSION; ml_kem_params.mode = CK_IBM_ML_KEM_DECAPSULATE; ml_kem_params.ulCipherLen = output_size; ml_kem_params.kdf = CKD_NULL; ml_kem_params.pCipher = output_data; ml_kem_params.pSharedData = NULL;; ml_kem_params.ulSharedDataLen = 0; ml_kem_params.bPrepend = CK_FALSE; ml_kem_params.hSecret = CK_INVALID_HANDLE; rc = funcs->C_DeriveKey(sess2, &kem_mech, priv_key2, derive_tmpl, derive_tmpl_len, &key2); if (rc != CKR_OK) { testcase_error("C_DeriveKey (decapsulation) on slot %lu rc=%s", slot1, p11_get_ckr(rc)); funcs->C_DestroyObject(sess1, key1); return rc; } rc = do_perform_operation(&aes_ebc_mech, slot1, sess1, key1, CK_INVALID_HANDLE, CK_INVALID_HANDLE, slot2, sess2, key2, CK_INVALID_HANDLE); funcs->C_DestroyObject(sess2, key2); if (rc != CKR_OK) return rc; break; case CKM_IBM_ML_KEM_WITH_ECDH: /* Generate EC key pairs on both slots */ rc = generate_EC_KeyPair(sess1, CKM_EC_KEY_PAIR_GEN, prime256v1, sizeof(prime256v1), &ec_publ_key1, &ec_priv_key1, CK_FALSE); if (rc != CKR_OK) { testcase_error("generate_EC_KeyPair on slot %lu rc=%s", slot1, p11_get_ckr(rc)); return rc; } rc = funcs->C_GetAttributeValue(sess1, ec_publ_key1, extr_tmpl1, extr_tmpl1_len); if (rc != CKR_OK) { testcase_error("C_GetAttributeValue: on slot %lu rc=%s", slot1, p11_get_ckr(rc)); funcs->C_DestroyObject(sess1, ec_priv_key1); funcs->C_DestroyObject(sess1, ec_publ_key1); return rc; } rc = generate_EC_KeyPair(sess2, CKM_EC_KEY_PAIR_GEN, prime256v1, sizeof(prime256v1), &ec_publ_key2, &ec_priv_key2, CK_FALSE); if (rc != CKR_OK) { testcase_error("generate_EC_KeyPair on slot %lu rc=%s", slot2, p11_get_ckr(rc)); funcs->C_DestroyObject(sess1, ec_priv_key1); funcs->C_DestroyObject(sess1, ec_publ_key1); return rc; } rc = funcs->C_GetAttributeValue(sess2, ec_publ_key2, extr_tmpl2, extr_tmpl2_len); if (rc != CKR_OK) { testcase_error("C_GetAttributeValue: on slot %lu rc=%s", slot2, p11_get_ckr(rc)); funcs->C_DestroyObject(sess1, ec_priv_key1); funcs->C_DestroyObject(sess1, ec_publ_key1); funcs->C_DestroyObject(sess2, ec_priv_key2); funcs->C_DestroyObject(sess2, ec_publ_key2); return rc; } kem_mech.mechanism = mech->mechanism; kem_mech.pParameter = &ml_kem_ecdh_params; kem_mech.ulParameterLen = sizeof(ml_kem_ecdh_params); /* Perform encapsulation with public key */ memset(&ml_kem_ecdh_params, 0, sizeof(ml_kem_ecdh_params)); ml_kem_ecdh_params.mode = CK_IBM_ML_KEM_ENCAPSULATE; ml_kem_ecdh_params.ulCipherLen = sizeof(output_data); ml_kem_ecdh_params.pCipher = output_data; ml_kem_ecdh_params.kdf = CKD_IBM_HYBRID_SHA256_KDF; ml_kem_ecdh_params.pSharedData = NULL; ml_kem_ecdh_params.ulSharedDataLen = 0; ml_kem_ecdh_params.hECPrivateKey = ec_priv_key1; ml_kem_ecdh_params.pPublicData = extr_tmpl2[0].pValue; ml_kem_ecdh_params.ulPublicDataLen = extr_tmpl2[0].ulValueLen; /* Encapsulation */ rc = funcs->C_DeriveKey(sess1, &kem_mech, publ_key1, derive_tmpl, derive_tmpl_len, &key1); if (rc != CKR_OK) { testcase_error("C_DeriveKey (encapsulation) on slot %lu rc=%s", slot1, p11_get_ckr(rc)); funcs->C_DestroyObject(sess1, ec_priv_key1); funcs->C_DestroyObject(sess1, ec_publ_key1); funcs->C_DestroyObject(sess2, ec_priv_key2); funcs->C_DestroyObject(sess2, ec_publ_key2); return rc; } output_size = ml_kem_ecdh_params.ulCipherLen; /* Perform Decapsulation with private key */ memset(&ml_kem_ecdh_params, 0, sizeof(ml_kem_ecdh_params)); ml_kem_ecdh_params.mode = CK_IBM_ML_KEM_DECAPSULATE; ml_kem_ecdh_params.ulCipherLen = output_size; ml_kem_ecdh_params.pCipher = output_data; ml_kem_ecdh_params.kdf = CKD_IBM_HYBRID_SHA256_KDF; ml_kem_ecdh_params.pSharedData = NULL; ml_kem_ecdh_params.ulSharedDataLen = 0; ml_kem_ecdh_params.hECPrivateKey = ec_priv_key2; ml_kem_ecdh_params.pPublicData = extr_tmpl1[0].pValue; ml_kem_ecdh_params.ulPublicDataLen = extr_tmpl1[0].ulValueLen; rc = funcs->C_DeriveKey(sess2, &kem_mech, priv_key2, derive_tmpl, derive_tmpl_len, &key2); if (rc != CKR_OK) { testcase_error("C_DeriveKey (decapsulation) on slot %lu rc=%s", slot1, p11_get_ckr(rc)); funcs->C_DestroyObject(sess1, key1); funcs->C_DestroyObject(sess1, ec_priv_key1); funcs->C_DestroyObject(sess1, ec_publ_key1); funcs->C_DestroyObject(sess2, ec_priv_key2); funcs->C_DestroyObject(sess2, ec_publ_key2); return rc; } rc = do_perform_operation(&aes_ebc_mech, slot1, sess1, key1, CK_INVALID_HANDLE, CK_INVALID_HANDLE, slot2, sess2, key2, CK_INVALID_HANDLE); funcs->C_DestroyObject(sess2, key2); funcs->C_DestroyObject(sess1, ec_priv_key1); funcs->C_DestroyObject(sess1, ec_publ_key1); funcs->C_DestroyObject(sess2, ec_priv_key2); funcs->C_DestroyObject(sess2, ec_publ_key2); if (rc != CKR_OK) return rc; break; case CKM_ECDH1_DERIVE: if (mech->ulParameterLen != sizeof(CK_ECDH1_DERIVE_PARAMS) || mech->pParameter == NULL) { testcase_error("ECDH mechanism param invalid"); return CKR_MECHANISM_PARAM_INVALID; } memcpy(&derive_params, mech->pParameter, sizeof(derive_params)); rc = funcs->C_GetAttributeValue(sess1, publ_key1, &ec_point_attr, 1); if (rc != CKR_OK) { testcase_error("C_GetAttributeValue on slot %lu rc=%s", slot1, p11_get_ckr(rc)); return rc; } derive_params.kdf = CKD_SHA256_KDF; derive_params.pPublicData = ec_point_attr.pValue; derive_params.ulPublicDataLen = ec_point_attr.ulValueLen; ecdh_mech.mechanism = mech->mechanism; ecdh_mech.pParameter = &derive_params; ecdh_mech.ulParameterLen = sizeof(derive_params); rc = funcs->C_DeriveKey(sess1, &ecdh_mech, priv_key1, derive_tmpl, derive_tmpl_len, &key1); if (rc != CKR_OK) { testcase_error("C_DeriveKey on slot %lu rc=%s", slot2, p11_get_ckr(rc)); return rc; } rc = funcs->C_DeriveKey(sess2, &ecdh_mech, priv_key2, derive_tmpl, derive_tmpl_len, &key2); if (rc != CKR_OK) { testcase_error("C_DeriveKey on slot %lu rc=%s", slot2, p11_get_ckr(rc)); funcs->C_DestroyObject(sess2, key1); return rc; } rc = do_perform_operation(&aes_ebc_mech, slot1, sess1, key1, CK_INVALID_HANDLE, CK_INVALID_HANDLE, slot2, sess2, key2, CK_INVALID_HANDLE); funcs->C_DestroyObject(sess2, key1); funcs->C_DestroyObject(sess2, key2); if (rc != CKR_OK) return rc; break; default: testcase_error("Operation not supported by testcase"); return CKR_FUNCTION_NOT_SUPPORTED; } } else if (encaps && decaps) { /* Perform Encaps/Decaps/KEM operation */ switch (mech->mechanism) { case CKM_ML_KEM: kem_mech.mechanism = mech->mechanism; kem_mech.pParameter = NULL; kem_mech.ulParameterLen = 0; /* Perform encapsulation with public key */ output_size = sizeof(output_data); rc = funcs3_2->C_EncapsulateKey(sess1, &kem_mech, publ_key1, derive_tmpl, derive_tmpl_len, output_data, &output_size, &key1); if (rc != CKR_OK) { testcase_error("C_EncapsulateKey on slot %lu rc=%s", slot1, p11_get_ckr(rc)); return rc; } /* Perform Decapsulation with private key */ rc = funcs3_2->C_DecapsulateKey(sess2, &kem_mech, priv_key2, derive_tmpl, derive_tmpl_len, output_data, output_size, &key2); if (rc != CKR_OK) { testcase_error("C_DecapsulateKey on slot %lu rc=%s", slot1, p11_get_ckr(rc)); return rc; } rc = do_perform_operation(&aes_ebc_mech, slot1, sess1, key1, CK_INVALID_HANDLE, CK_INVALID_HANDLE, slot2, sess2, key2, CK_INVALID_HANDLE); funcs->C_DestroyObject(sess2, key2); if (rc != CKR_OK) return rc; break; default: testcase_error("Operation not supported by testcase"); return CKR_FUNCTION_NOT_SUPPORTED; } } else { testcase_error("Neither Encrypt/Decrypt, Sign/Verify, nor derive supported"); return CKR_FUNCTION_NOT_SUPPORTED; } return CKR_OK; } CK_RV do_wrap_key_test(struct wrapped_mech_info *tsuite, CK_MECHANISM *wrap_mech) { CK_RV loc_rc, rc = CKR_OK; CK_OBJECT_HANDLE publ_key = CK_INVALID_HANDLE; CK_OBJECT_HANDLE priv_key = CK_INVALID_HANDLE; CK_OBJECT_HANDLE sym_key = CK_INVALID_HANDLE; CK_OBJECT_HANDLE unwrapped_key = CK_INVALID_HANDLE; CK_BYTE *wrapped_key = NULL; CK_ULONG wrapped_key_size = 0; CK_OBJECT_CLASS key_class; CK_KEY_TYPE key_type; CK_BBOOL ck_true = CK_TRUE; CK_BBOOL ck_false = CK_FALSE; CK_ULONG key_len, unwrapped_keylen; CK_ATTRIBUTE unwrap_tmpl[] = { {CKA_CLASS, &key_class, sizeof(CK_OBJECT_CLASS)}, {CKA_KEY_TYPE, &key_type, sizeof(CK_KEY_TYPE)}, {CKA_DERIVE, &ck_false, sizeof(ck_false)}, {CKA_VALUE_LEN, &key_len, sizeof(CK_ULONG)}, {0, NULL, 0} }; CK_ULONG unwrap_tmpl_num; CK_ATTRIBUTE getattr_tmpl[] = { {CKA_VALUE_LEN, &unwrapped_keylen, sizeof(CK_ULONG)} }; char *s = NULL; CK_RSA_PKCS_OAEP_PARAMS *oaep; testcase_begin("Wrap/Unwrap of %s with %s", tsuite->name, mech_to_str(wrap_mech->mechanism)); if (!mech_supported(slot_id1, tsuite->wrapped_key_gen_mech.mechanism)) { testcase_skip("Slot %u doesn't support %s (0x%x)", (unsigned int)slot_id1, mech_to_str(tsuite->wrapped_key_gen_mech.mechanism), (unsigned int)tsuite->wrapped_key_gen_mech.mechanism); goto testcase_cleanup; } if (!mech_supported(slot_id2, tsuite->wrapped_key_gen_mech.mechanism)) { testcase_skip("Slot %u doesn't support %s (0x%x)", (unsigned int)slot_id2, mech_to_str(tsuite->wrapped_key_gen_mech.mechanism), (unsigned int)tsuite->wrapped_key_gen_mech.mechanism); goto testcase_cleanup; } if (!mech_supported(slot_id1, tsuite->operation_mech.mechanism)) { testcase_skip("Slot %u doesn't support %s (0x%x)", (unsigned int)slot_id1, mech_to_str(tsuite->operation_mech.mechanism), (unsigned int)tsuite->operation_mech.mechanism); goto testcase_cleanup; } if (!mech_supported(slot_id2, tsuite->operation_mech.mechanism)) { testcase_skip("Slot %u doesn't support %s (0x%x)", (unsigned int)slot_id2, mech_to_str(tsuite->operation_mech.mechanism), (unsigned int)tsuite->operation_mech.mechanism); goto testcase_cleanup; } if (is_ep11_token(slot_id2) && wrap_mech->mechanism == CKM_AES_CBC && ((tsuite->wrapped_key_gen_mech.mechanism == CKM_AES_KEY_GEN && tsuite->sym_keylen == 24) || tsuite->wrapped_key_gen_mech.mechanism == CKM_DES3_KEY_GEN)) { testcase_skip("EP11 token in slot %lu doesn't support to unwrap " "AES-192 or DES3 keys with CKM_AES_CBC", slot_id2); goto testcase_cleanup; } if (wrap_mech->mechanism == CKM_AES_KEY_WRAP && tsuite->wrapped_key_gen_mech.mechanism == CKM_DES_KEY_GEN) { testcase_skip("Mechanism CKM_AES_KEY_WRAP can not wrap DES keys " "(min 16 bytes required)"); goto testcase_cleanup; } if (wrap_mech->mechanism == CKM_AES_KEY_WRAP && (tsuite->wrapped_key_gen_mech.mechanism == CKM_GENERIC_SECRET_KEY_GEN || tsuite->wrapped_key_gen_mech.mechanism == CKM_SHA_1_KEY_GEN) && tsuite->sym_keylen < 16) { testcase_skip("Mechanism CKM_AES_KEY_WRAP can not wrap generic secret " "keys of size %lu (min 16 bytes required)", tsuite->sym_keylen); goto testcase_cleanup; } /* Generate the to be wrapped key in slot 1 */ switch (tsuite->wrapped_key_gen_mech.mechanism) { case CKM_RSA_PKCS_KEY_PAIR_GEN: if (p11_ahex_dump(&s, tsuite->rsa_publ_exp, tsuite->rsa_publ_exp_len) == NULL) { testcase_error("p11_ahex_dump() failed"); rc = CKR_FUNCTION_FAILED; goto testcase_cleanup; } if (tsuite->rsa_modbits > 4096 && !rsa8k) { testcase_skip("Tests with modbits='%lu' are not enabled", tsuite->rsa_modbits); goto testcase_cleanup; } if (!keysize_supported(slot_id1, tsuite->wrapped_key_gen_mech.mechanism, tsuite->rsa_modbits)) { testcase_skip("Token in slot %lu cannot be used with modbits='%lu'", slot_id1, tsuite->rsa_modbits); goto testcase_cleanup; } if (!keysize_supported(slot_id2, tsuite->wrapped_key_gen_mech.mechanism, tsuite->rsa_modbits)) { testcase_skip("Token in slot %lu cannot be used with modbits='%lu'", slot_id2, tsuite->rsa_modbits); goto testcase_cleanup; } if (is_ep11_token(slot_id1) || is_ep11_token(slot_id2)) { if (!is_valid_ep11_pubexp(tsuite->rsa_publ_exp, tsuite->rsa_publ_exp_len)) { testcase_skip("EP11 Token in cannot be used with publ_exp.='%s'", s); goto testcase_cleanup; } } if (is_cca_token(slot_id1) || is_cca_token(slot_id2)) { if (!is_valid_cca_pubexp(tsuite->rsa_publ_exp, tsuite->rsa_publ_exp_len)) { testcase_skip("CCA Token in scannot be used with publ_exp.='%s'", s); goto testcase_cleanup; } } if (is_soft_token(slot_id1) || is_soft_token(slot_id2)) { if (!is_valid_soft_pubexp(tsuite->rsa_publ_exp, tsuite->rsa_publ_exp_len)) { testcase_skip("Soft Token in scannot be used with publ_exp.='%s'", s); goto testcase_cleanup; } } if (is_tpm_token(slot_id1) || is_tpm_token(slot_id2)) { if (!is_valid_tpm_pubexp(tsuite->rsa_publ_exp, tsuite->rsa_publ_exp_len) || !is_valid_tpm_modbits(tsuite->rsa_modbits)) { testcase_skip("TPM Token cannot " "be used with publ_exp.='%s'", s); goto testcase_cleanup; } } if (is_icsf_token(slot_id1) || is_icsf_token(slot_id2)) { if (!is_valid_icsf_pubexp(tsuite->rsa_publ_exp, tsuite->rsa_publ_exp_len) || tsuite->rsa_modbits < 1024) { testcase_skip("ICSF Token cannot be used with publ_exp='%s'.", s); goto testcase_cleanup; } } rc = generate_RSA_PKCS_KeyPair(session1, CKM_RSA_PKCS_KEY_PAIR_GEN, tsuite->rsa_modbits, tsuite->rsa_publ_exp, tsuite->rsa_publ_exp_len, &publ_key, &priv_key); break; case CKM_AES_KEY_GEN: case CKM_AES_XTS_KEY_GEN: if ((is_ep11_token(slot_id1) || is_ep11_token(slot_id2) || is_cca_token(slot_id1) || is_cca_token(slot_id2)) && tsuite->wrapped_key_gen_mech.mechanism == CKM_AES_XTS_KEY_GEN) { testcase_skip("Skipping as AES XTS is supported only with protected keys"); rc = CKR_OK; goto testcase_cleanup; } rc = generate_AESKey(session1, tsuite->sym_keylen, CK_TRUE, &tsuite->wrapped_key_gen_mech, &sym_key); break; case CKM_DES3_KEY_GEN: case CKM_DES2_KEY_GEN: case CKM_DES_KEY_GEN: rc = funcs->C_GenerateKey(session1, &tsuite->wrapped_key_gen_mech, NULL, 0, &sym_key); break; case CKM_GENERIC_SECRET_KEY_GEN: case CKM_SHA_1_KEY_GEN: rc = generate_SecretKey(session1, tsuite->sym_keylen, &tsuite->wrapped_key_gen_mech, &sym_key); break; case CKM_EC_KEY_PAIR_GEN: case CKM_EC_EDWARDS_KEY_PAIR_GEN: case CKM_EC_MONTGOMERY_KEY_PAIR_GEN: rc = generate_EC_KeyPair(session1, tsuite->wrapped_key_gen_mech.mechanism, tsuite->ec_params, tsuite->ec_params_len, &publ_key, &priv_key, CK_TRUE); // must be extractable for Wrap/Unwrap break; case CKM_IBM_DILITHIUM: rc = generate_Dilithium_KeyPair(session1, tsuite->pqc_keyform, &publ_key, &priv_key, CK_TRUE); // must be extractable for Wrap/Unwrap if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("generate to be wrapped key %s with mech %s (%u) in " "slot %lu is not supported", tsuite->name, mech_to_str(tsuite->wrapped_key_gen_mech.mechanism), (unsigned int)tsuite->wrapped_key_gen_mech.mechanism, slot_id1); rc = CKR_OK; goto testcase_cleanup; } break; case CKM_IBM_ML_DSA_KEY_PAIR_GEN: rc = generate_IBM_ML_DSA_KeyPair(session1, tsuite->pqc_keyform, &publ_key, &priv_key, CK_TRUE); // must be extractable for Wrap/Unwrap if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("generate to be wrapped key %s with mech %s (%u) in " "slot %lu is not supported", tsuite->name, mech_to_str(tsuite->wrapped_key_gen_mech.mechanism), (unsigned int)tsuite->wrapped_key_gen_mech.mechanism, slot_id1); rc = CKR_OK; goto testcase_cleanup; } break; case CKM_IBM_ML_KEM_KEY_PAIR_GEN: rc = generate_IBM_ML_KEM_KeyPair(session1, tsuite->pqc_keyform, &publ_key, &priv_key, CK_TRUE); // must be extractable for Wrap/Unwrap if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("generate to be wrapped key %s with mech %s (%u) in " "slot %lu is not supported", tsuite->name, mech_to_str(tsuite->wrapped_key_gen_mech.mechanism), (unsigned int)tsuite->wrapped_key_gen_mech.mechanism, slot_id1); rc = CKR_OK; goto testcase_cleanup; } break; case CKM_ML_DSA_KEY_PAIR_GEN: rc = generate_ML_DSA_KeyPair(session1, tsuite->pqc_keyform, &publ_key, &priv_key, CK_TRUE); // must be extractable for Wrap/Unwrap if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("generate to be wrapped key %s with mech %s (%u) in " "slot %lu is not supported", tsuite->name, mech_to_str(tsuite->wrapped_key_gen_mech.mechanism), (unsigned int)tsuite->wrapped_key_gen_mech.mechanism, slot_id1); rc = CKR_OK; goto testcase_cleanup; } break; case CKM_ML_KEM_KEY_PAIR_GEN: rc = generate_ML_KEM_KeyPair(session1, tsuite->pqc_keyform, &publ_key, &priv_key, CK_TRUE); // must be extractable for Wrap/Unwrap if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("generate to be wrapped key %s with mech %s (%u) in " "slot %lu is not supported", tsuite->name, mech_to_str(tsuite->wrapped_key_gen_mech.mechanism), (unsigned int)tsuite->wrapped_key_gen_mech.mechanism, slot_id1); rc = CKR_OK; goto testcase_cleanup; } break; default: testcase_error("Testcase does not support %s (%u)", mech_to_str(tsuite->wrapped_key_gen_mech.mechanism), (unsigned int)tsuite->wrapped_key_gen_mech.mechanism); goto testcase_cleanup; } if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("generate to be wrapped key with mech %s (%u) in slot " "%lu is not allowed by policy", mech_to_str(tsuite->wrapped_key_gen_mech.mechanism), (unsigned int)tsuite->wrapped_key_gen_mech.mechanism, slot_id1); rc = CKR_OK; goto testcase_cleanup; } if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("generate to be wrapped key of the key size with " "mech %s (%u) in slot %lu is not supported", mech_to_str(tsuite->wrapped_key_gen_mech.mechanism), (unsigned int)tsuite->wrapped_key_gen_mech.mechanism, slot_id1); rc = CKR_OK; goto testcase_cleanup; } testcase_error("generate to be wrapped key with mech %s (%u) in slot " "%lu failed, rc=%s", mech_to_str(tsuite->wrapped_key_gen_mech.mechanism), (unsigned int)tsuite->wrapped_key_gen_mech.mechanism, slot_id1, p11_get_ckr(rc)); goto testcase_cleanup; } /* Test the key with a crypto operation on slot 1 */ rc = do_perform_operation(&tsuite->operation_mech, slot_id1, session1, sym_key, publ_key, priv_key, slot_id1, session1, sym_key, priv_key); if (rc != CKR_OK) goto testcase_cleanup; /* Wrap the key on slot 1 */ do_wrap: rc = funcs->C_WrapKey(session1, wrap_mech, sym_wrap_key1 != CK_INVALID_HANDLE ? sym_wrap_key1 : publ_wrap_key1, sym_key != CK_INVALID_HANDLE ? sym_key : priv_key, wrapped_key, &wrapped_key_size); if (rc != CKR_OK) { if (rc == CKR_KEY_NOT_WRAPPABLE || rc == CKR_WRAPPING_KEY_TYPE_INCONSISTENT) { testcase_skip("Key not wrappable"); rc = CKR_OK; goto testcase_cleanup; } if (rc == CKR_KEY_SIZE_RANGE || rc == CKR_WRAPPING_KEY_SIZE_RANGE) { testcase_skip("Key size not supported"); rc = CKR_OK; goto testcase_cleanup; } if (rc == CKR_MECHANISM_PARAM_INVALID && wrap_mech->mechanism == CKM_RSA_PKCS_OAEP) { oaep = (CK_RSA_PKCS_OAEP_PARAMS *)wrap_mech->pParameter; if (is_cca_token(slot_id1) && oaep->source == CKZ_DATA_SPECIFIED) { testcase_skip("CCA does not support RSA OAEP with source data"); rc = CKR_OK; goto testcase_cleanup; } if (is_cca_token(slot_id1) && oaep->hashAlg != CKM_SHA_1 && oaep->hashAlg != CKM_SHA256) { testcase_skip("CCA does not support RSA OAEP with a hash other " "than SHA1 or SHA256"); rc = CKR_OK; goto testcase_cleanup; } if (is_ep11_token(slot_id1) && oaep->hashAlg != CKM_SHA_1 && oaep->mgf != CKG_MGF1_SHA1) { testcase_skip("EP11 may not support RSA OAEP with a hash other " "than SHA1 on older firmware levels"); rc = CKR_OK; goto testcase_cleanup; } } if (rc == CKR_ARGUMENTS_BAD) { if (is_ep11_token(slot_id1) && publ_wrap_key1 != CK_INVALID_HANDLE && (wrap_mech->mechanism == CKM_RSA_PKCS || wrap_mech->mechanism == CKM_RSA_PKCS_OAEP)) { testcase_skip("EP11 does not support to wrap asymmetric keys " "with RSA"); rc = CKR_OK; goto testcase_cleanup; } } testcase_error("wrap with mech %s (%u) in slot %lu failed, rc=%s", mech_to_str(wrap_mech->mechanism), (unsigned int)wrap_mech->mechanism, slot_id1, p11_get_ckr(rc)); goto testcase_cleanup; } if (wrapped_key == NULL) { wrapped_key = malloc(wrapped_key_size); if (wrapped_key == NULL) { testcase_error("Failed to allocate a buffer of size %lu.", wrapped_key_size); goto testcase_cleanup; } goto do_wrap; } /* Get class and key type from original key */ switch (tsuite->wrapped_key_gen_mech.mechanism) { case CKM_AES_KEY_GEN: case CKM_AES_XTS_KEY_GEN: case CKM_GENERIC_SECRET_KEY_GEN: case CKM_SHA_1_KEY_GEN: unwrap_tmpl_num = 4; break; default: unwrap_tmpl_num = 3; break; } rc = funcs->C_GetAttributeValue(session1, sym_key != CK_INVALID_HANDLE ? sym_key : priv_key, unwrap_tmpl, unwrap_tmpl_num); if (rc != CKR_OK) { testcase_error("C_GetAttributeValue() on slot %lu, rc=%s.", slot_id1, p11_get_ckr(rc)); goto testcase_cleanup; } switch (wrap_mech->mechanism) { case CKM_RSA_X_509: case CKM_AES_ECB: case CKM_AES_CBC: case CKM_DES_ECB: case CKM_DES_CBC: case CKM_DES3_ECB: case CKM_DES3_CBC: break; default: unwrap_tmpl_num = 3; break; } if (tsuite->operation_mech.mechanism == CKM_IBM_ML_KEM || tsuite->operation_mech.mechanism == CKM_IBM_ML_KEM_WITH_ECDH) { /* KEM needs CKA_DERIVE=TRUE in unwrap template */ unwrap_tmpl[unwrap_tmpl_num].type = CKA_DERIVE; unwrap_tmpl[unwrap_tmpl_num].pValue = &ck_true; unwrap_tmpl[unwrap_tmpl_num].ulValueLen = sizeof(ck_true); unwrap_tmpl_num++; } if (tsuite->operation_mech.mechanism == CKM_ML_KEM) { /* KEM needs CKA_DECAPSULATE=TRUE in unwrap template */ unwrap_tmpl[unwrap_tmpl_num].type = CKA_DECAPSULATE; unwrap_tmpl[unwrap_tmpl_num].pValue = &ck_true; unwrap_tmpl[unwrap_tmpl_num].ulValueLen = sizeof(ck_true); unwrap_tmpl_num++; } /* Unwrap the key on slot 2 */ rc = funcs->C_UnwrapKey(session2, wrap_mech, sym_wrap_key2 != CK_INVALID_HANDLE ? sym_wrap_key2 : priv_wrap_key2, wrapped_key, wrapped_key_size, unwrap_tmpl, unwrap_tmpl_num, &unwrapped_key); if (rc != CKR_OK) { if (rc == CKR_KEY_NOT_WRAPPABLE || rc == CKR_WRAPPED_KEY_INVALID || rc == CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT) { testcase_skip("Key not (un-)wrappable"); rc = CKR_OK; goto testcase_cleanup; } if (rc == CKR_KEY_SIZE_RANGE || rc == CKR_UNWRAPPING_KEY_SIZE_RANGE) { testcase_skip("Key size not supported"); rc = CKR_OK; goto testcase_cleanup; } if (rc == CKR_MECHANISM_PARAM_INVALID && wrap_mech->mechanism == CKM_RSA_PKCS_OAEP) { oaep = (CK_RSA_PKCS_OAEP_PARAMS *)wrap_mech->pParameter; if (is_cca_token(slot_id2) && oaep->source == CKZ_DATA_SPECIFIED) { testcase_skip("CCA does not support RSA OAEP with source data"); rc = CKR_OK; goto testcase_cleanup; } if (is_cca_token(slot_id2) && oaep->hashAlg != CKM_SHA_1 && oaep->hashAlg != CKM_SHA256) { testcase_skip("CCA does not support RSA OAEP with a hash other " "than SHA1 or SHA256"); rc = CKR_OK; goto testcase_cleanup; } if (is_ep11_token(slot_id2) && oaep->hashAlg != CKM_SHA_1 && oaep->mgf != CKG_MGF1_SHA1) { testcase_skip("EP11 may not support RSA OAEP with a hash other " "than SHA1 on older firmware levels"); rc = CKR_OK; goto testcase_cleanup; } } if ((rc == CKR_MECHANISM_INVALID || rc == CKR_KEY_TYPE_INCONSISTENT) && is_ep11_token(slot_id2) && wrap_mech->mechanism == CKM_DES3_CBC && (key_type == CKK_EC || key_type == CKK_RSA || key_type == CKK_IBM_PQC_DILITHIUM || key_type == CKK_IBM_ML_DSA || key_type == CKK_IBM_ML_KEM || key_type == CKK_ML_DSA || key_type == CKK_ML_KEM)) { testcase_skip("EP11 does not support unwrap of EC, RSA, or PQC keys with DES3 CBC"); rc = CKR_OK; goto testcase_cleanup; } if (rc == CKR_ENCRYPTED_DATA_INVALID && is_ep11_token(slot_id2) && (key_type == CKK_IBM_PQC_DILITHIUM || key_type == CKK_IBM_PQC_KYBER || key_type == CKK_IBM_ML_DSA || key_type == CKK_IBM_ML_KEM || key_type == CKK_ML_DSA || key_type == CKK_ML_KEM)) { testcase_skip("EP11 does not supported the PQC variant"); rc = CKR_OK; goto testcase_cleanup; } testcase_error("unwrap with mech %s (%u) in slot %lu failed, rc=%s", mech_to_str(wrap_mech->mechanism), (unsigned int)wrap_mech->mechanism, slot_id2, p11_get_ckr(rc)); goto testcase_cleanup; } if (key_type == CKK_AES || key_type == CKK_AES_XTS || key_type == CKK_GENERIC_SECRET || key_type == CKK_SHA_1_HMAC) { /* Check if the unwrapped key has the desired key length */ rc = funcs->C_GetAttributeValue(session2, unwrapped_key, getattr_tmpl, 1); if (rc != CKR_OK) { testcase_error("C_GetAttributeValue() on slot %lu, rc=%s.", slot_id2, p11_get_ckr(rc)); goto testcase_cleanup; } if (unwrapped_keylen != key_len) { testcase_error("Unwrapped key size (%lu) differers from original " "(%lu)", unwrapped_keylen, key_len); rc = CKR_UNWRAPPING_KEY_SIZE_RANGE; goto testcase_cleanup; } } /* Test the unwrapped key with a crypto operation on slot 2 */ rc = do_perform_operation(&tsuite->operation_mech, slot_id1, session1, sym_key, publ_key, priv_key, slot_id2, session2, unwrapped_key, unwrapped_key); if (rc != CKR_OK) goto testcase_cleanup; testcase_new_assertion(); testcase_pass("Wrap/Unwrap of %s with %s", tsuite->name, mech_to_str(wrap_mech->mechanism)); testcase_cleanup: if (sym_key != CK_INVALID_HANDLE) { loc_rc = funcs->C_DestroyObject(session1, sym_key); if (loc_rc != CKR_OK) testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(loc_rc)); } if (publ_key != CK_INVALID_HANDLE) { loc_rc = funcs->C_DestroyObject(session1, publ_key); if (loc_rc != CKR_OK) testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(loc_rc)); } if (priv_key != CK_INVALID_HANDLE) { loc_rc = funcs->C_DestroyObject(session1, priv_key); if (loc_rc != CKR_OK) testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(loc_rc)); } if (unwrapped_key != CK_INVALID_HANDLE) { loc_rc = funcs->C_DestroyObject(session2, unwrapped_key); if (loc_rc != CKR_OK) testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(loc_rc)); } if (wrapped_key != NULL) free(wrapped_key); if (s != NULL) free(s); if (rc != CKR_OK) testcase_fail("Wrap/Unwrap of %s with %s", tsuite->name, mech_to_str(wrap_mech->mechanism)); return rc; } CK_RV do_wrapping_test(struct wrapping_mech_info *tsuite) { CK_RV loc_rc, rc = CKR_OK; CK_ULONG i; char *s = NULL; CK_BYTE modulus[OPENSSL_RSA_MAX_MODULUS_BITS / 8]; CK_BYTE publ_exp[16]; CK_BYTE key[64]; CK_ULONG key_size = 0; CK_BYTE value[64]; CK_BYTE ec_params[50]; CK_BYTE ec_point[500]; CK_ATTRIBUTE rsa_publ_tmpl[] = { {CKA_MODULUS, modulus, sizeof(modulus) }, {CKA_PUBLIC_EXPONENT, publ_exp, sizeof(publ_exp) }, }; CK_ATTRIBUTE ec_publ_tmpl[] = { {CKA_EC_PARAMS, ec_params, sizeof(ec_params) }, {CKA_EC_POINT, ec_point, sizeof(ec_point) }, }; CK_ATTRIBUTE sym_tmpl[] = { {CKA_VALUE, value, sizeof(value) }, }; testsuite_begin("%s", tsuite->name); if (!mech_supported(slot_id1, tsuite->wrapping_key_gen_mech.mechanism)) { testsuite_skip(NUM_WRAPPED_KEY_TESTS, "Slot %u doesn't support %s (0x%x)", (unsigned int)slot_id1, mech_to_str(tsuite->wrapping_key_gen_mech.mechanism), (unsigned int)tsuite->wrapping_key_gen_mech.mechanism); goto testcase_cleanup; } if (!mech_supported(slot_id2, tsuite->wrapping_key_gen_mech.mechanism)) { testsuite_skip(NUM_WRAPPED_KEY_TESTS, "Slot %u doesn't support %s (0x%x)", (unsigned int)slot_id2, mech_to_str(tsuite->wrapping_key_gen_mech.mechanism), (unsigned int)tsuite->wrapping_key_gen_mech.mechanism); goto testcase_cleanup; } if (!mech_supported(slot_id1, tsuite->wrapping_mech.mechanism)) { testsuite_skip(NUM_WRAPPED_KEY_TESTS, "Slot %u doesn't support %s (0x%x)", (unsigned int)slot_id1, mech_to_str(tsuite->wrapping_mech.mechanism), (unsigned int)tsuite->wrapping_mech.mechanism); goto testcase_cleanup; } if (!wrap_supported(slot_id1, tsuite->wrapping_mech)) { testsuite_skip(NUM_WRAPPED_KEY_TESTS, "Slot %u doesn't support key " "wrapping with %s (0x%x)", (unsigned int)slot_id1, mech_to_str(tsuite->wrapping_mech.mechanism), (unsigned int)tsuite->wrapping_mech.mechanism); goto testcase_cleanup; } if (!mech_supported(slot_id2, tsuite->wrapping_mech.mechanism)) { testsuite_skip(NUM_WRAPPED_KEY_TESTS, "Slot %u doesn't support %s (0x%x)", (unsigned int)slot_id2, mech_to_str(tsuite->wrapping_mech.mechanism), (unsigned int)tsuite->wrapping_mech.mechanism); goto testcase_cleanup; } if (!unwrap_supported(slot_id2, tsuite->wrapping_mech)) { testsuite_skip(NUM_WRAPPED_KEY_TESTS, "Slot %u doesn't support key " "wrapping with %s (0x%x)", (unsigned int)slot_id2, mech_to_str(tsuite->wrapping_mech.mechanism), (unsigned int)tsuite->wrapping_mech.mechanism); goto testcase_cleanup; } /* * Generate the wrapping key in slot 2. * For symmetric wrapping keys, generate the key from a random clear key * value, to be able to import the same key in the other token. * For RSA wrapping keys, the public key can be extracted and imported in * the other token. */ switch (tsuite->wrapping_key_gen_mech.mechanism) { case CKM_RSA_PKCS_KEY_PAIR_GEN: if (p11_ahex_dump(&s, tsuite->rsa_publ_exp, tsuite->rsa_publ_exp_len) == NULL) { testcase_error("p11_ahex_dump() failed"); rc = CKR_FUNCTION_FAILED; goto testcase_cleanup; } if (tsuite->rsa_modbits > 4096 && !rsa8k) { testcase_skip("Tests with modbits='%lu' are not enabled", tsuite->rsa_modbits); goto testcase_cleanup; } if (!keysize_supported(slot_id1, tsuite->wrapping_key_gen_mech.mechanism, tsuite->rsa_modbits)) { testcase_skip("Token in slot %lu cannot be used with modbits='%lu'", slot_id1, tsuite->rsa_modbits); goto testcase_cleanup; } if (!keysize_supported(slot_id2, tsuite->wrapping_key_gen_mech.mechanism, tsuite->rsa_modbits)) { testcase_skip("Token in slot %lu cannot be used with modbits='%lu'", slot_id2, tsuite->rsa_modbits); goto testcase_cleanup; } if (is_ep11_token(slot_id1) || is_ep11_token(slot_id2)) { if (!is_valid_ep11_pubexp(tsuite->rsa_publ_exp, tsuite->rsa_publ_exp_len)) { testcase_skip("EP11 Token in cannot be used with publ_exp.='%s'", s); goto testcase_cleanup; } } if (is_cca_token(slot_id1) || is_cca_token(slot_id2)) { if (!is_valid_cca_pubexp(tsuite->rsa_publ_exp, tsuite->rsa_publ_exp_len)) { testcase_skip("CCA Token in scannot be used with publ_exp.='%s'", s); goto testcase_cleanup; } } if (is_soft_token(slot_id1) || is_soft_token(slot_id2)) { if (!is_valid_soft_pubexp(tsuite->rsa_publ_exp, tsuite->rsa_publ_exp_len)) { testcase_skip("Soft Token in scannot be used with publ_exp.='%s'", s); goto testcase_cleanup; } } if (is_tpm_token(slot_id1) || is_tpm_token(slot_id2)) { if (!is_valid_tpm_pubexp(tsuite->rsa_publ_exp, tsuite->rsa_publ_exp_len) || !is_valid_tpm_modbits(tsuite->rsa_modbits)) { testcase_skip("TPM Token cannot " "be used with publ_exp.='%s'", s); goto testcase_cleanup; } } if (is_icsf_token(slot_id1) || is_icsf_token(slot_id2)) { if (!is_valid_icsf_pubexp(tsuite->rsa_publ_exp, tsuite->rsa_publ_exp_len) || tsuite->rsa_modbits < 1024) { testcase_skip("ICSF Token cannot be used with publ_exp='%s'.", s); goto testcase_cleanup; } } rc = generate_RSA_PKCS_KeyPair(session2, CKM_RSA_PKCS_KEY_PAIR_GEN, tsuite->rsa_modbits, tsuite->rsa_publ_exp, tsuite->rsa_publ_exp_len, &publ_wrap_key2, &priv_wrap_key2); break; case CKM_EC_KEY_PAIR_GEN: rc = generate_EC_KeyPair(session2, CKM_EC_KEY_PAIR_GEN, tsuite->ec_parms, tsuite->ec_parms_len, &publ_wrap_key2, &priv_wrap_key2, FALSE); break; case CKM_EC_EDWARDS_KEY_PAIR_GEN: rc = generate_EC_KeyPair(session2, CKM_EC_EDWARDS_KEY_PAIR_GEN, tsuite->ec_parms, tsuite->ec_parms_len, &publ_wrap_key2, &priv_wrap_key2, FALSE); break; case CKM_EC_MONTGOMERY_KEY_PAIR_GEN: rc = generate_EC_KeyPair(session2, CKM_EC_MONTGOMERY_KEY_PAIR_GEN, tsuite->ec_parms, tsuite->ec_parms_len, &publ_wrap_key2, &priv_wrap_key2, FALSE); break; case CKM_AES_KEY_GEN: key_size = tsuite->sym_keylen; rc = funcs->C_GenerateRandom(session2, key, key_size); if (rc != CKR_OK) { testcase_error("C_GenerateRandom(), rc=%s.", p11_get_ckr(rc)); goto testcase_cleanup; } rc = create_AESKey(session2, CK_TRUE, key, key_size, CKK_AES, &sym_wrap_key2); if (rc == CKR_POLICY_VIOLATION) { testcase_skip("AES key import is not allowed by policy"); rc = CKR_OK; goto testcase_cleanup; } break; case CKM_AES_XTS_KEY_GEN: key_size = tsuite->sym_keylen; rc = funcs->C_GenerateRandom(session2, key, key_size); if (rc != CKR_OK) { testcase_error("C_GenerateRandom(), rc=%s.", p11_get_ckr(rc)); goto testcase_cleanup; } rc = create_AESKey(session2, CK_TRUE, key, key_size, CKK_AES_XTS, &sym_wrap_key2); if (rc == CKR_POLICY_VIOLATION) { testcase_skip("AES-XTS key import is not allowed by policy"); rc = CKR_OK; goto testcase_cleanup; } break; case CKM_DES3_KEY_GEN: key_size = 24; rc = funcs->C_GenerateRandom(session2, key, key_size); if (rc != CKR_OK) { testcase_error("C_GenerateRandom(), rc=%s.", p11_get_ckr(rc)); goto testcase_cleanup; } rc = create_DES3Key(session2, key, key_size, &sym_wrap_key2); break; case CKM_DES2_KEY_GEN: key_size = 16; rc = funcs->C_GenerateRandom(session2, key, key_size); if (rc != CKR_OK) { testcase_error("C_GenerateRandom(), rc=%s.", p11_get_ckr(rc)); goto testcase_cleanup; } rc = create_DES2Key(session2, key, key_size, &sym_wrap_key2); break; case CKM_DES_KEY_GEN: key_size = 8; rc = funcs->C_GenerateRandom(session2, key, key_size); if (rc != CKR_OK) { testcase_error("C_GenerateRandom(), rc=%s.", p11_get_ckr(rc)); goto testcase_cleanup; } rc = create_DESKey(session2, key, key_size, &sym_wrap_key2); break; default: testcase_error("Testcase does not support %s (%u)", mech_to_str(tsuite->wrapping_key_gen_mech.mechanism), (unsigned int)tsuite->wrapping_key_gen_mech.mechanism); goto testcase_cleanup; } if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("generate wrapping key with mech %s (%u) in slot %lu " "is not allowed by policy", mech_to_str(tsuite->wrapping_key_gen_mech.mechanism), (unsigned int)tsuite->wrapping_key_gen_mech.mechanism, slot_id2); rc = CKR_OK; goto testcase_cleanup; } if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("generate wrapping key of the key size with mech %s " "(%u) in slot %lu is not supported", mech_to_str(tsuite->wrapping_key_gen_mech.mechanism), (unsigned int)tsuite->wrapping_key_gen_mech.mechanism, slot_id2); rc = CKR_OK; goto testcase_cleanup; } testcase_error("generate wrapping key with mech %s (%u) in slot %lu " "failed, rc=%s", mech_to_str(tsuite->wrapping_key_gen_mech.mechanism), (unsigned int)tsuite->wrapping_key_gen_mech.mechanism, slot_id2, p11_get_ckr(rc)); goto testcase_cleanup; } /* Import the wrapping key into slot 1 */ switch (tsuite->wrapping_key_gen_mech.mechanism) { case CKM_RSA_PKCS_KEY_PAIR_GEN: rc = funcs->C_GetAttributeValue(session2, publ_wrap_key2, rsa_publ_tmpl, 2); if (rc != CKR_OK) { testcase_error("C_GetAttributeValue(), rc=%s.", p11_get_ckr(rc)); goto testcase_cleanup; } rc = create_RSAPublicKey(session1, rsa_publ_tmpl[0].pValue, rsa_publ_tmpl[1].pValue, rsa_publ_tmpl[0].ulValueLen, rsa_publ_tmpl[1].ulValueLen, &publ_wrap_key1); break; case CKM_AES_KEY_GEN: memcpy(sym_tmpl[0].pValue, key, key_size); sym_tmpl[0].ulValueLen = key_size; rc = create_AESKey(session1, CK_TRUE, sym_tmpl[0].pValue, sym_tmpl[0].ulValueLen, CKK_AES, &sym_wrap_key1); break; case CKM_AES_XTS_KEY_GEN: memcpy(sym_tmpl[0].pValue, key, key_size); sym_tmpl[0].ulValueLen = key_size; rc = create_AESKey(session1, CK_TRUE, sym_tmpl[0].pValue, sym_tmpl[0].ulValueLen, CKK_AES_XTS, &sym_wrap_key1); break; case CKM_DES3_KEY_GEN: memcpy(sym_tmpl[0].pValue, key, key_size); sym_tmpl[0].ulValueLen = key_size; rc = create_DES3Key(session1, sym_tmpl[0].pValue, sym_tmpl[0].ulValueLen, &sym_wrap_key1); break; case CKM_DES2_KEY_GEN: memcpy(sym_tmpl[0].pValue, key, key_size); sym_tmpl[0].ulValueLen = key_size; rc = create_DES2Key(session1, sym_tmpl[0].pValue, sym_tmpl[0].ulValueLen, &sym_wrap_key1); break; case CKM_DES_KEY_GEN: memcpy(sym_tmpl[0].pValue, key, key_size); sym_tmpl[0].ulValueLen = key_size; rc = create_DESKey(session1, sym_tmpl[0].pValue, sym_tmpl[0].ulValueLen, &sym_wrap_key1); break; case CKM_EC_KEY_PAIR_GEN: rc = funcs->C_GetAttributeValue(session2, publ_wrap_key2, ec_publ_tmpl, 2); if (rc != CKR_OK) { testcase_error("C_GetAttributeValue(), rc=%s.", p11_get_ckr(rc)); goto testcase_cleanup; } rc = create_ECPublicKey(session1, CKK_EC, ec_publ_tmpl[0].pValue, ec_publ_tmpl[0].ulValueLen, ec_publ_tmpl[1].pValue, ec_publ_tmpl[1].ulValueLen, &publ_wrap_key1, FALSE); break; case CKM_EC_EDWARDS_KEY_PAIR_GEN: rc = funcs->C_GetAttributeValue(session2, publ_wrap_key2, ec_publ_tmpl, 2); if (rc != CKR_OK) { testcase_error("C_GetAttributeValue(), rc=%s.", p11_get_ckr(rc)); goto testcase_cleanup; } rc = create_ECPublicKey(session1, CKK_EC_EDWARDS, ec_publ_tmpl[0].pValue, ec_publ_tmpl[0].ulValueLen, ec_publ_tmpl[1].pValue, ec_publ_tmpl[1].ulValueLen, &publ_wrap_key1, FALSE); break; case CKM_EC_MONTGOMERY_KEY_PAIR_GEN: rc = funcs->C_GetAttributeValue(session2, publ_wrap_key2, ec_publ_tmpl, 2); if (rc != CKR_OK) { testcase_error("C_GetAttributeValue(), rc=%s.", p11_get_ckr(rc)); goto testcase_cleanup; } rc = create_ECPublicKey(session1, CKK_EC_MONTGOMERY, ec_publ_tmpl[0].pValue, ec_publ_tmpl[0].ulValueLen, ec_publ_tmpl[1].pValue, ec_publ_tmpl[1].ulValueLen, &publ_wrap_key1, FALSE); break; default: testcase_error("Testcase does not support %s (%u)", mech_to_str(tsuite->wrapping_key_gen_mech.mechanism), (unsigned int)tsuite->wrapping_key_gen_mech.mechanism); goto testcase_cleanup; } if (rc != CKR_OK) { if (rc == CKR_POLICY_VIOLATION) { testcase_skip("import wrapping key in slot %lu is not allowed by policy", slot_id1); rc = CKR_OK; goto testcase_cleanup; } if (rc == CKR_KEY_SIZE_RANGE) { testcase_skip("import wrapping key size is not supported in slot %lu", slot_id1); rc = CKR_OK; goto testcase_cleanup; } testcase_error("import wrapping key in slot %lu failed, rc=%s", slot_id1, p11_get_ckr(rc)); goto testcase_cleanup; } /* Wrap/unwrap different keys with this wrapping key */ for (i = 0; i< NUM_WRAPPED_KEY_TESTS; i++) { /* Some combinations can not work due to size restrictions */ if (wrapped_key_tests[i].wrapped_key_gen_mech.mechanism == CKM_AES_XTS_KEY_GEN && ((tsuite->wrapping_mech.mechanism == CKM_RSA_PKCS && tsuite->rsa_modbits <= 512) || (tsuite->wrapping_mech.mechanism == CKM_RSA_PKCS_OAEP && tsuite->rsa_modbits <= 1024))) continue; if (wrapped_key_tests[i].wrapped_key_gen_mech.mechanism == CKM_DES_KEY_GEN && tsuite->wrapping_mech.mechanism == CKM_AES_XTS) continue; rc = do_wrap_key_test(&wrapped_key_tests[i], &tsuite->wrapping_mech); if (rc != CKR_OK) break; } testcase_cleanup: if (sym_wrap_key1 != CK_INVALID_HANDLE) { loc_rc = funcs->C_DestroyObject(session1, sym_wrap_key1); if (loc_rc != CKR_OK) testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(loc_rc)); } sym_wrap_key1 = CK_INVALID_HANDLE; if (sym_wrap_key2 != CK_INVALID_HANDLE) { loc_rc = funcs->C_DestroyObject(session2, sym_wrap_key2); if (loc_rc != CKR_OK) testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(loc_rc)); } sym_wrap_key2 = CK_INVALID_HANDLE; if (publ_wrap_key1 != CK_INVALID_HANDLE) { loc_rc = funcs->C_DestroyObject(session1, publ_wrap_key1); if (loc_rc != CKR_OK) testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(loc_rc)); } publ_wrap_key1 = CK_INVALID_HANDLE; if (publ_wrap_key2 != CK_INVALID_HANDLE) { loc_rc = funcs->C_DestroyObject(session2, publ_wrap_key2); if (loc_rc != CKR_OK) testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(loc_rc)); } publ_wrap_key2 = CK_INVALID_HANDLE; if (priv_wrap_key2 != CK_INVALID_HANDLE) { loc_rc = funcs->C_DestroyObject(session2, priv_wrap_key2); if (loc_rc != CKR_OK) testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(loc_rc)); } priv_wrap_key2 = CK_INVALID_HANDLE; if (s != NULL) free(s); return rc; } CK_RV do_tok2tok_tests(void) { CK_ULONG i; CK_RV rc; for (i = 0; i < NUM_WRAPPING_TESTS; i++) { rc = do_wrapping_test(&wrapping_tests[i]); if (rc != CKR_OK) break; } return CKR_OK; } int main(int argc, char **argv) { CK_C_INITIALIZE_ARGS cinit_args; int i, ret = 1; CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; CK_ULONG user_pin_len; CK_RV rv; CK_FLAGS flags; for (i = 1; i < argc; i++) { if (strcmp(argv[i], "-slot1") == 0) { ++i; if (i >= argc) { printf("Slot number missing\n"); return -1; } slot_id1 = atoi(argv[i]); } else if (strcmp(argv[i], "-slot2") == 0) { ++i; if (i >= argc) { printf("Slot number missing\n"); return -1; } slot_id2 = atoi(argv[i]); } else if (strcmp(argv[i], "-rsa8k") == 0) { ++i; rsa8k = TRUE; } else if (strcmp(argv[i], "-h") == 0) { printf("usage: %s [-slot1 ] [-slot2 ] [-rsa8k] [-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(); 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_id2, p11_get_ckr(rv)); goto close_session; } testcase_pass("C_OpenSession on slot %lu", slot_id2); testcase_new_assertion(); if (slot_id1 != slot_id2) { 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_id2, p11_get_ckr(rv)); goto close_session; } testcase_pass("C_Login as User on slot %lu", slot_id2); } else { testcase_skip("C_Login as User on slot %lu (already logged in)", slot_id2); } rv = do_tok2tok_tests(); if (rv != CKR_OK) goto close_session; ret = 0; 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 testcase_return(ret); } opencryptoki-opencryptoki-451d99c/testcases/misc_tests/tok_des.c000066400000000000000000000205641520105705100253020ustar00rootroot00000000000000/* * 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 "pkcs11types.h" #include "regress.h" #include "common.c" 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; if (i >= argc) { printf("Slot number missing\n"); return -1; } 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; } opencryptoki-opencryptoki-451d99c/testcases/misc_tests/tok_obj.c000066400000000000000000000426541520105705100253050ustar00rootroot00000000000000/* * 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); 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: %lu 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 #%lu 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: %lu\n", info.ulMaxSessionCount); printf(" ulSessionCount: %lu\n", info.ulSessionCount); printf(" ulMaxRwSessionCount: %lu\n", info.ulMaxRwSessionCount); printf(" ulRwSessionCount: %lu\n", info.ulRwSessionCount); printf(" ulMaxPinLen: %lu\n", info.ulMaxPinLen); printf(" ulMinPinLen: %lu\n", info.ulMinPinLen); printf(" ulTotalPublicMemory: %lu\n", info.ulTotalPublicMemory); printf(" ulFreePublicMemory: %lu\n", info.ulFreePublicMemory); printf(" ulTotalPrivateMemory: %lu\n", info.ulTotalPrivateMemory); printf(" ulFreePrivateMemory: %lu\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("8. Create Data Object\n"); printf("9. Exit\n"); printf("Selection: "); fflush(stdout); } int do_CreateDataObject(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 h_obj; CK_OBJECT_CLASS class = CKO_DATA; CK_UTF8CHAR label[] = "A data object"; CK_UTF8CHAR application[] = "An application"; CK_BYTE data[] = "Sample data"; CK_BBOOL true = CK_TRUE; CK_ATTRIBUTE attrs[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label) - 1}, {CKA_APPLICATION, application, sizeof(application) - 1}, {CKA_VALUE, data, sizeof(data)} }; CK_ULONG num_attrs = sizeof(attrs) / sizeof(CK_ATTRIBUTE); 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; printf("open 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 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; } printf("create data object\n"); rc = funcs->C_CreateObject(h_session, attrs, num_attrs, &h_obj); if (rc != CKR_OK) { show_error(" C_CreateObject #1", rc); rc = FALSE; goto done; } printf("Data object created successfully.\n"); rc = TRUE; done: printf("close session\n"); funcs->C_CloseAllSessions(SLOT_ID); return rc; } 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) { if (i + 1 >= argc) { printf("Slot number missing\n"); return -1; } 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 8: do_CreateDataObject(); break; case 9: goto done; break; } menu(); } done: rc = funcs->C_Finalize(NULL); return rc; } opencryptoki-opencryptoki-451d99c/testcases/misc_tests/tok_rsa.c000066400000000000000000000323031520105705100253060ustar00rootroot00000000000000/* * 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 "pkcs11types.h" #include "regress.h" 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; if (i >= argc) { printf("Slot number missing\n"); return -1; } 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 %ubit", 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 %ubit", 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 %ubit", 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 %ubit", 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 %ubit", 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 %ubit", 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 %ubit", 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 %ubit", 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; } opencryptoki-opencryptoki-451d99c/testcases/misc_tests/x25519-private-key.pem000066400000000000000000000001671520105705100273210ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MC4CAQAwBQYDK2VuBCIEIHioa2ryM+8VIf86cUkNYyNJImFgJhTbpHianrJEo6xb -----END PRIVATE KEY----- opencryptoki-opencryptoki-451d99c/testcases/misc_tests/x25519-public-key.pem000066400000000000000000000001611520105705100271170ustar00rootroot00000000000000-----BEGIN PUBLIC KEY----- MCowBQYDK2VuAyEAaVIC3TN/XftRmKDJADZvBZ47yi+NFBzY3Bfwi+MWRRg= -----END PUBLIC KEY----- opencryptoki-opencryptoki-451d99c/testcases/misc_tests/x448-private-key.pem000066400000000000000000000002301520105705100271420ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MEYCAQAwBQYDK2VvBDoEOAT7so83kh9B/N8yiMZ7x7ht6lfcCjLw1c/J6ydP6zs/ Ms1AZbr/JAKhD8yw7KWahYk+3PQ7jS+Y -----END PRIVATE KEY----- opencryptoki-opencryptoki-451d99c/testcases/misc_tests/x448-public-key.pem000066400000000000000000000002221520105705100267470ustar00rootroot00000000000000-----BEGIN PUBLIC KEY----- MEIwBQYDK2VvAzkArD/kqf53b2Z3Vooc21pMcj7LwVhk9GYLJX4pSxrNvtYO8cuc T3ZoB3DpgBUU8q1KPKHLfkCXyEM= -----END PUBLIC KEY----- opencryptoki-opencryptoki-451d99c/testcases/ock_tests.sh.in000077500000000000000000000237531520105705100242760ustar00rootroot00000000000000#!/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 environment 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 PLATFORM=$(uname) LSFLAGS="-U" if [ $PLATFORM = "AIX" ]; then unset LSFLAGS function pgrep { local progname="$1" if [ -z "$progname" ]; then echo "No program name specified." return 1 fi ps -eo pid,comm | grep -w $progname | awk '{print $1}' } fi # # 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_TESTS+=" pkcs11/attribute pkcs11/copyobjects pkcs11/destroyobjects" OCK_TESTS+=" pkcs11/findobjects pkcs11/generate_keypair" OCK_TESTS+=" pkcs11/get_interface pkcs11/getobjectsize pkcs11/sess_opstate" OCK_TESTS+=" misc_tests/fork misc_tests/obj_mgmt_tests" OCK_TESTS+=" misc_tests/obj_mgmt_lock_tests misc_tests/reencrypt" OCK_TESTS+=" misc_tests/events misc_tests/cca_ep11_export_import_test" OCK_TESTS+=" misc_tests/dual_functions misc_tests/always_auth" 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 } ### ## 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" TOKTYPE="CCA" ;; *ICA*) echo "ICA Token type detected" TOKTYPE="ICA" ;; *Soft*) 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 token 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 [ ! $PLATFORM = "AIX" -a ! -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 $LSFLAGS $OCK_TESTS)" ALLRES=0 COMBINED_EXTRACT="" for item in "$(cat test_combined_extract.slots 2>/dev/null)"; do if [[ "$1" == "$item" ]]; then COMBINED_EXTRACT="-combined-extract" fi done for j in $( ls $LSFLAGS $OCK_TESTS ); do echo "** Now executing '$j -slot $1 $NO_STOP $COMBINED_EXTRACT'" $j -slot $1 $NO_STOP $COMBINED_EXTRACT 2>&1 RES=$? if [ $RES -ne 0 ]; then ALLRES=$RES echo "ERROR: Testcase $j failed to execute, rc: $RES" echo "ERROR: Testcase $j failed to execute for slot $1, rc: $RES" >> error_file.$1 fi done return $ALLRES } ### ## 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 $LSFLAGS $OCK_BENCHS)" ALLRES=0 for i in $( ls $LSFLAGS $OCK_BENCHS ); do echo "** Now executing '$i" $i -slot $1 $NO_STOP 2>&1 RES=$? if [ $RES -ne 0 ]; then ALLRES=$RES echo "ERROR: Benchmark $i failed to execute, rc: $RES" echo "ERROR: Benchmark $i failed to execute for slot $1, rc: $RES" >> error_file.$1 fi done return $ALLRES } main_script() { LOGFILE=0 # check generic stuff first check_env # where to run if [ -z $SLOT ]; then SLOT="`awk '/^slot (.*)/ { print $2; }' $PKCONF`" LOGFILE=1 fi rm -f error_file.* for i in $SLOT; do ( echo "********** Testing Slot $i **********" check_slot $i || { echo "SKIPPING slot $i"; exit; } if [ $NONEED_TOKEN_INIT -eq 0 ]; then init_slot $i || { echo "SKIPPING slot $i"; exit; } fi for item in $OCK_TRACE_TOKENS; do [[ "$i" == "$item" ]] && export OPENCRYPTOKI_TRACE_LEVEL="${OCK_TRACE_LEVEL:-4}" done 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 RC=$? if [ -n "$BENCHMARK" ]; then run_benchs $i RC2=$? if [ $RC2 -ne 0 ]; then RC=RC2 fi fi echo "********** Finished Testing Slot $i with RC=$RC **********" ) & done wait ls error_file.* &>/dev/null if [ $? -eq 0 ]; then echo "********** At least one slot finished with error **********" cat error_file.* rm -f error_file.* exit 1 fi } 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 opencryptoki-opencryptoki-451d99c/testcases/pkcs11/000077500000000000000000000000001520105705100224245ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/testcases/pkcs11/README000066400000000000000000000004601520105705100233040ustar00rootroot00000000000000PKCS11 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. opencryptoki-opencryptoki-451d99c/testcases/pkcs11/attribute.c000066400000000000000000000515451520105705100246050ustar00rootroot00000000000000/* * 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_OBJECT_HANDLE obj_handle_no_mod = 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 so_pin[PKCS11_MAX_PIN_LEN]; CK_ULONG so_pin_len; CK_ULONG find_count; CK_OBJECT_HANDLE obj_list[10]; 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 label2[] = "Another RSA public key object"; CK_CHAR labelbuf[100]; CK_BBOOL false = FALSE; CK_BBOOL true = TRUE; CK_BBOOL boolval, boolval2; 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 pub_template_no_modify[] = { {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}, {CKA_MODIFIABLE, &false, sizeof(false)}, }; 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)}, }; CK_ATTRIBUTE update_modifiable_false[] = { {CKA_MODIFIABLE, &false, sizeof(false)}, }; CK_ATTRIBUTE update_modifiable_true[] = { {CKA_MODIFIABLE, &true, sizeof(true)}, }; CK_ATTRIBUTE update_copyable_false[] = { {CKA_COPYABLE, &false, sizeof(false)}, }; CK_ATTRIBUTE update_copyable_true[] = { {CKA_COPYABLE, &true, sizeof(true)}, }; CK_ATTRIBUTE update_destroyable_false[] = { {CKA_DESTROYABLE, &false, sizeof(false)}, }; CK_ATTRIBUTE update_destroyable_true[] = { {CKA_DESTROYABLE, &true, sizeof(true)}, }; CK_ATTRIBUTE update_trusted_true[] = { {CKA_TRUSTED, &true, sizeof(true)}, }; CK_ATTRIBUTE update_trusted_false[] = { {CKA_TRUSTED, &false, sizeof(false)}, }; CK_ATTRIBUTE array_attrs[] = { {CKA_ENCRYPT, &true, sizeof(true)}, {CKA_WRAP, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label) - 1}, }; CK_ATTRIBUTE pub_template_private[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_PRIVATE, &true, sizeof(true)}, {CKA_LABEL, label2, sizeof(label2) - 1}, {CKA_MODULUS, modulus, modulus_len}, {CKA_PUBLIC_EXPONENT, publicExponent, publicExponent_len}, {CKA_WRAP_TEMPLATE, array_attrs, sizeof(array_attrs)}, }; CK_ATTRIBUTE find_label[] = { {CKA_LABEL, label2, sizeof(label2) - 1}, }; CK_ATTRIBUTE verify_array_attrs[] = { {CKA_ENCRYPT, &boolval, sizeof(boolval)}, {CKA_WRAP, &boolval2, sizeof(boolval2)}, {CKA_LABEL, labelbuf, sizeof(labelbuf)}, }; CK_ATTRIBUTE verify_array[] = { {CKA_WRAP_TEMPLATE, &verify_array_attrs, sizeof(verify_array_attrs)}, }; testcase_begin(""); 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) { if (is_rejected_by_policy(rc, session)) { testcase_skip("Key generation is not allowed by policy"); goto testcase_cleanup; } 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."); /* Try to update attributes of an object which has CKA_MODIFIABLE=FALSE */ testcase_new_assertion(); /* create a public key object with CKA_MODIFIABLE=FALSE*/ rc = funcs->C_CreateObject(session, pub_template_no_modify, 7, &obj_handle_no_mod); if (rc != CKR_OK) { testcase_fail("C_CreateObject() rc = %s", p11_get_ckr(rc)); goto testcase_cleanup; } rc = funcs->C_SetAttributeValue(session, obj_handle_no_mod, update_label, 1); if (rc == CKR_ACTION_PROHIBITED) testcase_pass("C_SetAttributeValue() did not update the object rc = %s " "(as expected)", p11_get_ckr(rc)); else testcase_fail("C_SetAttributeValue() to update CKA_MODIFIABLE should " "have failed with CKR_ACTION_PROHIBITED, but got " "rc = %s.", p11_get_ckr(rc)); /* * Try to update CKA_MODIFIABLE on the object that has CKA_MODIFIABLE=TRUE. * This should fail. CKA_MODIFIABLE can not be changed after creation of * the object. */ testcase_new_assertion(); rc = funcs->C_SetAttributeValue(session, obj_handle, update_modifiable_false, 1); if (rc == CKR_ATTRIBUTE_READ_ONLY) testcase_pass("C_SetAttributeValue() did not update CKA_MODIFIABLE to " "FALSE rc = %s (as expected)", p11_get_ckr(rc)); else testcase_fail("C_SetAttributeValue() to update CKA_MODIFIABLE should " "have failed with CKR_ATTRIBUTE_READ_ONLY, but got " "rc = %s.", p11_get_ckr(rc)); testcase_new_assertion(); rc = funcs->C_SetAttributeValue(session, obj_handle, update_modifiable_true, 1); if (rc == CKR_ATTRIBUTE_READ_ONLY) testcase_pass("C_SetAttributeValue() did not update CKA_MODIFIABLE to " "TRUE rc = %s (as expected)", p11_get_ckr(rc)); else testcase_fail("C_SetAttributeValue() to update CKA_MODIFIABLE should " "have failed with CKR_ATTRIBUTE_READ_ONLY, but got" " rc = %s.", p11_get_ckr(rc)); /* * Try to update CKA_COPYABLE on the object that has CKA_COPYABLE=TRUE. * CKA_MODIFIABLE can not be changed to TRUE once it has been set to FALSE. */ testcase_new_assertion(); rc = funcs->C_SetAttributeValue(session, obj_handle, update_copyable_false, 1); if (rc != CKR_OK) { testcase_fail("C_SetAttributeValue() rc = %s", p11_get_ckr(rc)); goto testcase_cleanup; } testcase_pass("Successfully set CKA_COPYABLE to FALSE."); testcase_new_assertion(); rc = funcs->C_SetAttributeValue(session, obj_handle, update_copyable_true, 1); if (rc == CKR_ATTRIBUTE_READ_ONLY) testcase_pass("C_SetAttributeValue() did not update CKA_COPYABLE to " "TRUE rc = %s (as expected)", p11_get_ckr(rc)); else testcase_fail("C_SetAttributeValue() to update CKA_COPYABLE back to " "TRUE should have failed with CKR_ATTRIBUTE_READ_ONLY, " "but got rc = %s.", p11_get_ckr(rc)); /* * Try to update CKA_DESTROYABLE on the object that has CKA_DESTROYABLE=TRUE. */ testcase_new_assertion(); rc = funcs->C_SetAttributeValue(session, obj_handle, update_destroyable_false, 1); if (rc != CKR_OK) { testcase_fail("C_SetAttributeValue() rc = %s", p11_get_ckr(rc)); goto testcase_cleanup; } testcase_pass("Successfully set CKA_DESTROYABLE to FALSE."); testcase_new_assertion(); rc = funcs->C_SetAttributeValue(session, obj_handle, update_destroyable_true, 1); if (rc != CKR_OK) { testcase_fail("C_SetAttributeValue() rc = %s", p11_get_ckr(rc)); goto testcase_cleanup; } testcase_pass("Successfully set CKA_DESTROYABLE to TRUE."); /* * Try to update CKA_TRUSTED when logged in a user. * This is expected to fail with CKR_USER_NOT_LOGGED_IN. */ testcase_new_assertion(); rc = funcs->C_SetAttributeValue(session, obj_handle, update_trusted_true, 1); if (rc == CKR_USER_NOT_LOGGED_IN) testcase_pass("C_SetAttributeValue() did not update CKA_TRUSTED to " "TRUE rc = %s (as expected, because only SO can set " "CKA_TRUSTED to TRUE)", p11_get_ckr(rc)); else testcase_fail("C_SetAttributeValue() to update CKA_TRUSTED should " "have failed with CKR_USER_NOT_LOGGED_IN, but got " "rc = %s.", p11_get_ckr(rc)); /* Login a SO */ testcase_user_logout(); testcase_so_login(); /* Now add new attribute CKA_TRUSTED */ testcase_new_assertion(); rc = funcs->C_SetAttributeValue(session, obj_handle, update_trusted_true, 1); if (rc != CKR_OK) { testcase_fail("C_SetAttributeValue() rc = %s", p11_get_ckr(rc)); goto testcase_cleanup; } testcase_pass("Successfully added CKA_TRUSTED=TRUE (as SO)."); /* Login a User */ testcase_user_logout(); testcase_user_login(); /* Now set attribute CKA_TRUSTED to FALSE */ testcase_new_assertion(); rc = funcs->C_SetAttributeValue(session, obj_handle, update_trusted_false, 1); if (rc != CKR_OK) { testcase_fail("C_SetAttributeValue() rc = %s", p11_get_ckr(rc)); goto testcase_cleanup; } testcase_pass("Successfully added CKA_TRUSTED=FALSE (as User)."); testcase_new_assertion(); rv = funcs->C_DestroyObject(session, obj_handle); if (rv != CKR_OK) testcase_error("C_DestroyObject rv=%s", p11_get_ckr(rv)); /* create a public key object with an array-attribute */ rc = funcs->C_CreateObject(session, pub_template_private, 8, &obj_handle); if (rc != CKR_OK) { testcase_fail("C_CreateObject() rc = %s", p11_get_ckr(rc)); goto testcase_cleanup; } testcase_pass("Successfully created an object with an attribute-array attribute."); testcase_new_assertion(); /* * Logout and Login again to force a reload of private token objects. * This tests that the object is stored correctly into the token directory * and that it can be successfully be loaded again. */ testcase_user_logout(); testcase_user_login(); rc = funcs->C_FindObjectsInit(session, find_label, 1); 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 != 1) { testcase_fail("Should have found 1 objects, found %d", (int) find_count); goto testcase_cleanup; } obj_handle = obj_list[0]; rc = funcs->C_FindObjectsFinal(session); if (rc != CKR_OK) { testcase_fail("C_FindObjectsFinal() rc = %s", p11_get_ckr(rc)); goto testcase_cleanup; } testcase_pass("Successfully found the previously created object."); /* Now get the attribute-array attribute and verify it */ testcase_new_assertion(); rc = funcs->C_GetAttributeValue(session, obj_handle, verify_array, 1); if (rc != CKR_OK) { testcase_fail("C_GetAttributeValue() rc = %s", p11_get_ckr(rc)); goto testcase_cleanup; } /* verify the attribute values retrieved */ if (verify_array[0].ulValueLen != sizeof(verify_array_attrs)) { testcase_fail("CKA_WRAP_TEMPLATE array length mismatch"); goto testcase_cleanup; } if (verify_array_attrs[0].ulValueLen != sizeof(boolval) || *(CK_BBOOL *) verify_array_attrs[0].pValue != true) { testcase_fail("Array element CKA_ENCRYPT mismatch"); goto testcase_cleanup; } if (verify_array_attrs[1].ulValueLen != sizeof(boolval) || *(CK_BBOOL *) verify_array_attrs[1].pValue != true) { testcase_fail("Array element CKA_WRAP mismatch"); goto testcase_cleanup; } if (memcmp(verify_array_attrs[2].pValue, label, verify_array_attrs[2].ulValueLen) != 0) testcase_fail("Array element CKA_LABEL mismatch"); else testcase_pass("Successfully verified attribute-array elements."); testcase_cleanup: if (obj_handle != CK_INVALID_HANDLE) { rv = funcs->C_DestroyObject(session, obj_handle); if (rv != CKR_OK) testcase_error("C_DestroyObject rv=%s", p11_get_ckr(rv)); } if (obj_handle_no_mod != CK_INVALID_HANDLE) { rv = funcs->C_DestroyObject(session, obj_handle_no_mod); 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; } CK_RV do_TestAttributesAESXTS(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 key[] = { 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, }; int keylen = 64; CK_OBJECT_CLASS class = CKO_SECRET_KEY; CK_KEY_TYPE keyType = CKK_AES_XTS; CK_CHAR label[] = "An AES XTS key object"; CK_BBOOL false = FALSE; CK_BBOOL true = TRUE; CK_BBOOL boolval; CK_ATTRIBUTE keyTemplate[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &false, sizeof(false)}, {CKA_LABEL, label, sizeof(label) - 1}, {CKA_VALUE, key, keylen}, {CKA_EXTRACTABLE, &false, sizeof(CK_BBOOL)}, {CKA_IBM_PROTKEY_EXTRACTABLE, &true, sizeof(CK_BBOOL)}, }; CK_ULONG keyTemplate_len = sizeof(keyTemplate) / sizeof(CK_ATTRIBUTE); CK_ATTRIBUTE new_attrs[] = { {CKA_ENCRYPT, &false, sizeof(false)}, }; CK_ATTRIBUTE verify_attrs[] = { {CKA_ENCRYPT, &boolval, sizeof(boolval)}, }; testcase_begin(""); testcase_rw_session(); testcase_user_login(); /** skip test if the slot doesn't support this mechanism **/ if (!mech_supported(SLOT_ID, CKM_AES_XTS)) { testcase_skip("Skip test as CKM_AES_XTS not supported"); goto testcase_cleanup; } /* create a aes xts key object */ rc = funcs->C_CreateObject(session, keyTemplate, keyTemplate_len, &obj_handle); if (rc != CKR_OK) { if (is_rejected_by_policy(rc, session)) { testcase_skip("Key generation is not allowed by policy"); goto testcase_cleanup; } 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, 1); if (rc != CKR_OK) { testcase_fail("C_SetAttributeValue() rc = %s", p11_get_ckr(rc)); goto testcase_cleanup; } testcase_pass("Successfully added new attribute."); /* Now get the attributes that were updated */ testcase_new_assertion(); rc = funcs->C_GetAttributeValue(session, obj_handle, verify_attrs, 1); 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; } testcase_pass("Successfully verified newly added attribute."); testcase_cleanup: if (obj_handle != CK_INVALID_HANDLE) { 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; rv = funcs->C_GetFunctionStatus(hsess); if (rv != CKR_FUNCTION_NOT_PARALLEL) return rv; rv = funcs->C_CancelFunction(hsess); if (rv != CKR_FUNCTION_NOT_PARALLEL) return rv; } testcase_setup(); rc = do_TestAttributes(); rc = do_TestAttributesAESXTS(); testcase_print_result(); funcs->C_Finalize(NULL); return testcase_return(rc); } opencryptoki-opencryptoki-451d99c/testcases/pkcs11/copyobjects.c000066400000000000000000000317321520105705100251220ustar00rootroot00000000000000/* * 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 keyobj_no_copy = CK_INVALID_HANDLE; CK_OBJECT_HANDLE keyobj_copy = 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_OBJECT_HANDLE sixthobj = CK_INVALID_HANDLE; CK_OBJECT_HANDLE seventhobj = 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_ATTRIBUTE aes_tmpl_no_copy[] = { {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)}, {CKA_COPYABLE, &false, sizeof(false)} }; CK_ATTRIBUTE aes_tmpl_copy[] = { {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)}, {CKA_COPYABLE, &true, sizeof(true)} }; 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(""); testcase_rw_session(); testcase_user_login(); // Create an AES Key Object. rc = funcs->C_CreateObject(session, aes_tmpl, 4, &keyobj); if (rc != CKR_OK) { if (is_rejected_by_policy(rc, session)) { testcase_skip("Key import is not allowed by policy"); goto testcase_cleanup; } testcase_error("C_CreateObject() rc = %s", p11_get_ckr(rc)); goto testcase_cleanup; } rc = funcs->C_CreateObject(session, aes_tmpl_no_copy, 5, &keyobj_no_copy); if (rc != CKR_OK) { if (is_rejected_by_policy(rc, session)) { testcase_skip("Key import is not allowed by policy"); goto testcase_cleanup; } testcase_error("C_CreateObject() rc = %s", p11_get_ckr(rc)); goto testcase_cleanup; } rc = funcs->C_CreateObject(session, aes_tmpl_copy, 5, &keyobj_copy); if (rc != CKR_OK) { if (is_rejected_by_policy(rc, session)) { testcase_skip("Key import is not allowed by policy"); goto testcase_cleanup; } 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_ATTRIBUTE_READ_ONLY) testcase_pass("C_CopyObject() did not copy the object. rc = %s " "(as expected)", p11_get_ckr(rc)); else testcase_fail("C_CopyObject() should have failed."); // Testcase #6 - Copy object that has CKA_COPYABLE=FALSE, // this should fail with CKR_ACTION_PROHIBITED testcase_new_assertion(); rc = funcs->C_CopyObject(session, keyobj_no_copy, null_tmpl, 0, &sixthobj); if (rc == CKR_ACTION_PROHIBITED) testcase_pass("C_CopyObject() did not copy the object. rc = %s " "(as expected)", p11_get_ckr(rc)); else testcase_fail("C_CopyObject() should have failed with " "CKR_ACTION_PROHIBITED, but got rc = %s.", p11_get_ckr(rc)); // Testcase #7 - Copy object that has CKA_COPYABLE=TRUE, // this should be allowed testcase_new_assertion(); rc = funcs->C_CopyObject(session, keyobj_copy, null_tmpl, 0, &seventhobj); if (rc != CKR_OK) { testcase_fail("C_CopyObject() rc = %s", p11_get_ckr(rc)); goto testcase_cleanup; } testcase_pass("C_CopyObject) succeeded"); testcase_cleanup: funcs->C_DestroyObject(session, keyobj); funcs->C_DestroyObject(session, keyobj_no_copy); funcs->C_DestroyObject(session, keyobj_copy); 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); funcs->C_DestroyObject(session, sixthobj); funcs->C_DestroyObject(session, seventhobj); 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; rv = funcs->C_GetFunctionStatus(hsess); if (rv != CKR_FUNCTION_NOT_PARALLEL) return rv; rv = funcs->C_CancelFunction(hsess); if (rv != CKR_FUNCTION_NOT_PARALLEL) return rv; } testcase_setup(); rc = do_CopyObjects(); testcase_print_result(); funcs->C_Finalize(NULL); return testcase_return(rc); } opencryptoki-opencryptoki-451d99c/testcases/pkcs11/destroyobjects.c000066400000000000000000000224301520105705100256340ustar00rootroot00000000000000/* * 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_OBJECT_HANDLE keyobj_no_destroy = CK_INVALID_HANDLE; CK_ULONG i, num_objs = 0, find_count, found = 0; CK_MECHANISM mech; CK_BBOOL false = CK_FALSE; CK_BBOOL true = TRUE; CK_KEY_TYPE aes_type = CKK_AES; CK_OBJECT_CLASS key_class = CKO_SECRET_KEY; CK_CHAR aes_value[32] = "This is a fake aes key."; CK_CHAR test_id[5 + 1] = "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, strlen((char *)test_id)}, {CKA_VALUE, &aes_value, sizeof(aes_value)} }; CK_ATTRIBUTE aes_tmpl_no_destroy[] = { {CKA_CLASS, &key_class, sizeof(key_class)}, {CKA_KEY_TYPE, &aes_type, sizeof(aes_type)}, {CKA_ID, &test_id, strlen((char *)test_id)}, {CKA_VALUE, &aes_value, sizeof(aes_value)}, {CKA_DESTROYABLE, &false, sizeof(false)}, }; CK_ATTRIBUTE aesgen_tmpl[] = { {CKA_CLASS, &key_class, sizeof(key_class)}, {CKA_KEY_TYPE, &aes_type, sizeof(aes_type)}, {CKA_ID, &test_id, strlen((char *)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, strlen((char *)test_id)} }; testcase_begin(""); 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) { if (is_rejected_by_policy(rc, session)) { testcase_skip("Key generation is not allowed by policy"); goto testcase_cleanup; } 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) { if (is_rejected_by_policy(rc, session)) { testcase_skip("Key generation is not allowed by policy"); goto testcase_cleanup; } testcase_error("C_GenerateObject() rc = %s", p11_get_ckr(rc)); goto testcase_cleanup; } num_objs++; } testcase_new_assertion(); /* 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 */ testcase_new_assertion(); 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 */ testcase_new_assertion(); 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_new_assertion(); /* Create a key object with CKA_DESTROYABLE=FALSE */ rc = funcs->C_CreateObject(session, aes_tmpl_no_destroy, 5, &keyobj_no_destroy); if (rc != CKR_OK) { testcase_error("C_CreateObject() rc = %s", p11_get_ckr(rc)); goto testcase_cleanup; } /* * Try to delete the non-destroyable object, should fail with * CKR_ACTION_PROHIBITED */ rc = funcs->C_DestroyObject(session, keyobj_no_destroy); if (rc == CKR_ACTION_PROHIBITED) { testcase_pass("C_DestroyObject() did not delete the object. rc = %s " "(as expected)", p11_get_ckr(rc)); } else { testcase_fail("C_DestroyObject() should have failed with " "CKR_ACTION_PROHIBITED, but got rc = %s.", p11_get_ckr(rc)); keyobj_no_destroy = CK_INVALID_HANDLE; } testcase_cleanup: if (num_objs) { for (i = 0; i < num_objs; i++) funcs->C_DestroyObject(session, keyobj[i]); } if (keyobj_no_destroy != CK_INVALID_HANDLE) { CK_ATTRIBUTE update_destroyable_true[] = { {CKA_DESTROYABLE, &true, sizeof(true)}, }; funcs->C_SetAttributeValue(session, keyobj_no_destroy, update_destroyable_true, 1); funcs->C_DestroyObject(session, keyobj_no_destroy); } 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; rv = funcs->C_GetFunctionStatus(hsess); if (rv != CKR_FUNCTION_NOT_PARALLEL) return rv; rv = funcs->C_CancelFunction(hsess); if (rv != CKR_FUNCTION_NOT_PARALLEL) return rv; } testcase_setup(); rc = do_DestroyObjects(); testcase_print_result(); funcs->C_Finalize(NULL); return testcase_return(rc); } opencryptoki-opencryptoki-451d99c/testcases/pkcs11/findobjects.c000066400000000000000000000213431520105705100250650ustar00rootroot00000000000000/* * 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) { if (is_rejected_by_policy(rc, session)) { testcase_skip("key import is not allowed by policy"); return 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) { if (is_rejected_by_policy(rc, session)) { testcase_skip("EC key generation is not allowed by policy"); goto testcase_cleanup; } 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) { if (is_rejected_by_policy(rc, session)) { testcase_skip("EC key generation is not allowed by policy"); goto testcase_cleanup; } 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) { if (is_rejected_by_policy(rc, session)) { testcase_skip("EC key generation is not allowed by policy"); goto testcase_cleanup; } 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; rv = funcs->C_GetFunctionStatus(hsess); if (rv != CKR_FUNCTION_NOT_PARALLEL) return rv; rv = funcs->C_CancelFunction(hsess); if (rv != CKR_FUNCTION_NOT_PARALLEL) return rv; } testcase_setup(); rc = do_FindObjects(); testcase_print_result(); funcs->C_Finalize(NULL); return testcase_return(rc); } opencryptoki-opencryptoki-451d99c/testcases/pkcs11/gen_purpose.c000066400000000000000000000501101520105705100251130ustar00rootroot00000000000000/* * 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 retrieved successfully"); 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 used with an 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 successfully returned mechanism count."); else testcase_fail("C_GetMechanismList did 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 returned 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 public 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 public 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 failed: 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 #3 failed: 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; rv = funcs->C_GetFunctionStatus(hsess); if (rv != CKR_FUNCTION_NOT_PARALLEL) return rv; rv = funcs->C_CancelFunction(hsess); if (rv != CKR_FUNCTION_NOT_PARALLEL) return rv; } testcase_setup(); rv = api_driver(); testcase_print_result(); funcs->C_Finalize(NULL_PTR); return testcase_return(rv); } opencryptoki-opencryptoki-451d99c/testcases/pkcs11/generate_keypair.c000066400000000000000000000217211520105705100261110ustar00rootroot00000000000000/* * 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; if (!mech_supported(SLOT_ID, CKM_RSA_PKCS_KEY_PAIR_GEN)) { testcase_skip("Mechanism CKM_RSA_PKCS_KEY_PAIR_GEN is not supported with slot " "%lu. Skipping key check", SLOT_ID); goto testcase_cleanup; } /* 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) { if (is_rejected_by_policy(rc, session)) { testcase_skip("Key generation is not allowed by policy"); goto testcase_cleanup; } 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; rv = funcs->C_GetFunctionStatus(hsess); if (rv != CKR_FUNCTION_NOT_PARALLEL) return rv; rv = funcs->C_CancelFunction(hsess); if (rv != CKR_FUNCTION_NOT_PARALLEL) return rv; } testcase_setup(); rc = do_GenerateKeyPairRSA(); testcase_print_result(); return testcase_return(rc); } opencryptoki-opencryptoki-451d99c/testcases/pkcs11/get_interface.c000066400000000000000000000454541520105705100254030ustar00rootroot00000000000000/* * 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 "pkcs11types.h" #include "regress.h" static int get_interface_test(void) { CK_FUNCTION_LIST_3_2 *tfn; CK_INTERFACE *interface; CK_VERSION version, *v; CK_SLOT_ID slot; CK_FLAGS flags; CK_RV rv; int rc = -1; testcase_new_assertion(); flags = 0ULL; rv = funcs3->C_GetInterface(NULL, NULL, NULL, flags); if (rv != CKR_ARGUMENTS_BAD) { testcase_fail("C_GetInterface returned %s.\n", p11_get_ckr(rv)); goto ret; } flags = ~0UL; rv = funcs3->C_GetInterface((CK_UTF8CHAR *)"PKCS 11", NULL, &interface, flags); if (rv != CKR_FUNCTION_FAILED) { testcase_fail("C_GetInterface returned %s.\n", p11_get_ckr(rv)); goto ret; } version.major = 0; version.minor = 0; flags = 0ULL; rv = funcs3->C_GetInterface((CK_UTF8CHAR *)"PKCS 11", &version, &interface, flags); if (rv != CKR_FUNCTION_FAILED) { testcase_fail("C_GetInterface returned %s.\n", p11_get_ckr(rv)); goto ret; } flags = 0ULL; rv = funcs3->C_GetInterface((CK_UTF8CHAR *)"INVALID", NULL, &interface, flags); if (rv != CKR_FUNCTION_FAILED) { testcase_fail("C_GetInterface returned %s.\n", p11_get_ckr(rv)); goto ret; } flags = 0ULL; rv = funcs3->C_GetInterface(NULL, NULL, &interface, flags); if (rv != CKR_OK) { testcase_fail("C_GetInterface returned %s.\n", p11_get_ckr(rv)); goto ret; } v = (CK_VERSION *)interface->pFunctionList; printf("%s\n", "Default interface:"); printf("pInterfaceName %s\n", interface->pInterfaceName); printf("pFunctionList version %u.%u\n", v->major, v->minor); printf("flags 0x%016lx\n", interface->flags); flags = 0ULL; rv = funcs3->C_GetInterface((CK_UTF8CHAR *)"PKCS 11", NULL, &interface, flags); if (rv != CKR_OK) { testcase_fail("C_GetInterface returned %s.\n", p11_get_ckr(rv)); goto ret; } if (strcmp((char *)interface->pInterfaceName, "PKCS 11") != 0) { testcase_fail("Returned interface name: %s.\n", interface->pInterfaceName); goto ret; } v = (CK_VERSION *)interface->pFunctionList; printf("%s\n", "Default PKCS #11 interface:"); printf("pInterfaceName %s\n", interface->pInterfaceName); printf("pFunctionList version %u.%u\n", v->major, v->minor); printf("flags 0x%016lx\n", interface->flags); version.major = 1; version.minor = 0; flags = 0ULL; rv = funcs3->C_GetInterface((CK_UTF8CHAR *)"Vendor IBM", NULL, &interface, flags); if (rv != CKR_OK) { testcase_fail("C_GetInterface returned %s.\n", p11_get_ckr(rv)); goto ret; } if (strcmp((char *)interface->pInterfaceName, "Vendor IBM") != 0) { testcase_fail("Returned interface name: %s.\n", interface->pInterfaceName); goto ret; } v = (CK_VERSION *)interface->pFunctionList; printf("%s\n", "Vendor defined interface (IBM):"); printf("pInterfaceName %s\n", interface->pInterfaceName); printf("pFunctionList version %u.%u\n", v->major, v->minor); printf("flags 0x%016lx\n", interface->flags); version.major = 2; version.minor = 40; flags = 0ULL; rv = funcs3->C_GetInterface((CK_UTF8CHAR *)"PKCS 11", &version, &interface, flags); if (rv != CKR_OK) { testcase_fail("C_GetInterface returned %s.\n", p11_get_ckr(rv)); goto ret; } if (strcmp((char *)interface->pInterfaceName, "PKCS 11") != 0) { testcase_fail("Returned interface name: %s.\n", interface->pInterfaceName); goto ret; } v = (CK_VERSION *)interface->pFunctionList; if (v->major != version.major || v->minor != version.minor) { testcase_fail("Returned version: %u.%u.\n", v->major, v->minor); goto ret; } printf("%s\n", "PKCS #11 version 2.40 interface:"); printf("pInterfaceName %s\n", interface->pInterfaceName); printf("pFunctionList version %u.%u\n", v->major, v->minor); printf("flags 0x%016lx\n", interface->flags); version.major = 3; version.minor = 0; flags = 0ULL; rv = funcs3->C_GetInterface((CK_UTF8CHAR *)"PKCS 11", &version, &interface, flags); if (rv != CKR_OK) { testcase_fail("C_GetInterface returned %s.\n", p11_get_ckr(rv)); goto ret; } if (strcmp((char *)interface->pInterfaceName, "PKCS 11") != 0) { testcase_fail("Returned interface name: %s.\n", interface->pInterfaceName); goto ret; } v = (CK_VERSION *)interface->pFunctionList; if (v->major != version.major || v->minor != version.minor) { testcase_fail("Returned version: %u.%u.\n", v->major, v->minor); goto ret; } printf("%s\n", "PKCS #11 version 3.0 interface:"); printf("pInterfaceName %s\n", interface->pInterfaceName); printf("pFunctionList version %u.%u\n", v->major, v->minor); printf("flags 0x%016lx\n", interface->flags); version.major = 3; version.minor = 2; flags = 0ULL; rv = funcs3->C_GetInterface((CK_UTF8CHAR *)"PKCS 11", &version, &interface, flags); if (rv != CKR_OK) { testcase_fail("C_GetInterface returned %s.\n", p11_get_ckr(rv)); goto ret; } if (strcmp((char *)interface->pInterfaceName, "PKCS 11") != 0) { testcase_fail("Returned interface name: %s.\n", interface->pInterfaceName); goto ret; } v = (CK_VERSION *)interface->pFunctionList; if (v->major != version.major || v->minor != version.minor) { testcase_fail("Returned version: %u.%u.\n", v->major, v->minor); goto ret; } printf("%s\n", "PKCS #11 version 3.2 interface:"); printf("pInterfaceName %s\n", interface->pInterfaceName); printf("pFunctionList version %u.%u\n", v->major, v->minor); printf("flags 0x%016lx\n", interface->flags); tfn = (CK_FUNCTION_LIST_3_2 *)interface->pFunctionList; if (tfn->C_Initialize == NULL || tfn->C_Finalize == NULL || tfn->C_GetInfo == NULL || tfn->C_GetFunctionList == NULL || tfn->C_GetSlotList == NULL || tfn->C_GetSlotInfo == NULL || tfn->C_GetTokenInfo == NULL || tfn->C_GetMechanismList == NULL || tfn->C_GetMechanismInfo == NULL || tfn->C_InitToken == NULL || tfn->C_InitPIN == NULL || tfn->C_SetPIN == NULL || tfn->C_OpenSession == NULL || tfn->C_CloseSession == NULL || tfn->C_CloseAllSessions == NULL || tfn->C_GetSessionInfo == NULL || tfn->C_GetOperationState == NULL || tfn->C_SetOperationState == NULL || tfn->C_Login == NULL || tfn->C_Logout == NULL || tfn->C_CreateObject == NULL || tfn->C_CopyObject == NULL || tfn->C_DestroyObject == NULL || tfn->C_GetObjectSize == NULL || tfn->C_GetAttributeValue == NULL || tfn->C_SetAttributeValue == NULL || tfn->C_FindObjectsInit == NULL || tfn->C_FindObjects == NULL || tfn->C_FindObjectsFinal == NULL || tfn->C_EncryptInit == NULL || tfn->C_Encrypt == NULL || tfn->C_EncryptUpdate == NULL || tfn->C_EncryptFinal == NULL || tfn->C_DecryptInit == NULL || tfn->C_Decrypt == NULL || tfn->C_DecryptUpdate == NULL || tfn->C_DecryptFinal == NULL || tfn->C_DigestInit == NULL || tfn->C_Digest == NULL || tfn->C_DigestUpdate == NULL || tfn->C_DigestKey == NULL || tfn->C_DigestFinal == NULL || tfn->C_SignInit == NULL || tfn->C_Sign == NULL || tfn->C_SignUpdate == NULL || tfn->C_SignFinal == NULL || tfn->C_SignRecoverInit == NULL || tfn->C_SignRecover == NULL || tfn->C_VerifyInit == NULL || tfn->C_Verify == NULL || tfn->C_VerifyUpdate == NULL || tfn->C_VerifyFinal == NULL || tfn->C_VerifyRecoverInit == NULL || tfn->C_VerifyRecover == NULL || tfn->C_DigestEncryptUpdate == NULL || tfn->C_DecryptDigestUpdate == NULL || tfn->C_SignEncryptUpdate == NULL || tfn->C_DecryptVerifyUpdate == NULL || tfn->C_GenerateKey == NULL || tfn->C_GenerateKeyPair == NULL || tfn->C_WrapKey == NULL || tfn->C_UnwrapKey == NULL || tfn->C_DeriveKey == NULL || tfn->C_SeedRandom == NULL || tfn->C_GenerateRandom == NULL || tfn->C_GetFunctionStatus == NULL || tfn->C_CancelFunction == NULL || tfn->C_WaitForSlotEvent == NULL /* Additional PKCS #11 3.0 functions */ || tfn->C_GetInterfaceList == NULL || tfn->C_GetInterface == NULL || tfn->C_LoginUser == NULL || tfn->C_SessionCancel == NULL || tfn->C_MessageEncryptInit == NULL || tfn->C_EncryptMessage == NULL || tfn->C_EncryptMessageBegin == NULL || tfn->C_EncryptMessageNext == NULL || tfn->C_MessageEncryptFinal == NULL || tfn->C_MessageDecryptInit == NULL || tfn->C_DecryptMessage == NULL || tfn->C_DecryptMessageBegin == NULL || tfn->C_DecryptMessageNext == NULL || tfn->C_MessageDecryptFinal == NULL || tfn->C_MessageSignInit == NULL || tfn->C_SignMessage == NULL || tfn->C_SignMessageBegin == NULL || tfn->C_SignMessageNext == NULL || tfn->C_MessageSignFinal == NULL || tfn->C_MessageVerifyInit == NULL || tfn->C_VerifyMessage == NULL || tfn->C_VerifyMessageBegin == NULL || tfn->C_VerifyMessageNext == NULL || tfn->C_MessageVerifyFinal == NULL /* Additional PKCS #11 3.2 functions */ || tfn->C_EncapsulateKey == NULL || tfn->C_DecapsulateKey == NULL || tfn->C_VerifySignatureInit == NULL || tfn->C_VerifySignature == NULL || tfn->C_VerifySignatureUpdate == NULL || tfn->C_VerifySignatureFinal == NULL || tfn->C_GetSessionValidationFlags == NULL || tfn->C_AsyncComplete == NULL || tfn->C_AsyncGetID == NULL || tfn->C_AsyncJoin == NULL || tfn->C_WrapKeyAuthenticated == NULL || tfn->C_UnwrapKeyAuthenticated == NULL) { testcase_fail("%s", "Returned CK_FUNCTION_LIST_3_2 contains" " a NULL function pointer.\n"); goto ret; } /* * Function pointers are != NULL. * Now check if they are valid. */ slot = 0; tfn->C_Initialize(NULL); tfn->C_Finalize(NULL); tfn->C_GetInfo(NULL); tfn->C_GetFunctionList(NULL); tfn->C_GetSlotList(CK_FALSE, NULL, NULL); tfn->C_GetSlotInfo(slot, NULL); tfn->C_GetTokenInfo(slot, NULL); tfn->C_GetMechanismList(slot, NULL, NULL); tfn->C_GetMechanismInfo(slot, 0UL, NULL); tfn->C_InitToken(slot, NULL, 0UL, NULL); tfn->C_InitPIN(0UL, NULL, 0UL); tfn->C_SetPIN(0UL, NULL, 0UL, NULL, 0UL); tfn->C_OpenSession(slot, 0UL, NULL, NULL, NULL); tfn->C_CloseSession(0UL); tfn->C_CloseAllSessions(slot); tfn->C_GetSessionInfo(0UL, NULL); tfn->C_GetOperationState(0UL, NULL, NULL); tfn->C_SetOperationState(0UL, NULL, 0UL, 0UL, 0UL); tfn->C_Login(0UL, 0UL, NULL, 0UL); tfn->C_Logout(0UL); tfn->C_CreateObject(0UL, NULL, 0UL, NULL); tfn->C_CopyObject(0UL, 0UL, NULL, 0UL, NULL); tfn->C_DestroyObject(0UL, 0UL); tfn->C_GetObjectSize(0UL, 0UL, NULL); tfn->C_GetAttributeValue(0UL, 0UL, NULL, 0UL); tfn->C_SetAttributeValue(0UL, 0UL, NULL, 0UL); tfn->C_FindObjectsInit(0UL, NULL, 0UL); tfn->C_FindObjects(0UL, NULL, 0UL, NULL); tfn->C_FindObjectsFinal(0UL); tfn->C_EncryptInit(0UL, NULL, 0UL); tfn->C_Encrypt(0UL, NULL, 0UL, NULL, NULL); tfn->C_EncryptUpdate(0UL, NULL, 0UL, NULL, NULL); tfn->C_EncryptFinal(0UL, NULL, NULL); tfn->C_DecryptInit(0UL, NULL, 0UL); tfn->C_Decrypt(0UL, NULL, 0UL, NULL, NULL); tfn->C_DecryptUpdate(0UL, NULL, 0UL, NULL, NULL); tfn->C_DecryptFinal(0UL, NULL, NULL); tfn->C_DigestInit(0UL, NULL); tfn->C_Digest(0UL, NULL, 0UL, NULL, 0UL); tfn->C_DigestUpdate(0UL, NULL, 0UL); tfn->C_DigestKey(0UL, 0UL); tfn->C_DigestFinal(0UL, NULL, NULL); tfn->C_SignInit(0UL, NULL, 0UL); tfn->C_Sign(0UL, NULL, 0UL, NULL, NULL); tfn->C_SignUpdate(0UL, NULL, 0UL); tfn->C_SignFinal(0UL, NULL, NULL); tfn->C_SignRecoverInit(0UL, NULL, 0UL); tfn->C_SignRecover(0UL, NULL, 0UL, NULL, NULL); tfn->C_VerifyInit(0UL, NULL, 0UL); tfn->C_Verify(0UL, NULL, 0UL, NULL, 0UL); tfn->C_VerifyUpdate(0UL, NULL, 0UL); tfn->C_VerifyFinal(0UL, NULL, 0UL); tfn->C_VerifyRecoverInit(0UL, NULL, 0UL); tfn->C_VerifyRecover(0UL, NULL, 0UL, NULL, NULL); tfn->C_DigestEncryptUpdate(0UL, NULL, 0UL, NULL, NULL); tfn->C_DecryptDigestUpdate(0UL, NULL, 0UL, NULL, NULL); tfn->C_SignEncryptUpdate(0UL, NULL, 0UL, NULL, NULL); tfn->C_DecryptVerifyUpdate(0UL, NULL, 0UL, NULL, NULL); tfn->C_GenerateKey(0UL, NULL, NULL, 0UL, NULL); tfn->C_GenerateKeyPair(0UL, NULL, NULL, 0UL, NULL, 0UL, NULL, NULL); tfn->C_WrapKey(0UL, NULL, 0UL, 0UL, NULL, NULL); tfn->C_UnwrapKey(0UL, NULL, 0UL, NULL, 0UL, NULL, 0UL, NULL); tfn->C_DeriveKey(0UL, NULL, 0UL, NULL, 0UL, NULL); tfn->C_SeedRandom(0UL, NULL, 0UL); tfn->C_GenerateRandom(0UL, NULL, 0UL); tfn->C_GetFunctionStatus(0UL); tfn->C_CancelFunction(0UL); tfn->C_WaitForSlotEvent(0UL, &slot, NULL); /* Additional PKCS #11 3.0 functions */ tfn->C_GetInterfaceList(NULL, NULL); tfn->C_GetInterface(NULL, NULL, NULL, 0UL); tfn->C_LoginUser(0UL, 0UL, NULL, 0UL, NULL, 0UL); tfn->C_SessionCancel(0UL, 0UL); tfn->C_MessageEncryptInit(0UL, NULL, 0UL); tfn->C_EncryptMessage(0UL, NULL, 0UL, NULL, 0UL, NULL, 0UL, NULL, 0UL); tfn->C_EncryptMessageBegin(0UL, NULL, 0UL, NULL, 0UL); tfn->C_EncryptMessageNext(0UL, NULL, 0UL, NULL, 0UL, NULL, NULL, 0UL); tfn->C_MessageEncryptFinal(0UL); tfn->C_MessageDecryptInit(0UL, NULL, 0UL); tfn->C_DecryptMessage(0UL, NULL, 0UL, NULL, 0UL, NULL, 0UL, NULL, 0UL); tfn->C_DecryptMessageBegin(0UL, NULL, 0UL, NULL, 0UL); tfn->C_DecryptMessageNext(0UL, NULL, 0UL, NULL, 0UL, NULL, NULL, 0UL); tfn->C_MessageDecryptFinal(0UL); tfn->C_MessageSignInit(0UL, NULL, 0UL); tfn->C_SignMessage(0UL, NULL, 0UL, NULL, 0UL, NULL, NULL); tfn->C_SignMessageBegin(0UL, NULL, 0UL); tfn->C_SignMessageNext(0UL, NULL, 0UL, NULL, 0UL, NULL, NULL); tfn->C_MessageSignFinal(0UL); tfn->C_MessageVerifyInit(0UL, NULL, 0UL); tfn->C_VerifyMessage(0UL, NULL, 0UL, NULL, 0UL, NULL, 0UL); tfn->C_VerifyMessageBegin(0UL, NULL, 0UL); tfn->C_VerifyMessageNext(0UL, NULL, 0UL, NULL, 0UL, NULL, 0UL); tfn->C_MessageVerifyFinal(0UL); /* Additional PKCS #11 3.2 functions */ tfn->C_EncapsulateKey(0UL, NULL, 0UL, NULL, 0UL, NULL, 0UL, NULL); tfn->C_DecapsulateKey(0UL, NULL, 0UL, NULL, 0UL, NULL, 0UL, NULL); tfn->C_VerifySignatureInit(0UL, NULL, 0UL, NULL, 0UL); tfn->C_VerifySignature(0UL, NULL, 0UL); tfn->C_VerifySignatureUpdate(0UL, NULL, 0UL); tfn->C_VerifySignatureFinal(0UL); tfn->C_GetSessionValidationFlags(0UL, 0UL, NULL); tfn->C_AsyncComplete(0UL, NULL, NULL); tfn->C_AsyncGetID(0UL, NULL, NULL); tfn->C_AsyncJoin(0UL, NULL, 0UL, NULL, 0UL); tfn->C_WrapKeyAuthenticated(0UL, NULL, 0UL, 0UL, NULL, 0UL, NULL, NULL); tfn->C_UnwrapKeyAuthenticated(0UL, NULL, 0UL, NULL, 0UL, NULL, 0UL, NULL, 0UL, NULL); testcase_pass("C_GetInterface works.\n"); rc = 0; ret: return rc; } static int get_interface_list_test(void) { CK_INTERFACE *il = NULL; CK_ULONG nmemb = 0UL, i; CK_VERSION *version; CK_RV rv; int rc = -1; testcase_new_assertion(); rv = funcs3->C_GetInterfaceList(NULL, NULL); if (rv != CKR_ARGUMENTS_BAD) { testcase_fail("C_GetInterfaceList returned %s.\n", p11_get_ckr(rv)); goto ret; } rv = funcs3->C_GetInterfaceList(NULL, &nmemb); if (rv != CKR_OK) { testcase_fail("C_GetInterfaceList returned %s.\n", p11_get_ckr(rv)); goto ret; } if (nmemb == 0) { testcase_fail("C_GetInterfaceList interface list has" " %lu elements.\n", nmemb); goto ret; } il = calloc(nmemb, sizeof(*il)); if (il == NULL) { testcase_error("calloc failed.\n"); goto ret; } nmemb--; rv = funcs3->C_GetInterfaceList(il, &nmemb); if (rv != CKR_BUFFER_TOO_SMALL) { testcase_fail("C_GetInterfaceList returned %s.\n", p11_get_ckr(rv)); goto ret; } rv = funcs3->C_GetInterfaceList(il, &nmemb); if (rv != CKR_OK) { testcase_fail("C_GetInterfaceList returned %s.\n", p11_get_ckr(rv)); goto ret; } for (i = 0UL; i < nmemb; i++) { if (strncmp((char *)il[i].pInterfaceName, "PKCS 11", strlen("PKCS 11")) != 0 && strncmp((char *)il[i].pInterfaceName, "Vendor ", strlen("Vendor ")) != 0) { testcase_fail("Invalid interface name.\n"); goto ret; } if (il[i].pFunctionList == NULL) { testcase_fail("%s", "Interface with NULL function list.\n"); goto ret; } if ((il[i].flags & ~CKF_INTERFACE_FORK_SAFE) != 0) { testcase_fail("Interface with unknown flags: 0x%016lx.\n", il[i].flags); goto ret; } version = (CK_VERSION *)il[i].pFunctionList; printf("Interface %lu:\n", i); printf("pInterfaceName %s\n", il[i].pInterfaceName); printf("pFunctionList version %u.%u\n", version->major, version->minor); printf("flags 0x%016lx\n", il[i].flags); } testcase_pass("C_GetInterfaceList works.\n"); rc = 0; ret: free(il); return rc; } int main(void) { int rc = -1; testcase_setup(); if (do_GetFunctionList() != TRUE) { testcase_error("%s", "do_GetFunctionList() failed.\n"); goto ret; } rc = get_interface_list_test(); if (rc) goto ret; rc = get_interface_test(); ret: testcase_print_result(); return testcase_return(rc); } opencryptoki-opencryptoki-451d99c/testcases/pkcs11/getobjectsize.c000066400000000000000000000077071520105705100254440ustar00rootroot00000000000000/* * 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(); testcase_new_assertion(); // Create an AES Key Object. rc = funcs->C_CreateObject(session, aes_tmpl, 4, &keyobj); if (rc != CKR_OK) { if (is_rejected_by_policy(rc, session)) { testcase_skip("Key import is not allowed by policy"); goto testcase_cleanup; } 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; } testcase_pass("C_GetObjectSize test passed"); 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; rv = funcs->C_GetFunctionStatus(hsess); if (rv != CKR_FUNCTION_NOT_PARALLEL) return rv; rv = funcs->C_CancelFunction(hsess); if (rv != CKR_FUNCTION_NOT_PARALLEL) return rv; } testcase_setup(); rv = do_GetObjectSize(); testcase_print_result(); funcs->C_Finalize(NULL); /* make sure we return non-zero if rv is non-zero */ return testcase_return(rv); } opencryptoki-opencryptoki-451d99c/testcases/pkcs11/hw_fn.c000066400000000000000000000260251520105705100236760ustar00rootroot00000000000000/* * 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 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)} }; testcase_begin("do_HW_Feature_Search"); testcase_new_assertion(); /* Create the 5 test objects */ rc = funcs->C_CreateObject(sess, obj1_template, 4, &h_obj1); if (rc != CKR_OK) { testcase_fail("C_CreateObject #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_CreateObject(sess, obj2_template, 5, &h_obj2); if (rc != CKR_OK) { testcase_fail("C_CreateObject #2, rc=%lx, %s", rc, p11_get_ckr(rc)); goto destroy_1; } rc = funcs->C_CreateObject(sess, counter1_template, 6, &h_counter1); if (rc != CKR_ATTRIBUTE_READ_ONLY) { testcase_fail("C_CreateObject #3, rc=%lx, %s", rc, p11_get_ckr(rc)); goto destroy_2; } rc = funcs->C_CreateObject(sess, counter2_template, 6, &h_counter2); if (rc != CKR_ATTRIBUTE_READ_ONLY) { testcase_fail("C_CreateObject #4, rc=%lx, %s", rc, p11_get_ckr(rc)); goto destroy_3; } rc = funcs->C_CreateObject(sess, clock_template, 4, &h_clock); if (rc != CKR_OK) { testcase_fail("C_CreateObject #5, rc=%lx, %s", rc, p11_get_ckr(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) { testcase_fail("C_FindObjectsInit #1, rc=%lx, %s", rc, p11_get_ckr(rc)); goto done; } rc = funcs->C_FindObjects(sess, obj_list, 10, &find_count); if (rc != CKR_OK) { testcase_fail("C_FindObjects #1, rc=%lx, %s", rc, p11_get_ckr(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) { testcase_error("%s:%d ERROR: C_FindObjects #1 should have found 2 objects!\n" " It found %lu objects", __FILE__, __LINE__, find_count); rc = -1; goto done; } if (obj_list[0] != h_obj1 && obj_list[0] != h_obj2) { testcase_error("%s:%d ERROR: C_FindObjects #1 found the wrong objects!", __FILE__, __LINE__); rc = -1; goto done; } if (obj_list[1] != h_obj1 && obj_list[1] != h_obj2) { testcase_error("%s:%d ERROR: C_FindObjects #1 found the wrong objects!", __FILE__, __LINE__); rc = -1; goto done; } rc = funcs->C_FindObjectsFinal(sess); if (rc != CKR_OK) { testcase_fail("C_FindObjectsFinal #1, rc=%lx, %s", rc, p11_get_ckr(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) { testcase_fail("C_FindObjectsInit #2, rc=%lx, %s", rc, p11_get_ckr(rc)); goto done; } rc = funcs->C_FindObjects(sess, obj_list, 10, &find_count); if (rc != CKR_OK) { testcase_fail("C_FindObjects #2, rc=%lx, %s", rc, p11_get_ckr(rc)); goto done; } if (find_count != 1) { testcase_error("%s:%d ERROR: C_FindObjects #2 should have found 1 object!" " It found %lu objects\n", __FILE__, __LINE__, find_count); funcs->C_FindObjectsFinal(sess); 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) { testcase_error("%s:%d ERROR: C_FindObjects #2 found the wrong\n" " objects!", __FILE__, __LINE__); rc = -1; } } rc = funcs->C_FindObjectsFinal(sess); if (rc != CKR_OK) { testcase_fail("C_FindObjectsFinal #2, rc=%lx, %s", rc, p11_get_ckr(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); if (t_errors > 0) testcase_notice("do_HW_Feature_Search ended with %ld error(s)", t_errors); else testcase_pass("do_HW_Feature_Search passed"); return rc; } 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) { if (i + 1 >= argc) { printf("Slot number missing\n"); return -1; } slot_id = atoi(argv[i + 1]); i++; break; } } printf("Using slot %lu...\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) { testcase_fail("C_Initialize, rc=%lx, %s", rc, p11_get_ckr(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) { testcase_fail("C_OpenSession #1, rc=%lx, %s", rc, p11_get_ckr(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) { testcase_fail("C_Login #1, rc=%lx, %s", rc, p11_get_ckr(rc)); goto session_close; } testcase_setup(); rc = do_HW_Feature_Search(); if (rc) goto logout; logout: rc = funcs->C_Logout(sess); if (rc != CKR_OK) testcase_fail("C_Logout #1, rc=%lx, %s", rc, p11_get_ckr(rc)); session_close: rc = funcs->C_CloseSession(sess); /* Close the session */ if (rc != CKR_OK) testcase_fail("C_CloseSession, rc=%lx, %s", rc, p11_get_ckr(rc)); done: /* Call C_Finalize and dlclose the library */ testcase_print_result(); return clean_up(); } int clean_up(void) { CK_RV rc = 0; rc = funcs->C_Finalize(NULL); if (rc != CKR_OK) testcase_fail("C_Finalize, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } opencryptoki-opencryptoki-451d99c/testcases/pkcs11/pkcs11.mk000066400000000000000000000053331520105705100240630ustar00rootroot00000000000000noinst_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/get_interface 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 testcases_pkcs11_get_interface_CFLAGS = ${testcases_inc} testcases_pkcs11_get_interface_LDADD = testcases/common/libcommon.la testcases_pkcs11_get_interface_SOURCES = \ testcases/pkcs11/get_interface.c opencryptoki-opencryptoki-451d99c/testcases/pkcs11/sess_mgmt.c000066400000000000000000001455401520105705100246020ustar00rootroot00000000000000/* * 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: %lu\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: 0x%lx\n", info->flags); printf(" ulDeviceError: %lu\n", info->ulDeviceError); } CK_RV do_OpenSession(void) { CK_SLOT_ID slot_id; CK_FLAGS flags; CK_SESSION_HANDLE handle; CK_RV rc; testcase_begin("do_OpenSession"); testcase_new_assertion(); slot_id = SLOT_ID; flags = CKF_SERIAL_SESSION; // read-only session rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &handle); if (rc != CKR_OK) { testcase_fail("C_OpenSession #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_CloseSession(handle); if (rc != CKR_OK) { testcase_fail("C_CloseSession #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } testcase_pass("do_OpenSession passed"); return rc; } CK_RV do_OpenSession2(void) { CK_SLOT_ID slot_id; CK_FLAGS flags; CK_SESSION_HANDLE h1, h2; CK_RV rc; testcase_begin("do_OpenSession2"); testcase_new_assertion(); slot_id = SLOT_ID; flags = CKF_SERIAL_SESSION; // read-only session rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &h1); if (rc != CKR_OK) { testcase_fail("C_OpenSession #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &h2); if (rc != CKR_OK) { testcase_fail("C_OpenSession #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_CloseSession(h1); if (rc != CKR_OK) { testcase_fail("C_CloseSession #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_CloseSession(h2); if (rc != CKR_OK) { testcase_fail("C_CloseSession #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } testcase_pass("do_OpenSession2 passed"); return rc; } CK_RV do_CloseAllSessions(void) { CK_SLOT_ID slot_id; CK_FLAGS flags; CK_SESSION_HANDLE h1, h2, h3; CK_RV rc; testcase_begin("do_CloseAllSessions"); testcase_new_assertion(); slot_id = SLOT_ID; flags = CKF_SERIAL_SESSION; // read-only session rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &h1); if (rc != CKR_OK) { testcase_fail("C_OpenSession #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &h2); if (rc != CKR_OK) { testcase_fail("C_OpenSession #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &h3); if (rc != CKR_OK) { testcase_fail("C_OpenSession #3, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_CloseAllSessions(slot_id); if (rc != CKR_OK) { testcase_fail("C_CloseAllSessions, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } testcase_pass("do_CloseAllSessions passed"); 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; testcase_begin("do_GetSessionInfo"); testcase_new_assertion(); slot_id = SLOT_ID; flags = CKF_SERIAL_SESSION; // read-only session rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &h1); if (rc != CKR_OK) { testcase_fail("C_OpenSession #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &h2); if (rc != CKR_OK) { testcase_fail("C_OpenSession #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &h3); if (rc != CKR_OK) { testcase_fail("C_OpenSession #3, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_GetSessionInfo(h1, &info); if (rc != CKR_OK) { testcase_fail("C_GetSessionInfo #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } dump_session_info(&info); rc = funcs->C_GetSessionInfo(h2, &info); if (rc != CKR_OK) { testcase_fail("C_GetSessionInfo #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } dump_session_info(&info); rc = funcs->C_GetSessionInfo(h2, &info); if (rc != CKR_OK) { testcase_fail("C_GetSessionInfo #3, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } dump_session_info(&info); rc = funcs->C_CloseAllSessions(slot_id); if (rc != CKR_OK) { testcase_fail("C_CloseAllSessions, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } testcase_pass("do_GetSessionInfo passed"); 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; testcase_begin("do_LoginLogout"); testcase_new_assertion(); 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) { testcase_fail("C_OpenSession #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &h2); if (rc != CKR_OK) { testcase_fail("C_OpenSession #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &h3); if (rc != CKR_OK) { testcase_fail("C_OpenSession #3, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } // log the first session in. all sessions should become USER sessions rc = funcs->C_Login(h1, CKU_USER, user_pin, user_pin_len); if (rc != CKR_OK) { testcase_fail("C_Login #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_GetSessionInfo(h1, &info); if (rc != CKR_OK) { testcase_fail("C_GetSessionInfo #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } dump_session_info(&info); rc = funcs->C_GetSessionInfo(h2, &info); if (rc != CKR_OK) { testcase_fail("C_GetSessionInfo #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } dump_session_info(&info); rc = funcs->C_GetSessionInfo(h2, &info); if (rc != CKR_OK) { testcase_fail("C_GetSessionInfo #3, rc=%lx, %s", rc, p11_get_ckr(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) { testcase_fail("C_Login #2, rc=%lx, %s", rc, p11_get_ckr(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) { testcase_fail("C_Logout #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_Logout(h2); if (rc != CKR_USER_NOT_LOGGED_IN) { testcase_fail("C_Logout #2, rc=%lx, %s", rc, p11_get_ckr(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) { testcase_fail("C_Login #4, rc=%lx, %s", rc, p11_get_ckr(rc)); PRINT_ERR(" Expected CKR_SESSION_READ_ONLY_EXISTS\n"); return -1; } rc = funcs->C_Login(h2, CKU_SO, so_pin, so_pin_len); if (rc != CKR_SESSION_READ_ONLY_EXISTS) { testcase_fail("C_Login #5, rc=%lx, %s", rc, p11_get_ckr(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) { testcase_fail("C_CloseAllSessions #1, rc=%lx, %s", rc, p11_get_ckr(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) { testcase_fail("C_OpenSession #4, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &h2); if (rc != CKR_OK) { testcase_fail("C_OpenSession #5, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } // now, try to log the SO in. this should work rc = funcs->C_Login(h1, CKU_SO, so_pin, so_pin_len); if (rc != CKR_OK) { testcase_fail("C_Login #6, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_GetSessionInfo(h1, &info); if (rc != CKR_OK) { testcase_fail("C_GetSessionInfo #4, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } dump_session_info(&info); rc = funcs->C_GetSessionInfo(h2, &info); if (rc != CKR_OK) { testcase_fail("C_GetSessionInfo #5, rc=%lx, %s", rc, p11_get_ckr(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) { testcase_fail("C_OpenSession #6, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_GetSessionInfo(h3, &info); if (rc != CKR_OK) { testcase_fail("C_GetSessionInfo #6, rc=%lx, %s", rc, p11_get_ckr(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) { testcase_fail("C_OpenSession #6, rc=%lx, %s", rc, p11_get_ckr(rc)); PRINT_ERR(" Expected CKR_SESSION_READ_WRITE_SO_EXISTS\n"); return -1; } // we're done...close all sessions rc = funcs->C_CloseAllSessions(slot_id); if (rc != CKR_OK) { testcase_fail("C_CloseAllSessions #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } testcase_pass("do_LoginLogout passed"); 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; testcase_begin("do_OperationState1"); testcase_new_assertion(); 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) { testcase_fail("C_OpenSession #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &session2); if (rc != CKR_OK) { testcase_fail("C_OpenSession #2, rc=%lx, %s", rc, p11_get_ckr(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) { testcase_fail("C_Login #1, rc=%lx, %s", rc, p11_get_ckr(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)) { testcase_skip("Mechanism %s not supported. (skipped)", 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) { testcase_fail("C_GenerateKey #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } // now encrypt the original data all at once using CBC mech.mechanism = CKM_AES_CBC; mech.ulParameterLen = 16; mech.pParameter = "1234qwerasdfyxcv"; rc = funcs->C_EncryptInit(session1, &mech, h_key); if (rc != CKR_OK) { testcase_fail("C_EncryptInit #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } crypt1_len = sizeof(crypt1); rc = funcs->C_Encrypt(session1, original, orig_len, crypt1, &crypt1_len); if (rc != CKR_OK) { testcase_fail("C_Encrypt #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } // now, begin encrypting multipart rc = funcs->C_EncryptInit(session1, &mech, h_key); if (rc != CKR_OK) { testcase_fail("C_EncryptInit #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } crypt2_len = sizeof(crypt2); rc = funcs->C_EncryptUpdate(session1, original, orig_len / 2, crypt2, &crypt2_len); if (rc != CKR_OK) { testcase_fail("C_EncryptUpdate #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } // save session #1's operation state rc = funcs->C_GetOperationState(session1, NULL, &op_state_len); if (rc != CKR_OK) { if (rc == CKR_STATE_UNSAVEABLE) { testcase_skip("Session state not savable for mechanism %s. (skipped)", mech_to_str(mech.mechanism)); funcs->C_CloseSession(session1); funcs->C_CloseSession(session2); return 0; } testcase_fail("C_GetOperationState #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } op_state = (CK_BYTE *) malloc(op_state_len); if (!op_state) { testcase_fail("HOST MEMORY ERROR"); return -1; } rc = funcs->C_GetOperationState(session1, op_state, &op_state_len); if (rc != CKR_OK) { testcase_fail("C_GetOperationState #1, rc=%lx, %s", rc, p11_get_ckr(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) { testcase_fail("C_EncryptUpdate #2, rc=%lx, %s", rc, p11_get_ckr(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) { testcase_fail("C_SetOperationState #1, rc=%lx, %s", rc, p11_get_ckr(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) { testcase_fail("C_EncryptUpdate #3, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } crypt2_len += i; trash2_len = sizeof(trash2); rc = funcs->C_EncryptFinal(session2, trash2, &trash2_len); if (rc != CKR_OK) { testcase_fail("C_EncryptFinal #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } if (crypt2_len != crypt1_len) { testcase_error("ERROR: Lengths don't match"); return -1; } if (memcmp(crypt1, crypt2, crypt1_len) != 0) { testcase_error("ERROR: crypt1 != crypt2"); return -1; } rc = funcs->C_CloseSession(session1); if (rc != CKR_OK) { testcase_fail("C_CloseSession #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_CloseSession(session2); if (rc != CKR_OK) { testcase_fail("C_CloseSession #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } testcase_pass("do_OperationState1 passed"); 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[32]; CK_BYTE digest2[32]; CK_BYTE digest3[32]; 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; testcase_begin("do_OperationState2"); testcase_new_assertion(); 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) { testcase_fail("C_OpenSession #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &session2); if (rc != CKR_OK) { testcase_fail("C_OpenSession #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &session3); if (rc != CKR_OK) { testcase_fail("C_OpenSession #3, rc=%lx, %s", rc, p11_get_ckr(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) { testcase_fail("C_Login #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } orig_len = sizeof(original); for (i = 0; i < orig_len; i++) original[i] = i % 255; mech.mechanism = CKM_SHA256; mech.pParameter = NULL; mech.ulParameterLen = 0; if (!mech_supported(slot_id, mech.mechanism)) { testcase_skip("Mechanism %s not supported. (skipped)", 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) { testcase_fail("C_DigestInit #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_DigestInit(session2, &mech); if (rc != CKR_OK) { testcase_fail("C_DigestInit #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_DigestInit(session3, &mech); if (rc != CKR_OK) { testcase_fail("C_DigestInit #3, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_DigestUpdate(session1, original, 499); if (rc != CKR_OK) { testcase_fail("C_DigestUpdate #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_DigestUpdate(session2, original, 27); if (rc != CKR_OK) { testcase_fail("C_DigestUpdate #2, rc=%lx, %s", rc, p11_get_ckr(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) { testcase_fail("C_Digest #1, rc=%lx, %s", rc, p11_get_ckr(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) { if (rc == CKR_STATE_UNSAVEABLE) { testcase_skip("Session state not savable for mechanism %s. (skipped)", mech_to_str(mech.mechanism)); funcs->C_CloseSession(session1); funcs->C_CloseSession(session2); funcs->C_CloseSession(session3); return 0; } testcase_fail("C_GetOperationState #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } op_state1 = (CK_BYTE *) malloc(op_state1_len); if (!op_state1) { testcase_fail("HOST MEMORY ERROR"); return -1; } rc = funcs->C_GetOperationState(session1, op_state1, &op_state1_len); if (rc != CKR_OK) { testcase_fail("C_GetOperationState #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_GetOperationState(session2, NULL, &op_state2_len); if (rc != CKR_OK) { if (rc == CKR_STATE_UNSAVEABLE) { testcase_skip("Session state not savable for mechanism %s. (skipped)", mech_to_str(mech.mechanism)); funcs->C_CloseSession(session1); funcs->C_CloseSession(session2); funcs->C_CloseSession(session3); return 0; } testcase_fail("C_GetOperationState #3, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } op_state2 = (CK_BYTE *) malloc(op_state2_len); if (!op_state2) { testcase_fail("HOST MEMORY ERROR"); return -1; } rc = funcs->C_GetOperationState(session2, op_state2, &op_state2_len); if (rc != CKR_OK) { testcase_fail("C_GetOperationState #4, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } // switch the states rc = funcs->C_SetOperationState(session1, op_state2, op_state2_len, 0, 0); if (rc != CKR_OK) { testcase_fail("C_SetOperationState #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_SetOperationState(session2, op_state1, op_state1_len, 0, 0); if (rc != CKR_OK) { testcase_fail("C_SetOperationState #3, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } // now, finish the digest operations rc = funcs->C_DigestUpdate(session2, original + 499, (orig_len - 499)); if (rc != CKR_OK) { testcase_fail("C_DigestUpdate #3, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_DigestUpdate(session1, original + 27, orig_len - 27); if (rc != CKR_OK) { testcase_fail("C_DigestUpdate #4, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } digest1_len = sizeof(digest1); rc = funcs->C_DigestFinal(session1, digest1, &digest1_len); if (rc != CKR_OK) { testcase_fail("C_DigestFinal #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } digest2_len = sizeof(digest2); rc = funcs->C_DigestFinal(session2, digest2, &digest2_len); if (rc != CKR_OK) { testcase_fail("C_DigestFinal #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } if (digest1_len != digest2_len || digest1_len != digest3_len) { PRINT_ERR(" ERROR: digested lengths don't match\n"); 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) { testcase_fail("C_CloseSession #3, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_CloseSession(session2); if (rc != CKR_OK) { testcase_fail("C_CloseSession #4, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_CloseSession(session3); if (rc != CKR_OK) { testcase_fail("C_CloseSession #5, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } testcase_pass("do_OperationState2 passed"); 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[32]; CK_BYTE digest2[32]; CK_BYTE digest3[32]; 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; testcase_begin("do_OperationState3"); testcase_new_assertion(); 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) { testcase_fail("C_OpenSession #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &session2); if (rc != CKR_OK) { testcase_fail("C_OpenSession #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &session3); if (rc != CKR_OK) { testcase_fail("C_OpenSession #3, rc=%lx, %s", rc, p11_get_ckr(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) { testcase_fail("C_Login #1, rc=%lx, %s", rc, p11_get_ckr(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)) { testcase_skip("Mechanism %s not supported. (skipped)", 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) { testcase_fail("C_GenerateKey #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } mech1.mechanism = CKM_AES_ECB; mech1.pParameter = NULL; mech1.ulParameterLen = 0; if (!mech_supported(slot_id, mech1.mechanism)) { testcase_skip("Mechanism %s not supported. (skipped)", 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) { testcase_fail("C_EncryptInit #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } mech2.mechanism = CKM_SHA256; mech2.pParameter = NULL; mech2.ulParameterLen = 0; if (!mech_supported(slot_id, mech2.mechanism)) { testcase_skip("Mechanism %s not supported. (skipped)", 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) { testcase_fail("C_DigestInit #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_DigestInit(session3, &mech2); if (rc != CKR_OK) { testcase_fail("C_DigestInit #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_DigestUpdate(session2, original, 499); if (rc != CKR_OK) { testcase_fail("C_DigestUpdate #1, rc=%lx, %s", rc, p11_get_ckr(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) { testcase_fail("C_Digest #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_GetOperationState(session2, NULL, &op_state2_len); if (rc != CKR_OK) { if (rc == CKR_STATE_UNSAVEABLE) { testcase_skip("Session state not savable for mechanism %s. (skipped)", mech_to_str(mech2.mechanism)); funcs->C_CloseSession(session1); funcs->C_CloseSession(session2); funcs->C_CloseSession(session3); return 0; } testcase_fail("C_GetOperationState #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } op_state2 = (CK_BYTE *) malloc(op_state2_len); if (!op_state2) { testcase_error("HOST MEMORY ERROR #1"); return -1; } rc = funcs->C_GetOperationState(session2, op_state2, &op_state2_len); if (rc != CKR_OK) { testcase_fail("C_GetOperationState #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_SetOperationState(session1, op_state2, op_state2_len, 0, 0); if (rc != CKR_OK) { testcase_fail("C_SetOperationState #1, rc=%lx, %s", rc, p11_get_ckr(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) { testcase_fail("C_EncryptUpdate #1, rc=%lx, %s", rc, p11_get_ckr(rc)); testcase_error("Expected CKR_OPERATION_NOT_INITIALIZED"); return -1; } // now, finish the digest operations rc = funcs->C_DigestUpdate(session1, original + 499, (orig_len - 499)); if (rc != CKR_OK) { testcase_fail("C_DigestUpdate #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_DigestUpdate(session2, original + 499, (orig_len - 499)); if (rc != CKR_OK) { testcase_fail("C_DigestUpdate #3, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } digest1_len = sizeof(digest1); rc = funcs->C_DigestFinal(session1, digest1, &digest1_len); if (rc != CKR_OK) { testcase_fail("C_DigestFinal #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } digest2_len = sizeof(digest2); rc = funcs->C_DigestFinal(session2, digest2, &digest2_len); if (rc != CKR_OK) { testcase_fail("C_DigestFinal #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } if (digest1_len != digest2_len || digest1_len != digest3_len) { testcase_error("ERROR: digested lengths don't match"); return -1; } if (memcmp(digest1, digest2, digest1_len) != 0) { testcase_error("ERROR: digest1 != digest2"); return -1; } if (memcmp(digest1, digest3, digest1_len) != 0) { testcase_error("ERROR: digest1 != digest3"); return -1; } rc = funcs->C_CloseSession(session1); if (rc != CKR_OK) { testcase_fail("C_CloseSession #3, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_CloseSession(session2); if (rc != CKR_OK) { testcase_fail("C_CloseSession #4, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_CloseSession(session3); if (rc != CKR_OK) { testcase_fail("C_CloseSession #5, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } testcase_pass("do_OperationState3 passed"); free(op_state2); return rc; } CK_RV do_OperationState4(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 message[1024]; CK_BYTE signature[1024]; CK_BYTE *op_state = NULL; CK_ULONG op_state_len; CK_ULONG message_len, signature_len; CK_ULONG i; CK_ULONG key_len = 32; CK_ATTRIBUTE key_gen_tmpl[] = { {CKA_VALUE_LEN, &key_len, sizeof(CK_ULONG)} }; CK_MECHANISM mech; CK_OBJECT_HANDLE h_key; testcase_begin("do_OperationState4"); testcase_new_assertion(); slot_id = SLOT_ID; flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &session1); if (rc != CKR_OK) { testcase_fail("C_OpenSession #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &session2); if (rc != CKR_OK) { testcase_fail("C_OpenSession #2, rc=%lx, %s", rc, p11_get_ckr(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) { testcase_fail("C_Login #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } message_len = sizeof(message); for (i = 0; i < message_len; i++) message[i] = i % 255; mech.mechanism = CKM_GENERIC_SECRET_KEY_GEN; mech.ulParameterLen = 0; mech.pParameter = NULL; if (!mech_supported(slot_id, mech.mechanism)) { testcase_skip("Mechanism %s not supported. (skipped)", 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) { testcase_fail("C_GenerateKey #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } mech.mechanism = CKM_SHA256_HMAC; mech.ulParameterLen = 0; mech.pParameter = NULL; rc = funcs->C_SignInit(session1, &mech, h_key); if (rc != CKR_OK) { testcase_fail("C_SignInit #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } signature_len = sizeof(signature); rc = funcs->C_Sign(session1, message, message_len, signature, &signature_len); if (rc != CKR_OK) { testcase_fail("C_Sign #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_VerifyInit(session1, &mech, h_key); if (rc != CKR_OK) { testcase_fail("C_VerifyInit #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } // save session #1's operation state rc = funcs->C_GetOperationState(session1, NULL, &op_state_len); if (rc != CKR_OK) { if (rc == CKR_STATE_UNSAVEABLE) { testcase_skip("Session state not savable for mechanism %s. (skipped)", mech_to_str(mech.mechanism)); funcs->C_CloseSession(session1); funcs->C_CloseSession(session2); return 0; } testcase_fail("C_GetOperationState #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } op_state = (CK_BYTE *)malloc(op_state_len); if (!op_state) { testcase_fail("HOST MEMORY ERROR"); return -1; } rc = funcs->C_GetOperationState(session1, op_state, &op_state_len); if (rc != CKR_OK) { testcase_fail("C_GetOperationState #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } // restore session #1's operation state that we just saved back // into session #2 and continue with the verify rc = funcs->C_SetOperationState(session2, op_state, op_state_len, 0, h_key); if (rc != CKR_OK) { testcase_fail("C_SetOperationState #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } free(op_state); rc = funcs->C_Verify(session2, message, message_len, signature, signature_len); if (rc != CKR_OK) { testcase_fail("C_Verify #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs3->C_SessionCancel(session1, CKF_VERIFY); if (rc != CKR_OK) { testcase_fail("C_SessionCancel #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs3_2->C_VerifySignatureInit(session1, &mech, h_key, signature, signature_len); if (rc != CKR_OK) { testcase_fail("C_VerifySignatureInit #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } // save session #1's operation state rc = funcs->C_GetOperationState(session1, NULL, &op_state_len); if (rc != CKR_OK) { if (rc == CKR_STATE_UNSAVEABLE) { testcase_skip("Session state not savable for mechanism %s. (skipped)", mech_to_str(mech.mechanism)); funcs->C_CloseSession(session1); funcs->C_CloseSession(session2); return 0; } testcase_fail("C_GetOperationState #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } op_state = (CK_BYTE *)malloc(op_state_len); if (!op_state) { testcase_fail("HOST MEMORY ERROR"); return -1; } rc = funcs->C_GetOperationState(session1, op_state, &op_state_len); if (rc != CKR_OK) { testcase_fail("C_GetOperationState #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } // restore session #1's operation state that we just saved back // into session #2 and continue with the verify rc = funcs->C_SetOperationState(session2, op_state, op_state_len, 0, h_key); if (rc != CKR_OK) { testcase_fail("C_SetOperationState #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } free(op_state); rc = funcs3_2->C_VerifySignature(session2, message, message_len); if (rc != CKR_OK) { testcase_fail("C_VerifySignature #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_CloseSession(session1); if (rc != CKR_OK) { testcase_fail("C_CloseSession #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_CloseSession(session2); if (rc != CKR_OK) { testcase_fail("C_CloseSession #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } testcase_pass("do_OperationState4 passed"); return rc; } CK_RV do_SessionCancel(void) { CK_SLOT_ID slot_id; CK_SESSION_HANDLE session1; 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_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; testcase_begin("do_SessionCancel"); testcase_new_assertion(); slot_id = SLOT_ID; // create two USER RW sessions flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &session1); if (rc != CKR_OK) { testcase_fail("C_OpenSession #1, rc=%lx, %s", rc, p11_get_ckr(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) { testcase_fail("C_Login #1, rc=%lx, %s", rc, p11_get_ckr(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)) { testcase_skip("Mechanism %s not supported. (skipped)", mech_to_str(mech.mechanism)); funcs->C_CloseSession(session1); return 0; } rc = funcs->C_GenerateKey(session1, &mech, key_gen_tmpl, 1, &h_key); if (rc != CKR_OK) { testcase_fail("C_GenerateKey #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } // now encrypt the original data all at once using CBC mech.mechanism = CKM_AES_CBC; mech.ulParameterLen = 16; mech.pParameter = "1234qwerasdfyxcv"; rc = funcs->C_EncryptInit(session1, &mech, h_key); if (rc != CKR_OK) { testcase_fail("C_EncryptInit #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } // cancel the encrypt session rc = funcs3->C_SessionCancel(session1, CKF_ENCRYPT); if (rc != CKR_OK) { testcase_fail("C_SessionCancel #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } crypt1_len = sizeof(crypt1); rc = funcs->C_Encrypt(session1, original, orig_len, crypt1, &crypt1_len); if (rc != CKR_OPERATION_NOT_INITIALIZED) { testcase_fail("C_Encrypt #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } // now, begin encrypting multipart rc = funcs->C_EncryptInit(session1, &mech, h_key); if (rc != CKR_OK) { testcase_fail("C_EncryptInit #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } // cancel non existing sign session (no effect expected) rc = funcs3->C_SessionCancel(session1, CKF_SIGN); if (rc != CKR_OK) { testcase_fail("C_SessionCancel #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } crypt2_len = sizeof(crypt2); rc = funcs->C_EncryptUpdate(session1, original, orig_len / 2, crypt2, &crypt2_len); if (rc != CKR_OK) { testcase_fail("C_EncryptUpdate #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } // cancel non existing decrypt session (no effect expected) rc = funcs3->C_SessionCancel(session1, CKF_DECRYPT); if (rc != CKR_OK) { testcase_fail("C_SessionCancel #3, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } // now, encrypt the rest of the original data i = crypt2_len; crypt2_len = sizeof(crypt2) - crypt2_len; rc = funcs->C_EncryptUpdate(session1, original + orig_len / 2, orig_len / 2, crypt2 + i, &crypt2_len); if (rc != CKR_OK) { testcase_fail("C_EncryptUpdate #3, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } crypt2_len += i; // cancel non existing find session (no effect expected) rc = funcs3->C_SessionCancel(session1, CKF_FIND_OBJECTS); if (rc != CKR_OK) { testcase_fail("C_SessionCancel #3, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } trash2_len = sizeof(trash2); rc = funcs->C_EncryptFinal(session1, trash2, &trash2_len); if (rc != CKR_OK) { testcase_fail("C_EncryptFinal #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } // now, begin encrypting multipart again rc = funcs->C_EncryptInit(session1, &mech, h_key); if (rc != CKR_OK) { testcase_fail("C_EncryptInit #3, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } // cancel the operation by calling C_EncryptInit with NULL mechanism rc = funcs->C_EncryptInit(session1, NULL, h_key); if (rc != CKR_OK) { testcase_fail("C_EncryptInit (cancel), rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } // cancel the non existing sign operation by calling C_SignInit with NULL // mechanism (no effect expected) rc = funcs->C_SignInit(session1, NULL, h_key); if (rc != CKR_OK) { testcase_fail("C_SignInit (cancel), rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_CloseSession(session1); if (rc != CKR_OK) { testcase_fail("C_CloseSession #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } testcase_pass("do_SessionCancel passed"); return rc; } CK_RV sess_mgmt_functions(void) { SYSTEMTIME t1, t2; CK_RV rc; testcase_begin("sess_mgmt_functions"); testcase_new_assertion(); GetSystemTime(&t1); rc = do_OpenSession(); if (rc && !no_stop) { testcase_fail("do_OpenSession, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } GetSystemTime(&t2); process_time(t1, t2); GetSystemTime(&t1); rc = do_OpenSession2(); if (rc && !no_stop) { testcase_fail("do_OpenSession2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } GetSystemTime(&t2); process_time(t1, t2); GetSystemTime(&t1); rc = do_CloseAllSessions(); if (rc && !no_stop) { testcase_fail("do_CloseAllSessions, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } GetSystemTime(&t2); process_time(t1, t2); GetSystemTime(&t1); rc = do_GetSessionInfo(); if (rc && !no_stop) { testcase_fail("do_GetSessionInfo, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } GetSystemTime(&t2); process_time(t1, t2); GetSystemTime(&t1); rc = do_LoginLogout(); if (rc && !no_stop) { testcase_fail("do_LoginLogout, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } GetSystemTime(&t2); process_time(t1, t2); GetSystemTime(&t1); rc = do_OperationState1(); if (rc && !no_stop) { testcase_fail("do_OperationState1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } GetSystemTime(&t2); process_time(t1, t2); GetSystemTime(&t1); rc = do_OperationState2(); if (rc && !no_stop) { testcase_fail("do_OperationState2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } GetSystemTime(&t2); process_time(t1, t2); GetSystemTime(&t1); rc = do_OperationState3(); if (rc && !no_stop) { testcase_fail("do_OperationState3, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } GetSystemTime(&t2); process_time(t1, t2); GetSystemTime(&t1); rc = do_OperationState4(); if (rc && !no_stop) { testcase_fail("do_OperationState4, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } GetSystemTime(&t2); process_time(t1, t2); GetSystemTime(&t1); rc = do_SessionCancel(); if (rc && !no_stop) { testcase_fail("do_SessionCancel, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } GetSystemTime(&t2); process_time(t1, t2); testcase_pass("sess_mgmt_functions passed"); return rc; } 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(); rv = sess_mgmt_functions(); testcase_print_result(); /* make sure we return non-zero if rv is non-zero */ return ((rv == 0) || (rv % 256) ? (int)rv : -1); } opencryptoki-opencryptoki-451d99c/testcases/pkcs11/sess_opstate.c000066400000000000000000000207231520105705100253100ustar00rootroot00000000000000/* * 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(%ld) 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; testcase_begin("Get/SetOperationState digest test"); // 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; } if (!mech_supported(SLOT_ID, mech1.mechanism)) { testcase_skip("Mechanism CKM_SHA256 is not supported with slot " "%lu. Skipping key check", SLOT_ID); 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 = 1 + 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) { if (rc == CKR_STATE_UNSAVEABLE) { testcase_skip("Get/SetOperationState digest test: state unsavable"); rc = CKR_OK; goto out; } 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) { if (rc == CKR_STATE_UNSAVEABLE) { testcase_skip("Get/SetOperationState digest test: state unsavable"); rc = CKR_OK; goto out; } 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; } if (!mech_supported(SLOT_ID, mech2.mechanism)) { testcase_skip("Mechanism CKM_SHA_1 is not supported with slot " "%lu. Skipping key check", SLOT_ID); continue; } // 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 = 1 + 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_new_assertion(); 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; rv = funcs->C_GetFunctionStatus(hsess); if (rv != CKR_FUNCTION_NOT_PARALLEL) return rv; rv = funcs->C_CancelFunction(hsess); if (rv != CKR_FUNCTION_NOT_PARALLEL) return rv; } testcase_setup(); rc = sess_opstate_funcs(loops); testcase_print_result(); return testcase_return(rc); } opencryptoki-opencryptoki-451d99c/testcases/pkcs11/sess_perf.c000066400000000000000000000155211520105705100245650ustar00rootroot00000000000000/* * 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: %lu\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: 0x%lx\n", info->flags); printf(" ulDeviceError: %lu\n", info->ulDeviceError); } int create_aes_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) { testcase_error("C_OpenSession #1, rc=%lx, %s", rc, p11_get_ckr(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) { testcase_error("C_GenerateKey #1, rc=%lx, %s", rc, p11_get_ckr(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) { testcase_error("C_EncryptInit #1, rc=%lx, %s", rc, p11_get_ckr(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) { testcase_error("C_Encrypt #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return FALSE; } } return TRUE; } int finalize_aes_encrypt_context(CK_SESSION_HANDLE hsess) { CK_RV rc; CK_ULONG outlen = DATALEN; rc = funcs->C_EncryptFinal(hsess, DUMP, &outlen); if (rc != CKR_OK) { testcase_error("C_EncryptFinal#1, rc=%lx, %s", rc, p11_get_ckr(rc)); return FALSE; } rc = funcs->C_CloseSession(hsess); if (rc != CKR_OK) { testcase_error("C_CloseSession #1, rc=%lx, %s", rc, p11_get_ckr(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) { testcase_error("C_CloseAllSessions #1, rc=%lx, %s", rc, p11_get_ckr(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) { testcase_error("do_SessionPerformance: zero session count"); return FALSE; } t = (context_table_t *) calloc(count, sizeof(context_table_t)); if (t == NULL) { testcase_error("do_SessionPerformance: insufficient memory"); return FALSE; } /* create encryption contexts */ for (i = 0; i < count; i++) { rc = create_aes_encrypt_context(&(t[i].hsess), &(t[i].hkey)); if (rc == FALSE) { testcase_error("create_aes_encrypt_context"); 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) { testcase_error("encrypt_DATA #1"); goto ret; } rc = encrypt_DATA(t[count - 1].hsess, t[count - 1].hkey, 16); if (rc == FALSE) { testcase_error("encrypt_DATA #2"); goto ret; } GetSystemTime(&t2); process_time(t1, t2); for (i = 0; i < count; i++) { rc = finalize_aes_encrypt_context(t[i].hsess); if (rc == FALSE) { testcase_error("finalize_aes_encrypt_context"); 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; } testcase_setup(); testcase_begin("do_SessionPerformance"); testcase_new_assertion(); for (i = 100; i < 50000; i = 1.2 * i) { printf("timing do_SessionPerformance(%d)\n", i); do_SessionPerformance(i); } if (t_errors > 0) testcase_notice("do_SessionPerformance ran with %ld error(s)", t_errors); else testcase_pass("do_SessionPerformance passed"); testcase_print_result(); return 0; } opencryptoki-opencryptoki-451d99c/testcases/policy/000077500000000000000000000000001520105705100226215ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/testcases/policy/policy.mk000066400000000000000000000014271520105705100244550ustar00rootroot00000000000000noinst_PROGRAMS += testcases/policy/policytest testcases_policy_policytest_CFLAGS = ${testcases_inc} testcases_policy_policytest_LDFLAGS = -ldl testcases_policy_policytest_SOURCES = testcases/policy/policytest.c if AIX testcases_policy_policytest_SOURCES += usr/lib/common/aix/getopt_long.c endif noinst_SCRIPTS += testcases/policy/policytest.sh CLEANFILES += testcases/policy/policytest.sh EXTRA_DIST += testcases/policy/policytest.sh.in testcases/policy/policytest.sh: testcases/policy/policytest.sh.in $(AM_V_GEN)@SED@ -e s!\@sysconfdir\@!"@sysconfdir@"!g \ -e s!\@sbindir\@!"@sbindir@"!g \ -e s!\@libdir\@!"@libdir@"!g \ -e s!\@pkcsslotd_user\@!$(pkcsslotd_user)!g \ -e s!\@pkcs_group\@!$(pkcs_group)!g< $< > $@-t && \ @CHMOD@ a+x $@-t && \ $(am__mv) $@-t $@ opencryptoki-opencryptoki-451d99c/testcases/policy/policytest.c000066400000000000000000001061511520105705100251700ustar00rootroot00000000000000#include #include #include #include #include #include #include #include "platform.h" #include "pkcs11types.h" #include "ec_curves.h" #define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0])) #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 POLICY_TEST_RSA_SIZE 4096 #define POLICY_TEST_EC_SIZE 384 #define POLICY_TEST_AES_SIZE 256 /* Tests implemented (Bit indices) */ #define TEST_RSA 1u #define TEST_EC 2u #define TEST_AESWRAP 3u #define TEST_DIGEST 4u #define TEST_DH 5u static CK_FUNCTION_LIST *funcs; static void *pkcs11lib; static CK_SESSION_HANDLE session; static const char rsamessage[POLICY_TEST_RSA_SIZE / 8 - 11] = {0}; static const char ecmessage[POLICY_TEST_EC_SIZE / 8] = {0}; static const CK_UTF8CHAR poltestlabel[] = "policytest key"; static const CK_UTF8CHAR poltestdhlabelA[] = "policytest key A"; static const CK_UTF8CHAR poltestdhlabelB[] = "policytest key B"; static CK_BBOOL tokenkeys = CK_FALSE; static struct { CK_OBJECT_HANDLE rsapub; CK_OBJECT_HANDLE rsapriv; CK_OBJECT_HANDLE ecpub; CK_OBJECT_HANDLE ecpriv; CK_OBJECT_HANDLE aes; CK_OBJECT_HANDLE dhpubA; CK_OBJECT_HANDLE dhprivA; CK_OBJECT_HANDLE dhpubB; CK_OBJECT_HANDLE dhprivB; } keys; /* copied from testcases/crypto/dh_func.c */ 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 }; static void unloadLib(void) { #ifndef WITH_SANITIZER if (pkcs11lib) dlclose(pkcs11lib); #endif } static void finalizeLib(void) { funcs->C_Finalize(NULL); } static void closeSession(void) { funcs->C_CloseSession(session); } static void logoutUser(void) { funcs->C_Logout(session); } static int doLoadLib(void) { const char *lib = OCK_API_LIBNAME; const char *envlib; CK_RV (*pGetFuncList)(CK_FUNCTION_LIST **); CK_RV rc; if ((envlib = getenv("PKCSLIB")) != NULL) lib = envlib; pkcs11lib = dlopen(lib, DYNLIB_LDFLAGS); if (pkcs11lib == NULL) { fprintf(stderr, "Failed to open %s: %s\n", lib, dlerror()); return -1; } atexit(unloadLib); *(void**)(&pGetFuncList) = dlsym(pkcs11lib, "C_GetFunctionList"); if (pGetFuncList == NULL) { fprintf(stderr, "Failed to find C_GetFunctionList symbol in %s\n", lib); return -1; } rc = pGetFuncList(&funcs); if (rc != CKR_OK) { fprintf(stderr, "C_GetFunctionList failed with 0x%lx\n", rc); return -1; } return 0; } static int doInitLib(void) { CK_C_INITIALIZE_ARGS cinit_args; CK_RV rc; memset(&cinit_args, 0x0, sizeof(cinit_args)); cinit_args.flags = CKF_OS_LOCKING_OK; rc = funcs->C_Initialize(&cinit_args); if (rc != CKR_OK) { fprintf(stderr, "C_Initialize failed with 0x%lx\n", rc); return -1; } atexit(finalizeLib); return 0; } static int doOpenSession(CK_SLOT_ID slot) { CK_RV rc; CK_FLAGS flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; rc = funcs->C_OpenSession(slot, flags, NULL, NULL, &session); if (rc != CKR_OK) { fprintf(stderr, "Failed to open r/w session (rc = 0x%lx)\n", rc); return -1; } atexit(closeSession); return 0; } static int doLoginUser(unsigned char *pin) { CK_RV rc; rc = funcs->C_Login(session, CKU_USER, pin, strlen((char *)pin)); if (rc != CKR_OK) { fprintf(stderr, "Failed to log in to token (rc = 0x%lx)\n", rc); return -1; } atexit(logoutUser); return 0; } static 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; } static CK_RV generateRSAKey(void) { CK_OBJECT_HANDLE pubkey, privkey; CK_MECHANISM mech = { CKM_RSA_PKCS_KEY_PAIR_GEN, NULL, 0 }; CK_BYTE subject[] = {0}; CK_BYTE id[] = {123}; CK_BBOOL cktrue = TRUE; CK_ULONG modulusBits = POLICY_TEST_RSA_SIZE; CK_BYTE publicExponent[] = {0x01, 0x00, 0x01}; CK_ATTRIBUTE pubkeyTemplate[] = { {CKA_ENCRYPT, &cktrue, sizeof(cktrue)}, {CKA_VERIFY, &cktrue, sizeof(cktrue)}, {CKA_WRAP, &cktrue, sizeof(cktrue)}, {CKA_MODULUS_BITS, &modulusBits, sizeof(modulusBits)}, {CKA_PUBLIC_EXPONENT, publicExponent, sizeof(publicExponent)}, {CKA_TOKEN, &tokenkeys, sizeof(tokenkeys)}, {CKA_LABEL, (void *)poltestlabel, sizeof(poltestlabel)} }; CK_ATTRIBUTE privkeyTemplate[] = { {CKA_TOKEN, &cktrue, sizeof(cktrue)}, {CKA_PRIVATE, &cktrue, sizeof(cktrue)}, {CKA_SUBJECT, subject, 0}, {CKA_ID, id, sizeof(id)}, {CKA_DECRYPT, &cktrue, sizeof(cktrue)}, {CKA_SIGN, &cktrue, sizeof(cktrue)}, {CKA_UNWRAP, &cktrue, sizeof(cktrue)}, {CKA_TOKEN, &tokenkeys, sizeof(tokenkeys)}, {CKA_LABEL, (void *)poltestlabel, sizeof(poltestlabel)} }; return funcs->C_GenerateKeyPair(session, &mech, pubkeyTemplate, ARRAY_SIZE(pubkeyTemplate), privkeyTemplate, ARRAY_SIZE(privkeyTemplate), &pubkey, &privkey); } static CK_RV generateECKey(void) { CK_OBJECT_HANDLE pubkey, privkey; CK_BYTE secp384r1[] = OCK_SECP384R1; CK_MECHANISM mech = { CKM_EC_KEY_PAIR_GEN, NULL, 0 }; CK_BYTE subject[] = {0}; CK_BYTE id[] = { 123 }; CK_BBOOL true = TRUE; CK_ATTRIBUTE publicKeyTemplate[] = { {CKA_VERIFY, &true, sizeof(true)}, {CKA_EC_PARAMS, &secp384r1, sizeof(secp384r1)}, {CKA_TOKEN, &tokenkeys, sizeof(tokenkeys)}, {CKA_LABEL, (void *)poltestlabel, sizeof(poltestlabel)} }; CK_ATTRIBUTE privateKeyTemplate[] = { {CKA_PRIVATE, &true, sizeof(true)}, {CKA_SUBJECT, subject, 0}, {CKA_ID, id, sizeof(id)}, {CKA_SIGN, &true, sizeof(true)}, {CKA_DERIVE, &true, sizeof(true)}, {CKA_TOKEN, &tokenkeys, sizeof(tokenkeys)}, {CKA_LABEL, (void *)poltestlabel, sizeof(poltestlabel)} }; return funcs->C_GenerateKeyPair(session, &mech, publicKeyTemplate, ARRAY_SIZE(publicKeyTemplate), privateKeyTemplate, ARRAY_SIZE(privateKeyTemplate), &pubkey, &privkey); } static CK_RV generateAESKey(void) { CK_OBJECT_HANDLE key; CK_ULONG keylen = POLICY_TEST_AES_SIZE / 8; CK_ATTRIBUTE key_gen_tmpl[] = { {CKA_VALUE_LEN, &keylen, sizeof(CK_ULONG)}, {CKA_TOKEN, &tokenkeys, sizeof(tokenkeys)}, {CKA_LABEL, (void *)poltestlabel, sizeof(poltestlabel)} }; CK_MECHANISM mech = { .mechanism = CKM_AES_KEY_GEN, .ulParameterLen = 0, .pParameter = NULL, }; return funcs->C_GenerateKey(session, &mech, key_gen_tmpl, ARRAY_SIZE(key_gen_tmpl), &key); } static CK_RV generateDHKeys(void) { CK_OBJECT_HANDLE pubkeyA, privkeyA, pubkeyB, privkeyB; CK_OBJECT_CLASS pub_key_class = CKO_PUBLIC_KEY; CK_KEY_TYPE key_type = CKK_DH; CK_OBJECT_CLASS priv_key_class = CKO_PRIVATE_KEY; CK_BBOOL ltrue = CK_TRUE; CK_ATTRIBUTE publA_tmpl[] = { {CKA_CLASS, &pub_key_class, sizeof(pub_key_class)}, {CKA_KEY_TYPE, &key_type, sizeof(key_type)}, {CKA_PRIME, DH_PUBL_PRIME, sizeof(DH_PUBL_PRIME)}, {CKA_BASE, DH_PUBL_BASE, sizeof(DH_PUBL_BASE)}, {CKA_TOKEN, &tokenkeys, sizeof(tokenkeys)}, {CKA_LABEL, (void *)poltestdhlabelA, sizeof(poltestdhlabelA)} }; CK_ATTRIBUTE privA_tmpl[] = { {CKA_CLASS, &priv_key_class, sizeof(priv_key_class)}, {CKA_KEY_TYPE, &key_type, sizeof(key_type)}, {CKA_DERIVE, <rue, sizeof(ltrue)}, {CKA_TOKEN, &tokenkeys, sizeof(tokenkeys)}, {CKA_LABEL, (void *)poltestdhlabelA, sizeof(poltestdhlabelA)} }; CK_ATTRIBUTE publB_tmpl[] = { {CKA_CLASS, &pub_key_class, sizeof(pub_key_class)}, {CKA_KEY_TYPE, &key_type, sizeof(key_type)}, {CKA_PRIME, DH_PUBL_PRIME, sizeof(DH_PUBL_PRIME)}, {CKA_BASE, DH_PUBL_BASE, sizeof(DH_PUBL_BASE)}, {CKA_TOKEN, &tokenkeys, sizeof(tokenkeys)}, {CKA_LABEL, (void *)poltestdhlabelB, sizeof(poltestdhlabelB)} }; CK_ATTRIBUTE privB_tmpl[] = { {CKA_CLASS, &priv_key_class, sizeof(priv_key_class)}, {CKA_KEY_TYPE, &key_type, sizeof(key_type)}, {CKA_DERIVE, <rue, sizeof(ltrue)}, {CKA_TOKEN, &tokenkeys, sizeof(tokenkeys)}, {CKA_LABEL, (void *)poltestdhlabelB, sizeof(poltestdhlabelB)} }; CK_MECHANISM mech = { CKM_DH_PKCS_KEY_PAIR_GEN, NULL, 0 }; CK_RV rc; rc = funcs->C_GenerateKeyPair(session, &mech, publA_tmpl, ARRAY_SIZE(publA_tmpl), privA_tmpl, ARRAY_SIZE(privA_tmpl), &pubkeyA, &privkeyA); if (rc != CKR_OK) return rc; rc = funcs->C_GenerateKeyPair(session, &mech, publB_tmpl, ARRAY_SIZE(publB_tmpl), privB_tmpl, ARRAY_SIZE(privB_tmpl), &pubkeyB, &privkeyB); if (rc != CKR_OK) { funcs->C_DestroyObject(session, pubkeyA); funcs->C_DestroyObject(session, privkeyA); } return rc; } static CK_RV encryptRSA(CK_OBJECT_HANDLE key, CK_BYTE *res, CK_ULONG *reslen) { CK_MECHANISM mech = { .mechanism = CKM_RSA_PKCS, .pParameter = NULL, .ulParameterLen = 0 }; CK_RV rc; rc = funcs->C_EncryptInit(session, &mech, key); if (rc != CKR_OK) return rc; rc = funcs->C_Encrypt(session, (CK_BYTE *)rsamessage, sizeof(rsamessage), res, reslen); return rc; } static CK_RV decryptRSA(CK_OBJECT_HANDLE key, CK_BYTE *enc, CK_ULONG len) { CK_MECHANISM mech = { .mechanism = CKM_RSA_PKCS, .pParameter = NULL, .ulParameterLen = 0 }; CK_BYTE dec[POLICY_TEST_RSA_SIZE / 8]; CK_ULONG declen = sizeof(dec); CK_RV rc; rc = funcs->C_DecryptInit(session, &mech, key); if (rc != CKR_OK) return rc; rc = funcs->C_Decrypt(session, enc, len, dec, &declen); if (rc != CKR_OK) return rc; if (memcmp(rsamessage, dec, declen)) return CKR_GENERAL_ERROR; return rc; } static int runRSATest(void) { CK_BYTE enc[POLICY_TEST_RSA_SIZE / 8]; CK_ULONG enclen = sizeof(enc); CK_RV rc; rc = encryptRSA(keys.rsapub, enc, &enclen); if (rc != CKR_OK) { fprintf(stderr, "WARN: RSA public key usage failed with 0x%lx\n", rc); return -1; } rc = decryptRSA(keys.rsapriv, enc, enclen); if (rc != CKR_OK) { fprintf(stderr, "WARN: RSA private key usage failed with 0x%lx\n", rc); return -1; } return 0; } static CK_RV signEC(CK_OBJECT_HANDLE key, CK_BYTE *sig, CK_ULONG *siglen) { CK_MECHANISM mech = { CKM_ECDSA, NULL, 0 }; CK_RV rc; rc = funcs->C_SignInit(session, &mech, key); if (rc != CKR_OK) return rc; rc = funcs->C_Sign(session, (CK_BYTE *)ecmessage, sizeof(ecmessage), sig, siglen); return rc; } static CK_RV verifyEC(CK_OBJECT_HANDLE key, CK_BYTE *sig, CK_ULONG siglen) { CK_MECHANISM mech = { CKM_ECDSA, NULL, 0 }; CK_RV rc; rc = funcs->C_VerifyInit(session, &mech, key); if (rc != CKR_OK) return rc; rc = funcs->C_Verify(session, (CK_BYTE *)ecmessage, sizeof(ecmessage), sig, siglen); return rc; } static int runECTest(void) { CK_BYTE sig[2 * POLICY_TEST_EC_SIZE / 8]; CK_ULONG siglen = sizeof(sig); CK_RV rc; rc = signEC(keys.ecpriv, sig, &siglen); if (rc != CKR_OK) { fprintf(stderr, "WARN: EC private key usage failed with 0x%lx\n", rc); return -1; } rc = verifyEC(keys.ecpub, sig, siglen); if (rc != CKR_OK) { fprintf(stderr, "WARN: EC public key usage failed with 0x%lx\n", rc); return -1; } return 0; } static CK_RV wrapAESKey(CK_OBJECT_HANDLE key, CK_BYTE **wrapped, CK_ULONG *len) { CK_BYTE iv[16] = {0}; CK_MECHANISM mech = { CKM_AES_CBC_PAD, iv, sizeof(iv) }; CK_RV rc; CK_BYTE *res; rc = funcs->C_WrapKey(session, &mech, key, key, NULL, len); if (rc != CKR_OK) return rc; res = calloc(1, *len); if (!res) return CKR_HOST_MEMORY; rc = funcs->C_WrapKey(session, &mech, key, key, res, len); if (rc != CKR_OK) { free(res); return rc; } *wrapped = res; return rc; } static CK_RV unwrapAESKey(CK_OBJECT_HANDLE key, CK_BYTE *wrapped, CK_ULONG len, CK_OBJECT_HANDLE_PTR unwrapped, int iscca) { CK_BYTE iv[16] = {0}; CK_MECHANISM mech = { CKM_AES_CBC_PAD, iv, sizeof(iv) }; CK_RV rc; CK_OBJECT_CLASS key_class = CKO_SECRET_KEY; CK_KEY_TYPE key_type = CKK_AES; CK_ULONG key_size = POLICY_TEST_AES_SIZE / 8; 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_ULONG templatecount = 2 + iscca; rc = funcs->C_UnwrapKey(session, &mech, key, wrapped, len, template, templatecount, unwrapped); free(wrapped); return rc; } static int runAESWrapTest(CK_SLOT_ID slot) { CK_OBJECT_HANDLE unwrapped = CK_INVALID_HANDLE; CK_BYTE *wrapped; CK_ULONG wrappedlen; CK_RV rc; rc = wrapAESKey(keys.aes, &wrapped, &wrappedlen); if (rc != CKR_OK) { fprintf(stderr, "WARN: AES wrapping failed with 0x%lx\n", rc); return -1; } rc = unwrapAESKey(keys.aes, wrapped, wrappedlen, &unwrapped, is_cca_token(slot)); funcs->C_DestroyObject(session, unwrapped); if (rc != CKR_OK) { fprintf(stderr, "WARN: AES unwrapping failed with 0x%lx\n", rc); return -1; } return 0; } static int runDIGESTTest(void) { CK_BYTE digest[64]; CK_MECHANISM mech = { CKM_SHA512, NULL, 0 }; CK_RV rc; CK_ULONG len = sizeof(digest); rc = funcs->C_DigestInit(session, &mech); if (rc != CKR_OK) { fprintf(stderr, "WARN: Digest initialization failed with 0x%lx\n", rc); return -1; } rc = funcs->C_Digest(session, (CK_BYTE *)rsamessage, sizeof(rsamessage), digest, &len); if (rc != CKR_OK) { /* No policy checking done in C_Digest... */ fprintf(stderr, "WARN: Digest failed with 0x%lx\n", rc); return -1; } return 0; } static int runDHTest(void) { CK_BYTE key_value[sizeof(DH_PUBL_PRIME) * 2]; CK_ATTRIBUTE extr_tmpl = {CKA_VALUE, key_value, sizeof(key_value)}; 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_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)} }; CK_MECHANISM mech = { CKM_DH_PKCS_DERIVE, key_value, 0 }; CK_OBJECT_HANDLE derived = CK_INVALID_HANDLE; CK_RV rc; // Extract the peer's public key rc = funcs->C_GetAttributeValue(session, keys.dhpubB, &extr_tmpl, 1); if (rc != CKR_OK) { fprintf(stderr, "WARN: Getting CKA_VALUE for DH peer pub key failed with 0x%lx!\n", rc); return -1; } mech.ulParameterLen = extr_tmpl.ulValueLen; rc = funcs->C_DeriveKey(session, &mech, keys.dhprivA, secret_tmpl, ARRAY_SIZE(secret_tmpl), &derived); funcs->C_DestroyObject(session, derived); if (rc != CKR_OK) { fprintf(stderr, "WARN: DH key derivation failed with 0x%lx\n", rc); return -1; } return 0; } static int generateKeys(void) { int res = 0; if (generateRSAKey() != CKR_OK) res = -1; if (generateECKey() != CKR_OK) res = -1; if (generateAESKey() != CKR_OK) res = -1; if (generateDHKeys() != CKR_OK) res = -1; return res; } static int loadKeys(void) { static const CK_KEY_TYPE rsakt = CKK_RSA; static const CK_KEY_TYPE eckt = CKK_EC; static const CK_KEY_TYPE aeskt = CKK_AES; static const CK_KEY_TYPE dhkt = CKK_DH; static const CK_OBJECT_CLASS publickey = CKO_PUBLIC_KEY; static const CK_OBJECT_CLASS privatekey = CKO_PRIVATE_KEY; static const CK_ATTRIBUTE rsapubtmpl[] = { {CKA_KEY_TYPE, (void *)&rsakt, sizeof(rsakt)}, {CKA_CLASS, (void *)&publickey, sizeof(publickey)}, {CKA_LABEL, (void *)poltestlabel, sizeof(poltestlabel)} }; static const CK_ATTRIBUTE rsaprivtmpl[] = { {CKA_KEY_TYPE, (void *)&rsakt, sizeof(rsakt)}, {CKA_CLASS, (void *)&privatekey, sizeof(privatekey)}, {CKA_LABEL, (void *)poltestlabel, sizeof(poltestlabel)} }; static const CK_ATTRIBUTE ecpubtmpl[] = { {CKA_KEY_TYPE, (void *)&eckt, sizeof(eckt)}, {CKA_CLASS, (void *)&publickey, sizeof(publickey)}, {CKA_LABEL, (void *)poltestlabel, sizeof(poltestlabel)} }; static const CK_ATTRIBUTE ecprivtmpl[] = { {CKA_KEY_TYPE, (void *)&eckt, sizeof(eckt)}, {CKA_CLASS, (void *)&privatekey, sizeof(privatekey)}, {CKA_LABEL, (void *)poltestlabel, sizeof(poltestlabel)} }; static const CK_ATTRIBUTE aestmpl[] = { {CKA_KEY_TYPE, (void *)&aeskt, sizeof(aeskt)}, {CKA_LABEL, (void *)poltestlabel, sizeof(poltestlabel)} }; static const CK_ATTRIBUTE dhApubtmpl[] = { {CKA_KEY_TYPE, (void *)&dhkt, sizeof(dhkt)}, {CKA_CLASS, (void *)&publickey, sizeof(publickey)}, {CKA_LABEL, (void *)poltestdhlabelA, sizeof(poltestdhlabelA)} }; static const CK_ATTRIBUTE dhAprivtmpl[] = { {CKA_KEY_TYPE, (void *)&dhkt, sizeof(dhkt)}, {CKA_CLASS, (void *)&privatekey, sizeof(privatekey)}, {CKA_LABEL, (void *)poltestdhlabelA, sizeof(poltestdhlabelA)} }; static const CK_ATTRIBUTE dhBpubtmpl[] = { {CKA_KEY_TYPE, (void *)&dhkt, sizeof(dhkt)}, {CKA_CLASS, (void *)&publickey, sizeof(publickey)}, {CKA_LABEL, (void *)poltestdhlabelB, sizeof(poltestdhlabelB)} }; static const CK_ATTRIBUTE dhBprivtmpl[] = { {CKA_KEY_TYPE, (void *)&dhkt, sizeof(dhkt)}, {CKA_CLASS, (void *)&privatekey, sizeof(privatekey)}, {CKA_LABEL, (void *)poltestdhlabelB, sizeof(poltestdhlabelB)} }; CK_OBJECT_HANDLE handle; CK_ULONG count; CK_RV rc; int res = 0; // Find RSA pubkey rc = funcs->C_FindObjectsInit(session, (CK_ATTRIBUTE *)rsapubtmpl, ARRAY_SIZE(rsapubtmpl)); if (rc != CKR_OK) { res = -1; } else { rc = funcs->C_FindObjects(session, &handle, 1, &count); funcs->C_FindObjectsFinal(session); if (rc != CKR_OK || count != 1u) res = -1; else keys.rsapub = handle; } // Find RSA privkey rc = funcs->C_FindObjectsInit(session, (CK_ATTRIBUTE *)rsaprivtmpl, ARRAY_SIZE(rsaprivtmpl)); if (rc != CKR_OK) { res = -1; } else { rc = funcs->C_FindObjects(session, &handle, 1, &count); funcs->C_FindObjectsFinal(session); if (rc != CKR_OK || count != 1u) res = -1; else keys.rsapriv = handle; } // Find EC pubkey rc = funcs->C_FindObjectsInit(session, (CK_ATTRIBUTE *)ecpubtmpl, ARRAY_SIZE(ecpubtmpl)); if (rc != CKR_OK) { res = -1; } else { rc = funcs->C_FindObjects(session, &handle, 1, &count); funcs->C_FindObjectsFinal(session); if (rc != CKR_OK || count != 1u) res = -1; else keys.ecpub = handle; } // Find EC privkey rc = funcs->C_FindObjectsInit(session, (CK_ATTRIBUTE *)ecprivtmpl, ARRAY_SIZE(ecprivtmpl)); if (rc != CKR_OK) { res = -1; } else { rc = funcs->C_FindObjects(session, &handle, 1, &count); funcs->C_FindObjectsFinal(session); if (rc != CKR_OK || count != 1u) res = -1; else keys.ecpriv = handle; } // Find AES pubkey rc = funcs->C_FindObjectsInit(session, (CK_ATTRIBUTE *)aestmpl, ARRAY_SIZE(aestmpl)); if (rc != CKR_OK) { res = -1; } else { rc = funcs->C_FindObjects(session, &handle, 1, &count); funcs->C_FindObjectsFinal(session); if (rc != CKR_OK || count != 1u) res = -1; else keys.aes = handle; } // Find DH pubkey A rc = funcs->C_FindObjectsInit(session, (CK_ATTRIBUTE *)dhApubtmpl, ARRAY_SIZE(dhApubtmpl)); if (rc != CKR_OK) { res = -1; } else { rc = funcs->C_FindObjects(session, &handle, 1, &count); funcs->C_FindObjectsFinal(session); if (rc != CKR_OK || count != 1u) res = -1; else keys.dhpubA = handle; } // Find DH privkey A rc = funcs->C_FindObjectsInit(session, (CK_ATTRIBUTE *)dhAprivtmpl, ARRAY_SIZE(dhAprivtmpl)); if (rc != CKR_OK) { res = -1; } else { rc = funcs->C_FindObjects(session, &handle, 1, &count); funcs->C_FindObjectsFinal(session); if (rc != CKR_OK || count != 1u) res = -1; else keys.dhprivA = handle; } // Find DH pubkey B rc = funcs->C_FindObjectsInit(session, (CK_ATTRIBUTE *)dhBpubtmpl, ARRAY_SIZE(dhBpubtmpl)); if (rc != CKR_OK) { res = -1; } else { rc = funcs->C_FindObjects(session, &handle, 1, &count); funcs->C_FindObjectsFinal(session); if (rc != CKR_OK || count != 1u) res = -1; else keys.dhpubB = handle; } // Find DH privkey B rc = funcs->C_FindObjectsInit(session, (CK_ATTRIBUTE *)dhBprivtmpl, ARRAY_SIZE(dhBprivtmpl)); if (rc != CKR_OK) { res = -1; } else { rc = funcs->C_FindObjects(session, &handle, 1, &count); funcs->C_FindObjectsFinal(session); if (rc != CKR_OK || count != 1u) res = -1; else keys.dhprivB = handle; } return res; } static void deleteKeys(void) { funcs->C_DestroyObject(session, keys.rsapub); funcs->C_DestroyObject(session, keys.rsapriv); funcs->C_DestroyObject(session, keys.ecpub); funcs->C_DestroyObject(session, keys.ecpriv); funcs->C_DestroyObject(session, keys.aes); funcs->C_DestroyObject(session, keys.dhpubA); funcs->C_DestroyObject(session, keys.dhprivA); funcs->C_DestroyObject(session, keys.dhpubB); funcs->C_DestroyObject(session, keys.dhprivB); } static void dumpKeyInfo(void) { #define KEY_TO_STR(X) ((X) == CK_INVALID_HANDLE ? "UNAVAILABLE" : "ok") fprintf(stderr, "RSA public key: %s\n", KEY_TO_STR(keys.rsapub)); fprintf(stderr, "RSA private key: %s\n", KEY_TO_STR(keys.rsapriv)); fprintf(stderr, "EC public key: %s\n", KEY_TO_STR(keys.ecpub)); fprintf(stderr, "EC private key: %s\n", KEY_TO_STR(keys.ecpriv)); fprintf(stderr, "AES key: %s\n", KEY_TO_STR(keys.aes)); fprintf(stderr, "DH public key A: %s\n", KEY_TO_STR(keys.dhpubA)); fprintf(stderr, "DH private key A: %s\n", KEY_TO_STR(keys.dhprivA)); fprintf(stderr, "DH public key B: %s\n", KEY_TO_STR(keys.dhpubB)); fprintf(stderr, "DH private key B: %s\n", KEY_TO_STR(keys.dhprivB)); #undef KEY_TO_STR } static inline void initializeKeys(void) { keys.rsapub = keys.rsapriv = keys.ecpub = keys.ecpriv = keys.aes = keys.dhpubA = keys.dhprivA = keys.dhpubB = keys.dhprivB = CK_INVALID_HANDLE; } static int runTests(CK_SLOT_ID slot, uint32_t tests, uint32_t expfail) { int res = 0, tmpres, shouldfail; tmpres = 0; if (tests & (1u << TEST_RSA)) { shouldfail = expfail & (1u << TEST_RSA); if (keys.rsapub == CK_INVALID_HANDLE || keys.rsapriv == CK_INVALID_HANDLE) { fprintf(stderr, "WARN: RSA test requested, but RSA keys unavailable!\n"); tmpres = -1; } else { tmpres = runRSATest(); } if (tmpres && shouldfail == 0) { fprintf(stderr, "ERROR: RSA test failed unexpectedly!\n"); res = -1; } else if (tmpres == 0 && shouldfail) { fprintf(stderr, "ERROR: RSA test did not fail as expected!\n"); res = -1; } } tmpres = 0; if (tests & (1u << TEST_EC)) { shouldfail = expfail & (1u << TEST_EC); if (keys.ecpub == CK_INVALID_HANDLE || keys.ecpriv == CK_INVALID_HANDLE) { fprintf(stderr, "WARN: EC test requested, but EC keys unavailable!\n"); tmpres = -1; } else { tmpres = runECTest(); } if (tmpres && shouldfail == 0) { fprintf(stderr, "ERROR: EC test failed unexpectedly!\n"); res = -1; } else if (tmpres == 0 && shouldfail) { fprintf(stderr, "ERROR: EC test did not fail as expected!\n"); res = -1; } } tmpres = 0; if (tests & (1u << TEST_AESWRAP)) { shouldfail = expfail & (1u << TEST_AESWRAP); if (keys.aes == CK_INVALID_HANDLE) { fprintf(stderr, "WARN: AES test requested, but AES key unavailable!\n"); tmpres = -1; } else { tmpres = runAESWrapTest(slot); } if (tmpres && shouldfail == 0) { fprintf(stderr, "ERROR: AES Wrap test failed unexpectedly!\n"); res = -1; } else if (tmpres == 0 && shouldfail) { fprintf(stderr, "ERROR: AES Wrap test did not fail as expected!\n"); res = -1; } } if (tests & (1u << TEST_DIGEST)) { shouldfail = expfail & (1u << TEST_DIGEST); tmpres = runDIGESTTest(); if (tmpres && shouldfail == 0) { fprintf(stderr, "ERROR: Digest test failed unexpectedly!\n"); res = -1; } else if (tmpres == 0 && shouldfail) { fprintf(stderr, "ERROR: Digest test did not fail as expected!\n"); res = -1; } } tmpres = 0; if (tests & (1u << TEST_DH)) { shouldfail = expfail & (1u << TEST_DH); if (keys.dhpubA == CK_INVALID_HANDLE || keys.dhprivA == CK_INVALID_HANDLE || keys.dhpubB == CK_INVALID_HANDLE || keys.dhprivB == CK_INVALID_HANDLE) { fprintf(stderr, "WARN: DH test requested, but DH key unavailable!\n"); tmpres = -1; } else { tmpres = runDHTest(); } if (tmpres && shouldfail == 0) { fprintf(stderr, "ERROR: DH test failed unexpectedly!\n"); res = -1; } else if (tmpres == 0 && shouldfail) { fprintf(stderr, "ERROR: DH test did not fail as expected!\n"); res = -1; } } return res; } static void usage(char *prgname) { printf("USAGE: %s -s|--slot [-g|--generate] [-t|--tests] [-d|--delete] [-k|--token] [-r|--restrict ] [-f|--fail ]\n", prgname); printf("where:\n"); printf("\t-s or --slot specifies the PKCS #11 slot to use\n"); printf("\t-g or --generate specifies to generate keys for testing\n"); printf("\t-t or --tests specifies to run tests\n"); printf("\t-d or --delete specifies to delete the keys at the end\n"); printf("\t-k or --token specifies to use token keys (only useful with key generation)\n"); printf("\t-r or --restrict specifies which tests to run\n"); printf("\t-f or --fail specifies which tests are expected to fail\n"); printf("\nvalid tests are:\n"); printf("RSA - Encrypt/Decrypt test with 4k RSA key and CKM_RSA_PKCS\n"); printf("EC - CKM_ECDSA sign/verify with secp384r1 key\n"); printf("AESWRAP - CKM_AES_CBC_PAD key wrapping with 256bit key\n"); printf("DIGEST - CKM_SHA512\n"); printf("DH - CKM_DH_PKCS_DERIVE with 128 byte prime\n"); printf(" is a CSV of the keys above.\n"); } static int getslotid(CK_SLOT_ID *slotid, char *arg) { char *endptr; unsigned long res; errno = 0; res = strtoul(arg, &endptr, 0); if (*endptr || endptr == arg || (res == ULONG_MAX && errno == ERANGE)) { fprintf(stderr, "Failed to parse slot id %s\n", arg); return -1; } *slotid = res; return 0; } static 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; } static int parsecsv(uint32_t *mask, const char *carg) { char *arg = strdup(carg); char *s, *tok; int res = 0; if (!arg) return -1; s = arg; while ((tok = strtok(s, ",")) != NULL) { if (strcmp(tok, "RSA") == 0) *mask |= (1u << TEST_RSA); else if (strcmp(tok, "EC") == 0) *mask |= (1u << TEST_EC); else if (strcmp(tok, "AESWRAP") == 0) *mask |= (1u << TEST_AESWRAP); else if (strcmp(tok, "DIGEST") == 0) *mask |= (1u << TEST_DIGEST); else if (strcmp(tok, "DH") == 0) *mask |= (1u << TEST_DH); else res = -1; s = NULL; } free(arg); return res; } static int parseArgs(int argc, char **argv, CK_SLOT_ID *slot, int *keygen, int *test, int *delete, uint32_t *tests, uint32_t *fail) { static struct option long_options[] = { {"slot", required_argument, 0, 's'}, {"generate", no_argument, 0, 'g'}, {"tests", no_argument, 0, 't'}, {"delete", no_argument, 0, 'd'}, {"restrict", required_argument, 0, 'r'}, {"fail", required_argument, 0, 'f'}, {"token", no_argument, 0, 'k'}, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0 } }; int c, slotunspecified = -1; *keygen = *test = *delete = 0; *tests = ~0u; *fail = 0; while (1) { c = getopt_long(argc, argv, "s:gtdr:f:kh", long_options, 0); if (c == -1) break; switch (c) { case 's': if (getslotid(slot, optarg)) return -1; slotunspecified = 0; break; case 'g': *keygen = 1; break; case 't': *test = 1; break; case 'd': *delete = 1; break; case 'r': *tests = 0; if (parsecsv(tests, optarg)) return -1; break; case 'f': if (parsecsv(fail, optarg)) return -1; break; case 'k': tokenkeys = CK_TRUE; break; case 'h': usage(argv[0]); return 1; default: usage(argv[0]); return -1; } } if (slotunspecified) usage(argv[0]); return slotunspecified; } int main(int argc, char **argv) { CK_BYTE userpin[PKCS11_MAX_PIN_LEN]; int keygen, test, delete; uint32_t tests, fail; CK_SLOT_ID slot = 0; int res = 0; initializeKeys(); if (parseArgs(argc, argv, &slot, &keygen, &test, &delete, &tests, &fail)) return 1; if (get_user_pin(userpin)) return 2; if (doLoadLib()) return 3; if (doInitLib()) return 4; if (doOpenSession(slot)) return 5; if (doLoginUser(userpin)) return 6; if (keygen && generateKeys()) fprintf(stderr, "WARN: Could not generate all keys\n"); if (loadKeys()) { fprintf(stderr, "WARN: Could not load all keys\n"); dumpKeyInfo(); } if (test && runTests(slot, tests, fail)) res = 7; if (delete) deleteKeys(); return res; } opencryptoki-opencryptoki-451d99c/testcases/policy/policytest.sh.in000066400000000000000000000125351520105705100257670ustar00rootroot00000000000000#!/bin/bash # Get script directory as source directory for all other files SOURCE="${BASH_SOURCE[0]}" while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )" SOURCE="$(readlink "$SOURCE")" [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located done DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )" restoreconfig() { if test -e @sysconfdir@/opencryptoki/strength.conf.ptbak; then rm -f @sysconfdir@/opencryptoki/strength.conf mv @sysconfdir@/opencryptoki/strength.conf.ptbak @sysconfdir@/opencryptoki/strength.conf chown root:@pkcs_group@ @sysconfdir@/opencryptoki/strength.conf chmod 0640 @sysconfdir@/opencryptoki/strength.conf fi if test -e @sysconfdir@/opencryptoki/policy.conf.ptbak; then rm -f @sysconfdir@/opencryptoki/policy.conf mv @sysconfdir@/opencryptoki/policy.conf.ptbak @sysconfdir@/opencryptoki/policy.conf chown root:@pkcs_group@ @sysconfdir@/opencryptoki/policy.conf chmod 0640 @sysconfdir@/opencryptoki/policy.conf fi } backupconfig() { if test -e @sysconfdir@/opencryptoki/strength.conf; then mv @sysconfdir@/opencryptoki/strength.conf @sysconfdir@/opencryptoki/strength.conf.ptbak fi if test -e @sysconfdir@/opencryptoki/policy.conf; then mv @sysconfdir@/opencryptoki/policy.conf @sysconfdir@/opencryptoki/policy.conf.ptbak fi trap restoreconfig EXIT } initstrength() { cat < @sysconfdir@/opencryptoki/strength.conf version strength-0 strength 112 { MOD_EXP = 2048 ECC = 224 SYMMETRIC = 112 digest = 224 signature = 112 } strength 128 { MOD_EXP = 3072 ECC = 256 SYMMETRIC = 128 digest = 256 signature = 128 } strength 192 { MOD_EXP = 7680 ECC = 384 SYMMETRIC = 192 digest = 384 signature = 192 } strength 256 { MOD_EXP = 15360 ECC = 512 SYMMETRIC = 256 digest = 512 signature = 256 } EOF chown root:@pkcs_group@ @sysconfdir@/opencryptoki/strength.conf chmod 0640 @sysconfdir@/opencryptoki/strength.conf } # Usage: genpolicy genpolicy() { cat < @sysconfdir@/opencryptoki/policy.conf version policy-0 strength = $1 EOF chown root:@pkcs_group@ @sysconfdir@/opencryptoki/policy.conf chmod 0640 @sysconfdir@/opencryptoki/policy.conf } if test $# -ne 1; then echo "USAGE: policytest " exit 1; fi SLOT=$1 FAILED=/bin/false # basic initialization backupconfig initstrength # start with strength of 0 genpolicy 0 # check which tests we can run TESTS="" SEP="" if pkcsconf -m -c $SLOT | grep -q "(CKM_RSA_PKCS)"; then TESTS="${TESTS}${SEP}RSA" SEP="," fi if pkcsconf -m -c $SLOT | grep -q "(CKM_ECDSA)"; then TESTS="${TESTS}${SEP}EC" SEP="," fi if pkcsconf -m -c $SLOT | grep -q "(CKM_AES_CBC_PAD)" &&\ pkcsconf -m -c $SLOT | grep -A 2 "(CKM_AES_CBC_PAD)" | grep -q CKF_WRAP; then TESTS="${TESTS}${SEP}AESWRAP" SEP="," fi if pkcsconf -m -c $SLOT | grep -q "(CKM_SHA512)"; then TESTS="${TESTS}${SEP}DIGEST" SEP="," fi if pkcsconf -m -c $SLOT | grep -q "(CKM_DH_PKCS_DERIVE)"; then TESTS="${TESTS}${SEP}DH" SEP="," fi if test "x$TESTS" == "x"; then echo "Cannot run any tests on this slot" exit 0 fi echo "Using test mask $TESTS" echo "Running tests with session keys..." ${DIR}/policytest -s $SLOT -g -t -d -r $TESTS || { echo "Failed with session keys for strength 0" FAILED=/bin/true } genpolicy 112 ${DIR}/policytest -s $SLOT -g -t -d -r $TESTS -f DH || { echo "Failed with session keys for strength 112" FAILED=/bin/true } genpolicy 128 ${DIR}/policytest -s $SLOT -g -t -d -r $TESTS -f DH || { echo "Failed with session keys for strength 128" FAILED=/bin/true } genpolicy 192 ${DIR}/policytest -s $SLOT -g -t -d -r $TESTS -f DH,RSA || { echo "Failed with session keys for strength 192" FAILED=/bin/true } genpolicy 256 ${DIR}/policytest -s $SLOT -g -t -d -r $TESTS -f DH,RSA,EC || { echo "Failed with session keys for strength 256" FAILED=/bin/true } echo "...now generating token keys..." genpolicy 0 ${DIR}/policytest -s $SLOT -g -k || { echo "Failed to generate token keys" exit 1 } echo "...now running tests with token keys..." ${DIR}/policytest -s $SLOT -t -r $TESTS || { echo "Failed with token keys from strength 0" FAILED=/bin/true } genpolicy 112 ${DIR}/policytest -s $SLOT -t -r $TESTS -f DH || { echo "Failed with token keys from strength 112" FAILED=/bin/true } genpolicy 128 ${DIR}/policytest -s $SLOT -t -r $TESTS -f DH || { echo "Failed with token keys from strength 128" FAILED=/bin/true } genpolicy 192 ${DIR}/policytest -s $SLOT -t -r $TESTS -f DH,RSA || { echo "Failed with token keys from strength 192" FAILED=/bin/true } genpolicy 256 ${DIR}/policytest -s $SLOT -t -r $TESTS -f DH,RSA,EC || { echo "Failed with token keys from strength 256" FAILED=/bin/true } echo "...now deleting token keys" genpolicy 0 ${DIR}/policytest -s $SLOT -d || echo "Could not delete all generated tokens keys" if $FAILED; then echo "Some tests have failed" exit 1 fi exit 0 opencryptoki-opencryptoki-451d99c/testcases/testcases.mk000066400000000000000000000036741520105705100236630ustar00rootroot00000000000000testcases_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 \ -I${srcdir}/usr/lib/api -I${top_builddir}/usr/lib/api 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 include testcases/build/build.mk include testcases/unit/unit.mk include testcases/policy/policy.mk noinst_SCRIPTS += testcases/ock_tests.sh testcases/init_token.sh testcases/init_vhsm.exp testcases/cleanup_vhsm.exp CLEANFILES += testcases/ock_tests.sh testcases/init_token.sh testcases/init_vhsm.exp testcases/cleanup_vhsm.exp EXTRA_DIST += testcases/ock_tests.sh.in testcases/init_token.sh.in testcases/init_vhsm.exp.in testcases/cleanup_vhsm.exp.in testcases/ock_tests.sh: testcases/ock_tests.sh.in $(AM_V_GEN)@SED@ -e s!\@sysconfdir\@!"@sysconfdir@"!g \ -e s!\@sbindir\@!"@sbindir@"!g \ -e s!\@libdir\@!"@libdir@"!g < $< > $@-t && \ @CHMOD@ a+x $@-t && \ $(am__mv) $@-t $@ testcases/init_token.sh: testcases/init_token.sh.in $(AM_V_GEN)@SED@ -e s!\@localstatedir\@!"@localstatedir@"!g \ -e s!\@sbindir\@!"@sbindir@"!g \ -e s!\@libdir\@!"@libdir@"!g < $< > $@-t && \ @CHMOD@ a+x $@-t && \ $(am__mv) $@-t $@ testcases/init_vhsm.exp: testcases/init_vhsm.exp.in $(AM_V_GEN)@SED@ -e s!\@localstatedir\@!"@localstatedir@"!g \ -e s!\@sbindir\@!"@sbindir@"!g \ -e s!\@libdir\@!"@libdir@"!g < $< > $@-t && \ @CHMOD@ a+x $@-t && \ $(am__mv) $@-t $@ testcases/cleanup_vhsm.exp: testcases/cleanup_vhsm.exp.in $(AM_V_GEN)@SED@ -e s!\@localstatedir\@!"@localstatedir@"!g \ -e s!\@sbindir\@!"@sbindir@"!g \ -e s!\@libdir\@!"@libdir@"!g < $< > $@-t && \ @CHMOD@ a+x $@-t && \ $(am__mv) $@-t $@ opencryptoki-opencryptoki-451d99c/testcases/unit/000077500000000000000000000000001520105705100223015ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/testcases/unit/buffertest.c000066400000000000000000000075271520105705100246310ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2022 * * This program is provided under the terms of the Common Public License, * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this * software constitutes recipient's acceptance of CPL-1.0 terms which can be * found in the file LICENSE file or at * https://opensource.org/licenses/cpl1.0.php */ #include #include #include #include #include "unittest.h" #define STDERR_RC_UNEXP(n, func, rc, exp_rc) \ fprintf(stderr, "[%d] %s: %s (curr: %ld, expected: %ld)\n", \ n, func, "unexpected return value", rc, exp_rc) static char *short_string = "abc"; static char *long_string = "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; static int test_buffer_api(char *s) { int result = 0; long rc, exp_rc; size_t s_len = strlen(s); p11_buffer_t *buf = p11_buffer_new(); /* check for buffer length and size */ if ((*p11_buffer_char(buf) != '\0') || (p11_buffer_char(buf) == NULL) || (p11_buffer_size(buf) == 0) || (strlen(p11_buffer_char(buf)) != 0)) { fprintf(stderr, "[%d] %s: %s\n", 0, "p11_buffer_new()", "wrong initial buffer values"); result++; } /* check corner case s == NULL */ exp_rc = strlen(p11_buffer_char(buf)); rc = p11_buffer_append(buf, NULL); if (rc != exp_rc) { STDERR_RC_UNEXP(1, "p11_buffer_append()", rc, exp_rc); result++; } /* check corner case s == NULL, len == 0 */ exp_rc = strlen(p11_buffer_char(buf)); rc = p11_buffer_append_len(buf, NULL, 0); if (rc != exp_rc) { STDERR_RC_UNEXP(2, "p11_buffer_append_len()", rc, exp_rc); result++; } /* check corner case len == 0 */ exp_rc = strlen(p11_buffer_char(buf)); rc = p11_buffer_append_len(buf, s, 0); if (rc != exp_rc) { STDERR_RC_UNEXP(3, "p11_buffer_append_len()", rc, exp_rc); result++; } /* normal append */ exp_rc = strlen(p11_buffer_char(buf)) + s_len; rc = p11_buffer_append(buf, s); if (rc != exp_rc) { STDERR_RC_UNEXP(4, "p11_buffer_append()", rc, exp_rc); result++; } /* normal append with length */ exp_rc = strlen(p11_buffer_char(buf)) + s_len; rc = p11_buffer_append_len(buf, s, s_len); if (rc != exp_rc) { STDERR_RC_UNEXP(5, "p11_buffer_append()", rc, exp_rc); result++; } /* normal append with printf */ exp_rc = strlen(p11_buffer_char(buf)) + 14 + s_len; rc = p11_buffer_append_printf(buf, "append_prinf(%s)", s); if (rc != exp_rc) { STDERR_RC_UNEXP(6, "p11_buffer_append()", rc, exp_rc); result++; } /* reset buffer */ p11_buffer_reset(buf); if ((*p11_buffer_char(buf) != '\0') || (strlen(p11_buffer_char(buf)) != 0)) { fprintf(stderr, "[%d] %s: %s\n", 7, "p11_buffer_reset()", "wrong buffer values after reset"); result++; } p11_buffer_free(buf); return result; } int main(void) { if (test_buffer_api(short_string)) return TEST_FAIL; if (test_buffer_api(long_string)) return TEST_FAIL; return TEST_PASS; } opencryptoki-opencryptoki-451d99c/testcases/unit/configdump.c000066400000000000000000000052611520105705100246040ustar00rootroot00000000000000#include "unittest.h" #include #include #include #include #include "platform.h" #if defined(_AIX) const char *__progname = "configdump"; #endif static const char test1[] = "foo = 1\nbar = 2\n"; static const char test2[] = "foo = 1 bar = 2\n"; static const char test3[] = "foo {\n bar = 1\n buzz = 2\n}\n"; static const char test4[] = "foo {\n bar = 1 buzz = 2\n}\n"; static const char test5[] = "foo ( bar, buzz )\n"; static const char test6[] = "foo (\n bar,\n buzz\n )\n"; static const char test7[] = "foo\n(\n bar,\n buzz\n)\n"; static const char nested1[] = "nested {\n foo (\n bar,\n buzz\n )\n}\n"; static const char nested2[] = "nested {\n foo\n (\n bar,\n buzz\n )\n}\n"; static const char numpair1[] = "foo\n 1 2\n 3 4\nbar\n"; static const char bare1[] = "foo\n"; static const char bare2[] = "foo bar\n"; static const char bare3[] = "foo\nbar\n"; static const char bare4[] = "\"foo\"\n"; static const char bare5[] = "\"foo\"\n\"bar\"\n"; static const char bare6[] = "foo \"bar\"\n"; static char outbuf[1024]; static const char *curtest; static FILE *opentest(const char *test) { FILE *res = fmemopen((char *)test, strlen(test), "r"); if (!res) err(TEST_FAIL, "Could not fmemopen test string \"%s\"", test); return res; } static FILE *openout(void) { FILE *res = fmemopen(outbuf, sizeof(outbuf), "w"); if (!res) err(TEST_FAIL, "Could not fmemopen output"); return res; } static void parse_error(int line, int col, const char *msg) { errx(TEST_FAIL, "Parsing \"%s\", line %d, col %d: %s\n", curtest, line, col, msg); } static void runparsedumptest(const char *test) { struct ConfigBaseNode *config; FILE *in, *out; int ret; curtest = test; in = opentest(test); out = openout(); ret = parse_configlib_file(in, &config, parse_error, 1); fclose(in); if (ret) errx(TEST_FAIL, "Failed to parse \"%s\"", test); confignode_dump(out, config, NULL, 2); fclose(out); confignode_deepfree(config); if (strcmp(test, outbuf)) errx(TEST_FAIL, "Expected \"%s\", but got \"%s\"!", test, outbuf); } int main(void) { runparsedumptest(test1); runparsedumptest(test2); runparsedumptest(test3); runparsedumptest(test4); runparsedumptest(test5); runparsedumptest(test6); runparsedumptest(test7); runparsedumptest(nested1); runparsedumptest(nested2); runparsedumptest(numpair1); runparsedumptest(bare1); runparsedumptest(bare2); runparsedumptest(bare3); runparsedumptest(bare4); runparsedumptest(bare5); runparsedumptest(bare6); return TEST_PASS; } opencryptoki-opencryptoki-451d99c/testcases/unit/hashmaptest.c000066400000000000000000000137601520105705100247750ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021 * * 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 "hashmap.h" #include "unittest.h" #include #include #include #include #include #include "platform.h" static int testhashcollisionexpansion(void) { CK_ULONG values[] = { /* First 12 values that should end up in the same bucket if simplest hash function is used. Make sure they also end up in the same bucket after the first expansion. */ 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700, 0x800, 0x900, 0xa00, 0xb00, /* Next 12 values that should also end up in the same bucket after the expansion. */ 0x1100, 0x1200, 0x1300, 0x1400, 0x1500, 0x1600, 0x1700, 0x1800, 0x1900, 0x0a00, 0x1b00 }; union hashmap_value val = { .ulVal = 0 }; struct hashmap *h; unsigned long i; int res = 0; h = hashmap_new(); if (!h) { fprintf(stderr, "Failed to allocate mesh hash\n"); return -1; } for (i = 0; i < ARRAYSIZE(values) / 2; ++i) { if (hashmap_add(h, values[i], val, NULL)) { fprintf(stderr, "Failed to add element %lu to meshhash\n", i); res = -1; goto out; } } for (i = 0; i < ARRAYSIZE(values) / 2; ++i) { if (!hashmap_find(h, values[i], NULL)) { fprintf(stderr, "Lost element %lu (%lu) in hashmap\n", i, values[i]); res = -1; goto out; } } for ( ; i < ARRAYSIZE(values); ++i) { if (hashmap_add(h, values[i], val, NULL)) { fprintf(stderr, "Failed to add element %lu to meshhash\n", i); res = -1; goto out; } } for (i = 0; i < ARRAYSIZE(values); ++i) { if (!hashmap_find(h, values[i], NULL)) { fprintf(stderr, "Lost element %lu (%lu) in hashmap after expansion\n", i, values[i]); res = -1; goto out; } } out: hashmap_free(h, NULL); return res; } static int compareulong(const void *a, const void *b) { unsigned long la = *(const unsigned long *)a; unsigned long lb = *(const unsigned long *)b; if (la < lb) return -1; if (la == lb) return 0; return 1; } static int testhashrandom(unsigned long seed, unsigned long iterations) { unsigned long i, *arr, mid, unsucccnt; union hashmap_value val = { .ulVal = 0}; struct hashmap *h; int res = 0; h = hashmap_new(); if (!h) { fprintf(stderr, "Could not allocate hashmap\n"); return -1; } arr = calloc(iterations, sizeof(unsigned long)); if (!arr) { fprintf(stderr, "Failed to allocate data array\n"); res = -1; goto out; } srandom(seed); for (i = 0; i < iterations; ++i) arr[i] = random(); for (i = 0; i < iterations; ++i) { if (hashmap_add(h, arr[i], val, NULL)) { fprintf(stderr, "Failed to add %lu to hash\n", arr[i]); res = -1; goto out; } } /* successful searches */ for (i = 0; i < iterations; ++i) { if (!hashmap_find(h, arr[i], NULL)) { fprintf(stderr, "Failed to find %lu in hash\n", arr[i]); res = -1; goto out; } } /* unsuccessful searches */ unsucccnt = 0; qsort(arr, iterations, sizeof(unsigned long), compareulong); for (i = 0; i < iterations - 1; ++i) { mid = arr[i] + (arr[i + 1] - arr[i]) / 2; if (mid != arr[i]) { ++unsucccnt; if (hashmap_find(h, mid, NULL)) { fprintf(stderr, "Found non-existing element %lu in hash\n", mid); res = -1; goto out; } } } fprintf(stderr, "Performed %lu (expected) unsuccessful searches\n", unsucccnt); out: free(arr); hashmap_free(h, NULL); return res; } static int parseulong(const char *str, unsigned long *res) { unsigned long tmp; char *endptr; errno = 0; tmp = strtoul(str, &endptr, 0); if (*endptr || (tmp == ULONG_MAX && errno == ERANGE)) return 1; *res = tmp; return 0; } int main(int argc, char **argv) { unsigned long seed = 0, iterations = 100; static struct option long_options[] = { {"seed", required_argument, 0, 's'}, {"iterations", required_argument, 0, 'i'}, {0, 0, 0, 0 } }; int c; while (1) { c = getopt_long(argc, argv, "s:i:", long_options, NULL); if (c == -1) break; switch(c) { case 's': if (parseulong(optarg, &seed)) { fprintf(stderr, "Seed could not be parsed!\n"); return TEST_SKIP; } break; case 'i': if (parseulong(optarg, &iterations)) { fprintf(stderr, "Iterations could not be parsed!\n"); return TEST_SKIP; } break; default: printf("USAGE: %s [-s|--seed ] [-i|--iterations ]\n", argv[0]); printf("where the parameters configure the random hash test:\n"); printf("-s or --seed specifies the random seed\n"); printf("-i or --iterations specifies the number of iterations to perform\n"); return TEST_SKIP; } } if (testhashcollisionexpansion()) return TEST_FAIL; if (testhashrandom(seed, iterations)) return TEST_FAIL; /* hashmap_delete function is untested since it is unused so far */ return TEST_PASS; } opencryptoki-opencryptoki-451d99c/testcases/unit/mechtabletest.c000066400000000000000000000047101520105705100252730ustar00rootroot00000000000000#include #include #include "unittest.h" #include int checkstring(void) { unsigned int i; int idx, res = 0; for (i = 0; i < MECHTABLE_NUM_ELEMS; ++i) { idx = mechtable_idx_from_string(mechtable_rows[i].string); if (idx < 0) { fprintf(stderr, "Mechanism %s not found in table!\n", mechtable_rows[i].string); res = -1; } else if ((unsigned int) idx != i) { fprintf(stderr, "Expected mechanism %s at index %u, but query returned %d!\n", mechtable_rows[i].string, i, idx); res = -1; } if (mechrow_from_string(mechtable_rows[i].string) == NULL) { fprintf(stderr, "Unable to get row reference for mechanism %s!\n", mechtable_rows[i].string); res = -1; } } return res; } int checknumeric(void) { unsigned int i; int idx, res = 0; for (i = 0; i < MECHTABLE_NUM_ELEMS; ++i) { idx = mechtable_idx_from_numeric(mechtable_rows[i].numeric); if (idx < 0) { fprintf(stderr, "Mechanism %lu not found in table!\n", mechtable_rows[i].numeric); res = -1; } else if ((unsigned int) idx != i) { fprintf(stderr, "Expected mechanism %lu at index %u, but query returned %d!\n", mechtable_rows[i].numeric, i, idx); res = -1; } if (mechrow_from_numeric(mechtable_rows[i].numeric) == NULL) { fprintf(stderr, "Unable to get row reference for mechanism %lu!\n", mechtable_rows[i].numeric); res = -1; } } return res; } int checkalias(void) { const struct mechrow *row = mechrow_from_string("CKM_ECDSA_KEY_PAIR_GEN"); if (row) return strcmp(row->string, "CKM_EC_KEY_PAIR_GEN"); return -1; } int checkfailure(void) { int idxnum = mechtable_idx_from_numeric(0xffffffffu); int idxstr = mechtable_idx_from_string("CKM_DOES_NOT_EXIST"); int res = 0; if (idxnum != -1) { fprintf(stderr, "Did find 0xffffffff which should not be a valid mechanism!\n"); res = -1; } if (idxstr != -1) { fprintf(stderr, "Did find mechanism CKM_DOES_NOT_EXIST!\n"); res = -1; } return res; } int main(void) { if (checkstring() || checknumeric() || checkalias() || checkfailure()) return TEST_FAIL; return TEST_PASS; } opencryptoki-opencryptoki-451d99c/testcases/unit/pintest.c000066400000000000000000000017201520105705100241330ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2022 * * This program is provided under the terms of the Common Public License, * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this * software constitutes recipient's acceptance of CPL-1.0 terms which can be * found in the file LICENSE file or at * https://opensource.org/licenses/cpl1.0.php */ #include #include #include #include #include "unittest.h" int main(int argc, char *argv[]) { const char *pin; char *buf = NULL; switch(getopt(argc, argv, "pn")) { case 'p': pin = pin_prompt(&buf, "Enter the PIN: "); /* AIX prints an empty string instead of Linux-style (null) */ printf("pin: %s\n", pin != NULL ? pin : "(null)"); break; case 'n': pin = pin_prompt_new(&buf, "Enter new PIN: ", "Re-enter new PIN: "); printf("pin: %s\n", pin != NULL ? pin : "(null)"); break; default: break; } pin_free(&buf); return 0; } opencryptoki-opencryptoki-451d99c/testcases/unit/pintest.sh000077500000000000000000000027401520105705100243310ustar00rootroot00000000000000#!/bin/bash # # COPYRIGHT (c) International Business Machines Corp. 2022 # # This program is provided under the terms of the Common Public License, # version 1.0 (CPL-1.0). Any use, reproduction or distribution for this software # constitutes recipient's acceptance of CPL-1.0 terms which can be found # in the file LICENSE file or at https://opensource.org/licenses/cpl1.0.php PINTEST=testcases/unit/pintest # functions print_test_result() { local msg=$1 local result=$2 local result_exp=$3 if [ "${result}" = "${result_exp}" ]; then printf "${msg}: PASS result: \"${result}\", expected: \"${result_exp}\"\n" RC=0 else printf "${msg}: FAIL result: ${result}, expected: ${result_exp}\n" RC=1 fi return $RC } unset PKCS11_USER_PIN unset PKCS11_SO_PIN TEST_PIN=12345678 RESULT_PIN="pin: ${TEST_PIN}" RESULT_ERR="pin: (null)" # prompt RESULT=$(printf "${TEST_PIN}\n" | ${PINTEST} -p | tail -n1 ) print_test_result "pin prompt" "${RESULT}" "${RESULT_PIN}" || exit 99 RESULT=$(printf "${TEST_PIN}\n${TEST_PIN}\n" | ${PINTEST} -n | tail -n1 ) print_test_result "pin prompt-new" "${RESULT}" "${RESULT_PIN}" || exit 99 RESULT=$(printf "\n\n" | ${PINTEST} -n | tail -n1 ) print_test_result "pin prompt-new" "${RESULT}" "${RESULT_ERR}" || exit 99 RESULT=$(${PINTEST} -p <&- | tail -n1 ) print_test_result "pin prompt-user" "${RESULT}" "${RESULT_ERR}" || exit 99 RESULT=$(${PINTEST} -n <&- | tail -n1 ) print_test_result "pin prompt-new" "${RESULT}" "${RESULT_ERR}" || exit 99 exit 0 opencryptoki-opencryptoki-451d99c/testcases/unit/policytest.c000066400000000000000000000771061520105705100246570ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021 * * 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 "policy.h" #include "ec_defs.h" #include "unittest.h" #include #include #include #define UNUSED(var) ((void)(var)) /* Inlined strength definitions */ static const char niststrength[] = "version strength-0\n" "strength 112 {\n" " MOD_EXP = 2048\n" " ECC = 224\n" " SYMMETRIC = 112\n" " digest = 224\n" " signature = 112\n" "}\n" "strength 128 {\n" " MOD_EXP = 3072\n" " ECC = 256\n" " SYMMETRIC = 128\n" " digest = 256\n" " signature = 128\n" "}\n" "strength 192 {\n" " MOD_EXP = 7680\n" " ECC = 384\n" " SYMMETRIC = 192\n" " digest = 384\n" " signature = 192\n" "}\n" "strength 256 {\n" " MOD_EXP = 15360\n" " ECC = 512\n" " SYMMETRIC = 256\n" " digest = 512\n" " signature = 256\n" "}\n"; static const char quantum112[] = "version strength-0\n" "strength 112 {\n" " SYMMETRIC = 224\n" " digest = 448\n" " signature = 224\n" "}\n"; static const char emptystrength[] = "version strength-0\n"; /* Inlined policies */ static const char policysecponly[] = "version policy-0\n" "strength = 0\n" "allowedcurves ( SECP224R1, SECP384R1, SECP521R1, SECP256K1 )\n"; static const char policynocurves[] = "version policy-0\n" "strength = 0\n" "allowedcurves ( )\n"; static const char policystrength256[] = "version policy-0\n" "strength = 256\n"; static const char policystrength192[] = "version policy-0\n" "strength = 192\n"; static const char policystrength128[] = "version policy-0\n" "strength = 128\n"; static const char policystrength112[] = "version policy-0\n" "strength = 112\n"; static const char policyempty[] = "version policy-0\n" "strength = 0\n"; static const char policynomechs[] = "version policy-0\n" "strength = 0\n" "allowedmechs ()\n"; static const char policyfixedmechs[] = "version policy-0\n" "strength = 0\n" "allowedmechs ( CKM_RSA_PKCS, CKM_ECDSA )\n"; static const char policymgfstandard[] = "version policy-0\n" "strength = 0\n" "allowedmgfs ( CKG_MGF1_SHA1, CKG_MGF1_SHA224, CKG_MGF1_SHA256,\n" "CKG_MGF1_SHA384, CKG_MGF1_SHA512 )\n"; static const char policymgfibm[] = "version policy-0\n" "strength = 0\n" "allowedmgfs ( CKG_IBM_MGF1_SHA3_224, CKG_IBM_MGF1_SHA3_256,\n" "CKG_IBM_MGF1_SHA3_384, CKG_IBM_MGF1_SHA3_512 )\n"; static const char policymgfoneeach[] = "version policy-0\n" "strength = 0\n" "allowedmgfs ( CKG_MGF1_SHA512, CKG_IBM_MGF1_SHA3_224 )\n"; static const char policymgfnone[] = "version policy-0\n" "strength = 0\n" "allowedmgfs ()\n"; static const char policykdfnosha1[] = "version policy-0\n" "strength = 0\n" "allowedkdfs ( CKD_SHA224_KDF, CKD_SHA256_KDF, CKD_SHA384_KDF,\n" "CKD_SHA512_KDF )\n"; static const char policykdfnone[] = "version policy-0\n" "strength = 0\n" "allowedkdfs ()\n"; /* Loading functions (in usr/lib/api/policy.c) */ struct policy_private; extern void policy_init_policy(struct policy *p); extern CK_RV policy_load_strength_cfg(struct policy_private *pp, FILE *fp); extern CK_RV policy_load_policy_cfg(struct policy_private *pp, FILE *fp, CK_BBOOL *restricting); extern struct policy_private *policy_private_alloc(void); extern struct policy_private *policy_private_free(struct policy_private *pp); extern void policy_private_deactivate(struct policy_private *pp); struct keytest { CK_ULONG keytype; union { CK_ULONG value; int nid; } strengthattr; CK_ULONG sigattr; CK_ULONG expstrength;/* Index: 0=256; 1=192; 2=128; 3=112; 4=0 */ CK_ULONG expsiglen; CK_BBOOL expallowed; CK_RV exprc; }; #define STRENGTH_256 0 #define STRENGTH_192 1 #define STRENGTH_128 2 #define STRENGTH_112 3 #define STRENGTH_0 4 #define NUM_KEYTESTS_STRENGTHDET 4 static const struct strengthdettest { const char *definition; size_t definitionsize; struct keytest tests[NUM_KEYTESTS_STRENGTHDET]; } strengthdettests[] = { /* 0: NIST strength definition */ { niststrength, sizeof(niststrength), { { CKK_RSA, { .value = 7680 }, 0, STRENGTH_192, 7680, CK_TRUE, CKR_OK }, { CKK_DSA, { .value = 1024 }, 512, STRENGTH_0, 512 * 2, CK_TRUE, CKR_OK }, { CKK_EC, { .nid = NID_secp224r1 }, 0, STRENGTH_112, 224 * 2, CK_TRUE, CKR_OK }, { CKK_AES, { .value = 156 / 8 }, 0, STRENGTH_128, 128, CK_TRUE, CKR_OK }, } }, /* 1: PQ strength definition */ { quantum112, sizeof(quantum112), { { CKK_RSA, { .value = 7680 }, 0, STRENGTH_0, 7680, CK_TRUE, CKR_OK }, { CKK_DSA, { .value = 1024 }, 512, STRENGTH_0, 512 * 2, CK_TRUE, CKR_OK }, /* allowed is CK_TRUE since no policy is active */ { CKK_EC, { .nid = NID_secp224r1 }, 0, STRENGTH_0, 224 * 2, CK_TRUE, CKR_OK }, { CKK_AES, { .value = 256 / 8 }, 0, STRENGTH_112, 128, CK_TRUE, CKR_OK }, } }, /* 2: empty */ { emptystrength, sizeof(emptystrength), { { CKK_RSA, { .value = 7680 }, 0, STRENGTH_0, 7680, CK_TRUE, CKR_OK }, { CKK_DSA, { .value = 1024 }, 512, STRENGTH_0, 512 * 2, CK_TRUE, CKR_OK }, { CKK_EC, { .nid = NID_secp224r1 }, 0, STRENGTH_0, 224 * 2, CK_TRUE, CKR_OK }, { CKK_AES, { .value = 156 / 8 }, 0, STRENGTH_0, 128, CK_TRUE, CKR_OK }, } } }; #define NUM_KEYTESTS_STRENGTHENFORCE 4 static const struct strengthenforcetest { const char *strength; size_t strengthsize; const char *policy; size_t policysize; struct keytest tests[NUM_KEYTESTS_STRENGTHENFORCE]; } strengthenforcetests[] = { /* 0: NIST strength, require 0 and only secp curves */ { niststrength, sizeof(niststrength), policysecponly, sizeof(policysecponly), { /* MOD_EXP */ { CKK_RSA, { .value = 3072 }, 0, STRENGTH_128, 3072, CK_TRUE, CKR_OK }, /* ECC (Test 0) */ { CKK_EC, { .nid = NID_secp224r1 }, 0, STRENGTH_112, 448, CK_TRUE, CKR_OK }, /* ECC (Test 1) */ { CKK_EC, { .nid = NID_brainpoolP512t1 }, 0, STRENGTH_256, 1024, CK_FALSE, CKR_FUNCTION_FAILED }, /* SYMMETRIC */ { CKK_AES, { .value = 200 / 8 }, 0, STRENGTH_192, 128, CK_TRUE, CKR_OK } } }, /* 1: NIST strength, require 0 and no curves */ { niststrength, sizeof(niststrength), policynocurves, sizeof(policynocurves), { /* MOD_EXP */ { CKK_RSA, { .value = 3072 }, 0, STRENGTH_128, 3072, CK_TRUE, CKR_OK }, /* ECC (Test 0) */ { CKK_EC, { .nid = NID_secp224r1 }, 0, STRENGTH_112, 448, CK_FALSE, CKR_FUNCTION_FAILED }, /* ECC (Test 1) */ { CKK_EC, { .nid = NID_brainpoolP512t1 }, 0, STRENGTH_256, 1024, CK_FALSE, CKR_FUNCTION_FAILED }, /* SYMMETRIC */ { CKK_AES, { .value = 200 / 8 }, 0, STRENGTH_192, 128, CK_TRUE, CKR_OK } } }, /* 2: NIST strength, require 256 */ { niststrength, sizeof(niststrength), policystrength256, sizeof(policystrength256), { /* MOD_EXP */ { CKK_RSA, { .value = 3072 }, 0, STRENGTH_128, 3072, CK_TRUE, CKR_FUNCTION_FAILED }, /* ECC (Test 0) */ { CKK_EC, { .nid = NID_secp224r1 }, 0, STRENGTH_112, 448, CK_TRUE, CKR_FUNCTION_FAILED }, /* ECC (Test 1) */ { CKK_EC, { .nid = NID_brainpoolP512t1 }, 0, STRENGTH_256, 1024, CK_TRUE, CKR_OK }, /* SYMMETRIC */ { CKK_AES, { .value = 200 / 8 }, 0, STRENGTH_192, 128, CK_TRUE, CKR_FUNCTION_FAILED } } }, /* 3: NIST strength, require 192 */ { niststrength, sizeof(niststrength), policystrength192, sizeof(policystrength192), { /* MOD_EXP */ { CKK_RSA, { .value = 3072 }, 0, STRENGTH_128, 3072, CK_TRUE, CKR_FUNCTION_FAILED }, /* ECC (Test 0) */ { CKK_EC, { .nid = NID_secp224r1 }, 0, STRENGTH_112, 448, CK_TRUE, CKR_FUNCTION_FAILED }, /* ECC (Test 1) */ { CKK_EC, { .nid = NID_brainpoolP512t1 }, 0, STRENGTH_256, 1024, CK_TRUE, CKR_OK }, /* SYMMETRIC */ { CKK_AES, { .value = 200 / 8 }, 0, STRENGTH_192, 128, CK_TRUE, CKR_OK } } }, /* 4: NIST strength, require 128 */ { niststrength, sizeof(niststrength), policystrength128, sizeof(policystrength128), { /* MOD_EXP */ { CKK_RSA, { .value = 3072 }, 0, STRENGTH_128, 3072, CK_TRUE, CKR_OK }, /* ECC (Test 0) */ { CKK_EC, { .nid = NID_secp224r1 }, 0, STRENGTH_112, 448, CK_TRUE, CKR_FUNCTION_FAILED }, /* ECC (Test 1) */ { CKK_EC, { .nid = NID_brainpoolP512t1 }, 0, STRENGTH_256, 1024, CK_TRUE, CKR_OK }, /* SYMMETRIC */ { CKK_AES, { .value = 200 / 8 }, 0, STRENGTH_192, 128, CK_TRUE, CKR_OK } } }, /* 5: NIST strength, require 112 */ { niststrength, sizeof(niststrength), policystrength112, sizeof(policystrength112), { /* MOD_EXP */ { CKK_RSA, { .value = 3072 }, 0, STRENGTH_128, 3072, CK_TRUE, CKR_OK }, /* ECC (Test 0) */ { CKK_EC, { .nid = NID_secp224r1 }, 0, STRENGTH_112, 448, CK_TRUE, CKR_OK }, /* ECC (Test 1) */ { CKK_EC, { .nid = NID_brainpoolP512t1 }, 0, STRENGTH_256, 1024, CK_TRUE, CKR_OK }, /* SYMMETRIC */ { CKK_AES, { .value = 200 / 8 }, 0, STRENGTH_192, 128, CK_TRUE, CKR_OK } } }, /* 6: NIST strength, require 0 */ { niststrength, sizeof(niststrength), policyempty, sizeof(policyempty), { /* MOD_EXP */ { CKK_RSA, { .value = 3072 }, 0, STRENGTH_128, 3072, CK_TRUE, CKR_OK }, /* ECC (Test 0) */ { CKK_EC, { .nid = NID_secp224r1 }, 0, STRENGTH_112, 448, CK_TRUE, CKR_OK }, /* ECC (Test 1) */ { CKK_EC, { .nid = NID_brainpoolP512t1 }, 0, STRENGTH_256, 1024, CK_TRUE, CKR_OK }, /* SYMMETRIC */ { CKK_AES, { .value = 200 / 8 }, 0, STRENGTH_192, 128, CK_TRUE, CKR_OK } } } }; /* These tests run with niststrength and policystrength128 */ static const struct policyenforcetest { CK_ULONG strength; CK_ULONG siglen; CK_ULONG mech; int check; CK_RV exprc; } policyenforcetests[] = { { STRENGTH_0, 0, CKM_SHA_1, POLICY_CHECK_DIGEST, CKR_FUNCTION_FAILED }, { STRENGTH_0, 0, CKM_SHA256, POLICY_CHECK_DIGEST, CKR_OK }, { STRENGTH_112, 0, CKM_RSA_PKCS, POLICY_CHECK_ENCRYPT, CKR_FUNCTION_FAILED }, { STRENGTH_128, 0, CKM_RSA_PKCS, POLICY_CHECK_ENCRYPT, CKR_OK }, { STRENGTH_128, 112, CKM_RSA_PKCS, POLICY_CHECK_SIGNATURE, CKR_FUNCTION_FAILED }, { STRENGTH_128, 128, CKM_RSA_PKCS, POLICY_CHECK_SIGNATURE, CKR_OK }, }; static const CK_ULONG testhashmechs[] = { CKM_RSA_PKCS, CKM_SHA1_RSA_PKCS, CKM_ECDSA, CKM_ECDSA_SHA1 }; static const CK_RV testhashempty[] = { CKR_OK, CKR_OK, CKR_OK, CKR_OK }; static const CK_RV testhashnomechs[] = { CKR_FUNCTION_FAILED, CKR_FUNCTION_FAILED, CKR_FUNCTION_FAILED, CKR_FUNCTION_FAILED }; static const CK_RV testhashfixed[] = { CKR_OK, CKR_FUNCTION_FAILED, CKR_OK, CKR_FUNCTION_FAILED }; static const struct policyhashtest { const char *policy; size_t policysize; const CK_ULONG *mechs; const CK_RV *exprcs; size_t nummechs; } policyhashtests[] = { { policyempty, sizeof(policyempty), testhashmechs, testhashempty, ARRAYSIZE(testhashmechs) }, { policynomechs, sizeof(policynomechs), testhashmechs, testhashnomechs, ARRAYSIZE(testhashmechs) }, { policyfixedmechs, sizeof(policyfixedmechs), testhashmechs, testhashfixed, ARRAYSIZE(testhashmechs) } }; /* Helper functions for strength determination */ static CK_RV build_ulong_attr(CK_ATTRIBUTE_TYPE type, CK_ULONG value, CK_ATTRIBUTE **attr) { CK_ATTRIBUTE *a; a = malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_ULONG)); if (a == NULL) return CKR_HOST_MEMORY; a->type = type; a->pValue = ((char *)a) + sizeof(CK_ATTRIBUTE); a->ulValueLen = sizeof(CK_ULONG); *(CK_ULONG *)a->pValue = value; *attr = a; return CKR_OK; } static CK_RV build_bigint_attr(CK_ATTRIBUTE_TYPE type, CK_ULONG numbits, CK_ATTRIBUTE **attr) { CK_ATTRIBUTE *a; CK_ULONG numbytes = numbits / 8u; a = malloc(sizeof(CK_ATTRIBUTE) + numbytes); if (a == NULL) return CKR_HOST_MEMORY; a->type = type; a->pValue = ((char *)a) + sizeof(CK_ATTRIBUTE); a->ulValueLen = numbytes; *attr = a; return CKR_OK; } static CK_RV build_oid_attr(CK_ATTRIBUTE_TYPE type, const CK_BYTE *data, CK_ULONG datasize, CK_ATTRIBUTE **attr) { CK_ATTRIBUTE *a; a = malloc(sizeof(CK_ATTRIBUTE)); if (a == NULL) return CKR_HOST_MEMORY; a->type = type; a->pValue = (void *)data; a->ulValueLen = datasize; *attr = a; return CKR_OK; } static int attrcalls; static CK_RV getdetattr(void *d, CK_ATTRIBUTE_TYPE type, CK_ATTRIBUTE **attr) { struct keytest *t = d; int i; ++attrcalls; switch (type) { case CKA_KEY_TYPE: return build_ulong_attr(type, t->keytype, attr); case CKA_VALUE_LEN: return build_ulong_attr(type, t->strengthattr.value, attr); case CKA_MODULUS: case CKA_PRIME: return build_bigint_attr(type, t->strengthattr.value, attr); case CKA_SUBPRIME: return build_bigint_attr(type, t->sigattr, attr); case CKA_EC_PARAMS: for (i = 0; i < NUMEC; ++i) { if (der_ec_supported[i].nid == t->strengthattr.nid) return build_oid_attr(type, der_ec_supported[i].data, der_ec_supported[i].data_size, attr); } // Fallthrough default: return CKR_FUNCTION_FAILED; } } static void freedetattr(void *d, CK_ATTRIBUTE *a) { UNUSED(d); --attrcalls; free(a); } static int test_load_strength_cfg(struct policy_private *pp, void *cfg, size_t size) { FILE *fp; CK_RV rc; fp = fmemopen(cfg, size, "r"); if (fp == NULL) { fprintf(stderr, "Failed to memopen strength configuration\n"); return -1; } rc = policy_load_strength_cfg(pp, fp); fclose(fp); if (rc != CKR_OK) { fprintf(stderr, "Strength configuration could not be loaded\n"); return -1; } return 0; } static int test_load_policy_cfg(struct policy_private *pp, void *cfg, size_t size) { FILE *fp; CK_RV rc; CK_BBOOL ignored; fp = fmemopen(cfg, size, "r"); if (fp == NULL) { fprintf(stderr, "Failed to memopen policy\n"); return -1; } rc = policy_load_policy_cfg(pp, fp, &ignored); fclose(fp); if (rc != CKR_OK) { fprintf(stderr, "Policy configuration could not be loaded\n"); return -1; } return 0; } static int runstrengthdettests(void) { struct objstrength strength; struct policy_private *pp; const struct keytest *t; struct policy p; unsigned int o; CK_RV rc; int res; int i; fprintf(stderr, "Running strengthdettests\n"); res = 0; policy_init_policy(&p); for (o = 0; o < ARRAYSIZE(strengthdettests); ++o) { pp = policy_private_alloc(); if (pp == NULL) { fprintf(stderr, "Failed to allocate policy_private\n"); return -1; } policy_private_deactivate(pp); p.priv = pp; if (test_load_strength_cfg(pp, (void *)strengthdettests[o].definition, strengthdettests[o].definitionsize)) { fprintf(stderr, "Test %u: Failed to load strength configuration\n", o); return -1; } for (i = 0; i < NUM_KEYTESTS_STRENGTHDET; ++i) { attrcalls = 0; t = &(strengthdettests[o].tests[i]); rc = p.store_object_strength(&p, &strength, getdetattr, (void *)t, freedetattr, NULL); if (rc != CKR_OK) { res = -1; fprintf(stderr, "Test %u, case %i: Could not store object strength\n", o, i); break; } if (strength.strength != t->expstrength) { res = -1; fprintf(stderr, "Test %u, case %i: Unexpected strength:\nexpected: %lu\nis: %lu\n", o, i, t->expstrength, strength.strength); break; } if (strength.siglen != t->expsiglen) { res = -1; fprintf(stderr, "Test %u, case %i: Unexpected siglen:\nexpected: %lu\nis: %lu\n", o, i, t->expsiglen, strength.siglen); break; } if (t->keytype == CKK_EC && strength.allowed != t->expallowed) { res = -1; fprintf(stderr, "Test %u, case %i: Unexpected EC allowed flag\n", o, i); break; } if (attrcalls != 0) { res = -1; fprintf(stderr, "Unbalanced attribute calls. Count shows %i!\n", attrcalls); break; } } p.priv = policy_private_free(pp); if (res != 0) break; } return res; } static int runstrengthenforcetests(void) { struct objstrength strength; struct policy_private *pp; const struct keytest *t; struct policy p; unsigned int o; CK_RV rc; int res; int i; fprintf(stderr, "Running strengthenforcetests\n"); res = 0; policy_init_policy(&p); for (o = 0; o < ARRAYSIZE(strengthenforcetests); ++o) { pp = policy_private_alloc(); if (pp == NULL) { fprintf(stderr, "Test %u: Failed to allocate policy_private\n", o); return -1; } p.priv = pp; if (test_load_strength_cfg(pp,(void *)strengthenforcetests[o].strength, strengthenforcetests[o].strengthsize)) { policy_private_free(pp); fprintf(stderr, "Test %u: Failed to load strength configuration\n", o); return -1; } if (test_load_policy_cfg(pp, (void *)strengthenforcetests[o].policy, strengthenforcetests[o].policysize)) { policy_private_free(pp); fprintf(stderr, "Test %u: Failed to load policy configuration\n", o); return -1; } for (i = 0; i < NUM_KEYTESTS_STRENGTHENFORCE; ++i) { attrcalls = 0; t = &(strengthenforcetests[o].tests[i]); rc = p.store_object_strength(&p, &strength, getdetattr, (void *)t, freedetattr, NULL); if (rc != t->exprc) { res = -1; fprintf(stderr, "Test %u, case %i: Wrong result on strength determination: expected %lu, got %lu\n", o, i, t->exprc, rc); break; } /* Even if we get CKR_FUNCTION_FAILED, the policy should have stored the correct strength information. */ if (strength.strength != t->expstrength) { res = -1; fprintf(stderr, "Test %u, case %i: Unexpected strength:\nexpected: %lu\nis: %lu\n", o, i, t->expstrength, strength.strength); break; } if (strength.siglen != t->expsiglen) { res = -1; fprintf(stderr, "Test %u, case %i: Unexpected siglen:\nexpected: %lu\nis: %lu\n", o, i, t->expsiglen, strength.siglen); break; } if (t->keytype == CKK_EC && strength.allowed != t->expallowed) { res = -1; fprintf(stderr, "Test %u, case %i: Unexpected EC allowed flag\n", o, i); break; } if (attrcalls != 0) { res = -1; fprintf(stderr, "Unbalanced attribute calls. Count shows %i!\n", attrcalls); break; } } p.priv = policy_private_free(pp); if (res != 0) break; } return res; } static int runpolicyenforcetests(void) { struct objstrength strength, *s; struct policy_private *pp; CK_MECHANISM mech; struct policy p; unsigned int i; CK_RV rc; int res; fprintf(stderr, "Running policyenforcetests\n"); res = 0; mech.pParameter = NULL; mech.ulParameterLen = 0; strength.allowed = CK_TRUE; policy_init_policy(&p); pp = policy_private_alloc(); if (pp == NULL) { fprintf(stderr, "Failed to allocate policy_private\n"); return -1; } p.priv = pp; if (test_load_strength_cfg(pp, (void *)niststrength, sizeof(niststrength))) { policy_private_free(pp); fprintf(stderr, "Failed to load NIST strength configuration\n"); return -1; } if (test_load_policy_cfg(pp, (void *)policystrength128, sizeof(policystrength128))) { policy_private_free(pp); fprintf(stderr, "Failed to load policy with strength 128\n"); return -1; } for (i = 0; i < ARRAYSIZE(policyenforcetests); ++i) { strength.strength = policyenforcetests[i].strength; strength.siglen = policyenforcetests[i].siglen; s = policyenforcetests[i].check == POLICY_CHECK_DIGEST ? NULL : &strength; mech.mechanism = policyenforcetests[i].mech; rc = p.is_mech_allowed(&p, &mech, s, policyenforcetests[i].check, NULL); if (rc != policyenforcetests[i].exprc) { fprintf(stderr, "Test %u: Unexpected result: 0x%lx (expected 0x%lx)\n", i, rc, policyenforcetests[i].exprc); res = -1; } } policy_private_free(pp); return res; } static int runpolicyhashtests(void) { struct objstrength strength; struct policy_private *pp; CK_MECHANISM mech; struct policy p; unsigned int o, i; CK_RV rc; int res; fprintf(stderr, "Running policyhashtests\n"); res = 0; policy_init_policy(&p); mech.pParameter = NULL; mech.ulParameterLen = 0; strength.strength = 0; strength.siglen = 0; strength.allowed = CK_TRUE; for (o = 0; o < ARRAYSIZE(policyhashtests); ++o) { pp = policy_private_alloc(); if (pp == NULL) { fprintf(stderr, "Test %u: Failed to allocate policy_private\n", o); return -1; } p.priv = pp; if (test_load_strength_cfg(pp,(void *)niststrength, sizeof(niststrength))) { policy_private_free(pp); fprintf(stderr, "Test %u: Failed to load strength configuration\n", o); return -1; } if (test_load_policy_cfg(pp, (void *)policyhashtests[o].policy, policyhashtests[o].policysize)) { policy_private_free(pp); fprintf(stderr, "Test %u: Failed to load policy configuration\n", o); return -1; } for (i = 0; i < policyhashtests[o].nummechs; ++i) { mech.mechanism = policyhashtests[o].mechs[i]; /* check is wrong for most, but is chosen to not perform any additional size checking. */ rc = p.is_mech_allowed(&p, &mech, &strength, POLICY_CHECK_ENCRYPT, NULL); if (rc != policyhashtests[o].exprcs[i]) { fprintf(stderr, "Test %u case %u: Wrong result: 0x%lx (expected 0x%lx)\n", o, i, rc, policyhashtests[o].exprcs[i]); res = -1; } } policy_private_free(pp); } return res; } #define POLICYDEEPCHECKMGFNUM 4 static int runpolicydeepcheckmgftests(void) { static const CK_ULONG mgfs[POLICYDEEPCHECKMGFNUM] = { CKG_MGF1_SHA1, CKG_MGF1_SHA512, CKG_IBM_MGF1_SHA3_224, CKG_IBM_MGF1_SHA3_384 }; static const struct { const char *policy; size_t policylen; CK_RV exprc[POLICYDEEPCHECKMGFNUM]; } policies[] = { { policyempty, sizeof(policyempty), {CKR_OK, CKR_OK, CKR_OK, CKR_OK} }, { policymgfstandard, sizeof(policymgfstandard), {CKR_OK, CKR_OK, CKR_FUNCTION_FAILED, CKR_FUNCTION_FAILED} }, { policymgfibm, sizeof(policymgfibm), { CKR_FUNCTION_FAILED, CKR_FUNCTION_FAILED, CKR_OK, CKR_OK} }, { policymgfoneeach, sizeof(policymgfoneeach), { CKR_FUNCTION_FAILED, CKR_OK, CKR_OK, CKR_FUNCTION_FAILED} }, { policymgfnone, sizeof(policymgfnone), { CKR_FUNCTION_FAILED, CKR_FUNCTION_FAILED, CKR_FUNCTION_FAILED, CKR_FUNCTION_FAILED } } }; struct objstrength strength; struct policy_private *pp; CK_MECHANISM oaepmech, pssmech; struct policy p; unsigned int i, o; CK_RV rc; int res; CK_RSA_PKCS_OAEP_PARAMS oaepparams; CK_RSA_PKCS_PSS_PARAMS pssparams; fprintf(stderr, "Running policydeepcheckmgftests\n"); res = 0; policy_init_policy(&p); oaepparams.hashAlg = CKM_SHA_1; oaepparams.source = CKZ_DATA_SPECIFIED; oaepparams.pSourceData = NULL; oaepparams.ulSourceDataLen = 0; pssparams.hashAlg = CKM_SHA_1; pssparams.sLen = 0; strength.strength = 0; strength.siglen = 0; strength.allowed = CK_TRUE; oaepmech.mechanism = CKM_RSA_PKCS_OAEP; oaepmech.pParameter = &oaepparams; oaepmech.ulParameterLen = sizeof(oaepparams); pssmech.mechanism = CKM_RSA_PKCS_PSS; pssmech.pParameter = &pssparams; pssmech.ulParameterLen = sizeof(pssparams); for (o = 0; o < ARRAYSIZE(policies); ++o) { pp = policy_private_alloc(); if (pp == NULL) { fprintf(stderr, "Test %u: Failed to allocate policy_private\n", o); return -1; } p.priv = pp; if (test_load_strength_cfg(pp,(void *)niststrength, sizeof(niststrength))) { policy_private_free(pp); fprintf(stderr, "Test %u: Failed to load strength configuration\n", o); return -1; } if (test_load_policy_cfg(pp, (void *)policies[o].policy, policies[o].policylen)) { policy_private_free(pp); fprintf(stderr, "Test %u: Failed to load policy configuration\n", o); return -1; } for (i = 0; i < ARRAYSIZE(mgfs); ++i) { oaepparams.mgf = pssparams.mgf = mgfs[i]; /* Checking encrypt prevents output size checking here which is not the goal of this test. */ rc = p.is_mech_allowed(&p, &oaepmech, &strength, POLICY_CHECK_ENCRYPT, NULL); if (rc != policies[o].exprc[i]) { fprintf(stderr, "Test %u, case %u, OAEP: unexpected result 0x%lx (expected 0x%lx)\n", o, i, rc, policies[o].exprc[i]); res = -1; } rc = p.is_mech_allowed(&p, &pssmech, &strength, POLICY_CHECK_ENCRYPT, NULL); if (rc != policies[o].exprc[i]) { fprintf(stderr, "Test %u, case %u, PSS: unexpected result 0x%lx (expected 0x%lx)\n", o, i, rc, policies[o].exprc[i]); res = -1; } } p.priv = pp = policy_private_free(pp); } return res; } #define POLICYDEEPCHECKKDFNUM 4 static int runpolicydeepcheckkdftests(void) { static const CK_ULONG kdfs[POLICYDEEPCHECKKDFNUM] = { CKD_NULL, CKD_SHA1_KDF_ASN1, CKD_SHA256_KDF, CKD_SHA512_KDF }; static const struct { const char *policy; size_t policylen; CK_RV exprc[POLICYDEEPCHECKKDFNUM]; } policies[] = { { policyempty, sizeof(policyempty), { CKR_OK, CKR_OK, CKR_OK, CKR_OK } }, { policykdfnosha1, sizeof(policykdfnosha1), { CKR_FUNCTION_FAILED, CKR_FUNCTION_FAILED, CKR_OK, CKR_OK } }, { policykdfnone, sizeof(policykdfnone), { CKR_FUNCTION_FAILED, CKR_FUNCTION_FAILED, CKR_FUNCTION_FAILED, CKR_FUNCTION_FAILED } } }; CK_ECDH1_DERIVE_PARAMS ecdhparams; struct objstrength strength; struct policy_private *pp; CK_MECHANISM mech; struct policy p; unsigned int i, o; CK_RV rc; int res; fprintf(stderr, "Running policydeepcheckkdftests\n"); res = 0; policy_init_policy(&p); strength.strength = 0; strength.siglen = 0; strength.allowed = CK_TRUE; ecdhparams.ulSharedDataLen = 0; ecdhparams.pSharedData = NULL; ecdhparams.ulPublicDataLen = 0; ecdhparams.pPublicData = NULL; mech.mechanism = CKM_ECDH1_DERIVE; mech.pParameter = &ecdhparams; mech.ulParameterLen = sizeof(ecdhparams); for (o = 0; o < ARRAYSIZE(policies); ++o) { fprintf(stderr, "Test %u\n", o); pp = policy_private_alloc(); if (pp == NULL) { fprintf(stderr, "Test %u: Failed to allocate policy_private\n", o); return -1; } p.priv = pp; if (test_load_strength_cfg(pp,(void *)niststrength, sizeof(niststrength))) { policy_private_free(pp); fprintf(stderr, "Test %u: Failed to load strength configuration\n", o); return -1; } if (test_load_policy_cfg(pp, (void *)policies[o].policy, policies[o].policylen)) { policy_private_free(pp); fprintf(stderr, "Test %u: Failed to load policy configuration\n", o); return -1; } for (i = 0; i < ARRAYSIZE(kdfs); ++i) { fprintf(stderr, "Case %u\n", i); ecdhparams.kdf = kdfs[i]; rc = p.is_mech_allowed(&p, &mech, &strength, POLICY_CHECK_DERIVE, NULL); if (rc != policies[o].exprc[i]) { fprintf(stderr, "Test %u, case %u: unexpected result 0x%lx (expected 0x%lx)\n", o, i, rc, policies[o].exprc[i]); res = -1; } } p.priv = pp = policy_private_free(pp); } return res; } static int runpolicydeepchecktests(void) { return runpolicydeepcheckmgftests() | runpolicydeepcheckkdftests(); } static int runstrengthtests(void) { return runstrengthdettests() | runstrengthenforcetests(); } static int runpolicytests(void) { return runpolicyenforcetests() | runpolicyhashtests() | runpolicydeepchecktests(); } int main(void) { if (runstrengthtests()) return TEST_FAIL; if (runpolicytests()) return TEST_FAIL; return TEST_PASS; } opencryptoki-opencryptoki-451d99c/testcases/unit/unit.mk000066400000000000000000000060141520105705100236120ustar00rootroot00000000000000check_PROGRAMS = testcases/unit/policytest testcases/unit/hashmaptest \ testcases/unit/mechtabletest testcases/unit/configdump \ testcases/unit/buffertest testcases/unit/uritest \ testcases/unit/pintest TESTS = testcases/unit/policytest testcases/unit/hashmaptest \ testcases/unit/mechtabletest testcases/unit/configdump \ testcases/unit/buffertest testcases/unit/uritest \ testcases/unit/pintest.sh EXTRA_DIST += testcases/unit/pintest.sh noinst_HEADERS += testcases/unit/unittest.h testcases_unit_policytest_CFLAGS=-I${top_srcdir}/usr/lib/common \ -I${top_srcdir}/usr/lib/api -I${top_srcdir}/usr/include \ -DSTDLL_NAME=\"policytest\" -I${top_srcdir}/usr/lib/config \ -I${top_builddir}/usr/lib/config -I${top_builddir}/usr/lib/api if AIX testcases_unit_policytest_LDFLAGS=-lpthread endif testcases_unit_policytest_SOURCES=testcases/unit/policytest.c \ usr/lib/api/policy.c usr/lib/api/hashmap.c \ usr/lib/common/ec_supported.c usr/lib/common/trace.c \ usr/lib/common/utility_common.c \ usr/lib/config/configuration.c \ usr/lib/common/ec_curve_translation.c \ usr/lib/common/kdf_translation.c \ usr/lib/common/mgf_translation.c \ usr/lib/api/supportedstrengths.c \ usr/lib/config/cfgparse.y usr/lib/config/cfglex.l \ usr/lib/common/pqc_supported.c nodist_testcases_unit_policytest_SOURCES=usr/lib/api/mechtable.c testcases_unit_hashmaptest_CFLAGS=-I${top_srcdir}/usr/lib/api \ -I${top_srcdir}/usr/include -I${srcdir}/usr/lib/common testcases_unit_hashmaptest_SOURCES = testcases/unit/hashmaptest.c \ usr/lib/api/hashmap.c if AIX testcases_unit_hashmaptest_SOURCES += usr/lib/common/aix/getopt_long.c endif testcases_unit_mechtabletest_CFLAGS=-I${top_srcdir}/usr/lib/api \ -I${top_srcdir}/usr/include -I${top_builddir}/usr/lib/api testcases_unit_mechtabletest_SOURCES=testcases/unit/mechtabletest.c nodist_testcases_unit_mechtabletest_SOURCES=usr/lib/api/mechtable.c testcases_unit_configdump_SOURCES = testcases/unit/configdump.c \ usr/lib/config/cfglex.l usr/lib/config/cfgparse.y \ usr/lib/config/configuration.c if AIX testcases_unit_configdump_SOURCES += usr/lib/common/aix/err.c endif testcases_unit_configdump_CFLAGS=-I${top_srcdir}/usr/lib/config \ -I${top_builddir}/usr/lib/config -I${top_srcdir}/usr/include \ -I${srcdir}/usr/lib/common testcases_unit_buffertest_SOURCES=testcases/unit/buffertest.c \ usr/lib/common/buffer.c testcases_unit_buffertest_CFLAGS=-I${top_srcdir}/usr/lib/common \ -I$(top_srcdir)/usr/include testcases_unit_uritest_SOURCES=testcases/unit/uritest.c \ usr/lib/common/uri.c usr/lib/common/buffer.c \ usr/lib/common/p11util.c testcases_unit_uritest_CFLAGS=-I${top_srcdir}/usr/lib/common \ -I${top_srcdir}/usr/include -I${top_builddir}/usr/lib/api \ -I${srcdir}/usr/lib/common -I${srcdir}/usr/include \ -I${srcdir}/usr/lib/api testcases_unit_pintest_SOURCES=testcases/unit/pintest.c \ usr/lib/common/buffer.c usr/lib/common/pin_prompt.c testcases_unit_pintest_CFLAGS=-I${top_srcdir}/usr/lib/common \ -I${top_srcdir}/usr/include testcases_unit_pintest_LDFLAGS=-lcrypto opencryptoki-opencryptoki-451d99c/testcases/unit/unittest.h000066400000000000000000000011031520105705100243240ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021 * * 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 UNITTEST_H #define UNITTEST_H /* AUTOTOOLS definitions for tests */ #define TEST_SKIP 77 #define TEST_FAIL 99 #define TEST_PASS 0 #define ARRAYSIZE(X) (sizeof((X))/sizeof((X)[0])) #endif opencryptoki-opencryptoki-451d99c/testcases/unit/uritest.c000066400000000000000000000277751520105705100241660ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2022 * * This program is provided under the terms of the Common Public License, * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this * software constitutes recipient's acceptance of CPL-1.0 terms which can be * found in the file LICENSE file or at * https://opensource.org/licenses/cpl1.0.php */ #include #include #include #include #include #include "unittest.h" #define BUFLEN 128 #define MIN(a, b) (a < b) ? (a) : (b) #define BINIT(s, e) memset(s.e, ' ', sizeof(s.e)) #define SCPY(s, e, c) _cpy(s.e, sizeof(s.e), c) static CK_INFO i; static CK_SLOT_INFO s; static CK_TOKEN_INFO t; static CK_OBJECT_CLASS cko_data = CKO_DATA; static CK_OBJECT_CLASS cko_pubk = CKO_PUBLIC_KEY; static CK_OBJECT_CLASS cko_cert = CKO_CERTIFICATE; static CK_OBJECT_CLASS cko_prvk = CKO_PRIVATE_KEY; static CK_OBJECT_CLASS cko_seck = CKO_SECRET_KEY; static CK_CHAR ckc_id_buf[BUFLEN]; static CK_CHAR ckc_label_buf[BUFLEN]; static void _cpy(unsigned char *dest, size_t d_len, char *src) { size_t s_len; if (!src) return; s_len = strlen(src); memcpy(dest, src, MIN(s_len, d_len)); } static void _gen_uri(struct p11_uri *uri, char *i_dsc, char *i_man, int i_vmj, int i_vmi, int s_id, char *s_dsc, char *s_man, char *t_lbl, char *t_man, char *t_mod, char *t_ser, char *o_id, char *o_lbl, CK_OBJECT_CLASS_PTR o_type) { /* initialize string fields */ BINIT(i, manufacturerID); BINIT(i, libraryDescription); BINIT(s, manufacturerID); BINIT(s, slotDescription); BINIT(t, label); BINIT(t, manufacturerID); BINIT(t, model); BINIT(t, serialNumber); /* initialize attribute templates */ memset(ckc_id_buf, '\0', BUFLEN); memset(ckc_label_buf, '\0', BUFLEN); /* info */ SCPY(i, manufacturerID, i_man); SCPY(i, libraryDescription, i_dsc); i.libraryVersion.major = i_vmj; i.libraryVersion.minor = i_vmi; /* slot */ uri->slot_id = -1; if (s_id >= 0) uri->slot_id = s_id; SCPY(s, manufacturerID, s_man); SCPY(s, slotDescription, s_dsc); /* token */ SCPY(t, label, t_lbl); SCPY(t, manufacturerID, t_man); SCPY(t, model, t_mod); SCPY(t, serialNumber, t_ser); uri->info = NULL; if (i_man || i_dsc) uri->info = &i; uri->slot_info = NULL; if (s_man || s_dsc) uri->slot_info = &s; uri->token_info = NULL; if (t_lbl || t_man || t_mod || t_ser) uri->token_info = &t; if (o_type) { uri->obj_class[0].type = CKA_CLASS; uri->obj_class[0].pValue = o_type; uri->obj_class[0].ulValueLen = sizeof(CK_OBJECT_CLASS); } if (o_id) { memcpy(ckc_id_buf, o_id, strlen(o_id)); uri->obj_id[0].type = CKA_ID; uri->obj_id[0].pValue = ckc_id_buf; uri->obj_id[0].ulValueLen = strlen(o_id); } if (o_lbl) { memcpy(ckc_label_buf, o_lbl, strlen(o_lbl)); uri->obj_label[0].type = CKA_LABEL; uri->obj_label[0].pValue = ckc_label_buf; uri->obj_label[0].ulValueLen = strlen(o_lbl); } } static void _alloc_attr(CK_ATTRIBUTE_PTR attr) { attr->pValue = malloc(8); if (!attr->pValue) return; attr->ulValueLen = 8; } static void _alloc_attrs(struct p11_uri *uri) { _alloc_attr(&uri->obj_id[0]); _alloc_attr(&uri->obj_label[0]); _alloc_attr(&uri->obj_class[0]); } static int test_uri_base(void) { int result = 0; struct p11_uri *uri; uri = p11_uri_new(); if (!uri) return 1; if ((uri == NULL) || (uri->priv == NULL)) { fprintf(stderr, "[%d] %s: %s\n", 0, "p11_uri_new()", "wrong initial uri values"); result++; } p11_uri_free(uri); uri = p11_uri_new(); if (!uri) return 1; _alloc_attrs(uri); p11_uri_attributes_free(uri); if ((uri->obj_id[0].pValue) || (uri->obj_id[0].ulValueLen) || (uri->obj_label[0].pValue) || (uri->obj_label[0].ulValueLen) || (uri->obj_class[0].pValue) || (uri->obj_class[0].ulValueLen)) { fprintf(stderr, "[%d] %s: %s\n", 1, "p11_uri_attributes_free()", "wrong uri attribute values after free"); result++; } p11_uri_free(uri); return result; } static int test_uri_format(void) { int result = 0; const char *cur_uri, *exp_uri; struct p11_uri *uri; uri = p11_uri_new(); if (!uri) return 1; exp_uri = "pkcs11:library-description=testLib;library-manufacturer=ACME;library-version=47.11"; _gen_uri(uri, "testLib", "ACME", 47, 11, -1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); cur_uri = p11_uri_format(uri); if (strcmp(cur_uri, exp_uri) != 0) { fprintf(stderr,"[%d] p11_uri_format(): curr: %s, expected: %s\n", 0, cur_uri, exp_uri); result++; } p11_uri_free(uri); uri = p11_uri_new(); if (!uri) return 1; exp_uri = "pkcs11:slot-id=0;slot-description=testslot;slot-manufacturer=ACME"; _gen_uri(uri, NULL, NULL, -1, -1, 0, "testslot", "ACME", NULL, NULL, NULL, NULL, NULL, NULL, NULL); cur_uri = p11_uri_format(uri); if (strcmp(cur_uri, exp_uri) != 0) { fprintf(stderr,"[%d] p11_uri_format(): curr: %s, expected: %s\n", 1, cur_uri, exp_uri); result++; } p11_uri_free(uri); uri = p11_uri_new(); if (!uri) return 1; exp_uri = "pkcs11:manufacturer=ACME;model=TestModel;serial=0123456789;token=testtok"; _gen_uri(uri, NULL, NULL, -1, -1, -1, NULL, NULL, "testtok", "ACME", "TestModel", "0123456789", NULL, NULL, NULL); cur_uri = p11_uri_format(uri); if (strcmp(cur_uri, exp_uri) != 0) { fprintf(stderr,"[%d] p11_uri_format(): curr: %s, expected: %s\n", 2, cur_uri, exp_uri); result++; } p11_uri_free(uri); uri = p11_uri_new(); if (!uri) return 1; exp_uri = "pkcs11:id=%30%31%32%33%34%35%36%37%38%39%61%62%63;object=testo_data;type=data"; _gen_uri(uri, NULL, NULL, -1, -1, -1, NULL, NULL, NULL, NULL, NULL, NULL, "0123456789abc", "testo_data", &cko_data); cur_uri = p11_uri_format(uri); if (strcmp(cur_uri, exp_uri) != 0) { fprintf(stderr,"[%d] p11_uri_format(): curr: %s, expected: %s\n", 3, cur_uri, exp_uri); result++; } p11_uri_free(uri); uri = p11_uri_new(); if (!uri) return 1; exp_uri = "pkcs11:id=%30%31%32%33%34%35%36%37%38%39%61%62%63;object=testo_privk;type=private"; _gen_uri(uri, NULL, NULL, -1, -1, -1, NULL, NULL, NULL, NULL, NULL, NULL, "0123456789abc", "testo_privk", &cko_prvk); cur_uri = p11_uri_format(uri); if (strcmp(cur_uri, exp_uri) != 0) { fprintf(stderr,"[%d] p11_uri_format(): curr: %s, expected: %s\n", 4, cur_uri, exp_uri); result++; } p11_uri_free(uri); uri = p11_uri_new(); if (!uri) return 1; exp_uri = "pkcs11:id=%30%31%32%33%34%35%36%37%38%39%61%62%63;object=testo_pubk;type=public"; _gen_uri(uri, NULL, NULL, -1, -1, -1, NULL, NULL, NULL, NULL, NULL, NULL, "0123456789abc", "testo_pubk", &cko_pubk); cur_uri = p11_uri_format(uri); if (strcmp(cur_uri, exp_uri) != 0) { fprintf(stderr,"[%d] p11_uri_format(): curr: %s, expected: %s\n", 5, cur_uri, exp_uri); result++; } p11_uri_free(uri); uri = p11_uri_new(); if (!uri) return 1; exp_uri = "pkcs11:id=%30%31%32%33%34%35%36%37%38%39%61%62%63;object=testo_seck;type=secret-key"; _gen_uri(uri, NULL, NULL, -1, -1, -1, NULL, NULL, NULL, NULL, NULL, NULL, "0123456789abc", "testo_seck", &cko_seck); cur_uri = p11_uri_format(uri); if (strcmp(cur_uri, exp_uri) != 0) { fprintf(stderr,"[%d] p11_uri_format(): curr: %s, expected: %s\n", 6, cur_uri, exp_uri); result++; } p11_uri_free(uri); uri = p11_uri_new(); if (!uri) return 1; exp_uri = "pkcs11:id=%30%31%32%33%34%35%36%37%38%39%61%62%63;object=testo_cert;type=cert"; _gen_uri(uri, NULL, NULL, -1, -1, -1, NULL, NULL, NULL, NULL, NULL, NULL, "0123456789abc", "testo_cert", &cko_cert); cur_uri = p11_uri_format(uri); if (strcmp(cur_uri, exp_uri) != 0) { fprintf(stderr,"[%d] p11_uri_format(): curr: %s, expected: %s\n", 7, cur_uri, exp_uri); result++; } p11_uri_free(uri); uri = p11_uri_new(); if (!uri) return 1; exp_uri = "pkcs11:"; _gen_uri(uri, NULL, NULL, -1, -1, -1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); cur_uri = p11_uri_format(uri); if (strcmp(cur_uri, exp_uri) != 0) { fprintf(stderr,"[%d] p11_uri_format(): curr: %s, expected: %s\n", 8, cur_uri, exp_uri); result++; } p11_uri_free(uri); return result; } static int test_uri_encode(void) { int result = 0; const char *cur_uri, *exp_uri; struct p11_uri *uri; /* common non-encode characters */ uri = p11_uri_new(); if (!uri) return 1; exp_uri = "pkcs11:library-description=abcdefghijklmnopqrstuvwxyz;library-manufacturer=ACME;library-version=47.11"; _gen_uri(uri, "abcdefghijklmnopqrstuvwxyz", "ACME", 47, 11, -1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); cur_uri = p11_uri_format(uri); if (strcmp(cur_uri, exp_uri) != 0) { fprintf(stderr,"[%d] p11_uri_format(): curr: %s, expected: %s\n", 0, cur_uri, exp_uri); result++; } p11_uri_free(uri); uri = p11_uri_new(); if (!uri) return 1; exp_uri = "pkcs11:library-description=ABCDEFGHIJKLMNOPQRSTUVWXYZ;library-manufacturer=ACME;library-version=47.11"; _gen_uri(uri, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "ACME", 47, 11, -1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); cur_uri = p11_uri_format(uri); if (strcmp(cur_uri, exp_uri) != 0) { fprintf(stderr,"[%d] p11_uri_format(): curr: %s, expected: %s\n", 1, cur_uri, exp_uri); result++; } p11_uri_free(uri); uri = p11_uri_new(); if (!uri) return 1; exp_uri = "pkcs11:library-description=0123456789_-.;library-manufacturer=ACME;library-version=47.11"; _gen_uri(uri, "0123456789_-.", "ACME", 47, 11, -1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); cur_uri = p11_uri_format(uri); if (strcmp(cur_uri, exp_uri) != 0) { fprintf(stderr,"[%d] p11_uri_format(): curr: %s, expected: %s\n", 2, cur_uri, exp_uri); result++; } p11_uri_free(uri); /* reserved non-encode characters */ uri = p11_uri_new(); if (!uri) return 1; exp_uri = "pkcs11:library-description=:[]@!$\'()*+,=;library-manufacturer=ACME;library-version=47.11"; _gen_uri(uri, ":[]@!$\'()*+,=", "ACME", 47, 11, -1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); cur_uri = p11_uri_format(uri); if (strcmp(cur_uri, exp_uri) != 0) { fprintf(stderr,"[%d] p11_uri_format(): curr: %s, expected: %s\n", 3, cur_uri, exp_uri); result++; } p11_uri_free(uri); return result; } int main(void) { if (test_uri_base()) return TEST_FAIL; if (test_uri_format()) return TEST_FAIL; if (test_uri_encode()) return TEST_FAIL; return TEST_PASS; } opencryptoki-opencryptoki-451d99c/tools/000077500000000000000000000000001520105705100204645ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/tools/policyexamplegen.c000066400000000000000000000117141520105705100242010ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021 * * 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 int main(void) { size_t i; char *line = ""; puts("# OpenCryptoki policy example"); puts("# Move/copy to /etc/opencryptoki/policy.conf to use it with opencryptoki."); puts("# Then chown it to root:" PKCS_GROUP " and chmod it to 0640."); puts("# Also create a /etc/opencryptoki/strength.conf since this is a prerequisite"); puts("# for policies. You could just copy the strength-example.conf from this"); puts("# folder, chown it to root:" PKCS_GROUP " and chmod it to 0640."); puts(""); puts("version policy-0"); puts(""); puts("# Do not require any specific strength."); puts("# You probably do not want this!"); puts("strength = 0"); puts(""); puts("# Allow all mechanisms by name."); puts("# A simpler option to configure this is to just remove the allowedmechs list."); puts("allowedmechs ("); for (i = 0; i < MECHTABLE_NUM_ELEMS; ++i) { fputs(line, stdout); printf(" %s", mechtable_rows[i].string); line = ",\n"; } putchar('\n'); puts(" # No comma after last element!"); puts(")"); puts(""); puts("# Allow all elliptic curves."); puts("# A simpler method to configure this is to just remove the allowedcurves list."); puts("allowedcurves ("); puts(" BRAINPOOL_P160R1,"); puts(" BRAINPOOL_P160T1,"); puts(" BRAINPOOL_P192R1,"); puts(" BRAINPOOL_P192T1,"); puts(" BRAINPOOL_P224R1,"); puts(" BRAINPOOL_P224T1,"); puts(" BRAINPOOL_P256R1,"); puts(" BRAINPOOL_P256T1,"); puts(" BRAINPOOL_P320R1,"); puts(" BRAINPOOL_P320T1,"); puts(" BRAINPOOL_P384R1,"); puts(" BRAINPOOL_P384T1,"); puts(" BRAINPOOL_P512R1,"); puts(" BRAINPOOL_P512T1,"); puts(" PRIME192V1,"); puts(" SECP224R1,"); puts(" PRIME256V1,"); puts(" SECP384R1,"); puts(" SECP521R1,"); puts(" SECP256K1,"); puts(" CURVE25519,"); puts(" CURVE448,"); puts(" ED25519,"); puts(" ED448,"); puts(" BLS12_381"); puts(" # No comma after last element!"); puts(")"); puts(""); puts("# Allow all MGFs."); puts("# A simpler method to configure this is to just remove the allowedmgfs list."); puts("allowedmgfs ("); puts(" CKG_MGF1_SHA1,"); puts(" CKG_MGF1_SHA224,"); puts(" CKG_MGF1_SHA256,"); puts(" CKG_MGF1_SHA384,"); puts(" CKG_MGF1_SHA512,"); puts(" CKG_MGF1_SHA3_224,"); puts(" CKG_MGF1_SHA3_256,"); puts(" CKG_MGF1_SHA3_384,"); puts(" CKG_MGF1_SHA3_512,"); puts(" CKG_IBM_MGF1_SHA3_224,"); puts(" CKG_IBM_MGF1_SHA3_256,"); puts(" CKG_IBM_MGF1_SHA3_384,"); puts(" CKG_IBM_MGF1_SHA3_512"); puts(" # No comma after last element!"); puts(")"); puts(""); puts("# Allow all KDFs."); puts("# A simpler method to configure this is to just remove the allowedkdfs list."); puts("allowedkdfs ("); puts(" CKD_NULL,"); puts(" CKD_SHA1_KDF,"); puts(" CKD_SHA1_KDF_ASN1,"); puts(" CKD_SHA1_KDF_CONCATENATE,"); puts(" CKD_SHA224_KDF,"); puts(" CKD_SHA256_KDF,"); puts(" CKD_SHA384_KDF,"); puts(" CKD_SHA512_KDF,"); puts(" CKD_SHA3_224_KDF,"); puts(" CKD_SHA3_256_KDF,"); puts(" CKD_SHA3_384_KDF,"); puts(" CKD_SHA3_512_KDF,"); puts(" CKD_SHA1_KDF_SP800,"); puts(" CKD_SHA224_KDF_SP800,"); puts(" CKD_SHA256_KDF_SP800,"); puts(" CKD_SHA384_KDF_SP800,"); puts(" CKD_SHA512_KDF_SP800,"); puts(" CKD_SHA3_224_KDF_SP800,"); puts(" CKD_SHA3_256_KDF_SP800,"); puts(" CKD_SHA3_384_KDF_SP800,"); puts(" CKD_SHA3_512_KDF_SP800,"); puts(" CKD_IBM_HYBRID_NULL,"); puts(" CKD_IBM_HYBRID_SHA1_KDF,"); puts(" CKD_IBM_HYBRID_SHA224_KDF,"); puts(" CKD_IBM_HYBRID_SHA256_KDF,"); puts(" CKD_IBM_HYBRID_SHA384_KDF,"); puts(" CKD_IBM_HYBRID_SHA512_KDF"); puts(" # No comma after last element!"); puts(")"); puts(""); puts("# Allow all PRFs."); puts("# A simpler method to configure this is to just remove the allowedprfs list."); puts("allowedprfs ("); puts(" CKP_PKCS5_PBKD2_HMAC_SHA256,"); puts(" CKP_PKCS5_PBKD2_HMAC_SHA512"); puts(" # No comma after last element!"); puts(")"); return 0; } opencryptoki-opencryptoki-451d99c/tools/tableidxgen.c000066400000000000000000000521541520105705100231250ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021 * * 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 defined(_AIX) const char *__progname = "tableidxgen"; #endif #include "platform.h" #include #include #include #include #include #include "pkcs11types.h" #define MECHTABLE_IN_GEN #include #undef MECHTABLE_IN_GEN #define ARRAY_SIZE(X) (sizeof((X)) / sizeof((X)[0])) /* To satisfy symbols */ const struct mechtable_funcs mechtable_funcs; int mechtable_idx_from_numeric(CK_ULONG mech) { (void)mech; return -1; } int mechtable_idx_from_string(const char *mech) { (void)mech; return -1; } const struct mechrow *mechrow_from_numeric(CK_ULONG mech) { (void)mech; return NULL; } const struct mechrow *mechrow_from_string(const char *mech) { (void)mech; return NULL; } /* A list of all aliases. Add every non-unique mechanism number once to the table in mechtable.inc and add all aliases here. The one in the table will be the one used in the string output. */ const struct aliaslist { const char *string; const char *alias; } aliases[] = { { "CKM_ECDSA_KEY_PAIR_GEN", "CKM_EC_KEY_PAIR_GEN" }, { "CKM_IBM_EC_C25519", "CKM_IBM_EC_X25519" }, { "CKM_IBM_EC_C448", "CKM_IBM_EC_X448" }, { "CKM_IBM_EDDSA_SHA512", "CKM_IBM_ED25519_SHA512" }, { "CKM_SHA3_224_KEY_DERIVE", "CKM_SHA3_224_KEY_DERIVATION" }, { "CKM_SHA3_256_KEY_DERIVE", "CKM_SHA3_256_KEY_DERIVATION" }, { "CKM_SHA3_384_KEY_DERIVE", "CKM_SHA3_384_KEY_DERIVATION" }, { "CKM_SHA3_512_KEY_DERIVE", "CKM_SHA3_512_KEY_DERIVATION" }, }; /* Get the table */ #include "mechtable.inc" struct node; struct node { short table[256]; unsigned short num; unsigned int offset; unsigned int used; struct node *nextnum; }; static unsigned char idxtable[256]; static unsigned char usagetable[256]; static unsigned int usagecount; static unsigned short nextnum; static struct node *root, **last; static char *commonprefix; static size_t commonprefixlength; /* Utilities */ static struct node *getnodeforidx(short idx) { short i; struct node *res = root; for (i = 0; i < idx; ++i) res = res->nextnum; return res; } static struct node *allocatenode(void) { struct node *res = malloc(sizeof(struct node)); if (!res) errx(1, "Failed to allocate node"); res->num = nextnum++; res->nextnum = NULL; res->used = 0; res->offset = 0; *last = res; memset(res->table, 0, 256 * sizeof(short)); last = &(res->nextnum); return res; } static void freenodes(void) { struct node *i, *n; for (i = root; i; i = n) { n = i->nextnum; free(i); } } static void reinitializenodes(void) { freenodes(); root = NULL; last = &root; nextnum = 0; allocatenode(); } /* Additions */ static void addnumeric(const struct mechrow *m, short position) { short idx; struct node *n = root, *a; idx = (m->numeric & 0xff000000u) >> 24u; if (n->table[idx] == 0) { a = allocatenode(); n->table[idx] = a->num; n->used += 1; n = a; } else { n = getnodeforidx(n->table[idx]); } idx = (m->numeric & 0x00ff0000u) >> 16u; if (n->table[idx] == 0) { a = allocatenode(); n->table[idx] = a->num; n->used += 1; n = a; } else { n = getnodeforidx(n->table[idx]); } idx = (m->numeric & 0x0000ff00u) >> 8u; if (n->table[idx] == 0) { a = allocatenode(); n->table[idx] = a->num; n->used += 1; n = a; } else { n = getnodeforidx(n->table[idx]); } idx = m->numeric & 0x000000ffu; if (n->table[idx]) { errx(1, "Duplicated key 0x%lx. Please use aliaslist in tableidxgen.c for duplicates\n", m->numeric); return; } /* Make sure we do not insert zero. Zero marks an empty cell. */ n->table[idx] = -position - 1; n->used += 1; } static short recursiveaddstring(const char *str, short position) { size_t len = strlen(str); size_t i; struct node *n = root, *a; short val, readd = 0, idx; for (i = commonprefixlength; i <= len; ++i) { idx = str[i]; val = n->table[idx]; if (val > 0) { /* A link */ n = getnodeforidx(val); } else if (val == 0) { /* An empty slot */ n->table[idx] = -position - 1; n->used += 1; return readd; } else { /* A value */ readd = val; /* Duplication check */ if (strcmp(str, mechtable_rows[-val - 1].string) == 0) errx(1, "Dublicated string keys (%s) not supported!", str); a = allocatenode(); n->table[idx] = a->num; n->used += 1; n = a; } } /* I don't see how this can happen, but the compiler disagrees. */ errx(1, "Cannot add key %s!", str); } static void addstring(const struct mechrow *m, short position) { short res = position; const struct mechrow *toadd = m; while ((res = recursiveaddstring(toadd->string, res)) < 0) { res = -res - 1; toadd = &mechtable_rows[res]; } } /* Compressors */ static void compressnumericalphabet(void) { size_t i; unsigned int idx; memset(usagetable, 0, 256); memset(idxtable, 0, 256); usagecount = 0; for (i = 0; i < ARRAY_SIZE(mechtable_rows); ++i) { idx = (mechtable_rows[i].numeric & 0xff000000u) >> 24u; if (usagetable[idx] == 0) ++usagecount; usagetable[idx] = 1; idx = (mechtable_rows[i].numeric & 0x00ff0000u) >> 16u; if (usagetable[idx] == 0) ++usagecount; usagetable[idx] = 1; idx = (mechtable_rows[i].numeric & 0x0000ff00u) >> 8u; if (usagetable[idx] == 0) ++usagecount; usagetable[idx] = 1; idx = (mechtable_rows[i].numeric & 0x000000ffu); if (usagetable[idx] == 0) ++usagecount; usagetable[idx] = 1; } idx = 0; for (i = 0; i < 256; ++i) { if (usagetable[i]) idxtable[i] = (unsigned char)idx++; } } static void compressstringalphabet(void) { size_t i, j; unsigned int idx; memset(usagetable, 0, 256); memset(idxtable, 0, 256); usagecount = 0; for (i = 0; i < ARRAY_SIZE(mechtable_rows); ++i) { for (j = 0; j <= strlen(mechtable_rows[i].string); ++j) { idx = mechtable_rows[i].string[j]; if (usagetable[idx] == 0) ++usagecount; usagetable[idx] = 1; } } idx = 0; for (i = 0; i < 256; ++i) { if (usagetable[i]) idxtable[i] = (unsigned char)idx++; } } static unsigned int compresstable(void) { int pos, i, k, l; struct node *n; unsigned int maxoffset = 0; unsigned int offset; /* allocate properly too much */ unsigned char *t = calloc(nextnum, usagecount); struct node **sorttable = calloc(nextnum, sizeof(struct node *)); if (!t) errx(1, "Could not allocate compression table"); if (!sorttable) errx(1, "Could not allocate sort table"); pos = 0; /* sort nodes by used count (descending) */ for (n = root; n; n = n->nextnum) { for (i = 0; i < pos; ++i) { if (n->used > sorttable[i]->used) { memmove(sorttable + i + 1, sorttable + i, (pos - i) * sizeof(struct node *)); break; } } sorttable[i] = n; ++pos; } assert(pos == nextnum); /* now insert and compress */ /* for all nodes */ for (i = 0; i < nextnum; ++i) { /* for all possible offsets */ for (offset = 0; offset < (nextnum - 1) * usagecount; ++offset) { /* try to put table i at offset */ for (k = 0; k < 256; ++k) { if (usagetable[k] && sorttable[i]->table[k]) { if (t[idxtable[k] + offset]) break; t[idxtable[k] + offset] = 1; } } if (k == 256) { /* success for node i */ sorttable[i]->offset = offset; if (offset > maxoffset) maxoffset = offset; break; } else { /* failure => undo t updates */ for (l = 0; l < k; ++l) { if (usagetable[l] && sorttable[i]->table[l]) t[idxtable[l] + offset] = 0; } } } } free(sorttable); free(t); return maxoffset; } /* Common prefix elimination */ static void eliminatecommonprefixes(void) { size_t i, j, minlength, l; commonprefix = strdup(mechtable_rows[0].string); if (!commonprefix) errx(1, "Out of memory"); commonprefixlength = strlen(commonprefix); for (i = 1; i < ARRAY_SIZE(mechtable_rows); ++i) { l = strlen(mechtable_rows[i].string); minlength = commonprefixlength < l ? commonprefixlength : l; for (j = 0; j < minlength && commonprefix[j] == mechtable_rows[i].string[j]; ++j) { /* Advance */ } commonprefix[j] = 0; commonprefixlength = j; } } /* Builders */ static void buildnumeric(void) { unsigned int i; for (i = 0; i < ARRAY_SIZE(mechtable_rows); ++i) addnumeric(&mechtable_rows[i], i); } static void buildstring(void) { unsigned int i; for (i = 0; i < ARRAY_SIZE(mechtable_rows); ++i) addstring(&mechtable_rows[i], i); } static short *buildcompressedtable(unsigned int maxoffset) { struct node *n; unsigned int i, idx; short *res = calloc(maxoffset + usagecount, sizeof(short)); if (!res) errx(1, "Could not allocate compressed table"); for (n = root; n; n = n->nextnum) { for (i = 0; i < 256; ++i) { if (usagetable[i] && n->table[i]) { idx = idxtable[i] + n->offset; assert(res[idx] == 0); if (n->table[i] < 0) /* a value */ res[idx] = n->table[i]; else /* a link */ res[idx] = getnodeforidx(n->table[i])->offset; } } } return res; } static void freecompressedtable(short *table) { free(table); } /* Logging */ static void lognodes(FILE *fp) { struct node *n; int i; fputs("Jump table:\n", fp); for (n = root; n; n = n->nextnum) { fprintf(fp, "node %hu: (offset %u)\n", n->num, n->offset); for (i = 0; i < 256; ++i) { if (n->table[i] > 0) fprintf(fp, " %d (%d) => node %hd\n", i, (int)idxtable[i], n->table[i]); else if (n->table[i] < 0) fprintf(fp, " %d (%d) => mapping %d\n", i, (int)idxtable[i], -(n->table[i]+1)); } } } static FILE *openfile(char *name) { FILE *res = fopen(name, "w"); if (!res) err(1, "Failed to open %s", name); return res; } static void closefile(FILE *fp) { fclose(fp); } static void logalphabet(FILE *fp) { int i; fputs("Alphabet mapping:\n", fp); for (i = 0; i < 256; ++i) { if (usagetable[i]) fprintf(fp, "%c (%d) => %hhu\n", (char)i, i, idxtable[i]); } } /* dumpers */ static void dumptable(unsigned int maxoffset, short *table, char *name, FILE *fp) { unsigned int i, j; fprintf(fp, "static const short %stable[] = {\n", name); for (i = 0; i < (maxoffset + usagecount) / 8; ++i) { fprintf(fp, " %hd, %hd, %hd, %hd, %hd, %hd, %hd, %hd,\n", table[8 * i], table[8 * i + 1], table[8 * i + 2], table[8 * i + 3], table[8 * i + 4], table[8 * i + 5], table[8 * i + 6], table[8 * i + 7]); } if ((maxoffset + usagecount) % 8 != 0) { fputc(' ', fp); for (j = 0; j < (maxoffset + usagecount) % 8; ++j) { fprintf(fp, " %hd,", table[8 * i + j]); } fputc('\n', fp); } fputs("};\n", fp); } static void dumpalphabet(char *name, FILE *fp) { int i; fprintf(fp, "static const unsigned char %salphabet[] = {\n", name); for (i = 0; i < 256 / 8; ++i) { fprintf(fp, " %hhu, %hhu, %hhu, %hhu, %hhu, %hhu, %hhu, %hhu,\n", idxtable[8 * i], idxtable[8 * i + 1], idxtable[8 * i + 2], idxtable[8 * i + 3], idxtable[8 * i + 4], idxtable[8 * i + 5], idxtable[8 * i + 6], idxtable[8 * i + 7]); } fputs("};\n", fp); } static void dumpnumericfun(FILE *fp) { fputs("int mechtable_idx_from_numeric(CK_ULONG mech)\n", fp); fputs("{\n", fp); fputs(" unsigned int idx1, idx2, idx3, idx4;\n", fp); fputs(" int o1, o2, o3;\n", fp); fputs(" int midx;\n\n", fp); fputs(" idx1 = numericalphabet[(mech & 0xff000000u) >> 24u];\n", fp); fputs(" idx2 = numericalphabet[(mech & 0x00ff0000u) >> 16u];\n", fp); fputs(" idx3 = numericalphabet[(mech & 0x0000ff00u) >> 8u];\n", fp); fputs(" idx4 = numericalphabet[mech & 0x000000ffu];\n", fp); /* No need to check idx vars since they are 0 if unsigned char is not mapped and nothing problematic happens. The search will just be unsuccessful. */ fprintf(fp, " o1 = numerictable[%u + idx1];\n", root->offset); fputs(" if (o1 < 0) return -1;\n", fp); fputs(" o2 = numerictable[o1 + idx2];\n", fp); fputs(" if (o2 < 0) return -1;\n", fp); fputs(" o3 = numerictable[o2 + idx3];\n", fp); fputs(" if (o3 < 0) return -1;\n", fp); fputs(" midx = numerictable[o3 + idx4];\n", fp); fputs(" midx = -(midx + 1);\n", fp); fprintf(fp, " if (0 <= midx && midx < %zu && mechtable_rows[midx].numeric == mech)\n", ARRAY_SIZE(mechtable_rows)); fputs(" return midx;\n", fp); fputs(" return -1;\n", fp); fputs("}\n\n", fp); fputs("const struct mechrow *mechrow_from_numeric(CK_ULONG mech)\n", fp); fputs("{\n", fp); fputs(" int idx = mechtable_idx_from_numeric(mech);\n", fp); fputs("\n", fp); fputs(" if (idx < 0)\n", fp); fputs(" return NULL;\n", fp); fputs(" return &mechtable_rows[idx];\n", fp); fputs("}\n\n", fp); } static void dumpstringfun(FILE *fp) { size_t i; fprintf(fp, "static const size_t commonprefixlength = %zu;\n\n", commonprefixlength); fputs("int mechtable_idx_from_string(const char *mech)\n", fp); fputs("{\n", fp); fputs(" static const struct {\n", fp); fputs(" const char *string;\n", fp); fputs(" const char *alias;\n", fp); fputs(" } aliaslist[] = {\n", fp); for (i = 0; i < ARRAY_SIZE(aliases); ++i) { fprintf(fp, " { \"%s\", \"%s\" },\n", aliases[i].string, aliases[i].alias); } fputs(" };\n", fp); fputs(" size_t len = strlen(mech), i;\n", fp); fprintf(fp, " short idx = %u;\n", root->offset); fputs(" unsigned char h;\n\n", fp); fputs(" for (i = commonprefixlength; i <= len; ++i) {\n", fp); fputs(" h = stringalphabet[(int)mech[i]];\n", fp); /* No need to check the h since they are 0 if unsigned char is not mapped and nothing problematic happens. The search will just be unsuccessful. */ fputs(" idx = stringtable[idx + h];\n", fp); fputs(" if (idx < 0) {\n", fp); fputs(" idx = -(idx + 1);\n", fp); fputs(" if (strcmp(mech, mechtable_rows[idx].string) == 0)\n", fp); fputs(" return idx;\n", fp); fputs(" goto outcheckaliases;\n", fp); fputs(" }\n", fp); fputs(" }\n", fp); fputs(" outcheckaliases:\n", fp); fputs(" for (i = 0; i < sizeof(aliaslist) / sizeof(aliaslist[0]); ++i) {\n", fp); fputs(" if (strcmp(aliaslist[i].string, mech) == 0)\n", fp); fputs(" return mechtable_idx_from_string(aliaslist[i].alias);\n", fp); fputs(" }\n", fp); fputs(" return -1;\n", fp); fputs("}\n\n", fp); fputs("const struct mechrow *mechrow_from_string(const char *mech)\n", fp); fputs("{\n", fp); fputs(" int idx = mechtable_idx_from_string(mech);\n\n", fp); fputs(" if (idx < 0)\n", fp); fputs(" return NULL;\n", fp); fputs(" return &mechtable_rows[idx];\n", fp); fputs("}\n\n", fp); } static void generatelicense(FILE *fp) { fputs("/*\n", fp); fprintf(fp, " * COPYRIGHT (c) International Business Machines Corp. 2024\n"); fputs(" *\n", fp); fputs(" * This program is provided under the terms of the Common Public License,\n", fp); fputs(" * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this\n", fp); fputs(" * software constitutes recipient's acceptance of CPL-1.0 terms which can be\n", fp); fputs(" * found in the file LICENSE file or at\n", fp); fputs(" * https://opensource.org/licenses/cpl1.0.php\n", fp); fputs(" */\n", fp); fprintf(fp, "/* AUTO-GENERATED. DO NOT EDIT! */\n\n"); } static void generateheader(char *hname) { FILE *fp = openfile(hname); generatelicense(fp); fputs("#ifndef OCK_MECHTABLE_GEN_H\n", fp); fputs("#define OCK_MECHTABLE_GEN_H\n\n", fp); fprintf(fp, "#define MECHTABLE_NUM_ELEMS %zu\n\n", ARRAY_SIZE(mechtable_rows)); fputs("#endif\n\n", fp); closefile(fp); } static void dumpmechtableaccessors(FILE *fp) { fputs("const struct mechtable_funcs mechtable_funcs = {\n", fp); fputs(" .p_idx_from_num = &mechtable_idx_from_numeric,\n", fp); fputs(" .p_idx_from_str = &mechtable_idx_from_string,\n", fp); fputs(" .p_row_from_num = &mechrow_from_numeric,\n", fp); fputs(" .p_row_from_str = &mechrow_from_string\n", fp); fputs("};\n\n", fp); } static void usage(char *name, int exitcode) { printf("USAGE: %s [-l|--log ] [-c|--cfile ] [-d|-dname ]\n", name); puts("where:"); puts("\t-l|--log specifies the destination of the log file"); puts("\t-c|--cname specifies the destination of the generated c file"); puts("\t-d|--dname specifies the destination of the generated header file"); puts("\t-h|--help prints this help and exits"); puts("All arguments are mandatory!"); exit(exitcode); } static void parseargs(int argc, char **argv, char **lname, char **cname, char **hname) { char *progname = argv[0]; int c; static struct option long_options[] = { { "log", required_argument, 0, 'l' }, { "cname", required_argument, 0, 'c' }, { "dname", required_argument, 0, 'd' }, { "help", no_argument, 0, 'h' }, { 0, 0, 0, 0 } }; while (1) { c = getopt_long(argc, argv, "l:c:d:h", long_options, NULL); if (c == -1) break; switch(c) { case 'l': *lname = optarg; break; case 'c': *cname = optarg; break; case 'd': *hname = optarg; break; case 'h': usage(progname, 0); break; default: usage(progname, 1); break; } } if (optind < argc) /* Superfluous arguments */ usage(progname, 1); } int main(int argc, char **argv) { short *table; unsigned int maxoffset; FILE *logfp, *cfp; char *logname = 0, *cname = 0, *hname = 0; parseargs(argc, argv, &logname, &cname, &hname); if (!logname || !cname || !hname) usage(argv[0], 1); logfp = openfile(logname); cfp = openfile(cname); generateheader(hname); generatelicense(cfp); fputs("#include \n", cfp); fputs("#include \n", cfp); fputs("#include \"mechtable.h\"\n", cfp); fputs("#include \"mechtable.inc\"\n\n", cfp); eliminatecommonprefixes(); reinitializenodes(); buildnumeric(); compressnumericalphabet(); maxoffset = compresstable(); table = buildcompressedtable(maxoffset); dumpalphabet("numeric", cfp); dumptable(maxoffset, table, "numeric", cfp); dumpnumericfun(cfp); freecompressedtable(table); fputs("Numeric table:\n", logfp); logalphabet(logfp); lognodes(logfp); reinitializenodes(); buildstring(); compressstringalphabet(); maxoffset = compresstable(); table = buildcompressedtable(maxoffset); dumpalphabet("string", cfp); dumptable(maxoffset, table, "string", cfp); dumpstringfun(cfp); freecompressedtable(table); fputs("\nString table:\n", logfp); logalphabet(logfp); lognodes(logfp); dumpmechtableaccessors(cfp); closefile(logfp); closefile(cfp); free(commonprefix); freenodes(); return 0; } opencryptoki-opencryptoki-451d99c/tools/tools.mk000066400000000000000000000022501520105705100221540ustar00rootroot00000000000000noinst_PROGRAMS += tools/tableidxgen tools/policyexamplegen TOOLS_CFLAGS = -I${srcdir}/usr/include -I${srcdir}/usr/lib/api \ -I${top_builddir}/usr/lib/api -I${srcdir}/usr/lib/common tools_tableidxgen_SOURCES = tools/tableidxgen.c usr/lib/api/mechtable.inc if AIX tools_tableidxgen_SOURCES += usr/lib/common/aix/err.c \ usr/lib/common/aix/getopt_long.c endif tools_policyexamplegen_SOURCES = tools/policyexamplegen.c usr/lib/api/mechtable.c if CROSS tools_tableidxgen_LINK = $(CC_FOR_BUILD) $(CFLAGS_FOR_BUILD) $(LDFLAGS_FOR_BUILD) -o $@ $(tools_tableidxgen_OBJECTS): CC=$(CC_FOR_BUILD) $(tools_tableidxgen_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(TOOLS_CFLAGS) $(tools_tableidxgen_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) tools_policyexamplegen_LINK = $(CC_FOR_BUILD) $(CFLAGS_FOR_BUILD) $(LDFLAGS_FOR_BUILD) -o $@ $(tools_policyexamplegen_OBJECTS): CC=$(CC_FOR_BUILD) $(tools_policyexamplegen_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(TOOLS_CFLAGS) $(tools_policyexamplegen_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) else tools_tableidxgen_LINK = $(LINK) tools_tableidxgen_CFLAGS = $(TOOLS_CFLAGS) tools_policyexamplegen_LINK = $(LINK) tools_policyexamplegen_CFLAGS = $(TOOLS_CFLAGS) endif opencryptoki-opencryptoki-451d99c/usr/000077500000000000000000000000001520105705100201355ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/usr/include/000077500000000000000000000000001520105705100215605ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/usr/include/apiclient.h000066400000000000000000000307221520105705100237050ustar00rootroot00000000000000/* * 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" #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); CK_RV C_GetInterfaceList(CK_INTERFACE_PTR, CK_ULONG_PTR); CK_RV C_GetInterface(CK_UTF8CHAR_PTR, CK_VERSION_PTR, CK_INTERFACE_PTR_PTR, CK_FLAGS); CK_RV C_LoginUser(CK_SESSION_HANDLE, CK_USER_TYPE, CK_UTF8CHAR *, CK_ULONG, CK_UTF8CHAR *, CK_ULONG); CK_RV C_SessionCancel(CK_SESSION_HANDLE, CK_FLAGS); CK_RV C_MessageEncryptInit(CK_SESSION_HANDLE, CK_MECHANISM *, CK_OBJECT_HANDLE); CK_RV C_EncryptMessage(CK_SESSION_HANDLE , void *, CK_ULONG, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *); CK_RV C_EncryptMessageBegin(CK_SESSION_HANDLE, void *, CK_ULONG, CK_BYTE *, CK_ULONG); CK_RV C_EncryptMessageNext(CK_SESSION_HANDLE, void *, CK_ULONG, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *, CK_ULONG); CK_RV C_MessageEncryptFinal(CK_SESSION_HANDLE); CK_RV C_MessageDecryptInit(CK_SESSION_HANDLE, CK_MECHANISM *, CK_OBJECT_HANDLE); CK_RV C_DecryptMessage(CK_SESSION_HANDLE, void *, CK_ULONG, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *); CK_RV C_DecryptMessageBegin(CK_SESSION_HANDLE, void *, CK_ULONG, CK_BYTE *, CK_ULONG); CK_RV C_DecryptMessageNext(CK_SESSION_HANDLE, void *, CK_ULONG, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *, CK_FLAGS); CK_RV C_MessageDecryptFinal(CK_SESSION_HANDLE); CK_RV C_MessageSignInit(CK_SESSION_HANDLE, CK_MECHANISM *, CK_OBJECT_HANDLE); CK_RV C_SignMessage(CK_SESSION_HANDLE, void *, CK_ULONG, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *); CK_RV C_SignMessageBegin(CK_SESSION_HANDLE, void *, CK_ULONG); CK_RV C_SignMessageNext(CK_SESSION_HANDLE, void *, CK_ULONG, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *); CK_RV C_MessageSignFinal(CK_SESSION_HANDLE); CK_RV C_MessageVerifyInit(CK_SESSION_HANDLE, CK_MECHANISM *, CK_OBJECT_HANDLE); CK_RV C_VerifyMessage(CK_SESSION_HANDLE, void *, CK_ULONG, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG); CK_RV C_VerifyMessageBegin(CK_SESSION_HANDLE, void *, CK_ULONG); CK_RV C_VerifyMessageNext(CK_SESSION_HANDLE, void *, CK_ULONG, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG); CK_RV C_MessageVerifyFinal(CK_SESSION_HANDLE); CK_RV C_EncapsulateKey(CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_OBJECT_HANDLE, CK_ATTRIBUTE_PTR, CK_ULONG, CK_BYTE_PTR, CK_ULONG_PTR, CK_OBJECT_HANDLE_PTR); CK_RV C_DecapsulateKey(CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_OBJECT_HANDLE, CK_ATTRIBUTE_PTR, CK_ULONG, CK_BYTE_PTR, CK_ULONG, CK_OBJECT_HANDLE_PTR); CK_RV C_VerifySignatureInit(CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_OBJECT_HANDLE, CK_BYTE_PTR, CK_ULONG); CK_RV C_VerifySignature(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG); CK_RV C_VerifySignatureUpdate(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG); CK_RV C_VerifySignatureFinal(CK_SESSION_HANDLE); CK_RV C_GetSessionValidationFlags(CK_SESSION_HANDLE, CK_SESSION_VALIDATION_FLAGS_TYPE, CK_FLAGS_PTR); CK_RV C_AsyncComplete(CK_SESSION_HANDLE, CK_UTF8CHAR_PTR, CK_ASYNC_DATA_PTR); CK_RV C_AsyncGetID(CK_SESSION_HANDLE, CK_UTF8CHAR_PTR, CK_ULONG_PTR); CK_RV C_AsyncJoin(CK_SESSION_HANDLE, CK_UTF8CHAR_PTR, CK_ULONG, CK_BYTE_PTR, CK_ULONG); CK_RV C_WrapKeyAuthenticated(CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_OBJECT_HANDLE, CK_OBJECT_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR, CK_ULONG_PTR); CK_RV C_UnwrapKeyAuthenticated(CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_OBJECT_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_ATTRIBUTE_PTR, CK_ULONG, CK_BYTE_PTR, CK_ULONG, CK_OBJECT_HANDLE_PTR); CK_RV C_IBM_ReencryptSingle(CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_OBJECT_HANDLE, CK_MECHANISM_PTR, CK_OBJECT_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR, CK_ULONG_PTR); #ifdef __cplusplus } #endif #endif // _APICLIENT_H opencryptoki-opencryptoki-451d99c/usr/include/apictl.h000066400000000000000000000075431520105705100232160ustar00rootroot00000000000000/* * 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 #ifndef _APILOCAL_H #define _APILOCAL_H #if OPENSSL_VERSION_PREREQ(3, 0) #include #include #endif #define BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) \ do { \ if ((sltp)->TokData->hsm_mk_change_supported) { \ if (pthread_rwlock_rdlock( \ &(sltp)->TokData->hsm_mk_change_rwlock) != 0) { \ TRACE_DEVEL("HSM-MK-change Read-Lock failed.\n"); \ (rv) = CKR_CANT_LOCK; \ break; \ } \ } #define END_HSM_MK_CHANGE_LOCK(sltp, rv) \ if ((sltp)->TokData->hsm_mk_change_supported) { \ if (pthread_rwlock_unlock( \ &(sltp)->TokData->hsm_mk_change_rwlock) != 0) { \ TRACE_DEVEL("HSM-MK-change Unlock failed.\n"); \ if ((rv) == CKR_OK) \ (rv) = CKR_CANT_LOCK; \ break; \ } \ } \ } while (0); // SAB Add a linked list of STDLL's loaded to // only load and get list once, but let multiple slots us it. 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 { key_t shm_tok; struct btree sess_btree; void *SharedMemP; Slot_Mgr_Socket_t SocketDataP; Slot_Mgr_Client_Cred_t ClientCred; 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 int socketfd; pthread_t event_thread; #if OPENSSL_VERSION_PREREQ(3, 0) OSSL_LIB_CTX *openssl_libctx; OSSL_PROVIDER *openssl_default_provider; OSSL_PROVIDER *openssl_legacy_provider; #endif } API_Proc_Struct_t; #endif opencryptoki-opencryptoki-451d99c/usr/include/ec_curves.h000066400000000000000000000106161520105705100237130ustar00rootroot00000000000000/* * 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 } /* bls12_381_et: 1.3.6.1.4.1.2.267.999.3.2 */ #define OCK_BLS12_381 { 0x06, 0x0C, 0x2B, 0x06, 0x01, 0x04, 0x01, \ 0x02, 0x82, 0x0B, 0x87, 0x67, 0x03, 0x02 } #endif // _EC_CURVES_H_ opencryptoki-opencryptoki-451d99c/usr/include/events.h000066400000000000000000000076251520105705100232470ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021 * * 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 "local_types.h" #include "pkcs32.h" #ifndef _EVENTS_H #define _EVENTS_H typedef struct { unsigned int version; /* EVENT_VERSION_xxx */ unsigned int type; /* EVENT_TYPE_xxx */ unsigned int flags; /* EVENT_FLAGS_xxx */ unsigned int token_type; /* Destination token type: EVENT_TOK_TYPE_xxx */ char token_label[member_size(CK_TOKEN_INFO_32, label)]; /* Label of destination token (or blanks) */ pid_t process_id; /* Process ID of destination process (or 0) */ unsigned int payload_len; /* Length of payload in bytes */ /* Followed by payload_len bytes of payload (event specific) */ } __attribute__ ((__packed__)) event_msg_t; typedef struct { unsigned int version; /* EVENT_VERSION_xxx */ unsigned int positive_replies; /* Number of tokens that replied a */ unsigned int negative_replies; /* positive, or negative feedback, */ unsigned int nothandled_replies; /* or that did not handle the event. */ /* Note: Only tokens matching the event * destination fields (pid, label, * token-type) are counted. */ } __attribute__ ((__packed__)) event_reply_t; /* Event and reply versions */ #define EVENT_VERSION_1 1 /* Event classes (encoded into event type) */ #define EVENT_CLASS_MASK 0xffff0000 #define EVENT_CLASS_UDEV 0x00010000 #define EVENT_CLASS_ADMIN 0x00020000 #define EVENT_CLASS_MK_CHANGE 0x00040000 /* Event types */ #define EVENT_TYPE_APQN_ADD EVENT_CLASS_UDEV + 0x00000001 #define EVENT_TYPE_APQN_REMOVE EVENT_CLASS_UDEV + 0x00000002 #define EVENT_TYPE_MK_CHANGE_INITIATE_QUERY EVENT_CLASS_MK_CHANGE + 0x00000001 #define EVENT_TYPE_MK_CHANGE_REENCIPHER EVENT_CLASS_MK_CHANGE + 0x00000002 #define EVENT_TYPE_MK_CHANGE_FINALIZE_QUERY EVENT_CLASS_MK_CHANGE + 0x00000003 #define EVENT_TYPE_MK_CHANGE_FINALIZE EVENT_CLASS_MK_CHANGE + 0x00000004 #define EVENT_TYPE_MK_CHANGE_CANCEL_QUERY EVENT_CLASS_MK_CHANGE + 0x00000005 #define EVENT_TYPE_MK_CHANGE_CANCEL EVENT_CLASS_MK_CHANGE + 0x00000006 /* Event flags */ #define EVENT_FLAGS_NONE 0x00000000 #define EVENT_FLAGS_REPLY_REQ 0x00000001 /* Event token destination types */ #define EVENT_TOK_TYPE_ALL 0x00000000 #define EVENT_TOK_TYPE_CCA 0x00000001 #define EVENT_TOK_TYPE_EP11 0x00000002 /* Maximum event payload length 128k */ #define EVENT_MAX_PAYLOAD_LENGTH (128 * 1024) /* Event payload for EVENT_TYPE_APQN_ADD and EVENT_TYPE_APQN_REMOVE */ typedef struct { unsigned short card; unsigned short domain; unsigned int device_type; /* from uevent DEV_TYPE property */ } __attribute__ ((__packed__)) event_udev_apqn_data_t; /* AP device types */ #define AP_DEVICE_TYPE_CEX3A 8 #define AP_DEVICE_TYPE_CEX3C 9 #define AP_DEVICE_TYPE_CEX4 10 #define AP_DEVICE_TYPE_CEX5 11 #define AP_DEVICE_TYPE_CEX6 12 #define AP_DEVICE_TYPE_CEX7 13 /* Event payload for EVENT_TYPE_MK_CHANGE_xxx events */ typedef struct { char id[8]; pid_t tool_pid; unsigned int flags; /* Followed by flattened struct hsm_mk_change_info */ } event_mk_change_data_t; #define EVENT_MK_CHANGE_FLAGS_NONE 0x00000000 #define EVENT_MK_CHANGE_FLAGS_TOK_OBJS 0x00000001 #define EVENT_MK_CHANGE_FLAGS_TOK_OBJS_FINAL 0x00000002 #endif opencryptoki-opencryptoki-451d99c/usr/include/include.mk000066400000000000000000000006041520105705100235340ustar00rootroot00000000000000opencryptokiincludedir = ${includedir}/opencryptoki opencryptokiinclude_HEADERS = \ usr/include/apiclient.h usr/include/pkcs11types.h \ usr/include/pkcs11.h \ usr/include/ec_curves.h usr/include/pqc_oids.h noinst_HEADERS += \ usr/include/apictl.h usr/include/local_types.h \ usr/include/pkcs32.h usr/include/slotmgr.h usr/include/stdll.h \ usr/include/events.h opencryptoki-opencryptoki-451d99c/usr/include/local_types.h000066400000000000000000000040221520105705100242450ustar00rootroot00000000000000/* * 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 #define member_size(type, member) sizeof(((type *)0)->member) 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 { volatile unsigned long ref; }; #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; pthread_mutex_t mutex; 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); CK_RV bt_init(struct btree *t, void (*delete_func)(void *)); #endif opencryptoki-opencryptoki-451d99c/usr/include/pkcs11.h000066400000000000000000000010211520105705100230250ustar00rootroot00000000000000/* * 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 opencryptoki-opencryptoki-451d99c/usr/include/pkcs11types.h000066400000000000000000003443721520105705100241350ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2001-2021 * * 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 XCP_H__ #define OCK_NO_EP11_DEFINES #endif #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; typedef CK_ULONG CK_PTR CK_FLAGS_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 /* CKF_ERROR_STATE. If it is true, the token failed a FIPS 140 * self-test and entered an error state. */ #define CKF_ERROR_STATE 0x01000000 /* * CKF_SEED_RANDOM_REQUIRED. If this is true the token’s * random number generator must be seeded or re-seeded using * C_SeedRandom. */ #define CKF_SEED_RANDOM_REQUIRED 0x02000000 /* CKF_ASYNC_SESSION_SUPPORTED. If this is true the token * supports asynchronous sessions. */ #define CKF_ASYNC_SESSION_SUPPORTED 0x04000000 #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 /* Context specific */ #define CKU_CONTEXT_SPECIFIC 2 /* 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 */ #define CKF_ASYNC_SESSION 0x00000008 /* session is async */ 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_PROFILE 0x00000009 /* CKO_VALIDATION and CKO_TRUST are new for v3.2 */ #define CKO_VALIDATION 0x0000000A #define CKO_TRUST 0x0000000B #define CKO_VENDOR_DEFINED 0x80000000 typedef CK_OBJECT_CLASS CK_PTR CK_OBJECT_CLASS_PTR; /* Profile ID's */ #define CKP_INVALID_ID 0x00000000UL #define CKP_BASELINE_PROVIDER 0x00000001UL #define CKP_EXTENDED_PROVIDER 0x00000002UL #define CKP_AUTHENTICATION_TOKEN 0x00000003UL #define CKP_PUBLIC_CERTIFICATES_TOKEN 0x00000004UL #define CKP_VENDOR_DEFINED 0x80000000UL /* 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 /* CKK_AES_XTS is new for v3.0 */ #define CKK_AES_XTS 0x00000035 #define CKK_SHA_1_HMAC 0x00000028 #define CKK_SHA256_HMAC 0x0000002B #define CKK_SHA384_HMAC 0x0000002C #define CKK_SHA512_HMAC 0x0000002D #define CKK_SHA224_HMAC 0x0000002E #define CKK_SHA3_224_HMAC 0x00000036 #define CKK_SHA3_256_HMAC 0x00000037 #define CKK_SHA3_384_HMAC 0x00000038 #define CKK_SHA3_512_HMAC 0x00000039 #define CKK_SHA512_224_HMAC 0x00000043 #define CKK_SHA512_256_HMAC 0x00000044 /* new for v3.0 */ #define CKK_EC_EDWARDS 0x00000040 #define CKK_EC_MONTGOMERY 0x00000041 /* new for v3.2 */ #define CKK_ML_KEM 0x00000049 #define CKK_ML_DSA 0x0000004A #define CKK_VENDOR_DEFINED 0x80000000 #ifndef OCK_NO_EP11_DEFINES #define CKK_IBM_PQC_DILITHIUM CKK_VENDOR_DEFINED + 0x10023 #endif #define CKK_IBM_DILITHIUM CKK_IBM_PQC_DILITHIUM #ifndef OCK_NO_EP11_DEFINES #define CKK_IBM_PQC_KYBER CKK_VENDOR_DEFINED + 0x10024 #endif #define CKK_IBM_KYBER CKK_IBM_PQC_KYBER #ifndef OCK_NO_EP11_DEFINES #define CKK_IBM_ML_DSA CKK_VENDOR_DEFINED + 0x10025 #define CKK_IBM_ML_KEM CKK_VENDOR_DEFINED + 0x10026 #endif /* 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 typedef CK_ULONG CK_CERTIFICATE_CATEGORY; #define CK_CERTIFICATE_CATEGORY_UNSPECIFIED 0UL #define CK_CERTIFICATE_CATEGORY_TOKEN_USER 1UL #define CK_CERTIFICATE_CATEGORY_AUTHORITY 2UL #define CK_CERTIFICATE_CATEGORY_OTHER_ENTITY 3UL typedef CK_ULONG CK_JAVA_MIDP_SECURITY_DOMAIN; #define CK_SECURITY_DOMAIN_UNSPECIFIED 0UL #define CK_SECURITY_DOMAIN_MANUFACTURER 1UL #define CK_SECURITY_DOMAIN_OPERATOR 2UL #define CK_SECURITY_DOMAIN_THIRD_PARTY 3UL /* 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_UNIQUE_ID 0x00000004UL #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_CERTIFICATE_CATEGORY 0x00000087 #define CKA_JAVA_MIDP_SECURITY_DOMAIN 0x00000088 #define CKA_URL 0x00000089 #define CKA_HASH_OF_SUBJECT_PUBLIC_KEY 0x0000008A #define CKA_HASH_OF_ISSUER_PUBLIC_KEY 0x0000008B #define CKA_NAME_HASH_ALGORITHM 0x0000008C #define CKA_CHECK_VALUE 0x00000090 #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_PUBLIC_KEY_INFO 0x00000129 #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_SUB_PRIME_BITS CKA_SUBPRIME_BITS #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 #define CKA_COPYABLE 0x00000171 #define CKA_DESTROYABLE 0x00000172 /* 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 /* Deprecated since 2.11 */ #define CKA_AUTH_PIN_FLAGS 0x00000201 /* Deprecated since 2.11 */ #define CKA_ALWAYS_AUTHENTICATE 0x00000202 #define CKA_WRAP_WITH_TRUSTED 0x00000210 #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_DERIVE_TEMPLATE (CKF_ARRAY_ATTRIBUTE|0x00000213UL) #define CKA_ALLOWED_MECHANISMS (CKF_ARRAY_ATTRIBUTE|0x00000600UL) #define CKA_PROFILE_ID 0x00000601UL /* new for v3.2 */ #define CKA_PARAMETER_SET 0x0000061D #define CKA_ENCAPSULATE_TEMPLATE (CKF_ARRAY_ATTRIBUTE|0x0000062A) #define CKA_DECAPSULATE_TEMPLATE (CKF_ARRAY_ATTRIBUTE|0x0000062B) #define CKA_ENCAPSULATE 0x00000633 #define CKA_DECAPSULATE 0x00000634 #define CKA_SEED 0x00000637 #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_OPAQUE_REENC CKA_VENDOR_DEFINED + 3 #define CKA_IBM_OPAQUE_OLD CKA_VENDOR_DEFINED + 4 #define CKA_IBM_RESTRICTABLE (CKA_VENDOR_DEFINED +0x10001) #define CKA_IBM_NEVER_MODIFIABLE (CKA_VENDOR_DEFINED +0x10002) #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) #define CKA_IBM_PARAMETER_SET (CKA_VENDOR_DEFINED +0x10010) /* For protected key option */ #define CKA_IBM_PROTKEY_EXTRACTABLE (CKA_VENDOR_DEFINED +0x1000c) #define CKA_IBM_PROTKEY_NEVER_EXTRACTABLE (CKA_VENDOR_DEFINED +0x1000d) #define CKA_IBM_OPAQUE_PKEY (CKA_VENDOR_DEFINED + 0xd0100) #define CKA_IBM_CCA_AES_KEY_MODE (CKA_VENDOR_DEFINED + 0xd0101) typedef CK_ULONG CK_IBM_CCA_AES_KEY_MODE_TYPE; #define CK_IBM_CCA_AES_DATA_KEY 0 #define CK_IBM_CCA_AES_CIPHER_KEY 1 #define CKA_IBM_CCA_ML_DSA_KEY_MODE (CKA_VENDOR_DEFINED + 0xd0102) typedef CK_ULONG CK_IBM_CCA_ML_DSA_KEY_MODE_TYPE; #define CK_IBM_CCA_ML_DSA_PURE_KEY 0 #define CK_IBM_CCA_ML_DSA_PREHASH_KEY 1 #define CK_IBM_DILITHIUM_KEYFORM_ROUND2_65 1 #define CK_IBM_DILITHIUM_KEYFORM_ROUND2_87 2 #define CK_IBM_DILITHIUM_KEYFORM_ROUND3_44 3 #define CK_IBM_DILITHIUM_KEYFORM_ROUND3_65 4 #define CK_IBM_DILITHIUM_KEYFORM_ROUND3_87 5 #define IBM_DILITHIUM_KEYFORM_ROUND2 CK_IBM_DILITHIUM_KEYFORM_ROUND2_65 #define CKA_IBM_DILITHIUM_MODE (CKA_VENDOR_DEFINED + 0x00010) #define CKA_IBM_DILITHIUM_KEYFORM (CKA_VENDOR_DEFINED + 0xd0001) #define CKA_IBM_DILITHIUM_RHO CKA_IBM_ML_DSA_RHO #define CKA_IBM_DILITHIUM_SEED CKA_IBM_ML_DSA_SEED #define CKA_IBM_DILITHIUM_TR CKA_IBM_ML_DSA_TR #define CKA_IBM_DILITHIUM_S1 CKA_IBM_ML_DSA_S1 #define CKA_IBM_DILITHIUM_S2 CKA_IBM_ML_DSA_S2 #define CKA_IBM_DILITHIUM_T0 CKA_IBM_ML_DSA_T0 #define CKA_IBM_DILITHIUM_T1 CKA_IBM_ML_DSA_T1 #define CKA_IBM_KYBER_MODE (CKA_VENDOR_DEFINED + 0x0000E) #define CKA_IBM_KYBER_KEYFORM (CKA_VENDOR_DEFINED + 0xd0009) #define CKA_IBM_KYBER_PK CKA_IBM_ML_KEM_PK #define CKA_IBM_KYBER_SK CKA_IBM_ML_KEM_SK #define CK_IBM_KYBER_KEYFORM_ROUND2_768 1 #define CK_IBM_KYBER_KEYFORM_ROUND2_1024 2 /* Map the IBM Kyber param definitions to IBM_ML-KEM param definitions */ #define CK_IBM_KYBER_KEM_VERSION 0 #define CK_IBM_KYBER_KEM_MODE CK_IBM_ML_KEM_MODE #define CK_IBM_KYBER_KEM_ENCAPSULATE CK_IBM_ML_KEM_ENCAPSULATE #define CK_IBM_KYBER_KEM_DECAPSULATE CK_IBM_ML_KEM_DECAPSULATE #define CK_IBM_KYBER_KDF_TYPE CK_IBM_ML_KEM_KDF_TYPE #define CK_IBM_KYBER_PARAMS CK_IBM_ML_KEM_PARAMS #if !defined(CKD_VENDOR_DEFINED) #define CKD_VENDOR_DEFINED 0x80000000UL #endif #ifndef OCK_NO_EP11_DEFINES #define CKD_IBM_HYBRID_NULL CKD_VENDOR_DEFINED + 0x00000001UL #define CKD_IBM_HYBRID_SHA1_KDF CKD_VENDOR_DEFINED + 0x00000002UL #define CKD_IBM_HYBRID_SHA224_KDF CKD_VENDOR_DEFINED + 0x00000003UL #define CKD_IBM_HYBRID_SHA256_KDF CKD_VENDOR_DEFINED + 0x00000004UL #define CKD_IBM_HYBRID_SHA384_KDF CKD_VENDOR_DEFINED + 0x00000005UL #define CKD_IBM_HYBRID_SHA512_KDF CKD_VENDOR_DEFINED + 0x00000006UL #endif #define CKA_IBM_ML_DSA_RHO (CKA_VENDOR_DEFINED + 0xd0002) #define CKA_IBM_ML_DSA_SEED (CKA_VENDOR_DEFINED + 0xd0003) #define CKA_IBM_ML_DSA_TR (CKA_VENDOR_DEFINED + 0xd0004) #define CKA_IBM_ML_DSA_S1 (CKA_VENDOR_DEFINED + 0xd0005) #define CKA_IBM_ML_DSA_S2 (CKA_VENDOR_DEFINED + 0xd0006) #define CKA_IBM_ML_DSA_T0 (CKA_VENDOR_DEFINED + 0xd0007) #define CKA_IBM_ML_DSA_T1 (CKA_VENDOR_DEFINED + 0xd0008) #define CKA_IBM_ML_DSA_PRIVATE_SEED (CKA_VENDOR_DEFINED + 0xd000D) #define CKA_IBM_ML_KEM_PK (CKA_VENDOR_DEFINED + 0xd000A) #define CKA_IBM_ML_KEM_SK (CKA_VENDOR_DEFINED + 0xd000B) #define CKA_IBM_ML_KEM_PRIVATE_SEED (CKA_VENDOR_DEFINED + 0xd000C) #ifndef OCK_NO_EP11_DEFINES typedef CK_ULONG CK_IBM_ML_DSA_PARAMETER_SET_TYPE; #define CKP_IBM_ML_DSA_44 CKP_ML_DSA_44 #define CKP_IBM_ML_DSA_65 CKP_ML_DSA_65 #define CKP_IBM_ML_DSA_87 CKP_ML_DSA_87 typedef CK_ULONG CK_IBM_ML_KEM_PARAMETER_SET_TYPE; #define CKP_IBM_ML_KEM_512 CKP_ML_KEM_512 #define CKP_IBM_ML_KEM_768 CKP_ML_KEM_768 #define CKP_IBM_ML_KEM_1024 CKP_ML_KEM_1024 typedef CK_ULONG CK_IBM_HEDGE_TYPE; #define CKH_IBM_HEDGE_PREFERRED 1 #define CKH_IBM_HEDGE_REQUIRED 2 #define CKH_IBM_DETERMINISTIC_REQUIRED 3 typedef struct CK_IBM_SIGN_ADDITIONAL_CONTEXT { CK_IBM_HEDGE_TYPE hedgeVariant; CK_BYTE_PTR pContext; CK_ULONG ulContextLen; } CK_IBM_SIGN_ADDITIONAL_CONTEXT; #endif #define CK_IBM_ML_KEM_VERSION 0 typedef CK_ULONG CK_IBM_ML_KEM_MODE; #define CK_IBM_ML_KEM_ENCAPSULATE 1 #define CK_IBM_ML_KEM_DECAPSULATE 2 typedef CK_ULONG CK_IBM_ML_KEM_KDF_TYPE; typedef struct CK_IBM_ML_KEM_PARAMS { CK_ULONG ulVersion; CK_IBM_ML_KEM_MODE mode; CK_IBM_ML_KEM_KDF_TYPE kdf; CK_BBOOL bPrepend; CK_BYTE *pCipher; CK_ULONG ulCipherLen; CK_BYTE *pSharedData; CK_ULONG ulSharedDataLen; CK_OBJECT_HANDLE hSecret; } CK_IBM_ML_KEM_PARAMS; typedef struct CK_IBM_ML_KEM_WITH_ECDH_PARAMS { CK_IBM_ML_KEM_MODE mode; CK_BYTE *pCipher; CK_ULONG ulCipherLen; CK_OBJECT_HANDLE hECPrivateKey; CK_IBM_ML_KEM_KDF_TYPE kdf; CK_ULONG ulSharedDataLen; CK_BYTE_PTR pSharedData; CK_ULONG ulPublicDataLen; CK_BYTE_PTR pPublicData; } CK_IBM_ML_KEM_WITH_ECDH_PARAMS; /* 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, value * and length 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_PROFILE_ID is a value that identifies a profile ID. */ typedef CK_ULONG CK_PROFILE_ID; typedef CK_PROFILE_ID CK_PTR CK_PROFILE_ID_PTR; /* 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 /* The following are new for v3.0 */ #define CKM_SHA3_224_RSA_PKCS 0x00000066 #define CKM_SHA3_256_RSA_PKCS 0x00000060 #define CKM_SHA3_384_RSA_PKCS 0x00000061 #define CKM_SHA3_512_RSA_PKCS 0x00000062 #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 /* The following are new for v3.0 */ #define CKM_SHA3_224_RSA_PKCS_PSS 0x00000067 #define CKM_SHA3_256_RSA_PKCS_PSS 0x00000063 #define CKM_SHA3_384_RSA_PKCS_PSS 0x00000064 #define CKM_SHA3_512_RSA_PKCS_PSS 0x00000065 #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_224_KEY_DERIVATION 0x0000004B #define CKM_SHA512_256 0x0000004C #define CKM_SHA512_256_HMAC 0x0000004D #define CKM_SHA512_256_HMAC_GENERAL 0x0000004E #define CKM_SHA512_256_KEY_DERIVATION 0x0000004F /* The following are new for v3.0 */ #define CKM_SHA3_256 0x000002B0 #define CKM_SHA3_256_HMAC 0x000002B1 #define CKM_SHA3_256_HMAC_GENERAL 0x000002B2 #define CKM_SHA3_256_KEY_GEN 0x000002B3 #define CKM_SHA3_224 0x000002B5 #define CKM_SHA3_224_HMAC 0x000002B6 #define CKM_SHA3_224_HMAC_GENERAL 0x000002B7 #define CKM_SHA3_224_KEY_GEN 0x000002B8 #define CKM_SHA3_384 0x000002C0 #define CKM_SHA3_384_HMAC 0x000002C1 #define CKM_SHA3_384_HMAC_GENERAL 0x000002C2 #define CKM_SHA3_384_KEY_GEN 0x000002C3 #define CKM_SHA3_512 0x000002D0 #define CKM_SHA3_512_HMAC 0x000002D1 #define CKM_SHA3_512_HMAC_GENERAL 0x000002D2 #define CKM_SHA3_512_KEY_GEN 0x000002D3 /* 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 /* The following are new for v3.0 (aliases are new for v3.1) */ #define CKM_SHA3_256_KEY_DERIVATION 0x00000397 #define CKM_SHA3_224_KEY_DERIVATION 0x00000398 #define CKM_SHA3_384_KEY_DERIVATION 0x00000399 #define CKM_SHA3_512_KEY_DERIVATION 0x0000039A #define CKM_SHAKE_128_KEY_DERIVATION 0x0000039B #define CKM_SHAKE_256_KEY_DERIVATION 0x0000039C #define CKM_SHA3_256_KEY_DERIVE CKM_SHA3_256_KEY_DERIVATION #define CKM_SHA3_224_KEY_DERIVE CKM_SHA3_224_KEY_DERIVATION #define CKM_SHA3_384_KEY_DERIVE CKM_SHA3_384_KEY_DERIVATION #define CKM_SHA3_512_KEY_DERIVE CKM_SHA3_512_KEY_DERIVATION #define CKM_SHAKE_128_KEY_DERIVE CKM_SHAKE_128_KEY_DERIVATION #define CKM_SHAKE_256_KEY_DERIVE CKM_SHAKE_256_KEY_DERIVATION #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 v3.0 */ #define CKM_ECDSA_SHA3_224 0x00001047 #define CKM_ECDSA_SHA3_256 0x00001048 #define CKM_ECDSA_SHA3_384 0x00001049 #define CKM_ECDSA_SHA3_512 0x0000104A /* 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_ECDH_AES_KEY_WRAP 0x00001053 #define CKM_RSA_AES_KEY_WRAP 0x00001054 #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 v3.0 */ #define CKM_AES_XTS 0x00001071 #define CKM_AES_XTS_KEY_GEN 0x00001072 /* 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_AES_KEY_WRAP 0x00002109 #define CKM_AES_KEY_WRAP_PAD 0x0000210A /* Deprecated with v3.1 */ #define CKM_AES_KEY_WRAP_KWP 0x0000210B #define CKM_AES_KEY_WRAP_PKCS7 0x0000210C #define CKM_SHA_1_KEY_GEN 0x00004003 #define CKM_SHA224_KEY_GEN 0x00004004 #define CKM_SHA256_KEY_GEN 0x00004005 #define CKM_SHA384_KEY_GEN 0x00004006 #define CKM_SHA512_KEY_GEN 0x00004007 #define CKM_SHA512_224_KEY_GEN 0x00004008 #define CKM_SHA512_256_KEY_GEN 0x00004009 /* new for v3.0 */ #define CKM_EC_EDWARDS_KEY_PAIR_GEN 0x00001055 #define CKM_EC_MONTGOMERY_KEY_PAIR_GEN 0x00001056 #define CKM_EDDSA 0x00001057 /* new for v3.2 */ #define CKM_ML_KEM_KEY_PAIR_GEN 0x0000000F #define CKM_ML_KEM 0x00000017 #define CKM_ML_DSA_KEY_PAIR_GEN 0x0000001C #define CKM_ML_DSA 0x0000001D #define CKM_HASH_ML_DSA 0x0000001F #define CKM_HASH_ML_DSA_SHA224 0x00000023 #define CKM_HASH_ML_DSA_SHA256 0x00000024 #define CKM_HASH_ML_DSA_SHA384 0x00000025 #define CKM_HASH_ML_DSA_SHA512 0x00000026 #define CKM_HASH_ML_DSA_SHA3_224 0x00000027 #define CKM_HASH_ML_DSA_SHA3_256 0x00000028 #define CKM_HASH_ML_DSA_SHA3_384 0x00000029 #define CKM_HASH_ML_DSA_SHA3_512 0x0000002A #define CKM_HASH_ML_DSA_SHAKE128 0x0000002B #define CKM_HASH_ML_DSA_SHAKE256 0x0000002C #define CKM_ECDH_X_AES_KEY_WRAP 0x00004038 #define CKM_ECDH_COF_AES_KEY_WRAP 0x00004039 #define CKM_PUB_KEY_FROM_PRIV_KEY 0x0000403A #define CKM_VENDOR_DEFINED 0x80000000 #ifndef OCK_NO_EP11_DEFINES #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_KYBER CKM_VENDOR_DEFINED + 0x00010024 #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_X25519 CKM_VENDOR_DEFINED + 0x0001001b #define CKM_IBM_ED25519_SHA512 CKM_VENDOR_DEFINED + 0x0001001c #define CKM_IBM_EC_X448 CKM_VENDOR_DEFINED + 0x0001001e #define CKM_IBM_ED448_SHA3 CKM_VENDOR_DEFINED + 0x0001001f #define CKM_IBM_ECDSA_OTHER CKM_VENDOR_DEFINED + 0x00010031 #define CKM_IBM_EC_AGGREGATE CKM_VENDOR_DEFINED + 0x00010034 #define CKM_IBM_ML_DSA_KEY_PAIR_GEN CKM_VENDOR_DEFINED + 0x00010035 #define CKM_IBM_ML_DSA CKM_VENDOR_DEFINED + 0x00010036 #define CKM_IBM_ML_KEM_KEY_PAIR_GEN CKM_VENDOR_DEFINED + 0x00010037 #define CKM_IBM_ML_KEM CKM_VENDOR_DEFINED + 0x00010038 #define CKM_IBM_ATTRIBUTEBOUND_WRAP CKM_VENDOR_DEFINED + 0x00020004 #define CKM_IBM_BTC_DERIVE CKM_VENDOR_DEFINED + 0x00070001 #endif #define CKM_IBM_ML_KEM_WITH_ECDH CKM_VENDOR_DEFINED + 0x0001ff01 #define CKM_IBM_EC_C25519 CKM_IBM_EC_X25519 #define CKM_IBM_EC_C448 CKM_IBM_EC_X448 #define CKM_IBM_EDDSA_SHA512 CKM_IBM_ED25519_SHA512 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 */ /* new for PKCS#11 v3.0 */ #define CKF_MESSAGE_ENCRYPT 0x00000002 #define CKF_MESSAGE_DECRYPT 0x00000004 #define CKF_MESSAGE_SIGN 0x00000008 #define CKF_MESSAGE_VERIFY 0x00000010 #define CKF_MULTI_MESSAGE 0x00000020 #define CKF_FIND_OBJECTS 0x00000040 /* 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_OID 0x00800000 #define CKF_EC_NAMEDCURVE CKF_EC_OID /* deprecated since PKCS#11 v3.0 */ #define CKF_EC_UNCOMPRESS 0x01000000 #define CKF_EC_COMPRESS 0x02000000 #define CKF_EC_CURVENAME 0x04000000 /* New for v3.2 */ #define CKF_ENCAPSULATE 0x10000000 #define CKF_DECAPSULATE 0x20000000 #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_ACTION_PROHIBITED 0x0000001B #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_AEAD_DECRYPT_FAILED 0x00000042 #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 #define CKR_NEW_PIN_MODE 0x000001B0 #define CKR_NEXT_OTP 0x000001B1 #define CKR_EXCEEDED_MAX_ITERATIONS 0x000001B5 #define CKR_FIPS_SELF_TEST_FAILED 0x000001B6 #define CKR_LIBRARY_LOAD_FAILED 0x000001B7 #define CKR_PIN_TOO_WEAK 0x000001B8 #define CKR_PUBLIC_KEY_INVALID 0x000001B9 /* CKR_FUNCTION_REJECTED is new for v2.20 */ #define CKR_FUNCTION_REJECTED 0x00000200 /* New to v3.0 */ #define CKR_TOKEN_RESOURCE_EXCEEDED 0x00000201 #define CKR_OPERATION_CANCEL_FAILED 0x00000202 #define CKR_KEY_EXHAUSTED 0x00000203 /* New for v3.2 */ #define CKR_PENDING 0x00000204 #define CKR_SESSION_ASYNC_NOT_SUPPORTED 0x00000205 #define CKR_SEED_RANDOM_REQUIRED 0x00000206 #define CKR_OPERATION_NOT_VALIDATED 0x00000207 #define CKR_TOKEN_NOT_INITIALIZED 0x00000208 #define CKR_PARAMETER_SET_NOT_SUPPORTED 0x00000209 #define CKR_VENDOR_DEFINED 0x80000000 /* Not really a return value, but stored in ulDeviceError of session info for policy violations. */ #define CKR_POLICY_VIOLATION (CKR_VENDOR_DEFINED + 0x1) /* 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_ULONG ulIvBits; CK_BYTE_PTR pAAD; CK_ULONG ulAADLen; CK_ULONG ulTagBits; } CK_GCM_PARAMS; typedef CK_GCM_PARAMS CK_PTR CK_GCM_PARAMS_PTR; /* * There is a discrepancy between what the PKCS#11 v2.40 standard states in the * documentation and the official header file about structure CK_GCM_PARAMS: * https://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/errata01/os/include/pkcs11-v2.40/pkcs11t.h * The header file defines field ulIvBits for structure CK_GCM_PARAMS, but the * documentation does not mention that field at all. * Opencryptoki accepts both versions of the CK_GCM_PARAMS structure, with or * without the field. Structure CK_GCM_PARAMS_COMPAT represents the one without * field ulIvBits. */ typedef struct CK_GCM_PARAMS_COMPAT { CK_BYTE_PTR pIv; CK_ULONG ulIvLen; CK_BYTE_PTR pAAD; CK_ULONG ulAADLen; CK_ULONG ulTagBits; } CK_GCM_PARAMS_COMPAT; /* 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_MGF1_SHA3_224 0x00000006 #define CKG_MGF1_SHA3_256 0x00000007 #define CKG_MGF1_SHA3_384 0x00000008 #define CKG_MGF1_SHA3_512 0x00000009 #define CKG_VENDOR_DEFINED 0x80000000UL #ifndef OCK_NO_EP11_DEFINES #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 #endif 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; typedef struct CK_RSA_AES_KEY_WRAP_PARAMS { CK_ULONG ulAESKeyBits; CK_RSA_PKCS_OAEP_PARAMS_PTR pOAEPParams; } CK_RSA_AES_KEY_WRAP_PARAMS; typedef CK_RSA_AES_KEY_WRAP_PARAMS CK_PTR CK_RSA_AES_KEY_WRAP_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; typedef struct CK_ECDH_AES_KEY_WRAP_PARAMS { CK_ULONG ulAESKeyBits; CK_EC_KDF_TYPE kdf; CK_ULONG ulSharedDataLen; CK_BYTE_PTR pSharedData; } CK_ECDH_AES_KEY_WRAP_PARAMS; typedef CK_ECDH_AES_KEY_WRAP_PARAMS CK_PTR CK_ECDH_AES_KEY_WRAP_PARAMS_PTR; /* EDDSA */ typedef struct CK_EDDSA_PARAMS { CK_BBOOL phFlag; CK_ULONG ulContextDataLen; CK_BYTE_PTR pContextData; } CK_EDDSA_PARAMS; typedef CK_EDDSA_PARAMS CK_PTR CK_EDDSA_PARAMS_PTR; /* Async */ typedef struct CK_ASYNC_DATA { CK_ULONG ulVersion; CK_BYTE_PTR pValue; CK_ULONG ulValue; CK_OBJECT_HANDLE hObject; CK_OBJECT_HANDLE hAdditionalObject; } CK_ASYNC_DATA; typedef CK_ASYNC_DATA CK_PTR CK_ASYNC_DATA_PTR; typedef CK_ULONG CK_SESSION_VALIDATION_FLAGS_TYPE; typedef CK_ULONG CK_HEDGE_TYPE; #define CKH_HEDGE_PREFERRED 0x00000000 #define CKH_HEDGE_REQUIRED 0x00000001 #define CKH_DETERMINISTIC_REQUIRED 0x00000002 /* PQC */ typedef struct CK_SIGN_ADDITIONAL_CONTEXT { CK_HEDGE_TYPE hedgeVariant; CK_BYTE_PTR pContext; CK_ULONG ulContextLen; } CK_SIGN_ADDITIONAL_CONTEXT; typedef struct CK_HASH_SIGN_ADDITIONAL_CONTEXT { CK_HEDGE_TYPE hedgeVariant; CK_BYTE_PTR pContext; CK_ULONG ulContextLen; CK_MECHANISM_TYPE hash; } CK_HASH_SIGN_ADDITIONAL_CONTEXT; typedef CK_ULONG CK_ML_DSA_PARAMETER_SET_TYPE; #define CKP_ML_DSA_44 0x00000001 #define CKP_ML_DSA_65 0x00000002 #define CKP_ML_DSA_87 0x00000003 typedef CK_ULONG CK_ML_KEM_PARAMETER_SET_TYPE; #define CKP_ML_KEM_512 0x00000001 #define CKP_ML_KEM_768 0x00000002 #define CKP_ML_KEM_1024 0x00000003 /* Attribute bound wrapping mechanism */ typedef struct CK_IBM_ATTRIBUTEBOUND_WRAP { CK_OBJECT_HANDLE hSignVerifyKey; } CK_IBM_ATTRIBUTEBOUND_WRAP_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 /* The following are new for v3.0 */ #define CKD_SHA3_224_KDF 0x0000000AUL #define CKD_SHA3_256_KDF 0x0000000BUL #define CKD_SHA3_384_KDF 0x0000000CUL #define CKD_SHA3_512_KDF 0x0000000DUL #define CKD_SHA1_KDF_SP800 0x0000000EUL #define CKD_SHA224_KDF_SP800 0x0000000FUL #define CKD_SHA256_KDF_SP800 0x00000010UL #define CKD_SHA384_KDF_SP800 0x00000011UL #define CKD_SHA512_KDF_SP800 0x00000012UL #define CKD_SHA3_224_KDF_SP800 0x00000013UL #define CKD_SHA3_256_KDF_SP800 0x00000014UL #define CKD_SHA3_384_KDF_SP800 0x00000015UL #define CKD_SHA3_512_KDF_SP800 0x00000016UL /* PBKDF2 parameters */ #define CKP_PKCS5_PBKD2_HMAC_SHA256 0x00000004UL #define CKP_PKCS5_PBKD2_HMAC_SHA512 0x00000006UL #ifndef OCK_NO_EP11_DEFINES /* For CKM_IBM_BTC_DERIVE */ typedef struct CK_IBM_BTC_DERIVE_PARAMS { CK_ULONG type; CK_ULONG childKeyIndex; CK_BYTE_PTR pChainCode; CK_ULONG ulChainCodeLen; CK_ULONG version; } CK_IBM_BTC_DERIVE_PARAMS; typedef CK_IBM_BTC_DERIVE_PARAMS CK_PTR CK_IBM_BTC_DERIVE_PARAMS_PTR; #endif #define CK_IBM_BTC_DERIVE_PARAMS_VERSION_1 1 /* Key index flag */ #define CK_IBM_BTC_BIP0032_HARDENED 0x80000000 /* BTC types */ #define CK_IBM_BTC_BIP0032_PRV2PRV 1 #define CK_IBM_BTC_BIP0032_PRV2PUB 2 #define CK_IBM_BTC_BIP0032_PUB2PUB 3 #define CK_IBM_BTC_BIP0032_MASTERK 4 #define CK_IBM_BTC_SLIP0010_PRV2PRV 5 #define CK_IBM_BTC_SLIP0010_PRV2PUB 6 #define CK_IBM_BTC_SLIP0010_PUB2PUB 7 #define CK_IBM_BTC_SLIP0010_MASTERK 8 #define CK_IBM_BTC_CHAINCODE_LENGTH 32 /* For CKM_IBM_ECDSA_OTHER */ typedef struct CK_IBM_ECDSA_OTHER_PARAMS { CK_MECHANISM_TYPE submechanism; } CK_IBM_ECDSA_OTHER_PARAMS; typedef CK_IBM_ECDSA_OTHER_PARAMS CK_PTR CK_IBM_ECDSA_OTHER_PARAMS_PTR; /* CKM_IBM_ECDSA_OTHER sub-mechanisms */ #define CKM_IBM_ECSDSA_RAND 3 #define CKM_IBM_ECSDSA_COMPR_MULTI 5 #define CKM_IBM_BLS 6 #define CK_IBM_BLS12_381_SIGN_LEN 192 #define CK_IBM_BLS_MAX_AGGREGATIONS 12 typedef struct CK_IBM_ECDSA_OTHER_BLS_PARAMS { CK_ULONG numElements; CK_VOID_PTR pAggrElements[CK_IBM_BLS_MAX_AGGREGATIONS]; CK_ULONG elementSize; } CK_IBM_ECDSA_OTHER_BLS_PARAMS; #define CKF_INTERFACE_FORK_SAFE 0x00000001UL /* CK_INTERFACE is a structure which contains * an interface name with a function list and flag. */ typedef struct CK_INTERFACE { CK_UTF8CHAR_PTR pInterfaceName; CK_VOID_PTR pFunctionList; CK_FLAGS flags; } CK_INTERFACE; typedef CK_INTERFACE CK_PTR CK_INTERFACE_PTR; typedef CK_INTERFACE_PTR CK_PTR CK_INTERFACE_PTR_PTR; /* 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 struct CK_FUNCTION_LIST_3_0 CK_FUNCTION_LIST_3_0; typedef CK_FUNCTION_LIST_3_0 CK_PTR CK_FUNCTION_LIST_3_0_PTR; typedef CK_FUNCTION_LIST_3_0_PTR CK_PTR CK_FUNCTION_LIST_3_0_PTR_PTR; typedef struct CK_FUNCTION_LIST_3_2 CK_FUNCTION_LIST_3_2; typedef CK_FUNCTION_LIST_3_2 CK_PTR CK_FUNCTION_LIST_3_2_PTR; typedef CK_FUNCTION_LIST_3_2_PTR CK_PTR CK_FUNCTION_LIST_3_2_PTR_PTR; typedef struct CK_IBM_FUNCTION_LIST_1_0 CK_IBM_FUNCTION_LIST_1_0; typedef struct CK_IBM_FUNCTION_LIST_1_0 CK_PTR CK_IBM_FUNCTION_LIST_1_0_PTR; typedef CK_IBM_FUNCTION_LIST_1_0_PTR CK_PTR CK_IBM_FUNCTION_LIST_1_0_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); typedef CK_RV (CK_PTR CK_C_GetInterfaceList) (CK_INTERFACE *pInterfaceList, CK_ULONG *pulCount); typedef CK_RV (CK_PTR CK_C_GetInterface) (CK_UTF8CHAR *pInterfaceName, CK_VERSION *pVersion, CK_INTERFACE **ppInterface, CK_FLAGS flags); typedef CK_RV (CK_PTR CK_C_LoginUser) (CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, CK_UTF8CHAR *pPin, CK_ULONG ulPinLen, CK_UTF8CHAR *pUsername, CK_ULONG ulUsernameLen); typedef CK_RV (CK_PTR CK_C_SessionCancel) (CK_SESSION_HANDLE hSession, CK_FLAGS flags); typedef CK_RV (CK_PTR CK_C_MessageEncryptInit) (CK_SESSION_HANDLE hSession, CK_MECHANISM *pMechanism, CK_OBJECT_HANDLE hKey); typedef CK_RV (CK_PTR CK_C_EncryptMessage) (CK_SESSION_HANDLE hSession, void *pParameter, CK_ULONG ulParameterLen, CK_BYTE *pAssociatedData, CK_ULONG ulAssociatedDataLen, CK_BYTE *pPlaintext, CK_ULONG ulPlaintextLen, CK_BYTE *pCiphertext, CK_ULONG *pulCiphertextLen); typedef CK_RV (CK_PTR CK_C_EncryptMessageBegin) (CK_SESSION_HANDLE hSession, void *pParameter, CK_ULONG ulParameterLen, CK_BYTE *pAssociatedData, CK_ULONG ulAssociatedDataLen); typedef CK_RV (CK_PTR CK_C_EncryptMessageNext) (CK_SESSION_HANDLE hSession, void *pParameter, CK_ULONG ulParameterLen, CK_BYTE *pPlaintextPart, CK_ULONG ulPlaintextPartLen, CK_BYTE *pCiphertextPart, CK_ULONG *pulCiphertextPartLen, CK_ULONG flags); typedef CK_RV (CK_PTR CK_C_MessageEncryptFinal) (CK_SESSION_HANDLE hSession); typedef CK_RV (CK_PTR CK_C_MessageDecryptInit) (CK_SESSION_HANDLE hSession, CK_MECHANISM *pMechanism, CK_OBJECT_HANDLE hKey); typedef CK_RV (CK_PTR CK_C_DecryptMessage) (CK_SESSION_HANDLE hSession, void *pParameter, CK_ULONG ulParameterLen, CK_BYTE *pAssociatedData, CK_ULONG ulAssociatedDataLen, CK_BYTE *pCiphertext, CK_ULONG ulCiphertextLen, CK_BYTE *pPlaintext, CK_ULONG *pulPlaintextLen); typedef CK_RV (CK_PTR CK_C_DecryptMessageBegin) (CK_SESSION_HANDLE hSession, void *pParameter, CK_ULONG ulParameterLen, CK_BYTE *pAssociatedData, CK_ULONG ulAssociatedDataLen); typedef CK_RV (CK_PTR CK_C_DecryptMessageNext) (CK_SESSION_HANDLE hSession, void *pParameter, CK_ULONG ulParameterLen, CK_BYTE *pCiphertextPart, CK_ULONG ulCiphertextPartLen, CK_BYTE *pPlaintextPart, CK_ULONG *pulPlaintextPartLen, CK_FLAGS flags); typedef CK_RV (CK_PTR CK_C_MessageDecryptFinal) (CK_SESSION_HANDLE hSession); typedef CK_RV (CK_PTR CK_C_MessageSignInit) (CK_SESSION_HANDLE hSession, CK_MECHANISM *pMechanism, CK_OBJECT_HANDLE hKey); typedef CK_RV (CK_PTR CK_C_SignMessage) (CK_SESSION_HANDLE hSession, void *pParameter, CK_ULONG ulParameterLen, CK_BYTE *pData, CK_ULONG ulDataLen, CK_BYTE *pSignature, CK_ULONG *pulSignatureLen); typedef CK_RV (CK_PTR CK_C_SignMessageBegin) (CK_SESSION_HANDLE hSession, void *pParameter, CK_ULONG ulParameterLen); typedef CK_RV (CK_PTR CK_C_SignMessageNext) (CK_SESSION_HANDLE hSession, void *pParameter, CK_ULONG ulParameterLen, CK_BYTE *pDataPart, CK_ULONG ulDataPartLen, CK_BYTE *pSignature, CK_ULONG *pulSignatureLen); typedef CK_RV (CK_PTR CK_C_MessageSignFinal) (CK_SESSION_HANDLE hSession); typedef CK_RV (CK_PTR CK_C_MessageVerifyInit) (CK_SESSION_HANDLE hSession, CK_MECHANISM *pMechanism, CK_OBJECT_HANDLE hKey); typedef CK_RV (CK_PTR CK_C_VerifyMessage) (CK_SESSION_HANDLE hSession, void *pParameter, CK_ULONG ulParameterLen, CK_BYTE *pData, CK_ULONG ulDataLen, CK_BYTE *pSignature, CK_ULONG ulSignatureLen); typedef CK_RV (CK_PTR CK_C_VerifyMessageBegin) (CK_SESSION_HANDLE hSession, void *pParameter, CK_ULONG ulParameterLen); typedef CK_RV (CK_PTR CK_C_VerifyMessageNext) (CK_SESSION_HANDLE hSession, void *pParameter, CK_ULONG ulParameterLen, CK_BYTE *pDataPart, CK_ULONG ulDataPartLen, CK_BYTE *pSignature, CK_ULONG ulSignatureLen); typedef CK_RV (CK_PTR CK_C_MessageVerifyFinal) (CK_SESSION_HANDLE hSession); typedef CK_RV (CK_PTR CK_C_EncapsulateKey) (CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hPublicKey, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, CK_BYTE_PTR pCiphertext, CK_ULONG_PTR pulCiphertextLen, CK_OBJECT_HANDLE_PTR phKey); typedef CK_RV (CK_PTR CK_C_DecapsulateKey) (CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hPrivateKey, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, CK_BYTE_PTR pCiphertext, CK_ULONG ulCiphertextLen, CK_OBJECT_HANDLE_PTR phKey); typedef CK_RV (CK_PTR CK_C_VerifySignatureInit) (CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen); typedef CK_RV (CK_PTR CK_C_VerifySignature) (CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen); typedef CK_RV (CK_PTR CK_C_VerifySignatureUpdate) (CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen); typedef CK_RV (CK_PTR CK_C_VerifySignatureFinal) (CK_SESSION_HANDLE hSession); typedef CK_RV (CK_PTR CK_C_GetSessionValidationFlags) (CK_SESSION_HANDLE hSession, CK_SESSION_VALIDATION_FLAGS_TYPE type, CK_FLAGS_PTR pFlags); typedef CK_RV (CK_PTR CK_C_AsyncComplete) (CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pFunctionName, CK_ASYNC_DATA_PTR pResult); typedef CK_RV (CK_PTR CK_C_AsyncGetID) (CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pFunctionName, CK_ULONG_PTR pulID); typedef CK_RV (CK_PTR CK_C_AsyncJoin) (CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pFunctionName, CK_ULONG ulID, CK_BYTE_PTR pData, CK_ULONG ulData); typedef CK_RV (CK_PTR CK_C_WrapKeyAuthenticated) (CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hWrappingKey, CK_OBJECT_HANDLE hKey, CK_BYTE_PTR pAssociatedData, CK_ULONG ulAssociatedDataLen, CK_BYTE_PTR pWrappedKey, CK_ULONG_PTR pulWrappedKeyLen); typedef CK_RV (CK_PTR CK_C_UnwrapKeyAuthenticated) (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_BYTE_PTR pAssociatedData, CK_ULONG ulAssociatedDataLen, CK_OBJECT_HANDLE_PTR phKey); typedef CK_RV (CK_PTR CK_C_IBM_ReencryptSingle) (CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pDecrMech, CK_OBJECT_HANDLE hDecrKey, CK_MECHANISM_PTR pEncrMech, CK_OBJECT_HANDLE hEncrKey, CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen, CK_BYTE_PTR pReencryptedData, CK_ULONG_PTR pulReencryptedDataLen); 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; }; struct CK_FUNCTION_LIST_3_0 { 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; CK_C_GetInterfaceList C_GetInterfaceList; CK_C_GetInterface C_GetInterface; CK_C_LoginUser C_LoginUser; CK_C_SessionCancel C_SessionCancel; CK_C_MessageEncryptInit C_MessageEncryptInit; CK_C_EncryptMessage C_EncryptMessage; CK_C_EncryptMessageBegin C_EncryptMessageBegin; CK_C_EncryptMessageNext C_EncryptMessageNext; CK_C_MessageEncryptFinal C_MessageEncryptFinal; CK_C_MessageDecryptInit C_MessageDecryptInit; CK_C_DecryptMessage C_DecryptMessage; CK_C_DecryptMessageBegin C_DecryptMessageBegin; CK_C_DecryptMessageNext C_DecryptMessageNext; CK_C_MessageDecryptFinal C_MessageDecryptFinal; CK_C_MessageSignInit C_MessageSignInit; CK_C_SignMessage C_SignMessage; CK_C_SignMessageBegin C_SignMessageBegin; CK_C_SignMessageNext C_SignMessageNext; CK_C_MessageSignFinal C_MessageSignFinal; CK_C_MessageVerifyInit C_MessageVerifyInit; CK_C_VerifyMessage C_VerifyMessage; CK_C_VerifyMessageBegin C_VerifyMessageBegin; CK_C_VerifyMessageNext C_VerifyMessageNext; CK_C_MessageVerifyFinal C_MessageVerifyFinal; }; struct CK_FUNCTION_LIST_3_2 { 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; CK_C_GetInterfaceList C_GetInterfaceList; CK_C_GetInterface C_GetInterface; CK_C_LoginUser C_LoginUser; CK_C_SessionCancel C_SessionCancel; CK_C_MessageEncryptInit C_MessageEncryptInit; CK_C_EncryptMessage C_EncryptMessage; CK_C_EncryptMessageBegin C_EncryptMessageBegin; CK_C_EncryptMessageNext C_EncryptMessageNext; CK_C_MessageEncryptFinal C_MessageEncryptFinal; CK_C_MessageDecryptInit C_MessageDecryptInit; CK_C_DecryptMessage C_DecryptMessage; CK_C_DecryptMessageBegin C_DecryptMessageBegin; CK_C_DecryptMessageNext C_DecryptMessageNext; CK_C_MessageDecryptFinal C_MessageDecryptFinal; CK_C_MessageSignInit C_MessageSignInit; CK_C_SignMessage C_SignMessage; CK_C_SignMessageBegin C_SignMessageBegin; CK_C_SignMessageNext C_SignMessageNext; CK_C_MessageSignFinal C_MessageSignFinal; CK_C_MessageVerifyInit C_MessageVerifyInit; CK_C_VerifyMessage C_VerifyMessage; CK_C_VerifyMessageBegin C_VerifyMessageBegin; CK_C_VerifyMessageNext C_VerifyMessageNext; CK_C_MessageVerifyFinal C_MessageVerifyFinal; CK_C_EncapsulateKey C_EncapsulateKey; CK_C_DecapsulateKey C_DecapsulateKey; CK_C_VerifySignatureInit C_VerifySignatureInit; CK_C_VerifySignature C_VerifySignature; CK_C_VerifySignatureUpdate C_VerifySignatureUpdate; CK_C_VerifySignatureFinal C_VerifySignatureFinal; CK_C_GetSessionValidationFlags C_GetSessionValidationFlags; CK_C_AsyncComplete C_AsyncComplete; CK_C_AsyncGetID C_AsyncGetID; CK_C_AsyncJoin C_AsyncJoin; CK_C_WrapKeyAuthenticated C_WrapKeyAuthenticated; CK_C_UnwrapKeyAuthenticated C_UnwrapKeyAuthenticated; }; struct CK_IBM_FUNCTION_LIST_1_0 { CK_VERSION version; CK_C_IBM_ReencryptSingle C_IBM_ReencryptSingle; }; #ifdef __cplusplus } #endif #endif // _PKCS11TYPES_H_ opencryptoki-opencryptoki-451d99c/usr/include/pkcs32.h000066400000000000000000000124151520105705100230410ustar00rootroot00000000000000/* * 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; #ifdef __cplusplus } #endif #endif // _PKCS1132_HS_H_ opencryptoki-opencryptoki-451d99c/usr/include/pqc_oids.h000066400000000000000000000064321520105705100235370ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2022 * * This program is provided under the terms of the Common Public License, * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this * software constitutes recipient's acceptance of CPL-1.0 terms which can be * found in the file LICENSE file or at * https://opensource.org/licenses/cpl1.0.php */ #ifndef _PQC_OIDS_H_ #define _PQC_OIDS_H_ /* * OIDs and their DER encoding for the post-quantum crypto algorithms * supported by OpenCryptoki: */ /* Dilithium Round 2 high-security (SHAKE-256): 1.3.6.1.4.1.2.267.1.6.5 */ #define OCK_DILITHIUM_R2_65 { 0x06, 0x0B, 0x2B, 0x06, 0x01, 0x04, \ 0x01, 0x02, 0x82, 0x0B, 0x01, 0x06, 0x05 } /* Dilithium Round 2 for outbound authentication: 1.3.6.1.4.1.2.267.1.8.7 */ #define OCK_DILITHIUM_R2_87 { 0x06, 0x0B, 0x2B, 0x06, 0x01, 0x04, \ 0x01, 0x02, 0x82, 0x0B, 0x01, 0x08, 0x07 } /* Dilithium Round 3 weak (SHAKE-256): 1.3.6.1.4.1.2.267.7.4.4 */ #define OCK_DILITHIUM_R3_44 { 0x06, 0x0B, 0x2B, 0x06, 0x01, 0x04, \ 0x01, 0x02, 0x82, 0x0B, 0x07, 0x04, 0x04 } /* Dilithium Round 3 recommended (SHAKE-256): 1.3.6.1.4.1.2.267.7.6.5 */ #define OCK_DILITHIUM_R3_65 { 0x06, 0x0B, 0x2B, 0x06, 0x01, 0x04, \ 0x01, 0x02, 0x82, 0x0B, 0x07, 0x06, 0x05 } /* Dilithium Round 3 high-security (SHAKE-256): 1.3.6.1.4.1.2.267.7.8.7 */ #define OCK_DILITHIUM_R3_87 { 0x06, 0x0B, 0x2B, 0x06, 0x01, 0x04, \ 0x01, 0x02, 0x82, 0x0B, 0x07, 0x08, 0x07 } /* Kyber Round 2 768 (SHAKE-128): 1.3.6.1.4.1.2.267.5.3.3 */ #define OCK_KYBER_R2_768 { 0x06, 0x0B, 0x2B, 0x06, 0x01, 0x04, \ 0x01, 0x02, 0x82, 0x0B, 0x05, 0x03, 0x03 } /* Kyber Round 2 1024 (SHAKE-128): 1.3.6.1.4.1.2.267.5.4.4 */ #define OCK_KYBER_R2_1024 { 0x06, 0x0B, 0x2B, 0x06, 0x01, 0x04, \ 0x01, 0x02, 0x82, 0x0B, 0x05, 0x04, 0x04 } /* ML-DSA 44: 2.16.840.1.101.3.4.3.17 */ #define OCK_ML_DSA_44 { 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, \ 0x65, 0x03, 0x04, 0x03, 0x11 } /* ML-DSA 65: 2.16.840.1.101.3.4.3.18 */ #define OCK_ML_DSA_65 { 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, \ 0x65, 0x03, 0x04, 0x03, 0x12 } /* ML-DSA 87: 2.16.840.1.101.3.4.3.19 */ #define OCK_ML_DSA_87 { 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, \ 0x65, 0x03, 0x04, 0x03, 0x13 } /* ML-KEM 512: 2.16.840.1.101.3.4.4.1 */ #define OCK_ML_KEM_512 { 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, \ 0x65, 0x03, 0x04, 0x04, 0x01 } /* ML-KEM 768: 2.16.840.1.101.3.4.4.2 */ #define OCK_ML_KEM_768 { 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, \ 0x65, 0x03, 0x04, 0x04, 0x02 } #define OCK_ML_KEM_786 OCK_ML_KEM_768 /* backward compatibility */ /* ML-KEM 1024: 2.16.840.1.101.3.4.4.3 */ #define OCK_ML_KEM_1024 { 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, \ 0x65, 0x03, 0x04, 0x04, 0x03 } #endif // _PQC_OIDS_H_ opencryptoki-opencryptoki-451d99c/usr/include/slotmgr.h000066400000000000000000000254561520105705100234340ustar00rootroot00000000000000/* * 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 #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 OCK_HSM_MK_CHANGE_PATH CONFIG_PATH "/HSM_MK_CHANGE" #define OCK_HSM_MK_CHANGE_LOCK_FILE LOCKDIR_PATH "/LCK..HSM_MK_CHANGElock" #if defined(_AIX) /* * AIX needs the file to be opened in write mode for an exclusive lock. * Mode bits are changed to -w--w---- to allow starting up even when there * is a lock file left over from a previous start. */ #define MODE_BITS (S_IWUSR | S_IWGRP) #define OPEN_MODE O_WRONLY #else #define MODE_BITS (S_IRUSR | S_IRGRP) #define OPEN_MODE O_RDONLY #endif #define RUN_DIR RUN_PATH "/opencryptoki" #define PROC_SOCKET_FILE_PATH RUN_DIR "/pkcsslotd.socket" #define ADMIN_SOCKET_FILE_PATH RUN_DIR "/pkcsslotd.admin.socket" #define PID_FILE_PATH RUN_DIR "/pkcsslotd.pid" #define OCK_CONFIG OCK_CONFDIR "/opencryptoki.conf" #ifndef PKCSSLOTD_USER #error "PKCSSLOTD_USER is not defined" #endif #ifndef PKCS_GROUP #error "PKCS_GROUP is not defined" #endif #ifndef CK_BOOL #define CK_BOOL CK_BBOOL #endif /* CK_BOOL */ #ifndef TEST_COND_VARS #define TEST_COND_VARS 0 #endif /* TEST_COND_VARS */ #define NUMBER_SLOTS_MANAGED 1024 #define NUMBER_PROCESSES_ALLOWED 1000 #define NUMBER_ADMINS_ALLOWED 1000 #if defined(_AIX) /* * AIX does not define NAME_MAX and instead requires this * to be determined at runtime. Use the equivalent defined for * BSD-compatibility (which uses MAXNAMLEN) - also 255 */ #include #define NAME_MAX _D_NAME_MAX #endif // // 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; #define FLAG_EVENT_SUPPORT_DISABLED 0x01 #define FLAG_STATISTICS_ENABLED 0x02 #define FLAG_STATISTICS_IMPLICIT 0x04 #define FLAG_STATISTICS_INTERNAL 0x08 #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; /* pid of the process (in pkcsslotd-namespace). * 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 * counts for garbage * collection clean up * of the global * session count. */ uint32 slot_rw_session_count[NUMBER_SLOTS_MANAGED]; uint32 slot_tokspec_count[NUMBER_SLOTS_MANAGED]; 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 char usergroup[LOGIN_NAME_MAX]; // group of users having access to the token } 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]; uint32 slot_global_rw_sessions[NUMBER_SLOTS_MANAGED]; uint32 slot_global_tokspec_count[NUMBER_SLOTS_MANAGED]; Slot_Mgr_Proc_t_64 proc_table[NUMBER_PROCESSES_ALLOWED]; } Slot_Mgr_Shr_t; typedef struct { pid_t real_pid; /* pid of client process in pkcsslotd namespace */ uid_t real_uid; /* uid of client process in pkcsslotd namespace */ gid_t real_gid; /* gid of client process in pkcsslotd namespace */ } Slot_Mgr_Client_Cred_t; typedef struct { uint32 num_slots; uint8 flags; 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 { pid_t real_pid; /* pid of client process in pkcsslotd namespace */ uid_t real_uid; /* uid of client process in pkcsslotd namespace */ gid_t real_gid; /* gid of client process in pkcsslotd namespace */ } Slot_Mgr_Client_Cred_t; typedef struct { uint32 num_slots; uint8 flags; 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 " #ifndef CRYPTOKI_API_MAJOR_V #define CRYPTOKI_API_MAJOR_V 0x3 #endif #ifndef CRYPTOKI_API_MINOR_V #define CRYPTOKI_API_MINOR_V 0x2 #endif #define LIB_MAJOR_V 1 #define LIB_MINOR_V 4 #define RESTART_SYS_CALLS 1 #if defined(__GNUC__) || defined(__clang__) __attribute__((__format__ (__printf__, 3, 4))) #endif static inline int ock_snprintf(char *buf, size_t buflen, const char *fmt, ...) { va_list ap; int n; va_start(ap, fmt); n = vsnprintf(buf, buflen, fmt, ap); va_end(ap); if (n < 0 || (size_t)n >= buflen) return -1; return 0; } #endif /* _SLOTMGR_H */ opencryptoki-opencryptoki-451d99c/usr/include/stdll.h000066400000000000000000000666511520105705100230710ustar00rootroot00000000000000/* * 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; CK_BBOOL rw_session; } 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); typedef CK_RV (CK_PTR ST_C_SessionCancel)(STDLL_TokData_t *tokdata, ST_SESSION_T *hSession, CK_FLAGS flags); typedef CK_RV (CK_PTR ST_C_EncapsulateKey)(STDLL_TokData_t *tokdata, ST_SESSION_T *hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hPublicKey, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, CK_BYTE_PTR pCiphertext, CK_ULONG_PTR pulCiphertextLen, CK_OBJECT_HANDLE_PTR phKey); typedef CK_RV (CK_PTR ST_C_DecapsulateKey)(STDLL_TokData_t *tokdata, ST_SESSION_T *hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hPrivateKey, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, CK_BYTE_PTR pCiphertext, CK_ULONG ulCiphertextLen, CK_OBJECT_HANDLE_PTR phKey); typedef CK_RV (CK_PTR ST_C_VerifySignatureInit)(STDLL_TokData_t *tokdata, ST_SESSION_T *hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen); typedef CK_RV (CK_PTR ST_C_VerifySignature)(STDLL_TokData_t *tokdata, ST_SESSION_T *hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen); typedef CK_RV (CK_PTR ST_C_VerifySignatureUpdate)(STDLL_TokData_t *tokdata, ST_SESSION_T *hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen); typedef CK_RV (CK_PTR ST_C_VerifySignatureFinal)(STDLL_TokData_t *tokdata, ST_SESSION_T *hSession); typedef CK_RV (CK_PTR ST_C_IBM_ReencryptSingle)(STDLL_TokData_t *tokdata, ST_SESSION_T *hSession, CK_MECHANISM_PTR pDecrMech, CK_OBJECT_HANDLE hDecrKey, CK_MECHANISM_PTR pEncrMech, CK_OBJECT_HANDLE hEncrKey, CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen, CK_BYTE_PTR pReencryptedData, CK_ULONG_PTR pulReencryptedDataLen); typedef CK_RV (CK_PTR ST_C_HandleEvent)(STDLL_TokData_t *tokdata, unsigned int event_type, unsigned int event_flags, const char *payload, unsigned int payload_len); 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; ST_C_SessionCancel ST_SessionCancel; ST_C_EncapsulateKey ST_EncapsulateKey; ST_C_DecapsulateKey ST_DecapsulateKey; ST_C_VerifySignatureInit ST_VerifySignatureInit; ST_C_VerifySignature ST_VerifySignature; ST_C_VerifySignatureUpdate ST_VerifySignatureUpdate; ST_C_VerifySignatureFinal ST_VerifySignatureFinal; ST_C_IBM_ReencryptSingle ST_IBM_ReencryptSingle; /* The functions defined below are not part of the external API */ ST_C_HandleEvent ST_HandleEvent; }; typedef struct ST_FCN_LIST STDLL_FcnList_t; #endif opencryptoki-opencryptoki-451d99c/usr/lib/000077500000000000000000000000001520105705100207035ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/usr/lib/api/000077500000000000000000000000001520105705100214545ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/usr/lib/api/api.mk000066400000000000000000000043631520105705100225640ustar00rootroot00000000000000nobase_lib_LTLIBRARIES += opencryptoki/libopencryptoki.la noinst_HEADERS += usr/lib/api/apiproto.h usr/lib/api/policy.h \ usr/lib/api/statistics.h usr/lib/api/hashmap.h \ usr/lib/api/mechtable.h usr/lib/api/supportedstrengths.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 \ -I${srcdir}/usr/lib/config -I${top_builddir}/usr/lib/config \ -DSTDLL_NAME=\"api\" -DHASHMAP_JENKINS_MIX \ -I${top_builddir}/usr/lib/api if AIX opencryptoki_libopencryptoki_la_LDFLAGS = \ -shared -lc -ldl -lpthread -lcrypto -lrt -Wl,-binitfini:api_init:api_fini \ -version-info $(SO_CURRENT):$(SO_REVISION):$(SO_AGE) \ -Wl,-bnoautoexp -export-symbols ${srcdir}/opencryptoki.map.sym else opencryptoki_libopencryptoki_la_LDFLAGS = \ -shared -Wl,-z,defs,-Bsymbolic -lc -ldl -lpthread -lcrypto -lrt \ -version-info $(SO_CURRENT):$(SO_REVISION):$(SO_AGE) \ -Wl,--version-script=${srcdir}/opencryptoki.map endif 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 \ usr/lib/api/policy.c usr/lib/api/hashmap.c \ usr/lib/api/statistics.c \ usr/lib/common/utility_common.c usr/lib/common/ec_supported.c \ usr/lib/config/configuration.c \ usr/lib/common/ec_curve_translation.c \ usr/lib/common/kdf_translation.c \ usr/lib/common/mgf_translation.c \ usr/lib/api/supportedstrengths.c \ usr/lib/common/pqc_supported.c \ usr/lib/config/cfgparse.y usr/lib/config/cfglex.l \ usr/lib/common/btree.c if AIX opencryptoki_libopencryptoki_la_SOURCES += usr/lib/common/aix/short_name.c endif nodist_opencryptoki_libopencryptoki_la_SOURCES = \ usr/lib/api/mechtable.c usr/lib/api/mechtable.c usr/lib/api/mechtable-gen.h: tools/tableidxgen $(AM_V_GEN)$(MKDIR_P) usr/lib/api && ${abs_builddir}/tools/tableidxgen -c usr/lib/api/mechtable.c -d usr/lib/api/mechtable-gen.h -l usr/lib/api/mechtable.log BUILT_SOURCES += usr/lib/api/mechtable-gen.h EXTRA_DIST += usr/lib/api/mechtable.inc CLEANFILES += usr/lib/api/shrd_mem.c usr/lib/api/mechtable.c $(BUILT_SOURCES) \ usr/lib/api/mechtable.log opencryptoki-opencryptoki-451d99c/usr/lib/api/api_interface.c000066400000000000000000006277141520105705100244320ustar00rootroot00000000000000/* * 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 #include #include "trace.h" #include "ock_syslog.h" #include "policy.h" #include "statistics.h" #include void api_init(void); static int openssl_err_cb(const char *str, size_t len, void *u) { UNUSED(len); UNUSED(u); TRACE_DEVEL("OpenSSL error: %s", str); return 1; } #if OPENSSL_VERSION_PREREQ(3, 0) #define BEGIN_OPENSSL_LIBCTX(ossl_ctx, rc) \ do { \ ERR_set_mark(); \ OSSL_LIB_CTX *prev_ctx = OSSL_LIB_CTX_set0_default((ossl_ctx));\ if (prev_ctx == NULL) { \ (rc) = CKR_FUNCTION_FAILED; \ TRACE_ERROR("OSSL_LIB_CTX_set0_default failed\n"); \ ERR_pop_to_mark(); \ break; \ } #define END_OPENSSL_LIBCTX(rc) \ if (OSSL_LIB_CTX_set0_default(prev_ctx) == NULL) { \ if ((rc) == CKR_OK) \ (rc) = CKR_FUNCTION_FAILED; \ TRACE_ERROR("OSSL_LIB_CTX_set0_default failed\n"); \ } \ ERR_print_errors_cb(openssl_err_cb, NULL); \ ERR_pop_to_mark(); \ } while (0); #else #define BEGIN_OPENSSL_LIBCTX(ossl_ctx, rc) \ do { \ ERR_set_mark(); #define END_OPENSSL_LIBCTX(rc) \ ERR_print_errors_cb(openssl_err_cb, NULL); \ ERR_pop_to_mark(); \ } while (0); #endif // 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 struct policy policy; struct statistics statistics; static CK_IBM_FUNCTION_LIST_1_0 func_list_ibm_1_0 = { {1, 0}, C_IBM_ReencryptSingle }; static CK_FUNCTION_LIST func_list_pkcs11_2_40 = { {2, 40}, C_Initialize, C_Finalize, C_GetInfo, C_GetFunctionList, C_GetSlotList, C_GetSlotInfo, C_GetTokenInfo, C_GetMechanismList, C_GetMechanismInfo, C_InitToken, C_InitPIN, C_SetPIN, C_OpenSession, C_CloseSession, C_CloseAllSessions, C_GetSessionInfo, C_GetOperationState, C_SetOperationState, C_Login, C_Logout, C_CreateObject, C_CopyObject, C_DestroyObject, C_GetObjectSize, C_GetAttributeValue, C_SetAttributeValue, C_FindObjectsInit, C_FindObjects, C_FindObjectsFinal, C_EncryptInit, C_Encrypt, C_EncryptUpdate, C_EncryptFinal, C_DecryptInit, C_Decrypt, C_DecryptUpdate, C_DecryptFinal, C_DigestInit, C_Digest, C_DigestUpdate, C_DigestKey, C_DigestFinal, C_SignInit, C_Sign, C_SignUpdate, C_SignFinal, C_SignRecoverInit, C_SignRecover, C_VerifyInit, C_Verify, C_VerifyUpdate, C_VerifyFinal, C_VerifyRecoverInit, C_VerifyRecover, C_DigestEncryptUpdate, C_DecryptDigestUpdate, C_SignEncryptUpdate, C_DecryptVerifyUpdate, C_GenerateKey, C_GenerateKeyPair, C_WrapKey, C_UnwrapKey, C_DeriveKey, C_SeedRandom, C_GenerateRandom, C_GetFunctionStatus, C_CancelFunction, C_WaitForSlotEvent }; static CK_FUNCTION_LIST_3_0 func_list_pkcs11_3_0 = { {3, 0}, C_Initialize, C_Finalize, C_GetInfo, C_GetFunctionList, C_GetSlotList, C_GetSlotInfo, C_GetTokenInfo, C_GetMechanismList, C_GetMechanismInfo, C_InitToken, C_InitPIN, C_SetPIN, C_OpenSession, C_CloseSession, C_CloseAllSessions, C_GetSessionInfo, C_GetOperationState, C_SetOperationState, C_Login, C_Logout, C_CreateObject, C_CopyObject, C_DestroyObject, C_GetObjectSize, C_GetAttributeValue, C_SetAttributeValue, C_FindObjectsInit, C_FindObjects, C_FindObjectsFinal, C_EncryptInit, C_Encrypt, C_EncryptUpdate, C_EncryptFinal, C_DecryptInit, C_Decrypt, C_DecryptUpdate, C_DecryptFinal, C_DigestInit, C_Digest, C_DigestUpdate, C_DigestKey, C_DigestFinal, C_SignInit, C_Sign, C_SignUpdate, C_SignFinal, C_SignRecoverInit, C_SignRecover, C_VerifyInit, C_Verify, C_VerifyUpdate, C_VerifyFinal, C_VerifyRecoverInit, C_VerifyRecover, C_DigestEncryptUpdate, C_DecryptDigestUpdate, C_SignEncryptUpdate, C_DecryptVerifyUpdate, C_GenerateKey, C_GenerateKeyPair, C_WrapKey, C_UnwrapKey, C_DeriveKey, C_SeedRandom, C_GenerateRandom, C_GetFunctionStatus, C_CancelFunction, C_WaitForSlotEvent, C_GetInterfaceList, C_GetInterface, C_LoginUser, C_SessionCancel, C_MessageEncryptInit, C_EncryptMessage, C_EncryptMessageBegin, C_EncryptMessageNext, C_MessageEncryptFinal, C_MessageDecryptInit, C_DecryptMessage, C_DecryptMessageBegin, C_DecryptMessageNext, C_MessageDecryptFinal, C_MessageSignInit, C_SignMessage, C_SignMessageBegin, C_SignMessageNext, C_MessageSignFinal, C_MessageVerifyInit, C_VerifyMessage, C_VerifyMessageBegin, C_VerifyMessageNext, C_MessageVerifyFinal }; static CK_FUNCTION_LIST_3_2 func_list_pkcs11_3_2 = { {3, 2}, C_Initialize, C_Finalize, C_GetInfo, C_GetFunctionList, C_GetSlotList, C_GetSlotInfo, C_GetTokenInfo, C_GetMechanismList, C_GetMechanismInfo, C_InitToken, C_InitPIN, C_SetPIN, C_OpenSession, C_CloseSession, C_CloseAllSessions, C_GetSessionInfo, C_GetOperationState, C_SetOperationState, C_Login, C_Logout, C_CreateObject, C_CopyObject, C_DestroyObject, C_GetObjectSize, C_GetAttributeValue, C_SetAttributeValue, C_FindObjectsInit, C_FindObjects, C_FindObjectsFinal, C_EncryptInit, C_Encrypt, C_EncryptUpdate, C_EncryptFinal, C_DecryptInit, C_Decrypt, C_DecryptUpdate, C_DecryptFinal, C_DigestInit, C_Digest, C_DigestUpdate, C_DigestKey, C_DigestFinal, C_SignInit, C_Sign, C_SignUpdate, C_SignFinal, C_SignRecoverInit, C_SignRecover, C_VerifyInit, C_Verify, C_VerifyUpdate, C_VerifyFinal, C_VerifyRecoverInit, C_VerifyRecover, C_DigestEncryptUpdate, C_DecryptDigestUpdate, C_SignEncryptUpdate, C_DecryptVerifyUpdate, C_GenerateKey, C_GenerateKeyPair, C_WrapKey, C_UnwrapKey, C_DeriveKey, C_SeedRandom, C_GenerateRandom, C_GetFunctionStatus, C_CancelFunction, C_WaitForSlotEvent, C_GetInterfaceList, C_GetInterface, C_LoginUser, C_SessionCancel, C_MessageEncryptInit, C_EncryptMessage, C_EncryptMessageBegin, C_EncryptMessageNext, C_MessageEncryptFinal, C_MessageDecryptInit, C_DecryptMessage, C_DecryptMessageBegin, C_DecryptMessageNext, C_MessageDecryptFinal, C_MessageSignInit, C_SignMessage, C_SignMessageBegin, C_SignMessageNext, C_MessageSignFinal, C_MessageVerifyInit, C_VerifyMessage, C_VerifyMessageBegin, C_VerifyMessageNext, C_MessageVerifyFinal, C_EncapsulateKey, C_DecapsulateKey, C_VerifySignatureInit, C_VerifySignature, C_VerifySignatureUpdate, C_VerifySignatureFinal, C_GetSessionValidationFlags, C_AsyncComplete, C_AsyncGetID, C_AsyncJoin, C_WrapKeyAuthenticated, C_UnwrapKeyAuthenticated }; int slot_loaded[NUMBER_SLOTS_MANAGED]; // Array of flags to indicate // if the STDLL loaded CK_BBOOL in_child_fork_initializer = FALSE; CK_BBOOL in_destructor = FALSE; /* * Ordered array of interfaces: If more than one interface matches * interface_get's arguments, the interface at lowest index is returned. */ static CK_INTERFACE interface_list[] = { { (CK_UTF8CHAR *)"PKCS 11", &func_list_pkcs11_3_2, CKF_INTERFACE_FORK_SAFE /*XXX*/ }, { (CK_UTF8CHAR *)"PKCS 11", &func_list_pkcs11_3_0, CKF_INTERFACE_FORK_SAFE /*XXX*/ }, { (CK_UTF8CHAR *)"PKCS 11", &func_list_pkcs11_2_40, CKF_INTERFACE_FORK_SAFE /*XXX*/ }, { (CK_UTF8CHAR *)"Vendor IBM", &func_list_ibm_1_0, CKF_INTERFACE_FORK_SAFE /*XXX*/ } }; void child_fork_initializer(void) { /* * 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; } void parent_fork_prepare(void) { if (Anchor == NULL) return; /* * Stop the event thread in the fork parent, since having the event thread * active when a fork is performed causes various problems (e.g. deadlocks * in glibc). */ if (Anchor->event_thread > 0) stop_event_thread(); } void parent_fork_after(void) { if (Anchor == NULL) return; /* Restart the event thread in the parent when fork is complete */ if ((Anchor->SocketDataP.flags & FLAG_EVENT_SUPPORT_DISABLED) == 0 && Anchor->event_thread == 0) start_event_thread(); } //------------------------------------------------------------------------ // 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) { CK_RV rc = CKR_OK; // 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 */ BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rc) CloseAllSessions(slotID, FALSE); END_OPENSSL_LIBCTX(rc) return rc; } // 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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_CloseSession(sltp->TokData, &rSession, FALSE); TRACE_DEVEL("Called STDLL rv = 0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) // If the STDLL successfully closed the session // 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, rSession.rw_session); } 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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_CopyObject(sltp->TokData, &rSession, hObject, pTemplate, ulCount, phNewObject); TRACE_DEVEL("fcn->ST_CopyObject returned:0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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_ARGUMENTS_BAD)); return CKR_ARGUMENTS_BAD; } // 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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_CreateObject(sltp->TokData, &rSession, pTemplate, ulCount, phObject); TRACE_DEVEL("fcn->ST_CreateObject returned:0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_Decrypt(sltp->TokData, &rSession, pEncryptedData, ulEncryptedDataLen, pData, pulDataLen); END_HSM_MK_CHANGE_LOCK(sltp, rv) TRACE_DEVEL("fcn->ST_Decrypt returned:0x%lx\n", rv); END_OPENSSL_LIBCTX(rv) } else { 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); 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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_DecryptDigestUpdate(sltp->TokData, &rSession, pEncryptedPart, ulEncryptedPartLen, pPart, pulPartLen); TRACE_DEVEL("fcn->ST_DecryptDigestUpdate returned:0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_DecryptFinal(sltp->TokData, &rSession, pLastPart, pulLastPartLen); TRACE_DEVEL("fcn->ST_DecryptFinal returned: 0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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); 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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_DecryptInit(sltp->TokData, &rSession, pMechanism, hKey); TRACE_DEVEL("fcn->ST_DecryptInit returned:0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_DecryptUpdate(sltp->TokData, &rSession, pEncryptedPart, ulEncryptedPartLen, pPart, pulPartLen); TRACE_DEVEL("fcn->ST_DecryptUpdate:0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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); 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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_DecryptVerifyUpdate(sltp->TokData, &rSession, pEncryptedPart, ulEncryptedPartLen, pPart, pulPartLen); TRACE_DEVEL("fcn->ST_DecryptVerifyUpdate returned:0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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_ARGUMENTS_BAD)); return CKR_ARGUMENTS_BAD; } // 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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_DeriveKey(sltp->TokData, &rSession, pMechanism, hBaseKey, pTemplate, ulAttributeCount, phKey); TRACE_DEVEL("fcn->ST_DeriveKey returned:0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_DestroyObject(sltp->TokData, &rSession, hObject); TRACE_DEVEL("fcn->ST_DestroyObject returned:0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_Digest(sltp->TokData, &rSession, pData, ulDataLen, pDigest, pulDigestLen); TRACE_DEVEL("fcn->ST_Digest:0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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; } 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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_DigestEncryptUpdate(sltp->TokData, &rSession, pPart, ulPartLen, pEncryptedPart, pulEncryptedPartLen); TRACE_DEVEL("fcn->ST_DigestEncryptUpdate returned:0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_DigestFinal(sltp->TokData, &rSession, pDigest, pulDigestLen); TRACE_DEVEL("fcn->ST_DigestFinal returned:0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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 (!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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_DigestInit(sltp->TokData, &rSession, pMechanism); TRACE_DEVEL("fcn->ST_DigestInit returned:0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_DigestKey(sltp->TokData, &rSession, hKey); TRACE_DEBUG("fcn->ST_DigestKey returned:0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_DigestUpdate(sltp->TokData, &rSession, pPart, ulPartLen); TRACE_DEVEL("fcn->ST_DigestUpdate returned:0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_Encrypt(sltp->TokData, &rSession, pData, ulDataLen, pEncryptedData, pulEncryptedDataLen); TRACE_DEVEL("fcn->ST_Encrypt returned: 0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_EncryptFinal(sltp->TokData, &rSession, pLastEncryptedPart, pulLastEncryptedPartLen); TRACE_DEVEL("fcn->ST_EncryptFinal: 0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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 (!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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_EncryptInit(sltp->TokData, &rSession, pMechanism, hKey); TRACE_INFO("fcn->ST_EncryptInit returned:0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_EncryptUpdate(sltp->TokData, &rSession, pPart, ulPartLen, pEncryptedPart, pulEncryptedPartLen); TRACE_DEVEL("fcn->ST_EncryptUpdate returned:0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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 */ if (pthread_mutex_lock(&GlobMutex)) { // Grab Process level Global MUTEX TRACE_ERROR("Global Mutex Lock failed.\n"); return CKR_CANT_LOCK; } 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); /* * Stop the event thread and close the socket. * If C_Finalize is called as part of the fork initializer, don't stop * the thread, since a forked process does not have any threads, and don't * close the socket, as this would close the connection of the parent * process to the pkcsslotd as well. * */ if (!in_child_fork_initializer) { if (Anchor->event_thread > 0) stop_event_thread(); if (Anchor->socketfd >= 0) close(Anchor->socketfd); } // unload all the STDLL's from the application // This is in case the APP decides to do the re-initialize and // continue on BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rc) 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); } } /* * Calling dlclose() in a atfork handler may cause a deadlock. * dlclose() may itself modify the atfork handler table to remove * any fork handlers that the to be unloaded library has registered. * Since the atfork handler table is currently locked when we are in * an atfork handler, this would produce a deadlock. */ DL_UnLoad(sltp, slotID, in_child_fork_initializer); } END_OPENSSL_LIBCTX(rc) // Un register from Slot D API_UnRegister(); bt_destroy(&Anchor->sess_btree); #if OPENSSL_VERSION_PREREQ(3, 0) /* * Only cleanup OpenSSL library context and providers if we are not in the * library destructor. The library destructor calls C_Finalize if not * already finalized, but this may happen during at-exit handlers when the * program is terminating. At that point in time, the OpenSSL at-exit * handler may already have performed cleanup which will then cause * crashes when trying to cleanup the already freed library context here. * We are leaking the library context and providers if one just unloads * the library without calling C_Finalize. However, OpenSSL cleanup will * clean up the context at program termination anyway. */ if (in_destructor == FALSE) { ERR_set_mark(); if (Anchor->openssl_default_provider != NULL) OSSL_PROVIDER_unload(Anchor->openssl_default_provider); if (Anchor->openssl_legacy_provider != NULL) OSSL_PROVIDER_unload(Anchor->openssl_legacy_provider); if (Anchor->openssl_libctx != NULL) OSSL_LIB_CTX_free(Anchor->openssl_libctx); ERR_pop_to_mark(); } #endif detach_shared_memory(Anchor->SharedMemP); free(Anchor); // Free API Proc Struct Anchor = NULL; trace_finalize(); policy_unload(&policy); statistics_term(&statistics); //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 || ulMaxObjectCount == 0) { 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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_FindObjects(sltp->TokData, &rSession, phObject, ulMaxObjectCount, pulObjectCount); TRACE_DEVEL("fcn->ST_FindObjects returned:0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_FindObjectsFinal(sltp->TokData, &rSession); TRACE_DEVEL("fcn->ST_FindObjectsFinal returned: 0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_FindObjectsInit(sltp->TokData, &rSession, pTemplate, ulCount); TRACE_DEVEL("fcn->ST_FindObjectsInit returned:0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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_ARGUMENTS_BAD)); return CKR_ARGUMENTS_BAD; } 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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_GenerateKey(sltp->TokData, &rSession, pMechanism, pTemplate, ulCount, phKey); TRACE_DEVEL("fcn->ST_GenerateKey returned:0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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_ARGUMENTS_BAD)); return CKR_ARGUMENTS_BAD; } 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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_GenerateKeyPair(sltp->TokData, &rSession, pMechanism, pPublicKeyTemplate, ulPublicKeyAttributeCount, pPrivateKeyTemplate, ulPrivateKeyAttributeCount, phPublicKey, phPrivateKey); TRACE_DEVEL("fcn->ST_GenerateKeyPair returned:0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_GenerateRandom(sltp->TokData, &rSession, RandomData, ulRandomLen); TRACE_DEVEL("fcn->ST_GenerateRandom returned:0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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_ARGUMENTS_BAD)); return CKR_ARGUMENTS_BAD; } if (ulCount == 0) { 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_GetAttributeValue) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_GetAttributeValue(sltp->TokData, &rSession, hObject, pTemplate, ulCount); TRACE_DEVEL("fcn->ST_GetAttributeValue returned:0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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"); if (ppFunctionList) { (*ppFunctionList) = &func_list_pkcs11_2_40; 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_ARGUMENTS_BAD)); return CKR_ARGUMENTS_BAD; } 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_GetMechanismInfo %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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) rv = fcn->ST_GetMechanismInfo(sltp->TokData, slotID, type, pInfo); TRACE_DEVEL("fcn->ST_GetMechanismInfo returned:0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) rv = fcn->ST_GetMechanismList(sltp->TokData, slotID, pMechanismList, pulCount); TRACE_DEVEL("fcn->ST_GetMechanismList returned: 0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_GetObjectSize(sltp->TokData, &rSession, hObject, pulSize); TRACE_DEVEL("fcn->ST_GetObjectSize retuned: 0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_GetOperationState(sltp->TokData, &rSession, pOperationState, pulOperationStateLen); TRACE_DEVEL("fcn->ST_GetOperationState returned:0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_GetSessionInfo(sltp->TokData, &rSession, pInfo); 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); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } 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_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; } sinfp = &shData->slot_info[slotID]; // 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_TOKEN_NOT_PRESENT)); return CKR_TOKEN_NOT_PRESENT; } #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) { 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_ARGUMENTS_BAD)); return CKR_ARGUMENTS_BAD; } count = 0; if (slotID >= NUMBER_SLOTS_MANAGED) { TRACE_ERROR("%s\n", ock_err(ERR_SLOT_ID_INVALID)); return CKR_SLOT_ID_INVALID; } sinfp = &shData->slot_info[slotID]; // 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_TOKEN_NOT_PRESENT)); return CKR_TOKEN_NOT_PRESENT; } 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_ARGUMENTS_BAD)); return CKR_ARGUMENTS_BAD; } 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) { 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) { 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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) rv = fcn->ST_GetTokenInfo(sltp->TokData, slotID, pInfo); if (rv == CKR_OK) { get_sess_counts(slotID, &pInfo->ulSessionCount, &pInfo->ulRwSessionCount); } TRACE_DEVEL("rv %lu CK_TOKEN_INFO Flags %lx\n", rv, pInfo->flags); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); rv = CKR_FUNCTION_NOT_SUPPORTED; } return rv; } // end of C_GetTokenInfo void Call_Finalize(void) { 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; CK_SLOT_ID slotID; API_Slot_t *sltp; CK_ULONG stat_flags = 0; API_Proc_Struct_t *before_anchor; /* * Lock so that only one thread can run C_Initialize or C_Finalize at * a time */ if (pthread_mutex_lock(&GlobMutex)) { TRACE_ERROR("Global Mutex Lock failed.\n"); return CKR_CANT_LOCK; } /* * Ensure OpenSSL is initialized and the OpenSSL config is loaded * at the very beginning of C_Initialize(). Loading the OpenSSL config * may cause engines or providers to be loaded, which in turn may initialize * Opencryptoki again, if an engine or provider calls C_Initialize as * part of its initialization. * Special handling is required to allow this recursive use of C_Initialize * to avoid a CKR_CRYPTOKI_ALREADY_INITIALIZED error. * OPENSSL_init_crypto must be called without holding the GlobMutex as this * would cause a deadlock for such recursive calls of C_Initialize. */ before_anchor = Anchor; pthread_mutex_unlock(&GlobMutex); OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL); if (pthread_mutex_lock(&GlobMutex)) { TRACE_ERROR("Global Mutex Lock failed.\n"); return CKR_CANT_LOCK; } if (before_anchor == NULL && Anchor != NULL) { /* * An engine or provider loaded during OPENSSL_init_crypto has * recursively called C_Initialize. Thus, Opencryptoki is already * initialized by now, and we are done. */ rc = CKR_OK; goto done; } trace_initialize(); TRACE_INFO("C_Initialize\n"); rc = check_user_and_group(NULL); if (rc != CKR_OK) { OCK_SYSLOG(LOG_ERR, "C_Initialize: The current user '%s' is not a " "member of the '%s' group\n", cuserid(NULL), PKCS_GROUP); goto done; } /* * Register an atexit handler to gracefully terminate openCryptoki and * close all open sessions during termination. This is also done in the * destructor of the OpenCryptoki library. However, the library destructor * is called after the atexit handlers. * * The atexit handler registration must be AFTER OpenSSL initialization, * because OpenSSL also registers its own atexit handler during its * initialization. The atexit handlers are called in the reverse order of * their registration. So if we register our at-exit handler AFTER OpenSSL * registered its atexit handler, we are sure that ours gets called BEFORE * the OpenSSL atexit handler. * * This is important because we need to use OpenSSL services during our * atexit termination, so this works only before OpenSSL has performed its * cleanup in its atexit handler. This is also the reason why we need our * own atexit handler at all, because the library destructor is called * after OpenSSLs atexit handler, and thus OpenSSL services are no longer * available at that point in time. * * Note that if the calling application has already initialized OpenSSL * before initializing OpenCryptoki, then above OpenSSL initialization * done by OpenCryptoki is a no-operation, but still OpenSSL has already * registered its atexit handler during an earlier OpenSSL initialization, * i.e. before we register ours. * * Further note that when the OpenCryptoki library is unloaded by means of * dlclose(), then the atexit handler (which is located inside the unloaded * library) is unregistered automatically. Otherwise this would cause * segfaults when the no longer existent atexit handler would be called. * Nevertheless, the library destructor is called to perform termination * in that case. Here, OpenSSL services are still available, so it is safe * to use them during the library destructor. */ if (atexit(Call_Finalize) != 0) { TRACE_ERROR("atexit failed\n"); rc = CKR_FUNCTION_FAILED; goto done; } 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); // Zero out API_Proc_Struct // This must be done prior to all goto error calls, else bt_destroy() // will fail because it accesses uninitialized memory when t->size > 0. memset(Anchor, 0, sizeof(API_Proc_Struct_t)); Anchor->socketfd = -1; TRACE_DEBUG("Anchor allocated at %p\n", (void *) 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; } } // 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; } //Map Shared Memory Region //if ( Shared Memory Mapped not Successful ) // Free allocated Memory // Return CKR_HOST_MEMORY if (bt_init(&Anchor->sess_btree, free) != CKR_OK) { TRACE_ERROR("Btree init Failed.\n"); rc = CKR_FUNCTION_FAILED; goto error; } #if OPENSSL_VERSION_PREREQ(3, 0) /* * OpenSSL >= 3.0: * Create a separate library context for Opencryptoki's use of OpenSSL * services and explicitly load the 'default' and 'legacy' providers for * this context. * This prevents call loops when the calling application has configured a * PKCS#11 provider that uses Opencryptoki under the covers. This could * produce a loop with the following calling tree: * Application -> Openssl -> PKCS11-provider -> Opencryptoki -> OpenSSL * -> PKCS11-provider -> Opencryptoki -> ... * Explicitly using the 'default' provider only for Opencrypoki's OpenSSL * usage breaks this loop. * OpenSSL has already been initialized above, and the OpenSSL config has * been loaded already, thus all configured providers also have already been * loaded. */ ERR_set_mark(); Anchor->openssl_libctx = OSSL_LIB_CTX_new(); if (Anchor->openssl_libctx == NULL) { TRACE_ERROR("OSSL_LIB_CTX_new failed.\n"); rc = CKR_FUNCTION_FAILED; ERR_pop_to_mark(); goto error; } Anchor->openssl_default_provider = OSSL_PROVIDER_load(Anchor->openssl_libctx, "default"); if (Anchor->openssl_default_provider == NULL) { TRACE_ERROR("OSSL_PROVIDER_load for 'default' failed.\n"); rc = CKR_FUNCTION_FAILED; ERR_pop_to_mark(); goto error; } Anchor->openssl_legacy_provider = OSSL_PROVIDER_load(Anchor->openssl_libctx, "legacy"); if (Anchor->openssl_legacy_provider == NULL) { TRACE_ERROR("OSSL_PROVIDER_load for 'legacy' failed.\n"); rc = CKR_FUNCTION_FAILED; ERR_pop_to_mark(); goto error; } ERR_pop_to_mark(); #endif // 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); /* Connect to slot daemon and retrieve slot infos */ Anchor->socketfd = connect_socket(PROC_SOCKET_FILE_PATH); if (Anchor->socketfd < 0) { OCK_SYSLOG(LOG_ERR, "C_Initialize: Module failed to create a " "socket. Verify that the slot management daemon is " "running.\n"); TRACE_ERROR("Failed to connect to slot daemon\n"); rc = CKR_FUNCTION_FAILED; goto error_shm; } if (!init_socket_data(Anchor->socketfd)) { OCK_SYSLOG(LOG_ERR, "C_Initialize: Module failed to retrieve slot " "infos from slot deamon.\n"); TRACE_ERROR("Failed to receive slot infos from socket.\n"); rc = CKR_FUNCTION_FAILED; goto error_shm; } TRACE_DEVEL("pid: %u real-pid: %u euid: %u real-uid: %u real-gid: %u gid: %u\n", getpid(), Anchor->ClientCred.real_pid, geteuid(), Anchor->ClientCred.real_pid, getgid(), Anchor->ClientCred.real_pid); if (pVoid != NULL) { pArg = (CK_C_INITIALIZE_ARGS *) pVoid; if ((Anchor->SocketDataP.flags & FLAG_EVENT_SUPPORT_DISABLED) == 0 && (pArg->flags & CKF_LIBRARY_CANT_CREATE_OS_THREADS) != 0) { TRACE_ERROR("Flag CKF_LIBRARY_CANT_CREATE_OS_THREADS is set and " "event support is enabled\n"); OCK_SYSLOG(LOG_ERR, "C_Initialize: Application specified that " "library can't create OS threads. PKCS11 Module requires " "to create threads when event support is enabled.\n"); rc = CKR_NEED_TO_CREATE_THREADS; goto error; } } rc = policy_load(&policy); if (rc != CKR_OK) { TRACE_ERROR("Policy loading failed! rc=0x%lx\n", rc); goto error; } if (Anchor->SocketDataP.flags & FLAG_STATISTICS_ENABLED) { if (Anchor->SocketDataP.flags & FLAG_STATISTICS_IMPLICIT) stat_flags |= STATISTICS_FLAG_COUNT_IMPLICIT; if (Anchor->SocketDataP.flags & FLAG_STATISTICS_INTERNAL) stat_flags |= STATISTICS_FLAG_COUNT_INTERNAL; rc = statistics_init(&statistics, &Anchor->SocketDataP, stat_flags, Anchor->ClientCred.real_uid, &policy); if (rc != CKR_OK) { TRACE_ERROR("Statistics initialization failed! rc=0x%lx\n", rc); goto error; } } //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 BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rc) for (slotID = 0; slotID < NUMBER_SLOTS_MANAGED; slotID++) { sltp = &(Anchor->SltList[slotID]); slot_loaded[slotID] = DL_Load_and_Init(sltp, slotID, &policy, &statistics); } END_OPENSSL_LIBCTX(rc) if (rc != CKR_OK) goto error_shm; /* Start event receiver thread */ if ((Anchor->SocketDataP.flags & FLAG_EVENT_SUPPORT_DISABLED) == 0 && start_event_thread() != 0) { TRACE_ERROR("Failed to start event thread\n"); // unload all the STDLL's from the application // This is in case the APP decides to do the re-initialize and // continue on BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rc) for (slotID = 0; slotID < NUMBER_SLOTS_MANAGED; slotID++) { sltp = &(Anchor->SltList[slotID]); if (slot_loaded[slotID]) { if (sltp->pSTfini) { // call the terminate function.. sltp->pSTfini(sltp->TokData, slotID, &Anchor->SocketDataP.slot_info[slotID], &trace, 0); } } DL_UnLoad(sltp, slotID, FALSE); } END_OPENSSL_LIBCTX(rc) API_UnRegister(); rc = CKR_FUNCTION_FAILED; goto error_shm; } pthread_mutex_unlock(&GlobMutex); return CKR_OK; error_shm: detach_shared_memory(Anchor->SharedMemP); error: policy_unload(&policy); bt_destroy(&Anchor->sess_btree); if (Anchor->socketfd >= 0) close(Anchor->socketfd); #if OPENSSL_VERSION_PREREQ(3, 0) ERR_set_mark(); if (Anchor->openssl_default_provider != NULL) OSSL_PROVIDER_unload(Anchor->openssl_default_provider); if (Anchor->openssl_legacy_provider != NULL) OSSL_PROVIDER_unload(Anchor->openssl_legacy_provider); if (Anchor->openssl_libctx != NULL) OSSL_LIB_CTX_free(Anchor->openssl_libctx); ERR_pop_to_mark(); #endif 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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_InitPIN(sltp->TokData, &rSession, pPin, ulPinLen); TRACE_DEVEL("fcn->ST_InitPIN returned: 0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) rv = fcn->ST_InitToken(sltp->TokData, slotID, pPin, ulPinLen, pLabel); TRACE_DEVEL("fcn->ST_InitToken returned: 0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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 (!pPin) { 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_Login) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_Login(sltp->TokData, &rSession, userType, pPin, ulPinLen); TRACE_DEVEL("fcn->ST_Login returned:0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_Logout(sltp->TokData, &rSession); TRACE_DEVEL("fcn->ST_Logout returned:0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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 (flags & CKF_ASYNC_SESSION) { TRACE_ERROR("%s\n", ock_err(ERR_SESSION_ASYNC_NOT_SUPPORTED)); return CKR_SESSION_ASYNC_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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) rv = fcn->ST_OpenSession(sltp->TokData, slotID, flags, &(apiSessp->sessionh)); TRACE_DEVEL("fcn->ST_OpenSession returned: 0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) // If the session allocation is successful, then we need to // 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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) /* failed to add the object to the API-level tree, close the * STDLL-level session and return failure */ fcn->ST_CloseSession(sltp->TokData, apiSessp, FALSE); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) free(apiSessp); rv = CKR_HOST_MEMORY; goto done; } apiSessp->slotID = slotID; apiSessp->rw_session = (flags & CKF_RW_SESSION); // 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, apiSessp->rw_session); } 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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_SeedRandom(sltp->TokData, &rSession, pSeed, ulSeedLen); TRACE_DEVEL("fcn->ST_SeedRandom returned: 0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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_ARGUMENTS_BAD)); return CKR_ARGUMENTS_BAD; } if (!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_SetAttributeValue) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_SetAttributeValue(sltp->TokData, &rSession, hObject, pTemplate, ulCount); TRACE_DEVEL("fcn->ST_SetAttributeValue returned:0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_SetOperationState(sltp->TokData, &rSession, pOperationState, ulOperationStateLen, hEncryptionKey, hAuthenticationKey); TRACE_DEVEL("fcn->ST_SetOperationState returned:0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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) { 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_SetPIN) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_SetPIN(sltp->TokData, &rSession, pOldPin, ulOldLen, pNewPin, ulNewLen); TRACE_DEVEL("fcn->ST_SetPIN returned: 0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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 (!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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_Sign(sltp->TokData, &rSession, pData, ulDataLen, pSignature, pulSignatureLen); TRACE_DEVEL("fcn->ST_Sign returned: 0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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 (!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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_SignEncryptUpdate(sltp->TokData, &rSession, pPart, ulPartLen, pEncryptedPart, pulEncryptedPartLen); TRACE_DEVEL("fcn->ST_SignEncryptUpdate return: 0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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_SignFinal\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_SignFinal) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_SignFinal(sltp->TokData, &rSession, pSignature, pulSignatureLen); TRACE_DEVEL("fcn->ST_SignFinal returned: 0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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 (!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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_SignInit(sltp->TokData, &rSession, pMechanism, hKey); TRACE_DEVEL("fcn->ST_SignInit returned: 0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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 (!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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_SignRecover(sltp->TokData, &rSession, pData, ulDataLen, pSignature, pulSignatureLen); TRACE_DEVEL("fcn->ST_SignRecover returned:0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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 (!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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_SignRecoverInit(sltp->TokData, &rSession, pMechanism, hKey); TRACE_DEVEL("fcn->ST_SignRecoverInit returned: 0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_SignUpdate(sltp->TokData, &rSession, pPart, ulPartLen); TRACE_DEVEL("fcn->ST_SignUpdate returned: 0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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_ARGUMENTS_BAD)); return CKR_ARGUMENTS_BAD; } 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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_UnwrapKey(sltp->TokData, &rSession, pMechanism, hUnwrappingKey, pWrappedKey, ulWrappedKeyLen, pTemplate, ulAttributeCount, phKey); TRACE_DEVEL("fcn->ST_UnwrapKey returned: 0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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 (!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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_Verify(sltp->TokData, &rSession, pData, ulDataLen, pSignature, ulSignatureLen); TRACE_DEVEL("fcn->ST_Verify returned: 0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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 (!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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_VerifyFinal(sltp->TokData, &rSession, pSignature, ulSignatureLen); TRACE_DEVEL("fcn->ST_VerifyFinal returned: 0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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 (!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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_VerifyInit(sltp->TokData, &rSession, pMechanism, hKey); TRACE_DEVEL("fcn->ST_VerifyInit returned: 0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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 (!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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_VerifyRecover(sltp->TokData, &rSession, pSignature, ulSignatureLen, pData, pulDataLen); TRACE_DEVEL("fcn->ST_VerifyRecover returned: 0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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 (!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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_VerifyRecoverInit(sltp->TokData, &rSession, pMechanism, hKey); TRACE_DEVEL("fcn->ST_VerifyRecoverInit returned:0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_VerifyUpdate(sltp->TokData, &rSession, pPart, ulPartLen); TRACE_DEVEL("fcn->ST_VerifyUpdate returned: 0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); 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_ARGUMENTS_BAD)); return CKR_ARGUMENTS_BAD; } // 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) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_WrapKey(sltp->TokData, &rSession, pMechanism, hWrappingKey, hKey, pWrappedKey, pulWrappedKeyLen); TRACE_DEVEL("fcn->ST_WrapKey returned: 0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); rv = CKR_FUNCTION_NOT_SUPPORTED; } return rv; } CK_RV C_GetInterfaceList(CK_INTERFACE_PTR pInterfaceList, CK_ULONG_PTR pulCount) { CK_ULONG nmemb; CK_RV rv; TRACE_INFO("C_GetInterfaceList\n"); if (pulCount == NULL) { rv = CKR_ARGUMENTS_BAD; goto ret; } nmemb = sizeof(interface_list) / sizeof(interface_list[0]); if (pInterfaceList == NULL) { *pulCount = nmemb; rv = CKR_OK; goto ret; } if (*pulCount < nmemb) { *pulCount = nmemb; rv = CKR_BUFFER_TOO_SMALL; goto ret; } memcpy(pInterfaceList, interface_list, sizeof(interface_list)); rv = CKR_OK; ret: return rv; } CK_RV C_GetInterface(CK_UTF8CHAR_PTR pInterfaceName, CK_VERSION_PTR pVersion, CK_INTERFACE_PTR_PTR ppInterface, CK_FLAGS flags) { CK_INTERFACE *interf; CK_RV rv; size_t i; TRACE_INFO("C_GetInterface\n"); if (ppInterface == NULL) { rv = CKR_ARGUMENTS_BAD; goto ret; } /* * Returns the interface in interface_list that matches the arguments * and is at lowest index. If no interface in interface_list matches * the arguments, *ppInterface == NULL. */ *ppInterface = NULL; for (i = 0; i < sizeof(interface_list) / sizeof(interface_list[0]); i++) { interf = &interface_list[i]; if ((pInterfaceName == NULL || (pInterfaceName != NULL && strcmp((char *)pInterfaceName, (char *)interf->pInterfaceName) == 0)) && (pVersion == NULL || (pVersion->major == ((CK_VERSION *)interf->pFunctionList)->major && pVersion->minor == ((CK_VERSION *)interf->pFunctionList)->minor)) && (flags == (interf->flags & flags))) { *ppInterface = interf; break; } } if (*ppInterface == NULL) { rv = CKR_FUNCTION_FAILED; goto ret; } rv = CKR_OK; ret: return rv; } CK_RV C_LoginUser(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, CK_UTF8CHAR *pPin, CK_ULONG ulPinLen, CK_UTF8CHAR *pUsername, CK_ULONG ulUsernameLen) { CK_RV rv; UNUSED(hSession); UNUSED(userType); UNUSED(pPin); UNUSED(ulPinLen); UNUSED(pUsername); UNUSED(ulUsernameLen); TRACE_INFO("C_LoginUser\n"); if (API_Initialized() == FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); rv = CKR_CRYPTOKI_NOT_INITIALIZED; goto ret; } TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); rv = CKR_FUNCTION_NOT_SUPPORTED; ret: return rv; } CK_RV C_SessionCancel(CK_SESSION_HANDLE hSession, CK_FLAGS flags) { CK_RV rv; API_Slot_t *sltp; STDLL_FcnList_t *fcn; ST_SESSION_T rSession; TRACE_INFO("C_SessionCancel\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_SessionCancel) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) // Map the Session to the slot session rv = fcn->ST_SessionCancel(sltp->TokData, &rSession, flags); END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); rv = CKR_FUNCTION_NOT_SUPPORTED; } return rv; } CK_RV C_MessageEncryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM *pMechanism, CK_OBJECT_HANDLE hKey) { CK_RV rv; UNUSED(hSession); UNUSED(pMechanism); UNUSED(hKey); TRACE_INFO("C_MessageEncryptInit\n"); if (API_Initialized() == FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); rv = CKR_CRYPTOKI_NOT_INITIALIZED; goto ret; } TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); rv = CKR_FUNCTION_NOT_SUPPORTED; ret: return rv; } CK_RV C_EncryptMessage(CK_SESSION_HANDLE hSession, void *pParameter, CK_ULONG ulParameterLen, CK_BYTE *pAssociatedData, CK_ULONG ulAssociatedDataLen, CK_BYTE *pPlaintext, CK_ULONG ulPlaintextLen, CK_BYTE *pCiphertext, CK_ULONG *pulCiphertextLen) { CK_RV rv; UNUSED(hSession); UNUSED(pParameter); UNUSED(ulParameterLen); UNUSED(pAssociatedData); UNUSED(ulAssociatedDataLen); UNUSED(pPlaintext); UNUSED(ulPlaintextLen); UNUSED(pCiphertext); UNUSED(pulCiphertextLen); TRACE_INFO("C_EncryptMessage\n"); if (API_Initialized() == FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); rv = CKR_CRYPTOKI_NOT_INITIALIZED; goto ret; } TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); rv = CKR_FUNCTION_NOT_SUPPORTED; ret: return rv; } CK_RV C_EncryptMessageBegin(CK_SESSION_HANDLE hSession, void *pParameter, CK_ULONG ulParameterLen, CK_BYTE *pAssociatedData, CK_ULONG ulAssociatedDataLen) { CK_RV rv; UNUSED(hSession); UNUSED(pParameter); UNUSED(ulParameterLen); UNUSED(pAssociatedData); UNUSED(ulAssociatedDataLen); TRACE_INFO("C_EncryptMessageBegin\n"); if (API_Initialized() == FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); rv = CKR_CRYPTOKI_NOT_INITIALIZED; goto ret; } TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); rv = CKR_FUNCTION_NOT_SUPPORTED; ret: return rv; } CK_RV C_EncryptMessageNext(CK_SESSION_HANDLE hSession, void *pParameter, CK_ULONG ulParameterLen, CK_BYTE *pPlaintextPart, CK_ULONG ulPlaintextPartLen, CK_BYTE *pCiphertextPart, CK_ULONG *pulCiphertextPartLen, CK_ULONG flags) { CK_RV rv; UNUSED(hSession); UNUSED(pParameter); UNUSED(ulParameterLen); UNUSED(pPlaintextPart); UNUSED(ulPlaintextPartLen); UNUSED(pCiphertextPart); UNUSED(pulCiphertextPartLen); UNUSED(flags); TRACE_INFO("C_EncryptMessageNext\n"); if (API_Initialized() == FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); rv = CKR_CRYPTOKI_NOT_INITIALIZED; goto ret; } TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); rv = CKR_FUNCTION_NOT_SUPPORTED; ret: return rv; } CK_RV C_MessageEncryptFinal(CK_SESSION_HANDLE hSession) { CK_RV rv; UNUSED(hSession); TRACE_INFO("C_EncryptMessageFinal\n"); if (API_Initialized() == FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); rv = CKR_CRYPTOKI_NOT_INITIALIZED; goto ret; } TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); rv = CKR_FUNCTION_NOT_SUPPORTED; ret: return rv; } CK_RV C_MessageDecryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM *pMechanism, CK_OBJECT_HANDLE hKey) { CK_RV rv; UNUSED(hSession); UNUSED(pMechanism); UNUSED(hKey); TRACE_INFO("C_MessageDecryptInit\n"); if (API_Initialized() == FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); rv = CKR_CRYPTOKI_NOT_INITIALIZED; goto ret; } TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); rv = CKR_FUNCTION_NOT_SUPPORTED; ret: return rv; } CK_RV C_DecryptMessage(CK_SESSION_HANDLE hSession, void *pParameter, CK_ULONG ulParameterLen, CK_BYTE *pAssociatedData, CK_ULONG ulAssociatedDataLen, CK_BYTE *pCiphertext, CK_ULONG ulCiphertextLen, CK_BYTE *pPlaintext, CK_ULONG *pulPlaintextLen) { CK_RV rv; UNUSED(hSession); UNUSED(pParameter); UNUSED(ulParameterLen); UNUSED(pAssociatedData); UNUSED(ulAssociatedDataLen); UNUSED(pCiphertext); UNUSED(ulCiphertextLen); UNUSED(pPlaintext); UNUSED(pulPlaintextLen); TRACE_INFO("C_DecryptMessage\n"); if (API_Initialized() == FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); rv = CKR_CRYPTOKI_NOT_INITIALIZED; goto ret; } TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); rv = CKR_FUNCTION_NOT_SUPPORTED; ret: return rv; } CK_RV C_DecryptMessageBegin(CK_SESSION_HANDLE hSession, void *pParameter, CK_ULONG ulParameterLen, CK_BYTE *pAssociatedData, CK_ULONG ulAssociatedDataLen) { CK_RV rv; UNUSED(hSession); UNUSED(pParameter); UNUSED(ulParameterLen); UNUSED(pAssociatedData); UNUSED(ulAssociatedDataLen); TRACE_INFO("C_DecryptMessageBegin\n"); if (API_Initialized() == FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); rv = CKR_CRYPTOKI_NOT_INITIALIZED; goto ret; } TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); rv = CKR_FUNCTION_NOT_SUPPORTED; ret: return rv; } CK_RV C_DecryptMessageNext(CK_SESSION_HANDLE hSession, void *pParameter, CK_ULONG ulParameterLen, CK_BYTE *pCiphertextPart, CK_ULONG ulCiphertextPartLen, CK_BYTE *pPlaintextPart, CK_ULONG *pulPlaintextPartLen, CK_FLAGS flags) { CK_RV rv; UNUSED(hSession); UNUSED(pParameter); UNUSED(ulParameterLen); UNUSED(pCiphertextPart); UNUSED(ulCiphertextPartLen); UNUSED(pPlaintextPart); UNUSED(pulPlaintextPartLen); UNUSED(flags); TRACE_INFO("C_DecryptMessageNext\n"); if (API_Initialized() == FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); rv = CKR_CRYPTOKI_NOT_INITIALIZED; goto ret; } TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); rv = CKR_FUNCTION_NOT_SUPPORTED; ret: return rv; } CK_RV C_MessageDecryptFinal(CK_SESSION_HANDLE hSession) { CK_RV rv; UNUSED(hSession); TRACE_INFO("C_MessageDecryptFinal\n"); if (API_Initialized() == FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); rv = CKR_CRYPTOKI_NOT_INITIALIZED; goto ret; } TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); rv = CKR_FUNCTION_NOT_SUPPORTED; ret: return rv; } CK_RV C_MessageSignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM *pMechanism, CK_OBJECT_HANDLE hKey) { CK_RV rv; UNUSED(hSession); UNUSED(pMechanism); UNUSED(hKey); TRACE_INFO("C_MessageSignInit\n"); if (API_Initialized() == FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); rv = CKR_CRYPTOKI_NOT_INITIALIZED; goto ret; } TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); rv = CKR_FUNCTION_NOT_SUPPORTED; ret: return rv; } CK_RV C_SignMessage(CK_SESSION_HANDLE hSession, void *pParameter, CK_ULONG ulParameterLen, CK_BYTE *pData, CK_ULONG ulDataLen, CK_BYTE *pSignature, CK_ULONG *pulSignatureLen) { CK_RV rv; UNUSED(hSession); UNUSED(pParameter); UNUSED(ulParameterLen); UNUSED(pData); UNUSED(ulDataLen); UNUSED(pSignature); UNUSED(pulSignatureLen); TRACE_INFO("C_SignMessage\n"); if (API_Initialized() == FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); rv = CKR_CRYPTOKI_NOT_INITIALIZED; goto ret; } TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); rv = CKR_FUNCTION_NOT_SUPPORTED; ret: return rv; } CK_RV C_SignMessageBegin(CK_SESSION_HANDLE hSession, void *pParameter, CK_ULONG ulParameterLen) { CK_RV rv; UNUSED(hSession); UNUSED(pParameter); UNUSED(ulParameterLen); TRACE_INFO("C_SignMessageBegin\n"); if (API_Initialized() == FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); rv = CKR_CRYPTOKI_NOT_INITIALIZED; goto ret; } TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); rv = CKR_FUNCTION_NOT_SUPPORTED; ret: return rv; } CK_RV C_SignMessageNext(CK_SESSION_HANDLE hSession, void *pParameter, CK_ULONG ulParameterLen, CK_BYTE *pDataPart, CK_ULONG ulDataPartLen, CK_BYTE *pSignature, CK_ULONG *pulSignatureLen) { CK_RV rv; UNUSED(hSession); UNUSED(pParameter); UNUSED(ulParameterLen); UNUSED(pDataPart); UNUSED(ulDataPartLen); UNUSED(pSignature); UNUSED(pulSignatureLen); TRACE_INFO("C_SignMessageNext\n"); if (API_Initialized() == FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); rv = CKR_CRYPTOKI_NOT_INITIALIZED; goto ret; } TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); rv = CKR_FUNCTION_NOT_SUPPORTED; ret: return rv; } CK_RV C_MessageSignFinal(CK_SESSION_HANDLE hSession) { CK_RV rv; UNUSED(hSession); TRACE_INFO("C_MessageSignFinal\n"); if (API_Initialized() == FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); rv = CKR_CRYPTOKI_NOT_INITIALIZED; goto ret; } TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); rv = CKR_FUNCTION_NOT_SUPPORTED; ret: return rv; } CK_RV C_MessageVerifyInit(CK_SESSION_HANDLE hSession, CK_MECHANISM *pMechanism, CK_OBJECT_HANDLE hKey) { CK_RV rv; UNUSED(hSession); UNUSED(pMechanism); UNUSED(hKey); TRACE_INFO("C_MessageVerifyInit\n"); if (API_Initialized() == FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); rv = CKR_CRYPTOKI_NOT_INITIALIZED; goto ret; } TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); rv = CKR_FUNCTION_NOT_SUPPORTED; ret: return rv; } CK_RV C_VerifyMessage(CK_SESSION_HANDLE hSession, void *pParameter, CK_ULONG ulParameterLen, CK_BYTE *pData, CK_ULONG ulDataLen, CK_BYTE *pSignature, CK_ULONG ulSignatureLen) { CK_RV rv; UNUSED(hSession); UNUSED(pParameter); UNUSED(ulParameterLen); UNUSED(pData); UNUSED(ulDataLen); UNUSED(pSignature); UNUSED(ulSignatureLen); TRACE_INFO("C_VerifyMessage\n"); if (API_Initialized() == FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); rv = CKR_CRYPTOKI_NOT_INITIALIZED; goto ret; } TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); rv = CKR_FUNCTION_NOT_SUPPORTED; ret: return rv; } CK_RV C_VerifyMessageBegin(CK_SESSION_HANDLE hSession, void *pParameter, CK_ULONG ulParameterLen) { CK_RV rv; UNUSED(hSession); UNUSED(pParameter); UNUSED(ulParameterLen); TRACE_INFO("C_VerifyMessageBegin\n"); if (API_Initialized() == FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); rv = CKR_CRYPTOKI_NOT_INITIALIZED; goto ret; } TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); rv = CKR_FUNCTION_NOT_SUPPORTED; ret: return rv; } CK_RV C_VerifyMessageNext(CK_SESSION_HANDLE hSession, void *pParameter, CK_ULONG ulParameterLen, CK_BYTE *pDataPart, CK_ULONG ulDataPartLen, CK_BYTE *pSignature, CK_ULONG ulSignatureLen) { CK_RV rv; UNUSED(hSession); UNUSED(pParameter); UNUSED(ulParameterLen); UNUSED(pDataPart); UNUSED(ulDataPartLen); UNUSED(pSignature); UNUSED(ulSignatureLen); TRACE_INFO("C_VerifyMessageNext\n"); if (API_Initialized() == FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); rv = CKR_CRYPTOKI_NOT_INITIALIZED; goto ret; } TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); rv = CKR_FUNCTION_NOT_SUPPORTED; ret: return rv; } CK_RV C_MessageVerifyFinal(CK_SESSION_HANDLE hSession) { CK_RV rv; UNUSED(hSession); TRACE_INFO("C_VerifyMessageFinal\n"); if (API_Initialized() == FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); rv = CKR_CRYPTOKI_NOT_INITIALIZED; goto ret; } TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); rv = CKR_FUNCTION_NOT_SUPPORTED; ret: return rv; } CK_RV C_EncapsulateKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hPublicKey, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, CK_BYTE_PTR pCiphertext, CK_ULONG_PTR pulCiphertextLen, CK_OBJECT_HANDLE_PTR phKey) { CK_RV rv; API_Slot_t *sltp; STDLL_FcnList_t *fcn; ST_SESSION_T rSession; TRACE_INFO("C_EncapsulateKey\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_EncapsulateKey) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_EncapsulateKey(sltp->TokData, &rSession, pMechanism, hPublicKey, pTemplate, ulAttributeCount, pCiphertext, pulCiphertextLen, phKey); TRACE_DEVEL("fcn->ST_EncapsulateKey returned: 0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); rv = CKR_FUNCTION_NOT_SUPPORTED; } return rv; } CK_RV C_DecapsulateKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hPrivateKey, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, CK_BYTE_PTR pCiphertext, CK_ULONG ulCiphertextLen, CK_OBJECT_HANDLE_PTR phKey) { CK_RV rv; API_Slot_t *sltp; STDLL_FcnList_t *fcn; ST_SESSION_T rSession; TRACE_INFO("C_DecapsulateKey\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_DecapsulateKey) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_DecapsulateKey(sltp->TokData, &rSession, pMechanism, hPrivateKey, pTemplate, ulAttributeCount, pCiphertext, ulCiphertextLen, phKey); TRACE_DEVEL("fcn->ST_DecapsulateKey returned: 0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); rv = CKR_FUNCTION_NOT_SUPPORTED; } return rv; } CK_RV C_VerifySignatureInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey, 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_VerifySignatureInit\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_VerifySignatureInit) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_VerifySignatureInit(sltp->TokData, &rSession, pMechanism, hKey, pSignature, ulSignatureLen); TRACE_DEVEL("fcn->ST_VerifySignatureInit returned: 0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); rv = CKR_FUNCTION_NOT_SUPPORTED; } return rv; } CK_RV C_VerifySignature(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen) { CK_RV rv; API_Slot_t *sltp; STDLL_FcnList_t *fcn; ST_SESSION_T rSession; TRACE_INFO("C_VerifySignature\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_VerifySignature) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_VerifySignature(sltp->TokData, &rSession, pData, ulDataLen); TRACE_DEVEL("fcn->ST_VerifySignature returned: 0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); rv = CKR_FUNCTION_NOT_SUPPORTED; } return rv; } CK_RV C_VerifySignatureUpdate(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_VerifySignatureUpdate\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_VerifySignatureUpdate) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_VerifySignatureUpdate(sltp->TokData, &rSession, pPart, ulPartLen); TRACE_DEVEL("fcn->ST_VerifySignatureUpdate returned: 0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); rv = CKR_FUNCTION_NOT_SUPPORTED; } return rv; } CK_RV C_VerifySignatureFinal(CK_SESSION_HANDLE hSession) { CK_RV rv; API_Slot_t *sltp; STDLL_FcnList_t *fcn; ST_SESSION_T rSession; TRACE_INFO("C_VerifySignatureFinal\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_VerifySignatureFinal) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_VerifySignatureFinal(sltp->TokData, &rSession); TRACE_DEVEL("fcn->ST_VerifySignatureFinal returned: 0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); rv = CKR_FUNCTION_NOT_SUPPORTED; } return rv; } CK_RV C_GetSessionValidationFlags(CK_SESSION_HANDLE hSession, CK_SESSION_VALIDATION_FLAGS_TYPE type, CK_FLAGS_PTR pFlags) { CK_RV rv; UNUSED(hSession); UNUSED(type); UNUSED(pFlags); TRACE_INFO("C_GetSessionValidationFlags\n"); if (API_Initialized() == FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); rv = CKR_CRYPTOKI_NOT_INITIALIZED; goto ret; } TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); rv = CKR_FUNCTION_NOT_SUPPORTED; ret: return rv; } CK_RV C_AsyncComplete(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pFunctionName, CK_ASYNC_DATA_PTR pResult) { CK_RV rv; UNUSED(hSession); UNUSED(pFunctionName); UNUSED(pResult); TRACE_INFO("C_AsyncComplete\n"); if (API_Initialized() == FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); rv = CKR_CRYPTOKI_NOT_INITIALIZED; goto ret; } TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); rv = CKR_FUNCTION_NOT_SUPPORTED; ret: return rv; } CK_RV C_AsyncGetID(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pFunctionName, CK_ULONG_PTR pulID) { CK_RV rv; UNUSED(hSession); UNUSED(pFunctionName); UNUSED(pulID); TRACE_INFO("C_AsyncGetID\n"); if (API_Initialized() == FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); rv = CKR_CRYPTOKI_NOT_INITIALIZED; goto ret; } TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); rv = CKR_FUNCTION_NOT_SUPPORTED; ret: return rv; } CK_RV C_AsyncJoin(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pFunctionName, CK_ULONG ulID, CK_BYTE_PTR pData, CK_ULONG ulData) { CK_RV rv; UNUSED(hSession); UNUSED(pFunctionName); UNUSED(ulID); UNUSED(pData); UNUSED(ulData); TRACE_INFO("C_AsyncJoin\n"); if (API_Initialized() == FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); rv = CKR_CRYPTOKI_NOT_INITIALIZED; goto ret; } TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); rv = CKR_FUNCTION_NOT_SUPPORTED; ret: return rv; } CK_RV C_WrapKeyAuthenticated(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hWrappingKey, CK_OBJECT_HANDLE hKey, CK_BYTE_PTR pAssociatedData, CK_ULONG ulAssociatedDataLen, CK_BYTE_PTR pWrappedKey, CK_ULONG_PTR pulWrappedKeyLen) { CK_RV rv; UNUSED(hSession); UNUSED(pMechanism); UNUSED(hWrappingKey); UNUSED(hKey); UNUSED(pAssociatedData); UNUSED(ulAssociatedDataLen); UNUSED(pWrappedKey); UNUSED(pulWrappedKeyLen); TRACE_INFO("C_WrapKeyAuthenticated\n"); if (API_Initialized() == FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); rv = CKR_CRYPTOKI_NOT_INITIALIZED; goto ret; } TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); rv = CKR_FUNCTION_NOT_SUPPORTED; ret: return rv; } CK_RV C_UnwrapKeyAuthenticated(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_BYTE_PTR pAssociatedData, CK_ULONG ulAssociatedDataLen, CK_OBJECT_HANDLE_PTR phKey) { CK_RV rv; UNUSED(hSession); UNUSED(pMechanism); UNUSED(hUnwrappingKey); UNUSED(pWrappedKey); UNUSED(ulWrappedKeyLen); UNUSED(pTemplate); UNUSED(ulAttributeCount); UNUSED(pAssociatedData); UNUSED(ulAssociatedDataLen); UNUSED(phKey); TRACE_INFO("C_UnwrapKeyAuthenticated\n"); if (API_Initialized() == FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); rv = CKR_CRYPTOKI_NOT_INITIALIZED; goto ret; } TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); rv = CKR_FUNCTION_NOT_SUPPORTED; ret: return rv; } CK_RV C_IBM_ReencryptSingle(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pDecrMech, CK_OBJECT_HANDLE hDecrKey, CK_MECHANISM_PTR pEncrMech, CK_OBJECT_HANDLE hEncrKey, CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen, CK_BYTE_PTR pReencryptedData, CK_ULONG_PTR pulReencryptedDataLen) { CK_RV rv; API_Slot_t *sltp; STDLL_FcnList_t *fcn; ST_SESSION_T rSession; TRACE_INFO("C_IBM_ReencryptSingle\n"); if (API_Initialized() == FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); return CKR_CRYPTOKI_NOT_INITIALIZED; } if (!pDecrMech || !pEncrMech) { 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_IBM_ReencryptSingle) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_IBM_ReencryptSingle(sltp->TokData, &rSession, pDecrMech, hDecrKey, pEncrMech, hEncrKey, pEncryptedData, ulEncryptedDataLen, pReencryptedData, pulReencryptedDataLen); TRACE_DEVEL("fcn->ST_IBM_ReencryptSingle returned: 0x%lx\n", rv); END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); rv = CKR_FUNCTION_NOT_SUPPORTED; } return rv; } #if defined(__sun) || defined(_AIX) #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(parent_fork_prepare, parent_fork_after, child_fork_initializer); Initialized = 1; } } #if defined(__sun) || defined(_AIX) #pragma fini(api_fini) #else void api_fini(void) __attribute__ ((destructor)); #endif void api_fini(void) { if (API_Initialized() == TRUE) { in_destructor = TRUE; Call_Finalize(); } #if defined(_AIX) /* * Linux automatically unregisters any atexit handlers that are registered * from within a library when the library is unloaded, while AIX expects * the library to tidy up after itself. So we need to unregister the * handler explicitly when the destructor is called to prevent segfaults. * * Ignore the return code because the outcome is the same - either it was * registered, and it was successfully removed; Or it was never registered, * in which case the unregister call will fail (and that's okay too). * * This function is not defined by POSIX. */ (void)unatexit(Call_Finalize); #endif } opencryptoki-opencryptoki-451d99c/usr/lib/api/apiproto.h000066400000000000000000000032531520105705100234650ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2001-2021 * * 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" #include "policy.h" #include "statistics.h" void *attach_shared_memory(void); void detach_shared_memory(char *); int API_Initialized(void); int API_Register(void); void API_UnRegister(void); int DL_Load_and_Init(API_Slot_t *, CK_SLOT_ID, policy_t policy, statistics_t statistics); CK_RV CreateProcLock(void); CK_RV ProcLock(void); CK_RV ProcUnLock(void); CK_RV ProcClose(void); void _init(void); void get_sess_counts(CK_SLOT_ID, CK_ULONG *, CK_ULONG *); void incr_sess_counts(CK_SLOT_ID, CK_BBOOL rw_session); void decr_sess_counts(CK_SLOT_ID, CK_BBOOL rw_session); 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, CK_BBOOL inchildforkinit); void DL_Unload(API_Slot_t *); CK_RV check_user_and_group(const char *group); 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 connect_socket(const char *file_path); int init_socket_data(int socketfd); int start_event_thread(void); int stop_event_thread(void); #endif opencryptoki-opencryptoki-451d99c/usr/lib/api/apiutil.c000066400000000000000000000556671520105705100233120ustar00rootroot00000000000000/* * 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 #include #include static int xplfd = -1; pthread_rwlock_t xplfd_rwlock = PTHREAD_RWLOCK_INITIALIZER; #include #define LIBLOCATION LIB_PATH #if defined(_AIX) /* GNU extension, provides a replacement */ void populate_progname(void); extern char *program_invocation_short_name; #define SO_LDFLAGS (RTLD_LOCAL | RTLD_LAZY | RTLD_MEMBER) #else #define SO_LDFLAGS (RTLD_LOCAL | RTLD_LAZY) #endif extern API_Proc_Struct_t *Anchor; #include #include "trace.h" #include "ock_syslog.h" #include "platform.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, OPEN_MODE); if (xplfd == -1) { OCK_SYSLOG(LOG_ERR, "C_Initialize: Could not open '%s': %s. " "Possible reasons are that pkcsslotd is not running, " "or that the current user '%s' is not in the '%s' " "group.\n", OCK_API_LOCK_FILE, strerror(errno), cuserid(NULL), PKCS_GROUP); 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; BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) rv = fcn->ST_CloseSession(sltp->TokData, s, closeme_arg->in_fork_initializer); END_HSM_MK_CHANGE_LOCK(sltp, rv) if (rv == CKR_OK) { decr_sess_counts(closeme_arg->slot_id, s->rw_session); bt_node_free(&(Anchor->sess_btree), node_handle, TRUE); } } } /* 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; rSession->rw_session = tmp->rw_session; } rc = tmp ? TRUE : FALSE; bt_put_node_value(&(Anchor->sess_btree), tmp); tmp = NULL; return rc; } int API_Initialized(void) { 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_counts(CK_SLOT_ID slotID, CK_ULONG *ret, CK_ULONG *rw_ret) { Slot_Mgr_Shr_t *shm; shm = Anchor->SharedMemP; ProcLock(); *ret = shm->slot_global_sessions[slotID]; *rw_ret = shm->slot_global_rw_sessions[slotID]; ProcUnLock(); } void incr_sess_counts(CK_SLOT_ID slotID, CK_BBOOL rw_session) { 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]++; if (rw_session) shm->slot_global_rw_sessions[slotID]++; procp = &shm->proc_table[Anchor->MgrProcIndex]; procp->slot_session_count[slotID]++; if (rw_session) procp->slot_rw_session_count[slotID]++; ProcUnLock(); } void decr_sess_counts(CK_SLOT_ID slotID, CK_BBOOL rw_session) { 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]--; } if (rw_session && shm->slot_global_rw_sessions[slotID] > 0) { shm->slot_global_rw_sessions[slotID]--; } procp = &shm->proc_table[Anchor->MgrProcIndex]; if (procp->slot_session_count[slotID] > 0) { procp->slot_session_count[slotID]--; } if (rw_session && procp->slot_rw_session_count[slotID] > 0) { procp->slot_rw_session_count[slotID]--; } ProcUnLock(); } uint32_t get_tokspec_count(STDLL_TokData_t *tokdata) { Slot_Mgr_Shr_t *shm; uint32_t ret; shm = Anchor->SharedMemP; if (ProcLock() != CKR_OK) return 0; ret = shm->slot_global_tokspec_count[tokdata->slot_id]; ProcUnLock(); return ret; } void incr_tokspec_count(STDLL_TokData_t *tokdata) { 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_tokspec_count[tokdata->slot_id]++; procp = &shm->proc_table[Anchor->MgrProcIndex]; procp->slot_tokspec_count[tokdata->slot_id]++; ProcUnLock(); } void decr_tokspec_count(STDLL_TokData_t *tokdata) { 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_tokspec_count[tokdata->slot_id] > 0) shm->slot_global_tokspec_count[tokdata->slot_id]--; procp = &shm->proc_table[Anchor->MgrProcIndex]; if (procp->slot_tokspec_count[tokdata->slot_id] > 0) procp->slot_tokspec_count[tokdata->slot_id]--; 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(void) { 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; #if defined(_AIX) /* populate program_invocation_short_name for later use */ populate_progname(); #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; 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 == Anchor->ClientCred.real_pid) { 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 = Anchor->ClientCred.real_pid; procp->reg_time = time(NULL); Anchor->MgrProcIndex = indx; TRACE_DEVEL("API_Register MgrProcIndc %ld (real) pid %d \n", (long int) Anchor->MgrProcIndex, procp->proc_id); //??? 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(void) { 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, CK_BBOOL inchildforkinit) { Slot_Mgr_Socket_t *shData = &(Anchor->SocketDataP); #ifdef PKCS64 Slot_Info_t_64 *sinfp; #else Slot_Info_t *sinfp; #endif if (sltp->TokData) { pthread_rwlock_destroy(&sltp->TokData->sess_list_rwlock); pthread_mutex_destroy(&sltp->TokData->login_mutex); if (sltp->TokData->hsm_mk_change_supported) pthread_rwlock_destroy(&sltp->TokData->hsm_mk_change_rwlock); free(sltp->TokData); sltp->TokData = NULL; } sinfp = &(shData->slot_info[slotID]); if (sinfp->present == FALSE) { return; } if (!sltp->dlop_p) { return; } if (inchildforkinit) 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, SO_LDFLAGS); 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) { #ifndef WITH_SANITIZER dlclose(dllload->dlop_p); #endif dllload->dll_name = NULL; } // Clear out the slot information sltp->DLLoaded = FALSE; sltp->dlop_p = NULL; sltp->pSTfini = NULL; sltp->pSTcloseall = NULL; } CK_RV check_user_and_group(const char *group) { int i; uid_t euid; struct passwd *epw; struct group *grp; if (group == NULL || group[0] == '\0') group = PKCS_GROUP; /* * Check for root user or Group PKCS#11 Membership. * Only these are allowed. */ euid = geteuid(); /* effective Root is ok */ if (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(group); if (grp == NULL) { OCK_SYSLOG(LOG_ERR, "C_Initialize: Group '%s' does not exists\n", group); goto error; } if (getegid() == grp->gr_gid) return CKR_OK; /* Check if effective user is member of the group */ epw = getpwuid(euid); for (i = 0; grp->gr_mem[i]; i++) { if ((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; } int DL_Load_and_Init(API_Slot_t *sltp, CK_SLOT_ID slotID, policy_t policy, statistics_t statistics) { 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 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 (sltp->TokData != NULL) { TRACE_ERROR("Already initialized.\n"); return FALSE; } if (check_user_and_group(sinfp->usergroup) != CKR_OK) { TRACE_DEVEL("check_user_and_group failed for slot %lu, token will not " "be available.\n", slotID); /* Issue warning message if running in pkcshsm_mk_change tool */ if (strcmp(program_invocation_short_name, "pkcshsm_mk_change") == 0 && sinfp->usergroup[0] != '\0') { warnx("The current user '%s' is not a member of group '%s' used by " "slot %lu.", cuserid(NULL), sinfp->usergroup, slotID); warnx("The token in slot %lu will not be available!", slotID); } return FALSE; } /* * 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 FALSE; } sltp->TokData->slot_id = slotID; sltp->TokData->real_pid = Anchor->ClientCred.real_pid; sltp->TokData->real_uid = Anchor->ClientCred.real_uid; sltp->TokData->real_gid = Anchor->ClientCred.real_gid; strncpy(sltp->TokData->tokgroup, sinfp->usergroup, sizeof(sltp->TokData->tokgroup) - 1); sltp->TokData->tokgroup[sizeof(sltp->TokData->tokgroup) - 1] = '\0'; sltp->TokData->tokspec_counter.get_tokspec_count = get_tokspec_count; sltp->TokData->tokspec_counter.incr_tokspec_count = incr_tokspec_count; sltp->TokData->tokspec_counter.decr_tokspec_count = decr_tokspec_count; sltp->TokData->ro_session_count = 0; sltp->TokData->global_login_state = CKS_RO_PUBLIC_SESSION; sltp->TokData->spinxplfd = -1; sltp->TokData->spinxplfd_count = 0; if (pthread_rwlock_init(&sltp->TokData->sess_list_rwlock, NULL) != 0) { TRACE_ERROR("Initializing session list lock failed.\n"); free(sltp->TokData); sltp->TokData = NULL; return FALSE; } if (pthread_mutex_init(&sltp->TokData->login_mutex, NULL) != 0) { TRACE_ERROR("Initializing login mutex failed.\n"); free(sltp->TokData); sltp->TokData = NULL; return FALSE; } sltp->TokData->policy = policy; sltp->TokData->mechtable_funcs = &mechtable_funcs; sltp->TokData->statistics = statistics; if (strlen(sinfp->dll_location) > 0) { // 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 { free(sltp->TokData); sltp->TokData = NULL; return FALSE; } if (!sltp->dlop_p) { TRACE_DEBUG("DL_Load_and_Init pointer NULL\n"); DL_UnLoad(sltp, slotID, FALSE); return FALSE; } *(void **)(&pSTinit) = dlsym(sltp->dlop_p, "ST_Initialize"); if (!pSTinit) { // Unload the DLL DL_UnLoad(sltp, slotID, FALSE); 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, slotID, FALSE); sltp->DLLoaded = FALSE; return FALSE; } else { sltp->DLLoaded = TRUE; sinfp->pk_slot.flags |= CKF_TOKEN_PRESENT; // 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; } opencryptoki-opencryptoki-451d99c/usr/lib/api/hashmap.c000066400000000000000000000161301520105705100232420ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021 * * 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 "hashmap.h" /* * Hash map for mechanisms. It stores the mechanism number in a * linked hash map. Note that it does not directly store the * mechanism number, but the mechanism number plus one. This is done * to have 0 represent an empty bucket. The structure is optimized * for the non-chaining case in which case the value is directly * stored in the root of the bucket chain. Only further chain * elements are allocated separately. * * Furthermore, we use a size optimization to not pre-allocate buckets * when creating a new hash. Only on first addition to the hash do we * create the bucket list. * * The hash is a power of 2 hash to speed up hash value computation * (subtraction + binary and versus modulo computation). */ /* Default hash size has to be a power of 2. */ #define HASH_DEFAULT_CAPA 16 static unsigned int hash(unsigned int capa, CK_ULONG value) { #ifdef HASHMAP_FULL_JENKINS /* Full Jenkins hash */ unsigned char *key = (unsigned char *)&value; size_t i = 0; unsigned int hash = 0; while (i != 8) { hash += key[i++]; hash += hash << 10; hash ^= hash >> 6; } hash += hash << 3; hash ^= hash >> 11; hash += hash << 15; return hash & (capa - 1); #else # ifdef HASHMAP_JENKINS_MIX /* Jenkins hash mix function */ value += value << 3; value ^= value >> 11; value += value << 15; # endif return value & (capa - 1); #endif } struct hashmap_bucket; struct hashmap_bucket { CK_ULONG key; union hashmap_value value; struct hashmap_bucket *next; }; struct hashmap { struct hashmap_bucket *buckets; unsigned int size; unsigned int capa; freefunc_t freefunc; }; /* Create size-optimized empty hash. First add will expand the hash to its * default capacity. */ struct hashmap *hashmap_new(void) { struct hashmap *res = malloc(sizeof(struct hashmap)); if (!res) return res; res->buckets = NULL; res->size = 0; res->capa = 0; return res; } static void freebucketchain(struct hashmap_bucket *b, freefunc_t f) { struct hashmap_bucket *n; while (b) { n = b->next; if (f) f(b->value); free(b); b = n; } } static void freebuckets(struct hashmap_bucket *buckets, unsigned int size, freefunc_t f) { unsigned int i; for (i = 0; i < size; ++i) freebucketchain(buckets[i].next, f); } void hashmap_free(struct hashmap *h, freefunc_t f) { if (h) { if (h->buckets) { freebuckets(h->buckets, h->capa, f); free(h->buckets); } free(h); } } static int do_add(struct hashmap_bucket *buckets, unsigned int size, CK_ULONG key, union hashmap_value val) { unsigned int hval; struct hashmap_bucket *newbucket; hval = hash(size, key); if (buckets[hval].key) { newbucket = malloc(sizeof(struct hashmap_bucket)); if (!newbucket) return 1; newbucket->next = buckets[hval].next; newbucket->key = key; newbucket->value = val; buckets[hval].next = newbucket; } else { buckets[hval].key = key; buckets[hval].value = val; } return 0; } static int grow(struct hashmap *h) { unsigned int i; unsigned int newcapa; struct hashmap_bucket *newarr, *walk; newcapa = h->capa ? h->capa << 1 : HASH_DEFAULT_CAPA; if (newcapa < h->capa) return 1; newarr = calloc(newcapa, sizeof(struct hashmap_bucket)); if (!newarr) return 1; for (i = 0; i < h->capa; ++i) { if (h->buckets[i].key) { walk = &h->buckets[i]; while (walk) { if (do_add(newarr, newcapa, walk->key, walk->value)) { /* Pass no free function here since the values are still in the old hash buckets that remain in the hash. */ freebuckets(newarr, newcapa, NULL); free(newarr); return 1; } walk = walk->next; } } } if (h->buckets) { /* Pass no free function here since we copied the values into the new bucket array. */ freebuckets(h->buckets, h->capa, NULL); free(h->buckets); } h->buckets = newarr; h->capa = newcapa; return 0; } static struct hashmap_bucket *hashmap_findbucket(struct hashmap *h, CK_ULONG key) { unsigned int hval; struct hashmap_bucket *b = NULL; if (h->buckets) { hval = hash(h->capa, key + 1); b = &h->buckets[hval]; while (b && b->key != key + 1) b = b->next; } return b; } int hashmap_find(struct hashmap *h, CK_ULONG key, union hashmap_value *val) { struct hashmap_bucket *b = 0; if (!h) /* The non-existing hash is universal. */ return 1; b = hashmap_findbucket(h, key); if (b && val) *val = b->value; return !!b; } int hashmap_add(struct hashmap *h, CK_ULONG key, union hashmap_value val, union hashmap_value *oldval) { struct hashmap_bucket *b; b = hashmap_findbucket(h, key); if (b) { if (oldval) *oldval = b->value; b->value = val; return 0; } /* 0.75 fill factor */ if (h->capa - (h->capa / 4) < h->size + 1) { if (grow(h)) return 1; } if (do_add(h->buckets, h->capa, key + 1, val)) return 1; h->size++; return 0; } int hashmap_delete(struct hashmap *h, CK_ULONG key, union hashmap_value *val) { int retval = 0; unsigned int hval; struct hashmap_bucket *b, **indirect; if (h->buckets) { hval = hash(h->capa, key + 1); if (h->buckets[hval].key == key + 1) { if (val) *val = h->buckets[hval].value; if ((b = h->buckets[hval].next) != NULL) { h->buckets[hval].key = b->key; h->buckets[hval].value = b->value; h->buckets[hval].next = b->next; free(b); } else { h->buckets[hval].key = 0; } retval = 1; } else { b = h->buckets[hval].next; indirect = &h->buckets[hval].next; while (b && b->key != key + 1) { indirect = &b->next; b = b->next; } if (b) { if (val) *val = b->value; *indirect = b->next; free(b); retval = 1; } } } h->size -= retval; return retval; } opencryptoki-opencryptoki-451d99c/usr/lib/api/hashmap.h000066400000000000000000000016721520105705100232540ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021 * * 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_HASHMAP_H #define OCK_HASHMAP_H #include struct hashmap; union hashmap_value { CK_ULONG ulVal; void *pVal; }; typedef void (*freefunc_t)(union hashmap_value); struct hashmap *hashmap_new(void); void hashmap_free(struct hashmap *h, freefunc_t f); int hashmap_find(struct hashmap *h, CK_ULONG key, union hashmap_value *val); int hashmap_add(struct hashmap *h, CK_ULONG key, union hashmap_value val, union hashmap_value *oldval); int hashmap_delete(struct hashmap *h, CK_ULONG key, union hashmap_value *val); #endif opencryptoki-opencryptoki-451d99c/usr/lib/api/mechtable.h000066400000000000000000000055061520105705100235570ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021 * * 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_MECHTABLE_H #define OCK_MECHTABLE_H #include #include /* This include can only be done once the file is generated. Since the generator itself includes the current header file before generating mechtable-gen.h, we have to guard the include. */ #ifndef MECHTABLE_IN_GEN # include "mechtable-gen.h" #endif /* block size or output size not available */ #define MC_INFORMATION_UNAVAILABLE 0xffffu /* output size depends on key*/ #define MC_KEY_DEPENDENT 0xfffeu /*** Flags ***/ #define MCF_DIGEST (1u << 0u) #define MCF_SIGNVERIFY (1u << 1u) #define MCF_ENCRYPTDECRYPT (1u << 2u) #define MCF_KEYGEN (1u << 3u) #define MCF_WRAPUNWRAP (1u << 4u) #define MCF_DERIVE (1u << 5u) #define MCF_ENDECAPS (1u << 6u) #define MCF_NEEDSPARAM (1u << 8u) #define MCF_OPTIONALPARAM (1u << 9u) #define MCF_MAC_GENERAL (1u << 10u) struct mechrow { const char * string; CK_MECHANISM_TYPE numeric; uint16_t blocksize; /* the maximum size of general macs */ uint16_t outputsize; uint32_t flags; }; struct mechtable_funcs { int (*p_idx_from_num)(CK_ULONG mech); int (*p_idx_from_str)(const char *mech); const struct mechrow *(*p_row_from_num)(CK_ULONG mech); const struct mechrow *(*p_row_from_str)(const char *mech); }; extern const struct mechtable_funcs mechtable_funcs; /* The table. It has exactly MECHTABLE_NUM_ELEMS elements. The constant is in the generated header mechtable-gen.h which is included by this header. */ extern const struct mechrow mechtable_rows[]; /*** Index functions ***/ /* Locate a table row by numeric value of the mechanism. Returns -1 if the name is invalid. */ int mechtable_idx_from_numeric(CK_ULONG mech); /* Locate a table row by a string key. This respects aliases, so the row at the returned index might have a different string representation if the name changed in the meantime. Returns -1 if the name is invalid. */ int mechtable_idx_from_string(const char *mech); /* Translate a mechanism number into a mechanism column. Returns NULL if the mechanism number is not known to the table. */ const struct mechrow *mechrow_from_numeric(CK_ULONG mech); /* Translate a mechanism name into a mechanism column. Returns NULL if the mechanism name is not known to the table. */ const struct mechrow *mechrow_from_string(const char *mech); #endif opencryptoki-opencryptoki-451d99c/usr/lib/api/mechtable.inc000066400000000000000000000642711520105705100241050ustar00rootroot00000000000000/* -*- mode: C -*- */ /* * COPYRIGHT (c) International Business Machines Corp. 2021 * * 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 table will be included in the generated table index file to provide the global data. Since the inclusion happens at top level, keep the table constant. Order of the table elements matters as the order in this table reflects the index returned by the index search functions. The numeric value has to be unique (the string value also has to be unique, but that is easier to ensure). If you need to map multiple strings to the same numeric value (e.g., for EC_KEY_GEN and ECDSA_KEY_GEN), the update the aliaslist in the tableidxgen.c generator source. Feel free to add new rows or columns. The generator only cares about the columns "string" and "numeric". Everything else is ignored by the generator and simply included in the generated C file. */ const struct mechrow mechtable_rows[] = { /* string, numeric, blocksize, outputsize, flags */ { "CKM_AES_CBC", CKM_AES_CBC, 16, MC_INFORMATION_UNAVAILABLE, MCF_ENCRYPTDECRYPT | MCF_WRAPUNWRAP | MCF_NEEDSPARAM }, { "CKM_AES_CBC_PAD", CKM_AES_CBC_PAD, 16, MC_INFORMATION_UNAVAILABLE, MCF_ENCRYPTDECRYPT | MCF_WRAPUNWRAP | MCF_NEEDSPARAM }, { "CKM_AES_CFB128", CKM_AES_CFB128, 16, MC_INFORMATION_UNAVAILABLE, MCF_ENCRYPTDECRYPT | MCF_NEEDSPARAM }, { "CKM_AES_CFB64", CKM_AES_CFB64, 16, MC_INFORMATION_UNAVAILABLE, MCF_ENCRYPTDECRYPT | MCF_NEEDSPARAM }, { "CKM_AES_CFB8", CKM_AES_CFB8, 16, MC_INFORMATION_UNAVAILABLE, MCF_ENCRYPTDECRYPT | MCF_NEEDSPARAM }, { "CKM_AES_CMAC", CKM_AES_CMAC, 16, 16, MCF_SIGNVERIFY }, { "CKM_AES_CMAC_GENERAL", CKM_AES_CMAC_GENERAL, 16, 16, MCF_SIGNVERIFY | MCF_MAC_GENERAL | MCF_NEEDSPARAM }, { "CKM_AES_CTR", CKM_AES_CTR, 16, MC_INFORMATION_UNAVAILABLE, MCF_ENCRYPTDECRYPT | MCF_WRAPUNWRAP | MCF_NEEDSPARAM }, { "CKM_AES_ECB", CKM_AES_ECB, 16, MC_INFORMATION_UNAVAILABLE, MCF_ENCRYPTDECRYPT | MCF_WRAPUNWRAP }, { "CKM_AES_GCM", CKM_AES_GCM, 16, MC_INFORMATION_UNAVAILABLE, MCF_ENCRYPTDECRYPT | MCF_WRAPUNWRAP | MCF_NEEDSPARAM }, { "CKM_AES_KEY_GEN", CKM_AES_KEY_GEN, 0, MC_INFORMATION_UNAVAILABLE, MCF_KEYGEN }, { "CKM_AES_KEY_WRAP", CKM_AES_KEY_WRAP, 8, MC_INFORMATION_UNAVAILABLE, MCF_ENCRYPTDECRYPT | MCF_WRAPUNWRAP | MCF_OPTIONALPARAM }, { "CKM_AES_KEY_WRAP_PAD", CKM_AES_KEY_WRAP_PAD, 8, MC_INFORMATION_UNAVAILABLE, MCF_ENCRYPTDECRYPT | MCF_WRAPUNWRAP | MCF_OPTIONALPARAM }, { "CKM_AES_KEY_WRAP_KWP", CKM_AES_KEY_WRAP_KWP, 8, MC_INFORMATION_UNAVAILABLE, MCF_ENCRYPTDECRYPT | MCF_WRAPUNWRAP | MCF_OPTIONALPARAM }, { "CKM_AES_KEY_WRAP_PKCS7", CKM_AES_KEY_WRAP_PKCS7, 8, MC_INFORMATION_UNAVAILABLE, MCF_ENCRYPTDECRYPT | MCF_WRAPUNWRAP | MCF_OPTIONALPARAM }, { "CKM_AES_XTS_KEY_GEN", CKM_AES_XTS_KEY_GEN, 0, MC_INFORMATION_UNAVAILABLE, MCF_KEYGEN }, { "CKM_AES_XTS", CKM_AES_XTS, 16, MC_INFORMATION_UNAVAILABLE, MCF_ENCRYPTDECRYPT }, { "CKM_AES_MAC", CKM_AES_MAC, 16, 8, MCF_SIGNVERIFY }, { "CKM_AES_MAC_GENERAL", CKM_AES_MAC_GENERAL, 16, 16, MCF_SIGNVERIFY | MCF_NEEDSPARAM | MCF_MAC_GENERAL }, { "CKM_AES_OFB", CKM_AES_OFB, 16, MC_INFORMATION_UNAVAILABLE, MCF_ENCRYPTDECRYPT | MCF_WRAPUNWRAP | MCF_NEEDSPARAM }, { "CKM_DES2_KEY_GEN", CKM_DES2_KEY_GEN, 0, MC_INFORMATION_UNAVAILABLE, MCF_KEYGEN }, { "CKM_DES3_CBC", CKM_DES3_CBC, 8, MC_INFORMATION_UNAVAILABLE, MCF_ENCRYPTDECRYPT | MCF_WRAPUNWRAP | MCF_NEEDSPARAM }, { "CKM_DES3_CBC_PAD", CKM_DES3_CBC_PAD, 8, MC_INFORMATION_UNAVAILABLE, MCF_ENCRYPTDECRYPT | MCF_WRAPUNWRAP | MCF_NEEDSPARAM }, { "CKM_DES3_CMAC", CKM_DES3_CMAC, 8, 8, MCF_SIGNVERIFY }, { "CKM_DES3_CMAC_GENERAL", CKM_DES3_CMAC_GENERAL, 8, 8, MCF_SIGNVERIFY | MCF_NEEDSPARAM | MCF_MAC_GENERAL }, { "CKM_DES3_ECB", CKM_DES3_ECB, 8, MC_INFORMATION_UNAVAILABLE, MCF_ENCRYPTDECRYPT | MCF_WRAPUNWRAP }, { "CKM_DES3_KEY_GEN", CKM_DES3_KEY_GEN, 0, MC_INFORMATION_UNAVAILABLE, MCF_KEYGEN }, { "CKM_DES3_MAC", CKM_DES3_MAC, 8, 4, MCF_SIGNVERIFY }, { "CKM_DES3_MAC_GENERAL", CKM_DES3_MAC_GENERAL, 8, 8, MCF_SIGNVERIFY | MCF_NEEDSPARAM | MCF_MAC_GENERAL }, { "CKM_DES_CBC", CKM_DES_CBC, 8, MC_INFORMATION_UNAVAILABLE, MCF_ENCRYPTDECRYPT | MCF_WRAPUNWRAP | MCF_NEEDSPARAM }, { "CKM_DES_CBC_PAD", CKM_DES_CBC_PAD, 8, MC_INFORMATION_UNAVAILABLE, MCF_ENCRYPTDECRYPT | MCF_WRAPUNWRAP | MCF_NEEDSPARAM }, { "CKM_DES_CFB64", CKM_DES_CFB64, 8, MC_INFORMATION_UNAVAILABLE, MCF_ENCRYPTDECRYPT | MCF_NEEDSPARAM }, { "CKM_DES_CFB8", CKM_DES_CFB8, 8, MC_INFORMATION_UNAVAILABLE, MCF_ENCRYPTDECRYPT | MCF_NEEDSPARAM }, { "CKM_DES_ECB", CKM_DES_ECB, 8, MC_INFORMATION_UNAVAILABLE, MCF_ENCRYPTDECRYPT | MCF_WRAPUNWRAP }, { "CKM_DES_KEY_GEN", CKM_DES_KEY_GEN, 0, MC_INFORMATION_UNAVAILABLE, MCF_KEYGEN }, { "CKM_DES_OFB64", CKM_DES_OFB64, 8, MC_INFORMATION_UNAVAILABLE, MCF_ENCRYPTDECRYPT | MCF_WRAPUNWRAP | MCF_NEEDSPARAM }, { "CKM_DH_PKCS_DERIVE", CKM_DH_PKCS_DERIVE, 0, MC_INFORMATION_UNAVAILABLE, MCF_DERIVE | MCF_ENDECAPS | MCF_NEEDSPARAM }, { "CKM_DH_PKCS_KEY_PAIR_GEN", CKM_DH_PKCS_KEY_PAIR_GEN, 0, MC_INFORMATION_UNAVAILABLE, MCF_KEYGEN }, { "CKM_DH_PKCS_PARAMETER_GEN", CKM_DH_PKCS_PARAMETER_GEN, 0, MC_INFORMATION_UNAVAILABLE, MCF_KEYGEN }, { "CKM_DSA", CKM_DSA, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY }, { "CKM_DSA_KEY_PAIR_GEN", CKM_DSA_KEY_PAIR_GEN, 0, MC_INFORMATION_UNAVAILABLE, MCF_KEYGEN }, { "CKM_DSA_PARAMETER_GEN", CKM_DSA_PARAMETER_GEN, 0, MC_INFORMATION_UNAVAILABLE, MCF_KEYGEN }, { "CKM_DSA_SHA1", CKM_DSA_SHA1, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY }, { "CKM_ECDH1_COFACTOR_DERIVE", CKM_ECDH1_COFACTOR_DERIVE, 0, MC_INFORMATION_UNAVAILABLE, MCF_DERIVE | MCF_ENDECAPS | MCF_NEEDSPARAM }, { "CKM_ECDH1_DERIVE", CKM_ECDH1_DERIVE, 0, MC_INFORMATION_UNAVAILABLE, MCF_DERIVE | MCF_ENDECAPS | MCF_NEEDSPARAM }, { "CKM_ECDH_AES_KEY_WRAP", CKM_ECDH_AES_KEY_WRAP, 0, MC_KEY_DEPENDENT, MCF_WRAPUNWRAP | MCF_NEEDSPARAM }, { "CKM_ECDH_COF_AES_KEY_WRAP", CKM_ECDH_COF_AES_KEY_WRAP, 0, MC_KEY_DEPENDENT, MCF_WRAPUNWRAP | MCF_NEEDSPARAM }, { "CKM_ECDH_X_AES_KEY_WRAP", CKM_ECDH_X_AES_KEY_WRAP, 0, MC_KEY_DEPENDENT, MCF_WRAPUNWRAP | MCF_NEEDSPARAM}, { "CKM_ECDSA", CKM_ECDSA, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY }, { "CKM_ECDSA_SHA1", CKM_ECDSA_SHA1, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY }, { "CKM_ECDSA_SHA224", CKM_ECDSA_SHA224, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY }, { "CKM_ECDSA_SHA256", CKM_ECDSA_SHA256, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY }, { "CKM_ECDSA_SHA384", CKM_ECDSA_SHA384, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY }, { "CKM_ECDSA_SHA3_224", CKM_ECDSA_SHA3_224, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY }, { "CKM_ECDSA_SHA3_256", CKM_ECDSA_SHA3_256, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY }, { "CKM_ECDSA_SHA3_384", CKM_ECDSA_SHA3_384, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY }, { "CKM_ECDSA_SHA3_512", CKM_ECDSA_SHA3_512, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY }, { "CKM_ECDSA_SHA512", CKM_ECDSA_SHA512, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY }, { "CKM_EC_EDWARDS_KEY_PAIR_GEN", CKM_EC_EDWARDS_KEY_PAIR_GEN, 0, MC_INFORMATION_UNAVAILABLE, MCF_KEYGEN }, { "CKM_EC_MONTGOMERY_KEY_PAIR_GEN", CKM_EC_MONTGOMERY_KEY_PAIR_GEN, 0, MC_INFORMATION_UNAVAILABLE, MCF_KEYGEN }, { "CKM_EC_KEY_PAIR_GEN", CKM_EC_KEY_PAIR_GEN, 0, MC_INFORMATION_UNAVAILABLE, MCF_KEYGEN }, { "CKM_EDDSA", CKM_EDDSA, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY }, { "CKM_GENERIC_SECRET_KEY_GEN", CKM_GENERIC_SECRET_KEY_GEN, 0, MC_INFORMATION_UNAVAILABLE, MCF_KEYGEN }, { "CKM_HASH_ML_DSA", CKM_HASH_ML_DSA, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY | MCF_NEEDSPARAM }, { "CKM_HASH_ML_DSA_SHA224", CKM_HASH_ML_DSA_SHA224, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY }, { "CKM_HASH_ML_DSA_SHA256", CKM_HASH_ML_DSA_SHA256, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY }, { "CKM_HASH_ML_DSA_SHA384", CKM_HASH_ML_DSA_SHA384, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY }, { "CKM_HASH_ML_DSA_SHA3_224", CKM_HASH_ML_DSA_SHA3_224, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY }, { "CKM_HASH_ML_DSA_SHA3_256", CKM_HASH_ML_DSA_SHA3_256, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY }, { "CKM_HASH_ML_DSA_SHA3_384", CKM_HASH_ML_DSA_SHA3_384, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY }, { "CKM_HASH_ML_DSA_SHA3_512", CKM_HASH_ML_DSA_SHA3_512, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY }, { "CKM_HASH_ML_DSA_SHA512", CKM_HASH_ML_DSA_SHA512, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY }, { "CKM_HASH_ML_DSA_SHAKE128", CKM_HASH_ML_DSA_SHAKE128, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY }, { "CKM_HASH_ML_DSA_SHAKE256", CKM_HASH_ML_DSA_SHAKE256, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY }, { "CKM_IBM_ATTRIBUTEBOUND_WRAP", CKM_IBM_ATTRIBUTEBOUND_WRAP, 0, MC_INFORMATION_UNAVAILABLE, MCF_WRAPUNWRAP | MCF_NEEDSPARAM }, { "CKM_IBM_BTC_DERIVE", CKM_IBM_BTC_DERIVE, 0, MC_INFORMATION_UNAVAILABLE, MCF_DERIVE | MCF_NEEDSPARAM }, { "CKM_IBM_CMAC", CKM_IBM_CMAC, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY }, { "CKM_IBM_DILITHIUM", CKM_IBM_DILITHIUM, 0, MC_KEY_DEPENDENT, MCF_KEYGEN | MCF_SIGNVERIFY }, { "CKM_IBM_ECDSA_OTHER", CKM_IBM_ECDSA_OTHER, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY | MCF_NEEDSPARAM }, { "CKM_IBM_EC_AGGREGATE", CKM_IBM_EC_AGGREGATE, 0, 192, MCF_SIGNVERIFY | MCF_DERIVE | MCF_NEEDSPARAM }, { "CKM_IBM_EC_X25519", CKM_IBM_EC_X25519, 0, MC_INFORMATION_UNAVAILABLE, MCF_DERIVE }, { "CKM_IBM_EC_X448", CKM_IBM_EC_X448, 0, MC_INFORMATION_UNAVAILABLE, MCF_DERIVE }, { "CKM_IBM_ED25519_SHA512", CKM_IBM_ED25519_SHA512, 128, MC_KEY_DEPENDENT, MCF_SIGNVERIFY }, { "CKM_IBM_ED448_SHA3", CKM_IBM_ED448_SHA3, 144, MC_KEY_DEPENDENT, MCF_SIGNVERIFY }, { "CKM_IBM_KYBER", CKM_IBM_KYBER, 0, MC_KEY_DEPENDENT, MCF_KEYGEN | MCF_ENCRYPTDECRYPT | MCF_DERIVE | MCF_NEEDSPARAM}, { "CKM_IBM_ML_DSA", CKM_IBM_ML_DSA, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY }, { "CKM_IBM_ML_DSA_KEY_PAIR_GEN", CKM_IBM_ML_DSA_KEY_PAIR_GEN, 0, MC_KEY_DEPENDENT, MCF_KEYGEN }, { "CKM_IBM_ML_KEM", CKM_IBM_ML_KEM, 0, MC_KEY_DEPENDENT, MCF_DERIVE | MCF_NEEDSPARAM}, { "CKM_IBM_ML_KEM_KEY_PAIR_GEN", CKM_IBM_ML_KEM_KEY_PAIR_GEN, 0, MC_KEY_DEPENDENT, MCF_KEYGEN }, { "CKM_IBM_ML_KEM_WITH_ECDH", CKM_IBM_ML_KEM_WITH_ECDH, 0, MC_KEY_DEPENDENT, MCF_DERIVE | MCF_NEEDSPARAM}, { "CKM_IBM_SHA3_224", CKM_IBM_SHA3_224, 144, 28, MCF_DIGEST }, { "CKM_IBM_SHA3_224_HMAC", CKM_IBM_SHA3_224_HMAC, 144, 28, MCF_SIGNVERIFY }, { "CKM_IBM_SHA3_256", CKM_IBM_SHA3_256, 136, 32, MCF_DIGEST }, { "CKM_IBM_SHA3_256_HMAC", CKM_IBM_SHA3_256_HMAC, 136, 32, MCF_SIGNVERIFY }, { "CKM_IBM_SHA3_384", CKM_IBM_SHA3_384, 104, 48, MCF_DIGEST }, { "CKM_IBM_SHA3_384_HMAC", CKM_IBM_SHA3_384_HMAC, 104, 48, MCF_SIGNVERIFY }, { "CKM_IBM_SHA3_512", CKM_IBM_SHA3_512, 72, 64, MCF_DIGEST }, { "CKM_IBM_SHA3_512_HMAC", CKM_IBM_SHA3_512_HMAC, 72, 64, MCF_SIGNVERIFY }, { "CKM_MD5", CKM_MD5, 64, 16, MCF_DIGEST }, { "CKM_MD5_HMAC", CKM_MD5_HMAC, 64, 16, MCF_SIGNVERIFY }, { "CKM_MD5_HMAC_GENERAL", CKM_MD5_HMAC_GENERAL, 64, 16, MCF_SIGNVERIFY | MCF_NEEDSPARAM }, { "CKM_MD5_RSA_PKCS", CKM_MD5_RSA_PKCS, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY }, { "CKM_ML_DSA", CKM_ML_DSA, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY }, { "CKM_ML_DSA_KEY_PAIR_GEN", CKM_ML_DSA_KEY_PAIR_GEN, 0, MC_KEY_DEPENDENT, MCF_KEYGEN }, { "CKM_ML_KEM", CKM_ML_KEM, 0, MC_KEY_DEPENDENT, MCF_ENDECAPS }, { "CKM_ML_KEM_KEY_PAIR_GEN", CKM_ML_KEM_KEY_PAIR_GEN, 0, MC_KEY_DEPENDENT, MCF_KEYGEN }, { "CKM_PBE_SHA1_DES3_EDE_CBC", CKM_PBE_SHA1_DES3_EDE_CBC, 0, MC_INFORMATION_UNAVAILABLE, MCF_KEYGEN | MCF_NEEDSPARAM }, { "CKM_PUB_KEY_FROM_PRIV_KEY", CKM_PUB_KEY_FROM_PRIV_KEY, 0, MC_INFORMATION_UNAVAILABLE, MCF_DERIVE }, { "CKM_RSA_AES_KEY_WRAP", CKM_RSA_AES_KEY_WRAP, 0, MC_KEY_DEPENDENT, MCF_WRAPUNWRAP }, { "CKM_RSA_PKCS", CKM_RSA_PKCS, 0, MC_KEY_DEPENDENT, MCF_ENCRYPTDECRYPT | MCF_SIGNVERIFY | MCF_WRAPUNWRAP | MCF_ENDECAPS }, { "CKM_RSA_PKCS_KEY_PAIR_GEN", CKM_RSA_PKCS_KEY_PAIR_GEN, 0, MC_INFORMATION_UNAVAILABLE, MCF_KEYGEN }, { "CKM_RSA_PKCS_OAEP", CKM_RSA_PKCS_OAEP, 0, MC_KEY_DEPENDENT, MCF_ENCRYPTDECRYPT | MCF_WRAPUNWRAP | MCF_ENDECAPS | MCF_NEEDSPARAM }, { "CKM_RSA_PKCS_PSS", CKM_RSA_PKCS_PSS, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY | MCF_NEEDSPARAM }, { "CKM_RSA_X_509", CKM_RSA_X_509, 0, MC_KEY_DEPENDENT, MCF_ENCRYPTDECRYPT | MCF_SIGNVERIFY | MCF_WRAPUNWRAP }, { "CKM_RSA_X9_31", CKM_RSA_X9_31, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY }, { "CKM_RSA_X9_31_KEY_PAIR_GEN", CKM_RSA_X9_31_KEY_PAIR_GEN, 0, MC_INFORMATION_UNAVAILABLE, MCF_KEYGEN }, { "CKM_SHA_1", CKM_SHA_1, 64, 20, MCF_DIGEST }, { "CKM_SHA_1_HMAC", CKM_SHA_1_HMAC, 64, 20, MCF_SIGNVERIFY }, { "CKM_SHA_1_HMAC_GENERAL", CKM_SHA_1_HMAC_GENERAL, 64, 20, MCF_SIGNVERIFY | MCF_NEEDSPARAM | MCF_MAC_GENERAL }, { "CKM_SHA_1_KEY_GEN", CKM_SHA_1_KEY_GEN, 0, 20, MCF_KEYGEN }, { "CKM_SHA1_KEY_DERIVATION", CKM_SHA1_KEY_DERIVATION, 0, MC_INFORMATION_UNAVAILABLE, MCF_DERIVE }, { "CKM_SHA1_RSA_PKCS", CKM_SHA1_RSA_PKCS, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY }, { "CKM_SHA1_RSA_PKCS_PSS", CKM_SHA1_RSA_PKCS_PSS, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY | MCF_NEEDSPARAM }, { "CKM_SHA1_RSA_X9_31", CKM_SHA1_RSA_X9_31, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY }, { "CKM_SHA224", CKM_SHA224, 64, 28, MCF_DIGEST }, { "CKM_SHA224_HMAC", CKM_SHA224_HMAC, 64, 28, MCF_SIGNVERIFY }, { "CKM_SHA224_HMAC_GENERAL", CKM_SHA224_HMAC_GENERAL, 64, 28, MCF_SIGNVERIFY | MCF_NEEDSPARAM | MCF_MAC_GENERAL }, { "CKM_SHA224_KEY_DERIVATION", CKM_SHA224_KEY_DERIVATION, 0, MC_INFORMATION_UNAVAILABLE, MCF_DERIVE }, { "CKM_SHA224_KEY_GEN", CKM_SHA224_KEY_GEN, 0, 28, MCF_KEYGEN }, { "CKM_SHA224_RSA_PKCS", CKM_SHA224_RSA_PKCS, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY }, { "CKM_SHA224_RSA_PKCS_PSS", CKM_SHA224_RSA_PKCS_PSS, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY | MCF_NEEDSPARAM }, { "CKM_SHA256", CKM_SHA256, 64, 32, MCF_DIGEST }, { "CKM_SHA256_HMAC", CKM_SHA256_HMAC, 64, 32, MCF_SIGNVERIFY }, { "CKM_SHA256_HMAC_GENERAL", CKM_SHA256_HMAC_GENERAL, 64, 32, MCF_SIGNVERIFY | MCF_NEEDSPARAM | MCF_MAC_GENERAL }, { "CKM_SHA256_KEY_DERIVATION", CKM_SHA256_KEY_DERIVATION, 0, MC_INFORMATION_UNAVAILABLE, MCF_DERIVE }, { "CKM_SHA256_KEY_GEN", CKM_SHA256_KEY_GEN, 0, 32, MCF_KEYGEN }, { "CKM_SHA256_RSA_PKCS", CKM_SHA256_RSA_PKCS, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY }, { "CKM_SHA256_RSA_PKCS_PSS", CKM_SHA256_RSA_PKCS_PSS, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY | MCF_NEEDSPARAM }, { "CKM_SHA384", CKM_SHA384, 128, 48, MCF_DIGEST }, { "CKM_SHA384_HMAC", CKM_SHA384_HMAC, 128, 48, MCF_SIGNVERIFY }, { "CKM_SHA384_HMAC_GENERAL", CKM_SHA384_HMAC_GENERAL, 128, 48, MCF_SIGNVERIFY | MCF_NEEDSPARAM | MCF_MAC_GENERAL }, { "CKM_SHA384_KEY_DERIVATION", CKM_SHA384_KEY_DERIVATION, 0, MC_INFORMATION_UNAVAILABLE, MCF_DERIVE }, { "CKM_SHA384_KEY_GEN", CKM_SHA384_KEY_GEN, 0, 48, MCF_KEYGEN }, { "CKM_SHA384_RSA_PKCS", CKM_SHA384_RSA_PKCS, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY }, { "CKM_SHA384_RSA_PKCS_PSS", CKM_SHA384_RSA_PKCS_PSS, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY | MCF_NEEDSPARAM }, { "CKM_SHA3_224", CKM_SHA3_224, 144, 28, MCF_DIGEST }, { "CKM_SHA3_224_HMAC", CKM_SHA3_224_HMAC, 144, 28, MCF_SIGNVERIFY }, { "CKM_SHA3_224_HMAC_GENERAL", CKM_SHA3_224_HMAC_GENERAL, 144, 28, MCF_SIGNVERIFY | MCF_NEEDSPARAM | MCF_MAC_GENERAL }, { "CKM_SHA3_224_KEY_DERIVATION", CKM_SHA3_224_KEY_DERIVATION, 0, MC_INFORMATION_UNAVAILABLE, MCF_DIGEST }, { "CKM_SHA3_224_KEY_GEN", CKM_SHA3_224_KEY_GEN, 0, 28, MCF_KEYGEN }, { "CKM_SHA3_224_RSA_PKCS", CKM_SHA3_224_RSA_PKCS, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY }, { "CKM_SHA3_224_RSA_PKCS_PSS", CKM_SHA3_224_RSA_PKCS_PSS, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY | MCF_NEEDSPARAM }, { "CKM_SHA3_256", CKM_SHA3_256, 136, 32, MCF_DIGEST }, { "CKM_SHA3_256_HMAC", CKM_SHA3_256_HMAC, 136, 32, MCF_SIGNVERIFY }, { "CKM_SHA3_256_HMAC_GENERAL", CKM_SHA3_256_HMAC_GENERAL, 136, 32, MCF_SIGNVERIFY | MCF_NEEDSPARAM | MCF_MAC_GENERAL }, { "CKM_SHA3_256_KEY_DERIVATION", CKM_SHA3_256_KEY_DERIVATION, 0, MC_INFORMATION_UNAVAILABLE, MCF_DIGEST }, { "CKM_SHA3_256_KEY_GEN", CKM_SHA3_256_KEY_GEN, 0, 32, MCF_KEYGEN }, { "CKM_SHA3_256_RSA_PKCS", CKM_SHA3_256_RSA_PKCS, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY }, { "CKM_SHA3_256_RSA_PKCS_PSS", CKM_SHA3_256_RSA_PKCS_PSS, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY | MCF_NEEDSPARAM }, { "CKM_SHA3_384", CKM_SHA3_384, 104, 48, MCF_DIGEST }, { "CKM_SHA3_384_HMAC", CKM_SHA3_384_HMAC, 104, 48, MCF_SIGNVERIFY }, { "CKM_SHA3_384_HMAC_GENERAL", CKM_SHA3_384_HMAC_GENERAL, 104, 48, MCF_SIGNVERIFY | MCF_NEEDSPARAM | MCF_MAC_GENERAL }, { "CKM_SHA3_384_KEY_DERIVATION", CKM_SHA3_384_KEY_DERIVATION, 0, MC_INFORMATION_UNAVAILABLE, MCF_DIGEST }, { "CKM_SHA3_384_KEY_GEN", CKM_SHA3_384_KEY_GEN, 0, 48, MCF_KEYGEN }, { "CKM_SHA3_384_RSA_PKCS", CKM_SHA3_384_RSA_PKCS, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY }, { "CKM_SHA3_384_RSA_PKCS_PSS", CKM_SHA3_384_RSA_PKCS_PSS, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY | MCF_NEEDSPARAM }, { "CKM_SHA3_512", CKM_SHA3_512, 72, 64, MCF_DIGEST }, { "CKM_SHA3_512_HMAC", CKM_SHA3_512_HMAC, 72, 64, MCF_SIGNVERIFY }, { "CKM_SHA3_512_HMAC_GENERAL", CKM_SHA3_512_HMAC_GENERAL, 72, 64, MCF_SIGNVERIFY | MCF_NEEDSPARAM | MCF_MAC_GENERAL }, { "CKM_SHA3_512_KEY_DERIVATION", CKM_SHA3_512_KEY_DERIVATION, 0, MC_INFORMATION_UNAVAILABLE, MCF_DIGEST }, { "CKM_SHA3_512_KEY_GEN", CKM_SHA3_512_KEY_GEN, 0, 64, MCF_KEYGEN }, { "CKM_SHA3_512_RSA_PKCS", CKM_SHA3_512_RSA_PKCS, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY }, { "CKM_SHA3_512_RSA_PKCS_PSS", CKM_SHA3_512_RSA_PKCS_PSS, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY | MCF_NEEDSPARAM }, { "CKM_SHA512", CKM_SHA512, 128, 64, MCF_DIGEST }, { "CKM_SHA512_224", CKM_SHA512_224, 128, 28, MCF_DIGEST }, { "CKM_SHA512_224_HMAC", CKM_SHA512_224_HMAC, 128, 28, MCF_SIGNVERIFY }, { "CKM_SHA512_224_HMAC_GENERAL", CKM_SHA512_224_HMAC_GENERAL, 128, 28, MCF_SIGNVERIFY | MCF_NEEDSPARAM | MCF_MAC_GENERAL }, { "CKM_SHA512_224_KEY_DERIVATION", CKM_SHA512_224_KEY_DERIVATION, 0, MC_INFORMATION_UNAVAILABLE, MCF_DIGEST }, { "CKM_SHA512_224_KEY_GEN", CKM_SHA512_224_KEY_GEN, 0, 28, MCF_KEYGEN }, { "CKM_SHA512_256", CKM_SHA512_256, 128, 32, MCF_DIGEST }, { "CKM_SHA512_256_HMAC", CKM_SHA512_256_HMAC, 128, 32, MCF_SIGNVERIFY }, { "CKM_SHA512_256_HMAC_GENERAL", CKM_SHA512_256_HMAC_GENERAL, 128, 32, MCF_SIGNVERIFY | MCF_NEEDSPARAM | MCF_MAC_GENERAL }, { "CKM_SHA512_256_KEY_DERIVATION", CKM_SHA512_256_KEY_DERIVATION, 0, MC_INFORMATION_UNAVAILABLE, MCF_DIGEST }, { "CKM_SHA512_256_KEY_GEN", CKM_SHA512_256_KEY_GEN, 0, 32, MCF_KEYGEN }, { "CKM_SHA512_HMAC", CKM_SHA512_HMAC, 128, 64, MCF_SIGNVERIFY }, { "CKM_SHA512_HMAC_GENERAL", CKM_SHA512_HMAC_GENERAL, 128, 64, MCF_SIGNVERIFY | MCF_NEEDSPARAM | MCF_MAC_GENERAL }, { "CKM_SHA512_KEY_DERIVATION", CKM_SHA512_KEY_DERIVATION, 0, MC_INFORMATION_UNAVAILABLE, MCF_DIGEST }, { "CKM_SHA512_KEY_GEN", CKM_SHA512_KEY_GEN, 0, 64, MCF_KEYGEN }, { "CKM_SHA512_RSA_PKCS", CKM_SHA512_RSA_PKCS, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY }, { "CKM_SHA512_RSA_PKCS_PSS", CKM_SHA512_RSA_PKCS_PSS, 0, MC_KEY_DEPENDENT, MCF_SIGNVERIFY | MCF_NEEDSPARAM }, { "CKM_SHAKE_128_KEY_DERIVATION", CKM_SHAKE_128_KEY_DERIVATION, 0, MC_INFORMATION_UNAVAILABLE, MCF_DIGEST }, { "CKM_SHAKE_256_KEY_DERIVATION", CKM_SHAKE_256_KEY_DERIVATION, 0, MC_INFORMATION_UNAVAILABLE, MCF_DIGEST }, { "CKM_SSL3_KEY_AND_MAC_DERIVE", CKM_SSL3_KEY_AND_MAC_DERIVE, 0, MC_INFORMATION_UNAVAILABLE, MCF_DERIVE | MCF_NEEDSPARAM }, { "CKM_SSL3_MASTER_KEY_DERIVE", CKM_SSL3_MASTER_KEY_DERIVE, 0, 48, MCF_DERIVE | MCF_NEEDSPARAM }, { "CKM_SSL3_MD5_MAC", CKM_SSL3_MD5_MAC, 64, 8, MCF_SIGNVERIFY | MCF_NEEDSPARAM }, { "CKM_SSL3_PRE_MASTER_KEY_GEN", CKM_SSL3_PRE_MASTER_KEY_GEN, 0, 48, MCF_KEYGEN | MCF_NEEDSPARAM }, { "CKM_SSL3_SHA1_MAC", CKM_SSL3_SHA1_MAC, 64, 8, MCF_SIGNVERIFY | MCF_NEEDSPARAM }, { "CKM_TLS_KEY_AND_MAC_DERIVE", CKM_TLS_KEY_AND_MAC_DERIVE, 0, MC_INFORMATION_UNAVAILABLE, MCF_DERIVE | MCF_NEEDSPARAM }, { "CKM_TLS_PRE_MASTER_KEY_GEN", CKM_TLS_PRE_MASTER_KEY_GEN, 0, 48, MCF_KEYGEN | MCF_NEEDSPARAM }, /* Not supported by any token, but needed for Token Store */ { "CKM_PKCS5_PBKD2", CKM_PKCS5_PBKD2, 0, MC_INFORMATION_UNAVAILABLE, MCF_KEYGEN | MCF_NEEDSPARAM }, }; opencryptoki-opencryptoki-451d99c/usr/lib/api/policy.c000066400000000000000000002523071520105705100231300ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021 * * 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 "cfgparser.h" #include "stringtranslations.h" #include "policy.h" #include "trace.h" #include "ock_syslog.h" #include #include #include "hashmap.h" #include #include #include #include #include #include #include #include #include #include /* in h_extern.h, but not included since it creates too many unneeded dependencies for unit tests. */ extern CK_RV get_sha_size(CK_ULONG mech, CK_ULONG *hsize); #define COMPARE_MODEXP 0 #define COMPARE_ECC 1 #define COMPARE_SYMMETRIC 2 /* This is handled specially for now. Value chosen such that it is not a valid index for struct strength.strength.arr. */ #define COMPARE_PQC 5 #define COMPARE_NOKEY 0xff #define OCK_POLICY_CFG OCK_CONFDIR "/policy.conf" #define OCK_STRENGTH_CFG OCK_CONFDIR "/strength.conf" #define OCK_POLICY_MINVERSION 0u #define OCK_STRENGTH_MINVERSION 0u #define OCK_POLICY_PERMS (0640u) struct strength { union { CK_ULONG arr[5]; struct { /* Keep this order in sync with the COMPARE_* definitions */ CK_ULONG modexp; CK_ULONG ecc; CK_ULONG symmetric; CK_ULONG digests; CK_ULONG signatures; } details; } strength; CK_BBOOL set; }; struct policy_private { struct hashmap *allowedmechs; const struct _ec **allowedcurves; unsigned int minstrengthidx; int numallowedcurves; /* negative if all curves are allowed */ CK_ULONG allowedmgfs; CK_ULONG allowedvendormgfs; CK_ULONG allowedkdfs; CK_ULONG allowedvendorkdfs; CK_ULONG allowedprfs; CK_ULONG maxcurvesize; /* Strength struct ordered from highest to lowest. */ struct strength strengths[NUM_SUPPORTED_STRENGTHS]; }; static CK_ULONG policy_get_sym_key_strength(policy_t p, CK_ULONG sym_key_bits); struct policy_private *policy_private_alloc(void) { return calloc(1, sizeof(struct policy_private)); } struct policy_private *policy_private_free(struct policy_private *pp) { if (pp) { if (pp->allowedmechs) hashmap_free(pp->allowedmechs, NULL); if (pp->allowedcurves) free(pp->allowedcurves); free(pp); } return NULL; } void policy_private_deactivate(struct policy_private *pp) { hashmap_free(pp->allowedmechs, NULL); /* Non-existing hash is universal. */ pp->allowedmechs = NULL; free(pp->allowedcurves); pp->allowedcurves = NULL; pp->minstrengthidx = NUM_SUPPORTED_STRENGTHS; pp->numallowedcurves = -1; pp->allowedmgfs = ~0lu; pp->allowedvendormgfs = ~0lu; pp->allowedkdfs = ~0lu; pp->allowedvendorkdfs = ~0lu; pp->allowedprfs = ~0lu; pp->maxcurvesize = 521u; } static void policy_compute_strength(struct policy_private *pp, struct objstrength *s, CK_ULONG size, CK_ULONG ct) { unsigned int i; if (ct == COMPARE_NOKEY || ct == COMPARE_PQC) { s->strength = 0; } else { for (i = 0; i < NUM_SUPPORTED_STRENGTHS; ++i) { if (pp->strengths[i].set == CK_TRUE && size >= pp->strengths[i].strength.arr[ct]) { break; } } s->strength = i; } } static void policy_check_ec_allowed(struct policy_private *pp, struct objstrength *s, const CK_BYTE *oid, CK_ULONG oidlen) { int i; if (pp->numallowedcurves >= 0) { s->allowed = CK_FALSE; for (i = 0; i < pp->numallowedcurves; ++i) { if (pp->allowedcurves[i]->data_size == oidlen && memcmp(oid, pp->allowedcurves[i]->data, oidlen) == 0) { s->allowed = CK_TRUE; break; } } } else { s->allowed = CK_TRUE; } } static CK_RV policy_get_curve_args(get_attr_val_f getattr, void *d, free_attr_f free_attr, CK_ULONG *size, const CK_BYTE **oid, CK_ULONG *oidlen, uint8_t curve_type) { CK_ATTRIBUTE *ec_params = NULL; CK_RV rv; int i; rv = getattr(d, CKA_EC_PARAMS, &ec_params); if (rv == CKR_OK) { if (ec_params->pValue == NULL || ec_params->ulValueLen == 0) { TRACE_ERROR("Invalid CKA_EC_PARAMS value\n"); rv = CKR_FUNCTION_FAILED; goto out; } rv = CKR_CURVE_NOT_SUPPORTED; for (i = 0; i < NUMEC; ++i) { if (der_ec_supported[i].data_size == ec_params->ulValueLen && memcmp(ec_params->pValue, der_ec_supported[i].data, ec_params->ulValueLen) == 0 && (curve_type == (uint8_t)-1 || der_ec_supported[i].curve_type == curve_type)) { *size = der_ec_supported[i].prime_bits; *oid = der_ec_supported[i].data; *oidlen = der_ec_supported[i].data_size; rv = CKR_OK; break; } } } out: if (free_attr && ec_params) free_attr(d, ec_params); return rv; } static CK_RV policy_get_pqc_args(CK_KEY_TYPE key_type, get_attr_val_f getattr, void *d, free_attr_f free_attr, CK_ULONG *size, CK_ULONG *siglen, const CK_BYTE **oid, CK_ULONG *oidlen) { CK_ATTRIBUTE_TYPE keyform_attr; CK_ATTRIBUTE_TYPE mode_attr; CK_ATTRIBUTE *keyform = NULL, *mode = NULL; const struct pqc_oid *oids, *pqc_oid = NULL; CK_RV rv; switch (key_type) { case CKK_IBM_PQC_DILITHIUM: keyform_attr = CKA_IBM_DILITHIUM_KEYFORM; mode_attr = CKA_IBM_DILITHIUM_MODE; oids = dilithium_oids; break; case CKK_IBM_PQC_KYBER: keyform_attr = CKA_IBM_KYBER_KEYFORM; mode_attr = CKA_IBM_KYBER_MODE; oids = kyber_oids; break; case CKK_IBM_ML_DSA: keyform_attr = CKA_IBM_PARAMETER_SET; mode_attr = (CK_ATTRIBUTE_TYPE)-1; oids = ml_dsa_oids; break; case CKK_IBM_ML_KEM: keyform_attr = CKA_IBM_PARAMETER_SET; mode_attr = (CK_ATTRIBUTE_TYPE)-1; oids = ml_kem_oids; break; case CKK_ML_DSA: keyform_attr = CKA_PARAMETER_SET; mode_attr = (CK_ATTRIBUTE_TYPE)-1; oids = ml_dsa_oids; break; case CKK_ML_KEM: keyform_attr = CKA_PARAMETER_SET; mode_attr = (CK_ATTRIBUTE_TYPE)-1; oids = ml_kem_oids; break; default: TRACE_ERROR("Unsupported key type 0x%lx\n", key_type); return CKR_KEY_TYPE_INCONSISTENT; } rv = getattr(d, keyform_attr, &keyform); if (rv == CKR_OK && keyform->ulValueLen == sizeof(CK_ULONG)) { pqc_oid = find_pqc_by_keyform(oids, *(CK_ULONG *)keyform->pValue); } else if (mode_attr != (CK_ATTRIBUTE_TYPE)-1) { rv = getattr(d, mode_attr, &mode); if (rv == CKR_OK && mode->ulValueLen > 0) pqc_oid = find_pqc_by_oid(oids, mode->pValue, mode->ulValueLen); } if (pqc_oid == NULL) { TRACE_ERROR("Did not find KEYFORM or MODE for key type 0x%lx\n", key_type); rv = CKR_TEMPLATE_INCOMPLETE; goto out; } *size = pqc_oid->policy_size; *siglen = pqc_oid->policy_siglen; *oid = pqc_oid->oid; *oidlen = pqc_oid->oid_len; out: if (free_attr) { if (keyform) free_attr(d, keyform); if (mode) free_attr(d, mode); } return rv; } static CK_RV policy_extract_key_data(get_attr_val_f getattr, void *d, free_attr_f free_attr, CK_ULONG *comptarget, CK_ULONG *size, const CK_BYTE **oid, CK_ULONG *oidlen, CK_ULONG *siglen) { CK_RV rv; CK_ATTRIBUTE *keytype = NULL, *keysize = NULL, *sigsize = NULL; *oid = NULL; *oidlen = 0; *size = 0; rv = getattr(d, CKA_KEY_TYPE, &keytype); if (rv != CKR_OK) { TRACE_INFO("Failed to retrieve key type. rv=0x%lx\n", rv); *comptarget = COMPARE_NOKEY; *siglen = 0; return CKR_OK; } if (keytype->ulValueLen != sizeof(CK_ULONG)) { TRACE_ERROR("Wrong type for key type!\n"); rv = CKR_FUNCTION_FAILED; goto out; } switch (*(CK_ULONG *)keytype->pValue) { case CKK_RSA: rv = getattr(d, CKA_MODULUS, &keysize); if (rv != CKR_OK) { TRACE_ERROR("Did not find CKA_MODULUS for RSA key!\n"); goto out; } *size = keysize->ulValueLen * 8; *siglen = *size; *comptarget = COMPARE_MODEXP; break; case CKK_DSA: rv = getattr(d, CKA_SUBPRIME, &sigsize); if (rv != CKR_OK) { TRACE_ERROR("Did not find CKA_SUBPRIME for DSA key\n"); goto out; } *siglen = sigsize->ulValueLen * 8 * 2; /* Fallthrough */ case CKK_DH: /* Fallthrough */ case CKK_X9_42_DH: rv = getattr(d, CKA_PRIME, &keysize); if (rv != CKR_OK) { TRACE_ERROR("Did not find CKA_PRIME for key type 0x%lx\n", *(CK_ULONG *)keytype->pValue); return rv; } *size = keysize->ulValueLen * 8; *comptarget = COMPARE_MODEXP; break; case CKK_EC: rv = policy_get_curve_args(getattr, d, free_attr, size, oid, oidlen, (uint8_t)-1); *siglen = *size * 2; *comptarget = COMPARE_ECC; break; case CKK_EC_EDWARDS: rv = policy_get_curve_args(getattr, d, free_attr, size, oid, oidlen, EDWARDS_CURVE); *siglen = *size * 2; *comptarget = COMPARE_ECC; break; case CKK_EC_MONTGOMERY: rv = policy_get_curve_args(getattr, d, free_attr, size, oid, oidlen, MONTGOMERY_CURVE); *siglen = *size * 2; *comptarget = COMPARE_ECC; break; case CKK_DES: *size = 56; *siglen = 64; *comptarget = COMPARE_SYMMETRIC; break; case CKK_DES2: *size = 80; *siglen = 64; *comptarget = COMPARE_SYMMETRIC; break; case CKK_DES3: *size = 112; *siglen = 64; *comptarget = COMPARE_SYMMETRIC; break; case CKK_AES_XTS: /* Fallthrough */ case CKK_AES: if (*(CK_ULONG *)keytype->pValue == CKK_AES) *siglen = 128; /* Fallthrough */ case CKK_GENERIC_SECRET: case CKK_SHA_1_HMAC: case CKK_SHA224_HMAC: case CKK_SHA256_HMAC: case CKK_SHA384_HMAC: case CKK_SHA512_HMAC: case CKK_SHA3_224_HMAC: case CKK_SHA3_256_HMAC: case CKK_SHA3_384_HMAC: case CKK_SHA3_512_HMAC: case CKK_SHA512_224_HMAC: case CKK_SHA512_256_HMAC: rv = getattr(d, CKA_VALUE_LEN, &keysize); if (rv != CKR_OK) { TRACE_ERROR("Did not find CKA_PRIME for key type 0x%lx\n", *(CK_ULONG *)keytype->pValue); goto out; } if (keysize->ulValueLen != sizeof(CK_ULONG)) { TRACE_ERROR("Unexpected type for CKA_VALUE_LEN\n"); rv = CKR_FUNCTION_FAILED; goto out; } *size = (*(CK_ULONG*)keysize->pValue) * 8; if (*(CK_ULONG *)keytype->pValue == CKK_AES_XTS) *size /= 2; *comptarget = COMPARE_SYMMETRIC; break; case CKK_IBM_PQC_DILITHIUM: case CKK_IBM_PQC_KYBER: case CKK_IBM_ML_DSA: case CKK_IBM_ML_KEM: case CKK_ML_KEM: case CKK_ML_DSA: rv = policy_get_pqc_args(*(CK_ULONG *)keytype->pValue, getattr, d, free_attr, size, siglen, oid, oidlen); *comptarget = COMPARE_PQC; break; /* POLICY: New CKK */ default: TRACE_ERROR("Strength determination not implemented for key type 0x%lx\n", *(CK_ULONG *)keytype->pValue); rv = CKR_FUNCTION_FAILED; } out: if (free_attr) { if (keytype) free_attr(d, keytype); if (keysize) free_attr(d, keysize); if (sigsize) free_attr(d, sigsize); } return rv; } static CK_RV policy_get_digest_size(CK_MECHANISM_TYPE mech, CK_ULONG *hsize) { CK_RV rv = CKR_OK; if (mech == CKM_MD2 || mech == CKM_MD5) { *hsize = 128; /* POLICY: New CKM digest */ } else { rv = get_sha_size(mech, hsize); if (rv == CKR_OK) *hsize *= 8; } return rv; } static CK_RV policy_get_sig_size(CK_MECHANISM_PTR mech, struct objstrength *s, CK_ULONG *ssize) { const struct mechrow *col = mechrow_from_numeric(mech->mechanism); const struct mechrow *impl; CK_ULONG size; if (!col || !s) return CKR_FUNCTION_FAILED; if (col->flags & MCF_MAC_GENERAL) { if (mech->ulParameterLen != sizeof(CK_MAC_GENERAL_PARAMS) || mech->pParameter == NULL) { TRACE_ERROR("Invalid mechanism parameter\n"); return CKR_MECHANISM_PARAM_INVALID; } size = *(CK_MAC_GENERAL_PARAMS *)mech->pParameter; if (size > col->outputsize) size = col->outputsize; *ssize = size * 8; return CKR_OK; } if (col->outputsize == MC_KEY_DEPENDENT) { switch (mech->mechanism) { /* POLICY: New CKM Sign/Verify */ case CKM_IBM_CMAC: /* Fallthrough */ case CKM_DSA: /* Fallthrough */ case CKM_ECDSA: /* Fallthrough */ case CKM_RSA_PKCS: /* Fallthrough */ case CKM_RSA_PKCS_PSS: /* Fallthrough */ case CKM_RSA_X_509: /* Fallthrough */ case CKM_RSA_X9_31: /* Fallthrough */ case CKM_IBM_ED448_SHA3: /* Fallthrough */ case CKM_EDDSA: /* Fallthrough */ case CKM_IBM_DILITHIUM: /* Fallthrough */ case CKM_IBM_ML_DSA: /* Fallthrough */ case CKM_ML_DSA: *ssize = s->siglen; break; case CKM_DSA_SHA1: /* Fallthrough */ case CKM_ECDSA_SHA1: /* Fallthrough */ case CKM_SHA1_RSA_PKCS: /* Fallthrough */ case CKM_SHA1_RSA_PKCS_PSS: /* Fallthrough */ case CKM_SHA1_RSA_X9_31: *ssize = MIN(s->siglen, 160); break; case CKM_MD5_RSA_PKCS: *ssize = MIN(s->siglen, 128); break; case CKM_ECDSA_SHA224: /* Fallthrough */ case CKM_ECDSA_SHA3_224: /* Fallthrough */ case CKM_SHA224_RSA_PKCS: /* Fallthrough */ case CKM_SHA224_RSA_PKCS_PSS: /* Fallthrough */ case CKM_SHA3_224_RSA_PKCS: /* Fallthrough */ case CKM_SHA3_224_RSA_PKCS_PSS: /* Fallthrough */ case CKM_HASH_ML_DSA_SHA224: /* Fallthrough */ case CKM_HASH_ML_DSA_SHA3_224: *ssize = MIN(s->siglen, 224); break; case CKM_ECDSA_SHA256: /* Fallthrough */ case CKM_ECDSA_SHA3_256: /* Fallthrough */ case CKM_SHA256_RSA_PKCS: /* Fallthrough */ case CKM_SHA256_RSA_PKCS_PSS: /* Fallthrough */ case CKM_SHA3_256_RSA_PKCS: /* Fallthrough */ case CKM_SHA3_256_RSA_PKCS_PSS: /* Fallthrough */ case CKM_HASH_ML_DSA_SHA256: /* Fallthrough */ case CKM_HASH_ML_DSA_SHA3_256: /* Fallthrough */ case CKM_HASH_ML_DSA_SHAKE128: *ssize = MIN(s->siglen, 256); break; case CKM_ECDSA_SHA384: /* Fallthrough */ case CKM_ECDSA_SHA3_384: /* Fallthrough */ case CKM_SHA384_RSA_PKCS: /* Fallthrough */ case CKM_SHA384_RSA_PKCS_PSS: /* Fallthrough */ case CKM_SHA3_384_RSA_PKCS: /* Fallthrough */ case CKM_SHA3_384_RSA_PKCS_PSS: /* Fallthrough */ case CKM_HASH_ML_DSA_SHA384: /* Fallthrough */ case CKM_HASH_ML_DSA_SHA3_384: *ssize = MIN(s->siglen, 384); break; case CKM_ECDSA_SHA512: /* Fallthrough */ case CKM_ECDSA_SHA3_512: /* Fallthrough */ case CKM_SHA512_RSA_PKCS: /* Fallthrough */ case CKM_SHA512_RSA_PKCS_PSS: /* Fallthrough */ case CKM_SHA3_512_RSA_PKCS: /* Fallthrough */ case CKM_SHA3_512_RSA_PKCS_PSS: /* Fallthrough */ case CKM_IBM_ED25519_SHA512: /* Fallthrough */ case CKM_HASH_ML_DSA_SHA512: /* Fallthrough */ case CKM_HASH_ML_DSA_SHA3_512: /* Fallthrough */ case CKM_HASH_ML_DSA_SHAKE256: *ssize = MIN(s->siglen, 512); break; case CKM_IBM_ECDSA_OTHER: if (mech->ulParameterLen != sizeof(CK_IBM_ECDSA_OTHER_PARAMS) || mech->pParameter == NULL) { TRACE_ERROR("Invalid mechanism parameter\n"); return CKR_MECHANISM_PARAM_INVALID; } switch (((CK_IBM_ECDSA_OTHER_PARAMS *) mech->pParameter)->submechanism) { case CKM_IBM_ECSDSA_RAND: case CKM_IBM_ECSDSA_COMPR_MULTI: *ssize = MIN(s->siglen, 256); /* Uses SHA-256 internally */ break; case CKM_IBM_BLS: *ssize = MIN(s->siglen, CK_IBM_BLS12_381_SIGN_LEN * 8); break; default: return CKR_FUNCTION_FAILED; } break; case CKM_IBM_EC_AGGREGATE: *ssize = MIN(s->siglen, CK_IBM_BLS12_381_SIGN_LEN * 8); break; case CKM_HASH_ML_DSA: if (mech->ulParameterLen != sizeof(CK_HASH_SIGN_ADDITIONAL_CONTEXT) || mech->pParameter == NULL) { TRACE_ERROR("Invalid mechanism parameter\n"); return CKR_MECHANISM_PARAM_INVALID; } impl = mechrow_from_numeric( ((CK_HASH_SIGN_ADDITIONAL_CONTEXT *)mech->pParameter)->hash); if (impl == NULL || impl->outputsize == MC_INFORMATION_UNAVAILABLE) { TRACE_ERROR("Invalid mechanism parameter: hash mech invalid\n"); return CKR_MECHANISM_PARAM_INVALID; } *ssize = MIN(s->siglen, impl->outputsize * 8); break; default: return CKR_FUNCTION_FAILED; } return CKR_OK; } if (col->outputsize == MC_INFORMATION_UNAVAILABLE) return CKR_FUNCTION_FAILED; *ssize = col->outputsize * 8; return CKR_OK; } static inline CK_RV policy_is_mgf_allowed(struct policy_private *pp, CK_RSA_PKCS_MGF_TYPE mgf) { if (mgf > CKG_VENDOR_DEFINED) { if ((mgf - CKG_VENDOR_DEFINED - 1) <= 31 && (pp->allowedvendormgfs & (1u << (mgf - CKG_VENDOR_DEFINED - 1)))) return CKR_OK; } else { if (mgf <= 31 && (pp->allowedmgfs & (1u << mgf))) return CKR_OK; } TRACE_WARNING("POLICY VIOLATION: mgf not allowed: 0x%lx\n", mgf); return CKR_FUNCTION_FAILED; } static inline CK_RV policy_is_kdf_allowed(struct policy_private *pp, CK_ULONG kdf) { if (kdf > CKD_VENDOR_DEFINED) { if ((kdf - CKD_VENDOR_DEFINED - 1) <= 31 && (pp->allowedvendorkdfs & (1u << (kdf - CKD_VENDOR_DEFINED - 1)))) return CKR_OK; } else { if (kdf <= 31 && (pp->allowedkdfs & (1u << kdf))) return CKR_OK; } TRACE_WARNING("POLICY VIOLATION: kdf not allowed: 0x%lx\n", kdf); return CKR_FUNCTION_FAILED; } static inline CK_RV policy_is_prf_allowed(struct policy_private *pp, CK_ULONG val) { if (pp->allowedprfs & (1u << val)) return CKR_OK; TRACE_WARNING("POLICY VIOLATION: prf not allowed: 0x%lx\n", val); return CKR_FUNCTION_FAILED; } static CK_RV policy_is_key_allowed_i(struct policy_private *pp, struct objstrength *s) { /* 1. Check strength */ if (s->strength > pp->minstrengthidx) { TRACE_WARNING("POLICY VIOLATION: Key does not satisfy minimal strength constraint\n"); return CKR_FUNCTION_FAILED; } /* 2. EC check */ if (!s->allowed) { TRACE_WARNING("POLICY VIOLATION: Key belongs to a forbidden EC curve\n"); return CKR_FUNCTION_FAILED; } return CKR_OK; } static CK_RV policy_update_modexp(struct policy_private *pp, CK_MECHANISM_INFO_PTR info) { CK_ULONG minsize; if (pp->minstrengthidx < NUM_SUPPORTED_STRENGTHS && pp->strengths[pp->minstrengthidx].set) { minsize = pp->strengths[pp->minstrengthidx].strength.details.modexp; if (minsize > info->ulMaxKeySize) return CKR_MECHANISM_INVALID; if (minsize > info->ulMinKeySize) info->ulMinKeySize = minsize; } return CKR_OK; } static CK_RV policy_update_symmetric(struct policy_private *pp, CK_MECHANISM_INFO_PTR info, CK_BBOOL isbytes, CK_BBOOL isaesxts) { CK_ULONG minsize; if (pp->minstrengthidx < NUM_SUPPORTED_STRENGTHS && pp->strengths[pp->minstrengthidx].set) { minsize = pp->strengths[pp->minstrengthidx].strength.details.symmetric; if (isbytes == CK_TRUE) minsize /= 8; if (isaesxts == CK_TRUE) minsize *= 2; if (minsize > info->ulMaxKeySize) return CKR_MECHANISM_INVALID; if (minsize > info->ulMinKeySize) info->ulMinKeySize = minsize; } return CKR_OK; } static CK_RV policy_update_ec(struct policy_private *pp, CK_MECHANISM_INFO_PTR info) { CK_ULONG minsize; if (pp->numallowedcurves == 0) /* We do not have any allowed curves */ return CKR_MECHANISM_INVALID; if (pp->minstrengthidx < NUM_SUPPORTED_STRENGTHS && pp->strengths[pp->minstrengthidx].set) { minsize = pp->strengths[pp->minstrengthidx].strength.details.ecc; if (minsize > info->ulMaxKeySize) return CKR_MECHANISM_INVALID; if (minsize > info->ulMinKeySize) info->ulMinKeySize = minsize; } return CKR_OK; } static CK_RV policy_update_digest(struct policy_private *pp, CK_MECHANISM_TYPE mech) { CK_ULONG digestsize; if (pp->minstrengthidx < NUM_SUPPORTED_STRENGTHS && pp->strengths[pp->minstrengthidx].set) { if (policy_get_digest_size(mech, &digestsize) != CKR_OK) /* Policy would reject this unknown mechanism */ return CKR_MECHANISM_INVALID; if (digestsize < pp->strengths[pp->minstrengthidx].strength.details.digests) return CKR_MECHANISM_INVALID; } return CKR_OK; } static CK_RV policy_check_signature_size(struct policy_private *pp, CK_MECHANISM_TYPE mech, CK_MECHANISM_INFO_PTR info) { CK_ULONG minsiglen; CK_ULONG siglen = 0; CK_MECHANISM testmech; struct objstrength s; CK_MAC_GENERAL_PARAMS params = 0; if (info->flags & (CKF_SIGN | CKF_SIGN_RECOVER | CKF_VERIFY | CKF_VERIFY_RECOVER)) { testmech.mechanism = mech; testmech.pParameter = ¶ms; testmech.ulParameterLen = sizeof(params); if (pp->minstrengthidx < NUM_SUPPORTED_STRENGTHS && pp->strengths[pp->minstrengthidx].set) { minsiglen = pp->strengths[pp->minstrengthidx].strength.details.signatures; switch (mech) { /* POLICY: New CKM Sign/Verify */ case CKM_RSA_PKCS: /* Fallthrough */ case CKM_RSA_PKCS_PSS: /* Fallthrough */ case CKM_RSA_X_509: /* Fallthrough */ case CKM_RSA_X9_31: /* Fallthrough */ case CKM_SHA1_RSA_PKCS: /* Fallthrough */ case CKM_SHA224_RSA_PKCS: /* Fallthrough */ case CKM_SHA256_RSA_PKCS: /* Fallthrough */ case CKM_SHA384_RSA_PKCS: /* Fallthrough */ case CKM_SHA512_RSA_PKCS: /* Fallthrough */ case CKM_SHA3_224_RSA_PKCS: /* Fallthrough */ case CKM_SHA3_256_RSA_PKCS: /* Fallthrough */ case CKM_SHA3_384_RSA_PKCS: /* Fallthrough */ case CKM_SHA3_512_RSA_PKCS: /* Fallthrough */ case CKM_SHA1_RSA_PKCS_PSS: /* Fallthrough */ case CKM_SHA224_RSA_PKCS_PSS: /* Fallthrough */ case CKM_SHA256_RSA_PKCS_PSS: /* Fallthrough */ case CKM_SHA384_RSA_PKCS_PSS: /* Fallthrough */ case CKM_SHA512_RSA_PKCS_PSS: /* Fallthrough */ case CKM_SHA3_224_RSA_PKCS_PSS: /* Fallthrough */ case CKM_SHA3_256_RSA_PKCS_PSS: /* Fallthrough */ case CKM_SHA3_384_RSA_PKCS_PSS: /* Fallthrough */ case CKM_SHA3_512_RSA_PKCS_PSS: /* Fallthrough */ case CKM_SHA1_RSA_X9_31: siglen = info->ulMaxKeySize; break; case CKM_DSA: /* Fallthrough */ case CKM_DSA_SHA1: /* Max size of CKA_SUBPRIME is 256 bits, so this is the biggest * signature we can create with a DSA key. */ siglen = 2u * 256u; break; case CKM_ECDSA: /* Fallthrough */ case CKM_EDDSA: /* Fallthrough */ case CKM_ECDSA_SHA1: /* Fallthrough */ case CKM_ECDSA_SHA224: /* Fallthrough */ case CKM_ECDSA_SHA256: /* Fallthrough */ case CKM_ECDSA_SHA384: /* Fallthrough */ case CKM_ECDSA_SHA512: /* Fallthrough */ case CKM_ECDSA_SHA3_224: /* Fallthrough */ case CKM_ECDSA_SHA3_256: /* Fallthrough */ case CKM_ECDSA_SHA3_384: /* Fallthrough */ case CKM_ECDSA_SHA3_512: /* Fallthrough */ case CKM_IBM_ECDSA_OTHER: if (pp->numallowedcurves == 0) { /* No curve allowed */ return CKR_MECHANISM_INVALID; } siglen = 2u * pp->maxcurvesize; break; case CKM_AES_CMAC_GENERAL: /* Fallthrough */ case CKM_AES_MAC_GENERAL: params = 128 / 8; break; case CKM_DES3_CMAC_GENERAL: /* Fallthrough */ case CKM_DES3_MAC_GENERAL: params = 64 / 8; break; case CKM_MD5_HMAC_GENERAL: params = 128 / 8; break; case CKM_SHA_1_HMAC_GENERAL: params = 160 / 8; break; case CKM_SHA512_224_HMAC_GENERAL: /* Fallthrough */ case CKM_SHA224_HMAC_GENERAL: /* Fallthrough */ case CKM_SHA3_224_HMAC_GENERAL: params = 224 / 8; break; case CKM_SHA512_256_HMAC_GENERAL: /* Fallthrough */ case CKM_SHA256_HMAC_GENERAL: /* Fallthrough */ case CKM_SHA3_256_HMAC_GENERAL: params = 256 / 8; break; case CKM_SHA384_HMAC_GENERAL: /* Fallthrough */ case CKM_SHA3_384_HMAC_GENERAL: params = 384 / 8; break; case CKM_SHA512_HMAC_GENERAL: /* Fallthrough */ case CKM_SHA3_512_HMAC_GENERAL: params = 512 / 8; break; case CKM_SSL3_MD5_MAC: /* Fallthrough */ case CKM_SSL3_SHA1_MAC: params = 8; break; case CKM_IBM_DILITHIUM: /* Fallthrough */ case CKM_IBM_ML_DSA: /* Fallthrough */ case CKM_ML_DSA: siglen = 256; break; default: break; } s.siglen = siglen; if (policy_get_sig_size(&testmech, &s, &siglen) != CKR_OK) return CKR_MECHANISM_INVALID; if (siglen < minsiglen) return CKR_MECHANISM_INVALID; } } return CKR_OK; } /* main functions (exported via function pointers) */ static CK_RV policy_is_key_allowed(policy_t p, struct objstrength *s, SESSION *sess) { struct policy_private *pp = p->priv; CK_RV rv = CKR_OK; if (pp) { rv = policy_is_key_allowed_i(pp, s); if (rv != CKR_OK && sess) sess->session_info.ulDeviceError = CKR_POLICY_VIOLATION; } return rv; } static CK_RV policy_store_object_strength(policy_t p, struct objstrength *s, get_attr_val_f getattr, void *d, free_attr_f free_attr, SESSION *sess) { struct policy_private *pp = p->priv; /* silence maybe uninitialized warning for ct and siglen */ CK_ULONG ct = 0, size, oidlen, siglen = 0; const CK_BYTE *oid; CK_RV rv = CKR_OK; if (pp) { rv = policy_extract_key_data(getattr, d, free_attr, &ct, &size, &oid, &oidlen, &siglen); if (rv == CKR_OK) { s->siglen = siglen; policy_compute_strength(pp, s, size, ct); if (ct == COMPARE_ECC) policy_check_ec_allowed(pp, s, oid, oidlen); else s->allowed = CK_TRUE; rv = policy_is_key_allowed_i(pp, s); if (rv != CKR_OK) { switch (ct) { case COMPARE_MODEXP: TRACE_ERROR("POLICY: Modular exponentiation compare size %lu too small!\n", size); break; case COMPARE_ECC: if (s->allowed) TRACE_ERROR("POLICY: ECC curve size %lu too small!\n", size); else TRACE_ERROR("POLICY: ECC curve not allowed!\n"); break; case COMPARE_SYMMETRIC: TRACE_ERROR("POLICY: Symmetric key compare size %lu too small!\n", size); break; case COMPARE_PQC: TRACE_ERROR("POLICY: PQ key not allowed!\n"); break; case COMPARE_NOKEY: TRACE_ERROR("POLICY: non-key object not allowed!\n"); break; default: TRACE_ERROR("POLICY: Invalid compare target %lu!\n", ct); break; } } } else { TRACE_ERROR("POLICY: Failed to extract key data.\n"); s->strength = POLICY_STRENGTH_IDX_0; s->siglen = 0; s->allowed = CK_FALSE; } if (rv != CKR_OK && sess) sess->session_info.ulDeviceError = CKR_POLICY_VIOLATION; } else { s->strength = POLICY_STRENGTH_IDX_0; s->siglen = 0; s->allowed = CK_TRUE; } return rv; } static CK_RV policy_is_mech_allowed(policy_t p, CK_MECHANISM_PTR mech, struct objstrength *s, int check, SESSION *sess) { struct policy_private *pp = p->priv; struct objstrength tmp_strength = { 0, 0, CK_TRUE }; CK_RSA_PKCS_OAEP_PARAMS *oaep_params; CK_ULONG size; CK_RV rv = CKR_OK; if (pp) { if (s && policy_is_key_allowed_i(pp, s) != CKR_OK) { rv = CKR_FUNCTION_FAILED; goto out; } if (hashmap_find(pp->allowedmechs, mech->mechanism, NULL) == 0) { TRACE_WARNING("Mechanism 0x%lx not allowed by policy\n", mech->mechanism); rv = CKR_FUNCTION_FAILED; goto out; } if (check == POLICY_CHECK_DIGEST) { if (policy_get_digest_size(mech->mechanism, &size) != CKR_OK) { TRACE_WARNING("POLICY ERROR: Failed to retrieve digest size.\n"); rv = CKR_FUNCTION_FAILED; goto out; } if (pp->minstrengthidx < NUM_SUPPORTED_STRENGTHS && size < pp->strengths[pp->minstrengthidx].strength.details.digests) { TRACE_WARNING("Digest output too small for policy.\n"); rv = CKR_FUNCTION_FAILED; goto out; } } else if (check == POLICY_CHECK_SIGNATURE || check == POLICY_CHECK_VERIFY) { if (policy_get_sig_size(mech, s, &size) != CKR_OK) { TRACE_WARNING("POLICY ERROR: Failed to retrieve signature size.\n"); rv = CKR_FUNCTION_FAILED; goto out; } if (pp->minstrengthidx < NUM_SUPPORTED_STRENGTHS && size < pp->strengths[pp->minstrengthidx].strength.details.signatures) { TRACE_WARNING("Signature too small for policy.\n"); rv = CKR_FUNCTION_FAILED; goto out; } } switch (mech->mechanism) { /* POLICY: New CKM Deep Check */ case CKM_RSA_PKCS_PSS: case CKM_SHA1_RSA_PKCS_PSS: case CKM_SHA224_RSA_PKCS_PSS: case CKM_SHA256_RSA_PKCS_PSS: case CKM_SHA384_RSA_PKCS_PSS: case CKM_SHA512_RSA_PKCS_PSS: case CKM_SHA3_224_RSA_PKCS_PSS: case CKM_SHA3_256_RSA_PKCS_PSS: case CKM_SHA3_384_RSA_PKCS_PSS: case CKM_SHA3_512_RSA_PKCS_PSS: if (mech->ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS) || mech->pParameter == NULL) { TRACE_ERROR("Invalid mechanism parameter\n"); rv = CKR_MECHANISM_PARAM_INVALID; break; } if (hashmap_find(pp->allowedmechs, ((CK_RSA_PKCS_PSS_PARAMS *)mech->pParameter)->hashAlg, NULL) == 0) { TRACE_WARNING("POLICY VIOLATION: PSS hash algorithm not allowed by policy.\n"); rv = CKR_FUNCTION_FAILED; } else if (policy_is_mgf_allowed(pp, ((CK_RSA_PKCS_PSS_PARAMS *)mech->pParameter)->mgf) != CKR_OK) { rv = CKR_FUNCTION_FAILED; } break; case CKM_RSA_PKCS_OAEP: if (mech->ulParameterLen != sizeof(CK_RSA_PKCS_OAEP_PARAMS) || mech->pParameter == NULL) { TRACE_ERROR("Invalid mechanism parameter\n"); rv = CKR_MECHANISM_PARAM_INVALID; break; } if (hashmap_find(pp->allowedmechs, ((CK_RSA_PKCS_OAEP_PARAMS *)mech->pParameter)->hashAlg, NULL) == 0) { TRACE_WARNING("POLICY VIOLATION: OAEP hash algorithm not allowed by policy.\n"); rv = CKR_FUNCTION_FAILED; } else if (policy_is_mgf_allowed(pp, ((CK_RSA_PKCS_OAEP_PARAMS *)mech->pParameter)->mgf) != CKR_OK) { rv = CKR_FUNCTION_FAILED; } break; case CKM_ECDH1_DERIVE: case CKM_ECDH1_COFACTOR_DERIVE: if (mech->ulParameterLen != sizeof(CK_ECDH1_DERIVE_PARAMS) || mech->pParameter == NULL) { TRACE_ERROR("Invalid mechanism parameter\n"); rv = CKR_MECHANISM_PARAM_INVALID; break; } if (policy_is_kdf_allowed(pp, ((CK_ECDH1_DERIVE_PARAMS *)mech->pParameter)->kdf) != CKR_OK) rv = CKR_FUNCTION_FAILED; break; case CKM_IBM_ECDSA_OTHER: if (mech->ulParameterLen != sizeof(CK_IBM_ECDSA_OTHER_PARAMS) || mech->pParameter == NULL) { TRACE_ERROR("Invalid mechanism parameter\n"); rv = CKR_MECHANISM_PARAM_INVALID; break; } switch (((CK_IBM_ECDSA_OTHER_PARAMS *) mech->pParameter)->submechanism) { case CKM_IBM_ECSDSA_RAND: case CKM_IBM_ECSDSA_COMPR_MULTI: /* Uses SHA-256 internally */ if (hashmap_find(pp->allowedmechs, CKM_SHA256, NULL) == 0) { TRACE_WARNING("POLICY VIOLATION: ECDSA OTHER SHA-256 algorithm not allowed by policy.\n"); rv = CKR_FUNCTION_FAILED; } break; case CKM_IBM_BLS: break; default: rv = CKR_FUNCTION_FAILED; break; } break; case CKM_IBM_BTC_DERIVE: if (mech->ulParameterLen != sizeof(CK_IBM_BTC_DERIVE_PARAMS) || mech->pParameter == NULL) { TRACE_ERROR("Invalid mechanism parameter\n"); rv = CKR_MECHANISM_PARAM_INVALID; break; } if (((CK_IBM_BTC_DERIVE_PARAMS *)mech->pParameter)->version != CK_IBM_BTC_DERIVE_PARAMS_VERSION_1) break; switch (((CK_IBM_BTC_DERIVE_PARAMS *)mech->pParameter)->type) { case CK_IBM_BTC_BIP0032_PRV2PRV: case CK_IBM_BTC_BIP0032_PRV2PUB: case CK_IBM_BTC_BIP0032_PUB2PUB: case CK_IBM_BTC_BIP0032_MASTERK: case CK_IBM_BTC_SLIP0010_PRV2PRV: case CK_IBM_BTC_SLIP0010_PRV2PUB: case CK_IBM_BTC_SLIP0010_PUB2PUB: case CK_IBM_BTC_SLIP0010_MASTERK: /* Uses SHA-512 internally */ if (hashmap_find(pp->allowedmechs, CKM_SHA512_HMAC, NULL) == 0) { TRACE_WARNING("POLICY VIOLATION: BTC SHA-512-HMAC algorithm not allowed by policy.\n"); rv = CKR_FUNCTION_FAILED; } break; default: rv = CKR_FUNCTION_FAILED; break; } break; case CKM_IBM_KYBER: /* Only KEM uses a parameter, KeyGen, Encrypt/Decrypt don't */ if (mech->ulParameterLen != sizeof(CK_IBM_KYBER_PARAMS) && mech->ulParameterLen != 0) { TRACE_ERROR("Invalid mechanism parameter\n"); rv = CKR_MECHANISM_PARAM_INVALID; break; } if (mech->ulParameterLen != sizeof(CK_IBM_KYBER_PARAMS)) break; if (mech->pParameter == NULL) { TRACE_ERROR("Invalid mechanism parameter\n"); rv = CKR_MECHANISM_PARAM_INVALID; break; } if (policy_is_kdf_allowed(pp, ((CK_IBM_KYBER_PARAMS *)mech->pParameter)->kdf) != CKR_OK) { rv = CKR_FUNCTION_FAILED; break; } break; case CKM_IBM_ML_KEM: if (mech->ulParameterLen != sizeof(CK_IBM_ML_KEM_PARAMS)) { TRACE_ERROR("Invalid mechanism parameter\n"); rv = CKR_MECHANISM_PARAM_INVALID; break; } if (mech->pParameter == NULL) { TRACE_ERROR("Invalid mechanism parameter\n"); rv = CKR_MECHANISM_PARAM_INVALID; break; } if (policy_is_kdf_allowed(pp, ((CK_IBM_ML_KEM_PARAMS *)mech->pParameter)->kdf) != CKR_OK) { rv = CKR_FUNCTION_FAILED; break; } break; case CKM_IBM_ML_KEM_WITH_ECDH: if (mech->ulParameterLen != sizeof(CK_IBM_ML_KEM_WITH_ECDH_PARAMS)) { TRACE_ERROR("Invalid mechanism parameter\n"); rv = CKR_MECHANISM_PARAM_INVALID; break; } if (mech->pParameter == NULL) { TRACE_ERROR("Invalid mechanism parameter\n"); rv = CKR_MECHANISM_PARAM_INVALID; break; } if (policy_is_kdf_allowed(pp, ((CK_IBM_ML_KEM_WITH_ECDH_PARAMS *)mech->pParameter)->kdf) != CKR_OK) { rv = CKR_FUNCTION_FAILED; break; } break; case CKM_RSA_AES_KEY_WRAP: if (mech->ulParameterLen != sizeof(CK_RSA_AES_KEY_WRAP_PARAMS) || mech->pParameter == NULL) { TRACE_ERROR("Invalid mechanism parameter\n"); rv = CKR_MECHANISM_PARAM_INVALID; break; } oaep_params = ((CK_RSA_AES_KEY_WRAP_PARAMS *)mech->pParameter)->pOAEPParams; if (oaep_params == NULL) { rv = CKR_MECHANISM_PARAM_INVALID; break; } if (hashmap_find(pp->allowedmechs, oaep_params->hashAlg, NULL) == 0) { TRACE_WARNING("POLICY VIOLATION: OAEP hash algorithm not allowed by policy.\n"); rv = CKR_FUNCTION_FAILED; break; } else if (policy_is_mgf_allowed(pp, oaep_params->mgf) != CKR_OK) { rv = CKR_FUNCTION_FAILED; break; } if (((CK_RSA_AES_KEY_WRAP_PARAMS *) mech->pParameter)->ulAESKeyBits > 0) { tmp_strength.strength = policy_get_sym_key_strength(p, ((CK_RSA_AES_KEY_WRAP_PARAMS *) mech->pParameter)->ulAESKeyBits); rv = policy_is_key_allowed(p, &tmp_strength, sess); if (rv != CKR_OK) break; } break; case CKM_ECDH_AES_KEY_WRAP: case CKM_ECDH_COF_AES_KEY_WRAP: case CKM_ECDH_X_AES_KEY_WRAP: if (mech->ulParameterLen != sizeof(CK_ECDH_AES_KEY_WRAP_PARAMS) || mech->pParameter == NULL) { TRACE_ERROR("Invalid mechanism parameter\n"); rv = CKR_MECHANISM_PARAM_INVALID; break; } if (policy_is_kdf_allowed(pp, ((CK_ECDH_AES_KEY_WRAP_PARAMS *) mech->pParameter)->kdf) != CKR_OK) { rv = CKR_FUNCTION_FAILED; break; } if (((CK_ECDH_AES_KEY_WRAP_PARAMS *) mech->pParameter)->ulAESKeyBits > 0) { tmp_strength.strength = policy_get_sym_key_strength(p, ((CK_ECDH_AES_KEY_WRAP_PARAMS *) mech->pParameter)->ulAESKeyBits); rv = policy_is_key_allowed(p, &tmp_strength, sess); if (rv != CKR_OK) break; } break; case CKM_HASH_ML_DSA: if (mech->ulParameterLen != sizeof(CK_HASH_SIGN_ADDITIONAL_CONTEXT) || mech->pParameter == NULL) { TRACE_ERROR("Invalid mechanism parameter\n"); return CKR_MECHANISM_PARAM_INVALID; } if (hashmap_find(pp->allowedmechs, ((CK_HASH_SIGN_ADDITIONAL_CONTEXT *) mech->pParameter)->hash, NULL) == 0) { TRACE_WARNING("POLICY VIOLATION: ML-DSA hash algorithm not " "allowed by policy.\n"); rv = CKR_FUNCTION_FAILED; break; } break; default: break; } } out: if (rv != CKR_OK && sess) sess->session_info.ulDeviceError = CKR_POLICY_VIOLATION; return rv; } static CK_RV policy_update_mech_info(policy_t p, CK_MECHANISM_TYPE mech, CK_MECHANISM_INFO_PTR info) { struct policy_private *pp = p->priv; /* Silence spurious maybe-uninitialized warning. */ struct objstrength tmp = { 0, 0, CK_TRUE }; const struct mechrow *row; CK_BBOOL isaesxts = CK_FALSE; if (pp) { if (hashmap_find(pp->allowedmechs, mech, NULL) == 0) return CKR_MECHANISM_INVALID; switch (mech) { /* POLICY: New CKM */ case CKM_AES_CBC: case CKM_AES_CBC_PAD: case CKM_AES_CFB128: case CKM_AES_CFB64: case CKM_AES_CFB8: case CKM_AES_CMAC: case CKM_AES_CMAC_GENERAL: case CKM_AES_CTR: case CKM_AES_ECB: case CKM_AES_GCM: case CKM_AES_XTS: case CKM_AES_KEY_GEN: case CKM_AES_XTS_KEY_GEN: case CKM_AES_MAC: case CKM_AES_MAC_GENERAL: case CKM_AES_OFB: case CKM_AES_KEY_WRAP: case CKM_AES_KEY_WRAP_PAD: case CKM_AES_KEY_WRAP_KWP: case CKM_AES_KEY_WRAP_PKCS7: case CKM_IBM_CMAC: case CKM_SHA1_KEY_DERIVATION: case CKM_SHA224_KEY_DERIVATION: case CKM_SHA256_KEY_DERIVATION: case CKM_SHA384_KEY_DERIVATION: case CKM_SHA512_KEY_DERIVATION: case CKM_SHA512_224_KEY_DERIVATION: case CKM_SHA512_256_KEY_DERIVATION: case CKM_SHA3_224_KEY_DERIVATION: case CKM_SHA3_256_KEY_DERIVATION: case CKM_SHA3_384_KEY_DERIVATION: case CKM_SHA3_512_KEY_DERIVATION: case CKM_SHAKE_128_KEY_DERIVATION: case CKM_SHAKE_256_KEY_DERIVATION: case CKM_SSL3_MASTER_KEY_DERIVE: case CKM_SSL3_PRE_MASTER_KEY_GEN: case CKM_TLS_PRE_MASTER_KEY_GEN: isaesxts = (mech == CKM_AES_XTS_KEY_GEN || mech == CKM_AES_XTS); if (policy_update_symmetric(pp, info, CK_TRUE, isaesxts) != CKR_OK) { row = mechrow_from_numeric(mech); TRACE_DEVEL("Mechanism %s (0x%lx) blocked by policy!\n", row ? row->string : "UNKNOWN", mech); return CKR_MECHANISM_INVALID; } break; case CKM_DES_KEY_GEN: case CKM_DES_CBC: case CKM_DES_CBC_PAD: case CKM_DES_CFB64: case CKM_DES_CFB8: case CKM_DES_ECB: case CKM_DES_OFB64: policy_compute_strength(pp, &tmp, 56, COMPARE_SYMMETRIC); if (policy_is_key_allowed_i(pp, &tmp) != CKR_OK) return CKR_MECHANISM_INVALID; break; case CKM_DES2_KEY_GEN: policy_compute_strength(pp, &tmp, 80, COMPARE_SYMMETRIC); if (policy_is_key_allowed_i(pp, &tmp) != CKR_OK) return CKR_MECHANISM_INVALID; break; case CKM_DES3_KEY_GEN: case CKM_DES3_CBC: case CKM_DES3_CBC_PAD: case CKM_DES3_CMAC: case CKM_DES3_CMAC_GENERAL: case CKM_DES3_ECB: case CKM_DES3_MAC: case CKM_DES3_MAC_GENERAL: policy_compute_strength(pp, &tmp, 112, COMPARE_SYMMETRIC); if (policy_is_key_allowed_i(pp, &tmp) != CKR_OK) return CKR_MECHANISM_INVALID; break; case CKM_DH_PKCS_DERIVE: case CKM_DH_PKCS_KEY_PAIR_GEN: case CKM_DH_PKCS_PARAMETER_GEN: case CKM_DSA: case CKM_DSA_KEY_PAIR_GEN: case CKM_DSA_PARAMETER_GEN: case CKM_DSA_SHA1: case CKM_MD5_RSA_PKCS: case CKM_RSA_PKCS: case CKM_RSA_PKCS_KEY_PAIR_GEN: case CKM_RSA_PKCS_OAEP: case CKM_RSA_PKCS_PSS: case CKM_RSA_X_509: case CKM_RSA_X9_31: case CKM_RSA_X9_31_KEY_PAIR_GEN: case CKM_SHA1_RSA_PKCS: case CKM_SHA1_RSA_PKCS_PSS: case CKM_SHA1_RSA_X9_31: case CKM_SHA224_RSA_PKCS: case CKM_SHA224_RSA_PKCS_PSS: case CKM_SHA256_RSA_PKCS: case CKM_SHA256_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_SHA3_224_RSA_PKCS: case CKM_SHA3_224_RSA_PKCS_PSS: case CKM_SHA3_256_RSA_PKCS: case CKM_SHA3_256_RSA_PKCS_PSS: case CKM_SHA3_384_RSA_PKCS: case CKM_SHA3_384_RSA_PKCS_PSS: case CKM_SHA3_512_RSA_PKCS: case CKM_SHA3_512_RSA_PKCS_PSS: case CKM_RSA_AES_KEY_WRAP: if (policy_update_modexp(pp, info) != CKR_OK) { TRACE_DEVEL("Mechanism 0x%lx blocked by policy!\n", mech); return CKR_MECHANISM_INVALID; } break; case CKM_ECDH1_DERIVE: case CKM_ECDH1_COFACTOR_DERIVE: case CKM_ECDSA: case CKM_EC_KEY_PAIR_GEN: case CKM_EC_EDWARDS_KEY_PAIR_GEN: case CKM_EC_MONTGOMERY_KEY_PAIR_GEN: case CKM_ECDSA_SHA1: case CKM_ECDSA_SHA224: case CKM_ECDSA_SHA256: case CKM_ECDSA_SHA384: case CKM_ECDSA_SHA512: case CKM_ECDSA_SHA3_224: case CKM_ECDSA_SHA3_256: case CKM_ECDSA_SHA3_384: case CKM_ECDSA_SHA3_512: case CKM_IBM_EC_C25519: case CKM_IBM_EC_C448: case CKM_IBM_ED25519_SHA512: case CKM_IBM_ED448_SHA3: case CKM_IBM_ECDSA_OTHER: case CKM_IBM_BTC_DERIVE: case CKM_ECDH_AES_KEY_WRAP: case CKM_ECDH_COF_AES_KEY_WRAP: case CKM_ECDH_X_AES_KEY_WRAP: case CKM_IBM_EC_AGGREGATE: case CKM_EDDSA: if (policy_update_ec(pp, info) != CKR_OK) { TRACE_DEVEL("Mechanism 0x%lx blocked by policy!\n", mech); return CKR_MECHANISM_INVALID; } break; case CKM_GENERIC_SECRET_KEY_GEN: case CKM_SHA_1_KEY_GEN: case CKM_SHA224_KEY_GEN: case CKM_SHA256_KEY_GEN: case CKM_SHA384_KEY_GEN: case CKM_SHA512_KEY_GEN: case CKM_SHA512_224_KEY_GEN: case CKM_SHA512_256_KEY_GEN: case CKM_SHA3_224_KEY_GEN: case CKM_SHA3_256_KEY_GEN: case CKM_SHA3_384_KEY_GEN: case CKM_SHA3_512_KEY_GEN: case CKM_SSL3_MD5_MAC: case CKM_SSL3_SHA1_MAC: if (policy_update_symmetric(pp, info, CK_FALSE, CK_FALSE) != CKR_OK) { TRACE_DEVEL("Mechanism 0x%lx blocked by policy!\n", mech); return CKR_MECHANISM_INVALID; } break; case CKM_IBM_DILITHIUM: case CKM_IBM_KYBER: case CKM_IBM_ML_DSA_KEY_PAIR_GEN: case CKM_IBM_ML_DSA: case CKM_IBM_ML_KEM_KEY_PAIR_GEN: case CKM_IBM_ML_KEM: case CKM_IBM_ML_KEM_WITH_ECDH: case CKM_ML_KEM_KEY_PAIR_GEN: case CKM_ML_KEM: case CKM_ML_DSA_KEY_PAIR_GEN: case CKM_ML_DSA: case CKM_HASH_ML_DSA: case CKM_HASH_ML_DSA_SHA224: case CKM_HASH_ML_DSA_SHA256: case CKM_HASH_ML_DSA_SHA384: case CKM_HASH_ML_DSA_SHA512: case CKM_HASH_ML_DSA_SHA3_224: case CKM_HASH_ML_DSA_SHA3_256: case CKM_HASH_ML_DSA_SHA3_384: case CKM_HASH_ML_DSA_SHA3_512: case CKM_HASH_ML_DSA_SHAKE128: case CKM_HASH_ML_DSA_SHAKE256: break; case CKM_IBM_SHA3_224: case CKM_IBM_SHA3_256: case CKM_IBM_SHA3_384: case CKM_IBM_SHA3_512: case CKM_MD5: 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_SHA3_224: case CKM_SHA3_256: case CKM_SHA3_384: case CKM_SHA3_512: if (policy_update_digest(pp, mech) != CKR_OK) { TRACE_DEVEL("Mechanism 0x%lx blocked by policy!\n", mech); return CKR_MECHANISM_INVALID; } break; case CKM_PBE_SHA1_DES3_EDE_CBC: /* For this mechanism, the standard does not specify a value for the MECHANISM_INFO structure. But this mechanism generates a DES3 key. Check if DES3 keys can be generated in this policy. If not, block this mechanism since it can only fail. */ tmp.strength = POLICY_STRENGTH_IDX_112; tmp.allowed = CK_TRUE; if (policy_is_key_allowed_i(pp, &tmp) != CKR_OK) return CKR_MECHANISM_INVALID; break; case CKM_KEY_WRAP_LYNKS: case CKM_MD5_HMAC: case CKM_MD5_HMAC_GENERAL: 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_224_HMAC: case CKM_SHA512_224_HMAC_GENERAL: case CKM_SHA512_256_HMAC: case CKM_SHA512_256_HMAC_GENERAL: case CKM_SHA512_HMAC: case CKM_SHA512_HMAC_GENERAL: case CKM_SHA3_224_HMAC: case CKM_SHA3_224_HMAC_GENERAL: case CKM_SHA3_256_HMAC: case CKM_SHA3_256_HMAC_GENERAL: case CKM_SHA3_384_HMAC: case CKM_SHA3_384_HMAC_GENERAL: case CKM_SHA3_512_HMAC: case CKM_SHA3_512_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: case CKM_SSL3_KEY_AND_MAC_DERIVE: case CKM_TLS_KEY_AND_MAC_DERIVE: case CKM_IBM_ATTRIBUTEBOUND_WRAP: case CKM_PUB_KEY_FROM_PRIV_KEY: /* For these mechanisms, the standard does not specify a value for info. So we only pass them to the generic check for signature size. */ break; default: TRACE_ERROR("Mechanism 0x%lx unknown to policy!\n", mech); return CKR_MECHANISM_INVALID; } if (policy_check_signature_size(pp, mech, info) != CKR_OK) { row = mechrow_from_numeric(mech); TRACE_DEVEL("Policy removes SIGN/VERIFY from %s (0x%lx)\n", row ? row->string : "UNKNOWN", mech); info->flags &= ~(CKF_SIGN | CKF_SIGN_RECOVER | CKF_VERIFY | CKF_VERIFY_RECOVER); if ((info->flags & ~(CKF_HW | CKF_EC_F_P | CKF_EC_F_2M | CKF_EC_ECPARAMETERS | CKF_EC_OID | CKF_EC_NAMEDCURVE | CKF_EC_COMPRESS | CKF_EC_UNCOMPRESS | CKF_EC_CURVENAME | CKF_EXTENSION)) == 0) { TRACE_DEVEL("Mechanism %s (0x%lx) does not provide any " "feature after policy adjustment!\n", row ? row->string : "UNKNOWN", mech); return CKR_MECHANISM_INVALID; } } } return CKR_OK; } /* If encalgo is NULL, the function assumes it should check the ICSF token. */ static CK_RV policy_check_token_store(policy_t p, CK_BBOOL newversion, CK_MECHANISM_TYPE encalgo, CK_SLOT_ID slot, struct tokstore_strength *ts) { struct policy_private *pp = p->priv; struct objstrength s; if (pp) { s.allowed = CK_TRUE; if (newversion) { if (hashmap_find(pp->allowedmechs, CKM_AES_KEY_GEN, NULL) == 0) { TRACE_WARNING("POLICY VIOLATION: CKM_AES_KEY_GEN needed by Token-Store for slot %lu\n", slot); OCK_SYSLOG(LOG_ERR, "POLICY VIOLATION: CKM_AES_KEY_GEN needed by Token-Store for slot %lu\n", slot); return CKR_GENERAL_ERROR; } if (hashmap_find(pp->allowedmechs, CKM_AES_KEY_WRAP, NULL) == 0) { TRACE_WARNING("POLICY VIOLATION: CKM_AES_KEY_WRAP needed by Token-Store for slot %lu\n", slot); OCK_SYSLOG(LOG_ERR, "POLICY VIOLATION: CKM_AES_KEY_WRAP needed by Token-Store for slot %lu\n", slot); return CKR_GENERAL_ERROR; } if (hashmap_find(pp->allowedmechs, CKM_AES_GCM, NULL) == 0) { TRACE_WARNING("POLICY VIOLATION: CKM_AES_GCM needed by Token-Store for slot %lu\n", slot); OCK_SYSLOG(LOG_ERR, "POLICY VIOLATION: CKM_AES_GCM needed by Token-Store for slot %lu\n", slot); return CKR_GENERAL_ERROR; } policy_compute_strength(pp, &s, 256, COMPARE_SYMMETRIC); if (hashmap_find(pp->allowedmechs, CKM_PKCS5_PBKD2, NULL) == 0) { TRACE_WARNING("POLICY VIOLATION: CKM_PKCS5_PBKD2 needed by Token-Store for slot %lu\n", slot); OCK_SYSLOG(LOG_ERR, "POLICY VIOLATION: CKM_PKCS5_PBKD2 needed by Token-Store for slot %lu\n", slot); return CKR_GENERAL_ERROR; } if (policy_is_prf_allowed(pp, CKP_PKCS5_PBKD2_HMAC_SHA512) != CKR_OK) { TRACE_WARNING("POLICY VIOLATION: CKP_PKCS5_PBKD2_HMAC_SHA512 needed by Token-Store for slot %lu\n", slot); OCK_SYSLOG(LOG_ERR, "POLICY VIOLATION: CKP_PKCS5_PBKD2_HMAC_SHA512 needed by Token-Store for slot %lu\n", slot); return CKR_GENERAL_ERROR; } if (ts) { ts->mk_keygen.mechanism = CKM_AES_KEY_GEN; ts->mk_crypt.mechanism = CKM_AES_GCM; ts->wrap_crypt.mechanism = CKM_AES_GCM; ts->mk_keygen.pParameter = ts->mk_crypt.pParameter = ts->wrap_crypt.pParameter = NULL; ts->mk_keygen.ulParameterLen = ts->mk_crypt.ulParameterLen = ts->wrap_crypt.ulParameterLen = 0; ts->mk_strength = ts->wrap_strength = s.strength; } } else { /* ICSF does not use a datastore, so encalgo is 0. */ if (encalgo && hashmap_find(pp->allowedmechs, encalgo, NULL) == 0) { TRACE_WARNING("POLICY VIOLATION: Token-Store encryption method not allowed for slot %lu!\n", slot); OCK_SYSLOG(LOG_ERR, "POLICY VIOLATION: Token-Store encryption method not allowed for slot %lu!\n", slot); return CKR_GENERAL_ERROR; } /* SO pin hash */ if (hashmap_find(pp->allowedmechs, CKM_SHA_1, NULL) == 0) { TRACE_WARNING("POLICY VIOLATION: Token-Store requires SHA1 for slot %lu!\n", slot); OCK_SYSLOG(LOG_ERR, "POLICY VIOLATION: Token-Store requires SHA1 for slot %lu!\n", slot); return CKR_GENERAL_ERROR; } /* User pin hash */ if (hashmap_find(pp->allowedmechs, CKM_MD5, NULL) == 0) { TRACE_WARNING("POLICY VIOLATION: Token-Store requires MD5 for slot %lu!\n", slot); OCK_SYSLOG(LOG_ERR, "POLICY VIOLATION: Token-Store requires MD5 for slot %lu!\n", slot); return CKR_GENERAL_ERROR; } if (encalgo == CKM_DES3_CBC) { if (hashmap_find(pp->allowedmechs, CKM_DES3_KEY_GEN, NULL) == 0) { TRACE_WARNING("POLICY VIOLATION: CKM_DES3_KEY_GEN needed by Token-Store for slot %lu\n", slot); OCK_SYSLOG(LOG_ERR, "POLICY VIOLATION: CKM_DES3_KEY_GEN needed by Token-Store for slot %lu\n", slot); return CKR_GENERAL_ERROR; } /* We use a 3DES key with three parts as master key... */ policy_compute_strength(pp, &s, 112, COMPARE_SYMMETRIC); if (ts) ts->mk_strength = s.strength; /* ... and a 2Key 3DES keys as wrapping key. */ policy_compute_strength(pp, &s, 80, COMPARE_SYMMETRIC); if (ts) { ts->mk_keygen.mechanism = CKM_DES3_KEY_GEN; ts->mk_crypt.mechanism = ts->wrap_crypt.mechanism = encalgo; ts->mk_keygen.pParameter = ts->mk_crypt.pParameter = ts->wrap_crypt.pParameter = NULL; ts->mk_keygen.ulParameterLen = ts->mk_crypt.ulParameterLen = ts->wrap_crypt.ulParameterLen = 0; ts->wrap_strength = s.strength; } } else if (encalgo == CKM_AES_CBC) { if (hashmap_find(pp->allowedmechs, CKM_AES_KEY_GEN, NULL) == 0) { TRACE_WARNING("POLICY VIOLATION: CKM_AES_KEY_GEN needed by Token-Store for slot %lu\n", slot); OCK_SYSLOG(LOG_ERR, "POLICY VIOLATION: CKM_AES_KEY_GEN needed by Token-Store for slot %lu\n", slot); return CKR_GENERAL_ERROR; } policy_compute_strength(pp, &s, 256, COMPARE_SYMMETRIC); if (ts) { ts->mk_keygen.mechanism = CKM_AES_KEY_GEN; ts->mk_crypt.mechanism = ts->wrap_crypt.mechanism = encalgo; ts->mk_keygen.pParameter = ts->mk_crypt.pParameter = ts->wrap_crypt.pParameter = NULL; ts->mk_keygen.ulParameterLen = ts->mk_crypt.ulParameterLen = ts->wrap_crypt.ulParameterLen = 0; ts->mk_strength = ts->wrap_strength = s.strength; } } else if (encalgo) { TRACE_WARNING("POLICY VIOLATION: Unknown Token-Store encryption method for slot %lu!\n", slot); OCK_SYSLOG(LOG_ERR, "POLICY VIOLATION: Unknown Token-Store encryption method for slot %lu!\n", slot); return CKR_GENERAL_ERROR; } else { /* ICSF token */ if (hashmap_find(pp->allowedmechs, CKM_AES_KEY_GEN, NULL) == 0) { TRACE_WARNING("POLICY VIOLATION: CKM_AES_KEY_GEN needed by Token-Store for slot %lu\n", slot); OCK_SYSLOG(LOG_ERR, "POLICY VIOLATION: CKM_AES_KEY_GEN needed by Token-Store for slot %lu\n", slot); return CKR_GENERAL_ERROR; } if (hashmap_find(pp->allowedmechs, CKM_AES_CBC, NULL) == 0) { TRACE_WARNING("POLICY VIOLATION: CKM_AES_CBC needed by Token-Store for slot %lu\n", slot); OCK_SYSLOG(LOG_ERR, "POLICY VIOLATION: CKM_AES_CBC needed by Token-Store for slot %lu\n", slot); return CKR_GENERAL_ERROR; } policy_compute_strength(pp, &s, 256, COMPARE_SYMMETRIC); if (hashmap_find(pp->allowedmechs, CKM_PKCS5_PBKD2, NULL) == 0) { TRACE_WARNING("POLICY VIOLATION: CKM_PKCS5_PBKD2 needed by Token-Store for slot %lu\n", slot); OCK_SYSLOG(LOG_ERR, "POLICY VIOLATION: CKM_PKCS5_PBKD2 needed by Token-Store for slot %lu\n", slot); return CKR_GENERAL_ERROR; } if (policy_is_prf_allowed(pp, CKP_PKCS5_PBKD2_HMAC_SHA256) != CKR_OK) { TRACE_WARNING("POLICY VIOLATION: CKP_PKCS5_PBKD2_HMAC_SHA256 needed by Token-Store for slot %lu\n", slot); OCK_SYSLOG(LOG_ERR, "POLICY VIOLATION: CKP_PKCS5_PBKD2_HMAC_SHA256 needed by Token-Store for slot %lu\n", slot); return CKR_GENERAL_ERROR; } if (ts) { ts->mk_keygen.mechanism = CKM_AES_KEY_GEN; ts->mk_crypt.mechanism = ts->wrap_crypt.mechanism = CKM_AES_CBC; ts->mk_keygen.pParameter = ts->mk_crypt.pParameter = ts->wrap_crypt.pParameter = NULL; ts->mk_keygen.ulParameterLen = ts->mk_crypt.ulParameterLen = ts->wrap_crypt.ulParameterLen = 0; ts->mk_strength = ts->wrap_strength = s.strength; } } } /* Both token store versions now have the weakest key strength in s */ if (policy_is_key_allowed_i(pp, &s) != CKR_OK) { TRACE_WARNING("POLICY VIOLATION: Token-Store encryption key too weak for slot %lu!\n", slot); OCK_SYSLOG(LOG_ERR, "POLICY VIOLATION: Token-Store encryption key too weak for slot %lu!\n", slot); return CKR_GENERAL_ERROR; } } return CKR_OK; } static CK_ULONG policy_get_sym_key_strength(policy_t p, CK_ULONG sym_key_bits) { struct policy_private *pp = p->priv; struct objstrength s; policy_compute_strength(pp, &s, sym_key_bits, COMPARE_SYMMETRIC); return s.strength; } /* Policy loading support (internal functions) */ static CK_RV policy_check_cfg_file(FILE *fp, const char *name) { struct stat statbuf; struct group *grp = NULL; int err; grp = getgrnam(PKCS_GROUP); if (!grp) { TRACE_ERROR("Could not retrieve \"%s\" group!", PKCS_GROUP); OCK_SYSLOG(LOG_ERR, "POLICY: Could not retrieve \"%s\" group!", PKCS_GROUP); return CKR_GENERAL_ERROR; } if (fstat(fileno(fp), &statbuf)) { err = errno; TRACE_ERROR("Could not stat configuration file %s: %s\n", name, strerror(err)); OCK_SYSLOG(LOG_ERR, "POLICY: Could not stat configuration file %s: %s\n", name, strerror(err)); return CKR_GENERAL_ERROR; } if (statbuf.st_uid != 0) { TRACE_ERROR("Policy configuration file %s should be owned by \"root\"!\n", name); OCK_SYSLOG(LOG_ERR, "POLICY: Configuration file %s should be owned by \"root\"!\n", name); return CKR_GENERAL_ERROR; } if (statbuf.st_gid != grp->gr_gid) { TRACE_ERROR("Policy configuration file %s should have group \"%s\"!\n", name, PKCS_GROUP); OCK_SYSLOG(LOG_ERR, "POLICY: Configuration file %s should have group \"%s\"!\n", name, PKCS_GROUP); return CKR_GENERAL_ERROR; } if ((statbuf.st_mode & ~S_IFMT) != OCK_POLICY_PERMS) { TRACE_ERROR("Configuration file %s has wrong permissions!\n", name); OCK_SYSLOG(LOG_ERR, "POLICY: Configuration file %s has wrong permissions!\n", name); return CKR_GENERAL_ERROR; } return CKR_OK; } /* Policy loading support (externalized for testing purpose) */ void policy_init_policy(struct policy *p) { p->store_object_strength = policy_store_object_strength; p->is_key_allowed = policy_is_key_allowed; p->is_mech_allowed = policy_is_mech_allowed; p->update_mech_info = policy_update_mech_info; p->check_token_store = policy_check_token_store; p->get_sym_key_strength = policy_get_sym_key_strength; p->active = CK_FALSE; } static void parse_error_hook(int line, int col, const char *msg) { TRACE_ERROR("Parse error at %d:%d: %s\n", line, col, msg); } static CK_RV policy_fileversion_check(struct ConfigBaseNode *cfg, char *versionprefix, size_t prefixlen, unsigned int minversion, unsigned int *vers) { const char *filevers; if (!confignode_hastype(cfg, CT_FILEVERSION)) { TRACE_ERROR("Fileversion not found!\n"); return CKR_FUNCTION_FAILED; } filevers = cfg->key; if (strncmp(versionprefix, filevers, prefixlen) != 0 || sscanf(filevers + prefixlen, "%u", vers) != 1 || *vers < minversion) { TRACE_ERROR("Wrong version. Expected \"%s%d\" or higher but got \"%s\"\n", versionprefix, minversion, filevers); return CKR_FUNCTION_FAILED; } cfg->flags = 1; return CKR_OK; } static CK_RV policy_extract_strength_key(struct ConfigIdxStructNode *sd, const char *key, CK_ULONG *val, int i) { struct ConfigBaseNode *n; n = confignode_find(sd->value, key); if (!n) { TRACE_DEVEL("Strength configuration for %lu does not specify %s.\n", supportedstrengths[i], key); *val = ~0u; } else if (!confignode_hastype(n, CT_INTVAL)) { TRACE_ERROR("Strength configuration for %lu does not specify integer value for %s!\n", supportedstrengths[i], key); return CKR_FUNCTION_FAILED; } else { *val = confignode_to_intval(n)->value; n->flags = 1; } return CKR_OK; } static CK_RV policy_check_unmarked(struct ConfigBaseNode *n) { struct ConfigBaseNode *i; CK_RV rc = CKR_OK; int f; confignode_foreach(i, n, f) { if (i->flags != 1) { TRACE_ERROR("Unknown keyword \"%s\" in line %hd\n", i->key, i->line); rc = CKR_FUNCTION_FAILED; } } return rc; } static CK_RV policy_parse_mechlist(struct policy_private *pp, struct ConfigBaseNode *list) { union hashmap_value val = { .ulVal = 0 }; struct ConfigBaseNode *i; const char *mechstr; struct hashmap *h; CK_RV rc = CKR_OK; CK_ULONG mech; int f; h = hashmap_new(); if (!h) return CKR_HOST_MEMORY; if (list) { confignode_foreach(i, list, f) { mechstr = i->key; rc = translate_string_to_mech(mechstr, strlen(mechstr), &mech); if (rc != CKR_OK) { TRACE_ERROR("POLICY: Unknown mechanism: %s (line %hd)\n", mechstr, i->line); break; } if (hashmap_add(h, mech, val, NULL)) { TRACE_ERROR("POLICY: failed to add mechanism to hash!\n"); rc = CKR_HOST_MEMORY; break; } } } pp->allowedmechs = h; return rc; } static CK_RV policy_parse_curvelist(struct policy_private *pp, struct ConfigBaseNode *list) { const struct _ec **curves; struct ConfigBaseNode *i; const struct _ec *curve; int f, count = 0, p = 0; CK_ULONG maxsize = 0; CK_RV rc = CKR_OK; /* Compute size */ if (list) { confignode_foreach(i, list, f) { rc = translate_string_to_curve(i->key, strlen(i->key), &curve); if (rc != CKR_OK) { TRACE_ERROR("POLICY: Unknown curve \"%s\" in line %hd\n", i->key, i->line); OCK_SYSLOG(LOG_ERR, "POLICY: Unknown curve \"%s\" in line %hd\n", i->key, i->line); return rc; } ++count; if (curve->prime_bits > maxsize) maxsize = curve->prime_bits; } } pp->numallowedcurves = count; pp->maxcurvesize = maxsize; if (count == 0) return CKR_OK; curves = calloc(count, sizeof(const struct _ec *)); if (!curves) { TRACE_ERROR("POLICY: Not enough memory for curves array!\n"); return CKR_HOST_MEMORY; } confignode_foreach(i, list, f) { /* Ignore rc since it has been checked before. */ translate_string_to_curve(i->key, strlen(i->key), &curve); curves[p++] = curve; } pp->allowedcurves = curves; return rc; } static CK_RV policy_parse_mgfs(struct policy_private *pp, struct ConfigBaseNode *list) { CK_ULONG smgfs = 0, vmgfs = 0; struct ConfigBaseNode *i; CK_RV rc = CKR_OK; CK_ULONG mgf; int f; if (list) { confignode_foreach(i, list, f) { rc = translate_string_to_mgf(i->key, strlen(i->key), &mgf); if (rc != CKR_OK) { TRACE_ERROR("POLICY: Unknown MGF: \"%s\" (line %hd)\n", i->key, i->line); break; } if (mgf >= CKG_VENDOR_DEFINED) { if ((mgf - CKG_VENDOR_DEFINED - 1) > 31) { TRACE_ERROR("POLICY: MGF invalid: \"%s\" (line %hd)\n", i->key, i->line); rc = CKR_FUNCTION_FAILED; break; } vmgfs |= (1u << (mgf - CKG_VENDOR_DEFINED - 1)); } else { if (mgf > 31) { TRACE_ERROR("POLICY: MGF invalid: \"%s\" (line %hd)\n", i->key, i->line); rc = CKR_FUNCTION_FAILED; break; } smgfs |= (1u << mgf); } } } pp->allowedmgfs = smgfs; pp->allowedvendormgfs = vmgfs; return rc; } static CK_RV policy_parse_kdfs(struct policy_private *pp, struct ConfigBaseNode *list) { struct ConfigBaseNode *i; CK_ULONG kdfs = 0, vkdfs = 0, kdf; CK_RV rc = CKR_OK; int f; if (list) { confignode_foreach(i, list, f) { rc = translate_string_to_kdf(i->key, strlen(i->key), &kdf); if (rc != CKR_OK) { TRACE_ERROR("POLICY: Unknown KDF: \"%s\" (line %hd)\n", i->key, i->line); break; } if (kdf >= CKD_VENDOR_DEFINED) { if ((kdf - CKD_VENDOR_DEFINED - 1) > 31) { TRACE_ERROR("POLICY: KDF invalid: \"%s\" (line %hd)\n", i->key, i->line); rc = CKR_FUNCTION_FAILED; break; } vkdfs |= (1u << (kdf - CKD_VENDOR_DEFINED - 1)); } else { if (kdf > 31) { TRACE_ERROR("POLICY: KDF invalid: \"%s\" (line %hd)\n", i->key, i->line); rc = CKR_FUNCTION_FAILED; break; } kdfs |= (1u << kdf); } } } pp->allowedkdfs = kdfs; pp->allowedvendorkdfs = vkdfs; return rc; } static CK_RV policy_parse_prfs(struct policy_private *pp, struct ConfigBaseNode *list) { struct ConfigBaseNode *i; CK_ULONG prfs = 0, prf; CK_RV rc = CKR_OK; int f; if (list) { confignode_foreach(i, list, f) { rc = translate_string_to_prf(i->key, strlen(i->key), &prf); if (rc != CKR_OK) { TRACE_ERROR("POLICY: Unknown PRF: \"%s\" (line %hd)\n", i->key, i->line); break; } prfs |= (1u << prf); } } pp->allowedprfs = prfs; return rc; } CK_RV policy_load_strength_cfg(struct policy_private *pp, FILE *fp) { struct ConfigIdxStructNode *sd; struct ConfigBaseNode *cfg; CK_RV rc = CKR_OK; unsigned int vers; int i; TRACE_DEVEL("Parsing strength configuration file\n"); if (parse_configlib_file(fp, &cfg, parse_error_hook, 0)) { TRACE_ERROR("Parsing strength configuration failed!\n"); return CKR_FUNCTION_FAILED; } rc = policy_fileversion_check(cfg, "strength-", strlen("strength-"), OCK_STRENGTH_MINVERSION, &vers); if (rc != CKR_OK) goto out; for (i = 0; i < NUM_SUPPORTED_STRENGTHS; ++i) { sd = confignode_findidx(cfg, "strength", supportedstrengths[i]); if (sd) { sd->base.flags = 1; rc = policy_extract_strength_key(sd, "MOD_EXP", &pp->strengths[i].strength.details.modexp, i); if (rc != CKR_OK) goto out; rc = policy_extract_strength_key(sd, "ECC", &pp->strengths[i].strength.details.ecc, i); if (rc != CKR_OK) goto out; rc = policy_extract_strength_key(sd, "SYMMETRIC", &pp->strengths[i].strength.details.symmetric, i); if (rc != CKR_OK) goto out; rc = policy_extract_strength_key(sd, "digest", &pp->strengths[i].strength.details.digests, i); if (rc != CKR_OK) goto out; rc = policy_extract_strength_key(sd, "signature", &pp->strengths[i].strength.details.signatures, i); if (rc != CKR_OK) goto out; pp->strengths[i].set = CK_TRUE; rc = policy_check_unmarked(sd->value); if (rc != CKR_OK) goto out; } else { pp->strengths[i].set = CK_FALSE; } } out: if (rc == CKR_OK) rc = policy_check_unmarked(cfg); confignode_deepfree(cfg); return rc; } CK_RV policy_load_policy_cfg(struct policy_private *pp, FILE *fp, CK_BBOOL *restricting) { struct ConfigBaseNode *cfg, *strength, *allowedmechs, *allowedcurves, *allowedmgfs, *allowedkdfs, *allowedprfs; unsigned long reqstrength; CK_RV rc = CKR_OK; unsigned int vers; int i; *restricting = CK_FALSE; if (parse_configlib_file(fp, &cfg, parse_error_hook, 0)) { TRACE_ERROR("Parsing policy configuration failed!\n"); OCK_SYSLOG(LOG_ERR, "Parsing policy configuration failed!\n"); return CKR_FUNCTION_FAILED; } rc = policy_fileversion_check(cfg, "policy-", strlen("policy-"), OCK_STRENGTH_MINVERSION, &vers); if (rc != CKR_OK) return rc; strength = confignode_find(cfg, "strength"); if (!strength || !confignode_hastype(strength, CT_INTVAL)) { TRACE_ERROR("Invalid strength configuration in policy!\n"); OCK_SYSLOG(LOG_ERR, "Invalid strength configuration in policy!\n"); rc = CKR_FUNCTION_FAILED; goto out; } strength->flags = 1; reqstrength = confignode_to_intval(strength)->value; for (i = 0; i < NUM_SUPPORTED_STRENGTHS; ++i) { if (reqstrength == supportedstrengths[i]) { TRACE_DEVEL("POLICY: Using strength %lu\n", supportedstrengths[i]); break; } else if (reqstrength > supportedstrengths[i]) { if (i > 0) i -= 1; TRACE_DEVEL("POLICY: Using strength %lu\n", supportedstrengths[i]); break; } } if (i == NUM_SUPPORTED_STRENGTHS && reqstrength > 0) { i -=1; TRACE_DEVEL("POLICY: Using strength %lu\n", supportedstrengths[i]); } if (i != NUM_SUPPORTED_STRENGTHS) *restricting = CK_TRUE; pp->minstrengthidx = i; allowedmechs = confignode_find(cfg, "allowedmechs"); if (!allowedmechs) { TRACE_DEVEL("POLICY: No mechanism restriction\n"); } else if (!confignode_hastype(allowedmechs, CT_BARELIST)) { TRACE_ERROR("POLICY: allowedmechs has wrong type!\n"); OCK_SYSLOG(LOG_ERR, "POLICY: allowedmechs has wrong type!\n"); rc = CKR_FUNCTION_FAILED; goto out; } else { *restricting = CK_TRUE; allowedmechs->flags = 1; rc = policy_parse_mechlist(pp, confignode_to_barelist(allowedmechs)->value); if (rc != CKR_OK) goto out; } allowedcurves = confignode_find(cfg, "allowedcurves"); if (!allowedcurves) { TRACE_DEVEL("POLICY: No curve restrictions\n"); pp->allowedcurves = NULL; pp->numallowedcurves = -1; pp->maxcurvesize = 521; } else if (!confignode_hastype(allowedcurves, CT_BARELIST)) { TRACE_ERROR("POLICY: allowedcurves has wrong type!\n"); OCK_SYSLOG(LOG_ERR, "POLICY: allowedcurves has wrong type!\n"); rc = CKR_FUNCTION_FAILED; goto out; } else { *restricting = CK_TRUE; allowedcurves->flags = 1; rc = policy_parse_curvelist(pp, confignode_to_barelist(allowedcurves)-> value); if (rc != CKR_OK) goto out; } allowedmgfs = confignode_find(cfg, "allowedmgfs"); if (!allowedmgfs) { TRACE_DEVEL("POLICY: No MGF restrictions\n"); pp->allowedmgfs = ~0u; pp->allowedvendormgfs = ~0u; } else if (!confignode_hastype(allowedmgfs, CT_BARELIST)) { TRACE_ERROR("POLICY: allowedmgfs has wrong type!\n"); OCK_SYSLOG(LOG_ERR, "POLICY: allowedmgfs has wrong type!\n"); rc = CKR_FUNCTION_FAILED; goto out; } else { *restricting = CK_TRUE; allowedmgfs->flags = 1; rc = policy_parse_mgfs(pp, confignode_to_barelist(allowedmgfs)->value); if (rc != CKR_OK) goto out; } allowedkdfs = confignode_find(cfg, "allowedkdfs"); if (!allowedkdfs) { TRACE_DEVEL("POLICY: No KDF restrictions\n"); pp->allowedkdfs = ~0u; pp->allowedvendorkdfs = ~0u; } else if (!confignode_hastype(allowedkdfs, CT_BARELIST)) { TRACE_ERROR("POLICY: allowedkdfs has wrong type!\n"); OCK_SYSLOG(LOG_ERR, "POLICY: allowedkdfs has wrong type!\n"); rc = CKR_FUNCTION_FAILED; goto out; } else { *restricting = CK_TRUE; allowedkdfs->flags = 1; rc = policy_parse_kdfs(pp, confignode_to_barelist(allowedkdfs)->value); if (rc != CKR_OK) goto out; } allowedprfs = confignode_find(cfg, "allowedprfs"); if (!allowedprfs) { TRACE_DEVEL("POLICY: No PRF restrictions\n"); pp->allowedprfs = ~0u; } else if (!confignode_hastype(allowedprfs, CT_BARELIST)) { TRACE_ERROR("POLICY: allowedprfs has wrong type!\n"); OCK_SYSLOG(LOG_ERR, "POLICY: allowedprfs has wrong type!\n"); rc = CKR_FUNCTION_FAILED; goto out; } else { *restricting = CK_TRUE; allowedprfs->flags = 1; rc = policy_parse_prfs(pp, confignode_to_barelist(allowedprfs)->value); if (rc != CKR_OK) goto out; } out: if (rc == CKR_OK) rc = policy_check_unmarked(cfg); if (rc == CKR_FUNCTION_FAILED) rc = CKR_GENERAL_ERROR; confignode_deepfree(cfg); return rc; } /* Loading and unloading from API library */ CK_RV policy_load(struct policy *p) { FILE *fp = NULL; CK_RV rc = CKR_OK; struct policy_private *pp = NULL; int err; CK_BBOOL restricting = CK_FALSE; policy_init_policy(p); /* Load the strength definition */ fp = fopen(OCK_STRENGTH_CFG, "r"); if (fp == NULL) { err = errno; TRACE_ERROR("Failed to open " OCK_STRENGTH_CFG ": %s\n", strerror(err)); OCK_SYSLOG(LOG_ERR, "POLICY: Failed to open " OCK_STRENGTH_CFG ": %s\n", strerror(err)); rc = CKR_GENERAL_ERROR; goto out; } rc = policy_check_cfg_file(fp, OCK_STRENGTH_CFG); if (rc != CKR_OK) goto out; pp = policy_private_alloc(); if (pp == NULL) { TRACE_ERROR("Could not allocate policy private data!\n"); OCK_SYSLOG(LOG_ERR, "POLICY: Could not allocate policy private data!\n"); rc = CKR_HOST_MEMORY; goto out; } rc = policy_load_strength_cfg(pp, fp); if (rc != CKR_OK) { TRACE_ERROR("Strength definition failed to parse!\n"); OCK_SYSLOG(LOG_ERR, "POLICY: Strength definition %s failed to parse!\n", OCK_STRENGTH_CFG); goto out; } fclose(fp); /* Load the policy definition */ fp = fopen(OCK_POLICY_CFG, "r"); if (fp == NULL) { err = errno; if (errno == ENOENT) { /* If policy does not exit, but strength definition, run * without policy. */ policy_private_deactivate(pp); goto out; } TRACE_ERROR("Failed to open " OCK_POLICY_CFG ": %s\n", strerror(err)); OCK_SYSLOG(LOG_ERR, "POLICY: Failed to open " OCK_POLICY_CFG ": %s\n", strerror(err)); rc = CKR_GENERAL_ERROR; goto out; } rc = policy_check_cfg_file(fp, OCK_POLICY_CFG); if (rc != CKR_OK) goto out; rc = policy_load_policy_cfg(pp, fp, &restricting); if (rc != CKR_OK) { TRACE_ERROR("Policy definition failed to parse!\n"); OCK_SYSLOG(LOG_ERR, "POLICY: Policy definition %s failed to parse!\n", OCK_POLICY_CFG); } out: if (fp) fclose(fp); if (rc != CKR_OK) { pp = policy_private_free(pp); restricting = CK_FALSE; } p->priv = pp; p->active = restricting; return rc; } void policy_unload(struct policy *p) { struct policy_private *pp = p->priv; p->active = CK_FALSE; if (pp) p->priv = policy_private_free(pp); } opencryptoki-opencryptoki-451d99c/usr/lib/api/policy.h000066400000000000000000000112611520105705100231250ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021 * * 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_POLICY_H #define OCK_POLICY_H #include #include "supportedstrengths.h" #define POLICY_CHECK_DIGEST 0 #define POLICY_CHECK_SIGNATURE 1 #define POLICY_CHECK_VERIFY 2 #define POLICY_CHECK_ENCRYPT 3 #define POLICY_CHECK_DECRYPT 4 #define POLICY_CHECK_KEYGEN 5 #define POLICY_CHECK_DERIVE 6 #define POLICY_CHECK_WRAP 7 #define POLICY_CHECK_UNWRAP 8 #define POLICY_CHECK_ENCAPS 9 #define POLICY_CHECK_DECAPS 10 struct policy; typedef struct policy *policy_t; struct _SESSION; struct objstrength { /* Just the index into the supportedstrengths array. */ CK_ULONG strength; CK_ULONG siglen; CK_BBOOL allowed; }; struct tokstore_strength { CK_MECHANISM mk_keygen; CK_MECHANISM mk_crypt; CK_MECHANISM wrap_crypt; /* Next two are just indices into the supportedstrengths array. */ CK_ULONG mk_strength; CK_ULONG wrap_strength; }; /* * Helper function to retrieve attribute values from different * sources. This allows us to implement token specific input to the * policy while the policy drives the whole determination of strength. */ typedef CK_RV (*get_attr_val_f)(void *data, CK_ATTRIBUTE_TYPE type, CK_ATTRIBUTE **attr); /* * Helper function to free a returned attribute. */ typedef void (*free_attr_f)(void *data, CK_ATTRIBUTE *attr); /* * Stores into `obj` the strength and whether or not the EC is * allowed. Returns CKR_FUNCTION_FAILED if the strength is below the * required strength or the curve is not allowed. */ typedef CK_RV (*store_object_strength_f)(policy_t p, struct objstrength *s, get_attr_val_f get_attr_val, void *d, free_attr_f free_attr, struct _SESSION *session); /* * Return CKR_FUNCTION_FAILED if the key is not allowed in the current * policy. */ typedef CK_RV (*is_key_allowed_f)(policy_t p, struct objstrength *s, struct _SESSION *session); /* * Check if a given mechanism is allowed. \c check should be one of * the \c POLICY_CHECK_* values. */ typedef CK_RV (*is_mech_allowed_f)(policy_t p, CK_MECHANISM_PTR mech, struct objstrength *s, int check, struct _SESSION *session); /* * Update the mechanism info for a given mechanism to correctly * reflect the profile. Returns CKR_MECHANISM_INVALID if the * mechanism is not supported in the current profile either due to the * allowed-list or due key size constraints. */ typedef CK_RV (*update_mech_info_f)(policy_t p, CK_MECHANISM_TYPE mech, CK_MECHANISM_INFO_PTR info); /* * Check whether the crypto operations needed by a specific token * store are allowed by the policy. This check only has to be done * once since dynamic policy updates are not supported. */ typedef CK_RV (*check_token_store_f)(policy_t p, CK_BBOOL newversion, CK_MECHANISM_TYPE encalgo, CK_SLOT_ID slot, struct tokstore_strength *ts); /* Get the strength of an AES key of the specified key bit size */ typedef CK_ULONG (*get_aes_key_strength_f)(policy_t p, CK_ULONG aes_key_bits); struct policy { void *priv; CK_BBOOL active; store_object_strength_f store_object_strength; is_key_allowed_f is_key_allowed; is_mech_allowed_f is_mech_allowed; update_mech_info_f update_mech_info; check_token_store_f check_token_store; get_aes_key_strength_f get_sym_key_strength; }; /* * Load the policy and the strength definition into a pre-allocated struct. */ CK_RV policy_load(struct policy *policy); /* * Unload a pre-allocated policy. This does not free \c policy, but * all its contents and resets the policy to an empty one. */ void policy_unload(struct policy *policy); /* * Helper function for store_object_strength_f callbacks. This * function extracts the attribute from a template passed as data. It * does not need a corresponding free function. But either the object * has to be locked or it should not be visible yet. */ CK_RV policy_get_attr_from_template(void *data, CK_ATTRIBUTE_TYPE type, CK_ATTRIBUTE **attr); #endif opencryptoki-opencryptoki-451d99c/usr/lib/api/policyhelper.c000066400000000000000000000012531520105705100243200ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021 * * 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" #include "h_extern.h" CK_RV policy_get_attr_from_template(void *data, CK_ATTRIBUTE_TYPE type, CK_ATTRIBUTE **attr) { TEMPLATE *t = data; return template_attribute_get_non_empty(t, type, attr); } opencryptoki-opencryptoki-451d99c/usr/lib/api/shrd_mem.c.in000066400000000000000000000066301520105705100240300ustar00rootroot00000000000000/* * 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(void) { 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(PKCS_GROUP); 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 } opencryptoki-opencryptoki-451d99c/usr/lib/api/socket_client.c000066400000000000000000000356371520105705100244640ustar00rootroot00000000000000/* * 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 #include #include #include "apiproto.h" #include "slotmgr.h" #include "apictl.h" #include "trace.h" #include "ock_syslog.h" #include "events.h" extern API_Proc_Struct_t *Anchor; int connect_socket(const char *file_path) { int socketfd; struct sockaddr_un daemon_address; struct stat file_info; struct group *grp; struct passwd *pwd; if (stat(file_path, &file_info)) { OCK_SYSLOG(LOG_ERR, "connect_socket: failed to find socket file, errno=%d", errno); return -1; } grp = getgrnam(PKCS_GROUP); if (!grp) { OCK_SYSLOG(LOG_ERR, "connect_socket: %s group does not exist, errno=%d", PKCS_GROUP, errno); return -1; } pwd = getpwnam(PKCSSLOTD_USER); if (!pwd) { OCK_SYSLOG(LOG_ERR, "connect_socket: %s user does not exist, errno=%d", PKCSSLOTD_USER, errno); return -1; } if (file_info.st_uid != pwd->pw_uid || file_info.st_gid != grp->gr_gid) { OCK_SYSLOG(LOG_ERR, "connect_socket: incorrect permissions on socket file"); return -1; } if ((socketfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { OCK_SYSLOG(LOG_ERR, "connect_socket: failed to create socket, errno=%d", errno); return -1; } memset(&daemon_address, 0, sizeof(struct sockaddr_un)); daemon_address.sun_family = AF_UNIX; strncpy(daemon_address.sun_path, file_path, sizeof(daemon_address.sun_path) - 1); daemon_address.sun_path[sizeof(daemon_address.sun_path) - 1] = '\0'; if (connect(socketfd, (struct sockaddr *) &daemon_address, sizeof(struct sockaddr_un)) != 0) { OCK_SYSLOG(LOG_ERR, "connect_socket: failed to connect to slotmanager daemon, " "errno=%d", errno); goto error; } return socketfd; error: close(socketfd); return -1; } static ssize_t read_all(int socketfd, char *buffer, size_t size) { size_t bytes_received = 0; ssize_t n; while (bytes_received < size) { n = read(socketfd, buffer + bytes_received, size - bytes_received); if (n < 0) { // read error if (errno == EINTR) continue; return -errno; } if (n == 0) break; bytes_received += n; } return bytes_received; } static ssize_t send_all(int socketfd, char *buffer, size_t size) { size_t bytes_sent = 0; ssize_t n; while (bytes_sent < size) { n = send(socketfd, buffer + bytes_sent, size - bytes_sent, 0); if (n < 0) { // send error if (errno == EINTR) continue; return -errno; } if (n == 0) break; bytes_sent += n; } return bytes_sent; } // // Will fill out the Slot_Mgr_Socket_t and Slot_Mgr_Client_Cred_t structures // in the Anchor global data structure with the values passed by the pkcsslotd // via a socket RPC. int init_socket_data(int socketfd) { ssize_t n; n = read_all(socketfd, (char *)&Anchor->ClientCred, sizeof(Anchor->ClientCred)); if (n < 0) { // read error OCK_SYSLOG(LOG_ERR, "init_socket_data: read error \ on daemon socket, errno=%zd", -n); return FALSE; } if (n != sizeof(Anchor->ClientCred)) { // 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(Anchor->ClientCred) - n); return FALSE; } n = read_all(socketfd, (char *)&Anchor->SocketDataP, sizeof(Anchor->SocketDataP)); if (n < 0) { // read error OCK_SYSLOG(LOG_ERR, "init_socket_data: read error \ on daemon socket, errno=%zd", -n); return FALSE; } if (n != sizeof(Anchor->SocketDataP)) { // 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(Anchor->SocketDataP) - n); return FALSE; } return TRUE; } static bool match_token_label_filter(event_msg_t *event, API_Slot_t *sltp) { if (event->token_label[0] == ' ' || event->token_label[0] == '\0') return true; return memcmp(event->token_label, sltp->TokData->nv_token_data->token_info.label, sizeof(event->token_label)) == 0; } struct type_model { unsigned int type; char model[member_size(CK_TOKEN_INFO_32, model) + 1]; }; static const struct type_model type_model_flt[] = { { .type = EVENT_TOK_TYPE_CCA, .model = "CCA " }, { .type = EVENT_TOK_TYPE_EP11, .model = "EP11 " }, }; static bool match_token_type_filter(event_msg_t *event, API_Slot_t *sltp) { size_t i; if (event->token_type == EVENT_TOK_TYPE_ALL) return true; for (i = 0; i < sizeof(type_model_flt) / sizeof(struct type_model); i++) { if (memcmp(sltp->TokData->nv_token_data->token_info.model, type_model_flt[i].model, sizeof(sltp->TokData->nv_token_data->token_info.model)) == 0 && (event->token_type & type_model_flt[i].type) != 0) return true; } return false; } static int handle_event(API_Proc_Struct_t *anchor, event_msg_t *event, char *payload, event_reply_t *reply) { CK_SLOT_ID slotID; API_Slot_t *sltp; CK_RV rc; /* If its not for our process, ignore it, don't increment reply counters */ if (event->process_id != 0 && event->process_id != anchor->ClientCred.real_pid) return 0; for (slotID = 0; slotID < NUMBER_SLOTS_MANAGED; slotID++) { sltp = &anchor->SltList[slotID]; if (sltp->DLLoaded == FALSE || sltp->FcnList == NULL) continue; if (!match_token_label_filter(event, sltp)) continue; if (!match_token_type_filter(event, sltp)) continue; if (sltp->FcnList->ST_HandleEvent != NULL) rc = sltp->FcnList->ST_HandleEvent(sltp->TokData, event->type, event->flags, payload, event->payload_len); else rc = CKR_FUNCTION_NOT_SUPPORTED; TRACE_DEVEL("Slot %lu ST_HandleEvent rc: 0x%lx\n", slotID, rc); switch (rc) { case CKR_OK: reply->positive_replies++; break; case CKR_FUNCTION_NOT_SUPPORTED: reply->nothandled_replies++; break; default: reply->negative_replies++; break; } } return 0; } struct cleanup_data { API_Proc_Struct_t *anchor; #if OPENSSL_VERSION_PREREQ(3, 0) OSSL_LIB_CTX *prev_libctx; #endif }; static void event_thread_cleanup(void *arg) { struct cleanup_data *cleanup = arg; #if OPENSSL_VERSION_PREREQ(3, 0) OSSL_LIB_CTX_set0_default(cleanup->prev_libctx); #else UNUSED(cleanup); #endif TRACE_DEVEL("Event thread %lu terminating\n", pthread_self()); } static void *event_thread(void *arg) { API_Proc_Struct_t *anchor = arg; struct cleanup_data cleanup; #if OPENSSL_VERSION_PREREQ(3, 0) OSSL_LIB_CTX *prev_libctx; #endif int oldstate, oldtype; struct pollfd pollfd; event_msg_t event; char *payload; event_reply_t reply; ssize_t num; int rc; UNUSED(arg); pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate); TRACE_DEVEL("Event thread %lu running\n", pthread_self()); if (anchor->socketfd < 0) { TRACE_ERROR("socket is already closed.\n"); TRACE_DEVEL("Event thread %lu terminating\n", pthread_self()); return NULL; } #if OPENSSL_VERSION_PREREQ(3, 0) /* Ensure that the event thread uses Opencryptoki's own library context */ prev_libctx = OSSL_LIB_CTX_set0_default(Anchor->openssl_libctx); if (prev_libctx == NULL) { TRACE_ERROR("OSSL_LIB_CTX_set0_default failed\n"); TRACE_DEVEL("Event thread %lu terminating\n", pthread_self()); return NULL; } #endif /* Enable cancellation */ cleanup.anchor = anchor; #if OPENSSL_VERSION_PREREQ(3, 0) cleanup.prev_libctx = prev_libctx; #endif pthread_cleanup_push(event_thread_cleanup, &cleanup); pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); pollfd.fd = anchor->socketfd; pollfd.events = POLLIN | POLLHUP | POLLERR; while (1) { pollfd.revents = 0; rc = poll(&pollfd, 1, -1); if (rc < 0) { if (errno == EINTR) continue; pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate); TRACE_ERROR("poll failed: %d\n", errno); break; } if (rc == 0) continue; if (pollfd.revents & (POLLHUP | POLLERR)) { pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate); TRACE_ERROR("Error on socket, possibly closed by slot daemon\n"); break; } if ((pollfd.revents & POLLIN) == 0) continue; /* Disable for cancellation while we are working on an event */ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate); TRACE_DEVEL("Receive new event ....\n"); num = read_all(anchor->socketfd, (char *)&event, sizeof(event)); if (num != sizeof(event)) { TRACE_ERROR("Error receiving the event, rc: %zd\n", num); break; } TRACE_DEBUG("Event version: %u\n", event.version); TRACE_DEBUG("Event type: 0x%08x\n", event.type); TRACE_DEBUG("Event flags: 0x%08x\n", event.flags); TRACE_DEBUG("Event token_type: 0x%08x\n", event.token_type); TRACE_DEBUG("Event token_name: '%.32s'\n", event.token_label); TRACE_DEBUG("Event process_id: %u\n", event.process_id); TRACE_DEBUG("Event payload_len: %u\n", event.payload_len); if (event.version != EVENT_VERSION_1) { TRACE_ERROR("Event version invalid: %u\n", event.version); break; } payload = NULL; if (event.payload_len > 0) { payload = malloc(event.payload_len); if (payload == NULL) { TRACE_ERROR("Failed to allocate buffer for event payload\n"); break; } num = read_all(anchor->socketfd, payload, event.payload_len); if (num != (ssize_t)event.payload_len) { TRACE_ERROR("Error receiving the event payload, rc: %zd\n", num); if (payload != NULL) free(payload); break; } TRACE_DEBUG("Event payload:\n"); TRACE_DEBUG_DUMP(" ", payload, event.payload_len); } memset(&reply, 0, sizeof(reply)); reply.version = EVENT_VERSION_1; rc = handle_event(anchor, &event, payload, &reply); if (rc != 0) { TRACE_ERROR("Error handling the event, rc: %d\n", rc); if (payload != NULL) free(payload); break; } TRACE_DEBUG("Reply version: %u\n", reply.version); TRACE_DEBUG("Reply positive: %u\n", reply.positive_replies); TRACE_DEBUG("Reply negative: %u\n", reply.negative_replies); TRACE_DEBUG("Reply not-handled: %u\n", reply.nothandled_replies); if (event.flags & EVENT_FLAGS_REPLY_REQ) { num = send_all(anchor->socketfd, (char *)&reply, sizeof(reply)); if (num != sizeof(reply)) { TRACE_ERROR("Error sending the event reply, rc: %zd\n", num); if (payload != NULL) free(payload); break; } } if (payload != NULL) free(payload); /* Re-enable for and test if we got canceled in the meantime */ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); pthread_testcancel(); } /* * Close the socket if we encounter an unrecoverable error (e.g. received * invalid event) and stop the thread because of that. * If the thread is stopped via stop_event_thread(), then it gets canceled * via pthread_cancel(), and will not reach this place, thus the socket is * not closed. This is intended, and the socket will then be closed by * C_Finalize(). The atfork 'prepare' handler in the parent process also * stops the thread (via stop_event_thread()), and the socket must not be * closed in this case, because the thread is restarted in the atfork * 'parent' handler, and should continue to receive events from the * socket. */ close(anchor->socketfd); anchor->socketfd = -1; #if OPENSSL_VERSION_PREREQ(3, 0) OSSL_LIB_CTX_set0_default(prev_libctx); #endif pthread_cleanup_pop(1); return NULL; } int start_event_thread(void) { int rc; rc = pthread_create(&Anchor->event_thread, NULL, event_thread, Anchor); if (rc != 0) { OCK_SYSLOG(LOG_ERR, "start_event_thread: pthread_create failed, " "errno=%d", rc); TRACE_ERROR("Failed to start event thread, errno=%d\n", rc); return rc; } TRACE_DEVEL("Event thread %lu has been started\n", Anchor->event_thread); return 0; } int stop_event_thread(void) { int rc; void *status; TRACE_DEVEL("Canceling event thread %lu\n", Anchor->event_thread); rc = pthread_cancel(Anchor->event_thread); if (rc != 0 && rc != ESRCH) return rc; TRACE_DEVEL("Waiting for event thread %lu to terminate\n", Anchor->event_thread); rc = pthread_join(Anchor->event_thread, &status); if (rc != 0) return rc; if (status != PTHREAD_CANCELED) { TRACE_ERROR("Event thread was stopped, but did not return the " "expected status\n"); } TRACE_DEVEL("Event thread %lu has terminated\n", Anchor->event_thread); Anchor->event_thread = 0; return 0; } opencryptoki-opencryptoki-451d99c/usr/lib/api/statistics.c000066400000000000000000000444171520105705100240240ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021 * * 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 "statistics.h" #include "trace.h" #include "h_extern.h" #include "ock_syslog.h" #define COMPARE_SYMMETRIC 2 static CK_RV statistics_increment(struct statistics *statistics, CK_SLOT_ID slot, const CK_MECHANISM *mech, CK_ULONG strength_idx) { CK_ULONG ofs; counter_t *counter; int mech_idx; CK_MECHANISM implicit_mech = { 0, NULL, 0 }; CK_ULONG idx, impl_strength_idx; CK_ECDH1_DERIVE_PARAMS ecdh_params = { 0 }; CK_RV rc; if (slot >= NUMBER_SLOTS_MANAGED || strength_idx > POLICY_STRENGTH_IDX_0 || mech == NULL) return CKR_ARGUMENTS_BAD; ofs = statistics->slot_shm_offsets[slot]; if (ofs > statistics->shm_size) return CKR_SLOT_ID_INVALID; mech_idx = mechtable_idx_from_numeric(mech->mechanism); if (mech_idx < 0) return CKR_MECHANISM_INVALID; ofs += mech_idx * (NUM_SUPPORTED_STRENGTHS + 1) * sizeof(counter_t); idx = NUM_SUPPORTED_STRENGTHS - strength_idx; ofs += idx * sizeof(counter_t); if (ofs > statistics->shm_size) return CKR_FUNCTION_FAILED; counter = (counter_t*)(statistics->shm_data + ofs); __sync_add_and_fetch(counter, 1); if ((statistics->flags & STATISTICS_FLAG_COUNT_IMPLICIT) == 0) return CKR_OK; /* deep inspect certain mechanism params for implicit mechanism use */ switch (mech->mechanism) { case CKM_RSA_PKCS_PSS: case CKM_SHA1_RSA_PKCS_PSS: case CKM_SHA224_RSA_PKCS_PSS: case CKM_SHA256_RSA_PKCS_PSS: case CKM_SHA384_RSA_PKCS_PSS: case CKM_SHA512_RSA_PKCS_PSS: case CKM_SHA3_224_RSA_PKCS_PSS: case CKM_SHA3_256_RSA_PKCS_PSS: case CKM_SHA3_384_RSA_PKCS_PSS: case CKM_SHA3_512_RSA_PKCS_PSS: if (mech->pParameter == NULL || mech->ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS)) return CKR_MECHANISM_PARAM_INVALID; implicit_mech.mechanism = ((CK_RSA_PKCS_PSS_PARAMS *)mech->pParameter)->hashAlg; rc = statistics_increment(statistics, slot, &implicit_mech, POLICY_STRENGTH_IDX_0); if (rc != CKR_OK) return rc; rc = get_mgf_mech(((CK_RSA_PKCS_PSS_PARAMS *)mech->pParameter)->mgf, &implicit_mech.mechanism); if (rc != CKR_OK) return rc; rc = statistics_increment(statistics, slot, &implicit_mech, POLICY_STRENGTH_IDX_0); if (rc != CKR_OK) return rc; break; case CKM_RSA_PKCS_OAEP: if (mech->pParameter == NULL || mech->ulParameterLen != sizeof(CK_RSA_PKCS_OAEP_PARAMS)) return CKR_MECHANISM_PARAM_INVALID; implicit_mech.mechanism = ((CK_RSA_PKCS_OAEP_PARAMS *)mech->pParameter)->hashAlg; rc = statistics_increment(statistics, slot, &implicit_mech, POLICY_STRENGTH_IDX_0); if (rc != CKR_OK) return rc; rc = get_mgf_mech(((CK_RSA_PKCS_OAEP_PARAMS *)mech->pParameter)->mgf, &implicit_mech.mechanism); if (rc != CKR_OK) return rc; rc = statistics_increment(statistics, slot, &implicit_mech, POLICY_STRENGTH_IDX_0); if (rc != CKR_OK) return rc; break; case CKM_RSA_AES_KEY_WRAP: if (mech->pParameter == NULL || mech->ulParameterLen != sizeof(CK_RSA_AES_KEY_WRAP_PARAMS)) return CKR_MECHANISM_PARAM_INVALID; if (((CK_RSA_AES_KEY_WRAP_PARAMS *) mech->pParameter)->ulAESKeyBits > 0) { impl_strength_idx = statistics->policy->get_sym_key_strength( statistics->policy, ((CK_RSA_AES_KEY_WRAP_PARAMS *) mech->pParameter)->ulAESKeyBits); implicit_mech.mechanism = CKM_AES_KEY_WRAP; rc = statistics_increment(statistics, slot, &implicit_mech, impl_strength_idx); if (rc != CKR_OK) return rc; } implicit_mech.mechanism = CKM_RSA_PKCS_OAEP; implicit_mech.pParameter = ((CK_RSA_AES_KEY_WRAP_PARAMS *)mech->pParameter)->pOAEPParams; implicit_mech.ulParameterLen = sizeof(CK_RSA_PKCS_OAEP_PARAMS); rc = statistics_increment(statistics, slot, &implicit_mech, strength_idx); if (rc != CKR_OK) return rc; break; case CKM_ECDH1_DERIVE: case CKM_ECDH1_COFACTOR_DERIVE: if (mech->pParameter == NULL || mech->ulParameterLen != sizeof(CK_ECDH1_DERIVE_PARAMS)) return CKR_MECHANISM_PARAM_INVALID; if (((CK_ECDH1_DERIVE_PARAMS *)mech->pParameter)->kdf == CKD_NULL || ((CK_ECDH1_DERIVE_PARAMS *)mech->pParameter)->kdf == CKD_IBM_HYBRID_NULL) break; rc = digest_from_kdf(((CK_ECDH1_DERIVE_PARAMS *)mech->pParameter)->kdf, &implicit_mech.mechanism); if (rc != CKR_OK) return rc; rc = statistics_increment(statistics, slot, &implicit_mech, POLICY_STRENGTH_IDX_0); if (rc != CKR_OK) return rc; break; case CKM_ECDH_AES_KEY_WRAP: case CKM_ECDH_COF_AES_KEY_WRAP: case CKM_ECDH_X_AES_KEY_WRAP: if (mech->pParameter == NULL || mech->ulParameterLen != sizeof(CK_ECDH_AES_KEY_WRAP_PARAMS)) return CKR_MECHANISM_PARAM_INVALID; if (((CK_ECDH_AES_KEY_WRAP_PARAMS *) mech->pParameter)->ulAESKeyBits > 0) { impl_strength_idx = statistics->policy->get_sym_key_strength( statistics->policy, ((CK_ECDH_AES_KEY_WRAP_PARAMS *) mech->pParameter)->ulAESKeyBits); implicit_mech.mechanism = CKM_AES_KEY_WRAP; rc = statistics_increment(statistics, slot, &implicit_mech, impl_strength_idx); if (rc != CKR_OK) return rc; } ecdh_params.kdf = ((CK_ECDH_AES_KEY_WRAP_PARAMS *)mech->pParameter)->kdf; implicit_mech.mechanism = mech->mechanism == CKM_ECDH_COF_AES_KEY_WRAP ? CKM_ECDH1_COFACTOR_DERIVE : CKM_ECDH1_DERIVE; implicit_mech.pParameter = &ecdh_params; implicit_mech.ulParameterLen = sizeof(ecdh_params); rc = statistics_increment(statistics, slot, &implicit_mech, strength_idx); if (rc != CKR_OK) return rc; break; case CKM_IBM_ECDSA_OTHER: if (mech->pParameter == NULL || mech->ulParameterLen != sizeof(CK_IBM_ECDSA_OTHER_PARAMS)) return CKR_MECHANISM_PARAM_INVALID; switch (((CK_IBM_ECDSA_OTHER_PARAMS *)mech->pParameter)->submechanism) { case CKM_IBM_ECSDSA_RAND: case CKM_IBM_ECSDSA_COMPR_MULTI: /* Uses SHA-256 internally */ implicit_mech.mechanism = CKM_SHA256; rc = statistics_increment(statistics, slot, &implicit_mech, POLICY_STRENGTH_IDX_0); if (rc != CKR_OK) return rc; break; case CKM_IBM_BLS: break; } break; case CKM_IBM_BTC_DERIVE: if (mech->pParameter == NULL || mech->ulParameterLen != sizeof(CK_IBM_BTC_DERIVE_PARAMS)) return CKR_MECHANISM_PARAM_INVALID; if (((CK_IBM_BTC_DERIVE_PARAMS *)mech->pParameter)->version != CK_IBM_BTC_DERIVE_PARAMS_VERSION_1) break; switch (((CK_IBM_BTC_DERIVE_PARAMS *)mech->pParameter)->type) { case CK_IBM_BTC_BIP0032_PRV2PRV: case CK_IBM_BTC_BIP0032_PRV2PUB: case CK_IBM_BTC_BIP0032_PUB2PUB: case CK_IBM_BTC_BIP0032_MASTERK: case CK_IBM_BTC_SLIP0010_PRV2PRV: case CK_IBM_BTC_SLIP0010_PRV2PUB: case CK_IBM_BTC_SLIP0010_PUB2PUB: case CK_IBM_BTC_SLIP0010_MASTERK: /* Uses SHA-512 internally */ implicit_mech.mechanism = CKM_SHA512_HMAC; rc = statistics_increment(statistics, slot, &implicit_mech, POLICY_STRENGTH_IDX_0); if (rc != CKR_OK) return rc; break; } break; case CKM_IBM_KYBER: /* Only KEM uses a parameter, KeyGen, Encrypt/Decrypt don't */ if (mech->ulParameterLen != sizeof(CK_IBM_KYBER_PARAMS) && mech->ulParameterLen != 0) return CKR_MECHANISM_PARAM_INVALID; if (mech->ulParameterLen != sizeof(CK_IBM_KYBER_PARAMS)) break; if (mech->pParameter == NULL) return CKR_MECHANISM_PARAM_INVALID; if (((CK_IBM_KYBER_PARAMS *)mech->pParameter)->kdf == CKD_NULL || ((CK_IBM_KYBER_PARAMS *)mech->pParameter)->kdf == CKD_IBM_HYBRID_NULL) break; rc = digest_from_kdf(((CK_IBM_KYBER_PARAMS *)mech->pParameter)->kdf, &implicit_mech.mechanism); if (rc != CKR_OK) return rc; rc = statistics_increment(statistics, slot, &implicit_mech, POLICY_STRENGTH_IDX_0); if (rc != CKR_OK) return rc; break; case CKM_IBM_ML_KEM: if (mech->ulParameterLen != sizeof(CK_IBM_ML_KEM_PARAMS)) return CKR_MECHANISM_PARAM_INVALID; if (mech->pParameter == NULL) return CKR_MECHANISM_PARAM_INVALID; if (((CK_IBM_ML_KEM_PARAMS *)mech->pParameter)->kdf == CKD_NULL || ((CK_IBM_ML_KEM_PARAMS *)mech->pParameter)->kdf == CKD_IBM_HYBRID_NULL) break; rc = digest_from_kdf(((CK_IBM_ML_KEM_PARAMS *)mech->pParameter)->kdf, &implicit_mech.mechanism); if (rc != CKR_OK) return rc; rc = statistics_increment(statistics, slot, &implicit_mech, POLICY_STRENGTH_IDX_0); if (rc != CKR_OK) return rc; break; case CKM_IBM_ML_KEM_WITH_ECDH: if (mech->ulParameterLen != sizeof(CK_IBM_ML_KEM_WITH_ECDH_PARAMS)) return CKR_MECHANISM_PARAM_INVALID; if (mech->pParameter == NULL) return CKR_MECHANISM_PARAM_INVALID; if (((CK_IBM_ML_KEM_WITH_ECDH_PARAMS *)mech->pParameter)->kdf == CKD_NULL || ((CK_IBM_ML_KEM_WITH_ECDH_PARAMS *)mech->pParameter)->kdf == CKD_IBM_HYBRID_NULL) break; rc = digest_from_kdf(((CK_IBM_ML_KEM_WITH_ECDH_PARAMS *)mech->pParameter)->kdf, &implicit_mech.mechanism); if (rc != CKR_OK) return rc; rc = statistics_increment(statistics, slot, &implicit_mech, POLICY_STRENGTH_IDX_0); if (rc != CKR_OK) return rc; break; default: break; } return CKR_OK; } /* * Open the statistics shared memory segment for the specified user. * If user is -1, then it is opened for the current user. * If create is TRUE then the shared memory segment is created if it is not * already existent. */ static CK_RV statistics_open_shm(struct statistics *statistics, int user, CK_BBOOL create) { int i, err, clear = 0, fd; struct stat stat_buf; snprintf(statistics->shm_name, sizeof(statistics->shm_name) - 1, "%s_stats_%u", CONFIG_PATH, user == -1 ? geteuid() : (uid_t)user); for (i = 1; statistics->shm_name[i] != '\0'; i++) { if (statistics->shm_name[i] == '/') statistics->shm_name[i] = '.'; } if (statistics->shm_name[0] != '/') { memmove(&statistics->shm_name[1], &statistics->shm_name[0], strlen(statistics->shm_name) + 1); statistics->shm_name[0] = '/'; } TRACE_INFO("Statistics SHM name: '%s'\n", statistics->shm_name); fd = shm_open(statistics->shm_name, O_RDWR, S_IRUSR | S_IWUSR); if (fd == -1) { if (create) { /* try to create it */ fd = shm_open(statistics->shm_name, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); if (fd == -1) { err = errno; TRACE_ERROR("Failed to create SHM '%s': %s\n", statistics->shm_name, strerror(err)); OCK_SYSLOG(LOG_ERR, "Failed to create SHM '%s': %s\n", statistics->shm_name, strerror(err)); return CKR_FUNCTION_FAILED; } if (fchmod(fd, S_IRUSR | S_IWUSR) == -1) { err = errno; TRACE_ERROR("Failed to change mode of SHM '%s': %s\n", statistics->shm_name, strerror(err)); OCK_SYSLOG(LOG_ERR, "Failed to change mode of SHM '%s': %s\n", statistics->shm_name, strerror(err)); close(fd); shm_unlink(statistics->shm_name); return CKR_FUNCTION_FAILED; } } else { err = errno; TRACE_ERROR("Failed to open SHM '%s': %s\n", statistics->shm_name, strerror(err)); OCK_SYSLOG(LOG_ERR, "Failed to open SHM '%s': %s\n", statistics->shm_name, strerror(err)); return CKR_FUNCTION_FAILED; } } if (fstat(fd, &stat_buf)) { err = errno; TRACE_ERROR("Failed to stat SHM '%s': %s\n", statistics->shm_name, strerror(err)); OCK_SYSLOG(LOG_ERR, "Failed to stat SHM '%s': %s\n", statistics->shm_name, strerror(err)); close(fd); return CKR_FUNCTION_FAILED; } /* * If the shared memory segment does not belong to the current user or does * not have correct permissions, do not use it. */ if (stat_buf.st_uid != geteuid() || (stat_buf.st_mode & ~S_IFMT) != (S_IRUSR | S_IWUSR)) { TRACE_ERROR("SHM '%s' has wrong mode/owner\n", statistics->shm_name); OCK_SYSLOG(LOG_ERR, "SHM '%s' has wrong mode/owner\n", statistics->shm_name); close(fd); return CKR_FUNCTION_FAILED; } if ((CK_ULONG)stat_buf.st_size != statistics->shm_size) { if (create) { if (ftruncate(fd, statistics->shm_size) < 0) { err = errno; TRACE_ERROR("Failed to set size of SHM '%s': %s\n", statistics->shm_name, strerror(err)); OCK_SYSLOG(LOG_ERR, "Failed to set size of SHM '%s': %s\n", statistics->shm_name, strerror(err)); close(fd); return CKR_FUNCTION_FAILED; } clear = 1; } else { TRACE_ERROR("SHM '%s' has wrong size\n", statistics->shm_name); OCK_SYSLOG(LOG_ERR, "SHM '%s' has wrong size\n", statistics->shm_name); close(fd); return CKR_FUNCTION_FAILED; } } statistics->shm_data = (CK_BYTE *)mmap(NULL, statistics->shm_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); close(fd); if (statistics->shm_data == MAP_FAILED) { err = errno; TRACE_ERROR("Failed to memory-map SHM '%s': %s\n", statistics->shm_name, strerror(err)); OCK_SYSLOG(LOG_ERR, "Failed to memory-map SHM '%s': %s\n", statistics->shm_name, strerror(err)); statistics->shm_data = NULL; return CKR_FUNCTION_FAILED; } if (clear) memset(statistics->shm_data, 0, statistics->shm_size); return CKR_OK; } static CK_RV statistics_close_shm(struct statistics *statistics, CK_BBOOL destroy) { CK_RV rc; if (statistics->shm_data == NULL) return CKR_ARGUMENTS_BAD; munmap(statistics->shm_data, statistics->shm_size); if (destroy) { rc = shm_unlink(statistics->shm_name); if (rc != 0) { TRACE_ERROR("Failed to unlink SHM '%s': %s\n", statistics->shm_name, strerror(errno)); return CKR_FUNCTION_FAILED; } } statistics->shm_data = NULL; statistics->shm_size = -1; return CKR_OK; } CK_RV statistics_init(struct statistics *statistics, Slot_Mgr_Socket_t *slots_infos, CK_ULONG flags, uid_t uid, struct policy *policy) { CK_ULONG i; CK_RV rc; statistics->flags = flags; statistics->shm_data = NULL; /* Count number of configured slots and calculate slot offsets. */ statistics->num_slots = 0; for (i = 0; i < NUMBER_SLOTS_MANAGED; i++) { if (slots_infos->slot_info[i].present) { statistics->slot_shm_offsets[i] = statistics->num_slots * STAT_SLOT_SIZE; statistics->num_slots++; } else { statistics->slot_shm_offsets[i] = (CK_ULONG)-1; } } statistics->shm_size = statistics->num_slots * STAT_SLOT_SIZE; TRACE_INFO("%lu slots defined\n", statistics->num_slots); TRACE_INFO("Statistics SHM size: %lu\n", statistics->shm_size); rc = statistics_open_shm(statistics, uid, CK_TRUE); if (rc != CKR_OK) goto error; statistics->increment_func = statistics_increment; statistics->policy = policy; return CKR_OK; error: statistics_term(statistics); return rc; } void statistics_term(struct statistics *statistics) { statistics_close_shm(statistics, CK_FALSE); } opencryptoki-opencryptoki-451d99c/usr/lib/api/statistics.h000066400000000000000000000052341520105705100240230ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021 * * 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_STATISTICS_H #define OCK_STATISTICS_H #include #include "slotmgr.h" #include "mechtable.h" #include "supportedstrengths.h" #include "policy.h" /* * Statistics are collected in a shared memory segment per user. * The statistics shared memory segment has the following layout: * - For each configured slot: * - For each supported mechanism: * - one counter (counter_t) for non-key mechanisms (strength=0) * - one counter for each supported strength (counter_t each) * * The size of the shared segment therefore is: * Num configured slots * num supp.mechanisms * (num supp. strength + 1) * * size of a counter */ typedef CK_ULONG counter_t; #define STAT_MECH_SIZE ((NUM_SUPPORTED_STRENGTHS + 1) * sizeof(counter_t)) #define STAT_SLOT_SIZE (MECHTABLE_NUM_ELEMS * STAT_MECH_SIZE) struct statistics; typedef struct statistics *statistics_t; typedef CK_RV (*statistics_increment_f)(struct statistics *statistics, CK_SLOT_ID slot, const CK_MECHANISM *mech, CK_ULONG strength); #define STATISTICS_FLAG_COUNT_IMPLICIT (1 << 0) #define STATISTICS_FLAG_COUNT_INTERNAL (1 << 1) struct statistics { CK_ULONG flags; CK_ULONG num_slots; CK_ULONG slot_shm_offsets[NUMBER_SLOTS_MANAGED]; CK_ULONG shm_size; char shm_name[PATH_MAX]; CK_BYTE *shm_data; statistics_increment_f increment_func; /* NULL if statistics disabled */ struct policy *policy; }; #define INC_COUNTER(tokdata, sess, mech, key, no_key_strength) \ do { \ if ((tokdata)->statistics->increment_func != NULL) \ (tokdata)->statistics->increment_func((tokdata)->statistics, \ (sess)->session_info.slotID, (mech), (key) != NULL ? \ ((OBJECT *)(key))->strength.strength : (no_key_strength));\ } while (0) CK_RV statistics_init(struct statistics *statistics, Slot_Mgr_Socket_t *slots_infos, CK_ULONG flags, uid_t uid, struct policy *policy); void statistics_term(struct statistics *statistics); #endif opencryptoki-opencryptoki-451d99c/usr/lib/api/supportedstrengths.c000066400000000000000000000014611520105705100256110ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021 * * 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 "supportedstrengths.h" /* This file exists to allow external tools to access the supported strengths array without adding dependencies on the policy implementations. */ /* Specifies the strength value corresponding to the index of the strengths array. KEEP IN SYNC! ALSO KEEP IN DESCENDING ORDER! */ const CK_ULONG supportedstrengths[NUM_SUPPORTED_STRENGTHS] = { 256, 192, 128, 112 }; opencryptoki-opencryptoki-451d99c/usr/lib/api/supportedstrengths.h000066400000000000000000000015221520105705100256140ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021 * * 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_SUPPORTEDSTRENGTHS_H #define OCK_SUPPORTEDSTRENGTHS_H /* The number of supported non-0 strengths. */ #define NUM_SUPPORTED_STRENGTHS 4 #define POLICY_STRENGTH_IDX_0 NUM_SUPPORTED_STRENGTHS #define POLICY_STRENGTH_IDX_112 3 #define POLICY_STRENGTH_IDX_128 2 #define POLICY_STRENGTH_IDX_192 1 #define POLICY_STRENGTH_IDX_256 0 /* Non-0 supported strengths in descending order. */ extern const CK_ULONG supportedstrengths[NUM_SUPPORTED_STRENGTHS]; #endif opencryptoki-opencryptoki-451d99c/usr/lib/cca_stdll/000077500000000000000000000000001520105705100226335ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/usr/lib/cca_stdll/LICENSE000066400000000000000000000265351520105705100236530ustar00rootroot00000000000000Common 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. opencryptoki-opencryptoki-451d99c/usr/lib/cca_stdll/cca_func.h000066400000000000000000001776751520105705100245740ustar00rootroot00000000000000/* * 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 Token Change 2 */ typedef void (*CSNBKTC2_t) (long *return_code, long *reason_code, long *exit_data_length, unsigned char *exit_data, long *rule_array_count, unsigned char *rule_array, long *key_identifier_length, unsigned char *key_identifier); /* Key Translate */ typedef void (*CSNBKTR_t) (long *return_code, long *reason_code, 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); /* 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); /* Symmetric Key Import 2 */ typedef void (*CSNDSYI2_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 *transport_key_length, unsigned char *transport_key, long *key_name_len, unsigned char *key_name, long *target_key_identifier_length, unsigned char *target_key_identifier); /* 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); /*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); /* 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); /* Cipher Text Translate 2 */ typedef void (*CSNBCTT2_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_in_length, unsigned char *key_identifier_in, long *init_vector_in_length, unsigned char *init_vector_in, long *cipher_text_in_length, unsigned char *cipher_text_in, long *chaining_vector_length, unsigned char *chaining_vector, long *key_identifier_out_length, unsigned char *key_identifier_out, long *init_vector_out_length, unsigned char *init_vector_out, long *cipher_text_out_length, unsigned char *cipher_text_out, long *reserved1_length, unsigned long *reserved1, long *reserved2_length, unsigned char *reserved2); /* Cryptographic Facility Version */ typedef void (*CSUACFV_t)(long *return_code, long *reason_code, long *exit_data_length, unsigned char *exit_data, long *version_data_length, unsigned char *version_data); /* Restrict Key Attribute */ typedef void (*CSNBRKA_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 *ey_encrypting_key_identifier_length, unsigned char *ey_encrypting_key_identifier, long *opt_parameter1_length, unsigned char *opt_parameter1, long *opt_parameter2_length, unsigned char *opt_parameter2); /* Key Translate2 */ typedef void (*CSNBKTR2_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_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); /* CCA EC Diffie-Hellman function */ typedef void (*CSNDEDH_t)(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_info_length, unsigned char *party_info, long *key_bit_length, 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 *output_KEK_key_identifier_length, unsigned char *output_KEK_key_identifier, long *output_key_identifier_length, unsigned char *output_key_identifier); opencryptoki-opencryptoki-451d99c/usr/lib/cca_stdll/cca_mkchange.c000066400000000000000000002351541520105705100253740ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2023 * * 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 "platform.h" #include "p11util.h" #include "defs.h" #include "host_defs.h" #include "h_extern.h" #include "ock_syslog.h" #include "trace.h" #include "events.h" #include "cfgparser.h" #include "cca_stdll.h" static CK_RV cca_reencipher_sec_key(STDLL_TokData_t *tokdata, struct cca_mk_change_op *mk_change_op, CK_BYTE *sec_key, CK_BYTE *reenc_sec_key, CK_ULONG sec_key_len, CK_BBOOL from_old); struct cca_select_single_data { struct cca_mk_change_op *mk_change_op; struct cca_mk_change_op *mk_change_op2; CK_BBOOL prefer_new_mk; enum cca_mk_type mk_type; enum cca_mk_type mk_type2; char serialno[CCA_SERIALNO_LENGTH + 1]; unsigned short card; unsigned short domain; CK_BBOOL found; CK_BBOOL preferred_found; }; static CK_BBOOL cca_select_single_apqn_check_mkvp( STDLL_TokData_t *tokdata, const struct cca_mk_change_op *mk_change_op, enum cca_mk_type mk_type, CK_BBOOL prefer_new_mk, const unsigned char *cur_sym, const unsigned char *cur_aes, const unsigned char *cur_apka) { struct cca_private_data *cca_private = tokdata->private_data; CK_BBOOL preferred_found = FALSE; switch (mk_type) { case CCA_MK_SYM: if (prefer_new_mk && mk_change_op->new_sym_mkvp_set && memcmp(cur_sym, mk_change_op->new_sym_mkvp, CCA_MKVP_LENGTH) == 0) preferred_found = TRUE; if (prefer_new_mk == FALSE && memcmp(cur_sym, cca_private->expected_sym_mkvp, CCA_MKVP_LENGTH) == 0) preferred_found = TRUE; break; case CCA_MK_AES: if (prefer_new_mk && mk_change_op->new_aes_mkvp_set && memcmp(cur_aes, mk_change_op->new_aes_mkvp, CCA_MKVP_LENGTH) == 0) preferred_found = TRUE; if (prefer_new_mk == FALSE && memcmp(cur_aes, cca_private->expected_aes_mkvp, CCA_MKVP_LENGTH) == 0) preferred_found = TRUE; break; case CCA_MK_APKA: if (prefer_new_mk && mk_change_op->new_apka_mkvp_set && memcmp(cur_apka, mk_change_op->new_apka_mkvp, CCA_MKVP_LENGTH) == 0) preferred_found = TRUE; if (prefer_new_mk == FALSE && memcmp(cur_apka, cca_private->expected_apka_mkvp, CCA_MKVP_LENGTH) == 0) preferred_found = TRUE; break; default: return FALSE; } return preferred_found; } static CK_RV cca_select_single_apqn_cb(STDLL_TokData_t *tokdata, const char *adapter, unsigned short card, unsigned short domain, void *private) { struct cca_select_single_data *ssd = private; unsigned char cur_sym[CCA_MKVP_LENGTH]; unsigned char cur_aes[CCA_MKVP_LENGTH]; unsigned char cur_apka[CCA_MKVP_LENGTH]; CK_RV rc; if (ssd->preferred_found) return CKR_OK; TRACE_DEVEL("%s Adapter %s (%02X.%04X)\n", __func__, adapter, card, domain); rc = cca_get_mkvps(cur_sym, NULL, cur_aes, NULL, cur_apka, NULL); if (rc != CKR_OK) return CKR_OK; /* adapter may be offline */ ssd->preferred_found = cca_select_single_apqn_check_mkvp(tokdata, ssd->mk_change_op, ssd->mk_type, ssd->prefer_new_mk, cur_sym, cur_aes, cur_apka); if (ssd->mk_change_op2 != NULL) ssd->preferred_found &= cca_select_single_apqn_check_mkvp(tokdata, ssd->mk_change_op2, ssd->mk_type2, ssd->prefer_new_mk, cur_sym, cur_aes, cur_apka); rc = cca_get_adapter_serial_number(ssd->serialno); if (rc != CKR_OK) return CKR_OK; /* adapter may be offline */ ssd->card = card; ssd->domain = domain; ssd->found = TRUE; return CKR_OK; } static enum cca_mk_type cca_mk_type_from_key_type(enum cca_token_type keytype) { switch (keytype) { case sec_des_data_key: return CCA_MK_SYM; case sec_aes_data_key: case sec_aes_cipher_key: case sec_hmac_key: return CCA_MK_AES; case sec_rsa_priv_key: case sec_ecc_priv_key: case sec_qsa_priv_key: return CCA_MK_APKA; default: return -1; } } struct cca_mk_change_op *cca_mk_change_find_op_by_keytype( STDLL_TokData_t *tokdata, enum cca_token_type keytype) { struct cca_private_data *cca_private = tokdata->private_data; enum cca_mk_type mk_type = cca_mk_type_from_key_type(keytype); unsigned int idx; if (cca_mk_change_find_mkvp_in_ops(tokdata, mk_type, &idx) == NULL) return NULL; return &cca_private->mk_change_ops[idx]; } /* * Must NOT hold the CCA adapter lock when called ! * When a single APQN was selected (rc = CKR_OK), it holds the WRITE lock on * return. The lock must be released by the caller, once selection has been * turned back to default by using cca_deselect_single_apqn(). * No lock is held in case of an error. */ static CK_RV cca_select_single_apqn(STDLL_TokData_t *tokdata, struct cca_mk_change_op *mk_change_op, struct cca_mk_change_op *mk_change_op2, CK_BBOOL prefer_new_mk, enum cca_token_type keytype, enum cca_token_type keytype2, char *serialno, CK_BBOOL *preferred_selected, CK_BBOOL wait_for_new_wk) { struct cca_private_data *cca_private = tokdata->private_data; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; long return_code, reason_code, rule_array_count, device_name_len; unsigned char *device_name; struct cca_select_single_data ssd = { 0 }; int retries = 0; CK_RV rc; retry: ssd.mk_change_op = mk_change_op; ssd.mk_change_op2 = mk_change_op2; ssd.prefer_new_mk = prefer_new_mk; ssd.mk_type = cca_mk_type_from_key_type(keytype); ssd.mk_type2 = cca_mk_type_from_key_type(keytype2); rc = cca_iterate_adapters(tokdata, cca_select_single_apqn_cb, &ssd); if (rc != CKR_OK) return rc; if (ssd.found == FALSE) { TRACE_ERROR("No single CCA APQN found\n"); return CKR_DEVICE_ERROR; } TRACE_DEVEL("single APQN %02X.%04X (Serialno %s) selected\n", ssd.card, ssd.domain, ssd.serialno); TRACE_DEVEL("APQN with preferred MK found: %d\n", ssd.preferred_found); if (preferred_selected != NULL) *preferred_selected = ssd.preferred_found; if (prefer_new_mk && wait_for_new_wk && !ssd.preferred_found) { TRACE_DEVEL("%s no APQN with new MK set found, retry in 1 second\n", __func__); retries++; if (retries > 3600) /* Retry for max 1 hour */ return CKR_DEVICE_ERROR; sleep(1); goto retry; } /* * If neither DEV-ANY, nor DOM-ANY is specified, no need to allocate the * adapter, it's a single adapter/domain configuration anyway. */ if (!cca_private->dev_any && !cca_private->dom_any) goto done; /* Allocate the adapter */ memcpy(rule_array, "SERIAL ", CCA_KEYWORD_SIZE ); rule_array_count = 1; device_name_len = strlen(ssd.serialno); device_name = (unsigned char *)ssd.serialno; if (cca_private->dom_any) { sprintf((char *)(rule_array + CCA_KEYWORD_SIZE), "DOMN%04u", ssd.domain); rule_array_count = 2; if (pthread_rwlock_wrlock(&cca_adapter_rwlock) != 0) { TRACE_DEVEL("CCA adapter WR-Lock failed.\n"); return CKR_CANT_LOCK; } } dll_CSUACRA(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &device_name_len, device_name); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSUACRA failed. return:%ld, reason:%ld\n", return_code, reason_code); if (pthread_rwlock_unlock(&cca_adapter_rwlock) != 0) { TRACE_DEVEL("CCA adapter Unlock failed.\n"); return CKR_CANT_LOCK; } return CKR_FUNCTION_FAILED; } done: strncpy(serialno, ssd.serialno, CCA_SERIALNO_LENGTH + 1); serialno[CCA_SERIALNO_LENGTH] = '\0'; return CKR_OK; } /* Does NOT unlock the CCA adapter lock ! */ CK_RV cca_deselect_single_apqn(STDLL_TokData_t *tokdata, char *serialno) { struct cca_private_data *cca_private = tokdata->private_data; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; long return_code, reason_code, rule_array_count, device_name_len; unsigned char *device_name; /* * If neither DEV-ANY, nor DOM-ANY is specified, no need to deallocate the * adapter, it's a single adapter/domain configuration anyway. */ if (!cca_private->dev_any && !cca_private->dom_any) return CKR_OK; /* Deallocate the adapter */ memcpy(rule_array, "SERIAL ", CCA_KEYWORD_SIZE); rule_array_count = 1; device_name_len = strlen(serialno); device_name = (unsigned char *)serialno; if (cca_private->dom_any) { memcpy(rule_array + CCA_KEYWORD_SIZE, "DOMN-DEF", CCA_KEYWORD_SIZE); rule_array_count = 2; } dll_CSUACRD(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &device_name_len, device_name); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSUACRD failed. return:%ld, reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } return CKR_OK; } /* Must NOT hold the CCA adapter lock when called ! */ CK_RV cca_reencipher_created_key(STDLL_TokData_t *tokdata, TEMPLATE* tmpl, CK_BYTE *sec_key, CK_ULONG sec_key_len, CK_BBOOL new_mk, enum cca_token_type keytype, CK_BBOOL aes_xts_2dn_key) { struct cca_private_data *cca_private = tokdata->private_data; struct cca_mk_change_op *mk_change_op; char serialno[CCA_SERIALNO_LENGTH + 1]; CK_BBOOL new_selected = FALSE; CK_BYTE reenc_sec_key[CCA_KEY_TOKEN_SIZE] = { 0 }; CK_RV rc, rc2; CK_ULONG retries = 0; CK_ATTRIBUTE *reenc_attr = NULL; CK_BYTE reenc_buf[CCA_KEY_TOKEN_SIZE * 2] = { 0 }; if (sec_key_len > sizeof(reenc_sec_key)) { TRACE_ERROR("%s sec_key_len too large: %lu\n", __func__, sec_key_len); return CKR_ARGUMENTS_BAD; } mk_change_op = cca_mk_change_find_op_by_keytype(tokdata, keytype); if (mk_change_op == NULL) return CKR_OK; if (new_mk) { memcpy(reenc_sec_key, sec_key, sec_key_len); goto add_attr; } /* Try to re-encipher to new MK */ rc = cca_reencipher_sec_key(tokdata, mk_change_op, sec_key, reenc_sec_key, sec_key_len, FALSE); if (rc == CKR_OK) goto add_attr; TRACE_ERROR("%s cca_reencipher_sec_key failed: 0x%lx\n", __func__, rc); if (rc != CKR_DEVICE_ERROR) return rc; retry: /* Try to select a APQN with new MK set/activated */ rc = cca_select_single_apqn(tokdata, mk_change_op, NULL, TRUE, keytype, 0, serialno, &new_selected, FALSE); if (rc != CKR_OK) { TRACE_ERROR("%s cca_select_single_apqn failed: 0x%lx\n", __func__, rc); return rc; } TRACE_DEVEL("%s new_selected: %d\n", __func__, new_selected); /* * Retry re-enciphering, from-OLD if APQN with new MK was selected, * otherwise try to-NEW again. */ rc = cca_reencipher_sec_key(tokdata, mk_change_op, sec_key, reenc_sec_key, sec_key_len, new_selected); if (rc != CKR_OK) TRACE_ERROR("%s cca_reencipher_sec_key (2) failed: 0x%lx\n", __func__, rc); rc2 = cca_deselect_single_apqn(tokdata, serialno); /* cca_select_single_apqn() got the WRITE lock, unlock it now */ if (cca_private->dom_any) { if (pthread_rwlock_unlock(&cca_adapter_rwlock) != 0) { TRACE_ERROR("CCA adapter Unlock failed.\n"); return CKR_CANT_LOCK; } } if (rc2 != CKR_OK) { TRACE_ERROR("%s cca_deselect_single_apqn failed: 0x%lx\n", __func__, rc2); return rc2; } if (rc == CKR_OK) goto add_attr; /* * If re-enciphering to-New has failed because the selected single APQN * with old MK set has just got the new MK set, re-select a single APQN * (preferably with new MK set) and retry. We should then get an APQN with * the new MK set and then perform a re-encipher from-OLD. */ if (new_selected == FALSE && rc == CKR_DEVICE_ERROR && retries < 2) { retries++; goto retry; } return rc; add_attr: if (aes_xts_2dn_key) { rc = template_attribute_get_non_empty(tmpl, CKA_IBM_OPAQUE_REENC, &reenc_attr); if (rc == CKR_OK && reenc_attr->ulValueLen == sec_key_len) { memcpy(reenc_buf, reenc_attr->pValue, sec_key_len); memcpy(reenc_buf + reenc_attr->ulValueLen, reenc_sec_key, sec_key_len); rc = build_update_attribute(tmpl, CKA_IBM_OPAQUE_REENC, reenc_buf, sec_key_len * 2); if (rc != CKR_OK) { TRACE_DEVEL("build_update_attribute(CKA_IBM_OPAQUE_REENC) failed\n"); return rc; } return CKR_OK; } } rc = build_update_attribute(tmpl, CKA_IBM_OPAQUE_REENC, reenc_sec_key, sec_key_len); if (rc != CKR_OK) { TRACE_DEVEL("build_update_attribute(CKA_IBM_OPAQUE_REENC) failed\n"); return rc; } return CKR_OK; } /* Called with CCA adapter READ lock held (if DOM-ANY) */ CK_BBOOL cca_check_blob_select_single_apqn(STDLL_TokData_t *tokdata, const CK_BYTE *sec_key1, CK_ULONG sec_key1_len, const CK_BYTE *sec_key2, CK_ULONG sec_key2_len, char *serialno) { struct cca_private_data *cca_private = tokdata->private_data; enum cca_token_type keytype1, keytype2 = -1; unsigned int keybitsize1, keybitsize2; const CK_BYTE *mkvp1, *mkvp2; CK_BBOOL new_mk1 = FALSE, new_mk2 = FALSE, new_selected = FALSE; struct cca_mk_change_op *mk_change_op1 = NULL, *mk_change_op2 = NULL; if (analyse_cca_key_token(sec_key1, sec_key1_len, &keytype1, &keybitsize1, &mkvp1) == FALSE) return FALSE; if (check_expected_mkvp(tokdata, keytype1, mkvp1, &new_mk1) != CKR_OK) return FALSE; TRACE_DEVEL("%s new_mk1: %d\n", __func__, new_mk1); mk_change_op1 = cca_mk_change_find_op_by_keytype(tokdata, keytype1); if (sec_key2 != NULL) { if (analyse_cca_key_token(sec_key2, sec_key2_len, &keytype2, &keybitsize2, &mkvp2) == FALSE) return FALSE; if (check_expected_mkvp(tokdata, keytype1, mkvp1, &new_mk1) != CKR_OK) return FALSE; TRACE_DEVEL("%s new_mk1: %d\n", __func__, new_mk1); mk_change_op2 = cca_mk_change_find_op_by_keytype(tokdata, keytype2); } if (new_mk1 == FALSE && new_mk2 == FALSE) return FALSE; if (mk_change_op1 == NULL && mk_change_op2 == NULL) return FALSE; /* * Unlock CCA adapter lock (if DOM-ANY), cca_select_single_apqn() will * get WRITE lock. */ if (cca_private->dom_any) { if (pthread_rwlock_unlock(&cca_adapter_rwlock) != 0) { TRACE_ERROR("CCA adapter Unlock failed.\n"); return FALSE; } } /* Select a single APQN with new MK(s) set, wait if required */ TRACE_DEVEL("%s select single APQN with new MK set, wait if needed\n", __func__); if (cca_select_single_apqn(tokdata, mk_change_op1, mk_change_op2, TRUE, keytype1, keytype2, serialno, &new_selected, TRUE) != CKR_OK) new_selected = FALSE; /* Need to get RD-lock again in case no new APQN was selected */ if (!new_selected && cca_private->dom_any) { if (pthread_rwlock_rdlock(&cca_adapter_rwlock) != 0) { TRACE_ERROR("CCA adapter RD-Lock failed.\n"); return FALSE; } } return new_selected; } struct cca_affected_data { struct hsm_mk_change_info *info; CK_BBOOL affected; }; static CK_RV cca_mk_change_is_affected_cb(STDLL_TokData_t *tokdata, const char *adapter, unsigned short card, unsigned short domain, void *private) { struct cca_affected_data *ad = private; UNUSED(tokdata); if (hsm_mk_change_apqns_find(ad->info->apqns, ad->info->num_apqns, card, domain)) { TRACE_DEVEL("%s APQN %02X.%04X (%s) is affected by MK change\n", __func__, card, domain, adapter); ad->affected = TRUE; } return CKR_OK; } static CK_RV cca_mk_change_is_affected(STDLL_TokData_t *tokdata, struct hsm_mk_change_info *info) { unsigned int i; CK_BBOOL affected = FALSE; struct cca_affected_data ad; CK_RV rc; for (i = 0; i < info->num_mkvps; i++) { TRACE_DEVEL("%s MK type: %d\n", __func__, info->mkvps[i].type); switch (info->mkvps[i].type) { case HSM_MK_TYPE_CCA_SYM: case HSM_MK_TYPE_CCA_AES: case HSM_MK_TYPE_CCA_APKA: affected = TRUE; break; default: break; } } if (!affected) goto out; ad.info = info; ad.affected = FALSE; rc = cca_iterate_adapters(tokdata, cca_mk_change_is_affected_cb, &ad); if (rc != CKR_OK) { TRACE_ERROR("%s cca_iterate_adapters failed: 0x%lx\n", __func__, rc); return rc; } affected = ad.affected; out: TRACE_DEVEL("%s affected: %d\n", __func__, affected); return affected ? CKR_OK : CKR_FUNCTION_NOT_SUPPORTED; } unsigned char *cca_mk_change_find_mkvp_in_ops(STDLL_TokData_t *tokdata, enum cca_mk_type mk_type, unsigned int *idx) { struct cca_private_data *cca_private = tokdata->private_data; unsigned int i; for (i = 0; i < CCA_NUM_MK_TYPES; i++) { if (cca_private->mk_change_ops[i].mk_change_active) { switch (mk_type) { case CCA_MK_SYM: if (cca_private->mk_change_ops[i].new_sym_mkvp_set) { if (idx != NULL) *idx = i; return cca_private->mk_change_ops[i].new_sym_mkvp; } break; case CCA_MK_AES: if (cca_private->mk_change_ops[i].new_aes_mkvp_set) { if (idx != NULL) *idx = i; return cca_private->mk_change_ops[i].new_aes_mkvp; } break; case CCA_MK_APKA: if (cca_private->mk_change_ops[i].new_apka_mkvp_set) { if (idx != NULL) *idx = i; return cca_private->mk_change_ops[i].new_apka_mkvp; } break; default: break; } } } return NULL; } static struct cca_mk_change_op *cca_mk_change_find_op(STDLL_TokData_t *tokdata, const char *op, unsigned int *idx) { struct cca_private_data *cca_private = tokdata->private_data; unsigned int i; for (i = 0; i < CCA_NUM_MK_TYPES; i++) { if (cca_private->mk_change_ops[i].mk_change_active && strcmp(cca_private->mk_change_ops[i].mk_change_op, op) == 0) { if (idx != NULL) *idx = i; return &cca_private->mk_change_ops[i]; } } return NULL; } static CK_RV cca_mk_change_activate_op(STDLL_TokData_t *tokdata, const char *id, struct hsm_mk_change_info *info, const unsigned char *new_sym_mk, const unsigned char *new_aes_mk, const unsigned char *new_apka_mk, unsigned int *idx) { struct cca_private_data *cca_private = tokdata->private_data; unsigned int i; int op_idx; /* Find a free operation slot */ for (i = 0, op_idx = -1; i < CCA_NUM_MK_TYPES; i++) { if (cca_private->mk_change_ops[i].mk_change_active == FALSE) { op_idx = i; break; } } if (op_idx == -1) { TRACE_ERROR("%s More than %d MK change ops are already active\n", __func__, CCA_NUM_MK_TYPES); return CKR_FUNCTION_FAILED; } /* remember the infos of this MK change op */ memset(&cca_private->mk_change_ops[op_idx], 0, sizeof(cca_private->mk_change_ops[op_idx])); strncpy(cca_private->mk_change_ops[op_idx].mk_change_op, id, sizeof(cca_private->mk_change_ops[op_idx].mk_change_op) - 1); cca_private->mk_change_ops[op_idx].mk_change_op [sizeof(cca_private->mk_change_ops[op_idx].mk_change_op) - 1] = '\0'; if (new_sym_mk != NULL) { memcpy(cca_private->mk_change_ops[op_idx].new_sym_mkvp, new_sym_mk, CCA_MKVP_LENGTH); cca_private->mk_change_ops[op_idx].new_sym_mkvp_set = TRUE; TRACE_DEBUG_DUMP("New SYM MK: ", (void *)new_sym_mk, CCA_MKVP_LENGTH); } if (new_aes_mk != NULL) { memcpy(cca_private->mk_change_ops[op_idx].new_aes_mkvp, new_aes_mk, CCA_MKVP_LENGTH); cca_private->mk_change_ops[op_idx].new_aes_mkvp_set = TRUE; TRACE_DEBUG_DUMP("New AES MK: ", (void *)new_aes_mk, CCA_MKVP_LENGTH); } if (new_apka_mk != NULL) { memcpy(cca_private->mk_change_ops[op_idx].new_apka_mkvp, new_apka_mk, CCA_MKVP_LENGTH); cca_private->mk_change_ops[op_idx].new_apka_mkvp_set = TRUE; TRACE_DEBUG_DUMP("New APKA MK: ", (void *)new_apka_mk, CCA_MKVP_LENGTH); } cca_private->mk_change_ops[op_idx].apqns = calloc(info->num_apqns, sizeof(struct apqn)); if (cca_private->mk_change_ops[op_idx].apqns == NULL) { TRACE_ERROR("%s Failed to allocate list of MK change APQNs\n", __func__); return CKR_HOST_MEMORY; } cca_private->mk_change_ops[op_idx].num_apqns = info->num_apqns; memcpy(cca_private->mk_change_ops[op_idx].apqns, info->apqns, info->num_apqns * sizeof(struct apqn)); cca_private->mk_change_ops[op_idx].mk_change_active = TRUE; TRACE_DEVEL("%s active MK change op (idx %u): %s\n", __func__, op_idx, cca_private->mk_change_ops[op_idx].mk_change_op); OCK_SYSLOG(LOG_INFO, "Slot %lu: A concurrent HSM master key change " "operation (%s) is active for CCA %s%s%s%s%s\n", tokdata->slot_id, cca_private->mk_change_ops[op_idx].mk_change_op, new_sym_mk != NULL ? "SYM" : "", (new_sym_mk != NULL && new_aes_mk != NULL) ? ", " : "", new_aes_mk != NULL ? "AES" : "", ((new_aes_mk != NULL && new_apka_mk != NULL) || (new_aes_mk == NULL && new_sym_mk != NULL && new_apka_mk != NULL)) ? ", " : "", new_apka_mk != NULL ? "APKA" : ""); *idx = op_idx; return CKR_OK; } static CK_RV cca_mk_change_check_pending_ops_cb(struct hsm_mk_change_op *op, void *private) { STDLL_TokData_t *tokdata = private; struct cca_private_data *cca_private; struct hsm_mkvp *mkvps = NULL; unsigned int num_mkvps = 0; unsigned int i; const unsigned char *new_sym_mk = NULL; const unsigned char *new_aes_mk = NULL; const unsigned char *new_apka_mk = NULL; const unsigned char *mkvp; CK_RV rc; cca_private = tokdata->private_data; rc = cca_mk_change_is_affected(tokdata, &op->info); if (rc != CKR_OK) return CKR_OK; new_sym_mk = hsm_mk_change_mkvps_find(op->info.mkvps, op->info.num_mkvps, HSM_MK_TYPE_CCA_SYM, CCA_MKVP_LENGTH); new_aes_mk = hsm_mk_change_mkvps_find(op->info.mkvps, op->info.num_mkvps, HSM_MK_TYPE_CCA_AES, CCA_MKVP_LENGTH); new_apka_mk = hsm_mk_change_mkvps_find(op->info.mkvps, op->info.num_mkvps, HSM_MK_TYPE_CCA_APKA, CCA_MKVP_LENGTH); if (new_sym_mk == NULL && new_aes_mk == NULL && new_apka_mk == NULL) { TRACE_ERROR("%s No CCA MK type found in MK change operation: %s\n", __func__, op->id); return CKR_FUNCTION_FAILED; } switch (op->state) { case HSM_MK_CH_STATE_REENCIPHERING: case HSM_MK_CH_STATE_REENCIPHERED: /* * There can be up to 3 active MK change ops for the CCA token, * one for each MK type, if the MKs are changed individually. * However, these ops can not have intersecting MK types. * No need to have the hsm_mk_change_rwlock, we're in token init * function, and the API layer starts the event thread only after all * token init's have been performed. */ if (new_sym_mk != NULL && cca_mk_change_find_mkvp_in_ops(tokdata, CCA_MK_SYM, &i) != NULL) { TRACE_ERROR("%s Another MK change for CCA SYM is already " "active: %s\n", __func__, cca_private->mk_change_ops[i].mk_change_op); return CKR_FUNCTION_FAILED; } if (new_aes_mk != NULL && cca_mk_change_find_mkvp_in_ops(tokdata, CCA_MK_AES, &i) != NULL) { TRACE_ERROR("%s Another MK change for CCA AES is already " "active: %s\n", __func__, cca_private->mk_change_ops[i].mk_change_op); return CKR_FUNCTION_FAILED; } if (new_apka_mk != NULL && cca_mk_change_find_mkvp_in_ops(tokdata, CCA_MK_APKA, &i) != NULL) { TRACE_ERROR("%s Another MK change for CCA APKA is already " "active: %s\n", __func__, cca_private->mk_change_ops[i].mk_change_op); return CKR_FUNCTION_FAILED; } rc = cca_mk_change_activate_op(tokdata, op->id, &op->info, new_sym_mk, new_aes_mk, new_apka_mk, &i); if (rc != CKR_OK) return rc; /* Load expected current MKVPs */ rc = hsm_mk_change_token_mkvps_load(op->id, tokdata->slot_id, &mkvps, &num_mkvps); /* Ignore if this failed, no expected current MKVP is set then */ if (rc == CKR_OK) { mkvp = hsm_mk_change_mkvps_find(mkvps, num_mkvps, HSM_MK_TYPE_CCA_SYM, CCA_MKVP_LENGTH); if (mkvp != NULL) { memcpy(cca_private->expected_sym_mkvp, mkvp, CCA_MKVP_LENGTH); cca_private->expected_sym_mkvp_set = TRUE; TRACE_DEBUG_DUMP("Current SYM MKVP: ", cca_private->expected_sym_mkvp, CCA_MKVP_LENGTH); } mkvp = hsm_mk_change_mkvps_find(mkvps, num_mkvps, HSM_MK_TYPE_CCA_AES, CCA_MKVP_LENGTH); if (mkvp != NULL) { memcpy(cca_private->expected_aes_mkvp, mkvp, CCA_MKVP_LENGTH); cca_private->expected_aes_mkvp_set = TRUE; TRACE_DEBUG_DUMP("Current AES MKVP: ", cca_private->expected_aes_mkvp, CCA_MKVP_LENGTH); } mkvp = hsm_mk_change_mkvps_find(mkvps, num_mkvps, HSM_MK_TYPE_CCA_APKA, CCA_MKVP_LENGTH); if (mkvp != NULL) { memcpy(cca_private->expected_apka_mkvp, mkvp, CCA_MKVP_LENGTH); cca_private->expected_apka_mkvp_set = TRUE; TRACE_DEBUG_DUMP("Current APKA MKVP: ", cca_private->expected_apka_mkvp, CCA_MKVP_LENGTH); } } break; default: break; } if (mkvps != NULL) { hsm_mk_change_mkvps_clean(mkvps, num_mkvps); free(mkvps); } return CKR_OK; } CK_RV cca_mk_change_check_pending_ops(STDLL_TokData_t *tokdata) { CK_RV rc; rc = hsm_mk_change_lock_create(); if (rc != CKR_OK) return rc; rc = hsm_mk_change_lock(FALSE); if (rc != CKR_OK) goto out; rc = hsm_mk_change_op_iterate(cca_mk_change_check_pending_ops_cb, tokdata); hsm_mk_change_unlock(); out: hsm_mk_change_lock_destroy(); return rc; } static const char *mk_type_to_string(enum cca_mk_type mk_type) { switch (mk_type) { case CCA_MK_SYM: return "SYM"; case CCA_MK_AES: return "AES"; case CCA_MK_APKA: return "APKA"; default: return "UNKNOWN"; } } static CK_RV cca_mk_change_apqn_check_mk_state(enum cca_mk_type mk_type, const char *adapter, unsigned short card, unsigned short domain, CK_SLOT_ID slot, CK_BBOOL finalize, CK_BBOOL cancel, CK_BBOOL *error) { const char *mk_type_str = mk_type_to_string(mk_type); enum cca_cmk_state cur_mk_state; enum cca_nmk_state new_mk_state; CK_RV rc; rc = cca_get_mk_state(mk_type, &cur_mk_state, &new_mk_state); if (rc != CKR_OK) { TRACE_ERROR("cca_get_mk_state (%s) failed for %s (%02X.%04X)\n", mk_type_str, adapter, card, domain); return rc; } /* Ensure that a current master key is set in the card */ if (cur_mk_state != CCA_CMK_STATUS_FULL) { TRACE_ERROR("%s No CURRENT CCA %s master key is set on APQN %02X.%04X (%s)\n", __func__, mk_type_str, card, domain, adapter); warnx("Slot %lu: No CURRENT CCA %s master key is set on APQN %02X.%04X (%s)", slot, mk_type_str, card, domain, adapter); *error = TRUE; } if (finalize) { /* Ensure that the new master key register is empty */ if (new_mk_state != CCA_NMK_STATUS_CLEAR) { TRACE_ERROR("%s The NEW CCA %s master key register must be empty on APQN %02X.%04X (%s)\n", __func__, mk_type_str, card, domain, adapter); warnx("Slot %lu: The NEW CCA %s master key register must be empty on APQN %02X.%04X (%s)", slot, mk_type_str, card, domain, adapter); *error = TRUE; } } else if (!cancel) { /* Ensure that the new master key is set in the card */ if (new_mk_state != CCA_NMK_STATUS_FULL) { TRACE_ERROR("%s No NEW CCA %s master key is set on APQN %02X.%04X (%s)\n", __func__, mk_type_str, card, domain, adapter); warnx("Slot %lu: No NEW CCA %s master key is set on APQN %02X.%04X (%s)", slot, mk_type_str, card, domain, adapter); *error = TRUE; } } return CKR_OK; } static void cca_mk_change_apqn_check_mkvp(enum cca_mk_type mk_type, const unsigned char *queried_mkvp, const unsigned char *expected_mkvp, const char *adapter, unsigned short card, unsigned short domain, CK_SLOT_ID slot, CK_BBOOL new_mk, const char *msg, CK_BBOOL *error) { const char *mk_type_str = mk_type_to_string(mk_type); if (memcmp(queried_mkvp, expected_mkvp, CCA_MKVP_LENGTH) != 0) { TRACE_ERROR("%s CCA %s master key on APQN %02X.%04X (%s) does not " "match the %s master key\n", new_mk ? "NEW" : "CURRENT", mk_type_str, card, domain, adapter, msg); warnx("Slot %lu: The %s CCA %s MK on APQN %02X.%04X (%s) does not " "match the %s MKVP", slot, new_mk ? "NEW" : "CURRENT", mk_type_str, card, domain, adapter, msg); *error = TRUE; } } struct apqn_check_data { CK_SLOT_ID slot; event_mk_change_data_t *op; struct hsm_mk_change_info *info; const unsigned char *sym_new_mk; const unsigned char *aes_new_mk; const unsigned char *apka_new_mk; CK_BBOOL finalize; CK_BBOOL cancel; CK_BBOOL error; }; static CK_RV cca_mk_change_apqn_check_cb(STDLL_TokData_t *tokdata, const char *adapter, unsigned short card, unsigned short domain, void *private) { struct cca_private_data *cca_private = tokdata->private_data; struct apqn_check_data *ac = (struct apqn_check_data *)private; unsigned char sym_cur_mkvp[CCA_MKVP_LENGTH]; unsigned char sym_new_mkvp[CCA_MKVP_LENGTH]; unsigned char aes_cur_mkvp[CCA_MKVP_LENGTH]; unsigned char aes_new_mkvp[CCA_MKVP_LENGTH]; unsigned char apka_cur_mkvp[CCA_MKVP_LENGTH]; unsigned char apka_new_mkvp[CCA_MKVP_LENGTH]; CK_RV rc; /* Check that this APQN is part of the MK change operation */ if (hsm_mk_change_apqns_find(ac->info->apqns, ac->info->num_apqns, card, domain) == FALSE) { TRACE_ERROR("%s APQN %02X.%04X (%s) is not part of MK change '%s'\n", __func__, card, domain, adapter, ac->op->id); warnx("Slot %lu: APQN %02X.%04X must be included into this operation.", ac->slot, card, domain); ac->error = TRUE; return CKR_OK; } if (ac->sym_new_mk != NULL) { /* Check status of AES master key (DES, 3DES keys) */ rc = cca_mk_change_apqn_check_mk_state(CCA_MK_SYM, adapter, card, domain, ac->slot, ac->finalize, ac->cancel, &ac->error); if (rc != CKR_OK) return rc; } if (ac->aes_new_mk != NULL) { /* Check status of AES master key (AES, HMAC keys) */ rc = cca_mk_change_apqn_check_mk_state(CCA_MK_AES, adapter, card, domain, ac->slot, ac->finalize, ac->cancel, &ac->error); if (rc != CKR_OK) return rc; } if (ac->apka_new_mk != NULL) { /* Check status of APKA master key (RSA and ECC keys) */ rc = cca_mk_change_apqn_check_mk_state(CCA_MK_APKA, adapter, card, domain, ac->slot, ac->finalize, ac->cancel, &ac->error); if (rc != CKR_OK) return rc; } /* Get master key verification patterns */ rc = cca_get_mkvps(sym_cur_mkvp, sym_new_mkvp, aes_cur_mkvp, aes_new_mkvp, apka_cur_mkvp, apka_new_mkvp); if (rc != CKR_OK) { TRACE_ERROR("cca_get_mkvps failed for %s (%02X.%04X)\n", adapter, card, domain); return rc; } TRACE_DEBUG("Master key verification patterns for %s (%02X.%04X)\n", adapter, card, domain); TRACE_DEBUG_DUMP("SYM CUR MKVP: ", sym_cur_mkvp, CCA_MKVP_LENGTH); TRACE_DEBUG_DUMP("SYM NEW MKVP: ", sym_new_mkvp, CCA_MKVP_LENGTH); TRACE_DEBUG_DUMP("AES CUR MKVP: ", aes_cur_mkvp, CCA_MKVP_LENGTH); TRACE_DEBUG_DUMP("AES NEW MKVP: ", aes_new_mkvp, CCA_MKVP_LENGTH); TRACE_DEBUG_DUMP("APKA CUR MKVP: ", apka_cur_mkvp, CCA_MKVP_LENGTH); TRACE_DEBUG_DUMP("APKA NEW MKVP: ", apka_new_mkvp, CCA_MKVP_LENGTH); /* Current MKs (only those included in the op) must be the expected MKs */ if (ac->sym_new_mk != NULL) cca_mk_change_apqn_check_mkvp(CCA_MK_SYM, sym_cur_mkvp, ac->finalize ? ac->sym_new_mk : cca_private->expected_sym_mkvp, adapter, card, domain, ac->slot, FALSE, ac->finalize ? "operation's NEW" : "expected", &ac->error); if (ac->aes_new_mk != NULL) cca_mk_change_apqn_check_mkvp(CCA_MK_AES, aes_cur_mkvp, ac->finalize ? ac->aes_new_mk : cca_private->expected_aes_mkvp, adapter, card, domain, ac->slot, FALSE, ac->finalize ? "operation's NEW" : "expected", &ac->error); if (ac->apka_new_mk != NULL) cca_mk_change_apqn_check_mkvp(CCA_MK_APKA, apka_cur_mkvp, ac->finalize ? ac->apka_new_mk : cca_private->expected_apka_mkvp, adapter, card, domain, ac->slot, FALSE, ac->finalize ? "operation's NEW" : "expected", &ac->error); if (ac->finalize || ac->cancel) return CKR_OK; /* Don't check New MKs for finalize or cancel */ /* New MKs must be the expected new MKs of the operation */ if (ac->sym_new_mk != NULL) cca_mk_change_apqn_check_mkvp(CCA_MK_SYM, sym_new_mkvp, ac->sym_new_mk, adapter, card, domain, ac->slot, TRUE, "specified", &ac->error); if (ac->aes_new_mk != NULL) cca_mk_change_apqn_check_mkvp(CCA_MK_AES, aes_new_mkvp, ac->aes_new_mk, adapter, card, domain, ac->slot, TRUE, "specified", &ac->error); if (ac->apka_new_mk != NULL) cca_mk_change_apqn_check_mkvp(CCA_MK_APKA, apka_new_mkvp, ac->apka_new_mk, adapter, card, domain, ac->slot, TRUE, "specified", &ac->error); return CKR_OK; } /* * ATTENTION: This function is called in a separate thread. All actions * performed by this function must be thread safe and use locks to lock * against concurrent access by other threads. */ static CK_RV cca_mk_change_init_query(STDLL_TokData_t *tokdata, event_mk_change_data_t *op, struct hsm_mk_change_info *info) { struct cca_private_data *cca_private = tokdata->private_data; struct apqn_check_data acd; struct hsm_mkvp mkvps[3]; unsigned int num_mkvps = 0; CK_RV rc; TRACE_DEVEL("%s initial query for MK change op: %s\n", __func__, op->id); memset(&acd, 0, sizeof(acd)); acd.slot = tokdata->slot_id; acd.op = op; acd.info = info; acd.sym_new_mk = hsm_mk_change_mkvps_find(info->mkvps, info->num_mkvps, HSM_MK_TYPE_CCA_SYM, CCA_MKVP_LENGTH); acd.aes_new_mk = hsm_mk_change_mkvps_find(info->mkvps, info->num_mkvps, HSM_MK_TYPE_CCA_AES, CCA_MKVP_LENGTH); acd.apka_new_mk = hsm_mk_change_mkvps_find(info->mkvps, info->num_mkvps, HSM_MK_TYPE_CCA_APKA, CCA_MKVP_LENGTH); /* Check if selected APQNs have the expected MKs set/loaded */ rc = cca_iterate_adapters(tokdata, cca_mk_change_apqn_check_cb, &acd); if (rc != CKR_OK) { TRACE_ERROR("%s cca_iterate_adapters failed: 0x%lx\n", __func__, rc); return rc; } if (acd.error) return CKR_FUNCTION_FAILED; /* Save current MKVPs of affected MK types of this token */ if (acd.sym_new_mk != NULL) { mkvps[num_mkvps].type = HSM_MK_TYPE_CCA_SYM; mkvps[num_mkvps].mkvp_len = CCA_MKVP_LENGTH; mkvps[num_mkvps].mkvp = cca_private->expected_sym_mkvp; num_mkvps++; } if (acd.aes_new_mk != NULL) { mkvps[num_mkvps].type = HSM_MK_TYPE_CCA_AES; mkvps[num_mkvps].mkvp_len = CCA_MKVP_LENGTH; mkvps[num_mkvps].mkvp = cca_private->expected_aes_mkvp; num_mkvps++; } if (acd.apka_new_mk != NULL) { mkvps[num_mkvps].type = HSM_MK_TYPE_CCA_APKA; mkvps[num_mkvps].mkvp_len = CCA_MKVP_LENGTH; mkvps[num_mkvps].mkvp = cca_private->expected_apka_mkvp; num_mkvps++; } rc = hsm_mk_change_lock_create(); if (rc != CKR_OK) return rc; rc = hsm_mk_change_lock(TRUE); if (rc != CKR_OK) goto out; rc = hsm_mk_change_token_mkvps_save(op->id, tokdata->slot_id, mkvps, num_mkvps); hsm_mk_change_unlock(); out: hsm_mk_change_lock_destroy(); return rc; } static CK_RV cca_check_token_config_expected_mkvp(STDLL_TokData_t *tokdata, struct cca_mk_change_op *mk_change_op, CK_BBOOL new_mk) { struct cca_private_data *cca_private = tokdata->private_data; FILE *file; struct ConfigBaseNode *c, *config = NULL; struct ConfigStructNode *struct_node; unsigned char exp_sym_mkvp[CCA_MKVP_LENGTH]; unsigned char exp_aes_mkvp[CCA_MKVP_LENGTH]; unsigned char exp_apka_mkvp[CCA_MKVP_LENGTH]; CK_BBOOL exp_sym_mkvp_set = FALSE; CK_BBOOL exp_aes_mkvp_set = FALSE; CK_BBOOL exp_apka_mkvp_set = FALSE; CK_RV rc = CKR_OK; int ret, i; if (cca_private->token_config_filename[0] == '\0') return CKR_OK; file = fopen(cca_private->token_config_filename, "r"); if (file == NULL) { TRACE_ERROR("%s fopen('%s') failed with errno: %s\n", __func__, cca_private->token_config_filename, strerror(errno)); return CKR_FUNCTION_FAILED; } ret = parse_configlib_file(file, &config, cca_config_parse_error, 0); if (ret != 0) { TRACE_ERROR("Error parsing config file '%s'\n", cca_private->token_config_filename); rc = CKR_FUNCTION_FAILED; goto done; } confignode_foreach(c, config, i) { TRACE_DEBUG("Config node: '%s' type: %u line: %u\n", c->key, c->type, c->line); if (confignode_hastype(c, CT_STRUCT)) { struct_node = confignode_to_struct(c); if (strcasecmp(struct_node->base.key, CCA_CFG_EXPECTED_MKVPS) == 0) { rc = cca_config_parse_exp_mkvps( cca_private->token_config_filename, struct_node, exp_sym_mkvp, &exp_sym_mkvp_set, exp_aes_mkvp, &exp_aes_mkvp_set, exp_apka_mkvp, &exp_apka_mkvp_set); if (rc != CKR_OK) break; continue; } } } if (mk_change_op->new_sym_mkvp_set && exp_sym_mkvp_set && memcmp(exp_sym_mkvp, new_mk ? mk_change_op->new_sym_mkvp : cca_private->expected_sym_mkvp, CCA_MKVP_LENGTH) != 0) { TRACE_ERROR("Expected SYM MKVP in config file '%s' does not specify " "the %s MKVP\n", cca_private->token_config_filename, new_mk ? "new" : "current"); warnx("Expected SYM MKVP in config file '%s' does not specify the %s " "MKVP.", cca_private->token_config_filename, new_mk ? "new" : "current"); rc = CKR_FUNCTION_FAILED; } if (mk_change_op->new_aes_mkvp_set && exp_aes_mkvp_set && memcmp(exp_aes_mkvp, new_mk ? mk_change_op->new_aes_mkvp : cca_private->expected_aes_mkvp, CCA_MKVP_LENGTH) != 0) { TRACE_ERROR("Expected AES MKVP in config file '%s' does not specify " "the %s MKVP\n", cca_private->token_config_filename, new_mk ? "new" : "current"); warnx("Expected AES MKVP in config file '%s' does not specify the %s " "MKVP.", cca_private->token_config_filename, new_mk ? "new" : "current"); rc = CKR_FUNCTION_FAILED; } if (mk_change_op->new_apka_mkvp_set && exp_apka_mkvp_set && memcmp(exp_apka_mkvp, new_mk ? mk_change_op->new_apka_mkvp : cca_private->expected_apka_mkvp, CCA_MKVP_LENGTH) != 0) { TRACE_ERROR("Expected APKA MKVP in config file '%s' does not specify " "the %s MKVP\n", cca_private->token_config_filename, new_mk ? "new" : "current"); warnx("Expected APKA MKVP in config file '%s' does not specify the %s " "MKVP.", cca_private->token_config_filename, new_mk ? "new" : "current"); rc = CKR_FUNCTION_FAILED; } done: confignode_deepfree(config); fclose(file); return rc; } /* * ATTENTION: This function is called in a separate thread. All actions * performed by this function must be thread save and use locks to lock * against concurrent access by other threads. */ static CK_RV cca_mk_change_finalize_query(STDLL_TokData_t *tokdata, event_mk_change_data_t *op, struct hsm_mk_change_info *info) { struct cca_mk_change_op *mk_change_op; struct apqn_check_data acd; CK_RV rc; TRACE_DEVEL("%s finalize query for MK change op: %s\n", __func__, op->id); if (pthread_rwlock_rdlock(&tokdata->hsm_mk_change_rwlock) != 0) { TRACE_DEVEL("MK-change Read-Lock failed.\n"); return CKR_CANT_LOCK; } mk_change_op = cca_mk_change_find_op(tokdata, op->id, NULL); if (mk_change_op == NULL) { TRACE_ERROR("%s operation '%s' not active\n", __func__, op->id); rc = CKR_FUNCTION_FAILED; goto out; } memset(&acd, 0, sizeof(acd)); acd.slot = tokdata->slot_id; acd.op = op; acd.info = info; acd.finalize = TRUE; /* New MKs must be current ones */ if (mk_change_op->new_sym_mkvp_set) acd.sym_new_mk = mk_change_op->new_sym_mkvp; if (mk_change_op->new_aes_mkvp_set) acd.aes_new_mk = mk_change_op->new_aes_mkvp; if (mk_change_op->new_apka_mkvp_set) acd.apka_new_mk = mk_change_op->new_apka_mkvp; /* Check if selected APQNs have the expected MKs set/loaded */ rc = cca_iterate_adapters(tokdata, cca_mk_change_apqn_check_cb, &acd); if (rc != CKR_OK) { TRACE_ERROR("%s cca_iterate_adapters failed: 0x%lx\n", __func__, rc); goto out; } if (acd.error) { rc = CKR_FUNCTION_FAILED; goto out; } rc = cca_check_token_config_expected_mkvp(tokdata, mk_change_op, TRUE); if (rc != CKR_OK) { TRACE_ERROR("%s cca_check_token_config_expected_mkvp failed: 0x%lx\n", __func__, rc); goto out; } out: if (pthread_rwlock_unlock(&tokdata->hsm_mk_change_rwlock) != 0) { TRACE_DEVEL("HSM-MK-change Unlock failed.\n"); return CKR_CANT_LOCK; } return rc; } /* * ATTENTION: This function is called in a separate thread. All actions * performed by this function must be thread save and use locks to lock * against concurrent access by other threads. */ static CK_RV cca_mk_change_cancel_query(STDLL_TokData_t *tokdata, event_mk_change_data_t *op, struct hsm_mk_change_info *info) { struct cca_mk_change_op *mk_change_op; struct apqn_check_data acd; CK_RV rc; TRACE_DEVEL("%s cancel query for MK change op: %s\n", __func__, op->id); if (pthread_rwlock_rdlock(&tokdata->hsm_mk_change_rwlock) != 0) { TRACE_DEVEL("MK-change Read-Lock failed.\n"); return CKR_CANT_LOCK; } mk_change_op = cca_mk_change_find_op(tokdata, op->id, NULL); if (mk_change_op == NULL) { TRACE_ERROR("%s operation '%s' not active\n", __func__, op->id); rc = CKR_FUNCTION_FAILED; goto out; } memset(&acd, 0, sizeof(acd)); acd.slot = tokdata->slot_id; acd.op = op; acd.info = info; acd.cancel = TRUE; /* No new MKs must be set */ if (mk_change_op->new_sym_mkvp_set) acd.sym_new_mk = mk_change_op->new_sym_mkvp; if (mk_change_op->new_aes_mkvp_set) acd.aes_new_mk = mk_change_op->new_aes_mkvp; if (mk_change_op->new_apka_mkvp_set) acd.apka_new_mk = mk_change_op->new_apka_mkvp; /* Check if selected APQNs have the expected MKs set/loaded */ rc = cca_iterate_adapters(tokdata, cca_mk_change_apqn_check_cb, &acd); if (rc != CKR_OK) { TRACE_ERROR("%s cca_iterate_adapters failed: 0x%lx\n", __func__, rc); goto out; } if (acd.error) { rc = CKR_FUNCTION_FAILED; goto out; } rc = cca_check_token_config_expected_mkvp(tokdata, mk_change_op, FALSE); if (rc != CKR_OK) { TRACE_ERROR("%s cca_check_token_config_expected_mkvp failed: 0x%lx\n", __func__, rc); goto out; } out: if (pthread_rwlock_unlock(&tokdata->hsm_mk_change_rwlock) != 0) { TRACE_DEVEL("HSM-MK-change Unlock failed.\n"); return CKR_CANT_LOCK; } return rc; } static CK_RV cca_reencipher_sec_key(STDLL_TokData_t *tokdata, struct cca_mk_change_op *mk_change_op, CK_BYTE *sec_key, CK_BYTE *reenc_sec_key, CK_ULONG sec_key_len, CK_BBOOL from_old) { enum cca_token_type keytype; unsigned int keybitsize; const CK_BYTE *mkvp = NULL; const CK_BYTE *new_mkvp = NULL; const char *mk_type; const char *verb; enum cca_ktc_type ktc_type; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; long return_code, reason_code, rule_array_count, exit_data_len = 0; long token_length = sec_key_len; if (analyse_cca_key_token(sec_key, sec_key_len, &keytype, &keybitsize, &mkvp) == FALSE) { TRACE_ERROR("%s Blob is not a valid secure key token\n", __func__); return CKR_FUNCTION_FAILED; } memset(rule_array, 0, sizeof(rule_array)); if (from_old) memcpy(rule_array, "RTCMK ", CCA_KEYWORD_SIZE); else memcpy(rule_array, "RTNMK ", CCA_KEYWORD_SIZE); rule_array_count = 2; switch (keytype) { case sec_des_data_key: memcpy(rule_array + CCA_KEYWORD_SIZE, "DES ", CCA_KEYWORD_SIZE); mk_type = "SYM"; new_mkvp = mk_change_op->new_sym_mkvp; ktc_type = CCA_KTC_DATA; break; case sec_aes_data_key: memcpy(rule_array + CCA_KEYWORD_SIZE, "AES ", CCA_KEYWORD_SIZE); mk_type = "AES"; new_mkvp = mk_change_op->new_aes_mkvp; ktc_type = CCA_KTC_DATA; break; case sec_aes_cipher_key: memcpy(rule_array + CCA_KEYWORD_SIZE, "AES ", CCA_KEYWORD_SIZE); mk_type = "AES"; new_mkvp = mk_change_op->new_aes_mkvp; ktc_type = CCA_KTC_CIPHER; break; case sec_hmac_key: memcpy(rule_array + CCA_KEYWORD_SIZE, "HMAC ", CCA_KEYWORD_SIZE); mk_type = "AES"; new_mkvp = mk_change_op->new_aes_mkvp; ktc_type = CCA_KTC_CIPHER; break; case sec_rsa_priv_key: memcpy(rule_array + CCA_KEYWORD_SIZE, "RSA ", CCA_KEYWORD_SIZE); mk_type = "APKA"; new_mkvp = mk_change_op->new_apka_mkvp; ktc_type = CCA_KTC_PKA; break; case sec_ecc_priv_key: memcpy(rule_array + CCA_KEYWORD_SIZE, "ECC ", CCA_KEYWORD_SIZE); mk_type = "APKA"; new_mkvp = mk_change_op->new_apka_mkvp; ktc_type = CCA_KTC_PKA; break; case sec_qsa_priv_key: memcpy(rule_array + CCA_KEYWORD_SIZE, "QSA ", CCA_KEYWORD_SIZE); mk_type = "APKA"; new_mkvp = mk_change_op->new_apka_mkvp; ktc_type = CCA_KTC_PKA; break; default: TRACE_ERROR("%s Blob is an invalid secure key type: %d\n", __func__, keytype); return CKR_FUNCTION_FAILED; } if (new_mkvp == NULL) { TRACE_ERROR("%s Master key type %s is not affected by operation %s\n", __func__, mk_type, mk_change_op->mk_change_op); return CKR_FUNCTION_FAILED; } memcpy(reenc_sec_key, sec_key, sec_key_len); switch (ktc_type) { case CCA_KTC_DATA: verb = "CSNBKTC"; USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNBKTC(&return_code, &reason_code, &exit_data_len, NULL, &rule_array_count, rule_array, reenc_sec_key); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) break; case CCA_KTC_CIPHER: verb = "CSNBKTC2"; USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNBKTC2(&return_code, &reason_code, &exit_data_len, NULL, &rule_array_count, rule_array, &token_length, reenc_sec_key); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) break; case CCA_KTC_PKA: verb = "CSNDKTC"; USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNDKTC(&return_code, &reason_code, &exit_data_len, NULL, &rule_array_count, rule_array, &token_length, reenc_sec_key); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) break; default: return CKR_FUNCTION_FAILED; } if (return_code != CCA_SUCCESS) { TRACE_ERROR("%s (%s) failed. return:%ld, reason:%ld\n", verb, rule_array, return_code, reason_code); if (return_code == 8 && reason_code == 48) return CKR_DEVICE_ERROR; /* MKVP of key not valid */ return CKR_FUNCTION_FAILED; } /* check for expected new MK */ if (analyse_cca_key_token(reenc_sec_key, sec_key_len, &keytype, &keybitsize, &mkvp) == FALSE) { TRACE_ERROR("%s Blob is not a valid secure key token\n", __func__); return CKR_FUNCTION_FAILED; } if (memcmp(mkvp, new_mkvp, CCA_MKVP_LENGTH) != 0) { TRACE_ERROR("%s Re-enciphered key blob is not enciphered by expected " "new %s MK\n", __func__, mk_type); OCK_SYSLOG(LOG_ERR, "Slot %lu: Re-enciphered key blob is not enciphered" " by expected new %s MK\n", tokdata->slot_id, mk_type); return CKR_DEVICE_ERROR; } return CKR_OK; } struct reencipher_data { STDLL_TokData_t *tokdata; struct cca_mk_change_op *mk_change_op; }; static CK_RV cca_reencipher_objects_reenc(CK_BYTE *sec_key, CK_BYTE *reenc_sec_key, CK_ULONG sec_key_len, void *private) { struct reencipher_data *rd = private; return cca_reencipher_sec_key(rd->tokdata, rd->mk_change_op, sec_key, reenc_sec_key, sec_key_len, FALSE); } static CK_RV cca_reencipher_objects_cb(STDLL_TokData_t *tokdata, OBJECT *obj, void *cb_data) { struct reencipher_data *rd = cb_data; CK_RV rc; rc = obj_mgr_reencipher_secure_key(tokdata, obj, cca_reencipher_objects_reenc, rd); if (rc == CKR_OBJECT_HANDLE_INVALID) /* Obj was deleted by other proc */ rc = CKR_OK; return rc; } static CK_BBOOL cca_reencipher_filter_cb(STDLL_TokData_t *tokdata, OBJECT *obj, void *filter_data) { struct cca_mk_change_op *mk_change_op = filter_data; CK_ATTRIBUTE *attr; enum cca_token_type keytype; unsigned int keybitsize; const CK_BYTE *mkvp = NULL; UNUSED(tokdata); if (template_attribute_find(obj->template, CKA_IBM_OPAQUE, &attr) == FALSE) return FALSE; if (analyse_cca_key_token(attr->pValue, attr->ulValueLen, &keytype, &keybitsize, &mkvp) == FALSE) return FALSE; switch (keytype) { case sec_des_data_key: return mk_change_op->new_sym_mkvp_set; case sec_aes_data_key: case sec_aes_cipher_key: case sec_hmac_key: return mk_change_op->new_aes_mkvp_set; case sec_rsa_priv_key: case sec_ecc_priv_key: case sec_qsa_priv_key: return mk_change_op->new_apka_mkvp_set; default: return FALSE; } } static CK_BBOOL cca_reencipher_cancel_filter_cb(STDLL_TokData_t *tokdata, OBJECT *obj, void *filter_data) { CK_ATTRIBUTE *attr; if (template_attribute_find(obj->template, CKA_IBM_OPAQUE_REENC, &attr) == FALSE) return FALSE; return cca_reencipher_filter_cb(tokdata, obj, filter_data); } static CK_RV cca_reencipher_cancel_objects_cb(STDLL_TokData_t *tokdata, OBJECT *obj, void *cb_data) { CK_RV rc; UNUSED(cb_data); rc = obj_mgr_reencipher_secure_key_cancel(tokdata, obj); if (rc == CKR_ATTRIBUTE_TYPE_INVALID) rc = CKR_OK; if (rc == CKR_OBJECT_HANDLE_INVALID) /* Obj was deleted by other proc */ rc = CKR_OK; return rc; } static CK_BBOOL cca_reencipher_finalize_is_new_mk_cb(STDLL_TokData_t *tokdata, OBJECT *obj, CK_BYTE *sec_key, CK_ULONG sec_key_len, void *cb_private) { enum cca_token_type keytype; unsigned int keybitsize; const CK_BYTE *mkvp = NULL; CK_BBOOL new_mk = FALSE; UNUSED(cb_private); UNUSED(obj); if (analyse_cca_key_token(sec_key, sec_key_len, &keytype, &keybitsize, &mkvp) == FALSE) return FALSE; if (check_expected_mkvp(tokdata, keytype, mkvp, &new_mk) != CKR_OK) return FALSE; return new_mk; } static CK_RV cca_reencipher_finalize_objects_cb(STDLL_TokData_t *tokdata, OBJECT *obj, void *cb_data) { CK_RV rc; UNUSED(cb_data); rc = obj_mgr_reencipher_secure_key_finalize(tokdata, obj, cca_reencipher_finalize_is_new_mk_cb, NULL); if (rc == CKR_ATTRIBUTE_TYPE_INVALID) rc = CKR_OK; if (rc == CKR_OBJECT_HANDLE_INVALID) /* Obj was deleted by other proc */ rc = CKR_OK; return rc; } static CK_RV cca_finalize_sessions_cb(STDLL_TokData_t *tokdata, SESSION *session, CK_ULONG ctx_type, CK_MECHANISM *mech, CK_OBJECT_HANDLE key, CK_BYTE *context, CK_ULONG context_len, CK_BBOOL init_pending, CK_BBOOL pkey_active, CK_BBOOL recover, void *private) { struct cca_mk_change_op *mk_change_op = private; CK_ATTRIBUTE *opaque_attr = NULL; OBJECT *key_obj = NULL; CK_OBJECT_CLASS class; enum cca_token_type keytype; unsigned int keybitsize; const CK_BYTE *mkvp; CK_RV rc; UNUSED(session); UNUSED(ctx_type); UNUSED(mech); UNUSED(context); UNUSED(context_len); UNUSED(init_pending); UNUSED(pkey_active); UNUSED(recover); if (key == CK_INVALID_HANDLE) return CKR_OK; /* * Update the key object from disk if it is a token object, the secure key * is affected by the MK change operation, and it has been changed by * another process, i.e. due to re-enciphering of the object by the * pkcshsm_mk_change tool. */ rc = object_mgr_find_in_map_nocache(tokdata, key, &key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_DEVEL("object_mgr_find_in_map1 failed\n"); OCK_SYSLOG(LOG_ERR, "Slot %lu: Failed to get key object: 0x%lx\n", tokdata->slot_id, rc); goto done; } if (!object_is_token_object(key_obj)) goto done; rc = template_attribute_get_ulong(key_obj->template, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("%s Failed to get object class: 0x%lx\n", __func__, rc); OCK_SYSLOG(LOG_ERR, "Slot %lu: Failed to get object class: 0x%lx\n", tokdata->slot_id, rc); goto done; } switch (class) { case CKO_PUBLIC_KEY: case CKO_PRIVATE_KEY: case CKO_SECRET_KEY: break; default: /* Not a key object */ goto done; } if (!template_attribute_find(key_obj->template, CKA_IBM_OPAQUE, &opaque_attr)) { TRACE_ERROR("%s Failed to get CKA_IBM_OPAQUE\n", __func__); OCK_SYSLOG(LOG_ERR, "Slot %lu: Failed to gCKA_IBM_OPAQUE\n", tokdata->slot_id); rc = CKR_TEMPLATE_INCOMPLETE; goto done; } if (analyse_cca_key_token(opaque_attr->pValue, opaque_attr->ulValueLen, &keytype, &keybitsize, &mkvp) == FALSE) { TRACE_ERROR("%s Key token is not valid: handle: %lu\n", __func__, key); OCK_SYSLOG(LOG_ERR, "Slot %lu: Key token is not valid: handle: %lu\n", tokdata->slot_id, key); rc = CKR_FUNCTION_FAILED; goto done; } switch (keytype) { case sec_des_data_key: if (mk_change_op->new_sym_mkvp_set == FALSE) goto done; break; case sec_aes_data_key: case sec_aes_cipher_key: case sec_hmac_key: if (mk_change_op->new_aes_mkvp_set == FALSE) goto done; break; case sec_rsa_priv_key: case sec_ecc_priv_key: case sec_qsa_priv_key: if (mk_change_op->new_apka_mkvp_set == FALSE) goto done; break; default: goto done; } TRACE_INFO("%s Update token key object '%s' referenced by state of session " "0x%lx\n", __func__, key_obj->name, session->handle); OCK_SYSLOG(LOG_DEBUG, "Slot %lu: Update token key object '%s' referenced " "by state of session 0x%lx\n", tokdata->slot_id, key_obj->name, session->handle); rc = object_mgr_check_shm(tokdata, key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_DEVEL("object_mgr_check_shm failed.\n"); OCK_SYSLOG(LOG_ERR, "Slot %lu: Failed to update token key object '%s' " "from SHM: 0x%lx\n", tokdata->slot_id, key_obj->name, rc); goto done; } done: object_put(tokdata, key_obj, TRUE); key_obj = NULL; return rc; } /* * ATTENTION: This function is called in a separate thread. All actions * performed by this function must be thread save and use locks to lock * against concurrent access by other threads. */ static CK_RV cca_mk_change_reencipher(STDLL_TokData_t *tokdata, event_mk_change_data_t *op, struct hsm_mk_change_info *info) { struct cca_private_data *cca_private = tokdata->private_data; struct cca_mk_change_op *mk_change_op; const unsigned char *new_sym_mk = NULL; const unsigned char *new_aes_mk = NULL; const unsigned char *new_apka_mk = NULL; struct reencipher_data rd = { 0 }; CK_RV rc = CKR_OK; unsigned int op_idx; CK_BBOOL token_objs = FALSE; if ((op->flags & EVENT_MK_CHANGE_FLAGS_TOK_OBJS) != 0) { token_objs = TRUE; /* The tool should have logged in a R/W USER session */ if (!session_mgr_user_session_exists(tokdata)) { TRACE_ERROR("%s No user session exists\n", __func__); OCK_SYSLOG(LOG_ERR, "Slot %lu: No user session exists\n", tokdata->slot_id); return CKR_FUNCTION_FAILED; } } if (pthread_rwlock_wrlock(&tokdata->hsm_mk_change_rwlock) != 0) { TRACE_DEVEL("HSM-MK-change Write-Lock failed.\n"); OCK_SYSLOG(LOG_ERR, "Slot %lu: HSM-MK-change Write-Lock failed\n", tokdata->slot_id); rc = CKR_CANT_LOCK; goto out; } mk_change_op = cca_mk_change_find_op(tokdata, op->id, NULL); if (token_objs == TRUE && mk_change_op == NULL) { TRACE_DEVEL("HSM-MK-change op %s must already be active\n", op->id); OCK_SYSLOG(LOG_ERR, "Slot %lu: HSM-MK-change %s must already be active\n", tokdata->slot_id, op->id); rc = CKR_FUNCTION_FAILED; goto out; } /* Activate this MK change operation if not already active */ if (mk_change_op == NULL) { new_sym_mk = hsm_mk_change_mkvps_find(info->mkvps, info->num_mkvps, HSM_MK_TYPE_CCA_SYM, CCA_MKVP_LENGTH); new_aes_mk = hsm_mk_change_mkvps_find(info->mkvps, info->num_mkvps, HSM_MK_TYPE_CCA_AES, CCA_MKVP_LENGTH); new_apka_mk = hsm_mk_change_mkvps_find(info->mkvps, info->num_mkvps, HSM_MK_TYPE_CCA_APKA, CCA_MKVP_LENGTH); if (new_sym_mk == NULL && new_aes_mk == NULL && new_apka_mk == NULL) { TRACE_ERROR("%s No CCA MK type found in MK change operation: %s\n", __func__, op->id); OCK_SYSLOG(LOG_ERR, "Slot %lu: No CCA MK type found in MK change " "operation: %s\n", tokdata->slot_id, op->id); rc = CKR_FUNCTION_FAILED; goto out; } rc = cca_mk_change_activate_op(tokdata, op->id, info, new_sym_mk, new_aes_mk, new_apka_mk, &op_idx); if (rc != CKR_OK) goto out; mk_change_op = &cca_private->mk_change_ops[op_idx]; } TRACE_DEVEL("%s MK change op: %s\n", __func__, mk_change_op->mk_change_op); if (mk_change_op->new_sym_mkvp_set) { TRACE_DEBUG_DUMP("New SYM MK: ", (void *)mk_change_op->new_sym_mkvp, CCA_MKVP_LENGTH); } if (mk_change_op->new_aes_mkvp_set) { TRACE_DEBUG_DUMP("New AES MK: ", (void *)mk_change_op->new_aes_mkvp, CCA_MKVP_LENGTH); } if (mk_change_op->new_apka_mkvp_set) { TRACE_DEBUG_DUMP("New APKA MK: ", (void *)mk_change_op->new_apka_mkvp, CCA_MKVP_LENGTH); } /* Re-encipher key objects */ rd.tokdata = tokdata; rd.mk_change_op = mk_change_op; rc = obj_mgr_iterate_key_objects(tokdata, !token_objs, token_objs, cca_reencipher_filter_cb, mk_change_op, cca_reencipher_objects_cb, &rd, TRUE, "re-encipher"); if (rc != CKR_OK) { obj_mgr_iterate_key_objects(tokdata, !token_objs, token_objs, cca_reencipher_cancel_filter_cb, mk_change_op, cca_reencipher_cancel_objects_cb, NULL, TRUE, "cancel"); /* * The pkcshsm_mk_change tool will send a CANCEL event, so leave the * operation active for now. */ goto out; } out: if (pthread_rwlock_unlock(&tokdata->hsm_mk_change_rwlock) != 0) { TRACE_DEVEL("HSM-MK-change Unlock failed.\n"); OCK_SYSLOG(LOG_ERR, "Slot %lu: HSM-MK-change unlock failed\n", tokdata->slot_id); if (rc == CKR_OK) rc = CKR_CANT_LOCK; } return rc; } /* * ATTENTION: This function is called in a separate thread. All actions * performed by this function must be thread save and use locks to lock * against concurrent access by other threads. */ static CK_RV cca_mk_change_finalize_cancel(STDLL_TokData_t *tokdata, event_mk_change_data_t *op, struct hsm_mk_change_info *info, CK_BBOOL cancel) { struct cca_private_data *cca_private = tokdata->private_data; struct cca_mk_change_op *mk_change_op; CK_RV rc = CKR_OK; CK_BBOOL token_objs = FALSE; UNUSED(info); TRACE_DEVEL("%s %s MK change op: %s\n", __func__, cancel ? "canceling" : "finalizing", op->id); if ((op->flags & EVENT_MK_CHANGE_FLAGS_TOK_OBJS) != 0 || (op->flags & EVENT_MK_CHANGE_FLAGS_TOK_OBJS_FINAL) != 0) { token_objs = TRUE; /* The tool should have logged in a R/W USER session */ if (!session_mgr_user_session_exists(tokdata)) { TRACE_ERROR("%s No user session exists\n", __func__); OCK_SYSLOG(LOG_ERR, "Slot %lu: No user session exists\n", tokdata->slot_id); return CKR_FUNCTION_FAILED; } } if (pthread_rwlock_wrlock(&tokdata->hsm_mk_change_rwlock) != 0) { TRACE_DEVEL("HSM-MK-change Write-Lock failed.\n"); OCK_SYSLOG(LOG_ERR, "Slot %lu: HSM-MK-change Write-Lock failed\n", tokdata->slot_id); rc = CKR_CANT_LOCK; goto out; } mk_change_op = cca_mk_change_find_op(tokdata, op->id, NULL); if (mk_change_op == NULL) goto out; /* * Finalize/cancel token objects. * If flag EVENT_MK_CHANGE_FLAGS_TOK_OBJS_FINAL is on, only process such * token objects that do have the CKA_IBM_OPAQUE_REENC attribute. Those * Objects have been newly created by another process after the first token * finalization/cancellation (flag EVENT_MK_CHANGE_FLAGS_TOK_OBJS) has * been performed, and before all processes have deactivated the MK change * operation. Thus, they were created with the re-enciphered secure key, * and now need to be finalized/canceled. */ rc = obj_mgr_iterate_key_objects(tokdata, !token_objs, token_objs, token_objs && (op->flags & EVENT_MK_CHANGE_FLAGS_TOK_OBJS_FINAL) ? cca_reencipher_cancel_filter_cb : cca_reencipher_filter_cb, mk_change_op, cancel ? cca_reencipher_cancel_objects_cb : cca_reencipher_finalize_objects_cb, NULL, TRUE, cancel ? "cancel" : "finalize"); if (rc != CKR_OK) goto out; if (!token_objs && !cancel) { /* update token keys referenced in active sessions */ rc = session_mgr_iterate_session_ops(tokdata, NULL, cca_finalize_sessions_cb, mk_change_op); if (rc != CKR_OK) { OCK_SYSLOG(LOG_ERR, "Slot %lu: Failed to finalize sessions: 0x%lx\n", tokdata->slot_id, rc); goto out; } } /* * Deactivate this MK change operation. * For the pkcshsm_mk_change tool: Deactivate only after 2nd token object * processing. */ if ((token_objs == FALSE && op->tool_pid != tokdata->real_pid) || (op->flags & EVENT_MK_CHANGE_FLAGS_TOK_OBJS_FINAL) != 0) { if (!cancel) { /* From now on the new MKs are the expected one */ if (mk_change_op->new_sym_mkvp_set) memcpy(cca_private->expected_sym_mkvp, mk_change_op->new_sym_mkvp, CCA_MKVP_LENGTH); if (mk_change_op->new_aes_mkvp_set) memcpy(cca_private->expected_aes_mkvp, mk_change_op->new_aes_mkvp, CCA_MKVP_LENGTH); if (mk_change_op->new_apka_mkvp_set) memcpy(cca_private->expected_apka_mkvp, mk_change_op->new_apka_mkvp, CCA_MKVP_LENGTH); } mk_change_op->mk_change_active = 0; memset(mk_change_op->mk_change_op, 0, sizeof(mk_change_op->mk_change_op)); if (mk_change_op->apqns != NULL) free(mk_change_op->apqns); mk_change_op->apqns = NULL; mk_change_op->num_apqns = 0; TRACE_DEVEL("%s %s MK change op: %s\n", __func__, cancel ? "canceled" : "finalized", op->id); OCK_SYSLOG(LOG_INFO, "Slot %lu: Concurrent HSM master key change " "operation %s is %s\n", tokdata->slot_id, op->id, cancel ? "canceled" : "finalized"); } out: if (pthread_rwlock_unlock(&tokdata->hsm_mk_change_rwlock) != 0) { TRACE_DEVEL("HSM-MK-change Unlock failed.\n"); OCK_SYSLOG(LOG_ERR, "Slot %lu: HSM-MK-change unlock failed\n", tokdata->slot_id); if (rc == CKR_OK) rc = CKR_CANT_LOCK; } return rc; } /* * ATTENTION: This function is called in a separate thread. All actions * performed by this function must be thread save and use locks to lock * against concurrent access by other threads. */ CK_RV cca_handle_mk_change_event(STDLL_TokData_t *tokdata, unsigned int event_type, unsigned int event_flags, const char *payload, unsigned int payload_len) { CK_RV rc; size_t bytes_read = 0; struct hsm_mk_change_info info = { 0 }; event_mk_change_data_t *hdr = (event_mk_change_data_t *)payload; UNUSED(event_flags); TRACE_DEVEL("%s event: 0x%x\n", __func__, event_type); if (payload_len <= sizeof (*hdr)) return CKR_DATA_LEN_RANGE; TRACE_DEVEL("%s id: '%s' flags: 0x%x tool_pid: %d\n", __func__, hdr->id, hdr->flags, hdr->tool_pid); rc = hsm_mk_change_info_unflatten((unsigned char *)payload + sizeof(*hdr), payload_len - sizeof(*hdr), &bytes_read, &info); if (rc != CKR_OK) return rc; if (bytes_read < payload_len - sizeof(*hdr)) { rc = CKR_DATA_LEN_RANGE; goto out; } rc = cca_mk_change_is_affected(tokdata, &info); if (rc != CKR_OK) goto out; if (event_type != EVENT_TYPE_MK_CHANGE_INITIATE_QUERY && event_type != EVENT_TYPE_MK_CHANGE_REENCIPHER) { /* Operation must be active */ if (pthread_rwlock_rdlock(&tokdata->hsm_mk_change_rwlock) != 0) { TRACE_DEVEL("HSM-MK-change Read-Lock failed.\n"); rc = CKR_CANT_LOCK; goto out; } if (cca_mk_change_find_op(tokdata, hdr->id, NULL) == NULL) { TRACE_ERROR("%s Must be a currently active operation: '%s'\n", __func__, hdr->id); rc = CKR_FUNCTION_FAILED; pthread_rwlock_unlock(&tokdata->hsm_mk_change_rwlock); goto out; } if (pthread_rwlock_unlock(&tokdata->hsm_mk_change_rwlock) != 0) { TRACE_DEVEL("HSM-MK-change Unlock failed.\n"); rc = CKR_CANT_LOCK; goto out; } } switch (event_type) { case EVENT_TYPE_MK_CHANGE_INITIATE_QUERY: rc = cca_mk_change_init_query(tokdata, hdr, &info); break; case EVENT_TYPE_MK_CHANGE_REENCIPHER: rc = cca_mk_change_reencipher(tokdata, hdr, &info); break; case EVENT_TYPE_MK_CHANGE_FINALIZE_QUERY: rc = cca_mk_change_finalize_query(tokdata, hdr, &info); break; case EVENT_TYPE_MK_CHANGE_CANCEL_QUERY: rc = cca_mk_change_cancel_query(tokdata, hdr, &info); break; case EVENT_TYPE_MK_CHANGE_FINALIZE: rc = cca_mk_change_finalize_cancel(tokdata, hdr, &info, FALSE); break; case EVENT_TYPE_MK_CHANGE_CANCEL: rc = cca_mk_change_finalize_cancel(tokdata, hdr, &info, TRUE); break; default: rc = CKR_FUNCTION_NOT_SUPPORTED; break; } out: hsm_mk_change_info_clean(&info); TRACE_DEVEL("%s rc: 0x%lx\n", __func__, rc); return rc; } opencryptoki-opencryptoki-451d99c/usr/lib/cca_stdll/cca_specific.c000066400000000000000000023375311520105705100254100ustar00rootroot00000000000000/* * 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 #include #include #include #ifndef NO_PKEY #include #include #include #endif #include "platform.h" #include "cca_stdll.h" #include "p11util.h" #include "tok_specific.h" #include "tok_struct.h" #include "h_extern.h" #include "ec_defs.h" #include "trace.h" #include "ock_syslog.h" #include "cfgparser.h" #include "events.h" #include "constant_time.h" #include "pqc_defs.h" #include #include #ifndef NO_PKEY #include "pkey_utils.h" #endif #include "attributes.h" /** * 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"; #if defined(_AIX) /* GNU extension, provides a replacement */ void populate_progname(void); extern char *program_invocation_short_name; #if defined(__64BIT__) /* -q64 was passed */ #define CCASHAREDLIB "libcsufcca.a(sapi64)" #else #define CCASHAREDLIB "libcsufcca.a(sapi)" #endif /* __64BIT__ */ #else #define CCASHAREDLIB "libcsulcca.so" #endif #define CCA_MIN_VERSION 7 #define CCA_MIN_RELEASE 1 static CSNBCKI_t dll_CSNBCKI; static CSNBCKM_t dll_CSNBCKM; static CSNBDKX_t dll_CSNBDKX; static CSNBDKM_t dll_CSNBDKM; 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; CSNBKTC_t dll_CSNBKTC; CSNBKTC2_t dll_CSNBKTC2; 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; CSNDKTC_t dll_CSNDKTC; static CSNDPKX_t dll_CSNDPKX; static CSNDSYI_t dll_CSNDSYI; static CSNDSYI2_t dll_CSNDSYI2; 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; CSUACRA_t dll_CSUACRA; 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 CSUAPRB_t dll_CSUAPRB; 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; static CSNBCTT2_t dll_CSNBCTT2; static CSUACFV_t dll_CSUACFV; static CSNBRKA_t dll_CSNBRKA; static CSNBKTR2_t dll_CSNBKTR2; static CSNDEDH_t dll_CSNDEDH; /* * The CCA adapter lock is shared between all CCA token instances within the * same process. Users of the CCA adapter(s) should obtain a READ lock, to * be sure that no CCA adapter and/or domain selection is done concurrently. * Whenever a CCA adapter and/or domain selection is performed, a WRITE lock * must be obtained. This blocks all users until the selection processing is * finished. * While CCA device selection has thread scope, domain selection seems to have * process scope. Thus, domain selection influences not only the current thread, * but all threads of the process. */ pthread_rwlock_t cca_adapter_rwlock; static unsigned long cca_adapter_rwlock_ref_count = 0; /* mechanisms provided by this token */ static const MECH_LIST_ELEMENT cca_mech_list[] = { {CKM_DES_KEY_GEN, {8, 8, CKF_HW | CKF_GENERATE}}, {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 | CKF_WRAP | CKF_UNWRAP | CKF_ENCAPSULATE | CKF_DECAPSULATE}}, {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_SHA224_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_SHA3_224_RSA_PKCS, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {CKM_SHA3_256_RSA_PKCS, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {CKM_SHA3_384_RSA_PKCS, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {CKM_SHA3_512_RSA_PKCS, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {CKM_RSA_PKCS_PSS, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {CKM_SHA1_RSA_PKCS_PSS, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {CKM_SHA224_RSA_PKCS_PSS, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {CKM_SHA256_RSA_PKCS_PSS, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {CKM_SHA384_RSA_PKCS_PSS, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {CKM_SHA512_RSA_PKCS_PSS, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {CKM_RSA_PKCS_OAEP, {512, 4096, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP | CKF_ENCAPSULATE | CKF_DECAPSULATE}}, {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}}, {CKM_AES_KEY_GEN, {16, 32, CKF_HW | CKF_GENERATE}}, {CKM_AES_XTS_KEY_GEN, {32, 64, 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}}, {CKM_AES_XTS, {32, 64, CKF_ENCRYPT | CKF_DECRYPT}}, {CKM_AES_GCM, {16, 32, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT}}, {CKM_SHA3_512, {0, 0, CKF_HW | CKF_DIGEST}}, {CKM_SHA3_384, {0, 0, CKF_HW | CKF_DIGEST}}, {CKM_SHA3_256, {0, 0, CKF_HW | CKF_DIGEST}}, {CKM_SHA3_224, {0, 0, CKF_HW | CKF_DIGEST}}, {CKM_IBM_SHA3_512, {0, 0, CKF_HW | CKF_DIGEST}}, {CKM_IBM_SHA3_384, {0, 0, CKF_HW | CKF_DIGEST}}, {CKM_IBM_SHA3_256, {0, 0, CKF_HW | CKF_DIGEST}}, {CKM_IBM_SHA3_224, {0, 0, CKF_HW | CKF_DIGEST}}, {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_OID | CKF_EC_F_P | CKF_EC_UNCOMPRESS | CKF_EC_COMPRESS}}, {CKM_ECDSA, {160, 521, CKF_HW | CKF_SIGN | CKF_VERIFY | CKF_EC_OID | CKF_EC_F_P | CKF_EC_UNCOMPRESS | CKF_EC_COMPRESS}}, {CKM_ECDSA_SHA1, {160, 521, CKF_HW | CKF_SIGN | CKF_VERIFY | CKF_EC_OID | CKF_EC_F_P | CKF_EC_UNCOMPRESS | CKF_EC_COMPRESS}}, {CKM_ECDSA_SHA224, {160, 521, CKF_HW | CKF_SIGN | CKF_VERIFY | CKF_EC_OID | CKF_EC_F_P | CKF_EC_UNCOMPRESS | CKF_EC_COMPRESS}}, {CKM_ECDSA_SHA256, {160, 521, CKF_HW | CKF_SIGN | CKF_VERIFY | CKF_EC_OID | CKF_EC_F_P | CKF_EC_UNCOMPRESS | CKF_EC_COMPRESS}}, {CKM_ECDSA_SHA384, {160, 521, CKF_HW | CKF_SIGN | CKF_VERIFY | CKF_EC_OID | CKF_EC_F_P | CKF_EC_UNCOMPRESS | CKF_EC_COMPRESS}}, {CKM_ECDSA_SHA512, {160, 521, CKF_HW | CKF_SIGN | CKF_VERIFY | CKF_EC_OID | CKF_EC_F_P | CKF_EC_UNCOMPRESS | CKF_EC_COMPRESS}}, {CKM_ECDSA_SHA3_224, {160, 521, CKF_HW | CKF_SIGN | CKF_VERIFY | CKF_EC_OID | CKF_EC_F_P | CKF_EC_UNCOMPRESS | CKF_EC_COMPRESS}}, {CKM_ECDSA_SHA3_256, {160, 521, CKF_HW | CKF_SIGN | CKF_VERIFY | CKF_EC_OID | CKF_EC_F_P | CKF_EC_UNCOMPRESS | CKF_EC_COMPRESS}}, {CKM_ECDSA_SHA3_384, {160, 521, CKF_HW | CKF_SIGN | CKF_VERIFY | CKF_EC_OID | CKF_EC_F_P | CKF_EC_UNCOMPRESS | CKF_EC_COMPRESS}}, {CKM_ECDSA_SHA3_512, {160, 521, CKF_HW | CKF_SIGN | CKF_VERIFY | CKF_EC_OID | CKF_EC_F_P | CKF_EC_UNCOMPRESS | CKF_EC_COMPRESS}}, {CKM_ECDH1_DERIVE, {160, 521, CKF_DERIVE | CKF_EC_OID | CKF_EC_F_P | CKF_EC_UNCOMPRESS | CKF_EC_COMPRESS | CKF_ENCAPSULATE | CKF_DECAPSULATE}}, {CKM_GENERIC_SECRET_KEY_GEN, {80, 2048, CKF_HW | CKF_GENERATE}}, {CKM_SHA_1_KEY_GEN, {80, 2048, CKF_HW | CKF_GENERATE}}, {CKM_SHA224_KEY_GEN, {80, 2048, CKF_HW | CKF_GENERATE}}, {CKM_SHA256_KEY_GEN, {80, 2048, CKF_HW | CKF_GENERATE}}, {CKM_SHA384_KEY_GEN, {80, 2048, CKF_HW | CKF_GENERATE}}, {CKM_SHA512_KEY_GEN, {80, 2048, CKF_HW | CKF_GENERATE}}, {CKM_IBM_DILITHIUM, {256, 256, CKF_HW | CKF_GENERATE_KEY_PAIR | CKF_SIGN | CKF_VERIFY}}, {CKM_IBM_ML_DSA_KEY_PAIR_GEN, {1312, 2592, CKF_HW | CKF_GENERATE_KEY_PAIR}}, {CKM_IBM_ML_DSA, {1312, 2592, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {CKM_IBM_ML_KEM_KEY_PAIR_GEN, {800, 1568, CKF_HW | CKF_GENERATE_KEY_PAIR}}, {CKM_IBM_ML_KEM_WITH_ECDH, {800, 1568, CKF_HW | CKF_DERIVE}}, {CKM_ML_DSA_KEY_PAIR_GEN, {1312, 2592, CKF_HW | CKF_GENERATE_KEY_PAIR}}, {CKM_ML_DSA, {1312, 2592, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {CKM_HASH_ML_DSA, {1312, 2592, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {CKM_HASH_ML_DSA_SHA512, {1312, 2592, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {CKM_RSA_AES_KEY_WRAP, {2048, 4096, CKF_HW | CKF_WRAP | CKF_UNWRAP}}, {CKM_EC_EDWARDS_KEY_PAIR_GEN, {255, 448, CKF_HW | CKF_GENERATE_KEY_PAIR | CKF_EC_OID | CKF_EC_F_P | CKF_EC_COMPRESS}}, {CKM_EDDSA, {255, 448, CKF_HW | CKF_SIGN | CKF_VERIFY | CKF_EC_OID | CKF_EC_F_P | CKF_EC_COMPRESS}}, {CKM_PUB_KEY_FROM_PRIV_KEY,{ 0, 0, CKF_DERIVE}}, }; static const CK_ULONG cca_mech_list_len = (sizeof(cca_mech_list) / sizeof(MECH_LIST_ELEMENT)); const unsigned char cca_zero_mkvp[CCA_MKVP_LENGTH] = { 0 }; static CK_RV file_fgets(const char *fname, char *buf, size_t buflen); static CK_RV cca_key_gen(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, enum cca_key_type type, CK_BYTE *key, unsigned char *key_form, unsigned char *key_type_1, CK_ULONG key_size, CK_BBOOL aes_xts_2dn_key, CK_BBOOL *has_new_mk); static CK_RV cca_cipher_key_gen(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, enum cca_key_type type, CK_BYTE *key, CK_ULONG *key_len, unsigned char *key_form, unsigned char *key_type_1, CK_ULONG key_size, CK_BBOOL aes_xts_2dn_key, CK_BBOOL *has_new_mk); static CK_RV cca_build_aes_cipher_token(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_BYTE *key_token, CK_ULONG *key_token_size); static CK_RV cca_build_aes_data_token(STDLL_TokData_t *tokdata, CK_ULONG key_size, CK_BYTE *key_token, CK_ULONG *key_token_size); static CK_RV cca_aes_cipher_add_key_usage_keywords(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_BYTE *rule_array, CK_ULONG rule_array_size, CK_ULONG *rule_array_count); struct cca_hybrid_ecdh_data { char rule[CCA_KEYWORD_SIZE]; /* IHKEYKYB or IHKEYAES */ unsigned char *hybrid_key; long hybrid_key_len; unsigned char *iv; long iv_len; unsigned char *cipher; long cipher_len; }; static CK_RV cca_ecdh_pkcs_derive_kdf(STDLL_TokData_t *tokdata, SESSION *session, OBJECT *base_key_obj, CK_ECDH1_DERIVE_PARAMS *params, OBJECT *derived_key_obj, CK_ULONG derived_key_class, CK_ULONG derived_key_type, struct cca_hybrid_ecdh_data *hybrid_data); static CK_RV init_cca_adapter_lock(STDLL_TokData_t *tokdata) { struct cca_private_data *cca_private = tokdata->private_data; pthread_rwlockattr_t attr; unsigned long cnt; /* * Only for DOM-ANY, we will perform domain selections. Thus, we only need * to use the CCA adapter lock for for DOM-ANY configurations. */ if (!cca_private->dom_any) return CKR_OK; cnt = __sync_add_and_fetch(&cca_adapter_rwlock_ref_count, 1); if (cnt > 1) return CKR_OK; #if !defined(_AIX) if (pthread_rwlockattr_init(&attr) != 0) { TRACE_ERROR("pthread_rwlockattr_init failed\n"); OCK_SYSLOG(LOG_ERR, "%s: Failed to initialize the CCA adapter lock\n", __func__); return CKR_CANT_LOCK; } if (pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP) != 0) { TRACE_ERROR("pthread_rwlockattr_setkind_np failed\n"); OCK_SYSLOG(LOG_ERR, "%s: Failed to initialize the CCA adapter lock\n", __func__); pthread_rwlockattr_destroy(&attr); return CKR_CANT_LOCK; } #endif if (pthread_rwlock_init(&cca_adapter_rwlock, &attr) != 0) { TRACE_ERROR("pthread_rwlock_init failed\n"); OCK_SYSLOG(LOG_ERR, "%s: Failed to initialize the CCA adapter lock\n", __func__); pthread_rwlockattr_destroy(&attr); return CKR_CANT_LOCK; } pthread_rwlockattr_destroy(&attr); return CKR_OK; } static void destroy_cca_adapter_lock(STDLL_TokData_t *tokdata) { struct cca_private_data *cca_private = tokdata->private_data; unsigned long cnt; /* * Only for DOM-ANY, we will perform domain selections. Thus, we only need * to use the CCA adapter lock for for DOM-ANY configurations. */ if (!cca_private->dom_any) return; cnt = __sync_sub_and_fetch(&cca_adapter_rwlock_ref_count, 1); if (cnt == 0) pthread_rwlock_destroy(&cca_adapter_rwlock); } /* * Helper function: Analyse given CCA token. * returns TRUE and keytype, keybitsize, and MKVP address if token is known * and seems to be valid (only basic checks are done), otherwise FALSE. */ CK_BBOOL analyse_cca_key_token(const CK_BYTE *t, CK_ULONG tlen, enum cca_token_type *keytype, unsigned int *keybitsize, const CK_BYTE **mkvp) { if (t[0] == 0x01 && (t[4] == 0x00 || t[4] == 0x01)) { /* internal secure cca des data key with exact 64 bytes */ if (tlen != 64) { TRACE_DEVEL("CCA DES token has invalid token size %lu != 64\n", tlen); return FALSE; } *keytype = sec_des_data_key; if (t[4] == 0x00) { /* version 0 */ /* CV base is at offset 32, regardless of the type of key */ uint64_t cv = *((uint64_t *)&(t[32])); /* make it endian-safe */ cv = be64toh(cv); /* bits 40-42, but numbered starting from the MSB */ uint64_t keyform_mask = 0xE00000; /* rshift keyform to a form that'll fit in a byte */ uint8_t keyform = (cv & keyform_mask) >> 21; /* * refer to Figure 37 of LoZ CCA Programmer's Guide, v8 (2014) * also available online at https://www.ibm.com/docs/en/linux-on-systems?topic=table-control-vector-base-bit-maps#l0wskc02_cvbbmap__wskc_cv_base_bit_map_1_of_4 */ switch (keyform) { case 0: { *keybitsize = 8 * 8; break; } case 2: /* DOUBLE */ case 6: { /* DOUBLE-O */ *keybitsize = 2 * 8 * 8; break; } case 3: /* TRIPLE */ case 7: { /* TRIPLE-O */ *keybitsize = 3 * 8 * 8; break; } default: { TRACE_DEVEL("CCA DES DATA CV keyform has invalid value (%02d) for version 0 format specifications.\n", keyform); return FALSE; } } } else if (t[4] == 0x01) { /* version 1 */ if (t[59] == 0x10) *keybitsize = 16 * 8; else if (t[59] == 0x20) *keybitsize = 24 * 8; else { TRACE_DEVEL("CCA DES data key token has invalid/unknown keysize 0x%02x for version 1 format specifications.\n", (int)t[59]); return FALSE; } } *mkvp = &t[8]; return TRUE; } if (t[0] == 0x01 && t[4] == 0x04) { /* internal secure cca aes data key with exact 64 bytes */ if (tlen != 64) { TRACE_DEVEL("CCA AES data key token has invalid token size %lu != 64\n", tlen); return FALSE; } *keytype = sec_aes_data_key; *keybitsize = be16toh(*((uint16_t *)(t + 56))); if (*keybitsize != 128 && *keybitsize != 192 && *keybitsize != 256) { TRACE_DEVEL("CCA AES data key token has invalid/unknown keybitsize %u\n", *keybitsize); return FALSE; } *mkvp = &t[8]; return TRUE; } if (t[0] == 0x01 && t[4] == 0x05 && t[41] == 0x02) { /* internal variable length secure cca aes cipher key */ uint16_t key_type = be16toh(*((uint16_t*)(t + 42))); if (key_type != 0x0001) { TRACE_DEVEL("CCA AES cipher key token has invalid/unknown keytype 0x%04hx\n", key_type); return FALSE; } *keytype = sec_aes_cipher_key; if (t[28] == 0x00) { /* V0 payload */ switch (be16toh(*((uint16_t*)(t + 38)))) { case 512: *keybitsize = 128; break; case 576: *keybitsize = 192; break; case 640: *keybitsize = 256; break; default: *keybitsize = 0; /* unknown */ break; } } else { *keybitsize = 0; /* no chance to find out the key bit size for V1 */ } *mkvp = &t[10]; return TRUE; } if (t[0] == 0x01 && t[4] == 0x05 && t[41] == 0x03) { /* internal variable length HMAC key */ uint16_t key_type = be16toh(*((uint16_t*)(t + 42))); if (key_type != 0x0002) { TRACE_DEVEL("CCA HMAC key token has invalid/unknown keytype 0x%04hx\n", key_type); return FALSE; } if (t[8] != 0x03) { TRACE_DEVEL("CCA HMAC key token has unsupported format t[8]=%hhu != 0x03\n", t[8]); return FALSE; } if (t[26] != 0x02) { TRACE_DEVEL("CCA HMAC key token has unsupported format t[26]=%hhu != 0x02\n", t[26]); return FALSE; } if (t[27] != 0x02) { TRACE_DEVEL("CCA HMAC key token has unsupported format t[27]=%hhu != 0x02\n", t[26]); return FALSE; } if (t[28] != 0x00) { TRACE_DEVEL("CCA HMAC key token has unsupported format t[28]=%hhu != 0x00\n", t[26]); return FALSE; } *keytype = sec_hmac_key; *keybitsize = be16toh(*((uint16_t *)(t + CCA_HMAC_INTTOK_PAYLOAD_LENGTH_OFFSET))); /* this is not really the bitsize but the bitsize of the payload */ if (*keybitsize < 80 || *keybitsize > 2432) { TRACE_DEVEL("CCA HMAC key token has invalid/unknown payload bit size %u\n", *keybitsize); return FALSE; } *mkvp = &t[10]; return TRUE; } if (t[0] == 0x1f && (t[CCA_RSA_INTTOK_PRIVKEY_OFFSET] == 0x30 || t[CCA_RSA_INTTOK_PRIVKEY_OFFSET] == 0x31)) { /* internal secure cca private rsa key, ME or CRT format */ uint16_t n, privsec_len; privsec_len = be16toh(*((uint16_t *)(t + CCA_RSA_INTTOK_PRIVKEY_OFFSET + 2))); if (CCA_RSA_INTTOK_PRIVKEY_OFFSET + privsec_len >= (int) tlen) { TRACE_DEVEL("CCA RSA key token has invalid priv section len or token size\n"); return FALSE; } if (t[CCA_RSA_INTTOK_PRIVKEY_OFFSET + privsec_len] != 0x04) { TRACE_DEVEL("CCA RSA key token has invalid pub section marker\n"); return FALSE; } n = be16toh(*((uint16_t *)(t + CCA_RSA_INTTOK_PRIVKEY_OFFSET + privsec_len + 8))); *keytype = sec_rsa_priv_key; *keybitsize = n; if (t[CCA_RSA_INTTOK_PRIVKEY_OFFSET] == 0x30) *mkvp = &t[CCA_RSA_INTTOK_PRIVKEY_OFFSET + 104]; else *mkvp = &t[CCA_RSA_INTTOK_PRIVKEY_OFFSET + 116]; return TRUE; } if (t[0] == 0x1e && t[CCA_RSA_INTTOK_HDR_LENGTH] == 0x04) { /* external RSA public key token */ uint16_t n; n = be16toh(*((uint16_t *)(t + CCA_RSA_INTTOK_HDR_LENGTH + 8))); *keytype = sec_rsa_publ_key; *keybitsize = n; *mkvp = NULL; return TRUE; } if (t[0] == 0x1f && t[8] == 0x20) { /* internal secure cca private ecc key */ uint16_t ec_curve_bits; if (t[8+4] != 0x01) { TRACE_DEVEL("CCA private ECC key token has invalid wrapping method 0x%02hhx\n", t[8+4]); return FALSE; } if (t[8+10] != 0x08) { TRACE_DEVEL("CCA private ECC key token has invalid key format 0x%02hhx\n", t[8+10]); return FALSE; } ec_curve_bits = be16toh(*((uint16_t *)(t + 8 + 12))); *keytype = sec_ecc_priv_key; *keybitsize = ec_curve_bits; *mkvp = &t[8+16]; return TRUE; } if (t[0] == 0x1e && t[8] == 0x21) { /* external ECC public key token */ uint16_t ec_curve_bits; ec_curve_bits = be16toh(*((uint16_t *)(t + 8 + 10))); *keytype = sec_ecc_publ_key; *keybitsize = ec_curve_bits; *mkvp = NULL; return TRUE; } if (t[0] == 0x1f && t[8] == 0x50) { /* internal secure cca private QSA key */ uint16_t privsec_len; uint8_t algo_id; privsec_len = be16toh(*((uint16_t *) (t + CCA_QSA_INTTOK_PRIVKEY_OFFSET + 2))); if (CCA_QSA_INTTOK_PRIVKEY_OFFSET + privsec_len > (int)tlen) { TRACE_DEVEL("CCA QSA key token has invalid priv section len or " "token size\n"); return FALSE; } algo_id = t[CCA_QSA_INTTOK_PRIVKEY_OFFSET + CCA_QSA_INTTOK_ALGO_ID_OFFSET]; switch (algo_id) { case CCA_QSA_ALGO_DILITHIUM_ROUND_2: case CCA_QSA_ALGO_DILITHIUM_ROUND_3: case CCA_QSA_ALGO_ML_DSA_PURE: case CCA_QSA_ALGO_ML_DSA_PRE_HASH: case CCA_QSA_ALGO_ML_KEM: *keytype = sec_qsa_priv_key; break; default: TRACE_DEVEL("CCA QSA key token has invalid algorithm ID\n"); return FALSE; } *keybitsize = 0; /* no chance to find out the key bit size */ *mkvp = &t[CCA_QSA_INTTOK_PRIVKEY_OFFSET + CCA_QSA_INTTOK_MKVP_OFFSET]; return TRUE; } if (t[0] == 0x1e && t[8] == 0x51) { /* external QSA public key token */ uint16_t publsec_len; uint8_t algo_id; publsec_len = be16toh(*((uint16_t *) (t + CCA_QSA_EXTTOK_PUBLKEY_OFFSET + 2))); if (CCA_QSA_EXTTOK_PUBLKEY_OFFSET + publsec_len > (int)tlen) { TRACE_DEVEL("CCA QSA key token has invalid publ section len or " "token size\n"); return FALSE; } algo_id = t[CCA_QSA_EXTTOK_PUBLKEY_OFFSET + CCA_QSA_EXTTOK_ALGO_ID_OFFSET]; switch (algo_id) { case CCA_QSA_ALGO_DILITHIUM_ROUND_2: case CCA_QSA_ALGO_DILITHIUM_ROUND_3: case CCA_QSA_ALGO_ML_DSA_PURE: case CCA_QSA_ALGO_ML_DSA_PRE_HASH: case CCA_QSA_ALGO_ML_KEM: *keytype = sec_qsa_publ_key; break; default: TRACE_DEVEL("CCA QSA key token has invalid algorithm ID\n"); return FALSE; } *keybitsize = 0; /* no chance to find out the key bit size */ *mkvp = NULL; return TRUE; } return FALSE; } CK_RV check_expected_mkvp(STDLL_TokData_t *tokdata, enum cca_token_type keytype, const CK_BYTE *mkvp, CK_BBOOL *new_mk) { struct cca_private_data *cca_private = tokdata->private_data; const char *mktype; const CK_BYTE *expected_mkvp, *new_mkvp; if (new_mk != NULL) *new_mk = FALSE; switch (keytype) { case sec_des_data_key: expected_mkvp = cca_private->expected_sym_mkvp; new_mkvp = cca_mk_change_find_mkvp_in_ops(tokdata, CCA_MK_SYM, NULL); mktype = "SYM"; break; case sec_aes_data_key: case sec_aes_cipher_key: case sec_hmac_key: expected_mkvp = cca_private->expected_aes_mkvp; new_mkvp = cca_mk_change_find_mkvp_in_ops(tokdata, CCA_MK_AES, NULL); mktype = "AES"; break; case sec_rsa_priv_key: case sec_ecc_priv_key: case sec_qsa_priv_key: expected_mkvp = cca_private->expected_apka_mkvp; new_mkvp = cca_mk_change_find_mkvp_in_ops(tokdata, CCA_MK_APKA, NULL); mktype = "APKA"; break; case sec_rsa_publ_key: case sec_ecc_publ_key: case sec_qsa_publ_key: /* no MKVP checks for public keys */ return CKR_OK; default: TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } if (memcmp(mkvp, expected_mkvp, CCA_MKVP_LENGTH) != 0) { /* If an MK change operation is active, also allow the new MK */ if (new_mkvp != NULL && memcmp(mkvp, new_mkvp, CCA_MKVP_LENGTH) == 0) { TRACE_DEVEL("The key is wrapped by the new MK\n"); if (new_mk != NULL) *new_mk = TRUE; return CKR_OK; } TRACE_ERROR("The key's master key verification pattern does not " "match the expected CCA %s master key\n", mktype); TRACE_DEBUG_DUMP("MKVP of key: ", (CK_BYTE *)mkvp, CCA_MKVP_LENGTH); TRACE_DEBUG_DUMP("Expected MKVP: ", (CK_BYTE *)expected_mkvp, CCA_MKVP_LENGTH); OCK_SYSLOG(LOG_ERR, "The key's master key verification pattern does not " "match the expected CCA %s master key\n", mktype); return CKR_DEVICE_ERROR; } return CKR_OK; } /* Helper function: build attribute and update template */ 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; } if ((rv = template_update_attribute(tmpl, attr))) { TRACE_DEVEL("Template update for type=%lu failed, rv=0x%lx\n", type, rv); free(attr); return rv; } return CKR_OK; } static CK_RV cleanse_attribute(TEMPLATE *template, CK_ATTRIBUTE_TYPE attr_type) { CK_ATTRIBUTE *attr; if (template_attribute_get_non_empty(template, attr_type, &attr) != CKR_OK) return CKR_FUNCTION_FAILED; OPENSSL_cleanse(attr->pValue, attr->ulValueLen); return CKR_OK; } 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; USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNBRNGL(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &zero, NULL, (long *)&num_bytes, output + bytes_so_far); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBRNGL failed. return:%ld, reason:%ld\n", 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) { #define LDSYM_VERIFY(handle, verb) \ *(void **)(&dll_##verb) = dlsym(handle, #verb); \ if ((error = dlerror()) != NULL) { \ OCK_SYSLOG(LOG_ERR, \ "Loading verb %s failed: %s\n", #verb, error); \ TRACE_ERROR("%s: Loading verb %s failed: %s\n", \ __func__, #verb, error); \ return CKR_FUNCTION_FAILED; \ } char *error = NULL; dlerror(); /* Clear existing error */ LDSYM_VERIFY(hdl, CSNBCKI); LDSYM_VERIFY(hdl, CSNBCKM); LDSYM_VERIFY(hdl, CSNBDKX); LDSYM_VERIFY(hdl, CSNBDKM); LDSYM_VERIFY(hdl, CSNBKEX); LDSYM_VERIFY(hdl, CSNBKGN); LDSYM_VERIFY(hdl, CSNBKGN2); LDSYM_VERIFY(hdl, CSNBKIM); LDSYM_VERIFY(hdl, CSNBKPI); LDSYM_VERIFY(hdl, CSNBKPI2); LDSYM_VERIFY(hdl, CSNBKSI); LDSYM_VERIFY(hdl, CSNBKRC); LDSYM_VERIFY(hdl, CSNBAKRC); LDSYM_VERIFY(hdl, CSNBKRD); LDSYM_VERIFY(hdl, CSNBKRL); LDSYM_VERIFY(hdl, CSNBKRR); LDSYM_VERIFY(hdl, CSNBKRW); LDSYM_VERIFY(hdl, CSNDKRC); LDSYM_VERIFY(hdl, CSNDKRD); LDSYM_VERIFY(hdl, CSNDKRL); LDSYM_VERIFY(hdl, CSNDKRR); LDSYM_VERIFY(hdl, CSNDKRW); LDSYM_VERIFY(hdl, CSNBKYT); LDSYM_VERIFY(hdl, CSNBKYTX); LDSYM_VERIFY(hdl, CSNBKTC); LDSYM_VERIFY(hdl, CSNBKTC2); LDSYM_VERIFY(hdl, CSNBKTR); LDSYM_VERIFY(hdl, CSNBRNG); LDSYM_VERIFY(hdl, CSNBRNGL); LDSYM_VERIFY(hdl, CSNBSAE); LDSYM_VERIFY(hdl, CSNBSAD); LDSYM_VERIFY(hdl, CSNBDEC); LDSYM_VERIFY(hdl, CSNBENC); LDSYM_VERIFY(hdl, CSNBMGN); LDSYM_VERIFY(hdl, CSNBMVR); LDSYM_VERIFY(hdl, CSNBKTB); LDSYM_VERIFY(hdl, CSNBKTB2); LDSYM_VERIFY(hdl, CSNDPKG); LDSYM_VERIFY(hdl, CSNDPKB); LDSYM_VERIFY(hdl, CSNBOWH); LDSYM_VERIFY(hdl, CSNDPKI); LDSYM_VERIFY(hdl, CSNDDSG); LDSYM_VERIFY(hdl, CSNDDSV); LDSYM_VERIFY(hdl, CSNDKTC); LDSYM_VERIFY(hdl, CSNDPKX); LDSYM_VERIFY(hdl, CSNDSYI); LDSYM_VERIFY(hdl, CSNDSYI2); LDSYM_VERIFY(hdl, CSNDSYX); LDSYM_VERIFY(hdl, CSUACFQ); LDSYM_VERIFY(hdl, CSUACFC); LDSYM_VERIFY(hdl, CSNDSBC); LDSYM_VERIFY(hdl, CSNDSBD); LDSYM_VERIFY(hdl, CSUALCT); LDSYM_VERIFY(hdl, CSUAACM); LDSYM_VERIFY(hdl, CSUAACI); LDSYM_VERIFY(hdl, CSNDPKH); LDSYM_VERIFY(hdl, CSNDPKR); LDSYM_VERIFY(hdl, CSUAMKD); LDSYM_VERIFY(hdl, CSNDRKD); LDSYM_VERIFY(hdl, CSNDRKL); LDSYM_VERIFY(hdl, CSNDSYG); LDSYM_VERIFY(hdl, CSNBPTR); LDSYM_VERIFY(hdl, CSNBCPE); LDSYM_VERIFY(hdl, CSNBCPA); LDSYM_VERIFY(hdl, CSNBPGN); LDSYM_VERIFY(hdl, CSNBPVR); LDSYM_VERIFY(hdl, CSNBDKG); LDSYM_VERIFY(hdl, CSNBEPG); LDSYM_VERIFY(hdl, CSNBCVE); LDSYM_VERIFY(hdl, CSNBCSG); LDSYM_VERIFY(hdl, CSNBCSV); LDSYM_VERIFY(hdl, CSNBCVG); LDSYM_VERIFY(hdl, CSNBKTP); LDSYM_VERIFY(hdl, CSNDPKE); LDSYM_VERIFY(hdl, CSNDPKD); LDSYM_VERIFY(hdl, CSNBPEX); LDSYM_VERIFY(hdl, CSNBPEXX); LDSYM_VERIFY(hdl, CSUARNT); LDSYM_VERIFY(hdl, CSNBCVT); LDSYM_VERIFY(hdl, CSNBMDG); LDSYM_VERIFY(hdl, CSUACRA); LDSYM_VERIFY(hdl, CSUACRD); LDSYM_VERIFY(hdl, CSNBTRV); LDSYM_VERIFY(hdl, CSNBSKY); LDSYM_VERIFY(hdl, CSNBSPN); LDSYM_VERIFY(hdl, CSNBPCU); LDSYM_VERIFY(hdl, CSNDEDH); LDSYM_VERIFY(hdl, CSUAPRB); LDSYM_VERIFY(hdl, CSNDTBC); LDSYM_VERIFY(hdl, CSNDRKX); LDSYM_VERIFY(hdl, CSNBKET); LDSYM_VERIFY(hdl, CSNBHMG); LDSYM_VERIFY(hdl, CSNBHMV); LDSYM_VERIFY(hdl, CSNBCTT2); LDSYM_VERIFY(hdl, CSUACFV); LDSYM_VERIFY(hdl, CSNBRKA); LDSYM_VERIFY(hdl, CSNBKTR2); return CKR_OK; } /* Called during token_specific_init() , no need to obtain CCA adapter lock */ static CK_RV cca_get_version(STDLL_TokData_t *tokdata) { struct cca_private_data *cca_private = tokdata->private_data; unsigned char exit_data[4] = { 0, }; unsigned char version_data[20] = { 0 }; long return_code, reason_code; long version_data_length; long exit_data_len = 0; /* Get CCA host library version */ version_data_length = sizeof(version_data); dll_CSUACFV(&return_code, &reason_code, &exit_data_len, exit_data, &version_data_length, version_data); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSUACFV failed. return:%ld, reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } /* CSUACFV returns a null-terminated version string */ TRACE_DEVEL("CCA Version string: %s\n", version_data); if (sscanf((char *)version_data, "%u.%u.%u", &cca_private->cca_lib_version.ver, &cca_private->cca_lib_version.rel, &cca_private->cca_lib_version.mod) != 3) { TRACE_ERROR("CCA library version is invalid: %s\n", version_data); return CKR_FUNCTION_FAILED; } if (cca_private->cca_lib_version.ver < CCA_MIN_VERSION || (cca_private->cca_lib_version.ver == CCA_MIN_VERSION && cca_private->cca_lib_version.rel < CCA_MIN_RELEASE)) { TRACE_ERROR("The CCA host library version is too old: %u.%u.%u, " "required: %u.%u or later\n", cca_private->cca_lib_version.ver, cca_private->cca_lib_version.rel, cca_private->cca_lib_version.mod, CCA_MIN_VERSION, CCA_MIN_RELEASE); OCK_SYSLOG(LOG_ERR,"The CCA host library version is too old: %u.%u.%u, " "required: %u.%u or later\n", cca_private->cca_lib_version.ver, cca_private->cca_lib_version.rel, cca_private->cca_lib_version.mod, CCA_MIN_VERSION, CCA_MIN_RELEASE); return CKR_DEVICE_ERROR; } return CKR_OK; } /* * Called from within cca_iterate_adapters() handler function, thus no need to * obtain CCA adapter lock */ CK_RV cca_get_adapter_serial_number(char *serialno) { unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; long return_code, reason_code, rule_array_count, verb_data_length; memcpy(rule_array, "STATCRD2", CCA_KEYWORD_SIZE); rule_array_count = 1; verb_data_length = 0; dll_CSUACFQ(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &verb_data_length, NULL); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSUACFQ (STATCRD2) failed. return:%ld, reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } memcpy(serialno, &rule_array[CCA_STATCRD2_SERIAL_NUMBER_OFFSET], CCA_SERIALNO_LENGTH); serialno[CCA_SERIALNO_LENGTH] = '\0'; return CKR_OK; } /* * Called from within cca_iterate_adapters() handler function, thus no need to * obtain CCA adapter lock */ CK_RV cca_get_mk_state(enum cca_mk_type mk_type, enum cca_cmk_state *cur, enum cca_nmk_state *new) { unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; long return_code, reason_code, rule_array_count, verb_data_length; char *cmk, *nmk; switch (mk_type) { case CCA_MK_SYM: memcpy(rule_array, "STATCCAE", CCA_KEYWORD_SIZE); rule_array_count = 1; break; case CCA_MK_AES: memcpy(rule_array, "STATAES ", CCA_KEYWORD_SIZE); rule_array_count = 1; break; case CCA_MK_APKA: memcpy(rule_array, "STATAPKA", CCA_KEYWORD_SIZE); rule_array_count = 1; break; default: return CKR_ARGUMENTS_BAD; } 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 (%s) failed. return:%ld, reason:%ld\n", rule_array, return_code, reason_code); return CKR_FUNCTION_FAILED; } switch (mk_type) { case CCA_MK_SYM: cmk = (char *)&rule_array[CCA_STATCCAE_SYM_CMK_OFFSET]; nmk = (char *)&rule_array[CCA_STATCCAE_SYM_NMK_OFFSET]; break; case CCA_MK_AES: cmk = (char *)&rule_array[CCA_STATAES_AES_CMK_OFFSET]; nmk = (char *)&rule_array[CCA_STATAES_AES_NMK_OFFSET]; break; case CCA_MK_APKA: cmk = (char *)&rule_array[CCA_STATAPKA_APKA_CMK_OFFSET]; nmk = (char *)&rule_array[CCA_STATAPKA_APKA_NMK_OFFSET]; break; default: return CKR_ARGUMENTS_BAD; } cmk[1] = '\0'; nmk[1] = '\0'; if (cur != NULL) { if (sscanf(cmk, "%d", (int *)cur) != 1) { TRACE_ERROR("Bad CMK status '%s'\n", cmk); return CKR_FUNCTION_FAILED; } } if (new != NULL) { if (sscanf(nmk, "%d", (int *)new) != 1) { TRACE_ERROR("Bad CMK status '%s'\n", nmk); return CKR_FUNCTION_FAILED; } } return CKR_OK; } /* * Called from within cca_iterate_adapters() handler function, thus no need to * obtain CCA adapter lock */ CK_RV cca_get_mkvps(unsigned char *cur_sym, unsigned char *new_sym, unsigned char *cur_aes, unsigned char *new_aes, unsigned char *cur_apka, unsigned char *new_apka) { unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; unsigned char verb_data[256] = { 0, }; long return_code, reason_code, rule_array_count, verb_data_length; unsigned short *id; /* Get master key verification patterns */ memset(rule_array, 0, sizeof(rule_array)); memcpy(rule_array, "STATICSB", CCA_KEYWORD_SIZE); rule_array_count = 1; verb_data_length = sizeof(verb_data); dll_CSUACFQ(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &verb_data_length, verb_data); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSUACFQ (STATICSB) failed . return:%ld, reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } if (cur_sym != NULL) { id = (unsigned short *)(verb_data + CCA_STATICSB_SYM_CMK_ID_OFFSET); if (be16toh(*id) != CCA_STATICSB_SYM_CMK_ID) { TRACE_ERROR("CSUACFQ (STATICSB) current SYM MKVP not available\n"); return CKR_FUNCTION_FAILED; } memcpy(cur_sym, verb_data + CCA_STATICSB_SYM_CMK_MKVP_OFFSET, CCA_MKVP_LENGTH); } if (new_sym != NULL) { id = (unsigned short *)(verb_data + CCA_STATICSB_SYM_NMK_ID_OFFSET); if (be16toh(*id) != CCA_STATICSB_SYM_NMK_ID) { TRACE_ERROR("CSUACFQ (STATICSB) new SYM MKVP not available\n"); return CKR_FUNCTION_FAILED; } memcpy(new_sym, verb_data + CCA_STATICSB_SYM_NMK_MKVP_OFFSET, CCA_MKVP_LENGTH); } if (cur_aes != NULL) { id = (unsigned short *)(verb_data + CCA_STATICSB_AES_CMK_ID_OFFSET); if (be16toh(*id) != CCA_STATICSB_AES_CMK_ID) { TRACE_ERROR("CSUACFQ (STATICSB) current AES MKVP not available\n"); return CKR_FUNCTION_FAILED; } memcpy(cur_aes, verb_data + CCA_STATICSB_AES_CMK_MKVP_OFFSET, CCA_MKVP_LENGTH); } if (new_aes != NULL) { id = (unsigned short *)(verb_data + CCA_STATICSB_AES_NMK_ID_OFFSET); if (be16toh(*id) != CCA_STATICSB_AES_NMK_ID) { TRACE_ERROR("CSUACFQ (STATICSB) new AES MKVP not available\n"); return CKR_FUNCTION_FAILED; } memcpy(new_aes, verb_data + CCA_STATICSB_AES_NMK_MKVP_OFFSET, CCA_MKVP_LENGTH); } if (cur_apka != NULL) { id = (unsigned short *)(verb_data + CCA_STATICSB_APKA_CMK_ID_OFFSET); if (be16toh(*id) != CCA_STATICSB_APKA_CMK_ID) { TRACE_ERROR("CSUACFQ (STATICSB) current APKA MKVP not available\n"); return CKR_FUNCTION_FAILED; } memcpy(cur_apka, verb_data + CCA_STATICSB_APKA_CMK_MKVP_OFFSET, CCA_MKVP_LENGTH); } if (new_apka != NULL) { id = (unsigned short *)(verb_data + CCA_STATICSB_APKA_NMK_ID_OFFSET); if (be16toh(*id) != CCA_STATICSB_APKA_NMK_ID) { TRACE_ERROR("CSUACFQ (STATICSB) new APKA MKVP not available\n"); return CKR_FUNCTION_FAILED; } memcpy(new_apka, verb_data + CCA_STATICSB_APKA_NMK_MKVP_OFFSET, CCA_MKVP_LENGTH); } return CKR_OK; } static CK_RV cca_cmp_mkvp(unsigned char mkvp[CCA_MKVP_LENGTH], unsigned char exp_mkvp[CCA_MKVP_LENGTH], unsigned char *new_mkvp, const char *mktype, const char *adapter, unsigned short card, unsigned short domain, CK_BBOOL expected_mkvps_set) { /* * If an MK change operation is pending, the current MK may already * be the new MK of the operation. */ if (new_mkvp != NULL && memcmp(mkvp, new_mkvp, CCA_MKVP_LENGTH) == 0) { TRACE_DEVEL("CCA %s master key on adapter %s (%02X.%04X) has " "the new MK\n", mktype, adapter, card, domain); return CKR_OK; } if (expected_mkvps_set == FALSE && memcmp(exp_mkvp, cca_zero_mkvp, CCA_MKVP_LENGTH) == 0) { /* zero expected MKVP, copy current one */ memcpy(exp_mkvp, mkvp, CCA_MKVP_LENGTH); } else { if (memcmp(mkvp, exp_mkvp, CCA_MKVP_LENGTH) != 0) { TRACE_ERROR("CCA %s master key on adapter %s (%02X.%04X) does not " "match the %s master key\n", mktype, adapter, card, domain, expected_mkvps_set ? "expected" : "other APQN's"); OCK_SYSLOG(LOG_ERR, "CCA %s master key on adapter %s (%02X.%04X) does " "not match the %s master key\n", mktype, adapter, card, domain, expected_mkvps_set ? "expected" : "other APQN's"); return CKR_DEVICE_ERROR; } } return CKR_OK; } static CK_RV cca_get_and_check_mkvps(STDLL_TokData_t *tokdata, const char *adapter, unsigned short card, unsigned short domain, void *private) { struct cca_private_data *cca_private = tokdata->private_data; char serialno[CCA_SERIALNO_LENGTH + 1]; unsigned char sym_mkvp[CCA_MKVP_LENGTH]; unsigned char sym_new_mkvp[CCA_MKVP_LENGTH]; unsigned char aes_mkvp[CCA_MKVP_LENGTH]; unsigned char aes_new_mkvp[CCA_MKVP_LENGTH]; unsigned char apka_mkvp[CCA_MKVP_LENGTH]; unsigned char apka_new_mkvp[CCA_MKVP_LENGTH]; unsigned char *op_sym_mkvp, *op_aes_mkvp, *op_apka_mkvp; unsigned int sym_op_idx = 0, aes_op_idx = 0, apka_op_idx = 0; enum cca_cmk_state mk_state; enum cca_nmk_state sym_new_state, aes_new_state, apka_new_state; CK_RV rc, rc2 = CKR_OK; UNUSED(private); #if defined(_AIX) /* populate program_invocation_short_name for later use */ populate_progname(); #endif /* Get current adapter serial number */ rc = cca_get_adapter_serial_number(serialno); if (rc != CKR_OK) { TRACE_ERROR("cca_get_adapter_serial_number failed for %s (%02X.%04X)\n", adapter, card, domain); return rc; } TRACE_DEVEL("%s (%02X.%04X) serialno: %s\n", adapter, card, domain, serialno); /* Get status of SYM master key (DES, 3DES keys) */ rc = cca_get_mk_state(CCA_MK_SYM, &mk_state, &sym_new_state); if (rc != CKR_OK) { TRACE_ERROR("cca_get_mk_state (SYM) failed for %s (%02X.%04X)\n", adapter, card, domain); return rc; } /* Ensure the master key is set in the card */ if (mk_state != CCA_CMK_STATUS_FULL) { TRACE_ERROR("CCA SYM master key is not yet loaded on adapter %s (%02X.%04X)\n", adapter, card, domain); OCK_SYSLOG(LOG_ERR, "CCA SYM master key is not yet loaded on adapter %s (%02X.%04X)\n", adapter, card, domain); return CKR_DEVICE_ERROR; } /* Get status of AES master key (AES, HMAC keys) */ rc = cca_get_mk_state(CCA_MK_AES, &mk_state, &aes_new_state); if (rc != CKR_OK) { TRACE_ERROR("cca_get_mk_state (AES) failed for %s (%02X.%04X)\n", adapter, card, domain); return rc; } /* Ensure the master key is set in the card */ if (mk_state != CCA_CMK_STATUS_FULL) { TRACE_ERROR("CCA AES master key is not yet loaded on adapter %s (%02X.%04X)\n", adapter, card, domain); OCK_SYSLOG(LOG_ERR, "CCA AES master key is not yet loaded on adapter %s (%02X.%04X)\n", adapter, card, domain); return CKR_DEVICE_ERROR; } /* Get status of APKA master key (RSA and ECC keys) */ rc = cca_get_mk_state(CCA_MK_APKA, &mk_state, &apka_new_state); if (rc != CKR_OK) { TRACE_ERROR("cca_get_mk_state (APKA) failed for %s (%02X.%04X)\n", adapter, card, domain); return rc; } /* Ensure the master key is set in the card */ if (mk_state != CCA_CMK_STATUS_FULL) { TRACE_ERROR("CCA APKA master key is not yet loaded on adapter %s (%02X.%04X)\n", adapter, card, domain); OCK_SYSLOG(LOG_ERR, "CCA APKA master key is not yet loaded on adapter %s (%02X.%04X)\n", adapter, card, domain); return CKR_DEVICE_ERROR; } /* Get master key verification patterns */ rc = cca_get_mkvps(sym_mkvp, sym_new_mkvp, aes_mkvp, aes_new_mkvp, apka_mkvp, apka_new_mkvp); if (rc != CKR_OK) { TRACE_ERROR("cca_get_mkvps failed for %s (%02X.%04X)\n", adapter, card, domain); return rc; } TRACE_DEBUG("Master key verification patterns for %s (%02X.%04X)\n", adapter, card, domain); TRACE_DEBUG_DUMP("SYM CUR MKVP: ", sym_mkvp, CCA_MKVP_LENGTH); if (sym_new_state == CCA_NMK_STATUS_FULL) { TRACE_DEBUG_DUMP("SYM NEW MKVP: ", sym_new_mkvp, CCA_MKVP_LENGTH); } TRACE_DEBUG_DUMP("AES CUR MKVP: ", aes_mkvp, CCA_MKVP_LENGTH); if (aes_new_state == CCA_NMK_STATUS_FULL) { TRACE_DEBUG_DUMP("AES NEW MKVP: ", aes_new_mkvp, CCA_MKVP_LENGTH); } TRACE_DEBUG_DUMP("APKA CUR MKVP: ", apka_mkvp, CCA_MKVP_LENGTH); if (apka_new_state == CCA_NMK_STATUS_FULL) { TRACE_DEBUG_DUMP("APKA NEW MKVP: ", apka_new_mkvp, CCA_MKVP_LENGTH); } op_sym_mkvp = cca_mk_change_find_mkvp_in_ops(tokdata, CCA_MK_SYM, &sym_op_idx); op_aes_mkvp = cca_mk_change_find_mkvp_in_ops(tokdata, CCA_MK_AES, &aes_op_idx); op_apka_mkvp = cca_mk_change_find_mkvp_in_ops(tokdata, CCA_MK_APKA, &apka_op_idx); /* Current MK can either be expected one, or new from operation (if any) */ rc = cca_cmp_mkvp(sym_mkvp, cca_private->expected_sym_mkvp, op_sym_mkvp, "SYM", adapter, card, domain, cca_private->expected_sym_mkvp_set); rc |= cca_cmp_mkvp(aes_mkvp, cca_private->expected_aes_mkvp, op_aes_mkvp, "AES", adapter, card, domain, cca_private->expected_aes_mkvp_set); rc |= cca_cmp_mkvp(apka_mkvp, cca_private->expected_apka_mkvp, op_apka_mkvp, "APKA", adapter, card, domain, cca_private->expected_apka_mkvp_set); /* * If new MK is set, it must be the one from the MK change operation(s). * If new MK is not set, the current MK must be the expected new MK of * the operation(s). For this case, report error only if not within the * pkcshsm_mk_change tool process. Otherwise the MK change operation could * not be canceled when the new MK register has already been cleared by * the HSM admin. */ if (op_sym_mkvp != NULL) { rc2 |= cca_cmp_mkvp(sym_new_state == CCA_NMK_STATUS_FULL ? sym_new_mkvp : sym_mkvp, op_sym_mkvp, NULL, sym_new_state == CCA_NMK_STATUS_FULL ? "SYM NEW" : "SYM CURRENT", adapter, card, domain, TRUE); if (sym_new_state != CCA_NMK_STATUS_FULL && strcmp(program_invocation_short_name, "pkcshsm_mk_change") == 0) rc2 = CKR_OK; rc |= rc2; } if (op_aes_mkvp != NULL) { rc2 |= cca_cmp_mkvp(aes_new_state == CCA_NMK_STATUS_FULL ? aes_new_mkvp : aes_mkvp, op_aes_mkvp, NULL, aes_new_state == CCA_NMK_STATUS_FULL ? "AES NEW" : "AES CURRENT", adapter, card, domain, TRUE); if (aes_new_state != CCA_NMK_STATUS_FULL && strcmp(program_invocation_short_name, "pkcshsm_mk_change") == 0) rc2 = CKR_OK; rc |= rc2; } if (op_apka_mkvp != NULL) { rc2 |= cca_cmp_mkvp(apka_new_state == CCA_NMK_STATUS_FULL ? apka_new_mkvp : apka_mkvp, op_apka_mkvp, NULL, apka_new_state == CCA_NMK_STATUS_FULL ? "APKA NEW" : "APKA CURRENT", adapter, card, domain, TRUE); if (apka_new_state != CCA_NMK_STATUS_FULL && strcmp(program_invocation_short_name, "pkcshsm_mk_change") == 0) rc2 = CKR_OK; rc |= rc2; } /* * If an MK change operation is active, the current APQN must be part * of each operation. */ if (op_sym_mkvp != NULL && !hsm_mk_change_apqns_find( cca_private->mk_change_ops[sym_op_idx].apqns, cca_private->mk_change_ops[sym_op_idx].num_apqns, card, domain)) { TRACE_ERROR("APQN %02X.%04X is used by the CCA token, but it is " "not part of the active MK change operation '%s'\n", card, domain, cca_private->mk_change_ops[sym_op_idx].mk_change_op); OCK_SYSLOG(LOG_ERR, "APQN %02X.%04X is used by the CCA token, but " "it is not part of the active MK change operation '%s'\n", card, domain, cca_private->mk_change_ops[sym_op_idx].mk_change_op); rc |= CKR_DEVICE_ERROR; } if (op_aes_mkvp != NULL && !hsm_mk_change_apqns_find( cca_private->mk_change_ops[aes_op_idx].apqns, cca_private->mk_change_ops[aes_op_idx].num_apqns, card, domain)) { TRACE_ERROR("APQN %02X.%04X is used by the CCA token, but it is " "not part of the active MK change operation '%s'\n", card, domain, cca_private->mk_change_ops[aes_op_idx].mk_change_op); OCK_SYSLOG(LOG_ERR, "APQN %02X.%04X is used by the CCA token, but " "it is not part of the active MK change operation '%s'\n", card, domain, cca_private->mk_change_ops[aes_op_idx].mk_change_op); rc |= CKR_DEVICE_ERROR; } if (op_apka_mkvp != NULL && !hsm_mk_change_apqns_find( cca_private->mk_change_ops[apka_op_idx].apqns, cca_private->mk_change_ops[apka_op_idx].num_apqns, card, domain)) { TRACE_ERROR("APQN %02X.%04X is used by the CCA token, but it is " "not part of the active MK change operation '%s'\n", card, domain, cca_private->mk_change_ops[apka_op_idx].mk_change_op); OCK_SYSLOG(LOG_ERR, "APQN %02X.%04X is used by the CCA token, but " "it is not part of the active MK change operation '%s'\n", card, domain, cca_private->mk_change_ops[apka_op_idx].mk_change_op); rc |= CKR_DEVICE_ERROR; } if (rc != CKR_OK) return CKR_DEVICE_ERROR; return CKR_OK; } static CK_RV cca_get_current_domain(unsigned short *domain) { /* * Only CCA on Linux on IBM Z supports CSU_DEFAULT_DOMAIN, all others * support only one domain (i.e. domain 0). */ #if !defined(__s390__) *domain = 0; #else const char *val; unsigned int num; char fname[290]; char buf[250]; CK_RV rc; val = getenv(CCA_DEFAULT_DOMAIN_ENVAR); if (val == NULL) { /* Get default domain from AP bus */ sprintf(fname, "%s/ap_domain", SYSFS_BUS_AP); rc = file_fgets(fname, buf, sizeof(buf)); if (rc != CKR_OK) return rc; if (sscanf(buf, "%u", &num) != 1) return CKR_FUNCTION_FAILED; *domain = num; return CKR_OK; } if (strcmp(val, CCA_DOMAIN_ANY) == 0) { /* DOM-ANY mode, can not determine single domain */ return CKR_DEVICE_ERROR; } /* domain specified */ if (sscanf(val, "%u", &num) != 1) return CKR_FUNCTION_FAILED; *domain = num; #endif return CKR_OK; } static CK_RV cca_get_current_card(unsigned short *card, char *serialret) { char serialno[CCA_SERIALNO_LENGTH + 1]; #if defined(__s390__) DIR *d; struct dirent *de; regex_t reg_buf; regmatch_t pmatch[1]; char fname[290]; char buf[250]; unsigned long val; #endif CK_BBOOL found = FALSE; CK_RV rc; /* Get serial number of current adapter */ rc = cca_get_adapter_serial_number(serialno); if (rc != CKR_OK) return rc; TRACE_DEVEL("serialno: %s\n", serialno); /* Only Linux on IBM Z supports to find the cards via sysfs, for all * others the default card is always the first card (i.e. card number 0). */ #if !defined(__s390__) *card = 0; found = TRUE; #else if (regcomp(®_buf, REGEX_CARD_PATTERN, REG_EXTENDED) != 0) { TRACE_ERROR("Failed to compile regular expression '%s'\n", REGEX_CARD_PATTERN); return CKR_FUNCTION_FAILED; } /* Find card with that serial number in Sysfs */ d = opendir(SYSFS_DEVICES_AP); if (d == NULL) { TRACE_ERROR("Directory %s is not available\n", SYSFS_DEVICES_AP); regfree(®_buf); return CKR_FUNCTION_FAILED; } while ((de = readdir(d)) != NULL) { if (regexec(®_buf, de->d_name, (size_t) 1, pmatch, 0) == 0) { /* Check for CCA cards only */ sprintf(fname, "%s/%s/ap_functions", SYSFS_DEVICES_AP, de->d_name); rc = file_fgets(fname, buf, sizeof(buf)); if (rc != CKR_OK) continue; if (sscanf(buf, "%lx", &val) != 1) val = 0x00000000; if ((val & MASK_COPRO) == 0) continue; sprintf(fname, "%s/%s/serialnr", SYSFS_DEVICES_AP, de->d_name); rc = file_fgets(fname, buf, sizeof(buf)); if (rc != CKR_OK) continue; if (strcmp(buf, serialno) != 0) continue; if (sscanf(de->d_name + 4, "%lx", &val) != 1) continue; found = TRUE; *card = val; break; } } closedir(d); regfree(®_buf); #endif /* __s390__ */ if (found && serialret != NULL) strcpy(serialret, serialno); if (found) TRACE_DEVEL("Current card is %02x with serialno %s\n", *card, serialno); else TRACE_ERROR("Card with serialno %s not found in sysfs\n", serialno); return found ? CKR_OK : CKR_DEVICE_ERROR; } /* * Must NOT hold the CCA adapter lock when called ! * May obtain the WRITE lock during iteration processing, but returns without * holding a lock. * The handler function is called when a single adapter/domain is selected, * and the WRITE lock may be held, thus the handler function must not obtain * an CCA adapter lock. */ static CK_RV cca_iterate_domains(STDLL_TokData_t *tokdata, const char *device, CK_RV (*cb)(STDLL_TokData_t *tokdata, const char *adapter, unsigned short card, unsigned short domain, void *private), void *cb_private) { struct cca_private_data *cca_private = tokdata->private_data; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; long return_code, reason_code, rule_array_count, device_name_len; unsigned char *device_name; unsigned short card, domain = 0; unsigned int i, num_found = 0; CK_RV rc2, rc = CKR_OK; char serialno[CCA_SERIALNO_LENGTH + 1] = { 0 }; if (cca_private->dom_any == FALSE) { rc = cca_get_current_domain(&domain); if (rc != CKR_OK) return rc; } if (cca_private->dev_any == FALSE) { rc = cca_get_current_card(&card, serialno); if (rc != CKR_OK) return rc; } /* * Obtain the CCA adapter WRITE lock if DOM-ANY and release it only after * domain selection has been turned back to default. */ if (cca_private->dom_any) { if (pthread_rwlock_wrlock(&cca_adapter_rwlock) != 0) { TRACE_DEVEL("CCA adapter WR-Lock failed.\n"); return CKR_CANT_LOCK; } } for (i = 0; i < cca_private->num_usagedoms; i++) { /* Allocate the adapter based on device or serialno and domain */ if (cca_private->dev_any) { memcpy(rule_array, "DEVICE ", CCA_KEYWORD_SIZE); rule_array_count = 1; device_name_len = strlen(device); device_name = (unsigned char *)device; } else { memcpy(rule_array, "SERIAL ", CCA_KEYWORD_SIZE); rule_array_count = 1; device_name_len = strlen(serialno); device_name = (unsigned char *)serialno; } if (cca_private->dom_any) { sprintf((char *)(rule_array + CCA_KEYWORD_SIZE), "DOMN%04u", cca_private->usage_domains[i]); rule_array_count = 2; domain = cca_private->usage_domains[i]; } dll_CSUACRA(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &device_name_len, device_name); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSUACRA failed for %s domain %x. return:%ld, reason:%ld\n", device_name, domain, return_code, reason_code); rc = CKR_FUNCTION_FAILED; break; } if (cca_private->dev_any) { rc2 = cca_get_current_card(&card, NULL); if (rc2 != CKR_OK) { if (rc2 == CKR_FUNCTION_FAILED) /* device not avail., ignore */ rc2 = CKR_OK; else rc |= rc2; goto deallocate; } } rc2 = cb(tokdata, device, card, domain, cb_private); if (rc2 == CKR_OK) num_found++; if (rc2 == CKR_FUNCTION_FAILED) /* device not available, ignore */ rc2 = CKR_OK; rc |= rc2; deallocate: /* Deallocate the adapter */ if (cca_private->dom_any) { memcpy(rule_array + CCA_KEYWORD_SIZE, "DOMN-DEF", CCA_KEYWORD_SIZE); rule_array_count = 2; } dll_CSUACRD(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &device_name_len, device_name); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSUACRD failed for %s domain %x. return:%ld, reason:%ld\n", device_name, domain, return_code, reason_code); rc = CKR_FUNCTION_FAILED; break; } if (cca_private->dom_any == FALSE) break; } /* Release the CCA adapter WRITE lock now if DOM-ANY */ if (cca_private->dom_any) { if (pthread_rwlock_unlock(&cca_adapter_rwlock) != 0) { TRACE_DEVEL("CCA adapter Unlock failed.\n"); return CKR_CANT_LOCK; } } if (rc != CKR_OK) return CKR_DEVICE_ERROR; if (num_found == 0) /* none available */ return CKR_FUNCTION_FAILED; return CKR_OK; } /* * Must NOT hold the CCA adapter lock when called ! * May obtain the WRITE lock during iteration processing, but returns without * holding a lock. * The handler function is called when a single adapter/domain is selected, * and the WRITE lock may be held, thus the handler function must not obtain * an CCA adapter lock. */ CK_RV cca_iterate_adapters(STDLL_TokData_t *tokdata, CK_RV (*cb)(STDLL_TokData_t *tokdata, const char *adapter, unsigned short card, unsigned short domain, void *private), void *cb_private) { struct cca_private_data *cca_private = tokdata->private_data; unsigned int adapter, num_found = 0; char device_name[9] = {0, }; unsigned short card, domain; CK_RV rc, rc2; if (cca_private->dev_any == FALSE && cca_private->dom_any == FALSE) { /* CCA default adapter and domain selection */ rc = cca_get_current_card(&card, NULL); if (rc != CKR_OK) return rc; rc = cca_get_current_domain(&domain); if (rc != CKR_OK) return rc; rc = cb(tokdata, "DEFAULT", card, domain, cb_private); if (rc != CKR_OK) return rc; } else if (cca_private->dev_any == FALSE) { /* CCA default adapter selection, but domain ANY */ rc = cca_iterate_domains(tokdata, "DEFAULT", cb, cb_private); if (rc != CKR_OK) return rc; } else { /* Device ANY and domain ANY or default */ for (adapter = 1, rc = CKR_OK; adapter <= cca_private->num_adapters; adapter++) { sprintf(device_name, "CRP%02u", adapter); rc2 = cca_iterate_domains(tokdata, device_name, cb, cb_private); if (rc2 == CKR_FUNCTION_FAILED) /* adapter not available, ignore */ rc2 = CKR_OK; if (rc2 == CKR_OK) num_found++; rc |= rc2; } if (rc != CKR_OK) return CKR_DEVICE_ERROR; if (num_found == 0) return CKR_FUNCTION_FAILED; } return CKR_OK; } static CK_RV cca_get_adapter_domain_selection_infos(STDLL_TokData_t *tokdata) { struct cca_private_data *cca_private = tokdata->private_data; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; long return_code, reason_code, rule_array_count, verb_data_length; #if defined(__s390__) unsigned int i; const char *val; #endif /* * Only Linux on IBM Z supports the AUTOSELECT option with adapter/domain * selection using CSU_DEFAULT_ADAPTER with 'DEV-ANY' and/or * CSU_DEFAULT_DOMAIN with 'DOM-ANY'. All other platforms only support * selection of one distinct adapter, and no domain selection at all. * Enable the AUTOSELECT (i.e. 'DEV-ANY' / 'DOM-ANY') support code * only for CCA on Linux on IBM Z. */ #if defined(__s390__) /* Check if adapter and/or domain auto-selection is used */ val = getenv(CCA_DEFAULT_ADAPTER_ENVAR); if (val != NULL && strcmp(val, CCA_DEVICE_ANY) == 0) cca_private->dev_any = TRUE; TRACE_DEVEL("dev_any: %d\n", cca_private->dev_any); val = getenv(CCA_DEFAULT_DOMAIN_ENVAR); if (val != NULL && strcmp(val, CCA_DOMAIN_ANY) == 0) cca_private->dom_any = TRUE; TRACE_DEVEL("dom_any: %d\n", cca_private->dom_any); #endif /* Get number of adapters, current adapter serial number */ memcpy(rule_array, "STATCRD2", CCA_KEYWORD_SIZE); rule_array_count = 1; verb_data_length = 0; dll_CSUACFQ(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &verb_data_length, NULL); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSUACFQ (STATCRD2) failed. return:%ld, reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } rule_array[CCA_KEYWORD_SIZE] = '\0'; if (sscanf((char *)rule_array, "%u", &cca_private->num_adapters) != 1) { TRACE_ERROR("Failed to parse STATCRD2 output: number of adapters: %s\n", rule_array); return CKR_FUNCTION_FAILED; } TRACE_DEVEL("num_adapters: %u\n", cca_private->num_adapters); #if !defined(__s390__) /* * Short-circuit for all non-s390x platforms. No domains are supported on * those platforms, therefore we force a single domain and skip all future * tests. */ cca_private->num_usagedoms = 1; cca_private->num_domains = 1; #else /* Get number of domains */ memcpy(rule_array, "DOM-NUMS", CCA_KEYWORD_SIZE); rule_array_count = 1; verb_data_length = sizeof(cca_private->num_domains); dll_CSUACFQ(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &verb_data_length, (unsigned char *)&cca_private->num_domains); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSUACFQ (DOM-NUMS) failed. return:%ld, reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } cca_private->num_domains = be32toh(cca_private->num_domains); TRACE_DEVEL("num_domains: %u\n", cca_private->num_domains); /* Get usage domain mask */ memcpy(rule_array, "DOM-USAG", CCA_KEYWORD_SIZE); rule_array_count = 1; verb_data_length = sizeof(cca_private->usage_domains); dll_CSUACFQ(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &verb_data_length, (unsigned char *)cca_private->usage_domains); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSUACFQ (DOM-USAG) failed. return:%ld, reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } for (i = 0; i < cca_private->num_domains && (i + 1) * (unsigned int)sizeof(unsigned short) <= verb_data_length; i++) { cca_private->usage_domains[i] = be32toh(cca_private->usage_domains[i]); TRACE_DEVEL("usage_domains[%u] = %u\n", i, cca_private->usage_domains[i]); } cca_private->num_usagedoms = i; TRACE_DEVEL("num_usagedoms: %u\n", cca_private->num_usagedoms); #endif return CKR_OK; } static CK_RV cca_check_mks(STDLL_TokData_t *tokdata) { struct cca_private_data *cca_private = tokdata->private_data; unsigned char *new_mkvp; CK_RV rc; rc = cca_iterate_adapters(tokdata, cca_get_and_check_mkvps, NULL); if (rc != CKR_OK) return rc; TRACE_DEBUG("Expected master key verification patterns (queried):\n"); if (cca_private->expected_sym_mkvp_set == FALSE) { /* * If a MK change operation is active, and all APQNs have the new SYM MK * already, use the new SYM MKVP as the queried one. */ new_mkvp = cca_mk_change_find_mkvp_in_ops(tokdata, CCA_MK_SYM, NULL); if (new_mkvp && memcmp(cca_private->expected_sym_mkvp, cca_zero_mkvp, CCA_MKVP_LENGTH) == 0) { TRACE_DEBUG("%s All APQNs already have the new SYM MK\n",__func__); memcpy(cca_private->expected_sym_mkvp, new_mkvp, CCA_MKVP_LENGTH); } TRACE_DEBUG_DUMP("SYM MKVP: ", cca_private->expected_sym_mkvp, CCA_MKVP_LENGTH); } else { TRACE_DEBUG("SYM MKVP: specified in config\n"); } if (cca_private->expected_aes_mkvp_set == FALSE) { /* * If a MK change operation is active, and all APQNs have the new AES MK * already, use the new AES MKVP as the queried one. */ new_mkvp = cca_mk_change_find_mkvp_in_ops(tokdata, CCA_MK_AES, NULL); if (new_mkvp && memcmp(cca_private->expected_aes_mkvp, cca_zero_mkvp, CCA_MKVP_LENGTH) == 0) { TRACE_DEBUG("%s All APQNs already have the new AES MK\n",__func__); memcpy(cca_private->expected_aes_mkvp, new_mkvp, CCA_MKVP_LENGTH); } TRACE_DEBUG_DUMP("AES MKVP: ", cca_private->expected_aes_mkvp, CCA_MKVP_LENGTH); } else { TRACE_DEBUG("AES MKVP: specified in config\n"); } if (cca_private->expected_apka_mkvp_set == FALSE) { /* * If a MK change operation is active, and all APQNs have the new APKA * MK already, use the new APKA MKVP as the queried one. */ new_mkvp = cca_mk_change_find_mkvp_in_ops(tokdata, CCA_MK_APKA, NULL); if (new_mkvp && memcmp(cca_private->expected_apka_mkvp, cca_zero_mkvp, CCA_MKVP_LENGTH) == 0) { TRACE_DEBUG("%s All APQNs already have the new APKA MK\n",__func__); memcpy(cca_private->expected_apka_mkvp, new_mkvp, CCA_MKVP_LENGTH); } TRACE_DEBUG_DUMP("APKA MKVP: ", cca_private->expected_apka_mkvp, CCA_MKVP_LENGTH); } else { TRACE_DEBUG("APKA MKVP: specified in config\n"); } return CKR_OK; } static CK_RV cca_parse_hex(const char *str, unsigned char *bin, size_t size) { unsigned int i, val; if (strncasecmp(str, "0x", 2) == 0) str += 2; if (strlen(str) != size * 2) return CKR_FUNCTION_FAILED; for (i = 0; i < size; i++) { if (sscanf(str + (i * 2), "%02x", &val) != 1) return CKR_FUNCTION_FAILED; bin[i] = val; } return CKR_OK; } static CK_RV cca_config_set_pkey_mode(struct cca_private_data *cca_data, const char *fname, const char *strval) { if (strcmp(strval, "DISABLED") == 0) cca_data->pkey_mode = PKEY_MODE_DISABLED; #ifndef NO_PKEY else if (strcmp(strval, "DEFAULT") == 0) cca_data->pkey_mode = PKEY_MODE_DEFAULT; else if (strcmp(strval, "ENABLED") == 0) cca_data->pkey_mode = PKEY_MODE_ENABLED; #endif else { TRACE_ERROR("%s unsupported PKEY mode : '%s'\n", __func__, strval); OCK_SYSLOG(LOG_ERR,"%s: Error: unsupported PKEY mode '%s' " "in config file '%s'\n", __func__, strval, fname); return CKR_FUNCTION_FAILED; } return CKR_OK; } static CK_RV cca_config_set_aes_key_mode(struct cca_private_data *cca_data, const char *fname, const char *strval) { if (strcmp(strval, "DATA") == 0) cca_data->aes_key_mode = AES_KEY_MODE_DATA; else if (strcmp(strval, "CIPHER") == 0) cca_data->aes_key_mode = AES_KEY_MODE_CIPHER; else { TRACE_ERROR("%s unsupported AES key mode : '%s'\n", __func__, strval); OCK_SYSLOG(LOG_ERR,"%s: Error: unsupported AES key mode '%s' " "in config file '%s'\n", __func__, strval, fname); return CKR_FUNCTION_FAILED; } return CKR_OK; } static CK_RV cca_config_set_ml_dsa_key_mode(struct cca_private_data *cca_data, const char *fname, const char *strval) { if (strcmp(strval, "PURE") == 0) cca_data->ml_dsa_key_mode = ML_DSA_KEY_MODE_PURE; else if (strcmp(strval, "PREHASH") == 0) cca_data->ml_dsa_key_mode = ML_DSA_KEY_MODE_PREHASH; else { TRACE_ERROR("%s unsupported ML-DSA key mode : '%s'\n", __func__, strval); OCK_SYSLOG(LOG_ERR,"%s: Error: unsupported ML-DSA key mode '%s' " "in config file '%s'\n", __func__, strval, fname); return CKR_FUNCTION_FAILED; } return CKR_OK; } CK_RV cca_config_parse_exp_mkvps(char *fname, struct ConfigStructNode *exp_mkvp_node, unsigned char *expected_sym_mkvp, CK_BBOOL *expected_sym_mkvp_set, unsigned char *expected_aes_mkvp, CK_BBOOL *expected_aes_mkvp_set, unsigned char *expected_apka_mkvp, CK_BBOOL *expected_apka_mkvp_set) { struct ConfigBaseNode *c; char *str; CK_RV rc = CKR_OK; int i; confignode_foreach(c, exp_mkvp_node->value, i) { TRACE_DEBUG("Config node: '%s' type: %u line: %u\n", c->key, c->type, c->line); if (strcasecmp(c->key, CCA_CFG_SYM_MKVP) == 0 && (str = confignode_getstr(c)) != NULL) { rc = cca_parse_hex(str, expected_sym_mkvp, CCA_MKVP_LENGTH); if (rc != CKR_OK) { OCK_SYSLOG(LOG_ERR, "Error parsing config file '%s': invalid " "hex value '%s' at line %d\n", fname, confignode_getstr(c), c->line); TRACE_ERROR("Error parsing config file '%s': invalid hex value " "'%s' at line %d\n", fname, confignode_getstr(c), c->line); break; } *expected_sym_mkvp_set = TRUE; continue; } if (strcasecmp(c->key, CCA_CFG_AES_MKVP) == 0 && (str = confignode_getstr(c)) != NULL) { rc = cca_parse_hex(str, expected_aes_mkvp, CCA_MKVP_LENGTH); if (rc != CKR_OK) { OCK_SYSLOG(LOG_ERR, "Error parsing config file '%s': invalid " "hex value '%s' at line %d\n", fname, confignode_getstr(c), c->line); TRACE_ERROR("Error parsing config file '%s': invalid hex value " "'%s' at line %d\n", fname, confignode_getstr(c), c->line); break; } *expected_aes_mkvp_set = TRUE; continue; } if (strcasecmp(c->key, CCA_CFG_APKA_MKVP) == 0 && (str = confignode_getstr(c)) != NULL) { rc = cca_parse_hex(str, expected_apka_mkvp, CCA_MKVP_LENGTH); if (rc != CKR_OK) { OCK_SYSLOG(LOG_ERR, "Error parsing config file '%s': invalid " "hex value '%s' at line %d\n", fname, confignode_getstr(c), c->line); TRACE_ERROR("Error parsing config file '%s': invalid hex value " "'%s' at line %d\n", fname, confignode_getstr(c), c->line); break; } *expected_apka_mkvp_set = TRUE; continue; } OCK_SYSLOG(LOG_ERR, "Error parsing config file '%s': unexpected token " "'%s' at line %d\n", fname, c->key, c->line); TRACE_ERROR("Error parsing config file '%s': unexpected token '%s' " "at line %d\n", fname, c->key, c->line); return CKR_FUNCTION_FAILED; } TRACE_DEBUG("Expected master key verification patterns\n"); if (*expected_sym_mkvp_set == TRUE) { TRACE_DEBUG_DUMP("SYM MKVP: ", expected_sym_mkvp, CCA_MKVP_LENGTH); } else { TRACE_DEBUG("SYM MKVP: not specified\n"); } if (*expected_aes_mkvp_set == TRUE) { TRACE_DEBUG_DUMP("AES MKVP: ", expected_aes_mkvp, CCA_MKVP_LENGTH); } else { TRACE_DEBUG("AES MKVP: not specified\n"); } if (*expected_apka_mkvp_set == TRUE) { TRACE_DEBUG_DUMP("APKA MKVP: ", expected_apka_mkvp, CCA_MKVP_LENGTH); } else { TRACE_DEBUG("APKA MKVP: not specified\n"); } return rc; } void cca_config_parse_error(int line, int col, const char *msg) { OCK_SYSLOG(LOG_ERR, "Error parsing config file: line %d column %d: %s\n", line, col, msg); TRACE_ERROR("Error parsing config file: line %d column %d: %s\n", line, col, msg); } CK_RV cca_load_config_file(STDLL_TokData_t *tokdata, char *conf_name) { struct cca_private_data *cca_private = tokdata->private_data; char fname[PATH_MAX]; FILE *file; struct ConfigBaseNode *c, *config = NULL; struct ConfigStructNode *struct_node; CK_RV rc = CKR_OK; int ret, i; const char *strval; if (conf_name == NULL || strlen(conf_name) == 0) return CKR_OK; if (conf_name[0] == '/') { /* Absolute path name */ strncpy(fname, conf_name, sizeof(fname) - 1); fname[sizeof(fname) - 1] = '\0'; } else { /* relative path name */ snprintf(fname, sizeof(fname), "%s/%s", OCK_CONFDIR, conf_name); fname[sizeof(fname) - 1] = '\0'; } file = fopen(fname, "r"); if (file == NULL) { TRACE_ERROR("%s fopen('%s') failed with errno: %s\n", __func__, fname, strerror(errno)); return CKR_FUNCTION_FAILED; } ret = parse_configlib_file(file, &config, cca_config_parse_error, 0); if (ret != 0) { TRACE_ERROR("Error parsing config file '%s'\n", fname); rc = CKR_FUNCTION_FAILED; goto done; } strncpy(cca_private->token_config_filename, fname, sizeof(cca_private->token_config_filename)); cca_private->token_config_filename[ sizeof(cca_private->token_config_filename) - 1] = '\0'; confignode_foreach(c, config, i) { TRACE_DEBUG("Config node: '%s' type: %u line: %u\n", c->key, c->type, c->line); if (confignode_hastype(c, CT_FILEVERSION)) { TRACE_DEBUG("Config file version: '%s'\n", confignode_to_fileversion(c)->base.key); continue; } if (confignode_hastype(c, CT_BARECONST)) { /* single keyword tokens */ if (strcasecmp(c->key, "FORCE_SENSITIVE") == 0) { cca_private->cka_sensitive_default_true = TRUE; continue; } } if (confignode_hastype(c, CT_BAREVAL)) { /* New style (key = value) tokens */ strval = confignode_getstr(c); if (strcasecmp(c->key, "PKEY_MODE") == 0) { rc = cca_config_set_pkey_mode(cca_private, fname, strval); if (rc != CKR_OK) break; continue; } if (strcasecmp(c->key, "AES_KEY_MODE") == 0) { rc = cca_config_set_aes_key_mode(cca_private, fname, strval); if (rc != CKR_OK) break; continue; } if (strcasecmp(c->key, "ML_DSA_KEY_MODE") == 0) { rc = cca_config_set_ml_dsa_key_mode(cca_private, fname, strval); if (rc != CKR_OK) break; continue; } } if (confignode_hastype(c, CT_STRUCT)) { struct_node = confignode_to_struct(c); if (strcasecmp(struct_node->base.key, CCA_CFG_EXPECTED_MKVPS) == 0) { rc = cca_config_parse_exp_mkvps(fname, struct_node, cca_private->expected_sym_mkvp, &cca_private->expected_sym_mkvp_set, cca_private->expected_aes_mkvp, &cca_private->expected_aes_mkvp_set, cca_private->expected_apka_mkvp, &cca_private->expected_apka_mkvp_set); if (rc != CKR_OK) break; continue; } OCK_SYSLOG(LOG_ERR, "Error parsing config file '%s': unexpected " "token '%s' at line %d\n", fname, c->key, c->line); TRACE_ERROR("Error parsing config file '%s': unexpected token '%s' " "at line %d\n", fname, c->key, c->line); rc = CKR_FUNCTION_FAILED; break; } OCK_SYSLOG(LOG_ERR, "Error parsing config file '%s': unexpected token " "'%s' at line %d\n", fname, c->key, c->line); TRACE_ERROR("Error parsing config file '%s': unexpected token '%s' " "at line %d\n", fname, c->key, c->line); rc = CKR_FUNCTION_FAILED; break; } done: confignode_deepfree(config); fclose(file); return rc; } #ifndef NO_PKEY static CK_RV ccatok_pkey_add_attr_to_rule_array(CK_ATTRIBUTE_TYPE type, CK_BYTE *rule_array, CK_ULONG rule_array_size, CK_ULONG *rule_array_count) { if ((*rule_array_count + 1) * CCA_KEYWORD_SIZE > rule_array_size) return CKR_BUFFER_TOO_SMALL; switch (type) { case CKA_IBM_PROTKEY_EXTRACTABLE: memcpy(rule_array + (*rule_array_count * CCA_KEYWORD_SIZE), "XPRTCPAC", CCA_KEYWORD_SIZE); (*rule_array_count)++; break; default: break; } return CKR_OK; } /* * This routine checks if a given attr is applicable to pass it to the CCA * host lib via its corresponding rule_array keyword. */ static CK_BBOOL ccatok_pkey_attr_applicable(STDLL_TokData_t *tokdata, CK_ATTRIBUTE *attr, CK_KEY_TYPE ktype, int curve_type, int curve_bitlen, CK_IBM_CCA_AES_KEY_MODE_TYPE aes_key_mode) { struct cca_private_data *cca_data = tokdata->private_data; /* * On older cards, CKA_IBM_PROTKEY_EXTRACTABLE might cause errors, so * filter it out when the PKEY option is not supported on this system. */ if (attr->type == CKA_IBM_PROTKEY_EXTRACTABLE && cca_data->pkey_wrap_supported == 0) return CK_FALSE; switch (ktype) { case CKK_AES: case CKK_AES_XTS: /* * CCA AES DATA keys don't support any pkey attributes to be set, but * AES CIPHER keys do support the XPRTCPAC keyword to allow export to * CPACF protected key format. */ if (aes_key_mode != CK_IBM_CCA_AES_CIPHER_KEY) return CK_FALSE; switch (attr->type) { case CKA_IBM_PROTKEY_EXTRACTABLE: return *(CK_BBOOL *)attr->pValue; } break; case CKK_EC: case CKK_EC_EDWARDS: /* * There is currently only one attribute with a corresponding rule * array keyword. */ switch (attr->type) { case CKA_IBM_PROTKEY_EXTRACTABLE: if ((*(CK_BBOOL *)attr->pValue) == CK_TRUE) { /* * From CCA 7.3 Application Programmer's Guide, table 282: * Allow export to CPACF protected key format. Valid for ECC * curves P256, P384, P521, Ed25519, and Ed448. */ switch (curve_type) { case PRIME_CURVE: if (curve_bitlen == 256 || curve_bitlen == 384 || curve_bitlen == 521) return CK_TRUE; break; case EDWARDS_CURVE: if (curve_bitlen == 255 || curve_bitlen == 448) return CK_TRUE; break; default: break; } } } break; default: /* * Any other key types (RSA, ...) are currently not handled. No * additional rule array keywords here. */ break; } return CK_FALSE; } /* * Add protected key related attributes to be passed to CCA via the rule_array. */ static CK_RV ccatok_pkey_add_attrs(STDLL_TokData_t * tokdata, TEMPLATE *template, CK_KEY_TYPE ktype, int curve_type, int curve_bitlen, CK_IBM_CCA_AES_KEY_MODE_TYPE aes_key_mode, CK_BYTE *rule_array, CK_ULONG rule_array_size, CK_ULONG *rule_array_count) { DL_NODE *node; CK_ATTRIBUTE_PTR attr; CK_RV ret; node = template->attribute_list; while (node != NULL) { attr = node->data; if (ccatok_pkey_attr_applicable(tokdata, attr, ktype, curve_type, curve_bitlen, aes_key_mode)) { ret = ccatok_pkey_add_attr_to_rule_array(attr->type, rule_array, rule_array_size, rule_array_count); if (ret != CKR_OK) return ret; } node = node->next; } return CKR_OK; } #define MAXECPROTKEYSIZE 112 /* max 80 + 32 bytes for p521 */ #define PKEYDEVICE "/dev/pkey" typedef struct { STDLL_TokData_t *tokdata; CK_BBOOL wrap_was_successful; CK_RV wrap_error; CK_VOID_PTR secure_key; CK_ULONG secure_key_len; CK_BYTE *pkey_buf; size_t *pkey_buflen_p; enum cca_token_type keytype; /* for AES XTS processing */ CK_VOID_PTR secure_key2; CK_ULONG secure_key_len2; CK_BYTE *pkey_buf2; size_t *pkey_buflen_p2; CK_BBOOL aes_xts; } pkey_wrap_handler_data_t; /* * On older kernels, the PKEY_KBLOB2PROTK3 ioctl is not yet available, which is * no problem at runtime: protected key support is then just not available. * But we want that the CCA token still builds on such systems, so let's copy * the missing #defines and structs from kernel asm/pkey.h */ #ifndef PKEY_KBLOB2PROTK3 struct pkey_kblob2pkey3 { __u8 *key; /* in: pointer to key blob */ __u32 keylen; /* in: key blob size */ struct pkey_apqn *apqns; /* in: ptr to list of apqn targets */ __u32 apqn_entries; /* in: # of apqn target list entries */ __u32 pkeytype; /* out: prot key type (enum pkey_key_type) */ __u32 pkeylen; /* in/out: size of pkey buffer/actual len of pkey */ __u8 *pkey; /* in: pkey blob buffer space ptr */ }; #define PKEY_KBLOB2PROTK3 _IOWR(PKEY_IOCTL_MAGIC, 0x1D, struct pkey_kblob2pkey3) #define PKEY_TYPE_CCA_ECC (__u32)0x1f #endif /* PKEY_KBLOB2PROTK3 */ static enum pkey_key_type ccatok_pkey_type_from_keytype(enum cca_token_type keytype) { switch (keytype) { case sec_aes_data_key: return PKEY_TYPE_CCA_DATA; case sec_aes_cipher_key: return PKEY_TYPE_CCA_CIPHER; case sec_ecc_priv_key: return PKEY_TYPE_CCA_ECC; default: break; } return 0; } /* * Callback function used by ccatok_pkey_skey2pkey() for creating a protected * key using (card,domain) via the PKEY_KBLOB2PROTK3 ioctl. * Note that the PKEY_KBLOB2PROTK3 ioctl requires kernel 5.10 or later. * On older kernels this function fails when called at token init, trying to * determine the wkvp from the firmware wrapping key. In this case, protected * key support for CCA is just not available (indicated in cca_private_data). */ static CK_RV ccatok_pkey_sec2prot(STDLL_TokData_t *tokdata, const char *adapter, unsigned short card, unsigned short domain, void *handler_data) { pkey_wrap_handler_data_t *data = (pkey_wrap_handler_data_t *) handler_data; struct cca_private_data *cca_data = data->tokdata->private_data; struct pkey_kblob2pkey3 io; struct pkey_apqn apqn; int rc, i; UNUSED(tokdata); UNUSED(adapter); if (data->wrap_was_successful) goto done; apqn.card = card; apqn.domain = domain; memset(&io, 0, sizeof(io)); io.key = data->secure_key; io.keylen = data->secure_key_len; io.apqns = &apqn; io.apqn_entries = 1; io.pkeytype = ccatok_pkey_type_from_keytype(data->keytype); io.pkeylen = *(data->pkey_buflen_p); io.pkey = data->pkey_buf; for (i = 0; i < 10; i++) { rc = ioctl(cca_data->pkeyfd, PKEY_KBLOB2PROTK3, &io); if (rc == 0 || (errno != -EBUSY && errno != -EAGAIN)) break; sleep(1); } if (rc != 0) { data->wrap_error = CKR_FUNCTION_FAILED; data->wrap_was_successful = CK_FALSE; goto done; } *(data->pkey_buflen_p) = io.pkeylen; if (data->aes_xts) { memset(&io, 0, sizeof(io)); io.key = data->secure_key2; io.keylen = data->secure_key_len2; io.apqns = &apqn; io.apqn_entries = 1; io.pkeytype = ccatok_pkey_type_from_keytype(data->keytype); io.pkeylen = *(data->pkey_buflen_p2); io.pkey = data->pkey_buf2; for (i = 0; i < 10; i++) { rc = ioctl(cca_data->pkeyfd, PKEY_KBLOB2PROTK3, &io); if (rc == 0 || (errno != -EBUSY && errno != -EAGAIN)) break; sleep(1); } if (rc != 0) { data->wrap_error = CKR_FUNCTION_FAILED; data->wrap_was_successful = CK_FALSE; goto done; } *(data->pkey_buflen_p2) = io.pkeylen; } data->wrap_error = CKR_OK; data->wrap_was_successful = CK_TRUE; done: /* * Always return ok, calling function loops over this handler until * data->wrap_was_successful = true, or no more APQN left. * Pass back error in handler data anyway. */ return CKR_OK; } /* * Creates a protected key from the given secure key object by iterating * over all APQNs. */ static CK_RV ccatok_pkey_skey2pkey(STDLL_TokData_t *tokdata, CK_ATTRIBUTE *skey_attr, CK_ATTRIBUTE **pkey_attr, CK_BBOOL aes_xts) { CK_ATTRIBUTE *tmp_attr = NULL; CK_BYTE pkey_buf[MAXECPROTKEYSIZE], pkey_buf2[MAXECPROTKEYSIZE], pkey_buffer[MAXECPROTKEYSIZE * 2]; CK_ULONG pkey_buflen = sizeof(pkey_buf); CK_ULONG pkey_buflen2 = sizeof(pkey_buf2); pkey_wrap_handler_data_t pkey_wrap_handler_data; CK_RV ret; enum cca_token_type key_type; unsigned int token_keybitsize; const CK_BYTE *mkvp; CK_BBOOL new_mk; unsigned int num_retries = 0; /* Determine CCA key type */ if (analyse_cca_key_token(skey_attr->pValue, (aes_xts ? skey_attr->ulValueLen / 2 : skey_attr->ulValueLen), &key_type, &token_keybitsize, &mkvp) != TRUE) { TRACE_ERROR("Invalid/unknown cca token, cannot get key type\n"); ret = CKR_FUNCTION_FAILED; goto done; } if (check_expected_mkvp(tokdata, key_type, mkvp, &new_mk) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); ret = CKR_DEVICE_ERROR; goto done; } /* Create the protected key by iterating over all APQNs */ memset(&pkey_wrap_handler_data, 0, sizeof(pkey_wrap_handler_data_t)); pkey_wrap_handler_data.tokdata = tokdata; pkey_wrap_handler_data.secure_key = skey_attr->pValue; pkey_wrap_handler_data.secure_key_len = (aes_xts ? skey_attr->ulValueLen / 2 : skey_attr->ulValueLen); pkey_wrap_handler_data.pkey_buf = (CK_BYTE *)&pkey_buf; pkey_wrap_handler_data.pkey_buflen_p = &pkey_buflen; pkey_wrap_handler_data.aes_xts = aes_xts; if (aes_xts) { if (analyse_cca_key_token((CK_BYTE *)skey_attr->pValue + skey_attr->ulValueLen / 2, skey_attr->ulValueLen / 2, &key_type, &token_keybitsize, &mkvp) != TRUE) { TRACE_ERROR("Invalid/unknown cca token, cannot get key type\n"); ret = CKR_FUNCTION_FAILED; goto done; } if (check_expected_mkvp(tokdata, key_type, mkvp, &new_mk) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); ret = CKR_DEVICE_ERROR; goto done; } pkey_wrap_handler_data.secure_key2 = (CK_BYTE *)skey_attr->pValue + skey_attr->ulValueLen / 2; pkey_wrap_handler_data.secure_key_len2 = skey_attr->ulValueLen / 2; pkey_wrap_handler_data.pkey_buf2 = (CK_BYTE *)&pkey_buf2; pkey_wrap_handler_data.pkey_buflen_p2 = &pkey_buflen2; pkey_wrap_handler_data.keytype = key_type; } while (num_retries < 3600) { ret = cca_iterate_adapters(tokdata, ccatok_pkey_sec2prot, &pkey_wrap_handler_data); if (ret == CKR_OK && pkey_wrap_handler_data.wrap_was_successful) break; /* Retry the op if key encrypted with new MK and an MK change is active */ if (new_mk == CK_TRUE && cca_mk_change_find_op_by_keytype(tokdata, key_type) != NULL) { sleep(1); num_retries++; continue; } break; } if (ret != CKR_OK || !pkey_wrap_handler_data.wrap_was_successful) { TRACE_ERROR("cca_iterate_adapters failed or no APQN could create the pkey.\n"); ret = CKR_FUNCTION_FAILED; goto done; } /* Build new attribute for protected key */ if (aes_xts) { memcpy(pkey_buffer, pkey_buf, pkey_buflen); memcpy(pkey_buffer + pkey_buflen, pkey_buf2, pkey_buflen2); ret = build_attribute(CKA_IBM_OPAQUE_PKEY, pkey_buffer, pkey_buflen + pkey_buflen2, &tmp_attr); if (ret != CKR_OK) { TRACE_ERROR("build_attribute failed with rc=0x%lx\n", ret); ret = CKR_FUNCTION_FAILED;; goto done; } } else { ret = build_attribute(CKA_IBM_OPAQUE_PKEY, pkey_buf, pkey_buflen, &tmp_attr); if (ret != CKR_OK) { TRACE_ERROR("build_attribute failed with rc=0x%lx\n", ret); ret = CKR_FUNCTION_FAILED;; goto done; } } ret = CKR_OK; done: *pkey_attr = tmp_attr; return ret; } /* * Save the current firmware wrapping key verification pattern in the tokdata: * create a dummy test key, transform it into a protected key, and store the wk * verification pattern in the tokdata. */ static CK_RV ccatok_pkey_get_firmware_wkvp(STDLL_TokData_t *tokdata) { struct cca_private_data *cca_data = tokdata->private_data; CK_ATTRIBUTE *pkey_attr = NULL, *sec_attr = NULL; CK_RV ret; long return_code = 0, reason_code = 0; long exit_data_len = 0, clear_key_bit_length = 0; unsigned char exit_data[4]; unsigned char rule_array[CCA_RULE_ARRAY_SIZE]; long rule_array_count; unsigned char *clear_key_value = NULL; long key_name_length = 0; unsigned char key_name[CCA_KEY_ID_SIZE] = { 0, }; long user_data_length = 0; unsigned char user_data[64] = { 0, }; long token_data_length = 0; long verb_data_length = 0; unsigned char verb_data[64] = { 0, }; unsigned char the_key_token[CCA_KEY_TOKEN_SIZE] = { 0, }; long the_key_token_length = sizeof(the_key_token); unsigned char key_type_1[8] = { ' ', }; unsigned char key_type_2[8] = { ' ', }; long key_name_1_length = 0; long key_name_2_length = 0; long user_data_1_length = 0; long user_data_2_length = 0; long kek_identifier_1_length = 0; long kek_identifier_2_length = 0; long the_2nd_key_token_length = 0; unsigned int min_card_version; /* Check CCA host library version: XPRTCPAC requires min 7.0.0 */ if (cca_data->cca_lib_version.ver < 7) { TRACE_WARNING("CCA host lib is %d.%d.%d, but pkey support requires min 7.0.0\n", cca_data->cca_lib_version.ver,cca_data->cca_lib_version.rel, cca_data->cca_lib_version.mod); OCK_SYSLOG(LOG_WARNING, "CCA host lib is %d.%d.%d, but pkey support requires min 7.0.0\n", cca_data->cca_lib_version.ver,cca_data->cca_lib_version.rel, cca_data->cca_lib_version.mod); return CKR_FUNCTION_NOT_SUPPORTED; } /* Read min card version from CCA private data. Needs a read lock. */ if (pthread_rwlock_rdlock(&cca_data->min_card_version_rwlock) != 0) { TRACE_ERROR("CCA min_card_version RD-Lock failed.\n"); return CKR_CANT_LOCK; } min_card_version = cca_data->min_card_version.ver; if (pthread_rwlock_unlock(&cca_data->min_card_version_rwlock) != 0) { TRACE_ERROR("CCA min_card_version RD-Unlock failed.\n"); return CKR_CANT_LOCK; } /* Check minimum card version, XPRTCPAC requires min CEX7C */ if (min_card_version < 7) { TRACE_WARNING("Minimum card version must be CEX7C, but we only have %d.%d.%d\n", cca_data->min_card_version.ver,cca_data->min_card_version.rel, cca_data->min_card_version.mod); OCK_SYSLOG(LOG_WARNING, "Minimum card version must be CEX7C, but we only have %d.%d.%d\n", cca_data->min_card_version.ver,cca_data->min_card_version.rel, cca_data->min_card_version.mod); return CKR_FUNCTION_NOT_SUPPORTED; } /* Build CPACF-exportable AES internal cipher key token */ rule_array_count = 5; memcpy(rule_array, "INTERNAL" "NO-KEY " "AES " "CIPHER " "XPRTCPAC", rule_array_count * CCA_KEYWORD_SIZE); dll_CSNBKTB2(&return_code, &reason_code, &exit_data_len, exit_data, &rule_array_count, rule_array, &clear_key_bit_length, clear_key_value, &key_name_length, key_name, &user_data_length, user_data, &token_data_length, NULL, &verb_data_length, verb_data, &the_key_token_length, the_key_token); if (return_code != 0) { TRACE_ERROR("CSNBTKB2 (TOKEN BUILD2) failed with %ld/%ld\n", return_code, reason_code); ret = CKR_FUNCTION_FAILED; goto done; } /* Generate the key */ memset(rule_array, 0, sizeof(rule_array)); memcpy(rule_array, "AES " "OP ", 2 * CCA_KEYWORD_SIZE); rule_array_count = 2; clear_key_bit_length = 256; memcpy(key_type_1, "TOKEN ", CCA_KEYWORD_SIZE); the_key_token_length = sizeof(the_key_token); dll_CSNBKGN2(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &clear_key_bit_length, key_type_1, key_type_2, &key_name_1_length, NULL, &key_name_2_length, NULL, &user_data_1_length, NULL, &user_data_2_length, NULL, &kek_identifier_1_length, NULL, &kek_identifier_2_length, NULL, &the_key_token_length, the_key_token, &the_2nd_key_token_length, NULL); if (return_code != 0) { TRACE_ERROR("CSNBKGN2(KEYGEN2) failed with %ld/%ld\n", return_code, reason_code); ret = CKR_FUNCTION_FAILED; goto done; } /* Build attribute for secure key token */ ret = build_attribute(CKA_IBM_OPAQUE, (CK_BYTE *)&the_key_token, the_key_token_length, &sec_attr); if (ret != CKR_OK) { TRACE_ERROR("build_attribute CKA_IBM_OPAQUE failed with ret=0x%lx\n", ret); goto done; } /* * Create a protected key from this token to obtain the firmware wkvp. When * this function returns ok, we have a 64 byte pkey value: 32 bytes * encrypted key + 32 bytes vp. */ ret = ccatok_pkey_skey2pkey(tokdata, sec_attr, &pkey_attr, FALSE); if (ret != CKR_OK) { TRACE_ERROR("ccatok_pkey_skey2pkey failed with ret=0x%lx\n", ret); goto done; } /* Save WKVP in token data */ if (pthread_rwlock_wrlock(&cca_data->pkey_rwlock)) { TRACE_ERROR("%s Failed to lock pkey lock\n", __func__); ret = CKR_CANT_LOCK; goto done; } memcpy(&cca_data->pkey_mk_vp, (CK_BYTE *)pkey_attr->pValue + AES_KEY_SIZE_256, PKEY_MK_VP_LENGTH); __sync_or_and_fetch(&cca_data->pkey_wrap_supported, 1); if (pthread_rwlock_unlock(&cca_data->pkey_rwlock)) { TRACE_ERROR("%s Failed to unlock pkey lock\n", __func__); } done: if (sec_attr) free(sec_attr); if (pkey_attr) free(pkey_attr); return ret; } /* * Return true if PKEY_MODE DISABLED is set in the token specific * config file, false otherwise. */ static CK_BBOOL ccatok_pkey_option_disabled(STDLL_TokData_t *tokdata) { struct cca_private_data *cca_data = tokdata->private_data; if (cca_data->pkey_mode == PKEY_MODE_DISABLED) return CK_TRUE; return CK_FALSE; } /** * Return true, if the given key obj has a valid protected key, i.e. its * verification pattern matches the one of the current master key. */ static CK_BBOOL ccatok_pkey_is_valid(STDLL_TokData_t *tokdata, OBJECT *key_obj) { struct cca_private_data *cca_data = tokdata->private_data; CK_ATTRIBUTE *pkey_attr = NULL; int vp_offset; CK_BBOOL ret = CK_FALSE; if (template_attribute_get_non_empty(key_obj->template, CKA_IBM_OPAQUE_PKEY, &pkey_attr) == CKR_OK) { if (pkey_attr->ulValueLen >= AES_KEY_SIZE_128 + PKEY_MK_VP_LENGTH) { vp_offset = pkey_attr->ulValueLen - PKEY_MK_VP_LENGTH; if (pthread_rwlock_rdlock(&cca_data->pkey_rwlock)) { TRACE_ERROR("%s Failed to lock pkey lock\n", __func__); goto done; } if (memcmp((CK_BYTE *)pkey_attr->pValue + vp_offset, &cca_data->pkey_mk_vp, PKEY_MK_VP_LENGTH) == 0) { ret = CK_TRUE; } if (pthread_rwlock_unlock(&cca_data->pkey_rwlock)) { TRACE_ERROR("%s Failed to unlock pkey lock\n", __func__); } } } done: return ret; } /** * Create a new protected key for the given key obj and update attribute * CKA_IBM_OPAQUE with the new pkey. */ static CK_RV ccatok_pkey_update(STDLL_TokData_t *tokdata, OBJECT *key_obj, CK_BBOOL aes_xts) { struct cca_private_data *cca_data = tokdata->private_data; CK_ATTRIBUTE *skey_attr = NULL; CK_ATTRIBUTE *pkey_attr = NULL; CK_RV ret; int vp_offset; int num_retries = 0; /* Get secure key from obj */ if (template_attribute_get_non_empty(key_obj->template, CKA_IBM_OPAQUE, &skey_attr) != CKR_OK) { TRACE_ERROR("This key has no blob: should not occur!\n"); ret = CKR_FUNCTION_FAILED; goto done; } retry: /* Transform the secure key into a protected key */ ret = ccatok_pkey_skey2pkey(tokdata, skey_attr, &pkey_attr, aes_xts); if (ret != CKR_OK) { TRACE_ERROR("protected key creation failed with rc=0x%lx\n",ret); goto done; } if (pthread_rwlock_rdlock(&cca_data->pkey_rwlock)) { TRACE_ERROR("%s Failed to lock pkey lock\n", __func__); ret = CKR_CANT_LOCK; goto done; } /* * Check if the new pkey's verification pattern matches the one in * cca_data. This should always be the case, except there was a live * guest relocation (LGR) in the middle of the process. */ vp_offset = pkey_attr->ulValueLen - PKEY_MK_VP_LENGTH; if (memcmp(&cca_data->pkey_mk_vp, (CK_BYTE *)pkey_attr->pValue + vp_offset, PKEY_MK_VP_LENGTH) != 0) { TRACE_ERROR("vp of this pkey does not match with the one in cca_data\n"); ret = CKR_FUNCTION_FAILED; } if (aes_xts) { /* * Check if the new pkey's verification pattern matches the one in * cca_data. This should always be the case, except there was a live * guest relocation (LGR) in the middle of the process. * AES XTS has two keys, two keys are concatenated. * Second key is checked above and the first key is checked here */ vp_offset = pkey_attr->ulValueLen / 2 - PKEY_MK_VP_LENGTH; if (memcmp(&cca_data->pkey_mk_vp, (CK_BYTE *)pkey_attr->pValue + vp_offset, PKEY_MK_VP_LENGTH) != 0) { TRACE_ERROR("vp of this pkey does not match with the one in cca_data\n"); ret = CKR_FUNCTION_FAILED; } } if (pthread_rwlock_unlock(&cca_data->pkey_rwlock)) { TRACE_ERROR("%s Failed to unlock pkey lock\n", __func__); } if (ret != CKR_OK) { /* * Verification pattern does not match. Create it again and retry. * If there was an LGR, this op now takes place on the new system * and should succeed. */ ret = ccatok_pkey_get_firmware_wkvp(tokdata); if (ret != CKR_OK) goto done; num_retries++; if (num_retries < PKEY_CONVERT_KEY_RETRIES) { if (pkey_attr != NULL) free(pkey_attr); TRACE_DEVEL("%s VP mismatch probably due to LGR, retry %d of %d ...\n", __func__, num_retries, PKEY_CONVERT_KEY_RETRIES); goto retry; } } if (ret != CKR_OK) goto done; /* * Now update the key obj. If it's a token obj, it will be also updated * in the repository. */ ret = pkey_update_and_save(tokdata, key_obj, &pkey_attr); if (ret != CKR_OK) { TRACE_ERROR("pkey_update_and_save failed with rc=0x%lx\n", ret); goto done; } ret = CKR_OK; done: if (pkey_attr != NULL) free(pkey_attr); return ret; } /** * Returns true if the session is ok for creating protected keys, false * otherwise. The session must be read/write for token objects, and not public * nor SO for private objects. */ static CK_BBOOL ccatok_pkey_session_ok_for_obj(SESSION *session, OBJECT *key_obj) { if (object_is_token_object(key_obj) && (session->session_info.flags & CKF_RW_SESSION) == 0) return CK_FALSE; if (object_is_private(key_obj)) { switch (session->session_info.state) { case CKS_RO_PUBLIC_SESSION: case CKS_RW_PUBLIC_SESSION: case CKS_RW_SO_FUNCTIONS: return CK_FALSE; default: break; } } return CK_TRUE; } /** * Checks if the preconditions for using the related protected key of * the given secure key object are met. The caller of this routine must * have a READ_LOCK on the key object. * * The routine internally creates a protected key and adds it to the key_obj, * if the machine supports pkeys, the key is eligible for pkey support, does * not already have a valid pkey, and other conditions, like r/w session, are * fulfilled. As adding a protected key to the key_obj involves unlocking and * re-locking, the key blob, or any other attribute of the key, that was * retrieved via h_opaque_2_blob before calling this function might be no more * valid in a parallel environment. * * Therefore, the following return codes tell the calling function how to * proceed: * * @return CKR_OK: * a protected key was possibly created successfully and everything * is fine to use pkey support. In this case the protected key * shall be used, but a previously obtained key blob or other attr * might be invalid, because of a possible unlock/re-lock of the * key_obj. * * CKR_FUNCTION_NOT_SUPPORTED: * The system, session or key do not allow to use pkey support, but * no attempt was made to create a protected key. So the key blob, * or any other attr, is still valid and a fallback into the ep11 * path is ok. * * all others: * An internal error occurred and it was possibly attempted to create * a protected key for the object. In this case, the key blob, or * any other attr, might be no longer valid in a parallel environment * and the ep11 fallback is not possible anymore. The calling * function shall return with an error in this case. */ static CK_RV ccatok_pkey_check(STDLL_TokData_t *tokdata, SESSION *session, OBJECT *key_obj, CK_MECHANISM *mech) { struct cca_private_data *cca_data = tokdata->private_data; CK_ATTRIBUTE *opaque_attr = NULL; CK_RV ret = CKR_FUNCTION_NOT_SUPPORTED; /* Check if CPACF supports the operation implied by this key and mech */ if (!pkey_op_supported_by_cpacf(cca_data->msa_level, mech, key_obj->template)) { goto done; } /* Check config option */ switch (cca_data->pkey_mode) { case PKEY_MODE_DISABLED: goto done; break; case PKEY_MODE_DEFAULT: case PKEY_MODE_ENABLED: /* * Use existing pkeys, re-create invalid pkeys, and also create new * pkeys for secret/private keys that do not already have one. EC * public keys that are pkey-extractable, can always be used via CPACF * as there is no protected key involved. */ if (pkey_is_ec_public_key(key_obj->template) && object_is_pkey_extractable(key_obj)) { ret = CKR_OK; goto done; } if (!object_is_pkey_extractable(key_obj) || !cca_data->pkey_wrap_supported) { goto done; } if (template_attribute_get_non_empty(key_obj->template, CKA_IBM_OPAQUE_PKEY, &opaque_attr) != CKR_OK || !ccatok_pkey_is_valid(tokdata, key_obj)) { /* * this key has either no pkey attr, or it is not valid, * try to create one, if the session state allows it. */ if (!ccatok_pkey_session_ok_for_obj(session, key_obj)) goto done; ret = ccatok_pkey_update(tokdata, key_obj, mech->mechanism == CKM_AES_XTS); if (ret != CKR_OK) { TRACE_ERROR("error updating the protected key, rc=0x%lx\n", ret); if (ret == CKR_FUNCTION_NOT_SUPPORTED) ret = CKR_FUNCTION_FAILED; goto done; } } break; default: /* should not occur */ TRACE_ERROR("PKEY_MODE %i unsupported.\n", cca_data->pkey_mode); ret = CKR_FUNCTION_FAILED; goto done; break; } ret = CKR_OK; done: return ret; } static CK_RV ccatok_pkey_convert_key(STDLL_TokData_t *tokdata, SESSION *session, OBJECT *key_obj, CK_BBOOL xts_mode, CK_BYTE *protkey, CK_ULONG *protkey_len) { struct cca_private_data *cca_private = tokdata->private_data; int num_retries = 0, vp_offset1, vp_offset2; CK_ATTRIBUTE *skey_attr = NULL; CK_ATTRIBUTE *pkey_attr = NULL; CK_RV rc, rc2; /* Try to obtain a write lock on the key_obj */ rc = object_unlock(key_obj); if (rc != CKR_OK) { TRACE_ERROR("object_unlock failed, rc=0x%lx\n", rc); goto done; } rc = object_lock(key_obj, WRITE_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Could not obtain write lock.\n"); goto done; } /* * The key_obj could be modified between unlock and lock. Therefore get * the attribute when we have the write lock here. */ if (template_attribute_get_non_empty(key_obj->template, CKA_IBM_OPAQUE, &skey_attr) != CKR_OK) { TRACE_ERROR("This key has no blob: should not occur!\n"); rc = CKR_FUNCTION_FAILED; goto unlock; } retry: /* Convert secure key to protected key. */ rc = ccatok_pkey_skey2pkey(tokdata, skey_attr, &pkey_attr, xts_mode); if (rc != CKR_OK) { TRACE_ERROR("protkey creation failed, rc=0x%lx\n", rc); goto unlock; } /* * In case of XTS, check if the wkvp's of the two keys are identical. * An LGR could have happened between the creation of the two keys. */ if (xts_mode) { vp_offset1 = pkey_attr->ulValueLen / 2 - PKEY_MK_VP_LENGTH; vp_offset2 = pkey_attr->ulValueLen - PKEY_MK_VP_LENGTH; if (memcmp((CK_BYTE *)pkey_attr->pValue + vp_offset1, (CK_BYTE *)pkey_attr->pValue + vp_offset2, PKEY_MK_VP_LENGTH) != 0) { num_retries++; if (num_retries < PKEY_CONVERT_KEY_RETRIES) { TRACE_DEVEL("%s vp of xts key 1 does not match with vp of " "xts key 2, retry %d of %d ...\n", __func__, num_retries, PKEY_CONVERT_KEY_RETRIES); goto retry; } rc = CKR_FUNCTION_FAILED; goto unlock; } } /* * Save new protkey attr in key_obj. This happens only in memory, * works also for r/o sessions. */ rc = template_update_attribute(key_obj->template, pkey_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed, rc=0x%lx\n", rc); goto unlock; } /* If we have a r/w session, also save obj to disk. */ if (ccatok_pkey_session_ok_for_obj(session, key_obj)) { if (object_is_token_object(key_obj)) { rc = object_mgr_save_token_object(tokdata, key_obj); if (rc != CKR_OK) { TRACE_ERROR("Could not save token obj to repository, rc=0x%lx.\n", rc); goto unlock; } } } /* Update wkvp in CCA private data. */ if (pthread_rwlock_wrlock(&cca_private->pkey_rwlock)) { TRACE_ERROR("%s Failed to lock pkey lock\n", __func__); rc = CKR_CANT_LOCK; goto unlock; } memcpy(&cca_private->pkey_mk_vp, (CK_BYTE *)pkey_attr->pValue + pkey_attr->ulValueLen - PKEY_MK_VP_LENGTH, PKEY_MK_VP_LENGTH); if (pthread_rwlock_unlock(&cca_private->pkey_rwlock)) { TRACE_ERROR("%s Failed to unlock pkey lock\n", __func__); } /* Pass back new protkey. Need to do this before unlocking the obj. */ if (*protkey_len < pkey_attr->ulValueLen) { rc = CKR_BUFFER_TOO_SMALL; goto unlock; } memcpy(protkey, pkey_attr->pValue, pkey_attr->ulValueLen); *protkey_len = pkey_attr->ulValueLen; unlock: rc2 = object_unlock(key_obj); if (rc2 != CKR_OK) { TRACE_ERROR("object_unlock failed, rc=0x%lx\n", rc2); if (rc == CKR_OK) rc = rc2; goto done; } rc2 = object_lock(key_obj, READ_LOCK); if (rc2 != CKR_OK) { TRACE_ERROR("object_lock for READ failed, rc=0x%lx\n", rc2); if (rc == CKR_OK) rc = rc2; goto done; } done: return rc; } #endif /* * This function is called whenever a new object is created. It sets * attribute CKA_IBM_PROTKEY_EXTRACTABLE according to the PKEY_MODE token * option. * If the FORCE_SENSITIVE token option is enabled, it sets attribute * CKA_SENSITIVE to TRUE for secret keys (CKO_SECRET_KEY) if it is not * specified in the template. For private keys (CKO_PRIVATE_KEY) it always * sets CKA_SENSITIVE to TRUE if it is not specified in the template, * regardless of the FORCE_SENSITIVE option. */ CK_RV token_specific_set_attrs_for_new_object(STDLL_TokData_t *tokdata, CK_OBJECT_CLASS class, CK_ULONG mode, TEMPLATE *tmpl) { struct cca_private_data *cca_data = tokdata->private_data; CK_ATTRIBUTE *sensitive_attr = NULL; #ifndef NO_PKEY CK_ATTRIBUTE *pkey_attr = NULL, *ecp_attr = NULL; CK_BBOOL add_pkey_extractable = CK_FALSE, bfalse = CK_FALSE; CK_MECHANISM mech = { CKM_ECDSA, NULL, 0 }; #endif CK_BBOOL sensitive; CK_BBOOL btrue = CK_TRUE; CK_RV ret; UNUSED(mode); if (class != CKO_SECRET_KEY && class != CKO_PRIVATE_KEY && class != CKO_PUBLIC_KEY) return CKR_OK; if (class == CKO_PRIVATE_KEY || (class == CKO_SECRET_KEY && cca_data->cka_sensitive_default_true)) { /* private key, or secret key and FORCE_SENSITIVE is enabled */ ret = template_attribute_get_bool(tmpl, CKA_SENSITIVE, &sensitive); if (ret == CKR_TEMPLATE_INCOMPLETE) { /* Not in template, supply default (TRUE) */ ret = build_attribute(CKA_SENSITIVE, &btrue, sizeof(CK_BBOOL), &sensitive_attr); if (ret != CKR_OK) { TRACE_ERROR("build_attribute failed with ret=0x%lx\n", ret); goto done; } ret = template_update_attribute(tmpl, sensitive_attr); if (ret != CKR_OK) { TRACE_ERROR("update_attribute failed with ret=0x%lx\n", ret); free(sensitive_attr); goto done; } } } #ifndef NO_PKEY switch (cca_data->pkey_mode) { case PKEY_MODE_DISABLED: /* Nothing to do */ break; case PKEY_MODE_DEFAULT: /* * If the application did not specify pkey-extractable, all keys get * pkey-extractable=false. This was already set by default, so * nothing to do here. */ break; case PKEY_MODE_ENABLED: /* * All secret/private keys and all EC public keys where CPACF supports * the related curve, get pkey-extractable=true */ switch (class) { case CKO_PUBLIC_KEY: if (template_attribute_get_non_empty(tmpl, CKA_EC_PARAMS, &ecp_attr) == CKR_OK && pkey_op_supported_by_cpacf(cca_data->msa_level, &mech, tmpl)) add_pkey_extractable = CK_TRUE; /* * Note that the explicit parm CKM_ECDSA just tells the * function that it's not AES here. It covers all EC mechs */ break; default: add_pkey_extractable = CK_TRUE; break; } if (add_pkey_extractable) { if (!template_attribute_find(tmpl, CKA_IBM_PROTKEY_EXTRACTABLE, &pkey_attr)) { ret = build_attribute(CKA_IBM_PROTKEY_EXTRACTABLE, (CK_BBOOL *)&btrue, sizeof(CK_BBOOL), &pkey_attr); if (ret != CKR_OK) { TRACE_ERROR("build_attribute failed with ret=0x%lx\n", ret); goto done; } ret = template_update_attribute(tmpl, pkey_attr); if (ret != CKR_OK) { TRACE_ERROR("update_attribute failed with ret=0x%lx\n", ret); free(pkey_attr); goto done; } ret = build_attribute(CKA_IBM_PROTKEY_NEVER_EXTRACTABLE, (CK_BBOOL *)&bfalse, sizeof(CK_BBOOL), &pkey_attr); if (ret != CKR_OK) { TRACE_ERROR("build_attribute failed with ret=0x%lx\n", ret); goto done; } ret = template_update_attribute(tmpl, pkey_attr); if (ret != CKR_OK) { TRACE_ERROR("update_attribute failed with ret=0x%lx\n", ret); free(pkey_attr); goto done; } } } break; default: TRACE_ERROR("PKEY_MODE %i unsupported.\n", cca_data->pkey_mode); ret = CKR_FUNCTION_FAILED; goto done; break; } #endif ret = CKR_OK; done: return ret; } static CK_RV cca_get_and_set_aes_key_mode(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_IBM_CCA_AES_KEY_MODE_TYPE *mode) { struct cca_private_data *cca_data = tokdata->private_data; CK_ATTRIBUTE *attr = NULL; CK_RV rc; if (template_attribute_find(tmpl, CKA_IBM_CCA_AES_KEY_MODE, &attr)) { if (attr->ulValueLen != sizeof(CK_IBM_CCA_AES_KEY_MODE_TYPE) || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } *mode = *(CK_IBM_CCA_AES_KEY_MODE_TYPE *)attr->pValue; switch (*mode) { case CK_IBM_CCA_AES_DATA_KEY: case CK_IBM_CCA_AES_CIPHER_KEY: TRACE_DEVEL("AES key mode (attribute): %lu\n", *mode); return CKR_OK; default: TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } } switch (cca_data->aes_key_mode) { case AES_KEY_MODE_DATA: *mode = CK_IBM_CCA_AES_DATA_KEY; break; case AES_KEY_MODE_CIPHER: *mode = CK_IBM_CCA_AES_CIPHER_KEY; break; default: TRACE_DEVEL("Invalid AES key mode: %d\n", cca_data->aes_key_mode); return CKR_FUNCTION_FAILED; } rc = build_update_attribute(tmpl, CKA_IBM_CCA_AES_KEY_MODE, (CK_BYTE *)mode, sizeof(*mode)); if (rc != CKR_OK) { TRACE_DEVEL("build_update_attribute(CKA_IBM_CCA_AES_KEY_MODE) failed\n"); return rc; } TRACE_DEVEL("AES key mode (config): %lu\n", *mode); return CKR_OK; } static CK_RV cca_get_and_set_ml_dsa_key_mode( STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_IBM_CCA_ML_DSA_KEY_MODE_TYPE *mode) { struct cca_private_data *cca_data = tokdata->private_data; CK_ATTRIBUTE *attr = NULL; CK_RV rc; if (template_attribute_find(tmpl, CKA_IBM_CCA_ML_DSA_KEY_MODE, &attr)) { if (attr->ulValueLen != sizeof(CK_IBM_CCA_ML_DSA_KEY_MODE_TYPE) || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } *mode = *(CK_IBM_CCA_ML_DSA_KEY_MODE_TYPE *)attr->pValue; switch (*mode) { case CK_IBM_CCA_ML_DSA_PURE_KEY: case CK_IBM_CCA_ML_DSA_PREHASH_KEY: TRACE_DEVEL("ML-DSA key mode (attribute): %lu\n", *mode); return CKR_OK; default: TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } } switch (cca_data->ml_dsa_key_mode) { case ML_DSA_KEY_MODE_PURE: *mode = CK_IBM_CCA_ML_DSA_PURE_KEY; break; case ML_DSA_KEY_MODE_PREHASH: *mode = CK_IBM_CCA_ML_DSA_PREHASH_KEY; break; default: TRACE_DEVEL("Invalid ML-DSA key mode: %d\n", cca_data->ml_dsa_key_mode); return CKR_FUNCTION_FAILED; } rc = build_update_attribute(tmpl, CKA_IBM_CCA_ML_DSA_KEY_MODE, (CK_BYTE *)mode, sizeof(*mode)); if (rc != CKR_OK) { TRACE_DEVEL("build_update_attribute(CKA_IBM_CCA_ML_DSA_KEY_MODE) " "failed\n"); return rc; } TRACE_DEVEL("ML-DSA key mode (config): %lu\n", *mode); return CKR_OK; } static CK_RV ccatok_var_sym_token_is_exportable(const CK_BYTE *token, CK_ULONG token_len, CK_BBOOL *exportable, CK_BBOOL *cpacf_exportable) { uint16_t key_mgmt1; if (token_len < CCA_VAR_SYM_TOKEN_KEYMGMT1_OFFSET + 1) return CKR_ARGUMENTS_BAD; key_mgmt1 = be16toh(*((uint16_t *)&token[CCA_VAR_SYM_TOKEN_KEYMGMT1_OFFSET])); if (cpacf_exportable != NULL) #ifndef NO_PKEY *cpacf_exportable = (key_mgmt1 & CCA_VAR_SYM_XPRT_CPACF) != 0; #else *cpacf_exportable = FALSE; #endif if (exportable != NULL) { *exportable = (key_mgmt1 & (CCA_VAR_SYM_XPRT_SYM | CCA_VAR_SYM_XPRT_UASYM | CCA_VAR_SYM_XPRT_AASYM)) != 0; *exportable &= (key_mgmt1 & (CCA_VAR_SYM_NOEX_DES | CCA_VAR_SYM_NOEX_AES | CCA_VAR_SYM_NOEX_RSA)) == 0; } return CKR_OK; } #ifndef NO_PKEY static CK_BBOOL ccatok_ecc_token_is_cpacf_exportable(const CK_BYTE *token, CK_ULONG token_len) { CK_BYTE keyusage = token[CCA_ECC_TOKEN_KEYUSAGE_OFFSET]; if (token_len < CCA_ECC_TOKEN_KEYUSAGE_OFFSET) return CK_FALSE; if (keyusage & CCA_XPRTCPAC) return CK_TRUE; return CK_FALSE; } CK_RV ccatok_pkey_check_aes_xts(TEMPLATE *tmpl) { CK_BBOOL val; CK_RV rc; rc = template_attribute_get_bool(tmpl, CKA_IBM_PROTKEY_EXTRACTABLE, &val); if (rc != CKR_OK || val == TRUE) return CKR_TEMPLATE_INCONSISTENT; return CKR_OK; } CK_RV token_specific_aes_xts_key_gen(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_BYTE **aes_key, CK_ULONG *len, CK_ULONG key_size, CK_BBOOL *is_opaque) { struct cca_private_data *cca_data = tokdata->private_data; CK_ULONG key_len, key_token_len = 2 * 900; unsigned char key_token[900] = { 0, }; unsigned char key_form[CCA_KEYWORD_SIZE]; unsigned char key_type[CCA_KEYWORD_SIZE]; CK_BBOOL new_mk, new_mk2; CK_ATTRIBUTE *reenc_attr = NULL; CK_ULONG pl_ofs, pl_len; CK_IBM_CCA_AES_KEY_MODE_TYPE mode; CK_RV rc; if (cca_data->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } if (!cca_data->pkey_wrap_supported) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); return CKR_MECHANISM_INVALID; } if (!ccatok_pkey_check_aes_xts(tmpl)) { TRACE_ERROR("%s CCA AES XTS is not supported\n", __func__); return CKR_TEMPLATE_INCONSISTENT; } switch (key_size / 2) { case 16: case 32: break; default: TRACE_ERROR("Invalid key length: %lu\n", key_size); return CKR_KEY_SIZE_RANGE; } rc = cca_get_and_set_aes_key_mode(tokdata, tmpl, &mode); if (rc != CKR_OK) { TRACE_DEVEL("cca_get_and_set_aes_key_mode failed\n"); return rc; } if (mode == CK_IBM_CCA_AES_CIPHER_KEY) key_token_len = CCA_MAX_AES_CIPHER_KEY_SIZE; else key_token_len = CCA_KEY_ID_SIZE; *aes_key = calloc(key_token_len * 2, 1); if (*aes_key == NULL) return CKR_HOST_MEMORY; *len = key_token_len * 2; *is_opaque = TRUE; if (mode == CK_IBM_CCA_AES_CIPHER_KEY) rc = cca_build_aes_cipher_token(tokdata, tmpl, key_token, &key_token_len); else rc = cca_build_aes_data_token(tokdata, key_size / 2, key_token, &key_token_len); if (rc != CKR_OK) { TRACE_ERROR("Failed to build CCA key token"); /* Caller will free returned aes_key */ return CKR_DEVICE_ERROR; } memcpy(key_form, "OP ", CCA_KEYWORD_SIZE); if (mode == CK_IBM_CCA_AES_CIPHER_KEY) memcpy(key_type, "TOKEN ", CCA_KEYWORD_SIZE); else memcpy(key_type, "AESTOKEN", CCA_KEYWORD_SIZE); retry: memcpy(*aes_key, key_token, key_token_len); if (mode == CK_IBM_CCA_AES_CIPHER_KEY) { key_len = *len / 2; rc = cca_cipher_key_gen(tokdata, tmpl, CCA_AES_KEY, *aes_key, &key_len, key_form, key_type, key_size / 2, FALSE, &new_mk); } else { key_len = CCA_KEY_ID_SIZE; rc = cca_key_gen(tokdata, tmpl, CCA_AES_KEY, *aes_key, key_form, key_type, key_size / 2, FALSE, &new_mk); } if (rc != CKR_OK) { TRACE_ERROR("cca_%skey_gen function failed: rc=0x%lx\n", mode == CK_IBM_CCA_AES_CIPHER_KEY ? "cipher_" : "", rc); return rc; } memcpy(*aes_key + key_len, key_token, key_token_len); if (mode == CK_IBM_CCA_AES_CIPHER_KEY) { rc = cca_cipher_key_gen(tokdata, tmpl, CCA_AES_KEY, *aes_key + key_len, &key_len, key_form, key_type, key_size / 2, TRUE, &new_mk2); } else { rc = cca_key_gen(tokdata, tmpl, CCA_AES_KEY, *aes_key + key_len, key_form, key_type, key_size / 2, TRUE, &new_mk2); } if (rc != CKR_OK) { TRACE_ERROR("cca_%skey_gen function failed: rc=0x%lx\n", mode == CK_IBM_CCA_AES_CIPHER_KEY ? "cipher_" : "", rc); return rc; } if (new_mk == FALSE && new_mk2 == TRUE) { /* * Key 2 was created with new MK, key 1 with old MK. * Key 2 has CKA_IBM_OPAQUE and CKA_IBM_OPAQUE_REENC both * with new MK (was set by cca_reencipher_created_key() called inside * cca_key_gen()). * Key 1 has CKA_IBM_OPAQUE with old MK, and CKA_IBM_OPAQUE_REENC * with new MK (it was re-enciphered by cca_reencipher_created_key() * called inside 2nd cca_key_gen()). * Supply CKA_IBM_OPAQUE_REENC with new MK in CKA_IBM_OPAQUE * for key 1 also, so that both, CKA_IBM_OPAQUE and * CKA_IBM_OPAQUE_REENC have new MK only for both key parts. */ rc = template_attribute_get_non_empty(tmpl, CKA_IBM_OPAQUE_REENC, &reenc_attr); if (rc != CKR_OK || reenc_attr == NULL || reenc_attr->ulValueLen != key_len * 2) { TRACE_ERROR("No CKA_IBM_OPAQUE_REENC attr found\n"); return CKR_TEMPLATE_INCOMPLETE; } memcpy(*aes_key, reenc_attr->pValue, key_len); } else if (new_mk == TRUE && new_mk2 == FALSE) { /* * Key 1 was created with new MK, but key 2 with old MK. * This can happen when an APQN with new MK went offline * and another APQN with old MK is selected after creating * key 1 but before creating key 2. Since there is no key 1 blob * with old MK in CKA_IBM_OPAQUE, we need to re-create both keys * (both with old MK now). */ memset(*aes_key, 0, *len); goto retry; } /* * Compare the encrypted key material to ensure that the 2 key parts are * not the same. */ if (mode == CK_IBM_CCA_AES_CIPHER_KEY) { /* * A CCA AES-CIPHER key blob contains the encrypted key material at a * variable position dependent on several length bytes */ pl_ofs = 56 + (*aes_key)[34] + (*aes_key)[35] + (*aes_key)[36]; pl_len = (be16toh(*((uint16_t*)(*aes_key + 38))) + 7) / 8; } else { /* * A CCA AES-DATA key blob contains the encrypted key material at * offset 16, with a length of 32 bytes. */ pl_ofs = 16; pl_len = 32; } if (pl_ofs + pl_len <= key_len && memcmp(*aes_key + pl_ofs, *aes_key + key_len + pl_ofs, pl_len) == 0) { memset(*aes_key, 0, *len); goto retry; } *len = key_len * 2; return CKR_OK; } /** * This routine is currently only used when the operation is performed using * a protected key. Therefore we don't have (and don't need) an cca * fallback here. */ CK_RV token_specific_aes_xts(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, CK_BYTE *init_v, CK_BBOOL encrypt, CK_BBOOL initial, CK_BBOOL final, CK_BYTE *iv) { CK_ATTRIBUTE *attr = NULL; CK_RV rc; CK_MECHANISM mech = { CKM_AES_XTS, NULL, 0 }; if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } rc = template_attribute_get_non_empty(key_obj->template, CKA_IBM_OPAQUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_OPAQUE for the key.\n"); return rc; } /* CCA token protected key option */ rc = ccatok_pkey_check(tokdata, session, key_obj, &mech); switch (rc) { case CKR_OK: rc = pkey_aes_xts(tokdata, session, key_obj, init_v, in_data, in_data_len, out_data, out_data_len, encrypt, initial, final, iv, ccatok_pkey_convert_key); goto done; default: goto done; } done: return rc; } static CK_RV import_aes_xts_key(STDLL_TokData_t *tokdata, OBJECT * object) { CK_RV rc; CK_ATTRIBUTE *opaque_attr = NULL; enum cca_token_type token_type, token_type2; unsigned int token_keybitsize, token_keybitsize2; const CK_BYTE *mkvp, *mkvp2; CK_BBOOL new_mk, new_mk2; CK_ATTRIBUTE *reenc_attr = NULL; CK_ULONG pl_ofs, pl_len; if (!((struct cca_private_data *)tokdata->private_data)->pkey_wrap_supported) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); return CKR_MECHANISM_INVALID; } rc = template_attribute_find(object->template, CKA_IBM_OPAQUE, &opaque_attr); if (rc == TRUE) { /* * This is an import of an existing secure key which is stored in * the CKA_IBM_OPAQUE attribute. The CKA_VALUE attribute is only * a dummy reflecting the clear key byte size. However, let's * check if the template attributes match to the cca key in the * CKA_IBM_OPAQUE attribute. */ CK_BYTE zorro[64] = { 0 }; CK_BBOOL true = TRUE, false = FALSE; CK_ULONG value_len = 0; CK_BBOOL exp, cpacf_exp, exp2 = FALSE, cpacf_exp2 = FALSE; CK_IBM_CCA_AES_KEY_MODE_TYPE mode; if (analyse_cca_key_token(opaque_attr->pValue, opaque_attr->ulValueLen / 2, &token_type, &token_keybitsize, &mkvp) != TRUE) { TRACE_ERROR("Invalid/unknown cca token in CKA_IBM_OPAQUE attribute\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } if (token_type == sec_aes_data_key) { /* keybitsize has been checked by the analyse_cca_key_token() function */ mode = CK_IBM_CCA_AES_DATA_KEY; cpacf_exp = CK_TRUE; exp = CK_TRUE; } else if (token_type == sec_aes_cipher_key) { mode = CK_IBM_CCA_AES_CIPHER_KEY; if (token_keybitsize == 0) { /* * A CIPHER key with V1 payload does not allow to obtain the * keybitsize. The user must supply the CKA_VALUE_LEN with * a valid key size in the template. */ rc = template_attribute_get_ulong(object->template, CKA_VALUE_LEN, &value_len); if (rc != CKR_OK || value_len == 0) { TRACE_ERROR("For an AES CIPHER key token with V1 " "payload attribute CKA_VALUE_LEN must also " "be supplied to specify the key size\n"); return CKR_TEMPLATE_INCONSISTENT; } if (value_len != 32 && value_len != 64) { TRACE_ERROR("CKA_VALUE_LEN not valid for an AES key\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } token_keybitsize = value_len / 2 * 8; } rc = ccatok_var_sym_token_is_exportable(opaque_attr->pValue, opaque_attr->ulValueLen, &exp, &cpacf_exp); if (rc != CKR_OK) return rc; } else { TRACE_ERROR("CCA token type in CKA_IBM_OPAQUE does not match to keytype CKK_AES\n"); return CKR_TEMPLATE_INCONSISTENT; } if (check_expected_mkvp(tokdata, token_type, mkvp, &new_mk) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } rc = cca_reencipher_created_key(tokdata, object->template, opaque_attr->pValue, opaque_attr->ulValueLen / 2, new_mk, token_type, FALSE); if (rc != CKR_OK) { TRACE_ERROR("cca_reencipher_created_key failed: 0x%lx\n", rc); return rc; } if (analyse_cca_key_token(((CK_BYTE *)opaque_attr->pValue) + (opaque_attr->ulValueLen / 2), opaque_attr->ulValueLen / 2, &token_type2, &token_keybitsize2, &mkvp2) != TRUE) { TRACE_ERROR("Invalid/unknown cca token in CKA_IBM_OPAQUE attribute\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } if (token_type2 == sec_aes_data_key) { /* keybitsize has been checked by the analyse_cca_key_token() function */ cpacf_exp2 = CK_TRUE; exp2 = CK_TRUE; } else if (token_type2 == sec_aes_cipher_key) { if (token_keybitsize2 == 0) { /* * A CIPHER key with V1 payload does not allow to obtain the * keybitsize. The user must supply the CKA_VALUE_LEN with * a valid key size in the template. */ rc = template_attribute_get_ulong(object->template, CKA_VALUE_LEN, &value_len); if (rc != CKR_OK || value_len == 0) { TRACE_ERROR("For an AES CIPHER key token with V1 " "payload attribute CKA_VALUE_LEN must also " "be supplied to specify the key size\n"); return CKR_TEMPLATE_INCONSISTENT; } if (value_len != 32 && value_len != 64) { TRACE_ERROR("CKA_VALUE_LEN not valid for an AES key\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } token_keybitsize2 = value_len / 2 * 8; } rc = ccatok_var_sym_token_is_exportable(opaque_attr->pValue, opaque_attr->ulValueLen, &exp2, &cpacf_exp2); if (rc != CKR_OK) return rc; } else { TRACE_ERROR("CCA token type in CKA_IBM_OPAQUE does not match to keytype CKK_AES\n"); return CKR_TEMPLATE_INCONSISTENT; } if (check_expected_mkvp(tokdata, token_type2, mkvp2, &new_mk2) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } rc = cca_reencipher_created_key(tokdata, object->template, ((CK_BYTE *)opaque_attr->pValue) + (opaque_attr->ulValueLen / 2), opaque_attr->ulValueLen / 2, new_mk2, token_type2, TRUE); if (rc != CKR_OK) { TRACE_ERROR("cca_reencipher_created_key failed: 0x%lx\n", rc); return rc; } if (token_type != token_type2 || memcmp(mkvp, mkvp2, CCA_MKVP_LENGTH) != 0 || token_keybitsize != token_keybitsize2) { TRACE_ERROR("CCA AES XTS keys attribute value mismatch\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } if (exp != exp2 || cpacf_exp != cpacf_exp2) { TRACE_ERROR("CCA AES XTS keys attribute value mismatch\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } rc = build_update_attribute(object->template, CKA_EXTRACTABLE, (CK_BYTE *)&exp, sizeof(exp)); if (rc != CKR_OK) { TRACE_DEVEL("build_update_attribute(CKA_EXTRACTABLE) " "failed\n"); return rc; } #ifndef NO_PKEY rc = build_update_attribute(object->template, CKA_IBM_PROTKEY_EXTRACTABLE, (CK_BYTE *)&cpacf_exp, sizeof(cpacf_exp)); if (rc != CKR_OK) { TRACE_DEVEL("build_update_attribute(CKA_IBM_PROTKEY_EXTRACTABLE) " "failed\n"); return rc; } if (cpacf_exp) { rc = build_update_attribute(object->template, CKA_IBM_PROTKEY_NEVER_EXTRACTABLE, (CK_BYTE *)&false, sizeof(false)); if (rc != CKR_OK) { TRACE_DEVEL("build_update_attribute(CKA_IBM_PROTKEY_NEVER_EXTRACTABLE) " "failed\n"); return rc; } } #endif rc = build_update_attribute(object->template, CKA_IBM_CCA_AES_KEY_MODE, (CK_BYTE *)&mode, sizeof(mode)); if (rc != CKR_OK) { TRACE_DEVEL("build_update_attribute(CKA_IBM_CCA_AES_KEY_MODE) " "failed\n"); return rc; } /* * Compare the encrypted key material to ensure that the 2 key parts are * not the same. */ if (token_type == sec_aes_cipher_key) { /* * A CCA AES-CIPHER key blob contains the encrypted key material at a * variable position dependent on several length bytes */ pl_ofs = 56 + ((CK_BYTE *)opaque_attr->pValue)[34] + ((CK_BYTE *)opaque_attr->pValue)[35] + ((CK_BYTE *)opaque_attr->pValue)[36]; pl_len = (be16toh(*((uint16_t*)( ((CK_BYTE *)opaque_attr->pValue) + 38))) + 7) / 8; } else { /* * A CCA AES-DATA key blob contains the encrypted key material at * offset 16, with a length of 32 bytes. */ pl_ofs = 16; pl_len = 32; } if (pl_ofs + pl_len <= opaque_attr->ulValueLen / 2 && memcmp(((CK_BYTE *)opaque_attr->pValue) + pl_ofs , ((CK_BYTE *)opaque_attr->pValue) + opaque_attr->ulValueLen / 2 + pl_ofs, pl_len) == 0) { TRACE_ERROR("The 2 key parts of an AES-XTS key can not be the same\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } /* create a dummy CKA_VALUE attribute with the key bit size but all zero */ rc = build_update_attribute(object->template, CKA_VALUE, zorro, token_keybitsize * 2 / 8); if (rc != CKR_OK) { TRACE_DEVEL("build_update_attribute(CKA_VALUE) failed\n"); return rc; } /* Add/update CKA_SENSITIVE */ rc = build_update_attribute(object->template, CKA_SENSITIVE, &true, sizeof(CK_BBOOL)); if (rc != CKR_OK) { TRACE_DEVEL("build_update_attribute for CKA_SENSITIVE failed. rc=0x%lx\n", rc); return rc; } if (!ccatok_pkey_check_aes_xts(object->template)) { TRACE_ERROR("%s CCA AES XTS is not supported\n", __func__); return CKR_TEMPLATE_INCONSISTENT; } } else { /* * This is an import of a clear key value which is to be transfered * into a CCA Data AES key now. */ long return_code, reason_code, rule_array_count; unsigned char target_key_token[CCA_MAX_AES_CIPHER_KEY_SIZE * 2] = { 0 }; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0 }; long key_token_len, key_len; CK_ATTRIBUTE *value_attr = NULL; long reserved_1 = 0, key_part_len; CK_IBM_CCA_AES_KEY_MODE_TYPE mode; if (!ccatok_pkey_check_aes_xts(object->template)) { TRACE_ERROR("%s CCA AES XTS is not supported\n", __func__); return CKR_TEMPLATE_INCONSISTENT; } rc = template_attribute_get_non_empty(object->template, CKA_VALUE, &value_attr); if (rc != CKR_OK) { TRACE_ERROR("Incomplete key template\n"); return CKR_TEMPLATE_INCOMPLETE; } if (memcmp(value_attr->pValue, ((CK_BYTE *)value_attr->pValue) + value_attr->ulValueLen / 2, value_attr->ulValueLen / 2) == 0) { TRACE_ERROR("The 2 key parts of an AES-XTS key can not be the same\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } rc = cca_get_and_set_aes_key_mode(tokdata, object->template, &mode); if (rc != CKR_OK) { TRACE_DEVEL("cca_get_and_set_aes_key_mode failed\n"); return rc; } retry: if (mode == CK_IBM_CCA_AES_CIPHER_KEY) { memcpy(rule_array, "INTERNALAES CIPHER NO-KEY ANY-MODE", 5 * CCA_KEYWORD_SIZE); rule_array_count = 5; rc = cca_aes_cipher_add_key_usage_keywords(tokdata, object->template, rule_array, sizeof(rule_array), (CK_ULONG *) &rule_array_count); if (rc != CKR_OK) { TRACE_ERROR("Failed to add key usage keywords\n"); return rc; } key_len = sizeof(target_key_token) / 2; USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNBKTB2(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &reserved_1, NULL, &reserved_1, NULL, &reserved_1, NULL, &reserved_1, NULL, &reserved_1, NULL, &key_len, target_key_token); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBKTB2 (AES CIPHER KEY TOKEN BUILD) failed." " return:%ld, reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } memcpy(rule_array, "AES FIRST MIN1PART", 3 * CCA_KEYWORD_SIZE); rule_array_count = 3; key_len = sizeof(target_key_token) / 2; key_part_len = value_attr->ulValueLen / 2 * 8; USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNBKPI2(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &key_part_len, value_attr->pValue, &key_len, target_key_token); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBKPI2 (AES CIPHER KEY IMPORT FIRST) failed." " return:%ld, reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } memcpy(rule_array, "AES COMPLETE", 2 * CCA_KEYWORD_SIZE); rule_array_count = 2; USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNBKPI2(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &reserved_1, NULL, &key_len, target_key_token); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBKPI2 (AES CIPHER KEY IMPORT COMPLETE) failed." " return:%ld, reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } key_token_len = key_len; } else { memcpy(rule_array, "AES ", CCA_KEYWORD_SIZE); rule_array_count = 1; key_part_len = value_attr->ulValueLen / 2; USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNBCKM(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &key_part_len, value_attr->pValue, target_key_token); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBCKM failed. return:%ld, reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } key_token_len = CCA_KEY_ID_SIZE; } if (analyse_cca_key_token(target_key_token, key_token_len, &token_type, &token_keybitsize, &mkvp) == FALSE || mkvp == NULL) { TRACE_ERROR("Invalid/unknown cca token has been imported\n"); return CKR_FUNCTION_FAILED; } if (check_expected_mkvp(tokdata, token_type, mkvp, &new_mk) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } rc = cca_reencipher_created_key(tokdata, object->template, target_key_token, key_token_len, new_mk, token_type, FALSE); if (rc != CKR_OK) { TRACE_ERROR("cca_reencipher_created_key failed: 0x%lx\n", rc); return rc; } if (mode == CK_IBM_CCA_AES_CIPHER_KEY) { memcpy(rule_array, "INTERNALAES CIPHER NO-KEY ANY-MODE", 5 * CCA_KEYWORD_SIZE); rule_array_count = 5; rc = cca_aes_cipher_add_key_usage_keywords(tokdata, object->template, rule_array, sizeof(rule_array), (CK_ULONG *) &rule_array_count); if (rc != CKR_OK) { TRACE_ERROR("Failed to add key usage keywords\n"); return rc; } key_len = sizeof(target_key_token) / 2; USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNBKTB2(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &reserved_1, NULL, &reserved_1, NULL, &reserved_1, NULL, &reserved_1, NULL, &reserved_1, NULL, &key_len, target_key_token + key_token_len); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBKTB2 (AES CIPHER KEY TOKEN BUILD) failed." " return:%ld, reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } memcpy(rule_array, "AES FIRST MIN1PART", 3 * CCA_KEYWORD_SIZE); rule_array_count = 3; key_len = sizeof(target_key_token) / 2; key_part_len = value_attr->ulValueLen / 2 * 8; USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNBKPI2(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &key_part_len, (CK_BYTE *)value_attr->pValue + value_attr->ulValueLen / 2, &key_len, target_key_token + key_token_len); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBKPI2 (AES CIPHER KEY IMPORT FIRST) failed." " return:%ld, reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } memcpy(rule_array, "AES COMPLETE", 2 * CCA_KEYWORD_SIZE); rule_array_count = 2; USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNBKPI2(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &reserved_1, NULL, &key_len, target_key_token + key_token_len); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBKPI2 (AES CIPHER KEY IMPORT COMPLETE) failed." " return:%ld, reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } if (key_len != key_token_len) { TRACE_ERROR("Second XTS key part has different length than " "first one\n"); return CKR_FUNCTION_FAILED; } } else { key_part_len = value_attr->ulValueLen / 2; USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNBCKM(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &key_part_len, (CK_BYTE *)value_attr->pValue + value_attr->ulValueLen / 2, target_key_token + key_token_len); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBCKM failed. return:%ld, reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } } if (analyse_cca_key_token(target_key_token + key_token_len, key_token_len, &token_type2, &token_keybitsize2, &mkvp2) == FALSE || mkvp2 == NULL) { TRACE_ERROR("Invalid/unknown cca token has been imported\n"); return CKR_FUNCTION_FAILED; } if (check_expected_mkvp(tokdata, token_type2, mkvp2, &new_mk2) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } if (new_mk == FALSE && new_mk2 == TRUE) { /* * Key 2 was created with new MK, key 1 with old MK. * Key 2 will have CKA_IBM_OPAQUE and CKA_IBM_OPAQUE_REENC both * with new MK (will be set by cca_reencipher_created_key() below). * Key 1 has CKA_IBM_OPAQUE with old MK, and CKA_IBM_OPAQUE_REENC * with new MK (it was re-enciphered by cca_reencipher_created_key() * above). Supply CKA_IBM_OPAQUE_REENC with new MK in CKA_IBM_OPAQUE * for key 1 also, so that both, CKA_IBM_OPAQUE and * CKA_IBM_OPAQUE_REENC have new MK only for both key parts. */ rc = template_attribute_get_non_empty(object->template, CKA_IBM_OPAQUE_REENC, &reenc_attr); if (rc != CKR_OK || reenc_attr == NULL || reenc_attr->ulValueLen != CCA_KEY_ID_SIZE) { TRACE_ERROR("No CKA_IBM_OPAQUE_REENC attr found\n"); return CKR_TEMPLATE_INCOMPLETE; } memcpy(target_key_token, reenc_attr->pValue, key_token_len); } else if (new_mk == TRUE && new_mk2 == FALSE) { /* * Key 1 was created with new MK, but key 2 with old MK. * This can happen when an APQN with new MK went offline * and another APQN with old MK is selected after creating * key 1 but before creating key 2. Since there is no key 1 blob * with old MK in CKA_IBM_OPAQUE, we need to re-create both keys * (both with old MK now). */ memset(target_key_token, 0, sizeof(target_key_token)); goto retry; } rc = cca_reencipher_created_key(tokdata, object->template, target_key_token + key_token_len, CCA_KEY_ID_SIZE, new_mk2, token_type2, TRUE); if (rc != CKR_OK) { TRACE_ERROR("cca_reencipher_created_key failed: 0x%lx\n", rc); return rc; } if (token_type != token_type2 || memcmp(mkvp, mkvp2, CCA_MKVP_LENGTH) != 0 || token_keybitsize != token_keybitsize2) { TRACE_ERROR("CCA AES XTS keys attribute value mismatch\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } /* Add the key object to the template */ rc = build_update_attribute(object->template, CKA_IBM_OPAQUE, target_key_token, key_token_len * 2); if (rc != CKR_OK) { TRACE_DEVEL("build_update_attribute(CKA_IBM_OPAQUE) failed\n"); return rc; } /* zero clear key value */ OPENSSL_cleanse(value_attr->pValue, value_attr->ulValueLen); } TRACE_DEBUG("%s: imported object template attributes:\n", __func__); TRACE_DEBUG_DUMPTEMPL(object->template); return CKR_OK; } #endif /* NO_PKEY */ typedef struct { CK_BBOOL card_level_set; struct cca_version min_card_version; struct cca_version min_cex7_card_version; struct cca_version min_cex8_card_version; } cca_min_card_version_t; /* return -1 if v1 < v2, 0 if v1 == v2, 1 if v1 > v2 */ static int compare_cca_version(const struct cca_version *v1, const struct cca_version *v2) { if (v1->ver < v2->ver) return -1; if (v1->ver > v2->ver) return 1; if (v1->rel < v2->rel) return -1; if (v1->rel > v2->rel) return 1; if (v1->mod < v2->mod) return -1; if (v1->mod > v2->mod) return 1; return 0; } /* * Called from within cca_iterate_adapters() handler function, thus no need to * obtain CCA adapter lock */ static CK_RV cca_get_adapter_version(cca_min_card_version_t *data) { unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; long return_code, reason_code, rule_array_count, verb_data_length; struct cca_version adapter_version; char ccaversion[CCA_STATCCA_CCA_VERSION_LENGTH + 1]; memcpy(rule_array, "STATCCA ", CCA_KEYWORD_SIZE); rule_array_count = 1; verb_data_length = 0; dll_CSUACFQ(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &verb_data_length, NULL); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSUACFQ (STATCCA) failed. return:%ld, reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } ccaversion[CCA_STATCCA_CCA_VERSION_LENGTH] = '\0'; memcpy(ccaversion, &rule_array[CCA_STATCCA_CCA_VERSION_OFFSET], CCA_STATCCA_CCA_VERSION_LENGTH); if (sscanf(ccaversion, "%u.%u.%u", &adapter_version.ver, &adapter_version.rel, &adapter_version.mod) != 3) { TRACE_ERROR("sscanf of string %s failed, cannot determine CCA card version\n", ccaversion); return CKR_FUNCTION_FAILED; } if (compare_cca_version(&adapter_version, &data->min_card_version) < 0) { data->min_card_version = adapter_version; data->card_level_set = 1; } if (adapter_version.ver == 7 && compare_cca_version(&adapter_version, &data->min_cex7_card_version) < 0) data->min_cex7_card_version = adapter_version; if (adapter_version.ver == 8 && compare_cca_version(&adapter_version, &data->min_cex8_card_version) < 0) data->min_cex8_card_version = adapter_version; return CKR_OK; } /* * Callback function used by cca_get_min_card_level() to determine the * minimum CCA card level among all available APQNs. */ static CK_RV cca_get_card_level_handler(STDLL_TokData_t *tokdata, const char *adapter, unsigned short card, unsigned short domain, void *handler_data) { cca_min_card_version_t *data = (cca_min_card_version_t *) handler_data; UNUSED(tokdata); UNUSED(adapter); UNUSED(card); UNUSED(domain); return cca_get_adapter_version(data); } /* Called during token_specific_init() , no need to obtain CCA adapter lock */ static CK_RV cca_get_min_card_level(STDLL_TokData_t *tokdata) { struct cca_private_data *cca_private = tokdata->private_data; cca_min_card_version_t card_level_data; CK_RV ret; /* Determine min card level by iterating over all APQNs */ memset(&card_level_data, 0, sizeof(cca_min_card_version_t)); card_level_data.min_card_version.ver = UINT_MAX; card_level_data.min_card_version.rel = UINT_MAX; card_level_data.min_card_version.mod = UINT_MAX; card_level_data.min_cex7_card_version.ver = UINT_MAX; card_level_data.min_cex7_card_version.rel = UINT_MAX; card_level_data.min_cex7_card_version.mod = UINT_MAX; card_level_data.min_cex8_card_version.ver = UINT_MAX; card_level_data.min_cex8_card_version.rel = UINT_MAX; card_level_data.min_cex8_card_version.mod = UINT_MAX; ret = cca_iterate_adapters(tokdata, cca_get_card_level_handler, &card_level_data); if (ret != CKR_OK || card_level_data.card_level_set == 0) { TRACE_ERROR("cca_iterate_adapters failed, could not determine min card level.\n"); ret = CKR_FUNCTION_FAILED; goto done; } /* Update min card level in cca_private_data, needs write-lock. */ if (pthread_rwlock_wrlock(&cca_private->min_card_version_rwlock) != 0) { TRACE_ERROR("CCA min_card_version RW-lock failed.\n"); ret = CKR_CANT_LOCK; goto done; } cca_private->min_card_version = card_level_data.min_card_version; if (card_level_data.min_cex7_card_version.ver == 7) cca_private->min_cex7_card_version = card_level_data.min_cex7_card_version; else memset(&cca_private->min_cex7_card_version, 0, sizeof(cca_private->min_cex7_card_version)); if (card_level_data.min_cex8_card_version.ver == 8) cca_private->min_cex8_card_version = card_level_data.min_cex8_card_version; else memset(&cca_private->min_cex8_card_version, 0, sizeof(cca_private->min_cex8_card_version)); if (pthread_rwlock_unlock(&cca_private->min_card_version_rwlock) != 0) { TRACE_ERROR("CCA min_card_version RW-unlock failed.\n"); ret = CKR_CANT_LOCK; goto done; } ret = CKR_OK; done: return ret; } static CK_BBOOL cca_get_acp(struct cca_role_data *role_data, CK_ULONG role_data_size, CK_ULONG acp_num) { struct cca_acp_segment *acp_segment; CK_BBOOL ret = CK_FALSE, found = CK_FALSE; CK_BYTE *bitmap; CK_ULONG i, ofs, bit_no; if (role_data == NULL || role_data_size < sizeof(struct cca_role_data)) goto out; ofs = sizeof(struct cca_role_data); for (i = 0; i < be16toh(role_data->num_segments) && ofs < role_data_size; i++) { if (ofs + sizeof(struct cca_acp_segment) > role_data_size) goto out; acp_segment = (struct cca_acp_segment *)((CK_BYTE*)role_data + ofs); ofs += sizeof(struct cca_acp_segment); if (acp_num >= be16toh(acp_segment->start_bit_no) && acp_num <= be16toh(acp_segment->end_bit_no)) { if (ofs + be16toh(acp_segment->num_bytes) > role_data_size) goto out; bitmap = ((CK_BYTE *)acp_segment) + sizeof(struct cca_acp_segment); bit_no = acp_num - be16toh(acp_segment->start_bit_no); if (ACP_BYTE_NO(bit_no) > be16toh(acp_segment->num_bytes)) goto out; ret = (bitmap[ACP_BYTE_NO(bit_no)] & ACP_BIT_MASK(bit_no)) != 0; found = CK_TRUE; goto out; } ofs += be16toh(acp_segment->num_bytes); } out: TRACE_DEVEL("ACP 0x%04lx: %s %s\n", acp_num, ret ? "enabled" : "disabled", found ? "" : "(not in any segment)"); return ret; } typedef struct { CK_BBOOL acps_set; struct cca_acp_info acp_info; } cca_acp_info_data_t; /* * Callback function used by cca_get_acp_infos() to determine the * minimum ACP settings among all available APQNs. */ static CK_RV cca_get_acp_info_handler(STDLL_TokData_t *tokdata, const char *adapter, unsigned short card, unsigned short domain, void *handler_data) { cca_acp_info_data_t *data = (cca_acp_info_data_t *)handler_data; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; unsigned char role_name[8] = { 0 }; unsigned char roles_data[4000], role_data[4000]; long return_code, reason_code, rule_array_count, roles_data_len; long i, role_data_len; struct cca_role_data *role_info; CK_BBOOL found = CK_FALSE; UNUSED(tokdata); UNUSED(adapter); TRACE_DEBUG("APQN %02X.%04X (adapter '%s')\n", card, domain, adapter); memcpy(rule_array, "LSTROLES", CCA_KEYWORD_SIZE); rule_array_count = 1; roles_data_len = sizeof(roles_data); dll_CSUAACM(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, role_name, &roles_data_len, roles_data); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSUAACM (LSTROLES) failed for of APQN %02X.%04X. " "return:%ld, reason:%ld\n", card, domain, return_code, reason_code); return CKR_FUNCTION_FAILED; } for (i = 0; i < roles_data_len / 8; i++) { memcpy(role_name, &roles_data[i * 8], 8); TRACE_DEVEL("Found role '%.8s' for APQN %02X.%04X\n", role_name, card, domain); memcpy(rule_array, "GET-ROLE", CCA_KEYWORD_SIZE); rule_array_count = 1; role_data_len = sizeof(role_data); dll_CSUAACM(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, role_name, &role_data_len, role_data); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSUAACM (GET-ROLE) failed for APQN %02X.%04X. " "return:%ld, reason:%ld\n", card, domain, return_code, reason_code); return CKR_FUNCTION_FAILED; } TRACE_DEBUG_DUMP("Role-Data: ", (CK_BYTE *)role_data, role_data_len); if (role_data_len < (long)sizeof(struct cca_role_data)) { TRACE_ERROR("No role data is available for APQN %02X.%04X\n", card, domain); return CKR_FUNCTION_FAILED; } role_info = (struct cca_role_data *)role_data; /* Identify default role */ if ((memcmp(role_name, "DFLT", 4) != 0 && /* since z13 + non-s390x */ #if defined(__s390__) memcmp(role_name, "DEFALT", 6) != 0) || /* before z13 */ #else memcmp(role_name, "DEFAULT", 7) != 0) || /* non-s390x */ #endif be16toh(role_info->lower_time_limit) != 0x0000 || (be16toh(role_info->upper_time_limit) != 0x0000 && be16toh(role_info->upper_time_limit) != 0x173b) || /* 23:59 */ role_info->days_valid != 0xfe) continue; TRACE_DEVEL("Using ACPs of default role '%.8s' of APQN %02X.%04X\n", role_name, card, domain); data->acp_info.acp_03B8 &= cca_get_acp(role_info, role_data_len, 0x3B8); data->acp_info.acp_03CD &= cca_get_acp(role_info, role_data_len, 0x3CD); data->acps_set = CK_TRUE; found = CK_TRUE; break; } if (!found) { TRACE_ERROR("No default role found\n"); return CKR_FUNCTION_FAILED; } return CKR_OK; } /* Called during token_specific_init() , no need to obtain CCA adapter lock */ static CK_RV cca_get_acp_infos(STDLL_TokData_t *tokdata) { struct cca_private_data *cca_private = tokdata->private_data; cca_acp_info_data_t acp_info_data; CK_RV ret; /* Determine min ACP setting by iterating over all APQNs */ memset(&acp_info_data, 0, sizeof(cca_acp_info_data_t)); acp_info_data.acp_info.acp_03B8 = CK_TRUE; acp_info_data.acp_info.acp_03CD = CK_TRUE; ret = cca_iterate_adapters(tokdata, cca_get_acp_info_handler, &acp_info_data); if (ret != CKR_OK || acp_info_data.acps_set == 0) { TRACE_ERROR("cca_iterate_adapters failed, could not determine ACPs.\n"); ret = CKR_FUNCTION_FAILED; goto done; } TRACE_DEVEL("ACP 0x03B8: %s\n", acp_info_data.acp_info.acp_03B8 ? "enabled" : "disabled"); TRACE_DEVEL("ACP 0x03CD: %s\n", acp_info_data.acp_info.acp_03CD ? "enabled" : "disabled"); /* Update ACP infos in cca_private_data, needs write-lock. */ if (pthread_rwlock_wrlock(&cca_private->acp_info_rwlock) != 0) { TRACE_ERROR("CCA acp_info RW-lock failed.\n"); ret = CKR_CANT_LOCK; goto done; } cca_private->acp_info = acp_info_data.acp_info; if (pthread_rwlock_unlock(&cca_private->acp_info_rwlock) != 0) { TRACE_ERROR("CCA acp_info RW-unlock failed.\n"); ret = CKR_CANT_LOCK; goto done; } ret = CKR_OK; done: return ret; } static CK_BBOOL cca_pqc_strength_supported(STDLL_TokData_t * tokdata, CK_MECHANISM_TYPE mech, CK_ULONG keyform) { struct cca_private_data *cca_private = tokdata->private_data; #ifdef __s390__ const struct cca_version cca_v7_1 = { .ver = 7, .rel = 1, .mod = 0 }; #else const struct cca_version cca_v7_2_43 = { .ver = 7, .rel = 2, .mod = 43 }; #endif const struct cca_version cca_v8_0 = { .ver = 8, .rel = 0, .mod = 0 }; const struct cca_version cca_v8_4 = { .ver = 8, .rel = 4, .mod = 0 }; const struct cca_version *required = NULL; CK_BBOOL ret; switch (mech) { case CKM_IBM_DILITHIUM: switch (keyform) { case CK_IBM_DILITHIUM_KEYFORM_ROUND2_65: #ifdef __s390__ required = &cca_v7_1; #else required = &cca_v7_2_43; #endif break; case CK_IBM_DILITHIUM_KEYFORM_ROUND2_87: case CK_IBM_DILITHIUM_KEYFORM_ROUND3_65: case CK_IBM_DILITHIUM_KEYFORM_ROUND3_87: required = &cca_v8_0; break; default: TRACE_DEVEL("Dilithium keyform %lu not supported by CCA\n", keyform); return FALSE; } break; case CKM_IBM_ML_DSA_KEY_PAIR_GEN: case CKM_IBM_ML_DSA: case CKM_IBM_ML_KEM_KEY_PAIR_GEN: case CKM_IBM_ML_KEM_WITH_ECDH: case CKM_ML_DSA_KEY_PAIR_GEN: case CKM_ML_DSA: case CKM_HASH_ML_DSA: case CKM_HASH_ML_DSA_SHA512: required = &cca_v8_4; break; default: return FALSE; } if (pthread_rwlock_rdlock(&cca_private->min_card_version_rwlock) != 0) { TRACE_ERROR("CCA min_card_version RD-Lock failed.\n"); return FALSE; } ret = (compare_cca_version(&cca_private->cca_lib_version, required) >= 0 && compare_cca_version(&cca_private->min_card_version, required) >= 0); if (pthread_rwlock_unlock(&cca_private->min_card_version_rwlock) != 0) { TRACE_ERROR("CCA min_card_version RD-Unlock failed.\n"); return FALSE; } return ret; } static CK_BBOOL cca_sha3_supported(STDLL_TokData_t *tokdata) { #ifdef __s390__ CK_BBOOL ret; struct cca_private_data *cca_private = tokdata->private_data; const struct cca_version cca_v8_1 = { .ver = 8, .rel = 1, .mod = 0 }; if (pthread_rwlock_rdlock(&cca_private->min_card_version_rwlock) != 0) { TRACE_ERROR("CCA min_card_version RD-Lock failed.\n"); return FALSE; } ret = (compare_cca_version(&cca_private->cca_lib_version, &cca_v8_1) >= 0 && compare_cca_version(&cca_private->min_card_version, &cca_v8_1) >= 0); if (pthread_rwlock_unlock(&cca_private->min_card_version_rwlock) != 0) { TRACE_ERROR("CCA min_card_version RD-Unlock failed.\n"); return FALSE; } return ret; #else UNUSED(tokdata); /* CCA on Power and x86 doesn't support SHA3 at the moment */ return CK_FALSE; #endif } static CK_BBOOL cca_rsa_oaep_2_1_supported(STDLL_TokData_t *tokdata) { CK_BBOOL ret; struct cca_private_data *cca_private = tokdata->private_data; const struct cca_version cca_v8_1 = { .ver = 8, .rel = 1, .mod = 0 }; if (pthread_rwlock_rdlock(&cca_private->min_card_version_rwlock) != 0) { TRACE_ERROR("CCA min_card_version RD-Lock failed.\n"); return FALSE; } ret = (compare_cca_version(&cca_private->cca_lib_version, &cca_v8_1) >= 0 && compare_cca_version(&cca_private->min_card_version, &cca_v8_1) >= 0); if (pthread_rwlock_unlock(&cca_private->min_card_version_rwlock) != 0) { TRACE_ERROR("CCA min_card_version RD-Unlock failed.\n"); return FALSE; } return ret; } static CK_BBOOL cca_rsa_aeskw_supported(STDLL_TokData_t *tokdata, CK_KEY_TYPE key_type) { CK_BBOOL supp = CK_FALSE; CK_BBOOL aes_supp; struct cca_private_data *cca_private = tokdata->private_data; const struct cca_version cca_v8_2 = { .ver = 8, .rel = 2, .mod = 0 }; /* * The following ACPs must be enabled to support CKM_RSA_AES_KEY_WRAP * to wrap/unwrap certain key types: * * AES (requires CCA 8.2 or later): * - X'03B8' Symmetric Key Export - AES, CKM-RAKW * - X'03CD' Permit import of an AES key token from a PKCS#11 * CKM_RSA_AES_KEY_WRAP object * * Note: These ACPs are DISABLED by default, and must be explicitly enabled * by the crypto card admin to use CKM_RSA_AES_KEY_WRAP. */ if (pthread_rwlock_rdlock(&cca_private->acp_info_rwlock) != 0) { TRACE_ERROR("CCA acp_info RD-Lock failed.\n"); return FALSE; } aes_supp = cca_private->acp_info.acp_03B8 && cca_private->acp_info.acp_03CD; if (pthread_rwlock_unlock(&cca_private->acp_info_rwlock) != 0) { TRACE_ERROR("CCA acp_info RD-Unlock failed.\n"); return FALSE; } switch (key_type) { case CKK_AES: case (CK_KEY_TYPE)-1: supp = aes_supp; break; default: return FALSE; } if (pthread_rwlock_rdlock(&cca_private->min_card_version_rwlock) != 0) { TRACE_ERROR("CCA min_card_version RD-Lock failed.\n"); return FALSE; } supp = supp && compare_cca_version(&cca_private->cca_lib_version, &cca_v8_2) >= 0 && compare_cca_version(&cca_private->min_card_version, &cca_v8_2) >= 0; if (pthread_rwlock_unlock(&cca_private->min_card_version_rwlock) != 0) { TRACE_ERROR("CCA min_card_version RD-Unlock failed.\n"); return FALSE; } return supp; } static CK_BBOOL cca_rsa_8192_supported(STDLL_TokData_t *tokdata) { CK_BBOOL ret = FALSE; struct cca_private_data *cca_private = tokdata->private_data; const struct cca_version cca_v7_6 = { .ver = 7, .rel = 6, .mod = 0 }; const struct cca_version cca_v8_4 = { .ver = 8, .rel = 4, .mod = 0 }; if (pthread_rwlock_rdlock(&cca_private->min_card_version_rwlock) != 0) { TRACE_ERROR("CCA min_card_version RD-Lock failed.\n"); return FALSE; } /* CCA v7.x must be 7.6 or later, else v8.4 or later */ if (cca_private->cca_lib_version.ver == 7) ret = (compare_cca_version(&cca_private->cca_lib_version, &cca_v7_6) >= 0); else ret = (compare_cca_version(&cca_private->cca_lib_version, &cca_v8_4) >= 0); if (cca_private->min_card_version.ver <= 8) { if (cca_private->min_cex8_card_version.ver == 8) ret &= (compare_cca_version(&cca_private->min_cex8_card_version, &cca_v8_4) >= 0); if (cca_private->min_cex7_card_version.ver == 7) ret &= (compare_cca_version(&cca_private->min_cex7_card_version, &cca_v7_6) >= 0); if (cca_private->min_card_version.ver < 7) ret = FALSE; } if (pthread_rwlock_unlock(&cca_private->min_card_version_rwlock) != 0) { TRACE_ERROR("CCA min_card_version RD-Unlock failed.\n"); return FALSE; } return ret; } CK_RV token_specific_init(STDLL_TokData_t * tokdata, CK_SLOT_ID SlotNumber, char *conf_name) { struct cca_private_data *cca_private; CK_RV rc; UNUSED(conf_name); TRACE_INFO("cca %s slot=%lu running\n", __func__, SlotNumber); /* Request the API layer to lock against HSM-MK-change state changes. */ rc = init_hsm_mk_change_lock(tokdata); if (rc != CKR_OK) { TRACE_ERROR("init_hsm_mk_change_lock failed.\n"); return rc; } cca_private = calloc(1, sizeof(*cca_private)); if (cca_private == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); return CKR_HOST_MEMORY; } tokdata->private_data = cca_private; cca_private->pkeyfd = -1; #ifndef NO_PKEY cca_private->pkey_mode = PKEY_MODE_DEFAULT; #else cca_private->pkey_mode = PKEY_MODE_DISABLED; #endif cca_private->aes_key_mode = AES_KEY_MODE_DATA; cca_private->ml_dsa_key_mode = ML_DSA_KEY_MODE_PURE; rc = cca_load_config_file(tokdata, conf_name); if (rc != CKR_OK) goto error; rc = ock_generic_filter_mechanism_list(tokdata, cca_mech_list, cca_mech_list_len, &(tokdata->mech_list), &(tokdata->mech_list_len)); if (rc != CKR_OK) { TRACE_ERROR("Mechanism filtering failed! rc = 0x%lx\n", rc); goto error; } cca_private->lib_csulcca = dlopen(CCASHAREDLIB, RTLD_GLOBAL | DYNLIB_LDFLAGS); if (cca_private->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()); rc = CKR_FUNCTION_FAILED; goto error; } rc = cca_resolve_lib_sym(cca_private->lib_csulcca); if (rc != CKR_OK) goto error; rc = cca_get_version(tokdata); if (rc != CKR_OK) goto error; rc = cca_get_adapter_domain_selection_infos(tokdata); if (rc != CKR_OK) goto error; rc = init_cca_adapter_lock(tokdata); if (rc != CKR_OK) goto error; rc = cca_mk_change_check_pending_ops(tokdata); if (rc != CKR_OK) { TRACE_ERROR("%s Failed to check for pending HSM MK change operations " "rc=0x%lx\n", __func__, rc); OCK_SYSLOG(LOG_ERR, "Slot %lu: Failed to check for pending HSM MK " "change operations rc=0x%lx\n", tokdata->slot_id, rc); goto error; } rc = cca_check_mks(tokdata); if (rc != CKR_OK) goto error; if (pthread_rwlock_init(&cca_private->min_card_version_rwlock, NULL) != 0) { TRACE_ERROR("Initializing the min_card_version RW-Lock failed\n"); rc = CKR_CANT_LOCK; goto error; } rc = cca_get_min_card_level(tokdata); if (rc != CKR_OK) goto error; if (pthread_rwlock_init(&cca_private->acp_info_rwlock, NULL) != 0) { TRACE_ERROR("Initializing the acp_info RW-Lock failed\n"); rc = CKR_CANT_LOCK; goto error; } rc = cca_get_acp_infos(tokdata); if (rc != CKR_OK) goto error; #ifndef NO_PKEY cca_private->msa_level = get_msa_level(); TRACE_INFO("MSA level = %i\n", cca_private->msa_level); if (!ccatok_pkey_option_disabled(tokdata)) { cca_private->pkeyfd = open(PKEYDEVICE, O_RDWR); if (cca_private->pkeyfd >= 0) { TRACE_INFO("Opened /dev/pkey: file descriptor %d\n", cca_private->pkeyfd); rc = ccatok_pkey_get_firmware_wkvp(tokdata); if (rc != CKR_OK) { /* * Could not save mk_vp in cca_data, pkey support not available. * But the token should initialize ok, even if this happens. * We are just running without protected key support, i.e. the * pkey_wrap_supported flag in tokdata remains off. */ OCK_SYSLOG(LOG_WARNING, "%s: Warning: Could not get mk_vp, protected key support not available.\n", __func__); TRACE_WARNING( "Could not get mk_vp, protected key support not available.\n"); } } else { TRACE_WARNING("Could not open /dev/pkey, protected key support not available.\n"); } } #endif if (pthread_rwlock_init(&cca_private->pkey_rwlock, NULL) != 0) { TRACE_ERROR("Initializing PKEY lock failed.\n"); rc = CKR_CANT_LOCK; goto error; } return CKR_OK; error: token_specific_final(tokdata, FALSE); return rc; } CK_RV token_specific_final(STDLL_TokData_t *tokdata, CK_BBOOL in_fork_initializer) { struct cca_private_data *cca_private = tokdata->private_data; CK_ULONG i; TRACE_INFO("cca %s running\n", __func__); destroy_cca_adapter_lock(tokdata); if (tokdata->mech_list != NULL) free(tokdata->mech_list); if (cca_private != NULL) { if (cca_private->lib_csulcca != NULL && !in_fork_initializer) dlclose(cca_private->lib_csulcca); cca_private->lib_csulcca = NULL; for (i = 0; i < CCA_NUM_MK_TYPES; i++) { if (cca_private->mk_change_ops[i].mk_change_active && cca_private->mk_change_ops[i].apqns != NULL) free(cca_private->mk_change_ops[i].apqns); } #ifndef NO_PKEY if (cca_private->pkeyfd >= 0) close(cca_private->pkeyfd); #endif pthread_rwlock_destroy(&cca_private->min_card_version_rwlock); pthread_rwlock_destroy(&cca_private->acp_info_rwlock); pthread_rwlock_destroy(&cca_private->pkey_rwlock); free(cca_private); } tokdata->private_data = NULL; return CKR_OK; } static CK_RV cca_key_gen(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, enum cca_key_type type, CK_BYTE *key, unsigned char *key_form, unsigned char *key_type_1, CK_ULONG key_size, CK_BBOOL aes_xts_2dn_key, CK_BBOOL *has_new_mk) { 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, }; enum cca_token_type keytype; unsigned int keybitsize; const CK_BYTE *mkvp; CK_BBOOL new_mk; CK_RV rc; if (type == CCA_DES_KEY) { switch (key_size) { case 8: memcpy(key_length, "KEYLN8 ", (size_t) CCA_KEYWORD_SIZE); break; case 16: memcpy(key_length, "DOUBLE-O", (size_t) CCA_KEYWORD_SIZE); break; case 24: memcpy(key_length, "TRIPLE-O", (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; } USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNBKGN(&return_code, &reason_code, NULL, NULL, key_form, key_length, key_type_1, key_type_2, kek_key_identifier_1, kek_key_identifier_2, key, generated_key_identifier_2); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBKGN(KEYGEN) failed. return:%ld, reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } if (analyse_cca_key_token(key, CCA_KEY_ID_SIZE, &keytype, &keybitsize, &mkvp) == FALSE || mkvp == NULL) { TRACE_ERROR("Invalid/unknown cca token has been generated\n"); return CKR_FUNCTION_FAILED; } if (check_expected_mkvp(tokdata, keytype, mkvp, &new_mk) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } rc = cca_reencipher_created_key(tokdata, tmpl, key, CCA_KEY_ID_SIZE, new_mk, keytype, aes_xts_2dn_key); if (rc != CKR_OK) { TRACE_ERROR("cca_reencipher_created_key failed: 0x%lx\n", rc); return rc; } if (has_new_mk != NULL) *has_new_mk = new_mk; return CKR_OK; } static CK_RV cca_cipher_key_gen(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, enum cca_key_type type, CK_BYTE *key, CK_ULONG *key_len, unsigned char *key_form, unsigned char *key_type_1, CK_ULONG key_size, CK_BBOOL aes_xts_2dn_key, CK_BBOOL *has_new_mk) { long return_code, reason_code; 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 key_type_2[CCA_KEYWORD_SIZE + 1] = " "; long clear_key_bit_length, zero_length = 0, key_token_len; enum cca_token_type keytype; unsigned int keybitsize; const CK_BYTE *mkvp; CK_BBOOL new_mk; CK_RV rc; if (type == CCA_AES_KEY) { switch (key_size) { case 16: case 24: case 32: clear_key_bit_length = key_size * 8; break; default: TRACE_ERROR("Invalid key length: %lu\n", key_size); return CKR_KEY_SIZE_RANGE; } rule_array_count = 1; memcpy(rule_array, "AES ", CCA_KEYWORD_SIZE); } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } memcpy(rule_array + (rule_array_count * CCA_KEYWORD_SIZE), key_form, CCA_KEYWORD_SIZE); rule_array_count++; key_token_len = *key_len; USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNBKGN2(&return_code, &reason_code, &exit_data_len, exit_data, &rule_array_count, rule_array, &clear_key_bit_length, key_type_1, key_type_2, &zero_length, NULL, &zero_length, NULL, &zero_length, NULL, &zero_length, NULL, &zero_length, NULL, &zero_length, NULL, &key_token_len, key, &zero_length, NULL); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBKGN2(KEYGEN) failed. return:%ld, reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } *key_len = key_token_len; if (analyse_cca_key_token(key, key_token_len, &keytype, &keybitsize, &mkvp) == FALSE || mkvp == NULL) { TRACE_ERROR("Invalid/unknown cca token has been generated\n"); return CKR_FUNCTION_FAILED; } if (check_expected_mkvp(tokdata, keytype, mkvp, &new_mk) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } rc = cca_reencipher_created_key(tokdata, tmpl, key, key_token_len, new_mk, keytype, aes_xts_2dn_key); if (rc != CKR_OK) { TRACE_ERROR("cca_reencipher_created_key failed: 0x%lx\n", rc); return rc; } if (has_new_mk != NULL) *has_new_mk = new_mk; return CKR_OK; } CK_RV token_specific_des_key_gen(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_BYTE **des_key, CK_ULONG *len, CK_ULONG keysize, CK_BBOOL *is_opaque) { unsigned char key_form[CCA_KEYWORD_SIZE]; unsigned char key_type_1[CCA_KEYWORD_SIZE]; UNUSED(tmpl); if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } *des_key = calloc(CCA_KEY_ID_SIZE, 1); if (*des_key == NULL) return CKR_HOST_MEMORY; *len = CCA_KEY_ID_SIZE; *is_opaque = TRUE; memcpy(key_form, "OP ", (size_t) CCA_KEYWORD_SIZE); memcpy(key_type_1, "DATA ", (size_t) CCA_KEYWORD_SIZE); return cca_key_gen(tokdata, tmpl, CCA_DES_KEY, *des_key, key_form, key_type_1, keysize, FALSE, NULL); } 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; CK_RV rc; if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } rc = template_attribute_get_non_empty(key->template, CKA_IBM_OPAQUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_OPAQUE for the key.\n"); return rc; } /* 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); USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) RETRY_NEW_MK_BLOB_START() if (encrypt) { dll_CSNBENC(&return_code, &reason_code, NULL, NULL, attr->pValue, &length, in_data, init_v, &rule_array_count, rule_array, &pad_character, chaining_vector, local_out); } else { dll_CSNBDEC(&return_code, &reason_code, NULL, NULL, attr->pValue, &length, in_data, init_v, &rule_array_count, rule_array, chaining_vector, local_out); } RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, attr->pValue, attr->ulValueLen) USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { if (encrypt) 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); } static uint16_t cca_rsa_inttok_privkey_get_len(CK_BYTE * tok) { return be16toh(*(uint16_t *)&tok[CCA_RSA_INTTOK_PRIVKEY_LENGTH_OFFSET]); } /* Extract modulus n from a priv key section within an CCA internal RSA private key token */ static CK_RV cca_rsa_inttok_privkeysec_get_n(CK_BYTE *sec, CK_ULONG *n_len, CK_BYTE *n) { int n_len_offset, n_value_offset; uint16_t n_length; if (sec[0] == 0x30) { /* internal CCA RSA key token, 4096 bits, ME format */ n_len_offset = CCA_RSA_INTTOK_PRIVKEY_ME_N_LENGTH_OFFSET; n_value_offset = CCA_RSA_INTTOK_PRIVKEY_ME_N_OFFSET; } else if (sec[0] == 0x31) { /* internal CCA RSA key token, 4096 bits, CRT format */ n_len_offset = CCA_RSA_INTTOK_PRIVKEY_CRT_N_LENGTH_OFFSET; n_value_offset = CCA_RSA_INTTOK_PRIVKEY_CRT_N_OFFSET; } else { TRACE_ERROR("Invalid private key section identifier 0x%02hhx\n", sec[0]); return CKR_FUNCTION_FAILED; } n_length = be16toh(*(uint16_t *)&sec[n_len_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; } memcpy(n, &sec[n_value_offset], (size_t) n_length); *n_len = n_length; return CKR_OK; } /* Extract exponent e from a pubkey section within an CCA internal RSA private key token */ static CK_RV cca_rsa_inttok_pubkeysec_get_e(CK_BYTE *sec, CK_ULONG *e_len, CK_BYTE *e) { uint16_t e_length; CK_BYTE *p; if (sec[0] != 0x04) { TRACE_ERROR("Invalid public key section identifier 0x%02hhx\n", sec[0]); return CKR_FUNCTION_FAILED; } e_length = be16toh(*((uint16_t *) &sec[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; } *e_len = e_length; p = p11_bigint_trim(&sec[CCA_RSA_INTTOK_PUBKEY_E_OFFSET], e_len); memcpy(e, p, *e_len); return CKR_OK; } /* Get modulus n from an CCA external public RSA key token's pub key section */ static CK_RV cca_rsa_exttok_pubkeysec_get_n(CK_BYTE *sec, CK_ULONG *n_len, CK_BYTE *n) { uint16_t e_length, n_length, n_offset; if (sec[0] != 0x04) { TRACE_ERROR("Invalid public key section identifier 0x%02hhx\n", sec[0]); return CKR_FUNCTION_FAILED; } n_length = be16toh(*((uint16_t *)&sec[CCA_RSA_EXTTOK_PUBKEY_N_LENGTH_OFFSET])); e_length = be16toh(*((uint16_t *)&sec[CCA_RSA_INTTOK_PUBKEY_E_LENGTH_OFFSET])); n_offset = CCA_RSA_INTTOK_PUBKEY_E_OFFSET + e_length; if (n_length == 0) { TRACE_ERROR("n_length is 0 - pub section from priv key given ?!?.\n"); return CKR_FUNCTION_FAILED; } 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; } memcpy(n, &sec[n_offset], (size_t) n_length); *n_len = n_length; return CKR_OK; } /* Get exponent e from an CCA external public RSA key token's pub key section */ static CK_RV cca_rsa_exttok_pubkeysec_get_e(CK_BYTE *sec, CK_ULONG *e_len, CK_BYTE *e) { uint16_t e_length; CK_BYTE *p; if (sec[0] != 0x04) { TRACE_ERROR("Invalid public key section identifier 0x%02hhx\n", sec[0]); return CKR_FUNCTION_FAILED; } e_length = be16toh(*((uint16_t *) &sec[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; } *e_len = e_length; p = p11_bigint_trim(&sec[CCA_RSA_INTTOK_PUBKEY_E_OFFSET], e_len); memcpy(e, p, *e_len); return CKR_OK; } /* Pull n and e from RSA priv key token and add to template */ static CK_RV add_n_and_e_from_rsa_priv_key_to_templ(TEMPLATE *tmpl, CK_BYTE *cca_rsa_priv_key_token) { 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_RV rv; CK_BYTE *tok = cca_rsa_priv_key_token; if (tok[0] != 0x1F) { TRACE_ERROR("Invalid cca rsa private key token identifier 0x%02hhx\n", tok[0]); return CKR_FUNCTION_FAILED; } privkey_len = cca_rsa_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 */ rv = cca_rsa_inttok_privkeysec_get_n(&tok[CCA_RSA_INTTOK_PRIVKEY_OFFSET], &n_len, n); if (rv != CKR_OK) { TRACE_DEVEL("cca_inttok_privkey_get_n() failed. rv=0x%lx\n", rv); return rv; } /* Get e */ if ((rv = cca_rsa_inttok_pubkeysec_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 */ rv = build_update_attribute(tmpl, CKA_MODULUS, n, n_len); if (rv != CKR_OK) { TRACE_DEVEL("add CKA_MODULUS attribute to template failed, rv=0x%lx\n", rv); return rv; } /* Add e's value to the template */ rv = build_update_attribute(tmpl, CKA_PUBLIC_EXPONENT, e, e_len); if (rv != CKR_OK) { TRACE_DEVEL("add CKA_PUBLIC_EXPONENT attribute to template failed, rv=0x%lx\n", rv); return rv; } 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; } if ((rv = template_update_attribute(priv_tmpl, modulus))) { TRACE_DEVEL("template_update_attribute for n failed. rv=0x%lx\n", rv); goto error; } modulus = NULL; /* 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; } if ((rv = template_update_attribute(priv_tmpl, opaque_key))) { TRACE_DEVEL("template_update_attribute for opaque key failed. " "rv=0x%lx\n", rv); goto error; } opaque_key = NULL; return CKR_OK; error: if (modulus != NULL) free(modulus); if (opaque_key != NULL) free(opaque_key); return rv; } #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; long priv_key_token_length, publ_key_token_length; unsigned char regeneration_data[CCA_REGENERATION_DATA_SIZE] = { 0, }; unsigned char transport_key_identifier[CCA_KEY_ID_SIZE] = { 0, }; unsigned char priv_key_token[CCA_KEY_TOKEN_SIZE] = { 0, }; unsigned char publ_key_token[CCA_KEY_TOKEN_SIZE] = { 0, }; uint16_t size_of_e; uint16_t mod_bits, be_mod_bits; CK_ATTRIBUTE *pub_exp = NULL; CK_RV rv; CK_BYTE_PTR ptr; CK_ULONG tmpsize, tmpexp, tmpbits; enum cca_token_type keytype; unsigned int keybitsize; const CK_BYTE *mkvp; CK_BBOOL new_mk; if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } rv = template_attribute_get_ulong(publ_tmpl, CKA_MODULUS_BITS, &tmpbits); if (rv != CKR_OK) { TRACE_ERROR("Could not find CKA_MODULUS_BITS for the key.\n"); return rv; } mod_bits = tmpbits; /* If e is specified in the template, use it */ rv = template_attribute_get_non_empty(publ_tmpl, CKA_PUBLIC_EXPONENT, &pub_exp); if (rv == CKR_OK) { /* Per CCA manual, we really only support 6 values here: * * * 0 (generate random public exponent) * * * 3 or * * * 5 (since CCA 5.2) or * * * 17 (since CCA 5.2) or * * * 257 (since CCA 5.2) 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) { TRACE_ERROR("Unsupported public exponent (too large)\n"); 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 (it's always big endian) */ if (sizeof(CK_ULONG) == 64 / 8) tmpexp = be64toh(tmpexp); else tmpexp = be32toh(tmpexp); /* Check for one of the three allowed values */ switch (tmpexp) { case 0: case 3: case 5: case 17: case 257: case 65537: break; default: TRACE_ERROR("Unsupported public exponent\n"); return CKR_TEMPLATE_INCONSISTENT; } size_of_e = htobe16((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; be_mod_bits = htobe16(mod_bits); memcpy(key_value_structure, &be_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-AESCKEY-MGMT", (size_t) (CCA_KEYWORD_SIZE * 2)); private_key_name_length = 0; key_token_length = CCA_KEY_TOKEN_SIZE; USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNDPKB(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &key_value_structure_length, key_value_structure, &private_key_name_length, private_key_name, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, &key_token_length, key_token); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKB (RSA KEY TOKEN BUILD) failed. return:%ld," " reason:%ld\n", return_code, reason_code); if (return_code == 8 && reason_code == 760) return CKR_KEY_SIZE_RANGE; return CKR_FUNCTION_FAILED; } rule_array_count = 1; memset(rule_array, 0, sizeof(rule_array)); memcpy(rule_array, "MASTER ", (size_t) CCA_KEYWORD_SIZE); priv_key_token_length = CCA_KEY_TOKEN_SIZE; regeneration_data_length = 0; USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNDPKG(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, ®eneration_data_length, regeneration_data, &key_token_length, key_token, transport_key_identifier, &priv_key_token_length, priv_key_token); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKG (RSA KEY GENERATE) failed. return:%ld," " reason:%ld\n", return_code, reason_code); if (return_code == 8 && reason_code == 121) return CKR_KEY_SIZE_RANGE; return CKR_FUNCTION_FAILED; } if (analyse_cca_key_token(priv_key_token, priv_key_token_length, &keytype, &keybitsize, &mkvp) == FALSE || mkvp == NULL) { TRACE_ERROR("Invalid/unknown cca token has been generated\n"); return CKR_FUNCTION_FAILED; } if (check_expected_mkvp(tokdata, keytype, mkvp, &new_mk) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } rv = cca_reencipher_created_key(tokdata, priv_tmpl, priv_key_token, priv_key_token_length, new_mk, keytype, FALSE); if (rv != CKR_OK) { TRACE_ERROR("cca_reencipher_created_key failed: 0x%lx\n", rv); return rv; } TRACE_DEVEL("RSA secure key token generated. size: %ld\n", priv_key_token_length); rule_array_count = 0; publ_key_token_length = CCA_KEY_TOKEN_SIZE; USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNDPKX(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &priv_key_token_length, priv_key_token, &publ_key_token_length, publ_key_token); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKX (PUBLIC KEY TOKEN EXTRACT) failed. return:%ld," " reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } TRACE_DEVEL("RSA public key token extracted. size: %ld\n", publ_key_token_length); /* update priv template, add n, e and ibm opaque attr with priv key token */ rv = add_n_and_e_from_rsa_priv_key_to_templ(priv_tmpl, priv_key_token); if (rv != CKR_OK) { TRACE_DEVEL("add_n_and_e_from_rsa_priv_key_to_templ failed. rv:%lu\n", rv); return rv; } rv = build_update_attribute(priv_tmpl, CKA_IBM_OPAQUE, priv_key_token, priv_key_token_length); if (rv != CKR_OK) { TRACE_DEVEL("add CKA_IBM_OPAQUE attribute to priv template failed, rv:%lu\n", rv); return rv; } /* update pub template, add n, e and ibm opaque attr with pub key token */ rv = add_n_and_e_from_rsa_priv_key_to_templ(publ_tmpl, priv_key_token); if (rv != CKR_OK) { TRACE_DEVEL("add_n_and_e_from_rsa_priv_key_to_templ failed. rv:%lu\n", rv); return rv; } rv = build_update_attribute(publ_tmpl, CKA_IBM_OPAQUE, publ_key_token, publ_key_token_length); if (rv != CKR_OK) { TRACE_DEVEL("add CKA_IBM_OPAQUE attribute to publ template failed, rv:%lu\n", rv); return rv; } TRACE_DEBUG("%s: priv template attributes:\n", __func__); TRACE_DEBUG_DUMPTEMPL(priv_tmpl); TRACE_DEBUG("%s: publ template attributes:\n", __func__); TRACE_DEBUG_DUMPTEMPL(publ_tmpl); 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) { long return_code, reason_code, rule_array_count, data_structure_length; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; CK_ATTRIBUTE *attr; CK_ULONG max_out_len; CK_RV rc; if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } /* Find the secure key token */ rc = template_attribute_get_non_empty(key_obj->template, CKA_IBM_OPAQUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_OPAQUE for the key.\n"); return rc; } /* The max value allowable by CCA for out_data_len is 512/1024, so cap the * incoming value if its too large. CCA will throw error 8, 72 otherwise. */ max_out_len = (cca_rsa_8192_supported(tokdata) ? 1024 : 512); if (*out_data_len > max_out_len) *out_data_len = max_out_len; rule_array_count = 1; memcpy(rule_array, "PKCS-1.2", CCA_KEYWORD_SIZE); data_structure_length = 0; USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) RETRY_NEW_MK_BLOB_START() dll_CSNDPKE(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, (long *) &in_data_len, in_data, &data_structure_length, // must be 0 NULL, // ignored (long *) &(attr->ulValueLen), attr->pValue, (long *) out_data_len, out_data); RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, attr->pValue, attr->ulValueLen) USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKE (RSA ENCRYPT) failed. return:%ld, reason:%ld\n", return_code, reason_code); if (return_code == 8 && reason_code == 770) return CKR_KEY_SIZE_RANGE; 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; CK_ULONG max_out_len; CK_RV rc; if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } /* Find the secure key token */ rc = template_attribute_get_non_empty(key_obj->template, CKA_IBM_OPAQUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_OPAQUE for the key.\n"); return rc; } /* The max value allowable by CCA for out_data_len is 512/1024, so cap the * incoming value if its too large. CCA will throw error 8, 72 otherwise. */ max_out_len = (cca_rsa_8192_supported(tokdata) ? 1024 : 512); if (*out_data_len > max_out_len) *out_data_len = max_out_len; rule_array_count = 1; memcpy(rule_array, "PKCS-1.2", CCA_KEYWORD_SIZE); data_structure_length = 0; USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) RETRY_NEW_MK_BLOB_START() dll_CSNDPKD(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, (long *) &in_data_len, in_data, &data_structure_length, // must be 0 NULL, // ignored (long *) &(attr->ulValueLen), attr->pValue, (long *) out_data_len, out_data); RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, attr->pValue, attr->ulValueLen) USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) TRACE_DEVEL("CSNDPKD (RSA DECRYPT): return:%ld, reason:%ld\n", return_code, reason_code); rc = constant_time_select(constant_time_eq(return_code, CCA_SUCCESS), CKR_OK, CKR_FUNCTION_FAILED); rc = constant_time_select(constant_time_eq(return_code, 8) & constant_time_eq(reason_code, 66), CKR_ENCRYPTED_DATA_INVALID, rc); rc = constant_time_select(constant_time_eq(return_code, 8) & constant_time_eq(reason_code, 770), CKR_KEY_SIZE_RANGE, rc); 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_RSA_PKCS_OAEP_PARAMS *oaep; long return_code, reason_code, rule_array_count, data_structure_length; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; CK_ATTRIBUTE *attr; CK_ULONG max_out_len; OBJECT *key_obj = NULL; CK_BBOOL oaep2_supported; CK_MECHANISM_TYPE mgf_mech; CK_RV rc; UNUSED(hash); UNUSED(hlen); if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } 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"); goto done; } /* Find the secure key token */ rc = template_attribute_get_non_empty(key_obj->template, CKA_IBM_OPAQUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_OPAQUE for the key.\n"); goto done; } oaep = (CK_RSA_PKCS_OAEP_PARAMS *)ctx->mech.pParameter; if (oaep == NULL || ctx->mech.ulParameterLen != sizeof(CK_RSA_PKCS_OAEP_PARAMS)) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } if (oaep->source == CKZ_DATA_SPECIFIED && oaep->ulSourceDataLen > 0) { TRACE_ERROR("CCA does not support non-empty OAEP source data\n"); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } rc = get_mgf_mech(oaep->mgf, &mgf_mech); if (rc != CKR_OK) { TRACE_DEVEL("MGF mechanism is invalid.\n"); goto done; } if (oaep->hashAlg != mgf_mech) { TRACE_ERROR("OAEP MGF must be the same digest as the hash algorithm\n"); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } /* The max value allowable by CCA for out_data_len is 512/1024, so cap the * incoming value if its too large. CCA will throw error 8, 72 otherwise. */ max_out_len = (cca_rsa_8192_supported(tokdata) ? 1024 : 512); if (*out_data_len > max_out_len) *out_data_len = max_out_len; oaep2_supported = cca_rsa_oaep_2_1_supported(tokdata); if (oaep2_supported) memcpy(rule_array, "PKOAEP2 ", CCA_KEYWORD_SIZE); else memcpy(rule_array, "PKCSOAEP", CCA_KEYWORD_SIZE); rule_array_count = 2; switch (oaep->hashAlg) { case CKM_SHA_1: memcpy(rule_array + CCA_KEYWORD_SIZE, "SHA-1 ", CCA_KEYWORD_SIZE); break; case CKM_SHA224: if (!oaep2_supported) { TRACE_ERROR("OAEP with SHA224 requires CCA 8.1 or later\n"); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } memcpy(rule_array + CCA_KEYWORD_SIZE, "SHA-224 ", CCA_KEYWORD_SIZE); break; case CKM_SHA256: memcpy(rule_array + CCA_KEYWORD_SIZE, "SHA-256 ", CCA_KEYWORD_SIZE); break; case CKM_SHA384: if (!oaep2_supported) { TRACE_ERROR("OAEP with SHA384 requires CCA 8.1 or later\n"); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } memcpy(rule_array + CCA_KEYWORD_SIZE, "SHA-384 ", CCA_KEYWORD_SIZE); break; case CKM_SHA512: if (!oaep2_supported) { TRACE_ERROR("OAEP with SHA512 requires CCA 8.1 or later\n"); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } memcpy(rule_array + CCA_KEYWORD_SIZE, "SHA-512 ", CCA_KEYWORD_SIZE); break; default: TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } data_structure_length = 0; USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) RETRY_NEW_MK_BLOB_START() dll_CSNDPKE(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, (long *)&in_data_len, in_data, &data_structure_length, // must be 0 NULL, // ignored (long *)&(attr->ulValueLen), attr->pValue, (long *)out_data_len, out_data); RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, attr->pValue, attr->ulValueLen) USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKE (RSA ENCRYPT) failed. return:%ld, reason:%ld\n", return_code, reason_code); if (return_code == 8 && reason_code == 770) { rc = CKR_KEY_SIZE_RANGE; goto done; } rc = CKR_FUNCTION_FAILED; goto done; } else if (reason_code != 0) { TRACE_WARNING("CSNDPKE (RSA ENCRYPT) succeeded, but" " returned reason:%ld\n", reason_code); } done: 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_RSA_PKCS_OAEP_PARAMS *oaep; long return_code, reason_code, rule_array_count, data_structure_length; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; CK_ATTRIBUTE *attr; CK_ULONG max_out_len; OBJECT *key_obj = NULL; CK_BBOOL oaep2_supported; CK_MECHANISM_TYPE mgf_mech; CK_RV rc; UNUSED(hash); UNUSED(hlen); if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } 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"); goto done; } /* Find the secure key token */ rc = template_attribute_get_non_empty(key_obj->template, CKA_IBM_OPAQUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_OPAQUE for the key.\n"); goto done; } oaep = (CK_RSA_PKCS_OAEP_PARAMS *)ctx->mech.pParameter; if (oaep == NULL || ctx->mech.ulParameterLen != sizeof(CK_RSA_PKCS_OAEP_PARAMS)) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } if (oaep->source == CKZ_DATA_SPECIFIED && oaep->ulSourceDataLen > 0) { TRACE_ERROR("CCA does not support non-empty OAEP source data\n"); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } rc = get_mgf_mech(oaep->mgf, &mgf_mech); if (rc != CKR_OK) { TRACE_DEVEL("MGF mechanism is invalid.\n"); goto done; } if (oaep->hashAlg != mgf_mech) { TRACE_ERROR("OAEP MGF must be the same digest as the hash algorithm\n"); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } /* The max value allowable by CCA for out_data_len is 512/1024, so cap the * incoming value if its too large. CCA will throw error 8, 72 otherwise. */ max_out_len = (cca_rsa_8192_supported(tokdata) ? 1024 : 512); if (*out_data_len > max_out_len) *out_data_len = max_out_len; oaep2_supported = cca_rsa_oaep_2_1_supported(tokdata); if (oaep2_supported) memcpy(rule_array, "PKOAEP2 ", CCA_KEYWORD_SIZE); else memcpy(rule_array, "PKCSOAEP", CCA_KEYWORD_SIZE); rule_array_count = 2; switch (oaep->hashAlg) { case CKM_SHA_1: memcpy(rule_array + CCA_KEYWORD_SIZE, "SHA-1 ", CCA_KEYWORD_SIZE); break; case CKM_SHA224: if (!oaep2_supported) { TRACE_ERROR("OAEP with SHA224 requires CCA v8.1 or later\n"); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } memcpy(rule_array + CCA_KEYWORD_SIZE, "SHA-224 ", CCA_KEYWORD_SIZE); break; case CKM_SHA256: memcpy(rule_array + CCA_KEYWORD_SIZE, "SHA-256 ", CCA_KEYWORD_SIZE); break; case CKM_SHA384: if (!oaep2_supported) { TRACE_ERROR("OAEP with SHA384 requires CCA v8.1 or later\n"); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } memcpy(rule_array + CCA_KEYWORD_SIZE, "SHA-384 ", CCA_KEYWORD_SIZE); break; case CKM_SHA512: if (!oaep2_supported) { TRACE_ERROR("OAEP with SHA512 requires CCA v8.1 or later\n"); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } memcpy(rule_array + CCA_KEYWORD_SIZE, "SHA-512 ", CCA_KEYWORD_SIZE); break; default: TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } data_structure_length = 0; USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) RETRY_NEW_MK_BLOB_START() dll_CSNDPKD(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, (long *)&in_data_len, in_data, &data_structure_length, // must be 0 NULL, // ignored (long *) &(attr->ulValueLen), attr->pValue, (long *)out_data_len, out_data); RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, attr->pValue, attr->ulValueLen) USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) TRACE_DEVEL("CSNDPKD (RSA DECRYPT): return:%ld, reason:%ld\n", return_code, reason_code); rc = constant_time_select(constant_time_eq(return_code, CCA_SUCCESS), CKR_OK, CKR_FUNCTION_FAILED); rc = constant_time_select(constant_time_eq(return_code, 8) & constant_time_eq(reason_code, 2054), CKR_ENCRYPTED_DATA_INVALID, rc); rc = constant_time_select(constant_time_eq(return_code, 8) & constant_time_eq(reason_code, 2053), CKR_ENCRYPTED_DATA_INVALID, rc); rc = constant_time_select(constant_time_eq(return_code, 8) & constant_time_eq(reason_code, 770), CKR_KEY_SIZE_RANGE, rc); done: object_put(tokdata, key_obj, TRUE); key_obj = NULL; 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) { long return_code, reason_code, rule_array_count; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; long signature_bit_length; CK_ULONG max_out_len; CK_ATTRIBUTE *attr; CK_RV rc; UNUSED(sess); if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } /* Find the secure key token */ rc = template_attribute_get_non_empty(key_obj->template, CKA_IBM_OPAQUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_OPAQUE for the key.\n"); return rc; } /* The max value allowable by CCA for out_data_len is 512/1024, so cap the * incoming value if its too large. CCA will throw error 8, 72 otherwise. */ max_out_len = (cca_rsa_8192_supported(tokdata) ? 1024 : 512); if (*out_data_len > max_out_len) *out_data_len = max_out_len; rule_array_count = 1; memcpy(rule_array, "PKCS-1.1", CCA_KEYWORD_SIZE); USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) RETRY_NEW_MK_BLOB_START() dll_CSNDDSG(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, (long *) &(attr->ulValueLen), attr->pValue, (long *) &in_data_len, in_data, (long *) out_data_len, &signature_bit_length, out_data); RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, attr->pValue, attr->ulValueLen) USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDDSG (RSA SIGN) failed. return :%ld, reason: %ld\n", return_code, reason_code); if (return_code == 8 && reason_code == 770) return CKR_KEY_SIZE_RANGE; 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; CK_ULONG max_out_len; CK_RV rc; UNUSED(sess); if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } /* Find the secure key token */ rc = template_attribute_get_non_empty(key_obj->template, CKA_IBM_OPAQUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_OPAQUE for the key.\n"); return rc; } /* The max value allowable by CCA for out_data_len is 512/1024, so cap the * incoming value if its too large. CCA will throw error 8, 72 otherwise. */ max_out_len = (cca_rsa_8192_supported(tokdata) ? 1024 : 512); if (out_data_len > max_out_len) out_data_len = max_out_len; rule_array_count = 1; memcpy(rule_array, "PKCS-1.1", CCA_KEYWORD_SIZE); USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) RETRY_NEW_MK_BLOB_START() dll_CSNDDSV(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, (long *) &(attr->ulValueLen), attr->pValue, (long *) &in_data_len, in_data, (long *) &out_data_len, out_data); RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, attr->pValue, attr->ulValueLen) USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code == 4 && reason_code == 429) { return CKR_SIGNATURE_INVALID; } 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; } if (return_code == 8 && reason_code == 770) return CKR_KEY_SIZE_RANGE; return CKR_FUNCTION_FAILED; } if (reason_code != 0) { TRACE_WARNING("CSNDDSV (RSA VERIFY) succeeded, but" " returned reason:%ld\n", reason_code); } return CKR_OK; } 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 *out_data, CK_ULONG *out_data_len) { CK_RSA_PKCS_PSS_PARAMS *pss; long return_code, reason_code, rule_array_count; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; long signature_bit_length, message_len; CK_ATTRIBUTE *attr; CK_ULONG max_out_len; OBJECT *key_obj = NULL; CK_BYTE *message = NULL; CK_RV rc; UNUSED(sess); if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } 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"); goto done; } /* Find the secure key token */ rc = template_attribute_get_non_empty(key_obj->template, CKA_IBM_OPAQUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_OPAQUE for the key.\n"); goto done; } pss = (CK_RSA_PKCS_PSS_PARAMS *)ctx->mech.pParameter; if (pss == NULL || ctx->mech.ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS)) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } message_len = 4 + in_data_len; message = malloc(message_len); if (message == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto done; } *((uint32_t *)message) = htobe32(pss->sLen); memcpy(message + 4, in_data, in_data_len); /* The max value allowable by CCA for out_data_len is 512/1024, so cap the * incoming value if its too large. CCA will throw error 8, 72 otherwise. */ max_out_len = (cca_rsa_8192_supported(tokdata) ? 1024 : 512); if (*out_data_len > max_out_len) *out_data_len = max_out_len; rule_array_count = 2; switch (pss->hashAlg) { case CKM_SHA_1: if (pss->mgf != CKG_MGF1_SHA1) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } memcpy(rule_array, "PKCS-PSSSHA-1 ", 2 * CCA_KEYWORD_SIZE); break; case CKM_SHA224: if (pss->mgf != CKG_MGF1_SHA224) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } memcpy(rule_array, "PKCS-PSSSHA-224 ", 2 * CCA_KEYWORD_SIZE); break; case CKM_SHA256: if (pss->mgf != CKG_MGF1_SHA256) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } memcpy(rule_array, "PKCS-PSSSHA-256 ", 2 * CCA_KEYWORD_SIZE); break; case CKM_SHA384: if (pss->mgf != CKG_MGF1_SHA384) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } memcpy(rule_array, "PKCS-PSSSHA-384 ", 2 * CCA_KEYWORD_SIZE); break; case CKM_SHA512: if (pss->mgf != CKG_MGF1_SHA512) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } memcpy(rule_array, "PKCS-PSSSHA-512 ", 2 * CCA_KEYWORD_SIZE); break; } USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) RETRY_NEW_MK_BLOB_START() dll_CSNDDSG(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, (long *)&(attr->ulValueLen), attr->pValue, &message_len, message, (long *)out_data_len, &signature_bit_length, out_data); RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, attr->pValue, attr->ulValueLen) USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDDSG (RSA PSS SIGN) failed. return :%ld, reason: %ld\n", return_code, reason_code); if (return_code == 8 && reason_code == 770) { rc = CKR_KEY_SIZE_RANGE; goto done; } rc = CKR_FUNCTION_FAILED; goto done; } else if (reason_code != 0) { TRACE_WARNING("CSNDDSG (RSA PSS SIGN) succeeded, but " "returned reason: %ld\n", reason_code); } done: object_put(tokdata, key_obj, TRUE); key_obj = NULL; if (message != NULL) free(message); 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 *out_data, CK_ULONG out_data_len) { CK_RSA_PKCS_PSS_PARAMS *pss; long return_code, reason_code, rule_array_count, message_len; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; CK_ATTRIBUTE *attr; CK_ULONG max_out_len; OBJECT *key_obj = NULL; CK_BYTE *message = NULL; CK_RV rc; UNUSED(sess); if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } 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"); goto done; } /* Find the secure key token */ rc = template_attribute_get_non_empty(key_obj->template, CKA_IBM_OPAQUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_OPAQUE for the key.\n"); goto done; } pss = (CK_RSA_PKCS_PSS_PARAMS *)ctx->mech.pParameter; if (pss == NULL || ctx->mech.ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS)) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } message_len = 4 + in_data_len; message = malloc(message_len); if (message == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto done; } *((uint32_t *)message) = htobe32(pss->sLen); memcpy(message + 4, in_data, in_data_len); /* The max value allowable by CCA for out_data_len is 512/1024, so cap the * incoming value if its too large. CCA will throw error 8, 72 otherwise. */ max_out_len = (cca_rsa_8192_supported(tokdata) ? 1024 : 512); if (out_data_len > max_out_len) out_data_len = max_out_len; rule_array_count = 2; switch (pss->hashAlg) { case CKM_SHA_1: if (pss->mgf != CKG_MGF1_SHA1) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } memcpy(rule_array, "PKCS-PSSSHA-1 ", 2 * CCA_KEYWORD_SIZE); break; case CKM_SHA224: if (pss->mgf != CKG_MGF1_SHA224) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } memcpy(rule_array, "PKCS-PSSSHA-224 ", 2 * CCA_KEYWORD_SIZE); break; case CKM_SHA256: if (pss->mgf != CKG_MGF1_SHA256) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } memcpy(rule_array, "PKCS-PSSSHA-256 ", 2 * CCA_KEYWORD_SIZE); break; case CKM_SHA384: if (pss->mgf != CKG_MGF1_SHA384) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } memcpy(rule_array, "PKCS-PSSSHA-384 ", 2 * CCA_KEYWORD_SIZE); break; case CKM_SHA512: if (pss->mgf != CKG_MGF1_SHA512) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } memcpy(rule_array, "PKCS-PSSSHA-512 ", 2 * CCA_KEYWORD_SIZE); break; } USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) RETRY_NEW_MK_BLOB_START() dll_CSNDDSV(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, (long *)&(attr->ulValueLen), attr->pValue, &message_len, message, (long *)&out_data_len, out_data); RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, attr->pValue, attr->ulValueLen) USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code == 4 && reason_code == 429) { rc = CKR_SIGNATURE_INVALID; goto done; } else if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDDSV (RSA PSS 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. */ rc = CKR_SIGNATURE_INVALID; goto done; } if (return_code == 8 && reason_code == 770) { rc = CKR_KEY_SIZE_RANGE; goto done; } rc = CKR_FUNCTION_FAILED; goto done; } if (reason_code != 0) { TRACE_WARNING("CSNDDSV (RSA PSS VERIFY) succeeded, but" " returned reason:%ld\n", reason_code); } done: object_put(tokdata, key_obj, TRUE); key_obj = NULL; if (message != NULL) free(message); return rc; } static CK_RV cca_aes_cipher_add_key_usage_keywords(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_BYTE *rule_array, CK_ULONG rule_array_size, CK_ULONG *rule_array_count) { CK_BBOOL extractable = TRUE; CK_RV rc; #ifdef NO_PKEY UNUSED(tokdata); #endif rc = template_attribute_get_bool(tmpl, CKA_EXTRACTABLE, &extractable); if (rc != CKR_OK && rc != CKR_TEMPLATE_INCOMPLETE) { TRACE_ERROR("Failed to get CKA_EXTRACTABLE\n"); return rc; } if (!extractable) { if ((*rule_array_count + 6) * CCA_KEYWORD_SIZE > rule_array_size) return CKR_BUFFER_TOO_SMALL; memcpy(rule_array + (*rule_array_count * CCA_KEYWORD_SIZE), "NOEX-SYMNOEXUASYNOEXAASYNOEX-DESNOEX-AESNOEX-RSA", 6 * CCA_KEYWORD_SIZE); (*rule_array_count) += 6; } #ifndef NO_PKEY /* Add protected key related attributes to the rule array */ rc = ccatok_pkey_add_attrs(tokdata, tmpl, CKK_AES, 0, 0, CK_IBM_CCA_AES_CIPHER_KEY, rule_array, rule_array_size, rule_array_count); if (rc != CKR_OK) { TRACE_ERROR("%s ccatok_pkey_add_attrs failed with rc=0x%lx\n", __func__, rc); return rc; } #endif /* NO_PKEY */ return CKR_OK; } static CK_RV cca_build_aes_cipher_token(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_BYTE *key_token, CK_ULONG *key_token_size) { long return_code, reason_code; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; long exit_data_len = 0, rule_array_count; unsigned char exit_data[4] = { 0, }; long reserved_1 = 0; long key_token_len; CK_RV rc; rule_array_count = 5; memcpy(rule_array, "INTERNALAES CIPHER NO-KEY ANY-MODE", 5 * CCA_KEYWORD_SIZE); if (tmpl != NULL) { rc = cca_aes_cipher_add_key_usage_keywords(tokdata, tmpl, rule_array, sizeof(rule_array), (CK_ULONG *) &rule_array_count); if (rc != CKR_OK) { TRACE_ERROR("Failed to add key usage keywords\n"); return rc; } } key_token_len = *key_token_size; USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNBKTB2(&return_code, &reason_code, &exit_data_len, exit_data, &rule_array_count, rule_array, &reserved_1, NULL, &reserved_1, NULL, &reserved_1, NULL, &reserved_1, NULL, &reserved_1, NULL, &key_token_len, key_token); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBKTB2 (AES CIPHER KEY TOKEN BUILD) failed." " return:%ld, reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } *key_token_size = key_token_len; return CKR_OK; } static CK_RV cca_build_aes_data_token(STDLL_TokData_t *tokdata, CK_ULONG key_size, CK_BYTE *key_token, CK_ULONG *key_token_size) { long return_code, reason_code; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; unsigned char key_type[CCA_KEYWORD_SIZE]; unsigned char point_to_array_of_zeros = 0; unsigned char mkvp[16] = { 0, }; long exit_data_len = 0, rule_array_count; unsigned char exit_data[4] = { 0, }; unsigned char reserved_1[4] = { 0, }; if (*key_token_size < CCA_KEY_ID_SIZE) { TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); return CKR_BUFFER_TOO_SMALL; } memcpy(rule_array, "INTERNALAES NO-KEY ", CCA_KEYWORD_SIZE * 3); memcpy(key_type, "DATA ", 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 ", CCA_KEYWORD_SIZE); break; case 32: memcpy(rule_array + 3 * CCA_KEYWORD_SIZE, "KEYLN32 ", CCA_KEYWORD_SIZE); break; default: TRACE_ERROR("Invalid key length: %lu\n", key_size); return CKR_KEY_SIZE_RANGE; } rule_array_count = 4; USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNBKTB(&return_code, &reason_code, &exit_data_len, exit_data, key_token, key_type, &rule_array_count, rule_array, NULL, reserved_1, NULL, &point_to_array_of_zeros, NULL, NULL, NULL, NULL, mkvp); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBTKB (AES TOKEN BUILD) failed. return:%ld," " reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } *key_token_size = CCA_KEY_ID_SIZE; return CKR_OK; } CK_RV token_specific_aes_key_gen(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_BYTE **aes_key, CK_ULONG *len, CK_ULONG key_size, CK_BBOOL *is_opaque) { struct cca_private_data *cca_data = tokdata->private_data; CK_ULONG key_token_len; unsigned char key_form[CCA_KEYWORD_SIZE]; unsigned char key_type[CCA_KEYWORD_SIZE]; CK_IBM_CCA_AES_KEY_MODE_TYPE mode; CK_RV rc; if (cca_data->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } rc = cca_get_and_set_aes_key_mode(tokdata, tmpl, &mode); if (rc != CKR_OK) { TRACE_DEVEL("cca_get_and_set_aes_key_mode failed\n"); return rc; } if (mode == CK_IBM_CCA_AES_CIPHER_KEY) key_token_len = CCA_MAX_AES_CIPHER_KEY_SIZE; else key_token_len = CCA_KEY_ID_SIZE; *aes_key = calloc(key_token_len, 1); if (*aes_key == NULL) return CKR_HOST_MEMORY; *len = key_token_len; *is_opaque = TRUE; if (mode == CK_IBM_CCA_AES_CIPHER_KEY) rc = cca_build_aes_cipher_token(tokdata, tmpl, *aes_key, &key_token_len); else rc = cca_build_aes_data_token(tokdata, key_size, *aes_key, &key_token_len); if (rc != CKR_OK) { TRACE_ERROR("Failed to build CCA key token"); /* Caller will free returned aes_key */ return rc; } memcpy(key_form, "OP ", CCA_KEYWORD_SIZE); if (mode == CK_IBM_CCA_AES_CIPHER_KEY) memcpy(key_type, "TOKEN ", CCA_KEYWORD_SIZE); else memcpy(key_type, "AESTOKEN", CCA_KEYWORD_SIZE); if (mode == CK_IBM_CCA_AES_CIPHER_KEY) return cca_cipher_key_gen(tokdata, tmpl, CCA_AES_KEY, *aes_key, len, key_form, key_type, key_size, FALSE, NULL); else return cca_key_gen(tokdata, tmpl, CCA_AES_KEY, *aes_key, key_form, key_type, key_size, FALSE, NULL); } CK_RV token_specific_aes_ecb(STDLL_TokData_t * tokdata, SESSION *session, CK_BYTE * in_data, CK_ULONG in_data_len, CK_BYTE * out_data, CK_ULONG * out_data_len, OBJECT * key, CK_BYTE encrypt) { 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; CK_RV rc; #ifndef NO_PKEY CK_MECHANISM mech = { CKM_AES_ECB, NULL, 0 }; #endif #ifdef NO_PKEY UNUSED(session); #endif if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } rc = template_attribute_get_non_empty(key->template, CKA_IBM_OPAQUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_OPAQUE for the key.\n"); return rc; } key_len = attr->ulValueLen; #ifndef NO_PKEY /* CCA token protected key option */ rc = ccatok_pkey_check(tokdata, session, key, &mech); switch (rc) { case CKR_OK: rc = pkey_aes_ecb(tokdata, session, key, in_data, in_data_len, out_data, out_data_len, encrypt, ccatok_pkey_convert_key); goto done; case CKR_FUNCTION_NOT_SUPPORTED: /* fallback */ break; default: goto done; } #endif /* NO_PKEY */ /* Fallback: Perform the function via the CCA card ... */ rule_array_count = 4; memcpy(rule_array, "AES ECB KEYIDENTINITIAL ", rule_array_count * (size_t) CCA_KEYWORD_SIZE); USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) RETRY_NEW_MK_BLOB_START() if (encrypt) { dll_CSNBSAE(&return_code, &reason_code, &exit_data_len, exit_data, &rule_array_count, rule_array, &key_len, attr->pValue, &key_params_len, NULL, &block_size, &IV_len, NULL, &chain_vector_len, NULL, (long int *)&in_data_len, in_data, (long int *)out_data_len, local_out, &opt_data_len, NULL); } else { dll_CSNBSAD(&return_code, &reason_code, &exit_data_len, exit_data, &rule_array_count, rule_array, &key_len, attr->pValue, &key_params_len, NULL, &block_size, &IV_len, NULL, &chain_vector_len, NULL, (long int *)&in_data_len, in_data, (long int *)out_data_len, local_out, &opt_data_len, NULL); } RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, attr->pValue, attr->ulValueLen) USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { if (encrypt) { 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); } } rc = CKR_OK; #ifndef NO_PKEY done: #endif return rc; } CK_RV token_specific_aes_cbc(STDLL_TokData_t * tokdata, SESSION *session, CK_BYTE * in_data, CK_ULONG in_data_len, CK_BYTE * out_data, 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; CK_RV rc; #ifndef NO_PKEY CK_MECHANISM mech = { CKM_AES_CBC, init_v, IV_len }; #endif #ifdef NO_PKEY UNUSED(session); #endif if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } // get the key value rc = template_attribute_get_non_empty(key->template, CKA_IBM_OPAQUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_OPAQUE for the key.\n"); return rc; } key_len = attr->ulValueLen; #ifndef NO_PKEY /* CCA token protected key option */ rc = ccatok_pkey_check(tokdata, session, key, &mech); switch (rc) { case CKR_OK: rc = pkey_aes_cbc(tokdata, session, key, init_v, in_data, in_data_len, out_data, out_data_len, encrypt, ccatok_pkey_convert_key); goto done; case CKR_FUNCTION_NOT_SUPPORTED: /* fallback */ break; default: goto done; } #endif /* NO_PKEY */ /* Fallback: Perform the function via the CCA card ... */ if (in_data_len % 16 == 0) { rule_array_count = 3; memcpy(rule_array, "AES KEYIDENTINITIAL ", 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; USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) RETRY_NEW_MK_BLOB_START() if (encrypt) { dll_CSNBSAE(&return_code, &reason_code, &exit_data_len, exit_data, &rule_array_count, rule_array, &key_len, attr->pValue, &key_params_len, exit_data, &block_size, &IV_len, init_v, &chain_vector_len, chaining_vector, &length, in_data, (long int *)out_data_len, local_out, &opt_data_len, NULL); } else { dll_CSNBSAD(&return_code, &reason_code, &exit_data_len, exit_data, &rule_array_count, rule_array, &key_len, attr->pValue, &key_params_len, NULL, &block_size, &IV_len, init_v, &chain_vector_len, chaining_vector, &length, in_data, (long int *)out_data_len, local_out, &opt_data_len, NULL); } RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, attr->pValue, attr->ulValueLen) USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { if (encrypt) { 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; rc = CKR_OK; #ifndef NO_PKEY done: #endif 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) { UNUSED(sess); UNUSED(ctx); UNUSED(mech); UNUSED(key); UNUSED(encrypt); if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } return CKR_OK; } 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) { long return_code, reason_code, rule_array_count, exit_data_len = 0; unsigned char rule_array[CCA_RULE_ARRAY_SIZE]; unsigned char chaining_vector[104] = { 0 }; long in_length, out_length, key_len, block_size = 16, chain_vector_len; unsigned char exit_data[1]; CK_GCM_PARAMS *aes_gcm_param = NULL; OBJECT *key = NULL; CK_ATTRIBUTE *attr = NULL; long tag_len, iv_len, aad_len; CK_BYTE *tag_data; CK_RV rc; UNUSED(sess); if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } aes_gcm_param = (CK_GCM_PARAMS *)ctx->mech.pParameter; if (aes_gcm_param == NULL) { TRACE_ERROR("Mechanism parameter is NULL\n"); return CKR_MECHANISM_PARAM_INVALID; } tag_len = (aes_gcm_param->ulTagBits + 7) / 8; if (tag_len != 4 && tag_len != 8 && tag_len < 12 && tag_len > 16) { TRACE_ERROR("Tag len is invalid\n"); return CKR_MECHANISM_PARAM_INVALID; } if (encrypt) { if (*out_data_len < in_data_len + tag_len) { TRACE_ERROR("Output buffer is too small\n"); *out_data_len = in_data_len + tag_len; return CKR_BUFFER_TOO_SMALL; } } else { if (in_data_len < (CK_ULONG)tag_len) { TRACE_ERROR("Input buffer is too small\n"); return CKR_ARGUMENTS_BAD; } if (*out_data_len < in_data_len - tag_len) { TRACE_ERROR("Output buffer is too small\n"); *out_data_len = in_data_len - tag_len; return CKR_BUFFER_TOO_SMALL; } } 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; } rc = template_attribute_get_non_empty(key->template, CKA_IBM_OPAQUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key\n"); goto done; } rule_array_count = 4; memcpy(rule_array, "AES GCM KEYIDENTONLY ", 4 * CCA_KEYWORD_SIZE); key_len = attr->ulValueLen; iv_len = aes_gcm_param->ulIvLen; aad_len = aes_gcm_param->ulAADLen; chain_vector_len = sizeof(chaining_vector); USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) RETRY_NEW_MK_BLOB_START() if (encrypt) { in_length = in_data_len; out_length = *out_data_len - tag_len; tag_data = out_data + in_data_len; dll_CSNBSAE(&return_code, &reason_code, &exit_data_len, exit_data, &rule_array_count, rule_array, &key_len, attr->pValue, &tag_len, tag_data, &block_size, &iv_len, aes_gcm_param->pIv, &chain_vector_len, chaining_vector, &in_length, in_data, &out_length, out_data, &aad_len, aes_gcm_param->pAAD); out_length += tag_len; } else { in_length = in_data_len - tag_len; out_length = *out_data_len; tag_data = in_data + in_data_len - tag_len; dll_CSNBSAD(&return_code, &reason_code, &exit_data_len, exit_data, &rule_array_count, rule_array, &key_len, attr->pValue, &tag_len, tag_data, &block_size, &iv_len, aes_gcm_param->pIv, &chain_vector_len, chaining_vector, &in_length, in_data, &out_length, out_data, &aad_len, aes_gcm_param->pAAD); } RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, attr->pValue, attr->ulValueLen) USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { if (encrypt) { TRACE_ERROR("CSNBSAE (AES GCM ENCRYPT) failed. return:%ld," " reason:%ld\n", return_code, reason_code); } else { TRACE_ERROR("CSNBSAD (AES GCM DECRYPT) failed. return:%ld," " reason:%ld\n", return_code, reason_code); } (*out_data_len) = 0; if (!encrypt && return_code == 8 && reason_code == 2947) rc = CKR_ENCRYPTED_DATA_INVALID; /* Auth tag invalid */ else rc = CKR_FUNCTION_FAILED; goto done; } else if (reason_code != 0) { if (encrypt) { TRACE_WARNING("CSNBSAE (AES GCM ENCRYPT) succeeded, but" " returned reason:%ld\n", reason_code); } else { TRACE_WARNING("CSNBSAD (AES GCM DECRYPT) succeeded, but" " returned reason:%ld\n", reason_code); } } *out_data_len = out_length; rc = CKR_OK; done: object_put(tokdata, key, TRUE); key = NULL; return rc; } static CK_BBOOL token_specific_filter_mechanism(STDLL_TokData_t *tokdata, CK_MECHANISM_TYPE mechanism, CK_MECHANISM_INFO *info) { CK_BBOOL rc = CK_FALSE; switch(mechanism) { case CKM_AES_XTS: case CKM_AES_XTS_KEY_GEN: #ifndef NO_PKEY if (ccatok_pkey_option_disabled(tokdata) || !((struct cca_private_data *)tokdata->private_data)->pkey_wrap_supported) { TRACE_ERROR("AES XTS Mech not supported\n"); rc = CK_FALSE; break; } rc = CK_TRUE; #else UNUSED(tokdata); rc = CK_FALSE; #endif break; case CKM_IBM_DILITHIUM: /* Enable the mechanism if at least Dilithium Round 2 65 is supported */ rc = cca_pqc_strength_supported(tokdata, mechanism, CK_IBM_DILITHIUM_KEYFORM_ROUND2_65); break; case CKM_IBM_ML_DSA_KEY_PAIR_GEN: case CKM_IBM_ML_DSA: case CKM_ML_DSA: case CKM_HASH_ML_DSA: case CKM_HASH_ML_DSA_SHA512: rc = cca_pqc_strength_supported(tokdata, mechanism, CKP_ML_DSA_65); break; case CKM_IBM_ML_KEM_KEY_PAIR_GEN: case CKM_IBM_ML_KEM_WITH_ECDH: rc = cca_pqc_strength_supported(tokdata, mechanism, CKP_IBM_ML_KEM_768); break; case CKM_SHA3_224_RSA_PKCS: case CKM_SHA3_256_RSA_PKCS: case CKM_SHA3_384_RSA_PKCS: case CKM_SHA3_512_RSA_PKCS: if (info != NULL && cca_rsa_8192_supported(tokdata)) info->ulMaxKeySize = 8192; /* Fall through */ case CKM_SHA3_224: case CKM_SHA3_256: case CKM_SHA3_384: case CKM_SHA3_512: case CKM_IBM_SHA3_224: case CKM_IBM_SHA3_256: case CKM_IBM_SHA3_384: case CKM_IBM_SHA3_512: case CKM_ECDSA_SHA3_224: case CKM_ECDSA_SHA3_256: case CKM_ECDSA_SHA3_384: case CKM_ECDSA_SHA3_512: rc = cca_sha3_supported(tokdata); break; case CKM_RSA_AES_KEY_WRAP: rc = cca_rsa_aeskw_supported(tokdata, -1); if (info != NULL && rc == TRUE && cca_rsa_8192_supported(tokdata)) info->ulMaxKeySize = 8192; break; case CKM_RSA_PKCS_KEY_PAIR_GEN: case CKM_RSA_PKCS: case CKM_MD5_RSA_PKCS: case CKM_SHA1_RSA_PKCS: case CKM_SHA224_RSA_PKCS: case CKM_SHA256_RSA_PKCS: case CKM_SHA384_RSA_PKCS: case CKM_SHA512_RSA_PKCS: case CKM_RSA_PKCS_PSS: case CKM_SHA1_RSA_PKCS_PSS: case CKM_SHA224_RSA_PKCS_PSS: case CKM_SHA256_RSA_PKCS_PSS: case CKM_SHA384_RSA_PKCS_PSS: case CKM_SHA512_RSA_PKCS_PSS: case CKM_RSA_PKCS_OAEP: if (info != NULL && cca_rsa_8192_supported(tokdata)) info->ulMaxKeySize = 8192; rc = CK_TRUE; break; default: rc = CK_TRUE; break; } return rc; } /* 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, &token_specific_filter_mechanism); } 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, &token_specific_filter_mechanism); } 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(STDLL_TokData_t *tokdata, TEMPLATE *templ, uint8_t *curve_type, uint16_t *curve_bitlen, int *curve_nid) { struct cca_private_data *cca_private = tokdata->private_data; const struct cca_version cca_v7_2 = { .ver = 7, .rel = 2, .mod = 0 }; CK_ATTRIBUTE *attr = NULL; CK_KEY_TYPE key_type; unsigned int i; int ret; CK_RV rc; rc = template_attribute_get_ulong(templ, CKA_KEY_TYPE, &key_type); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); return rc; } /* Check if curve supported */ rc = template_attribute_get_non_empty(templ, CKA_EC_PARAMS, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_EC_PARAMS for the key.\n"); return rc; } 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 == KOBLITZ_CURVE || der_ec_supported[i].curve_type == BRAINPOOL_CURVE || der_ec_supported[i].curve_type == EDWARDS_CURVE) && der_ec_supported[i].twisted == CK_FALSE) { /* Check if the curves fits to the key type */ switch (key_type) { case CKK_EC: if (der_ec_supported[i].curve_type == EDWARDS_CURVE) { TRACE_ERROR("Edwards curves are not supported for key " "type CKK_EC.\n"); return CKR_CURVE_NOT_SUPPORTED; } break; case CKK_EC_EDWARDS: if (der_ec_supported[i].curve_type != EDWARDS_CURVE) { TRACE_ERROR("Only Edwards curves are supported for key " "type CKK_EC_EDWARDS.\n"); return CKR_CURVE_NOT_SUPPORTED; } break; default: TRACE_ERROR("Only EC or Edwards keys are supported.\n"); return CKR_KEY_TYPE_INCONSISTENT; } if (der_ec_supported[i].curve_type == KOBLITZ_CURVE) { /* * The Koblitz curve is only supported if all configured CCA * adapters have firmware version 7.2 or later, and if the CCA * host library has version 7.2 or later. */ if (pthread_rwlock_rdlock(&cca_private->min_card_version_rwlock) != 0) { TRACE_ERROR("CCA min_card_version RD-Lock failed.\n"); return CKR_CANT_LOCK; } ret = compare_cca_version(&cca_private->min_card_version, &cca_v7_2); if (pthread_rwlock_unlock(&cca_private->min_card_version_rwlock) != 0) { TRACE_ERROR("CCA min_card_version RD-Unlock failed.\n"); return CKR_CANT_LOCK; } if (ret < 0 || compare_cca_version(&cca_private->cca_lib_version, &cca_v7_2) < 0 ) { TRACE_DEVEL("Koblitz curve is only supported by CCA " "version 7.2 or later\n"); return CKR_CURVE_NOT_SUPPORTED; } } *curve_type = der_ec_supported[i].curve_type; *curve_bitlen = der_ec_supported[i].prime_bits; *curve_nid = der_ec_supported[i].nid; 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 = *(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 = be16toh(*(uint16_t *)&tok[priv_offset + CCA_SECTION_LEN_OFFSET]); publkey_rec = *(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); } struct cca_key_derivation_data *cca_ec_ecc_key_derivation_info(CK_BYTE *tok) { uint16_t pub_offset, pubsec_len, tok_len, ecc_offset; struct cca_key_derivation_data *eccinfo; tok_len = be16toh(*(uint16_t *)&tok[CCA_SECTION_LEN_OFFSET]); pub_offset = cca_ec_publkey_offset(tok); pubsec_len = be16toh(*(uint16_t *)&tok[pub_offset + CCA_SECTION_LEN_OFFSET]); ecc_offset = pub_offset + pubsec_len; if (ecc_offset >= tok_len) return NULL; if (tok[ecc_offset] != CCA_ECCDERIVEINFO_ID) return NULL; eccinfo = (struct cca_key_derivation_data *) (&tok[ecc_offset] + CCA_SECTION_HEADER_LEN); return eccinfo; } CK_RV token_create_ec_keypair(TEMPLATE * publ_tmpl, TEMPLATE * priv_tmpl, uint8_t curve_type, CK_ULONG priv_tok_len, CK_BYTE *priv_tok, CK_ULONG publ_tok_len, CK_BYTE *publ_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_EC_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(priv_tok); qlen_offset = pubkey_offset + CCA_EC_INTTOK_PUBKEY_Q_LEN_OFFSET; q_len = *(uint16_t *) & priv_tok[qlen_offset]; q_len = be16toh(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, &priv_tok[q_offset], (size_t) q_len); if (curve_type != EDWARDS_CURVE) { 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; } } else { ecpoint = q; ecpoint_len = q_len; } 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); if (curve_type != EDWARDS_CURVE) free(ecpoint); return rv; } if (curve_type != EDWARDS_CURVE) free(ecpoint); /* Add ec params to private key */ rv = template_attribute_get_non_empty(publ_tmpl, CKA_EC_PARAMS, &attr); if (rv != CKR_OK) { TRACE_ERROR("Could not find CKA_EC_PARAMS for the key.\n"); return rv; } if ((rv = build_update_attribute(priv_tmpl, CKA_EC_PARAMS, attr->pValue, attr->ulValueLen))) { TRACE_DEVEL("build_update_attribute for der data failed " "rv=0x%lx\n", rv); return rv; } /* store publ key token into CKA_IBM_OPAQUE of the public key object */ if ((rv = build_update_attribute(publ_tmpl, CKA_IBM_OPAQUE, publ_tok, publ_tok_len))) { TRACE_DEVEL("build_update_attribute for publ_tok failed rv=0x%lx\n", rv); return rv; } /* store priv key token into CKA_IBM_OPAQUE of the private key object */ if ((rv = build_update_attribute(priv_tmpl, CKA_IBM_OPAQUE, priv_tok, priv_tok_len))) { TRACE_DEVEL("build_update_attribute for priv_tok failed rv=0x%lx\n", rv); return rv; } return CKR_OK; } static CK_RV ccatok_get_key_info_from_template_attr(TEMPLATE *priv_tmpl, CK_ATTRIBUTE_TYPE attr_type, CK_KEY_TYPE *key_type, CK_ULONG *value_len, CK_IBM_CCA_AES_KEY_MODE_TYPE *key_mode) { CK_ATTRIBUTE *tmpl_attr = NULL; CK_RV rv; *key_type = (CK_ULONG)-1; *value_len = 0; *key_mode = (CK_ULONG)-1; if (template_attribute_find(priv_tmpl, attr_type, &tmpl_attr) != TRUE) return CKR_OK; rv = get_ulong_attribute_by_type((CK_ATTRIBUTE_PTR)tmpl_attr->pValue, tmpl_attr->ulValueLen / sizeof(CK_ATTRIBUTE), CKA_KEY_TYPE, key_type); if (rv != CKR_OK && rv != CKR_TEMPLATE_INCOMPLETE) return rv; rv = get_ulong_attribute_by_type((CK_ATTRIBUTE_PTR)tmpl_attr->pValue, tmpl_attr->ulValueLen / sizeof(CK_ATTRIBUTE), CKA_VALUE_LEN, value_len); if (rv != CKR_OK && rv != CKR_TEMPLATE_INCOMPLETE) return rv; rv = get_ulong_attribute_by_type((CK_ATTRIBUTE_PTR)tmpl_attr->pValue, tmpl_attr->ulValueLen / sizeof(CK_ATTRIBUTE), CKA_IBM_CCA_AES_KEY_MODE, key_mode); if (rv != CKR_OK && rv != CKR_TEMPLATE_INCOMPLETE) return rv; return CKR_OK; } static CK_RV ccatok_get_key_info_from_template_attrs(TEMPLATE *priv_tmpl, CK_KEY_TYPE *key_type, CK_ULONG *value_len, CK_IBM_CCA_AES_KEY_MODE_TYPE *key_mode) { CK_ATTRIBUTE_TYPE tmpl_attr[2] = { CKA_DERIVE_TEMPLATE, CKA_DECAPSULATE_TEMPLATE }; CK_KEY_TYPE tmpl_key_type[2] = { (CK_KEY_TYPE)-1, (CK_KEY_TYPE)-1 }; CK_ULONG tmpl_value_len[2] = { 0, 0 }; CK_IBM_CCA_AES_KEY_MODE_TYPE tmpl_key_mode[2] = { (CK_IBM_CCA_AES_KEY_MODE_TYPE)-1, (CK_IBM_CCA_AES_KEY_MODE_TYPE)-1 }; CK_ULONG i; CK_RV rc; *key_type = (CK_KEY_TYPE)-1; *value_len = 0; *key_mode = (CK_IBM_CCA_AES_KEY_MODE_TYPE)-1; for (i = 0; i < 2; i++) { rc = ccatok_get_key_info_from_template_attr(priv_tmpl, tmpl_attr[i], &tmpl_key_type[i], &tmpl_value_len[i], &tmpl_key_mode[i]); if (rc != CKR_OK) return rc; } for (i = 0; i < 2; i++) { if (tmpl_key_type[i] != (CK_KEY_TYPE)-1) { if (*key_type == (CK_KEY_TYPE)-1) { *key_type = tmpl_key_type[i]; } else if (*key_type != tmpl_key_type[i]) { TRACE_ERROR("CKA_KEY_TYPE is inconsistent in template attrs " "CKA_DERIVE_TEMPLATE, CKA_DECAPSULATE_TEMPLATE\n"); return CKR_TEMPLATE_INCONSISTENT; } } if (tmpl_value_len[i] != 0) { if (*value_len == 0) { *value_len = tmpl_value_len[i]; } else if (*value_len != tmpl_value_len[i]) { TRACE_ERROR("CKA_VALUE_LEN is inconsistent in template attrs " "CKA_DERIVE_TEMPLATE, CKA_DECAPSULATE_TEMPLATE\n"); return CKR_TEMPLATE_INCONSISTENT; } } if (tmpl_key_mode[i] != (CK_IBM_CCA_AES_KEY_MODE_TYPE)-1) { if (*key_mode == (CK_IBM_CCA_AES_KEY_MODE_TYPE)-1) { *key_mode = tmpl_key_mode[i]; } else if (*key_mode != tmpl_key_mode[i]) { TRACE_ERROR("CKA_IBM_CCA_AES_KEY_MODE is inconsistent in " "template attrs CKA_DERIVE_TEMPLATE, " "CKA_DECAPSULATE_TEMPLATE\n"); return CKR_TEMPLATE_INCONSISTENT; } } } return CKR_OK; } /* * Try to get derive key type and size from CKA_DERIVE_TEMPLATE or * CKA_DECAPSULATE_TEMPLATE. If neither CKA_DERIVE_TEMPLATE nor * CKA_DECAPSULATE_TEMPLATE is not available, or they do not contain attribute * CKA_KEY_TYPE, then the default is AES-256. * If CKA_KEY_TYPE is contained and is CKK_AES, it also checks if attribute * CKA_VALUE_LEN is contained and specifies a valid AES key size. * If CKA_IBM_CCA_AES_KEY_MODE is contained, it determines the CCA key mode, * otherwise the global default from the CCA config file is used. * The CCA token only supports to derive AES keys. */ static CK_RV ccatok_build_ec_derive_info(STDLL_TokData_t *tokdata, TEMPLATE *priv_tmpl, struct cca_key_derivation_data *derive_info) { struct cca_private_data *cca_private = tokdata->private_data; CK_IBM_CCA_AES_KEY_MODE_TYPE key_mode; CK_KEY_TYPE key_type; CK_ULONG value_len; CK_RV rv; /* Defaults: AES-256, DATA or CIPHER as per global setting */ switch (cca_private->aes_key_mode) { case AES_KEY_MODE_DATA: derive_info->key_type = CCA_KEY_DERIVE_TYPE_DATA; break; case AES_KEY_MODE_CIPHER: derive_info->key_type = CCA_KEY_DERIVE_TYPE_CIPHER; break; default: TRACE_DEVEL("Invalid AES key mode: %d\n", cca_private->aes_key_mode); return CKR_FUNCTION_FAILED; } derive_info->key_algorithm = CCA_AES_KEY; derive_info->key_size = htobe16(256); rv = ccatok_get_key_info_from_template_attrs(priv_tmpl, &key_type, &value_len, &key_mode); if (rv != CKR_OK) return rv; switch (key_mode) { case CK_IBM_CCA_AES_DATA_KEY: derive_info->key_type = CCA_KEY_DERIVE_TYPE_DATA; break; case CK_IBM_CCA_AES_CIPHER_KEY: derive_info->key_type = CCA_KEY_DERIVE_TYPE_CIPHER; break; default: /* Use global default as set above */ break; } if (key_type == (CK_ULONG)-1) return CKR_OK; switch (key_type) { case CKK_AES: switch (value_len) { case 0: derive_info->key_size = htobe16(256); /* Default to AES-256 */ break; case AES_KEY_SIZE_128: case AES_KEY_SIZE_192: case AES_KEY_SIZE_256: derive_info->key_size = htobe16(value_len * 8); break; default: TRACE_ERROR("Unsupported AES key size %lu\n", value_len); return CKR_ATTRIBUTE_VALUE_INVALID; } break; default: TRACE_ERROR("CCA does not support to derive/decaps keys of type " "0x%lx as DATA keys\n", key_type); return CKR_ATTRIBUTE_VALUE_INVALID; } return CKR_OK; } static CK_RV ccatok_check_ec_derive_info(STDLL_TokData_t *tokdata, OBJECT *obj, TEMPLATE *new_tmpl) { CK_ATTRIBUTE *opaque_attr, *tmpl_attr = NULL; CK_IBM_CCA_AES_KEY_MODE_TYPE derive_key_mode; CK_KEY_TYPE derive_key_type; CK_ULONG derive_value_len; CK_BBOOL derive = FALSE; CK_BBOOL decaps = FALSE; struct cca_key_derivation_data *ecc_info; CK_RV rc; UNUSED(tokdata); rc = template_attribute_get_non_empty(obj->template, CKA_IBM_OPAQUE, &opaque_attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_OPAQUE for the key.\n"); return rc; } ecc_info = cca_ec_ecc_key_derivation_info(opaque_attr->pValue); rc = template_attribute_get_bool(new_tmpl, CKA_DERIVE, &derive); rc |= template_attribute_get_bool(new_tmpl, CKA_DECAPSULATE, &decaps); if (rc == CKR_OK && (derive == TRUE || decaps == TRUE)) { /* * CKA_DERIVE or CKA_DECAPSULATE of an ECC private key is set to TRUE. * Check if the key has an ECC key derivation section (X'23'). * This is required to be able to support ECDH key derivation. */ if (ecc_info == NULL) { TRACE_ERROR("ECC private key does not have an ECC key derivation " "info section X'23'\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } if (ecc_info->key_type != CCA_KEY_DERIVE_TYPE_DATA && ecc_info->key_type != CCA_KEY_DERIVE_TYPE_CIPHER && ecc_info->key_algorithm != CCA_AES_KEY) { TRACE_ERROR("CCA can not derive/decaps keys other than AES DATA or " "AES CIPHER key tokens\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } } if (template_attribute_find(new_tmpl, CKA_DERIVE_TEMPLATE, &tmpl_attr) || template_attribute_find(new_tmpl, CKA_DECAPSULATE_TEMPLATE, &tmpl_attr)) { /* * CKA_DERIVE_TEMPLATE or CKA_DECAPSULATE_TEMPLATE is changed. * Check if the key has an ECC key derivation section (X'23'), * and if it matches the CKA_KEY_TYPE, CKA_VALUE_LEN and * CKA_IBM_CCA_AES_KEY_MODE attributes in these templates. */ rc = ccatok_get_key_info_from_template_attrs(new_tmpl, &derive_key_type, &derive_value_len, &derive_key_mode); if (rc == CKR_OK && ecc_info != NULL) { switch (derive_key_type) { case (CK_ULONG)-1: case CKK_AES: if (ecc_info->key_algorithm != CCA_AES_KEY) { TRACE_ERROR("The EC private key can not derive/decaps keys " "other than AES keys\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } /* Also check key size, if specified in template */ if (derive_value_len != 0 && derive_value_len * 8 != be16toh(ecc_info->key_size)) { TRACE_ERROR("The EC private key can not derive/decaps keys " "other than AES-%u keys\n", be16toh(ecc_info->key_size)); return CKR_ATTRIBUTE_VALUE_INVALID; } break; default: TRACE_ERROR("CCA does not support to derive/decaps keys of " "type 0x%lx\n", derive_key_type); return CKR_ATTRIBUTE_VALUE_INVALID; } switch (derive_key_mode) { case (CK_ULONG)-1: if (ecc_info->key_type != CCA_KEY_DERIVE_TYPE_DATA && ecc_info->key_type != CCA_KEY_DERIVE_TYPE_CIPHER) { TRACE_ERROR("The EC private key can not derive/decaps keys " "other than AES DATA or AES CIPHER keys\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } break; case CK_IBM_CCA_AES_DATA_KEY: if (ecc_info->key_type != CCA_KEY_DERIVE_TYPE_DATA) { TRACE_ERROR("The EC private key can not derive/decaps keys " "other than AES DATA keys\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } break; case CK_IBM_CCA_AES_CIPHER_KEY: if (ecc_info->key_type != CCA_KEY_DERIVE_TYPE_CIPHER) { TRACE_ERROR("The EC private key can not derive/decaps keys " "other than AES CIPHER keys\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } break; default: TRACE_ERROR("CCA does not support to derive/decaps keys of " "mode 0x%lx\n", derive_key_mode); return CKR_ATTRIBUTE_VALUE_INVALID; } } } 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; long priv_key_token_length, publ_key_token_length; unsigned char regeneration_data[CCA_REGENERATION_DATA_SIZE] = { 0, }; unsigned char transport_key_identifier[CCA_KEY_ID_SIZE] = { 0, }; unsigned char priv_key_token[CCA_KEY_TOKEN_SIZE] = { 0, }; unsigned char publ_key_token[CCA_KEY_TOKEN_SIZE] = { 0, }; struct cca_key_derivation_data deriv_data; long deriv_data_size = 0; CK_RV rv; long param1 = 0; unsigned char *param2 = NULL; uint8_t curve_type; uint16_t curve_bitlen, be_curve_bitlen; int curve_nid; enum cca_token_type keytype; unsigned int keybitsize; const CK_BYTE *mkvp; CK_BBOOL new_mk; if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } rv = curve_supported(tokdata, publ_tmpl, &curve_type, &curve_bitlen, &curve_nid); 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)); be_curve_bitlen = be16toh(curve_bitlen); memcpy(&key_value_structure[CCA_PKB_EC_LEN_OFFSET], &be_curve_bitlen, sizeof(uint16_t)); key_value_structure_length = CCA_EC_KEY_VALUE_STRUCT_SIZE; /* Enable ECDH key derivation with keys generated by the CCA token */ if (curve_type != EDWARDS_CURVE) { rule_array_count = 3; memcpy(rule_array, "ECC-PAIRKEY-MGMTECC-VER1", 3 * CCA_KEYWORD_SIZE); } else { rule_array_count = 2; memcpy(rule_array, "ECC-PAIRSIG-ONLY", 2 * CCA_KEYWORD_SIZE); } #ifndef NO_PKEY /* Add protected key related attributes to the rule array */ rv = ccatok_pkey_add_attrs(tokdata, priv_tmpl, curve_type == EDWARDS_CURVE ? CKK_EC_EDWARDS : CKK_EC, curve_type, curve_bitlen, 0, rule_array, sizeof(rule_array), (CK_ULONG *)&rule_array_count); if (rv != CKR_OK) { TRACE_ERROR("%s ccatok_pkey_add_attrs failed with rc=0x%lx\n", __func__, rv); return rv; } #endif /* NO_PKEY */ private_key_name_length = 0; if (curve_type != EDWARDS_CURVE) { /* Enable the ECC private key to derive keys */ rv = ccatok_build_ec_derive_info(tokdata, priv_tmpl, &deriv_data); if (rv != CKR_OK) { TRACE_ERROR("%s ccatok_build_derive_info failed with rc=0x%lx\n", __func__, rv); return rv; } deriv_data_size = sizeof(deriv_data); } key_token_length = CCA_KEY_TOKEN_SIZE; USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNDPKB(&return_code, &reason_code, &exit_data_len, exit_data, &rule_array_count, rule_array, &key_value_structure_length, key_value_structure, &private_key_name_length, private_key_name, ¶m1, param2, &deriv_data_size, curve_type != EDWARDS_CURVE ? (unsigned char *)&deriv_data : NULL, ¶m1, param2, ¶m1, param2, ¶m1, param2, &key_token_length, key_token); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKB (EC KEY TOKEN BUILD) failed. return:%ld," " 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); priv_key_token_length = CCA_KEY_TOKEN_SIZE; regeneration_data_length = 0; USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNDPKG(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, ®eneration_data_length, regeneration_data, &key_token_length, key_token, transport_key_identifier, &priv_key_token_length, priv_key_token); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKG (EC KEY GENERATE) failed." " 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; } if (analyse_cca_key_token(priv_key_token, priv_key_token_length, &keytype, &keybitsize, &mkvp) == FALSE || mkvp == NULL) { TRACE_ERROR("Invalid/unknown cca token has been generated\n"); return CKR_FUNCTION_FAILED; } if (check_expected_mkvp(tokdata, keytype, mkvp, &new_mk) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } rv = cca_reencipher_created_key(tokdata, priv_tmpl, priv_key_token, priv_key_token_length, new_mk, keytype, FALSE); if (rv != CKR_OK) { TRACE_ERROR("cca_reencipher_created_key failed: 0x%lx\n", rv); return rv; } TRACE_DEVEL("ECC secure private key token generated. size: %ld\n", priv_key_token_length); rule_array_count = 0; publ_key_token_length = CCA_KEY_TOKEN_SIZE; USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNDPKX(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &priv_key_token_length, priv_key_token, &publ_key_token_length, publ_key_token); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKX (PUBLIC KEY TOKEN EXTRACT) failed. return:%ld," " reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } TRACE_DEVEL("ECC secure public key token generated. size: %ld\n", publ_key_token_length); rv = token_create_ec_keypair(publ_tmpl, priv_tmpl, curve_type, priv_key_token_length, priv_key_token, publ_key_token_length, publ_key_token); if (rv != CKR_OK) { TRACE_DEVEL("token_create_ec_keypair failed. rv: %lu\n", rv); return rv; } TRACE_DEBUG("%s: priv template attributes:\n", __func__); TRACE_DEBUG_DUMPTEMPL(priv_tmpl); TRACE_DEBUG("%s: publ template attributes:\n", __func__); TRACE_DEBUG_DUMPTEMPL(publ_tmpl); return rv; } static CK_RV cca_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_MECHANISM *mech) { long return_code, reason_code, rule_array_count; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; long signature_bit_length; CK_ATTRIBUTE *attr; CK_RV rc; #ifdef NO_PKEY UNUSED(sess); #endif if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } /* Find the secure key token */ rc = template_attribute_get_non_empty(key_obj->template, CKA_IBM_OPAQUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_OPAQUE for the key.\n"); return rc; } #ifndef NO_PKEY /* CCA token protected key option: perform the function via CPACF */ rc = ccatok_pkey_check(tokdata, sess, key_obj, mech); switch (rc) { case CKR_OK: switch (mech->mechanism) { case CKM_ECDSA: rc = pkey_ec_sign(tokdata, sess, key_obj, in_data, in_data_len, out_data, out_data_len, NULL, ccatok_pkey_convert_key); goto done; case CKM_EDDSA: rc = pkey_ed_sign(tokdata, sess, key_obj, in_data, in_data_len, out_data, out_data_len, ccatok_pkey_convert_key); goto done; default: rc = CKR_MECHANISM_INVALID; goto done; } break; case CKR_FUNCTION_NOT_SUPPORTED: /* fallback */ break; default: goto done; } #endif /* NO_PKEY */ /* Fallback: Perform the function via the CCA card */ switch (mech->mechanism) { case CKM_ECDSA: rule_array_count = 1; memcpy(rule_array, "ECDSA ", CCA_KEYWORD_SIZE); *out_data_len = *out_data_len > 132 ? 132 : *out_data_len; break; case CKM_EDDSA: rule_array_count = 3; memcpy(rule_array, "EDDSA ED-HASH MESSAGE ", 3 * CCA_KEYWORD_SIZE); *out_data_len = *out_data_len > 144 ? 144 : *out_data_len; break; default: rc = CKR_MECHANISM_INVALID; goto done; } USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) RETRY_NEW_MK_BLOB_START() dll_CSNDDSG(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, (long *) &(attr->ulValueLen), attr->pValue, (long *) &in_data_len, in_data, (long *) out_data_len, &signature_bit_length, out_data); RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, attr->pValue, attr->ulValueLen) USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDDSG (EC SIGN) failed. return:%ld," " 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); } rc = CKR_OK; done: return rc; } static CK_RV cca_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_MECHANISM *mech) { long return_code, reason_code, rule_array_count; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; CK_ATTRIBUTE *attr; CK_RV rc; #ifdef NO_PKEY UNUSED(sess); #endif if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } /* Find the secure key token */ rc = template_attribute_get_non_empty(key_obj->template, CKA_IBM_OPAQUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_OPAQUE for the key.\n"); return rc; } #ifndef NO_PKEY /* CCA token protected key option: perform the function via CPACF */ rc = ccatok_pkey_check(tokdata, sess, key_obj, mech); switch (rc) { case CKR_OK: switch (mech->mechanism) { case CKM_ECDSA: rc = pkey_ec_verify(key_obj, in_data, in_data_len, out_data, out_data_len); goto done; case CKM_EDDSA: rc = pkey_ed_verify(key_obj, in_data, in_data_len, out_data, out_data_len, CKK_EC_EDWARDS); goto done; default: rc = CKR_MECHANISM_INVALID; goto done; } break; case CKR_FUNCTION_NOT_SUPPORTED: /* fallback */ break; default: goto done; } #endif /* NO_PKEY */ /* Fallback: Perform the function via the CCA card */ switch (mech->mechanism) { case CKM_ECDSA: rule_array_count = 1; memcpy(rule_array, "ECDSA ", CCA_KEYWORD_SIZE); break; case CKM_EDDSA: rule_array_count = 3; memcpy(rule_array, "EDDSA ED-HASH MESSAGE ", 3 * CCA_KEYWORD_SIZE); break; default: rc = CKR_MECHANISM_INVALID; goto done; } USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) RETRY_NEW_MK_BLOB_START() dll_CSNDDSV(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, (long *) &(attr->ulValueLen), attr->pValue, (long *) &in_data_len, in_data, (long *) &out_data_len, out_data); RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, attr->pValue, attr->ulValueLen) USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code == 4 && reason_code == 429) { return CKR_SIGNATURE_INVALID; } else if (return_code == 12 && reason_code == 769) { 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); } rc = CKR_OK; done: return rc; } 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) { CK_MECHANISM mech = { CKM_ECDSA, NULL, 0 }; return cca_ec_sign(tokdata, sess, in_data, in_data_len, out_data, out_data_len, key_obj, &mech); } 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) { CK_MECHANISM mech = { CKM_ECDSA, NULL, 0 }; return cca_ec_verify(tokdata, sess, in_data, in_data_len, out_data, out_data_len, key_obj, &mech); } CK_RV token_specific_ec_edwards_generate_keypair(STDLL_TokData_t *tokdata, TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl) { return token_specific_ec_generate_keypair(tokdata, publ_tmpl, priv_tmpl); } static CK_RV cca_check_ec_edwards_mech_param(STDLL_TokData_t *tokdata, OBJECT *key_obj, CK_MECHANISM *mech) { CK_EDDSA_PARAMS* eddsa_params = NULL; uint8_t curve_type; uint16_t curve_bitlen; int curve_nid; CK_RV rc; if (mech->ulParameterLen == sizeof(CK_EDDSA_PARAMS) && mech->pParameter != NULL) { eddsa_params = mech->pParameter; if (eddsa_params->ulContextDataLen != 0 || eddsa_params->pContextData != NULL) { TRACE_ERROR("CCA does not support a non-empty context\n"); return CKR_MECHANISM_PARAM_INVALID; } if (eddsa_params->phFlag) { TRACE_ERROR("CCA does not support pre-hash\n"); return CKR_MECHANISM_PARAM_INVALID; } } /* Check if curve supported and determine curve type and bitlen */ rc = curve_supported(tokdata, key_obj->template, &curve_type, &curve_bitlen, &curve_nid); if (rc != CKR_OK) { TRACE_ERROR("Curve not supported by this token.\n"); return rc; } switch (curve_nid) { case NID_ED25519: break; case NID_ED448: if (eddsa_params == NULL) { TRACE_ERROR("Mechanism parameter is required for Ed448\n"); return CKR_MECHANISM_PARAM_INVALID; } break; default: TRACE_ERROR("Not an edwards curve.\n"); return CKR_CURVE_NOT_SUPPORTED; } return CKR_OK; } CK_RV token_specific_ec_edwards_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_MECHANISM *mech) { CK_RV rc; rc = cca_check_ec_edwards_mech_param(tokdata, key_obj, mech); if (rc != CKR_OK) return rc; return cca_ec_sign(tokdata, sess, in_data, in_data_len, out_data, out_data_len, key_obj, mech); } CK_RV token_specific_ec_edwards_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, CK_MECHANISM * mech) { CK_RV rc; rc = cca_check_ec_edwards_mech_param(tokdata, key_obj, mech); if (rc != CKR_OK) return rc; return cca_ec_verify(tokdata, sess, in_data, in_data_len, signature, signature_len, key_obj, mech); } static CK_BBOOL cca_is_sha3_mech(CK_MECHANISM *mech) { switch (mech->mechanism) { case CKM_SHA3_224: case CKM_SHA3_256: case CKM_SHA3_384: case CKM_SHA3_512: case CKM_IBM_SHA3_224: case CKM_IBM_SHA3_256: case CKM_IBM_SHA3_384: case CKM_IBM_SHA3_512: case CKM_SHA3_224_RSA_PKCS: case CKM_SHA3_256_RSA_PKCS: case CKM_SHA3_384_RSA_PKCS: case CKM_SHA3_512_RSA_PKCS: case CKM_ECDSA_SHA3_224: case CKM_ECDSA_SHA3_256: case CKM_ECDSA_SHA3_384: case CKM_ECDSA_SHA3_512: return CK_TRUE; default: return CK_FALSE; } } 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; CK_RV rc; if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } rc = get_sha_size(mech->mechanism, &hash_size); if (rc != CKR_OK) { TRACE_ERROR("get_sha_size failed\n"); return rc; } if (cca_is_sha3_mech(mech) && !cca_sha3_supported(tokdata)) { TRACE_ERROR("SHA-3 mechanism is not supported due to CCA version\n"); 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_is_sha3_mech(mech) ? CCA_CHAIN_VECTOR_SHA3_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, }; if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } 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; case CKM_SHA3_224: case CKM_IBM_SHA3_224: memcpy(rule_array, "SHA3-224ONLY ", CCA_KEYWORD_SIZE * 2); cca_ctx->part = CCA_HASH_PART_ONLY; break; case CKM_SHA3_256: case CKM_IBM_SHA3_256: memcpy(rule_array, "SHA3-256ONLY ", CCA_KEYWORD_SIZE * 2); cca_ctx->part = CCA_HASH_PART_ONLY; break; case CKM_SHA3_384: case CKM_IBM_SHA3_384: memcpy(rule_array, "SHA3-384ONLY ", CCA_KEYWORD_SIZE * 2); cca_ctx->part = CCA_HASH_PART_ONLY; break; case CKM_SHA3_512: case CKM_IBM_SHA3_512: memcpy(rule_array, "SHA3-512ONLY ", CCA_KEYWORD_SIZE * 2); cca_ctx->part = CCA_HASH_PART_ONLY; break; default: return CKR_MECHANISM_INVALID; } if (cca_is_sha3_mech(&ctx->mech) && !cca_sha3_supported(tokdata)) { TRACE_ERROR("SHA-3 mechanism is not supported due to CCA version\n"); return CKR_MECHANISM_INVALID; } USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNBOWH(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, (long int *)&in_data_len, in_data, &cca_ctx->chain_vector_len, cca_ctx->chain_vector, &cca_ctx->hash_len, cca_ctx->hash); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBOWH failed. return:%ld, reason:%ld\n", 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; CK_ULONG blocksz; int use_buffer = 0; if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } if (!in_data) return CKR_ARGUMENTS_BAD; if (!ctx || !ctx->context) return CKR_OPERATION_NOT_INITIALIZED; rc = get_sha_block_size(ctx->mech.mechanism, &blocksz); if (rc != CKR_OK) { TRACE_ERROR("get_sha_block_size failed\n"); return rc; } if (cca_is_sha3_mech(&ctx->mech) && !cca_sha3_supported(tokdata)) { TRACE_ERROR("SHA-3 mechanism is not supported due to CCA version\n"); 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) == 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 >= (long)blocksz) { int remainder; remainder = total % blocksz; 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; case CKM_SHA3_224: case CKM_IBM_SHA3_224: if (cca_ctx->part == CCA_HASH_PART_FIRST) { memcpy(rule_array, "SHA3-224FIRST ", CCA_KEYWORD_SIZE * 2); cca_ctx->part = CCA_HASH_PART_MIDDLE; } else { memcpy(rule_array, "SHA3-224MIDDLE ", CCA_KEYWORD_SIZE * 2); } break; case CKM_SHA3_256: case CKM_IBM_SHA3_256: if (cca_ctx->part == CCA_HASH_PART_FIRST) { memcpy(rule_array, "SHA3-256FIRST ", CCA_KEYWORD_SIZE * 2); cca_ctx->part = CCA_HASH_PART_MIDDLE; } else { memcpy(rule_array, "SHA3-256MIDDLE ", CCA_KEYWORD_SIZE * 2); } break; case CKM_SHA3_384: case CKM_IBM_SHA3_384: if (cca_ctx->part == CCA_HASH_PART_FIRST) { memcpy(rule_array, "SHA3-384FIRST ", CCA_KEYWORD_SIZE * 2); cca_ctx->part = CCA_HASH_PART_MIDDLE; } else { memcpy(rule_array, "SHA3-384MIDDLE ", CCA_KEYWORD_SIZE * 2); } break; case CKM_SHA3_512: case CKM_IBM_SHA3_512: if (cca_ctx->part == CCA_HASH_PART_FIRST) { memcpy(rule_array, "SHA3-512FIRST ", CCA_KEYWORD_SIZE * 2); cca_ctx->part = CCA_HASH_PART_MIDDLE; } else { memcpy(rule_array, "SHA3-512MIDDLE ", CCA_KEYWORD_SIZE * 2); } break; } USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNBOWH(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, use_buffer ? &buffer_len : (long *) &in_data_len, use_buffer ? buffer : in_data, &cca_ctx->chain_vector_len, cca_ctx->chain_vector, &cca_ctx->hash_len, cca_ctx->hash); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBOWH (SHA UPDATE) failed. return:%ld," " 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, }; if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } 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; case CKM_SHA3_224: case CKM_IBM_SHA3_224: if (cca_ctx->part == CCA_HASH_PART_FIRST) { memcpy(rule_array, "SHA3-224ONLY ", CCA_KEYWORD_SIZE * 2); } else { /* there's some extra data we need to hash to * complete the operation */ memcpy(rule_array, "SHA3-224LAST ", CCA_KEYWORD_SIZE * 2); } break; case CKM_SHA3_256: case CKM_IBM_SHA3_256: if (cca_ctx->part == CCA_HASH_PART_FIRST) { memcpy(rule_array, "SHA3-256ONLY ", CCA_KEYWORD_SIZE * 2); } else { /* there's some extra data we need to hash to * complete the operation */ memcpy(rule_array, "SHA3-256LAST ", CCA_KEYWORD_SIZE * 2); } break; case CKM_SHA3_384: case CKM_IBM_SHA3_384: if (cca_ctx->part == CCA_HASH_PART_FIRST) { memcpy(rule_array, "SHA3-384ONLY ", CCA_KEYWORD_SIZE * 2); } else { /* there's some extra data we need to hash to * complete the operation */ memcpy(rule_array, "SHA3-384LAST ", CCA_KEYWORD_SIZE * 2); } break; case CKM_SHA3_512: case CKM_IBM_SHA3_512: if (cca_ctx->part == CCA_HASH_PART_FIRST) { memcpy(rule_array, "SHA3-512ONLY ", CCA_KEYWORD_SIZE * 2); } else { /* there's some extra data we need to hash to * complete the operation */ memcpy(rule_array, "SHA3-512LAST ", CCA_KEYWORD_SIZE * 2); } break; default: return CKR_MECHANISM_INVALID; } if (cca_is_sha3_mech(&ctx->mech) && !cca_sha3_supported(tokdata)) { TRACE_ERROR("SHA-3 mechanism is not supported due to CCA version\n"); 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); USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNBOWH(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &cca_ctx->tail_len, cca_ctx->tail, &cca_ctx->chain_vector_len, cca_ctx->chain_vector, &cca_ctx->hash_len, cca_ctx->hash); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBOWH (SHA FINAL) failed. return:%ld," " 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) { if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } 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) { if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } 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 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; } rc = template_attribute_get_non_empty(key->template, CKA_IBM_OPAQUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_OPAQUE for the key.\n"); 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("The mac length is %ld\n", cca_ctx->hash_len); if (sign) { USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) RETRY_NEW_MK_BLOB_START() dll_CSNBHMG(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, (long int *)&attr->ulValueLen, attr->pValue, (long int *)&in_data_len, in_data, &cca_ctx->chain_vector_len, cca_ctx->chain_vector, &cca_ctx->hash_len, cca_ctx->hash); RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, attr->pValue, attr->ulValueLen) USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBHMG (HMAC GENERATE) failed. " "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 USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) RETRY_NEW_MK_BLOB_START() dll_CSNBHMV(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, (long int *)&attr->ulValueLen, attr->pValue, (long int *)&in_data_len, in_data, &cca_ctx->chain_vector_len, cca_ctx->chain_vector, &cca_ctx->hash_len, signature); RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, attr->pValue, attr->ulValueLen) USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code == 4 && (reason_code == 429 || reason_code == 1)) { TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID)); 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) { if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } 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) { if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } 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; CK_ULONG blocksz; int use_buffer = 0; OBJECT *key = NULL; CK_ATTRIBUTE *attr = NULL; CK_MECHANISM_TYPE sha_mech; CK_BBOOL generic; 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; } rc = template_attribute_get_non_empty(key->template, CKA_IBM_OPAQUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_OPAQUE for the key.\n"); goto done; } rc = get_hmac_digest(ctx->mech.mechanism, &sha_mech, &generic); if (rc != CKR_OK) { TRACE_ERROR("get_hmac_digest failed\n"); goto done; } rc = get_sha_block_size(sha_mech, &blocksz); if (rc != CKR_OK) { TRACE_ERROR("get_sha_block_size failed\n"); 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) == 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 >= (long)blocksz) { int remainder; remainder = total % blocksz; // 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) { USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) RETRY_NEW_MK_BLOB_START() dll_CSNBHMG(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, (long int *)&attr->ulValueLen, attr->pValue, use_buffer ? &buffer_len : (long int *) &in_data_len, use_buffer ? buffer : in_data, &cca_ctx->chain_vector_len, cca_ctx->chain_vector, &hsize, cca_ctx->hash); RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, attr->pValue, attr->ulValueLen) USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBHMG (HMAC SIGN UPDATE) failed. " "return:%ld, reason:%ld\n", return_code, reason_code); rc = CKR_FUNCTION_FAILED; } } else { // verify USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) RETRY_NEW_MK_BLOB_START() dll_CSNBHMV(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, (long int *)&attr->ulValueLen, attr->pValue, use_buffer ? &buffer_len : (long int *) &in_data_len, use_buffer ? buffer : in_data, &cca_ctx->chain_vector_len, cca_ctx->chain_vector, &hsize, cca_ctx->hash); RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, attr->pValue, attr->ulValueLen) USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBHMG (HMAC VERIFY UPDATE) failed. " "return:%ld, reason:%ld\n", return_code, reason_code); 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) { if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } 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) { if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } 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; } rc = template_attribute_get_non_empty(key->template, CKA_IBM_OPAQUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_OPAQUE for the key.\n"); 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) { USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) RETRY_NEW_MK_BLOB_START() dll_CSNBHMG(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, (long int *)&attr->ulValueLen, attr->pValue, &cca_ctx->tail_len, cca_ctx->tail, &cca_ctx->chain_vector_len, cca_ctx->chain_vector, &cca_ctx->hash_len, cca_ctx->hash); RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, attr->pValue, attr->ulValueLen) USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBHMG (HMAC SIGN FINAL) failed. " "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 USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) RETRY_NEW_MK_BLOB_START() dll_CSNBHMV(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, (long int *)&attr->ulValueLen, attr->pValue, &cca_ctx->tail_len, cca_ctx->tail, &cca_ctx->chain_vector_len, cca_ctx->chain_vector, &cca_ctx->hash_len, signature); RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, attr->pValue, attr->ulValueLen) USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code == 4 && (reason_code == 429 || reason_code == 1)) { TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID)); 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) { if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } 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) { if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } return ccatok_hmac_final(tokdata, &sess->verify_ctx, signature, &sig_len, FALSE); } static CK_RV token_create_pqc_keypair(CK_MECHANISM_TYPE mech, CK_IBM_CCA_ML_DSA_KEY_MODE_TYPE mode, TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl, const struct pqc_oid *oid, CK_ULONG priv_tok_len, CK_BYTE *priv_tok, CK_ULONG publ_tok_len, CK_BYTE *publ_tok) { CK_RV rc; uint16_t publsec_len, rho_len, t1_len, pk_len, seed_len; CK_BYTE *spki = NULL; CK_ULONG spki_len = 0; CK_KEY_TYPE keytype; switch (mech) { case CKM_IBM_DILITHIUM: keytype = CKK_IBM_PQC_DILITHIUM; break; case CKM_IBM_ML_DSA_KEY_PAIR_GEN: keytype = CKK_IBM_ML_DSA; break; case CKM_IBM_ML_KEM_KEY_PAIR_GEN: keytype = CKK_IBM_ML_KEM; break; case CKM_ML_DSA_KEY_PAIR_GEN: keytype = CKK_ML_DSA; break; default: return CKR_MECHANISM_INVALID; } publsec_len = be16toh(*((uint16_t *) (publ_tok + CCA_QSA_EXTTOK_PUBLKEY_OFFSET + 2))); if (CCA_QSA_EXTTOK_PUBLKEY_OFFSET + publsec_len > (int)publ_tok_len) { TRACE_ERROR("CCA QSA key token has invalid publ section len or " "token size\n"); return CKR_FUNCTION_FAILED; } switch (mech) { case CKM_IBM_DILITHIUM: case CKM_IBM_ML_DSA_KEY_PAIR_GEN: case CKM_ML_DSA_KEY_PAIR_GEN: rho_len = be16toh(*((uint16_t *)(publ_tok + CCA_QSA_EXTTOK_PUBLKEY_OFFSET + CCA_QSA_EXTTOK_RHO_OFFSET))); t1_len = be16toh(*((uint16_t *)(publ_tok + CCA_QSA_EXTTOK_PUBLKEY_OFFSET + CCA_QSA_EXTTOK_T1_OFFSET))); if (rho_len != oid->len_info.ml_dsa.rho_len || t1_len != oid->len_info.ml_dsa.t1_len) { TRACE_ERROR("CCA QSA key token has invalid key component length\n"); return CKR_FUNCTION_FAILED; } break; case CKM_IBM_ML_KEM_KEY_PAIR_GEN: pk_len = be16toh(*((uint16_t *)(publ_tok + CCA_QSA_EXTTOK_PUBLKEY_OFFSET + CCA_QSA_EXTTOK_PK_OFFSET))); seed_len = be16toh(*((uint16_t *)(publ_tok + CCA_QSA_EXTTOK_PUBLKEY_OFFSET + CCA_QSA_EXTTOK_SEED_OFFSET))); if (pk_len + seed_len != oid->len_info.ml_kem.pk_len) { TRACE_ERROR("CCA QSA key token has invalid key component length\n"); return CKR_FUNCTION_FAILED; } break; default: return CKR_MECHANISM_INVALID; } /* Add public attributes to private and public template */ rc = pqc_unpack_pub_key(publ_tok + CCA_QSA_EXTTOK_PUBLKEY_OFFSET + CCA_QSA_EXTTOK_PAYLOAD_OFFSET, publ_tok_len - CCA_QSA_EXTTOK_PUBLKEY_OFFSET - CCA_QSA_EXTTOK_PAYLOAD_OFFSET, oid, mech, publ_tmpl); if (rc != CKR_OK) { TRACE_ERROR("pqc_unpack_pub_key failed\n"); return rc; } switch (mech) { case CKM_IBM_DILITHIUM: case CKM_IBM_ML_DSA_KEY_PAIR_GEN: case CKM_IBM_ML_KEM_KEY_PAIR_GEN: rc = pqc_unpack_pub_key(publ_tok + CCA_QSA_EXTTOK_PUBLKEY_OFFSET + CCA_QSA_EXTTOK_PAYLOAD_OFFSET, publ_tok_len - CCA_QSA_EXTTOK_PUBLKEY_OFFSET - CCA_QSA_EXTTOK_PAYLOAD_OFFSET, oid, mech, priv_tmpl); if (rc != CKR_OK) { TRACE_ERROR("pqc_unpack_pub_key failed\n"); return rc; } break; default: break; } /* Add keyform and mode attributes to public and private template */ rc = pqc_add_keyform_mode(publ_tmpl, oid, mech); if (rc != CKR_OK) { TRACE_ERROR("pqc_add_keyform_mode failed\n"); return rc; } rc = pqc_add_keyform_mode(priv_tmpl, oid, mech); if (rc != CKR_OK) { TRACE_ERROR("pqc_add_keyform_mode failed\n"); return rc; } switch (mech) { case CKM_ML_DSA_KEY_PAIR_GEN: /* Add ML-DSA mode attributes to public and private template */ rc = build_update_attribute(publ_tmpl, CKA_IBM_CCA_ML_DSA_KEY_MODE, (CK_BYTE *)&mode, sizeof(mode)); if (rc != CKR_OK) { TRACE_ERROR("build_update_attribute for publ failed rv=0x%lx\n", rc); return rc; } rc = build_update_attribute(priv_tmpl, CKA_IBM_CCA_ML_DSA_KEY_MODE, (CK_BYTE *)&mode, sizeof(mode)); if (rc != CKR_OK) { TRACE_ERROR("build_update_attribute for priv failed rv=0x%lx\n", rc); return rc; } break; default: /* Add SPKI as CKA_VALUE to public template */ rc = pqc_publ_get_spki(publ_tmpl, keytype, FALSE, &spki, &spki_len, FALSE); if (rc != CKR_OK) { TRACE_ERROR("pqc_publ_get_spki failed\n"); return rc; } rc = build_update_attribute(publ_tmpl, CKA_VALUE, spki, spki_len); free(spki); if (rc != CKR_OK) { TRACE_ERROR("build_update_attribute for CKA_VALUE failed rv=0x%lx\n", rc); return rc; } break; } /* store publ key token into CKA_IBM_OPAQUE of the public key object */ rc = build_update_attribute(publ_tmpl, CKA_IBM_OPAQUE, publ_tok, publ_tok_len); if (rc != CKR_OK) { TRACE_ERROR("build_update_attribute for publ_tok failed rv=0x%lx\n", rc); return rc; } /* store priv key token into CKA_IBM_OPAQUE of the private key object */ rc = build_update_attribute(priv_tmpl, CKA_IBM_OPAQUE, priv_tok, priv_tok_len); if (rc != CKR_OK) { TRACE_ERROR("build_update_attribute for priv_tok failed rv=0x%lx\n", rc); return rc; } return CKR_OK; } static CK_RV token_create_pqc_privkey(CK_MECHANISM_TYPE mech, TEMPLATE *priv_tmpl, const struct pqc_oid *oid, CK_ULONG priv_tok_len, CK_BYTE *priv_tok) { CK_RV rc; uint16_t privsec_len, publsec_len, rho_len, t1_len, pk_len, seed_len; CK_BYTE *publ_sec; CK_BYTE *spki = NULL; CK_ULONG spki_len = 0; privsec_len = be16toh(*(uint16_t *)&priv_tok[CCA_QSA_INTTOK_PRIVKEY_OFFSET + CCA_SECTION_LEN_OFFSET]); publ_sec = &priv_tok[CCA_QSA_INTTOK_PRIVKEY_OFFSET + privsec_len]; publsec_len = be16toh(*((uint16_t *)(publ_sec + CCA_SECTION_LEN_OFFSET))); if (CCA_QSA_INTTOK_PRIVKEY_OFFSET + privsec_len + publsec_len > (int)priv_tok_len) { TRACE_ERROR("CCA QSA key token has invalid publ section len or " "token size\n"); return CKR_FUNCTION_FAILED; } switch (mech) { case CKM_IBM_DILITHIUM: case CKM_IBM_ML_DSA_KEY_PAIR_GEN: case CKM_ML_DSA_KEY_PAIR_GEN: rho_len = be16toh(*((uint16_t *)(publ_sec + CCA_QSA_EXTTOK_RHO_OFFSET))); t1_len = be16toh(*((uint16_t *)(publ_sec + CCA_QSA_EXTTOK_T1_OFFSET))); if (rho_len != oid->len_info.ml_dsa.rho_len || t1_len != oid->len_info.ml_dsa.t1_len) { TRACE_ERROR("CCA QSA key token has invalid key component length\n"); return CKR_FUNCTION_FAILED; } break; case CKM_IBM_ML_KEM_KEY_PAIR_GEN: pk_len = be16toh(*((uint16_t *)(publ_sec + CCA_QSA_EXTTOK_PK_OFFSET))); seed_len = be16toh(*((uint16_t *)(publ_sec + CCA_QSA_EXTTOK_SEED_OFFSET))); if (pk_len + seed_len != oid->len_info.ml_kem.pk_len) { TRACE_ERROR("CCA QSA key token has invalid key component length\n"); return CKR_FUNCTION_FAILED; } break; default: return CKR_MECHANISM_INVALID; } switch (mech) { case CKM_IBM_DILITHIUM: case CKM_IBM_ML_DSA_KEY_PAIR_GEN: case CKM_IBM_ML_KEM_KEY_PAIR_GEN: /* Add public attributes to private template */ rc = pqc_unpack_pub_key(publ_sec + CCA_QSA_EXTTOK_PAYLOAD_OFFSET, publsec_len - CCA_QSA_EXTTOK_PAYLOAD_OFFSET, oid, mech, priv_tmpl); if (rc != CKR_OK) { TRACE_ERROR("pqc_unpack_pub_key failed\n"); return rc; } break; case CKM_ML_DSA_KEY_PAIR_GEN: /* Try to add SPKI as CKA_PUBLIC_KEY_INFO to private template */ rc = pqc_publ_get_spki(priv_tmpl, CKK_ML_DSA, FALSE, &spki, &spki_len, TRUE); if (rc == CKR_OK) { rc = build_update_attribute(priv_tmpl, CKA_PUBLIC_KEY_INFO, spki, spki_len); free(spki); if (rc != CKR_OK) { TRACE_ERROR("build_update_attribute for CKA_PUBLIC_KEY_INFO" " failed rv=0x%lx\n", rc); return rc; } } break; default: break; } /* Add keyform and mode attributes to private template */ rc = pqc_add_keyform_mode(priv_tmpl, oid, mech); if (rc != CKR_OK) { TRACE_ERROR("pqc_add_keyform_mode failed\n"); return rc; } /* store priv key token into CKA_IBM_OPAQUE of the private key object */ rc = build_update_attribute(priv_tmpl, CKA_IBM_OPAQUE, priv_tok, priv_tok_len); if (rc != CKR_OK) { TRACE_ERROR("build_update_attribute for priv_tok failed rv=0x%lx\n", rc); return rc; } return CKR_OK; } static CK_RV build_pqc_key_value_struct(CK_MECHANISM_TYPE mech, CK_IBM_CCA_ML_DSA_KEY_MODE_TYPE mode, const struct pqc_oid *oid, unsigned char *key_value_structure, long *key_value_structure_length) { uint8_t algo_id, format = CCA_QSA_CLEAR_FORMAT_NO_KEY; uint16_t algo_param, clear_len = 0; if (*key_value_structure_length < CCA_QSA_KEY_VALUE_STRUCT_SIZE) return CKR_ARGUMENTS_BAD; switch (mech) { case CKM_IBM_DILITHIUM: switch (oid->keyform) { case CK_IBM_DILITHIUM_KEYFORM_ROUND2_65: algo_id = CCA_QSA_ALGO_DILITHIUM_ROUND_2; algo_param = htobe16(CCA_QSA_ALGO_DILITHIUM_65); break; case CK_IBM_DILITHIUM_KEYFORM_ROUND2_87: algo_id = CCA_QSA_ALGO_DILITHIUM_ROUND_2; algo_param = htobe16(CCA_QSA_ALGO_DILITHIUM_87); break; case CK_IBM_DILITHIUM_KEYFORM_ROUND3_65: algo_id = CCA_QSA_ALGO_DILITHIUM_ROUND_3; algo_param = htobe16(CCA_QSA_ALGO_DILITHIUM_65); break; case CK_IBM_DILITHIUM_KEYFORM_ROUND3_87: algo_id = CCA_QSA_ALGO_DILITHIUM_ROUND_3; algo_param = htobe16(CCA_QSA_ALGO_DILITHIUM_87); break; default: TRACE_DEVEL("Dilithium keyform %lu not supported by CCA\n", oid->keyform); return CKR_KEY_SIZE_RANGE; } break; case CKM_IBM_ML_DSA_KEY_PAIR_GEN: case CKM_ML_DSA_KEY_PAIR_GEN: if (mech == CKM_ML_DSA_KEY_PAIR_GEN) { switch (mode) { case CK_IBM_CCA_ML_DSA_PURE_KEY: algo_id = CCA_QSA_ALGO_ML_DSA_PURE; break; case CK_IBM_CCA_ML_DSA_PREHASH_KEY: algo_id = CCA_QSA_ALGO_ML_DSA_PRE_HASH; break; default: TRACE_DEVEL("ML-DSA mode %lu not supported by CCA\n", mode); return CKR_ATTRIBUTE_VALUE_INVALID; } } else { algo_id = CCA_QSA_ALGO_ML_DSA_PURE; } switch (oid->keyform) { case CKP_ML_DSA_44: algo_param = htobe16(CCA_QSA_ALGO_ML_DSA_44); break; case CKP_ML_DSA_65: algo_param = htobe16(CCA_QSA_ALGO_ML_DSA_65); break; case CKP_ML_DSA_87: algo_param = htobe16(CCA_QSA_ALGO_ML_DSA_87); break; default: TRACE_DEVEL("ML-DSA keyform %lu not supported by CCA\n", oid->keyform); return CKR_KEY_SIZE_RANGE; } break; case CKM_IBM_ML_KEM_KEY_PAIR_GEN: algo_id = CCA_QSA_ALGO_ML_KEM; switch (oid->keyform) { case CKP_IBM_ML_KEM_512: algo_param = htobe16(CCA_QSA_ALGO_ML_KEM_512); break; case CKP_IBM_ML_KEM_768: algo_param = htobe16(CCA_QSA_ALGO_ML_KEM_768); break; case CKP_IBM_ML_KEM_1024: algo_param = htobe16(CCA_QSA_ALGO_ML_KEM_1024); break; default: TRACE_DEVEL("ML-KEM keyform %lu not supported by CCA\n", oid->keyform); return CKR_KEY_SIZE_RANGE; } break; default: return CKR_MECHANISM_INVALID; } /* * See CCA doc for offset of data in key_value_structure */ memcpy(key_value_structure, &algo_id, sizeof(uint8_t)); memcpy(&key_value_structure[CCA_PKB_QSA_CLEAR_FORMAT_OFFSET], &format, sizeof(uint8_t)); memcpy(&key_value_structure[CCA_PKB_QSA_ALGO_PARAM_OFFSET], &algo_param, sizeof(uint16_t)); memcpy(&key_value_structure[CCA_PKB_QSA_CLEAR_LEN_OFFSET], &clear_len, sizeof(uint16_t)); *key_value_structure_length = CCA_QSA_KEY_VALUE_STRUCT_SIZE; return CKR_OK; } static CK_RV ccatok_pqc_generate_keypair(STDLL_TokData_t *tokdata, CK_MECHANISM *mech, const struct pqc_oid *oid, 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_QSA_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; long priv_key_token_length, publ_key_token_length; unsigned char regeneration_data[CCA_REGENERATION_DATA_SIZE] = { 0, }; unsigned char transport_key_identifier[CCA_KEY_ID_SIZE] = { 0, }; unsigned char priv_key_token[CCA_KEY_TOKEN_SIZE] = { 0, }; unsigned char publ_key_token[CCA_KEY_TOKEN_SIZE] = { 0, }; CK_RV rv; long param1 = 0; unsigned char *param2 = NULL; enum cca_token_type keytype; unsigned int keybitsize; const CK_BYTE *mkvp; CK_BBOOL new_mk; CK_IBM_CCA_ML_DSA_KEY_MODE_TYPE mode = CK_IBM_CCA_ML_DSA_PURE_KEY; if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } if (!cca_pqc_strength_supported(tokdata, mech->mechanism, oid->keyform)) { TRACE_DEVEL("PQC keyform %lu not supported by CCA\n", oid->keyform); return CKR_KEY_SIZE_RANGE; } switch (mech->mechanism) { case CKM_ML_DSA_KEY_PAIR_GEN: rv = cca_get_and_set_ml_dsa_key_mode(tokdata, priv_tmpl, &mode); if (rv != CKR_OK) { TRACE_ERROR("cca_get_and_set_ml_dsa_key_mode failed: 0x%lx\n", rv); return rv; } break; default: break; } key_value_structure_length = CCA_QSA_KEY_VALUE_STRUCT_SIZE; rv = build_pqc_key_value_struct(mech->mechanism, mode, oid, key_value_structure, &key_value_structure_length); if (rv != CKR_OK) { TRACE_ERROR("build_pqc_key_value_struct failed: 0x%lx\n", rv); return rv; } switch (mech->mechanism) { case CKM_IBM_DILITHIUM: case CKM_IBM_ML_DSA_KEY_PAIR_GEN: case CKM_ML_DSA_KEY_PAIR_GEN: rule_array_count = 2; memcpy(rule_array, "QSA-PAIRU-DIGSIG", (size_t) (CCA_KEYWORD_SIZE * 2)); break; case CKM_IBM_ML_KEM_KEY_PAIR_GEN: rule_array_count = 2; memcpy(rule_array, "QSA-PAIRU-DATENC", (size_t) (CCA_KEYWORD_SIZE * 2)); break; default: return CKR_MECHANISM_INVALID; } private_key_name_length = 0; key_token_length = CCA_KEY_TOKEN_SIZE; USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNDPKB(&return_code, &reason_code, &exit_data_len, exit_data, &rule_array_count, rule_array, &key_value_structure_length, key_value_structure, &private_key_name_length, private_key_name, ¶m1, param2, ¶m1, param2, ¶m1, param2, ¶m1, param2, ¶m1, param2, &key_token_length, key_token); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKB (QSA KEY TOKEN BUILD) failed. return:%ld," " reason:%ld\n", return_code, reason_code); if (return_code == 8 && reason_code == 998) return CKR_KEY_SIZE_RANGE; return CKR_FUNCTION_FAILED; } rule_array_count = 1; memset(rule_array, 0, sizeof(rule_array)); memcpy(rule_array, "MASTER ", (size_t) CCA_KEYWORD_SIZE); priv_key_token_length = CCA_KEY_TOKEN_SIZE; regeneration_data_length = 0; USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNDPKG(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, ®eneration_data_length, regeneration_data, &key_token_length, key_token, transport_key_identifier, &priv_key_token_length, priv_key_token); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKG (QSA KEY GENERATE) failed." " return:%ld, reason:%ld\n", return_code, reason_code); if (return_code == 8 && reason_code == 998) return CKR_KEY_SIZE_RANGE; return CKR_FUNCTION_FAILED; } if (analyse_cca_key_token(priv_key_token, priv_key_token_length, &keytype, &keybitsize, &mkvp) == FALSE || mkvp == NULL) { TRACE_ERROR("Invalid/unknown cca token has been generated\n"); return CKR_FUNCTION_FAILED; } if (check_expected_mkvp(tokdata, keytype, mkvp, &new_mk) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } rv = cca_reencipher_created_key(tokdata, priv_tmpl, priv_key_token, priv_key_token_length, new_mk, keytype, FALSE); if (rv != CKR_OK) { TRACE_ERROR("cca_reencipher_created_key failed: 0x%lx\n", rv); return rv; } TRACE_DEVEL("Secure QSA private key token generated. size: %ld\n", priv_key_token_length); rule_array_count = 0; publ_key_token_length = CCA_KEY_TOKEN_SIZE; USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNDPKX(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &priv_key_token_length, priv_key_token, &publ_key_token_length, publ_key_token); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKX (PUBLIC KEY TOKEN EXTRACT) failed. return:%ld," " reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } TRACE_DEVEL("Secure public QSA key token generated. size: %ld\n", publ_key_token_length); rv = token_create_pqc_keypair(mech->mechanism, mode, publ_tmpl, priv_tmpl, oid, priv_key_token_length, priv_key_token, publ_key_token_length, publ_key_token); if (rv != CKR_OK) { TRACE_DEVEL("token_create_pqc_keypair failed. rv: %lu\n", rv); return rv; } TRACE_DEBUG("%s: priv template attributes:\n", __func__); TRACE_DEBUG_DUMPTEMPL(priv_tmpl); TRACE_DEBUG("%s: publ template attributes:\n", __func__); TRACE_DEBUG_DUMPTEMPL(publ_tmpl); return rv; } CK_RV token_specific_ibm_ml_dsa_generate_keypair(STDLL_TokData_t *tokdata, CK_MECHANISM *mech, const struct pqc_oid *oid, TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl) { return ccatok_pqc_generate_keypair(tokdata, mech, oid, publ_tmpl, priv_tmpl); } CK_RV token_specific_ml_dsa_generate_keypair(STDLL_TokData_t *tokdata, const struct pqc_oid *oid, TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl) { CK_MECHANISM mech = { CKM_ML_DSA_KEY_PAIR_GEN, NULL, 0 }; return ccatok_pqc_generate_keypair(tokdata, &mech, oid, publ_tmpl, priv_tmpl); } static CK_RV check_ml_dsa_data_len(STDLL_TokData_t *tokdata, CK_MECHANISM_TYPE mech, const struct pqc_oid *oid, CK_ULONG in_data_len) { struct cca_private_data *cca_private = tokdata->private_data; const struct cca_version cca_v8_0 = { .ver = 8, .rel = 0, .mod = 0 }; CK_BBOOL is_CEX8; if (pthread_rwlock_rdlock(&cca_private->min_card_version_rwlock) != 0) { TRACE_ERROR("CCA min_card_version RD-Lock failed.\n"); return CKR_CANT_LOCK; } is_CEX8 = (compare_cca_version(&cca_private->cca_lib_version, &cca_v8_0) >= 0 && compare_cca_version(&cca_private->min_card_version, &cca_v8_0) >= 0); if (pthread_rwlock_unlock(&cca_private->min_card_version_rwlock) != 0) { TRACE_ERROR("CCA min_card_version RD-Unlock failed.\n"); return CKR_CANT_LOCK; } switch (mech) { case CKM_IBM_DILITHIUM: switch (oid->keyform) { case CK_IBM_DILITHIUM_KEYFORM_ROUND2_65: case CK_IBM_DILITHIUM_KEYFORM_ROUND3_65: if (in_data_len > (is_CEX8 ? CCA_MAX_CEX8_DILITHIUM_65_DATA_LEN : CCA_MAX_DILITHIUM_65_DATA_LEN)) { TRACE_DEVEL("Input too large for Dilithium keyform %lu\n", oid->keyform); return CKR_DATA_LEN_RANGE; } break; case CK_IBM_DILITHIUM_KEYFORM_ROUND2_87: case CK_IBM_DILITHIUM_KEYFORM_ROUND3_87: if (in_data_len > (is_CEX8 ? CCA_MAX_CEX8_DILITHIUM_87_DATA_LEN : CCA_MAX_DILITHIUM_87_DATA_LEN)) { TRACE_DEVEL("Input too large for Dilithium keyform %lu\n", oid->keyform); return CKR_DATA_LEN_RANGE; } break; default: TRACE_DEVEL("Dilithium keyform %lu not supported by CCA\n", oid->keyform); return CKR_KEY_SIZE_RANGE; } break; case CKM_IBM_ML_DSA: /* CEX8 or later only */ case CKM_ML_DSA: /* CEX8 or later only */ case CKM_HASH_ML_DSA: /* CEX8 or later only */ switch (oid->keyform) { case CKP_ML_DSA_44: if (in_data_len > CCA_MAX_CEX8_ML_DSA_44_DATA_LEN) { TRACE_DEVEL("Input too large for ML-DSA keyform %lu\n", oid->keyform); return CKR_DATA_LEN_RANGE; } break; case CKP_ML_DSA_65: if (in_data_len > CCA_MAX_CEX8_ML_DSA_65_DATA_LEN) { TRACE_DEVEL("Input too large for ML-DSA keyform %lu\n", oid->keyform); return CKR_DATA_LEN_RANGE; } break; case CKP_ML_DSA_87: if (in_data_len > CCA_MAX_CEX8_ML_DSA_87_DATA_LEN) { TRACE_DEVEL("Input too large for ML-DSA keyform %lu\n", oid->keyform); return CKR_DATA_LEN_RANGE; } break; default: TRACE_DEVEL("ML-DSA keyform %lu not supported by CCA\n", oid->keyform); return CKR_KEY_SIZE_RANGE; } break; default: return CKR_MECHANISM_INVALID; } return CKR_OK; } static CK_RV ccatok_ml_dsa_build_context_msg(CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *context, CK_ULONG context_len, CK_BYTE **context_msg, CK_ULONG *context_msg_len) { uint16_t ctx_len = htobe16(context_len); if (context_len > 255) { TRACE_ERROR("Context can only be up to 255 bytes\n"); return CKR_MECHANISM_PARAM_INVALID; } *context_msg_len = sizeof(ctx_len) + context_len + in_data_len; *context_msg = malloc(*context_msg_len); if (*context_msg == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); return CKR_HOST_MEMORY; } memcpy(*context_msg, &ctx_len, sizeof(ctx_len)); memcpy(*context_msg + sizeof(ctx_len), context, context_len); memcpy(*context_msg + sizeof(ctx_len) + context_len, in_data, in_data_len); return CKR_OK; } static CK_RV ccatok_ml_dsa_build_rule_array(CK_MECHANISM *mech, CK_BBOOL sign, OBJECT *key_obj, unsigned char* rule_array, long *rule_array_count, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE **context_msg, CK_ULONG *context_msg_len) { CK_SIGN_ADDITIONAL_CONTEXT sign_param = { CKH_HEDGE_PREFERRED, NULL, 0 }; CK_MECHANISM_TYPE hash_mech = 0; CK_IBM_CCA_ML_DSA_KEY_MODE_TYPE mode; CK_RV rc; /* Check if ML-DSA key mode fits to mechanism */ switch (mech->mechanism) { case CKM_ML_DSA: case CKM_HASH_ML_DSA: rc = template_attribute_get_ulong(key_obj->template, CKA_IBM_CCA_ML_DSA_KEY_MODE, &mode); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_CCA_ML_DSA_KEY_MODE for " "the key.\n"); return rc; } if ((mech->mechanism == CKM_ML_DSA && mode == CK_IBM_CCA_ML_DSA_PREHASH_KEY) || (mech->mechanism == CKM_HASH_ML_DSA && mode == CK_IBM_CCA_ML_DSA_PURE_KEY)) { TRACE_ERROR("The CCA key mode does not fit to the mechanism\n"); return CKR_KEY_TYPE_INCONSISTENT; } break; default: break; } /* Unify and translate mechanism parameter */ switch (mech->mechanism) { case CKM_IBM_DILITHIUM: break; case CKM_IBM_ML_DSA: if (mech->pParameter != NULL && mech->ulParameterLen != sizeof(CK_IBM_SIGN_ADDITIONAL_CONTEXT)) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); return CKR_MECHANISM_PARAM_INVALID; } rc = ml_dsa_translate_sign_mech_param_from_ibm(mech->pParameter, &sign_param); if (rc != CKR_OK) { TRACE_ERROR("ml_dsa_translate_sign_mech_param_from_ibm failed.\n"); return rc; } break; case CKM_ML_DSA: if (mech->pParameter != NULL && mech->ulParameterLen != sizeof(CK_SIGN_ADDITIONAL_CONTEXT)) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); return CKR_MECHANISM_PARAM_INVALID; } if (mech->pParameter != NULL) memcpy(&sign_param, mech->pParameter, sizeof(sign_param)); break; case CKM_HASH_ML_DSA: if (mech->pParameter == NULL || mech->ulParameterLen != sizeof(CK_HASH_SIGN_ADDITIONAL_CONTEXT)) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); return CKR_MECHANISM_PARAM_INVALID; } rc = ml_dsa_translate_sign_mech_param_from_hash(mech->pParameter, &sign_param, &hash_mech); if (rc != CKR_OK) { TRACE_ERROR("ml_dsa_translate_sign_mech_param_from_hash failed.\n"); return rc; } break; default: TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); return CKR_MECHANISM_INVALID; } /* Setup rule array according to mech */ switch (mech->mechanism) { case CKM_IBM_DILITHIUM: case CKM_IBM_ML_DSA: case CKM_ML_DSA: *rule_array_count = 3; memcpy(rule_array, "CRDL-DSAMESSAGE CRDLHASH", CCA_KEYWORD_SIZE * 3); break; case CKM_HASH_ML_DSA: *rule_array_count = 2; memcpy(rule_array, "CRDL-DSAHASH ", CCA_KEYWORD_SIZE * 2); switch (hash_mech) { case CKM_SHA512: memcpy(rule_array + (*rule_array_count * CCA_KEYWORD_SIZE), "SHA-512 ", CCA_KEYWORD_SIZE); (*rule_array_count)++; break; default: TRACE_ERROR("CCA only supports SHA-512 as prehash mechanism\n"); return CKR_MECHANISM_PARAM_INVALID; } break; default: break; } /* Process hedge type (for sign only) and context */ switch (mech->mechanism) { case CKM_IBM_ML_DSA: case CKM_ML_DSA: case CKM_HASH_ML_DSA: if (sign) { switch (sign_param.hedgeVariant) { case CKH_HEDGE_PREFERRED: case CKH_HEDGE_REQUIRED: memcpy(rule_array + (*rule_array_count * CCA_KEYWORD_SIZE), "NONDETER", CCA_KEYWORD_SIZE); (*rule_array_count)++; break; case CKH_DETERMINISTIC_REQUIRED: memcpy(rule_array + (*rule_array_count * CCA_KEYWORD_SIZE), "DETER ", CCA_KEYWORD_SIZE); (*rule_array_count)++; break; default: TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); return CKR_MECHANISM_PARAM_INVALID; } } if (sign_param.pContext != NULL && sign_param.ulContextLen > 0) { rc = ccatok_ml_dsa_build_context_msg(in_data, in_data_len, sign_param.pContext, sign_param.ulContextLen, context_msg, context_msg_len); if (rc != CKR_OK) { TRACE_ERROR("ccatok_ml_dsa_build_context_msg failed.\n"); return rc; } memcpy(rule_array + (*rule_array_count * CCA_KEYWORD_SIZE), "CONTEXT ", CCA_KEYWORD_SIZE); (*rule_array_count)++; } break; default: break; } return CKR_OK; } static CK_RV ccatok_ml_dsa_sign(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, const struct pqc_oid *oid, CK_MECHANISM *mech, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *signature, CK_ULONG *signature_len, OBJECT *key_obj, CK_BBOOL final_part) { long return_code, reason_code, rule_array_count; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; long signature_bit_length; CK_ATTRIBUTE *attr; CK_BYTE *context_msg = NULL; CK_ULONG context_msg_len; CK_BYTE *tmp; CK_RV rc; UNUSED(sess); if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } if (!cca_pqc_strength_supported(tokdata, mech->mechanism, oid->keyform)) { TRACE_DEVEL("PQC keyform %lu not supported by CCA\n", oid->keyform); return CKR_KEY_SIZE_RANGE; } if (mech->mechanism == CKM_HASH_ML_DSA && !final_part) { /* CKM_HASH_ML_DSA does not support multipart */ TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); return CKR_MECHANISM_INVALID; } if (!final_part || (mech->mechanism == CKM_ML_DSA && sess->sign_ctx.context != NULL && in_data_len > 0)) { /* Collect the input data in the context */ if (in_data_len == 0) return CKR_OK; tmp = (CK_BYTE *)realloc(sess->sign_ctx.context, sess->sign_ctx.context_len + in_data_len); if (tmp == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); return CKR_HOST_MEMORY; } memcpy(tmp + sess->sign_ctx.context_len, in_data, in_data_len); sess->sign_ctx.context = tmp; sess->sign_ctx.context_len += in_data_len; if (!final_part) return CKR_OK; } if (mech->mechanism == CKM_ML_DSA && sess->sign_ctx.context != NULL && sess->sign_ctx.context_len > 0) { in_data = sess->sign_ctx.context; in_data_len = sess->sign_ctx.context_len; } rc = check_ml_dsa_data_len(tokdata, mech->mechanism, oid, in_data_len); if (rc != CKR_OK) return rc; rc = ccatok_ml_dsa_build_rule_array(mech, TRUE, key_obj, rule_array, &rule_array_count, in_data, in_data_len, &context_msg, &context_msg_len); if (rc != CKR_OK) { TRACE_ERROR("ccatok_ml_dsa_build_rule_array failed.\n"); return rc; } /* Find the secure key token */ rc = template_attribute_get_non_empty(key_obj->template, CKA_IBM_OPAQUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_OPAQUE for the key.\n"); if (context_msg != NULL) free(context_msg); return rc; } if (length_only) { *signature_len = CCA_MAX_ML_DSA_SIGNATURE_LEN; if (context_msg != NULL) free(context_msg); return CKR_OK; } if (*signature_len > CCA_MAX_ML_DSA_SIGNATURE_LEN) *signature_len = CCA_MAX_ML_DSA_SIGNATURE_LEN; USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) RETRY_NEW_MK_BLOB_START() dll_CSNDDSG(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, (long *)&(attr->ulValueLen), attr->pValue, (long *)(context_msg != NULL ? &context_msg_len : &in_data_len), context_msg != NULL ? context_msg : in_data, (long *)signature_len, &signature_bit_length, signature); RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, attr->pValue, attr->ulValueLen) USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (context_msg != NULL) free(context_msg); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDDSG (QSA SIGN) failed. return:%ld," " reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } else if (reason_code != 0) { TRACE_WARNING("CSNDDSG (QSA SIGN) succeeded, but" " returned reason:%ld\n", reason_code); } if (final_part && sess->sign_ctx.context != NULL) { free(sess->sign_ctx.context); sess->sign_ctx.context = NULL; sess->sign_ctx.context_len = 0; } return CKR_OK; } static CK_RV ccatok_ml_dsa_verify(STDLL_TokData_t *tokdata, SESSION *sess, const struct pqc_oid *oid, CK_MECHANISM *mech, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *signature, CK_ULONG signature_len, OBJECT *key_obj, CK_BBOOL final_part) { long return_code, reason_code, rule_array_count; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; CK_ATTRIBUTE *attr; CK_BYTE *context_msg = NULL; CK_ULONG context_msg_len; CK_BYTE *tmp; CK_RV rc; UNUSED(sess); if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } if (!cca_pqc_strength_supported(tokdata, mech->mechanism, oid->keyform)) { TRACE_DEVEL("PQC keyform %lu not supported by CCA\n", oid->keyform); return CKR_KEY_SIZE_RANGE; } if (mech->mechanism == CKM_HASH_ML_DSA && !final_part) { /* CKM_HASH_ML_DSA does not support multipart */ TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); return CKR_MECHANISM_INVALID; } if (!final_part || (mech->mechanism == CKM_ML_DSA && sess->verify_ctx.context != NULL && in_data_len > 0)) { /* Collect the input data in the context */ if (in_data_len == 0) return CKR_OK; tmp = (CK_BYTE *)realloc(sess->verify_ctx.context, sess->verify_ctx.context_len + in_data_len); if (tmp == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); return CKR_HOST_MEMORY; } memcpy(tmp + sess->verify_ctx.context_len, in_data, in_data_len); sess->verify_ctx.context = tmp; sess->verify_ctx.context_len += in_data_len; if (!final_part) return CKR_OK; } if (mech->mechanism == CKM_ML_DSA && sess->verify_ctx.context != NULL && sess->verify_ctx.context_len > 0) { in_data = sess->verify_ctx.context; in_data_len = sess->verify_ctx.context_len; } rc = check_ml_dsa_data_len(tokdata, mech->mechanism, oid, in_data_len); if (rc != CKR_OK) return rc; rc = ccatok_ml_dsa_build_rule_array(mech, FALSE, key_obj, rule_array, &rule_array_count, in_data, in_data_len, &context_msg, &context_msg_len); if (rc != CKR_OK) { TRACE_ERROR("ccatok_ml_dsa_build_rule_array failed.\n"); return rc; } /* Find the secure key token */ rc = template_attribute_get_non_empty(key_obj->template, CKA_IBM_OPAQUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_OPAQUE for the key.\n"); if (context_msg != NULL) free(context_msg); return rc; } USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) RETRY_NEW_MK_BLOB_START() dll_CSNDDSV(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, (long *)&(attr->ulValueLen), attr->pValue, (long *)(context_msg != NULL ? &context_msg_len : &in_data_len), context_msg != NULL ? context_msg : in_data, (long *)&signature_len, signature); RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, attr->pValue, attr->ulValueLen) USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (context_msg != NULL) free(context_msg); if (return_code == 4 && reason_code == 429) { return CKR_SIGNATURE_INVALID; } else if (return_code == 12 && reason_code == 769) { return CKR_SIGNATURE_INVALID; } else if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDDSV (QSA VERIFY) failed. return:%ld," " reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } else if (reason_code != 0) { TRACE_WARNING("CSNDDSV (QSA VERIFY) succeeded, but" " returned reason:%ld\n", reason_code); } if (final_part && sess->verify_ctx.context != NULL) { free(sess->verify_ctx.context); sess->verify_ctx.context = NULL; sess->verify_ctx.context_len = 0; } return CKR_OK; } CK_RV token_specific_ibm_ml_dsa_sign(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, const struct pqc_oid *oid, CK_MECHANISM *mech, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *signature, CK_ULONG *signature_len, OBJECT *key_obj) { return ccatok_ml_dsa_sign(tokdata, sess, length_only, oid, mech, in_data, in_data_len, signature, signature_len, key_obj, TRUE); } CK_RV token_specific_ibm_ml_dsa_verify(STDLL_TokData_t *tokdata, SESSION *sess, const struct pqc_oid *oid, CK_MECHANISM *mech, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *signature, CK_ULONG signature_len, OBJECT *key_obj) { return ccatok_ml_dsa_verify(tokdata, sess, oid, mech, in_data, in_data_len, signature, signature_len, key_obj, TRUE); } CK_RV token_specific_ml_dsa_sign(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, const struct pqc_oid *oid, CK_MECHANISM *mech, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *signature, CK_ULONG *signature_len, OBJECT *key_obj, CK_BBOOL final_part) { return ccatok_ml_dsa_sign(tokdata, sess, length_only, oid, mech, in_data, in_data_len, signature, signature_len, key_obj, final_part); } CK_RV token_specific_ml_dsa_verify(STDLL_TokData_t *tokdata, SESSION *sess, const struct pqc_oid *oid, CK_MECHANISM *mech, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *signature, CK_ULONG signature_len, OBJECT *key_obj, CK_BBOOL final_part) { return ccatok_ml_dsa_verify(tokdata, sess, oid, mech, in_data, in_data_len, signature, signature_len, key_obj, final_part); } CK_RV token_specific_ibm_ml_kem_generate_keypair(STDLL_TokData_t *tokdata, CK_MECHANISM *mech, const struct pqc_oid *oid, TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl) { return ccatok_pqc_generate_keypair(tokdata, mech, oid, publ_tmpl, priv_tmpl); } static CK_RV cca_ibm_ml_kem_derive_with_ecdh(STDLL_TokData_t *tokdata, SESSION *sess, const struct pqc_oid *oid, CK_MECHANISM *mech, OBJECT *base_key_object, CK_OBJECT_CLASS base_key_class, CK_KEY_TYPE base_key_type, OBJECT *derived_key_object, CK_KEY_TYPE derived_key_type, CK_ULONG derived_keylen) { long return_code, reason_code, rule_array_count, exit_data_len = 0; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; unsigned char exit_data[4]; unsigned char aes_key_token[CCA_MAX_AES_CIPHER_KEY_SIZE] = { 0 }; long aes_key_token_len = sizeof(aes_key_token); unsigned char enc_secret[32] = { 0 }; unsigned char IV[AES_INIT_VECTOR_SIZE] = { 0 }; long enc_secret_len = sizeof(enc_secret); long clear_key_bit_length = 256, zero_length = 0; unsigned char key_type1[CCA_KEYWORD_SIZE]; unsigned char key_type2[CCA_KEYWORD_SIZE]; CK_IBM_ML_KEM_WITH_ECDH_PARAMS *kem_params = NULL; CK_ECDH1_DERIVE_PARAMS ecdh_params; struct cca_hybrid_ecdh_data ecdh_hybrid_data; CK_ATTRIBUTE *base_opaque_attr = NULL; OBJECT *ec_key_obj = NULL; CK_RV rc; UNUSED(derived_keylen); if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } if (!cca_pqc_strength_supported(tokdata, mech->mechanism, oid->keyform)) { TRACE_DEVEL("PQC keyform %lu not supported by CCA\n", oid->keyform); return CKR_KEY_SIZE_RANGE; } if (mech->mechanism != CKM_IBM_ML_KEM_WITH_ECDH) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); return CKR_MECHANISM_INVALID; } if (base_key_type != CKK_IBM_ML_KEM) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); return CKR_KEY_TYPE_INCONSISTENT; } rc = template_attribute_get_non_empty(base_key_object->template, CKA_IBM_OPAQUE, &base_opaque_attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_OPAQUE for the base key.\n"); return rc; } if (mech->pParameter == NULL || mech->ulParameterLen != sizeof(CK_IBM_ML_KEM_WITH_ECDH_PARAMS)) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); return CKR_MECHANISM_PARAM_INVALID; } kem_params = mech->pParameter; /* Perform Encapsuation/decapsulation */ switch (kem_params->mode) { case CK_IBM_ML_KEM_ENCAPSULATE: if (base_key_class != CKO_PUBLIC_KEY) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); return CKR_KEY_TYPE_INCONSISTENT; } /* pCipher/ulCipherLen is output on encapsulate */ if (kem_params->ulCipherLen > 0 && kem_params->pCipher == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); return CKR_MECHANISM_PARAM_INVALID; } if (kem_params->pCipher == NULL || kem_params->ulCipherLen < oid->len_info.ml_kem.pk_len) { kem_params->ulCipherLen = oid->len_info.ml_kem.pk_len; return CKR_BUFFER_TOO_SMALL; } /* Generate a temporary AES-CIPHER key */ rc = cca_build_aes_cipher_token(tokdata, NULL, aes_key_token, (CK_ULONG *)&aes_key_token_len); if (rc != CKR_OK) { TRACE_ERROR("Failed to build CCA CIPHER key token"); return rc; } rule_array_count = 2; memcpy(rule_array, "AES OP ", 2 * CCA_KEYWORD_SIZE); memcpy(key_type1, "TOKEN ", CCA_KEYWORD_SIZE); memcpy(key_type2, " ", CCA_KEYWORD_SIZE); aes_key_token_len = sizeof(aes_key_token); dll_CSNBKGN2(&return_code, &reason_code, &exit_data_len, exit_data, &rule_array_count, rule_array, &clear_key_bit_length, key_type1, key_type2, &zero_length, NULL, &zero_length, NULL, &zero_length, NULL, &zero_length, NULL, &zero_length, NULL, &zero_length, NULL, &aes_key_token_len, aes_key_token, &zero_length, NULL); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBKGN2(KEYGEN) failed. return:%ld, reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } /* Create and encrypt the random ML-KEM secret */ rule_array_count = 3; memcpy(rule_array, "RANDOM ZERO-PADAES-ENC ", 3 * CCA_KEYWORD_SIZE); memcpy(enc_secret, IV, sizeof(IV)); USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) RETRY_NEW_MK_BLOB_START() dll_CSNDPKE(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &enc_secret_len, enc_secret, &aes_key_token_len, aes_key_token, (long *)&(base_opaque_attr->ulValueLen), base_opaque_attr->pValue, (long *)&kem_params->ulCipherLen, kem_params->pCipher); RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, base_opaque_attr->pValue, base_opaque_attr->ulValueLen) USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKE (QSA ENCRYPT) failed. return:%ld, " "reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } break; case CK_IBM_ML_KEM_DECAPSULATE: if (base_key_class != CKO_PRIVATE_KEY) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); return CKR_KEY_TYPE_INCONSISTENT; } /* pCipher/ulCipherLen is input on decapsulate */ if (kem_params->pCipher == NULL || kem_params->ulCipherLen == 0) { 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_PARAM_INVALID)); return CKR_MECHANISM_PARAM_INVALID; } /* Get EC private key */ rc = object_mgr_find_in_map1(tokdata, kem_params->hECPrivateKey, &ec_key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to acquire EC private key from handle.\n"); if (rc == CKR_OBJECT_HANDLE_INVALID) rc = CKR_KEY_HANDLE_INVALID; return rc; } /* Perform ECDH */ ecdh_params.kdf = kem_params->kdf; ecdh_params.pPublicData = kem_params->pPublicData; ecdh_params.ulPublicDataLen = kem_params->ulPublicDataLen; ecdh_params.pSharedData = kem_params->pSharedData; ecdh_params.ulSharedDataLen = kem_params->ulSharedDataLen; switch (kem_params->mode) { case CK_IBM_ML_KEM_ENCAPSULATE: memcpy(ecdh_hybrid_data.rule, "IHKEYAES", CCA_KEYWORD_SIZE); ecdh_hybrid_data.hybrid_key = aes_key_token; ecdh_hybrid_data.hybrid_key_len = aes_key_token_len; ecdh_hybrid_data.iv = IV; ecdh_hybrid_data.iv_len = sizeof(IV); ecdh_hybrid_data.cipher = enc_secret; ecdh_hybrid_data.cipher_len = enc_secret_len; break; case CK_IBM_ML_KEM_DECAPSULATE: memcpy(ecdh_hybrid_data.rule, "IHKEYKYB", CCA_KEYWORD_SIZE); ecdh_hybrid_data.hybrid_key = base_opaque_attr->pValue; ecdh_hybrid_data.hybrid_key_len = base_opaque_attr->ulValueLen; ecdh_hybrid_data.iv = NULL; ecdh_hybrid_data.iv_len = 0; ecdh_hybrid_data.cipher = kem_params->pCipher; ecdh_hybrid_data.cipher_len = kem_params->ulCipherLen; break; default: TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto out; } rc = cca_ecdh_pkcs_derive_kdf(tokdata, sess, ec_key_obj, &ecdh_params, derived_key_object, CKO_SECRET_KEY, derived_key_type, &ecdh_hybrid_data); if (rc != CKR_OK) { TRACE_ERROR("cca_ecdh_pkcs_derive_kdf failed"); goto out; } out: if (ec_key_obj != NULL) { object_put(tokdata, ec_key_obj, TRUE); ec_key_obj = NULL; } return rc; } CK_RV token_specific_ibm_ml_kem_derive(STDLL_TokData_t *tokdata, SESSION *sess, const struct pqc_oid *oid, CK_MECHANISM *mech, OBJECT *base_key_object, CK_OBJECT_CLASS base_key_class, CK_KEY_TYPE base_key_type, OBJECT *derived_key_object, CK_KEY_TYPE derived_key_type, CK_ULONG derived_keylen) { switch (mech->mechanism) { case CKM_IBM_ML_KEM_WITH_ECDH: return cca_ibm_ml_kem_derive_with_ecdh(tokdata, sess, oid, mech, base_key_object, base_key_class, base_key_type, derived_key_object, derived_key_type, derived_keylen); default: return CKR_MECHANISM_INVALID; } } static CK_RV import_rsa_privkey(STDLL_TokData_t *tokdata, TEMPLATE * priv_tmpl) { CK_RV rc; CK_ATTRIBUTE *opaque_attr = NULL; enum cca_token_type token_type; unsigned int token_keybitsize; const CK_BYTE *mkvp; CK_BBOOL new_mk; rc = template_attribute_find(priv_tmpl, CKA_IBM_OPAQUE, &opaque_attr); if (rc == TRUE) { /* * This is an import of an existing secure rsa private key which * is stored in the CKA_IBM_OPAQUE attribute. */ CK_BYTE *t, n[CCATOK_MAX_N_LEN], e[CCATOK_MAX_E_LEN]; CK_ULONG n_len = CCATOK_MAX_N_LEN, e_len = CCATOK_MAX_E_LEN; uint16_t privkey_len, pubkey_offset; CK_BBOOL true = TRUE; if (analyse_cca_key_token(opaque_attr->pValue, opaque_attr->ulValueLen, &token_type, &token_keybitsize, &mkvp) != TRUE) { TRACE_ERROR("Invalid/unknown cca token in CKA_IBM_OPAQUE attribute\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } if (token_type != sec_rsa_priv_key) { TRACE_ERROR("CCA token type in CKA_IBM_OPAQUE does not match to keytype CKK_RSA\n"); return CKR_TEMPLATE_INCONSISTENT; } if (check_expected_mkvp(tokdata, token_type, mkvp, &new_mk) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } rc = cca_reencipher_created_key(tokdata, priv_tmpl, opaque_attr->pValue, opaque_attr->ulValueLen, new_mk, token_type, FALSE); if (rc != CKR_OK) { TRACE_ERROR("cca_reencipher_created_key failed: 0x%lx\n", rc); return rc; } t = opaque_attr->pValue; privkey_len = cca_rsa_inttok_privkey_get_len(&t[CCA_RSA_INTTOK_PRIVKEY_OFFSET]); pubkey_offset = CCA_RSA_INTTOK_HDR_LENGTH + privkey_len; /* modulus n is stored in the private (!) key area, get it there */ rc = cca_rsa_inttok_privkeysec_get_n(&t[CCA_RSA_INTTOK_PRIVKEY_OFFSET], &n_len, n); if (rc != CKR_OK) { TRACE_DEVEL("cca_inttok_privkey_get_n() failed. rc=0x%lx\n", rc); return rc; } /* Add/update CKA_SENSITIVE */ rc = build_update_attribute(priv_tmpl, CKA_SENSITIVE, &true, sizeof(CK_BBOOL)); if (rc != CKR_OK) { TRACE_DEVEL("build_update_attribute for CKA_SENSITIVE failed. rc=0x%lx\n", rc); return rc; } /* get public exponent e */ rc = cca_rsa_inttok_pubkeysec_get_e(&t[pubkey_offset], &e_len, e); if (rc != CKR_OK) { TRACE_DEVEL("cca_inttok_pubkey_get_e() failed. rc=0x%lx\n", rc); return rc; } /* add n's value to the template */ rc = build_update_attribute(priv_tmpl, CKA_MODULUS, n, n_len); if (rc != CKR_OK) { TRACE_DEVEL("build_update_attribute for n failed. rc=0x%lx\n", rc); return rc; } /* Add e's value to the template */ rc = build_update_attribute(priv_tmpl, CKA_PUBLIC_EXPONENT, e, e_len); if (rc != CKR_OK) { TRACE_DEVEL("build_update_attribute for e failed. rc=0x%lx\n", rc); return rc; } /* Add dummy attributes to satisfy PKCS#11 */ rc = build_update_attribute(priv_tmpl, CKA_PRIVATE_EXPONENT, NULL, 0); if (rc != CKR_OK) { TRACE_DEVEL("build_update_attribute for d failed. rc=0x%lx\n", rc); return rc; } } else { /* * This is an import of a clear key value which is to be transfered * into a CCA RSA private key. */ 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, size_of_d; uint16_t mod_bits, mod_bytes, bytes; CK_ATTRIBUTE *pub_exp = NULL, *mod = NULL, *p_prime = NULL, *q_prime = NULL, *dmp1 = NULL, *dmq1 = NULL, *iqmp = NULL, *priv_exp = NULL; CK_BBOOL is_me_format = FALSE; /* Try to get CRT key components (no rc checking) */ template_attribute_get_non_empty(priv_tmpl, CKA_PRIME_1, &p_prime); template_attribute_get_non_empty(priv_tmpl, CKA_PRIME_2, &q_prime); template_attribute_get_non_empty(priv_tmpl, CKA_EXPONENT_1, &dmp1); template_attribute_get_non_empty(priv_tmpl, CKA_EXPONENT_2, &dmq1); template_attribute_get_non_empty(priv_tmpl, CKA_COEFFICIENT, &iqmp); if (p_prime == NULL || q_prime == NULL || dmp1 == NULL || dmq1 == NULL || iqmp == NULL) { /* No CRT components, then get private exponent instead */ rc = template_attribute_get_non_empty(priv_tmpl, CKA_PRIVATE_EXPONENT, &priv_exp); if (rc != CKR_OK) { TRACE_ERROR("CKA_PRIVATE_EXPONENT attribute missing for ME.\n"); return rc; } is_me_format = TRUE; } /* Public exponent and Modulus are always required */ rc = template_attribute_get_non_empty(priv_tmpl, CKA_PUBLIC_EXPONENT, &pub_exp); if (rc != CKR_OK) { TRACE_ERROR("CKA_PUBLIC_EXPONENT attribute missing for CRT/ME.\n"); return rc; } rc = template_attribute_get_non_empty(priv_tmpl, CKA_MODULUS, &mod); if (rc != CKR_OK) { TRACE_ERROR("CKA_MODULUS attribute missing for CRT/ME.\n"); return rc; } if (is_me_format) { total += priv_exp->ulValueLen; total += pub_exp->ulValueLen; total += mod->ulValueLen; /* check total length does not exceed key_value_structure_length */ if ((total + 8) > 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-AESM 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 = htobe16(mod->ulValueLen * 8); memcpy(&key_value_structure[0], &mod_bits, sizeof(uint16_t)); /* Field #2 - Length of modulus field in bytes */ mod_bytes = htobe16(mod->ulValueLen); memcpy(&key_value_structure[2], &mod_bytes, sizeof(uint16_t)); /* Field #3 - Length of public exponent field in bytes */ size_of_e = htobe16(pub_exp->ulValueLen); memcpy(&key_value_structure[4], &size_of_e, sizeof(uint16_t)); /* Field #4 - Length of private exponent field in bytes */ size_of_d = htobe16(priv_exp->ulValueLen); memcpy(&key_value_structure[6], &size_of_d, sizeof(uint16_t)); /* Field #5 - Modulus */ memcpy(&key_value_structure[8], mod->pValue, mod->ulValueLen); offset = 8 + mod->ulValueLen; /* Field #6 - Public Exponent */ memcpy(&key_value_structure[offset], pub_exp->pValue, pub_exp->ulValueLen); offset += pub_exp->ulValueLen; /* Field #7 - Private Exponent */ memcpy(&key_value_structure[offset], priv_exp->pValue, priv_exp->ulValueLen); rule_array_count = 2; memcpy(rule_array, "RSA-AESMKEY-MGMT", (CCA_KEYWORD_SIZE * 2)); } else { /* CRT format */ total += p_prime->ulValueLen; total += q_prime->ulValueLen; total += dmp1->ulValueLen; total += dmq1->ulValueLen; total += iqmp->ulValueLen; total += pub_exp->ulValueLen; 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-AESC 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 = htobe16(mod->ulValueLen * 8); memcpy(&key_value_structure[0], &mod_bits, sizeof(uint16_t)); /* Field #2 - Length of modulus field in bytes */ mod_bytes = htobe16(mod->ulValueLen); memcpy(&key_value_structure[2], &mod_bytes, sizeof(uint16_t)); /* Field #3 - Length of public exponent field in bytes */ size_of_e = htobe16(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 = htobe16(p_prime->ulValueLen); memcpy(&key_value_structure[8], &bytes, sizeof(uint16_t)); /* Field #6 - Length of prime Q */ bytes = htobe16(q_prime->ulValueLen); memcpy(&key_value_structure[10], &bytes, sizeof(uint16_t)); /* Field #7 - Length of dp in bytes */ bytes = htobe16(dmp1->ulValueLen); memcpy(&key_value_structure[12], &bytes, sizeof(uint16_t)); /* Field #8 - Length of dq in bytes */ bytes = htobe16(dmq1->ulValueLen); memcpy(&key_value_structure[14], &bytes, sizeof(uint16_t)); /* Field #9 - Length of U in bytes */ bytes = htobe16(iqmp->ulValueLen); memcpy(&key_value_structure[16], &bytes, sizeof(uint16_t)); /* Field #10 - Modulus */ memcpy(&key_value_structure[18], mod->pValue, mod->ulValueLen); offset = 18 + mod->ulValueLen; /* 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); rule_array_count = 2; memcpy(rule_array, "RSA-AESCKEY-MGMT", (CCA_KEYWORD_SIZE * 2)); } /* Now build a key token with the imported public key */ private_key_name_length = 0; key_token_length = CCA_KEY_TOKEN_SIZE; USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNDPKB(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &key_value_structure_length, key_value_structure, &private_key_name_length, private_key_name, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, &key_token_length, key_token); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKB (RSA KEY TOKEN BUILD RSA CRT/ME) failed." " return:%ld, reason:%ld\n", return_code, reason_code); if (return_code == 8 && reason_code == 760) { rc = CKR_KEY_SIZE_RANGE; goto err; } rc = CKR_FUNCTION_FAILED; goto err; } /* Now import the PKA key token */ rule_array_count = 0; target_key_token_length = CCA_KEY_TOKEN_SIZE; key_token_length = CCA_KEY_TOKEN_SIZE; USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNDPKI(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &key_token_length, key_token, transport_key_identifier, &target_key_token_length, target_key_token); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKI (RSA KEY TOKEN IMPORT) failed." " return:%ld, reason:%ld\n", return_code, reason_code); if ((return_code == 8 && reason_code == 43) || (return_code == 8 && reason_code == 770)) { rc = CKR_KEY_SIZE_RANGE; goto err; } rc = CKR_FUNCTION_FAILED; goto err; } if (analyse_cca_key_token(target_key_token, target_key_token_length, &token_type, &token_keybitsize, &mkvp) == FALSE || mkvp == NULL) { TRACE_ERROR("Invalid/unknown cca token has been imported\n"); return CKR_FUNCTION_FAILED; } if (check_expected_mkvp(tokdata, token_type, mkvp, &new_mk) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } rc = cca_reencipher_created_key(tokdata, priv_tmpl, target_key_token, target_key_token_length, new_mk, token_type, FALSE); if (rc != CKR_OK) { TRACE_ERROR("cca_reencipher_created_key failed: 0x%lx\n", rc); return rc; } /* Add the key object to the template */ if ((rc = build_update_attribute(priv_tmpl, CKA_IBM_OPAQUE, target_key_token, target_key_token_length))) { TRACE_DEVEL("build_update_attribute failed\n"); goto err; } if (p_prime != NULL) OPENSSL_cleanse(p_prime->pValue, p_prime->ulValueLen); if (q_prime != NULL) OPENSSL_cleanse(q_prime->pValue, q_prime->ulValueLen); if (dmp1 != NULL) OPENSSL_cleanse(dmp1->pValue, dmp1->ulValueLen); if (dmq1 != NULL) OPENSSL_cleanse(dmq1->pValue, dmq1->ulValueLen); if (iqmp != NULL) OPENSSL_cleanse(iqmp->pValue, iqmp->ulValueLen); if (priv_exp != NULL) OPENSSL_cleanse(priv_exp->pValue, priv_exp->ulValueLen); rc = CKR_OK; err: OPENSSL_cleanse(key_value_structure, sizeof(key_value_structure)); } if (rc == CKR_OK) { TRACE_DEBUG("%s: imported object template attributes:\n", __func__); TRACE_DEBUG_DUMPTEMPL(priv_tmpl); } return rc; } static CK_RV import_rsa_pubkey(STDLL_TokData_t *tokdata, TEMPLATE *publ_tmpl) { CK_RV rc; CK_ATTRIBUTE *opaque_attr = NULL; rc = template_attribute_find(publ_tmpl, CKA_IBM_OPAQUE, &opaque_attr); if (rc == TRUE) { /* * This is an import of an existing secure rsa public key which * is stored in the CKA_IBM_OPAQUE attribute. */ enum cca_token_type token_type; unsigned int token_keybitsize; CK_BYTE *t, n[CCATOK_MAX_N_LEN], e[CCATOK_MAX_E_LEN]; CK_ULONG n_len = CCATOK_MAX_N_LEN, e_len = CCATOK_MAX_E_LEN; const CK_BYTE *mkvp; if (analyse_cca_key_token(opaque_attr->pValue, opaque_attr->ulValueLen, &token_type, &token_keybitsize, &mkvp) != TRUE) { TRACE_ERROR("Invalid/unknown cca token in CKA_IBM_OPAQUE attribute\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } if (token_type != sec_rsa_publ_key) { TRACE_ERROR("CCA token type in CKA_IBM_OPAQUE does not match to keytype CKK_RSA\n"); return CKR_TEMPLATE_INCONSISTENT; } t = opaque_attr->pValue; /* extract modulus n from public key section */ rc = cca_rsa_exttok_pubkeysec_get_n(&t[CCA_RSA_EXTTOK_PUBKEY_OFFSET], &n_len, n); if (rc != CKR_OK) { TRACE_DEVEL("cca_exttok_pubkey_get_n() failed. rc=0x%lx\n", rc); return rc; } /* extract exponent e from public key section */ rc = cca_rsa_exttok_pubkeysec_get_e(&t[CCA_RSA_EXTTOK_PUBKEY_OFFSET], &e_len, e); if (rc != CKR_OK) { TRACE_DEVEL("cca_exttok_pubkey_get_e() failed. rc=0x%lx\n", rc); return rc; } /* add n's value to the template */ rc = build_update_attribute(publ_tmpl, CKA_MODULUS, n, n_len); if (rc != CKR_OK) { TRACE_DEVEL("build_update_attribute for n failed. rc=0x%lx\n", rc); return rc; } /* Add e's value to the template */ rc = build_update_attribute(publ_tmpl, CKA_PUBLIC_EXPONENT, e, e_len); if (rc != CKR_OK) { TRACE_DEVEL("build_update_attribute for e failed. rc=0x%lx\n", rc); return rc; } } else { /* * This is an import of a clear key value which is to be transfered * into a CCA RSA public key. */ 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 *pub_exp = NULL; CK_ATTRIBUTE *pub_mod = NULL, *attr = NULL; /* check that modulus and public exponent are available */ rc = template_attribute_get_non_empty(publ_tmpl, CKA_PUBLIC_EXPONENT, &pub_exp); if (rc != CKR_OK) { TRACE_ERROR("CKA_PUBLIC_EXPONENT attribute missing.\n"); return rc; } rc = template_attribute_get_non_empty(publ_tmpl, CKA_MODULUS, &pub_mod); if (rc != CKR_OK) { TRACE_ERROR("CKA_MODULUS attribute missing.\n"); return rc; } rc = template_attribute_get_non_empty(publ_tmpl, CKA_MODULUS_BITS, &attr); if (rc != CKR_OK) { TRACE_ERROR("CKA_MODULUS_BITS attribute missing.\n"); return rc; } /* check total length does not exceed key_value_structure_length */ if ((pub_mod->ulValueLen + 8 + pub_exp->ulValueLen) > (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 = htobe16(pub_mod->ulValueLen * 8); else mod_bits = htobe16(*(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 = htobe16(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 = htobe16((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 + pub_mod->ulValueLen], 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. USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNDPKB(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &key_value_structure_length, key_value_structure, &private_key_name_length, private_key_name, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, &key_token_length, key_token); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKB (RSA KEY TOKEN BUILD RSA-PUBL) failed." " return:%ld, reason:%ld\n", return_code, reason_code); if (return_code == 8 && reason_code == 760) return CKR_KEY_SIZE_RANGE; return CKR_FUNCTION_FAILED; } // Add the key object to the template. if ((rc = build_update_attribute(publ_tmpl, CKA_IBM_OPAQUE, key_token, key_token_length))) { TRACE_DEVEL("build_update_attribute failed\n"); return rc; } } TRACE_DEBUG("%s: imported object template attributes:\n", __func__); TRACE_DEBUG_DUMPTEMPL(publ_tmpl); return CKR_OK; } static CK_RV import_symmetric_key(STDLL_TokData_t *tokdata, OBJECT * object, CK_ULONG keytype) { CK_RV rc; CK_ATTRIBUTE *opaque_attr = NULL; enum cca_token_type token_type; unsigned int token_keybitsize; const CK_BYTE *mkvp; CK_BBOOL new_mk, exp, cpacf_exp; rc = template_attribute_find(object->template, CKA_IBM_OPAQUE, &opaque_attr); if (rc == TRUE) { /* * This is an import of an existing secure key which is stored in * the CKA_IBM_OPAQUE attribute. The CKA_VALUE attribute is only * a dummy reflecting the clear key byte size. However, let's * check if the template attributes match to the cca key in the * CKA_IBM_OPAQUE attribute. */ CK_BYTE zorro[32] = { 0 }; CK_BBOOL true = TRUE; CK_ULONG value_len = 0; CK_IBM_CCA_AES_KEY_MODE_TYPE mode; #ifndef NO_PKEY CK_BBOOL false = FALSE; #endif if (analyse_cca_key_token(opaque_attr->pValue, opaque_attr->ulValueLen, &token_type, &token_keybitsize, &mkvp) != TRUE) { TRACE_ERROR("Invalid/unknown cca token in CKA_IBM_OPAQUE attribute\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } if (keytype == CKK_DES) { if (token_type != sec_des_data_key) { TRACE_ERROR("CCA token type in CKA_IBM_OPAQUE does not match to keytype CKK_DES\n"); return CKR_TEMPLATE_INCONSISTENT; } if (token_keybitsize != 8 * 8) { TRACE_ERROR("CCA token keybitsize %u does not match to keytype CKK_DES\n", token_keybitsize); return CKR_TEMPLATE_INCONSISTENT; } } else if (keytype == CKK_DES3) { if (token_type != sec_des_data_key) { TRACE_ERROR("CCA token type in CKA_IBM_OPAQUE does not match to keytype CKK_DES3\n"); return CKR_TEMPLATE_INCONSISTENT; } if (token_keybitsize != 8 * 24) { TRACE_ERROR("CCA token keybitsize %u does not match to keytype CKK_DES3\n", token_keybitsize); return CKR_TEMPLATE_INCONSISTENT; } } else if (keytype == CKK_AES) { if (token_type == sec_aes_data_key) { /* keybitsize has been checked by the analyse_cca_key_token() function */ mode = CK_IBM_CCA_AES_DATA_KEY; cpacf_exp = CK_TRUE; exp = CK_TRUE; } else if (token_type == sec_aes_cipher_key) { mode = CK_IBM_CCA_AES_CIPHER_KEY; if (token_keybitsize == 0) { /* * A CIPHER key with V1 payload does not allow to obtain the * keybitsize. The user must supply the CKA_VALUE_LEN with * a valid key size in the template. */ rc = template_attribute_get_ulong(object->template, CKA_VALUE_LEN, &value_len); if (rc != CKR_OK || value_len == 0) { TRACE_ERROR("For an AES CIPHER key token with V1 " "payload attribute CKA_VALUE_LEN must also " "be supplied to specify the key size\n"); return CKR_TEMPLATE_INCONSISTENT; } if (value_len != 16 && value_len != 24 && value_len != 32) { TRACE_ERROR("CKA_VALUE_LEN not valid for an AES key\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } token_keybitsize = value_len * 8; } rc = ccatok_var_sym_token_is_exportable(opaque_attr->pValue, opaque_attr->ulValueLen, &exp, &cpacf_exp); if (rc != CKR_OK) return rc; } else { TRACE_ERROR("CCA token type in CKA_IBM_OPAQUE does not match to keytype CKK_AES\n"); return CKR_TEMPLATE_INCONSISTENT; } rc = build_update_attribute(object->template, CKA_EXTRACTABLE, (CK_BYTE *)&exp, sizeof(exp)); if (rc != CKR_OK) { TRACE_DEVEL("build_update_attribute(CKA_EXTRACTABLE) " "failed\n"); return rc; } #ifndef NO_PKEY rc = build_update_attribute(object->template, CKA_IBM_PROTKEY_EXTRACTABLE, (CK_BYTE *)&cpacf_exp, sizeof(cpacf_exp)); if (rc != CKR_OK) { TRACE_DEVEL("build_update_attribute(CKA_IBM_PROTKEY_EXTRACTABLE) " "failed\n"); return rc; } if (cpacf_exp) { rc = build_update_attribute(object->template, CKA_IBM_PROTKEY_NEVER_EXTRACTABLE, (CK_BYTE *)&false, sizeof(false)); if (rc != CKR_OK) { TRACE_DEVEL("build_update_attribute(CKA_IBM_PROTKEY_NEVER_EXTRACTABLE) " "failed\n"); return rc; } } #endif rc = build_update_attribute(object->template, CKA_IBM_CCA_AES_KEY_MODE, (CK_BYTE *)&mode, sizeof(mode)); if (rc != CKR_OK) { TRACE_DEVEL("build_update_attribute(CKA_IBM_CCA_AES_KEY_MODE) " "failed\n"); return rc; } } else { TRACE_DEBUG("Unknown/unsupported keytype in function %s line %d\n", __func__, __LINE__); return CKR_KEY_FUNCTION_NOT_PERMITTED; } if (check_expected_mkvp(tokdata, token_type, mkvp, &new_mk) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } rc = cca_reencipher_created_key(tokdata, object->template, opaque_attr->pValue, opaque_attr->ulValueLen, new_mk, token_type, FALSE); if (rc != CKR_OK) { TRACE_ERROR("cca_reencipher_created_key failed: 0x%lx\n", rc); return rc; } /* create a dummy CKA_VALUE attribute with the key bit size but all zero */ if ((rc = build_update_attribute(object->template, CKA_VALUE, zorro, token_keybitsize / 8))) { TRACE_DEVEL("build_update_attribute(CKA_VALUE) failed\n"); return rc; } /* Add/update CKA_SENSITIVE */ rc = build_update_attribute(object->template, CKA_SENSITIVE, &true, sizeof(CK_BBOOL)); if (rc != CKR_OK) { TRACE_DEVEL("build_update_attribute for CKA_SENSITIVE failed. rc=0x%lx\n", rc); return rc; } } else { /* * This is an import of a clear key value which is to be transfered * into a CCA Data AES or DES key now. */ long return_code, reason_code, rule_array_count; unsigned char target_key_token[CCA_MAX_AES_CIPHER_KEY_SIZE] = { 0 }; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0 }; CK_ATTRIBUTE *value_attr = NULL; long reserved_1 = 0, key_token_len = sizeof(target_key_token); long key_part_len; CK_IBM_CCA_AES_KEY_MODE_TYPE mode = CK_IBM_CCA_AES_DATA_KEY; rc = template_attribute_get_non_empty(object->template, CKA_VALUE, &value_attr); if (rc != CKR_OK) { TRACE_ERROR("Incomplete key template\n"); return CKR_TEMPLATE_INCOMPLETE; } if (keytype == CKK_AES) { rc = cca_get_and_set_aes_key_mode(tokdata, object->template, &mode); if (rc != CKR_OK) { TRACE_DEVEL("cca_get_and_set_aes_key_mode failed\n"); return rc; } } if (mode == CK_IBM_CCA_AES_CIPHER_KEY) { memcpy(rule_array, "INTERNALAES CIPHER NO-KEY ANY-MODE", 5 * CCA_KEYWORD_SIZE); rule_array_count = 5; rc = cca_aes_cipher_add_key_usage_keywords(tokdata, object->template, rule_array, sizeof(rule_array), (CK_ULONG *) &rule_array_count); if (rc != CKR_OK) { TRACE_ERROR("Failed to add key usage keywords\n"); return rc; } USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNBKTB2(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &reserved_1, NULL, &reserved_1, NULL, &reserved_1, NULL, &reserved_1, NULL, &reserved_1, NULL, &key_token_len, target_key_token); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBKTB2 (AES CIPHER KEY TOKEN BUILD) failed." " return:%ld, reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } memcpy(rule_array, "AES FIRST MIN1PART", 3 * CCA_KEYWORD_SIZE); rule_array_count = 3; key_token_len = sizeof(target_key_token); key_part_len = value_attr->ulValueLen * 8; USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNBKPI2(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &key_part_len, value_attr->pValue, &key_token_len, target_key_token); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBKPI2 (AES CIPHER KEY IMPORT FIRST) failed." " return:%ld, reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } memcpy(rule_array, "AES COMPLETE", 2 * CCA_KEYWORD_SIZE); rule_array_count = 2; USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNBKPI2(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &reserved_1, NULL, &key_token_len, target_key_token); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBKPI2 (AES CIPHER KEY IMPORT COMPLETE) failed." " return:%ld, reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } } else { 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; USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNBCKM(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, (long int *)&value_attr->ulValueLen, value_attr->pValue, target_key_token); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBCKM failed. return:%ld, reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } key_token_len = CCA_KEY_ID_SIZE; } if (analyse_cca_key_token(target_key_token, key_token_len, &token_type, &token_keybitsize, &mkvp) == FALSE || mkvp == NULL) { TRACE_ERROR("Invalid/unknown cca token has been imported\n"); return CKR_FUNCTION_FAILED; } if (check_expected_mkvp(tokdata, token_type, mkvp, &new_mk) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } rc = cca_reencipher_created_key(tokdata, object->template, target_key_token, key_token_len, new_mk, token_type, FALSE); if (rc != CKR_OK) { TRACE_ERROR("cca_reencipher_created_key failed: 0x%lx\n", rc); return rc; } /* Add the key object to the template */ if ((rc = build_update_attribute(object->template, CKA_IBM_OPAQUE, target_key_token, key_token_len))) { TRACE_DEVEL("build_update_attribute(CKA_IBM_OPAQUE) failed\n"); return rc; } /* zero clear key value */ OPENSSL_cleanse(value_attr->pValue, value_attr->ulValueLen); } TRACE_DEBUG("%s: imported object template attributes:\n", __func__); TRACE_DEBUG_DUMPTEMPL(object->template); return CKR_OK; } static CK_RV import_generic_secret_key(STDLL_TokData_t *tokdata, OBJECT * object) { CK_RV rc; CK_ATTRIBUTE *opaque_attr = NULL; CK_ATTRIBUTE *value_attr = NULL; CK_ULONG keylen, keybitlen; enum cca_token_type token_type; unsigned int token_payloadbitsize; const CK_BYTE *mkvp; CK_BBOOL new_mk, exp, cpacf_exp; rc = template_attribute_find(object->template, CKA_VALUE, &value_attr); if (rc == FALSE) { TRACE_ERROR("Incomplete Generic Secret (HMAC) key template\n"); return CKR_TEMPLATE_INCOMPLETE; } keylen = value_attr->ulValueLen; keybitlen = 8 * keylen; /* key bit length needs to be 80-2048 bits */ if (keybitlen < 80 || keybitlen > 2048) { TRACE_ERROR("HMAC key bit size of %lu not within CCA range (80-2048 bits)\n", keybitlen); return CKR_KEY_SIZE_RANGE; } rc = template_attribute_find(object->template, CKA_IBM_OPAQUE, &opaque_attr); if (rc == TRUE) { /* * This is an import of an existing secure key which is stored in * the CKA_IBM_OPAQUE attribute. The CKA_VALUE attribute is only * a dummy reflecting the clear key byte size. However, let's * check if the template attributes match to the cca key in the * CKA_IBM_OPAQUE attribute. */ unsigned int plbitsize; CK_BBOOL true = TRUE; #ifndef NO_PKEY CK_BBOOL false = FALSE; #endif if (analyse_cca_key_token(opaque_attr->pValue, opaque_attr->ulValueLen, &token_type, &token_payloadbitsize, &mkvp) != TRUE) { TRACE_ERROR("Invalid/unknown cca token in CKA_IBM_OPAQUE attribute\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } if (token_type != sec_hmac_key) { TRACE_ERROR("CCA token type in CKA_IBM_OPAQUE does not match to" " keytype CKK_GENERIC_SECRET\n"); return CKR_TEMPLATE_INCONSISTENT; } rc = ccatok_var_sym_token_is_exportable(opaque_attr->pValue, opaque_attr->ulValueLen, &exp, &cpacf_exp); if (rc != CKR_OK) return rc; rc = build_update_attribute(object->template, CKA_EXTRACTABLE, (CK_BYTE *)&exp, sizeof(exp)); if (rc != CKR_OK) { TRACE_DEVEL("build_update_attribute(CKA_EXTRACTABLE) " "failed\n"); return rc; } #ifndef NO_PKEY rc = build_update_attribute(object->template, CKA_IBM_PROTKEY_EXTRACTABLE, (CK_BYTE *)&cpacf_exp, sizeof(cpacf_exp)); if (rc != CKR_OK) { TRACE_DEVEL("build_update_attribute(CKA_IBM_PROTKEY_EXTRACTABLE) " "failed\n"); return rc; } if (cpacf_exp) { rc = build_update_attribute(object->template, CKA_IBM_PROTKEY_NEVER_EXTRACTABLE, (CK_BYTE *)&false, sizeof(false)); if (rc != CKR_OK) { TRACE_DEVEL("build_update_attribute(CKA_IBM_PROTKEY_NEVER_EXTRACTABLE) " "failed\n"); return rc; } } #endif if (check_expected_mkvp(tokdata, token_type, mkvp, &new_mk) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } rc = cca_reencipher_created_key(tokdata, object->template, opaque_attr->pValue, opaque_attr->ulValueLen, new_mk, token_type, FALSE); if (rc != CKR_OK) { TRACE_ERROR("cca_reencipher_created_key failed: 0x%lx\n", rc); return rc; } /* calculate expected payload size from the given keybitlen */ plbitsize = (((keybitlen + 32) + 63) & (~63)) + 320; /* and check with the payload size within the cca hmac token */ if (plbitsize != token_payloadbitsize) { TRACE_ERROR("CCA HMAC token payload size and keysize do not match\n"); return CKR_TEMPLATE_INCONSISTENT; } /* Add/update CKA_SENSITIVE */ rc = build_update_attribute(object->template, CKA_SENSITIVE, &true, sizeof(CK_BBOOL)); if (rc != CKR_OK) { TRACE_DEVEL("build_update_attribute for CKA_SENSITIVE failed. rc=0x%lx\n", rc); return rc; } } else { /* * This is an import of a clear key value which is to be transfered * into a CCA HMAC key now. */ 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_BBOOL extractable = TRUE; memcpy(rule_array, "INTERNALNO-KEY HMAC MAC GENERATE", 5 * CCA_KEYWORD_SIZE); rule_array_count = 5; rc = template_attribute_get_bool(object->template, CKA_EXTRACTABLE, &extractable); if (rc != CKR_OK && rc != CKR_TEMPLATE_INCOMPLETE) { TRACE_ERROR("Failed to get CKA_EXTRACTABLE\n"); return rc; } if (!extractable) { memcpy(rule_array + (rule_array_count * CCA_KEYWORD_SIZE), "NOEX-SYMNOEXUASYNOEXAASYNOEX-DESNOEX-AESNOEX-RSA", 6 * CCA_KEYWORD_SIZE); rule_array_count += 6; } USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNBKTB2(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &clr_key_len, NULL, &key_name_len, NULL, &user_data_len, NULL, &token_data_len, NULL, &verb_data_len, NULL, &key_token_len, key_token); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBKTB2 (HMAC KEY TOKEN BUILD) failed." " return:%ld, reason:%ld\n", return_code, reason_code); 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); USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNBKPI2(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &key_part_len, value_attr->pValue, &key_token_len, key_token); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBKPI2 (HMAC KEY IMPORT FIRST) failed." " return:%ld, reason:%ld\n", return_code, reason_code); 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); USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNBKPI2(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &key_part_len, NULL, &key_token_len, key_token); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBKPI2 (HMAC KEY IMPORT COMPLETE) failed." " return:%ld, reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } if (analyse_cca_key_token(key_token, key_token_len, &token_type, &token_payloadbitsize, &mkvp) == FALSE || mkvp == NULL) { TRACE_ERROR("Invalid/unknown cca token has been imported\n"); return CKR_FUNCTION_FAILED; } if (check_expected_mkvp(tokdata, token_type, mkvp, &new_mk) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } rc = cca_reencipher_created_key(tokdata, object->template, key_token, key_token_len, new_mk, token_type, FALSE); if (rc != CKR_OK) { TRACE_ERROR("cca_reencipher_created_key failed: 0x%lx\n", rc); return rc; } /* Add the key object to the template */ if ((rc = build_update_attribute(object->template, CKA_IBM_OPAQUE, key_token, key_token_len))) { TRACE_DEVEL("build_update_attribute(CKA_IBM_OPAQUE) failed\n"); return rc; } } /* zero clear key value */ OPENSSL_cleanse(value_attr->pValue, value_attr->ulValueLen); TRACE_DEBUG("%s: imported object template attributes:\n", __func__); TRACE_DEBUG_DUMPTEMPL(object->template); 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 = htobe16(curve_bitlen); ecc_pair.d_length = htobe16(privlen); /* Adjust public key if necessary: there may be an indication if the public * key is compressed, uncompressed, or hybrid. */ if (curve_type == EDWARDS_CURVE) { ecc_pair.q_length = htobe16(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 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 = htobe16(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 = htobe16(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, int curve_nid, unsigned char *key_value_structure, long *key_value_structure_length) { ECC_PUBL ecc_publ; CK_RV rc = CKR_OK; BN_CTX *ctx = NULL; EC_GROUP *group = NULL; EC_POINT *point = NULL; BIGNUM *bn_x = NULL, *bn_y = NULL; int y_bit; ecc_publ.curve_type = curve_type; ecc_publ.reserved = 0x00; ecc_publ.p_bitlen = htobe16(curve_bitlen); if (curve_type == EDWARDS_CURVE) { ecc_publ.q_length = htobe16(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 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 = htobe16(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 = htobe16(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 if (publen == bitlen2bytelen(curve_bitlen) + 1) { if (pubkey[0] != POINT_CONVERSION_COMPRESSED && pubkey[0] != POINT_CONVERSION_COMPRESSED + 1) { TRACE_ERROR("Unsupported public key format\n"); return CKR_TEMPLATE_INCONSISTENT; } /* Uncompress the EC point, CCA needs it uncompressed */ ctx = BN_CTX_new(); if (ctx == NULL) { TRACE_ERROR("BN_CTX_new failed\n"); rc = CKR_FUNCTION_FAILED; goto done; } group = EC_GROUP_new_by_curve_name(curve_nid); if (group == NULL) { TRACE_ERROR("Curve %d is not supported by openssl. Cannot decompress " "public key\n", curve_nid); return CKR_CURVE_NOT_SUPPORTED; } point = EC_POINT_new(group); if (point == NULL) { TRACE_ERROR("EC_POINT_new failed\n"); rc = CKR_FUNCTION_FAILED; goto done; } bn_x = BN_bin2bn(pubkey + 1, bitlen2bytelen(curve_bitlen), NULL); bn_y = BN_new(); if (bn_x == NULL || bn_y == NULL) { TRACE_ERROR("BN_bin2bn/BN_new failed\n"); rc = CKR_FUNCTION_FAILED; goto done; } y_bit = (pubkey[0] == POINT_CONVERSION_COMPRESSED ? 0 : 1); if (!EC_POINT_set_compressed_coordinates(group, point, bn_x, y_bit, ctx)) { TRACE_ERROR("EC_POINT_set_compressed_coordinates failed\n"); rc = CKR_FUNCTION_FAILED; goto done; } if (!EC_POINT_is_on_curve(group, point, ctx)) { TRACE_ERROR("EC_POINT_is_on_curve failed\n"); rc = CKR_FUNCTION_FAILED; goto done; } if (!EC_POINT_get_affine_coordinates(group, point, bn_x, bn_y, ctx)) { TRACE_ERROR("EC_POINT_is_on_curve failed\n"); rc = CKR_FUNCTION_FAILED; goto done; } if (BN_bn2binpad(bn_x, key_value_structure + sizeof(ECC_PUBL) + 1, bitlen2bytelen(curve_bitlen)) <= 0 || BN_bn2binpad(bn_y, key_value_structure + sizeof(ECC_PUBL) + 1 + bitlen2bytelen(curve_bitlen), bitlen2bytelen(curve_bitlen)) <= 0) { TRACE_ERROR("BN_bn2binpad failed\n"); rc = CKR_FUNCTION_FAILED; goto done; } ecc_publ.q_length = htobe16(publen + bitlen2bytelen(curve_bitlen)); memcpy(key_value_structure, &ecc_publ, sizeof(ECC_PUBL)); memset(key_value_structure + sizeof(ECC_PUBL), POINT_CONVERSION_UNCOMPRESSED, 1); *key_value_structure_length = sizeof(ECC_PUBL) + be16toh(ecc_publ.q_length); } else { TRACE_ERROR("Unsupported public key length %ld\n",publen); return CKR_TEMPLATE_INCONSISTENT; } done: if (ctx) BN_CTX_free(ctx); if (group) EC_GROUP_free(group); if (point) EC_POINT_free(point); if (bn_x) BN_free(bn_x); if (bn_y) BN_free(bn_y); return rc; } /* helper function, check cca ec type, keybits and add the CKA_EC_PARAMS attribute */ static CK_RV check_cca_ec_type_and_add_params(uint8_t cca_ec_type, uint16_t cca_ec_bits, TEMPLATE *templ, uint8_t *curve_type) { CK_RV rc; CK_ULONG i; CK_KEY_TYPE key_type; for (i = 0; i < NUMEC; i++) { if ((der_ec_supported[i].curve_type == PRIME_CURVE || der_ec_supported[i].curve_type == BRAINPOOL_CURVE || der_ec_supported[i].curve_type == KOBLITZ_CURVE || der_ec_supported[i].curve_type == EDWARDS_CURVE) && !der_ec_supported[i].twisted && der_ec_supported[i].curve_type == cca_ec_type && der_ec_supported[i].prime_bits == cca_ec_bits) { /* Check if the curves fits to the key type */ rc = template_attribute_get_ulong(templ, CKA_KEY_TYPE, &key_type); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); return rc; } switch (key_type) { case CKK_EC: if (der_ec_supported[i].curve_type == EDWARDS_CURVE) { TRACE_ERROR("Edwards curves are not supported for key " "type CKK_EC.\n"); return CKR_CURVE_NOT_SUPPORTED; } break; case CKK_EC_EDWARDS: if (der_ec_supported[i].curve_type != EDWARDS_CURVE) { TRACE_ERROR("Only Edwards curves are supported for key " "type CKK_EC_EDWARDS.\n"); return CKR_CURVE_NOT_SUPPORTED; } break; default: TRACE_ERROR("Only EC or Edwards keys are supported.\n"); return CKR_KEY_TYPE_INCONSISTENT; } rc = build_update_attribute(templ, CKA_EC_PARAMS, (CK_BYTE *)der_ec_supported[i].data, der_ec_supported[i].data_size); if (rc != CKR_OK) { TRACE_DEVEL("build_update_attribute(CKA_EC_PARAMS) failed\n"); return rc; } *curve_type = der_ec_supported[i].curve_type; return CKR_OK; } } TRACE_ERROR("CCA token type with unknown curve type %hhu or length %hu\n", cca_ec_type, cca_ec_bits); return CKR_ATTRIBUTE_VALUE_INVALID; } static CK_RV import_ec_privkey(STDLL_TokData_t *tokdata, TEMPLATE *priv_templ) { CK_RV rc; CK_ATTRIBUTE *opaque_attr = NULL; enum cca_token_type token_type; unsigned int token_keybitsize; const CK_BYTE *mkvp; CK_BBOOL new_mk; #ifndef NO_PKEY CK_BBOOL cpacf_exp, false = FALSE; #endif CK_BBOOL derive = FALSE; rc = template_attribute_find(priv_templ, CKA_IBM_OPAQUE, &opaque_attr); if (rc == TRUE) { /* * This is an import of an existing secure ecc private key which * is stored in the CKA_IBM_OPAQUE attribute. */ CK_BBOOL true = TRUE; CK_BYTE *t; struct cca_key_derivation_data *ecc_info; uint16_t priv_offset; uint8_t curve_type; if (analyse_cca_key_token(opaque_attr->pValue, opaque_attr->ulValueLen, &token_type, &token_keybitsize, &mkvp) != TRUE) { TRACE_ERROR("Invalid/unknown cca token in CKA_IBM_OPAQUE attribute\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } if (token_type != sec_ecc_priv_key) { TRACE_ERROR("CCA token type in CKA_IBM_OPAQUE does not match to " "keytype CKK_EC/CKK_EC_EDWARDS\n"); return CKR_TEMPLATE_INCONSISTENT; } if (check_expected_mkvp(tokdata, token_type, mkvp, &new_mk) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } #ifndef NO_PKEY cpacf_exp = ccatok_ecc_token_is_cpacf_exportable(opaque_attr->pValue, opaque_attr->ulValueLen); rc = build_update_attribute(priv_templ, CKA_IBM_PROTKEY_EXTRACTABLE, (CK_BYTE *)&cpacf_exp, sizeof(cpacf_exp)); if (rc != CKR_OK) { TRACE_DEVEL("build_update_attribute(CKA_IBM_PROTKEY_EXTRACTABLE) " "failed\n"); return rc; } if (cpacf_exp) { rc = build_update_attribute(priv_templ, CKA_IBM_PROTKEY_NEVER_EXTRACTABLE, (CK_BYTE *)&false, sizeof(false)); if (rc != CKR_OK) { TRACE_DEVEL("build_update_attribute(CKA_IBM_PROTKEY_NEVER_EXTRACTABLE) " "failed\n"); return rc; } } #endif /* NO_PKEY */ /* * The CCA token only supports to derive DATA and CIPHER keys. So if * the ECC private key token has an ECC key derivation info section, the * to-be-derived key type must be DATA or CIPHER. * Furthermore, check if CKA_DERIVE is TRUE. If so, the ECC private key * token must have an ECC key derivation info section (requires V1 ECC * key token), and must have been generated by random (see pedigree/ * key-source field). */ ecc_info = cca_ec_ecc_key_derivation_info(opaque_attr->pValue); if (ecc_info != NULL && ecc_info->key_algorithm != CCA_AES_KEY && ecc_info->key_type != CCA_KEY_DERIVE_TYPE_DATA && ecc_info->key_type != CCA_KEY_DERIVE_TYPE_CIPHER) { TRACE_ERROR("ECC private key has an ECC key derivation info section " "(X'23'), but the key type is not AES DATA or " "AES CIPHER\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } rc = template_attribute_get_bool(priv_templ, CKA_DERIVE, &derive); if (rc == CKR_OK && derive == TRUE) { if (ecc_info == NULL) { TRACE_ERROR("CKA_DERIVE is TRUE, but ECC private key does not " "have an ECC key derivation info section (X'23')\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } priv_offset = cca_ec_privkey_offset(opaque_attr->pValue); if (((CK_BYTE *)opaque_attr->pValue)[priv_offset + CCA_EC_INTTOK_PRIVKEY_KEY_SOURCE_OFFSET] != CCA_EC_INTTOK_PRIVKEY_KEY_SOURCE_RANDOM) { TRACE_ERROR("CKA_DERIVE is TRUE, but ECC private key was not " "generated by random\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } } rc = cca_reencipher_created_key(tokdata, priv_templ, opaque_attr->pValue, opaque_attr->ulValueLen, new_mk, token_type, FALSE); if (rc != CKR_OK) { TRACE_ERROR("cca_reencipher_created_key failed: 0x%lx\n", rc); return rc; } /* check curve and add CKA_EC_PARAMS attribute */ t = opaque_attr->pValue; rc = check_cca_ec_type_and_add_params(t[8+9], token_keybitsize, priv_templ, &curve_type); if (rc != CKR_OK) return rc; /* Add/update CKA_SENSITIVE */ rc = build_update_attribute(priv_templ, CKA_SENSITIVE, &true, sizeof(CK_BBOOL)); if (rc != CKR_OK) { TRACE_DEVEL("build_update_attribute for CKA_SENSITIVE failed. rc=0x%lx\n", rc); return rc; } } else { /* * This is an import of a clear ecc private key which is to be transfered * into a CCA ECC private key. */ 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; CK_ULONG privlen = 0, publen = 0; uint8_t curve_type; uint16_t curve_bitlen; int curve_nid; /* Check if curve supported and determine curve type and bitlen */ rc = curve_supported(tokdata, priv_templ, &curve_type, &curve_bitlen, &curve_nid); if (rc != CKR_OK) { TRACE_ERROR("Curve not supported by this token.\n"); return rc; } /* * Check if CKA_DERIVE is TRUE. An ECC key imported from clear text * can not be used for ECDH. CCA allows ECDH only for randomly * generated keys. */ rc = template_attribute_get_bool(priv_templ, CKA_DERIVE, &derive); if (rc == CKR_OK && derive == TRUE) { TRACE_ERROR("CKA_DERIVE is TRUE. CCA does not allow ECDH key " "derivation with keys imported from clear\n"); return CKR_TEMPLATE_INCONSISTENT; } /* Find private key data in template */ rc = template_attribute_get_non_empty(priv_templ, CKA_VALUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); return rc; } privlen = attr->ulValueLen; privkey = attr->pValue; /* calculate the public key from the private key */ rc = template_attribute_get_non_empty(priv_templ, CKA_EC_PARAMS, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_EC_PARAMS for the key.\n"); return rc; } rc = ec_point_from_priv_key(attr->pValue, attr->ulValueLen, privkey, privlen, &pubkey, &publen); if (rc != CKR_OK) { TRACE_ERROR("ec_point_from_priv_key failed.\n"); return rc; } /* 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); free(pubkey); if (rc != CKR_OK) return rc; /* * Build key token. * An ECC key imported from clear text can not be used for ECDH. * CCA allows ECDH only for randomly generated keys. * Thus no need for keywords KEY-MGMT and ECC-VER1 here. */ 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; #ifndef NO_PKEY /* Add protected key related attributes to the rule array */ rc = ccatok_pkey_add_attrs(tokdata, priv_templ, curve_type == EDWARDS_CURVE ? CKK_EC_EDWARDS : CKK_EC, curve_type, curve_bitlen, 0, rule_array, sizeof(rule_array), (CK_ULONG *)&rule_array_count); if (rc != CKR_OK) { TRACE_ERROR("%s ccatok_pkey_add_attrs failed with rc=0x%lx\n", __func__, rc); return rc; } #endif /* NO_PKEY */ USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNDPKB(&return_code, &reason_code, &exit_data_len, exit_data, &rule_array_count, rule_array, &key_value_structure_length, key_value_structure, &private_key_name_length, private_key_name, ¶m1, param2, ¶m1, param2, ¶m1, param2, ¶m1, param2, ¶m1, param2, &key_token_length, key_token); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKB (EC KEY TOKEN BUILD) failed. return:%ld," " 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; USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNDPKI(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &key_token_length, key_token, transport_key_identifier, &target_key_token_length, target_key_token); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKI (EC KEY TOKEN IMPORT) failed." " return:%ld, reason:%ld\n", return_code, reason_code); if (is_curve_error(return_code, reason_code)) return CKR_CURVE_NOT_SUPPORTED; return CKR_FUNCTION_FAILED; } if (analyse_cca_key_token(target_key_token, target_key_token_length, &token_type, &token_keybitsize, &mkvp) == FALSE || mkvp == NULL) { TRACE_ERROR("Invalid/unknown cca token has been imported\n"); return CKR_FUNCTION_FAILED; } if (check_expected_mkvp(tokdata, token_type, mkvp, &new_mk) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } rc = cca_reencipher_created_key(tokdata, priv_templ, target_key_token, target_key_token_length, new_mk, token_type, FALSE); if (rc != CKR_OK) { TRACE_ERROR("cca_reencipher_created_key failed: 0x%lx\n", rc); return rc; } /* Add key token to template as CKA_IBM_OPAQUE */ if ((rc = build_update_attribute(priv_templ, CKA_IBM_OPAQUE, target_key_token, target_key_token_length))) { TRACE_DEVEL("build_update_attribute(CKA_IBM_OPAQUE) failed\n"); return rc; } /* zero clear key values */ OPENSSL_cleanse(privkey, privlen); } TRACE_DEBUG("%s: imported object template attributes:\n", __func__); TRACE_DEBUG_DUMPTEMPL(priv_templ); return CKR_OK; } static CK_RV import_ec_pubkey(STDLL_TokData_t *tokdata, TEMPLATE *pub_templ) { CK_RV rc; CK_ATTRIBUTE *opaque_attr = NULL; rc = template_attribute_find(pub_templ, CKA_IBM_OPAQUE, &opaque_attr); if (rc == TRUE) { /* * This is an import of an existing secure ecc public key which * is stored in the CKA_IBM_OPAQUE attribute. */ enum cca_token_type token_type; unsigned int token_keybitsize; const CK_BYTE *mkvp; CK_BYTE *t, *q; uint16_t q_len; CK_BYTE *ecpoint = NULL; CK_ULONG ecpoint_len; uint8_t curve_type; if (analyse_cca_key_token(opaque_attr->pValue, opaque_attr->ulValueLen, &token_type, &token_keybitsize, &mkvp) != TRUE) { TRACE_ERROR("Invalid/unknown cca token in CKA_IBM_OPAQUE attribute\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } if (token_type != sec_ecc_publ_key) { TRACE_ERROR("CCA token type in CKA_IBM_OPAQUE does not match to " "keytype CKK_EC/CKK_EC_EDWARDS\n"); return CKR_TEMPLATE_INCONSISTENT; } /* check curve and add CKA_EC_PARAMS attribute */ t = opaque_attr->pValue; rc = check_cca_ec_type_and_add_params(t[8+8], token_keybitsize, pub_templ, &curve_type); if (rc != CKR_OK) return rc; /* we need to add the CKA_EC_POINT attribute */ q = (CK_BYTE *)(t + 8 + 14); q_len = be16toh(*((uint16_t *)(t + 8 + 12))); if (q_len > CCATOK_EC_MAX_Q_LEN) { TRACE_ERROR("Invalid Q len %hu\n", q_len); return CKR_ATTRIBUTE_VALUE_INVALID; } if (curve_type != EDWARDS_CURVE) { rc = ber_encode_OCTET_STRING(FALSE, &ecpoint, &ecpoint_len, q, q_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_OCTET_STRING failed\n"); return rc; } } else { ecpoint = q; ecpoint_len = q_len; } rc = build_update_attribute(pub_templ, CKA_EC_POINT, ecpoint, ecpoint_len); if (curve_type != EDWARDS_CURVE) free(ecpoint); if (rc != CKR_OK) { TRACE_DEVEL("build_update_attribute(CKA_EC_POINT) failed\n"); return rc; } } else { /* * This is an import of a clear ecc public key which is to be transfered * into a CCA ECC public key. */ 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, }; long param1=0; unsigned char *param2=NULL; uint8_t curve_type; uint16_t curve_bitlen; int curve_nid; CK_BYTE *pubkey = NULL; CK_ULONG publen = 0; CK_ATTRIBUTE *attr = NULL; CK_ULONG field_len; /* Check if curve supported and determine curve type and bitlen */ rc = curve_supported(tokdata, pub_templ, &curve_type, &curve_bitlen, &curve_nid); 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_get_non_empty(pub_templ, CKA_EC_POINT, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_EC_POINT for the key.\n"); return rc; } if (curve_type != EDWARDS_CURVE) { rc = ber_decode_OCTET_STRING(attr->pValue, attr->ulValueLen, &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; } } else { pubkey = attr->pValue; publen = attr->ulValueLen; } /* 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, curve_nid, (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; USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNDPKB(&return_code, &reason_code, &exit_data_len, exit_data, &rule_array_count, rule_array, &key_value_structure_length, key_value_structure, &private_key_name_length, private_key_name, ¶m1, param2, ¶m1, param2, ¶m1, param2, ¶m1, param2, ¶m1, param2, &key_token_length, key_token); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKB (EC KEY TOKEN BUILD) failed. return:%ld," " 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_update_attribute(pub_templ, CKA_IBM_OPAQUE, key_token, key_token_length))) { TRACE_DEVEL("build_update_attribute(CKA_IBM_OPAQUE) failed\n"); return rc; } } TRACE_DEBUG("%s: imported object template attributes:\n", __func__); TRACE_DEBUG_DUMPTEMPL(pub_templ); return CKR_OK; } /* * ECDH key derivation. * CCA requires that the ECC private key used for ECDH with keyword DERIV02 * has an ECC key derivation section (X'23') that contains the type and size * of keys that can be derived with that key. * The CCA token generates or imports ECC keys with an ECC key derivation * section allowing to derive AES keys only. Thus, the derivation is restricted * to just that one key type and size that is contained in the private key's * ECC key derivation section. * For ECC key generation, the to be derived key type and size can be specified * using the CKA_DERIVE_TEMPLATE or CKA_DECAPSULATE_TEMPLATE containing * CKA_KEY_TYPE, CKA_VALUE_LEN and CKA_IBM_CCA_AES_KEY_MODE. * This information will then be added as ECC key derivation section to the * private key. The default derivation key type and size is is AES-256. * The default CCA key mode is determined by the global configuration setting. * Furthermore, CCA allows ECDH key derivation with keyword DERIV02 only * with ECC private keys that were generated by random. Keys imported from * clear can not be used for ECDH. */ static CK_RV cca_ecdh_pkcs_derive_kdf(STDLL_TokData_t *tokdata, SESSION *session, OBJECT *base_key_obj, CK_ECDH1_DERIVE_PARAMS *params, OBJECT *derived_key_obj, CK_ULONG derived_key_class, CK_ULONG derived_key_type, struct cca_hybrid_ecdh_data *hybrid_data) { long return_code, reason_code, rule_array_count, exit_data_len = 0; long private_key_name_length, pubkey_token_length, param1 = 0; unsigned char *exit_data = NULL; unsigned char *param2 = NULL; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; long key_value_structure_length, key_bit_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 pubkey_token[CCA_KEY_TOKEN_SIZE] = { 0, }; unsigned char symkey_token[CCA_MAX_AES_CIPHER_KEY_SIZE] = { 0, }; CK_ULONG symkey_token_size = sizeof(symkey_token); long symkey_token_length = sizeof(symkey_token); long shared_data_length, privkey_token_length; CK_ATTRIBUTE *opaque_attr; CK_ULONG base_key_class, base_key_type, key_len = 0; struct cca_key_derivation_data *ecc_info; CK_BYTE dummy[AES_KEY_SIZE_256] = { 0, }; CK_IBM_CCA_AES_KEY_MODE_TYPE key_mode; enum cca_token_type keytype; unsigned int keybitsize; const CK_BYTE *mkvp; CK_BBOOL new_mk; uint8_t curve_type; uint16_t curve_bitlen; int curve_nid; CK_ULONG privlen; CK_BBOOL allocated = FALSE; CK_BYTE *ecpoint = NULL; CK_ULONG ecpoint_len; CK_RV rc; UNUSED(session); if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } /* Check the ECDH params */ if (params->pPublicData == NULL || params->ulPublicDataLen == 0 || (params->ulSharedDataLen > 0 && params->pSharedData == NULL)) { TRACE_ERROR("Invalid mechanism parameter\n"); return CKR_MECHANISM_PARAM_INVALID; } switch (params->kdf) { case CKD_SHA224_KDF: case CKD_SHA256_KDF: case CKD_SHA384_KDF: case CKD_SHA512_KDF: case CKD_IBM_HYBRID_SHA224_KDF: case CKD_IBM_HYBRID_SHA256_KDF: case CKD_IBM_HYBRID_SHA384_KDF: case CKD_IBM_HYBRID_SHA512_KDF: break; default: TRACE_ERROR("CCA does not support KDFs other than " "SHA224/256/384/512\n"); return CKR_MECHANISM_PARAM_INVALID; } if (params->ulSharedDataLen > 256) { TRACE_ERROR("CCA does not support shared data > 256 bytes\n"); return CKR_MECHANISM_PARAM_INVALID; } /* Get private key token */ rc = template_attribute_get_non_empty(base_key_obj->template, CKA_IBM_OPAQUE, &opaque_attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_OPAQUE for the key.\n"); return rc; } /* Check base key: must be an EC private key */ if (!template_get_class(base_key_obj->template, &base_key_class, &base_key_type)) { TRACE_ERROR("Could not find CKA_CLASS in the template\n"); return CKR_TEMPLATE_INCOMPLETE; } if (base_key_class != CKO_PRIVATE_KEY || base_key_type != CKK_EC) { TRACE_ERROR("Base key is not an EC private key\n"); return CKR_KEY_TYPE_INCONSISTENT; } /* Check the EC curve used */ rc = curve_supported(tokdata, base_key_obj->template, &curve_type, &curve_bitlen, &curve_nid); if (rc != CKR_OK) { TRACE_ERROR("Curve not supported\n"); return rc; } rc = get_ecsiglen(base_key_obj, &privlen); if (rc != CKR_OK) { TRACE_ERROR("get_ecsiglen failed\n"); return rc; } privlen /= 2; if (derived_key_class != CKO_SECRET_KEY || derived_key_type != CKK_AES) { TRACE_ERROR("CCA can not derive keys of type other than AES\n"); return CKR_KEY_TYPE_INCONSISTENT; } /* Must have a ECC key derivation info section */ ecc_info = cca_ec_ecc_key_derivation_info(opaque_attr->pValue); if (ecc_info == NULL) { TRACE_ERROR("ECC private key does not have an ECC key derivation info " "section X'23'\n"); return CKR_KEY_FUNCTION_NOT_PERMITTED; } /* Check the derived key: Must match the ECC key derivation info */ if (ecc_info->key_algorithm != CCA_AES_KEY && ecc_info->key_type != CCA_KEY_DERIVE_TYPE_DATA && ecc_info->key_type != CCA_KEY_DERIVE_TYPE_CIPHER) { TRACE_ERROR("The EC private key can not derive keys other than AES " "DATA or AES CIPHER key tokens\n"); return CKR_KEY_TYPE_INCONSISTENT; } rc = template_attribute_get_ulong(derived_key_obj->template, CKA_VALUE_LEN, &key_len); if (rc == CKR_TEMPLATE_INCOMPLETE) key_len = privlen; /* curve can derive that many bytes */ else if (rc != CKR_OK) return rc; if (key_len != be16toh(ecc_info->key_size) / 8) { TRACE_ERROR("The EC private key can not derive keys of type other than " "AES-%u\n", be16toh(ecc_info->key_size)); return CKR_ATTRIBUTE_VALUE_INVALID; } rc = template_attribute_get_ulong(derived_key_obj->template, CKA_IBM_CCA_AES_KEY_MODE, &key_mode); if (rc == CKR_OK) { switch (key_mode) { case CK_IBM_CCA_AES_DATA_KEY: if (ecc_info->key_type != CCA_KEY_DERIVE_TYPE_DATA) { TRACE_ERROR("The EC private key can not derive keys " "other than AES DATA keys\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } break; case CK_IBM_CCA_AES_CIPHER_KEY: if (ecc_info->key_type != CCA_KEY_DERIVE_TYPE_CIPHER) { TRACE_ERROR("The EC private key can not derive keys " "other than AES CIPHER keys\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } break; default: TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } } /* Get the public key as CCA key token */ rc = ec_point_from_public_data(params->pPublicData, params->ulPublicDataLen, privlen, TRUE, &allocated, &ecpoint, &ecpoint_len); if (rc != CKR_OK) { TRACE_DEVEL("ec_point_from_public_data failed\n"); return rc; } memset(key_value_structure, 0, CCA_KEY_VALUE_STRUCT_SIZE); rc = build_public_EC_key_value_structure(ecpoint, ecpoint_len, curve_type, curve_bitlen, curve_nid, (unsigned char *) &key_value_structure, &key_value_structure_length); if (rc != CKR_OK) goto done; /* Build public key token */ rule_array_count = 1; memcpy(rule_array, "ECC-PUBL", CCA_KEYWORD_SIZE); private_key_name_length = 0; pubkey_token_length = CCA_KEY_TOKEN_SIZE; key_value_structure_length = CCA_KEY_VALUE_STRUCT_SIZE; USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNDPKB(&return_code, &reason_code, &exit_data_len, exit_data, &rule_array_count, rule_array, &key_value_structure_length, key_value_structure, &private_key_name_length, private_key_name, ¶m1, param2, ¶m1, param2, ¶m1, param2, ¶m1, param2, ¶m1, param2, &pubkey_token_length, pubkey_token); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKB (EC KEY TOKEN BUILD) failed. return:%ld," " reason:%ld\n", return_code, reason_code); if (is_curve_error(return_code, reason_code)) rc = CKR_CURVE_NOT_SUPPORTED; else rc = CKR_FUNCTION_FAILED; goto done; } /* Build the output key skeleton */ if (ecc_info->key_type != CCA_KEY_DERIVE_TYPE_DATA) { key_mode = CK_IBM_CCA_AES_DATA_KEY; rc = cca_build_aes_cipher_token(tokdata, derived_key_obj->template, symkey_token, &symkey_token_size); } else { key_mode = CK_IBM_CCA_AES_DATA_KEY; rc = cca_build_aes_data_token(tokdata, key_len, symkey_token, &symkey_token_size); } if (rc != CKR_OK) { TRACE_ERROR("Failed to build CCA key token"); goto done; } /* Build rule array for CSNDEDH */ rule_array_count = 3; memcpy(rule_array, "DERIV02 KEY-AES ", 2 * CCA_KEYWORD_SIZE); switch (params->kdf) { case CKD_SHA224_KDF: case CKD_IBM_HYBRID_SHA224_KDF: memcpy(rule_array + 2 * CCA_KEYWORD_SIZE, "SHA-224 ", (size_t)(CCA_KEYWORD_SIZE)); break; case CKD_SHA256_KDF: case CKD_IBM_HYBRID_SHA256_KDF: memcpy(rule_array + 2 * CCA_KEYWORD_SIZE, "SHA-256 ", (size_t)(CCA_KEYWORD_SIZE)); break; case CKD_SHA384_KDF: case CKD_IBM_HYBRID_SHA384_KDF: memcpy(rule_array + 2 * CCA_KEYWORD_SIZE, "SHA-384 ", (size_t)(CCA_KEYWORD_SIZE)); break; case CKD_SHA512_KDF: case CKD_IBM_HYBRID_SHA512_KDF: memcpy(rule_array + 2 * CCA_KEYWORD_SIZE, "SHA-512 ", (size_t)(CCA_KEYWORD_SIZE)); break; default: TRACE_ERROR("CCA does not support KDFs other than " "SHA224/256/384/512\n"); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } if (hybrid_data != NULL) { memcpy(rule_array + (rule_array_count * CCA_KEYWORD_SIZE) , "QSA-ECDH", CCA_KEYWORD_SIZE); rule_array_count++; memcpy(rule_array + (rule_array_count * CCA_KEYWORD_SIZE) , hybrid_data->rule, CCA_KEYWORD_SIZE); rule_array_count++; } key_bit_length = key_len * 8; shared_data_length = params->ulSharedDataLen; privkey_token_length = opaque_attr->ulValueLen; USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) RETRY_NEW_MK_BLOB_START() dll_CSNDEDH(&return_code, &reason_code, &exit_data_len, exit_data, &rule_array_count, rule_array, &privkey_token_length, opaque_attr->pValue, ¶m1, param2, &pubkey_token_length, pubkey_token, hybrid_data != NULL ? &hybrid_data->hybrid_key_len : ¶m1, hybrid_data != NULL ? hybrid_data->hybrid_key : param2, &shared_data_length, params->pSharedData, &key_bit_length, hybrid_data != NULL ? &hybrid_data->iv_len : ¶m1, hybrid_data != NULL ? hybrid_data->iv : param2, hybrid_data != NULL ? &hybrid_data->cipher_len : ¶m1, hybrid_data != NULL ? hybrid_data->cipher : param2, ¶m1, param2, ¶m1, param2, ¶m1, param2, ¶m1, param2, &symkey_token_length, symkey_token); RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, opaque_attr->pValue, opaque_attr->ulValueLen) USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDEDH (%sEC Diffie-Hellman) failed. return:%ld," " reason:%ld\n", hybrid_data != NULL ? "QSA " : "", return_code, reason_code); rc = CKR_FUNCTION_FAILED; if (return_code == 8 && reason_code >= 2243 && reason_code <= 2246) rc = CKR_KEY_FUNCTION_NOT_PERMITTED; if (return_code == 8 && reason_code == 2149) rc = CKR_KEY_SIZE_RANGE; if (return_code == 8 && reason_code == 90) rc = CKR_FUNCTION_CANCELED; /* Control point prohibits function */ goto done; } if (analyse_cca_key_token(symkey_token, symkey_token_length, &keytype, &keybitsize, &mkvp) == FALSE || mkvp == NULL) { TRACE_ERROR("Invalid/unknown cca token has been unwrapped\n"); rc = CKR_FUNCTION_FAILED; goto done; } if (check_expected_mkvp(tokdata, keytype, mkvp, &new_mk) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); rc = CKR_DEVICE_ERROR; goto done; } rc = cca_reencipher_created_key(tokdata, derived_key_obj->template, symkey_token, symkey_token_length, new_mk, keytype, FALSE); if (rc != CKR_OK) { TRACE_ERROR("cca_reencipher_created_key failed: 0x%lx\n", rc); goto done; } /* Add CKA_IBM_OPAQUE */ rc = build_update_attribute(derived_key_obj->template, CKA_IBM_OPAQUE, symkey_token, symkey_token_length); if (rc != CKR_OK) { TRACE_ERROR("%s build_update_attribute failed with rc=0x%lx\n", __func__, rc); goto done; } /* Add CKA_VALUE as all zeros */ rc = build_update_attribute(derived_key_obj->template, CKA_VALUE, dummy, key_len); if (rc != CKR_OK) { TRACE_ERROR("%s build_update_attribute failed with rc=0x%lx\n", __func__, rc); goto done; } /* Add CKA_VALUE_LEN */ rc = build_update_attribute(derived_key_obj->template, CKA_VALUE_LEN, (CK_BYTE *)&key_len, sizeof(key_len)); if (rc != CKR_OK) { TRACE_ERROR("%s build_update_attribute failed with rc=0x%lx\n", __func__, rc); goto done; } /* Add CKA_IBM_CCA_AES_KEY_MODE */ rc = build_update_attribute(derived_key_obj->template, CKA_IBM_CCA_AES_KEY_MODE, (CK_BYTE *)&key_mode, sizeof(key_mode)); if (rc != CKR_OK) { TRACE_ERROR("%s build_update_attribute failed with rc=0x%lx\n", __func__, rc); goto done; } done: if (allocated && ecpoint != NULL) free(ecpoint); return rc; } CK_RV token_specific_ecdh_pkcs_derive_kdf(STDLL_TokData_t *tokdata, SESSION *session, OBJECT *base_key_obj, CK_ECDH1_DERIVE_PARAMS *params, OBJECT *derived_key_obj, CK_ULONG derived_key_class, CK_ULONG derived_key_type, CK_BBOOL cofactor_mode) { if (cofactor_mode) { TRACE_ERROR("ECDH with cofactor mode is not supported. \n"); return CKR_MECHANISM_INVALID; } return cca_ecdh_pkcs_derive_kdf(tokdata, session, base_key_obj, params, derived_key_obj, derived_key_class, derived_key_type, NULL); } static CK_RV build_pqc_import_key_value_struct( CK_MECHANISM_TYPE mech, CK_BBOOL private_key, CK_IBM_CCA_ML_DSA_KEY_MODE_TYPE mode, const struct pqc_oid *oid, TEMPLATE *templ, unsigned char *key_value_structure, long *key_value_structure_length) { CK_RV rc; uint8_t clear_format; uint16_t clear_len; long ofs = *key_value_structure_length; #if OPENSSL_VERSION_PREREQ(3, 0) CK_ATTRIBUTE val_attr = { 0, NULL, 0 }; #endif CK_ULONG len; rc = build_pqc_key_value_struct(mech, mode, oid, key_value_structure, &ofs); if (rc != CKR_OK) { TRACE_ERROR("build_pqc_key_value_struct failed: 0x%lx\n", rc); return rc; } clear_format = private_key ? CCA_QSA_CLEAR_FORMAT_KAT : CCA_QSA_CLEAR_FORMAT_PUB_ONLY; memcpy(&key_value_structure[CCA_PKB_QSA_CLEAR_FORMAT_OFFSET], &clear_format, sizeof(uint8_t)); if (private_key) { len = *key_value_structure_length - ofs; rc = pqc_pack_priv_key(templ, oid, mech, key_value_structure + ofs, &len); if (rc != CKR_OK) { TRACE_ERROR("pqc_pack_priv_key failed: 0x%lx\n", rc); return rc; } ofs += len; /* * The private key of ML-KEM includes the public key already, * for the ML-DSA mechanisms the public key must be appended. * CKM_IBM_DILITHIUM and CKM_IBM_ML_DSA_KEY_PAIR_GEN have * individual public key attributes that are usually also contained * in the private key template. Try to unpack the publick key from * there. If it fails, or for CKM_ML_DSA_KEY_PAIR_GEN, try to * calculate the public key via OpenSSL. */ switch (mech) { case CKM_IBM_DILITHIUM: case CKM_IBM_ML_DSA_KEY_PAIR_GEN: len = *key_value_structure_length - ofs; rc = pqc_pack_pub_key(templ, oid, mech, key_value_structure + ofs, &len); if (rc == CKR_OK) { ofs += len; break; } /* Fallthrough */ case CKM_ML_DSA_KEY_PAIR_GEN: #if OPENSSL_VERSION_PREREQ(3, 0) rc = openssl_specific_pqc_get_pub_key_from_priv_key(templ, oid, mech, &val_attr); if (rc != CKR_OK) { TRACE_ERROR("openssl_specific_pqc_get_pub_key_from_priv_key " "failed: 0x%lx.\n", rc); return CKR_KEY_SIZE_RANGE; /* priv only not supported */ } if (val_attr.ulValueLen != oid->len_info.ml_dsa.rho_len + oid->len_info.ml_dsa.t1_len) { TRACE_ERROR("Public key length not as expected\n"); free(val_attr.pValue); return CKR_FUNCTION_FAILED; } memcpy(key_value_structure + ofs, val_attr.pValue, val_attr.ulValueLen); ofs += val_attr.ulValueLen; free(val_attr.pValue); #else TRACE_ERROR("OpenSSL < 3.0.0: Can not calc pub key from priv " "key\n"); return CKR_KEY_SIZE_RANGE; /* priv only not supported */ #endif break; default: break; } } else { len = *key_value_structure_length - ofs; rc = pqc_pack_pub_key(templ, oid, mech, key_value_structure + ofs, &len); if (rc != CKR_OK) { TRACE_ERROR("pqc_pack_pub_key failed: 0x%lx\n", rc); return rc; } ofs += len; } clear_len = htobe16(ofs - CCA_QSA_KEY_VALUE_STRUCT_SIZE); memcpy(key_value_structure + CCA_PKB_QSA_CLEAR_LEN_OFFSET, &clear_len, sizeof(uint16_t)); *key_value_structure_length = ofs; return CKR_OK; } static const struct pqc_oid *get_pqc_oid_from_algo_info(uint8_t algo_id, uint16_t algo_params, CK_MECHANISM_TYPE mech) { const struct pqc_oid *pqcs = NULL; CK_ULONG keyform = 0; switch (algo_id) { case CCA_QSA_ALGO_DILITHIUM_ROUND_2: if (mech != CKM_IBM_DILITHIUM) return NULL; pqcs = dilithium_oids; switch (algo_params) { case CCA_QSA_ALGO_DILITHIUM_65: keyform = CK_IBM_DILITHIUM_KEYFORM_ROUND2_65; break; case CCA_QSA_ALGO_DILITHIUM_87: keyform = CK_IBM_DILITHIUM_KEYFORM_ROUND2_87; break; } break; case CCA_QSA_ALGO_DILITHIUM_ROUND_3: if (mech != CKM_IBM_DILITHIUM) return NULL; pqcs = dilithium_oids; switch (algo_params) { case CCA_QSA_ALGO_DILITHIUM_65: keyform = CK_IBM_DILITHIUM_KEYFORM_ROUND3_65; break; case CCA_QSA_ALGO_DILITHIUM_87: keyform = CK_IBM_DILITHIUM_KEYFORM_ROUND3_87; break; } break; case CCA_QSA_ALGO_ML_DSA_PURE: case CCA_QSA_ALGO_ML_DSA_PRE_HASH: if (algo_id == CCA_QSA_ALGO_ML_DSA_PURE && mech != CKM_IBM_ML_DSA_KEY_PAIR_GEN && mech != CKM_ML_DSA_KEY_PAIR_GEN) return NULL; if (algo_id == CCA_QSA_ALGO_ML_DSA_PRE_HASH && mech != CKM_ML_DSA_KEY_PAIR_GEN) return NULL; pqcs = ml_dsa_oids; switch (algo_params) { case CCA_QSA_ALGO_ML_DSA_44: keyform = CKP_ML_DSA_44; break; case CCA_QSA_ALGO_ML_DSA_65: keyform = CKP_ML_DSA_65; break; case CCA_QSA_ALGO_ML_DSA_87: keyform = CKP_ML_DSA_87; break; } break; case CCA_QSA_ALGO_ML_KEM: if (mech != CKM_IBM_ML_KEM_KEY_PAIR_GEN) return NULL; pqcs = ml_kem_oids; switch (algo_params) { case CCA_QSA_ALGO_ML_KEM_512: keyform = CKP_IBM_ML_KEM_512; break; case CCA_QSA_ALGO_ML_KEM_768: keyform = CKP_IBM_ML_KEM_768; break; case CCA_QSA_ALGO_ML_KEM_1024: keyform = CKP_IBM_ML_KEM_1024; break; } break; default: return NULL; } return find_pqc_by_keyform(pqcs, keyform); } static CK_RV import_pqc_privkey(STDLL_TokData_t *tokdata, TEMPLATE *priv_templ, CK_KEY_TYPE keytype) { CK_RV rc; CK_ATTRIBUTE *opaque_attr = NULL; const struct pqc_oid *oid = NULL; enum cca_token_type token_type; unsigned int token_keybitsize; const CK_BYTE *mkvp; CK_BBOOL new_mk; CK_MECHANISM_TYPE mech; CK_ATTRIBUTE_TYPE priv_seed_attr = (CK_ATTRIBUTE_TYPE)-1; switch (keytype) { case CKK_IBM_PQC_DILITHIUM: mech = CKM_IBM_DILITHIUM; break; case CKK_IBM_ML_DSA: mech = CKM_IBM_ML_DSA_KEY_PAIR_GEN; priv_seed_attr = CKA_IBM_ML_DSA_PRIVATE_SEED; break; case CKK_IBM_ML_KEM: mech = CKM_IBM_ML_KEM_KEY_PAIR_GEN; priv_seed_attr = CKA_IBM_ML_KEM_PRIVATE_SEED; break; case CKK_ML_DSA: mech = CKM_ML_DSA_KEY_PAIR_GEN; priv_seed_attr = CKA_SEED; break; default: return CKR_KEY_TYPE_INCONSISTENT; } rc = template_attribute_find(priv_templ, CKA_IBM_OPAQUE, &opaque_attr); if (rc == TRUE) { /* * This is an import of an existing secure QSA private key which * is stored in the CKA_IBM_OPAQUE attribute. */ CK_BBOOL true = TRUE; uint8_t algo_id; uint16_t privsec_len, pubsec_len, algo_params; CK_BYTE *t, *pub; CK_IBM_CCA_ML_DSA_KEY_MODE_TYPE mode; CK_ATTRIBUTE val_attr = { 0, NULL, 0 }; CK_BYTE *spki = NULL; CK_ULONG spki_len = 0; if (analyse_cca_key_token(opaque_attr->pValue, opaque_attr->ulValueLen, &token_type, &token_keybitsize, &mkvp) != TRUE) { TRACE_ERROR("Invalid/unknown cca token in CKA_IBM_OPAQUE " "attribute\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } if (token_type != sec_qsa_priv_key) { TRACE_ERROR("CCA token type in CKA_IBM_OPAQUE does not match to " "keytype %lu\n", keytype); return CKR_TEMPLATE_INCONSISTENT; } if (check_expected_mkvp(tokdata, token_type, mkvp, &new_mk) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } rc = cca_reencipher_created_key(tokdata, priv_templ, opaque_attr->pValue, opaque_attr->ulValueLen, new_mk, token_type, FALSE); if (rc != CKR_OK) { TRACE_ERROR("cca_reencipher_created_key failed: 0x%lx\n", rc); return rc; } /* check PQC variant and add keyform and mode attributes */ t = opaque_attr->pValue; privsec_len = be16toh(*((uint16_t *) (t + CCA_QSA_INTTOK_PRIVKEY_OFFSET + 2))); if (CCA_QSA_INTTOK_PRIVKEY_OFFSET + privsec_len + CCA_QSA_EXTTOK_PUBLKEY_OFFSET > (int)opaque_attr->ulValueLen) { TRACE_DEVEL("CCA QSA key token has invalid priv section len or " "token size\n"); return CKR_FUNCTION_FAILED; } pub = t + CCA_QSA_INTTOK_PRIVKEY_OFFSET + privsec_len; pubsec_len = be16toh(*((uint16_t *)(pub + 2))); if (CCA_QSA_INTTOK_PRIVKEY_OFFSET + privsec_len + pubsec_len > (int)opaque_attr->ulValueLen) { TRACE_DEVEL("CCA QSA key token has invalid pub section len or " "token size\n"); return CKR_FUNCTION_FAILED; } algo_id = t[CCA_QSA_INTTOK_PRIVKEY_OFFSET + CCA_QSA_INTTOK_ALGO_ID_OFFSET]; algo_params = be16toh(*((uint16_t *)(t + CCA_QSA_INTTOK_PRIVKEY_OFFSET + CCA_QSA_INTTOK_ALGO_PARAMS_OFFSET))); oid = get_pqc_oid_from_algo_info(algo_id, algo_params, mech); if (oid == NULL) { TRACE_ERROR("Invalid/unknown algorithm ID in CCA QSA token\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } if (!cca_pqc_strength_supported(tokdata, mech, oid->keyform)) { TRACE_DEVEL("PQC keyform %lu not supported by CCA\n", oid->keyform); return CKR_KEY_SIZE_RANGE; } rc = pqc_add_keyform_mode(priv_templ, oid, mech); if (rc != CKR_OK) { TRACE_ERROR("pqc_add_keyform_mode failed\n"); return rc; } switch (keytype) { case CKK_ML_DSA: /* Add ML-DSA mode attributes to template */ switch (algo_id) { case CCA_QSA_ALGO_ML_DSA_PURE: mode = CK_IBM_CCA_ML_DSA_PURE_KEY; break; case CCA_QSA_ALGO_ML_DSA_PRE_HASH: mode = CK_IBM_CCA_ML_DSA_PREHASH_KEY; break; default: TRACE_ERROR("Invalid/unknown algorithm ID in CCA QSA token\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } rc = build_update_attribute(priv_templ, CKA_IBM_CCA_ML_DSA_KEY_MODE, (CK_BYTE *)&mode, sizeof(mode)); if (rc != CKR_OK) { TRACE_DEVEL("build_update_attribute " "(CKA_IBM_CCA_ML_DSA_KEY_MODE) failed\n"); return rc; } /* * Private key does not have the public key components, so build * SPKI from public key now from the CCA public key section. */ val_attr.pValue = pub + CCA_QSA_EXTTOK_PAYLOAD_OFFSET; val_attr.ulValueLen = pubsec_len - CCA_QSA_EXTTOK_PAYLOAD_OFFSET; val_attr.type = CKA_VALUE; rc = ber_encode_ML_DSA_PublicKey(FALSE, &spki, &spki_len, oid->oid, oid->oid_len, &val_attr); if (rc != CKR_OK) { TRACE_ERROR("ber_encode_ML_DSA_PublicKey failed.\n"); return rc; } rc = build_update_attribute(priv_templ, CKA_PUBLIC_KEY_INFO, spki, spki_len); free(spki); if (rc != CKR_OK) { TRACE_DEVEL("build_update_attribute " "(CKA_PUBLIC_KEY_INFO) failed\n"); return rc; } break; default: /* Extract public key attributes, common code will build SPKI. */ rc = pqc_unpack_pub_key(pub + CCA_QSA_EXTTOK_PAYLOAD_OFFSET, pubsec_len - CCA_QSA_EXTTOK_PAYLOAD_OFFSET, oid, mech, priv_templ); if (rc != CKR_OK) { TRACE_ERROR("pqc_unpack_pub_key failed\n"); return rc; } break; } /* Add/update CKA_SENSITIVE */ rc = build_update_attribute(priv_templ, CKA_SENSITIVE, &true, sizeof(CK_BBOOL)); if (rc != CKR_OK) { TRACE_DEVEL("build_update_attribute for CKA_SENSITIVE failed. " "rc=0x%lx\n", rc); return rc; } } else { /* * This is an import of a clear PQC private key * which is to be transferred into a CCA QSA private key. */ 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, regeneration_data_len; 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_ATTRIBUTE *attr = NULL, *priv_seed = NULL; CK_ULONG priv_seed_len = 0; CK_IBM_CCA_ML_DSA_KEY_MODE_TYPE mode = CK_IBM_CCA_ML_DSA_PURE_KEY; switch (keytype) { case CKK_IBM_DILITHIUM: case CKK_IBM_ML_DSA: case CKK_IBM_ML_KEM: /* A clear IBM PQC key must either have a CKA_VALUE * containing the PKCS#8 encoded private key, or must have a * keyform/mode value and the individual attributes */ if (template_attribute_find(priv_templ, CKA_VALUE, &attr) == TRUE && attr->ulValueLen > 0 && attr->pValue != NULL) { /* Private key in PKCS#8 form is present in CKA_VALUE */ rc = pqc_priv_unwrap(priv_templ, keytype, attr->pValue, attr->ulValueLen, FALSE); if (rc != CKR_OK) { TRACE_ERROR("Failed to decode private key from " "CKA_VALUE.\n"); return rc; } } break; default: /* ML-DSA has raw key components in CKA_VALUE */ break; } oid = pqc_get_keyform_mode(priv_templ, mech); if (oid == NULL) { TRACE_ERROR("%s Failed to determine PQC OID\n", __func__); return CKR_TEMPLATE_INCOMPLETE; } if (!cca_pqc_strength_supported(tokdata, mech, oid->keyform)) { TRACE_DEVEL("PQC keyform %lu not supported by CCA\n", oid->keyform); return CKR_KEY_SIZE_RANGE; } switch (keytype) { case CKK_ML_DSA: rc = cca_get_and_set_ml_dsa_key_mode(tokdata, priv_templ, &mode); if (rc != CKR_OK) { TRACE_ERROR("cca_get_and_set_ml_dsa_key_mode failed: 0x%lx\n", rc); return rc; } break; default: break; } /* The private seed attribute might be available */ if (priv_seed_attr != (CK_ATTRIBUTE_TYPE)-1 && template_attribute_find(priv_templ, priv_seed_attr, &priv_seed) == TRUE && priv_seed->ulValueLen > 0 && priv_seed->pValue != NULL) { /* Use private seed for import */ switch (keytype) { case CKK_IBM_ML_DSA: case CKK_ML_DSA: priv_seed_len = oid->len_info.ml_dsa.priv_seed_len; break; case CKK_IBM_ML_KEM: priv_seed_len = oid->len_info.ml_kem.priv_seed_len; break; default: return CKR_KEY_TYPE_INCONSISTENT; } if (priv_seed->ulValueLen != priv_seed_len) { TRACE_ERROR("Private seed length is invalid\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } key_value_structure_length = CCA_QSA_KEY_VALUE_STRUCT_SIZE; rc = build_pqc_key_value_struct(mech, mode, oid, key_value_structure, &key_value_structure_length); if (rc != CKR_OK) { TRACE_ERROR("build_pqc_key_value_struct failed: 0x%lx\n", rc); return rc; } } else { priv_seed = NULL; /* Build key_value_structure */ key_value_structure_length = CCA_KEY_VALUE_STRUCT_SIZE; rc = build_pqc_import_key_value_struct( mech, TRUE, mode, oid, priv_templ, (unsigned char *)&key_value_structure, &key_value_structure_length); if (rc != CKR_OK) { TRACE_ERROR("build_pqc_import_key_value_struct failed: " "0x%lx\n", rc); return rc; } } /* Build key token */ switch (keytype) { case CKK_IBM_PQC_DILITHIUM: case CKK_IBM_ML_DSA: case CKK_ML_DSA: rule_array_count = 2; memcpy(rule_array, "QSA-PAIRU-DIGSIG", CCA_KEYWORD_SIZE * 2); break; case CKK_IBM_ML_KEM: rule_array_count = 2; memcpy(rule_array, "QSA-PAIRU-DATENC", CCA_KEYWORD_SIZE * 2); break; default: return CKR_KEY_TYPE_INCONSISTENT; } private_key_name_length = 0; key_token_length = CCA_KEY_TOKEN_SIZE; USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNDPKB(&return_code, &reason_code, &exit_data_len, exit_data, &rule_array_count, rule_array, &key_value_structure_length, key_value_structure, &private_key_name_length, private_key_name, ¶m1, param2, ¶m1, param2, ¶m1, param2, ¶m1, param2, ¶m1, param2, &key_token_length, key_token); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKB (QSA KEY TOKEN BUILD) failed. return:%ld," " reason:%ld\n", return_code, reason_code); if (return_code == 8 && reason_code == 998) return CKR_KEY_SIZE_RANGE; return CKR_FUNCTION_FAILED; } if (priv_seed != NULL) { /* Generate a PKA key using the seed as regeneration data */ rule_array_count = 2; memcpy(rule_array, "MASTER RAWSEED ", CCA_KEYWORD_SIZE * 2); regeneration_data_len = priv_seed->ulValueLen; target_key_token_length = CCA_KEY_TOKEN_SIZE; USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNDPKG(&return_code, &reason_code, &exit_data_len, exit_data, &rule_array_count, rule_array, ®eneration_data_len, priv_seed->pValue, &key_token_length, key_token, transport_key_identifier, &target_key_token_length, target_key_token); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKG (QSA KEY RE-GENERATE) failed." " return:%ld, reason:%ld\n", return_code, reason_code); if (return_code == 8 && reason_code == 998) return CKR_KEY_SIZE_RANGE; return CKR_FUNCTION_FAILED; } } else { /* Now import the PKA key token */ rule_array_count = 1; memcpy(rule_array, "QSA ", (size_t)(CCA_KEYWORD_SIZE)); key_token_length = CCA_KEY_TOKEN_SIZE; target_key_token_length = CCA_KEY_TOKEN_SIZE; USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNDPKI(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &key_token_length, key_token, transport_key_identifier, &target_key_token_length, target_key_token); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKI (QSA KEY TOKEN IMPORT) failed. " "return:%ld, reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } } if (analyse_cca_key_token(target_key_token, target_key_token_length, &token_type, &token_keybitsize, &mkvp) == FALSE || mkvp == NULL) { TRACE_ERROR("Invalid/unknown cca token has been imported\n"); return CKR_FUNCTION_FAILED; } if (check_expected_mkvp(tokdata, token_type, mkvp, &new_mk) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } rc = cca_reencipher_created_key(tokdata, priv_templ, target_key_token, target_key_token_length, new_mk, token_type, FALSE); if (rc != CKR_OK) { TRACE_ERROR("cca_reencipher_created_key failed: 0x%lx\n", rc); return rc; } /* Add required attributes to template */ rc = token_create_pqc_privkey(mech, priv_templ, oid, target_key_token_length, target_key_token); if (rc != CKR_OK) { TRACE_DEVEL("token_create_pqc_privkey failed: %lu\n", rc); return rc; } /* zeroize key values */ if (attr != NULL && attr->pValue != NULL && attr->ulValueLen > 0) OPENSSL_cleanse(attr->pValue, attr->ulValueLen); switch (keytype) { case CKK_IBM_PQC_DILITHIUM: case CKK_IBM_ML_DSA: cleanse_attribute(priv_templ, CKA_IBM_ML_DSA_SEED); cleanse_attribute(priv_templ, CKA_IBM_ML_DSA_TR); cleanse_attribute(priv_templ, CKA_IBM_ML_DSA_S1); cleanse_attribute(priv_templ, CKA_IBM_ML_DSA_S2); cleanse_attribute(priv_templ, CKA_IBM_ML_DSA_T0); cleanse_attribute(priv_templ, CKA_IBM_ML_DSA_PRIVATE_SEED); break; case CKK_IBM_ML_KEM: cleanse_attribute(priv_templ, CKA_IBM_ML_KEM_SK); cleanse_attribute(priv_templ, CKA_IBM_ML_KEM_PRIVATE_SEED); break; case CKK_ML_DSA: cleanse_attribute(priv_templ, CKA_VALUE); cleanse_attribute(priv_templ, CKA_SEED); break; } } TRACE_DEBUG("%s: imported object template attributes:\n", __func__); TRACE_DEBUG_DUMPTEMPL(priv_templ); return CKR_OK; } static CK_RV import_pqc_pubkey(STDLL_TokData_t *tokdata, TEMPLATE *pub_templ, CK_KEY_TYPE keytype) { CK_RV rc; CK_ATTRIBUTE *opaque_attr = NULL; const struct pqc_oid *oid = NULL; CK_BYTE *spki = NULL; CK_ULONG spki_len = 0; CK_MECHANISM_TYPE mech; switch (keytype) { case CKK_IBM_PQC_DILITHIUM: mech = CKM_IBM_DILITHIUM; break; case CKK_IBM_ML_DSA: mech = CKM_IBM_ML_DSA_KEY_PAIR_GEN; break; case CKK_IBM_ML_KEM: mech = CKM_IBM_ML_KEM_KEY_PAIR_GEN; break; case CKK_ML_DSA: mech = CKM_ML_DSA_KEY_PAIR_GEN; break; default: return CKR_KEY_TYPE_INCONSISTENT; } rc = template_attribute_find(pub_templ, CKA_IBM_OPAQUE, &opaque_attr); if (rc == TRUE) { /* * This is an import of an existing secure QSA public key which * is stored in the CKA_IBM_OPAQUE attribute. */ enum cca_token_type token_type; unsigned int token_keybitsize; const CK_BYTE *mkvp; uint8_t algo_id; uint16_t pubsec_len, algo_params; CK_BYTE *t; CK_IBM_CCA_ML_DSA_KEY_MODE_TYPE mode; if (analyse_cca_key_token(opaque_attr->pValue, opaque_attr->ulValueLen, &token_type, &token_keybitsize, &mkvp) != TRUE) { TRACE_ERROR("Invalid/unknown cca token in CKA_IBM_OPAQUE " "attribute\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } if (token_type != sec_qsa_publ_key) { TRACE_ERROR("CCA token type in CKA_IBM_OPAQUE does not match to " "keytype %lu\n", keytype); return CKR_TEMPLATE_INCONSISTENT; } /* check PQC variant and add keyform and mode attributes */ t = opaque_attr->pValue; pubsec_len = be16toh(*((uint16_t *)(t + CCA_QSA_EXTTOK_PUBLKEY_OFFSET + 2))); if (pubsec_len + CCA_QSA_EXTTOK_PUBLKEY_OFFSET > (int)opaque_attr->ulValueLen) { TRACE_DEVEL("CCA QSA key token has invalid pub section len or " "token size\n"); return CKR_FUNCTION_FAILED; } algo_id = t[CCA_QSA_EXTTOK_PUBLKEY_OFFSET + CCA_QSA_EXTTOK_ALGO_ID_OFFSET]; algo_params = be16toh(*((uint16_t *)(t + CCA_QSA_EXTTOK_PUBLKEY_OFFSET + CCA_QSA_EXTTOK_ALGO_PARAMS_OFFSET))); oid = get_pqc_oid_from_algo_info(algo_id, algo_params, mech); if (oid == NULL) { TRACE_ERROR("Invalid/unknown algorithm ID in CCA QSA token\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } if (!cca_pqc_strength_supported(tokdata, mech, oid->keyform)) { TRACE_DEVEL("PQC keyform %lu not supported by CCA\n", oid->keyform); return CKR_KEY_SIZE_RANGE; } rc = pqc_add_keyform_mode(pub_templ, oid, mech); if (rc != CKR_OK) { TRACE_ERROR("pqc_add_keyform_mode failed\n"); return rc; } switch (keytype) { case CKK_ML_DSA: /* Add ML-DSA mode attributes to template */ switch (algo_id) { case CCA_QSA_ALGO_ML_DSA_PURE: mode = CK_IBM_CCA_ML_DSA_PURE_KEY; break; case CCA_QSA_ALGO_ML_DSA_PRE_HASH: mode = CK_IBM_CCA_ML_DSA_PREHASH_KEY; break; default: TRACE_ERROR("Invalid/unknown algorithm ID in CCA QSA token\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } rc = build_update_attribute(pub_templ, CKA_IBM_CCA_ML_DSA_KEY_MODE, (CK_BYTE *)&mode, sizeof(mode)); if (rc != CKR_OK) { TRACE_DEVEL("build_update_attribute " "(CKA_IBM_CCA_ML_DSA_KEY_MODE) failed\n"); return rc; } break; default: break; } /* Extract public key attributes */ rc = pqc_unpack_pub_key(t + CCA_QSA_EXTTOK_PUBLKEY_OFFSET + CCA_QSA_EXTTOK_PAYLOAD_OFFSET, pubsec_len - CCA_QSA_EXTTOK_PAYLOAD_OFFSET, oid, mech, pub_templ); if (rc != CKR_OK) { TRACE_ERROR("pqc_unpack_pub_key failed\n"); return rc; } switch (keytype) { case CKK_IBM_DILITHIUM: case CKK_IBM_ML_DSA: case CKK_IBM_ML_KEM: /* Add SPKI as CKA_VALUE to public template */ rc = pqc_publ_get_spki(pub_templ, keytype, FALSE, &spki, &spki_len, FALSE); if (rc != CKR_OK) { TRACE_ERROR("pqc_publ_get_spki failed\n"); return rc; } rc = build_update_attribute(pub_templ, CKA_VALUE, spki, spki_len); free(spki); if (rc != CKR_OK) { TRACE_ERROR("build_update_attribute for CKA_VALUE failed rv=0x%lx\n", rc); return rc; } break; default: break; } } else { /* * This is an import of a clear PQC public key which * is to be transferred into a CCA QSA public key. */ 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, }; long param1 = 0; unsigned char *param2 = NULL; CK_ATTRIBUTE *attr = NULL; CK_IBM_CCA_ML_DSA_KEY_MODE_TYPE mode = CK_IBM_CCA_ML_DSA_PURE_KEY; switch (keytype) { case CKK_IBM_DILITHIUM: case CKK_IBM_ML_DSA: case CKK_IBM_ML_KEM: /* A clear IBM PQC key must either have a CKA_VALUE * containing the SPKI encoded public key, or must have a * keyform/mode value and the individual attributes */ if (template_attribute_find(pub_templ, CKA_VALUE, &attr) == TRUE && attr->ulValueLen > 0 && attr->pValue != NULL) { /* Public key in SPKI form is present in CKA_VALUE */ rc = pqc_priv_unwrap_get_data(pub_templ, keytype, attr->pValue, attr->ulValueLen, FALSE); if (rc != CKR_OK) { TRACE_ERROR("Failed to decode public key from CKA_VALUE\n"); return rc; } } else { /* Add SPKI as CKA_VALUE to public template */ rc = pqc_publ_get_spki(pub_templ, keytype, FALSE, &spki, &spki_len, FALSE); if (rc != CKR_OK) { TRACE_ERROR("pqc_publ_get_spki failed\n"); return rc; } rc = build_update_attribute(pub_templ, CKA_VALUE, spki, spki_len); free(spki); if (rc != CKR_OK) { TRACE_ERROR("build_update_attribute for CKA_VALUE failed " "rv=0x%lx\n", rc); return rc; } } break; default: /* ML-DSA has raw key components in CKA_VALUE */ break; } oid = pqc_get_keyform_mode(pub_templ, mech); if (oid == NULL) { TRACE_ERROR("%s Failed to determine PQC OID\n", __func__); return CKR_TEMPLATE_INCOMPLETE; } if (!cca_pqc_strength_supported(tokdata, mech, oid->keyform)) { TRACE_DEVEL("PQC keyform %lu not supported by CCA\n", oid->keyform); return CKR_KEY_SIZE_RANGE; } rc = pqc_add_keyform_mode(pub_templ, oid, mech); if (rc != CKR_OK) { TRACE_ERROR("pqc_add_keyform_mode failed\n"); return rc; } switch (keytype) { case CKK_ML_DSA: rc = cca_get_and_set_ml_dsa_key_mode(tokdata, pub_templ, &mode); if (rc != CKR_OK) { TRACE_ERROR("cca_get_and_set_ml_dsa_key_mode failed: 0x%lx\n", rc); return rc; } break; default: break; } /* Build key_value_structure */ key_value_structure_length = CCA_KEY_VALUE_STRUCT_SIZE; rc = build_pqc_import_key_value_struct( mech, FALSE, mode, oid, pub_templ, (unsigned char *)&key_value_structure, &key_value_structure_length); if (rc != CKR_OK) { TRACE_ERROR("build_pqc_import_key_value_struct failed: " "0x%lx\n", rc); return rc; } /* Build key token */ switch (keytype) { case CKK_IBM_PQC_DILITHIUM: case CKK_IBM_ML_DSA: case CKK_ML_DSA: rule_array_count = 2; memcpy(rule_array, "QSA-PUBLU-DIGSIG", CCA_KEYWORD_SIZE * 2); break; case CKK_IBM_ML_KEM: rule_array_count = 2; memcpy(rule_array, "QSA-PUBLU-DATENC", CCA_KEYWORD_SIZE * 2); break; default: return CKR_KEY_TYPE_INCONSISTENT; } private_key_name_length = 0; key_token_length = CCA_KEY_TOKEN_SIZE; USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNDPKB(&return_code, &reason_code, &exit_data_len, exit_data, &rule_array_count, rule_array, &key_value_structure_length, key_value_structure, &private_key_name_length, private_key_name, ¶m1, param2, ¶m1, param2, ¶m1, param2, ¶m1, param2, ¶m1, param2, &key_token_length, key_token); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKB (QSA KEY TOKEN BUILD) failed. return:%ld," " reason:%ld\n", return_code, reason_code); if (return_code == 8 && reason_code == 998) return CKR_KEY_SIZE_RANGE; 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_update_attribute(pub_templ, CKA_IBM_OPAQUE, key_token, key_token_length))) { TRACE_DEVEL("build_update_attribute(CKA_IBM_OPAQUE) failed\n"); return rc; } } TRACE_DEBUG("%s: imported object template attributes:\n", __func__); TRACE_DEBUG_DUMPTEMPL(pub_templ); 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(sess); if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } if (!object) { TRACE_ERROR("Invalid argument\n"); return CKR_FUNCTION_FAILED; } /* we only deal with key objects here */ rc = template_attribute_get_ulong(object->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { // not a key, so nothing to do. Just return. TRACE_DEVEL("object not a key, no need to import.\n"); return CKR_OK; } /* CKA_CLASS is mandatory */ rc = template_attribute_get_ulong(object->template, CKA_CLASS, &keyclass); if (rc != CKR_OK) { TRACE_ERROR("object has no CKA_CLASS value %s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); return CKR_TEMPLATE_INCOMPLETE; } switch (keytype) { case CKK_RSA: switch (keyclass) { case CKO_PUBLIC_KEY: // do import public key and create opaque object rc = import_rsa_pubkey(tokdata, object->template); if (rc != CKR_OK) { TRACE_DEVEL("RSA public key import failed, rc=0x%lx\n", rc); return rc; } TRACE_INFO("RSA public key imported\n"); break; case CKO_PRIVATE_KEY: // do import keypair and create opaque object rc = import_rsa_privkey(tokdata, object->template); if (rc != CKR_OK) { TRACE_DEVEL("RSA private key import failed, rc=0x%lx\n", rc); return rc; } TRACE_INFO("RSA private key imported\n"); break; default: TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); return CKR_KEY_TYPE_INCONSISTENT; } break; #ifndef NO_PKEY case CKK_AES_XTS: rc = import_aes_xts_key(tokdata, object); if (rc != CKR_OK) { TRACE_DEVEL("AES XTS key import failed, rc=0x%lx\n", rc); return rc; } template_attribute_find(object->template, CKA_VALUE, &attr); TRACE_INFO("AES XTS key with len=%ld successfully imported\n", attr != NULL ? attr->ulValueLen : 0); break; #endif case CKK_AES: case CKK_DES: case CKK_DES3: rc = import_symmetric_key(tokdata, object, keytype); if (rc != CKR_OK) { TRACE_DEVEL("Symmetric key import failed, rc=0x%lx\n", rc); return rc; } template_attribute_find(object->template, CKA_VALUE, &attr); TRACE_INFO("symmetric key with len=%ld successful imported\n", attr != NULL ? attr->ulValueLen : 0); break; case CKK_GENERIC_SECRET: case CKK_SHA_1_HMAC: case CKK_SHA224_HMAC: case CKK_SHA256_HMAC: case CKK_SHA384_HMAC: case CKK_SHA512_HMAC: rc = import_generic_secret_key(tokdata, object); if (rc != CKR_OK) { TRACE_DEVEL("Generic Secret (HMAC) key import failed " " with rc=0x%lx\n", rc); return rc; } template_attribute_find(object->template, CKA_VALUE, &attr); TRACE_INFO("Generic Secret (HMAC) key with len=%ld successfully" " imported\n", attr != NULL ? attr->ulValueLen : 0); break; case CKK_EC: case CKK_EC_EDWARDS: switch (keyclass) { case CKO_PUBLIC_KEY: // do import public key and create opaque object rc = import_ec_pubkey(tokdata, object->template); if (rc != CKR_OK) { TRACE_DEVEL("ECpublic key import failed, rc=0x%lx\n", rc); return rc; } TRACE_INFO("EC public key imported\n"); break; case CKO_PRIVATE_KEY: // do import keypair and create opaque object rc = import_ec_privkey(tokdata, object->template); if (rc != CKR_OK) { TRACE_DEVEL("EC private key import failed, rc=0x%lx\n", rc); return rc; } TRACE_INFO("EC private key imported\n"); break; default: TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); return CKR_KEY_TYPE_INCONSISTENT; } break; case CKK_IBM_PQC_DILITHIUM: case CKK_IBM_ML_DSA: case CKK_IBM_ML_KEM: case CKK_ML_DSA: switch (keyclass) { case CKO_PUBLIC_KEY: // do import public key and create opaque object rc = import_pqc_pubkey(tokdata, object->template, keytype); if (rc != CKR_OK) { TRACE_DEVEL("PQC public key import failed, rc=0x%lx\n", rc); return rc; } TRACE_INFO("PQC public key imported\n"); break; case CKO_PRIVATE_KEY: // do import keypair and create opaque object rc = import_pqc_privkey(tokdata, object->template, keytype); if (rc != CKR_OK) { TRACE_DEVEL("PQC private key import failed, rc=0x%lx\n", rc); return rc; } TRACE_INFO("PQC private key imported\n"); break; default: TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); return CKR_KEY_TYPE_INCONSISTENT; } 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_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 }; enum cca_token_type keytype; unsigned int keybitsize; const CK_BYTE *mkvp; CK_BBOOL new_mk, extractable = TRUE; if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } rc = template_attribute_get_ulong(template, CKA_VALUE_LEN, &keylength); if (rc != CKR_OK) { TRACE_ERROR("CKA_VALUE_LEN missing in (HMAC) key template\n"); return rc; } /* HMAC key length needs to be 80-2048 bits */ if ((keylength < (80 / 8)) || (keylength > (2048 / 8))) { 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); rc = template_attribute_get_bool(template, CKA_EXTRACTABLE, &extractable); if (rc != CKR_OK && rc != CKR_TEMPLATE_INCOMPLETE) { TRACE_ERROR("Failed to get CKA_EXTRACTABLE\n"); return rc; } if (!extractable) { memcpy(rule_array + (rule_array_count * CCA_KEYWORD_SIZE), "NOEX-SYMNOEXUASYNOEXAASYNOEX-DESNOEX-AESNOEX-RSA", 6 * CCA_KEYWORD_SIZE); rule_array_count += 6; } USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNBKTB2(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &clear_key_length, NULL, &key_name_length, NULL, &user_data_length, NULL, &zero_length, NULL, &zero_length, NULL, &key_token_length, key_token); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBKTB2 (HMAC KEY TOKEN BUILD) failed." " 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); USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNBKGN2(&return_code, &reason_code, &zero_length, NULL, &rule_array_count, rule_array, &clear_key_length, key_type1, key_type2, &key_name_length, NULL, &key_name_length, NULL, &user_data_length, NULL, &user_data_length, NULL, &zero_length, NULL, &zero_length, NULL, &key_token_length, key_token, &zero_length, NULL); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBKGN2 (HMAC KEY GENERATE) failed." " return:%ld, reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } if (analyse_cca_key_token(key_token, key_token_length, &keytype, &keybitsize, &mkvp) == FALSE || mkvp == NULL) { TRACE_ERROR("Invalid/unknown cca token has been generated\n"); return CKR_FUNCTION_FAILED; } if (check_expected_mkvp(tokdata, keytype, mkvp, &new_mk) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } rc = cca_reencipher_created_key(tokdata, template, key_token, key_token_length, new_mk, keytype, FALSE); if (rc != CKR_OK) { TRACE_ERROR("cca_reencipher_created_key failed: 0x%lx\n", rc); return rc; } /* Add the key object to the template */ rc = build_attribute(CKA_IBM_OPAQUE, key_token, key_token_length, &opaque_key); 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"); free(opaque_key); return rc; } TRACE_DEBUG("%s: secret key template attributes:\n", __func__); TRACE_DEBUG_DUMPTEMPL(template); return CKR_OK; } static CK_RV ccatok_wrap_key_rsa_pkcs(STDLL_TokData_t *tokdata, CK_MECHANISM *mech, CK_BBOOL length_only, OBJECT *wrapping_key, OBJECT *key, CK_BYTE *wrapped_key, CK_ULONG *wrapped_key_len) { long return_code, reason_code, rule_array_count; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0 }; CK_BYTE buffer[3500] = { 0, }; long buffer_len = sizeof(buffer); CK_ATTRIBUTE *key_opaque, *wrap_key_opaque; CK_OBJECT_CLASS key_class; CK_KEY_TYPE key_type; CK_RSA_PKCS_OAEP_PARAMS *oaep; enum cca_token_type keytype; unsigned int keybitsize; const CK_BYTE *mkvp; CK_RV rc; rc = template_attribute_get_ulong(key->template, CKA_CLASS, &key_class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); return rc; } if (key_class != CKO_SECRET_KEY) return CKR_KEY_NOT_WRAPPABLE; rc = template_attribute_get_non_empty(key->template, CKA_IBM_OPAQUE, &key_opaque); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_OPAQUE for the key.\n"); return rc; } if (analyse_cca_key_token((CK_BYTE *)key_opaque->pValue, key_opaque->ulValueLen, &keytype, &keybitsize, &mkvp) == FALSE) { TRACE_ERROR("Invalid/unknown cca token, cannot get key type\n"); return CKR_FUNCTION_FAILED; } rc = template_attribute_get_ulong(key->template, CKA_KEY_TYPE, &key_type); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); return rc; } switch (key_type) { case CKK_DES: case CKK_DES2: case CKK_DES3: switch (mech->mechanism) { case CKM_RSA_PKCS: rule_array_count = 2; memcpy(rule_array, "DES PKCS-1.2", 2 * CCA_KEYWORD_SIZE); break; case CKM_RSA_PKCS_OAEP: rule_array_count = 3; oaep = (CK_RSA_PKCS_OAEP_PARAMS *)mech->pParameter; if (oaep == NULL || mech->ulParameterLen != sizeof(CK_RSA_PKCS_OAEP_PARAMS)) return CKR_MECHANISM_PARAM_INVALID; if (oaep->source == CKZ_DATA_SPECIFIED && oaep->ulSourceDataLen > 0) { TRACE_ERROR("CCA doesn't support non-empty OAEP source data\n"); return CKR_MECHANISM_PARAM_INVALID; } switch (oaep->hashAlg) { case CKM_SHA_1: if (oaep->mgf != CKG_MGF1_SHA1) return CKR_MECHANISM_PARAM_INVALID; memcpy(rule_array, "DES PKCSOAEPSHA-1 ", 3 * CCA_KEYWORD_SIZE); break; case CKM_SHA256: if (oaep->mgf != CKG_MGF1_SHA256) return CKR_MECHANISM_PARAM_INVALID; memcpy(rule_array, "DES PKCSOAEPSHA-256 ", 3 * CCA_KEYWORD_SIZE); break; default: return CKR_MECHANISM_PARAM_INVALID; } break; default: return CKR_MECHANISM_INVALID; } break; case CKK_AES: switch (mech->mechanism) { case CKM_RSA_PKCS: if (keytype == sec_aes_cipher_key) { TRACE_ERROR("CCA does not support wrapping with CKM_RSA_PKCS " "for AES CIPHER keys\n"); return CKR_KEY_NOT_WRAPPABLE; } rule_array_count = 2; memcpy(rule_array, "AES PKCS-1.2", 2 * CCA_KEYWORD_SIZE); break; case CKM_RSA_PKCS_OAEP: if (keytype == sec_aes_cipher_key) { TRACE_ERROR("CCA does not support wrapping with " "CKM_RSA_PKCS_OAEP for AES CIPHER keys\n"); return CKR_KEY_NOT_WRAPPABLE; } rule_array_count = 3; oaep = (CK_RSA_PKCS_OAEP_PARAMS *)mech->pParameter; if (oaep == NULL || mech->ulParameterLen != sizeof(CK_RSA_PKCS_OAEP_PARAMS)) return CKR_MECHANISM_PARAM_INVALID; if (oaep->source == CKZ_DATA_SPECIFIED && oaep->ulSourceDataLen > 0) { TRACE_ERROR("CCA does not support non-empty OAEP source " "data\n"); return CKR_MECHANISM_PARAM_INVALID; } switch (oaep->hashAlg) { case CKM_SHA_1: if (oaep->mgf != CKG_MGF1_SHA1) return CKR_MECHANISM_PARAM_INVALID; memcpy(rule_array, "AES PKCSOAEPSHA-1 ", 3 * CCA_KEYWORD_SIZE); break; case CKM_SHA256: if (oaep->mgf != CKG_MGF1_SHA256) return CKR_MECHANISM_PARAM_INVALID; memcpy(rule_array, "AES PKCSOAEPSHA-256 ", 3 * CCA_KEYWORD_SIZE); break; default: return CKR_MECHANISM_PARAM_INVALID; } break; default: return CKR_MECHANISM_INVALID; } break; default: return CKR_KEY_NOT_WRAPPABLE; } rc = template_attribute_get_non_empty(wrapping_key->template, CKA_IBM_OPAQUE, &wrap_key_opaque); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_OPAQUE for the wrapping key.\n"); return rc; } USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) RETRY_NEW_MK_BLOB_START() dll_CSNDSYX(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, (long *)&key_opaque->ulValueLen, key_opaque->pValue, (long *)&wrap_key_opaque->ulValueLen, wrap_key_opaque->pValue, &buffer_len, buffer); RETRY_NEW_MK_BLOB2_END(tokdata, return_code, reason_code, key_opaque->pValue, key_opaque->ulValueLen, wrap_key_opaque->pValue, wrap_key_opaque->ulValueLen) USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDSYX (SYMMETRIC KEY EXPORT) failed." " return:%ld, reason:%ld\n", return_code, reason_code); if (return_code == 8 && reason_code == 770) return CKR_WRAPPING_KEY_SIZE_RANGE; return CKR_FUNCTION_FAILED; } if (length_only) { *wrapped_key_len = buffer_len; return CKR_OK; } if ((CK_ULONG)buffer_len > *wrapped_key_len) { *wrapped_key_len = buffer_len; return CKR_BUFFER_TOO_SMALL; } memcpy(wrapped_key, buffer, buffer_len); *wrapped_key_len = buffer_len; return CKR_OK; } static CK_RV ccatok_unwrap_key_rsa_pkcs(STDLL_TokData_t *tokdata, CK_MECHANISM *mech, OBJECT *wrapping_key, OBJECT *key, CK_BYTE *wrapped_key, CK_ULONG wrapped_key_len) { long return_code, reason_code, rule_array_count; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0 }; CK_BYTE buffer[3500] = { 0, }; CK_BYTE dummy[AES_KEY_SIZE_256] = { 0, }; long buffer_len = sizeof(buffer); CK_ATTRIBUTE *wrap_key_opaque,*key_opaque = NULL; CK_ATTRIBUTE *value = NULL, *value_len = NULL; CK_OBJECT_CLASS key_class; CK_KEY_TYPE key_type, cca_key_type; CK_ULONG key_size = 0; CK_RSA_PKCS_OAEP_PARAMS *oaep; enum cca_token_type keytype; unsigned int keybitsize; const CK_BYTE *mkvp; CK_BBOOL new_mk; uint16_t val; CK_IBM_CCA_AES_KEY_MODE_TYPE mode; CK_RV rc; rc = template_attribute_get_ulong(key->template, CKA_CLASS, &key_class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); return rc; } if (key_class != CKO_SECRET_KEY) return CKR_WRAPPED_KEY_INVALID; rc = template_attribute_get_ulong(key->template, CKA_KEY_TYPE, &key_type); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); return rc; } switch (key_type) { case CKK_DES: case CKK_DES2: case CKK_DES3: switch (mech->mechanism) { case CKM_RSA_PKCS: rule_array_count = 2; memcpy(rule_array, "DES PKCS-1.2", 2 * CCA_KEYWORD_SIZE); break; case CKM_RSA_PKCS_OAEP: rule_array_count = 3; oaep = (CK_RSA_PKCS_OAEP_PARAMS *)mech->pParameter; if (oaep == NULL || mech->ulParameterLen != sizeof(CK_RSA_PKCS_OAEP_PARAMS)) return CKR_MECHANISM_PARAM_INVALID; if (oaep->source == CKZ_DATA_SPECIFIED && oaep->ulSourceDataLen > 0) { TRACE_ERROR("CCA does not support non-empty OAEP source " "data\n"); return CKR_MECHANISM_PARAM_INVALID; } switch (oaep->hashAlg) { case CKM_SHA_1: if (oaep->mgf != CKG_MGF1_SHA1) return CKR_MECHANISM_PARAM_INVALID; memcpy(rule_array, "DES PKCSOAEPSHA-1 ", 3 * CCA_KEYWORD_SIZE); break; case CKM_SHA256: if (oaep->mgf != CKG_MGF1_SHA256) return CKR_MECHANISM_PARAM_INVALID; memcpy(rule_array, "DES PKCSOAEPSHA-256 ", 3 * CCA_KEYWORD_SIZE); break; default: return CKR_MECHANISM_PARAM_INVALID; } break; default: return CKR_MECHANISM_INVALID; } break; case CKK_AES: rc = cca_get_and_set_aes_key_mode(tokdata, key->template, &mode); if (rc != CKR_OK) { TRACE_DEVEL("cca_get_and_set_aes_key_mode failed\n"); return rc; } switch (mech->mechanism) { case CKM_RSA_PKCS: if (mode == CK_IBM_CCA_AES_CIPHER_KEY) { TRACE_ERROR("CCA does not support to unwrap with CKM_RSA_PKCS " "for AES CIPHER keys\n"); return CKR_WRAPPED_KEY_INVALID; } rule_array_count = 2; memcpy(rule_array, "AES PKCS-1.2", 2 * CCA_KEYWORD_SIZE); break; case CKM_RSA_PKCS_OAEP: if (mode == CK_IBM_CCA_AES_CIPHER_KEY) { TRACE_ERROR("CCA does not support to unwrap with " "CKM_RSA_PKCS_OAEP for AES CIPHER keys\n"); return CKR_WRAPPED_KEY_INVALID; } rule_array_count = 3; oaep = (CK_RSA_PKCS_OAEP_PARAMS *)mech->pParameter; if (oaep == NULL || mech->ulParameterLen != sizeof(CK_RSA_PKCS_OAEP_PARAMS)) return CKR_MECHANISM_PARAM_INVALID; if (oaep->source == CKZ_DATA_SPECIFIED && oaep->ulSourceDataLen > 0) { TRACE_ERROR("CCA does not support non-empty OAEP source " "data\n"); return CKR_MECHANISM_PARAM_INVALID; } switch (oaep->hashAlg) { case CKM_SHA_1: if (oaep->mgf != CKG_MGF1_SHA1) return CKR_MECHANISM_PARAM_INVALID; memcpy(rule_array, "AES PKCSOAEPSHA-1 ", 3 * CCA_KEYWORD_SIZE); break; case CKM_SHA256: if (oaep->mgf != CKG_MGF1_SHA256) return CKR_MECHANISM_PARAM_INVALID; memcpy(rule_array, "AES PKCSOAEPSHA-256 ", 3 * CCA_KEYWORD_SIZE); break; default: return CKR_MECHANISM_PARAM_INVALID; } break; default: return CKR_MECHANISM_INVALID; } break; default: return CKR_WRAPPED_KEY_INVALID; } rc = template_attribute_get_non_empty(wrapping_key->template, CKA_IBM_OPAQUE, &wrap_key_opaque); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_OPAQUE for the wrapping key.\n"); return rc; } USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) RETRY_NEW_MK_BLOB_START() dll_CSNDSYI(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, (long *)&wrapped_key_len, wrapped_key, (long *)&wrap_key_opaque->ulValueLen, wrap_key_opaque->pValue, &buffer_len, buffer); RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, wrap_key_opaque->pValue, wrap_key_opaque->ulValueLen) USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDSYI (SYMMETRIC KEY IMPORT) failed." " return:%ld, reason:%ld\n", return_code, reason_code); if (return_code == 8 && reason_code == 770) return CKR_UNWRAPPING_KEY_SIZE_RANGE; return CKR_FUNCTION_FAILED; } if (buffer[0] != 0x01) { /* Internal key token */ TRACE_DEVEL("key token invalid\n"); return CKR_FUNCTION_FAILED; } if (analyse_cca_key_token(buffer, buffer_len, &keytype, &keybitsize, &mkvp) == FALSE || mkvp == NULL) { TRACE_ERROR("Invalid/unknown cca token has been unwrapped\n"); return CKR_FUNCTION_FAILED; } if (check_expected_mkvp(tokdata, keytype, mkvp, &new_mk) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } rc = cca_reencipher_created_key(tokdata, key->template, buffer, buffer_len, new_mk, keytype, FALSE); if (rc != CKR_OK) { TRACE_ERROR("cca_reencipher_created_key failed: 0x%lx\n", rc); return rc; } switch (buffer[4]) { case 0x00: /* DES key token */ case 0x01: { /* DES3 key token */ /* analyse_cca_key_token has already reliably identified the token type, so use that */ switch(keybitsize) { case (1 * DES_KEY_SIZE * 8): cca_key_type = CKK_DES; key_size = DES_KEY_SIZE; break; case (2 * DES_KEY_SIZE * 8): cca_key_type = CKK_DES2; key_size = 2 * DES_KEY_SIZE; break; case (3 * DES_KEY_SIZE * 8): cca_key_type = CKK_DES3; key_size = 3 * DES_KEY_SIZE; break; default: TRACE_DEVEL("key token invalid\n"); return CKR_FUNCTION_FAILED; } break; } case 0x04:/* AES key token */ cca_key_type = CKK_AES; memcpy(&val, &buffer[56], sizeof(val)); key_size = be16toh(val) / 8; break; default: TRACE_DEVEL("key token invalid\n"); return CKR_FUNCTION_FAILED; } if (key_type != cca_key_type) { TRACE_DEVEL("Wrong key type\n"); return CKR_FUNCTION_FAILED; } rc = build_attribute(CKA_IBM_OPAQUE, buffer, buffer_len, &key_opaque); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto error; } rc = build_attribute(CKA_VALUE, dummy, key_size, &value); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto error; } switch (key_type) { case CKK_GENERIC_SECRET: case CKK_AES: rc = build_attribute(CKA_VALUE_LEN, (CK_BYTE *)&key_size, sizeof(CK_ULONG), &value_len); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto error; } break; default: break; } rc = template_update_attribute(key->template, key_opaque); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); goto error; } key_opaque = NULL; rc = template_update_attribute(key->template, value); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); goto error; } value = NULL; if (value_len != NULL) { rc = template_update_attribute(key->template, value_len); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); goto error; } value_len = NULL; } return CKR_OK; error: if (key_opaque) free(key_opaque); if (value) free(value); if (value_len) free(value_len); return rc; } static CK_RV ccatok_wrap_key_rsa_aeskw_aes(STDLL_TokData_t *tokdata, CK_BBOOL length_only, CK_ATTRIBUTE *wrap_key_opaque, CK_ATTRIBUTE *key_opaque, CK_BYTE *wrapped_key, CK_ULONG *wrapped_key_len) { long return_code, reason_code, rule_array_count; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0 }; CK_BYTE buffer[3500] = { 0, }; long buffer_len = sizeof(buffer); enum cca_token_type keytype; unsigned int keybitsize; const CK_BYTE *mkvp; if (!cca_rsa_aeskw_supported(tokdata, CKK_AES)) { TRACE_ERROR("CKM_RSA_AES_KEY_WRAP requires CCA 8.2 or later and " "certain ACPs set for wrapping AES keys\n"); return CKR_KEY_NOT_WRAPPABLE; } if (analyse_cca_key_token((CK_BYTE *)key_opaque->pValue, key_opaque->ulValueLen, &keytype, &keybitsize, &mkvp) == FALSE) { TRACE_ERROR("Invalid/unknown cca token, cannot get key type\n"); return CKR_FUNCTION_FAILED; } if (keytype != sec_aes_cipher_key) { TRACE_ERROR("CCA does not support wrapping with CKM_RSA_AES_KEY_WRAP " "for AES DATA keys\n"); return CKR_KEY_NOT_WRAPPABLE; } rule_array_count = 2; memcpy(rule_array, "AES CKM-RAKW", 2 * CCA_KEYWORD_SIZE); USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) RETRY_NEW_MK_BLOB_START() dll_CSNDSYX(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, (long *)&key_opaque->ulValueLen, key_opaque->pValue, (long *)&wrap_key_opaque->ulValueLen, wrap_key_opaque->pValue, &buffer_len, buffer); RETRY_NEW_MK_BLOB2_END(tokdata, return_code, reason_code, key_opaque->pValue, key_opaque->ulValueLen, wrap_key_opaque->pValue, wrap_key_opaque->ulValueLen) USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDSYX (SYMMETRIC KEY EXPORT) failed." " return:%ld, reason:%ld\n", return_code, reason_code); if (return_code == 8 && reason_code == 90) return CKR_FUNCTION_CANCELED; /* Control point prohibits function */ if (return_code == 8 && reason_code == 760) return CKR_WRAPPING_KEY_SIZE_RANGE; /* must be >= 2048 bit */ if (return_code == 8 && reason_code == 770) return CKR_WRAPPING_KEY_SIZE_RANGE; return CKR_FUNCTION_FAILED; } if (length_only) { *wrapped_key_len = buffer_len; return CKR_OK; } if ((CK_ULONG)buffer_len > *wrapped_key_len) { *wrapped_key_len = buffer_len; return CKR_BUFFER_TOO_SMALL; } memcpy(wrapped_key, buffer, buffer_len); *wrapped_key_len = buffer_len; return CKR_OK; } static CK_RV ccatok_wrap_key_rsa_aeskw(STDLL_TokData_t *tokdata, CK_MECHANISM *mech, CK_BBOOL length_only, OBJECT *wrapping_key, OBJECT *key, CK_BYTE *wrapped_key, CK_ULONG *wrapped_key_len) { CK_ATTRIBUTE *key_opaque, *wrap_key_opaque; CK_OBJECT_CLASS key_class; CK_KEY_TYPE key_type; CK_RSA_AES_KEY_WRAP_PARAMS *params; CK_RSA_PKCS_OAEP_PARAMS *oaep; CK_RV rc; params = (CK_RSA_AES_KEY_WRAP_PARAMS *)mech->pParameter; if (params == NULL || mech->ulParameterLen != sizeof(CK_RSA_AES_KEY_WRAP_PARAMS)) return CKR_MECHANISM_PARAM_INVALID; if (params->ulAESKeyBits != 256) { TRACE_ERROR("CCA only supports AES-256 as temporary key size\n"); return CKR_MECHANISM_PARAM_INVALID; } oaep = params->pOAEPParams; if (oaep == NULL) return CKR_MECHANISM_PARAM_INVALID; if (oaep->source == CKZ_DATA_SPECIFIED && oaep->ulSourceDataLen > 0) { TRACE_ERROR("CCA does not support non-empty OAEP source data\n"); return CKR_MECHANISM_PARAM_INVALID; } if (oaep->hashAlg != CKM_SHA_1 || oaep->mgf != CKG_MGF1_SHA1) { TRACE_ERROR("CCA only supports SHA-1 as hash algorithm and MGF\n"); return CKR_MECHANISM_PARAM_INVALID; } rc = template_attribute_get_non_empty(wrapping_key->template, CKA_IBM_OPAQUE, &wrap_key_opaque); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_OPAQUE for the wrapping key.\n"); return rc; } rc = template_attribute_get_ulong(key->template, CKA_CLASS, &key_class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); return rc; } rc = template_attribute_get_ulong(key->template, CKA_KEY_TYPE, &key_type); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); return rc; } rc = template_attribute_get_non_empty(key->template, CKA_IBM_OPAQUE, &key_opaque); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_OPAQUE for the key.\n"); return rc; } switch (key_class) { case CKO_SECRET_KEY: switch (key_type) { case CKK_AES: return ccatok_wrap_key_rsa_aeskw_aes(tokdata, length_only, wrap_key_opaque, key_opaque, wrapped_key, wrapped_key_len); default: TRACE_ERROR("The type of they key to wrap is not supported.\n"); return CKR_KEY_NOT_WRAPPABLE; } break; default: TRACE_ERROR("The class of the key to wrap is not supported.\n"); return CKR_KEY_NOT_WRAPPABLE; } } static CK_RV ccatok_unwrap_key_rsa_aeskw_aes(STDLL_TokData_t *tokdata, CK_ATTRIBUTE *wrap_key_opaque, OBJECT *key, CK_BYTE *wrapped_key, CK_ULONG wrapped_key_len) { long return_code, reason_code, rule_array_count; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0 }; unsigned char exit_data[4] = { 0, }; unsigned char key_name[CCA_KEY_ID_SIZE] = { 0, }; long exit_data_len = 0, key_name_length = 0; CK_BYTE buffer[725] = { 0, }; CK_BYTE dummy[AES_KEY_SIZE_256] = { 0, }; long buffer_len = sizeof(buffer); CK_ULONG buf_len = sizeof(buffer); CK_ATTRIBUTE *key_opaque = NULL; CK_ATTRIBUTE *value = NULL, *value_len = NULL; CK_ULONG key_size = 0; enum cca_token_type keytype; unsigned int keybitsize; const CK_BYTE *mkvp; CK_BBOOL new_mk; CK_IBM_CCA_AES_KEY_MODE_TYPE mode; CK_RV rc; if (!cca_rsa_aeskw_supported(tokdata, CKK_AES)) { TRACE_ERROR("CKM_RSA_AES_KEY_WRAP requires CCA 8.2 or later and " "certain ACPs set for unwrapping AES keys\n"); return CKR_WRAPPED_KEY_INVALID; } rc = cca_get_and_set_aes_key_mode(tokdata, key->template, &mode); if (rc != CKR_OK) { TRACE_DEVEL("cca_get_and_set_aes_key_mode failed\n"); return rc; } if (mode != CK_IBM_CCA_AES_CIPHER_KEY) { TRACE_ERROR("CCA does not support unwrapping with CKM_RSA_AES_KEY_WRAP " "for AES DATA keys\n"); return CKR_WRAPPED_KEY_INVALID; } rc = cca_build_aes_cipher_token(tokdata, key->template, buffer, &buf_len); if (rc != CKR_OK) { TRACE_DEVEL("cca_build_aes_cipher_token failed\n"); return rc; } rule_array_count = 2; memcpy(rule_array, "AES CKM-RAKW", 2 * CCA_KEYWORD_SIZE); USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) RETRY_NEW_MK_BLOB_START() dll_CSNDSYI2(&return_code, &reason_code, &exit_data_len, exit_data, &rule_array_count, rule_array, (long *)&wrapped_key_len, wrapped_key, (long *)&wrap_key_opaque->ulValueLen, wrap_key_opaque->pValue, &key_name_length, key_name, &buffer_len, buffer); RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, wrap_key_opaque->pValue, wrap_key_opaque->ulValueLen) USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDSYI2 (SYMMETRIC KEY IMPORT2) failed." " return:%ld, reason:%ld\n", return_code, reason_code); if (return_code == 8 && reason_code == 90) return CKR_FUNCTION_CANCELED; /* Control point prohibits function */ if (return_code == 8 && reason_code == 33) return CKR_FUNCTION_CANCELED; /* Control point prohibits function */ if (return_code == 8 && reason_code == 760) return CKR_UNWRAPPING_KEY_SIZE_RANGE; /* must be >= 2048 bit */ if (return_code == 8 && reason_code == 770) return CKR_UNWRAPPING_KEY_SIZE_RANGE; if (return_code == 8 && reason_code == 55) return CKR_WRAPPED_KEY_INVALID; /* temp AES key not 256 bits */ return CKR_FUNCTION_FAILED; } if (analyse_cca_key_token(buffer, buffer_len, &keytype, &keybitsize, &mkvp) == FALSE || mkvp == NULL) { TRACE_ERROR("Invalid/unknown cca token has been unwrapped\n"); return CKR_FUNCTION_FAILED; } if (keytype != sec_aes_cipher_key) { TRACE_ERROR("Invalid cca token has been unwrapped\n"); return CKR_FUNCTION_FAILED; } if (keybitsize == 0) { /* Indicates V1 payload. Get unwrapped key size from wrapped data */ if (analyse_cca_key_token(wrap_key_opaque->pValue, wrap_key_opaque->ulValueLen, &keytype, &keybitsize, &mkvp) == FALSE || mkvp == NULL) { TRACE_ERROR("Invalid/unknown cca token used as wrapping key\n"); return CKR_FUNCTION_FAILED; } /* Unwrapped key size is input size - RSA modulus size - AESKW block */ key_size = wrapped_key_len - (keybitsize / 8) - AES_KEY_WRAP_BLOCK_SIZE; } else { key_size = keybitsize / 8; } if (check_expected_mkvp(tokdata, keytype, mkvp, &new_mk) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } rc = cca_reencipher_created_key(tokdata, key->template, buffer, buffer_len, new_mk, keytype, FALSE); if (rc != CKR_OK) { TRACE_ERROR("cca_reencipher_created_key failed: 0x%lx\n", rc); return rc; } rc = build_attribute(CKA_IBM_OPAQUE, buffer, buffer_len, &key_opaque); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto error; } rc = build_attribute(CKA_VALUE, dummy, key_size, &value); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto error; } rc = build_attribute(CKA_VALUE_LEN, (CK_BYTE *)&key_size, sizeof(CK_ULONG), &value_len); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto error; } rc = template_update_attribute(key->template, key_opaque); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); goto error; } key_opaque = NULL; rc = template_update_attribute(key->template, value); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); goto error; } value = NULL; if (value_len != NULL) { rc = template_update_attribute(key->template, value_len); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); goto error; } value_len = NULL; } return CKR_OK; error: if (key_opaque) free(key_opaque); if (value) free(value); if (value_len) free(value_len); return rc; } static CK_RV ccatok_unwrap_key_rsa_aeskw(STDLL_TokData_t *tokdata, CK_MECHANISM *mech, OBJECT *wrapping_key, OBJECT *key, CK_BYTE *wrapped_key, CK_ULONG wrapped_key_len) { CK_ATTRIBUTE *wrap_key_opaque; CK_OBJECT_CLASS key_class; CK_KEY_TYPE key_type; CK_RSA_AES_KEY_WRAP_PARAMS *params; CK_RSA_PKCS_OAEP_PARAMS *oaep; CK_RV rc; params = (CK_RSA_AES_KEY_WRAP_PARAMS *)mech->pParameter; if (params == NULL || mech->ulParameterLen != sizeof(CK_RSA_AES_KEY_WRAP_PARAMS)) return CKR_MECHANISM_PARAM_INVALID; /* CCA always uses a AES-256 bit temporary key */ if (params->ulAESKeyBits == 0) params->ulAESKeyBits = 256; if (params->ulAESKeyBits != 256) { TRACE_ERROR("CCA only supports AES-256 as temporary key size\n"); return CKR_MECHANISM_PARAM_INVALID; } oaep = params->pOAEPParams; if (oaep == NULL) return CKR_MECHANISM_PARAM_INVALID; if (oaep->source == CKZ_DATA_SPECIFIED && oaep->ulSourceDataLen > 0) { TRACE_ERROR("CCA does not support non-empty OAEP source data\n"); return CKR_MECHANISM_PARAM_INVALID; } if (oaep->hashAlg != CKM_SHA_1 || oaep->mgf != CKG_MGF1_SHA1) { TRACE_ERROR("CCA only supports SHA-1 as hash algorithm and MGF\n"); return CKR_MECHANISM_PARAM_INVALID; } rc = template_attribute_get_non_empty(wrapping_key->template, CKA_IBM_OPAQUE, &wrap_key_opaque); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_OPAQUE for the wrapping key.\n"); return rc; } rc = template_attribute_get_ulong(key->template, CKA_CLASS, &key_class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); return rc; } rc = template_attribute_get_ulong(key->template, CKA_KEY_TYPE, &key_type); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); return rc; } switch (key_class) { case CKO_SECRET_KEY: switch (key_type) { case CKK_AES: return ccatok_unwrap_key_rsa_aeskw_aes(tokdata, wrap_key_opaque, key, wrapped_key, wrapped_key_len); default: TRACE_ERROR("The type of they key to wrap is not supported.\n"); return CKR_KEY_NOT_WRAPPABLE; } break; default: TRACE_ERROR("The class of the key to wrap is not supported.\n"); return CKR_KEY_NOT_WRAPPABLE; } return CKR_OK; } CK_RV token_specific_key_wrap(STDLL_TokData_t *tokdata, SESSION *session, CK_MECHANISM *mech, CK_BBOOL length_only, OBJECT *wrapping_key, OBJECT *key, CK_BYTE *wrapped_key, CK_ULONG *wrapped_key_len, CK_BBOOL *not_opaque) { CK_OBJECT_CLASS wrap_key_class; CK_KEY_TYPE wrap_key_type; CK_RV rc; UNUSED(session); if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } *not_opaque = FALSE; rc = template_attribute_get_ulong(wrapping_key->template, CKA_CLASS, &wrap_key_class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the wrapping key.\n"); return rc; } rc = template_attribute_get_ulong(wrapping_key->template, CKA_KEY_TYPE, &wrap_key_type); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the wrapping key.\n"); return rc; } switch (mech->mechanism) { case CKM_RSA_PKCS: case CKM_RSA_PKCS_OAEP: if (wrap_key_class != CKO_PUBLIC_KEY && wrap_key_type != CKK_RSA) return CKR_WRAPPING_KEY_TYPE_INCONSISTENT; return ccatok_wrap_key_rsa_pkcs(tokdata, mech, length_only, wrapping_key, key, wrapped_key, wrapped_key_len); case CKM_RSA_AES_KEY_WRAP: if (wrap_key_class != CKO_PUBLIC_KEY && wrap_key_type != CKK_RSA) return CKR_WRAPPING_KEY_TYPE_INCONSISTENT; return ccatok_wrap_key_rsa_aeskw(tokdata, mech, length_only, wrapping_key, key, wrapped_key, wrapped_key_len); default: return CKR_MECHANISM_INVALID; } } CK_RV token_specific_key_unwrap(STDLL_TokData_t *tokdata, SESSION *session, CK_MECHANISM *mech, CK_BYTE *wrapped_key, CK_ULONG wrapped_key_len, OBJECT *unwrapping_key, OBJECT *unwrapped_key, CK_BBOOL *not_opaque) { CK_ATTRIBUTE *local = NULL, *always_sens = NULL, *sensitive = NULL; CK_ATTRIBUTE *extractable = NULL, *never_extract = NULL; CK_OBJECT_CLASS unwrap_key_class; CK_KEY_TYPE unwrap_keytype; CK_BBOOL true = TRUE; CK_BBOOL false = FALSE; CK_RV rc; UNUSED(session); if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } *not_opaque = FALSE; rc = template_attribute_get_ulong(unwrapping_key->template, CKA_CLASS, &unwrap_key_class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); return rc; } rc = template_attribute_get_ulong(unwrapping_key->template, CKA_KEY_TYPE, &unwrap_keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); return rc; } switch (mech->mechanism) { case CKM_RSA_PKCS: case CKM_RSA_PKCS_OAEP: if (unwrap_key_class != CKO_PRIVATE_KEY && unwrap_keytype != CKK_RSA) return CKR_WRAPPING_KEY_TYPE_INCONSISTENT; rc = ccatok_unwrap_key_rsa_pkcs(tokdata, mech, unwrapping_key, unwrapped_key, wrapped_key, wrapped_key_len); if (rc != CKR_OK) goto error; break; case CKM_RSA_AES_KEY_WRAP: if (unwrap_key_class != CKO_PRIVATE_KEY && unwrap_keytype != CKK_RSA) return CKR_WRAPPING_KEY_TYPE_INCONSISTENT; rc = ccatok_unwrap_key_rsa_aeskw(tokdata, mech, unwrapping_key, unwrapped_key, wrapped_key, wrapped_key_len); if (rc != CKR_OK) goto error; break; default: return CKR_MECHANISM_INVALID; } /* * 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 error; } rc = build_attribute(CKA_ALWAYS_SENSITIVE, &false, 1, &always_sens); if (rc != CKR_OK) { TRACE_DEVEL("build attribute failed\n"); goto error; } rc = build_attribute(CKA_SENSITIVE, &false, 1, &sensitive); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto error; } rc = build_attribute(CKA_EXTRACTABLE, &true, 1, &extractable); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto error; } rc = build_attribute(CKA_NEVER_EXTRACTABLE, &false, 1, &never_extract); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto error; } rc = template_update_attribute(unwrapped_key->template, local); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); goto error; } local = NULL; rc = template_update_attribute(unwrapped_key->template, always_sens); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); goto error; } always_sens = NULL; rc = template_update_attribute(unwrapped_key->template, sensitive); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); goto error; } sensitive = NULL; rc = template_update_attribute(unwrapped_key->template, extractable); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); goto error; } extractable = NULL; rc = template_update_attribute(unwrapped_key->template, never_extract); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); goto error; } never_extract = NULL; return CKR_OK; error: if (local) free(local); if (extractable) free(extractable); if (sensitive) free(sensitive); if (always_sens) free(always_sens); if (never_extract) free(never_extract); return rc; } CK_RV token_specific_reencrypt_single(STDLL_TokData_t *tokdata, SESSION *session, ENCR_DECR_CONTEXT *decr_ctx, CK_MECHANISM *decr_mech, OBJECT *decr_key_obj, ENCR_DECR_CONTEXT *encr_ctx, CK_MECHANISM *encr_mech, OBJECT *encr_key_obj, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len) { CK_ATTRIBUTE *decr_key_opaque, *encr_key_opaque; long return_code, reason_code, rule_array_count = 0; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0 }; CK_BYTE in_iv[AES_BLOCK_SIZE] = { 0 }; CK_BYTE out_iv[AES_BLOCK_SIZE] = { 0 }; long in_iv_len = 0, out_iv_len = 0; CK_BYTE cv[128] = { 0 }; long cv_len = 128, zero = 0; CK_ULONG max_clear_len, req_out_len; CK_RV rc; UNUSED(session); UNUSED(decr_ctx); UNUSED(encr_ctx); if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } rc = template_attribute_get_non_empty(decr_key_obj->template, CKA_IBM_OPAQUE, &decr_key_opaque); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_OPAQUE for the decryption key.\n"); return rc; } rc = template_attribute_get_non_empty(encr_key_obj->template, CKA_IBM_OPAQUE, &encr_key_opaque); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_OPAQUE for the encryption key.\n"); return rc; } /* CCA only supports AES-ECB/CBC, and 3DES-CBC with CSNBCTT2 */ switch (decr_mech->mechanism) { case CKM_AES_ECB: rule_array_count = 2; memcpy(rule_array, "IKEY-AESI-ECB ", 2 * CCA_KEYWORD_SIZE); max_clear_len = in_data_len; break; case CKM_AES_CBC: rule_array_count = 2; memcpy(rule_array, "IKEY-AESI-CBC ", 2 * CCA_KEYWORD_SIZE); in_iv_len = decr_mech->ulParameterLen; if (in_iv_len != AES_BLOCK_SIZE) return CKR_MECHANISM_PARAM_INVALID; memcpy(in_iv, decr_mech->pParameter, in_iv_len); max_clear_len = in_data_len; break; case CKM_AES_CBC_PAD: rule_array_count = 2; memcpy(rule_array, "IKEY-AESIPKCSPAD", 2 * CCA_KEYWORD_SIZE); in_iv_len = decr_mech->ulParameterLen; if (in_iv_len != AES_BLOCK_SIZE) return CKR_MECHANISM_PARAM_INVALID; memcpy(in_iv, decr_mech->pParameter, in_iv_len); /* PKCS#7 pads at least 1 byte in any case */ max_clear_len = in_data_len - 1; break; case CKM_DES3_CBC: rule_array_count = 2; memcpy(rule_array, "IKEY-DESI-CBC ", 2 * CCA_KEYWORD_SIZE); in_iv_len = decr_mech->ulParameterLen; if (in_iv_len != DES_BLOCK_SIZE) return CKR_MECHANISM_PARAM_INVALID; memcpy(in_iv, decr_mech->pParameter, in_iv_len); max_clear_len = in_data_len; break; default: TRACE_DEVEL("Decryption method %lu not supported\n", decr_mech->mechanism); return CKR_MECHANISM_INVALID; } switch (encr_mech->mechanism) { case CKM_AES_ECB: memcpy(rule_array + (rule_array_count * CCA_KEYWORD_SIZE), "OKEY-AESO-ECB ", 2 * CCA_KEYWORD_SIZE); rule_array_count += 2; /* Round up to the next block size */ req_out_len = (max_clear_len / AES_BLOCK_SIZE) * AES_BLOCK_SIZE + (max_clear_len % AES_BLOCK_SIZE ? AES_BLOCK_SIZE : 0); break; case CKM_AES_CBC: memcpy(rule_array + (rule_array_count * CCA_KEYWORD_SIZE), "OKEY-AESO-CBC ", 2 * CCA_KEYWORD_SIZE); rule_array_count += 2; out_iv_len = encr_mech->ulParameterLen; if (out_iv_len != AES_BLOCK_SIZE) return CKR_MECHANISM_PARAM_INVALID; memcpy(out_iv, encr_mech->pParameter, out_iv_len); /* Round up to the next block size */ req_out_len = (max_clear_len / AES_BLOCK_SIZE) * AES_BLOCK_SIZE + (max_clear_len % AES_BLOCK_SIZE ? AES_BLOCK_SIZE : 0); break; case CKM_AES_CBC_PAD: memcpy(rule_array + (rule_array_count * CCA_KEYWORD_SIZE), "OKEY-AESOPKCSPAD", 2 * CCA_KEYWORD_SIZE); rule_array_count += 2; out_iv_len = encr_mech->ulParameterLen; if (out_iv_len != AES_BLOCK_SIZE) return CKR_MECHANISM_PARAM_INVALID; memcpy(out_iv, encr_mech->pParameter, out_iv_len); /* PKCS#7 pads a full block, if already a multiple of the block size */ req_out_len = AES_BLOCK_SIZE * (max_clear_len / AES_BLOCK_SIZE + 1); break; case CKM_DES3_CBC: memcpy(rule_array + (rule_array_count * CCA_KEYWORD_SIZE), "OKEY-DESO-CBC ", 2 * CCA_KEYWORD_SIZE); rule_array_count += 2; out_iv_len = encr_mech->ulParameterLen; if (out_iv_len != DES_BLOCK_SIZE) return CKR_MECHANISM_PARAM_INVALID; memcpy(out_iv, encr_mech->pParameter, out_iv_len); /* Round up to the next block size */ req_out_len = (max_clear_len / DES_BLOCK_SIZE) * DES_BLOCK_SIZE + (max_clear_len % DES_BLOCK_SIZE ? DES_BLOCK_SIZE : 0); break; default: TRACE_DEVEL("Encryption method %lu not supported\n", decr_mech->mechanism); return CKR_MECHANISM_INVALID; } if (out_data == NULL) { *out_data_len = req_out_len; return CKR_OK; } if (*out_data_len < req_out_len) { *out_data_len = req_out_len; TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); return CKR_BUFFER_TOO_SMALL; } USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) RETRY_NEW_MK_BLOB_START() dll_CSNBCTT2(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, (long *)&decr_key_opaque->ulValueLen, decr_key_opaque->pValue, &in_iv_len, in_iv, (long *)&in_data_len, in_data, &cv_len, cv, (long *)&encr_key_opaque->ulValueLen, encr_key_opaque->pValue, &out_iv_len, out_iv, (long *)out_data_len, out_data, &zero, NULL, &zero, NULL); RETRY_NEW_MK_BLOB2_END(tokdata, return_code, reason_code, encr_key_opaque->pValue, encr_key_opaque->ulValueLen, decr_key_opaque->pValue, decr_key_opaque->ulValueLen); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBCTT2 (CIPHER TEXT TRANSLATE) failed." " return:%ld, reason:%ld\n", return_code, reason_code); if (return_code == 8 && reason_code == 72) return CKR_DATA_LEN_RANGE; return CKR_FUNCTION_FAILED; } 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) { 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; out_fclose: fclose(fp); return rc; } /* * ATTENTION: This function is called in a separate thread. All actions * performed by this function must be thread save and use locks to lock * against concurrent access by other threads. */ static CK_RV cca_handle_apqn_event(STDLL_TokData_t *tokdata, unsigned int event_type, event_udev_apqn_data_t *apqn_data) { struct cca_private_data *cca_private = tokdata->private_data; char fname[290]; char buf[250]; CK_RV rc; unsigned long val; #ifndef NO_PKEY unsigned int min_card_version; #endif UNUSED(event_type); sprintf(fname, "%scard%02x/ap_functions", SYSFS_DEVICES_AP, apqn_data->card); rc = file_fgets(fname, buf, sizeof(buf)); if (rc != CKR_OK) return CKR_OK; if (sscanf(buf, "%lx", &val) != 1) val = 0x00000000; if ((val & MASK_COPRO) == 0) return CKR_OK; TRACE_DEVEL("%s Cross checking MKVPs due to event for APQN %02X.%04X\n", __func__, apqn_data->card, apqn_data->domain); rc = cca_check_mks(tokdata); if (rc != CKR_OK) { if (__sync_fetch_and_or(&cca_private->inconsistent, TRUE) == FALSE) { TRACE_ERROR("CCA master key setup is inconsistent, all crypto operations will fail from now on\n"); OCK_SYSLOG(LOG_ERR, "CCA master key setup is inconsistent, all crypto operations will fail from now on\n"); } return CKR_OK; } if (__sync_fetch_and_and(&cca_private->inconsistent, FALSE) == TRUE) { TRACE_INFO("CCA master key setup is now consistent again\n"); OCK_SYSLOG(LOG_INFO, "CCA master key setup is now consistent again\n"); } /* Get ACP infos again after APQN set changed */ rc = cca_get_acp_infos(tokdata); if (rc != CKR_OK) { TRACE_WARNING("Could not re-determine min ACP settings\n"); return rc; } /* Re-check after APQN set change if protected key support is available */ rc = cca_get_min_card_level(tokdata); if (rc != CKR_OK) { TRACE_WARNING("Could not re-determine min card level, protected key support not available.\n"); return rc; } #ifndef NO_PKEY /* Read min card version from CCA private data. Needs a read lock.*/ if (pthread_rwlock_rdlock(&cca_private->min_card_version_rwlock) != 0) { TRACE_ERROR("CCA min_card_version RD-Lock failed.\n"); return CKR_CANT_LOCK; } min_card_version = cca_private->min_card_version.ver; if (pthread_rwlock_unlock(&cca_private->min_card_version_rwlock) != 0) { TRACE_ERROR("CCA min_card_version RD-Unlock failed.\n"); return CKR_CANT_LOCK; } /* Check minimum card version, XPRTCPAC requires min CEX7C */ if (min_card_version < 7) { TRACE_WARNING("Min card version now is %d, protected key support not available on this system.\n", cca_private->min_card_version.ver); /* Disable pkey */ __sync_and_and_fetch(&cca_private->pkey_wrap_supported, 0); } else if (cca_private->pkey_wrap_supported == 0 && !ccatok_pkey_option_disabled(tokdata)) { /* get firmware WKVP, this will enable PKEY on success */ rc = ccatok_pkey_get_firmware_wkvp(tokdata); if (rc != CKR_OK) { OCK_SYSLOG(LOG_WARNING, "%s: Warning: Could not get wkvp, protected key support not available.\n", __func__); TRACE_WARNING("Could not get wkvp, protected key support not available.\n"); } } #endif /* NO_PKEY */ return CKR_OK; } /* * Called by the event thread, on receipt of an event. * * ATTENTION: This function is called in a separate thread. All actions * performed by this function must be thread save and use locks to lock * against concurrent access by other threads. */ CK_RV token_specific_handle_event(STDLL_TokData_t *tokdata, unsigned int event_type, unsigned int event_flags, const char *payload, unsigned int payload_len) { UNUSED(event_flags); switch (event_type) { case EVENT_TYPE_APQN_ADD: case EVENT_TYPE_APQN_REMOVE: if (payload_len != sizeof(event_udev_apqn_data_t)) return CKR_FUNCTION_FAILED; return cca_handle_apqn_event(tokdata, event_type, (event_udev_apqn_data_t *)payload); case EVENT_TYPE_MK_CHANGE_INITIATE_QUERY: case EVENT_TYPE_MK_CHANGE_REENCIPHER: case EVENT_TYPE_MK_CHANGE_FINALIZE_QUERY: case EVENT_TYPE_MK_CHANGE_FINALIZE: case EVENT_TYPE_MK_CHANGE_CANCEL_QUERY: case EVENT_TYPE_MK_CHANGE_CANCEL: return cca_handle_mk_change_event(tokdata, event_type, event_flags, payload, payload_len); default: return CKR_FUNCTION_NOT_SUPPORTED; } return CKR_OK; } static CK_RV cca_convert_aes_data_to_cipher_key(STDLL_TokData_t *tokdata, SESSION *session, OBJECT *obj, CK_BBOOL is_xts) { long return_code, reason_code, rule_array_count, target_key_len; unsigned char target_key_token[CCA_MAX_AES_CIPHER_KEY_SIZE * 2] = { 0 }; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0 }; unsigned char null_token[64] = { 0, }; long null_token_len = sizeof(null_token); long reserved_1 = 0, key_part1_len, inp_key_len; enum cca_token_type keytype, keytype2; unsigned int keybitsize, keybitsize2; const CK_BYTE *mkvp, *mkvp2; CK_BBOOL new_mk, new_mk2; CK_ATTRIBUTE *attr, *reenc_attr = NULL; CK_ULONG key_size; CK_IBM_CCA_AES_KEY_MODE_TYPE mode = CK_IBM_CCA_AES_CIPHER_KEY; CK_RV rc; UNUSED(session); rc = template_attribute_get_non_empty(obj->template, CKA_IBM_OPAQUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("%s CKA_IBM_OPAQUE is missing\n", __func__); return rc; } key_size = (is_xts ? attr->ulValueLen / 2 : attr->ulValueLen); if (analyse_cca_key_token(attr->pValue, key_size, &keytype, &keybitsize, &mkvp) == FALSE || mkvp == NULL) { TRACE_ERROR("Invalid/unknown cca token\n"); return CKR_FUNCTION_FAILED; } switch (keytype) { case sec_aes_data_key: break; case sec_aes_cipher_key: /* Already a CIPHER key, nothing to do */ return CKR_OK; default: TRACE_ERROR("Invalid/unknown cca token\n"); return CKR_FUNCTION_FAILED; } retry: memcpy(rule_array, "INTERNALAES CIPHER ANY-MODE", 4 * CCA_KEYWORD_SIZE); rule_array_count = 4; rc = cca_aes_cipher_add_key_usage_keywords(tokdata, obj->template, rule_array, sizeof(rule_array), (CK_ULONG *)&rule_array_count); if (rc != CKR_OK) { TRACE_ERROR("Failed to add key usage keywords\n"); return rc; } target_key_len = sizeof(target_key_token) / 2; USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNBKTB2(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &reserved_1, NULL, &reserved_1, NULL, &reserved_1, NULL, &reserved_1, NULL, &reserved_1, NULL, &target_key_len, target_key_token); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBKTB2 (AES CIPHER KEY TOKEN BUILD) failed." " return:%ld, reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } memcpy(rule_array, "AES REFORMAT", 2 * CCA_KEYWORD_SIZE); rule_array_count = 2; target_key_len = sizeof(target_key_token) / 2; inp_key_len = key_size; USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) RETRY_NEW_MK_BLOB_START() dll_CSNBKTR2(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &inp_key_len, attr->pValue, &null_token_len, null_token, &reserved_1, NULL, &target_key_len, target_key_token); RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, attr->pValue, key_size) USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBKTR2 (KEY TRANSLATE2) failed." " return:%ld, reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } if (analyse_cca_key_token(target_key_token, target_key_len, &keytype, &keybitsize, &mkvp) == FALSE || mkvp == NULL || keytype != sec_aes_cipher_key) { TRACE_ERROR("Invalid/unknown cca token has been imported\n"); return CKR_FUNCTION_FAILED; } if (check_expected_mkvp(tokdata, keytype, mkvp, &new_mk) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } rc = cca_reencipher_created_key(tokdata, obj->template, target_key_token, target_key_len, new_mk, keytype, FALSE); if (rc != CKR_OK) { TRACE_ERROR("cca_reencipher_created_key failed: 0x%lx\n", rc); return rc; } if (is_xts) { key_part1_len = target_key_len; memcpy(rule_array, "INTERNALAES CIPHER ANY-MODE", 4 * CCA_KEYWORD_SIZE); rule_array_count = 4; rc = cca_aes_cipher_add_key_usage_keywords(tokdata, obj->template, rule_array, sizeof(rule_array), (CK_ULONG *) &rule_array_count); if (rc != CKR_OK) { TRACE_ERROR("Failed to add key usage keywords\n"); return rc; } target_key_len = sizeof(target_key_token) - key_part1_len; USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) dll_CSNBKTB2(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &reserved_1, NULL, &reserved_1, NULL, &reserved_1, NULL, &reserved_1, NULL, &reserved_1, NULL, &target_key_len, target_key_token + key_part1_len); USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBKTB2 (AES CIPHER KEY TOKEN BUILD) failed." " return:%ld, reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } memcpy(rule_array, "AES REFORMAT", 2 * CCA_KEYWORD_SIZE); rule_array_count = 2; target_key_len = sizeof(target_key_token) - key_part1_len; inp_key_len = key_size; USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) RETRY_NEW_MK_BLOB_START() dll_CSNBKTR2(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &inp_key_len, attr->pValue, &null_token_len, null_token, &reserved_1, NULL, &target_key_len, target_key_token + key_part1_len); RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, attr->pValue, key_size) USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBKTR2 (KEY TRANSLATE2) failed." " return:%ld, reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } if (analyse_cca_key_token(target_key_token + key_part1_len, target_key_len, &keytype2, &keybitsize2, &mkvp2) == FALSE || mkvp2 == NULL || keytype2 != sec_aes_cipher_key) { TRACE_ERROR("Invalid/unknown cca token has been imported\n"); return CKR_FUNCTION_FAILED; } if (check_expected_mkvp(tokdata, keytype2, mkvp2, &new_mk2) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } if (new_mk == FALSE && new_mk2 == TRUE) { /* * Key 2 was created with new MK, key 1 with old MK. * Key 2 will have CKA_IBM_OPAQUE and CKA_IBM_OPAQUE_REENC both * with new MK (will be set by cca_reencipher_created_key() below). * Key 1 has CKA_IBM_OPAQUE with old MK, and CKA_IBM_OPAQUE_REENC * with new MK (it was re-enciphered by cca_reencipher_created_key() * above). Supply CKA_IBM_OPAQUE_REENC with new MK in CKA_IBM_OPAQUE * for key 1 also, so that both, CKA_IBM_OPAQUE and * CKA_IBM_OPAQUE_REENC have new MK only for both key parts. */ rc = template_attribute_get_non_empty(obj->template, CKA_IBM_OPAQUE_REENC, &reenc_attr); if (rc != CKR_OK || reenc_attr == NULL || reenc_attr->ulValueLen != (CK_ULONG)key_part1_len) { TRACE_ERROR("No CKA_IBM_OPAQUE_REENC attr found\n"); return CKR_TEMPLATE_INCOMPLETE; } memcpy(target_key_token, reenc_attr->pValue, key_part1_len); } else if (new_mk == TRUE && new_mk2 == FALSE) { /* * Key 1 was created with new MK, but key 2 with old MK. * This can happen when an APQN with new MK went offline * and another APQN with old MK is selected after creating * key 1 but before creating key 2. Since there is no key 1 blob * with old MK in CKA_IBM_OPAQUE, we need to re-create both keys * (both with old MK now). */ memset(target_key_token, 0, sizeof(target_key_token)); goto retry; } rc = cca_reencipher_created_key(tokdata, obj->template, target_key_token + key_part1_len, target_key_len, new_mk2, keytype2, TRUE); if (rc != CKR_OK) { TRACE_ERROR("cca_reencipher_created_key failed: 0x%lx\n", rc); return rc; } if (memcmp(mkvp, mkvp2, CCA_MKVP_LENGTH) != 0 || keybitsize != keybitsize2) { TRACE_ERROR("CCA AES XTS keys attribute value mismatch\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } target_key_len += key_part1_len; } rc = build_update_attribute(obj->template, CKA_IBM_OPAQUE, target_key_token, target_key_len); if (rc != CKR_OK) { TRACE_DEVEL("build_update_attribute(CKA_IBM_OPAQUE) failed\n"); return rc; } rc = build_update_attribute(obj->template, CKA_IBM_CCA_AES_KEY_MODE, (CK_BYTE *)&mode, sizeof(mode)); if (rc != CKR_OK) { TRACE_DEVEL("build_update_attribute(CKA_IBM_CCA_AES_KEY_MODE) failed\n"); return rc; } return CKR_OK; } CK_RV token_specific_set_attribute_values(STDLL_TokData_t *tokdata, SESSION *session, OBJECT *obj, TEMPLATE *new_tmpl) { long return_code, reason_code; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; unsigned char exit_data[4]; long rule_array_count, exit_data_len = 0, zero = 0, key_len; enum cca_token_type keytype, keytype2; unsigned int keybitsize, keybitsize2; const CK_BYTE *mkvp, *mkvp2; CK_BBOOL new_mk, new_mk2; CK_OBJECT_CLASS class; CK_KEY_TYPE ktype; DL_NODE *node; CK_ATTRIBUTE *attr, *reenc_attr; CK_ULONG key_size; CK_RV rc; UNUSED(session); rc = template_attribute_get_ulong(obj->template, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("%s CKA_CLASS is missing\n", __func__); return rc; } switch (class) { case CKO_SECRET_KEY: case CKO_PRIVATE_KEY: case CKO_PUBLIC_KEY: break; default: /* Not a key, nothing to do */ return CKR_OK; } rc = template_attribute_get_ulong(obj->template, CKA_KEY_TYPE, &ktype); if (rc != CKR_OK) { TRACE_ERROR("%s CKA_KEY_TYPE is missing\n", __func__); return rc; } switch (ktype) { case CKK_AES: case CKK_AES_XTS: memcpy(rule_array, "AES ", CCA_KEYWORD_SIZE); rule_array_count = 1; break; case CKK_GENERIC_SECRET: memcpy(rule_array, "HMAC ", CCA_KEYWORD_SIZE); rule_array_count = 1; break; case CKK_EC: if (class != CKO_PRIVATE_KEY) return CKR_OK; return ccatok_check_ec_derive_info(tokdata, obj, new_tmpl); case CKK_EC_EDWARDS: return CKR_OK; default: /* Not an AES or HMAC key, nothing to do */ return CKR_OK; } node = new_tmpl->attribute_list; while (node) { attr = (CK_ATTRIBUTE *)node->data; switch (attr->type) { case CKA_EXTRACTABLE: if (attr->ulValueLen != sizeof(CK_BBOOL) || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } if (*((CK_BBOOL *)attr->pValue) != FALSE) continue; memcpy(rule_array + (rule_array_count * CCA_KEYWORD_SIZE), "NOEX-SYMNOEXUASYNOEXAASYNOEX-DESNOEX-AESNOEX-RSA", 6 * CCA_KEYWORD_SIZE); rule_array_count += 6; break; case CKA_IBM_CCA_AES_KEY_MODE: if (ktype != CKK_AES && ktype != CKK_AES_XTS) break; if (attr->ulValueLen != sizeof(CK_IBM_CCA_AES_KEY_MODE_TYPE) || attr->pValue == NULL || *((CK_IBM_CCA_AES_KEY_MODE_TYPE *)attr->pValue) != CK_IBM_CCA_AES_CIPHER_KEY) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } rc = cca_convert_aes_data_to_cipher_key(tokdata, session, obj, ktype == CKK_AES_XTS); if (rc != CKR_OK) { TRACE_ERROR("%s cca_convert_data_to_cipher_key failed " "rc=0x%lx\n", __func__, rc); return rc; } break; } node = node->next; } if (rule_array_count == 1) return CKR_OK; /* Nothing to do */ rc = template_attribute_get_non_empty(obj->template, CKA_IBM_OPAQUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("%s CKA_IBM_OPAQUE is missing\n", __func__); return rc; } key_size = (ktype == CKK_AES_XTS ? attr->ulValueLen / 2 : attr->ulValueLen); if (analyse_cca_key_token(attr->pValue, key_size, &keytype, &keybitsize, &mkvp) == FALSE || mkvp == NULL) { TRACE_ERROR("Invalid/unknown cca token\n"); return CKR_FUNCTION_FAILED; } if (keytype != sec_aes_cipher_key && keytype != sec_hmac_key) return CKR_OK; /* AES DATA key can not be restricted, nothing to do */ rc = build_attribute(CKA_IBM_OPAQUE, attr->pValue, attr->ulValueLen, &attr); if (rc != CKR_OK) { TRACE_ERROR("%s build_attribute failed rc=0x%lx\n", __func__, rc); return rc; } retry: USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) RETRY_NEW_MK_BLOB_START() key_len = key_size; dll_CSNBRKA(&return_code, &reason_code, &exit_data_len, exit_data, &rule_array_count, rule_array, &key_len, attr->pValue, &zero, NULL, &zero, NULL, &zero, NULL); RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, attr->pValue, key_size) USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBRKA (Restrict Key Attribute) failed." " return:%ld, reason:%ld\n", return_code, reason_code); rc = CKR_FUNCTION_FAILED; goto out; } if (analyse_cca_key_token(attr->pValue, key_size, &keytype, &keybitsize, &mkvp) == FALSE || mkvp == NULL) { TRACE_ERROR("Invalid/unknown cca token has been generated\n"); rc = CKR_FUNCTION_FAILED; goto out; } if (check_expected_mkvp(tokdata, keytype, mkvp, &new_mk) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); rc = CKR_DEVICE_ERROR; goto out; } rc = cca_reencipher_created_key(tokdata, obj->template, attr->pValue, key_size, new_mk, keytype, FALSE); if (rc != CKR_OK) { TRACE_ERROR("cca_reencipher_created_key failed: 0x%lx\n", rc); goto out; } if (ktype == CKK_AES_XTS) { USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) RETRY_NEW_MK_BLOB_START() key_len = key_size; dll_CSNBRKA(&return_code, &reason_code, &exit_data_len, exit_data, &rule_array_count, rule_array, &key_len, (CK_BYTE *)attr->pValue + key_size, &zero, NULL, &zero, NULL, &zero, NULL); RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, (CK_BYTE *)attr->pValue + key_size, key_size) USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBRKA (Restrict Key Attribute) failed." " return:%ld, reason:%ld\n", return_code, reason_code); rc = CKR_FUNCTION_FAILED; goto out; } if (analyse_cca_key_token((CK_BYTE *)attr->pValue + key_size, key_size, &keytype2, &keybitsize2, &mkvp2) == FALSE || mkvp2 == NULL) { TRACE_ERROR("Invalid/unknown cca token has been generated\n"); rc = CKR_FUNCTION_FAILED; goto out; } if (check_expected_mkvp(tokdata, keytype2, mkvp2, &new_mk2) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); rc = CKR_DEVICE_ERROR; goto out; } if (new_mk == FALSE && new_mk2 == TRUE) { /* * Key 2 was created with new MK, key 1 with old MK. * Key 2 will have CKA_IBM_OPAQUE and CKA_IBM_OPAQUE_REENC both * with new MK (will be set by cca_reencipher_created_key() below). * Key 1 has CKA_IBM_OPAQUE with old MK, and CKA_IBM_OPAQUE_REENC * with new MK (it was re-enciphered by cca_reencipher_created_key() * above). Supply CKA_IBM_OPAQUE_REENC with new MK in CKA_IBM_OPAQUE * for key 1 also, so that both, CKA_IBM_OPAQUE and * CKA_IBM_OPAQUE_REENC have new MK only for both key parts. */ rc = template_attribute_get_non_empty(obj->template, CKA_IBM_OPAQUE_REENC, &reenc_attr); if (rc != CKR_OK || reenc_attr == NULL || reenc_attr->ulValueLen != key_size) { TRACE_ERROR("No CKA_IBM_OPAQUE_REENC attr found\n"); return CKR_TEMPLATE_INCOMPLETE; } memcpy(attr->pValue, reenc_attr->pValue, key_size); } else if (new_mk == TRUE && new_mk2 == FALSE) { /* * Key 1 was created with new MK, but key 2 with old MK. * This can happen when an APQN with new MK went offline * and another APQN with old MK is selected after creating * key 1 but before creating key 2. Since there is no key 1 blob * with old MK in CKA_IBM_OPAQUE, we need to re-create both keys * (both with old MK now). */ memset(attr->pValue, 0, sizeof(key_size)); goto retry; } rc = cca_reencipher_created_key(tokdata, obj->template, (CK_BYTE *)attr->pValue + key_size, key_size, new_mk2, keytype2, TRUE); if (rc != CKR_OK) { TRACE_ERROR("cca_reencipher_created_key failed: 0x%lx\n", rc); goto out; } if (keytype != keytype2 || memcmp(mkvp, mkvp2, CCA_MKVP_LENGTH) != 0 || keybitsize != keybitsize2) { TRACE_ERROR("CCA AES XTS keys attribute value mismatch\n"); rc = CKR_ATTRIBUTE_VALUE_INVALID; goto out; } } rc = template_update_attribute(obj->template, attr); if (rc != CKR_OK) { TRACE_ERROR("%s template_update_attribute failed rc=0x%lx\n", __func__, rc); goto out; } attr = NULL; out: if (attr != NULL) free(attr); return rc; } static CK_RV get_token_info_cb(STDLL_TokData_t *tokdata, const char *adapter, unsigned short card, unsigned short domain, void *private) { CK_CHAR *serialNumber = private; CK_ULONG i; CK_RV rc; UNUSED(tokdata); UNUSED(adapter); UNUSED(card); UNUSED(domain); if (serialNumber == NULL || serialNumber[0] != ' ') return CKR_OK; if (member_size(CK_TOKEN_INFO, serialNumber) < CCA_SERIALNO_LENGTH + 1) return CKR_BUFFER_TOO_SMALL; rc = cca_get_adapter_serial_number((char *)serialNumber); if (rc != CKR_OK) return rc; for (i = CCA_SERIALNO_LENGTH; i < member_size(CK_TOKEN_INFO, serialNumber); i++) serialNumber[i] = ' '; return CKR_OK; } CK_RV token_specific_get_token_info(STDLL_TokData_t *tokdata, CK_TOKEN_INFO_PTR pInfo) { struct cca_private_data *cca_private = tokdata->private_data; CK_RV rc; pInfo->firmwareVersion.major = cca_private->cca_lib_version.ver; pInfo->firmwareVersion.minor = cca_private->cca_lib_version.rel; if (pthread_rwlock_rdlock(&cca_private->min_card_version_rwlock) != 0) { TRACE_ERROR("CCA min_card_version RD-Lock failed.\n"); return CKR_CANT_LOCK; } pInfo->hardwareVersion.major = cca_private->min_card_version.ver; pInfo->hardwareVersion.minor = cca_private->min_card_version.rel; if (pthread_rwlock_unlock(&cca_private->min_card_version_rwlock) != 0) { TRACE_ERROR("CCA min_card_version RD-Unlock failed.\n"); return CKR_CANT_LOCK; } /* Supply serial number of first card (in case of DEV-ANY) */ rc = cca_iterate_adapters(tokdata, get_token_info_cb, pInfo->serialNumber); if (rc != CKR_OK) { TRACE_ERROR("Failed to obtain the serial number.\n"); return rc; } return CKR_OK; } opencryptoki-opencryptoki-451d99c/usr/lib/cca_stdll/cca_stdll.h000066400000000000000000000565141520105705100247470ustar00rootroot00000000000000 /* * 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__ #include #include "pkcs11types.h" #include "defs.h" #include "host_defs.h" #include "csulincl.h" #include "cca_func.h" #include "hsm_mk_change.h" #include "configuration.h" /* CCA library constants */ #define CCA_PRIVATE_KEY_NAME_SIZE 64 #define CCA_REGENERATION_DATA_SIZE 64 #define CCA_KEY_TOKEN_SIZE 8000 #define CCA_KEY_VALUE_STRUCT_SIZE 8000 #define CCA_MAX_AES_CIPHER_KEY_SIZE 455 #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 #define CCA_CHAIN_VECTOR_SHA3_LEN 256 /* 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 /* QSA constants */ #define CCA_QSA_KEY_VALUE_STRUCT_SIZE 8 #define CCA_PKB_QSA_CLEAR_FORMAT_OFFSET 1 #define CCA_PKB_QSA_ALGO_PARAM_OFFSET 2 #define CCA_PKB_QSA_CLEAR_LEN_OFFSET 4 #define CCA_QSA_ALGO_DILITHIUM_ROUND_2 0x01 #define CCA_QSA_ALGO_DILITHIUM_ROUND_3 0x03 #define CCA_QSA_ALGO_ML_DSA_PURE 0x05 #define CCA_QSA_ALGO_ML_KEM 0x06 #define CCA_QSA_ALGO_ML_DSA_PRE_HASH 0x07 #define CCA_QSA_ALGO_DILITHIUM_65 0x0605 #define CCA_QSA_ALGO_DILITHIUM_87 0x0807 #define CCA_QSA_ALGO_ML_DSA_44 0x0404 #define CCA_QSA_ALGO_ML_DSA_65 0x0605 #define CCA_QSA_ALGO_ML_DSA_87 0x0807 #define CCA_QSA_ALGO_ML_KEM_512 0x0512 #define CCA_QSA_ALGO_ML_KEM_768 0x0768 #define CCA_QSA_ALGO_ML_KEM_1024 0x1024 #define CCA_QSA_CLEAR_FORMAT_NO_KEY 0x00 #define CCA_QSA_CLEAR_FORMAT_KAT 0x01 #define CCA_QSA_CLEAR_FORMAT_PUB_ONLY 0x03 #define CCA_MAX_ML_DSA_SIGNATURE_LEN 5000 #define CCA_MAX_DILITHIUM_65_DATA_LEN 6000 #define CCA_MAX_DILITHIUM_87_DATA_LEN 4000 #define CCA_MAX_CEX8_DILITHIUM_65_DATA_LEN 18000 #define CCA_MAX_CEX8_DILITHIUM_87_DATA_LEN 16000 #define CCA_MAX_CEX8_ML_DSA_44_DATA_LEN 18000 #define CCA_MAX_CEX8_ML_DSA_65_DATA_LEN 18000 #define CCA_MAX_CEX8_ML_DSA_87_DATA_LEN 16000 /* * ECC private key section (X'20'), Key-usage and translation control flag. */ #define CCA_XPRTCPAC 0x01 #define CCA_ECC_TOKEN_KEYUSAGE_OFFSET 16 #define CCA_VAR_SYM_TOKEN_KEYMGMT1_OFFSET 50 #define CCA_VAR_SYM_XPRT_SYM 0x8000 #define CCA_VAR_SYM_XPRT_UASYM 0x4000 #define CCA_VAR_SYM_XPRT_AASYM 0x2000 #define CCA_VAR_SYM_XPRT_RAW 0x1000 #define CCA_VAR_SYM_XPRT_CPACF 0x0800 #define CCA_VAR_SYM_NOEX_DES 0x0080 #define CCA_VAR_SYM_NOEX_AES 0x0040 #define CCA_VAR_SYM_NOEX_RSA 0x0008 /* Key token generated by CSNDPKG */ /* CCA spec: page 460 & 470 & 471 */ #define CCA_PRIVKEY_ID 0x20 #define CCA_PUBLKEY_ID 0x21 #define CCA_ECCDERIVEINFO_ID 0x23 #define CCA_SECTION_LEN_OFFSET 2 #define CCA_SECTION_HEADER_LEN 4 #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 #define CCA_EC_INTTOK_PRIVKEY_KEY_SOURCE_OFFSET 11 #define CCA_EC_INTTOK_PRIVKEY_KEY_SOURCE_RANDOM 0x24 /* 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 (4096 bits, ME format) area of the length of n, the modulus */ #define CCA_RSA_INTTOK_PRIVKEY_ME_N_LENGTH_OFFSET 52 /* Offset into an RSA private key (4096 bits, ME format) area of n, the modulus */ #define CCA_RSA_INTTOK_PRIVKEY_ME_N_OFFSET 122 /* Offset into an RSA private key (4096 bits, CRT format) area of the length of n, the modulus */ #define CCA_RSA_INTTOK_PRIVKEY_CRT_N_LENGTH_OFFSET 62 /* Offset into an RSA private key (4096 bits, CRT format) area of n, the modulus */ #define CCA_RSA_INTTOK_PRIVKEY_CRT_N_OFFSET 134 /* 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 an QSA internal key token of the private key area */ #define CCA_QSA_INTTOK_PRIVKEY_OFFSET 8 /* Offset into an QSA private key area of the algorithm id */ #define CCA_QSA_INTTOK_ALGO_ID_OFFSET 9 /* Offset into an QSA private key area of the algorithm parameters */ #define CCA_QSA_INTTOK_ALGO_PARAMS_OFFSET 10 /* Offset into an QSA private key area of the MKVP */ #define CCA_QSA_INTTOK_MKVP_OFFSET 118 /* Offset into an QSA external key token of the public key area */ #define CCA_QSA_EXTTOK_PUBLKEY_OFFSET 8 /* Offset into an QSA public key area of the algorithm id */ #define CCA_QSA_EXTTOK_ALGO_ID_OFFSET 5 /* Offset into an QSA public key area of the algorithm parameters */ #define CCA_QSA_EXTTOK_ALGO_PARAMS_OFFSET 6 /* Offset into an QSA public key area of the rho length */ #define CCA_QSA_EXTTOK_RHO_OFFSET 10 /* Offset into an QSA public key area of the t1 length */ #define CCA_QSA_EXTTOK_T1_OFFSET 12 /* Offset into an QSA public key area of the pk length */ #define CCA_QSA_EXTTOK_PK_OFFSET 10 /* Offset into an QSA public key area of the seed length */ #define CCA_QSA_EXTTOK_SEED_OFFSET 12 /* Offset into an QSA public key area of the payload area */ #define CCA_QSA_EXTTOK_PAYLOAD_OFFSET 24 /* Offset into the rule array returned by STATCCA and length of the returned * CCA version field. */ #define CCA_STATCCA_CCA_VERSION_OFFSET 24 #define CCA_STATCCA_CCA_VERSION_LENGTH 8 /* Offset into the rule_array returned by the STATCCAE command for the * New and Current Symmetric Master Key register status */ #define CCA_STATCCAE_SYM_NMK_OFFSET 0 #define CCA_STATCCAE_SYM_CMK_OFFSET 8 /* Offset into the rule_array returned by the STATAES command for the * New and Current AES Master Key register status */ #define CCA_STATAES_AES_NMK_OFFSET 0 #define CCA_STATAES_AES_CMK_OFFSET 8 /* Offset into the rule_array returned by the STATAPKA command for the * New and Current APKA Master Key register status */ #define CCA_STATAPKA_APKA_NMK_OFFSET 0 #define CCA_STATAPKA_APKA_CMK_OFFSET 8 /* Offsets into the verb_data returned by the STATICSB command for the * Master Key register verification pattern */ #define CCA_STATICSB_SYM_CMK_ID 0x0f07 #define CCA_STATICSB_SYM_CMK_ID_OFFSET 134 /* ID = 0x0f07 */ #define CCA_STATICSB_SYM_CMK_MKVP_OFFSET 136 /* 8 bytes MKVP */ #define CCA_STATICSB_SYM_NMK_ID 0x0f06 #define CCA_STATICSB_SYM_NMK_ID_OFFSET 146 /* ID = 0x0f06 */ #define CCA_STATICSB_SYM_NMK_MKVP_OFFSET 148 /* 8 bytes MKVP */ #define CCA_STATICSB_AES_CMK_ID 0x0f0b #define CCA_STATICSB_AES_CMK_ID_OFFSET 182 /* ID = 0x0f0b */ #define CCA_STATICSB_AES_CMK_MKVP_OFFSET 184 /* 8 bytes MKVP */ #define CCA_STATICSB_AES_NMK_ID 0x0f0a #define CCA_STATICSB_AES_NMK_ID_OFFSET 194 /* ID = 0x0f0a */ #define CCA_STATICSB_AES_NMK_MKVP_OFFSET 196 /* 8 bytes MKVP */ #define CCA_STATICSB_APKA_CMK_ID 0x0f0e #define CCA_STATICSB_APKA_CMK_ID_OFFSET 218 /* ID = 0x0f0e */ #define CCA_STATICSB_APKA_CMK_MKVP_OFFSET 220 /* 8 bytes MKVP */ #define CCA_STATICSB_APKA_NMK_ID 0x0f0d #define CCA_STATICSB_APKA_NMK_ID_OFFSET 230 /* ID = 0x0f0d */ #define CCA_STATICSB_APKA_NMK_MKVP_OFFSET 232 /* 8 bytes MKVP */ /* Offset to start of public RSA key section for an external public RSA key token */ #define CCA_RSA_EXTTOK_PUBKEY_OFFSET 8 /* Offset to length of n within an public RSA key section in an ext public RSA key token */ #define CCA_RSA_EXTTOK_PUBKEY_N_LENGTH_OFFSET 10 /* Offset into the rule_array returned by the STATCRD2 command for the * adapter serial number */ #define CCA_STATCRD2_SERIAL_NUMBER_OFFSET 112 #define CCA_SERIALNO_LENGTH 8 /* CCA internal HMAC token payload bit length field offset */ #define CCA_HMAC_INTTOK_PAYLOAD_LENGTH_OFFSET 38 struct cca_key_derivation_data { uint8_t key_algorithm; /* CCA_AES_KEY or CCA_DES_KEY */ uint8_t key_type; /* CCA_KEY_DERIVE_TYPE_xxx values */ uint16_t key_size; /* in bits */ } __attribute__ ((__packed__)); #define CCA_KEY_DERIVE_TYPE_DATA 0x01 /* DATA key */ #define CCA_KEY_DERIVE_TYPE_CIPHER 0x04 /* CIPHER key */ struct cca_acp_segment { uint16_t start_bit_no; uint16_t end_bit_no; uint16_t num_bytes; uint16_t reserved; } __attribute__ ((__packed__)); #define ACP_BYTE_NO(acp) ((acp) / 8) #define ACP_BIT_IN_BYTE(acp) ((acp) % 8) #define ACP_BIT_MASK(acp) (0x80 >> ACP_BIT_IN_BYTE(acp)) struct cca_role_data { uint16_t version; /* 0x0101 */ char comment[20]; uint16_t auth_level; uint16_t lower_time_limit; /* 0xhhmm */ uint16_t upper_time_limit; /* 0xhhmm */ uint8_t days_valid; /* 7 bits, Sunday, Monday ... Saturday */ uint16_t num_segments; uint16_t reserved; } __attribute__ ((__packed__)); struct cca_acp_info { CK_BBOOL acp_03B8; /* Symmetric Key Export - AES, CKM-RAKW */ CK_BBOOL acp_03CD; /* Permit import of an AES key token from a PKCS#11 CKM_RSA_AES_KEY_WRAP object */ }; /* CCA STDLL constants */ #define CCATOK_MAX_N_LEN 1024 #define CCATOK_MAX_E_LEN 512 enum cca_key_type { CCA_AES_KEY = 0x02, CCA_DES_KEY = 0x01, }; #define CCA_DEFAULT_ADAPTER_ENVAR "CSU_DEFAULT_ADAPTER" #define CCA_DEFAULT_DOMAIN_ENVAR "CSU_DEFAULT_DOMAIN" #define CCA_DEVICE_ANY "DEV-ANY" #define CCA_DOMAIN_ANY "DOM-ANY" #define CCA_MKVP_LENGTH 8 enum cca_mk_type { CCA_MK_SYM, CCA_MK_AES, CCA_MK_APKA, }; #define CCA_NUM_MK_TYPES 3 enum cca_nmk_state { CCA_NMK_STATUS_CLEAR = 1, CCA_NMK_STATUS_PARTIAL = 2, CCA_NMK_STATUS_FULL = 3, }; enum cca_cmk_state { CCA_CMK_STATUS_CLEAR = 1, CCA_CMK_STATUS_FULL = 2, }; enum cca_ktc_type { CCA_KTC_DATA, CCA_KTC_CIPHER, CCA_KTC_PKA, }; /* CCA STDLL debug logging definitions */ #ifdef DEBUG #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 /* cca token type enum, used with analyse_cca_key_token() */ enum cca_token_type { sec_des_data_key, sec_aes_data_key, sec_aes_cipher_key, sec_hmac_key, sec_rsa_priv_key, sec_rsa_publ_key, sec_ecc_priv_key, sec_ecc_publ_key, sec_qsa_priv_key, sec_qsa_publ_key }; struct cca_mk_change_op { volatile int mk_change_active; char mk_change_op[8]; /* set if mk_change_active = 1 */ unsigned char new_sym_mkvp[CCA_MKVP_LENGTH]; unsigned char new_aes_mkvp[CCA_MKVP_LENGTH]; unsigned char new_apka_mkvp[CCA_MKVP_LENGTH]; CK_BBOOL new_sym_mkvp_set; CK_BBOOL new_aes_mkvp_set; CK_BBOOL new_apka_mkvp_set; struct apqn *apqns; unsigned int num_apqns; }; /* CCA token private data */ #define PKEY_MK_VP_LENGTH 32 #define PKEY_MODE_DISABLED 0 #define PKEY_MODE_DEFAULT 1 #define PKEY_MODE_ENABLED 2 #define AES_KEY_MODE_DATA 0 #define AES_KEY_MODE_CIPHER 1 #define ML_DSA_KEY_MODE_PURE 0 #define ML_DSA_KEY_MODE_PREHASH 1 struct cca_version { unsigned int ver; unsigned int rel; unsigned int mod; }; struct cca_private_data { void *lib_csulcca; struct cca_version cca_lib_version; struct cca_version min_card_version; struct cca_version min_cex7_card_version; struct cca_version min_cex8_card_version; pthread_rwlock_t min_card_version_rwlock; unsigned char expected_sym_mkvp[CCA_MKVP_LENGTH]; unsigned char expected_aes_mkvp[CCA_MKVP_LENGTH]; unsigned char expected_apka_mkvp[CCA_MKVP_LENGTH]; CK_BBOOL expected_sym_mkvp_set; CK_BBOOL expected_aes_mkvp_set; CK_BBOOL expected_apka_mkvp_set; CK_BBOOL dev_any; CK_BBOOL dom_any; unsigned int num_adapters; unsigned int num_domains; unsigned int num_usagedoms; unsigned short usage_domains[256]; CK_BBOOL inconsistent; struct cca_mk_change_op mk_change_ops[CCA_NUM_MK_TYPES]; char token_config_filename[PATH_MAX]; int pkey_mode; int pkey_wrap_supported; char pkey_mk_vp[PKEY_MK_VP_LENGTH]; pthread_rwlock_t pkey_rwlock; int pkeyfd; int msa_level; CK_BBOOL cka_sensitive_default_true; int aes_key_mode; int ml_dsa_key_mode; pthread_rwlock_t acp_info_rwlock; struct cca_acp_info acp_info; }; #define CCA_CFG_EXPECTED_MKVPS "EXPECTED_MKVPS" #define CCA_CFG_SYM_MKVP "SYM" #define CCA_CFG_AES_MKVP "AES" #define CCA_CFG_APKA_MKVP "APKA" #define SYSFS_BUS_AP "/sys/bus/ap/" #define SYSFS_DEVICES_AP "/sys/devices/ap/" #define REGEX_CARD_PATTERN "card[0-9a-fA-F]+" #define MASK_COPRO 0x10000000 extern CSUACRA_t dll_CSUACRA; extern CSUACRD_t dll_CSUACRD; extern CSNBKTC_t dll_CSNBKTC; extern CSNBKTC2_t dll_CSNBKTC2; extern CSNDKTC_t dll_CSNDKTC; /* * Macros to enclose CCA verbs that use a secure key blob. * If the CCA verb fails with return code 8 reason code 48 "One or more keys * has a master key verification pattern that is not valid.", check if the * secure key bob is enciphered with the new MK already. If so, and if a * MK change operation for that master key type is currently active, select * a single APQN that has the new MK set/activated. Wait in case no APQN is * currently available. Once a single APQN has been selected, retry the CCA * verb on the now selected single APQN. */ #define RETRY_NEW_MK_BLOB_START() \ do { \ int single_selected = 0; \ char serialno[CCA_SERIALNO_LENGTH + 1]; \ do { #define RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, \ blob, bloblen) \ RETRY_NEW_MK_BLOB2_END(tokdata, return_code, reason_code, \ blob, bloblen, NULL, 0) #define RETRY_NEW_MK_BLOB2_END(tokdata, return_code, reason_code, \ blob1, bloblen1, blob2, bloblen2) \ if (constant_time_eq((return_code), 8) & \ constant_time_eq((reason_code), 48)) { \ TRACE_DEVEL("%s MKVP mismatch\n", __func__); \ if (!single_selected && \ cca_check_blob_select_single_apqn((tokdata), \ (blob1), (bloblen1), \ (blob2), (bloblen2), \ serialno)) { \ single_selected = 1; \ continue; \ } \ } \ if (single_selected) { \ if (cca_deselect_single_apqn((tokdata), \ serialno) != CKR_OK) { \ TRACE_ERROR("%s Failed to de-select single " \ "APQN\n", __func__); \ (return_code) = 16; \ (reason_code) = 336; \ } \ } \ break; \ } while (1); \ } while (0); /* * Macros to enclose any usage of CCA verbs. * Obtains a READ lock on the CCA adapter lock, if a DOM-ANY configuration is * used. This prevents CCA adapter usage concurrent to another thread performing * Domain selection processing. Domain selection works on process scope, so * it would influence all threads that currently use CCA verbs. */ #define USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) \ do { \ if (((struct cca_private_data *) \ (tokdata)->private_data)->dom_any) { \ if (pthread_rwlock_rdlock(&cca_adapter_rwlock) \ != 0) { \ TRACE_ERROR("CCA adapter RD-Lock failed.\n"); \ (return_code) = 16; \ (reason_code) = 336; \ break; \ } \ } #define USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) \ if (((struct cca_private_data *) \ (tokdata)->private_data)->dom_any) { \ if (pthread_rwlock_unlock(&cca_adapter_rwlock) \ != 0) { \ TRACE_ERROR("CCA adapter Unlock failed.\n"); \ (return_code) = 16; \ (reason_code) = 336; \ break; \ } \ } \ } while (0); extern pthread_rwlock_t cca_adapter_rwlock; CK_RV build_update_attribute(TEMPLATE * tmpl, CK_ATTRIBUTE_TYPE type, CK_BYTE * data, CK_ULONG data_len); CK_BBOOL analyse_cca_key_token(const CK_BYTE *t, CK_ULONG tlen, enum cca_token_type *keytype, unsigned int *keybitsize, const CK_BYTE **mkvp); CK_RV check_expected_mkvp(STDLL_TokData_t *tokdata, enum cca_token_type keytype, const CK_BYTE *mkvp, CK_BBOOL *new_mk); CK_RV cca_get_mkvps(unsigned char *cur_sym, unsigned char *new_sym, unsigned char *cur_aes, unsigned char *new_aes, unsigned char *cur_apka, unsigned char *new_apka); CK_RV cca_get_mk_state(enum cca_mk_type mk_type, enum cca_cmk_state *cur, enum cca_nmk_state *new); void cca_config_parse_error(int line, int col, const char *msg); CK_RV cca_config_parse_exp_mkvps(char *fname, struct ConfigStructNode *exp_mkvp_node, unsigned char *expected_sym_mkvp, CK_BBOOL *expected_sym_mkvp_set, unsigned char *expected_aes_mkvp, CK_BBOOL *expected_aes_mkvp_set, unsigned char *expected_apka_mkvp, CK_BBOOL *expected_apka_mkvp_set); CK_RV cca_get_adapter_serial_number(char *serialno); CK_RV cca_iterate_adapters(STDLL_TokData_t *tokdata, CK_RV (*cb)(STDLL_TokData_t *tokdata, const char *adapter, unsigned short card, unsigned short domain, void *private), void *cb_private); unsigned char *cca_mk_change_find_mkvp_in_ops(STDLL_TokData_t *tokdata, enum cca_mk_type mk_type, unsigned int *idx); struct cca_mk_change_op *cca_mk_change_find_op_by_keytype( STDLL_TokData_t *tokdata, enum cca_token_type keytype); CK_RV cca_mk_change_check_pending_ops(STDLL_TokData_t *tokdata); CK_BBOOL cca_check_blob_select_single_apqn(STDLL_TokData_t *tokdata, const CK_BYTE *sec_key1, CK_ULONG sec_key1_len, const CK_BYTE *sec_key2, CK_ULONG sec_key2_len, char *serialno); CK_RV cca_deselect_single_apqn(STDLL_TokData_t *tokdata, char *serialno); CK_RV cca_reencipher_created_key(STDLL_TokData_t *tokdata, TEMPLATE* tmpl, CK_BYTE *sec_key, CK_ULONG sec_key_len, CK_BBOOL new_mk, enum cca_token_type keytype, CK_BBOOL aes_xts_2dn_key); CK_RV cca_handle_mk_change_event(STDLL_TokData_t *tokdata, unsigned int event_type, unsigned int event_flags, const char *payload, unsigned int payload_len); #endif opencryptoki-opencryptoki-451d99c/usr/lib/cca_stdll/cca_stdll.mk000066400000000000000000000054711520105705100251230ustar00rootroot00000000000000nobase_lib_LTLIBRARIES += opencryptoki/stdll/libpkcs11_cca.la EXTRA_DIST += usr/lib/cca_stdll/ccatok.conf 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 -DNODSA -DNODH \ -DTOK_NEW_DATA_STORE=0x0003000c \ -I${srcdir}/usr/lib/cca_stdll -I${srcdir}/usr/lib/common \ -I${srcdir}/usr/include -DSTDLL_NAME=\"ccatok\" \ -I${top_builddir}/usr/lib/api -I${srcdir}/usr/lib/api \ -I${top_builddir}/usr/lib/config -I${srcdir}/usr/lib/config \ -I${srcdir}/usr/lib/hsm_mk_change \ -I${top_builddir}/usr/lib/hsm_mk_change if AIX opencryptoki_stdll_libpkcs11_cca_la_LDFLAGS = -qmkshrobj -lcrypto \ -lpthread -qnocrt -lrt -ldl -Wl,-bnoautoexp -Wl,-bstatic,-llber,-bdynamic \ -export-symbols ${srcdir}/opencryptoki_tok.map.sym else opencryptoki_stdll_libpkcs11_cca_la_LDFLAGS = -shared \ -Wl,-z,defs,-Bsymbolic -lcrypto -lpthread -nostartfiles \ -Wl,-soname,$@ -lrt -ldl -llber \ -Wl,--version-script=${srcdir}/opencryptoki_tok.map endif 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/common/profile_obj.c usr/lib/cca_stdll/cca_specific.c \ usr/lib/common/attributes.c usr/lib/common/dlist.c \ usr/lib/common/utility_common.c usr/lib/common/ec_supported.c \ usr/lib/api/policyhelper.c usr/lib/config/configuration.c \ usr/lib/config/cfgparse.y usr/lib/config/cfglex.l \ usr/lib/common/mech_openssl.c usr/lib/common/pqc_supported.c \ usr/lib/hsm_mk_change/hsm_mk_change.c \ usr/lib/common/btree.c usr/lib/common/sess_mgr.c \ usr/lib/cca_stdll/cca_mkchange.c usr/lib/common/mech_pqc.c if AIX opencryptoki_stdll_libpkcs11_cca_la_SOURCES += usr/lib/common/aix/short_name.c endif if !NO_PKEY opencryptoki_stdll_libpkcs11_cca_la_SOURCES += \ usr/lib/common/pkey_utils.c endif opencryptoki-opencryptoki-451d99c/usr/lib/cca_stdll/ccatok.conf000066400000000000000000000112551520105705100247520ustar00rootroot00000000000000version cca-0 # Optionally specify the expected master key verification patterns for the # SYM, AES, and APKA master key. The CCA token does not use the ASYM master key. # # You can use the TKE or panel.exe to query the current master key verification # pattern: # panel.exe --mk-query --mktype=SYM --mkregister=CURRENT # panel.exe --mk-query --mktype=AES --mkregister=CURRENT # panel.exe --mk-query --mktype=APKA --mkregister=CURRENT # For SYM, use the hex string under [RND], for AES and APKA use the hex string # under [VER]. # For AES and APKA you can also find the master key verification patterns # in sysfs: 'cat /sys/bus/ap/devices/./mkvps' # # EXPECTED_MKVPS # { # SYM = "" # AES = "" # APKA = "" # } # # -------------------------------------------------------------------------- # # For s390x (Linux on IBM Z) systems: # # To optimize encrypt/decrypt and sign/verify performance, a corresponding # protected key can be created for AES and EC secure keys and added to the # secure key. This protected key is then used for certain mechanisms via # CPACF, instead of performing the function via the CCA coprocessor. # IBM specific boolean attribute CKA_IBM_PROTKEY_EXTRACTABLE must be true to # make a key eligible for protected key support. # # AES-XTS related mechanisms are only available if the PKEY_MODE option is not # disabled and additional hardware and firmware prerequisites are met. AES-XTS # is not supported via the CCA coprocessor itself. # # PKEY_MODE = DISABLED | DEFAULT | ENABLED # # DISABLED : Protected key support disabled. All keys are used # via their secure key attribute. This option allows # to completely disable protected key support, e.g. # for performance comparisons. # # DEFAULT : Use defaults for CKA_IBM_PROTKEY_EXTRACTABLE. If # the application did not specify # CKA_IBM_PROTKEY_EXTRACTABLE = true in its template, # new keys of any type get default value # CKA_IBM_PROTKEY_EXTRACTABLE = false. # # ENABLED : Enable protected key support for all keys. # If the application did not specify # CKA_IBM_PROTKEY_EXTRACTABLE = false in its template, # new keys of any type get CKA_IBM_PROTKEY_EXTRACTABLE # = true and a protected key is automatically created # at first use of the key. # # -------------------------------------------------------------------------- # # To force that the default for CKA_SENSITIVE is CK_TRUE for # secret keys specify the following option: # # FORCE_SENSITIVE # # -------------------------------------------------------------------------- # # The AES_KEY_MODE option specifies the mode of the CCA AES secure keys that # are used to back AES key objects of the CCA token. Possible values are # 'DATA' (this is the default) and 'CIPHER'. # CCA AES CIPHER secure keys can be export-restricted, while AES DATA keys can # not. When the AES_KEY_MODE option is specified, newly generated or imported # keys will use CCA AES CIPHER or CCA AES DATA secure keys according to the # option value. If the AES_KEY_MODE is omitted, then CCA AES DATA secure keys # are generated or imported. Existing key objects that are backed by AES DATA # secure keys can still be used. # # Note: When CCA AES CIPHER keys are used, wrapping and unwrapping of such # AES CIPHER keys with mechanisms CKM_RSA_PKCS and CKM_RSA_PKCS_OAEP is not # possible. Wrapping and unwrapping of CCA AES DATA keys is possible with those # mechanisms. # # AES_KEY_MODE = DATA | CIPHER # # -------------------------------------------------------------------------- # # The ML_DSA_KEY_MODE option specifies the mode of the CCA ML-DSA secure keys # that are used to back ML-DSA key objects of the CCA token. Possible values are # 'PURE' (this is the default) and 'PREHASH'. # ML-DSA keys in 'PURE' mode can be used for Pure-ML-DSA sign/verify only, that # is, only mechanism CKM_ML_DSA can be used with them. # ML-DSA keys in 'PREHASH' mode can be used for PreHash-ML-DSA sign/verify only, # that is, only mechanisms CKM_HASH_ML_DSA[_xxx] can be used with them. # When the ML_DSA_KEY_MODE option is specified, newly generated or imported # ML-DSA keys will use CCA Pure-ML-DSA or CCA Prehash-ML-DSA secure keys # according to the option value. If the ML_DSA_KEY_MODE is omitted, then CCA # Pure-ML-DSA secure keys are generated or imported. # # ML_DSA_KEY_MODE = PURE | PREHASH # opencryptoki-opencryptoki-451d99c/usr/lib/cca_stdll/csulincl.h000066400000000000000000004044441520105705100246320ustar00rootroot00000000000000/* * 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__ opencryptoki-opencryptoki-451d99c/usr/lib/cca_stdll/defs.h000066400000000000000000000021201520105705100237200ustar00rootroot00000000000000/* * 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_SHA3_LEN 256 #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_SHA3_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 opencryptoki-opencryptoki-451d99c/usr/lib/cca_stdll/tok_struct.h000066400000000000000000000135661520105705100252200ustar00rootroot00000000000000/* * 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", TRUE, // 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_get_token_info, &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 &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 &token_specific_ec_sign, &token_specific_ec_verify, &token_specific_ec_edwards_sign, &token_specific_ec_edwards_verify, &token_specific_ec_generate_keypair, &token_specific_ec_edwards_generate_keypair, NULL, // ec_montgomery_generate_keypair NULL, // ecdh_derive &token_specific_ecdh_pkcs_derive_kdf, 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, // SHAKE derive NULL, // shake_key_derive // 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 &token_specific_aes_key_gen, #ifndef NO_PKEY &token_specific_aes_xts_key_gen, #else NULL, #endif &token_specific_aes_ecb, &token_specific_aes_cbc, NULL, // aes_ctr &token_specific_aes_gcm_init, &token_specific_aes_gcm, NULL, // aes_gcm_update NULL, // aes_gcm_final NULL, // aes_ofb NULL, // aes_cfb NULL, // aes_mac NULL, // aes_cmac #ifndef NO_PKEY &token_specific_aes_xts, #else NULL, #endif NULL, // aes_key_wrap // DSA NULL, // dsa_generate_keypair NULL, // dsa_sign NULL, // dsa_verify // PQC &token_specific_ibm_ml_dsa_generate_keypair, &token_specific_ibm_ml_dsa_sign, &token_specific_ibm_ml_dsa_verify, &token_specific_ibm_ml_kem_generate_keypair, &token_specific_ibm_ml_kem_derive, &token_specific_ml_dsa_generate_keypair, &token_specific_ml_dsa_sign, &token_specific_ml_dsa_verify, NULL, // ml_kem_generate_keypair NULL, // ml_kem_encapsulate_key NULL, // ml_kem_decapsulate_key &token_specific_get_mechanism_list, &token_specific_get_mechanism_info, &token_specific_object_add, &token_specific_key_wrap, &token_specific_key_unwrap, NULL, // encapsulate_rsa_sym_keygen NULL, // encapsulate_rsa_key_wrap NULL, // encapsulate_rsa_key_unwrap NULL, // encapsulate_dh_ecdh_key_pair_gen NULL, // en_decapsulate_dh_ecdh_derive_key &token_specific_reencrypt_single, &token_specific_set_attribute_values, &token_specific_set_attrs_for_new_object, &token_specific_handle_event, NULL, // check_obj_access }; #endif opencryptoki-opencryptoki-451d99c/usr/lib/common/000077500000000000000000000000001520105705100221735ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/usr/lib/common/aix/000077500000000000000000000000001520105705100227545ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/usr/lib/common/aix/asprintf.h000066400000000000000000000023331520105705100247540ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2024 * * 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 UTIL_LINUX_ASPRINTF_H #define UTIL_LINUX_ASPRINTF_H #include #include #include #ifndef HAVE_VASPRINTF static inline int vasprintf(char **strp, const char *fmt, va_list ap) { int str_size = -1, len; va_list cap; va_copy(cap, ap); len = vsnprintf(0, 0, fmt, cap); va_end(cap); if (len < 0) return -1; *strp = (char *)malloc (len + 1); if (!*strp) return -1; str_size = vsnprintf(*strp, len + 1, fmt, ap); if (str_size < 0 || str_size >= len + 1) { free(*strp); str_size = -1; } return str_size; } #endif #ifndef HAVE_ASPRINTF static inline int asprintf(char **strp, const char *fmt, ...) { int res; va_list ap; va_start (ap, fmt); res = vasprintf (strp, fmt, ap); va_end (ap); return res; } #endif #endif opencryptoki-opencryptoki-451d99c/usr/lib/common/aix/endian.h000066400000000000000000000054631520105705100243730ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2024 * * 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 GENERIC_AIX_BYTESWAP_H #define GENERIC_AIX_BYTESWAP_H #include #include #ifndef bswap_16 # define bswap_16(x) \ ((uint16_t)((((uint16_t) (x) & 0xff00) >> 8) | \ (((uint16_t) (x) & 0x00ff) << 8))) #endif /* !bswap_16 */ #ifndef bswap_32 # define bswap_32(x) \ ((uint32_t)((((uint32_t) (x) & 0xff000000) >> 24) | \ (((uint32_t) (x) & 0x00ff0000) >> 8) | \ (((uint32_t) (x) & 0x0000ff00) << 8) | \ (((uint32_t) (x) & 0x000000ff) << 24))) #endif /* !bswap_32 */ #ifndef bswap_64 # define bswap_64(x) \ ((uint64_t)((((uint64_t) (x) & 0xff00000000000000ULL) >> 56) | \ (((uint64_t) (x) & 0x00ff000000000000ULL) >> 40) | \ (((uint64_t) (x) & 0x0000ff0000000000ULL) >> 24) | \ (((uint64_t) (x) & 0x000000ff00000000ULL) >> 8) | \ (((uint64_t) (x) & 0x00000000ff000000ULL) << 8) | \ (((uint64_t) (x) & 0x0000000000ff0000ULL) << 24) | \ (((uint64_t) (x) & 0x000000000000ff00ULL) << 40) | \ (((uint64_t) (x) & 0x00000000000000ffULL) << 56))) #endif /* !bswap_64 */ #endif /* GENERIC_AIX_BYTESWAP_H */ #ifndef GENERIC_AIX_ENDIAN_H #define GENERIC_AIX_ENDIAN_H #ifndef htobe16 # if __BIG_ENDIAN__ # define htobe16(x) (x) # define htole16(x) bswap_16(x) # define be16toh(x) (x) # define le16toh(x) bswap_16(x) # else /* __BIG_ENDIAN__ */ # define htobe16(x) bswap_16(x) # define htole16(x) (x) # define be16toh(x) bswap_16(x) # define le16toh(x) (x) # endif /* __BIG_ENDIAN__ */ #endif /* !htobe16 */ #ifndef htobe32 # if __BIG_ENDIAN__ # define htobe32(x) (x) # define htole32(x) bswap_32(x) # define be32toh(x) (x) # define le32toh(x) bswap_32(x) # else /* __BIG_ENDIAN__ */ # define htobe32(x) bswap_32(x) # define htole32(x) (x) # define be32toh(x) bswap_32(x) # define le32toh(x) (x) # endif /* __BIG_ENDIAN__ */ #endif /* !htobe32 */ #ifndef htobe64 # if __BIG_ENDIAN__ # define htobe64(x) (x) # define htole64(x) bswap_64(x) # define be64toh(x) (x) # define le64toh(x) bswap_64(x) #else /* __BIG_ENDIAN__ */ # define htobe64(x) bswap_64(x) # define htole64(x) (x) # define be64toh(x) bswap_64(x) # define le64toh(x) (x) # endif /* __BIG_ENDIAN__ */ #endif /* !htobe64 */ #endif /* GENERIC_AIX_ENDIAN_H */ opencryptoki-opencryptoki-451d99c/usr/lib/common/aix/err.c000066400000000000000000000042621520105705100237140ustar00rootroot00000000000000/* * Implementation of the err/errx/verr/verrx/warn/warnx/vwarn/vwarnx * functions from BSD. * * This file is public-domain; anyone may deal in it without restriction. * * Written by Graue on January 16, 2006. */ #if defined(__WIN32) || defined(_AIX) #define NEED_ERR #define LACK_PROGNAME #define NEED_ENDIAN_STUBS #define LACK_SYSTYPES #endif #ifdef NEED_ERR /* err/warn family of functions cheat sheet: Print: last component of program name [ if fmt is non-NULL ": " the formatted error message ] [ if function name does not end in x ": " strerror(errno) ] newline Then if function name has "err" in it, quit with exit code `eval'. BSD's -x versions actually print ": " at the end if passed NULL, so I duplicate that behavior. Passing these functions NULL is kind of useless though. */ #include #include #include #include #include extern const char *__progname; #define progname __progname void vwarn(const char *fmt, va_list args) { fputs(progname, stderr); if (fmt != NULL) { fputs(": ", stderr); vfprintf(stderr, fmt, args); } fputs(": ", stderr); fputs(strerror(errno), stderr); putc('\n', stderr); } void vwarnx(const char *fmt, va_list args) { fputs(progname, stderr); fputs(": ", stderr); if (fmt != NULL) vfprintf(stderr, fmt, args); putc('\n', stderr); } void verr(int eval, const char *fmt, va_list args) { vwarn(fmt, args); exit(eval); } void verrx(int eval, const char *fmt, va_list args) { vwarnx(fmt, args); exit(eval); } void warn(const char *fmt, ...) { va_list argptr; va_start(argptr, fmt); vwarn(fmt, argptr); va_end(argptr); } void warnx(const char *fmt, ...) { va_list argptr; va_start(argptr, fmt); vwarnx(fmt, argptr); va_end(argptr); } void err(int eval, const char *fmt, ...) { va_list argptr; va_start(argptr, fmt); verr(eval, fmt, argptr); /* NOTREACHED, so don't worry about va_end() */ } void errx(int eval, const char *fmt, ...) { va_list argptr; va_start(argptr, fmt); verrx(eval, fmt, argptr); /* NOTREACHED, so don't worry about va_end() */ } #endif opencryptoki-opencryptoki-451d99c/usr/lib/common/aix/err.h000066400000000000000000000015261520105705100237210ustar00rootroot00000000000000/* * Implementation of the err/errx/verr/verrx/warn/warnx/vwarn/vwarnx * functions from BSD. * * This file is public-domain; anyone may deal in it without restriction. * * Written by Graue on January 16, 2006. */ #if defined(__WIN32) || defined(_AIX) #define NEED_ERR #endif #ifndef NEED_ERR #include /* system version of this file */ #else #ifndef _ERR_H #define _ERR_H #include void err (int eval, const char *fmt, ...); void errx (int eval, const char *fmt, ...); void verr (int eval, const char *fmt, va_list args); void verrx (int eval, const char *fmt, va_list args); void warn ( const char *fmt, ...); void warnx( const char *fmt, ...); void vwarn ( const char *fmt, va_list args); void vwarnx( const char *fmt, va_list args); #endif #endif opencryptoki-opencryptoki-451d99c/usr/lib/common/aix/getopt.h000066400000000000000000000012711520105705100244300ustar00rootroot00000000000000/* * Portions Copyright (c) 1987, 1993, 1994 * The Regents of the University of California. All rights reserved. * * Portions Copyright (c) 2003-2022, PostgreSQL Global Development Group */ /* This code is only used on AIX; Linux uses its own glibc implementation */ #ifndef GETOPT_EXT_H #define GETOPT_EXT_H /* getopt is provided by unistd, according to POSIX */ #include struct option { const char *name; int has_arg; int *flag; int val; }; #define no_argument 0 #define required_argument 1 #define optional_argument 2 int getopt_long(int argc, char *const argv[], const char *optstring, const struct option *longopts, int *longindex); #endif /* GETOPT_EXT_H */ opencryptoki-opencryptoki-451d99c/usr/lib/common/aix/getopt_long.c000066400000000000000000000121601520105705100254410ustar00rootroot00000000000000/* * getopt_long() -- long options parser * * Portions Copyright (c) 1987, 1993, 1994 * The Regents of the University of California. All rights reserved. * * Portions Copyright (c) 2003 * PostgreSQL Global Development Group * * 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 the University 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 REGENTS 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 THE REGENTS OR 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. * * src/port/getopt_long.c */ #include #include #include "aix/getopt.h" #define BADCH '?' #define BADARG ':' #define EMSG "" /* * getopt_long * Parse argc/argv argument vector, with long options. * * This implementation does not use optreset. Instead, we guarantee that * it can be restarted on a new argv array after a previous call returned -1, * if the caller resets optind to 1 before the first call of the new series. * (Internally, this means we must be sure to reset "place" to EMSG before * returning -1.) */ int getopt_long(int argc, char *const argv[], const char *optstring, const struct option *longopts, int *longindex) { static char *place = EMSG; /* option letter processing */ char *oli; /* option letter list index */ if (!*place) { /* update scanning pointer */ if (optind >= argc) { place = EMSG; return -1; } place = argv[optind]; if (place[0] != '-') { place = EMSG; return -1; } place++; if (!*place) { /* treat "-" as not being an option */ place = EMSG; return -1; } if (place[0] == '-' && place[1] == '\0') { /* found "--", treat it as end of options */ ++optind; place = EMSG; return -1; } if (place[0] == '-' && place[1]) { /* long option */ size_t namelen; int i; place++; namelen = strcspn(place, "="); for (i = 0; longopts[i].name != NULL; i++) { if (strlen(longopts[i].name) == namelen && strncmp(place, longopts[i].name, namelen) == 0) { int has_arg = longopts[i].has_arg; if (has_arg != no_argument) { if (place[namelen] == '=') optarg = place + namelen + 1; else if (optind < argc - 1 && has_arg == required_argument) { optind++; optarg = argv[optind]; } else { if (optstring[0] == ':') return BADARG; if (opterr && has_arg == required_argument) fprintf(stderr, "%s: option requires an argument -- %s\n", argv[0], place); place = EMSG; optind++; if (has_arg == required_argument) return BADCH; optarg = NULL; } } else { optarg = NULL; if (place[namelen] != 0) { /* XXX error? */ } } optind++; if (longindex) *longindex = i; place = EMSG; if (longopts[i].flag == NULL) return longopts[i].val; else { *longopts[i].flag = longopts[i].val; return 0; } } } if (opterr && optstring[0] != ':') fprintf(stderr, "%s: illegal option -- %s\n", argv[0], place); place = EMSG; optind++; return BADCH; } } /* short option */ optopt = (int) *place++; oli = strchr(optstring, optopt); if (!oli) { if (!*place) ++optind; if (opterr && *optstring != ':') fprintf(stderr, "%s: illegal option -- %c\n", argv[0], optopt); return BADCH; } if (oli[1] != ':') { /* don't need argument */ optarg = NULL; if (!*place) ++optind; } else { /* need an argument */ if (*place) /* no white space */ optarg = place; else if (argc <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') return BADARG; if (opterr) fprintf(stderr, "%s: option requires an argument -- %c\n", argv[0], optopt); return BADCH; } else /* white space */ optarg = argv[optind]; place = EMSG; ++optind; } return optopt; } opencryptoki-opencryptoki-451d99c/usr/lib/common/aix/secure_getenv.h000066400000000000000000000012211520105705100257570ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2024 * * 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 SECURE_GETENV_H #define SECURE_GETENV_H #include #include static inline char* secure_getenv(char const *name) { if (geteuid() != getuid() || getegid() != getgid()) return NULL; return getenv(name); } #endif /* SECURE_GETENV_H */ opencryptoki-opencryptoki-451d99c/usr/lib/common/aix/short_name.c000066400000000000000000000023031520105705100252550ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2024 * * 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 defined(_AIX) #include #include #include #include #include #include /* program_invocation_short_name is GNU extension */ char program_invocation_short_name[256 + 1] = { NULL, }; void populate_progname(void) { struct psinfo ps; int psfd; snprintf(program_invocation_short_name, 256, "/proc/%lld/psinfo", getpid()); psfd = open(program_invocation_short_name, O_RDONLY); if (psfd == -1) { fprintf(stderr, "Failed to open procfs to read cmdname: %s\n", strerror(errno)); return; } if (read(psfd, &ps, sizeof(ps)) == -1) { fprintf(stderr, "Failed to populate psinfo: %s\n", strerror(errno)); return; } close(psfd); strncpy(program_invocation_short_name, ps.pr_fname, PRFNSZ); } #endif opencryptoki-opencryptoki-451d99c/usr/lib/common/asn1.c000066400000000000000000006511461520105705100232160ustar00rootroot00000000000000/* * 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" #include "pqc_defs.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_ULONG ber_int_len, CK_BYTE **data, CK_ULONG *data_len, CK_ULONG *field_len) { CK_ULONG len, length_octets; if (ber_int == NULL || ber_int_len < 2) { 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; if (1 + 1 + len > ber_int_len) { TRACE_ERROR("BER length is larger than encoded data.\n"); return CKR_FUNCTION_FAILED; } *data = &ber_int[2]; *data_len = len; if (len > 0 && 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 (1 + 1 + length_octets > ber_int_len) { TRACE_ERROR("BER length is larger than encoded data.\n"); return CKR_FUNCTION_FAILED; } if (length_octets == 1) { len = ber_int[2]; if (1 + (1 + 1) + len > ber_int_len) { TRACE_ERROR("BER length is larger than encoded data.\n"); return CKR_FUNCTION_FAILED; } *data = &ber_int[3]; *data_len = len; if (len > 0 && 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]; if (1 + (1 + 2) + len > ber_int_len) { TRACE_ERROR("BER length is larger than encoded data.\n"); return CKR_FUNCTION_FAILED; } *data = &ber_int[4]; *data_len = len; if (len > 0 && 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]; if (1 + (1 + 3) + len > ber_int_len) { TRACE_ERROR("BER length is larger than encoded data.\n"); return CKR_FUNCTION_FAILED; } *data = &ber_int[5]; *data_len = len; if (len > 0 && 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_ULONG str_len, 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 || str_len < 2) { 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; if (1 + 1 + len > str_len) { TRACE_ERROR("BER length is larger than encoded data.\n"); return CKR_FUNCTION_FAILED; } *data = &str[2]; *data_len = len; *field_len = 1 + (1) + len; return CKR_OK; } length_octets = str[1] & 0x7F; if (1 + 1 + length_octets > str_len) { TRACE_ERROR("BER length is larger than encoded data.\n"); return CKR_FUNCTION_FAILED; } if (length_octets == 1) { len = str[2]; if (1 + (1 + 1) + len > str_len) { TRACE_ERROR("BER length is larger than encoded data.\n"); return CKR_FUNCTION_FAILED; } *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]; if (1 + (1 + 2) + len > str_len) { TRACE_ERROR("BER length is larger than encoded data.\n"); return CKR_FUNCTION_FAILED; } *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]; if (1 + (1 + 3) + len > str_len) { TRACE_ERROR("BER length is larger than encoded data.\n"); return CKR_FUNCTION_FAILED; } *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_ULONG str_len, CK_BYTE **data, CK_ULONG *data_len, CK_ULONG *field_len) { CK_ULONG len, length_octets; if (!str || str_len < 2) { 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; if (1 + 1 + len > str_len) { TRACE_ERROR("BER length is larger than encoded data.\n"); return CKR_FUNCTION_FAILED; } if (len < 1) { TRACE_ERROR("BER length is too small to include the " "unused-bits-byte\n"); return CKR_FUNCTION_FAILED; } *data = &str[2]; *data_len = len; *field_len = 1 + (1) + len; return CKR_OK; } length_octets = str[1] & 0x7F; if (1 + 1 + length_octets > str_len) { TRACE_ERROR("BER length is larger than encoded data.\n"); return CKR_FUNCTION_FAILED; } if (length_octets == 1) { len = str[2]; if (1 + (1 + 1) + len > str_len) { TRACE_ERROR("BER length is larger than encoded data.\n"); return CKR_FUNCTION_FAILED; } if (len < 1) { TRACE_ERROR("BER length is too small to include the " "unused-bits-byte\n"); return CKR_FUNCTION_FAILED; } *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]; if (1 + (1 + 2) + len > str_len) { TRACE_ERROR("BER length is larger than encoded data.\n"); return CKR_FUNCTION_FAILED; } if (len < 1) { TRACE_ERROR("BER length is too small to include the " "unused-bits-byte\n"); return CKR_FUNCTION_FAILED; } *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]; if (1 + (1 + 3) + len > str_len) { TRACE_ERROR("BER length is larger than encoded data.\n"); return CKR_FUNCTION_FAILED; } if (len < 1) { TRACE_ERROR("BER length is too small to include the " "unused-bits-byte\n"); return CKR_FUNCTION_FAILED; } *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_ULONG seq_len, CK_BYTE **data, CK_ULONG *data_len, CK_ULONG *field_len) { CK_ULONG len, length_octets; if (!seq || seq_len < 2) { 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; if (1 + 1 + len > seq_len) { TRACE_ERROR("BER length is larger than encoded data.\n"); return CKR_FUNCTION_FAILED; } *data = &seq[2]; *data_len = len; *field_len = 1 + (1) + len; return CKR_OK; } length_octets = seq[1] & 0x7F; if (1 + 1 + length_octets > seq_len) { TRACE_ERROR("BER length is larger than encoded data.\n"); return CKR_FUNCTION_FAILED; } if (length_octets == 1) { len = seq[2]; if (1 + (1 + 1) + len > seq_len) { TRACE_ERROR("BER length is larger than encoded data.\n"); return CKR_FUNCTION_FAILED; } *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]; if (1 + (1 + 2) + len > seq_len) { TRACE_ERROR("BER length is larger than encoded data.\n"); return CKR_FUNCTION_FAILED; } *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]; if (1 + (1 + 3) + len > seq_len) { TRACE_ERROR("BER length is larger than encoded data.\n"); return CKR_FUNCTION_FAILED; } *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_BBOOL constructed) { 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] = 0x80 | (constructed ? 0x20 : 0x00) | option; // 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] = 0x80 | (constructed ? 0x20 : 0x00) | option; // 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] = 0x80 | (constructed ? 0x20 : 0x00) | option; // 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] = 0x80 | (constructed ? 0x20 : 0x00) | option; // 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; } CK_RV ber_decode_CHOICE(CK_BYTE *choice, CK_ULONG choice_len, CK_BBOOL constructed, CK_BYTE **data, CK_ULONG *data_len, CK_ULONG *field_len, CK_ULONG *option) { CK_ULONG len, length_octets; if (!choice || choice_len < 2) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } if ((choice[0] & 0xE0) != (0x80 | (constructed ? 0x20 : 0x00))) { 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; if (1 + 1 + len > choice_len) { TRACE_ERROR("BER length is larger than encoded data.\n"); return CKR_FUNCTION_FAILED; } *data = &choice[2]; *data_len = len; *field_len = 1 + (1) + len; return CKR_OK; } length_octets = choice[1] & 0x7F; if (1 + 1 + length_octets > choice_len) { TRACE_ERROR("BER length is larger than encoded data.\n"); return CKR_FUNCTION_FAILED; } if (length_octets == 1) { len = choice[2]; if (1 + (1 + 1) + len > choice_len) { TRACE_ERROR("BER length is larger than encoded data.\n"); return CKR_FUNCTION_FAILED; } *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]; if (1 + (1 + 2) + len > choice_len) { TRACE_ERROR("BER length is larger than encoded data.\n"); return CKR_FUNCTION_FAILED; } *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]; if (1 + (1 + 3) + len > choice_len) { TRACE_ERROR("BER length is larger than encoded data.\n"); return CKR_FUNCTION_FAILED; } *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); tmp = NULL; } 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); tmp = NULL; rc = ber_encode_SEQUENCE(FALSE, data, data_len, buf, len); if (rc != CKR_OK) TRACE_DEVEL("ber_encode_SEQUENCE failed\n"); error: if (tmp != NULL) free(tmp); 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_ULONG *priv_key_len) { 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, data_len, &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, buf_len - 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, buf_len - offset, &alg, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_SEQUENCE failed\n"); return rc; } offset += field_len; *algorithm = alg; *alg_len = len; rc = ber_decode_OCTET_STRING(buf + offset, buf_len - offset, priv_key, priv_key_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_ULONG spki_len, 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, out_seq_len, id_seq_len, bit_str_len; CK_ULONG field_len; CK_RV rc; *alg_oid_len = 0; *param_len = 0; *key_len = 0; out_seq = spki; out_seq_len = spki_len; rc = ber_decode_SEQUENCE(out_seq, out_seq_len, &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; id_seq_len = out_seq_len - field_len + data_len; /* get id seq */ rc = ber_decode_SEQUENCE(id_seq, id_seq_len, &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; } if (data_len < 2) { TRACE_ERROR("%s Length of id_seq is too short\n", __func__); return CKR_FUNCTION_FAILED; } *alg_oid = data; *alg_oid_len = data[1] + 2; if (*alg_oid_len > data_len) { TRACE_ERROR("%s Length of id_seq is too short\n", __func__); return CKR_FUNCTION_FAILED; } *param = data + *alg_oid_len; *param_len = data_len - *alg_oid_len; bit_str = id_seq + field_len; bit_str_len = id_seq_len - field_len; /* get bitstring */ rc = ber_decode_BIT_STRING(bit_str, bit_str_len, 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 // 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_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; 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 = 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; } 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 *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_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, rsa_priv_key_len; CK_RV rc; rc = ber_decode_PrivateKeyInfo(data, data_len, &alg, &len, &rsa_priv_key, &rsa_priv_key_len); 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, rsa_priv_key_len, &buf, &buf_len, &field_len); if (rc != CKR_OK) return rc; // parse the RSAPrivateKey // offset = 0; // Version // rc = ber_decode_INTEGER(buf + offset, buf_len - 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, buf_len - 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, buf_len - offset, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); goto cleanup; } offset += field_len; // private exponent // rc = ber_decode_INTEGER(buf + offset, buf_len - 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, buf_len - 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, buf_len - 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, buf_len - 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, buf_len - 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, buf_len - 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, buf_len - 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, buf_len - 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, buf_len - 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; } // private exponent // rc = ber_decode_INTEGER(buf + offset, buf_len - 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, buf_len - 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, buf_len - 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, buf_len - 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, buf_len - 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, buf_len - 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 (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 = 0, offset, total, total_len; CK_RV rc; CK_BYTE *buf = NULL; CK_BYTE *buf2 = NULL; CK_BYTE *buf3 = NULL; BerValue *val = NULL; 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 = 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); free(buf); 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); free(buf); 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); free(buf); return rc; } free(buf); /* 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); free(buf2); 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__); free(buf2); 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) <= 0 ? 1 : 0); rc |= ber_flatten(ber, &val); if (rc != 0) { TRACE_DEVEL("%s ber_alloc_t/ber_flatten failed \n", __func__); rc = CKR_FUNCTION_FAILED; ber_free(ber, 1); ber_bvfree(val); free(buf2); goto out; } memcpy(buf3 + total_len, val->bv_val, val->bv_len); total_len += val->bv_len; ber_free(ber, 1); ber_bvfree(val); free(buf2); 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); out: free(buf3); 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; rc = ber_decode_SPKI(data, data_len, &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, ber_AlgIdRSAEncryptionLen, &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, val_len, &seq, &seq_len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_SEQUENCE failed\n"); return rc; } rc = ber_decode_INTEGER(seq, seq_len, &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, seq_len - 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; len = 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, dsakey_len, offset; CK_RV rc; rc = ber_decode_PrivateKeyInfo(data, data_len, &alg, &len, &dsakey, &dsakey_len); 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, len- 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, buf_len - 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, buf_len - 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, buf_len - 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, buf_len - 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, buf_len - 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, buf_len - 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, dsakey_len, &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 = 0, parm_len, id_len, pub_len, offset, total; CK_RV rc = 0; CK_BYTE *buf = NULL; CK_BYTE *buf2 = NULL; BerValue *val = NULL; 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) <= 0 ? 1 : 0); rc |= ber_flatten(ber, &val); if (rc != 0) { TRACE_DEVEL("%s ber_alloc_t/ber_flatten failed \n", __func__); ber_free(ber, 1); ber_bvfree(val); free(buf); return CKR_FUNCTION_FAILED; } pub_len = val->bv_len; ber_free(ber, 1); free(buf); ber_bvfree(val); 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); free(buf); 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); free(buf); 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); free(buf); 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); free(buf); 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); free(buf); 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); free(buf2); return rc; } ber = ber_alloc_t(LBER_USE_DER); rc = (ber_put_bitstring(ber, (char *)buf, len * 8, 0x03) <= 0 ? 1 : 0); rc |= ber_flatten(ber, &val); free(buf); if (rc != 0) { TRACE_DEVEL("%s ber_put_bitstring/ber_flatten failed\n", __func__); ber_free(ber, 1); ber_bvfree(val); free(buf2); return CKR_FUNCTION_FAILED; } buf = (CK_BYTE *) malloc(id_len + val->bv_len); if (!buf) { TRACE_ERROR("%s Memory allocation failed\n", __func__); ber_free(ber, 1); ber_bvfree(val); free(buf2); 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); ber_bvfree(val); /* 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); free(buf); 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_BYTE *v; CK_ULONG v_len; CK_ULONG field_len, offset; CK_RV rc; rc = ber_decode_SPKI(data, data_len, &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, param_len, &seq, &seq_len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_SEQUENCE failed\n"); return rc; } rc = ber_decode_INTEGER(seq, seq_len, &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, seq_len - 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, seq_len - offset, &b, &b_len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); return rc; } rc = ber_decode_INTEGER(val, val_len, &v, &v_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, v, v_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 *privkey, CK_ATTRIBUTE *pubkey, CK_KEY_TYPE key_type) { CK_BYTE *buf = NULL; CK_BYTE *buf2 = NULL; CK_BYTE *buf3 = 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; 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 rc |= ber_encode_OCTET_STRING(TRUE, NULL, &len, NULL, privkey->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) { switch (key_type) { case CKK_EC: rc = ber_decode_OCTET_STRING(pubkey->pValue, pubkey->ulValueLen, &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; } break; case CKK_EC_EDWARDS: case CKK_EC_MONTGOMERY: /* Edwards/Montgomery keys have raw CKA_EC_POINT */ ecpoint = pubkey->pValue; ecpoint_len = pubkey->ulValueLen; break; default: TRACE_DEVEL("Key type 0x%lx not supported.\n", key_type); return CKR_KEY_TYPE_INCONSISTENT; } rc = ber_encode_BIT_STRING(FALSE, &buf3, &len, ecpoint, ecpoint_len, 0); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_BIT_STRING failed\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } rc = ber_encode_CHOICE(TRUE, 1, &buf2, &len, buf3, len, TRUE); free(buf3); buf3 = NULL; if (rc != 0) { TRACE_DEVEL("ber_encode_CHOICE failed\n"); return CKR_FUNCTION_FAILED; } offset += len; } 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; } switch (key_type) { case CKK_EC: break; case CKK_EC_EDWARDS: case CKK_EC_MONTGOMERY: /* ALgID itself is curve OID */ der_AlgIdECLen = 2 + params->ulValueLen; break; default: TRACE_DEVEL("Key type 0x%lx not supported.\n", key_type); return CKR_KEY_TYPE_INCONSISTENT; } 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 = 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_OCTET_STRING(FALSE, &buf2, &len, (CK_BYTE *)privkey + sizeof(CK_ATTRIBUTE), privkey->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) { switch (key_type) { case CKK_EC: rc = ber_decode_OCTET_STRING(pubkey->pValue, pubkey->ulValueLen, &ecpoint, &ecpoint_len, &field_len); if (rc != CKR_OK || pubkey->ulValueLen != field_len) { TRACE_DEVEL("ber decoding of public key failed\n"); rc = CKR_ATTRIBUTE_VALUE_INVALID; goto error; } break; case CKK_EC_EDWARDS: case CKK_EC_MONTGOMERY: /* Edwards/Montgomery keys have raw CKA_EC_POINT */ ecpoint = pubkey->pValue; ecpoint_len = pubkey->ulValueLen; break; default: TRACE_DEVEL("Key type 0x%lx not supported.\n", key_type); rc = CKR_KEY_TYPE_INCONSISTENT; goto error; } rc = ber_encode_BIT_STRING(FALSE, &buf3, &len, ecpoint, ecpoint_len, 0); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_BIT_STRING failed\n"); rc = CKR_ATTRIBUTE_VALUE_INVALID; goto error; } rc = ber_encode_CHOICE(FALSE, 1, &buf2, &len, buf3, len, TRUE); free(buf3); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_CHOICE failed\n"); goto error; } 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; } switch (key_type) { case CKK_EC: /* AlgID param is curve OID. */ /* 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; break; case CKK_EC_EDWARDS: case CKK_EC_MONTGOMERY: /* ALgID itself is curve OID */ memcpy(der_AlgIdEC, der_AlgIdECBase, 2); /* Only SEQUENCE */ memcpy(der_AlgIdEC + 2, params->pValue, params->ulValueLen); der_AlgIdECLen = 2 + params->ulValueLen; /* adjust length field */ der_AlgIdEC[1] = params->ulValueLen; break; default: TRACE_DEVEL("Key type 0x%lx not supported.\n", key_type); rc= CKR_KEY_TYPE_INCONSISTENT; goto error; } 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_KEY_TYPE key_type) { CK_ATTRIBUTE *pub_attr = NULL; CK_ATTRIBUTE *priv_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, eckey_len; CK_ULONG pubkey_available = 0; CK_BYTE *ecpoint = NULL; CK_ULONG ecpoint_len; CK_BBOOL ecpoint_allocated = FALSE; CK_RV rc; /* * For unwrapping, the data passed to this function may be larger than the * actual sequence, due to padding. So look at the data only up to the * length in the first SEQUENCE. * Since an EC private key may include an optional public key, we need to * know the actual length to be able to find out of the optional public key * is present or not. */ rc = ber_decode_SEQUENCE(data, data_len, &buf, &buf_len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_SEQUENCE failed\n"); return rc; } if (field_len > data_len) { TRACE_DEVEL("passed data is too short\n"); return CKR_FUNCTION_FAILED; } data_len = field_len; /* Decode PrivateKeyInfo into alg and eckey */ rc = ber_decode_PrivateKeyInfo(data, data_len, &alg, &alg_len, &eckey, &eckey_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_PrivateKeyInfo failed\n"); return rc; } switch (key_type) { case CKK_EC: /* 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; } break; case CKK_EC_EDWARDS: case CKK_EC_MONTGOMERY: /* ALgID itself is curve OID */ break; default: TRACE_DEVEL("Key type 0x%lx not supported.\n", key_type); return CKR_KEY_TYPE_INCONSISTENT; } /* Decode the ecdhkey into buf */ rc = ber_decode_SEQUENCE(eckey, eckey_len, &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, buf_len - 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, buf_len - 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, buf_len - offset, TRUE, &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, buf_len - offset, &pub_buf, &pub_len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_BIT_STRING failed\n"); goto cleanup; } pub_buf++; /* Remove unused-bits byte */ pub_len--; 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_EC_PARAMS */ switch (key_type) { case CKK_EC: /* AlgID param is curve OID */ parm_buf = alg + ber_idECLen; parm_len = alg_len - ber_idECLen; break; case CKK_EC_EDWARDS: case CKK_EC_MONTGOMERY: /* ALgID itself is curve OID */ parm_buf = alg; parm_len = alg_len; break; default: TRACE_DEVEL("Key type 0x%lx not supported.\n", key_type); return CKR_KEY_TYPE_INCONSISTENT; } rc = build_attribute(CKA_EC_PARAMS, parm_buf, parm_len, &parm_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute for CKA_EC_PARAMS failed\n"); goto cleanup; } /* Build attr for public key as BER encoded OCTET STRING */ if (pubkey_available) { switch (key_type) { case CKK_EC: 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; } ecpoint_allocated = TRUE; break; case CKK_EC_EDWARDS: case CKK_EC_MONTGOMERY: /* Edwards/Montgomery keys have raw CKA_EC_POINT */ ecpoint = pub_buf; ecpoint_len = pub_len; break; default: TRACE_DEVEL("Key type 0x%lx not supported.\n", key_type); return CKR_KEY_TYPE_INCONSISTENT; } 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 */ 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; *params = parm_attr; if (ecpoint_allocated && ecpoint) free(ecpoint); return CKR_OK; cleanup: if (pub_attr) free(pub_attr); if (priv_attr) free(priv_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_KEY_TYPE key_type) { CK_ULONG len, len2, total, ofs; CK_ULONG algid_len; CK_RV rc = 0; CK_BYTE *buf = NULL, *buf2 = NULL; CK_BYTE *ecpoint; CK_ULONG ecpoint_len, field_len; switch (key_type) { case CKK_EC: /* CKA_EC_POINT is a BER encoded OCTET STRING. Extract it. */ rc = ber_decode_OCTET_STRING((CK_BYTE *)point->pValue, point->ulValueLen, &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; } /* AlgID param is curve OID. */ algid_len = der_AlgIdECBaseLen + params->ulValueLen; break; case CKK_EC_EDWARDS: case CKK_EC_MONTGOMERY: /* Edwards/Montgomery keys have raw CKA_EC_POINT */ ecpoint = point->pValue; ecpoint_len = point->ulValueLen; /* ALgID itself is curve OID */ rc = ber_encode_SEQUENCE(TRUE, NULL, &algid_len, NULL, params->ulValueLen); if (rc != CKR_OK) { TRACE_DEVEL("%s der_encode_sequence failed with rc=0x%lx\n", __func__, rc); return rc; } break; default: TRACE_DEVEL("Key type 0x%lx not supported.\n", key_type); return CKR_KEY_TYPE_INCONSISTENT; } /* 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 */ rc = ber_encode_BIT_STRING(TRUE, NULL, &len2, NULL, ecpoint_len, 0); if (rc != CKR_OK) { TRACE_DEVEL("%s ber_encode_BIT_STRING failed with rc=0x%lx\n", __func__, rc); return rc; } rc = ber_encode_SEQUENCE(TRUE, NULL, &total, NULL, len + len2); 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; } /* Now compute with real data */ buf = (CK_BYTE *) malloc(total); if (!buf) { TRACE_ERROR("%s Memory allocation failed\n", __func__); return CKR_HOST_MEMORY; } switch (key_type) { case CKK_EC: /* AlgID param is curve OID. */ memcpy(buf, der_AlgIdECBase, der_AlgIdECBaseLen); memcpy(buf + der_AlgIdECBaseLen, params->pValue, params->ulValueLen); buf[1] += params->ulValueLen; ofs = der_AlgIdECBaseLen + params->ulValueLen; break; case CKK_EC_EDWARDS: case CKK_EC_MONTGOMERY: /* ALgID itself is curve OID */ rc = ber_encode_SEQUENCE(FALSE, &buf2, &len, params->pValue, params->ulValueLen); if (rc != CKR_OK) { TRACE_DEVEL("%s der_encode_sequence failed with rc=0x%lx\n", __func__, rc); free(buf); return rc; } memcpy(buf, buf2, len); free(buf2); buf2 = NULL; ofs = len; break; default: TRACE_DEVEL("Key type 0x%lx not supported.\n", key_type); free(buf); return CKR_KEY_TYPE_INCONSISTENT; } /* generate bitstring */ rc = ber_encode_BIT_STRING(FALSE, &buf2, &len2, ecpoint, ecpoint_len, 0); if (rc != CKR_OK) { TRACE_DEVEL("%s ber_encode_BIT_STRING failed with rc=0x%lx\n", __func__, rc); free(buf); return rc; } memcpy(buf + ofs, buf2, len2); free(buf2); rc = ber_encode_SEQUENCE(FALSE, data, data_len, buf, algid_len + len2); if (rc != CKR_OK) { TRACE_DEVEL("%s der_encode_Seq failed with rc=0x%lx\n", __func__, rc); free(buf); 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_KEY_TYPE key_type) { 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_BBOOL ecpoint_allocated = FALSE; CK_RV rc; rc = ber_decode_SPKI(data, data_len, &algid, &algid_len, ¶m, ¶m_len, &point, &point_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_SPKI failed\n"); return rc; } switch (key_type) { case CKK_EC: /* AlgID param is curve OID. * 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, der_AlgIdECBaseLen, &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; } break; case CKK_EC_EDWARDS: case CKK_EC_MONTGOMERY: /* ALgID itself is curve OID */ param = algid; param_len = algid_len; break; default: TRACE_DEVEL("Key type 0x%lx not supported.\n", key_type); return CKR_KEY_TYPE_INCONSISTENT; } // 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; } switch (key_type) { case CKK_EC: /* 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; } ecpoint_allocated = TRUE; break; case CKK_EC_EDWARDS: case CKK_EC_MONTGOMERY: /* Edwards/Montgomery keys have raw CKA_EC_POINT */ ecpoint = point; ecpoint_len = point_len; break; default: TRACE_DEVEL("Key type 0x%lx not supported.\n", key_type); return CKR_KEY_TYPE_INCONSISTENT; } rc = build_attribute(CKA_EC_POINT, ecpoint, ecpoint_len, &point_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto cleanup; } if (ecpoint_allocated && ecpoint) 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_allocated && 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; len = 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, dhkey_len, offset; CK_RV rc; rc = ber_decode_PrivateKeyInfo(data, data_len, &alg, &len, &dhkey, &dhkey_len); 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_idDHLen, len - ber_idDHLen, &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, buf_len - 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, buf_len - 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, buf_len - 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, buf_len - 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, dhkey_len, &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 = 0, parm_len, id_len, pub_len, offset, total; CK_RV rc = 0; CK_BYTE *buf = NULL; CK_BYTE *buf2 = NULL; BerValue *val = NULL; 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) <= 0 ? 1 : 0); rc |= ber_flatten(ber, &val); if (rc != CKR_OK) { TRACE_DEVEL("%s ber_put_bitstring/ber_flatten failed\n", __func__); ber_free(ber, 1); ber_bvfree(val); free(buf); return CKR_FUNCTION_FAILED; } pub_len = val->bv_len; ber_free(ber, 1); ber_bvfree(val); 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); free(buf); 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); free(buf); 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); free(buf); 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); free(buf); 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); free(buf2); return rc; } ber = ber_alloc_t(LBER_USE_DER); rc = (ber_put_bitstring(ber, (char *)buf, len * 8, 0x03) <= 0 ? 1 : 0); rc |= ber_flatten(ber, &val); free(buf); if (rc != CKR_OK) { TRACE_DEVEL("%s ber_put_bitstring/ber_flatten failed\n", __func__); ber_free(ber, 1); ber_bvfree(val); free(buf2); return CKR_FUNCTION_FAILED; } buf = (CK_BYTE *) malloc(id_len + val->bv_len); if (!buf) { TRACE_ERROR("%s Memory allocation failed\n", __func__); ber_free(ber, 1); ber_bvfree(val); free(buf2); 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); ber_bvfree(val); /* outer sequence */ rc = ber_encode_SEQUENCE(FALSE, data, data_len, buf, id_len + pub_len); free(buf); if (rc != CKR_OK) { TRACE_DEVEL("%s der_encode_Seq failed with rc=0x%lx\n", __func__, rc); return rc; } 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_BYTE *v; CK_ULONG v_len; CK_ULONG field_len, offset; CK_RV rc; rc = ber_decode_SPKI(data, data_len, &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, param_len, &seq, &seq_len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_SEQUENCE failed\n"); return rc; } rc = ber_decode_INTEGER(seq, seq_len, &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, seq_len - offset, &b, &b_len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); return rc; } rc = ber_decode_INTEGER(val, val_len, &v, &v_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, v, v_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.xxx * NULL * BIT STRING (1 elem) * SEQUENCE (2 elem) * BIT STRING (256 bit) = 32 bytes * BIT STRING (13824 bit) = 1728 bytes */ static CK_RV ber_encode_IBM_DilithiumPublicKey(CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, const CK_BYTE *oid, CK_ULONG oid_len, CK_ATTRIBUTE *rho, CK_ATTRIBUTE *t1) { CK_BYTE *buf = NULL, *buf2 = NULL, *buf3 = NULL, *buf4 = NULL; CK_BYTE *buf5 = NULL, *algid = NULL; CK_ULONG len = 0, len4, offset, total, total_len, algid_len; CK_RV rc; UNUSED(length_only); offset = 0; rc = 0; total_len = 0; total = 0; /* Calculate storage for AlgID sequence */ rc |= ber_encode_SEQUENCE(TRUE, NULL, &total_len, NULL, oid_len + ber_NULLLen); /* 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); buf2 = NULL; 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); buf2 = NULL; 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.xxx * NULL <- no parms for this oid */ buf5 = (CK_BYTE *) malloc(oid_len + ber_NULLLen); if (!buf5) { TRACE_ERROR("%s Memory allocation failed\n", __func__); rc = CKR_HOST_MEMORY; goto error; } memcpy(buf5, oid, oid_len); memcpy(buf5 + oid_len, ber_NULL, ber_NULLLen); rc = ber_encode_SEQUENCE(FALSE, &algid, &algid_len, buf5, oid_len + ber_NULLLen); free(buf5); if (rc != CKR_OK) { TRACE_ERROR("%s ber_encode_SEQUENCE failed with rc=0x%lx\n", __func__, rc); goto error; } total_len = algid_len; memcpy(buf3, algid, algid_len); free(algid); algid = NULL; /* * 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; } static CK_RV ber_decode_IBM_DilithiumPublicKey(CK_BYTE *data, CK_ULONG data_len, CK_ATTRIBUTE **rho_attr, CK_ATTRIBUTE **t1_attr, CK_ATTRIBUTE **value_attr, const struct pqc_oid **oid) { CK_ATTRIBUTE *rho_attr_temp = NULL; CK_ATTRIBUTE *t1_attr_temp = NULL; CK_ATTRIBUTE *value_attr_temp = NULL; CK_BYTE *algoid = NULL; CK_ULONG algoid_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, raw_spki_len; CK_RV rc; rc = ber_decode_SPKI(data, data_len, &algoid, &algoid_len, ¶m, ¶m_len, &val, &val_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_SPKI failed\n"); return rc; } *oid = find_pqc_by_oid(dilithium_oids, algoid, algoid_len); if (*oid == NULL) { 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, val_len, &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, seq_len, &rho, &rho_len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); return rc; } rho++; /* Remove unused-bits byte */ rho_len--; /* Decode t1 */ offset = field_len; rc = ber_decode_BIT_STRING(seq + offset, seq_len - offset, &t1, &t1_len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); return rc; } t1++; /* Remove unused-bits byte */ t1_len--; /* 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; } /* Add raw SPKI as CKA_VALUE to public key (z/OS ICSF compatibility) */ rc = ber_decode_SEQUENCE(data, data_len, &val, &val_len, &raw_spki_len); if (rc != CKR_OK) { TRACE_ERROR("%s ber_decode_SEQUENCE failed with rc=0x%lx\n", __func__, rc); goto cleanup; } rc = build_attribute(CKA_VALUE, data, raw_spki_len, &value_attr_temp); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto cleanup; } *rho_attr = rho_attr_temp; *t1_attr = t1_attr_temp; *value_attr = value_attr_temp; return CKR_OK; cleanup: if (rho_attr_temp) free(rho_attr_temp); if (t1_attr_temp) free(t1_attr_temp); if (value_attr_temp) free(value_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 * } * } */ static CK_RV ber_encode_IBM_DilithiumPrivateKey(CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, const CK_BYTE *oid, CK_ULONG oid_len, CK_ATTRIBUTE *rho, CK_ATTRIBUTE *seed, CK_ATTRIBUTE *tr, CK_ATTRIBUTE *s1, CK_ATTRIBUTE *s2, CK_ATTRIBUTE *t0, CK_ATTRIBUTE *t1) { CK_BYTE *buf = NULL, *buf2 = NULL, *buf3 = NULL; CK_BYTE *algid = NULL, *algid_buf = NULL; CK_ULONG len, len2 = 0, offset, algid_len = 0; CK_BYTE version[] = { 0 }; CK_RV rc; /* Calculate storage for sequence */ offset = 0; rc = 0; rc |= ber_encode_SEQUENCE(TRUE, NULL, &algid_len, NULL, oid_len + ber_NULLLen); rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, sizeof(version)); offset += len; 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, TRUE); 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, algid_len, 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; /* 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; /* 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, TRUE); 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; } algid_buf = (CK_BYTE *) malloc(oid_len + ber_NULLLen); if (!algid_buf) { TRACE_ERROR("%s Memory allocation failed\n", __func__); rc = CKR_HOST_MEMORY; goto error; } memcpy(algid_buf, oid, oid_len); memcpy(algid_buf + oid_len, ber_NULL, ber_NULLLen); rc = ber_encode_SEQUENCE(FALSE, &algid, &algid_len, algid_buf, oid_len + ber_NULLLen); free(algid_buf); if (rc != CKR_OK) { TRACE_ERROR("%s ber_encode_SEQUENCE failed with rc=0x%lx\n", __func__, rc); goto error; } rc = ber_encode_PrivateKeyInfo(FALSE, data, data_len, algid, algid_len, 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); if (algid) free(algid); 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 * } * } */ static 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 **value, const struct pqc_oid **oid) { 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, *value_attr = NULL; CK_BYTE *algoid = NULL; CK_BYTE *dilithium_priv_key = NULL; CK_BYTE *buf = NULL; CK_BYTE *tmp = NULL; CK_ULONG offset, buf_len, field_len, len, dilithium_priv_key_len, option; CK_RV rc; /* Check if this is a Dilithium private key */ rc = ber_decode_PrivateKeyInfo(data, data_len, &algoid, &len, &dilithium_priv_key, &dilithium_priv_key_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_PrivateKeyInfo failed\n"); return rc; } if (len <= ber_NULLLen || memcmp(algoid + len - ber_NULLLen, ber_NULL, ber_NULLLen) != 0) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } len -= ber_NULLLen; *oid = find_pqc_by_oid(dilithium_oids, algoid, len); if (*oid == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } /* Decode private Dilithium key */ rc = ber_decode_SEQUENCE(dilithium_priv_key, dilithium_priv_key_len, &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, buf_len - offset, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); goto cleanup; } offset += field_len; /* rho */ rc = ber_decode_BIT_STRING(buf + offset, buf_len - offset, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_BIT_STRING of (rho) failed\n"); goto cleanup; } else { tmp++; /* Remove unused-bits byte */ len--; 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, buf_len - offset, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_BIT_STRING of (seed) failed\n"); goto cleanup; } else { tmp++; /* Remove unused-bits byte */ len--; 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, buf_len - offset, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_BIT_STRING of (tr) failed\n"); goto cleanup; } else { tmp++; /* Remove unused-bits byte */ len--; 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, buf_len - offset, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_BIT_STRING of (s1) failed\n"); goto cleanup; } else { tmp++; /* Remove unused-bits byte */ len--; 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, buf_len - offset, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_BIT_STRING of (s2) failed\n"); goto cleanup; } else { tmp++; /* Remove unused-bits byte */ len--; 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, buf_len - offset, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_BIT_STRING of (t0) failed\n"); goto cleanup; } else { tmp++; /* Remove unused-bits byte */ len--; 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 (optional, within choice) */ if (offset < buf_len) { rc = ber_decode_CHOICE(buf + offset, buf_len - offset, TRUE, &tmp, &len, &field_len, &option); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_BIT_STRING of (t1) failed\n"); goto cleanup; } if (option != 0x00) { TRACE_DEVEL("ber_decode_CHOICE returned invalid option %ld\n", option); goto cleanup; } offset += field_len - len; rc = ber_decode_BIT_STRING(buf + offset, buf_len - offset, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_BIT_STRING of (t1) failed\n"); goto cleanup; } tmp++; /* Remove unused-bits byte */ len--; 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; } /* Add private key as CKA_VALUE to public key (z/OS ICSF compatibility) */ rc = ber_decode_SEQUENCE(data, data_len, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_ERROR("%s ber_decode_SEQUENCE failed with rc=0x%lx\n", __func__, rc); goto cleanup; } rc = build_attribute(CKA_VALUE, data, field_len, &value_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute for (value) failed\n"); goto cleanup; } *rho = rho_attr; *seed = seed_attr; *tr = tr_attr; *s1 = s1_attr; *s2 = s2_attr; *t0 = t0_attr; *t1 = t1_attr; *value = value_attr; return CKR_OK; cleanup: if (seed_attr) free(seed_attr); if (t1_attr) free(t1_attr); if (rho_attr) free(rho_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 (value_attr) free(value_attr); return rc; } /** * An IBM Kyber public key is given by: * * SEQUENCE (2 elem) * SEQUENCE (2 elem) * OBJECT IDENTIFIER 1.3.6.1.4.1.2.267.5.xxx * NULL * BIT STRING (1 elem) * SEQUENCE (1 elem) * pk BIT STRING -- public key */ static CK_RV ber_encode_IBM_KyberPublicKey(CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, const CK_BYTE *oid, CK_ULONG oid_len, CK_ATTRIBUTE *pk) { CK_BYTE *buf = NULL, *buf2 = NULL, *buf3 = NULL, *buf4 = NULL; CK_BYTE *buf5 = NULL, *algid = NULL; CK_ULONG len, len4, offset, total, total_len, algid_len; CK_RV rc; UNUSED(length_only); offset = 0; rc = 0; total_len = 0; total = 0; /* Calculate storage for AlgID sequence */ rc |= ber_encode_SEQUENCE(TRUE, NULL, &total_len, NULL, oid_len + ber_NULLLen); /* Calculate storage for inner sequence */ rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, pk->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 (1 elem) * BIT STRING -> pk */ offset = 0; rc = ber_encode_BIT_STRING(FALSE, &buf2, &len, pk->pValue, pk->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); buf2 = NULL; 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.5.xxx * NULL <- no parms for this oid */ buf5 = (CK_BYTE *) malloc(oid_len + ber_NULLLen); if (!buf5) { TRACE_ERROR("%s Memory allocation failed\n", __func__); rc = CKR_HOST_MEMORY; goto error; } memcpy(buf5, oid, oid_len); memcpy(buf5 + oid_len, ber_NULL, ber_NULLLen); rc = ber_encode_SEQUENCE(FALSE, &algid, &algid_len, buf5, oid_len + ber_NULLLen); free(buf5); if (rc != CKR_OK) { TRACE_ERROR("%s ber_encode_SEQUENCE failed with rc=0x%lx\n", __func__, rc); goto error; } total_len = algid_len; memcpy(buf3, algid, algid_len); free(algid); algid = NULL; /* * BIT STRING (1 elem) * SEQUENCE (1 elem) * BIT STRING -> pk */ 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.5.xxx * NULL -> no parms for this oid * BIT STRING (1 elem) * SEQUENCE (2 elem) * BIT STRING -> pk */ 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; } static CK_RV ber_decode_IBM_KyberPublicKey(CK_BYTE *data, CK_ULONG data_len, CK_ATTRIBUTE **pk_attr, CK_ATTRIBUTE **value_attr, const struct pqc_oid **oid) { CK_ATTRIBUTE *pk_attr_temp = NULL; CK_ATTRIBUTE *value_attr_temp = NULL; CK_BYTE *algoid = NULL; CK_ULONG algoid_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 *pk; CK_ULONG pk_len; CK_ULONG field_len, raw_spki_len; CK_RV rc; rc = ber_decode_SPKI(data, data_len, &algoid, &algoid_len, ¶m, ¶m_len, &val, &val_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_SPKI failed\n"); return rc; } *oid = find_pqc_by_oid(kyber_oids, algoid, algoid_len); if (*oid == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } /* Decode sequence: * SEQUENCE (1 elem) * BIT STRING = pk */ rc = ber_decode_SEQUENCE(val, val_len, &seq, &seq_len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_SEQUENCE failed\n"); return rc; } /* Decode pk */ rc = ber_decode_BIT_STRING(seq, seq_len, &pk, &pk_len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); return rc; } pk++; /* Remove unused-bits byte */ pk_len--; /* Build pk attribute */ rc = build_attribute(CKA_IBM_KYBER_PK, pk, pk_len, &pk_attr_temp); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto cleanup; } /* Add raw SPKI as CKA_VALUE to public key (z/OS ICSF compatibility) */ rc = ber_decode_SEQUENCE(data, data_len, &val, &val_len, &raw_spki_len); if (rc != CKR_OK) { TRACE_ERROR("%s ber_decode_SEQUENCE failed with rc=0x%lx\n", __func__, rc); goto cleanup; } rc = build_attribute(CKA_VALUE, data, raw_spki_len, &value_attr_temp); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto cleanup; } *pk_attr = pk_attr_temp; *value_attr = value_attr_temp; return CKR_OK; cleanup: if (pk_attr_temp) free(pk_attr_temp); if (value_attr_temp) free(value_attr_temp); return rc; } /** * An IBM Kyber private key is given by: * * KyberPrivateKey ::= SEQUENCE { * version INTEGER, -- v0, reserved 0 * sk BIT STRING, -- private key * pk [0] IMPLICIT OPTIONAL { * pk||fs BIT STRING -- public key (pk) concatenated with 2x32 bytes fs * } * } */ static CK_RV ber_encode_IBM_KyberPrivateKey(CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, const CK_BYTE *oid, CK_ULONG oid_len, CK_ATTRIBUTE *sk, CK_ATTRIBUTE *pk) { CK_BYTE *buf = NULL, *buf2 = NULL, *buf3 = NULL; CK_BYTE *algid = NULL, *algid_buf = NULL, *pk_fs = NULL; CK_ULONG len, len2 = 0, offset, algid_len = 0; CK_BYTE version[] = { 0 }; const struct pqc_oid *pqc_oid; CK_RV rc; pqc_oid = find_pqc_by_oid(kyber_oids, oid, oid_len); if (pqc_oid == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } /* Calculate storage for sequence */ offset = 0; rc = 0; rc |= ber_encode_SEQUENCE(TRUE, NULL, &algid_len, NULL, oid_len + ber_NULLLen); rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, sizeof(version)); offset += len; rc |= ber_encode_BIT_STRING(TRUE, NULL, &len, NULL, sk->ulValueLen, 0); offset += len; if (pk) { rc |= ber_encode_BIT_STRING(TRUE, NULL, &len2, NULL, pk->ulValueLen + 64, 0); rc |= ber_encode_CHOICE(TRUE, 0, NULL, &len, NULL, len2, TRUE); 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, algid_len, 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; /* 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; /* sk */ rc = ber_encode_BIT_STRING(FALSE, &buf2, &len, sk->pValue, sk->ulValueLen, 0); if (rc != CKR_OK) { TRACE_ERROR("ber_encode_BIT_STRING of sk failed\n"); goto error; } memcpy(buf + offset, buf2, len); offset += len; free(buf2); buf2 = NULL; /* (pk) Optional bit-string of public key */ if (pk && pk->pValue) { /* append fs to public key */ pk_fs = (CK_BYTE *)malloc(pk->ulValueLen + pqc_oid->len_info.ml_kem.fs_len); if (!pk_fs) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto error; } memcpy(pk_fs, pk->pValue, pk->ulValueLen); memset(pk_fs + pk->ulValueLen, 0x30, pqc_oid->len_info.ml_kem.fs_len); rc = ber_encode_BIT_STRING(FALSE, &buf3, &len2, pk_fs, pk->ulValueLen + pqc_oid->len_info.ml_kem.fs_len, 0); rc |= ber_encode_CHOICE(FALSE, 0, &buf2, &len, buf3, len2, TRUE); if (rc != CKR_OK) { TRACE_ERROR("encoding of pk 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; } algid_buf = (CK_BYTE *) malloc(oid_len + ber_NULLLen); if (!algid_buf) { TRACE_ERROR("%s Memory allocation failed\n", __func__); rc = CKR_HOST_MEMORY; goto error; } memcpy(algid_buf, oid, oid_len); memcpy(algid_buf + oid_len, ber_NULL, ber_NULLLen); rc = ber_encode_SEQUENCE(FALSE, &algid, &algid_len, algid_buf, oid_len + ber_NULLLen); free(algid_buf); if (rc != CKR_OK) { TRACE_ERROR("%s ber_encode_SEQUENCE failed with rc=0x%lx\n", __func__, rc); goto error; } rc = ber_encode_PrivateKeyInfo(FALSE, data, data_len, algid, algid_len, 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); if (algid) free(algid); if (pk_fs) free(pk_fs); return rc; } /** * decode an IBM Kyber private key: * * KyberPrivateKey ::= SEQUENCE { * version INTEGER, -- v0, reserved 0 * sk BIT STRING, -- private key * pk [0] IMPLICIT OPTIONAL { * pk||fs BIT STRING -- public key (pk) concatenated with 2x32 bytes fs * } * } */ static CK_RV ber_decode_IBM_KyberPrivateKey(CK_BYTE *data, CK_ULONG data_len, CK_ATTRIBUTE **sk, CK_ATTRIBUTE **pk, CK_ATTRIBUTE **value, const struct pqc_oid **oid) { CK_ATTRIBUTE *sk_attr = NULL, *pk_attr = NULL, *value_attr = NULL; CK_BYTE *algoid = NULL; CK_BYTE *kyber_priv_key = NULL; CK_BYTE *buf = NULL; CK_BYTE *tmp = NULL; CK_ULONG offset, buf_len, field_len, len, kyber_priv_key_len, option; CK_RV rc; /* Check if this is a Kyber private key */ rc = ber_decode_PrivateKeyInfo(data, data_len, &algoid, &len, &kyber_priv_key, &kyber_priv_key_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_PrivateKeyInfo failed\n"); return rc; } if (len <= ber_NULLLen || memcmp(algoid + len - ber_NULLLen, ber_NULL, ber_NULLLen) != 0) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } len -= ber_NULLLen; *oid = find_pqc_by_oid(kyber_oids, algoid, len); if (*oid == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } /* Decode private Kyber key */ rc = ber_decode_SEQUENCE(kyber_priv_key, kyber_priv_key_len, &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, buf_len - offset, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); goto cleanup; } offset += field_len; /* sk */ rc = ber_decode_BIT_STRING(buf + offset, buf_len - offset, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_BIT_STRING of (sk) failed\n"); goto cleanup; } else { tmp++; /* Remove unused-bits byte */ len--; rc = build_attribute(CKA_IBM_KYBER_SK, tmp, len, &sk_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute for (sk) failed\n"); goto cleanup; } offset += field_len; } /* pk (optional, within choice) */ if (offset < buf_len) { rc = ber_decode_CHOICE(buf + offset, buf_len - offset, TRUE, &tmp, &len, &field_len, &option); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_BIT_STRING of (t1) failed\n"); goto cleanup; } if (option != 0x00) { TRACE_DEVEL("ber_decode_CHOICE returned invalid option %ld\n", option); goto cleanup; } offset += field_len - len; rc = ber_decode_BIT_STRING(buf + offset, buf_len - offset, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_BIT_STRING of (pk) failed\n"); goto cleanup; } tmp++; /* Remove unused-bits byte */ len--; if (len > (*oid)->len_info.ml_kem.fs_len) len -= (*oid)->len_info.ml_kem.fs_len; /* Remove 'fs' */ rc = build_attribute(CKA_IBM_KYBER_PK, tmp, len, &pk_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute for (pk) 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; } /* Add private key as CKA_VALUE to public key (z/OS ICSF compatibility) */ rc = ber_decode_SEQUENCE(data, data_len, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_ERROR("%s ber_decode_SEQUENCE failed with rc=0x%lx\n", __func__, rc); goto cleanup; } rc = build_attribute(CKA_VALUE, data, field_len, &value_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute for (value) failed\n"); goto cleanup; } *sk = sk_attr; *pk = pk_attr; *value = value_attr; return CKR_OK; cleanup: if (sk_attr) free(sk_attr); if (pk_attr) free(pk_attr); if (value_attr) free(value_attr); return rc; } /** * An IBM ML-DSA public key is given by: * * SEQUENCE (2 elem) * SEQUENCE (2 elem) * OBJECT IDENTIFIER 2.16.840.1.101.3.4.3.xxx * BIT STRING - public key (rho | t1) */ CK_RV ber_encode_IBM_ML_DSA_PublicKey(CK_MECHANISM_TYPE mech, CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, const CK_BYTE *oid, CK_ULONG oid_len, CK_ATTRIBUTE *rho, CK_ATTRIBUTE *t1) { CK_BYTE *buf = NULL, *pub = NULL, *alg = NULL; CK_ULONG alg_len = 0, pub_len = 0, total_len = 0; CK_RV rc; if (mech == CKM_IBM_DILITHIUM) return ber_encode_IBM_DilithiumPublicKey(length_only, data, data_len, oid, oid_len, rho, t1); /* Calculate storage for AlgID sequence */ rc = ber_encode_SEQUENCE(TRUE, NULL, &alg_len, NULL, oid_len); /* Calculate storage for public key bitsring */ rc |= ber_encode_BIT_STRING(TRUE, NULL, &pub_len, NULL, rho->ulValueLen + t1->ulValueLen, 0); /* Calculate storage for outer sequence */ rc |= ber_encode_SEQUENCE(TRUE, NULL, &total_len, NULL, alg_len + pub_len); if (rc != CKR_OK) { TRACE_ERROR("%s ber_encode failed with rc=0x%lx\n", __func__, rc); return rc; } if (length_only) { *data_len = total_len; return CKR_OK; } /* Allocate storage for public key */ buf = malloc(rho->ulValueLen + t1->ulValueLen); if (buf == NULL) { TRACE_ERROR("%s Memory allocation failed\n", __func__); return CKR_HOST_MEMORY; } memcpy(buf, rho->pValue, rho->ulValueLen); memcpy(buf + rho->ulValueLen, t1->pValue, t1->ulValueLen); rc = ber_encode_BIT_STRING(FALSE, &pub, &pub_len, buf, rho->ulValueLen + t1->ulValueLen, 0); if (rc != CKR_OK) { TRACE_ERROR("%s ber_encode_BIT_STRING failed with rc=0x%lx\n", __func__, rc); goto error; } free(buf); buf = NULL; rc = ber_encode_SEQUENCE(FALSE, &alg, &alg_len, (CK_BYTE *)oid, oid_len); if (rc != CKR_OK) { TRACE_ERROR("%s ber_encode_SEQUENCE failed with rc=0x%lx\n", __func__, rc); goto error; } /* Allocate storage for outer sequence */ buf = malloc(alg_len + pub_len); if (buf == NULL) { TRACE_ERROR("%s Memory allocation failed\n", __func__); rc = CKR_HOST_MEMORY; goto error; } memcpy(buf, alg, alg_len); memcpy(buf + alg_len, pub, pub_len); rc = ber_encode_SEQUENCE(FALSE, data, data_len, buf, alg_len + pub_len); if (rc != CKR_OK) { TRACE_ERROR("%s ber_encode_SEQUENCE failed with rc=0x%lx\n", __func__, rc); goto error; } error: if (buf != NULL) free(buf); if (pub != NULL) free(pub); if (alg != NULL) free(alg); return rc; } CK_RV ber_decode_IBM_ML_DSA_PublicKey(CK_MECHANISM_TYPE mech, CK_BYTE *data, CK_ULONG data_len, CK_ATTRIBUTE **rho_attr, CK_ATTRIBUTE **t1_attr, CK_ATTRIBUTE **value_attr, const struct pqc_oid **oid) { CK_ATTRIBUTE *rho_attr_temp = NULL; CK_ATTRIBUTE *t1_attr_temp = NULL; CK_ATTRIBUTE *value_attr_temp = NULL; CK_BYTE *algoid = NULL; CK_ULONG algoid_len; CK_BYTE *param = NULL; CK_ULONG param_len; CK_BYTE *pub = NULL; CK_ULONG pub_len = 0; CK_ULONG raw_spki_len; CK_RV rc; if (mech == CKM_IBM_DILITHIUM) return ber_decode_IBM_DilithiumPublicKey(data, data_len, rho_attr, t1_attr, value_attr, oid); /* * SEQUENCE (2 elem) * SEQUENCE (2 elem) * OBJECT IDENTIFIER 2.16.840.1.101.3.4.3.xxx * BIT STRING - public key (rho | t1) */ rc = ber_decode_SPKI(data, data_len, &algoid, &algoid_len, ¶m, ¶m_len, &pub, &pub_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_SPKI failed\n"); return rc; } *oid = find_pqc_by_oid(ml_dsa_oids, algoid, algoid_len); if (*oid == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } if (pub_len != (*oid)->len_info.ml_dsa.rho_len + (*oid)->len_info.ml_dsa.t1_len) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } /* Build rho attribute */ rc = build_attribute(CKA_IBM_ML_DSA_RHO, pub, (*oid)->len_info.ml_dsa.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_ML_DSA_T1, pub + (*oid)->len_info.ml_dsa.rho_len, (*oid)->len_info.ml_dsa.t1_len, &t1_attr_temp); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto cleanup; } /* Add raw SPKI as CKA_VALUE to public key (z/OS ICSF compatibility) */ rc = ber_decode_SEQUENCE(data, data_len, &pub, &pub_len, &raw_spki_len); if (rc != CKR_OK) { TRACE_ERROR("%s ber_decode_SEQUENCE failed with rc=0x%lx\n", __func__, rc); goto cleanup; } rc = build_attribute(CKA_VALUE, data, raw_spki_len, &value_attr_temp); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto cleanup; } *rho_attr = rho_attr_temp; *t1_attr = t1_attr_temp; *value_attr = value_attr_temp; return CKR_OK; cleanup: if (rho_attr_temp) free(rho_attr_temp); if (t1_attr_temp) free(t1_attr_temp); if (value_attr_temp) free(value_attr_temp); return rc; } /** * An IBM ML-DSA private key is given by: * * ML-DSA-PrivateKey ::= CHOICE { * private-seed [0] OCTET STRING (SIZE (32), * expandedKey OCTET STRING (rho | seed | tr | s1 | s2 | t0), * both SEQUENCE { * private-seed OCTET STRING (SIZE (32), * expandedKey OCTET STRING (rho | seed | tr | s1 | s2 | t0) * } * } * */ CK_RV ber_encode_IBM_ML_DSA_PrivateKey(CK_MECHANISM_TYPE mech, CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, const CK_BYTE *oid, CK_ULONG oid_len, CK_ATTRIBUTE *rho, CK_ATTRIBUTE *seed, CK_ATTRIBUTE *tr, CK_ATTRIBUTE *s1, CK_ATTRIBUTE *s2, CK_ATTRIBUTE *t0, CK_ATTRIBUTE *t1, CK_ATTRIBUTE *priv_seed) { CK_BBOOL priv_avail, priv_seed_avail; CK_ULONG priv_seed_len = 0, exp_key_len = 0, priv_key_len = 0; CK_ULONG alg_len = 0, ofs = 0; CK_BYTE *alg = NULL, *buf = NULL, *priv_key = NULL, *exp_key = NULL; CK_BYTE *pseed = NULL; CK_RV rc; if (mech == CKM_IBM_DILITHIUM) return ber_encode_IBM_DilithiumPrivateKey(length_only, data, data_len, oid, oid_len, rho, seed, tr, s1, s2, t0, t1); priv_avail = (rho != NULL && rho->ulValueLen != 0 && rho->pValue != NULL && seed != NULL && seed->ulValueLen != 0 && seed->pValue != NULL && tr != NULL && tr->ulValueLen != 0 && tr->pValue != NULL && s1 != NULL && s1->ulValueLen != 0 && s1->pValue != NULL && s2 != NULL && s2->ulValueLen != 0 && s2->pValue != NULL && t0 != NULL && t0->ulValueLen != 0 && t0->pValue != NULL); priv_seed_avail = (priv_seed != NULL && priv_seed->ulValueLen != 0 && priv_seed->pValue != NULL); /* Calculate length of key material */ rc = ber_encode_SEQUENCE(TRUE, NULL, &alg_len, NULL, oid_len); if (priv_avail && priv_seed_avail) { /* both format */ rc |= ber_encode_OCTET_STRING(TRUE, NULL, &exp_key_len, NULL, rho->ulValueLen + seed->ulValueLen + tr->ulValueLen + s1->ulValueLen + s2->ulValueLen + t0->ulValueLen); rc |= ber_encode_OCTET_STRING(TRUE, NULL, &priv_seed_len, NULL, priv_seed->ulValueLen); rc |= ber_encode_SEQUENCE(TRUE, NULL, &priv_key_len, NULL, exp_key_len + priv_seed_len); } else if (priv_avail) { /* expanded key only */ rc |= ber_encode_OCTET_STRING(TRUE, NULL, &priv_key_len, NULL, rho->ulValueLen + seed->ulValueLen + tr->ulValueLen + s1->ulValueLen + s2->ulValueLen + t0->ulValueLen); } else if (priv_seed_avail) { /* private-seed only */ rc = ber_encode_CHOICE(TRUE, 0x00, NULL, &priv_key_len, NULL, priv_seed->ulValueLen, FALSE); } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } if (rc != CKR_OK) { TRACE_DEVEL("ber_encode failed\n"); return rc; } if (length_only == TRUE) { rc = ber_encode_PrivateKeyInfo(TRUE, NULL, data_len, NULL, alg_len, NULL, priv_key_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_PrivateKeyInfo failed\n"); return rc; } return CKR_OK; } rc = ber_encode_SEQUENCE(FALSE, &alg, &alg_len, (CK_BYTE *)oid, oid_len); if (priv_avail) { buf = malloc(rho->ulValueLen + seed->ulValueLen + tr->ulValueLen + s1->ulValueLen + s2->ulValueLen + t0->ulValueLen); if (buf == NULL) { TRACE_ERROR("%s Memory allocation failed\n", __func__); rc = CKR_HOST_MEMORY; goto error; } ofs = 0; memcpy(buf + ofs, rho->pValue, rho->ulValueLen); ofs += rho->ulValueLen; memcpy(buf + ofs, seed->pValue, seed->ulValueLen); ofs += seed->ulValueLen; memcpy(buf + ofs, tr->pValue, tr->ulValueLen); ofs += tr->ulValueLen; memcpy(buf + ofs, s1->pValue, s1->ulValueLen); ofs += s1->ulValueLen; memcpy(buf + ofs, s2->pValue, s2->ulValueLen); ofs += s2->ulValueLen; memcpy(buf + ofs, t0->pValue, t0->ulValueLen); ofs += t0->ulValueLen; } if (priv_avail && priv_seed_avail) { /* both format */ rc |= ber_encode_OCTET_STRING(FALSE, &exp_key, &exp_key_len, buf, rho->ulValueLen + seed->ulValueLen + tr->ulValueLen + s1->ulValueLen + s2->ulValueLen + t0->ulValueLen); rc |= ber_encode_OCTET_STRING(FALSE, &pseed, &priv_seed_len, priv_seed->pValue, priv_seed->ulValueLen); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode failed\n"); goto error; } free(buf); buf = malloc(exp_key_len + priv_seed_len); if (buf == NULL) { TRACE_ERROR("%s Memory allocation failed\n", __func__); rc = CKR_HOST_MEMORY; goto error; } memcpy(buf, pseed, priv_seed_len); memcpy(buf + priv_seed_len, exp_key, exp_key_len); rc = ber_encode_SEQUENCE(FALSE, &priv_key, &priv_key_len, buf, exp_key_len + priv_seed_len); } else if (priv_avail) { /* expanded key only */ rc |= ber_encode_OCTET_STRING(FALSE, &priv_key, &priv_key_len, buf, rho->ulValueLen + seed->ulValueLen + tr->ulValueLen + s1->ulValueLen + s2->ulValueLen + t0->ulValueLen); } else if (priv_seed_avail) { /* private-seed only */ rc = ber_encode_CHOICE(FALSE, 0x00, &priv_key, &priv_key_len, priv_seed->pValue, priv_seed->ulValueLen, FALSE); } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto error; } if (rc != CKR_OK) { TRACE_DEVEL("ber_encode failed\n"); goto error; } rc = ber_encode_PrivateKeyInfo(FALSE, data, data_len, alg, alg_len, priv_key, priv_key_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_PrivateKeyInfo failed\n"); goto error; } error: if (alg != NULL) free(alg); if (buf != NULL) free(buf); if (priv_key != NULL) free(priv_key); if (exp_key != NULL) free(exp_key); if (pseed != NULL) free(pseed); return rc; } CK_RV ber_decode_IBM_ML_DSA_PrivateKey(CK_MECHANISM_TYPE mech, 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 **priv_seed, CK_ATTRIBUTE **value, const struct pqc_oid **oid) { CK_ATTRIBUTE *rho_attr = NULL, *seed_attr = NULL; CK_ATTRIBUTE *tr_attr = NULL, *s1_attr = NULL, *s2_attr = NULL; CK_ATTRIBUTE *t0_attr = NULL, *priv_seed_attr = NULL, *value_attr = NULL; CK_BYTE *algid = NULL, *priv = NULL, *both = NULL, *key = NULL; CK_BYTE *pseed = NULL, *tmp = NULL; CK_ULONG both_len, field_len, algid_len, key_len = 0, pseed_len = 0; CK_ULONG ofs = 0, option, len, priv_len; CK_RV rc; if (mech == CKM_IBM_DILITHIUM) { *priv_seed = NULL; return ber_decode_IBM_DilithiumPrivateKey(data, data_len, rho, seed, tr, s1, s2, t0, t1, value, oid); } /* Check if this is a ML-DSA private key */ rc = ber_decode_PrivateKeyInfo(data, data_len, &algid, &algid_len, &priv, &priv_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_PrivateKeyInfo failed\n"); return rc; } *oid = find_pqc_by_oid(ml_dsa_oids, algid, algid_len); if (*oid == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } /* * Check which choice is used: * * ML-DSA-PrivateKey ::= CHOICE { * private-seed [0] OCTET STRING (SIZE (32), * expandedKey OCTET STRING (rho | seed | tr | s1 | s2 | t0), * both SEQUENCE { * private-seed OCTET STRING (SIZE (32), * expandedKey OCTET STRING (rho | seed | tr | s1 | s2 | t0) * } * } */ switch (priv[0]) { case 0x30: /* SEQUENCE - both format*/ rc = ber_decode_SEQUENCE(priv, priv_len, &both, &both_len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_SEQUENCE failed\n"); return rc; } rc = ber_decode_OCTET_STRING(both, both_len, &pseed, &pseed_len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_OCTET_STRING failed\n"); return rc; } rc = ber_decode_OCTET_STRING(both + field_len, both_len - field_len, &key, &key_len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_OCTET_STRING failed\n"); return rc; } break; case 0x04: /* OCTET STRING - expanded key */ rc = ber_decode_OCTET_STRING(priv, priv_len, &key, &key_len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_OCTET_STRING failed\n"); return rc; } break; case 0x80: /* CHOICE - private seed only */ rc = ber_decode_CHOICE(priv, priv_len, FALSE, &pseed, &pseed_len, &field_len, &option); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_CHOICE failed\n"); return rc; } break; default: TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } if (key != NULL) { if (key_len != (*oid)->len_info.ml_dsa.rho_len + (*oid)->len_info.ml_dsa.seed_len + (*oid)->len_info.ml_dsa.tr_len + (*oid)->len_info.ml_dsa.s1_len + (*oid)->len_info.ml_dsa.s2_len + (*oid)->len_info.ml_dsa.t0_len) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } rc = build_attribute(CKA_IBM_ML_DSA_RHO, key + ofs, (*oid)->len_info.ml_dsa.rho_len, &rho_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute for (rho) failed\n"); goto cleanup; } ofs += (*oid)->len_info.ml_dsa.rho_len; rc = build_attribute(CKA_IBM_ML_DSA_SEED, key + ofs, (*oid)->len_info.ml_dsa.seed_len, &seed_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute for (seed) failed\n"); goto cleanup; } ofs += (*oid)->len_info.ml_dsa.seed_len; rc = build_attribute(CKA_IBM_ML_DSA_TR, key + ofs, (*oid)->len_info.ml_dsa.tr_len, &tr_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute for (tr) failed\n"); goto cleanup; } ofs += (*oid)->len_info.ml_dsa.tr_len; rc = build_attribute(CKA_IBM_ML_DSA_S1, key + ofs, (*oid)->len_info.ml_dsa.s1_len, &s1_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute for (s1) failed\n"); goto cleanup; } ofs += (*oid)->len_info.ml_dsa.s1_len; rc = build_attribute(CKA_IBM_ML_DSA_S2, key + ofs, (*oid)->len_info.ml_dsa.s2_len, &s2_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute for (s2) failed\n"); goto cleanup; } ofs += (*oid)->len_info.ml_dsa.s2_len; rc = build_attribute(CKA_IBM_ML_DSA_T0, key + ofs, (*oid)->len_info.ml_dsa.t0_len, &t0_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute for (t0) failed\n"); goto cleanup; } ofs += (*oid)->len_info.ml_dsa.t0_len; } if (pseed != NULL) { if (pseed_len != (*oid)->len_info.ml_dsa.priv_seed_len) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto cleanup; } rc = build_attribute(CKA_IBM_ML_DSA_PRIVATE_SEED, pseed, (*oid)->len_info.ml_dsa.priv_seed_len, &priv_seed_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute for (priv-seed) failed\n"); goto cleanup; } } /* Add private key as CKA_VALUE to public key (z/OS ICSF compatibility) */ rc = ber_decode_SEQUENCE(data, data_len, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_ERROR("%s ber_decode_SEQUENCE failed with rc=0x%lx\n", __func__, rc); goto cleanup; } rc = build_attribute(CKA_VALUE, data, field_len, &value_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute for (value) failed\n"); goto cleanup; } *rho = rho_attr; *seed = seed_attr; *tr = tr_attr; *s1 = s1_attr; *s2 = s2_attr; *t0 = t0_attr; *t1 = NULL; *priv_seed = priv_seed_attr; *value = value_attr; return CKR_OK; cleanup: 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 (priv_seed_attr) free(priv_seed_attr); if (value_attr) free(value_attr); return rc; } /** * An IBM ML-DSA public key is given by: * * SEQUENCE (2 elem) * SEQUENCE (2 elem) * OBJECT IDENTIFIER 2.16.840.1.101.3.4.4.xxx * BIT STRING - public key (pk) */ CK_RV ber_encode_IBM_ML_KEM_PublicKey(CK_MECHANISM_TYPE mech, CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, const CK_BYTE *oid, CK_ULONG oid_len, CK_ATTRIBUTE *pk) { CK_BYTE *buf = NULL, *pub = NULL, *alg = NULL; CK_ULONG alg_len = 0, pub_len = 0, total_len = 0; CK_RV rc; if (mech == CKM_IBM_KYBER) return ber_encode_IBM_KyberPublicKey(length_only, data, data_len, oid, oid_len, pk); /* Calculate storage for AlgID sequence */ rc = ber_encode_SEQUENCE(TRUE, NULL, &alg_len, NULL, oid_len); /* Calculate storage for public key bitsring */ rc |= ber_encode_BIT_STRING(TRUE, NULL, &pub_len, NULL, pk->ulValueLen, 0); /* Calculate storage for outer sequence */ rc |= ber_encode_SEQUENCE(TRUE, NULL, &total_len, NULL, alg_len + pub_len); if (rc != CKR_OK) { TRACE_ERROR("%s ber_encode failed with rc=0x%lx\n", __func__, rc); return rc; } if (length_only) { *data_len = total_len; return CKR_OK; } rc = ber_encode_BIT_STRING(FALSE, &pub, &pub_len, pk->pValue, pk->ulValueLen, 0); if (rc != CKR_OK) { TRACE_ERROR("%s ber_encode_BIT_STRING failed with rc=0x%lx\n", __func__, rc); goto error; } rc = ber_encode_SEQUENCE(FALSE, &alg, &alg_len, (CK_BYTE *)oid, oid_len); if (rc != CKR_OK) { TRACE_ERROR("%s ber_encode_SEQUENCE failed with rc=0x%lx\n", __func__, rc); goto error; } /* Allocate storage for outer sequence */ buf = malloc(alg_len + pub_len); if (buf == NULL) { TRACE_ERROR("%s Memory allocation failed\n", __func__); rc = CKR_HOST_MEMORY; goto error; } memcpy(buf, alg, alg_len); memcpy(buf + alg_len, pub, pub_len); rc = ber_encode_SEQUENCE(FALSE, data, data_len, buf, alg_len + pub_len); if (rc != CKR_OK) { TRACE_ERROR("%s ber_encode_SEQUENCE failed with rc=0x%lx\n", __func__, rc); goto error; } error: if (buf != NULL) free(buf); if (pub != NULL) free(pub); if (alg != NULL) free(alg); return rc; } CK_RV ber_decode_IBM_ML_KEM_PublicKey(CK_MECHANISM_TYPE mech, CK_BYTE *data, CK_ULONG data_len, CK_ATTRIBUTE **pk_attr, CK_ATTRIBUTE **value_attr, const struct pqc_oid **oid) { CK_ATTRIBUTE *pk_attr_temp = NULL; CK_ATTRIBUTE *value_attr_temp = NULL; CK_BYTE *algoid = NULL; CK_ULONG algoid_len; CK_BYTE *param = NULL; CK_ULONG param_len; CK_BYTE *pub = NULL; CK_ULONG pub_len = 0; CK_ULONG raw_spki_len; CK_RV rc; if (mech == CKM_IBM_KYBER) return ber_decode_IBM_KyberPublicKey(data, data_len, pk_attr, value_attr, oid); /* * SEQUENCE (2 elem) * SEQUENCE (2 elem) * OBJECT IDENTIFIER 2.16.840.1.101.3.4.4.xxx * BIT STRING - public key (pk) */ rc = ber_decode_SPKI(data, data_len, &algoid, &algoid_len, ¶m, ¶m_len, &pub, &pub_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_SPKI failed\n"); return rc; } *oid = find_pqc_by_oid(ml_kem_oids, algoid, algoid_len); if (*oid == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } if (pub_len != (*oid)->len_info.ml_kem.pk_len) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } /* Build pk attribute */ rc = build_attribute(CKA_IBM_ML_KEM_PK, pub, (*oid)->len_info.ml_kem.pk_len, &pk_attr_temp); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto cleanup; } /* Add raw SPKI as CKA_VALUE to public key (z/OS ICSF compatibility) */ rc = ber_decode_SEQUENCE(data, data_len, &pub, &pub_len, &raw_spki_len); if (rc != CKR_OK) { TRACE_ERROR("%s ber_decode_SEQUENCE failed with rc=0x%lx\n", __func__, rc); goto cleanup; } rc = build_attribute(CKA_VALUE, data, raw_spki_len, &value_attr_temp); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto cleanup; } *pk_attr = pk_attr_temp; *value_attr = value_attr_temp; return CKR_OK; cleanup: if (pk_attr_temp) free(pk_attr_temp); if (value_attr_temp) free(value_attr_temp); return rc; } /* * An IBM ML-KEM private key is given by: * * ML-KEM-PrivateKey ::= CHOICE { * private-seed [0] OCTET STRING (SIZE (64), * expandedKey OCTET STRING (sk), * both SEQUENCE { * private-seed OCTET STRING (SIZE (64), * expandedKey OCTET STRING (sk) * } * } * */ CK_RV ber_encode_IBM_ML_KEM_PrivateKey(CK_MECHANISM_TYPE mech, CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, const CK_BYTE *oid, CK_ULONG oid_len, CK_ATTRIBUTE *sk, CK_ATTRIBUTE *pk, CK_ATTRIBUTE *priv_seed) { CK_BBOOL priv_avail, priv_seed_avail; CK_ULONG priv_seed_len = 0, exp_key_len = 0, priv_key_len = 0; CK_ULONG alg_len = 0; CK_BYTE *alg = NULL, *buf = NULL, *priv_key = NULL, *exp_key = NULL; CK_BYTE *pseed = NULL; CK_RV rc; if (mech == CKM_IBM_KYBER) return ber_encode_IBM_KyberPrivateKey(length_only, data, data_len, oid, oid_len, sk, pk); priv_avail = (sk != NULL && sk->ulValueLen != 0 && sk->pValue != NULL); priv_seed_avail = (priv_seed != NULL && priv_seed->ulValueLen != 0 && priv_seed->pValue != NULL); /* Calculate length of key material */ rc = ber_encode_SEQUENCE(TRUE, NULL, &alg_len, NULL, oid_len); if (priv_avail && priv_seed_avail) { /* both format */ rc |= ber_encode_OCTET_STRING(TRUE, NULL, &exp_key_len, NULL, sk->ulValueLen); rc |= ber_encode_OCTET_STRING(TRUE, NULL, &priv_seed_len, NULL, priv_seed->ulValueLen); rc |= ber_encode_SEQUENCE(TRUE, NULL, &priv_key_len, NULL, exp_key_len + priv_seed_len); } else if (priv_avail) { /* expanded key only */ rc |= ber_encode_OCTET_STRING(TRUE, NULL, &priv_key_len, NULL, sk->ulValueLen); } else if (priv_seed_avail) { /* private-seed only */ rc = ber_encode_CHOICE(TRUE, 0x00, NULL, &priv_key_len, NULL, priv_seed->ulValueLen, FALSE); } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } if (rc != CKR_OK) { TRACE_DEVEL("ber_encode failed\n"); return rc; } if (length_only == TRUE) { rc = ber_encode_PrivateKeyInfo(TRUE, NULL, data_len, NULL, alg_len, NULL, priv_key_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_PrivateKeyInfo failed\n"); return rc; } return CKR_OK; } rc = ber_encode_SEQUENCE(FALSE, &alg, &alg_len, (CK_BYTE *)oid, oid_len); if (priv_avail && priv_seed_avail) { /* both format */ rc |= ber_encode_OCTET_STRING(FALSE, &exp_key, &exp_key_len, sk->pValue, sk->ulValueLen); rc |= ber_encode_OCTET_STRING(FALSE, &pseed, &priv_seed_len, priv_seed->pValue, priv_seed->ulValueLen); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode failed\n"); goto error; } buf = malloc(exp_key_len + priv_seed_len); if (buf == NULL) { TRACE_ERROR("%s Memory allocation failed\n", __func__); rc = CKR_HOST_MEMORY; goto error; } memcpy(buf, pseed, priv_seed_len); memcpy(buf + priv_seed_len, exp_key, exp_key_len); rc = ber_encode_SEQUENCE(FALSE, &priv_key, &priv_key_len, buf, exp_key_len + priv_seed_len); } else if (priv_avail) { /* expanded key only */ rc |= ber_encode_OCTET_STRING(FALSE, &priv_key, &priv_key_len, sk->pValue, sk->ulValueLen); } else if (priv_seed_avail) { /* private-seed only */ rc = ber_encode_CHOICE(FALSE, 0x00, &priv_key, &priv_key_len, priv_seed->pValue, priv_seed->ulValueLen, FALSE); } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto error; } if (rc != CKR_OK) { TRACE_DEVEL("ber_encode failed\n"); goto error; } rc = ber_encode_PrivateKeyInfo(FALSE, data, data_len, alg, alg_len, priv_key, priv_key_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_PrivateKeyInfo failed\n"); goto error; } error: if (alg != NULL) free(alg); if (buf != NULL) free(buf); if (priv_key != NULL) free(priv_key); if (exp_key != NULL) free(exp_key); if (pseed != NULL) free(pseed); return rc; } CK_RV ber_decode_IBM_ML_KEM_PrivateKey(CK_MECHANISM_TYPE mech, CK_BYTE *data, CK_ULONG data_len, CK_ATTRIBUTE **sk, CK_ATTRIBUTE **pk, CK_ATTRIBUTE **priv_seed, CK_ATTRIBUTE **value, const struct pqc_oid **oid) { CK_ATTRIBUTE *sk_attr = NULL; CK_ATTRIBUTE *priv_seed_attr = NULL, *value_attr = NULL; CK_BYTE *algid = NULL, *priv = NULL, *both = NULL, *key = NULL; CK_BYTE *pseed = NULL, *tmp = NULL; CK_ULONG both_len, field_len, algid_len, key_len = 0, pseed_len = 0; CK_ULONG option, len, priv_len; CK_RV rc; if (mech == CKM_IBM_KYBER) { *priv_seed = NULL; return ber_decode_IBM_KyberPrivateKey(data, data_len, sk, pk, value, oid); } /* Check if this is a ML-KEM private key */ rc = ber_decode_PrivateKeyInfo(data, data_len, &algid, &algid_len, &priv, &priv_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_PrivateKeyInfo failed\n"); return rc; } *oid = find_pqc_by_oid(ml_kem_oids, algid, algid_len); if (*oid == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } /* * Check which choice is used: * * ML-KEM-PrivateKey ::= CHOICE { * private-seed [0] OCTET STRING (SIZE (64), * expandedKey OCTET STRING (sk), * both SEQUENCE { * private-seed OCTET STRING (SIZE (64), * expandedKey OCTET STRING (sk) * } * } */ switch (priv[0]) { case 0x30: /* SEQUENCE - both format*/ rc = ber_decode_SEQUENCE(priv, priv_len, &both, &both_len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_SEQUENCE failed\n"); return rc; } rc = ber_decode_OCTET_STRING(both, both_len, &pseed, &pseed_len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_OCTET_STRING failed\n"); return rc; } rc = ber_decode_OCTET_STRING(both + field_len, both_len - field_len, &key, &key_len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_OCTET_STRING failed\n"); return rc; } break; case 0x04: /* OCTET STRING - expanded key */ rc = ber_decode_OCTET_STRING(priv, priv_len, &key, &key_len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_OCTET_STRING failed\n"); return rc; } break; case 0x80: /* CHOICE - private seed only */ rc = ber_decode_CHOICE(priv, priv_len, FALSE, &pseed, &pseed_len, &field_len, &option); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_CHOICE failed\n"); return rc; } break; default: TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } if (key != NULL) { if (key_len != (*oid)->len_info.ml_kem.sk_len) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto cleanup; } rc = build_attribute(CKA_IBM_ML_KEM_SK, key, (*oid)->len_info.ml_kem.sk_len, &sk_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute for (sk) failed\n"); goto cleanup; } } if (pseed != NULL) { if (pseed_len != (*oid)->len_info.ml_kem.priv_seed_len) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto cleanup; } rc = build_attribute(CKA_IBM_ML_KEM_PRIVATE_SEED, pseed, (*oid)->len_info.ml_kem.priv_seed_len, &priv_seed_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute for (priv-seed) failed\n"); goto cleanup; } } /* Add private key as CKA_VALUE to public key (z/OS ICSF compatibility) */ rc = ber_decode_SEQUENCE(data, data_len, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_ERROR("%s ber_decode_SEQUENCE failed with rc=0x%lx\n", __func__, rc); goto cleanup; } rc = build_attribute(CKA_VALUE, data, field_len, &value_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute for (value) failed\n"); goto cleanup; } *sk = sk_attr; *pk = NULL; *priv_seed = priv_seed_attr; *value = value_attr; return CKR_OK; cleanup: if (sk_attr) free(sk_attr); if (priv_seed_attr) free(priv_seed_attr); if (value_attr) free(value_attr); return rc; } /** * An ML-DSA public key is given by: * * SEQUENCE (2 elem) * SEQUENCE (2 elem) * OBJECT IDENTIFIER 2.16.840.1.101.3.4.3.xxx * BIT STRING - public key (value = rho | t1) */ CK_RV ber_encode_ML_DSA_PublicKey(CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, const CK_BYTE *oid, CK_ULONG oid_len, CK_ATTRIBUTE *value) { CK_BYTE *buf = NULL, *pub = NULL, *alg = NULL; CK_ULONG alg_len = 0, pub_len = 0, total_len = 0; CK_RV rc; /* Calculate storage for AlgID sequence */ rc = ber_encode_SEQUENCE(TRUE, NULL, &alg_len, NULL, oid_len); /* Calculate storage for public key bitsring */ rc |= ber_encode_BIT_STRING(TRUE, NULL, &pub_len, NULL, value->ulValueLen, 0); /* Calculate storage for outer sequence */ rc |= ber_encode_SEQUENCE(TRUE, NULL, &total_len, NULL, alg_len + pub_len); if (rc != CKR_OK) { TRACE_ERROR("%s ber_encode failed with rc=0x%lx\n", __func__, rc); return rc; } if (length_only) { *data_len = total_len; return CKR_OK; } rc = ber_encode_BIT_STRING(FALSE, &pub, &pub_len, value->pValue, value->ulValueLen, 0); if (rc != CKR_OK) { TRACE_ERROR("%s ber_encode_BIT_STRING failed with rc=0x%lx\n", __func__, rc); goto error; } rc = ber_encode_SEQUENCE(FALSE, &alg, &alg_len, (CK_BYTE *)oid, oid_len); if (rc != CKR_OK) { TRACE_ERROR("%s ber_encode_SEQUENCE failed with rc=0x%lx\n", __func__, rc); goto error; } /* Allocate storage for outer sequence */ buf = malloc(alg_len + pub_len); if (buf == NULL) { TRACE_ERROR("%s Memory allocation failed\n", __func__); rc = CKR_HOST_MEMORY; goto error; } memcpy(buf, alg, alg_len); memcpy(buf + alg_len, pub, pub_len); rc = ber_encode_SEQUENCE(FALSE, data, data_len, buf, alg_len + pub_len); if (rc != CKR_OK) { TRACE_ERROR("%s ber_encode_SEQUENCE failed with rc=0x%lx\n", __func__, rc); goto error; } error: if (buf != NULL) free(buf); if (pub != NULL) free(pub); if (alg != NULL) free(alg); return rc; } CK_RV ber_decode_ML_DSA_PublicKey(CK_BYTE *data, CK_ULONG data_len, CK_ATTRIBUTE **value_attr, const struct pqc_oid **oid) { CK_BYTE *algoid = NULL; CK_ULONG algoid_len; CK_BYTE *param = NULL; CK_ULONG param_len; CK_BYTE *pub = NULL; CK_ULONG pub_len = 0; CK_RV rc; /* * SEQUENCE (2 elem) * SEQUENCE (2 elem) * OBJECT IDENTIFIER 2.16.840.1.101.3.4.3.xxx * BIT STRING - public key (value = rho | t1) */ rc = ber_decode_SPKI(data, data_len, &algoid, &algoid_len, ¶m, ¶m_len, &pub, &pub_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_SPKI failed\n"); return rc; } *oid = find_pqc_by_oid(ml_dsa_oids, algoid, algoid_len); if (*oid == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } if (pub_len != (*oid)->len_info.ml_dsa.rho_len + (*oid)->len_info.ml_dsa.t1_len) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } /* Build value attribute */ rc = build_attribute(CKA_VALUE, pub, (*oid)->len_info.ml_dsa.rho_len + (*oid)->len_info.ml_dsa.t1_len, value_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); return rc; } return CKR_OK; } /** * An ML-DSA private key is given by: * * ML-DSA-PrivateKey ::= CHOICE { * private-seed [0] OCTET STRING (SIZE (32), * expandedKey OCTET STRING (value = rho | seed | tr | s1 | s2 | t0), * both SEQUENCE { * private-seed OCTET STRING (SIZE (32), * expandedKey OCTET STRING (value = rho | seed | tr | s1 | s2 | t0) * } * } * */ CK_RV ber_encode_ML_DSA_PrivateKey(CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, const CK_BYTE *oid, CK_ULONG oid_len, CK_ATTRIBUTE *value, CK_ATTRIBUTE *seed) { CK_BBOOL value_avail, seed_avail; CK_ULONG seed_len = 0, exp_key_len = 0, priv_key_len = 0; CK_ULONG alg_len = 0; CK_BYTE *alg = NULL, *buf = NULL, *priv_key = NULL, *exp_key = NULL; CK_BYTE *pseed = NULL; CK_RV rc; value_avail = (value != NULL && value->ulValueLen != 0 && value->pValue != NULL); seed_avail = (seed != NULL && seed->ulValueLen != 0 && seed->pValue != NULL); /* Calculate length of key material */ rc = ber_encode_SEQUENCE(TRUE, NULL, &alg_len, NULL, oid_len); if (value_avail && seed_avail) { /* both format */ rc |= ber_encode_OCTET_STRING(TRUE, NULL, &exp_key_len, NULL, value->ulValueLen); rc |= ber_encode_OCTET_STRING(TRUE, NULL, &seed_len, NULL, seed->ulValueLen); rc |= ber_encode_SEQUENCE(TRUE, NULL, &priv_key_len, NULL, exp_key_len + seed_len); } else if (value_avail) { /* expanded key only */ rc |= ber_encode_OCTET_STRING(TRUE, NULL, &priv_key_len, NULL, value->ulValueLen); } else if (seed_avail) { /* private-seed only */ rc = ber_encode_CHOICE(TRUE, 0x00, NULL, &priv_key_len, NULL, seed->ulValueLen, FALSE); } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } if (rc != CKR_OK) { TRACE_DEVEL("ber_encode failed\n"); return rc; } if (length_only == TRUE) { rc = ber_encode_PrivateKeyInfo(TRUE, NULL, data_len, NULL, alg_len, NULL, priv_key_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_PrivateKeyInfo failed\n"); return rc; } return CKR_OK; } rc = ber_encode_SEQUENCE(FALSE, &alg, &alg_len, (CK_BYTE *)oid, oid_len); if (value_avail && seed_avail) { /* both format */ rc |= ber_encode_OCTET_STRING(FALSE, &exp_key, &exp_key_len, value->pValue, value->ulValueLen ); rc |= ber_encode_OCTET_STRING(FALSE, &pseed, &seed_len, seed->pValue, seed->ulValueLen); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode failed\n"); goto error; } free(buf); buf = malloc(exp_key_len + seed_len); if (buf == NULL) { TRACE_ERROR("%s Memory allocation failed\n", __func__); rc = CKR_HOST_MEMORY; goto error; } memcpy(buf, pseed, seed_len); memcpy(buf + seed_len, exp_key, exp_key_len); rc = ber_encode_SEQUENCE(FALSE, &priv_key, &priv_key_len, buf, exp_key_len + seed_len); } else if (value_avail) { /* expanded key only */ rc |= ber_encode_OCTET_STRING(FALSE, &priv_key, &priv_key_len, value->pValue, value->ulValueLen); } else if (seed_avail) { /* private-seed only */ rc = ber_encode_CHOICE(FALSE, 0x00, &priv_key, &priv_key_len, seed->pValue, seed->ulValueLen, FALSE); } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto error; } if (rc != CKR_OK) { TRACE_DEVEL("ber_encode failed\n"); goto error; } rc = ber_encode_PrivateKeyInfo(FALSE, data, data_len, alg, alg_len, priv_key, priv_key_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_PrivateKeyInfo failed\n"); goto error; } error: if (alg != NULL) free(alg); if (buf != NULL) free(buf); if (priv_key != NULL) free(priv_key); if (exp_key != NULL) free(exp_key); if (pseed != NULL) free(pseed); return rc; } CK_RV ber_decode_ML_DSA_PrivateKey(CK_BYTE *data, CK_ULONG data_len, CK_ATTRIBUTE **value, CK_ATTRIBUTE **seed, const struct pqc_oid **oid) { CK_ATTRIBUTE *seed_attr = NULL, *value_attr = NULL; CK_BYTE *algid = NULL, *priv = NULL, *both = NULL, *key = NULL; CK_BYTE *pseed = NULL; CK_ULONG both_len, field_len, algid_len, key_len = 0, pseed_len = 0; CK_ULONG option, priv_len; CK_RV rc; /* Check if this is a ML-DSA private key */ rc = ber_decode_PrivateKeyInfo(data, data_len, &algid, &algid_len, &priv, &priv_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_PrivateKeyInfo failed\n"); return rc; } *oid = find_pqc_by_oid(ml_dsa_oids, algid, algid_len); if (*oid == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } /* * Check which choice is used: * * ML-DSA-PrivateKey ::= CHOICE { * private-seed [0] OCTET STRING (SIZE (32), * expandedKey OCTET STRING (rho | seed | tr | s1 | s2 | t0), * both SEQUENCE { * private-seed OCTET STRING (SIZE (32), * expandedKey OCTET STRING (rho | seed | tr | s1 | s2 | t0) * } * } */ switch (priv[0]) { case 0x30: /* SEQUENCE - both format*/ rc = ber_decode_SEQUENCE(priv, priv_len, &both, &both_len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_SEQUENCE failed\n"); return rc; } rc = ber_decode_OCTET_STRING(both, both_len, &pseed, &pseed_len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_OCTET_STRING failed\n"); return rc; } rc = ber_decode_OCTET_STRING(both + field_len, both_len - field_len, &key, &key_len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_OCTET_STRING failed\n"); return rc; } break; case 0x04: /* OCTET STRING - expanded key */ rc = ber_decode_OCTET_STRING(priv, priv_len, &key, &key_len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_OCTET_STRING failed\n"); return rc; } break; case 0x80: /* CHOICE - private seed only */ rc = ber_decode_CHOICE(priv, priv_len, FALSE, &pseed, &pseed_len, &field_len, &option); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_CHOICE failed\n"); return rc; } break; default: TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } if (key != NULL) { if (key_len != (*oid)->len_info.ml_dsa.rho_len + (*oid)->len_info.ml_dsa.seed_len + (*oid)->len_info.ml_dsa.tr_len + (*oid)->len_info.ml_dsa.s1_len + (*oid)->len_info.ml_dsa.s2_len + (*oid)->len_info.ml_dsa.t0_len) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } rc = build_attribute(CKA_VALUE, key, (*oid)->len_info.ml_dsa.rho_len + (*oid)->len_info.ml_dsa.seed_len + (*oid)->len_info.ml_dsa.tr_len + (*oid)->len_info.ml_dsa.s1_len + (*oid)->len_info.ml_dsa.s2_len + (*oid)->len_info.ml_dsa.t0_len, &value_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute for (value) failed\n"); goto cleanup; } } if (pseed != NULL) { if (pseed_len != (*oid)->len_info.ml_dsa.priv_seed_len) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto cleanup; } rc = build_attribute(CKA_SEED, pseed, (*oid)->len_info.ml_dsa.priv_seed_len, &seed_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute for (seed) failed\n"); goto cleanup; } } *value = value_attr; *seed = seed_attr; return CKR_OK; cleanup: if (value_attr) free(value_attr); if (seed_attr) free(seed_attr); return rc; } /** * An ML-KEM public key is given by: * * SEQUENCE (2 elem) * SEQUENCE (2 elem) * OBJECT IDENTIFIER 2.16.840.1.101.3.4.4.xxx * BIT STRING - public key (pk) */ CK_RV ber_encode_ML_KEM_PublicKey(CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, const CK_BYTE *oid, CK_ULONG oid_len, CK_ATTRIBUTE *value) { CK_BYTE *buf = NULL, *pub = NULL, *alg = NULL; CK_ULONG alg_len = 0, pub_len = 0, total_len = 0; CK_RV rc; /* Calculate storage for AlgID sequence */ rc = ber_encode_SEQUENCE(TRUE, NULL, &alg_len, NULL, oid_len); /* Calculate storage for public key bitsring */ rc |= ber_encode_BIT_STRING(TRUE, NULL, &pub_len, NULL, value->ulValueLen, 0); /* Calculate storage for outer sequence */ rc |= ber_encode_SEQUENCE(TRUE, NULL, &total_len, NULL, alg_len + pub_len); if (rc != CKR_OK) { TRACE_ERROR("%s ber_encode failed with rc=0x%lx\n", __func__, rc); return rc; } if (length_only) { *data_len = total_len; return CKR_OK; } rc = ber_encode_BIT_STRING(FALSE, &pub, &pub_len, value->pValue, value->ulValueLen, 0); if (rc != CKR_OK) { TRACE_ERROR("%s ber_encode_BIT_STRING failed with rc=0x%lx\n", __func__, rc); goto error; } rc = ber_encode_SEQUENCE(FALSE, &alg, &alg_len, (CK_BYTE *)oid, oid_len); if (rc != CKR_OK) { TRACE_ERROR("%s ber_encode_SEQUENCE failed with rc=0x%lx\n", __func__, rc); goto error; } /* Allocate storage for outer sequence */ buf = malloc(alg_len + pub_len); if (buf == NULL) { TRACE_ERROR("%s Memory allocation failed\n", __func__); rc = CKR_HOST_MEMORY; goto error; } memcpy(buf, alg, alg_len); memcpy(buf + alg_len, pub, pub_len); rc = ber_encode_SEQUENCE(FALSE, data, data_len, buf, alg_len + pub_len); if (rc != CKR_OK) { TRACE_ERROR("%s ber_encode_SEQUENCE failed with rc=0x%lx\n", __func__, rc); goto error; } error: if (buf != NULL) free(buf); if (pub != NULL) free(pub); if (alg != NULL) free(alg); return rc; } CK_RV ber_decode_ML_KEM_PublicKey(CK_BYTE *data, CK_ULONG data_len, CK_ATTRIBUTE **value_attr, const struct pqc_oid **oid) { CK_BYTE *algoid = NULL; CK_ULONG algoid_len; CK_BYTE *param = NULL; CK_ULONG param_len; CK_BYTE *pub = NULL; CK_ULONG pub_len = 0; CK_RV rc; /* * SEQUENCE (2 elem) * SEQUENCE (2 elem) * OBJECT IDENTIFIER 2.16.840.1.101.3.4.4.xxx * BIT STRING - public key (pk) */ rc = ber_decode_SPKI(data, data_len, &algoid, &algoid_len, ¶m, ¶m_len, &pub, &pub_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_SPKI failed\n"); return rc; } *oid = find_pqc_by_oid(ml_kem_oids, algoid, algoid_len); if (*oid == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } if (pub_len != (*oid)->len_info.ml_kem.pk_len) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } /* Build value attribute */ rc = build_attribute(CKA_VALUE, pub, (*oid)->len_info.ml_kem.pk_len, value_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); return rc; } return CKR_OK; } /* * An ML-KEM private key is given by: * * ML-KEM-PrivateKey ::= CHOICE { * private-seed [0] OCTET STRING (SIZE (64), * expandedKey OCTET STRING (sk), * both SEQUENCE { * private-seed OCTET STRING (SIZE (64), * expandedKey OCTET STRING (sk) * } * } * */ CK_RV ber_encode_ML_KEM_PrivateKey(CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, const CK_BYTE *oid, CK_ULONG oid_len, CK_ATTRIBUTE *value, CK_ATTRIBUTE *seed) { CK_BBOOL value_avail, seed_avail; CK_ULONG seed_len = 0, exp_key_len = 0, priv_key_len = 0; CK_ULONG alg_len = 0; CK_BYTE *alg = NULL, *buf = NULL, *priv_key = NULL, *exp_key = NULL; CK_BYTE *pseed = NULL; CK_RV rc; value_avail = (value != NULL && value->ulValueLen != 0 && value->pValue != NULL); seed_avail = (seed != NULL && seed->ulValueLen != 0 && seed->pValue != NULL); /* Calculate length of key material */ rc = ber_encode_SEQUENCE(TRUE, NULL, &alg_len, NULL, oid_len); if (value_avail && seed_avail) { /* both format */ rc |= ber_encode_OCTET_STRING(TRUE, NULL, &exp_key_len, NULL, value->ulValueLen); rc |= ber_encode_OCTET_STRING(TRUE, NULL, &seed_len, NULL, seed->ulValueLen); rc |= ber_encode_SEQUENCE(TRUE, NULL, &priv_key_len, NULL, exp_key_len + seed_len); } else if (value_avail) { /* expanded key only */ rc |= ber_encode_OCTET_STRING(TRUE, NULL, &priv_key_len, NULL, value->ulValueLen); } else if (seed_avail) { /* private-seed only */ rc = ber_encode_CHOICE(TRUE, 0x00, NULL, &priv_key_len, NULL, seed->ulValueLen, FALSE); } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } if (rc != CKR_OK) { TRACE_DEVEL("ber_encode failed\n"); return rc; } if (length_only == TRUE) { rc = ber_encode_PrivateKeyInfo(TRUE, NULL, data_len, NULL, alg_len, NULL, priv_key_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_PrivateKeyInfo failed\n"); return rc; } return CKR_OK; } rc = ber_encode_SEQUENCE(FALSE, &alg, &alg_len, (CK_BYTE *)oid, oid_len); if (value_avail && seed_avail) { /* both format */ rc |= ber_encode_OCTET_STRING(FALSE, &exp_key, &exp_key_len, value->pValue, value->ulValueLen ); rc |= ber_encode_OCTET_STRING(FALSE, &pseed, &seed_len, seed->pValue, seed->ulValueLen); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode failed\n"); goto error; } free(buf); buf = malloc(exp_key_len + seed_len); if (buf == NULL) { TRACE_ERROR("%s Memory allocation failed\n", __func__); rc = CKR_HOST_MEMORY; goto error; } memcpy(buf, pseed, seed_len); memcpy(buf + seed_len, exp_key, exp_key_len); rc = ber_encode_SEQUENCE(FALSE, &priv_key, &priv_key_len, buf, exp_key_len + seed_len); } else if (value_avail) { /* expanded key only */ rc |= ber_encode_OCTET_STRING(FALSE, &priv_key, &priv_key_len, value->pValue, value->ulValueLen); } else if (seed_avail) { /* private-seed only */ rc = ber_encode_CHOICE(FALSE, 0x00, &priv_key, &priv_key_len, seed->pValue, seed->ulValueLen, FALSE); } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto error; } if (rc != CKR_OK) { TRACE_DEVEL("ber_encode failed\n"); goto error; } rc = ber_encode_PrivateKeyInfo(FALSE, data, data_len, alg, alg_len, priv_key, priv_key_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_PrivateKeyInfo failed\n"); goto error; } error: if (alg != NULL) free(alg); if (buf != NULL) free(buf); if (priv_key != NULL) free(priv_key); if (exp_key != NULL) free(exp_key); if (pseed != NULL) free(pseed); return rc; } CK_RV ber_decode_ML_KEM_PrivateKey(CK_BYTE *data, CK_ULONG data_len, CK_ATTRIBUTE **value, CK_ATTRIBUTE **seed, const struct pqc_oid **oid) { CK_ATTRIBUTE *seed_attr = NULL, *value_attr = NULL; CK_BYTE *algid = NULL, *priv = NULL, *both = NULL, *key = NULL; CK_BYTE *pseed = NULL; CK_ULONG both_len, field_len, algid_len, key_len = 0, pseed_len = 0; CK_ULONG option, priv_len; CK_RV rc; /* Check if this is a ML-KEM private key */ rc = ber_decode_PrivateKeyInfo(data, data_len, &algid, &algid_len, &priv, &priv_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_PrivateKeyInfo failed\n"); return rc; } *oid = find_pqc_by_oid(ml_kem_oids, algid, algid_len); if (*oid == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } /* * Check which choice is used: * * ML-KEM-PrivateKey ::= CHOICE { * private-seed [0] OCTET STRING (SIZE (64), * expandedKey OCTET STRING (sk), * both SEQUENCE { * private-seed OCTET STRING (SIZE (64), * expandedKey OCTET STRING (sk) * } * } */ switch (priv[0]) { case 0x30: /* SEQUENCE - both format*/ rc = ber_decode_SEQUENCE(priv, priv_len, &both, &both_len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_SEQUENCE failed\n"); return rc; } rc = ber_decode_OCTET_STRING(both, both_len, &pseed, &pseed_len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_OCTET_STRING failed\n"); return rc; } rc = ber_decode_OCTET_STRING(both + field_len, both_len - field_len, &key, &key_len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_OCTET_STRING failed\n"); return rc; } break; case 0x04: /* OCTET STRING - expanded key */ rc = ber_decode_OCTET_STRING(priv, priv_len, &key, &key_len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_OCTET_STRING failed\n"); return rc; } break; case 0x80: /* CHOICE - private seed only */ rc = ber_decode_CHOICE(priv, priv_len, FALSE, &pseed, &pseed_len, &field_len, &option); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_CHOICE failed\n"); return rc; } break; default: TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } if (key != NULL) { if (key_len != (*oid)->len_info.ml_kem.sk_len) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } rc = build_attribute(CKA_VALUE, key, (*oid)->len_info.ml_kem.sk_len, &value_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute for (value) failed\n"); goto cleanup; } } if (pseed != NULL) { if (pseed_len != (*oid)->len_info.ml_kem.priv_seed_len) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto cleanup; } rc = build_attribute(CKA_SEED, pseed, (*oid)->len_info.ml_kem.priv_seed_len, &seed_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute for (seed) failed\n"); goto cleanup; } } *value = value_attr; *seed = seed_attr; return CKR_OK; cleanup: if (value_attr) free(value_attr); if (seed_attr) free(seed_attr); return rc; } opencryptoki-opencryptoki-451d99c/usr/lib/common/attributes.c000066400000000000000000000312311520105705100245250ustar00rootroot00000000000000/* * 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 "p11util.h" #include "trace.h" #include static void __cleanse_and_free_attribute_array(CK_ATTRIBUTE_PTR attrs, CK_ULONG attrs_len, CK_BBOOL cleanse, CK_BBOOL free_array) { CK_ULONG i; if (!attrs) return; for (i = 0; i < attrs_len; i++) if (attrs[i].pValue) { if (is_attribute_attr_array(attrs[i].type)) { __cleanse_and_free_attribute_array( (CK_ATTRIBUTE_PTR)attrs[i].pValue, attrs[i].ulValueLen / sizeof(CK_ATTRIBUTE), cleanse, TRUE); continue; } if (cleanse) OPENSSL_cleanse(attrs[i].pValue, attrs[i].ulValueLen); free(attrs[i].pValue); } if (free_array) 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, TRUE); } /* * Free an array of attributes allocated with dup_attribute_array() and cleanse * all attribute values. */ void cleanse_and_free_attribute_array2(CK_ATTRIBUTE_PTR attrs, CK_ULONG attrs_len, CK_BBOOL free_array) { __cleanse_and_free_attribute_array(attrs, attrs_len, TRUE, free_array); } /* * 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, TRUE); } /* * Duplicate an array of attributes and all its values. * The array itself must have been allocated by the caller, and must be the * same size as the original array. * * The returned array must be freed with free_attribute_array(). */ CK_RV dup_attribute_array_no_alloc(CK_ATTRIBUTE_PTR orig, CK_ULONG num_attrs, CK_ATTRIBUTE_PTR dest) { CK_RV rc = CKR_OK; CK_ATTRIBUTE_PTR it; memset(dest, 0, num_attrs * sizeof(CK_ATTRIBUTE)); /* Copy each element */ for (it = dest; it != (dest + num_attrs); it++, orig++) { it->type = orig->type; it->ulValueLen = orig->ulValueLen; if (it->ulValueLen > 0) { if (is_attribute_attr_array(it->type)) { rc = dup_attribute_array((CK_ATTRIBUTE_PTR)orig->pValue, orig->ulValueLen / sizeof(CK_ATTRIBUTE), (CK_ATTRIBUTE_PTR *)&it->pValue, &it->ulValueLen); if (rc != CKR_OK) goto done; it->ulValueLen *= sizeof(CK_ATTRIBUTE); } else { 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); } } else { it->pValue = NULL; } } done: if (rc != CKR_OK) __cleanse_and_free_attribute_array(dest, num_attrs, TRUE, FALSE); return rc; } /* * 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; if (orig == NULL || orig_len == 0) { *p_dest = NULL; *p_dest_len = 0; return CKR_OK; } /* 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; } rc = dup_attribute_array_no_alloc(orig, orig_len, dest); if (rc != CKR_OK) { free(dest); return rc; } *p_dest = dest; *p_dest_len = dest_len; return CKR_OK; } /* * 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; if (attrs == NULL || attrs_len == 0) return NULL; for (it = attrs; it != attrs + attrs_len; it++) if (it->type == type) return it; return NULL; } /* * Return the ULONG attribute value for a given type */ CK_RV get_ulong_attribute_by_type(CK_ATTRIBUTE_PTR attrs, CK_ULONG attrs_len, CK_ULONG type, CK_ULONG *value) { CK_ATTRIBUTE_PTR attr; attr = get_attribute_by_type(attrs, attrs_len, type); if (attr == NULL) return CKR_TEMPLATE_INCOMPLETE; if (attr->ulValueLen != sizeof(CK_ULONG) || attr->pValue == NULL) { TRACE_ERROR("%s: %lx\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID), type); return CKR_ATTRIBUTE_VALUE_INVALID; } *value = *(CK_ULONG *)attr->pValue; return CKR_OK; } /* * Return the BOOL attribute value for a given type */ CK_RV get_bool_attribute_by_type(CK_ATTRIBUTE_PTR attrs, CK_ULONG attrs_len, CK_ULONG type, CK_BBOOL *value) { CK_ATTRIBUTE_PTR attr; attr = get_attribute_by_type(attrs, attrs_len, type); if (attr == NULL) return CKR_TEMPLATE_INCOMPLETE; if (attr->ulValueLen != sizeof(CK_BBOOL) || attr->pValue == NULL) { TRACE_ERROR("%s: %lx\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID), type); return CKR_ATTRIBUTE_VALUE_INVALID; } *value = *(CK_BBOOL *)attr->pValue; return CKR_OK; } /* * 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 = NULL; CK_RV rc; if (value_len > 0) { if (is_attribute_attr_array(type)) { rc = dup_attribute_array((CK_ATTRIBUTE_PTR)value, value_len / sizeof(CK_ATTRIBUTE), (CK_ATTRIBUTE_PTR *)&copied_value, &value_len); if (rc != CKR_OK) return rc; value_len *= sizeof(CK_ATTRIBUTE); } else { 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) { if (is_attribute_attr_array(type)) free_attribute_array((CK_ATTRIBUTE_PTR)copied_value, value_len / sizeof(CK_ATTRIBUTE)); else 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; } CK_BBOOL compare_attribute(CK_ATTRIBUTE_PTR a1, CK_ATTRIBUTE_PTR a2) { if (a1->type != a2->type) return FALSE; if (a1->ulValueLen != a2->ulValueLen) return FALSE; if (a1->ulValueLen == 0) return TRUE; if (a1->pValue == NULL || a2->pValue == NULL) return FALSE; if (is_attribute_attr_array(a1->type)) { if (!compare_attribute_array((CK_ATTRIBUTE_PTR)a1->pValue, a1->ulValueLen / sizeof(CK_ATTRIBUTE), (CK_ATTRIBUTE_PTR)a2->pValue, a2->ulValueLen / sizeof(CK_ATTRIBUTE))) return FALSE; } else { if (memcmp(a1->pValue, a2->pValue, a1->ulValueLen) != 0) return FALSE; } return TRUE; } /* * Compares two attribute arrays. Returns true if a1 and a2 contain the same * attributes. The order of the attributes does not care. */ CK_BBOOL compare_attribute_array(CK_ATTRIBUTE_PTR a1, CK_ULONG a1_len, CK_ATTRIBUTE_PTR a2, CK_ULONG a2_len) { CK_ATTRIBUTE_PTR attr; CK_ULONG i; if (a1_len != a2_len) return FALSE; if (a1_len == 0) return TRUE; if (a1 == NULL || a2 == NULL) return FALSE; for (i = 0; i < a1_len; i++) { attr = get_attribute_by_type(a2, a2_len, a1[i].type); if (attr == NULL) return FALSE; if (!compare_attribute(&a1[i], attr)) return FALSE; } return TRUE; } CK_RV validate_attribute_array(CK_ATTRIBUTE_PTR attrs, CK_ULONG num_attrs) { CK_ULONG i; CK_RV rc; if (num_attrs > 0 && attrs == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } for (i = 0; i < num_attrs; i++) { if (!is_attribute_defined(attrs[i].type)) { TRACE_ERROR("%s: element %lu\n", ock_err(ERR_ATTRIBUTE_TYPE_INVALID), i); return CKR_ATTRIBUTE_TYPE_INVALID; } if (attrs[i].ulValueLen > 0 && attrs[i].pValue == NULL) { TRACE_ERROR("%s: element %lu\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID), i); return CKR_ATTRIBUTE_VALUE_INVALID; } if (is_attribute_attr_array(attrs[i].type)) { if (attrs[i].ulValueLen % sizeof(CK_ATTRIBUTE)) { TRACE_ERROR("%s: element %lu\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID), i); return CKR_ATTRIBUTE_VALUE_INVALID; } rc = validate_attribute_array((CK_ATTRIBUTE_PTR)attrs[i].pValue, attrs[i].ulValueLen / sizeof(CK_ATTRIBUTE)); if (rc != CKR_OK) { TRACE_ERROR("validate_attribute_array rc=0x%lx: element %lu\n", rc, i); return rc; } } } return CKR_OK; } #ifdef DEBUG void dump_array_attr(CK_ATTRIBUTE_PTR a) { CK_ATTRIBUTE_PTR attrs; CK_ULONG num_attrs, i; const char *typestr = p11_get_cka(a->type); attrs = (CK_ATTRIBUTE_PTR)a->pValue; num_attrs = a->ulValueLen / sizeof(CK_ATTRIBUTE); TRACE_DEBUG(" %s: begin array: num_elements=%lu\n", typestr, num_attrs); for (i = 0; i < num_attrs; i++) dump_attr(&attrs[i]); TRACE_DEBUG(" %s: end array\n", p11_get_cka(a->type)); } void dump_attr(CK_ATTRIBUTE_PTR a) { const char *typestr; if (is_attribute_attr_array(a->type)) { dump_array_attr(a); return; } typestr = p11_get_cka(a->type); switch (a->ulValueLen) { case 0: TRACE_DEBUG(" %s: len=0 pValue=%p\n", typestr, a->pValue); break; case 1: TRACE_DEBUG(" %s: len=%lu value=0x%02hhx\n", typestr, a->ulValueLen, *((uint8_t *)(a->pValue))); break; case 2: TRACE_DEBUG(" %s: len=%lu value=0x%04hx\n", typestr, a->ulValueLen, *((uint16_t *)(a->pValue))); break; case 4: TRACE_DEBUG(" %s: len=%lu value=0x%08x\n", typestr, a->ulValueLen, *((uint32_t *)(a->pValue))); break; case 8: TRACE_DEBUG(" %s: len=%lu value=0x%016lx\n", typestr, a->ulValueLen, *((uint64_t *)(a->pValue))); break; default: TRACE_DEBUG(" %s: len=%lu value:\n", typestr, a->ulValueLen); TRACE_DEBUG_DUMP(" ", a->pValue, a->ulValueLen); break; } } #endif opencryptoki-opencryptoki-451d99c/usr/lib/common/attributes.h000066400000000000000000000045371520105705100245430ustar00rootroot00000000000000/* * 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); void cleanse_and_free_attribute_array2(CK_ATTRIBUTE_PTR attrs, CK_ULONG attrs_len, CK_BBOOL free_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 dup_attribute_array_no_alloc(CK_ATTRIBUTE_PTR orig, CK_ULONG num_attrs, CK_ATTRIBUTE_PTR dest); CK_ATTRIBUTE_PTR get_attribute_by_type(CK_ATTRIBUTE_PTR attrs, CK_ULONG attrs_len, CK_ULONG type); CK_RV get_ulong_attribute_by_type(CK_ATTRIBUTE_PTR attrs, CK_ULONG attrs_len, CK_ULONG type, CK_ULONG *value); CK_RV get_bool_attribute_by_type(CK_ATTRIBUTE_PTR attrs, CK_ULONG attrs_len, CK_ULONG type, CK_BBOOL *value); 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_BBOOL compare_attribute(CK_ATTRIBUTE_PTR a1, CK_ATTRIBUTE_PTR a2); CK_BBOOL compare_attribute_array(CK_ATTRIBUTE_PTR a1, CK_ULONG a1_len, CK_ATTRIBUTE_PTR a2, CK_ULONG a2_len); CK_RV validate_attribute_array(CK_ATTRIBUTE_PTR attrs, CK_ULONG num_attrs); #ifdef DEBUG /* Debug function: dump one attribute */ void dump_attr(CK_ATTRIBUTE_PTR a); #define TRACE_DEBUG_DUMPATTR(x) dump_attr(x) #else #define TRACE_DEBUG_DUMPATTR(...) #endif #endif opencryptoki-opencryptoki-451d99c/usr/lib/common/btree.c000066400000000000000000000324021520105705100234410ustar00rootroot00000000000000/* * 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 #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(). */ CK_RV bt_init(struct btree *t, void (*delete_func)(void *)) { pthread_mutexattr_t attr; t->free_list = NULL; t->top = NULL; t->size = 0; t->free_nodes = 0; t->delete_func = delete_func; /* * Need a recursive mutex, because btree callback functions may call * btree functions again */ if (pthread_mutexattr_init(&attr) != 0) { TRACE_ERROR("pthread_mutexattr_init failed.\n"); return CKR_CANT_LOCK; } if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) != 0) { TRACE_ERROR("pthread_mutexattr_settype failed.\n"); return CKR_CANT_LOCK; } if (pthread_mutex_init(&t->mutex, &attr) != 0) { TRACE_ERROR("pthread_mutex_init failed.\n"); return CKR_CANT_LOCK; } return CKR_OK; } opencryptoki-opencryptoki-451d99c/usr/lib/common/buffer.c000066400000000000000000000051561520105705100236170ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2022 * * This program is provided under the terms of the Common Public License, * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this * software constitutes recipient's acceptance of CPL-1.0 terms which can be * found in the file LICENSE file or at * https://opensource.org/licenses/cpl1.0.php */ #include #include #include #include #include "platform.h" #include "buffer.h" #define BUFFER_INIT_SIZE (128ul) struct _buffer { size_t b_size; char *b; }; p11_buffer_t *p11_buffer_new(void) { p11_buffer_t *ret = malloc(sizeof(p11_buffer_t)); if (ret == NULL) goto err; ret->b_size = BUFFER_INIT_SIZE; ret->b = calloc(BUFFER_INIT_SIZE, sizeof(char)); if (ret->b == NULL) goto err_free; return ret; err_free: free(ret); err: return NULL; } void p11_buffer_free(p11_buffer_t *buf) { free(buf->b); free(buf); } void p11_buffer_reset(p11_buffer_t *buf) { memset(buf->b, 0, buf->b_size); } const char *p11_buffer_char(const p11_buffer_t *buf) { return (const char *) buf->b; } size_t p11_buffer_size(const p11_buffer_t *buf) { return buf->b_size; } long p11_buffer_append_len(p11_buffer_t *buf, const char *s, size_t len) { size_t new_len = strlen(buf->b) + len; char *b_end; if (!s || (len == 0)) return strlen(buf->b); /* extend buffer if required */ if ((new_len + 1) > buf->b_size) { size_t new_b_size = (((new_len + 1) / BUFFER_INIT_SIZE) + 1) * BUFFER_INIT_SIZE; char *new_b = realloc(buf->b, new_b_size); /* ENOMEM */ if (new_b == NULL) return -1; buf->b = new_b; buf->b_size = new_b_size; } /* * workaround: the obvious way to concatenate buf->b and s with * strncat(buf->b, s, len) is insecure, therefore do it manually. */ /* copy len bytes to the end of buf->b */ b_end = buf->b + strnlen(buf->b, buf->b_size); memcpy(b_end, s, len); /* terminate with \0 */ b_end += len; *b_end = '\0'; return new_len; } long p11_buffer_append(p11_buffer_t *buf, const char *s) { if (!s) return strlen(buf->b); return p11_buffer_append_len(buf, s, strlen(s)); } long p11_buffer_append_printf(p11_buffer_t *buf, const char *fmt, ...) { va_list ap; int len, rc = 0; char *tmp = NULL; va_start(ap, fmt); len = vasprintf(&tmp, fmt, ap); va_end(ap); if (len < 0) goto err; rc = p11_buffer_append_len(buf, tmp, len); err: free(tmp); return rc; } opencryptoki-opencryptoki-451d99c/usr/lib/common/buffer.h000066400000000000000000000016751520105705100236260ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2022 * * This program is provided under the terms of the Common Public License, * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this * software constitutes recipient's acceptance of CPL-1.0 terms which can be * found in the file LICENSE file or at * https://opensource.org/licenses/cpl1.0.php */ #ifndef __BUFFER_H #define __BUFFER_H #include typedef struct _buffer p11_buffer_t; p11_buffer_t *p11_buffer_new(void); void p11_buffer_free(p11_buffer_t *buf); void p11_buffer_reset(p11_buffer_t *buf); const char *p11_buffer_char(const p11_buffer_t *buf); size_t p11_buffer_size(const p11_buffer_t *buf); long p11_buffer_append_len(p11_buffer_t *buf, const char *s, size_t len); long p11_buffer_append(p11_buffer_t *buf, const char *s); long p11_buffer_append_printf(p11_buffer_t *buf, const char *fmt, ...); #endif /* __BUFFER_H */ opencryptoki-opencryptoki-451d99c/usr/lib/common/cert.c000066400000000000000000000435131520105705100233020ustar00rootroot00000000000000/* * 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_ULONG val; CK_RV rc; if (!tmpl) return CKR_FUNCTION_FAILED; if (mode == MODE_CREATE) { rc = template_attribute_get_ulong(tmpl, CKA_CERTIFICATE_TYPE, &val); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CERTIFICATE_TYPE\n"); return rc; } // don't bother checking the value. it was checked in the 'validate' // routine. } return template_check_required_base_attributes(tmpl, mode); } // cert_set_default_attributes() // // Set the default attributes for X.509 certificates // // CKA_TRUSTED : FALSE // CKA_CERTIFICATE_CATEGORY : CK_CERTIFICATE_CATEGORY_UNSPECIFIED // CKA_CHECK_VALUE : empty byte array // CKA_START_DATE : empty CK_DATE // CKA_END_DATE : empty CK_DATE // CKA_PUBLIC_KEY_INFO : empty byte array // CK_RV cert_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) { CK_ATTRIBUTE *trusted_attr = NULL; CK_ATTRIBUTE *category_attr = NULL; CK_ATTRIBUTE *chkval_attr = NULL; CK_ATTRIBUTE *start_attr = NULL; CK_ATTRIBUTE *end_attr = NULL; CK_ATTRIBUTE *pki_attr = NULL; CK_RV rc; UNUSED(mode); trusted_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); category_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_CERTIFICATE_CATEGORY)); chkval_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); start_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); end_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); pki_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); if (!trusted_attr || !category_attr || !chkval_attr || !start_attr || !end_attr || !pki_attr) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto error; } trusted_attr->type = CKA_TRUSTED; trusted_attr->ulValueLen = sizeof(CK_BBOOL); trusted_attr->pValue = (CK_BYTE *)trusted_attr + sizeof(CK_ATTRIBUTE); *(CK_BBOOL *) trusted_attr->pValue = FALSE; category_attr->type = CKA_CERTIFICATE_CATEGORY; category_attr->ulValueLen = sizeof(CK_CERTIFICATE_CATEGORY); category_attr->pValue = (CK_BYTE *)category_attr + sizeof(CK_ATTRIBUTE); *(CK_CERTIFICATE_CATEGORY *) category_attr->pValue = CK_CERTIFICATE_CATEGORY_UNSPECIFIED; chkval_attr->type = CKA_CHECK_VALUE; chkval_attr->ulValueLen = 0; // empty byte array chkval_attr->pValue = NULL; start_attr->type = CKA_START_DATE; start_attr->ulValueLen = 0; // empty CK_DATE start_attr->pValue = NULL; end_attr->type = CKA_END_DATE; end_attr->ulValueLen = 0; // empty CK_DATE end_attr->pValue = NULL; pki_attr->type = CKA_PUBLIC_KEY_INFO; pki_attr->ulValueLen = 0; // empty byte array pki_attr->pValue = NULL; rc = template_update_attribute(tmpl, trusted_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); goto error; } trusted_attr = NULL; rc = template_update_attribute(tmpl, category_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); goto error; } category_attr = NULL; rc = template_update_attribute(tmpl, chkval_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); goto error; } chkval_attr = NULL; rc = template_update_attribute(tmpl, start_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); goto error; } start_attr = NULL; rc = template_update_attribute(tmpl, end_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); goto error; } end_attr = NULL; rc = template_update_attribute(tmpl, pki_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); goto error; } pki_attr = NULL; return CKR_OK; error: if (trusted_attr != NULL) free(trusted_attr); if (category_attr != NULL) free(category_attr); if (chkval_attr != NULL) free(chkval_attr); if (start_attr != NULL) free(start_attr); if (end_attr != NULL) free(end_attr); if (pki_attr != NULL) free(pki_attr); return rc; } // cert_validate_attribute() // CK_RV cert_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_ATTRIBUTE *attr, CK_ULONG mode) { CK_CERTIFICATE_TYPE type; CK_CERTIFICATE_CATEGORY category; 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; } if (attr->ulValueLen != sizeof(CK_CERTIFICATE_TYPE) || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } 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; case CKA_TRUSTED: /* Can only be set to CK_TRUE by the SO user */ if (attr->ulValueLen != sizeof(CK_BBOOL) || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } if (*((CK_BBOOL *)attr->pValue) == CK_TRUE && !session_mgr_so_session_exists(tokdata)) { return CKR_USER_NOT_LOGGED_IN; } return CKR_OK; case CKA_CERTIFICATE_CATEGORY: if (attr->ulValueLen != sizeof(CK_CERTIFICATE_CATEGORY) || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } category = *(CK_CERTIFICATE_CATEGORY *) attr->pValue; switch (category) { case CK_CERTIFICATE_CATEGORY_UNSPECIFIED: case CK_CERTIFICATE_CATEGORY_TOKEN_USER: case CK_CERTIFICATE_CATEGORY_AUTHORITY: case CK_CERTIFICATE_CATEGORY_OTHER_ENTITY: return CKR_OK; default: TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } case CKA_CHECK_VALUE: case CKA_START_DATE: case CKA_END_DATE: case CKA_PUBLIC_KEY_INFO: return CKR_OK; 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_RV rc; rc = template_attribute_get_non_empty(tmpl, CKA_SUBJECT, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_SUBJECT\n"); return rc; } rc = template_attribute_get_non_empty(tmpl, CKA_URL, &attr); if (rc != CKR_OK) { /* CKA_VALUE MUST be non-empty if CKA_URL is empty or not specified */ rc = template_attribute_get_non_empty(tmpl, CKA_VALUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE\n"); return rc; } } else { /* Hashes can only be empty if CKA_URL is empty */ rc = template_attribute_get_non_empty(tmpl, CKA_HASH_OF_SUBJECT_PUBLIC_KEY, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_HASH_OF_SUBJECT_PUBLIC_KEY\n"); return rc; } rc = template_attribute_get_non_empty(tmpl, CKA_HASH_OF_ISSUER_PUBLIC_KEY, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_HASH_OF_ISSUER_PUBLIC_KEY\n"); return rc; } } 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 // CKA_URL : empty string // CKA_HASH_OF_SUBJECT_PUBLIC_KEY : empty string // CKA_HASH_OF_ISSUER_PUBLIC_KEY : empty string // CKA_JAVA_MIDP_SECURITY_DOMAIN : CK_SECURITY_DOMAIN_UNSPECIFIED // CKA_NAME_HASH_ALGORITHM : CKM_SHA1 // 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; CK_ATTRIBUTE *url_attr = NULL; CK_ATTRIBUTE *subject_hash_attr = NULL; CK_ATTRIBUTE *issuer_hash_attr = NULL; CK_ATTRIBUTE *sec_domain_attr = NULL; CK_ATTRIBUTE *hash_mech_attr = NULL; CK_RV rc; rc = cert_set_default_attributes(tmpl, mode); if (rc != CKR_OK) { TRACE_DEVEL("cert_set_default_attributes failed\n"); return rc; } id_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); issuer_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); serial_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); url_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); subject_hash_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); issuer_hash_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); sec_domain_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_JAVA_MIDP_SECURITY_DOMAIN)); hash_mech_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_MECHANISM_TYPE)); if (!id_attr || !issuer_attr || !serial_attr || !url_attr || !subject_hash_attr || !issuer_hash_attr || !sec_domain_attr || !hash_mech_attr) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto error; } 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; url_attr->type = CKA_URL; url_attr->ulValueLen = 0; // empty byte array url_attr->pValue = NULL; subject_hash_attr->type = CKA_HASH_OF_SUBJECT_PUBLIC_KEY; subject_hash_attr->ulValueLen = 0; // empty byte array subject_hash_attr->pValue = NULL; issuer_hash_attr->type = CKA_HASH_OF_ISSUER_PUBLIC_KEY; issuer_hash_attr->ulValueLen = 0; // empty byte array issuer_hash_attr->pValue = NULL; sec_domain_attr->type = CKA_JAVA_MIDP_SECURITY_DOMAIN; sec_domain_attr->ulValueLen = sizeof(CK_JAVA_MIDP_SECURITY_DOMAIN); sec_domain_attr->pValue = (CK_BYTE *)sec_domain_attr + sizeof(CK_ATTRIBUTE); *(CK_JAVA_MIDP_SECURITY_DOMAIN *) sec_domain_attr->pValue = CK_SECURITY_DOMAIN_UNSPECIFIED; hash_mech_attr->type = CKA_NAME_HASH_ALGORITHM; hash_mech_attr->ulValueLen = sizeof(CK_MECHANISM_TYPE); hash_mech_attr->pValue = (CK_BYTE *)hash_mech_attr + sizeof(CK_ATTRIBUTE); *(CK_MECHANISM_TYPE *) hash_mech_attr->pValue = CKM_SHA_1; rc = template_update_attribute(tmpl, id_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); goto error; } id_attr = NULL; rc = template_update_attribute(tmpl, issuer_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); goto error; } issuer_attr = NULL; rc = template_update_attribute(tmpl, serial_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); goto error; } serial_attr = NULL; rc = template_update_attribute(tmpl, url_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); goto error; } url_attr = NULL; rc = template_update_attribute(tmpl, subject_hash_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); goto error; } subject_hash_attr = NULL; rc = template_update_attribute(tmpl, issuer_hash_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); goto error; } issuer_hash_attr = NULL; rc = template_update_attribute(tmpl, sec_domain_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); goto error; } sec_domain_attr = NULL; rc = template_update_attribute(tmpl, hash_mech_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); goto error; } hash_mech_attr = NULL; return CKR_OK; error: if (id_attr) free(id_attr); if (issuer_attr) free(issuer_attr); if (serial_attr) free(serial_attr); if (url_attr) free(url_attr); if (subject_hash_attr) free(subject_hash_attr); if (issuer_hash_attr) free(issuer_hash_attr); if (sec_domain_attr) free(sec_domain_attr); if (hash_mech_attr) free(hash_mech_attr); return rc; } // cert_x509_validate_attributes() // CK_RV cert_x509_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_ATTRIBUTE *attr, CK_ULONG mode) { CK_JAVA_MIDP_SECURITY_DOMAIN sec_domain; 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; case CKA_URL: if (mode != MODE_CREATE) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); return CKR_ATTRIBUTE_READ_ONLY; } return CKR_OK; case CKA_HASH_OF_SUBJECT_PUBLIC_KEY: if (mode != MODE_CREATE) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); return CKR_ATTRIBUTE_READ_ONLY; } return CKR_OK; case CKA_HASH_OF_ISSUER_PUBLIC_KEY: if (mode != MODE_CREATE) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); return CKR_ATTRIBUTE_READ_ONLY; } return CKR_OK; case CKA_JAVA_MIDP_SECURITY_DOMAIN: if (mode != MODE_CREATE) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); return CKR_ATTRIBUTE_READ_ONLY; } if (attr->ulValueLen != sizeof(CK_JAVA_MIDP_SECURITY_DOMAIN) || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } sec_domain = *(CK_CERTIFICATE_CATEGORY *) attr->pValue; switch (sec_domain) { case CK_SECURITY_DOMAIN_UNSPECIFIED: case CK_SECURITY_DOMAIN_MANUFACTURER: case CK_SECURITY_DOMAIN_OPERATOR: case CK_SECURITY_DOMAIN_THIRD_PARTY: return CKR_OK; default: TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } case CKA_NAME_HASH_ALGORITHM: if (mode != MODE_CREATE) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); return CKR_ATTRIBUTE_READ_ONLY; } if (attr->ulValueLen != sizeof(CK_MECHANISM_TYPE) || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } return CKR_OK; default: return cert_validate_attribute(tokdata, 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(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_ATTRIBUTE *attr, CK_ULONG mode) { // cryptoki specifies no attributes for CKC_VENDOR certificates // return cert_validate_attribute(tokdata, tmpl, attr, mode); } opencryptoki-opencryptoki-451d99c/usr/lib/common/common.mk000066400000000000000000000016411520105705100240160ustar00rootroot00000000000000noinst_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/event_client.h \ usr/lib/common/list.h usr/lib/common/tok_specific.h \ usr/lib/common/uri_enc.h usr/lib/common/uri.h \ usr/lib/common/buffer.h usr/lib/common/pin_prompt.h \ usr/lib/common/pqc_defs.h usr/lib/common/constant_time.h \ usr/lib/common/dlist.h usr/lib/common/p11util.h \ usr/lib/common/pkcs_utils.h usr/lib/common/pkey_utils.h \ usr/lib/common/stringtranslations.h usr/lib/common/aix/asprintf.h \ usr/lib/common/aix/endian.h usr/lib/common/aix/err.h \ usr/lib/common/aix/getopt.h usr/lib/common/aix/secure_getenv.h \ usr/lib/common/platform.h opencryptoki-opencryptoki-451d99c/usr/lib/common/constant_time.h000066400000000000000000000314421520105705100252170ustar00rootroot00000000000000/* * Copyright 2014-2021 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html * * Copied from OpenSSL include/internal/constant_time.h * The only changes are to add this notice. */ #ifndef OSSL_INTERNAL_CONSTANT_TIME_H # define OSSL_INTERNAL_CONSTANT_TIME_H # pragma once # include # include # include /* For 'ossl_inline' */ /*- * The boolean methods return a bitmask of all ones (0xff...f) for true * and 0 for false. This is useful for choosing a value based on the result * of a conditional in constant time. For example, * if (a < b) { * c = a; * } else { * c = b; * } * can be written as * unsigned int lt = constant_time_lt(a, b); * c = constant_time_select(lt, a, b); */ /* Returns the given value with the MSB copied to all the other bits. */ static ossl_inline unsigned int constant_time_msb(unsigned int a); /* Convenience method for uint32_t. */ static ossl_inline uint32_t constant_time_msb_32(uint32_t a); /* Convenience method for uint64_t. */ static ossl_inline uint64_t constant_time_msb_64(uint64_t a); /* Returns 0xff..f if a < b and 0 otherwise. */ static ossl_inline unsigned int constant_time_lt(unsigned int a, unsigned int b); /* Convenience method for getting an 8-bit mask. */ static ossl_inline unsigned char constant_time_lt_8(unsigned int a, unsigned int b); /* Convenience method for uint64_t. */ static ossl_inline uint64_t constant_time_lt_64(uint64_t a, uint64_t b); /* Returns 0xff..f if a >= b and 0 otherwise. */ static ossl_inline unsigned int constant_time_ge(unsigned int a, unsigned int b); /* Convenience method for getting an 8-bit mask. */ static ossl_inline unsigned char constant_time_ge_8(unsigned int a, unsigned int b); /* Returns 0xff..f if a == 0 and 0 otherwise. */ static ossl_inline unsigned int constant_time_is_zero(unsigned int a); /* Convenience method for getting an 8-bit mask. */ static ossl_inline unsigned char constant_time_is_zero_8(unsigned int a); /* Convenience method for getting a 32-bit mask. */ static ossl_inline uint32_t constant_time_is_zero_32(uint32_t a); /* Returns 0xff..f if a == b and 0 otherwise. */ static ossl_inline unsigned int constant_time_eq(unsigned int a, unsigned int b); /* Convenience method for getting an 8-bit mask. */ static ossl_inline unsigned char constant_time_eq_8(unsigned int a, unsigned int b); /* Signed integers. */ static ossl_inline unsigned int constant_time_eq_int(int a, int b); /* Convenience method for getting an 8-bit mask. */ static ossl_inline unsigned char constant_time_eq_int_8(int a, int b); /*- * Returns (mask & a) | (~mask & b). * * When |mask| is all 1s or all 0s (as returned by the methods above), * the select methods return either |a| (if |mask| is nonzero) or |b| * (if |mask| is zero). */ static ossl_inline unsigned int constant_time_select(unsigned int mask, unsigned int a, unsigned int b); /* Convenience method for unsigned chars. */ static ossl_inline unsigned char constant_time_select_8(unsigned char mask, unsigned char a, unsigned char b); /* Convenience method for uint32_t. */ static ossl_inline uint32_t constant_time_select_32(uint32_t mask, uint32_t a, uint32_t b); /* Convenience method for uint64_t. */ static ossl_inline uint64_t constant_time_select_64(uint64_t mask, uint64_t a, uint64_t b); /* Convenience method for signed integers. */ static ossl_inline int constant_time_select_int(unsigned int mask, int a, int b); static ossl_inline unsigned int constant_time_msb(unsigned int a) { return 0 - (a >> (sizeof(a) * 8 - 1)); } static ossl_inline uint32_t constant_time_msb_32(uint32_t a) { return 0 - (a >> 31); } static ossl_inline uint64_t constant_time_msb_64(uint64_t a) { return 0 - (a >> 63); } static ossl_inline size_t constant_time_msb_s(size_t a) { return 0 - (a >> (sizeof(a) * 8 - 1)); } static ossl_inline unsigned int constant_time_lt(unsigned int a, unsigned int b) { return constant_time_msb(a ^ ((a ^ b) | ((a - b) ^ b))); } static ossl_inline size_t constant_time_lt_s(size_t a, size_t b) { return constant_time_msb_s(a ^ ((a ^ b) | ((a - b) ^ b))); } static ossl_inline unsigned char constant_time_lt_8(unsigned int a, unsigned int b) { return (unsigned char)constant_time_lt(a, b); } static ossl_inline uint64_t constant_time_lt_64(uint64_t a, uint64_t b) { return constant_time_msb_64(a ^ ((a ^ b) | ((a - b) ^ b))); } static ossl_inline unsigned int constant_time_ge(unsigned int a, unsigned int b) { return ~constant_time_lt(a, b); } static ossl_inline size_t constant_time_ge_s(size_t a, size_t b) { return ~constant_time_lt_s(a, b); } static ossl_inline unsigned char constant_time_ge_8(unsigned int a, unsigned int b) { return (unsigned char)constant_time_ge(a, b); } static ossl_inline unsigned char constant_time_ge_8_s(size_t a, size_t b) { return (unsigned char)constant_time_ge_s(a, b); } static ossl_inline unsigned int constant_time_is_zero(unsigned int a) { return constant_time_msb(~a & (a - 1)); } static ossl_inline size_t constant_time_is_zero_s(size_t a) { return constant_time_msb_s(~a & (a - 1)); } static ossl_inline unsigned char constant_time_is_zero_8(unsigned int a) { return (unsigned char)constant_time_is_zero(a); } static ossl_inline uint32_t constant_time_is_zero_32(uint32_t a) { return constant_time_msb_32(~a & (a - 1)); } static ossl_inline uint64_t constant_time_is_zero_64(uint64_t a) { return constant_time_msb_64(~a & (a - 1)); } static ossl_inline unsigned int constant_time_eq(unsigned int a, unsigned int b) { return constant_time_is_zero(a ^ b); } static ossl_inline size_t constant_time_eq_s(size_t a, size_t b) { return constant_time_is_zero_s(a ^ b); } static ossl_inline unsigned char constant_time_eq_8(unsigned int a, unsigned int b) { return (unsigned char)constant_time_eq(a, b); } static ossl_inline unsigned char constant_time_eq_8_s(size_t a, size_t b) { return (unsigned char)constant_time_eq_s(a, b); } static ossl_inline unsigned int constant_time_eq_int(int a, int b) { return constant_time_eq((unsigned)(a), (unsigned)(b)); } static ossl_inline unsigned char constant_time_eq_int_8(int a, int b) { return constant_time_eq_8((unsigned)(a), (unsigned)(b)); } /* * Returns the value unmodified, but avoids optimizations. * The barriers prevent the compiler from narrowing down the * possible value range of the mask and ~mask in the select * statements, which avoids the recognition of the select * and turning it into a conditional load or branch. */ static ossl_inline unsigned int value_barrier(unsigned int a) { #if !defined(OPENSSL_NO_ASM) && defined(__GNUC__) unsigned int r; __asm__("" : "=r"(r) : "0"(a)); #else volatile unsigned int r = a; #endif return r; } /* Convenience method for uint32_t. */ static ossl_inline uint32_t value_barrier_32(uint32_t a) { #if !defined(OPENSSL_NO_ASM) && defined(__GNUC__) uint32_t r; __asm__("" : "=r"(r) : "0"(a)); #else volatile uint32_t r = a; #endif return r; } /* Convenience method for uint64_t. */ static ossl_inline uint64_t value_barrier_64(uint64_t a) { #if !defined(OPENSSL_NO_ASM) && defined(__GNUC__) uint64_t r; __asm__("" : "=r"(r) : "0"(a)); #else volatile uint64_t r = a; #endif return r; } /* Convenience method for size_t. */ static ossl_inline size_t value_barrier_s(size_t a) { #if !defined(OPENSSL_NO_ASM) && defined(__GNUC__) size_t r; __asm__("" : "=r"(r) : "0"(a)); #else volatile size_t r = a; #endif return r; } static ossl_inline unsigned int constant_time_select(unsigned int mask, unsigned int a, unsigned int b) { return (value_barrier(mask) & a) | (value_barrier(~mask) & b); } static ossl_inline size_t constant_time_select_s(size_t mask, size_t a, size_t b) { return (value_barrier_s(mask) & a) | (value_barrier_s(~mask) & b); } static ossl_inline unsigned char constant_time_select_8(unsigned char mask, unsigned char a, unsigned char b) { return (unsigned char)constant_time_select(mask, a, b); } static ossl_inline int constant_time_select_int(unsigned int mask, int a, int b) { return (int)constant_time_select(mask, (unsigned)(a), (unsigned)(b)); } static ossl_inline int constant_time_select_int_s(size_t mask, int a, int b) { return (int)constant_time_select((unsigned)mask, (unsigned)(a), (unsigned)(b)); } static ossl_inline uint32_t constant_time_select_32(uint32_t mask, uint32_t a, uint32_t b) { return (value_barrier_32(mask) & a) | (value_barrier_32(~mask) & b); } static ossl_inline uint64_t constant_time_select_64(uint64_t mask, uint64_t a, uint64_t b) { return (value_barrier_64(mask) & a) | (value_barrier_64(~mask) & b); } /* * mask must be 0xFFFFFFFF or 0x00000000. * * if (mask) { * uint32_t tmp = *a; * * *a = *b; * *b = tmp; * } */ static ossl_inline void constant_time_cond_swap_32(uint32_t mask, uint32_t *a, uint32_t *b) { uint32_t xor = *a ^ *b; xor &= mask; *a ^= xor; *b ^= xor; } /* * mask must be 0xFFFFFFFF or 0x00000000. * * if (mask) { * uint64_t tmp = *a; * * *a = *b; * *b = tmp; * } */ static ossl_inline void constant_time_cond_swap_64(uint64_t mask, uint64_t *a, uint64_t *b) { uint64_t xor = *a ^ *b; xor &= mask; *a ^= xor; *b ^= xor; } /* * mask must be 0xFF or 0x00. * "constant time" is per len. * * if (mask) { * unsigned char tmp[len]; * * memcpy(tmp, a, len); * memcpy(a, b); * memcpy(b, tmp); * } */ static ossl_inline void constant_time_cond_swap_buff(unsigned char mask, unsigned char *a, unsigned char *b, size_t len) { size_t i; unsigned char tmp; for (i = 0; i < len; i++) { tmp = a[i] ^ b[i]; tmp &= mask; a[i] ^= tmp; b[i] ^= tmp; } } /* * table is a two dimensional array of bytes. Each row has rowsize elements. * Copies row number idx into out. rowsize and numrows are not considered * private. */ static ossl_inline void constant_time_lookup(void *out, const void *table, size_t rowsize, size_t numrows, size_t idx) { size_t i, j; const unsigned char *tablec = (const unsigned char *)table; unsigned char *outc = (unsigned char *)out; unsigned char mask; memset(out, 0, rowsize); /* Note idx may underflow - but that is well defined */ for (i = 0; i < numrows; i++, idx--) { mask = (unsigned char)constant_time_is_zero_s(idx); for (j = 0; j < rowsize; j++) *(outc + j) |= constant_time_select_8(mask, *(tablec++), 0); } } /* * Expected usage pattern is to unconditionally set error and then * wipe it if there was no actual error. |clear| is 1 or 0. */ void err_clear_last_constant_time(int clear); #endif /* OSSL_INTERNAL_CONSTANT_TIME_H */ opencryptoki-opencryptoki-451d99c/usr/lib/common/data_obj.c000066400000000000000000000100731520105705100241030ustar00rootroot00000000000000/* * 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; CK_ATTRIBUTE *objid_attr = NULL; CK_RV rc; UNUSED(mode); // 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)); objid_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); if (!class_attr || !app_attr || !value_attr || !objid_attr) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto error; } 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; objid_attr->type = CKA_OBJECT_ID; objid_attr->ulValueLen = 0; // empty byte array objid_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; rc = template_update_attribute(tmpl, class_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); goto error; } class_attr = NULL; rc = template_update_attribute(tmpl, app_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); goto error; } app_attr = NULL; rc = template_update_attribute(tmpl, value_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); goto error; } value_attr = NULL; rc = template_update_attribute(tmpl, objid_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); goto error; } objid_attr = NULL; return CKR_OK; error: if (class_attr) free(class_attr); if (app_attr) free(app_attr); if (value_attr) free(value_attr); if (objid_attr) free(objid_attr); return rc; } // 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: case CKA_OBJECT_ID: if (mode == MODE_CREATE) return CKR_OK; return CKR_ATTRIBUTE_READ_ONLY; default: return template_validate_base_attribute(tmpl, attr, mode); } return CKR_OK; } opencryptoki-opencryptoki-451d99c/usr/lib/common/decr_mgr.c000066400000000000000000001327511520105705100241320ustar00rootroot00000000000000/* * 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" #include "p11util.h" #include "../api/policy.h" #include "../api/statistics.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, CK_BBOOL checkpolicy, CK_BBOOL checkauth) { OBJECT *key_obj = NULL; CK_BYTE *ptr = NULL; CK_KEY_TYPE keytype; CK_BBOOL flag; CK_RV rc; int policy_check; CK_ATTRIBUTE_TYPE key_usage_attr; CK_ULONG strength = POLICY_STRENGTH_IDX_0; CK_GCM_PARAMS gcm_params; CK_MECHANISM temp_mech; CK_ULONG aeskw_iv_len = AES_KEY_WRAP_KWP_IV_SIZE; 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; } switch (operation) { case OP_DECRYPT_INIT: key_usage_attr = CKA_DECRYPT; policy_check = POLICY_CHECK_DECRYPT; break; case OP_UNWRAP: key_usage_attr = CKA_UNWRAP; policy_check = POLICY_CHECK_UNWRAP; break; case OP_DECAPSULATE: key_usage_attr = CKA_DECAPSULATE; policy_check = POLICY_CHECK_DECAPS; break; default: TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto done; } /* key usage restrictions */ 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 operation == OP_UNWRAP ? CKR_WRAPPING_KEY_HANDLE_INVALID : CKR_KEY_HANDLE_INVALID; else return rc; } /* is key allowed to do the desired operation? */ rc = template_attribute_get_bool(key_obj->template, key_usage_attr, &flag); if (rc != CKR_OK) { TRACE_ERROR("Could not find %s for the key.\n", p11_get_cka(key_usage_attr)); rc = CKR_KEY_FUNCTION_NOT_PERMITTED; goto done; } if (flag != TRUE) { TRACE_ERROR("%s is set to FALSE.\n", p11_get_cka(key_usage_attr)); rc = CKR_KEY_FUNCTION_NOT_PERMITTED; goto done; } if (checkpolicy) { rc = tokdata->policy->is_mech_allowed(tokdata->policy, mech, &key_obj->strength, policy_check, sess); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: decrypt/unwrap init\n"); goto done; } } ctx->auth_required = FALSE; if (checkauth) { rc = key_object_is_always_authenticate(key_obj->template, &ctx->auth_required); if (rc != CKR_OK) { TRACE_ERROR("key_object_is_always_authenticate failed\n"); goto done; } } if (!key_object_is_mechanism_allowed(key_obj->template, mech->mechanism)) { TRACE_ERROR("Mechanism not allowed per CKA_ALLOWED_MECHANISMS.\n"); rc = CKR_MECHANISM_INVALID; 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_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } 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_CBC: case CKM_DES_CBC_PAD: if (mech->ulParameterLen != DES_BLOCK_SIZE || mech->pParameter == NULL) { 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_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } 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 || mech->pParameter == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } rc = template_attribute_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } 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_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } 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 || mech->pParameter == NULL) { 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_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } 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 != sizeof(CK_RSA_PKCS_OAEP_PARAMS) || mech->pParameter == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } rc = template_attribute_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } 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_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } 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_ECDH_AES_KEY_WRAP: case CKM_ECDH_COF_AES_KEY_WRAP: case CKM_ECDH_X_AES_KEY_WRAP: /* CKM_ECDH_AES_[COF_|X_]KEY_WRAP can only be used for wrap/unwrap */ if (operation != OP_UNWRAP) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); rc = CKR_MECHANISM_INVALID; goto done; } if (mech->ulParameterLen != sizeof(CK_ECDH_AES_KEY_WRAP_PARAMS) || mech->pParameter == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } rc = template_attribute_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } switch (mech->mechanism) { case CKM_ECDH_AES_KEY_WRAP: if (keytype != CKK_EC && keytype != CKK_EC_MONTGOMERY) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); rc = CKR_KEY_TYPE_INCONSISTENT; goto done; } break; case CKM_ECDH_COF_AES_KEY_WRAP: if (keytype != CKK_EC) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); rc = CKR_KEY_TYPE_INCONSISTENT; goto done; } break; case CKM_ECDH_X_AES_KEY_WRAP: if (keytype != CKK_EC_MONTGOMERY) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); rc = CKR_KEY_TYPE_INCONSISTENT; goto done; } break; default: TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); rc = CKR_MECHANISM_INVALID; goto done; } // cannot be used for multi-part operations // ctx->context_len = 0; ctx->context = NULL; break; case CKM_RSA_AES_KEY_WRAP: /* CKM_RSA_AES_KEY_WRAP can only be used for wrap/unwrap */ if (operation != OP_UNWRAP) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); rc = CKR_MECHANISM_INVALID; goto done; } if (mech->ulParameterLen != sizeof(CK_RSA_AES_KEY_WRAP_PARAMS) || mech->pParameter == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } rc = template_attribute_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } 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_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } 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 || mech->pParameter == NULL) { 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_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } 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) || mech->pParameter == NULL) { 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_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } 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) && mech->ulParameterLen != sizeof(CK_GCM_PARAMS_COMPAT)) || mech->pParameter == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } if (mech->ulParameterLen == sizeof(CK_GCM_PARAMS_COMPAT)) { aes_gcm_param_from_compat((CK_GCM_PARAMS_COMPAT *)mech->pParameter, &gcm_params); temp_mech.mechanism = mech->mechanism; temp_mech.pParameter = &gcm_params; temp_mech.ulParameterLen = sizeof(gcm_params); mech = &temp_mech; } rc = template_attribute_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } 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)); strength = key_obj->strength.strength; /* Release obj lock, token specific aes-gcm may re-acquire the lock */ object_put(tokdata, key_obj, TRUE); key_obj = NULL; 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 || mech->pParameter == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } rc = template_attribute_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } 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_XTS: if (mech->ulParameterLen != AES_INIT_VECTOR_SIZE || mech->pParameter == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } rc = template_attribute_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } if (keytype != CKK_AES_XTS) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); rc = CKR_KEY_TYPE_INCONSISTENT; goto done; } ctx->context_len = sizeof(AES_XTS_CONTEXT); ctx->context = (CK_BYTE *) malloc(sizeof(AES_XTS_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_XTS_CONTEXT)); break; case CKM_AES_KEY_WRAP: case CKM_AES_KEY_WRAP_PAD: case CKM_AES_KEY_WRAP_PKCS7: aeskw_iv_len = AES_KEY_WRAP_IV_SIZE; /* fallthrough */ case CKM_AES_KEY_WRAP_KWP: if ((mech->ulParameterLen != 0 && mech->pParameter == NULL) || (mech->ulParameterLen == 0 && mech->pParameter != NULL) || (mech->ulParameterLen != 0 && mech->ulParameterLen != aeskw_iv_len)) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } rc = template_attribute_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } if (keytype != CKK_AES) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); rc = CKR_KEY_TYPE_INCONSISTENT; goto done; } /* AES key wrap cannot be used for multi-part operations */ ctx->context_len = 0; ctx->context = NULL; break; default: TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_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); /* Deep copy mechanism parameter, if required */ switch (mech->mechanism) { case CKM_AES_GCM: rc = aes_gcm_dup_param((CK_GCM_PARAMS *)mech->pParameter, (CK_GCM_PARAMS *)ptr); if (rc != CKR_OK) { TRACE_ERROR("aes_gcm_dup_param failed\n"); free(ptr); goto done; } break; default: break; } } 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; ctx->pkey_active = FALSE; rc = CKR_OK; done: if (ctx->count_statistics == TRUE && rc == CKR_OK) INC_COUNTER(tokdata, sess, mech, key_obj, strength); object_put(tokdata, key_obj, TRUE); key_obj = NULL; return rc; } // // CK_RV decr_mgr_cleanup(STDLL_TokData_t *tokdata, SESSION *sess, ENCR_DECR_CONTEXT *ctx) { if (!ctx) { TRACE_ERROR("Invalid function argument.\n"); return CKR_FUNCTION_FAILED; } ctx->key = 0; ctx->multi_init = FALSE; ctx->multi = FALSE; ctx->active = FALSE; ctx->init_pending = FALSE; ctx->pkey_active = FALSE; ctx->state_unsaveable = FALSE; ctx->count_statistics = FALSE; ctx->auth_required = FALSE; if (ctx->mech.pParameter) { /* Deep free mechanism parameter, if required */ switch (ctx->mech.mechanism) { case CKM_AES_GCM: aes_gcm_free_param((CK_GCM_PARAMS *)ctx->mech.pParameter); break; default: break; } free(ctx->mech.pParameter); ctx->mech.pParameter = NULL; } ctx->mech.ulParameterLen = 0; ctx->mech.mechanism = 0; if (ctx->context) { if (ctx->context_free_func != NULL) ctx->context_free_func(tokdata, sess, ctx->context, ctx->context_len); else free(ctx->context); ctx->context = NULL; } ctx->context_len = 0; ctx->context_free_func = 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 = 0; 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->auth_required == TRUE) { TRACE_ERROR("%s\n", ock_err(ERR_USER_NOT_LOGGED_IN)); return CKR_USER_NOT_LOGGED_IN; } 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_DES_ECB: return des_ecb_decrypt(tokdata, sess, length_only, ctx, in_data, in_data_len, out_data, out_data_len); 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: 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); case CKM_ECDH_AES_KEY_WRAP: case CKM_ECDH_COF_AES_KEY_WRAP: case CKM_ECDH_X_AES_KEY_WRAP: return ecdh_aes_key_unwrap(tokdata, sess, length_only, ctx, in_data, in_data_len, out_data, out_data_len); case CKM_RSA_AES_KEY_WRAP: return rsa_aes_key_unwrap(tokdata, sess, length_only, ctx, in_data, in_data_len, out_data, out_data_len); 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); case CKM_AES_XTS: return aes_xts_decrypt(tokdata, sess, length_only, ctx, in_data, in_data_len, out_data, out_data_len); case CKM_AES_KEY_WRAP: case CKM_AES_KEY_WRAP_PAD: case CKM_AES_KEY_WRAP_KWP: case CKM_AES_KEY_WRAP_PKCS7: return aes_key_wrap_decrypt(tokdata, sess, length_only, ctx, in_data, in_data_len, out_data, out_data_len); 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 = 0; 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->auth_required == TRUE) { TRACE_ERROR("%s\n", ock_err(ERR_USER_NOT_LOGGED_IN)); return CKR_USER_NOT_LOGGED_IN; } 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_DES_ECB: return des_ecb_decrypt_update(tokdata, sess, length_only, ctx, in_data, in_data_len, out_data, out_data_len); 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: 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); 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); case CKM_AES_XTS: return aes_xts_decrypt_update(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_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 = 0; 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->auth_required == TRUE) { TRACE_ERROR("%s\n", ock_err(ERR_USER_NOT_LOGGED_IN)); return CKR_USER_NOT_LOGGED_IN; } 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_DES_ECB: return des_ecb_decrypt_final(tokdata, sess, length_only, ctx, out_data, out_data_len); case CKM_DES_CBC: return des_cbc_decrypt_final(tokdata, sess, length_only, ctx, out_data, out_data_len); case CKM_DES_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); 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); case CKM_AES_XTS: return aes_xts_decrypt_final(tokdata, sess, length_only, ctx, out_data, out_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; } opencryptoki-opencryptoki-451d99c/usr/lib/common/defs.h000066400000000000000000000117001520105705100232640ustar00rootroot00000000000000/* * 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 #include #ifndef OPENSSL_VERSION_PREREQ #if defined(OPENSSL_VERSION_MAJOR) && defined(OPENSSL_VERSION_MINOR) #define OPENSSL_VERSION_PREREQ(maj, min) \ ((OPENSSL_VERSION_MAJOR << 16) + \ OPENSSL_VERSION_MINOR >= ((maj) << 16) + (min)) #else #define OPENSSL_VERSION_PREREQ(maj, min) \ (OPENSSL_VERSION_NUMBER >= (((maj) << 28) | \ ((min) << 20))) #endif #endif #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) #define MODE_UNWRAPPED (1 << 6) #define MODE_ENCAPS (1 << 7) #define MODE_DECAPS (1 << 8) #define MODE_EXTRACT (1 << 9) // 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 #define OP_ENCAPSULATE 7 #define OP_DECAPSULATE 8 #define OP_KEYGEN 9 #define OP_DERIVE 10 // 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 (OPENSSL_RSA_MAX_MODULUS_BITS / 8) #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 AES_KEY_WRAP_BLOCK_SIZE 8 #define AES_KEY_WRAP_IV_SIZE AES_KEY_WRAP_BLOCK_SIZE #define AES_KEY_WRAP_KWP_IV_SIZE 4 #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 SHA224_HASH_SIZE 28 #define SHA224_BLOCK_SIZE 64 #define SHA256_HASH_SIZE 32 #define SHA256_BLOCK_SIZE 64 #define SHA384_HASH_SIZE 48 #define SHA384_BLOCK_SIZE 128 #define SHA512_HASH_SIZE 64 #define SHA512_BLOCK_SIZE 128 #define SHA3_224_HASH_SIZE SHA224_HASH_SIZE #define SHA3_224_BLOCK_SIZE 144 #define SHA3_256_HASH_SIZE SHA256_HASH_SIZE #define SHA3_256_BLOCK_SIZE 136 #define SHA3_384_HASH_SIZE SHA384_HASH_SIZE #define SHA3_384_BLOCK_SIZE 104 #define SHA3_512_HASH_SIZE SHA512_HASH_SIZE #define SHA3_512_BLOCK_SIZE 72 #define SHAKE128_BLOCK_SIZE 168 #define SHAKE256_BLOCK_SIZE 136 #define MAX_SHA_HASH_SIZE SHA512_HASH_SIZE #define MAX_SHA_BLOCK_SIZE SHAKE128_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; }; #if !(NOMD2) #define MD2_HASH_SIZE 16 #define MD2_BLOCK_SIZE 48 #endif #define MD5_HASH_SIZE 16 #define MD5_BLOCK_SIZE 64 #define DSA_SIGNATURE_SIZE 40 #define DEFAULT_SO_PIN "87654321" #ifndef MAX_TOK_OBJS #define MAX_TOK_OBJS 2048 #endif 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 opencryptoki-opencryptoki-451d99c/usr/lib/common/dig_mgr.c000066400000000000000000000352131520105705100237530ustar00rootroot00000000000000/* * 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" #include "../api/statistics.h" // // CK_RV digest_mgr_init(STDLL_TokData_t *tokdata, SESSION *sess, DIGEST_CONTEXT *ctx, CK_MECHANISM *mech, CK_BBOOL checkpolicy) { 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; } if (checkpolicy) { rc = tokdata->policy->is_mech_allowed(tokdata->policy, mech, NULL, POLICY_CHECK_DIGEST, sess); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: digest init\n"); return rc; } } // 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_SHA3_224: case CKM_SHA3_256: case CKM_SHA3_384: case CKM_SHA3_512: 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(tokdata, sess, ctx); // to de-initialize context above TRACE_ERROR("Failed to init sha context.\n"); return rc; } break; #if !(NOMD2) 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(tokdata, sess, 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; #endif 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(tokdata, sess, ctx); // to de-initialize context above TRACE_ERROR("Failed to init md5 context.\n"); return rc; } break; case CKM_OCK_SHAKE128: case CKM_OCK_SHAKE256: if (mech->ulParameterLen != sizeof(CK_ULONG)) { 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(tokdata, sess, ctx); // to de-initialize context above TRACE_ERROR("Failed to init sha context.\n"); return rc; } break; default: TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); return CKR_MECHANISM_INVALID; } if (mech->ulParameterLen > 0 && mech->pParameter != NULL) { ptr = (CK_BYTE *) malloc(mech->ulParameterLen); if (!ptr) { digest_mgr_cleanup(tokdata, sess, 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; if (ctx->count_statistics == TRUE) INC_COUNTER(tokdata, sess, mech, NULL, POLICY_STRENGTH_IDX_0); return CKR_OK; } // // CK_RV digest_mgr_cleanup(STDLL_TokData_t *tokdata, SESSION *sess, 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->state_unsaveable = FALSE; ctx->count_statistics = FALSE; if (ctx->mech.pParameter) { free(ctx->mech.pParameter); ctx->mech.pParameter = NULL; } if (ctx->context != NULL) { if (ctx->context_free_func != NULL) ctx->context_free_func(tokdata, sess, ctx->context, ctx->context_len); else free(ctx->context); ctx->context = NULL; } ctx->context_len = 0; ctx->context_free_func = 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_SHA3_224: case CKM_SHA3_256: case CKM_SHA3_384: case CKM_SHA3_512: case CKM_IBM_SHA3_224: case CKM_IBM_SHA3_256: case CKM_IBM_SHA3_384: case CKM_IBM_SHA3_512: case CKM_OCK_SHAKE128: case CKM_OCK_SHAKE256: 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(tokdata, sess, 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_SHA3_224: case CKM_SHA3_256: case CKM_SHA3_384: case CKM_SHA3_512: case CKM_IBM_SHA3_224: case CKM_IBM_SHA3_256: case CKM_IBM_SHA3_384: case CKM_IBM_SHA3_512: case CKM_OCK_SHAKE128: case CKM_OCK_SHAKE256: 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(tokdata, sess, 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 (token_specific.secure_key_token) { TRACE_ERROR("%s because its a secure key token\n", ock_err(ERR_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_get_ulong(key_obj->template, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); goto out; } 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_get_non_empty(key_obj->template, CKA_VALUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); 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(tokdata, sess, 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_SHA3_224: case CKM_SHA3_256: case CKM_SHA3_384: case CKM_SHA3_512: case CKM_IBM_SHA3_224: case CKM_IBM_SHA3_256: case CKM_IBM_SHA3_384: case CKM_IBM_SHA3_512: case CKM_OCK_SHAKE128: case CKM_OCK_SHAKE256: 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(tokdata, sess, ctx); } return rc; } opencryptoki-opencryptoki-451d99c/usr/lib/common/dlist.c000066400000000000000000000075021520105705100234620ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021 * * 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 "dlist.h" #include "host_defs.h" #include "h_extern.h" // 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; } opencryptoki-opencryptoki-451d99c/usr/lib/common/dlist.h000066400000000000000000000016541520105705100234710ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021 * * 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 _DLIST_H_ #define _DLIST_H_ #include "pkcs11types.h" #include "defs.h" // 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); #endif opencryptoki-opencryptoki-451d99c/usr/lib/common/dp_obj.c000066400000000000000000000444231520105705100236030ustar00rootroot00000000000000/* * 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_ULONG val; CK_RV rc; rc = template_attribute_get_ulong(tmpl, CKA_KEY_TYPE, &val); if (rc != CKR_OK) { if (mode == MODE_CREATE) { TRACE_ERROR("Could not find CKA_KEY_TYPE\n"); return rc; } } 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_ULONG val; CK_RV rc; if (mode == MODE_CREATE) { rc = template_attribute_get_non_empty(tmpl, CKA_PRIME, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_PRIME\n"); return rc; } rc = template_attribute_get_non_empty(tmpl, CKA_SUBPRIME, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_SUBPRIME\n"); return rc; } rc = template_attribute_get_non_empty(tmpl, CKA_BASE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_BASE\n"); return rc; } } else if (mode == MODE_KEYGEN) { rc = template_attribute_get_ulong(tmpl, CKA_PRIME_BITS, &val); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_PRIME_BITS\n"); return rc; } } 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_ULONG val; CK_RV rc; if (mode == MODE_CREATE) { rc = template_attribute_get_non_empty(tmpl, CKA_PRIME, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_PRIME\n"); return rc; } rc = template_attribute_get_non_empty(tmpl, CKA_BASE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_BASE\n"); return rc; } } else if (mode == MODE_KEYGEN) { rc = template_attribute_get_ulong(tmpl, CKA_PRIME_BITS, &val); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_PRIME_BITS\n"); return rc; } } 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_ULONG val; CK_RV rc; if (mode == MODE_CREATE) { rc = template_attribute_get_non_empty(tmpl, CKA_PRIME, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_PRIME\n"); return rc; } rc = template_attribute_get_non_empty(tmpl, CKA_SUBPRIME, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_SUBPRIME\n"); return rc; } rc = template_attribute_get_non_empty(tmpl, CKA_BASE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_BASE\n"); return rc; } } else if (mode == MODE_KEYGEN) { rc = template_attribute_get_ulong(tmpl, CKA_PRIME_BITS, &val); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_PRIME_BITS\n"); return rc; } rc = template_attribute_get_ulong(tmpl, CKA_SUBPRIME_BITS, &val); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_SUBPRIME_BITS\n"); return rc; } } 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; CK_RV rc; 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; rc = template_update_attribute(tmpl, local_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); free(local_attr); return rc; } 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 (attr->ulValueLen != sizeof(CK_KEY_TYPE) || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } 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 (attr->ulValueLen != sizeof(CK_BBOOL) || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } if (mode == MODE_CREATE || mode == MODE_KEYGEN) { TRACE_ERROR("%s: %lx\n", ock_err(ERR_ATTRIBUTE_TYPE_INVALID), attr->type); 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 (attr->ulValueLen != sizeof(CK_ULONG) || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } 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 (attr->ulValueLen != sizeof(CK_ULONG) || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } 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 (attr->ulValueLen != sizeof(CK_ULONG) || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } 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 (attr->ulValueLen != sizeof(CK_ULONG) || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } 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) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto error; } 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; rc = template_update_attribute(tmpl, prime_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); goto error; } prime_attr = NULL; rc = template_update_attribute(tmpl, subprime_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); goto error; } subprime_attr = NULL; rc = template_update_attribute(tmpl, base_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); goto error; } base_attr = NULL; rc = template_update_attribute(tmpl, primebits_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); goto error; } primebits_attr = NULL; rc = template_update_attribute(tmpl, type_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); goto error; } type_attr = NULL; return CKR_OK; error: 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); return rc; } 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) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto error; } 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; rc = template_update_attribute(tmpl, prime_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); goto error; } prime_attr = NULL; rc = template_update_attribute(tmpl, base_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); goto error; } base_attr = NULL; rc = template_update_attribute(tmpl, primebits_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); goto error; } primebits_attr = NULL; rc = template_update_attribute(tmpl, type_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); goto error; } type_attr = NULL; return CKR_OK; error: if (prime_attr) free(prime_attr); if (base_attr) free(base_attr); if (primebits_attr) free(primebits_attr); if (type_attr) free(type_attr); return rc; } 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) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto error; } 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; rc = template_update_attribute(tmpl, prime_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); goto error; } prime_attr = NULL; rc = template_update_attribute(tmpl, subprime_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); goto error; } subprime_attr = NULL; rc = template_update_attribute(tmpl, base_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); goto error; } base_attr = NULL; rc = template_update_attribute(tmpl, primebits_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); goto error; } primebits_attr = NULL; rc = template_update_attribute(tmpl, subprimebits_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); goto error; } subprimebits_attr = NULL; rc = template_update_attribute(tmpl, type_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); goto error; } type_attr = NULL; return CKR_OK; error: 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); return rc; } opencryptoki-opencryptoki-451d99c/usr/lib/common/ec_curve_translation.c000066400000000000000000000042541520105705100265550ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021 * * 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 "ec_defs.h" static int get_curve_index(const char *str) { /* Keep in sync with the order in der_ec_supported */ static const struct nameidxmapping { const char *name; int idx; } mappings[] = { { "BRAINPOOL_P160R1", 0 }, { "BRAINPOOL_P160T1", 1 }, { "BRAINPOOL_P192R1", 2 }, { "BRAINPOOL_P192T1", 3 }, { "BRAINPOOL_P224R1", 4 }, { "BRAINPOOL_P224T1", 5 }, { "BRAINPOOL_P256R1", 6 }, { "BRAINPOOL_P256T1", 7 }, { "BRAINPOOL_P320R1", 8 }, { "BRAINPOOL_P320T1", 9 }, { "BRAINPOOL_P384R1", 10 }, { "BRAINPOOL_P384T1", 11 }, { "BRAINPOOL_P512R1", 12 }, { "BRAINPOOL_P512T1", 13 }, { "PRIME192V1", 14 }, { "SECP224R1", 15 }, { "PRIME256V1", 16 }, { "SECP384R1", 17 }, { "SECP521R1", 18 }, { "SECP256K1", 19 }, { "CURVE25519", 20 }, { "CURVE448", 21 }, { "ED25519", 22 }, { "ED448", 23 }, { "BLS12_381", 24 }, }; size_t i; for (i = 0; i < sizeof(mappings) / sizeof(struct nameidxmapping); ++i) { if (strcmp(mappings[i].name, str) == 0) return i; } return -1; } CK_RV translate_string_to_curve(const char *str, size_t len, const struct _ec **curve) { (void)len; int idx = get_curve_index(str); if (idx >= 0) { *curve = &der_ec_supported[idx]; return CKR_OK; } return CKR_FUNCTION_FAILED; } opencryptoki-opencryptoki-451d99c/usr/lib/common/ec_defs.h000066400000000000000000000063021520105705100237350ustar00rootroot00000000000000/* * 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 #include #include "ec_curves.h" // Elliptic Curve type (sync with CCA curve type in key value structure) // #define PRIME_CURVE 0x00 #define BRAINPOOL_CURVE 0x01 #define EDWARDS_CURVE 0x02 #define KOBLITZ_CURVE 0x03 #define MONTGOMERY_CURVE 0x04 /* Not used by CCA */ #define BLS12_381_CURVE 0x05 /* Not used by CCA */ // Elliptic Curve length in bits // #define CURVE160 0x00A0 #define CURVE192 0x00C0 #define CURVE224 0x00E0 #define CURVE255 0x00FF #define CURVE256 0x0100 #define CURVE320 0x0140 #define CURVE384 0x0180 #define CURVE448 0x01C0 #define CURVE456 0x01C8 #define CURVE512 0x0200 #define CURVE521 0x0209 /* Supported Elliptic Curves */ #define NUMEC 25 /* 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[]; extern const CK_BYTE bls12_381[]; // structure of supported Elliptic Curves struct _ec { uint8_t curve_type; /* uint8_t - prime or brainpool curve */ uint16_t len_bits; /* uint16_t - signature len in bits */ uint16_t prime_bits; /* len of the prime in bits */ int nid; CK_BBOOL twisted; 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 opencryptoki-opencryptoki-451d99c/usr/lib/common/ec_supported.c000066400000000000000000000132421520105705100250350ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021 * * 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" #include "ec_defs.h" #include "openssl/obj_mac.h" #include #ifndef NID_brainpoolP160r1 /* * Older OpenSSL 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 CK_BYTE bls12_381[] = OCK_BLS12_381; const struct _ec der_ec_supported[NUMEC] = { {BRAINPOOL_CURVE, CURVE160, CURVE160, NID_brainpoolP160r1, CK_FALSE, sizeof(brainpoolP160r1), &brainpoolP160r1}, {BRAINPOOL_CURVE, CURVE160, CURVE160, NID_brainpoolP160t1, CK_TRUE, sizeof(brainpoolP160t1), &brainpoolP160t1}, {BRAINPOOL_CURVE, CURVE192, CURVE192, NID_brainpoolP192r1, CK_FALSE, sizeof(brainpoolP192r1), &brainpoolP192r1}, {BRAINPOOL_CURVE, CURVE192, CURVE192, NID_brainpoolP192t1, CK_TRUE, sizeof(brainpoolP192t1), &brainpoolP192t1}, {BRAINPOOL_CURVE, CURVE224, CURVE224, NID_brainpoolP224r1, CK_FALSE, sizeof(brainpoolP224r1), &brainpoolP224r1}, {BRAINPOOL_CURVE, CURVE224, CURVE224, NID_brainpoolP224t1, CK_TRUE, sizeof(brainpoolP224t1), &brainpoolP224t1}, {BRAINPOOL_CURVE, CURVE256, CURVE256, NID_brainpoolP256r1, CK_FALSE, sizeof(brainpoolP256r1), &brainpoolP256r1}, {BRAINPOOL_CURVE, CURVE256, CURVE256, NID_brainpoolP256t1, CK_TRUE, sizeof(brainpoolP256t1), &brainpoolP256t1}, {BRAINPOOL_CURVE, CURVE320, CURVE320, NID_brainpoolP320r1, CK_FALSE, sizeof(brainpoolP320r1), &brainpoolP320r1}, {BRAINPOOL_CURVE, CURVE320, CURVE320, NID_brainpoolP320t1, CK_TRUE, sizeof(brainpoolP320t1), &brainpoolP320t1}, {BRAINPOOL_CURVE, CURVE384, CURVE384, NID_brainpoolP384r1, CK_FALSE, sizeof(brainpoolP384r1), &brainpoolP384r1}, {BRAINPOOL_CURVE, CURVE384, CURVE384, NID_brainpoolP384t1, CK_TRUE, sizeof(brainpoolP384t1), &brainpoolP384t1}, {BRAINPOOL_CURVE, CURVE512, CURVE512, NID_brainpoolP512r1, CK_FALSE, sizeof(brainpoolP512r1), &brainpoolP512r1}, {BRAINPOOL_CURVE, CURVE512, CURVE512, NID_brainpoolP512t1, CK_TRUE, sizeof(brainpoolP512t1), &brainpoolP512t1}, {PRIME_CURVE, CURVE192, CURVE192, NID_X9_62_prime192v1, CK_FALSE, sizeof(prime192v1), &prime192v1}, {PRIME_CURVE, CURVE224, CURVE224, NID_secp224r1, CK_FALSE, sizeof(secp224r1), &secp224r1}, {PRIME_CURVE, CURVE256, CURVE256, NID_X9_62_prime256v1, CK_FALSE, sizeof(prime256v1), &prime256v1}, {PRIME_CURVE, CURVE384, CURVE384, NID_secp384r1, CK_FALSE, sizeof(secp384r1), &secp384r1}, {PRIME_CURVE, CURVE521, CURVE521, NID_secp521r1, CK_FALSE, sizeof(secp521r1), &secp521r1}, {KOBLITZ_CURVE, CURVE256, CURVE256, NID_secp256k1, CK_FALSE, sizeof(secp256k1), &secp256k1}, {MONTGOMERY_CURVE, CURVE256, CURVE255, NID_X25519, CK_FALSE, sizeof(curve25519), &curve25519}, {MONTGOMERY_CURVE, CURVE448, CURVE448, NID_X448, CK_FALSE, sizeof(curve448), &curve448}, /* Curve448: 56 bytes ! */ {EDWARDS_CURVE, CURVE256, CURVE255, NID_ED25519, CK_FALSE, sizeof(ed25519), &ed25519}, {EDWARDS_CURVE, CURVE456, CURVE448, NID_ED448, CK_FALSE, sizeof(ed448), &ed448}, /* Ed448: 57 bytes ! */ {BLS12_381_CURVE, CURVE384, CURVE384, NID_undef, CK_TRUE, sizeof(bls12_381), &bls12_381}, }; opencryptoki-opencryptoki-451d99c/usr/lib/common/encr_mgr.c000066400000000000000000001442761520105705100241510ustar00rootroot00000000000000/* * 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" #include "p11util.h" #include "../api/policy.h" #include "../api/statistics.h" #include // // 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_BBOOL checkpolicy) { OBJECT *key_obj = NULL; CK_BYTE *ptr = NULL; CK_KEY_TYPE keytype; CK_BBOOL flag; CK_RV rc; int poilicy_check; CK_ATTRIBUTE_TYPE key_usage_attr; CK_ULONG strength = POLICY_STRENGTH_IDX_0; CK_GCM_PARAMS gcm_params; CK_MECHANISM temp_mech; CK_ULONG aeskw_iv_len = AES_KEY_WRAP_KWP_IV_SIZE; 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; } switch (operation) { case OP_ENCRYPT_INIT: key_usage_attr = CKA_ENCRYPT; poilicy_check = POLICY_CHECK_ENCRYPT; break; case OP_WRAP: key_usage_attr = CKA_WRAP; poilicy_check = POLICY_CHECK_WRAP; break; case OP_ENCAPSULATE: key_usage_attr = CKA_ENCAPSULATE; poilicy_check = POLICY_CHECK_ENCAPS; break; default: TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto done; } /* key usage restrictions */ 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 operation == OP_WRAP ? CKR_WRAPPING_KEY_HANDLE_INVALID : CKR_KEY_HANDLE_INVALID; else return rc; } /* is key allowed to do the desired operation? */ rc = template_attribute_get_bool(key_obj->template, key_usage_attr, &flag); if (rc != CKR_OK) { TRACE_ERROR("Could not find %s for the key.\n", p11_get_cka(key_usage_attr)); rc = CKR_KEY_FUNCTION_NOT_PERMITTED; goto done; } if (flag != TRUE) { TRACE_ERROR("%s is set to FALSE.\n", p11_get_cka(key_usage_attr)); rc = CKR_KEY_FUNCTION_NOT_PERMITTED; goto done; } if (checkpolicy) { rc = tokdata->policy->is_mech_allowed(tokdata->policy, mech, &key_obj->strength, poilicy_check, sess); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: encrypt/wrap init\n"); goto done; } } if (!key_object_is_mechanism_allowed(key_obj->template, mech->mechanism)) { TRACE_ERROR("Mechanism not allwed per CKA_ALLOWED_MECHANISMS.\n"); rc = CKR_MECHANISM_INVALID; 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_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } 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_CBC: case CKM_DES_CBC_PAD: if (mech->ulParameterLen != DES_BLOCK_SIZE || mech->pParameter == NULL) { 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_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } 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 || mech->pParameter == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } rc = template_attribute_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } 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_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } 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 || mech->pParameter == NULL) { 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_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } 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 != sizeof(CK_RSA_PKCS_OAEP_PARAMS) || mech->pParameter == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } rc = template_attribute_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } 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_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } 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_ECDH_AES_KEY_WRAP: case CKM_ECDH_COF_AES_KEY_WRAP: case CKM_ECDH_X_AES_KEY_WRAP: /* CKM_ECDH_[COF_|X_]AES_KEY_WRAP can only be used for wrap/unwrap */ if (operation != OP_WRAP) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); rc = CKR_MECHANISM_INVALID; goto done; } if (mech->ulParameterLen != sizeof(CK_ECDH_AES_KEY_WRAP_PARAMS) || mech->pParameter == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } rc = template_attribute_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } switch (mech->mechanism) { case CKM_ECDH_AES_KEY_WRAP: if (keytype != CKK_EC && keytype != CKK_EC_MONTGOMERY) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); rc = CKR_KEY_TYPE_INCONSISTENT; goto done; } break; case CKM_ECDH_COF_AES_KEY_WRAP: if (keytype != CKK_EC) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); rc = CKR_KEY_TYPE_INCONSISTENT; goto done; } break; case CKM_ECDH_X_AES_KEY_WRAP: if (keytype != CKK_EC_MONTGOMERY) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); rc = CKR_KEY_TYPE_INCONSISTENT; goto done; } break; default: TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); rc = CKR_MECHANISM_INVALID; goto done; } // cannot be used for multi-part operations // ctx->context_len = 0; ctx->context = NULL; break; case CKM_RSA_AES_KEY_WRAP: /* CKM_RSA_AES_KEY_WRAP can only be used for wrap/unwrap */ if (operation != OP_WRAP) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); rc = CKR_MECHANISM_INVALID; goto done; } if (mech->ulParameterLen != sizeof(CK_RSA_AES_KEY_WRAP_PARAMS) || mech->pParameter == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } rc = template_attribute_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } 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_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } 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 || mech->pParameter == NULL) { 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_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } 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) || mech->pParameter == NULL) { 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_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } 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) && mech->ulParameterLen != sizeof(CK_GCM_PARAMS_COMPAT)) || mech->pParameter == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } if (mech->ulParameterLen == sizeof(CK_GCM_PARAMS_COMPAT)) { aes_gcm_param_from_compat((CK_GCM_PARAMS_COMPAT *)mech->pParameter, &gcm_params); temp_mech.mechanism = mech->mechanism; temp_mech.pParameter = &gcm_params; temp_mech.ulParameterLen = sizeof(gcm_params); mech = &temp_mech; } rc = template_attribute_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } 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)); strength = key_obj->strength.strength; /* Release obj lock, token specific aes-gcm may re-acquire the lock */ object_put(tokdata, key_obj, TRUE); key_obj = NULL; 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 || mech->pParameter == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } rc = template_attribute_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } 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_XTS: if (mech->ulParameterLen != AES_INIT_VECTOR_SIZE || mech->pParameter == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } rc = template_attribute_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } if (keytype != CKK_AES_XTS) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); rc = CKR_KEY_TYPE_INCONSISTENT; goto done; } ctx->context_len = sizeof(AES_XTS_CONTEXT); ctx->context = (CK_BYTE *) malloc(sizeof(AES_XTS_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_XTS_CONTEXT)); break; case CKM_AES_KEY_WRAP: case CKM_AES_KEY_WRAP_PAD: case CKM_AES_KEY_WRAP_PKCS7: aeskw_iv_len = AES_KEY_WRAP_IV_SIZE; /* fallthrough */ case CKM_AES_KEY_WRAP_KWP: if ((mech->ulParameterLen != 0 && mech->pParameter == NULL) || (mech->ulParameterLen == 0 && mech->pParameter != NULL) || (mech->ulParameterLen != 0 && mech->ulParameterLen != aeskw_iv_len)) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } rc = template_attribute_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } if (keytype != CKK_AES) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); rc = CKR_KEY_TYPE_INCONSISTENT; goto done; } /* AES key wrap cannot be used for multi-part operations */ ctx->context_len = 0; ctx->context = NULL; break; default: TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_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); /* Deep copy mechanism parameter, if required */ switch (mech->mechanism) { case CKM_AES_GCM: rc = aes_gcm_dup_param((CK_GCM_PARAMS *)mech->pParameter, (CK_GCM_PARAMS *)ptr); if (rc != CKR_OK) { TRACE_ERROR("aes_gcm_dup_param failed\n"); free(ptr); goto done; } break; default: break; } } 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; ctx->pkey_active = FALSE; rc = CKR_OK; done: if (ctx->count_statistics == TRUE && rc == CKR_OK) INC_COUNTER(tokdata, sess, mech, key_obj, strength); object_put(tokdata, key_obj, TRUE); key_obj = NULL; return rc; } // // CK_RV encr_mgr_cleanup(STDLL_TokData_t *tokdata, SESSION *sess, ENCR_DECR_CONTEXT *ctx) { if (!ctx) { TRACE_ERROR("Invalid function argument.\n"); return CKR_FUNCTION_FAILED; } ctx->key = 0; ctx->multi_init = FALSE; ctx->multi = FALSE; ctx->active = FALSE; ctx->init_pending = FALSE; ctx->pkey_active = FALSE; ctx->state_unsaveable = FALSE; ctx->count_statistics = FALSE; if (ctx->mech.pParameter) { /* Deep free mechanism parameter, if required */ switch (ctx->mech.mechanism) { case CKM_AES_GCM: aes_gcm_free_param((CK_GCM_PARAMS *)ctx->mech.pParameter); break; default: break; } free(ctx->mech.pParameter); ctx->mech.pParameter = NULL; } ctx->mech.ulParameterLen = 0; ctx->mech.mechanism = 0; if (ctx->context) { if (ctx->context_free_func != NULL) ctx->context_free_func(tokdata, sess, ctx->context, ctx->context_len); else free(ctx->context); ctx->context = NULL; } ctx->context_len = 0; ctx->context_free_func = 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 = 0; 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_DES_ECB: return pk_des_ecb_encrypt(tokdata, sess, length_only, ctx, in_data, in_data_len, out_data, out_data_len); 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: 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); case CKM_ECDH_AES_KEY_WRAP: case CKM_ECDH_COF_AES_KEY_WRAP: case CKM_ECDH_X_AES_KEY_WRAP: return ecdh_aes_key_wrap(tokdata, sess, length_only, ctx, in_data, in_data_len, out_data, out_data_len); case CKM_RSA_AES_KEY_WRAP: return rsa_aes_key_wrap(tokdata, sess, length_only, ctx, in_data, in_data_len, out_data, out_data_len); 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); case CKM_AES_XTS: return aes_xts_encrypt(tokdata, sess, length_only, ctx, in_data, in_data_len, out_data, out_data_len); case CKM_AES_KEY_WRAP: case CKM_AES_KEY_WRAP_PAD: case CKM_AES_KEY_WRAP_KWP: case CKM_AES_KEY_WRAP_PKCS7: return aes_key_wrap_encrypt(tokdata, sess, length_only, ctx, in_data, in_data_len, out_data, out_data_len); 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 = 0; 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_DES_ECB: return des_ecb_encrypt_update(tokdata, sess, length_only, ctx, in_data, in_data_len, out_data, out_data_len); 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: 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); 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); case CKM_AES_XTS: return aes_xts_encrypt_update(tokdata, sess, length_only, ctx, in_data, in_data_len, out_data, out_data_len); 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 = 0; 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_DES_ECB: return des_ecb_encrypt_final(tokdata, sess, length_only, ctx, out_data, out_data_len); case CKM_DES_CBC: return des_cbc_encrypt_final(tokdata, sess, length_only, ctx, out_data, out_data_len); case CKM_DES_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); 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); case CKM_AES_XTS: return aes_xts_encrypt_final(tokdata, sess, length_only, ctx, out_data, out_data_len); default: return CKR_MECHANISM_INVALID; } TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } CK_RV encr_mgr_reencrypt_single(STDLL_TokData_t *tokdata, SESSION *sess, ENCR_DECR_CONTEXT *decr_ctx, CK_MECHANISM *decr_mech, CK_OBJECT_HANDLE decr_key, ENCR_DECR_CONTEXT *encr_ctx, CK_MECHANISM *encr_mech, CK_OBJECT_HANDLE encr_key, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len) { OBJECT *decr_key_obj = NULL; OBJECT *encr_key_obj = NULL; CK_ULONG decr_data_len = 0; CK_BYTE *decr_data = NULL; CK_BBOOL flag; CK_RV rc; if (!sess || !decr_ctx || !encr_ctx || !decr_mech || !encr_mech) { TRACE_ERROR("Invalid function arguments.\n"); return CKR_FUNCTION_FAILED; } if (decr_ctx->active != FALSE || encr_ctx->active != FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); return CKR_OPERATION_ACTIVE; } if (token_specific.t_reencrypt_single != NULL) { rc = object_mgr_find_in_map1(tokdata, decr_key, &decr_key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to acquire decr-key from specified handle.\n"); if (rc == CKR_OBJECT_HANDLE_INVALID) return CKR_KEY_HANDLE_INVALID; else return rc; } rc = object_mgr_find_in_map1(tokdata, encr_key, &encr_key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to acquire encr-key from specified handle.\n"); if (rc == CKR_OBJECT_HANDLE_INVALID) rc = CKR_KEY_HANDLE_INVALID; goto done; } rc = tokdata->policy->is_mech_allowed(tokdata->policy, decr_mech, &decr_key_obj->strength, POLICY_CHECK_DECRYPT, sess); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: Reencrypt_single decryption\n"); goto done; } rc = tokdata->policy->is_mech_allowed(tokdata->policy, encr_mech, &encr_key_obj->strength, POLICY_CHECK_ENCRYPT, sess); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: Reencrypt_single encryption\n"); goto done; } if (!key_object_is_mechanism_allowed(decr_key_obj->template, decr_mech->mechanism)) { TRACE_ERROR("Decrypt mechanism not allwed per " "CKA_ALLOWED_MECHANISMS.\n"); rc = CKR_MECHANISM_INVALID; goto done; } if (!key_object_is_mechanism_allowed(encr_key_obj->template, encr_mech->mechanism)) { TRACE_ERROR("Encrypt mechanism not allwed per " "CKA_ALLOWED_MECHANISMS.\n"); rc = CKR_MECHANISM_INVALID; goto done; } rc = template_attribute_get_bool(decr_key_obj->template, CKA_DECRYPT, &flag); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_DECRYPT for the key.\n"); rc = CKR_KEY_FUNCTION_NOT_PERMITTED; goto done; } if (flag != TRUE) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_FUNCTION_NOT_PERMITTED)); rc = CKR_KEY_FUNCTION_NOT_PERMITTED; goto done; } rc = template_attribute_get_bool(encr_key_obj->template, CKA_ENCRYPT, &flag); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_ENCRYPT for the key.\n"); rc = CKR_KEY_FUNCTION_NOT_PERMITTED; goto done; } if (flag != TRUE) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_FUNCTION_NOT_PERMITTED)); rc = CKR_KEY_FUNCTION_NOT_PERMITTED; goto done; } rc = token_specific.t_reencrypt_single(tokdata, sess, decr_ctx, decr_mech, decr_key_obj, encr_ctx, encr_mech, encr_key_obj, in_data, in_data_len, out_data, out_data_len); if (rc != CKR_OK) TRACE_DEVEL("Token specific reencrypt single failed.\n"); if (decr_ctx->count_statistics == TRUE && rc == CKR_OK) INC_COUNTER(tokdata, sess, decr_mech, decr_key_obj, POLICY_STRENGTH_IDX_0); if (encr_ctx->count_statistics == TRUE && rc == CKR_OK) INC_COUNTER(tokdata, sess, encr_mech, encr_key_obj, POLICY_STRENGTH_IDX_0); goto done; } /* No token specific reencrypt_single function, perform it manually */ /* Enforces policy */ rc = decr_mgr_init(tokdata, sess, decr_ctx, OP_DECRYPT_INIT, decr_mech, decr_key, TRUE, TRUE); if (rc != CKR_OK) goto done; /* Enforces Policy */ rc = encr_mgr_init(tokdata, sess, encr_ctx, OP_ENCRYPT_INIT, encr_mech, encr_key, TRUE); if (rc != CKR_OK) goto done; rc = decr_mgr_decrypt(tokdata, sess, TRUE, decr_ctx, in_data, in_data_len, NULL, &decr_data_len); if (rc != CKR_OK) goto done; decr_data = malloc(decr_data_len); if (decr_data == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto done; } rc = decr_mgr_decrypt(tokdata, sess, FALSE, decr_ctx, in_data, in_data_len, decr_data, &decr_data_len); if (rc != CKR_OK) goto done; rc = encr_mgr_encrypt(tokdata, sess, out_data == NULL, encr_ctx, decr_data, decr_data_len, out_data, out_data_len); if (rc != CKR_OK) goto done; done: object_put(tokdata, decr_key_obj, TRUE); decr_key_obj = NULL; object_put(tokdata, encr_key_obj, TRUE); encr_key_obj = NULL; if (decr_data != NULL) { OPENSSL_cleanse(decr_data, decr_data_len); free(decr_data); } decr_mgr_cleanup(tokdata, sess, decr_ctx); encr_mgr_cleanup(tokdata, sess, encr_ctx); return rc; } opencryptoki-opencryptoki-451d99c/usr/lib/common/event_client.c000066400000000000000000000137621520105705100250270ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021 * * 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 "slotmgr.h" #include "event_client.h" static int connect_socket(const char *file_path) { int socketfd; struct sockaddr_un daemon_address; struct stat file_info; struct group *grp; struct passwd *pwd; int rc; if (stat(file_path, &file_info)) return -errno; grp = getgrnam(PKCS_GROUP); if (!grp) return -errno; pwd = getpwnam(PKCSSLOTD_USER); if (!pwd) return -errno; if (file_info.st_uid != pwd->pw_uid || file_info.st_gid != grp->gr_gid) return -EPERM; if ((socketfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) return -errno; memset(&daemon_address, 0, sizeof(struct sockaddr_un)); daemon_address.sun_family = AF_UNIX; strncpy(daemon_address.sun_path, file_path, sizeof(daemon_address.sun_path)); daemon_address.sun_path[sizeof(daemon_address.sun_path) - 1] = '\0'; if (connect(socketfd, (struct sockaddr *) &daemon_address, sizeof(struct sockaddr_un)) != 0) { rc = -errno; goto error; } return socketfd; error: close(socketfd); return rc; } static ssize_t read_all(int socketfd, char *buffer, size_t size) { size_t bytes_received = 0; ssize_t n; while (bytes_received < size) { n = read(socketfd, buffer + bytes_received, size - bytes_received); if (n < 0) { // read error if (errno == EINTR) continue; return -errno; } if (n == 0) break; bytes_received += n; } return bytes_received; } static ssize_t send_all(int socketfd, char *buffer, size_t size) { size_t bytes_sent = 0; ssize_t n; while (bytes_sent < size) { n = send(socketfd, buffer + bytes_sent, size - bytes_sent, 0); if (n < 0) { // send error if (errno == EINTR) continue; return -errno; } if (n == 0) break; bytes_sent += n; } return bytes_sent; } /* * Initialize an admin connection to the pkcsslotd. * Returns a file descriptor representing the connection, or a negative errno * in case of an error. */ int init_event_client(void) { int fd; fd = connect_socket(ADMIN_SOCKET_FILE_PATH); return fd; } /* * Send an event though the admin connection to the pkcsslotd, and thus to * all active token instances. * If parameter fd is < 0, then a connection to pkcsslotd is established * inside the function and closed before return. This is for a one shot event. * Otherwise, pass a file descriptor received from init_event_client(). This * is to send multiple events. * Event type is mandatory, flags can be zero. * The event payload is optional, if payload_len is non-zero, then payload must * point to a buffer containing the payload to send with the event. * The event destination can be used to selectively send the event to certain * token instances only. If destination is NULL, it is sent to all token * instances. * If flag EVENT_FLAGS_REPLY_REQ is on in the flags parameter, then it is waited * until all active token instances have replied. The combined result of the * replies from the token instances is returned in the reply structure. * Parameter reply must be non-NULL if flag EVENT_FLAGS_REPLY_REQ is set. * Returns zero for success, or a negative errno in case of an error. In most * error cases the connection to the pkcsslotd is out of sequence and can no * longer be used to send further events. */ int send_event(int fd, unsigned int type, unsigned int flags, unsigned int payload_len, const char *payload, const struct event_destination *destination, struct event_reply *reply) { event_msg_t event_msg; event_reply_t event_reply; int rc, term = 0; if (payload_len > 0 && payload == NULL) return -EINVAL; if ((flags & EVENT_FLAGS_REPLY_REQ) && reply == NULL) return -EINVAL; if (payload_len > EVENT_MAX_PAYLOAD_LENGTH) return -EMSGSIZE; if (fd < 0) { fd = init_event_client(); if (fd < 0) return fd; term = 1; } memset(&event_msg, 0, sizeof(event_msg)); event_msg.version = EVENT_VERSION_1; event_msg.type = type; event_msg.flags = flags; if (destination != NULL) { event_msg.token_type = destination->token_type; memcpy(event_msg.token_label, destination->token_label, sizeof(event_msg.token_label)); event_msg.process_id = destination->process_id; } else { memset(event_msg.token_label, ' ', sizeof(event_msg.token_label)); } event_msg.payload_len = payload_len; rc = send_all(fd, (char *)&event_msg, sizeof(event_msg)); if (rc < 0) goto out; if (payload_len > 0) { rc = send_all(fd, (char *)payload, payload_len); if (rc < 0) goto out; } if (flags & EVENT_FLAGS_REPLY_REQ) { rc = read_all(fd, (char *)&event_reply, sizeof(event_reply)); if (rc < 0) goto out; reply->positive_replies = event_reply.positive_replies; reply->negative_replies = event_reply.negative_replies; reply->nothandled_replies = event_reply.nothandled_replies; } rc = 0; out: if (term) term_event_client(fd); return rc; } /* * Terminate the admin connection to the pkcsslotd. */ void term_event_client(int fd) { if (fd >= 0) close(fd); } opencryptoki-opencryptoki-451d99c/usr/lib/common/event_client.h000066400000000000000000000023001520105705100250160ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021 * * 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 _EVENT_CLIENT_H_ #define _EVENT_CLIENT_H_ #include "events.h" struct event_destination { unsigned int token_type; /* Destination token type: EVENT_TOK_TYPE_xxx */ char token_label[member_size(event_msg_t, token_label)]; /* Label of destination token (or blanks) */ pid_t process_id; /* Process ID of destination process (or 0) */ }; struct event_reply { unsigned long positive_replies; unsigned long negative_replies; unsigned long nothandled_replies; }; int init_event_client(void); int send_event(int fd, unsigned int type, unsigned int flags, unsigned int payload_len, const char *payload, const struct event_destination *destination, struct event_reply *reply); void term_event_client(int fd); #endif opencryptoki-opencryptoki-451d99c/usr/lib/common/globals.c000066400000000000000000000223411520105705100237640ustar00rootroot00000000000000/* * 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" #include "pqc_oids.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 }; #if !(NOMD2) const CK_BYTE ber_md2WithRSAEncryption[] = { 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x02 }; #endif 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) // #if !(NOMD2) const CK_BYTE ber_AlgMd2[] = { 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x02, 0x05, 0x00 }; #endif 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_AlgSha3_224[] = { 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x07, 0x05, 0x00 }; const CK_BYTE ber_AlgSha3_256[] = { 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x08, 0x05, 0x00 }; const CK_BYTE ber_AlgSha3_384[] = { 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x09, 0x05, 0x00 }; const CK_BYTE ber_AlgSha3_512[] = { 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0A, 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_NULL[] = { 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); #if !(NOMD2) const CK_ULONG ber_md2WithRSAEncryptionLen = sizeof(ber_md2WithRSAEncryption); #endif 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); #if !(NOMD2) const CK_ULONG ber_AlgMd2Len = sizeof(ber_AlgMd2); #endif 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_AlgSha3_224Len = sizeof(ber_AlgSha3_224); const CK_ULONG ber_AlgSha3_256Len = sizeof(ber_AlgSha3_256); const CK_ULONG ber_AlgSha3_384Len = sizeof(ber_AlgSha3_384); const CK_ULONG ber_AlgSha3_512Len = sizeof(ber_AlgSha3_512); const CK_ULONG ber_AlgIdRSAEncryptionLen = sizeof(ber_AlgIdRSAEncryption); const CK_ULONG der_AlgIdECBaseLen = sizeof(der_AlgIdECBase); const CK_ULONG ber_NULLLen = sizeof(ber_NULL); 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 }; opencryptoki-opencryptoki-451d99c/usr/lib/common/h_extern.h000066400000000000000000005347741520105705100242040ustar00rootroot00000000000000/* * 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 #include "dlist.h" #include "host_defs.h" #include "pqc_defs.h" #include /* Forward declaration to keep dependencies as small as possible. */ struct policy; // 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_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_NULL[]; extern const CK_ULONG ber_NULLLen; #if !(NOMD2) extern const CK_BYTE ber_md2WithRSAEncryption[]; extern const CK_ULONG ber_md2WithRSAEncryptionLen; #endif extern const CK_BYTE ber_md5WithRSAEncryption[]; extern const CK_ULONG ber_md5WithRSAEncryptionLen; extern const CK_BYTE ber_sha1WithRSAEncryption[]; extern const CK_ULONG ber_sha1WithRSAEncryptionLen; #if !(NOMD2) extern const CK_BYTE ber_AlgMd2[]; extern const CK_ULONG ber_AlgMd2Len; #endif 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_BYTE ber_AlgSha3_224[]; extern const CK_ULONG ber_AlgSha3_224Len; extern const CK_BYTE ber_AlgSha3_256[]; extern const CK_ULONG ber_AlgSha3_256Len; extern const CK_BYTE ber_AlgSha3_384[]; extern const CK_ULONG ber_AlgSha3_384Len; extern const CK_BYTE ber_AlgSha3_512[]; extern const CK_ULONG ber_AlgSha3_512Len; 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 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, const char *fname); 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 *, size_t); 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); CK_RV init_data_store(STDLL_TokData_t *tokdata, char *directory, char *data_store, size_t len); 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 init_hsm_mk_change_lock(STDLL_TokData_t *tokdata); CK_RV compute_PKCS5_PBKDF2_HMAC(STDLL_TokData_t *tokdata, CK_CHAR *pPin, CK_ULONG ulPinLen, CK_BYTE *salt, CK_ULONG salt_len, CK_ULONG it_count, const EVP_MD *digest, CK_ULONG key_len, CK_BYTE *key); 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 get_hmac_digest(CK_ULONG mech, CK_ULONG *digest_mech, CK_BBOOL *general); CK_RV mgf1(STDLL_TokData_t *tokdata, const CK_BYTE *seed, CK_ULONG seedlen, CK_BYTE *mask, CK_ULONG maskLen, CK_RSA_PKCS_MGF_TYPE mgf); CK_RV get_ecsiglen(OBJECT *key_obj, CK_ULONG *size); //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, OBJECT *base_key_obj, CK_ATTRIBUTE *attributes, CK_ULONG count, CK_OBJECT_HANDLE *handle, CK_BBOOL count_statistic); CK_RV ssl3_key_and_mac_derive(STDLL_TokData_t *tokdata, SESSION *sess, CK_MECHANISM *mech, OBJECT *base_key_obj, CK_ATTRIBUTE *attributes, CK_ULONG count, CK_BBOOL count_statistic); CK_RV ckm_ssl3_pre_master_key_gen(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_MECHANISM *mech); // RSA routines // CK_BBOOL is_rsa_mechanism(CK_MECHANISM_TYPE mech); CK_RV rsa_pkcs_encrypt(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, 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_aes_key_wrap(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_aes_key_unwrap(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_encapsulate_key(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, CK_MECHANISM *mech, OBJECT *public_key, CK_ATTRIBUTE *pTemplate, CK_ULONG ulAttributeCount, CK_BYTE *pCiphertext, CK_ULONG *pulCiphertextLen, CK_OBJECT_HANDLE *phKey); CK_RV rsa_decapsulate_key(STDLL_TokData_t *tokdata, SESSION *sess, CK_MECHANISM *mech, OBJECT *private_key, CK_ATTRIBUTE *pTemplate, CK_ULONG ulAttributeCount, CK_BYTE *pCiphertext, CK_ULONG ulCiphertextLen, CK_OBJECT_HANDLE *phKey); CK_RV ecdh_aes_key_wrap(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 ecdh_aes_key_unwrap(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 ecdh_encapsulate_key(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, CK_MECHANISM *mech, OBJECT *public_key, CK_ATTRIBUTE *pTemplate, CK_ULONG ulAttributeCount, CK_BYTE *pCiphertext, CK_ULONG *pulCiphertextLen, CK_OBJECT_HANDLE *phKey); CK_RV ecdh_decapsulate_key(STDLL_TokData_t *tokdata, SESSION *sess, CK_MECHANISM *mech, OBJECT *private_key, CK_ATTRIBUTE *pTemplate, CK_ULONG ulAttributeCount, CK_BYTE *pCiphertext, CK_ULONG ulCiphertextLen, CK_OBJECT_HANDLE *phKey); 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, CK_BYTE *kdk, CK_ULONG kdklen); CK_RV get_mgf_mech(CK_RSA_PKCS_MGF_TYPE mgf, CK_MECHANISM_TYPE *mech); // 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, OBJECT *base_key_obj, CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE *handle, CK_BBOOL count_statistic); // DH mechanisms // CK_RV ckm_dh_pkcs_derive(STDLL_TokData_t *tokdata, SESSION *sess, CK_VOID_PTR other_pubkey, CK_ULONG other_pubkey_len, OBJECT *base_key_obj, CK_BYTE *secret, CK_ULONG *secret_len, CK_MECHANISM_PTR mech, CK_BBOOL count_statistic); 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); CK_RV dh_encapsulate_key(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, CK_MECHANISM *mech, OBJECT *public_key, CK_ATTRIBUTE *pTemplate, CK_ULONG ulAttributeCount, CK_BYTE *pCiphertext, CK_ULONG *pulCiphertextLen, CK_OBJECT_HANDLE *phKey); CK_RV dh_decapsulate_key(STDLL_TokData_t *tokdata, SESSION *sess, CK_MECHANISM *mech, OBJECT *private_key, CK_ATTRIBUTE *pTemplate, CK_ULONG ulAttributeCount, CK_BYTE *pCiphertext, CK_ULONG ulCiphertextLen, CK_OBJECT_HANDLE *phKey); #endif /* End code contributed by Corrent corp. */ CK_RV ckm_ibm_ml_dsa_key_pair_gen(STDLL_TokData_t *tokdata, CK_MECHANISM *mech, TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl); CK_RV ibm_ml_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); CK_RV ibm_ml_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); CK_RV ckm_ibm_ml_kem_key_pair_gen(STDLL_TokData_t *tokdata, CK_MECHANISM *mech, TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl); CK_RV ibm_ml_kem_derive(STDLL_TokData_t *tokdata, SESSION *sess, CK_MECHANISM *mech, OBJECT *base_key_obj, CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE *derived_key_handle); CK_RV pqc_pack_priv_key(TEMPLATE *templ, const struct pqc_oid *oid, CK_MECHANISM_TYPE mech, CK_BYTE *priv, CK_ULONG *priv_len); CK_RV pqc_pack_pub_key(TEMPLATE *templ, const struct pqc_oid *oid, CK_MECHANISM_TYPE mech, CK_BYTE *pub, CK_ULONG *pub_len); CK_RV pqc_unpack_priv_key(CK_BYTE *priv, CK_ULONG priv_len, const struct pqc_oid *oid, CK_MECHANISM_TYPE mech, TEMPLATE *templ); CK_RV pqc_unpack_pub_key(CK_BYTE *pub, CK_ULONG pub_len, const struct pqc_oid *oid, CK_MECHANISM_TYPE mech, TEMPLATE *templ); CK_RV ibm_ml_dsa_dup_param(CK_VOID_PTR src, CK_VOID_PTR dst, CK_ULONG len); CK_RV ibm_ml_dsa_free_param(CK_VOID_PTR p, CK_ULONG len); CK_RV ckm_ml_dsa_key_pair_gen(STDLL_TokData_t *tokdata, TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl); CK_RV ckm_ml_kem_key_pair_gen(STDLL_TokData_t *tokdata, TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl); CK_RV ml_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_BBOOL final_part); CK_RV ml_dsa_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 ml_dsa_hash_sign_verify_update(STDLL_TokData_t *tokdata, SESSION *sess, SIGN_VERIFY_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len); CK_RV ml_dsa_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 ml_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, CK_BBOOL final_part); CK_RV ml_dsa_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 ml_dsa_hash_verify_final(STDLL_TokData_t *tokdata, SESSION *sess, SIGN_VERIFY_CONTEXT *ctx, CK_BYTE *signature, CK_ULONG sig_len); CK_RV ml_dsa_dup_param(CK_VOID_PTR src, CK_VOID_PTR dst, CK_ULONG len); CK_RV ml_dsa_free_param(CK_VOID_PTR p, CK_ULONG len); CK_RV ml_dsa_hash_dup_param(CK_VOID_PTR src, CK_VOID_PTR dst, CK_ULONG len); CK_RV ml_dsa_hash_free_param(CK_VOID_PTR p, CK_ULONG len); struct CK_IBM_SIGN_ADDITIONAL_CONTEXT; CK_RV ml_dsa_translate_sign_mech_param_from_ibm( struct CK_IBM_SIGN_ADDITIONAL_CONTEXT *from, CK_SIGN_ADDITIONAL_CONTEXT *to); CK_RV ml_dsa_translate_ibm_sign_mech_param_from_sign( CK_SIGN_ADDITIONAL_CONTEXT *from, struct CK_IBM_SIGN_ADDITIONAL_CONTEXT *to); CK_RV ml_dsa_translate_sign_mech_param_from_hash( CK_HASH_SIGN_ADDITIONAL_CONTEXT *from, CK_SIGN_ADDITIONAL_CONTEXT *to, CK_MECHANISM_TYPE *hash_mech); CK_RV ml_dsa_translate_hash_sign_mech_param_from_sign( CK_SIGN_ADDITIONAL_CONTEXT *from, CK_HASH_SIGN_ADDITIONAL_CONTEXT *to, CK_MECHANISM_TYPE hash_mech); CK_RV ml_kem_encapsulate_key(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, CK_MECHANISM *mech, OBJECT *public_key, CK_ATTRIBUTE *pTemplate, CK_ULONG ulAttributeCount, CK_BYTE *pCiphertext, CK_ULONG *pulCiphertextLen, CK_OBJECT_HANDLE *phKey); CK_RV ml_kem_decapsulate_key(STDLL_TokData_t *tokdata, SESSION *sess, CK_MECHANISM *mech, OBJECT *private_key, CK_ATTRIBUTE *pTemplate, CK_ULONG ulAttributeCount, CK_BYTE *pCiphertext, CK_ULONG ulCiphertextLen, CK_OBJECT_HANDLE *phKey); CK_RV digest_from_kdf(CK_EC_KDF_TYPE kdf, CK_MECHANISM_TYPE *mech); CK_RV get_digest_from_mech(CK_MECHANISM_TYPE mech, CK_MECHANISM_TYPE *digest); CK_RV pkcs_get_keytype(CK_ATTRIBUTE *attrs, CK_ULONG attrs_len, CK_MECHANISM_PTR mech, CK_KEY_TYPE *type, CK_OBJECT_CLASS *class); CK_RV pkcsget_keytype_for_mech(CK_MECHANISM_TYPE mech, CK_KEY_TYPE *keytype, CK_KEY_TYPE *alt_keytype); CK_RV ecdh_get_derived_key_size(CK_ULONG prime_len, CK_BYTE *curve_oid, CK_ULONG curve_oid_len, CK_EC_KDF_TYPE kdf, CK_ULONG key_type, CK_ULONG value_len, CK_ULONG *key_len); CK_RV ecdh_pkcs_derive(STDLL_TokData_t *tokdata, SESSION *sess, CK_MECHANISM *mech, OBJECT *base_key_obj, CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE *derived_key_obj, CK_BBOOL count_statistic, CK_ULONG mode); // 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_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_xts_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_xts_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_xts_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_xts_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_BBOOL xts); CK_RV ckm_aes_ecb_encrypt(STDLL_TokData_t *, SESSION *sess, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, OBJECT *key); CK_RV ckm_aes_ecb_decrypt(STDLL_TokData_t *, SESSION *sess, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, OBJECT *key); CK_RV ckm_aes_cbc_encrypt(STDLL_TokData_t *, SESSION *sess, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, CK_BYTE *init_v, OBJECT *key); CK_RV ckm_aes_cbc_decrypt(STDLL_TokData_t *, SESSION *sess, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, CK_BYTE *init_v, OBJECT *key); CK_RV ckm_aes_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_xts_crypt(STDLL_TokData_t *tokdata, SESSION *sess, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, CK_BYTE *tweak, OBJECT *key, CK_BBOOL initial, CK_BBOOL final, CK_BYTE *iv, CK_BBOOL encrypt); CK_RV aes_xts_cipher(CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, CK_BYTE *tweak, CK_BOOL encrypt, CK_BBOOL initial, CK_BBOOL final, CK_BYTE* iv, CK_RV (*iv_from_tweak)(CK_BYTE *tweak, CK_BYTE* iv, void * cb_data), CK_RV (*cipher_blocks)(CK_BYTE *in, CK_BYTE *out, CK_ULONG len, CK_BYTE *iv, void * cb_data), void *cb_data); CK_RV ckm_aes_wrap_format(STDLL_TokData_t *tokdata, CK_BBOOL length_only, CK_ULONG block_size, 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_gcm_dup_param(CK_GCM_PARAMS *from, CK_GCM_PARAMS *to); CK_RV aes_gcm_free_param(CK_GCM_PARAMS *params); void aes_gcm_param_from_compat(const CK_GCM_PARAMS_COMPAT *from, CK_GCM_PARAMS *to); 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); CK_RV aes_xts_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_xts_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_key_wrap_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_key_wrap_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); // SHA mechanisms // CK_RV 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 sha_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 sha_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); CK_RV ckm_sha_derive(STDLL_TokData_t *tokdata, SESSION *sess, CK_MECHANISM *mech, OBJECT *base_key_obj, CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE *derived_key_obj, CK_BBOOL count_statistic); CK_RV ckm_shake_derive(STDLL_TokData_t *tokdata, SESSION *sess, CK_MECHANISM *mech, OBJECT *base_key_obj, CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE *derived_key_obj); #if !(NOMD2) // 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); #endif // 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); CK_RV 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_edwards_key_pair_gen(STDLL_TokData_t *tokdata, TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl); CK_RV ckm_ec_montgomery_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_MECHANISM *mech); 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_MECHANISM *mech); 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 ckm_ecdh_pkcs_derive(STDLL_TokData_t *tokdata, SESSION *sess, CK_VOID_PTR other_pubkey, CK_ULONG other_pubkey_len, OBJECT* base_key_obj, CK_BYTE *secret_value, CK_ULONG *secret_value_len, CK_MECHANISM_PTR mech, CK_BBOOL count_statistic); 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_RV ckm_kdf_sp800_56c(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, uint32_t purpose, CK_BYTE *key, CK_ULONG key_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); CK_RV ec_point_from_priv_key(CK_BYTE *parms, CK_ULONG parms_len, CK_BYTE *d, CK_ULONG d_len, CK_BYTE **point, CK_ULONG *point_len); int ec_point_from_public_data(const CK_BYTE *data, CK_ULONG data_len, CK_ULONG prime_len, CK_BBOOL allow_raw, CK_BBOOL *allocated, CK_BYTE **ec_point, CK_ULONG *ec_point_len); int ec_point_uncompressed_from_public_data(const CK_BYTE *data, CK_ULONG data_len, CK_ULONG prime_len, CK_BYTE *curve_oid, CK_ULONG curve_oid_len, CK_BBOOL allow_raw, CK_BBOOL *allocated, CK_BYTE **ec_point, CK_ULONG *ec_point_len); CK_RV ec_agg_dup_param(CK_IBM_ECDSA_OTHER_BLS_PARAMS *from, CK_IBM_ECDSA_OTHER_BLS_PARAMS *to); CK_RV ec_agg_free_param(CK_IBM_ECDSA_OTHER_BLS_PARAMS *params); 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); //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(STDLL_TokData_t *tokdata, 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_BBOOL checkpolicy); CK_RV encr_mgr_cleanup(STDLL_TokData_t *tokdata, SESSION *sess, 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); CK_RV encr_mgr_reencrypt_single(STDLL_TokData_t *tokdata, SESSION *sess, ENCR_DECR_CONTEXT *decr_ctx, CK_MECHANISM *decr_mech, CK_OBJECT_HANDLE decr_key, ENCR_DECR_CONTEXT *encr_ctx, CK_MECHANISM *encr_mech, CK_OBJECT_HANDLE encr_key, 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_BBOOL checkpolicy, CK_BBOOL checkauth); CK_RV decr_mgr_cleanup(STDLL_TokData_t *tokdata, SESSION *sess, 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(STDLL_TokData_t *tokdata, SESSION *sess, DIGEST_CONTEXT *ctx); CK_RV digest_mgr_init(STDLL_TokData_t *tokdata, SESSION *sess, DIGEST_CONTEXT *ctx, CK_MECHANISM *mech, CK_BBOOL checkpolicy); 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_apply_always_sensitive_never_extractable_attrs( STDLL_TokData_t *tokdata, OBJECT *key_obj); CK_RV key_mgr_derive_always_sensitive_never_extractable_attrs( STDLL_TokData_t *tokdata, OBJECT *base_key_obj, OBJECT *derived_key_obj); 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_BBOOL count_statistics, CK_ULONG operation); 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_BBOOL count_statistics, CK_ULONG operation); CK_RV key_mgr_get_private_key_type(CK_BYTE *keydata, CK_ULONG keylen, CK_KEY_TYPE *keytype, CK_KEY_TYPE *alt_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_BBOOL count_statistics, CK_ULONG operation); 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_BBOOL count_statistics, CK_ULONG operation); 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_BBOOL count_statistics, CK_ULONG operation); CK_RV key_mgr_encapsulate_key(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, CK_MECHANISM *pMechanism, CK_OBJECT_HANDLE hPublicKey, CK_ATTRIBUTE *pTemplate, CK_ULONG ulAttributeCount, CK_BYTE *pCiphertext, CK_ULONG *pulCiphertextLen, CK_OBJECT_HANDLE *phKey, CK_BBOOL count_statistics); CK_RV key_mgr_decapsulate_key(STDLL_TokData_t *tokdata, SESSION *sess, CK_MECHANISM *pMechanism, CK_OBJECT_HANDLE hPrivateKey, CK_ATTRIBUTE *pTemplate, CK_ULONG ulAttributeCount, CK_BYTE *pCiphertext, CK_ULONG ulCiphertextLen, CK_OBJECT_HANDLE *phKey, CK_BBOOL count_statistics); // 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_BBOOL checkpolicy, CK_BBOOL checkauth); CK_RV sign_mgr_cleanup(STDLL_TokData_t *tokdata, SESSION *sess, 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_BBOOL checkpolicy); CK_RV verify_mgr_cleanup(STDLL_TokData_t *tokdata, SESSION *sess, 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); SESSION *session_mgr_find_reset_error(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(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, CK_BYTE *data, CK_ULONG *data_len); CK_RV session_mgr_set_op_state(STDLL_TokData_t *tokdata, SESSION *sess, CK_OBJECT_HANDLE encr_key, CK_OBJECT_HANDLE auth_key, CK_BYTE *data, CK_ULONG data_len); CK_RV session_mgr_cancel(STDLL_TokData_t *tokdata, SESSION *sess, CK_FLAGS flags); 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 *); #define CONTEXT_TYPE_DIGEST 1 #define CONTEXT_TYPE_SIGN 2 #define CONTEXT_TYPE_VERIFY 3 #define CONTEXT_TYPE_ENCRYPT 4 #define CONTEXT_TYPE_DECRYPT 5 CK_RV session_mgr_iterate_session_ops(STDLL_TokData_t *tokdata, SESSION *session, CK_RV (*cb)(STDLL_TokData_t *tokdata, SESSION *session, CK_ULONG ctx_type, CK_MECHANISM *mech, CK_OBJECT_HANDLE key, CK_BYTE *context, CK_ULONG context_len, CK_BBOOL init_pending, CK_BBOOL pkey_active, CK_BBOOL recover, void *private), void *private); // object manager routines // CK_RV object_mgr_add(STDLL_TokData_t *tokdata, SESSION *sess, CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE *handle, CK_ULONG mode); 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_get_shm_entry_for_obj(STDLL_TokData_t *tokdata, OBJECT *obj, TOK_OBJ_ENTRY **entry); CK_RV object_mgr_check_shm(STDLL_TokData_t *tokdata, OBJECT *obj, OBJ_LOCK_TYPE lock_type); 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_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_withSize(STDLL_TokData_t *tokdata, CK_BYTE *data, OBJECT *oldObj, CK_ULONG data_size, const char *fname); CK_RV object_mgr_save_token_object(STDLL_TokData_t *tokdata, OBJECT *obj); 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); CK_RV obj_mgr_reencipher_secure_key(STDLL_TokData_t *tokdata, OBJECT *obj, CK_RV (*reenc)(CK_BYTE *sec_key, CK_BYTE *reenc_sec_key, CK_ULONG sec_key_len, void *private), void *private); CK_RV obj_mgr_reencipher_secure_key_finalize(STDLL_TokData_t *tokdata, OBJECT *obj, CK_BBOOL is_blob_new_mk_cb( STDLL_TokData_t *tokdata, OBJECT *obj, CK_BYTE *sec_key, CK_ULONG sec_key_len, void *cb_private), void *cb_private); CK_RV obj_mgr_reencipher_secure_key_cancel(STDLL_TokData_t *tokdata, OBJECT *obj); CK_RV obj_mgr_iterate_key_objects(STDLL_TokData_t *tokdata, CK_BBOOL session_objects, CK_BBOOL token_objects, CK_BBOOL(*filter)(STDLL_TokData_t *tokdata, OBJECT *obj, void *filter_data), void *filter_data, CK_RV (*cb)(STDLL_TokData_t *tokdata, OBJECT *obj, void *cb_data), void *cb_data, CK_BBOOL syslog, const char *msg); /* structures used to hold arguments to callback functions triggered by either * bt_for_each_node or bt_node_free */ struct find_args { 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_ULONG mode); 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, SESSION *sess, 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_withSize(struct policy *policy, CK_BYTE *data, OBJECT **obj, CK_BBOOL replace, CK_ULONG data_size, const char *fname); CK_RV object_set_attribute_values(STDLL_TokData_t *tokdata, SESSION *sess, OBJECT *obj, CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount); CK_BBOOL object_is_modifiable(OBJECT *obj); CK_BBOOL object_is_copyable(OBJECT *obj); CK_BBOOL object_is_destroyable(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_BBOOL object_is_extractable(OBJECT *obj); CK_BBOOL object_is_pkey_extractable(OBJECT *obj); CK_BBOOL object_is_attr_bound(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); CK_RV object_init_ex_data_lock(OBJECT *obj); CK_RV object_destroy_ex_data_lock(OBJECT *obj); CK_RV object_ex_data_lock(OBJECT *obj, OBJ_LOCK_TYPE type); CK_RV object_ex_data_unlock(OBJECT *obj); // object attribute template routines // CK_RV template_add_attributes(TEMPLATE *tmpl, CK_ATTRIBUTE *attr, CK_ULONG ulCount); CK_RV template_add_default_attributes(STDLL_TokData_t *tokdata, 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); CK_RV template_attribute_get_ulong(TEMPLATE *tmpl, CK_ATTRIBUTE_TYPE type, CK_ULONG *value); CK_RV template_attribute_get_bool(TEMPLATE *tmpl, CK_ATTRIBUTE_TYPE type, CK_BBOOL *value); CK_RV template_attribute_get_non_empty(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_BBOOL private); CK_RV template_merge(TEMPLATE *dest, TEMPLATE **src); CK_RV template_remove_attribute(TEMPLATE *tmpl, CK_ATTRIBUTE_TYPE type); CK_RV template_update_attribute(TEMPLATE *tmpl, CK_ATTRIBUTE *attr); CK_RV template_build_update_attribute(TEMPLATE * tmpl, CK_ATTRIBUTE_TYPE type, CK_BYTE * data, CK_ULONG data_len); CK_RV template_unflatten_withSize(TEMPLATE **new_tmpl, CK_BYTE *buf, CK_ULONG count, CK_ULONG 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); #ifdef DEBUG void dump_template(TEMPLATE *tmpl); #define TRACE_DEBUG_DUMPTEMPL(x) dump_template(x) #else #define TRACE_DEBUG_DUMPTEMPL(...) #endif // 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); // PROFILE OBJECT ROUTINES CK_RV profile_object_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); CK_RV profile_object_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode); CK_RV profile_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_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode); CK_RV cert_validate_attribute(STDLL_TokData_t *tokdata, 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(STDLL_TokData_t *tokdata, 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(STDLL_TokData_t *tokdata, 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_BBOOL key_object_is_mechanism_allowed(TEMPLATE *tmpl, CK_MECHANISM_TYPE mech); CK_BBOOL key_object_wrap_template_matches(TEMPLATE *wrap_tmpl, TEMPLATE *tmpl); CK_RV key_object_apply_template_attr(TEMPLATE *unwrap_tmpl, CK_ATTRIBUTE_TYPE attr_type, CK_ATTRIBUTE_PTR attrs, CK_ULONG attrs_count, CK_ATTRIBUTE_PTR *new_attrs, CK_ULONG *new_attrs_count); CK_RV key_object_is_always_authenticate(TEMPLATE *tmpl, CK_BBOOL *auth); CK_RV key_pub_from_priv(STDLL_TokData_t *tokdata, SESSION *sess, OBJECT *priv_key_obj, CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE *pub_key_handle); 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 publ_key_get_spki(TEMPLATE *tmpl, CK_ULONG keytype, CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, CK_BBOOL is_priv_tmpl); 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_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_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_RV rsa_publ_get_spki(TEMPLATE *tmpl, CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len); 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_RV rsa_priv_unwrap_get_data(TEMPLATE *tmpl, CK_BYTE *data, CK_ULONG total_length, CK_BBOOL is_public); CK_RV rsa_priv_check_and_swap_pq(TEMPLATE *tmpl); // 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_RV dsa_publ_get_spki(TEMPLATE *tmpl, CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len); 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, CK_BBOOL is_public); // ecdsa routines // CK_RV ec_publ_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); CK_RV ec_publ_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode, CK_KEY_TYPE key_type); CK_RV ec_publ_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_ATTRIBUTE *attr, CK_ULONG mode); CK_RV ec_publ_get_spki(TEMPLATE *tmpl, CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, CK_KEY_TYPE key_type); CK_BBOOL ec_priv_check_exportability(CK_ATTRIBUTE_TYPE type); CK_RV ec_priv_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); CK_RV ec_priv_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode, CK_KEY_TYPE key_type); CK_RV ec_priv_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_ATTRIBUTE *attr, CK_ULONG mode, CK_KEY_TYPE key_type); CK_RV ec_priv_wrap_get_data(TEMPLATE *tmpl, CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, CK_KEY_TYPE key_type); CK_RV ec_priv_unwrap_get_data(TEMPLATE *tmpl, CK_BYTE *data, CK_ULONG data_len, CK_BBOOL is_public, CK_KEY_TYPE key_type); CK_RV ec_priv_unwrap(TEMPLATE *tmpl, CK_BYTE *data, CK_ULONG data_len, CK_KEY_TYPE key_type); // IBM ML-DSA and Dilithium routines // CK_RV ibm_ml_dsa_publ_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode, CK_MECHANISM_TYPE mech); CK_RV ibm_ml_dsa_publ_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode, CK_KEY_TYPE key_type); CK_RV ibm_ml_dsa_publ_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_ATTRIBUTE *attr, CK_ULONG mode, CK_MECHANISM_TYPE mech); CK_RV ibm_ml_dsa_publ_get_spki(TEMPLATE *tmpl, CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, CK_MECHANISM_TYPE mech); CK_RV ibm_ml_dsa_priv_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode, CK_MECHANISM_TYPE mech); CK_RV ibm_ml_dsa_priv_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode, CK_KEY_TYPE key_type); CK_RV ibm_ml_dsa_priv_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_ATTRIBUTE *attr, CK_ULONG mode, CK_MECHANISM_TYPE mech); CK_BBOOL ibm_ml_dsa_priv_check_exportability(CK_ATTRIBUTE_TYPE type); CK_RV ibm_ml_dsa_priv_wrap_get_data(TEMPLATE *tmpl, CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, CK_MECHANISM_TYPE mech); CK_RV ibm_ml_dsa_priv_unwrap(TEMPLATE *tmpl, CK_BYTE *data, CK_ULONG total_length, CK_BBOOL add_value, CK_MECHANISM_TYPE mech); CK_RV ibm_ml_dsa_priv_unwrap_get_data(TEMPLATE *tmpl, CK_BYTE *data, CK_ULONG total_length, CK_BBOOL is_public, CK_MECHANISM_TYPE mech); // IBM ML-KEM and Kyber routines // CK_RV ibm_ml_kem_publ_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode, CK_MECHANISM_TYPE mech); CK_RV ibm_ml_kem_publ_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode, CK_KEY_TYPE key_type); CK_RV ibm_ml_kem_publ_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_ATTRIBUTE *attr, CK_ULONG mode, CK_MECHANISM_TYPE mech); CK_RV ibm_ml_kem_publ_get_spki(TEMPLATE *tmpl, CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, CK_MECHANISM_TYPE mech); CK_RV ibm_ml_kem_priv_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode, CK_MECHANISM_TYPE mech); CK_RV ibm_ml_kem_priv_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode, CK_KEY_TYPE key_type); CK_RV ibm_ml_kem_priv_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_ATTRIBUTE *attr, CK_ULONG mode, CK_MECHANISM_TYPE mech); CK_BBOOL ibm_ml_kem_priv_check_exportability(CK_ATTRIBUTE_TYPE type); CK_RV ibm_ml_kem_priv_wrap_get_data(TEMPLATE *tmpl, CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, CK_MECHANISM_TYPE mech); CK_RV ibm_ml_kem_priv_unwrap(TEMPLATE *tmpl, CK_BYTE *data, CK_ULONG total_length, CK_BBOOL add_value, CK_MECHANISM_TYPE mech); CK_RV ibm_ml_kem_priv_unwrap_get_data(TEMPLATE *tmpl, CK_BYTE *data, CK_ULONG total_length, CK_BBOOL is_public, CK_MECHANISM_TYPE mech); // ML-DSA routines // CK_RV ml_dsa_publ_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode); CK_RV ml_dsa_priv_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode); CK_RV ml_dsa_publ_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); CK_RV ml_dsa_priv_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); CK_RV ml_dsa_publ_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_ATTRIBUTE *attr, CK_ULONG mode); CK_RV ml_dsa_priv_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_ATTRIBUTE *attr, CK_ULONG mode); CK_BBOOL ml_dsa_priv_check_exportability(CK_ATTRIBUTE_TYPE type); CK_RV ml_dsa_publ_get_spki(TEMPLATE *tmpl, CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, CK_BBOOL is_priv_tmpl); CK_RV ml_dsa_priv_wrap_get_data(TEMPLATE *tmpl, CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len); CK_RV ml_dsa_priv_unwrap_get_data(TEMPLATE *tmpl, CK_BYTE *data, CK_ULONG total_length, CK_BBOOL is_public); CK_RV ml_dsa_priv_unwrap(TEMPLATE *tmpl, CK_BYTE *data, CK_ULONG total_length, CK_BBOOL add_value); // ML-KEM routines // CK_RV ml_kem_publ_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode); CK_RV ml_kem_priv_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode); CK_RV ml_kem_publ_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); CK_RV ml_kem_priv_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); CK_RV ml_kem_publ_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_ATTRIBUTE *attr, CK_ULONG mode); CK_RV ml_kem_priv_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_ATTRIBUTE *attr, CK_ULONG mode); CK_BBOOL ml_kem_priv_check_exportability(CK_ATTRIBUTE_TYPE type); CK_RV ml_kem_publ_get_spki(TEMPLATE *tmpl, CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, CK_BBOOL is_priv_tmpl); CK_RV ml_kem_priv_wrap_get_data(TEMPLATE *tmpl, CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len); CK_RV ml_kem_priv_unwrap_get_data(TEMPLATE *tmpl, CK_BYTE *data, CK_ULONG total_length, CK_BBOOL is_public); CK_RV ml_kem_priv_unwrap(TEMPLATE *tmpl, CK_BYTE *data, CK_ULONG total_length, CK_BBOOL add_value); // PQC helper routines // CK_RV pqc_publ_get_spki(TEMPLATE *tmpl, CK_KEY_TYPE keytype, CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, CK_BBOOL is_priv_tmpl); CK_RV pqc_priv_wrap_get_data(TEMPLATE *tmpl, CK_KEY_TYPE keytype, CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len); CK_RV pqc_priv_unwrap(TEMPLATE *tmpl, CK_KEY_TYPE keytype, CK_BYTE *data, CK_ULONG total_length, CK_BBOOL add_value); CK_RV pqc_priv_unwrap_get_data(TEMPLATE *tmpl, CK_KEY_TYPE keytype, CK_BYTE *data, CK_ULONG total_length, CK_BBOOL is_public); const struct pqc_oid *pqc_get_keyform_mode(TEMPLATE *tmpl, CK_MECHANISM_TYPE mech); CK_RV pqc_add_keyform_mode(TEMPLATE *tmpl, const struct pqc_oid *oid, CK_MECHANISM_TYPE mech); // 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_RV dh_publ_get_spki(TEMPLATE *tmpl, CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len); 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_BBOOL is_public); CK_RV dh_priv_unwrap(TEMPLATE *tmpl, CK_BYTE *data, CK_ULONG data_len); // 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_KEY_TYPE key_type); 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); // 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_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_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, TEMPLATE *basetmpl, CK_ULONG mode, CK_BBOOL xts); CK_RV aes_unwrap(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_BYTE *data, CK_ULONG data_len, CK_BBOOL fromend, CK_BBOOL xts); CK_RV aes_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_ATTRIBUTE *attr, CK_ULONG mode, CK_BBOOL xts); CK_RV aes_wrap_get_data(TEMPLATE *tmpl, CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len); // 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_ULONG ber_int_len, CK_BYTE **data, CK_ULONG *data_len, CK_ULONG *field_len); 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_RV ber_decode_BIT_STRING(CK_BYTE *str, CK_ULONG str_len, 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_ULONG str_len, 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_ULONG seq_len, CK_BYTE **data, CK_ULONG *data_len, CK_ULONG *field_len); 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_BBOOL constructed); CK_RV ber_decode_CHOICE(CK_BYTE *choice, CK_ULONG choice_len, CK_BBOOL constructed, CK_BYTE **data, CK_ULONG *data_len, CK_ULONG *field_len, CK_ULONG *option); 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_ULONG *priv_key_len); CK_RV ber_decode_SPKI(CK_BYTE *spki, CK_ULONG spki_len, 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_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_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 *pubkey, CK_KEY_TYPE key_type); CK_RV der_decode_ECPrivateKey(CK_BYTE *data, CK_ULONG data_len, CK_ATTRIBUTE **params, CK_ATTRIBUTE **pub_key, CK_ATTRIBUTE **priv_key, CK_KEY_TYPE key_type); CK_RV ber_encode_ECPublicKey(CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, CK_ATTRIBUTE *params, CK_ATTRIBUTE *point, CK_KEY_TYPE key_type); CK_RV der_decode_ECPublicKey(CK_BYTE *data, CK_ULONG data_len, CK_ATTRIBUTE **params, CK_ATTRIBUTE **point, CK_KEY_TYPE key_type); 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_ML_DSA_PublicKey(CK_MECHANISM_TYPE mech, CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, const CK_BYTE *oid, CK_ULONG oid_len, CK_ATTRIBUTE *rho, CK_ATTRIBUTE *t1); CK_RV ber_decode_IBM_ML_DSA_PublicKey(CK_MECHANISM_TYPE mech, CK_BYTE *data, CK_ULONG data_len, CK_ATTRIBUTE **rho_attr, CK_ATTRIBUTE **t1_attr, CK_ATTRIBUTE **value_attr, const struct pqc_oid **oid); CK_RV ber_encode_IBM_ML_DSA_PrivateKey(CK_MECHANISM_TYPE mech, CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, const CK_BYTE *oid, CK_ULONG oid_len, CK_ATTRIBUTE *rho, CK_ATTRIBUTE *seed, CK_ATTRIBUTE *tr, CK_ATTRIBUTE *s1, CK_ATTRIBUTE *s2, CK_ATTRIBUTE *t0, CK_ATTRIBUTE *t1, CK_ATTRIBUTE *priv_seed); CK_RV ber_decode_IBM_ML_DSA_PrivateKey(CK_MECHANISM_TYPE mech, 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 **priv_seed, CK_ATTRIBUTE **value, const struct pqc_oid **oid); CK_RV ber_encode_IBM_ML_KEM_PublicKey(CK_MECHANISM_TYPE mech, CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, const CK_BYTE *oid, CK_ULONG oid_len, CK_ATTRIBUTE *pk); CK_RV ber_decode_IBM_ML_KEM_PublicKey(CK_MECHANISM_TYPE mech, CK_BYTE *data, CK_ULONG data_len, CK_ATTRIBUTE **pk_attr, CK_ATTRIBUTE **value_attr, const struct pqc_oid **oid); CK_RV ber_encode_IBM_ML_KEM_PrivateKey(CK_MECHANISM_TYPE mech, CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, const CK_BYTE *oid, CK_ULONG oid_len, CK_ATTRIBUTE *sk, CK_ATTRIBUTE *pk, CK_ATTRIBUTE *priv_seed); CK_RV ber_decode_IBM_ML_KEM_PrivateKey(CK_MECHANISM_TYPE mech, CK_BYTE *data, CK_ULONG data_len, CK_ATTRIBUTE **sk, CK_ATTRIBUTE **pk, CK_ATTRIBUTE **priv_seed, CK_ATTRIBUTE **value, const struct pqc_oid **oid); CK_RV ber_encode_ML_DSA_PublicKey(CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, const CK_BYTE *oid, CK_ULONG oid_len, CK_ATTRIBUTE *value); CK_RV ber_decode_ML_DSA_PublicKey(CK_BYTE *data, CK_ULONG data_len, CK_ATTRIBUTE **value_attr, const struct pqc_oid **oid); CK_RV ber_encode_ML_DSA_PrivateKey(CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, const CK_BYTE *oid, CK_ULONG oid_len, CK_ATTRIBUTE *value, CK_ATTRIBUTE *seed); CK_RV ber_decode_ML_DSA_PrivateKey(CK_BYTE *data, CK_ULONG data_len, CK_ATTRIBUTE **value, CK_ATTRIBUTE **seed, const struct pqc_oid **oid); CK_RV ber_encode_ML_KEM_PublicKey(CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, const CK_BYTE *oid, CK_ULONG oid_len, CK_ATTRIBUTE *value); CK_RV ber_decode_ML_KEM_PublicKey(CK_BYTE *data, CK_ULONG data_len, CK_ATTRIBUTE **value_attr, const struct pqc_oid **oid); CK_RV ber_encode_ML_KEM_PrivateKey(CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, const CK_BYTE *oid, CK_ULONG oid_len, CK_ATTRIBUTE *value, CK_ATTRIBUTE *seed); CK_RV ber_decode_ML_KEM_PrivateKey(CK_BYTE *data, CK_ULONG data_len, CK_ATTRIBUTE **value, CK_ATTRIBUTE **seed, const struct pqc_oid **oid); typedef CK_RV (*t_rsa_encrypt)(STDLL_TokData_t *, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, OBJECT *key_obj); typedef CK_RV (*t_rsa_decrypt)(STDLL_TokData_t *, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, OBJECT *key_obj); struct openssl_ex_data { EVP_PKEY *pkey; }; void openssl_free_ex_data(OBJECT *obj, void *ex_data, size_t ex_data_len); CK_RV openssl_get_ex_data(OBJECT *obj, void **ex_data, size_t ex_data_len, CK_BBOOL (*need_wr_lock)(OBJECT *obj, void *ex_data, size_t ex_data_len), void (*ex_data_free)(struct _OBJECT *obj, void *ex_data, size_t ex_data_len)); CK_RV openssl_specific_rsa_keygen(TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl); CK_RV openssl_specific_rsa_encrypt(STDLL_TokData_t *, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, OBJECT *key_obj); CK_RV openssl_specific_rsa_decrypt(STDLL_TokData_t *, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, OBJECT *key_obj); CK_RV openssl_specific_rsa_pkcs_decrypt(STDLL_TokData_t *, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *, OBJECT *, t_rsa_decrypt); CK_RV openssl_specific_rsa_pkcs_encrypt(STDLL_TokData_t *, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *, OBJECT *, t_rsa_encrypt); CK_RV openssl_specific_rsa_pkcs_sign(STDLL_TokData_t *, SESSION *, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *, OBJECT *, t_rsa_decrypt); CK_RV openssl_specific_rsa_pkcs_verify(STDLL_TokData_t *tokdata, SESSION *, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG, OBJECT *, t_rsa_encrypt); CK_RV openssl_specific_rsa_pkcs_verify_recover(STDLL_TokData_t *tokdata, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *, OBJECT *, t_rsa_encrypt); CK_RV openssl_specific_rsa_pss_sign(STDLL_TokData_t *, SESSION *, SIGN_VERIFY_CONTEXT *, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *, t_rsa_decrypt); CK_RV openssl_specific_rsa_pss_verify(STDLL_TokData_t *, SESSION *, SIGN_VERIFY_CONTEXT *, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG, t_rsa_encrypt); CK_RV openssl_specific_rsa_x509_encrypt(STDLL_TokData_t *tokdata, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *, OBJECT *, t_rsa_encrypt); CK_RV openssl_specific_rsa_x509_decrypt(STDLL_TokData_t *tokdata, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *, OBJECT *, t_rsa_decrypt); CK_RV openssl_specific_rsa_x509_sign(STDLL_TokData_t *tokdata, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *, OBJECT *, t_rsa_decrypt); CK_RV openssl_specific_rsa_x509_verify(STDLL_TokData_t *tokdata, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG, OBJECT *, t_rsa_encrypt); CK_RV openssl_specific_rsa_x509_verify_recover(STDLL_TokData_t *tokdata, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *, OBJECT *, t_rsa_encrypt); CK_RV openssl_specific_rsa_oaep_encrypt(STDLL_TokData_t *, ENCR_DECR_CONTEXT *, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *, CK_BYTE *, CK_ULONG, t_rsa_encrypt); CK_RV openssl_specific_rsa_oaep_decrypt(STDLL_TokData_t *, ENCR_DECR_CONTEXT *, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *, CK_BYTE *, CK_ULONG, t_rsa_decrypt); CK_RV openssl_make_ec_key_from_template(TEMPLATE *template, EVP_PKEY **pkey); CK_RV openssl_specific_ec_generate_keypair(STDLL_TokData_t *tokdata, TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl, CK_MECHANISM_TYPE mech); #if OPENSSL_VERSION_PREREQ(3, 0) CK_RV openssl_ec_edwards_point_from_priv_key(CK_BYTE *parms, CK_ULONG parms_len, CK_BYTE *priv, CK_ULONG priv_len, CK_BYTE **point, CK_ULONG *point_len); #endif CK_RV openssl_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); CK_RV openssl_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); CK_RV openssl_specific_ec_edwards_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_MECHANISM *mech); CK_RV openssl_specific_ec_edwards_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, CK_MECHANISM *mech); CK_RV openssl_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, CK_BBOOL cofactor_mode); CK_RV openssl_specific_sha_init(STDLL_TokData_t *tokdata, DIGEST_CONTEXT *ctx, CK_MECHANISM *mech); CK_RV openssl_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); CK_RV openssl_specific_sha_update(STDLL_TokData_t *tokdata, DIGEST_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len); CK_RV openssl_specific_sha_final(STDLL_TokData_t *tokdata, DIGEST_CONTEXT *ctx, CK_BYTE *out_data, CK_ULONG *out_data_len); CK_RV openssl_specific_shake_key_derive(STDLL_TokData_t *tokdata, SESSION *sess, CK_MECHANISM *mech, OBJECT *base_key_obj, CK_KEY_TYPE base_key_type, OBJECT *derived_key_obj, CK_KEY_TYPE derived_key_type, CK_ULONG derived_key_len); CK_RV openssl_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_RV openssl_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 openssl_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 openssl_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, CK_BYTE encrypt); CK_RV openssl_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, CK_ULONG cfb_len, CK_BYTE encrypt); CK_RV openssl_specific_aes_gcm_init(STDLL_TokData_t *tokdata, SESSION *sess, ENCR_DECR_CONTEXT *ctx, CK_MECHANISM *mech, CK_OBJECT_HANDLE hkey, CK_BYTE encrypt); CK_RV openssl_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 openssl_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 openssl_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 openssl_specific_aes_mac(STDLL_TokData_t *tokdata, CK_BYTE *message, CK_ULONG message_len, OBJECT *key, CK_BYTE *mac); CK_RV openssl_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 openssl_specific_aes_xts(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 *tweak, CK_BOOL encrypt, CK_BBOOL initial, CK_BBOOL final, CK_BYTE* iv); CK_RV openssl_specific_aes_key_wrap(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 *iv, CK_ULONG iv_len, CK_BBOOL encrypt, CK_BBOOL pad); CK_RV openssl_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 openssl_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 openssl_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 openssl_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 openssl_specific_tdes_ofb(STDLL_TokData_t *tokdata, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, OBJECT *key, CK_BYTE *init_v, CK_BYTE encrypt); CK_RV openssl_specific_tdes_cfb(STDLL_TokData_t *tokdata, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, OBJECT *key, CK_BYTE *init_v, CK_ULONG cfb_len, CK_BYTE encrypt); CK_RV openssl_specific_tdes_mac(STDLL_TokData_t *tokdata, CK_BYTE *message, CK_ULONG message_len, OBJECT *key, CK_BYTE *mac); CK_RV openssl_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 openssl_specific_hmac_init(STDLL_TokData_t *tokdata, SIGN_VERIFY_CONTEXT *ctx, CK_MECHANISM_PTR mech, CK_OBJECT_HANDLE Hkey); CK_RV openssl_specific_hmac(SIGN_VERIFY_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *signature, CK_ULONG *sig_len, CK_BBOOL sign); CK_RV openssl_specific_hmac_update(SIGN_VERIFY_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BBOOL sign); CK_RV openssl_specific_hmac_final(SIGN_VERIFY_CONTEXT *ctx, CK_BYTE *signature, CK_ULONG *sig_len, CK_BBOOL sign); CK_RV openssl_specific_rsa_derive_kdk(STDLL_TokData_t *tokdata, OBJECT *key_obj, const CK_BYTE *in, CK_ULONG inlen, CK_BYTE *kdk, CK_ULONG kdklen); CK_RV openssl_specific_rsa_prf(CK_BYTE *out, CK_ULONG outlen, const char *label, CK_ULONG labellen, const CK_BYTE *kdk, CK_ULONG kdklen, uint16_t bitlen); CK_RV calc_rsa_crt_from_me(CK_ATTRIBUTE *modulus, CK_ATTRIBUTE *pub_exp, CK_ATTRIBUTE *priv_exp, CK_ATTRIBUTE **prime1, CK_ATTRIBUTE **prime2, CK_ATTRIBUTE **exponent1, CK_ATTRIBUTE **exponent2, CK_ATTRIBUTE **coef); #if OPENSSL_VERSION_PREREQ(3, 0) const char *openssl_get_pqc_oid_name(const struct pqc_oid *oid); CK_RV openssl_get_key_from_pkey(EVP_PKEY *pkey, const char *param, CK_BYTE **key, size_t *key_len, CK_BBOOL check); CK_RV openssl_specific_pqc_generate_keypair(STDLL_TokData_t *tokdata, const struct pqc_oid *oid, CK_MECHANISM *mech, TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl); CK_RV openssl_make_pqc_key_from_template(TEMPLATE *tmpl, const struct pqc_oid *oid, CK_MECHANISM_TYPE mech, CK_BBOOL private_key, const char *alg_name, EVP_PKEY **pkey); CK_RV openssl_specific_pqc_get_pub_key_from_priv_key(TEMPLATE *priv_tmpl, const struct pqc_oid *oid, CK_MECHANISM_TYPE mech, CK_ATTRIBUTE *pub_value); CK_RV openssl_specific_pqc_sign(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, const struct pqc_oid *oid, CK_MECHANISM *mech, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *signature, CK_ULONG *signature_len, OBJECT *key_obj, CK_BBOOL final_part); CK_RV openssl_specific_pqc_verify(STDLL_TokData_t *tokdata, SESSION *sess, const struct pqc_oid *oid, CK_MECHANISM *mech, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *signature, CK_ULONG signature_len, OBJECT *key_obj, CK_BBOOL final_part); CK_RV openssl_specific_pqc_kem_derive(STDLL_TokData_t *tokdata, SESSION *sess, const struct pqc_oid *oid, CK_MECHANISM *mech, OBJECT *base_object, CK_OBJECT_CLASS base_key_class, CK_KEY_TYPE base_key_type, OBJECT *derived_object, CK_KEY_TYPE derived_key_type, CK_ULONG derived_keylen); CK_RV openssl_specific_pqc_encapsulate_key(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, const struct pqc_oid *oid, CK_MECHANISM *mech, OBJECT *key_obj, CK_ATTRIBUTE *pTemplate, CK_ULONG ulAttributeCount, CK_BYTE *pCiphertext, CK_ULONG *pulCiphertextLen, CK_KEY_TYPE keytype, CK_ULONG keylen, CK_OBJECT_HANDLE *phKey); CK_RV openssl_specific_pqc_decapsulate_key(STDLL_TokData_t *tokdata, SESSION *sess, const struct pqc_oid *oid, CK_MECHANISM *mech, OBJECT *key_obj, CK_ATTRIBUTE *pTemplate, CK_ULONG ulAttributeCount, CK_BYTE *pCiphertext, CK_ULONG ulCiphertextLen, CK_KEY_TYPE keytype, CK_ULONG keylen, CK_OBJECT_HANDLE *phKey); #endif #include "tok_spec_struct.h" extern token_spec_t token_specific; /* 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 /* * Opencryptoki internal mechanisms for SHAKE, not defined by PKCS#11. * The have a CK_ULONG mechanism parameter specifying the output size. */ #define CKM_OCK_SHAKE128 CKM_VENDOR_DEFINED + 0x01000001 #define CKM_OCK_SHAKE256 CKM_VENDOR_DEFINED + 0x01000002 #endif opencryptoki-opencryptoki-451d99c/usr/lib/common/host_defs.h000066400000000000000000000322631520105705100243300ustar00rootroot00000000000000/* * 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 #if defined(_AIX) #include #else #include #endif #include "pkcs32.h" #include #include #include "local_types.h" #include "../api/policy.h" #include "../api/mechtable.h" #include "../api/statistics.h" struct _SESSION; typedef void (*context_free_func_t)(STDLL_TokData_t *tokdata, struct _SESSION *sess, CK_BYTE *context, CK_ULONG context_len); typedef struct _ENCR_DECR_CONTEXT { CK_OBJECT_HANDLE key; CK_MECHANISM mech; CK_BYTE *context; CK_ULONG context_len; context_free_func_t context_free_func; 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 CK_BBOOL pkey_active; CK_BBOOL state_unsaveable; CK_BBOOL count_statistics; CK_BBOOL auth_required; } ENCR_DECR_CONTEXT; typedef struct _DIGEST_CONTEXT { CK_MECHANISM mech; CK_BYTE *context; CK_ULONG context_len; context_free_func_t context_free_func; CK_BBOOL multi; CK_BBOOL active; CK_BBOOL multi_init; // multi field is initialized // on first call *after* init CK_BBOOL state_unsaveable; CK_BBOOL count_statistics; } 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; context_free_func_t context_free_func; 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 CK_BBOOL pkey_active; CK_BBOOL state_unsaveable; CK_BBOOL count_statistics; CK_BBOOL auth_required; CK_BYTE *saved_signature; // for C_VerifySignature[Init/Update/Final] CK_ULONG saved_signature_len; } 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_XTS_CONTEXT { CK_BYTE iv[AES_INIT_VECTOR_SIZE]; CK_BYTE data[2 * AES_BLOCK_SIZE]; CK_ULONG len; CK_BBOOL initialized; } AES_XTS_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; #if !(NOMD2) 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; #endif 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; // policy support (set via store_object_strength_f pointer) struct objstrength strength; /* Allow to attach external data to an object */ void *ex_data; size_t ex_data_len; pthread_rwlock_t ex_data_rwlock; void (*ex_data_free)(struct _OBJECT *obj, void *ex_data, size_t ex_data_len); CK_RV (*ex_data_reload)(struct _OBJECT *obj, void *ex_data, size_t ex_data_len); } OBJECT; 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_CHAR library_version[16]; /* zero termination does not matter here */ CK_CHAR manufacturerID[member_size(CK_TOKEN_INFO_32, manufacturerID)]; CK_CHAR model[member_size(CK_TOKEN_INFO_32, model)]; 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 unused[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 _MP_DIGEST_CONTEXT { DIGEST_CONTEXT hash_context; CK_BBOOL flag; } MP_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_filter_mechanism_list(STDLL_TokData_t *tokdata, const MECH_LIST_ELEMENT *list, CK_ULONG listlen, MECH_LIST_ELEMENT **reslist, CK_ULONG *reslen); /* mech_list.c */ CK_RV ock_generic_get_mechanism_list(STDLL_TokData_t * tokdata, CK_MECHANISM_TYPE_PTR pMechanismList, CK_ULONG_PTR pulCount, CK_BBOOL (*filter_mechanism) (STDLL_TokData_t *tokdata, CK_MECHANISM_TYPE mechanism, CK_MECHANISM_INFO *info)); /* mech_list.c */ CK_RV ock_generic_get_mechanism_info(STDLL_TokData_t * tokdata, CK_MECHANISM_TYPE type, CK_MECHANISM_INFO_PTR pInfo, CK_BBOOL (*filter_mechanism) (STDLL_TokData_t *tokdata, CK_MECHANISM_TYPE mechanism, CK_MECHANISM_INFO *info)); typedef struct _TOK_OBJ_ENTRY { 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 tokspec_counter { uint32_t (*get_tokspec_count)(STDLL_TokData_t *tokdata); void (*incr_tokspec_count)(STDLL_TokData_t *tokdata); void (*decr_tokspec_count)(STDLL_TokData_t *tokdata); }; struct _STDLL_TokData_t { CK_SLOT_INFO slot_info; CK_SLOT_ID slot_id; pid_t real_pid; /* pid of client process in pkcsslotd namespace */ uid_t real_uid; /* uid of client process in pkcsslotd namespace */ gid_t real_gid; /* gid of client process in pkcsslotd namespace */ char tokgroup[LOGIN_NAME_MAX]; struct tokspec_counter tokspec_counter; 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; pthread_rwlock_t sess_list_rwlock; 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; struct policy *policy; const struct mechtable_funcs *mechtable_funcs; struct statistics *statistics; struct tokstore_strength store_strength; CK_BBOOL hsm_mk_change_supported; pthread_rwlock_t hsm_mk_change_rwlock; }; #endif opencryptoki-opencryptoki-451d99c/usr/lib/common/hwf_obj.c000066400000000000000000000167241520105705100237670ustar00rootroot00000000000000/* * 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_ULONG val; CK_RV rc; rc = template_attribute_get_ulong(tmpl, CKA_HW_FEATURE_TYPE, &val); if (rc != CKR_OK) { if (mode == MODE_CREATE) { TRACE_ERROR("Could not find CKA_HW_FEATURE_TYPE\n"); return rc; } } return template_check_required_base_attributes(tmpl, mode); } CK_RV clock_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) { CK_ATTRIBUTE *attr = NULL; CK_RV rc; if (mode == MODE_CREATE) { rc = template_attribute_get_non_empty(tmpl, CKA_VALUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE\n"); return rc; } } 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 val; CK_RV rc; if (mode == MODE_CREATE) { rc = template_attribute_get_non_empty(tmpl, CKA_VALUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE\n"); return rc; } rc = template_attribute_get_bool(tmpl, CKA_HAS_RESET, &val); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_HAS_RESET\n"); return rc; } rc = template_attribute_get_bool(tmpl, CKA_RESET_ON_INIT, &val); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_RESET_ON_INIT\n"); return rc; } } 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; CK_RV rc; 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; rc = template_update_attribute(tmpl, local_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); free(local_attr); return rc; } #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 (attr->ulValueLen != sizeof(CK_HW_FEATURE_TYPE) || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } 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: %lx\n", ock_err(ERR_ATTRIBUTE_TYPE_INVALID), attr->type); 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; rc = template_update_attribute(tmpl, value_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); free(value_attr); return rc; } 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) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto error; } 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; rc = template_update_attribute(tmpl, value_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); goto error; } value_attr = NULL; rc = template_update_attribute(tmpl, hasreset_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); goto error; } hasreset_attr = NULL; rc = template_update_attribute(tmpl, resetoninit_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); goto error; } resetoninit_attr = NULL; return CKR_OK; error: if (value_attr) free(value_attr); if (hasreset_attr) free(hasreset_attr); if (resetoninit_attr) free(resetoninit_attr); return rc; } opencryptoki-opencryptoki-451d99c/usr/lib/common/kdf_translation.c000066400000000000000000000111601520105705100255200ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021 * * 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 CK_RV translate_string_to_kdf(const char *str, size_t len, CK_ULONG* kdf) { switch(len) { case 8: if (strcmp("CKD_NULL", str) == 0) { *kdf = CKD_NULL; return CKR_OK; } return CKR_FUNCTION_FAILED; case 12: if (strcmp("CKD_SHA1_KDF", str) == 0) { *kdf = CKD_SHA1_KDF; return CKR_OK; } return CKR_FUNCTION_FAILED; case 17: if (strcmp("CKD_SHA1_KDF_ASN1", str) == 0) { *kdf = CKD_SHA1_KDF_ASN1; return CKR_OK; } return CKR_FUNCTION_FAILED; case 24: if (strcmp("CKD_SHA1_KDF_CONCATENATE", str) == 0) { *kdf = CKD_SHA1_KDF_CONCATENATE; return CKR_OK; } return CKR_FUNCTION_FAILED; case 14: if (strcmp("CKD_SHA224_KDF", str) == 0) { *kdf = CKD_SHA224_KDF; return CKR_OK; } if (strcmp("CKD_SHA256_KDF", str) == 0) { *kdf = CKD_SHA256_KDF; return CKR_OK; } if (strcmp("CKD_SHA384_KDF", str) == 0) { *kdf = CKD_SHA384_KDF; return CKR_OK; } if (strcmp("CKD_SHA512_KDF", str) == 0) { *kdf = CKD_SHA512_KDF; return CKR_OK; } return CKR_FUNCTION_FAILED; case 16: if (strcmp("CKD_SHA3_224_KDF", str) == 0) { *kdf = CKD_SHA3_224_KDF; return CKR_OK; } if (strcmp("CKD_SHA3_256_KDF", str) == 0) { *kdf = CKD_SHA3_256_KDF; return CKR_OK; } if (strcmp("CKD_SHA3_384_KDF", str) == 0) { *kdf = CKD_SHA3_384_KDF; return CKR_OK; } if (strcmp("CKD_SHA3_512_KDF", str) == 0) { *kdf = CKD_SHA3_512_KDF; return CKR_OK; } return CKR_FUNCTION_FAILED; case 18: if (strcmp("CKD_SHA1_KDF_SP800", str) == 0) { *kdf = CKD_SHA1_KDF_SP800; return CKR_OK; } return CKR_FUNCTION_FAILED; case 19: if (strcmp("CKD_IBM_HYBRID_NULL", str) == 0) { *kdf = CKD_IBM_HYBRID_NULL; return CKR_OK; } return CKR_FUNCTION_FAILED; case 20: if (strcmp("CKD_SHA224_KDF_SP800", str) == 0) { *kdf = CKD_SHA224_KDF_SP800; return CKR_OK; } if (strcmp("CKD_SHA256_KDF_SP800", str) == 0) { *kdf = CKD_SHA256_KDF_SP800; return CKR_OK; } if (strcmp("CKD_SHA384_KDF_SP800", str) == 0) { *kdf = CKD_SHA384_KDF_SP800; return CKR_OK; } if (strcmp("CKD_SHA512_KDF_SP800", str) == 0) { *kdf = CKD_SHA512_KDF_SP800; return CKR_OK; } return CKR_FUNCTION_FAILED; case 22: if (strcmp("CKD_SHA3_224_KDF_SP800", str) == 0) { *kdf = CKD_SHA3_224_KDF_SP800; return CKR_OK; } if (strcmp("CKD_SHA3_256_KDF_SP800", str) == 0) { *kdf = CKD_SHA3_256_KDF_SP800; return CKR_OK; } if (strcmp("CKD_SHA3_384_KDF_SP800", str) == 0) { *kdf = CKD_SHA3_384_KDF_SP800; return CKR_OK; } if (strcmp("CKD_SHA3_512_KDF_SP800", str) == 0) { *kdf = CKD_SHA3_512_KDF_SP800; return CKR_OK; } return CKR_FUNCTION_FAILED; case 23: if (strcmp("CKD_IBM_HYBRID_SHA1_KDF", str) == 0) { *kdf = CKD_IBM_HYBRID_SHA1_KDF; return CKR_OK; } return CKR_FUNCTION_FAILED; case 25: if (strcmp("CKD_IBM_HYBRID_SHA224_KDF", str) == 0) { *kdf = CKD_IBM_HYBRID_SHA224_KDF; return CKR_OK; } if (strcmp("CKD_IBM_HYBRID_SHA256_KDF", str) == 0) { *kdf = CKD_IBM_HYBRID_SHA256_KDF; return CKR_OK; } if (strcmp("CKD_IBM_HYBRID_SHA384_KDF", str) == 0) { *kdf = CKD_IBM_HYBRID_SHA384_KDF; return CKR_OK; } if (strcmp("CKD_IBM_HYBRID_SHA512_KDF", str) == 0) { *kdf = CKD_IBM_HYBRID_SHA512_KDF; return CKR_OK; } return CKR_FUNCTION_FAILED; default: return CKR_FUNCTION_FAILED; } } opencryptoki-opencryptoki-451d99c/usr/lib/common/key.c000066400000000000000000010436421520105705100231410ustar00rootroot00000000000000/* * 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 // // ec_publ_check_required_attributes // ec_publ_validate_attribute // ec_priv_check_required_attributes // ec_priv_validate_attribute // ec_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 // // generic_secret_check_required_attributes // generic_secret_validate_attribute // generic_secret_set_default_attributes // // 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 // #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 "attributes.h" #include "trace.h" #include "pqc_defs.h" #include "ec_defs.h" #include "tok_spec_struct.h" #include // 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_ULONG val; CK_RV rc; rc = template_attribute_get_ulong(tmpl, CKA_KEY_TYPE, &val); if (rc != CKR_OK) { if (mode == MODE_CREATE || mode == MODE_EXTRACT) { TRACE_ERROR("Could not find CKA_KEY_TYPE\n"); return rc; } } 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; CK_ATTRIBUTE *allowedmechs_attr = NULL; CK_ATTRIBUTE *pkey_attr = NULL; CK_ATTRIBUTE *pkey_nextr_attr = NULL; CK_RV rc; UNUSED(mode); 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)); allowedmechs_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); pkey_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); pkey_nextr_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); if (!id_attr || !sdate_attr || !edate_attr || !derive_attr || !local_attr || !keygenmech_attr || !allowedmechs_attr || !pkey_attr || !pkey_nextr_attr) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto error; } 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; allowedmechs_attr->type = CKA_ALLOWED_MECHANISMS; allowedmechs_attr->ulValueLen = 0; allowedmechs_attr->pValue = NULL; pkey_attr->type = CKA_IBM_PROTKEY_EXTRACTABLE; pkey_attr->ulValueLen = sizeof(CK_BBOOL); pkey_attr->pValue = (CK_BBOOL *) pkey_attr + sizeof(CK_ATTRIBUTE); *(CK_BBOOL *) pkey_attr->pValue = FALSE; pkey_nextr_attr->type = CKA_IBM_PROTKEY_NEVER_EXTRACTABLE; pkey_nextr_attr->ulValueLen = sizeof(CK_BBOOL); pkey_nextr_attr->pValue = (CK_BBOOL *)pkey_nextr_attr + sizeof(CK_ATTRIBUTE); *(CK_BBOOL *)pkey_nextr_attr->pValue = TRUE; rc = template_update_attribute(tmpl, id_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } id_attr = NULL; rc = template_update_attribute(tmpl, sdate_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } sdate_attr = NULL; rc = template_update_attribute(tmpl, edate_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } edate_attr = NULL; rc = template_update_attribute(tmpl, derive_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } derive_attr = NULL; rc = template_update_attribute(tmpl, local_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } local_attr = NULL; rc = template_update_attribute(tmpl, keygenmech_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } keygenmech_attr = NULL; rc = template_update_attribute(tmpl, allowedmechs_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } allowedmechs_attr = NULL; rc = template_update_attribute(tmpl, pkey_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } pkey_attr = NULL; rc = template_update_attribute(tmpl, pkey_nextr_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } pkey_nextr_attr = NULL; return CKR_OK; error: 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); if (allowedmechs_attr) free(allowedmechs_attr); if (pkey_attr) free(pkey_attr); if (pkey_nextr_attr) free(pkey_nextr_attr); return rc; } // key_object_validate_attribute() // CK_RV key_object_validate_attribute(TEMPLATE *tmpl, CK_ATTRIBUTE *attr, CK_ULONG mode) { CK_RV rc; CK_BBOOL ck_false = TRUE; switch (attr->type) { case CKA_KEY_TYPE: if (attr->ulValueLen != sizeof(CK_KEY_TYPE) || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } if (mode == MODE_CREATE || mode == MODE_DERIVE || mode == MODE_KEYGEN || mode == MODE_UNWRAP || mode == MODE_ENCAPS || mode == MODE_DECAPS || mode == MODE_EXTRACT) 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: return CKR_OK; case CKA_ALLOWED_MECHANISMS: if ((attr->ulValueLen > 0 && attr->pValue == NULL) || attr->ulValueLen % sizeof(CK_MECHANISM_TYPE)) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } if (mode == MODE_CREATE || mode == MODE_KEYGEN || mode == MODE_DERIVE || mode == MODE_UNWRAP || mode == MODE_ENCAPS || mode == MODE_DECAPS || mode == MODE_EXTRACT) return CKR_OK; TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); return CKR_ATTRIBUTE_READ_ONLY; case CKA_DERIVE: if (attr->ulValueLen != sizeof(CK_BBOOL) || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } return CKR_OK; case CKA_KEY_GEN_MECHANISM: case CKA_LOCAL: /* * CKA_LOCAL and CKA_KEY_GEN_MECHANISM are only set by the * key-generate routine, but for extract it is allowed to be set. */ if (mode == MODE_EXTRACT) return CKR_OK; TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); return CKR_ATTRIBUTE_READ_ONLY; case CKA_IBM_PROTKEY_EXTRACTABLE: if (attr->ulValueLen != sizeof(CK_BBOOL) || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } CK_BBOOL value = *(CK_BBOOL *) attr->pValue; if (mode != MODE_CREATE && mode != MODE_DERIVE && mode != MODE_KEYGEN && mode != MODE_UNWRAP && mode != MODE_ENCAPS && mode != MODE_DECAPS && mode != MODE_EXTRACT && value != FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); return CKR_ATTRIBUTE_READ_ONLY; } if (value == TRUE) { rc = template_build_update_attribute(tmpl, CKA_IBM_PROTKEY_NEVER_EXTRACTABLE, (CK_BYTE *)&ck_false, sizeof(ck_false)); if (rc != CKR_OK) { TRACE_DEVEL("template_build_update_attribute failed.\n"); return rc; } } return CKR_OK; case CKA_IBM_PROTKEY_NEVER_EXTRACTABLE: TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); return CKR_ATTRIBUTE_READ_ONLY; case CKA_IBM_ATTRBOUND: if (attr->ulValueLen != sizeof(CK_BBOOL) || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } if (mode == MODE_CREATE || mode == MODE_DERIVE || mode == MODE_KEYGEN || mode == MODE_UNWRAP || mode == MODE_ENCAPS || mode == MODE_DECAPS || mode == MODE_EXTRACT) return CKR_OK; TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); return CKR_ATTRIBUTE_READ_ONLY; case CKA_IBM_USE_AS_DATA: if (attr->ulValueLen != sizeof(CK_BBOOL) || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } if (mode == MODE_CREATE || mode == MODE_DERIVE || mode == MODE_KEYGEN || mode == MODE_UNWRAP || mode == MODE_ENCAPS || mode == MODE_DECAPS || mode == MODE_EXTRACT) 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: %lx\n", ock_err(ERR_ATTRIBUTE_TYPE_INVALID), attr->type); return CKR_ATTRIBUTE_TYPE_INVALID; } /* * Check if the specified mechanism is contained in the CKA_ALLOWED_MECHANISMS * attribute. If CKA_ALLOWED_MECHANISMS is not existing, or empty, then all * mechanisms are allowed. */ CK_BBOOL key_object_is_mechanism_allowed(TEMPLATE *tmpl, CK_MECHANISM_TYPE mech) { CK_ATTRIBUTE *attr = NULL; CK_MECHANISM_TYPE *mechs; CK_ULONG num_mechs, i; if (!template_attribute_find(tmpl, CKA_ALLOWED_MECHANISMS, &attr)) return TRUE; if (attr->ulValueLen == 0 || attr->pValue == NULL) return TRUE; mechs = (CK_MECHANISM_TYPE *)attr->pValue; num_mechs = attr->ulValueLen / sizeof(CK_MECHANISM_TYPE); for (i = 0; i < num_mechs; i++) { if (mechs[i] == mech) return TRUE; } return FALSE; } /* * Check if the to be wrapped key template matches the wrap template of the * wrapping key (CKA_WRAP_TEMPLATE), if the wrapping key has one. */ CK_BBOOL key_object_wrap_template_matches(TEMPLATE *wrap_tmpl, TEMPLATE *tmpl) { CK_ATTRIBUTE *attr = NULL; if (!template_attribute_find(wrap_tmpl, CKA_WRAP_TEMPLATE, &attr)) return TRUE; if (attr->ulValueLen == 0 || attr->pValue == NULL) return TRUE; return template_compare((CK_ATTRIBUTE_PTR)attr->pValue, attr->ulValueLen / sizeof(CK_ATTRIBUTE), tmpl); } CK_RV key_object_apply_template_attr(TEMPLATE *unwrap_tmpl, CK_ATTRIBUTE_TYPE attr_type, CK_ATTRIBUTE_PTR attrs, CK_ULONG attrs_count, CK_ATTRIBUTE_PTR *new_attrs, CK_ULONG *new_attrs_count) { CK_ATTRIBUTE *attr = NULL; CK_ATTRIBUTE_PTR apply_attrs; CK_ULONG num_apply_attrs, i; CK_RV rc; rc = dup_attribute_array(attrs, attrs_count, new_attrs, new_attrs_count); if (rc != CKR_OK) { TRACE_DEVEL("dup_attribute_array failed\n"); return rc; } if (!template_attribute_find(unwrap_tmpl, attr_type, &attr)) return CKR_OK; if (attr->ulValueLen == 0 || attr->pValue == NULL) return CKR_OK; apply_attrs = (CK_ATTRIBUTE_PTR)attr->pValue; num_apply_attrs = attr->ulValueLen / sizeof (CK_ATTRIBUTE); for (i = 0; i < num_apply_attrs; i++) { /* * If the attribute to apply is already in the user supplied template, * make sure that it does not conflict. */ attr = get_attribute_by_type(attrs, attrs_count, apply_attrs[i].type); if (attr != NULL) { if (compare_attribute(attr, &apply_attrs[i]) == FALSE) { TRACE_DEVEL("%s: %lu conflicts\n", ock_err(ERR_TEMPLATE_INCONSISTENT), apply_attrs[i].type); return CKR_TEMPLATE_INCONSISTENT; } } else { rc = add_to_attribute_array(new_attrs, new_attrs_count, apply_attrs[i].type, apply_attrs[i].pValue, apply_attrs[i].ulValueLen); if (rc != CKR_OK) { TRACE_DEVEL("add_to_attribute_array failed\n"); return rc; } } } return CKR_OK; } CK_RV key_object_is_always_authenticate(TEMPLATE *tmpl, CK_BBOOL *auth) { CK_OBJECT_CLASS class; CK_BBOOL private; CK_RV rc; rc = template_attribute_get_ulong(tmpl, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_DEVEL("Can not find CKA_CLASS in object\n"); return rc; } /* CKA_ALWAYS_AUTHENTICATE is only defined for CKO_PRIVATE_KEY objects */ if (class != CKO_PRIVATE_KEY) { *auth = FALSE; return CKR_OK; } rc = template_attribute_get_bool(tmpl, CKA_PRIVATE, &private); if (rc != CKR_OK) { TRACE_DEVEL("Can not find CKA_PRIVATE in object\n"); return rc; } /* CKA_ALWAYS_AUTHENTICATE can only be true if CKA_PRIVATE is also TRUE */ if (private == FALSE) { *auth = FALSE; return CKR_OK; } rc = template_attribute_get_bool(tmpl, CKA_ALWAYS_AUTHENTICATE, auth); if (rc == CKR_TEMPLATE_INCOMPLETE) { *auth = FALSE; } else if (rc != CKR_OK) { TRACE_DEVEL("CKA_ALWAYS_AUTHENTICATE is invalid\n"); return rc; } return CKR_OK; } CK_RV key_pub_from_priv(STDLL_TokData_t *tokdata, SESSION *sess, OBJECT *priv_key_obj, CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE *pub_key_handle) { CK_ATTRIBUTE *attrs = NULL; CK_ULONG num_attrs = 0; CK_ATTRIBUTE *attr, *spki_attr; CK_OBJECT_CLASS class; CK_KEY_TYPE keytype; CK_BBOOL ck_true = CK_TRUE, ck_false = CK_FALSE; CK_ULONG i; TEMPLATE *tmpl = NULL; DL_NODE *node; CK_RV rc; const struct default_attr { CK_ATTRIBUTE attr; CK_BBOOL copy_from_priv; CK_ATTRIBUTE_TYPE priv_attr_type; } default_attrs[] = { { .attr = { CKA_TOKEN, &ck_false, sizeof(ck_false)} }, { .attr = { CKA_PRIVATE, &ck_false, sizeof(ck_false) } }, { .attr = { CKA_MODIFIABLE, &ck_true, sizeof(ck_true) } }, { .attr = { CKA_LOCAL, &ck_false, sizeof(ck_false) } }, { .attr = { CKA_COPYABLE, &ck_true, sizeof(ck_true) } }, { .attr = { CKA_DESTROYABLE, &ck_true, sizeof(ck_true) } }, { .attr = { CKA_LABEL, NULL, 0 } }, { .attr = { CKA_WRAP_TEMPLATE, NULL, 0 } }, { .attr = { CKA_ENCRYPT, &ck_false, sizeof(ck_false) }, .copy_from_priv = CK_TRUE, .priv_attr_type = CKA_DECRYPT }, { .attr = { CKA_VERIFY, &ck_false, sizeof(ck_false) }, .copy_from_priv = CK_TRUE, .priv_attr_type = CKA_SIGN }, { .attr = { CKA_VERIFY_RECOVER, &ck_false, sizeof(ck_false) }, .copy_from_priv = CK_TRUE, .priv_attr_type = CKA_SIGN_RECOVER }, { .attr = { CKA_WRAP, &ck_false, sizeof(ck_false) }, .copy_from_priv = CK_TRUE, .priv_attr_type = CKA_UNWRAP }, { .attr = { CKA_DERIVE, &ck_false, sizeof(ck_false) }, .copy_from_priv = CK_TRUE, .priv_attr_type = CKA_DERIVE }, { .attr = { CKA_ID, NULL, 0 }, .copy_from_priv = CK_TRUE, .priv_attr_type = CKA_ID }, { .attr = { CKA_START_DATE, NULL, 0 }, .copy_from_priv = CK_TRUE, .priv_attr_type = CKA_START_DATE }, { .attr = { CKA_END_DATE, NULL, 0 }, .copy_from_priv = CK_TRUE, .priv_attr_type = CKA_END_DATE }, { .attr = { CKA_SUBJECT, NULL, 0 }, .copy_from_priv = CK_TRUE, .priv_attr_type = CKA_SUBJECT }, { .attr = { CKA_PUBLIC_KEY_INFO, NULL, 0 }, .copy_from_priv = CK_TRUE, .priv_attr_type = CKA_PUBLIC_KEY_INFO }, { .attr = { CKA_KEY_GEN_MECHANISM, NULL, 0 }, .copy_from_priv = CK_TRUE, .priv_attr_type = CKA_KEY_GEN_MECHANISM }, { .attr = { CKA_ALLOWED_MECHANISMS, NULL, 0 }, .copy_from_priv = CK_TRUE, .priv_attr_type = CKA_ALLOWED_MECHANISMS }, }; rc = template_attribute_get_ulong(priv_key_obj->template, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_DEVEL("Can not find CKA_CLASS in object\n"); return rc; } if (class != CKO_PRIVATE_KEY) { TRACE_DEVEL("Base key is not a private key\n"); return CKR_KEY_TYPE_INCONSISTENT; } rc = template_attribute_get_ulong(priv_key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_DEVEL("Can not find CKA_KEY_TYPE in object\n"); return rc; } rc = template_attribute_get_non_empty(priv_key_obj->template, CKA_PUBLIC_KEY_INFO, &spki_attr); if (rc != CKR_OK) { TRACE_DEVEL("Can not find CKA_PUBLIC_KEY_INFO in object\n"); return CKR_PUBLIC_KEY_INVALID; } rc = dup_attribute_array(pTemplate, ulCount, &attrs, &num_attrs); if (rc != CKR_OK) { TRACE_DEVEL("dup_attribute_array failed\n"); return rc; } /* Add class and key type attributes */ class = CKO_PUBLIC_KEY; rc = add_to_attribute_array(&attrs, &num_attrs, CKA_CLASS, (CK_BYTE *)&class, sizeof(class)); if (rc != CKR_OK) { TRACE_DEVEL("add_to_attribute_array failed\n"); goto done; } rc = add_to_attribute_array(&attrs, &num_attrs, CKA_KEY_TYPE, (CK_BYTE *)&keytype, sizeof(keytype)); if (rc != CKR_OK) { TRACE_DEVEL("add_to_attribute_array failed\n"); goto done; } /* Apply defaults for public key object, if not in the template */ for (i = 0; i < sizeof(default_attrs) / sizeof(struct default_attr); i++) { attr = get_attribute_by_type(pTemplate, ulCount, default_attrs[i].attr.type); if (attr == NULL) { attr = (CK_ATTRIBUTE *)&default_attrs[i].attr; if (default_attrs[i].copy_from_priv) { if (template_attribute_find(priv_key_obj->template, default_attrs[i].priv_attr_type, &attr) == CK_FALSE) { TRACE_DEVEL("Can not find %s in object\n", p11_get_cka( default_attrs[i].priv_attr_type)); rc = CKR_TEMPLATE_INCOMPLETE; goto done; } } rc = add_to_attribute_array(&attrs, &num_attrs, default_attrs[i].attr.type, attr->pValue, attr->ulValueLen); if (rc != CKR_OK) { TRACE_DEVEL("add_to_attribute_array failed\n"); goto done; } } } /* Get the public key attributes from SPKI into temporary template */ tmpl = calloc(1, sizeof(TEMPLATE)); if (tmpl == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto done; } switch (keytype) { case CKK_EC: case CKK_EC_EDWARDS: case CKK_EC_MONTGOMERY: rc = ec_priv_unwrap_get_data(tmpl, spki_attr->pValue, spki_attr->ulValueLen, CK_TRUE, keytype); break; case CKK_RSA: rc = rsa_priv_unwrap_get_data(tmpl, spki_attr->pValue, spki_attr->ulValueLen, CK_TRUE); break; case CKK_DSA: rc = dsa_priv_unwrap_get_data(tmpl, spki_attr->pValue, spki_attr->ulValueLen, CK_TRUE); break; case CKK_DH: rc = dh_priv_unwrap_get_data(tmpl, spki_attr->pValue, spki_attr->ulValueLen, CK_TRUE); break; case CKK_IBM_PQC_DILITHIUM: case CKK_IBM_PQC_KYBER: case CKK_IBM_ML_DSA: case CKK_IBM_ML_KEM: case CKK_ML_DSA: case CKK_ML_KEM: rc = pqc_priv_unwrap_get_data(tmpl, keytype, spki_attr->pValue, spki_attr->ulValueLen, CK_TRUE); break; default: rc = CKR_KEY_TYPE_INCONSISTENT; break; } if (rc != 0) { TRACE_ERROR("xxx_priv_unwrap_get_data failed (keytype 0x%lx): 0x%lx\n", keytype, rc); goto done; } /* Add public key attributes to array of attributes */ node = tmpl->attribute_list; while (node != NULL) { attr = (CK_ATTRIBUTE *)node->data; rc = add_to_attribute_array(&attrs, &num_attrs, attr->type, attr->pValue, attr->ulValueLen); if (rc != CKR_OK) { TRACE_DEVEL("add_to_attribute_array failed\n"); goto done; } node = node->next; } /* Create the public key object */ rc = object_mgr_add(tokdata, sess, attrs, num_attrs, pub_key_handle, MODE_EXTRACT); if (rc != CKR_OK) { TRACE_DEVEL("object_mgr_add failed\n"); goto done; } done: if (attrs != NULL && num_attrs > 0) free_attribute_array(attrs, num_attrs); if (tmpl != NULL) template_free(tmpl); return rc; } // 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_ATTRIBUTE *trusted_attr = NULL; CK_ATTRIBUTE *pki_attr = NULL; CK_ATTRIBUTE *wraptmpl_attr = NULL; CK_ATTRIBUTE *encaps_attr = NULL; CK_ATTRIBUTE *encapstmpl_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)); 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)); trusted_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); pki_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); wraptmpl_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); encaps_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); encapstmpl_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); if (!class_attr || !subject_attr || !encrypt_attr || !verify_attr || !verify_recover_attr || !wrap_attr || !trusted_attr || !pki_attr || !wraptmpl_attr || !encaps_attr || !encapstmpl_attr) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto error; } 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; trusted_attr->type = CKA_TRUSTED; trusted_attr->ulValueLen = sizeof(CK_BBOOL); trusted_attr->pValue = (CK_BYTE *)trusted_attr + sizeof(CK_ATTRIBUTE); *(CK_BBOOL *) trusted_attr->pValue = FALSE; pki_attr->type = CKA_PUBLIC_KEY_INFO; pki_attr->ulValueLen = 0; // empty string pki_attr->pValue = NULL; wraptmpl_attr->type = CKA_WRAP_TEMPLATE; wraptmpl_attr->ulValueLen = 0; wraptmpl_attr->pValue = NULL; encaps_attr->type = CKA_ENCAPSULATE; encaps_attr->ulValueLen = sizeof(CK_BBOOL); encaps_attr->pValue = (CK_BYTE *)encaps_attr + sizeof(CK_ATTRIBUTE); *(CK_BBOOL *) encaps_attr->pValue = FALSE; encapstmpl_attr->type = CKA_ENCAPSULATE_TEMPLATE; encapstmpl_attr->ulValueLen = 0; encapstmpl_attr->pValue = NULL; rc = template_update_attribute(tmpl, class_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } class_attr = NULL; rc = template_update_attribute(tmpl, subject_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } subject_attr = NULL; rc = template_update_attribute(tmpl, encrypt_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } encrypt_attr = NULL; rc = template_update_attribute(tmpl, verify_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } verify_attr = NULL; rc = template_update_attribute(tmpl, verify_recover_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } verify_recover_attr = NULL; rc = template_update_attribute(tmpl, wrap_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } wrap_attr = NULL; rc = template_update_attribute(tmpl, trusted_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } trusted_attr = NULL; rc = template_update_attribute(tmpl, pki_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } pki_attr = NULL; rc = template_update_attribute(tmpl, wraptmpl_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } wraptmpl_attr = NULL; rc = template_update_attribute(tmpl, encaps_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } encaps_attr = NULL; rc = template_update_attribute(tmpl, encapstmpl_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } encapstmpl_attr = NULL; return CKR_OK; error: 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); if (trusted_attr) free(trusted_attr); if (pki_attr) free(pki_attr); if (wraptmpl_attr) free(wraptmpl_attr); if (encaps_attr) free(encaps_attr); if (encapstmpl_attr) free(encapstmpl_attr); return rc; } // publ_key_validate_attribute // CK_RV publ_key_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_ATTRIBUTE *attr, CK_ULONG mode) { CK_RV rc; switch (attr->type) { case CKA_SUBJECT: return CKR_OK; case CKA_ENCRYPT: case CKA_VERIFY: case CKA_VERIFY_RECOVER: case CKA_WRAP: case CKA_ENCAPSULATE: 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; } if (attr->ulValueLen != sizeof(CK_BBOOL) || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } return CKR_OK; case CKA_TRUSTED: /* Can only be set to CK_TRUE by the SO user */ if (attr->ulValueLen != sizeof(CK_BBOOL) || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } if (*((CK_BBOOL *)attr->pValue) == CK_TRUE && !session_mgr_so_session_exists(tokdata)) { TRACE_ERROR("CKA_TRUSTED can only be set to TRUE by SO\n"); return CKR_USER_NOT_LOGGED_IN; } return CKR_OK; case CKA_PUBLIC_KEY_INFO: if (mode == MODE_CREATE || mode == MODE_UNWRAP || mode == MODE_ENCAPS || mode == MODE_DECAPS || mode == MODE_EXTRACT) return CKR_OK; return CKR_ATTRIBUTE_READ_ONLY; case CKA_WRAP_TEMPLATE: case CKA_ENCAPSULATE_TEMPLATE: if ((attr->ulValueLen > 0 && attr->pValue == NULL) || attr->ulValueLen % sizeof(CK_ATTRIBUTE)) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } rc = validate_attribute_array((CK_ATTRIBUTE_PTR)attr->pValue, attr->ulValueLen / sizeof(CK_ATTRIBUTE)); if (rc != CKR_OK) { TRACE_ERROR("validate_attribute_array rc=0x%lx\n", rc); return rc; } if (mode == MODE_CREATE || mode == MODE_KEYGEN || mode == MODE_DERIVE || mode == MODE_UNWRAP || mode == MODE_ENCAPS || mode == MODE_DECAPS || mode == MODE_EXTRACT) return CKR_OK; 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: %lx\n", ock_err(ERR_ATTRIBUTE_TYPE_INVALID), attr->type); return CKR_ATTRIBUTE_TYPE_INVALID; } /* * Extract the SubjectPublicKeyInfo from the public key */ CK_RV publ_key_get_spki(TEMPLATE *tmpl, CK_ULONG keytype, CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, CK_BBOOL is_priv_tmpl) { CK_RV rc; switch (keytype) { case CKK_RSA: rc = rsa_publ_get_spki(tmpl, length_only, data, data_len); break; case CKK_DSA: rc = dsa_publ_get_spki(tmpl, length_only, data, data_len); break; case CKK_DH: rc = dh_publ_get_spki(tmpl, length_only, data, data_len); break; case CKK_EC: case CKK_EC_EDWARDS: case CKK_EC_MONTGOMERY: rc = ec_publ_get_spki(tmpl, length_only, data, data_len, keytype); break; case CKK_IBM_PQC_DILITHIUM: rc = ibm_ml_dsa_publ_get_spki(tmpl, length_only, data, data_len, CKM_IBM_DILITHIUM); break; case CKK_IBM_PQC_KYBER: rc = ibm_ml_kem_publ_get_spki(tmpl, length_only, data, data_len, CKM_IBM_KYBER); break; case CKK_IBM_ML_DSA: rc = ibm_ml_dsa_publ_get_spki(tmpl, length_only, data, data_len, CKM_IBM_ML_DSA); break; case CKK_IBM_ML_KEM: rc = ibm_ml_kem_publ_get_spki(tmpl, length_only, data, data_len, CKM_IBM_ML_KEM); break; case CKK_ML_DSA: rc = ml_dsa_publ_get_spki(tmpl, length_only, data, data_len, is_priv_tmpl); break; case CKK_ML_KEM: rc = ml_kem_publ_get_spki(tmpl, length_only, data, data_len, is_priv_tmpl); break; default: TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); return CKR_KEY_TYPE_INCONSISTENT; } return rc; } // 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_ATTRIBUTE *wrap_trusted_attr = NULL; CK_ATTRIBUTE *pki_attr = NULL; CK_ATTRIBUTE *unwraptmpl_attr = NULL; CK_ATTRIBUTE *derivetmpl_attr = NULL; CK_ATTRIBUTE *decaps_attr = NULL; CK_ATTRIBUTE *decapstmpl_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)); wrap_trusted_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); pki_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); unwraptmpl_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); derivetmpl_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); decaps_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); decapstmpl_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); 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 || !wrap_trusted_attr || !pki_attr || !unwraptmpl_attr || !derivetmpl_attr || !decaps_attr || !decapstmpl_attr) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto error; } 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; wrap_trusted_attr->type = CKA_WRAP_WITH_TRUSTED; wrap_trusted_attr->ulValueLen = sizeof(CK_BBOOL); wrap_trusted_attr->pValue = (CK_BYTE *) wrap_trusted_attr + sizeof(CK_ATTRIBUTE); *(CK_BBOOL *) wrap_trusted_attr->pValue = FALSE; pki_attr->type = CKA_SUBJECT; pki_attr->ulValueLen = 0; // empty string pki_attr->pValue = NULL; unwraptmpl_attr->type = CKA_UNWRAP_TEMPLATE; unwraptmpl_attr->ulValueLen = 0; unwraptmpl_attr->pValue = NULL; derivetmpl_attr->type = CKA_DERIVE_TEMPLATE; derivetmpl_attr->ulValueLen = 0; derivetmpl_attr->pValue = NULL; decaps_attr->type = CKA_DECAPSULATE; decaps_attr->ulValueLen = sizeof(CK_BBOOL); decaps_attr->pValue = (CK_BYTE *) decaps_attr + sizeof(CK_ATTRIBUTE); *(CK_BBOOL *) decaps_attr->pValue = FALSE; decapstmpl_attr->type = CKA_DECAPSULATE_TEMPLATE; decapstmpl_attr->ulValueLen = 0; decapstmpl_attr->pValue = NULL; rc = template_update_attribute(tmpl, class_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } class_attr = NULL; rc = template_update_attribute(tmpl, subject_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } subject_attr = NULL; rc = template_update_attribute(tmpl, sensitive_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } sensitive_attr = NULL; rc = template_update_attribute(tmpl, decrypt_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } decrypt_attr = NULL; rc = template_update_attribute(tmpl, sign_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } sign_attr = NULL; rc = template_update_attribute(tmpl, sign_recover_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } sign_recover_attr = NULL; rc = template_update_attribute(tmpl, unwrap_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } unwrap_attr = NULL; rc = template_update_attribute(tmpl, extractable_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } extractable_attr = NULL; rc = template_update_attribute(tmpl, never_extr_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } never_extr_attr = NULL; rc = template_update_attribute(tmpl, always_sens_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } always_sens_attr = NULL; rc = template_update_attribute(tmpl, always_auth_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } always_auth_attr = NULL; rc = template_update_attribute(tmpl, wrap_trusted_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } wrap_trusted_attr = NULL; rc = template_update_attribute(tmpl, pki_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } pki_attr = NULL; rc = template_update_attribute(tmpl, unwraptmpl_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } unwraptmpl_attr = NULL; rc = template_update_attribute(tmpl, derivetmpl_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } derivetmpl_attr = NULL; rc = template_update_attribute(tmpl, decaps_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } decaps_attr = NULL; rc = template_update_attribute(tmpl, decapstmpl_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } decapstmpl_attr = NULL; return CKR_OK; error: 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); if (wrap_trusted_attr) free(wrap_trusted_attr); if (pki_attr) free(pki_attr); if (unwraptmpl_attr) free(unwraptmpl_attr); if (derivetmpl_attr) free(derivetmpl_attr); if (decaps_attr) free(decaps_attr); if (decapstmpl_attr) free(decapstmpl_attr); return rc; } // // CK_RV priv_key_unwrap(TEMPLATE *tmpl, CK_ULONG keytype, CK_BYTE *data, CK_ULONG data_len) { CK_ATTRIBUTE *extractable = NULL; CK_ATTRIBUTE *always_sens = NULL; CK_ATTRIBUTE *never_extract = NULL; CK_ATTRIBUTE *sensitive = NULL; CK_ATTRIBUTE *local = NULL; CK_ATTRIBUTE *pub_key_info = NULL; CK_BBOOL true = TRUE; CK_BBOOL false = FALSE; CK_BYTE *spki = NULL; CK_ULONG spki_length = 0; CK_RV rc; switch (keytype) { case CKK_RSA: rc = rsa_priv_unwrap(tmpl, data, data_len); 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: case CKK_EC_EDWARDS: case CKK_EC_MONTGOMERY: rc = ec_priv_unwrap(tmpl, data, data_len, keytype); break; case CKK_IBM_PQC_DILITHIUM: rc = ibm_ml_dsa_priv_unwrap(tmpl, data, data_len, TRUE, CKM_IBM_DILITHIUM); break; case CKK_IBM_PQC_KYBER: rc = ibm_ml_kem_priv_unwrap(tmpl, data, data_len, TRUE, CKM_IBM_KYBER); break; case CKK_IBM_ML_DSA: rc = ibm_ml_dsa_priv_unwrap(tmpl, data, data_len, TRUE, CKM_IBM_ML_DSA); break; case CKK_IBM_ML_KEM: rc = ibm_ml_kem_priv_unwrap(tmpl, data, data_len, TRUE, CKM_IBM_ML_KEM); break; case CKK_ML_DSA: rc = ml_dsa_priv_unwrap(tmpl, data, data_len, TRUE); break; case CKK_ML_KEM: rc = ml_kem_priv_unwrap(tmpl, data, data_len, TRUE); 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; } /* * Try to extract the SPKI and add CKA_PUBLIC_KEY_INFO to the key. * This may fail if the public key info can not be reconstructed from * the private key (e.g. because its a secure key token). */ rc = publ_key_get_spki(tmpl, keytype, FALSE, &spki, &spki_length, TRUE); if (rc == CKR_OK && spki != NULL && spki_length > 0) { rc = build_attribute(CKA_PUBLIC_KEY_INFO, spki, spki_length, &pub_key_info); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto cleanup; } rc = template_update_attribute(tmpl, pub_key_info); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto cleanup; } pub_key_info = NULL; } rc = template_update_attribute(tmpl, local); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto cleanup; } local = NULL; rc = template_update_attribute(tmpl, always_sens); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto cleanup; } always_sens = NULL; rc = template_update_attribute(tmpl, sensitive); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto cleanup; } sensitive = NULL; rc = template_update_attribute(tmpl, extractable); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto cleanup; } extractable = NULL; rc = template_update_attribute(tmpl, never_extract); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto cleanup; } never_extract = NULL; if (spki != NULL) free(spki); return CKR_OK; cleanup: if (local) free(local); if (always_sens) free(always_sens); if (sensitive) free(sensitive); if (extractable) free(extractable); if (never_extract) free(never_extract); if (pub_key_info) free(pub_key_info); if (spki != NULL) free(spki); return rc; } // priv_key_validate_attribute() // CK_RV priv_key_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_ATTRIBUTE *attr, CK_ULONG mode) { CK_RV rc; switch (attr->type) { case CKA_SUBJECT: return CKR_OK; case CKA_DECRYPT: case CKA_SIGN: case CKA_SIGN_RECOVER: case CKA_UNWRAP: case CKA_DECAPSULATE: if (attr->ulValueLen != sizeof(CK_BBOOL) || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } // 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 and CKA_WRAP_WITH_TRUSTED may only * be set to TRUE */ case CKA_SENSITIVE: case CKA_WRAP_WITH_TRUSTED: { CK_BBOOL value; if (attr->ulValueLen != sizeof(CK_BBOOL) || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } if (mode == MODE_CREATE || mode == MODE_KEYGEN || mode == MODE_ENCAPS || mode == MODE_DECAPS) 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; if (attr->ulValueLen != sizeof(CK_BBOOL) || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } value = *(CK_BBOOL *) attr->pValue; if ((mode != MODE_CREATE && mode != MODE_KEYGEN && mode != MODE_ENCAPS) && value != FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); return CKR_ATTRIBUTE_READ_ONLY; } if (value == TRUE) { 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; rc = template_update_attribute(tmpl, attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); free(attr); return rc; } } 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; case CKA_PUBLIC_KEY_INFO: /* * PKCS#11: A token MAY choose not to support the CKA_PUBLIC_KEY_INFO * attribute for commands which create new private keys. If it does not * support the attribute, the command SHALL return * CKR_ATTRIBUTE_TYPE_INVALID. */ TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_TYPE_INVALID)); return CKR_ATTRIBUTE_TYPE_INVALID; case CKA_UNWRAP_TEMPLATE: case CKA_DERIVE_TEMPLATE: case CKA_DECAPSULATE_TEMPLATE: if ((attr->ulValueLen > 0 && attr->pValue == NULL) || attr->ulValueLen % sizeof(CK_ATTRIBUTE)) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } rc = validate_attribute_array((CK_ATTRIBUTE_PTR)attr->pValue, attr->ulValueLen / sizeof(CK_ATTRIBUTE)); if (rc != CKR_OK) { TRACE_ERROR("validate_attribute_array rc=0x%lx\n", rc); return rc; } if (mode == MODE_CREATE || mode == MODE_KEYGEN || mode == MODE_DERIVE || mode == MODE_UNWRAP || mode == MODE_ENCAPS || mode == MODE_DECAPS) return CKR_OK; TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); return CKR_ATTRIBUTE_READ_ONLY; case CKA_ALWAYS_AUTHENTICATE: { CK_BBOOL value = FALSE; if (attr->ulValueLen != sizeof(CK_BBOOL) || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } if (mode == MODE_MODIFY || mode == MODE_COPY) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); return CKR_ATTRIBUTE_READ_ONLY; } /* * CKA_ALWAYS_AUTHENTICATE can only be set to TRUE if CKA_PRIVATE * is also true. If CKA_PRIVATE is not in the template, we assume * the default value of CKA_PRIVATE (FALSE). */ if (*(CK_BBOOL *)attr->pValue == FALSE) return CKR_OK; if (template_attribute_get_bool(tmpl, CKA_PRIVATE, &value) != CKR_OK || value == FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } return CKR_OK; } default: return key_object_validate_attribute(tmpl, attr, mode); } TRACE_ERROR("%s: %lx\n", ock_err(ERR_ATTRIBUTE_TYPE_INVALID), attr->type); 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_ATTRIBUTE *trusted_attr = NULL; CK_ATTRIBUTE *wrap_trusted_attr = NULL; CK_ATTRIBUTE *chkval_attr = NULL; CK_ATTRIBUTE *wraptmpl_attr = NULL; CK_ATTRIBUTE *unwraptmpl_attr = NULL; CK_ATTRIBUTE *derivetmpl_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)); trusted_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); wrap_trusted_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); chkval_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); wraptmpl_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); unwraptmpl_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); derivetmpl_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); 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 || !trusted_attr || !wrap_trusted_attr || !chkval_attr || !wraptmpl_attr || !unwraptmpl_attr || !derivetmpl_attr) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto error; } 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; trusted_attr->type = CKA_TRUSTED; trusted_attr->ulValueLen = sizeof(CK_BBOOL); trusted_attr->pValue = (CK_BYTE *)trusted_attr + sizeof(CK_ATTRIBUTE); *(CK_BBOOL *) trusted_attr->pValue = FALSE; wrap_trusted_attr->type = CKA_WRAP_WITH_TRUSTED; wrap_trusted_attr->ulValueLen = sizeof(CK_BBOOL); wrap_trusted_attr->pValue = (CK_BYTE *) wrap_trusted_attr + sizeof(CK_ATTRIBUTE); *(CK_BBOOL *) wrap_trusted_attr->pValue = FALSE; chkval_attr->type = CKA_CHECK_VALUE; chkval_attr->ulValueLen = 0; chkval_attr->pValue = NULL; wraptmpl_attr->type = CKA_WRAP_TEMPLATE; wraptmpl_attr->ulValueLen = 0; wraptmpl_attr->pValue = NULL; unwraptmpl_attr->type = CKA_UNWRAP_TEMPLATE; unwraptmpl_attr->ulValueLen = 0; unwraptmpl_attr->pValue = NULL; derivetmpl_attr->type = CKA_DERIVE_TEMPLATE; derivetmpl_attr->ulValueLen = 0; derivetmpl_attr->pValue = NULL; rc = template_update_attribute(tmpl, class_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } class_attr = NULL; rc = template_update_attribute(tmpl, sensitive_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } sensitive_attr = NULL; rc = template_update_attribute(tmpl, encrypt_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } encrypt_attr = NULL; rc = template_update_attribute(tmpl, decrypt_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } decrypt_attr = NULL; rc = template_update_attribute(tmpl, sign_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } sign_attr = NULL; rc = template_update_attribute(tmpl, verify_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } verify_attr = NULL; rc = template_update_attribute(tmpl, wrap_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } wrap_attr = NULL; rc = template_update_attribute(tmpl, unwrap_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } unwrap_attr = NULL; rc = template_update_attribute(tmpl, extractable_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } extractable_attr = NULL; rc = template_update_attribute(tmpl, never_extr_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } never_extr_attr = NULL; rc = template_update_attribute(tmpl, always_sens_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } always_sens_attr = NULL; rc = template_update_attribute(tmpl, trusted_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } trusted_attr = NULL; rc = template_update_attribute(tmpl, wrap_trusted_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } wrap_trusted_attr = NULL; rc = template_update_attribute(tmpl, chkval_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } chkval_attr = NULL; rc = template_update_attribute(tmpl, wraptmpl_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } wraptmpl_attr = NULL; rc = template_update_attribute(tmpl, unwraptmpl_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } unwraptmpl_attr = NULL; rc = template_update_attribute(tmpl, derivetmpl_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } derivetmpl_attr = NULL; return CKR_OK; error: 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); if (trusted_attr) free(trusted_attr); if (wrap_trusted_attr) free(wrap_trusted_attr); if (chkval_attr) free(chkval_attr); if (wraptmpl_attr) free(wraptmpl_attr); if (unwraptmpl_attr) free(unwraptmpl_attr); if (derivetmpl_attr) free(derivetmpl_attr); return rc; } // // 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_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_DES: rc = des_unwrap(tokdata, tmpl, data, data_len, fromend); break; case CKK_DES3: rc = des3_unwrap(tokdata, tmpl, data, data_len, fromend); break; case CKK_AES: case CKK_AES_XTS: rc = aes_unwrap(tokdata, tmpl, data, data_len, fromend, keytype == CKK_AES_XTS); break; case CKK_GENERIC_SECRET: case CKK_SHA_1_HMAC: case CKK_SHA224_HMAC: case CKK_SHA256_HMAC: case CKK_SHA384_HMAC: case CKK_SHA512_HMAC: case CKK_SHA3_224_HMAC: case CKK_SHA3_256_HMAC: case CKK_SHA3_384_HMAC: case CKK_SHA3_512_HMAC: case CKK_SHA512_224_HMAC: case CKK_SHA512_256_HMAC: rc = generic_secret_unwrap(tmpl, data, data_len, fromend); 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; } rc = template_update_attribute(tmpl, local); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto cleanup; } local = NULL; rc = template_update_attribute(tmpl, always_sens); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto cleanup; } always_sens = NULL; rc = template_update_attribute(tmpl, sensitive); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto cleanup; } sensitive = NULL; rc = template_update_attribute(tmpl, extractable); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto cleanup; } extractable = NULL; rc = template_update_attribute(tmpl, never_extract); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto cleanup; } never_extract = NULL; return CKR_OK; cleanup: if (local) free(local); if (sensitive) free(sensitive); 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) { CK_RV rc; switch (attr->type) { case CKA_ENCRYPT: case CKA_DECRYPT: case CKA_SIGN: case CKA_VERIFY: case CKA_WRAP: case CKA_UNWRAP: if (attr->ulValueLen != sizeof(CK_BBOOL) || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } 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; case CKA_TRUSTED: /* Can only be set to CK_TRUE by the SO user */ if (attr->ulValueLen != sizeof(CK_BBOOL) || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } if (*((CK_BBOOL *)attr->pValue) == CK_TRUE && !session_mgr_so_session_exists(tokdata)) { TRACE_ERROR("CKA_TRUSTED can only be set to TRUE by SO\n"); return CKR_USER_NOT_LOGGED_IN; } return CKR_OK; /* * After key creation, CKA_SENSITIVE and CKA_WRAP_WITH_TRUSTED may only * be set to TRUE */ case CKA_SENSITIVE: case CKA_WRAP_WITH_TRUSTED: { CK_BBOOL value; if (attr->ulValueLen != sizeof(CK_BBOOL) || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } value = *(CK_BBOOL *) attr->pValue; if ((mode != MODE_CREATE && mode != MODE_DERIVE && mode != MODE_KEYGEN && mode != MODE_ENCAPS && mode != MODE_DECAPS) && (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 // if (attr->ulValueLen != sizeof(CK_BBOOL) || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } value = *(CK_BBOOL *) attr->pValue; if ((mode != MODE_CREATE && mode != MODE_DERIVE && mode != MODE_KEYGEN && mode != MODE_ENCAPS && mode != MODE_DECAPS) && (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; rc = template_update_attribute(tmpl, attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); free(attr); return rc; } } 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; case CKA_CHECK_VALUE: if (mode != MODE_CREATE) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); return CKR_ATTRIBUTE_READ_ONLY; } return CKR_OK; case CKA_WRAP_TEMPLATE: case CKA_UNWRAP_TEMPLATE: case CKA_DERIVE_TEMPLATE: if ((attr->ulValueLen > 0 && attr->pValue == NULL) || attr->ulValueLen % sizeof(CK_ATTRIBUTE)) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } rc = validate_attribute_array((CK_ATTRIBUTE_PTR)attr->pValue, attr->ulValueLen / sizeof(CK_ATTRIBUTE)); if (rc != CKR_OK) { TRACE_ERROR("validate_attribute_array rc=0x%lx\n", rc); return rc; } if (mode == MODE_CREATE || mode == MODE_KEYGEN || mode == MODE_DERIVE || mode == MODE_UNWRAP || mode == MODE_ENCAPS || mode == MODE_DECAPS) return CKR_OK; 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: %lx\n", ock_err(ERR_ATTRIBUTE_TYPE_INVALID), attr->type); 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_ULONG val; CK_RV rc; if (mode == MODE_CREATE && token_specific.secure_key_token == TRUE && template_attribute_get_non_empty(tmpl, CKA_IBM_OPAQUE, &attr) == CKR_OK) { /* * Import of an already existing secure key. Only * do the base checks for public key templates. */ return publ_key_check_required_attributes(tmpl, mode); } rc = template_attribute_get_non_empty(tmpl, CKA_MODULUS, &attr); if (rc != CKR_OK) { if (mode == MODE_CREATE || mode == MODE_EXTRACT) { TRACE_ERROR("Could not find CKA_MODULUS\n"); return rc; } } rc = template_attribute_get_ulong(tmpl, CKA_MODULUS_BITS, &val); if (rc != CKR_OK) { if (mode == MODE_KEYGEN || mode == MODE_ENCAPS) { TRACE_ERROR("Could not find CKA_MODULUS_BITS\n"); return rc; } } rc = template_attribute_get_non_empty(tmpl, CKA_PUBLIC_EXPONENT, &attr); if (rc != CKR_OK) { if (mode == MODE_CREATE || mode == MODE_EXTRACT) { TRACE_ERROR("Could not find CKA_PUBLIC_EXPONENT\n"); return rc; } } 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 }; CK_RV rc; 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) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto error; } 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)); rc = template_update_attribute(tmpl, type_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } type_attr = NULL; rc = template_update_attribute(tmpl, modulus_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } modulus_attr = NULL; rc = template_update_attribute(tmpl, modulus_bits_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } modulus_bits_attr = NULL; rc = template_update_attribute(tmpl, public_exp_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } public_exp_attr = NULL; return CKR_OK; error: 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); return rc; } // 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 || mode == MODE_ENCAPS || mode == MODE_EXTRACT) { if (attr->ulValueLen != sizeof(CK_ULONG) || attr->pValue == NULL) { 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 > OPENSSL_RSA_MAX_MODULUS_BITS) { 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 || mode == MODE_EXTRACT) { 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 || mode == MODE_ENCAPS || mode == MODE_EXTRACT) { 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); } } /* * Extract the SubjectPublicKeyInfo from the RSA public key */ CK_RV rsa_publ_get_spki(TEMPLATE *tmpl, CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len) { CK_ATTRIBUTE *modulus = NULL; CK_ATTRIBUTE *publ_exp = NULL; CK_RV rc; rc = template_attribute_get_non_empty(tmpl, CKA_MODULUS, &modulus); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); return rc; } rc = template_attribute_get_non_empty(tmpl, CKA_PUBLIC_EXPONENT, &publ_exp); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_PUBLIC_EXPONENT for the key.\n"); return rc; } rc = ber_encode_RSAPublicKey(length_only, data,data_len, modulus, publ_exp); if (rc != CKR_OK) { TRACE_ERROR("ber_encode_RSAPublicKey failed.\n"); return rc; } return CKR_OK; } // rsa_priv_check_required_attributes() // CK_RV rsa_priv_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) { CK_ATTRIBUTE *attr = NULL, *coef = NULL; CK_ATTRIBUTE *prime1 = NULL, *prime2 = NULL, *exp1 = NULL, *exp2 = NULL; CK_RV rc; if (mode == MODE_CREATE && token_specific.secure_key_token == TRUE && template_attribute_get_non_empty(tmpl, CKA_IBM_OPAQUE, &attr) == CKR_OK) { /* * Import of an already existing secure key. Only * do the base checks for private key templates. */ return priv_key_check_required_attributes(tmpl, mode); } rc = template_attribute_get_non_empty(tmpl, CKA_MODULUS, &attr); if (rc != CKR_OK) { if (mode == MODE_CREATE) { TRACE_ERROR("Could not find CKA_MODULUS\n"); return rc; } } /* * 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. Effective with version * 2.40, tokens MUST store CKA_PUBLIC_EXPONENT in any case. This permits the * retrieval of sufficient data to reconstitute the associated public key. */ rc = template_attribute_get_non_empty(tmpl, CKA_PUBLIC_EXPONENT, &attr); if (rc != CKR_OK) { if (mode == MODE_CREATE) { TRACE_ERROR("Could not find CKA_PUBLIC_EXPONENT\n"); return rc; } } rc = template_attribute_get_non_empty(tmpl, CKA_PRIVATE_EXPONENT, &attr); if (rc != CKR_OK) { if (mode == MODE_CREATE) { TRACE_ERROR("Could not find CKA_PRIVATE_EXPONENT\n"); return rc; } } /* The RSA CRT components are optional, no return code checking */ template_attribute_get_non_empty(tmpl, CKA_PRIME_1, &prime1); template_attribute_get_non_empty(tmpl, CKA_PRIME_2, &prime2); template_attribute_get_non_empty(tmpl, CKA_EXPONENT_1, &exp1); template_attribute_get_non_empty(tmpl, CKA_EXPONENT_2, &exp2); template_attribute_get_non_empty(tmpl, CKA_COEFFICIENT, &coef); /* For CREATE either all CRT components or none of them must be specified */ if (mode == MODE_CREATE && !((prime1 == NULL && prime2 == NULL && exp1 == NULL && exp2 == NULL && coef == NULL) || (prime1 != NULL && prime2 != NULL && exp1 != NULL && exp2 != NULL && coef != NULL))) { TRACE_ERROR("Either all CRT attrs must be specified or none of them\n"); return CKR_TEMPLATE_INCONSISTENT; } 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; CK_RV rc; 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) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto error; } 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; rc = template_update_attribute(tmpl, type_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } type_attr = NULL; rc = template_update_attribute(tmpl, modulus_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } modulus_attr = NULL; rc = template_update_attribute(tmpl, private_exp_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } private_exp_attr = NULL; rc = template_update_attribute(tmpl, public_exp_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } public_exp_attr = NULL; return CKR_OK; error: if (type_attr) free(type_attr); if (modulus_attr) free(modulus_attr); if (private_exp_attr) free(private_exp_attr); if (public_exp_attr) free(public_exp_attr); return rc; } // 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_BBOOL crt_alloced = FALSE; CK_RV rc; rc = template_attribute_get_non_empty(tmpl, CKA_MODULUS, &modulus); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); return rc; } rc = template_attribute_get_non_empty(tmpl, CKA_PUBLIC_EXPONENT, &publ_exp); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_PUBLIC_EXPONENT for the key.\n"); return rc; } rc = template_attribute_get_non_empty(tmpl, CKA_PRIVATE_EXPONENT, &priv_exp); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_PRIVATE_EXPONENT for the key.\n"); return rc; } /* CRT attributes are optional */ template_attribute_get_non_empty(tmpl, CKA_PRIME_1, &prime1); template_attribute_get_non_empty(tmpl, CKA_PRIME_2, &prime2); template_attribute_get_non_empty(tmpl, CKA_EXPONENT_1, &exponent1); template_attribute_get_non_empty(tmpl, CKA_EXPONENT_2, &exponent2); template_attribute_get_non_empty(tmpl, CKA_COEFFICIENT, &coeff); if (prime1 == NULL || prime2 == NULL || exponent1 == NULL || exponent2 == NULL || coeff == NULL) { /* no CRT components, calculate them */ rc = calc_rsa_crt_from_me(modulus, publ_exp, priv_exp, &prime1, &prime2, &exponent1, &exponent2, &coeff); if (rc != CKR_OK) { TRACE_ERROR("calc_rsa_crt_from_me failed\n"); return rc; } crt_alloced = TRUE; } rc = ber_encode_RSAPrivateKey(length_only, data, data_len, modulus, publ_exp, priv_exp, prime1, prime2, exponent1, exponent2, coeff); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_RSAPrivateKey failed\n"); } if (crt_alloced) { OPENSSL_cleanse(prime1->pValue, prime1->ulValueLen); free(prime1); OPENSSL_cleanse(prime2->pValue, prime2->ulValueLen); free(prime2); OPENSSL_cleanse(exponent1->pValue, exponent1->ulValueLen); free(exponent1); OPENSSL_cleanse(exponent2->pValue, exponent2->ulValueLen); free(exponent2); OPENSSL_cleanse(coeff->pValue, coeff->ulValueLen); free(coeff); } return rc; } // // CK_RV rsa_priv_unwrap(TEMPLATE *tmpl, CK_BYTE *data, CK_ULONG total_length) { 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_RV rc; rc = ber_decode_RSAPrivateKey(data, total_length, &modulus, &publ_exp, &priv_exp, &prime1, &prime2, &exponent1, &exponent2, &coeff); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_RSAPrivateKey failed\n"); return rc; } p11_attribute_trim(modulus); p11_attribute_trim(publ_exp); 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); rc = template_update_attribute(tmpl, modulus); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } modulus = NULL; rc = template_update_attribute(tmpl, publ_exp); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } publ_exp = NULL; rc = template_update_attribute(tmpl, priv_exp); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } priv_exp = NULL; rc = template_update_attribute(tmpl, prime1); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } prime1 = NULL; rc = template_update_attribute(tmpl, prime2); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } prime2 = NULL; rc = template_update_attribute(tmpl, exponent1); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } exponent1 = NULL; rc = template_update_attribute(tmpl, exponent2); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } exponent2 = NULL; rc = template_update_attribute(tmpl, coeff); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } coeff = NULL; return CKR_OK; error: if (modulus) free(modulus); if (publ_exp) free(publ_exp); if (priv_exp) free(priv_exp); if (prime1) free(prime1); if (prime2) free(prime2); if (exponent1) free(exponent1); if (exponent2) free(exponent2); if (coeff) free(coeff); return rc; } CK_RV rsa_priv_unwrap_get_data(TEMPLATE *tmpl, CK_BYTE *data, CK_ULONG total_length, CK_BBOOL is_public) { CK_ATTRIBUTE *modulus = NULL; CK_ATTRIBUTE *publ_exp = NULL; CK_ULONG mod_bits; 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); mod_bits = modulus->ulValueLen * 8; if (is_public) { rc = template_build_update_attribute(tmpl, CKA_MODULUS_BITS, (CK_BYTE *)&mod_bits, sizeof(mod_bits)); if (rc != CKR_OK) { TRACE_DEVEL("template_build_update_attribute failed.\n"); goto error; } } rc = template_update_attribute(tmpl, modulus); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } modulus = NULL; rc = template_update_attribute(tmpl, publ_exp); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } publ_exp = NULL; return CKR_OK; error: if (modulus) free(modulus); if (publ_exp) free(publ_exp); return rc; } CK_RV rsa_priv_check_and_swap_pq(TEMPLATE *tmpl) { CK_ATTRIBUTE *prime1 = NULL, *prime2 = NULL; CK_ATTRIBUTE *exponent1 = NULL, *exponent2 = NULL; CK_ATTRIBUTE *coeff = NULL; BIGNUM *bn_tmp = NULL; BIGNUM *bn_p = NULL; BIGNUM *bn_q = NULL; BIGNUM *bn_invq = NULL; BN_CTX *ctx = NULL; CK_RV rc = CKR_OK; CK_ULONG len; CK_BYTE *buf = NULL; if (template_attribute_find(tmpl, CKA_PRIME_1, &prime1) == FALSE || prime1->ulValueLen == 0 || prime1->pValue == NULL) { TRACE_DEVEL("Could not find CKA_PRIME_1 for the key, not CRT format.\n"); return CKR_OK; } if (template_attribute_find(tmpl, CKA_PRIME_2, &prime2) == FALSE || prime2->ulValueLen == 0 || prime2->pValue == NULL) { TRACE_DEVEL("Could not find CKA_PRIME_2 for the key, not CRT format.\n"); return CKR_OK; } if (template_attribute_find(tmpl, CKA_EXPONENT_1, &exponent1) == FALSE || exponent1->ulValueLen == 0 || exponent1->pValue == NULL) { TRACE_DEVEL("Could not find CKA_EXPONENT_1 for the key, not CRT format.\n"); return CKR_OK; } if (template_attribute_find(tmpl, CKA_EXPONENT_2, &exponent2) == FALSE || exponent2->ulValueLen == 0 || exponent2->pValue == NULL) { TRACE_DEVEL("Could not find CKA_EXPONENT_2 for the key, not CRT format.\n"); return CKR_OK; } if (template_attribute_find(tmpl, CKA_COEFFICIENT, &coeff) == FALSE || coeff->ulValueLen == 0 || coeff->pValue == NULL) { TRACE_DEVEL("Could not find CKA_COEFFICIENT for the key, not CRT format.\n"); return CKR_OK; } ctx = BN_CTX_secure_new(); if (ctx == NULL) { TRACE_ERROR("BN_CTX_secure_new failed.\n"); rc = CKR_FUNCTION_FAILED; goto out; } bn_p = BN_CTX_get(ctx); bn_q = BN_CTX_get(ctx); bn_invq = BN_CTX_get(ctx); if (bn_p == NULL || bn_q == NULL || bn_invq== NULL) { TRACE_ERROR("BN_CTX_get failed.\n"); rc = CKR_FUNCTION_FAILED; goto out; } if (BN_bin2bn(prime1->pValue, prime1->ulValueLen, bn_p) == NULL || BN_bin2bn(prime2->pValue, prime2->ulValueLen, bn_q) == NULL){ TRACE_ERROR("BN_bin2bn failed.\n"); rc = CKR_FUNCTION_FAILED; goto out; } /* check if p > q */ if (BN_ucmp(bn_p, bn_q) != 1) { /* Unprivileged key format, swap p and q, swap dp and dq, recalc qinv */ bn_tmp = bn_p; bn_p = bn_q; bn_q = bn_tmp; /* qInv = (1/q) mod p */ if (BN_mod_inverse(bn_invq, bn_q, bn_p, ctx) == NULL) { TRACE_ERROR("BN_mod_inverse failed.\n"); rc = CKR_FUNCTION_FAILED; goto out; } len = BN_num_bytes(bn_invq); buf = OPENSSL_secure_zalloc(len); if (buf == NULL) { TRACE_ERROR("OPENSSL_secure_zalloc failed.\n"); rc = CKR_HOST_MEMORY; goto out; } if (BN_bn2binpad(bn_invq, buf, len) <= 0) { TRACE_ERROR("BN_bn2binpad failed.\n"); rc = CKR_FUNCTION_FAILED; goto out; } prime1->type = CKA_PRIME_2; prime2->type = CKA_PRIME_1; exponent1->type = CKA_EXPONENT_2; exponent2->type = CKA_EXPONENT_1; rc = build_attribute(CKA_COEFFICIENT, buf, len, &coeff); if (rc != CKR_OK) { TRACE_ERROR("build_attribute for CKA_COEFFICIENT failed.\n"); goto out; } rc = template_update_attribute(tmpl, coeff); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute for CKA_COEFFICIENT failed.\n"); free(coeff); goto out; } } out: if (bn_p != NULL) BN_clear(bn_p); if (bn_q != NULL) BN_clear(bn_q); if (ctx != NULL) BN_CTX_free(ctx); if (buf != NULL) OPENSSL_clear_free(buf, len); return rc; } static CK_RV pqc_keyform_mode_attrs_by_mech(CK_MECHANISM_TYPE mech, CK_ATTRIBUTE_TYPE *keyform_attr, CK_ATTRIBUTE_TYPE *mode_attr, const struct pqc_oid **oids) { switch (mech) { case CKM_IBM_DILITHIUM: *keyform_attr = CKA_IBM_DILITHIUM_KEYFORM; *mode_attr = CKA_IBM_DILITHIUM_MODE; *oids = dilithium_oids; break; case CKM_IBM_KYBER: *keyform_attr = CKA_IBM_KYBER_KEYFORM; *mode_attr = CKA_IBM_KYBER_MODE; *oids = kyber_oids; break; case CKM_IBM_ML_DSA: case CKM_IBM_ML_DSA_KEY_PAIR_GEN: *keyform_attr = CKA_IBM_PARAMETER_SET; *mode_attr = (CK_ATTRIBUTE_TYPE)-1; *oids = ml_dsa_oids; break; case CKM_IBM_ML_KEM: case CKM_IBM_ML_KEM_KEY_PAIR_GEN: case CKM_IBM_ML_KEM_WITH_ECDH: *keyform_attr = CKA_IBM_PARAMETER_SET; *mode_attr = (CK_ATTRIBUTE_TYPE)-1; *oids = ml_kem_oids; break; case CKM_ML_DSA: case CKM_ML_DSA_KEY_PAIR_GEN: case CKM_HASH_ML_DSA: *keyform_attr = CKA_PARAMETER_SET; *mode_attr = (CK_ATTRIBUTE_TYPE)-1; *oids = ml_dsa_oids; break; case CKM_ML_KEM: case CKM_ML_KEM_KEY_PAIR_GEN: *keyform_attr = CKA_PARAMETER_SET; *mode_attr = (CK_ATTRIBUTE_TYPE)-1; *oids = ml_kem_oids; break; default: TRACE_ERROR("Unsupported mechanims: 0x%lx\n", mech); return CKR_MECHANISM_INVALID; } return CKR_OK; } const struct pqc_oid *pqc_get_keyform_mode(TEMPLATE *tmpl, CK_MECHANISM_TYPE mech) { CK_ATTRIBUTE *attr = NULL; const struct pqc_oid *oids = NULL, *oid; CK_ATTRIBUTE_TYPE keyform_attr = 0; CK_ATTRIBUTE_TYPE mode_attr = 0; if (pqc_keyform_mode_attrs_by_mech(mech, &keyform_attr, &mode_attr, &oids) != CKR_OK) return NULL; if (template_attribute_find(tmpl, keyform_attr, &attr) && attr->ulValueLen == sizeof(CK_ULONG) && attr->pValue != NULL) { oid = find_pqc_by_keyform(oids, *(CK_ULONG *)(attr->pValue)); if (oid == NULL) { TRACE_ERROR("KEYFORM attribute specifies an invalid value: %lu\n", *(CK_ULONG *)(attr->pValue)); return NULL; } return oid; } if (mode_attr != (CK_ATTRIBUTE_TYPE)-1 && template_attribute_find(tmpl, mode_attr, &attr) && attr->ulValueLen != 0 && attr->pValue != NULL) { oid = find_pqc_by_oid(oids, attr->pValue, attr->ulValueLen); if (oid == NULL) { TRACE_ERROR("MODE attribute specifies an invalid value\n"); return NULL; } return oid; } TRACE_ERROR("Neither KEYFORM nor MODE found\n"); return NULL; } CK_RV pqc_add_keyform_mode(TEMPLATE *tmpl, const struct pqc_oid *oid, CK_MECHANISM_TYPE mech) { CK_ATTRIBUTE *mode = NULL; CK_ATTRIBUTE *keyform = NULL; CK_RV rc; CK_ATTRIBUTE_TYPE keyform_attr = 0; CK_ATTRIBUTE_TYPE mode_attr = 0; const struct pqc_oid *oids; if (pqc_keyform_mode_attrs_by_mech(mech, &keyform_attr, &mode_attr, &oids) != CKR_OK) return CKR_MECHANISM_INVALID; if (mode_attr != (CK_ATTRIBUTE_TYPE)-1) { rc = build_attribute(mode_attr, (CK_BYTE *)oid->oid, oid->oid_len, &mode); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto error; } rc = template_update_attribute(tmpl, mode); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } mode = NULL; } rc = build_attribute(keyform_attr, (CK_BYTE *)&oid->keyform, sizeof(CK_ULONG), &keyform); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto error; } rc = template_update_attribute(tmpl, keyform); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } keyform = NULL; return CKR_OK; error: if (mode) free(mode); if (keyform) free(keyform); return rc; } static CK_RV pqc_private_seed_attr_by_mech(CK_MECHANISM_TYPE mech, CK_ATTRIBUTE_TYPE *priv_seed_attr) { switch (mech) { case CKM_IBM_DILITHIUM: *priv_seed_attr = (CK_ATTRIBUTE_TYPE)-1; break; case CKM_IBM_KYBER: *priv_seed_attr = (CK_ATTRIBUTE_TYPE)-1; break; case CKM_IBM_ML_DSA: case CKM_IBM_ML_DSA_KEY_PAIR_GEN: *priv_seed_attr = CKA_IBM_ML_DSA_PRIVATE_SEED; break; case CKM_IBM_ML_KEM: case CKM_IBM_ML_KEM_KEY_PAIR_GEN: *priv_seed_attr = CKA_IBM_ML_KEM_PRIVATE_SEED; break; default: TRACE_ERROR("Unsupported mechanims: 0x%lx\n", mech); return CKR_MECHANISM_INVALID; } return CKR_OK; } /* * Extract the SubjectPublicKeyInfo from the Dilithium or ML-DSA public key */ CK_RV ibm_ml_dsa_publ_get_spki(TEMPLATE *tmpl, CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, CK_MECHANISM_TYPE mech) { CK_ATTRIBUTE *rho = NULL; CK_ATTRIBUTE *t1 = NULL; const struct pqc_oid *oid; CK_RV rc; oid = pqc_get_keyform_mode(tmpl, mech); if (oid == NULL) return CKR_TEMPLATE_INCOMPLETE; rc = template_attribute_get_non_empty(tmpl, CKA_IBM_ML_DSA_RHO, &rho); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_ML_DSA_RHO for the key.\n"); return rc; } rc = template_attribute_get_non_empty(tmpl, CKA_IBM_ML_DSA_T1, &t1); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_ML_DSA_T1 for the key.\n"); return rc; } rc = ber_encode_IBM_ML_DSA_PublicKey(mech, length_only, data, data_len, oid->oid, oid->oid_len, rho, t1); if (rc != CKR_OK) { TRACE_ERROR("ber_encode_IBM_ML_DSA_PublicKey failed.\n"); return rc; } return CKR_OK; } CK_RV ibm_ml_dsa_priv_wrap_get_data(TEMPLATE *tmpl, CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, CK_MECHANISM_TYPE mech) { CK_ATTRIBUTE *rho = NULL, *seed = NULL; CK_ATTRIBUTE *tr = NULL, *s1 = NULL, *s2 = NULL; CK_ATTRIBUTE *t0 = NULL, *t1 = NULL, *priv_seed = NULL; const struct pqc_oid *oid; CK_MECHANISM_TYPE priv_seed_attr; CK_RV rc; oid = pqc_get_keyform_mode(tmpl, mech); if (oid == NULL) return CKR_TEMPLATE_INCOMPLETE; rc = pqc_private_seed_attr_by_mech(mech, &priv_seed_attr); if (rc != CKR_OK) return rc; /* If private seed is available, then the other components are optional */ if (priv_seed_attr != (CK_MECHANISM_TYPE)-1 && template_attribute_find(tmpl, priv_seed_attr, &priv_seed) == TRUE) { if (priv_seed->ulValueLen == 0 || priv_seed->pValue == NULL) priv_seed = NULL; } template_attribute_find(tmpl, CKA_IBM_ML_DSA_RHO, &rho); template_attribute_find(tmpl, CKA_IBM_ML_DSA_SEED, &seed); template_attribute_find(tmpl, CKA_IBM_ML_DSA_TR, &tr); template_attribute_find(tmpl, CKA_IBM_ML_DSA_S1, &s1); template_attribute_find(tmpl, CKA_IBM_ML_DSA_S2, &s2); template_attribute_find(tmpl, CKA_IBM_ML_DSA_T0, &t0); template_attribute_find(tmpl, CKA_IBM_ML_DSA_T1, &t1); if (priv_seed == NULL) { if (rho == NULL || rho->ulValueLen == 0 || rho->pValue == NULL) { TRACE_ERROR("Could not find CKA_IBM_ML_DSA_RHO for the key.\n"); return CKR_TEMPLATE_INCOMPLETE; } if (seed == NULL || seed->ulValueLen == 0 || seed->pValue == NULL) { TRACE_ERROR("Could not find CKA_IBM_ML_DSA_SEED for the key.\n"); return CKR_TEMPLATE_INCOMPLETE; } if (tr == NULL || tr->ulValueLen == 0 || tr->pValue == NULL) { TRACE_ERROR("Could not find CKA_IBM_ML_DSA_TR for the key.\n"); return CKR_TEMPLATE_INCOMPLETE; } if (s1 == NULL || s1->ulValueLen == 0 || s1->pValue == NULL) { TRACE_ERROR("Could not find CKA_IBM_ML_DSA_S1 for the key.\n"); return CKR_TEMPLATE_INCOMPLETE; } if (s2 == NULL || s2->ulValueLen == 0 || s2->pValue == NULL) { TRACE_ERROR("Could not find CKA_IBM_ML_DSA_S2 for the key.\n"); return CKR_TEMPLATE_INCOMPLETE; } if (t0 == NULL || t0->ulValueLen == 0 || t0->pValue == NULL) { TRACE_ERROR("Could not find CKA_IBM_ML_DSA_T0 for the key.\n"); return CKR_TEMPLATE_INCOMPLETE; } /* t1 is optional and can be NULL */ } rc = ber_encode_IBM_ML_DSA_PrivateKey(mech, length_only, data, data_len, oid->oid, oid->oid_len, rho, seed, tr, s1, s2, t0, t1, priv_seed); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_IBM_ML_DSA_PrivateKey failed\n"); } return rc; } CK_RV ibm_ml_dsa_priv_unwrap_get_data(TEMPLATE *tmpl, CK_BYTE *data, CK_ULONG total_length, CK_BBOOL is_public, CK_MECHANISM_TYPE mech) { CK_ATTRIBUTE *rho = NULL; CK_ATTRIBUTE *t1 = NULL; CK_ATTRIBUTE *value = NULL; const struct pqc_oid *oid; CK_RV rc; rc = ber_decode_IBM_ML_DSA_PublicKey(mech, data, total_length, &rho, &t1, &value, &oid); if (rc != CKR_OK) { TRACE_ERROR("ber_decode_IBM_ML_DSA_PublicKey failed\n"); return rc; } rc = pqc_add_keyform_mode(tmpl, oid, mech); if (rc != CKR_OK) { TRACE_ERROR("pqc_add_keyform_mode failed\n"); goto error; } rc = template_update_attribute(tmpl, rho); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } rho = NULL; rc = template_update_attribute(tmpl, t1); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } t1 = NULL; if (is_public) { rc = template_update_attribute(tmpl, value); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } } else { free(value); } value = NULL; return CKR_OK; error: if (rho) free(rho); if (t1) free(t1); if (value) free(value); return rc; } // // CK_RV ibm_ml_dsa_priv_unwrap(TEMPLATE *tmpl, CK_BYTE *data, CK_ULONG total_length, CK_BBOOL add_value, CK_MECHANISM_TYPE mech) { CK_ATTRIBUTE *rho = NULL, *seed = NULL, *tr = NULL, *value = NULL; CK_ATTRIBUTE *s1 = NULL, *s2 = NULL, *t0 = NULL, *t1 = NULL; CK_ATTRIBUTE *private_seed = NULL; const struct pqc_oid *oid; CK_RV rc; rc = ber_decode_IBM_ML_DSA_PrivateKey(mech, data, total_length, &rho, &seed, &tr, &s1, &s2, &t0, &t1, &private_seed, &value, &oid); if (rc != CKR_OK) { TRACE_ERROR("ber_decode_IBM_ML_DSA_PrivateKey failed\n"); return rc; } rc = pqc_add_keyform_mode(tmpl, oid, mech); if (rc != CKR_OK) { TRACE_ERROR("pqc_add_keyform_mode failed\n"); goto error; } if (rho != NULL) { rc = template_update_attribute(tmpl, rho); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } rho = NULL; } if (seed != NULL) { rc = template_update_attribute(tmpl, seed); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } seed = NULL; } if (tr != NULL) { rc = template_update_attribute(tmpl, tr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } tr = NULL; } if (s1 != NULL) { rc = template_update_attribute(tmpl, s1); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } s1 = NULL; } if (s2 != NULL) { rc = template_update_attribute(tmpl, s2); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } s2 = NULL; } if (t0 != NULL) { rc = template_update_attribute(tmpl, t0); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } t0 = NULL; } if (t1 != NULL) { rc = template_update_attribute(tmpl, t1); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } t1 = NULL; } if (private_seed) { rc = template_update_attribute(tmpl, private_seed); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } private_seed = NULL; } if (add_value) { rc = template_update_attribute(tmpl, value); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } } else { free(value); } value = NULL; return CKR_OK; error: if (rho) free(rho); if (seed) free(seed); if (tr) free(tr); if (s1) free(s1); if (s2) free(s2); if (t0) free(t0); if (t1) free(t1); if (private_seed) free(private_seed); if (value) free(value); return rc; } /* * Extract the SubjectPublicKeyInfo from the Kyber or ML-KEM public key */ CK_RV ibm_ml_kem_publ_get_spki(TEMPLATE *tmpl, CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, CK_MECHANISM_TYPE mech) { CK_ATTRIBUTE *pk = NULL; const struct pqc_oid *oid; CK_RV rc; oid = pqc_get_keyform_mode(tmpl, mech); if (oid == NULL) return CKR_TEMPLATE_INCOMPLETE; rc = template_attribute_get_non_empty(tmpl, CKA_IBM_ML_KEM_PK, &pk); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_ML_KEM_PK for the key.\n"); return rc; } rc = ber_encode_IBM_ML_KEM_PublicKey(mech, length_only, data, data_len, oid->oid, oid->oid_len, pk); if (rc != CKR_OK) { TRACE_ERROR("ber_encode_IBM_ML_KEM_PublicKey failed.\n"); return rc; } return CKR_OK; } CK_RV ibm_ml_kem_priv_wrap_get_data(TEMPLATE *tmpl, CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, CK_MECHANISM_TYPE mech) { CK_ATTRIBUTE *sk = NULL, *pk = NULL, *priv_seed = NULL; const struct pqc_oid *oid; CK_MECHANISM_TYPE priv_seed_attr; CK_RV rc; oid = pqc_get_keyform_mode(tmpl, mech); if (oid == NULL) return CKR_TEMPLATE_INCOMPLETE; rc = pqc_private_seed_attr_by_mech(mech, &priv_seed_attr); if (rc != CKR_OK) return rc; /* If private seed is available, then the other components are optional */ if (priv_seed_attr != (CK_MECHANISM_TYPE)-1 && template_attribute_find(tmpl, priv_seed_attr, &priv_seed) == TRUE) { if (priv_seed->ulValueLen == 0 || priv_seed->pValue == NULL) priv_seed = NULL; } template_attribute_find(tmpl, CKA_IBM_ML_KEM_SK, &sk); template_attribute_find(tmpl, CKA_IBM_ML_KEM_PK, &pk); if (priv_seed == NULL) { if (sk == NULL || sk->ulValueLen == 0 || sk->pValue == NULL) { TRACE_ERROR("Could not find CKA_IBM_ML_KEM_SK for the key.\n"); return CKR_TEMPLATE_INCOMPLETE; } /* pk is optional and can be NULL */ } rc = ber_encode_IBM_ML_KEM_PrivateKey(mech, length_only, data, data_len, oid->oid, oid->oid_len, sk, pk, priv_seed); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_IBM_ML_KEM_PrivateKey failed\n"); } return rc; } CK_RV ibm_ml_kem_priv_unwrap_get_data(TEMPLATE *tmpl, CK_BYTE *data, CK_ULONG total_length, CK_BBOOL is_public, CK_MECHANISM_TYPE mech) { CK_ATTRIBUTE *pk = NULL; CK_ATTRIBUTE *value = NULL; const struct pqc_oid *oid; CK_RV rc; rc = ber_decode_IBM_ML_KEM_PublicKey(mech, data, total_length, &pk, &value, &oid); if (rc != CKR_OK) { TRACE_ERROR("ber_decode_IBM_ML_KEM_PublicKey failed\n"); return rc; } rc = pqc_add_keyform_mode(tmpl, oid, mech); if (rc != CKR_OK) { TRACE_ERROR("pqc_add_keyform_mode failed\n"); goto error; } rc = template_update_attribute(tmpl, pk); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } pk = NULL; if (is_public) { rc = template_update_attribute(tmpl, value); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } } else { free(value); } value = NULL; return CKR_OK; error: if (pk) free(pk); if (value) free(value); return rc; } // // CK_RV ibm_ml_kem_priv_unwrap(TEMPLATE *tmpl, CK_BYTE *data, CK_ULONG total_length, CK_BBOOL add_value, CK_MECHANISM_TYPE mech) { CK_ATTRIBUTE *sk = NULL, *pk = NULL, *value = NULL; CK_ATTRIBUTE *private_seed = NULL; const struct pqc_oid *oid; CK_RV rc; rc = ber_decode_IBM_ML_KEM_PrivateKey(mech, data, total_length, &sk, &pk, &private_seed, &value, &oid); if (rc != CKR_OK) { TRACE_ERROR("ber_decode_IBM_ML_KEM_PrivateKey mech, failed\n"); return rc; } rc = pqc_add_keyform_mode(tmpl, oid, mech); if (rc != CKR_OK) { TRACE_ERROR("pqc_add_keyform_mode failed\n"); goto error; } if (sk != NULL) { rc = template_update_attribute(tmpl, sk); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } sk = NULL; } if (pk != NULL) { rc = template_update_attribute(tmpl, pk); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } pk = NULL; } if (private_seed != NULL) { rc = template_update_attribute(tmpl, private_seed); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } private_seed = NULL; } if (add_value) { rc = template_update_attribute(tmpl, value); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } } else { free(value); } value = NULL; return CKR_OK; error: if (sk) free(sk); if (pk) free(pk); if (private_seed) free(private_seed); if (value) free(value); return rc; } CK_RV ml_dsa_publ_get_spki(TEMPLATE *tmpl, CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, CK_BBOOL is_priv_tmpl) { CK_ATTRIBUTE *value = NULL; const struct pqc_oid *oid; CK_ATTRIBUTE val_attr = { 0, NULL, 0 }; CK_RV rc; oid = pqc_get_keyform_mode(tmpl, CKM_ML_DSA); if (oid == NULL) return CKR_TEMPLATE_INCOMPLETE; if (is_priv_tmpl) { #if OPENSSL_VERSION_PREREQ(3, 0) /* * An ML-DSA private key does not contain the public key components, * try to calculate them from the private key using OpenSSL */ rc = openssl_specific_pqc_get_pub_key_from_priv_key(tmpl, oid, CKM_ML_DSA, &val_attr); if (rc != CKR_OK) { TRACE_ERROR("openssl_specific_pqc_get_pub_key_from_priv_key " "failed.\n"); goto out; } value = &val_attr; #else TRACE_ERROR("OpenSSL < 3.0.0: Can not calc pub key from priv key\n"); return CKR_TEMPLATE_INCOMPLETE; #endif } else { rc = template_attribute_get_non_empty(tmpl, CKA_VALUE, &value); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); goto out; } } rc = ber_encode_ML_DSA_PublicKey(length_only, data, data_len, oid->oid, oid->oid_len, value); if (rc != CKR_OK) { TRACE_ERROR("ber_encode_ML_DSA_PublicKey failed.\n"); goto out; } out: if (val_attr.pValue != NULL) free(val_attr.pValue); return rc; } CK_RV ml_dsa_priv_wrap_get_data(TEMPLATE *tmpl, CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len) { CK_ATTRIBUTE *value = NULL, *seed = NULL; const struct pqc_oid *oid; CK_RV rc; oid = pqc_get_keyform_mode(tmpl, CKM_ML_DSA); if (oid == NULL) return CKR_TEMPLATE_INCOMPLETE; /* If seed is available, then the value is optional */ if (template_attribute_find(tmpl, CKA_SEED, &seed) == TRUE) { if (seed->ulValueLen == 0 || seed->pValue == NULL) seed = NULL; } template_attribute_find(tmpl, CKA_VALUE, &value); if (seed == NULL) { if (value == NULL || value->ulValueLen == 0 || value->pValue == NULL) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); return CKR_TEMPLATE_INCOMPLETE; } } rc = ber_encode_ML_DSA_PrivateKey(length_only, data, data_len, oid->oid, oid->oid_len, value, seed); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_ML_DSA_PrivateKey failed\n"); } return rc; } CK_RV ml_dsa_priv_unwrap_get_data(TEMPLATE *tmpl, CK_BYTE *data, CK_ULONG total_length, CK_BBOOL is_public) { CK_ATTRIBUTE *value = NULL; const struct pqc_oid *oid; CK_RV rc; rc = ber_decode_ML_DSA_PublicKey(data, total_length, &value, &oid); if (rc != CKR_OK) { TRACE_ERROR("ber_decode_ML_DSA_PublicKey failed\n"); return rc; } rc = pqc_add_keyform_mode(tmpl, oid, CKM_ML_DSA); if (rc != CKR_OK) { TRACE_ERROR("pqc_add_keyform_mode failed\n"); goto error; } if (is_public) { rc = template_update_attribute(tmpl, value); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } } else { free(value); } value = NULL; return CKR_OK; error: if (value) free(value); return rc; } CK_RV ml_dsa_priv_unwrap(TEMPLATE *tmpl, CK_BYTE *data, CK_ULONG total_length, CK_BBOOL add_value) { CK_ATTRIBUTE *seed = NULL, *value = NULL; const struct pqc_oid *oid; CK_RV rc; rc = ber_decode_ML_DSA_PrivateKey(data, total_length, &value, &seed, &oid); if (rc != CKR_OK) { TRACE_ERROR("ber_decode_ML_DSA_PrivateKey failed\n"); return rc; } rc = pqc_add_keyform_mode(tmpl, oid, CKM_ML_DSA); if (rc != CKR_OK) { TRACE_ERROR("pqc_add_keyform_mode failed\n"); goto error; } if (seed != NULL) { rc = template_update_attribute(tmpl, seed); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } seed = NULL; } if (add_value && value != NULL) { rc = template_update_attribute(tmpl, value); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } } else if (value != NULL) { free(value); } value = NULL; return CKR_OK; error: if (seed) free(seed); if (value) free(value); return rc; } CK_RV ml_kem_publ_get_spki(TEMPLATE *tmpl, CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, CK_BBOOL is_priv_tmpl) { CK_ATTRIBUTE *value = NULL; const struct pqc_oid *oid; CK_ATTRIBUTE val_attr = { 0, NULL, 0 }; CK_RV rc; oid = pqc_get_keyform_mode(tmpl, CKM_ML_KEM); if (oid == NULL) return CKR_TEMPLATE_INCOMPLETE; if (is_priv_tmpl) { #if OPENSSL_VERSION_PREREQ(3, 0) /* * An ML-KEM private key does not contain the public key components, * try to calculate them from the private key using OpenSSL */ rc = openssl_specific_pqc_get_pub_key_from_priv_key(tmpl, oid, CKM_ML_KEM, &val_attr); if (rc != CKR_OK) { TRACE_ERROR("openssl_specific_pqc_get_pub_key_from_priv_key " "failed.\n"); goto out; } value = &val_attr; #else TRACE_ERROR("OpenSSL < 3.0.0: Can not calc pub key from priv key\n"); return CKR_TEMPLATE_INCOMPLETE; #endif } else { rc = template_attribute_get_non_empty(tmpl, CKA_VALUE, &value); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); goto out; } } rc = ber_encode_ML_KEM_PublicKey(length_only, data, data_len, oid->oid, oid->oid_len, value); if (rc != CKR_OK) { TRACE_ERROR("ber_encode_ML_KEM_PublicKey failed.\n"); goto out; } out: if (val_attr.pValue != NULL) free(val_attr.pValue); return rc; } CK_RV ml_kem_priv_wrap_get_data(TEMPLATE *tmpl, CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len) { CK_ATTRIBUTE *value = NULL, *seed = NULL; const struct pqc_oid *oid; CK_RV rc; oid = pqc_get_keyform_mode(tmpl, CKM_ML_KEM); if (oid == NULL) return CKR_TEMPLATE_INCOMPLETE; /* If seed is available, then the value is optional */ if (template_attribute_find(tmpl, CKA_SEED, &seed) == TRUE) { if (seed->ulValueLen == 0 || seed->pValue == NULL) seed = NULL; } template_attribute_find(tmpl, CKA_VALUE, &value); if (seed == NULL) { if (value == NULL || value->ulValueLen == 0 || value->pValue == NULL) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); return CKR_TEMPLATE_INCOMPLETE; } } rc = ber_encode_ML_KEM_PrivateKey(length_only, data, data_len, oid->oid, oid->oid_len, value, seed); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_ML_KEM_PrivateKey failed\n"); } return rc; } CK_RV ml_kem_priv_unwrap_get_data(TEMPLATE *tmpl, CK_BYTE *data, CK_ULONG total_length, CK_BBOOL is_public) { CK_ATTRIBUTE *value = NULL; const struct pqc_oid *oid; CK_RV rc; rc = ber_decode_ML_KEM_PublicKey(data, total_length, &value, &oid); if (rc != CKR_OK) { TRACE_ERROR("ber_decode_ML_KEM_PublicKey failed\n"); return rc; } rc = pqc_add_keyform_mode(tmpl, oid, CKM_ML_KEM); if (rc != CKR_OK) { TRACE_ERROR("pqc_add_keyform_mode failed\n"); goto error; } if (is_public) { rc = template_update_attribute(tmpl, value); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } } else { free(value); } value = NULL; return CKR_OK; error: if (value) free(value); return rc; } CK_RV ml_kem_priv_unwrap(TEMPLATE *tmpl, CK_BYTE *data, CK_ULONG total_length, CK_BBOOL add_value) { CK_ATTRIBUTE *seed = NULL, *value = NULL; const struct pqc_oid *oid; CK_RV rc; rc = ber_decode_ML_KEM_PrivateKey(data, total_length, &value, &seed, &oid); if (rc != CKR_OK) { TRACE_ERROR("ber_decode_ML_KEM_PrivateKey failed\n"); return rc; } rc = pqc_add_keyform_mode(tmpl, oid, CKM_ML_KEM); if (rc != CKR_OK) { TRACE_ERROR("pqc_add_keyform_mode failed\n"); goto error; } if (seed != NULL) { rc = template_update_attribute(tmpl, seed); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } seed = NULL; } if (add_value && value != NULL) { rc = template_update_attribute(tmpl, value); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } } else if (value != NULL) { free(value); } value = NULL; return CKR_OK; error: if (seed) free(seed); if (value) free(value); return rc; } CK_RV pqc_publ_get_spki(TEMPLATE *tmpl, CK_KEY_TYPE keytype, CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, CK_BBOOL is_priv_tmpl) { switch (keytype) { case CKK_IBM_PQC_DILITHIUM: return ibm_ml_dsa_publ_get_spki(tmpl, length_only, data, data_len, CKM_IBM_DILITHIUM); case CKK_IBM_PQC_KYBER: return ibm_ml_kem_publ_get_spki(tmpl, length_only, data, data_len, CKM_IBM_KYBER); case CKK_IBM_ML_DSA: return ibm_ml_dsa_publ_get_spki(tmpl, length_only, data, data_len, CKM_IBM_ML_DSA); case CKK_IBM_ML_KEM: return ibm_ml_kem_publ_get_spki(tmpl, length_only, data, data_len, CKM_IBM_ML_KEM); case CKK_ML_DSA: return ml_dsa_publ_get_spki(tmpl, length_only, data, data_len, is_priv_tmpl); case CKK_ML_KEM: return ml_kem_publ_get_spki(tmpl, length_only, data, data_len, is_priv_tmpl); default: TRACE_DEVEL("Key type 0x%lx not supported.\n", keytype); return CKR_KEY_TYPE_INCONSISTENT; } } CK_RV pqc_priv_wrap_get_data(TEMPLATE *tmpl, CK_KEY_TYPE keytype, CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len) { switch (keytype) { case CKK_IBM_PQC_DILITHIUM: return ibm_ml_dsa_priv_wrap_get_data(tmpl, length_only, data, data_len, CKM_IBM_DILITHIUM); case CKK_IBM_PQC_KYBER: return ibm_ml_kem_priv_wrap_get_data(tmpl, length_only, data, data_len, CKM_IBM_KYBER); case CKK_IBM_ML_DSA: return ibm_ml_dsa_priv_wrap_get_data(tmpl, length_only, data, data_len, CKM_IBM_ML_DSA); case CKK_IBM_ML_KEM: return ibm_ml_kem_priv_wrap_get_data(tmpl, length_only, data, data_len, CKM_IBM_ML_KEM); case CKK_ML_DSA: return ml_dsa_priv_wrap_get_data(tmpl, length_only, data, data_len); case CKK_ML_KEM: return ml_kem_priv_wrap_get_data(tmpl, length_only, data, data_len); default: TRACE_DEVEL("Key type 0x%lx not supported.\n", keytype); return CKR_KEY_TYPE_INCONSISTENT; } } CK_RV pqc_priv_unwrap(TEMPLATE *tmpl, CK_KEY_TYPE keytype, CK_BYTE *data, CK_ULONG total_length, CK_BBOOL add_value) { switch (keytype) { case CKK_IBM_PQC_DILITHIUM: return ibm_ml_dsa_priv_unwrap(tmpl, data, total_length, add_value, CKM_IBM_DILITHIUM); case CKK_IBM_PQC_KYBER: return ibm_ml_kem_priv_unwrap(tmpl, data, total_length, add_value, CKM_IBM_KYBER); case CKK_IBM_ML_DSA: return ibm_ml_dsa_priv_unwrap(tmpl, data, total_length, add_value, CKM_IBM_ML_DSA); case CKK_IBM_ML_KEM: return ibm_ml_kem_priv_unwrap(tmpl, data, total_length, add_value, CKM_IBM_ML_KEM); case CKK_ML_DSA: return ml_dsa_priv_unwrap(tmpl, data, total_length, add_value); case CKK_ML_KEM: return ml_kem_priv_unwrap(tmpl, data, total_length, add_value); default: TRACE_DEVEL("Key type 0x%lx not supported.\n", keytype); return CKR_KEY_TYPE_INCONSISTENT; } } CK_RV pqc_priv_unwrap_get_data(TEMPLATE *tmpl, CK_KEY_TYPE keytype, CK_BYTE *data, CK_ULONG total_length, CK_BBOOL is_public) { switch (keytype) { case CKK_IBM_PQC_DILITHIUM: return ibm_ml_dsa_priv_unwrap_get_data(tmpl, data, total_length, is_public, CKM_IBM_DILITHIUM); case CKK_IBM_PQC_KYBER: return ibm_ml_kem_priv_unwrap_get_data(tmpl, data, total_length, is_public, CKM_IBM_KYBER); case CKK_IBM_ML_DSA: return ibm_ml_dsa_priv_unwrap_get_data(tmpl, data, total_length, is_public, CKM_IBM_ML_DSA); case CKK_IBM_ML_KEM: return ibm_ml_kem_priv_unwrap_get_data(tmpl, data, total_length, is_public, CKM_IBM_ML_KEM); case CKK_ML_DSA: return ml_dsa_priv_unwrap_get_data(tmpl, data, total_length, is_public); case CKK_ML_KEM: return ml_kem_priv_unwrap_get_data(tmpl, data, total_length, is_public); default: TRACE_DEVEL("Key type 0x%lx not supported.\n", keytype); return CKR_KEY_TYPE_INCONSISTENT; } } // dsa_publ_check_required_attributes() // CK_RV dsa_publ_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) { CK_ATTRIBUTE *attr = NULL; CK_RV rc; if (mode == MODE_CREATE && token_specific.secure_key_token == TRUE && template_attribute_get_non_empty(tmpl, CKA_IBM_OPAQUE, &attr) == CKR_OK) { /* * Import of an already existing secure key. Only * do the base checks for public key templates. */ return publ_key_check_required_attributes(tmpl, mode); } rc = template_attribute_get_non_empty(tmpl, CKA_PRIME, &attr); if (rc != CKR_OK) { if (mode == MODE_CREATE || mode == MODE_EXTRACT) { TRACE_ERROR("Could not find CKA_PRIME\n"); return rc; } } rc = template_attribute_get_non_empty(tmpl, CKA_SUBPRIME, &attr); if (rc != CKR_OK) { if (mode == MODE_CREATE || mode == MODE_EXTRACT) { TRACE_ERROR("Could not find CKA_SUBPRIME\n"); return rc; } } rc = template_attribute_get_non_empty(tmpl, CKA_BASE, &attr); if (rc != CKR_OK) { if (mode == MODE_CREATE || mode == MODE_EXTRACT) { TRACE_ERROR("Could not find CKA_BASE\n"); return rc; } } rc = template_attribute_get_non_empty(tmpl, CKA_VALUE, &attr); if (rc != CKR_OK) { if (mode == MODE_CREATE || mode == MODE_EXTRACT) { TRACE_ERROR("Could not find CKA_VALUE\n"); return rc; } } 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; CK_RV rc; 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) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto error; } 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; rc = template_update_attribute(tmpl, type_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } type_attr = NULL; rc = template_update_attribute(tmpl, prime_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } prime_attr = NULL; rc = template_update_attribute(tmpl, subprime_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } subprime_attr = NULL; rc = template_update_attribute(tmpl, base_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } base_attr = NULL; rc = template_update_attribute(tmpl, value_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } value_attr = NULL; return CKR_OK; error: 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); return rc; } // 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 && mode != MODE_ENCAPS && mode != MODE_EXTRACT) { 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 % 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 && mode != MODE_ENCAPS && mode != MODE_EXTRACT) { 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 || mode == MODE_ENCAPS || mode == MODE_EXTRACT) { 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 || mode == MODE_EXTRACT) { 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); } } /* * Extract the SubjectPublicKeyInfo from the DSA public key */ CK_RV dsa_publ_get_spki(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; rc = template_attribute_get_non_empty(tmpl, CKA_PRIME, &prime); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_PRIME for the key.\n"); return rc; } rc = template_attribute_get_non_empty(tmpl, CKA_BASE, &base); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_BASE for the key.\n"); return rc; } rc = template_attribute_get_non_empty(tmpl, CKA_SUBPRIME, &subprime); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_SUBPRIME for the key.\n"); return rc; } rc = template_attribute_get_non_empty(tmpl, CKA_VALUE, &value); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); return rc; } rc = ber_encode_DSAPublicKey(length_only, data,data_len, prime, subprime, base, value); if (rc != CKR_OK) { TRACE_ERROR("ber_encode_DSAPublicKey failed.\n"); return rc; } return CKR_OK; } // dsa_priv_check_required_attributes() // CK_RV dsa_priv_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) { CK_ATTRIBUTE *attr = NULL; CK_RV rc; if (mode == MODE_CREATE && token_specific.secure_key_token == TRUE && template_attribute_get_non_empty(tmpl, CKA_IBM_OPAQUE, &attr) == CKR_OK) { /* * Import of an already existing secure key. Only * do the base checks for private key templates. */ return priv_key_check_required_attributes(tmpl, mode); } rc = template_attribute_get_non_empty(tmpl, CKA_PRIME, &attr); if (rc != CKR_OK) { if (mode == MODE_CREATE) { TRACE_ERROR("Could not find CKA_PRIME\n"); return rc; } } rc = template_attribute_get_non_empty(tmpl, CKA_SUBPRIME, &attr); if (rc != CKR_OK) { if (mode == MODE_CREATE) { TRACE_ERROR("Could not find CKA_SUBPRIME\n"); return rc; } } rc = template_attribute_get_non_empty(tmpl, CKA_BASE, &attr); if (rc != CKR_OK) { if (mode == MODE_CREATE) { TRACE_ERROR("Could not find CKA_BASE\n"); return rc; } } rc = template_attribute_get_non_empty(tmpl, CKA_VALUE, &attr); if (rc != CKR_OK) { if (mode == MODE_CREATE) { TRACE_ERROR("Could not find CKA_VALUE\n"); return rc; } } 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; CK_RV rc; 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) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto error; } 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; rc = template_update_attribute(tmpl, type_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } type_attr = NULL; rc = template_update_attribute(tmpl, prime_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } prime_attr = NULL; rc = template_update_attribute(tmpl, subprime_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } subprime_attr = NULL; rc = template_update_attribute(tmpl, base_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } base_attr = NULL; rc = template_update_attribute(tmpl, value_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } value_attr = NULL; return CKR_OK; error: 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); return rc; } // 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 // rc = template_attribute_get_non_empty(tmpl, CKA_PRIME, &prime); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_PRIME for the key.\n"); return rc; } rc = template_attribute_get_non_empty(tmpl, CKA_SUBPRIME, &subprime); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_SUBPRIME for the key.\n"); return rc; } rc = template_attribute_get_non_empty(tmpl, CKA_BASE, &base); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_BASE for the key.\n"); return rc; } rc = template_attribute_get_non_empty(tmpl, CKA_VALUE, &value); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); return rc; } 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); rc = template_update_attribute(tmpl, prime); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } prime = NULL; rc = template_update_attribute(tmpl, subprime); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } subprime = NULL; rc = template_update_attribute(tmpl, base); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } base = NULL; rc = template_update_attribute(tmpl, value); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } value = NULL; return CKR_OK; error: if (prime) free(prime); if (subprime) free(subprime); if (base) free(base); if (value) free(value); return rc; } CK_RV dsa_priv_unwrap_get_data(TEMPLATE *tmpl, CK_BYTE *data, CK_ULONG total_length, CK_BBOOL is_public) { 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_ERROR("template_update_attribute failed\n"); goto error; } prime = NULL; rc = template_update_attribute(tmpl, subprime); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } subprime = NULL; rc = template_update_attribute(tmpl, base); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } base = NULL; if (is_public) { rc = template_update_attribute(tmpl, value); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } } else { free(value); } value = NULL; return CKR_OK; error: if (prime) free(prime); if (subprime) free(subprime); if (base) free(base); if (value) free(value); return rc; } // ec_publ_check_required_attributes() // CK_RV ec_publ_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) { CK_ATTRIBUTE *attr = NULL; CK_RV rc; if (mode == MODE_CREATE && token_specific.secure_key_token == TRUE && template_attribute_get_non_empty(tmpl, CKA_IBM_OPAQUE, &attr) == CKR_OK) { /* * Import of an already existing secure key. Only * do the base checks for a public key templates. */ return publ_key_check_required_attributes(tmpl, mode); } rc = template_attribute_get_non_empty(tmpl, CKA_EC_PARAMS, &attr); if (rc != CKR_OK) { if (mode == MODE_CREATE || mode == MODE_KEYGEN || mode == MODE_ENCAPS || mode == MODE_EXTRACT) { TRACE_ERROR("Could not find CKA_EC_PARAMS\n"); return rc; } } rc = template_attribute_get_non_empty(tmpl, CKA_EC_POINT, &attr); if (rc != CKR_OK) { if (mode == MODE_CREATE || mode == MODE_EXTRACT) { TRACE_ERROR("Could not find CKA_EC_POINT\n"); return rc; } } return publ_key_check_required_attributes(tmpl, mode); } // ec_publ_set_default_attributes() // CK_RV ec_publ_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode, CK_KEY_TYPE key_type) { CK_ATTRIBUTE *params_attr = NULL; CK_ATTRIBUTE *ec_point_attr = NULL; CK_ATTRIBUTE *type_attr = NULL; CK_RV rc; 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) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto error; } params_attr->type = CKA_EC_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 = key_type; rc = template_update_attribute(tmpl, type_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } type_attr = NULL; rc = template_update_attribute(tmpl, params_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } params_attr = NULL; rc = template_update_attribute(tmpl, ec_point_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } ec_point_attr = NULL; return CKR_OK; error: if (type_attr) free(type_attr); if (params_attr) free(params_attr); if (ec_point_attr) free(ec_point_attr); return rc; } // ec_publ_validate_attributes() // CK_RV ec_publ_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_ATTRIBUTE *attr, CK_ULONG mode) { switch (attr->type) { case CKA_EC_PARAMS: if (mode == MODE_CREATE || mode == MODE_KEYGEN || mode == MODE_DERIVE || mode == MODE_ENCAPS || mode == MODE_EXTRACT) 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 || mode == MODE_EXTRACT) 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); } } /* * Extract the SubjectPublicKeyInfo from the EC public key */ CK_RV ec_publ_get_spki(TEMPLATE *tmpl, CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, CK_KEY_TYPE key_type) { CK_ATTRIBUTE *ec_parms = NULL; CK_ATTRIBUTE *ec_point = NULL; CK_ATTRIBUTE *value = NULL; CK_BYTE *buf = NULL; CK_ULONG buf_len = 0; CK_ATTRIBUTE point = { .type = CKA_EC_POINT, .pValue = NULL, .ulValueLen = 0 }; int i, curve_type = -1; CK_RV rc; rc = template_attribute_get_non_empty(tmpl, CKA_EC_PARAMS, &ec_parms); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_EC_PARAMS for the key.\n"); return rc; } for (i = 0; i < NUMEC; i++) { if (der_ec_supported[i].data_size == ec_parms->ulValueLen && memcmp(der_ec_supported[i].data, ec_parms->pValue, ec_parms->ulValueLen) == 0) { curve_type = der_ec_supported[i].curve_type; break; } } if (curve_type == -1) { TRACE_ERROR("Could not find a curve type\n"); return CKR_CURVE_NOT_SUPPORTED; } /* CKA_EC_POINT is optional in EC private keys */ rc = template_attribute_get_non_empty(tmpl, CKA_EC_POINT, &ec_point); if (rc != CKR_OK) { TRACE_DEVEL("Could not find CKA_EC_POINT, possibly EC private key.\n"); /* * For a secure key token, we can't calculate the public key from the * private key */ if (token_specific.secure_key_token) { TRACE_DEVEL("Its a secure key token, no SPKI avaiable.\n"); *data = NULL; *data_len = 0; return CKR_OK; } rc = template_attribute_get_non_empty(tmpl, CKA_VALUE, &value); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); return rc; } rc = ec_point_from_priv_key(ec_parms->pValue, ec_parms->ulValueLen, value->pValue, value->ulValueLen, &buf, &buf_len); if (rc != CKR_OK) { TRACE_ERROR("ec_point_from_priv_key failed.\n"); return rc; } if (curve_type != EDWARDS_CURVE && curve_type != MONTGOMERY_CURVE) { rc = ber_encode_OCTET_STRING(FALSE, (CK_BYTE **)&point.pValue, &point.ulValueLen, buf, buf_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_OCTET_STRING failed\n"); goto out; } } else { /* Edwards/Montgomery keys have raw CKA_EC_POINT */ point.pValue = buf; point.ulValueLen = buf_len; buf = NULL; } ec_point = &point; } rc = ber_encode_ECPublicKey(length_only, data,data_len, ec_parms, ec_point, key_type); if (rc != CKR_OK) { TRACE_ERROR("ber_encode_ECPublicKey failed.\n"); goto out; } out: if (buf != NULL) free(buf); if (point.pValue != NULL) free(point.pValue); return rc; } // ec_priv_check_required_attributes() // CK_RV ec_priv_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) { CK_ATTRIBUTE *attr = NULL; CK_RV rc; if (mode == MODE_CREATE && token_specific.secure_key_token == TRUE && template_attribute_get_non_empty(tmpl, CKA_IBM_OPAQUE, &attr) == CKR_OK) { /* * Import of an already existing secure key. Only * do the base checks for private key templates. */ return priv_key_check_required_attributes(tmpl, mode); } rc = template_attribute_get_non_empty(tmpl, CKA_EC_PARAMS, &attr); if (rc != CKR_OK) { if (mode == MODE_CREATE) { TRACE_ERROR("Could not find CKA_EC_PARAMS\n"); return rc; } } rc = template_attribute_get_non_empty(tmpl, CKA_VALUE, &attr); if (rc != CKR_OK) { if (mode == MODE_CREATE) { TRACE_ERROR("Could not find CKA_VALUE\n"); return rc; } } return priv_key_check_required_attributes(tmpl, mode); } // ec_priv_set_default_attributes() // CK_RV ec_priv_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode, CK_KEY_TYPE key_type) { CK_ATTRIBUTE *params_attr = NULL; CK_ATTRIBUTE *value_attr = NULL; CK_ATTRIBUTE *type_attr = NULL; CK_RV rc; 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_EC_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 = key_type; rc = template_update_attribute(tmpl, type_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } type_attr = NULL; rc = template_update_attribute(tmpl, params_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } params_attr = NULL; rc = template_update_attribute(tmpl, value_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } value_attr = NULL; return CKR_OK; error: if (type_attr) free(type_attr); if (params_attr) free(params_attr); if (value_attr) free(value_attr); return rc; } // ec_priv_validate_attribute() // CK_RV ec_priv_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_ATTRIBUTE *attr, CK_ULONG mode, CK_KEY_TYPE key_type) { switch (attr->type) { case CKA_EC_PARAMS: if (mode == MODE_CREATE || mode == MODE_DERIVE) 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) { if (key_type == CKK_EC) 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) { 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); } } // ec_priv_check_exportability() // CK_BBOOL ec_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 ec_priv_wrap_get_data(TEMPLATE *tmpl, CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, CK_KEY_TYPE key_type) { CK_ATTRIBUTE *params = NULL; CK_ATTRIBUTE *privkey = NULL; CK_ATTRIBUTE *pubkey = NULL; CK_RV rc; // compute the total length of the BER-encoded data // rc = template_attribute_get_non_empty(tmpl, CKA_EC_PARAMS, ¶ms); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_EC_PARAMS for the key.\n"); return rc; } rc = template_attribute_get_non_empty(tmpl, CKA_VALUE, &privkey); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); return rc; } /* check if optional public-key part was defined */ template_attribute_get_non_empty(tmpl, CKA_EC_POINT, &pubkey); rc = der_encode_ECPrivateKey(length_only, data, data_len, params, privkey, pubkey, key_type); if (rc != CKR_OK) { TRACE_DEVEL("der_encode_ECPrivateKey failed\n"); } return rc; } CK_RV ec_priv_unwrap_get_data(TEMPLATE *tmpl, CK_BYTE *data, CK_ULONG total_length, CK_BBOOL is_public, CK_KEY_TYPE key_type) { CK_ATTRIBUTE *params = NULL; CK_ATTRIBUTE *point = NULL; CK_RV rc; rc = der_decode_ECPublicKey(data, total_length, ¶ms, &point, key_type); if (rc != CKR_OK) { TRACE_DEVEL("der_decode_ECPublicKey failed\n"); return rc; } rc = template_update_attribute(tmpl, params); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } params = NULL; if (is_public) { rc = template_update_attribute(tmpl, point); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } } else { free(point); } point = NULL; return CKR_OK; error: if (params) free(params); if (point) free(point); return rc; } // // CK_RV ec_priv_unwrap(TEMPLATE *tmpl, CK_BYTE *data, CK_ULONG total_length, CK_KEY_TYPE key_type) { CK_ATTRIBUTE *pubkey = NULL; CK_ATTRIBUTE *privkey = NULL; CK_ATTRIBUTE *ecparam = NULL; CK_RV rc; rc = der_decode_ECPrivateKey(data, total_length, &ecparam, &pubkey, &privkey, key_type); if (rc != CKR_OK) { TRACE_DEVEL("der_decode_ECPrivateKey failed\n"); return rc; } if (key_type == CKK_EC) p11_attribute_trim(privkey); if (pubkey) { rc = template_update_attribute(tmpl, pubkey); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } pubkey = NULL; } if (privkey) { rc = template_update_attribute(tmpl, privkey); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } privkey = NULL; } rc = template_update_attribute(tmpl, ecparam); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } ecparam = NULL; return CKR_OK; error: if (pubkey) free(pubkey); if (privkey) free(privkey); if (ecparam) free(ecparam); return rc; } // dh_publ_check_required_attributes() // CK_RV dh_publ_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) { CK_ATTRIBUTE *attr = NULL; CK_RV rc; if (mode == MODE_CREATE && token_specific.secure_key_token == TRUE && template_attribute_get_non_empty(tmpl, CKA_IBM_OPAQUE, &attr) == CKR_OK) { /* * Import of an already existing secure key. Only * do the base checks for public key templates. */ return publ_key_check_required_attributes(tmpl, mode); } rc = template_attribute_get_non_empty(tmpl, CKA_PRIME, &attr); if (rc != CKR_OK) { if (mode == MODE_CREATE || mode == MODE_KEYGEN || mode == MODE_ENCAPS || mode == MODE_EXTRACT) { TRACE_ERROR("Could not find CKA_PRIME\n"); return rc; } } rc = template_attribute_get_non_empty(tmpl, CKA_BASE, &attr); if (rc != CKR_OK) { if (mode == MODE_CREATE || mode == MODE_KEYGEN || mode == MODE_ENCAPS || mode == MODE_EXTRACT) { TRACE_ERROR("Could not find CKA_BASE\n"); return rc; } } rc = template_attribute_get_non_empty(tmpl, CKA_VALUE, &attr); if (rc != CKR_OK) { if (mode == MODE_CREATE || mode == MODE_EXTRACT) { TRACE_ERROR("Could not find CKA_VALUE\n"); return rc; } } 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; CK_RV rc; 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) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto error; } 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; rc = template_update_attribute(tmpl, type_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } type_attr = NULL; rc = template_update_attribute(tmpl, prime_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } prime_attr = NULL; rc = template_update_attribute(tmpl, base_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } base_attr = NULL; rc = template_update_attribute(tmpl, value_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } value_attr = NULL; return CKR_OK; error: if (type_attr) free(type_attr); if (prime_attr) free(prime_attr); if (base_attr) free(base_attr); if (value_attr) free(value_attr); return rc; } // 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 || mode == MODE_ENCAPS || mode == MODE_EXTRACT) { 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 || mode == MODE_EXTRACT) { 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); } } /* * Extract the SubjectPublicKeyInfo from the DH public key */ CK_RV dh_publ_get_spki(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; rc = template_attribute_get_non_empty(tmpl, CKA_PRIME, &prime); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_PRIME for the key.\n"); return rc; } rc = template_attribute_get_non_empty(tmpl, CKA_BASE, &base); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_BASE for the key.\n"); return rc; } rc = template_attribute_get_non_empty(tmpl, CKA_VALUE, &value); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); return rc; } rc = ber_encode_DHPublicKey(length_only, data,data_len, prime, base, value); if (rc != CKR_OK) { TRACE_ERROR("ber_encode_DHPublicKey failed.\n"); return rc; } return CKR_OK; } // dh_priv_check_required_attributes() // CK_RV dh_priv_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) { CK_ATTRIBUTE *attr = NULL; CK_ULONG val; CK_RV rc; if (mode == MODE_CREATE && token_specific.secure_key_token == TRUE && template_attribute_get_non_empty(tmpl, CKA_IBM_OPAQUE, &attr) == CKR_OK) { /* * Import of an already existing secure key. Only * do the base checks for private key templates. */ return priv_key_check_required_attributes(tmpl, mode); } rc = template_attribute_get_non_empty(tmpl, CKA_PRIME, &attr); if (rc != CKR_OK) { if (mode == MODE_CREATE) { TRACE_ERROR("Could not find CKA_PRIME\n"); return rc; } } rc = template_attribute_get_non_empty(tmpl, CKA_BASE, &attr); if (rc != CKR_OK) { if (mode == MODE_CREATE) { TRACE_ERROR("Could not find CKA_BASE\n"); return rc; } } rc = template_attribute_get_non_empty(tmpl, CKA_VALUE, &attr); if (rc != CKR_OK) { if (mode == MODE_CREATE) { TRACE_ERROR("Could not find CKA_VALUE\n"); return rc; } } rc = template_attribute_get_ulong(tmpl, CKA_VALUE_BITS, &val); if (rc != CKR_TEMPLATE_INCOMPLETE) { if (mode == MODE_CREATE || mode == MODE_UNWRAP || mode == MODE_ENCAPS || mode == MODE_DECAPS) { 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; CK_RV rc; 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)); if (mode != MODE_CREATE && mode != MODE_UNWRAP && mode != MODE_ENCAPS && mode != MODE_DECAPS) value_bits_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_ULONG)); if (!type_attr || !prime_attr || !base_attr || !value_attr) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto error; } if (mode != MODE_CREATE && mode != MODE_UNWRAP && mode != MODE_ENCAPS && mode != MODE_DECAPS && !value_bits_attr) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto error; } 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; if (mode != MODE_CREATE && mode != MODE_UNWRAP && mode != MODE_ENCAPS && mode != MODE_DECAPS) { 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; rc = template_update_attribute(tmpl, type_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } type_attr = NULL; rc = template_update_attribute(tmpl, prime_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } prime_attr = NULL; rc = template_update_attribute(tmpl, base_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } base_attr = NULL; rc = template_update_attribute(tmpl, value_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } value_attr = NULL; if (mode != MODE_CREATE && mode != MODE_UNWRAP && mode != MODE_ENCAPS && mode != MODE_DECAPS) { rc = template_update_attribute(tmpl, value_bits_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } value_bits_attr = NULL; } return CKR_OK; error: 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); return rc; } // 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 || mode == MODE_ENCAPS) { 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; if (attr->ulValueLen != sizeof(CK_ULONG) || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } 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); rc = template_update_attribute(tmpl, prime); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } prime = NULL; rc = template_update_attribute(tmpl, base); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } base = NULL; rc = template_update_attribute(tmpl, value); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } value = NULL; return CKR_OK; error: if (prime) free(prime); if (base) free(base); if (value) free(value); return rc; } CK_RV dh_priv_unwrap_get_data(TEMPLATE *tmpl, CK_BYTE *data, CK_ULONG total_length, CK_BBOOL is_public) { CK_ATTRIBUTE *prime = NULL; CK_ATTRIBUTE *base = NULL; CK_ATTRIBUTE *value = NULL; CK_ATTRIBUTE *value_bits = NULL; CK_ULONG num_bits; 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); num_bits = value->ulValueLen * 8; rc = template_update_attribute(tmpl, prime); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } prime = NULL; rc = template_update_attribute(tmpl, base); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } base = NULL; if (is_public) { rc = template_update_attribute(tmpl, value); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } } else { free(value); } value = NULL; if (!is_public) { rc = build_attribute(CKA_VALUE_BITS, (CK_BYTE *)&num_bits, sizeof(num_bits), &value_bits); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto error; } rc = template_update_attribute(tmpl, value_bits); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } value_bits = NULL; } return CKR_OK; error: if (prime) free(prime); if (base) free(base); if (value) free(value); if (value_bits) free(value_bits); return rc; } // 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 rc = template_attribute_get_non_empty(tmpl, CKA_PRIME, &prime); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_PRIME for the key.\n"); return rc; } rc = template_attribute_get_non_empty(tmpl, CKA_BASE, &base); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_BASE for the key.\n"); return rc; } rc = template_attribute_get_non_empty(tmpl, CKA_VALUE, &value); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); return rc; } 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; } // ibm_ml_dsa_publ_set_default_attributes() - for Dilithium and ML-DSA // CK_RV ibm_ml_dsa_publ_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode, CK_KEY_TYPE key_type) { CK_ATTRIBUTE *type_attr = NULL; CK_ATTRIBUTE *rho_attr = NULL; CK_ATTRIBUTE *t1_attr = NULL; CK_ATTRIBUTE *value_attr = NULL; CK_RV rc; publ_key_set_default_attributes(tmpl, mode); type_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE)); rho_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); t1_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); if (!type_attr || !rho_attr || !t1_attr || !value_attr) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto error; } 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 = key_type; rho_attr->type = CKA_IBM_ML_DSA_RHO; rho_attr->ulValueLen = 0; rho_attr->pValue = NULL; t1_attr->type = CKA_IBM_ML_DSA_T1; t1_attr->ulValueLen = 0; t1_attr->pValue = NULL; value_attr->type = CKA_VALUE; value_attr->ulValueLen = 0; value_attr->pValue = NULL; rc = template_update_attribute(tmpl, type_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } type_attr = NULL; rc = template_update_attribute(tmpl, rho_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } rho_attr = NULL; rc = template_update_attribute(tmpl, t1_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } t1_attr = NULL; rc = template_update_attribute(tmpl, value_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } value_attr = NULL; return CKR_OK; error: if (type_attr) free(type_attr); if (rho_attr) free(rho_attr); if (t1_attr) free(t1_attr); if (value_attr) free(value_attr); return rc; } // ibm_ml_dsa_priv_set_default_attributes() - for Dilithium and ML-DSA // CK_RV ibm_ml_dsa_priv_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode, CK_KEY_TYPE key_type) { 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 *priv_seed_attr = NULL; CK_ATTRIBUTE *value_attr = NULL; CK_RV rc; priv_key_set_default_attributes(tmpl, mode); type_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE)); 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)); value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); if (key_type == CKK_IBM_ML_DSA) priv_seed_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); if (!type_attr || !rho_attr || !seed_attr || !tr_attr || !s1_attr || !s2_attr || !t0_attr || !t1_attr || !value_attr || (key_type == CKK_IBM_ML_DSA && !priv_seed_attr)) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto error; } 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 = key_type; rho_attr->type = CKA_IBM_ML_DSA_RHO; rho_attr->ulValueLen = 0; rho_attr->pValue = NULL; seed_attr->type = CKA_IBM_ML_DSA_SEED; seed_attr->ulValueLen = 0; seed_attr->pValue = NULL; tr_attr->type = CKA_IBM_ML_DSA_TR; tr_attr->ulValueLen = 0; tr_attr->pValue = NULL; s1_attr->type = CKA_IBM_ML_DSA_S1; s1_attr->ulValueLen = 0; s1_attr->pValue = NULL; s2_attr->type = CKA_IBM_ML_DSA_S2; s2_attr->ulValueLen = 0; s2_attr->pValue = NULL; t0_attr->type = CKA_IBM_ML_DSA_T0; t0_attr->ulValueLen = 0; t0_attr->pValue = NULL; t1_attr->type = CKA_IBM_ML_DSA_T1; t1_attr->ulValueLen = 0; t1_attr->pValue = NULL; if (key_type == CKK_IBM_ML_DSA) { priv_seed_attr->type = CKA_IBM_ML_DSA_PRIVATE_SEED; priv_seed_attr->ulValueLen = 0; priv_seed_attr->pValue = NULL; } value_attr->type = CKA_VALUE; value_attr->ulValueLen = 0; value_attr->pValue = NULL; rc = template_update_attribute(tmpl, type_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } type_attr = NULL; rc = template_update_attribute(tmpl, rho_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } rho_attr = NULL; rc = template_update_attribute(tmpl, seed_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } seed_attr = NULL; rc = template_update_attribute(tmpl, tr_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } tr_attr = NULL; rc = template_update_attribute(tmpl, s1_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } s1_attr = NULL; rc = template_update_attribute(tmpl, s2_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } s2_attr = NULL; rc = template_update_attribute(tmpl, t0_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } t0_attr = NULL; rc = template_update_attribute(tmpl, t1_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } t1_attr = NULL; if (key_type == CKK_IBM_ML_DSA) { rc = template_update_attribute(tmpl, priv_seed_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } priv_seed_attr = NULL; } rc = template_update_attribute(tmpl, value_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } value_attr = NULL; return CKR_OK; error: 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 (priv_seed_attr) free(priv_seed_attr); if (value_attr) free(value_attr); return rc; } // ibm_ml_kem_publ_set_default_attributes() - for Kyber and ML-KEM // CK_RV ibm_ml_kem_publ_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode, CK_KEY_TYPE key_type) { CK_ATTRIBUTE *type_attr = NULL; CK_ATTRIBUTE *pk_attr = NULL; CK_ATTRIBUTE *value_attr = NULL; CK_RV rc; publ_key_set_default_attributes(tmpl, mode); type_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE)); pk_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); if (!type_attr || !pk_attr ||!value_attr) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto error; } 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 = key_type; pk_attr->type = CKA_IBM_ML_KEM_PK; pk_attr->ulValueLen = 0; pk_attr->pValue = NULL; value_attr->type = CKA_VALUE; value_attr->ulValueLen = 0; value_attr->pValue = NULL; rc = template_update_attribute(tmpl, type_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } type_attr = NULL; rc = template_update_attribute(tmpl, pk_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } pk_attr = NULL; rc = template_update_attribute(tmpl, value_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } value_attr = NULL; return CKR_OK; error: if (type_attr) free(type_attr); if (pk_attr) free(pk_attr); if (value_attr) free(value_attr); return rc; } // ibm_ml_kem_priv_set_default_attributes() - for Kyber and ML-KEM // CK_RV ibm_ml_kem_priv_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode, CK_KEY_TYPE key_type) { CK_ATTRIBUTE *type_attr = NULL; CK_ATTRIBUTE *sk_attr = NULL; CK_ATTRIBUTE *pk_attr = NULL; CK_ATTRIBUTE *priv_seed_attr = NULL; CK_ATTRIBUTE *value_attr = NULL; CK_RV rc; priv_key_set_default_attributes(tmpl, mode); type_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE)); sk_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); pk_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); if (key_type == CKK_IBM_ML_KEM) priv_seed_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); if (!type_attr || !sk_attr || !pk_attr || !value_attr || (key_type == CKK_IBM_ML_KEM && !priv_seed_attr)) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto error; } 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 = key_type; sk_attr->type = CKA_IBM_ML_KEM_SK; sk_attr->ulValueLen = 0; sk_attr->pValue = NULL; pk_attr->type = CKA_IBM_ML_KEM_PK; pk_attr->ulValueLen = 0; pk_attr->pValue = NULL; if (key_type == CKK_IBM_ML_KEM) { priv_seed_attr->type = CKA_IBM_ML_KEM_PRIVATE_SEED; priv_seed_attr->ulValueLen = 0; priv_seed_attr->pValue = NULL; } value_attr->type = CKA_VALUE; value_attr->ulValueLen = 0; value_attr->pValue = NULL; rc = template_update_attribute(tmpl, type_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } type_attr = NULL; rc = template_update_attribute(tmpl, sk_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } sk_attr = NULL; rc = template_update_attribute(tmpl, pk_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } pk_attr = NULL; if (key_type == CKK_IBM_ML_KEM) { rc = template_update_attribute(tmpl, priv_seed_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } priv_seed_attr = NULL; } rc = template_update_attribute(tmpl, value_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } value_attr = NULL; return CKR_OK; error: if (type_attr) free(type_attr); if (sk_attr) free(sk_attr); if (pk_attr) free(pk_attr); if (priv_seed_attr) free(priv_seed_attr); if (value_attr) free(value_attr); return rc; } CK_RV ml_dsa_publ_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) { CK_ATTRIBUTE *type_attr = NULL; CK_ATTRIBUTE *value_attr = NULL; CK_RV rc; publ_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) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto error; } 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_ML_DSA; value_attr->type = CKA_VALUE; value_attr->ulValueLen = 0; value_attr->pValue = NULL; rc = template_update_attribute(tmpl, type_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } type_attr = NULL; rc = template_update_attribute(tmpl, value_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } value_attr = NULL; return CKR_OK; error: if (type_attr) free(type_attr); if (value_attr) free(value_attr); return rc; } CK_RV ml_dsa_priv_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) { CK_ATTRIBUTE *type_attr = NULL; CK_ATTRIBUTE *seed_attr = NULL; CK_ATTRIBUTE *value_attr = NULL; CK_RV rc; priv_key_set_default_attributes(tmpl, mode); type_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE)); seed_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); if (!type_attr || !seed_attr || !value_attr) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto error; } 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_ML_DSA; seed_attr->type = CKA_SEED; seed_attr->ulValueLen = 0; seed_attr->pValue = NULL; value_attr->type = CKA_VALUE; value_attr->ulValueLen = 0; value_attr->pValue = NULL; rc = template_update_attribute(tmpl, type_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } type_attr = NULL; rc = template_update_attribute(tmpl, seed_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } seed_attr = NULL; rc = template_update_attribute(tmpl, value_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } value_attr = NULL; return CKR_OK; error: if (type_attr) free(type_attr); if (seed_attr) free(seed_attr); if (value_attr) free(value_attr); return rc; } CK_RV ml_kem_publ_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) { CK_ATTRIBUTE *type_attr = NULL; CK_ATTRIBUTE *value_attr = NULL; CK_RV rc; publ_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) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto error; } 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_ML_KEM; value_attr->type = CKA_VALUE; value_attr->ulValueLen = 0; value_attr->pValue = NULL; rc = template_update_attribute(tmpl, type_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } type_attr = NULL; rc = template_update_attribute(tmpl, value_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } value_attr = NULL; return CKR_OK; error: if (type_attr) free(type_attr); if (value_attr) free(value_attr); return rc; } CK_RV ml_kem_priv_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) { CK_ATTRIBUTE *type_attr = NULL; CK_ATTRIBUTE *seed_attr = NULL; CK_ATTRIBUTE *value_attr = NULL; CK_RV rc; priv_key_set_default_attributes(tmpl, mode); type_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE)); seed_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); if (!type_attr || !seed_attr || !value_attr) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto error; } 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_ML_KEM; seed_attr->type = CKA_SEED; seed_attr->ulValueLen = 0; seed_attr->pValue = NULL; value_attr->type = CKA_VALUE; value_attr->ulValueLen = 0; value_attr->pValue = NULL; rc = template_update_attribute(tmpl, type_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } type_attr = NULL; rc = template_update_attribute(tmpl, seed_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } seed_attr = NULL; rc = template_update_attribute(tmpl, value_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } value_attr = NULL; return CKR_OK; error: if (type_attr) free(type_attr); if (seed_attr) free(seed_attr); if (value_attr) free(value_attr); return rc; } static CK_RV pqc_check_attributes(TEMPLATE *tmpl, CK_ULONG mode, CK_MECHANISM_TYPE mech, const CK_MECHANISM_TYPE *req_attrs, CK_ULONG num_req_attrs, CK_MECHANISM_TYPE priv_seed_attr) { CK_ATTRIBUTE_TYPE keyform_attr; CK_ATTRIBUTE_TYPE mode_attr; CK_ATTRIBUTE *attr = NULL; CK_BBOOL keyform_present = FALSE; CK_BBOOL mode_present = FALSE; const struct pqc_oid *oids, *oid; CK_ULONG i; CK_RV rc; if (pqc_keyform_mode_attrs_by_mech(mech, &keyform_attr, &mode_attr, &oids) != CKR_OK) return CKR_MECHANISM_INVALID; if (template_attribute_find(tmpl, keyform_attr, &attr) && attr->ulValueLen == sizeof(CK_ULONG) && attr->pValue != NULL) { oid = find_pqc_by_keyform(oids, *(CK_ULONG *)(attr->pValue)); if (oid == NULL) { TRACE_ERROR("%s, attribute KEYFORM has an unsupported value.\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } keyform_present = TRUE; } if (mode_attr != (CK_ATTRIBUTE_TYPE)-1 && template_attribute_find(tmpl, mode_attr, &attr) && attr->ulValueLen > 0 && attr->pValue != NULL) { oid = find_pqc_by_oid(oids, attr->pValue, attr->ulValueLen); if (oid == NULL) { TRACE_ERROR("%s, attribute MODE has an unsupported value.\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } mode_present = TRUE; } switch (mode) { case MODE_CREATE: case MODE_EXTRACT: /* Import of an already existing secure key via CKA_IBM_OPAQUE */ if (token_specific.secure_key_token == TRUE && template_attribute_get_non_empty(tmpl, CKA_IBM_OPAQUE, &attr) == CKR_OK) break; /* Either CKA_VALUE or priv. seed or all other attrs must be present */ if (template_attribute_get_non_empty(tmpl, CKA_VALUE, &attr) == CKR_OK) break; if (priv_seed_attr != (CK_ATTRIBUTE_TYPE)-1 && template_attribute_get_non_empty(tmpl, priv_seed_attr, &attr) == CKR_OK) break; for (i = 0; i < num_req_attrs; i++) { rc = template_attribute_get_non_empty(tmpl, req_attrs[i], &attr); if (rc != CKR_OK) { if (rc != CKR_ATTRIBUTE_VALUE_INVALID) TRACE_ERROR("%s, attribute %08lX missing.\n", ock_err(ERR_TEMPLATE_INCOMPLETE), req_attrs[i]); return rc; } } if (num_req_attrs == 0) { TRACE_ERROR("%s, Either CKA_VALUE or private seed attr %08lX must " "be specified.\n", ock_err(ERR_TEMPLATE_INCOMPLETE), priv_seed_attr); return CKR_TEMPLATE_INCONSISTENT; } /* fallthrough */ case MODE_KEYGEN: case MODE_ENCAPS: /* Either keyform or mode or none of it must be present */ if (keyform_present && mode_present) { TRACE_ERROR("%s, only one of KEYFORM or MODE can be specified .\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); return CKR_TEMPLATE_INCONSISTENT; } break; case MODE_UNWRAP: case MODE_DECAPS: /* neither keyform or mode must be present */ if (keyform_present || mode_present) { TRACE_ERROR("%s, none of KEYFORM or MODE can be specified .\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); return CKR_TEMPLATE_INCONSISTENT; } break; case MODE_COPY: /* All attributes must be present */ if (!keyform_present || (mode_attr != (CK_ATTRIBUTE_TYPE)-1 && !mode_present)) { TRACE_ERROR("%s, KEYFORM or MODE must be specified .\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); return CKR_TEMPLATE_INCOMPLETE; } for (i = 0; i < num_req_attrs; 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; } } if (priv_seed_attr != (CK_ATTRIBUTE_TYPE)-1 && !template_attribute_find(tmpl, priv_seed_attr, &attr)) { TRACE_ERROR("%s, attribute %08lX missing.\n", ock_err(ERR_TEMPLATE_INCOMPLETE), priv_seed_attr); return CKR_TEMPLATE_INCOMPLETE; } break; } return CKR_OK; } // ibm_ml_dsa_publ_check_required_attributes() - for Dilithium and ML-DSA // CK_RV ibm_ml_dsa_publ_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode, CK_MECHANISM_TYPE mech) { static const CK_MECHANISM_TYPE req_attrs[] = { CKA_IBM_ML_DSA_RHO, CKA_IBM_ML_DSA_T1, }; CK_RV rc; rc = pqc_check_attributes(tmpl, mode, mech, req_attrs, sizeof(req_attrs) / sizeof(req_attrs[0]), (CK_MECHANISM_TYPE)-1); if (rc != CKR_OK) return rc; /* All required attrs found, check them */ return publ_key_check_required_attributes(tmpl, mode); } // ibm_ml_dsa_priv_check_required_attributes() - for Dilithium and ML-DSA // CK_RV ibm_ml_dsa_priv_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode, CK_MECHANISM_TYPE mech) { static const CK_MECHANISM_TYPE req_attrs[] = { CKA_IBM_ML_DSA_RHO, CKA_IBM_ML_DSA_SEED, CKA_IBM_ML_DSA_TR, CKA_IBM_ML_DSA_S1, CKA_IBM_ML_DSA_S2, CKA_IBM_ML_DSA_T0, CKA_IBM_ML_DSA_T1, }; CK_MECHANISM_TYPE priv_seed_attr; CK_RV rc; if (pqc_private_seed_attr_by_mech(mech, &priv_seed_attr) != CKR_OK) return CKR_MECHANISM_INVALID; rc = pqc_check_attributes(tmpl, mode, mech, req_attrs, sizeof(req_attrs) / sizeof(req_attrs[0]), priv_seed_attr); if (rc != CKR_OK) return rc; /* All required attrs found, check them */ return priv_key_check_required_attributes(tmpl, mode); } // ibm_ml_kem_publ_check_required_attributes() - for Kyber and ML-KEM // CK_RV ibm_ml_kem_publ_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode, CK_MECHANISM_TYPE mech) { static const CK_MECHANISM_TYPE req_attrs[] = { CKA_IBM_ML_KEM_PK, }; CK_RV rc; rc = pqc_check_attributes(tmpl, mode, mech, req_attrs, sizeof(req_attrs) / sizeof(req_attrs[0]), (CK_MECHANISM_TYPE)-1); if (rc != CKR_OK) return rc; /* All required attrs found, check them */ return publ_key_check_required_attributes(tmpl, mode); } // ibm_ml_kem_priv_check_required_attributes() - for Kyber and ML-KEM // CK_RV ibm_ml_kem_priv_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode, CK_MECHANISM_TYPE mech) { static const CK_MECHANISM_TYPE req_attrs[] = { CKA_IBM_ML_KEM_SK, CKA_IBM_ML_KEM_PK, }; CK_MECHANISM_TYPE priv_seed_attr; CK_RV rc; if (pqc_private_seed_attr_by_mech(mech, &priv_seed_attr) != CKR_OK) return CKR_MECHANISM_INVALID; rc = pqc_check_attributes(tmpl, mode, mech, req_attrs, sizeof(req_attrs) / sizeof(req_attrs[0]), priv_seed_attr); if (rc != CKR_OK) return rc; /* All required attrs found, check them */ return priv_key_check_required_attributes(tmpl, mode); } CK_RV ml_dsa_publ_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) { CK_RV rc; rc = pqc_check_attributes(tmpl, mode, CKM_ML_DSA, NULL, 0, (CK_MECHANISM_TYPE)-1); if (rc != CKR_OK) return rc; /* All required attrs found, check them */ return publ_key_check_required_attributes(tmpl, mode); } CK_RV ml_dsa_priv_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) { CK_RV rc; rc = pqc_check_attributes(tmpl, mode, CKM_ML_DSA, NULL, 0, CKA_SEED); if (rc != CKR_OK) return rc; /* All required attrs found, check them */ return priv_key_check_required_attributes(tmpl, mode); } CK_RV ml_kem_publ_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) { CK_RV rc; rc = pqc_check_attributes(tmpl, mode, CKM_ML_KEM, NULL, 0, (CK_MECHANISM_TYPE)-1); if (rc != CKR_OK) return rc; /* All required attrs found, check them */ return publ_key_check_required_attributes(tmpl, mode); } CK_RV ml_kem_priv_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) { CK_RV rc; rc = pqc_check_attributes(tmpl, mode, CKM_ML_KEM, NULL, 0, CKA_SEED); if (rc != CKR_OK) return rc; /* All required attrs found, check them */ return priv_key_check_required_attributes(tmpl, mode); } static CK_RV pqc_validate_keyform_mode(CK_ATTRIBUTE *attr, CK_ULONG mode, CK_MECHANISM_TYPE mech) { CK_ATTRIBUTE_TYPE keyform_attr; CK_ATTRIBUTE_TYPE mode_attr; const struct pqc_oid *oids, *oid; if (pqc_keyform_mode_attrs_by_mech(mech, &keyform_attr, &mode_attr, &oids) != CKR_OK) return CKR_MECHANISM_INVALID; if (attr->type == keyform_attr) { if (mode == MODE_CREATE || mode == MODE_KEYGEN || mode == MODE_ENCAPS || mode == MODE_EXTRACT) { if (attr->ulValueLen != sizeof(CK_ULONG) || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } oid = find_pqc_by_keyform(oids, *((CK_ULONG *)attr->pValue)); if (oid == NULL) { 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; } if (attr->type == mode_attr) { if (mode == MODE_CREATE || mode == MODE_KEYGEN || mode == MODE_ENCAPS || mode == MODE_EXTRACT) { if (attr->ulValueLen == 0 || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } oid = find_pqc_by_oid(oids, attr->pValue, attr->ulValueLen); if (oid == NULL) { 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; } return CKR_ATTRIBUTE_TYPE_INVALID; } // ibm_ml_dsa_publ_validate_attribute() - for Dilithium and ML-DSA // CK_RV ibm_ml_dsa_publ_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_ATTRIBUTE *attr, CK_ULONG mode, CK_MECHANISM_TYPE mech) { CK_RV rc; switch (attr->type) { case CKA_IBM_DILITHIUM_KEYFORM: case CKA_IBM_DILITHIUM_MODE: case CKA_IBM_PARAMETER_SET: rc = pqc_validate_keyform_mode(attr, mode, mech); if (rc != CKR_OK) return rc; return CKR_OK; case CKA_IBM_ML_DSA_RHO: case CKA_IBM_ML_DSA_T1: case CKA_VALUE: if (mode == MODE_CREATE || mode == MODE_EXTRACT) 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); } } // ibm_ml_dsa_priv_validate_attribute() - for Dilithium and ML-DSA // CK_RV ibm_ml_dsa_priv_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_ATTRIBUTE *attr, CK_ULONG mode, CK_MECHANISM_TYPE mech) { CK_RV rc; switch (attr->type) { case CKA_IBM_DILITHIUM_KEYFORM: case CKA_IBM_DILITHIUM_MODE: case CKA_IBM_PARAMETER_SET: rc = pqc_validate_keyform_mode(attr, mode, mech); if (rc != CKR_OK) return rc; return CKR_OK; case CKA_IBM_ML_DSA_PRIVATE_SEED: if (mech != CKM_IBM_ML_DSA) return CKR_ATTRIBUTE_TYPE_INVALID; /* Fall through */ case CKA_IBM_ML_DSA_RHO: case CKA_IBM_ML_DSA_SEED: case CKA_IBM_ML_DSA_TR: case CKA_IBM_ML_DSA_S1: case CKA_IBM_ML_DSA_S2: case CKA_IBM_ML_DSA_T0: case CKA_IBM_ML_DSA_T1: 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; default: return priv_key_validate_attribute(tokdata, tmpl, attr, mode); } } CK_BBOOL ibm_ml_dsa_priv_check_exportability(CK_ATTRIBUTE_TYPE type) { switch (type) { case CKA_VALUE: case CKA_IBM_ML_DSA_SEED: case CKA_IBM_ML_DSA_TR: case CKA_IBM_ML_DSA_S1: case CKA_IBM_ML_DSA_S2: case CKA_IBM_ML_DSA_T0: case CKA_IBM_ML_DSA_PRIVATE_SEED: return FALSE; } return TRUE; } // ibm_ml_kem_publ_validate_attribute() - for Kyber and KL-KEM // CK_RV ibm_ml_kem_publ_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_ATTRIBUTE *attr, CK_ULONG mode, CK_MECHANISM_TYPE mech) { CK_RV rc; switch (attr->type) { case CKA_IBM_KYBER_KEYFORM: case CKA_IBM_KYBER_MODE: case CKA_IBM_PARAMETER_SET: rc = pqc_validate_keyform_mode(attr, mode, mech); if (rc != CKR_OK) return rc; return CKR_OK; case CKA_IBM_KYBER_PK: case CKA_VALUE: if (mode == MODE_CREATE || mode == MODE_EXTRACT) 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); } } // ibm_ml_kem_priv_validate_attribute() - for Kyber and KL-KEM // CK_RV ibm_ml_kem_priv_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_ATTRIBUTE *attr, CK_ULONG mode, CK_MECHANISM_TYPE mech) { CK_RV rc; switch (attr->type) { case CKA_IBM_KYBER_KEYFORM: case CKA_IBM_KYBER_MODE: case CKA_IBM_PARAMETER_SET: rc = pqc_validate_keyform_mode(attr, mode, mech); if (rc != CKR_OK) return rc; return CKR_OK; case CKA_IBM_ML_KEM_PRIVATE_SEED: if (mech != CKM_IBM_ML_KEM) return CKR_ATTRIBUTE_TYPE_INVALID; /* Fall through */ case CKA_IBM_ML_KEM_SK: case CKA_IBM_ML_KEM_PK: 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; default: return priv_key_validate_attribute(tokdata, tmpl, attr, mode); } } CK_BBOOL ibm_ml_kem_priv_check_exportability(CK_ATTRIBUTE_TYPE type) { switch (type) { case CKA_VALUE: case CKA_IBM_ML_KEM_SK: case CKA_IBM_ML_KEM_PRIVATE_SEED: return FALSE; } return TRUE; } CK_RV ml_dsa_publ_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_ATTRIBUTE *attr, CK_ULONG mode) { CK_RV rc; extern const char manuf[]; extern const char model[]; switch (attr->type) { case CKA_PARAMETER_SET: rc = pqc_validate_keyform_mode(attr, mode, CKM_ML_DSA); if (rc != CKR_OK) return rc; return CKR_OK; case CKA_VALUE: if (mode == MODE_CREATE || mode == MODE_EXTRACT) return CKR_OK; TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); return CKR_ATTRIBUTE_READ_ONLY; case CKA_IBM_CCA_ML_DSA_KEY_MODE: if (strcmp(manuf, "IBM") != 0 || strcmp(model, "CCA") != 0) { TRACE_ERROR("%s (only valid for the CCA token)\n", ock_err(ERR_ATTRIBUTE_TYPE_INVALID)); return CKR_ATTRIBUTE_TYPE_INVALID; } /* * CKA_IBM_CCA_ML_DSA_KEY_MODE can not be specified for the public key, * but only for the private key when generating a ML-DSA key pair * (MODE_KEYGEN). Nevertheless, both generated keys, private and public * key, get the CKA_IBM_CCA_ML_DSA_KEY_MODE attribute with the same * value. * For other modes, only the public key is created/derived/etc, and * thus attribute CKA_IBM_CCA_ML_DSA_KEY_MODE can be specified here. */ if (mode == MODE_CREATE || mode == MODE_DERIVE || mode == MODE_UNWRAP ||mode == MODE_ENCAPS || mode == MODE_DECAPS || mode == MODE_EXTRACT) { if (attr->ulValueLen != sizeof(CK_IBM_CCA_AES_KEY_MODE_TYPE) || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } switch (*(CK_IBM_CCA_ML_DSA_KEY_MODE_TYPE *)attr->pValue) { case CK_IBM_CCA_ML_DSA_PURE_KEY: case CK_IBM_CCA_ML_DSA_PREHASH_KEY: return CKR_OK; default: TRACE_ERROR("%s\n", ock_err(ERR_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); } } CK_RV ml_dsa_priv_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_ATTRIBUTE *attr, CK_ULONG mode) { CK_RV rc; extern const char manuf[]; extern const char model[]; switch (attr->type) { case CKA_PARAMETER_SET: rc = pqc_validate_keyform_mode(attr, mode, CKM_ML_DSA); if (rc != CKR_OK) return rc; return CKR_OK; case CKA_VALUE: case CKA_SEED: 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_CCA_ML_DSA_KEY_MODE: if (strcmp(manuf, "IBM") != 0 || strcmp(model, "CCA") != 0) { TRACE_ERROR("%s (only valid for the CCA token)\n", ock_err(ERR_ATTRIBUTE_TYPE_INVALID)); return CKR_ATTRIBUTE_TYPE_INVALID; } if (mode == MODE_CREATE || mode == MODE_DERIVE || mode == MODE_KEYGEN || mode == MODE_UNWRAP || mode == MODE_ENCAPS || mode == MODE_DECAPS) { if (attr->ulValueLen != sizeof(CK_IBM_CCA_AES_KEY_MODE_TYPE) || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } switch (*(CK_IBM_CCA_ML_DSA_KEY_MODE_TYPE *)attr->pValue) { case CK_IBM_CCA_ML_DSA_PURE_KEY: case CK_IBM_CCA_ML_DSA_PREHASH_KEY: return CKR_OK; default: TRACE_ERROR("%s\n", ock_err(ERR_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); } } CK_BBOOL ml_dsa_priv_check_exportability(CK_ATTRIBUTE_TYPE type) { switch (type) { case CKA_VALUE: case CKA_SEED: return FALSE; } return TRUE; } CK_RV ml_kem_publ_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_ATTRIBUTE *attr, CK_ULONG mode) { CK_RV rc; switch (attr->type) { case CKA_PARAMETER_SET: rc = pqc_validate_keyform_mode(attr, mode, CKM_ML_KEM); if (rc != CKR_OK) return rc; return CKR_OK; case CKA_VALUE: if (mode == MODE_CREATE || mode == MODE_EXTRACT) 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); } } CK_RV ml_kem_priv_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_ATTRIBUTE *attr, CK_ULONG mode) { CK_RV rc; switch (attr->type) { case CKA_PARAMETER_SET: rc = pqc_validate_keyform_mode(attr, mode, CKM_ML_KEM); if (rc != CKR_OK) return rc; return CKR_OK; case CKA_VALUE: case CKA_SEED: if (mode == MODE_CREATE) 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); } } CK_BBOOL ml_kem_priv_check_exportability(CK_ATTRIBUTE_TYPE type) { switch (type) { case CKA_VALUE: case CKA_SEED: return FALSE; } return TRUE; } // generic_secret_check_required_attributes() // CK_RV generic_secret_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) { CK_ATTRIBUTE *attr = NULL; CK_ULONG val; CK_RV rc; if (mode == MODE_CREATE && token_specific.secure_key_token == TRUE && template_attribute_get_non_empty(tmpl, CKA_IBM_OPAQUE, &attr) == CKR_OK) { /* * Import of an already existing secure key. Only * do the base checks for des key templates. */ return secret_key_check_required_attributes(tmpl, mode); } rc = template_attribute_get_non_empty(tmpl, CKA_VALUE, &attr); if (rc != CKR_OK) { if (mode == MODE_CREATE) { TRACE_ERROR("Could not find CKA_VALUE\n"); return rc; } } rc = template_attribute_get_ulong(tmpl, CKA_VALUE_LEN, &val); if (rc != CKR_OK) { // 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_KEY_TYPE key_type) { 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; CK_RV rc; /* 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) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto error; } 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; rc = template_update_attribute(tmpl, id_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } id_attr = NULL; rc = template_update_attribute(tmpl, sdate_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } sdate_attr = NULL; rc = template_update_attribute(tmpl, edate_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } edate_attr = NULL; rc = template_update_attribute(tmpl, derive_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } derive_attr = NULL; rc = template_update_attribute(tmpl, local_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } local_attr = NULL; /* 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) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto error; } 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; rc = template_update_attribute(tmpl, class_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } class_attr = NULL; rc = template_update_attribute(tmpl, sensitive_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } sensitive_attr = NULL; rc = template_update_attribute(tmpl, encrypt_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } encrypt_attr = NULL; rc = template_update_attribute(tmpl, decrypt_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } decrypt_attr = NULL; rc = template_update_attribute(tmpl, sign_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } sign_attr = NULL; rc = template_update_attribute(tmpl, verify_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } verify_attr = NULL; rc = template_update_attribute(tmpl, wrap_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } wrap_attr = NULL; rc = template_update_attribute(tmpl, unwrap_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } unwrap_attr = NULL; rc = template_update_attribute(tmpl, extractable_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } extractable_attr = NULL; rc = template_update_attribute(tmpl, never_extr_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } never_extr_attr = NULL; rc = template_update_attribute(tmpl, always_sens_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } always_sens_attr = NULL; /* 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) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto error; } 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 = key_type; rc = template_update_attribute(tmpl, type_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } type_attr = NULL; rc = template_update_attribute(tmpl, value_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } value_attr = NULL; rc = template_update_attribute(tmpl, value_len_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } value_len_attr = NULL; return CKR_OK; error: 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 (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); if (type_attr) free(type_attr); if (value_attr) free(value_attr); if (value_len_attr) free(value_len_attr); return rc; } // 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 (attr->ulValueLen != sizeof(CK_ULONG) || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } if (mode == MODE_KEYGEN || mode == MODE_DERIVE) return CKR_OK; if (mode == MODE_UNWRAP || mode == MODE_ENCAPS || mode == MODE_DECAPS) { 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_get_non_empty(tmpl, CKA_VALUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); return rc; } *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_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_get_ulong(tmpl, CKA_VALUE_LEN, &len); if (rc == CKR_OK) { 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; 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; } } rc = template_update_attribute(tmpl, value_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } value_attr = NULL; if (data_len != len) { rc = template_update_attribute(tmpl, value_len_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } value_len_attr = NULL; } return CKR_OK; error: if (value_attr) free(value_attr); if (value_len_attr) free(value_len_attr); return rc; } // // CK_RV des_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) { CK_ATTRIBUTE *attr = NULL; CK_RV rc; if (mode == MODE_CREATE && token_specific.secure_key_token == TRUE && template_attribute_get_non_empty(tmpl, CKA_IBM_OPAQUE, &attr) == CKR_OK) { /* * Import of an already existing secure key. Only * do the base checks for des key templates. */ return secret_key_check_required_attributes(tmpl, mode); } rc = template_attribute_get_non_empty(tmpl, CKA_VALUE, &attr); if (rc != CKR_OK) { if (mode == MODE_CREATE) { TRACE_ERROR("Could not find CKA_VALUE\n"); return rc; } } 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; CK_RV rc; 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) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto error; } 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; rc = template_update_attribute(tmpl, type_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } type_attr = NULL; rc = template_update_attribute(tmpl, value_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } value_attr = NULL; return CKR_OK; error: if (value_attr) free(value_attr); if (type_attr) free(type_attr); return rc; } // // CK_RV des_unwrap(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_BYTE *data, CK_ULONG data_len, CK_BBOOL fromend) { CK_ATTRIBUTE *value_attr = NULL; CK_BYTE *ptr = NULL; CK_ULONG i; CK_RV rc; if (data_len < DES_BLOCK_SIZE) { TRACE_ERROR("%s\n", ock_err(ERR_WRAPPED_KEY_INVALID)); return CKR_WRAPPED_KEY_INVALID; } if (fromend == TRUE) ptr = data + data_len - DES_BLOCK_SIZE; else ptr = data; 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; } 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); rc = template_update_attribute(tmpl, value_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); free(value_attr); return rc; } 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; if (ptr == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } 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 (attr->ulValueLen != sizeof(CK_ULONG) || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } if (tokdata->nv_token_data->tweak_vector.netscape_mods == TRUE) { if (mode == MODE_CREATE || mode == MODE_DERIVE || mode == MODE_KEYGEN || mode == MODE_UNWRAP || mode == MODE_ENCAPS || mode == MODE_DECAPS) { 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_ATTRIBUTE_TYPE_INVALID)); return CKR_ATTRIBUTE_TYPE_INVALID; 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_get_non_empty(tmpl, CKA_VALUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); return rc; } *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_RV rc; if (mode == MODE_CREATE && token_specific.secure_key_token == TRUE && template_attribute_get_non_empty(tmpl, CKA_IBM_OPAQUE, &attr) == CKR_OK) { /* * Import of an already existing secure key. Only * do the base checks for des key templates. */ return secret_key_check_required_attributes(tmpl, mode); } rc = template_attribute_get_non_empty(tmpl, CKA_VALUE, &attr); if (rc != CKR_OK) { if (mode == MODE_CREATE) { TRACE_ERROR("Could not find CKA_VALUE\n"); return rc; } } 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; CK_RV rc; 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) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto error; } 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; rc = template_update_attribute(tmpl, type_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } type_attr = NULL; rc = template_update_attribute(tmpl, value_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } value_attr = NULL; return CKR_OK; error: if (value_attr) free(value_attr); if (type_attr) free(type_attr); return rc; } // 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; if (ptr == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } 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: if (attr->ulValueLen != sizeof(CK_ULONG) || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } // 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 || mode == MODE_ENCAPS || mode == MODE_DECAPS) { 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_ATTRIBUTE_TYPE_INVALID)); return CKR_ATTRIBUTE_TYPE_INVALID; 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_RV rc; if (mode == MODE_CREATE && token_specific.secure_key_token == TRUE && template_attribute_get_non_empty(tmpl, CKA_IBM_OPAQUE, &attr) == CKR_OK) { /* * Import of an already existing secure key. Only * do the base checks for des3 key templates. */ return secret_key_check_required_attributes(tmpl, mode); } rc = template_attribute_get_non_empty(tmpl, CKA_VALUE, &attr); if (rc != CKR_OK) { if (mode == MODE_CREATE) { TRACE_ERROR("Could not find CKA_VALUE\n"); return rc; } } 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; CK_RV rc; 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) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto error; } 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; rc = template_update_attribute(tmpl, type_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } type_attr = NULL; rc = template_update_attribute(tmpl, value_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } value_attr = NULL; return CKR_OK; error: if (value_attr) free(value_attr); if (type_attr) free(type_attr); return rc; } // // CK_RV des3_unwrap(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_BYTE *data, CK_ULONG data_len, CK_BBOOL fromend) { CK_ATTRIBUTE *value_attr = NULL; CK_BYTE *ptr = NULL; CK_ULONG i; CK_RV rc; 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) ptr = data + data_len - (3 * DES_BLOCK_SIZE); else ptr = data; 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; } 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); rc = template_update_attribute(tmpl, value_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); free(value_attr); return rc; } 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; if (ptr == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } 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: if (attr->ulValueLen != sizeof(CK_ULONG) || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } // 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 || mode == MODE_ENCAPS || mode == MODE_DECAPS) { 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_ATTRIBUTE_TYPE_INVALID)); return CKR_ATTRIBUTE_TYPE_INVALID; 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; } rc = template_attribute_get_non_empty(tmpl, CKA_VALUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); return rc; } *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; } // aes_set_default_attributes() // CK_RV aes_set_default_attributes(TEMPLATE *tmpl, TEMPLATE *basetmpl, CK_ULONG mode, CK_BBOOL xts) { CK_ATTRIBUTE *value_attr = NULL; CK_ATTRIBUTE *type_attr = NULL; CK_ATTRIBUTE *len_attr = NULL; CK_ULONG keysize; CK_RV rc; 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) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto error; } 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 = xts ? CKK_AES_XTS : CKK_AES; rc = template_update_attribute(tmpl, type_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } type_attr = NULL; rc = template_update_attribute(tmpl, value_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } value_attr = NULL; /* If CKA_VALUE specified in base tmpl, add CKA_VALUE_LEN to tmpl. */ if (template_attribute_find(basetmpl, CKA_VALUE, &value_attr) && !template_attribute_find(basetmpl, CKA_VALUE_LEN, &len_attr)) { keysize = value_attr->ulValueLen; rc = build_attribute(CKA_VALUE_LEN, (CK_BYTE *)&keysize, sizeof(CK_ULONG), &len_attr); if (rc != CKR_OK) { TRACE_ERROR("build_attribute failed\n"); goto error; } rc = template_update_attribute(tmpl, len_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } value_attr = NULL; } return CKR_OK; error: if (type_attr) free(type_attr); if (value_attr) free(value_attr); return rc; } // aes_check_required_attributes() // CK_RV aes_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) { CK_ATTRIBUTE *attr = NULL; CK_RV rc; if (mode == MODE_CREATE && token_specific.secure_key_token == TRUE && template_attribute_get_non_empty(tmpl, CKA_IBM_OPAQUE, &attr) == CKR_OK) { /* * Import of an already existing secure key. Only * do the base checks for aes key templates. */ return secret_key_check_required_attributes(tmpl, mode); } rc = template_attribute_get_non_empty(tmpl, CKA_VALUE, &attr); if (rc != CKR_OK) { if (mode == MODE_CREATE) { TRACE_ERROR("Could not find CKA_VALUE\n"); return rc; } } 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_BBOOL xts) { CK_ULONG val; extern const char manuf[]; extern const char model[]; 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 * (xts ? 2 : 1)) && (xts || attr->ulValueLen != AES_KEY_SIZE_192) && attr->ulValueLen != (AES_KEY_SIZE_256 * (xts ? 2 : 1))) { 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 (attr->ulValueLen != sizeof(CK_ULONG) || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } if (mode == MODE_CREATE || mode == MODE_DERIVE || mode == MODE_KEYGEN || mode == MODE_UNWRAP || mode == MODE_ENCAPS || mode == MODE_DECAPS) { if (attr->ulValueLen != sizeof(CK_ULONG) || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } val = *(CK_ULONG *) attr->pValue; if (val != (AES_KEY_SIZE_128 * (xts ? 2 : 1)) && (xts || val != AES_KEY_SIZE_192) && val != (AES_KEY_SIZE_256 * (xts ? 2 : 1))) { 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_IBM_CCA_AES_KEY_MODE: if (strcmp(manuf, "IBM") != 0 || strcmp(model, "CCA") != 0) { TRACE_ERROR("%s (only valid for the CCA token)\n", ock_err(ERR_ATTRIBUTE_TYPE_INVALID)); return CKR_ATTRIBUTE_TYPE_INVALID; } if (mode == MODE_CREATE || mode == MODE_DERIVE || mode == MODE_KEYGEN || mode == MODE_UNWRAP || mode == MODE_ENCAPS || mode == MODE_DECAPS || mode == MODE_COPY || mode == MODE_MODIFY) { if (attr->ulValueLen != sizeof(CK_IBM_CCA_AES_KEY_MODE_TYPE) || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } switch (*(CK_IBM_CCA_AES_KEY_MODE_TYPE *)attr->pValue) { case CK_IBM_CCA_AES_DATA_KEY: /* Modify/Copy can only set it to mode CIPHER */ if (mode == MODE_COPY || mode == MODE_MODIFY) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } return CKR_OK; case CK_IBM_CCA_AES_CIPHER_KEY: return CKR_OK; default: TRACE_ERROR("%s\n", ock_err(ERR_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 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_get_non_empty(tmpl, CKA_VALUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); return rc; } *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 xts) { CK_ATTRIBUTE *value_attr = NULL; CK_ATTRIBUTE *val_len_attr = NULL; CK_BYTE *ptr = NULL; CK_ULONG key_size; CK_BBOOL found = FALSE; CK_RV rc; 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 * If not a available, 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. */ rc = template_attribute_get_ulong(tmpl, CKA_VALUE_LEN, &key_size); if (rc == CKR_ATTRIBUTE_VALUE_INVALID) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } if (rc == CKR_OK) found = TRUE; else key_size = data_len; /* key_size should be one of AES's possible sizes */ if (key_size != (AES_KEY_SIZE_128 * (xts ? 2 : 1)) && (xts || key_size != AES_KEY_SIZE_192) && key_size != (AES_KEY_SIZE_256 * (xts ? 2 : 1))) { TRACE_ERROR("%s\n", ock_err(ERR_WRAPPED_KEY_LEN_RANGE)); return CKR_WRAPPED_KEY_LEN_RANGE; } if (fromend == TRUE) ptr = data + data_len - key_size; else ptr = data; 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; } 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); rc = template_update_attribute(tmpl, value_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); free(value_attr); return rc; } /* 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; rc = template_update_attribute(tmpl, val_len_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); free(val_len_attr); return rc; } } return CKR_OK; } opencryptoki-opencryptoki-451d99c/usr/lib/common/key_mgr.c000066400000000000000000002400471520105705100240030ustar00rootroot00000000000000/* * 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 "attributes.h" #include "tok_spec_struct.h" #include "trace.h" #include "pqc_defs.h" #include "ec_defs.h" #include "p11util.h" #include "../api/policy.h" #include "../api/statistics.h" #include static CK_BBOOL true = TRUE; CK_RV key_mgr_apply_always_sensitive_never_extractable_attrs( STDLL_TokData_t *tokdata, OBJECT *key_obj) { CK_BBOOL ck_true = TRUE; CK_ATTRIBUTE *new_attr = NULL; CK_BBOOL flag; CK_RV rc; UNUSED(tokdata); rc = template_attribute_get_bool(key_obj->template, CKA_SENSITIVE, &flag); if (rc != CKR_OK) { TRACE_ERROR("Failed to find CKA_SENSITIVE in key object template.\n"); goto error; } rc = build_attribute(CKA_ALWAYS_SENSITIVE, &flag, sizeof(CK_BBOOL), &new_attr); if (rc != CKR_OK) { TRACE_DEVEL("build attribute failed.\n"); goto error; } rc = template_update_attribute(key_obj->template, new_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } new_attr = NULL; rc = template_attribute_get_bool(key_obj->template, CKA_EXTRACTABLE, &flag); if (rc != CKR_OK) { TRACE_ERROR("Failed to find CKA_EXTRACTABLE in key object template.\n"); goto error; } rc = build_attribute(CKA_NEVER_EXTRACTABLE, &ck_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; rc = template_update_attribute(key_obj->template, new_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } new_attr = NULL; /* * Also apply CKA_IBM_PROTKEY_NEVER_EXTRACTABLE if attribute * CKA_IBM_PROTKEY_EXTRACTABLE is available in the key */ rc = template_attribute_get_bool(key_obj->template, CKA_IBM_PROTKEY_EXTRACTABLE, &flag); if (rc == CKR_TEMPLATE_INCOMPLETE) { rc = CKR_OK; goto error; } if (rc != CKR_OK) { TRACE_ERROR("CKA_IBM_PROTKEY_EXTRACTABLE in key object template is " "invalid.\n"); goto error; } rc = build_attribute(CKA_IBM_PROTKEY_NEVER_EXTRACTABLE, &ck_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; rc = template_update_attribute(key_obj->template, new_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } new_attr = NULL; error: if (new_attr != NULL) free(new_attr); return rc; } CK_RV key_mgr_derive_always_sensitive_never_extractable_attrs( STDLL_TokData_t *tokdata, OBJECT *base_key_obj, OBJECT *derived_key_obj) { CK_ATTRIBUTE *always_sens_attr = NULL, *never_extract_attr = NULL; CK_BBOOL flag; CK_RV rc; UNUSED(tokdata); /* * If base key has ALWAYS_SENSITIVE = FALSE, then new key does too * otherwise, the value of CKA_ALWAYS_SENSITIVE = CKA_SENSITIVE */ rc = template_attribute_get_bool(base_key_obj->template, CKA_ALWAYS_SENSITIVE, &flag); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_ALWAYS_SENSITIVE in the template\n"); goto end; } if (flag == TRUE) { rc = template_attribute_get_bool(derived_key_obj->template, CKA_SENSITIVE, &flag); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_SENSITIVE in the template\n"); goto end; } } 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 end; } /* * If base key has NEVER_EXTRACTABLE = FALSE, the new key does too * otherwise, the value of CKA_NEVER_EXTRACTABLE = !CKA_EXTRACTABLE */ rc = template_attribute_get_bool(base_key_obj->template, CKA_NEVER_EXTRACTABLE, &flag); if (rc != CKR_OK) { TRACE_DEVEL("Could not find CKA_NEVER_EXTRACTABLE in the template.\n"); goto end; } if (flag == TRUE) { rc = template_attribute_get_bool(derived_key_obj->template, CKA_EXTRACTABLE, &flag); if (rc != CKR_OK) { TRACE_DEVEL("Could not find CKA_EXTRACTABLE in the template.\n"); goto end; } flag = !flag; } rc = build_attribute(CKA_NEVER_EXTRACTABLE, &flag, sizeof(CK_BBOOL), &never_extract_attr); if (rc != CKR_OK) { TRACE_DEVEL("Failed to build CKA_NEVER_EXTRACTABLE attribute.\n"); goto end; } rc = template_update_attribute(derived_key_obj->template, always_sens_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto end; } always_sens_attr = NULL; rc = template_update_attribute(derived_key_obj->template, never_extract_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto end; } never_extract_attr = NULL; end: if (always_sens_attr != NULL) free(always_sens_attr); if (never_extract_attr != NULL) free(never_extract_attr); return rc; } // // 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, CK_BBOOL count_statistics, CK_ULONG operation) { OBJECT *key_obj = NULL; CK_ATTRIBUTE *new_attr = NULL; CK_ULONG keyclass, subclass = 0; CK_KEY_TYPE keytype1, keytype2; CK_ULONG mode, check; 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; } switch (operation) { case OP_KEYGEN: check = POLICY_CHECK_KEYGEN; mode = MODE_KEYGEN; break; case OP_ENCAPSULATE: check = POLICY_CHECK_ENCAPS; mode = MODE_ENCAPS; break; default: TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } rc = tokdata->policy->is_mech_allowed(tokdata->policy, mech, NULL, check, sess); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: Key generation mechanism not allowed\n"); return rc; } // 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 // rc = get_ulong_attribute_by_type(pTemplate, ulCount, CKA_CLASS, &keyclass); if (rc == CKR_ATTRIBUTE_VALUE_INVALID) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } if (rc == CKR_OK && keyclass != CKO_SECRET_KEY) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); return CKR_TEMPLATE_INCONSISTENT; } rc = get_ulong_attribute_by_type(pTemplate, ulCount, CKA_KEY_TYPE, &subclass); if (rc == CKR_ATTRIBUTE_VALUE_INVALID) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } 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; 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) || mech->pParameter == NULL) { 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_AES_XTS_KEY_GEN: if (subclass != 0 && subclass != CKK_AES_XTS) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); return CKR_TEMPLATE_INCONSISTENT; } subclass = CKK_AES_XTS; 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; case CKM_SHA_1_KEY_GEN: case CKM_SHA224_KEY_GEN: case CKM_SHA256_KEY_GEN: case CKM_SHA384_KEY_GEN: case CKM_SHA512_KEY_GEN: case CKM_SHA512_224_KEY_GEN: case CKM_SHA512_256_KEY_GEN: case CKM_SHA3_224_KEY_GEN: case CKM_SHA3_256_KEY_GEN: case CKM_SHA3_384_KEY_GEN: case CKM_SHA3_512_KEY_GEN: rc = pkcsget_keytype_for_mech(mech->mechanism, &keytype1, &keytype2); if (rc != CKR_OK) { TRACE_ERROR("pkcsget_keytype_for_mech failed.\n"); return rc; } if (subclass != 0 && subclass != keytype1) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); return CKR_TEMPLATE_INCONSISTENT; } subclass = keytype1; 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, 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; case CKM_SSL3_PRE_MASTER_KEY_GEN: rc = ckm_ssl3_pre_master_key_gen(tokdata, key_obj->template, mech); break; case CKM_AES_KEY_GEN: rc = ckm_aes_key_gen(tokdata, key_obj->template, FALSE); break; case CKM_AES_XTS_KEY_GEN: rc = ckm_aes_key_gen(tokdata, key_obj->template, TRUE); break; case CKM_GENERIC_SECRET_KEY_GEN: case CKM_SHA_1_KEY_GEN: case CKM_SHA224_KEY_GEN: case CKM_SHA256_KEY_GEN: case CKM_SHA384_KEY_GEN: case CKM_SHA512_KEY_GEN: case CKM_SHA512_224_KEY_GEN: case CKM_SHA512_256_KEY_GEN: case CKM_SHA3_224_KEY_GEN: case CKM_SHA3_256_KEY_GEN: case CKM_SHA3_384_KEY_GEN: case CKM_SHA3_512_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 // rc = key_mgr_apply_always_sensitive_never_extractable_attrs(tokdata, key_obj); if (rc != CKR_OK) { TRACE_ERROR("%s key_mgr_apply_always_sensitive_never_extractable_attrs " "failed with rc=0x%lx\n", __func__, rc); 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; } rc = template_update_attribute(key_obj->template, new_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } new_attr = NULL; /* add CKA_KEY_GEN_MECHANISM */ rc = build_attribute(CKA_KEY_GEN_MECHANISM, (CK_BYTE *)&mech->mechanism, sizeof(CK_MECHANISM_TYPE), &new_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto error; } rc = template_update_attribute(key_obj->template, new_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } new_attr = NULL; // at this point, the key should be fully constructed...assign // an object handle and store the key // Enforce policy rc = object_mgr_create_final(tokdata, sess, key_obj, handle); if (rc != CKR_OK) { TRACE_DEVEL("object_mgr_create_final failed.\n"); goto error; } if (count_statistics == TRUE && rc == CKR_OK) INC_COUNTER(tokdata, sess, mech, key_obj, POLICY_STRENGTH_IDX_0); return rc; error: if (key_obj) object_free(key_obj); if (new_attr != NULL) free(new_attr); *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, CK_BBOOL count_statistics, CK_ULONG operation) { OBJECT *publ_key_obj = NULL; OBJECT *priv_key_obj = NULL; CK_ATTRIBUTE *new_attr = NULL; CK_ULONG keyclass, subclass = 0; CK_BYTE *spki = NULL; CK_ULONG temp, spki_length = 0; CK_ULONG mode; int policy_check; 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; } switch (operation) { case OP_KEYGEN: policy_check = POLICY_CHECK_KEYGEN; mode = MODE_KEYGEN; break; case OP_ENCAPSULATE: policy_check = POLICY_CHECK_ENCAPS; mode = MODE_ENCAPS; break; default: TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } rc = tokdata->policy->is_mech_allowed(tokdata->policy, mech, NULL, policy_check, sess); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: Keypair generation mechanism not allowed\n"); return rc; } // 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 // rc = get_ulong_attribute_by_type(publ_tmpl, publ_count, CKA_CLASS, &keyclass); if (rc == CKR_ATTRIBUTE_VALUE_INVALID) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } if (rc == CKR_OK && keyclass != CKO_PUBLIC_KEY) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); return CKR_TEMPLATE_INCONSISTENT; } rc = get_ulong_attribute_by_type(publ_tmpl, publ_count, CKA_KEY_TYPE, &subclass); if (rc == CKR_ATTRIBUTE_VALUE_INVALID) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } rc = get_ulong_attribute_by_type(priv_tmpl, priv_count, CKA_CLASS, &keyclass); if (rc == CKR_ATTRIBUTE_VALUE_INVALID) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } if (rc == CKR_OK && keyclass != CKO_PRIVATE_KEY) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); return CKR_TEMPLATE_INCONSISTENT; } rc = get_ulong_attribute_by_type(priv_tmpl, priv_count, CKA_KEY_TYPE, &temp); if (rc == CKR_ATTRIBUTE_VALUE_INVALID) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } if (rc == CKR_OK && 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; case CKM_EC_EDWARDS_KEY_PAIR_GEN: if (subclass != 0 && subclass != CKK_EC_EDWARDS) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); return CKR_TEMPLATE_INCONSISTENT; } subclass = CKK_EC_EDWARDS; break; case CKM_EC_MONTGOMERY_KEY_PAIR_GEN: if (subclass != 0 && subclass != CKK_EC_MONTGOMERY) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); return CKR_TEMPLATE_INCONSISTENT; } subclass = CKK_EC_MONTGOMERY; 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. */ case CKM_IBM_DILITHIUM: if (subclass != 0 && subclass != CKK_IBM_PQC_DILITHIUM) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); return CKR_TEMPLATE_INCONSISTENT; } subclass = CKK_IBM_DILITHIUM; break; case CKM_IBM_ML_DSA_KEY_PAIR_GEN: if (subclass != 0 && subclass != CKK_IBM_ML_DSA) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); return CKR_TEMPLATE_INCONSISTENT; } subclass = CKK_IBM_ML_DSA; break; case CKM_IBM_KYBER: if (subclass != 0 && subclass != CKK_IBM_PQC_KYBER) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); return CKR_TEMPLATE_INCONSISTENT; } subclass = CKK_IBM_KYBER; break; case CKM_IBM_ML_KEM_KEY_PAIR_GEN: if (subclass != 0 && subclass != CKK_IBM_ML_KEM) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); return CKR_TEMPLATE_INCONSISTENT; } subclass = CKK_IBM_ML_KEM; break; case CKM_ML_DSA_KEY_PAIR_GEN: if (subclass != 0 && subclass != CKK_ML_DSA) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); return CKR_TEMPLATE_INCONSISTENT; } subclass = CKK_ML_DSA; break; case CKM_ML_KEM_KEY_PAIR_GEN: if (subclass != 0 && subclass != CKK_ML_KEM) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); return CKR_TEMPLATE_INCONSISTENT; } subclass = CKK_ML_KEM; break; 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, 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, 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; case CKM_EC_EDWARDS_KEY_PAIR_GEN: rc = ckm_ec_edwards_key_pair_gen(tokdata, publ_key_obj->template, priv_key_obj->template); break; case CKM_EC_MONTGOMERY_KEY_PAIR_GEN: rc = ckm_ec_montgomery_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. */ case CKM_IBM_DILITHIUM: case CKM_IBM_ML_DSA_KEY_PAIR_GEN: rc = ckm_ibm_ml_dsa_key_pair_gen(tokdata, mech, publ_key_obj->template, priv_key_obj->template); break; case CKM_IBM_KYBER: case CKM_IBM_ML_KEM_KEY_PAIR_GEN: rc = ckm_ibm_ml_kem_key_pair_gen(tokdata, mech, publ_key_obj->template, priv_key_obj->template); break; case CKM_ML_DSA_KEY_PAIR_GEN: rc = ckm_ml_dsa_key_pair_gen(tokdata, publ_key_obj->template, priv_key_obj->template); break; case CKM_ML_KEM_KEY_PAIR_GEN: rc = ckm_ml_kem_key_pair_gen(tokdata, publ_key_obj->template, priv_key_obj->template); break; 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 // rc = key_mgr_apply_always_sensitive_never_extractable_attrs(tokdata, priv_key_obj); if (rc != CKR_OK) { TRACE_ERROR("%s key_mgr_apply_always_sensitive_never_extractable_attrs " "failed with rc=0x%lx\n", __func__, rc); 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; } rc = template_update_attribute(publ_key_obj->template, new_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } new_attr = NULL; rc = build_attribute(CKA_LOCAL, &true, sizeof(CK_BBOOL), &new_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto error; } rc = template_update_attribute(priv_key_obj->template, new_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } new_attr = NULL; /* add CKA_KEY_GEN_MECHANISM */ rc = build_attribute(CKA_KEY_GEN_MECHANISM, (CK_BYTE *)&mech->mechanism, sizeof(CK_MECHANISM_TYPE), &new_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto error; } rc = template_update_attribute(publ_key_obj->template, new_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } new_attr = NULL; rc = build_attribute(CKA_KEY_GEN_MECHANISM, (CK_BYTE *)&mech->mechanism, sizeof(CK_MECHANISM_TYPE), &new_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto error; } rc = template_update_attribute(priv_key_obj->template, new_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } new_attr = NULL; /* Extract the SPKI and add CKA_PUBLIC_KEY_INFO to both keys */ rc = publ_key_get_spki(publ_key_obj->template, subclass, FALSE, &spki, &spki_length, FALSE); if (rc != CKR_OK) { TRACE_DEVEL("publ_key_get_spki failed\n"); goto error; } rc = build_attribute(CKA_PUBLIC_KEY_INFO, spki, spki_length, &new_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto error; } rc = template_update_attribute(publ_key_obj->template, new_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } new_attr = NULL; rc = build_attribute(CKA_PUBLIC_KEY_INFO, spki, spki_length, &new_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto error; } rc = template_update_attribute(priv_key_obj->template, new_attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed.\n"); goto error; } new_attr = NULL; free(spki); spki = NULL; // at this point, the keys should be fully constructed...assign // object handles and store the keys // Enforce policy 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; } if (count_statistics == TRUE && rc == CKR_OK) INC_COUNTER(tokdata, sess, mech, priv_key_obj, POLICY_STRENGTH_IDX_0); return rc; error: if (publ_key_obj) object_free(publ_key_obj); if (priv_key_obj) object_free(priv_key_obj); if (spki != NULL) free(spki); if (new_attr != NULL) free(new_attr); *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, CK_BBOOL count_statistics, CK_ULONG operation) { ENCR_DECR_CONTEXT *ctx = NULL; OBJECT *wrapping_key_obj = NULL; OBJECT *key_obj = NULL; CK_BYTE *data = NULL; CK_ULONG data_len; CK_OBJECT_CLASS class; CK_KEY_TYPE keytype; CK_BBOOL flag, not_opaque = FALSE; CK_ATTRIBUTE_TYPE key_usage_attr; int policy_check; CK_RV rc; if (!sess || !wrapped_key_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } switch (operation) { case OP_WRAP: key_usage_attr = CKA_WRAP; policy_check = POLICY_CHECK_WRAP; break; case OP_ENCAPSULATE: key_usage_attr = CKA_ENCAPSULATE; policy_check = POLICY_CHECK_ENCAPS; break; default: TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto done; } rc = object_mgr_find_in_map1(tokdata, h_wrapping_key, &wrapping_key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_WRAPPING_KEY_HANDLE_INVALID)); if (rc == CKR_OBJECT_HANDLE_INVALID) rc = CKR_WRAPPING_KEY_HANDLE_INVALID; goto done; } rc = object_mgr_find_in_map1(tokdata, h_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) rc = CKR_KEY_HANDLE_INVALID; goto done; } rc = tokdata->policy->is_mech_allowed(tokdata->policy, mech, &wrapping_key_obj->strength, policy_check, sess); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: key wrap\n"); goto done; } rc = tokdata->policy->is_key_allowed(tokdata->policy, &key_obj->strength, sess); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: key wrap\n"); goto done; } if (!key_object_is_mechanism_allowed(wrapping_key_obj->template, mech->mechanism)) { TRACE_ERROR("Mechanism not allowed per CKA_ALLOWED_MECHANISMS.\n"); rc = CKR_MECHANISM_INVALID; goto done; } if (operation == OP_WRAP) { if (!key_object_wrap_template_matches(wrapping_key_obj->template, key_obj->template)) { TRACE_ERROR("Wrap template does not match.\n"); rc = CKR_KEY_HANDLE_INVALID; goto done; } } // is the key-to-be-wrapped EXTRACTABLE? // rc = template_attribute_get_bool(key_obj->template, CKA_EXTRACTABLE, &flag); if (rc != CKR_OK) { 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; } if (flag == FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_UNEXTRACTABLE)); rc = CKR_KEY_UNEXTRACTABLE; goto done; } /* is key allowed to do the desired operation? */ rc = template_attribute_get_bool(wrapping_key_obj->template, key_usage_attr, &flag); if (rc != CKR_OK) { TRACE_ERROR("Could not find %s for the wrapping key.\n", p11_get_cka(key_usage_attr)); rc = CKR_KEY_FUNCTION_NOT_PERMITTED; goto done; } if (flag == FALSE) { TRACE_ERROR("%s is set to FALSE.\n", p11_get_cka(key_usage_attr)); rc = CKR_KEY_FUNCTION_NOT_PERMITTED; goto done; } if (operation == OP_WRAP) { /* Is a wrapping key with CKA_TRUSTED = CK_TRUE required? */ rc = template_attribute_get_bool(key_obj->template, CKA_WRAP_WITH_TRUSTED, &flag); if (rc == CKR_ATTRIBUTE_VALUE_INVALID) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); goto done; } if (rc == CKR_OK && flag == TRUE) { rc = template_attribute_get_bool(wrapping_key_obj->template, CKA_TRUSTED, &flag); if (rc == CKR_ATTRIBUTE_VALUE_INVALID) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); goto done; } if (rc != CKR_OK || flag == FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_NOT_WRAPPABLE)); rc = CKR_KEY_NOT_WRAPPABLE; 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_get_ulong(key_obj->template, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); goto done; } // 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) { 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: case CKM_AES_XTS: case CKM_AES_GCM: case CKM_AES_KEY_WRAP: case CKM_AES_KEY_WRAP_PAD: case CKM_AES_KEY_WRAP_KWP: case CKM_AES_KEY_WRAP_PKCS7: case CKM_RSA_AES_KEY_WRAP: case CKM_ECDH_AES_KEY_WRAP: case CKM_ECDH_COF_AES_KEY_WRAP: case CKM_ECDH_X_AES_KEY_WRAP: 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_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; } if (token_specific.t_key_wrap == NULL && token_specific.secure_key_token) { TRACE_ERROR("Need a token specific wrap for a secure key token\n"); rc = CKR_FUNCTION_NOT_SUPPORTED; goto done; } if (token_specific.t_key_wrap != NULL) { rc = token_specific.t_key_wrap(tokdata, sess, mech, length_only, wrapping_key_obj, key_obj, wrapped_key, wrapped_key_len, ¬_opaque); if (rc != CKR_OK) { TRACE_ERROR("token specific wrap function failed\n"); goto done; } if (rc == CKR_OK && not_opaque == FALSE) goto done; } // extract the secret data to be wrapped // rc = template_attribute_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } switch (keytype) { case CKK_DES: rc = des_wrap_get_data(key_obj->template, FALSE, &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(key_obj->template, FALSE, &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(key_obj->template, FALSE, &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(key_obj->template, FALSE, &data, &data_len); if (rc != CKR_OK) { TRACE_DEVEL("dsa_priv_wrap_get_data failed.\n"); goto done; } break; #endif #if !(NODH) case CKK_DH: rc = dh_priv_wrap_get_data(key_obj->template, FALSE, &data, &data_len); if (rc != CKR_OK) { TRACE_DEVEL("dh_priv_wrap_get_data failed.\n"); goto done; } break; #endif case CKK_GENERIC_SECRET: case CKK_SHA_1_HMAC: case CKK_SHA224_HMAC: case CKK_SHA256_HMAC: case CKK_SHA384_HMAC: case CKK_SHA512_HMAC: case CKK_SHA3_224_HMAC: case CKK_SHA3_256_HMAC: case CKK_SHA3_384_HMAC: case CKK_SHA3_512_HMAC: case CKK_SHA512_224_HMAC: case CKK_SHA512_256_HMAC: rc = generic_secret_wrap_get_data(key_obj->template, FALSE, &data, &data_len); if (rc != CKR_OK) { TRACE_DEVEL("generic_secret_wrap_get_data failed.\n"); goto done; } break; case CKK_AES: case CKK_AES_XTS: rc = aes_wrap_get_data(key_obj->template, FALSE, &data, &data_len); if (rc != CKR_OK) { TRACE_DEVEL("aes_wrap_get_data failed.\n"); goto done; } break; case CKK_EC: case CKK_EC_EDWARDS: case CKK_EC_MONTGOMERY: rc = ec_priv_wrap_get_data(key_obj->template, FALSE, &data, &data_len, keytype); if (rc != CKR_OK) { TRACE_DEVEL("ec_priv_wrap_get_data failed.\n"); goto done; } break; case CKK_IBM_PQC_DILITHIUM: case CKK_IBM_PQC_KYBER: case CKK_IBM_ML_DSA: case CKK_IBM_ML_KEM: case CKK_ML_DSA: case CKK_ML_KEM: rc = pqc_priv_wrap_get_data(key_obj->template, keytype, FALSE, &data, &data_len); if (rc != CKR_OK) { TRACE_DEVEL("pqc_priv_wrap_get_data failed.\n"); 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) { case CKM_DES_ECB: case CKM_DES_CBC: case CKM_DES3_ECB: case CKM_DES3_CBC: rc = ckm_des_wrap_format(tokdata, FALSE, &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; 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: case CKM_AES_KEY_WRAP: rc = ckm_aes_wrap_format(tokdata, FALSE, mech->mechanism == CKM_AES_KEY_WRAP ? AES_KEY_WRAP_BLOCK_SIZE : AES_BLOCK_SIZE, &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; case CKM_AES_KEY_WRAP_PAD: case CKM_AES_KEY_WRAP_KWP: case CKM_AES_KEY_WRAP_PKCS7: case CKM_RSA_AES_KEY_WRAP: case CKM_ECDH_AES_KEY_WRAP: case CKM_ECDH_COF_AES_KEY_WRAP: case CKM_ECDH_X_AES_KEY_WRAP: 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: case CKM_AES_XTS: case CKM_AES_GCM: 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 // /* Policy already checked */ rc = encr_mgr_init(tokdata, sess, ctx, operation, mech, h_wrapping_key, FALSE); 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, 'wrapped_key' 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(tokdata, sess, ctx); free(ctx); done: if (count_statistics == TRUE && rc == CKR_OK) INC_COUNTER(tokdata, sess, mech, wrapping_key_obj, POLICY_STRENGTH_IDX_0); if (wrapping_key_obj != NULL) { object_put(tokdata, wrapping_key_obj, TRUE); wrapping_key_obj = NULL; } if (key_obj != NULL) { object_put(tokdata, key_obj, TRUE); key_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, CK_BBOOL count_statistics, CK_ULONG operation) { ENCR_DECR_CONTEXT *ctx = NULL; OBJECT *key_obj = NULL, *unwrapping_key_obj = NULL; CK_BYTE *data = NULL; CK_ULONG data_len, value_len = 0; CK_ULONG keyclass = 0, keytype = 0, priv_keytype = 0, alt_priv_keytype = 0; CK_BBOOL fromend, not_opaque = FALSE, flag; CK_ATTRIBUTE *new_attrs = NULL; CK_ULONG new_attr_count = 0; CK_MECHANISM *statistics_mech = mech; int policy_check; CK_ATTRIBUTE_TYPE key_usage_attr, apply_tmpl_attr; CK_ULONG mode; CK_RV rc; if (!sess || !wrapped_key || !h_unwrapped_key) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } switch (operation) { case OP_UNWRAP: key_usage_attr = CKA_UNWRAP; apply_tmpl_attr = CKA_UNWRAP_TEMPLATE; policy_check = POLICY_CHECK_UNWRAP; mode = MODE_UNWRAP; break; case OP_DECAPSULATE: key_usage_attr = CKA_DECAPSULATE; apply_tmpl_attr = CKA_DECAPSULATE_TEMPLATE; policy_check = POLICY_CHECK_DECAPS; mode = MODE_DECAPS; break; default: TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto done; } rc = object_mgr_find_in_map1(tokdata, h_unwrapping_key, &unwrapping_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_UNWRAPPING_KEY_HANDLE_INVALID; goto done; } rc = tokdata->policy->is_mech_allowed(tokdata->policy, mech, &unwrapping_key_obj->strength, policy_check, sess); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: key unwrap\n"); goto done; } if (!key_object_is_mechanism_allowed(unwrapping_key_obj->template, mech->mechanism)) { TRACE_ERROR("Mechanism not allowed per CKA_ALLOWED_MECHANISMS.\n"); rc = CKR_MECHANISM_INVALID; goto done; } /* is key allowed to do the desired operation? */ rc = template_attribute_get_bool(unwrapping_key_obj->template, key_usage_attr, &flag); if (rc != CKR_OK) { TRACE_ERROR("Could not find %s for the unwrapping key.\n", p11_get_cka(key_usage_attr)); rc = CKR_KEY_FUNCTION_NOT_PERMITTED; goto done; } if (flag == FALSE) { TRACE_ERROR("%s is set to FALSE.\n", p11_get_cka(key_usage_attr)); rc = CKR_KEY_FUNCTION_NOT_PERMITTED; goto done; } /* * 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 */ rc = get_ulong_attribute_by_type(attributes, attrib_count, CKA_CLASS, &keyclass); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); goto done; } rc = get_ulong_attribute_by_type(attributes, attrib_count, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } switch (mech->mechanism) { 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"); rc = CKR_ARGUMENTS_BAD; goto done; } break; 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: case CKM_AES_XTS: case CKM_AES_GCM: case CKM_AES_KEY_WRAP: case CKM_AES_KEY_WRAP_PAD: case CKM_AES_KEY_WRAP_KWP: case CKM_AES_KEY_WRAP_PKCS7: case CKM_RSA_AES_KEY_WRAP: case CKM_ECDH_AES_KEY_WRAP: case CKM_ECDH_COF_AES_KEY_WRAP: case CKM_ECDH_X_AES_KEY_WRAP: if ((keyclass != CKO_SECRET_KEY) && (keyclass != CKO_PRIVATE_KEY)) { TRACE_ERROR("Specified mech unwraps secret & private keys only.\n"); rc = CKR_ARGUMENTS_BAD; goto done; } break; default: TRACE_ERROR("The specified mechanism cannot unwrap keys.\n"); rc = CKR_MECHANISM_INVALID; goto done; } rc = key_object_apply_template_attr(unwrapping_key_obj->template, apply_tmpl_attr, attributes, attrib_count, &new_attrs, &new_attr_count); if (rc != CKR_OK) { TRACE_DEVEL("key_object_apply_template_attr failed.\n"); goto done; } rc = get_ulong_attribute_by_type(new_attrs, new_attr_count, CKA_VALUE_LEN, &value_len); if (rc == CKR_OK) { /* * Only some wrapping mechanisms allow CKA_VALUE_LEN to be specified * in the unwrapping template for certain key types. */ switch (mech->mechanism) { case CKM_RSA_X_509: case CKM_DES_ECB: case CKM_AES_ECB: case CKM_AES_CBC: 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_AES_XTS: case CKM_AES_GCM: case CKM_AES_KEY_WRAP: switch (keytype) { case CKK_AES: case CKK_AES_XTS: case CKK_GENERIC_SECRET: case CKK_SHA_1_HMAC: case CKK_SHA224_HMAC: case CKK_SHA256_HMAC: case CKK_SHA384_HMAC: case CKK_SHA512_HMAC: case CKK_SHA3_224_HMAC: case CKK_SHA3_256_HMAC: case CKK_SHA3_384_HMAC: case CKK_SHA3_512_HMAC: case CKK_SHA512_224_HMAC: case CKK_SHA512_256_HMAC: break; default: TRACE_ERROR("The key type does not allow CKA_VALUE_LEN to be " "specified in the unwrapping template.\n"); rc = CKR_TEMPLATE_INCONSISTENT; goto done; } break; default: TRACE_ERROR("The specified mechanism does not allow CKA_VALUE_LEN " "to be specified in the unwrapping template.\n"); rc = CKR_TEMPLATE_INCONSISTENT; goto done; } } rc = object_mgr_create_skel(tokdata, sess, new_attrs, new_attr_count, mode, keyclass, keytype, &key_obj); if (rc != CKR_OK) { TRACE_DEVEL("object_mgr_create_skel failed.\n"); goto done; } if (token_specific.t_key_unwrap == NULL && token_specific.secure_key_token) { TRACE_ERROR("Need a token specific unwrap for a secure key token\n"); rc = CKR_FUNCTION_NOT_SUPPORTED; goto done; } if (token_specific.t_key_unwrap != NULL) { rc = token_specific.t_key_unwrap(tokdata, sess, mech, wrapped_key, wrapped_key_len, unwrapping_key_obj, key_obj, ¬_opaque); if (rc != CKR_OK) { TRACE_ERROR("token specific unwrap function failed\n"); goto done; } if (rc == CKR_OK && not_opaque == FALSE) goto final; } // 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)); rc = CKR_HOST_MEMORY; goto done; } memset(ctx, 0x0, sizeof(ENCR_DECR_CONTEXT)); /* Policy already checked */ rc = decr_mgr_init(tokdata, sess, ctx, operation, mech, h_unwrapping_key, FALSE, FALSE); if (rc != CKR_OK) goto done; rc = decr_mgr_decrypt(tokdata, sess, TRUE, ctx, wrapped_key, wrapped_key_len, data, &data_len); if (rc != CKR_OK) { if (rc == CKR_ENCRYPTED_DATA_LEN_RANGE) rc = CKR_WRAPPED_KEY_LEN_RANGE; TRACE_DEVEL("decr_mgr_decrypt failed.\n"); goto done; } data = (CK_BYTE *) malloc(data_len); if (!data) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto done; } rc = decr_mgr_decrypt(tokdata, sess, FALSE, ctx, wrapped_key, wrapped_key_len, data, &data_len); if (rc != CKR_OK) { if (rc == CKR_ENCRYPTED_DATA_LEN_RANGE) rc = CKR_WRAPPED_KEY_LEN_RANGE; TRACE_DEVEL("decr_mgr_decrypt failed.\n"); goto done; } // 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; if (mech->mechanism == CKM_RSA_AES_KEY_WRAP) { /* * For CKM_RSA_AES_KEY_WRAP, the mechanism parameter copy in ctx has * been updated to hold the actual size of the temp. AES key. Use this * for statistics counting, not the user supplied mechanism parameter, * which might contain an invalid/incorrect AES key size. * Ctx is cleaned up and freed only after statistics counting, so the * copied (and updated) mechanism parameter is still available. */ statistics_mech = &ctx->mech; } // extract the key type from the PrivateKeyInfo::AlgorithmIndicator if (keyclass == CKO_PRIVATE_KEY) { rc = key_mgr_get_private_key_type(data, data_len, &priv_keytype, &alt_priv_keytype); if (rc != CKR_OK) { TRACE_DEVEL("key_mgr_get_private_key_type failed.\n"); goto done; } if (priv_keytype != keytype && alt_priv_keytype != keytype) { rc = CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT; TRACE_DEVEL("keytype in template (%lu) does not match the unwrapped" " key (%lu or %lu).\n", keytype, priv_keytype, alt_priv_keytype); goto done; } } // 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); break; case CKO_PRIVATE_KEY: rc = priv_key_unwrap(key_obj->template, keytype, data, data_len); break; default: rc = CKR_WRAPPED_KEY_INVALID; break; } if (rc != CKR_OK) { TRACE_DEVEL("key_unwrap failed.\n"); goto done; } /* Give the token a chance to check if it supports the unwrapped key */ if (token_specific.t_set_attrs_for_new_object != NULL) { rc = token_specific.t_set_attrs_for_new_object(tokdata, keyclass, MODE_UNWRAPPED, key_obj->template); if (rc != CKR_OK) { TRACE_ERROR("token_specific.t_set_attrs_for_new_object failed with " "rc=%lx\n", rc); goto done; } } final: // 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 done; } done: if (count_statistics == TRUE && rc == CKR_OK) INC_COUNTER(tokdata, sess, statistics_mech, unwrapping_key_obj, POLICY_STRENGTH_IDX_0); if (rc != CKR_OK && key_obj) object_free(key_obj); if (unwrapping_key_obj != NULL) { object_put(tokdata, unwrapping_key_obj, TRUE); unwrapping_key_obj = NULL; } if (new_attrs != NULL) cleanse_and_free_attribute_array(new_attrs, new_attr_count); if (data) { OPENSSL_cleanse(data, data_len); free(data); } if (ctx != NULL) { decr_mgr_cleanup(tokdata, sess, ctx); free(ctx); } return rc; } CK_RV key_mgr_get_private_key_type(CK_BYTE *keydata, CK_ULONG keylen, CK_KEY_TYPE *keytype, CK_KEY_TYPE *alt_keytype) { CK_BYTE *alg = NULL; CK_BYTE *priv_key = NULL; CK_ULONG alg_len, priv_key_len, i; CK_RV rc; *alt_keytype = (CK_KEY_TYPE)-1; rc = ber_decode_PrivateKeyInfo(keydata, keylen, &alg, &alg_len, &priv_key, &priv_key_len); 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; } } // Check only the OBJECT IDENTIFIERs for Edwards // for (i = 0; i < NUMEC; i++) { if (der_ec_supported[i].curve_type == EDWARDS_CURVE && alg_len >= der_ec_supported[i].data_size && memcmp(alg, der_ec_supported[i].data, der_ec_supported[i].data_size) == 0) { *keytype = CKK_EC_EDWARDS; return CKR_OK; } } // Check only the OBJECT IDENTIFIERs for Montgomery // for (i = 0; i < NUMEC; i++) { if (der_ec_supported[i].curve_type == MONTGOMERY_CURVE && alg_len >= der_ec_supported[i].data_size && memcmp(alg, der_ec_supported[i].data, der_ec_supported[i].data_size) == 0) { *keytype = CKK_EC_MONTGOMERY; return CKR_OK; } } // Check only the OBJECT IDENTIFIER for DH // if (alg_len >= ber_idDHLen) { if (memcmp(alg, ber_idDH, ber_idDHLen) == 0) { *keytype = CKK_DH; return CKR_OK; } } // Check only the OBJECT IDENTIFIERs for DILITHIUM // for (i = 0; dilithium_oids[i].oid != NULL; i++) { if (alg_len == dilithium_oids[i].oid_len + ber_NULLLen && memcmp(alg, dilithium_oids[i].oid, dilithium_oids[i].oid_len) == 0 && memcmp(alg + dilithium_oids[i].oid_len, ber_NULL, ber_NULLLen) == 0) { *keytype = CKK_IBM_PQC_DILITHIUM; return CKR_OK; } } // Check only the OBJECT IDENTIFIERs for KYBER // for (i = 0; kyber_oids[i].oid != NULL; i++) { if (alg_len == kyber_oids[i].oid_len + ber_NULLLen && memcmp(alg, kyber_oids[i].oid, kyber_oids[i].oid_len) == 0 && memcmp(alg + kyber_oids[i].oid_len, ber_NULL, ber_NULLLen) == 0) { *keytype = CKK_IBM_PQC_KYBER; return CKR_OK; } } // Check only the OBJECT IDENTIFIERs for ML-DSA // for (i = 0; ml_dsa_oids[i].oid != NULL; i++) { if (alg_len == ml_dsa_oids[i].oid_len && memcmp(alg, ml_dsa_oids[i].oid, ml_dsa_oids[i].oid_len) == 0) { *keytype = CKK_ML_DSA; *alt_keytype = CKK_IBM_ML_DSA; return CKR_OK; } } // Check only the OBJECT IDENTIFIERs for ML-KEM // for (i = 0; ml_kem_oids[i].oid != NULL; i++) { if (alg_len == ml_kem_oids[i].oid_len && memcmp(alg, ml_kem_oids[i].oid, ml_kem_oids[i].oid_len) == 0) { *keytype = CKK_ML_KEM; *alt_keytype = CKK_IBM_ML_KEM; 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, CK_BBOOL count_statistics, CK_ULONG operation) { OBJECT *base_key_obj = NULL; CK_ATTRIBUTE *new_attrs = NULL; CK_ULONG new_attr_count = 0; CK_BBOOL flag; CK_ATTRIBUTE_TYPE key_usage_attr, apply_tmpl_attr; CK_ULONG mode; int policy_check; CK_RV rc; 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 (operation) { case OP_DERIVE: key_usage_attr = CKA_DERIVE; apply_tmpl_attr = CKA_DERIVE_TEMPLATE; policy_check = POLICY_CHECK_DERIVE; mode = MODE_DERIVE; break; case OP_ENCAPSULATE: if (mech->mechanism != CKM_ECDH1_DERIVE && mech->mechanism != CKM_ECDH1_COFACTOR_DERIVE && mech->mechanism != CKM_DH_PKCS_DERIVE) { TRACE_ERROR("OP_ENCAPSULATE is only supportd with " "CKM_ECDH1_DERIVE, CKM_ECDH1_COFACTOR_DERIVE, and " "CKM_DH_PKCS_DERIVE\n"); rc = CKR_FUNCTION_FAILED; goto done; } /* * Check for CKA_DECAPSULATE for OP_ENCAPSUALTE as well. Derive is * always done with the private key as base key which has * CKA_DECAPSULATE. */ key_usage_attr = CKA_DECAPSULATE; apply_tmpl_attr = CKA_DECAPSULATE_TEMPLATE; policy_check = POLICY_CHECK_ENCAPS; mode = MODE_ENCAPS; break; case OP_DECAPSULATE: if (mech->mechanism != CKM_ECDH1_DERIVE && mech->mechanism != CKM_ECDH1_COFACTOR_DERIVE && mech->mechanism != CKM_DH_PKCS_DERIVE) { TRACE_ERROR("OP_DECAPSULATE is only supportd with " "CKM_ECDH1_DERIVE, CKM_ECDH1_COFACTOR_DERIVE, and " "CKM_DH_PKCS_DERIVE\n"); rc = CKR_FUNCTION_FAILED; goto done; } key_usage_attr = CKA_DECAPSULATE; apply_tmpl_attr = CKA_DECAPSULATE_TEMPLATE; policy_check = POLICY_CHECK_DECAPS; mode = MODE_DECAPS; break; case OP_WRAP: if (mech->mechanism != CKM_ECDH1_DERIVE && mech->mechanism != CKM_ECDH1_COFACTOR_DERIVE) { TRACE_ERROR("OP_WRAP/UNWRAP is only supportd with " "CKM_ECDH1_DERIVE and CKM_ECDH1_COFACTOR_DERIVE\n"); rc = CKR_FUNCTION_FAILED; goto done; } /* * Check for CKA_UNWRAP for OP_WRAP as well, Derive is always done * with the private key as base key which has CKA_UNWRAP. */ key_usage_attr = CKA_UNWRAP; apply_tmpl_attr = CKA_UNWRAP_TEMPLATE; policy_check = POLICY_CHECK_WRAP; mode = MODE_DERIVE; /* Use DERIVE, WRAP does not produce a key object */ break; case OP_UNWRAP: if (mech->mechanism != CKM_ECDH1_DERIVE && mech->mechanism != CKM_ECDH1_COFACTOR_DERIVE) { TRACE_ERROR("OP_WRAP/UNWRAP is only supportd with " "CKM_ECDH1_DERIVE and CKM_ECDH1_COFACTOR_DERIVE\n"); rc = CKR_FUNCTION_FAILED; goto done; } key_usage_attr = CKA_UNWRAP; apply_tmpl_attr = CKA_UNWRAP_TEMPLATE; policy_check = POLICY_CHECK_UNWRAP; mode = MODE_UNWRAP; break; default: TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } 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.\n"); if (rc == CKR_OBJECT_HANDLE_INVALID) rc = CKR_KEY_HANDLE_INVALID; goto done; } rc = tokdata->policy->is_mech_allowed(tokdata->policy, mech, &base_key_obj->strength, policy_check, sess); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: derive key\n"); goto done; } if (!key_object_is_mechanism_allowed(base_key_obj->template, mech->mechanism)) { TRACE_ERROR("Mechanism not allowed per CKA_ALLOWED_MECHANISMS.\n"); rc = CKR_MECHANISM_INVALID; goto done; } /* is base key allowed to do the desired operation? */ rc = template_attribute_get_bool(base_key_obj->template, key_usage_attr, &flag); if (rc != CKR_OK) { TRACE_ERROR("Could not find %s for the base key.\n", p11_get_cka(key_usage_attr)); rc = CKR_KEY_FUNCTION_NOT_PERMITTED; goto done; } if (flag != TRUE) { TRACE_ERROR("%s is set to FALSE.\n", p11_get_cka(key_usage_attr)); rc = CKR_KEY_FUNCTION_NOT_PERMITTED; goto done; } rc = key_object_apply_template_attr(base_key_obj->template, apply_tmpl_attr, pTemplate, ulCount, &new_attrs, &new_attr_count); if (rc != CKR_OK) { TRACE_DEVEL("key_object_apply_template_attr failed.\n"); goto done; } switch (mech->mechanism) { case CKM_SSL3_MASTER_KEY_DERIVE: if (!derived_key) { TRACE_ERROR("%s received bad argument(s)\n", __func__); rc = CKR_FUNCTION_FAILED; break; } rc = ssl3_master_key_derive(tokdata, sess, mech, base_key_obj, new_attrs, new_attr_count, derived_key, count_statistics); break; case CKM_SSL3_KEY_AND_MAC_DERIVE: rc = ssl3_key_and_mac_derive(tokdata, sess, mech, base_key_obj, new_attrs, new_attr_count, count_statistics); 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__); rc = CKR_FUNCTION_FAILED; break; } rc = dh_pkcs_derive(tokdata, sess, mech, base_key_obj, new_attrs, new_attr_count, derived_key, count_statistics); break; #endif /* End code contributed by Corrent corp. */ case CKM_ECDH1_DERIVE: case CKM_ECDH1_COFACTOR_DERIVE: if (!derived_key) { TRACE_ERROR("%s received bad argument(s)\n", __func__); rc = CKR_FUNCTION_FAILED; break; } rc = ecdh_pkcs_derive(tokdata, sess, mech, base_key_obj, new_attrs, new_attr_count, derived_key, count_statistics, mode); break; case CKM_SHA1_KEY_DERIVATION: case CKM_SHA224_KEY_DERIVATION: case CKM_SHA256_KEY_DERIVATION: case CKM_SHA384_KEY_DERIVATION: case CKM_SHA512_KEY_DERIVATION: case CKM_SHA512_224_KEY_DERIVATION: case CKM_SHA512_256_KEY_DERIVATION: case CKM_SHA3_224_KEY_DERIVATION: case CKM_SHA3_256_KEY_DERIVATION: case CKM_SHA3_384_KEY_DERIVATION: case CKM_SHA3_512_KEY_DERIVATION: if (!derived_key) { TRACE_ERROR("%s received bad argument(s)\n", __func__); rc = CKR_FUNCTION_FAILED; break; } rc = ckm_sha_derive(tokdata, sess, mech, base_key_obj, new_attrs, new_attr_count, derived_key, count_statistics); break; case CKM_SHAKE_128_KEY_DERIVATION: case CKM_SHAKE_256_KEY_DERIVATION: if (!derived_key) { TRACE_ERROR("%s received bad argument(s)\n", __func__); rc = CKR_FUNCTION_FAILED; break; } rc = ckm_shake_derive(tokdata, sess, mech, base_key_obj, new_attrs, new_attr_count, derived_key); break; case CKM_IBM_KYBER: case CKM_IBM_ML_KEM: case CKM_IBM_ML_KEM_WITH_ECDH: if (!derived_key) { TRACE_ERROR("%s received bad argument(s)\n", __func__); rc = CKR_FUNCTION_FAILED; break; } rc = ibm_ml_kem_derive(tokdata, sess, mech, base_key_obj, new_attrs, new_attr_count, derived_key); break; case CKM_PUB_KEY_FROM_PRIV_KEY: if (!derived_key) { TRACE_ERROR("%s received bad argument(s)\n", __func__); rc = CKR_FUNCTION_FAILED; break; } rc = key_pub_from_priv(tokdata, sess, base_key_obj, new_attrs, new_attr_count, derived_key); break; default: TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); rc = CKR_MECHANISM_INVALID; break; } done: if (new_attrs != NULL) cleanse_and_free_attribute_array(new_attrs, new_attr_count); if (base_key_obj != NULL) { object_put(tokdata, base_key_obj, TRUE); base_key_obj = NULL; } return rc; } CK_RV key_mgr_encapsulate_key(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, CK_MECHANISM *mech, CK_OBJECT_HANDLE hPublicKey, CK_ATTRIBUTE *pTemplate, CK_ULONG ulAttributeCount, CK_BYTE *pCiphertext, CK_ULONG *pulCiphertextLen, CK_OBJECT_HANDLE *phKey, CK_BBOOL count_statistics) { OBJECT *public_key_obj = NULL; CK_ATTRIBUTE *new_attrs = NULL; CK_ULONG new_attr_count = 0; CK_BBOOL flag; CK_RV rc; if (sess == NULL || mech == NULL || pulCiphertextLen == NULL) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } if (!length_only && (pCiphertext == NULL || phKey == NULL)) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } if (phKey != NULL) *phKey = CK_INVALID_HANDLE; rc = object_mgr_find_in_map1(tokdata, hPublicKey, &public_key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_OBJECT_HANDLE_INVALID)); goto done; } rc = tokdata->policy->is_mech_allowed(tokdata->policy, mech, &public_key_obj->strength, POLICY_CHECK_ENCAPS, sess); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: key encapsulation\n"); goto done; } if (!key_object_is_mechanism_allowed(public_key_obj->template, mech->mechanism)) { TRACE_ERROR("Mechanism not allowed per CKA_ALLOWED_MECHANISMS.\n"); rc = CKR_MECHANISM_INVALID; goto done; } rc = template_attribute_get_bool(public_key_obj->template, CKA_ENCAPSULATE, &flag); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_ENCAPSULATE for the public key.\n"); rc = CKR_KEY_FUNCTION_NOT_PERMITTED; goto done; } if (flag == FALSE) { TRACE_ERROR("CKA_ENCAPSULATE is set to FALSE.\n"); rc = CKR_KEY_FUNCTION_NOT_PERMITTED; goto done; } rc = key_object_apply_template_attr(public_key_obj->template, CKA_ENCAPSULATE_TEMPLATE, pTemplate, ulAttributeCount, &new_attrs, &new_attr_count); if (rc != CKR_OK) { TRACE_DEVEL("key_object_apply_template_attr failed.\n"); goto done; } switch (mech->mechanism) { case CKM_RSA_PKCS_OAEP: case CKM_RSA_PKCS: rc = rsa_encapsulate_key(tokdata, sess, length_only, mech, public_key_obj, new_attrs, new_attr_count, pCiphertext, pulCiphertextLen, phKey); break; case CKM_ECDH1_DERIVE: case CKM_ECDH1_COFACTOR_DERIVE: rc = ecdh_encapsulate_key(tokdata, sess, length_only, mech, public_key_obj, new_attrs, new_attr_count, pCiphertext, pulCiphertextLen, phKey); break; #ifndef NODH case CKM_DH_PKCS_DERIVE: rc = dh_encapsulate_key(tokdata, sess, length_only, mech, public_key_obj, new_attrs, new_attr_count, pCiphertext, pulCiphertextLen, phKey); break; #endif case CKM_ML_KEM: rc = ml_kem_encapsulate_key(tokdata, sess, length_only, mech, public_key_obj, new_attrs, new_attr_count, pCiphertext, pulCiphertextLen, phKey); break; default: TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); rc = CKR_MECHANISM_INVALID; break; } done: if (count_statistics == TRUE && rc == CKR_OK) INC_COUNTER(tokdata, sess, mech, public_key_obj, POLICY_STRENGTH_IDX_0); if (new_attrs != NULL) cleanse_and_free_attribute_array(new_attrs, new_attr_count); if (public_key_obj != NULL) { object_put(tokdata, public_key_obj, TRUE); public_key_obj = NULL; } return rc; } CK_RV key_mgr_decapsulate_key(STDLL_TokData_t *tokdata, SESSION *sess, CK_MECHANISM *mech, CK_OBJECT_HANDLE hPrivateKey, CK_ATTRIBUTE *pTemplate, CK_ULONG ulAttributeCount, CK_BYTE *pCiphertext, CK_ULONG ulCiphertextLen, CK_OBJECT_HANDLE *phKey, CK_BBOOL count_statistics) { OBJECT *private_key_obj = NULL; CK_ATTRIBUTE *new_attrs = NULL; CK_ULONG new_attr_count = 0; CK_BBOOL flag; CK_RV rc; if (sess == NULL || mech == NULL || pCiphertext == NULL || ulCiphertextLen == 0 || phKey == NULL) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } *phKey = CK_INVALID_HANDLE; rc = object_mgr_find_in_map1(tokdata, hPrivateKey, &private_key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_OBJECT_HANDLE_INVALID)); goto done; } rc = tokdata->policy->is_mech_allowed(tokdata->policy, mech, &private_key_obj->strength, POLICY_CHECK_DECAPS, sess); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: key decapsulation\n"); goto done; } if (!key_object_is_mechanism_allowed(private_key_obj->template, mech->mechanism)) { TRACE_ERROR("Mechanism not allowed per CKA_ALLOWED_MECHANISMS.\n"); rc = CKR_MECHANISM_INVALID; goto done; } rc = template_attribute_get_bool(private_key_obj->template, CKA_DECAPSULATE, &flag); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_DECAPSULATE for the public key.\n"); rc = CKR_KEY_FUNCTION_NOT_PERMITTED; goto done; } if (flag == FALSE) { TRACE_ERROR("CKA_DECAPSULATE is set to FALSE.\n"); rc = CKR_KEY_FUNCTION_NOT_PERMITTED; goto done; } rc = key_object_apply_template_attr(private_key_obj->template, CKA_DECAPSULATE_TEMPLATE, pTemplate, ulAttributeCount, &new_attrs, &new_attr_count); if (rc != CKR_OK) { TRACE_DEVEL("key_object_apply_template_attr failed.\n"); goto done; } switch (mech->mechanism) { case CKM_RSA_PKCS_OAEP: case CKM_RSA_PKCS: rc = rsa_decapsulate_key(tokdata, sess, mech, private_key_obj, new_attrs, new_attr_count, pCiphertext, ulCiphertextLen, phKey); break; case CKM_ECDH1_DERIVE: case CKM_ECDH1_COFACTOR_DERIVE: rc = ecdh_decapsulate_key(tokdata, sess, mech, private_key_obj, new_attrs, new_attr_count, pCiphertext, ulCiphertextLen, phKey); break; #ifndef NODH case CKM_DH_PKCS_DERIVE: rc = dh_decapsulate_key(tokdata, sess, mech, private_key_obj, new_attrs, new_attr_count, pCiphertext, ulCiphertextLen, phKey); break; #endif case CKM_ML_KEM: rc = ml_kem_decapsulate_key(tokdata, sess, mech,private_key_obj, new_attrs, new_attr_count, pCiphertext, ulCiphertextLen, phKey); break; default: TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); rc = CKR_MECHANISM_INVALID; break; } done: if (count_statistics == TRUE && rc == CKR_OK) INC_COUNTER(tokdata, sess, mech, private_key_obj, POLICY_STRENGTH_IDX_0); if (new_attrs != NULL) cleanse_and_free_attribute_array(new_attrs, new_attr_count); if (private_key_obj != NULL) { object_put(tokdata, private_key_obj, TRUE); private_key_obj = NULL; } return rc; } opencryptoki-opencryptoki-451d99c/usr/lib/common/list.h000066400000000000000000000065211520105705100233230ustar00rootroot00000000000000/* * 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 opencryptoki-opencryptoki-451d99c/usr/lib/common/loadsave.c000066400000000000000000002636731520105705100241560ustar00rootroot00000000000000/* * 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 // // #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "platform.h" #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" #include "slotmgr.h" // for ock_snprintf CK_RV set_perm(int, const char *group); CK_RV restore_private_token_object_old(STDLL_TokData_t *tokdata, CK_BYTE *data, CK_ULONG len, OBJECT *pObj, const char *fname); 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); static int get_token_object_path(char *buf, size_t buflen, STDLL_TokData_t *tokdata, const char *path, const char *postfix) { if (ock_snprintf(buf, buflen, "%s/" PK_LITE_OBJ_DIR "/%.8s%s", tokdata->data_store, path, postfix != NULL ? postfix : "") != 0) { TRACE_ERROR("buffer overflow for object path %s", path); return -1; } return 0; } static FILE *open_token_object_path(char *buf, size_t buflen, STDLL_TokData_t *tokdata, const char *path, const char *mode) { FILE *fp; if (get_token_object_path(buf, buflen, tokdata, path, NULL) < 0) return NULL; /* CWE-59 fix: Use fopen_nofollow to prevent symlink attacks */ fp = fopen_nofollow(buf, mode); if (fp == NULL && errno == ELOOP) TRACE_ERROR("Refusing to follow symlink: %s\n", buf); return fp; } static FILE *open_token_object_path_new(char *newbuf, size_t newbuflen, char *basebuf, size_t basebuflen, STDLL_TokData_t *tokdata, const char *path, const char *mode) { FILE *fp; if (get_token_object_path(newbuf, newbuflen, tokdata, path, ".TMP") < 0) return NULL; if (get_token_object_path(basebuf, basebuflen, tokdata, path, NULL) < 0) return NULL; /* CWE-59 fix: Use fopen_nofollow to prevent symlink attacks */ fp = fopen_nofollow(newbuf, mode); if (fp == NULL && errno == ELOOP) TRACE_ERROR("Refusing to follow symlink: %s\n", newbuf); return fp; } static int get_token_data_store_path(char *buf, size_t buflen, STDLL_TokData_t *tokdata, const char *path, const char *postfix) { if (ock_snprintf(buf, buflen, "%s/%s%s", tokdata->data_store, path, postfix != NULL ? postfix : "")) { TRACE_ERROR("buffer overflow for path %s", path); return -1; } return 0; } static FILE *open_token_data_store_path(char *buf, size_t buflen, STDLL_TokData_t *tokdata, const char *path, const char *mode) { FILE *fp; if (get_token_data_store_path(buf, buflen, tokdata, path, NULL) < 0) return NULL; /* CWE-59 fix: Use fopen_nofollow to prevent symlink attacks */ fp = fopen_nofollow(buf, mode); if (fp == NULL && errno == ELOOP) TRACE_ERROR("Refusing to follow symlink: %s\n", buf); return fp; } static FILE *open_token_data_store_path_new(char *newbuf, size_t newbuflen, char *basebuf, size_t basebuflen, STDLL_TokData_t *tokdata, const char *path, const char *mode) { FILE *fp; if (get_token_data_store_path(newbuf, newbuflen, tokdata, path, ".TMP") < 0) return NULL; if (get_token_data_store_path(basebuf, basebuflen, tokdata, path, NULL) < 0) return NULL; /* CWE-59 fix: Use fopen_nofollow to prevent symlink attacks */ fp = fopen_nofollow(newbuf, mode); if (fp == NULL && errno == ELOOP) TRACE_ERROR("Refusing to follow symlink: %s\n", newbuf); return fp; } static FILE *open_token_object_index(char *buf, size_t buflen, STDLL_TokData_t *tokdata, const char *mode) { return open_token_object_path(buf, buflen, tokdata, PK_LITE_OBJ_IDX, mode); } static FILE *open_token_nvdat(char *buf, size_t buflen, STDLL_TokData_t *tokdata, const char *mode) { FILE *fp; if (ock_snprintf(buf, buflen, "%s/" PK_LITE_NV, tokdata->data_store)) { TRACE_ERROR("NVDAT.TOK file name buffer overflow\n"); return NULL; } /* CWE-59 fix: Use fopen_nofollow to prevent symlink attacks */ fp = fopen_nofollow(buf, mode); if (fp == NULL && errno == ELOOP) TRACE_ERROR("Refusing to follow symlink: %s\n", buf); return fp; } static FILE *open_token_nvdat_new(char *newbuf, size_t newbuflen, char *basebuf, size_t basebuflen, STDLL_TokData_t *tokdata, const char *mode) { FILE *fp; if (ock_snprintf(newbuf, newbuflen, "%s/" PK_LITE_NV ".TMP", tokdata->data_store)) { TRACE_ERROR("NVDAT.TOK file name buffer overflow\n"); return NULL; } if (ock_snprintf(basebuf, basebuflen, "%s/" PK_LITE_NV, tokdata->data_store)) { TRACE_ERROR("NVDAT.TOK file name buffer overflow\n"); return NULL; } /* CWE-59 fix: Use fopen_nofollow to prevent symlink attacks */ fp = fopen_nofollow(newbuf, mode); if (fp == NULL && errno == ELOOP) TRACE_ERROR("Refusing to follow symlink: %s\n", newbuf); return fp; } static CK_RV close_token_file_new(FILE * fp, CK_RV rc, const char *newname, const char *basename) { if (fp != NULL) { fclose(fp); if (rc == CKR_OK) { /* Rename will replace already existing basename file */ if (rename(newname, basename) != 0) { TRACE_ERROR("rename(%s, %s): %s\n", newname, basename, strerror(errno)); rc = CKR_FUNCTION_FAILED; } } else { remove((newname)); } } return rc; } char *get_pk_dir(STDLL_TokData_t *tokdata, char *fname, size_t len) { int snres; struct passwd *pw = NULL; if (token_specific.data_store.per_user && (pw = getpwuid(geteuid())) != NULL) snres = ock_snprintf(fname, len, "%s/%s", tokdata->pk_dir, pw->pw_name); else snres = ock_snprintf(fname, len, "%s", tokdata->pk_dir); return snres != 0 ? NULL : fname; } CK_RV set_perm(int file, const char *group) { struct stat sb; struct group *grp; mode_t mode; if (group == NULL || group[0] == '\0') group = PKCS_GROUP; if (fstat(file, &sb) != 0) { TRACE_DEVEL("fstat failed: %s\n", strerror(errno)); return CKR_FUNCTION_FAILED; } grp = getgrnam(group); if (grp == NULL) { TRACE_DEVEL("getgrnam(%s) failed: %s\n", group, strerror(errno)); return CKR_FUNCTION_FAILED; } 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. * Only change the file mode if its not already as expected. */ if (S_ISDIR(sb.st_mode)) mode = S_IRUSR | S_IWUSR | S_IXUSR; else mode = S_IRUSR | S_IWUSR; if ((sb.st_mode & ~S_IFMT) != mode) { if (fchmod(file, mode) != 0) { TRACE_DEVEL("fchmod(rw-------) failed: %s\n", strerror(errno)); return CKR_FUNCTION_FAILED; } } } else { /* Set absolute permissions or rw-rw----, if not already as expected */ if (S_ISDIR(sb.st_mode)) mode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP; else mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; if ((sb.st_mode & ~S_IFMT) != mode) { if (fchmod(file, mode) != 0) { TRACE_DEVEL("fchmod(rw-rw----) failed: %s\n", strerror(errno)); return CKR_FUNCTION_FAILED; } } /* set ownership to pkcs11 group, if not already as expected */ if (sb.st_gid != grp->gr_gid) { if (fchown(file, -1, grp->gr_gid) != 0) { TRACE_DEVEL("fchown(-1, %s) failed: %s\n", group, strerror(errno)); return CKR_FUNCTION_FAILED; } } } return CKR_OK; } // // 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 fp = open_token_object_index(fname, sizeof(fname), tokdata, "r"); if (fp) { rc = set_perm(fileno(fp), tokdata->tokgroup); if (rc != CKR_OK) { fclose(fp); return rc; } 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_nofollow(fname, "a"); if (!fp) { if (errno == ELOOP) TRACE_ERROR("Refusing to follow symlink: %s\n", fname); else TRACE_ERROR("fopen(%s): %s\n", fname, strerror(errno)); return CKR_FUNCTION_FAILED; } rc = set_perm(fileno(fp), tokdata->tokgroup); if (rc != CKR_OK) { fclose(fp); return rc; } 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]; CK_RV rc; // 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 = open_token_object_index(objidx, sizeof(objidx), tokdata, "r"); fp2 = open_token_object_path(idxtmp, sizeof(idxtmp), tokdata, "IDX.TMP", "w"); if (!fp1 || !fp2) { if (fp1) fclose(fp1); if (fp2) fclose(fp2); TRACE_ERROR("fopen failed\n"); return CKR_FUNCTION_FAILED; } rc = set_perm(fileno(fp2), tokdata->tokgroup); if (rc != CKR_OK) { fclose(fp1); fclose(fp2); return rc; } 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); if (rename(idxtmp, objidx) != 0) { TRACE_ERROR("rename failed\n"); return CKR_FUNCTION_FAILED; } if (get_token_object_path(fname, sizeof(fname), tokdata, (char *)obj->name, NULL) < 0) TRACE_DEVEL("file name buffer overflow in obj unlink\n"); else 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; } CK_RV init_data_store(STDLL_TokData_t *tokdata, char *directory, char *data_store, size_t len) { char *pkdir; int pklen; struct stat statbuf; struct group *grp; const char *group; if (tokdata->pk_dir != NULL) { free(tokdata->pk_dir); tokdata->pk_dir = NULL; } if ((pkdir = secure_getenv("PKCS_APP_STORE")) != NULL) { pklen = strlen(pkdir) + 1024; tokdata->pk_dir = (char *) calloc(pklen, 1); if (!(tokdata->pk_dir)) return CKR_HOST_MEMORY; if (ock_snprintf(tokdata->pk_dir, pklen, "%s/%s", pkdir, SUB_DIR) != 0) return CKR_FUNCTION_FAILED; if (get_pk_dir(tokdata, data_store, len) == NULL) return CKR_FUNCTION_FAILED; goto check; } if (directory) { pklen = strlen(directory) + 1; tokdata->pk_dir = (char *) calloc(pklen, 1); if (!(tokdata->pk_dir)) return CKR_HOST_MEMORY; if (ock_snprintf(tokdata->pk_dir, pklen, "%s", directory) != 0) return CKR_FUNCTION_FAILED; } else { pklen = strlen(PK_DIR) + 1; tokdata->pk_dir = (char *) calloc(pklen, 1); if (!(tokdata->pk_dir)) return CKR_HOST_MEMORY; if (ock_snprintf(tokdata->pk_dir, pklen, "%s", PK_DIR) != 0) return CKR_FUNCTION_FAILED; } if (get_pk_dir(tokdata, data_store, len) == NULL) return CKR_FUNCTION_FAILED; check: group = tokdata->tokgroup; if (group == NULL || group[0] == '\0') group = PKCS_GROUP; grp = getgrnam(group); if (grp == NULL) { OCK_SYSLOG(LOG_ERR, "getgrname(%s): %s\n", group, strerror(errno)); TRACE_ERROR("getgrname(%s): %s\n", group, strerror(errno)); return CKR_FUNCTION_FAILED; } if (stat(tokdata->pk_dir, &statbuf) != 0) { OCK_SYSLOG(LOG_ERR, "Could not stat directory '%s': %s\n", tokdata->pk_dir, strerror(errno)); TRACE_ERROR("Could not stat directory '%s': %s\n", tokdata->pk_dir, strerror(errno)); return CKR_FUNCTION_FAILED; } if (statbuf.st_gid != grp->gr_gid) { OCK_SYSLOG(LOG_ERR, "Directory '%s' is not owned by token group '%s'\n", tokdata->pk_dir, group); TRACE_ERROR("Directory '%s' is not owned by token group '%s'\n", tokdata->pk_dir, group); return CKR_FUNCTION_FAILED; } return CKR_OK; } 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(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 CKR_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_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_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, CK_BBOOL mk_crypt) { #ifndef CLEARTEXT CK_RV rc = CKR_OK; CK_BYTE *initial_vector = NULL; initial_vector = duplicate_initial_vector(iv); if (initial_vector == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); return CKR_HOST_MEMORY; } switch (token_specific.data_store.encryption_algorithm) { case CKM_DES3_CBC: rc = 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 = CKR_MECHANISM_INVALID; } if (initial_vector) free(initial_vector); if (rc == CKR_OK && (tokdata->statistics->flags & STATISTICS_FLAG_COUNT_INTERNAL) != 0) { if (mk_crypt) tokdata->statistics->increment_func(tokdata->statistics, tokdata->slot_id, &tokdata->store_strength.mk_crypt, tokdata->store_strength.mk_strength); else tokdata->statistics->increment_func(tokdata->statistics, tokdata->slot_id, &tokdata->store_strength.wrap_crypt, tokdata->store_strength.wrap_strength); } return rc; #else memcpy(cipher, clear, clear_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, CK_BBOOL mk_crypt) { #ifndef CLEARTEXT CK_RV rc = CKR_OK; CK_BYTE *initial_vector = NULL; initial_vector = duplicate_initial_vector(iv); if (initial_vector == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); return CKR_HOST_MEMORY; } switch (token_specific.data_store.encryption_algorithm) { case CKM_DES3_CBC: rc = 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 = CKR_MECHANISM_INVALID; } if (initial_vector) free(initial_vector); if (rc == CKR_OK && (tokdata->statistics->flags & STATISTICS_FLAG_COUNT_INTERNAL) != 0) { if (mk_crypt) tokdata->statistics->increment_func(tokdata->statistics, tokdata->slot_id, &tokdata->store_strength.mk_crypt, tokdata->store_strength.mk_strength); else tokdata->statistics->increment_func(tokdata->statistics, tokdata->slot_id, &tokdata->store_strength.wrap_crypt, tokdata->store_strength.wrap_strength); } 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; } fp = open_token_nvdat(fname, sizeof(fname), tokdata, "r"); if (!fp) { /* Better error checking added */ if (errno == ENOENT) { init_token_data(tokdata, slot_id); fp = fopen_nofollow(fname, "r"); if (!fp) { // were really hosed here since the created // did not occur if (errno == ELOOP) TRACE_ERROR("Refusing to follow symlink: %s\n", fname); else 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; } } rc = set_perm(fileno(fp), tokdata->tokgroup); if (rc != CKR_OK) goto out_unlock; /* Load generic token data */ if (fread(&td, sizeof(TOKEN_DATA_OLD), 1, fp) != 1) { 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]; char basename[PATH_MAX]; rc = XProcLock(tokdata); if (rc != CKR_OK) { TRACE_ERROR("Failed to get Process Lock.\n"); goto out_nolock; } fp = open_token_nvdat_new(fname, sizeof(fname), basename, sizeof(basename), tokdata, "w"); if (!fp) { TRACE_ERROR("fopen(%s): %s\n", fname, strerror(errno)); rc = CKR_FUNCTION_FAILED; goto done; } rc = set_perm(fileno(fp), tokdata->tokgroup); if (rc != CKR_OK) goto done; /* 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: rc = close_token_file_new(fp, rc, fname, basename); 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]; char basename[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 <--+ // rc = compute_sha1(tokdata, obj_data, obj_data_len, hash_sha); if (rc != CKR_OK) goto error; // 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, CK_FALSE); if (rc != CKR_OK) { goto error; } fp = open_token_object_path_new(fname, sizeof(fname), basename, sizeof(basename), tokdata, (char *)obj->name, "w"); if (!fp) { TRACE_ERROR("fopen(%s): %s\n", fname, strerror(errno)); rc = CKR_FUNCTION_FAILED; goto error; } rc = set_perm(fileno(fp), tokdata->tokgroup); if (rc != CKR_OK) goto error; 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); rc = close_token_file_new(fp, rc, fname, basename); free(obj_data); free(clear); free(cipher); free(key); return rc; oom_error: rc = CKR_HOST_MEMORY; error: if (obj_data) free(obj_data); if (clear) free(clear); if (cipher) free(cipher); if (key) free(key); rc = close_token_file_new(fp, rc, fname, basename); 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; fp1 = open_token_object_index(iname, sizeof(iname), tokdata, "r"); if (!fp1) return CKR_OK; // no token objects while (fgets(tmp, 50, fp1)) { tmp[strlen(tmp) - 1] = 0; fp2 = open_token_object_path(fname, sizeof(fname), tokdata, tmp, "r"); if (!fp2) continue; if (fread(&size, sizeof(CK_ULONG_32), 1, fp2) != 1) { fclose(fp2); OCK_SYSLOG(LOG_ERR, "Cannot read size\n"); continue; } if (fread(&priv, sizeof(CK_BBOOL), 1, fp2) != 1) { fclose(fp2); OCK_SYSLOG(LOG_ERR, "Cannot read boolean\n"); continue; } if (priv == FALSE) { fclose(fp2); continue; } if (size <= sizeof(CK_ULONG_32) + sizeof(CK_BBOOL)) { fclose(fp2); OCK_SYSLOG(LOG_ERR, "Improper size of object %s (ignoring it)\n", fname); continue; } 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, fname); 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; struct stat sb; if ((rc = get_encryption_info(&key_len, &block_size)) != CKR_OK) goto done; master_key_len = key_len; 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); sprintf(fname, "%s/MK_SO", tokdata->data_store); if (stat(fname, &sb) != 0) { TRACE_ERROR("stat(%s): %s\n", fname, strerror(errno)); rc = CKR_FUNCTION_FAILED; goto done; } if ((CK_ULONG)sb.st_size > cipher_len && token_specific.secure_key_token && strcmp(token_specific.token_subdir, "ccatok") == 0) { /* * The CCA token used to have a secure master key length of 64, although * it uses clear keys for the master key in the meantime. The master key * length has an influence on the file size of the MK_SO and MK_USER * files when using the old pin encryption format. Use special handling * for such larger MK_SO files, and accept the larger length. Newly * written MK_SO files will use the clear key master key length, but we * need to be able to read larger files for backwards compatibility. */ master_key_len = 64; 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 = CKR_HOST_MEMORY; goto done; } // this file gets created on C_InitToken so we can assume that it always // exists // fp = open_token_data_store_path(fname, sizeof(fname), tokdata, "MK_SO", "r"); if (!fp) { rc = CKR_FUNCTION_FAILED; goto done; } rc = set_perm(fileno(fp), tokdata->tokgroup); if (rc != CKR_OK) goto done; 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, CK_TRUE); 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; struct stat sb; if ((rc = get_encryption_info(&key_len, &block_size)) != CKR_OK) goto done; master_key_len = key_len; 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); sprintf(fname, "%s/MK_USER", tokdata->data_store); if (stat(fname, &sb) != 0) { TRACE_ERROR("stat(%s): %s\n", fname, strerror(errno)); rc = CKR_FUNCTION_FAILED; goto done; } if ((CK_ULONG)sb.st_size > cipher_len && token_specific.secure_key_token && strcmp(token_specific.token_subdir, "ccatok") == 0) { /* * The CCA token used to have a secure master key length of 64, although * it uses clear keys for the master key in the meantime. The master key * length has an influence on the file size of the MK_SO and MK_USER * files when using the old pin encryption format. Use special handling * for such larger MK_USER files, and accept the larger length. Newly * written MK_USER files will use the clear key master key length, but * we need to be able to read larger files for backwards compatibility. */ master_key_len = 64; 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 = CKR_HOST_MEMORY; goto done; } // this file gets created on C_InitToken so we can assume that it always // exists // fp = open_token_data_store_path(fname, sizeof(fname), tokdata, "MK_USER", "r"); if (!fp) { rc = CKR_FUNCTION_FAILED; goto done; } rc = set_perm(fileno(fp), tokdata->tokgroup); if (rc != CKR_OK) goto done; 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, CK_TRUE); 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 block_size = 0L; CK_ULONG data_len = 0L; char fname[PATH_MAX]; char basename[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(&key_len, &block_size)) != CKR_OK) goto done; data_len = 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 = CKR_HOST_MEMORY; goto done; } // Copy data to buffer (key+hash) memcpy(clear, tokdata->master_key, key_len); if ((rc = compute_sha1(tokdata, tokdata->master_key, key_len, clear + 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, CK_TRUE); if (rc != CKR_OK) { goto done; } // write the file // // probably ought to ensure the permissions are correct // fp = open_token_data_store_path_new(fname, sizeof(fname), basename, sizeof(basename), tokdata, "MK_SO", "w"); if (!fp) { rc = CKR_FUNCTION_FAILED; goto done; } rc = set_perm(fileno(fp), tokdata->tokgroup); if (rc != CKR_OK) goto done; 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: rc = close_token_file_new(fp, rc, fname, basename); 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 block_size = 0L; CK_ULONG data_len = 0L; char fname[PATH_MAX]; char basename[PATH_MAX]; CK_RV rc; if ((rc = get_encryption_info(&key_len, &block_size)) != CKR_OK) goto done; data_len = 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 = CKR_HOST_MEMORY; goto done; } // Copy data to buffer (key+hash) memcpy(clear, tokdata->master_key, key_len); if ((rc = compute_sha1(tokdata, tokdata->master_key, key_len, clear + 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, CK_TRUE); if (rc != CKR_OK) { goto done; } // write the file // // probably ought to ensure the permissions are correct // fp = open_token_data_store_path_new(fname, sizeof(fname), basename, sizeof(basename), tokdata, "MK_USER", "w"); if (!fp) { rc = CKR_FUNCTION_FAILED; goto done; } rc = set_perm(fileno(fp), tokdata->tokgroup); if (rc != CKR_OK) goto done; 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: rc = close_token_file_new(fp, rc, fname, basename); 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; CK_BYTE *master_key = NULL; CK_BBOOL is_opaque = FALSE; TEMPLATE *tmpl = NULL; /* Skip it if master key is not needed. */ if (!token_specific.data_store.use_master_key) return CKR_OK; if (get_encryption_info(&key_len, NULL) != CKR_OK) return CKR_FUNCTION_FAILED; /* For secure key tokens, object encrypt/decrypt uses * software(openssl), not token. So generate masterkey via RNG. */ if (token_specific.secure_key_token) { rc = rng_generate(tokdata, key, key_len); if (rc == CKR_OK && (tokdata->statistics->flags & STATISTICS_FLAG_COUNT_INTERNAL) != 0) tokdata->statistics->increment_func(tokdata->statistics, tokdata->slot_id, &tokdata->store_strength.mk_keygen, tokdata->store_strength.mk_strength); return rc; } /* For clear key tokens, let token generate masterkey * since token will also encrypt/decrypt the objects. */ tmpl = (TEMPLATE *)calloc(1, sizeof(TEMPLATE)); if (tmpl == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); return CKR_HOST_MEMORY; } switch (token_specific.data_store.encryption_algorithm) { case CKM_DES3_CBC: rc = token_specific.t_des_key_gen(tokdata, tmpl, &master_key, &master_key_len, key_len, &is_opaque); break; case CKM_AES_CBC: rc = token_specific.t_aes_key_gen(tokdata, tmpl, &master_key, &master_key_len, key_len, &is_opaque); break; default: template_free(tmpl); return CKR_MECHANISM_INVALID; } template_free(tmpl); if (rc != CKR_OK) return rc; if (master_key_len != key_len) { TRACE_ERROR("Invalid master key size: %lu\n", master_key_len); free(master_key); return CKR_FUNCTION_FAILED; } memcpy(key, master_key, master_key_len); free(master_key); if ((tokdata->statistics->flags & STATISTICS_FLAG_COUNT_INTERNAL) != 0) tokdata->statistics->increment_func(tokdata->statistics, tokdata->slot_id, &tokdata->store_strength.mk_keygen, tokdata->store_strength.mk_strength); return CKR_OK; } CK_RV restore_private_token_object_old(STDLL_TokData_t *tokdata, CK_BYTE *data, CK_ULONG len, OBJECT *pObj, const char *fname) { CK_BYTE *clear = NULL; CK_BYTE *obj_data = NULL; CK_BYTE *ptr = NULL; CK_BYTE *key = NULL; CK_ULONG key_len = 0; 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 = CKR_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, CK_FALSE); 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_withSize(tokdata, obj_data, pObj, obj_data_len, fname); 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; fp = open_token_object_path(fname, sizeof(fname), tokdata, (char *)obj->name, "r"); if (!fp) { TRACE_ERROR("fopen(%s): %s\n", fname, strerror(errno)); rc = CKR_FUNCTION_FAILED; goto done; } rc = set_perm(fileno(fp), tokdata->tokgroup); if (rc != CKR_OK) goto done; if (fread(&size, sizeof(CK_ULONG_32), 1, fp) != 1) { OCK_SYSLOG(LOG_ERR, "Cannot read size\n"); rc = CKR_FUNCTION_FAILED; goto done; } if (fread(&priv, sizeof(CK_BBOOL), 1, fp) != 1) { OCK_SYSLOG(LOG_ERR, "Cannot read boolean\n"); rc = CKR_FUNCTION_FAILED; goto done; } if (size <= sizeof(CK_ULONG_32) + sizeof(CK_BBOOL)) { rc = CKR_FUNCTION_FAILED; OCK_SYSLOG(LOG_ERR, "Improper size of object %s (ignoring it)\n", fname); goto done; } size -= sizeof(CK_ULONG_32) + sizeof(CK_BBOOL); 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, fname); else rc = object_mgr_restore_obj_withSize(tokdata, buf, obj, size_64, fname); 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]; char basename[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; } fp = open_token_object_path_new(fname, sizeof(fname), basename, sizeof(basename), tokdata, (char *)obj->name, "w"); if (!fp) { TRACE_ERROR("fopen(%s): %s\n", fname, strerror(errno)); rc = CKR_FUNCTION_FAILED; goto error; } rc = set_perm(fileno(fp), tokdata->tokgroup); if (rc != CKR_OK) goto error; 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); rc = close_token_file_new(fp, rc, fname, basename); free(clear); return CKR_OK; error: if (clear) free(clear); rc = close_token_file_new(fp, rc, fname, basename); 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; fp1 = open_token_object_index(iname, sizeof(iname), tokdata, "r"); if (!fp1) return CKR_OK; // no token objects while (fgets(tmp, 50, fp1)) { tmp[strlen(tmp) - 1] = 0; fp2 = open_token_object_path(fname, sizeof(fname), tokdata, tmp, "r"); if (!fp2) continue; if (fread(&size, sizeof(CK_ULONG_32), 1, fp2) != 1) { fclose(fp2); OCK_SYSLOG(LOG_ERR, "Cannot read size\n"); continue; } if (fread(&priv, sizeof(CK_BBOOL), 1, fp2) != 1) { fclose(fp2); OCK_SYSLOG(LOG_ERR, "Cannot read boolean\n"); continue; } if (priv == TRUE) { fclose(fp2); continue; } if (size <= sizeof(CK_ULONG_32) + sizeof(CK_BBOOL)) { fclose(fp2); OCK_SYSLOG(LOG_ERR, "Improper size of object %s (ignoring it)\n", fname); continue; } 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, fname) != 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(STDLL_TokData_t *tokdata, 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 = CKR_HOST_MEMORY; goto done; } if (EVP_CipherInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL, -1) != 1 || EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 12, NULL) != 1 || EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, 1) != 1 || EVP_CipherUpdate(ctx, NULL, &outlen, aad, aadlen) != 1 || EVP_CipherUpdate(ctx, out, &outlen, in, inlen) != 1 || EVP_CipherFinal_ex(ctx, out + outlen, &outlen) != 1 || EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag) != 1) { TRACE_ERROR("%s\n", ock_err(ERR_GENERAL_ERROR)); rc = CKR_GENERAL_ERROR; goto done; } rc = CKR_OK; if ((tokdata->statistics->flags & STATISTICS_FLAG_COUNT_INTERNAL) != 0) tokdata->statistics->increment_func(tokdata->statistics, tokdata->slot_id, &tokdata->store_strength.mk_crypt, tokdata->store_strength.mk_strength); done: EVP_CIPHER_CTX_free(ctx); return rc; } static CK_RV aes_256_gcm_unseal(STDLL_TokData_t *tokdata, 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 = CKR_HOST_MEMORY; goto done; } if (EVP_CipherInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL, -1) != 1 || EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_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, &outlen) != 1) { TRACE_ERROR("%s\n", ock_err(ERR_GENERAL_ERROR)); rc = CKR_GENERAL_ERROR; goto done; } rc = CKR_OK; if ((tokdata->statistics->flags & STATISTICS_FLAG_COUNT_INTERNAL) != 0) tokdata->statistics->increment_func(tokdata->statistics, tokdata->slot_id, &tokdata->store_strength.mk_crypt, tokdata->store_strength.mk_strength); done: EVP_CIPHER_CTX_free(ctx); return rc; } static CK_RV aes_256_wrap(STDLL_TokData_t *tokdata, unsigned char out[40], const unsigned char in[32], const unsigned char kek[32]) { CK_RV rc; int outlen; unsigned char buffer[40 + EVP_MAX_BLOCK_LENGTH]; EVP_CIPHER_CTX *ctx = NULL; ctx = EVP_CIPHER_CTX_new(); if (ctx == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto done; } EVP_CIPHER_CTX_set_flags(ctx, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW); if (EVP_CipherInit_ex(ctx, EVP_aes_256_wrap(), NULL, kek, NULL, 1) != 1 || EVP_CipherUpdate(ctx, buffer, &outlen, in, 32) != 1 || EVP_CipherFinal_ex(ctx, buffer + outlen, &outlen) != 1) { TRACE_ERROR("%s\n", ock_err(ERR_GENERAL_ERROR)); rc = CKR_GENERAL_ERROR; goto done; } memcpy(out, buffer, 40); rc = CKR_OK; if ((tokdata->statistics->flags & STATISTICS_FLAG_COUNT_INTERNAL) != 0) tokdata->statistics->increment_func(tokdata->statistics, tokdata->slot_id, &tokdata->store_strength.wrap_crypt, tokdata->store_strength.wrap_strength); done: EVP_CIPHER_CTX_free(ctx); return rc; } static CK_RV aes_256_unwrap(STDLL_TokData_t *tokdata, unsigned char key[32], const unsigned char in[40], const unsigned char kek[32]) { CK_RV rc; int outlen; unsigned char buffer[32 + EVP_MAX_BLOCK_LENGTH]; EVP_CIPHER_CTX *ctx = NULL; ctx = EVP_CIPHER_CTX_new(); if (ctx == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto done; } EVP_CIPHER_CTX_set_flags(ctx, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW); if (EVP_CipherInit_ex(ctx, EVP_aes_256_wrap(), NULL, kek, NULL, 0) != 1 || EVP_CipherUpdate(ctx, buffer, &outlen, in, 40) != 1 || EVP_CipherFinal_ex(ctx, buffer + outlen, &outlen) != 1) { TRACE_ERROR("%s\n", ock_err(ERR_GENERAL_ERROR)); rc = CKR_GENERAL_ERROR; goto done; } memcpy(key, buffer, 32); rc = CKR_OK; if ((tokdata->statistics->flags & STATISTICS_FLAG_COUNT_INTERNAL) != 0) tokdata->statistics->increment_func(tokdata->statistics, tokdata->slot_id, &tokdata->store_strength.wrap_crypt, tokdata->store_strength.wrap_strength); done: EVP_CIPHER_CTX_free(ctx); return rc; } CK_RV generate_master_key(STDLL_TokData_t *tokdata, CK_BYTE *key) { CK_RV rc; if (tokdata->version < TOK_NEW_DATA_STORE) return generate_master_key_old(tokdata, key); /* generate a 256-bit AES key */ rc = rng_generate(tokdata, key, 32); if (rc == CKR_OK && (tokdata->statistics->flags & STATISTICS_FLAG_COUNT_INTERNAL) != 0) tokdata->statistics->increment_func(tokdata->statistics, tokdata->slot_id, &tokdata->store_strength.mk_keygen, tokdata->store_strength.mk_strength); return rc; } /** * 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]; char basename[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(tokdata, 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 // fp = open_token_data_store_path_new(fname, sizeof(fname), basename, sizeof(basename), tokdata, "MK_SO", "w"); if (!fp) { rc = CKR_FUNCTION_FAILED; goto done; } rc = set_perm(fileno(fp), tokdata->tokgroup); if (rc != CKR_OK) goto done; 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: rc = close_token_file_new(fp, rc, fname, basename); 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 // fp = open_token_data_store_path(fname, sizeof(fname), tokdata, "MK_SO", "r"); if (!fp) { rc = CKR_FUNCTION_FAILED; goto done; } rc = set_perm(fileno(fp), tokdata->tokgroup); if (rc != CKR_OK) goto done; 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, 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]; char basename[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(tokdata, 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 // fp = open_token_data_store_path_new(fname, sizeof(fname), basename, sizeof(basename), tokdata, "MK_USER", "w"); if (!fp) { rc = CKR_FUNCTION_FAILED; goto done; } rc = set_perm(fileno(fp), tokdata->tokgroup); if (rc != CKR_OK) goto done; 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: rc = close_token_file_new(fp, rc, fname, basename); 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 // fp = open_token_data_store_path(fname, sizeof(fname), tokdata, "MK_USER", "r"); if (!fp) { rc = CKR_FUNCTION_FAILED; goto done; } rc = set_perm(fileno(fp), tokdata->tokgroup); if (rc != CKR_OK) goto done; 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, 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]; char basename[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; } fp = open_token_nvdat_new(fname, sizeof(fname), basename, sizeof(basename), tokdata, "w"); if (!fp) { TRACE_ERROR("fopen(%s): %s\n", fname, strerror(errno)); rc = CKR_FUNCTION_FAILED; goto done; } rc = set_perm(fileno(fp), tokdata->tokgroup); if (rc != CKR_OK) goto done; /* 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: rc = close_token_file_new(fp, rc, fname, basename); 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; } fp = open_token_nvdat(fname, sizeof(fname), tokdata, "r"); if (!fp) { /* Better error checking added */ if (errno == ENOENT) { init_token_data(tokdata, slot_id); fp = fopen_nofollow(fname, "r"); if (!fp) { // were really hosed here since the created // did not occur if (errno == ELOOP) TRACE_ERROR("Refusing to follow symlink: %s\n", fname); else 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; } } rc = set_perm(fileno(fp), tokdata->tokgroup); if (rc != CKR_OK) goto out_unlock; /* Load generic token data */ if (fread(&td, sizeof(TOKEN_DATA), 1, fp) != 1) { 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 /** * 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 #define HEADER_COMMON_LEN 5 // // 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]; char basename[PATH_MAX]; struct stat sb; 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); 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 = open_token_object_path(fname, sizeof(fname), tokdata, (char *)obj->name, "r"); if (fp == NULL) { /* create new token object */ new = 1; } else { if (fstat(fileno(fp), &sb) != 0) { TRACE_ERROR("fstat(%s): %s\n", fname, strerror(errno)); rc = CKR_FUNCTION_FAILED; goto done; } /* New token objects files created by mkstemp have a size of zero */ if (sb.st_size == 0) { new = 1; fclose(fp); fp = NULL; goto do_work; } /* 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(tokdata, obj_key, obj_key_wrapped, tokdata->master_key); if (rc != CKR_OK) goto done; } } do_work: 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(tokdata, 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(tokdata, /* 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 = open_token_object_path_new(fname, sizeof(fname), basename, sizeof(basename), tokdata, (char *)obj->name, "w"); if (!fp) { TRACE_ERROR("fopen(%s): %s\n", fname, strerror(errno)); rc = CKR_FUNCTION_FAILED; goto done; } rc = set_perm(fileno(fp), tokdata->tokgroup); if (rc != CKR_OK) goto done; if (fwrite(data, total_len, 1, fp) != 1) { TRACE_ERROR("fwrite(%s): %s\n", fname, strerror(errno)); rc = CKR_FUNCTION_FAILED; goto done; } rc = CKR_OK; done: rc = close_token_file_new(fp, rc, fname, basename); 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); fp1 = open_token_object_index(iname, sizeof(iname), tokdata, "r"); if (!fp1) return CKR_OK; // no token objects while (fgets(tmp, 50, fp1)) { tmp[strlen(tmp) - 1] = 0; fp2 = open_token_object_path(fname, sizeof(fname), tokdata, tmp, "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) { free(buf); 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, fname); 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, const char *fname) { 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, fname); /* wrapped key */ memcpy(obj_key_wrapped, header + 8, 40); /* iv */ memcpy(obj_iv, header + 48, 12); rc = aes_256_unwrap(tokdata, 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(tokdata, 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_withSize(tokdata, buff, pObj, len, fname); 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; uint32_t ver; if (tokdata->version < TOK_NEW_DATA_STORE) return reload_token_object_old(tokdata, obj); fp = open_token_object_path(fname, sizeof(fname), tokdata, (char *)obj->name, "r"); if (!fp) { TRACE_ERROR("fopen(%s): %s\n", fname, strerror(errno)); rc = CKR_FUNCTION_FAILED; goto done; } rc = set_perm(fileno(fp), tokdata->tokgroup); if (rc != CKR_OK) goto done; if (fread(header, HEADER_COMMON_LEN, 1, fp) != 1) { OCK_SYSLOG(LOG_ERR, "Cannot read header\n"); rc = CKR_FUNCTION_FAILED; goto done; } memcpy(&ver, header, 4); memcpy(&priv, header + 4, 1); if (priv) { if (fread(header + HEADER_COMMON_LEN, HEADER_LEN - HEADER_COMMON_LEN, 1, fp) != 1) { OCK_SYSLOG(LOG_ERR, "Cannot read header\n"); rc = CKR_FUNCTION_FAILED; goto done; } memcpy(&len, header + 60, 4); } else { if (fread(header + HEADER_COMMON_LEN, PUB_HEADER_LEN - HEADER_COMMON_LEN, 1, fp) != 1) { OCK_SYSLOG(LOG_ERR, "Cannot read header\n"); rc = CKR_FUNCTION_FAILED; goto done; } memcpy(&len, header + 12, 4); } /* * In OCK 3.12 - 3.14 the version and size was not stored in BE. So if * version field is in platform endianness, keep size as is also. */ if (ver == TOK_NEW_DATA_STORE) size = len; else size = be32toh(len); buf = (CK_BYTE *) malloc(size); if (buf == NULL) { 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 (priv) { 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, fname); } else { rc = object_mgr_restore_obj_withSize(tokdata, buf, obj, size_64, fname); } done: if (fp) fclose(fp); if (buf) free(buf); return rc; } // // 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]; char basename[PATH_MAX]; CK_ULONG clear_len; CK_BBOOL flag = FALSE; CK_RV rc; CK_ULONG_32 len, be_len; unsigned char reserved[7] = {0}; uint32_t tmp; if (tokdata->version < TOK_NEW_DATA_STORE) return save_public_token_object_old(tokdata, obj); rc = object_flatten(obj, &clear, &clear_len); if (rc != CKR_OK) { goto done; } len = (CK_ULONG_32)clear_len; fp = open_token_object_path_new(fname, sizeof(fname), basename, sizeof(basename), tokdata, (char *)obj->name, "w"); if (!fp) { TRACE_ERROR("fopen(%s): %s\n", fname, strerror(errno)); rc = CKR_FUNCTION_FAILED; goto done; } tmp = htobe32(tokdata->version); be_len = htobe32(len); rc = set_perm(fileno(fp), tokdata->tokgroup); if (rc != CKR_OK) goto done; if (fwrite(&tmp, 4, 1, fp) != 1 || fwrite(&flag, 1, 1, fp) != 1 || fwrite(reserved, 7, 1, fp) != 1 || fwrite(&be_len, 4, 1, fp) != 1 || fwrite(clear, len, 1, fp) != 1) { rc = CKR_FUNCTION_FAILED; goto done; } rc = CKR_OK; done: rc = close_token_file_new(fp, rc, fname, basename); 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]; uint32_t ver; if (tokdata->version < TOK_NEW_DATA_STORE) return load_public_token_objects_old(tokdata); fp1 = open_token_object_index(iname, sizeof(iname), tokdata, "r"); if (!fp1) return CKR_OK; // no token objects while (fgets(tmp, 50, fp1)) { tmp[strlen(tmp) - 1] = 0; fp2 = open_token_object_path(fname, sizeof(fname), tokdata, tmp, "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(&ver, header, 4); memcpy(&priv, header + 4, 1); memcpy(&size, header + 12, 4); /* * In OCK 3.12 - 3.14 the version and size was not stored in BE. So if * version field is in platform endianness, keep size as is also */ if (ver != TOK_NEW_DATA_STORE) size = be32toh(size); if (priv == TRUE) { fclose(fp2); continue; } /* size can not be negative if treated as signed int */ if (size >= 0x80000000) { fclose(fp2); OCK_SYSLOG(LOG_ERR, "Size is invalid in header of token object %s " "(ignoring it)\n", fname); 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, fname) != CKR_OK) { OCK_SYSLOG(LOG_ERR, "Cannot restore token object %s " "(ignoring it)", fname); } free(buf); fclose(fp2); } fclose(fp1); return CKR_OK; } opencryptoki-opencryptoki-451d99c/usr/lib/common/mech_aes.c000066400000000000000000004544721520105705100241230ustar00rootroot00000000000000/* * 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, sess, 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, sess, 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, sess, 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, sess, 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; } if (in_data != NULL && in_data_len > 0) 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, sess, 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, sess, 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; } static CK_RV aes_xts_crypt(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, CK_BBOOL encrypt, ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len) { AES_XTS_CONTEXT *context; 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; } context = (AES_XTS_CONTEXT *)ctx->context; /* CKM_AES_XTS requires the input data to be at least one full block */ if (in_data_len < AES_BLOCK_SIZE) { 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_xts_crypt(tokdata, sess, in_data, in_data_len, out_data, out_data_len, ctx->mech.pParameter, key, TRUE, TRUE, context->iv, encrypt); done: object_put(tokdata, key, TRUE); key = NULL; return rc; } CK_RV aes_xts_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) { return aes_xts_crypt(tokdata, sess, length_only, TRUE, ctx, in_data, in_data_len, out_data, out_data_len); } CK_RV aes_xts_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) { return aes_xts_crypt(tokdata, sess, length_only, FALSE, ctx, in_data, in_data_len, out_data, out_data_len); } // // 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, sess, 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, sess, 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, sess, 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, sess, 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 && 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 { remain = (total % AES_BLOCK_SIZE); out_len = total - remain; // out_len is a multiple of AES_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, sess, 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 && 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 + 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, sess, 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; } } static CK_RV aes_xts_crypt_update(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, CK_BBOOL encrypt, ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len) { AES_XTS_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_XTS_CONTEXT *)ctx->context; total = (context->len + in_data_len); if (total < 2 * AES_BLOCK_SIZE) { if (length_only == FALSE && in_data_len > 0) { memcpy(context->data + context->len, in_data, in_data_len); context->len += in_data_len; } *out_data_len = 0; return CKR_OK; } /* We have at least 2 full blocks, keep at least one full block */ remain = AES_BLOCK_SIZE + (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) return CKR_BUFFER_TOO_SMALL; 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 (out_len < context->len) { rc = ckm_aes_xts_crypt(tokdata, sess, context->data, out_len, out_data, out_data_len, ctx->mech.pParameter, key, !context->initialized, FALSE, context->iv, encrypt); if (rc == CKR_OK) { TRACE_ERROR("ckm_aes_xts_crypt failed\n"); goto out; } memmove(context->data, context->data + out_len, context->len - out_len); context->len -= out_len; memcpy(context->data + context->len, in_data, in_data_len); context->len += in_data_len; context->initialized = TRUE; } else { clear = (CK_BYTE *) malloc(out_len); if (!clear) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto out; } memcpy(clear, context->data, context->len); memcpy(clear + context->len, in_data, out_len - context->len); rc = ckm_aes_xts_crypt(tokdata, sess, clear, out_len, out_data, out_data_len, ctx->mech.pParameter, key, !context->initialized, FALSE, context->iv, encrypt); if (rc == CKR_OK) { if (remain != 0) memcpy(context->data, in_data + (in_data_len - remain), remain); context->len = remain; context->initialized = TRUE; } else { TRACE_ERROR("ckm_aes_xts_crypt failed\n"); } free(clear); } out: object_put(tokdata, key, TRUE); key = NULL; return rc; } CK_RV aes_xts_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) { return aes_xts_crypt_update(tokdata, sess, length_only, TRUE, ctx, in_data, in_data_len, out_data, out_data_len); } CK_RV aes_xts_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) { return aes_xts_crypt_update(tokdata, sess, length_only, FALSE, ctx, in_data, in_data_len, out_data, out_data_len); } // // 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); UNUSED(length_only); if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } 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); UNUSED(length_only); if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } 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); UNUSED(length_only); if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } 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); UNUSED(length_only); if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } 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, sess, 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, sess, 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); UNUSED(length_only); if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } 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); UNUSED(length_only); if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } 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; } static CK_RV aes_xts_crypt_final(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, CK_BBOOL encrypt, ENCR_DECR_CONTEXT *ctx, CK_BYTE *out_data, CK_ULONG *out_data_len) { AES_XTS_CONTEXT *context = NULL; 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; } context = (AES_XTS_CONTEXT *)ctx->context; if (length_only) { *out_data_len = context->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; } rc = ckm_aes_xts_crypt(tokdata, sess, context->data, context->len, out_data, out_data_len, ctx->mech.pParameter, key, !context->initialized, TRUE, context->iv, encrypt); if (rc == CKR_OK) { *out_data_len = context->len; memset(context, 0, sizeof(*context)); } else { TRACE_ERROR("ckm_aes_xts_crypt failed\n"); } object_put(tokdata, key, TRUE); key = NULL; return CKR_OK; } CK_RV aes_xts_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) { return aes_xts_crypt_final(tokdata, sess, length_only, TRUE, ctx, out_data, out_data_len); } CK_RV aes_xts_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) { return aes_xts_crypt_final(tokdata, sess, length_only, FALSE, ctx, out_data, out_data_len); } 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; } 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; sign_mgr_cleanup(tokdata, sess, ctx); 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) { if (in_data_len > 0) 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; sign_mgr_cleanup(tokdata, sess, ctx); 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) { verify_mgr_cleanup(tokdata, sess, ctx); return CKR_OK; } verify_mgr_cleanup(tokdata, sess, ctx); 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) { if (in_data_len > 0) 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) { verify_mgr_cleanup(tokdata, sess, ctx); return CKR_OK; } verify_mgr_cleanup(tokdata, sess, ctx); return CKR_SIGNATURE_INVALID; } static void aes_cmac_cleanup(STDLL_TokData_t *tokdata, SESSION *sess, CK_BYTE *context, CK_ULONG context_len) { UNUSED(tokdata); UNUSED(sess); UNUSED(context_len); if (((AES_CMAC_CONTEXT *)context)->ctx != NULL) { token_specific.t_aes_cmac(tokdata, sess, (CK_BYTE *)"", 0, NULL, ((AES_CMAC_CONTEXT *)context)->iv, CK_FALSE, CK_TRUE, ((AES_CMAC_CONTEXT *)context)->ctx); ((AES_CMAC_CONTEXT *)context)->ctx = NULL; } free(context); } 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, sess, 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; } if (((AES_CMAC_CONTEXT *)ctx->context)->ctx != NULL) ctx->state_unsaveable = CK_TRUE; ctx->context_free_func = aes_cmac_cleanup; memcpy(out_data, ((AES_CMAC_CONTEXT *) ctx->context)->iv, mac_len); *out_data_len = mac_len; sign_mgr_cleanup(tokdata, sess, ctx); 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) { if (in_data_len > 0) 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, sess, 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; if (context->ctx != NULL) ctx->state_unsaveable = CK_TRUE; ctx->context_free_func = aes_cmac_cleanup; } 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, sess, 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; } if (context->ctx != NULL) ctx->state_unsaveable = CK_TRUE; ctx->context_free_func = aes_cmac_cleanup; memcpy(out_data, context->iv, mac_len); *out_data_len = mac_len; done: object_put(tokdata, key_obj, TRUE); key_obj = NULL; sign_mgr_cleanup(tokdata, sess, ctx); 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, sess, 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 (((AES_CMAC_CONTEXT *)ctx->context)->ctx != NULL) ctx->state_unsaveable = CK_TRUE; ctx->context_free_func = aes_cmac_cleanup; if (CRYPTO_memcmp(out_data, ((AES_CMAC_CONTEXT *) ctx->context)->iv, out_data_len) == 0) { verify_mgr_cleanup(tokdata, sess, ctx); return CKR_OK; } verify_mgr_cleanup(tokdata, sess, ctx); 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) { if (in_data_len > 0) 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, sess, 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; if (context->ctx != NULL) ctx->state_unsaveable = CK_TRUE; ctx->context_free_func = aes_cmac_cleanup; } 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, sess, context->data, context->len, key_obj, context->iv, !context->initialized, CK_TRUE, &context->ctx); object_put(tokdata, key_obj, TRUE); key_obj = NULL; if (context->ctx != NULL) ctx->state_unsaveable = CK_TRUE; ctx->context_free_func = aes_cmac_cleanup; if (rc != CKR_OK) { TRACE_DEVEL("Token specific aes mac failed.\n"); return rc; } if (CRYPTO_memcmp(signature, context->iv, signature_len) == 0) { verify_mgr_cleanup(tokdata, sess, ctx); return CKR_OK; } verify_mgr_cleanup(tokdata, sess, ctx); 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; remain = total % AES_BLOCK_SIZE; out_len = total - remain; if (length_only) { if (total < AES_BLOCK_SIZE) { *out_data_len = 0; return CKR_OK; } else { *out_data_len = out_len; TRACE_DEVEL("Length Only requested (%02ld bytes).\n", *out_data_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; } 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) { *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 */ aesgcm = (CK_GCM_PARAMS *) ctx->mech.pParameter; context = (AES_GCM_CONTEXT *) ctx->context; total = context->len + in_data_len; tag_data_len = (aesgcm->ulTagBits + 7) / 8; /* round to full byte */ remain = ((total - tag_data_len) % AES_BLOCK_SIZE) + tag_data_len; out_len = total - remain; if (length_only) { if (total < AES_BLOCK_SIZE + tag_data_len) { *out_data_len = 0; return CKR_OK; } else { *out_data_len = out_len; TRACE_DEVEL("Length Only requested (%02ld bytes).\n", *out_data_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; } 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) { *out_data_len = context->len; return CKR_OK; } if (*out_data_len < context->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, 0); if (rc != CKR_OK) TRACE_ERROR("Token specific AES GCM DecryptFinal failed: %02lx\n", rc); return rc; } CK_RV aes_gcm_dup_param(CK_GCM_PARAMS *from, CK_GCM_PARAMS *to) { if (from == NULL || to == NULL) return CKR_ARGUMENTS_BAD; to->pIv = NULL; to->ulIvLen = 0; to->ulIvBits = 0; if (from->ulIvLen != 0 && from->pIv != NULL) { to->pIv = malloc(from->ulIvLen); if (to->pIv == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); aes_gcm_free_param(to); return CKR_HOST_MEMORY; } memcpy(to->pIv, from->pIv, from->ulIvLen); to->ulIvLen = from->ulIvLen; to->ulIvBits = from->ulIvBits; } to->pAAD = NULL; to->ulAADLen = 0; if (from->ulAADLen != 0 && from->pAAD) { to->pAAD = malloc(from->ulAADLen); if (to->pAAD == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); aes_gcm_free_param(to); return CKR_HOST_MEMORY; } memcpy(to->pAAD, from->pAAD, from->ulAADLen); to->ulAADLen = from->ulAADLen; } return CKR_OK; } CK_RV aes_gcm_free_param(CK_GCM_PARAMS *params) { if (params == NULL) return CKR_ARGUMENTS_BAD; if (params->pIv != NULL) free(params->pIv); if (params->pAAD != NULL) free(params->pAAD); memset(params, 0, sizeof(*params)); return CKR_OK; } void aes_gcm_param_from_compat(const CK_GCM_PARAMS_COMPAT *from, CK_GCM_PARAMS *to) { to->pIv = from->pIv; to->ulIvLen = from->ulIvLen; to->ulIvBits = from->ulIvLen * 8; to->pAAD = from->pAAD; to->ulAADLen = from->ulAADLen; to->ulTagBits = from->ulTagBits; } // // mechanisms // // // CK_RV ckm_aes_key_gen(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_BBOOL xts) { 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_BYTE *aes_key = NULL; CK_ULONG rc; CK_ULONG key_size; CK_ULONG token_keysize; CK_BBOOL is_opaque = FALSE; rc = template_attribute_get_ulong(tmpl, CKA_VALUE_LEN, &key_size); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE_LEN for the key.\n"); return rc; } if (key_size != (AES_KEY_SIZE_128 * (xts ? 2 : 1)) && (xts || key_size != AES_KEY_SIZE_192) && key_size != (AES_KEY_SIZE_256 * (xts ? 2 : 1))) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); 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 (xts) rc = token_specific.t_aes_xts_key_gen(tokdata, tmpl, &aes_key, &token_keysize, key_size, &is_opaque); else rc = token_specific.t_aes_key_gen(tokdata, tmpl, &aes_key, &token_keysize, key_size, &is_opaque); if (rc != CKR_OK) goto err; /* For opaque keys put in CKA_IBM_OPAQUE and put dummy_key in CKA_VALUE. */ if (is_opaque) { 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); rc = template_update_attribute(tmpl, opaque_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); free(opaque_attr); goto err; } } else { if (token_keysize != key_size) { TRACE_ERROR("Invalid key size: %lu\n", token_keysize); rc = CKR_FUNCTION_FAILED; goto err; } } 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) { 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_opaque) memset(value_attr->pValue, 0, key_size); else memcpy(value_attr->pValue, aes_key, key_size); free(aes_key); aes_key = NULL; 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 = xts ? CKK_AES_XTS : 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; rc = template_update_attribute(tmpl, value_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto err; } value_attr = NULL; rc = template_update_attribute(tmpl, key_type_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto err; } key_type_attr = NULL; rc = template_update_attribute(tmpl, class_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto err; } class_attr = NULL; rc = template_update_attribute(tmpl, local_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto err; } local_attr = NULL; return CKR_OK; err: if (aes_key) free(aes_key); 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); return rc; } // // CK_RV ckm_aes_ecb_encrypt(STDLL_TokData_t *tokdata, SESSION *sess, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, 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, sess, 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, SESSION *sess, 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, sess, 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, SESSION *sess, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, CK_BYTE *init_v, OBJECT *key) { CK_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, sess, 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, SESSION *sess, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, CK_BYTE *init_v, OBJECT *key) { CK_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, sess, 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_ULONG block_size, CK_BYTE **data, CK_ULONG *data_len) { CK_BYTE *ptr = NULL; CK_ULONG len1, len2; UNUSED(tokdata); len1 = *data_len; // if the input key data isn't a multiple of the blocksize, // we pad with NULLs to the next blocksize multiple. // if (len1 % block_size != 0) { len2 = block_size * ((len1 / 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; } else { *data_len = len2; } } return CKR_OK; } CK_RV ckm_aes_xts_crypt(STDLL_TokData_t *tokdata, SESSION *sess, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, CK_BYTE *tweak, OBJECT *key, CK_BBOOL initial, CK_BBOOL final, CK_BYTE *iv, CK_BBOOL encrypt) { CK_ULONG rc; if (!in_data || !out_data || !tweak || !iv || !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_xts == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); return CKR_MECHANISM_INVALID; } rc = token_specific.t_aes_xts(tokdata, sess, in_data, in_data_len, out_data, out_data_len, key, tweak, encrypt, initial, final, iv); if (rc != CKR_OK) TRACE_DEVEL("Token specific aes xts encrypt failed.\n"); return rc; } CK_RV aes_xts_cipher(CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, CK_BYTE *tweak, CK_BOOL encrypt, CK_BBOOL initial, CK_BBOOL final, CK_BYTE* iv, CK_RV (*iv_from_tweak)(CK_BYTE *tweak, CK_BYTE* iv, void * cb_data), CK_RV (*cipher_blocks)(CK_BYTE *in, CK_BYTE *out, CK_ULONG len, CK_BYTE *iv, void * cb_data), void *cb_data) { unsigned char partial[AES_BLOCK_SIZE]; unsigned char iv_prev[AES_INIT_VECTOR_SIZE] = { 0 }; CK_ULONG len, rest, bytes_processed; CK_RV rc; /* Full block size unless final call */ if (!final && (in_data_len % AES_BLOCK_SIZE) != 0) return CKR_DATA_LEN_RANGE; /* Final block must be at least one full block */ if (final && in_data_len < AES_BLOCK_SIZE) return CKR_DATA_LEN_RANGE; if (out_data == NULL) { *out_data_len = in_data_len; return CKR_OK; } if (*out_data_len < in_data_len) return CKR_BUFFER_TOO_SMALL; /* Calculate IV from tweak if initial call, otherwise IV is already set */ if (initial) { rc = iv_from_tweak(tweak, iv, cb_data); if (rc != CKR_OK) { TRACE_ERROR("iv_from_tweak callback failed\n"); return rc; } } rest = in_data_len % AES_BLOCK_SIZE; len = in_data_len - rest; bytes_processed = 0; /* * It was checked above that we have at least one full block if we are in * the final call. */ if (!encrypt && final) len -= AES_BLOCK_SIZE; /* process full blocks */ if (len > 0) { rc = cipher_blocks(in_data, out_data, len, iv, cb_data); if (rc != CKR_OK) { TRACE_ERROR("cipher_blocks callback failed\n"); return rc; } in_data += len; in_data_len -= len; out_data += len; bytes_processed = len; } if (!encrypt && final) { /* Remember IV of block n-1 */ memcpy(iv_prev, iv, AES_BLOCK_SIZE); rc = cipher_blocks(in_data, out_data, AES_BLOCK_SIZE, iv, cb_data); if (rc != CKR_OK) { TRACE_ERROR("cipher_blocks callback failed\n"); return rc; } in_data += AES_BLOCK_SIZE; in_data_len -= AES_BLOCK_SIZE; out_data += AES_BLOCK_SIZE; bytes_processed += AES_BLOCK_SIZE; } /* Partial block? Only possible for final call */ if (final && in_data_len > 0) { /* * It was checked above that we had at least one previous * block if we are in the final call, thus * 'out_data - AES_BLOCK_SIZE' or 'in_data - AES_BLOCK_SIZE' is OK. */ if (!encrypt) { /* * For decrypt: The last complete block uses the * IV from n-1, and the very last incomplete block * uses the IV from n. */ rc = cipher_blocks(in_data - AES_BLOCK_SIZE, out_data - AES_BLOCK_SIZE, AES_BLOCK_SIZE, iv, cb_data); if (rc != CKR_OK) { TRACE_ERROR("cipher_blocks callback failed\n"); return rc; } /* Restore IV from block n-1 */ memcpy(iv, iv_prev, AES_BLOCK_SIZE); } /* Steal ciphertext to complete the block */ memcpy(partial, in_data, in_data_len); memcpy(out_data, out_data - AES_BLOCK_SIZE, in_data_len); memcpy(partial + in_data_len, out_data - AES_BLOCK_SIZE + in_data_len, AES_BLOCK_SIZE - in_data_len); bytes_processed += in_data_len; rc = cipher_blocks(partial, out_data - AES_BLOCK_SIZE, AES_BLOCK_SIZE, iv, cb_data); if (rc != CKR_OK) { TRACE_ERROR("cipher_blocks callback failed\n"); return rc; } } *out_data_len = bytes_processed; return CKR_OK; } /* * The implementation of the AESKW functions is copied from OpenSSL's source * file crypto/modes/wrap128.c and is slightly modified to fit to the * OpenCryptoki environment. * * The OpenSSL code is licensed under the Apache License 2.0. * You can obtain a copy in the file LICENSE in the OpenSSL source * distribution or at https://www.openssl.org/source/license.html * * Changes include: * - Different variable, function and parameter names. * - Use of token specific AES ECB as block function. * - Different return codes. */ /* RFC 3394 section 2.2.3.1 Default Initial Value */ static const CK_BYTE aeskw_default_iv[AES_KEY_WRAP_IV_SIZE] = { 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, }; /* RFC 5649 section 3 Alternative Initial Value 32-bit constant */ static const CK_BYTE aeskw_default_aiv[AES_KEY_WRAP_KWP_IV_SIZE] = { 0xA6, 0x59, 0x59, 0xA6 }; /* * Wrapping according to RFC 3394 section 2.2.1. * Input and output buffers can overlap. */ static CK_RV aeskw_wrap(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, const CK_BYTE *iv) { CK_BYTE *A, B[AES_BLOCK_SIZE], C[AES_BLOCK_SIZE], *R; CK_ULONG i, j, t, l; CK_RV rc; if (in_data_len % AES_KEY_WRAP_BLOCK_SIZE != 0 || in_data_len < 2 * AES_KEY_WRAP_BLOCK_SIZE || in_data_len > UINT32_MAX) { TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); return CKR_DATA_LEN_RANGE; } if (*out_data_len < in_data_len + AES_KEY_WRAP_BLOCK_SIZE) { TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); return CKR_BUFFER_TOO_SMALL; } A = B; t = 1; memmove(out_data + AES_KEY_WRAP_BLOCK_SIZE, in_data, in_data_len); if (iv == NULL) iv = aeskw_default_iv; memcpy(A, iv, AES_KEY_WRAP_IV_SIZE); for (j = 0; j < 6; j++) { R = out_data + AES_KEY_WRAP_BLOCK_SIZE; for (i = 0; i < in_data_len; i += AES_KEY_WRAP_BLOCK_SIZE, t++, R += AES_KEY_WRAP_BLOCK_SIZE) { memcpy(B + AES_KEY_WRAP_BLOCK_SIZE, R, AES_KEY_WRAP_BLOCK_SIZE); l = AES_BLOCK_SIZE; rc = token_specific.t_aes_ecb(tokdata, sess, B, AES_BLOCK_SIZE, C, &l, key, 1); if (rc != CKR_OK) return rc; memcpy(B, C, AES_BLOCK_SIZE); A[7] ^= (CK_BYTE)(t & 0xff); if (t > 0xff) { A[6] ^= (CK_BYTE)((t >> 8) & 0xff); A[5] ^= (CK_BYTE)((t >> 16) & 0xff); A[4] ^= (CK_BYTE)((t >> 24) & 0xff); } memcpy(R, B + AES_KEY_WRAP_BLOCK_SIZE, AES_KEY_WRAP_BLOCK_SIZE); } } memcpy(out_data, A, AES_KEY_WRAP_BLOCK_SIZE); *out_data_len = in_data_len + AES_KEY_WRAP_BLOCK_SIZE; return CKR_OK; } /* * Unwrapping according to RFC 3394 section 2.2.2 steps 1-2. * Input and output buffers can overlap. * The IV check (step 3) is responsibility of the caller. */ static CK_RV aeskw_unwrap_raw(STDLL_TokData_t *tokdata, SESSION *sess, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, OBJECT *key, CK_BYTE *iv) { CK_BYTE *A, B[AES_BLOCK_SIZE], C[AES_BLOCK_SIZE], *R; CK_ULONG i, j, t, l; CK_RV rc; if (in_data_len % AES_KEY_WRAP_BLOCK_SIZE != 0 || in_data_len < 3 * AES_KEY_WRAP_BLOCK_SIZE || in_data_len > UINT32_MAX) { TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); return CKR_DATA_LEN_RANGE; } if (*out_data_len < in_data_len - AES_KEY_WRAP_BLOCK_SIZE) { TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); return CKR_BUFFER_TOO_SMALL; } in_data_len -= AES_KEY_WRAP_BLOCK_SIZE; A = B; t = 6 * (in_data_len / AES_KEY_WRAP_BLOCK_SIZE); memcpy(A, in_data, AES_KEY_WRAP_BLOCK_SIZE); memmove(out_data, in_data + AES_KEY_WRAP_BLOCK_SIZE, in_data_len); for (j = 0; j < 6; j++) { R = out_data + in_data_len - AES_KEY_WRAP_BLOCK_SIZE; for (i = 0; i < in_data_len; i += AES_KEY_WRAP_BLOCK_SIZE, t--, R -= AES_KEY_WRAP_BLOCK_SIZE) { A[7] ^= (unsigned char)(t & 0xff); if (t > 0xff) { A[6] ^= (unsigned char)((t >> 8) & 0xff); A[5] ^= (unsigned char)((t >> 16) & 0xff); A[4] ^= (unsigned char)((t >> 24) & 0xff); } memcpy(B + AES_KEY_WRAP_BLOCK_SIZE, R, AES_KEY_WRAP_BLOCK_SIZE); l = AES_BLOCK_SIZE; rc = token_specific.t_aes_ecb(tokdata, sess, B, AES_BLOCK_SIZE, C, &l, key, 0); if (rc != CKR_OK) return rc; memcpy(B, C, AES_BLOCK_SIZE); memcpy(R, B + AES_KEY_WRAP_BLOCK_SIZE, AES_KEY_WRAP_BLOCK_SIZE); } } memcpy(iv, A, AES_KEY_WRAP_BLOCK_SIZE); *out_data_len = in_data_len; return CKR_OK; } /* * Unwrapping according to RFC 3394 section 2.2.2, including the IV check. * Input and output buffers can overlap. * The first block of plaintext has to match the supplied IV, otherwise an * error is returned. */ static CK_RV aeskw_unwrap(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, const CK_BYTE *iv) { CK_RV rc; CK_BYTE ret_iv[AES_KEY_WRAP_IV_SIZE]; rc = aeskw_unwrap_raw(tokdata, sess, in_data, in_data_len, out_data, out_data_len, key, ret_iv); if (rc != CKR_OK) return rc; if (iv == NULL) iv = aeskw_default_iv; if (memcmp(ret_iv, iv, AES_KEY_WRAP_IV_SIZE) != 0) { OPENSSL_cleanse(out_data, *out_data_len); return CKR_ENCRYPTED_DATA_INVALID; } return CKR_OK; } /* * Wrapping according to RFC 5649 section 4.1. * Input and output buffers can overlap. */ static CK_RV aeskw_wrap_pad(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, const CK_BYTE *iv) { CK_ULONG blocks_padded = (in_data_len + 7) / 8; CK_ULONG padded_len = blocks_padded * 8; CK_ULONG padding_len = padded_len - in_data_len; CK_BYTE aiv[AES_KEY_WRAP_IV_SIZE]; CK_BYTE buff[AES_BLOCK_SIZE]; CK_RV rc; if (in_data_len == 0 || in_data_len > UINT32_MAX) { TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); return CKR_DATA_LEN_RANGE; } if (*out_data_len < padded_len + AES_KEY_WRAP_BLOCK_SIZE) { TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); return CKR_BUFFER_TOO_SMALL; } if (iv == NULL) memcpy(aiv, aeskw_default_aiv, AES_KEY_WRAP_KWP_IV_SIZE); else memcpy(aiv, iv, AES_KEY_WRAP_KWP_IV_SIZE); aiv[4] = (in_data_len >> 24) & 0xFF; aiv[5] = (in_data_len >> 16) & 0xFF; aiv[6] = (in_data_len >> 8) & 0xFF; aiv[7] = in_data_len & 0xFF; /* * If length of plain text is not a multiple of 8, pad the plain text octet * string on the right with octets of zeros, where final length is the * smallest multiple of 8 that is greater than length of plain text. * If length of plain text is a multiple of 8, then there is no padding. */ if (padded_len == AES_KEY_WRAP_BLOCK_SIZE) { /* * Section 4.1 - special case in step 2: If the padded plaintext * contains exactly eight octets, then prepend the AIV and encrypt * the resulting 128-bit block using AES in ECB mode. */ if (in_data_len > AES_KEY_WRAP_BLOCK_SIZE) { TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); return CKR_DATA_LEN_RANGE; } memmove(buff + AES_KEY_WRAP_BLOCK_SIZE, in_data, in_data_len); memcpy(buff, aiv, AES_KEY_WRAP_IV_SIZE); memset(buff + AES_KEY_WRAP_IV_SIZE + in_data_len, 0, padding_len); rc = token_specific.t_aes_ecb(tokdata, sess, buff, AES_BLOCK_SIZE, out_data, out_data_len, key, 1); } else { memmove(out_data, in_data, in_data_len); memset(out_data + in_data_len, 0, padding_len); rc = aeskw_wrap(tokdata, sess, out_data, padded_len, out_data, out_data_len, key, aiv); } return rc; } /* * Unwrapping according to RFC 5649 section 4.2. * Input and output buffers can overlap. */ static CK_RV aeskw_unwrap_pad(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, const CK_BYTE *iv) { CK_ULONG n = in_data_len / AES_KEY_WRAP_BLOCK_SIZE - 1; CK_ULONG padded_len, padding_len, ptext_len, l; CK_BYTE aiv[AES_KEY_WRAP_IV_SIZE]; CK_BYTE buff[AES_BLOCK_SIZE]; static const CK_BYTE zeros[AES_KEY_WRAP_BLOCK_SIZE] = { 0x0 }; const CK_BYTE *exp_iv = iv; CK_RV rc; if (in_data_len % AES_KEY_WRAP_BLOCK_SIZE != 0 || in_data_len < 2 * AES_KEY_WRAP_BLOCK_SIZE || in_data_len > UINT32_MAX) { TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); return CKR_DATA_LEN_RANGE; } if (*out_data_len < in_data_len - AES_KEY_WRAP_BLOCK_SIZE) { TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); return CKR_BUFFER_TOO_SMALL; } if (in_data_len == 16) { /* * Section 4.2 - special case in step 1: When n=1, the ciphertext * contains exactly two 64-bit blocks and they are decrypted as a * single AES block using AES in ECB mode: AIV | P[1] = DEC(K, C[0] | * C[1]) */ l = AES_BLOCK_SIZE; rc = token_specific.t_aes_ecb(tokdata, sess, in_data, AES_BLOCK_SIZE, buff, &l, key, 0); if (rc != CKR_OK) return rc; memcpy(aiv, buff, AES_KEY_WRAP_IV_SIZE); /* Remove AIV */ memcpy(out_data, buff + AES_KEY_WRAP_IV_SIZE, AES_KEY_WRAP_BLOCK_SIZE); padded_len = AES_KEY_WRAP_BLOCK_SIZE; OPENSSL_cleanse(buff, sizeof(buff)); } else { padded_len = in_data_len - AES_KEY_WRAP_BLOCK_SIZE; rc = aeskw_unwrap_raw(tokdata, sess, in_data, in_data_len, out_data, out_data_len, key, aiv); if (rc != CKR_OK) return rc; if (padded_len != *out_data_len) { OPENSSL_cleanse(out_data, *out_data_len); return CKR_ENCRYPTED_DATA_INVALID; } } /* * Section 3: AIV checks: Check that MSB(32,A) = A65959A6. Optionally a * user-supplied value can be used (even if standard doesn't mention * this). */ if (exp_iv == NULL) exp_iv = aeskw_default_aiv; if (memcmp(aiv, exp_iv, AES_KEY_WRAP_KWP_IV_SIZE) != 0) { OPENSSL_cleanse(out_data, *out_data_len); return CKR_ENCRYPTED_DATA_INVALID; } /* * Check that 8*(n-1) < LSB(32,AIV) <= 8*n. If so, let ptext_len = * LSB(32,AIV). */ ptext_len = ((unsigned int)aiv[4] << 24) | ((unsigned int)aiv[5] << 16) | ((unsigned int)aiv[6] << 8) | (unsigned int)aiv[7]; if (AES_KEY_WRAP_BLOCK_SIZE * (n - 1) >= ptext_len || ptext_len > AES_KEY_WRAP_BLOCK_SIZE * n) { OPENSSL_cleanse(out_data, *out_data_len); return CKR_ENCRYPTED_DATA_INVALID; } /* * Check that the rightmost padding_len octets of the output data are * zero. */ padding_len = padded_len - ptext_len; if (memcmp(out_data + ptext_len, zeros, padding_len) != 0) { OPENSSL_cleanse(out_data, *out_data_len); return CKR_ENCRYPTED_DATA_INVALID; } /* Section 4.2 step 3: Remove padding */ *out_data_len = ptext_len; return CKR_OK; } static CK_RV ckm_aes_key_wrap(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, const CK_BYTE *iv, CK_ULONG iv_len, CK_BBOOL encrypt, CK_BBOOL pad) { CK_RV rc; if (token_specific.t_aes_ecb == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); return CKR_MECHANISM_INVALID; } if (pad) { if (iv != NULL && iv_len != AES_KEY_WRAP_KWP_IV_SIZE) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); return CKR_MECHANISM_PARAM_INVALID; } if (encrypt) rc = aeskw_wrap_pad(tokdata, sess, in_data, in_data_len, out_data, out_data_len, key, iv); else rc = aeskw_unwrap_pad(tokdata, sess, in_data, in_data_len, out_data, out_data_len, key, iv); } else { if (iv != NULL && iv_len != AES_KEY_WRAP_IV_SIZE) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); return CKR_MECHANISM_PARAM_INVALID; } if (encrypt) rc = aeskw_wrap(tokdata, sess, in_data, in_data_len, out_data, out_data_len, key, iv); else rc = aeskw_unwrap(tokdata, sess, in_data, in_data_len, out_data, out_data_len, key, iv); } return rc; } CK_RV aes_key_wrap_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_BBOOL pkcs7_pad = FALSE, aeskw_pad = FALSE; CK_ULONG padded_len = 0, out_len, in_len = in_data_len; CK_BYTE *pad_buffer = NULL, *in = in_data; CK_RV rc; if (sess == NULL || ctx == NULL || out_data_len == NULL) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } switch (ctx->mech.mechanism) { case CKM_AES_KEY_WRAP: padded_len = in_data_len; /* must be multiple of 8 bytes */ break; case CKM_AES_KEY_WRAP_PAD: case CKM_AES_KEY_WRAP_PKCS7: pkcs7_pad = TRUE; padded_len = AES_BLOCK_SIZE * ((in_data_len / AES_BLOCK_SIZE) + 1); break; case CKM_AES_KEY_WRAP_KWP: aeskw_pad = TRUE; if (in_data_len % AES_KEY_WRAP_BLOCK_SIZE != 0) padded_len = AES_KEY_WRAP_BLOCK_SIZE - (in_data_len % AES_KEY_WRAP_BLOCK_SIZE); padded_len += in_data_len; break; default: return CKR_MECHANISM_INVALID; } out_len = padded_len + AES_KEY_WRAP_BLOCK_SIZE; /* * If no padding, a multiple of the AESKW block size is required, at at * least 2 blocks. */ if (pkcs7_pad == FALSE && aeskw_pad == FALSE && (in_data_len % AES_KEY_WRAP_BLOCK_SIZE != 0 || in_data_len < 2 * AES_KEY_WRAP_BLOCK_SIZE)) { TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); return CKR_DATA_LEN_RANGE; } if (length_only == TRUE) { *out_data_len = out_len; return CKR_OK; } if (*out_data_len < out_len) { *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, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to find specified object.\n"); return rc; } if (pkcs7_pad == TRUE) { pad_buffer = (CK_BYTE *)malloc(padded_len); if (pad_buffer == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto done; } if (in_data != NULL && in_data_len > 0) memcpy(pad_buffer, in_data, in_data_len); rc = add_pkcs_padding(pad_buffer + in_data_len, AES_BLOCK_SIZE, in_data_len, padded_len); if (rc != CKR_OK) { TRACE_ERROR("add_pkcs_padding failed.\n"); goto done; } in = pad_buffer; in_len = padded_len; } if (token_specific.t_aes_key_wrap != NULL) { rc = token_specific.t_aes_key_wrap(tokdata, sess, in, in_len, out_data, out_data_len, key, ctx->mech.pParameter, ctx->mech.ulParameterLen, TRUE, aeskw_pad); if (rc != CKR_OK) TRACE_DEVEL("Token specific aes key wrap encrypt failed.\n"); goto done; } /* No token specific AES key wrap function, implement via AES ECB calls */ rc = ckm_aes_key_wrap(tokdata, sess, in, in_len, out_data, out_data_len, key, ctx->mech.pParameter, ctx->mech.ulParameterLen, TRUE, aeskw_pad); if (rc != CKR_OK) TRACE_DEVEL("ckm_aes_key_wrap encrypt failed.\n"); done: object_put(tokdata, key, TRUE); key = NULL; if (pad_buffer) { OPENSSL_cleanse(pad_buffer, padded_len); free(pad_buffer); } return rc; } CK_RV aes_key_wrap_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_BBOOL pkcs7_pad = FALSE, aeskw_pad = FALSE; CK_ULONG unpadded_len = 0, out_len; CK_RV rc; if (sess == NULL || ctx == NULL || out_data_len == NULL) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } switch (ctx->mech.mechanism) { case CKM_AES_KEY_WRAP: break; case CKM_AES_KEY_WRAP_PAD: case CKM_AES_KEY_WRAP_PKCS7: pkcs7_pad = TRUE; break; case CKM_AES_KEY_WRAP_KWP: aeskw_pad = TRUE; break; default: return CKR_MECHANISM_INVALID; } if (in_data_len % AES_KEY_WRAP_BLOCK_SIZE != 0 || in_data_len < AES_KEY_WRAP_BLOCK_SIZE) { TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); return CKR_DATA_LEN_RANGE; } out_len = in_data_len - AES_KEY_WRAP_BLOCK_SIZE; if (length_only == TRUE) { *out_data_len = out_len; return CKR_OK; } if (*out_data_len < out_len) { *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, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to find specified object.\n"); return rc; } if (token_specific.t_aes_key_wrap != NULL) { rc = token_specific.t_aes_key_wrap(tokdata, sess, in_data, in_data_len, out_data, out_data_len, key, ctx->mech.pParameter, ctx->mech.ulParameterLen, FALSE, aeskw_pad); if (rc != CKR_OK) TRACE_DEVEL("Token specific aes key wrap encrypt failed.\n"); goto done; } /* No token specific AES key wrap function, implement via AES ECB calls */ rc = ckm_aes_key_wrap(tokdata, sess, in_data, in_data_len, out_data, out_data_len, key, ctx->mech.pParameter, ctx->mech.ulParameterLen, FALSE, aeskw_pad); if (rc != CKR_OK) TRACE_DEVEL("ckm_aes_key_wrap encrypt failed.\n"); done: if (rc == CKR_OK && pkcs7_pad == TRUE && out_data != NULL && *out_data_len > 0) { rc = strip_pkcs_padding(out_data, *out_data_len, &unpadded_len); if (rc != CKR_OK) { TRACE_ERROR("strip_pkcs_padding failed.\n"); goto done; } if (unpadded_len < *out_data_len) memset(out_data + unpadded_len, 0, *out_data_len - unpadded_len); *out_data_len = unpadded_len; } object_put(tokdata, key, TRUE); key = NULL; return rc; } opencryptoki-opencryptoki-451d99c/usr/lib/common/mech_des.c000066400000000000000000001266011520105705100241140ustar00rootroot00000000000000/* * 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; } if (in_data != NULL && in_data_len > 0) 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 && 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 + 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 && 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 + 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); UNUSED(length_only); if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } 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); UNUSED(length_only); if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } 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); UNUSED(length_only); if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } 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); UNUSED(length_only); if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } 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_ULONG rc; CK_ULONG keysize = 0; CK_BBOOL is_opaque = FALSE; if (token_specific.t_des_key_gen == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); return CKR_MECHANISM_INVALID; } rc = token_specific.t_des_key_gen(tokdata, tmpl, &des_key, &keysize, DES_KEY_SIZE, &is_opaque); if (rc != CKR_OK) goto err; /* For opaque keys put in CKA_IBM_OPAQUE and put dummy_key in CKA_VALUE. */ if (is_opaque) { 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); rc = template_update_attribute(tmpl, opaque_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); free(opaque_attr); goto err; } } else { if (keysize != DES_KEY_SIZE) { TRACE_ERROR("Invalid key size: %lu\n", keysize); rc = CKR_FUNCTION_FAILED; goto err; } } 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) { 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_opaque) memset(value_attr->pValue, 0, DES_KEY_SIZE); else memcpy(value_attr->pValue, des_key, DES_KEY_SIZE); free(des_key); des_key = NULL; 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; rc = template_update_attribute(tmpl, value_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto err; } value_attr = NULL; rc = template_update_attribute(tmpl, key_type_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto err; } key_type_attr = NULL; rc = template_update_attribute(tmpl, class_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto err; } class_attr = NULL; rc = template_update_attribute(tmpl, local_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto err; } local_attr = NULL; return CKR_OK; err: if (des_key) free(des_key); 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); return rc; } // // 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 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; } else { *data_len = len2; } } return CKR_OK; } opencryptoki-opencryptoki-451d99c/usr/lib/common/mech_des3.c000066400000000000000000002620311520105705100241750ustar00rootroot00000000000000/* * 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; } if (in_data != NULL && in_data_len > 0) 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 && 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_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 && 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_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 && 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 { 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 && 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 + 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); UNUSED(length_only); if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } 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); UNUSED(length_only); if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } 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); UNUSED(length_only); if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } 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); UNUSED(length_only); if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } 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; sign_mgr_cleanup(tokdata, sess, ctx); 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) { if (in_data_len > 0) 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; sign_mgr_cleanup(tokdata, sess, ctx); 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) { verify_mgr_cleanup(tokdata, sess, ctx); return CKR_OK; } verify_mgr_cleanup(tokdata, sess, ctx); 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) { if (in_data_len > 0) 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) { verify_mgr_cleanup(tokdata, sess, ctx); return CKR_OK; } verify_mgr_cleanup(tokdata, sess, ctx); return CKR_SIGNATURE_INVALID; } static void des3_cmac_cleanup(STDLL_TokData_t *tokdata, SESSION *sess, CK_BYTE *context, CK_ULONG context_len) { UNUSED(tokdata); UNUSED(sess); UNUSED(context_len); if (((DES_CMAC_CONTEXT *)context)->ctx != NULL) { token_specific.t_tdes_cmac(tokdata, (CK_BYTE *)"", 0, NULL, ((DES_CMAC_CONTEXT *)context)->iv, CK_FALSE, CK_TRUE, ((DES_CMAC_CONTEXT *)context)->ctx); ((DES_CMAC_CONTEXT *)context)->ctx = NULL; } free(context); } 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"); if (((DES_CMAC_CONTEXT *)ctx->context)->ctx != NULL) ctx->state_unsaveable = CK_TRUE; ctx->context_free_func = des3_cmac_cleanup; 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; sign_mgr_cleanup(tokdata, sess, ctx); 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) { if (in_data_len > 0) 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; if (context->ctx != NULL) ctx->state_unsaveable = CK_TRUE; ctx->context_free_func = des3_cmac_cleanup; } 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; } if (context->ctx != NULL) ctx->state_unsaveable = CK_TRUE; ctx->context_free_func = des3_cmac_cleanup; memcpy(out_data, context->iv, mac_len); *out_data_len = mac_len; done: object_put(tokdata, key_obj, TRUE); key_obj = NULL; sign_mgr_cleanup(tokdata, sess, ctx); 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 (((DES_CMAC_CONTEXT *)ctx->context)->ctx != NULL) ctx->state_unsaveable = CK_TRUE; ctx->context_free_func = des3_cmac_cleanup; if (CRYPTO_memcmp(out_data, ((DES_CMAC_CONTEXT *) ctx->context)->iv, out_data_len) == 0) { verify_mgr_cleanup(tokdata, sess, ctx); return CKR_OK; } verify_mgr_cleanup(tokdata, sess, ctx); 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) { if (in_data_len > 0) 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; if (context->ctx != NULL) ctx->state_unsaveable = CK_TRUE; ctx->context_free_func = des3_cmac_cleanup; } 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 (context->ctx != NULL) ctx->state_unsaveable = CK_TRUE; ctx->context_free_func = des3_cmac_cleanup; if (CRYPTO_memcmp(signature, context->iv, signature_len) == 0) { verify_mgr_cleanup(tokdata, sess, ctx); return CKR_OK; } verify_mgr_cleanup(tokdata, sess, ctx); 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_ULONG rc; CK_ULONG keysize = 0; CK_BBOOL is_opaque = FALSE; if (token_specific.t_des_key_gen == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); return CKR_MECHANISM_INVALID; } rc = token_specific.t_des_key_gen(tokdata, tmpl, &des_key, &keysize, 3 * DES_KEY_SIZE, &is_opaque); if (rc != CKR_OK) goto err; /* For opaque keys put in CKA_IBM_OPAQUE and put dummy_key in CKA_VALUE. */ if (is_opaque) { 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); rc = template_update_attribute(tmpl, opaque_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); free(opaque_attr); goto err; } } else { if (keysize != 3 * DES_KEY_SIZE) { TRACE_ERROR("Invalid key size: %lu\n", keysize); rc = CKR_FUNCTION_FAILED; goto err; } } 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) { 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_opaque) memset(value_attr->pValue, 0, 3 * DES_KEY_SIZE); else memcpy(value_attr->pValue, des_key, 3 * DES_KEY_SIZE); free(des_key); des_key = NULL; 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; rc = template_update_attribute(tmpl, value_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto err; } value_attr = NULL; rc = template_update_attribute(tmpl, key_type_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto err; } key_type_attr = NULL; rc = template_update_attribute(tmpl, class_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto err; } class_attr = NULL; rc = template_update_attribute(tmpl, local_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto err; } local_attr = NULL; return CKR_OK; err: if (des_key) free(des_key); 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); 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; } opencryptoki-opencryptoki-451d99c/usr/lib/common/mech_dh.c000066400000000000000000000464111520105705100237340ustar00rootroot00000000000000/* * 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 "attributes.h" #include "tok_spec_struct.h" #include "trace.h" #include "p11util.h" #ifndef NODH 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 dh_pkcs_derive(STDLL_TokData_t *tokdata, SESSION *sess, CK_MECHANISM *mech, OBJECT *base_key_obj, CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE *handle, CK_BBOOL count_statistic) { CK_RV rc; CK_ULONG keyclass = 0, keytype = 0; CK_ATTRIBUTE *new_attr; CK_ULONG value_len = 0, secret_len; 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 == NULL || mech->ulParameterLen == 0) { 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. rc = get_ulong_attribute_by_type(pTemplate, ulCount, CKA_CLASS, &keyclass); if (rc == CKR_ATTRIBUTE_VALUE_INVALID) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } if (rc == CKR_OK && keyclass != CKO_SECRET_KEY) { TRACE_ERROR("This operation requires a secret key.\n"); return CKR_KEY_FUNCTION_NOT_PERMITTED; } rc = get_ulong_attribute_by_type(pTemplate, ulCount, CKA_KEY_TYPE, &keytype); if (rc == CKR_ATTRIBUTE_VALUE_INVALID) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } // 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, sess, mech->pParameter, mech->ulParameterLen, base_key_obj, secret_key_value, &secret_key_value_len, mech, count_statistic); if (rc != CKR_OK) return rc; rc = get_ulong_attribute_by_type(pTemplate, ulCount, CKA_VALUE_LEN, &value_len); if (rc == CKR_ATTRIBUTE_VALUE_INVALID) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } secret_len = keylen_from_keytype(keytype); if (secret_len == 0) secret_len = value_len; if (secret_len == 0) { /* Neither CKA_VALUE_LEN nor predefined length by key type */ TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); return CKR_TEMPLATE_INCONSISTENT; } if (secret_len > secret_key_value_len) { /* Requested key size can not be derived */ TRACE_ERROR("%s\n", ock_err(ERR_KEY_SIZE_RANGE)); return CKR_KEY_SIZE_RANGE; } // Build the attribute from the vales that were returned back rc = build_attribute(CKA_VALUE, secret_key_value + secret_key_value_len - secret_len, secret_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_DERIVE, 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 rc = template_update_attribute(temp_obj->template, new_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); free(new_attr); object_free(temp_obj); temp_obj = NULL; return rc; } // 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, SESSION *sess, CK_VOID_PTR other_pubkey, CK_ULONG other_pubkey_len, OBJECT *base_key_obj, CK_BYTE *secret_value, CK_ULONG *secret_value_len, CK_MECHANISM_PTR mech, CK_BBOOL count_statistic) { CK_RV rc; CK_ATTRIBUTE *x_attr, *p_attr; // Extract secret (x) from base_key rc = template_attribute_get_non_empty(base_key_obj->template, CKA_VALUE, &x_attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the base key\n"); goto done; } // Extract prime (p) from base_key rc = template_attribute_get_non_empty(base_key_obj->template, CKA_PRIME, &p_attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_PRIME for the base key\n"); goto done; } // Perform: z = other_pubkey^x mod p rc = token_specific.t_dh_pkcs_derive(tokdata, secret_value, secret_value_len, (CK_BYTE *)other_pubkey, other_pubkey_len, (CK_BYTE *)x_attr->pValue, x_attr->ulValueLen, (CK_BYTE *)p_attr->pValue, p_attr->ulValueLen); if (rc != CKR_OK) TRACE_DEVEL("Token specific dh pkcs derive failed.\n"); done: if (count_statistic == TRUE && rc == CKR_OK) INC_COUNTER(tokdata, sess, mech, base_key_obj, POLICY_STRENGTH_IDX_0); 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; } CK_RV dh_encapsulate_key(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, CK_MECHANISM *mech, OBJECT *public_key, CK_ATTRIBUTE *pTemplate, CK_ULONG ulAttributeCount, CK_BYTE *pCiphertext, CK_ULONG *pulCiphertextLen, CK_OBJECT_HANDLE *phKey) { CK_MECHANISM dh_keygen_mech = { CKM_DH_PKCS_KEY_PAIR_GEN, NULL, 0 }; CK_MECHANISM dh_mech; CK_ATTRIBUTE *pub_key_value, *prime, *base; CK_OBJECT_HANDLE gen_dh_publ_key_handle = CK_INVALID_HANDLE; CK_OBJECT_HANDLE gen_dh_priv_key_handle = CK_INVALID_HANDLE; CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE; OBJECT *gen_pub_key_obj = NULL; CK_ATTRIBUTE *gen_pub_key_value; CK_BBOOL ck_true = TRUE; CK_BBOOL ck_false = TRUE; CK_RV rc, rc2; CK_ATTRIBUTE dh_publ_key_tmpl[] = { { CKA_PRIME, NULL, 0 }, { CKA_BASE, NULL, 0 }, { CKA_HIDDEN, &ck_true, sizeof(ck_true) }, { CKA_TOKEN, &ck_false, sizeof(ck_false) }, { CKA_PRIVATE, &ck_true, sizeof(ck_true) }, { CKA_ENCAPSULATE, &ck_true, sizeof(ck_true) }, { CKA_WRAP, &ck_false, sizeof(ck_false) }, { CKA_ENCRYPT, &ck_false, sizeof(ck_false) }, { CKA_VERIFY, &ck_false, sizeof(ck_false) }, { CKA_VERIFY_RECOVER, &ck_false, sizeof(ck_false) }, { CKA_DERIVE, &ck_true, sizeof(ck_true) }, }; CK_ATTRIBUTE dh_priv_key_tmpl[] = { { CKA_HIDDEN, &ck_true, sizeof(ck_true) }, { CKA_SENSITIVE, &ck_true, sizeof(ck_true) }, { CKA_TOKEN, &ck_false, sizeof(ck_false) }, { CKA_PRIVATE, &ck_true, sizeof(ck_true) }, { CKA_UNWRAP, &ck_false, sizeof(ck_false) }, { CKA_DECRYPT, &ck_false, sizeof(ck_false) }, { CKA_SIGN, &ck_false, sizeof(ck_false) }, { CKA_SIGN_RECOVER, &ck_false, sizeof(ck_false) }, { CKA_DERIVE, &ck_true, sizeof(ck_true) }, { CKA_DECAPSULATE, &ck_true, sizeof(ck_true) }, }; /* Mechanism parameter (= public key) must be NULL and 0 */ if (mech->ulParameterLen != 0 || mech->pParameter != NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); return CKR_MECHANISM_PARAM_INVALID; } /* Generate a temporary DH key pair using the same DH parameters */ rc = template_attribute_get_non_empty(public_key->template, CKA_PRIME, &prime); if (rc != CKR_OK) { TRACE_DEVEL("Failed to get CKA_PRIME.\n"); goto done; } rc = template_attribute_get_non_empty(public_key->template, CKA_BASE, &base); if (rc != CKR_OK) { TRACE_DEVEL("Failed to get CKA_BASE.\n"); goto done; } if (length_only) { *pulCiphertextLen = prime->ulValueLen; goto done; } if (*pulCiphertextLen < prime->ulValueLen) { *pulCiphertextLen = prime->ulValueLen; rc = CKR_BUFFER_TOO_SMALL; goto done; } dh_publ_key_tmpl[0].pValue = prime->pValue; dh_publ_key_tmpl[0].ulValueLen = prime->ulValueLen; dh_publ_key_tmpl[1].pValue = base->pValue; dh_publ_key_tmpl[1].ulValueLen = base->ulValueLen; if (token_specific.t_encapsulate_dh_ecdh_key_pair_gen != NULL) { rc = token_specific.t_encapsulate_dh_ecdh_key_pair_gen( tokdata, sess,&dh_keygen_mech, dh_publ_key_tmpl, sizeof(dh_publ_key_tmpl) / sizeof(CK_ATTRIBUTE), dh_priv_key_tmpl, sizeof(dh_priv_key_tmpl) / sizeof(CK_ATTRIBUTE), &gen_dh_publ_key_handle, &gen_dh_priv_key_handle); if (rc != CKR_OK) { TRACE_DEVEL("token specific encapsulate_dh_ecdh_key_pair_gen " "failed to generate temporary DH key pair: %s " "(0x%lx)\n", p11_get_ckr(rc), rc); goto done; } } else { rc = key_mgr_generate_key_pair(tokdata, sess, &dh_keygen_mech, dh_publ_key_tmpl, sizeof(dh_publ_key_tmpl) / sizeof(CK_ATTRIBUTE), dh_priv_key_tmpl, sizeof(dh_priv_key_tmpl) / sizeof(CK_ATTRIBUTE), &gen_dh_publ_key_handle, &gen_dh_priv_key_handle, FALSE, OP_ENCAPSULATE); if (rc != CKR_OK) { TRACE_ERROR("key_mgr_generate_key_pair failed to generate " "temporary DH key pair: %s (0x%lx)\n", p11_get_ckr(rc), rc); goto done; } } /* Get the size of the generated DH public value */ rc = object_mgr_find_in_map1(tokdata, gen_dh_publ_key_handle, &gen_pub_key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to acquire key from DH public key handle.\n"); if (rc == CKR_OBJECT_HANDLE_INVALID) rc = CKR_KEY_HANDLE_INVALID; goto done; } rc = template_attribute_get_non_empty(gen_pub_key_obj->template, CKA_VALUE, &gen_pub_key_value); if (rc != CKR_OK) { TRACE_DEVEL("Failed to get CKA_VALUE.\n"); goto done; } if (gen_pub_key_value->ulValueLen > prime->ulValueLen) { TRACE_DEVEL("DH Public key is larger than prime.\n"); rc = CKR_FUNCTION_FAILED; goto done; } rc = template_attribute_get_non_empty(public_key->template, CKA_VALUE, &pub_key_value); if (rc != CKR_OK) { TRACE_DEVEL("Failed to get CKA_VALUE.\n"); goto done; } dh_mech.mechanism = CKM_DH_PKCS_DERIVE; dh_mech.pParameter = pub_key_value->pValue; dh_mech.ulParameterLen = pub_key_value->ulValueLen; if (token_specific.t_en_decapsulate_dh_ecdh_derive_key != NULL) { rc = token_specific.t_en_decapsulate_dh_ecdh_derive_key( tokdata, sess, &dh_mech, gen_dh_priv_key_handle, &hKey, pTemplate, ulAttributeCount, OP_ENCAPSULATE); if (rc != CKR_OK) { TRACE_DEVEL("token specific en_decapsulate_dh_ecdh_derive_key " "failed.\n"); goto done; } } else { rc = key_mgr_derive_key(tokdata, sess, &dh_mech, gen_dh_priv_key_handle, &hKey, pTemplate, ulAttributeCount, FALSE, OP_ENCAPSULATE); if (rc != CKR_OK) { TRACE_DEVEL("key_mgr_derive_key failed.\n"); goto done; } } *pulCiphertextLen = prime->ulValueLen; if (gen_pub_key_value->ulValueLen < prime->ulValueLen) memset(pCiphertext, 0, prime->ulValueLen - gen_pub_key_value->ulValueLen); memcpy(pCiphertext + prime->ulValueLen - gen_pub_key_value->ulValueLen, gen_pub_key_value->pValue, gen_pub_key_value->ulValueLen); *phKey = hKey; done: if (gen_dh_publ_key_handle != CK_INVALID_HANDLE) { rc2 = object_mgr_destroy_object(tokdata, sess, gen_dh_publ_key_handle); if (rc2 != CKR_OK) { TRACE_ERROR("Failed to destroy temporary DH public key: %s " "(0x%lx)\n", p11_get_ckr(rc2), rc2); if (rc == CKR_OK) rc = rc2; } } if (gen_dh_priv_key_handle != CK_INVALID_HANDLE) { rc2 = object_mgr_destroy_object(tokdata, sess, gen_dh_priv_key_handle); if (rc2 != CKR_OK) { TRACE_ERROR("Failed to destroy temporary DH private key: %s " "(0x%lx)\n", p11_get_ckr(rc2), rc2); if (rc == CKR_OK) rc = rc2; } } if (rc != CKR_OK && hKey != CK_INVALID_HANDLE) { rc2 = object_mgr_destroy_object(tokdata, sess, hKey); if (rc2 != CKR_OK) { TRACE_ERROR("Failed to destroy derived secret key: %s " "(0x%lx)\n", p11_get_ckr(rc2), rc2); if (rc == CKR_OK) rc = rc2; } } object_put(tokdata, gen_pub_key_obj, TRUE); gen_pub_key_obj = NULL; return rc; } CK_RV dh_decapsulate_key(STDLL_TokData_t *tokdata, SESSION *sess, CK_MECHANISM *mech, OBJECT *private_key, CK_ATTRIBUTE *pTemplate, CK_ULONG ulAttributeCount, CK_BYTE *pCiphertext, CK_ULONG ulCiphertextLen, CK_OBJECT_HANDLE *phKey) { CK_MECHANISM dh_mech; CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE; CK_RV rc; /* Mechanism parameter (= public key) must be NULL and 0 */ if (mech->ulParameterLen != 0 || mech->pParameter != NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); return CKR_MECHANISM_PARAM_INVALID; } dh_mech.mechanism = CKM_DH_PKCS_DERIVE; dh_mech.pParameter = pCiphertext; dh_mech.ulParameterLen = ulCiphertextLen; if (token_specific.t_en_decapsulate_dh_ecdh_derive_key != NULL) { rc = token_specific.t_en_decapsulate_dh_ecdh_derive_key( tokdata, sess, &dh_mech, private_key->map_handle, &hKey, pTemplate, ulAttributeCount, OP_DECAPSULATE); if (rc != CKR_OK) { TRACE_DEVEL("token specific en_decapsulate_dh_ecdh_derive_key " "failed.\n"); goto done; } } else { rc = key_mgr_derive_key(tokdata, sess, &dh_mech, private_key->map_handle, &hKey, pTemplate, ulAttributeCount, FALSE, OP_DECAPSULATE); if (rc != CKR_OK) { TRACE_DEVEL("key_mgr_derive_key failed.\n"); goto done; } } *phKey = hKey; done: return rc; } #endif opencryptoki-opencryptoki-451d99c/usr/lib/common/mech_dsa.c000066400000000000000000000146271520105705100241140ustar00rootroot00000000000000/* * 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_BYTE sig[DSA_SIGNATURE_SIZE]; CK_OBJECT_CLASS class; 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\n"); if (rc == CKR_OBJECT_HANDLE_INVALID) return CKR_KEY_HANDLE_INVALID; else return rc; } // must be a PRIVATE key operation // rc = template_attribute_get_ulong(key_obj->template, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); goto done; } // 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_OBJECT_CLASS class; 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.\n"); if (rc == CKR_OBJECT_HANDLE_INVALID) return CKR_KEY_HANDLE_INVALID; else return rc; } // must be a PUBLIC key operation // rc = template_attribute_get_ulong(key_obj->template, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); goto done; } 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_OBJECT_CLASS keyclass; CK_RV rc; rc = template_attribute_get_ulong(priv_key->template, CKA_CLASS, &keyclass); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); return rc; } // 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_OBJECT_CLASS keyclass; CK_RV rc; rc = template_attribute_get_ulong(publ_key->template, CKA_CLASS, &keyclass); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); return rc; } // 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 opencryptoki-opencryptoki-451d99c/usr/lib/common/mech_ec.c000066400000000000000000002626021520105705100237320ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2001-2021 * * 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 "platform.h" #include "pkcs11types.h" #include "defs.h" #include "host_defs.h" #include "h_extern.h" #include "attributes.h" #include "tok_spec_struct.h" #include "trace.h" #include "tok_specific.h" #include "ec_defs.h" #include "p11util.h" #include "openssl/obj_mac.h" #include CK_RV get_ecsiglen(OBJECT *key_obj, CK_ULONG *size) { CK_ATTRIBUTE *attr = NULL; int i; CK_RV rc; rc = template_attribute_get_non_empty(key_obj->template, CKA_ECDSA_PARAMS, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_ECDSA_PARAMS for the key.\n"); return rc; } /* 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_edwards_key_pair_gen(STDLL_TokData_t *tokdata, TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl) { CK_RV rc; if (token_specific.t_ec_edwards_generate_keypair == NULL) { TRACE_ERROR("ec_edwards_generate_keypair not supported by this " "token\n"); return CKR_FUNCTION_NOT_SUPPORTED; } rc = token_specific.t_ec_edwards_generate_keypair(tokdata, publ_tmpl, priv_tmpl); if (rc != CKR_OK) TRACE_ERROR("Key Generation failed\n"); return rc; } CK_RV ckm_ec_montgomery_key_pair_gen(STDLL_TokData_t *tokdata, TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl) { CK_RV rc; if (token_specific.t_ec_montgomery_generate_keypair == NULL) { TRACE_ERROR("ec_montgomery_generate_keypair not supported by this " "token\n"); return CKR_FUNCTION_NOT_SUPPORTED; } rc = token_specific.t_ec_montgomery_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_MECHANISM *mech) { CK_OBJECT_CLASS keyclass; CK_RV rc; switch (mech->mechanism) { case CKM_ECDSA: if (token_specific.t_ec_sign == NULL) { TRACE_ERROR("ec_sign not supported by this token\n"); return CKR_FUNCTION_NOT_SUPPORTED; } break; case CKM_EDDSA: if (token_specific.t_ec_edwards_sign == NULL) { TRACE_ERROR("ec_edwards_sign not supported by this token\n"); return CKR_FUNCTION_NOT_SUPPORTED; } break; default: return CKR_MECHANISM_INVALID; } rc = template_attribute_get_ulong(key_obj->template, CKA_CLASS, &keyclass); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); return rc; } // 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; } switch (mech->mechanism) { case CKM_ECDSA: rc = token_specific.t_ec_sign(tokdata, sess, in_data, in_data_len, out_data, out_data_len, key_obj); break; case CKM_EDDSA: rc = token_specific.t_ec_edwards_sign(tokdata, sess, in_data, in_data_len, out_data, out_data_len, key_obj, mech); break; default: return CKR_MECHANISM_INVALID; } 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.\n"); 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, &ctx->mech); 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_MECHANISM *mech) { CK_OBJECT_CLASS keyclass; CK_RV rc; switch (mech->mechanism) { case CKM_ECDSA: if (token_specific.t_ec_verify == NULL) { TRACE_ERROR("ec_verify not supported by this token\n"); return CKR_FUNCTION_NOT_SUPPORTED; } break; case CKM_EDDSA: if (token_specific.t_ec_edwards_verify == NULL) { TRACE_ERROR("ec_edwards_verify not supported by this token\n"); return CKR_FUNCTION_NOT_SUPPORTED; } break; default: return CKR_MECHANISM_INVALID; } rc = template_attribute_get_ulong(key_obj->template, CKA_CLASS, &keyclass); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); return rc; } // 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; } switch (mech->mechanism) { case CKM_ECDSA: rc = token_specific.t_ec_verify(tokdata, sess, in_data, in_data_len, out_data, out_data_len, key_obj); break; case CKM_EDDSA: rc = token_specific.t_ec_edwards_verify(tokdata, sess, in_data, in_data_len, out_data, out_data_len, key_obj, mech); break; default: return CKR_MECHANISM_INVALID; } 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.\n"); 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, &ctx->mech); 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)); rc = get_digest_from_mech(ctx->mech.mechanism, &digest_mech.mechanism); if (rc != CKR_OK) { TRACE_ERROR("%s get_digest_from_mech failed\n", __func__); return rc; } 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, FALSE); 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"); digest_mgr_cleanup(tokdata, sess, &digest_ctx); 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, FALSE, FALSE); 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(tokdata, sess, &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) { MP_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 = (MP_DIGEST_CONTEXT *) ctx->context; if (context->flag == FALSE) { rc = get_digest_from_mech(ctx->mech.mechanism, &digest_mech.mechanism); if (rc != CKR_OK) { TRACE_ERROR("%s get_digest_from_mech failed\n", __func__); return rc; } digest_mech.ulParameterLen = 0; digest_mech.pParameter = NULL; rc = digest_mgr_init(tokdata, sess, &context->hash_context, &digest_mech, FALSE); if (rc != CKR_OK) { TRACE_DEVEL("Digest Mgr Init failed.\n"); return rc; } context->flag = TRUE; ctx->state_unsaveable |= context->hash_context.state_unsaveable; } 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]; MP_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 = (MP_DIGEST_CONTEXT *) ctx->context; if (context->flag == FALSE) { rc = ec_hash_sign_update(tokdata, sess, ctx, NULL, 0); TRACE_DEVEL("ec_hash_sign_update\n"); if (rc != 0) return rc; } 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, FALSE, FALSE); 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(tokdata, sess, &sign_ctx); return rc; } done: sign_mgr_cleanup(tokdata, sess, &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)); rc = get_digest_from_mech(ctx->mech.mechanism, &digest_mech.mechanism); if (rc != CKR_OK) { TRACE_ERROR("%s get_digest_from_mech failed\n", __func__); return rc; } 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, FALSE); 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"); digest_mgr_cleanup(tokdata, sess, &digest_ctx); 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, FALSE); 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(tokdata, sess, &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) { MP_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 = (MP_DIGEST_CONTEXT *) ctx->context; if (context->flag == FALSE) { rc = get_digest_from_mech(ctx->mech.mechanism, &digest_mech.mechanism); if (rc != CKR_OK) { TRACE_ERROR("%s get_digest_from_mech failed\n", __func__); return rc; } digest_mech.ulParameterLen = 0; digest_mech.pParameter = NULL; rc = digest_mgr_init(tokdata, sess, &context->hash_context, &digest_mech, FALSE); if (rc != CKR_OK) { TRACE_DEVEL("Digest Mgr Init failed.\n"); return rc; } context->flag = TRUE; ctx->state_unsaveable |= context->hash_context.state_unsaveable; } 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]; MP_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 = (MP_DIGEST_CONTEXT *) ctx->context; if (context->flag == FALSE) { rc = ec_hash_verify_update(tokdata, sess, ctx, NULL, 0); TRACE_DEVEL("ec_hash_verify_update\n"); if (rc != 0) return rc; } 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, FALSE); 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(tokdata, sess, &verify_ctx); return rc; } static 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)); rc = digest_from_kdf(kdf, &digest_mech.mechanism); if (rc != CKR_OK) { TRACE_ERROR("digest_from_kdf failed\n"); return CKR_FUNCTION_NOT_SUPPORTED; } rc = get_sha_size(digest_mech.mechanism, h_len); if (rc != CKR_OK) { TRACE_ERROR("get_sha_size failed\n"); return CKR_FUNCTION_NOT_SUPPORTED; } rc = digest_mgr_init(tokdata, sess, &ctx, &digest_mech, FALSE); 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=0x%lx\n", rc); digest_mgr_cleanup(tokdata, sess, &ctx); 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 = sizeof(uint32_t); CK_BYTE *ctx = NULL; CK_ULONG ctx_len; CK_BYTE hash[MAX_SUPPORTED_HASH_LENGTH]; CK_ULONG h_len; CK_RV rc; uint32_t counter, counter_en; unsigned int i; /* 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; } /* * 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++) { counter_en = htobe32(counter); memcpy(ctx + z_len, &counter_en, counter_length); 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_kdf_sp800_56c(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, uint32_t purpose, CK_BYTE *key, CK_ULONG key_len) { CK_ULONG counter_length = sizeof(uint32_t); CK_ULONG purpose_length = purpose > 0 ? sizeof(uint32_t) : 0; CK_BYTE *ctx = NULL; CK_ULONG ctx_len; CK_BYTE hash[MAX_SUPPORTED_HASH_LENGTH]; CK_ULONG h_len; CK_RV rc; uint32_t counter, counter_en, purpose_en = htobe32(purpose); unsigned int i; /* Check max keylen according to FIPS SP800-56C */ /* 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; } /* * Allocate memory for hash context: * be32(counter) || [be32(purpose)] || || */ ctx_len = counter_length + purpose_length + z_len + shared_data_len; ctx = malloc(ctx_len); if (!ctx) return CKR_HOST_MEMORY; if (purpose > 0) memcpy(ctx + counter_length, &purpose_en, purpose_length); memcpy(ctx + counter_length + purpose_length, z, z_len); if (shared_data_len > 0) memcpy(ctx + counter_length + purpose_length + z_len, 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++) { counter_en = htobe32(counter); memcpy(ctx, &counter_en, counter_length); 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, SESSION *sess, CK_VOID_PTR other_pubkey, CK_ULONG other_pubkey_len, OBJECT* base_key_obj, CK_BYTE *secret_value, CK_ULONG *secret_value_len, CK_MECHANISM_PTR mech, CK_BBOOL count_statistic) { CK_RV rc; CK_ATTRIBUTE *attr; CK_BYTE *oid_p; CK_ULONG oid_len; CK_ULONG class = 0, keytype = 0; 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; } /* Get curve oid from CKA_ECDSA_PARAMS */ rc = template_attribute_get_non_empty(base_key_obj->template, CKA_ECDSA_PARAMS, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_ECDSA_PARAMS for the base key.\n"); goto done; } oid_p = attr->pValue; oid_len = attr->ulValueLen; if (!template_get_class(base_key_obj->template, &class, &keytype)) { TRACE_ERROR("Could not find CKA_CLASS in the template\n"); rc = CKR_TEMPLATE_INCOMPLETE; goto done; } if (class != CKO_PRIVATE_KEY || (keytype != CKK_EC && keytype != CKK_EC_MONTGOMERY)) { TRACE_ERROR("Base key is not an EC private key\n"); rc = CKR_KEY_TYPE_INCONSISTENT; goto done; } if (mech->mechanism == CKM_ECDH1_COFACTOR_DERIVE && keytype != CKK_EC) { TRACE_ERROR("Cofactor mode only works with an EC private key\n"); rc = CKR_KEY_TYPE_INCONSISTENT; goto done; } /* Extract EC private key (D) from base_key */ rc = template_attribute_get_non_empty(base_key_obj->template, CKA_VALUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the base key.\n"); 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, mech->mechanism == CKM_ECDH1_COFACTOR_DERIVE); if (rc != CKR_OK) { TRACE_ERROR("Token specific ecdh pkcs derive failed with rc=%ld.\n", rc); } done: if (count_statistic == TRUE && rc == CKR_OK) INC_COUNTER(tokdata, sess, mech, base_key_obj, POLICY_STRENGTH_IDX_0); return rc; } /** * 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_get_derived_key_size(CK_ULONG prime_len, CK_BYTE *curve_oid, CK_ULONG curve_oid_len, CK_EC_KDF_TYPE kdf, CK_ULONG key_type, CK_ULONG value_len, CK_ULONG *key_len) { CK_RV rc; CK_ULONG key_len_type; CK_MECHANISM_TYPE digest_mech; int i; *key_len = value_len; key_len_type = keylen_from_keytype(key_type); if (*key_len == 0) { *key_len = key_len_type; } else if (key_len_type != 0 && *key_len != key_len_type) { TRACE_ERROR("Derived key length does not work for the key type\n"); return CKR_TEMPLATE_INCONSISTENT; } if (prime_len == 0) { for (i = 0; i < NUMEC; i++) { if (der_ec_supported[i].data_size == curve_oid_len && memcmp(der_ec_supported[i].data, curve_oid, curve_oid_len) == 0) prime_len = (der_ec_supported[i].len_bits + 7) / 8; } if (prime_len == 0) { TRACE_ERROR("Curve not supported\n"); return CKR_CURVE_NOT_SUPPORTED; } } /* * If no CKA_VALUE_LEN is specified and the key type does also not dictate * a certain length, then take then digest length of the used KDF, or if * no KDF, the size of the derived shared secret. */ if (*key_len == 0) { /* Determine digest length */ if (kdf != CKD_NULL && kdf != CKD_IBM_HYBRID_NULL) { rc = digest_from_kdf(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, key_len); if (rc != CKR_OK) { TRACE_ERROR("Cannot determine SHA digest size.\n"); return CKR_ARGUMENTS_BAD; } } else { *key_len = prime_len; } switch (key_type) { case CKK_AES: if (*key_len != AES_KEY_SIZE_128 && *key_len != AES_KEY_SIZE_192 && *key_len != AES_KEY_SIZE_256) { TRACE_ERROR("Derived key length does not work for the key " "type\n"); return CKR_TEMPLATE_INCONSISTENT; } break; case CKK_AES_XTS: if (*key_len != (AES_KEY_SIZE_128 * 2) && *key_len != (AES_KEY_SIZE_256 * 2)) { TRACE_ERROR("Derived key length does not work for the key " "type\n"); return CKR_TEMPLATE_INCONSISTENT; } break; default: /* DES/DES2/DE3 has already been checked above */ break; } } /* If no KDF used, max possible key length is the prime_len */ if ((kdf == CKD_NULL || kdf == CKD_IBM_HYBRID_NULL) && *key_len > prime_len) { TRACE_ERROR("Can only provide %ld key bytes without a KDF, " "but %ld bytes requested.\n", prime_len, *key_len); return CKR_ARGUMENTS_BAD; } return CKR_OK; } CK_RV ecdh_pkcs_derive(STDLL_TokData_t *tokdata, SESSION *sess, CK_MECHANISM *mech, OBJECT *base_key_obj, CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE *derived_key_obj, CK_BBOOL count_statistic, CK_ULONG mode) { CK_RV rc; CK_ULONG class = 0, keytype = 0, key_len = 0; CK_ATTRIBUTE *value_attr, *vallen_attr = NULL; 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; /* Check parm length */ if (mech->ulParameterLen != sizeof(CK_ECDH1_DERIVE_PARAMS) || mech->pParameter == NULL) { 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 CKR_TEMPLATE_INCOMPLETE; } /* Optional shared data can only be provided together with a KDF */ if ((pParms->kdf == CKD_NULL || pParms->kdf == CKD_IBM_HYBRID_NULL) && (pParms->pSharedData != NULL || pParms->ulSharedDataLen != 0)) { TRACE_ERROR("No KDF specified, but shared data ptr is not NULL.\n"); return CKR_MECHANISM_PARAM_INVALID; } rc = object_mgr_create_skel(tokdata, sess, pTemplate, ulCount, mode, class, keytype, &temp_obj); if (rc != CKR_OK) { TRACE_ERROR("Object Mgr create skeleton failed, rc=0x%lx.\n", rc); return rc; } if (token_specific.t_ecdh_pkcs_derive_kdf != NULL) { rc = token_specific.t_ecdh_pkcs_derive_kdf(tokdata, sess, base_key_obj, pParms, temp_obj, class, keytype, mech->mechanism == CKM_ECDH1_COFACTOR_DERIVE); if (rc != CKR_OK) { TRACE_ERROR("t_ecdh_pkcs_derive_kdf failed, rc=0x%lx.\n", rc); goto end; } INC_COUNTER(tokdata, sess, mech, base_key_obj, POLICY_STRENGTH_IDX_0); goto derive_done; } /* Derive the shared secret */ rc = ckm_ecdh_pkcs_derive(tokdata, sess, pParms->pPublicData, pParms->ulPublicDataLen, base_key_obj, z_value, &z_len, mech, count_statistic); if (rc != CKR_OK) { TRACE_ERROR("Error deriving the shared secret.\n"); goto end; } /* Determine derived key length */ rc = get_ulong_attribute_by_type(pTemplate, ulCount, CKA_VALUE_LEN, &key_len); if (rc == CKR_ATTRIBUTE_VALUE_INVALID) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); goto end; } rc = ecdh_get_derived_key_size(z_len, NULL, 0, pParms->kdf, keytype, key_len, &key_len); if (rc != CKR_OK) { TRACE_ERROR("Can not determine the derived key length\n"); goto end; } /* Determine digest length */ if (pParms->kdf != CKD_NULL && pParms->kdf != CKD_IBM_HYBRID_NULL) { rc = digest_from_kdf(pParms->kdf, &digest_mech); if (rc != CKR_OK) { TRACE_ERROR("Cannot determine mech from kdf.\n"); rc = CKR_MECHANISM_PARAM_INVALID; goto end; } rc = get_sha_size(digest_mech, &kdf_digest_len); if (rc != CKR_OK) { TRACE_ERROR("Cannot determine SHA digest size.\n"); rc = CKR_MECHANISM_PARAM_INVALID; goto end; } } 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); rc = CKR_HOST_MEMORY; goto end; } /* Apply KDF function to shared secret */ switch (pParms->kdf) { case CKD_NULL: case CKD_IBM_HYBRID_NULL: memcpy(derived_key, z_value, z_len); break; case CKD_SHA1_KDF: case CKD_SHA224_KDF: case CKD_SHA256_KDF: case CKD_SHA384_KDF: case CKD_SHA512_KDF: case CKD_SHA3_224_KDF: case CKD_SHA3_256_KDF: case CKD_SHA3_384_KDF: case CKD_SHA3_512_KDF: case CKD_IBM_HYBRID_SHA1_KDF: case CKD_IBM_HYBRID_SHA224_KDF: case CKD_IBM_HYBRID_SHA256_KDF: case CKD_IBM_HYBRID_SHA384_KDF: case CKD_IBM_HYBRID_SHA512_KDF: 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; break; case CKD_SHA1_KDF_SP800: case CKD_SHA224_KDF_SP800: case CKD_SHA256_KDF_SP800: case CKD_SHA384_KDF_SP800: case CKD_SHA512_KDF_SP800: case CKD_SHA3_224_KDF_SP800: case CKD_SHA3_256_KDF_SP800: case CKD_SHA3_384_KDF_SP800: case CKD_SHA3_512_KDF_SP800: rc = ckm_kdf_sp800_56c(tokdata, sess, pParms->kdf, kdf_digest_len, z_value, z_len, pParms->pSharedData, pParms->ulSharedDataLen, 0, derived_key, derived_key_len); if (rc != CKR_OK) goto end; break; default: TRACE_ERROR("Unsupported KDF: 0x%lx\n", pParms->kdf); rc = CKR_MECHANISM_PARAM_INVALID; goto end; } /* Return the hashed and truncated derived bytes as CKA_VALUE attribute */ rc = build_attribute(CKA_VALUE, derived_key, key_len, &value_attr); if (rc != CKR_OK) { TRACE_ERROR("Failed to build the attribute from CKA_VALUE, rc=0x%lx.\n", rc); goto end; } switch (keytype) { case CKK_GENERIC_SECRET: case CKK_SHA_1_HMAC: case CKK_SHA256_HMAC: case CKK_SHA384_HMAC: case CKK_SHA512_HMAC: case CKK_SHA224_HMAC: case CKK_SHA3_224_HMAC: case CKK_SHA3_256_HMAC: case CKK_SHA3_384_HMAC: case CKK_SHA3_512_HMAC: case CKK_SHA512_224_HMAC: case CKK_SHA512_256_HMAC: case CKK_AES: case CKK_AES_XTS: /* Supply CKA_VAUE_LEN since this is required for those key types */ rc = build_attribute(CKA_VALUE_LEN, (CK_BYTE*)&key_len, sizeof(key_len), &vallen_attr); if (rc != CKR_OK) { TRACE_ERROR("Failed to build the attribute from CKA_VALUE_LEN, " "rc=0x%lx.\n", rc); free(value_attr); goto end; } break; default: break; } /* Update the template in the object with the new attribute */ rc = template_update_attribute(temp_obj->template, value_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); free(value_attr); free(vallen_attr); goto end; } if (vallen_attr != NULL) { rc = template_update_attribute(temp_obj->template, vallen_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); free(vallen_attr); goto end; } } derive_done: /* 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=0x%lx.\n", rc); goto end; } temp_obj = NULL; rc = CKR_OK; end: if (derived_key != NULL) free(derived_key); if (temp_obj != NULL) object_free(temp_obj); 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(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(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; } /* * Calculate the EC public key (ECPoint) from the EC private key. */ CK_RV ec_point_from_priv_key(CK_BYTE *parms, CK_ULONG parms_len, CK_BYTE *d, CK_ULONG d_len, CK_BYTE **point, CK_ULONG *point_len) { EC_POINT *pub_key = NULL; EC_GROUP *group = NULL; int nid, p_len; BIGNUM *bn_d = NULL, *bn_x = NULL, *bn_y = NULL; CK_RV rc = CKR_OK; CK_BYTE *ec_point = NULL; CK_ULONG ec_point_len; nid = ec_nid_from_oid(parms, parms_len); if (nid == -1) return CKR_CURVE_NOT_SUPPORTED; #if OPENSSL_VERSION_PREREQ(3, 0) switch (nid) { case NID_ED25519: case NID_ED448: case NID_X25519: case NID_X448: return openssl_ec_edwards_point_from_priv_key(parms, parms_len, d, d_len, point, point_len); } #endif bn_d = BN_secure_new(); if (bn_d == NULL) { rc = CKR_FUNCTION_FAILED; goto done; } if (BN_bin2bn(d, d_len, bn_d) == NULL) { rc = CKR_FUNCTION_FAILED; goto done; } group = EC_GROUP_new_by_curve_name(nid); if (group == NULL) { rc = CKR_CURVE_NOT_SUPPORTED; goto done; } p_len = (EC_GROUP_get_degree(group) + 7) / 8; pub_key = EC_POINT_new(group); if (pub_key == NULL) { rc = CKR_FUNCTION_FAILED; goto done; } if (!EC_POINT_mul(group, pub_key, bn_d, NULL, NULL, NULL)) { rc = CKR_FUNCTION_FAILED; goto done; } /* Get (X,Y) as BIGNUMs */ bn_x = BN_new(); bn_y = BN_new(); if (bn_x == NULL || bn_y == NULL) { rc = CKR_HOST_MEMORY; goto done; } if (!EC_POINT_get_affine_coordinates(group, pub_key, bn_x, bn_y, NULL)) { rc = CKR_FUNCTION_FAILED; goto done; } ec_point_len = 1 + 2 * p_len; ec_point = malloc(ec_point_len); if (ec_point == NULL) { rc = CKR_HOST_MEMORY; goto done; } ec_point[0] = POINT_CONVERSION_UNCOMPRESSED; BN_bn2binpad(bn_x, ec_point + 1, p_len); BN_bn2binpad(bn_y, ec_point + 1 + p_len, p_len); *point = ec_point; *point_len = ec_point_len; ec_point = NULL; done: if (pub_key) EC_POINT_free(pub_key); BN_clear_free(bn_x); BN_clear_free(bn_y); BN_clear_free(bn_d); if (group != NULL) EC_GROUP_free(group); return rc; } /* * Return the EC point from the specified data. * 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 EC point (encoded or raw) may or may not have a format byte. * The returned buffer in ec_point must be freed by the caller if * parameter 'allocated' is true on return. */ int ec_point_from_public_data(const CK_BYTE *data, CK_ULONG data_len, CK_ULONG prime_len, CK_BBOOL allow_raw, CK_BBOOL *allocated, CK_BYTE **ec_point, CK_ULONG *ec_point_len) { CK_ULONG value_len = 0, field_len = 0, pad_len; CK_BYTE *value = NULL; CK_BYTE *buff = NULL; CK_BYTE form; CK_RV rc; if (!allow_raw) goto check_encoded; /* Check if this could be a raw EC Point */ form = data[0] & ~0x01; switch (form) { case POINT_CONVERSION_COMPRESSED: if (data_len == prime_len + 1) { /* Length is as expected for a raw EC point in compressed form */ *ec_point = (CK_BYTE *)data; *ec_point_len = data_len; *allocated = FALSE; TRACE_DEVEL("Raw EC Point in compressed form\n"); return CKR_OK; } break; case POINT_CONVERSION_UNCOMPRESSED: case POINT_CONVERSION_HYBRID: if (data_len == 2 * prime_len + 1) { /* Length is as expected for a raw EC point in uncompressed form */ *ec_point = (CK_BYTE *)data; *ec_point_len = data_len; *allocated = FALSE; TRACE_DEVEL("Raw EC Point in uncompressed/hybrid form\n"); return CKR_OK; } break; default: /* No valid format byte */ break; } check_encoded: /* If we reach here, try to BER decode it as OCTET-STRING */ rc = ber_decode_OCTET_STRING((CK_BYTE *)data, data_len, &value, &value_len, &field_len); if (rc == CKR_OK && field_len == data_len && value_len <= data_len - 2) { /* Looks like a BER encoded EC Point */ form = value[0] & ~0x01; TRACE_DEVEL("Encoded EC Point, form: %02x\n", form); switch (form) { case POINT_CONVERSION_COMPRESSED: if (value_len == prime_len + 1) { /* Length is as expected for an EC point in compressed form */ *ec_point = (CK_BYTE *)value; *ec_point_len = value_len; *allocated = FALSE; TRACE_DEVEL("Encoded EC Point in compressed form\n"); return CKR_OK; } break; case POINT_CONVERSION_UNCOMPRESSED: case POINT_CONVERSION_HYBRID: if (value_len == 2 * prime_len + 1) { /* Length is as expected for an EC point in uncompressed form */ *ec_point = (CK_BYTE *)value; *ec_point_len = value_len; *allocated = FALSE; TRACE_DEVEL("Encoded EC Point in uncompressed/hybrid form\n"); return CKR_OK; } break; default: /* No valid format byte */ break; } } else { /* It is not BER encoded */ TRACE_DEVEL("Raw EC Point\n"); value = NULL; value_len = 0; } /* * If we reach here, the length do not match, neither as a raw EC Point, * nor for a BER encoded EC Point. Must be a EC Point without a format * byte, and possibly without leading zeros. Build a full EC Point * in uncompressed form, and pad with zeros on the left (if needed). */ if ((value_len != 0 ? value_len : data_len) <= prime_len) { /* Must be larger than prime length to have x and y */ TRACE_ERROR("Not a valid EC Point: data too short\n"); return CKR_PUBLIC_KEY_INVALID; } if ((value_len != 0 ? value_len : data_len) > 2 * prime_len) { /* Can not be larger than 2 * prime length */ TRACE_ERROR("Not a valid EC Point: data too large\n"); return CKR_PUBLIC_KEY_INVALID; } buff = malloc(1 + 2 * prime_len); if (buff == NULL) { TRACE_ERROR("Malloc failed\n"); return CKR_HOST_MEMORY; } buff[0] = POINT_CONVERSION_UNCOMPRESSED; pad_len = 2 * prime_len - (value_len != 0 ? value_len : data_len); memset(buff + 1, 0, pad_len); if (value != NULL) memcpy(buff + 1 + pad_len, value, value_len); else memcpy(buff + 1 + pad_len, data, data_len); *ec_point = (CK_BYTE *)buff; *ec_point_len = 1 + 2 * prime_len; *allocated = TRUE; TRACE_DEVEL("EC Point built from no format byte and trimmed\n"); return CKR_OK; } /* * Like ec_point_from_public_data(), but returns the EC point in uncompressed * form. If the public data is in compressed form, it uncompresses it. * If it is in hybrid form, convert it into uncompressed form. */ int ec_point_uncompressed_from_public_data(const CK_BYTE *data, CK_ULONG data_len, CK_ULONG prime_len, CK_BYTE *curve_oid, CK_ULONG curve_oid_len, CK_BBOOL allow_raw, CK_BBOOL *allocated, CK_BYTE **ec_point, CK_ULONG *ec_point_len) { CK_RV rc; CK_BYTE form; CK_ULONG ec_point2_len; CK_BYTE *ec_point2 = NULL; rc = ec_point_from_public_data(data, data_len, prime_len, allow_raw, allocated, ec_point, ec_point_len); if (rc != CKR_OK) return rc; form = (*ec_point)[0] & ~0x01; switch (form) { case POINT_CONVERSION_COMPRESSED: case POINT_CONVERSION_HYBRID: ec_point2_len = 1 + 2 * prime_len; ec_point2 = malloc(ec_point2_len); if (ec_point2 == NULL) { TRACE_ERROR("Malloc failed\n"); rc = CKR_HOST_MEMORY; break; } rc = ec_uncompress_public_key(curve_oid, curve_oid_len, *ec_point, *ec_point_len, prime_len, ec_point2, &ec_point2_len); if (rc != CKR_OK) { TRACE_ERROR("Failed to uncompress\n"); break; } if (*allocated) free(*ec_point); *ec_point = ec_point2; *ec_point_len = ec_point2_len; *allocated = TRUE; ec_point2 = NULL; break; case POINT_CONVERSION_UNCOMPRESSED: default: break; } if (rc != CKR_OK && *allocated) { free(*ec_point); *ec_point = NULL; *ec_point_len = 0; *allocated = FALSE; } if (ec_point2 != NULL) free(ec_point2); return rc; } CK_RV ecdh_aes_key_wrap(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_ECDH_AES_KEY_WRAP_PARAMS *params; CK_ATTRIBUTE *ec_params = NULL, *ec_point = NULL; CK_MECHANISM ec_keygen_mech = { 0, NULL, 0 }; CK_ECDH1_DERIVE_PARAMS ecdh_params = { 0 }; CK_MECHANISM ecdh_mech = { 0, &ecdh_params, sizeof(ecdh_params) }; CK_MECHANISM aeskw_kwm_mech = { CKM_AES_KEY_WRAP_KWP, NULL, 0 }; ENCR_DECR_CONTEXT aeskw_ctx = { 0 }; CK_OBJECT_HANDLE ec_publ_key_handle = CK_INVALID_HANDLE; CK_OBJECT_HANDLE ec_priv_key_handle = CK_INVALID_HANDLE; CK_OBJECT_HANDLE aes_key_handle = CK_INVALID_HANDLE; CK_OBJECT_CLASS aes_key_class = CKO_SECRET_KEY; CK_KEY_TYPE aes_key_type = CKK_AES; CK_ULONG aes_key_size, field_len = 0, pub_ec_point_len = 0; CK_ULONG wrapped_key_len = 0, total_len; CK_BYTE *pub_ec_point = NULL; CK_BBOOL ck_true = TRUE; CK_BBOOL ck_false = TRUE; OBJECT *key_obj = NULL, *pub_key_obj = NULL; int curve_type; CK_RV rc, rc2; CK_ATTRIBUTE ec_publ_key_tmpl[] = { { CKA_EC_PARAMS, NULL, 0 }, { CKA_HIDDEN, &ck_true, sizeof(ck_true) }, { CKA_TOKEN, &ck_false, sizeof(ck_false) }, { CKA_PRIVATE, &ck_true, sizeof(ck_true) }, { CKA_WRAP, &ck_true, sizeof(ck_true) }, { CKA_ENCRYPT, &ck_false, sizeof(ck_false) }, { CKA_VERIFY, &ck_false, sizeof(ck_false) }, { CKA_VERIFY_RECOVER, &ck_false, sizeof(ck_false) }, { CKA_DERIVE, &ck_true, sizeof(ck_true) }, }; CK_ATTRIBUTE ec_priv_key_tmpl[] = { { CKA_HIDDEN, &ck_true, sizeof(ck_true) }, { CKA_SENSITIVE, &ck_true, sizeof(ck_true) }, { CKA_TOKEN, &ck_false, sizeof(ck_false) }, { CKA_PRIVATE, &ck_true, sizeof(ck_true) }, { CKA_UNWRAP, &ck_true, sizeof(ck_true) }, { CKA_DECRYPT, &ck_false, sizeof(ck_false) }, { CKA_SIGN, &ck_false, sizeof(ck_false) }, { CKA_SIGN_RECOVER, &ck_false, sizeof(ck_false) }, { CKA_DERIVE, &ck_true, sizeof(ck_true) }, }; CK_ATTRIBUTE aes_key_tmpl[] = { { CKA_CLASS, &aes_key_class, sizeof(aes_key_class) }, { CKA_KEY_TYPE, &aes_key_type, sizeof(aes_key_type) }, { CKA_VALUE_LEN, &aes_key_size, sizeof(aes_key_size) }, { CKA_HIDDEN, &ck_true, sizeof(ck_true) }, { CKA_SENSITIVE, &ck_true, sizeof(ck_true) }, { CKA_TOKEN, &ck_false, sizeof(ck_false) }, { CKA_PRIVATE, &ck_true, sizeof(ck_true) }, { CKA_WRAP, &ck_false, sizeof(ck_false) }, { CKA_UNWRAP, &ck_true, sizeof(ck_true) }, { CKA_ENCRYPT, &ck_false, sizeof(ck_false) }, { CKA_DECRYPT, &ck_false, sizeof(ck_false) }, { CKA_SIGN, &ck_false, sizeof(ck_false) }, { CKA_VERIFY, &ck_false, sizeof(ck_false) }, { CKA_DERIVE, &ck_false, sizeof(ck_false) }, }; params = (CK_ECDH_AES_KEY_WRAP_PARAMS *)ctx->mech.pParameter; /* Get the EC parameters of the EC public key used with this mechanism */ 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.\n"); if (rc == CKR_OBJECT_HANDLE_INVALID) return CKR_KEY_HANDLE_INVALID; else return rc; } rc = template_attribute_get_non_empty(key_obj->template, CKA_EC_PARAMS, &ec_params); if (rc != CKR_OK) { TRACE_DEVEL("Failed to get CKA_EC_PARAMS.\n"); goto done; } curve_type = ec_curve_type_from_oid(ec_params->pValue, ec_params->ulValueLen); if (curve_type < 0) { TRACE_DEVEL("Failed to get CKA_EC_PARAMS.\n"); rc = CKR_CURVE_NOT_SUPPORTED; goto done; } switch (ctx->mech.mechanism) { case CKM_ECDH_AES_KEY_WRAP: if (curve_type != PRIME_CURVE && curve_type != BRAINPOOL_CURVE && curve_type != KOBLITZ_CURVE && curve_type != MONTGOMERY_CURVE) { TRACE_DEVEL("Curve not supported for CKM_ECDH_AES_KEY_WRAP.\n"); rc = CKR_CURVE_NOT_SUPPORTED; goto done; } ecdh_mech.mechanism = CKM_ECDH1_DERIVE; break; case CKM_ECDH_COF_AES_KEY_WRAP: if (curve_type != PRIME_CURVE && curve_type != BRAINPOOL_CURVE && curve_type != KOBLITZ_CURVE) { TRACE_DEVEL("Curve not supported for CKM_ECDH_COF_AES_KEY_WRAP.\n"); rc = CKR_CURVE_NOT_SUPPORTED; goto done; } ecdh_mech.mechanism = CKM_ECDH1_COFACTOR_DERIVE; break; case CKM_ECDH_X_AES_KEY_WRAP: if (curve_type != MONTGOMERY_CURVE) { TRACE_DEVEL("Curve not supported for CKM_ECDH_X_AES_KEY_WRAP.\n"); rc = CKR_CURVE_NOT_SUPPORTED; goto done; } ecdh_mech.mechanism = CKM_ECDH1_DERIVE; break; default: TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); rc = CKR_MECHANISM_INVALID; goto done; break; } /* Generate a temporary EC key pair using the same EC parameters */ ec_keygen_mech.mechanism = curve_type == MONTGOMERY_CURVE ? CKM_EC_MONTGOMERY_KEY_PAIR_GEN : CKM_EC_KEY_PAIR_GEN; ec_publ_key_tmpl[0] = *ec_params; rc = key_mgr_generate_key_pair(tokdata, sess, &ec_keygen_mech, ec_publ_key_tmpl, sizeof(ec_publ_key_tmpl) / sizeof(CK_ATTRIBUTE), ec_priv_key_tmpl, sizeof(ec_priv_key_tmpl) / sizeof(CK_ATTRIBUTE), &ec_publ_key_handle, &ec_priv_key_handle, FALSE, OP_KEYGEN); if (rc != CKR_OK) { TRACE_ERROR("Failed to generate temporary EC key pair: " "%s (0x%lx)\n", p11_get_ckr(rc), rc); goto done; } /* Get the (raw) size of the generated EC point */ rc = object_mgr_find_in_map1(tokdata, ec_publ_key_handle, &pub_key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to acquire key from EC public key handle.\n"); if (rc == CKR_OBJECT_HANDLE_INVALID) rc = CKR_KEY_HANDLE_INVALID; goto done; } rc = template_attribute_get_non_empty(pub_key_obj->template, CKA_EC_POINT, &ec_point); if (rc != CKR_OK) { TRACE_DEVEL("Failed to get CKA_EC_POINT.\n"); goto done; } if (curve_type == MONTGOMERY_CURVE) { /* Montgomery curves have a raw EC point */ pub_ec_point = ec_point->pValue; pub_ec_point_len = ec_point->ulValueLen; } else { rc = ber_decode_OCTET_STRING((CK_BYTE *)ec_point->pValue, ec_point->ulValueLen, &pub_ec_point, &pub_ec_point_len, &field_len); if (rc != CKR_OK || field_len != ec_point->ulValueLen) { rc = CKR_FUNCTION_FAILED; TRACE_DEVEL("Failed to decode CKA_EC_POINT.\n"); goto done; } } /* Perform ECDH to derive a shared AES key */ ecdh_params.kdf = params->kdf; ecdh_params.pSharedData = params->pSharedData; ecdh_params.ulSharedDataLen = params->ulSharedDataLen; rc = template_attribute_get_non_empty(key_obj->template, CKA_EC_POINT, &ec_point); if (rc != CKR_OK) { TRACE_DEVEL("Failed to get CKA_EC_POINT.\n"); goto done; } if (curve_type == MONTGOMERY_CURVE) { /* Montgomery curves have a raw EC point */ ecdh_params.pPublicData = ec_point->pValue; ecdh_params.ulPublicDataLen = ec_point->ulValueLen; } else { rc = ber_decode_OCTET_STRING((CK_BYTE *)ec_point->pValue, ec_point->ulValueLen, &ecdh_params.pPublicData, &ecdh_params.ulPublicDataLen, &field_len); if (rc != CKR_OK || field_len != ec_point->ulValueLen) { rc = CKR_FUNCTION_FAILED; TRACE_DEVEL("Failed to decode CKA_EC_POINT.\n"); goto done; } } aes_key_size = params->ulAESKeyBits / 8; rc = key_mgr_derive_key(tokdata, sess, &ecdh_mech, ec_priv_key_handle, &aes_key_handle, aes_key_tmpl, sizeof(aes_key_tmpl) / sizeof(CK_ATTRIBUTE), FALSE, OP_WRAP); if (rc != CKR_OK) { TRACE_ERROR("Failed to derive temporary AES key (%lu bits): " "%s (0x%lx)\n", params->ulAESKeyBits, p11_get_ckr(rc), rc); goto done; } /* * Encrypt (wrap) the to-be-wrapped key as the second part of the wrapped * key data (length-only operation to get the size of the second part). */ rc = encr_mgr_init(tokdata, sess, &aeskw_ctx, OP_WRAP, &aeskw_kwm_mech, aes_key_handle, TRUE); if (rc != CKR_OK) { TRACE_ERROR("Failed to encrypt the to-be-wrapped key: %s (0x%lx)\n", p11_get_ckr(rc), rc); goto done; } rc = encr_mgr_encrypt(tokdata, sess, TRUE, &aeskw_ctx, in_data, in_data_len, NULL, &wrapped_key_len); if (rc != CKR_OK) { TRACE_ERROR("Failed to encrypt the to-be-wrapped key: %s (0x%lx)\n", p11_get_ckr(rc), rc); goto done; } /* Calculate the final length of the wrapped key data */ total_len = pub_ec_point_len + wrapped_key_len; if (length_only) { *out_data_len = total_len; goto done; } if (*out_data_len < total_len) { *out_data_len = total_len; TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); rc = CKR_BUFFER_TOO_SMALL; goto done; } /* * Copy the (raw) EC point of the public transport EC key as first part of * the wrapped key data. */ memcpy(out_data, pub_ec_point, pub_ec_point_len); /* * Encrypt (wrap) the to-be-wrapped key as the second part of the wrapped * key data. */ rc = encr_mgr_encrypt(tokdata, sess, FALSE, &aeskw_ctx, in_data, in_data_len, out_data + pub_ec_point_len, &wrapped_key_len); if (rc != CKR_OK) { TRACE_ERROR("Failed to encrypt the to-be-wrapped key: %s (0x%lx)\n", p11_get_ckr(rc), rc); goto done; } *out_data_len = total_len; done: if (ec_publ_key_handle != CK_INVALID_HANDLE) { rc2 = object_mgr_destroy_object(tokdata, sess, ec_publ_key_handle); if (rc2 != CKR_OK) { TRACE_ERROR("Failed to destroy temporary EC public key: %s " "(0x%lx)\n", p11_get_ckr(rc2), rc2); if (rc == CKR_OK) rc = rc2; } } if (ec_priv_key_handle != CK_INVALID_HANDLE) { rc2 = object_mgr_destroy_object(tokdata, sess, ec_priv_key_handle); if (rc2 != CKR_OK) { TRACE_ERROR("Failed to destroy temporary EC private key: %s " "(0x%lx)\n", p11_get_ckr(rc2), rc2); if (rc == CKR_OK) rc = rc2; } } if (aes_key_handle != CK_INVALID_HANDLE) { rc2 = object_mgr_destroy_object(tokdata, sess, aes_key_handle); if (rc2 != CKR_OK) { TRACE_ERROR("Failed to destroy temporary AES key: %s (0x%lx)\n", p11_get_ckr(rc2), rc2); if (rc == CKR_OK) rc = rc2; } } encr_mgr_cleanup(tokdata, sess, &aeskw_ctx); object_put(tokdata, key_obj, TRUE); key_obj = NULL; object_put(tokdata, pub_key_obj, TRUE); pub_key_obj = NULL; return rc; } CK_RV ecdh_aes_key_unwrap(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_ECDH_AES_KEY_WRAP_PARAMS *params; CK_ECDH1_DERIVE_PARAMS ecdh_params = { 0 }; CK_MECHANISM ecdh_mech = { 0, &ecdh_params, sizeof(ecdh_params) }; CK_MECHANISM aeskw_kwm_mech = { CKM_AES_KEY_WRAP_KWP, NULL, 0 }; CK_OBJECT_HANDLE aes_key_handle = CK_INVALID_HANDLE; ENCR_DECR_CONTEXT aeskw_ctx = { 0 }; CK_BBOOL ck_true = TRUE; CK_BBOOL ck_false = TRUE; OBJECT *key_obj = NULL; CK_ULONG prime_len = 0, public_data_len = 0; CK_OBJECT_CLASS aes_key_class = CKO_SECRET_KEY; CK_KEY_TYPE aes_key_type = CKK_AES; CK_ULONG aes_key_size; CK_BYTE form; CK_ATTRIBUTE *ec_params; int curve_type; CK_RV rc, rc2; CK_ATTRIBUTE aes_key_tmpl[] = { { CKA_CLASS, &aes_key_class, sizeof(aes_key_class) }, { CKA_KEY_TYPE, &aes_key_type, sizeof(aes_key_type) }, { CKA_VALUE_LEN, &aes_key_size, sizeof(aes_key_size) }, { CKA_HIDDEN, &ck_true, sizeof(ck_true) }, { CKA_SENSITIVE, &ck_true, sizeof(ck_true) }, { CKA_TOKEN, &ck_false, sizeof(ck_false) }, { CKA_PRIVATE, &ck_true, sizeof(ck_true) }, { CKA_WRAP, &ck_false, sizeof(ck_false) }, { CKA_UNWRAP, &ck_true, sizeof(ck_true) }, { CKA_ENCRYPT, &ck_false, sizeof(ck_false) }, { CKA_DECRYPT, &ck_false, sizeof(ck_false) }, { CKA_SIGN, &ck_false, sizeof(ck_false) }, { CKA_VERIFY, &ck_false, sizeof(ck_false) }, { CKA_DERIVE, &ck_false, sizeof(ck_false) }, }; params = (CK_ECDH_AES_KEY_WRAP_PARAMS *)ctx->mech.pParameter; /* Get the EC parameters of the EC key used with this mechanism */ 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.\n"); if (rc == CKR_OBJECT_HANDLE_INVALID) return CKR_KEY_HANDLE_INVALID; else return rc; } rc = template_attribute_get_non_empty(key_obj->template, CKA_EC_PARAMS, &ec_params); if (rc != CKR_OK) { TRACE_DEVEL("Failed to get CKA_EC_PARAMS.\n"); goto done; } curve_type = ec_curve_type_from_oid(ec_params->pValue, ec_params->ulValueLen); if (curve_type < 0) { TRACE_DEVEL("Failed to get CKA_EC_PARAMS.\n"); rc = CKR_CURVE_NOT_SUPPORTED; goto done; } switch (ctx->mech.mechanism) { case CKM_ECDH_AES_KEY_WRAP: if (curve_type != PRIME_CURVE && curve_type != BRAINPOOL_CURVE && curve_type != KOBLITZ_CURVE && curve_type != MONTGOMERY_CURVE) { TRACE_DEVEL("Curve not supported for CKM_ECDH_AES_KEY_WRAP.\n"); rc = CKR_CURVE_NOT_SUPPORTED; goto done; } ecdh_mech.mechanism = CKM_ECDH1_DERIVE; break; case CKM_ECDH_COF_AES_KEY_WRAP: if (curve_type != PRIME_CURVE && curve_type != BRAINPOOL_CURVE && curve_type != KOBLITZ_CURVE) { TRACE_DEVEL("Curve not supported for CKM_ECDH_COF_AES_KEY_WRAP.\n"); rc = CKR_CURVE_NOT_SUPPORTED; goto done; } ecdh_mech.mechanism = CKM_ECDH1_COFACTOR_DERIVE; break; case CKM_ECDH_X_AES_KEY_WRAP: if (curve_type != MONTGOMERY_CURVE) { TRACE_DEVEL("Curve not supported for CKM_ECDH_X_AES_KEY_WRAP.\n"); rc = CKR_CURVE_NOT_SUPPORTED; goto done; } ecdh_mech.mechanism = CKM_ECDH1_DERIVE; break; default: TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); rc = CKR_MECHANISM_INVALID; goto done; break; } rc = get_ecsiglen(key_obj, &prime_len); if (rc != CKR_OK) { TRACE_DEVEL("get_ecsiglen failed.\n"); goto done; } prime_len /= 2; /* prime length is half the size of an EC signature */ if (curve_type == MONTGOMERY_CURVE) { /* Input must be at least a raw EC point plus wrapped data */ if (in_data_len < prime_len + 2 * AES_KEY_WRAP_BLOCK_SIZE) { TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_LEN_RANGE)); rc = CKR_ENCRYPTED_DATA_LEN_RANGE; goto done; } /* Montgomery keys have a raw EC point */ public_data_len = prime_len; } else { /* Input must be at least a compressed EC point plus wrapped data */ if (in_data_len < prime_len + 1 + 2 * AES_KEY_WRAP_BLOCK_SIZE) { TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_LEN_RANGE)); rc = CKR_ENCRYPTED_DATA_LEN_RANGE; goto done; } form = in_data[0] & ~0x01; switch (form) { case POINT_CONVERSION_COMPRESSED: public_data_len = prime_len + 1; /* Length checked above already */ break; case POINT_CONVERSION_UNCOMPRESSED: case POINT_CONVERSION_HYBRID: public_data_len = 2 * prime_len + 1; if (in_data_len < public_data_len + 2 * AES_KEY_WRAP_BLOCK_SIZE) { TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_LEN_RANGE)); rc = CKR_ENCRYPTED_DATA_LEN_RANGE; goto done; } break; default: TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_INVALID)); rc = CKR_ENCRYPTED_DATA_INVALID; goto done; } } /* Perform ECDH to derive a shared AES key */ ecdh_params.kdf = params->kdf; ecdh_params.pSharedData = params->pSharedData; ecdh_params.ulSharedDataLen = params->ulSharedDataLen; ecdh_params.pPublicData = in_data; ecdh_params.ulPublicDataLen = public_data_len; aes_key_size = params->ulAESKeyBits / 8; rc = key_mgr_derive_key(tokdata, sess, &ecdh_mech, ctx->key, &aes_key_handle, aes_key_tmpl, sizeof(aes_key_tmpl) / sizeof(CK_ATTRIBUTE), FALSE, OP_UNWRAP); if (rc != CKR_OK) { TRACE_ERROR("Failed to derive temporary AES key (%lu bits): " "%s (0x%lx)\n", params->ulAESKeyBits, p11_get_ckr(rc), rc); goto done; } /* * Decrypt (unwrap) the final key data from the the second part of the * wrapped key data. */ rc = decr_mgr_init(tokdata, sess, &aeskw_ctx, OP_UNWRAP, &aeskw_kwm_mech, aes_key_handle, TRUE, FALSE); if (rc != CKR_OK) { TRACE_ERROR("Failed to decrypt the to-be-unwrapped key: %s (0x%lx)\n", p11_get_ckr(rc), rc); goto done; } rc = decr_mgr_decrypt(tokdata, sess, length_only, &aeskw_ctx, in_data + public_data_len, in_data_len - public_data_len, out_data, out_data_len); if (rc != CKR_OK) { TRACE_ERROR("Failed to decrypt the to-be-unwrapped key: %s (0x%lx)\n", p11_get_ckr(rc), rc); goto done; } done: if (aes_key_handle != CK_INVALID_HANDLE) { rc2 = object_mgr_destroy_object(tokdata, sess, aes_key_handle); if (rc2 != CKR_OK) { TRACE_ERROR("Failed to destroy temporary AES key: %s (0x%lx)\n", p11_get_ckr(rc2), rc2); if (rc == CKR_OK) rc = rc2; } } encr_mgr_cleanup(tokdata, sess, &aeskw_ctx); object_put(tokdata, key_obj, TRUE); key_obj = NULL; return rc; } CK_RV ec_agg_dup_param(CK_IBM_ECDSA_OTHER_BLS_PARAMS *from, CK_IBM_ECDSA_OTHER_BLS_PARAMS *to) { CK_ULONG i; if (from == NULL || to == NULL) return CKR_ARGUMENTS_BAD; if (from->numElements != 0 && from->elementSize > 0) { for (i = 0; i < CK_IBM_BLS_MAX_AGGREGATIONS; i++) { if (i < from->numElements) { to->pAggrElements[i] = (CK_BYTE*)malloc(from->elementSize); if (to->pAggrElements[i] == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); ec_agg_free_param(to); return CKR_HOST_MEMORY; } memcpy(to->pAggrElements[i], from->pAggrElements[i], from->elementSize); } else { to->pAggrElements[i] = NULL; } } to->numElements = from->numElements; to->elementSize = from->elementSize; } else { to->numElements = 0; to->elementSize = 0; memset(to->pAggrElements, 0, sizeof(to->pAggrElements)); } return CKR_OK; } CK_RV ec_agg_free_param(CK_IBM_ECDSA_OTHER_BLS_PARAMS *params) { CK_ULONG i; if (params == NULL) return CKR_ARGUMENTS_BAD; for (i = 0; i < CK_IBM_BLS_MAX_AGGREGATIONS; i++) { free(params->pAggrElements[i]); params->pAggrElements[i] = NULL; } params->numElements = 0; params->elementSize = 0; return CKR_OK; } CK_RV ecdh_encapsulate_key(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, CK_MECHANISM *mech, OBJECT *public_key, CK_ATTRIBUTE *pTemplate, CK_ULONG ulAttributeCount, CK_BYTE *pCiphertext, CK_ULONG *pulCiphertextLen, CK_OBJECT_HANDLE *phKey) { CK_ECDH1_DERIVE_PARAMS ecdh_params, *params; CK_MECHANISM ec_keygen_mech = { 0, NULL, 0 }; CK_MECHANISM ecdh_mech; CK_ATTRIBUTE *ec_params = NULL, *ec_point = NULL; CK_OBJECT_HANDLE gen_ec_publ_key_handle = CK_INVALID_HANDLE; CK_OBJECT_HANDLE gen_ec_priv_key_handle = CK_INVALID_HANDLE; CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE; OBJECT *gen_pub_key_obj = NULL; CK_ULONG field_len = 0, gen_pub_ec_point_len = 0; CK_BYTE *gen_pub_ec_point = NULL; CK_BBOOL ck_true = TRUE; CK_BBOOL ck_false = TRUE; int curve_type; CK_KEY_TYPE decaps_key_type; CK_ULONG decaps_tmpl_num = 0, decaps_key_len; CK_IBM_CCA_AES_KEY_MODE_TYPE decaps_cca_key_mode; CK_RV rc, rc2; CK_ATTRIBUTE decaps_tmpl[3] = { 0 }; CK_ATTRIBUTE ec_publ_key_tmpl[] = { { CKA_EC_PARAMS, NULL, 0 }, /* must be first */ { CKA_HIDDEN, &ck_true, sizeof(ck_true) }, { CKA_TOKEN, &ck_false, sizeof(ck_false) }, { CKA_PRIVATE, &ck_true, sizeof(ck_true) }, { CKA_ENCAPSULATE, &ck_true, sizeof(ck_true) }, { CKA_WRAP, &ck_false, sizeof(ck_false) }, { CKA_ENCRYPT, &ck_false, sizeof(ck_false) }, { CKA_VERIFY, &ck_false, sizeof(ck_false) }, { CKA_VERIFY_RECOVER, &ck_false, sizeof(ck_false) }, { CKA_DERIVE, &ck_true, sizeof(ck_true) }, }; CK_ATTRIBUTE ec_priv_key_tmpl[] = { { CKA_DECAPSULATE_TEMPLATE, decaps_tmpl, 0 }, /* must be first */ { CKA_HIDDEN, &ck_true, sizeof(ck_true) }, { CKA_SENSITIVE, &ck_true, sizeof(ck_true) }, { CKA_TOKEN, &ck_false, sizeof(ck_false) }, { CKA_PRIVATE, &ck_true, sizeof(ck_true) }, { CKA_UNWRAP, &ck_false, sizeof(ck_false) }, { CKA_DECRYPT, &ck_false, sizeof(ck_false) }, { CKA_SIGN, &ck_false, sizeof(ck_false) }, { CKA_SIGN_RECOVER, &ck_false, sizeof(ck_false) }, { CKA_DERIVE, &ck_true, sizeof(ck_true) }, { CKA_DECAPSULATE, &ck_true, sizeof(ck_true) }, }; if (mech->ulParameterLen != sizeof(CK_ECDH1_DERIVE_PARAMS) || mech->pParameter == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); return CKR_MECHANISM_PARAM_INVALID; } params = mech->pParameter; /* pPublicData and ulPublicDataLen must be NULL and 0 */ if (params->pPublicData != NULL || params->ulPublicDataLen != 0) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); return CKR_MECHANISM_PARAM_INVALID; } rc = template_attribute_get_non_empty(public_key->template, CKA_EC_PARAMS, &ec_params); if (rc != CKR_OK) { TRACE_DEVEL("Failed to get CKA_EC_PARAMS.\n"); goto done; } curve_type = ec_curve_type_from_oid(ec_params->pValue, ec_params->ulValueLen); if (curve_type == -1 || curve_type == EDWARDS_CURVE || curve_type == BLS12_381_CURVE) { TRACE_DEVEL("Only EC or Montgomery curves are supported.\n"); rc = CKR_CURVE_NOT_SUPPORTED; goto done; } /* Supply CKA_DECAPSULATE_TEMPLATE contents (required by CCA token) */ rc = get_ulong_attribute_by_type(pTemplate, ulAttributeCount, CKA_KEY_TYPE, &decaps_key_type); if (rc == CKR_OK) { decaps_tmpl[decaps_tmpl_num].type = CKA_KEY_TYPE; decaps_tmpl[decaps_tmpl_num].pValue = &decaps_key_type; decaps_tmpl[decaps_tmpl_num].ulValueLen = sizeof(decaps_key_type); decaps_tmpl_num++; } rc = get_ulong_attribute_by_type(pTemplate, ulAttributeCount, CKA_VALUE_LEN, &decaps_key_len); if (rc == CKR_OK) { decaps_tmpl[decaps_tmpl_num].type = CKA_VALUE_LEN; decaps_tmpl[decaps_tmpl_num].pValue = &decaps_key_len; decaps_tmpl[decaps_tmpl_num].ulValueLen = sizeof(decaps_key_len); decaps_tmpl_num++; } rc = get_ulong_attribute_by_type(pTemplate, ulAttributeCount, CKA_IBM_CCA_AES_KEY_MODE, &decaps_cca_key_mode); if (rc == CKR_OK) { decaps_tmpl[decaps_tmpl_num].type = CKA_IBM_CCA_AES_KEY_MODE; decaps_tmpl[decaps_tmpl_num].pValue = &decaps_cca_key_mode; decaps_tmpl[decaps_tmpl_num].ulValueLen = sizeof(decaps_cca_key_mode); decaps_tmpl_num++; } ec_priv_key_tmpl[0].ulValueLen = decaps_tmpl_num * sizeof(CK_ATTRIBUTE); /* Generate a temporary EC key pair using the same EC parameters */ ec_keygen_mech.mechanism = curve_type == MONTGOMERY_CURVE ? CKM_EC_MONTGOMERY_KEY_PAIR_GEN : CKM_EC_KEY_PAIR_GEN; ec_publ_key_tmpl[0] = *ec_params; if (token_specific.t_encapsulate_dh_ecdh_key_pair_gen != NULL) { rc = token_specific.t_encapsulate_dh_ecdh_key_pair_gen( tokdata, sess,&ec_keygen_mech, ec_publ_key_tmpl, sizeof(ec_publ_key_tmpl) / sizeof(CK_ATTRIBUTE), ec_priv_key_tmpl, sizeof(ec_priv_key_tmpl) / sizeof(CK_ATTRIBUTE), &gen_ec_publ_key_handle, &gen_ec_priv_key_handle); if (rc != CKR_OK) { TRACE_DEVEL("token specific encapsulate_dh_ecdh_key_pair_gen " "failed to generate temporary EC key pair: %s " "(0x%lx)\n", p11_get_ckr(rc), rc); goto done; } } else { rc = key_mgr_generate_key_pair(tokdata, sess, &ec_keygen_mech, ec_publ_key_tmpl, sizeof(ec_publ_key_tmpl) / sizeof(CK_ATTRIBUTE), ec_priv_key_tmpl, sizeof(ec_priv_key_tmpl) / sizeof(CK_ATTRIBUTE), &gen_ec_publ_key_handle, &gen_ec_priv_key_handle, FALSE, OP_ENCAPSULATE); if (rc != CKR_OK) { TRACE_ERROR("key_mgr_generate_key_pair failed to generate " "temporary EC key pair: %s (0x%lx)\n", p11_get_ckr(rc), rc); goto done; } } /* Get the (raw) size of the generated EC point */ rc = object_mgr_find_in_map1(tokdata, gen_ec_publ_key_handle, &gen_pub_key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to acquire key from EC public key handle.\n"); if (rc == CKR_OBJECT_HANDLE_INVALID) rc = CKR_KEY_HANDLE_INVALID; goto done; } rc = template_attribute_get_non_empty(gen_pub_key_obj->template, CKA_EC_POINT, &ec_point); if (rc != CKR_OK) { TRACE_DEVEL("Failed to get CKA_EC_POINT.\n"); goto done; } if (curve_type != MONTGOMERY_CURVE) { rc = ber_decode_OCTET_STRING((CK_BYTE *)ec_point->pValue, ec_point->ulValueLen, &gen_pub_ec_point, &gen_pub_ec_point_len, &field_len); if (rc != CKR_OK || field_len != ec_point->ulValueLen) { rc = CKR_FUNCTION_FAILED; TRACE_DEVEL("Failed to decode CKA_EC_POINT.\n"); goto done; } } else { gen_pub_ec_point = ec_point->pValue; gen_pub_ec_point_len = ec_point->ulValueLen; } if (length_only) { *pulCiphertextLen = gen_pub_ec_point_len; goto done; } if (*pulCiphertextLen < gen_pub_ec_point_len) { *pulCiphertextLen = gen_pub_ec_point_len; rc = CKR_BUFFER_TOO_SMALL; goto done; } rc = template_attribute_get_non_empty(public_key->template, CKA_EC_POINT, &ec_point); if (rc != CKR_OK) { TRACE_DEVEL("Failed to get CKA_EC_POINT.\n"); goto done; } ecdh_params = *params; ecdh_params.pPublicData = ec_point->pValue; ecdh_params.ulPublicDataLen = ec_point->ulValueLen; ecdh_mech.mechanism = mech->mechanism; ecdh_mech.pParameter = &ecdh_params; ecdh_mech.ulParameterLen = sizeof(ecdh_params); if (token_specific.t_en_decapsulate_dh_ecdh_derive_key != NULL) { rc = token_specific.t_en_decapsulate_dh_ecdh_derive_key( tokdata, sess, &ecdh_mech, gen_ec_priv_key_handle, &hKey, pTemplate, ulAttributeCount, OP_ENCAPSULATE); if (rc != CKR_OK) { TRACE_DEVEL("token specific en_decapsulate_dh_ecdh_derive_key " "failed.\n"); goto done; } } else { rc = key_mgr_derive_key(tokdata, sess, &ecdh_mech, gen_ec_priv_key_handle, &hKey, pTemplate, ulAttributeCount, FALSE, OP_ENCAPSULATE); if (rc != CKR_OK) { TRACE_DEVEL("key_mgr_derive_key failed.\n"); goto done; } } *pulCiphertextLen = gen_pub_ec_point_len; memcpy(pCiphertext, gen_pub_ec_point, gen_pub_ec_point_len); *phKey = hKey; done: if (gen_ec_publ_key_handle != CK_INVALID_HANDLE) { rc2 = object_mgr_destroy_object(tokdata, sess, gen_ec_publ_key_handle); if (rc2 != CKR_OK) { TRACE_ERROR("Failed to destroy temporary EC public key: %s " "(0x%lx)\n", p11_get_ckr(rc2), rc2); if (rc == CKR_OK) rc = rc2; } } if (gen_ec_priv_key_handle != CK_INVALID_HANDLE) { rc2 = object_mgr_destroy_object(tokdata, sess, gen_ec_priv_key_handle); if (rc2 != CKR_OK) { TRACE_ERROR("Failed to destroy temporary EC private key: %s " "(0x%lx)\n", p11_get_ckr(rc2), rc2); if (rc == CKR_OK) rc = rc2; } } if (rc != CKR_OK && hKey != CK_INVALID_HANDLE) { rc2 = object_mgr_destroy_object(tokdata, sess, hKey); if (rc2 != CKR_OK) { TRACE_ERROR("Failed to destroy deriv ed secret key: %s " "(0x%lx)\n", p11_get_ckr(rc2), rc2); if (rc == CKR_OK) rc = rc2; } } object_put(tokdata, gen_pub_key_obj, TRUE); gen_pub_key_obj = NULL; return rc; } CK_RV ecdh_decapsulate_key(STDLL_TokData_t *tokdata, SESSION *sess, CK_MECHANISM *mech, OBJECT *private_key, CK_ATTRIBUTE *pTemplate, CK_ULONG ulAttributeCount, CK_BYTE *pCiphertext, CK_ULONG ulCiphertextLen, CK_OBJECT_HANDLE *phKey) { CK_ECDH1_DERIVE_PARAMS ecdh_params, *params; CK_MECHANISM ecdh_mech; CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE; CK_RV rc; if (mech->ulParameterLen != sizeof(CK_ECDH1_DERIVE_PARAMS) || mech->pParameter == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); return CKR_MECHANISM_PARAM_INVALID; } params = mech->pParameter; /* pPublicData and ulPublicDataLen must be NULL and 0 */ if (params->pPublicData != NULL || params->ulPublicDataLen != 0) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); return CKR_MECHANISM_PARAM_INVALID; } ecdh_params = *params; ecdh_params.pPublicData = pCiphertext; ecdh_params.ulPublicDataLen = ulCiphertextLen; ecdh_mech.mechanism = mech->mechanism; ecdh_mech.pParameter = &ecdh_params; ecdh_mech.ulParameterLen = sizeof(ecdh_params); if (token_specific.t_en_decapsulate_dh_ecdh_derive_key != NULL) { rc = token_specific.t_en_decapsulate_dh_ecdh_derive_key( tokdata, sess, &ecdh_mech, private_key->map_handle, &hKey, pTemplate, ulAttributeCount, OP_DECAPSULATE); if (rc != CKR_OK) { TRACE_DEVEL("token specific en_decapsulate_dh_ecdh_derive_key " "failed.\n"); goto done; } } else { rc = key_mgr_derive_key(tokdata, sess, &ecdh_mech, private_key->map_handle, &hKey, pTemplate, ulAttributeCount, FALSE, OP_DECAPSULATE); if (rc != CKR_OK) { TRACE_DEVEL("key_mgr_derive_key failed.\n"); goto done; } } *phKey = hKey; done: return rc; } opencryptoki-opencryptoki-451d99c/usr/lib/common/mech_list.c000066400000000000000000000136531520105705100243160ustar00rootroot00000000000000/* * 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" #include "p11util.h" #include "mechtable.h" CK_RV ock_generic_filter_mechanism_list(STDLL_TokData_t *tokdata, const MECH_LIST_ELEMENT *list, CK_ULONG listlen, MECH_LIST_ELEMENT **reslist, CK_ULONG *reslen) { CK_ULONG i, j; *reslist = calloc(listlen, sizeof(MECH_LIST_ELEMENT)); if (!*reslist) return CKR_HOST_MEMORY; for (i = 0, j = 0; i < listlen; ++i) { memcpy(*reslist + j, list + i, sizeof(MECH_LIST_ELEMENT)); if (tokdata->policy->update_mech_info(tokdata->policy, (*reslist)[j].mech_type, &(*reslist)[j].mech_info) == CKR_OK) ++j; } *reslen = j; *reslist = realloc(*reslist, sizeof(MECH_LIST_ELEMENT) * j); return CKR_OK; } CK_RV ock_generic_get_mechanism_list(STDLL_TokData_t * tokdata, CK_MECHANISM_TYPE_PTR pMechanismList, CK_ULONG_PTR pulCount, CK_BBOOL (*filter_mechanism) (STDLL_TokData_t *tokdata, CK_MECHANISM_TYPE mechanism, CK_MECHANISM_INFO *info)) { int rc = CKR_OK; unsigned int i, j; for (i = 0, j = 0; i < tokdata->mech_list_len; i++) { if (filter_mechanism == NULL || filter_mechanism(tokdata, tokdata->mech_list[i].mech_type, NULL)) { if (pMechanismList != NULL) { if ((*pulCount) <= j) rc = CKR_BUFFER_TOO_SMALL; else pMechanismList[j] = tokdata->mech_list[i].mech_type; } j++; } } (*pulCount) = j; if (rc == CKR_BUFFER_TOO_SMALL) { TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); } return rc; } CK_RV ock_generic_get_mechanism_info(STDLL_TokData_t * tokdata, CK_MECHANISM_TYPE type, CK_MECHANISM_INFO_PTR pInfo, CK_BBOOL (*filter_mechanism) (STDLL_TokData_t *tokdata, CK_MECHANISM_TYPE mechanism, CK_MECHANISM_INFO *info)) { CK_MECHANISM_INFO info; int rc = CKR_OK; unsigned int i; for (i = 0; i < tokdata->mech_list_len; i++) { if (tokdata->mech_list[i].mech_type == type) { info = tokdata->mech_list[i].mech_info; if (filter_mechanism == NULL || filter_mechanism(tokdata, type, &info)) { *pInfo = info; goto out; } else { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); rc = CKR_MECHANISM_INVALID; 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) { CK_ULONG i; if (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; } } } } /* * Compare the 2 mechanisms alphabetically, this gives the best sorting result. */ static int compare_mech(const void *p1, const void *p2, void *arg) { const struct mechtable_funcs *mechtable_funcs = arg; return strcmp(p11_get_ckm(mechtable_funcs, *((CK_MECHANISM_TYPE *)p1)), p11_get_ckm(mechtable_funcs, *((CK_MECHANISM_TYPE *)p2))); } #if defined(_AIX) /* This must be a thread local variable ! */ __thread const struct mechtable_funcs *thread_local_mechtable_funcs = NULL; static int compare_mech_aix(const void *p1, const void *p2) { if (thread_local_mechtable_funcs == NULL) return 0; return compare_mech(p1, p2, (void *)thread_local_mechtable_funcs); } #endif static void sort_mech_list(STDLL_TokData_t *tokdata, CK_MECHANISM_TYPE_PTR mech_arr_ptr, CK_ULONG count) { #if defined(_AIX) thread_local_mechtable_funcs = tokdata->mechtable_funcs; qsort(mech_arr_ptr, count, sizeof(CK_MECHANISM_TYPE), compare_mech_aix); thread_local_mechtable_funcs = NULL; #else qsort_r(mech_arr_ptr, count, sizeof(CK_MECHANISM_TYPE), compare_mech, (void *)tokdata->mechtable_funcs); #endif } void mechanism_list_transformations(STDLL_TokData_t *tokdata, CK_MECHANISM_TYPE_PTR mech_arr_ptr, CK_ULONG_PTR count_ptr) { if (mech_arr_ptr == NULL) return; netscape_hack(mech_arr_ptr, (*count_ptr)); sort_mech_list(tokdata, mech_arr_ptr, (*count_ptr)); } opencryptoki-opencryptoki-451d99c/usr/lib/common/mech_md2.c000066400000000000000000000355131520105705100240240ustar00rootroot00000000000000/* * 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 #if !(NOMD2) // 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.\n"); if (rc == CKR_OBJECT_HANDLE_INVALID) return CKR_KEY_HANDLE_INVALID; else return rc; } rc = template_attribute_get_non_empty(key_obj->template, CKA_VALUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE in the template\n"); 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, FALSE); 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"); digest_mgr_cleanup(tokdata, sess, &digest_ctx); 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, FALSE); 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, FALSE); 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, FALSE); 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]; } #endif opencryptoki-opencryptoki-451d99c/usr/lib/common/mech_md5.c000066400000000000000000000177141520105705100240320ustar00rootroot00000000000000/* * 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) // static void sw_md5_free(STDLL_TokData_t *tokdata, SESSION *sess, CK_BYTE *context, CK_ULONG context_len) { UNUSED(tokdata); UNUSED(sess); UNUSED(context_len); EVP_MD_CTX_free((EVP_MD_CTX *)context); } CK_RV sw_md5_init(DIGEST_CONTEXT *ctx) { ctx->context_len = 1; ctx->context = (CK_BYTE *)EVP_MD_CTX_new(); if (ctx->context == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); ctx->context_len = 0; return CKR_HOST_MEMORY; } if (!EVP_DigestInit_ex((EVP_MD_CTX *)ctx->context, EVP_md5(), NULL)) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); EVP_MD_CTX_free((EVP_MD_CTX *)ctx->context); ctx->context = NULL; ctx->context_len = 0; return CKR_FUNCTION_FAILED; } ctx->state_unsaveable = CK_TRUE; ctx->context_free_func = sw_md5_free; return CKR_OK; } 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) { unsigned int 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; len = *out_data_len; if (!EVP_DigestUpdate((EVP_MD_CTX *)ctx->context, in_data, in_data_len) || !EVP_DigestFinal((EVP_MD_CTX *)ctx->context, out_data, &len)) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } *out_data_len = len; EVP_MD_CTX_free((EVP_MD_CTX *)ctx->context); ctx->context = NULL; ctx->context_free_func = NULL; return CKR_OK; } static 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; if (!EVP_DigestUpdate((EVP_MD_CTX *)ctx->context, in_data, in_data_len)) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } return CKR_OK; } static CK_RV sw_md5_final(DIGEST_CONTEXT *ctx, CK_BYTE *out_data, CK_ULONG *out_data_len) { unsigned int len; if (ctx->context == NULL) return CKR_OPERATION_NOT_INITIALIZED; if (*out_data_len < MD5_HASH_SIZE) { TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); return CKR_BUFFER_TOO_SMALL; } len = *out_data_len; if (!EVP_DigestFinal((EVP_MD_CTX *)ctx->context, out_data, &len)) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } *out_data_len = len; EVP_MD_CTX_free((EVP_MD_CTX *)ctx->context); ctx->context = NULL; ctx->context_free_func = 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) { return sw_md5_init(ctx); } 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) { CK_ULONG hmac_len; 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; } rc = openssl_specific_hmac_init(tokdata, ctx, &ctx->mech, ctx->key); if (rc != CKR_OK) return rc; rc = openssl_specific_hmac(ctx, in_data, in_data_len, out_data, out_data_len, TRUE); if (rc != CKR_OK) return rc; return CKR_OK; } 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_RV rc; if (!sess || !ctx || !signature) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } rc = openssl_specific_hmac_init(tokdata, ctx, &ctx->mech, ctx->key); if (rc != CKR_OK) return rc; rc = openssl_specific_hmac(ctx, in_data, in_data_len, signature, &sig_len, FALSE); if (rc != CKR_OK) return rc; return CKR_OK; } opencryptoki-opencryptoki-451d99c/usr/lib/common/mech_openssl.c000066400000000000000000010277331520105705100250330ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021 * * 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 "defs.h" #include "host_defs.h" #include "h_extern.h" #include "tok_spec_struct.h" #include "trace.h" #include "ec_defs.h" #include "attributes.h" #include #include #include #include #include #include #include #include #include #if OPENSSL_VERSION_PREREQ(3, 0) #include #include #define SN_Ed25519 "Ed25519" #define SN_Ed25519ph "Ed25519ph" #define SN_Ed25519ctx "Ed25519ctx" #define SN_Ed448 "Ed448" #define SN_Ed448ph "Ed448ph" #ifndef OSSL_PKEY_PARAM_ML_DSA_SEED #define OSSL_PKEY_PARAM_ML_DSA_SEED "seed" #endif #ifndef OSSL_PKEY_PARAM_ML_KEM_SEED #define OSSL_PKEY_PARAM_ML_KEM_SEED "seed" #endif #endif void openssl_free_ex_data(OBJECT *obj, void *ex_data, size_t ex_data_len) { struct openssl_ex_data *data = ex_data; if (ex_data == NULL || ex_data_len < sizeof(struct openssl_ex_data)) return; if (data->pkey != NULL) { EVP_PKEY_free(data->pkey); data->pkey = NULL; } free(data); obj->ex_data = NULL; obj->ex_data_len = 0; } CK_RV openssl_reload_ex_data(OBJECT *obj, void *ex_data, size_t ex_data_len) { if (obj->ex_data_free != NULL) obj->ex_data_free(obj, ex_data, ex_data_len); return CKR_OK; } /* * Gets the attached OpenSSL ex_data from the key object. If no ex_data is * attached yet, then a WRITE lock is obtained, the ex_data is allocated in the * specified size, and the ex_data is returned. If the ex_data is already * attached, the need_wr_lock routine is called to determine if a WRTE lock is * needed. If the need_wr_lock routine returns TRUE, a WRITE lock is obtained, * else, or if no need_wr_lock routine is specified, a READ lock is obtained * and the ex_data is returned. The caller must release ex-data lock when * finished working with it. */ CK_RV openssl_get_ex_data(OBJECT *obj, void **ex_data, size_t ex_data_len, CK_BBOOL (*need_wr_lock)(OBJECT *obj, void *ex_data, size_t ex_data_len), void (*ex_data_free)(struct _OBJECT *obj, void *ex_data, size_t ex_data_len)) { CK_RV rc; rc = object_ex_data_lock(obj, READ_LOCK); if (rc != CKR_OK) return rc; if (obj->ex_data != NULL && obj->ex_data_len >= ex_data_len && (need_wr_lock == NULL || need_wr_lock(obj, obj->ex_data, obj->ex_data_len) == FALSE)) { *ex_data = obj->ex_data; return CKR_OK; } rc = object_ex_data_unlock(obj); if (rc != CKR_OK) return rc; rc = object_ex_data_lock(obj, WRITE_LOCK); if (rc != CKR_OK) return rc; if (obj->ex_data == NULL) { obj->ex_data = calloc(1, ex_data_len); if (obj->ex_data == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); object_ex_data_unlock(obj); return CKR_HOST_MEMORY; } obj->ex_data_len = ex_data_len; obj->ex_data_free = ex_data_free != NULL ? ex_data_free : openssl_free_ex_data; obj->ex_data_reload = openssl_reload_ex_data; } *ex_data = obj->ex_data; return CKR_OK; } static CK_BBOOL openssl_need_wr_lock(OBJECT *obj, void *ex_data, size_t ex_data_len) { struct openssl_ex_data *data = ex_data; UNUSED(obj); if (ex_data == NULL || ex_data_len < sizeof(struct openssl_ex_data)) return FALSE; return data->pkey == NULL; } CK_RV openssl_specific_rsa_keygen(TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl) { CK_ATTRIBUTE *publ_exp = NULL; CK_ATTRIBUTE *attr = NULL; CK_ULONG mod_bits; CK_BBOOL flag; CK_RV rc; CK_ULONG BNLength; #if !OPENSSL_VERSION_PREREQ(3, 0) const RSA *rsa = NULL; const BIGNUM *bignum = NULL; #else BIGNUM *bignum = NULL; int try; #endif CK_BYTE *ssl_ptr = NULL; BIGNUM *e = NULL; EVP_PKEY *pkey = NULL; EVP_PKEY_CTX *ctx = NULL; rc = template_attribute_get_ulong(publ_tmpl, CKA_MODULUS_BITS, &mod_bits); if (rc != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); return CKR_TEMPLATE_INCOMPLETE; // should never happen } // we don't support less than 512 bit keys in the sw if (mod_bits < 512 || mod_bits > OPENSSL_RSA_MAX_MODULUS_BITS) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_SIZE_RANGE)); return CKR_KEY_SIZE_RANGE; } rc = template_attribute_get_non_empty(publ_tmpl, CKA_PUBLIC_EXPONENT, &publ_exp); if (rc != CKR_OK) { 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(); if (e == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); return CKR_HOST_MEMORY; } BN_bin2bn(publ_exp->pValue, publ_exp->ulValueLen, e); ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL); if (ctx == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto done; } if (EVP_PKEY_keygen_init(ctx) != 1) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto done; } if (mod_bits > INT_MAX || EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, mod_bits) != 1) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto done; } #if !OPENSSL_VERSION_PREREQ(3, 0) if (EVP_PKEY_CTX_set_rsa_keygen_pubexp(ctx, e) != 1) { #else if (EVP_PKEY_CTX_set1_rsa_keygen_pubexp(ctx, e) != 1) { #endif TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto done; } #if !OPENSSL_VERSION_PREREQ(3, 0) e = NULL; // will be freed as part of the context #endif #if OPENSSL_VERSION_PREREQ(3, 0) /* * In OpenSSL 3.0 the RSA key gen algorithm has been changed and can now * fail to generate a key. Retry up to 10 times in such a case. */ for (try = 1; try <= 10; try++) { if (EVP_PKEY_keygen(ctx, &pkey) == 1) { rc = CKR_OK; break; } TRACE_ERROR("%s (try %d)\n", ock_err(ERR_FUNCTION_FAILED), try); rc = CKR_FUNCTION_FAILED; } if (rc != CKR_OK) goto done; #else if (EVP_PKEY_keygen(ctx, &pkey) != 1) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto done; } #endif #if !OPENSSL_VERSION_PREREQ(3, 0) if ((rsa = EVP_PKEY_get0_RSA(pkey)) == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto done; } RSA_get0_key(rsa, &bignum, NULL, NULL); #else if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_N, &bignum)) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto done; } #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; } rc = template_update_attribute(publ_tmpl, attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); free(attr); goto done; } free(ssl_ptr); ssl_ptr = NULL; #if OPENSSL_VERSION_PREREQ(3, 0) BN_free(bignum); bignum = NULL; #endif // Public Exponent #if !OPENSSL_VERSION_PREREQ(3, 0) RSA_get0_key(rsa, NULL, &bignum, NULL); #else if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_E, &bignum)) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto done; } #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; } rc = template_update_attribute(publ_tmpl, attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); free(attr); goto done; } /* 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; } rc = template_update_attribute(priv_tmpl, attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); free(attr); goto done; } free(ssl_ptr); ssl_ptr = NULL; #if OPENSSL_VERSION_PREREQ(3, 0) BN_free(bignum); bignum = NULL; #endif // 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; } rc = template_update_attribute(publ_tmpl, attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); free(attr); goto done; } // // 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 #if !OPENSSL_VERSION_PREREQ(3, 0) RSA_get0_key(rsa, &bignum, NULL, NULL); #else if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_N, &bignum)) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto done; } #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; } rc = template_update_attribute(priv_tmpl, attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); free(attr); goto done; } free(ssl_ptr); ssl_ptr = NULL; #if OPENSSL_VERSION_PREREQ(3, 0) BN_free(bignum); bignum = NULL; #endif // Private Exponent #if !OPENSSL_VERSION_PREREQ(3, 0) RSA_get0_key(rsa, NULL, NULL, &bignum); #else if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_D, &bignum)) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto done; } #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; } rc = template_update_attribute(priv_tmpl, attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); OPENSSL_cleanse(attr, sizeof(CK_ATTRIBUTE) + attr->ulValueLen); free(attr); goto done; } OPENSSL_cleanse(ssl_ptr, BNLength); free(ssl_ptr); ssl_ptr = NULL; #if OPENSSL_VERSION_PREREQ(3, 0) BN_free(bignum); bignum = NULL; #endif // prime #1: p #if !OPENSSL_VERSION_PREREQ(3, 0) RSA_get0_factors(rsa, &bignum, NULL); #else if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_FACTOR1, &bignum)) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto done; } #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; } rc = template_update_attribute(priv_tmpl, attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); OPENSSL_cleanse(attr, sizeof(CK_ATTRIBUTE) + attr->ulValueLen); free(attr); goto done; } OPENSSL_cleanse(ssl_ptr, BNLength); free(ssl_ptr); ssl_ptr = NULL; #if OPENSSL_VERSION_PREREQ(3, 0) BN_free(bignum); bignum = NULL; #endif // prime #2: q #if !OPENSSL_VERSION_PREREQ(3, 0) RSA_get0_factors(rsa, NULL, &bignum); #else if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_FACTOR2, &bignum)) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto done; } #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; } rc = template_update_attribute(priv_tmpl, attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); OPENSSL_cleanse(attr, sizeof(CK_ATTRIBUTE) + attr->ulValueLen); free(attr); goto done; } OPENSSL_cleanse(ssl_ptr, BNLength); free(ssl_ptr); ssl_ptr = NULL; #if OPENSSL_VERSION_PREREQ(3, 0) BN_free(bignum); bignum = NULL; #endif // exponent 1: d mod(p-1) #if !OPENSSL_VERSION_PREREQ(3, 0) RSA_get0_crt_params(rsa, &bignum, NULL, NULL); #else if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_EXPONENT1, &bignum)) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto done; } #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; } rc = template_update_attribute(priv_tmpl, attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); OPENSSL_cleanse(attr, sizeof(CK_ATTRIBUTE) + attr->ulValueLen); free(attr); goto done; } OPENSSL_cleanse(ssl_ptr, BNLength); free(ssl_ptr); ssl_ptr = NULL; #if OPENSSL_VERSION_PREREQ(3, 0) BN_free(bignum); bignum = NULL; #endif // exponent 2: d mod(q-1) #if !OPENSSL_VERSION_PREREQ(3, 0) RSA_get0_crt_params(rsa, NULL, &bignum, NULL); #else if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_EXPONENT2, &bignum)) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto done; } #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; } rc = template_update_attribute(priv_tmpl, attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); OPENSSL_cleanse(attr, sizeof(CK_ATTRIBUTE) + attr->ulValueLen); free(attr); goto done; } OPENSSL_cleanse(ssl_ptr, BNLength); free(ssl_ptr); ssl_ptr = NULL; #if OPENSSL_VERSION_PREREQ(3, 0) BN_free(bignum); bignum = NULL; #endif // CRT coefficient: q_inverse mod(p) #if !OPENSSL_VERSION_PREREQ(3, 0) RSA_get0_crt_params(rsa, NULL, NULL, &bignum); #else if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_COEFFICIENT1, &bignum)) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto done; } #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; } rc = template_update_attribute(priv_tmpl, attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); OPENSSL_cleanse(attr, sizeof(CK_ATTRIBUTE) + attr->ulValueLen); free(attr); goto done; } OPENSSL_cleanse(ssl_ptr, BNLength); free(ssl_ptr); ssl_ptr = NULL; #if OPENSSL_VERSION_PREREQ(3, 0) BN_free(bignum); bignum = NULL; #endif flag = TRUE; rc = build_attribute(CKA_LOCAL, &flag, sizeof(CK_BBOOL), &attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto done; } rc = template_update_attribute(priv_tmpl, attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); free(attr); goto done; } done: if (ssl_ptr != NULL) { OPENSSL_cleanse(ssl_ptr, BNLength); free(ssl_ptr); } if (pkey != NULL) EVP_PKEY_free(pkey); if (ctx != NULL) EVP_PKEY_CTX_free(ctx); if (e != NULL) BN_free(e); #if OPENSSL_VERSION_PREREQ(3, 0) if (bignum != NULL) BN_free(bignum); #endif return rc; } // convert from the local PKCS11 template representation to // the underlying requirement // returns the pointer to the local key representation static EVP_PKEY *rsa_convert_public_key(OBJECT *key_obj) { CK_BBOOL rc; CK_ATTRIBUTE *modulus = NULL; CK_ATTRIBUTE *pub_exp = NULL; EVP_PKEY *pkey = NULL; BIGNUM *bn_mod, *bn_exp; #if OPENSSL_VERSION_PREREQ(3, 0) EVP_PKEY_CTX *pctx = NULL; OSSL_PARAM_BLD *tmpl = NULL; OSSL_PARAM *params = NULL; #else RSA *rsa; #endif rc = template_attribute_get_non_empty(key_obj->template, CKA_MODULUS, &modulus); if (rc != CKR_OK) return NULL; rc = template_attribute_get_non_empty(key_obj->template, CKA_PUBLIC_EXPONENT, &pub_exp); if (rc != CKR_OK) return NULL; // Create and init BIGNUM structs 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); return NULL; } // Convert from strings to BIGNUMs BN_bin2bn((unsigned char *) modulus->pValue, modulus->ulValueLen, bn_mod); BN_bin2bn((unsigned char *) pub_exp->pValue, pub_exp->ulValueLen, bn_exp); #if !OPENSSL_VERSION_PREREQ(3, 0) // Create an RSA key struct to return rsa = RSA_new(); if (rsa == NULL) { if (bn_mod) free(bn_mod); if (bn_exp) free(bn_exp); return NULL; } RSA_set0_key(rsa, bn_mod, bn_exp, NULL); pkey = EVP_PKEY_new(); if (pkey == NULL) { RSA_free(rsa); return NULL; } if (EVP_PKEY_assign_RSA(pkey, rsa) != 1) { RSA_free(rsa); EVP_PKEY_free(pkey); return NULL; } #else tmpl = OSSL_PARAM_BLD_new(); if (tmpl == NULL) goto out; if (!OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_RSA_N, bn_mod) || !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_RSA_E, bn_exp)) goto out; params = OSSL_PARAM_BLD_to_param(tmpl); if (params == NULL) goto out; pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL); if (pctx == NULL) goto out; if (!EVP_PKEY_fromdata_init(pctx) || !EVP_PKEY_fromdata(pctx, &pkey, EVP_PKEY_PUBLIC_KEY, params)) goto out; out: if (pctx != NULL) EVP_PKEY_CTX_free(pctx); if (tmpl != NULL) OSSL_PARAM_BLD_free(tmpl); if (params != NULL) OSSL_PARAM_free(params); if (bn_mod != NULL) BN_free(bn_mod); if (bn_exp != NULL) BN_free(bn_exp); #endif return pkey; } static EVP_PKEY *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 *exp_1 = NULL; CK_ATTRIBUTE *exp_2 = NULL; CK_ATTRIBUTE *coeff = NULL; EVP_PKEY *pkey = NULL; #if OPENSSL_VERSION_PREREQ(3, 0) EVP_PKEY_CTX *pctx = NULL; OSSL_PARAM_BLD *tmpl = NULL; OSSL_PARAM *params = NULL; #else RSA *rsa; #endif BIGNUM *bn_mod, *bn_pub_exp, *bn_priv_exp, *bn_p1, *bn_p2, *bn_e1, *bn_e2, *bn_cf; template_attribute_get_non_empty(key_obj->template, CKA_MODULUS, &modulus); template_attribute_get_non_empty(key_obj->template, CKA_PUBLIC_EXPONENT, &pub_exp); 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, &exp_1); template_attribute_find(key_obj->template, CKA_EXPONENT_2,&exp_2); template_attribute_find(key_obj->template, CKA_COEFFICIENT, &coeff); if (!prime2 && !modulus) { return NULL; } #if !OPENSSL_VERSION_PREREQ(3, 0) // 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. */ RSA_set_method(rsa, RSA_PKCS1_OpenSSL()); #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)) goto out; // CRT key? if (prime1) { if (!prime2 || !exp_1 || !exp_2 || !coeff) goto out; // 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 *) exp_1->pValue, exp_1->ulValueLen, bn_e1); BN_bin2bn((unsigned char *) exp_2->pValue, exp_2->ulValueLen, bn_e2); BN_bin2bn((unsigned char *) coeff->pValue, coeff->ulValueLen, bn_cf); #if !OPENSSL_VERSION_PREREQ(3, 0) RSA_set0_key(rsa, bn_mod, bn_pub_exp, bn_priv_exp); bn_mod = NULL; bn_pub_exp = NULL; bn_priv_exp = NULL; RSA_set0_factors(rsa, bn_p1, bn_p2); bn_p1 = NULL; bn_p2 = NULL; RSA_set0_crt_params(rsa, bn_e1, bn_e2, bn_cf); bn_e1 = NULL; bn_e2 = NULL; bn_cf = NULL; pkey = EVP_PKEY_new(); if (pkey == NULL) goto out; if (EVP_PKEY_assign_RSA(pkey, rsa) != 1) goto out; #else tmpl = OSSL_PARAM_BLD_new(); if (tmpl == NULL) goto out; if (!OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_RSA_N, bn_mod) || !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_RSA_E, bn_pub_exp) || !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_RSA_D, bn_priv_exp) || !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_RSA_FACTOR1, bn_p1) || !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_RSA_FACTOR2, bn_p2) || !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_RSA_EXPONENT1, bn_e1) || !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_RSA_EXPONENT2, bn_e2) || !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_RSA_COEFFICIENT1, bn_cf)) goto out; #endif } 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); #if !OPENSSL_VERSION_PREREQ(3, 0) RSA_set0_key(rsa, bn_mod, bn_pub_exp, bn_priv_exp); bn_mod = NULL; bn_pub_exp = NULL; bn_priv_exp = NULL; pkey = EVP_PKEY_new(); if (pkey == NULL) goto out; if (EVP_PKEY_assign_RSA(pkey, rsa) != 1) goto out; #else tmpl = OSSL_PARAM_BLD_new(); if (tmpl == NULL) goto out; if (!OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_RSA_N, bn_mod) || !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_RSA_E, bn_pub_exp) || !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_RSA_D, bn_priv_exp)) goto out; #endif } #if OPENSSL_VERSION_PREREQ(3, 0) params = OSSL_PARAM_BLD_to_param(tmpl); if (params == NULL) goto out; pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL); if (pctx == NULL) goto out; if (!EVP_PKEY_fromdata_init(pctx) || !EVP_PKEY_fromdata(pctx, &pkey, EVP_PKEY_KEYPAIR, params)) goto out; EVP_PKEY_CTX_free(pctx); OSSL_PARAM_BLD_free(tmpl); OSSL_PARAM_free(params); BN_free(bn_mod); BN_free(bn_pub_exp); BN_free(bn_priv_exp); BN_free(bn_p1); BN_free(bn_p2); BN_free(bn_e1); BN_free(bn_e2); BN_free(bn_cf); #endif return pkey; out: #if !OPENSSL_VERSION_PREREQ(3, 0) if (rsa) RSA_free(rsa); #else if (pctx != NULL) EVP_PKEY_CTX_free(pctx); if (tmpl != NULL) OSSL_PARAM_BLD_free(tmpl); if (params != NULL) OSSL_PARAM_free(params); #endif if (pkey) EVP_PKEY_free(pkey); 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; } CK_RV openssl_specific_rsa_encrypt(STDLL_TokData_t *tokdata, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, OBJECT *key_obj) { struct openssl_ex_data *ex_data = NULL; EVP_PKEY_CTX *ctx = NULL; EVP_PKEY *pkey = NULL; CK_RV rc; size_t outlen = in_data_len; UNUSED(tokdata); rc = openssl_get_ex_data(key_obj, (void **)&ex_data, sizeof(struct openssl_ex_data), openssl_need_wr_lock, NULL); if (rc != CKR_OK) return rc; if (ex_data->pkey == NULL) { ex_data->pkey = rsa_convert_public_key(key_obj); if (ex_data->pkey == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto done; } } pkey = ex_data->pkey; if (EVP_PKEY_up_ref(pkey) != 1) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto done; } ctx = EVP_PKEY_CTX_new(pkey, NULL); if (ctx == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto done; } if (EVP_PKEY_encrypt_init(ctx) != 1) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto done; } if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_NO_PADDING) != 1) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto done; } if (EVP_PKEY_encrypt(ctx, out_data, &outlen, in_data, in_data_len) != 1) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto done; } rc = CKR_OK; done: if (pkey != NULL) EVP_PKEY_free(pkey); if (ctx != NULL) EVP_PKEY_CTX_free(ctx); object_ex_data_unlock(key_obj); return rc; } CK_RV openssl_specific_rsa_decrypt(STDLL_TokData_t *tokdata, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, OBJECT *key_obj) { struct openssl_ex_data *ex_data = NULL; EVP_PKEY_CTX *ctx = NULL; EVP_PKEY *pkey = NULL; size_t outlen = in_data_len; CK_RV rc; UNUSED(tokdata); rc = openssl_get_ex_data(key_obj, (void **)&ex_data, sizeof(struct openssl_ex_data), openssl_need_wr_lock, NULL); if (rc != CKR_OK) return rc; if (ex_data->pkey == NULL) { ex_data->pkey = rsa_convert_private_key(key_obj); if (ex_data->pkey == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto done; } } pkey = ex_data->pkey; if (EVP_PKEY_up_ref(pkey) != 1) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto done; } ctx = EVP_PKEY_CTX_new(pkey, NULL); if (ctx == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto done; } if (EVP_PKEY_decrypt_init(ctx) != 1) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto done; } if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_NO_PADDING) != 1) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto done; } if (EVP_PKEY_decrypt(ctx, out_data, &outlen, in_data, in_data_len) != 1) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto done; } rc = CKR_OK; done: if (pkey != NULL) EVP_PKEY_free(pkey); if (ctx != NULL) EVP_PKEY_CTX_free(ctx); object_ex_data_unlock(key_obj); return rc; } CK_RV openssl_specific_rsa_pkcs_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, t_rsa_encrypt rsa_encrypt_func) { CK_RV rc; CK_ULONG modulus_bytes; CK_BYTE clear[MAX_RSA_KEYLEN], cipher[MAX_RSA_KEYLEN]; CK_ATTRIBUTE *attr = NULL; /* format the data */ rc = template_attribute_get_non_empty(key_obj->template, CKA_MODULUS, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); return rc; } 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 = rsa_encrypt_func(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("openssl_specific_rsa_encrypt failed\n"); } done: OPENSSL_cleanse(clear, sizeof(clear)); return rc; } CK_RV openssl_specific_rsa_pkcs_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, t_rsa_decrypt rsa_decrypt_func) { CK_RV rc; CK_BYTE out[MAX_RSA_KEYLEN]; CK_ULONG modulus_bytes; unsigned char kdk[SHA256_HASH_SIZE] = { 0 }; modulus_bytes = in_data_len; rc = rsa_decrypt_func(tokdata, in_data, modulus_bytes, out, key_obj); if (rc != CKR_OK) { TRACE_DEVEL("openssl_specific_rsa_decrypt failed\n"); goto done; } rc = openssl_specific_rsa_derive_kdk(tokdata, key_obj, in_data, in_data_len, kdk, sizeof(kdk)); if (rc != CKR_OK) { TRACE_DEVEL("openssl_specific_rsa_derive_kdk failed\n"); goto done; } rc = rsa_parse_block(out, modulus_bytes, out_data, out_data_len, PKCS_BT_2, kdk, sizeof(kdk)); done: OPENSSL_cleanse(out, sizeof(out)); return rc; } CK_RV openssl_specific_rsa_pkcs_sign(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, t_rsa_decrypt rsa_decrypt_func) { CK_BYTE data[MAX_RSA_KEYLEN], sig[MAX_RSA_KEYLEN]; CK_ULONG modulus_bytes; CK_RV rc; CK_ATTRIBUTE *attr = NULL; UNUSED(sess); /* format the data */ rc = template_attribute_get_non_empty(key_obj->template, CKA_MODULUS, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); return rc; } 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 = rsa_decrypt_func(tokdata, data, modulus_bytes, sig, key_obj); if (rc == CKR_OK) { memcpy(signature, sig, modulus_bytes); *sig_len = modulus_bytes; } else { TRACE_DEVEL("openssl_specific_rsa_decrypt failed\n"); } return rc; } CK_RV openssl_specific_rsa_pkcs_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, t_rsa_encrypt rsa_encrypt_func) { CK_ATTRIBUTE *attr = NULL; CK_BYTE out[MAX_RSA_KEYLEN], out_data[MAX_RSA_KEYLEN]; CK_ULONG modulus_bytes, out_data_len; CK_RV rc; UNUSED(sess); UNUSED(sig_len); out_data_len = MAX_RSA_KEYLEN; rc = template_attribute_get_non_empty(key_obj->template, CKA_MODULUS, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); return rc; } else { modulus_bytes = attr->ulValueLen; } // verifying is a public key operation --> encrypt // rc = rsa_encrypt_func(tokdata, signature, modulus_bytes, out, key_obj); if (rc != CKR_OK) { TRACE_DEVEL("openssl_specific_rsa_encrypt failed: %lx\n", rc); /* * Return CKR_SIGNATURE_INVALID in case of CKR_ARGUMENTS_BAD or * CKR_FUNCTION_FAILED 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 || rc == CKR_FUNCTION_FAILED) { TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID)); rc = CKR_SIGNATURE_INVALID; } return rc; } rc = rsa_parse_block(out, modulus_bytes, out_data, &out_data_len, PKCS_BT_1, NULL, 0); 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 openssl_specific_rsa_pkcs_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, t_rsa_encrypt rsa_encrypt_func) { CK_ATTRIBUTE *attr = NULL; CK_BYTE out[MAX_RSA_KEYLEN]; CK_ULONG modulus_bytes; CK_RV rc; UNUSED(sig_len); rc = template_attribute_get_non_empty(key_obj->template, CKA_MODULUS, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); return rc; } else { modulus_bytes = attr->ulValueLen; } // verifying is a public key operation --> encrypt // rc = rsa_encrypt_func(tokdata, signature, modulus_bytes, out, key_obj); if (rc != CKR_OK) { TRACE_DEVEL("openssl_specific_rsa_encrypt failed: %lx\n", rc); /* * Return CKR_SIGNATURE_INVALID in case of CKR_ARGUMENTS_BAD or * CKR_FUNCTION_FAILED 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 || rc == CKR_FUNCTION_FAILED) { TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID)); rc = CKR_SIGNATURE_INVALID; } return rc; } rc = rsa_parse_block(out, modulus_bytes, out_data, out_data_len, PKCS_BT_1, NULL, 0); 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 openssl_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, t_rsa_decrypt rsa_decrypt_func) { CK_RV rc; CK_ULONG modbytes; 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; } rc = template_attribute_get_non_empty(key_obj->template, CKA_MODULUS, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); 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 = rsa_decrypt_func(tokdata, emdata, modbytes, sig, key_obj); if (rc == CKR_OK) *sig_len = modbytes; else TRACE_DEVEL("openssl_specific_rsa_decrypt failed\n"); done: if (emdata) free(emdata); object_put(tokdata, key_obj, TRUE); key_obj = NULL; return rc; } CK_RV openssl_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, t_rsa_encrypt rsa_encrypt_func) { CK_RV rc; CK_ULONG modbytes; OBJECT *key_obj = NULL; 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 = rsa_encrypt_func(tokdata, signature, sig_len, out, key_obj); if (rc != CKR_OK) { TRACE_DEVEL("openssl_specific_rsa_encrypt failed: %lx\n", rc); /* * Return CKR_SIGNATURE_INVALID in case of CKR_ARGUMENTS_BAD or * CKR_FUNCTION_FAILED 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 || rc == CKR_FUNCTION_FAILED) { TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID)); rc = CKR_SIGNATURE_INVALID; } goto done; } rc = template_attribute_get_non_empty(key_obj->template, CKA_MODULUS, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); 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 openssl_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, t_rsa_encrypt rsa_encrypt_func) { CK_ATTRIBUTE *attr = NULL; CK_BYTE clear[MAX_RSA_KEYLEN], cipher[MAX_RSA_KEYLEN]; CK_ULONG modulus_bytes; CK_RV rc; rc = template_attribute_get_non_empty(key_obj->template, CKA_MODULUS, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); goto done; } modulus_bytes = attr->ulValueLen; // prepad with zeros // memset(clear, 0, modulus_bytes - in_data_len); memcpy(&clear[modulus_bytes - in_data_len], in_data, in_data_len); rc = rsa_encrypt_func(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("openssl_specific_rsa_encrypt failed\n"); } done: OPENSSL_cleanse(clear, sizeof(clear)); return rc; } CK_RV openssl_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, t_rsa_decrypt rsa_decrypt_func) { CK_ATTRIBUTE *attr = NULL; CK_BYTE out[MAX_RSA_KEYLEN]; CK_ULONG modulus_bytes; CK_RV rc; UNUSED(in_data_len); rc = template_attribute_get_non_empty(key_obj->template, CKA_MODULUS, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); goto done; } modulus_bytes = attr->ulValueLen; rc = rsa_decrypt_func(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("openssl_specific_rsa_decrypt failed\n"); } done: OPENSSL_cleanse(out, sizeof(out)); return rc; } CK_RV openssl_specific_rsa_x509_sign(STDLL_TokData_t *tokdata, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *signature, CK_ULONG *sig_len, OBJECT *key_obj, t_rsa_decrypt rsa_decrypt_func) { CK_ATTRIBUTE *attr = NULL; CK_BYTE data[MAX_RSA_KEYLEN], sig[MAX_RSA_KEYLEN]; CK_ULONG modulus_bytes; CK_RV rc; rc = template_attribute_get_non_empty(key_obj->template, CKA_MODULUS, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); return rc; } 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 = rsa_decrypt_func(tokdata, data, modulus_bytes, sig, key_obj); if (rc == CKR_OK) { memcpy(signature, sig, modulus_bytes); *sig_len = modulus_bytes; } else { TRACE_DEVEL("openssl_specific_rsa_encrypt failed: %lx\n", rc); /* * Return CKR_SIGNATURE_INVALID in case of CKR_ARGUMENTS_BAD or * CKR_FUNCTION_FAILED 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 || rc == CKR_FUNCTION_FAILED) { TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID)); rc = CKR_SIGNATURE_INVALID; } } return rc; } CK_RV openssl_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, t_rsa_encrypt rsa_encrypt_func) { CK_ATTRIBUTE *attr = NULL; CK_BYTE out[MAX_RSA_KEYLEN]; CK_ULONG modulus_bytes; CK_RV rc; UNUSED(sig_len); rc = template_attribute_get_non_empty(key_obj->template, CKA_MODULUS, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); return rc; } else { modulus_bytes = attr->ulValueLen; } rc = rsa_encrypt_func(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("openssl_specific_rsa_encrypt failed: %lx\n", rc); /* * Return CKR_SIGNATURE_INVALID in case of CKR_ARGUMENTS_BAD or * CKR_FUNCTION_FAILED 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 || rc == CKR_FUNCTION_FAILED) { TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID)); rc = CKR_SIGNATURE_INVALID; } } return rc; } CK_RV openssl_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, t_rsa_encrypt rsa_encrypt_func) { CK_ATTRIBUTE *attr = NULL; CK_BYTE out[MAX_RSA_KEYLEN]; CK_ULONG modulus_bytes; CK_RV rc; UNUSED(sig_len); rc = template_attribute_get_non_empty(key_obj->template, CKA_MODULUS, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); return rc; } else { modulus_bytes = attr->ulValueLen; } rc = rsa_encrypt_func(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("openssl_specific_rsa_encrypt failed\n"); } return rc; } CK_RV openssl_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, t_rsa_encrypt rsa_encrypt_func) { CK_RV rc; CK_BYTE cipher[MAX_RSA_KEYLEN]; CK_ULONG modulus_bytes; 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; } rc = template_attribute_get_non_empty(key_obj->template, CKA_MODULUS, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); 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 = rsa_encrypt_func(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("openssl_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 openssl_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, t_rsa_encrypt rsa_decrypt_func) { CK_RV rc; CK_BYTE *decr_data = NULL; OBJECT *key_obj = NULL; 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; } rc = template_attribute_get_non_empty(key_obj->template, CKA_MODULUS, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); 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 = rsa_decrypt_func(tokdata, 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 NO_EC static int curve_nid_from_params(const CK_BYTE *params, CK_ULONG params_len) { const unsigned char *oid; ASN1_OBJECT *obj = NULL; EC_GROUP *grp; int nid; oid = params; obj = d2i_ASN1_OBJECT(NULL, &oid, params_len); if (obj == NULL || oid != params + params_len) { TRACE_ERROR("curve not supported by OpenSSL.\n"); return NID_undef; } nid = OBJ_obj2nid(obj); ASN1_OBJECT_free(obj); #if OPENSSL_VERSION_PREREQ(3, 0) switch (nid) { case NID_ED25519: case NID_X25519: case NID_ED448: case NID_X448: return nid; } #endif grp = EC_GROUP_new_by_curve_name(nid); if (grp == NULL) { TRACE_ERROR("curve not supported by OpenSSL.\n"); return NID_undef; } EC_GROUP_free(grp); return nid; } static int ec_prime_len_from_nid(int nid) { EC_GROUP *group; int primelen; #if OPENSSL_VERSION_PREREQ(3, 0) switch (nid) { case NID_ED25519: case NID_X25519: return (CURVE256 + 7) / 8; case NID_ED448: case NID_X448: return (CURVE448 + 7) / 8; } #endif group = EC_GROUP_new_by_curve_name(nid); if (group == NULL) return -1; primelen = EC_GROUP_order_bits(group); EC_GROUP_free(group); return (primelen + 7) / 8; } static int ec_prime_len_from_pkey(EVP_PKEY *pkey) { #if !OPENSSL_VERSION_PREREQ(3, 0) return (EC_GROUP_order_bits(EC_KEY_get0_group( EVP_PKEY_get0_EC_KEY(pkey))) + 7) / 8; #else size_t curve_len; char curve[80]; if (!EVP_PKEY_get_utf8_string_param(pkey, OSSL_PKEY_PARAM_GROUP_NAME, curve, sizeof(curve), &curve_len)) return -1; return ec_prime_len_from_nid(OBJ_sn2nid(curve)); #endif } #if !OPENSSL_VERSION_PREREQ(3, 0) static CK_RV make_ec_key_from_params(const CK_BYTE *params, CK_ULONG params_len, EC_KEY **key) { EC_KEY *ec_key = NULL; int nid; CK_RV rc = CKR_OK; nid = curve_nid_from_params(params, params_len); if (nid == NID_undef) { TRACE_ERROR("curve not supported by OpenSSL.\n"); rc = CKR_CURVE_NOT_SUPPORTED; goto out; } ec_key = EC_KEY_new_by_curve_name(nid); if (ec_key == NULL) { TRACE_ERROR("curve not supported by OpenSSL.\n"); rc = CKR_CURVE_NOT_SUPPORTED; goto out; } out: if (rc != CKR_OK) { if (ec_key != NULL) EC_KEY_free(ec_key); return rc; } *key = ec_key; return CKR_OK; } #endif #if OPENSSL_VERSION_PREREQ(3, 0) static CK_RV build_pkey_from_params(OSSL_PARAM_BLD *tmpl, int pkey_type, int selection, EVP_PKEY **pkey) { OSSL_PARAM *params = NULL; EVP_PKEY_CTX *pctx = NULL; CK_RV rc = CKR_OK; params = OSSL_PARAM_BLD_to_param(tmpl); if (params == NULL) { TRACE_ERROR("OSSL_PARAM_BLD_to_param failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } pctx = EVP_PKEY_CTX_new_id(pkey_type, NULL); if (pctx == NULL) { TRACE_ERROR("EVP_PKEY_CTX_new_id failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } if (!EVP_PKEY_fromdata_init(pctx) || !EVP_PKEY_fromdata(pctx, pkey, selection, params)) { TRACE_ERROR("EVP_PKEY_fromdata failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } EVP_PKEY_CTX_free(pctx); pctx = EVP_PKEY_CTX_new(*pkey, NULL); if (pctx == NULL) { TRACE_ERROR("EVP_PKEY_CTX_new failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } if (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) { if (EVP_PKEY_check(pctx) != 1) { TRACE_ERROR("EVP_PKEY_check failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } } else { if (EVP_PKEY_public_check(pctx) != 1) { TRACE_ERROR("EVP_PKEY_public_check failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } } out: if (pctx != NULL) EVP_PKEY_CTX_free(pctx); if (params != NULL) OSSL_PARAM_free(params); if (rc != 0 && *pkey != NULL) { EVP_PKEY_free(*pkey); *pkey = NULL; } return rc; } #endif #if !OPENSSL_VERSION_PREREQ(3, 0) static CK_RV fill_ec_key_from_pubkey(EC_KEY *ec_key, const CK_BYTE *data, CK_ULONG data_len, CK_BBOOL allow_raw, int nid, EVP_PKEY **ec_pkey) #else static CK_RV fill_ec_key_from_pubkey(OSSL_PARAM_BLD *tmpl, const CK_BYTE *data, CK_ULONG data_len, CK_BBOOL allow_raw, int nid, EVP_PKEY **ec_pkey) #endif { CK_BYTE *ecpoint = NULL; CK_ULONG ecpoint_len, privlen; CK_BBOOL allocated = FALSE; int len; #if OPENSSL_VERSION_PREREQ(3, 0) int pkey_type; #endif CK_RV rc; switch (nid) { #if OPENSSL_VERSION_PREREQ(3, 0) case NID_ED25519: case NID_ED448: case NID_X25519: case NID_X448: /* Edwards/Montgomery is always raw */ ecpoint = (CK_BYTE *)data; ecpoint_len = data_len; pkey_type = nid; break; #endif default: len = ec_prime_len_from_nid(nid); if (len <= 0) { TRACE_ERROR("ec_prime_len_from_nid failed\n"); rc = CKR_CURVE_NOT_SUPPORTED; goto out; } privlen = len; rc = ec_point_from_public_data(data, data_len, privlen, allow_raw, &allocated, &ecpoint, &ecpoint_len); if (rc != CKR_OK) { TRACE_DEVEL("ec_point_from_public_data failed\n"); goto out; } #if OPENSSL_VERSION_PREREQ(3, 0) pkey_type = EVP_PKEY_EC; #endif break; } #if !OPENSSL_VERSION_PREREQ(3, 0) if (!EC_KEY_oct2key(ec_key, ecpoint, ecpoint_len, NULL)) { TRACE_ERROR("EC_KEY_oct2key failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } if (!EC_KEY_check_key(ec_key)) { TRACE_ERROR("EC_KEY_check_key failed\n"); rc = CKR_PUBLIC_KEY_INVALID; goto out; } *ec_pkey = EVP_PKEY_new(); if (*ec_pkey == NULL) { TRACE_ERROR("EVP_PKEY_CTX_new failed.\n"); rc = CKR_HOST_MEMORY; goto out; } if (!EVP_PKEY_assign_EC_KEY(*ec_pkey, ec_key)) { TRACE_ERROR("EVP_PKEY_assign_EC_KEY failed.\n"); rc = CKR_FUNCTION_FAILED; goto out; } #else if (!OSSL_PARAM_BLD_push_octet_string(tmpl, OSSL_PKEY_PARAM_PUB_KEY, ecpoint, ecpoint_len)) { TRACE_ERROR("OSSL_PARAM_BLD_push_octet_string failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } rc = build_pkey_from_params(tmpl, pkey_type, EVP_PKEY_PUBLIC_KEY, ec_pkey); if (rc != CKR_OK) { TRACE_ERROR("build_pkey_from_params failed\n"); goto out; } #endif out: if (allocated && ecpoint != NULL) free(ecpoint); return rc; } #if !OPENSSL_VERSION_PREREQ(3, 0) static CK_RV fill_ec_key_from_privkey(EC_KEY *ec_key, const CK_BYTE *data, CK_ULONG data_len, EVP_PKEY **ec_pkey) #else static CK_RV fill_ec_key_from_privkey(OSSL_PARAM_BLD *tmpl, const CK_BYTE *data, CK_ULONG data_len, int nid, EVP_PKEY **ec_pkey) #endif { EC_POINT *point = NULL; #if OPENSSL_VERSION_PREREQ(3, 0) EC_GROUP *group = NULL; BIGNUM *bn_priv = NULL; unsigned char *pub_key = NULL; unsigned int pub_key_len; point_conversion_form_t form; int pkey_type; #endif CK_RV rc = CKR_OK; #if !OPENSSL_VERSION_PREREQ(3, 0) if (!EC_KEY_oct2priv(ec_key, data, data_len)) { TRACE_ERROR("EC_KEY_oct2priv failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } point = EC_POINT_new(EC_KEY_get0_group(ec_key)); if (point == NULL) { TRACE_ERROR("EC_POINT_new failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } if (!EC_POINT_mul(EC_KEY_get0_group(ec_key), point, EC_KEY_get0_private_key(ec_key), NULL, NULL, NULL)) { TRACE_ERROR("EC_POINT_mul failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } if (!EC_KEY_set_public_key(ec_key, point)) { TRACE_ERROR("EC_KEY_set_public_key failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } if (!EC_KEY_check_key(ec_key)) { TRACE_ERROR("EC_KEY_check_key failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } *ec_pkey = EVP_PKEY_new(); if (*ec_pkey == NULL) { TRACE_ERROR("EVP_PKEY_CTX_new failed.\n"); rc = CKR_HOST_MEMORY; goto out; } if (!EVP_PKEY_assign_EC_KEY(*ec_pkey, ec_key)) { TRACE_ERROR("EVP_PKEY_assign_EC_KEY failed.\n"); rc = CKR_FUNCTION_FAILED; goto out; } #else switch (nid) { case NID_ED25519: case NID_ED448: case NID_X25519: case NID_X448: /* Edwards/Montgomery: private key is a octet string */ if (!OSSL_PARAM_BLD_push_octet_string(tmpl, OSSL_PKEY_PARAM_PRIV_KEY, data, data_len)) { TRACE_ERROR("OSSL_PARAM_BLD_push_octet_string failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } pkey_type = nid; break; default: /* EC: private key is a bignum */ group = EC_GROUP_new_by_curve_name(nid); if (group == NULL) { TRACE_ERROR("EC_GROUP_new_by_curve_name failed\n"); rc = CKR_CURVE_NOT_SUPPORTED; goto out; } point = EC_POINT_new(group); if (point == NULL) { TRACE_ERROR("EC_POINT_new failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } bn_priv = BN_bin2bn(data, data_len, NULL); if (bn_priv == NULL) { rc = CKR_FUNCTION_FAILED; goto out; } if (!EC_POINT_mul(group, point, bn_priv, NULL, NULL, NULL)) { TRACE_ERROR("EC_POINT_mul failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } form = EC_GROUP_get_point_conversion_form(group); pub_key_len = EC_POINT_point2buf(group, point, form, &pub_key, NULL); if (pub_key_len == 0) { TRACE_ERROR("EC_POINT_point2buf failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } if (!OSSL_PARAM_BLD_push_octet_string(tmpl, OSSL_PKEY_PARAM_PUB_KEY, pub_key, pub_key_len)) { TRACE_ERROR("OSSL_PARAM_BLD_push_octet_string failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } if (!OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_PRIV_KEY, bn_priv)) { TRACE_ERROR("OSSL_PARAM_BLD_push_BN failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } pkey_type = EVP_PKEY_EC; break; } rc = build_pkey_from_params(tmpl, pkey_type, EVP_PKEY_KEYPAIR, ec_pkey); if (rc != CKR_OK) { TRACE_ERROR("build_pkey_from_params failed\n"); goto out; } #endif out: if (point != NULL) EC_POINT_free(point); #if OPENSSL_VERSION_PREREQ(3, 0) if (group != NULL) EC_GROUP_free(group); if (bn_priv != NULL) BN_free(bn_priv); if (pub_key != NULL) OPENSSL_free(pub_key); #endif return rc; } CK_RV openssl_make_ec_key_from_template(TEMPLATE *template, EVP_PKEY **pkey) { CK_ATTRIBUTE *attr = NULL; CK_OBJECT_CLASS keyclass; CK_KEY_TYPE keytype; EVP_PKEY *ec_pkey = NULL; int nid; #if !OPENSSL_VERSION_PREREQ(3, 0) EC_KEY *ec_key = NULL; #else OSSL_PARAM_BLD *tmpl = NULL; #endif CK_RV rc; rc = template_attribute_get_ulong(template, CKA_CLASS, &keyclass); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS in the template\n"); goto out; } rc = template_attribute_get_ulong(template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS in the template\n"); goto out; } rc = template_attribute_get_non_empty(template, CKA_EC_PARAMS, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_EC_PARAMS in the template\n"); goto out; } nid = curve_nid_from_params(attr->pValue, attr->ulValueLen); if (nid == NID_undef) { TRACE_ERROR("curve not supported by OpenSSL.\n"); rc = CKR_CURVE_NOT_SUPPORTED; goto out; } switch (nid) { case NID_ED25519: case NID_ED448: if (keytype != CKK_EC_EDWARDS) { TRACE_ERROR("Edwards curve only supported with CKK_EC_EDWARDS " "key type.\n"); rc = CKR_CURVE_NOT_SUPPORTED; goto out; } break; case NID_X25519: case NID_X448: if (keytype != CKK_EC_MONTGOMERY) { TRACE_ERROR("Montgomery curve only supported with " "CKK_EC_MONTGOMERY key type.\n"); rc = CKR_CURVE_NOT_SUPPORTED; goto out; } break; default: if (keytype != CKK_EC) { TRACE_ERROR("EC curve only supported with CKK_EC key type.\n"); rc = CKR_CURVE_NOT_SUPPORTED; goto out; } break; } #if !OPENSSL_VERSION_PREREQ(3, 0) rc = make_ec_key_from_params(attr->pValue, attr->ulValueLen, &ec_key); if (rc != CKR_OK) goto out; #else tmpl = OSSL_PARAM_BLD_new(); if (tmpl == NULL) { TRACE_ERROR("OSSL_PARAM_BLD_new failed\n"); rc = CKR_HOST_MEMORY; goto out; } if (!OSSL_PARAM_BLD_push_utf8_string(tmpl, OSSL_PKEY_PARAM_GROUP_NAME, OBJ_nid2sn(nid), 0)) { TRACE_ERROR("OSSL_PARAM_BLD_push_utf8_string failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } #endif switch (keyclass) { case CKO_PUBLIC_KEY: rc = template_attribute_get_non_empty(template, CKA_EC_POINT, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_EC_POINT in the template\n"); goto out; } #if !OPENSSL_VERSION_PREREQ(3, 0) rc = fill_ec_key_from_pubkey(ec_key, attr->pValue, attr->ulValueLen, FALSE, nid, &ec_pkey); #else rc = fill_ec_key_from_pubkey(tmpl, attr->pValue, attr->ulValueLen, FALSE, nid, &ec_pkey); #endif if (rc != CKR_OK) { TRACE_DEVEL("fill_ec_key_from_pubkey failed\n"); goto out; } break; case CKO_PRIVATE_KEY: rc = template_attribute_get_non_empty(template, CKA_VALUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE in the template\n"); goto out; } #if !OPENSSL_VERSION_PREREQ(3, 0) rc = fill_ec_key_from_privkey(ec_key, attr->pValue, attr->ulValueLen, &ec_pkey); #else rc = fill_ec_key_from_privkey(tmpl, attr->pValue, attr->ulValueLen, nid, &ec_pkey); #endif if (rc != CKR_OK) { TRACE_DEVEL("fill_ec_key_from_privkey failed\n"); goto out; } break; default: rc = CKR_KEY_FUNCTION_NOT_PERMITTED; goto out; } #if !OPENSSL_VERSION_PREREQ(3, 0) ec_key = NULL; #endif rc = CKR_OK; out: #if OPENSSL_VERSION_PREREQ(3, 0) if (tmpl != NULL) OSSL_PARAM_BLD_free(tmpl); #endif if (rc != CKR_OK) { if (ec_pkey != NULL) EVP_PKEY_free(ec_pkey); #if !OPENSSL_VERSION_PREREQ(3, 0) if (ec_key != NULL) EC_KEY_free(ec_key); #endif return rc; } *pkey = ec_pkey; return CKR_OK; } #if OPENSSL_VERSION_PREREQ(3, 0) /* * Calculate the EC-Edwards public key (ECPoint) from the EC-Edwards private key. */ CK_RV openssl_ec_edwards_point_from_priv_key(CK_BYTE *parms, CK_ULONG parms_len, CK_BYTE *priv, CK_ULONG priv_len, CK_BYTE **point, CK_ULONG *point_len) { OSSL_PARAM_BLD *tmpl = NULL; EVP_PKEY *ed_pkey = NULL; CK_RV rc; size_t pub_len = 0; CK_BYTE *pub = NULL; int nid; nid = curve_nid_from_params(parms, parms_len); if (nid == NID_undef) { TRACE_ERROR("curve not supported by OpenSSL.\n"); rc = CKR_CURVE_NOT_SUPPORTED; goto out; } tmpl = OSSL_PARAM_BLD_new(); if (tmpl == NULL) { TRACE_ERROR("OSSL_PARAM_BLD_new failed\n"); rc = CKR_HOST_MEMORY; goto out; } if (!OSSL_PARAM_BLD_push_utf8_string(tmpl, OSSL_PKEY_PARAM_GROUP_NAME, OBJ_nid2sn(nid), 0)) { TRACE_ERROR("OSSL_PARAM_BLD_push_utf8_string failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } rc = fill_ec_key_from_privkey(tmpl, priv, priv_len, nid, &ed_pkey); if (rc != CKR_OK) { TRACE_DEVEL("fill_ec_key_from_privkey failed\n"); goto out; } if (EVP_PKEY_get_octet_string_param(ed_pkey, OSSL_PKEY_PARAM_PUB_KEY, NULL, 0, &pub_len) != 1) { TRACE_DEVEL("EVP_PKEY_get_octet_string_param failed\n"); goto out; } pub = malloc(pub_len); if (pub == NULL) { rc = CKR_HOST_MEMORY; goto out; } if (EVP_PKEY_get_octet_string_param(ed_pkey, OSSL_PKEY_PARAM_PUB_KEY, pub, pub_len, &pub_len) != 1) { TRACE_DEVEL("EVP_PKEY_get_octet_string_param failed\n"); goto out; } *point = pub; *point_len = pub_len; pub = NULL; out: if (tmpl != NULL) OSSL_PARAM_BLD_free(tmpl); if (ed_pkey != NULL) EVP_PKEY_free(ed_pkey); if (pub != NULL) free(pub); return rc; } #endif CK_RV openssl_specific_ec_generate_keypair(STDLL_TokData_t *tokdata, TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl, CK_MECHANISM_TYPE mech) { CK_ATTRIBUTE *attr = NULL, *ec_point_attr, *value_attr, *parms_attr; #if !OPENSSL_VERSION_PREREQ(3, 0) const EC_KEY *ec_key = NULL; BN_CTX *bnctx = NULL; #else BIGNUM *bn_d = NULL; int len; #endif CK_BYTE *ecpoint = NULL, *enc_ecpoint = NULL, *d = NULL; CK_ULONG enc_ecpoint_len, d_len; size_t ecpoint_len; EVP_PKEY_CTX *ctx = NULL; EVP_PKEY *ec_pkey = NULL; int nid, pkey_type; CK_RV rc; UNUSED(tokdata); rc = template_attribute_get_non_empty(publ_tmpl, CKA_EC_PARAMS, &attr); if (rc != CKR_OK) goto out; nid = curve_nid_from_params(attr->pValue, attr->ulValueLen); if (nid == NID_undef) { TRACE_ERROR("curve not supported by OpenSSL.\n"); rc = CKR_CURVE_NOT_SUPPORTED; goto out; } switch (nid) { #if OPENSSL_VERSION_PREREQ(3, 0) case NID_ED25519: case NID_ED448: if (mech != CKM_EC_EDWARDS_KEY_PAIR_GEN) { TRACE_ERROR("Edwards curve only supported with " "CKM_EC_EDWARDS_KEY_PAIR_GEN.\n"); rc = CKR_CURVE_NOT_SUPPORTED; goto out; } pkey_type = nid; break; case NID_X25519: case NID_X448: if (mech != CKM_EC_MONTGOMERY_KEY_PAIR_GEN) { TRACE_ERROR("Montgomery curve only supported with " "CKM_EC_MONTGOMERY_KEY_PAIR_GEN.\n"); rc = CKR_CURVE_NOT_SUPPORTED; goto out; } pkey_type = nid; break; #endif default: if (mech != CKM_EC_KEY_PAIR_GEN) { TRACE_ERROR("curve only supported with CKM_EC_KEY_PAIR_GEN.\n"); rc = CKR_CURVE_NOT_SUPPORTED; goto out; } pkey_type = EVP_PKEY_EC; break; } ctx = EVP_PKEY_CTX_new_id(pkey_type, NULL); if (ctx == NULL) { TRACE_ERROR("EVP_PKEY_CTX_new failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } if (EVP_PKEY_keygen_init(ctx) <= 0) { TRACE_ERROR("EVP_PKEY_keygen_init failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } if (pkey_type == EVP_PKEY_EC) { if (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, nid) <= 0) { TRACE_ERROR("EVP_PKEY_CTX_set_ec_paramgen_curve_nid failed\n"); rc = CKR_CURVE_NOT_SUPPORTED; goto out; } } if (EVP_PKEY_keygen(ctx, &ec_pkey) <= 0) { TRACE_ERROR("EVP_PKEY_keygen failed\n"); if (ERR_GET_REASON(ERR_peek_last_error()) == EC_R_INVALID_CURVE) rc = CKR_CURVE_NOT_SUPPORTED; else rc = CKR_FUNCTION_FAILED; goto out; } #if !OPENSSL_VERSION_PREREQ(3, 0) ec_key = EVP_PKEY_get0_EC_KEY(ec_pkey); if (ec_key == NULL) { TRACE_ERROR("EVP_PKEY_get0_EC_KEY failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } bnctx = BN_CTX_new(); if (bnctx == NULL) { rc = CKR_HOST_MEMORY; goto out; } ecpoint_len = EC_KEY_key2buf(ec_key, POINT_CONVERSION_UNCOMPRESSED, &ecpoint, bnctx); if (ecpoint_len == 0) { TRACE_ERROR("Failed to get the EC Point compressed.\n"); rc = CKR_FUNCTION_FAILED; goto out; } #else if (!EVP_PKEY_get_octet_string_param(ec_pkey, pkey_type == EVP_PKEY_EC ? OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY : OSSL_PKEY_PARAM_PUB_KEY, NULL, 0, &ecpoint_len)) { TRACE_ERROR("EVP_PKEY_get_octet_string_param failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } ecpoint = OPENSSL_zalloc(ecpoint_len); if (ecpoint == NULL) { TRACE_ERROR("OPENSSL_zalloc failed\n"); rc = CKR_HOST_MEMORY; goto out; } if (!EVP_PKEY_get_octet_string_param(ec_pkey, pkey_type == EVP_PKEY_EC ? OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY : OSSL_PKEY_PARAM_PUB_KEY, ecpoint, ecpoint_len, &ecpoint_len)) { TRACE_ERROR("EVP_PKEY_get_octet_string_param failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } #endif if (pkey_type == EVP_PKEY_EC) { rc = ber_encode_OCTET_STRING(FALSE, &enc_ecpoint, &enc_ecpoint_len, ecpoint, ecpoint_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_OCTET_STRING failed\n"); goto out; } rc = build_attribute(CKA_EC_POINT, enc_ecpoint, enc_ecpoint_len, &ec_point_attr); if (rc != CKR_OK) { TRACE_ERROR("build_attribute for CKA_EC_POINT failed rc=0x%lx\n", rc); goto out; } } else { /* Edwards/Montgomery keys have raw CKA_EC_POINT */ rc = build_attribute(CKA_EC_POINT, ecpoint, ecpoint_len, &ec_point_attr); if (rc != CKR_OK) { TRACE_ERROR("build_attribute for CKA_EC_POINT failed rc=0x%lx\n", rc); goto out; } } rc = template_update_attribute(publ_tmpl, ec_point_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); free(ec_point_attr); goto out; } #if !OPENSSL_VERSION_PREREQ(3, 0) d_len = EC_KEY_priv2buf(ec_key, &d); if (d_len == 0) { TRACE_ERROR("Failed to get the EC private key.\n"); rc = CKR_FUNCTION_FAILED; goto out; } #else if (pkey_type == EVP_PKEY_EC) { /* EC: private key is a bignum */ if (!EVP_PKEY_get_bn_param(ec_pkey, OSSL_PKEY_PARAM_PRIV_KEY, &bn_d)) { TRACE_ERROR("EVP_PKEY_get_bn_param failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } len = ec_prime_len_from_nid(nid); if (len <= 0) { TRACE_ERROR("ec_prime_len_from_nid failed\n"); rc = CKR_CURVE_NOT_SUPPORTED; goto out; } d_len = len; d = OPENSSL_zalloc(d_len); if (d == NULL) { TRACE_ERROR("OPENSSL_zalloc failed\n"); rc = CKR_HOST_MEMORY; goto out; } BN_bn2binpad(bn_d, d, d_len); } else { /* Edwards/Montgomery: private key is a octet string */ if (!EVP_PKEY_get_octet_string_param(ec_pkey, OSSL_PKEY_PARAM_PRIV_KEY, d, 0, &d_len)) { TRACE_ERROR("EVP_PKEY_get_octet_string_param failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } d = OPENSSL_zalloc(d_len); if (d == NULL) { TRACE_ERROR("OPENSSL_zalloc failed\n"); rc = CKR_HOST_MEMORY; goto out; } if (!EVP_PKEY_get_octet_string_param(ec_pkey, OSSL_PKEY_PARAM_PRIV_KEY, d, d_len, &d_len)) { TRACE_ERROR("EVP_PKEY_get_octet_string_param failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } } #endif rc = build_attribute(CKA_VALUE, d, d_len, &value_attr); if (rc != CKR_OK) { TRACE_ERROR("build_attribute for CKA_VALUE failed, rc=0x%lx\n", rc); goto out; } rc = template_update_attribute(priv_tmpl, value_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); free(value_attr); goto out; } /* Add CKA_EC_PARAMS to private template also */ rc = build_attribute(CKA_EC_PARAMS, attr->pValue, attr->ulValueLen, &parms_attr); if (rc != CKR_OK) { TRACE_ERROR("build_attribute for CKA_EC_PARAMS failed, rc=0x%lx\n", rc); goto out; } rc = template_update_attribute(priv_tmpl, parms_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); free(parms_attr); goto out; } rc = CKR_OK; out: if (ctx != NULL) EVP_PKEY_CTX_free(ctx); #if !OPENSSL_VERSION_PREREQ(3, 0) if (bnctx != NULL) BN_CTX_free(bnctx); #else if (bn_d != NULL) BN_free(bn_d); #endif if (ec_pkey != NULL) EVP_PKEY_free(ec_pkey); if (ecpoint != NULL) OPENSSL_free(ecpoint); if (enc_ecpoint != NULL) free(enc_ecpoint); if (d != NULL) OPENSSL_free(d); return rc; } CK_RV openssl_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) { struct openssl_ex_data *ex_data = NULL; EVP_PKEY *ec_key = NULL; ECDSA_SIG *sig = NULL; const BIGNUM *r, *s; CK_ULONG privlen, n; CK_RV rc = CKR_OK; EVP_PKEY_CTX *ctx = NULL; size_t siglen; CK_BYTE *sigbuf = NULL; const unsigned char *p; int len; UNUSED(tokdata); UNUSED(sess); *out_data_len = 0; rc = openssl_get_ex_data(key_obj, (void **)&ex_data, sizeof(struct openssl_ex_data), openssl_need_wr_lock, NULL); if (rc != CKR_OK) return rc; if (ex_data->pkey == NULL) { rc = openssl_make_ec_key_from_template(key_obj->template, &ex_data->pkey); if (rc != CKR_OK) goto out; } ec_key = ex_data->pkey; if (EVP_PKEY_up_ref(ec_key) != 1) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto out; } ctx = EVP_PKEY_CTX_new(ec_key, NULL); if (ctx == NULL) { TRACE_ERROR("EVP_PKEY_CTX_new failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } if (EVP_PKEY_sign_init(ctx) <= 0) { TRACE_ERROR("EVP_PKEY_sign_init failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } if (EVP_PKEY_sign(ctx, NULL, &siglen, in_data, in_data_len) <= 0) { TRACE_ERROR("EVP_PKEY_sign failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } sigbuf = malloc(siglen); if (sigbuf == NULL) { TRACE_ERROR("malloc failed\n"); rc = CKR_HOST_MEMORY; goto out; } if (EVP_PKEY_sign(ctx, sigbuf, &siglen, in_data, in_data_len) <= 0) { TRACE_ERROR("EVP_PKEY_sign failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } p = sigbuf; sig = d2i_ECDSA_SIG(NULL, &p, siglen); if (sig == NULL) { TRACE_ERROR("d2i_ECDSA_SIG failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } ECDSA_SIG_get0(sig, &r, &s); len = ec_prime_len_from_pkey(ec_key); if (len <= 0) { TRACE_ERROR("ec_prime_len_from_pkey failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } privlen = len; /* Insert leading 0's if r or s shorter than privlen */ n = privlen - BN_num_bytes(r); memset(out_data, 0, n); BN_bn2bin(r, &out_data[n]); n = privlen - BN_num_bytes(s); memset(out_data + privlen, 0x00, n); BN_bn2bin(s, &out_data[privlen + n]); *out_data_len = 2 * privlen; out: if (sig != NULL) ECDSA_SIG_free(sig); if (ec_key != NULL) EVP_PKEY_free(ec_key); if (sigbuf != NULL) free(sigbuf); if (ctx != NULL) EVP_PKEY_CTX_free(ctx); object_ex_data_unlock(key_obj); return rc; } CK_RV openssl_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) { struct openssl_ex_data *ex_data = NULL; EVP_PKEY *ec_key = NULL; CK_ULONG privlen; ECDSA_SIG *sig = NULL; BIGNUM *r = NULL, *s = NULL; CK_RV rc = CKR_OK; int len; size_t siglen; CK_BYTE *sigbuf = NULL; EVP_PKEY_CTX *ctx = NULL; UNUSED(tokdata); UNUSED(sess); rc = openssl_get_ex_data(key_obj, (void **)&ex_data, sizeof(struct openssl_ex_data), openssl_need_wr_lock, NULL); if (rc != CKR_OK) return rc; if (ex_data->pkey == NULL) { rc = openssl_make_ec_key_from_template(key_obj->template, &ex_data->pkey); if (rc != CKR_OK) goto out; } ec_key = ex_data->pkey; if (EVP_PKEY_up_ref(ec_key) != 1) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto out; } len = ec_prime_len_from_pkey(ec_key); if (len <= 0) { TRACE_ERROR("ec_prime_len_from_pkey failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } privlen = len; if (signature_len < 2 * privlen) { TRACE_ERROR("Signature is too short\n"); rc = CKR_SIGNATURE_LEN_RANGE; goto out; } sig = ECDSA_SIG_new(); if (sig == NULL) { rc = CKR_HOST_MEMORY; goto out; } r = BN_bin2bn(signature, privlen, NULL); s = BN_bin2bn(signature + privlen, privlen, NULL); if (r == NULL || s == NULL) { TRACE_ERROR("BN_bin2bn failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } if (!ECDSA_SIG_set0(sig, r, s)) { TRACE_ERROR("ECDSA_SIG_set0 failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } len = i2d_ECDSA_SIG(sig, &sigbuf); if (len <= 0) { TRACE_ERROR("i2d_ECDSA_SIG failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } siglen = len; ctx = EVP_PKEY_CTX_new(ec_key, NULL); if (ctx == NULL) { TRACE_ERROR("EVP_PKEY_CTX_new failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } if (EVP_PKEY_verify_init(ctx) <= 0) { TRACE_ERROR("EVP_PKEY_verify_init failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } rc = EVP_PKEY_verify(ctx, sigbuf, siglen, in_data, in_data_len); switch (rc) { case 0: rc = CKR_SIGNATURE_INVALID; break; case 1: rc = CKR_OK; break; default: rc = CKR_FUNCTION_FAILED; break; } out: if (sig != NULL) ECDSA_SIG_free(sig); if (ec_key != NULL) EVP_PKEY_free(ec_key); if (sigbuf != NULL) OPENSSL_free(sigbuf); if (ctx != NULL) EVP_PKEY_CTX_free(ctx); object_ex_data_unlock(key_obj); return rc; } #if OPENSSL_VERSION_PREREQ(3, 0) static CK_RV build_edwards_params(CK_MECHANISM *mech, EVP_PKEY *ed_key, OSSL_PARAM params[3]) { CK_EDDSA_PARAMS* eddsa_params; int i = 0; if (mech->ulParameterLen == sizeof(CK_EDDSA_PARAMS) && mech->pParameter != NULL) { eddsa_params = mech->pParameter; if (eddsa_params->ulContextDataLen != 0 && eddsa_params->pContextData == NULL) { TRACE_ERROR("Invalid mechanism parameter contents\n"); return CKR_MECHANISM_PARAM_INVALID; } if (eddsa_params->phFlag) { #ifdef OSSL_SIGNATURE_PARAM_INSTANCE if (EVP_PKEY_is_a(ed_key, "Ed25519")) params[i++] = OSSL_PARAM_construct_utf8_string( OSSL_SIGNATURE_PARAM_INSTANCE, SN_Ed25519ph, strlen(SN_Ed25519ph)); else params[i++] = OSSL_PARAM_construct_utf8_string( OSSL_SIGNATURE_PARAM_INSTANCE, SN_Ed448ph, strlen(SN_Ed448ph)); #else TRACE_ERROR("OpenSSL does not support the Edwards Instance " "parameter\n"); return CKR_MECHANISM_PARAM_INVALID; #endif } else { if (EVP_PKEY_is_a(ed_key, "Ed25519")) { if (eddsa_params->pContextData != NULL && eddsa_params->ulContextDataLen > 0) { #ifdef OSSL_SIGNATURE_PARAM_INSTANCE params[i++] = OSSL_PARAM_construct_utf8_string( OSSL_SIGNATURE_PARAM_INSTANCE, SN_Ed25519ctx, strlen(SN_Ed25519ctx)); #else TRACE_ERROR("OpenSSL does not support the Edwards Instance " "parameter\n"); return CKR_MECHANISM_PARAM_INVALID; #endif } else { #ifdef OSSL_SIGNATURE_PARAM_INSTANCE params[i++] = OSSL_PARAM_construct_utf8_string( OSSL_SIGNATURE_PARAM_INSTANCE, SN_Ed25519, strlen(SN_Ed25519)); #endif } } else { #ifdef OSSL_SIGNATURE_PARAM_INSTANCE params[i++] = OSSL_PARAM_construct_utf8_string( OSSL_SIGNATURE_PARAM_INSTANCE, SN_Ed448, strlen(SN_Ed448)); #endif } } if (eddsa_params->pContextData != NULL && eddsa_params->ulContextDataLen > 0) { if (eddsa_params->ulContextDataLen > 255) { TRACE_ERROR("Max context size is 255 bytes\n"); return CKR_MECHANISM_PARAM_INVALID; } #ifdef OSSL_SIGNATURE_PARAM_CONTEXT_STRING params[i++] = OSSL_PARAM_construct_octet_string( OSSL_SIGNATURE_PARAM_CONTEXT_STRING, eddsa_params->pContextData, eddsa_params->ulContextDataLen); #else TRACE_ERROR("OpenSSL does not support Edwards Context parameter\n"); return CKR_MECHANISM_PARAM_INVALID; #endif } } else { if (EVP_PKEY_is_a(ed_key, "Ed25519")) { #ifdef OSSL_SIGNATURE_PARAM_INSTANCE params[i++] = OSSL_PARAM_construct_utf8_string( OSSL_SIGNATURE_PARAM_INSTANCE, SN_Ed25519, strlen(SN_Ed25519)); #endif } else { TRACE_ERROR("Mechanism parameter is required for Ed448\n"); return CKR_MECHANISM_PARAM_INVALID; } } params[i++] = OSSL_PARAM_construct_end(); return CKR_OK; } #endif CK_RV openssl_specific_ec_edwards_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_MECHANISM *mech) { #if OPENSSL_VERSION_PREREQ(3, 0) struct openssl_ex_data *ex_data = NULL; EVP_PKEY *ed_key = NULL; EVP_MD_CTX *md_ctx = NULL; OSSL_PARAM params[3]; CK_RV rc = CKR_OK; size_t siglen; UNUSED(tokdata); UNUSED(sess); rc = openssl_get_ex_data(key_obj, (void **)&ex_data, sizeof(struct openssl_ex_data), openssl_need_wr_lock, NULL); if (rc != CKR_OK) return rc; if (ex_data->pkey == NULL) { rc = openssl_make_ec_key_from_template(key_obj->template, &ex_data->pkey); if (rc != CKR_OK) goto out; } ed_key = ex_data->pkey; if (EVP_PKEY_up_ref(ed_key) != 1) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto out; } md_ctx = EVP_MD_CTX_new(); if (md_ctx == NULL) { TRACE_ERROR("EVP_MD_CTX_new failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } rc = build_edwards_params(mech, ed_key, params); if (rc != CKR_OK) goto out; if (EVP_DigestSignInit_ex(md_ctx, NULL, NULL, NULL, NULL, ed_key, params) != 1) { TRACE_ERROR("EVP_DigestSignInit_ex failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } if (EVP_DigestSign(md_ctx, NULL, &siglen, in_data, in_data_len) <= 0) { TRACE_ERROR("EVP_DigestSign failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } if (*out_data_len < siglen) { TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); rc = CKR_BUFFER_TOO_SMALL; goto out; } if (EVP_DigestSign(md_ctx, out_data, &siglen, in_data, in_data_len) <= 0) { TRACE_ERROR("EVP_DigestSign failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } *out_data_len = siglen; out: if (ed_key != NULL) EVP_PKEY_free(ed_key); if (md_ctx != NULL) EVP_MD_CTX_free(md_ctx); object_ex_data_unlock(key_obj); return rc; #else UNUSED(tokdata); UNUSED(sess); UNUSED(in_data); UNUSED(in_data_len); UNUSED(out_data); UNUSED(out_data_len); UNUSED(key_obj); UNUSED(mech); return CKR_MECHANISM_INVALID; #endif } CK_RV openssl_specific_ec_edwards_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, CK_MECHANISM *mech) { #if OPENSSL_VERSION_PREREQ(3, 0) struct openssl_ex_data *ex_data = NULL; EVP_PKEY *ed_key = NULL; EVP_MD_CTX *md_ctx = NULL; OSSL_PARAM params[3]; CK_RV rc = CKR_OK; UNUSED(tokdata); UNUSED(sess); rc = openssl_get_ex_data(key_obj, (void **)&ex_data, sizeof(struct openssl_ex_data), openssl_need_wr_lock, NULL); if (rc != CKR_OK) return rc; if (ex_data->pkey == NULL) { rc = openssl_make_ec_key_from_template(key_obj->template, &ex_data->pkey); if (rc != CKR_OK) goto out; } ed_key = ex_data->pkey; if (EVP_PKEY_up_ref(ed_key) != 1) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto out; } md_ctx = EVP_MD_CTX_new(); if (md_ctx == NULL) { TRACE_ERROR("EVP_MD_CTX_new failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } rc = build_edwards_params(mech, ed_key, params); if (rc != CKR_OK) goto out; if (EVP_DigestVerifyInit_ex(md_ctx, NULL, NULL, NULL, NULL, ed_key, params) != 1) { TRACE_ERROR("EVP_DigestVerifyInit_ex failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } rc = EVP_DigestVerify(md_ctx, signature, signature_len, in_data, in_data_len); switch (rc) { case 0: rc = CKR_SIGNATURE_INVALID; break; case 1: rc = CKR_OK; break; default: TRACE_ERROR("EVP_DigestVerify failed\n"); rc = CKR_FUNCTION_FAILED; break; } out: if (ed_key != NULL) EVP_PKEY_free(ed_key); if (md_ctx != NULL) EVP_MD_CTX_free(md_ctx); object_ex_data_unlock(key_obj); return rc; #else UNUSED(tokdata); UNUSED(sess); UNUSED(in_data); UNUSED(in_data_len); UNUSED(signature); UNUSED(signature_len); UNUSED(key_obj); UNUSED(mech); return CKR_MECHANISM_INVALID; #endif } CK_RV openssl_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, CK_BBOOL cofactor_mode) { #if !OPENSSL_VERSION_PREREQ(3, 0) EC_KEY *pub = NULL, *priv = NULL; #else OSSL_PARAM_BLD *tmpl = NULL; #endif EVP_PKEY *ec_pub = NULL, *ec_priv = NULL; EVP_PKEY_CTX *ctx = NULL; size_t secret_len; int nid, len; CK_RV rc; UNUSED(tokdata); nid = curve_nid_from_params(oid, oid_length); if (nid == NID_undef) { TRACE_ERROR("curve not supported by OpenSSL.\n"); rc = CKR_CURVE_NOT_SUPPORTED; goto out; } #if !OPENSSL_VERSION_PREREQ(3, 0) rc = make_ec_key_from_params(oid, oid_length, &priv); if (rc != CKR_OK) { TRACE_DEVEL("make_ec_key_from_params failed\n"); goto out; } #else tmpl = OSSL_PARAM_BLD_new(); if (tmpl == NULL) { TRACE_ERROR("OSSL_PARAM_BLD_new failed\n"); rc = CKR_HOST_MEMORY; goto out; } if (!OSSL_PARAM_BLD_push_utf8_string(tmpl, OSSL_PKEY_PARAM_GROUP_NAME, OBJ_nid2sn(nid), 0)) { TRACE_ERROR("OSSL_PARAM_BLD_push_utf8_string failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } #endif #if !OPENSSL_VERSION_PREREQ(3, 0) rc = fill_ec_key_from_privkey(priv, priv_bytes, priv_length, &ec_priv); #else rc = fill_ec_key_from_privkey(tmpl, priv_bytes, priv_length, nid, &ec_priv); #endif if (rc != CKR_OK) { TRACE_DEVEL("fill_ec_key_from_privkey failed\n"); goto out; } #if !OPENSSL_VERSION_PREREQ(3, 0) priv = NULL; #else OSSL_PARAM_BLD_free(tmpl); tmpl = NULL; #endif #if !OPENSSL_VERSION_PREREQ(3, 0) rc = make_ec_key_from_params(oid, oid_length, &pub); if (rc != CKR_OK) { TRACE_DEVEL("make_ec_key_from_params failed\n"); goto out; } #else tmpl = OSSL_PARAM_BLD_new(); if (tmpl == NULL) { TRACE_ERROR("OSSL_PARAM_BLD_new failed\n"); rc = CKR_HOST_MEMORY; goto out; } if (!OSSL_PARAM_BLD_push_utf8_string(tmpl, OSSL_PKEY_PARAM_GROUP_NAME, OBJ_nid2sn(nid), 0)) { TRACE_ERROR("OSSL_PARAM_BLD_push_utf8_string failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } #endif #if !OPENSSL_VERSION_PREREQ(3, 0) rc = fill_ec_key_from_pubkey(pub, pub_bytes, pub_length, TRUE, nid, &ec_pub); #else rc = fill_ec_key_from_pubkey(tmpl, pub_bytes, pub_length, TRUE, nid, &ec_pub); #endif if (rc != CKR_OK) { TRACE_DEVEL("fill_ec_key_from_pubkey failed\n"); goto out; } #if !OPENSSL_VERSION_PREREQ(3, 0) pub = NULL; #else OSSL_PARAM_BLD_free(tmpl); tmpl = NULL; #endif ctx = EVP_PKEY_CTX_new(ec_priv, NULL); if (ctx == NULL) { TRACE_DEVEL("EVP_PKEY_CTX_new failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } if (EVP_PKEY_derive_init(ctx) <= 0 || EVP_PKEY_derive_set_peer(ctx, ec_pub) <= 0) { TRACE_DEVEL("EVP_PKEY_derive_init/EVP_PKEY_derive_set_peer failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } switch (nid) { case NID_X25519: case NID_X448: if (cofactor_mode) { TRACE_DEVEL("Cofactor mode does not work with Montgomrey keys\n"); rc = CKR_KEY_TYPE_INCONSISTENT; goto out; } break; default: if (EVP_PKEY_CTX_set_ecdh_cofactor_mode(ctx, cofactor_mode ? 1 : 0) <= 0) { TRACE_DEVEL("EVP_PKEY_CTX_set_ecdh_cofactor_mode failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } break; } len = ec_prime_len_from_nid(nid); if (len <= 0) { TRACE_ERROR("ec_prime_len_from_nid failed\n"); rc = CKR_CURVE_NOT_SUPPORTED; goto out; } secret_len = len; if (EVP_PKEY_derive(ctx, secret_value, &secret_len) <= 0) { TRACE_DEVEL("ECDH_compute_key failed\n"); rc = CKR_FUNCTION_FAILED; *secret_value_len = 0; goto out; } *secret_value_len = secret_len; out: #if !OPENSSL_VERSION_PREREQ(3, 0) if (priv != NULL) EC_KEY_free(priv); if (pub != NULL) EC_KEY_free(pub); #else if (tmpl != NULL) OSSL_PARAM_BLD_free(tmpl); #endif if (ec_priv != NULL) EVP_PKEY_free(ec_priv); if (ec_pub != NULL) EVP_PKEY_free(ec_pub); if (ctx != NULL) EVP_PKEY_CTX_free(ctx); return rc; } #endif static const EVP_MD *md_from_mech(CK_MECHANISM *mech) { const EVP_MD *md = NULL; switch (mech->mechanism) { case CKM_SHA_1: md = EVP_sha1(); break; case CKM_SHA224: md = EVP_sha224(); break; case CKM_SHA256: md = EVP_sha256(); break; case CKM_SHA384: md = EVP_sha384(); break; case CKM_SHA512: md = EVP_sha512(); break; #ifdef NID_sha512_224WithRSAEncryption case CKM_SHA512_224: md = EVP_sha512_224(); break; #endif #ifdef NID_sha512_256WithRSAEncryption case CKM_SHA512_256: md = EVP_sha512_256(); break; #endif #ifdef NID_sha3_224 case CKM_SHA3_224: case CKM_IBM_SHA3_224: md = EVP_sha3_224(); break; #endif #ifdef NID_sha3_256 case CKM_SHA3_256: case CKM_IBM_SHA3_256: md = EVP_sha3_256(); break; #endif #ifdef NID_sha3_384 case CKM_SHA3_384: case CKM_IBM_SHA3_384: md = EVP_sha3_384(); break; #endif #ifdef NID_sha3_512 case CKM_SHA3_512: case CKM_IBM_SHA3_512: md = EVP_sha3_512(); break; #endif #ifdef NID_shake128 case CKM_OCK_SHAKE128: md = EVP_shake128(); break; #endif #ifdef NID_shake256 case CKM_OCK_SHAKE256: md = EVP_shake256(); break; #endif default: break; } return md; } #if !OPENSSL_VERSION_PREREQ(3, 0) static EVP_MD_CTX *md_ctx_from_context(DIGEST_CONTEXT *ctx) { const EVP_MD *md; EVP_MD_CTX *md_ctx; md_ctx = EVP_MD_CTX_new(); if (md_ctx == NULL) return NULL; md = md_from_mech(&ctx->mech); if (md == NULL || !EVP_DigestInit_ex(md_ctx, md, NULL)) { TRACE_ERROR("md_from_mech or EVP_DigestInit_ex failed\n"); EVP_MD_CTX_free(md_ctx); return NULL; } if (ctx->context_len == 0) { ctx->context_len = EVP_MD_meth_get_app_datasize(EVP_MD_CTX_md(md_ctx)); ctx->context = malloc(ctx->context_len); if (ctx->context == NULL) { TRACE_ERROR("malloc failed\n"); EVP_MD_CTX_free(md_ctx); ctx->context_len = 0; return NULL; } /* Save context data for later use */ memcpy(ctx->context, EVP_MD_CTX_md_data(md_ctx), ctx->context_len); } else { if (ctx->context_len != (CK_ULONG)EVP_MD_meth_get_app_datasize(EVP_MD_CTX_md(md_ctx))) { TRACE_ERROR("context size mismatcht\n"); return NULL; } /* restore the MD context data */ memcpy(EVP_MD_CTX_md_data(md_ctx), ctx->context, ctx->context_len); } return md_ctx; } #endif #if OPENSSL_VERSION_PREREQ(3, 0) static void openssl_specific_sha_free(STDLL_TokData_t *tokdata, SESSION *sess, CK_BYTE *context, CK_ULONG context_len) { UNUSED(tokdata); UNUSED(sess); UNUSED(context_len); EVP_MD_CTX_free((EVP_MD_CTX *)context); } #endif CK_RV openssl_specific_sha_init(STDLL_TokData_t *tokdata, DIGEST_CONTEXT *ctx, CK_MECHANISM *mech) { #if !OPENSSL_VERSION_PREREQ(3, 0) EVP_MD_CTX *md_ctx; #else const EVP_MD *md; #endif UNUSED(tokdata); ctx->mech.ulParameterLen = mech->ulParameterLen; ctx->mech.mechanism = mech->mechanism; #if !OPENSSL_VERSION_PREREQ(3, 0) md_ctx = md_ctx_from_context(ctx); if (md_ctx == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); return CKR_HOST_MEMORY; } EVP_MD_CTX_free(md_ctx); #else ctx->context_len = 1; ctx->context = (CK_BYTE *)EVP_MD_CTX_new(); if (ctx->context == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); return CKR_HOST_MEMORY; } md = md_from_mech(&ctx->mech); if (md == NULL || !EVP_DigestInit_ex((EVP_MD_CTX *)ctx->context, md, NULL)) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); EVP_MD_CTX_free((EVP_MD_CTX *)ctx->context); return CKR_FUNCTION_FAILED; } ctx->state_unsaveable = CK_TRUE; ctx->context_free_func = openssl_specific_sha_free; #endif return CKR_OK; } CK_RV openssl_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 len; CK_RV rc = CKR_OK; CK_ULONG hsize; #if !OPENSSL_VERSION_PREREQ(3, 0) EVP_MD_CTX *md_ctx; #endif UNUSED(tokdata); if (!ctx || !ctx->context) return CKR_OPERATION_NOT_INITIALIZED; if (!in_data || !out_data) return CKR_ARGUMENTS_BAD; #if !OPENSSL_VERSION_PREREQ(3, 0) /* Recreate the OpenSSL MD context from the saved context */ md_ctx = md_ctx_from_context(ctx); if (md_ctx == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); return CKR_HOST_MEMORY; } switch (ctx->mech.mechanism) { case CKM_OCK_SHAKE128: case CKM_OCK_SHAKE256: if (ctx->mech.ulParameterLen != sizeof(CK_ULONG)) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto out; } hsize = *(CK_ULONG *)ctx->mech.pParameter; if (*out_data_len < hsize) { TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); rc = CKR_BUFFER_TOO_SMALL; goto out; } len = hsize; if (!EVP_DigestUpdate(md_ctx, in_data, in_data_len) || !EVP_DigestFinalXOF(md_ctx, out_data, len)) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto out; } break; default: if (*out_data_len < (CK_ULONG)EVP_MD_CTX_size(md_ctx)) return CKR_BUFFER_TOO_SMALL; len = *out_data_len; if (!EVP_DigestUpdate(md_ctx, in_data, in_data_len) || !EVP_DigestFinal(md_ctx, out_data, &len)) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto out; } } *out_data_len = len; #else switch (ctx->mech.mechanism) { case CKM_OCK_SHAKE128: case CKM_OCK_SHAKE256: if (ctx->mech.ulParameterLen != sizeof(CK_ULONG)) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); return CKR_MECHANISM_PARAM_INVALID; } hsize = *(CK_ULONG *)ctx->mech.pParameter; if (*out_data_len < hsize) { TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); return CKR_BUFFER_TOO_SMALL; } len = hsize; if (!EVP_DigestUpdate((EVP_MD_CTX *)ctx->context, in_data, in_data_len) || !EVP_DigestFinalXOF((EVP_MD_CTX *)ctx->context, out_data, len)) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } break; default: if (*out_data_len < (CK_ULONG)EVP_MD_CTX_size((EVP_MD_CTX *)ctx->context)) { TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); return CKR_BUFFER_TOO_SMALL; } len = *out_data_len; if (!EVP_DigestUpdate((EVP_MD_CTX *)ctx->context, in_data, in_data_len) || !EVP_DigestFinal((EVP_MD_CTX *)ctx->context, out_data, &len)) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } } *out_data_len = len; #endif #if !OPENSSL_VERSION_PREREQ(3, 0) out: EVP_MD_CTX_free(md_ctx); free(ctx->context); #else EVP_MD_CTX_free((EVP_MD_CTX *)ctx->context); #endif ctx->context = NULL; ctx->context_len = 0; ctx->context_free_func = NULL; return rc; } CK_RV openssl_specific_sha_update(STDLL_TokData_t *tokdata, DIGEST_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len) { #if !OPENSSL_VERSION_PREREQ(3, 0) EVP_MD_CTX *md_ctx; #endif UNUSED(tokdata); if (!ctx || !ctx->context) return CKR_OPERATION_NOT_INITIALIZED; if (!in_data) return CKR_ARGUMENTS_BAD; #if !OPENSSL_VERSION_PREREQ(3, 0) /* Recreate the OpenSSL MD context from the saved context */ md_ctx = md_ctx_from_context(ctx); if (md_ctx == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); return CKR_HOST_MEMORY; } if (!EVP_DigestUpdate(md_ctx, in_data, in_data_len)) { EVP_MD_CTX_free(md_ctx); free(ctx->context); ctx->context = NULL; ctx->context_len = 0; ctx->context_free_func = NULL; TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } /* Save context data for later use */ memcpy(ctx->context, EVP_MD_CTX_md_data(md_ctx), ctx->context_len); EVP_MD_CTX_free(md_ctx); #else if (!EVP_DigestUpdate((EVP_MD_CTX *)ctx->context, in_data, in_data_len)) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } #endif return CKR_OK; } CK_RV openssl_specific_sha_final(STDLL_TokData_t *tokdata, DIGEST_CONTEXT *ctx, CK_BYTE *out_data, CK_ULONG *out_data_len) { unsigned int len; CK_RV rc = CKR_OK; CK_ULONG hsize; #if !OPENSSL_VERSION_PREREQ(3, 0) EVP_MD_CTX *md_ctx; #endif UNUSED(tokdata); if (!ctx || !ctx->context) return CKR_OPERATION_NOT_INITIALIZED; if (!out_data) return CKR_ARGUMENTS_BAD; #if !OPENSSL_VERSION_PREREQ(3, 0) /* Recreate the OpenSSL MD context from the saved context */ md_ctx = md_ctx_from_context(ctx); if (md_ctx == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); return CKR_HOST_MEMORY; } switch (ctx->mech.mechanism) { case CKM_OCK_SHAKE128: case CKM_OCK_SHAKE256: if (ctx->mech.ulParameterLen != sizeof(CK_ULONG)) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto out; } hsize = *(CK_ULONG *)ctx->mech.pParameter; if (*out_data_len < hsize) { TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); rc = CKR_BUFFER_TOO_SMALL; goto out; } len = hsize; if (!EVP_DigestFinalXOF(md_ctx, out_data, len)) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto out; } break; default: if (*out_data_len < (CK_ULONG)EVP_MD_CTX_size(md_ctx)) return CKR_BUFFER_TOO_SMALL; len = *out_data_len; if (!EVP_DigestFinal(md_ctx, out_data, &len)) { rc = CKR_FUNCTION_FAILED; goto out; } } *out_data_len = len; out: EVP_MD_CTX_free(md_ctx); free(ctx->context); ctx->context = NULL; ctx->context_len = 0; ctx->context_free_func = NULL; #else switch (ctx->mech.mechanism) { case CKM_OCK_SHAKE128: case CKM_OCK_SHAKE256: if (ctx->mech.ulParameterLen != sizeof(CK_ULONG)) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); return CKR_MECHANISM_PARAM_INVALID; } hsize = *(CK_ULONG *)ctx->mech.pParameter; if (*out_data_len < hsize) { TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); return CKR_BUFFER_TOO_SMALL; } len = hsize; if (!EVP_DigestFinalXOF((EVP_MD_CTX *)ctx->context, out_data, len)) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } break; default: if (*out_data_len < (CK_ULONG)EVP_MD_CTX_size((EVP_MD_CTX *)ctx->context)) { TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); return CKR_BUFFER_TOO_SMALL; } len = *out_data_len; if (!EVP_DigestFinal((EVP_MD_CTX *)ctx->context, out_data, &len)) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } } *out_data_len = len; EVP_MD_CTX_free((EVP_MD_CTX *)ctx->context); ctx->context = NULL; ctx->context_len = 0; ctx->context_free_func = NULL; #endif return rc; } CK_RV openssl_specific_shake_key_derive(STDLL_TokData_t *tokdata, SESSION *sess, CK_MECHANISM *mech, OBJECT *base_key_obj, CK_KEY_TYPE base_key_type, OBJECT *derived_key_obj, CK_KEY_TYPE derived_key_type, CK_ULONG derived_key_len) { CK_ATTRIBUTE *base_key_value = NULL; CK_ATTRIBUTE *value_attr = NULL, *vallen_attr = NULL; CK_BYTE *derived_key_value = NULL; EVP_MD_CTX *ctx = NULL; const EVP_MD *md = NULL; CK_RV rc; UNUSED(tokdata); UNUSED(sess); UNUSED(base_key_type); rc = template_attribute_get_non_empty(base_key_obj->template, CKA_VALUE, &base_key_value); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the base key.\n"); return rc; } derived_key_value = malloc(derived_key_len); if (derived_key_value == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto out; } ctx = EVP_MD_CTX_new(); if (ctx == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto out; } switch (mech->mechanism) { case CKM_SHAKE_128_KEY_DERIVATION: md = EVP_shake128(); break; case CKM_SHAKE_256_KEY_DERIVATION: md = EVP_shake256(); break; default: TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); rc = CKR_MECHANISM_INVALID; goto out; } if (md == NULL || !EVP_DigestInit_ex(ctx, md, NULL) || !EVP_DigestUpdate(ctx, base_key_value->pValue, base_key_value->ulValueLen) || !EVP_DigestFinalXOF(ctx, derived_key_value, derived_key_len)) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto out; } rc = build_attribute(CKA_VALUE, derived_key_value, derived_key_len, &value_attr); if (rc != CKR_OK) { TRACE_ERROR("Failed to build the attribute from CKA_VALUE, rc=0x%lx.\n", rc); goto out; } switch (derived_key_type) { case CKK_GENERIC_SECRET: case CKK_SHA_1_HMAC: case CKK_SHA256_HMAC: case CKK_SHA384_HMAC: case CKK_SHA512_HMAC: case CKK_SHA224_HMAC: case CKK_SHA3_224_HMAC: case CKK_SHA3_256_HMAC: case CKK_SHA3_384_HMAC: case CKK_SHA3_512_HMAC: case CKK_SHA512_224_HMAC: case CKK_SHA512_256_HMAC: case CKK_AES: case CKK_AES_XTS: /* Supply CKA_VALUE_LEN since this is required for those key types */ rc = build_attribute(CKA_VALUE_LEN, (CK_BYTE*)&derived_key_len, sizeof(derived_key_len), &vallen_attr); if (rc != CKR_OK) { TRACE_ERROR("Failed to build the attribute from CKA_VALUE_LEN, " "rc=0x%lx.\n", rc); goto out; } break; case CKK_DES: if (des_check_weak_key(derived_key_value)) { TRACE_ERROR("Derived key is a weak DES key\n"); rc = CKR_FUNCTION_FAILED; goto out; } break; default: break; } rc = template_update_attribute(derived_key_obj->template, value_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto out; } value_attr = NULL; if (vallen_attr != NULL) { rc = template_update_attribute(derived_key_obj->template, vallen_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto out; } vallen_attr = NULL; } out: if (ctx != NULL) EVP_MD_CTX_free(ctx); if (derived_key_value != NULL) { OPENSSL_cleanse(derived_key_value, derived_key_len); free(derived_key_value); } if (value_attr != NULL) free(value_attr); if (vallen_attr != NULL) free(vallen_attr); return rc; } static const EVP_CIPHER *openssl_cipher_from_mech(CK_MECHANISM_TYPE mech, CK_ULONG keylen, CK_KEY_TYPE keytype) { switch (mech) { case CKM_DES_ECB: if (keytype == CKK_DES && keylen == DES_KEY_SIZE) return EVP_des_ecb(); break; case CKM_DES_CBC: if (keytype == CKK_DES && keylen == DES_KEY_SIZE) return EVP_des_cbc(); break; case CKM_DES3_ECB: if (keytype == CKK_DES2 && keylen == DES_KEY_SIZE * 2) return EVP_des_ede_ecb(); if (keytype == CKK_DES3 && keylen == DES_KEY_SIZE * 3) return EVP_des_ede3_ecb(); break; case CKM_DES3_CBC: if (keytype == CKK_DES2 && keylen == DES_KEY_SIZE * 2) return EVP_des_ede_cbc(); if (keytype == CKK_DES3 && keylen == DES_KEY_SIZE * 3) return EVP_des_ede3_cbc(); break; case CKM_DES_OFB64: if (keytype == CKK_DES && keylen == DES_KEY_SIZE) return EVP_des_ofb(); if (keytype == CKK_DES2 && keylen == DES_KEY_SIZE * 2) return EVP_des_ede_ofb(); if (keytype == CKK_DES3 && keylen == DES_KEY_SIZE * 3) return EVP_des_ede3_ofb(); break; case CKM_DES_CFB8: if (keytype == CKK_DES && keylen == DES_KEY_SIZE) return EVP_des_cfb8(); if (keytype == CKK_DES3 && keylen == DES_KEY_SIZE * 3) return EVP_des_ede3_cfb8(); break; case CKM_DES_CFB64: if (keytype == CKK_DES && keylen == DES_KEY_SIZE) return EVP_des_cfb64(); if (keytype == CKK_DES2 && keylen == DES_KEY_SIZE * 2) return EVP_des_ede_cfb64(); if (keytype == CKK_DES3 && keylen == DES_KEY_SIZE * 3) return EVP_des_ede3_cfb64(); break; case CKM_AES_ECB: if (keytype != CKK_AES) break; switch (keylen * 8) { case 128: return EVP_aes_128_ecb(); case 192: return EVP_aes_192_ecb(); case 256: return EVP_aes_256_ecb(); default: break; } break; case CKM_AES_CBC: if (keytype != CKK_AES) break; switch (keylen * 8) { case 128: return EVP_aes_128_cbc(); case 192: return EVP_aes_192_cbc(); case 256: return EVP_aes_256_cbc(); default: break; } break; case CKM_AES_CTR: if (keytype != CKK_AES) break; switch (keylen * 8) { case 128: return EVP_aes_128_ctr(); case 192: return EVP_aes_192_ctr(); case 256: return EVP_aes_256_ctr(); default: break; } break; case CKM_AES_OFB: if (keytype != CKK_AES) break; switch (keylen * 8) { case 128: return EVP_aes_128_ofb(); case 192: return EVP_aes_192_ofb(); case 256: return EVP_aes_256_ofb(); default: break; } break; case CKM_AES_CFB8: if (keytype != CKK_AES) break; switch (keylen * 8) { case 128: return EVP_aes_128_cfb8(); case 192: return EVP_aes_192_cfb8(); case 256: return EVP_aes_256_cfb8(); default: break; } break; case CKM_AES_CFB128: if (keytype != CKK_AES) break; switch (keylen * 8) { case 128: return EVP_aes_128_cfb128(); case 192: return EVP_aes_192_cfb128(); case 256: return EVP_aes_256_cfb128(); default: break; } break; case CKM_AES_GCM: if (keytype != CKK_AES) break; switch (keylen * 8) { case 128: return EVP_aes_128_gcm(); case 192: return EVP_aes_192_gcm(); case 256: return EVP_aes_256_gcm(); default: break; } break; case CKM_AES_XTS: if (keytype != CKK_AES_XTS) break; switch (keylen * 8) { case 256: return EVP_aes_128_xts(); case 512: return EVP_aes_256_xts(); default: break; } break; case CKM_AES_KEY_WRAP: if (keytype != CKK_AES) break; switch (keylen * 8) { case 128: return EVP_aes_128_wrap(); case 192: return EVP_aes_192_wrap(); case 256: return EVP_aes_256_wrap(); default: break; } break; case CKM_AES_KEY_WRAP_KWP: if (keytype != CKK_AES) break; switch (keylen * 8) { case 128: return EVP_aes_128_wrap_pad(); case 192: return EVP_aes_192_wrap_pad(); case 256: return EVP_aes_256_wrap_pad(); default: break; } break; default: TRACE_ERROR("mechanism 0x%lx not supported\n", mech); return NULL; } TRACE_ERROR("key length %lu or key type %lu not supported for mech 0x%lx\n", keylen, keytype, mech); return NULL; } static CK_RV openssl_cipher_perform(OBJECT *key, CK_MECHANISM_TYPE mech, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, CK_BYTE *init_v, CK_BYTE *out_v, CK_BYTE encrypt) { const EVP_CIPHER *cipher = NULL; CK_ATTRIBUTE *key_attr = NULL; EVP_CIPHER_CTX *ctx = NULL; CK_KEY_TYPE keytype = 0; int blocksize, outlen = 0, outlen2 = 0; CK_RV rc; rc = template_attribute_get_ulong(key->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key\n"); return rc; } rc = template_attribute_get_non_empty(key->template, CKA_VALUE, &key_attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); return rc; } cipher = openssl_cipher_from_mech(mech, key_attr->ulValueLen, keytype); if (cipher == NULL) { TRACE_ERROR("Cipher not supported.\n"); return CKR_MECHANISM_INVALID; } #if !OPENSSL_VERSION_PREREQ(3, 0) blocksize = EVP_CIPHER_block_size(cipher); #else blocksize = EVP_CIPHER_get_block_size(cipher); #endif if ((mech != CKM_AES_KEY_WRAP_KWP && (mech == CKM_AES_XTS ? in_data_len < AES_BLOCK_SIZE : in_data_len % blocksize)) || in_data_len > INT_MAX) { TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); return CKR_DATA_LEN_RANGE; } ctx = EVP_CIPHER_CTX_new(); if (ctx == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); return CKR_HOST_MEMORY; } switch (mech) { case CKM_AES_KEY_WRAP: case CKM_AES_KEY_WRAP_KWP: EVP_CIPHER_CTX_set_flags(ctx, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW); break; } if (EVP_CipherInit_ex(ctx, cipher, NULL, key_attr->pValue, init_v, encrypt ? 1 : 0) != 1) { TRACE_ERROR("%s\n", ock_err(ERR_GENERAL_ERROR)); rc = CKR_GENERAL_ERROR; goto done; } if (EVP_CIPHER_CTX_set_padding(ctx, 0) != 1 || EVP_CipherUpdate(ctx, out_data, &outlen, in_data, in_data_len) != 1 || EVP_CipherFinal_ex(ctx, out_data, &outlen2) != 1) { TRACE_ERROR("%s\n", ock_err(ERR_GENERAL_ERROR)); rc = CKR_GENERAL_ERROR; goto done; } if (out_v != NULL) { #if !OPENSSL_VERSION_PREREQ(3, 0) memcpy(out_v, EVP_CIPHER_CTX_iv(ctx), EVP_CIPHER_CTX_iv_length(ctx)); #else if (EVP_CIPHER_CTX_get_updated_iv(ctx, out_v, EVP_CIPHER_CTX_get_iv_length(ctx)) != 1) { TRACE_ERROR("%s\n", ock_err(ERR_GENERAL_ERROR)); rc = CKR_GENERAL_ERROR; goto done; } #endif } *out_data_len = outlen + outlen2; rc = CKR_OK; done: EVP_CIPHER_CTX_free(ctx); return rc; } CK_RV openssl_cmac_perform(CK_MECHANISM_TYPE mech, CK_BYTE *message, CK_ULONG message_len, OBJECT *key, CK_BYTE *mac, CK_BBOOL first, CK_BBOOL last, CK_VOID_PTR *ctx) { int rc; size_t maclen; CK_RV rv = CKR_OK; CK_ATTRIBUTE *key_attr = NULL; const EVP_CIPHER *cipher; CK_KEY_TYPE keytype = 0; struct cmac_ctx { #if !OPENSSL_VERSION_PREREQ(3, 0) EVP_MD_CTX *mctx; EVP_PKEY_CTX *pctx; EVP_PKEY *pkey; #else EVP_MAC *mac; EVP_MAC_CTX *mctx; #endif int macsize; }; struct cmac_ctx *cmac = NULL; #if OPENSSL_VERSION_PREREQ(3, 0) OSSL_PARAM params[2]; #endif if (first) { if (key == NULL) return CKR_ARGUMENTS_BAD; rv = template_attribute_get_ulong(key->template, CKA_KEY_TYPE, &keytype); if (rv != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key\n"); goto err; } rv = template_attribute_get_non_empty(key->template, CKA_VALUE, &key_attr); if (rv != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); goto err; } switch (mech) { case CKM_AES_CMAC: cipher = openssl_cipher_from_mech(CKM_AES_CBC, key_attr->ulValueLen, keytype); break; case CKM_DES3_CMAC: cipher = openssl_cipher_from_mech(CKM_DES3_CBC, key_attr->ulValueLen, keytype); break; default: TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); rv = CKR_MECHANISM_INVALID; goto err; } if (cipher == NULL) { TRACE_ERROR("Cipher not supported.\n"); rv = CKR_MECHANISM_INVALID; goto err; } cmac = calloc(1, sizeof(*cmac)); if (cmac == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rv = CKR_HOST_MEMORY; goto err; } cmac->macsize = EVP_CIPHER_block_size(cipher); #if !OPENSSL_VERSION_PREREQ(3, 0) cmac->mctx = EVP_MD_CTX_new(); if (cmac->mctx == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rv = CKR_HOST_MEMORY; goto err; } cmac->pkey = EVP_PKEY_new_CMAC_key(NULL, key_attr->pValue, key_attr->ulValueLen, cipher); if (cmac->pkey == NULL) { TRACE_ERROR("EVP_DigestSignInit failed\n"); rv = CKR_FUNCTION_FAILED; goto err; } if (EVP_DigestSignInit(cmac->mctx, &cmac->pctx, NULL, NULL, cmac->pkey) != 1) { TRACE_ERROR("EVP_DigestSignInit failed\n"); rv = CKR_FUNCTION_FAILED; goto err; } #else cmac->mac = EVP_MAC_fetch(NULL, "CMAC", NULL); if (cmac->mac == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rv = CKR_FUNCTION_FAILED; goto err; } cmac->mctx = EVP_MAC_CTX_new(cmac->mac); if (cmac->mctx == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rv = CKR_HOST_MEMORY; goto err; } params[0] = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_CIPHER, (char *)EVP_CIPHER_get0_name(cipher), 0); params[1] = OSSL_PARAM_construct_end(); if (!EVP_MAC_init(cmac->mctx, key_attr->pValue, key_attr->ulValueLen, params)) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rv = CKR_FUNCTION_FAILED; goto err; } #endif *ctx = cmac; } cmac = (struct cmac_ctx *)*ctx; if (cmac == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rv = CKR_FUNCTION_FAILED; goto err; } #if !OPENSSL_VERSION_PREREQ(3, 0) rc = EVP_DigestSignUpdate(cmac->mctx, message, message_len); #else rc = EVP_MAC_update(cmac->mctx, message, message_len); #endif if (rc != 1 || message_len > INT_MAX) { #if !OPENSSL_VERSION_PREREQ(3, 0) TRACE_ERROR("EVP_DigestSignUpdate failed\n"); #else TRACE_ERROR("EVP_MAC_update failed\n"); #endif rv = CKR_FUNCTION_FAILED; goto err; } if (last) { maclen = cmac->macsize; #if !OPENSSL_VERSION_PREREQ(3, 0) rc = EVP_DigestSignFinal(cmac->mctx, mac, &maclen); #else rc = EVP_MAC_final(cmac->mctx, mac, &maclen, maclen); #endif if (rc != 1) { #if !OPENSSL_VERSION_PREREQ(3, 0) TRACE_ERROR("EVP_DigestSignFinal failed\n"); #else TRACE_ERROR("EVP_MAC_final failed\n"); #endif rv = CKR_FUNCTION_FAILED; goto err; } #if !OPENSSL_VERSION_PREREQ(3, 0) EVP_MD_CTX_free(cmac->mctx); /* frees pctx */ EVP_PKEY_free(cmac->pkey); #else EVP_MAC_CTX_free(cmac->mctx); EVP_MAC_free(cmac->mac); #endif free(cmac); *ctx = NULL; } return CKR_OK; err: if (cmac != NULL) { #if !OPENSSL_VERSION_PREREQ(3, 0) if (cmac->mctx != NULL) EVP_MD_CTX_free(cmac->mctx); /* frees pctx */ if (cmac->pkey != NULL) EVP_PKEY_free(cmac->pkey); #else if (cmac->mctx != NULL) EVP_MAC_CTX_free(cmac->mctx); if (cmac->mac != NULL) EVP_MAC_free(cmac->mac); #endif free(cmac); } *ctx = NULL; return rv; } CK_RV openssl_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) { UNUSED(tokdata); return openssl_cipher_perform(key, CKM_AES_ECB, in_data, in_data_len, out_data, out_data_len, NULL, NULL, encrypt); } CK_RV openssl_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) { UNUSED(tokdata); return openssl_cipher_perform(key, CKM_AES_CBC, in_data, in_data_len, out_data, out_data_len, init_v, NULL, encrypt); } CK_RV openssl_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) { unsigned char init_v[AES_BLOCK_SIZE]; CK_RV rc; UNUSED(tokdata); if (counter_width > AES_BLOCK_SIZE * 8 || counter_width == 0) { TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); return CKR_ARGUMENTS_BAD; } memset(init_v, 0, sizeof(init_v)); memcpy(init_v, counterblock + AES_BLOCK_SIZE - (counter_width / 8), counter_width / 8); rc = openssl_cipher_perform(key, CKM_AES_CTR, in_data, in_data_len, out_data, out_data_len, init_v, init_v, encrypt); if (rc == CKR_OK) memcpy(counterblock, init_v + AES_BLOCK_SIZE - (counter_width / 8), counter_width / 8); return rc; } CK_RV openssl_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, CK_BYTE encrypt) { CK_ULONG out_data_len; UNUSED(tokdata); return openssl_cipher_perform(key, CKM_AES_OFB, in_data, in_data_len, out_data, &out_data_len, init_v, init_v, encrypt); } CK_RV openssl_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, CK_ULONG cfb_len, CK_BYTE encrypt) { CK_ULONG out_data_len; CK_MECHANISM_TYPE mech; UNUSED(tokdata); switch (cfb_len * 8) { case 8: mech = CKM_AES_CFB8; break; case 128: mech = CKM_AES_CFB128; break; default: TRACE_ERROR("CFB length %lu not supported\n", cfb_len); return CKR_MECHANISM_INVALID; } return openssl_cipher_perform(key, mech, in_data, in_data_len, out_data, &out_data_len, init_v, init_v, encrypt); } static void openssl_specific_aes_gcm_free(STDLL_TokData_t *tokdata, struct _SESSION *sess, CK_BYTE *context, CK_ULONG context_len) { AES_GCM_CONTEXT *ctx = (AES_GCM_CONTEXT *)context; UNUSED(tokdata); UNUSED(sess); UNUSED(context_len); if (ctx == NULL) return; if ((EVP_CIPHER_CTX *)ctx->ulClen != NULL) EVP_CIPHER_CTX_free((EVP_CIPHER_CTX *)ctx->ulClen); free(context); } CK_RV openssl_specific_aes_gcm_init(STDLL_TokData_t *tokdata, SESSION *sess, ENCR_DECR_CONTEXT *ctx, CK_MECHANISM *mech, CK_OBJECT_HANDLE hkey, CK_BYTE encrypt) { CK_GCM_PARAMS *aes_gcm_param = NULL; AES_GCM_CONTEXT *context = NULL; OBJECT *key = NULL; EVP_CIPHER_CTX *gcm_ctx = NULL; CK_ATTRIBUTE *attr = NULL; unsigned char akey[32]; const EVP_CIPHER *cipher = NULL; CK_ULONG keylen, tag_len; int outlen; CK_RV rc; UNUSED(sess); context = (AES_GCM_CONTEXT *)ctx->context; aes_gcm_param = (CK_GCM_PARAMS *)mech->pParameter; tag_len = (aes_gcm_param->ulTagBits + 7) / 8; if (tag_len > AES_BLOCK_SIZE) { TRACE_ERROR("Tag len too large.\n"); return CKR_MECHANISM_PARAM_INVALID; } // get the key value rc = object_mgr_find_in_map_nocache(tokdata, hkey, &key, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to find specified object.\n"); return rc; } rc = template_attribute_get_non_empty(key->template, CKA_VALUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key\n"); goto done; } keylen = attr->ulValueLen; cipher = openssl_cipher_from_mech(mech->mechanism, keylen, CKK_AES); if (cipher == NULL) { rc = CKR_MECHANISM_INVALID; goto done; } memcpy(akey, attr->pValue, keylen); gcm_ctx = EVP_CIPHER_CTX_new(); if (gcm_ctx == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto done; } if (EVP_CipherInit_ex(gcm_ctx, cipher, NULL, NULL, NULL, encrypt ? 1 : 0) != 1 || EVP_CIPHER_CTX_ctrl(gcm_ctx, EVP_CTRL_AEAD_SET_IVLEN, aes_gcm_param->ulIvLen, NULL) != 1 || EVP_CipherInit_ex(gcm_ctx, NULL, NULL, akey, aes_gcm_param->pIv, encrypt ? 1 : 0) != 1) { TRACE_ERROR("GCM context initialization failed\n"); rc = CKR_GENERAL_ERROR; goto done; } if (aes_gcm_param->ulAADLen > 0) { if (EVP_CipherUpdate(gcm_ctx, NULL, &outlen, aes_gcm_param->pAAD, aes_gcm_param->ulAADLen) != 1) { TRACE_ERROR("GCM add AAD data failed\n"); rc = CKR_GENERAL_ERROR; goto done; } } /* (Miss-)use the ulClen of AES_GCM_CONTEXT to store the context */ context->ulClen = (CK_ULONG)gcm_ctx; ctx->state_unsaveable = CK_TRUE; ctx->context_free_func = openssl_specific_aes_gcm_free; done: object_put(tokdata, key, TRUE); key = NULL; if (rc != CKR_OK) EVP_CIPHER_CTX_free(gcm_ctx); return rc; } CK_RV openssl_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) { AES_GCM_CONTEXT *context = NULL; CK_GCM_PARAMS *aes_gcm_param = NULL; EVP_CIPHER_CTX *gcm_ctx = NULL; CK_RV rc = CKR_OK; CK_ULONG tag_len; int outlen, finlen; UNUSED(tokdata); UNUSED(sess); context = (AES_GCM_CONTEXT *)ctx->context; gcm_ctx = (EVP_CIPHER_CTX *)context->ulClen; aes_gcm_param = (CK_GCM_PARAMS *)ctx->mech.pParameter; tag_len = (aes_gcm_param->ulTagBits + 7) / 8; if (encrypt) { /* encrypt */ if (EVP_CipherUpdate(gcm_ctx, out_data, &outlen, in_data, in_data_len) != 1 || EVP_CipherFinal_ex(gcm_ctx, out_data + outlen, &finlen) != 1) { TRACE_ERROR("GCM add plaintext data failed\n"); rc = CKR_GENERAL_ERROR; goto done; } /* Append the tag to the output */ if (EVP_CIPHER_CTX_ctrl(gcm_ctx, EVP_CTRL_AEAD_GET_TAG, tag_len, out_data + outlen + finlen) != 1) { TRACE_ERROR("GCM get tag failed\n"); rc = CKR_GENERAL_ERROR; goto done; } *out_data_len = outlen + finlen + tag_len; } else { /* decrypt data exluding the tag */ if (EVP_CipherUpdate(gcm_ctx, out_data, &outlen, in_data, in_data_len - tag_len) != 1) { TRACE_ERROR("GCM add ciphertext data failed\n"); rc = CKR_GENERAL_ERROR; goto done; } /* Set the expected tag */ if (EVP_CIPHER_CTX_ctrl(gcm_ctx, EVP_CTRL_AEAD_SET_TAG, tag_len, in_data + in_data_len - tag_len) != 1) { TRACE_ERROR("GCM set tag failed\n"); rc = CKR_GENERAL_ERROR; goto done; } /* Finalize the decryption */ if(EVP_CipherFinal_ex(gcm_ctx, out_data + outlen, &finlen) != 1) { TRACE_ERROR("GCM finalize decryption failed\n"); rc = CKR_ENCRYPTED_DATA_INVALID; goto done; } *out_data_len = outlen + finlen; } done: EVP_CIPHER_CTX_free(gcm_ctx); context->ulClen = (CK_ULONG)NULL; return rc; } CK_RV openssl_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) { AES_GCM_CONTEXT *context = NULL; CK_GCM_PARAMS *aes_gcm_param = NULL; EVP_CIPHER_CTX *gcm_ctx = NULL; CK_RV rc = CKR_OK; CK_ULONG tag_len, len, out_buf_len; int outlen; UNUSED(tokdata); UNUSED(sess); context = (AES_GCM_CONTEXT *)ctx->context; gcm_ctx = (EVP_CIPHER_CTX *)context->ulClen; aes_gcm_param = (CK_GCM_PARAMS *)ctx->mech.pParameter; if (gcm_ctx == NULL) return CKR_OPERATION_NOT_INITIALIZED; tag_len = (aes_gcm_param->ulTagBits + 7) / 8; if (encrypt) { /* encrypt */ if (*out_data_len < in_data_len) { TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); *out_data_len = in_data_len; rc = CKR_BUFFER_TOO_SMALL; goto done; } if (EVP_CipherUpdate(gcm_ctx, out_data, &outlen, in_data, in_data_len) != 1) { TRACE_ERROR("GCM update failed\n"); rc = CKR_GENERAL_ERROR; goto done; } *out_data_len = outlen; } else { /* decrypt */ out_buf_len = *out_data_len; *out_data_len = 0; /* Buffer the last tag_len input bytes */ if (in_data_len >= tag_len) { if (out_buf_len < context->len + (in_data_len - tag_len)) { TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); *out_data_len = context->len + (in_data_len - tag_len); rc = CKR_BUFFER_TOO_SMALL; goto done; } /* push buffered data */ if (context->len > 0) { if (EVP_CipherUpdate(gcm_ctx, out_data, &outlen, context->data, context->len) != 1) { TRACE_ERROR("GCM update failed\n"); rc = CKR_GENERAL_ERROR; goto done; } context->len = 0; *out_data_len += outlen; out_data += outlen; } /* push input data except tag_len last bytes */ if (EVP_CipherUpdate(gcm_ctx, out_data, &outlen, in_data, in_data_len - tag_len) != 1) { TRACE_ERROR("GCM update failed\n"); rc = CKR_GENERAL_ERROR; goto done; } *out_data_len += outlen; out_data += outlen; /* save tag in buffer */ memcpy(context->data, in_data + in_data_len - tag_len, tag_len); context->len = tag_len; } else if (context->len + in_data_len > tag_len) { /* push first bytes of buffer */ len = context->len + in_data_len - tag_len; if (out_buf_len < len) { TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); *out_data_len = len; rc = CKR_BUFFER_TOO_SMALL; goto done; } if (EVP_CipherUpdate(gcm_ctx, out_data, &outlen, context->data, len) != 1) { TRACE_ERROR("GCM update failed\n"); rc = CKR_GENERAL_ERROR; goto done; } *out_data_len += outlen; out_data += outlen; /* move remaining to beginning of buffer */ memmove(context->data, &context->data[len], context->len - len); context->len = context->len - len; /* append input data to buffer */ memcpy(&context->data[context->len], in_data, in_data_len); context->len += in_data_len; } else { /* append input data to buffer */ memcpy(&context->data[context->len], in_data, in_data_len); context->len += in_data_len; } } done: return rc; } CK_RV openssl_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) { AES_GCM_CONTEXT *context = NULL; CK_GCM_PARAMS *aes_gcm_param = NULL; EVP_CIPHER_CTX *gcm_ctx = NULL; CK_RV rc = CKR_OK; CK_ULONG tag_len; int outlen; UNUSED(tokdata); UNUSED(sess); UNUSED(encrypt); context = (AES_GCM_CONTEXT *)ctx->context; gcm_ctx = (EVP_CIPHER_CTX *)context->ulClen; aes_gcm_param = (CK_GCM_PARAMS *)ctx->mech.pParameter; if (gcm_ctx == NULL) return CKR_OPERATION_NOT_INITIALIZED; tag_len = (aes_gcm_param->ulTagBits + 7) / 8; if (encrypt) { /* encrypt */ if (context->len == 0) { if (EVP_CipherFinal_ex(gcm_ctx, context->data, &outlen) != 1) { TRACE_ERROR("GCM finalize encryption failed\n"); rc = CKR_GENERAL_ERROR; goto done; } if (outlen > 0) context->len = outlen; else context->len = (CK_ULONG)-1; /* no EVP_CipherFinal again */ } outlen = (context->len == (CK_ULONG)-1 ? 0 : context->len); if (outlen + tag_len > *out_data_len) { TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); /* Return here, do not cleanup the context */ *out_data_len = outlen + tag_len; return CKR_BUFFER_TOO_SMALL; } memcpy(out_data, context->data, outlen); /* Append the tag to the output */ if (EVP_CIPHER_CTX_ctrl(gcm_ctx, EVP_CTRL_AEAD_GET_TAG, tag_len, out_data + outlen) != 1) { TRACE_ERROR("GCM get tag failed\n"); rc = CKR_GENERAL_ERROR; goto done; } *out_data_len = outlen + tag_len; } else { if (context->len < tag_len) { TRACE_ERROR("GCM ciphertext does not contain tag data\n"); rc = CKR_ENCRYPTED_DATA_INVALID; goto done; } if (*out_data_len < AES_BLOCK_SIZE) { TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); /* Return here, do not cleanup the context */ *out_data_len = AES_BLOCK_SIZE; return CKR_BUFFER_TOO_SMALL; } /* Set the expected tag */ if (EVP_CIPHER_CTX_ctrl(gcm_ctx, EVP_CTRL_AEAD_SET_TAG, tag_len, context->data) != 1) { TRACE_ERROR("GCM set tag failed\n"); rc = CKR_GENERAL_ERROR; goto done; } /* Finalize the decryption */ if(EVP_CipherFinal_ex(gcm_ctx, out_data, &outlen) != 1) { TRACE_ERROR("GCM finalize decryption failed\n"); rc = CKR_ENCRYPTED_DATA_INVALID; goto done; } *out_data_len = outlen; } done: EVP_CIPHER_CTX_free(gcm_ctx); context->ulClen = (CK_ULONG)NULL; return rc; } CK_RV openssl_specific_aes_mac(STDLL_TokData_t *tokdata, CK_BYTE *message, CK_ULONG message_len, OBJECT *key, CK_BYTE *mac) { CK_BYTE *out_buf; CK_ULONG out_len; CK_RV rc; out_buf = malloc(message_len); if (out_buf == NULL) { TRACE_ERROR("Malloc failed.\n"); return CKR_HOST_MEMORY; } rc = openssl_specific_aes_cbc(tokdata, message, message_len, out_buf, &out_len, key, mac, 1); if (rc == CKR_OK && out_len >= AES_BLOCK_SIZE) memcpy(mac, out_buf + out_len - AES_BLOCK_SIZE, AES_BLOCK_SIZE); free(out_buf); return rc; } CK_RV openssl_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) { UNUSED(tokdata); return openssl_cmac_perform(CKM_AES_CMAC, message, message_len, key, mac, first, last, ctx); } static EVP_CIPHER_CTX *aes_xts_init_ecb_cipher_ctx(const CK_BYTE *key, CK_ULONG keylen, CK_BBOOL encrypt) { const EVP_CIPHER *cipher; EVP_CIPHER_CTX *ctx = NULL; if (key == NULL) return NULL; switch (keylen) { case AES_KEY_SIZE_128: cipher = EVP_aes_128_ecb(); break; case AES_KEY_SIZE_256: cipher = EVP_aes_256_ecb(); break; default: TRACE_ERROR("Key size wrong: %lu.\n", keylen); return NULL; } ctx = EVP_CIPHER_CTX_new(); if (ctx == NULL) { TRACE_ERROR("EVP_CIPHER_CTX_new failed\n"); return NULL; } if (EVP_CipherInit_ex(ctx, cipher, NULL, key, NULL, encrypt ? 1 : 0) != 1) { EVP_CIPHER_CTX_free(ctx); TRACE_ERROR("EVP_CipherInit_ex failed\n"); return NULL; } return ctx; } static void aes_xts_xor_block(const CK_BYTE *in1, const CK_BYTE *in2, CK_BYTE *out) { CK_ULONG i; for (i = 0; i < AES_BLOCK_SIZE; i++) out[i] = in1[i] ^ in2[i]; } static void aes_xts_mult(CK_BYTE *iv) { CK_ULONG c, i; for (c = 0, i = 0; i < AES_BLOCK_SIZE; ++i) { c += ((CK_ULONG)iv[i]) << 1; iv[i] = (CK_BYTE)c; c = c >> 8; } iv[0] ^= (CK_BYTE)(0x87 & (0 - c)); } struct aes_xts_cb_data { EVP_CIPHER_CTX *tweak_ctx; EVP_CIPHER_CTX *cipher_ctx; }; static CK_RV aes_xts_iv_from_tweak(CK_BYTE *tweak, CK_BYTE* iv, void * cb_data) { struct aes_xts_cb_data *data = cb_data; if (EVP_Cipher(data->tweak_ctx, iv, tweak, AES_BLOCK_SIZE) <= 0) { TRACE_ERROR("EVP_Cipher failed\n"); return CKR_FUNCTION_FAILED; } return CKR_OK; } static CK_RV aes_xts_cipher_blocks(CK_BYTE *in, CK_BYTE *out, CK_ULONG len, CK_BYTE *iv, void * cb_data) { struct aes_xts_cb_data *data = cb_data; CK_BYTE buf[AES_INIT_VECTOR_SIZE]; while (len >= AES_BLOCK_SIZE) { aes_xts_xor_block(in, iv, buf); if (EVP_Cipher(data->cipher_ctx, out, buf, AES_BLOCK_SIZE) <= 0) { TRACE_ERROR("EVP_Cipher failed\n"); return CKR_FUNCTION_FAILED; } aes_xts_xor_block(out, iv, out); in += AES_BLOCK_SIZE; out += AES_BLOCK_SIZE; len -= AES_BLOCK_SIZE; aes_xts_mult(iv); } return CKR_OK; } CK_RV openssl_specific_aes_xts(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 *tweak, CK_BOOL encrypt, CK_BBOOL initial, CK_BBOOL final, CK_BYTE* iv) { struct aes_xts_cb_data data = { 0 }; CK_ATTRIBUTE *key_attr; CK_RV rc; UNUSED(tokdata); if (initial && final) return openssl_cipher_perform(key_obj, CKM_AES_XTS, in_data, in_data_len, out_data, out_data_len, tweak, NULL, encrypt); rc = template_attribute_get_non_empty(key_obj->template, CKA_VALUE, &key_attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); return rc; } if (initial) { data.tweak_ctx = aes_xts_init_ecb_cipher_ctx( (CK_BYTE *)key_attr->pValue + key_attr->ulValueLen / 2, key_attr->ulValueLen / 2, TRUE); if (data.tweak_ctx == NULL) { TRACE_ERROR("aes_xts_init_ecb_cipher_ctx failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } } data.cipher_ctx = aes_xts_init_ecb_cipher_ctx((CK_BYTE *)key_attr->pValue, key_attr->ulValueLen / 2, encrypt); if (data.cipher_ctx == NULL) { TRACE_ERROR("aes_xts_init_ecb_cipher_ctx failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } rc = aes_xts_cipher(in_data, in_data_len, out_data, out_data_len, tweak, encrypt, initial, final, iv, aes_xts_iv_from_tweak, aes_xts_cipher_blocks, &data); out: if (data.tweak_ctx != NULL) EVP_CIPHER_CTX_free(data.tweak_ctx); if (data.cipher_ctx != NULL) EVP_CIPHER_CTX_free(data.cipher_ctx); return rc; } CK_RV openssl_specific_aes_key_wrap(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 *iv, CK_ULONG iv_len, CK_BBOOL encrypt, CK_BBOOL pad) { UNUSED(tokdata); if (iv != NULL && iv_len != (pad ? AES_KEY_WRAP_KWP_IV_SIZE : AES_KEY_WRAP_IV_SIZE)) { TRACE_ERROR("IV len is invalid\n"); return CKR_MECHANISM_PARAM_INVALID; } return openssl_cipher_perform(key_obj, pad ? CKM_AES_KEY_WRAP_KWP : CKM_AES_KEY_WRAP, in_data, in_data_len, out_data, out_data_len, iv, NULL, encrypt); } CK_RV openssl_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); return openssl_cipher_perform(key, CKM_DES_ECB, in_data, in_data_len, out_data, out_data_len, NULL, NULL, encrypt); } CK_RV openssl_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) { UNUSED(tokdata); return openssl_cipher_perform(key, CKM_DES_CBC, in_data, in_data_len, out_data, out_data_len, init_v, NULL, encrypt); } CK_RV openssl_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); return openssl_cipher_perform(key, CKM_DES3_ECB, in_data, in_data_len, out_data, out_data_len, NULL, NULL, encrypt); } CK_RV openssl_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) { UNUSED(tokdata); return openssl_cipher_perform(key, CKM_DES3_CBC, in_data, in_data_len, out_data, out_data_len, init_v, NULL, encrypt); } CK_RV openssl_specific_tdes_ofb(STDLL_TokData_t *tokdata, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, OBJECT *key, CK_BYTE *init_v, CK_BYTE encrypt) { CK_ULONG out_data_len; UNUSED(tokdata); return openssl_cipher_perform(key, CKM_DES_OFB64, in_data, in_data_len, out_data, &out_data_len, init_v, init_v, encrypt); } CK_RV openssl_specific_tdes_cfb(STDLL_TokData_t *tokdata, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, OBJECT *key, CK_BYTE *init_v, CK_ULONG cfb_len, CK_BYTE encrypt) { CK_ULONG out_data_len; CK_MECHANISM_TYPE mech; UNUSED(tokdata); switch (cfb_len * 8) { case 8: mech = CKM_DES_CFB8; break; case 64: mech = CKM_DES_CFB64; break; default: TRACE_ERROR("CFB length %lu not supported\n", cfb_len); return CKR_MECHANISM_INVALID; } return openssl_cipher_perform(key, mech, in_data, in_data_len, out_data, &out_data_len, init_v, init_v, encrypt); } CK_RV openssl_specific_tdes_mac(STDLL_TokData_t *tokdata, CK_BYTE *message, CK_ULONG message_len, OBJECT *key, CK_BYTE *mac) { CK_BYTE *out_buf; CK_ULONG out_len; CK_RV rc; out_buf = malloc(message_len); if (out_buf == NULL) { TRACE_ERROR("Malloc failed.\n"); return CKR_HOST_MEMORY; } rc = openssl_specific_tdes_cbc(tokdata, message, message_len, out_buf, &out_len, key, mac, 1); if (rc == CKR_OK && out_len >= DES_BLOCK_SIZE) memcpy(mac, out_buf + out_len - DES_BLOCK_SIZE, DES_BLOCK_SIZE); free(out_buf); return rc; } CK_RV openssl_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) { UNUSED(tokdata); return openssl_cmac_perform(CKM_DES3_CMAC, message, message_len, key, mac, first, last, ctx); } static void openssl_specific_hmac_free(STDLL_TokData_t *tokdata, SESSION *sess, CK_BYTE *context, CK_ULONG context_len) { UNUSED(tokdata); UNUSED(sess); UNUSED(context_len); EVP_MD_CTX_destroy((EVP_MD_CTX *)context); } CK_RV openssl_specific_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; } rc = template_attribute_get_non_empty(key->template, CKA_VALUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); 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_MD5_HMAC_GENERAL: case CKM_MD5_HMAC: rc = EVP_DigestSignInit(mdctx, NULL, EVP_md5(), NULL, pkey); break; 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; #ifdef NID_sha512_224WithRSAEncryption case CKM_SHA512_224_HMAC_GENERAL: case CKM_SHA512_224_HMAC: rc = EVP_DigestSignInit(mdctx, NULL, EVP_sha512_224(), NULL, pkey); break; #endif #ifdef NID_sha512_256WithRSAEncryption case CKM_SHA512_256_HMAC_GENERAL: case CKM_SHA512_256_HMAC: rc = EVP_DigestSignInit(mdctx, NULL, EVP_sha512_256(), NULL, pkey); break; #endif #ifdef NID_sha3_224 case CKM_SHA3_224_HMAC: case CKM_SHA3_224_HMAC_GENERAL: case CKM_IBM_SHA3_224_HMAC: rc = EVP_DigestSignInit(mdctx, NULL, EVP_sha3_224(), NULL, pkey); break; #endif #ifdef NID_sha3_256 case CKM_SHA3_256_HMAC: case CKM_SHA3_256_HMAC_GENERAL: case CKM_IBM_SHA3_256_HMAC: rc = EVP_DigestSignInit(mdctx, NULL, EVP_sha3_256(), NULL, pkey); break; #endif #ifdef NID_sha3_384 case CKM_SHA3_384_HMAC: case CKM_SHA3_384_HMAC_GENERAL: case CKM_IBM_SHA3_384_HMAC: rc = EVP_DigestSignInit(mdctx, NULL, EVP_sha3_384(), NULL, pkey); break; #endif #ifdef NID_sha3_512 case CKM_SHA3_512_HMAC: case CKM_SHA3_512_HMAC_GENERAL: case CKM_IBM_SHA3_512_HMAC: rc = EVP_DigestSignInit(mdctx, NULL, EVP_sha3_512(), NULL, pkey); break; #endif 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; ctx->context_free_func = openssl_specific_hmac_free; ctx->state_unsaveable = TRUE; } rc = CKR_OK; done: if (pkey != NULL) EVP_PKEY_free(pkey); object_put(tokdata, key, TRUE); key = NULL; return rc; } CK_RV openssl_specific_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; CK_MECHANISM_TYPE digest_mech; CK_ULONG mac_len2; 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; } rc = get_hmac_digest(ctx->mech.mechanism, &digest_mech, &general); if (rc != CKR_OK) { TRACE_ERROR("%s get_hmac_digest failed\n", __func__); return rc; } rc = get_sha_size(digest_mech, &mac_len2); if (rc != CKR_OK) { TRACE_ERROR("%s get_sha_size failed\n", __func__); return rc; } mac_len = mac_len2; 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 openssl_specific_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 { return CKR_OK; } EVP_MD_CTX_destroy(mdctx); ctx->context = NULL; return rv; } CK_RV openssl_specific_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; CK_MECHANISM_TYPE digest_mech; CK_ULONG mac_len2; 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; } rc = get_hmac_digest(ctx->mech.mechanism, &digest_mech, &general); if (rc != CKR_OK) { TRACE_ERROR("%s get_hmac_digest failed\n", __func__); return rc; } rc = get_sha_size(digest_mech, &mac_len2); if (rc != CKR_OK) { TRACE_ERROR("%s get_sha_size failed\n", __func__); return rc; } mac_len = mac_len2; 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 calc_rsa_crt_from_me(CK_ATTRIBUTE *modulus, CK_ATTRIBUTE *pub_exp, CK_ATTRIBUTE *priv_exp, CK_ATTRIBUTE **prime1, CK_ATTRIBUTE **prime2, CK_ATTRIBUTE **exponent1, CK_ATTRIBUTE **exponent2, CK_ATTRIBUTE **coef) { BN_CTX *bn_ctx; BIGNUM *n, *e, *d, *k, *r, *t, *two, *g, *y, *n_minus_1, *j, *x; BIGNUM *p, *q, *dp, *dq, *invq; int i, prime_len; CK_BYTE *buff = NULL; CK_RV rc; bn_ctx = BN_CTX_secure_new(); if (bn_ctx == NULL) { TRACE_ERROR("BN_CTX_secure_new failed\n"); return CKR_FUNCTION_FAILED; } /* Get modulus as BIGNUM */ n = BN_CTX_get(bn_ctx); if (n == NULL || BN_bin2bn(modulus->pValue, modulus->ulValueLen, n) == NULL) { TRACE_ERROR("BN_CTX_get/BN_bin2bn failed for modulus\n"); rc = CKR_FUNCTION_FAILED; goto done; } /* Get public exponent as BIGNUM */ e = BN_CTX_get(bn_ctx); if (e == NULL || BN_bin2bn(pub_exp->pValue, pub_exp->ulValueLen, e) == NULL) { TRACE_ERROR("BN_CTX_get/BN_bin2bn failed for public exponent\n"); rc = CKR_FUNCTION_FAILED; goto done; } /* Get private exponent as BIGNUM */ d = BN_CTX_get(bn_ctx); if (d == NULL || BN_bin2bn(priv_exp->pValue, priv_exp->ulValueLen, d) == NULL) { TRACE_ERROR("BN_CTX_get/BN_bin2bn failed for private exponent\n"); rc = CKR_FUNCTION_FAILED; goto done; } n_minus_1 = BN_CTX_get(bn_ctx); two = BN_CTX_get(bn_ctx); k = BN_CTX_get(bn_ctx); r = BN_CTX_get(bn_ctx); t = BN_CTX_get(bn_ctx); g = BN_CTX_get(bn_ctx); y = BN_CTX_get(bn_ctx); j = BN_CTX_get(bn_ctx); x = BN_CTX_get(bn_ctx); p = BN_CTX_get(bn_ctx); q = BN_CTX_get(bn_ctx); dp = BN_CTX_get(bn_ctx); dq = BN_CTX_get(bn_ctx); invq = BN_CTX_get(bn_ctx); if (n_minus_1 == NULL || two == NULL || k == NULL || r == NULL || t == NULL || g == NULL || y == NULL || j == NULL || x == NULL || p == NULL || q == NULL || dp == NULL || dq == NULL || invq == NULL) { TRACE_ERROR("BN_CTX_get failed\n"); rc = CKR_FUNCTION_FAILED; goto done; } if (BN_set_word(two, 2) != 1 || BN_sub(n_minus_1, n, BN_value_one()) != 1) { TRACE_ERROR("BN_set_word/BN_sub failed\n"); rc = CKR_FUNCTION_FAILED; goto done; } /* * Prime-Factor Recovery from n, e and d described in NIST Special * Publication 800-56B R2 Recommendation for Pair-Wise Key Establishment * Schemes Using Integer Factorization Cryptography in Appendix C. */ /* Step 1: Let k = d*e – 1. If k is odd, then go to Step 4. */ if (BN_mul(k, d, e, bn_ctx) != 1 || BN_sub_word(k, 1) != 1) { TRACE_ERROR("BN_mul/BN_sub_word failed for k\n"); rc = CKR_FUNCTION_FAILED; goto done; } if (BN_is_odd(k)) goto step4_fail; /* * Step 2: Write k as k = (2^t)*r, where r is the largest odd integer * dividing k, and t >= 1. */ BN_zero(t); if (BN_copy(r, k) == NULL) { TRACE_ERROR("BN_set_word/BN_copy failed\n"); rc = CKR_FUNCTION_FAILED; goto done; } do { if (BN_div(r, NULL, r, two, bn_ctx) != 1 || BN_add_word(t, 1) != 1) { TRACE_ERROR("BN_div/BN_add_word failed\n"); rc = CKR_FUNCTION_FAILED; goto done; } } while(!BN_is_odd(r)); /* Step 3: For i = 1 to 100 do: */ for (i = 1; i <= 100; i++) { /* Step 3a: Generate a random integer g in the range [0, n-1] */ #if OPENSSL_VERSION_PREREQ(3, 0) if (BN_rand_range_ex(g, n, 0, bn_ctx) != 1) { #else if (BN_rand_range(g, n) != 1) { #endif TRACE_ERROR("BN_rand_range[_ex] failed\n"); rc = CKR_FUNCTION_FAILED; goto done; } /* Step 3b: Let y = g^r mod n */ if (BN_mod_exp(y, g, r, n, bn_ctx) != 1) { TRACE_ERROR("BN_mod_exp failed\n"); rc = CKR_FUNCTION_FAILED; goto done; } /* Step 3c: If y = 1 or y = n – 1, then step 3g */ if (BN_cmp(y, BN_value_one()) == 0 || BN_cmp(y, n_minus_1) == 0) goto step_3g; /* Step 3d: For j = 1 to t – 1 do */ for (BN_one(j); BN_cmp(j, t) < 0; BN_add_word(t, 1)) { /* Step 3d1: Let x = y^2 mod n */ if (BN_mod_exp(x, y, two, n, bn_ctx) != 1) { TRACE_ERROR("BN_mod_exp failed\n"); rc = CKR_FUNCTION_FAILED; goto done; } /* Step 3d2: If x = 1, go to Step 5 */ if (BN_cmp(x, BN_value_one()) == 0) goto step5_success; /* Step 3d3: if x = n – 1, goto step 3g */ if (BN_cmp(x, n_minus_1) == 0) goto step_3g; /* Step 3d4: Let y = x */ if (BN_copy(y, x) == NULL) { TRACE_ERROR("BN_copy failed\n"); rc = CKR_FUNCTION_FAILED; goto done; } } /* Step 3e: Let x = y^2 mod n. */ if (BN_mod_exp(x, y, two, n, bn_ctx) != 1) { TRACE_ERROR("BN_mod_exp failed\n"); rc = CKR_FUNCTION_FAILED; goto done; } /* Step 3f: If x = 1, go to Step 5 */ if (BN_cmp(x, BN_value_one()) == 0) goto step5_success; step_3g: /* Step 3g: continue */ continue; } step4_fail: /* Step 4: Output "prime factors not found" and exit */ TRACE_ERROR("Prime factors not found\n"); rc = CKR_FUNCTION_FAILED; goto done; step5_success: /* Step 5: Let p = GCD(y – 1, n) and let q = n/p */ if (BN_sub_word(y, 1) != 1 || BN_gcd(p, y, n, bn_ctx) != 1 || BN_div(q, NULL, n, p, bn_ctx) != 1) { TRACE_ERROR("BN_sub_word/BN_gcd/BN_div failed\n"); rc = CKR_FUNCTION_FAILED; goto done; } /* Swap if p < q */ if (BN_cmp(p, q) < 0) { x = q; q = p; p = x; } /* Calculate dp = d mod p−1, dq = d mod q-1, and qinv = q^−1 mod p */ if (BN_copy(dp, p) == NULL || BN_sub_word(dp, 1) != 1 || BN_div(NULL, dp, d, dp, bn_ctx) != 1 || BN_copy(dq, q) == NULL || BN_sub_word(dq, 1) != 1 || BN_div(NULL, dq, d, dq, bn_ctx) != 1 || BN_mod_inverse(invq, q, p, bn_ctx) == NULL) { TRACE_ERROR("BN_copy/BN_sub_word/BN_div/BN_mod_inverse failed\n"); rc = CKR_FUNCTION_FAILED; goto done; } /* Add the CRT attributes to the key */ prime_len = BN_num_bytes(p); buff = calloc(prime_len, 1); if (buff == NULL) { TRACE_DEVEL("calloc failed for buffer\n"); rc = CKR_HOST_MEMORY; goto done; } if (BN_bn2bin(p, buff) != prime_len) { TRACE_DEVEL("BN_bn2bin failed for p\n"); rc = CKR_FUNCTION_FAILED; goto done; } rc = build_attribute(CKA_PRIME_1, buff, prime_len, prime1); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed for CKA_PRIME_1\n"); goto done; } memset(buff, 0, prime_len); if (BN_bn2bin(q, buff) != prime_len) { TRACE_DEVEL("BN_bn2bin failed for q\n"); rc = CKR_FUNCTION_FAILED; goto done; } rc = build_attribute(CKA_PRIME_2, buff, prime_len, prime2); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed for CKA_PRIME_2\n"); goto done; } memset(buff, 0, prime_len); if (BN_bn2bin(dp, buff) != prime_len) { TRACE_DEVEL("BN_bn2bin failed for dp\n"); rc = CKR_FUNCTION_FAILED; goto done; } rc = build_attribute(CKA_EXPONENT_1, buff, prime_len, exponent1); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed for CKA_EXPONENT_1\n"); goto done; } memset(buff, 0, prime_len); if (BN_bn2bin(dq, buff) != prime_len) { TRACE_DEVEL("BN_bn2bin failed for dq\n"); rc = CKR_FUNCTION_FAILED; goto done; } rc = build_attribute(CKA_EXPONENT_2, buff, prime_len, exponent2); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed for CKA_EXPONENT_2\n"); goto done; } memset(buff, 0, prime_len); if (BN_bn2bin(invq, buff) != prime_len) { TRACE_DEVEL("BN_bn2bin failed for qinv\n"); rc = CKR_FUNCTION_FAILED; goto done; } rc = build_attribute(CKA_COEFFICIENT, buff, prime_len, coef); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed for CKA_COEFFICIENT\n"); goto done; } done: BN_CTX_free(bn_ctx); if (buff != NULL) { OPENSSL_cleanse(buff, prime_len); free(buff); } if (rc != CKR_OK) { if (*prime1 != NULL) { OPENSSL_cleanse((*prime1)->pValue, (*prime1)->ulValueLen); free(*prime1); *prime1 = NULL; } if (*prime2 != NULL) { OPENSSL_cleanse((*prime2)->pValue, (*prime2)->ulValueLen); free(*prime2); *prime2 = NULL; } if (*exponent1 != NULL) { OPENSSL_cleanse((*exponent1)->pValue, (*exponent1)->ulValueLen); free(*exponent1); *exponent1 = NULL; } if (*exponent2 != NULL) { OPENSSL_cleanse((*exponent2)->pValue, (*exponent2)->ulValueLen); free(*exponent2); *exponent2 = NULL; } if (*coef != NULL) { OPENSSL_cleanse((*coef)->pValue, (*coef)->ulValueLen); free(*coef); *coef = NULL; } } return rc; } static CK_RV calc_rsa_priv_exp(STDLL_TokData_t *tokdata, OBJECT *key_obj, CK_BYTE *priv_exp, CK_ULONG priv_exp_len) { CK_ATTRIBUTE *modulus = NULL, *pub_exp = NULL; CK_ATTRIBUTE *prime1 = NULL, *prime2 = NULL; BN_CTX *bn_ctx; BIGNUM *n, *e, *p, *q, *d; CK_RV rc; UNUSED(tokdata); bn_ctx = BN_CTX_secure_new(); if (bn_ctx == NULL) { TRACE_ERROR("BN_CTX_secure_new failed\n"); return CKR_FUNCTION_FAILED; } /* Get modulus a BIGNUM */ rc = template_attribute_get_non_empty(key_obj->template, CKA_MODULUS, &modulus); if (rc != CKR_OK) { TRACE_ERROR("Failed to get CKA_MODULUS\n"); goto done; } n = BN_CTX_get(bn_ctx); if (n == NULL || BN_bin2bn(modulus->pValue, modulus->ulValueLen, n) == NULL) { TRACE_ERROR("BN_CTX_get/BN_bin2bn failed for modulus\n"); rc = CKR_FUNCTION_FAILED; goto done; } BN_set_flags(n, BN_FLG_CONSTTIME); /* Get public exponent a BIGNUM */ rc = template_attribute_get_non_empty(key_obj->template, CKA_PUBLIC_EXPONENT, &pub_exp); if (rc != CKR_OK) { TRACE_ERROR("Failed to get CKA_PUBLIC_EXPONENT\n"); goto done; } e = BN_CTX_get(bn_ctx); if (e == NULL || BN_bin2bn(pub_exp->pValue, pub_exp->ulValueLen, e) == NULL) { TRACE_ERROR("BN_CTX_get/BN_bin2bn failed for public exponent\n"); rc = CKR_FUNCTION_FAILED; goto done; } BN_set_flags(e, BN_FLG_CONSTTIME); /* Get prime1 a BIGNUM */ rc = template_attribute_get_non_empty(key_obj->template, CKA_PRIME_1, &prime1); if (rc != CKR_OK) { TRACE_ERROR("Failed to get CKA_PRIME_1\n"); goto done; } p = BN_CTX_get(bn_ctx); if (p == NULL || BN_bin2bn(prime1->pValue, prime1->ulValueLen, p) == NULL) { TRACE_ERROR("BN_CTX_get/BN_bin2bn failed for prime1\n"); rc = CKR_FUNCTION_FAILED; goto done; } BN_set_flags(p, BN_FLG_CONSTTIME); /* Get prime2 a BIGNUM */ rc = template_attribute_get_non_empty(key_obj->template, CKA_PRIME_2, &prime2); if (rc != CKR_OK) { TRACE_ERROR("Failed to get CKA_PRIME_2\n"); goto done; } q = BN_CTX_get(bn_ctx); if (q == NULL || BN_bin2bn(prime2->pValue, prime2->ulValueLen, q) == NULL) { TRACE_ERROR("BN_CTX_get/BN_bin2bn failed for prime2\n"); rc = CKR_FUNCTION_FAILED; goto done; } BN_set_flags(q, BN_FLG_CONSTTIME); d = BN_CTX_get(bn_ctx); if (d == NULL) { TRACE_ERROR("BN_CTX_get failed to get d\n"); rc = CKR_FUNCTION_FAILED; goto done; } BN_set_flags(d, BN_FLG_CONSTTIME); /* * phi(n) = (p - 1 )(q - 1) = n - p - q + 1 * d = e ^{-1} mod phi(n). */ if (BN_copy(d, n) == NULL || BN_sub(d, d, p) == 0 || BN_sub(d, d, q) == 0 || BN_add_word(d, 1) == 0 || BN_mod_inverse(d, e, d, bn_ctx) == NULL) { TRACE_ERROR("Failed to calculate private key part d\n"); rc = CKR_FUNCTION_FAILED; goto done; } if (BN_bn2binpad(d, priv_exp, priv_exp_len) <= 0) { TRACE_ERROR("BN_bn2binpad failed\n"); rc = CKR_FUNCTION_FAILED; goto done; } done: BN_CTX_free(bn_ctx); return rc; } CK_RV openssl_specific_rsa_derive_kdk(STDLL_TokData_t *tokdata, OBJECT *key_obj, const CK_BYTE *in, CK_ULONG inlen, CK_BYTE *kdk, CK_ULONG kdklen) { CK_ATTRIBUTE *priv_exp_attr = NULL, *modulus = NULL; CK_BYTE *priv_exp = NULL, *buf = NULL; EVP_PKEY *pkey = NULL; EVP_MD_CTX *mdctx = NULL; const EVP_MD *md = NULL; size_t md_len; unsigned char d_hash[SHA256_HASH_SIZE] = { 0 }; CK_RV rc; /* * The implementation of this function is copied from OpenSSL's function * derive_kdk() in crypto/rsa/rsa_ossl.c and is slightly modified to fit to * the OpenCryptoki environment. * Changes include: * - Different variable and define names. * - Usage of TRACE_ERROR to report errors and issue debug messages. * - Different return codes. * - Different code to get the private key component 'd'. * - Use of the EVP APIs instead of the internal APIs for Digest and HMAC * operations. */ if (kdklen != SHA256_HASH_SIZE) { TRACE_ERROR("KDK length is wrong\n"); return CKR_ARGUMENTS_BAD; } rc = template_attribute_get_non_empty(key_obj->template, CKA_MODULUS, &modulus); if (rc != CKR_OK) { TRACE_ERROR("Failed to get CKA_MODULUS\n"); return rc; } buf = calloc(1, modulus->ulValueLen); if (buf == NULL) { TRACE_ERROR("Failed to allocate a buffer for private exponent\n"); return CKR_HOST_MEMORY; } rc = template_attribute_get_non_empty(key_obj->template, CKA_PRIVATE_EXPONENT, &priv_exp_attr); if (rc != CKR_OK && rc != CKR_TEMPLATE_INCOMPLETE && rc != CKR_ATTRIBUTE_VALUE_INVALID) { TRACE_ERROR("Failed to get CKA_PRIVATE_EXPONENT\n"); goto out; } if (priv_exp_attr == NULL) { rc = calc_rsa_priv_exp(tokdata, key_obj, buf, modulus->ulValueLen); if (rc != CKR_OK) { TRACE_ERROR("calc_rsa_priv_exp failed\n"); goto out; } priv_exp = buf; } else { if (priv_exp_attr->ulValueLen < modulus->ulValueLen) { memcpy(buf + modulus->ulValueLen - priv_exp_attr->ulValueLen, priv_exp_attr->pValue, priv_exp_attr->ulValueLen); priv_exp = buf; } else { priv_exp = (CK_BYTE *)priv_exp_attr->pValue + priv_exp_attr->ulValueLen - modulus->ulValueLen; } } /* * we use hardcoded hash so that migrating between versions that use * different hash doesn't provide a Bleichenbacher oracle: * if the attacker can see that different versions return different * messages for the same ciphertext, they'll know that the message is * synthetically generated, which means that the padding check failed */ md = EVP_sha256(); if (md == NULL) { TRACE_ERROR("EVP_sha256 failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } if (EVP_Digest(priv_exp, modulus->ulValueLen, d_hash, NULL, md, NULL) <= 0) { TRACE_ERROR("EVP_Digest failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, d_hash, sizeof(d_hash)); if (pkey == NULL) { TRACE_ERROR("EVP_PKEY_new_mac_key() failed.\n"); rc = CKR_FUNCTION_FAILED; goto out; } mdctx = EVP_MD_CTX_create(); if (mdctx == NULL) { TRACE_ERROR("EVP_MD_CTX_create() failed.\n"); rc = CKR_FUNCTION_FAILED; goto out; } if (EVP_DigestSignInit(mdctx, NULL, md, NULL, pkey) != 1) { TRACE_ERROR("EVP_DigestSignInit failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } if (inlen < modulus->ulValueLen) { memset(buf, 0, modulus->ulValueLen - inlen); if (EVP_DigestSignUpdate(mdctx, buf, modulus->ulValueLen - inlen)!= 1) { TRACE_ERROR("EVP_DigestSignUpdate failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } } if (EVP_DigestSignUpdate(mdctx, in, inlen) != 1) { TRACE_ERROR("EVP_DigestSignUpdate failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } md_len = kdklen; if (EVP_DigestSignFinal(mdctx, kdk, &md_len) != 1 || md_len != kdklen) { TRACE_ERROR("EVP_DigestSignFinal failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } rc = CKR_OK; out: if (buf != NULL) free(buf); if (pkey != NULL) EVP_PKEY_free(pkey); if (mdctx != NULL) EVP_MD_CTX_free(mdctx); return rc; } CK_RV openssl_specific_rsa_prf(CK_BYTE *out, CK_ULONG outlen, const char *label, CK_ULONG labellen, const CK_BYTE *kdk, CK_ULONG kdklen, uint16_t bitlen) { CK_RV rc; CK_ULONG pos; uint16_t iter = 0; unsigned char be_iter[sizeof(iter)]; unsigned char be_bitlen[sizeof(bitlen)]; EVP_PKEY *pkey = NULL; EVP_MD_CTX *mdctx = NULL; unsigned char hmac_out[SHA256_HASH_SIZE]; size_t md_len; /* * The implementation of this function is copied from OpenSSL's function * ossl_rsa_prf() in crypto/rsa/rsapk1.c and is slightly modified to fit to * the providers environment. * Changes include: * - Different variable and define names. * - Usage of TRACE_ERROR report errors and issue debug messages. * - Different return codes. * - Use of the EVP API instead of the internal APIs for HMAC operations. */ if (kdklen != SHA256_HASH_SIZE) { TRACE_ERROR("invalid kdklen\n"); return CKR_ARGUMENTS_BAD; } if (outlen * 8 != bitlen) { TRACE_ERROR("invalid outlen\n"); return CKR_ARGUMENTS_BAD; } be_bitlen[0] = (bitlen >> 8) & 0xff; be_bitlen[1] = bitlen & 0xff; pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, kdk, kdklen); if (pkey == NULL) { TRACE_ERROR("EVP_PKEY_new_mac_key() failed.\n"); rc = CKR_FUNCTION_FAILED; goto out; } mdctx = EVP_MD_CTX_create(); if (mdctx == NULL) { TRACE_ERROR("EVP_MD_CTX_create() failed.\n"); rc = CKR_FUNCTION_FAILED; goto out; } /* * we use hardcoded hash so that migrating between versions that use * different hash doesn't provide a Bleichenbacher oracle: * if the attacker can see that different versions return different * messages for the same ciphertext, they'll know that the message is * synthetically generated, which means that the padding check failed */ for (pos = 0; pos < outlen; pos += SHA256_HASH_SIZE, iter++) { if (EVP_DigestSignInit(mdctx, NULL, EVP_sha256(), NULL, pkey) != 1) { TRACE_ERROR("EVP_DigestSignInit failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } be_iter[0] = (iter >> 8) & 0xff; be_iter[1] = iter & 0xff; if (EVP_DigestSignUpdate(mdctx, be_iter, sizeof(be_iter)) != 1) { TRACE_ERROR("EVP_DigestSignUpdate failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } if (EVP_DigestSignUpdate(mdctx, (unsigned char *)label, labellen) != 1) { TRACE_ERROR("EVP_DigestSignUpdate failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } if (EVP_DigestSignUpdate(mdctx, be_bitlen, sizeof(be_bitlen)) != 1) { TRACE_ERROR("EVP_DigestSignUpdate failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } /* * HMAC_Final requires the output buffer to fit the whole MAC * value, so we need to use the intermediate buffer for the last * unaligned block */ md_len = SHA256_HASH_SIZE; if (pos + SHA256_HASH_SIZE > outlen) { md_len = sizeof(hmac_out); if (EVP_DigestSignFinal(mdctx, hmac_out, &md_len) != 1) { TRACE_ERROR("EVP_DigestSignFinal failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } memcpy(out + pos, hmac_out, outlen - pos); } else { md_len = outlen - pos; if (EVP_DigestSignFinal(mdctx, out + pos, &md_len) != 1) { TRACE_ERROR("EVP_DigestSignFinal failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } } } rc = CKR_OK; out: if (pkey != NULL) EVP_PKEY_free(pkey); if (mdctx != NULL) EVP_MD_CTX_free(mdctx); return rc; } #if OPENSSL_VERSION_PREREQ(3, 0) const char *openssl_get_pqc_oid_name(const struct pqc_oid *oid) { const CK_BYTE *poid = oid->oid; ASN1_OBJECT *obj = NULL; const char *alg_name; EVP_PKEY_CTX *ctx = NULL; int nid; if (d2i_ASN1_OBJECT(&obj, &poid, oid->oid_len) == NULL) return NULL; nid = OBJ_obj2nid(obj); ASN1_OBJECT_free(obj); if (nid == NID_undef) return NULL; alg_name = OBJ_nid2ln(nid); if (alg_name == NULL) return NULL; /* Try to fetch that algorithm to check if it is really supported */ ctx = EVP_PKEY_CTX_new_from_name(NULL, alg_name, NULL); if (ctx == NULL) alg_name = NULL; EVP_PKEY_CTX_free(ctx); return alg_name; } CK_RV openssl_get_key_from_pkey(EVP_PKEY *pkey, const char *param, CK_BYTE **key, size_t *key_len, CK_BBOOL check) { const OSSL_PARAM *params; CK_BBOOL found = FALSE; int i; if (check) { params = EVP_PKEY_gettable_params(pkey); for (i = 0; params != NULL && params[i].key != NULL; i++) { if (strcmp(params[i].key, param) == 0) { found = TRUE; break; } } if (!found) { *key = NULL; *key_len = 0; return CKR_OK; } } if (EVP_PKEY_get_octet_string_param(pkey, param, NULL, 0, key_len) != 1 || *key_len == OSSL_PARAM_UNMODIFIED) { TRACE_ERROR("EVP_PKEY_get_octet_string_param failed for '%s'\n", param); return CKR_FUNCTION_FAILED; } *key = calloc(1, *key_len); if (*key == NULL) { TRACE_ERROR("Failed to allocate buffer for '%s'\n", param); return CKR_HOST_MEMORY; } if (EVP_PKEY_get_octet_string_param(pkey, param, *key, *key_len, key_len) != 1) { TRACE_ERROR("EVP_PKEY_get_octet_string_param failed for '%s'\n", param); return CKR_FUNCTION_FAILED; } return CKR_OK; } CK_RV openssl_specific_pqc_generate_keypair(STDLL_TokData_t *tokdata, const struct pqc_oid *oid, CK_MECHANISM *mech, TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl) { EVP_PKEY_CTX *ctx = NULL; EVP_PKEY *pkey = NULL; const char *alg_name; CK_BYTE *spki = NULL, *pkcs8 = NULL; CK_ULONG spki_len = 0, pkcs8_len = 0; size_t priv_len = 0, pub_len = 0; CK_BYTE *priv_key = NULL, *pub_key = NULL; size_t seed_len = 0; CK_BYTE *priv_seed = NULL; CK_KEY_TYPE keytype; CK_OBJECT_CLASS class; CK_RV rc = CKR_OK; CK_ATTRIBUTE_TYPE seed_attr = (CK_ATTRIBUTE_TYPE)-1; const char *seed_param = NULL; UNUSED(tokdata); rc = pkcs_get_keytype(NULL, 0, mech, &keytype, &class); if (rc != CKR_OK) { TRACE_ERROR("pkcs_get_keytype failed\n"); goto out; } alg_name = openssl_get_pqc_oid_name(oid); if (alg_name == NULL) { TRACE_ERROR("PQC key form '%lu' not supported by oqsprovider\n", oid->keyform); rc = CKR_KEY_SIZE_RANGE; goto out; } /* Generate key via oqsprovider or OpenSSL 3.5 */ ctx = EVP_PKEY_CTX_new_from_name(NULL, alg_name, mech->mechanism != CKM_IBM_DILITHIUM && mech->mechanism != CKM_IBM_KYBER ? "?provider=default" : NULL); if (ctx == NULL) { TRACE_ERROR("EVP_PKEY_CTX_new_from_name failed for '%s'\n", alg_name); rc = CKR_FUNCTION_FAILED; goto out; } if (EVP_PKEY_keygen_init(ctx) != 1) { TRACE_ERROR("EVP_PKEY_keygen_init failed for '%s'\n", alg_name); rc = CKR_FUNCTION_FAILED; goto out; } if (EVP_PKEY_generate(ctx, &pkey) != 1) { TRACE_ERROR("EVP_PKEY_generate failed for '%s'\n", alg_name); rc = CKR_FUNCTION_FAILED; goto out; } /* Get private and public key */ rc = openssl_get_key_from_pkey(pkey, OSSL_PKEY_PARAM_PRIV_KEY, &priv_key, &priv_len, FALSE); if (rc != CKR_OK) { TRACE_ERROR("get_key_from_pkey failed for priv key\n"); goto out; } rc = openssl_get_key_from_pkey(pkey, OSSL_PKEY_PARAM_PUB_KEY, &pub_key, &pub_len, FALSE); if (rc != CKR_OK) { TRACE_ERROR("get_key_from_pkey failed for pub key\n"); goto out; } /* Extract key components */ rc = pqc_unpack_priv_key(priv_key, priv_len, oid, mech->mechanism, priv_tmpl); if (rc != CKR_OK) { TRACE_ERROR("pqc_unpack_priv_key failed for priv key\n"); goto out; } rc = pqc_unpack_pub_key(pub_key, pub_len, oid, mech->mechanism, publ_tmpl); if (rc != CKR_OK) { TRACE_ERROR("pqc_unpack_pub_key failed for pub key\n"); goto out; } switch (keytype) { case CKK_IBM_ML_DSA: seed_attr = CKA_IBM_ML_DSA_PRIVATE_SEED; seed_param = OSSL_PKEY_PARAM_ML_DSA_SEED; break; case CKK_IBM_ML_KEM: seed_attr = CKA_IBM_ML_KEM_PRIVATE_SEED; seed_param = OSSL_PKEY_PARAM_ML_KEM_SEED; break; case CKK_ML_DSA: seed_attr = CKA_SEED; seed_param = OSSL_PKEY_PARAM_ML_DSA_SEED; break; case CKK_ML_KEM: seed_attr = CKA_SEED; seed_param = OSSL_PKEY_PARAM_ML_KEM_SEED; break; default: seed_attr = (CK_ATTRIBUTE_TYPE)-1; seed_param = NULL; break; } /* Get and add private seed, if available */ if (seed_attr != (CK_ATTRIBUTE_TYPE)-1 && seed_param != NULL) { rc = openssl_get_key_from_pkey(pkey, seed_param, &priv_seed, &seed_len, TRUE); if (rc != CKR_OK) { TRACE_ERROR("get_key_from_pkey failed for priv key seed\n"); goto out; } if (priv_seed != NULL) { rc = template_build_update_attribute(priv_tmpl, seed_attr, priv_seed, seed_len); if (rc != CKR_OK) { TRACE_ERROR("template_build_update_attribute for " "attr 0x%lx failed rc=0x%lx\n", seed_attr, rc); goto out; } } } switch (mech->mechanism) { case CKM_IBM_DILITHIUM: case CKM_IBM_KYBER: case CKM_IBM_ML_DSA_KEY_PAIR_GEN: case CKM_IBM_ML_KEM_KEY_PAIR_GEN: /* Also add public key components to private template */ rc = pqc_unpack_pub_key(pub_key, pub_len, oid, mech->mechanism, priv_tmpl); if (rc != CKR_OK) { TRACE_ERROR("pqc_unpack_pub_key failed for pub key\n"); goto out; } default: /* ML-DSA and ML-KEM have no public key components in priv key */ break; } /* Add keyform and mode attributes to public and private template */ rc = pqc_add_keyform_mode(publ_tmpl, oid, mech->mechanism); if (rc != CKR_OK) { TRACE_ERROR("pqc_add_keyform_mode failed\n"); goto out; } rc = pqc_add_keyform_mode(priv_tmpl, oid, mech->mechanism); if (rc != CKR_OK) { TRACE_ERROR("pqc_add_keyform_mode failed\n"); goto out; } switch (mech->mechanism) { case CKM_IBM_DILITHIUM: case CKM_IBM_KYBER: case CKM_IBM_ML_DSA_KEY_PAIR_GEN: case CKM_IBM_ML_KEM_KEY_PAIR_GEN: /* Add SPKI as CKA_VALUE to public template */ rc = pqc_publ_get_spki(publ_tmpl, keytype, FALSE, &spki, &spki_len, FALSE); if (rc != CKR_OK) { TRACE_ERROR("pqc_publ_get_spki failed\n"); goto out; } rc = template_build_update_attribute(publ_tmpl, CKA_VALUE, spki, spki_len); if (rc != CKR_OK) { TRACE_ERROR("template_build_update_attribute for CKA_VALUE failed " "rc=0x%lx\n", rc); goto out; } /* Add PKCS#8 encoding of private key to private template */ rc = pqc_priv_wrap_get_data(priv_tmpl, keytype, FALSE, &pkcs8, &pkcs8_len); if (rc != CKR_OK) { TRACE_ERROR("pqc_priv_wrap_get_data failed\n"); goto out; } rc = template_build_update_attribute(priv_tmpl, CKA_VALUE, pkcs8, pkcs8_len); if (rc != CKR_OK) { TRACE_ERROR("template_build_update_attribute for CKA_VALUE failed " "rc=0x%lx\n", rc); goto out; } break; default: /* ML-DSA and ML-KEM have raw key components in CKA_VALUE */ break; } out: if (ctx != NULL) EVP_PKEY_CTX_free(ctx); if (pkey != NULL) EVP_PKEY_free(pkey); if (priv_key != NULL) { OPENSSL_cleanse(priv_key, priv_len); free(priv_key); } if (priv_seed != NULL) { OPENSSL_cleanse(priv_seed, seed_len); free(priv_seed); } if (pub_key != NULL) free(pub_key); if (spki != NULL) free(spki); if (pkcs8 != NULL) { OPENSSL_cleanse(pkcs8, pkcs8_len); free(pkcs8); } return rc; } static CK_BBOOL check_settable_fromdata_params(EVP_PKEY_CTX *ctx, const char *name) { const OSSL_PARAM *settable, *p; settable = EVP_PKEY_fromdata_settable(ctx, EVP_PKEY_KEYPAIR); for (p = settable; p != NULL && p->key != NULL; p++) { if (strcmp(p->key, name) == 0) return TRUE; } return CK_FALSE; } CK_RV openssl_make_pqc_key_from_template(TEMPLATE *tmpl, const struct pqc_oid *oid, CK_MECHANISM_TYPE mech, CK_BBOOL private_key, const char *alg_name, EVP_PKEY **pkey) { CK_ULONG priv_len = 0, pub_len = 0; CK_BYTE *priv_key = NULL, *pub_key = NULL; EVP_PKEY_CTX *pctx = NULL; OSSL_PARAM_BLD *bld = NULL; OSSL_PARAM *params = NULL; CK_ATTRIBUTE_TYPE seed_attr = (CK_ATTRIBUTE_TYPE)-1; const char *seed_param = NULL; CK_ATTRIBUTE *attr = NULL; CK_RV rc; switch (mech) { case CKM_IBM_ML_DSA: seed_attr = CKA_IBM_ML_DSA_PRIVATE_SEED; seed_param = OSSL_PKEY_PARAM_ML_DSA_SEED; break; case CKM_IBM_ML_KEM: seed_attr = CKA_IBM_ML_KEM_PRIVATE_SEED; seed_param = OSSL_PKEY_PARAM_ML_KEM_SEED; break; case CKM_ML_DSA: case CKM_HASH_ML_DSA: seed_attr = CKA_SEED; seed_param = OSSL_PKEY_PARAM_ML_DSA_SEED; break; case CKM_ML_KEM: seed_attr = CKA_SEED; seed_param = OSSL_PKEY_PARAM_ML_KEM_SEED; break; default: seed_attr = (CK_ATTRIBUTE_TYPE)-1; seed_param = NULL; break; } if (private_key) { rc = pqc_pack_priv_key(tmpl, oid, mech, NULL, &priv_len); if (rc != CKR_OK) { TRACE_ERROR("pqc_pack_priv_key failed\n"); goto out; } priv_key = calloc(1, priv_len); if (priv_key == NULL) { TRACE_ERROR("Failed to allocate private key buffer\n"); rc = CKR_HOST_MEMORY; goto out; } rc = pqc_pack_priv_key(tmpl, oid, mech, priv_key, &priv_len); if (rc != CKR_OK) { if (rc == CKR_ATTRIBUTE_VALUE_INVALID) { free(priv_key); priv_key = NULL; /* Indicate no priv key */ } else { TRACE_ERROR("pqc_pack_priv_key failed\n"); goto out; } } } if (mech == CKM_IBM_ML_DSA || mech == CKM_IBM_ML_KEM || !private_key) { rc = pqc_pack_pub_key(tmpl, oid, mech, NULL, &pub_len); if (rc != CKR_OK) { TRACE_ERROR("pqc_pack_pub_key failed\n"); goto out; } pub_key = calloc(1, pub_len); if (pub_key == NULL) { TRACE_ERROR("Failed to allocate public key buffer\n"); rc = CKR_HOST_MEMORY; goto out; } rc = pqc_pack_pub_key(tmpl, oid, mech, pub_key, &pub_len); if (rc != CKR_OK) { if (rc == CKR_ATTRIBUTE_VALUE_INVALID) { free(pub_key); pub_key = NULL; /* Indicate no pub key */ } else { TRACE_ERROR("pqc_pack_pub_key failed\n"); goto out; } } } pctx = EVP_PKEY_CTX_new_from_name(NULL, alg_name, mech != CKM_IBM_DILITHIUM && mech != CKM_IBM_KYBER ? "?provider=default" : NULL); if (pctx == NULL) { TRACE_ERROR("EVP_PKEY_CTX_new_from_name failed for '%s'\n", alg_name); rc = CKR_FUNCTION_FAILED; goto out; } bld = OSSL_PARAM_BLD_new(); if (bld == NULL) { TRACE_ERROR("OSSL_PARAM_BLD_new failed\n"); rc = CKR_HOST_MEMORY; goto out; } if (private_key) { if (priv_key != NULL && OSSL_PARAM_BLD_push_octet_string(bld, OSSL_PKEY_PARAM_PRIV_KEY, priv_key, priv_len) != 1) { TRACE_ERROR("OSSL_PARAM_BLD_push_octet_string failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } /* Use private seed, if available */ if (seed_attr != (CK_ATTRIBUTE_TYPE)-1 && seed_param != NULL && template_attribute_find(tmpl, seed_attr, &attr) == TRUE && attr->ulValueLen != 0 && attr->pValue != NULL && check_settable_fromdata_params(pctx, seed_param)) { if (OSSL_PARAM_BLD_push_octet_string(bld, seed_param, attr->pValue, attr->ulValueLen) != 1) { TRACE_ERROR("OSSL_PARAM_BLD_push_octet_string failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } } else if (priv_key == NULL) { TRACE_ERROR("No private key available, and private-seed is not " "supported by OpenSSL/OQS-provider\n"); rc = CKR_KEY_SIZE_RANGE; goto out; } } if (pub_key != NULL && OSSL_PARAM_BLD_push_octet_string(bld, OSSL_PKEY_PARAM_PUB_KEY, pub_key, pub_len) != 1) { TRACE_ERROR("OSSL_PARAM_BLD_push_octet_string failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } params = OSSL_PARAM_BLD_to_param(bld); if (params == NULL) { TRACE_ERROR("OSSL_PARAM_BLD_to_param failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } if (EVP_PKEY_fromdata_init(pctx) != 1) { TRACE_ERROR("EVP_PKEY_fromdata_init failed for '%s'\n", alg_name); rc = CKR_FUNCTION_FAILED; goto out; } if (EVP_PKEY_fromdata(pctx, pkey, private_key ? EVP_PKEY_KEYPAIR : EVP_PKEY_PUBLIC_KEY, params) != 1) { TRACE_ERROR("EVP_PKEY_fromdata failed for '%s'\n", alg_name); rc = CKR_FUNCTION_FAILED; goto out; } rc = CKR_OK; out: if (priv_key != NULL) { OPENSSL_cleanse(priv_key, priv_len); free(priv_key); } if (pub_key != NULL) free(pub_key); if (pctx != NULL) EVP_PKEY_CTX_free(pctx); if (bld != NULL) OSSL_PARAM_BLD_free(bld); if (params != NULL) OSSL_PARAM_free(params); return rc; } CK_RV openssl_specific_pqc_get_pub_key_from_priv_key(TEMPLATE *priv_tmpl, const struct pqc_oid *oid, CK_MECHANISM_TYPE mech, CK_ATTRIBUTE *pub_value) { const char *alg_name; EVP_PKEY *pkey = NULL; CK_RV rc; alg_name = openssl_get_pqc_oid_name(oid); if (alg_name == NULL) { TRACE_ERROR("PQC key form is not supported by oqsprovider or " "OpenSSL\n"); rc = CKR_KEY_SIZE_RANGE; goto out; } rc = openssl_make_pqc_key_from_template(priv_tmpl, oid, mech, TRUE, alg_name, &pkey); if (rc != CKR_OK) { TRACE_ERROR("openssl_make_pqc_key_from_template failed.\n"); goto out; } rc = openssl_get_key_from_pkey(pkey, OSSL_PKEY_PARAM_PUB_KEY, (CK_BYTE **)&pub_value->pValue, &pub_value->ulValueLen, FALSE); if (rc != CKR_OK) { TRACE_ERROR("get_key_from_pkey failed for pub key\n"); goto out; } pub_value->type = CKA_VALUE; out: if (pkey != NULL) EVP_PKEY_free(pkey); return rc; } #if defined(OSSL_SIGNATURE_PARAM_DETERMINISTIC) || \ defined(OSSL_SIGNATURE_PARAM_CONTEXT_STRING) || \ defined(OSSL_SIGNATURE_PARAM_MESSAGE_ENCODING) || \ defined(OSSL_SIGNATURE_PARAM_SIGNATURE) static CK_BBOOL check_settable_ctx_params(EVP_PKEY_CTX *ctx, const char *name) { const OSSL_PARAM *settable, *p; settable = EVP_PKEY_CTX_settable_params(ctx); for (p = settable; p != NULL && p->key != NULL; p++) { if (strcmp(p->key, name) == 0) return TRUE; } return CK_FALSE; } #endif static CK_RV openssl_specific_ml_dsa_set_params(EVP_PKEY_CTX *ctx, CK_MECHANISM *mech) { CK_SIGN_ADDITIONAL_CONTEXT *param, tmp_param; OSSL_PARAM params[2]; int deterministic = 0; CK_RV rc; switch (mech->mechanism) { case CKM_IBM_ML_DSA: if (mech->pParameter == NULL || mech->ulParameterLen != sizeof(CK_IBM_SIGN_ADDITIONAL_CONTEXT)) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); return CKR_MECHANISM_PARAM_INVALID; } /* Translate IBM mech param to PKCS#11 standard one */ rc = ml_dsa_translate_sign_mech_param_from_ibm(mech->pParameter, &tmp_param); if (rc != CKR_OK) { TRACE_ERROR("ml_dsa_translate_sign_mech_param_from_ibm failed\n"); return rc; } param = &tmp_param; break; case CKM_ML_DSA: if (mech->pParameter == NULL || mech->ulParameterLen != sizeof(CK_SIGN_ADDITIONAL_CONTEXT)) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); return CKR_MECHANISM_PARAM_INVALID; } param = mech->pParameter; break; case CKM_HASH_ML_DSA: if (mech->pParameter == NULL || mech->ulParameterLen != sizeof(CK_HASH_SIGN_ADDITIONAL_CONTEXT)) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); return CKR_MECHANISM_PARAM_INVALID; } /* Translate hash sign param to sign param one */ rc = ml_dsa_translate_sign_mech_param_from_hash(mech->pParameter, &tmp_param, NULL); if (rc != CKR_OK) { TRACE_ERROR("ml_dsa_translate_sign_mech_param_from_hash failed\n"); return rc; } param = &tmp_param; break; default: TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); return CKR_MECHANISM_INVALID; } #ifndef OSSL_SIGNATURE_PARAM_DETERMINISTIC #ifndef OSSL_SIGNATURE_PARAM_CONTEXT_STRING UNUSED(ctx); UNUSED(params); #endif #endif switch (param->hedgeVariant) { case CKH_HEDGE_PREFERRED: case CKH_HEDGE_REQUIRED: deterministic = 0; break; case CKH_DETERMINISTIC_REQUIRED: deterministic = 1; break; default: TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); return CKR_MECHANISM_PARAM_INVALID; } if (deterministic) { #ifdef OSSL_SIGNATURE_PARAM_DETERMINISTIC if (!check_settable_ctx_params(ctx, OSSL_SIGNATURE_PARAM_DETERMINISTIC)) { TRACE_ERROR("OpenSSL does not support deterministic ML-DSA " "signatures\n"); return CKR_MECHANISM_PARAM_INVALID; } params[0] = OSSL_PARAM_construct_int(OSSL_SIGNATURE_PARAM_DETERMINISTIC, &deterministic); params[1] = OSSL_PARAM_construct_end(); if (EVP_PKEY_CTX_set_params(ctx, params) != 1) { TRACE_ERROR("EVP_PKEY_CTX_set_params (deterministic) failed\n"); return CKR_MECHANISM_PARAM_INVALID; } #else TRACE_ERROR("OpenSSL does not support deterministic ML-DSA " "signatures\n"); return CKR_MECHANISM_PARAM_INVALID; #endif } if (param->pContext != NULL && param->ulContextLen != 0) { #ifdef OSSL_SIGNATURE_PARAM_CONTEXT_STRING if (!check_settable_ctx_params(ctx, OSSL_SIGNATURE_PARAM_CONTEXT_STRING)) { TRACE_ERROR("OpenSSL does not support ML-DSA with context\n"); return CKR_MECHANISM_PARAM_INVALID; } params[0] = OSSL_PARAM_construct_octet_string( OSSL_SIGNATURE_PARAM_CONTEXT_STRING, param->pContext, param->ulContextLen); params[1] = OSSL_PARAM_construct_end(); if (EVP_PKEY_CTX_set_params(ctx, params) != 1) { TRACE_ERROR("EVP_PKEY_CTX_set_params (context) failed\n"); return CKR_MECHANISM_PARAM_INVALID; } #else TRACE_ERROR("OpenSSL does not support ML-DSA with context\n"); return CKR_MECHANISM_PARAM_INVALID; #endif } return CKR_OK; } static CK_RV openssl_specific_ml_dsa_encode_prehashed_msg( EVP_PKEY_CTX *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, CK_MECHANISM_TYPE prehash_mech, CK_BYTE *context, CK_ULONG context_len, CK_BYTE **prehashed_msg, CK_ULONG *prehashed_msg_len) { #ifdef OSSL_SIGNATURE_PARAM_MESSAGE_ENCODING CK_RV rc = CKR_OK; ASN1_OBJECT *obj = NULL; CK_BYTE *oid = NULL, *p; int oid_len; OSSL_PARAM params[2]; int encoding = 0; if (context_len > 255) { TRACE_ERROR("Context length is too large\n"); rc = CKR_MECHANISM_PARAM_INVALID; goto out; } if (!check_settable_ctx_params(ctx, OSSL_SIGNATURE_PARAM_MESSAGE_ENCODING)) { TRACE_ERROR("OpenSSL does not support Prehash-ML-DSA\n"); rc = CKR_MECHANISM_PARAM_INVALID; goto out; } switch (prehash_mech) { case CKM_SHA_1: obj = OBJ_nid2obj(NID_sha1); break; case CKM_SHA224: obj = OBJ_nid2obj(NID_sha224); break; case CKM_SHA256: obj = OBJ_nid2obj(NID_sha256); break; case CKM_SHA384: obj = OBJ_nid2obj(NID_sha384); break; case CKM_SHA512: obj = OBJ_nid2obj(NID_sha512); break; case CKM_SHA512_224: obj = OBJ_nid2obj(NID_sha512_224); break; case CKM_SHA512_256: obj = OBJ_nid2obj(NID_sha512_256); break; case CKM_SHA3_224: obj = OBJ_nid2obj(NID_sha3_224); break; case CKM_SHA3_256: obj = OBJ_nid2obj(NID_sha3_256); break; case CKM_SHA3_384: obj = OBJ_nid2obj(NID_sha3_384); break; case CKM_SHA3_512: obj = OBJ_nid2obj(NID_sha3_512); break; case CKM_OCK_SHAKE128: obj = OBJ_nid2obj(NID_shake128); break; case CKM_OCK_SHAKE256: obj = OBJ_nid2obj(NID_shake256); break; default: break; } if (obj == NULL) { TRACE_ERROR("Prehash-mechanism not supported\n"); rc = CKR_MECHANISM_INVALID; goto out; } oid_len = i2d_ASN1_OBJECT(obj, &oid); if (oid_len <= 0) { TRACE_ERROR("Prehash-mechanism not supported\n"); rc = CKR_MECHANISM_INVALID; goto out; } params[0] = OSSL_PARAM_construct_int( OSSL_SIGNATURE_PARAM_MESSAGE_ENCODING, &encoding); params[1] = OSSL_PARAM_construct_end(); if (EVP_PKEY_CTX_set_params(ctx, params) != 1) { TRACE_ERROR("EVP_PKEY_CTX_set_params (encoding) failed\n"); rc = CKR_MECHANISM_PARAM_INVALID; goto out; } *prehashed_msg_len = 2 + context_len + oid_len + in_data_len; *prehashed_msg = malloc(*prehashed_msg_len); if (*prehashed_msg == NULL) { TRACE_ERROR("Failed to allocate message buffer\n"); rc = CKR_HOST_MEMORY; goto out; } /* * Encode the prehashed message 'phm' according to FIPS 204 algorithm 4 * step 23 (HashML-sign) and algorithm 5 step 18 (HashML-verify), i.e.: * 0x01 || len(ctx) || ctx || oid || phm */ p = *prehashed_msg; *(p++) = 0x01; *(p++) = context_len; memcpy(p, context, context_len); p += context_len; memcpy(p, oid, oid_len); p += oid_len; memcpy(p, in_data, in_data_len); out: if (obj != NULL) ASN1_OBJECT_free(obj); if (oid != NULL) OPENSSL_free(oid); return rc; #else UNUSED(ctx); UNUSED(in_data); UNUSED(in_data_len); UNUSED(prehash_mech); UNUSED(context); UNUSED(context_len); UNUSED(prehashed_msg); UNUSED(prehashed_msg_len); TRACE_ERROR("OpenSSL does not support Prehash-ML-DSA\n"); return CKR_MECHANISM_INVALID; #endif } static void openssl_specific_pqc_ctx_free(STDLL_TokData_t *tokdata, SESSION *sess, CK_BYTE *context, CK_ULONG context_len) { UNUSED(tokdata); UNUSED(sess); UNUSED(context_len); EVP_PKEY_CTX_free((EVP_PKEY_CTX *)context); } CK_RV openssl_specific_pqc_sign(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, const struct pqc_oid *oid, CK_MECHANISM *mech, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *signature, CK_ULONG *signature_len, OBJECT *key_obj, CK_BBOOL final_part) { struct openssl_ex_data *ex_data = NULL; #ifdef EVP_PKEY_OP_SIGNMSG EVP_SIGNATURE *alg = NULL; #endif EVP_PKEY *pkey = NULL; CK_RV rc = CKR_OK; EVP_PKEY_CTX *ctx = NULL; const char *alg_name; size_t siglen; CK_HASH_SIGN_ADDITIONAL_CONTEXT *hash_sign_context; CK_BYTE *prehashed_msg = NULL; CK_ULONG prehashed_msg_len = 0; CK_BBOOL single_part = FALSE; UNUSED(tokdata); UNUSED(sess); if (mech->mechanism == CKM_HASH_ML_DSA && !final_part) { /* CKM_HASH_ML_DSA does not support multipart */ TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); return CKR_MECHANISM_INVALID; } if (mech->mechanism == CKM_HASH_ML_DSA || sess->sign_ctx.context == NULL) { alg_name = openssl_get_pqc_oid_name(oid); if (alg_name == NULL) { TRACE_ERROR("PQC key form is not supported by oqsprovider or " "OpenSSL\n"); return CKR_KEY_SIZE_RANGE; } rc = openssl_get_ex_data(key_obj, (void **)&ex_data, sizeof(struct openssl_ex_data), openssl_need_wr_lock, NULL); if (rc != CKR_OK) return rc; if (ex_data->pkey == NULL) { rc = openssl_make_pqc_key_from_template(key_obj->template, oid, mech->mechanism, TRUE, alg_name, &ex_data->pkey); if (rc != CKR_OK) goto out; } pkey = ex_data->pkey; if (EVP_PKEY_up_ref(pkey) != 1) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto out; } ctx = EVP_PKEY_CTX_new(pkey, NULL); if (ctx == NULL) { TRACE_ERROR("EVP_PKEY_CTX_new failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } ERR_set_mark(); if (EVP_PKEY_sign_init(ctx) <= 0) { #ifdef EVP_PKEY_OP_SIGNMSG /* * OpenSSL 3.5 supports ML-DSA sign only with the sign-message API */ ERR_pop_to_mark(); alg = EVP_SIGNATURE_fetch(NULL, alg_name, NULL); if (alg == NULL) { TRACE_ERROR("EVP_SIGNATURE_fetch failed for %s\n", alg_name); rc = CKR_FUNCTION_FAILED; goto out; } if (EVP_PKEY_sign_message_init(ctx, alg, NULL) <= 0) { TRACE_ERROR("EVP_PKEY_sign_message_init and EVP_PKEY_sign_init " "have both failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } #else TRACE_ERROR("EVP_PKEY_sign_init failed\n"); rc = CKR_FUNCTION_FAILED; goto out; #endif } if (mech->pParameter != NULL && mech->ulParameterLen > 0) { rc = openssl_specific_ml_dsa_set_params(ctx, mech); if (rc != CKR_OK) { TRACE_ERROR("openssl_specific_ml_dsa_set_params failed\n"); goto out; } } single_part = final_part; if (!single_part) { sess->sign_ctx.context = (CK_BYTE*)ctx; sess->sign_ctx.context_free_func = openssl_specific_pqc_ctx_free; sess->sign_ctx.state_unsaveable = TRUE; } } else { ctx = (EVP_PKEY_CTX*)sess->sign_ctx.context; } if (!final_part) { #ifdef EVP_PKEY_OP_SIGNMSG if (in_data_len > 0 && EVP_PKEY_sign_message_update(ctx, in_data, in_data_len) <= 0) { #ifdef EVP_R_PROVIDER_SIGNATURE_NOT_SUPPORTED if (ERR_GET_REASON(ERR_get_error()) == EVP_R_PROVIDER_SIGNATURE_NOT_SUPPORTED) { rc = CKR_MECHANISM_INVALID; /* Multi-part not supported */ TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); } else { rc = CKR_FUNCTION_FAILED; TRACE_ERROR("EVP_PKEY_sign_message_update failed\n"); } #else rc = CKR_FUNCTION_FAILED; TRACE_ERROR("EVP_PKEY_sign_message_update failed\n"); #endif goto out; } rc = CKR_OK; goto out; #else rc = CKR_MECHANISM_INVALID; /* Multi-part not supported */ TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); goto out; #endif } /* Prehash-mode is only supported with CKM_HASH_ML_DSA */ if (mech->mechanism == CKM_HASH_ML_DSA) { if (mech->pParameter == NULL || mech->ulParameterLen != sizeof(CK_HASH_SIGN_ADDITIONAL_CONTEXT)) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto out; } hash_sign_context = mech->pParameter; rc = openssl_specific_ml_dsa_encode_prehashed_msg( ctx, in_data, in_data_len, hash_sign_context->hash, hash_sign_context->pContext, hash_sign_context->ulContextLen, &prehashed_msg, &prehashed_msg_len); if (rc != CKR_OK) { TRACE_ERROR("openssl_specific_ml_dsa_encode_prehashed_msg " "failed\n"); goto out; } in_data = prehashed_msg; in_data_len = prehashed_msg_len; } if (length_only) { if (single_part) { if (EVP_PKEY_sign(ctx, NULL, &siglen, in_data, in_data_len) <= 0) { TRACE_ERROR("EVP_PKEY_sign failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } } else { #ifdef EVP_PKEY_OP_SIGNMSG if (in_data_len > 0 && EVP_PKEY_sign_message_update(ctx, in_data, in_data_len) <= 0) { #ifdef EVP_R_PROVIDER_SIGNATURE_NOT_SUPPORTED if (ERR_GET_REASON(ERR_get_error()) == EVP_R_PROVIDER_SIGNATURE_NOT_SUPPORTED) { rc = CKR_MECHANISM_INVALID; /* Multi-part not supported */ TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); } else { rc = CKR_FUNCTION_FAILED; TRACE_ERROR("EVP_PKEY_sign_message_update failed\n"); } #else rc = CKR_FUNCTION_FAILED; TRACE_ERROR("EVP_PKEY_sign_message_update failed\n"); #endif goto out; } if (EVP_PKEY_sign_message_final(ctx, NULL, &siglen) <= 0) { #ifdef EVP_R_PROVIDER_SIGNATURE_NOT_SUPPORTED if (ERR_GET_REASON(ERR_get_error()) == EVP_R_PROVIDER_SIGNATURE_NOT_SUPPORTED) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); rc = CKR_MECHANISM_INVALID; /* Multi-part not supported */ } else { TRACE_ERROR("EVP_PKEY_sign_message_final failed\n"); rc = CKR_FUNCTION_FAILED; } #else TRACE_ERROR("EVP_PKEY_sign_message_final failed\n"); rc = CKR_FUNCTION_FAILED; #endif goto out; } #else rc = CKR_MECHANISM_INVALID; /* Multi-part not supported */ TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); goto out; #endif } *signature_len = siglen; goto out; } siglen = *signature_len; if (single_part) { if (EVP_PKEY_sign(ctx, signature, &siglen, in_data, in_data_len) <= 0) { TRACE_ERROR("EVP_PKEY_sign failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } } else { #ifdef EVP_PKEY_OP_SIGNMSG if (EVP_PKEY_sign_message_final(ctx, signature, &siglen) <= 0) { #ifdef EVP_R_PROVIDER_SIGNATURE_NOT_SUPPORTED if (ERR_GET_REASON(ERR_get_error()) == EVP_R_PROVIDER_SIGNATURE_NOT_SUPPORTED) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); rc = CKR_MECHANISM_INVALID; /* Multi-part not supported */ } else { TRACE_ERROR("EVP_PKEY_sign_message_final failed\n"); rc = CKR_FUNCTION_FAILED; } #else TRACE_ERROR("EVP_PKEY_sign_message_final failed\n"); rc = CKR_FUNCTION_FAILED; #endif } #else rc = CKR_MECHANISM_INVALID; /* Multi-part not supported */ TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); goto out; #endif } *signature_len = siglen; out: if (prehashed_msg != NULL) free(prehashed_msg); if (pkey != NULL) EVP_PKEY_free(pkey); if (final_part && (single_part || !length_only) && ctx != NULL) { EVP_PKEY_CTX_free(ctx); if (!single_part) { sess->sign_ctx.context = NULL; sess->sign_ctx.context_free_func = 0; } } #ifdef EVP_PKEY_OP_SIGNMSG if (alg != NULL) EVP_SIGNATURE_free(alg); #endif if (ex_data != NULL) object_ex_data_unlock(key_obj); return rc; } CK_RV openssl_specific_pqc_verify(STDLL_TokData_t *tokdata, SESSION *sess, const struct pqc_oid *oid, CK_MECHANISM *mech, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *signature, CK_ULONG signature_len, OBJECT *key_obj, CK_BBOOL final_part) { struct openssl_ex_data *ex_data = NULL; #ifdef EVP_PKEY_OP_VERIFYMSG EVP_SIGNATURE *alg = NULL; #endif EVP_PKEY *pkey = NULL; CK_RV rc = CKR_OK; EVP_PKEY_CTX *ctx = NULL; const char *alg_name; size_t siglen; CK_HASH_SIGN_ADDITIONAL_CONTEXT *hash_verify_context; CK_BYTE *prehashed_msg = NULL; CK_ULONG prehashed_msg_len = 0; CK_BBOOL single_part = FALSE; UNUSED(tokdata); UNUSED(sess); if (mech->mechanism == CKM_HASH_ML_DSA && !final_part) { /* CKM_HASH_ML_DSA does not support multipart */ TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); return CKR_MECHANISM_INVALID; } if (mech->mechanism == CKM_HASH_ML_DSA || sess->verify_ctx.context == NULL) { alg_name = openssl_get_pqc_oid_name(oid); if (alg_name == NULL) { TRACE_ERROR("PQC key form is not supported by oqsprovider or " "OpenSSL\n"); return CKR_KEY_SIZE_RANGE; } rc = openssl_get_ex_data(key_obj, (void **)&ex_data, sizeof(struct openssl_ex_data), openssl_need_wr_lock, NULL); if (rc != CKR_OK) return rc; if (ex_data->pkey == NULL) { rc = openssl_make_pqc_key_from_template(key_obj->template, oid, mech->mechanism, FALSE, alg_name, &ex_data->pkey); if (rc != CKR_OK) goto out; } pkey = ex_data->pkey; if (EVP_PKEY_up_ref(pkey) != 1) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto out; } ctx = EVP_PKEY_CTX_new(pkey, NULL); if (ctx == NULL) { TRACE_ERROR("EVP_PKEY_CTX_new failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } ERR_set_mark(); if (EVP_PKEY_verify_init(ctx) <= 0) { #ifdef EVP_PKEY_OP_VERIFYMSG /* * OpenSSL 3.5 supports ML-DSA verify only with the verify-message * API */ ERR_pop_to_mark(); alg = EVP_SIGNATURE_fetch(NULL, alg_name, NULL); if (alg == NULL) { TRACE_ERROR("EVP_SIGNATURE_fetch failed for %s\n", alg_name); rc = CKR_FUNCTION_FAILED; goto out; } if (EVP_PKEY_verify_message_init(ctx, alg, NULL) <= 0) { TRACE_ERROR("EVP_PKEY_verify_message_init and " "EVP_PKEY_verify_init have both failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } #else TRACE_ERROR("EVP_PKEY_verify_init failed\n"); rc = CKR_FUNCTION_FAILED; goto out; #endif } if (mech->pParameter != NULL && mech->ulParameterLen > 0) { rc = openssl_specific_ml_dsa_set_params(ctx, mech); if (rc != CKR_OK) { TRACE_ERROR("openssl_specific_ml_dsa_set_params failed\n"); goto out; } } single_part = final_part; if (!single_part) { sess->verify_ctx.context = (CK_BYTE*)ctx; sess->verify_ctx.context_free_func = openssl_specific_pqc_ctx_free; sess->verify_ctx.state_unsaveable = TRUE; } } else { ctx = (EVP_PKEY_CTX*)sess->verify_ctx.context; } if (!final_part) { #ifdef EVP_PKEY_OP_VERIFYMSG if (in_data_len > 0 && EVP_PKEY_verify_message_update(ctx, in_data, in_data_len) <= 0) { #ifdef EVP_R_PROVIDER_SIGNATURE_NOT_SUPPORTED if (ERR_GET_REASON(ERR_get_error()) == EVP_R_PROVIDER_SIGNATURE_NOT_SUPPORTED) { rc = CKR_MECHANISM_INVALID; /* Multi-part not supported */ TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); } else { rc = CKR_FUNCTION_FAILED; TRACE_ERROR("EVP_PKEY_verify_message_update failed\n"); } #else rc = CKR_FUNCTION_FAILED; TRACE_ERROR("EVP_PKEY_verify_message_update failed\n"); #endif goto out; } rc = CKR_OK; goto out; #else rc = CKR_MECHANISM_INVALID; /* Multi-part not supported */ TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); goto out; #endif } /* Prehash-mode is only supported with CKM_HASH_ML_DSA */ if (mech->mechanism == CKM_HASH_ML_DSA) { if (mech->pParameter == NULL || mech->ulParameterLen != sizeof(CK_HASH_SIGN_ADDITIONAL_CONTEXT)) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto out; } hash_verify_context = mech->pParameter; rc = openssl_specific_ml_dsa_encode_prehashed_msg( ctx, in_data, in_data_len, hash_verify_context->hash, hash_verify_context->pContext, hash_verify_context->ulContextLen, &prehashed_msg, &prehashed_msg_len); if (rc != CKR_OK) { TRACE_ERROR("openssl_specific_ml_dsa_encode_prehashed_msg failed\n"); goto out; } in_data = prehashed_msg; in_data_len = prehashed_msg_len; } siglen = signature_len; if (single_part) { rc = EVP_PKEY_verify(ctx, signature, siglen, in_data, in_data_len); } else { #ifdef EVP_PKEY_OP_VERIFYMSG if (in_data_len > 0 && EVP_PKEY_verify_message_update(ctx, in_data, in_data_len) <= 0) { #ifdef EVP_R_PROVIDER_SIGNATURE_NOT_SUPPORTED if (ERR_GET_REASON(ERR_get_error()) == EVP_R_PROVIDER_SIGNATURE_NOT_SUPPORTED) { rc = CKR_MECHANISM_INVALID; /* Multi-part not supported */ TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); } else { rc = CKR_FUNCTION_FAILED; TRACE_ERROR("EVP_PKEY_verify_message_update failed\n"); } #else rc = CKR_FUNCTION_FAILED; TRACE_ERROR("EVP_PKEY_verify_message_update failed\n"); #endif goto out; } if (!check_settable_ctx_params(ctx, OSSL_SIGNATURE_PARAM_SIGNATURE)) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); rc = CKR_MECHANISM_INVALID; /* Multi-part not supported */ goto out; } if (EVP_PKEY_CTX_set_signature(ctx, signature, siglen) != 1) { TRACE_ERROR("EVP_PKEY_CTX_set_signature failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } rc = EVP_PKEY_verify_message_final(ctx); #else rc = CKR_MECHANISM_INVALID; /* Multi-part not supported */ TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); goto out; #endif } switch (rc) { case 0: rc = CKR_SIGNATURE_INVALID; break; case 1: rc = CKR_OK; break; default: #ifdef EVP_R_PROVIDER_SIGNATURE_NOT_SUPPORTED if (ERR_GET_REASON(ERR_get_error()) == EVP_R_PROVIDER_SIGNATURE_NOT_SUPPORTED) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); rc = CKR_MECHANISM_INVALID; /* Multi-part not supported */ } else { TRACE_ERROR("EVP_PKEY_verify[_message_final] failed\n"); rc = CKR_FUNCTION_FAILED; } #else TRACE_ERROR("EVP_PKEY_verify failed\n"); rc = CKR_FUNCTION_FAILED; #endif break; } out: if (prehashed_msg != NULL) free(prehashed_msg); if (pkey != NULL) EVP_PKEY_free(pkey); if (final_part && ctx != NULL) { EVP_PKEY_CTX_free(ctx); if (!single_part) { sess->verify_ctx.context = NULL; sess->verify_ctx.context_free_func = 0; } } #ifdef EVP_PKEY_OP_VERIFYMSG if (alg != NULL) EVP_SIGNATURE_free(alg); #endif if (ex_data != NULL) object_ex_data_unlock(key_obj); return rc; } static CK_RV openssl_specific_pqc_perform_kem(const struct pqc_oid *oid, CK_MECHANISM *mech, OBJECT *base_key_object, CK_OBJECT_CLASS base_key_class, CK_BBOOL encapsulate, CK_BYTE *pCipher, CK_ULONG *ulCipherLen, CK_BYTE **pSecret, CK_ULONG *ulSecretLen) { struct openssl_ex_data *ex_data = NULL; EVP_PKEY *pkey = NULL; CK_RV rc = CKR_OK; EVP_PKEY_CTX *ctx = NULL; const char *alg_name; size_t cipher_len, secret_len = 0; *pSecret = NULL; alg_name = openssl_get_pqc_oid_name(oid); if (alg_name == NULL) { TRACE_ERROR("PQC key form is not supported by oqsprovider or " "OpenSSL\n"); return CKR_KEY_SIZE_RANGE; } rc = openssl_get_ex_data(base_key_object, (void **)&ex_data, sizeof(struct openssl_ex_data), openssl_need_wr_lock, NULL); if (rc != CKR_OK) return rc; if (ex_data->pkey == NULL) { rc = openssl_make_pqc_key_from_template(base_key_object->template, oid, mech->mechanism, !encapsulate, alg_name, &ex_data->pkey); if (rc != CKR_OK) goto out; } pkey = ex_data->pkey; if (EVP_PKEY_up_ref(pkey) != 1) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto out; } ctx = EVP_PKEY_CTX_new(pkey, NULL); if (ctx == NULL) { TRACE_ERROR("EVP_PKEY_CTX_new failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } if (encapsulate) { if (base_key_class != CKO_PUBLIC_KEY) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); rc = CKR_KEY_TYPE_INCONSISTENT; goto out; } if (EVP_PKEY_encapsulate_init(ctx, NULL) != 1) { TRACE_ERROR("EVP_PKEY_encapsulate_init failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } /* size query */ if (EVP_PKEY_encapsulate(ctx, NULL, &cipher_len, NULL, &secret_len) <= 0) { TRACE_ERROR("EVP_PKEY_encapsulate (size query) failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } if (*ulCipherLen < cipher_len || pCipher == NULL) { *ulCipherLen = cipher_len; TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); rc = CKR_BUFFER_TOO_SMALL; goto out; } *pSecret = calloc(secret_len, 1); if (*pSecret == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto out; } /* Do the encapsulate */ cipher_len = *ulCipherLen; if (EVP_PKEY_encapsulate(ctx, pCipher, &cipher_len, *pSecret, &secret_len) <= 0) { TRACE_ERROR("EVP_PKEY_encapsulate failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } *ulCipherLen = cipher_len; *ulSecretLen = secret_len; } else { if (base_key_class != CKO_PRIVATE_KEY) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); rc = CKR_KEY_TYPE_INCONSISTENT; goto out; } if (EVP_PKEY_decapsulate_init(ctx, NULL) != 1) { TRACE_ERROR("EVP_PKEY_decapsulate_init failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } /* Size query */ if (EVP_PKEY_decapsulate(ctx, NULL, &secret_len, pCipher, *ulCipherLen) <= 0) { TRACE_ERROR("EVP_PKEY_decapsulate (size query) failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } *pSecret = calloc(secret_len, 1); if (*pSecret == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto out; } /* Do the decapsulate */ if (EVP_PKEY_decapsulate(ctx, *pSecret, &secret_len, pCipher, *ulCipherLen) <= 0) { TRACE_ERROR("EVP_PKEY_decapsulate failed\n"); rc = CKR_FUNCTION_FAILED; goto out; } *ulSecretLen = secret_len; } out: if (pkey != NULL) EVP_PKEY_free(pkey); if (ctx != NULL) EVP_PKEY_CTX_free(ctx); if (rc != CKR_OK && *pSecret != NULL) { OPENSSL_cleanse(*pSecret, secret_len); free(*pSecret); *pSecret = NULL; *ulSecretLen = 0; } object_ex_data_unlock(base_key_object); return rc; } static CK_RV openssl_specific_pqc_kem(STDLL_TokData_t *tokdata, SESSION *sess, const struct pqc_oid *oid, CK_MECHANISM *mech, OBJECT *base_key_object, CK_OBJECT_CLASS base_key_class, CK_KEY_TYPE base_key_type, OBJECT *derived_key_object, CK_KEY_TYPE derived_key_type, CK_ULONG derived_keylen) { CK_RV rc = CKR_OK; CK_IBM_ML_KEM_PARAMS *kem_params = NULL; CK_BBOOL encapsulate = TRUE; CK_ULONG kdf_type = CKD_NULL; CK_OBJECT_HANDLE hybrid_secret_handle = CK_INVALID_HANDLE; CK_BYTE *shared_data = NULL; CK_ULONG shared_data_len = 0; CK_BBOOL prepend = FALSE; OBJECT *hybrid_key_object = NULL; CK_OBJECT_CLASS hybrid_key_class; CK_KEY_TYPE hybrid_key_type; CK_ATTRIBUTE *hybrid_key_value = NULL; CK_MECHANISM_TYPE digest_mech; CK_ULONG kdf_digest_len; CK_ULONG secret_len = 0; CK_BYTE *secret = NULL; CK_BYTE *hybrid_secret = NULL; CK_ULONG hybrid_secret_len; CK_BYTE *value = NULL; CK_ULONG value_len; CK_BBOOL value_allocated = FALSE, use_as_data = FALSE; switch (mech->mechanism) { case CKM_IBM_KYBER: if (base_key_type != CKK_IBM_PQC_KYBER) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); rc = CKR_KEY_TYPE_INCONSISTENT; goto out; } break; case CKM_IBM_ML_KEM: if (base_key_type != CKK_IBM_ML_KEM) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); rc = CKR_KEY_TYPE_INCONSISTENT; goto out; } break; default: TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); rc = CKR_MECHANISM_INVALID; goto out; } switch (mech->mechanism) { case CKM_IBM_KYBER: case CKM_IBM_ML_KEM: if (mech->pParameter == NULL || mech->ulParameterLen != sizeof(CK_IBM_ML_KEM_PARAMS)) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto out; } kem_params = mech->pParameter; if (kem_params->ulVersion != CK_IBM_ML_KEM_VERSION) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto out; } switch (kem_params->mode) { case CK_IBM_ML_KEM_ENCAPSULATE: encapsulate = TRUE; /* pCipher/ulCipherLen is output on encapsulate */ if (kem_params->ulCipherLen > 0 && kem_params->pCipher == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto out; } break; case CK_IBM_ML_KEM_DECAPSULATE: encapsulate = FALSE; /* pCipher/ulCipherLen is input on decapsulate */ if (kem_params->pCipher == NULL || kem_params->ulCipherLen == 0) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto out; } break; default: TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto out; } if (kem_params->ulSharedDataLen > 0 && kem_params->pSharedData == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto out; } kdf_type = kem_params->kdf; hybrid_secret_handle = kem_params->hSecret; shared_data = kem_params->pSharedData; shared_data_len = kem_params->ulSharedDataLen; prepend = kem_params->bPrepend; break; default: TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); rc = CKR_MECHANISM_INVALID; goto out; } if (hybrid_secret_handle != CK_INVALID_HANDLE) { rc = object_mgr_find_in_map1(tokdata, hybrid_secret_handle, &hybrid_key_object, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to acquire hybrid key from handle.\n"); if (rc == CKR_OBJECT_HANDLE_INVALID) rc = CKR_KEY_HANDLE_INVALID; goto out; } if (!template_get_class(hybrid_key_object->template, &hybrid_key_class, &hybrid_key_type)) { TRACE_ERROR("Could not find CKA_CLASS in the hybrid key\n"); rc = CKR_TEMPLATE_INCOMPLETE; goto out; } if (hybrid_key_class != CKO_SECRET_KEY) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); rc = CKR_KEY_TYPE_INCONSISTENT; goto out; } rc = template_attribute_get_bool(hybrid_key_object->template, CKA_IBM_USE_AS_DATA, &use_as_data); if (rc != CKR_OK || use_as_data == FALSE) { if (rc != CKR_OK) { TRACE_ERROR("hybrid key does not have " "CKA_IBM_USE_AS_DATA=TRUE\n"); rc = CKR_ACTION_PROHIBITED; goto out; } } rc = template_attribute_get_non_empty(hybrid_key_object->template, CKA_VALUE, &hybrid_key_value); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE in the hybrid key\n"); goto out; } } rc = openssl_specific_pqc_perform_kem(oid, mech, base_key_object, base_key_class, encapsulate, kem_params->pCipher, &kem_params->ulCipherLen, &secret, &secret_len); if (rc != CKR_OK) { TRACE_ERROR("openssl_specific_pqc_perform_kem failed\n"); goto out; } if (hybrid_key_value != NULL) { hybrid_secret_len = secret_len + hybrid_key_value->ulValueLen; hybrid_secret = malloc(hybrid_secret_len); if (hybrid_secret == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto out; } if (prepend) { /* prepend KEM key material to hybrid secret */ memcpy(hybrid_secret, secret, secret_len); memcpy(hybrid_secret + secret_len, hybrid_key_value->pValue, hybrid_key_value->ulValueLen); } else { /* append KEM key material to hybrid secret */ memcpy(hybrid_secret, hybrid_key_value->pValue, hybrid_key_value->ulValueLen); memcpy(hybrid_secret + hybrid_key_value->ulValueLen, secret, secret_len); } OPENSSL_cleanse(secret, secret_len); free(secret); secret = hybrid_secret; secret_len = hybrid_secret_len; } switch (kdf_type) { case CKD_NULL: case CKD_IBM_HYBRID_NULL: value = secret; value_len = secret_len; if (value_len > derived_keylen) { value_len = derived_keylen; } else if (value_len < derived_keylen) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); rc = CKR_TEMPLATE_INCONSISTENT; goto out; } break; case CKD_SHA1_KDF: case CKD_SHA224_KDF: case CKD_SHA256_KDF: case CKD_SHA384_KDF: case CKD_SHA512_KDF: case CKD_SHA3_224_KDF: case CKD_SHA3_256_KDF: case CKD_SHA3_384_KDF: case CKD_SHA3_512_KDF: case CKD_IBM_HYBRID_SHA1_KDF: case CKD_IBM_HYBRID_SHA224_KDF: case CKD_IBM_HYBRID_SHA256_KDF: case CKD_IBM_HYBRID_SHA384_KDF: case CKD_IBM_HYBRID_SHA512_KDF: rc = digest_from_kdf(kdf_type, &digest_mech); if (rc != CKR_OK) { TRACE_ERROR("Cannot determine mech from kdf.\n"); rc = CKR_MECHANISM_PARAM_INVALID; goto out; } rc = get_sha_size(digest_mech, &kdf_digest_len); if (rc != CKR_OK) { TRACE_ERROR("Cannot determine SHA digest size.\n"); rc = CKR_MECHANISM_PARAM_INVALID; goto out; } value_len = derived_keylen; /* ckm_kdf_X9_63() needs a buffer of multiple of kdf digest length */ derived_keylen = ((value_len / kdf_digest_len) + 1) * kdf_digest_len; value = malloc(derived_keylen); if (value == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto out; } value_allocated = TRUE; rc = ckm_kdf_X9_63(tokdata, sess, kdf_type, kdf_digest_len, secret, secret_len, shared_data, shared_data_len, value, derived_keylen); if (rc != CKR_OK) { TRACE_ERROR("ckm_kdf_X9_63 failed\n"); goto out; } break; default: TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto out; } /* Update derived key value in target object */ rc = template_build_update_attribute(derived_key_object->template, CKA_VALUE, value, value_len); if (rc != CKR_OK) { TRACE_ERROR("template_build_update_attribute failed for CKA_VALUE, " "rc=0x%lx.\n", rc); goto out; } switch (derived_key_type) { case CKK_GENERIC_SECRET: case CKK_AES: case CKK_AES_XTS: /* Supply CKA_VALUE_LEN since this is required for those key types */ rc = template_build_update_attribute(derived_key_object->template, CKA_VALUE_LEN, (CK_BYTE*)&value_len, sizeof(value_len)); if (rc != CKR_OK) { TRACE_ERROR("template_build_update_attribute failed for " "CKA_VALUE_LEN, rc=0x%lx.\n", rc); goto out; } break; case CKK_DES: if (des_check_weak_key(secret)) { TRACE_ERROR("Derived key is a weak DES key\n"); rc = CKR_FUNCTION_FAILED; goto out; } break; default: break; } out: if (secret != NULL) { OPENSSL_cleanse(secret, secret_len); free(secret); } if (value != NULL && value_allocated) { OPENSSL_cleanse(value, value_len); free(value); } if (hybrid_key_object != NULL) { object_put(tokdata, hybrid_key_object, TRUE); hybrid_key_object = NULL; } return rc; } static CK_RV openssl_specific_pqc_kem_with_ecdh(STDLL_TokData_t *tokdata, SESSION *sess, const struct pqc_oid *oid, CK_MECHANISM *mech, OBJECT *base_key_object, CK_OBJECT_CLASS base_key_class, CK_KEY_TYPE base_key_type, OBJECT *derived_key_object, CK_KEY_TYPE derived_key_type, CK_ULONG derived_keylen) { CK_RV rc = CKR_OK; CK_IBM_ML_KEM_WITH_ECDH_PARAMS *kem_params = NULL; CK_BBOOL encapsulate = TRUE; OBJECT *ec_key_object = NULL; CK_BYTE ecdh_secret_z[MAX_ECDH_SHARED_SECRET_SIZE]; CK_ULONG ecdh_secret_z_len = 0; CK_MECHANISM_TYPE digest_mech; CK_ULONG kdf_digest_len; CK_ULONG kem_secret_t_len = 0; CK_BYTE *kem_secret_t = NULL; CK_BYTE *hybrid_secret = NULL; CK_ULONG hybrid_secret_len; CK_BYTE *value = NULL; CK_ULONG value_len; CK_BBOOL value_allocated = FALSE; CK_MECHANISM ecdh_mech = { CKM_ECDH1_DERIVE, NULL, 0 }; if (base_key_type != CKK_IBM_ML_KEM) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); rc = CKR_KEY_TYPE_INCONSISTENT; goto out; } if (mech->pParameter == NULL || mech->ulParameterLen != sizeof(CK_IBM_ML_KEM_WITH_ECDH_PARAMS)) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto out; } kem_params = mech->pParameter; switch (kem_params->mode) { case CK_IBM_ML_KEM_ENCAPSULATE: encapsulate = TRUE; /* pCipher/ulCipherLen is output on encapsulate */ if (kem_params->ulCipherLen > 0 && kem_params->pCipher == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto out; } break; case CK_IBM_ML_KEM_DECAPSULATE: encapsulate = FALSE; /* pCipher/ulCipherLen is input on decapsulate */ if (kem_params->pCipher == NULL || kem_params->ulCipherLen == 0) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto out; } break; default: TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto out; } if (kem_params->ulSharedDataLen > 0 && kem_params->pSharedData == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto out; } /* Optional shared data can only be provided together with a KDF */ if ((kem_params->kdf == CKD_NULL || kem_params->kdf == CKD_IBM_HYBRID_NULL) && (kem_params->pSharedData != NULL || kem_params->ulSharedDataLen != 0)) { TRACE_ERROR("No KDF specified, but shared data ptr is not NULL.\n"); rc = CKR_MECHANISM_PARAM_INVALID; goto out; } if (kem_params->ulPublicDataLen == 0 || kem_params->pPublicData == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto out; } /* Perform ECDH first */ rc = object_mgr_find_in_map1(tokdata, kem_params->hECPrivateKey, &ec_key_object, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to acquire EC private key from handle.\n"); if (rc == CKR_OBJECT_HANDLE_INVALID) rc = CKR_KEY_HANDLE_INVALID; goto out; } rc = ckm_ecdh_pkcs_derive(tokdata, sess, kem_params->pPublicData, kem_params->ulPublicDataLen, ec_key_object, ecdh_secret_z, &ecdh_secret_z_len, &ecdh_mech, FALSE); if (rc != CKR_OK) { TRACE_ERROR("ckm_ecdh_pkcs_derive failed\n"); goto out; } /* Perform KEM next */ rc = openssl_specific_pqc_perform_kem(oid, mech, base_key_object, base_key_class, encapsulate, kem_params->pCipher, &kem_params->ulCipherLen, &kem_secret_t, &kem_secret_t_len); if (rc != CKR_OK) { TRACE_ERROR("openssl_specific_pqc_perform_kem failed\n"); goto out; } /* concatenate secrets: Z' = Z || T */ hybrid_secret_len = ecdh_secret_z_len + kem_secret_t_len; hybrid_secret = malloc(hybrid_secret_len); if (hybrid_secret == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto out; } memcpy(hybrid_secret, ecdh_secret_z, ecdh_secret_z_len); memcpy(hybrid_secret + ecdh_secret_z_len, kem_secret_t, kem_secret_t_len); OPENSSL_cleanse(kem_secret_t, kem_secret_t_len); OPENSSL_cleanse(ecdh_secret_z, ecdh_secret_z_len); /* Apply KDF (if any) */ switch (kem_params->kdf) { case CKD_NULL: case CKD_IBM_HYBRID_NULL: value = hybrid_secret; value_len = hybrid_secret_len; if (value_len > derived_keylen) { value_len = derived_keylen; } else if (value_len < derived_keylen) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); rc = CKR_TEMPLATE_INCONSISTENT; goto out; } break; case CKD_SHA1_KDF: case CKD_SHA224_KDF: case CKD_SHA256_KDF: case CKD_SHA384_KDF: case CKD_SHA512_KDF: case CKD_SHA3_224_KDF: case CKD_SHA3_256_KDF: case CKD_SHA3_384_KDF: case CKD_SHA3_512_KDF: case CKD_IBM_HYBRID_SHA1_KDF: case CKD_IBM_HYBRID_SHA224_KDF: case CKD_IBM_HYBRID_SHA256_KDF: case CKD_IBM_HYBRID_SHA384_KDF: case CKD_IBM_HYBRID_SHA512_KDF: rc = digest_from_kdf(kem_params->kdf, &digest_mech); if (rc != CKR_OK) { TRACE_ERROR("Cannot determine mech from kdf.\n"); rc = CKR_MECHANISM_PARAM_INVALID; goto out; } rc = get_sha_size(digest_mech, &kdf_digest_len); if (rc != CKR_OK) { TRACE_ERROR("Cannot determine SHA digest size.\n"); rc = CKR_MECHANISM_PARAM_INVALID; goto out; } value_len = derived_keylen; /* ckm_kdf_X9_63() needs a buffer of multiple of kdf digest length */ derived_keylen = ((value_len / kdf_digest_len) + 1) * kdf_digest_len; value = malloc(derived_keylen); if (value == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto out; } value_allocated = TRUE; rc = ckm_kdf_X9_63(tokdata, sess, kem_params->kdf, kdf_digest_len, hybrid_secret, hybrid_secret_len, kem_params->pSharedData, kem_params->ulSharedDataLen, value, derived_keylen); if (rc != CKR_OK) { TRACE_ERROR("ckm_kdf_X9_63 failed\n"); goto out; } break; default: TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto out; } /* Update derived key value in target object */ rc = template_build_update_attribute(derived_key_object->template, CKA_VALUE, value, value_len); if (rc != CKR_OK) { TRACE_ERROR("template_build_update_attribute failed for CKA_VALUE, " "rc=0x%lx.\n", rc); goto out; } switch (derived_key_type) { case CKK_GENERIC_SECRET: case CKK_AES: case CKK_AES_XTS: /* Supply CKA_VALUE_LEN since this is required for those key types */ rc = template_build_update_attribute(derived_key_object->template, CKA_VALUE_LEN, (CK_BYTE*)&value_len, sizeof(value_len)); if (rc != CKR_OK) { TRACE_ERROR("template_build_update_attribute failed for " "CKA_VALUE_LEN, rc=0x%lx.\n", rc); goto out; } break; case CKK_DES: if (des_check_weak_key(hybrid_secret)) { TRACE_ERROR("Derived key is a weak DES key\n"); rc = CKR_FUNCTION_FAILED; goto out; } break; default: break; } out: if (kem_secret_t != NULL) { OPENSSL_cleanse(kem_secret_t, kem_secret_t_len); free(kem_secret_t); } if (hybrid_secret != NULL) { OPENSSL_cleanse(hybrid_secret, hybrid_secret_len); free(hybrid_secret); } if (value != NULL && value_allocated) { OPENSSL_cleanse(value, value_len); free(value); } if (ec_key_object != NULL) { object_put(tokdata, ec_key_object, TRUE); ec_key_object = NULL; } return rc; } CK_RV openssl_specific_pqc_kem_derive(STDLL_TokData_t *tokdata, SESSION *sess, const struct pqc_oid *oid, CK_MECHANISM *mech, OBJECT *base_key_object, CK_OBJECT_CLASS base_key_class, CK_KEY_TYPE base_key_type, OBJECT *derived_key_object, CK_KEY_TYPE derived_key_type, CK_ULONG derived_keylen) { switch (mech->mechanism) { case CKM_IBM_KYBER: case CKM_IBM_ML_KEM: return openssl_specific_pqc_kem(tokdata, sess, oid, mech, base_key_object, base_key_class, base_key_type, derived_key_object, derived_key_type, derived_keylen); case CKM_IBM_ML_KEM_WITH_ECDH: return openssl_specific_pqc_kem_with_ecdh(tokdata, sess, oid, mech, base_key_object, base_key_class, base_key_type, derived_key_object, derived_key_type, derived_keylen); default: return CKR_MECHANISM_INVALID; } } static CK_RV openssl_specific_pqc_en_decapsulate_key(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL encapsulate, CK_BBOOL length_only, const struct pqc_oid *oid, CK_MECHANISM *mech, OBJECT *key_obj, CK_ATTRIBUTE *pTemplate, CK_ULONG ulAttributeCount, CK_BYTE *pCiphertext, CK_ULONG *pulCiphertextLen, CK_KEY_TYPE keytype, CK_ULONG keylen, CK_OBJECT_HANDLE *phKey) { CK_RV rc = CKR_OK; CK_ULONG secret_len = 0; CK_BYTE *secret = NULL; OBJECT *new_key_obj = NULL; rc = object_mgr_create_skel(tokdata, sess, pTemplate, ulAttributeCount, encapsulate ? MODE_ENCAPS : MODE_DECAPS, CKO_SECRET_KEY, keytype, &new_key_obj); if (rc != CKR_OK) { TRACE_ERROR("Object Mgr create skeleton failed, rc=0x%lx.\n", rc); return rc; } rc = openssl_specific_pqc_perform_kem(oid, mech, key_obj, encapsulate ? CKO_PUBLIC_KEY : CKO_PRIVATE_KEY, encapsulate, pCiphertext, pulCiphertextLen, &secret, &secret_len); if (length_only && rc == CKR_BUFFER_TOO_SMALL) { rc = CKR_OK; goto out; } if (rc != CKR_OK) { TRACE_ERROR("openssl_specific_pqc_perform_kem failed\n"); goto out; } if (secret_len < keylen) { TRACE_ERROR("Cannot create a key longer that %lu bytes.\n", secret_len); rc = CKR_TEMPLATE_INCONSISTENT; goto out; } /* Update key value in new object */ rc = template_build_update_attribute(new_key_obj->template, CKA_VALUE, secret, keylen); if (rc != CKR_OK) { TRACE_ERROR("template_build_update_attribute failed for CKA_VALUE, " "rc=0x%lx.\n", rc); goto out; } switch (keytype) { case CKK_GENERIC_SECRET: case CKK_AES: case CKK_AES_XTS: /* Supply CKA_VALUE_LEN since this is required for those key types */ rc = template_build_update_attribute(new_key_obj->template, CKA_VALUE_LEN, (CK_BYTE*)&keylen, sizeof(keylen)); if (rc != CKR_OK) { TRACE_ERROR("template_build_update_attribute failed for " "CKA_VALUE_LEN, rc=0x%lx.\n", rc); goto out; } break; case CKK_DES: if (des_check_weak_key(secret)) { TRACE_ERROR("Derived key is a weak DES key\n"); rc = CKR_FUNCTION_FAILED; goto out; } break; default: break; } rc = object_mgr_create_final(tokdata, sess, new_key_obj, phKey); if (rc != CKR_OK) { TRACE_ERROR("Object Mgr create final failed, rc=0x%lx.\n", rc); goto out; } out: if (secret != NULL) { OPENSSL_cleanse(secret, secret_len); free(secret); } if ((rc != CKR_OK || length_only) && new_key_obj != NULL) { object_free(new_key_obj); if (phKey != NULL) *phKey = CK_INVALID_HANDLE; } return rc; } CK_RV openssl_specific_pqc_encapsulate_key(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, const struct pqc_oid *oid, CK_MECHANISM *mech, OBJECT *key_obj, CK_ATTRIBUTE *pTemplate, CK_ULONG ulAttributeCount, CK_BYTE *pCiphertext, CK_ULONG *pulCiphertextLen, CK_KEY_TYPE keytype, CK_ULONG keylen, CK_OBJECT_HANDLE *phKey) { return openssl_specific_pqc_en_decapsulate_key(tokdata, sess, TRUE, length_only, oid, mech, key_obj, pTemplate, ulAttributeCount, pCiphertext, pulCiphertextLen, keytype, keylen,phKey); } CK_RV openssl_specific_pqc_decapsulate_key(STDLL_TokData_t *tokdata, SESSION *sess, const struct pqc_oid *oid, CK_MECHANISM *mech, OBJECT *key_obj, CK_ATTRIBUTE *pTemplate, CK_ULONG ulAttributeCount, CK_BYTE *pCiphertext, CK_ULONG ulCiphertextLen, CK_KEY_TYPE keytype, CK_ULONG keylen, CK_OBJECT_HANDLE *phKey) { return openssl_specific_pqc_en_decapsulate_key(tokdata, sess, FALSE, FALSE, oid, mech, key_obj, pTemplate, ulAttributeCount, pCiphertext, &ulCiphertextLen, keytype, keylen, phKey); } #endif opencryptoki-opencryptoki-451d99c/usr/lib/common/mech_pqc.c000066400000000000000000002062241520105705100241240ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2024 * * 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" #include "defs.h" #include "host_defs.h" #include "h_extern.h" #include "tok_spec_struct.h" #include "trace.h" #include "attributes.h" CK_RV ckm_ibm_ml_dsa_key_pair_gen(STDLL_TokData_t *tokdata, CK_MECHANISM *mech, TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl) { const struct pqc_oid *pqc_oid; CK_RV rc; if (token_specific.t_ibm_ml_dsa_generate_keypair == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); return CKR_MECHANISM_INVALID; } pqc_oid = pqc_get_keyform_mode(publ_tmpl, mech->mechanism); if (pqc_oid == NULL) pqc_oid = pqc_get_keyform_mode(priv_tmpl, mech->mechanism); if (pqc_oid == NULL && mech->mechanism == CKM_IBM_DILITHIUM) pqc_oid = find_pqc_by_keyform(dilithium_oids, CK_IBM_DILITHIUM_KEYFORM_ROUND2_65); if (pqc_oid == NULL) { TRACE_ERROR("%s Failed to determine ML-DSA OID\n", __func__); return CKR_TEMPLATE_INCOMPLETE; } rc = token_specific.t_ibm_ml_dsa_generate_keypair(tokdata, mech, pqc_oid, publ_tmpl, priv_tmpl); if (rc != CKR_OK) TRACE_DEVEL("Token specific ML-DSA keypair generation failed.\n"); return rc; } CK_RV ibm_ml_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_OBJECT_CLASS class; const struct pqc_oid *oid; CK_RV rc; if (token_specific.t_ibm_ml_dsa_sign == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); return CKR_MECHANISM_INVALID; } 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\n"); if (rc == CKR_OBJECT_HANDLE_INVALID) return CKR_KEY_HANDLE_INVALID; else return rc; } rc = template_attribute_get_ulong(key_obj->template, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); goto done; } if (class != CKO_PRIVATE_KEY) { TRACE_ERROR("This operation requires a private key.\n"); rc = CKR_KEY_FUNCTION_NOT_PERMITTED; goto done; } oid = pqc_get_keyform_mode(key_obj->template, ctx->mech.mechanism); if (oid == NULL) { TRACE_DEVEL("No keyform/mode found in key object\n"); rc = CKR_TEMPLATE_INCOMPLETE; goto done; } rc = token_specific.t_ibm_ml_dsa_sign(tokdata, sess, length_only, oid, &ctx->mech, in_data, in_data_len, out_data, out_data_len, key_obj); if (rc != CKR_OK) TRACE_DEVEL("Token specific IBM ML-DSA sign failed.\n"); done: object_put(tokdata, key_obj, TRUE); key_obj = NULL; return rc; } CK_RV ibm_ml_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_OBJECT_CLASS class; const struct pqc_oid *oid; CK_RV rc; if (token_specific.t_ibm_ml_dsa_verify == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); return CKR_MECHANISM_INVALID; } 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\n"); if (rc == CKR_OBJECT_HANDLE_INVALID) return CKR_KEY_HANDLE_INVALID; else return rc; } rc = template_attribute_get_ulong(key_obj->template, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); goto done; } if (class != CKO_PUBLIC_KEY) { TRACE_ERROR("This operation requires a public key.\n"); rc = CKR_KEY_FUNCTION_NOT_PERMITTED; goto done; } oid = pqc_get_keyform_mode(key_obj->template, ctx->mech.mechanism); if (oid == NULL) { TRACE_DEVEL("No keyform/mode found in key object\n"); rc = CKR_TEMPLATE_INCOMPLETE; goto done; } rc = token_specific.t_ibm_ml_dsa_verify(tokdata, sess, oid, &ctx->mech, in_data, in_data_len, signature, sig_len, key_obj); if (rc != CKR_OK) TRACE_DEVEL("Token specific IBM ML-DSA verify failed.\n"); done: object_put(tokdata, key_obj, TRUE); key_obj = NULL; return rc; } CK_RV ckm_ibm_ml_kem_key_pair_gen(STDLL_TokData_t *tokdata, CK_MECHANISM *mech, TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl) { const struct pqc_oid *pqc_oid; CK_RV rc; if (token_specific.t_ibm_ml_kem_generate_keypair == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); return CKR_MECHANISM_INVALID; } pqc_oid = pqc_get_keyform_mode(publ_tmpl, mech->mechanism); if (pqc_oid == NULL) pqc_oid = pqc_get_keyform_mode(priv_tmpl, mech->mechanism); if (pqc_oid == NULL && mech->mechanism == CKM_IBM_KYBER) pqc_oid = find_pqc_by_keyform(kyber_oids, CK_IBM_KYBER_KEYFORM_ROUND2_1024); if (pqc_oid == NULL) { TRACE_ERROR("%s Failed to determine ML-KEM OID\n", __func__); return CKR_TEMPLATE_INCOMPLETE; } rc = token_specific.t_ibm_ml_kem_generate_keypair(tokdata, mech, pqc_oid, publ_tmpl, priv_tmpl); if (rc != CKR_OK) TRACE_DEVEL("Token specific ML-KEM keypair generation failed.\n"); return rc; } CK_RV ibm_ml_kem_derive(STDLL_TokData_t *tokdata, SESSION *sess, CK_MECHANISM *mech, OBJECT *base_key_obj, CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE *derived_key_handle) { const struct pqc_oid *oid; OBJECT *derived_key_obj = NULL; CK_ULONG allowed_keysize = 0; CK_ULONG derived_keytype = 0, derived_keylen = 0; CK_ULONG base_key_class, base_key_type; CK_RV rc; if (token_specific.t_ibm_ml_kem_derive == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); return CKR_MECHANISM_INVALID; } oid = pqc_get_keyform_mode(base_key_obj->template, mech->mechanism); if (oid == NULL) { TRACE_DEVEL("No keyform/mode found in key object\n"); return CKR_TEMPLATE_INCOMPLETE; } if (!template_get_class(base_key_obj->template, &base_key_class, &base_key_type)) { TRACE_ERROR("Could not find CKA_CLASS in the template\n"); return CKR_TEMPLATE_INCOMPLETE; } if (base_key_class != CKO_PRIVATE_KEY && base_key_class != CKO_PUBLIC_KEY) { TRACE_ERROR("Base key is not a private or public key\n"); return CKR_KEY_TYPE_INCONSISTENT; } rc = get_ulong_attribute_by_type(pTemplate, ulCount, CKA_VALUE_LEN, &derived_keylen); if (rc == CKR_ATTRIBUTE_VALUE_INVALID) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return rc; } rc = get_ulong_attribute_by_type(pTemplate, ulCount, CKA_KEY_TYPE, &derived_keytype); if (rc == CKR_ATTRIBUTE_VALUE_INVALID) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return rc; } /* * - no key length and no key type: CKR_TEMPLATE_INCOMPLETE * - no key type, but length given: CKK_GENERIC_SECRET of specified length. * - no key length but key type specified: key must have a well-defined * length, otherwise error. * - key length and key type specified: length must be compatible with key * type, otherwise error. */ if (derived_keytype == 0 && derived_keylen == 0) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); return CKR_TEMPLATE_INCOMPLETE; } if (derived_keytype == 0) derived_keytype = CKK_GENERIC_SECRET; switch (derived_keytype) { case CKK_GENERIC_SECRET: if (derived_keylen == 0) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); return CKR_TEMPLATE_INCONSISTENT; } allowed_keysize = derived_keylen; break; case CKK_DES: allowed_keysize = DES_KEY_SIZE; break; case CKK_DES2: allowed_keysize = 2 * DES_KEY_SIZE; break; case CKK_DES3: allowed_keysize = 3 * DES_KEY_SIZE; break; case CKK_AES: switch (derived_keylen) { case AES_KEY_SIZE_128: case AES_KEY_SIZE_192: case AES_KEY_SIZE_256: allowed_keysize = derived_keylen; break; default: TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); return CKR_TEMPLATE_INCONSISTENT; } break; case CKK_AES_XTS: switch (derived_keylen) { case 2 * AES_KEY_SIZE_128: case 2 * AES_KEY_SIZE_256: allowed_keysize = derived_keylen; break; default: TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); return CKR_TEMPLATE_INCONSISTENT; } break; default: TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); return CKR_TEMPLATE_INCONSISTENT; } if (derived_keylen == 0) derived_keylen = allowed_keysize; if (derived_keylen != allowed_keysize) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); return CKR_TEMPLATE_INCONSISTENT; } rc = object_mgr_create_skel(tokdata, sess, pTemplate, ulCount, MODE_DERIVE, CKO_SECRET_KEY, derived_keytype, &derived_key_obj); if (rc != CKR_OK) { TRACE_ERROR("Object Mgr create skeleton failed, rc=0x%lx.\n", rc); return rc; } rc = token_specific.t_ibm_ml_kem_derive(tokdata, sess, oid, mech, base_key_obj, base_key_class, base_key_type, derived_key_obj, derived_keytype, derived_keylen); if (rc != CKR_OK) { TRACE_DEVEL("Token specific ML-KEM derive failed.\n"); goto end; } rc = object_mgr_create_final(tokdata, sess, derived_key_obj, derived_key_handle); if (rc != CKR_OK) { TRACE_ERROR("Object Mgr create final failed, rc=0x%lx.\n", rc); goto end; } INC_COUNTER(tokdata, sess, mech, base_key_obj, POLICY_STRENGTH_IDX_0); rc = CKR_OK; end: if (rc != CKR_OK && derived_key_obj != NULL) { object_free(derived_key_obj); derived_key_handle = CK_INVALID_HANDLE; } return rc; } CK_RV ckm_ml_dsa_key_pair_gen(STDLL_TokData_t *tokdata, TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl) { const struct pqc_oid *pqc_oid; CK_RV rc; if (token_specific.t_ml_dsa_generate_keypair == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); return CKR_MECHANISM_INVALID; } pqc_oid = pqc_get_keyform_mode(publ_tmpl, CKM_ML_DSA_KEY_PAIR_GEN); if (pqc_oid == NULL) { TRACE_ERROR("%s Failed to determine ML-DSA OID\n", __func__); return CKR_TEMPLATE_INCOMPLETE; } rc = token_specific.t_ml_dsa_generate_keypair(tokdata, pqc_oid, publ_tmpl, priv_tmpl); if (rc != CKR_OK) TRACE_DEVEL("Token specific ML-DSA keypair generation failed.\n"); return rc; } CK_RV ckm_ml_kem_key_pair_gen(STDLL_TokData_t *tokdata, TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl) { const struct pqc_oid *pqc_oid; CK_RV rc; if (token_specific.t_ml_kem_generate_keypair == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); return CKR_MECHANISM_INVALID; } pqc_oid = pqc_get_keyform_mode(publ_tmpl, CKM_ML_KEM_KEY_PAIR_GEN); if (pqc_oid == NULL) { TRACE_ERROR("%s Failed to determine ML-KEM OID\n", __func__); return CKR_TEMPLATE_INCOMPLETE; } rc = token_specific.t_ml_kem_generate_keypair(tokdata, pqc_oid, publ_tmpl, priv_tmpl); if (rc != CKR_OK) TRACE_DEVEL("Token specific ML-KEM keypair generation failed.\n"); return rc; } static CK_RV ml_dsa_setup_digest_mech(CK_MECHANISM *digest_mech, CK_ULONG *hlen) { CK_RV rc; switch(digest_mech->mechanism) { case CKM_OCK_SHAKE128: *hlen = SHA3_256_HASH_SIZE; digest_mech->ulParameterLen = sizeof(*hlen); digest_mech->pParameter = hlen; break; case CKM_OCK_SHAKE256: *hlen = SHA3_512_HASH_SIZE; digest_mech->ulParameterLen = sizeof(*hlen); digest_mech->pParameter = hlen; break; default: digest_mech->ulParameterLen = 0; digest_mech->pParameter = NULL; rc = get_sha_size(digest_mech->mechanism, hlen); if (rc != CKR_OK) { TRACE_DEVEL("Get SHA Size failed.\n"); return rc; } break; } return CKR_OK; } static CK_RV ml_dsa_get_digest_mech(CK_MECHANISM *ml_dsa_mech, CK_MECHANISM_TYPE *digest_mech) { CK_RV rc; if (ml_dsa_mech->mechanism == CKM_HASH_ML_DSA) { if (ml_dsa_mech->ulParameterLen != sizeof(CK_HASH_SIGN_ADDITIONAL_CONTEXT) || ml_dsa_mech->pParameter == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); return CKR_MECHANISM_PARAM_INVALID; } *digest_mech = ((CK_HASH_SIGN_ADDITIONAL_CONTEXT *)ml_dsa_mech->pParameter)->hash; } else { if (ml_dsa_mech->ulParameterLen != sizeof(CK_SIGN_ADDITIONAL_CONTEXT) && ml_dsa_mech->ulParameterLen != 0) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); return CKR_MECHANISM_PARAM_INVALID; } if (ml_dsa_mech->ulParameterLen != 0 && ml_dsa_mech->pParameter == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); return CKR_MECHANISM_PARAM_INVALID; } rc = get_digest_from_mech(ml_dsa_mech->mechanism, digest_mech); if (rc != CKR_OK) { TRACE_ERROR("%s get_digest_from_mech failed\n", __func__); return rc; } } return CKR_OK; } CK_RV ml_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_BBOOL final_part) { OBJECT *key_obj = NULL; CK_OBJECT_CLASS class; const struct pqc_oid *oid; CK_RV rc; if (token_specific.t_ml_dsa_sign == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); return CKR_MECHANISM_INVALID; } 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\n"); if (rc == CKR_OBJECT_HANDLE_INVALID) return CKR_KEY_HANDLE_INVALID; else return rc; } rc = template_attribute_get_ulong(key_obj->template, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); goto done; } if (class != CKO_PRIVATE_KEY) { TRACE_ERROR("This operation requires a private key.\n"); rc = CKR_KEY_FUNCTION_NOT_PERMITTED; goto done; } oid = pqc_get_keyform_mode(key_obj->template, ctx->mech.mechanism); if (oid == NULL) { TRACE_DEVEL("No keyform/mode found in key object\n"); rc = CKR_TEMPLATE_INCOMPLETE; goto done; } rc = token_specific.t_ml_dsa_sign(tokdata, sess, length_only, oid, &ctx->mech, in_data, in_data_len, signature, sig_len, key_obj, final_part); if (rc != CKR_OK) TRACE_DEVEL("Token specific ML-DSA sign failed.\n"); done: object_put(tokdata, key_obj, TRUE); key_obj = NULL; return rc; } CK_RV ml_dsa_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_HASH_SIGN_ADDITIONAL_CONTEXT hash_sign_param = { 0 }; SIGN_VERIFY_CONTEXT sign_ctx; CK_BYTE hash[MAX_SHA_HASH_SIZE]; CK_BYTE *hash_tbs; DIGEST_CONTEXT digest_ctx = { 0 }; CK_MECHANISM digest_mech; CK_ULONG hash_len; CK_RV rc; if (sess == NULL || ctx == NULL || in_data == NULL) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } rc = ml_dsa_get_digest_mech(&ctx->mech, &digest_mech.mechanism); if (rc != CKR_OK) { TRACE_DEVEL("ml_dsa_get_digest_mech failed.\n"); return rc; } rc = ml_dsa_setup_digest_mech(&digest_mech, &hash_len); if (rc != CKR_OK) { TRACE_DEVEL("ml_dsa_setup_digest_mech failed.\n"); return rc; } sign_ctx = *ctx; if (ctx->mech.mechanism == CKM_HASH_ML_DSA) { /* Input is the already hashed message PH */ if (in_data_len != hash_len) { TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); return CKR_DATA_LEN_RANGE; } hash_tbs = in_data; } else { rc = digest_mgr_init(tokdata, sess, &digest_ctx, &digest_mech, FALSE); 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"); digest_mgr_cleanup(tokdata, sess, &digest_ctx); return rc; } hash_tbs = hash; /* Translate to CKM_HASH_ML_DSA mechanism */ sign_ctx.mech.mechanism = CKM_HASH_ML_DSA; sign_ctx.mech.pParameter = &hash_sign_param; sign_ctx.mech.ulParameterLen = sizeof(hash_sign_param); rc = ml_dsa_translate_hash_sign_mech_param_from_sign( ctx->mech.pParameter, &hash_sign_param, digest_mech.mechanism); if (rc != CKR_OK) { TRACE_DEVEL("ml_dsa_translate_hash_sign_mech_param_from_sign" " failed.\n"); return rc; } } rc = ml_dsa_sign(tokdata, sess, length_only, &sign_ctx, hash_tbs, hash_len, signature, sig_len, TRUE); if (rc != CKR_OK) TRACE_DEVEL("ml_dsa_sign failed.\n"); return rc; } CK_RV ml_dsa_hash_sign_verify_update(STDLL_TokData_t *tokdata, SESSION *sess, SIGN_VERIFY_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len) { MP_DIGEST_CONTEXT *context = NULL; CK_MECHANISM digest_mech; CK_ULONG output_len; CK_RV rc; if (sess == NULL || ctx == NULL) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } context = (MP_DIGEST_CONTEXT *)ctx->context; if (context->flag == FALSE) { rc = get_digest_from_mech(ctx->mech.mechanism, &digest_mech.mechanism); if (rc != CKR_OK) { TRACE_ERROR("%s get_digest_from_mech failed\n", __func__); return rc; } rc = ml_dsa_setup_digest_mech(&digest_mech, &output_len); if (rc != CKR_OK) { TRACE_DEVEL("ml_dsa_setup_digest_mech failed.\n"); return rc; } rc = digest_mgr_init(tokdata, sess, &context->hash_context, &digest_mech, FALSE); if (rc != CKR_OK) { TRACE_DEVEL("Digest Mgr Init failed.\n"); return rc; } context->flag = TRUE; ctx->state_unsaveable |= context->hash_context.state_unsaveable; } 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 ml_dsa_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_HASH_SIGN_ADDITIONAL_CONTEXT hash_sign_param = { 0 }; SIGN_VERIFY_CONTEXT sign_ctx; CK_BYTE hash[MAX_SHA_HASH_SIZE]; MP_DIGEST_CONTEXT *context = NULL; CK_MECHANISM digest_mech; CK_ULONG hash_len; CK_RV rc; if (sess == NULL || ctx == NULL || sig_len == NULL) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } if (ctx->mech.ulParameterLen != sizeof(CK_SIGN_ADDITIONAL_CONTEXT) && ctx->mech.ulParameterLen != 0) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); return CKR_MECHANISM_PARAM_INVALID; } if (ctx->mech.ulParameterLen != 0 && ctx->mech.pParameter == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); return CKR_MECHANISM_PARAM_INVALID; } context = (MP_DIGEST_CONTEXT *)ctx->context; if (context->flag == FALSE) { rc = ml_dsa_hash_sign_verify_update(tokdata, sess, ctx, NULL, 0); TRACE_DEVEL("ml_dsa_hash_sign_verify_update\n"); if (rc != 0) return rc; } digest_mech = context->hash_context.mech; rc = ml_dsa_setup_digest_mech(&digest_mech, &hash_len); if (rc != CKR_OK) { TRACE_DEVEL("ml_dsa_setup_digest_mech 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; } /* Translate to CKM_HASH_ML_DSA mechanism */ sign_ctx = *ctx; sign_ctx.mech.mechanism = CKM_HASH_ML_DSA; sign_ctx.mech.pParameter = &hash_sign_param; sign_ctx.mech.ulParameterLen = sizeof(hash_sign_param); rc = ml_dsa_translate_hash_sign_mech_param_from_sign( ctx->mech.pParameter, &hash_sign_param, digest_mech.mechanism); if (rc != CKR_OK) { TRACE_DEVEL("ml_dsa_translate_hash_sign_mech_param_from_sign" " failed.\n"); return rc; } rc = ml_dsa_sign(tokdata, sess, length_only, &sign_ctx, hash, hash_len, signature, sig_len, TRUE); if (rc != CKR_OK) TRACE_DEVEL("ml_dsa_sign failed.\n"); return rc; } CK_RV ml_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, CK_BBOOL final_part) { OBJECT *key_obj = NULL; CK_OBJECT_CLASS class; const struct pqc_oid *oid; CK_RV rc; if (token_specific.t_ml_dsa_verify == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); return CKR_MECHANISM_INVALID; } 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\n"); if (rc == CKR_OBJECT_HANDLE_INVALID) return CKR_KEY_HANDLE_INVALID; else return rc; } rc = template_attribute_get_ulong(key_obj->template, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); goto done; } if (class != CKO_PUBLIC_KEY) { TRACE_ERROR("This operation requires a public key.\n"); rc = CKR_KEY_FUNCTION_NOT_PERMITTED; goto done; } oid = pqc_get_keyform_mode(key_obj->template, ctx->mech.mechanism); if (oid == NULL) { TRACE_DEVEL("No keyform/mode found in key object\n"); rc = CKR_TEMPLATE_INCOMPLETE; goto done; } rc = token_specific.t_ml_dsa_verify(tokdata, sess, oid, &ctx->mech, in_data, in_data_len, signature, sig_len, key_obj, final_part); if (rc != CKR_OK) TRACE_DEVEL("Token specific ML-DSA verify failed.\n"); done: object_put(tokdata, key_obj, TRUE); key_obj = NULL; return rc; } CK_RV ml_dsa_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_HASH_SIGN_ADDITIONAL_CONTEXT hash_verify_param = { 0 }; SIGN_VERIFY_CONTEXT verify_ctx; CK_BYTE hash[MAX_SHA_HASH_SIZE]; CK_BYTE *hash_tbv = hash; DIGEST_CONTEXT digest_ctx = { 0 }; CK_MECHANISM digest_mech; CK_ULONG hash_len; CK_RV rc; if (sess == NULL || ctx == NULL || in_data == NULL) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } rc = ml_dsa_get_digest_mech(&ctx->mech, &digest_mech.mechanism); if (rc != CKR_OK) { TRACE_DEVEL("ml_dsa_get_digest_mech failed.\n"); return rc; } rc = ml_dsa_setup_digest_mech(&digest_mech, &hash_len); if (rc != CKR_OK) { TRACE_DEVEL("ml_dsa_setup_digest_mech failed.\n"); return rc; } verify_ctx = *ctx; if (ctx->mech.mechanism == CKM_HASH_ML_DSA) { /* Input is the already hashed message PH */ if (in_data_len != hash_len) { TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); return CKR_DATA_LEN_RANGE; } hash_tbv = in_data; } else { rc = digest_mgr_init(tokdata, sess, &digest_ctx, &digest_mech, FALSE); 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"); digest_mgr_cleanup(tokdata, sess, &digest_ctx); return rc; } hash_tbv = hash; /* Translate to CKM_HASH_ML_DSA mechanism */ verify_ctx.mech.mechanism = CKM_HASH_ML_DSA; verify_ctx.mech.pParameter = &hash_verify_param; verify_ctx.mech.ulParameterLen = sizeof(hash_verify_param); rc = ml_dsa_translate_hash_sign_mech_param_from_sign( ctx->mech.pParameter, &hash_verify_param, digest_mech.mechanism); if (rc != CKR_OK) { TRACE_DEVEL("ml_dsa_translate_hash_sign_mech_param_from_sign" " failed.\n"); return rc; } } rc = ml_dsa_verify(tokdata, sess, &verify_ctx, hash_tbv, hash_len, signature, sig_len, TRUE); if (rc != CKR_OK) TRACE_DEVEL("ml_dsa_verify failed.\n"); return rc; } CK_RV ml_dsa_hash_verify_final(STDLL_TokData_t *tokdata, SESSION *sess, SIGN_VERIFY_CONTEXT *ctx, CK_BYTE *signature, CK_ULONG sig_len) { CK_HASH_SIGN_ADDITIONAL_CONTEXT hash_verify_param = { 0 }; SIGN_VERIFY_CONTEXT verify_ctx; CK_BYTE hash[MAX_SHA_HASH_SIZE]; MP_DIGEST_CONTEXT *context = NULL; CK_MECHANISM digest_mech; CK_ULONG hash_len; CK_RV rc; if (sess == NULL || ctx == NULL || signature == NULL) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } if (ctx->mech.ulParameterLen != sizeof(CK_SIGN_ADDITIONAL_CONTEXT) && ctx->mech.ulParameterLen != 0) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); return CKR_MECHANISM_PARAM_INVALID; } if (ctx->mech.ulParameterLen != 0 && ctx->mech.pParameter == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); return CKR_MECHANISM_PARAM_INVALID; } context = (MP_DIGEST_CONTEXT *)ctx->context; if (context->flag == FALSE) { rc = ml_dsa_hash_sign_verify_update(tokdata, sess, ctx, NULL, 0); TRACE_DEVEL("ml_dsa_hash_sign_verify_update\n"); if (rc != 0) return rc; } digest_mech = context->hash_context.mech; rc = ml_dsa_setup_digest_mech(&digest_mech, &hash_len); if (rc != CKR_OK) { TRACE_DEVEL("ml_dsa_setup_digest_mech 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; } /* Translate to CKM_HASH_ML_DSA mechanism */ verify_ctx = *ctx; verify_ctx.mech.mechanism = CKM_HASH_ML_DSA; verify_ctx.mech.pParameter = &hash_verify_param; verify_ctx.mech.ulParameterLen = sizeof(hash_verify_param); rc = ml_dsa_translate_hash_sign_mech_param_from_sign( ctx->mech.pParameter, &hash_verify_param, digest_mech.mechanism); if (rc != CKR_OK) { TRACE_DEVEL("ml_dsa_translate_hash_sign_mech_param_from_sign" " failed.\n"); return rc; } rc = ml_dsa_verify(tokdata, sess, &verify_ctx, hash, hash_len, signature, sig_len, TRUE); if (rc != CKR_OK) TRACE_DEVEL("ml_dsa_sign failed.\n"); return rc; } static CK_RV ml_kem_get_key_type_key_len(CK_ATTRIBUTE *pTemplate, CK_ULONG ulAttributeCount, CK_KEY_TYPE *key_type, CK_ULONG *key_len) { CK_ULONG allowed_keylen; CK_RV rc; *key_len = 0; rc = get_ulong_attribute_by_type(pTemplate, ulAttributeCount, CKA_VALUE_LEN, key_len); if (rc == CKR_ATTRIBUTE_VALUE_INVALID) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return rc; } *key_type = 0; rc = get_ulong_attribute_by_type(pTemplate, ulAttributeCount, CKA_KEY_TYPE, key_type); if (rc == CKR_ATTRIBUTE_VALUE_INVALID) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return rc; } /* * - no key length and no key type: CKR_TEMPLATE_INCOMPLETE * - no key type, but length given: CKK_GENERIC_SECRET of specified length. * - no key length but key type specified: key must have a well-defined * length, otherwise error. * - key length and key type specified: length must be compatible with key * type, otherwise error. */ if (*key_type == 0 && *key_len == 0) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); return CKR_TEMPLATE_INCOMPLETE; } if (*key_type == 0) *key_type = CKK_GENERIC_SECRET; switch (*key_type) { case CKK_GENERIC_SECRET: if (*key_len == 0) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); return CKR_TEMPLATE_INCONSISTENT; } allowed_keylen = *key_len; break; case CKK_DES: allowed_keylen = DES_KEY_SIZE; break; case CKK_DES2: allowed_keylen = 2 * DES_KEY_SIZE; break; case CKK_DES3: allowed_keylen = 3 * DES_KEY_SIZE; break; case CKK_AES: switch (*key_len) { case AES_KEY_SIZE_128: case AES_KEY_SIZE_192: case AES_KEY_SIZE_256: allowed_keylen = *key_len; break; default: TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); return CKR_TEMPLATE_INCONSISTENT; } break; case CKK_AES_XTS: switch (*key_len) { case 2 * AES_KEY_SIZE_128: case 2 * AES_KEY_SIZE_256: allowed_keylen = *key_len; break; default: TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); return CKR_TEMPLATE_INCONSISTENT; } break; default: TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); return CKR_TEMPLATE_INCONSISTENT; } if (*key_len == 0) *key_len = allowed_keylen; if (*key_len != allowed_keylen) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); return CKR_TEMPLATE_INCONSISTENT; } if (*key_len > 32) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); return CKR_TEMPLATE_INCONSISTENT; } return CKR_OK; } CK_RV ml_kem_encapsulate_key(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, CK_MECHANISM *mech, OBJECT *public_key, CK_ATTRIBUTE *pTemplate, CK_ULONG ulAttributeCount, CK_BYTE *pCiphertext, CK_ULONG *pulCiphertextLen, CK_OBJECT_HANDLE *phKey) { CK_OBJECT_CLASS class; CK_KEY_TYPE keytype; CK_ULONG keylen; const struct pqc_oid *oid; CK_RV rc; if (token_specific.t_ml_kem_encapsulate_key == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); return CKR_MECHANISM_INVALID; } rc = template_attribute_get_ulong(public_key->template, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); return rc; } if (class != CKO_PUBLIC_KEY) { TRACE_ERROR("This operation requires a public key.\n"); return CKR_KEY_FUNCTION_NOT_PERMITTED; } rc = template_attribute_get_ulong(public_key->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); return rc; } switch (mech->mechanism) { case CKM_ML_KEM: if (keytype != CKK_ML_KEM) { TRACE_ERROR("This operation requires a ML-KEM key.\n"); return CKR_KEY_FUNCTION_NOT_PERMITTED; } if (mech->ulParameterLen != 0 || mech->pParameter != NULL) { 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; } oid = pqc_get_keyform_mode(public_key->template, mech->mechanism); if (oid == NULL) { TRACE_DEVEL("No keyform/mode found in key object\n"); return CKR_TEMPLATE_INCOMPLETE; } rc = ml_kem_get_key_type_key_len(pTemplate, ulAttributeCount, &keytype, &keylen); if (rc != CKR_OK) { TRACE_DEVEL("ml_kem_get_key_type_key_len failed.\n"); return rc; } rc = token_specific.t_ml_kem_encapsulate_key(tokdata, sess, length_only, oid, mech, public_key, pTemplate, ulAttributeCount, pCiphertext, pulCiphertextLen, keytype, keylen, phKey); if (rc != CKR_OK) { TRACE_DEVEL("Token specific ML-KEM encapsulate failed.\n"); return rc; } return CKR_OK; } CK_RV ml_kem_decapsulate_key(STDLL_TokData_t *tokdata, SESSION *sess, CK_MECHANISM *mech, OBJECT *private_key, CK_ATTRIBUTE *pTemplate, CK_ULONG ulAttributeCount, CK_BYTE *pCiphertext, CK_ULONG ulCiphertextLen, CK_OBJECT_HANDLE *phKey) { CK_OBJECT_CLASS class; CK_KEY_TYPE keytype; CK_ULONG keylen; const struct pqc_oid *oid; CK_RV rc; if (token_specific.t_ml_kem_decapsulate_key == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); return CKR_MECHANISM_INVALID; } rc = template_attribute_get_ulong(private_key->template, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); return rc; } if (class != CKO_PRIVATE_KEY) { TRACE_ERROR("This operation requires a private key.\n"); return CKR_KEY_FUNCTION_NOT_PERMITTED; } rc = template_attribute_get_ulong(private_key->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); return rc; } switch (mech->mechanism) { case CKM_ML_KEM: if (keytype != CKK_ML_KEM) { TRACE_ERROR("This operation requires a ML-KEM key.\n"); return CKR_KEY_FUNCTION_NOT_PERMITTED; } if (mech->ulParameterLen != 0 || mech->pParameter != NULL) { 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; } oid = pqc_get_keyform_mode(private_key->template, mech->mechanism); if (oid == NULL) { TRACE_DEVEL("No keyform/mode found in key object\n"); return CKR_TEMPLATE_INCOMPLETE; } rc = ml_kem_get_key_type_key_len(pTemplate, ulAttributeCount, &keytype, &keylen); if (rc != CKR_OK) { TRACE_DEVEL("ml_kem_get_key_type_key_len failed.\n"); return rc; } rc = token_specific.t_ml_kem_decapsulate_key(tokdata, sess, oid, mech, private_key, pTemplate, ulAttributeCount, pCiphertext, ulCiphertextLen, keytype, keylen, phKey); if (rc != CKR_OK) { TRACE_DEVEL("Token specific ML-KEM decapsulate failed.\n"); return rc; } return CKR_OK; } #define PACK_PART(attr, explen, buf, buflen, ofs) \ if ((attr)->ulValueLen != (explen)) { \ TRACE_ERROR("Key part #attr length not as expected\n"); \ return CKR_ATTRIBUTE_VALUE_INVALID; \ } \ if ((ofs) + (attr)->ulValueLen > (buflen)) { \ TRACE_ERROR("Buffer is too small\n"); \ return CKR_BUFFER_TOO_SMALL; \ } \ memcpy(&(buf)[(ofs)], (attr)->pValue, (attr)->ulValueLen); \ (ofs) += (attr)->ulValueLen #define UNPACK_PART(attr, attr_type, len, buf, buflen, ofs, rc, label) \ if ((ofs) + (len) > (buflen)) { \ TRACE_ERROR("Buffer is too small\n"); \ (rc) = CKR_BUFFER_TOO_SMALL; \ goto label; \ } \ (rc) = build_attribute(attr_type, &(buf)[(ofs)], (len), &(attr)); \ if ((rc) != CKR_OK) { \ TRACE_ERROR("build_attribute for #attr failed\n"); \ goto label; \ } \ (ofs) += (len); static CK_RV ibm_ml_dsa_pack_priv_key(TEMPLATE *templ, const struct pqc_oid *oid, CK_MECHANISM_TYPE mech, CK_BYTE *priv, CK_ULONG *priv_len) { CK_ATTRIBUTE *rho = NULL, *seed = NULL; CK_ATTRIBUTE *tr = NULL, *s1 = NULL, *s2 = NULL; CK_ATTRIBUTE *t0 = NULL; CK_ULONG ofs = 0; CK_RV rc; UNUSED(mech); if (priv == NULL) { *priv_len = oid->len_info.ml_dsa.rho_len + oid->len_info.ml_dsa.seed_len + oid->len_info.ml_dsa.tr_len + oid->len_info.ml_dsa.s1_len + oid->len_info.ml_dsa.s2_len + oid->len_info.ml_dsa.t0_len; return CKR_OK; } rc = template_attribute_get_non_empty(templ, CKA_IBM_ML_DSA_RHO, &rho); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_ML_DSA_RHO for the key.\n"); return rc; } rc = template_attribute_get_non_empty(templ, CKA_IBM_ML_DSA_SEED, &seed); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_ML_DSA_SEED for the key.\n"); return rc; } rc = template_attribute_get_non_empty(templ, CKA_IBM_ML_DSA_TR, &tr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_ML_DSA_TR for the key.\n"); return rc; } rc = template_attribute_get_non_empty(templ, CKA_IBM_ML_DSA_S1, &s1); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_ML_DSA_S1 for the key.\n"); return rc; } rc = template_attribute_get_non_empty(templ, CKA_IBM_ML_DSA_S2, &s2); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_ML_DSA_S2 for the key.\n"); return rc; } rc = template_attribute_get_non_empty(templ, CKA_IBM_ML_DSA_T0, &t0); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_ML_DSA_T0 for the key.\n"); return rc; } PACK_PART(rho, oid->len_info.ml_dsa.rho_len, priv, *priv_len, ofs); PACK_PART(seed, oid->len_info.ml_dsa.seed_len, priv, *priv_len, ofs); PACK_PART(tr, oid->len_info.ml_dsa.tr_len, priv, *priv_len, ofs); PACK_PART(s1, oid->len_info.ml_dsa.s1_len, priv, *priv_len, ofs); PACK_PART(s2, oid->len_info.ml_dsa.s2_len, priv, *priv_len, ofs); PACK_PART(t0, oid->len_info.ml_dsa.t0_len, priv, *priv_len, ofs); *priv_len = ofs; return CKR_OK; } static CK_RV ibm_ml_dsa_pack_pub_key(TEMPLATE *templ, const struct pqc_oid *oid, CK_MECHANISM_TYPE mech, CK_BYTE *pub, CK_ULONG *pub_len) { CK_ATTRIBUTE *rho = NULL, *t1 = NULL; CK_ULONG ofs = 0; CK_RV rc; UNUSED(mech); if (pub == NULL) { *pub_len = oid->len_info.ml_dsa.rho_len + oid->len_info.ml_dsa.t1_len; return CKR_OK; } rc = template_attribute_get_non_empty(templ, CKA_IBM_ML_DSA_RHO, &rho); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_ML_DSA_RHO for the key.\n"); return rc; } rc = template_attribute_get_non_empty(templ, CKA_IBM_ML_DSA_T1, &t1); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_ML_DSA_T1 for the key.\n"); return rc; } PACK_PART(rho, oid->len_info.ml_dsa.rho_len, pub, *pub_len, ofs); PACK_PART(t1, oid->len_info.ml_dsa.t1_len, pub, *pub_len, ofs); *pub_len = ofs; return CKR_OK; } static CK_RV ibm_ml_dsa_unpack_priv_key(CK_BYTE *priv, CK_ULONG priv_len, const struct pqc_oid *oid, CK_MECHANISM_TYPE mech, TEMPLATE *templ) { CK_ATTRIBUTE *rho = NULL, *seed = NULL; CK_ATTRIBUTE *tr = NULL, *s1 = NULL, *s2 = NULL; CK_ATTRIBUTE *t0 = NULL; CK_ULONG ofs = 0; CK_RV rc; UNUSED(mech); UNPACK_PART(rho, CKA_IBM_ML_DSA_RHO, oid->len_info.ml_dsa.rho_len, priv, priv_len, ofs, rc, out); UNPACK_PART(seed, CKA_IBM_ML_DSA_SEED, oid->len_info.ml_dsa.seed_len, priv, priv_len, ofs, rc, out); UNPACK_PART(tr, CKA_IBM_ML_DSA_TR, oid->len_info.ml_dsa.tr_len, priv, priv_len, ofs, rc, out); UNPACK_PART(s1, CKA_IBM_ML_DSA_S1, oid->len_info.ml_dsa.s1_len, priv, priv_len, ofs, rc, out); UNPACK_PART(s2, CKA_IBM_ML_DSA_S2, oid->len_info.ml_dsa.s2_len, priv, priv_len, ofs, rc, out); UNPACK_PART(t0, CKA_IBM_ML_DSA_T0, oid->len_info.ml_dsa.t0_len, priv, priv_len, ofs, rc, out); rc = template_update_attribute(templ, rho); if (rc != CKR_OK) { TRACE_DEVEL("Template update for CKA_IBM_ML_DSA_RHO failed\n"); goto out; } rho = NULL; rc = template_update_attribute(templ, seed); if (rc != CKR_OK) { TRACE_DEVEL("Template update for CKA_IBM_ML_DSA_SEED failed\n"); goto out; } seed = NULL; rc = template_update_attribute(templ, tr); if (rc != CKR_OK) { TRACE_DEVEL("Template update for CKA_IBM_ML_DSA_TR failed\n"); goto out; } tr = NULL; rc = template_update_attribute(templ, s1); if (rc != CKR_OK) { TRACE_DEVEL("Template update for CKA_IBM_ML_DSA_S1 failed\n"); goto out; } s1 = NULL; rc = template_update_attribute(templ, s2); if (rc != CKR_OK) { TRACE_DEVEL("Template update for CKA_IBM_ML_DSA_S2 failed\n"); goto out; } s2 = NULL; rc = template_update_attribute(templ, t0); if (rc != CKR_OK) { TRACE_DEVEL("Template update for CKA_IBM_ML_DSA_T0 failed\n"); goto out; } t0 = NULL; out: if (rho != NULL) free(rho); if (seed != NULL) free(seed); if (tr != NULL) free(tr); if (s1 != NULL) free(s1); if (s2 != NULL) free(s2); if (t0 != NULL) free(t0); return rc; } static CK_RV ibm_ml_dsa_unpack_pub_key(CK_BYTE *pub, CK_ULONG pub_len, const struct pqc_oid *oid, CK_MECHANISM_TYPE mech, TEMPLATE *templ) { CK_ATTRIBUTE *rho = NULL, *t1 = NULL; CK_ULONG ofs = 0; CK_RV rc; UNUSED(mech); UNPACK_PART(rho, CKA_IBM_ML_DSA_RHO, oid->len_info.ml_dsa.rho_len, pub, pub_len, ofs, rc, out); UNPACK_PART(t1, CKA_IBM_ML_DSA_T1, oid->len_info.ml_dsa.t1_len, pub, pub_len, ofs, rc, out); rc = template_update_attribute(templ, rho); if (rc != CKR_OK) { TRACE_DEVEL("Template update for CKA_IBM_ML_DSA_RHO failed\n"); goto out; } rho = NULL; rc = template_update_attribute(templ, t1); if (rc != CKR_OK) { TRACE_DEVEL("Template update for CKA_IBM_ML_DSA_T1 failed\n"); goto out; } t1 = NULL; out: if (rho != NULL) free(rho); if (t1 != NULL) free(t1); return rc; } static CK_RV ibm_ml_kem_pack_priv_key(TEMPLATE *templ, const struct pqc_oid *oid, CK_MECHANISM_TYPE mech, CK_BYTE *priv, CK_ULONG *priv_len) { CK_ATTRIBUTE *sk = NULL; CK_ULONG ofs = 0; CK_RV rc; UNUSED(mech); if (priv == NULL) { *priv_len = oid->len_info.ml_kem.sk_len; return CKR_OK; } rc = template_attribute_get_non_empty(templ, CKA_IBM_ML_KEM_SK, &sk); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_ML_KEM_SK for the key.\n"); return rc; } PACK_PART(sk, oid->len_info.ml_kem.sk_len, priv, *priv_len, ofs); *priv_len = ofs; return CKR_OK; } static CK_RV ibm_ml_kem_pack_pub_key(TEMPLATE *templ, const struct pqc_oid *oid, CK_MECHANISM_TYPE mech, CK_BYTE *pub, CK_ULONG *pub_len) { CK_ATTRIBUTE *pk = NULL; CK_ULONG ofs = 0; CK_RV rc; UNUSED(mech); if (pub == NULL) { *pub_len = oid->len_info.ml_kem.pk_len; return CKR_OK; } rc = template_attribute_get_non_empty(templ, CKA_IBM_ML_KEM_PK, &pk); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_ML_KEM_PK for the key.\n"); return rc; } PACK_PART(pk, oid->len_info.ml_kem.pk_len, pub, *pub_len, ofs); *pub_len = ofs; return CKR_OK; } static CK_RV ibm_ml_kem_unpack_priv_key(CK_BYTE *priv, CK_ULONG priv_len, const struct pqc_oid *oid, CK_MECHANISM_TYPE mech, TEMPLATE *templ) { CK_ATTRIBUTE *sk = NULL; CK_ULONG ofs = 0; CK_RV rc; UNUSED(mech); UNPACK_PART(sk, CKA_IBM_ML_KEM_SK, oid->len_info.ml_kem.sk_len, priv, priv_len, ofs, rc, out); rc = template_update_attribute(templ, sk); if (rc != CKR_OK) { TRACE_DEVEL("Template update for CKA_IBM_ML_KEM_SK failed\n"); goto out; } sk = NULL; out: if (sk != NULL) free(sk); return rc; } static CK_RV ibm_ml_kem_unpack_pub_key(CK_BYTE *pub, CK_ULONG pub_len, const struct pqc_oid *oid, CK_MECHANISM_TYPE mech, TEMPLATE *templ) { CK_ATTRIBUTE *pk = NULL; CK_ULONG ofs = 0; CK_RV rc; UNUSED(mech); UNPACK_PART(pk, CKA_IBM_ML_KEM_PK, oid->len_info.ml_kem.pk_len, pub, pub_len, ofs, rc, out); rc = template_update_attribute(templ, pk); if (rc != CKR_OK) { TRACE_DEVEL("Template update for CKA_IBM_ML_KEM_PK failed\n"); goto out; } pk = NULL; out: if (pk != NULL) free(pk); return rc; } static CK_RV ml_dsa_pack_priv_key(TEMPLATE *templ, const struct pqc_oid *oid, CK_BYTE *priv, CK_ULONG *priv_len) { CK_ATTRIBUTE *value = NULL; CK_ULONG ofs = 0; CK_RV rc; if (priv == NULL) { *priv_len = oid->len_info.ml_dsa.rho_len + oid->len_info.ml_dsa.seed_len + oid->len_info.ml_dsa.tr_len + oid->len_info.ml_dsa.s1_len + oid->len_info.ml_dsa.s2_len + oid->len_info.ml_dsa.t0_len; return CKR_OK; } rc = template_attribute_get_non_empty(templ, CKA_VALUE, &value); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); return rc; } PACK_PART(value, oid->len_info.ml_dsa.rho_len + oid->len_info.ml_dsa.seed_len + oid->len_info.ml_dsa.tr_len + oid->len_info.ml_dsa.s1_len + oid->len_info.ml_dsa.s2_len + oid->len_info.ml_dsa.t0_len, priv, *priv_len, ofs); *priv_len = ofs; return CKR_OK; } static CK_RV ml_dsa_pack_pub_key(TEMPLATE *templ, const struct pqc_oid *oid, CK_BYTE *pub, CK_ULONG *pub_len) { CK_ATTRIBUTE *value = NULL; CK_ULONG ofs = 0; CK_RV rc; if (pub == NULL) { *pub_len = oid->len_info.ml_dsa.rho_len + oid->len_info.ml_dsa.t1_len; return CKR_OK; } rc = template_attribute_get_non_empty(templ, CKA_VALUE, &value); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); return rc; } PACK_PART(value, oid->len_info.ml_dsa.rho_len + oid->len_info.ml_dsa.t1_len, pub, *pub_len, ofs); *pub_len = ofs; return CKR_OK; } static CK_RV ml_dsa_unpack_priv_key(CK_BYTE *priv, CK_ULONG priv_len, const struct pqc_oid *oid, TEMPLATE *templ) { CK_ATTRIBUTE *value = NULL; CK_ULONG ofs = 0; CK_RV rc; UNPACK_PART(value, CKA_VALUE, oid->len_info.ml_dsa.rho_len + oid->len_info.ml_dsa.seed_len + oid->len_info.ml_dsa.tr_len + oid->len_info.ml_dsa.s1_len + oid->len_info.ml_dsa.s2_len + oid->len_info.ml_dsa.t0_len, priv, priv_len, ofs, rc, out); rc = template_update_attribute(templ, value); if (rc != CKR_OK) { TRACE_DEVEL("Template update for CKA_VALUE failed\n"); goto out; } value = NULL; out: if (value != NULL) free(value); return rc; } static CK_RV ml_dsa_unpack_pub_key(CK_BYTE *pub, CK_ULONG pub_len, const struct pqc_oid *oid, TEMPLATE *templ) { CK_ATTRIBUTE *value = NULL; CK_ULONG ofs = 0; CK_RV rc; UNPACK_PART(value, CKA_VALUE, oid->len_info.ml_dsa.rho_len + oid->len_info.ml_dsa.t1_len, pub, pub_len, ofs, rc, out); rc = template_update_attribute(templ, value); if (rc != CKR_OK) { TRACE_DEVEL("Template update for CKA_VALUE failed\n"); goto out; } value = NULL; out: if (value != NULL) free(value); return rc; } static CK_RV ml_kem_pack_priv_key(TEMPLATE *templ, const struct pqc_oid *oid, CK_BYTE *priv, CK_ULONG *priv_len) { CK_ATTRIBUTE *value = NULL; CK_ULONG ofs = 0; CK_RV rc; if (priv == NULL) { *priv_len = oid->len_info.ml_kem.sk_len; return CKR_OK; } rc = template_attribute_get_non_empty(templ, CKA_VALUE, &value); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); return rc; } PACK_PART(value, oid->len_info.ml_kem.sk_len, priv, *priv_len, ofs); *priv_len = ofs; return CKR_OK; } static CK_RV ml_kem_pack_pub_key(TEMPLATE *templ, const struct pqc_oid *oid, CK_BYTE *pub, CK_ULONG *pub_len) { CK_ATTRIBUTE *value = NULL; CK_ULONG ofs = 0; CK_RV rc; if (pub == NULL) { *pub_len = oid->len_info.ml_kem.pk_len; return CKR_OK; } rc = template_attribute_get_non_empty(templ, CKA_VALUE, &value); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); return rc; } PACK_PART(value, oid->len_info.ml_kem.pk_len, pub, *pub_len, ofs); *pub_len = ofs; return CKR_OK; } static CK_RV ml_kem_unpack_priv_key(CK_BYTE *priv, CK_ULONG priv_len, const struct pqc_oid *oid, TEMPLATE *templ) { CK_ATTRIBUTE *value = NULL; CK_ULONG ofs = 0; CK_RV rc; UNPACK_PART(value, CKA_VALUE, oid->len_info.ml_kem.sk_len, priv, priv_len, ofs, rc, out); rc = template_update_attribute(templ, value); if (rc != CKR_OK) { TRACE_DEVEL("Template update for CKA_VALUE failed\n"); goto out; } value = NULL; out: if (value != NULL) free(value); return rc; } static CK_RV ml_kem_unpack_pub_key(CK_BYTE *pub, CK_ULONG pub_len, const struct pqc_oid *oid, TEMPLATE *templ) { CK_ATTRIBUTE *value = NULL; CK_ULONG ofs = 0; CK_RV rc; UNPACK_PART(value, CKA_VALUE, oid->len_info.ml_kem.pk_len, pub, pub_len, ofs, rc, out); rc = template_update_attribute(templ, value); if (rc != CKR_OK) { TRACE_DEVEL("Template update for CKA_VALUE failed\n"); goto out; } value = NULL; out: if (value != NULL) free(value); return rc; } #undef PACK_PART #undef UNPACK_PART CK_RV pqc_pack_priv_key(TEMPLATE *templ, const struct pqc_oid *oid, CK_MECHANISM_TYPE mech, CK_BYTE *priv, CK_ULONG *priv_len) { switch(mech) { case CKM_IBM_DILITHIUM: case CKM_IBM_ML_DSA: case CKM_IBM_ML_DSA_KEY_PAIR_GEN: return ibm_ml_dsa_pack_priv_key(templ, oid, mech, priv, priv_len); case CKM_IBM_ML_KEM: case CKM_IBM_ML_KEM_KEY_PAIR_GEN: case CKM_IBM_ML_KEM_WITH_ECDH: return ibm_ml_kem_pack_priv_key(templ, oid, mech, priv, priv_len); case CKM_ML_DSA: case CKM_ML_DSA_KEY_PAIR_GEN: case CKM_HASH_ML_DSA: return ml_dsa_pack_priv_key(templ, oid, priv, priv_len); case CKM_ML_KEM: case CKM_ML_KEM_KEY_PAIR_GEN: return ml_kem_pack_priv_key(templ, oid, priv, priv_len); default: return CKR_MECHANISM_INVALID; } } CK_RV pqc_pack_pub_key(TEMPLATE *templ, const struct pqc_oid *oid, CK_MECHANISM_TYPE mech, CK_BYTE *pub, CK_ULONG *pub_len) { switch(mech) { case CKM_IBM_DILITHIUM: case CKM_IBM_ML_DSA: case CKM_IBM_ML_DSA_KEY_PAIR_GEN: return ibm_ml_dsa_pack_pub_key(templ, oid, mech, pub, pub_len); case CKM_IBM_ML_KEM: case CKM_IBM_ML_KEM_KEY_PAIR_GEN: case CKM_IBM_ML_KEM_WITH_ECDH: return ibm_ml_kem_pack_pub_key(templ, oid, mech, pub, pub_len); case CKM_ML_DSA: case CKM_ML_DSA_KEY_PAIR_GEN: case CKM_HASH_ML_DSA: return ml_dsa_pack_pub_key(templ, oid, pub, pub_len); case CKM_ML_KEM: case CKM_ML_KEM_KEY_PAIR_GEN: return ml_kem_pack_pub_key(templ, oid, pub, pub_len); default: return CKR_MECHANISM_INVALID; } } CK_RV pqc_unpack_priv_key(CK_BYTE *priv, CK_ULONG priv_len, const struct pqc_oid *oid, CK_MECHANISM_TYPE mech, TEMPLATE *templ) { switch(mech) { case CKM_IBM_DILITHIUM: case CKM_IBM_ML_DSA: case CKM_IBM_ML_DSA_KEY_PAIR_GEN: return ibm_ml_dsa_unpack_priv_key(priv, priv_len, oid, mech, templ); case CKM_IBM_ML_KEM: case CKM_IBM_ML_KEM_KEY_PAIR_GEN: case CKM_IBM_ML_KEM_WITH_ECDH: return ibm_ml_kem_unpack_priv_key(priv, priv_len, oid, mech, templ); case CKM_ML_DSA: case CKM_ML_DSA_KEY_PAIR_GEN: case CKM_HASH_ML_DSA: return ml_dsa_unpack_priv_key(priv, priv_len, oid, templ); case CKM_ML_KEM: case CKM_ML_KEM_KEY_PAIR_GEN: return ml_kem_unpack_priv_key(priv, priv_len, oid, templ); default: return CKR_MECHANISM_INVALID; } } CK_RV pqc_unpack_pub_key(CK_BYTE *pub, CK_ULONG pub_len, const struct pqc_oid *oid, CK_MECHANISM_TYPE mech, TEMPLATE *templ) { switch(mech) { case CKM_IBM_DILITHIUM: case CKM_IBM_ML_DSA: case CKM_IBM_ML_DSA_KEY_PAIR_GEN: return ibm_ml_dsa_unpack_pub_key(pub, pub_len, oid, mech, templ); case CKM_IBM_ML_KEM: case CKM_IBM_ML_KEM_KEY_PAIR_GEN: case CKM_IBM_ML_KEM_WITH_ECDH: return ibm_ml_kem_unpack_pub_key(pub, pub_len, oid, mech, templ); case CKM_ML_DSA: case CKM_ML_DSA_KEY_PAIR_GEN: case CKM_HASH_ML_DSA: return ml_dsa_unpack_pub_key(pub, pub_len, oid, templ); case CKM_ML_KEM: case CKM_ML_KEM_KEY_PAIR_GEN: return ml_kem_unpack_pub_key(pub, pub_len, oid, templ); default: return CKR_MECHANISM_INVALID; } } CK_RV ibm_ml_dsa_dup_param(CK_VOID_PTR src, CK_VOID_PTR dst, CK_ULONG len) { CK_IBM_SIGN_ADDITIONAL_CONTEXT *param_src = src; CK_IBM_SIGN_ADDITIONAL_CONTEXT *param_dst = dst; if (param_src == NULL || len == 0) return CKR_OK; if (len != sizeof(CK_IBM_SIGN_ADDITIONAL_CONTEXT)) return CKR_MECHANISM_PARAM_INVALID; if(param_src->pContext == NULL || param_src->ulContextLen == 0) return CKR_OK; if (param_dst == NULL) return CKR_ARGUMENTS_BAD; param_dst->pContext = malloc(param_src->ulContextLen); if (param_dst->pContext == NULL) { TRACE_ERROR("%s Memory allocation failed\n", __func__); return CKR_HOST_MEMORY; } memcpy(param_dst->pContext, param_src->pContext, param_src->ulContextLen); param_dst->ulContextLen = param_src->ulContextLen; return CKR_OK; } CK_RV ibm_ml_dsa_free_param(CK_VOID_PTR p, CK_ULONG len) { CK_IBM_SIGN_ADDITIONAL_CONTEXT *param = p; if (param == NULL || len == 0) return CKR_OK; if (len != sizeof(CK_IBM_SIGN_ADDITIONAL_CONTEXT)) return CKR_MECHANISM_PARAM_INVALID; if (param->pContext != NULL) free(param->pContext); memset(param, 0, sizeof(*param)); return CKR_OK; } CK_RV ml_dsa_dup_param(CK_VOID_PTR src, CK_VOID_PTR dst, CK_ULONG len) { CK_SIGN_ADDITIONAL_CONTEXT *param_src = src; CK_SIGN_ADDITIONAL_CONTEXT *param_dst = dst; if (param_src == NULL || len == 0) return CKR_OK; if (len != sizeof(CK_SIGN_ADDITIONAL_CONTEXT)) return CKR_MECHANISM_PARAM_INVALID; if(param_src->pContext == NULL || param_src->ulContextLen == 0) return CKR_OK; if (param_dst == NULL) return CKR_ARGUMENTS_BAD; param_dst->pContext = malloc(param_src->ulContextLen); if (param_dst->pContext == NULL) { TRACE_ERROR("%s Memory allocation failed\n", __func__); return CKR_HOST_MEMORY; } memcpy(param_dst->pContext, param_src->pContext, param_src->ulContextLen); param_dst->ulContextLen = param_src->ulContextLen; return CKR_OK; } CK_RV ml_dsa_free_param(CK_VOID_PTR p, CK_ULONG len) { CK_SIGN_ADDITIONAL_CONTEXT *param = p; if (param == NULL || len == 0) return CKR_OK; if (len != sizeof(CK_SIGN_ADDITIONAL_CONTEXT)) return CKR_MECHANISM_PARAM_INVALID; if (param->pContext != NULL) free(param->pContext); memset(param, 0, sizeof(*param)); return CKR_OK; } CK_RV ml_dsa_hash_dup_param(CK_VOID_PTR src, CK_VOID_PTR dst, CK_ULONG len) { CK_HASH_SIGN_ADDITIONAL_CONTEXT *param_src = src; CK_HASH_SIGN_ADDITIONAL_CONTEXT *param_dst = dst; if (param_src == NULL || len == 0) return CKR_MECHANISM_PARAM_INVALID; if (len != sizeof(CK_HASH_SIGN_ADDITIONAL_CONTEXT)) return CKR_MECHANISM_PARAM_INVALID; if(param_src->pContext == NULL || param_src->ulContextLen == 0) return CKR_OK; if (param_dst == NULL) return CKR_ARGUMENTS_BAD; param_dst->pContext = malloc(param_src->ulContextLen); if (param_dst->pContext == NULL) { TRACE_ERROR("%s Memory allocation failed\n", __func__); return CKR_HOST_MEMORY; } memcpy(param_dst->pContext, param_src->pContext, param_src->ulContextLen); param_dst->ulContextLen = param_src->ulContextLen; return CKR_OK; } CK_RV ml_dsa_hash_free_param(CK_VOID_PTR p, CK_ULONG len) { CK_HASH_SIGN_ADDITIONAL_CONTEXT *param = p; if (param == NULL || len == 0) return CKR_MECHANISM_PARAM_INVALID; if (len != sizeof(CK_HASH_SIGN_ADDITIONAL_CONTEXT)) return CKR_MECHANISM_PARAM_INVALID; if (param->pContext != NULL) free(param->pContext); memset(param, 0, sizeof(*param)); return CKR_OK; } CK_RV ml_dsa_translate_sign_mech_param_from_ibm( CK_IBM_SIGN_ADDITIONAL_CONTEXT *from, CK_SIGN_ADDITIONAL_CONTEXT *to) { if (to == NULL) return CKR_ARGUMENTS_BAD; if (from != NULL) { switch (from->hedgeVariant) { case CKH_IBM_HEDGE_PREFERRED: to->hedgeVariant = CKH_HEDGE_PREFERRED; break; case CKH_IBM_HEDGE_REQUIRED: to->hedgeVariant = CKH_HEDGE_REQUIRED; break; case CKH_IBM_DETERMINISTIC_REQUIRED: to->hedgeVariant = CKH_DETERMINISTIC_REQUIRED; break; default: TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); return CKR_MECHANISM_PARAM_INVALID; } to->pContext = from->pContext; to->ulContextLen = from->ulContextLen; } else { to->hedgeVariant = CKH_HEDGE_PREFERRED; to->pContext = NULL; to->ulContextLen = 0; } return CKR_OK; } CK_RV ml_dsa_translate_ibm_sign_mech_param_from_sign( CK_SIGN_ADDITIONAL_CONTEXT *from, CK_IBM_SIGN_ADDITIONAL_CONTEXT *to) { if (to == NULL) return CKR_ARGUMENTS_BAD; if (from != NULL) { switch (from->hedgeVariant) { case CKH_HEDGE_PREFERRED: to->hedgeVariant = CKH_IBM_HEDGE_PREFERRED; break; case CKH_HEDGE_REQUIRED: to->hedgeVariant = CKH_IBM_HEDGE_REQUIRED; break; case CKH_DETERMINISTIC_REQUIRED: to->hedgeVariant = CKH_IBM_DETERMINISTIC_REQUIRED; break; default: TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); return CKR_MECHANISM_PARAM_INVALID; } to->pContext = from->pContext; to->ulContextLen = from->ulContextLen; } else { to->hedgeVariant = CKH_IBM_HEDGE_PREFERRED; to->pContext = NULL; to->ulContextLen = 0; } return CKR_OK; } CK_RV ml_dsa_translate_sign_mech_param_from_hash( CK_HASH_SIGN_ADDITIONAL_CONTEXT *from, CK_SIGN_ADDITIONAL_CONTEXT *to, CK_MECHANISM_TYPE *hash_mech) { if (to == NULL || from == NULL) return CKR_ARGUMENTS_BAD; to->hedgeVariant = from->hedgeVariant; to->pContext = from->pContext; to->ulContextLen = from->ulContextLen; if (hash_mech != NULL) *hash_mech = from->hash; return CKR_OK; } CK_RV ml_dsa_translate_hash_sign_mech_param_from_sign( CK_SIGN_ADDITIONAL_CONTEXT *from, CK_HASH_SIGN_ADDITIONAL_CONTEXT *to, CK_MECHANISM_TYPE hash_mech) { if (to == NULL) return CKR_ARGUMENTS_BAD; if (from != NULL) { to->hedgeVariant = from->hedgeVariant; to->pContext = from->pContext; to->ulContextLen = from->ulContextLen; } else { to->hedgeVariant = CKH_HEDGE_PREFERRED; to->pContext = NULL; to->ulContextLen = 0; } to->hash = hash_mech; return CKR_OK; } opencryptoki-opencryptoki-451d99c/usr/lib/common/mech_rng.c000066400000000000000000000034531520105705100241260ustar00rootroot00000000000000/* * 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); if (rlen <= 0) { close(ranfd); return CKR_FUNCTION_FAILED; } 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; } opencryptoki-opencryptoki-451d99c/usr/lib/common/mech_rsa.c000066400000000000000000003313421520105705100241260ustar00rootroot00000000000000/* * 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 "constant_time.h" #include "p11util.h" #include "attributes.h" #include #include CK_BBOOL is_rsa_mechanism(CK_MECHANISM_TYPE mech) { switch (mech) { case CKM_RSA_9796: case CKM_RSA_PKCS: case CKM_MD2_RSA_PKCS: case CKM_MD5_RSA_PKCS: case CKM_SHA1_RSA_PKCS: case CKM_SHA224_RSA_PKCS: case CKM_SHA256_RSA_PKCS: case CKM_SHA384_RSA_PKCS: case CKM_SHA512_RSA_PKCS: case CKM_SHA3_224_RSA_PKCS: case CKM_SHA3_256_RSA_PKCS: case CKM_SHA3_384_RSA_PKCS: case CKM_SHA3_512_RSA_PKCS: case CKM_RSA_PKCS_PSS: case CKM_SHA1_RSA_PKCS_PSS: case CKM_SHA224_RSA_PKCS_PSS: case CKM_SHA256_RSA_PKCS_PSS: case CKM_SHA384_RSA_PKCS_PSS: case CKM_SHA512_RSA_PKCS_PSS: case CKM_SHA3_224_RSA_PKCS_PSS: case CKM_SHA3_256_RSA_PKCS_PSS: case CKM_SHA3_384_RSA_PKCS_PSS: case CKM_SHA3_512_RSA_PKCS_PSS: case CKM_RSA_PKCS_OAEP: case CKM_RSA_X_509: case CKM_RSA_X9_31: case CKM_SHA1_RSA_X9_31: return TRUE; } return FALSE; } CK_RV rsa_get_key_info(OBJECT *key_obj, CK_ULONG *mod_bytes, CK_OBJECT_CLASS *keyclass) { CK_RV rc; CK_ATTRIBUTE *attr; rc = template_attribute_get_non_empty(key_obj->template, CKA_MODULUS, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_MODULUS in the template\n"); return rc; } *mod_bytes = attr->ulValueLen; rc = template_attribute_get_ulong(key_obj->template, CKA_CLASS, keyclass); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS in the template\n"); return rc; } 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. */ static CK_RV rsa_parse_block_type_1(CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len) { CK_ULONG i; CK_RV rc = CKR_OK; int found = 0; 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) PKCS_BT_1) { TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_INVALID)); return CKR_ENCRYPTED_DATA_INVALID; } /* * The block type shall be a single octet indicating the structure of the * encryption block. It shall have value 01. For a private-key * operation, the block type shall be 01. * * For block type 01, they shall have value FF. * * For block type 01, the encryption block can be parsed * unambiguously since the padding string contains no octets with value 00 * and the padding string is separated from the data by an octet with * value 00. */ for (i = 2; i <= (in_data_len - 2); i++) { if (in_data[i] != (CK_BYTE) 0xff) { if (in_data[i] == (CK_BYTE) 0) { i++; found = 1; break; } TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_INVALID)); return CKR_ENCRYPTED_DATA_INVALID; } } if (!found) i++; /* * For block type 01, the padding string is at least eight octets * long, which is a security condition for public-key operations that * prevents an attacker from recoving data by trying all possible * encryption blocks. */ if ((i - 3) < 8) { TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_INVALID)); return CKR_ENCRYPTED_DATA_INVALID; } if (in_data_len < 2) { 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; } #define MAX_LEN_GEN_TRIES 128 static CK_RV rsa_parse_block_type_2(CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, CK_BYTE *kdk, CK_ULONG kdklen) { unsigned int good = 0, found_zero_byte, equals0; size_t zero_index = 0, msg_index; unsigned char *synthetic = NULL; int synthetic_length; uint16_t len_candidate; unsigned char candidate_lengths[MAX_LEN_GEN_TRIES * sizeof(len_candidate)]; uint16_t len_mask; uint16_t max_sep_offset; int synth_msg_index = 0; size_t i, j; CK_RV rc; if (kdk == NULL || kdklen == 0) { TRACE_DEVEL("%s\n", ock_err(ERR_ARGUMENTS_BAD)); return CKR_ARGUMENTS_BAD; } /* * The implementation of this function is copied from OpenSSL's function * ossl_rsa_padding_check_PKCS1_type_2() in crypto/rsa/rsa_pk1.c * and is slightly modified to fit to the OpenCryptoki environment. * * The OpenSSL code is licensed under the Apache License 2.0. * You can obtain a copy in the file LICENSE in the OpenSSL source * distribution or at https://www.openssl.org/source/license.html * * Changes include: * - Different variable, function and define names. * - Usage of TRACE_ERROR to report errors and issue debug messages. * - Different return codes. */ /* * The format is * 00 || BT || PS || 00 || D * BT - block type * PS - padding string, at least 8 bytes of random non-zero data for BT = 2 * D - data. */ /* * PKCS#1 v1.5 decryption. See "PKCS #1 v2.2: RSA Cryptography Standard", * section 7.2.2. */ if (in_data_len < RSA_PKCS1_PADDING_SIZE) { TRACE_DEVEL("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } /* Generate a random message to return in case the padding checks fail. */ synthetic = calloc(1, in_data_len); if (synthetic == NULL) { TRACE_ERROR("Failed to allocate synthetic buffer"); return CKR_HOST_MEMORY; } rc = openssl_specific_rsa_prf(synthetic, in_data_len, "message", 7, kdk, kdklen, in_data_len * 8); if (rc != CKR_OK) goto out; /* decide how long the random message should be */ rc = openssl_specific_rsa_prf(candidate_lengths, sizeof(candidate_lengths), "length", 6, kdk, kdklen, MAX_LEN_GEN_TRIES * sizeof(len_candidate) * 8); if (rc != CKR_OK) goto out; /* * max message size is the size of the modulus size minus 2 bytes for * version and padding type and a minimum of 8 bytes padding */ len_mask = max_sep_offset = in_data_len - 2 - 8; /* * we want a mask so let's propagate the high bit to all positions less * significant than it */ len_mask |= len_mask >> 1; len_mask |= len_mask >> 2; len_mask |= len_mask >> 4; len_mask |= len_mask >> 8; synthetic_length = 0; for (i = 0; i < MAX_LEN_GEN_TRIES * (int)sizeof(len_candidate); i += sizeof(len_candidate)) { len_candidate = (candidate_lengths[i] << 8) | candidate_lengths[i + 1]; len_candidate &= len_mask; synthetic_length = constant_time_select_int( constant_time_lt(len_candidate, max_sep_offset), len_candidate, synthetic_length); } synth_msg_index = in_data_len - synthetic_length; good = constant_time_is_zero(in_data[0]); good &= constant_time_eq(in_data[1], 2); /* scan over padding data */ found_zero_byte = 0; for (i = 2; i < in_data_len; i++) { equals0 = constant_time_is_zero(in_data[i]); zero_index = constant_time_select_int(~found_zero_byte & equals0, i, zero_index); found_zero_byte |= equals0; } /* * PS must be at least 8 bytes long, and it starts two bytes into |in_data|. * If we never found a 0-byte, then |zero_index| is 0 and the check * also fails. */ good &= constant_time_ge(zero_index, 2 + 8); /* * Skip the zero byte. This is incorrect if we never found a zero-byte * but in this case we also do not copy the message out. */ msg_index = zero_index + 1; /* * old code returned an error in case the decrypted message wouldn't fit * into the |out_data|, since that would leak information, return the * synthetic message instead */ good &= constant_time_ge(*out_data_len, in_data_len - msg_index); msg_index = constant_time_select_int(good, msg_index, synth_msg_index); /* * since at this point the |msg_index| does not provide the signal * indicating if the padding check failed or not, we don't have to worry * about leaking the length of returned message, we still need to ensure * that we read contents of both buffers so that cache accesses don't leak * the value of |good| */ for (i = msg_index, j = 0; i < in_data_len && j < *out_data_len; i++, j++) out_data[j] = constant_time_select_8(good, in_data[i], synthetic[i]); *out_data_len = j; out: if (synthetic != NULL) free(synthetic); return rc; } 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_BYTE *kdk, CK_ULONG kdklen) { switch (type) { case PKCS_BT_1: return rsa_parse_block_type_1(in_data, in_data_len, out_data, out_data_len); case PKCS_BT_2: return rsa_parse_block_type_2(in_data, in_data_len, out_data, out_data_len, kdk, kdklen); } return CKR_ARGUMENTS_BAD; } // // 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.\n"); 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.\n"); 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); rc = constant_time_select_int(constant_time_eq(rc, CKR_DATA_LEN_RANGE), CKR_ENCRYPTED_DATA_INVALID, rc); done: object_put(tokdata, key_obj, TRUE); 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.\n"); 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; } /* * 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; } 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; } } 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; } /* 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; } /* Release obj lock, token specific rsa-oaep may re-acquire the lock */ object_put(tokdata, key_obj, TRUE); key_obj = NULL; 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; } /* Release obj lock, token specific rsa-oaep may re-acquire the lock */ object_put(tokdata, key_obj, TRUE); key_obj = NULL; 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.\n"); 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.\n"); 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.\n"); 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.\n"); 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.\n"); 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.\n"); 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.\n"); 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.\n"); 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.\n"); 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(ERR_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; } /* Release obj lock, token specific rsa_pss may re-acquire the lock */ object_put(tokdata, key_obj, TRUE); key_obj = NULL; 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.\n"); 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; } /* Release obj lock, token specific rsa_pss may re-acquire the lock */ object_put(tokdata, key_obj, TRUE); key_obj = NULL; 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)); rc = get_digest_from_mech(ctx->mech.mechanism, &digest_mech.mechanism); if (rc != CKR_OK) { TRACE_ERROR("%s get_digest_from_mech failed\n", __func__); return rc; } 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, FALSE); 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"); digest_mgr_cleanup(tokdata, sess, &digest_ctx); 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, FALSE, FALSE); 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(tokdata, sess, &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) { rc = get_digest_from_mech(ctx->mech.mechanism, &digest_mech.mechanism); if (rc != CKR_OK) { TRACE_ERROR("%s get_digest_from_mech failed\n", __func__); return rc; } digest_mech.ulParameterLen = 0; digest_mech.pParameter = NULL; rc = digest_mgr_init(tokdata, sess, digest_ctx, &digest_mech, FALSE); if (rc != CKR_OK) { TRACE_DEVEL("Digest Mgr Init failed.\n"); return rc; } ctx->state_unsaveable |= digest_ctx->state_unsaveable; } 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; if (digest_ctx->active == FALSE) { rc = rsa_hash_pss_update(tokdata, sess, ctx, NULL, 0); TRACE_DEVEL("rsa_hash_pss_update\n"); if (rc != 0) return rc; } 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, FALSE, FALSE); 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(tokdata, sess, &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)); rc = get_digest_from_mech(ctx->mech.mechanism, &digest_mech.mechanism); if (rc != CKR_OK) { TRACE_ERROR("%s get_digest_from_mech failed\n", __func__); return rc; } 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, FALSE); 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"); digest_mgr_cleanup(tokdata, sess, &digest_ctx); 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, FALSE); 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(tokdata, sess, &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; if (digest_ctx->active == FALSE) { rc = rsa_hash_pss_update(tokdata, sess, ctx, NULL, 0); TRACE_DEVEL("rsa_hash_pss_update\n"); if (rc != 0) return rc; } 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, FALSE); 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(tokdata, sess, &verify_ctx); return rc; } static CK_RV rsa_pkcs_alg_oid_from_mech(CK_MECHANISM_TYPE mech, const CK_BYTE **oid, CK_ULONG *oid_len) { switch (mech) { #if !(NOMD2) case CKM_MD2_RSA_PKCS: *oid = ber_AlgMd2; *oid_len = ber_AlgMd2Len; break; #endif case CKM_MD5_RSA_PKCS: *oid = ber_AlgMd5; *oid_len = ber_AlgMd5Len; break; case CKM_SHA1_RSA_PKCS: *oid = ber_AlgSha1; *oid_len = ber_AlgSha1Len; break; case CKM_SHA224_RSA_PKCS: *oid = ber_AlgSha224; *oid_len = ber_AlgSha224Len; break; case CKM_SHA256_RSA_PKCS: *oid = ber_AlgSha256; *oid_len = ber_AlgSha256Len; break; case CKM_SHA384_RSA_PKCS: *oid = ber_AlgSha384; *oid_len = ber_AlgSha384Len; break; case CKM_SHA512_RSA_PKCS: *oid = ber_AlgSha512; *oid_len = ber_AlgSha512Len; break; case CKM_SHA3_224_RSA_PKCS: *oid = ber_AlgSha3_224; *oid_len = ber_AlgSha3_224Len; break; case CKM_SHA3_256_RSA_PKCS: *oid = ber_AlgSha3_256; *oid_len = ber_AlgSha3_256Len; break; case CKM_SHA3_384_RSA_PKCS: *oid = ber_AlgSha3_384; *oid_len = ber_AlgSha3_384Len; break; case CKM_SHA3_512_RSA_PKCS: *oid = ber_AlgSha3_512; *oid_len = ber_AlgSha3_512Len; break; default: return CKR_MECHANISM_INVALID; } return CKR_OK; } // // 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)); rc = get_digest_from_mech(ctx->mech.mechanism, &digest_mech.mechanism); if (rc != CKR_OK) { TRACE_ERROR("%s get_digest_from_mech failed\n", __func__); return rc; } digest_mech.ulParameterLen = 0; digest_mech.pParameter = NULL; rc = rsa_pkcs_alg_oid_from_mech(ctx->mech.mechanism, &oid, &oid_len); if (rc != CKR_OK) { TRACE_ERROR("%s rsa_pkcs_alg_oid_from_mech failed\n", __func__); return rc; } rc = digest_mgr_init(tokdata, sess, &digest_ctx, &digest_mech, FALSE); 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"); digest_mgr_cleanup(tokdata, sess, &digest_ctx); 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, FALSE, FALSE); 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(tokdata, sess, &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) { MP_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 = (MP_DIGEST_CONTEXT *) ctx->context; if (context->flag == FALSE) { rc = get_digest_from_mech(ctx->mech.mechanism, &digest_mech.mechanism); if (rc != CKR_OK) { TRACE_ERROR("%s get_digest_from_mech failed\n", __func__); return rc; } digest_mech.ulParameterLen = 0; digest_mech.pParameter = NULL; rc = digest_mgr_init(tokdata, sess, &context->hash_context, &digest_mech, FALSE); if (rc != CKR_OK) { TRACE_DEVEL("Digest Mgr Init failed.\n"); return rc; } context->flag = TRUE; ctx->state_unsaveable |= context->hash_context.state_unsaveable; } 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)); rc = get_digest_from_mech(ctx->mech.mechanism, &digest_mech.mechanism); if (rc != CKR_OK) { TRACE_ERROR("%s get_digest_from_mech failed\n", __func__); return rc; } digest_mech.ulParameterLen = 0; digest_mech.pParameter = NULL; rc = rsa_pkcs_alg_oid_from_mech(ctx->mech.mechanism, &oid, &oid_len); if (rc != CKR_OK) { TRACE_ERROR("%s rsa_pkcs_alg_oid_from_mech failed\n", __func__); return rc; } rc = digest_mgr_init(tokdata, sess, &digest_ctx, &digest_mech, FALSE); 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"); digest_mgr_cleanup(tokdata, sess, &digest_ctx); 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, FALSE); 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(tokdata, sess, &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) { MP_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 = (MP_DIGEST_CONTEXT *) ctx->context; if (context->flag == FALSE) { rc = get_digest_from_mech(ctx->mech.mechanism, &digest_mech.mechanism); if (rc != CKR_OK) { TRACE_ERROR("%s get_digest_from_mech failed\n", __func__); return rc; } digest_mech.ulParameterLen = 0; digest_mech.pParameter = NULL; rc = digest_mgr_init(tokdata, sess, &context->hash_context, &digest_mech, FALSE); if (rc != CKR_OK) { TRACE_DEVEL("Digest Mgr Init failed.\n"); return rc; } context->flag = TRUE; ctx->state_unsaveable |= context->hash_context.state_unsaveable; } 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]; MP_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; } rc = rsa_pkcs_alg_oid_from_mech(ctx->mech.mechanism, &oid, &oid_len); if (rc != CKR_OK) { TRACE_ERROR("%s rsa_pkcs_alg_oid_from_mech failed\n", __func__); return rc; } memset(&sign_ctx, 0x0, sizeof(sign_ctx)); context = (MP_DIGEST_CONTEXT *) ctx->context; if (context->flag == FALSE) { rc = rsa_hash_pkcs_sign_update(tokdata, sess, ctx, NULL, 0); TRACE_DEVEL("rsa_hash_pkcs_sign_update\n"); if (rc != 0) return rc; } 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, FALSE, FALSE); 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(tokdata, sess, &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]; MP_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; } rc = rsa_pkcs_alg_oid_from_mech(ctx->mech.mechanism, &oid, &oid_len); if (rc != CKR_OK) { TRACE_ERROR("%s rsa_pkcs_alg_oid_from_mech failed\n", __func__); return rc; } memset(&verify_ctx, 0x0, sizeof(verify_ctx)); context = (MP_DIGEST_CONTEXT *) ctx->context; if (context->flag == FALSE) { rc = rsa_hash_pkcs_verify_update(tokdata, sess, ctx, NULL, 0); TRACE_DEVEL("rsa_hash_pkcs_verify_update\n"); if (rc != 0) return rc; } 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, FALSE); 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(tokdata, sess, &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, const 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) { size_t i, dblen = 0, mlen = -1, one_index = 0, msg_index; unsigned int ok = 0, found_one_byte, mask; const unsigned char *maskedseed, *maskeddb; unsigned char *db = NULL; unsigned char seed[EVP_MAX_MD_SIZE]; /* * The implementation of this function is copied from OpenSSL's function * RSA_padding_check_PKCS1_OAEP_mgf1() in crypto/rsa/rsa_oaep.c * and is slightly modified to fit to the OpenCryptoki environment. * * The OpenSSL code is licensed under the Apache License 2.0. * You can obtain a copy in the file LICENSE in the OpenSSL source * distribution or at https://www.openssl.org/source/license.html * * Changes include: * - Different variable and define names. * - Usage of TRACE_ERROR to report errors and issue debug messages. * - Different return codes. * - No need for copying the input to an allocated 'em' buffer. The caller * guarantees that the size of the input is already the size of the * modulus. */ /* * |emLen| is guaranteed by the caller to be the modulus size. * |emLen| >= 2 * |hlen| + 2 must hold for the modulus * irrespective of the ciphertext, see PKCS #1 v2.2, section 7.1.2. * This does not leak any side-channel information. */ if (emLen < 2 * hlen + 2) { TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); return CKR_ARGUMENTS_BAD; } dblen = emLen - hlen - 1; db = calloc(1, dblen); if (db == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); return CKR_HOST_MEMORY; } /* * The first byte must be zero, however we must not leak if this is * true. See James H. Manger, "A Chosen Ciphertext Attack on RSA * Optimal Asymmetric Encryption Padding (OAEP) [...]", CRYPTO 2001). */ ok = constant_time_is_zero(emData[0]); maskedseed = emData + 1; maskeddb = emData + 1 + hlen; if (mgf1(tokdata, maskeddb, dblen, seed, hlen, mgf) != CKR_OK) goto done; for (i = 0; i < hlen; i++) seed[i] ^= maskedseed[i]; if (mgf1(tokdata, seed, hlen, db, dblen, mgf) != CKR_OK) goto done; for (i = 0; i < dblen; i++) db[i] ^= maskeddb[i]; ok &= constant_time_is_zero(CRYPTO_memcmp(db, hash, hlen)); found_one_byte = 0; for (i = hlen; i < dblen; i++) { /* * Padding consists of a number of 0-bytes, followed by a 1. */ unsigned int equals1 = constant_time_eq(db[i], 1); unsigned int equals0 = constant_time_is_zero(db[i]); one_index = constant_time_select_int(~found_one_byte & equals1, i, one_index); found_one_byte |= equals1; ok &= (found_one_byte | equals0); } ok &= found_one_byte; /* * At this point |good| is zero unless the plaintext was valid, * so plaintext-awareness ensures timing side-channels are no longer a * concern. */ msg_index = one_index + 1; mlen = dblen - msg_index; /* * For good measure, do this check in constant time as well. */ ok &= constant_time_ge(*out_data_len, mlen); /* * Move the result in-place by |dblen| - |hlen| - 1 - |mlen| bytes * to the left. * Then if |good| move |mlen| bytes from |db| + |hlen| + 1 to |out|. * Otherwise leave |out| unchanged. * Copy the memory back in a way that does not reveal the size of * the data being copied via a timing side channel. This requires copying * parts of the buffer multiple times based on the bits set in the real * length. Clear bits do a non-copy with identical access pattern. * The loop below has overall complexity of O(N*log(N)). */ *out_data_len = constant_time_select_int(constant_time_lt(dblen - hlen - 1, *out_data_len), dblen - hlen - 1, *out_data_len); for (msg_index = 1; msg_index < dblen - hlen - 1; msg_index <<= 1) { mask = ~constant_time_eq(msg_index & (dblen - hlen - 1 - mlen), 0); for (i = hlen + 1; i < dblen - msg_index; i++) db[i] = constant_time_select_8(mask, db[i + msg_index], db[i]); } for (i = 0; i < *out_data_len; i++) { mask = ok & constant_time_lt(i, mlen); out_data[i] = constant_time_select_8(mask, db[i + hlen + 1], out_data[i]); } done: OPENSSL_cleanse(seed, sizeof(seed)); if (db) { OPENSSL_cleanse(db, dblen); free(db); } *out_data_len = constant_time_select_int(ok, mlen, 0); return constant_time_select_int(ok, CKR_OK, CKR_ENCRYPTED_DATA_INVALID); } CK_RV emsa_pss_encode(STDLL_TokData_t *tokdata, 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' */ if (in_data_len > 0) 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 ((i < plen) && (buf[i] == 0)) 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); if (in_data_len > 0) 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, digest_mech; CK_ULONG hlen; CK_RV rc; pssParams = (CK_RSA_PKCS_PSS_PARAMS *) mech->pParameter; if (mech->ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS) || mech->pParameter == NULL) { 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; } if (mech->mechanism != CKM_RSA_PKCS_PSS) { rc = get_digest_from_mech(mech->mechanism, &digest_mech); if (rc != CKR_OK) { TRACE_ERROR("%s get_digest_from_mech failed\n", __func__); return rc; } } else { digest_mech = mgf_mech; } if (pssParams->hashAlg != digest_mech || pssParams->hashAlg != mgf_mech) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); return CKR_MECHANISM_PARAM_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; } CK_RV rsa_aes_key_wrap(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_RSA_AES_KEY_WRAP_PARAMS *params; CK_MECHANISM aes_keygen_mech = { CKM_AES_KEY_GEN, NULL, 0 }; CK_MECHANISM rsa_oaep_mech = { CKM_RSA_PKCS_OAEP, NULL, 0 }; CK_MECHANISM aeskw_kwm_mech = { CKM_AES_KEY_WRAP_KWP, NULL, 0 }; ENCR_DECR_CONTEXT aeskw_ctx = { 0 }; CK_OBJECT_HANDLE aes_key_handle = CK_INVALID_HANDLE; CK_ULONG wrapped_aes_key_len = 0, wrapped_key_len = 0, total_len; CK_ULONG aes_key_size; CK_BBOOL ck_true = TRUE; CK_BBOOL ck_false = TRUE; CK_RV rc, rc2; CK_ATTRIBUTE aes_key_tmpl[] = { { CKA_VALUE_LEN, &aes_key_size, sizeof(aes_key_size) }, { CKA_HIDDEN, &ck_true, sizeof(ck_true) }, { CKA_EXTRACTABLE, &ck_true, sizeof(ck_true) }, { CKA_SENSITIVE, &ck_true, sizeof(ck_true) }, { CKA_TOKEN, &ck_false, sizeof(ck_false) }, { CKA_PRIVATE, &ck_true, sizeof(ck_true) }, { CKA_WRAP, &ck_true, sizeof(ck_true) }, { CKA_UNWRAP, &ck_false, sizeof(ck_false) }, { CKA_ENCRYPT, &ck_false, sizeof(ck_false) }, { CKA_DECRYPT, &ck_false, sizeof(ck_false) }, { CKA_SIGN, &ck_false, sizeof(ck_false) }, { CKA_VERIFY, &ck_false, sizeof(ck_false) }, { CKA_DERIVE, &ck_false, sizeof(ck_false) }, }; params = (CK_RSA_AES_KEY_WRAP_PARAMS *)ctx->mech.pParameter; if (params->pOAEPParams == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); return CKR_MECHANISM_PARAM_INVALID; } /* Generate a temporary AES key of the desired size */ aes_key_size = params->ulAESKeyBits / 8; rc = key_mgr_generate_key(tokdata, sess, &aes_keygen_mech, aes_key_tmpl, sizeof(aes_key_tmpl) / sizeof(CK_ATTRIBUTE), &aes_key_handle, FALSE, OP_KEYGEN); if (rc != CKR_OK) { TRACE_ERROR("Failed to generate temporary AES key (%lu bits): " "%s (0x%lx)\n", params->ulAESKeyBits, p11_get_ckr(rc), rc); goto done; } /* * Wrap the temporary AES key as first part of the wrapped key data * (length-only operation to get the size of the first part). */ rsa_oaep_mech.pParameter = params->pOAEPParams; rsa_oaep_mech.ulParameterLen = sizeof(*params->pOAEPParams); rc = key_mgr_wrap_key(tokdata, sess, TRUE, &rsa_oaep_mech, ctx->key, aes_key_handle, NULL, &wrapped_aes_key_len, FALSE, OP_WRAP); if (rc != CKR_OK) { TRACE_ERROR("Failed to wrap temporary AES key: %s (0x%lx)\n", p11_get_ckr(rc), rc); if (rc == CKR_DATA_LEN_RANGE) { /* * An AES key of a certain size can only be wrapped by OAEP with a * large enough RSA key size. E.g. RSA 1014 with OAEP and SHA-384 * can not wrap a 32 bytes AES key. */ rc = CKR_WRAPPING_KEY_SIZE_RANGE; } goto done; } /* * Encrypt (wrap) the to-be-wrapped key as the second part of the wrapped * key data (length-only operation to get the size of the second part). */ rc = encr_mgr_init(tokdata, sess, &aeskw_ctx, OP_WRAP, &aeskw_kwm_mech, aes_key_handle, TRUE); if (rc != CKR_OK) { TRACE_ERROR("Failed to encrypt the to-be-wrapped key: %s (0x%lx)\n", p11_get_ckr(rc), rc); goto done; } rc = encr_mgr_encrypt(tokdata, sess, TRUE, &aeskw_ctx, in_data, in_data_len, NULL, &wrapped_key_len); if (rc != CKR_OK) { TRACE_ERROR("Failed to encrypt the to-be-wrapped key: %s (0x%lx)\n", p11_get_ckr(rc), rc); goto done; } /* Calculate the final length of the wrapped key data */ total_len = wrapped_aes_key_len + wrapped_key_len; if (length_only) { *out_data_len = total_len; goto done; } if (*out_data_len < total_len) { *out_data_len = total_len; TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); rc = CKR_BUFFER_TOO_SMALL; goto done; } /* Wrap the temporary AES key as first part of the wrapped key data */ rc = key_mgr_wrap_key(tokdata, sess, FALSE, &rsa_oaep_mech, ctx->key, aes_key_handle, out_data, &wrapped_aes_key_len, FALSE, OP_WRAP); if (rc != CKR_OK) { TRACE_ERROR("Failed to wrap temporary AES key: %s (0x%lx)\n", p11_get_ckr(rc), rc); if (rc == CKR_DATA_LEN_RANGE) { /* * An AES key of a certain size can only be wrapped by OAEP with a * large enough RSA key size. E.g. RSA 1014 with OAEP and SHA-384 * can not wrap a 32 bytes AES key. */ rc = CKR_WRAPPING_KEY_SIZE_RANGE; } goto done; } /* * Encrypt (wrap) the to-be-wrapped key as the second part of the wrapped * key data. */ rc = encr_mgr_encrypt(tokdata, sess, FALSE, &aeskw_ctx, in_data, in_data_len, out_data + wrapped_aes_key_len, &wrapped_key_len); if (rc != CKR_OK) { TRACE_ERROR("Failed to encrypt the to-be-wrapped key: %s (0x%lx)\n", p11_get_ckr(rc), rc); goto done; } *out_data_len = total_len; done: if (aes_key_handle != CK_INVALID_HANDLE) { rc2 = object_mgr_destroy_object(tokdata, sess, aes_key_handle); if (rc2 != CKR_OK) { TRACE_ERROR("Failed to destroy temporary AES key: %s (0x%lx)\n", p11_get_ckr(rc2), rc2); if (rc == CKR_OK) rc = rc2; } } encr_mgr_cleanup(tokdata, sess, &aeskw_ctx); return rc; } CK_RV rsa_aes_key_unwrap(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_RSA_AES_KEY_WRAP_PARAMS *params; CK_MECHANISM rsa_oaep_mech = { CKM_RSA_PKCS_OAEP, NULL, 0 }; CK_MECHANISM aeskw_kwm_mech = { CKM_AES_KEY_WRAP_KWP, NULL, 0 }; ENCR_DECR_CONTEXT aeskw_ctx = { 0 }; CK_OBJECT_HANDLE aes_key_handle = CK_INVALID_HANDLE; CK_ULONG modulus_size = 0, value_len = 0; CK_OBJECT_CLASS rsa_key_class, aes_key_class = CKO_SECRET_KEY; CK_KEY_TYPE aes_key_type = CKK_AES; CK_BBOOL ck_true = TRUE; CK_BBOOL ck_false = TRUE; OBJECT *key_obj = NULL; CK_RV rc, rc2; CK_ATTRIBUTE aes_key_tmpl[] = { { CKA_CLASS, &aes_key_class, sizeof(aes_key_class) }, { CKA_KEY_TYPE, &aes_key_type, sizeof(aes_key_type) }, { CKA_HIDDEN, &ck_true, sizeof(ck_true) }, { CKA_SENSITIVE, &ck_true, sizeof(ck_true) }, { CKA_TOKEN, &ck_false, sizeof(ck_false) }, { CKA_PRIVATE, &ck_true, sizeof(ck_true) }, { CKA_WRAP, &ck_false, sizeof(ck_false) }, { CKA_UNWRAP, &ck_true, sizeof(ck_true) }, { CKA_ENCRYPT, &ck_false, sizeof(ck_false) }, { CKA_DECRYPT, &ck_false, sizeof(ck_false) }, { CKA_SIGN, &ck_false, sizeof(ck_false) }, { CKA_VERIFY, &ck_false, sizeof(ck_false) }, { CKA_DERIVE, &ck_false, sizeof(ck_false) }, }; params = (CK_RSA_AES_KEY_WRAP_PARAMS *)ctx->mech.pParameter; if (params->pOAEPParams == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); return CKR_MECHANISM_PARAM_INVALID; } /* Get RSA key size to split off first part of wrapped key data */ 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.\n"); if (rc == CKR_OBJECT_HANDLE_INVALID) return CKR_KEY_HANDLE_INVALID; else return rc; } rc = rsa_get_key_info(key_obj, &modulus_size, &rsa_key_class); object_put(tokdata, key_obj, TRUE); key_obj = NULL; if (rc != CKR_OK) { TRACE_DEVEL("rsa_get_key_info failed.\n"); return rc; } if (in_data_len < modulus_size + 2 * AES_KEY_WRAP_BLOCK_SIZE) { TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_LEN_RANGE)); return CKR_ENCRYPTED_DATA_LEN_RANGE; } /* Unwrap the temporary AES key */ rsa_oaep_mech.pParameter = params->pOAEPParams; rsa_oaep_mech.ulParameterLen = sizeof(*params->pOAEPParams); rc = key_mgr_unwrap_key(tokdata, sess, &rsa_oaep_mech, aes_key_tmpl, sizeof(aes_key_tmpl) / sizeof(CK_ATTRIBUTE), in_data, modulus_size, ctx->key, &aes_key_handle, FALSE, OP_UNWRAP); if (rc != CKR_OK) { TRACE_ERROR("Failed to unwrap temporary AES key: %s (0x%lx)\n", p11_get_ckr(rc), rc); goto done; } /* Get the bit-size of the temporary AES key */ rc = object_mgr_find_in_map1(tokdata, aes_key_handle, &key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to acquire key from temporary AES key handle.\n"); if (rc == CKR_OBJECT_HANDLE_INVALID) rc = CKR_KEY_HANDLE_INVALID; goto done; } rc = template_attribute_get_ulong(key_obj->template, CKA_VALUE_LEN, &value_len); object_put(tokdata, key_obj, TRUE); key_obj = NULL; if (rc != CKR_OK) { TRACE_DEVEL("Failed to get CKA_VALUE_LEN from temp. AES key.\n"); return rc; } /* Update the mechanism param (copy) in context. Might be needed later on */ params->ulAESKeyBits = value_len * 8; /* * Decrypt (unwrap) the final key data from the the second part of the * wrapped key data. */ rc = decr_mgr_init(tokdata, sess, &aeskw_ctx, OP_UNWRAP, &aeskw_kwm_mech, aes_key_handle, TRUE, FALSE); if (rc != CKR_OK) { TRACE_ERROR("Failed to decrypt the to-be-unwrapped key: %s (0x%lx)\n", p11_get_ckr(rc), rc); goto done; } rc = decr_mgr_decrypt(tokdata, sess, length_only, &aeskw_ctx, in_data + modulus_size, in_data_len - modulus_size, out_data, out_data_len); if (rc != CKR_OK) { TRACE_ERROR("Failed to decrypt the to-be-unwrapped key: %s (0x%lx)\n", p11_get_ckr(rc), rc); goto done; } done: if (aes_key_handle != CK_INVALID_HANDLE) { rc2 = object_mgr_destroy_object(tokdata, sess, aes_key_handle); if (rc2 != CKR_OK) { TRACE_ERROR("Failed to destroy temporary AES key: %s (0x%lx)\n", p11_get_ckr(rc2), rc2); if (rc == CKR_OK) rc = rc2; } } encr_mgr_cleanup(tokdata, sess, &aeskw_ctx); return rc; } CK_RV rsa_encapsulate_key(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, CK_MECHANISM *mech, OBJECT *public_key, CK_ATTRIBUTE *pTemplate, CK_ULONG ulAttributeCount, CK_BYTE *pCiphertext, CK_ULONG *pulCiphertextLen, CK_OBJECT_HANDLE *phKey) { CK_RV rc, rc2; CK_OBJECT_CLASS class; CK_KEY_TYPE key_type; CK_MECHANISM keygen_mech = { 0, NULL, 0}; CK_ATTRIBUTE *attrs = NULL; CK_ULONG num_attrs = 0; CK_BBOOL extractable, ck_true = CK_TRUE; CK_ATTRIBUTE *attr; CK_ATTRIBUTE set_tmpl = {CKA_EXTRACTABLE, &extractable, sizeof(CK_BBOOL)}; CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE; /* * PKCS#11 v3.2: When the mechanism is used in key encapsulation, the * secret key is generated in the C_EncapsulateKey function and then * wrapped with RSA PKCS/OAEP. */ rc = get_ulong_attribute_by_type(pTemplate, ulAttributeCount, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS in the template\n"); goto done; } if (class != CKO_SECRET_KEY) { TRACE_ERROR("Can only encapsulate a secret key\n"); rc = CKR_KEY_TYPE_INCONSISTENT; goto done; } rc = get_ulong_attribute_by_type(pTemplate, ulAttributeCount, CKA_KEY_TYPE, &key_type); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE in the template\n"); goto done; } switch (key_type) { case CKK_GENERIC_SECRET: keygen_mech.mechanism = CKM_GENERIC_SECRET_KEY_GEN; break; case CKK_SHA_1_HMAC: keygen_mech.mechanism = CKM_SHA_1_KEY_GEN; break; case CKK_SHA224_HMAC: keygen_mech.mechanism = CKM_SHA224_KEY_GEN; break; case CKK_SHA256_HMAC: keygen_mech.mechanism = CKM_SHA256_KEY_GEN; break; case CKK_SHA384_HMAC: keygen_mech.mechanism = CKM_SHA384_KEY_GEN; break; case CKK_SHA512_HMAC: keygen_mech.mechanism = CKM_SHA512_KEY_GEN; break; case CKK_SHA512_224_HMAC: keygen_mech.mechanism = CKM_SHA512_224_KEY_GEN; break; case CKK_SHA512_256_HMAC: keygen_mech.mechanism = CKM_SHA512_256_KEY_GEN; break; case CKK_SHA3_224_HMAC: keygen_mech.mechanism = CKM_SHA3_224_KEY_GEN; break; case CKK_SHA3_256_HMAC: keygen_mech.mechanism = CKM_SHA3_256_KEY_GEN; break; case CKK_SHA3_384_HMAC: keygen_mech.mechanism = CKM_SHA3_384_KEY_GEN; break; case CKK_SHA3_512_HMAC: keygen_mech.mechanism = CKM_SHA3_512_KEY_GEN; break; case CKK_AES: keygen_mech.mechanism = CKM_AES_KEY_GEN; break; case CKK_AES_XTS: keygen_mech.mechanism = CKM_AES_XTS_KEY_GEN; break; case CKK_DES: keygen_mech.mechanism = CKM_DES_KEY_GEN; break; case CKK_DES3: keygen_mech.mechanism = CKM_DES3_KEY_GEN; break; default: TRACE_ERROR("Key type 0x%lu can not be encapsulated\n", key_type); rc = CKR_KEY_TYPE_INCONSISTENT; goto done; } rc = dup_attribute_array(pTemplate, ulAttributeCount, &attrs, &num_attrs); if (rc != CKR_OK) { TRACE_DEVEL("dup_attribute_array failed.\n"); goto done; } /* Ensure that CKA_EXTRACTABLE is initially TRUE on keygen */ attr = get_attribute_by_type(attrs, num_attrs, CKA_EXTRACTABLE); if (attr != NULL) { if (attr->ulValueLen != sizeof(CK_BBOOL) || attr->pValue == NULL) { TRACE_ERROR("%s: %lx\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID), (CK_ULONG)CKA_EXTRACTABLE); rc = CKR_ATTRIBUTE_VALUE_INVALID; goto done; } extractable = *(CK_BBOOL *)attr->pValue; *(CK_BBOOL *)attr->pValue = CK_TRUE; } else { rc = add_to_attribute_array(&attrs, &num_attrs, CKA_EXTRACTABLE, &ck_true, sizeof(ck_true)); if (rc != CKR_OK) { TRACE_DEVEL("add_to_attribute_array failed.\n"); goto done; } extractable = CK_TRUE; } if (length_only) { rc = add_to_attribute_array(&attrs, &num_attrs, CKA_HIDDEN, &ck_true, sizeof(ck_true)); if (rc != CKR_OK) { TRACE_DEVEL("add_to_attribute_array failed.\n"); goto done; } } if (token_specific.t_encapsulate_rsa_sym_keygen != NULL) { rc = token_specific.t_encapsulate_rsa_sym_keygen(tokdata, sess, &keygen_mech, attrs, num_attrs, &hKey); if (rc != CKR_OK) { TRACE_DEVEL("token specific encapsulate_rsa_sym_keygen failed.\n"); goto done; } } else { rc = key_mgr_generate_key(tokdata, sess, &keygen_mech, attrs, num_attrs, &hKey, FALSE, OP_ENCAPSULATE); if (rc != CKR_OK) { TRACE_DEVEL("key_mgr_generate_key failed.\n"); goto done; } } if (token_specific.t_encapsulate_rsa_key_wrap != NULL) { rc = token_specific.t_encapsulate_rsa_key_wrap(tokdata, sess, length_only, mech, public_key->map_handle, hKey, pCiphertext, pulCiphertextLen); if (rc != CKR_OK) { TRACE_DEVEL("token specific encapsulate_rsa_key_wrap failed.\n"); goto done; } } else { rc = key_mgr_wrap_key(tokdata, sess, length_only, mech, public_key->map_handle, hKey, pCiphertext, pulCiphertextLen, FALSE, OP_ENCAPSULATE); if (rc != CKR_OK) { TRACE_DEVEL("key_mgr_wrap_key failed.\n"); goto done; } } if (!length_only) { /* Adjust CKA_EXTRACTABEL in key if in template it is FALSE */ if (extractable == CK_FALSE) { rc = object_mgr_set_attribute_values(tokdata, sess, hKey, &set_tmpl, 1); if (rc != CKR_OK) { TRACE_DEVEL("object_mgr_set_attribute_values failed.\n"); goto done; } } *phKey = hKey; } done: if ((rc != CKR_OK || length_only) && hKey != CK_INVALID_HANDLE) { rc2 = object_mgr_destroy_object(tokdata, sess, hKey); if (rc2 != CKR_OK) { TRACE_DEVEL("object_mgr_destroy_object failed.\n"); } } free_attribute_array(attrs, num_attrs); return rc; } CK_RV rsa_decapsulate_key(STDLL_TokData_t *tokdata, SESSION *sess, CK_MECHANISM *mech, OBJECT *private_key, CK_ATTRIBUTE *pTemplate, CK_ULONG ulAttributeCount, CK_BYTE *pCiphertext, CK_ULONG ulCiphertextLen, CK_OBJECT_HANDLE *phKey) { CK_RV rc; /* * PKCS#11 v3.2: C_DecapsulateKey is exactly equivalent to C_UnwrapKey * for RSA PKCS/OAEP. */ if (token_specific.t_encapsulate_rsa_key_unwrap != NULL) { rc = token_specific.t_encapsulate_rsa_key_unwrap(tokdata, sess, mech, pTemplate, ulAttributeCount, pCiphertext, ulCiphertextLen, private_key->map_handle, phKey); if (rc != CKR_OK) { TRACE_DEVEL("token specific encapsulate_rsa_key_unwrap failed.\n"); return rc; } } else { rc = key_mgr_unwrap_key(tokdata, sess, mech, pTemplate, ulAttributeCount, pCiphertext, ulCiphertextLen, private_key->map_handle, phKey, FALSE, OP_DECAPSULATE); if (rc != CKR_OK) { TRACE_DEVEL("key_mgr_wrap_key failed.\n"); return rc; } } return CKR_OK; } opencryptoki-opencryptoki-451d99c/usr/lib/common/mech_sha.c000066400000000000000000001003171520105705100241100ustar00rootroot00000000000000/* * 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 "attributes.h" #include #include // // Software SHA-1 implementation (OpenSSL based) // static void sw_sha1_free(STDLL_TokData_t *tokdata, SESSION *sess, CK_BYTE *context, CK_ULONG context_len) { UNUSED(tokdata); UNUSED(sess); UNUSED(context_len); EVP_MD_CTX_free((EVP_MD_CTX *)context); } CK_RV sw_sha1_init(DIGEST_CONTEXT *ctx) { ctx->context_len = 1; ctx->context = (CK_BYTE *)EVP_MD_CTX_new(); if (ctx->context == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); ctx->context_len = 0; return CKR_HOST_MEMORY; } if (!EVP_DigestInit_ex((EVP_MD_CTX *)ctx->context, EVP_sha1(), NULL)) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); EVP_MD_CTX_free((EVP_MD_CTX *)ctx->context); ctx->context = NULL; ctx->context_len = 0; return CKR_FUNCTION_FAILED; } ctx->state_unsaveable = CK_TRUE; ctx->context_free_func = sw_sha1_free; return CKR_OK; } 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) { unsigned int 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; len = *out_data_len; if (!EVP_DigestUpdate((EVP_MD_CTX *)ctx->context, in_data, in_data_len) || !EVP_DigestFinal((EVP_MD_CTX *)ctx->context, out_data, &len)) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } *out_data_len = len; EVP_MD_CTX_free((EVP_MD_CTX *)ctx->context); ctx->context = NULL; ctx->context_free_func = NULL; return CKR_OK; } static 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; if (!EVP_DigestUpdate((EVP_MD_CTX *)ctx->context, in_data, in_data_len)) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } return CKR_OK; } static CK_RV sw_sha1_final(DIGEST_CONTEXT *ctx, CK_BYTE *out_data, CK_ULONG *out_data_len) { unsigned int len; if (ctx->context == NULL) return CKR_OPERATION_NOT_INITIALIZED; if (*out_data_len < SHA1_HASH_SIZE) { TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); return CKR_BUFFER_TOO_SMALL; } len = *out_data_len; if (!EVP_DigestFinal((EVP_MD_CTX *)ctx->context, out_data, &len)) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } *out_data_len = len; EVP_MD_CTX_free((EVP_MD_CTX *)ctx->context); ctx->context = NULL; ctx->context_free_func = 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) { return sw_sha1_init(ctx); } 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; CK_RV rc; 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_OCK_SHAKE128: case CKM_OCK_SHAKE256: if (ctx->mech.ulParameterLen != sizeof(CK_ULONG)) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); return CKR_MECHANISM_PARAM_INVALID; } hsize = *(CK_ULONG *)ctx->mech.pParameter; break; default: rc = get_sha_size(ctx->mech.mechanism, &hsize); if (rc != CKR_OK) { TRACE_ERROR("get_sha_size failed\n"); return CKR_FUNCTION_NOT_SUPPORTED; } break; } 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; CK_RV rc; 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_OCK_SHAKE128: case CKM_OCK_SHAKE256: if (ctx->mech.ulParameterLen != sizeof(CK_ULONG)) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); return CKR_MECHANISM_PARAM_INVALID; } hsize = *(CK_ULONG *)ctx->mech.pParameter; break; default: rc = get_sha_size(ctx->mech.mechanism, &hsize); if (rc != CKR_OK) { TRACE_ERROR("get_sha_size failed\n"); return CKR_FUNCTION_NOT_SUPPORTED; } break; } 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 these mechanisms actually: // CKM_SHA_1_HMAC // CKM_SHA_1_HMAC_GENERAL // CKM_SHA224_HMAC // CKM_SHA224_HMAC_GENERAL // CKM_SHA256_HMAC // CKM_SHA256_HMAC_GENERAL // CKM_SHA384_HMAC // CKM_SHA384_HMAC_GENERAL // 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 // CKM_SHA3_224_HMAC // CKM_SHA3_224_HMAC_GENERAL // CKM_SHA3_256_HMAC // CKM_SHA3_256_HMAC_GENERAL // CKM_SHA3_384_HMAC // CKM_SHA3_384_HMAC_GENERAL // CKM_SHA3_512_HMAC // CKM_SHA3_512_HMAC_GENERAL // CKM_IBM_SHA3_224_HMAC // CKM_IBM_SHA3_256_HMAC // CKM_IBM_SHA3_384_HMAC // CKM_IBM_SHA3_512_HMAC // CK_RV sha_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_MECHANISM digest_mech; CK_ULONG hmac_len, digest_hash_len, digest_block_size; CK_BBOOL general = FALSE; CK_RV rc; if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } digest_mech.ulParameterLen = 0; digest_mech.pParameter = NULL; rc = get_hmac_digest(ctx->mech.mechanism, &digest_mech.mechanism, &general); if (rc != 0) { TRACE_ERROR("get_hmac_digest failed"); return rc; } rc = get_sha_block_size(digest_mech.mechanism, &digest_block_size); if (rc != 0) { TRACE_ERROR("get_sha_block_size failed"); return rc; } rc = get_sha_size(digest_mech.mechanism, &digest_hash_len); if (rc != 0) { TRACE_ERROR("get_sha_size failed"); return rc; } if (general == FALSE) { hmac_len = digest_hash_len; } else { hmac_len = *(CK_ULONG *)ctx->mech.pParameter; if (hmac_len > digest_hash_len) return CKR_MECHANISM_PARAM_INVALID; if (hmac_len == 0) { *out_data_len = 0; return CKR_OK; } } 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); return openssl_specific_hmac(&sess->sign_ctx, in_data, in_data_len, out_data, out_data_len, TRUE); } // this routine gets called for these mechanisms actually: // CKM_SHA_1_HMAC // CKM_SHA_1_HMAC_GENERAL // CKM_SHA224_HMAC // CKM_SHA224_HMAC_GENERAL // CKM_SHA256_HMAC // CKM_SHA256_HMAC_GENERAL // CKM_SHA384_HMAC // CKM_SHA384_HMAC_GENERAL // 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 // CKM_SHA3_224_HMAC // CKM_SHA3_224_HMAC_GENERAL // CKM_SHA3_256_HMAC // CKM_SHA3_256_HMAC_GENERAL // CKM_SHA3_384_HMAC // CKM_SHA3_384_HMAC_GENERAL // CKM_SHA3_512_HMAC // CKM_SHA3_512_HMAC_GENERAL // CKM_IBM_SHA3_224_HMAC // CKM_IBM_SHA3_256_HMAC // CKM_IBM_SHA3_384_HMAC // CKM_IBM_SHA3_512_HMAC // CK_RV sha_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) { 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); return openssl_specific_hmac(&sess->verify_ctx, in_data, in_data_len, signature, &sig_len, FALSE); } 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 openssl_specific_hmac_init(tokdata, &sess->sign_ctx, mech, hkey); } 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); return openssl_specific_hmac_update(&sess->sign_ctx, in_data, in_data_len, TRUE); } 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); return openssl_specific_hmac_final(&sess->sign_ctx, signature, sig_len, TRUE); } 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 openssl_specific_hmac_init(tokdata, &sess->verify_ctx, mech, hkey); } 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); return openssl_specific_hmac_update(&sess->verify_ctx, in_data, in_data_len, FALSE); } 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); return openssl_specific_hmac_final(&sess->verify_ctx, signature, &sig_len, FALSE); } 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); } CK_RV ckm_sha_derive(STDLL_TokData_t *tokdata, SESSION *sess, CK_MECHANISM *mech, OBJECT *base_key_obj, CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE *derived_key_handle, CK_BBOOL count_statistic) { OBJECT *derived_key_obj = NULL; CK_BYTE derived_key_value[MAX_SHA_HASH_SIZE]; DIGEST_CONTEXT ctx; CK_MECHANISM digest_mech; CK_ULONG hsize = 0, allowed_keysize = 0; CK_ULONG derived_keytype = 0, derived_keylen = 0; CK_ATTRIBUTE *base_key_value; CK_ATTRIBUTE *value_attr, *vallen_attr = NULL; CK_ULONG base_key_class, base_key_type; CK_KEY_TYPE keytype1, keytype2; CK_RV rc; memset(&ctx, 0, sizeof(DIGEST_CONTEXT)); memset(&digest_mech, 0, sizeof(CK_MECHANISM)); rc = get_digest_from_mech(mech->mechanism, &digest_mech.mechanism); if (rc != CKR_OK) { TRACE_ERROR("%s get_digest_from_mech failed\n", __func__); return rc; } rc = get_sha_size(digest_mech.mechanism, &hsize); if (rc != CKR_OK) { TRACE_ERROR("%s get_sha_size failed\n", __func__); return CKR_FUNCTION_NOT_SUPPORTED; } rc = get_ulong_attribute_by_type(pTemplate, ulCount, CKA_VALUE_LEN, &derived_keylen); if (rc == CKR_ATTRIBUTE_VALUE_INVALID) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return rc; } rc = get_ulong_attribute_by_type(pTemplate, ulCount, CKA_KEY_TYPE, &derived_keytype); if (rc == CKR_ATTRIBUTE_VALUE_INVALID) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return rc; } /* * According to PKCS#11: * - no key length and no key type: CKK_GENERIC_SECRET of size . * - no key type, but length given: CKK_GENERIC_SECRET if specified length. * - no key length but key type specified: key must have a well-defined * length, otherwise error. * - key length and key type specified: length must be compatible with key * type, otherwise error. * - key length must always be less or equal to the digest size. */ if (derived_keytype == 0) derived_keytype = CKK_GENERIC_SECRET; switch (derived_keytype) { case CKK_GENERIC_SECRET: allowed_keysize = hsize; break; case CKK_SHA_1_HMAC: case CKK_SHA224_HMAC: case CKK_SHA256_HMAC: case CKK_SHA384_HMAC: case CKK_SHA512_HMAC: case CKK_SHA3_224_HMAC: case CKK_SHA3_256_HMAC: case CKK_SHA3_384_HMAC: case CKK_SHA3_512_HMAC: case CKK_SHA512_224_HMAC: case CKK_SHA512_256_HMAC: rc = pkcsget_keytype_for_mech(mech->mechanism, &keytype1, &keytype2); if (rc != CKR_OK) { TRACE_ERROR("pkcsget_keytype_for_mech failed.\n"); return rc; } if (derived_keytype != keytype1 && derived_keytype != keytype2) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); return CKR_KEY_TYPE_INCONSISTENT; } allowed_keysize = hsize; break; case CKK_DES: allowed_keysize = DES_KEY_SIZE; break; case CKK_DES2: allowed_keysize = 2 * DES_KEY_SIZE; break; case CKK_DES3: allowed_keysize = 3 * DES_KEY_SIZE; break; case CKK_AES: switch (derived_keylen) { case AES_KEY_SIZE_128: case AES_KEY_SIZE_192: case AES_KEY_SIZE_256: allowed_keysize = derived_keylen; break; default: TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); return CKR_TEMPLATE_INCONSISTENT; } break; case CKK_AES_XTS: switch (derived_keylen) { case 2 * AES_KEY_SIZE_128: case 2 * AES_KEY_SIZE_256: allowed_keysize = derived_keylen; break; default: TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); return CKR_TEMPLATE_INCONSISTENT; } break; default: TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); return CKR_TEMPLATE_INCONSISTENT; } if (derived_keylen == 0) derived_keylen = allowed_keysize; if (derived_keylen > hsize) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); return CKR_TEMPLATE_INCONSISTENT; } switch (derived_keytype) { case CKK_GENERIC_SECRET: case CKK_SHA_1_HMAC: case CKK_SHA224_HMAC: case CKK_SHA256_HMAC: case CKK_SHA384_HMAC: case CKK_SHA512_HMAC: case CKK_SHA3_224_HMAC: case CKK_SHA3_256_HMAC: case CKK_SHA3_384_HMAC: case CKK_SHA3_512_HMAC: case CKK_SHA512_224_HMAC: case CKK_SHA512_256_HMAC: break; default: /* All other have a fixed key size */ if (derived_keylen != allowed_keysize) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); return CKR_TEMPLATE_INCONSISTENT; } break; } if (!template_get_class(base_key_obj->template, &base_key_class, &base_key_type)) { TRACE_ERROR("Could not find CKA_CLASS in the template\n"); return CKR_TEMPLATE_INCOMPLETE; } if (base_key_class != CKO_SECRET_KEY) { TRACE_ERROR("Base key is not a secret key\n"); return CKR_KEY_TYPE_INCONSISTENT; } switch (base_key_type) { case CKK_GENERIC_SECRET: case CKK_SHA_1_HMAC: case CKK_SHA256_HMAC: case CKK_SHA384_HMAC: case CKK_SHA512_HMAC: case CKK_SHA224_HMAC: case CKK_SHA3_224_HMAC: case CKK_SHA3_256_HMAC: case CKK_SHA3_384_HMAC: case CKK_SHA3_512_HMAC: case CKK_SHA512_224_HMAC: case CKK_SHA512_256_HMAC: case CKK_DES: case CKK_DES2: case CKK_DES3: case CKK_AES: case CKK_AES_XTS: break; default: TRACE_ERROR("Base key type is not supported\n"); return CKR_KEY_TYPE_INCONSISTENT; } /* Digest the base key to derive the derived key */ rc = template_attribute_get_non_empty(base_key_obj->template, CKA_VALUE, &base_key_value); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the base key.\n"); return rc; } rc = digest_mgr_init(tokdata, sess, &ctx, &digest_mech, FALSE); if (rc != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return rc; } rc = digest_mgr_digest(tokdata, sess, FALSE, &ctx, base_key_value->pValue, base_key_value->ulValueLen, derived_key_value, &hsize); if (rc != CKR_OK) { TRACE_ERROR("digest_mgr_digest failed with rc=0x%lx\n", rc); digest_mgr_cleanup(tokdata, sess, &ctx); return rc; } rc = build_attribute(CKA_VALUE, derived_key_value, derived_keylen, &value_attr); if (rc != CKR_OK) { TRACE_ERROR("Failed to build the attribute from CKA_VALUE, rc=0x%lx.\n", rc); return rc; } switch (derived_keytype) { case CKK_GENERIC_SECRET: case CKK_SHA_1_HMAC: case CKK_SHA224_HMAC: case CKK_SHA256_HMAC: case CKK_SHA384_HMAC: case CKK_SHA512_HMAC: case CKK_SHA3_224_HMAC: case CKK_SHA3_256_HMAC: case CKK_SHA3_384_HMAC: case CKK_SHA3_512_HMAC: case CKK_SHA512_224_HMAC: case CKK_SHA512_256_HMAC: case CKK_AES: case CKK_AES_XTS: /* Supply CKA_VALUE_LEN since this is required for those key types */ rc = build_attribute(CKA_VALUE_LEN, (CK_BYTE*)&derived_keylen, sizeof(derived_keylen), &vallen_attr); if (rc != CKR_OK) { TRACE_ERROR("Failed to build the attribute from CKA_VALUE_LEN, " "rc=0x%lx.\n", rc); goto end; } break; case CKK_DES: if (des_check_weak_key(derived_key_value)) { TRACE_ERROR("Derived key is a weak DES key\n"); rc = CKR_FUNCTION_FAILED; goto end; } break; default: break; } /* Create the derived key object and update the attributes */ rc = object_mgr_create_skel(tokdata, sess, pTemplate, ulCount, MODE_DERIVE, CKO_SECRET_KEY, derived_keytype, &derived_key_obj); if (rc != CKR_OK) { TRACE_ERROR("Object Mgr create skeleton failed, rc=%s.\n", ock_err(rc)); goto end; } /* Update the template in the object with the new attributes */ rc = template_update_attribute(derived_key_obj->template, value_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto end; } value_attr = NULL; if (vallen_attr != NULL) { rc = template_update_attribute(derived_key_obj->template, vallen_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto end; } vallen_attr = NULL; } rc = key_mgr_derive_always_sensitive_never_extractable_attrs(tokdata, base_key_obj, derived_key_obj); if (rc != CKR_OK) { TRACE_ERROR("key_mgr_derive_always_sensitive_never_extractable_attrs " "failed\n"); goto end; } rc = object_mgr_create_final(tokdata, sess, derived_key_obj, derived_key_handle); if (rc != CKR_OK) { TRACE_ERROR("Object Mgr create final failed, rc=0x%lx.\n", rc); goto end; } if (count_statistic == TRUE) INC_COUNTER(tokdata, sess, mech, base_key_obj, POLICY_STRENGTH_IDX_0); rc = CKR_OK; end: if (rc != CKR_OK && derived_key_obj != NULL) { object_free(derived_key_obj); derived_key_handle = CK_INVALID_HANDLE; } if (value_attr != NULL) free(value_attr); if (vallen_attr != NULL) free(vallen_attr); return rc; } CK_RV ckm_shake_derive(STDLL_TokData_t *tokdata, SESSION *sess, CK_MECHANISM *mech, OBJECT *base_key_obj, CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE *derived_key_handle) { OBJECT *derived_key_obj = NULL; CK_ULONG allowed_keysize = 0; CK_ULONG derived_keytype = 0, derived_keylen = 0; CK_ULONG base_key_class, base_key_type; CK_RV rc; if (token_specific.t_shake_key_derive == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); return CKR_MECHANISM_INVALID; } rc = get_ulong_attribute_by_type(pTemplate, ulCount, CKA_VALUE_LEN, &derived_keylen); if (rc == CKR_ATTRIBUTE_VALUE_INVALID) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return rc; } rc = get_ulong_attribute_by_type(pTemplate, ulCount, CKA_KEY_TYPE, &derived_keytype); if (rc == CKR_ATTRIBUTE_VALUE_INVALID) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return rc; } /* * According to PKCS#11: * - no key length and no key type: CKR_TEMPLATE_INCOMPLETE * - no key type, but length given: CKK_GENERIC_SECRET of specified length. * - no key length but key type specified: key must have a well-defined * length, otherwise error. * - key length and key type specified: length must be compatible with key * type, otherwise error. */ if (derived_keytype == 0 && derived_keylen == 0) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); return CKR_TEMPLATE_INCOMPLETE; } if (derived_keytype == 0) derived_keytype = CKK_GENERIC_SECRET; switch (derived_keytype) { case CKK_GENERIC_SECRET: case CKK_SHA_1_HMAC: case CKK_SHA224_HMAC: case CKK_SHA256_HMAC: case CKK_SHA384_HMAC: case CKK_SHA512_HMAC: case CKK_SHA3_224_HMAC: case CKK_SHA3_256_HMAC: case CKK_SHA3_384_HMAC: case CKK_SHA3_512_HMAC: case CKK_SHA512_224_HMAC: case CKK_SHA512_256_HMAC: if (derived_keylen == 0) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); return CKR_TEMPLATE_INCONSISTENT; } allowed_keysize = derived_keylen; break; case CKK_DES: allowed_keysize = DES_KEY_SIZE; break; case CKK_DES2: allowed_keysize = 2 * DES_KEY_SIZE; break; case CKK_DES3: allowed_keysize = 3 * DES_KEY_SIZE; break; case CKK_AES: switch (derived_keylen) { case AES_KEY_SIZE_128: case AES_KEY_SIZE_192: case AES_KEY_SIZE_256: allowed_keysize = derived_keylen; break; default: TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); return CKR_TEMPLATE_INCONSISTENT; } break; case CKK_AES_XTS: switch (derived_keylen) { case 2 * AES_KEY_SIZE_128: case 2 * AES_KEY_SIZE_256: allowed_keysize = derived_keylen; break; default: TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); return CKR_TEMPLATE_INCONSISTENT; } break; default: TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); return CKR_TEMPLATE_INCONSISTENT; } if (derived_keylen == 0) derived_keylen = allowed_keysize; if (derived_keylen != allowed_keysize) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); return CKR_TEMPLATE_INCONSISTENT; } if (!template_get_class(base_key_obj->template, &base_key_class, &base_key_type)) { TRACE_ERROR("Could not find CKA_CLASS in the template\n"); return CKR_TEMPLATE_INCOMPLETE; } if (base_key_class != CKO_SECRET_KEY) { TRACE_ERROR("Base key is not a secret key\n"); return CKR_KEY_TYPE_INCONSISTENT; } switch (base_key_type) { case CKK_GENERIC_SECRET: case CKK_SHA_1_HMAC: case CKK_SHA224_HMAC: case CKK_SHA256_HMAC: case CKK_SHA384_HMAC: case CKK_SHA512_HMAC: case CKK_SHA3_224_HMAC: case CKK_SHA3_256_HMAC: case CKK_SHA3_384_HMAC: case CKK_SHA3_512_HMAC: case CKK_SHA512_224_HMAC: case CKK_SHA512_256_HMAC: case CKK_DES: case CKK_DES2: case CKK_DES3: case CKK_AES: case CKK_AES_XTS: break; default: TRACE_ERROR("Base key type is not supported\n"); return CKR_KEY_TYPE_INCONSISTENT; } rc = object_mgr_create_skel(tokdata, sess, pTemplate, ulCount, MODE_DERIVE, CKO_SECRET_KEY, derived_keytype, &derived_key_obj); if (rc != CKR_OK) { TRACE_ERROR("Object Mgr create skeleton failed, rc=0x%lx.\n", rc); return rc; } rc = token_specific.t_shake_key_derive(tokdata, sess, mech, base_key_obj, base_key_type, derived_key_obj, derived_keytype, derived_keylen); if (rc != CKR_OK) { TRACE_DEVEL("Token specific shake key derive failed.\n"); goto end; } rc = key_mgr_derive_always_sensitive_never_extractable_attrs(tokdata, base_key_obj, derived_key_obj); if (rc != CKR_OK) { TRACE_ERROR("key_mgr_derive_always_sensitive_never_extractable_attrs " "failed\n"); goto end; } rc = object_mgr_create_final(tokdata, sess, derived_key_obj, derived_key_handle); if (rc != CKR_OK) { TRACE_ERROR("Object Mgr create final failed, rc=0x%lx.\n", rc); goto end; } INC_COUNTER(tokdata, sess, mech, base_key_obj, POLICY_STRENGTH_IDX_0); rc = CKR_OK; end: if (rc != CKR_OK && derived_key_obj != NULL) { object_free(derived_key_obj); derived_key_handle = CK_INVALID_HANDLE; } return rc; } opencryptoki-opencryptoki-451d99c/usr/lib/common/mech_ssl3.c000066400000000000000000002054751520105705100242340ustar00rootroot00000000000000/* * 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 "attributes.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.\n"); if (rc == CKR_OBJECT_HANDLE_INVALID) return CKR_KEY_HANDLE_INVALID; else return rc; } rc = template_attribute_get_non_empty(key_obj->template, CKA_VALUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE in the template\n"); 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, FALSE); 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, FALSE); 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; MP_DIGEST_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 = (MP_DIGEST_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.\n"); if (rc == CKR_OBJECT_HANDLE_INVALID) return CKR_KEY_HANDLE_INVALID; else return rc; } rc = template_attribute_get_non_empty(key_obj->template, CKA_VALUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE in the template\n"); 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, FALSE); 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; ctx->state_unsaveable |= context->hash_context.state_unsaveable; } 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]; MP_DIGEST_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 = (MP_DIGEST_CONTEXT *) ctx->context; if (context->flag == FALSE) { rc = ssl3_mac_sign_update(tokdata, sess, ctx, NULL, 0); TRACE_DEVEL("ssl3_mac_sign_update\n"); if (rc != 0) return 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.\n"); if (rc == CKR_OBJECT_HANDLE_INVALID) return CKR_KEY_HANDLE_INVALID; else return rc; } rc = template_attribute_get_non_empty(key_obj->template, CKA_VALUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE in the template\n"); 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(MP_DIGEST_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, FALSE); 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, FALSE, FALSE); 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(tokdata, sess, &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; MP_DIGEST_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 = (MP_DIGEST_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.\n"); if (rc == CKR_OBJECT_HANDLE_INVALID) return CKR_KEY_HANDLE_INVALID; else return rc; } rc = template_attribute_get_non_empty(key_obj->template, CKA_VALUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE in the template\n"); 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, FALSE); 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; ctx->state_unsaveable |= context->hash_context.state_unsaveable; } 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; MP_DIGEST_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 = (MP_DIGEST_CONTEXT *) ctx->context; if (context->flag == FALSE) { rc = ssl3_mac_verify_update(tokdata, sess, ctx, NULL, 0); TRACE_DEVEL("ssl3_mac_verify_update\n"); if (rc != 0) return 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.\n"); if (rc == CKR_OBJECT_HANDLE_INVALID) return CKR_KEY_HANDLE_INVALID; else return rc; } rc = template_attribute_get_non_empty(key_obj->template, CKA_VALUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE in the template\n"); 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(MP_DIGEST_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, FALSE); 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) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto error; } 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; rc = template_update_attribute(tmpl, value_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } value_attr = NULL; rc = template_update_attribute(tmpl, value_len_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } value_len_attr = NULL; rc = template_update_attribute(tmpl, key_type_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } key_type_attr = NULL; rc = template_update_attribute(tmpl, class_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } class_attr = NULL; rc = template_update_attribute(tmpl, local_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } local_attr = NULL; rc = template_update_attribute(tmpl, derive_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } derive_attr = NULL; return CKR_OK; error: 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); return rc; } // // 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, FALSE); 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, FALSE); 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, FALSE); 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, OBJECT* base_key_obj, CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE *handle, CK_BBOOL count_statistics) { OBJECT *derived_key_obj = NULL; CK_ATTRIBUTE *attr = NULL; CK_ATTRIBUTE *value_attr = NULL; CK_ATTRIBUTE *value_len_attr = NULL; CK_BYTE *base_key_value = NULL; CK_BYTE key_data[48]; CK_ULONG base_key_len; CK_OBJECT_CLASS class; CK_KEY_TYPE keytype; CK_ULONG value_len; 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 = template_attribute_get_non_empty(base_key_obj->template, CKA_VALUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE in the template\n"); goto error; } 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 // rc = get_ulong_attribute_by_type(pTemplate, ulCount, CKA_CLASS, &class); if (rc == CKR_ATTRIBUTE_VALUE_INVALID) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } if (rc == CKR_OK && class != CKO_SECRET_KEY) { TRACE_ERROR("This operation requires a secret key.\n"); rc = CKR_KEY_FUNCTION_NOT_PERMITTED; goto error; } rc = get_ulong_attribute_by_type(pTemplate, ulCount, CKA_KEY_TYPE, &keytype); if (rc == CKR_ATTRIBUTE_VALUE_INVALID) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } if (rc == CKR_OK && keytype != CKK_GENERIC_SECRET) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); rc = CKR_KEY_TYPE_INCONSISTENT; goto error; } rc = get_ulong_attribute_by_type(pTemplate, ulCount, CKA_VALUE_LEN, &value_len); if (rc == CKR_ATTRIBUTE_VALUE_INVALID) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } if (rc == CKR_OK && 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; } rc = key_mgr_derive_always_sensitive_never_extractable_attrs(tokdata, base_key_obj, derived_key_obj); if (rc != CKR_OK) { TRACE_ERROR("key_mgr_derive_always_sensitive_never_extractable_attrs " "failed\n"); goto error; } rc = template_update_attribute(derived_key_obj->template, value_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } value_attr = NULL; rc = template_update_attribute(derived_key_obj->template, value_len_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } value_len_attr = NULL; // 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; 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 // if (count_statistics == TRUE) INC_COUNTER(tokdata, sess, mech, base_key_obj, POLICY_STRENGTH_IDX_0); return CKR_OK; error: if (value_attr) free(value_attr); if (value_len_attr) free(value_len_attr); if (derived_key_obj) object_free(derived_key_obj); return rc; } // // CK_RV ssl3_key_and_mac_derive(STDLL_TokData_t *tokdata, SESSION *sess, CK_MECHANISM *mech, OBJECT *base_key_obj, CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount, CK_BBOOL count_statistic) { 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; 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_BBOOL tmp; CK_OBJECT_CLASS cl; 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 = template_attribute_get_non_empty(base_key_obj->template, CKA_VALUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE in the template\n"); 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. // rc = get_ulong_attribute_by_type(pTemplate, ulCount, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto error; } rc = get_ulong_attribute_by_type(pTemplate, ulCount, CKA_CLASS, &cl); if (rc == CKR_ATTRIBUTE_VALUE_INVALID) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } if (rc == CKR_OK && cl != CKO_SECRET_KEY) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); rc = CKR_TEMPLATE_INCONSISTENT; goto error; } rc = get_bool_attribute_by_type(pTemplate, ulCount, CKA_SENSITIVE, &tmp); if (rc == CKR_ATTRIBUTE_VALUE_INVALID) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } if (rc == CKR_OK && tmp != base_sensitive) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); rc = CKR_TEMPLATE_INCONSISTENT; goto error; } rc = get_bool_attribute_by_type(pTemplate, ulCount, CKA_ALWAYS_SENSITIVE, &tmp); if (rc == CKR_ATTRIBUTE_VALUE_INVALID) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } if (rc == CKR_OK && tmp != base_always_sensitive) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); rc = CKR_TEMPLATE_INCONSISTENT; goto error; } rc = get_bool_attribute_by_type(pTemplate, ulCount, CKA_EXTRACTABLE, &tmp); if (rc == CKR_ATTRIBUTE_VALUE_INVALID) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } if (rc == CKR_OK && tmp != base_extractable) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); rc = CKR_TEMPLATE_INCONSISTENT; goto error; } rc = get_bool_attribute_by_type(pTemplate, ulCount, CKA_NEVER_EXTRACTABLE, &tmp); if (rc == CKR_ATTRIBUTE_VALUE_INVALID) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } if (rc == CKR_OK && tmp != base_never_extractable) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); rc = CKR_TEMPLATE_INCONSISTENT; 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 } if (count_statistic == TRUE) INC_COUNTER(tokdata, sess, mech, base_key_obj, POLICY_STRENGTH_IDX_0); error: 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 *) calloc(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; if (attr->ulValueLen > 0) { if (pTemplate[i].pValue == NULL) { rc = CKR_ATTRIBUTE_VALUE_INVALID; TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); goto error; } 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); } else { attr->pValue = NULL; } 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; } rc = template_update_attribute(client_obj->template, client_val_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } client_val_attr = NULL; rc = template_update_attribute(client_obj->template, client_val_len_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } client_val_len_attr = NULL; rc = template_update_attribute(server_obj->template, server_val_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } server_val_attr = NULL; rc = template_update_attribute(server_obj->template, server_val_len_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } 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); if (server_obj) object_free(server_obj); 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 *) calloc(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; if (attr->ulValueLen > 0) { if (pTemplate[i].pValue == NULL) { rc = CKR_ATTRIBUTE_VALUE_INVALID; TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); goto error; } 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); } else { attr->pValue = NULL; } 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_AES: case CKK_AES_XTS: case CKK_GENERIC_SECRET: case CKK_DES: case CKK_DES2: case CKK_DES3: 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; } rc = template_update_attribute(client_obj->template, client_val_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } client_val_attr = NULL; rc = template_update_attribute(server_obj->template, server_val_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } server_val_attr = NULL; rc = template_update_attribute(client_obj->template, client_val_len_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } client_val_len_attr = NULL; rc = template_update_attribute(server_obj->template, server_val_len_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } 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; } rc = template_update_attribute(client_obj->template, client_val_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } client_val_attr = NULL; rc = template_update_attribute(server_obj->template, server_val_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } 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; } opencryptoki-opencryptoki-451d99c/usr/lib/common/mgf_translation.c000066400000000000000000000046151520105705100255340ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021 * * 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 CK_RV translate_string_to_mgf(const char *str, size_t len, CK_ULONG* mgf) { switch(len) { case 13: if (strcmp("CKG_MGF1_SHA1", str) == 0) { *mgf = CKG_MGF1_SHA1; return CKR_OK; } return CKR_FUNCTION_FAILED; case 15: if (strcmp("CKG_MGF1_SHA224", str) == 0) { *mgf = CKG_MGF1_SHA224; return CKR_OK; } if (strcmp("CKG_MGF1_SHA256", str) == 0) { *mgf = CKG_MGF1_SHA256; return CKR_OK; } if (strcmp("CKG_MGF1_SHA384", str) == 0) { *mgf = CKG_MGF1_SHA384; return CKR_OK; } if (strcmp("CKG_MGF1_SHA512", str) == 0) { *mgf = CKG_MGF1_SHA512; return CKR_OK; } return CKR_FUNCTION_FAILED; case 17: if (strcmp("CKG_MGF1_SHA3_224", str) == 0) { *mgf = CKG_MGF1_SHA3_224; return CKR_OK; } if (strcmp("CKG_MGF1_SHA3_256", str) == 0) { *mgf = CKG_MGF1_SHA3_256; return CKR_OK; } if (strcmp("CKG_MGF1_SHA3_384", str) == 0) { *mgf = CKG_MGF1_SHA3_384; return CKR_OK; } if (strcmp("CKG_MGF1_SHA3_512", str) == 0) { *mgf = CKG_MGF1_SHA3_512; return CKR_OK; } return CKR_FUNCTION_FAILED; case 21: if (strcmp("CKG_IBM_MGF1_SHA3_224", str) == 0) { *mgf = CKG_IBM_MGF1_SHA3_224; return CKR_OK; } if (strcmp("CKG_IBM_MGF1_SHA3_256", str) == 0) { *mgf = CKG_IBM_MGF1_SHA3_256; return CKR_OK; } if (strcmp("CKG_IBM_MGF1_SHA3_384", str) == 0) { *mgf = CKG_IBM_MGF1_SHA3_384; return CKR_OK; } if (strcmp("CKG_IBM_MGF1_SHA3_512", str) == 0) { *mgf = CKG_IBM_MGF1_SHA3_512; return CKR_OK; } return CKR_FUNCTION_FAILED; default: return CKR_FUNCTION_FAILED; } } opencryptoki-opencryptoki-451d99c/usr/lib/common/new_host.c000066400000000000000000004414061520105705100241760ustar00rootroot00000000000000/* * 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 #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 "attributes.h" #include "constant_time.h" #include "../api/apiproto.h" #include "../api/policy.h" void SC_SetFunctionList(void); CK_RV SC_Logout(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession); 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]; CK_BBOOL newdatastore; policy_t policy = sltp->TokData->policy; /* set trace info */ set_trace(t); rc = bt_init(&sltp->TokData->sess_btree, free); rc |= bt_init(&sltp->TokData->object_map_btree, free); rc |= bt_init(&sltp->TokData->sess_obj_btree, call_object_free); rc |= bt_init(&sltp->TokData->priv_token_obj_btree, call_object_free); rc |= bt_init(&sltp->TokData->publ_token_obj_btree, call_object_free); if (rc != CKR_OK) { TRACE_ERROR("Btree init failed\n"); rc = CKR_FUNCTION_FAILED; goto done; } if (strlen(sinfp->tokname)) { if (ock_snprintf(abs_tokdir_name, PATH_MAX, "%s/%s", CONFIG_PATH, sinfp->tokname) != 0) { TRACE_ERROR("token directory path buffer overflow\n"); rc = CKR_FUNCTION_FAILED; goto done; } TRACE_DEVEL("Token directory: %s\n", abs_tokdir_name); rc = init_data_store(sltp->TokData, (char *) abs_tokdir_name, sltp->TokData->data_store, sizeof(sltp->TokData->data_store)); } else { rc = init_data_store(sltp->TokData, (char *) PK_DIR, sltp->TokData->data_store, sizeof(sltp->TokData->data_store)); } if (rc != CKR_OK) { TRACE_ERROR("init_data_store failed with buffer error.\n"); goto done; } sltp->TokData->version = sinfp->version; TRACE_DEVEL("Token version: %u.%u\n", (unsigned int)(sinfp->version >> 16), (unsigned int)(sinfp->version & 0xffff)); /* Check token store encryption against policy */ newdatastore = sinfp->version >= TOK_NEW_DATA_STORE ? CK_TRUE : CK_FALSE; rc = policy->check_token_store(policy, newdatastore, token_specific.data_store.encryption_algorithm, SlotNumber, &sltp->TokData->store_strength); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: Token cannot load since data store encryption is too weak for policy.\n"); goto done; } /* 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); final_data_store(sltp->TokData); 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; final_data_store(sltp->TokData); 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); final_data_store(sltp->TokData); bt_destroy(&sltp->TokData->sess_btree); bt_destroy(&sltp->TokData->object_map_btree); bt_destroy(&sltp->TokData->sess_obj_btree); bt_destroy(&sltp->TokData->priv_token_obj_btree); bt_destroy(&sltp->TokData->publ_token_obj_btree); } } 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); 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); 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); if (token_specific.t_get_token_info != NULL) rc = token_specific.t_get_token_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; } 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(tokdata, 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 (rc != CKR_OK) { TRACE_DEVEL("compute_sha1 failed.\n"); goto done; } 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 = compute_PKCS5_PBKDF2_HMAC(tokdata, pPin, ulPinLen, dat->so_login_salt, 64, dat->so_login_it, EVP_sha512(), 256 / 8, login_key); if (rc != CKR_OK) { TRACE_DEVEL("PBKDF2 failed.\n"); 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; tokdata->nv_token_data->token_info.flags &= ~(CKF_USER_PIN_INITIALIZED | CKF_USER_PIN_LOCKED | CKF_USER_PIN_FINAL_TRY | CKF_USER_PIN_COUNT_LOW); 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 = 0, wrap_it = 0; 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_reset_error(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 = compute_PKCS5_PBKDF2_HMAC(tokdata, pPin, ulPinLen, login_salt, 64, login_it, EVP_sha512(), 256 / 8, login_key); if (rc != CKR_OK) { TRACE_DEVEL("PBKDF2 failed.\n"); goto done; } wrap_it = USER_KDF_WRAP_IT; memcpy(wrap_salt, USER_KDF_WRAP_PURPOSE, 32); rng_generate(tokdata, wrap_salt + 32, 32); rc = compute_PKCS5_PBKDF2_HMAC(tokdata, pPin, ulPinLen, wrap_salt, 64, wrap_it, EVP_sha512(), 256 / 8, wrap_key); if (rc != CKR_OK) { TRACE_DEVEL("PBKDF2 failed.\n"); 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_reset_error(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 = compute_PKCS5_PBKDF2_HMAC(tokdata, pNewPin, ulNewLen, login_salt, 64, login_it, EVP_sha512(), 256 / 8, new_login_key); if (rc != CKR_OK) { TRACE_DEVEL("PBKDF2 failed.\n"); goto done; } wrap_it = USER_KDF_WRAP_IT; memcpy(wrap_salt, USER_KDF_WRAP_PURPOSE, 32); rng_generate(tokdata, wrap_salt + 32, 32); rc = compute_PKCS5_PBKDF2_HMAC(tokdata, pNewPin, ulNewLen, wrap_salt, 64, wrap_it, EVP_sha512(), 256 / 8, new_wrap_key); if (rc != CKR_OK) { TRACE_DEVEL("PBKDF2 failed.\n"); goto done; } rc = compute_PKCS5_PBKDF2_HMAC(tokdata, pOldPin, ulOldLen, dat->user_login_salt, 64, dat->user_login_it, EVP_sha512(), 256 / 8, old_login_key); if (rc != CKR_OK) { TRACE_DEVEL("PBKDF2 failed.\n"); goto done; } rc = compute_PKCS5_PBKDF2_HMAC(tokdata, pNewPin, ulNewLen, dat->user_login_salt, 64, dat->user_login_it, EVP_sha512(), 256 / 8, new_login_key_old_salt); if (rc != CKR_OK) { TRACE_DEVEL("PBKDF2 failed.\n"); 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 = compute_PKCS5_PBKDF2_HMAC(tokdata, pNewPin, ulNewLen, login_salt, 64, login_it, EVP_sha512(), 256 / 8, new_login_key); if (rc != CKR_OK) { TRACE_DEVEL("PBKDF2 failed.\n"); goto done; } wrap_it = SO_KDF_WRAP_IT; memcpy(wrap_salt, SO_KDF_WRAP_PURPOSE, 32); rng_generate(tokdata, wrap_salt + 32, 32); rc = compute_PKCS5_PBKDF2_HMAC(tokdata, pNewPin, ulNewLen, wrap_salt, 64, wrap_it, EVP_sha512(), 256 / 8, new_wrap_key); if (rc != CKR_OK) { TRACE_DEVEL("PBKDF2 failed.\n"); goto done; } rc = compute_PKCS5_PBKDF2_HMAC(tokdata, pOldPin, ulOldLen, dat->so_login_salt, 64, dat->so_login_it, EVP_sha512(), 256 / 8, old_login_key); if (rc != CKR_OK) { TRACE_DEVEL("PBKDF2 failed.\n"); goto done; } rc = compute_PKCS5_PBKDF2_HMAC(tokdata, pNewPin, ulNewLen, dat->so_login_salt, 64, dat->so_login_it, EVP_sha512(), 256 / 8, new_login_key_old_salt); if (rc != CKR_OK) { TRACE_DEVEL("PBKDF2 failed.\n"); 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_reset_error(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_reset_error(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(tokdata, 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_reset_error(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(tokdata, 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_SessionCancel(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, CK_FLAGS flags) { 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 = session_mgr_cancel(tokdata, sess, flags); done: TRACE_INFO("SC_SessionCancel: sess = %lu\n", 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_reset_error(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 */ switch (userType) { case 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; } break; case 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; } break; case CKU_CONTEXT_SPECIFIC: /* * Although not explicitly required by the PKCS#11 standard, check that * a USER session exists. C_Login with CKU_CONTEXT_SPECIFIC is performed * due to CKA_ALWAYS_AUTHENTICATE=TRUE on a key used with an operation. * CKA_ALWAYS_AUTHENTICATE=TRUE is only allowed for keys of class * CKO_PRIVATE_KEY that have CKA_PRIVATE=TRUE. Key objects with * CKA_PRIVATE=TRUE can only be accessed in a USER session, so a * C_Login with CKU_CONTEXT_SPECIFIC can also only happen when a USER * session exists. */ if (!session_mgr_user_session_exists(tokdata)) { TRACE_ERROR("%s\n", ock_err(ERR_USER_NOT_LOGGED_IN)); rc = CKR_USER_NOT_LOGGED_IN; } if (!(sess->sign_ctx.active && sess->sign_ctx.auth_required) && !(sess->decr_ctx.active && sess->decr_ctx.auth_required)) { TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); rc = CKR_OPERATION_NOT_INITIALIZED; } break; default: rc = CKR_USER_TYPE_INVALID; TRACE_ERROR("%s\n", ock_err(ERR_USER_TYPE_INVALID)); break; } if (rc != CKR_OK) goto done; dat = &tokdata->nv_token_data->dat; switch (userType) { case 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 behavior. */ 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 (!(*flags & CKF_USER_PIN_INITIALIZED)) { TRACE_ERROR("%s\n", ock_err(ERR_USER_PIN_NOT_INITIALIZED)); rc = CKR_USER_PIN_NOT_INITIALIZED; 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 (rc != CKR_OK) { TRACE_DEVEL("compute_sha1 failed.\n"); goto done; } 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 = compute_PKCS5_PBKDF2_HMAC(tokdata, pPin, ulPinLen, dat->user_login_salt, 64, dat->user_login_it, EVP_sha512(), 256 / 8, login_key); if (rc != CKR_OK) { TRACE_DEVEL("PBKDF2 failed.\n"); goto done; } rc = compute_PKCS5_PBKDF2_HMAC(tokdata, pPin, ulPinLen, dat->user_wrap_salt, 64, dat->user_wrap_it, EVP_sha512(), 256 / 8, wrap_key); if (rc != CKR_OK) { TRACE_DEVEL("PBKDF2 failed.\n"); 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; } break; case CKU_SO: 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 behavior. */ 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 (rc != CKR_OK) { TRACE_DEVEL("compute_sha1 failed.\n"); goto done; } 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 = compute_PKCS5_PBKDF2_HMAC(tokdata, pPin, ulPinLen, dat->so_login_salt, 64, dat->so_login_it, EVP_sha512(), 256 / 8, login_key); if (rc != CKR_OK) { TRACE_DEVEL("PBKDF2 failed.\n"); goto done; } rc = compute_PKCS5_PBKDF2_HMAC(tokdata, pPin, ulPinLen, dat->so_wrap_salt, 64, dat->so_wrap_it, EVP_sha512(), 256 / 8, wrap_key); if (rc != CKR_OK) { TRACE_DEVEL("PBKDF2 failed.\n"); 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"); } break; case CKU_CONTEXT_SPECIFIC: 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 behavior. */ 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 (!(*flags & CKF_USER_PIN_INITIALIZED)) { TRACE_ERROR("%s\n", ock_err(ERR_USER_PIN_NOT_INITIALIZED)); rc = CKR_USER_PIN_NOT_INITIALIZED; goto done; } if (tokdata->version < TOK_NEW_DATA_STORE) { rc = compute_sha1(tokdata, pPin, ulPinLen, hash_sha); if (rc != CKR_OK) { TRACE_DEVEL("compute_sha1 failed.\n"); goto done; } 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); } else { rc = compute_PKCS5_PBKDF2_HMAC(tokdata, pPin, ulPinLen, dat->user_login_salt, 64, dat->user_login_it, EVP_sha512(), 256 / 8, login_key); if (rc != CKR_OK) { TRACE_DEVEL("PBKDF2 failed.\n"); 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); } /* * Reset flag in operation context to indicate that a login has been * successfully performed */ if (sess->sign_ctx.active && sess->sign_ctx.auth_required) sess->sign_ctx.auth_required = FALSE; if (sess->decr_ctx.active && sess->decr_ctx.auth_required) sess->decr_ctx.auth_required = FALSE; break; default: rc = CKR_USER_TYPE_INVALID; TRACE_ERROR("%s\n", ock_err(ERR_USER_TYPE_INVALID)); goto done; } done: if (rc == CKR_OK && userType != CKU_CONTEXT_SPECIFIC) { rc = session_mgr_login_all(tokdata, userType); if (rc != CKR_OK) TRACE_DEVEL("session_mgr_login_all failed.\n"); } /* * PKCS#11 states for failing C_Login with user type CKU_CONTEXT_SPECIFIC: * '... repeated failed re-authentication attempts may cause the PIN to be * locked. C_Login returns in this case CKR_PIN_LOCKED and this also logs * the user out from the token' */ if (userType == CKU_CONTEXT_SPECIFIC && rc == CKR_PIN_INCORRECT && pin_locked(&sess->session_info, tokdata->nv_token_data->token_info.flags)) { TRACE_DEVEL("USER pin now locked, logout the user\n"); SC_Logout(tokdata, sSession); rc = CKR_PIN_LOCKED; } 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_reset_error(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_reset_error(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; } /* Enforces policy */ rc = object_mgr_add(tokdata, sess, pTemplate, ulCount, phObject, MODE_CREATE); 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 && pTemplate[i].ulValueLen == sizeof(CK_ULONG) && pTemplate[i].pValue != NULL) { 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_reset_error(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; } /* Enforces policy */ 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_reset_error(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_reset_error(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_reset_error(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 val[4]; CK_ULONG i; attr = pTemplate; for (i = 0; i < ulCount && attr != NULL; i++, attr++) { TRACE_DEBUG("%lu: Attribute type: 0x%08lx, Value Length: %lu\n", i, attr->type, attr->ulValueLen); if (rc == CKR_OK && attr->ulValueLen != CK_UNAVAILABLE_INFORMATION) { if (attr->ulValueLen >= sizeof(val) && attr->pValue != NULL) { memset(val, 0, sizeof(val)); memcpy(val, attr->pValue, attr->ulValueLen > sizeof(val) ? sizeof(val) : attr->ulValueLen); TRACE_DEBUG("First 4 bytes: %02x %02x %02x %02x\n", val[0], val[1], val[2], val[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_reset_error(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_BYTE val[4]; CK_ULONG i; attr = pTemplate; for (i = 0; i < ulCount && attr != NULL; i++, attr++) { TRACE_DEBUG("%lu: Attribute type: 0x%08lx, Value Length: %lu\n", i, attr->type, attr->ulValueLen); if (attr->ulValueLen >= sizeof(val) && attr->pValue != NULL) { memset(val, 0, sizeof(val)); memcpy(val, attr->pValue, attr->ulValueLen > sizeof(val) ? sizeof(val) : attr->ulValueLen); TRACE_DEBUG("First 4 bytes: %02x %02x %02x %02x\n", val[0], val[1], val[2], val[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_reset_error(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_BYTE val[4]; CK_ULONG i; attr = pTemplate; for (i = 0; i < ulCount && attr != NULL; i++, attr++) { TRACE_DEBUG("%lu: Attribute type: 0x%08lx, Value Length: %lu\n", i, attr->type, attr->ulValueLen); if (attr->ulValueLen >= sizeof(val) && attr->pValue != NULL) { memset(val, 0, sizeof(val)); memcpy(val, attr->pValue, attr->ulValueLen > sizeof(val) ? sizeof(val) : attr->ulValueLen); TRACE_DEBUG("First 4 bytes: %02x %02x %02x %02x\n", val[0], val[1], val[2], val[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_reset_error(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_reset_error(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; } sess = session_mgr_find_reset_error(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 (pMechanism == NULL) { /* As per PKCS#11 v3.0 Init with NULL pMechanism cancels operation */ rc = session_mgr_cancel(tokdata, sess, CKF_ENCRYPT); goto done; } rc = valid_mech(tokdata, pMechanism, CKF_ENCRYPT); if (rc != CKR_OK) 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.count_statistics = TRUE; rc = encr_mgr_init(tokdata, sess, &sess->encr_ctx, OP_ENCRYPT_INIT, pMechanism, hKey, TRUE); 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_reset_error(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(tokdata, sess, &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_reset_error(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(tokdata, sess, &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_reset_error(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(tokdata, sess, &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; } sess = session_mgr_find_reset_error(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 (pMechanism == NULL) { /* As per PKCS#11 v3.0 Init with NULL pMechanism cancels operation */ rc = session_mgr_cancel(tokdata, sess, CKF_DECRYPT); goto done; } rc = valid_mech(tokdata, pMechanism, CKF_DECRYPT); if (rc != CKR_OK) 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.count_statistics = TRUE; rc = decr_mgr_init(tokdata, sess, &sess->decr_ctx, OP_DECRYPT_INIT, pMechanism, hKey, TRUE, TRUE); 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; unsigned int mask; 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_reset_error(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); /* (!is_rsa_mechanism(sess->decr_ctx.mech.mechanism) && rc != CKR_OK) */ mask = constant_time_is_zero( is_rsa_mechanism(sess->decr_ctx.mech.mechanism)); mask &= ~constant_time_eq(rc, CKR_OK); if (mask) TRACE_DEVEL("decr_mgr_decrypt() failed.\n"); done: /* (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) */ mask = ~constant_time_eq(rc, CKR_OK); mask |= constant_time_is_zero(length_only); mask &= ~constant_time_eq(rc, CKR_BUFFER_TOO_SMALL); if (mask) { if (sess) decr_mgr_cleanup(tokdata, sess, &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; unsigned int mask; 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_reset_error(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); /* (!is_rsa_mechanism(sess->decr_ctx.mech.mechanism) && rc != CKR_OK) */ mask = constant_time_is_zero( is_rsa_mechanism(sess->decr_ctx.mech.mechanism)); mask &= ~constant_time_eq(rc, CKR_OK); if (mask) TRACE_DEVEL("decr_mgr_decrypt_update() failed.\n"); done: /* (rc != CKR_OK && rc != CKR_BUFFER_TOO_SMALL */ mask = ~constant_time_eq(rc, CKR_OK); mask &= ~constant_time_eq(rc, CKR_BUFFER_TOO_SMALL); if (mask) { if (sess) decr_mgr_cleanup(tokdata, sess, &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; unsigned int mask; 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_reset_error(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); /* (!is_rsa_mechanism(sess->decr_ctx.mech.mechanism) && rc != CKR_OK) */ mask = constant_time_is_zero( is_rsa_mechanism(sess->decr_ctx.mech.mechanism)); mask &= ~constant_time_eq(rc, CKR_OK); if (mask) TRACE_DEVEL("decr_mgr_decrypt_final() failed.\n"); done: /* (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) */ mask = ~constant_time_eq(rc, CKR_OK); mask |= constant_time_is_zero(length_only); mask &= ~constant_time_eq(rc, CKR_BUFFER_TOO_SMALL); if (mask) { if (sess) decr_mgr_cleanup(tokdata, sess, &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; } sess = session_mgr_find_reset_error(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 (pMechanism == NULL) { /* As per PKCS#11 v3.0 Init with NULL pMechanism cancels operation */ rc = session_mgr_cancel(tokdata, sess, CKF_DIGEST); goto done; } rc = valid_mech(tokdata, pMechanism, CKF_DIGEST); if (rc != CKR_OK) goto done; if (sess->digest_ctx.active == TRUE) { TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); rc = CKR_OPERATION_ACTIVE; goto done; } sess->digest_ctx.count_statistics = TRUE; rc = digest_mgr_init(tokdata, sess, &sess->digest_ctx, pMechanism, TRUE); 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_reset_error(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_reset_error(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_reset_error(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_reset_error(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; } sess = session_mgr_find_reset_error(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 (pMechanism == NULL) { /* As per PKCS#11 v3.0 Init with NULL pMechanism cancels operation */ rc = session_mgr_cancel(tokdata, sess, CKF_SIGN); goto done; } rc = valid_mech(tokdata, pMechanism, CKF_SIGN); if (rc != CKR_OK) goto done; if (sess->sign_ctx.active == TRUE) { rc = CKR_OPERATION_ACTIVE; TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); goto done; } sess->sign_ctx.count_statistics = TRUE; rc = sign_mgr_init(tokdata, sess, &sess->sign_ctx, pMechanism, FALSE, hKey, TRUE, TRUE); 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; } sess = session_mgr_find_reset_error(tokdata, sSession->sessionh); if (!sess) { TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); rc = CKR_SESSION_HANDLE_INVALID; goto done; } if (!pData || !pulSignatureLen) { TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); rc = CKR_ARGUMENTS_BAD; 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)) { if (sess != NULL) sign_mgr_cleanup(tokdata, sess, &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; } sess = session_mgr_find_reset_error(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) { TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); rc = CKR_ARGUMENTS_BAD; 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 && sess != NULL) sign_mgr_cleanup(tokdata, sess, &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; } sess = session_mgr_find_reset_error(tokdata, sSession->sessionh); if (!sess) { TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); rc = CKR_SESSION_HANDLE_INVALID; goto done; } if (!pulSignatureLen) { TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); rc = CKR_ARGUMENTS_BAD; 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)) { if (sess != NULL) sign_mgr_cleanup(tokdata, sess, &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; } sess = session_mgr_find_reset_error(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 (pMechanism == NULL) { /* As per PKCS#11 v3.0 Init with NULL pMechanism cancels operation */ rc = session_mgr_cancel(tokdata, sess, CKF_SIGN_RECOVER); goto done; } rc = valid_mech(tokdata, pMechanism, CKF_SIGN_RECOVER); if (rc != CKR_OK) 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, TRUE, TRUE); 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; } sess = session_mgr_find_reset_error(tokdata, sSession->sessionh); if (!sess) { TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); rc = CKR_SESSION_HANDLE_INVALID; goto done; } if (!pData || !pulSignatureLen) { TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); rc = CKR_ARGUMENTS_BAD; 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)) { if (sess != NULL) sign_mgr_cleanup(tokdata, sess, &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; } static CK_RV VerifyInit(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey, 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; } sess = session_mgr_find_reset_error(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 (pMechanism == NULL) { /* As per PKCS#11 v3.0 Init with NULL pMechanism cancels operation */ rc = session_mgr_cancel(tokdata, sess, CKF_VERIFY); goto done; } rc = valid_mech(tokdata, pMechanism, CKF_VERIFY); if (rc != CKR_OK) goto done; if (sess->verify_ctx.active == TRUE) { rc = CKR_OPERATION_ACTIVE; TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); goto done; } if (pSignature != NULL && ulSignatureLen != 0) { /* Save signature in context for later verification */ sess->verify_ctx.saved_signature = malloc(ulSignatureLen); if (sess->verify_ctx.saved_signature == NULL) { rc = CKR_HOST_MEMORY; TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); goto done; } memcpy(sess->verify_ctx.saved_signature, pSignature, ulSignatureLen); sess->verify_ctx.saved_signature_len = ulSignatureLen; } sess->verify_ctx.count_statistics = TRUE; rc = verify_mgr_init(tokdata, sess, &sess->verify_ctx, pMechanism, FALSE, hKey, TRUE); if (rc != CKR_OK) TRACE_DEVEL("verify_mgr_init() failed.\n"); done: TRACE_INFO("C_Verify%sInit: rc = 0x%08lx, sess = %ld, mech = 0x%lx\n", pSignature != NULL && ulSignatureLen != 0 ? "Signature" : "", 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_VerifyInit(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { return VerifyInit(tokdata, sSession, pMechanism, hKey, NULL, 0); } static CK_RV 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; } sess = session_mgr_find_reset_error(tokdata, sSession->sessionh); if (!sess) { TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); rc = CKR_SESSION_HANDLE_INVALID; goto done; } if (!pData) { TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); rc = CKR_ARGUMENTS_BAD; 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 (sess->verify_ctx.saved_signature == NULL && pSignature == NULL) { /* Operation was initialized with C_VerifyInit() */ TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); rc = CKR_ARGUMENTS_BAD; goto done; } if (sess->verify_ctx.saved_signature != NULL && pSignature != NULL) { /* Operation was initialized with C_VerifySignatureInit() */ TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); rc = CKR_OPERATION_NOT_INITIALIZED; goto done; } rc = verify_mgr_verify(tokdata, sess, &sess->verify_ctx, pData, ulDataLen, sess->verify_ctx.saved_signature != NULL ? sess->verify_ctx.saved_signature : pSignature, sess->verify_ctx.saved_signature != NULL ? sess->verify_ctx.saved_signature_len : ulSignatureLen); if (rc != CKR_OK) TRACE_DEVEL("verify_mgr_verify() failed.\n"); done: if (sess != NULL) verify_mgr_cleanup(tokdata, sess, &sess->verify_ctx); TRACE_INFO("C_Verify%s: rc = 0x%08lx, sess = %ld, datalen = %lu\n", pSignature == NULL ? "Signature" : "", rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, ulDataLen); 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) { return Verify(tokdata, sSession, pData, ulDataLen, pSignature, ulSignatureLen); } static CK_RV VerifyUpdate(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen, CK_BBOOL verify_message) { 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_reset_error(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) { TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); rc = CKR_ARGUMENTS_BAD; 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 ((sess->verify_ctx.saved_signature != NULL) != verify_message) { 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 && sess != NULL) verify_mgr_cleanup(tokdata, sess, &sess->verify_ctx); TRACE_INFO("C_Verify%sUpdate: rc = 0x%08lx, sess = %ld, datalen = %lu\n", (sess != NULL && sess->verify_ctx.saved_signature != NULL) ? "Signature" : "", rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, ulPartLen); 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) { return VerifyUpdate(tokdata, sSession, pPart, ulPartLen, FALSE); } static CK_RV 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; } sess = session_mgr_find_reset_error(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 (pSignature == NULL && sess->verify_ctx.saved_signature == NULL) { /* Operation was initialized with C_VerifyInit() */ rc = CKR_OPERATION_NOT_INITIALIZED; TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); goto done; } if (pSignature != NULL && sess->verify_ctx.saved_signature != NULL) { /* Operation was initialized with C_VerifySignatureInit() */ 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, sess->verify_ctx.saved_signature != NULL ? sess->verify_ctx.saved_signature : pSignature, sess->verify_ctx.saved_signature != NULL ? sess->verify_ctx.saved_signature_len : ulSignatureLen); if (rc != CKR_OK) TRACE_DEVEL("verify_mgr_verify_final() failed.\n"); done: if (sess != NULL) verify_mgr_cleanup(tokdata, sess, &sess->verify_ctx); TRACE_INFO("C_Verify%sFinal: rc = 0x%08lx, sess = %ld\n", pSignature == NULL ? "Signature" : "", rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle); 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) { if (pSignature == NULL || ulSignatureLen == 0) { TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); return CKR_ARGUMENTS_BAD; } return VerifyFinal(tokdata, sSession, pSignature, ulSignatureLen); } 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; } sess = session_mgr_find_reset_error(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 (pMechanism == NULL) { /* As per PKCS#11 v3.0 Init with NULL pMechanism cancels operation */ rc = session_mgr_cancel(tokdata, sess, CKF_VERIFY_RECOVER); goto done; } rc = valid_mech(tokdata, pMechanism, CKF_VERIFY_RECOVER); if (rc != CKR_OK) 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, TRUE); 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; } sess = session_mgr_find_reset_error(tokdata, sSession->sessionh); if (!sess) { TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); rc = CKR_SESSION_HANDLE_INVALID; goto done; } if (!pSignature || !pulDataLen) { TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); rc = CKR_ARGUMENTS_BAD; 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)) { if (sess != NULL) verify_mgr_cleanup(tokdata, sess, &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_VerifySignatureInit(STDLL_TokData_t *tokdata, ST_SESSION_T *sSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen) { if (pSignature == NULL || ulSignatureLen == 0) { TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); return CKR_ARGUMENTS_BAD; } return VerifyInit(tokdata, sSession, pMechanism, hKey, pSignature, ulSignatureLen); } CK_RV SC_VerifySignature(STDLL_TokData_t *tokdata, ST_SESSION_T *sSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen) { return Verify(tokdata, sSession, pData, ulDataLen, NULL, 0); } CK_RV SC_VerifySignatureUpdate(STDLL_TokData_t *tokdata, ST_SESSION_T *sSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen) { return VerifyUpdate(tokdata, sSession, pPart, ulPartLen, TRUE); } CK_RV SC_VerifySignatureFinal(STDLL_TokData_t *tokdata, ST_SESSION_T *sSession) { return VerifyFinal(tokdata, sSession, NULL, 0); } 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) { CK_RV rc; rc = SC_EncryptUpdate(tokdata, sSession, pPart, ulPartLen, pEncryptedPart, pulEncryptedPartLen); if (rc != CKR_OK || pEncryptedPart == NULL) goto out; rc = SC_DigestUpdate(tokdata, sSession, pPart, ulPartLen); out: return rc; } 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) { CK_RV rc; rc = SC_DecryptUpdate(tokdata, sSession, pEncryptedPart, ulEncryptedPartLen, pPart, pulPartLen); if (rc != CKR_OK || pPart == NULL) goto out; rc = SC_DigestUpdate(tokdata, sSession, pPart, *pulPartLen); out: return rc; } 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) { CK_RV rc; rc = SC_EncryptUpdate(tokdata, sSession, pPart, ulPartLen, pEncryptedPart, pulEncryptedPartLen); if (rc != CKR_OK || pEncryptedPart == NULL) goto out; rc = SC_SignUpdate(tokdata, sSession, pPart, ulPartLen); out: return rc; } 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) { CK_RV rc; rc = SC_DecryptUpdate(tokdata, sSession, pEncryptedPart, ulEncryptedPartLen, pPart, pulPartLen); if (rc != CKR_OK || pPart == NULL) goto out; rc = SC_VerifyUpdate(tokdata, sSession, pPart, *pulPartLen); out: return rc; } 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_reset_error(tokdata, sSession->sessionh); if (!sess) { TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); rc = CKR_SESSION_HANDLE_INVALID; goto done; } rc = tokdata->policy->is_mech_allowed(tokdata->policy, pMechanism, NULL, POLICY_CHECK_KEYGEN, sess); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: Key generation mechanism not allowed\n"); 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, TRUE, OP_KEYGEN); 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_BYTE val[4]; CK_ULONG i; attr = pTemplate; for (i = 0; i < ulCount && attr != NULL; i++, attr++) { TRACE_DEBUG("%lu: Attribute type: 0x%08lx, Value Length: %lu\n", i, attr->type, attr->ulValueLen); if (attr->ulValueLen >= sizeof(val) && attr->pValue != NULL) { memset(val, 0, sizeof(val)); memcpy(val, attr->pValue, attr->ulValueLen > sizeof(val) ? sizeof(val) : attr->ulValueLen); TRACE_DEBUG("First 4 bytes: %02x %02x %02x %02x\n", val[0], val[1], val[2], val[3]); } } #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_reset_error(tokdata, sSession->sessionh); if (!sess) { TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); rc = CKR_SESSION_HANDLE_INVALID; goto done; } rc = tokdata->policy->is_mech_allowed(tokdata->policy, pMechanism, NULL, POLICY_CHECK_KEYGEN, sess); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: Keypair generation mechanism not allowed\n"); 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, TRUE, OP_KEYGEN); 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; 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; for (i = 0; i < ulPublicKeyAttributeCount && attr != NULL; i++, attr++) { TRACE_DEBUG_DUMPATTR(attr); } TRACE_DEBUG("Private Template:\n"); attr = pPrivateKeyTemplate; for (i = 0; i < ulPrivateKeyAttributeCount && attr != NULL; i++, attr++) { TRACE_DEBUG_DUMPATTR(attr); } #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_reset_error(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, TRUE, OP_WRAP); 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_reset_error(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, TRUE, OP_UNWRAP); 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 val[4]; CK_ULONG i; attr = pTemplate; for (i = 0; i < ulCount && attr != NULL; i++, attr++) { TRACE_DEBUG("%lu: Attribute type: 0x%08lx, Value Length: %lu\n", i, attr->type, attr->ulValueLen); if (attr->ulValueLen >= sizeof(val) && attr->pValue != NULL) { memset(val, 0, sizeof(val)); memcpy(val, attr->pValue, attr->ulValueLen > sizeof(val) ? sizeof(val) : attr->ulValueLen); TRACE_DEBUG("First 4 bytes: %02x %02x %02x %02x\n", val[0], val[1], val[2], val[3]); } } #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_reset_error(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, TRUE, OP_DERIVE); 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 val[4]; 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; for (i = 0; i < ulCount && attr != NULL; i++, attr++) { TRACE_DEBUG("%lu: Attribute type: 0x%08lx, Value Length: %lu\n", i, attr->type, attr->ulValueLen); if (attr->ulValueLen >= sizeof(val) && attr->pValue != NULL) { memset(val, 0, sizeof(val)); memcpy(val, attr->pValue, attr->ulValueLen > sizeof(val) ? sizeof(val) : attr->ulValueLen); TRACE_DEBUG("First 4 bytes: %02x %02x %02x %02x\n", val[0], val[1], val[2], val[3]); } } #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_reset_error(tokdata, sSession->sessionh); if (!sess) { TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); rc = CKR_SESSION_HANDLE_INVALID; goto done; } if (ulRandomLen == 0) 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; } CK_RV SC_EncapsulateKey(STDLL_TokData_t *tokdata, ST_SESSION_T *sSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hPublicKey, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, CK_BYTE_PTR pCiphertext, CK_ULONG_PTR pulCiphertextLen, CK_OBJECT_HANDLE_PTR phKey) { 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 || !pulCiphertextLen) { TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); rc = CKR_ARGUMENTS_BAD; goto done; } rc = valid_mech(tokdata, pMechanism, CKF_ENCAPSULATE); if (rc != CKR_OK) goto done; if (!pCiphertext) length_only = TRUE; sess = session_mgr_find_reset_error(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_encapsulate_key(tokdata, sess, length_only, pMechanism, hPublicKey, pTemplate, ulAttributeCount, pCiphertext, pulCiphertextLen, phKey, TRUE); if (rc != CKR_OK) TRACE_DEVEL("key_mgr_encapsulate_key() failed.\n"); done: TRACE_INFO("SC_EncapsulateKey: rc = 0x%08lx, sess = %ld, priv key = %lu, " "ciphertext = %lu, encpsed key = %lu\n", rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, hPublicKey, (pulCiphertextLen ? *pulCiphertextLen : 0), (phKey ? *phKey : 0)); if (sess != NULL) session_mgr_put(tokdata, sess); return rc; } CK_RV SC_DecapsulateKey(STDLL_TokData_t *tokdata, ST_SESSION_T *sSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hPrivateKey, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, CK_BYTE_PTR pCiphertext, CK_ULONG ulCiphertextLen, 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 || !pCiphertext) { TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); rc = CKR_ARGUMENTS_BAD; goto done; } rc = valid_mech(tokdata, pMechanism, CKF_DECAPSULATE); if (rc != CKR_OK) goto done; sess = session_mgr_find_reset_error(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_decapsulate_key(tokdata, sess, pMechanism, hPrivateKey, pTemplate, ulAttributeCount, pCiphertext, ulCiphertextLen, phKey, TRUE); if (rc != CKR_OK) TRACE_DEVEL("key_mgr_decapsulate_key() failed.\n"); done: TRACE_INFO("SC_DecapsulateKey: rc = 0x%08lx, sess = %ld, pub key = %lu, " "encpsed key = %lu\n", rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, hPrivateKey, (phKey ? *phKey : 0)); if (sess != NULL) session_mgr_put(tokdata, sess); return rc; } CK_RV SC_IBM_ReencryptSingle(STDLL_TokData_t *tokdata, ST_SESSION_T *sSession, CK_MECHANISM_PTR pDecrMech, CK_OBJECT_HANDLE hDecrKey, CK_MECHANISM_PTR pEncrMech, CK_OBJECT_HANDLE hEncrKey, CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen, CK_BYTE_PTR pReencryptedData, CK_ULONG_PTR pulReencryptedDataLen) { 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 (!pDecrMech || !pEncrMech) { TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); rc = CKR_ARGUMENTS_BAD; goto done; } sess = session_mgr_find_reset_error(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, pDecrMech, CKF_DECRYPT); if (rc != CKR_OK) goto done; rc = valid_mech(tokdata, pEncrMech, CKF_ENCRYPT); 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->decr_ctx.active == TRUE || sess->encr_ctx.active == TRUE) { rc = CKR_OPERATION_ACTIVE; TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); goto done; } sess->decr_ctx.count_statistics = TRUE; sess->encr_ctx.count_statistics = TRUE; rc = encr_mgr_reencrypt_single(tokdata, sess, &sess->decr_ctx, pDecrMech, hDecrKey, &sess->encr_ctx, pEncrMech, hEncrKey, pEncryptedData, ulEncryptedDataLen, pReencryptedData, pulReencryptedDataLen); if (rc != CKR_OK) TRACE_DEVEL("encr_mgr_reencrypt_single() failed.\n"); done: TRACE_INFO("SC_IBM_ReencryptSingle: rc = 0x%08lx, sess = %ld, " "decrmech = 0x%lx, encrmech = 0x%lx\n", rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, (pDecrMech ? pDecrMech->mechanism : (CK_ULONG)-1), (pEncrMech ? pEncrMech->mechanism : (CK_ULONG)-1)); if (sess != NULL) session_mgr_put(tokdata, sess); return rc; } CK_RV SC_HandleEvent(STDLL_TokData_t *tokdata, unsigned int event_type, unsigned int event_flags, const char *payload, unsigned int payload_len) { CK_RV rc; if (token_specific.t_handle_event == NULL) return CKR_FUNCTION_NOT_SUPPORTED; rc = token_specific.t_handle_event(tokdata, event_type, event_flags, payload, payload_len); TRACE_INFO("SC_HandleEvent: rc = 0x%08lx, event_type = 0x%08x, " "event_flags = 0x%08x\n", rc, event_type, event_flags); return rc; } 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 = SC_DigestEncryptUpdate; function_list.ST_DecryptDigestUpdate = SC_DecryptDigestUpdate; function_list.ST_SignEncryptUpdate = SC_SignEncryptUpdate; function_list.ST_DecryptVerifyUpdate = 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; function_list.ST_SessionCancel = SC_SessionCancel; function_list.ST_EncapsulateKey = SC_EncapsulateKey; function_list.ST_DecapsulateKey = SC_DecapsulateKey; function_list.ST_VerifySignatureInit = SC_VerifySignatureInit; function_list.ST_VerifySignature = SC_VerifySignature; function_list.ST_VerifySignatureUpdate = SC_VerifySignatureUpdate; function_list.ST_VerifySignatureFinal = SC_VerifySignatureFinal; function_list.ST_IBM_ReencryptSingle = SC_IBM_ReencryptSingle; function_list.ST_HandleEvent = SC_HandleEvent; } opencryptoki-opencryptoki-451d99c/usr/lib/common/obj_mgr.c000066400000000000000000002557201520105705100237710ustar00rootroot00000000000000/* * 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 #include #include "pkcs11types.h" #include "defs.h" #include "host_defs.h" #include "h_extern.h" #include "attributes.h" #include "tok_spec_struct.h" #include "trace.h" #include "ock_syslog.h" #include "../api/apiproto.h" #include "../api/policy.h" static CK_RV object_mgr_check_session(SESSION *sess, CK_BBOOL priv_obj, CK_BBOOL sess_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 (priv_obj) { TRACE_ERROR("%s\n", ock_err(ERR_USER_NOT_LOGGED_IN)); return CKR_USER_NOT_LOGGED_IN; } if (!sess_obj) { 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) { 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) { 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) { TRACE_ERROR("%s\n", ock_err(ERR_USER_NOT_LOGGED_IN)); return CKR_USER_NOT_LOGGED_IN; } } return CKR_OK; } CK_RV object_mgr_add(STDLL_TokData_t *tokdata, SESSION *sess, CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE *handle, CK_ULONG mode) { OBJECT *o = NULL; CK_BBOOL priv_obj, sess_obj; CK_RV rc; CK_OBJECT_CLASS class; CK_KEY_TYPE keytype; CK_BYTE *spki = NULL; CK_ULONG spki_len = 0; CK_ATTRIBUTE *spki_attr = NULL, *value_attr = NULL, *vallen_attr = NULL; if (!sess || !pTemplate || !handle) { TRACE_ERROR("Invalid function arguments.\n"); return CKR_ARGUMENTS_BAD; } rc = object_create(tokdata, pTemplate, ulCount, &o, mode); if (rc != CKR_OK) { TRACE_DEVEL("Object Create failed.\n"); goto done; } if (token_specific.t_check_obj_access != NULL) { rc = token_specific.t_check_obj_access(tokdata, o, TRUE); if (rc != CKR_OK) { TRACE_DEVEL("check_obj_access rejected access to object.\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; } } rc = template_attribute_get_ulong(o->template, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the object.\n"); goto done; } switch(class) { case CKO_PUBLIC_KEY: case CKO_PRIVATE_KEY: /* Skip if there is already a non-empty CKA_PUBLIC_KEY_INFO */ if (template_attribute_get_non_empty(o->template, CKA_PUBLIC_KEY_INFO, &spki_attr) == CKR_OK) break; rc = template_attribute_get_ulong(o->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key object.\n"); goto done; } /* * Try to extract the SPKI and add CKA_PUBLIC_KEY_INFO to the key. * This may fail if the public key info can not be reconstructed from * the private key (e.g. because its a secure key token). */ rc = publ_key_get_spki(o->template, keytype, FALSE, &spki, &spki_len, class == CKO_PRIVATE_KEY); if (rc == CKR_OK && spki != NULL && spki_len > 0) { rc = build_attribute(CKA_PUBLIC_KEY_INFO, spki, spki_len, &spki_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto done; } rc = template_update_attribute(o->template, spki_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); free(spki_attr); goto done; } } break; case CKO_SECRET_KEY: rc = template_attribute_get_ulong(o->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key object.\n"); goto done; } switch (keytype) { case CKK_GENERIC_SECRET: case CKK_SHA_1_HMAC: case CKK_SHA256_HMAC: case CKK_SHA384_HMAC: case CKK_SHA512_HMAC: case CKK_SHA224_HMAC: case CKK_SHA3_224_HMAC: case CKK_SHA3_256_HMAC: case CKK_SHA3_384_HMAC: case CKK_SHA3_512_HMAC: case CKK_SHA512_224_HMAC: case CKK_SHA512_256_HMAC: case CKK_AES: case CKK_AES_XTS: rc = template_attribute_get_non_empty(o->template, CKA_VALUE, &value_attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key object.\n"); goto done; } rc = build_attribute(CKA_VALUE_LEN, (CK_BYTE *)&value_attr->ulValueLen, sizeof(CK_ULONG), &vallen_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto done; } rc = template_update_attribute(o->template, vallen_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); free(vallen_attr); goto done; } break; default: break; } break; default: break; } sess_obj = object_is_session_object(o); priv_obj = object_is_private(o); rc = object_mgr_check_session(sess, priv_obj, sess_obj); if (rc != CKR_OK) goto done; // okay, object is created and the session permissions look okay. // add the object to the appropriate list and assign an object handle // rc = object_mgr_create_final(tokdata, sess, o, handle); done: if ((rc != CKR_OK) && (o != NULL)) { object_free(o); o = NULL; } if (spki != NULL) free(spki); if (rc == CKR_OK) TRACE_DEVEL("Object created: handle: %lu\n", *handle); 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_RV rc; 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; } if (!object_is_copyable(old_obj)) { TRACE_ERROR("Object is not copyable\n"); rc = CKR_ACTION_PROHIBITED; goto done; } rc = object_copy(tokdata, sess, pTemplate, ulCount, old_obj, &new_obj); if (rc != CKR_OK) { TRACE_DEVEL("Object Copy failed.\n"); goto done; } sess_obj = object_is_session_object(new_obj); priv_obj = object_is_private(new_obj); rc = object_mgr_check_session(sess, priv_obj, sess_obj); if (rc != CKR_OK) goto done; if (token_specific.t_check_obj_access != NULL) { rc = token_specific.t_check_obj_access(tokdata, new_obj, TRUE); if (rc != CKR_OK) { TRACE_DEVEL("check_obj_access rejected access to object.\n"); goto done; } } // okay, object is created and the session permissions look okay. // add the object to the appropriate list and assign an object handle // rc = object_mgr_create_final(tokdata, sess, new_obj, new_handle); done: if ((rc != CKR_OK) && (new_obj != NULL)) { object_free(new_obj); new_obj = NULL; } object_put(tokdata, old_obj, TRUE); old_obj = NULL; 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; } } if (token_specific.t_check_obj_access != NULL) { rc = token_specific.t_check_obj_access(tokdata, o, TRUE); if (rc != CKR_OK) { TRACE_DEVEL("check_obj_access rejected access to object.\n"); object_free(o); return rc; } } *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; char fname[PATH_MAX] = ""; int fd; if (!sess || !obj || !handle) { TRACE_ERROR("Invalid function arguments.\n"); return CKR_FUNCTION_FAILED; } TRACE_DEBUG("Attributes at create final:\n"); TRACE_DEBUG_DUMPTEMPL(obj->template); rc = tokdata->policy->store_object_strength(tokdata->policy, &obj->strength, policy_get_attr_from_template, obj->template, NULL, sess); if (rc != CKR_OK) { TRACE_ERROR("Failed to store acceptable object strength.\n"); return rc; } 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 { // 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; } } /* create unique file name in token directory */ if (ock_snprintf(fname, sizeof(fname), "%s/" PK_LITE_OBJ_DIR "/%s", tokdata->data_store, "OBXXXXXX") != 0) { TRACE_ERROR("buffer overflow for object path"); rc = CKR_FUNCTION_FAILED; goto done; } fd = mkstemp(fname); if (fd < 0) { TRACE_ERROR("mkstemp failed with: %s\n", strerror(errno)); rc = CKR_FUNCTION_FAILED; goto done; } close(fd); /* written and permissions set by save_token_object */ obj->session = NULL; memcpy(&obj->name, &fname[strlen(fname) - 8], 8); rc = save_token_object(tokdata, obj); if (rc != CKR_OK) goto done; // add the object identifier to the shared memory segment // object_mgr_add_to_shm(obj, tokdata->global_shm); // 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); } } if (rc == CKR_OK) TRACE_DEVEL("Object created: handle: %lu\n", *handle); else if (fname[0] != '\0') remove(fname); 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; CK_BBOOL priv_obj; CK_BBOOL sess_obj; UNUSED(sess); rc = object_mgr_find_in_map1(tokdata, handle, &o, READ_LOCK); if (rc != CKR_OK || o == NULL) { TRACE_DEVEL("object_mgr_find_in_map1 failed.\n"); return CKR_OBJECT_HANDLE_INVALID; } if (!object_is_destroyable(o)) { TRACE_ERROR("Object is not destroyable\n"); object_put(tokdata, o, TRUE); o = NULL; return CKR_ACTION_PROHIBITED; } sess_obj = object_is_session_object(o); priv_obj = object_is_private(o); rc = object_mgr_check_session(sess, priv_obj, sess_obj); object_put(tokdata, o, TRUE); o = NULL; if (rc != CKR_OK) return rc; /* 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: 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 handle: %lu\n", ock_err(ERR_OBJECT_HANDLE_INVALID), handle); 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 handle: %lu\n", ock_err(ERR_OBJECT_HANDLE_INVALID), handle); return CKR_OBJECT_HANDLE_INVALID; } rc = object_lock(obj, lock_type); if (rc != CKR_OK) { object_put(tokdata, obj, FALSE); obj = NULL; return rc; } if (token_specific.t_check_obj_access != NULL) { rc = token_specific.t_check_obj_access(tokdata, obj, FALSE); if (rc != CKR_OK) { TRACE_DEVEL("check_obj_access rejected access to object.\n"); object_put(tokdata, obj, lock_type != NO_LOCK); obj = NULL; return rc; } } TRACE_DEVEL("Object found: handle: %lu\n", handle); *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 handle: %lu\n", ock_err(ERR_OBJECT_HANDLE_INVALID), handle); 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 handle: %lu\n", ock_err(ERR_OBJECT_HANDLE_INVALID), handle); 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 object lock */ rc = object_lock(obj, lock_type); if (rc != CKR_OK) goto done; locked = TRUE; rc = object_mgr_check_shm(tokdata, obj, lock_type); if (rc != CKR_OK) { TRACE_DEVEL("object_mgr_check_shm failed.\n"); goto done; } } if (!locked) { rc = object_lock(obj, lock_type); if (rc != CKR_OK) goto done; } if (token_specific.t_check_obj_access != NULL) { rc = token_specific.t_check_obj_access(tokdata, obj, FALSE); if (rc != CKR_OK) { TRACE_DEVEL("check_obj_access rejected access to object.\n"); goto done; } } done: if (rc == CKR_OK) { TRACE_DEVEL("Object found: handle: %lu\n", handle); *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, READ_LOCK); 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_INVALID_HANDLE; CK_BBOOL match = FALSE, flag = FALSE; CK_OBJECT_HANDLE *find_list; CK_ULONG find_len; CK_OBJECT_CLASS class; 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_get_ulong(obj->template, CKA_CLASS, &class) == CKR_OK) { if (class == 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_get_bool(obj->template, CKA_HIDDEN, &flag) == CKR_OK) { if (flag == TRUE) goto done; } if (token_specific.t_check_obj_access != NULL) { rc = token_specific.t_check_obj_access(tokdata, obj, FALSE); if (rc != CKR_OK) { TRACE_DEVEL("check_obj_access rejected access to object.\n"); 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; find_len = fa->sess->find_len + 15; find_list = (CK_OBJECT_HANDLE *)realloc(fa->sess->find_list, find_len * sizeof(CK_OBJECT_HANDLE)); if (!find_list) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); goto done; } fa->sess->find_list = find_list; fa->sess->find_len = find_len; } } 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_OBJECT_CLASS class = 0; CK_BBOOL flag = FALSE; 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) { TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); return CKR_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 rc = get_ulong_attribute_by_type(pTemplate, ulCount, CKA_CLASS, &class); if (rc == CKR_ATTRIBUTE_VALUE_INVALID) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } if (rc == CKR_OK && class == CKO_HW_FEATURE) fa.hw_feature = TRUE; rc = get_bool_attribute_by_type(pTemplate, ulCount, CKA_HIDDEN, &flag); if (rc == CKR_ATTRIBUTE_VALUE_INVALID) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } if (rc == CKR_OK && flag == 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; } // //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, CK_ULONG data_size, const char *fname) { OBJECT *obj = NULL; CK_BBOOL priv; CK_RV rc, tmp; TOK_OBJ_ENTRY *entry = NULL; if (!data) { TRACE_ERROR("Invalid function argument.\n"); return CKR_FUNCTION_FAILED; } // The calling stack MUST have the mutex // to many grab it now. obj = oldObj; rc = object_restore_withSize(tokdata->policy, data, &obj, oldObj != NULL, data_size, fname); if (rc != CKR_OK) { TRACE_DEVEL("object_restore_withSize failed.\n"); return rc; } rc = XProcLock(tokdata); if (rc != CKR_OK) { TRACE_ERROR("Failed to get Process Lock.\n"); if (oldObj == NULL) object_free(obj); return rc; } if (oldObj != NULL) { /* Update of existing object */ rc = object_mgr_get_shm_entry_for_obj(tokdata, obj, &entry); if (rc == CKR_OK) { obj->count_lo = entry->count_lo; obj->count_hi = entry->count_hi; } } else { /* New object */ 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; object_free(obj); 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; object_free(obj); 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; goto unlock; } } else { rc = object_mgr_get_shm_entry_for_obj(tokdata, obj, &entry); if (rc == CKR_OK) { obj->count_lo = entry->count_lo; obj->count_hi = entry->count_hi; } } } 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; goto unlock; } } else { rc = object_mgr_get_shm_entry_for_obj(tokdata, obj, &entry); if (rc == CKR_OK) { obj->count_lo = entry->count_lo; obj->count_hi = entry->count_hi; } } } } unlock: tmp = XProcUnLock(tokdata); if (tmp != CKR_OK) TRACE_ERROR("Failed to release Process Lock.\n"); if (rc == CKR_OK) rc = tmp; return rc; } /** * Save the token object to disk and update the shared memory segment. */ CK_RV object_mgr_save_token_object(STDLL_TokData_t *tokdata, OBJECT *obj) { TOK_OBJ_ENTRY *entry = NULL; CK_ULONG index; CK_RV rc; 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; } if (object_is_private(obj)) { if (tokdata->global_shm->num_priv_tok_obj == 0) { TRACE_DEVEL("%s\n", ock_err(ERR_OBJECT_HANDLE_INVALID)); rc = CKR_OBJECT_HANDLE_INVALID; XProcUnLock(tokdata); goto done; } rc = object_mgr_search_shm_for_obj(tokdata->global_shm-> priv_tok_objs, 0, tokdata->global_shm-> 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 { if (tokdata->global_shm->num_publ_tok_obj == 0) { TRACE_DEVEL("%s\n", ock_err(ERR_OBJECT_HANDLE_INVALID)); rc = CKR_OBJECT_HANDLE_INVALID; XProcUnLock(tokdata); goto done; } rc = object_mgr_search_shm_for_obj(tokdata->global_shm-> publ_tok_objs, 0, tokdata->global_shm-> 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]; } rc = save_token_object(tokdata, obj); if (rc != CKR_OK) { TRACE_ERROR("Failed to save token object, rc=0x%lx.\n",rc); XProcUnLock(tokdata); goto done; } entry->count_lo = obj->count_lo; entry->count_hi = obj->count_hi; rc = XProcUnLock(tokdata); if (rc != CKR_OK) { TRACE_ERROR("Failed to release Process Lock.\n"); goto done; } done: return rc; } static CK_BBOOL modifiable_override(CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount) { CK_ULONG i, k; CK_BBOOL found; const CK_ATTRIBUTE_TYPE always_modifiable_attrs[] = { CKA_IBM_OPAQUE, CKA_IBM_OPAQUE_REENC, CKA_IBM_OPAQUE_OLD, }; if (!token_specific.secure_key_token) return CK_FALSE; /* Check if template only contains always modifiable attrs */ for (i = 0; i < ulCount; i++) { found = CK_FALSE; for (k = 0; k < sizeof(always_modifiable_attrs) / sizeof(CK_ATTRIBUTE_TYPE); k++) { if (pTemplate[i].type == always_modifiable_attrs[k]) { found = CK_TRUE; break; } } if (!found) return CK_FALSE; } return CK_TRUE; } // // 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 && !modifiable_override(pTemplate, ulCount)) { TRACE_ERROR("Object is not modifiable\n"); rc = CKR_ACTION_PROHIBITED; goto done; } rc = object_mgr_check_session(sess, priv_obj, sess_obj); if (rc != CKR_OK) goto done; rc = object_set_attribute_values(tokdata, sess, 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) { rc = object_mgr_save_token_object(tokdata, obj); if (rc != CKR_OK) { TRACE_ERROR("Failed to save token object, rc=%lx.\n",rc); goto done; } } TRACE_DEBUG("Attributes after set:\n"); TRACE_DEBUG_DUMPTEMPL(obj->template); 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->count_lo = 0; entry->count_hi = 0; memcpy(entry->name, obj->name, 8); if (priv) { obj->index = global_shm->num_priv_tok_obj; global_shm->num_priv_tok_obj++; } else { obj->index = global_shm->num_publ_tok_obj; global_shm->num_publ_tok_obj++; } 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) { if (global_shm->num_priv_tok_obj == 0) { TRACE_DEVEL("%s\n", ock_err(ERR_OBJECT_HANDLE_INVALID)); return CKR_OBJECT_HANDLE_INVALID; } rc = object_mgr_search_shm_for_obj(global_shm->priv_tok_objs, 0, global_shm->num_priv_tok_obj - 1, obj, &index); 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 { if (global_shm->num_publ_tok_obj == 0) { TRACE_DEVEL("%s\n", ock_err(ERR_OBJECT_HANDLE_INVALID)); return CKR_OBJECT_HANDLE_INVALID; } rc = object_mgr_search_shm_for_obj(global_shm->publ_tok_objs, 0, global_shm->num_publ_tok_obj - 1, obj, &index); 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)); } } return CKR_OK; } CK_RV object_mgr_get_shm_entry_for_obj(STDLL_TokData_t *tokdata, OBJECT *obj, TOK_OBJ_ENTRY **entry) { CK_ULONG index; CK_RV rc; *entry = NULL; if (object_is_private(obj)) { /* 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)); return CKR_OBJECT_HANDLE_INVALID; } 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"); return rc; } *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)); return CKR_OBJECT_HANDLE_INVALID; } 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"); return rc; } *entry = &tokdata->global_shm->publ_tok_objs[index]; } return CKR_OK; } // The object must hold the READ or WRITE lock when this function is called! // CK_RV object_mgr_check_shm(STDLL_TokData_t *tokdata, OBJECT *obj, OBJ_LOCK_TYPE lock_type) { TOK_OBJ_ENTRY *entry = NULL; CK_BBOOL rd_locked = FALSE, wr_locked = FALSE; CK_RV rc; switch (lock_type) { case READ_LOCK: rd_locked = TRUE; break; case WRITE_LOCK: wr_locked = TRUE; break; case NO_LOCK: TRACE_ERROR("Function must be called with READ or WRITE lock.\n"); return CKR_FUNCTION_FAILED; } retry: rc = XProcLock(tokdata); if (rc != CKR_OK) { TRACE_ERROR("Failed to get Process Lock.\n"); goto done_no_xproc_unlock; } rc = object_mgr_get_shm_entry_for_obj(tokdata, obj, &entry); if (rc != CKR_OK) goto done; 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_ex_data_lock(obj, WRITE_LOCK); if (rc != CKR_OK) goto done; if (obj->ex_data != NULL && obj->ex_data_reload != NULL) { rc = obj->ex_data_reload(obj, obj->ex_data, obj->ex_data_len); if (rc != CKR_OK) { TRACE_ERROR("ex_data_reload failed 0x%lx\n", rc); object_ex_data_unlock(obj); goto done; } } rc = object_ex_data_unlock(obj); if (rc != CKR_OK) goto done; if (lock_type == READ_LOCK) { rc = object_unlock(obj); if (rc != CKR_OK) goto done; wr_locked = FALSE; /* Re-acquire the READ lock only after we have released the XProcLock! */ } done: if (rc == CKR_OK) { rc = XProcUnLock(tokdata); if (rc != CKR_OK) { TRACE_ERROR("Failed to release Process Lock.\n"); } } else { XProcUnLock(tokdata); } done_no_xproc_unlock: if (lock_type == READ_LOCK && wr_locked) object_unlock(obj); if (lock_type == READ_LOCK && !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) { CK_ULONG idx; UNUSED(lo); if (obj->index == 0) { /* * obj->index 0 is a valid index, but is also used to indicate that no * index is set/known. In case of a valid index 0, below loop should * find the matching SHM entry in the very first iteration, so the * code is not different to the code when obj->index would be > 0, * i.e. a memcmp of the name to check that the SHM entry still matches, * and a return if it matches, and a search loop if it is not matching. */ 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 { /* Check if the SHM entry is still for the desired object */ if (memcmp(obj->name, obj_list[obj->index].name, 8) == 0) { *index = obj->index; return CKR_OK; } else { /* * SHM entry is no longer for the desired object, search for it. * This can happen if a token object was deleted and the SHM entry * of it was removed, moving all following entries up by one. */ 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; } // 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)); if (new_obj == NULL) return CKR_HOST_MEMORY; memset(new_obj, 0x0, sizeof(OBJECT)); rc = object_init_lock(new_obj); if (rc != CKR_OK) { free(new_obj); continue; } rc = object_init_ex_data_lock(new_obj); if (rc != CKR_OK) { object_destroy_lock(new_obj); free(new_obj); continue; } memcpy(new_obj->name, shm_te->name, 8); rc = reload_token_object(tokdata, new_obj); if (rc == CKR_OK) 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)); if (new_obj == NULL) return CKR_HOST_MEMORY; memset(new_obj, 0x0, sizeof(OBJECT)); rc = object_init_lock(new_obj); if (rc != CKR_OK) { free(new_obj); continue; } rc = object_init_ex_data_lock(new_obj); if (rc != CKR_OK) { object_destroy_lock(new_obj); free(new_obj); continue; } memcpy(new_obj->name, shm_te->name, 8); rc = reload_token_object(tokdata, new_obj); if (rc == CKR_OK) 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); 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 /* * Re-enciphers a key that has a secure key in attribute CKA_IBM_OPAQUE by * calling the reenc callback function. * Returns CKR_ATTRIBUTE_TYPE_INVALID if the key does not contain a secure key. * The object must hold the WRITE lock when this function is called! */ CK_RV obj_mgr_reencipher_secure_key(STDLL_TokData_t *tokdata, OBJECT *obj, CK_RV (*reenc)(CK_BYTE *sec_key, CK_BYTE *reenc_sec_key, CK_ULONG sec_key_len, void *private), void *private) { CK_ATTRIBUTE *opaque_attr = NULL, *reenc_attr = NULL; CK_KEY_TYPE key_type; CK_RV rc; /* Update token object from SHM, if needed */ if (object_is_token_object(obj)) { rc = object_mgr_check_shm(tokdata, obj, WRITE_LOCK); if (rc != CKR_OK) { TRACE_DEVEL("object_mgr_check_shm failed.\n"); goto out; } } if (template_attribute_get_ulong(obj->template, CKA_KEY_TYPE, &key_type) != CKR_OK) { rc = CKR_ATTRIBUTE_TYPE_INVALID; goto out; } if (!template_attribute_find(obj->template, CKA_IBM_OPAQUE, &opaque_attr)) { rc = CKR_ATTRIBUTE_TYPE_INVALID; goto out; } rc = build_attribute(CKA_IBM_OPAQUE_REENC, opaque_attr->pValue, opaque_attr->ulValueLen, &reenc_attr); if (rc != CKR_OK) goto out; if (key_type == CKK_AES_XTS) { /* * AES-XTS has 2 secure keys concatenated to each other. * Re-encipher both keys separately. */ rc = reenc(opaque_attr->pValue, reenc_attr->pValue, reenc_attr->ulValueLen / 2, private); if (rc != CKR_OK) { TRACE_ERROR("Reencipher callback has failed, rc=0x%lx.\n",rc); goto out; } rc = reenc((CK_BYTE *)opaque_attr->pValue + reenc_attr->ulValueLen / 2, reenc_attr->pValue, reenc_attr->ulValueLen / 2, private); if (rc != CKR_OK) { TRACE_ERROR("Reencipher callback has failed, rc=0x%lx.\n",rc); goto out; } } else { rc = reenc(opaque_attr->pValue, reenc_attr->pValue, reenc_attr->ulValueLen, private); if (rc != CKR_OK) { TRACE_ERROR("Reencipher callback has failed, rc=0x%lx.\n",rc); goto out; } } rc = template_update_attribute(obj->template, reenc_attr); if (rc != CKR_OK) goto out; reenc_attr = NULL; if (!object_is_session_object(obj)) { rc = object_mgr_save_token_object(tokdata, obj); if (rc != CKR_OK) { TRACE_ERROR("Failed to save token object, rc=%lx.\n",rc); goto out; } } out: if (reenc_attr != NULL) free(reenc_attr); return rc; } /* * Moves the re-enciphered secure key from attribute CKA_IBM_OPAQUE_REENC to * CKA_IBM_OPAQUE, and the previous secure key from CKA_IBM_OPAQUE to * CKA_IBM_OPAQUE_OLD. * If the is_blob_new_mk_cb callback function is specified, then it is called to * determine if the key blob in CKA_IBM_OPAQUE is already enciphered with the * new master key. If it returns TRUE, then the key blob from CKA_IBM_OPAQUE * is not moved to CKA_IBM_OPAQUE_OLD, and CKA_IBM_OPAQUE_REENC is removed. * Returns CKR_ATTRIBUTE_TYPE_INVALID if the key does not contain a secure key. * The object must hold the WRITE lock when this function is called! */ CK_RV obj_mgr_reencipher_secure_key_finalize(STDLL_TokData_t *tokdata, OBJECT *obj, CK_BBOOL is_blob_new_mk_cb( STDLL_TokData_t *tokdata, OBJECT *obj, CK_BYTE *sec_key, CK_ULONG sec_key_len, void *cb_private), void *cb_private) { CK_ATTRIBUTE *opaque_attr = NULL, *old_attr = NULL, *reenc_attr = NULL; CK_ATTRIBUTE *new_opaque_attr = NULL; CK_KEY_TYPE key_type; CK_RV rc; /* Update token object from SHM, if needed */ if (object_is_token_object(obj)) { rc = object_mgr_check_shm(tokdata, obj, WRITE_LOCK); if (rc != CKR_OK) { TRACE_DEVEL("object_mgr_check_shm failed.\n"); goto out; } } if (template_attribute_get_ulong(obj->template, CKA_KEY_TYPE, &key_type) != CKR_OK) { rc = CKR_ATTRIBUTE_TYPE_INVALID; goto out; } if (!template_attribute_find(obj->template, CKA_IBM_OPAQUE_REENC, &reenc_attr)) { rc = CKR_ATTRIBUTE_TYPE_INVALID; goto out; } if (!template_attribute_find(obj->template, CKA_IBM_OPAQUE, &opaque_attr)) { rc = CKR_ATTRIBUTE_TYPE_INVALID; goto out; } if (is_blob_new_mk_cb != NULL && is_blob_new_mk_cb(tokdata, obj, opaque_attr->pValue, key_type == CKK_AES_XTS ? opaque_attr->ulValueLen / 2 : opaque_attr->ulValueLen, cb_private) == TRUE) { TRACE_DEVEL("is_blob_new_mk_cb returned TRUE, don't move blobs\n"); rc = template_remove_attribute(obj->template, CKA_IBM_OPAQUE_REENC); if (rc == CKR_ATTRIBUTE_TYPE_INVALID) rc = CKR_OK; if (rc != CKR_OK) goto out; goto remove; } rc = build_attribute(CKA_IBM_OPAQUE_OLD, opaque_attr->pValue, opaque_attr->ulValueLen, &old_attr); if (rc != CKR_OK) goto out; rc = template_update_attribute(obj->template, old_attr); if (rc != CKR_OK) goto out; old_attr = NULL; rc = build_attribute(CKA_IBM_OPAQUE, reenc_attr->pValue, reenc_attr->ulValueLen, &new_opaque_attr); if (rc != CKR_OK) goto out; rc = template_update_attribute(obj->template, new_opaque_attr); if (rc != CKR_OK) goto out; new_opaque_attr = NULL; remove: rc = template_remove_attribute(obj->template, CKA_IBM_OPAQUE_REENC); if (rc == CKR_ATTRIBUTE_TYPE_INVALID) rc = CKR_OK; if (rc != CKR_OK) goto out; if (!object_is_session_object(obj)) { rc = object_mgr_save_token_object(tokdata, obj); if (rc != CKR_OK) { TRACE_ERROR("Failed to save token object, rc=%lx.\n", rc); goto out; } } out: if (old_attr != NULL) free(old_attr); if (new_opaque_attr != NULL) free(new_opaque_attr); return rc; } /* * Removes the re-enciphered secure key from attribute CKA_IBM_OPAQUE_REENC * and also CKA_IBM_OPAQUE_OLD. * Returns CKR_ATTRIBUTE_TYPE_INVALID if the key does not contain a secure key. * The object must hold the WRITE lock when this function is called! */ CK_RV obj_mgr_reencipher_secure_key_cancel(STDLL_TokData_t *tokdata, OBJECT *obj) { CK_RV rc; /* Update token object from SHM, if needed */ if (object_is_token_object(obj)) { rc = object_mgr_check_shm(tokdata, obj, WRITE_LOCK); if (rc != CKR_OK) { TRACE_DEVEL("object_mgr_check_shm failed.\n"); goto out; } } rc = template_remove_attribute(obj->template, CKA_IBM_OPAQUE_REENC); if (rc == CKR_ATTRIBUTE_TYPE_INVALID) rc = CKR_OK; if (rc != CKR_OK) goto out; rc = template_remove_attribute(obj->template, CKA_IBM_OPAQUE_OLD); if (rc == CKR_ATTRIBUTE_TYPE_INVALID) rc = CKR_OK; if (rc != CKR_OK) goto out; if (!object_is_session_object(obj)) { rc = object_mgr_save_token_object(tokdata, obj); if (rc != CKR_OK) { TRACE_ERROR("Failed to save token object, rc=%lx.\n",rc); goto out; } } out: return rc; } struct iterate_obj_data { CK_BBOOL (*filter)(STDLL_TokData_t *tokdata, OBJECT *obj, void *filter_data); void *filter_data; CK_RV (*cb)(STDLL_TokData_t *tokdata, OBJECT *obj, void *cb_data); void *cb_data; const char *msg; CK_BBOOL syslog; CK_RV error; }; static void obj_mgr_iterate_key_objects_cb(STDLL_TokData_t *tokdata, void *p1, unsigned long p2, void *p3) { struct iterate_obj_data *iod = p3; OBJECT *obj = p1; CK_OBJECT_CLASS class; CK_RV rc; UNUSED(p2); if (iod->error != CKR_OK) /* Skip if previous reported an error */ return; rc = object_lock(obj, WRITE_LOCK); if (rc != CKR_OK) { if (iod->syslog) OCK_SYSLOG(LOG_ERR, "Slot %lu: Failed to get the object lock\n", tokdata->slot_id); return; } rc = template_attribute_get_ulong(obj->template, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("%s Failed to get object class: 0x%lx\n", __func__, rc); if (iod->syslog) OCK_SYSLOG(LOG_ERR, "Slot %lu: Failed to get object class: 0x%lx\n", tokdata->slot_id, rc); iod->error = rc; goto out; } switch (class) { case CKO_PUBLIC_KEY: case CKO_PRIVATE_KEY: case CKO_SECRET_KEY: break; default: /* Not a key object */ goto out; } if (iod->filter != NULL && !iod->filter(tokdata, obj, iod->filter_data)) goto out; if (obj->session != NULL) { TRACE_INFO("%s %s session object 0x%lx of session 0x%lx\n", __func__, iod->msg, p2, obj->session->handle); if (iod->syslog) OCK_SYSLOG(LOG_DEBUG, "Slot %lu: %s session object 0x%lx of " "session 0x%lx\n", tokdata->slot_id, iod->msg, p2, obj->session->handle); } else { TRACE_INFO("%s %s token object %s\n", __func__, iod->msg, obj->name); if (iod->syslog) OCK_SYSLOG(LOG_DEBUG, "Slot %lu: %s token object '%s'\n", tokdata->slot_id, iod->msg, obj->name); } rc = iod->cb(tokdata, obj, iod->cb_data); if (rc != CKR_OK) { if (obj->session != NULL) { TRACE_ERROR("%s callback failed to process session object: 0x%lx\n", __func__, rc); if (iod->syslog) OCK_SYSLOG(LOG_ERR, "Slot %lu: Failed to %s session object " "0x%lx of session 0x%lx: 0x%lx\n", tokdata->slot_id, iod->msg, p2, obj->session->handle, rc); } else { TRACE_ERROR("%s callback failed to process token object %s: 0x%lx\n", __func__, obj->name, rc); if (iod->syslog) OCK_SYSLOG(LOG_ERR, "Slot %lu: Failed to %s token object '%s': 0x%lx\n", tokdata->slot_id, iod->msg, obj->name, rc); } iod->error = rc; goto out; } out: object_unlock(obj); } CK_RV obj_mgr_iterate_key_objects(STDLL_TokData_t *tokdata, CK_BBOOL session_objects, CK_BBOOL token_objects, CK_BBOOL(*filter)(STDLL_TokData_t *tokdata, OBJECT *obj, void *filter_data), void *filter_data, CK_RV (*cb)(STDLL_TokData_t *tokdata, OBJECT *obj, void *cb_data), void *cb_data, CK_BBOOL syslog, const char *msg) { struct iterate_obj_data iod; CK_RV rc; iod.filter = filter; iod.filter_data = filter_data; iod.cb = cb; iod.cb_data = cb_data; iod.syslog = syslog; iod.msg = msg; iod.error = CKR_OK; if (session_objects) { /* Session objects */ bt_for_each_node(tokdata, &tokdata->sess_obj_btree, obj_mgr_iterate_key_objects_cb, &iod); if (iod.error != CKR_OK) { TRACE_ERROR("%s failed to %s session objects: 0x%lx\n", __func__, msg, iod.error); if (syslog) OCK_SYSLOG(LOG_ERR, "Slot %lu: Failed to %s session objects: 0x%lx\n", tokdata->slot_id, msg, iod.error); return iod.error; } } if (token_objects) { /* Update token objects */ rc = XProcLock(tokdata); if (rc != CKR_OK) { TRACE_ERROR("Failed to get Process Lock.\n"); if (syslog) OCK_SYSLOG(LOG_ERR, "Slot %lu: Failed to get Process Lock\n", tokdata->slot_id); return rc; } object_mgr_update_from_shm(tokdata); rc = XProcUnLock(tokdata); if (rc != CKR_OK) { TRACE_ERROR("Failed to release Process Lock.\n"); if (syslog) OCK_SYSLOG(LOG_ERR, "Slot %lu: Failed to release Process Lock\n", tokdata->slot_id); return rc; } /* Public token objects */ bt_for_each_node(tokdata, &tokdata->publ_token_obj_btree, obj_mgr_iterate_key_objects_cb, &iod); if (iod.error != CKR_OK) { TRACE_ERROR("%s failed to %s public token objects: 0x%lx\n", __func__, msg, iod.error); if (syslog) OCK_SYSLOG(LOG_ERR, "Slot %lu: Failed to %s public token " "objects: 0x%lx\n", tokdata->slot_id, msg, iod.error); return iod.error; } /* Private token objects */ bt_for_each_node(tokdata, &tokdata->priv_token_obj_btree, obj_mgr_iterate_key_objects_cb, &iod); if (iod.error != CKR_OK) { TRACE_ERROR("%s failed to %s private token objects: 0x%lx\n", __func__, msg, iod.error); if (syslog) OCK_SYSLOG(LOG_ERR,"Slot %lu: Failed to %s private token " "objects: 0x%lx\n", tokdata->slot_id, msg, iod.error); return iod.error; } } return CKR_OK; } opencryptoki-opencryptoki-451d99c/usr/lib/common/object.c000066400000000000000000000713251520105705100236150ustar00rootroot00000000000000/* * 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 "attributes.h" #include "p11util.h" #include "tok_spec_struct.h" #include "pkcs32.h" #include "trace.h" #include "../api/policy.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, CK_ULONG mode) { OBJECT *o = NULL; CK_BBOOL subclass_given = FALSE; CK_ULONG class, subclass = 0xFFFFFFFF; CK_RV rc; if (!pTemplate) { TRACE_ERROR("Invalid function arguments.\n"); return CKR_FUNCTION_FAILED; } // extract the object class and subclass // rc = get_ulong_attribute_by_type(pTemplate, ulCount, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); return rc; } rc = get_ulong_attribute_by_type(pTemplate, ulCount, CKA_CERTIFICATE_TYPE, &subclass); if (rc == CKR_ATTRIBUTE_VALUE_INVALID) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } if (rc == CKR_OK) subclass_given = TRUE; rc = get_ulong_attribute_by_type(pTemplate, ulCount, CKA_KEY_TYPE, &subclass); if (rc == CKR_ATTRIBUTE_VALUE_INVALID) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } if (rc == CKR_OK) subclass_given = TRUE; rc = get_ulong_attribute_by_type(pTemplate, ulCount, CKA_HW_FEATURE_TYPE, &subclass); if (rc == CKR_ATTRIBUTE_VALUE_INVALID) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } if (rc == CKR_OK) subclass_given = TRUE; // 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 (subclass_given != TRUE && class != CKO_DATA && class != CKO_PROFILE) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); return CKR_TEMPLATE_INCONSISTENT; } rc = object_create_skel(tokdata, pTemplate, ulCount, mode, 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, SESSION *sess, CK_ATTRIBUTE * pTemplate, CK_ULONG ulCount, OBJECT * old_obj, OBJECT ** new_obj) { TEMPLATE *tmpl, *new_tmpl; 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)); o->template = tmpl; rc = object_init_lock(o); if (rc != CKR_OK) goto error; rc = object_init_ex_data_lock(o); if (rc != CKR_OK) goto error; // copy the original object's attribute template // rc = template_copy(o->template, old_obj->template); 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(o->template, &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; } /* * Let the token know that attributes of the copied object have been * changed. */ if (token_specific.t_set_attribute_values != NULL) { rc = token_specific.t_set_attribute_values(tokdata, sess, o, new_tmpl); if (rc != CKR_OK) { TRACE_DEVEL("token_specific_set_attribute_values failed with %lu\n", rc); goto error; } } // merge in the new attributes // rc = template_merge(o->template, &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(o->template, 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 // *new_obj = o; return CKR_OK; error: 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->ex_data != NULL) { if (obj->ex_data_free != NULL) obj->ex_data_free(obj, obj->ex_data, obj->ex_data_len); else free(obj->ex_data); } object_destroy_ex_data_lock(obj); if (obj->template) template_free(obj->template); object_destroy_lock(obj); 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); } CK_BBOOL object_is_modifiable(OBJECT * obj) { CK_BBOOL val; CK_RV rc; rc = template_attribute_get_bool(obj->template, CKA_MODIFIABLE, &val); if (rc != CKR_OK) return TRUE; return val; } CK_BBOOL object_is_copyable(OBJECT * obj) { CK_BBOOL val; CK_RV rc; rc = template_attribute_get_bool(obj->template, CKA_COPYABLE, &val); if (rc != CKR_OK) return TRUE; return val; } CK_BBOOL object_is_destroyable(OBJECT * obj) { CK_BBOOL val; CK_RV rc; rc = template_attribute_get_bool(obj->template, CKA_DESTROYABLE, &val); if (rc != CKR_OK) return TRUE; return val; } // object_is_private() // // an is_private member should probably be added to OBJECT // CK_BBOOL object_is_private(OBJECT * obj) { CK_BBOOL val; CK_RV rc; rc = template_attribute_get_bool(obj->template, CKA_PRIVATE, &val); if (rc != CKR_OK) return TRUE; return val; } // 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_BBOOL val; CK_RV rc; rc = template_attribute_get_bool(obj->template, CKA_TOKEN, &val); if (rc != CKR_OK) return FALSE; return val; } // 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_is_extractable() // CK_BBOOL object_is_extractable(OBJECT * obj) { CK_BBOOL val; CK_RV rc; rc = template_attribute_get_bool(obj->template, CKA_EXTRACTABLE, &val); if (rc != CKR_OK) return TRUE; return val; } // object_is_pkey_extractable() // CK_BBOOL object_is_pkey_extractable(OBJECT * obj) { CK_BBOOL val; CK_RV rc; rc = template_attribute_get_bool(obj->template, CKA_IBM_PROTKEY_EXTRACTABLE, &val); if (rc != CKR_OK) return FALSE; return val; } // object_is_attr_bound() // CK_BBOOL object_is_attr_bound(OBJECT * obj) { CK_BBOOL val; CK_RV rc; rc = template_attribute_get_bool(obj->template, CKA_IBM_ATTRBOUND, &val); if (rc != CKR_OK) return FALSE; return val; } // object_get_size() // CK_ULONG object_get_size(OBJECT * obj) { CK_ULONG size; size = sizeof(OBJECT) + template_get_size(obj->template); return size; } static CK_RV object_get_attribute_array(CK_ATTRIBUTE *array_attr, CK_ATTRIBUTE *tmpl_attr) { CK_RV rc = CKR_OK, rc2; CK_ULONG num_elemets, i; CK_ATTRIBUTE_PTR array_elements; CK_ATTRIBUTE_PTR tmpl_elements; if (!is_attribute_attr_array(array_attr->type)) return CKR_ATTRIBUTE_TYPE_INVALID; if (tmpl_attr->pValue == NULL) { tmpl_attr->ulValueLen = array_attr->ulValueLen; return CKR_OK; } if (tmpl_attr->ulValueLen < array_attr->ulValueLen) { tmpl_attr->ulValueLen = CK_UNAVAILABLE_INFORMATION; return CKR_BUFFER_TOO_SMALL; } num_elemets = array_attr->ulValueLen / sizeof(CK_ATTRIBUTE); array_elements = (CK_ATTRIBUTE_PTR)array_attr->pValue; tmpl_elements = (CK_ATTRIBUTE_PTR)tmpl_attr->pValue; for (i = 0; i < num_elemets; i++) { tmpl_elements[i].type = array_elements[i].type; if (tmpl_elements[i].pValue == NULL) { tmpl_elements[i].ulValueLen = array_elements[i].ulValueLen; } else if (tmpl_elements[i].ulValueLen >= array_elements[i].ulValueLen) { if (array_elements[i].pValue != NULL) { if (is_attribute_attr_array(array_elements[i].type)) { rc2 = object_get_attribute_array(&array_elements[i], &tmpl_elements[i]); if (rc2 == CKR_BUFFER_TOO_SMALL) rc = rc2; else if (rc2 != CKR_OK) { TRACE_ERROR("object_get_attribute_array failed\n"); rc = rc2; break; } } else { memcpy(tmpl_elements[i].pValue, array_elements[i].pValue, array_elements[i].ulValueLen); } } tmpl_elements[i].ulValueLen = array_elements[i].ulValueLen; } else { TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); rc = CKR_BUFFER_TOO_SMALL; tmpl_elements[i].ulValueLen = CK_UNAVAILABLE_INFORMATION; } } return rc; } // // 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, rc2; 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: %lx\n", ock_err(ERR_ATTRIBUTE_SENSITIVE), pTemplate[i].type); rc = CKR_ATTRIBUTE_SENSITIVE; pTemplate[i].ulValueLen = (CK_ULONG)CK_UNAVAILABLE_INFORMATION; continue; } flag = template_attribute_find(obj_tmpl, pTemplate[i].type, &attr); if (flag == FALSE) { TRACE_ERROR("%s: %lx\n", ock_err(ERR_ATTRIBUTE_TYPE_INVALID), pTemplate[i].type); rc = CKR_ATTRIBUTE_TYPE_INVALID; pTemplate[i].ulValueLen = (CK_ULONG)CK_UNAVAILABLE_INFORMATION; continue; } if (pTemplate[i].pValue == NULL) { pTemplate[i].ulValueLen = attr->ulValueLen; } else if (pTemplate[i].ulValueLen >= attr->ulValueLen) { if (attr->pValue != NULL) { if (is_attribute_attr_array(attr->type)) { rc2 = object_get_attribute_array(attr, &pTemplate[i]); if (rc2 == CKR_BUFFER_TOO_SMALL) rc = rc2; else if (rc2 != CKR_OK) { TRACE_ERROR("object_get_attribute_array failed\n"); rc = rc2; break; } } else { 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)CK_UNAVAILABLE_INFORMATION; } } return rc; } // object_set_attribute_values() // CK_RV object_set_attribute_values(STDLL_TokData_t * tokdata, SESSION *sess, 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; } if (token_specific.t_set_attribute_values != NULL) { rc = token_specific.t_set_attribute_values(tokdata, sess, obj, new_tmpl); if (rc != CKR_OK) { TRACE_DEVEL("token_specific_set_attribute_values failed with %lu\n", rc); 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_withSize(struct policy *policy, CK_BYTE * data, OBJECT ** new_obj, CK_BBOOL replace, CK_ULONG data_size, const char *fname) { TEMPLATE *tmpl = NULL; OBJECT *obj = NULL; CK_ULONG offset = 0; CK_ULONG_32 count = 0; CK_RV rc; CK_OBJECT_CLASS_32 class32; const char *obj_name; if (!data || !new_obj || data_size < sizeof(CK_OBJECT_CLASS_32) + sizeof(CK_ULONG_32) + 8) { 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; if (fname != NULL) { /* The last path element of the file name must match the object name */ obj_name = strrchr(fname, '/'); if (obj_name == NULL) { TRACE_ERROR("File name has invalid format: '%s'\n", fname); rc = CKR_FUNCTION_FAILED; goto error; } obj_name++; if (strlen(obj_name) != 8) { TRACE_ERROR("File name has invalid format: '%s'\n", fname); rc = CKR_FUNCTION_FAILED; goto error; } if (memcmp(obj->name, obj_name, 8) != 0) { TRACE_ERROR("Object name '%.8s' does not match the file name it was loaded from: '%s'\n", obj->name, fname); rc = CKR_FUNCTION_FAILED; goto error; } } rc = template_unflatten_withSize(&tmpl, data + offset, count, data_size - offset); if (rc != CKR_OK) { TRACE_DEVEL("template_unflatten_withSize failed.\n"); goto error; } /* External tools (e.g., pkcscca) might use this function and not be aware of any policy. Allow them to pass NULL. */ if (policy) { /* Ignore policy violations here since the point is to get the correct strength classification for the usage scenario which will then allow or block key usage. */ policy->store_object_strength(policy, &obj->strength, policy_get_attr_from_template, tmpl, NULL, NULL); } obj->template = tmpl; tmpl = NULL; if (replace == FALSE) { rc = object_init_lock(obj); if (rc != CKR_OK) goto error; rc = object_init_ex_data_lock(obj); if (rc != CKR_OK) { object_destroy_lock(obj); goto error; } *new_obj = obj; } else { /* Reload of existing object only changes the template */ template_free((*new_obj)->template); (*new_obj)->template = obj->template; (*new_obj)->strength.strength = obj->strength.strength; (*new_obj)->strength.siglen = obj->strength.siglen; (*new_obj)->strength.allowed = obj->strength.allowed; 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(tokdata, tmpl, tmpl2, class, subclass, mode); if (rc != CKR_OK) goto done; if (token_specific.t_set_attrs_for_new_object != NULL) { rc = token_specific.t_set_attrs_for_new_object(tokdata, class, mode, tmpl2); if (rc != CKR_OK) { TRACE_ERROR("token_specific.t_set_pkey_attr failed with rc=%lx\n",rc); 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; rc = object_init_ex_data_lock(o); if (rc != CKR_OK) { object_destroy_lock(o); goto done; } *obj = o; return CKR_OK; done: if (o) { if (o->template) template_free(o->template); 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; } CK_RV object_init_ex_data_lock(OBJECT *obj) { if (pthread_rwlock_init(&obj->ex_data_rwlock, NULL) != 0) { TRACE_DEVEL("Ex_data Lock init failed.\n"); return CKR_CANT_LOCK; } return CKR_OK; } CK_RV object_destroy_ex_data_lock(OBJECT *obj) { if (pthread_rwlock_destroy(&obj->ex_data_rwlock) != 0) { TRACE_DEVEL("Ex_data Lock destroy failed.\n"); return CKR_CANT_LOCK; } return CKR_OK; } CK_RV object_ex_data_lock(OBJECT *obj, OBJ_LOCK_TYPE type) { switch (type) { case NO_LOCK: break; case READ_LOCK: if (pthread_rwlock_rdlock(&obj->ex_data_rwlock) != 0) { TRACE_DEVEL("Ex_data Read-Lock failed.\n"); return CKR_CANT_LOCK; } break; case WRITE_LOCK: if (pthread_rwlock_wrlock(&obj->ex_data_rwlock) != 0) { TRACE_DEVEL("Ex_data Write-Lock failed.\n"); return CKR_CANT_LOCK; } break; } return CKR_OK; } CK_RV object_ex_data_unlock(OBJECT *obj) { if (pthread_rwlock_unlock(&obj->ex_data_rwlock) != 0) { TRACE_DEVEL("Ex_data Unlock failed.\n"); return CKR_CANT_LOCK; } return CKR_OK; } opencryptoki-opencryptoki-451d99c/usr/lib/common/ock_syslog.h000066400000000000000000000017331520105705100245240ustar00rootroot00000000000000/* * 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 opencryptoki-opencryptoki-451d99c/usr/lib/common/p11util.c000066400000000000000000000350511520105705100236420ustar00rootroot00000000000000/* * 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" #include "mechtable.h" #define _sym2str(X) case X: return #X // // p11_get_ckr - return textual interpretation of a CKR_ error code // @rc is the CKR_.. error // const 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); _sym2str(CKR_ACTION_PROHIBITED); _sym2str(CKR_AEAD_DECRYPT_FAILED); _sym2str(CKR_NEW_PIN_MODE); _sym2str(CKR_NEXT_OTP); _sym2str(CKR_EXCEEDED_MAX_ITERATIONS); _sym2str(CKR_FIPS_SELF_TEST_FAILED); _sym2str(CKR_LIBRARY_LOAD_FAILED); _sym2str(CKR_PIN_TOO_WEAK); _sym2str(CKR_PUBLIC_KEY_INVALID); _sym2str(CKR_TOKEN_RESOURCE_EXCEEDED); _sym2str(CKR_OPERATION_CANCEL_FAILED); _sym2str(CKR_KEY_EXHAUSTED); _sym2str(CKR_PENDING); _sym2str(CKR_SESSION_ASYNC_NOT_SUPPORTED); _sym2str(CKR_SEED_RANDOM_REQUIRED); _sym2str(CKR_OPERATION_NOT_VALIDATED); _sym2str(CKR_TOKEN_NOT_INITIALIZED); _sym2str(CKR_PARAMETER_SET_NOT_SUPPORTED); default: return "UNKNOWN"; } } #ifndef CKA_IBM_PQC_PARAMS #define CKA_IBM_PQC_PARAMS (CKA_VENDOR_DEFINED +0x1000e) #endif // // p11_get_cka - return textual interpretation of an attribute type // only simple types - no arrays. For unknown a ptr to a static // buffer is returned. So be carefull this is not thread safe then. // const char *p11_get_cka(CK_ATTRIBUTE_TYPE atype) { static char buf[50]; switch (atype) { _sym2str(CKA_CLASS); _sym2str(CKA_TOKEN); _sym2str(CKA_PRIVATE); _sym2str(CKA_LABEL); _sym2str(CKA_UNIQUE_ID); _sym2str(CKA_VALUE); _sym2str(CKA_OBJECT_ID); _sym2str(CKA_CERTIFICATE_TYPE); _sym2str(CKA_ISSUER); _sym2str(CKA_SERIAL_NUMBER); _sym2str(CKA_ATTR_TYPES); _sym2str(CKA_TRUSTED); _sym2str(CKA_KEY_TYPE); _sym2str(CKA_SUBJECT); _sym2str(CKA_CERTIFICATE_CATEGORY); _sym2str(CKA_JAVA_MIDP_SECURITY_DOMAIN); _sym2str(CKA_URL); _sym2str(CKA_HASH_OF_SUBJECT_PUBLIC_KEY); _sym2str(CKA_HASH_OF_ISSUER_PUBLIC_KEY); _sym2str(CKA_NAME_HASH_ALGORITHM); _sym2str(CKA_CHECK_VALUE); _sym2str(CKA_ID); _sym2str(CKA_SENSITIVE); _sym2str(CKA_ENCRYPT); _sym2str(CKA_DECRYPT); _sym2str(CKA_WRAP); _sym2str(CKA_UNWRAP); _sym2str(CKA_SIGN); _sym2str(CKA_SIGN_RECOVER); _sym2str(CKA_VERIFY); _sym2str(CKA_VERIFY_RECOVER); _sym2str(CKA_DERIVE); _sym2str(CKA_START_DATE); _sym2str(CKA_END_DATE); _sym2str(CKA_MODULUS); _sym2str(CKA_MODULUS_BITS); _sym2str(CKA_PUBLIC_EXPONENT); _sym2str(CKA_PRIVATE_EXPONENT); _sym2str(CKA_PRIME_1); _sym2str(CKA_PRIME_2); _sym2str(CKA_EXPONENT_1); _sym2str(CKA_EXPONENT_2); _sym2str(CKA_COEFFICIENT); _sym2str(CKA_PUBLIC_KEY_INFO); _sym2str(CKA_PRIME); _sym2str(CKA_SUBPRIME); _sym2str(CKA_BASE); _sym2str(CKA_PRIME_BITS); _sym2str(CKA_SUBPRIME_BITS); _sym2str(CKA_VALUE_BITS); _sym2str(CKA_VALUE_LEN); _sym2str(CKA_EXTRACTABLE); _sym2str(CKA_LOCAL); _sym2str(CKA_NEVER_EXTRACTABLE); _sym2str(CKA_ALWAYS_SENSITIVE); _sym2str(CKA_KEY_GEN_MECHANISM); _sym2str(CKA_MODIFIABLE); _sym2str(CKA_COPYABLE); _sym2str(CKA_DESTROYABLE); _sym2str(CKA_EC_PARAMS); _sym2str(CKA_EC_POINT); _sym2str(CKA_SECONDARY_AUTH); _sym2str(CKA_AUTH_PIN_FLAGS); _sym2str(CKA_ALWAYS_AUTHENTICATE); _sym2str(CKA_WRAP_WITH_TRUSTED); _sym2str(CKA_HW_FEATURE_TYPE); _sym2str(CKA_RESET_ON_INIT); _sym2str(CKA_HAS_RESET); _sym2str(CKA_WRAP_TEMPLATE); _sym2str(CKA_UNWRAP_TEMPLATE); _sym2str(CKA_DERIVE_TEMPLATE); _sym2str(CKA_ALLOWED_MECHANISMS); _sym2str(CKA_PROFILE_ID); _sym2str(CKA_PARAMETER_SET); _sym2str(CKA_ENCAPSULATE_TEMPLATE); _sym2str(CKA_DECAPSULATE_TEMPLATE); _sym2str(CKA_ENCAPSULATE); _sym2str(CKA_DECAPSULATE); _sym2str(CKA_SEED); _sym2str(CKA_IBM_OPAQUE); _sym2str(CKA_IBM_OPAQUE_REENC); _sym2str(CKA_IBM_OPAQUE_OLD); _sym2str(CKA_IBM_RESTRICTABLE); _sym2str(CKA_IBM_NEVER_MODIFIABLE); _sym2str(CKA_IBM_RETAINKEY); _sym2str(CKA_IBM_ATTRBOUND); _sym2str(CKA_IBM_KEYTYPE); _sym2str(CKA_IBM_CV); _sym2str(CKA_IBM_MACKEY); _sym2str(CKA_IBM_USE_AS_DATA); _sym2str(CKA_IBM_STRUCT_PARAMS); _sym2str(CKA_IBM_STD_COMPLIANCE1); _sym2str(CKA_IBM_PROTKEY_EXTRACTABLE); _sym2str(CKA_IBM_PROTKEY_NEVER_EXTRACTABLE); _sym2str(CKA_IBM_OPAQUE_PKEY); _sym2str(CKA_IBM_DILITHIUM_KEYFORM); _sym2str(CKA_IBM_DILITHIUM_MODE); _sym2str(CKA_IBM_ML_DSA_RHO); _sym2str(CKA_IBM_ML_DSA_SEED); _sym2str(CKA_IBM_ML_DSA_TR); _sym2str(CKA_IBM_ML_DSA_S1); _sym2str(CKA_IBM_ML_DSA_S2); _sym2str(CKA_IBM_ML_DSA_T0); _sym2str(CKA_IBM_ML_DSA_T1); _sym2str(CKA_IBM_ML_DSA_PRIVATE_SEED); _sym2str(CKA_IBM_PQC_PARAMS); _sym2str(CKA_IBM_KYBER_KEYFORM); _sym2str(CKA_IBM_KYBER_MODE); _sym2str(CKA_IBM_ML_KEM_PK); _sym2str(CKA_IBM_ML_KEM_SK); _sym2str(CKA_IBM_ML_KEM_PRIVATE_SEED); _sym2str(CKA_IBM_CCA_AES_KEY_MODE); _sym2str(CKA_IBM_CCA_ML_DSA_KEY_MODE); _sym2str(CKA_IBM_PARAMETER_SET); default: sprintf(buf, "unknown attribute type 0x%08lx", atype); return buf; } } // 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_UNIQUE_ID: case CKA_PROFILE_ID: 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_WRAP_WITH_TRUSTED: case CKA_WRAP_TEMPLATE: case CKA_UNWRAP_TEMPLATE: case CKA_CERTIFICATE_CATEGORY: case CKA_JAVA_MIDP_SECURITY_DOMAIN: case CKA_URL: case CKA_HASH_OF_SUBJECT_PUBLIC_KEY: case CKA_HASH_OF_ISSUER_PUBLIC_KEY: case CKA_NAME_HASH_ALGORITHM: case CKA_CHECK_VALUE: case CKA_PUBLIC_KEY_INFO: case CKA_COPYABLE: case CKA_DESTROYABLE: case CKA_ALLOWED_MECHANISMS: case CKA_DERIVE_TEMPLATE: case CKA_PARAMETER_SET: case CKA_ENCAPSULATE_TEMPLATE: case CKA_DECAPSULATE_TEMPLATE: case CKA_ENCAPSULATE: case CKA_DECAPSULATE: case CKA_SEED: return TRUE; } return FALSE; } /* * Returns true if the attribute is an attribute array type. */ CK_BBOOL is_attribute_attr_array(CK_ATTRIBUTE_TYPE type) { if (!is_attribute_defined(type)) return FALSE; switch (type) { case CKA_WRAP_TEMPLATE: case CKA_UNWRAP_TEMPLATE: case CKA_DERIVE_TEMPLATE: case CKA_ENCAPSULATE_TEMPLATE: case CKA_DECAPSULATE_TEMPLATE: return TRUE; } return FALSE; } const char *p11_get_ckm(const struct mechtable_funcs *f, CK_ULONG mechanism) { const struct mechrow *row = f->p_row_from_num(mechanism); if (row) return row->string; 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 *) malloc(2 * len + 1); 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 && attr->ulValueLen > 0 && attr->pValue != NULL) { size = attr->ulValueLen; ptr = p11_bigint_trim(attr->pValue, &size); if (ptr != attr->pValue) { attr->ulValueLen = size; memmove(attr->pValue, ptr, size); } } } /* p11_strlen() - calculate the length of CK_CHAR field, which * are not '\0' terminated but padded with spaces. * @s is a pointer to a CK_CHAR string. * @max_len is its maximum length. */ size_t p11_strlen(const CK_CHAR *s, size_t max_len) { size_t len = max_len; while (len > 0 && s[len - 1] == ' ') --len; return len; } opencryptoki-opencryptoki-451d99c/usr/lib/common/p11util.h000066400000000000000000000050111520105705100236400ustar00rootroot00000000000000/* * 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" struct mechtable_funcs; // // p11_get_ckr - return textual interpretation of a CKR_ error code // @rc is the CKR_.. error // const 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 // const char *p11_get_ckm(const struct mechtable_funcs *,CK_ULONG); // // p11_get_cka - return textual interpretation of an attribute type // only simple types - no arrays. For unknown a ptr to a static // buffer is returned. So be carefull this is not thread safe then. // const char *p11_get_cka(CK_ATTRIBUTE_TYPE atype); // is_attribute_defined() // // determine whether the specified attribute is defined by Cryptoki // CK_BBOOL is_attribute_defined(CK_ATTRIBUTE_TYPE type); CK_BBOOL is_attribute_attr_array(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); /* p11_strlen() - calculate the length of CK_CHAR field, which * are not '\0' terminated but padded with spaces. * @s is a pointer to a CK_CHAR string. * @max_len is its maximum length. */ size_t p11_strlen(const CK_CHAR *s, size_t max_len); #endif // #ifndef _P11UTIL_H_ opencryptoki-opencryptoki-451d99c/usr/lib/common/pin_prompt.c000066400000000000000000000035531520105705100245340ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2022 * * This program is provided under the terms of the Common Public License, * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this * software constitutes recipient's acceptance of CPL-1.0 terms which can be * found in the file LICENSE file or at * https://opensource.org/licenses/cpl1.0.php */ #define _POSIX_C_SOURCE 200809L #include #include #include #include #include #include #include #include #include static void echo(bool on) { struct termios term; if (tcgetattr(fileno(stdin), &term)) return; if (on) term.c_lflag |= ECHO; else term.c_lflag &= ~ECHO; tcsetattr(fileno(stdin), TCSAFLUSH, &term); } void pin_free(char **buf) { if (!buf) return; if (*buf) OPENSSL_cleanse(*buf, strlen(*buf)); free(*buf); *buf = NULL; } const char *pin_prompt(char **buf, const char *msg) { ssize_t n = 0; size_t s = 0; if (!buf || *buf) return NULL; printf("%s", msg); fflush(stdout); echo(false); n = getline(buf, &s, stdin); echo(true); printf("\n"); fflush(stdout); /* delayed getline() error handling */ if (n == -1) { free(*buf); *buf = NULL; return NULL; } /* strip on first occurence of CR/LF */ (*buf)[strcspn(*buf, "\r\n")] = '\0'; return (const char *)*buf; } const char *pin_prompt_new(char **buf, const char *msg1, const char *msg2) { const char *pin = NULL; char *buf2 = NULL; if (!pin_prompt(buf, msg1) || !pin_prompt(&buf2, msg2)) return NULL; if (strlen(*buf) && strlen(buf2) && (!strcmp(*buf, buf2))) pin = *buf; pin_free(&buf2); return pin; } opencryptoki-opencryptoki-451d99c/usr/lib/common/pin_prompt.h000066400000000000000000000027051520105705100245370ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2022 * * This program is provided under the terms of the Common Public License, * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this * software constitutes recipient's acceptance of CPL-1.0 terms which can be * found in the file LICENSE file or at * https://opensource.org/licenses/cpl1.0.php */ #ifndef _PIN_PROMPT_H_ #define _PIN_PROMPT_H_ void pin_free(char **buf); /** * Print a message and prompt for input on stdin (echo is disabled during * input). * * @param buf Pointer to a string (char *) for buffering the input. It must * be free-ed after usage. * @param msg Pointer to the prompt message. * @returns Pointer to the input on success, otherwise NULL. The returned * pointer must not be free-ed. */ const char *pin_prompt(char **buf, const char *msg); /** * Prompt for a new pin twice and compare both inputs. * * @param buf Pointer to a string (char *) for buffering the input. It must * be free-ed after usage. * @param msg1 Pointer to the first prompt message. * @param msg2 Pointer to the first prompt message. * @returns Pointer to the pin on success (both inputs must be successful * and both values must be equal), otherwise NULL. The returned * pointer must not be free-ed. */ const char *pin_prompt_new(char **buf, const char *msg1, const char *msg2); #endif /* _PIN_PROMPT_H_ */ opencryptoki-opencryptoki-451d99c/usr/lib/common/pkcs_utils.c000066400000000000000000000313031520105705100245170ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2020 * * This program is provided under the terms of the Common Public License, * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this * software constitutes recipient's acceptance of CPL-1.0 terms which can be * found in the file LICENSE file or at * https://opensource.org/licenses/cpl1.0.php */ /* * Some routines that are shared between the pkcs utilities in usr/sbin. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "defs.h" #include "host_defs.h" #ifndef OCK_TOOL #define OCK_TOOL #endif #include "pkcs_utils.h" extern pkcs_trace_level_t trace_level; void pkcs_trace(pkcs_trace_level_t level, const char *file, int line, const char *fmt, ...) { va_list ap; const char *fmt_pre; char buf[1024]; char *pbuf; int buflen, len; if (level > trace_level) return; pbuf = buf; buflen = sizeof(buf); /* add file line */ switch (level) { case TRACE_LEVEL_NONE: fmt_pre = ""; break; case TRACE_LEVEL_ERROR: fmt_pre = "[%s:%d] ERROR: "; break; case TRACE_LEVEL_WARNING: fmt_pre = "[%s:%d] WARN: "; break; case TRACE_LEVEL_INFO: fmt_pre = "[%s:%d] INFO: "; break; case TRACE_LEVEL_DEVEL: fmt_pre = "[%s:%d] DEVEL: "; break; case TRACE_LEVEL_DEBUG: fmt_pre = "[%s:%d] DEBUG: "; break; default: return; } snprintf(pbuf, buflen, fmt_pre, file, line); len = strlen(buf); pbuf = buf + len; buflen = sizeof(buf) - len; va_start(ap, fmt); vsnprintf(pbuf, buflen, fmt, ap); va_end(ap); printf("%s", buf); } #ifdef DEBUG /* a simple function for dumping out a memory area */ void pkcs_hexdump(const char *prestr, void *buf, size_t buflen) { /* 1 2 3 4 5 6 0123456789012345678901234567890123456789012345678901234567890123456789 xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx ................ */ size_t i, j; char line[68]; for (i = 0; i < buflen; i += 16) { for (j = 0; j < 16; j++) { if (i + j < buflen) { unsigned char b = ((unsigned char *) buf)[i + j]; sprintf(line + j * 3, "%02hhx ", b); line[51 + j] = (isalnum(b) ? b : '.'); } else { sprintf(line + j * 3, " "); line[51 + j] = ' '; } } line[47] = line[48] = line[49] = line[50] = ' '; line[67] = '\0'; if (prestr) TRACE_DEBUG("%s%s\n", prestr, line); else TRACE_DEBUG("%s\n", line); } } #endif /* DEBUG */ int compute_hash(int hash_type, int buf_size, const char *buf, char *digest) { EVP_MD_CTX *md_ctx = NULL; unsigned int result_size; int rc; md_ctx = EVP_MD_CTX_create(); switch (hash_type) { case HASH_SHA1: rc = EVP_DigestInit(md_ctx, EVP_sha1()); break; case HASH_MD5: rc = EVP_DigestInit(md_ctx, EVP_md5()); break; default: rc = -1; goto done; } if (rc != 1) { TRACE_ERROR("EVP_DigestInit() failed: rc = %d\n", rc); rc = -1; goto done; } rc = EVP_DigestUpdate(md_ctx, buf, buf_size); if (rc != 1) { TRACE_ERROR("EVP_DigestUpdate() failed: rc = %d\n", rc); rc = -1; goto done; } result_size = EVP_MD_CTX_size(md_ctx); rc = EVP_DigestFinal(md_ctx, (unsigned char *) digest, &result_size); if (rc != 1) { TRACE_ERROR("EVP_DigestFinal() failed: rc = %d\n", rc); rc = -1; goto done; } rc = 0; done: EVP_MD_CTX_destroy(md_ctx); return rc; } #ifndef OCK_NO_LOCAL_RNG CK_RV local_rng(CK_BYTE *output, CK_ULONG bytes) { int ranfd; int rlen; unsigned int totallen = 0; ranfd = open("/dev/prandom", 0); if (ranfd < 0) ranfd = open("/dev/urandom", 0); if (ranfd >= 0) { do { rlen = read(ranfd, output + totallen, bytes - totallen); if (rlen <= 0) { close(ranfd); return CKR_FUNCTION_FAILED; } totallen += rlen; } while (totallen < bytes); close(ranfd); return CKR_OK; } return CKR_FUNCTION_FAILED; } #endif CK_RV aes_256_wrap(unsigned char out[40], const unsigned char in[32], const unsigned char kek[32]) { CK_RV rc; int outlen; unsigned char buffer[40 + EVP_MAX_BLOCK_LENGTH]; EVP_CIPHER_CTX *ctx = NULL; ctx = EVP_CIPHER_CTX_new(); if (ctx == NULL) { TRACE_ERROR("EVP_CIPHER_CTX_new failed.\n"); rc = CKR_HOST_MEMORY; goto done; } EVP_CIPHER_CTX_set_flags(ctx, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW); if (EVP_CipherInit_ex(ctx, EVP_aes_256_wrap(), NULL, kek, NULL, 1) != 1 || EVP_CipherUpdate(ctx, buffer, &outlen, in, 32) != 1 || EVP_CipherFinal_ex(ctx, buffer + outlen, &outlen) != 1) { TRACE_ERROR("EVP_Cipher funcs failed\n"); rc = CKR_FUNCTION_FAILED; goto done; } memcpy(out, buffer, 40); rc = CKR_OK; done: EVP_CIPHER_CTX_free(ctx); return rc; } CK_RV aes_256_unwrap(unsigned char key[32], const unsigned char in[40], const unsigned char kek[32]) { CK_RV rc; int outlen; unsigned char buffer[32 + EVP_MAX_BLOCK_LENGTH]; EVP_CIPHER_CTX *ctx = NULL; ctx = EVP_CIPHER_CTX_new(); if (ctx == NULL) { TRACE_ERROR("EVP_CIPHER_CTX_new failed\n"); rc = CKR_HOST_MEMORY; goto done; } EVP_CIPHER_CTX_set_flags(ctx, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW); if (EVP_CipherInit_ex(ctx, EVP_aes_256_wrap(), NULL, kek, NULL, 0) != 1 || EVP_CipherUpdate(ctx, buffer, &outlen, in, 40) != 1 || EVP_CipherFinal_ex(ctx, buffer + outlen, &outlen) != 1) { rc = CKR_FUNCTION_FAILED; goto done; } memcpy(key, buffer, 32); rc = CKR_OK; done: EVP_CIPHER_CTX_free(ctx); return rc; } CK_RV aes_256_gcm_seal(unsigned char *out, unsigned char tag[16], const unsigned char *aad, size_t aadlen, const unsigned char *in, size_t inlen, const unsigned char key[32], const unsigned char iv[12]) { CK_RV rc; int outlen; EVP_CIPHER_CTX *ctx = NULL; ctx = EVP_CIPHER_CTX_new(); if (ctx == NULL) { TRACE_ERROR("EVP_CIPHER_CTX_new failed\n"); rc = CKR_HOST_MEMORY; goto done; } if (EVP_CipherInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL, -1) != 1 || EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 12, NULL) != 1 || EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, 1) != 1 || EVP_CipherUpdate(ctx, NULL, &outlen, aad, aadlen) != 1 || EVP_CipherUpdate(ctx, out, &outlen, in, inlen) != 1 || EVP_CipherFinal_ex(ctx, out + outlen, &outlen) != 1 || EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag) != 1) { TRACE_ERROR("EVP_Cipher funcs failed\n"); rc = CKR_FUNCTION_FAILED; goto done; } rc = CKR_OK; done: EVP_CIPHER_CTX_free(ctx); return rc; } /** * Verify that SO PIN and user PIN are correct by comparing their SHA-1 * values with the stored hashes in NVTOK.DAT. */ int verify_pins(char *data_store, const char *sopin, unsigned long sopinlen, const char *userpin, unsigned long userpinlen) { TOKEN_DATA td; char fname[PATH_MAX]; char pin_sha[SHA1_HASH_SIZE]; FILE *fp = NULL; int ret; int tdnew; struct stat stbuf; size_t tdlen; int fd; /* read the NVTOK.DAT */ snprintf(fname, PATH_MAX, "%s/NVTOK.DAT", data_store); fp = fopen((char *) fname, "r"); if (!fp) { TRACE_ERROR("Cannot not open %s: %s\n", fname, strerror(errno)); return -1; } fd = fileno(fp); if ((fstat(fd, &stbuf) != 0) || (!S_ISREG(stbuf.st_mode))) { ret = -1; goto done; } if (stbuf.st_size == sizeof(TOKEN_DATA_OLD)) { /* old data store/pin format */ tdnew = 0; tdlen = sizeof(TOKEN_DATA_OLD); } else if (stbuf.st_size == sizeof(TOKEN_DATA)) { /* new data store/pin format */ tdnew = 1; tdlen = sizeof(TOKEN_DATA); } else { TRACE_ERROR("%s has an invalid size of %ld bytes. Neither old nor new token format.\n", fname, stbuf.st_size); ret = -1; goto done; } ret = fread(&td, tdlen, 1, fp); if (ret != 1) { TRACE_ERROR("Could not read %s: %s\n", fname, strerror(errno)); ret = -1; goto done; } if (tdnew == 0) { /* Now compute the SHAs for the SO and USER pins entered. * Compare with the SHAs for SO and USER PINs saved in * NVTOK.DAT to verify. */ if (sopin != NULL) { ret = compute_sha1(sopin, sopinlen, pin_sha); if (ret) { TRACE_ERROR("Failed to compute sha for SO.\n"); goto done; } if (memcmp(td.so_pin_sha, pin_sha, SHA1_HASH_SIZE) != 0) { TRACE_ERROR("SO PIN is incorrect.\n"); ret = -1; goto done; } } if (userpin != NULL) { ret = compute_sha1(userpin, userpinlen, pin_sha); if (ret) { TRACE_ERROR("Failed to compute sha for USER.\n"); goto done; } if (memcmp(td.user_pin_sha, pin_sha, SHA1_HASH_SIZE) != 0) { TRACE_ERROR("USER PIN is incorrect.\n"); ret = -1; goto done; } } } else if (tdnew == 1) { if (sopin != NULL) { unsigned char so_login_key[32]; ret = PKCS5_PBKDF2_HMAC(sopin, sopinlen, td.dat.so_login_salt, 64, td.dat.so_login_it, EVP_sha512(), 256 / 8, so_login_key); if (ret != 1) { TRACE_ERROR("PBKDF2 failed.\n"); goto done; } if (CRYPTO_memcmp(td.dat.so_login_key, so_login_key, 32) != 0) { TRACE_ERROR("USER PIN is incorrect.\n"); ret = -1; goto done; } } if (userpin != NULL) { unsigned char user_login_key[32]; ret = PKCS5_PBKDF2_HMAC(userpin, userpinlen, td.dat.user_login_salt, 64, td.dat.user_login_it, EVP_sha512(), 256 / 8, user_login_key); if (ret != 1) { TRACE_ERROR("PBKDF2 failed.\n"); goto done; } if (CRYPTO_memcmp(td.dat.user_login_key, user_login_key, 32) != 0) { TRACE_ERROR("USER PIN is incorrect.\n"); ret = -1; goto done; } } } else { TRACE_ERROR("Unknown token format.\n"); ret = -1; goto done; } ret = 0; done: /* clear out the hash */ memset(pin_sha, 0, SHA1_HASH_SIZE); if (fp) fclose(fp); return ret; } #ifndef OCK_NO_SET_PERM CK_RV set_perm(int file, const char *group) { struct stat sb; struct group *grp; mode_t mode; if (group == NULL || group[0] == '\0') group = PKCS_GROUP; if (fstat(file, &sb) != 0) { TRACE_DEVEL("fstat failed: %s\n", strerror(errno)); return CKR_FUNCTION_FAILED; } grp = getgrnam(group); if (grp == NULL) { TRACE_DEVEL("getgrnam(%s) failed: %s\n", group, strerror(errno)); return CKR_FUNCTION_FAILED; } /* Set absolute permissions or rw-rw----, if not already as expected */ if (S_ISDIR(sb.st_mode)) mode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP; else mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; if ((sb.st_mode & ~S_IFMT) != mode) { if (fchmod(file, mode) != 0) { TRACE_DEVEL("fchmod(rw-rw----) failed: %s\n", strerror(errno)); return CKR_FUNCTION_FAILED; } } /* set ownership to pkcs11 group, if not already as expected */ if (sb.st_gid != grp->gr_gid) { if (fchown(file, -1, grp->gr_gid) != 0) { TRACE_DEVEL("fchown(-1, %s) failed: %s\n", group, strerror(errno)); return CKR_FUNCTION_FAILED; } } return CKR_OK; } #endif opencryptoki-opencryptoki-451d99c/usr/lib/common/pkcs_utils.h000066400000000000000000000060551520105705100245320ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2020 * * This program is provided under the terms of the Common Public License, * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this * software constitutes recipient's acceptance of CPL-1.0 terms which can be * found in the file LICENSE file or at * https://opensource.org/licenses/cpl1.0.php */ #ifndef PKCS_UTILS_H #define PKCS_UTILS_H #include "pkcs11types.h" #define MASTER_KEY_SIZE 24 #define MASTER_KEY_SIZE_CCA 64 #define MAX_MASTER_KEY_SIZE MASTER_KEY_SIZE_CCA #define MK_FILE_SIZE_00 48 #define MK_FILE_SIZE_00_CCA 88 #define HASH_SHA1 1 #define HASH_MD5 2 #define compute_sha1(a,b,c) compute_hash((HASH_SHA1),(b),(a),(c)) #define compute_md5(a,b,c) compute_hash(HASH_MD5,(b),(a),(c)) int compute_hash(int hash_type, int buf_size, const char *buf, char *digest); CK_RV local_rng(CK_BYTE *output, CK_ULONG bytes); CK_RV aes_256_wrap(unsigned char out[40], const unsigned char in[32], const unsigned char kek[32]); CK_RV aes_256_unwrap(unsigned char key[32], const unsigned char in[40], const unsigned char kek[32]); CK_RV aes_256_gcm_seal(unsigned char *out, unsigned char tag[16], const unsigned char *aad, size_t aadlen, const unsigned char *in, size_t inlen, const unsigned char key[32], const unsigned char iv[12]); int verify_pins(char *data_store, const char *sopin, unsigned long sopinlen, const char *userpin, unsigned long userpinlen); CK_RV set_perm(int file, const char *group); #ifdef OCK_TOOL /* Log levels */ typedef enum { TRACE_LEVEL_NONE = 0, TRACE_LEVEL_ERROR, TRACE_LEVEL_WARNING, TRACE_LEVEL_INFO, TRACE_LEVEL_DEVEL, TRACE_LEVEL_DEBUG } pkcs_trace_level_t; #if defined(__GNUC__) && __GNUC__ >= 7 || defined(__clang__) && __clang_major__ >= 12 #define PRINTF_FORMAT __attribute__ ((format(printf, 4, 5))) #else #define PRINTF_FORMAT #endif void pkcs_trace(pkcs_trace_level_t level, const char * file, int line, const char *fmt, ...) PRINTF_FORMAT; void pkcs_hexdump(const char *prestr, void *buf, size_t buflen); #define TRACE_NONE(...) \ pkcs_trace(TRACE_LEVEL_NONE, __FILE__, __LINE__, __VA_ARGS__) #define TRACE_ERROR(...) \ pkcs_trace(TRACE_LEVEL_ERROR, __FILE__, __LINE__, __VA_ARGS__) #define TRACE_WARN(...) \ pkcs_trace(TRACE_LEVEL_WARNING, __FILE__, __LINE__, __VA_ARGS__) #define TRACE_INFO(...) \ pkcs_trace(TRACE_LEVEL_INFO, __FILE__, __LINE__, __VA_ARGS__) #define TRACE_DEVEL(...) \ pkcs_trace(TRACE_LEVEL_DEVEL, __FILE__, __LINE__, __VA_ARGS__) #define TRACE_DEBUG(...) \ pkcs_trace(TRACE_LEVEL_DEBUG, __FILE__, __LINE__, __VA_ARGS__) #ifdef DEBUG void hexdump(const char *prestr, void *buf, size_t buflen); #define TRACE_DEBUG_DUMP(_prestr, _buf, _buflen) pkcs_hexdump(_prestr, _buf, _buflen) #else #define TRACE_DEBUG_DUMP(...) #endif #endif /* OCK_TOOL */ #endif opencryptoki-opencryptoki-451d99c/usr/lib/common/pkey_utils.c000066400000000000000000001737511520105705100245450ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2020 * * This program is provided under the terms of the Common Public License, * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this * software constitutes recipient's acceptance of CPL-1.0 terms which can be * found in the file LICENSE file or at * https://opensource.org/licenses/cpl1.0.php */ /* * Some protected key related routines that are shared between the * CCA and EP11 tokens. */ #include #include #include #include #include #include #include #include #include #include #include "defs.h" #include "host_defs.h" #include "h_extern.h" #include "attributes.h" #include "trace.h" #include "pkey_utils.h" /* * The CPACF buffers for p521 key and signature parts have 80 bytes each, * but only the 66 right-most bytes are used. P521 signatures have 132 bytes. */ #define P521_BUF_OFFSET 14 /* * The CPACF buffers for ED448 key and signature parts have 64 bytes each, * but only the 57 right-most bytes are used. ED448 signatures have 114 bytes. */ #define ED448_BUF_OFFSET 7 static const CK_BYTE p256[] = OCK_PRIME256V1; static const CK_BYTE p384[] = OCK_SECP384R1; static const CK_BYTE p521[] = OCK_SECP521R1; static const CK_BYTE ed25519[] = OCK_ED25519; static const CK_BYTE ed448[] = OCK_ED448; #if defined(__GLIBC__) && defined(__GLIBC_PREREQ) # if __GLIBC_PREREQ(2, 16) # include # if defined(HWCAP_S390_STFLE) && defined(HWCAP_S390_VX) # define IMPLEMENT_GETAUXVAL # endif # endif #endif /** * s390_stfle: * * Executes the STFLE operation of the CPU. * * Returns the no. of double words needed to store the facility bits. */ static inline int s390_stfle(unsigned long long *list, int doublewords) { register unsigned long __nr __asm__("0") = doublewords - 1; __asm__ volatile(".insn s,0xb2b00000,0(%1)" /* stfle */ : "+d" (__nr) : "a" (list) : "memory", "cc"); return __nr + 1; } /** * Determine the machine's MSA level. */ int get_msa_level(void) { #ifdef IMPLEMENT_GETAUXVAL unsigned long long facility_bits[3]; int msa = 0; int num = 0; const unsigned long hwcap = getauxval(AT_HWCAP); if (hwcap & HWCAP_S390_STFLE) { memset(facility_bits, 0, sizeof(facility_bits)); num = s390_stfle(facility_bits, 3); /* s390_stfle always returns the no. of double words needed to store the * facility bits. This quantity is machine dependent. With MSA8, we * need the first three double words. */ if (num >= 2) { if(facility_bits[0] & (1ULL << (63 - 17))) msa = 1; if(facility_bits[1] & (1ULL << (127 - 76))) msa = 3; if(facility_bits[1] & (1ULL << (127 - 77))) msa = 4; if(facility_bits[0] & (1ULL << (63 - 57))) msa = 5; if (facility_bits[2] & (1ULL << (191 - 146))) msa = 8; if (facility_bits[2] & (1ULL << (191 - 155))) msa = 9; } } return msa; #endif return 0; } /** * s390_km: * @func: the function code passed to KM; see s390_km_func * @param: address of parameter block; see POP for details on each func * @dest: address of destination memory area * @src: address of source memory area * @src_len: length of src operand in bytes * * Executes the KM (CIPHER MESSAGE) operation of the CPU. * * Returns 0 for the query func, number of processed * bytes for encryption/decryption funcs */ static unsigned int s390_km(unsigned long func, void *param, unsigned char *dest, const unsigned char *src, unsigned long src_len) { register unsigned long __func __asm__("0") = func; register void *__param __asm__("1") = param; register const unsigned char *__src __asm__("2") = src; register unsigned long __src_len __asm__("3") = src_len; register unsigned char *__dest __asm__("4") = dest; __asm__ volatile ( "0: .insn rre,0xb92e0000,%2,%0 \n" /* KM opcode */ " brc 1,0b \n" /* handle partial completion */ : "+a"(__src), "+d"(__src_len), "+a"(__dest) : "d"(__func), "a"(__param) : "cc", "memory"); return func ? src_len - __src_len : __src_len; } /** * s390_kmc: * @func: the function code passed to KM; see s390_kmc_func * @param: address of parameter block; see POP for details on each func * @dest: address of destination memory area * @src: address of source memory area * @src_len: length of src operand in bytes * * Executes the KMC (CIPHER MESSAGE WITH CHAINING) operation of the CPU. * * Returns 0 for the query func, number of processed * bytes for encryption/decryption funcs */ static unsigned int s390_kmc(unsigned long func, void *param, unsigned char *dest, const unsigned char *src, unsigned long src_len) { register unsigned long __func __asm__("0") = func; register void *__param __asm__("1") = param; register const unsigned char *__src __asm__("2") = src; register unsigned long __src_len __asm__("3") = src_len; register unsigned char *__dest __asm__("4") = dest; __asm__ volatile ( "0: .insn rre, 0xb92f0000,%2,%0 \n" /* KMC opcode */ " brc 1, 0b \n" /* handle partial completion */ : "+a"(__src), "+d"(__src_len), "+a"(__dest) : "d"(__func), "a"(__param) : "cc", "memory"); return func ? src_len - __src_len : __src_len; } /** * s390_kdsa: * @func: the function code passed to KDSA; see s390_kdsa_functions * @param: address of parameter block; see POP for details on each func * @src: address of source memory area * @srclen: length of src operand in bytes * * Executes the KDSA (COMPUTE DIGITAL SIGNATURE AUTHENTICATION) operation of * the CPU. * * Returns 0 on success. Fails in case of sign if the random number was not * invertible. Fails in case of verify if the signature is invalid or the * public key is not on the curve. */ static int s390_kdsa(unsigned long func, void *param, const unsigned char *src, unsigned long srclen) { register unsigned long r0 __asm__("0") = (unsigned long)func; register unsigned long r1 __asm__("1") = (unsigned long)param; register unsigned long r2 __asm__("2") = (unsigned long)src; register unsigned long r3 __asm__("3") = (unsigned long)srclen; unsigned long rc = 1; __asm__ volatile( "0: .insn rre,%[__opc] << 16,0,%[__src]\n" " brc 1,0b\n" /* handle partial completion */ " brc 7,1f\n" " lghi %[__rc],0\n" "1:\n" : [__src] "+a" (r2), [__srclen] "+d" (r3), [__rc] "+d" (rc) : [__fc] "d" (r0), [__param] "a" (r1), [__opc] "i" (0xb93a) : "cc", "memory"); return (int)rc; } /** * s390_kmac: * @func: the function code passed to KMAC; see s390_kmac_func * @param: address of parameter block; see POP for details on each func * @src: address of source memory area * @src_len: length of src operand in bytes * * Executes the KMAC (COMPUTE MESSAGE AUTHENTICATION CODE) operation of the CPU. * * Returns 0 for the query func, number of processed * bytes for encryption/decryption funcs */ static unsigned int s390_kmac(unsigned long func, void *param, const unsigned char *src, unsigned long src_len) { register unsigned long __func __asm__("0") = func; register void *__param __asm__("1") = param; register const unsigned char *__src __asm__("2") = src; register unsigned long __src_len __asm__("3") = src_len; __asm__ volatile ( "0: .insn rre, 0xb91e0000,%0,%0 \n" " brc 1, 0b \n" : "+a"(__src), "+d"(__src_len) : "d"(__func), "a"(__param) : "cc", "memory"); return func ? src_len - __src_len : __src_len; } /** * s390_pcc: * @func: the function code passed to PCC; see s390_pcc_functions * @param: address of parameter block; see POP for details on each func * * Executes the PCC operation of the CPU. * * Returns condition code of the PCC instruction */ static inline int s390_pcc(unsigned long func, void *param) { register unsigned long r0 __asm__("0") = (unsigned long)func; register unsigned long r1 __asm__("1") = (unsigned long)param; char cc; __asm__ volatile( "0: .insn rre,%[opc] << 16,0,0\n" /* PCC opcode */ " brc 1,0b\n" /* handle partial completion */ " ipm %[cc]\n" " srl %[cc],28\n" : [cc] "=d" (cc) : [func] "d" (r0), [param] "a" (r1), [opc] "i" (0xb92c) : "cc", "memory" ); return cc; } static inline void s390_flip_endian_32(void *dest, const void *src) { __asm__ volatile( " lrvg %%r0,0(%[__src])\n" " lrvg %%r1,8(%[__src])\n" " lrvg %%r4,16(%[__src])\n" " lrvg %%r5,24(%[__src])\n" " stg %%r0,24(%[__dest])\n" " stg %%r1,16(%[__dest])\n" " stg %%r4,8(%[__dest])\n" " stg %%r5,0(%[__dest])\n" : : [__dest] "a" (dest), [__src] "a" (src) : "memory", "%r0", "%r1", "%r4", "%r5"); } static inline void s390_flip_endian_64(void *dest, const void *src) { __asm__ volatile( " lrvg %%r0,0(%[__src])\n" " lrvg %%r1,8(%[__src])\n" " lrvg %%r4,16(%[__src])\n" " lrvg %%r5,24(%[__src])\n" " lrvg %%r6,32(%[__src])\n" " lrvg %%r7,40(%[__src])\n" " lrvg %%r8,48(%[__src])\n" " lrvg %%r9,56(%[__src])\n" " stg %%r0,56(%[__dest])\n" " stg %%r1,48(%[__dest])\n" " stg %%r4,40(%[__dest])\n" " stg %%r5,32(%[__dest])\n" " stg %%r6,24(%[__dest])\n" " stg %%r7,16(%[__dest])\n" " stg %%r8,8(%[__dest])\n" " stg %%r9,0(%[__dest])\n" : : [__dest] "a" (dest), [__src] "a" (src) : "memory", "%r0", "%r1", "%r4", "%r5", "%r6", "%r7", "%r8", "%r9"); } /** * Return true if the given template indicates an EC public key, * false otherwise. */ CK_BBOOL pkey_is_ec_public_key(TEMPLATE *tmpl) { CK_ATTRIBUTE *attr = NULL; CK_ULONG class; if (template_attribute_get_ulong(tmpl, CKA_CLASS, &class) != CKR_OK) return CK_FALSE; if (class == CKO_PUBLIC_KEY) { if (template_attribute_get_non_empty(tmpl, CKA_ECDSA_PARAMS, &attr) == CKR_OK) return CK_TRUE; else return CK_FALSE; } return CK_FALSE; } /** * Update the specified attribute of the given key object. The object gets * locked for write and is saved, if it's a token object. * * Note: When calling this function, the XProcLock MUST NOT be held, * because it tries to obtain a write lock on the key object. */ CK_RV pkey_update_and_save(STDLL_TokData_t *tokdata, OBJECT *key_obj, CK_ATTRIBUTE **pkey_attr) { CK_RV ret1, ret2; /* Unlock obj to remove READ_LOCK */ ret1 = object_unlock(key_obj); if (ret1 != CKR_OK) { TRACE_ERROR("object_unlock failed with rc=0x%lx\n", ret1); return ret1; } /* Obtain write lock on key object */ ret1 = object_lock(key_obj, WRITE_LOCK); if (ret1 != CKR_OK) { TRACE_ERROR("object_lock for WRITE failed with rc=0x%lx\n", ret1); /* Try to restore read lock without rc checking */ object_lock(key_obj, READ_LOCK); return ret1; } /* Update attribute */ ret1 = template_update_attribute(key_obj->template, *pkey_attr); if (ret1 != CKR_OK) { TRACE_ERROR("template_update_attribute failed with rc=0x%lx\n", ret1); goto done; } *pkey_attr = NULL; /* Save to repository if it's a token object */ if (object_is_token_object(key_obj)) { ret1 = object_mgr_save_token_object(tokdata, key_obj); if (ret1 != CKR_OK) { TRACE_ERROR("Could not save token obj to repository, rc=0x%lx.\n", ret1); } } done: /* Restore object's READ_LOCK */ ret2 = object_unlock(key_obj); if (ret2 != CKR_OK) { TRACE_ERROR("object_unlock failed with rc=0x%lx\n", ret2); return ret1 == CKR_OK ? ret2 : ret1; } ret2 = object_lock(key_obj, READ_LOCK); if (ret2 != CKR_OK) { TRACE_ERROR("object_lock for READ failed with rc=0x%lx\n", ret2); return ret1 == CKR_OK ? ret2 : ret1; } return ret1; } /** * Returns true if the elliptic curve implied by the given key_obj * is supported by CPACF, false otherwise. */ CK_BBOOL pkey_op_ec_curve_supported_by_cpacf(TEMPLATE *tmpl) { CK_ATTRIBUTE *attr = NULL; CK_BYTE *ec_params; if (template_attribute_get_non_empty(tmpl, CKA_ECDSA_PARAMS, &attr) != CKR_OK) { TRACE_ERROR("%s: No CKA_ECDSA_PARAMS found in template, cannot determine curve\n", __func__); return CK_FALSE; } ec_params = (CK_BYTE *) attr->pValue; if ((attr->ulValueLen == sizeof(p256) && memcmp(ec_params, p256, sizeof(p256)) == 0) || (attr->ulValueLen == sizeof(p384) && memcmp(ec_params, p384, sizeof(p384)) == 0) || (attr->ulValueLen == sizeof(p521) && memcmp(ec_params, p521, sizeof(p521)) == 0) || (attr->ulValueLen == sizeof(ed25519) && memcmp(ec_params, ed25519, sizeof(ed25519)) == 0) || (attr->ulValueLen == sizeof(ed448) && memcmp(ec_params, ed448, sizeof(ed448)) == 0)) { return CK_TRUE; } return CK_FALSE; } /** * Returns true if the protected key operation implied by the given mechanism * is supported by CPACF, false otherwise. */ CK_BBOOL pkey_op_supported_by_cpacf(int msa_level, CK_MECHANISM *mech, TEMPLATE *tmpl) { CK_EDDSA_PARAMS *eddsa_params; switch (mech->mechanism) { case CKM_AES_ECB: case CKM_AES_CBC: case CKM_AES_CBC_PAD: if (msa_level > 1) return CK_TRUE; break; case CKM_AES_CMAC_GENERAL: case CKM_AES_CMAC: case CKM_AES_XTS: if (msa_level > 3) return CK_TRUE; break; case CKM_EDDSA: /* EDDSA is only supported with no prehashing and no context */ if (mech->ulParameterLen == sizeof(CK_EDDSA_PARAMS) && mech->pParameter != NULL) { eddsa_params = mech->pParameter; if (eddsa_params->phFlag || eddsa_params->ulContextDataLen > 0) return CK_FALSE; } /* Fall through */ case CKM_ECDSA: case CKM_ECDSA_SHA1: case CKM_ECDSA_SHA224: case CKM_ECDSA_SHA256: case CKM_ECDSA_SHA384: case CKM_ECDSA_SHA512: case CKM_IBM_ED25519_SHA512: case CKM_IBM_ED448_SHA3: if (msa_level > 8) return pkey_op_ec_curve_supported_by_cpacf(tmpl); break; default: break; } return CK_FALSE; } /** * Return the KM/KMC/KMAC function code for the given key length and * encrypt/decrypt op. */ unsigned long get_function_code(CK_ULONG clear_keylen, CK_BYTE encrypt) { unsigned long fc; switch (clear_keylen) { case 16: fc = ENCRYPTED_AES_128; break; case 24: fc = ENCRYPTED_AES_192; break; case 32: fc = ENCRYPTED_AES_256; break; default: return 0; } if (!encrypt) fc |= CPACF_DECRYPT; return fc; } /** * Performs an aes-ecb operation on the given data, using a protected key * via the KM-encrypted-AES instruction. The protected key must be * available in the key template as CKA_IBM_OPAQUE_PKEY. */ CK_RV pkey_aes_ecb(STDLL_TokData_t *tokdata, SESSION *session, OBJECT *key_obj, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG_PTR p_output_data_len, CK_BYTE encrypt, convert_key_t convert_key) { CK_RV ret; unsigned long fc; CK_ATTRIBUTE *pkey_attr = NULL; CK_ULONG clear_keylen; struct __attribute__((packed)){ uint8_t key[MAXPROTKEYSIZE]; } param; unsigned int bytes_processed = 0; int num_tries = 0; CK_BYTE protkey[MAXPROTKEYSIZE]; CK_ULONG protkey_len = sizeof(protkey); CK_BYTE *in_pos = in_data; CK_BYTE *out_pos = out_data; CK_ULONG len = in_data_len; /* Check parms */ if (in_data_len == 0) { ret = CKR_OK; goto done; } /* Handle implicit length_only parm (not passed down) */ if (!out_data) { *p_output_data_len = in_data_len; ret = CKR_OK; goto done; } /* Get protected key from key object */ if (template_attribute_get_non_empty(key_obj->template, CKA_IBM_OPAQUE_PKEY, &pkey_attr) != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_OPAQUE_PKEY in key's template.\n"); ret = CKR_FUNCTION_FAILED; goto done; } /* Determine clear key length */ if (template_attribute_get_ulong(key_obj->template, CKA_VALUE_LEN, &clear_keylen) != CKR_OK) { TRACE_ERROR("There is no CKA_VALUE_LEN, cannot determine clear keylen.\n"); ret = CKR_FUNCTION_FAILED; goto done; } /* Set function code */ fc = get_function_code(clear_keylen, encrypt); if (fc == 0) { TRACE_ERROR("Could not determine CPACF fc for given keylen %ld\n", clear_keylen); ret = CKR_FUNCTION_FAILED; goto done; } /* Call CPACF */ memcpy(param.key, pkey_attr->pValue, MIN(pkey_attr->ulValueLen, sizeof(param.key))); while (len > 0 && num_tries < PKEY_CONVERT_KEY_RETRIES) { bytes_processed = s390_km(fc, ¶m, out_pos, in_pos, len); if (bytes_processed < len) { TRACE_DEVEL("%s partial completion probably caused by an LGR: " "%d of %ld bytes processed.\n", __func__, bytes_processed, len); ret = convert_key(tokdata, session, key_obj, CK_FALSE, protkey, &protkey_len); if (ret != CKR_OK) goto done; memcpy(param.key, protkey, MIN(protkey_len, sizeof(param.key))); } in_pos += bytes_processed; out_pos += bytes_processed; len -= bytes_processed; num_tries++; } if (len > 0) { TRACE_ERROR("CPACF error: s390_km returned %i\n", bytes_processed); ret = CKR_FUNCTION_FAILED; goto done; } *p_output_data_len = in_data_len; ret = CKR_OK; done: return ret; } /** * Performs an AES-CBC operation via CPACF using a protected key. */ CK_RV pkey_aes_cbc(STDLL_TokData_t *tokdata, SESSION *session, OBJECT *key_obj, CK_BYTE *iv, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG_PTR p_output_data_len, CK_BYTE encrypt, convert_key_t convert_key) { CK_RV ret; unsigned long fc; CK_ATTRIBUTE *pkey_attr = NULL; CK_ULONG clear_keylen; struct __attribute__((packed)){ uint8_t iv[16]; uint8_t key[MAXPROTKEYSIZE]; } param; unsigned int bytes_processed = 0; int num_tries = 0; CK_BYTE protkey[MAXPROTKEYSIZE]; CK_ULONG protkey_len = sizeof(protkey); CK_BYTE *in_pos = in_data; CK_BYTE *out_pos = out_data; CK_ULONG len = in_data_len; /* Check parms */ if (in_data_len == 0) { ret = CKR_OK; goto done; } /* Handle implicit length_only parm (not passed down) */ if (!out_data) { *p_output_data_len = in_data_len; ret = CKR_OK; goto done; } /* Get protected key from key object */ if (template_attribute_get_non_empty(key_obj->template, CKA_IBM_OPAQUE_PKEY, &pkey_attr) != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_OPAQUE_PKEY in key's template.\n"); ret = CKR_FUNCTION_FAILED; goto done; } /* Determine clear key length */ if (template_attribute_get_ulong(key_obj->template, CKA_VALUE_LEN, &clear_keylen) != CKR_OK) { TRACE_ERROR("Cannot determine clear key len.\n"); ret = CKR_FUNCTION_FAILED; goto done; } /* Set function code */ fc = get_function_code(clear_keylen, encrypt); if (fc == 0) { TRACE_ERROR("Could not determine CPACF fc for given keylen %ld\n", clear_keylen); ret = CKR_FUNCTION_FAILED; goto done; } /* Call CPACF */ memcpy(param.iv, iv, 16); memcpy(param.key, pkey_attr->pValue, MIN(pkey_attr->ulValueLen, sizeof(param.key))); while (len > 0 || num_tries < PKEY_CONVERT_KEY_RETRIES) { bytes_processed = s390_kmc(fc, ¶m, out_pos, in_pos, len); if (bytes_processed < len) { TRACE_DEVEL("%s partial completion probably caused by an LGR: " "%d of %ld bytes processed.\n", __func__, bytes_processed, len); ret = convert_key(tokdata, session, key_obj, CK_FALSE, protkey, &protkey_len); if (ret != CKR_OK) goto done; memcpy(param.key, protkey, MIN(protkey_len, sizeof(param.key))); } in_pos += bytes_processed; out_pos += bytes_processed; len -= bytes_processed; num_tries++; } if (len > 0) { TRACE_ERROR("CPACF error: s390_kmc returned %i\n", bytes_processed); ret = CKR_FUNCTION_FAILED; goto done; } *p_output_data_len = in_data_len; memcpy(iv, param.iv, AES_BLOCK_SIZE); ret = CKR_OK; done: return ret; } #define PARM_BLOCK_SIZE 8192 typedef unsigned char parm_block_t[PARM_BLOCK_SIZE]; struct parm_block_lookup { unsigned int block_size; unsigned char *base; uint8_t *ml; unsigned char *message; unsigned char *iv; unsigned char *keys; }; static inline void parm_block_lookup_init(struct parm_block_lookup *lookup, parm_block_t base, unsigned int block_size) { lookup->block_size = block_size; lookup->base = base; lookup->ml = (uint8_t *)base; lookup->message = (unsigned char *)(base + 8); lookup->iv = (unsigned char *)(lookup->message + block_size); lookup->keys = (unsigned char *)(lookup->iv + block_size); } /** * Calculates an AES-CMAC via CPACF using a protected key. */ CK_RV pkey_aes_cmac(STDLL_TokData_t *tokdata, SESSION *session, OBJECT *key_obj, CK_BYTE *message, CK_ULONG message_len, CK_BYTE *cmac, CK_BYTE *iv, convert_key_t convert_key) { CK_RV ret; parm_block_t parm_block; unsigned long fc; struct parm_block_lookup pb_lookup; unsigned int length_tail; unsigned long length_head; CK_ULONG clear_keylen; CK_ATTRIBUTE *pkey_attr = NULL; int rc; unsigned int bytes_processed; int num_tries; CK_BYTE protkey[MAXPROTKEYSIZE]; CK_ULONG protkey_len = sizeof(protkey); CK_BYTE *in_pos = message; CK_ULONG len = message_len; /* Determine clear key length */ if (template_attribute_get_ulong(key_obj->template, CKA_VALUE_LEN, &clear_keylen) != CKR_OK) { TRACE_ERROR("No CKA_VALUE_LEN given, cannot determine clear key length\n"); ret = CKR_FUNCTION_FAILED; goto done; } /* Set function code */ fc = get_function_code(clear_keylen, CPACF_DECRYPT); if (fc == 0) { TRACE_ERROR("Could not determine CPACF fc for given keylen %ld\n", clear_keylen); ret = CKR_FUNCTION_FAILED; goto done; } /* Get protected key from key object */ if (template_attribute_get_non_empty(key_obj->template, CKA_IBM_OPAQUE_PKEY, &pkey_attr) != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_OPAQUE_PKEY in key's template.\n"); ret = CKR_FUNCTION_FAILED; goto done; } /* Setup parm block */ memset(parm_block, 0, sizeof(parm_block)); parm_block_lookup_init(&pb_lookup, parm_block, AES_BLOCK_SIZE); memcpy(pb_lookup.keys, pkey_attr->pValue, MIN(pkey_attr->ulValueLen, MAXPROTKEYSIZE)); /* copy iv into param block, if available (intermediate) */ if (iv != NULL) memcpy(pb_lookup.iv, iv, pb_lookup.block_size); if (cmac == NULL) { /* intermediate */ num_tries = 0; while (len > 0 && num_tries < PKEY_CONVERT_KEY_RETRIES) { bytes_processed = s390_kmac(fc, pb_lookup.iv, in_pos, len); if (bytes_processed < len) { TRACE_DEVEL("%s partial completion probably caused by an LGR: " "%d of %ld bytes processed.\n", __func__, bytes_processed, len); ret = convert_key(tokdata, session, key_obj, CK_FALSE, protkey, &protkey_len); if (ret != CKR_OK) goto done; memcpy(pb_lookup.keys, protkey, MIN(protkey_len, MAXPROTKEYSIZE)); } in_pos += bytes_processed; len -= bytes_processed; num_tries++; } if (len > 0) { ret = CKR_FUNCTION_FAILED; goto done; } /* rescue iv for chained calls (intermediate) */ memcpy(iv, pb_lookup.iv, pb_lookup.block_size); } else { if (message_len) { length_tail = message_len % pb_lookup.block_size; if (length_tail) length_head = message_len - length_tail; else { length_head = message_len - pb_lookup.block_size; length_tail = pb_lookup.block_size; } if (length_head) { num_tries = 0; len = length_head; while (len > 0 && num_tries < PKEY_CONVERT_KEY_RETRIES) { bytes_processed = s390_kmac(fc, pb_lookup.iv, in_pos, len); if (bytes_processed < len) { TRACE_DEVEL("%s partial completion probably caused by an LGR: " "%d of %ld bytes processed.\n", __func__, bytes_processed, len); ret = convert_key(tokdata, session, key_obj, CK_FALSE, protkey, &protkey_len); if (ret != CKR_OK) goto done; memcpy(pb_lookup.keys, protkey, MIN(protkey_len, MAXPROTKEYSIZE)); } in_pos += bytes_processed; len -= bytes_processed; num_tries++; } if (len > 0) { memset(pb_lookup.keys, 0, pkey_attr->ulValueLen); ret = CKR_FUNCTION_FAILED; goto done; } } *pb_lookup.ml = length_tail * 8; /* message length in bits */ memcpy(pb_lookup.message, message + length_head, length_tail); } /* calculate final block (last/full) */ num_tries = 0; rc = 1; while (rc != 0 && num_tries < PKEY_CONVERT_KEY_RETRIES) { rc = s390_pcc(fc, pb_lookup.base); num_tries++; } memset(pb_lookup.keys, 0, pkey_attr->ulValueLen); if (rc != 0) { ret = CKR_FUNCTION_FAILED; goto done; } if (cmac) memcpy(cmac, pb_lookup.iv, AES_BLOCK_SIZE); } ret = CKR_OK; done: return ret; } /** * Return the KM/KMC/KMAC function code for the given key length and * encrypt/decrypt op. */ unsigned long get_xts_function_code(CK_ULONG keylen, CK_BYTE encrypt) { unsigned long fc; switch (keylen) { case 32: fc = ENCRYPTED_AES_XTS_128; break; case 64: fc = ENCRYPTED_AES_XTS_256; break; default: return 0; } if (!encrypt) fc |= CPACF_DECRYPT; return fc; } /* compute protected key length [bytes] from key-size [bits] */ #define AES_XTS_PROTKEYLEN(size) (32 + 16 * (size) / 128 ) /* compute offsets [bytes] in PCC param structure from key-size [bits] */ #define AES_XTS_PCC_I(size) (AES_XTS_PROTKEYLEN(size) + 0 * 16) #define AES_XTS_PCC_XTSPARAM(size) (AES_XTS_PROTKEYLEN(size) + 3 * 16) /* compute offsets [bytes] in KM param structure from key-size [bits] */ #define AES_XTS_KM_XTSPARAM(size) (AES_XTS_PROTKEYLEN(size) + 0 * 16) /* parameter block for pcc compute for aes xts 256 */ struct cpacf_pcc_xts_aes_256_param { uint8_t protkey[64]; /* WKa(K)|WKaVP */ uint8_t i[16]; uint8_t j[16]; uint8_t t[16]; uint8_t xtsparams[16]; }; /* parameter block for aes xts 256 */ struct cpacf_km_xts_aes_256_param { uint8_t protkey[64]; /* WKa(K)|WKaVP */ uint8_t xtsparam[16]; }; struct aes_xts_param { union { struct cpacf_km_xts_aes_256_param param_s; uint8_t param_km[sizeof(struct cpacf_km_xts_aes_256_param)]; } km; union { struct cpacf_pcc_xts_aes_256_param param_s; uint8_t param_pcc[sizeof(struct cpacf_pcc_xts_aes_256_param)]; } pcc; unsigned int fc; unsigned int keylen; convert_key_t convert_key; STDLL_TokData_t *tokdata; SESSION *session; OBJECT *key_obj; }; static CK_RV pkey_aes_xts_iv_from_tweak(CK_BYTE *tweak, CK_BYTE* iv, void *cb_data) { struct aes_xts_param *param = cb_data; convert_key_t convert_key = param->convert_key; int offset, rc = 1, num_tries = 0; CK_BYTE protkey[MAXPROTKEYSIZE * 2]; CK_ULONG protkey_len = sizeof(protkey); CK_RV ret; offset = AES_XTS_PCC_I(param->keylen * 8); memcpy(param->pcc.param_pcc + offset, tweak, AES_BLOCK_SIZE); while (rc != 0 && num_tries < PKEY_CONVERT_KEY_RETRIES) { rc = s390_pcc(param->fc & 0x7f, param->pcc.param_pcc); if (rc != 0) { TRACE_DEVEL("%s rc from s390_pcc = %d, probably caused by " "an LGR. Rederiving protkey and retrying ...\n", __func__, rc); ret = convert_key(param->tokdata, param->session, param->key_obj, CK_TRUE, protkey, &protkey_len); if (ret != CKR_OK) break; /* * Copy XTS key 1 into CPACF parmblock for KM instruction. After * re-deriving the iv from tweak, the subsequent calls to * pkey_aes_xts_cipher_blocks will then use the re-derived key * as well. */ memcpy(param->km.param_s.protkey, protkey, MIN(protkey_len / 2, sizeof(param->km.param_s.protkey))); /* * Copy XTS key 2 into CPACF parmblock for PCC instruction. Key 2 * is used to create the iv from tweak via PCC. The key object * itself contains both keys in re-derived form after convert_key. */ memcpy(param->pcc.param_s.protkey, protkey + protkey_len / 2, MIN(protkey_len / 2, sizeof(param->pcc.param_s.protkey))); num_tries++; } } if (rc != 0) { TRACE_ERROR("s390_pcc function failed\n"); return CKR_FUNCTION_FAILED; } offset = AES_XTS_PCC_XTSPARAM(param->keylen * 8); memcpy(iv, param->pcc.param_pcc + offset, AES_BLOCK_SIZE); return CKR_OK; } static CK_RV pkey_aes_xts_cipher_blocks(CK_BYTE *in, CK_BYTE *out, CK_ULONG len, CK_BYTE *iv, void *cb_data) { struct aes_xts_param *param = cb_data; convert_key_t convert_key = param->convert_key; unsigned int bytes_processed = 0; int num_tries = 0; CK_BYTE protkey[MAXPROTKEYSIZE * 2]; CK_ULONG protkey_len = sizeof(protkey); CK_BYTE *in_pos = in; CK_BYTE *out_pos = out; CK_ULONG len2 = len; CK_RV ret; int offset = AES_XTS_KM_XTSPARAM(param->keylen * 8); memcpy(param->km.param_km + offset, iv, AES_BLOCK_SIZE); while (len2 > 0 && num_tries < PKEY_CONVERT_KEY_RETRIES) { bytes_processed = s390_km(param->fc, param->km.param_km, out_pos, in_pos, len2); if (bytes_processed < len2) { TRACE_DEVEL("%s partial completion probably caused by an LGR: " "%d of %ld bytes processed.\n", __func__, bytes_processed, len2); ret = convert_key(param->tokdata, param->session, param->key_obj, CK_TRUE, protkey, &protkey_len); if (ret != CKR_OK) goto done; /* * Copy XTS key 1 into CPACF parmblock for KM instruction. Key 2 * is no more needed, as it was only used at the beginning of the * op to create the iv from tweak via PCC. But the key object now * contains both keys in rederived form. */ memcpy(param->km.param_s.protkey, protkey, MIN(protkey_len / 2, sizeof(param->km.param_s.protkey))); } in_pos += bytes_processed; out_pos += bytes_processed; len2 -= bytes_processed; num_tries++; } if (len2 > 0) { TRACE_ERROR("s390_km function failed\n"); ret = CKR_FUNCTION_FAILED; goto done; } memcpy(iv, param->km.param_km + offset, AES_BLOCK_SIZE); ret = CKR_OK; done: return ret; } /** * Performs an AES-XTS operation via CPACF using a protected key. */ CK_RV pkey_aes_xts(STDLL_TokData_t *tokdata, SESSION *session, OBJECT *key_obj, CK_BYTE *tweak, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG_PTR p_output_data_len, CK_BYTE encrypt, CK_BBOOL initial, CK_BBOOL final, CK_BYTE *iv, convert_key_t convert_key) { CK_RV ret = CKR_OK; CK_ATTRIBUTE *pkey_attr = NULL; struct aes_xts_param param = {0}; CK_ULONG keylen = 0; unsigned long fc; /* Check parms */ if (in_data_len == 0) { ret = CKR_OK; return CKR_OK; } /* Handle implicit length_only parm (not passed down) */ if (out_data == NULL) { *p_output_data_len = in_data_len; return CKR_OK; } if (*p_output_data_len < in_data_len) { TRACE_ERROR("Output buffer too small.\n"); return CKR_BUFFER_TOO_SMALL; } /* Get protected key from key object */ if (template_attribute_get_non_empty(key_obj->template, CKA_IBM_OPAQUE_PKEY, &pkey_attr) != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_OPAQUE_PKEY in key's template.\n"); return CKR_FUNCTION_FAILED; } /* Determine clear key length */ if (template_attribute_get_ulong(key_obj->template, CKA_VALUE_LEN, &keylen) != CKR_OK) { TRACE_ERROR("Cannot determine clear key len.\n"); return CKR_FUNCTION_FAILED; } /* Set function code */ fc = get_xts_function_code(keylen, encrypt); if (fc == 0) { TRACE_ERROR("Could not determine CPACF fc for given keylen %ld\n", keylen); return CKR_FUNCTION_FAILED; } keylen = keylen / 2; memcpy(param.km.param_s.protkey, pkey_attr->pValue, MIN(pkey_attr->ulValueLen / 2, sizeof(param.km.param_s.protkey))); memcpy(param.pcc.param_s.protkey, (CK_BYTE *)pkey_attr->pValue + pkey_attr->ulValueLen / 2, MIN(pkey_attr->ulValueLen / 2, sizeof(param.pcc.param_s.protkey))); param.fc = fc; param.keylen = keylen; param.convert_key = convert_key; param.tokdata = tokdata; param.session = session; param.key_obj = key_obj; ret = aes_xts_cipher(in_data, in_data_len, out_data, p_output_data_len, tweak, encrypt, initial, final, iv, pkey_aes_xts_iv_from_tweak, pkey_aes_xts_cipher_blocks, ¶m); return ret; } /** * Determine the CPACF curve type from given template. */ cpacf_curve_type_t get_cpacf_curve_type(TEMPLATE *tmpl) { CK_BYTE *ec_params; CK_ATTRIBUTE *attr = NULL; cpacf_curve_type_t curve_type; /* Determine CKA_EC_PARAMS */ if (template_attribute_get_non_empty(tmpl, CKA_EC_PARAMS, &attr) != CKR_OK) { TRACE_ERROR("%s: This template does not have CKA_EC_PARAMS, cannot determine curve type.\n", __func__); curve_type = curve_invalid; goto done; } ec_params = (CK_BYTE *) attr->pValue; if (attr->ulValueLen == sizeof(p256) && memcmp(ec_params, p256, sizeof(p256)) == 0) curve_type = curve_p256; else if (attr->ulValueLen == sizeof(p384) && memcmp(ec_params, p384, sizeof(p384)) == 0) curve_type = curve_p384; else if (attr->ulValueLen == sizeof(p521) && memcmp(ec_params, p521, sizeof(p521)) == 0) curve_type = curve_p521; else if (attr->ulValueLen == sizeof(ed25519) && memcmp(ec_params, ed25519, sizeof(ed25519)) == 0) curve_type = curve_ed25519; else if (attr->ulValueLen == sizeof(ed448) && memcmp(ec_params, ed448, sizeof(ed448)) == 0) curve_type = curve_ed448; else curve_type = curve_invalid; done: return curve_type; } /** * Sign the given hash via CPACF using the given protected private key. */ CK_RV pkey_ec_sign(STDLL_TokData_t *tokdata, SESSION *session, OBJECT *privkey, CK_BYTE *hash, CK_ULONG hash_len, CK_BYTE *sig, CK_ULONG *sig_len, void (*rng_cb)(unsigned char *, size_t), convert_key_t convert_key) { #define DEF_PARAM(curve, size) \ struct { \ unsigned char sig_r[size]; \ unsigned char sig_s[size]; \ unsigned char hash[size]; \ unsigned char priv[size]; \ unsigned char rand[size]; \ unsigned char vp[32]; \ short c; \ short res; \ } curve union { long long buff[512]; /* 4k buffer: params + reserved area */ DEF_PARAM(P256, 32); DEF_PARAM(P384, 48); DEF_PARAM(P521, 80); } param; #undef DEF_PARAM CK_RV ret; unsigned long fc; CK_ATTRIBUTE *pkey_attr = NULL; int rc, off; cpacf_curve_type_t curve_type; CK_BYTE protkey[112]; /* max = 80 (p521) + 32 wkvp */ CK_ULONG protkey_len = sizeof(protkey); CK_ULONG retry_count = 0; /* Get protected key from key object */ if (template_attribute_get_non_empty(privkey->template, CKA_IBM_OPAQUE_PKEY, &pkey_attr) != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_OPAQUE_PKEY in key's template.\n"); ret = CKR_FUNCTION_FAILED; goto done; } /* Setup CPACF parmblock */ memset(¶m, 0, sizeof(param)); curve_type = get_cpacf_curve_type(privkey->template); switch (curve_type) { case curve_p256: if (pkey_attr->ulValueLen != sizeof(param.P256.priv) + sizeof(param.P256.vp)) { TRACE_ERROR("Protected key has an invalid length of %ld bytes.\n", pkey_attr->ulValueLen); ret = CKR_ATTRIBUTE_VALUE_INVALID; goto done; } if (hash_len > sizeof(param.P256.hash)) hash_len = sizeof(param.P256.hash); off = sizeof(param.P256.hash) - hash_len; memcpy(param.P256.hash + off, hash, hash_len); memcpy(param.P256.priv, pkey_attr->pValue, sizeof(param.P256.priv)); memcpy(param.P256.vp, (char *)pkey_attr->pValue + sizeof(param.P256.priv), sizeof(param.P256.vp)); *sig_len = 2 * sizeof(param.P256.sig_r); break; case curve_p384: if (pkey_attr->ulValueLen != sizeof(param.P384.priv) + sizeof(param.P384.vp)) { TRACE_ERROR("Protected key has an invalid length of %ld bytes.\n", pkey_attr->ulValueLen); ret = CKR_ATTRIBUTE_VALUE_INVALID; goto done; } if (hash_len > sizeof(param.P384.hash)) hash_len = sizeof(param.P384.hash); off = sizeof(param.P384.hash) - hash_len; memcpy(param.P384.hash + off, hash, hash_len); memcpy(param.P384.priv, pkey_attr->pValue, sizeof(param.P384.priv)); memcpy(param.P384.vp, (char *)pkey_attr->pValue + sizeof(param.P384.priv), sizeof(param.P384.vp)); *sig_len = 2 * sizeof(param.P384.sig_r); break; case curve_p521: if (pkey_attr->ulValueLen != sizeof(param.P521.priv) + sizeof(param.P521.vp)) { TRACE_ERROR("Protected key has an invalid length of %ld bytes.\n", pkey_attr->ulValueLen); ret = CKR_ATTRIBUTE_VALUE_INVALID; goto done; } if (hash_len > sizeof(param.P521.hash) - P521_BUF_OFFSET) hash_len = sizeof(param.P521.hash) - P521_BUF_OFFSET; /* Note that the pkey for p521 has 80 + 32 bytes. */ off = sizeof(param.P521.hash) - hash_len; memcpy(param.P521.hash + off, hash, hash_len); memcpy(param.P521.priv, pkey_attr->pValue, sizeof(param.P521.priv)); memcpy(param.P521.vp, (char *)pkey_attr->pValue + sizeof(param.P521.priv), sizeof(param.P521.vp)); *sig_len = 2 * (sizeof(param.P521.sig_r) - P521_BUF_OFFSET); break; default: TRACE_ERROR("Could not determine the curve type.\n"); ret = CKR_FUNCTION_FAILED; goto done; } if (sig == NULL) { /* length_only requested, just return with *sig_len */ ret = CKR_OK; goto done; } /* Set random number and function code */ switch (curve_type) { case curve_p256: fc = KDSA_ENCRYPTED_ECDSA_SIGN_P256 | 0x80; if (rng_cb != NULL) { rng_cb(param.P256.rand, sizeof(param.P256.rand)); fc = KDSA_ENCRYPTED_ECDSA_SIGN_P256; } break; case curve_p384: fc = KDSA_ENCRYPTED_ECDSA_SIGN_P384 | 0x80; if (rng_cb != NULL) { rng_cb(param.P384.rand, sizeof(param.P384.rand)); fc = KDSA_ENCRYPTED_ECDSA_SIGN_P384; } break; case curve_p521: fc = KDSA_ENCRYPTED_ECDSA_SIGN_P521 | 0x80; if (rng_cb != NULL) { rng_cb(param.P521.rand, sizeof(param.P521.rand)); fc = KDSA_ENCRYPTED_ECDSA_SIGN_P521; } break; default: TRACE_ERROR("Could not determine the curve type.\n"); ret = CKR_FUNCTION_FAILED; goto done; } /* Call CPACF */ retry: if (retry_count > PKEY_CONVERT_KEY_RETRIES) goto done; rc = s390_kdsa(fc, param.buff, NULL, 0); switch (rc) { case 0: ret = CKR_OK; break; case 1: switch (curve_type) { case curve_p256: TRACE_ERROR("%s rc from KDSA = 1 and C = %02X.\n", __func__, param.P256.c); break; case curve_p384: TRACE_ERROR("%s rc from KDSA = 1 and C = %02X.\n", __func__, param.P384.c); break; case curve_p521: TRACE_ERROR("%s rc from KDSA = 1 and C = %02X.\n", __func__, param.P521.c); break; default: break; } ret = CKR_FUNCTION_FAILED; break; default: /* rc = 2 */ TRACE_ERROR("%s rc from KDSA = 2\n", __func__); ret = CKR_FUNCTION_FAILED; } if (ret != CKR_OK) { ret = convert_key(tokdata, session, privkey, CK_FALSE, protkey, &protkey_len); if (ret != CKR_OK) goto done; TRACE_DEVEL("%s KDSA failed probably caused by an LGR, hash len " "was %ld, retrying ...\n", __func__, hash_len); retry_count++; switch (curve_type) { case curve_p256: memcpy(param.P256.priv, protkey, sizeof(param.P256.priv)); memcpy(param.P256.vp, protkey + sizeof(param.P256.priv), sizeof(param.P256.vp)); goto retry; case curve_p384: memcpy(param.P384.priv, protkey, sizeof(param.P384.priv)); memcpy(param.P384.vp, protkey + sizeof(param.P384.priv), sizeof(param.P384.vp)); goto retry; case curve_p521: memcpy(param.P521.priv, protkey, sizeof(param.P521.priv)); memcpy(param.P521.vp, protkey + sizeof(param.P521.priv), sizeof(param.P521.vp)); goto retry; default: TRACE_ERROR("Could not determine the curve type.\n"); ret = CKR_FUNCTION_FAILED; goto done; } } /* Provide signature to caller */ switch (curve_type) { case curve_p256: case curve_p384: /* r and s are consecutive in the param block */ memcpy(sig, param.buff, *sig_len); break; case curve_p521: /* r and s are both righ-aligned in the param block */ memcpy(sig, param.P521.sig_r + P521_BUF_OFFSET, sizeof(param.P521.sig_r) - P521_BUF_OFFSET); memcpy(sig + sizeof(param.P521.sig_r) - P521_BUF_OFFSET, param.P521.sig_s + P521_BUF_OFFSET, sizeof(param.P521.sig_s) - P521_BUF_OFFSET); break; default: TRACE_ERROR("Could not determine the curve type.\n"); ret = CKR_FUNCTION_FAILED; goto done; } OPENSSL_cleanse(¶m, sizeof(param)); ret = CKR_OK; done: return ret; } /** * Sign the given input message via CPACF using the given protected private key. * This routine only supports the two Edwards curves ED25519 and ED448. * Note: The original input message is passed to CPACF without being * pre-hashed. Hashing is done internally in CPACF. Also no context is * supported. */ CK_RV pkey_ed_sign(STDLL_TokData_t *tokdata, SESSION *session, OBJECT *privkey, CK_BYTE *msg, CK_ULONG msg_len, CK_BYTE *sig, CK_ULONG *sig_len, convert_key_t convert_key) { #define DEF_EDPARAM(curve, size) \ struct { \ unsigned char sig_r[size]; \ unsigned char sig_s[size]; \ unsigned char priv[size]; \ unsigned char vp[32]; \ unsigned char res1[16]; \ short c; \ short res2; \ } curve union { long long buff[512]; /* 4k buffer: params + reserved area */ DEF_EDPARAM(ED25519, 32); DEF_EDPARAM(ED448, 64); } edparam; #undef DEF_EDPARAM CK_RV ret; unsigned long fc; CK_ATTRIBUTE *pkey_attr = NULL; int rc; cpacf_curve_type_t curve_type; CK_BYTE protkey[96]; /* max = 64 (ed448) + 32 wkvp */ CK_ULONG protkey_len = sizeof(protkey); CK_ULONG retry_count = 0; /* Get protected key from key object */ if (template_attribute_get_non_empty(privkey->template, CKA_IBM_OPAQUE_PKEY, &pkey_attr) != CKR_OK) { TRACE_ERROR("Could not find CKA_IBM_OPAQUE_PKEY in key's template.\n"); ret = CKR_FUNCTION_FAILED; goto done; } /* Setup CPACF parmblock */ memset(&edparam, 0, sizeof(edparam)); curve_type = get_cpacf_curve_type(privkey->template); switch (curve_type) { case curve_ed25519: if (pkey_attr->ulValueLen != sizeof(edparam.ED25519.priv) + sizeof(edparam.ED25519.vp)) { TRACE_ERROR("Protected key has an invalid length of %ld bytes.\n", pkey_attr->ulValueLen); ret = CKR_ATTRIBUTE_VALUE_INVALID; goto done; } fc = KDSA_ENCRYPTED_EDDSA_SIGN_ED25519; memcpy(edparam.ED25519.priv, pkey_attr->pValue, sizeof(edparam.ED25519.priv)); memcpy(edparam.ED25519.vp, (char *)pkey_attr->pValue + sizeof(edparam.ED25519.priv), sizeof(edparam.ED25519.vp)); *sig_len = 2 * sizeof(edparam.ED25519.sig_r); break; case curve_ed448: if (pkey_attr->ulValueLen != sizeof(edparam.ED448.priv) + sizeof(edparam.ED448.vp)) { TRACE_ERROR("Protected key has an invalid length of %ld bytes.\n", pkey_attr->ulValueLen); ret = CKR_ATTRIBUTE_VALUE_INVALID; goto done; } fc = KDSA_ENCRYPTED_EDDSA_SIGN_ED448; memcpy(edparam.ED448.priv, pkey_attr->pValue, sizeof(edparam.ED448.priv)); memcpy(edparam.ED448.vp, (char *)pkey_attr->pValue + sizeof(edparam.ED448.priv), sizeof(edparam.ED448.vp)); *sig_len = 2 * (sizeof(edparam.ED448.sig_r) - ED448_BUF_OFFSET); break; default: TRACE_ERROR("Could not determine the curve type.\n"); ret = CKR_FUNCTION_FAILED; goto done; } if (sig == NULL) { /* length_only requested, just return with *sig_len */ ret = CKR_OK; goto done; } /* Call CPACF */ retry: if (retry_count > PKEY_CONVERT_KEY_RETRIES) goto done; rc = s390_kdsa(fc, edparam.buff, msg, msg_len); switch (rc) { case 0: ret = CKR_OK; break; case 1: switch (curve_type) { case curve_ed25519: TRACE_ERROR("%s rc from KDSA = 1 and C = %02X.\n", __func__, edparam.ED25519.c); break; case curve_ed448: TRACE_ERROR("%s rc from KDSA = 1 and C = %02X.\n", __func__, edparam.ED448.c); break; default: break; } ret = CKR_FUNCTION_FAILED; break; default: /* rc = 2 */ TRACE_ERROR("%s rc from KDSA = 2\n", __func__); ret = CKR_FUNCTION_FAILED; } if (ret != CKR_OK) { ret = convert_key(tokdata, session, privkey, CK_FALSE, protkey, &protkey_len); if (ret != CKR_OK) goto done; TRACE_DEVEL("%s KDSA failed probably caused by an LGR, msg len " "was %ld, retrying ...\n", __func__, msg_len); retry_count++; switch (curve_type) { case curve_ed25519: memcpy(edparam.ED25519.priv, protkey, sizeof(edparam.ED25519.priv)); memcpy(edparam.ED25519.vp, protkey + sizeof(edparam.ED25519.priv), sizeof(edparam.ED25519.vp)); goto retry; case curve_ed448: memcpy(edparam.ED448.priv, protkey, sizeof(edparam.ED448.priv)); memcpy(edparam.ED448.vp, protkey + sizeof(edparam.ED448.priv), sizeof(edparam.ED448.vp)); goto retry; default: TRACE_ERROR("Could not determine the curve type.\n"); ret = CKR_FUNCTION_FAILED; goto done; } } /* Provide signature to caller */ switch (curve_type) { case curve_ed25519: /* r and s are consecutive in the param block */ s390_flip_endian_32(sig, edparam.ED25519.sig_r); s390_flip_endian_32(sig + sizeof(edparam.ED25519.sig_r), edparam.ED25519.sig_s); break; case curve_ed448: /* r and s are right aligned in the param block */ s390_flip_endian_64(edparam.ED448.sig_r, edparam.ED448.sig_r); s390_flip_endian_64(edparam.ED448.sig_s, edparam.ED448.sig_s); memcpy(sig, edparam.ED448.sig_r, sizeof(edparam.ED448.sig_r) - ED448_BUF_OFFSET); memcpy(sig + sizeof(edparam.ED448.sig_r) - ED448_BUF_OFFSET, edparam.ED448.sig_s, sizeof(edparam.ED448.sig_s) - ED448_BUF_OFFSET); break; default: TRACE_ERROR("Could not determine the curve type.\n"); ret = CKR_FUNCTION_FAILED; goto done; } OPENSSL_cleanse(&edparam, sizeof(edparam)); ret = CKR_OK; done: return ret; } /** * Verify the given signature via CPACF using the given public key. */ CK_RV pkey_ec_verify(OBJECT *pubkey, CK_BYTE *hash, CK_ULONG hash_len, CK_BYTE *sig, CK_ULONG sig_len) { #define DEF_PARAM(curve, size) \ struct { \ unsigned char sig_r[size]; \ unsigned char sig_s[size]; \ unsigned char hash[size]; \ unsigned char pub_x[size]; \ unsigned char pub_y[size]; \ } curve union { long long buff[512]; /* 4k buffer: params + reserved area */ DEF_PARAM(P256, 32); DEF_PARAM(P384, 48); DEF_PARAM(P521, 80); } param; #undef DEF_PARAM CK_RV ret; unsigned long fc; CK_ATTRIBUTE *pub_attr = NULL; int rc, hash_off, key_off; CK_BYTE *ecpoint; CK_ULONG ecpoint_len, field_len; cpacf_curve_type_t curve_type; /* Get public key from template */ if (template_attribute_get_non_empty(pubkey->template, CKA_EC_POINT, &pub_attr) != CKR_OK) { TRACE_ERROR("%s: This public key does not have a CKA_EC_POINT.\n", __func__); ret = CKR_FUNCTION_FAILED; goto done; } /* CKA_EC_POINT is an BER encoded OCTET STRING. Extract it. */ rc = ber_decode_OCTET_STRING(pub_attr->pValue, pub_attr->ulValueLen, &ecpoint, &ecpoint_len, &field_len); if (rc != CKR_OK || pub_attr->ulValueLen != field_len) { TRACE_ERROR("%s: ber_decode_OCTET_STRING failed\n", __func__); ret = CKR_ATTRIBUTE_VALUE_INVALID; goto done; } /* Uncompressed EC keys have both (x,y) values and begin with 0x04 */ if (ecpoint[0] != 0x04) { TRACE_ERROR("%s: EC_POINT is compressed, not supported here.\n", __func__); ret = CKR_ATTRIBUTE_VALUE_INVALID; goto done; } ecpoint++; ecpoint_len--; /* Setup parmblock and function code */ memset(¶m, 0, sizeof(param)); curve_type = get_cpacf_curve_type(pubkey->template); switch (curve_type) { case curve_p256: if (sig_len != 2 * sizeof(param.P256.sig_r)) { TRACE_ERROR("Signature has an invalid length of %ld bytes.\n", sig_len); ret = CKR_ARGUMENTS_BAD; goto done; } if (ecpoint_len != 2 * sizeof(param.P256.pub_x)) { TRACE_ERROR("Public key has an invalid length of %ld bytes.\n", ecpoint_len); ret = CKR_ATTRIBUTE_VALUE_INVALID; goto done; } if (hash_len > sizeof(param.P256.hash)) hash_len = sizeof(param.P256.hash); fc = KDSA_ECDSA_VERIFY_P256; hash_off = sizeof(param.P256.hash) - hash_len; memcpy(param.P256.sig_r, sig, 2 * sizeof(param.P256.sig_r)); memcpy(param.P256.hash + hash_off, hash, hash_len); memcpy(param.P256.pub_x, ecpoint, 2 * sizeof(param.P256.pub_x)); break; case curve_p384: if (sig_len != 2 * sizeof(param.P384.sig_r)) { TRACE_ERROR("Signature has an invalid length of %ld bytes.\n", sig_len); ret = CKR_ARGUMENTS_BAD; goto done; } if (ecpoint_len != 2 * sizeof(param.P384.pub_x)) { TRACE_ERROR("Public key has an invalid length of %ld bytes.\n", ecpoint_len); ret = CKR_ATTRIBUTE_VALUE_INVALID; goto done; } if (hash_len > sizeof(param.P384.hash)) hash_len = sizeof(param.P384.hash); fc = KDSA_ECDSA_VERIFY_P384; hash_off = sizeof(param.P384.hash) - hash_len; memcpy(param.P384.sig_r, sig, 2 * sizeof(param.P384.sig_r)); memcpy(param.P384.hash + hash_off, hash, hash_len); memcpy(param.P384.pub_x, ecpoint, 2 * sizeof(param.P384.pub_x)); break; case curve_p521: if (sig_len != 2 * (sizeof(param.P521.sig_r) - P521_BUF_OFFSET)) { TRACE_ERROR("Signature has an invalid length of %ld bytes.\n", sig_len); ret = CKR_ARGUMENTS_BAD; goto done; } if (ecpoint_len != 2 * (sizeof(param.P521.pub_x) - P521_BUF_OFFSET)) { TRACE_ERROR("Public key has an invalid length of %ld bytes.\n", ecpoint_len); ret = CKR_ATTRIBUTE_VALUE_INVALID; goto done; } if (hash_len > sig_len / 2) hash_len = sig_len / 2; fc = KDSA_ECDSA_VERIFY_P521; /* Note that the pkey for p521 has 80 + 32 bytes. */ hash_off = sizeof(param.P521.hash) - hash_len; key_off = sizeof(param.P521.pub_x) - (ecpoint_len / 2); memcpy(param.P521.sig_r + key_off, sig, sig_len / 2); memcpy(param.P521.sig_s + key_off, sig + (sig_len / 2), sig_len / 2); memcpy(param.P521.hash + hash_off, hash, hash_len); memcpy(param.P521.pub_x + key_off, ecpoint, ecpoint_len / 2); memcpy(param.P521.pub_y + key_off, ecpoint + (ecpoint_len / 2), ecpoint_len / 2); break; default: TRACE_ERROR("Could not determine the curve type.\n"); ret = CKR_FUNCTION_FAILED; goto done; } /* Call CPACF */ rc = s390_kdsa(fc, param.buff, NULL, 0); switch (rc) { case 0: /* signature verified successfully */ ret = CKR_OK; break; default: ret = CKR_SIGNATURE_INVALID; break; } done: return ret; } /** * Verify the given signature via CPACF using the given public key. * This routine only supports the two Edwards curves ED25519 and ED448. * Note: The original input message is passed to CPACF without being * pre-hashed. Hashing is done internally in CPACF. Also no context is * supported. */ CK_RV pkey_ed_verify(OBJECT *pubkey, CK_BYTE *msg, CK_ULONG msg_len, CK_BYTE *sig, CK_ULONG sig_len, CK_KEY_TYPE key_type) { #define DEF_EDPARAM(curve, size) \ struct { \ unsigned char sig_r[size]; \ unsigned char sig_s[size]; \ unsigned char pub[size]; \ } curve union { long long buff[512]; /* 4k buffer: params + reserved area */ DEF_EDPARAM(ED25519, 32); DEF_EDPARAM(ED448, 64); } edparam; #undef DEF_EDPARAM CK_RV ret; unsigned long fc; CK_ATTRIBUTE *pub_attr = NULL; int rc; CK_BYTE *ecpoint; CK_ULONG ecpoint_len, field_len; cpacf_curve_type_t curve_type; /* Get public key from template */ if (template_attribute_get_non_empty(pubkey->template, CKA_EC_POINT, &pub_attr) != CKR_OK) { TRACE_ERROR("%s: This public key does not have a CKA_EC_POINT.\n", __func__); ret = CKR_FUNCTION_FAILED; goto done; } switch (key_type) { case CKK_EC: /* CKA_EC_POINT is an BER encoded OCTET STRING. Extract it. */ rc = ber_decode_OCTET_STRING(pub_attr->pValue, pub_attr->ulValueLen, &ecpoint, &ecpoint_len, &field_len); if (rc != CKR_OK || pub_attr->ulValueLen != field_len) { TRACE_ERROR("%s: ber_decode_OCTET_STRING failed\n", __func__); ret = CKR_ATTRIBUTE_VALUE_INVALID; goto done; } break; case CKK_EC_EDWARDS: /* CKA_EC_POINT is the public key directly */ ecpoint = pub_attr->pValue; ecpoint_len = pub_attr->ulValueLen; break; default: return CKR_KEY_TYPE_INCONSISTENT; } /* Setup parmblock and function code */ memset(&edparam, 0, sizeof(edparam)); curve_type = get_cpacf_curve_type(pubkey->template); switch (curve_type) { case curve_ed25519: if (sig_len != 2 * sizeof(edparam.ED25519.sig_r)) { TRACE_ERROR("Signature has an invalid length of %ld bytes.\n", sig_len); ret = CKR_ARGUMENTS_BAD; goto done; } if (ecpoint_len != sizeof(edparam.ED25519.pub)) { TRACE_ERROR("Public key has an invalid length of %ld bytes.\n", ecpoint_len); ret = CKR_ATTRIBUTE_VALUE_INVALID; goto done; } fc = KDSA_EDDSA_VERIFY_ED25519; /* * The flip_endian_32 will copy the 32-byte signature parts and public * key into the CPACF buffers and flip to little-endian as required * by CPACF. */ s390_flip_endian_32(edparam.ED25519.sig_r, sig); s390_flip_endian_32(edparam.ED25519.sig_s, sig + sizeof(edparam.ED25519.sig_r)); s390_flip_endian_32(edparam.ED25519.pub, ecpoint); break; case curve_ed448: if (sig_len != 2 * (sizeof(edparam.ED448.sig_r) - ED448_BUF_OFFSET)) { TRACE_ERROR("Signature has an invalid length of %ld bytes.\n", sig_len); ret = CKR_ARGUMENTS_BAD; goto done; } if (ecpoint_len != sizeof(edparam.ED448.pub) - ED448_BUF_OFFSET) { TRACE_ERROR("Public key has an invalid length of %ld bytes.\n", ecpoint_len); ret = CKR_ATTRIBUTE_VALUE_INVALID; goto done; } fc = KDSA_EDDSA_VERIFY_ED448; /* * Copy the 57-byte signature parts and public key into the CPACF parm * block left-aligned. The subsequent flip_endian_64 will result in * right-aligned 57 meaningful little-endian bytes in the 64-byte * buffers. */ memcpy(edparam.ED448.sig_r, sig, sig_len / 2); memcpy(edparam.ED448.sig_s, sig + (sig_len / 2), sig_len / 2); memcpy(edparam.ED448.pub, ecpoint, MIN(ecpoint_len, sizeof(edparam.ED448.pub))); s390_flip_endian_64(edparam.ED448.sig_r, edparam.ED448.sig_r); s390_flip_endian_64(edparam.ED448.sig_s, edparam.ED448.sig_s); s390_flip_endian_64(edparam.ED448.pub, edparam.ED448.pub); break; default: TRACE_ERROR("Could not determine the curve type.\n"); ret = CKR_FUNCTION_FAILED; goto done; } /* Call CPACF */ switch (curve_type) { case curve_ed25519: rc = s390_kdsa(fc, edparam.buff, msg, msg_len); break; case curve_ed448: rc = s390_kdsa(fc, edparam.buff, msg, msg_len); if (sig[2 * (sizeof(edparam.ED448.sig_r) - ED448_BUF_OFFSET) - 1] != 0) { /* KDSA doesn't check last byte sig[113] */ rc = 1; } break; default: TRACE_ERROR("Could not determine the curve type.\n"); ret = CKR_FUNCTION_FAILED; goto done; } switch (rc) { case 0: /* signature verified successfully */ ret = CKR_OK; break; default: ret = CKR_SIGNATURE_INVALID; break; } done: return ret; } opencryptoki-opencryptoki-451d99c/usr/lib/common/pkey_utils.h000066400000000000000000000114101520105705100245310ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2020 * * This program is provided under the terms of the Common Public License, * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this * software constitutes recipient's acceptance of CPL-1.0 terms which can be * found in the file LICENSE file or at * https://opensource.org/licenses/cpl1.0.php */ #ifndef PKEY_UTILS_H #define PKEY_UTILS_H #include "pkcs11types.h" #include "ec_curves.h" /** * the pkey kernel module */ #define PKEYDEVICE "/dev/pkey" /** * Modifier bit for CPACF instructions. */ #define CPACF_ENCRYPT 0x00 #define CPACF_DECRYPT 0x80 /** * function codes for the KM/KMC/KMAC instruction. */ #define ENCRYPTED_AES_128 0x1a #define ENCRYPTED_AES_192 0x1b #define ENCRYPTED_AES_256 0x1c /** * function codes for the KM/KMC/KMAC instruction. */ #define ENCRYPTED_AES_XTS_128 0x3a #define ENCRYPTED_AES_XTS_256 0x3c /** * function codes for the KDSA instruction. */ #define KDSA_ECDSA_VERIFY_P256 0x01 #define KDSA_ECDSA_VERIFY_P384 0x02 #define KDSA_ECDSA_VERIFY_P521 0x03 #define KDSA_EDDSA_VERIFY_ED25519 0x20 #define KDSA_EDDSA_VERIFY_ED448 0x24 #define KDSA_ENCRYPTED_ECDSA_SIGN_P256 0x11 #define KDSA_ENCRYPTED_ECDSA_SIGN_P384 0x12 #define KDSA_ENCRYPTED_ECDSA_SIGN_P521 0x13 #define KDSA_ENCRYPTED_EDDSA_SIGN_ED25519 0x30 #define KDSA_ENCRYPTED_EDDSA_SIGN_ED448 0x34 /** * EP11 blob header as defined in linux/drivers/s390/crypto/zcrypt_ep11misc.h */ #define TOKTYPE_NON_CCA 0x00 #define TOKVER_EP11_AES 0x03 typedef struct { uint8_t type; /* 0x00 (TOKTYPE_NON_CCA) */ uint8_t res0; /* unused */ uint16_t len; /* total length in bytes of this blob */ uint8_t version; /* 0x06 (TOKVER_EP11_AES) */ uint8_t res1; /* unused */ uint16_t keybitlen; /* clear key bit len, 0 for unknown */ } __attribute__ ((packed)) ep11_blob_header; typedef enum { encmode_ecb, encmode_cbc } encmode_t; typedef enum { curve_invalid, curve_p256, curve_p384, curve_p521, curve_ed25519, curve_ed448, } cpacf_curve_type_t; #define PKEY_CONVERT_KEY_RETRIES 100 typedef CK_RV (*convert_key_t) (STDLL_TokData_t *tokdata, SESSION *session, OBJECT *key_obj, CK_BBOOL xts_mode, CK_BYTE *protkey, CK_ULONG *protkey_len); int get_msa_level(void); CK_BBOOL pkey_is_ec_public_key(TEMPLATE *tmpl); CK_RV pkey_update_and_save(STDLL_TokData_t *tokdata, OBJECT *key_obj, CK_ATTRIBUTE **attr); CK_BBOOL pkey_op_supported_by_cpacf(int msa_level, CK_MECHANISM *mech, TEMPLATE *tmpl); CK_BBOOL pkey_op_ec_curve_supported_by_cpacf(TEMPLATE *tmpl); CK_RV pkey_aes_ecb(STDLL_TokData_t *tokdata, SESSION *session, OBJECT *key_obj, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG_PTR p_output_data_len, CK_BYTE encrypt, convert_key_t convert_key); CK_RV pkey_aes_cbc(STDLL_TokData_t *tokdata, SESSION *session, OBJECT *key_obj, CK_BYTE *iv, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG_PTR p_output_data_len, CK_BYTE encrypt, convert_key_t convert_key); CK_RV pkey_aes_cmac(STDLL_TokData_t *tokdata, SESSION *session, OBJECT *key_obj, CK_BYTE *message, CK_ULONG message_len, CK_BYTE *cmac, CK_BYTE *iv, convert_key_t convert_key); CK_RV pkey_aes_xts(STDLL_TokData_t *tokdata, SESSION *session, OBJECT *key_obj, CK_BYTE *tweak, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG_PTR p_output_data_len, CK_BYTE encrypt, CK_BBOOL initial, CK_BBOOL final, CK_BYTE *iv, convert_key_t convert_key); CK_RV pkey_ec_sign(STDLL_TokData_t *tokdata, SESSION *session, OBJECT *privkey, CK_BYTE *hash, CK_ULONG hash_len, CK_BYTE *sig, CK_ULONG *sig_len, void (*rng_cb)(unsigned char *, size_t), convert_key_t convert_key); CK_RV pkey_ed_sign(STDLL_TokData_t *tokdata, SESSION *session, OBJECT *privkey, CK_BYTE *msg, CK_ULONG msg_len, CK_BYTE *sig, CK_ULONG *sig_len, convert_key_t convert_key); CK_RV pkey_ec_verify(OBJECT *pubkey, CK_BYTE *hash, CK_ULONG hashlen, CK_BYTE *sig, CK_ULONG sig_len); CK_RV pkey_ed_verify(OBJECT *pubkey, CK_BYTE *msg, CK_ULONG msg_len, CK_BYTE *sig, CK_ULONG sig_len, CK_KEY_TYPE key_type); #endif opencryptoki-opencryptoki-451d99c/usr/lib/common/platform.h000066400000000000000000000063071520105705100241760ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2024 * * 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 PLATFORM_H #define PLATFORM_H #include #include #include #include #include #include #include #if defined(_AIX) #include "aix/getopt.h" #include "aix/secure_getenv.h" #include "aix/endian.h" #include "aix/asprintf.h" #include "aix/err.h" #define OCK_API_LIBNAME "libopencryptoki.a(libopencryptoki.so.0)" #define DYNLIB_LDFLAGS (RTLD_NOW | RTLD_MEMBER) #else /* _AIX */ /* for getopt, getopt_long */ #include /* for secure_getenv */ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif /* _GNU_SOURCE */ #include /* for htobexx, htolexx, bexxtoh and lexxtoh macros */ #include /* macros from bsdlog and friends */ #include #define OCK_API_LIBNAME "libopencryptoki.so" #define DYNLIB_LDFLAGS (RTLD_NOW) #endif /* _AIX */ /* * Check for O_NOFOLLOW support at compile time. * If not available, fall back to lstat() + fopen() (has TOCTOU race). */ #ifndef O_NOFOLLOW #define OCK_NO_O_NOFOLLOW 1 #warning "O_NOFOLLOW not supported, symlink protection uses racy lstat() fallback!" #endif /* * CWE-59 fix: Open file without following symlinks. * * On platforms with O_NOFOLLOW support: * Uses open(O_NOFOLLOW) + fdopen() for atomic symlink rejection. * * On platforms without O_NOFOLLOW (e.g., older AIX): * Falls back to lstat() + fopen(). This has a TOCTOU race condition, * but still catches pre-planted symlinks which is the common attack * scenario. Better than no protection at all. * * Returns NULL with errno=ELOOP if path is a symlink. */ static inline FILE *fopen_nofollow(const char *path, const char *mode) { #ifdef OCK_NO_O_NOFOLLOW /* * Fallback for platforms without O_NOFOLLOW: use lstat() check. * This has a TOCTOU race but catches pre-planted symlinks. */ struct stat sb; if (lstat(path, &sb) == 0) { if (S_ISLNK(sb.st_mode)) { errno = ELOOP; return NULL; } } /* Note: if lstat fails (e.g., file doesn't exist for "w" mode), * we proceed with fopen() which will handle the error appropriately */ return fopen(path, mode); #else /* Preferred: atomic symlink rejection via O_NOFOLLOW */ int flags = O_NOFOLLOW; int fd; FILE *fp; /* Determine flags based on mode */ if (mode[0] == 'r') { flags |= (mode[1] == '+') ? O_RDWR : O_RDONLY; } else if (mode[0] == 'w') { flags |= O_CREAT | O_TRUNC | ((mode[1] == '+') ? O_RDWR : O_WRONLY); } else if (mode[0] == 'a') { flags |= O_CREAT | O_APPEND | ((mode[1] == '+') ? O_RDWR : O_WRONLY); } else { return NULL; } fd = open(path, flags, 0600); if (fd < 0) return NULL; fp = fdopen(fd, mode); if (fp == NULL) { close(fd); return NULL; } return fp; #endif } #endif /* PLATFORM_H */ opencryptoki-opencryptoki-451d99c/usr/lib/common/pqc_defs.h000066400000000000000000000037751520105705100241440ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2022 * * This program is provided under the terms of the Common Public License, * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this * software constitutes recipient's acceptance of CPL-1.0 terms which can be * found in the file LICENSE file or at * https://opensource.org/licenses/cpl1.0.php */ #ifndef _PQC_DEFS #define _PQC_DEFS #include #include "pqc_oids.h" extern const CK_BYTE dilithium_r2_65[]; extern const CK_BYTE dilithium_r2_87[]; extern const CK_BYTE dilithium_r3_44[]; extern const CK_BYTE dilithium_r3_56[]; extern const CK_BYTE dilithium_r3_87[]; extern const CK_BYTE kyber_r2_768[]; extern const CK_BYTE kyber_r2_1024[]; extern const CK_BYTE ml_dsa_44[]; extern const CK_BYTE ml_dsa_65[]; extern const CK_BYTE ml_dsa_87[]; extern const CK_BYTE ml_kem_512[]; extern const CK_BYTE ml_kem_768[]; extern const CK_BYTE ml_kem_1024[]; struct pqc_oid { const CK_BYTE *oid; CK_ULONG oid_len; CK_ULONG keyform; CK_ULONG policy_size; CK_ULONG policy_siglen; union { struct { CK_ULONG rho_len; CK_ULONG seed_len; CK_ULONG tr_len; CK_ULONG s1_len; CK_ULONG s2_len; CK_ULONG t0_len; CK_ULONG t1_len; CK_ULONG priv_seed_len; } ml_dsa; struct { CK_ULONG sk_len; CK_ULONG pk_len; CK_ULONG fs_len; CK_ULONG priv_seed_len; CK_ULONG pubseed_len; } ml_kem; } len_info; }; extern const struct pqc_oid dilithium_oids[]; extern const struct pqc_oid kyber_oids[]; extern const struct pqc_oid ml_dsa_oids[]; extern const struct pqc_oid ml_kem_oids[]; const struct pqc_oid *find_pqc_by_keyform(const struct pqc_oid *pqcs, CK_ULONG keyform); const struct pqc_oid *find_pqc_by_oid(const struct pqc_oid *pqcs, const CK_BYTE *oid, CK_ULONG oid_len); #endif opencryptoki-opencryptoki-451d99c/usr/lib/common/pqc_supported.c000066400000000000000000000160031520105705100252270ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2022 * * This program is provided under the terms of the Common Public License, * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this * software constitutes recipient's acceptance of CPL-1.0 terms which can be * found in the file LICENSE file or at * https://opensource.org/licenses/cpl1.0.php */ #include #include "pkcs11types.h" #include "pqc_defs.h" const CK_BYTE dilithium_r2_65[] = OCK_DILITHIUM_R2_65; const CK_BYTE dilithium_r2_87[] = OCK_DILITHIUM_R2_87; const CK_BYTE dilithium_r3_44[] = OCK_DILITHIUM_R3_44; const CK_BYTE dilithium_r3_65[] = OCK_DILITHIUM_R3_65; const CK_BYTE dilithium_r3_87[] = OCK_DILITHIUM_R3_87; const struct pqc_oid dilithium_oids[] = { { .oid = dilithium_r2_65, .oid_len = sizeof(dilithium_r2_65), .keyform = CK_IBM_DILITHIUM_KEYFORM_ROUND2_65, .policy_size = 256, .policy_siglen = 3366, .len_info.ml_dsa.rho_len = 32, .len_info.ml_dsa.seed_len = 32, .len_info.ml_dsa.tr_len = 48, .len_info.ml_dsa.s1_len = 480, .len_info.ml_dsa.s2_len = 576, .len_info.ml_dsa.t0_len = 2688, .len_info.ml_dsa.t1_len = 1728, }, { .oid = dilithium_r2_87, .oid_len = sizeof(dilithium_r2_87), .keyform = CK_IBM_DILITHIUM_KEYFORM_ROUND2_87, .policy_size = 256, .policy_siglen = 4668, .len_info.ml_dsa.rho_len = 32, .len_info.ml_dsa.seed_len = 32, .len_info.ml_dsa.tr_len = 48, .len_info.ml_dsa.s1_len = 672, .len_info.ml_dsa.s2_len = 768, .len_info.ml_dsa.t0_len = 3584, .len_info.ml_dsa.t1_len = 2304, }, { .oid = dilithium_r3_44, .oid_len = sizeof(dilithium_r3_44), .keyform = CK_IBM_DILITHIUM_KEYFORM_ROUND3_44, .policy_size = 256, .policy_siglen = 2420, .len_info.ml_dsa.rho_len = 32, .len_info.ml_dsa.seed_len = 32, .len_info.ml_dsa.tr_len = 32, .len_info.ml_dsa.s1_len = 384, .len_info.ml_dsa.s2_len = 384, .len_info.ml_dsa.t0_len = 1664, .len_info.ml_dsa.t1_len = 1280, }, { .oid = dilithium_r3_65, .oid_len = sizeof(dilithium_r3_65), .keyform = CK_IBM_DILITHIUM_KEYFORM_ROUND3_65, .policy_size = 256, .policy_siglen = 3293, .len_info.ml_dsa.rho_len = 32, .len_info.ml_dsa.seed_len = 32, .len_info.ml_dsa.tr_len = 32, .len_info.ml_dsa.s1_len = 640, .len_info.ml_dsa.s2_len = 768, .len_info.ml_dsa.t0_len = 2496, .len_info.ml_dsa.t1_len = 1920, }, { .oid = dilithium_r3_87, .oid_len = sizeof(dilithium_r3_87), .keyform = CK_IBM_DILITHIUM_KEYFORM_ROUND3_87, .policy_size = 256, .policy_siglen = 4595, .len_info.ml_dsa.rho_len = 32, .len_info.ml_dsa.seed_len = 32, .len_info.ml_dsa.tr_len = 32, .len_info.ml_dsa.s1_len = 672, .len_info.ml_dsa.s2_len = 768, .len_info.ml_dsa.t0_len = 3328, .len_info.ml_dsa.t1_len = 2560, }, { .oid = NULL, .oid_len = 0, .keyform = 0, .policy_size = 0, .policy_siglen = 0 } }; const CK_BYTE kyber_r2_768[] = OCK_KYBER_R2_768; const CK_BYTE kyber_r2_1024[] = OCK_KYBER_R2_1024; const struct pqc_oid kyber_oids[] = { { .oid = kyber_r2_768, .oid_len = sizeof(kyber_r2_768), .keyform = CK_IBM_KYBER_KEYFORM_ROUND2_768, .policy_size = 256, .policy_siglen = 0, .len_info.ml_kem.sk_len = 2400, .len_info.ml_kem.pk_len = 1184, .len_info.ml_kem.fs_len = 64, .len_info.ml_kem.pubseed_len = 32 }, { .oid = kyber_r2_1024, .oid_len = sizeof(kyber_r2_1024), .keyform = CK_IBM_KYBER_KEYFORM_ROUND2_1024, .policy_size = 256, .policy_siglen = 0, .len_info.ml_kem.sk_len = 3168, .len_info.ml_kem.pk_len = 1568, .len_info.ml_kem.fs_len = 64, .len_info.ml_kem.pubseed_len = 32 }, { .oid = NULL, .oid_len = 0, .keyform = 0, .policy_size = 0, .policy_siglen = 0 } }; const CK_BYTE ml_dsa_44[] = OCK_ML_DSA_44; const CK_BYTE ml_dsa_65[] = OCK_ML_DSA_65; const CK_BYTE ml_dsa_87[] = OCK_ML_DSA_87; const struct pqc_oid ml_dsa_oids[] = { { .oid = ml_dsa_44, .oid_len = sizeof(ml_dsa_44), .keyform = CKP_ML_DSA_44, .policy_size = 128, .policy_siglen = 128, .len_info.ml_dsa.rho_len = 32, .len_info.ml_dsa.seed_len = 32, .len_info.ml_dsa.tr_len = 64, .len_info.ml_dsa.s1_len = 384, .len_info.ml_dsa.s2_len = 384, .len_info.ml_dsa.t0_len = 1664, .len_info.ml_dsa.t1_len = 1280, .len_info.ml_dsa.priv_seed_len = 32, }, { .oid = ml_dsa_65, .oid_len = sizeof(ml_dsa_65), .keyform = CKP_ML_DSA_65, .policy_size = 192, .policy_siglen = 192, .len_info.ml_dsa.rho_len = 32, .len_info.ml_dsa.seed_len = 32, .len_info.ml_dsa.tr_len = 64, .len_info.ml_dsa.s1_len = 640, .len_info.ml_dsa.s2_len = 768, .len_info.ml_dsa.t0_len = 2496, .len_info.ml_dsa.t1_len = 1920, .len_info.ml_dsa.priv_seed_len = 32, }, { .oid = ml_dsa_87, .oid_len = sizeof(ml_dsa_87), .keyform = CKP_ML_DSA_87, .policy_size = 256, .policy_siglen = 256, .len_info.ml_dsa.rho_len = 32, .len_info.ml_dsa.seed_len = 32, .len_info.ml_dsa.tr_len = 64, .len_info.ml_dsa.s1_len = 672, .len_info.ml_dsa.s2_len = 768, .len_info.ml_dsa.t0_len = 3328, .len_info.ml_dsa.t1_len = 2560, .len_info.ml_dsa.priv_seed_len = 32, }, { .oid = NULL, .oid_len = 0, .keyform = 0, .policy_size = 0, .policy_siglen = 0 } }; const CK_BYTE ml_kem_512[] = OCK_ML_KEM_512; const CK_BYTE ml_kem_768[] = OCK_ML_KEM_768; const CK_BYTE ml_kem_1024[] = OCK_ML_KEM_1024; const struct pqc_oid ml_kem_oids[] = { { .oid = ml_kem_512, .oid_len = sizeof(ml_kem_512), .keyform = CKP_ML_KEM_512, .policy_size = 126, .policy_siglen = 0, .len_info.ml_kem.sk_len = 1632, .len_info.ml_kem.pk_len = 800, .len_info.ml_kem.fs_len = 64, .len_info.ml_kem.priv_seed_len = 64, .len_info.ml_kem.pubseed_len = 32, }, { .oid = ml_kem_768, .oid_len = sizeof(ml_kem_768), .keyform = CKP_ML_KEM_768, .policy_size = 192, .policy_siglen = 0, .len_info.ml_kem.sk_len = 2400, .len_info.ml_kem.pk_len = 1184, .len_info.ml_kem.fs_len = 64, .len_info.ml_kem.priv_seed_len = 64, .len_info.ml_kem.pubseed_len = 32 }, { .oid = ml_kem_1024, .oid_len = sizeof(ml_kem_1024), .keyform = CKP_ML_KEM_1024, .policy_size = 256, .policy_siglen = 0, .len_info.ml_kem.sk_len = 3168, .len_info.ml_kem.pk_len = 1568, .len_info.ml_kem.fs_len = 64, .len_info.ml_kem.priv_seed_len = 64, .len_info.ml_kem.pubseed_len = 32 }, { .oid = NULL, .oid_len = 0, .keyform = 0, .policy_size = 0, .policy_siglen = 0 } }; const struct pqc_oid *find_pqc_by_keyform(const struct pqc_oid *pqcs, CK_ULONG keyform) { CK_ULONG i; for (i = 0; pqcs[i].oid != NULL; i++) { if (pqcs[i].keyform == keyform) return &pqcs[i]; } return NULL; } const struct pqc_oid *find_pqc_by_oid(const struct pqc_oid *pqcs, const CK_BYTE *oid, CK_ULONG oid_len) { CK_ULONG i; for (i = 0; pqcs[i].oid != NULL; i++) { if (pqcs[i].oid_len == oid_len && memcmp(pqcs[i].oid, oid, oid_len) == 0) return &pqcs[i]; } return NULL; } opencryptoki-opencryptoki-451d99c/usr/lib/common/profile_obj.c000066400000000000000000000052061520105705100246340ustar00rootroot00000000000000/* * 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 "pkcs11types.h" #include "defs.h" #include "host_defs.h" #include "h_extern.h" #include "trace.h" CK_RV profile_object_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) { /* CKO_PROFILE has no required attributes */ return template_check_required_base_attributes(tmpl, mode); } CK_RV profile_object_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) { CK_ATTRIBUTE *class_attr = NULL; CK_ATTRIBUTE *profile_id_attr = NULL; CK_RV rc; UNUSED(mode); class_attr = (CK_ATTRIBUTE *)malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_OBJECT_CLASS)); profile_id_attr = (CK_ATTRIBUTE *)malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_PROFILE_ID)); if (!class_attr || !profile_id_attr) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto error; } 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_PROFILE; profile_id_attr->type = CKA_PROFILE_ID; profile_id_attr->ulValueLen = sizeof(CK_PROFILE_ID); profile_id_attr->pValue = (CK_BYTE *)profile_id_attr + sizeof(CK_ATTRIBUTE); *(CK_PROFILE_ID *)profile_id_attr->pValue = CKP_INVALID_ID; rc = template_update_attribute(tmpl, class_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } class_attr = NULL; rc = template_update_attribute(tmpl, profile_id_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } profile_id_attr = NULL; return CKR_OK; error: if (class_attr) free(class_attr); if (profile_id_attr) free(profile_id_attr); return rc; } CK_RV profile_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_PROFILE_ID: return CKR_OK; default: return template_validate_base_attribute(tmpl, attr, mode); } } opencryptoki-opencryptoki-451d99c/usr/lib/common/sess_mgr.c000066400000000000000000001466251520105705100241770ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2001-2017 * * This program is provided under the terms of the Common Public License, * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this * software constitutes recipient's acceptance of CPL-1.0 terms which can be * found in the file LICENSE file or at * https://opensource.org/licenses/cpl1.0.php */ // File: session.c // // Session manager related functions // #include #include // for memcmp() et al #include #include "pkcs11types.h" #include "local_types.h" #include "defs.h" #include "host_defs.h" #include "h_extern.h" #include "tok_spec_struct.h" #include "trace.h" // session_mgr_find() // // search for the specified session. returning a pointer to the session // might be dangerous, but performs well. // // The returned session must be put back (using bt_put_node_value()) by the // caller to decrease the reference count! // // Returns: SESSION * or NULL // SESSION *session_mgr_find(STDLL_TokData_t *tokdata, CK_SESSION_HANDLE handle) { SESSION *result = NULL; if (!handle) { return NULL; } result = bt_get_node_value(&tokdata->sess_btree, handle); return result; } // session_mgr_find_reset_error() // // search for the specified session and reset the ulDeviceError field // in the session info. returning a pointer to the session might be // dangerous, but performs well // // The returned session must be put back (using bt_put_node_value()) by the // caller to decrease the reference count! // // Returns: SESSION * or NULL // SESSION *session_mgr_find_reset_error(STDLL_TokData_t *tokdata, CK_SESSION_HANDLE handle) { SESSION *res = session_mgr_find(tokdata, handle); if (res) res->session_info.ulDeviceError = 0; return res; } void session_mgr_put(STDLL_TokData_t *tokdata, SESSION *session) { bt_put_node_value(&tokdata->sess_btree, session); } // session_mgr_new() // // creates a new session structure and adds it to the process's list // of sessions // // Args: CK_ULONG flags : session flags (INPUT) // SESSION ** sess : new session pointer (OUTPUT) // // Returns: CK_RV // CK_RV session_mgr_new(STDLL_TokData_t *tokdata, CK_ULONG flags, CK_SLOT_ID slot_id, CK_SESSION_HANDLE_PTR phSession) { SESSION *new_session = NULL; CK_BBOOL user_session = FALSE; CK_BBOOL so_session = FALSE; CK_RV rc = CKR_OK; new_session = (SESSION *) malloc(sizeof(SESSION)); if (!new_session) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto done; } memset(new_session, 0x0, sizeof(SESSION)); // find an unused session handle. session handles will wrap automatically... // new_session->session_info.slotID = slot_id; new_session->session_info.flags = flags; new_session->session_info.ulDeviceError = 0; // determine the login/logout status of the new session. PKCS 11 requires // that all sessions belonging to a process have the same login/logout // status // so_session = session_mgr_so_session_exists(tokdata); user_session = session_mgr_user_session_exists(tokdata); if (pthread_rwlock_wrlock(&tokdata->sess_list_rwlock)) { TRACE_ERROR("Write Lock failed.\n"); rc = CKR_CANT_LOCK; goto done; } // we don't have to worry about having a user and SO session at the same // time. that is prevented in the login routine // if (user_session) { if (new_session->session_info.flags & CKF_RW_SESSION) { new_session->session_info.state = CKS_RW_USER_FUNCTIONS; } else { new_session->session_info.state = CKS_RO_USER_FUNCTIONS; tokdata->ro_session_count++; } } else if (so_session) { new_session->session_info.state = CKS_RW_SO_FUNCTIONS; } else { if (new_session->session_info.flags & CKF_RW_SESSION) { new_session->session_info.state = CKS_RW_PUBLIC_SESSION; } else { new_session->session_info.state = CKS_RO_PUBLIC_SESSION; tokdata->ro_session_count++; } } pthread_rwlock_unlock(&tokdata->sess_list_rwlock); *phSession = bt_node_add(&tokdata->sess_btree, new_session); if (*phSession == 0) { rc = CKR_HOST_MEMORY; /* new_session will be free'd below */ } done: if (rc != CKR_OK && new_session != NULL) { TRACE_ERROR("Failed to add session to the btree.\n"); free(new_session); } return rc; } // session_mgr_so_session_exists() // // determines whether a RW_SO session exists for the specified process // // Returns: TRUE or FALSE // CK_BBOOL session_mgr_so_session_exists(STDLL_TokData_t *tokdata) { CK_BBOOL result; /* we must acquire sess_list_rwlock in order to inspect * global_login_state */ if (pthread_rwlock_rdlock(&tokdata->sess_list_rwlock)) { TRACE_ERROR("Read Lock failed.\n"); return FALSE; } result = (tokdata->global_login_state == CKS_RW_SO_FUNCTIONS); pthread_rwlock_unlock(&tokdata->sess_list_rwlock); return result; } // session_mgr_user_session_exists() // // determines whether a USER session exists for the specified process // // Returns: TRUE or FALSE // CK_BBOOL session_mgr_user_session_exists(STDLL_TokData_t *tokdata) { CK_BBOOL result; /* we must acquire sess_list_rwlock in order to inspect * glogal_login_state */ if (pthread_rwlock_rdlock(&tokdata->sess_list_rwlock)) { TRACE_ERROR("Read Lock failed.\n"); return FALSE; } result = ((tokdata->global_login_state == CKS_RO_USER_FUNCTIONS) || (tokdata->global_login_state == CKS_RW_USER_FUNCTIONS)); pthread_rwlock_unlock(&tokdata->sess_list_rwlock); return result; } // session_mgr_public_session_exists() // // determines whether a PUBLIC session exists for the specified process // // Returns: TRUE or FALSE // CK_BBOOL session_mgr_public_session_exists(STDLL_TokData_t *tokdata) { CK_BBOOL result; /* we must acquire sess_list_rwlock in order to inspect * global_login_state */ if (pthread_rwlock_rdlock(&tokdata->sess_list_rwlock)) { TRACE_ERROR("Read Lock failed.\n"); return FALSE; } result = ((tokdata->global_login_state == CKS_RO_PUBLIC_SESSION) || (tokdata->global_login_state == CKS_RW_PUBLIC_SESSION)); pthread_rwlock_unlock(&tokdata->sess_list_rwlock); return result; } // session_mgr_readonly_exists() // // determines whether the specified process owns any read-only sessions. this is // useful because the SO cannot log in if a read-only session exists. // CK_BBOOL session_mgr_readonly_session_exists(STDLL_TokData_t *tokdata) { CK_BBOOL result; /* we must acquire sess_list_rwlock in order to inspect ro_session_count */ if (pthread_rwlock_rdlock(&tokdata->sess_list_rwlock)) { TRACE_ERROR("Read Lock failed.\n"); return FALSE; } result = (tokdata->ro_session_count > 0); pthread_rwlock_unlock(&tokdata->sess_list_rwlock); return result; } // session_mgr_close_session() // // removes the specified session from the process' session list // // Args: PROCESS * proc : parent process // SESSION * session : session to remove // // Returns: TRUE on success else FALSE // CK_RV session_mgr_close_session(STDLL_TokData_t *tokdata, CK_SESSION_HANDLE handle) { SESSION *sess; CK_RV rc = CKR_OK; sess = bt_get_node_value(&tokdata->sess_btree, handle); if (!sess) { TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); return CKR_SESSION_HANDLE_INVALID; } if (pthread_rwlock_wrlock(&tokdata->sess_list_rwlock)) { TRACE_ERROR("Write Lock failed.\n"); bt_put_node_value(&tokdata->sess_btree, sess); sess = NULL; return CKR_CANT_LOCK; } object_mgr_purge_session_objects(tokdata, sess, ALL); if ((sess->session_info.state == CKS_RO_PUBLIC_SESSION) || (sess->session_info.state == CKS_RO_USER_FUNCTIONS)) { tokdata->ro_session_count--; } // Make sure this address is now invalid sess->handle = CK_INVALID_HANDLE; if (sess->find_list) free(sess->find_list); if (sess->encr_ctx.context) { if (sess->encr_ctx.context_free_func != NULL) sess->encr_ctx.context_free_func(tokdata, sess, sess->encr_ctx.context, sess->encr_ctx.context_len); else free(sess->encr_ctx.context); } if (sess->encr_ctx.mech.pParameter) free(sess->encr_ctx.mech.pParameter); if (sess->decr_ctx.context) { if (sess->decr_ctx.context_free_func != NULL) sess->decr_ctx.context_free_func(tokdata, sess, sess->decr_ctx.context, sess->decr_ctx.context_len); else free(sess->decr_ctx.context); } if (sess->decr_ctx.mech.pParameter) free(sess->decr_ctx.mech.pParameter); if (sess->digest_ctx.context) { if (sess->digest_ctx.context_free_func != NULL) sess->digest_ctx.context_free_func(tokdata, sess, sess->digest_ctx.context, sess->digest_ctx.context_len); else free(sess->digest_ctx.context); } if (sess->digest_ctx.mech.pParameter) free(sess->digest_ctx.mech.pParameter); if (sess->sign_ctx.context) { if (sess->sign_ctx.context_free_func != NULL) sess->sign_ctx.context_free_func(tokdata, sess, sess->sign_ctx.context, sess->sign_ctx.context_len); else free(sess->sign_ctx.context); } if (sess->sign_ctx.mech.pParameter) free(sess->sign_ctx.mech.pParameter); if (sess->verify_ctx.context) { if (sess->verify_ctx.context_free_func != NULL) sess->verify_ctx.context_free_func(tokdata, sess, sess->verify_ctx.context, sess->verify_ctx.context_len); else free(sess->verify_ctx.context); } if (sess->verify_ctx.mech.pParameter) free(sess->verify_ctx.mech.pParameter); bt_put_node_value(&tokdata->sess_btree, sess); sess = NULL; bt_node_free(&tokdata->sess_btree, handle, TRUE); // XXX XXX Not having this is a problem // for IHS. The spec states that there is an implicit logout // when the last session is closed. Cannonicaly this is what other // implementaitons do. however on linux for some reason IHS can't seem // to keep the session open, which means that they go through the login // path EVERY time, which of course causes a reload of the private // objects EVERY time. If we are logged out, we MUST purge the private // objects from this process.. // if (bt_is_empty(&tokdata->sess_btree)) { // SAB XXX if all sessions are closed. Is this effectivly logging out if (token_specific.t_logout) { rc = token_specific.t_logout(tokdata); } object_mgr_purge_private_token_objects(tokdata); tokdata->global_login_state = CKS_RO_PUBLIC_SESSION; // The objects really need to be purged .. but this impacts the // performance under linux. So we need to make sure that the // login state is valid. I don't really like this. object_mgr_purge_map(tokdata, (SESSION *) 0xFFFF, PRIVATE); } pthread_rwlock_unlock(&tokdata->sess_list_rwlock); return rc; } /* session_free * * Callback used to free an individual SESSION object */ void session_free(STDLL_TokData_t *tokdata, void *node_value, unsigned long node_idx, void *p3) { SESSION *sess = (SESSION *) node_value; UNUSED(p3); object_mgr_purge_session_objects(tokdata, sess, ALL); sess->handle = CK_INVALID_HANDLE; if (sess->find_list) free(sess->find_list); if (sess->encr_ctx.context) { if (sess->encr_ctx.context_free_func != NULL) sess->encr_ctx.context_free_func(tokdata, sess, sess->encr_ctx.context, sess->encr_ctx.context_len); else free(sess->encr_ctx.context); } if (sess->encr_ctx.mech.pParameter) free(sess->encr_ctx.mech.pParameter); if (sess->decr_ctx.context) { if (sess->decr_ctx.context_free_func != NULL) sess->decr_ctx.context_free_func(tokdata, sess, sess->decr_ctx.context, sess->decr_ctx.context_len); else free(sess->decr_ctx.context); } if (sess->decr_ctx.mech.pParameter) free(sess->decr_ctx.mech.pParameter); if (sess->digest_ctx.context) { if (sess->digest_ctx.context_free_func != NULL) sess->digest_ctx.context_free_func(tokdata, sess, sess->digest_ctx.context, sess->digest_ctx.context_len); else free(sess->digest_ctx.context); } if (sess->digest_ctx.mech.pParameter) free(sess->digest_ctx.mech.pParameter); if (sess->sign_ctx.context) { if (sess->sign_ctx.context_free_func != NULL) sess->sign_ctx.context_free_func(tokdata, sess, sess->sign_ctx.context, sess->sign_ctx.context_len); else free(sess->sign_ctx.context); } if (sess->sign_ctx.mech.pParameter) free(sess->sign_ctx.mech.pParameter); if (sess->verify_ctx.context) { if (sess->verify_ctx.context_free_func != NULL) sess->verify_ctx.context_free_func(tokdata, sess, sess->verify_ctx.context, sess->verify_ctx.context_len); else free(sess->verify_ctx.context); } if (sess->verify_ctx.mech.pParameter) free(sess->verify_ctx.mech.pParameter); /* NB: any access to sess or @node_value after this returns will segfault */ bt_node_free(&tokdata->sess_btree, node_idx, TRUE); } // session_mgr_close_all_sessions() // // removes all sessions from the specified process. // If tokdata is not NULL, then only sessions for that token instance are // removed. // CK_RV session_mgr_close_all_sessions(STDLL_TokData_t *tokdata) { bt_for_each_node(tokdata, &tokdata->sess_btree, session_free, NULL); if (pthread_rwlock_wrlock(&tokdata->sess_list_rwlock)) { TRACE_ERROR("Write Lock failed.\n"); return CKR_CANT_LOCK; } tokdata->global_login_state = CKS_RO_PUBLIC_SESSION; tokdata->ro_session_count = 0; pthread_rwlock_unlock(&tokdata->sess_list_rwlock); return CKR_OK; } /* session_login * * Callback used to update a SESSION object's login state to logged in based on * user type */ void session_login(STDLL_TokData_t *tokdata, void *node_value, unsigned long node_idx, void *p3) { SESSION *s = (SESSION *) node_value; CK_USER_TYPE user_type = *(CK_USER_TYPE *) p3; UNUSED(tokdata); UNUSED(node_idx); if (s->session_info.flags & CKF_RW_SESSION) { if (user_type == CKU_USER) s->session_info.state = CKS_RW_USER_FUNCTIONS; else s->session_info.state = CKS_RW_SO_FUNCTIONS; } else { if (user_type == CKU_USER) s->session_info.state = CKS_RO_USER_FUNCTIONS; } tokdata->global_login_state = s->session_info.state; // SAB } // session_mgr_login_all() // // changes the login status of all sessions in the token // // Arg: CK_USER_TYPE user_type : USER or SO // CK_RV session_mgr_login_all(STDLL_TokData_t *tokdata, CK_USER_TYPE user_type) { if (pthread_rwlock_wrlock(&tokdata->sess_list_rwlock)) { TRACE_ERROR("Write Lock failed.\n"); return CKR_CANT_LOCK; } bt_for_each_node(tokdata, &tokdata->sess_btree, session_login, (void *)&user_type); pthread_rwlock_unlock(&tokdata->sess_list_rwlock); return CKR_OK; } /* session_logout * * Callback used to update a SESSION object's login state to be logged out */ void session_logout(STDLL_TokData_t *tokdata, void *node_value, unsigned long node_idx, void *p3) { SESSION *s = (SESSION *) node_value; UNUSED(node_idx); UNUSED(p3); // all sessions get logged out so destroy any private objects // public objects are left alone // object_mgr_purge_session_objects(tokdata, s, PRIVATE); if (s->session_info.flags & CKF_RW_SESSION) s->session_info.state = CKS_RW_PUBLIC_SESSION; else s->session_info.state = CKS_RO_PUBLIC_SESSION; tokdata->global_login_state = s->session_info.state; // SAB } // session_mgr_logout_all() // // changes the login status of all sessions in the token // CK_RV session_mgr_logout_all(STDLL_TokData_t *tokdata) { if (pthread_rwlock_wrlock(&tokdata->sess_list_rwlock)) { TRACE_ERROR("Write Lock failed.\n"); return CKR_CANT_LOCK; } bt_for_each_node(tokdata, &tokdata->sess_btree, session_logout, NULL); pthread_rwlock_unlock(&tokdata->sess_list_rwlock); return CKR_OK; } // // CK_RV session_mgr_get_op_state(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, CK_BYTE *data, CK_ULONG *data_len) { OP_STATE_DATA *op_data = NULL; CK_ULONG max_data_len = *data_len; CK_ULONG op_data_len; CK_ULONG all_data_len = 0; CK_ULONG offset, active_ops; if (!sess) { TRACE_ERROR("Invalid function arguments.\n"); return CKR_FUNCTION_FAILED; } if (sess->find_active == TRUE) { TRACE_ERROR("%s\n", ock_err(ERR_STATE_UNSAVEABLE)); return CKR_STATE_UNSAVEABLE; } // ensure that at least one operation is active // active_ops = 0; if (sess->encr_ctx.active == TRUE) { if (sess->encr_ctx.state_unsaveable) { TRACE_ERROR("%s\n", ock_err(ERR_STATE_UNSAVEABLE)); return CKR_STATE_UNSAVEABLE; } active_ops++; op_data_len = sizeof(OP_STATE_DATA) + sizeof(ENCR_DECR_CONTEXT) + sess->encr_ctx.context_len + sess->encr_ctx.mech.ulParameterLen; all_data_len += op_data_len; if (length_only == FALSE) { op_data = (OP_STATE_DATA *) data; if (max_data_len < op_data_len) { TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); return CKR_BUFFER_TOO_SMALL; } memset(op_data, 0, sizeof(*op_data)); #ifdef PACKAGE_VERSION strncpy((char *)op_data->library_version, PACKAGE_VERSION, sizeof(op_data->library_version)); #endif memcpy(op_data->manufacturerID, tokdata->nv_token_data->token_info.manufacturerID, sizeof(op_data->manufacturerID)); memcpy(op_data->model, tokdata->nv_token_data->token_info.model, sizeof(op_data->model)); op_data->data_len = op_data_len - sizeof(OP_STATE_DATA); op_data->session_state = sess->session_info.state; op_data->active_operation = STATE_ENCR; offset = sizeof(OP_STATE_DATA); memcpy((CK_BYTE *) op_data + offset, &sess->encr_ctx, sizeof(ENCR_DECR_CONTEXT)); offset += sizeof(ENCR_DECR_CONTEXT); if (sess->encr_ctx.context_len != 0) { memcpy((CK_BYTE *) op_data + offset, sess->encr_ctx.context, sess->encr_ctx.context_len); offset += sess->encr_ctx.context_len; } if (sess->encr_ctx.mech.ulParameterLen != 0) { memcpy((CK_BYTE *) op_data + offset, sess->encr_ctx.mech.pParameter, sess->encr_ctx.mech.ulParameterLen); } max_data_len -= op_data_len; data += op_data_len; } } if (sess->decr_ctx.active == TRUE) { if (sess->decr_ctx.state_unsaveable) { TRACE_ERROR("%s\n", ock_err(ERR_STATE_UNSAVEABLE)); return CKR_STATE_UNSAVEABLE; } active_ops++; op_data_len = sizeof(OP_STATE_DATA) + sizeof(ENCR_DECR_CONTEXT) + sess->decr_ctx.context_len + sess->decr_ctx.mech.ulParameterLen; all_data_len += op_data_len; if (length_only == FALSE) { op_data = (OP_STATE_DATA *) data; if (max_data_len < op_data_len) { TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); return CKR_BUFFER_TOO_SMALL; } memset(op_data, 0, sizeof(*op_data)); #ifdef PACKAGE_VERSION strncpy((char *)op_data->library_version, PACKAGE_VERSION, sizeof(op_data->library_version)); #endif memcpy(op_data->manufacturerID, tokdata->nv_token_data->token_info.manufacturerID, sizeof(op_data->manufacturerID)); memcpy(op_data->model, tokdata->nv_token_data->token_info.model, sizeof(op_data->model)); op_data->data_len = op_data_len - sizeof(OP_STATE_DATA); op_data->session_state = sess->session_info.state; op_data->active_operation = STATE_DECR; offset = sizeof(OP_STATE_DATA); memcpy((CK_BYTE *) op_data + offset, &sess->decr_ctx, sizeof(ENCR_DECR_CONTEXT)); offset += sizeof(ENCR_DECR_CONTEXT); if (sess->decr_ctx.context_len != 0) { memcpy((CK_BYTE *) op_data + offset, sess->decr_ctx.context, sess->decr_ctx.context_len); offset += sess->decr_ctx.context_len; } if (sess->decr_ctx.mech.ulParameterLen != 0) { memcpy((CK_BYTE *) op_data + offset, sess->decr_ctx.mech.pParameter, sess->decr_ctx.mech.ulParameterLen); } max_data_len -= op_data_len; data += op_data_len; } } if (sess->digest_ctx.active == TRUE) { if (sess->digest_ctx.state_unsaveable) { TRACE_ERROR("%s\n", ock_err(ERR_STATE_UNSAVEABLE)); return CKR_STATE_UNSAVEABLE; } active_ops++; op_data_len = sizeof(OP_STATE_DATA) + sizeof(DIGEST_CONTEXT) + sess->digest_ctx.context_len + sess->digest_ctx.mech.ulParameterLen; all_data_len += op_data_len; if (length_only == FALSE) { op_data = (OP_STATE_DATA *) data; if (max_data_len < op_data_len) { TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); return CKR_BUFFER_TOO_SMALL; } memset(op_data, 0, sizeof(*op_data)); #ifdef PACKAGE_VERSION strncpy((char *)op_data->library_version, PACKAGE_VERSION, sizeof(op_data->library_version)); #endif memcpy(op_data->manufacturerID, tokdata->nv_token_data->token_info.manufacturerID, sizeof(op_data->manufacturerID)); memcpy(op_data->model, tokdata->nv_token_data->token_info.model, sizeof(op_data->model)); op_data->data_len = op_data_len - sizeof(OP_STATE_DATA); op_data->session_state = sess->session_info.state; op_data->active_operation = STATE_DIGEST; offset = sizeof(OP_STATE_DATA); memcpy((CK_BYTE *) op_data + offset, &sess->digest_ctx, sizeof(DIGEST_CONTEXT)); offset += sizeof(DIGEST_CONTEXT); if (sess->digest_ctx.context_len != 0) { memcpy((CK_BYTE *) op_data + offset, sess->digest_ctx.context, sess->digest_ctx.context_len); offset += sess->digest_ctx.context_len; } if (sess->digest_ctx.mech.ulParameterLen != 0) { memcpy((CK_BYTE *) op_data + offset, sess->digest_ctx.mech.pParameter, sess->digest_ctx.mech.ulParameterLen); } max_data_len -= op_data_len; data += op_data_len; } } if (sess->sign_ctx.active == TRUE) { if (sess->sign_ctx.state_unsaveable) { TRACE_ERROR("%s\n", ock_err(ERR_STATE_UNSAVEABLE)); return CKR_STATE_UNSAVEABLE; } active_ops++; op_data_len = sizeof(OP_STATE_DATA) + sizeof(SIGN_VERIFY_CONTEXT) + sess->sign_ctx.context_len + sess->sign_ctx.mech.ulParameterLen; all_data_len += op_data_len; if (length_only == FALSE) { op_data = (OP_STATE_DATA *) data; if (max_data_len < op_data_len) { TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); return CKR_BUFFER_TOO_SMALL; } memset(op_data, 0, sizeof(*op_data)); #ifdef PACKAGE_VERSION strncpy((char *)op_data->library_version, PACKAGE_VERSION, sizeof(op_data->library_version)); #endif memcpy(op_data->manufacturerID, tokdata->nv_token_data->token_info.manufacturerID, sizeof(op_data->manufacturerID)); memcpy(op_data->model, tokdata->nv_token_data->token_info.model, sizeof(op_data->model)); op_data->data_len = op_data_len - sizeof(OP_STATE_DATA); op_data->session_state = sess->session_info.state; op_data->active_operation = STATE_SIGN; offset = sizeof(OP_STATE_DATA); memcpy((CK_BYTE *) op_data + offset, &sess->sign_ctx, sizeof(SIGN_VERIFY_CONTEXT)); offset += sizeof(SIGN_VERIFY_CONTEXT); if (sess->sign_ctx.context_len != 0) { memcpy((CK_BYTE *) op_data + offset, sess->sign_ctx.context, sess->sign_ctx.context_len); offset += sess->sign_ctx.context_len; } if (sess->sign_ctx.mech.ulParameterLen != 0) { memcpy((CK_BYTE *) op_data + offset, sess->sign_ctx.mech.pParameter, sess->sign_ctx.mech.ulParameterLen); } max_data_len -= op_data_len; data += op_data_len; } } if (sess->verify_ctx.active == TRUE) { if (sess->verify_ctx.state_unsaveable) { TRACE_ERROR("%s\n", ock_err(ERR_STATE_UNSAVEABLE)); return CKR_STATE_UNSAVEABLE; } active_ops++; op_data_len = sizeof(OP_STATE_DATA) + sizeof(SIGN_VERIFY_CONTEXT) + sess->verify_ctx.context_len + sess->verify_ctx.mech.ulParameterLen + sess->verify_ctx.saved_signature_len; all_data_len += op_data_len; if (length_only == FALSE) { op_data = (OP_STATE_DATA *) data; if (max_data_len < op_data_len) { TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); return CKR_BUFFER_TOO_SMALL; } memset(op_data, 0, sizeof(*op_data)); #ifdef PACKAGE_VERSION strncpy((char *)op_data->library_version, PACKAGE_VERSION, sizeof(op_data->library_version)); #endif memcpy(op_data->manufacturerID, tokdata->nv_token_data->token_info.manufacturerID, sizeof(op_data->manufacturerID)); memcpy(op_data->model, tokdata->nv_token_data->token_info.model, sizeof(op_data->model)); op_data->data_len = op_data_len - sizeof(OP_STATE_DATA); op_data->session_state = sess->session_info.state; op_data->active_operation = STATE_VERIFY; offset = sizeof(OP_STATE_DATA); memcpy((CK_BYTE *) op_data + offset, &sess->verify_ctx, sizeof(SIGN_VERIFY_CONTEXT)); offset += sizeof(SIGN_VERIFY_CONTEXT); if (sess->verify_ctx.context_len != 0) { memcpy((CK_BYTE *) op_data + offset, sess->verify_ctx.context, sess->verify_ctx.context_len); offset += sess->verify_ctx.context_len; } if (sess->verify_ctx.mech.ulParameterLen != 0) { memcpy((CK_BYTE *) op_data + offset, sess->verify_ctx.mech.pParameter, sess->verify_ctx.mech.ulParameterLen); offset += sess->verify_ctx.mech.ulParameterLen; } if (sess->verify_ctx.saved_signature_len != 0) { memcpy((CK_BYTE *) op_data + offset, sess->verify_ctx.saved_signature, sess->verify_ctx.saved_signature_len); } max_data_len -= op_data_len; data += op_data_len; } } if (active_ops == 0) { TRACE_ERROR("%s\n", ock_err(ERR_STATE_UNSAVEABLE)); return CKR_OPERATION_NOT_INITIALIZED; } *data_len = all_data_len; return CKR_OK; } // // CK_RV session_mgr_set_op_state(STDLL_TokData_t *tokdata, SESSION *sess, CK_OBJECT_HANDLE encr_key, CK_OBJECT_HANDLE auth_key, CK_BYTE *data, CK_ULONG data_len) { CK_BYTE *cur_data; CK_ULONG cur_data_len; OP_STATE_DATA *op_data = NULL; CK_BYTE *mech_param = NULL; CK_BYTE *context = NULL; CK_BYTE *saved_signature = NULL; CK_BYTE *ptr1 = NULL; CK_BYTE *ptr2 = NULL; CK_BYTE *ptr3 = NULL; CK_BYTE *ptr4 = NULL; CK_ULONG len; CK_ULONG encr_key_needed = 0; CK_ULONG auth_key_needed = 0; if (!sess || !data) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } /* * Validate the new state information. Don't touch the session * until the new state is valid. */ cur_data = data; cur_data_len = data_len; while (cur_data_len >= sizeof(OP_STATE_DATA)) { op_data = (OP_STATE_DATA *)cur_data; if (cur_data_len < op_data->data_len + sizeof(OP_STATE_DATA)) { TRACE_ERROR("%s\n", ock_err(ERR_SAVED_STATE_INVALID)); return CKR_SAVED_STATE_INVALID; } /* * Make sure the session states are compatible: same OCK version, * same token model, same session state. */ #ifdef PACKAGE_VERSION if (strncmp((char *)op_data->library_version, PACKAGE_VERSION, sizeof(op_data->library_version)) != 0) { TRACE_ERROR("%s\n", ock_err(ERR_SAVED_STATE_INVALID)); return CKR_SAVED_STATE_INVALID; } #endif if (memcmp(op_data->manufacturerID, tokdata->nv_token_data->token_info.manufacturerID, sizeof(op_data->manufacturerID)) != 0 || memcmp(op_data->model, tokdata->nv_token_data->token_info.model, sizeof(op_data->model)) != 0) { TRACE_ERROR("%s\n", ock_err(ERR_SAVED_STATE_INVALID)); return CKR_SAVED_STATE_INVALID; } if (sess->session_info.state != op_data->session_state) { TRACE_ERROR("%s\n", ock_err(ERR_SAVED_STATE_INVALID)); return CKR_SAVED_STATE_INVALID; } switch (op_data->active_operation) { case STATE_ENCR: case STATE_DECR: { ENCR_DECR_CONTEXT *ctx = (ENCR_DECR_CONTEXT *)(cur_data + sizeof(OP_STATE_DATA)); len = sizeof(ENCR_DECR_CONTEXT) + ctx->context_len + ctx->mech.ulParameterLen; if (len != op_data->data_len) { TRACE_ERROR("%s\n", ock_err(ERR_SAVED_STATE_INVALID)); return CKR_SAVED_STATE_INVALID; } encr_key_needed++; } break; case STATE_SIGN: case STATE_VERIFY: { SIGN_VERIFY_CONTEXT *ctx = (SIGN_VERIFY_CONTEXT *)(cur_data + sizeof(OP_STATE_DATA)); len = sizeof(SIGN_VERIFY_CONTEXT) + ctx->context_len + ctx->mech.ulParameterLen + ctx->saved_signature_len; if (len != op_data->data_len) { TRACE_ERROR("%s\n", ock_err(ERR_SAVED_STATE_INVALID)); return CKR_SAVED_STATE_INVALID; } auth_key_needed++; } break; case STATE_DIGEST: { DIGEST_CONTEXT *ctx = (DIGEST_CONTEXT *) (cur_data + sizeof(OP_STATE_DATA)); len = sizeof(DIGEST_CONTEXT) + ctx->context_len + ctx->mech.ulParameterLen; if (len != op_data->data_len) { TRACE_ERROR("%s\n", ock_err(ERR_SAVED_STATE_INVALID)); return CKR_SAVED_STATE_INVALID; } } break; default: TRACE_ERROR("%s\n", ock_err(ERR_SAVED_STATE_INVALID)); return CKR_SAVED_STATE_INVALID; } /* move on to next operation */ cur_data_len -= (op_data->data_len + sizeof(OP_STATE_DATA)); cur_data += (op_data->data_len + sizeof(OP_STATE_DATA)); } /* nothing must be left over */ if (cur_data_len > 0) { TRACE_ERROR("%s\n", ock_err(ERR_SAVED_STATE_INVALID)); return CKR_SAVED_STATE_INVALID; } if (encr_key_needed > 0 && encr_key == CK_INVALID_HANDLE) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_NEEDED)); return CKR_KEY_NEEDED; } if (encr_key_needed == 0 && encr_key != CK_INVALID_HANDLE) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_NOT_NEEDED)); return CKR_KEY_NOT_NEEDED; } if (auth_key_needed > 0 && auth_key == CK_INVALID_HANDLE) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_NEEDED)); return CKR_KEY_NEEDED; } if (auth_key_needed == 0 && auth_key != CK_INVALID_HANDLE) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_NOT_NEEDED)); return CKR_KEY_NOT_NEEDED; } /* State information looks okay. Cleanup the current session state, first */ if (sess->encr_ctx.active) encr_mgr_cleanup(tokdata, sess, &sess->encr_ctx); if (sess->decr_ctx.active) decr_mgr_cleanup(tokdata, sess, &sess->decr_ctx); if (sess->digest_ctx.active) digest_mgr_cleanup(tokdata, sess, &sess->digest_ctx); if (sess->sign_ctx.active) sign_mgr_cleanup(tokdata, sess, &sess->sign_ctx); if (sess->verify_ctx.active) verify_mgr_cleanup(tokdata, sess, &sess->verify_ctx); /* Now process the saved operation states */ cur_data = data; cur_data_len = data_len; while (cur_data_len >= sizeof(OP_STATE_DATA)) { op_data = (OP_STATE_DATA *)cur_data; if (cur_data_len < op_data->data_len + sizeof(OP_STATE_DATA)) { TRACE_ERROR("%s\n", ock_err(ERR_SAVED_STATE_INVALID)); return CKR_SAVED_STATE_INVALID; } switch (op_data->active_operation) { case STATE_ENCR: case STATE_DECR: { ENCR_DECR_CONTEXT *ctx = (ENCR_DECR_CONTEXT *)(cur_data + sizeof(OP_STATE_DATA)); len = sizeof(ENCR_DECR_CONTEXT) + ctx->context_len + ctx->mech.ulParameterLen; if (len != op_data->data_len) { TRACE_ERROR("%s\n", ock_err(ERR_SAVED_STATE_INVALID)); return CKR_SAVED_STATE_INVALID; } if (encr_key == CK_INVALID_HANDLE) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_NEEDED)); return CKR_KEY_NEEDED; } ptr1 = (CK_BYTE *) ctx; ptr2 = ptr1 + sizeof(ENCR_DECR_CONTEXT); ptr3 = ptr2 + ctx->context_len; if (ctx->context_len) { context = (CK_BYTE *) malloc(ctx->context_len); if (!context) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); return CKR_HOST_MEMORY; } memcpy(context, ptr2, ctx->context_len); } if (ctx->mech.ulParameterLen) { mech_param = (CK_BYTE *) malloc(ctx->mech.ulParameterLen); if (!mech_param) { if (context) free(context); TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); return CKR_HOST_MEMORY; } memcpy(mech_param, ptr3, ctx->mech.ulParameterLen); } } break; case STATE_SIGN: case STATE_VERIFY: { SIGN_VERIFY_CONTEXT *ctx = (SIGN_VERIFY_CONTEXT *)(cur_data + sizeof(OP_STATE_DATA)); len = sizeof(SIGN_VERIFY_CONTEXT) + ctx->context_len + ctx->mech.ulParameterLen + ctx->saved_signature_len; if (len != op_data->data_len) { TRACE_ERROR("%s\n", ock_err(ERR_SAVED_STATE_INVALID)); return CKR_SAVED_STATE_INVALID; } if (auth_key == CK_INVALID_HANDLE) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_NEEDED)); return CKR_KEY_NEEDED; } ptr1 = (CK_BYTE *) ctx; ptr2 = ptr1 + sizeof(SIGN_VERIFY_CONTEXT); ptr3 = ptr2 + ctx->context_len; ptr4 = ptr3 + ctx->mech.ulParameterLen; 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); } if (op_data->active_operation == STATE_VERIFY && ctx->saved_signature_len != 0) { saved_signature = (CK_BYTE *)malloc(ctx->saved_signature_len); if (!saved_signature) { if (context) free(context); if (mech_param) free(mech_param); TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); return CKR_HOST_MEMORY; } memcpy(saved_signature, ptr4, ctx->saved_signature_len); } } break; case STATE_DIGEST: { DIGEST_CONTEXT *ctx = (DIGEST_CONTEXT *)(cur_data + sizeof(OP_STATE_DATA)); len = sizeof(DIGEST_CONTEXT) + ctx->context_len + ctx->mech.ulParameterLen; if (len != op_data->data_len) { TRACE_ERROR("%s\n", ock_err(ERR_SAVED_STATE_INVALID)); return CKR_SAVED_STATE_INVALID; } ptr1 = (CK_BYTE *) ctx; ptr2 = ptr1 + sizeof(DIGEST_CONTEXT); ptr3 = ptr2 + ctx->context_len; if (ctx->context_len) { context = (CK_BYTE *) malloc(ctx->context_len); if (!context) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); return CKR_HOST_MEMORY; } memcpy(context, ptr2, ctx->context_len); } if (ctx->mech.ulParameterLen) { mech_param = (CK_BYTE *) malloc(ctx->mech.ulParameterLen); if (!mech_param) { if (context) free(context); TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); return CKR_HOST_MEMORY; } memcpy(mech_param, ptr3, ctx->mech.ulParameterLen); } } break; default: TRACE_ERROR("%s\n", ock_err(ERR_SAVED_STATE_INVALID)); return CKR_SAVED_STATE_INVALID; } /* copy the new state information */ switch (op_data->active_operation) { case STATE_ENCR: memcpy(&sess->encr_ctx, ptr1, sizeof(ENCR_DECR_CONTEXT)); sess->encr_ctx.key = encr_key; sess->encr_ctx.context = context; sess->encr_ctx.mech.pParameter = mech_param; break; case STATE_DECR: memcpy(&sess->decr_ctx, ptr1, sizeof(ENCR_DECR_CONTEXT)); sess->decr_ctx.key = encr_key; sess->decr_ctx.context = context; sess->decr_ctx.mech.pParameter = mech_param; break; case STATE_SIGN: memcpy(&sess->sign_ctx, ptr1, sizeof(SIGN_VERIFY_CONTEXT)); sess->sign_ctx.key = auth_key; sess->sign_ctx.context = context; sess->sign_ctx.mech.pParameter = mech_param; sess->verify_ctx.saved_signature = saved_signature; 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; sess->verify_ctx.saved_signature = saved_signature; break; case STATE_DIGEST: memcpy(&sess->digest_ctx, ptr1, sizeof(DIGEST_CONTEXT)); sess->digest_ctx.context = context; sess->digest_ctx.mech.pParameter = mech_param; break; } context = NULL; mech_param = NULL; saved_signature = NULL; /* move on to next operation */ cur_data_len -= (op_data->data_len + sizeof(OP_STATE_DATA)); cur_data += (op_data->data_len + sizeof(OP_STATE_DATA)); } return CKR_OK; } CK_RV session_mgr_cancel(STDLL_TokData_t *tokdata, SESSION *sess, CK_FLAGS flags) { if ((flags & CKF_ENCRYPT) && sess->encr_ctx.active) encr_mgr_cleanup(tokdata, sess, &sess->encr_ctx); if ((flags & CKF_DECRYPT) && sess->decr_ctx.active) decr_mgr_cleanup(tokdata, sess, &sess->decr_ctx); if ((flags & CKF_DIGEST) && sess->digest_ctx.active) digest_mgr_cleanup(tokdata, sess, &sess->digest_ctx); if ((flags & CKF_SIGN) && sess->sign_ctx.active && !sess->sign_ctx.recover) sign_mgr_cleanup(tokdata, sess, &sess->sign_ctx); if ((flags & CKF_SIGN_RECOVER) && sess->sign_ctx.active && sess->sign_ctx.recover) sign_mgr_cleanup(tokdata, sess, &sess->sign_ctx); if ((flags & CKF_VERIFY) && sess->verify_ctx.active && !sess->verify_ctx.recover) verify_mgr_cleanup(tokdata, sess, &sess->verify_ctx); if ((flags & CKF_VERIFY_RECOVER) && sess->verify_ctx.active && sess->verify_ctx.recover) verify_mgr_cleanup(tokdata, sess, &sess->verify_ctx); if ((flags & CKF_FIND_OBJECTS) && sess->find_active) { if (sess->find_list) free(sess->find_list); sess->find_list = NULL; sess->find_len = 0; sess->find_idx = 0; sess->find_active = FALSE; } return CKR_OK; } // Return TRUE if the session we're in has its PIN expired. CK_BBOOL pin_expired(CK_SESSION_INFO *si, CK_FLAGS flags) { // If this is an SO session if ((flags & CKF_SO_PIN_TO_BE_CHANGED) && (si->state == CKS_RW_SO_FUNCTIONS)) return TRUE; // Else we're a User session return ((flags & CKF_USER_PIN_TO_BE_CHANGED) && ((si->state == CKS_RO_USER_FUNCTIONS) || (si->state == CKS_RW_USER_FUNCTIONS))); } // Return TRUE if the session we're in has its PIN locked. CK_BBOOL pin_locked(CK_SESSION_INFO *si, CK_FLAGS flags) { // If this is an SO session if ((flags & CKF_SO_PIN_LOCKED) && (si->state == CKS_RW_SO_FUNCTIONS)) return TRUE; // Else we're a User session return ((flags & CKF_USER_PIN_LOCKED) && ((si->state == CKS_RO_USER_FUNCTIONS) || (si->state == CKS_RW_USER_FUNCTIONS))); } // Increment the login flags after an incorrect password // has been passed to C_Login. New for v2.11. - KEY void set_login_flags(CK_USER_TYPE userType, CK_FLAGS_32 *flags) { if (userType == CKU_USER) { if (*flags & CKF_USER_PIN_FINAL_TRY) { *flags |= CKF_USER_PIN_LOCKED; *flags &= ~(CKF_USER_PIN_FINAL_TRY); } else if (*flags & CKF_USER_PIN_COUNT_LOW) { *flags |= CKF_USER_PIN_FINAL_TRY; *flags &= ~(CKF_USER_PIN_COUNT_LOW); } else { *flags |= CKF_USER_PIN_COUNT_LOW; } } else { if (*flags & CKF_SO_PIN_FINAL_TRY) { *flags |= CKF_SO_PIN_LOCKED; *flags &= ~(CKF_SO_PIN_FINAL_TRY); } else if (*flags & CKF_SO_PIN_COUNT_LOW) { *flags |= CKF_SO_PIN_FINAL_TRY; *flags &= ~(CKF_SO_PIN_COUNT_LOW); } else { *flags |= CKF_SO_PIN_COUNT_LOW; } } } struct session_iterate_data { CK_RV (*cb)(STDLL_TokData_t *tokdata, SESSION *session, CK_ULONG ctx_type, CK_MECHANISM *mech, CK_OBJECT_HANDLE key, CK_BYTE *context, CK_ULONG context_len, CK_BBOOL init_pending, CK_BBOOL pkey_active, CK_BBOOL recover, void *private); void *private; CK_RV error; }; static void session_mgr_iterate_session_ops_cb(STDLL_TokData_t *tokdata, void *p1, unsigned long p2, void *p3) { struct session_iterate_data *sid = p3; SESSION *session = p1; CK_RV rc = CKR_OK; UNUSED(p2); if (sid->error != CKR_OK) return; if (session->digest_ctx.active && session->digest_ctx.context != NULL && session->digest_ctx.context_len > 0) { rc = sid->cb(tokdata, session, CONTEXT_TYPE_DIGEST, &session->digest_ctx.mech, CK_INVALID_HANDLE, session->digest_ctx.context, session->digest_ctx.context_len, FALSE, FALSE, FALSE, sid->private); if (rc != CKR_OK) { TRACE_ERROR("%s callback function failed: 0x%lx\n", __func__, rc); goto out; } } if (session->sign_ctx.active && session->sign_ctx.context != NULL && session->sign_ctx.context_len > 0) { rc = sid->cb(tokdata, session, CONTEXT_TYPE_SIGN, &session->sign_ctx.mech, session->sign_ctx.key, session->sign_ctx.context, session->sign_ctx.context_len, session->sign_ctx.init_pending, session->sign_ctx.pkey_active, session->sign_ctx.recover, sid->private); if (rc != CKR_OK) { TRACE_ERROR("%s callback function failed: 0x%lx\n", __func__, rc); goto out; } } if (session->verify_ctx.active && session->verify_ctx.context != NULL && session->verify_ctx.context_len > 0) { rc = sid->cb(tokdata, session, CONTEXT_TYPE_VERIFY, &session->verify_ctx.mech, session->verify_ctx.key, session->verify_ctx.context, session->verify_ctx.context_len, session->verify_ctx.init_pending, session->verify_ctx.pkey_active, session->verify_ctx.recover, sid->private); if (rc != CKR_OK) { TRACE_ERROR("%s callback function failed: 0x%lx\n", __func__, rc); goto out; } } if (session->encr_ctx.active && session->encr_ctx.context != NULL && session->encr_ctx.context_len > 0) { rc = sid->cb(tokdata, session, CONTEXT_TYPE_ENCRYPT, &session->encr_ctx.mech, session->encr_ctx.key, session->encr_ctx.context, session->encr_ctx.context_len, session->encr_ctx.init_pending, session->encr_ctx.pkey_active, FALSE, sid->private); if (rc != CKR_OK) { TRACE_ERROR("%s callback function failed: 0x%lx\n", __func__, rc); goto out; } } if (session->decr_ctx.active && session->decr_ctx.context != NULL && session->decr_ctx.context_len > 0) { rc = sid->cb(tokdata, session, CONTEXT_TYPE_DECRYPT, &session->decr_ctx.mech, session->decr_ctx.key, session->decr_ctx.context, session->decr_ctx.context_len, session->decr_ctx.init_pending, session->decr_ctx.pkey_active, FALSE, sid->private); if (rc != CKR_OK) { TRACE_ERROR("%s callback function failed: 0x%lx\n", __func__, rc); goto out; } } out: if (rc != CKR_OK) sid->error = rc; } CK_RV session_mgr_iterate_session_ops(STDLL_TokData_t *tokdata, SESSION *session, CK_RV (*cb)(STDLL_TokData_t *tokdata, SESSION *session, CK_ULONG ctx_type, CK_MECHANISM *mech, CK_OBJECT_HANDLE key, CK_BYTE *context, CK_ULONG context_len, CK_BBOOL init_pending, CK_BBOOL pkey_active, CK_BBOOL recover, void *private), void *private) { struct session_iterate_data sid; sid.cb = cb; sid.private = private; sid.error = CKR_OK; if (session != NULL) session_mgr_iterate_session_ops_cb(tokdata, session, 0, &sid); else bt_for_each_node(tokdata, &tokdata->sess_btree, session_mgr_iterate_session_ops_cb, &sid); return sid.error; } opencryptoki-opencryptoki-451d99c/usr/lib/common/shared_memory.c000066400000000000000000000323261520105705100252030ustar00rootroot00000000000000/* * 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 #include /* For logging functions: */ #include "pkcs11types.h" #include "defs.h" #include "host_defs.h" #include "h_extern.h" #include "trace.h" #include "ock_syslog.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, const char *group) { 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; struct group *grp; /* * 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; } if (group == NULL || group[0] == '\0') group = PKCS_GROUP; grp = getgrnam(group); if (!grp) { rc = -errno; SYS_ERROR(errno, "getgrname(\"%s\"): %s\n", group, strerror(errno)); 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; } if (fchown(fd, -1, grp->gr_gid) != 0) { rc = -errno; SYS_ERROR(errno, "fchown of token shm segment: %s\n", 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; } /* * If the shared memory segment does not belong to the pkcs11 group or does * not have correct permissions, do not use it. */ if (stat_buf.st_gid != grp->gr_gid || (stat_buf.st_mode & ~S_IFMT) != (unsigned int)mode) { TRACE_ERROR("SHM segment '%s' has wrong gid/mode combination " "(expected: %u/0%o; got: %u/0%o)\n", name, grp->gr_gid, mode, stat_buf.st_gid, stat_buf.st_mode); OCK_SYSLOG(LOG_ERR, "SHM segment '%s' has wrong gid/mode combination " "(expected: %u/0%o; got: %u/0%o)\n", name, grp->gr_gid, mode, stat_buf.st_gid, stat_buf.st_mode); rc = -EINVAL; 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 or too small real_len indicates the new token data format * is used, or the desired size of the shared memory segment has * changed by other means. * If no application is attached to the shm (ref==1) it can be * safely expanded/recreated. Otherwise, fail. * The caller must have the token xproc-lock, so it is save to check * the reference counter here. */ 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) { strncpy(ctx->name, name, SM_NAME_LEN); ctx->name[SM_NAME_LEN] = '\0'; 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) { memcpy(name, ctx->name, SM_NAME_LEN); 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; } opencryptoki-opencryptoki-451d99c/usr/lib/common/shared_memory.h000066400000000000000000000021751520105705100252070ustar00rootroot00000000000000/* * 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, const char *group); 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 opencryptoki-opencryptoki-451d99c/usr/lib/common/sign_mgr.c000066400000000000000000001656371520105705100241660ustar00rootroot00000000000000/* * 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" #include "../api/policy.h" #include "../api/statistics.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, CK_BBOOL checkpolicy, CK_BBOOL checkauth) { OBJECT *key_obj = NULL; CK_ATTRIBUTE *attr = NULL; CK_BYTE *ptr = NULL; CK_KEY_TYPE keytype, exp_keytype, alt_keytype; CK_OBJECT_CLASS class; CK_BBOOL flag; CK_RV rc; CK_ULONG strength = POLICY_STRENGTH_IDX_0; 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 (checkpolicy) { rc = tokdata->policy->is_mech_allowed(tokdata->policy, mech, &key_obj->strength, POLICY_CHECK_SIGNATURE, sess); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: Sign init\n"); goto done; } } ctx->auth_required = FALSE; if (checkauth) { rc = key_object_is_always_authenticate(key_obj->template, &ctx->auth_required); if (rc != CKR_OK) { TRACE_ERROR("key_object_is_always_authenticate failed\n"); goto done; } } if (recover_mode) { // is key allowed to generate signatures where the data can be // recovered from the signature? rc = template_attribute_get_bool(key_obj->template, CKA_SIGN_RECOVER, &flag); if (rc != CKR_OK) { 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_get_bool(key_obj->template, CKA_SIGN, &flag); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_SIGN for the key.\n"); rc = CKR_KEY_FUNCTION_NOT_PERMITTED; goto done; } } if (flag != TRUE) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_FUNCTION_NOT_PERMITTED)); rc = CKR_KEY_FUNCTION_NOT_PERMITTED; goto done; } if (!key_object_is_mechanism_allowed(key_obj->template, mech->mechanism)) { TRACE_ERROR("Mechanism not allowed per CKA_ALLOWED_MECHANISMS.\n"); rc = CKR_MECHANISM_INVALID; 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_get_non_empty(key_obj->template, CKA_MODULUS, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); 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_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } 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 // rc = template_attribute_get_ulong(key_obj->template, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); goto done; } // 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: case CKM_ECDSA_SHA3_224: case CKM_ECDSA_SHA3_256: case CKM_ECDSA_SHA3_384: case CKM_ECDSA_SHA3_512: if (mech->ulParameterLen != 0) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } rc = template_attribute_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } 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 // rc = template_attribute_get_ulong(key_obj->template, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); goto done; } 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(MP_DIGEST_CONTEXT); ctx->context = (CK_BYTE *) malloc(sizeof(MP_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(MP_DIGEST_CONTEXT)); } break; case CKM_EDDSA: /* Mechanism parameter CK_EDDSA_PARAMS is optional */ if (mech->ulParameterLen != 0 && mech->ulParameterLen != sizeof(CK_EDDSA_PARAMS)) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } rc = template_attribute_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } if (keytype != CKK_EC_EDWARDS) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); rc = CKR_KEY_TYPE_INCONSISTENT; goto done; } // must be a PRIVATE key // rc = template_attribute_get_ulong(key_obj->template, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); goto done; } 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 = 0; ctx->context = NULL; 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: case CKM_SHA3_224_RSA_PKCS: case CKM_SHA3_256_RSA_PKCS: case CKM_SHA3_384_RSA_PKCS: case CKM_SHA3_512_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_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } 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 // rc = template_attribute_get_ulong(key_obj->template, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); goto done; } 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(MP_DIGEST_CONTEXT); ctx->context = (CK_BYTE *) malloc(sizeof(MP_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(MP_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: case CKM_SHA3_224_RSA_PKCS_PSS: case CKM_SHA3_256_RSA_PKCS_PSS: case CKM_SHA3_384_RSA_PKCS_PSS: case CKM_SHA3_512_RSA_PKCS_PSS: rc = template_attribute_get_non_empty(key_obj->template, CKA_MODULUS, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); 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_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } 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 // rc = template_attribute_get_ulong(key_obj->template, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } 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_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } 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 // rc = template_attribute_get_ulong(key_obj->template, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); goto done; } // 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_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } 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: case CKM_SHA3_224_HMAC: case CKM_SHA3_256_HMAC: case CKM_SHA3_384_HMAC: case CKM_SHA3_512_HMAC: case CKM_IBM_SHA3_224_HMAC: case CKM_IBM_SHA3_256_HMAC: case CKM_IBM_SHA3_384_HMAC: case CKM_IBM_SHA3_512_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_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } rc = pkcsget_keytype_for_mech(mech->mechanism, &exp_keytype, &alt_keytype); if (rc != CKR_OK) { TRACE_ERROR("pkcsget_keytype_for_mech failed.\n"); goto done; } if (keytype != exp_keytype && keytype != alt_keytype) { 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; strength = key_obj->strength.strength; /* Release obj lock, token specific hmac-sign may re-acquire the lock */ object_put(tokdata, key_obj, TRUE); key_obj = 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) || mech->pParameter == NULL) { 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_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } 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: case CKM_SHA3_224_HMAC_GENERAL: case CKM_SHA3_256_HMAC_GENERAL: case CKM_SHA3_384_HMAC_GENERAL: case CKM_SHA3_512_HMAC_GENERAL: { CK_MAC_GENERAL_PARAMS *param = (CK_MAC_GENERAL_PARAMS *) mech->pParameter; CK_MECHANISM_TYPE digest_mech; CK_BBOOL general; CK_ULONG hsize; if (mech->ulParameterLen != sizeof(CK_MAC_GENERAL_PARAMS) || mech->pParameter == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } rc = get_hmac_digest(mech->mechanism, &digest_mech, &general); if (rc != CKR_OK) { TRACE_ERROR("%s get_hmac_digest failed\n", __func__); goto done; } rc = get_sha_size(digest_mech, &hsize); if (rc != CKR_OK) { TRACE_ERROR("%s get_sha_size failed\n", __func__); goto done; } if (*param > hsize) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } rc = template_attribute_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } rc = pkcsget_keytype_for_mech(mech->mechanism, &exp_keytype, &alt_keytype); if (rc != CKR_OK) { TRACE_ERROR("pkcsget_keytype_for_mech failed.\n"); goto done; } if (keytype != exp_keytype && keytype != alt_keytype) { 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_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) || mech->pParameter == NULL) { 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_get_ulong(key_obj->template, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); goto done; } 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(MP_DIGEST_CONTEXT); ctx->context = (CK_BYTE *) malloc(sizeof(MP_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(MP_DIGEST_CONTEXT)); } break; case CKM_DES3_MAC: case CKM_DES3_MAC_GENERAL: if (mech->pParameter) { if (mech->ulParameterLen != sizeof(CK_MAC_GENERAL_PARAMS) || mech->pParameter == NULL) { 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) || mech->pParameter == NULL) { 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) || mech->pParameter == NULL) { 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) || mech->pParameter == NULL) { 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; case CKM_IBM_DILITHIUM: if (mech->ulParameterLen != 0) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } rc = template_attribute_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } if (keytype != CKK_IBM_PQC_DILITHIUM) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); rc = CKR_KEY_TYPE_INCONSISTENT; goto done; } rc = template_attribute_get_ulong(key_obj->template, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); goto done; } 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 = 0; ctx->context = NULL; break; case CKM_IBM_ML_DSA: if (mech->ulParameterLen != 0 && mech->ulParameterLen != sizeof(CK_IBM_SIGN_ADDITIONAL_CONTEXT)) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } if (mech->ulParameterLen == sizeof(CK_IBM_SIGN_ADDITIONAL_CONTEXT) && mech->pParameter == NULL) { rc = CKR_MECHANISM_PARAM_INVALID; goto done; } rc = template_attribute_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } if (keytype != CKK_IBM_ML_DSA) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); rc = CKR_KEY_TYPE_INCONSISTENT; goto done; } rc = template_attribute_get_ulong(key_obj->template, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); goto done; } 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 = 0; ctx->context = NULL; break; case CKM_ML_DSA: case CKM_HASH_ML_DSA: case CKM_HASH_ML_DSA_SHA224: case CKM_HASH_ML_DSA_SHA256: case CKM_HASH_ML_DSA_SHA384: case CKM_HASH_ML_DSA_SHA512: case CKM_HASH_ML_DSA_SHA3_224: case CKM_HASH_ML_DSA_SHA3_256: case CKM_HASH_ML_DSA_SHA3_384: case CKM_HASH_ML_DSA_SHA3_512: case CKM_HASH_ML_DSA_SHAKE128: case CKM_HASH_ML_DSA_SHAKE256: if (mech->mechanism == CKM_HASH_ML_DSA) { if (mech->ulParameterLen != sizeof(CK_HASH_SIGN_ADDITIONAL_CONTEXT) || mech->pParameter == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } } else { if (mech->ulParameterLen != 0 && mech->ulParameterLen != sizeof(CK_SIGN_ADDITIONAL_CONTEXT)) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } if (mech->ulParameterLen == sizeof(CK_SIGN_ADDITIONAL_CONTEXT) && mech->pParameter == NULL) { rc = CKR_MECHANISM_PARAM_INVALID; goto done; } } rc = template_attribute_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } if (keytype != CKK_ML_DSA) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); rc = CKR_KEY_TYPE_INCONSISTENT; goto done; } rc = template_attribute_get_ulong(key_obj->template, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); goto done; } 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_ML_DSA || mech->mechanism == CKM_HASH_ML_DSA) { ctx->context_len = 0; ctx->context = NULL; } else { ctx->context_len = sizeof(MP_DIGEST_CONTEXT); ctx->context = (CK_BYTE *) malloc(sizeof(MP_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(MP_DIGEST_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); /* Deep copy mechanism parameter, if required */ switch (mech->mechanism) { case CKM_IBM_ML_DSA: rc = ibm_ml_dsa_dup_param(mech->pParameter, ptr, mech->ulParameterLen); if (rc != CKR_OK) { TRACE_ERROR("ibm_ml_dsa_dup_param failed\n"); free(ptr); } break; case CKM_ML_DSA: case CKM_HASH_ML_DSA_SHA224: case CKM_HASH_ML_DSA_SHA256: case CKM_HASH_ML_DSA_SHA384: case CKM_HASH_ML_DSA_SHA512: case CKM_HASH_ML_DSA_SHA3_224: case CKM_HASH_ML_DSA_SHA3_256: case CKM_HASH_ML_DSA_SHA3_384: case CKM_HASH_ML_DSA_SHA3_512: case CKM_HASH_ML_DSA_SHAKE128: case CKM_HASH_ML_DSA_SHAKE256: rc = ml_dsa_dup_param(mech->pParameter, ptr, mech->ulParameterLen); if (rc != CKR_OK) { TRACE_ERROR("ml_dsa_dup_param failed\n"); free(ptr); } break; case CKM_HASH_ML_DSA: rc = ml_dsa_hash_dup_param(mech->pParameter, ptr, mech->ulParameterLen); if (rc != CKR_OK) { TRACE_ERROR("ml_dsa_hash_dup_param failed\n"); free(ptr); } break; default: break; } } 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; ctx->pkey_active = FALSE; rc = CKR_OK; done: if (ctx->count_statistics == TRUE && rc == CKR_OK) INC_COUNTER(tokdata, sess, mech, key_obj, strength); object_put(tokdata, key_obj, TRUE); key_obj = NULL; return rc; } // // CK_RV sign_mgr_cleanup(STDLL_TokData_t *tokdata, SESSION *sess, SIGN_VERIFY_CONTEXT *ctx) { if (!ctx) { TRACE_ERROR("Invalid function argument.\n"); return CKR_FUNCTION_FAILED; } ctx->key = 0; ctx->multi_init = FALSE; ctx->multi = FALSE; ctx->active = FALSE; ctx->init_pending = FALSE; ctx->recover = FALSE; ctx->pkey_active = FALSE; ctx->state_unsaveable = FALSE; ctx->count_statistics = FALSE; ctx->auth_required = FALSE; if (ctx->mech.pParameter) { /* Deep free mechanism parameter, if required */ switch (ctx->mech.mechanism) { case CKM_IBM_EC_AGGREGATE: ec_agg_free_param((CK_IBM_ECDSA_OTHER_BLS_PARAMS *)ctx->mech.pParameter); break; case CKM_IBM_ML_DSA: ibm_ml_dsa_free_param(ctx->mech.pParameter, ctx->mech.ulParameterLen); break; case CKM_ML_DSA: case CKM_HASH_ML_DSA_SHA224: case CKM_HASH_ML_DSA_SHA256: case CKM_HASH_ML_DSA_SHA384: case CKM_HASH_ML_DSA_SHA512: case CKM_HASH_ML_DSA_SHA3_224: case CKM_HASH_ML_DSA_SHA3_256: case CKM_HASH_ML_DSA_SHA3_384: case CKM_HASH_ML_DSA_SHA3_512: case CKM_HASH_ML_DSA_SHAKE128: case CKM_HASH_ML_DSA_SHAKE256: ml_dsa_free_param(ctx->mech.pParameter, ctx->mech.ulParameterLen); break; case CKM_HASH_ML_DSA: ml_dsa_hash_free_param(ctx->mech.pParameter, ctx->mech.ulParameterLen); break; default: break; } free(ctx->mech.pParameter); ctx->mech.pParameter = NULL; } ctx->mech.ulParameterLen = 0; if (ctx->context) { /* Cleanup nested contexts if required */ 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: case CKM_SHA3_224_RSA_PKCS: case CKM_SHA3_256_RSA_PKCS: case CKM_SHA3_384_RSA_PKCS: case CKM_SHA3_512_RSA_PKCS: case CKM_ECDSA_SHA1: case CKM_ECDSA_SHA224: case CKM_ECDSA_SHA256: case CKM_ECDSA_SHA384: case CKM_ECDSA_SHA512: case CKM_ECDSA_SHA3_224: case CKM_ECDSA_SHA3_256: case CKM_ECDSA_SHA3_384: case CKM_ECDSA_SHA3_512: case CKM_SSL3_MD5_MAC: case CKM_SSL3_SHA1_MAC: case CKM_HASH_ML_DSA_SHA224: case CKM_HASH_ML_DSA_SHA256: case CKM_HASH_ML_DSA_SHA384: case CKM_HASH_ML_DSA_SHA512: case CKM_HASH_ML_DSA_SHA3_224: case CKM_HASH_ML_DSA_SHA3_256: case CKM_HASH_ML_DSA_SHA3_384: case CKM_HASH_ML_DSA_SHA3_512: case CKM_HASH_ML_DSA_SHAKE128: case CKM_HASH_ML_DSA_SHAKE256: /* Uses MP_DIGEST_CONTEXT as context, contains a DIGEST_CONTEXT */ if (ctx->context_len != sizeof(MP_DIGEST_CONTEXT)) break; digest_mgr_cleanup(tokdata, sess, &((MP_DIGEST_CONTEXT *)ctx->context)->hash_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: case CKM_SHA3_224_RSA_PKCS_PSS: case CKM_SHA3_256_RSA_PKCS_PSS: case CKM_SHA3_384_RSA_PKCS_PSS: case CKM_SHA3_512_RSA_PKCS_PSS: /* Uses DIGEST_CONTEXT as context */ if (ctx->context_len != sizeof(DIGEST_CONTEXT)) break; digest_mgr_cleanup(tokdata, sess, (DIGEST_CONTEXT *)ctx->context); break; default: break; } if (ctx->context_free_func != NULL) ctx->context_free_func(tokdata, sess, ctx->context, ctx->context_len); else free(ctx->context); ctx->context = NULL; } ctx->context_len = 0; ctx->context_free_func = NULL; ctx->mech.mechanism = 0; if (ctx->saved_signature) { free(ctx->saved_signature); ctx->saved_signature = 0; } ctx->saved_signature_len = 0; 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->auth_required == TRUE) { TRACE_ERROR("%s\n", ock_err(ERR_USER_NOT_LOGGED_IN)); return CKR_USER_NOT_LOGGED_IN; } 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: case CKM_SHA3_224_RSA_PKCS: case CKM_SHA3_256_RSA_PKCS: case CKM_SHA3_384_RSA_PKCS: case CKM_SHA3_512_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: case CKM_SHA3_224_RSA_PKCS_PSS: case CKM_SHA3_256_RSA_PKCS_PSS: case CKM_SHA3_384_RSA_PKCS_PSS: case CKM_SHA3_512_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: 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_SHA3_224_HMAC: case CKM_SHA3_224_HMAC_GENERAL: case CKM_SHA3_256_HMAC: case CKM_SHA3_256_HMAC_GENERAL: case CKM_SHA3_384_HMAC: case CKM_SHA3_384_HMAC_GENERAL: case CKM_SHA3_512_HMAC: case CKM_SHA3_512_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: return sha_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: case CKM_ECDSA_SHA3_224: case CKM_ECDSA_SHA3_256: case CKM_ECDSA_SHA3_384: case CKM_ECDSA_SHA3_512: return ec_hash_sign(tokdata, sess, length_only, ctx, in_data, in_data_len, out_data, out_data_len); case CKM_ECDSA: case CKM_EDDSA: 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); case CKM_IBM_DILITHIUM: case CKM_IBM_ML_DSA: return ibm_ml_dsa_sign(tokdata, sess, length_only, ctx, in_data, in_data_len, out_data, out_data_len); case CKM_ML_DSA: return ml_dsa_sign(tokdata, sess, length_only, ctx, in_data, in_data_len, out_data, out_data_len, TRUE); case CKM_HASH_ML_DSA: case CKM_HASH_ML_DSA_SHA224: case CKM_HASH_ML_DSA_SHA256: case CKM_HASH_ML_DSA_SHA384: case CKM_HASH_ML_DSA_SHA512: case CKM_HASH_ML_DSA_SHA3_224: case CKM_HASH_ML_DSA_SHA3_256: case CKM_HASH_ML_DSA_SHA3_384: case CKM_HASH_ML_DSA_SHA3_512: case CKM_HASH_ML_DSA_SHAKE128: case CKM_HASH_ML_DSA_SHAKE256: return ml_dsa_hash_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->auth_required == TRUE) { TRACE_ERROR("%s\n", ock_err(ERR_USER_NOT_LOGGED_IN)); return CKR_USER_NOT_LOGGED_IN; } 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: case CKM_SHA3_224_RSA_PKCS: case CKM_SHA3_256_RSA_PKCS: case CKM_SHA3_384_RSA_PKCS: case CKM_SHA3_512_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: case CKM_SHA3_224_RSA_PKCS_PSS: case CKM_SHA3_256_RSA_PKCS_PSS: case CKM_SHA3_384_RSA_PKCS_PSS: case CKM_SHA3_512_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: case CKM_ECDSA_SHA3_224: case CKM_ECDSA_SHA3_256: case CKM_ECDSA_SHA3_384: case CKM_ECDSA_SHA3_512: 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: case CKM_SHA3_224_HMAC: case CKM_SHA3_224_HMAC_GENERAL: case CKM_SHA3_256_HMAC: case CKM_SHA3_256_HMAC_GENERAL: case CKM_SHA3_384_HMAC: case CKM_SHA3_384_HMAC_GENERAL: case CKM_SHA3_512_HMAC: case CKM_SHA3_512_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: return hmac_sign_update(tokdata, sess, in_data, in_data_len); case CKM_ML_DSA: return ml_dsa_sign(tokdata, sess, FALSE, ctx, in_data, in_data_len, NULL, NULL, FALSE); case CKM_HASH_ML_DSA_SHA224: case CKM_HASH_ML_DSA_SHA256: case CKM_HASH_ML_DSA_SHA384: case CKM_HASH_ML_DSA_SHA512: case CKM_HASH_ML_DSA_SHA3_224: case CKM_HASH_ML_DSA_SHA3_256: case CKM_HASH_ML_DSA_SHA3_384: case CKM_HASH_ML_DSA_SHA3_512: case CKM_HASH_ML_DSA_SHAKE128: case CKM_HASH_ML_DSA_SHAKE256: return ml_dsa_hash_sign_verify_update(tokdata, sess, ctx, 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->auth_required == TRUE) { TRACE_ERROR("%s\n", ock_err(ERR_USER_NOT_LOGGED_IN)); return CKR_USER_NOT_LOGGED_IN; } if (ctx->multi_init == FALSE || 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: case CKM_SHA3_224_RSA_PKCS: case CKM_SHA3_256_RSA_PKCS: case CKM_SHA3_384_RSA_PKCS: case CKM_SHA3_512_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: case CKM_SHA3_224_RSA_PKCS_PSS: case CKM_SHA3_256_RSA_PKCS_PSS: case CKM_SHA3_384_RSA_PKCS_PSS: case CKM_SHA3_512_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: case CKM_ECDSA_SHA3_224: case CKM_ECDSA_SHA3_256: case CKM_ECDSA_SHA3_384: case CKM_ECDSA_SHA3_512: 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: case CKM_SHA3_224_HMAC: case CKM_SHA3_224_HMAC_GENERAL: case CKM_SHA3_256_HMAC: case CKM_SHA3_256_HMAC_GENERAL: case CKM_SHA3_384_HMAC: case CKM_SHA3_384_HMAC_GENERAL: case CKM_SHA3_512_HMAC: case CKM_SHA3_512_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: return hmac_sign_final(tokdata, sess, signature, sig_len); case CKM_ML_DSA: return ml_dsa_sign(tokdata, sess, length_only, ctx, NULL, 0, signature, sig_len, TRUE); case CKM_HASH_ML_DSA_SHA224: case CKM_HASH_ML_DSA_SHA256: case CKM_HASH_ML_DSA_SHA384: case CKM_HASH_ML_DSA_SHA512: case CKM_HASH_ML_DSA_SHA3_224: case CKM_HASH_ML_DSA_SHA3_256: case CKM_HASH_ML_DSA_SHA3_384: case CKM_HASH_ML_DSA_SHA3_512: case CKM_HASH_ML_DSA_SHAKE128: case CKM_HASH_ML_DSA_SHAKE256: return ml_dsa_hash_sign_final(tokdata, sess, length_only, ctx, 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 (ctx->auth_required == TRUE) { TRACE_ERROR("%s\n", ock_err(ERR_USER_NOT_LOGGED_IN)); return CKR_USER_NOT_LOGGED_IN; } // 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; } opencryptoki-opencryptoki-451d99c/usr/lib/common/stringtranslations.h000066400000000000000000000033331520105705100263160ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021 * * 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_STRINGTRANSLATIONS_H #define OCK_STRINGTRANSLATIONS_H #include #include #include "ec_defs.h" #include "mechtable.h" /* * Translate a string of a given length CK_RVo a mechanism id. */ static inline CK_RV translate_string_to_mech(const char *str, size_t len, CK_ULONG *mech) { (void)len; const struct mechrow *col = mechrow_from_string(str); if (col) { *mech = col->numeric; return CKR_OK; } return CKR_FUNCTION_FAILED; } /* * Translate an elliptic curve name (all caps) of a given length CK_RVo * a struct _ec. */ CK_RV translate_string_to_curve(const char *str, size_t len, const struct _ec **curve); CK_RV translate_string_to_mgf(const char *str, size_t len, CK_ULONG* mgf); CK_RV translate_string_to_kdf(const char *str, size_t len, CK_ULONG* kdf); static inline CK_RV translate_string_to_prf(const char *str, size_t len, CK_ULONG* prf) { (void)len; if (strcmp(str, "CKP_PKCS5_PBKD2_HMAC_SHA256") == 0) { *prf = CKP_PKCS5_PBKD2_HMAC_SHA256; return CKR_OK; } if (strcmp(str, "CKP_PKCS5_PBKD2_HMAC_SHA512") == 0) { *prf = CKP_PKCS5_PBKD2_HMAC_SHA512; return CKR_OK; } return CKR_FUNCTION_FAILED; } #endif opencryptoki-opencryptoki-451d99c/usr/lib/common/sw_crypt.c000066400000000000000000000064561520105705100242240ustar00rootroot00000000000000/* * 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 "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) { CK_RV rc; int outlen; const EVP_CIPHER *cipher = EVP_des_ede3_cbc(); EVP_CIPHER_CTX *ctx = NULL; if (in_data_len % DES_BLOCK_SIZE || in_data_len > INT_MAX) { TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); return CKR_DATA_LEN_RANGE; } ctx = EVP_CIPHER_CTX_new(); if (ctx == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto done; } if (EVP_CipherInit_ex(ctx, cipher, NULL, key_value, init_v, encrypt ? 1 : 0) != 1 || EVP_CIPHER_CTX_set_padding(ctx, 0) != 1 || EVP_CipherUpdate(ctx, out_data, &outlen, in_data, in_data_len) != 1 || EVP_CipherFinal_ex(ctx, out_data, &outlen) != 1) { TRACE_ERROR("%s\n", ock_err(ERR_GENERAL_ERROR)); rc = CKR_GENERAL_ERROR; goto done; } *out_data_len = in_data_len; rc = CKR_OK; done: EVP_CIPHER_CTX_free(ctx); return rc; } 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) { CK_RV rc; int outlen; const EVP_CIPHER *cipher = NULL; EVP_CIPHER_CTX *ctx = NULL; UNUSED(out_data_len); if (keylen == 128 / 8) cipher = EVP_aes_128_cbc(); else if (keylen == 192 / 8) cipher = EVP_aes_192_cbc(); else if (keylen == 256 / 8) cipher = EVP_aes_256_cbc(); if (in_data_len % AES_BLOCK_SIZE || in_data_len > INT_MAX) { TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); rc = CKR_DATA_LEN_RANGE; goto done; } ctx = EVP_CIPHER_CTX_new(); if (ctx == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto done; } if (EVP_CipherInit_ex(ctx, cipher, NULL, key_value, init_v, encrypt ? 1 : 0) != 1 || EVP_CIPHER_CTX_set_padding(ctx, 0) != 1 || EVP_CipherUpdate(ctx, out_data, &outlen, in_data, in_data_len) != 1 || EVP_CipherFinal_ex(ctx, out_data, &outlen) != 1) { TRACE_ERROR("%s\n", ock_err(ERR_GENERAL_ERROR)); rc = CKR_GENERAL_ERROR; goto done; } rc = CKR_OK; done: EVP_CIPHER_CTX_free(ctx); return rc; } opencryptoki-opencryptoki-451d99c/usr/lib/common/sw_crypt.h000066400000000000000000000026241520105705100242220ustar00rootroot00000000000000/* * 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 opencryptoki-opencryptoki-451d99c/usr/lib/common/template.c000066400000000000000000002201441520105705100241550ustar00rootroot00000000000000/* * 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 #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 "attributes.h" #include "trace.h" static CK_ULONG attribute_get_compressed_size(CK_ATTRIBUTE_PTR attr); /* Random 32 byte string is unique with overwhelming probability. */ #define UNIQUE_ID_LEN 32 static CK_RV get_unique_id_str(char unique_id_str[2 * UNIQUE_ID_LEN + 1]) { unsigned char buf[UNIQUE_ID_LEN]; size_t i; if (RAND_bytes(buf, sizeof(buf)) != 1) return CKR_FUNCTION_FAILED; for (i = 0; i < sizeof(buf); i++) sprintf(&unique_id_str[i * 2], "%02x", buf[i]); return CKR_OK; } /* 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: %lx\n", ock_err(ERR_ATTRIBUTE_TYPE_INVALID), pTemplate[i].type); return CKR_ATTRIBUTE_TYPE_INVALID; } if (pTemplate[i].ulValueLen > 0 && pTemplate[i].pValue == NULL) { TRACE_ERROR("%s: %lx\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID), pTemplate[i].type); return CKR_ATTRIBUTE_VALUE_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); if (is_attribute_attr_array(pTemplate[i].type)) { rc = dup_attribute_array_no_alloc( (CK_ATTRIBUTE_PTR)pTemplate[i].pValue, attr->ulValueLen / sizeof(CK_ATTRIBUTE), (CK_ATTRIBUTE_PTR)attr->pValue); if (rc !=CKR_OK) { if (attr->pValue != NULL) OPENSSL_cleanse(attr->pValue, attr->ulValueLen); free(attr); TRACE_DEVEL("dup_attribute_array_no_alloc failed.\n"); return rc; } } else { memcpy(attr->pValue, pTemplate[i].pValue, attr->ulValueLen); } } else { attr->pValue = NULL; } rc = template_update_attribute(tmpl, attr); if (rc != CKR_OK) { if (attr->pValue != NULL) OPENSSL_cleanse(attr->pValue, attr->ulValueLen); 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(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, TEMPLATE *basetmpl, CK_ULONG class, CK_ULONG subclass, CK_ULONG mode) { CK_RV rc; /* * First add the default common attributes. CKA_PRIVATE is TRUE by default * for private and secret keys, but only if USER is logged in. An SO session * or a public session does not have access to private objects, thus private * objects can not be created without USER being logged in. */ rc = template_set_default_common_attributes( tmpl, session_mgr_user_session_exists(tokdata) && (class == CKO_SECRET_KEY || class == CKO_PRIVATE_KEY)); 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_EC: case CKK_EC_EDWARDS: case CKK_EC_MONTGOMERY: return ec_publ_set_default_attributes(tmpl, mode, subclass); case CKK_DH: return dh_publ_set_default_attributes(tmpl, mode); case CKK_IBM_PQC_DILITHIUM: case CKK_IBM_ML_DSA: return ibm_ml_dsa_publ_set_default_attributes(tmpl, mode, subclass); case CKK_IBM_PQC_KYBER: case CKK_IBM_ML_KEM: return ibm_ml_kem_publ_set_default_attributes(tmpl, mode, subclass); case CKK_ML_DSA: return ml_dsa_publ_set_default_attributes(tmpl, mode); case CKK_ML_KEM: return ml_kem_publ_set_default_attributes(tmpl, mode); default: TRACE_ERROR("%s: %lx\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID), subclass); 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_EC: case CKK_EC_EDWARDS: case CKK_EC_MONTGOMERY: return ec_priv_set_default_attributes(tmpl, mode, subclass); case CKK_DH: return dh_priv_set_default_attributes(tmpl, mode); case CKK_IBM_PQC_DILITHIUM: case CKK_IBM_ML_DSA: return ibm_ml_dsa_priv_set_default_attributes(tmpl, mode, subclass); case CKK_IBM_PQC_KYBER: case CKK_IBM_ML_KEM: return ibm_ml_kem_priv_set_default_attributes(tmpl, mode, subclass); case CKK_ML_DSA: return ml_dsa_priv_set_default_attributes(tmpl, mode); case CKK_ML_KEM: return ml_kem_priv_set_default_attributes(tmpl, mode); default: TRACE_ERROR("%s: %lx\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID), subclass); return CKR_ATTRIBUTE_VALUE_INVALID; // unknown key type } case CKO_SECRET_KEY: switch (subclass) { case CKK_GENERIC_SECRET: case CKK_SHA_1_HMAC: case CKK_SHA224_HMAC: case CKK_SHA256_HMAC: case CKK_SHA384_HMAC: case CKK_SHA512_HMAC: case CKK_SHA3_224_HMAC: case CKK_SHA3_256_HMAC: case CKK_SHA3_384_HMAC: case CKK_SHA3_512_HMAC: case CKK_SHA512_224_HMAC: case CKK_SHA512_256_HMAC: return generic_secret_set_default_attributes(tmpl, mode, subclass); 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_AES: return aes_set_default_attributes(tmpl, basetmpl, mode, FALSE); case CKK_AES_XTS: return aes_set_default_attributes(tmpl, basetmpl, mode, TRUE); default: TRACE_ERROR("%s: %lx\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID), subclass); 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: %lx\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID), subclass); 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: %lx\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID), subclass); return CKR_ATTRIBUTE_VALUE_INVALID; } case CKO_PROFILE: return profile_object_set_default_attributes(tmpl, mode); default: TRACE_ERROR("%s: %lx\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID), class); 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; } /* * Find the ULONG attribute in the list and check that the value length is * sizeof(CK_ULONG) and that it is non-empty. * Returns CKR_TEMPLATE_INCOMPLETE if the attribute is not found. * Returns CKR_ATTRIBUTE_VALUE_INVALID if the attribute value is empty or of * invalid size. */ CK_RV template_attribute_get_ulong(TEMPLATE *tmpl, CK_ATTRIBUTE_TYPE type, CK_ULONG *value) { CK_ATTRIBUTE *attr = NULL; CK_BBOOL found; found = template_attribute_find(tmpl, type, &attr); if (!found || attr == NULL) return CKR_TEMPLATE_INCOMPLETE; if (attr->ulValueLen != sizeof(CK_LONG) || attr->pValue == NULL) { TRACE_ERROR("%s: %lx\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID), type); return CKR_ATTRIBUTE_VALUE_INVALID; } *value = *(CK_ULONG *)attr->pValue; return CKR_OK; } /* * Find the BOOL attribute in the list and check that the value length is * sizeof(CK_ULONG) and that it is non-empty. * Returns CKR_TEMPLATE_INCOMPLETE if the attribute is not found. * Returns CKR_ATTRIBUTE_VALUE_INVALID if the attribute value is empty or of * invalid size. */ CK_RV template_attribute_get_bool(TEMPLATE *tmpl, CK_ATTRIBUTE_TYPE type, CK_BBOOL *value) { CK_ATTRIBUTE *attr = NULL; CK_BBOOL found; found = template_attribute_find(tmpl, type, &attr); if (!found || attr == NULL) return CKR_TEMPLATE_INCOMPLETE; if (attr->ulValueLen != sizeof(CK_BBOOL) || attr->pValue == NULL) { TRACE_ERROR("%s: %lx\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID), type); return CKR_ATTRIBUTE_VALUE_INVALID; } *value = *(CK_BBOOL *)attr->pValue; return CKR_OK; } /* * Find the attribute in the list and check that the value length is > 0 and * that it is non-empty. * Returns CKR_TEMPLATE_INCOMPLETE if the attribute is not found. * Returns CKR_ATTRIBUTE_VALUE_INVALID if the attribute value is empty or of * invalid size. */ CK_RV template_attribute_get_non_empty(TEMPLATE *tmpl, CK_ATTRIBUTE_TYPE type, CK_ATTRIBUTE **attr) { CK_BBOOL found; found = template_attribute_find(tmpl, type, attr); if (!found || *attr == NULL) { *attr = NULL; return CKR_TEMPLATE_INCOMPLETE; } if ((*attr)->ulValueLen == 0 || (*attr)->pValue == NULL) { *attr = NULL; TRACE_DEVEL("%s: %lx\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID), type); return CKR_ATTRIBUTE_VALUE_INVALID; } return CKR_OK; } /* 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; CK_RV rc; 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) { if (attr->ulValueLen <= parselist[i].len) parselist[i].len = attr->ulValueLen; if (attr->pValue != NULL) { if (is_attribute_attr_array(attr->type)) { rc = dup_attribute_array_no_alloc( (CK_ATTRIBUTE_PTR)attr->pValue, attr->ulValueLen / sizeof(CK_ATTRIBUTE), (CK_ATTRIBUTE_PTR)parselist[i].ptr); if (rc != CKR_OK) { parselist[i].found = FALSE; TRACE_DEVEL("dup_attribute_array_no_alloc failed\n"); } } else { 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_EC: case CKK_EC_EDWARDS: case CKK_EC_MONTGOMERY: return ec_publ_check_required_attributes(tmpl, mode); case CKK_DH: return dh_publ_check_required_attributes(tmpl, mode); case CKK_IBM_PQC_DILITHIUM: return ibm_ml_dsa_publ_check_required_attributes(tmpl, mode, CKM_IBM_DILITHIUM); case CKK_IBM_PQC_KYBER: return ibm_ml_kem_publ_check_required_attributes(tmpl, mode, CKM_IBM_KYBER); case CKK_IBM_ML_DSA: return ibm_ml_dsa_publ_check_required_attributes(tmpl, mode, CKM_IBM_ML_DSA); case CKK_IBM_ML_KEM: return ibm_ml_kem_publ_check_required_attributes(tmpl, mode, CKM_IBM_ML_KEM); case CKK_ML_DSA: return ml_dsa_publ_check_required_attributes(tmpl, mode); case CKK_ML_KEM: return ml_kem_publ_check_required_attributes(tmpl, mode); default: TRACE_ERROR("%s: %lx\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID), subclass); 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_EC: case CKK_EC_EDWARDS: case CKK_EC_MONTGOMERY: return ec_priv_check_required_attributes(tmpl, mode); case CKK_DH: return dh_priv_check_required_attributes(tmpl, mode); case CKK_IBM_PQC_DILITHIUM: return ibm_ml_dsa_priv_check_required_attributes(tmpl, mode, CKM_IBM_DILITHIUM); case CKK_IBM_PQC_KYBER: return ibm_ml_kem_priv_check_required_attributes(tmpl, mode, CKM_IBM_KYBER); case CKK_IBM_ML_DSA: return ibm_ml_dsa_priv_check_required_attributes(tmpl, mode, CKM_IBM_ML_DSA); case CKK_IBM_ML_KEM: return ibm_ml_kem_priv_check_required_attributes(tmpl, mode, CKM_IBM_ML_KEM); case CKK_ML_DSA: return ml_dsa_priv_check_required_attributes(tmpl, mode); case CKK_ML_KEM: return ml_kem_priv_check_required_attributes(tmpl, mode); default: TRACE_ERROR("%s: %lx\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID), subclass); return CKR_ATTRIBUTE_VALUE_INVALID; // unknown key type } } else if (class == CKO_SECRET_KEY) { switch (subclass) { case CKK_GENERIC_SECRET: case CKK_SHA_1_HMAC: case CKK_SHA224_HMAC: case CKK_SHA256_HMAC: case CKK_SHA384_HMAC: case CKK_SHA512_HMAC: case CKK_SHA3_224_HMAC: case CKK_SHA3_256_HMAC: case CKK_SHA3_384_HMAC: case CKK_SHA3_512_HMAC: case CKK_SHA512_224_HMAC: case CKK_SHA512_256_HMAC: return generic_secret_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_AES: case CKK_AES_XTS: return aes_check_required_attributes(tmpl, mode); default: TRACE_ERROR("%s: %lx\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID), subclass); 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: %lx\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID), subclass); 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: %lx\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID), subclass); return CKR_ATTRIBUTE_VALUE_INVALID; } } else if (class == CKO_PROFILE) { return profile_object_check_required_attributes(tmpl, mode); } TRACE_ERROR("%s: %lx\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID), class); 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_ULONG val; CK_RV rc; rc = template_attribute_get_ulong(tmpl, CKA_CLASS, &val); if ((mode == MODE_CREATE || mode == MODE_EXTRACT) && rc != CKR_OK) 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 (!compare_attribute(attr1, attr2)) 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) { char unique_id_str[2 * UNIQUE_ID_LEN + 1]; DL_NODE *node, *list; 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; 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); if (new_attr->ulValueLen > 0) new_attr->pValue = (CK_BYTE *) new_attr + sizeof(CK_ATTRIBUTE); else new_attr->pValue = NULL; if (is_attribute_attr_array(new_attr->type) && new_attr->ulValueLen > 0) { rc = dup_attribute_array_no_alloc((CK_ATTRIBUTE_PTR)attr->pValue, attr->ulValueLen / sizeof(CK_ATTRIBUTE), (CK_ATTRIBUTE_PTR)new_attr->pValue); if (rc != CKR_OK) { if (new_attr->pValue != NULL) OPENSSL_cleanse(new_attr->pValue, new_attr->ulValueLen); free(new_attr); TRACE_ERROR("dup_attribute_array_no_alloc failed\n"); return rc; } } if (attr->type == CKA_UNIQUE_ID) { if (attr->ulValueLen < 2 * UNIQUE_ID_LEN) { if (new_attr->pValue != NULL) OPENSSL_cleanse(new_attr->pValue, new_attr->ulValueLen); free(new_attr); TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } if (get_unique_id_str(unique_id_str) != CKR_OK) { if (new_attr->pValue != NULL) OPENSSL_cleanse(new_attr->pValue, new_attr->ulValueLen); free(new_attr); TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } memcpy(new_attr->pValue, unique_id_str, 2 * UNIQUE_ID_LEN); new_attr->ulValueLen = 2 * UNIQUE_ID_LEN; } list = dlist_add_as_first(dest->attribute_list, new_attr); if (list == NULL) { if (is_attribute_attr_array(new_attr->type)) cleanse_and_free_attribute_array2( (CK_ATTRIBUTE_PTR)new_attr->pValue, new_attr->ulValueLen / sizeof(CK_ATTRIBUTE), FALSE); if (new_attr->pValue != NULL) OPENSSL_cleanse(new_attr->pValue, new_attr->ulValueLen); free(new_attr); TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); return CKR_HOST_MEMORY; } dest->attribute_list = list; node = node->next; } return CKR_OK; } static CK_BBOOL flatten_ulong_attribute_as_ulong32(CK_ATTRIBUTE_TYPE type) { /* * Note: The attributes mentioned here are by far not all ULONG attribute * types. However, for backward compatibility, we need to keep the list as * is, since previous version of OCK has not flattened the other ULONG * attributes as 32 bit ULONG, but 'as-is', so we need to continue to do so * to not break backward compatibility. */ switch (type) { case CKA_CLASS: case CKA_KEY_TYPE: case CKA_MODULUS_BITS: case CKA_VALUE_BITS: case CKA_CERTIFICATE_TYPE: case CKA_VALUE_LEN: return TRUE; default: return FALSE; } } static CK_RV attribute_array_flatten(CK_ATTRIBUTE_PTR array_attr, CK_BYTE **dest) { CK_ULONG_32 long_len = sizeof(CK_ULONG); CK_ATTRIBUTE_32 attr_32, element_32; CK_ULONG_32 Val_32; CK_ATTRIBUTE attr; CK_BYTE *ptr = *dest; CK_ATTRIBUTE_PTR attrs; CK_ULONG num_attrs, i; CK_RV rc; if (!is_attribute_attr_array(array_attr->type)) return CKR_ATTRIBUTE_TYPE_INVALID; attrs = (CK_ATTRIBUTE_PTR)array_attr->pValue; num_attrs = array_attr->ulValueLen / sizeof(CK_ATTRIBUTE); if (long_len == 4) { attr.type = array_attr->type; attr.ulValueLen = 0; attr.pValue = NULL; for (i = 0; i < num_attrs; i++) attr.ulValueLen += attribute_get_compressed_size(&attrs[i]); memcpy(ptr, &attr, sizeof(CK_ATTRIBUTE)); ptr += sizeof(CK_ATTRIBUTE); for (i = 0; i < num_attrs; i++) { if(is_attribute_attr_array(attrs[i].type)) { rc = attribute_array_flatten(&attrs[i], &ptr); if (rc != CKR_OK) { TRACE_ERROR("attribute_array_flatten failed\n"); return rc; } } else { memcpy(ptr, &attrs[i], sizeof(CK_ATTRIBUTE) + attrs[i].ulValueLen); ptr += sizeof(CK_ATTRIBUTE) + attrs[i].ulValueLen; } } } else { attr_32.type = array_attr->type; attr_32.pValue = 0x00; attr_32.ulValueLen = 0; for (i = 0; i < num_attrs; i++) attr_32.ulValueLen += attribute_get_compressed_size(&attrs[i]); memcpy(ptr, &attr_32, sizeof(CK_ATTRIBUTE_32)); ptr += sizeof(CK_ATTRIBUTE_32); for (i = 0; i < num_attrs; i++) { if(is_attribute_attr_array(attrs[i].type)) { rc = attribute_array_flatten(&attrs[i], &ptr); if (rc != CKR_OK) { TRACE_ERROR("attribute_array_flatten failed\n"); return rc; } } else { element_32.type = attrs[i].type; element_32.pValue = 0x00; if (flatten_ulong_attribute_as_ulong32(attrs[i].type) && attrs[i].ulValueLen != 0) { element_32.ulValueLen = sizeof(CK_ULONG_32); memcpy(ptr, &element_32, sizeof(CK_ATTRIBUTE_32)); ptr += sizeof(CK_ATTRIBUTE_32); Val_32 = (CK_ULONG_32) *((CK_ULONG *) attrs[i].pValue); memcpy(ptr, &Val_32, sizeof(CK_ULONG_32)); ptr += sizeof(CK_ULONG_32); } else { element_32.ulValueLen = attrs[i].ulValueLen; memcpy(ptr, &element_32, sizeof(CK_ATTRIBUTE_32)); ptr += sizeof(CK_ATTRIBUTE_32); if (attrs[i].ulValueLen != 0) { memcpy(ptr, attrs[i].pValue, attrs[i].ulValueLen); ptr += attrs[i].ulValueLen; } } } } } *dest = ptr; 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 = sizeof(CK_ULONG); CK_ATTRIBUTE_32 attr_32; CK_ULONG_32 Val_32; CK_RV rc; 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 (is_attribute_attr_array(attr->type)) { rc = attribute_array_flatten(attr, &ptr); if (rc != CKR_OK) { TRACE_ERROR("attribute_array_flatten failed\n"); return rc; } node = node->next; continue; } if (long_len == 4) { memcpy(ptr, attr, sizeof(CK_ATTRIBUTE) + attr->ulValueLen); ptr += sizeof(CK_ATTRIBUTE) + attr->ulValueLen; } else { attr_32.type = attr->type; attr_32.pValue = 0x00; if (flatten_ulong_attribute_as_ulong32(attr->type) && attr->ulValueLen != 0) { attr_32.ulValueLen = sizeof(CK_ULONG_32); memcpy(ptr, &attr_32, sizeof(CK_ATTRIBUTE_32)); ptr += sizeof(CK_ATTRIBUTE_32); Val_32 = (CK_ULONG_32) *((CK_ULONG *) attr->pValue); 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; } } } node = node->next; } return CKR_OK; } static CK_RV attribute_array_unflatten(CK_BYTE **buf, CK_ULONG buf_len, CK_ATTRIBUTE_PTR *attrs, CK_ULONG *num_attrs) { CK_ULONG_32 long_len = sizeof(CK_ULONG); CK_ATTRIBUTE *a1 = NULL, *a2 = NULL; CK_ATTRIBUTE_32 a1_32, a2_32; CK_BYTE *ptr = *buf; CK_ULONG ofs = 0, num_elements = 0; CK_ATTRIBUTE_PTR elements = NULL; CK_ULONG_32 attr_ulong_32; CK_ULONG attr_ulong; CK_RV rc; *attrs = NULL; *num_attrs = 0; if (long_len == 4) { if (buf_len < sizeof(CK_ATTRIBUTE)) return CKR_FUNCTION_FAILED; a1 = (CK_ATTRIBUTE *)ptr; ptr += sizeof(CK_ATTRIBUTE); buf_len -= sizeof(CK_ATTRIBUTE); if (!is_attribute_attr_array(a1->type)) return CKR_ATTRIBUTE_TYPE_INVALID; if (buf_len < a1->ulValueLen) return CKR_FUNCTION_FAILED; while(ofs < a1->ulValueLen) { if (buf_len < sizeof(CK_ATTRIBUTE)) { rc = CKR_FUNCTION_FAILED; goto error; } a2 = (CK_ATTRIBUTE *)ptr; if (buf_len < sizeof(CK_ATTRIBUTE) + a2->ulValueLen) { rc = CKR_FUNCTION_FAILED; goto error; } if (is_attribute_attr_array(a2->type)) { rc = attribute_array_unflatten(&ptr, sizeof(CK_ATTRIBUTE) + a2->ulValueLen, &elements, &num_elements); if (rc != CKR_OK) { TRACE_ERROR("attribute_array_unflatten failed\n"); goto error; } rc = add_to_attribute_array(attrs, num_attrs, a2->type, (CK_BYTE *)elements, num_elements * sizeof(CK_ATTRIBUTE)); if (rc != CKR_OK) { TRACE_ERROR("attribute_array_unflatten failed\n"); goto error; } cleanse_and_free_attribute_array(elements, num_elements); elements = NULL; num_elements = 0; } else { rc = add_to_attribute_array(attrs, num_attrs, a2->type, ptr + sizeof(CK_ATTRIBUTE), a2->ulValueLen); if (rc != CKR_OK) { TRACE_ERROR("attribute_array_unflatten failed\n"); goto error; } ptr += sizeof(CK_ATTRIBUTE) + a2->ulValueLen; } ofs += sizeof(CK_ATTRIBUTE) + a2->ulValueLen; buf_len -= sizeof(CK_ATTRIBUTE) + a2->ulValueLen; } } else { if (buf_len < sizeof(a1_32)) return CKR_FUNCTION_FAILED; memcpy(&a1_32, ptr, sizeof(a1_32)); ptr += sizeof(CK_ATTRIBUTE_32); buf_len -= sizeof(CK_ATTRIBUTE_32); if (!is_attribute_attr_array(a1_32.type)) return CKR_ATTRIBUTE_TYPE_INVALID; if (buf_len < a1_32.ulValueLen) return CKR_FUNCTION_FAILED; while(ofs < a1_32.ulValueLen) { if (buf_len < sizeof(a2_32)) { rc = CKR_FUNCTION_FAILED; goto error; } memcpy(&a2_32, ptr, sizeof(a2_32)); if (buf_len < sizeof(a2_32) + a2_32.ulValueLen) { rc = CKR_FUNCTION_FAILED; goto error; } if (is_attribute_attr_array(a2_32.type)) { rc = attribute_array_unflatten(&ptr, sizeof(a2_32) + a2_32.ulValueLen, &elements, &num_elements); if (rc != CKR_OK) { TRACE_ERROR("attribute_array_unflatten failed\n"); goto error; } rc = add_to_attribute_array(attrs, num_attrs, a2_32.type, (CK_BYTE *)elements, num_elements * sizeof(CK_ATTRIBUTE)); if (rc != CKR_OK) { TRACE_ERROR("attribute_array_unflatten failed\n"); goto error; } cleanse_and_free_attribute_array(elements, num_elements); elements = NULL; num_elements = 0; } else { if (flatten_ulong_attribute_as_ulong32(a2_32.type) && a2_32.ulValueLen > 0) { if (buf_len < sizeof(a2_32) + sizeof(attr_ulong_32)) { rc = CKR_FUNCTION_FAILED; goto error; } memcpy(&attr_ulong_32, ptr + sizeof(CK_ATTRIBUTE_32), sizeof(attr_ulong_32)); attr_ulong = attr_ulong_32; rc = add_to_attribute_array(attrs, num_attrs, a2_32.type, (CK_BYTE *)&attr_ulong, sizeof(attr_ulong)); } else { rc = add_to_attribute_array(attrs, num_attrs, a2_32.type, ptr + sizeof(CK_ATTRIBUTE_32), a2_32.ulValueLen); } if (rc != CKR_OK) { TRACE_ERROR("attribute_array_unflatten failed\n"); goto error; } ptr += sizeof(CK_ATTRIBUTE_32) + a2_32.ulValueLen; } ofs += sizeof(CK_ATTRIBUTE_32) + a2_32.ulValueLen; buf_len -= sizeof(CK_ATTRIBUTE_32) + a2_32.ulValueLen; } } *buf = ptr; return CKR_OK; error: cleanse_and_free_attribute_array(*attrs, *num_attrs); *attrs = NULL; *num_attrs = 0; cleanse_and_free_attribute_array(elements, num_elements); return rc; } CK_RV template_unflatten_withSize(TEMPLATE **new_tmpl, CK_BYTE *buf, CK_ULONG count, CK_ULONG 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 = NULL; CK_ATTRIBUTE_32 a1_32; CK_ATTRIBUTE_PTR attrs = NULL; CK_ULONG num_attrs = 0; if (!new_tmpl) { 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 (long_len == 4) { if (((ptr + sizeof(CK_ATTRIBUTE)) > (buf + buf_size))) { template_free(tmpl); return CKR_FUNCTION_FAILED; } a1 = (CK_ATTRIBUTE *) ptr; if (is_attribute_attr_array(a1->type)) { if ((ptr + sizeof(CK_ATTRIBUTE) + a1->ulValueLen ) > (buf + buf_size)) { template_free(tmpl); return CKR_FUNCTION_FAILED; } rc = attribute_array_unflatten(&ptr, sizeof(CK_ATTRIBUTE) + a1->ulValueLen, &attrs, &num_attrs); if (rc != CKR_OK) { TRACE_ERROR("attribute_array_unflatten failed\n"); template_free(tmpl); return rc; } len = sizeof(CK_ATTRIBUTE) + num_attrs * sizeof(CK_ATTRIBUTE); a2 = (CK_ATTRIBUTE *) malloc(len); if (!a2) { template_free(tmpl); cleanse_and_free_attribute_array(attrs, num_attrs); TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); return CKR_HOST_MEMORY; } a2->type = a1->type; a2->ulValueLen = num_attrs * sizeof(CK_ATTRIBUTE); if (a2->ulValueLen > 0) { a2->pValue = ((CK_BYTE *)a2) + sizeof(CK_ATTRIBUTE); memcpy(a2->pValue, attrs, a2->ulValueLen); } else { a2->pValue = NULL; } free(attrs); /* Array elements were copied, don't free them! */ goto add_it; } len = sizeof(CK_ATTRIBUTE) + a1->ulValueLen; /* Make sure it doesn't get overrun the input buffer */ if ((((unsigned char *)a1 + len) > (buf + buf_size))) { template_free(tmpl); return CKR_FUNCTION_FAILED; } a2 = (CK_ATTRIBUTE *) malloc(len); if (!a2) { template_free(tmpl); TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); return CKR_HOST_MEMORY; } memcpy(a2, a1, len); if (a2->ulValueLen > 0) a2->pValue = ((CK_BYTE *)a2) + sizeof(CK_ATTRIBUTE); else a2->pValue = NULL; ptr += len; } else { if (((ptr + sizeof(CK_ATTRIBUTE_32)) > (buf + buf_size))) { template_free(tmpl); return CKR_FUNCTION_FAILED; } memcpy(&a1_32, ptr, sizeof(a1_32)); if (is_attribute_attr_array(a1_32.type)) { if ((ptr + sizeof(CK_ATTRIBUTE_32) + a1_32.ulValueLen ) > (buf + buf_size)) { template_free(tmpl); return CKR_FUNCTION_FAILED; } rc = attribute_array_unflatten(&ptr, sizeof(CK_ATTRIBUTE_32) + a1_32.ulValueLen, &attrs, &num_attrs); if (rc != CKR_OK) { TRACE_ERROR("attribute_array_unflatten failed\n"); template_free(tmpl); return rc; } len = sizeof(CK_ATTRIBUTE) + num_attrs * sizeof(CK_ATTRIBUTE); a2 = (CK_ATTRIBUTE *) malloc(len); if (!a2) { template_free(tmpl); cleanse_and_free_attribute_array(attrs, num_attrs); TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); return CKR_HOST_MEMORY; } a2->type = a1_32.type; a2->ulValueLen = num_attrs * sizeof(CK_ATTRIBUTE); if (a2->ulValueLen > 0) { a2->pValue = ((CK_BYTE *)a2) + sizeof(CK_ATTRIBUTE); memcpy(a2->pValue, attrs, a2->ulValueLen); } else { a2->pValue = NULL; } free(attrs); /* Array elements were copied, don't free them! */ goto add_it; } if (flatten_ulong_attribute_as_ulong32(a1_32.type) && a1_32.ulValueLen != 0) { /* Make sure it doesn't get overrun the input buffer */ if ((ptr + sizeof(CK_ATTRIBUTE_32) + sizeof(attr_ulong_32)) > (buf + buf_size)) { template_free(tmpl); return CKR_FUNCTION_FAILED; } len = sizeof(CK_ATTRIBUTE) + sizeof(CK_ULONG); } else { /* Make sure it doesn't get overrun the input buffer */ if ((ptr + sizeof(CK_ATTRIBUTE_32) + a1_32.ulValueLen) > (buf + buf_size)) { template_free(tmpl); return CKR_FUNCTION_FAILED; } len = sizeof(CK_ATTRIBUTE) + a1_32.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_32.type; a2->ulValueLen = 0; if (a1_32.ulValueLen != 0) a2->pValue = (CK_BYTE *)a2 + sizeof(CK_ATTRIBUTE); else a2->pValue = NULL; if (flatten_ulong_attribute_as_ulong32(a1_32.type) && a1_32.ulValueLen != 0) { a2->ulValueLen = sizeof(CK_ULONG); /* Make sure it doesn't get overrun the input buffer */ if ((ptr + sizeof(CK_ATTRIBUTE_32) + sizeof(attr_ulong_32)) > (buf + buf_size)) { free(a2); template_free(tmpl); return CKR_FUNCTION_FAILED; } memcpy(&attr_ulong_32, ptr + sizeof(CK_ATTRIBUTE_32), sizeof(attr_ulong_32)); attr_ulong = attr_ulong_32; memcpy(a2->pValue, (CK_BYTE *)&attr_ulong, sizeof(CK_ULONG)); } else if (a1_32.ulValueLen != 0) { a2->ulValueLen = a1_32.ulValueLen; /* Make sure it doesn't get overrun the input buffer */ if ((ptr + sizeof(CK_ATTRIBUTE_32) + a1_32.ulValueLen) > (buf + buf_size)) { free(a2); template_free(tmpl); return CKR_FUNCTION_FAILED; } memcpy(a2->pValue, ptr + sizeof(CK_ATTRIBUTE_32), a1_32.ulValueLen); } ptr += sizeof(CK_ATTRIBUTE_32) + a1_32.ulValueLen; } add_it: rc = template_update_attribute(tmpl, a2); if (rc != CKR_OK) { if (is_attribute_attr_array(a2->type)) cleanse_and_free_attribute_array2((CK_ATTRIBUTE_PTR)a2->pValue, a2->ulValueLen / sizeof(CK_ATTRIBUTE), FALSE); free(a2); template_free(tmpl); return rc; } } *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) { if (is_attribute_attr_array(attr->type)) { cleanse_and_free_attribute_array2( (CK_ATTRIBUTE_PTR)attr->pValue, attr->ulValueLen / sizeof(CK_ATTRIBUTE), FALSE); } if (attr->pValue != NULL) OPENSSL_cleanse(attr->pValue, attr->ulValueLen); 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 && attr->ulValueLen == sizeof(CK_OBJECT_CLASS) && attr->pValue != NULL) { *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 && attr->ulValueLen == sizeof(CK_CERTIFICATE_TYPE) && attr->pValue != NULL) *subclass = *(CK_CERTIFICATE_TYPE *) attr->pValue; if (attr->type == CKA_KEY_TYPE && attr->ulValueLen == sizeof(CK_KEY_TYPE) && attr->pValue != NULL) *subclass = *(CK_KEY_TYPE *) attr->pValue; if (attr->type == CKA_HW_FEATURE_TYPE && attr->ulValueLen == sizeof(CK_HW_FEATURE_TYPE) && attr->pValue != NULL) *subclass = *(CK_HW_FEATURE_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, i, num_attrs; CK_ATTRIBUTE_PTR attrs; if (tmpl == NULL) return 0; node = tmpl->attribute_list; while (node) { CK_ATTRIBUTE *attr = (CK_ATTRIBUTE *) node->data; size += sizeof(CK_ATTRIBUTE) + attr->ulValueLen; if (is_attribute_attr_array(attr->type)) { num_attrs = attr->ulValueLen / sizeof(CK_ATTRIBUTE); attrs = (CK_ATTRIBUTE_PTR)attr->pValue; for (i = 0; i< num_attrs; i++) size += sizeof(CK_ATTRIBUTE) + attrs[i].ulValueLen; } node = node->next; } return size; } static CK_ULONG attribute_get_compressed_size(CK_ATTRIBUTE_PTR attr) { CK_ULONG size = 0, i, num_attrs; CK_ATTRIBUTE_PTR attrs; size += sizeof(CK_ATTRIBUTE_32); if (flatten_ulong_attribute_as_ulong32(attr->type) && attr->ulValueLen != 0) { size += sizeof(CK_ULONG_32); } else if (is_attribute_attr_array(attr->type)) { num_attrs = attr->ulValueLen / sizeof(CK_ATTRIBUTE); attrs = (CK_ATTRIBUTE_PTR)attr->pValue; for (i = 0; i< num_attrs; i++) size += attribute_get_compressed_size(&attrs[i]); } else { size += attr->ulValueLen; } 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 += attribute_get_compressed_size(attr); 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_ULONG class = 0; CK_ULONG subclass = 0; CK_BBOOL sensitive_val; CK_BBOOL extractable_val; if (!tmpl) return FALSE; /* * Early exit: A protected key shall not be exported. Otherwise an application * could use the protected key outside of this environment and separately * from the secure key object. */ if (type == CKA_IBM_OPAQUE_PKEY) 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; if (template_attribute_get_bool(tmpl, CKA_SENSITIVE, &sensitive_val) != CKR_OK) return FALSE; if (template_attribute_get_bool(tmpl, CKA_EXTRACTABLE, &extractable_val) != CKR_OK) return FALSE; if (sensitive_val == FALSE && extractable_val == TRUE) return TRUE; /* 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_EC: case CKK_EC_EDWARDS: case CKK_EC_MONTGOMERY: return ec_priv_check_exportability(type); case CKK_X9_42_DH: case CKK_DH: return dh_priv_check_exportability(type); case CKK_IBM_DILITHIUM: case CKK_IBM_ML_DSA: return ibm_ml_dsa_priv_check_exportability(type); case CKK_IBM_KYBER: case CKK_IBM_ML_KEM: return ibm_ml_kem_priv_check_exportability(type); case CKK_ML_DSA: return ml_dsa_priv_check_exportability(type); case CKK_ML_KEM: return ml_kem_priv_check_exportability(type); default: TRACE_ERROR("%s: %lx\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID), subclass); return TRUE; } } else if (class == CKO_SECRET_KEY) { return secret_key_check_exportability(type); } TRACE_ERROR("%s: %lx\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID), class); 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: use the value specified in the 'private' argument * CKA_MODIFIABLE: TRUE * CKA_LABEL: empty string */ CK_RV template_set_default_common_attributes(TEMPLATE *tmpl, CK_BBOOL private) { char unique_id_str[2 * UNIQUE_ID_LEN + 1]; CK_ATTRIBUTE *token_attr; CK_ATTRIBUTE *priv_attr; CK_ATTRIBUTE *mod_attr; CK_ATTRIBUTE *label_attr; CK_ATTRIBUTE *unique_id_attr; CK_ATTRIBUTE *copy_attr; CK_ATTRIBUTE *destr_attr; CK_RV rc; if (get_unique_id_str(unique_id_str) != CKR_OK) return CKR_FUNCTION_FAILED; /* 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); unique_id_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + UNIQUE_ID_LEN * 2); copy_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); destr_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); if (!token_attr || !priv_attr || !mod_attr || !label_attr || !unique_id_attr || !copy_attr || !destr_attr) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto error; } 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 = private; 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; unique_id_attr->type = CKA_UNIQUE_ID; unique_id_attr->ulValueLen = UNIQUE_ID_LEN * 2; unique_id_attr->pValue = (CK_BYTE *) unique_id_attr + sizeof(CK_ATTRIBUTE); memcpy(unique_id_attr->pValue, unique_id_str, UNIQUE_ID_LEN * 2); copy_attr->type = CKA_COPYABLE; copy_attr->ulValueLen = sizeof(CK_BBOOL); copy_attr->pValue = (CK_BYTE *) copy_attr + sizeof(CK_ATTRIBUTE); *(CK_BBOOL *) copy_attr->pValue = TRUE; destr_attr->type = CKA_DESTROYABLE; destr_attr->ulValueLen = sizeof(CK_BBOOL); destr_attr->pValue = (CK_BYTE *) destr_attr + sizeof(CK_ATTRIBUTE); *(CK_BBOOL *) destr_attr->pValue = TRUE; rc = template_update_attribute(tmpl, token_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } token_attr = NULL; rc = template_update_attribute(tmpl, priv_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } priv_attr = NULL; rc = template_update_attribute(tmpl, mod_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } mod_attr = NULL; rc = template_update_attribute(tmpl, label_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } label_attr = NULL; rc = template_update_attribute(tmpl, unique_id_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } unique_id_attr = NULL; rc = template_update_attribute(tmpl, copy_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } copy_attr = NULL; rc = template_update_attribute(tmpl, destr_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto error; } destr_attr = NULL; /* the TEMPLATE 'owns' the attributes now. * it is responsible for freeing them upon deletion... */ return CKR_OK; error: if (token_attr) free(token_attr); if (priv_attr) free(priv_attr); if (mod_attr) free(mod_attr); if (label_attr) free(label_attr); if (unique_id_attr) free(unique_id_attr); if (copy_attr) free(copy_attr); if (destr_attr) free(destr_attr); return rc; } /* template_remove_attribute() * * removes an attribute (if existing) from the template. * * Returns: CKR_OK on success, other CKR error on failure */ CK_RV template_remove_attribute(TEMPLATE *tmpl, CK_ATTRIBUTE_TYPE type) { DL_NODE *node = NULL; CK_ATTRIBUTE *attr = NULL; CK_BBOOL found = FALSE; if (!tmpl) { TRACE_ERROR("Invalid function arguments.\n"); return CKR_ARGUMENTS_BAD; } node = tmpl->attribute_list; while (node != NULL) { attr = (CK_ATTRIBUTE *) node->data; if (type == attr->type) { found = TRUE; if (is_attribute_attr_array(attr->type)) { cleanse_and_free_attribute_array2( (CK_ATTRIBUTE_PTR)attr->pValue, attr->ulValueLen / sizeof(CK_ATTRIBUTE), FALSE); } if (attr->pValue != NULL) OPENSSL_cleanse(attr->pValue, attr->ulValueLen); free(attr); tmpl->attribute_list = dlist_remove_node(tmpl->attribute_list, node); break; } node = node->next; } return found ? CKR_OK : CKR_ATTRIBUTE_TYPE_INVALID; } /* template_update_attribute() * * modifies an existing attribute or adds a new attribute to the template * * Returns: CKR_OK on success, other CKR error on failure */ CK_RV template_update_attribute(TEMPLATE *tmpl, CK_ATTRIBUTE *new_attr) { DL_NODE *list; CK_RV rc; if (!tmpl || !new_attr) { TRACE_ERROR("Invalid function arguments.\n"); return CKR_ARGUMENTS_BAD; } /* if the attribute already exists in the list, remove it. * this algorithm will limit an attribute to appearing at most * once in the list */ rc = template_remove_attribute(tmpl, new_attr->type); if (rc != CKR_OK && rc != CKR_ATTRIBUTE_TYPE_INVALID) return rc; /* add the new attribute */ list = dlist_add_as_first(tmpl->attribute_list, new_attr); if (list == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); return CKR_HOST_MEMORY; } tmpl->attribute_list = list; return CKR_OK; } CK_RV template_build_update_attribute(TEMPLATE *tmpl, CK_ATTRIBUTE_TYPE type, CK_BYTE * data, CK_ULONG data_len) { CK_ATTRIBUTE *attr; CK_RV rc; rc = build_attribute(type, data, data_len, &attr); if (rc != CKR_OK) { TRACE_DEVEL("Build attribute for type=%lu failed, rv=0x%lx\n", type, rc); return rc; } rc = template_update_attribute(tmpl, attr); if (rc != CKR_OK) { TRACE_DEVEL("Template update for type=%lu failed, rv=0x%lx\n", type, rc); free(attr); return rc; } 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 (attr->ulValueLen > 0 && attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } 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(tokdata, tmpl, attr, mode); else return cert_vendor_validate_attribute(tokdata, 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_EC: case CKK_EC_EDWARDS: case CKK_EC_MONTGOMERY: return ec_publ_validate_attribute(tokdata, tmpl, attr, mode); case CKK_DH: return dh_publ_validate_attribute(tokdata, tmpl, attr, mode); case CKK_IBM_PQC_DILITHIUM: return ibm_ml_dsa_publ_validate_attribute(tokdata, tmpl, attr, mode, CKM_IBM_DILITHIUM); case CKK_IBM_PQC_KYBER: return ibm_ml_kem_publ_validate_attribute(tokdata, tmpl, attr, mode, CKM_IBM_KYBER); case CKK_IBM_ML_DSA: return ibm_ml_dsa_publ_validate_attribute(tokdata, tmpl, attr, mode, CKM_IBM_ML_DSA); case CKK_IBM_ML_KEM: return ibm_ml_kem_publ_validate_attribute(tokdata, tmpl, attr, mode, CKM_IBM_ML_KEM); case CKK_ML_DSA: return ml_dsa_publ_validate_attribute(tokdata, tmpl, attr, mode); case CKK_ML_KEM: return ml_kem_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_EC: case CKK_EC_EDWARDS: case CKK_EC_MONTGOMERY: return ec_priv_validate_attribute(tokdata, tmpl, attr, mode, subclass); case CKK_DH: return dh_priv_validate_attribute(tokdata, tmpl, attr, mode); case CKK_IBM_PQC_DILITHIUM: return ibm_ml_dsa_priv_validate_attribute(tokdata, tmpl, attr, mode, CKM_IBM_DILITHIUM); case CKK_IBM_PQC_KYBER: return ibm_ml_kem_priv_validate_attribute(tokdata, tmpl, attr, mode, CKM_IBM_KYBER); case CKK_IBM_ML_DSA: return ibm_ml_dsa_priv_validate_attribute(tokdata, tmpl, attr, mode, CKM_IBM_ML_DSA); case CKK_IBM_ML_KEM: return ibm_ml_kem_priv_validate_attribute(tokdata, tmpl, attr, mode, CKM_IBM_ML_KEM); case CKK_ML_DSA: return ml_dsa_priv_validate_attribute(tokdata, tmpl, attr, mode); case CKK_ML_KEM: return ml_kem_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: case CKK_SHA_1_HMAC: case CKK_SHA224_HMAC: case CKK_SHA256_HMAC: case CKK_SHA384_HMAC: case CKK_SHA512_HMAC: case CKK_SHA3_224_HMAC: case CKK_SHA3_256_HMAC: case CKK_SHA3_384_HMAC: case CKK_SHA3_512_HMAC: case CKK_SHA512_224_HMAC: case CKK_SHA512_256_HMAC: return generic_secret_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_AES: return aes_validate_attribute(tokdata, tmpl, attr, mode, FALSE); case CKK_AES_XTS: return aes_validate_attribute(tokdata, tmpl, attr, mode, TRUE); 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; } } else if (class == CKO_PROFILE) { return profile_object_validate_attribute(tmpl, attr, mode); } 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 (attr->ulValueLen != sizeof(CK_OBJECT_CLASS) || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } if ((mode & (MODE_CREATE | MODE_DERIVE | MODE_KEYGEN | MODE_UNWRAP | MODE_ENCAPS | MODE_DECAPS | MODE_EXTRACT)) != 0) return CKR_OK; break; case CKA_TOKEN: if (attr->ulValueLen != sizeof(CK_BBOOL) || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } if ((mode & (MODE_CREATE | MODE_COPY | MODE_DERIVE | MODE_KEYGEN | MODE_UNWRAP | MODE_ENCAPS | MODE_DECAPS | MODE_EXTRACT)) != 0) return CKR_OK; break; case CKA_PRIVATE: if (attr->ulValueLen != sizeof(CK_BBOOL) || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } if ((mode & (MODE_CREATE | MODE_COPY | MODE_DERIVE | MODE_KEYGEN | MODE_UNWRAP | MODE_ENCAPS | MODE_DECAPS | MODE_EXTRACT)) != 0) return CKR_OK; break; case CKA_LABEL: return CKR_OK; case CKA_IBM_OPAQUE: case CKA_IBM_OPAQUE_REENC: case CKA_IBM_OPAQUE_OLD: /* Allow this attribute to be modified in order to support * migratable keys on secure key tokens. */ if ((mode & (MODE_CREATE | MODE_COPY | MODE_MODIFY | MODE_EXTRACT)) != 0) return CKR_OK; break; case CKA_MODIFIABLE: if (attr->ulValueLen != sizeof(CK_BBOOL) || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } /* CKA_MODIFIABLE can only be set on creation and copy */ if ((mode & (MODE_CREATE | MODE_COPY | MODE_DERIVE | MODE_KEYGEN | MODE_UNWRAP | MODE_ENCAPS | MODE_DECAPS | MODE_EXTRACT)) != 0) return CKR_OK; break; case CKA_DESTROYABLE: if (attr->ulValueLen != sizeof(CK_BBOOL) || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } return CKR_OK; case CKA_COPYABLE: /* CKA_COPYABLE can not be set to TRUE once it was set to FALSE */ if (attr->ulValueLen != sizeof(CK_BBOOL) || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } if ((mode & (MODE_CREATE | MODE_DERIVE | MODE_KEYGEN | MODE_UNWRAP | MODE_ENCAPS | MODE_DECAPS | MODE_EXTRACT)) != 0) return CKR_OK; if (attr->pValue != NULL && *(CK_BBOOL *)attr->pValue == FALSE) return CKR_OK; break; case CKA_UNIQUE_ID: break; case CKA_HIDDEN: if ((mode & (MODE_CREATE | MODE_DERIVE | MODE_KEYGEN | MODE_UNWRAP | MODE_ENCAPS | MODE_DECAPS | MODE_EXTRACT)) != 0) return CKR_OK; break; default: TRACE_ERROR("%s: %lx\n", ock_err(ERR_ATTRIBUTE_TYPE_INVALID), attr->type); return CKR_ATTRIBUTE_TYPE_INVALID; } TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); return CKR_ATTRIBUTE_READ_ONLY; } #ifdef DEBUG /* Debug function: dump list of attribues from a template */ void dump_template(TEMPLATE *tmpl) { DL_NODE *node = NULL; CK_ATTRIBUTE *a = NULL; node = tmpl->attribute_list; while (node) { a = (CK_ATTRIBUTE *) node->data; TRACE_DEBUG_DUMPATTR(a); node = node->next; } } #endif opencryptoki-opencryptoki-451d99c/usr/lib/common/tok_spec_struct.h000066400000000000000000000461431520105705100255670ustar00rootroot00000000000000/* * 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 #include "pqc_defs.h" 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]; // Specifies if the token is using secure keys CK_BBOOL secure_key_token; // 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) (STDLL_TokData_t *); // 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); CK_RV (*t_get_token_info) (STDLL_TokData_t *tokdata, CK_TOKEN_INFO_PTR pInfo); // 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 *, TEMPLATE *, CK_BYTE **, CK_ULONG *, CK_ULONG, CK_BBOOL *); CK_RV(*t_des_ecb) (STDLL_TokData_t *, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *, OBJECT *, CK_BYTE); CK_RV(*t_des_cbc) (STDLL_TokData_t *, CK_BYTE *, CK_ULONG, 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_edwards_sign) (STDLL_TokData_t *tokdata, SESSION *, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *, OBJECT *, CK_MECHANISM *); CK_RV(*t_ec_edwards_verify) (STDLL_TokData_t *tokdata, SESSION *, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG, OBJECT *, CK_MECHANISM *); CK_RV(*t_ec_generate_keypair) (STDLL_TokData_t *tokdata, TEMPLATE *, TEMPLATE *); CK_RV(*t_ec_edwards_generate_keypair) (STDLL_TokData_t *tokdata, TEMPLATE *, TEMPLATE *); CK_RV(*t_ec_montgomery_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, CK_BBOOL); CK_RV (*t_ecdh_pkcs_derive_kdf) (STDLL_TokData_t *, SESSION *, OBJECT *, CK_ECDH1_DERIVE_PARAMS *, OBJECT *, CK_ULONG, CK_ULONG, CK_BBOOL); /* 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 shake key derive */ CK_RV (*t_shake_key_derive) (STDLL_TokData_t *, SESSION *, CK_MECHANISM *, OBJECT *, CK_KEY_TYPE, OBJECT *, CK_KEY_TYPE, 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 *, TEMPLATE *, CK_BYTE **, CK_ULONG *, CK_ULONG, CK_BBOOL *); CK_RV(*t_aes_xts_key_gen) (STDLL_TokData_t *, TEMPLATE *, CK_BYTE **, CK_ULONG *, CK_ULONG, CK_BBOOL *); CK_RV(*t_aes_ecb) (STDLL_TokData_t *tokdata, SESSION *, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *, OBJECT *, CK_BYTE); CK_RV(*t_aes_cbc) (STDLL_TokData_t *tokdata, SESSION *, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *, OBJECT *, CK_BYTE *, CK_BYTE); CK_RV(*t_aes_ctr) (STDLL_TokData_t *tokdata, CK_BYTE *, CK_ULONG, 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 *, SESSION *, CK_BYTE *, CK_ULONG, OBJECT *, CK_BYTE *, CK_BBOOL, CK_BBOOL, CK_VOID_PTR *); CK_RV(*t_aes_xts) (STDLL_TokData_t *tokdata, SESSION *, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *, OBJECT *, CK_BYTE *, CK_BBOOL, CK_BBOOL, CK_BBOOL, CK_BYTE*); CK_RV(*t_aes_key_wrap) (STDLL_TokData_t *, SESSION *, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *, OBJECT *, CK_BYTE *, CK_ULONG, CK_BBOOL, CK_BBOOL); // 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 *); // Token Specific PQC functions CK_RV (*t_ibm_ml_dsa_generate_keypair)(STDLL_TokData_t *, CK_MECHANISM *mech, const struct pqc_oid *, TEMPLATE *, TEMPLATE *); CK_RV (*t_ibm_ml_dsa_sign)(STDLL_TokData_t *, SESSION *, CK_BBOOL, const struct pqc_oid *, CK_MECHANISM *, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *, OBJECT *); CK_RV (*t_ibm_ml_dsa_verify)(STDLL_TokData_t *, SESSION *, const struct pqc_oid *, CK_MECHANISM *, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG, OBJECT *); CK_RV (*t_ibm_ml_kem_generate_keypair)(STDLL_TokData_t *, CK_MECHANISM *mech, const struct pqc_oid *, TEMPLATE *, TEMPLATE *); CK_RV (*t_ibm_ml_kem_derive)(STDLL_TokData_t *, SESSION *, const struct pqc_oid *, CK_MECHANISM *, OBJECT *, CK_OBJECT_CLASS, CK_KEY_TYPE, OBJECT *, CK_KEY_TYPE, CK_ULONG); CK_RV (*t_ml_dsa_generate_keypair)(STDLL_TokData_t *, const struct pqc_oid *, TEMPLATE *, TEMPLATE *); CK_RV (*t_ml_dsa_sign)(STDLL_TokData_t *, SESSION *, CK_BBOOL, const struct pqc_oid *, CK_MECHANISM *, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *, OBJECT *, CK_BBOOL); CK_RV (*t_ml_dsa_verify)(STDLL_TokData_t *, SESSION *, const struct pqc_oid *, CK_MECHANISM *, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG, OBJECT *, CK_BBOOL); CK_RV (*t_ml_kem_generate_keypair)(STDLL_TokData_t *, const struct pqc_oid *, TEMPLATE *, TEMPLATE *); CK_RV (*t_ml_kem_encapsulate_key)(STDLL_TokData_t *, SESSION *, CK_BBOOL, const struct pqc_oid *, CK_MECHANISM *, OBJECT *, CK_ATTRIBUTE *, CK_ULONG, CK_BYTE *, CK_ULONG *, CK_KEY_TYPE, CK_ULONG, CK_OBJECT_HANDLE *); CK_RV (*t_ml_kem_decapsulate_key)(STDLL_TokData_t *, SESSION *, const struct pqc_oid *, CK_MECHANISM *, OBJECT *, CK_ATTRIBUTE *, CK_ULONG, CK_BYTE *, CK_ULONG, CK_KEY_TYPE, CK_ULONG, CK_OBJECT_HANDLE *); 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 *); CK_RV(*t_key_wrap) (STDLL_TokData_t *, SESSION *, CK_MECHANISM *, CK_BBOOL, OBJECT *, OBJECT *, CK_BYTE *, CK_ULONG *, CK_BBOOL *); CK_RV(*t_key_unwrap) (STDLL_TokData_t *, SESSION *, CK_MECHANISM *, CK_BYTE *, CK_ULONG, OBJECT *, OBJECT *, CK_BBOOL *); CK_RV(* t_encapsulate_rsa_sym_keygen)(STDLL_TokData_t *, SESSION *, CK_MECHANISM *, CK_ATTRIBUTE *, CK_ULONG, CK_OBJECT_HANDLE *); CK_RV(* t_encapsulate_rsa_key_wrap)(STDLL_TokData_t *, SESSION *, CK_BBOOL, CK_MECHANISM *, CK_OBJECT_HANDLE, CK_OBJECT_HANDLE, CK_BYTE *, CK_ULONG *); CK_RV(* t_encapsulate_rsa_key_unwrap)(STDLL_TokData_t *, SESSION *, CK_MECHANISM *, CK_ATTRIBUTE *, CK_ULONG, CK_BYTE *, CK_ULONG, CK_OBJECT_HANDLE, CK_OBJECT_HANDLE*); CK_RV(* t_encapsulate_dh_ecdh_key_pair_gen)(STDLL_TokData_t *, SESSION *, CK_MECHANISM *, CK_ATTRIBUTE *, CK_ULONG, CK_ATTRIBUTE *, CK_ULONG, CK_OBJECT_HANDLE *, CK_OBJECT_HANDLE *); CK_RV(* t_en_decapsulate_dh_ecdh_derive_key)(STDLL_TokData_t *, SESSION *, CK_MECHANISM *, CK_OBJECT_HANDLE baskey, CK_OBJECT_HANDLE *, CK_ATTRIBUTE *, CK_ULONG, CK_ULONG); CK_RV(*t_reencrypt_single) (STDLL_TokData_t *, SESSION *, ENCR_DECR_CONTEXT *, CK_MECHANISM *, OBJECT *, ENCR_DECR_CONTEXT *, CK_MECHANISM *, OBJECT *, CK_BYTE *, CK_ULONG , CK_BYTE *, CK_ULONG *); CK_RV(*t_set_attribute_values) (STDLL_TokData_t *, SESSION *, OBJECT *, TEMPLATE *); CK_RV(*t_set_attrs_for_new_object) (STDLL_TokData_t *, CK_OBJECT_CLASS, CK_ULONG, TEMPLATE *); CK_RV(*t_handle_event) (STDLL_TokData_t *tokdata, unsigned int event_type, unsigned int event_flags, const char *payload, unsigned int payload_len); CK_RV (*t_check_obj_access) (STDLL_TokData_t *tokdata, OBJECT *obj, CK_BBOOL create); }; typedef struct token_specific_struct token_spec_t; #endif opencryptoki-opencryptoki-451d99c/usr/lib/common/tok_specific.h000066400000000000000000000543561520105705100250230ustar00rootroot00000000000000/* * 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 #include "pqc_defs.h" int token_specific_creatlock(STDLL_TokData_t *); 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_get_token_info(STDLL_TokData_t *tokdata, CK_TOKEN_INFO_PTR pInfo); 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 *, TEMPLATE *tmpl, CK_BYTE **, CK_ULONG *, CK_ULONG, CK_BBOOL *); 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_ec_edwards_sign(STDLL_TokData_t *, SESSION *, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *, OBJECT *, CK_MECHANISM *); CK_RV token_specific_ec_edwards_verify(STDLL_TokData_t *, SESSION *, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG, OBJECT *, CK_MECHANISM *); 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_BBOOL); CK_RV token_specific_ecdh_pkcs_derive_kdf(STDLL_TokData_t *, SESSION *, OBJECT *, CK_ECDH1_DERIVE_PARAMS *, OBJECT *, CK_ULONG, CK_ULONG, CK_BBOOL); 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_ec_edwards_generate_keypair(STDLL_TokData_t *, TEMPLATE *, TEMPLATE *); CK_RV token_specific_ec_montgomery_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_shake_key_derive(STDLL_TokData_t *, SESSION *, CK_MECHANISM *, OBJECT *, CK_KEY_TYPE, OBJECT *, CK_KEY_TYPE, 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); CK_RV token_specific_aes_key_gen(STDLL_TokData_t *, TEMPLATE *tmpl, CK_BYTE **, CK_ULONG *, CK_ULONG, CK_BBOOL *); CK_RV token_specific_aes_xts_key_gen(STDLL_TokData_t *, TEMPLATE *tmpl, CK_BYTE **, CK_ULONG *, CK_ULONG, CK_BBOOL *); CK_RV token_specific_aes_ecb(STDLL_TokData_t *, SESSION *, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *, OBJECT *, CK_BYTE); CK_RV token_specific_aes_cbc(STDLL_TokData_t *, SESSION *, 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 *, SESSION *, CK_BYTE *, CK_ULONG, OBJECT *, CK_BYTE *, CK_BBOOL, CK_BBOOL, CK_VOID_PTR *); CK_RV token_specific_aes_xts(STDLL_TokData_t *, SESSION *, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *, OBJECT *, CK_BYTE *, CK_BBOOL, CK_BBOOL, CK_BBOOL, CK_BYTE*); CK_RV token_specific_aes_key_wrap(STDLL_TokData_t *, SESSION *, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *, OBJECT *, CK_BYTE *, CK_ULONG, CK_BBOOL, CK_BBOOL); 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_ibm_ml_dsa_generate_keypair(STDLL_TokData_t *, CK_MECHANISM *mech, const struct pqc_oid *, TEMPLATE *, TEMPLATE *); CK_RV token_specific_ibm_ml_dsa_sign(STDLL_TokData_t *, SESSION *, CK_BBOOL, const struct pqc_oid *, CK_MECHANISM *, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *, OBJECT *); CK_RV token_specific_ibm_ml_dsa_verify(STDLL_TokData_t *, SESSION *, const struct pqc_oid *, CK_MECHANISM *, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG, OBJECT *); CK_RV token_specific_ibm_ml_kem_generate_keypair(STDLL_TokData_t *, CK_MECHANISM *mech, const struct pqc_oid *, TEMPLATE *, TEMPLATE *); CK_RV token_specific_ibm_ml_kem_derive(STDLL_TokData_t *, SESSION *, const struct pqc_oid *, CK_MECHANISM *, OBJECT *, CK_OBJECT_CLASS, CK_KEY_TYPE, OBJECT *, CK_KEY_TYPE, CK_ULONG); CK_RV token_specific_ml_dsa_generate_keypair(STDLL_TokData_t *, const struct pqc_oid *, TEMPLATE *, TEMPLATE *); CK_RV token_specific_ml_dsa_sign(STDLL_TokData_t *, SESSION *, CK_BBOOL, const struct pqc_oid *, CK_MECHANISM *, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *, OBJECT *, CK_BBOOL); CK_RV token_specific_ml_dsa_verify(STDLL_TokData_t *, SESSION *, const struct pqc_oid *, CK_MECHANISM *, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG, OBJECT *, CK_BBOOL); CK_RV token_specific_ml_kem_generate_keypair(STDLL_TokData_t *, const struct pqc_oid *, TEMPLATE *, TEMPLATE *); CK_RV token_specific_ml_kem_encapsulate_key(STDLL_TokData_t *, SESSION *, CK_BBOOL, const struct pqc_oid *, CK_MECHANISM *, OBJECT *, CK_ATTRIBUTE *, CK_ULONG, CK_BYTE *, CK_ULONG *, CK_KEY_TYPE, CK_ULONG, CK_OBJECT_HANDLE *); CK_RV token_specific_ml_kem_decapsulate_key(STDLL_TokData_t *, SESSION *, const struct pqc_oid *, CK_MECHANISM *, OBJECT *, CK_ATTRIBUTE *, CK_ULONG, CK_BYTE *, CK_ULONG, CK_KEY_TYPE, CK_ULONG, CK_OBJECT_HANDLE *); 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 *); CK_RV token_specific_key_wrap(STDLL_TokData_t *, SESSION *, CK_MECHANISM *, CK_BBOOL, OBJECT *, OBJECT *, CK_BYTE *, CK_ULONG *, CK_BBOOL *); CK_RV token_specific_key_unwrap(STDLL_TokData_t *, SESSION *, CK_MECHANISM *, CK_BYTE *, CK_ULONG, OBJECT *, OBJECT *, CK_BBOOL *); CK_RV token_specific_encapsulate_rsa_sym_keygen(STDLL_TokData_t *, SESSION *, CK_MECHANISM *, CK_ATTRIBUTE *, CK_ULONG, CK_OBJECT_HANDLE *); CK_RV token_specific_encapsulate_rsa_key_wrap(STDLL_TokData_t *, SESSION *, CK_BBOOL, CK_MECHANISM *, CK_OBJECT_HANDLE, CK_OBJECT_HANDLE, CK_BYTE *, CK_ULONG *); CK_RV token_specific_encapsulate_rsa_key_unwrap(STDLL_TokData_t *, SESSION *, CK_MECHANISM *, CK_ATTRIBUTE *, CK_ULONG, CK_BYTE *, CK_ULONG, CK_OBJECT_HANDLE, CK_OBJECT_HANDLE*); CK_RV token_specific_encapsulate_dh_ecdh_key_pair_gen(STDLL_TokData_t *, SESSION *, CK_MECHANISM *, CK_ATTRIBUTE *, CK_ULONG, CK_ATTRIBUTE *, CK_ULONG, CK_OBJECT_HANDLE *, CK_OBJECT_HANDLE *); CK_RV token_specific_en_decapsulate_dh_ecdh_derive_key(STDLL_TokData_t *, SESSION *, CK_MECHANISM *, CK_OBJECT_HANDLE baskey, CK_OBJECT_HANDLE *, CK_ATTRIBUTE *, CK_ULONG, CK_ULONG); CK_RV token_specific_reencrypt_single(STDLL_TokData_t *, SESSION *, ENCR_DECR_CONTEXT *, CK_MECHANISM *, OBJECT *, ENCR_DECR_CONTEXT *, CK_MECHANISM *, OBJECT *, CK_BYTE *, CK_ULONG , CK_BYTE *, CK_ULONG *); CK_RV token_specific_set_attribute_values(STDLL_TokData_t *, SESSION *, OBJECT *, TEMPLATE *); CK_RV token_specific_set_attrs_for_new_object(STDLL_TokData_t *, CK_OBJECT_CLASS, CK_ULONG, TEMPLATE *); CK_RV token_specific_handle_event(STDLL_TokData_t *tokdata, unsigned int event_type, unsigned int event_flags, const char *payload, unsigned int payload_len); CK_RV token_specific_check_obj_access(STDLL_TokData_t *tokdata, OBJECT *obj, CK_BBOOL create); #endif opencryptoki-opencryptoki-451d99c/usr/lib/common/trace.c000066400000000000000000000264671520105705100234540ustar00rootroot00000000000000/* * 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 #include #include #include #include #include #include #include #if !defined(_AIX) #include #else #include #endif #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) #elif !defined(_AIX) #define __gettid() gettid() #else #define __gettid() pthread_self() #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 */ "Async Session Not Supported", /*ERR_SESSION_ASYNC_NOT_SUPPORTED */ "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 >= 0) 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(PKCS_GROUP); if (grp == NULL) { OCK_SYSLOG(LOG_ERR, "getgrnam(%s) failed: %s." "Tracing is disabled.\n", PKCS_GROUP, 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,%s) failed: %s." "Tracing is disabled.\n", tracefile, PKCS_GROUP, strerror(errno)); goto error; } #ifdef PACKAGE_VERSION TRACE_ERROR("**** OCK Trace level %d activated for OCK version %s ****\n", trace.level, PACKAGE_VERSION); #endif return (CKR_OK); error: trace_finalize(); 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]; } #ifdef DEBUG /* a simple function for dumping out a memory area */ void hexdump(const char *prestr, void *buf, size_t buflen) { /* 1 2 3 4 5 6 0123456789012345678901234567890123456789012345678901234567890123456789 xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx ................ */ size_t i, j; char line[68]; for (i = 0; i < buflen; i += 16) { for (j = 0; j < 16; j++) { if (i + j < buflen) { unsigned char b = ((unsigned char *) buf)[i + j]; sprintf(line + j * 3, "%02hhx ", b); line[51 + j] = (isalnum(b) ? b : '.'); } else { sprintf(line + j * 3, " "); line[51 + j] = ' '; } } line[47] = line[48] = line[49] = line[50] = ' '; line[67] = '\0'; if (prestr) TRACE_DEBUG("%s%s\n", prestr, line); else TRACE_DEBUG("%s\n", line); } } #endif /* DEBUG */ opencryptoki-opencryptoki-451d99c/usr/lib/common/trace.h000066400000000000000000000111671520105705100234500ustar00rootroot00000000000000/* * 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 #if defined(__GNUC__) && __GNUC__ >= 7 || defined(__clang__) && __clang_major__ >= 12 #define PRINTF_FORMAT __attribute__ ((format(printf, 5, 6))) #else #define PRINTF_FORMAT #endif #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_SESSION_ASYNC_NOT_SUPPORTED, 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); void trace_finalize(void); void ock_traceit(trace_level_t level, const char *file, int line, const char *stdll_name, const char *fmt, ...) PRINTF_FORMAT; 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 #ifdef DEBUG /* a simple function for dumping out a memory area */ void hexdump(const char *prestr, void *buf, size_t buflen); #define TRACE_DEBUG_DUMP(_prestr, _buf, _buflen) hexdump(_prestr, _buf, _buflen) #else #define TRACE_DEBUG_DUMP(...) #endif #endif opencryptoki-opencryptoki-451d99c/usr/lib/common/uri.c000066400000000000000000000244171520105705100231460ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2022 * * This program is provided under the terms of the Common Public License, * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this * software constitutes recipient's acceptance of CPL-1.0 terms which can be * found in the file LICENSE file or at * https://opensource.org/licenses/cpl1.0.php */ #include #include #include #include #include #include #include #define buffer_get(u) (p11_buffer_t *)(u)->priv #define P11_URI_SEP_PROT ':' #define P11_URI_SEP_ATTR ';' #define P11_URI_SEP_QUERY '&' #define P11_URI_SEP_QUERY_START '?' #define START_END(c, c_max) \ (const CK_CHAR *)(c), \ (const CK_CHAR *)((CK_CHAR *)c + p11_strlen(c, c_max)) #define FORMAT_STRING(sep, txt, s, buf) \ do { \ if (p11_strlen((s), sizeof(s))) { \ p11_buffer_append_len(buf, sep, 1); \ p11_buffer_append(buf, txt); \ p11_url_encode(START_END((s), sizeof(s)), \ P11_URI_P_UNRES, buf); \ *sep = P11_URI_SEP_ATTR; \ } \ } while(0) #define FORMAT_QUERY_CSTRING(sep, txt, s, buf) \ do { \ if (strlen((s))) { \ p11_buffer_append_len(buf, sep, 1); \ p11_buffer_append(buf, txt); \ p11_url_encode((unsigned char *)(s), \ (unsigned char *)(s) + strlen(s), \ P11_URI_Q_UNRES, buf); \ *sep = P11_URI_SEP_QUERY; \ } \ } while(0) #define FORMAT_ATTRIBUTE_STRING(sep, txt, a, t, buf) \ do { \ if (((a)[0].type == (t)) && \ ((a)[0].pValue)) { \ p11_buffer_append_len(buf, sep, 1); \ p11_buffer_append(buf, txt); \ p11_url_encode(START_END((a)[0].pValue, (a)[0].ulValueLen), \ P11_URI_P_UNRES, buf); \ *sep = P11_URI_SEP_ATTR; \ } \ } while(0) #define FORMAT_ATTRIBUTE_ALL(sep, txt, a, t, buf) \ do { \ if (((a)[0].type == (t)) && \ ((a)[0].pValue)) { \ p11_buffer_append_len(buf, sep, 1); \ p11_buffer_append(buf, txt); \ p11_encode(START_END((a)[0].pValue, \ (a)[0].ulValueLen), \ buf); \ *sep = P11_URI_SEP_ATTR; \ } \ } while(0) #define FORMAT_ATTRIBUTE_CLASS(sep, txt, a, buf) \ do { \ if (((a)[0].type == CKA_CLASS) && \ ((a)[0].pValue) && \ (rfc7512_get_cko((a)[0].pValue))) { \ p11_buffer_append_len(buf, sep, 1); \ p11_buffer_append(buf, txt); \ p11_buffer_append(buf, rfc7512_get_cko((a)[0].pValue)); \ *sep = P11_URI_SEP_ATTR; \ } \ } while(0) #define FORMAT_VERSION(sep, txt, v, buf) \ do { \ if (((v).major != (CK_BYTE)-1) || \ ((v).minor != (CK_BYTE)-1)) { \ p11_buffer_append_len(buf, sep, 1); \ p11_buffer_append_printf(buf, txt "%d.%d", \ (v).major, (v).minor); \ *sep = P11_URI_SEP_ATTR; \ } \ } while(0) #define FORMAT_ULONG(sep, txt, ul, buf) \ do { \ if ((ul) != (CK_ULONG)-1) { \ p11_buffer_append_len(buf, sep, 1); \ p11_buffer_append_printf(buf, txt "%lu", ul); \ *sep = P11_URI_SEP_ATTR; \ } \ } while(0) static const char HEX_CHARS_LOWER[] = "0123456789abcdef"; static char *rfc7512_get_cko(CK_OBJECT_CLASS *class) { switch (*class) { case CKO_CERTIFICATE: return "cert"; case CKO_DATA: return "data"; case CKO_PRIVATE_KEY: return "private"; case CKO_PUBLIC_KEY: return "public"; case CKO_SECRET_KEY: return "secret-key"; default: break; } return NULL; } static void p11_encode(const unsigned char *start, const unsigned char *end, p11_buffer_t *buf) { unsigned char hex[3]; if (end <= start) return; while (start != end) { /* encoding required */ hex[0] = '%'; hex[1] = HEX_CHARS_LOWER[(*start) >> 4]; hex[2] = HEX_CHARS_LOWER[(*start) & 0x0F]; p11_buffer_append_len(buf, (const char *)hex, 3); ++start; } } static void p11_url_encode(const unsigned char *start, const unsigned char *end, const char *verbatim, p11_buffer_t *buf) { while (start != end) { if (*start && strchr(verbatim, *start) != NULL) { /* no encoding */ p11_buffer_append_len(buf, (const char *)start, 1); } else { p11_encode(start, start + 1, buf); } ++start; } } static void p11_uri_init(struct p11_uri *uri) { uri->slot_id = (CK_ULONG) - 1; uri->obj_id[0].type = CKA_ID; uri->obj_label[0].type = CKA_LABEL; uri->obj_class[0].type = CKA_CLASS; uri->pin_value = NULL; uri->pin_source = NULL; p11_buffer_reset(buffer_get(uri)); } const char *p11_uri_format(struct p11_uri *uri) { p11_buffer_t *buf; char sep; if (!uri) return NULL; buf = buffer_get(uri); p11_buffer_reset(buf); p11_buffer_append(buf, "pkcs11"); sep = P11_URI_SEP_PROT; /* CK_INFO */ if (uri->info) { FORMAT_STRING(&sep, "library-description=", uri->info->libraryDescription, buf); FORMAT_STRING(&sep, "library-manufacturer=", uri->info->manufacturerID, buf); FORMAT_VERSION(&sep, "library-version=", uri->info->libraryVersion, buf); } FORMAT_ULONG(&sep, "slot-id=", uri->slot_id, buf); /* CK_SLOT_INFO */ if (uri->slot_info) { FORMAT_STRING(&sep, "slot-description=", uri->slot_info->slotDescription, buf); FORMAT_STRING(&sep, "slot-manufacturer=", uri->slot_info->manufacturerID, buf); } /* CK_TOKEN_INFO */ if (uri->token_info) { FORMAT_STRING(&sep, "manufacturer=", uri->token_info->manufacturerID, buf); FORMAT_STRING(&sep, "model=", uri->token_info->model, buf); FORMAT_STRING(&sep, "serial=", uri->token_info->serialNumber, buf); FORMAT_STRING(&sep, "token=", uri->token_info->label, buf); } /* OBJECT */ FORMAT_ATTRIBUTE_ALL(&sep, "id=", uri->obj_id, CKA_ID, buf); FORMAT_ATTRIBUTE_STRING(&sep, "object=", uri->obj_label, CKA_LABEL, buf); FORMAT_ATTRIBUTE_CLASS(&sep, "type=", uri->obj_class, buf); if (uri->pin_value) { sep = P11_URI_SEP_QUERY_START; FORMAT_QUERY_CSTRING(&sep, "pin-value=", uri->pin_value, buf); } else if (uri->pin_source) { sep = P11_URI_SEP_QUERY_START; FORMAT_QUERY_CSTRING(&sep, "pin-source=", uri->pin_source, buf); } /* append the protocol separator for empty URI */ if (sep == P11_URI_SEP_PROT) p11_buffer_append_len(buf, &sep, 1); return p11_buffer_char(buf); } struct p11_uri *p11_uri_new(void) { struct p11_uri *uri; if (!(uri = calloc(1, sizeof(struct p11_uri)))) goto out; if (!(uri->priv = (void *) p11_buffer_new())) goto err; p11_uri_init(uri); out: return uri; err: free(uri); return NULL_PTR; } static void p11_uri_attribute_free(CK_ATTRIBUTE_PTR attr) { if (attr->pValue) free(attr->pValue); attr->pValue = NULL; attr->ulValueLen = 0; } void p11_uri_attributes_free(struct p11_uri *uri) { if (!uri) return; p11_uri_attribute_free(&uri->obj_id[0]); p11_uri_attribute_free(&uri->obj_label[0]); p11_uri_attribute_free(&uri->obj_class[0]); } void p11_uri_free(struct p11_uri *uri) { if (!uri) return; p11_buffer_free((p11_buffer_t *) uri->priv); free(uri); } opencryptoki-opencryptoki-451d99c/usr/lib/common/uri.h000066400000000000000000000017041520105705100231450ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2022 * * This program is provided under the terms of the Common Public License, * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this * software constitutes recipient's acceptance of CPL-1.0 terms which can be * found in the file LICENSE file or at * https://opensource.org/licenses/cpl1.0.php */ #ifndef __URI_H #define __URI_H #include #include struct p11_uri { CK_INFO_PTR info; CK_SLOT_ID slot_id; CK_SLOT_INFO_PTR slot_info; CK_TOKEN_INFO_PTR token_info; CK_ATTRIBUTE obj_id[1]; CK_ATTRIBUTE obj_label[1]; CK_ATTRIBUTE obj_class[1]; char *pin_value; char *pin_source; void *priv; }; const char *p11_uri_format(struct p11_uri *uri); struct p11_uri *p11_uri_new(void); void p11_uri_attributes_free(struct p11_uri *uri); void p11_uri_free(struct p11_uri *uri); #endif /* __URI_H */ opencryptoki-opencryptoki-451d99c/usr/lib/common/uri_enc.h000066400000000000000000000015341520105705100237730ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2022 * * This program is provided under the terms of the Common Public License, * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this * software constitutes recipient's acceptance of CPL-1.0 terms which can be * found in the file LICENSE file or at * https://opensource.org/licenses/cpl1.0.php */ #ifndef __URI_ENC_H #define __URI_ENC_H #define URL_UNRES \ "abcdefghijklmnopqrstuvwxyz" \ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \ "0123456789_-." #define P11_URI_UNRES \ ":[]@!$\'()*+,=" #define P11_URI_P_UNRES \ URL_UNRES \ P11_URI_UNRES \ "&" #define P11_URI_Q_UNRES \ URL_UNRES \ P11_URI_UNRES \ "/?|" #endif /* __URI_ENC_H */ opencryptoki-opencryptoki-451d99c/usr/lib/common/utility.c000066400000000000000000001063651520105705100240550ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2001-2021 * * 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 "p11util.h" #include "attributes.h" #include "tok_spec_struct.h" #include "pkcs32.h" #include "shared_memory.h" #include "trace.h" #include "ock_syslog.h" #include "slotmgr.h" // for ock_snprintf #include #include CK_RV CreateXProcLock(char *tokname, STDLL_TokData_t *tokdata) { char lockfile[PATH_MAX]; char lockdir[PATH_MAX]; struct group *grp; struct stat statbuf; int ret = -1; char *toklockname, *group; group = tokdata->tokgroup; if (group == NULL || group[0] == '\0') group = PKCS_GROUP; if (tokdata->spinxplfd == -1) { if (token_specific.t_creatlock != NULL) { tokdata->spinxplfd = token_specific.t_creatlock(tokdata); if (tokdata->spinxplfd != -1) return CKR_OK; else return CKR_FUNCTION_FAILED; } toklockname = (strlen(tokname) > 0) ? tokname : SUB_DIR; /* * create lock subdir for each token if it doesn't exist. * The root directory should be created in slotmgr daemon */ if (ock_snprintf(lockdir, PATH_MAX, "%s/%s", LOCKDIR_PATH, toklockname) != 0) { OCK_SYSLOG(LOG_ERR, "lock directory path too long\n"); TRACE_ERROR("lock directory path too long\n"); goto err; } grp = getgrnam(group); if (grp == NULL) { OCK_SYSLOG(LOG_ERR, "getgrname(%s): %s\n", group, strerror(errno)); TRACE_ERROR("getgrname(%s): %s\n", group, strerror(errno)); goto err; } 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)); TRACE_ERROR("Directory(%s) missing: %s\n", lockdir, strerror(errno)); goto err; } /* set ownership to euid, and token group */ if (chown(lockdir, geteuid(), grp->gr_gid) != 0) { OCK_SYSLOG(LOG_ERR, "Failed to set owner:group ownership on " "'%s' directory\n", lockdir); TRACE_ERROR("Failed to set owner:group ownership on '%s' " "directory\n", lockdir); goto err; } /* mkdir does not set group permission right, set explicitly here */ if (chmod(lockdir, S_IRWXU | S_IRWXG) != 0) { OCK_SYSLOG(LOG_ERR, "Failed to change permissions on '%s' " "directory\n", lockdir); TRACE_ERROR("Failed to change permissions on '%s' directory\n", lockdir); goto err; } } else if (ret != 0) { OCK_SYSLOG(LOG_ERR, "Could not stat directory '%s': %s\n", lockdir, strerror(errno)); TRACE_ERROR("Could not stat directory '%s': %s\n", lockdir, strerror(errno)); goto err; } else if (statbuf.st_gid != grp->gr_gid) { OCK_SYSLOG(LOG_ERR, "Directory '%s' is not owned by token group " "'%s'\n", lockdir, group); TRACE_ERROR("Directory '%s' is not owned by token group '%s'\n", lockdir, group); goto err; } /* create user lock file */ if (ock_snprintf(lockfile, sizeof(lockfile), "%s/%s/LCK..%s", LOCKDIR_PATH, toklockname, toklockname) != 0) { OCK_SYSLOG(LOG_ERR, "lock file path too long\n"); TRACE_ERROR("lock file path too long\n"); goto err; } if (stat(lockfile, &statbuf) == 0) { tokdata->spinxplfd = open(lockfile, OPEN_MODE); } else { tokdata->spinxplfd = open(lockfile, O_CREAT | OPEN_MODE, MODE_BITS); if (tokdata->spinxplfd != -1) { /* umask may prevent correct mode, so set it. */ if (fchmod(tokdata->spinxplfd, MODE_BITS) == -1) { OCK_SYSLOG(LOG_ERR, "fchmod(%s): %s\n", lockfile, strerror(errno)); TRACE_ERROR("fchmod(%s): %s\n", lockfile, strerror(errno)); goto err; } if (fchown(tokdata->spinxplfd, -1, grp->gr_gid) == -1) { OCK_SYSLOG(LOG_ERR, "fchown(%s): %s\n", lockfile, strerror(errno)); TRACE_ERROR("fchown(%s): %s\n", lockfile, strerror(errno)); goto err; } } } if (tokdata->spinxplfd == -1) { OCK_SYSLOG(LOG_ERR, "open(%s): %s\n", lockfile, strerror(errno)); TRACE_ERROR("open(%s): %s\n", lockfile, strerror(errno)); goto err; } } 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"); pthread_mutex_unlock(&tokdata->spinxplfd_mutex); return CKR_CANT_LOCK; } if (tokdata->spinxplfd_count == 0) { if (flock(tokdata->spinxplfd, LOCK_EX) != 0) { TRACE_DEVEL("flock has failed.\n"); pthread_mutex_unlock(&tokdata->spinxplfd_mutex); return CKR_CANT_LOCK; } } tokdata->spinxplfd_count++; return CKR_OK; } CK_RV XProcUnLock(STDLL_TokData_t *tokdata) { CK_RV rc = CKR_OK; CK_RV rc2; if (tokdata->spinxplfd < 0) { TRACE_DEVEL("No file descriptor to unlock with.\n"); rc = CKR_CANT_LOCK; goto done; } if (tokdata->spinxplfd_count == 0) { TRACE_DEVEL("No file lock is held.\n"); rc = CKR_CANT_LOCK; goto done; } if (tokdata->spinxplfd_count == 1) { if (flock(tokdata->spinxplfd, LOCK_UN) != 0) { TRACE_DEVEL("flock has failed.\n"); rc = CKR_CANT_LOCK; goto done; } } tokdata->spinxplfd_count--; done: rc2 = XThreadUnLock(tokdata); if (rc == CKR_OK && rc2 != CKR_OK) rc = rc2; return rc; } 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 | CKF_USER_PIN_TO_BE_CHANGED | CKF_DUAL_CRYPTO_OPERATIONS; // 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 { 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); rc = compute_PKCS5_PBKDF2_HMAC(tokdata, (CK_BYTE *)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 (rc != CKR_OK) { TRACE_DEVEL("PBKDF2 failed.\n"); return rc; } /* 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); rc = compute_PKCS5_PBKDF2_HMAC(tokdata, (CK_BYTE *)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 (rc != CKR_OK) { TRACE_DEVEL("PBKDF2 failed.\n"); return rc; } /* 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); rc = compute_PKCS5_PBKDF2_HMAC(tokdata, (CK_BYTE *)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 (rc != CKR_OK) { TRACE_DEVEL("PBKDF2 failed.\n"); return rc; } /* 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); rc = compute_PKCS5_PBKDF2_HMAC(tokdata, (CK_BYTE *)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 (rc != CKR_OK) { TRACE_DEVEL("PBKDF2 failed.\n"); return rc; } } // 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; } // // CK_RV build_attribute(CK_ATTRIBUTE_TYPE type, CK_BYTE *data, CK_ULONG data_len, CK_ATTRIBUTE **attrib) { CK_ATTRIBUTE *attr = NULL; CK_RV rc; 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); if (is_attribute_attr_array(type)) { rc = dup_attribute_array_no_alloc((CK_ATTRIBUTE_PTR)data, data_len / sizeof(CK_ATTRIBUTE), (CK_ATTRIBUTE_PTR)attr->pValue); if (rc != CKR_OK) { TRACE_ERROR("dup_attribute_array_no_alloc failed\n"); free(attr); return rc; } } else { 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) || attrs[i].pValue == NULL) return CKR_ATTRIBUTE_VALUE_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) return rc; /* * 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. */ if (get_pk_dir(tokdata, buf, PATH_MAX) == NULL) { TRACE_ERROR("pk_dir buffer overflow"); rc = CKR_FUNCTION_FAILED; goto err; } ret = sm_open(buf, 0660, (void **) shm, sizeof(**shm), 0, tokdata->tokgroup); 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) return rc; 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; } /* Compute specified SHA or MD5 using software */ CK_RV compute_sha(STDLL_TokData_t *tokdata, CK_BYTE *data, CK_ULONG len, CK_BYTE *hash, CK_ULONG mech) { const EVP_MD *md; unsigned int hash_len; UNUSED(tokdata); switch (mech) { case CKM_MD5: hash_len = MD5_HASH_SIZE; md = EVP_md5(); break; case CKM_SHA_1: hash_len = SHA1_HASH_SIZE; md = EVP_sha1(); break; case CKM_SHA224: case CKM_SHA512_224: hash_len = SHA224_HASH_SIZE; md = EVP_sha224(); break; case CKM_SHA256: case CKM_SHA512_256: hash_len = SHA256_HASH_SIZE; md = EVP_sha256(); break; case CKM_SHA384: hash_len = SHA384_HASH_SIZE; md = EVP_sha384(); break; case CKM_SHA512: hash_len = SHA512_HASH_SIZE; md = EVP_sha512(); break; #ifdef NID_sha3_224 case CKM_SHA3_224: case CKM_IBM_SHA3_224: hash_len = SHA3_224_HASH_SIZE; md = EVP_sha3_224(); break; #endif #ifdef NID_sha3_256 case CKM_SHA3_256: case CKM_IBM_SHA3_256: hash_len = SHA3_256_HASH_SIZE; md = EVP_sha3_256(); break; #endif #ifdef NID_sha3_384 case CKM_SHA3_384: case CKM_IBM_SHA3_384: hash_len = SHA3_384_HASH_SIZE; md = EVP_sha3_384(); break; #endif #ifdef NID_sha3_512 case CKM_SHA3_512: case CKM_IBM_SHA3_512: hash_len = SHA3_512_HASH_SIZE; md = EVP_sha3_512(); break; #endif default: return CKR_MECHANISM_INVALID; } if (EVP_Digest(data, len, hash, &hash_len, md, NULL) != 1) { TRACE_ERROR("%s EVP_Digest failed\n", __func__); return CKR_FUNCTION_FAILED; } return CKR_OK; } /* Compute SHA1 using software implementation */ CK_RV compute_sha1(STDLL_TokData_t *tokdata, CK_BYTE *data, CK_ULONG len, CK_BYTE *hash) { CK_RV rc; const CK_MECHANISM mech = { CKM_SHA_1, NULL, 0 }; rc = compute_sha(tokdata, data, len, hash, CKM_SHA_1); if (rc == CKR_OK && (tokdata->statistics->flags & STATISTICS_FLAG_COUNT_INTERNAL) != 0) tokdata->statistics->increment_func(tokdata->statistics, tokdata->slot_id, &mech, POLICY_STRENGTH_IDX_0); return rc; } CK_RV compute_md5(STDLL_TokData_t *tokdata, CK_BYTE *data, CK_ULONG len, CK_BYTE *hash) { CK_RV rc; const CK_MECHANISM mech = { CKM_MD5, NULL, 0 }; rc = compute_sha(tokdata, data, len, hash, CKM_MD5); if (rc == CKR_OK && (tokdata->statistics->flags & STATISTICS_FLAG_COUNT_INTERNAL) != 0) tokdata->statistics->increment_func(tokdata->statistics, tokdata->slot_id, &mech, POLICY_STRENGTH_IDX_0); return rc; } CK_RV compute_PKCS5_PBKDF2_HMAC(STDLL_TokData_t *tokdata, CK_CHAR *pPin, CK_ULONG ulPinLen, CK_BYTE *salt, CK_ULONG salt_len, CK_ULONG it_count, const EVP_MD *digest, CK_ULONG key_len, CK_BYTE *key) { CK_RV rc = CKR_OK; const CK_MECHANISM mech = { CKM_PKCS5_PBKD2, NULL, 0 }; CK_MECHANISM mech2 = { 0, NULL, 0 }; if (PKCS5_PBKDF2_HMAC((char *)pPin, ulPinLen, salt, salt_len, it_count, digest, key_len, key) != 1) { TRACE_DEVEL("PKCS5_PBKDF2_HMAC failed.\n"); rc = CKR_FUNCTION_FAILED; } if (rc == CKR_OK && (tokdata->statistics->flags & STATISTICS_FLAG_COUNT_INTERNAL) != 0) { tokdata->statistics->increment_func(tokdata->statistics, tokdata->slot_id, &mech, POLICY_STRENGTH_IDX_0); if ((tokdata->statistics->flags & STATISTICS_FLAG_COUNT_IMPLICIT) != 0) { /* We use CKM_PKCS5_PBKD2 with CKP_PKCS5_PBKD2_HMAC_SHAxxx */ switch (EVP_MD_type(digest)) { case NID_sha1: mech2.mechanism = CKM_SHA_1_HMAC; break; case NID_sha224: mech2.mechanism = CKM_SHA224_HMAC; break; case NID_sha256: mech2.mechanism = CKM_SHA256_HMAC; break; case NID_sha384: mech2.mechanism = CKM_SHA384_HMAC; break; case NID_sha512: mech2.mechanism = CKM_SHA512_HMAC; break; default: return rc; } /* * Use strength 0 because the HMAC key is the pin, and it is max * 8 char (i.e. 64 bit) long, which is way below 112 bit anyway. */ tokdata->statistics->increment_func(tokdata->statistics, tokdata->slot_id, &mech2, POLICY_STRENGTH_IDX_0); } } return rc; } CK_RV get_keytype(STDLL_TokData_t *tokdata, CK_OBJECT_HANDLE hkey, CK_KEY_TYPE *keytype) { CK_RV rc; OBJECT *key_obj = 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_get_ulong(key_obj->template, CKA_KEY_TYPE, keytype); object_put(tokdata, key_obj, TRUE); key_obj = NULL; return rc; } CK_RV pkcsget_keytype_for_mech(CK_MECHANISM_TYPE mech, CK_KEY_TYPE *keytype, CK_KEY_TYPE *alt_keytype) { *alt_keytype = (CK_KEY_TYPE)-1; switch (mech) { case CKM_DES_KEY_GEN: *keytype = CKK_DES; break; case CKM_DES2_KEY_GEN: case CKM_PBE_SHA1_DES2_EDE_CBC: *keytype = CKK_DES2; break; case CKM_DES3_KEY_GEN: case CKM_PBE_SHA1_DES3_EDE_CBC: *keytype = CKK_DES3; break; case CKM_AES_KEY_GEN: *keytype = CKK_AES; break; case CKM_AES_XTS_KEY_GEN: *keytype = CKK_AES_XTS; break; case CKM_GENERIC_SECRET_KEY_GEN: case CKM_SHAKE_128_KEY_DERIVATION: case CKM_SHAKE_256_KEY_DERIVATION: *keytype = CKK_GENERIC_SECRET; break; case CKM_SHA_1_KEY_GEN: *keytype = CKK_SHA_1_HMAC; break; case CKM_SHA1_KEY_DERIVATION: case CKM_SHA_1_HMAC: case CKM_SHA_1_HMAC_GENERAL: *keytype = CKK_GENERIC_SECRET; *alt_keytype = CKK_SHA_1_HMAC; break; case CKM_SHA224_KEY_GEN: *keytype = CKK_SHA224_HMAC; break; case CKM_SHA224_KEY_DERIVATION: case CKM_SHA224_HMAC: case CKM_SHA224_HMAC_GENERAL: *keytype = CKK_GENERIC_SECRET; *alt_keytype = CKK_SHA224_HMAC; break; case CKM_SHA256_KEY_GEN: *keytype = CKK_SHA256_HMAC; break; case CKM_SHA256_KEY_DERIVATION: case CKM_SHA256_HMAC: case CKM_SHA256_HMAC_GENERAL: *keytype = CKK_GENERIC_SECRET; *alt_keytype = CKK_SHA256_HMAC; break; case CKM_SHA384_KEY_GEN: *keytype = CKK_SHA384_HMAC; break; case CKM_SHA384_KEY_DERIVATION: case CKM_SHA384_HMAC: case CKM_SHA384_HMAC_GENERAL: *keytype = CKK_GENERIC_SECRET; *alt_keytype = CKK_SHA384_HMAC; break; case CKM_SHA512_KEY_GEN: *keytype = CKK_SHA512_HMAC; break; case CKM_SHA512_KEY_DERIVATION: case CKM_SHA512_HMAC: case CKM_SHA512_HMAC_GENERAL: *keytype = CKK_GENERIC_SECRET; *alt_keytype = CKK_SHA512_HMAC; break; case CKM_SHA512_224_KEY_GEN: *keytype = CKK_SHA512_224_HMAC; break; case CKM_SHA512_224_KEY_DERIVATION: case CKM_SHA512_224_HMAC: case CKM_SHA512_224_HMAC_GENERAL: *keytype = CKK_GENERIC_SECRET; *alt_keytype = CKK_SHA512_224_HMAC; break; case CKM_SHA512_256_KEY_GEN: *keytype = CKK_SHA512_256_HMAC; break; case CKM_SHA512_256_KEY_DERIVATION: case CKM_SHA512_256_HMAC: case CKM_SHA512_256_HMAC_GENERAL: *keytype = CKK_GENERIC_SECRET; *alt_keytype = CKK_SHA512_256_HMAC; break; case CKM_SHA3_224_KEY_GEN: *keytype = CKK_SHA3_224_HMAC; break; case CKM_SHA3_224_KEY_DERIVATION: case CKM_SHA3_224_HMAC: case CKM_SHA3_224_HMAC_GENERAL: case CKM_IBM_SHA3_224_HMAC: *keytype = CKK_GENERIC_SECRET; *alt_keytype = CKK_SHA3_224_HMAC; break; case CKM_SHA3_256_KEY_GEN: *keytype = CKK_SHA3_256_HMAC; break; case CKM_SHA3_256_KEY_DERIVATION: case CKM_SHA3_256_HMAC: case CKM_SHA3_256_HMAC_GENERAL: case CKM_IBM_SHA3_256_HMAC: *keytype = CKK_GENERIC_SECRET; *alt_keytype = CKK_SHA3_256_HMAC; break; case CKM_SHA3_384_KEY_GEN: *keytype = CKK_SHA3_384_HMAC; break; case CKM_SHA3_384_KEY_DERIVATION: case CKM_SHA3_384_HMAC: case CKM_SHA3_384_HMAC_GENERAL: case CKM_IBM_SHA3_384_HMAC: *keytype = CKK_GENERIC_SECRET; *alt_keytype = CKK_SHA3_384_HMAC; break; case CKM_SHA3_512_KEY_GEN: *keytype = CKK_SHA3_512_HMAC; break; case CKM_SHA3_512_KEY_DERIVATION: case CKM_SHA3_512_HMAC: case CKM_SHA3_512_HMAC_GENERAL: case CKM_IBM_SHA3_512_HMAC: *keytype = CKK_GENERIC_SECRET; *alt_keytype = CKK_SHA3_512_HMAC; break; case CKM_RSA_PKCS_KEY_PAIR_GEN: case CKM_RSA_X9_31_KEY_PAIR_GEN: *keytype = CKK_RSA; break; case CKM_EC_KEY_PAIR_GEN: *keytype = CKK_EC; break; case CKM_EC_EDWARDS_KEY_PAIR_GEN: *keytype = CKK_EC_EDWARDS; break; case CKM_EC_MONTGOMERY_KEY_PAIR_GEN: *keytype = CKK_EC_MONTGOMERY; break; case CKM_DSA_KEY_PAIR_GEN: *keytype = CKK_DSA; break; case CKM_DH_PKCS_KEY_PAIR_GEN: *keytype = CKK_DH; break; case CKM_IBM_DILITHIUM: *keytype = CKK_IBM_PQC_DILITHIUM; break; case CKM_IBM_KYBER: *keytype = CKK_IBM_PQC_KYBER; break; case CKM_IBM_ML_DSA: case CKM_IBM_ML_DSA_KEY_PAIR_GEN: *keytype = CKK_IBM_ML_DSA; break; case CKM_IBM_ML_KEM: case CKM_IBM_ML_KEM_KEY_PAIR_GEN: case CKM_IBM_ML_KEM_WITH_ECDH: *keytype = CKK_IBM_ML_KEM; break; case CKM_ML_DSA: case CKM_ML_DSA_KEY_PAIR_GEN: case CKM_HASH_ML_DSA: *keytype = CKK_ML_DSA; break; case CKM_ML_KEM: case CKM_ML_KEM_KEY_PAIR_GEN: *keytype = CKK_ML_KEM; break; default: return CKR_MECHANISM_INVALID; } return CKR_OK; } CK_RV pkcs_get_keytype(CK_ATTRIBUTE *attrs, CK_ULONG attrs_len, CK_MECHANISM_PTR mech, CK_KEY_TYPE *type, CK_OBJECT_CLASS *class) { CK_KEY_TYPE alt_keytype; CK_RV rc; *type = 0; *class = 0; rc = get_ulong_attribute_by_type(attrs, attrs_len, CKA_CLASS, class); if (rc == CKR_ATTRIBUTE_VALUE_INVALID) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } rc = get_ulong_attribute_by_type(attrs, attrs_len, CKA_KEY_TYPE, type); if (rc == CKR_ATTRIBUTE_VALUE_INVALID) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } if (rc == CKR_OK) return CKR_OK; /* no CKA_KEY_TYPE found, derive from mech */ return pkcsget_keytype_for_mech(mech->mechanism, type, &alt_keytype); } 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 is set at the API level */ } CK_RV init_hsm_mk_change_lock(STDLL_TokData_t *tokdata) { pthread_rwlockattr_t attr; /* * Request the API layer to lock against HSM-MK-change state changes. * Set lock kind PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP to avoid * writer starvation - but only on Linux. This is a non-portable GNU * extension, with no POSIX mechanism to achieve a similar functionality. * Otherwise in a multi-threaded OCK application * with a heavy crypto workload, the event thread would never get the * HSM-MK-change lock as writer. */ if (pthread_rwlockattr_init(&attr) != 0) { TRACE_ERROR("pthread_rwlockattr_init failed\n"); OCK_SYSLOG(LOG_ERR, "%s: Failed to initialize the HSM-MK-change lock\n", __func__); return CKR_CANT_LOCK; } #if !defined(_AIX) #if _XOPEN_SOURCE >= 500 || _POSIX_C_SOURCE >= 200809L if (pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP) != 0) { TRACE_ERROR("pthread_rwlockattr_setkind_np failed\n"); OCK_SYSLOG(LOG_ERR, "%s: Failed to initialize the HSM-MK-change lock\n", __func__); pthread_rwlockattr_destroy(&attr); return CKR_CANT_LOCK; } #endif /* _XOPEN_SOURCE >= 500 || _POSIX_C_SOURCE >= 200809L */ #endif /* _AIX */ if (pthread_rwlock_init(&tokdata->hsm_mk_change_rwlock, &attr) != 0) { TRACE_ERROR("pthread_rwlock_init failed\n"); OCK_SYSLOG(LOG_ERR, "%s: Failed to initialize the HSM-MK-change lock\n", __func__); pthread_rwlockattr_destroy(&attr); return CKR_CANT_LOCK; } pthread_rwlockattr_destroy(&attr); tokdata->hsm_mk_change_supported = TRUE; return CKR_OK; } opencryptoki-opencryptoki-451d99c/usr/lib/common/utility_common.c000066400000000000000000000254321520105705100254200ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021 * * 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 "pkcs11types.h" #include "defs.h" #include "trace.h" #include "h_extern.h" CK_RV get_sha_size(CK_ULONG mech, CK_ULONG *hsize) { switch (mech) { #if !(NOMD2 ) case CKM_MD2: *hsize = MD2_HASH_SIZE; break; #endif case CKM_MD5: *hsize = MD5_HASH_SIZE; break; 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_SHA3_224: case CKM_IBM_SHA3_224: *hsize = SHA3_224_HASH_SIZE; break; case CKM_SHA3_256: case CKM_IBM_SHA3_256: *hsize = SHA3_256_HASH_SIZE; break; case CKM_SHA3_384: case CKM_IBM_SHA3_384: *hsize = SHA3_384_HASH_SIZE; break; case CKM_SHA3_512: case CKM_IBM_SHA3_512: *hsize = SHA3_512_HASH_SIZE; break; case CKM_OCK_SHAKE128: case CKM_OCK_SHAKE256: *hsize = 0; /* Variable output length */ break; default: return CKR_MECHANISM_INVALID; } return CKR_OK; } CK_RV get_sha_block_size(CK_ULONG mech, CK_ULONG *bsize) { switch (mech) { #if !(NOMD2 ) case CKM_MD2: *bsize = MD2_BLOCK_SIZE; break; #endif case CKM_MD5: *bsize = MD5_BLOCK_SIZE; break; 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_SHA3_224: case CKM_IBM_SHA3_224: *bsize = SHA3_224_BLOCK_SIZE; break; case CKM_SHA3_256: case CKM_IBM_SHA3_256: *bsize = SHA3_256_BLOCK_SIZE; break; case CKM_SHA3_384: case CKM_IBM_SHA3_384: *bsize = SHA3_384_BLOCK_SIZE; break; case CKM_SHA3_512: case CKM_IBM_SHA3_512: *bsize = SHA3_512_BLOCK_SIZE; break; case CKM_OCK_SHAKE128: *bsize = SHAKE128_BLOCK_SIZE; break; case CKM_OCK_SHAKE256: *bsize = SHAKE256_BLOCK_SIZE; break; default: return CKR_MECHANISM_INVALID; } return CKR_OK; } CK_RV get_hmac_digest(CK_ULONG mech, CK_ULONG *digest_mech, CK_BBOOL *general) { switch (mech) { #if !(NOMD2 ) case CKM_MD2_HMAC: case CKM_MD2_HMAC_GENERAL: *digest_mech = CKM_MD2; *general = (mech == CKM_MD2_HMAC_GENERAL); break; #endif case CKM_MD5_HMAC: case CKM_MD5_HMAC_GENERAL: *digest_mech = CKM_MD5; *general = (mech == CKM_MD5_HMAC_GENERAL); break; case CKM_RIPEMD128_HMAC: case CKM_RIPEMD128_HMAC_GENERAL: *digest_mech = CKM_RIPEMD128; *general = (mech == CKM_RIPEMD128_HMAC_GENERAL); break; case CKM_SHA_1_HMAC: case CKM_SHA_1_HMAC_GENERAL: *digest_mech = CKM_SHA_1; *general = (mech == CKM_SHA_1_HMAC_GENERAL); break; case CKM_SHA224_HMAC: case CKM_SHA224_HMAC_GENERAL: *digest_mech = CKM_SHA224; *general = (mech == CKM_SHA224_HMAC_GENERAL); break; case CKM_SHA256_HMAC: case CKM_SHA256_HMAC_GENERAL: *digest_mech = CKM_SHA256; *general = (mech == CKM_SHA256_HMAC_GENERAL); break; case CKM_SHA384_HMAC: case CKM_SHA384_HMAC_GENERAL: *digest_mech = CKM_SHA384; *general = (mech == CKM_SHA384_HMAC_GENERAL); break; case CKM_SHA512_HMAC: case CKM_SHA512_HMAC_GENERAL: *digest_mech = CKM_SHA512; *general = (mech == CKM_SHA512_HMAC_GENERAL); break; case CKM_SHA512_224_HMAC: case CKM_SHA512_224_HMAC_GENERAL: *digest_mech = CKM_SHA512_224; *general = (mech == CKM_SHA512_224_HMAC_GENERAL); break; case CKM_SHA512_256_HMAC: case CKM_SHA512_256_HMAC_GENERAL: *digest_mech = CKM_SHA512_256; *general = (mech == CKM_SHA512_256_HMAC_GENERAL); break; case CKM_SHA3_224_HMAC: case CKM_SHA3_224_HMAC_GENERAL: *digest_mech = CKM_SHA3_224; *general = (mech == CKM_SHA3_224_HMAC_GENERAL); break; case CKM_SHA3_256_HMAC: case CKM_SHA3_256_HMAC_GENERAL: *digest_mech = CKM_SHA3_256; *general = (mech == CKM_SHA3_256_HMAC_GENERAL); break; case CKM_SHA3_384_HMAC: case CKM_SHA3_384_HMAC_GENERAL: *digest_mech = CKM_SHA3_384; *general = (mech == CKM_SHA3_384_HMAC_GENERAL); break; case CKM_SHA3_512_HMAC: case CKM_SHA3_512_HMAC_GENERAL: *digest_mech = CKM_SHA3_512; *general = (mech == CKM_SHA3_512_HMAC_GENERAL); break; case CKM_IBM_SHA3_224_HMAC: *digest_mech = CKM_IBM_SHA3_224; *general = FALSE; break; case CKM_IBM_SHA3_256_HMAC: *digest_mech = CKM_IBM_SHA3_256; *general = FALSE; break; case CKM_IBM_SHA3_384_HMAC: *digest_mech = CKM_IBM_SHA3_384; *general = FALSE; break; case CKM_IBM_SHA3_512_HMAC: *digest_mech = CKM_IBM_SHA3_512; *general = FALSE; break; default: return CKR_MECHANISM_INVALID; } return CKR_OK; } CK_RV digest_from_kdf(CK_EC_KDF_TYPE kdf, CK_MECHANISM_TYPE *mech) { switch (kdf) { case CKD_SHA1_KDF: case CKD_SHA1_KDF_SP800: case CKD_IBM_HYBRID_SHA1_KDF: *mech = CKM_SHA_1; break; case CKD_SHA224_KDF: case CKD_SHA224_KDF_SP800: case CKD_IBM_HYBRID_SHA224_KDF: *mech = CKM_SHA224; break; case CKD_SHA256_KDF: case CKD_SHA256_KDF_SP800: case CKD_IBM_HYBRID_SHA256_KDF: *mech = CKM_SHA256; break; case CKD_SHA384_KDF: case CKD_SHA384_KDF_SP800: case CKD_IBM_HYBRID_SHA384_KDF: *mech = CKM_SHA384; break; case CKD_SHA512_KDF: case CKD_SHA512_KDF_SP800: case CKD_IBM_HYBRID_SHA512_KDF: *mech = CKM_SHA512; break; case CKD_SHA3_224_KDF: case CKD_SHA3_224_KDF_SP800: *mech = CKM_SHA3_224; break; case CKD_SHA3_256_KDF: case CKD_SHA3_256_KDF_SP800: *mech = CKM_SHA3_256; break; case CKD_SHA3_384_KDF: case CKD_SHA3_384_KDF_SP800: *mech = CKM_SHA3_384; break; case CKD_SHA3_512_KDF: case CKD_SHA3_512_KDF_SP800: *mech = CKM_SHA3_512; break; default: TRACE_ERROR("Error unsupported KDF %ld.\n", kdf); return CKR_FUNCTION_FAILED; } return CKR_OK; } CK_RV get_digest_from_mech(CK_MECHANISM_TYPE mech, CK_MECHANISM_TYPE *digest) { switch (mech) { #if !(NOMD2) case CKM_MD2_RSA_PKCS: *digest = CKM_MD2; break; #endif case CKM_MD5_RSA_PKCS: *digest = CKM_MD5; break; case CKM_ECDSA_SHA1: case CKM_SHA1_RSA_PKCS: case CKM_SHA1_RSA_PKCS_PSS: case CKM_SHA1_KEY_DERIVATION: *digest = CKM_SHA_1; break; case CKM_ECDSA_SHA224: case CKM_SHA224_RSA_PKCS: case CKM_SHA224_RSA_PKCS_PSS: case CKM_SHA224_KEY_DERIVATION: case CKM_HASH_ML_DSA_SHA224: *digest = CKM_SHA224; break; case CKM_ECDSA_SHA256: case CKM_SHA256_RSA_PKCS: case CKM_SHA256_RSA_PKCS_PSS: case CKM_SHA256_KEY_DERIVATION: case CKM_HASH_ML_DSA_SHA256: *digest = CKM_SHA256; break; case CKM_ECDSA_SHA384: case CKM_SHA384_RSA_PKCS: case CKM_SHA384_RSA_PKCS_PSS: case CKM_SHA384_KEY_DERIVATION: case CKM_HASH_ML_DSA_SHA384: *digest = CKM_SHA384; break; case CKM_ECDSA_SHA512: case CKM_SHA512_RSA_PKCS: case CKM_SHA512_RSA_PKCS_PSS: case CKM_SHA512_KEY_DERIVATION: case CKM_HASH_ML_DSA_SHA512: *digest = CKM_SHA512; break; case CKM_SHA512_224_KEY_DERIVATION: *digest = CKM_SHA512_224; break; case CKM_SHA512_256_KEY_DERIVATION: *digest = CKM_SHA512_256; break; case CKM_ECDSA_SHA3_224: case CKM_SHA3_224_RSA_PKCS: case CKM_SHA3_224_RSA_PKCS_PSS: case CKM_SHA3_224_KEY_DERIVATION: case CKM_HASH_ML_DSA_SHA3_224: *digest = CKM_SHA3_224; break; case CKM_ECDSA_SHA3_256: case CKM_SHA3_256_RSA_PKCS: case CKM_SHA3_256_RSA_PKCS_PSS: case CKM_SHA3_256_KEY_DERIVATION: case CKM_HASH_ML_DSA_SHA3_256: *digest = CKM_SHA3_256; break; case CKM_ECDSA_SHA3_384: case CKM_SHA3_384_RSA_PKCS: case CKM_SHA3_384_RSA_PKCS_PSS: case CKM_SHA3_384_KEY_DERIVATION: case CKM_HASH_ML_DSA_SHA3_384: *digest = CKM_SHA3_384; break; case CKM_ECDSA_SHA3_512: case CKM_SHA3_512_RSA_PKCS: case CKM_SHA3_512_RSA_PKCS_PSS: case CKM_SHA3_512_KEY_DERIVATION: case CKM_HASH_ML_DSA_SHA3_512: *digest = CKM_SHA3_512; break; case CKM_HASH_ML_DSA_SHAKE128: *digest = CKM_OCK_SHAKE128; break; case CKM_HASH_ML_DSA_SHAKE256: *digest = CKM_OCK_SHAKE256; break; default: return CKR_MECHANISM_INVALID; } return CKR_OK; } /* helper function for rsa-oaep and rsa-pss */ 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; case CKG_MGF1_SHA3_224: *mech = CKM_SHA3_224; break; case CKG_MGF1_SHA3_256: *mech = CKM_SHA3_256; break; case CKG_MGF1_SHA3_384: *mech = CKM_SHA3_384; break; case CKG_MGF1_SHA3_512: *mech = CKM_SHA3_512; break; case CKG_IBM_MGF1_SHA3_224: *mech = CKM_IBM_SHA3_224; break; case CKG_IBM_MGF1_SHA3_256: *mech = CKM_IBM_SHA3_256; break; case CKG_IBM_MGF1_SHA3_384: *mech = CKM_IBM_SHA3_384; break; case CKG_IBM_MGF1_SHA3_512: *mech = CKM_IBM_SHA3_512; break; default: return CKR_MECHANISM_INVALID; } return CKR_OK; } opencryptoki-opencryptoki-451d99c/usr/lib/common/verify_mgr.c000066400000000000000000001623641520105705100245240ustar00rootroot00000000000000/* * 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" #include "../api/policy.h" #include "../api/statistics.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, CK_BBOOL checkpolicy) { OBJECT *key_obj = NULL; CK_ATTRIBUTE *attr = NULL; CK_BYTE *ptr = NULL; CK_KEY_TYPE keytype, exp_keytype, alt_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 (checkpolicy) { rc = tokdata->policy->is_mech_allowed(tokdata->policy, mech, &key_obj->strength, POLICY_CHECK_VERIFY, sess); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: Verify init\n"); goto done; } } if (recover_mode) { // is key allowed to verify signatures where the data can be // recovered from the signature? rc = template_attribute_get_bool(key_obj->template, CKA_VERIFY_RECOVER, &flag); if (rc != CKR_OK) { 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_get_bool(key_obj->template, CKA_VERIFY, &flag); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VERIFY for the key.\n"); rc = CKR_KEY_FUNCTION_NOT_PERMITTED; goto done; } } if (flag != TRUE) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_FUNCTION_NOT_PERMITTED)); rc = CKR_KEY_FUNCTION_NOT_PERMITTED; goto done; } if (!key_object_is_mechanism_allowed(key_obj->template, mech->mechanism)) { TRACE_ERROR("Mechanism not allowed per CKA_ALLOWED_MECHANISMS.\n"); rc = CKR_MECHANISM_INVALID; 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_get_non_empty(key_obj->template, CKA_MODULUS, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VERIFY for the key.\n"); 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_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } 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 // rc = template_attribute_get_ulong(key_obj->template, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); goto done; } 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: case CKM_ECDSA_SHA3_224: case CKM_ECDSA_SHA3_256: case CKM_ECDSA_SHA3_384: case CKM_ECDSA_SHA3_512: if (mech->ulParameterLen != 0) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } rc = template_attribute_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } 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 // rc = template_attribute_get_ulong(key_obj->template, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); goto done; } 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(MP_DIGEST_CONTEXT); ctx->context = (CK_BYTE *) malloc(sizeof(MP_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(MP_DIGEST_CONTEXT)); } break; case CKM_EDDSA: /* Mechanism parameter CK_EDDSA_PARAMS is optional */ if (mech->ulParameterLen != 0 && mech->ulParameterLen != sizeof(CK_EDDSA_PARAMS)) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } rc = template_attribute_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } if (keytype != CKK_EC_EDWARDS) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); rc = CKR_KEY_TYPE_INCONSISTENT; goto done; } // must be a PUBLIC key operation // rc = template_attribute_get_ulong(key_obj->template, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); goto done; } 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 = 0; ctx->context = NULL; 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: case CKM_SHA3_224_RSA_PKCS: case CKM_SHA3_256_RSA_PKCS: case CKM_SHA3_384_RSA_PKCS: case CKM_SHA3_512_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_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } 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 // rc = template_attribute_get_ulong(key_obj->template, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); goto done; } 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(MP_DIGEST_CONTEXT); ctx->context = (CK_BYTE *) malloc(sizeof(MP_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(MP_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: case CKM_SHA3_224_RSA_PKCS_PSS: case CKM_SHA3_256_RSA_PKCS_PSS: case CKM_SHA3_384_RSA_PKCS_PSS: case CKM_SHA3_512_RSA_PKCS_PSS: rc = template_attribute_get_non_empty(key_obj->template, CKA_MODULUS, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); 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_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } 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 // rc = template_attribute_get_ulong(key_obj->template, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); goto done; } 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_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } 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 // rc = template_attribute_get_ulong(key_obj->template, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); goto done; } 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 #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_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } 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: case CKM_SHA3_224_HMAC: case CKM_SHA3_256_HMAC: case CKM_SHA3_384_HMAC: case CKM_SHA3_512_HMAC: case CKM_IBM_SHA3_224_HMAC: case CKM_IBM_SHA3_256_HMAC: case CKM_IBM_SHA3_384_HMAC: case CKM_IBM_SHA3_512_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_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } rc = pkcsget_keytype_for_mech(mech->mechanism, &exp_keytype, &alt_keytype); if (rc != CKR_OK) { TRACE_ERROR("pkcsget_keytype_for_mech failed.\n"); goto done; } if (keytype != exp_keytype && keytype != alt_keytype) { 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; #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) || mech->pParameter == NULL) { 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_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } 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: case CKM_SHA3_224_HMAC_GENERAL: case CKM_SHA3_256_HMAC_GENERAL: case CKM_SHA3_384_HMAC_GENERAL: case CKM_SHA3_512_HMAC_GENERAL: { CK_MAC_GENERAL_PARAMS *param = (CK_MAC_GENERAL_PARAMS *) mech->pParameter; CK_MECHANISM_TYPE digest_mech; CK_BBOOL general; CK_ULONG hsize; if (mech->ulParameterLen != sizeof(CK_MAC_GENERAL_PARAMS) || mech->pParameter == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc= CKR_MECHANISM_PARAM_INVALID; goto done; } rc = get_hmac_digest(mech->mechanism, &digest_mech, &general); if (rc != CKR_OK) { TRACE_ERROR("%s get_hmac_digest failed\n", __func__); goto done; } rc = get_sha_size(digest_mech, &hsize); if (rc != CKR_OK) { TRACE_ERROR("%s get_sha_size failed\n", __func__); goto done; } if (*param > hsize) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } rc = template_attribute_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } rc = pkcsget_keytype_for_mech(mech->mechanism, &exp_keytype, &alt_keytype); if (rc != CKR_OK) { TRACE_ERROR("pkcsget_keytype_for_mech failed.\n"); goto done; } if (keytype != exp_keytype && keytype != alt_keytype) { 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) || mech->pParameter == NULL) { 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_get_ulong(key_obj->template, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); goto done; } 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(MP_DIGEST_CONTEXT); ctx->context = (CK_BYTE *) malloc(sizeof(MP_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(MP_DIGEST_CONTEXT)); } break; case CKM_DES3_MAC: case CKM_DES3_MAC_GENERAL: { if (mech->pParameter) { if (mech->ulParameterLen != sizeof(CK_MAC_GENERAL_PARAMS) || mech->pParameter == NULL) { 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) || mech->pParameter == NULL) { 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) || mech->pParameter == NULL) { 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) || mech->pParameter == NULL) { 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; case CKM_IBM_DILITHIUM: if (mech->ulParameterLen != 0) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } rc = template_attribute_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } if (keytype != CKK_IBM_PQC_DILITHIUM) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); rc = CKR_KEY_TYPE_INCONSISTENT; goto done; } rc = template_attribute_get_ulong(key_obj->template, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); goto done; } 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 = 0; ctx->context = NULL; break; case CKM_IBM_ML_DSA: if (mech->ulParameterLen != 0 && mech->ulParameterLen != sizeof(CK_IBM_SIGN_ADDITIONAL_CONTEXT)) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } if (mech->ulParameterLen == sizeof(CK_IBM_SIGN_ADDITIONAL_CONTEXT) && mech->pParameter == NULL) { rc = CKR_MECHANISM_PARAM_INVALID; goto done; } rc = template_attribute_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } if (keytype != CKK_IBM_ML_DSA) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); rc = CKR_KEY_TYPE_INCONSISTENT; goto done; } rc = template_attribute_get_ulong(key_obj->template, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); goto done; } 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 = 0; ctx->context = NULL; break; case CKM_ML_DSA: case CKM_HASH_ML_DSA: case CKM_HASH_ML_DSA_SHA224: case CKM_HASH_ML_DSA_SHA256: case CKM_HASH_ML_DSA_SHA384: case CKM_HASH_ML_DSA_SHA512: case CKM_HASH_ML_DSA_SHA3_224: case CKM_HASH_ML_DSA_SHA3_256: case CKM_HASH_ML_DSA_SHA3_384: case CKM_HASH_ML_DSA_SHA3_512: case CKM_HASH_ML_DSA_SHAKE128: case CKM_HASH_ML_DSA_SHAKE256: if (mech->mechanism == CKM_HASH_ML_DSA) { if (mech->ulParameterLen != sizeof(CK_HASH_SIGN_ADDITIONAL_CONTEXT) || mech->pParameter == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } } else { if (mech->ulParameterLen != 0 && mech->ulParameterLen != sizeof(CK_SIGN_ADDITIONAL_CONTEXT)) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } if (mech->ulParameterLen == sizeof(CK_SIGN_ADDITIONAL_CONTEXT) && mech->pParameter == NULL) { rc = CKR_MECHANISM_PARAM_INVALID; goto done; } } rc = template_attribute_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } if (keytype != CKK_ML_DSA) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); rc = CKR_KEY_TYPE_INCONSISTENT; goto done; } rc = template_attribute_get_ulong(key_obj->template, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); goto done; } 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_ML_DSA || mech->mechanism == CKM_HASH_ML_DSA) { ctx->context_len = 0; ctx->context = NULL; } else { ctx->context_len = sizeof(MP_DIGEST_CONTEXT); ctx->context = (CK_BYTE *) malloc(sizeof(MP_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(MP_DIGEST_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); /* Deep copy mechanism parameter, if required */ switch (mech->mechanism) { case CKM_IBM_ML_DSA: rc = ibm_ml_dsa_dup_param(mech->pParameter, ptr, mech->ulParameterLen); if (rc != CKR_OK) { TRACE_ERROR("ibm_ml_dsa_dup_param failed\n"); free(ptr); } break; case CKM_ML_DSA: case CKM_HASH_ML_DSA_SHA224: case CKM_HASH_ML_DSA_SHA256: case CKM_HASH_ML_DSA_SHA384: case CKM_HASH_ML_DSA_SHA512: case CKM_HASH_ML_DSA_SHA3_224: case CKM_HASH_ML_DSA_SHA3_256: case CKM_HASH_ML_DSA_SHA3_384: case CKM_HASH_ML_DSA_SHA3_512: case CKM_HASH_ML_DSA_SHAKE128: case CKM_HASH_ML_DSA_SHAKE256: rc = ml_dsa_dup_param(mech->pParameter, ptr, mech->ulParameterLen); if (rc != CKR_OK) { TRACE_ERROR("ml_dsa_dup_param failed\n"); free(ptr); } break; case CKM_HASH_ML_DSA: rc = ml_dsa_hash_dup_param(mech->pParameter, ptr, mech->ulParameterLen); if (rc != CKR_OK) { TRACE_ERROR("ml_dsa_hash_dup_param failed\n"); free(ptr); } break; default: break; } } 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; ctx->pkey_active = FALSE; rc = CKR_OK; done: if (ctx->count_statistics == TRUE && rc == CKR_OK) INC_COUNTER(tokdata, sess, mech, key_obj, POLICY_STRENGTH_IDX_0); object_put(tokdata, key_obj, TRUE); key_obj = NULL; return rc; } // // CK_RV verify_mgr_cleanup(STDLL_TokData_t *tokdata, SESSION *sess, SIGN_VERIFY_CONTEXT *ctx) { if (!ctx) { TRACE_ERROR("Invalid function argument.\n"); return CKR_FUNCTION_FAILED; } ctx->key = 0; ctx->multi_init = FALSE; ctx->multi = FALSE; ctx->active = FALSE; ctx->init_pending = FALSE; ctx->recover = FALSE; ctx->pkey_active = FALSE; ctx->state_unsaveable = FALSE; ctx->count_statistics = FALSE; if (ctx->mech.pParameter) { /* Deep free mechanism parameter, if required */ switch (ctx->mech.mechanism) { case CKM_IBM_ML_DSA: ibm_ml_dsa_free_param(ctx->mech.pParameter, ctx->mech.ulParameterLen); break; case CKM_ML_DSA: case CKM_HASH_ML_DSA_SHA224: case CKM_HASH_ML_DSA_SHA256: case CKM_HASH_ML_DSA_SHA384: case CKM_HASH_ML_DSA_SHA512: case CKM_HASH_ML_DSA_SHA3_224: case CKM_HASH_ML_DSA_SHA3_256: case CKM_HASH_ML_DSA_SHA3_384: case CKM_HASH_ML_DSA_SHA3_512: case CKM_HASH_ML_DSA_SHAKE128: case CKM_HASH_ML_DSA_SHAKE256: ml_dsa_free_param(ctx->mech.pParameter, ctx->mech.ulParameterLen); break; case CKM_HASH_ML_DSA: ml_dsa_hash_free_param(ctx->mech.pParameter, ctx->mech.ulParameterLen); break; default: break; } free(ctx->mech.pParameter); ctx->mech.pParameter = NULL; } ctx->mech.ulParameterLen = 0; if (ctx->context) { /* Cleanup nested contexts if required */ 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: case CKM_SHA3_224_RSA_PKCS: case CKM_SHA3_256_RSA_PKCS: case CKM_SHA3_384_RSA_PKCS: case CKM_SHA3_512_RSA_PKCS: case CKM_ECDSA_SHA1: case CKM_ECDSA_SHA224: case CKM_ECDSA_SHA256: case CKM_ECDSA_SHA384: case CKM_ECDSA_SHA512: case CKM_ECDSA_SHA3_224: case CKM_ECDSA_SHA3_256: case CKM_ECDSA_SHA3_384: case CKM_ECDSA_SHA3_512: case CKM_SSL3_MD5_MAC: case CKM_SSL3_SHA1_MAC: case CKM_HASH_ML_DSA_SHA224: case CKM_HASH_ML_DSA_SHA256: case CKM_HASH_ML_DSA_SHA384: case CKM_HASH_ML_DSA_SHA512: case CKM_HASH_ML_DSA_SHA3_224: case CKM_HASH_ML_DSA_SHA3_256: case CKM_HASH_ML_DSA_SHA3_384: case CKM_HASH_ML_DSA_SHA3_512: case CKM_HASH_ML_DSA_SHAKE128: case CKM_HASH_ML_DSA_SHAKE256: /* Uses MP_DIGEST_CONTEXT as context, contains a DIGEST_CONTEXT */ if (ctx->context_len != sizeof(MP_DIGEST_CONTEXT)) break; digest_mgr_cleanup(tokdata, sess, &((MP_DIGEST_CONTEXT *)ctx->context)->hash_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: case CKM_SHA3_224_RSA_PKCS_PSS: case CKM_SHA3_256_RSA_PKCS_PSS: case CKM_SHA3_384_RSA_PKCS_PSS: case CKM_SHA3_512_RSA_PKCS_PSS: /* Uses DIGEST_CONTEXT as context */ if (ctx->context_len != sizeof(DIGEST_CONTEXT)) break; digest_mgr_cleanup(tokdata, sess, (DIGEST_CONTEXT *)ctx->context); break; default: break; } if (ctx->context_free_func != NULL) ctx->context_free_func(tokdata, sess, ctx->context, ctx->context_len); else free(ctx->context); ctx->context = NULL; } ctx->context_len = 0; ctx->context_free_func = NULL; ctx->mech.mechanism = 0; if (ctx->saved_signature) { free(ctx->saved_signature); ctx->saved_signature = 0; } ctx->saved_signature_len = 0; 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); #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: case CKM_SHA3_224_RSA_PKCS: case CKM_SHA3_256_RSA_PKCS: case CKM_SHA3_384_RSA_PKCS: case CKM_SHA3_512_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: case CKM_SHA3_224_RSA_PKCS_PSS: case CKM_SHA3_256_RSA_PKCS_PSS: case CKM_SHA3_384_RSA_PKCS_PSS: case CKM_SHA3_512_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: 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_SHA3_224_HMAC: case CKM_SHA3_224_HMAC_GENERAL: case CKM_SHA3_256_HMAC: case CKM_SHA3_256_HMAC_GENERAL: case CKM_SHA3_384_HMAC: case CKM_SHA3_384_HMAC_GENERAL: case CKM_SHA3_512_HMAC: case CKM_SHA3_512_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: return sha_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: case CKM_ECDSA_SHA3_224: case CKM_ECDSA_SHA3_256: case CKM_ECDSA_SHA3_384: case CKM_ECDSA_SHA3_512: return ec_hash_verify(tokdata, sess, ctx, in_data, in_data_len, signature, sig_len); case CKM_ECDSA: case CKM_EDDSA: return ec_verify(tokdata, sess, ctx, in_data, in_data_len, signature, sig_len); case CKM_IBM_DILITHIUM: case CKM_IBM_ML_DSA: return ibm_ml_dsa_verify(tokdata, sess, ctx, in_data, in_data_len, signature, sig_len); case CKM_ML_DSA: return ml_dsa_verify(tokdata, sess, ctx, in_data, in_data_len, signature, sig_len, TRUE); case CKM_HASH_ML_DSA: case CKM_HASH_ML_DSA_SHA224: case CKM_HASH_ML_DSA_SHA256: case CKM_HASH_ML_DSA_SHA384: case CKM_HASH_ML_DSA_SHA512: case CKM_HASH_ML_DSA_SHA3_224: case CKM_HASH_ML_DSA_SHA3_256: case CKM_HASH_ML_DSA_SHA3_384: case CKM_HASH_ML_DSA_SHA3_512: case CKM_HASH_ML_DSA_SHAKE128: case CKM_HASH_ML_DSA_SHAKE256: return ml_dsa_hash_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) { #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: case CKM_SHA3_224_RSA_PKCS: case CKM_SHA3_256_RSA_PKCS: case CKM_SHA3_384_RSA_PKCS: case CKM_SHA3_512_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: case CKM_SHA3_224_RSA_PKCS_PSS: case CKM_SHA3_256_RSA_PKCS_PSS: case CKM_SHA3_384_RSA_PKCS_PSS: case CKM_SHA3_512_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: case CKM_ECDSA_SHA3_224: case CKM_ECDSA_SHA3_256: case CKM_ECDSA_SHA3_384: case CKM_ECDSA_SHA3_512: 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: case CKM_SHA3_224_HMAC: case CKM_SHA3_224_HMAC_GENERAL: case CKM_SHA3_256_HMAC: case CKM_SHA3_256_HMAC_GENERAL: case CKM_SHA3_384_HMAC: case CKM_SHA3_384_HMAC_GENERAL: case CKM_SHA3_512_HMAC: case CKM_SHA3_512_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: return hmac_verify_update(tokdata, sess, in_data, in_data_len); case CKM_ML_DSA: return ml_dsa_verify(tokdata, sess, ctx, in_data, in_data_len, ctx->saved_signature, ctx->saved_signature_len, FALSE); case CKM_HASH_ML_DSA_SHA224: case CKM_HASH_ML_DSA_SHA256: case CKM_HASH_ML_DSA_SHA384: case CKM_HASH_ML_DSA_SHA512: case CKM_HASH_ML_DSA_SHA3_224: case CKM_HASH_ML_DSA_SHA3_256: case CKM_HASH_ML_DSA_SHA3_384: case CKM_HASH_ML_DSA_SHA3_512: case CKM_HASH_ML_DSA_SHAKE128: case CKM_HASH_ML_DSA_SHAKE256: return ml_dsa_hash_sign_verify_update(tokdata, sess, ctx, 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 == 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: case CKM_SHA3_224_RSA_PKCS: case CKM_SHA3_256_RSA_PKCS: case CKM_SHA3_384_RSA_PKCS: case CKM_SHA3_512_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: case CKM_SHA3_224_RSA_PKCS_PSS: case CKM_SHA3_256_RSA_PKCS_PSS: case CKM_SHA3_384_RSA_PKCS_PSS: case CKM_SHA3_512_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: case CKM_ECDSA_SHA3_224: case CKM_ECDSA_SHA3_256: case CKM_ECDSA_SHA3_384: case CKM_ECDSA_SHA3_512: 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: case CKM_SHA3_224_HMAC: case CKM_SHA3_224_HMAC_GENERAL: case CKM_SHA3_256_HMAC: case CKM_SHA3_256_HMAC_GENERAL: case CKM_SHA3_384_HMAC: case CKM_SHA3_384_HMAC_GENERAL: case CKM_SHA3_512_HMAC: case CKM_SHA3_512_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: return hmac_verify_final(tokdata, sess, signature, sig_len); case CKM_ML_DSA: return ml_dsa_verify(tokdata, sess, ctx, NULL, 0, signature, sig_len, TRUE); case CKM_HASH_ML_DSA_SHA224: case CKM_HASH_ML_DSA_SHA256: case CKM_HASH_ML_DSA_SHA384: case CKM_HASH_ML_DSA_SHA512: case CKM_HASH_ML_DSA_SHA3_224: case CKM_HASH_ML_DSA_SHA3_256: case CKM_HASH_ML_DSA_SHA3_384: case CKM_HASH_ML_DSA_SHA3_512: case CKM_HASH_ML_DSA_SHAKE128: case CKM_HASH_ML_DSA_SHAKE256: return ml_dsa_hash_verify_final(tokdata, sess, ctx, 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; } opencryptoki-opencryptoki-451d99c/usr/lib/config/000077500000000000000000000000001520105705100221505ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/usr/lib/config/cfglex.l000066400000000000000000000063341520105705100236030ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021 * * 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 */ %{ /* Generic Config Parser */ #include #include #include #include "cfgparse.h" #include "configuration.h" /* Ignore some warnings for autogenerated code. */ #if defined(_AIX) #pragma info (nocmp,noobs,nogen) #else #pragma GCC diagnostic ignored "-Wsign-compare" #endif #define YY_USER_ACTION \ yylloc->first_line = yylloc->last_line; \ yylloc->first_column = yylloc->last_column; \ for(int i = 0; yytext[i] != '\0'; i++) { \ if(yytext[i] == '\n') { \ yylloc->last_line++; \ yylloc->last_column = 0; \ } \ else { \ yylloc->last_column++; \ } \ } #define YYSTYPE CONFIGSTYPE #define YYLTYPE CONFIGLTYPE %} %option reentrant %option noyywrap nounput noinput yylineno stack bison-bridge bison-locations noyy_top_state %option prefix="config" /* Option only relevant if speed is preferred over size. Typically not the case for DSOs. */ /* %option full */ %option warn %option extra-type="int" %option header-file="cfglex.h" %x COMMENT STRING MAIN %% version { yy_push_state(MAIN, yyscanner); return FILEVERSION; } [\t ]+ /* ignore spaces */; \n return EOL;
= return EQUAL;
\{ return BEGIN_DEF;
\} return END_DEF;
\( return BEGIN_LIST;
\) return END_LIST; # yy_push_state(COMMENT, yyscanner);
\" yy_push_state(STRING, yyscanner);
0|[1-9][0-9]* { yylval->num = strtoul(yytext, NULL, 10); return NUMBER; }
0x[0-9a-fA-F]+ { yylval->num = strtoul(yytext, NULL, 16); return NUMBER; }
[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 VERSION_TOK; }
, { return COMMA; }
[a-zA-Z./][a-zA-Z0-9_\-./]* { yylval->str = strdup(yytext); return BARE; } \n { yy_pop_state(yyscanner); return EOL; } [^\n]+ { if (yyextra) { yylval->str = strdup(yytext); return COMMENT_TOK; } } \" yy_pop_state(yyscanner); [^\"]+ { yylval->str = strdup(yytext); return STRING_TOK; } . { yy_push_state(MAIN, yyscanner); yyless(0); } %% opencryptoki-opencryptoki-451d99c/usr/lib/config/cfgparse.y000066400000000000000000000234361520105705100241440ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021 * * 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 */ %{ /* * Generic config file parser. */ #include %} %code requires { #include "configuration.h" typedef void* configscan_t; typedef void (*error_hook_f)(int line, int col, const char *msg); } %code provides { // Tell Flex the expected prototype of yylex. #define YY_DECL \ int configlex (CONFIGSTYPE *yylval_param, CONFIGLTYPE *yylloc_param, configscan_t yyscanner) // Declare the scanner. YY_DECL; static inline void configerror(CONFIGLTYPE *lloc, configscan_t scanner, struct ConfigBaseNode **res, error_hook_f error_hook, int trackComments, const char *msg) { (void)scanner; (void)res; (void)trackComments; if (error_hook) { error_hook(lloc->first_line, lloc->first_column, msg); } } } %union { char *str; unsigned long num; struct ConfigBaseNode *node; } %token EOL EQUAL BEGIN_DEF END_DEF BEGIN_LIST END_LIST COMMA FILEVERSION NUMBER VERSION_TOK BARE COMMENT_TOK STRING_TOK %type configelemstar configelem barelist barelist_ne eoc eocstar eocplus commentedconfigelemstar numpairlist %defines %destructor { free($$); } %destructor { confignode_deepfree($$); } %define api.pure full %locations %define api.prefix {config} %lex-param { configscan_t scanner } %parse-param { configscan_t scanner } %parse-param { struct ConfigBaseNode **res } %parse-param { error_hook_f error_hook } %parse-param { int trackComments } %define parse.trace %define parse.error verbose %define parse.lac full %% /* Parse the whole config file: configfile ::= commentedconfigelem* */ configfile: commentedconfigelemstar { *res = $1; $1 = NULL; } /* Parse configelemstar that might start with an arbitrary number of initial comments. This is used to take care of comments before the first configelem. The rules for configelem take care of comments after the configelem. Since "after configelem i" is "before configelem (i+1)", we cannot add comment tracking to before and after a configelem. So we use this rule to fill the vacant position before the first configelem. */ commentedconfigelemstar : eocstar configelemstar { $$ = confignode_append($1, $2); $1 = $2 = NULL; } /* 0-n configuration elements with comments between them. */ configelemstar: configelem configelemstar { $$ = confignode_append($1, $2); $1 = $2 = NULL; } | /* empty */ { $$ = NULL; } /* Valid configuration elements: - "version" BARE - BARE = NUMBER - BARE = VERSION - BARE = STRING - BARE = BARE - BARE NUMBER { configelemstar } - BARE { configelemstar } - BARE ( barelist ) Special care has to be taken for newlines and comments. They are supported before and after {, }, (, and ), but not before or after = or the special keyword "version". Note: the lexer only emits the FILEVERSION token as first "active" configuration element. You may have an arbitrary number of comments and newlines before, but the first keyword can either be version (in which case it is seen as FILEVERSION and not BARE), or any other BARE to start a different alternative. Every config elem has to end with eocstar to allow an arbitrary number of comments at the end of the element. The element also has to take care of all the positions where it wants to allow comments. */ configelem: /* version somestring*/ FILEVERSION BARE eocstar { struct ConfigFileVersionNode *n = confignode_allocfileversion($2, @1.first_line); if (!n) { YYERROR; } $$ = confignode_append(&(n->base), $3); $2 = NULL; $3 = NULL; } | /* conf = 42 */ BARE EQUAL NUMBER eocstar { struct ConfigIntValNode *n = confignode_allocintval($1, $3, @1.first_line); if (!n) { YYERROR; } $$ = confignode_append(&(n->base), $4); $1 = NULL; $4 = NULL; } | /* conf = 1.0 */ BARE EQUAL VERSION_TOK eocstar { struct ConfigVersionValNode *n = confignode_allocversionval($1, $3, @1.first_line); if (!n) { YYERROR; } $$ = confignode_append(&(n->base), $4); $1 = NULL; $4 = NULL; } | /* conf = "A string" */ BARE EQUAL STRING_TOK eocstar { struct ConfigStringValNode *n = confignode_allocstringval($1, $3, @1.first_line); if (!n) { YYERROR; } $$ = confignode_append(&(n->base), $4); $1 = NULL; $3 = NULL; $4 = NULL; } | /* conf = configuration */ BARE EQUAL BARE eocstar { struct ConfigBareValNode *n = confignode_allocbareval($1, $3, @1.first_line); if (!n) { YYERROR; } $$ = confignode_append(&(n->base), $4); $1 = NULL; $3 = NULL; $4 = NULL; } | /* conf 42 { subconf = 73 } */ BARE NUMBER eocstar BEGIN_DEF commentedconfigelemstar END_DEF eocstar { struct ConfigIdxStructNode *n = confignode_allocidxstruct($1, $2, $3, $5, @1.first_line); if (!n) { YYERROR; } $$ = confignode_append(&(n->base), $7); $1 = NULL; $3 = $5 = $7 = NULL; } | /* conf { subconf = 73 } */ BARE eocstar BEGIN_DEF commentedconfigelemstar END_DEF eocstar { struct ConfigStructNode *n = confignode_allocstruct($1, $2, $4, @1.first_line); if (!n) { YYERROR; } $$ = confignode_append(&(n->base), $6); $1 = NULL; $2 = $4 = $6 = NULL; } | /* conf ( A, B, C ) */ BARE eocstar BEGIN_LIST barelist END_LIST eocstar { struct ConfigBareListNode *n = confignode_allocbarelist($1, $2, $4, @1.first_line); if (!n) { YYERROR; } $$ = confignode_append(&(n->base), $6); $1 = NULL; $2 = $4 = $6 = NULL; } | BARE eocstar { struct ConfigBareConstNode *n = confignode_allocbareconst($1, @1.first_line); if (!n) { YYERROR; } $$ = confignode_append(&(n->base), $2); $1 = NULL; $2 = NULL; } | /* A \n 1 2 B */ BARE eocplus numpairlist BARE eocstar { struct ConfigNumPairListNode *n = confignode_allocnumpairlist($1, $4, $2, $3, @1.first_line); if (!n) { YYERROR; } $$ = confignode_append(&(n->base), $5); $1 = NULL; $2 = NULL; $3 = NULL; $4 = NULL; $5 = NULL; } | STRING_TOK eocstar { struct ConfigBareStringConstNode *n = confignode_allocbarestringconst($1, @1.first_line); if (!n) { YYERROR; } $$ = confignode_append(&(n->base), $2); $1 = NULL; $2 = NULL; } /* A list of number pairs. */ numpairlist: NUMBER NUMBER eocstar { struct ConfigNumPairNode *n = confignode_allocnumpair($1, $2, @1.first_line); if (!n) { YYERROR; } $$ = confignode_append(&(n->base), $3); $3 = NULL; } | NUMBER NUMBER eocstar numpairlist { struct ConfigNumPairNode *n = confignode_allocnumpair($1, $2, @1.first_line); if (!n) { YYERROR; } $$ = confignode_append(&(n->base), confignode_append($3, $4)); $3 = $4 = NULL; } /* A possibly empty list of barewords or comments. Two bare words have to be separated by a comma (see barelist_ne). */ barelist: eocstar { $$ = $1; $1 = NULL; } | eocstar barelist_ne eocstar { $$ = confignode_append($1, confignode_append($2, $3)); $1 = $2 = $3 = NULL; } /* Nonempty list of bare words. If the list contains multiple elements, they are separated by a comma. After a comma you can optionally add as many end-of-line comments as you wish (see eocstar). Note that the list may not end with a comma! */ barelist_ne: BARE COMMA eocstar barelist_ne { struct ConfigBareNode *n = confignode_allocbare($1, @1.first_line); if (!n) { YYERROR; } $1 = NULL; $$ = confignode_append(&n->base, confignode_append($3, $4)); $3 = $4 = NULL; } | BARE { struct ConfigBareNode *n = confignode_allocbare($1, @1.first_line); if (!n) { YYERROR; } $1 = NULL; $$ = &n->base; } /* Either end of line comment or just end of line token. Either way, a line ends with this non-terminal. */ eoc: COMMENT_TOK EOL { if (trackComments) { struct ConfigEOCNode *eocn = confignode_alloceoc($1, @1.first_line); if (!eocn) { YYERROR; }; $1 = NULL; $$ = &eocn->base; } else { $$ = NULL; } } | EOL { if (trackComments) { struct ConfigEOCNode *eocn = confignode_alloceoc(NULL, @1.first_line); if (!eocn) { YYERROR; }; $$ = &eocn->base; } else { $$ = NULL; } } /* BNF form of eoc* */ eocstar: eocplus { $$ = $1; $1 = NULL; } | /* empty */ { $$ = NULL; } /* BNF form of eoc+ */ eocplus: eoc { $$ = $1; $1 = NULL; } | eoc eocplus { $$ = confignode_append($1, $2); $1 = $2 = NULL; } %% #include "cfglex.h" int parse_configlib_file(FILE *conf, struct ConfigBaseNode **res, error_hook_f error_hook, int trackComments) { configscan_t scanner; int ret; configlex_init_extra(trackComments, &scanner); configset_in(conf, scanner); ret = configparse(scanner, res, error_hook, trackComments) ? -1 : 0; configlex_destroy(scanner); return ret; } opencryptoki-opencryptoki-451d99c/usr/lib/config/cfgparser.h000066400000000000000000000012471520105705100243010ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021 * * 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 CFGPARSER_H #define CFGPARSER_H #include #include "configuration.h" typedef void (*error_hook_f)(int line, int col, const char *msg); int parse_configlib_file(FILE *conf, struct ConfigBaseNode **res, error_hook_f error_hook, int trackComments); #endif opencryptoki-opencryptoki-451d99c/usr/lib/config/config.mk000066400000000000000000000020061520105705100237440ustar00rootroot00000000000000noinst_HEADERS += usr/lib/config/configuration.h usr/lib/config/cfglex.h \ usr/lib/config/cfgparse.h usr/lib/config/cfgparser.h EXTRA_DIST += usr/lib/config/cfgparse.y usr/lib/config/cfglex.l BUILT_SOURCES += usr/lib/config/cfglex.c usr/lib/config/cfgparse.c usr/lib/config/cfglex.$(OBJEXT): usr/lib/config/cfgparse.h usr/lib/config/cfgparse.$(OBJEXT): usr/lib/config/cfglex.h usr/lib/config/cfgparse.c: usr/lib/config/cfgparse.y $(AM_V_YACC)$(MKDIR_P) usr/lib/config && $(am__skipyacc) $(SHELL) $(YLWRAP) $< cfgparse.tab.c usr/lib/config/cfgparse.c cfgparse.tab.h usr/lib/config/cfgparse.h cfgparse.output usr/lib/config/cfgparse.output -- $(YACCCOMPILE) usr/lib/config/cfglex.c: usr/lib/config/cfglex.l $(AM_V_LEX)$(MKDIR_P) usr/lib/config && $(am__skiplex) $(SHELL) $(YLWRAP) $< lex.config.c usr/lib/config/cfglex.c cfglex.h usr/lib/config/cfglex.h -- $(LEXCOMPILE) CLEANFILES += usr/lib/config/cfglex.c usr/lib/config/cfglex.h \ usr/lib/config/cfgparse.c usr/lib/config/cfgparse.h \ usr/lib/config/cfgparse.output opencryptoki-opencryptoki-451d99c/usr/lib/config/configuration.c000066400000000000000000000556151520105705100251770ustar00rootroot00000000000000#include "configuration.h" void confignode_deepfree(struct ConfigBaseNode *n) { struct ConfigBaseNode *b, *i, *t; if (n) { b = n; i = n->next; while (i != b) { t = i->next; confignode_free(i); i = t; } confignode_free(n); } } void confignode_free(struct ConfigBaseNode *n) { if (n) { switch (n->type) { case CT_FILEVERSION: confignode_freefileversion(confignode_to_fileversion(n)); break; case CT_INTVAL: confignode_freeintval(confignode_to_intval(n)); break; case CT_STRINGVAL: confignode_freestringval(confignode_to_stringval(n)); break; case CT_VERSIONVAL: confignode_freeversionval(confignode_to_versionval(n)); break; case CT_BAREVAL: confignode_freebareval(confignode_to_bareval(n)); break; case CT_STRUCT: confignode_freestruct(confignode_to_struct(n)); break; case CT_IDX_STRUCT: confignode_freeidxstruct(confignode_to_idxstruct(n)); break; case CT_BARELIST: confignode_freebarelist(confignode_to_barelist(n)); break; case CT_EOC: confignode_freeeoc(confignode_to_eoc(n)); break; case CT_BARE: confignode_freebare(confignode_to_bare(n)); break; case CT_BARECONST: confignode_freebareconst(confignode_to_bareconst(n)); break; case CT_NUMPAIR: confignode_freenumpair(confignode_to_numpair(n)); break; case CT_NUMPAIRLIST: confignode_freenumpairlist(confignode_to_numpairlist(n)); break; case CT_BARESTRINGCONST: confignode_freebarestringconst(confignode_to_barestringconst(n)); break; default: break; } } } static void confignode_dump_indent(FILE *fp, unsigned indent) { unsigned i; for (i = 0; i < indent; ++i) fputc(' ', fp); } static int confignode_dump_i(FILE *fp, struct ConfigBaseNode *n, struct ConfigDumpCb *cb, unsigned flags, unsigned indent, unsigned curindent, unsigned numbares, int curatbol); static void confignode_dumpstruct(FILE *fp, struct ConfigStructNode *n, struct ConfigDumpCb *cb, unsigned flags, unsigned indent, unsigned curindent) { if (n->beforeOpen) { fputs(n->base.key, fp); if (confignode_dump_i(fp, n->beforeOpen, cb, flags, indent, curindent, 0, 0)) confignode_dump_indent(fp, curindent); fputc('{', fp); } else { fprintf(fp, "%s {", n->base.key); } if (n->value) if (confignode_dump_i(fp, n->value, cb, flags, indent, curindent + indent, 0, 0)) confignode_dump_indent(fp, curindent); fputc('}', fp); } static void confignode_dumpidxstruct(FILE *fp, struct ConfigIdxStructNode *n, struct ConfigDumpCb *cb, unsigned flags, unsigned indent, unsigned curindent) { if (n->beforeOpen) { fprintf(fp, "%s %lu", n->base.key, n->idx); if (confignode_dump_i(fp, n->beforeOpen, cb, flags, indent, curindent, 0, 0)) confignode_dump_indent(fp, curindent); fputc('{', fp); } else { fprintf(fp, "%s %lu {", n->base.key, n->idx); } if (n->value) if (confignode_dump_i(fp, n->value, cb, flags, indent, curindent + indent, 0, 0)) confignode_dump_indent(fp, curindent); fputc('}', fp); } static void confignode_dumpbarelist(FILE *fp, struct ConfigBareListNode *n, struct ConfigDumpCb *cb, unsigned flags, unsigned indent, unsigned curindent) { struct ConfigBaseNode *i; unsigned num = 0, braceindent = curindent, valindent = 2; int f; if (n->beforeOpen) { fputs(n->base.key, fp); if (confignode_dump_i(fp, n->beforeOpen, cb, flags, indent, curindent, 0, 0)) { confignode_dump_indent(fp, curindent); valindent = indent; } else { braceindent += strlen(n->base.key) + 1; } fputc('(', fp); } else { fprintf(fp, "%s (", n->base.key); braceindent += strlen(n->base.key) + 1; } if (n->value) { confignode_foreach(i, n->value, f) num += (unsigned) confignode_hastype(i, CT_BARE); if (confignode_dump_i(fp, n->value, cb, flags, indent, braceindent + valindent, num, 0)) confignode_dump_indent(fp, braceindent); } fputc(')', fp); } static void confignode_dumpintval(FILE *fp, struct ConfigIntValNode *n, unsigned flags) { if (flags & CONFIG_FLAG_INT_PRINT_MODE_HEX) fprintf(fp, "%s = 0x%lx", n->base.key, n->value); else fprintf(fp, "%s = %lu", n->base.key, n->value); } static void confignode_dumpnumpair(FILE *fp, struct ConfigNumPairNode *n, unsigned flags) { if (flags & CONFIG_FLAG_INT_PRINT_MODE_HEX) fprintf(fp, "0x%lx 0x%lx", n->value1, n->value2); else fprintf(fp, "%lu %lu", n->value1, n->value2); } static void confignode_dumpnumpairlist(FILE *fp, struct ConfigNumPairListNode *n, struct ConfigDumpCb *cb, unsigned flags, unsigned indent, unsigned curindent) { struct ConfigBaseNode *i; int f, atbol = 1; fputs(n->base.key, fp); if (n->beforeFirst) atbol = confignode_dump_i(fp, n->beforeFirst, cb, flags, indent, curindent, 0, 0); if (!atbol) fputc('\n', fp); if (n->value) { confignode_foreach(i, n->value, f) { switch (i->type) { case CT_NUMPAIR: if (atbol) confignode_dump_indent(fp, curindent + indent); atbol = 0; confignode_dumpnumpair(fp, confignode_to_numpair(i), flags); break; case CT_EOC: if (i->key) { if (atbol) fprintf(fp, "#%s", i->key); else fprintf(fp, " #%s", i->key); } fputc('\n', fp); atbol = 1; break; default: break; } } } if (!atbol) fputc('\n', fp); confignode_dump_indent(fp, curindent); fputs(n->end, fp); } static int confignode_dump_i(FILE *fp, struct ConfigBaseNode *n, struct ConfigDumpCb *cb, unsigned flags, unsigned indent, unsigned curindent, unsigned numbares, int curatbol) { struct ConfigBaseNode *i; int atbol = curatbol, newatbol; i = n; do { newatbol = 0; if (cb) { flags = cb->flags(i, flags); } if (atbol) { confignode_dump_indent(fp, curindent); if (curindent != 0) atbol = 0; } else if (i->type != CT_EOC) { /* In this case, we did not indent, but if a user writes multiple configurations in one line, we will concatenate value of previous item with key of new item producing an invalid configuration. So add a space. */ fputc(' ', fp); } switch (i->type) { case CT_FILEVERSION: fprintf(fp, "version %s", i->key); break; case CT_INTVAL: confignode_dumpintval(fp, confignode_to_intval(i), flags); break; case CT_STRINGVAL: fprintf(fp, "%s = \"%s\"", i->key, confignode_to_stringval(i)->value); break; case CT_VERSIONVAL: fprintf(fp, "%s = %d.%d", i->key, (confignode_to_versionval(i)->value & 0xffff0000) >> 16, confignode_to_versionval(i)->value & 0xffff); break; case CT_BAREVAL: fprintf(fp, "%s = %s", i->key, confignode_to_bareval(i)->value); break; case CT_STRUCT: confignode_dumpstruct(fp, confignode_to_struct(i), cb, flags, indent, curindent); break; case CT_IDX_STRUCT: confignode_dumpidxstruct(fp, confignode_to_idxstruct(i), cb, flags, indent, curindent); break; case CT_BARELIST: confignode_dumpbarelist(fp, confignode_to_barelist(i), cb, flags, indent, curindent); break; case CT_EOC: if (i->key) { if (atbol) fprintf(fp, "#%s", i->key); else fprintf(fp, " #%s", i->key); } fputc('\n', fp); newatbol = 1; break; case CT_BARE: fputs(i->key, fp); if (numbares > 1) { fputc(',', fp); --numbares; } else if (i->next == n) { /* In this case, there is no EOL node after the last element of the list. Put a blank to separate it from the closing bracket. */ fputc(' ', fp); } break; case CT_BARECONST: fputs(i->key, fp); break; case CT_NUMPAIR: if (atbol) confignode_dump_indent(fp, curindent); confignode_dumpnumpair(fp, confignode_to_numpair(i), flags); break; case CT_NUMPAIRLIST: confignode_dumpnumpairlist(fp, confignode_to_numpairlist(i), cb, flags, indent, curindent); newatbol = 1; break; case CT_BARESTRINGCONST: fprintf(fp, "\"%s\"", i->key); break; default: break; } atbol = newatbol; i = i->next; } while (i != n); return atbol; } void confignode_dump(FILE *fp, struct ConfigBaseNode *n, struct ConfigDumpCb *cb, unsigned indent) { if (n) confignode_dump_i(fp, n, cb, 0, indent, 0, 0, 1); } /* dumpable allocations */ struct ConfigFileVersionNode * confignode_allocfileversiondumpable(char *version, int line, char *comment) { struct ConfigFileVersionNode *res; struct ConfigEOCNode *eoc; char *key, *cmt = NULL; key = strdup(version); if (!key) return NULL; if (comment != NULL) { cmt = strdup(comment); if (cmt == NULL) { free(key); return NULL; } } res = confignode_allocfileversion(key, line); if (res) { eoc = confignode_alloceoc(cmt, line); if (eoc) { confignode_append(&(res->base), &(eoc->base)); } else { confignode_freefileversion(res); if (cmt != NULL) free(cmt); res = NULL; } } else { free(key); if (cmt != NULL) free(cmt); } return res; } struct ConfigIntValNode * confignode_allocintvaldumpable(char *key, unsigned long val, int line, char *comment) { struct ConfigIntValNode *res; struct ConfigEOCNode *eoc; char *dkey, *cmt = NULL; dkey = strdup(key); if (!dkey) return NULL; if (comment != NULL) { cmt = strdup(comment); if (cmt == NULL) { free(dkey); return NULL; } } res = confignode_allocintval(dkey, val, line); if (res) { eoc = confignode_alloceoc(cmt, line); if (eoc) { confignode_append(&(res->base), &(eoc->base)); } else { confignode_freeintval(res); if (cmt != NULL) free(cmt); res = NULL; } } else { free(dkey); if (cmt != NULL) free(cmt); } return res; } struct ConfigVersionValNode * confignode_allocversionvaldumpable(char *key, unsigned long val, int line, char *comment) { struct ConfigVersionValNode *res; struct ConfigEOCNode *eoc; char *dkey, *cmt = NULL; dkey = strdup(key); if (!dkey) return NULL; if (comment != NULL) { cmt = strdup(comment); if (cmt == NULL) { free(dkey); return NULL; } } res = confignode_allocversionval(dkey, val, line); if (res) { eoc = confignode_alloceoc(cmt, line); if (eoc) { confignode_append(&(res->base), &(eoc->base)); } else { confignode_freeversionval(res); if (cmt != NULL) free(cmt); res = NULL; } } else { free(dkey); if (cmt != NULL) free(cmt); } return res; } struct ConfigStringValNode * confignode_allocstringvaldumpable(char *key, char *val, int line, char *comment) { struct ConfigStringValNode *res; struct ConfigEOCNode *eoc; char *str, *dkey, *cmt = NULL; dkey = strdup(key); str = strdup(val); if (!str || !dkey) { free(str); free(dkey); return NULL; } if (comment != NULL) { cmt = strdup(comment); if (cmt == NULL) { free(str); free(dkey); return NULL; } } res = confignode_allocstringval(dkey, str, line); if (res) { eoc = confignode_alloceoc(cmt, line); if (eoc) { confignode_append(&(res->base), &(eoc->base)); } else { confignode_freestringval(res); if (cmt != NULL) free(cmt); res = NULL; } } else { free(str); free(dkey); if (cmt != NULL) free(cmt); } return res; } struct ConfigBareValNode * confignode_allocbarevaldumpable(char *key, char *val, int line, char *comment) { struct ConfigBareValNode *res; struct ConfigEOCNode *eoc; char *str, *dkey, *cmt = NULL; dkey = strdup(key); str = strdup(val); if (!str || !dkey) { free(str); free(dkey); return NULL; } if (comment != NULL) { cmt = strdup(comment); if (cmt == NULL) { free(str); free(dkey); return NULL; } } res = confignode_allocbareval(dkey, str, line); if (res) { eoc = confignode_alloceoc(cmt, line); if (eoc) { confignode_append(&(res->base), &(eoc->base)); } else { confignode_freebareval(res); if (cmt != NULL) free(cmt); res = NULL; } } else { free(str); free(dkey); if (cmt != NULL) free(cmt); } return res; } struct ConfigIdxStructNode * confignode_allocidxstructdumpable(char *key, unsigned long num, struct ConfigBaseNode *beforeOpen, struct ConfigBaseNode *value, int line, char *comment) { struct ConfigIdxStructNode *res = NULL; struct ConfigEOCNode *eoc; char *dkey, *cmt = NULL; dkey = strdup(key); if (!dkey) return NULL; if (comment != NULL) { cmt = strdup(comment); if (cmt == NULL) { free(dkey); return NULL; } } /* First allocate eoc node such that if allocating res fails, we do not take ownership of beforeOpen or value. */ eoc = confignode_alloceoc(cmt, line); if (eoc) { res = confignode_allocidxstruct(dkey, num, beforeOpen, value, line); if (res) { confignode_append(&(res->base), &(eoc->base)); } else { confignode_freeeoc(eoc); free(dkey); } } else { free(dkey); if (cmt != NULL) free(cmt); } return res; } struct ConfigStructNode * confignode_allocstructdumpable(char *key, struct ConfigBaseNode *beforeOpen, struct ConfigBaseNode *value, int line, char *comment) { struct ConfigStructNode *res = NULL; struct ConfigEOCNode *eoc; char *dkey, *cmt = NULL; dkey = strdup(key); if (!dkey) return NULL; if (comment != NULL) { cmt = strdup(comment); if (cmt == NULL) { free(dkey); return NULL; } } /* First allocate eoc node such that if allocating res fails, we do not take ownership of beforeOpen or value. */ eoc = confignode_alloceoc(cmt, line); if (eoc) { res = confignode_allocstruct(dkey, beforeOpen, value, line); if (res) { confignode_append(&(res->base), &(eoc->base)); } else { confignode_freeeoc(eoc); free(dkey); } } else { free(dkey); if (cmt != NULL) free(cmt); } return res; } struct ConfigBareListNode * confignode_allocbarelistdumpable(char *key, struct ConfigBaseNode *beforeOpen, struct ConfigBaseNode *value, int line, char *comment) { struct ConfigBareListNode *res = NULL; struct ConfigEOCNode *eoc; char *dkey, *cmt = NULL; dkey = strdup(key); if (!dkey) return NULL; if (comment != NULL) { cmt = strdup(comment); if (cmt == NULL) { free(dkey); return NULL; } } /* First allocate eoc node such that if allocating res fails, we do not take ownership of beforeOpen or value. */ eoc = confignode_alloceoc(cmt, line); if (eoc) { res = confignode_allocbarelist(dkey, beforeOpen, value, line); if (res) { confignode_append(&(res->base), &(eoc->base)); } else { confignode_freeeoc(eoc); free(dkey); } } else { free(dkey); if (cmt != NULL) free(cmt); } return res; } struct ConfigBareNode * confignode_allocbaredumpable(char *bareval, int line, char *comment) { struct ConfigBareNode *res; struct ConfigEOCNode *eoc; char *dkey, *cmt = NULL; dkey = strdup(bareval); if (!dkey) return NULL; if (comment != NULL) { cmt = strdup(comment); if (cmt == NULL) { free(dkey); return NULL; } } res = confignode_allocbare(dkey, line); if (res) { eoc = confignode_alloceoc(cmt, line); if (eoc) { confignode_append(&(res->base), &(eoc->base)); } else { confignode_freebare(res); if (cmt != NULL) free(cmt); res = NULL; } } else { free(dkey); if (cmt != NULL) free(cmt); } return res; } struct ConfigBareConstNode * confignode_allocbareconstdumpable(char *key, int line, char *comment) { struct ConfigBareConstNode *res; struct ConfigEOCNode *eoc; char *dkey, *cmt = NULL; dkey = strdup(key); if (!dkey) return NULL; if (comment != NULL) { cmt = strdup(comment); if (cmt == NULL) { free(dkey); return NULL; } } res = confignode_allocbareconst(dkey, line); if (res) { eoc = confignode_alloceoc(cmt, line); if (eoc) { confignode_append(&(res->base), &(eoc->base)); } else { confignode_freebareconst(res); if (cmt != NULL) free(cmt); res = NULL; } } else { free(dkey); if (cmt != NULL) free(cmt); } return res; } struct ConfigNumPairNode * confignode_allocnumpairdumpable(unsigned long value1, unsigned long value2, int line, char *comment) { struct ConfigNumPairNode *res; struct ConfigEOCNode *eoc; char *cmt = NULL; if (comment != NULL) { cmt = strdup(comment); if (cmt == NULL) return NULL; } res = confignode_allocnumpair(value1, value2, line); if (res) { eoc = confignode_alloceoc(cmt, line); if (eoc) { confignode_append(&(res->base), &(eoc->base)); } else { confignode_freenumpair(res); if (cmt != NULL) free(cmt); res = NULL; } } else { if (cmt != NULL) free(cmt); } return res; } struct ConfigNumPairListNode * confignode_allocnumpairlistdumpable(char *key, char* end, struct ConfigBaseNode *beforeFirst, struct ConfigBaseNode *value, int line, char *comment) { struct ConfigNumPairListNode *res = NULL; struct ConfigEOCNode *eoc; char *dkey, *dend, *cmt = NULL; dkey = strdup(key); if (!dkey) return NULL; dend = strdup(end); if (!dend) { free(dkey); return NULL; } if (comment != NULL) { cmt = strdup(comment); if (cmt == NULL) { free(dkey); free(dend); return NULL; } } /* First allocate eoc node such that if allocating res fails, we do not take ownership of beforeOpen or value. */ eoc = confignode_alloceoc(cmt, line); if (eoc) { res = confignode_allocnumpairlist(dkey, dend, beforeFirst, value, line); if (res) { confignode_append(&(res->base), &(eoc->base)); } else { confignode_freeeoc(eoc); free(dkey); free(dend); } } else { free(dkey); free(dend); if (cmt != NULL) free(cmt); } return res; } struct ConfigBareStringConstNode * confignode_allocbarestringconstdumpable(char *key, int line, char *comment) { struct ConfigBareStringConstNode *res; struct ConfigEOCNode *eoc; char *cmt = NULL; if (comment != NULL) { cmt = strdup(comment); if (cmt == NULL) return NULL; } res = confignode_allocbarestringconst(key, line); if (res) { eoc = confignode_alloceoc(cmt, line); if (eoc) { confignode_append(&(res->base), &(eoc->base)); } else { confignode_freebarestringconst(res); if (cmt != NULL) free(cmt); res = NULL; } } else { if (cmt != NULL) free(cmt); } return res; } opencryptoki-opencryptoki-451d99c/usr/lib/config/configuration.h000066400000000000000000000536161520105705100252030ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021 * * 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 CONFIGURATION_H #define CONFIGURATION_H #include #include #include #include #include #define MAJOR_FROM_VERSION(V) (((V) >> 16) & 0xffu) #define MINOR_FROM_VERSION(V) ((V) & 0xffu) /* * A file version node. */ #define CT_FILEVERSION (1u << 0u) /* * key=value with unsigned long value. */ #define CT_INTVAL (1u << 1u) /* * key=value with string value. */ #define CT_STRINGVAL (1u << 2u) /* * key=value with version value (packed as a 16/16 bit unsigned integer). */ #define CT_VERSIONVAL (1u << 3u) /* * key=value with bare string value. */ #define CT_BAREVAL (1u << 4u) /* * Structure value. */ #define CT_STRUCT (1u << 5u) /* * Indexed structure value. */ #define CT_IDX_STRUCT (1u << 6u) /* * Bare list. List contains bare values. */ #define CT_BARELIST (1u << 7u) /* * End-of-line comment. */ #define CT_EOC (1u << 8u) /* * A bare value. */ #define CT_BARE (1u << 9u) /* * A bare constant, i.e., a bare word outside of a list that * represents its own configuration element. */ #define CT_BARECONST (1u << 10u) /* * A pair of numbers */ #define CT_NUMPAIR (1u << 11u) /* * A list of number pairs */ #define CT_NUMPAIRLIST (1u << 12u) /* * A bare quoted string constant, i.e., a bare string outside of a list that * represents its own configuration element. */ #define CT_BARESTRINGCONST (1u << 13u) /* * Mask for all types that have a key. This excludes FILEVERSION, * EOC, and BARE which reuse the key field for the value. */ #define CT_HAS_KEY_MASK (CT_INTVAL | CT_STRINGVAL | CT_VERSIONVAL | \ CT_BAREVAL | CT_STRINGVAL | CT_IDX_STRUCT | \ CT_BARELIST | CT_BARECONST | CT_NUMPAIRLIST | CT_BARESTRINGCONST) /***** Node Types *****/ struct ConfigBaseNode; struct ConfigBaseNode { struct ConfigBaseNode *next, *prev; unsigned int type; char *key; uint16_t line; uint16_t flags; }; struct ConfigFileVersionNode { struct ConfigBaseNode base; }; struct ConfigIntValNode { struct ConfigBaseNode base; unsigned long value; }; struct ConfigStringValNode { struct ConfigBaseNode base; char *value; }; struct ConfigVersionValNode { struct ConfigBaseNode base; unsigned int value; }; struct ConfigBareValNode { struct ConfigBaseNode base; char *value; }; struct ConfigIdxStructNode { struct ConfigBaseNode base; unsigned long idx; struct ConfigBaseNode *beforeOpen; struct ConfigBaseNode *value; }; struct ConfigStructNode { struct ConfigBaseNode base; struct ConfigBaseNode *beforeOpen; struct ConfigBaseNode *value; }; struct ConfigBareNode { /* Reuses base.key for bare value. */ struct ConfigBaseNode base; }; struct ConfigBareListNode { struct ConfigBaseNode base; struct ConfigBaseNode *beforeOpen; /* either a ConfigBareNode or a ConfigEOCNode */ struct ConfigBaseNode *value; }; struct ConfigEOCNode { /* Reuses base.key for comment */ struct ConfigBaseNode base; }; struct ConfigBareConstNode { struct ConfigBaseNode base; }; struct ConfigNumPairNode { struct ConfigBaseNode base; unsigned long value1; unsigned long value2; }; struct ConfigNumPairListNode { struct ConfigBaseNode base; struct ConfigBaseNode *beforeFirst; /* either a ConfigNumPairNode or a ConfigEOCNode */ struct ConfigBaseNode *value; char *end; }; struct ConfigBareStringConstNode { struct ConfigBaseNode base; }; /* Casting from base type functions */ static inline struct ConfigFileVersionNode * confignode_to_fileversion(struct ConfigBaseNode *n) { return (struct ConfigFileVersionNode *) (((char *)n) - offsetof(struct ConfigFileVersionNode, base)); } static inline struct ConfigIntValNode * confignode_to_intval(struct ConfigBaseNode *n) { return (struct ConfigIntValNode *) (((char *)n) - offsetof(struct ConfigIntValNode, base)); } static inline struct ConfigStringValNode * confignode_to_stringval(struct ConfigBaseNode *n) { return (struct ConfigStringValNode *) (((char *)n) - offsetof(struct ConfigStringValNode, base)); } static inline struct ConfigVersionValNode * confignode_to_versionval(struct ConfigBaseNode *n) { return (struct ConfigVersionValNode *) (((char *)n) - offsetof(struct ConfigVersionValNode, base)); } static inline struct ConfigBareValNode * confignode_to_bareval(struct ConfigBaseNode *n) { return (struct ConfigBareValNode *) (((char *)n) - offsetof(struct ConfigBareValNode, base)); } static inline struct ConfigIdxStructNode * confignode_to_idxstruct(struct ConfigBaseNode *n) { return (struct ConfigIdxStructNode *) (((char *)n) - offsetof(struct ConfigIdxStructNode, base)); } static inline struct ConfigStructNode * confignode_to_struct(struct ConfigBaseNode *n) { return (struct ConfigStructNode *) (((char *)n) - offsetof(struct ConfigStructNode, base)); } static inline struct ConfigBareNode * confignode_to_bare(struct ConfigBaseNode *n) { return (struct ConfigBareNode *) (((char *)n) - offsetof(struct ConfigBareNode, base)); } static inline struct ConfigBareListNode * confignode_to_barelist(struct ConfigBaseNode *n) { return (struct ConfigBareListNode *) (((char *)n) - offsetof(struct ConfigBareListNode, base)); } static inline struct ConfigEOCNode * confignode_to_eoc(struct ConfigBaseNode *n) { return (struct ConfigEOCNode *) (((char *)n) - offsetof(struct ConfigEOCNode, base)); } static inline struct ConfigBareConstNode * confignode_to_bareconst(struct ConfigBaseNode *n) { return (struct ConfigBareConstNode *) (((char *)n) - offsetof(struct ConfigBareConstNode, base)); } static inline struct ConfigNumPairNode * confignode_to_numpair(struct ConfigBaseNode *n) { return (struct ConfigNumPairNode *) (((char *)n) - offsetof(struct ConfigNumPairNode, base)); } static inline struct ConfigNumPairListNode * confignode_to_numpairlist(struct ConfigBaseNode *n) { return (struct ConfigNumPairListNode *) (((char *)n) - offsetof(struct ConfigNumPairListNode, base)); } static inline struct ConfigBareStringConstNode * confignode_to_barestringconst(struct ConfigBaseNode *n) { return (struct ConfigBareStringConstNode *) (((char *)n) - offsetof(struct ConfigBareStringConstNode, base)); } /* Freeing functions */ /** * Free a node and all its descendants. * @param n Node to free. */ void confignode_deepfree(struct ConfigBaseNode *n); /** * Free only one node but not its descendants. * This function basically is a dispatcher based on the node type. * @param n Node to free. */ void confignode_free(struct ConfigBaseNode *n); static inline void confignode_freefileversion(struct ConfigFileVersionNode *n) { if (n) { free(n->base.key); free(n); } } static inline void confignode_freeintval(struct ConfigIntValNode *n) { if (n) { free(n->base.key); free(n); } } static inline void confignode_freestringval(struct ConfigStringValNode *n) { if (n) { free(n->base.key); free(n->value); free(n); } } static inline void confignode_freeversionval(struct ConfigVersionValNode *n) { if (n) { free(n->base.key); free(n); } } static inline void confignode_freebareval(struct ConfigBareValNode *n) { if (n) { free(n->base.key); free(n->value); free(n); } } static inline void confignode_freeidxstruct(struct ConfigIdxStructNode *n) { if (n) { free(n->base.key); confignode_deepfree(n->beforeOpen); confignode_deepfree(n->value); free(n); } } static inline void confignode_freestruct(struct ConfigStructNode *n) { if (n) { free(n->base.key); confignode_deepfree(n->beforeOpen); confignode_deepfree(n->value); free(n); } } static inline void confignode_freebare(struct ConfigBareNode *n) { if (n) { free(n->base.key); free(n); } } static inline void confignode_freebarelist(struct ConfigBareListNode *n) { if (n) { free(n->base.key); confignode_deepfree(n->beforeOpen); confignode_deepfree(n->value); free(n); } } static inline void confignode_freeeoc(struct ConfigEOCNode *n) { if (n) { free(n->base.key); free(n); } } static inline void confignode_freebareconst(struct ConfigBareConstNode *n) { if (n) { free(n->base.key); free(n); } } static inline void confignode_freenumpair(struct ConfigNumPairNode *n) { if (n) { free(n->base.key); free(n); } } static inline void confignode_freenumpairlist(struct ConfigNumPairListNode *n) { if (n) { free(n->base.key); confignode_deepfree(n->beforeFirst); confignode_deepfree(n->value); free(n->end); free(n); } } static inline void confignode_freebarestringconst( struct ConfigBareStringConstNode *n) { if (n) { free(n->base.key); free(n); } } /* Allocation functions */ static inline struct ConfigFileVersionNode * confignode_allocfileversion(char *version, int line) { struct ConfigFileVersionNode *res = malloc(sizeof(struct ConfigFileVersionNode)); if (res) { res->base.next = res->base.prev = &(res->base); res->base.key = version; res->base.type = CT_FILEVERSION; res->base.line = line; } return res; } static inline struct ConfigIntValNode * confignode_allocintval(char *key, unsigned long val, int line) { struct ConfigIntValNode *res = malloc(sizeof(struct ConfigIntValNode)); if (res) { res->base.next = res->base.prev = &(res->base); res->base.key = key; res->base.type = CT_INTVAL; res->base.line = line; res->base.flags = 0; res->value = val; } return res; } static inline struct ConfigVersionValNode * confignode_allocversionval(char *key, unsigned long val, int line) { struct ConfigVersionValNode *res = malloc(sizeof(struct ConfigVersionValNode)); if (res) { res->base.next = res->base.prev = &(res->base); res->base.key = key; res->base.type = CT_VERSIONVAL; res->base.line = line; res->base.flags = 0; res->value = val; } return res; } static inline struct ConfigStringValNode * confignode_allocstringval(char *key, char *val, int line) { struct ConfigStringValNode *res = malloc(sizeof(struct ConfigStringValNode)); if (res) { res->base.next = res->base.prev = &(res->base); res->base.key = key; res->base.type = CT_STRINGVAL; res->base.line = line; res->base.flags = 0; res->value = val; } return res; } static inline struct ConfigBareValNode * confignode_allocbareval(char *key, char *val, int line) { struct ConfigBareValNode *res = malloc(sizeof(struct ConfigBareValNode)); if (res) { res->base.next = res->base.prev = &(res->base); res->base.key = key; res->base.type = CT_BAREVAL; res->base.line = line; res->base.flags = 0; res->value = val; } return res; } static inline struct ConfigIdxStructNode * confignode_allocidxstruct(char *key, unsigned long num, struct ConfigBaseNode *beforeOpen, struct ConfigBaseNode *value, int line) { struct ConfigIdxStructNode *res = malloc(sizeof(struct ConfigIdxStructNode)); if (res) { res->base.next = res->base.prev = &(res->base); res->base.key = key; res->base.type = CT_IDX_STRUCT; res->base.line = line; res->base.flags = 0; res->idx = num; res->beforeOpen = beforeOpen; res->value = value; } return res; } static inline struct ConfigStructNode * confignode_allocstruct(char *key, struct ConfigBaseNode *beforeOpen, struct ConfigBaseNode *value, int line) { struct ConfigStructNode *res = malloc(sizeof(struct ConfigStructNode)); if (res) { res->base.next = res->base.prev = &(res->base); res->base.key = key; res->base.type = CT_STRUCT; res->beforeOpen = beforeOpen; res->base.line = line; res->base.flags = 0; res->value = value; } return res; } static inline struct ConfigBareListNode * confignode_allocbarelist(char *key, struct ConfigBaseNode *beforeOpen, struct ConfigBaseNode *value, int line) { struct ConfigBareListNode *res = malloc(sizeof(struct ConfigBareListNode)); if (res) { res->base.next = res->base.prev = &(res->base); res->base.key = key; res->base.type = CT_BARELIST; res->base.line = line; res->base.flags = 0; res->beforeOpen = beforeOpen; res->value = value; } return res; } static inline struct ConfigBareNode *confignode_allocbare(char *bareval, int line) { struct ConfigBareNode *res = malloc(sizeof(struct ConfigBareNode)); if (res) { res->base.next = res->base.prev = &(res->base); res->base.key = bareval; res->base.type = CT_BARE; res->base.line = line; res->base.flags = 0; } return res; } static inline struct ConfigEOCNode *confignode_alloceoc(char *comment, int line) { struct ConfigEOCNode *res = malloc(sizeof(struct ConfigEOCNode)); if (res) { res->base.next = res->base.prev = &(res->base); res->base.key = comment; res->base.type = CT_EOC; res->base.line = line; res->base.flags = 0; } return res; } static inline struct ConfigBareConstNode *confignode_allocbareconst(char *key, int line) { struct ConfigBareConstNode *res = malloc(sizeof(struct ConfigBareConstNode)); if (res) { res->base.next = res->base.prev = &(res->base); res->base.key = key; res->base.type = CT_BARECONST; res->base.line = line; res->base.flags = 0; } return res; } static inline struct ConfigNumPairNode *confignode_allocnumpair( unsigned long value1, unsigned long value2, int line) { struct ConfigNumPairNode *res = malloc(sizeof(struct ConfigNumPairNode)); if (res) { res->base.next = res->base.prev = &(res->base); res->base.key = NULL; res->base.type = CT_NUMPAIR; res->base.line = line; res->base.flags = 0; res->value1 = value1; res->value2 = value2; } return res; } static inline struct ConfigNumPairListNode * confignode_allocnumpairlist(char *key, char *end, struct ConfigBaseNode *beforeFirst, struct ConfigBaseNode *value, int line) { struct ConfigNumPairListNode *res = malloc(sizeof(struct ConfigNumPairListNode)); if (res) { res->base.next = res->base.prev = &(res->base); res->base.key = key; res->base.type = CT_NUMPAIRLIST; res->base.line = line; res->base.flags = 0; res->beforeFirst = beforeFirst; res->value = value; res->end = end; } return res; } static inline struct ConfigBareStringConstNode *confignode_allocbarestringconst( char *key, int line) { struct ConfigBareStringConstNode *res = malloc(sizeof(struct ConfigBareStringConstNode)); if (res) { res->base.next = res->base.prev = &(res->base); res->base.key = key; res->base.type = CT_BARESTRINGCONST; res->base.line = line; res->base.flags = 0; } return res; } /* Convenience functions for AST manipulation. These functions automatically append an EOC-node to the correct node which optionally includes a comment. If no comment is desired, simply pass NULL for the comment argument. The dumpable versions below also strdup all strings (keys, values, and the optional comment). */ struct ConfigFileVersionNode * confignode_allocfileversiondumpable(char *version, int line, char *comment); struct ConfigIntValNode * confignode_allocintvaldumpable(char *key, unsigned long val, int line, char *comment); struct ConfigVersionValNode * confignode_allocversionvaldumpable(char *key, unsigned long val, int line, char *comment); struct ConfigStringValNode * confignode_allocstringvaldumpable(char *key, char *val, int line, char *comment); struct ConfigBareValNode * confignode_allocbarevaldumpable(char *key, char *val, int line, char *comment); struct ConfigIdxStructNode * confignode_allocidxstructdumpable(char *key, unsigned long num, struct ConfigBaseNode *beforeOpen, struct ConfigBaseNode *value, int line, char *comment); struct ConfigStructNode * confignode_allocstructdumpable(char *key, struct ConfigBaseNode *beforeOpen, struct ConfigBaseNode *value, int line, char *comment); struct ConfigBareListNode * confignode_allocbarelistdumpable(char *key, struct ConfigBaseNode *beforeOpen, struct ConfigBaseNode *value, int line, char *comment); struct ConfigBareNode * confignode_allocbaredumpable(char *bareval, int line, char *comment); struct ConfigBareConstNode * confignode_allocbareconstdumpable(char *key, int line, char *comment); struct ConfigNumPairNode * confignode_allocnumpairdumpable(unsigned long value1, unsigned long value2, int line, char *comment); struct ConfigNumPairListNode * confignode_allocnumpairlistdumpable(char *key, char* end, struct ConfigBaseNode *beforeFirst, struct ConfigBaseNode *value, int line, char *comment); /* Append the list n2 to the end of the list n1. NULL is considered as empty list. */ static inline struct ConfigBaseNode *confignode_append(struct ConfigBaseNode *n1, struct ConfigBaseNode *n2) { struct ConfigBaseNode *tmp; if (n1) { if (n2) { n1->prev->next = n2; tmp = n2->prev; n2->prev = n1->prev; tmp->next = n1; n1->prev = tmp; return n1; } else { return n1; } } else { return n2; } } /* Dumping support */ #define CONFIG_FLAG_INT_PRINT_MODE_HEX (1 << 0u) struct ConfigDumpCb { /* Called for every node to update the dump flags. */ unsigned (*flags)(struct ConfigBaseNode *n, unsigned curflags); }; void confignode_dump(FILE *fp, struct ConfigBaseNode *n, struct ConfigDumpCb *cb, unsigned indent); /* Iteration and searching */ /* * Iterate over a configuration. * i is the iterator of type struct ConfigBaseNode * * c is the configuration to iterate over (of type struct ConfigBaseNode *) * f is an integer */ #define confignode_foreach(i,c,f) \ for((i)=(c),(f)=1;(i)&&((f)||(i)!=(c));(i)=(i)->next,(f)=0) static inline struct ConfigBaseNode * confignode_find(struct ConfigBaseNode *cfg, const char *key) { struct ConfigBaseNode *i; if (cfg) { i = cfg; do { if ((i->type & CT_HAS_KEY_MASK) && strcmp(key, i->key) == 0) return i; i = i->next; } while (i != cfg); } return NULL; } static inline struct ConfigIdxStructNode * confignode_findidx(struct ConfigBaseNode *cfg, const char *key, unsigned idx) { struct ConfigBaseNode *i; struct ConfigIdxStructNode *res; if (cfg) { i = cfg; do { if ((i->type & CT_IDX_STRUCT) && strcmp(key, i->key) == 0) { res = confignode_to_idxstruct(i); if (res->idx == idx) return res; } i = i->next; } while (i != cfg); } return NULL; } /* Type checking */ static inline int confignode_hastype(struct ConfigBaseNode *n, unsigned typemask) { return (n->type & typemask) != 0; } /* Convenience functions */ static inline char *confignode_getstr(struct ConfigBaseNode *n) { if (n->type & CT_STRINGVAL) return confignode_to_stringval(n)->value; if (n->type & CT_BAREVAL) return confignode_to_bareval(n)->value; return NULL; } /* Returns 0 if a valid version was found and -1 otherwise. */ static inline int confignode_getversion(struct ConfigBaseNode *n, unsigned int *version) { int res = 0; unsigned int major, minor; if (n->type & CT_VERSIONVAL) { *version = confignode_to_versionval(n)->value; } else if (n->type & CT_STRINGVAL) { if (sscanf(confignode_to_stringval(n)->value, "%u.%u", &major, &minor) == 2) *version = major << 16 | minor; else res = -1; } else { res = -1; } return res; } #endif opencryptoki-opencryptoki-451d99c/usr/lib/ep11_stdll/000077500000000000000000000000001520105705100226535ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/usr/lib/ep11_stdll/ep11.h000066400000000000000000005145031520105705100236020ustar00rootroot00000000000000/* * (C) Copyright IBM Corp. 2012, 2025 * * 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 * *---------------------------------------------------------------------- * EP11 service mail address: EP11SERV@de.ibm.com * * Use this e-mail address for Bugs and Comments with the EP11 product. *----------------------------------------------------------------------*/ #if !defined(XCP_H__) #define XCP_H__ #define XCP_API_VERSION 0x0906 #if !defined(CKR_OK) #include "pkcs11.h" #endif #if !defined(INT64_MIN) #error "We need 64-bit types, please include before this file." #endif // // used for internal and external paths/addresses #define MAX_FNAME_CHARS 256 // Error Values for functions that do not return CK_RV // general errors #define XCP_OK 0 /* function successful */ #define XCP_EINTERNAL -1 /* host library internal error. * host library is in an inconsistent state * shutdown and new init is needed */ #define XCP_EARG -2 /* Argument is invalid */ #define XCP_ETARGET -3 /* Target argument is invalid */ #define XCP_EMEMORY -4 /* could not allocate memory */ #define XCP_EMUTEX -5 /* Mutex is invalid */ #define XCP_EINIT -6 /* Could not initialize library */ #define XCP_EDEVICE -7 /* The channel that is used to communicate * with the backend is not available or * invalid */ #define XCP_EGROUP -8 /* Target group is unusable or invalid */ #define XCP_ESIZE -9 /* invalid size */ #define XCP_EINVALID -10 /* invalid content of parameter */ #define XCP_ERESPONSE -11 /* bad response from module. Sometimes * it is not possible to return the CK_RV * value directly and we can only say that * something failed. */ #define XCP_EAPI -12 /* incompatible/invalid api */ // module specific errors #define XCP_MOD_EOBSOLETE -101 /* past feature has been obsoleted, * no longer available. check notes on * future-compatibility. */ #define XCP_MOD_EVERSION -102 /* library predates caller, does not * support requested API version */ #define XCP_MOD_EFLAGS -103 /* library does not support all requested * flags, even if call/struct is otherwise * API-compatible. expect this only when * device-specific details (module * selection, communication/channel type) * are not supported by the backend. */ #define XCP_MOD_EMODULE -104 /* library does not support this module * number (a real one, not virtual ones). * typical error when locally attached * modules' count has an upper bound. */ #define XCP_MOD_EDOMAIN -105 /* the targeted module does not support * the requested domain. */ #define XCP_MOD_EINIT -106 /* the targeted module is not initialized * typical error for socket attached * modules, because adding this modules * on the fly is not possible */ #define XCP_MOD_EPROBE -107 /* probe did fail for all defined domains. * This is an error even when the strict * flag is not active */ /*--------------------------------------------------------------------------*/ #define XCP_COMMON_PUBLIC_H__ #ifndef XCP_H__ #define CK_DISABLE_TRUE_FALSE #endif #define XCP_API_VERSION_Z16 0x0827 /* major[8] minor[8] */ #define XCP_API_VERSION_Z17 0x0906 /* major[8] minor[8] */ #define XCP_API_ORDINAL 0x0006 /* increment this with every major/minor change */ #define XCP_HOST_API_VER 0x040200 /* major[8] minor[8] fixpack[8] */ /* HSM connection information; not for PKCS11 user consumption */ #define XCP_HSM_AGENT_ID 0x5843 /* ASCII "XC" */ #define XCP_HSM_USERDEF32 0x01234567 // protected key requires API ordinal greater or equal to 4 #define XCP_API_ALLOW_PROTKEY 0x0004 // Support for extended FIPS2021 attributes // // Requests for card/domain attributes (XCP_ADMQ_ATTRS/XCP_ADMQ_DOM_ATTRS) // will contain the extended attributes (key-types, adm FIPS2021 compliance) // only with API ordinal 5 (or higher) for compatibility reasons. // Also, the module sub-queries CK_IBM_XCPMSQ_ATTRLIST, CK_IBM_XCPMSQ_ATTRS // and CK_IBM_XCPMSQ_ATTRCOUNT will contain the information related to the // extended attributes only with this API ordinal. #define XCP_API_ALLOW_FIPS2021 0x0005 // function sub-variants // 0 means regular request typedef enum { XCP_FNVAR_SIZEQUERY = 1, /* sizequery: databytes[64]->resp.bytes[64] */ XCP_FNVAR_MULTIDATA = 2, /* multi-data request */ XCP_FNVAR_MULTISIZEQ = 3 /* multi-data request, size query */ } XCP_FNVariant_t; // XCP-specific return codes // #define CKR_IBM_WKID_MISMATCH (CKR_VENDOR_DEFINED +0x10001) #define CKR_IBM_INTERNAL_ERROR (CKR_VENDOR_DEFINED +0x10002) #define CKR_IBM_TRANSPORT_ERROR (CKR_VENDOR_DEFINED +0x10003) #define CKR_IBM_BLOB_ERROR (CKR_VENDOR_DEFINED +0x10004) /* WK setup changed during the execution of a single request, * preventing return of encrypted data to the host. (i.e., * an administrative operation changed WKs before the * function could re-wrap data to pass back to the host) */ #define CKR_IBM_BLOBKEY_CONFLICT (CKR_VENDOR_DEFINED +0x10005) #define CKR_IBM_MODE_CONFLICT (CKR_VENDOR_DEFINED +0x10006) /* an RSA key in non-CRT form is encountered which is not * supported by this hardware/engine configuration, if the * setup has non/CRT-specific size restrictions. * in essence, a more specific sub-division of * the standard CKR_KEY_SIZE_RANGE, and MAY be * safely mapped to that by host libraries. */ #define CKR_IBM_NONCRT_KEY_SIZE (CKR_VENDOR_DEFINED +0x10008) #define CKR_IBM_WK_NOT_INITIALIZED (CKR_VENDOR_DEFINED +0x10009) /* unexpected/consistency error of CA operations of the * hosting HSM, if not otherwise classified. */ #define CKR_IBM_OA_API_ERROR (CKR_VENDOR_DEFINED +0x1000a) /* potentially long-running request, such as those involving * prime generation, did not complete in a 'reasonable' * number of iterations. supported to prevent timeout- * triggered module resets, such as mainframe firmware * resetting modules 'stuck in infinite loops' (as perceived * by the host) */ #define CKR_IBM_REQ_TIMEOUT (CKR_VENDOR_DEFINED +0x1000b) /* backend in read-only state, rejecting state-changing * operations: */ #define CKR_IBM_READONLY (CKR_VENDOR_DEFINED +0x1000c) /* backend/policy may not be configured to accept request. * this is the permanent form of policy failure * (which is mapped to standard CKR_FUNCTION_CANCELED) */ #define CKR_IBM_STATIC_POLICY (CKR_VENDOR_DEFINED +0x1000d) /* backend not allowed to return requested nr of bytes: */ #define CKR_IBM_TRANSPORT_LIMIT (CKR_VENDOR_DEFINED +0x10010) // // use CKR_IBM_TRANSPORT_ERROR for errors introduced between ep11.h and backend // CKR_IBM_TRANSPORT_LIMIT for errors on return path // CKR_ARGUMENTS_BAD or specific one for bad data passed through ep11.h #define CKR_IBM_FCV_NOT_SET (CKR_VENDOR_DEFINED +0x10011) // Error returned by check if the performance category has not been set #define CKR_IBM_PERF_CATEGORY_INVALID (CKR_VENDOR_DEFINED +0x10012) // API ORDINAL number is unknown or function id is in illegal range #define CKR_IBM_API_MISMATCH (CKR_VENDOR_DEFINED +0x10013) // target token is invalid #define CKR_IBM_TARGET_INVALID (CKR_VENDOR_DEFINED +0x10030) #define CKR_IBM_PQC_PARAMS_NOT_SUPPORTED (CKR_VENDOR_DEFINED +0x10031) #define CKR_IBM_PARAM_NOT_SUPPORTED (CKR_VENDOR_DEFINED +0x10032) #define CKR_IBM_SESSION_IMMUTABLE (CKR_VENDOR_DEFINED +0x10033) // Error returned if internal verification of crypto engines fail #define CKR_IBM_ERROR_STATE (CKR_VENDOR_DEFINED +0x10101) /*--- mechanisms ---------------------------------------------------------*/ #define CKM_IBM_SHA3_224 (CKM_VENDOR_DEFINED +0x10001) #define CKM_IBM_SHA3_256 (CKM_VENDOR_DEFINED +0x10002) #define CKM_IBM_SHA3_384 (CKM_VENDOR_DEFINED +0x10003) #define CKM_IBM_SHA3_512 (CKM_VENDOR_DEFINED +0x10004) #define CKM_IBM_CMAC (CKM_VENDOR_DEFINED +0x10007) // // non-SHA-1 ECDSA: no standard mechansims pre-v2.40 #define CKM_IBM_ECDSA_SHA224 (CKM_VENDOR_DEFINED +0x10008) #define CKM_IBM_ECDSA_SHA256 (CKM_VENDOR_DEFINED +0x10009) #define CKM_IBM_ECDSA_SHA384 (CKM_VENDOR_DEFINED +0x1000a) #define CKM_IBM_ECDSA_SHA512 (CKM_VENDOR_DEFINED +0x1000b) // EC point multiply #define CKM_IBM_EC_MULTIPLY (CKM_VENDOR_DEFINED +0x1000c) // EAC (machine-readable travel document: passport, DL, ID card PKI) // // derive secure messaging, a class of functions #define CKM_IBM_EAC (CKM_VENDOR_DEFINED +0x1000d) #define XCP_EAC_NONCE_MAX_BYTES 64 /* salt/nonce */ #define XCP_EAC_INFO_MAX_BYTES 64 /* other auxiliary data */ // // variants within EAC typedef enum { EACV_IBM_KEK_V101 = 1, // secret -> secure msg KEK (EAC v1.01) EACV_IBM_MACK_V101 = 2, // secret -> secure msg MACK (EAC v1.01) EACV_IBM_PWD_V200 = 3, // passphrase -> secure msg KEK (EAC v2.00) EACV_IBM_HKDF = 4, // HKDF( base-key, mechanism-attached salt ) // salt is supplied with mechanism parameter // output bytecount specified as attribute // of derived key EACV_IBM_BCHAIN_TCERT0 = 5 // blockchain: derive tcert from base EC key // and additive cleartext [potentially insecure] } EAC_Var_t; // test access #define CKM_IBM_TESTCODE (CKM_VENDOR_DEFINED +0x1000e) // SHA-512 derivatives later than PKCS#11 v2.20, SHA-512/256 and SHA-512/224 // see pkcs11add.h (since v2.40 drafts)(since v2.40 drafts)(since v2.40 drafts)(since v2.40 drafts) // #define CKM_IBM_SHA512_256 (CKM_VENDOR_DEFINED +0x10012) #define CKM_IBM_SHA512_224 (CKM_VENDOR_DEFINED +0x10013) #define CKM_IBM_SHA512_256_HMAC (CKM_VENDOR_DEFINED +0x10014) #define CKM_IBM_SHA512_224_HMAC (CKM_VENDOR_DEFINED +0x10015) // // curve25519, key agreement #define CKM_IBM_EC_X25519 (CKM_VENDOR_DEFINED +0x1001b) // // eddsa/25519 signatures, with SHA-512, no prehashing #define CKM_IBM_ED25519_SHA512 (CKM_VENDOR_DEFINED +0x1001c) // curve448 ('Goldilocks'), key agreement #define CKM_IBM_EC_X448 (CKM_VENDOR_DEFINED +0x1001e) // // ed448 signatures, with SHA-3/XOF, no prehashing #define CKM_IBM_ED448_SHA3 (CKM_VENDOR_DEFINED +0x1001f) // round counts are passed as mechanism parameters #define CKM_IBM_SIPHASH (CKM_VENDOR_DEFINED +0x10021) // these need a strength definition // XCP_U32_VALUE_BITS/CKA_VALUE_BITS would be sufficient; strength->K/L mapping // // umbrella mech for PQC/Crystals variants #define CKM_IBM_DILITHIUM (CKM_VENDOR_DEFINED +0x10023) // ^^^ sign/verify plus keygen only #define CKM_IBM_KYBER (CKM_VENDOR_DEFINED +0x10024) // ^^^ en/decrypt, keygen, key transport, and (hybrid) key derivation // SHA-3 HMAC variants #define CKM_IBM_SHA3_224_HMAC (CKM_VENDOR_DEFINED +0x10025) #define CKM_IBM_SHA3_256_HMAC (CKM_VENDOR_DEFINED +0x10026) #define CKM_IBM_SHA3_384_HMAC (CKM_VENDOR_DEFINED +0x10027) #define CKM_IBM_SHA3_512_HMAC (CKM_VENDOR_DEFINED +0x10028) // curve25519, key agreement (using KEK) #define CKM_IBM_EC_X25519_RAW (CKM_VENDOR_DEFINED +0x10029) // curve448 ('Goldilocks'), key agreement (using KEK) #define CKM_IBM_EC_X448_RAW (CKM_VENDOR_DEFINED +0x10030) #define CKM_IBM_ECDSA_OTHER (CKM_VENDOR_DEFINED +0x10031) typedef enum { ECSG_IBM_ECSDSA_S256 = 3, // [Randomized] Schnorr signatures // BSI TR03111 ECSDSA // no prehashing; SHA-256 only ECSG_IBM_ECSDSA_COMPR_MULTI = 5, // [Randomized] Schnorr signatures // BSI TR-03111 @2012, working on // compressed public key format and // including signers public key ECSG_IBM_BLS = 6, // Boneh-Lynn-Shacham signatures // RFC draft-irtf-cfrg-bls-signature-05 ECSG_IBM_MAX = ECSG_IBM_BLS, } ECSG_Var_t; #define CKM_IBM_EC_AGGREGATE (CKM_VENDOR_DEFINED +0x10034) typedef enum { EC_AGG_BLS12_381_SIGN = 1, // size of signature is sufficient indicator EC_AGG_BLS12_381_PKEY = 2, EC_AGG_BLS12_381_MAX = EC_AGG_BLS12_381_PKEY, } ECAgg_Var_t; #define CK_IBM_EC_AGG_BLS12_381_SIGN EC_AGG_BLS12_381_SIGN #define CK_IBM_EC_AGG_BLS12_381_PKEY EC_AGG_BLS12_381_PKEY typedef struct XCP_EC_AGGREGATE_PARAMS { CK_ULONG version; CK_ULONG mode; CK_ULONG perElementSize; CK_BYTE_PTR pElements; CK_ULONG ulElementsLen; } XCP_EC_AGGREGATE_PARAMS; #define CK_IBM_ECSG_IBM_ECSDSA_S256 ECSG_IBM_ECSDSA_S256 #define CK_IBM_ECSG_IBM_ECDSA_COMPR_MULTI_S256 ECSG_IBM_ECDSA_COMPR_MULTI_S256 #define CK_IBM_ECSG_IBM_BLS ECSG_IBM_BLS #define CK_IBM_ECSG_IBM_MAX ECSG_IBM_MAX #define CKM_IBM_ML_DSA_KEY_PAIR_GEN (CKM_VENDOR_DEFINED +0x10035) #define CKM_IBM_ML_DSA (CKM_VENDOR_DEFINED +0x10036) // ^^^ sign/verify only #define CKM_IBM_ML_KEM_KEY_PAIR_GEN (CKM_VENDOR_DEFINED +0x10037) #define CKM_IBM_ML_KEM (CKM_VENDOR_DEFINED +0x10038) // ^^^ key transport, and (hybrid) key derivation //--- transport additions -------------------------------------------------- #define CKM_IBM_CLEARKEY_TRANSPORT (CKM_VENDOR_DEFINED +0x20001) // key+attributes bound format (ignores other attributes) #define CKM_IBM_ATTRIBUTEBOUND_WRAP (CKM_VENDOR_DEFINED +0x20004) // operations related to key cloning #define CKM_IBM_TRANSPORTKEY (CKM_VENDOR_DEFINED +0x20005) // EC/DH equivalents: derive key, then return encrypted under // KEK supplied as auxiliary data // (does not resemble regular PKCS11 mechanisms) // #define CKM_IBM_DH_PKCS_DERIVE_RAW (CKM_VENDOR_DEFINED +0x20006) #define CKM_IBM_ECDH1_DERIVE_RAW (CKM_VENDOR_DEFINED +0x20007) // none of these have PKCS11 constants (as of 2018-02) // // allow direct access to mechanism's wireform // parameter of this mechanism is used as wire form #define CKM_IBM_WIRETEST (CKM_VENDOR_DEFINED +0x30004) //--- separate infrastructure-related mechs -------------------------------- // to generate/refill semi-retained keys // see also CKA_IBM_RETAINKEY // #define CKM_IBM_RETAINKEY (CKM_VENDOR_DEFINED +0x40001) // IBM protkey data key import mechanism (WrapKey) #define CKM_IBM_CPACF_WRAP (CKM_VENDOR_DEFINED +0x60001) // bitcoin key derivation #define CKM_IBM_BTC_DERIVE (CKM_VENDOR_DEFINED +0x70001) // etherium key derivation #define CKM_IBM_ETH_DERIVE (CKM_VENDOR_DEFINED +0x70002) /*--- attributes ---------------------------------------------------------*/ // object may have rights removed, but not added (subset of modifiability) #define CKA_IBM_RESTRICTABLE (CKA_VENDOR_DEFINED +0x10001) // object was created non-MODIFIABLE #define CKA_IBM_NEVER_MODIFIABLE (CKA_VENDOR_DEFINED +0x10002) // object is HSM-resident (handle instead of full token) // has a single parameter, usage count #define CKA_IBM_RETAINKEY (CKA_VENDOR_DEFINED +0x10003) // object must be transported with attributes, never separated // note: incompatible with pure-PKCS#11 un/wrap #define CKA_IBM_ATTRBOUND (CKA_VENDOR_DEFINED +0x10004) // symbolic key type in other hierarchies (CK_ULONG) // XCP stores but ignores it #define CKA_IBM_KEYTYPE (CKA_VENDOR_DEFINED +0x10005) // restrictions inherited from other type systems // XCP stores and partially interprets it #define CKA_IBM_CV (CKA_VENDOR_DEFINED +0x10006) // attribute containing MAC key handle, or blob, for authenticated key transport #define CKA_IBM_MACKEY (CKA_VENDOR_DEFINED +0x10007) // object may be used as base data of other ops, i.e., hashing or key derivation // #define CKA_IBM_USE_AS_DATA (CKA_VENDOR_DEFINED +0x10008) // DSA/DH parameters as ALGID structure (PKCS#3) #define CKA_IBM_STRUCT_PARAMS (CKA_VENDOR_DEFINED +0x10009) // compliance mode, bitfield within 32-bit (CK_ULONG) parameter #define CKA_IBM_STD_COMPLIANCE1 (CKA_VENDOR_DEFINED +0x1000a) // key is extractable only as protected key #define CKA_IBM_PROTKEY_EXTRACTABLE (CKA_VENDOR_DEFINED +0x1000c) // key is never extractable as protected key #define CKA_IBM_PROTKEY_NEVER_EXTRACTABLE (CKA_VENDOR_DEFINED +0x1000d) #define CKA_IBM_PQC_PARAMS (CKA_VENDOR_DEFINED +0x1000e) // query or modify login session an object is bound to #define CKA_IBM_LOGIN_SESSION (CKA_VENDOR_DEFINED +0x1000f) // query or modify login session an object is bound to #define CKA_IBM_LOGIN_SESSION (CKA_VENDOR_DEFINED +0x1000f) #define CKA_IBM_PARAMETER_SET (CKA_VENDOR_DEFINED +0x10010) // query MAC'd spki from a private key #define CKA_IBM_MACED_PUBLIC_KEY_INFO (CKA_VENDOR_DEFINED +0x20002) // direct access to attributes' wire form // parameters of this attribute, if it's the only one present, // inserted verbatim into request package #define CKA_IBM_WIRETEST (CKA_VENDOR_DEFINED +0x20001) // matches the key type constant for clear key Dilithium with ICSF #define CKK_IBM_PQC_DILITHIUM (CKK_VENDOR_DEFINED +0x10023) #define CKK_IBM_PQC_KYBER (CKK_VENDOR_DEFINED +0x10024) #define CKK_IBM_ML_DSA (CKK_VENDOR_DEFINED +0x10025) #define CKK_IBM_ML_KEM (CKK_VENDOR_DEFINED +0x10026) #define XCP_MOD_ERROR_STATE_OFF 0x00000000 #define XCP_MOD_ERROR_STATE_MODULE_SELFTEST 0x00000001 #define XCP_MOD_ERROR_STATE_KEYPAIR_GEN_PCT 0x00000002 #define XCP_MOD_ERROR_STATE_SYSTEST_CMD 0x00000003 #define XCP_MOD_ERROR_STATE_TRNG_HEALTH 0x00000004 /*---------------------------------------------------------------------------- * sizes related to blobs and host-visible entities * * Cast as many to size_t/unsigned types as possible, to minimize the number * of 'mixed un/signed types' warnings. Unfortunately, this does not work * for those which are used by preprocessor math (XCP_WK_BYTES, for example), * since the preprocessor can not deal with typed arithmetic. */ #define XCP_HMAC_BYTES ((size_t) (256 /8)) /* SHA-256 */ #define XCP_FWID_BYTES ((size_t) (256 /8)) /* SHA-256 */ #define XCP_WK_BYTES ((size_t) (256 /8)) /* keypart and session sizes */ /* are identical */ #define XCP_WKID_BYTES ((size_t) (128 /8)) /* truncated hash */ #define XCP_BLOBCLRATTR_BYTES 8 /* clear blob attr's bytecount */ /* keep in sync with objattr_t */ #define XCP_BLOBCLRMODE_BYTES 8 /* clear blob modefield bytecount */ #define XCP_WRAP_BLOCKSIZE ((size_t) (128 /8)) /* blob crypt block bytecount */ #define XCP_MACKEY_BYTES (256 /8) /* derived from controlling WK */ // #define XCP_PIN_SALT_BYTES XCP_WRAP_BLOCKSIZE #define XCP_PINBLOB_BYTES \ (XCP_WK_BYTES +XCP_PIN_SALT_BYTES +XCP_HMAC_BYTES) #define XCP_SESSION_SALT_BYTES ((size_t) 128 /8) /* salt used in PIN blob rewrapping */ #define XCP_SESSION_TCTR_BYTES ((size_t) (128/8)) /* transaction counter */ #define XCP_SESSION_MAC1_BYTES ((size_t) 64 /8) /* AES/KW MAC */ // // full v1 (FIPS/2021) PIN, AESKW/pad ciphertext size #define XCP_PINBLOB_V1_BYTES \ (XCP_WK_BYTES +XCP_SESSION_SALT_BYTES +XCP_SESSION_MAC1_BYTES) #define XCP_PBE_TYPE_CLEAR 0 /* clear passphrase */ #define XCP_PBE_TYPE_BLOB 1 /* passphrase as generic secretkey */ #define XCP_PBE_TYPE_MAX (XCP_PBE_TYPE_BLOB) // #define XCP_PBE_HDR_BYTES 16 /* fixed part of PBE wire struct */ #define XCP_PBE_PWD_MAX_BYTES 1024 #define XCP_PBE_SALT_MAX_BYTES 256 // currently, these are the largest possible param structs #define XCP_MECH_WIRE_PRM_BYTES ((size_t) 4) /* CK_ULONG(mech) on wire */ #define XCP_MECH_PRM_MAX_BYTES \ (XCP_MECH_WIRE_PRM_BYTES +XCP_PBE_HDR_BYTES \ +XCP_PBE_PWD_MAX_BYTES +XCP_PBE_SALT_MAX_BYTES) // wire-encoded file header: file ID, start/offset, bytecount // return path fills in fields, plus may supply data slice #define XCP_WIRE_FILEHDR_BYTES ((size_t) (4+4+4)) // currently, PBE iteration count limit is global // the limit may increase, but not decrease, in the future #define XCP_PBE_ITER_MAX (64*1024) // SYS_TEST-only, configuration query size #define XCP_CSP_CONFIG_BYTES 40 #define XCP_SESSIONBLOB_SALT_BYTES 16 #define XCP_SESSIONBLOB_BYTES \ (XCP_WK_BYTES +XCP_SESSIONBLOB_SALT_BYTES +XCP_HMAC_BYTES) #define XCP_SIZEQ_WIRE_BYTES 8 /* wire size of data/response bytecounts */ #define XCP_PSS_WIRE_BYTES (4+4+4) /* hash[32] || MGF[32] || salt bytes[32] */ // // infer value from mechanism/hash function #define XCP_PSS_DEFAULT_VALUE 0xffffffff #define XCP_OAEP_MIN_WIRE_BYTES (4+4+4) /* hash[32] || MGF[32] || src[32] */ #define XCP_OAEP_MAX_SOURCE_BYTES 1024 /* limit encoding parameter length to a sane number of Bytes */ #define XCP_SHAKE_WIRE_BYTES 4 /* XOF Bytes[32] */ #define XCP_ECDH1_DERIVE_MIN_WIRE_BYTES (4+4+4) /* kdf[32] || SharedDataLen[32] || PublicDataLen[32] */ #define XCP_BTC_MIN_WIRE_BYTES (4+4+4+4) /* type[32] || childKeyIndex[32] || chaincode[32] version[32] */ #define XCP_BIP0032_CHAINCODE_BYTES 32 #define XCP_BTC_VERSION 1 #define XCP_ETH_MIN_WIRE_BYTES (4+4+4+4+4) /* type[32] || childKeyIndex[32] || KeyInfo[32] || version[32] || sigVersion[32] */ #define XCP_EIP2333_KEYINFO_BYTES 32 #define XCP_ETH_VERSION 1 #define XCP_ETH_SIG_VERSION 4 #define XCP_KYBER_KEM_VERSION 0 #define XCP_KYBER_KEM_MIN_WIRE_BYTES (4 + 4 + 4 + 4 + 4 + 4) /* version[32] || kdf[32] || mode[32] || cphr[32] || shrd[32] || blob [32] */ #define XCP_KYBER_RAW_BYTES 32 #define XCP_ECDH1_DERIVE_MAX_PUBLIC_BYTES 1024 /* limit public data length to reasonable number of bytes */ // #define XCP_ECDH1_DERIVE_MAX_SHARED_BYTES 1024 /* limit shared data length to reasonable number of bytes */ // // full RK ID (handle) #define XCP_RETAINID_BYTES (XCP_HMAC_BYTES +XCP_HMAC_BYTES) // // RK label (name, other human-readable information) #define XCP_RETAINLABEL_BYTES ((size_t) 64) // // truncated form #define XCP_RETAINID_SHORT_BYTES 4 /*--- infrastructure -----------------------------------------------------*/ typedef enum { CKF_IBM_HW_EXTWNG = 1, // module monitors removal from its slot. CKF_IBM_HW_ATTEST = 2, // module has hardware-assisted attestation CKF_IBM_HW_BATTERY = 4, // module has battery, may raise warnings CKF_IBM_HW_SYSTEST = 8, // module supports insecure test functions CKF_IBM_HW_RETAIN = 0x10, // module may retain hardware-internal keys CKF_IBM_HW_AUDIT = 0x40, // module supports audit-event logging CKF_IBM_HW_ADM_DOMIMPORT = 0x0200, // module supports domain import // see also related extended capability // (CK_IBM_XCPXQ_DOMIMPORT_VER) CKF_IBM_HW_PROTKEY_TOLERATION = 0x0400, // module tolerates blob attributes // related to the protected-key capability // see also CKA_IBM_PROTKEY_* description CKF_IBM_HW_DUAL_OA = 0x1000, // module supports dual OA certs/signatures // see CK_IBM_XCPXQ_OA_CAP for more details CKF_IBM_HW_RSA_IMPLICIT_REJECTION = 0x2000, // module performs implicit rejection of // data with invalid RSA PKCS 1.5 padding } XCP_CK_EXTFLAGS_t; // these numbers apply to current version, subject to change // #define XCP_MAX_MODULES 256 /* number of targetable backends */ #define XCP_SERIALNR_CHARS 8 #define XCP_DOMAIN_INSTANCE_BYTES 4 #define XCP_DOMAIN_NUMBER_BYTES 4 #define XCP_DOMAIN_REVISION_BYTES 4 #define XCP_DOMAIN_FLAGS_BYTES 4 #define XCP_WRAPKEY_BYTES 32 /* keep integer blocks of blob cipher */ #define XCP_SPKISALT_BYTES 8 /* in MACed SPKIs (public key objs) */ #define XCP_DOMAINS 256 /* keep multiple of 8 */ #define XCP_DOMAIN_BYTES 4 /* wire-encoding bytecount */ #define XCP_MAX_ADMINS 8 /* per domain; card has +1 */ #define XCP_MAX_KEYPARTS 20 /* per export/import call */ #define XCP_MIN_PINBYTES 8 #define XCP_MAX_PINBYTES 16 // // v1 PINs, LoginExtended(FIPS/2021), specific limits #define XCP_MIN_ALG1_PINBYTES ((size_t) 8) #define XCP_MAX_ALG1_PINBYTES ((size_t) 64) #define XCP_MAX_LXTD_CONTEXT_BYTES ((size_t) 128) /* addl.context */ // // max(...all possible PIN sizes...) #define XCP_MAX_ANY_PINBYTES XCP_MAX_ALG1_PINBYTES // ~arbitrary limit on acceptable admin. certificates // additional limits, such as transport-bytecount, may restrict further #define XCP_CERT_MAX_BYTES ((size_t) 12288) /* fits dil certs (8k + meta) */ #define XCP_CERTHASH_BYTES (256/8) /* hash or SKI of public key, or other hash-identified things; SHA-256 */ #define XCP_ADMCTR_BYTES ((size_t) (128/8)) /* card/domain admin transaction ctrs */ #define XCP_KEYCSUM_BYTES (256/8) /* full size of verification pattern */ /* maximum coordinate bytecount, NIST P or BP curves */ #define XCP_MAX_EC_COORD_BYTES ((size_t) 66) /* P-521-> 512+9 bits */ #define XCP_MIN_EC_CURVE_BITS 192 /* ^^^ increase this when policy moves beyond shorter curves */ #define XCP_MAX_EC_CURVE_BITS 521 #define XCP_MAX_DIL_SIGNATURE_BYTES 4668 /* max. length of dil. 8-7 sigs */ #define XCP_MAX_SINFO_META_BYTES 100 /* signer info framework bytes */ /* bytecount of raw (generic) keys, not key schedules */ #define MOD_MAX_SYMMKEY_BYTES 256 #define XCP_FCV_PUBLIC_BYTES ((size_t) 76) /* raw struct without signature */ /**/ /* note: entire signed packet, w/o key info, before Sentry */ /* Sentry and beyond, key info is no longer passed to card */ /**/ typedef enum { XCP_FCV_RSA_BYTES = (76+ 4096/8), /* RSA/4096 signature */ XCP_FCV_EC_BYTES = (76+ 2*66), /* ECDSA/P-521 */ XCP_FCV_MAX_BYTES = XCP_FCV_RSA_BYTES } XCP_FCV_Bytes_t; #define PKCS11_CHECKSUM_BYTES ((size_t) 3) #define XCP_KEYBITS_FIELD_BYTES ((size_t) 4) /* trailing big-endian bitcount field after UnwrapKey() checksum */ /* card(OA) signature bytecount: SKI-identified SignerInfo, * Non quantum safe: Must contain space for either: * - 4096-bit RSA signature, hash OID, encr. OID and SKI * - EC-P521 signature, hash OID, encr. OID and SKI */ #define XCP_RSPSIG_RSA (4096 / 8) #define XCP_RSPSIG_MAX_BYTES (XCP_MAX_SINFO_META_BYTES + \ XCP_RSPSIG_RSA) /* card(OA) signature bytecount: SKI-identified SignerInfo, * Quantum safe: Must contain space for: * - DIL signature, hash OID, encr. OID and SKI */ #define XCP_RSPSIG_QS_MAX_BYTES (XCP_MAX_SINFO_META_BYTES + \ XCP_MAX_DIL_SIGNATURE_BYTES) /* minimal padding for raw RSA enc/dec/sign/ver/wr/unwr * Used for example in CKM_RSA_PKCS. See RFC 2313 chapter 8 for a complete * description */ #define XCP_RSA_PKCS_MIN_PAD 11 /*=== audit events =======================================================*/ #define XCP_LOG_STATE_BYTES (256 /8) /* SHA-256-based hash chain */ #define XCP_LOG_HEADER_BYTE 0x42 /* event-record header, v0 */ #define XCP_LOGEV_SPEC (0xffff0000) /* indicates particular events, not generic event types/categories, */ /* if bits in this region are non-zero */ /* functionality categories: keep within uint16_t range */ #define XCP_LOGEV_QUERY 0 #define XCP_LOGEV_FUNCTION 1 #define XCP_LOGEV_ADMFUNCTION 2 #define XCP_LOGEV_STARTUP 3 #define XCP_LOGEV_SHUTDOWN 4 #define XCP_LOGEV_SELFTEST 5 #define XCP_LOGEV_DOM_IMPORT 6 /* import sec-relevant data to */ /* domain */ #define XCP_LOGEV_DOM_EXPORT 7 /* export sec-relevant data from */ /* domain */ #define XCP_LOGEV_FAILURE 8 #define XCP_LOGEV_GENERATE 9 #define XCP_LOGEV_REMOVE 10 #define XCP_LOGEV_SPECIFIC 11 /* obtain meaning elsewhere */ #define XCP_LOGEV_STATE_IMPORT 12 /* import to card/multiple domains */ #define XCP_LOGEV_STATE_EXPORT 13 /* export from card/multiple */ /* domains */ /* [after successful export] */ #define XCP_LOGEV_IMPORT 14 /* key/state import (UnwrapKey) */ /* fields provide more context */ #define XCP_LOGEV_EXPORT 15 /* key/state import (WrapKey) */ /* fields provide more context */ /*--- specific events (any including XCP_LOGEV_SPEC) ---------*/ #define XCP_LOGSPEV_TRANSACT_ZEROIZE (XCP_LOGEV_SPEC +1) /* zeroize card by transaction */ #define XCP_LOGSPEV_KAT_FAILED (XCP_LOGEV_SPEC +2) /* algorithm selftest failed */ #define XCP_LOGSPEV_KAT_COMPLETED (XCP_LOGEV_SPEC +3) /* algorithm selftests completed */ /* redundant; logged only to */ /* provide specific event */ #define XCP_LOGSPEV_EARLY_Q_START (XCP_LOGEV_SPEC +4) /* subsequent events were found */ /* in the early-event queue. */ /* their timestamps are only */ /* approximate; order is correct */ #define XCP_LOGSPEV_EARLY_Q_END (XCP_LOGEV_SPEC +5) /* early-even queue processing ends. */ /* subsequent events are through */ /* regular auditing, with valid */ /* timestamps and ordering. */ #define XCP_LOGSPEV_AUDIT_NEWCHAIN (XCP_LOGEV_SPEC +6) /* audit state is corrupted; removed. */ /* generating new instance and start */ /* new chain as a replacement */ #define XCP_LOGSPEV_TIMECHG_BEFORE (XCP_LOGEV_SPEC +7) /* time change: original time */ #define XCP_LOGSPEV_TIMECHG_AFTER (XCP_LOGEV_SPEC +8) /* time change: updated time */ #define XCP_LOGSPEV_MODSTIMPORT_START (XCP_LOGEV_SPEC +9) /* accepted full-state import */ /* data structure */ /* starting update procedure */ #define XCP_LOGSPEV_MODSTIMPORT_FAIL (XCP_LOGEV_SPEC +10) /* rejected import structure */ /* issued after initial verify; */ /* indicates some inconsistency */ /* of import data structures */ #define XCP_LOGSPEV_MODSTIMPORT_END (XCP_LOGEV_SPEC +11) /* completed full-state import */ #define XCP_LOGSPEV_MODSTEXPORT_START (XCP_LOGEV_SPEC +12) /* started full-state export */ /* see also: XCP_LOGEV_STATE_EXPORT */ #define XCP_LOGSPEV_MODSTEXPORT_FAIL (XCP_LOGEV_SPEC +13) typedef enum { XCP_LOGSYS_AUDIT = 1, /* audit infrastructure itself */ XCP_LOGSYS_CRYPTTEST = 2, /* cryptographic test operations */ /* such as known-answer tests */ XCP_LOGSYS_SELFTEST = 3, /* non-crypto tests */ XCP_LOGSYS_FULL = 4, /* full module functionality */ XCP_LOGSYS_WK = 5, /* one wrapping key (WK) */ XCP_LOGSYS_STATE = 6 /* all transportable module state */ } XCP_LogSystem_t; /* bitmask of audit-event flags (mainly optional fields) */ #define XCP_LOGFL_WK_PRESENT 0x80000000 #define XCP_LOGFL_COMPLIANCE_PRESENT 0x40000000 /* ...of hosting domain */ #define XCP_LOGFL_FINALWK_PRESENT 0x20000000 #define XCP_LOGFL_KEYREC0_PRESENT 0x10000000 #define XCP_LOGFL_KEYREC0_COMPL 0x08000000 /* key0 compliance */ #define XCP_LOGFL_KEYREC1_PRESENT 0x04000000 #define XCP_LOGFL_KEYREC2_PRESENT 0x02000000 #define XCP_LOGFL_FINTIME_PRESENT 0x01000000 #define XCP_LOGFL_SALT0_PRESENT 0x00800000 #define XCP_LOGFL_SALT1_PRESENT 0x00400000 #define XCP_LOGFL_SALT2_PRESENT 0x00200000 #define XCP_LOGFL_REASON_PRESENT 0x00100000 #define XCP_LOGFL_SEQPRF_PRESENT 0x00080000 //--- importer PK types ---------------------------------------------------- typedef enum { XCP_IMPRKEY_RSA_2048 = 0, XCP_IMPRKEY_RSA_4096 = 1, XCP_IMPRKEY_EC_P256 = 2, /* EC, NIST P-256 */ XCP_IMPRKEY_EC_P521 = 3, /* EC, NIST P-521 */ XCP_IMPRKEY_EC_BP256r = 4, /* EC, Brainpool BP-256r */ XCP_IMPRKEY_EC_BP320r = 5, /* EC, Brainpool BP-320r */ XCP_IMPRKEY_EC_BP512r = 6, /* EC, Brainpool BP-512r */ XCP_IMPRKEY_RSA_3072 = 7, XCP_IMPRKEY_EC_P521_TKE = 8, /* EC, NIST P-521 (TKE propr. sign.) */ XCP_IMPRKEY_MAX = XCP_IMPRKEY_EC_P521_TKE } XCP_IMPRKEY_t; //--- OA key types ---------------------------------------------------- typedef enum { XCP_OAKEY_RSA_4096 = 1, /* RSA 4096 bit */ XCP_OAKEY_ECC_P521 = 2, /* ECC NIST P-521 */ XCP_OAKEY_DIL_87R2 = 3, /* DIL 8-7 R2 */ XCP_OAKEY_MAX = XCP_OAKEY_DIL_87R2 } XCP_OAKEY_t; //--- retained key structures --------------------------- // initial loading: // NULL rkData means no refills; invalid with 0 credits // // serialized as: // nothing if structure is missing (i.e., no restrictions) // // credits [be32] if structure is present // rkdata [var ] // typedef struct CK_RETAINEDKEY_PARAMS { CK_ULONG credits; CK_VOID_PTR rkData; CK_ULONG rkdLen; } CK_RETAINEDKEY_PARAMS; //--- operation categories (perf. measurement) ----------------------------- typedef enum { XCP_OPCAT_ASYMM_SLOW = 1, XCP_OPCAT_ASYMM_FAST = 2, XCP_OPCAT_SYMM_PARTIAL = 3, /* including hashing */ XCP_OPCAT_SYMM_FULL = 4, /* including key generation/derivation */ XCP_OPCAT_ASYMM_GEN = 5, XCP_OPCAT_ASYMM_MAX = XCP_OPCAT_ASYMM_GEN } XCP_OPCAT_t; // //--- query sub-types ------------------------------------------------------ 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 */ /* 9 not used ----------------- */ CK_IBM_XCPQ_EC_CURVES = 10, /* supported elliptic curves, */ /* individual curves, bitmask */ /* see: XCP_ECcurve_t */ CK_IBM_XCPQ_COMPAT = 11, /* domains' compatibility modes */ CK_IBM_XCPQ_EC_CURVEGRPS = 12, /* supported elliptic curves, */ /* groups/categories, bitmask */ /* see: CK_IBM_ECCURVEQ_t */ CK_IBM_XCPQ_CP_BLACKLIST = 13, /* control point blacklist: */ /* control points which may */ /* never be enabled due to */ /* policy-minimum restrictions. */ CK_IBM_XCPQ_PQC_STRENGTHS = 14, /* supported quantum safe levels*/ /* of strength */ /* see: XCP_PQCStrength_t */ CK_IBM_XCPQ_LOGIN_IMPORTER = 15, /* current session importer key */ /* and it's transaction counter */ /* for given curve type */ /* see: XCP_ECCurve_t and */ /* CK_IBM_XCPXQ_LOGIN_KEYTYPES */ CK_IBM_XCPQ_COMPAT_ADM = 16, /* domains' administrative */ /* compatibility modes */ CK_IBM_XCPQ_MAX = CK_IBM_XCPQ_COMPAT_ADM } CK_IBM_XCPQUERY_t; //--- module sub-query sub-types -------------------------------------------- typedef enum { CK_IBM_XCPMSQ_DEFAULT = 0, /* zero indicates no sub-query */ CK_IBM_XCPMSQ_DESCRTEXT = 1, /* human-readable text/tokens */ CK_IBM_XCPMSQ_FNLIST = 2, /* supported function id bitmask*/ CK_IBM_XCPMSQ_FNS = 3, /* count of fn ids */ CK_IBM_XCPMSQ_MOD_V1 = 4, /* add version one fields to */ /* module query */ CK_IBM_XCPMSQ_ATTRLIST = 5, /* supported administrative */ /* attributes bitmask */ CK_IBM_XCPMSQ_ATTRS = 6, /* list of supported attribute */ /* bits (1 byte / attribute) */ /* administrative attributes */ CK_IBM_XCPMSQ_MOD_V2 = 7, /* add version two fields to */ /* module query */ CK_IBM_XCPMSQ_ATTRCOUNT = 8, /* number of supported */ /* administrative attributes */ CK_IBM_XCPMSQ_MAX = CK_IBM_XCPMSQ_ATTRCOUNT } CK_IBM_XCPMSUBQUERY_t; //--- selftest sub-query sub-types ------------------------------------------ typedef enum { CK_IBM_XCPSSQ_DEFAULT = 0, /* run non-failing POST tests */ CK_IBM_XCPSSQ_POST_F = 1, /* run failing POST tests */ } CK_IBM_XCPSSUBQUERY_t; // byte sizes of queries which are not represented as structures #define XCP_MSQ_FNLIST_SIZE 16 #define XCP_XCPMSQ_FNS_SIZE 1 #define XCP_XCPMSQ_ATTRCOUNT_SIZE 4 #define CK_IBM_XCP_HOSTQ_IDX 0xff000000 /* host-only queries index, min. */ #define CK_IBM_XCPHQ_COUNT 0xff000000 /* number of host-query indexes */ /* including this type itself */ #define CK_IBM_XCPHQ_VERSION 0xff000001 /* host-specific package version */ /* such as packaging library ID */ #define CK_IBM_XCPHQ_VERSION_HASH 0xff000002 /* assumed-unique identifier of */ /* host code, such as version- */ /* identifying cryptographic hash*/ /* (library signature field...) */ #define CK_IBM_XCPHQ_DIAGS 0xff000003 /* host code diagnostic level */ /* 0 if non-diagnostics host code*/ #define CK_IBM_XCPHQ_HVERSION 0xff000004 /* human-readable host version */ /* identification (recommended: */ /* UTF-8 string) */ #define CK_IBM_XCPHQ_TGT_MODE 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 */ #define CK_IBM_XCPHQ_ECDH_DERPRM 0xff000006 /* ECDH DeriveKey parameter usage*/ /* is being enforced with hostlib*/ /* version */ /**/ #define CK__IBM_XCPHQ_MAX CK_IBM_XCPHQ_TGT_MODE typedef enum { CK_IBM_XCPHQ_TGT_MODES_TGTGRP = 1, /* target groups are supported */ CK_IBM_XCPHQ_TGT_MODES_MAX = CK_IBM_XCPHQ_TGT_MODES_TGTGRP } CK_IBM_XCPHQ_TGT_MODES_t; typedef enum { CK_IBM_XCPXQ_AUDIT_EV_BYTES = 2, /* largest audit event, bytecount */ CK_IBM_XCPXQ_AUDIT_ENTRIES = 3, /* max. size of event history */ CK_IBM_XCPXQ_DEBUGLVL_MAX = 4, /* backend diagnostics granularity */ CK_IBM_XCPXQ_ERRINJECT_FREQ = 5, /* error-inject frequency N */ /* N calls fail in a million */ /* 0 for production releases, */ /* which do not error-injection */ CK_IBM_XCPXQ_MULTIDATA_N = 6, /* maximum number of supported */ /* sub-fields in multi-data */ /* requests. 0 if not supported, */ /* all-1's if no predefined limit. */ CK_IBM_XCPXQ_IMPEXP_CAPS = 7, /* capability for WK and state */ /* export / import. See 8.7.1.1.1 */ /* for more info */ CK_IBM_XCPXQ_CERT_MAXBYTES = 8, /* bytecount of largest accepted */ /* administrative certificate, if */ /* there is an upper limit. 0 if */ /* the backend does not enforce */ /* any specific limit of its own. */ CK_IBM_XCPXQ_MOD_COUNTERS = 9, /* number of module-internal dev */ /* counters supported, 0 if none */ CK_IBM_XCPXQ_MAX_SESSIONS = 12, CK_IBM_XCPXQ_AVAIL_SESSIONS = 13, /* maximum, currently available */ /* number of backend sessions */ CK_IBM_XCPXQ_BTC_CAP = 14, /* bit field for bitcoin related */ /* additions */ CK_IBM_XCPXQ_ECDSA_OTHER = 15, /* bitmask of supported, other EC signing mechanisms */ CK_IBM_XCPXQ_OA_CAP = 16, /* bitmask of supported outbound authority signing mechanisms */ CK_IBM_XCPXQ_LOGIN_ALG = 18, /* bitmask of login algorithms */ /* supported with LoginExtended */ CK_IBM_XCPXQ_LOGIN_ATTR0 = 19, /* bitmask of supported session */ /* attributes with Login Extended */ /* first double-word */ CK_IBM_XCPXQ_LOGIN_ATTR1 = 20, /* session attributes, 2nd DW */ #if 0 CK_IBM_XCPXQ_LOGIN_ATTR2 = 21, /* session attributes, 3rd DW */ CK_IBM_XCPXQ_LOGIN_ATTR3 = 22, /* session attributes, 4th DW */ #endif CK_IBM_XCPXQ_LOGIN_KEYTYPES = 23, /* bitmask of Login importer types */ /* supported for PIN encryption */ CK_IBM_XCPXQ_MAXIDX = CK_IBM_XCPXQ_LOGIN_KEYTYPES, } CK_IBM_XCPEXTCAP_t; #define CK_IBM_DOM_ADMIND 1 /* administrators present */ #define CK_IBM_DOM_CURR_WK 2 /* domain has current WK */ #define CK_IBM_DOM_NEXT_WK 4 /* domain has pending/next WK */ #define CK_IBM_DOM_COMMITTED_NWK 8 /* next WK is active(committed) */ #define CK_IBM_DOM_IMPRINTED 0x10 /* has left imprint mode */ #define CK_IBM_DOM_IMPRINTS 0x80000000 /* enforces imprint mode */ #define CK_IBM_DOM_PROTKEY_ALLOW 0x20 /* policies allow protected key */ // // note: CK_IBM_DOM_IMPRINTS will go away #define CK_IBM_DOM_ACTIVE \ (CK_IBM_DOM_ADMIND | \ CK_IBM_DOM_CURR_WK | \ CK_IBM_DOM_NEXT_WK | \ CK_IBM_DOM_COMMITTED_NWK | \ CK_IBM_DOM_IMPRINTED) typedef enum { CK_IBM_ECCURVE_NIST = 1, /* NIST P-curves P-192 to P-521 */ CK_IBM_ECCURVE_BPOOL = 2, /* Brainpool curves, regular+twisted */ /* BP160R to BP512T */ CK_IBM_ECCURVE_S256K1 = 4, /* secp256k1 (Bitcoin default) */ CK_IBM_ECCURVE_25519 = 8, /* curve25519 */ /* ECDH/sign vars (isomorphic curves) */ /* are not reported separately */ CK_IBM_ECCURVE_ED448 = 0x20, /* ed448 (Goldilocks) Edwards curve */ } CK_IBM_ECCURVEQ_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; #define CK_IBM_XCP_INFO_MEMBERS_V0 \ 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; #define CK_IBM_XCP_DESCINFO_MEMBER \ CK_CHAR manufacturerID[ 32 ]; \ CK_CHAR model[ 16 ]; #define CK_IBM_XCP_ADMATTRLIST_MEMBER \ CK_BYTE perm_modes[ 8 ]; \ CK_BYTE infra_modes[ 8 ]; \ CK_BYTE comp_modes[ 8 ]; #define CK_IBM_XCP_ADMATTRCOUNT_MEMBER \ CK_BYTE perm_count; \ CK_BYTE infra_count; \ CK_BYTE comp_count; #define CK_IBM_XCP_ADMATTRLIST_MEMBER_V2 \ CK_BYTE perm_ext01_modes[ 8 ]; #define CK_IBM_XCP_ADMATTRCOUNT_MEMBER_V2 \ CK_BYTE perm_ext01_count; #define CK_IBM_XCP_ADMATTRLIST_MEMBER_EXT \ CK_BYTE gen_ktype_modes[ 8 ]; \ CK_BYTE ecc_ktype_modes[ 8 ]; \ CK_BYTE dil_ktype_modes[ 8 ]; \ CK_BYTE adm_compl_modes[ 8 ]; #define CK_IBM_XCP_ADMATTRCOUNT_MEMBER_EXT \ CK_BYTE gen_ktype_count; \ CK_BYTE ecc_ktype_count; \ CK_BYTE dil_ktype_count; \ CK_BYTE adm_compl_count; // see chapter 5.1.1. in the wire spec typedef struct CK_IBM_XCP_INFO { CK_IBM_XCP_INFO_MEMBERS_V0 } CK_IBM_XCP_INFO; // // see chapter 5.1.1. in the wire spec typedef struct CK_IBM_XCP_INFO_V1 { CK_IBM_XCP_INFO_MEMBERS_V0 CK_IBM_XCP_DESCINFO_MEMBER CK_BYTE fnid_mask[ 16 ]; CK_BYTE fnid_count; CK_IBM_XCP_ADMATTRLIST_MEMBER CK_IBM_XCP_ADMATTRCOUNT_MEMBER } CK_IBM_XCP_INFO_V1; // // see chapter 5.1.1. in the wire spec typedef struct CK_IBM_XCP_INFO_V2 { CK_IBM_XCP_INFO_MEMBERS_V0 CK_IBM_XCP_DESCINFO_MEMBER CK_BYTE fnid_mask[ 16 ]; CK_BYTE fnid_count; CK_IBM_XCP_ADMATTRLIST_MEMBER CK_IBM_XCP_ADMATTRCOUNT_MEMBER CK_IBM_XCP_ADMATTRLIST_MEMBER_V2 CK_IBM_XCP_ADMATTRCOUNT_MEMBER_V2 } CK_IBM_XCP_INFO_V2; // // see chapter 5.1.1.1. in the wire spec typedef struct CK_IBM_XCP_DESCINFO { CK_IBM_XCP_DESCINFO_MEMBER } CK_IBM_XCP_DESCINFO; // // see chapter 5.1.1.3. in the wire spec typedef struct CK_IBM_XCP_ATTRLIST { CK_IBM_XCP_ADMATTRLIST_MEMBER CK_IBM_XCP_ADMATTRLIST_MEMBER_V2 CK_IBM_XCP_ADMATTRLIST_MEMBER_EXT } CK_IBM_XCP_ATTRLIST; // // see chapter 5.1.1.3. in the wire spec typedef struct CK_IBM_XCP_ATTRCOUNT { CK_IBM_XCP_ADMATTRCOUNT_MEMBER CK_IBM_XCP_ADMATTRCOUNT_MEMBER_V2 CK_IBM_XCP_ADMATTRCOUNT_MEMBER_EXT } CK_IBM_XCP_ATTRCOUNT; typedef struct CK_IBM_XCP_ATTRLIST_LGC { CK_IBM_XCP_ADMATTRLIST_MEMBER CK_IBM_XCP_ADMATTRLIST_MEMBER_V2 } CK_IBM_XCP_ATTRLIST_LGC; typedef struct CK_IBM_XCP_ATTRCOUNT_LGC { CK_IBM_XCP_ADMATTRCOUNT_MEMBER CK_IBM_XCP_ADMATTRCOUNT_MEMBER_V2 } CK_IBM_XCP_ATTRCOUNT_LGC; /**/ #define CK_IBM_XCP_INFO_INIT0 \ { 0,0, {0,0,},{0,0,}, {0,},{0,},{0,}, {0,},{0,}, \ 0,0, 0,0, 0,0,0,0,0,0,0, 0,0,0, } #define CK_IBM_XCP_INFO_V2_INIT0 \ { 0,0, {0,0,},{0,0,}, {0,},{0,},{0,}, {0,},{0,}, \ 0,0, 0,0, 0,0,0,0,0,0,0, 0,0,0, \ {0}, {0}, {0}, 0, {0}, {0}, {0}, 0, 0, 0, \ {0}, 0} typedef CK_IBM_XCP_INFO CK_PTR CK_IBM_XCP_INFO_PTR; typedef CK_IBM_XCP_INFO_V1 CK_PTR CK_IBM_XCP_INFO_V1_PTR; typedef CK_IBM_XCP_INFO_V2 CK_PTR CK_IBM_XCP_INFO_V2_PTR; typedef CK_IBM_XCP_DESCINFO CK_PTR CK_IBM_XCP_DESCINFO_PTR; typedef CK_IBM_XCP_ATTRLIST CK_PTR CK_IBM_XCP_ATTRLIST_PTR; typedef CK_IBM_XCP_ATTRCOUNT CK_PTR CK_IBM_XCP_ATTRCOUNT_PTR; 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; /**/ #define CK_IBM_DOMAIN_INFO_INIT0 { 0, { 0, }, { 0, }, 0, { 0, } } typedef CK_IBM_DOMAIN_INFO CK_PTR CK_IBM_DOMAIN_INFO_PTR; //--- BTC mechparams -------------------------------------------------- typedef struct CK_IBM_BTC_DERIVE_PARAMS { CK_ULONG type; CK_ULONG childKeyIndex; CK_BYTE_PTR pChainCode; CK_ULONG ulChainCodeLen; CK_ULONG version; } CK_IBM_BTC_DERIVE_PARAMS; typedef CK_IBM_BTC_DERIVE_PARAMS CK_PTR CK_IBM_BTC_DERIVE_PARAMS_PTR; // key index flag; hardened, i.e., keys cannot be used for pub2pub derivation #define CK_IBM_BIP0032_HARDENED (0x80000000) // sub-variants of BIP-0032 key derivation typedef enum { CK_IBM_BIP0032_PRV2PRV = 1, CK_IBM_BIP0032_PRV2PUB = 2, CK_IBM_BIP0032_PUB2PUB = 3, CK_IBM_BIP0032_MASTERK = 4, CK_IBM_SLIP0010_PRV2PRV = 5, CK_IBM_SLIP0010_PRV2PUB = 6, CK_IBM_SLIP0010_PUB2PUB = 7, CK_IBM_SLIP0010_MASTERK = 8, } CK_IBM_BTC_t; //--- ETH mechparams -------------------------------------------------- typedef struct CK_IBM_ETH_DERIVE_PARAMS { CK_ULONG version; CK_ULONG sigVersion; CK_ULONG type; CK_ULONG childKeyIndex; CK_BYTE_PTR pKeyInfo; CK_ULONG ulKeyInfoLen; } CK_IBM_ETH_DERIVE_PARAMS; typedef CK_IBM_ETH_DERIVE_PARAMS CK_PTR CK_IBM_ETH_DERIVE_PARAMS_PTR; // sub-variants of EIP-2333 key derivation typedef enum { CK_IBM_EIP2333_PRV2PRV = 1, CK_IBM_EIP2333_PRV2PUB = 2, CK_IBM_EIP2333_MASTERK = 3, } CK_IBM_ETH_t; typedef enum { XCP_KEM_ENCAPSULATE = 1, XCP_KEM_DECAPSULATE = 2, } XCP_KEM_t; typedef CK_ULONG CK_IBM_KEM_MODE; #define XCP_ML_KEM_DSA_MAX_SEED_BYTES 64 #define CK_IBM_KEM_ENCAPSULATE XCP_KEM_ENCAPSULATE #define CK_IBM_KEM_DECAPSULATE XCP_KEM_DECAPSULATE typedef struct XCP_KYBER_KEM_PARAMS { CK_ULONG version; CK_IBM_KEM_MODE mode; CK_ULONG kdf; CK_BBOOL prepend; CK_BYTE *pCipher; CK_ULONG ulCipherLen; CK_BYTE *pSharedData; CK_ULONG ulSharedDataLen; CK_BYTE *pBlob; CK_ULONG ulBlobLen; } XCP_KYBER_KEM_PARAMS_t; //--- Login Extended Information ------------------------------------------- // data types and constants related to LoginExtended and LogoutExtended // see wire spec 6.19 // currently known Login Algorithms for Session ID calculation typedef enum XCP_LoginAlgorithm { XCP_LOGIN_ALG_PRE_F2021 = 0, XCP_LOGIN_ALG_F2021 = 2, XCP_LOGIN_ALG_MAX = XCP_LOGIN_ALG_F2021 } XCP_LoginAlgorithm_t; typedef CK_ULONG CK_IBM_LOGIN_ALG; #define CK_IBM_LOGIN_ALG_PRE_F2021 XCP_LOGIN_ALG_PRE_F2021 #define CK_IBM_LOGIN_ALG_F2021 XCP_LOGIN_ALG_F2021 // currently known Login importer key types for encrypted PIN transport typedef enum XCP_LoginImporter { XCP_LOGIN_IMPR_EC_P256 = 1, /* EC, NIST P-256 */ XCP_LOGIN_IMPR_EC_P521 = 2, /* EC, NIST P-521 */ } XCP_LoginImporter_t; // maximum size of login importer structure, assuming DER encoding // and EC P-521 as maximum key // #define XCP_LOGIN_IMPR_MAX_SIZE (3 + (2 + XCP_CERTHASH_BYTES) \ + (3 + 158) \ + (2 + XCP_SESSION_TCTR_BYTES) ) // login session attributes, bit index typedef enum XCP_LoginAttribute { XCP_LOGIN_ATTR_SUPERVISOR = 0, XCP_LOGIN_ATTR_MIGRATION = 1, XCP_LOGIN_ATTR_VOLATILE = 2, XCP_LOGIN_ATTR_MAX = XCP_LOGIN_ATTR_VOLATILE, } XCP_LoginAttribute_t; #define CK_IBM_LOGIN_ATTR_SUPERVISOR XCP_LOGIN_ATTR_SUPERVISOR #define CK_IBM_LOGIN_ATTR_MIGRATION XCP_LOGIN_ATTR_MIGRATION #define CK_IBM_LOGIN_ATTR_VOLATILE XCP_LOGIN_ATTR_VOLATILE #define CK_IBM_LOGIN_ATTR_MAX XCP_LOGIN_ATTR_VOLATILE // login recipient structure typedef struct XCP_LoginRecipient { CK_BYTE recipient_ski[ XCP_CERTHASH_BYTES ]; CK_BYTE sender_spki; CK_ULONG spkilen; } XCP_LoginRecipient_t; // extended login information structure typedef struct XCP_LoginExtendedInfo { CK_BYTE *version; CK_ULONG verlen; CK_IBM_LOGIN_ALG algorithm; CK_BYTE parent[ XCP_WK_BYTES ]; XCP_LoginRecipient_t *recepient; CK_ULONG attributes; CK_BYTE context; CK_ULONG contlen; } XCP_LoginExtendedInfo_t; //--- attribute constants -------------------------------------------------- // typedef enum { XCP_BLOB_EXTRACTABLE = 1, // May be encrypted by other keys. // May not be reset. XCP_BLOB_NEVER_EXTRACTABLE = 2, // set if key was created non-extractable. // Set only initially, may not be // modified. XCP_BLOB_MODIFIABLE = 4, // attributes may be changed XCP_BLOB_NEVER_MODIFIABLE = 8, // object was created read-only. // Set only initially, may not be // modified. XCP_BLOB_RESTRICTABLE = 0x10, // attributes may be removed, but may not be // made more permissive. XCP_BLOB_LOCAL = 0x20, // was created inside this CSP, // was not imported. Set upon object // creation, may not be modified. XCP_BLOB_ATTRBOUND = 0x40, // may be transported only in // attribute-bound formats, // but not pure PKCS11 ones. // May not be modified. XCP_BLOB_USE_AS_DATA = 0x80, // raw key bytes may be input // to other processing as data, // such as hashed, or deriving // keys from them. XCP_BLOB_SIGN = 0x0100, // may generate signatures XCP_BLOB_SIGN_RECOVER = 0x0200, // may generate (asymmetric) // signatures with message recovery XCP_BLOB_DECRYPT = 0x0400, // may decrypt data XCP_BLOB_ENCRYPT = 0x0800, // may encrypt data XCP_BLOB_DERIVE = 0x1000, // may derive other keys XCP_BLOB_UNWRAP = 0x2000, // may decrypt (transport) other keys XCP_BLOB_WRAP = 0x4000, // may encrypt (transport) other keys XCP_BLOB_VERIFY = 0x8000, // may verify signatures XCP_BLOB_VERIFY_RECOVER = 0x010000, // may verify signatures and recover // signed messages XCP_BLOB_TRUSTED = 0x020000, // PKCS11 CKA_TRUSTED key XCP_BLOB_WRAP_W_TRUSTED = 0x040000, // needs CKA_TRUSTED KEK // note: _TRUSTED enforcement does not // provide security guarantees. We only // track it inside the HSM to assist hosts. XCP_BLOB_RETAINED = 0x080000, // blob resides within // backend, not (no longer) on host XCP_BLOB_ALWAYS_RETAINED = 0x100000, // blob has been generated // inside XCP_BLOB_PROTKEY_EXTRACTABLE = 0x200000, // May be imported as protected key. // May not be reset. XCP_BLOB_PROTKEY_NEVER_EXTRACTABLE = 0x400000, // set if key was created non-extractable // as a protected key. // Set only initially, may not be // modified. XCP_BLOB_BIT_MAX = XCP_BLOB_PROTKEY_NEVER_EXTRACTABLE } XCP_Attr_t; //--- control points ------------------------------------------------------- #define XCP_CPID_BYTES 8 /* bytecount in CP profiles */ /* if backend supports them */ #define XCP_CPBLOCK_BITS 128 /* handle CPs in this granularity */ /* CP sets get padded to multiple */ typedef enum { XCP_CPB_ADD_CPBS = 0, // allow activation of CP bits XCP_CPB_DELETE_CPBS = 1, // allow deactivation of CP bits // (remove both ADD_CPBs and DELETE_CPBs // to make unit read-only) XCP_CPB_SIGN_ASYMM = 2, // sign with private keys XCP_CPB_SIGN_SYMM = 3, // sign with HMAC or CMAC XCP_CPB_SIGVERIFY_SYMM = 4, // verify with HMAC or CMAC. // No asymmetric counterpart: one // may not restrict use of public keys. XCP_CPB_ENCRYPT_SYMM = 5, // encrypt with symmetric keys. // No asymmetric counterpart: one // may not restrict use of public keys. XCP_CPB_DECRYPT_ASYMM = 6, // decrypt with private keys XCP_CPB_DECRYPT_SYMM = 7, // decrypt with symmetric keys XCP_CPB_WRAP_ASYMM = 8, // key export with public keys XCP_CPB_WRAP_SYMM = 9, // key export with symmetric keys XCP_CPB_UNWRAP_ASYMM = 10, // key import with private keys XCP_CPB_UNWRAP_SYMM = 11, // key import with symmetric keys XCP_CPB_KEYGEN_ASYMM = 12, // generate asymmetric keypairs // (fn:GenerateKeyPair) XCP_CPB_KEYGEN_SYMM = 13, // generate or derive symmetric keys // including DSA or DH parameters XCP_CPB_RETAINKEYS = 14, // allow backend to save semi-retained keys XCP_CPB_SKIP_KEYTESTS = 15, // disable selftests on new asymmetric keys XCP_CPB_NON_ATTRBOUND = 16, // allow keywrap without attribute-binding XCP_CPB_MODIFY_OBJECTS = 17, // allow changes to objects (Booleans only) XCP_CPB_RNG_SEED = 18, // allow mixing external seed to RNG // backend may restrict further XCP_CPB_ALG_RAW_RSA = 19, // allow RSA private-key use without padding // (highly discouraged) XCP_CPB_ALG_NFIPS2009 = 20, // allow non-FIPS-approved algs (as of 2009) // including non-FIPS keysizes XCP_CPB_ALG_NBSI2009 = 21, // allow non-BSI algorithms (as of 2009) // including non-BSI keysizes XCP_CPB_KEYSZ_HMAC_ANY = 22, // don't enforce minimum keysize on HMAC // (allows keys shorter than half of digest) XCP_CPB_KEYSZ_BELOW80BIT = 23, // allow algorithms below 80-bit strength XCP_CPB_KEYSZ_80BIT = 24, // allow 80 to 111-bit algorithms XCP_CPB_KEYSZ_112BIT = 25, // allow 112 to 127-bit algorithms XCP_CPB_KEYSZ_128BIT = 26, // allow 128 to 191-bit algorithms XCP_CPB_KEYSZ_192BIT = 27, // allow 192 to 255-bit algorithms XCP_CPB_KEYSZ_256BIT = 28, // allow 256-bit algorithms XCP_CPB_KEYSZ_RSA65536 = 29, // allow RSA public exponents below 0x10001 XCP_CPB_ALG_RSA = 30, // RSA private-key or key-encrypt use XCP_CPB_ALG_DSA = 31, // DSA private-key use XCP_CPB_ALG_EC = 32, // EC private-key use (see CP on curves) XCP_CPB_ALG_EC_BPOOLCRV = 33, // Brainpool (E.U.) EC curves XCP_CPB_ALG_EC_NISTCRV = 34, // NIST/SECG EC curves XCP_CPB_ALG_NFIPS2011 = 35, // allow non-FIPS-approved algs (as of 2011) // including non-FIPS keysizes XCP_CPB_ALG_NBSI2011 = 36, // allow non-BSI algorithms (as of 2011) // including non-BSI keysizes XCP_CPB_USER_SET_TRUSTED = 37, // allow non-admin set TRUSTED on blob/SPKI XCP_CPB_ALG_SKIP_CROSSCHK = 38, // do not double-check sign/decrypt ops XCP_CPB_WRAP_CRYPT_KEYS = 39, // allow keys which can en/decrypt data // and also un/wrap other keys // (applies to both generation and use) XCP_CPB_SIGN_CRYPT_KEYS = 40, // allow keys which can en/decrypt data // and also sign/verify // (applies to both generation and use) XCP_CPB_WRAP_SIGN_KEYS = 41, // allow keys which can un/wrap data // and also sign/verify // (applies to both generation and use) XCP_CPB_USER_SET_ATTRBOUND = 42, // allow non-administrators to // mark public key objects ATTRBOUND XCP_CPB_ALLOW_PASSPHRASE = 43, // allow host to pass passprases, such as // PKCS12 data, in the clear XCP_CPB_WRAP_STRONGER_KEY = 44, // allow wrapping of stronger keys // by weaker keys XCP_CPB_WRAP_WITH_RAW_SPKI = 45, // allow wrapping with SPKIs without // MAC and attributes XCP_CPB_ALG_DH = 46, // Diffie-Hellman use (private keys) XCP_CPB_DERIVE = 47, // allow key derivation (symmetric+EC/DH) XCP_CPB_ALLOW_NONSESSION = 48, // allow use of blobs without sessions // i.e., key/session state not bound // to Login/Logout-controlled state XCP_CPB_ALG_EC_25519 = 55, // enable support of curve25519, // c448 and related algorithms // incl. EdDSA (ed25519 and ed448) XCP_CPB_ALG_EC_SECGCRV = 60, // Prime-field SECG EC curves excluding // those shared with NIST P-curves XCP_CPB_ALG_NBSI2017 = 61, // allow non-BSI algorithms (as of 2017) // including non-BSI keysizes // (fn:Sign/RSA) XCP_CPB_CPACF_PK = 64, // support data key generation and import // for protected key XCP_CPB_ALG_PQC = 65, // support for PQ algorithms (top CPB) XCP_CPB_BTC = 66, // enable BTC-related functionality // including blockchain, altcoins, and // digital assets XCP_CPB_ECDSA_OTHER = 67, // enable non-ECDSA/non-EdDSA elliptic // curve signature algorithms XCP_CPB_ALG_NFIPS2021 = 68, // allow non-FIPS-approved algs (2021) XCP_CPB_ALG_NFIPS2024 = 69, // allow non-FIPS-approved algs (2024) XCP_CPB_COMPAT_LEGACY_SHA3 = 70, // allow fall-back to non-standard // SHA3 defaults XCP_CPB_DSA_PARAMETER_GEN = 71, // allow DSA/PQG parameter generation XCP_CPB_DERIVE_NON_AB_KEYS = 72, // allow the derivation of a non-AB or raw // from an AB key. Only relevant if // XCP_CPB_NON_ATTRBOUND XCP_CPB_ALLOW_LOGIN_PRE_F2021 = 73, // allow usage of basic login sessions // or extended login sessions using // pre-FIPS2021-algorithms XCP_CPB_ALG_RSA_OAEP = 74, // allow RSA OAEP XCP_CPB_ALLOW_COMBINED_EXTRACT = 75, // allow creation and usage of keys // with both EXTRACTABLE and // PROTKEY_EXTRACTABLE attributes set XCP_CPB_ALG_EC_PAIRING_FRIENDLY = 76, XCP_CPB_ALG_DILITHIUM = 77, // support for pre-Standard dilithium XCP_CPB_ALG_KYBER = 78, // support for pre-Standard kyber XCP_CPB_ALG_ML_DSA = 79, // support for NIST 204 XCP_CPB_ALG_ML_KEM = 80, // support for NIST 203 XCP_CPBITS_MAX = XCP_CPB_ALG_ML_KEM // marks last used CPB } XCP_CPbit_t; // rounded CP count, multiple of XCP_CPBLOCK_BITS // integer bytes, by construction (CPBLOCK_BITS is) // #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 */ #define XCP_CPB__INVERT (XCP_CPCOUNT-1) /* reserve MS CP bit for negation */ /*--- CP checks --------------------*/ // // XCP_CPB_ADD_CPBS // - SetAttribute() // XCP_CPB_DELETE_CPBS // - SetAttribute() -- if attempting to set a previously unset attribute // XCP_CPB_SIGN_ASYMM // - SignSingle() -- private key blobs // - SignInit() -- private key blobs // XCP_CPB_SIGN_SYMM // - SignSingle() -- symmetric blobs // - SignInit() -- symmetric blobs // XCP_CPB_SIGVERIFY_SYMM // - VerifySingle() -- symmetric blobs // - VerifyInit() -- symmetric blobs // XCP_CPB_ENCRYPT_SYMM // - EncryptSingle() -- symmetric blobs // - EncryptInit() -- symmetric blobs // XCP_CPB_DECRYPT_ASYMM // - DecryptSingle() -- private key blobs // - DecryptInit() -- private key blobs // XCP_CPB_DECRYPT_SYMM // - DecryptSingle() -- symmetric blobs // - DecryptInit() -- symmetric blobs // XCP_CPB_WRAP_ASYMM // - WrapKey() -- SPKIs // XCP_CPB_WRAP_SYMM // - WrapKey() -- symmetric blobs // XCP_CPB_UNWRAP_ASYMM // - UnwrapKey() -- private key blobs // XCP_CPB_UNWRAP_SYMM // - UnwrapKey() -- symmetric blobs // XCP_CPB_KEYGEN_ASYMM // - GenerateKeyPair() // XCP_CPB_KEYGEN_SYMM // - GenerateKey() // - UnwrapKey() -- symmetric target // - DeriveKey() -- all targets, except openblockchain t-cert // -- derivation, are symmetric // XCP_CPB_RETAINKEYS // - WrapKey(), the form which turns blob into SRK (handle+object) // XCP_CPB_SKIP_KEYTESTS // - GenerateKeyPair() // - UnwrapKey() // -- note: this functionality can only be verified based on logs // -- it enables cross-checking opaque to the host // XCP_CPB_NON_ATTRBOUND // - WrapKey() -- when wrapping to non-AB form // - UnwrapKey() -- when accepting non-AB form // XCP_CPB_MODIFY_OBJECTS // - SetAttributeValue() -- globally, not just per object // XCP_CPB_RNG_SEED // - SeedRandom() // XCP_CPB_ALG_RAW_RSA // - SignSingle() -- RSA blobs // - Sign() -- RSA blobs // - DecryptSingle() -- RSA blobs // - Decrypt() -- RSA blobs // XCP_CPB_ALG_NFIPS2009 // - see NIST algorithms // XCP_CPB_ALG_NBSI2009 // - see BSI algorithms // XCP_CPB_KEYSZ_HMAC_ANY // - SignSingle() -- symmetric blobs with HMAC mech // - Sign() -- symmetric blobs with HMAC mech // - VerifySingle() -- symmetric blobs with HMAC mech // - Verify() -- symmetric blobs with HMAC mech // XCP_CPB_KEYSZ_BELOW80BIT // - see size restrictions // XCP_CPB_KEYSZ_80BIT // - see size restrictions // XCP_CPB_KEYSZ_112BIT // - see size restrictions // XCP_CPB_KEYSZ_128BIT // - see size restrictions // XCP_CPB_KEYSZ_192BIT // - see size restrictions // XCP_CPB_KEYSZ_256BIT // - see size restrictions // XCP_CPB_KEYSZ_RSA65536 // - GenerateKeyPair() // - UnwrapKey() // XCP_CPB_ALG_RSA // - GenerateKeyPair() -- CKK_RSA // - UnwrapKey() -- CKK_RSA // - SignSingle() -- RSA blobs // - Sign() -- RSA blobs // - VerifySingle() -- RSA blobs // - Verify() -- RSA blobs // XCP_CPB_ALG_DSA // - GenerateKeyPair() -- CKK_DSA // - UnwrapKey() -- CKK_DSA // - SignSingle() -- DSA blobs // - Sign() -- DSA blobs // XCP_CPB_ALG_EC // - GenerateKeyPair() -- CKK_EC // - UnwrapKey() -- CKK_EC // - SignSingle() -- EC blobs // - Sign() -- EC blobs // XCP_CPB_ALG_EC_BPOOLCRV // - GenerateKeyPair() -- CKK_EC with Brainpool curves // - UnwrapKey() -- CKK_EC with Brainpool curves // XCP_CPB_ALG_EC_NISTCRV // - GenerateKeyPair() -- CKK_EC with NIST curves // - UnwrapKey() -- CKK_EC with NIST curves // XCP_CPB_ALG_NFIPS2011 // - see NIST algorithms // XCP_CPB_ALG_NBSI2011 // - see BSI algorithms // XCP_CPB_USER_SET_TRUSTED // - SetAttributeValue() // XCP_CPB_ALG_SKIP_CROSSCHK // XCP_CPB_WRAP_CRYPT_KEYS // - unwrap_blob() -- all blob uses // XCP_CPB_SIGN_CRYPT_KEYS // - unwrap_blob() -- all blob uses // XCP_CPB_WRAP_SIGN_KEYS // - unwrap_blob() -- all blob uses // XCP_CPB_USER_SET_ATTRBOUND // - SetAttributeValue() // XCP_CPB_ALLOW_PASSPHRASE // - DeriveKey() // XCP_CPB_WRAP_STRONGER_KEY // - WrapKey() // - UnwrapKey() // XCP_CPB_WRAP_WITH_RAW_SPKI // - WrapKey() // /*-- /CP checks --------------------*/ /*--- administration -----------------------------------------------------*/ #define XCP_ADM_QUERY 0x10000 typedef enum { XCP_ADM_ADMIN_LOGIN = 1, // add admin certificate XCP_ADM_DOM_ADMIN_LOGIN = 2, // add domain admin certificate XCP_ADM_ADMIN_LOGOUT = 3, // revoke admin certificate XCP_ADM_DOM_ADMIN_LOGOUT = 4, // revoke domain admin certificate XCP_ADM_ADMIN_REPLACE = 5, // transition admin certificate XCP_ADM_DOM_ADMIN_REPLACE = 6, // transition domain admin certificate XCP_ADM_SET_ATTR = 7, // set card attribute/s XCP_ADM_DOM_SET_ATTR = 8, // set domain attribute/ XCP_ADM_GEN_DOM_IMPORTER = 9, // generate new importer (PK) key XCP_ADM_GEN_WK = 10, // create random domain WK XCP_ADM_EXPORT_WK = 11, // wrap+output WK or parts XCP_ADM_EXPORT_NEXT_WK = 38, // wrap+output next WK or parts XCP_ADM_IMPORT_WK = 12, // set (set of) WK (parts) to pending XCP_ADM_COMMIT_WK = 13, // activate pending WK XCP_ADM_FINALIZE_WK = 14, // remove previous WK's XCP_ADM_ZEROIZE = 15, // release CSPs from entire module XCP_ADM_DOM_ZEROIZE = 16, // release CSPs from domain/s XCP_ADM_DOM_CTRLPOINT_SET = 17, // fix domain control points XCP_ADM_DOM_CTRLPOINT_ADD = 18, // enable domain control points XCP_ADM_DOM_CTRLPOINT_DEL = 19, // disable domain control points XCP_ADM_SET_CLOCK = 20, // set module-internal UTC time XCP_ADM_SET_FCV = 21, // set function-control vector XCP_ADM_CTRLPOINT_SET = 22, // fix card control points XCP_ADM_CTRLPOINT_ADD = 23, // enable card control points XCP_ADM_CTRLPOINT_DEL = 24, // disable card control points XCP_ADM_REENCRYPT = 25, // transform blobs to next WK XCP_ADM_RK_REMOVE = 26, // remove (semi-) retained key XCP_ADM_CLEAR_WK = 27, // erase current WK XCP_ADM_CLEAR_NEXT_WK = 28, // erase pending WK XCP_ADM_SYSTEM_ZEROIZE = 29, // card zeroize, preserving system // key, if it is present XCP_ADM_EXPORT_STATE = 30, // create card state backup XCP_ADM_IMPORT_STATE = 31, // import card state backup (part) XCP_ADM_COMMIT_STATE = 32, // activate imported card state XCP_ADM_REMOVE_STATE = 33, // purge import/export state backup XCP_ADM_GEN_MODULE_IMPORTER= 34, // generate new importer (PK) key XCP_ADM_SET_TRUSTED = 35, // activate TRUSTED attribute on // blob/SPKI XCP_ADM_DOMAINS_ZEROIZE = 36, // multi-domain zeroize // XCP_ADM_EXPORT_NEXT_WK = 38, // placeholder, find real entry above XCP_ADM_SESSION_REMOVE = 39, // remove all or selected sessions XCP_ADMQ_ADMIN = 1 | XCP_ADM_QUERY, // admin SKI/cert XCP_ADMQ_DOMADMIN = 2 | XCP_ADM_QUERY, // domain adm. SKI/cert XCP_ADMQ_DEVICE_CERT = 3 | XCP_ADM_QUERY, // module CA (OA) cert XCP_ADMQ_DOM_IMPORTER_CERT = 4 | XCP_ADM_QUERY, // dom WK importer XCP_ADMQ_CTRLPOINTS = 5 | XCP_ADM_QUERY, // card CP XCP_ADMQ_DOM_CTRLPOINTS = 6 | XCP_ADM_QUERY, // domain CP XCP_ADMQ_WK = 7 | XCP_ADM_QUERY, // current WK XCP_ADMQ_NEXT_WK = 8 | XCP_ADM_QUERY, // pending WK XCP_ADMQ_ATTRS = 9 | XCP_ADM_QUERY, // card attributes XCP_ADMQ_DOM_ATTRS = 10 | XCP_ADM_QUERY, // domain attributes XCP_ADMQ_FCV = 11 | XCP_ADM_QUERY, // public parts of FCV XCP_ADMQ_WK_ORIGINS = 12 | XCP_ADM_QUERY, // information on original WK // components (keyparts // verification patterns) XCP_ADMQ_RKLIST = 13 | XCP_ADM_QUERY, // retained-key id list XCP_ADMQ_INTERNAL_STATE = 14 | XCP_ADM_QUERY, // (part of) import/export state(file) XCP_ADMQ_IMPORTER_CERT = 15 | XCP_ADM_QUERY, // current migration importer XCP_ADMQ_AUDIT_STATE = 16 | XCP_ADM_QUERY, // audit state entry or event count XCP_ADMQ_LASTCMD_DOM_MASK = 17 | XCP_ADM_QUERY, // domain-bitmask affected by last // state-related administrative // command (export, import) XCP_ADMQ_SVCADMIN = 18 | XCP_ADM_QUERY, // svc admin SKI/cert XCP_ADMQ_LOGIN_IMPORTER = 19 | XCP_ADM_QUERY, // session importer key } XCP_Admcmd_t; typedef enum { XCP_ADMINT_SIGN_THR = 1, // signature threshold XCP_ADMINT_REVOKE_THR = 2, // revocation (signature) threshold XCP_ADMINT_PERMS = 3, // permissions XCP_ADMINT_MODE = 4, // operating mode XCP_ADMINT_STD = 5, // standards' compliance XCP_ADMINT_PERMS_EXT01 = 6, // permissions (extension #1) XCP_ADMINT_GEN_KTYPES = 7, // generic keytypes XCP_ADMINT_ECC_KTYPES = 8, // ECC curve types XCP_ADMINT_DIL_KTYPES = 9, // Dilithium types XCP_ADMINT_ADM_COMPL = 10, // administrative compliance XCP_ADMINT_IDX_MAX = XCP_ADMINT_ADM_COMPL } XCP_AdmAttr_t; #define XCP_ADMIN_ATTRIBUTE_COUNT XCP_ADMINT_IDX_MAX // init-time value #define XCP_ADM_SIGTHR__DEFAULT 0 #define XCP_ADM_REVTHR__DEFAULT 0 // permissions #define XCP_ADMP_WK_IMPORT 1 // allow WK import #define XCP_ADMP_WK_EXPORT 2 // allow WK export #define XCP_ADMP_WK_1PART 4 // allow WK transport in one part #define XCP_ADMP_WK_RANDOM 8 // allow internally generated WK #define XCP_ADMP_1SIGN 0x10 // allow single-signed administration // (threshold set to 1) #define XCP_ADMP_CP_1SIGN 0x20 // allow single-signed CP modification #define XCP_ADMP_ZERO_1SIGN 0x40 // allow single-signed zeroize // #define XCP_ADMP_NO_DOMAIN_IMPRINT \ 0x0080 // prohibit logging in to domains in // imprint mode (card only) #define XCP_ADMP_STATE_IMPORT 0x0100 // allow state (part) import // (ignored by domains) #define XCP_ADMP_STATE_EXPORT 0x0200 // allow state (part) export // (ignored by domains) #define XCP_ADMP_STATE_1PART 0x0400 // allow state transport with 1-part // key (ignored by domains) #define XCP_ADMP_DO_NOT_DISTURB 0x2000 // do not count module-administrator // signatures for domain commands, // other than zeroize commands // (managed but ignored for module- // level attributes) // // if adding other change-control bits, also update: // #define XCP_ADMP_CHG_WK_IMPORT 0x10000 // allow changing WK import flag #define XCP_ADMP_CHG_WK_EXPORT 0x20000 // allow changing WK export flag #define XCP_ADMP_CHG_WK_1PART 0x40000 // allow changing WK 1-part // transport flag #define XCP_ADMP_CHG_WK_RANDOM 0x80000 // allow changing internal WK flag #define XCP_ADMP_CHG_SIGN_THR 0x100000 // allow changing sign threshold #define XCP_ADMP_CHG_REVOKE_THR 0x200000 // allow changing revoke threshold #define XCP_ADMP_CHG_1SIGN 0x400000 // allow changing single-sign // threshold setting #define XCP_ADMP_CHG_CP_1SIGN 0x800000 // allow changing 1-sign (CPs) #define XCP_ADMP_CHG_ZERO_1SIGN \ 0x01000000 // allow changing 1-sign (zeroize) #define XCP_ADMP_CHG_ST_IMPORT \ 0x02000000 // allow changing state import bit // (ignored by domains) #define XCP_ADMP_CHG_ST_EXPORT \ 0x04000000 // allow changing state export bit // (ignored by domains) #define XCP_ADMP_CHG_ST_1PART 0x08000000 // allow changing 1-part encrypt bit // (ignored by domains) #define XCP_ADMP_CHG_DO_NOT_DISTURB \ 0x80000000 // allow changing the corresponding // Do Not Disturb bit // // permissions (extension 01) // #define XCP_ADMP_NQS_OA_SIGNATURES 1 // enable non-quantum-safe OA signat. #define XCP_ADMP_QS_OA_SIGNATURES 2 // enable quantum-safe OA signatures #define XCP_ADMP_NQS_ADM_SIGNATURES 4 // enable non-quantum-safe adm signat. #define XCP_ADMP_QS_ADM_SIGNATURES 8 // enable quantum-safe adm signatures #define XCP_ADMP_CHG_NQS_OA_SIGNATURES \ 0x10000 // allow changing the corresponding // non-quantum-safe OA signature bit #define XCP_ADMP_CHG_QS_OA_SIGNATURES \ 0x20000 // allow changing the corresponding // quantum-safe OA signature bit #define XCP_ADMP_CHG_NQS_ADM_SIGNATURES \ 0x40000 // allow changing the corresponding // non-quantum-safe adm signature bit #define XCP_ADMP_CHG_QS_ADM_SIGNATURES \ 0x80000 // allow changing the corresponding // quantum-safe adm signature bit // // generic administrative keytypes // #define XCP_ADMK_KTYPE_RSA 1 // enable admin key type RSA #define XCP_ADMK_KTYPE_ECC 2 // enable admin key type EC #define XCP_ADMK_KTYPE_DIL 4 // enable admin key type Dilithium #define XCP_ADMK_CHG_KTYPE_RSA 0x10000 // allow changing the corresponding // adm key type RSA #define XCP_ADMK_CHG_KTYPE_ECC \ 0x20000 // allow changing the corresponding // adm key type EC #define XCP_ADMK_CHG_KTYPE_DIL \ 0x40000 // allow changing the corresponding // adm key type Dilithium #define XCP_ADMK__ALL \ (XCP_ADMK_KTYPE_RSA | \ XCP_ADMK_KTYPE_ECC | \ XCP_ADMK_KTYPE_DIL) #define XCP_ADMK__CHGBITS \ (XCP_ADMK_CHG_KTYPE_RSA | \ XCP_ADMK_CHG_KTYPE_ECC | \ XCP_ADMK_CHG_KTYPE_DIL) #define XCP_ADMK__DEFAULT \ (XCP_ADMK__CHGBITS | \ XCP_ADMK__ALL) #define XCP__ADMK_SUP XCP_ADMK__DEFAULT // // supported administrative curve types // (depends on XCP_ADMK_KTYPE_ECC) // #define XCP_ADME_KTYPE_ECC_NIST 1 // enable admin key type EC NIST #define XCP_ADME_KTYPE_ECC_BP 2 // enable admin key type EC Brainpool #define XCP_ADME_KTYPE_ECC_ED 4 // enable admin key type EC Edwards #define XCP_ADME_KTYPE_ECC_MG 8 // enable admin key type EC Montgomery #define XCP_ADME_CHG_KTYPE_ECC_NIST \ 0x10000 // allow changing the corresponding // adm key type EC NIST #define XCP_ADME_CHG_KTYPE_ECC_BP \ 0x20000 // allow changing the corresponding // adm key type EC Brainpool #define XCP_ADME_CHG_KTYPE_ECC_ED \ 0x40000 // allow changing the corresponding // adm key type EC Edwards #define XCP_ADME_CHG_KTYPE_ECC_MG \ 0x80000 // allow changing the corresponding // adm key type EC Montgomery #define XCP_ADME__ALL \ (XCP_ADME_KTYPE_ECC_NIST | \ XCP_ADME_KTYPE_ECC_BP | \ XCP_ADME_KTYPE_ECC_ED) #define XCP_ADME__CHGBITS \ (XCP_ADME_CHG_KTYPE_ECC_NIST | \ XCP_ADME_CHG_KTYPE_ECC_BP | \ XCP_ADME_CHG_KTYPE_ECC_ED) #define XCP_ADME__DEFAULT \ (XCP_ADME__CHGBITS | \ XCP_ADME__ALL) #define XCP__ADME_SUP XCP_ADME__DEFAULT // // supported administrative DIL types // (depends on XCP_ADMK_KTYPE_DIL) // #define XCP_ADMQ_KTYPE_DIL_R2 1 // enable admin key type Dilithium R2 #define XCP_ADMQ_KTYPE_DIL_R3 2 // enable admin key type Dilithium R3 #define XCP_ADMQ_CHG_KTYPE_DIL_R2 \ 0x10000 // allow changing the corresponding // adm key type Dilithium R2 #define XCP_ADMQ_CHG_KTYPE_DIL_R3 \ 0x20000 // allow changing the corresponding // adm key type Dilithium R3 #define XCP_ADMQ__ALL \ (XCP_ADMQ_KTYPE_DIL_R2 | \ XCP_ADMQ_KTYPE_DIL_R3) #define XCP_ADMQ__CHGBITS \ (XCP_ADMQ_CHG_KTYPE_DIL_R2 | \ XCP_ADMQ_CHG_KTYPE_DIL_R3) #define XCP_ADMQ__DEFAULT \ (XCP_ADMQ__CHGBITS | \ XCP_ADMQ__ALL) #define XCP__ADMQ_SUP XCP_ADMQ__DEFAULT // // Administrative compliance // #define XCP_ADMC_ADM_FIPS2021 1 // NIST SP800-131A REV.2, 2021.01.01 // // if adding other change-control bits, also update: // prevented_perm_changes() // valid_attr_reactivate() // ...as well as constants below // #define XCP_ADMP__CHGBITS \ (XCP_ADMP_CHG_WK_IMPORT | \ XCP_ADMP_CHG_WK_EXPORT | \ XCP_ADMP_CHG_WK_1PART | \ XCP_ADMP_CHG_WK_RANDOM | \ XCP_ADMP_CHG_SIGN_THR | \ XCP_ADMP_CHG_REVOKE_THR | \ XCP_ADMP_CHG_1SIGN | \ XCP_ADMP_CHG_CP_1SIGN | \ XCP_ADMP_CHG_ZERO_1SIGN | \ XCP_ADMP_CHG_ST_IMPORT | \ XCP_ADMP_CHG_ST_EXPORT | \ XCP_ADMP_CHG_ST_1PART | \ XCP_ADMP_CHG_DO_NOT_DISTURB) // #define XCP_ADMP__PERMS \ (XCP_ADMP_WK_IMPORT | \ XCP_ADMP_WK_EXPORT | \ XCP_ADMP_WK_1PART | \ XCP_ADMP_WK_RANDOM | \ XCP_ADMP_1SIGN | \ XCP_ADMP_CP_1SIGN | \ XCP_ADMP_ZERO_1SIGN | \ XCP_ADMP_NO_DOMAIN_IMPRINT | \ XCP_ADMP_STATE_IMPORT | \ XCP_ADMP_STATE_EXPORT | \ XCP_ADMP_STATE_1PART | \ XCP_ADMP_DO_NOT_DISTURB) // // CHGBITS / PERMS (extension 01) #define XCP_ADMP__CHGBITS_EXT01 \ (XCP_ADMP_CHG_NQS_OA_SIGNATURES | \ XCP_ADMP_CHG_QS_OA_SIGNATURES | \ XCP_ADMP_CHG_NQS_ADM_SIGNATURES | \ XCP_ADMP_CHG_QS_ADM_SIGNATURES) // #define XCP_ADMP__PERMS_EXT01 \ (XCP_ADMP_NQS_OA_SIGNATURES | \ XCP_ADMP_QS_OA_SIGNATURES | \ XCP_ADMP_NQS_ADM_SIGNATURES | \ XCP_ADMP_QS_ADM_SIGNATURES) // #define XCP__ADMP_SUP_EXT01 (XCP_ADMP__PERMS_EXT01 | \ XCP_ADMP__CHGBITS_EXT01) // // #define XCP_ADMP__DEFAULT \ (XCP_ADMP_WK_IMPORT | \ XCP_ADMP_1SIGN | \ XCP_ADMP__CHGBITS) // #define XCP_ADMP__DEFAULT_EXT01 \ (XCP_ADMP__CHGBITS_EXT01 | \ XCP_ADMP_NQS_OA_SIGNATURES | \ XCP_ADMP_QS_OA_SIGNATURES | \ XCP_ADMP_NQS_ADM_SIGNATURES | \ XCP_ADMP_QS_ADM_SIGNATURES) // #define XCPM_ADMP__MODULE_DEFAULTS_MASK \ (XCP_ADMP_DO_NOT_DISTURB | \ XCP_ADMP_CHG_DO_NOT_DISTURB) // #define XCPM_ADMP__MODULE_DEFAULTS_MASK_EXT01 \ (XCP_ADMP_NQS_OA_SIGNATURES | \ XCP_ADMP_CHG_NQS_OA_SIGNATURES | \ XCP_ADMP_QS_OA_SIGNATURES | \ XCP_ADMP_CHG_QS_OA_SIGNATURES | \ XCP_ADMP_NQS_ADM_SIGNATURES | \ XCP_ADMP_CHG_NQS_ADM_SIGNATURES | \ XCP_ADMP_QS_ADM_SIGNATURES | \ XCP_ADMP_CHG_QS_ADM_SIGNATURES) // #define XCP_ADMP__CARD_MASK \ ~(XCP_ADMP_WK_IMPORT | \ XCP_ADMP_WK_EXPORT | \ XCP_ADMP_WK_1PART | \ XCP_ADMP_WK_RANDOM | \ XCP_ADMP_CP_1SIGN | \ XCP_ADMP_CHG_WK_IMPORT | \ XCP_ADMP_CHG_WK_EXPORT | \ XCP_ADMP_CHG_WK_1PART | \ XCP_ADMP_CHG_WK_RANDOM | \ XCP_ADMP_CHG_CP_1SIGN) // #define XCP_ADMP__CARD_MASK_EXT01 \ ~(0U) // #define XCP_ADMP__DOM_MASK \ ~(XCP_ADMP_NO_DOMAIN_IMPRINT | \ XCP_ADMP_STATE_IMPORT | \ XCP_ADMP_STATE_EXPORT | \ XCP_ADMP_STATE_1PART | \ XCP_ADMP_CHG_ST_IMPORT | \ XCP_ADMP_CHG_ST_EXPORT | \ XCP_ADMP_CHG_ST_1PART) // #define XCP_ADMP__DOM_MASK_EXT01 \ ~(0U) // #define XCP__ADMP_SUP ((XCP_ADMP__PERMS | XCP_ADMP__CHGBITS) &\ ~XCP_ADMP_NOT_SUP) // card modes #define XCP_ADMM_AUTHENTICATED 1U // no longer in imprint mode #define XCP_ADMM_EXTWNG 2U // zeroize if starting w/ ext. // warning included in default setup // // minimum administrator strength #define XCP_ADMM_STR_112BIT 4U // require 112+ bits' admin strength #define XCP_ADMM_STR_128BIT 8U // require 128+ bits' admin strength #define XCP_ADMM_STR_160BIT 0x10U // require 160+ bits' admin strength #define XCP_ADMM_STR_192BIT 0x20U // require 192+ bits' admin strength #define XCP_ADMM_STR_256BIT 0x40U // require 256 bits' admin strength #define XCP_ADMM_WKCLEAN_EXTWNG 0x80U // zeroize WKs if starting with // ext. warning set. Leaves // other parameters unaffected #define XCP_ADMM_BATT_LOW 0x0100U // module reports low battery // (read only) #define XCP_ADMM_API_ACTIVE 0x0200U // remove to disable XCP within card // // change-control bits #define XCP_ADMM_CHG_KEYSTR 0x040000 // change key strength bits (112-256) // #define XCP_ADMM__DEFAULT \ (XCP_ADMM_EXTWNG | \ XCP_ADMM_API_ACTIVE | \ XCP_ADMM_CHG_KEYSTR) // // all defined attributes #define XCP_ADMM__MASK \ (XCP_ADMM_AUTHENTICATED | \ XCP_ADMM_EXTWNG | \ XCP_ADMM_STR_112BIT | \ XCP_ADMM_STR_128BIT | \ XCP_ADMM_STR_160BIT | \ XCP_ADMM_STR_192BIT | \ XCP_ADMM_STR_256BIT | \ XCP_ADMM_WKCLEAN_EXTWNG | \ XCP_ADMM_BATT_LOW | \ XCP_ADMM_API_ACTIVE | \ XCP_ADMM_CHG_KEYSTR) // // infrastructure modes read only on domain level #define XCP_ADMM__CARD_ONLY_ATTR \ (XCP_ADMM_EXTWNG | \ XCP_ADMM_WKCLEAN_EXTWNG | \ XCP_ADMM_API_ACTIVE) // #define XCP_ADMM__READ_ONLY_ATTR \ (XCP_ADMM_AUTHENTICATED | \ XCP_ADMM_BATT_LOW) // strength bits restrict adm key strength #define XCP__ADMM_ADMSTR \ (XCP_ADMM_STR_112BIT | \ XCP_ADMM_STR_128BIT | \ XCP_ADMM_STR_160BIT | \ XCP_ADMM_STR_192BIT | \ XCP_ADMM_STR_256BIT) #define XCP__ADMM_SUP XCP_ADMM__MASK // specific standards' compliance suites #define XCP_ADMS_FIPS2009 1 // NIST, 80+ bits, -2011.01.01. #define XCP_ADMS_BSI2009 2 // BSI , 80+ bits, -2011.01.01. #define XCP_ADMS_FIPS2011 4 // NIST, 112+ bits, 2011.01.01.- #define XCP_ADMS_BSI2011 8 // BSI, 112+ bits, 2011.01.01.- // // two bits reserved but not yet reported #define XCP_ADMS_SIGG_IMPORT 0x10 // .de SigG, key import #define XCP_ADMS_SIGG 0x20 // .de SigG, no key import // #define XCP_ADMS_BSICC2017 0x40 // BSI, EP11 Common Criteria EAL4 2017 // #define XCP_ADMS_FIPS2021 0x80 // NIST SP800-131A REV.2, 2021.01.01 #define XCP_ADMS_FIPS2024 0x100 // NIST SP800-131A REV.2, 2024.01.01 #define XCP_ADMS__ALL \ (XCP_ADMS_FIPS2009 | \ XCP_ADMS_BSI2009 | \ XCP_ADMS_FIPS2011 | \ XCP_ADMS_BSI2011 | \ XCP_ADMS_BSICC2017 | \ XCP_ADMS_FIPS2021 | \ XCP_ADMS_FIPS2024) #define XCP_ADMC__ALL \ (XCP_ADMC_ADM_FIPS2021) // The following 'legacy' defines are used as default 'supported bit masks' // for older devices that do not have native bit masks for that purpose. // Note: If supported bits are not present, the import of these bits are // skipped and the default values will be kept. #define XCP__ADMP_SUP_LEGACY \ (XCP_ADMP_WK_IMPORT | \ XCP_ADMP_WK_EXPORT | \ XCP_ADMP_WK_1PART | \ XCP_ADMP_WK_RANDOM | \ XCP_ADMP_1SIGN | \ XCP_ADMP_CP_1SIGN | \ XCP_ADMP_ZERO_1SIGN | \ XCP_ADMP_NO_DOMAIN_IMPRINT | \ XCP_ADMP_STATE_IMPORT | \ XCP_ADMP_STATE_EXPORT | \ XCP_ADMP_STATE_1PART | \ XCP_ADMP_CHG_WK_IMPORT | \ XCP_ADMP_CHG_WK_EXPORT | \ XCP_ADMP_CHG_WK_1PART | \ XCP_ADMP_CHG_WK_RANDOM | \ XCP_ADMP_CHG_SIGN_THR | \ XCP_ADMP_CHG_REVOKE_THR | \ XCP_ADMP_CHG_1SIGN | \ XCP_ADMP_CHG_CP_1SIGN | \ XCP_ADMP_CHG_ZERO_1SIGN | \ XCP_ADMP_CHG_ST_IMPORT | \ XCP_ADMP_CHG_ST_EXPORT | \ XCP_ADMP_CHG_ST_1PART) #define XCP__ADMM_SUP_LEGACY \ (XCP_ADMM_AUTHENTICATED | \ XCP_ADMM_EXTWNG | \ XCP__ADMM_ADMSTR | \ XCP_ADMM_WKCLEAN_EXTWNG | \ XCP_ADMM_BATT_LOW | \ XCP_ADMM_API_ACTIVE) #define XCP_ADMS__ALL_LEGACY \ (XCP_ADMS_FIPS2009 | \ XCP_ADMS_BSI2009 | \ XCP_ADMS_FIPS2011 | \ XCP_ADMS_BSI2011 | \ XCP_ADMS_BSICC2017) #define XCP__ADMP_SUP_EXT01_LEGACY \ (XCP_ADMP_NQS_OA_SIGNATURES | \ XCP_ADMP_QS_OA_SIGNATURES | \ XCP_ADMP_CHG_NQS_OA_SIGNATURES | \ XCP_ADMP_CHG_QS_OA_SIGNATURES | \ XCP_ADMP_NQS_ADM_SIGNATURES | \ XCP_ADMP_QS_ADM_SIGNATURES | \ XCP_ADMP_CHG_NQS_ADM_SIGNATURES | \ XCP_ADMP_CHG_QS_ADM_SIGNATURES) // has compliance any BSI mode #define XCP_ADMS_IS_BSI(mode) (!!((mode) & (XCP_ADMS_BSI2009 | \ XCP_ADMS_BSI2011 | \ XCP_ADMS_BSICC2017 )) ) // mask of supported import keys // 3k and 4k RSA are not supported #define XCP_ADM_IMPEXP_KEYS__MASK \ ((1 << XCP_IMPRKEY_RSA_2048) | \ (1 << XCP_IMPRKEY_EC_P256) | \ (1 << XCP_IMPRKEY_EC_P521) | \ (1 << XCP_IMPRKEY_EC_BP256r) | \ (1 << XCP_IMPRKEY_EC_BP320r) | \ (1 << XCP_IMPRKEY_EC_BP512r) | \ (1 << XCP_IMPRKEY_EC_P521_TKE)) /*--- audit chains -------------------------------------------------------*/ #define XCP_LOG_KEYREC_BYTES 24 #define XCP_LOG_SEQNR_BYTES 6 #define XCP_LOG_INSTANCEID_BYTES 2 #define XCP_LOG_TIMET_BYTES (4+2) /* sec[36](time_t) || msec[12] */ #define XCP_LOG_SEQNR_OFFSET ((size_t) 4) /* in fixed event header */ #define XCP_LOG_SEQPRF_BASE_BYTES \ ((size_t) XCP_LOG_SEQNR_BYTES +XCP_LOG_TIMET_BYTES) #define XCP_LOG_COMPLIANCE_BYTES 8 #define XCP_LOG_REASON_BYTES 4 #define XCP_LOG_SALTUNIT_BYTES 4 #define XCP_LOG_SALT_MAX_UNITS 3 #define XCP_LOG_SALT_MAX_BYTES \ (XCP_LOG_SALT_MAX_UNITS * XCP_LOG_SALTUNIT_BYTES) #define XCP_LOG_PRFSALT_BYTES ((size_t) 64/8) /* Siphash-2-4 */ /* event context: fields present in all audit records */ #define XCP_LOG_CONTEXT_BYTES \ (2* XCP_SERIALNR_CHARS+ \ 2+2+ /* audit instance, event type */ \ 4+4+ /* event type, firmware ID */ \ 4+4 /* fn ID, domain, var-len size */ ) /* optional fields, total (see flags) */ #define XCP_LOG_OPTFIELD_MAX_BYTES \ (2* XCP_WK_BYTES + \ XCP_LOG_COMPLIANCE_BYTES + \ 3* XCP_LOG_KEYREC_BYTES + \ XCP_LOG_TIMET_BYTES + \ XCP_LOG_COMPLIANCE_BYTES + \ XCP_LOG_REASON_BYTES + \ XCP_LOG_SALT_MAX_BYTES) #define XCP_LOG_HEADER_BYTES \ (1+1+2 + /* type, version, bytecount */ \ XCP_LOG_SEQNR_BYTES + \ XCP_LOG_TIMET_BYTES) /* worst-case full wire-formatted entry, incl. trailing hash */ #define XCP_LOG_ENTRY_MAX_BYTES \ (XCP_LOG_HEADER_BYTES + \ XCP_LOG_STATE_BYTES + /* initial state/hash */ \ XCP_LOG_CONTEXT_BYTES + \ XCP_LOG_OPTFIELD_MAX_BYTES + \ XCP_LOG_STATE_BYTES) /*--- state serialization ------------------------------------------------*/ typedef enum { XCP_STSTYPE_SECTIONCOUNT = 1, // section count +file hash XCP_STSTYPE_DOMAINIDX_MAX = 2, // largest index +total nr of doms XCP_STSTYPE_DOMAINS_MASK = 3, // bitmask of included domains XCP_STSTYPE_SERIALNR = 4, XCP_STSTYPE_CREATE_TIME = 5, // file date/time (UTC) XCP_STSTYPE_FCV = 6, // public parts of originating FCV XCP_STSTYPE_CARD_QUERY = 7, // V0 card state struct (xcp_info) XCP_STSTYPE_CARD_ADM_SKIS = 8, // card admin SKIs, packed XCP_STSTYPE_CARD_ADM_CERTS = 9, // card admin certificates, packed XCP_STSTYPE_DOM_ADM_SKIS = 10, // domain admin SKIs, packed XCP_STSTYPE_DOM_ADM_CERTS = 11, // domain admin certs, packed XCP_STSTYPE_DOM_QUERY = 12, // domain state struct (xcp_info) XCP_STSTYPE_KPH_SKIS = 13, // count and SKIs of targeted KPHs XCP_STSTYPE_CARD_ATTRS = 14, // card attributes XCP_STSTYPE_DOM_ATTRS = 15, // domain attributes XCP_STSTYPE_CARD_TRANSCTR = 16, // card transaction counter XCP_STSTYPE_DOM_TRANSCTR = 17, // domain transaction counter XCP_STSTYPE_WK_ENCR_ALG = 18, XCP_STSTYPE_WK_ENCR_DATA = 19, XCP_STSTYPE_SIG_CERT_COUNT = 20, XCP_STSTYPE_SIG_CERTS = 21, XCP_STSTYPE_FILE_SIG = 22, XCP_STSTYPE_DOM_CPS = 23, // full set of control points XCP_STSTYPE_STATE_SALT = 24, XCP_STSTYPE_KEYPART = 25, // encrypted keypart (RecipientInfo) XCP_STSTYPE_KEYPART_SIG = 26, // signature on encrypted keypart XCP_STSTYPE_KEYPART_COUNT = 27, // total number of keyparts XCP_STSTYPE_KEYPART_LIMIT = 28, // number of keyparts needed to // restore XCP_STSTYPE_KEYPART_CERT = 29, // certificate of keypart holder XCP_STSTYPE_CERT_AUTH = 30, // certificate authority issuing // some of the certificates. This // field contains host-supplied data // and it is ignored by EP11 itself. XCP_STSTYPE_STATE_SCOPE = 31, // restriction on contents of full // state structure XCP_STSTYPE_MULTIIMPORT_MASK = 32, // import only: designate import // request to be replicated into // multiple recipient domains XCP_STSTYPE_CPS_MASK = 33, // bitmask of all CPs supported // by the exporting module XCP_STSTYPE_CARD_QUERY_V1 = 34, // V1 card state struct (xcp_info) XCP_STSTYPE_CARD_QUERY_V2 = 35, // V2 card state struct (xcp_info) XCP_STSTYPE_CARD_EXTADM_SKIS = 36, // ext. card admin SKIs, packed XCP_STSTYPE_CARD_EXTADM_CERTS = 37, // ext. card admin certs, packed XCP_STSTYPE_DOM_EXTADM_SKIS = 38, // ext. dom admin SKIs, packed XCP_STSTYPE_DOM_EXTADM_CERTS = 39, // ext. dom admin certs, packed XCP_STSTYPE_CARD_ATTRS_SUPP = 40, // supported bits of card attributes XCP_STSTYPE_MAX = XCP_STSTYPE_CARD_ATTRS_SUPP } XCP_StateSection_t; typedef enum { XCP_STALG_AES256_CBC = 1 } XCP_StateEncrAlg_t; typedef enum { XCP_FILEID_SAVED_STATE = 1, // serialized state XCP_FILEID_KEYPARTS = 2, // encrypted keyparts XCP_FILEID_TESTDATA = 3, // not supported by production code XCP_FILEID_EXPREQUEST = 4, // export request XCP_FILEID_MAX = XCP_FILEID_EXPREQUEST } XCP_FileId_t; typedef enum { XCP_STDATA_NO_RESTRICTION = 0, // no state restrictions to card // or domain data XCP_STDATA_DOMAIN = 1, // state restricted to domain data // only, excluding card-specific // sections XCP_STDATA_NONSENSITIVE = 2, // serialized state restricted to // non-sensitive sections only XCP_STWK_KP_NO_CERT = 4, // keypart section restricted to // not return KPH certificates XCP_STWK_KP_NO_OA_CHAIN = 8, // keypart section restricted to // not return OA certificate chain XCP_STDATA_NQS = 0x20,// allow use of non-quantum-safe // algorithms in KP export/signature XCP_STDATA_QS = 0x40,// allow use of quantum-safe // algorithms in KP export/signature XCP_STDATA_MAX = ((XCP_STDATA_QS *2) -1) } XCP_StateType_t; // type || identifier prefixes #define XCP_STSTYPE_TYPE_BYTES 2 #define XCP_STSTYPE_TYPEID_BYTES 4 /*--- EC curves ----------------------------------------------------------*/ // NIST/SECG object identifiers #define XCP_EC_P192 "\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x01" #define XCP_EC_P192_BYTES 10 #define XCP_EC_P224 "\x06\x05\x2b\x81\x04\x00\x21" #define XCP_EC_P224_BYTES 7 #define XCP_EC_P256 "\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07" #define XCP_EC_P256_BYTES 10 #define XCP_EC_P384 "\x06\x05\x2b\x81\x04\x00\x22" #define XCP_EC_P384_BYTES 7 #define XCP_EC_P521 "\x06\x05\x2b\x81\x04\x00\x23" #define XCP_EC_P521_BYTES 7 // NIST/SECG, curve names as UTF-8/ASCII strings #define XCP_EC_P192_NAME "\x50\x2d\x31\x39\x32" /* P-192 */ #define XCP_EC_P192_NAME_BYTES 5 #define XCP_EC_P224_NAME "\x50\x2d\x32\x32\x34" /* P-224 */ #define XCP_EC_P224_NAME_BYTES 5 #define XCP_EC_P256_NAME "\x50\x2d\x32\x35\x36" /* P-256 */ #define XCP_EC_P256_NAME_BYTES 5 #define XCP_EC_P384_NAME "\x50\x2d\x33\x38\x34" /* P-384 */ #define XCP_EC_P384_NAME_BYTES 5 #define XCP_EC_P521_NAME "\x50\x2d\x35\x32\x31" /* P-521 */ #define XCP_EC_P521_NAME_BYTES 5 // Brainpool object identifiers #define XCP_EC_BP160R "\x06\x09\x2b\x24\x03\x03\x02\x08\x01\x01\x01" #define XCP_EC_BP160R_BYTES 11 #define XCP_EC_BP160T "\x06\x09\x2b\x24\x03\x03\x02\x08\x01\x01\x02" #define XCP_EC_BP160T_BYTES 11 #define XCP_EC_BP192R "\x06\x09\x2b\x24\x03\x03\x02\x08\x01\x01\x03" #define XCP_EC_BP192R_BYTES 11 #define XCP_EC_BP192T "\x06\x09\x2b\x24\x03\x03\x02\x08\x01\x01\x04" #define XCP_EC_BP192T_BYTES 11 #define XCP_EC_BP224R "\x06\x09\x2b\x24\x03\x03\x02\x08\x01\x01\x05" #define XCP_EC_BP224R_BYTES 11 #define XCP_EC_BP224T "\x06\x09\x2b\x24\x03\x03\x02\x08\x01\x01\x06" #define XCP_EC_BP224T_BYTES 11 #define XCP_EC_BP256R "\x06\x09\x2b\x24\x03\x03\x02\x08\x01\x01\x07" #define XCP_EC_BP256R_BYTES 11 #define XCP_EC_BP256T "\x06\x09\x2b\x24\x03\x03\x02\x08\x01\x01\x08" #define XCP_EC_BP256T_BYTES 11 #define XCP_EC_BP320R "\x06\x09\x2b\x24\x03\x03\x02\x08\x01\x01\x09" #define XCP_EC_BP320R_BYTES 11 #define XCP_EC_BP320T "\x06\x09\x2b\x24\x03\x03\x02\x08\x01\x01\x0a" #define XCP_EC_BP320T_BYTES 11 #define XCP_EC_BP384R "\x06\x09\x2b\x24\x03\x03\x02\x08\x01\x01\x0b" #define XCP_EC_BP384R_BYTES 11 #define XCP_EC_BP384T "\x06\x09\x2b\x24\x03\x03\x02\x08\x01\x01\x0c" #define XCP_EC_BP384T_BYTES 11 #define XCP_EC_BP512R "\x06\x09\x2b\x24\x03\x03\x02\x08\x01\x01\x0d" #define XCP_EC_BP512R_BYTES 11 #define XCP_EC_BP512T "\x06\x09\x2b\x24\x03\x03\x02\x08\x01\x01\x0e" #define XCP_EC_BP512T_BYTES 11 #define XCP_EC_BPOID_BYTES 11 // #define XCP_EC_BPOIDS 14 // Brainpool, curve names as UTF-8/ASCII strings #define XCP_EC_BP160R_NAME "\x42\x50\x2d\x31\x36\x30\x52" /* BP-160R */ #define XCP_EC_BP160R_NAME_BYTES 7 #define XCP_EC_BP160T_NAME "\x42\x50\x2d\x31\x36\x30\x54" /* BP-160T */ #define XCP_EC_BP160T_NAME_BYTES 7 #define XCP_EC_BP192R_NAME "\x42\x50\x2d\x31\x39\x32\x52" /* BP-192R */ #define XCP_EC_BP192R_NAME_BYTES 7 #define XCP_EC_BP192T_NAME "\x42\x50\x2d\x31\x39\x32\x54" /* BP-192T */ #define XCP_EC_BP192T_NAME_BYTES 7 #define XCP_EC_BP224R_NAME "\x42\x50\x2d\x32\x32\x34\x52" /* BP-224R */ #define XCP_EC_BP224R_NAME_BYTES 7 #define XCP_EC_BP224T_NAME "\x42\x50\x2d\x32\x32\x34\x54" /* BP-224T */ #define XCP_EC_BP224T_NAME_BYTES 7 #define XCP_EC_BP256R_NAME "\x42\x50\x2d\x32\x35\x36\x52" /* BP-256R */ #define XCP_EC_BP256R_NAME_BYTES 7 #define XCP_EC_BP256T_NAME "\x42\x50\x2d\x32\x35\x36\x54" /* BP-256T */ #define XCP_EC_BP256T_NAME_BYTES 7 #define XCP_EC_BP320R_NAME "\x42\x50\x2d\x33\x32\x30\x52" /* BP-320R */ #define XCP_EC_BP320R_NAME_BYTES 7 #define XCP_EC_BP320T_NAME "\x42\x50\x2d\x33\x32\x30\x54" /* BP-320T */ #define XCP_EC_BP320T_NAME_BYTES 7 #define XCP_EC_BP384R_NAME "\x42\x50\x2d\x33\x38\x34\x52" /* BP-384R */ #define XCP_EC_BP384R_NAME_BYTES 7 #define XCP_EC_BP384T_NAME "\x42\x50\x2d\x33\x38\x34\x54" /* BP-384T */ #define XCP_EC_BP384T_NAME_BYTES 7 #define XCP_EC_BP512R_NAME "\x42\x50\x2d\x35\x31\x32\x52" /* BP-512R */ #define XCP_EC_BP512R_NAME_BYTES 7 #define XCP_EC_BP512T_NAME "\x42\x50\x2d\x35\x31\x32\x54" /* BP-512T */ #define XCP_EC_BP512T_NAME_BYTES 7 // secp256k1 (Bitcoin default curve) #define XCP_EC_S256K1 "\x06\x05" "\x2b\x81\x04\x00\x0a" #define XCP_EC_S256K1_BYTES 7 #define XCP_EC_S256K1_NAME "\x53\x45\x43\x50\x32\x35\x36\x4b\x31" /* SECP256K1 */ #define XCP_EC_S256K1_NAME_BYTES 9 // curve25519, curve448, related OIDs // // 1.3.101.110: curve25519, allocated by PKIX, ECDH only #define XCP_EC_X25519 "\x06\x03\x2b\x65\x6e" #define XCP_EC_X25519_BYTES 5 #define XCP_EC_X25519_NAME "\x63\x75\x72\x76\x65\x32\x35\x35\x31\x39" /* curve25519 */ #define XCP_EC_X25519_NAME_BYTES 10 // // 1.3.101.111: curve[of-ed]448 'Goldilocks', allocated by PKIX, ECDH only #define XCP_EC_X448 "\x06\x03\x2b\x65\x6f" #define XCP_EC_X448_BYTES 5 #define XCP_EC_X448_NAME "\x78\x34\x34\x38" /* c448, matching RFC8410 */ #define XCP_EC_X448_NAME_BYTES 4 // // 1.3.101.112: EDDSA, 25519 #define XCP_EC_DSA25519 "\x06\x03\x2b\x65\x70" #define XCP_EC_DSA25519_BYTES 5 #define XCP_EC_DSA25519_NAME "\x65\x64\x32\x35\x35\x31\x39" /* ed25519 */ #define XCP_EC_DSA25519_NAME_BYTES 7 // 1.3.101.113: EDDSA/448 (ed448) #define XCP_EC_DSA448 "\x06\x03\x2b\x65\x71" #define XCP_EC_DSA448_BYTES 5 #define XCP_EC_DSA448_NAME "\x65\x64\x34\x34\x38" /* ed448 */ #define XCP_EC_DSA448_NAME_BYTES 5 // 1.3.6.1.4.1.2.267.999.3.2 : 2B0601040102820B87670302 : bls12_381_et #define XCP_EC_BLS12_381_ET "\x6\xC\x2B\x6\x1\x4\x1\x2\x82\xB\x87\x67\x3\x2" #define XCP_EC_BLS12_381_ET_BYTES 14 #define XCP_EC_MAX_ID_BYTES 14 /* fits all EC names/OIDs */ /*------------------------------------*/ typedef enum { XCP_EC_C_NIST_P192 = 1, /* NIST, FP curves */ XCP_EC_C_NIST_P224 = 2, XCP_EC_C_NIST_P256 = 3, XCP_EC_C_NIST_P384 = 4, XCP_EC_C_NIST_P521 = 5, XCP_EC_C_BP160R = 6, /* Brainpool, FP curves */ XCP_EC_C_BP160T = 7, XCP_EC_C_BP192R = 8, XCP_EC_C_BP192T = 9, XCP_EC_C_BP224R = 10, XCP_EC_C_BP224T = 11, XCP_EC_C_BP256R = 12, XCP_EC_C_BP256T = 13, XCP_EC_C_BP320R = 14, XCP_EC_C_BP320T = 15, XCP_EC_C_BP384R = 16, XCP_EC_C_BP384T = 17, XCP_EC_C_BP512R = 18, XCP_EC_C_BP512T = 19, XCP_EC_C_25519 = 20, /* curve25519, FP (2^255-19) */ XCP_EC_C_SECP256K1 = 23, /* secp256k1, Bitcoin default curve */ XCP_EC_C_ED448 = 24, /* ed448 ('Goldilocks') FP(2^448-2^244+1)*/ XCP_EC_C_448 = 25, /* c448/x448, ECDH only */ XCP_EC_C_ED25519 = 26, /* ed25519, EDDSA */ XCP_EC_C_BLS12_381 = 28, /* pairing-friendly BLS12-381 */ XCP_EC_C_MAX = XCP_EC_C_BLS12_381, /* last possible value */ } XCP_ECcurve_t; /*-------------------------------------- * groups of EC curves, without specific OIDs */ typedef enum { XCP_EC_CG_NIST = 1, /* NIST, FP curves */ XCP_EC_CG_BPOOL = 2, /* Brainpool, FP curves */ XCP_EC_CG_C25519 = 3, /* curve25519, ed25519 */ XCP_EC_CG_SECP256K1 = 4, /* SECP K-curves, */ /* incl. Bitcoin default */ XCP_EC_CG_C448 = 6, /* c448, ed448 ('Goldilocks') */ XCP_EC_CG_PAIRING_FRIENDLY = 7, /* pairing-friendly curves, BLS12-381 */ XCP_EC_CG_MAX = XCP_EC_CG_PAIRING_FRIENDLY } XCP_ECCurveGrp_t; /*--- PQC algorithms ------------------------------------------------------*/ // Dilithium related OIDs // Round 2 Dilithium-3 (5-4) #define XCP_PQC_DILITHIUM_R2_54 "\x6\xb\x2b\x6\x1\x4\x1\x2\x82\xb\x1\x5\x4" #define XCP_PQC_DILITHIUM_R2_54_BYTES 13 // Round 2 Dilithium-4 (6-5) #define XCP_PQC_DILITHIUM_R2_65 "\x6\xb\x2b\x6\x1\x4\x1\x2\x82\xb\x1\x6\x5" #define XCP_PQC_DILITHIUM_R2_65_BYTES 13 // Round 2 Dilithium-5 (8-7) #define XCP_PQC_DILITHIUM_R2_87 "\x6\xb\x2b\x6\x1\x4\x1\x2\x82\xb\x1\x8\x7" #define XCP_PQC_DILITHIUM_R2_87_BYTES 13 // Round 3 Dilithium-2 (4-4) #define XCP_PQC_DILITHIUM_R3_44 "\x6\xb\x2b\x6\x1\x4\x1\x2\x82\xb\x7\x4\x4" #define XCP_PQC_DILITHIUM_R3_44_BYTES 13 // Round 3 Dilithium-3 (6-5) #define XCP_PQC_DILITHIUM_R3_65 "\x6\xb\x2b\x6\x1\x4\x1\x2\x82\xb\x7\x6\x5" #define XCP_PQC_DILITHIUM_R3_65_BYTES 13 // Round 3 Dilithium-5 (8-7) #define XCP_PQC_DILITHIUM_R3_87 "\x6\xb\x2b\x6\x1\x4\x1\x2\x82\xb\x7\x8\x7" #define XCP_PQC_DILITHIUM_R3_87_BYTES 13 // Round 2 Kyber 512 #define XCP_PQC_KYBER_R2_512 "\x6\x9\x2B\x6\x1\x4\x1\x2\x82\xB\x5" #define XCP_PQC_KYBER_R2_512_BYTES 11 // Round 2 Kyber 768 #define XCP_PQC_KYBER_R2_768 "\x6\xB\x2B\x6\x1\x4\x1\x2\x82\xB\x5\x3\x3" #define XCP_PQC_KYBER_R2_768_BYTES 13 // Round 2 Kyber 1024 #define XCP_PQC_KYBER_R2_1024 "\x6\xB\x2B\x6\x1\x4\x1\x2\x82\xB\x5\x4\x4" #define XCP_PQC_KYBER_R2_1024_BYTES 13 // NIST Standards typedef CK_ULONG CK_IBM_ML_DSA_PARAMETER_SET_TYPE; #define CKP_IBM_ML_DSA_44 ((CK_IBM_ML_DSA_PARAMETER_SET_TYPE)1) #define CKP_IBM_ML_DSA_65 ((CK_IBM_ML_DSA_PARAMETER_SET_TYPE)2) #define CKP_IBM_ML_DSA_87 ((CK_IBM_ML_DSA_PARAMETER_SET_TYPE)3) typedef CK_ULONG CK_IBM_ML_KEM_PARAMETER_SET_TYPE; #define CKP_IBM_ML_KEM_512 ((CK_IBM_ML_KEM_PARAMETER_SET_TYPE)1) #define CKP_IBM_ML_KEM_768 ((CK_IBM_ML_KEM_PARAMETER_SET_TYPE)2) #define CKP_IBM_ML_KEM_1024 ((CK_IBM_ML_KEM_PARAMETER_SET_TYPE)3) typedef CK_ULONG CK_IBM_HEDGE_TYPE; #define CKH_IBM_HEDGE_PREFERRED ((CK_IBM_HEDGE_TYPE)1) #define CKH_IBM_HEDGE_REQUIRED ((CK_IBM_HEDGE_TYPE)2) #define CKH_IBM_DETERMINISTIC_REQUIRED ((CK_IBM_HEDGE_TYPE)3) typedef struct CK_IBM_SIGN_ADDITIONAL_CONTEXT { CK_IBM_HEDGE_TYPE hedgeVariant; CK_BYTE_PTR pContext; CK_ULONG ulContextLen; } CK_IBM_SIGN_ADDITIONAL_CONTEXT; /*------------------------------------*/ typedef enum { XCP_PQC_S_DILITHIUM_R2_54 = 1, /* Round-2 Dilithium */ XCP_PQC_S_DILITHIUM_R2_65 = 2, XCP_PQC_S_DILITHIUM_R2_87 = 3, XCP_PQC_S_DILITHIUM_R3_44 = 4, /* Round-3 Dilithium */ XCP_PQC_S_DILITHIUM_R3_65 = 5, XCP_PQC_S_DILITHIUM_R3_87 = 6, XCP_PQC_S_KYBER_R2_512 = 7, /* Round-2 Kyber */ XCP_PQC_S_KYBER_R2_768 = 8, XCP_PQC_S_KYBER_R2_1024 = 9, XCP_PQC_S_ML_DSA_44 = 10, /* NIST Standards */ XCP_PQC_S_ML_DSA_65 = 11, XCP_PQC_S_ML_DSA_87 = 12, XCP_PQC_S_ML_KEM_512 = 13, XCP_PQC_S_ML_KEM_768 = 14, XCP_PQC_S_ML_KEM_1024 = 15, XCP_PQC_MAX = XCP_PQC_S_ML_KEM_1024, } XCP_PQCStrength_t; // binary encoding of function/version query // SEQUENCE { OCTET STRING (0) } // module responds with API version and build ID // #define XCP_VERS_QUERY_REQ 0x30,0x03,0x04,0x01,0x00 /* request body */ #define XCP_VERS_QUERY_REQ_BYTES 5 /*--- development-only test functions ------------------------------------*/ typedef enum { XCP_DEV_SET_WK = 1, // set and activate (imprint) WK XCP_DEV_SET_NEXT_WK = 2, // set+commit next WK (+imprint) XCP_DEV_AES_ENCR_CYCLE = 3, // AES encrypt in loop // (side-channel, other measurements) XCP_DEV_AES_DECR_CYCLE = 4, // AES decrypt in loop XCP_DEV_DES_ENCR_CYCLE = 5, // 1/2/3DES, auto-selected XCP_DEV_DES_DECR_CYCLE = 6, // 1/2/3DES, auto-selected XCP_DEV_ZEROIZE_CARD = 7, XCP_DEV_ZEROIZE_DOMAIN = 8, XCP_DEV_SET_DOMAIN_CPS = 9, // import full set of CPs XCP_DEV_SET_WK_RAW = 10, // set WK without imprinting XCP_DEV_COMMIT_NEXT_WK = 11, // finalizes next WK to current XCP_DEVQ_ADMINLIST = 12, // SKI list, without card signature XCP_DEVQ_DOM_ADMINLIST = 13, // SKI list, without card signature XCP_DEV_SET_NEXT_WK_RAW = 14, // set next WK, does not imprint XCP_DEV_FSMODE = 15, // manage access to filesystems XCP_DEV_ADMSIGN = 16, // admin-sign file in filesystem // used to pass arbitrary bad structs // for verification XCP_DEV_FSWRITE = 17, // write data to temporary file XCP_DEV_DSA_PQG_GEN = 18, XCP_DEVQ_BLOBCONFIG = 19, // blob details: endianness and sizes XCP_DEV_RSA_X931_KEYGEN = 20, // ANSI x9.31 key gen. from prime seeds // returns PKCS8-encoded key, in clear // may be unsupported, depending on CSP // setup XCP_DEV_RNGSTATE = 21, // query or set backend RNG state XCP_DEV_RNG_SEED = 22, // forces immediate RNG re/seeding // recommended before exporting RNG // state, to maximize number of // matching bits after state is restored XCP_DEVQ_ENTROPY = 23, // retrieve raw TRNG output // conditioned entropy, no DRNG // processing a direct-call subset of // XCP_DEV_RNG_TRNG (does not require // background completion) // note that this call changes DRNG // setup during processing, // slowing it down // see also: XCP_DEV_RAWENTROPY XCP_DEVQ_PERFMODE = 24, // query performance/timestamp setup XCP_DEV_PERFMODE = 25, // change performance/timestamp setup XCP_DEV_RSA_DECR_CYCLE = 26, // RSA, raw mod. exponentiation, looped XCP_DEV_RSACRT_DECR_CYCLE = 27, // RSA, private exponent, CRT, looped XCP_DEV_ECMUL_CYCLE = 28, // EC scalar multiplication, looped XCP_DEV_PERFMARK = 29, // add performance-test marker // LS 4 bits included in entry XCP_DEVQ_PERF_LOCK = 30, // raw performance: un/lock cycles, // single thread // test on otherwise quiesced backend XCP_DEVQ_PERF_WAKE = 31, // raw performance: un/lock cycles, // forcing context switching // test on otherwise quiesced backend XCP_DEVQ_PERF_SCALE = 32, // raw performance: add calibrating // timestamp/syslog/etc. entries // to simplify offline scaling of // performance management XCP_DEV_CACHE_MODE = 33, // set or query module-internal cache // state and statistics XCP_DEVQ_CACHE_STATS = 34, // log cache-statistics summary // over syslog etc. (system-dependent) XCP_DEV_DELAY = 35, // NOP: delay the backend thread by // a host-influenced amount of time, // without performing other operations XCP_DEV_COMPRESS = 36, // return 'summarized' version of any // supplied data XCP_DEV_XOR_FF = 37, // returns a copy of data, all bits // flipped (XORed with 0xff) XCP_DEV_PRF = 38, // returns PRF stream from caller- // provided seed and bytecount XCP_DEV_TRANSPORTSTATE1 = 39, // transport-statistics dump // (system-dependent functionality) XCP_DEVQ_CACHEINDEX = 40, // return module-internal blob index // of caller-provided key XCP_DEVQ_CSP_OBJCOUNT = 41, // CSP-object reference counter, // if available XCP_DEV_CSPTYPE = 42, // preferred CSP-object (engine) type XCP_DEV_FCV = 43, // query and/or set current FCV // without signature verification XCP_DEV_CLEAR_FCV = 44, // erase any existing FCV XCP_DEVQ_ASSERTIONS = 45, // verify the consistency of module- // internal data structures, as a // stronger form of assertion-checking XCP_DEV_TEST_LATESTART = 46, // perform any initial test which has // been skipped during backend startup. // not necessary unless running against // the most aggressive SYS_TEST_0START // settings [which trim down backend // testing to a bare minimum]. Safe to // issue, a NOP otherwise. XCP_DEV_ENVSEED = 47, // seed backend with device-unique, // environment-derived, low quality // entropy [augments/replaces real // entropy seeding; added to let // unrelated backends diverge even // when VM-hosted or otherwise lacking // proper initial entropy] XCP_DEVQ_RAWENTROPY = 48, // retrieve raw entropy pool, before // compression, if backend supports // this (see Clic docs for raw-pool // state details) // // see also: XCP_DEV_ENTROPY XCP_DEV_EC_SIGVER_CYCLE = 49, // EC sign/verify in loop // operation derived from supplied blob // (EC private/SPKI) // see also: XCP_DEV_ECMUL_CYCLE XCP_DEV_DRAIN_ENTROPY = 50, // TRNG: force at least one collect // entropy->compression call // [may be more, depends on DRNG state] XCP_DEV_CONV_EC_BLOB = 51, // CLiC blob conversion: Convert a // software Blob to a 4767 hardware blob // At the moment only EC blobs are // supported XCP_DEVQ_COUNTERS = 52, // retrieve coverage counters // these are intentionally not published XCP_DEV_RSACRT_MSG_CYCLE = 53, // RSA, private exponent, CRT, looped // this variant increments message // and returns per-message statistics XCP_DEV_AUDIT_CYCLE = 54, // audit-log, generate log entries // in a loop XCP_DEV_EDDSA = 55, // EC dig.signature forms XCP_DEV_ECDH = 56, // EC Diffie-Hellman/Montgomery forms XCP_DEV_PQC_DILITHIUM = 57, // post-quantum algs: generic call // for Dilithium (from PQ Crystals) XCP_DEV_ABORT = 63, // raise abort signal XCP_DEV_DRNG = 64, // gen non-randomly-seeded DRNG bytes XCP_DEV_DRNG_RESEED = 65, // explicitly set DRNG seed XCP_DEV_FAULT_INJECT = 66, // control fault point injection XCP_DEVQ_FAULTLIST = 67, // list available fault points XCP_DEV_FLIP_ERRORSTATE = 68, // explicitly flip the setting of the // error state of the module XCP_DEV_AESKW = 69, XCP_DEV_KDF_SP108 = 70, // NIST SP800-108 KDF XCP_DEV_KDF_SP56C = 71, // NIST SP800-56C ECDH+KDF(ECIES) XCP_DEV_UNIT_TEST = 72, // run unit tests on module XCP_DEV_MAX_INDEX = XCP_DEV_UNIT_TEST } XCP_DEVcmd_t; // // upper limit on additional data bytes, for SYS-TEST commands with aux. data // (arbitrary limit, commands may restict further) #define XCP_DEV_MAX_DATABYTES ((size_t) 64000) // // iteration-count limit applies to any iterative call // driver[timeout] may interfere; dev-only feature is not otherwise restricted #define XCP_DEV_MAX_ITERATIONS ((unsigned int) 128*1024) #define XCP_DEV_C25519 (unsigned int)255 #define XCP_DEV_C448 (unsigned int)448 #define XCP_DEV_ED25519 ~((unsigned int)255) #define XCP_DEV_ED448 ~((unsigned int)448) #define XCP_DEV_ED25519_2 ~((unsigned int)256) #define XCP_DEV_ED448_2 ~((unsigned int)456) #define XCP_DEV_AESKW_WRAP (unsigned int)1 #define XCP_DEV_AESKW_UNWRAP (unsigned int)2 #define XCP_DEV_AESKW_WRAP_PAD (unsigned int)3 #define XCP_DEV_AESKW_UNWRAP_PAD (unsigned int)4 typedef enum { XCP_DEVC_CACHE_ACTIVE = 1, // blob-cache is available XCP_DEVC_CACHE_INACTIVE = 2, // caching suspended: lookups fail, // new entries are not accepted XCP_DEVC_CACHE_FLUSH = 4, // evict all currently cached objects // available even if cache is suspended } XCP_DEVcache_t; typedef enum { XCP_DEV_RNG_TRNG = 0, // no DRNG involvement XCP_DEV_RNG_DRNG = 1, // DRNG, no reseeding XCP_DEV_RNG_MIXED = 2, // DRNG, with TRNG reseeding XCP_DEV_RNG_SWDRNG = 4, // Software-DRNG XCP_DEV_RNG_TYPE_MAX = XCP_DEV_RNG_SWDRNG } XCP_DEVrng_t; typedef enum { XCP_DEVFS_QUERY = 0, // current state query only XCP_DEVFS_READONLY = 1, // prevent writes XCP_DEVFS_NOACCESS = 2 // prevent all filesystem access } XCP_DEVfs_t; // size of coverage counters #define XCP_DEV_CTR_SIZE 4 #define XCP_DEV_CTR_TYPE uint32_t typedef enum { XCP_DEV_FAULT_EXPR = 1, // evaluate to non-null if triggered XCP_DEV_FAULT_FUNC = 2, // call callback function XCP_DEV_FAULT_MSLEEP = 4, // sleep for msleep ms XCP_DEV_FAULT_RV = 8, // faultpoint returns rv XCP_DEV_FAULT_DBIT = 16, // flip bit at compile-time const offset XCP_DEV_FAULT_DNULL = 32, // faultpoint memsets data to zero XCP_DEV_FAULT_RBIT = 64, // flip bit at random offset } XCP_DEVfault_t; // no vendor extension definition for CKG available yet #if !defined(CKG_VENDOR_DEFINED) #define CKG_VENDOR_DEFINED 0x80000000UL #endif #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) #if !defined(CKD_VENDOR_DEFINED) #define CKD_VENDOR_DEFINED 0x80000000UL #endif #define CKD_IBM_HYBRID_NULL (CKD_VENDOR_DEFINED + 0x00000001UL) #define CKD_IBM_HYBRID_SHA1_KDF (CKD_VENDOR_DEFINED + 0x00000002UL) #define CKD_IBM_HYBRID_SHA224_KDF (CKD_VENDOR_DEFINED + 0x00000003UL) #define CKD_IBM_HYBRID_SHA256_KDF (CKD_VENDOR_DEFINED + 0x00000004UL) #define CKD_IBM_HYBRID_SHA384_KDF (CKD_VENDOR_DEFINED + 0x00000005UL) #define CKD_IBM_HYBRID_SHA512_KDF (CKD_VENDOR_DEFINED + 0x00000006UL) #define XCP_MODEL_CEX4P 4 #define XCP_MODEL_CEX5P 5 #define XCP_MODEL_CEX6P 6 #define XCP_MODEL_CEX7P 7 #define XCP_MODEL_CEX8P 8 /*--------------------------------------------------------------------------*/ // max value for target groups #define XCP_MAX_GRPIDX 1024u // // macros for setting/checking and removing domains from (tgt.mgmt) domain mask #define XCPTGTMASK_SET_DOM(mask, domain) \ ((mask)[((domain)/8)] |= (1 << (7-(domain)%8))) #define XCPTGTMASK_DOM_IS_SET(mask, domain) \ ((mask)[((domain)/8)] & (1 << (7-(domain)%8))) #define XCPTGTMASK_CLR_DOM(mask, domain) \ ((mask)[((domain)/8)] &= ~(1 << (7-(domain)%8))) /* flags that can be set for the target tokens * * This flags are domain specific and are therefore called domain flags * * start of flags is >16 Bit. Max value for domains is 0xFF. Should be enough * room for extensions */ #define XCP_TGTFL_WCAP 0x10000000 /* Capture wire request in output buffer * without sending it to the module */ #define XCP_TGTFL_WCAP_SQ 0x20000000 /* Size query: Return size of request in * output buffer length field */ #define XCP_TGTFL_SET_SCMD 0x40000000 /* Protected key special command: Set the * special command flag in the CPRB * header */ #define XCP_TGTFL_API_CHKD 0x80000000 /* supported API version of modules in * target (group) has been checked */ #define XCP_TGTFL_NO_LOCK 0x01000000 /* target token ignores sequential locks * for target probing */ #define XCP_TGTFL_CHK_ATTR 0x02000000 /* reject unknown attribute in attribute * templates with * CKR_TEMPLATE_INCONSISTENT. Default is * to ignore unknown attributes. */ #define XCP_TGTFL_SET_ACMD 0x04000000 /* add CPRB admin flag to CPRB header */ #define XCP_TGTFL_NO_SPLIT 0x08000000 /* enforce single-shot requests */ //-------------------------------------- // socket use only #define XCP_MAXCONNECTIONS 256 /* max value for active connections */ #define XCP_MAX_PORT 0xffff // hostname and port value fore one module typedef struct XCP_ModuleSocket { char host[ MAX_FNAME_CHARS +1 ]; uint32_t port; } *XCP_ModuleSocket_t ; //-------------------------------------- // diagnostics use only typedef struct XCP_DomainPerf { /* perf value of last request per domain * * At the moment unused * */ unsigned int lastperf[ 256 ]; } *XCP_DomainPerf_t; // current version of XCP_Module structure; host code SHOULD interact with // future/past versions, MUST be set by caller before using m_add_module() // valid versions are all >0 #define XCP_MOD_VERSION 2 //-------------------------------------- // subsequent communications with a module MAY skip infrastructure-specific // fields, such as a query not reporting device handles etc., even if they // have been supplied originally when the module has been registered. // typedef struct XCP_Module { uint32_t version; /* >0 for supported API versions */ uint64_t flags; /* see XCP_Module_Flags */ uint32_t domains; /* max# addressable under this module; * cached from OS * * when callers set domains to 0, the library * returns the module-claimed domain count. */ unsigned char domainmask[ 256 /8 ]; /* higher domain# through future flags (none * currently defined) which would add things * like 'FLAG_256_1023' etc. at the same time, * we would add domainmask2[] etc. * corresponding new fields. * * new fields would then store mask for * domains 256+ etc. * * domain #0 is bit x80 of 1st byte, * #255 is bit 0x01 of last byte. */ // when a domainmask is supplied, with bits set beyond // what the module supports, the bitmask is trimmed to // the supported range, but this is NOT reported as an // error, unless XCP_MFL_STRICT is also supplied. // // without XCP_MFL_STRICT, callers are expected to check // at least the returned domain count. /* used only when flags includes XCP_MFL_SOCKET */ struct XCP_ModuleSocket socket; /* used when system exposes modules through an * array of transparent pipes, or similar abstraction * (such as mainframe AP Queues, or other Linux * 'device-minor' numbers etc.). Interpretation * is platform-dependent. * * used only when flags includes XCP_MFL_MODULE */ uint32_t module_nr; /* used by systems which associate devices with * device handles/structs/etc. persistent state. * opaque pointer, usually a const pointer to * such aux structs, MAY be stored here. * * interpretation is platform-dependent. * used only when flags includes XCP_MFL_MHANDLE */ void *mhandle; /* diagnostics use only, when XCP_MFL_PERF is set */ struct XCP_DomainPerf perf; //----- end of v1 fields ------------------------------------------- uint32_t api; /* module api version*/ //----- end of v2 fields ------------------------------------------- } *XCP_Module_t ; typedef enum { XCP_MFL_SOCKET = 1, /* backend is socket-attached */ XCP_MFL_MODULE = 2, /* backends identified in array-of-modules */ XCP_MFL_MHANDLE = 4, /* backends uses 'module handle' field */ XCP_MFL_PERF = 8, /* performance statistics collected * for this module, see .perf */ XCP_MFL_VIRTUAL = 0x10, /* queried 'target' is a load-balancer, * other other group. */ XCP_MFL_STRICT = 0x20, /* enable aggressive error checking, * see field descriptions for effect */ XCP_MFL_PROBE = 0x40, /* send api query to module, to check if * target(s) can be used */ XCP_MFL_ALW_TGT_ADD = 0x80, /* Allows it to use a target in any * functional and admin call without * adding it beforehand with * m_add_module() */ XCP_MFL_MAX = 0xff } XCP_Module_Flags; typedef uint64_t target_t; #define XCP_TGT_INIT ~0UL #define XCP_TGT_FMT "x%016" PRIx64 int m_add_module(XCP_Module_t module, target_t *target) ; int m_rm_module(XCP_Module_t module, 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) ; /*---------------------------------------------------------------------- * 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_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_LoginExtended( CK_UTF8CHAR_PTR pin, CK_ULONG pinlen, const unsigned char *nonce, size_t nlen, const unsigned char *xstruct, size_t xslen, unsigned char *pinblob, size_t *pinbloblen, target_t target) ; CK_RV m_LogoutExtended( CK_UTF8CHAR_PTR pin, CK_ULONG pinlen, const unsigned char *nonce, size_t nlen, const unsigned char *xstruct, size_t xslen, target_t target) ; int xcpu_LoginRecipient (uint8_t *result, size_t *rlen, uint32_t version, const uint8_t *rcpt_ski, size_t rslen, const uint8_t *send_spki, size_t slen); 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_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) ; /* 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_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_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_get_xcp_info (CK_VOID_PTR pinfo, CK_ULONG_PTR infbytes, unsigned int query, unsigned int subquery, target_t target) ; // see also: CK_IBM_XCPQUERY_t 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_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) ; // m_wire() by default removes transport headers of responses (CPRB header etc.) // setting to prevent stripping: // #define XCP_CHN_RETURN_RAW 1 /* return raw wire response, w/headers */ #define XCP_CHN_HIGH_PRIORITY 2 /* please note: Not all backends */ #define XCP_CHN_MEDIUM_PRIORITY 4 /* support channel priority mgmt */ #define XCP_CHN_NODEV_LOG_SKIP 8 /* do not log if no device is found */ #define XCP_CHN_PARSE_IRV 0x10 /*-------------------------------------------------------------------------- * direct interface without wire formatting & parsing. */ CK_RV m_wire (unsigned char *rsp, size_t *rsplen, CK_RV *irv, const unsigned char *req, size_t reqlen, unsigned int flags, target_t target) ; // options allowed within flags #define XCP_W_NO_SEND_CPRB 1 /* data already includes request header */ #define XCP_W_NO_RECV_CPRB 2 /* leave transport header in response */ // initializes the library int m_init(void); // shutting down the library int m_shutdown(void); /*-- build identification ------------------------------------------------*/ #define XCP_BUILD_ID 0x3942f3bb #define XCP_BUILD_DATE 0x20250923 /* UTC */ #define XCP_BUILD_TIME 0x083816 /* UTC */ /*--------------------------------------------------------------------------*/ #define __XCP_REASONCODES_H__ 1 typedef enum { XCP_RSC_NO_IMPORTER = 1, /* targeted domain has no importer private key */ XCP_RSC_NO_KEYPARTS = 2, /* import WK request without keypart SEQUENCEs */ XCP_RSC_IMPR_CMDBLK_BER = 3, /* embedded keyparts' BER envelope invalid */ XCP_RSC_IMPR_CMDBLK_FIELDS = 4, /* command block BER structure (field count) invalid */ XCP_RSC_IMPR_CMDBLK_FIELDCOUNT = 5, /* command block field count invalid */ XCP_RSC_IMPR_EMBEDDED_FN = 6, /* embedded admin request (external) with invalid/non-m_admin() function identifier */ XCP_RSC_IMPR_DOMAIN_DIFF = 7, /* internal block (within import WK) with different targeted domain */ XCP_RSC_IMPR_NO_INT_CMDBLK = 8, /* import internal keypart SEQUENCE without command block */ XCP_RSC_IMPR_NO_INT_SIGNATURE = 9, /* import internal keypart SEQUENCE without signature */ XCP_RSC_IMPR_BAD_CMDBLK_BER = 10, /* import internal keypart SEQUENCE without signature */ XCP_RSC_CMD_EMBEDDED_FN = 11, /* admin command block with invalid function identifier */ XCP_RSC_CMD_DOMAIN_RANGE = 12, /* requested domain index is out of range */ XCP_RSC_DOMAIN_INST_FMT = 13, /* domain instance malformed, or non-zero for card service */ XCP_RSC_DOMAIN_INST_MISMATCH = 14, /* domain instance does not match that of domain */ XCP_RSC_MODULE_INST_FMT = 15, /* module serialnumber/instance malformed */ XCP_RSC_MODULE_INST_MISMATCH = 16, /* module instance does not match that of domain */ XCP_RSC_MODULE_SERNO_MISMATCH = 17, /* module serial number does not match that of module */ XCP_RSC_TCTR_FMT = 18, /* transaction counter malformed (for this service) */ XCP_RSC_TCTR_VALUE = 19, /* transaction counter value invalid (already passed) */ XCP_RSC_DOMAIN_INST_DIFF = 20, /* internal block domain instance (within import WK) differs from external one */ XCP_RSC_SIGS_INSUFFICIENT = 21, /* not enough signatures for requested admin service */ XCP_RSC_SIGS_REJECTED = 22, /* at least one signature has been rejected */ XCP_RSC_RCPTINFO_FMT = 23, /* recipientInfo SEQUENCE malformed */ XCP_RSC_RCPTINFO_ENCRD_SIZE = 24, /* encrypted keypart size invalid */ XCP_RSC_RCPTINFO_ECDH_SRC = 25, /* ECDH failed (possibly invalid originator point) */ XCP_RSC_RCPTINFO_KDF_SHARED = 26, /* ECDH sharedinfo parameters are invalid */ XCP_RSC_RCPTINFO_KDF = 27, /* ECDH key derivation failed */ XCP_RSC_RCPTINFO_KEY_SIZE = 28, /* derived/recovered key size invalid */ XCP_RSC_RCPTINFO_KEY_MIXMODE = 29, /* standalone and full-key keyparts mixed (keyparts both with and without full-key VP) */ XCP_RSC_RCPTINFO_KEY_VPS_DIFF = 30, /* keypart full-key VPs are not identical */ XCP_RSC_RCPTINFO_KEY_VPS_MISMATCH = 31, /* reassembled key VP differs from those within keyparts */ XCP_RSC_SKI_MALFORMED = 32, /* admin key SKI bytecount is invalid */ XCP_RSC_SKI_NOT_FOUND = 33, /* admin key SKI bytecount is not present */ XCP_RSC_MODE_IMPRINT = 34, /* service not available in imprint mode */ XCP_RSC_MODE_NONIMPRINT = 35, /* service not available when no longer in imprint mode */ XCP_RSC_IMPRINT_EXIT_INVD = 36, /* attempt to leave imprint mode is not permitted */ XCP_RSC_CP_MODE_SET = 37, /* activating one or more CP bits is not allowed (operational mode) */ XCP_RSC_SKI_FOUND = 38, /* SKI is already registered, may not be repeatedly logged in */ XCP_RSC_ADMINLIST_FULL = 39, /* no more SKIs may be registered */ XCP_RSC_CERT_FMT = 40, /* certificate not recognized as X.509 one */ XCP_RSC_ATTRS_FMT = 41, /* packed attributes' size is invalid */ XCP_RSC_ATTRS_TYPE_INVALID = 42, /* unsupported attribute (index) specified */ XCP_RSC_ATTRS_REPEAT = 43, /* attribute (index) repeats */ XCP_RSC_CPS_FMT = 44, /* control point set (size) invalid */ XCP_RSC_CPS_SET_INCONSISTENT = 45, /* specified control points are rejected */ XCP_RSC_CPS_PREVENT_ADD = 46, /* policy prevents enabling the specified CP bits */ XCP_RSC_CPS_PREVENT_DEL = 47, /* policy prevents disabling the specified CP bits */ XCP_RSC_WK_MISMATCH = 48, /* indicated WK (verification pattern) is malformed/does not match targeted one */ XCP_RSC_WK_MISSING = 49, /* service requires a WK, while none present */ XCP_RSC_NEXT_WK_MISSING = 50, /* service requires next-WK, while none present */ XCP_RSC_EC_IMPORT_SYMM = 51, /* can not use KDF-derived value as KEK */ XCP_RSC_RANDOM_WK_PROHIBITED = 52, /* use of random WKs and next-WKs prohibited by policy */ XCP_RSC_WKS_PRESENT = 53, /* presence of WK and pending WK prevents random-WK generation */ XCP_RSC_IMPR_FIELD_SIZE = 54, /* invalid importer type (field length) */ XCP_RSC_IMPORTER_INVD_TYPE = 55, /* requested importer type is unknown/unsupported */ XCP_RSC_IMPR_REVOKE_ZERO = 56, /* not allowed to leave imprint mode with revoke threshold of 0 */ XCP_RSC_IMPR_TOOMANY_SIGNERS = 57, /* attempting to set threshold to more than current signers */ XCP_RSC_IMPR_TOOMANY_REVOKERS = 58, /* attempting to set revoke threshold to more than current signers */ XCP_RSC_OAIDX_FIELD_SIZE = 59, /* invalid OA certificate index (field length) */ XCP_RSC_OAIDX_INVALID = 60, /* OA certificate index out of range */ XCP_RSC_FCV_NOT_PRESENT = 61, /* no FCV has been loaded */ XCP_RSC_FCV_FMT = 62, /* FCV size/structure is invalid */ XCP_RSC_FCV_DIFFERS = 63, /* different FCV is already present */ XCP_RSC_COMMITTED_WK_MISSING = 64, /* service requires a committed pending WK, which is not present */ XCP_RSC_IMPR_EMBEDDED_FN_FMT = 65, /* embedded admin request (external) with malformed function identifier (wrong size) */ XCP_RSC_LOGOUT_BELOW_THRESHOLD = 66, /* attempted logout would decrease number of admins below signature or revocation threshold */ XCP_RSC_LOGOUT_NO_SINGLE_SIGN = 67, /* attempted logout of second last admin but single sign not allowed */ XCP_RSC_LOGOUT_LAST_ADMIN = 68, /* attempted logout of last admin */ XCP_RSC_REACTIVATE_RO_ATTRS = 69, /* attempting to enable reset-only attribute/s */ XCP_RSC_CHG_PROTECTED_ATTRS = 70, /* attempting to modify change-protected attribute/s */ XCP_RSC_CHG_PROTECTED_THRESHOLD = 71, /* attempting to modify change-protected signing or revocation threshold */ XCP_RSC_CHG_READONLY_ATTRS = 72, /* attempting to modify read-only attribute/s */ XCP_RSC_INACTIVE_CHG_ATTRS = 73, /* attempting to modify attributes of inactive backend */ XCP_RSC_CHG_ATTRS_PREVENTED = 74, /* attempting to modify attributes prevented by other setting */ XCP_RSC_IMPR_MANY_KEYPARTS = 75, /* too many keyparts are present */ XCP_RSC_LOWERING_SIGNERS_TO_ZERO = 76, /* lowering sign threshold to zero */ XCP_RSC_LOWERING_REVOKERS_TO_ZERO = 77, /* lowering revoke threshold to zero */ XCP_RSC_CHG_SIGNERS_TO_ONE_NO_1SIGN = 78, /* changing sign threshold to one but XCP_ADMP_1SIGN is not set */ XCP_RSC_CHG_REVOKERS_TO_ONE_NO_1SIGN = 79, /* changing revoke threshold to one but XCP_ADMP_1SIGN is not set */ XCP_RSC_IMPORT_WK_PROHIBITED = 80, /* import of WKs prohibited by policy */ XCP_RSC_IMPR_SINGLE_KEYPART = 81, /* import attempted with single keypart, prohibited by policy */ XCP_RSC_IMPR_CSP = 82, /* crypto operation failed during imported WK administration (should not happen) */ XCP_RSC_QUERY_DMASK_VERSION = 83, /* unsupported domain-mask version */ XCP_RSC_QUERY_DMASK_FMT = 84, /* domain-mask field format invalid */ XCP_RSC_LEAVE_DOM_IMPR_CARD_STILL = 85, /* attempting to leave domain imprint mode but card is still in imprint mode */ XCP_RSC_BLOB_REENCRYPT_REJECT = 86, /* blob to re-encrypt is rejected */ XCP_RSC_TOO_MANY_SIGNERINFOS = 87, /* too many signerinfos present */ XCP_RSC_NO_GLOBAL_CONTEXT = 88, /* no initialized global context */ XCP_RSC_ATTRS_TOO_MANY = 89, /* too many attributes (index too high) */ XCP_RSC_CP_SET_INVALID = 90, /* CP set invalid */ XCP_RSC_RK_IDLEN_INVALID = 91, /* retained-key ID size not supported */ XCP_RSC_RK_ID_INVALID = 92, /* retained-key ID not present */ XCP_RSC_FILEID_UNKNOWN = 93, /* file identifier is beyond those recognized by the backend */ XCP_RSC_FILEID_UNSUPPORTED = 94, /* recognized, conditionally present file ID is not supported by this backend */ XCP_RSC_CPS_REJECTED_FCV = 95, /* requested set of control points conflicts with installed FCV */ XCP_RSC_EXPR_KEYPART_LIMIT = 96, /* requested limit and KPH count inconsistent */ XCP_RSC_EXPR_KEYPART_ZEROLIMIT = 97, /* requested nonzero KP reconstruction limit */ XCP_RSC_EXPR_KEYPART_DIFF_LIMIT = 98, /* export: multiple, different KP reconstruction limits specified */ XCP_RSC_EXPR_KEYPART_DIFF_COUNT = 99, /* export: conflicting keypart counts specified */ XCP_RSC_EXPR_DOMMASK_DIFF = 100, /* export: conflicting domain masks specified */ XCP_RSC_EXPR_INDEX_INVALID = 101, /* export: supplied keypart index repeats or is out of range */ XCP_RSC_EXPR_CERT_INVALID = 102, /* export: supplied KPH certificate is not recognized/unsupported */ XCP_RSC_IMPR_STATE_STRUCT = 103, /* import: state file missing, bytecount out of range, or file structure invalid */ XCP_RSC_EXPR_AUTHCERT_INVALID = 104, /* export: supplied MCA certificate is not recognized/unsupported */ XCP_RSC_IMPR_KEYPARTS_STRUCT = 105, /* import: keyparts missing, bytecount out of range, or file structure invalid */ XCP_RSC_IMPR_STATE_REPEAT = 106, /* import: sections repeat with incompatible instances */ XCP_RSC_IMPR_ENCR_ALG = 107, /* import: unsupported encryption algorithm or malformed auxiliary data */ XCP_RSC_IMPR_FILESIG_INFRASTRUCTURE = 108, /* import: sections related to file-signature are missing, malformed or invalid */ XCP_RSC_IMPR_FILESIG = 109, /* import: signature of the file is invalid (infrastructure has been verified) */ XCP_RSC_EXPR_SINGLE_KEYPART = 110, /* export attempted with 1-of-N keypart/s, prohibited by policy */ XCP_RSC_IMPR_KEYPARTS_REASSEMBLY = 111, /* import: reconstructing key from keyparts failed */ XCP_RSC_IMPR_KEYPARTS_CONFLICT = 112, /* import: multiple keyparts present, with type/size conflicts */ XCP_RSC_IMPR_ENCRD_DATA_DIFF = 113, /* import: multiple, conflicting encrypted state fields present */ XCP_RSC_IMPR_ENCRD_DATA_STRUCT = 114, /* import: encrypted state field missing or size invalid */ XCP_RSC_IMPR_ENCR_PARAMS = 115, /* import: encryption parameter (IV) missing */ XCP_RSC_IMPR_ENCRD_CONSISTENCY = 116, /* import: encrypted state/integrity/structure invalid */ XCP_RSC_BLOB_SETTRUST_REJECT = 117, /* blob to mark as TRUSTED is rejected */ XCP_RSC_BLOB_SETCLK_FIELD = 118, /* time field malformed/missing */ XCP_RSC_BLOB_SETCLK_TIME = 119, /* time field (UTC string) contents invalid */ XCP_RSC_EXPR_SCOPE_INVALID = 120, /* export: scope restriction not recognized/unsupported */ XCP_RSC_IMPR_SCOPE_INVALID = 121, /* import: scope restriction not recognized/unsupported */ XCP_RSC_IMPR_SCOPE_DOM_RES_VIOLATION = 122, /* import: domain restricted scope but card sections present */ XCP_RSC_IMPR_AMBIGUOUS_DOMAIN_SOURCE = 123, /* import: multiple exported domains for multi domain import */ XCP_RSC_IMPR_MDOMAIN_IMPORT_MASK_INVALID = 124, /* import: invalid domain mask for multi domain import */ XCP_RSC_IMPR_NO_CARD_IMPORTER = 125, /* import: no card importer key */ XCP_RSC_IMPR_IMPORT_DOM_DATA_FAILED = 126, /* import: importing domain data failed */ XCP_RSC_IMPR_IMPORT_DOM_WKS_FAILED = 127, /* import: importing domain WKs failed */ XCP_RSC_IMPR_IMPORT_TGT_DOM_ZEROIZE_FAILED = 128, /* import: zeroize of target domain failed */ XCP_RSC_AUDIT_QUERY_PAYLOAD_SIZE = 129, /* audit query: size of payload too small */ XCP_RSC_AUDIT_QUERY_INVALID_INDEX = 130, /* audit query: invalid audit history index */ XCP_RSC_EXPORT_WK_PROHIBITED = 131, /* export of WKs prohibited by policy */ XCP_RSC_EXPORT_STATE_PROHIBITED = 132, /* export of state prohibited by policy */ XCP_RSC_IMPORT_STATE_PROHIBITED = 133, /* import of state prohibited by policy */ XCP_RSC_EXPORT_WK_UNAUTHORIZED = 134, /* Card admin attempted to export a DnD domain WK (empty dom admin exp.request?) */ XCP_RSC_OA_SIG_POLICY_VIOLATION = 135, /* invalid OA signature config, at least one OA signature type must be enabled */ XCP_RSC_OA_SIG_NOT_SUPPORTED = 136, /* requested OA signature type not supported/configured */ XCP_RSC_ASN_FMT_INVALID = 137, /* invalid ASN.1 encoded format */ XCP_RSC_CERT_TYPE_INVALID = 138, /* Certificate type invalid */ XCP_RSC_ROLE_ID_INVALID = 139, /* Role ID invalid */ XCP_RSC_ADM_SIG_POLICY_VIOLATION = 140, /* invalid ADM signature config, at least one ADM signature type must be enabled */ XCP_RSC_KEY_STRENGTH_POLICY_VIOLATION = 141, /* invalid key strength configuration, a maximum of only one bit may be enabled */ XCP_RSC_ADM_SIG_CHANGE_PROHIBITED = 142, /* ADM signature configuration change prohibited, not enough remaining admins to meet security */ XCP_RSC_KEY_STRENGTH_CHANGE_PROHIBITED = 143, /* Key strength configuration change prohibited, not enough remaining admins to meet security */ XCP_RSC_ADM_KTYPE_POLICY_VIOLATION = 144, /* invalid ADM key type config, inconsistent sig/key types or no key type enabled at all */ XCP_RSC_ADM_KTYPE_CHANGE_PROHIBITED = 145, /* Key type configuration change prohibited, not enough remaining admins to meet security */ XCP_RSC_ADM_SVC_ADMIN_POLICY_VIOLATION = 146, /* Changing security policy or thresholds prohibited, not enough svc admins to meet security */ XCP_RSC_ADM_EP11_ADMIN_POLICY_VIOLATION = 147, /* Changing security policy or thresholds prohibited, not enough ep11 admins to meet security */ XCP_RSC_CMD_NOT_ALLOWED_IN_INACTIVE_STATE = 148, /* Command rejected, card is in inactive state */ XCP_RSC_MAX = XCP_RSC_CMD_NOT_ALLOWED_IN_INACTIVE_STATE } XCP_ReasonCode_t ; /* function identifiers must be consecutive, between: */ #define __MIN_MOD_FNID 1 #define __MAX_MOD_FNID 44 /* selectively disabled functions within that range reported separately */ #define __FNID_Login 1 #define __FNID_Logout 2 #define __FNID_SeedRandom 3 #define __FNID_GenerateRandom 4 #define __FNID_DigestInit 5 #define __FNID_DigestUpdate 6 #define __FNID_DigestKey 7 #define __FNID_DigestFinal 8 #define __FNID_Digest 9 #define __FNID_DigestSingle 10 #define __FNID_EncryptInit 11 #define __FNID_DecryptInit 12 #define __FNID_EncryptUpdate 13 #define __FNID_DecryptUpdate 14 #define __FNID_EncryptFinal 15 #define __FNID_DecryptFinal 16 #define __FNID_Encrypt 17 #define __FNID_Decrypt 18 #define __FNID_EncryptSingle 19 #define __FNID_DecryptSingle 20 #define __FNID_GenerateKey 21 #define __FNID_GenerateKeyPair 22 #define __FNID_SignInit 23 #define __FNID_SignUpdate 24 #define __FNID_SignFinal 25 #define __FNID_Sign 26 #define __FNID_VerifyInit 27 #define __FNID_VerifyUpdate 28 #define __FNID_VerifyFinal 29 #define __FNID_Verify 30 #define __FNID_SignSingle 31 #define __FNID_VerifySingle 32 #define __FNID_WrapKey 33 #define __FNID_UnwrapKey 34 #define __FNID_DeriveKey 35 #define __FNID_GetMechanismList 36 #define __FNID_GetMechanismInfo 37 #define __FNID_get_xcp_info 38 #define __FNID_GetAttributeValue 39 #define __FNID_SetAttributeValue 40 #define __FNID_admin 41 #define __FNID_ReencryptSingle 42 #define __FNID_LoginExtended 43 #define __FNID_LogoutExtended 44 // #define __FNID_NEXT_AVAILABLE 45 // #define __FNID_MAX __FNID_LogoutExtended // // 64 bit mask. See XCP__FNIDS_DW1 if more bits required (up to 128 bit) #define XCP__FNIDS_BIT0 0x8000000000000000ULL #define XCP__FNIDS_DW0 \ ( (XCP__FNIDS_BIT0) |\ (XCP__FNIDS_BIT0 >> __FNID_Login) |\ (XCP__FNIDS_BIT0 >> __FNID_Logout) |\ (XCP__FNIDS_BIT0 >> __FNID_SeedRandom) |\ (XCP__FNIDS_BIT0 >> __FNID_GenerateRandom) |\ (XCP__FNIDS_BIT0 >> __FNID_DigestInit) |\ (XCP__FNIDS_BIT0 >> __FNID_DigestUpdate) |\ /*NOTE: FNID_DigestKey is not supported \ (XCP__FNIDS_BIT0 >> __FNID_DigestKey) |\ */ \ (XCP__FNIDS_BIT0 >> __FNID_DigestFinal) |\ (XCP__FNIDS_BIT0 >> __FNID_Digest) |\ (XCP__FNIDS_BIT0 >> __FNID_DigestSingle) |\ (XCP__FNIDS_BIT0 >> __FNID_EncryptInit) |\ (XCP__FNIDS_BIT0 >> __FNID_DecryptInit) |\ (XCP__FNIDS_BIT0 >> __FNID_EncryptUpdate) |\ (XCP__FNIDS_BIT0 >> __FNID_DecryptUpdate) |\ (XCP__FNIDS_BIT0 >> __FNID_EncryptFinal) |\ (XCP__FNIDS_BIT0 >> __FNID_DecryptFinal) |\ (XCP__FNIDS_BIT0 >> __FNID_Encrypt) |\ (XCP__FNIDS_BIT0 >> __FNID_Decrypt) |\ (XCP__FNIDS_BIT0 >> __FNID_EncryptSingle) |\ (XCP__FNIDS_BIT0 >> __FNID_DecryptSingle) |\ (XCP__FNIDS_BIT0 >> __FNID_GenerateKey) |\ (XCP__FNIDS_BIT0 >> __FNID_GenerateKeyPair) |\ (XCP__FNIDS_BIT0 >> __FNID_SignInit) |\ (XCP__FNIDS_BIT0 >> __FNID_SignUpdate) |\ (XCP__FNIDS_BIT0 >> __FNID_SignFinal) |\ (XCP__FNIDS_BIT0 >> __FNID_Sign) |\ (XCP__FNIDS_BIT0 >> __FNID_VerifyInit) |\ (XCP__FNIDS_BIT0 >> __FNID_VerifyUpdate) |\ (XCP__FNIDS_BIT0 >> __FNID_VerifyFinal) |\ (XCP__FNIDS_BIT0 >> __FNID_Verify) |\ (XCP__FNIDS_BIT0 >> __FNID_SignSingle) |\ (XCP__FNIDS_BIT0 >> __FNID_VerifySingle) |\ (XCP__FNIDS_BIT0 >> __FNID_WrapKey) |\ (XCP__FNIDS_BIT0 >> __FNID_UnwrapKey) |\ (XCP__FNIDS_BIT0 >> __FNID_DeriveKey) |\ (XCP__FNIDS_BIT0 >> __FNID_GetMechanismList) |\ (XCP__FNIDS_BIT0 >> __FNID_GetMechanismInfo) |\ (XCP__FNIDS_BIT0 >> __FNID_get_xcp_info) |\ (XCP__FNIDS_BIT0 >> __FNID_GetAttributeValue) |\ (XCP__FNIDS_BIT0 >> __FNID_SetAttributeValue) |\ (XCP__FNIDS_BIT0 >> __FNID_admin) |\ (XCP__FNIDS_BIT0 >> __FNID_ReencryptSingle) |\ (XCP__FNIDS_BIT0 >> __FNID_LoginExtended) |\ (XCP__FNIDS_BIT0 >> __FNID_LogoutExtended)) // used for the module query, see CK_IBM_XCPMSQ_FNLIST #define XCP__FNIDS_DW1 0 /* maximum nr of non-system parameters: */ #define __HOST2MOD_DATAPRM 9 #define __MOD2HOST_DATAPRM 2 #endif /* n defined(XCP_H__) */ opencryptoki-opencryptoki-451d99c/usr/lib/ep11_stdll/ep11_func.h000066400000000000000000000356221520105705100246150ustar00rootroot00000000000000/* * 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 */ #ifndef EP11_FUNC_H #define EP11_FUNC_H /* * I dont see a better way than to ignore this warning for now. * Note that the GCC pragma also works for clang. */ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpedantic" #include "ep11.h" #include "ep11adm.h" #pragma GCC diagnostic pop #define XCP_MOD_VERSION_1 1 #define XCP_MOD_VERSION_2 2 /* 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 /* EP11 specific mechanisms unknown by ock, known by EP11, but not in ep11.h */ #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_SM3 CKM_VENDOR_DEFINED + 0x0005000e #define XCP_CPB_ALG_PQC_DILITHIUM XCP_CPB_ALG_PQC /* EP11 function types */ 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_LoginExtended_t) (CK_UTF8CHAR_PTR pin, CK_ULONG pinlen, const unsigned char *nonce, size_t nlen, const unsigned char *xstruct, size_t xslen, unsigned char *pinblob, size_t *pinbloblen, target_t target); typedef CK_RV (*m_LogoutExtended_t) (CK_UTF8CHAR_PTR pin, CK_ULONG pinlen, const unsigned char *nonce, size_t nlen, const unsigned char *xstruct, size_t xslen, 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); 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); 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_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 *, size_t, struct XCPadmresp *, CK_RV *); #endif opencryptoki-opencryptoki-451d99c/usr/lib/ep11_stdll/ep11_login.c000066400000000000000000001122101520105705100247520ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2023 * * 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 #define OCK_NO_EP11_DEFINES #include "pkcs11types.h" #include "defs.h" #include "host_defs.h" #include "h_extern.h" #include "trace.h" #include #include #include #if OPENSSL_VERSION_PREREQ(3, 0) #include #endif #include "ep11_specific.h" static const CK_BYTE zero_session[XCP_WK_BYTES] = { 0 }; static const CK_BYTE OID_IBM_misc_ep11_session_info[] = { 0x06, 0x0c, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x02, 0x82, 0x0b, 0x87, 0x67, 0x04, 0x01 }; static CK_RV generate_ec_session_key(XCP_LoginImporter_t imp_keytype, EVP_PKEY **ec_privkey) { EVP_PKEY_CTX *ctx = NULL; CK_RV rc = CKR_FUNCTION_FAILED; int nid; switch (imp_keytype) { case XCP_LOGIN_IMPR_EC_P256: nid = NID_X9_62_prime256v1; break; case XCP_LOGIN_IMPR_EC_P521: nid = NID_secp521r1; break; default: TRACE_ERROR("%s Unsupported importer key type: %d\n", __func__, imp_keytype); return CKR_ARGUMENTS_BAD; } ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL); if (ctx == NULL) { TRACE_ERROR("%s EVP_PKEY_CTX_new_id failed\n", __func__); goto out; } if (EVP_PKEY_keygen_init(ctx) <= 0) { TRACE_ERROR("%s EVP_PKEY_keygen_init failed\n", __func__); goto out; } if (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, nid) <= 0) { TRACE_ERROR("%s EVP_PKEY_CTX_set_ec_paramgen_curve_nid failed\n", __func__); goto out; } if (EVP_PKEY_keygen(ctx, ec_privkey) <= 0) { TRACE_ERROR("%s EVP_PKEY_keygen failed\n", __func__); goto out; } rc = CKR_OK; out: if (ctx != NULL) EVP_PKEY_CTX_free(ctx); return rc; } static CK_RV get_login_importer_key(target_t target, XCP_LoginImporter_t imp_keytype, CK_BYTE ski[XCP_CERTHASH_BYTES], CK_BYTE tcounter[XCP_ADMCTR_BYTES], EVP_PKEY **ec_pubkey) { CK_BYTE res[XCP_LOGIN_IMPR_MAX_SIZE]; CK_ULONG reslen = sizeof(res); CK_BYTE *data = NULL, *spki = NULL, *ski_field = NULL, *cnt = NULL; CK_ULONG data_len = 0, field_len = 0; CK_ULONG spki_len = 0, ski_field_len, cnt_len = 0; const unsigned char *p; CK_RV rc; rc = dll_m_get_xcp_info(res, &reslen, CK_IBM_XCPQ_LOGIN_IMPORTER, imp_keytype, target); if (rc != CKR_OK) { TRACE_ERROR("%s Failed to query Login Importer key: 0x%lx\n", __func__, rc); return CKR_FUNCTION_FAILED; } /* * xcpRsp ::= SEQUENCE * SKI OCTET STRING, * SPKI OCTET STRING (SEQUENCE ...), * tcounter OCTET STRING (16 bytes) */ rc = ber_decode_SEQUENCE(res, reslen, &data, &data_len, &field_len); if (rc != CKR_OK || field_len > reslen) { TRACE_ERROR("%s ber_decode_SEQUENCE failed\n", __func__); return CKR_FUNCTION_FAILED; } rc = ber_decode_OCTET_STRING(data, data_len, &ski_field, &ski_field_len, &field_len); if (rc != CKR_OK || field_len > data_len) { TRACE_ERROR("%s ber_decode_OCTET_STRING (SKI) failed\n", __func__); return CKR_FUNCTION_FAILED; } data += field_len; data_len -= field_len; rc = ber_decode_OCTET_STRING(data, data_len, &spki, &spki_len, &field_len); if (rc != CKR_OK || field_len > data_len) { TRACE_ERROR("%s ber_decode_OCTET_STRING (SPKI) failed\n", __func__); return CKR_FUNCTION_FAILED; } data += field_len; data_len -= field_len; rc = ber_decode_OCTET_STRING(data, data_len, &cnt, &cnt_len, &field_len); if (rc != CKR_OK || field_len > data_len) { TRACE_ERROR("%s ber_decode_OCTET_STRING (COUNTER) failed\n", __func__); return CKR_FUNCTION_FAILED; } #ifdef DEBUG TRACE_DEBUG("SKI (size: %lu):\n", ski_field_len); TRACE_DEBUG_DUMP(" ", ski_field, ski_field_len); TRACE_DEBUG("SPKI (size: %lu):\n", spki_len); TRACE_DEBUG_DUMP(" ", spki, spki_len); TRACE_DEBUG("TCounter (size: %lu):\n", cnt_len); TRACE_DEBUG_DUMP(" ", cnt, cnt_len); #endif if (ski_field_len != XCP_CERTHASH_BYTES) { TRACE_ERROR("%s SKI length is not as expected (%lu != %u)\n", __func__, ski_field_len, XCP_CERTHASH_BYTES); return CKR_BUFFER_TOO_SMALL; } memcpy(ski, ski_field, ski_field_len); if (cnt_len > XCP_ADMCTR_BYTES) { TRACE_ERROR("%s counter length is too large (%lu > %lu)\n", __func__, cnt_len, XCP_ADMCTR_BYTES); return CKR_FUNCTION_FAILED; } memset(tcounter, 0, XCP_ADMCTR_BYTES - cnt_len); memcpy(tcounter + XCP_ADMCTR_BYTES - cnt_len, cnt, cnt_len); p = (const unsigned char *)spki; *ec_pubkey = d2i_PUBKEY(NULL, &p, spki_len); if (*ec_pubkey == NULL) { TRACE_ERROR("%s d2i_PUBKEY failed\n", __func__); return CKR_FUNCTION_FAILED; } return rc; } static void increment_tcounter(CK_BYTE tcounter[XCP_ADMCTR_BYTES]) { int i; for (i = XCP_ADMCTR_BYTES - 1; i >= 0; i--) { tcounter[i]++; if (tcounter[i] != 0) break; } #ifdef DEBUG TRACE_DEBUG("TCounter after increment:\n"); TRACE_DEBUG_DUMP(" ", tcounter, XCP_ADMCTR_BYTES); #endif } static CK_RV ecdh_derive(EVP_PKEY *privkey, EVP_PKEY *pubkey, CK_BYTE *secret, CK_ULONG *secret_len) { CK_RV rc = CKR_FUNCTION_FAILED; EVP_PKEY_CTX *ctx = NULL; ctx = EVP_PKEY_CTX_new(privkey, NULL); if (ctx == NULL) { TRACE_ERROR("%s EVP_PKEY_CTX_new failed\n", __func__); goto out; } if (EVP_PKEY_derive_init(ctx) <= 0) { TRACE_ERROR("%s EVP_PKEY_derive_init failed\n", __func__); goto out; } if (EVP_PKEY_derive_set_peer(ctx, pubkey) != 1) { TRACE_ERROR("%s EVP_PKEY_derive_set_peer failed\n", __func__); goto out; } if (EVP_PKEY_derive(ctx, secret, secret_len) <= 0) { TRACE_ERROR("%s EVP_PKEY_derive failed\n", __func__); goto out; } #ifdef DEBUG TRACE_DEBUG("Shared secret (%lu bytes):\n", *secret_len); TRACE_DEBUG_DUMP(" ", secret, *secret_len); #endif rc = CKR_OK; out: if (ctx != NULL) EVP_PKEY_CTX_free(ctx); return rc; } #if OPENSSL_VERSION_PREREQ(3, 0) static int ec_prime_len_from_nid(int nid) { EC_GROUP *group; int primelen; group = EC_GROUP_new_by_curve_name(nid); if (group == NULL) return -1; primelen = EC_GROUP_order_bits(group); EC_GROUP_free(group); return (primelen + 7) / 8; } #endif static int ec_prime_len_from_pkey(EVP_PKEY *pkey) { #if !OPENSSL_VERSION_PREREQ(3, 0) return (EC_GROUP_order_bits(EC_KEY_get0_group( EVP_PKEY_get0_EC_KEY(pkey))) + 7) / 8; #else size_t curve_len; char curve[80]; if (!EVP_PKEY_get_utf8_string_param(pkey, OSSL_PKEY_PARAM_GROUP_NAME, curve, sizeof(curve), &curve_len)) return -1; return ec_prime_len_from_nid(OBJ_sn2nid(curve)); #endif } static CK_RV ec_x_from_pkey(EVP_PKEY *pkey, CK_BYTE *x, CK_ULONG *x_len) { int prime_len; #if OPENSSL_VERSION_PREREQ(3, 0) OSSL_PARAM params[2]; #else const EC_KEY *ec_key; BIGNUM *bn_x = NULL; #endif prime_len = ec_prime_len_from_pkey(pkey); if (prime_len < 0) { TRACE_ERROR("%s ec_prime_len_from_pkey failed\n", __func__); return CKR_FUNCTION_FAILED; } if (*x_len < (CK_ULONG)prime_len) { TRACE_ERROR("%s X buffer too small\n", __func__); return CKR_BUFFER_TOO_SMALL; } *x_len = prime_len; #if OPENSSL_VERSION_PREREQ(3, 0) params[0] = OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_EC_PUB_X, x, *x_len); params[1] = OSSL_PARAM_construct_end(); if (EVP_PKEY_get_params(pkey, params) != 1 || !OSSL_PARAM_modified(¶ms[0])) { TRACE_ERROR("%s EVP_PKEY_get_params failed\n", __func__); return CKR_FUNCTION_FAILED; } #else ec_key = EVP_PKEY_get0_EC_KEY(pkey); if (ec_key == NULL) { TRACE_ERROR("EVP_PKEY_get0_EC_KEY failed\n"); return CKR_FUNCTION_FAILED; } bn_x = BN_new(); if (bn_x == NULL) { TRACE_ERROR("BN_new failed\n"); return CKR_HOST_MEMORY; } if (!EC_POINT_get_affine_coordinates(EC_KEY_get0_group(ec_key), EC_KEY_get0_public_key(ec_key), bn_x, NULL, NULL)) { TRACE_ERROR("EC_POINT_get_affine_coordinates failed\n"); BN_free(bn_x); return CKR_FUNCTION_FAILED; } if (BN_bn2binpad(bn_x, x, *x_len) != (int)*x_len) { TRACE_ERROR("BN_bn2binpad failed\n"); BN_free(bn_x); return CKR_FUNCTION_FAILED; } BN_free(bn_x); #endif #ifdef DEBUG TRACE_DEBUG("EC coordinate X (%lu bytes):\n", *x_len); TRACE_DEBUG_DUMP(" ", x, *x_len); #endif return CKR_OK; } static CK_RV kdf_sp800_56c_sha256(EVP_PKEY *ec_privkey, CK_BYTE *secret, CK_ULONG secret_len, CK_BYTE key[AES_KEY_SIZE_256]) { CK_RV rc = CKR_FUNCTION_FAILED; EVP_MD_CTX *ctx = NULL; CK_BYTE x[256]; CK_ULONG x_len = sizeof(x); uint32_t be32_1 = htobe32(1); unsigned int md_len = AES_KEY_SIZE_256; /* * key = SHA256( BE32(1) * || BE32(1) * || secret * || X coordinate of callers public key Qe ) */ rc = ec_x_from_pkey(ec_privkey, x, &x_len); if (rc != CKR_OK) return rc; ctx = EVP_MD_CTX_new(); if (ctx == NULL) { TRACE_ERROR("%s EVP_MD_CTX_new failed\n", __func__); goto out; } if (EVP_DigestInit_ex(ctx, EVP_sha256(), NULL) != 1) { TRACE_ERROR("%s EVP_DigestInit_ex failed\n", __func__); goto out; } if (EVP_DigestUpdate(ctx, &be32_1, sizeof(be32_1)) != 1) { TRACE_ERROR("%s EVP_DigestUpdate failed\n", __func__); goto out; } if (EVP_DigestUpdate(ctx, &be32_1, sizeof(be32_1)) != 1) { TRACE_ERROR("%s EVP_DigestUpdate failed\n", __func__); goto out; } if (EVP_DigestUpdate(ctx, secret, secret_len) != 1) { TRACE_ERROR("%s EVP_DigestUpdate failed\n", __func__); goto out; } if (EVP_DigestUpdate(ctx, x, x_len) != 1) { TRACE_ERROR("%s EVP_DigestUpdate failed\n", __func__); goto out; } if (EVP_DigestFinal(ctx, key, &md_len) != 1 || md_len != AES_KEY_SIZE_256) { TRACE_ERROR("%s EVP_DigestFinal failed\n", __func__); goto out; } #ifdef DEBUG TRACE_DEBUG("Derived key (%u bytes):\n", AES_KEY_SIZE_256); TRACE_DEBUG_DUMP(" ", key, AES_KEY_SIZE_256); #endif rc = CKR_OK; out: if (ctx != NULL) EVP_MD_CTX_free(ctx); return rc; } static CK_RV create_login_recipient(const CK_BYTE ski[XCP_CERTHASH_BYTES], EVP_PKEY *ec_privkey, CK_BYTE **buf, CK_ULONG *buf_len) { CK_RV rc; CK_BBOOL length_only = (buf == NULL); uint32_t version = htobe32(1); CK_BYTE *spki = NULL, *data = NULL; CK_BYTE *v1_os = NULL, *ski_os = NULL, *spki_os = NULL; CK_ULONG v1_os_len, ski_os_len, spki_os_len, data_len, ofs; int spki_len; /* * LoginRecipient ::= SEQUENCE * OCTET STRING <00000001> -- v1 * OCTET STRING -- SKI (recipient) * OCTET STRING ( * SEQUENCE ... -- SPKI (sender) * ) */ spki_len = i2d_PUBKEY(ec_privkey, length_only ? NULL : &spki); if (spki_len <= 0 || (spki == NULL && !length_only)) { TRACE_ERROR("%s i2d_PUBKEY failed\n", __func__); rc = CKR_FUNCTION_FAILED; goto out; } #ifdef DEBUG TRACE_DEBUG("SPKI (%u bytes):\n", spki_len); if (!length_only) { TRACE_DEBUG_DUMP(" ", spki, spki_len); } #endif rc = ber_encode_OCTET_STRING(length_only, &v1_os, &v1_os_len, (CK_BYTE *)&version, sizeof(version)); if (rc != CKR_OK) { TRACE_ERROR("%s ber_encode_OCTET_STRING (VERSION) failed\n", __func__); goto out; } rc = ber_encode_OCTET_STRING(length_only, &ski_os, &ski_os_len, (CK_BYTE *)ski, XCP_CERTHASH_BYTES); if (rc != CKR_OK) { TRACE_ERROR("%s ber_encode_OCTET_STRING (SKI) failed\n", __func__); goto out; } rc = ber_encode_OCTET_STRING(length_only, &spki_os, &spki_os_len, spki, spki_len); if (rc != CKR_OK) { TRACE_ERROR("%s ber_encode_OCTET_STRING (SPKI) failed\n", __func__); goto out; } data_len = v1_os_len + ski_os_len + spki_os_len; if (!length_only) { data = malloc(data_len); if (data == NULL) { TRACE_ERROR("%s Failed to allocate data buffer\n", __func__); rc = CKR_HOST_MEMORY; goto out; } ofs = 0; memcpy(data + ofs, v1_os, v1_os_len); ofs += v1_os_len; memcpy(data + ofs, ski_os, ski_os_len); ofs += ski_os_len; memcpy(data + ofs, spki_os, spki_os_len); } rc = ber_encode_SEQUENCE(length_only, buf, buf_len, data, data_len); if (rc != CKR_OK) { TRACE_ERROR("%s ber_encode_SEQUENCE failed\n", __func__); goto out; } #ifdef DEBUG TRACE_DEBUG("Login recipient (%lu bytes):\n", *buf_len); if (!length_only) { TRACE_DEBUG_DUMP(" ", *buf, *buf_len); } #endif out: if (spki != NULL) OPENSSL_free(spki); if (v1_os != NULL) free(v1_os); if (ski_os != NULL) free(ski_os); if (spki_os != NULL) free(spki_os); if (data != NULL) free(data); return rc; } static CK_RV create_login_extended_info(const CK_BYTE ski[XCP_CERTHASH_BYTES], XCP_LoginAlgorithm_t login_alg, const CK_BYTE *parent_session_id, EVP_PKEY *ec_privkey, CK_BYTE **buf, CK_ULONG *buf_len) { CK_RV rc; CK_BBOOL length_only = (buf == NULL); uint32_t alg = htobe32(login_alg); CK_BYTE *recipient = NULL, *data = NULL; CK_ULONG recipient_len, data_len, ofs; CK_BYTE *vers_os = NULL, *alg_os = NULL, *parent_os = NULL; CK_BYTE *recipient_os = NULL, *attr_os = NULL, *ctx_os = NULL; CK_ULONG vers_os_len, alg_os_len, parent_os_len, recipient_os_len; CK_ULONG attr_os_len, ctx_os_len; /* * CK_IBM_LOGIN_EXTENDED_INFO ::= SEQUENCE * version OCTET STRING -- OBJECT IDENTIFIER * OID_IBM_misc_ep11_session_info) * -- 1.3.6.1.4.1.2.267.999.4.1 * algorithm OCTET STRING -- derivation algorithm, 4 Bytes * parent OCTET STRING -- parent session id, 32 Bytes, may be zero * recipient OCTET STRING -- OPTIONAL: recipient info * attributes OCTET STRING -- OPTIONAL: session attributes, 8 Bytes * context OCTET STRING -- OPTIONAL: additional session context */ rc = create_login_recipient(ski, ec_privkey, length_only ? NULL : &recipient, &recipient_len); if (rc != CKR_OK) { TRACE_ERROR("%s create_login_recipient failed\n", __func__); goto out; } rc = ber_encode_OCTET_STRING(length_only, &vers_os, &vers_os_len, (CK_BYTE *)OID_IBM_misc_ep11_session_info, sizeof(OID_IBM_misc_ep11_session_info)); if (rc != CKR_OK) { TRACE_ERROR("%s ber_encode_OCTET_STRING (VERSION) failed\n", __func__); goto out; } rc = ber_encode_OCTET_STRING(length_only, &alg_os, &alg_os_len, (CK_BYTE *)&alg, sizeof(alg)); if (rc != CKR_OK) { TRACE_ERROR("%s ber_encode_OCTET_STRING (ALG) failed\n", __func__); goto out; } rc = ber_encode_OCTET_STRING(length_only, &parent_os, &parent_os_len, (CK_BYTE *)(parent_session_id != NULL ? parent_session_id : zero_session), XCP_WK_BYTES); if (rc != CKR_OK) { TRACE_ERROR("%s ber_encode_OCTET_STRING (PARENT) failed\n", __func__); goto out; } rc = ber_encode_OCTET_STRING(length_only, &recipient_os, &recipient_os_len, recipient, recipient_len); if (rc != CKR_OK) { TRACE_ERROR("%s ber_encode_OCTET_STRING (RECIPIENT) failed\n", __func__); goto out; } rc = ber_encode_OCTET_STRING(length_only, &attr_os, &attr_os_len, (CK_BYTE *)"", 0); if (rc != CKR_OK) { TRACE_ERROR("%s ber_encode_OCTET_STRING (ATTRS) failed\n", __func__); goto out; } rc = ber_encode_OCTET_STRING(length_only, &ctx_os, &ctx_os_len, (CK_BYTE *)"", 0); if (rc != CKR_OK) { TRACE_ERROR("%s ber_encode_OCTET_STRING (CONTEXT) failed\n", __func__); goto out; } data_len = vers_os_len + alg_os_len + parent_os_len + recipient_os_len + attr_os_len + ctx_os_len; if (!length_only) { data = malloc(data_len); if (data == NULL) { TRACE_ERROR("%s Failed to allocate data buffer\n", __func__); rc = CKR_HOST_MEMORY; goto out; } ofs = 0; memcpy(data + ofs, vers_os, vers_os_len); ofs += vers_os_len; memcpy(data + ofs, alg_os, alg_os_len); ofs += alg_os_len; memcpy(data + ofs, parent_os, parent_os_len); ofs += parent_os_len; memcpy(data + ofs, recipient_os, recipient_os_len); ofs += recipient_os_len; memcpy(data + ofs, attr_os, attr_os_len); ofs += attr_os_len; memcpy(data + ofs, ctx_os, ctx_os_len); } rc = ber_encode_SEQUENCE(length_only, buf, buf_len, data, data_len); if (rc != CKR_OK) { TRACE_ERROR("%s ber_encode_SEQUENCE failed\n", __func__); goto out; } #ifdef DEBUG TRACE_DEBUG("Login extended info (%lu bytes):\n", *buf_len); if (!length_only) { TRACE_DEBUG_DUMP(" ", *buf, *buf_len); } #endif out: if (recipient != NULL) free(recipient); if (vers_os != NULL) free(vers_os); if (alg_os != NULL) free(alg_os); if (parent_os != NULL) free(parent_os); if (recipient_os != NULL) free(recipient_os); if (attr_os != NULL) free(attr_os); if (ctx_os != NULL) free(ctx_os); if (data != NULL) free(data); return rc; } static CK_RV create_padded_pin(const CK_BYTE *pin, CK_ULONG pin_len, const CK_BYTE tcounter[XCP_ADMCTR_BYTES], int func_id, CK_BYTE **buf, CK_ULONG *buf_len) { CK_RV rc; CK_BBOOL length_only = (buf == NULL); uint32_t version = htobe32(1); uint32_t fnid = htobe32(func_id); CK_BYTE *vers_os = NULL, *fnid_os = NULL, *counter_os = NULL; CK_BYTE *pin_os = NULL, *data = NULL; CK_ULONG vers_os_len, fnid_os_len, counter_os_len, pin_os_len; CK_ULONG data_len, ofs; /* * PaddedPIN ::= SEQUENCE * OCTET STRING <00000001> -- v1 * OCTET STRING -- function ID targeted * - LoginExtended/LogoutExtended * OCTET STRING -- transaction counter +1 * OCTET STRING -- user-provided PIN */ rc = ber_encode_OCTET_STRING(length_only, &vers_os, &vers_os_len, (CK_BYTE *)&version, sizeof(version)); if (rc != CKR_OK) { TRACE_ERROR("%s ber_encode_OCTET_STRING (VERSION) failed\n", __func__); goto out; } rc = ber_encode_OCTET_STRING(length_only, &fnid_os, &fnid_os_len, (CK_BYTE *)&fnid, sizeof(fnid)); if (rc != CKR_OK) { TRACE_ERROR("%s ber_encode_OCTET_STRING (FNID) failed\n", __func__); goto out; } rc = ber_encode_OCTET_STRING(length_only, &counter_os, &counter_os_len, (CK_BYTE *)tcounter, XCP_ADMCTR_BYTES); if (rc != CKR_OK) { TRACE_ERROR("%s ber_encode_OCTET_STRING (COUNTER) failed\n", __func__); goto out; } rc = ber_encode_OCTET_STRING(length_only, &pin_os, &pin_os_len, (CK_BYTE *)pin, pin_len); if (rc != CKR_OK) { TRACE_ERROR("%s ber_encode_OCTET_STRING (PIN) failed\n", __func__); goto out; } data_len = vers_os_len + fnid_os_len + counter_os_len + pin_os_len; if (!length_only) { data = malloc(data_len); if (data == NULL) { TRACE_ERROR("%s Failed to allocate data buffer\n", __func__); rc = CKR_HOST_MEMORY; goto out; } ofs = 0; memcpy(data + ofs, vers_os, vers_os_len); ofs += vers_os_len; memcpy(data + ofs, fnid_os, fnid_os_len); ofs += fnid_os_len; memcpy(data + ofs, counter_os, counter_os_len); ofs += counter_os_len; memcpy(data + ofs, pin_os, pin_os_len); } rc = ber_encode_SEQUENCE(length_only, buf, buf_len, data, data_len); if (rc != CKR_OK) { TRACE_ERROR("%s ber_encode_SEQUENCE failed\n", __func__); goto out; } #ifdef DEBUG TRACE_DEBUG("Padded pin (%lu bytes):\n", *buf_len); if (!length_only) { TRACE_DEBUG_DUMP(" ", *buf, *buf_len); } #endif out: if (vers_os != NULL) free(vers_os); if (fnid_os != NULL) free(fnid_os); if (counter_os != NULL) free(counter_os); if (pin_os != NULL) free(pin_os); if (data != NULL) free(data); return rc; } static CK_ULONG aes_256_wrap_pad_encrypt_len(CK_ULONG clear_len) { CK_ULONG enc_len; /* * aes_256_wrap_pad encrypt pads up to 8 bytes if the input length is * not a multiple of 8 bytes, and it always adds an authentication tag of * 8 bytes. */ enc_len = clear_len; if (clear_len % 8 > 0) enc_len += 8 - (clear_len % 8); return enc_len + 8; } static CK_RV encrypt_padded_pin(const CK_BYTE* padded_pin, CK_ULONG padded_pin_len, const CK_BYTE key[AES_KEY_SIZE_256], CK_BYTE **buf, CK_ULONG *buf_len) { CK_RV rc = CKR_FUNCTION_FAILED; EVP_CIPHER_CTX *ctx; int len, total_len; if (buf == NULL) { *buf_len = aes_256_wrap_pad_encrypt_len(padded_pin_len); return CKR_OK; } ctx = EVP_CIPHER_CTX_new(); if (ctx == NULL) { TRACE_ERROR("%s EVP_CIPHER_CTX_new failed\n", __func__); goto out; } EVP_CIPHER_CTX_set_flags(ctx, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW); if (EVP_EncryptInit_ex(ctx, EVP_aes_256_wrap_pad(), NULL, key, NULL) != 1) { TRACE_ERROR("%s EVP_EncryptInit_ex failed\n", __func__); goto out; } total_len = aes_256_wrap_pad_encrypt_len(padded_pin_len); *buf = malloc(total_len); if (*buf == NULL) { TRACE_ERROR("%s Failed to allocate output buffer\n", __func__); rc = CKR_HOST_MEMORY; goto out; } len = total_len; if (EVP_EncryptUpdate(ctx, *buf, &len, padded_pin, padded_pin_len) != 1) { TRACE_ERROR("%s EVP_EncryptUpdate failed\n", __func__); goto out; } *buf_len = len; len = total_len - len; if (EVP_EncryptFinal(ctx, (*buf) + *buf_len, &len) != 1) { TRACE_ERROR("%s EVP_EncryptFinal failed\n", __func__); goto out; } *buf_len += len; #ifdef DEBUG TRACE_DEBUG("Encrypted padded pin (%lu bytes):\n", *buf_len); TRACE_DEBUG_DUMP(" ", *buf, *buf_len); #endif rc = CKR_OK; out: if (ctx != NULL) EVP_CIPHER_CTX_free(ctx); return rc; } static CK_RV decrypt_pinblob(const CK_BYTE *enc_pinblob, CK_ULONG enc_pinblob_len, const CK_BYTE key[AES_KEY_SIZE_256], CK_BYTE *pinblob, CK_ULONG *pinblob_len) { CK_RV rc = CKR_FUNCTION_FAILED; EVP_CIPHER_CTX *ctx; int len, remaining; #ifdef DEBUG TRACE_DEBUG("Encrypted pin blob (%lu bytes):\n", enc_pinblob_len); TRACE_DEBUG_DUMP(" ", (CK_BYTE *)enc_pinblob, enc_pinblob_len); #endif if (*pinblob_len < enc_pinblob_len - 8) { TRACE_ERROR("%s pin blob buffer is too small\n", __func__); return CKR_BUFFER_TOO_SMALL; } ctx = EVP_CIPHER_CTX_new(); if (ctx == NULL) { TRACE_ERROR("%s EVP_CIPHER_CTX_new failed\n", __func__); goto out; } EVP_CIPHER_CTX_set_flags(ctx, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW); if (EVP_DecryptInit_ex(ctx, EVP_aes_256_wrap_pad(), NULL, key, NULL) != 1) { TRACE_ERROR("%s EVP_DecryptInit_ex failed\n", __func__); goto out; } len = *pinblob_len; if (EVP_DecryptUpdate(ctx, pinblob, &len, enc_pinblob, enc_pinblob_len) != 1) { TRACE_ERROR("%s EVP_DecryptUpdate failed\n", __func__); goto out; } remaining = *pinblob_len - len; *pinblob_len = len; len = remaining; if (EVP_DecryptFinal(ctx, pinblob + *pinblob_len, &len) != 1) { TRACE_ERROR("%s EVP_DecryptFinal failed\n", __func__); goto out; } *pinblob_len += len; #ifdef DEBUG TRACE_DEBUG("Clear pin blob (%lu bytes):\n", *pinblob_len); TRACE_DEBUG_DUMP(" ", pinblob, *pinblob_len); #endif rc = CKR_OK; out: if (ctx != NULL) EVP_CIPHER_CTX_free(ctx); return rc; } static CK_RV derive_pinblob_key(const CK_BYTE *pinblob, CK_ULONG pinblob_len, const CK_BYTE *pin, CK_ULONG pin_len, CK_BYTE key[AES_KEY_SIZE_256]) { CK_RV rc = CKR_FUNCTION_FAILED; EVP_MD_CTX *ctx = NULL; uint32_t be32_1 = htobe32(1); uint32_t be32_3 = htobe32(3); uint8_t be8_0 = 0; unsigned int md_len = AES_KEY_SIZE_256; /* * CLear pin blob: * SKM 32 session key modifier * s 16 intermediate value for operational pinblob / * session identifier calculation */ if (pinblob_len != 48 || pinblob[EP11_PINBLOB_MARKER_OFS] != EP11_PINBLOB_V1_MARKER) { TRACE_ERROR("%s pinblob is invalid\n", __func__); goto out; } /* key = SHA-256(BE32(1) || BE32(3) || PIN || BE8(0) || s) */ ctx = EVP_MD_CTX_new(); if (ctx == NULL) { TRACE_ERROR("%s EVP_MD_CTX_new failed\n", __func__); goto out; } if (EVP_DigestInit_ex(ctx, EVP_sha256(), NULL) != 1) { TRACE_ERROR("%s EVP_DigestInit_ex failed\n", __func__); goto out; } if (EVP_DigestUpdate(ctx, &be32_1, sizeof(be32_1)) != 1) { TRACE_ERROR("%s EVP_DigestUpdate failed\n", __func__); goto out; } if (EVP_DigestUpdate(ctx, &be32_3, sizeof(be32_3)) != 1) { TRACE_ERROR("%s EVP_DigestUpdate failed\n", __func__); goto out; } if (EVP_DigestUpdate(ctx, pin, pin_len) != 1) { TRACE_ERROR("%s EVP_DigestUpdate failed\n", __func__); goto out; } if (EVP_DigestUpdate(ctx, &be8_0, sizeof(be8_0)) != 1) { TRACE_ERROR("%s EVP_DigestUpdate failed\n", __func__); goto out; } if (EVP_DigestUpdate(ctx, pinblob + XCP_WK_BYTES, 16) != 1) { TRACE_ERROR("%s EVP_DigestUpdate failed\n", __func__); goto out; } if (EVP_DigestFinal(ctx, key, &md_len) != 1 || md_len != AES_KEY_SIZE_256) { TRACE_ERROR("%s EVP_DigestFinal failed\n", __func__); goto out; } #ifdef DEBUG TRACE_DEBUG("Derived pin blob key (%u bytes):\n", AES_KEY_SIZE_256); TRACE_DEBUG_DUMP(" ", key, AES_KEY_SIZE_256); #endif rc = CKR_OK; out: if (ctx != NULL) EVP_MD_CTX_free(ctx); return rc; } static CK_RV encrypt_pinblob(const CK_BYTE *pinblob, CK_ULONG pinblob_len, const CK_BYTE key[AES_KEY_SIZE_256], CK_BYTE *op_pinblob, CK_ULONG *op_pinblob_len) { CK_RV rc = CKR_FUNCTION_FAILED; EVP_CIPHER_CTX *ctx; int len, len2; if (aes_256_wrap_pad_encrypt_len(pinblob_len) > *op_pinblob_len) { TRACE_ERROR("%s pin blob buffer is too small\n", __func__); return CKR_BUFFER_TOO_SMALL; } ctx = EVP_CIPHER_CTX_new(); if (ctx == NULL) { TRACE_ERROR("%s EVP_CIPHER_CTX_new failed\n", __func__); goto out; } EVP_CIPHER_CTX_set_flags(ctx, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW); if (EVP_EncryptInit_ex(ctx, EVP_aes_256_wrap_pad(), NULL, key, NULL) != 1) { TRACE_ERROR("%s EVP_EncryptInit_ex failed\n", __func__); goto out; } len = *op_pinblob_len; if (EVP_EncryptUpdate(ctx, op_pinblob, &len, pinblob, pinblob_len) != 1) { TRACE_ERROR("%s EVP_EncryptUpdate failed\n", __func__); goto out; } len2 = *op_pinblob_len - len; if (EVP_EncryptFinal(ctx, op_pinblob + len, &len2) != 1) { TRACE_ERROR("%s EVP_EncryptFinal failed\n", __func__); goto out; } *op_pinblob_len = len + len2; op_pinblob[EP11_PINBLOB_MARKER_OFS] = EP11_PINBLOB_V1_MARKER; if (op_pinblob[0] == 0x30) op_pinblob[0] = 0xcc; #ifdef DEBUG TRACE_DEBUG("Operational pin blob (%lu bytes):\n", *op_pinblob_len); TRACE_DEBUG_DUMP(" ", op_pinblob, *op_pinblob_len); #endif rc = CKR_OK; out: if (ctx != NULL) EVP_CIPHER_CTX_free(ctx); return rc; } static CK_RV do_LoginLogoutExtended(int func_id, XCP_LoginAlgorithm_t alg, XCP_LoginImporter_t imp_keytype, const CK_BYTE *pin, CK_ULONG pin_len, const CK_BYTE *nonce, CK_ULONG nonce_len, CK_BYTE *pin_blob, CK_ULONG *pin_blob_len, const CK_BYTE *parent_session_id, target_t target) { CK_BYTE peer_ski[XCP_CERTHASH_BYTES]; CK_BYTE tcounter[XCP_ADMCTR_BYTES]; CK_BYTE shared_secret[256]; CK_ULONG shared_secret_len = sizeof(shared_secret); CK_BYTE shared_key[AES_KEY_SIZE_256]; CK_BYTE *extended_info = NULL; CK_ULONG extended_info_len = 0; CK_BYTE *padded_pin = NULL; CK_ULONG padded_pin_len = 0; CK_BYTE *enc_padded_pin = NULL; CK_ULONG enc_padded_pin_len = 0; EVP_PKEY *local_ec_privkey = NULL, *peer_ec_pubkey = NULL; CK_BYTE enc_pinblob[XCP_PINBLOB_V1_BYTES]; CK_ULONG enc_pinblob_len = sizeof(enc_pinblob); CK_BYTE clear_pinblob[XCP_PINBLOB_V1_BYTES]; CK_ULONG clear_pinblob_len = sizeof(clear_pinblob); CK_BYTE pinblob_key[AES_KEY_SIZE_256]; CK_ULONG retry_cnt = 0; CK_RV rc; if (alg != XCP_LOGIN_ALG_F2021) { TRACE_ERROR("%s Unsupported login algorithm: %u\n", __func__, alg); return CKR_ARGUMENTS_BAD; } rc = generate_ec_session_key(imp_keytype, &local_ec_privkey); if (rc != CKR_OK) goto done; retry: rc = get_login_importer_key(target, imp_keytype, peer_ski, tcounter, &peer_ec_pubkey); if (rc != CKR_OK) goto done; rc = ecdh_derive(local_ec_privkey, peer_ec_pubkey, shared_secret, &shared_secret_len); if (rc != CKR_OK) goto done; rc = kdf_sp800_56c_sha256(local_ec_privkey, shared_secret, shared_secret_len, shared_key); if (rc != CKR_OK) goto done; rc = create_login_extended_info(peer_ski, alg, parent_session_id, local_ec_privkey, &extended_info, &extended_info_len); if (rc != CKR_OK) goto done; increment_tcounter(tcounter); rc = create_padded_pin(pin, pin_len, tcounter, func_id, &padded_pin, &padded_pin_len); if (rc != CKR_OK) goto done; rc = encrypt_padded_pin(padded_pin, padded_pin_len, shared_key, &enc_padded_pin, &enc_padded_pin_len); if (rc != CKR_OK) goto done; switch (func_id) { case __FNID_LoginExtended: rc = dll_m_LoginExtended(enc_padded_pin, enc_padded_pin_len, nonce, nonce_len, extended_info, extended_info_len, enc_pinblob, &enc_pinblob_len, target); break; case __FNID_LogoutExtended: rc = dll_m_LogoutExtended(enc_padded_pin, enc_padded_pin_len, nonce, nonce_len, extended_info, extended_info_len, target); break; default: TRACE_ERROR("%s Unsupported function: %u\n", __func__, func_id); rc = CKR_FUNCTION_NOT_SUPPORTED; break; } if (rc == CKR_DATA_INVALID && retry_cnt < MAX_RETRY_COUNT) { /* * Transaction counter was modified by other process concurrently. * Retry with updated counter. */ if (peer_ec_pubkey != NULL) { EVP_PKEY_free(peer_ec_pubkey); peer_ec_pubkey = NULL; } if (extended_info != NULL) { free(extended_info); extended_info = NULL; } if (padded_pin != NULL) { OPENSSL_cleanse(padded_pin, padded_pin_len); free(padded_pin); padded_pin = NULL; } if (enc_padded_pin != NULL) { OPENSSL_cleanse(enc_padded_pin, enc_padded_pin_len); free(enc_padded_pin); enc_padded_pin = NULL; } OPENSSL_cleanse(shared_key, sizeof(shared_key)); OPENSSL_cleanse(shared_secret, shared_secret_len); retry_cnt++; goto retry; } if (rc != CKR_OK) goto done; if (func_id == __FNID_LogoutExtended) goto done; rc = decrypt_pinblob(enc_pinblob, enc_pinblob_len, shared_key, clear_pinblob, &clear_pinblob_len); if (rc != CKR_OK) goto done; rc = derive_pinblob_key(clear_pinblob, clear_pinblob_len, pin, pin_len, pinblob_key); if (rc != CKR_OK) goto done; rc = encrypt_pinblob(clear_pinblob, clear_pinblob_len, pinblob_key, pin_blob, pin_blob_len); if (rc != CKR_OK) goto done; done: if (local_ec_privkey != NULL) EVP_PKEY_free(local_ec_privkey); if (peer_ec_pubkey != NULL) EVP_PKEY_free(peer_ec_pubkey); if (extended_info != NULL) free(extended_info); if (padded_pin != NULL) { OPENSSL_cleanse(padded_pin, padded_pin_len); free(padded_pin); } if (enc_padded_pin != NULL) { OPENSSL_cleanse(enc_padded_pin, enc_padded_pin_len); free(enc_padded_pin); } OPENSSL_cleanse(shared_key, sizeof(shared_key)); OPENSSL_cleanse(shared_secret, shared_secret_len); OPENSSL_cleanse(enc_pinblob, enc_pinblob_len); OPENSSL_cleanse(clear_pinblob, clear_pinblob_len); OPENSSL_cleanse(pinblob_key, sizeof(pinblob_key)); return rc; } CK_RV do_LoginExtended(XCP_LoginAlgorithm_t alg, XCP_LoginImporter_t imp_keytype, const CK_BYTE *pin, CK_ULONG pin_len, const CK_BYTE *nonce, CK_ULONG nonce_len, CK_BYTE *pin_blob, CK_ULONG *pin_blob_len, const CK_BYTE *parent_session_id, target_t target) { if (dll_m_LoginExtended == NULL) { TRACE_ERROR("%s dll_m_LoginExtended is not available\n", __func__); return CKR_FUNCTION_NOT_SUPPORTED; } return do_LoginLogoutExtended(__FNID_LoginExtended, alg, imp_keytype, pin, pin_len, nonce, nonce_len, pin_blob, pin_blob_len, parent_session_id, target); } CK_RV do_LogoutExtended(XCP_LoginAlgorithm_t alg, XCP_LoginImporter_t imp_keytype, const CK_BYTE *pin, CK_ULONG pin_len, const CK_BYTE *nonce, CK_ULONG nonce_len, target_t target) { if (dll_m_LogoutExtended == NULL) { TRACE_ERROR("%s dll_m_LogoutExtended is not available\n", __func__); return CKR_FUNCTION_NOT_SUPPORTED; } return do_LoginLogoutExtended(__FNID_LogoutExtended, alg, imp_keytype, pin, pin_len, nonce, nonce_len, NULL, NULL, NULL, target); } opencryptoki-opencryptoki-451d99c/usr/lib/ep11_stdll/ep11_mkchange.c000066400000000000000000001444131520105705100254310ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2001-2023 * * 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 OCK_NO_EP11_DEFINES #include "pkcs11types.h" #include "defs.h" #include "host_defs.h" #include "h_extern.h" #include "attributes.h" #include "trace.h" #include "ock_syslog.h" #include "stdll.h" #include "events.h" #include "hsm_mk_change.h" #include "cfgparser.h" #include "ep11_specific.h" #include #include CK_BBOOL ep11tok_is_blob_new_wkid(STDLL_TokData_t *tokdata, CK_BYTE *blob, CK_ULONG blob_len) { ep11_private_data_t *ep11_data = tokdata->private_data; CK_BYTE *wkid; CK_RV rc; rc = ep11tok_extract_blob_info(blob, blob_len, NULL, &wkid, NULL, NULL); if (rc != CKR_OK || wkid == NULL) { TRACE_ERROR("ep11tok_extract_blob_info failed\n"); return CK_FALSE; } if (memcmp(wkid, ep11_data->new_wkvp, XCP_WKID_BYTES) == 0) return CK_TRUE; return CK_FALSE; } CK_RV ep11tok_reencipher_blob(STDLL_TokData_t *tokdata, SESSION *session, ep11_target_info_t **target_info, CK_BYTE *blob, CK_ULONG blob_len, CK_BYTE *new_blob) { CK_BYTE req[MAX_BLOBSIZE]; CK_BYTE resp[MAX_BLOBSIZE]; CK_LONG req_len = 0; size_t resp_len = 0; struct XCPadmresp rb; struct XCPadmresp lrb; CK_ULONG retry_count = 0; CK_RV rc; UNUSED(tokdata); TRACE_DEVEL("%s blob: %p blob_len: %lu\n", __func__, (void *)blob, blob_len); if ((*target_info)->single_apqn == 0) { TRACE_ERROR("%s must be used with single APQN target\n", __func__); return CKR_FUNCTION_FAILED; } retry: memset(&rb, 0, sizeof(rb)); memset(&lrb, 0, sizeof(lrb)); RETRY_SINGLE_APQN_START(tokdata, rc) rb.domain = (*target_info)->domain; lrb.domain = (*target_info)->domain; resp_len = MAX_BLOBSIZE; req_len = dll_xcpa_cmdblock(req, MAX_BLOBSIZE, XCP_ADM_REENCRYPT, &rb, NULL, blob, blob_len); if (req_len < 0) { TRACE_ERROR("%s reencrypt cmd block construction failed\n", __func__); rc = CKR_FUNCTION_FAILED; break; } rc = dll_m_admin(resp, &resp_len, NULL, 0, req, req_len, NULL, 0, (*target_info)->target); if (session != NULL && (rc == CKR_SESSION_CLOSED || rc == CKR_PIN_INCORRECT)) { rc = ep11tok_relogin_session(tokdata, session); if (rc != CKR_OK) break; continue; } RETRY_SINGLE_APQN_END(rc, tokdata, *target_info) if (rc != CKR_OK || resp_len == 0) { TRACE_ERROR("%s reencryption failed: 0x%lx %ld\n", __func__, rc, req_len); return resp_len == 0 ? CKR_FUNCTION_FAILED : rc; } if (dll_xcpa_internal_rv(resp, resp_len, &lrb, &rc) < 0) { TRACE_ERROR("%s reencryption response malformed: 0x%lx\n", __func__, rc); return CKR_FUNCTION_FAILED; } if (session != NULL && (rc == CKR_SESSION_CLOSED || rc == CKR_PIN_INCORRECT) && retry_count < MAX_RETRY_COUNT) { rc = ep11tok_relogin_session(tokdata, session); if (rc == CKR_OK) { retry_count++; goto retry; } } if (rc != 0) { TRACE_ERROR("%s reencryption failed: rc: 0x%lx reason: %u\n", __func__, rc, lrb.reason); switch (lrb.reason) { case XCP_RSC_WK_MISSING: case XCP_RSC_NEXT_WK_MISSING: rc = CKR_IBM_WK_NOT_INITIALIZED; } return rc; } if (blob_len != lrb.pllen) { TRACE_ERROR("%s reencryption blob size changed: 0x%lx 0x%lx 0x%lx 0x%lx\n", __func__, blob_len, lrb.pllen, resp_len, req_len); return CKR_FUNCTION_FAILED; } memcpy(new_blob, lrb.payload, blob_len); if (!ep11tok_is_blob_new_wkid(tokdata, new_blob, blob_len)) { TRACE_ERROR("%s Re-enciphered key blob is not enciphered by expected " "new WK\n", __func__); OCK_SYSLOG(LOG_ERR, "Slot %lu: Re-enciphered key blob is not enciphered" " by expected new WK\n", tokdata->slot_id); return CKR_DEVICE_ERROR; } return CKR_OK; } static CK_RV ep11tok_mk_change_is_affected(STDLL_TokData_t *tokdata, struct hsm_mk_change_info *info) { ep11_private_data_t *ep11_data = tokdata->private_data; unsigned int i; CK_BBOOL affected = FALSE; if (hsm_mk_change_mkvps_find(info->mkvps, info->num_mkvps, HSM_MK_TYPE_EP11, 0) == NULL) goto out; /* APQN_ANY: token is affected independently of APQNs changed */ if (ep11_data->target_list.length == 0) { affected = TRUE; goto out; } /* APQN_ALLOWLIST */ for (i = 0; i < (unsigned int)ep11_data->target_list.length; i++) { if (hsm_mk_change_apqns_find(info->apqns, info->num_apqns, ep11_data->target_list.apqns[2 * i], ep11_data->target_list.apqns[2 * i + 1])) affected = TRUE; } out: TRACE_DEVEL("%s affected: %d\n", __func__, affected); return affected ? CKR_OK : CKR_FUNCTION_NOT_SUPPORTED; } static CK_RV ep11tok_activate_mk_change_op(STDLL_TokData_t *tokdata, const char *id, const struct hsm_mk_change_info *info) { ep11_private_data_t *ep11_data = tokdata->private_data; ep11_data->mk_change_apqns = calloc(info->num_apqns, sizeof(struct apqn)); if (ep11_data->mk_change_apqns == NULL) { TRACE_ERROR("%s Failed to allocate list of MK change APQNs\n", __func__); return CKR_HOST_MEMORY; } ep11_data->num_mk_change_apqns = info->num_apqns; memcpy(ep11_data->mk_change_apqns, info->apqns, info->num_apqns * sizeof(struct apqn)); strncpy(ep11_data->mk_change_op, id, sizeof(ep11_data->mk_change_op) - 1); ep11_data->mk_change_op[sizeof(ep11_data->mk_change_op) - 1] = '\0'; ep11_data->mk_change_active = 1; return CKR_OK; } static CK_RV ep11tok_mk_change_check_pending_ops_cb(struct hsm_mk_change_op *op, void *private) { STDLL_TokData_t *tokdata = private; ep11_private_data_t *ep11_data; struct hsm_mkvp *mkvps = NULL; unsigned int num_mkvps = 0; const unsigned char *wkvp; int new_wkvp_set = 0; CK_RV rc; ep11_data = tokdata->private_data; rc = ep11tok_mk_change_is_affected(tokdata, &op->info); if (rc != CKR_OK) return CKR_OK; switch (op->state) { case HSM_MK_CH_STATE_REENCIPHERING: case HSM_MK_CH_STATE_REENCIPHERED: /* * There can only be one active MK change op for the EP11 token. * No need to have the hsm_mk_change_rwlock, we're in token init * function, and the API layer starts the event thread only after all * token init's have been performed. */ if (ep11_data->mk_change_active) { TRACE_ERROR("%s Another MK change is already active: %s\n", __func__, ep11_data->mk_change_op); return CKR_FUNCTION_FAILED; } /* Activate this MK change op for the token */ rc = ep11tok_activate_mk_change_op(tokdata, op->id, &op->info); if (rc != CKR_OK) return rc; TRACE_DEVEL("%s active MK change op: %s\n", __func__, ep11_data->mk_change_op); wkvp = hsm_mk_change_mkvps_find(op->info.mkvps, op->info.num_mkvps, HSM_MK_TYPE_EP11, sizeof(ep11_data->new_wkvp)); if (wkvp != NULL) { memcpy(ep11_data->new_wkvp, wkvp, sizeof(ep11_data->new_wkvp)); new_wkvp_set = 1; } if (new_wkvp_set == 0) { TRACE_ERROR("%s No EP11 WKVP found in MK change operation: %s\n", __func__, ep11_data->mk_change_op); return CKR_FUNCTION_FAILED; } TRACE_DEBUG_DUMP("New WKVP: ", ep11_data->new_wkvp, sizeof(ep11_data->new_wkvp)); /* Load expected current WKVP */ rc = hsm_mk_change_token_mkvps_load(op->id, tokdata->slot_id, &mkvps, &num_mkvps); /* Ignore if this failed, no expected current WKVP is set then */ if (rc == CKR_OK) { wkvp = hsm_mk_change_mkvps_find(mkvps, num_mkvps, HSM_MK_TYPE_EP11, sizeof(ep11_data->expected_wkvp)); if (wkvp != NULL) { memcpy(ep11_data->expected_wkvp, wkvp, sizeof(ep11_data->expected_wkvp)); ep11_data->expected_wkvp_set = 1; TRACE_DEBUG_DUMP("Current WKVP: ", ep11_data->expected_wkvp, sizeof(ep11_data->expected_wkvp)); } } break; default: break; } if (mkvps != NULL) { hsm_mk_change_mkvps_clean(mkvps, num_mkvps); free(mkvps); } return CKR_OK; } CK_RV ep11tok_mk_change_check_pending_ops(STDLL_TokData_t *tokdata) { CK_RV rc; rc = hsm_mk_change_lock_create(); if (rc != CKR_OK) return rc; rc = hsm_mk_change_lock(false); if (rc != CKR_OK) goto out; rc = hsm_mk_change_op_iterate(ep11tok_mk_change_check_pending_ops_cb, tokdata); hsm_mk_change_unlock(); out: hsm_mk_change_lock_destroy(); return rc; } struct apqn_check_data { ep11_private_data_t *ep11_data; CK_SLOT_ID slot; event_mk_change_data_t *op; struct hsm_mk_change_info *info; CK_BBOOL finalize; CK_BBOOL cancel; CK_BBOOL error; }; /* * Note: This function is called EVENT_TYPE_MK_CHANGE_INITIATE_QUERY event * handling within the pkcshsm_mk_change tool's process only. It is supposed * to print error messages to stderr to inform the user about errors. * */ static CK_RV mk_change_apqn_check_handler(uint_32 adapter, uint_32 domain, void *handler_data) { struct apqn_check_data *ac = (struct apqn_check_data *)handler_data; CK_IBM_DOMAIN_INFO domain_info; CK_ULONG domain_info_len = sizeof(domain_info); const unsigned char *wkvp; CK_RV rc; target_t target; /* * Check that this APQN is part of the MK change operation, even if it is * offline (this only applies to an APQN_ALLOWLIST configuration, for a * APQN_ANY configuration, we will only be called for currently online * APQNs anyway). */ if (hsm_mk_change_apqns_find(ac->info->apqns, ac->info->num_apqns, adapter, domain) == FALSE) { TRACE_ERROR("%s APQN %02X.%04X is not part of MK change '%s'\n", __func__, adapter, domain, ac->op->id); warnx("Slot %lu: APQN %02X.%04X must be included into this operation.", ac->slot, adapter, domain); ac->error = TRUE; return CKR_OK; } /* Check that current and new WK is as expected */ rc = get_ep11_target_for_apqn(adapter, domain, &target, 0); if (rc != CKR_OK) { warnx("Slot %lu: Failed to get target for APQN %02X.%04X", ac->slot, adapter, domain); ac->error = TRUE; return rc; } rc = dll_m_get_xcp_info(&domain_info, &domain_info_len, CK_IBM_XCPQ_DOMAIN, 0, target); if (rc != CKR_OK) { TRACE_ERROR("%s Failed to query domain info from APQN %02X.%04X: " "0x%lx\n", __func__, adapter, domain, rc); /* card may no longer be online, so ignore this error situation */ rc = CKR_OK; goto out; } if ((domain_info.flags & CK_IBM_DOM_CURR_WK) == 0) { TRACE_ERROR("%s No current EP11 wrapping key is set on APQN %02X.%04X\n", __func__, adapter, domain); warnx("Slot %lu: No current EP11 wrapping key is set on APQN %02X.%04X", ac->slot, adapter, domain); ac->error = TRUE; goto out; } TRACE_DEBUG("%s Current WKVP of APQN %02X.%04X:\n", __func__, adapter, domain); TRACE_DEBUG_DUMP("full WKVP: ", domain_info.wk, sizeof(domain_info.wk)); if (ac->finalize) { /* Current WK must be the new WK. * hsm_mk_change_rwlock is held by caller, if check_new_wk_set is TRUE. */ if (memcmp(domain_info.wk, ac->ep11_data->new_wkvp, XCP_WKID_BYTES) != 0) { TRACE_ERROR("EP11 wrapping key on APQN %02X.%04X does not " "match the new wrapping key\n", adapter, domain); warnx("Slot %lu: The current EP11 WK on APQN %02X.%04X does not match " "the new WK", ac->slot, adapter, domain); ac->error = TRUE; } goto out; } /* Current WK must be the expected WK */ if (memcmp(domain_info.wk, ac->ep11_data->expected_wkvp, XCP_WKID_BYTES) != 0) { TRACE_ERROR("EP11 wrapping key on APQN %02X.%04X does not " "match the expected wrapping key\n", adapter, domain); warnx("Slot %lu: The current EP11 WK on APQN %02X.%04X does not match " "the expected one", ac->slot, adapter, domain); ac->error = TRUE; goto out; } if (ac->cancel) /* Skip new WK check in case of cancel */ goto out; if ((domain_info.flags & CK_IBM_DOM_COMMITTED_NWK) == 0) { TRACE_ERROR("%s No new EP11 wrapping key is set/committed on APQN %02X.%04X\n", __func__, adapter, domain); warnx("Slot %lu: No new EP11 wrapping key is set/committed on APQN %02X.%04X", ac->slot, adapter, domain); ac->error = TRUE; goto out; } TRACE_DEBUG("%s New WKVP of APQN %02X.%04X:\n", __func__, adapter, domain); TRACE_DEBUG_DUMP("full WKVP: ", domain_info.nextwk, sizeof(domain_info.nextwk)); wkvp = hsm_mk_change_mkvps_find(ac->info->mkvps, ac->info->num_mkvps, HSM_MK_TYPE_EP11, XCP_WKID_BYTES); if (wkvp != NULL && memcmp(domain_info.nextwk, wkvp, XCP_WKID_BYTES) != 0) { TRACE_ERROR("New EP11 wrapping key on APQN %02X.%04X does not " "match the specified wrapping key\n", adapter, domain); warnx("Slot %lu: The new EP11 WK on APQN %02X.%04X does not match " "the specified WKVP", ac->slot, adapter, domain); ac->error = TRUE; goto out; } out: free_ep11_target_for_apqn(target); return CKR_OK; } struct reencipher_data { STDLL_TokData_t *tokdata; SESSION *session; ep11_target_info_t *target_info; }; static CK_RV ep11tok_reencipher_objects_reenc(CK_BYTE *sec_key, CK_BYTE *reenc_sec_key, CK_ULONG sec_key_len, void *private) { struct reencipher_data *rd = private; return ep11tok_reencipher_blob(rd->tokdata, rd->session, &rd->target_info, sec_key, sec_key_len, reenc_sec_key); } static CK_RV ep11tok_reencipher_objects_cb(STDLL_TokData_t *tokdata, OBJECT *obj, void *cb_data) { struct reencipher_data *rd = cb_data; SESSION *session_save; CK_RV rc; session_save = rd->session; if (obj->session != NULL) /* session is NULL for token objects */ rd->session = obj->session; rc = obj_mgr_reencipher_secure_key(tokdata, obj, ep11tok_reencipher_objects_reenc, rd); if (rc == CKR_OBJECT_HANDLE_INVALID) /* Obj was deleted by other proc */ rc = CKR_OK; rd->session = session_save; return rc; } static CK_BBOOL ep11tok_reencipher_filter_cb(STDLL_TokData_t *tokdata, OBJECT *obj, void *filter_data) { CK_ATTRIBUTE *attr; UNUSED(tokdata); UNUSED(filter_data); return template_attribute_find(obj->template, CKA_IBM_OPAQUE_REENC, &attr); } static CK_RV ep11tok_reencipher_cancel_objects_cb(STDLL_TokData_t *tokdata, OBJECT *obj, void *cb_data) { CK_RV rc; UNUSED(cb_data); rc = obj_mgr_reencipher_secure_key_cancel(tokdata, obj); if (rc == CKR_ATTRIBUTE_TYPE_INVALID) rc = CKR_OK; if (rc == CKR_OBJECT_HANDLE_INVALID) /* Obj was deleted by other proc */ rc = CKR_OK; return rc; } static CK_BBOOL ep11tok_reencipher_finalize_is_new_wk_cb( STDLL_TokData_t *tokdata, OBJECT *obj, CK_BYTE *sec_key, CK_ULONG sec_key_len, void *cb_private) { UNUSED(cb_private); UNUSED(obj); return ep11tok_is_blob_new_wkid(tokdata, sec_key, sec_key_len); } static CK_RV ep11tok_reencipher_finalize_objects_cb(STDLL_TokData_t *tokdata, OBJECT *obj, void *cb_data) { CK_RV rc; UNUSED(cb_data); rc = obj_mgr_reencipher_secure_key_finalize(tokdata, obj, ep11tok_reencipher_finalize_is_new_wk_cb, NULL); if (rc == CKR_ATTRIBUTE_TYPE_INVALID) rc = CKR_OK; if (rc == CKR_OBJECT_HANDLE_INVALID) /* Obj was deleted by other proc */ rc = CKR_OK; return rc; } static CK_RV ep11tok_reencipher_session_op_ctx(STDLL_TokData_t *tokdata, SESSION *session, CK_BYTE *context, CK_ULONG context_len, ep11_target_info_t **target_info, const char *ctx_type, CK_BBOOL finalize) { CK_RV rc; TRACE_INFO("%s %s %s state blob of session 0x%lx\n", __func__, finalize ? "Finalize" : "Re-encipher", ctx_type, session->handle); OCK_SYSLOG(LOG_DEBUG, "Slot %lu: %s %s state blob of session 0x%lx\n", tokdata->slot_id, finalize ? "Finalize" : "Re-encipher", ctx_type, session->handle); /* The context is allocated at least twice as large as needed */ if (finalize == FALSE) { rc = ep11tok_reencipher_blob(tokdata, session, target_info, context, context_len / 2, context + (context_len / 2)); if (rc != CKR_OK) { TRACE_ERROR("%s failed to re-encipher %s state blob of session " "0x%lx: 0x%lx\n", __func__, ctx_type, session->handle, rc); OCK_SYSLOG(LOG_ERR, "Slot %lu: Failed to re-encipher %s state blob" "of session 0x%lx: 0x%lx\n", tokdata->slot_id, ctx_type, session->handle, rc); return rc; } } else { memcpy(context, context + (context_len / 2), context_len / 2); } return CKR_OK; } struct reencipher_session_data { ep11_target_info_t *target_info; CK_BBOOL finalize; CK_RV (*func)(STDLL_TokData_t *tokdata, SESSION *session, CK_BYTE *context, CK_ULONG context_len, ep11_target_info_t **target_info, const char *ctx_type, CK_BBOOL finalize); }; static CK_RV ep11tok_reencipher_sessions_cb(STDLL_TokData_t *tokdata, SESSION *session, CK_ULONG ctx_type, CK_MECHANISM *mech, CK_OBJECT_HANDLE key, CK_BYTE *context, CK_ULONG context_len, CK_BBOOL init_pending, CK_BBOOL pkey_active, CK_BBOOL recover, void *private) { ep11_private_data_t *ep11_data = tokdata->private_data; struct reencipher_session_data *rsd = private; const char *ctx_type_str = NULL; UNUSED(recover); /* Check preconditions */ switch (ctx_type) { case CONTEXT_TYPE_DIGEST: if (ep11tok_libica_digest_available(tokdata, ep11_data, mech->mechanism)) return CKR_OK; ctx_type_str = "digest"; break; case CONTEXT_TYPE_SIGN: if (init_pending || pkey_active) return CKR_OK; if (ep11tok_is_common_code_sign_verify_mech(mech) || ep11tok_libica_mech_available(tokdata, mech->mechanism, key)) return CKR_OK; ctx_type_str = "sign"; break; case CONTEXT_TYPE_VERIFY: if (init_pending || pkey_active) return CKR_OK; if (ep11tok_is_common_code_sign_verify_mech(mech) || ep11tok_libica_mech_available(tokdata, mech->mechanism, key)) return CKR_OK; ctx_type_str = "verify"; break; case CONTEXT_TYPE_ENCRYPT: if (init_pending || pkey_active) return CKR_OK; ctx_type_str = "encrypt"; break; case CONTEXT_TYPE_DECRYPT: if (init_pending || pkey_active) return CKR_OK; ctx_type_str = "decrypt"; break; default: return CKR_OK; } return rsd->func(tokdata, session, context, context_len, &rsd->target_info, ctx_type_str, rsd->finalize); } static CK_RV ep11tok_reencipher_sessions(STDLL_TokData_t *tokdata, ep11_target_info_t **target_info, CK_BBOOL finalize) { struct reencipher_session_data rsd = { 0 }; CK_RV rc; if (target_info != NULL) rsd.target_info = *target_info; rsd.finalize = finalize; rsd.func = ep11tok_reencipher_session_op_ctx; rc = session_mgr_iterate_session_ops(tokdata, NULL, ep11tok_reencipher_sessions_cb, &rsd); if (target_info != NULL) *target_info = rsd.target_info; return rc; } /* * ATTENTION: This function is called in a separate thread. All actions * performed by this function must be thread save and use locks to lock * against concurrent access by other threads. */ static CK_RV ep11tok_mk_change_init_query(STDLL_TokData_t *tokdata, event_mk_change_data_t *op, struct hsm_mk_change_info *info) { ep11_private_data_t *ep11_data = tokdata->private_data; struct apqn_check_data acd; struct hsm_mkvp mkvp; CK_RV rc; TRACE_DEVEL("%s initial query for MK change op: %s\n", __func__, op->id); memset(&acd, 0, sizeof(acd)); acd.ep11_data = ep11_data; acd.slot = tokdata->slot_id; acd.op = op; acd.info = info; acd.error = FALSE; rc = handle_all_ep11_cards(&ep11_data->target_list, mk_change_apqn_check_handler, &acd); if (rc != CKR_OK) { TRACE_ERROR("%s handle_all_ep11_cards failed: 0x%lx\n", __func__, rc); return rc; } if (acd.error) return CKR_FUNCTION_FAILED; /* Save current WKVP of this token */ mkvp.type = HSM_MK_TYPE_EP11; mkvp.mkvp_len = XCP_WKID_BYTES; mkvp.mkvp = ep11_data->expected_wkvp; rc = hsm_mk_change_lock_create(); if (rc != CKR_OK) return rc; rc = hsm_mk_change_lock(true); if (rc != CKR_OK) goto out; rc = hsm_mk_change_token_mkvps_save(op->id, tokdata->slot_id, &mkvp, 1); hsm_mk_change_unlock(); out: hsm_mk_change_lock_destroy(); return rc; } static void ep11tok_mk_change_find_rw_session_cb(STDLL_TokData_t *tokdata, void *node_value, unsigned long node_idx, void *p3) { SESSION *s = (SESSION *)node_value; CK_SESSION_HANDLE *ret = (CK_SESSION_HANDLE *)p3; UNUSED(tokdata); UNUSED(node_idx); if (*ret != CK_INVALID_HANDLE) return; if ((s->session_info.flags & CKF_RW_SESSION) != 0 && s->session_info.state == CKS_RW_USER_FUNCTIONS) *ret = s->handle; } static CK_RV ep11tok_mk_change_find_rw_session(STDLL_TokData_t *tokdata, SESSION **session) { CK_SESSION_HANDLE handle = CK_INVALID_HANDLE; 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, ep11tok_mk_change_find_rw_session_cb, &handle); pthread_rwlock_unlock(&tokdata->sess_list_rwlock); if (handle == CK_INVALID_HANDLE) { TRACE_ERROR("No R/W session found.\n"); return CKR_FUNCTION_FAILED; } *session = session_mgr_find(tokdata, handle); if (*session == NULL) { TRACE_ERROR("No R/W session found.\n"); return CKR_FUNCTION_FAILED; } return CKR_OK; } /* * ATTENTION: This function is called in a separate thread. All actions * performed by this function must be thread save and use locks to lock * against concurrent access by other threads. */ static CK_RV ep11tok_mk_change_reencipher(STDLL_TokData_t *tokdata, event_mk_change_data_t *op, struct hsm_mk_change_info *info) { ep11_private_data_t *ep11_data = tokdata->private_data; struct reencipher_data rd = { 0 }; CK_RV rc = CKR_OK; const unsigned char *wkvp; int new_wkvp_set = 0; CK_BBOOL token_objs = FALSE; if ((op->flags & EVENT_MK_CHANGE_FLAGS_TOK_OBJS) != 0) { token_objs = TRUE; /* The tool should have logged in a R/W USER session */ rc = ep11tok_mk_change_find_rw_session(tokdata, &rd.session); if (rc != CKR_OK) { TRACE_ERROR("%s No user session exists\n", __func__); OCK_SYSLOG(LOG_ERR, "Slot %lu: No user session exists\n", tokdata->slot_id); return CKR_FUNCTION_FAILED; } } if (pthread_rwlock_wrlock(&tokdata->hsm_mk_change_rwlock) != 0) { TRACE_DEVEL("HSM-MK-change Write-Lock failed.\n"); OCK_SYSLOG(LOG_ERR, "Slot %lu: HSM-MK-change Write-Lock failed\n", tokdata->slot_id); rc = CKR_CANT_LOCK; goto out; } if (token_objs == TRUE && ep11_data->mk_change_active == FALSE) { TRACE_DEVEL("HSM-MK-change must already be active\n"); OCK_SYSLOG(LOG_ERR, "Slot %lu: HSM-MK-change must already be active\n", tokdata->slot_id); rc = CKR_FUNCTION_FAILED; goto out; } /* Activate this MK change operation */ if (ep11_data->mk_change_active == FALSE) { rc = ep11tok_activate_mk_change_op(tokdata, op->id, info); if (rc != CKR_OK) goto out; } TRACE_DEVEL("%s active MK change op: %s\n", __func__, ep11_data->mk_change_op); wkvp = hsm_mk_change_mkvps_find(info->mkvps, info->num_mkvps, HSM_MK_TYPE_EP11, sizeof(ep11_data->new_wkvp)); if (wkvp != NULL) { memcpy(ep11_data->new_wkvp, wkvp, sizeof(ep11_data->new_wkvp)); new_wkvp_set = 1; } if (new_wkvp_set == 0) { TRACE_ERROR("%s No EP11 WKVP found in MK change operation: %s\n", __func__, ep11_data->mk_change_op); OCK_SYSLOG(LOG_ERR, "Slot %lu: No EP11 WKVP found in MK change operation: %s\n", tokdata->slot_id, ep11_data->mk_change_op); rc = CKR_FUNCTION_FAILED; goto out; } TRACE_DEBUG_DUMP("New WKVP: ", ep11_data->new_wkvp, sizeof(ep11_data->new_wkvp)); /* Switch to single APQN mode (only for first event - token_objs = FALSE) */ if (token_objs == FALSE) { rc = refresh_target_info(tokdata, FALSE); if (rc != CKR_OK) { OCK_SYSLOG(LOG_ERR, "Slot %lu: Failed to select a single APQN: 0x%lx\n", tokdata->slot_id, rc); goto out; } } rd.tokdata = tokdata; rd.target_info = get_target_info(tokdata); if (rd.target_info == NULL) { rc = CKR_FUNCTION_FAILED; OCK_SYSLOG(LOG_ERR, "Slot %lu: Failed to select a single APQN\n", tokdata->slot_id); goto out; } if (rd.target_info->single_apqn == FALSE) { TRACE_ERROR("%s Must operate in single-APQN mode\n", __func__); OCK_SYSLOG(LOG_ERR, "Slot %lu: Failed to select a single APQN\n", tokdata->slot_id); rc = CKR_FUNCTION_FAILED; goto out; } /* Re-encipher key objects */ rc = obj_mgr_iterate_key_objects(tokdata, !token_objs, token_objs, NULL, NULL, ep11tok_reencipher_objects_cb, &rd, TRUE, "re-encipher"); if (rc != CKR_OK) goto out; if (!token_objs) { /* Re-encipher session state blobs */ rc = ep11tok_reencipher_sessions(tokdata, &rd.target_info, FALSE); if (rc != CKR_OK) { OCK_SYSLOG(LOG_ERR, "Slot %lu: Failed to re-encipher session " "states: 0x%lx\n", tokdata->slot_id, rc); goto out; } /* Re-enciper the wrap blob (if already available) */ if (pthread_mutex_lock(&ep11_data->raw2key_wrap_blob_mutex)) { TRACE_ERROR("%s Failed to lock Wrap-Blob lock\n", __func__); rc = CKR_CANT_LOCK; goto out; } if (ep11_data->raw2key_wrap_blob_l > 0) { TRACE_INFO("Re-encipher the wrap blob\n"); rc = ep11tok_reencipher_blob(tokdata, NULL, &rd.target_info, ep11_data->raw2key_wrap_blob, ep11_data->raw2key_wrap_blob_l, ep11_data->raw2key_wrap_blob_reenc); } if (pthread_mutex_unlock(&ep11_data->raw2key_wrap_blob_mutex)) { TRACE_ERROR("%s Failed to unlock Wrap-Blob lock\n", __func__); } if (rc != CKR_OK) { TRACE_ERROR("Re-encipher of wrap blob failed.\n"); OCK_SYSLOG(LOG_ERR, "Slot %lu: Failed to re-encipher the wrap blob: 0x%lx\n", tokdata->slot_id, rc); goto out; } } out: if (rc != CKR_OK && rd.target_info != NULL) { obj_mgr_iterate_key_objects(tokdata, !token_objs, token_objs, ep11tok_reencipher_filter_cb, NULL, ep11tok_reencipher_cancel_objects_cb, NULL, TRUE, "cancel"); /* * The pkcshsm_mk_change tool will send a CANCEL event, so leave the * operation active for now. */ } put_target_info(tokdata, rd.target_info); if (rd.session != NULL) session_mgr_put(tokdata, rd.session); if (pthread_rwlock_unlock(&tokdata->hsm_mk_change_rwlock) != 0) { TRACE_DEVEL("HSM-MK-change Unlock failed.\n"); OCK_SYSLOG(LOG_ERR, "Slot %lu: HSM-MK-change unlock failed\n", tokdata->slot_id); if (rc == CKR_OK) rc = CKR_CANT_LOCK; } return rc; } static CK_RV ep11tok_set_operation_state_cb(STDLL_TokData_t *tokdata, SESSION *session, CK_BYTE *context, CK_ULONG context_len, ep11_target_info_t **target_info, const char *ctx_type, CK_BBOOL finalize) { TRACE_INFO("%s Re-encipher %s state blob of session 0x%lx\n", __func__, ctx_type, session->handle); if (ep11tok_is_blob_new_wkid(tokdata, context, context_len / 2)) { TRACE_DEVEL("%s state blob is already enciphered with new WK\n", __func__); return CKR_OK; } if (ep11tok_is_blob_new_wkid(tokdata, context + (context_len / 2), context_len / 2)) { TRACE_DEVEL("%s state blob is already reenciphered\n", __func__); return CKR_OK; } if ((*target_info)->single_apqn_has_new_wk) { TRACE_ERROR("%s New WK already activated, state blob can not be " "reenciphered\n", __func__); return CKR_SAVED_STATE_INVALID; } return ep11tok_reencipher_session_op_ctx(tokdata, session, context, context_len, target_info, ctx_type, finalize); } CK_RV ep11tok_set_operation_state(STDLL_TokData_t *tokdata, SESSION *session) { ep11_private_data_t *ep11_data = tokdata->private_data; struct reencipher_session_data rsd = { 0 }; CK_RV rc; if (ep11_data->mk_change_active == FALSE) return CKR_OK; /* Re-encipher the newly set session (if needed) */ rsd.target_info = get_target_info(tokdata); if (rsd.target_info == NULL) return CKR_FUNCTION_FAILED; rsd.finalize = FALSE; rsd.func = ep11tok_set_operation_state_cb; rc = session_mgr_iterate_session_ops(tokdata, session, ep11tok_reencipher_sessions_cb, &rsd); put_target_info(tokdata, rsd.target_info); return rc; } static CK_RV parse_expected_wkvp(ep11_private_data_t *ep11_data, const char *fname, const char *strval, unsigned char expected_wkvp[XCP_WKID_BYTES]) { unsigned int i, val; if (strncasecmp(strval, "0x", 2) == 0) strval += 2; if (strlen(strval) < XCP_WKID_BYTES * 2) { TRACE_ERROR("%s expected WKVP is too short: '%s', expected %lu hex " "characters in config file '%s'\n", __func__, strval, sizeof(ep11_data->expected_wkvp) * 2, fname); return CKR_FUNCTION_FAILED; } if (strlen(strval) > XCP_WKID_BYTES * 2) { TRACE_INFO("%s only the first %lu characters of the expected WKVP in " "config file '%s' are used: %s\n", __func__, sizeof(ep11_data->expected_wkvp) * 2, fname, strval); } for (i = 0; i < XCP_WKID_BYTES; i++) { if (sscanf(strval + (i * 2), "%02x", &val) != 1) { TRACE_ERROR("%s failed to parse expected WKVP: '%s' at character " "%u in config file '%s'\n", __func__, strval, (i * 2), fname); return CKR_FUNCTION_FAILED; } expected_wkvp[i] = val; } TRACE_DEBUG_DUMP("Expected WKVP: ", expected_wkvp, XCP_WKID_BYTES); return CKR_OK; } static CK_RV check_token_config_expected_wkvp(STDLL_TokData_t *tokdata, CK_BBOOL new_wk) { ep11_private_data_t *ep11_data = tokdata->private_data; struct ConfigBaseNode *c, *config = NULL; struct ConfigBareStringConstNode *barestr; unsigned char wkvp[XCP_WKID_BYTES]; char *strval = NULL; FILE *fp; CK_RV rc = CKR_OK; int rc2, i; fp = fopen(ep11_data->token_config_filename, "r"); if (fp == NULL) { TRACE_ERROR("Failed to open config file '%s'\n", ep11_data->token_config_filename); return CKR_FUNCTION_FAILED; } rc2 = parse_configlib_file(fp, &config, ep11_config_parse_error, 0); fclose(fp); if (rc2 != 0) { TRACE_ERROR("Error parsing config file '%s'\n", ep11_data->token_config_filename); return CKR_FUNCTION_FAILED; } confignode_foreach(c, config, i) { TRACE_DEBUG("Config node: '%s' type: %u line: %u\n", c->key, c->type, c->line); if (strcmp(c->key, "EXPECTED_WKVP") == 0) { if (confignode_hastype(c, CT_STRINGVAL) || confignode_hastype(c, CT_BAREVAL)) { /* New style (key = value) tokens */ strval = confignode_getstr(c); break; } else if (confignode_hastype(c, CT_BARECONST)) { rc = ep11_config_next(&c, CT_BARESTRINGCONST, ep11_data->token_config_filename, "WKID as quoted hex string"); if (rc != CKR_OK) break; barestr = confignode_to_barestringconst(c); strval = barestr->base.key; break; } ep11_config_error_token(ep11_data->token_config_filename, c->key, c->line, NULL); rc = CKR_FUNCTION_FAILED; break; } } if (strval == NULL) { TRACE_DEVEL("No 'EXPECTED_WKVP' in config file '%s'\n", ep11_data->token_config_filename); goto out; } rc = parse_expected_wkvp(ep11_data, ep11_data->token_config_filename, strval, wkvp); if (rc != CKR_OK) goto out; if (memcmp(wkvp, new_wk ? ep11_data->new_wkvp : ep11_data->expected_wkvp, XCP_WKID_BYTES) != 0) { TRACE_ERROR("Expected WKVP in config file '%s' does not specify the %s WKVP\n", ep11_data->token_config_filename, new_wk ? "new" : "current"); warnx("Expected WKVP in config file '%s' does not specify the %s WKVP.", ep11_data->token_config_filename, new_wk ? "new" : "current"); rc = CKR_FUNCTION_FAILED; } out: confignode_deepfree(config); return rc; } /* * ATTENTION: This function is called in a separate thread. All actions * performed by this function must be thread save and use locks to lock * against concurrent access by other threads. */ static CK_RV ep11tok_mk_change_finalize_query(STDLL_TokData_t *tokdata, event_mk_change_data_t *op, struct hsm_mk_change_info *info) { ep11_private_data_t *ep11_data = tokdata->private_data; struct apqn_check_data acd; CK_RV rc; TRACE_DEVEL("%s finalize query for MK change op: %s\n", __func__, op->id); if (pthread_rwlock_rdlock(&tokdata->hsm_mk_change_rwlock) != 0) { TRACE_DEVEL("MK-change Read-Lock failed.\n"); return CKR_CANT_LOCK; } memset(&acd, 0, sizeof(acd)); acd.ep11_data = ep11_data; acd.slot = tokdata->slot_id; acd.op = op; acd.info = info; acd.finalize = TRUE; /* New WK must be set */ acd.error = FALSE; rc = handle_all_ep11_cards(&ep11_data->target_list, mk_change_apqn_check_handler, &acd); if (rc != CKR_OK) { TRACE_ERROR("%s handle_all_ep11_cards failed: 0x%lx\n", __func__, rc); goto out; } if (acd.error) { rc = CKR_FUNCTION_FAILED; goto out; } rc = check_token_config_expected_wkvp(tokdata, TRUE); if (rc != CKR_OK) { TRACE_ERROR("%s check_token_config_expected_wkvp failed: 0x%lx\n", __func__, rc); goto out; } out: if (pthread_rwlock_unlock(&tokdata->hsm_mk_change_rwlock) != 0) { TRACE_DEVEL("MK-change Unlock failed.\n"); return CKR_CANT_LOCK; } return rc; } /* * ATTENTION: This function is called in a separate thread. All actions * performed by this function must be thread save and use locks to lock * against concurrent access by other threads. */ static CK_RV ep11tok_mk_change_finalize_cancel(STDLL_TokData_t *tokdata, event_mk_change_data_t *op, struct hsm_mk_change_info *info, CK_BBOOL cancel) { ep11_private_data_t *ep11_data = tokdata->private_data; CK_RV rc = CKR_OK; CK_BBOOL token_objs = FALSE; UNUSED(info); TRACE_DEVEL("%s %s MK change op: %s\n", __func__, cancel ? "canceling" : "finalizing", op->id); if ((op->flags & EVENT_MK_CHANGE_FLAGS_TOK_OBJS) != 0 || (op->flags & EVENT_MK_CHANGE_FLAGS_TOK_OBJS_FINAL) != 0) { token_objs = TRUE; /* The tool should have logged in a R/W USER session */ if (!session_mgr_user_session_exists(tokdata)) { TRACE_ERROR("%s No user session exists\n", __func__); OCK_SYSLOG(LOG_ERR, "Slot %lu: No user session exists\n", tokdata->slot_id); return CKR_FUNCTION_FAILED; } } if (pthread_rwlock_wrlock(&tokdata->hsm_mk_change_rwlock) != 0) { TRACE_DEVEL("HSM-MK-change Write-Lock failed.\n"); OCK_SYSLOG(LOG_ERR, "Slot %lu: HSM-MK-change Write-Lock failed\n", tokdata->slot_id); rc = CKR_CANT_LOCK; goto out; } if (ep11_data->mk_change_active == FALSE) goto out; /* * Finalize/cancel token objects. * If flag EVENT_MK_CHANGE_FLAGS_TOK_OBJS_FINAL is on, only process such * token objects that do have the CKA_IBM_OPAQUE_REENC attribute. Those * Objects have been newly created by another process after the first token * finalization/cancellation (flag EVENT_MK_CHANGE_FLAGS_TOK_OBJS) has * been performed, and before all processes have deactivated the MK change * operation. Thus, they were created with the re-enciphered secure key, * and now need to be finalized/canceled. */ rc = obj_mgr_iterate_key_objects(tokdata, !token_objs, token_objs, token_objs && (op->flags & EVENT_MK_CHANGE_FLAGS_TOK_OBJS_FINAL) ? ep11tok_reencipher_filter_cb : NULL, NULL, cancel ? ep11tok_reencipher_cancel_objects_cb : ep11tok_reencipher_finalize_objects_cb, NULL, TRUE, cancel ? "cancel" : "finalize"); if (rc != CKR_OK) goto out; if (!token_objs && !cancel) { /* finalize session state blobs */ rc = ep11tok_reencipher_sessions(tokdata, NULL, TRUE); if (rc != CKR_OK) { OCK_SYSLOG(LOG_ERR, "Slot %lu: Failed to finalize session states: 0x%lx\n", tokdata->slot_id, rc); goto out; } /* Finalize the wrap blob (if already available) */ if (pthread_mutex_lock(&ep11_data->raw2key_wrap_blob_mutex)) { TRACE_ERROR("%s Failed to lock Wrap-Blob lock\n", __func__); rc = CKR_CANT_LOCK; goto out; } if (ep11_data->raw2key_wrap_blob_l > 0) { TRACE_INFO("Finalize the wrap blob\n"); memcpy(ep11_data->raw2key_wrap_blob, ep11_data->raw2key_wrap_blob_reenc, ep11_data->raw2key_wrap_blob_l); } if (pthread_mutex_unlock(&ep11_data->raw2key_wrap_blob_mutex)) { TRACE_ERROR("%s Failed to unlock Wrap-Blob lock\n", __func__); } } /* * Deactivate this MK change operation. * For the pkcshsm_mk_change tool: Deactivate only after 2nd token object * processing. */ if ((token_objs == FALSE && op->tool_pid != tokdata->real_pid) || (op->flags & EVENT_MK_CHANGE_FLAGS_TOK_OBJS_FINAL) != 0) { if (!cancel) { /* From now on the new WK is the expected one */ memcpy(ep11_data->expected_wkvp, ep11_data->new_wkvp, XCP_WKID_BYTES); } ep11_data->mk_change_active = 0; memset(ep11_data->mk_change_op, 0, sizeof(ep11_data->mk_change_op)); free(ep11_data->mk_change_apqns); ep11_data->mk_change_apqns = NULL; ep11_data->num_mk_change_apqns = 0; /* Switch to multiple APQN mode */ rc = refresh_target_info(tokdata, FALSE); if (rc != CKR_OK) { OCK_SYSLOG(LOG_ERR, "Slot %lu: Failed to switch back to multi-APQN mode\n", tokdata->slot_id); goto out; } TRACE_DEVEL("%s %s MK change op: %s\n", __func__, cancel ? "canceled" : "finalized", op->id); OCK_SYSLOG(LOG_INFO, "Slot %lu: Concurrent HSM master key change " "operation %s is %s, EP11 token now use multi-APQN mode\n", tokdata->slot_id, op->id, cancel ? "canceled" : "finalized"); } out: if (pthread_rwlock_unlock(&tokdata->hsm_mk_change_rwlock) != 0) { TRACE_DEVEL("HSM-MK-change Unlock failed.\n"); OCK_SYSLOG(LOG_ERR, "Slot %lu: HSM-MK-change unlock failed\n", tokdata->slot_id); if (rc == CKR_OK) rc = CKR_CANT_LOCK; } return rc; } /* * ATTENTION: This function is called in a separate thread. All actions * performed by this function must be thread save and use locks to lock * against concurrent access by other threads. */ static CK_RV ep11tok_mk_change_cancel_query(STDLL_TokData_t *tokdata, event_mk_change_data_t *op, struct hsm_mk_change_info *info) { ep11_private_data_t *ep11_data = tokdata->private_data; struct apqn_check_data acd; CK_RV rc; TRACE_DEVEL("%s cancel query for MK change op: %s\n", __func__, op->id); if (pthread_rwlock_rdlock(&tokdata->hsm_mk_change_rwlock) != 0) { TRACE_DEVEL("MK-change Read-Lock failed.\n"); return CKR_CANT_LOCK; } memset(&acd, 0, sizeof(acd)); acd.ep11_data = ep11_data; acd.slot = tokdata->slot_id; acd.op = op; acd.info = info; acd.cancel = TRUE; /* No new WK must be set */ acd.error = FALSE; rc = handle_all_ep11_cards(&ep11_data->target_list, mk_change_apqn_check_handler, &acd); if (rc != CKR_OK) { TRACE_ERROR("%s handle_all_ep11_cards failed: 0x%lx\n", __func__, rc); goto out; } if (acd.error) { rc = CKR_FUNCTION_FAILED; goto out; } rc = check_token_config_expected_wkvp(tokdata, FALSE); if (rc != CKR_OK) { TRACE_ERROR("%s check_token_config_expected_wkvp failed: 0x%lx\n", __func__, rc); goto out; } out: if (pthread_rwlock_unlock(&tokdata->hsm_mk_change_rwlock) != 0) { TRACE_DEVEL("MK-change Unlock failed.\n"); return CKR_CANT_LOCK; } return rc; } /* * ATTENTION: This function is called in a separate thread. All actions * performed by this function must be thread save and use locks to lock * against concurrent access by other threads. */ CK_RV ep11tok_handle_mk_change_event(STDLL_TokData_t *tokdata, unsigned int event_type, unsigned int event_flags, const char *payload, unsigned int payload_len) { ep11_private_data_t *ep11_data = tokdata->private_data; CK_RV rc; size_t bytes_read = 0; struct hsm_mk_change_info info = { 0 }; event_mk_change_data_t *hdr = (event_mk_change_data_t *)payload; UNUSED(event_flags); TRACE_DEVEL("%s event: 0x%x\n", __func__, event_type); if (payload_len <= sizeof (*hdr)) return CKR_DATA_LEN_RANGE; TRACE_DEVEL("%s id: '%s' flags: 0x%x tool_pid: %d\n", __func__, hdr->id, hdr->flags, hdr->tool_pid); rc = hsm_mk_change_info_unflatten((unsigned char *)payload + sizeof(*hdr), payload_len - sizeof(*hdr), &bytes_read, &info); if (rc != CKR_OK) return rc; if (bytes_read < payload_len - sizeof(*hdr)) { rc = CKR_DATA_LEN_RANGE; goto out; } rc = ep11tok_mk_change_is_affected(tokdata, &info); if (rc != CKR_OK) goto out; if (pthread_rwlock_rdlock(&tokdata->hsm_mk_change_rwlock) != 0) { TRACE_DEVEL("HSM-MK-change Read-Lock failed.\n"); rc = CKR_CANT_LOCK; goto out; } if (ep11_data->mk_change_active && strcmp(ep11_data->mk_change_op, hdr->id) != 0) { TRACE_ERROR("%s Must be currently active operation: '%s' vs '%s'\n", __func__, ep11_data->mk_change_op, hdr->id); rc = CKR_FUNCTION_FAILED; pthread_rwlock_unlock(&tokdata->hsm_mk_change_rwlock); goto out; } if (pthread_rwlock_unlock(&tokdata->hsm_mk_change_rwlock) != 0) { TRACE_DEVEL("HSM-MK-change Unlock failed.\n"); rc = CKR_CANT_LOCK; goto out; } switch (event_type) { case EVENT_TYPE_MK_CHANGE_INITIATE_QUERY: rc = ep11tok_mk_change_init_query(tokdata, hdr, &info); break; case EVENT_TYPE_MK_CHANGE_REENCIPHER: rc = ep11tok_mk_change_reencipher(tokdata, hdr, &info); break; case EVENT_TYPE_MK_CHANGE_FINALIZE_QUERY: rc = ep11tok_mk_change_finalize_query(tokdata, hdr, &info); break; case EVENT_TYPE_MK_CHANGE_FINALIZE: rc = ep11tok_mk_change_finalize_cancel(tokdata, hdr, &info, FALSE); break; case EVENT_TYPE_MK_CHANGE_CANCEL_QUERY: rc = ep11tok_mk_change_cancel_query(tokdata, hdr, &info); break; case EVENT_TYPE_MK_CHANGE_CANCEL: rc = ep11tok_mk_change_finalize_cancel(tokdata, hdr, &info, TRUE); break; default: rc = CKR_FUNCTION_NOT_SUPPORTED; break; } out: hsm_mk_change_info_clean(&info); TRACE_DEVEL("%s rc: 0x%lx\n", __func__, rc); return rc; } opencryptoki-opencryptoki-451d99c/usr/lib/ep11_stdll/ep11_session.c000066400000000000000000001243101520105705100253310ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2001-2023 * * 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 OCK_NO_EP11_DEFINES #include "pkcs11types.h" #include "defs.h" #include "host_defs.h" #include "h_extern.h" #include "attributes.h" #include "trace.h" #include "ock_syslog.h" #include "stdll.h" #include #include #include #include "ep11_specific.h" 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_SetAttributeValue(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, CK_BBOOL in_fork_initializer); 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, CK_BBOOL in_fork_initializer); static CK_RV update_ep11_object(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *handle, CK_OBJECT_HANDLE obj, ep11_serialno_t *serial_numbers, CK_ULONG num_serial_numbers); 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; } CK_BOOL ep11_is_private_object(CK_ATTRIBUTE_PTR attrs, CK_ULONG attrs_len) { CK_ATTRIBUTE_PTR attr; attr = get_attribute_by_type(attrs, attrs_len, CKA_PRIVATE); if (attr == NULL) return FALSE; if (attr->pValue == NULL) return FALSE; return *((CK_BBOOL *)attr->pValue); } 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; login_logout_data_t data = { 0 }; ST_SESSION_HANDLE handle = { .slotID = session->session_info.slotID, .sessionh = session->handle }; CK_SESSION_HANDLE helper_session = CK_INVALID_HANDLE; CK_ULONG num_serial_numbers_before = 0; CK_RV rc, rc2; TRACE_INFO("%s session=%lu\n", __func__, session->handle); if (!ep11_data->strict_mode && !ep11_data->vhsm_mode && !ep11_data->fips_session_mode) return CKR_OK; if (ep11_data->strict_mode && ep11_session == NULL) { TRACE_INFO("%s Session not yet logged in\n", __func__); return CKR_USER_NOT_LOGGED_IN; } if (ep11_data->vhsm_mode || ep11_data->fips_session_mode) { if (pthread_mutex_lock(&ep11_data->session_mutex)) { TRACE_ERROR("%s Failed to lock session lock\n", __func__); return CKR_CANT_LOCK; } } if (ep11_data->strict_mode) num_serial_numbers_before = ep11_session->num_serial_numbers; data.tokdata = tokdata; data.ep11_session = ep11_session; data.relogin = TRUE; rc = handle_all_ep11_cards(&ep11_data->target_list, ep11_login_handler, &data); if (rc != CKR_OK) { TRACE_ERROR("%s handle_all_ep11_cards failed: 0x%lx\n", __func__, rc); goto unlock; } /* Update Session object if list of serial numbers changed */ if (ep11_data->strict_mode && num_serial_numbers_before != ep11_session->num_serial_numbers) { 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__); rc = CKR_OK; goto unlock; case CKS_RO_USER_FUNCTIONS: rc = ep11_open_helper_session(tokdata, session, &helper_session); if (rc != CKR_OK) goto unlock; handle.sessionh = helper_session; break; default: break; } rc = update_ep11_object(tokdata, &handle, ep11_session->session_object, ep11_session->serial_numbers, ep11_session->num_serial_numbers); if (rc != CKR_OK) { TRACE_ERROR("%s update_ep11_object failed: 0x%lx\n", __func__, rc); goto unlock; } } unlock: if (ep11_data->vhsm_mode || ep11_data->fips_session_mode) { if (pthread_mutex_unlock(&ep11_data->session_mutex)) { TRACE_ERROR("%s Failed to unlock session lock\n", __func__); } } if (helper_session != CK_INVALID_HANDLE) { rc2 = ep11_close_helper_session(tokdata, &handle, FALSE); if (rc2 != CKR_OK) TRACE_ERROR("%s ep11_close_helper_session failed: 0x%lx\n", __func__, rc2); } return rc; } void ep11_get_pin_blob(STDLL_TokData_t *tokdata, ep11_session_t *ep11_session, CK_BOOL is_session_obj, CK_BOOL is_private_obj, CK_BYTE **pin_blob, CK_ULONG *pin_blob_len) { ep11_private_data_t *ep11_data = tokdata->private_data; if (ep11_data->strict_mode && ep11_session != NULL && ep11_session->pin_blob_valid && is_session_obj && is_private_obj) { *pin_blob = ep11_session->session_pin_blob; *pin_blob_len = sizeof(ep11_session->session_pin_blob); TRACE_DEVEL("%s Strict mode with CKA_TOKEN=FALSE & CKA_PRIVATE=TRUE " "-> pass session pin_blob\n", __func__); } else if (ep11_data->vhsm_mode && ep11_data->vhsm_pin_blob_valid && is_private_obj) { *pin_blob = ep11_data->vhsm_pin_blob; *pin_blob_len = sizeof(ep11_data->vhsm_pin_blob); TRACE_DEVEL("%s VHSM mode with CKA_PRIVATE=TRUE -> pass VHSM pin_blob\n", __func__); } else if (ep11_data->fips_session_mode && ep11_data->fips_pin_blob_valid) { *pin_blob = ep11_data->fips_pin_blob; *pin_blob_len = sizeof(ep11_data->fips_pin_blob); TRACE_DEVEL("%s FIPS session mode -> pass FIPS 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_BBOOL in_fork_initializer) { CK_RV rc; TRACE_INFO("%s\n", __func__); rc = SC_CloseSession(tokdata, sSession, in_fork_initializer); if (rc != CKR_OK) TRACE_ERROR("%s SC_CloseSession failed: 0x%lx\n", __func__, rc); return rc; } 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; CK_SLOT_ID slot; struct timeval timeofday; clock_t clock; pid_t pid; CK_BYTE nonce[32]; } session_id_data; CK_MECHANISM mech; CK_ULONG len; libica_sha_context_t ctx; ep11_target_info_t* target_info; session_id_data.handle = session->handle; session_id_data.slot = session->session_info.slotID; gettimeofday(&session_id_data.timeofday, NULL); session_id_data.clock = clock(); session_id_data.pid = tokdata->real_pid; rc = rng_generate(tokdata, session_id_data.nonce, sizeof(session_id_data.nonce)); if (rc != CKR_OK) { TRACE_ERROR("%s rng_generate failed: 0x%lx\n", __func__, rc); return rc; } target_info = get_target_info(tokdata); if (target_info == NULL) return CKR_FUNCTION_FAILED; mech.mechanism = CKM_SHA256; mech.pParameter = NULL; mech.ulParameterLen = 0; len = sizeof(ep11_session->session_id); if (ep11tok_libica_digest_available(tokdata, ep11_data, mech.mechanism)) { rc = ep11tok_libica_digest(tokdata, ep11_data, mech.mechanism, &ctx, (CK_BYTE_PTR)&session_id_data, sizeof(session_id_data), ep11_session->session_id, &len, SHA_MSG_PART_ONLY); } else { RETRY_SINGLE_APQN_START(tokdata, rc) rc = dll_m_DigestSingle(&mech, (CK_BYTE_PTR)&session_id_data, sizeof(session_id_data), ep11_session->session_id, &len, target_info->target); RETRY_SINGLE_APQN_END(rc, tokdata, target_info) } put_target_info(tokdata, target_info); 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, CK_BYTE *session_id, CK_ULONG session_id_len, CK_BYTE *pin_blob, CK_ULONG pin_blob_len, ep11_serialno_t *serial_numbers, CK_ULONG num_serial_numbers, 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_BYTE *app_data = NULL; CK_ULONG app_data_len; 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, session_id, session_id_len }, { CKA_APPLICATION, NULL, 0 }, // Keep at index 8 { CKA_OWNER, &pid, sizeof(pid) }, { CKA_START_DATE, &date, sizeof(date) } }; app_data_len = sizeof(ep11_target_t) + num_serial_numbers * sizeof(ep11_serialno_t); app_data = malloc(app_data_len); if (app_data == NULL) { TRACE_ERROR("%s Failed to allocate memory\n", __func__); rc = CKR_HOST_MEMORY; goto out; } memcpy(app_data, &ep11_data->target_list, sizeof(ep11_target_t)); if (num_serial_numbers > 0) memcpy(app_data + sizeof(ep11_target_t), serial_numbers, num_serial_numbers * sizeof(ep11_serialno_t)); attrs[8].pValue = app_data; attrs[8].ulValueLen = app_data_len; pid = tokdata->real_pid; time(&t); tm = localtime(&t); sprintf(tmp, "%04d%02d%02d", 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); } out: if (app_data != NULL) free(app_data); return rc; } static CK_RV update_ep11_object(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *handle, CK_OBJECT_HANDLE obj, ep11_serialno_t *serial_numbers, CK_ULONG num_serial_numbers) { ep11_private_data_t *ep11_data = tokdata->private_data; CK_RV rc; CK_BYTE *app_data = NULL; CK_ULONG app_data_len; CK_ATTRIBUTE attr = { CKA_APPLICATION, NULL, 0 }; app_data_len = sizeof(ep11_target_t) + num_serial_numbers * sizeof(ep11_serialno_t); app_data = malloc(app_data_len); if (app_data == NULL) { TRACE_ERROR("%s Failed to allocate memory\n", __func__); rc = CKR_HOST_MEMORY; goto out; } memcpy(app_data, &ep11_data->target_list, sizeof(ep11_target_t)); if (num_serial_numbers > 0) memcpy(app_data + sizeof(ep11_target_t), serial_numbers, num_serial_numbers * sizeof(ep11_serialno_t)); attr.pValue = app_data; attr.ulValueLen = app_data_len; rc = SC_SetAttributeValue(tokdata, handle, obj, &attr, 1); if (rc != CKR_OK) { TRACE_ERROR("%s SC_SetAttributeValue failed: 0x%lx\n", __func__, rc); } out: if (app_data != NULL) free(app_data); return rc; } static CK_RV get_pin(STDLL_TokData_t *tokdata, SESSION *session, CK_HW_FEATURE_TYPE type, CK_BYTE *pin, CK_ULONG pin_len) { 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_BBOOL cktrue = TRUE; CK_ATTRIBUTE pinobj_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, pin, pin_len }, }; rc = SC_FindObjectsInit(tokdata, &handle, pinobj_template, sizeof(pinobj_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; } out: SC_FindObjectsFinal(tokdata, &handle); return rc; } static CK_RV get_serial_number(STDLL_TokData_t *tokdata, target_t target, uint_32 adapter, uint_32 domain, ep11_serialno_t serial_number) { CK_IBM_XCP_INFO xcp_info; CK_ULONG xcp_info_len = sizeof(xcp_info); CK_RV rc; UNUSED(tokdata); 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 */ return rc; } memcpy(serial_number, xcp_info.serialNumber, sizeof(ep11_serialno_t)); TRACE_DEVEL("%s serial number of adapter %02X.%04X: %.16s\n", __func__, adapter, domain, serial_number); return CKR_OK; } static CK_RV add_serial_number(STDLL_TokData_t *tokdata, ep11_session_t *ep11_session, ep11_serialno_t serial_number) { CK_ULONG i; ep11_serialno_t *tmp; UNUSED(tokdata); for (i = 0; i < ep11_session->num_serial_numbers; i++) { if (memcmp(ep11_session->serial_numbers[i], serial_number, 16) == 0) return CKR_OK; } TRACE_DEVEL("%s adding serial number : %.16s\n", __func__, serial_number); tmp = realloc(ep11_session->serial_numbers, sizeof(ep11_serialno_t) * (ep11_session->num_serial_numbers + 1)); if (tmp == NULL) { TRACE_ERROR("%s Failed allocate serial number list\n",__func__); return CKR_HOST_MEMORY; } memcpy(tmp[ep11_session->num_serial_numbers], serial_number, sizeof(ep11_serialno_t)); ep11_session->num_serial_numbers++; ep11_session->serial_numbers = tmp; return CKR_OK; } static void remove_serial_number(STDLL_TokData_t *tokdata, ep11_session_t *ep11_session, ep11_serialno_t serial_number) { CK_ULONG i; CK_BOOL found = FALSE; UNUSED(tokdata); for (i = 0; i < ep11_session->num_serial_numbers; i++) { if (memcmp(ep11_session->serial_numbers[i], serial_number, sizeof(ep11_serialno_t)) == 0) { found = TRUE; break; } } if (!found) return; TRACE_DEVEL("%s removing serial number : %.16s\n", __func__, serial_number); memmove(ep11_session->serial_numbers[i], ep11_session->serial_numbers[i + 1], (ep11_session->num_serial_numbers - i) * sizeof(ep11_serialno_t)); memset(ep11_session->serial_numbers[ep11_session->num_serial_numbers - 1], 0, sizeof(ep11_serialno_t)); /* Don't shrink the area, just leave it allocated as is */ ep11_session->num_serial_numbers--; return; } static void free_ep11_session(ep11_session_t *ep11_session) { memset(ep11_session->session_pin_blob, 0, sizeof(ep11_session->session_pin_blob)); if (ep11_session->serial_numbers != NULL) free(ep11_session->serial_numbers); free(ep11_session); } CK_RV ep11_login_handler(uint_32 adapter, uint_32 domain, void *handler_data) { login_logout_data_t *data = (login_logout_data_t *)handler_data; ep11_private_data_t *ep11_data = data->tokdata->private_data; target_t target; CK_RV rc; CK_BYTE pin_blob[MAX(sizeof(ep11_data->fips_pin_blob), MAX(sizeof(ep11_data->vhsm_pin_blob), sizeof(data->ep11_session->session_pin_blob)))]; CK_ULONG pin_blob_len; 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; session_nonce_t session_nonce; ep11_serialno_t serial_number; TRACE_INFO("Logging in adapter %02X.%04X\n", adapter, domain); rc = get_ep11_target_for_apqn(adapter, domain, &target, 0); if (rc != CKR_OK) return rc; if (ep11_data->fips_session_mode && (ep11_data->session_refcount == 0 || data->relogin)) { session_nonce.slot_id = htobe32(data->tokdata->slot_id); memcpy(session_nonce.purpose, FIPS_NONCE_PURPOSE, 12); nonce = (CK_BYTE *)&session_nonce; nonce_len = sizeof(session_nonce); pin_blob_len = sizeof(ep11_data->fips_pin_blob); rc = do_LoginExtended(XCP_LOGIN_ALG_F2021, XCP_LOGIN_IMPR_EC_P521, ep11_data->fips_pin, sizeof(ep11_data->fips_pin), nonce, nonce_len, pin_blob, &pin_blob_len, NULL, target); if (rc != CKR_OK || pin_blob_len != sizeof(ep11_data->fips_pin_blob)) { rc = ep11_error_to_pkcs11_error(rc, NULL); TRACE_ERROR("%s do_LoginExtended failed: 0x%lx pin_blob_len: %lu\n", __func__, rc, pin_blob_len); /* ignore the error here, the adapter may not be able to perform * m_Login at this moment */ rc = CKR_OK; goto vhsm_mode; } #ifdef DEBUG TRACE_DEBUG("EP11 FIPS Pin blob:\n"); TRACE_DEBUG_DUMP(" ", pin_blob, pin_blob_len); #endif if (ep11_data->fips_pin_blob_valid) { /* First part of pin-blob (keypart and session) must be equal */ if (memcmp(ep11_data->fips_pin_blob, pin_blob, XCP_WK_BYTES) != 0) { TRACE_ERROR("%s FIPS-Pin blob not equal to previous one\n", __func__); OCK_SYSLOG(LOG_ERR, "%s: Error: FIPS-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_data->fips_pin_blob, pin_blob, pin_blob_len); ep11_data->fips_pin_blob_valid = TRUE; } } vhsm_mode: if (ep11_data->vhsm_mode) { pin = ep11_data->vhsm_pin; pin_len = sizeof(ep11_data->vhsm_pin); } if (ep11_data->vhsm_mode && (ep11_data->session_refcount == 0 || data->relogin)) { session_nonce.slot_id = htobe32(data->tokdata->slot_id); memcpy(session_nonce.purpose, VHSM_NONCE_PURPOSE, 12); nonce = (CK_BYTE *)&session_nonce; nonce_len = sizeof(session_nonce); pin_blob_len = sizeof(ep11_data->vhsm_pin_blob); rc = dll_m_Login(pin, pin_len, nonce, nonce_len, pin_blob, &pin_blob_len, target); if (rc != CKR_OK || pin_blob_len != sizeof(ep11_data->vhsm_pin_blob)) { rc = ep11_error_to_pkcs11_error(rc, NULL); TRACE_ERROR("%s dll_m_Login failed: 0x%lx pin_blob_len: %lu\n", __func__, rc, pin_blob_len); /* ignore the error here, the adapter may not be able to perform * m_Login at this moment */ rc = CKR_OK; goto strict_mode; } #ifdef DEBUG TRACE_DEBUG("EP11 VHSM Pin blob:\n"); TRACE_DEBUG_DUMP(" ", pin_blob, pin_blob_len); #endif if (ep11_data->vhsm_pin_blob_valid) { /* First part of pin-blob (keypart and session) must be equal */ if (memcmp(ep11_data->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_data->vhsm_pin_blob, pin_blob, sizeof(ep11_data->vhsm_pin_blob)); ep11_data->vhsm_pin_blob_valid = TRUE; } } strict_mode: if (ep11_data->strict_mode && data->ep11_session != NULL) { rc = get_serial_number(data->tokdata, target, adapter, domain, serial_number); if (rc != CKR_OK) { /* ignore the error here, the adapter may not be able to perform * the query at this moment */ rc = CKR_OK; goto out; } nonce = data->ep11_session->session_id; nonce_len = sizeof(data->ep11_session->session_id); /* pin is already set to default pin or vhsm pin (if VHSM mode) */ pin_blob_len = sizeof(data->ep11_session->session_pin_blob); rc = dll_m_Login(pin, pin_len, nonce, nonce_len, pin_blob, &pin_blob_len, target); if (rc != CKR_OK || pin_blob_len != sizeof(data->ep11_session->session_pin_blob)) { rc = ep11_error_to_pkcs11_error(rc, NULL); TRACE_ERROR("%s dll_m_Login failed: 0x%lx pin_blob_len: %lu\n", __func__, rc, pin_blob_len); /* 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:\n"); TRACE_DEBUG_DUMP(" ", pin_blob, pin_blob_len); #endif if (data->ep11_session->pin_blob_valid) { /* First part of pin-blob (keypart and session) must be equal */ if (memcmp(data->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(data->ep11_session->session_pin_blob, pin_blob, sizeof(data->ep11_session->session_pin_blob)); data->ep11_session->pin_blob_valid = TRUE; } rc = add_serial_number(data->tokdata, data->ep11_session, serial_number); } out: free_ep11_target_for_apqn(target); return rc; } static CK_RV ep11_logout_handler(uint_32 adapter, uint_32 domain, void *handler_data) { login_logout_data_t *data = (login_logout_data_t *)handler_data; ep11_private_data_t *ep11_data = data->tokdata->private_data; target_t target; session_nonce_t session_nonce; ep11_serialno_t serial_number; CK_RV rc; TRACE_INFO("Logging out adapter %02X.%04X\n", adapter, domain); rc = get_ep11_target_for_apqn(adapter, domain, &target, 0); if (rc != CKR_OK) return rc; if (ep11_data->strict_mode && data->ep11_session != NULL && data->ep11_session->pin_blob_valid) { rc = get_serial_number(data->tokdata, target, adapter, domain, serial_number); if (rc != CKR_OK) { /* ignore the error here, the adapter may not be able to perform * the query at this moment */ rc = CKR_OK; goto vhsm_mode; } #ifdef DEBUG TRACE_DEBUG("EP11 Session Pin blob\n"); TRACE_DEBUG_DUMP(" ", data->ep11_session->session_pin_blob, sizeof(data->ep11_session->session_pin_blob)); #endif rc = dll_m_Logout(data->ep11_session->session_pin_blob, sizeof(data->ep11_session->session_pin_blob), 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 */ } else { remove_serial_number(data->tokdata, data->ep11_session, serial_number); } } vhsm_mode: if (ep11_data->vhsm_mode && ep11_data->get_session_refcount(data->tokdata) == 0 && ep11_data->vhsm_pin_blob_valid) { #ifdef DEBUG TRACE_DEBUG("EP11 VHSM Pin blob:\n"); TRACE_DEBUG_DUMP(" ", ep11_data->vhsm_pin_blob, sizeof(ep11_data->vhsm_pin_blob)); #endif rc = dll_m_Logout(ep11_data->vhsm_pin_blob, sizeof(ep11_data->vhsm_pin_blob), 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_data->fips_session_mode && ep11_data->get_session_refcount(data->tokdata) == 0 && ep11_data->fips_pin_blob_valid) { #ifdef DEBUG TRACE_DEBUG("EP11 FIPS Pin blob:\n"); TRACE_DEBUG_DUMP(" ", ep11_data->fips_pin_blob, sizeof(ep11_data->fips_pin_blob)); #endif session_nonce.slot_id = htobe32(data->tokdata->slot_id); memcpy(session_nonce.purpose, FIPS_NONCE_PURPOSE, 12); rc = do_LogoutExtended(XCP_LOGIN_ALG_F2021, XCP_LOGIN_IMPR_EC_P521, ep11_data->fips_pin, sizeof(ep11_data->fips_pin), (CK_BYTE *)&session_nonce, sizeof(session_nonce), target); if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, NULL); TRACE_ERROR("%s do_LogoutExtended 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 = NULL; 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; login_logout_data_t data = { 0 }; CK_BBOOL cnt_incr = FALSE; TRACE_INFO("%s session=%lu\n", __func__, session->handle); if (!ep11_data->strict_mode && !ep11_data->vhsm_mode && !ep11_data->fips_session_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__); rc = CKR_USER_ALREADY_LOGGED_IN; goto done_no_lock; } if (ep11_data->vhsm_mode || ep11_data->fips_session_mode) { if (pthread_mutex_lock(&ep11_data->session_mutex)) { TRACE_ERROR("%s Failed to lock session lock\n", __func__); rc = CKR_CANT_LOCK; goto done_no_lock; } TRACE_DEVEL("%s global session refcount: %u\n", __func__, ep11_data->get_session_refcount(tokdata)); TRACE_DEVEL("%s session refcount: %u\n", __func__, ep11_data->session_refcount); } if (ep11_data->strict_mode) { ep11_session = calloc(1, sizeof(ep11_session_t)); if (ep11_session == NULL) { TRACE_ERROR("%s Memory allocation failed\n", __func__); rc = CKR_HOST_MEMORY; goto done; } ep11_session->session = session; ep11_session->session_object = CK_INVALID_HANDLE; 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->fips_session_mode && !ep11_data->fips_pin_valid) { rc = get_pin(tokdata, session, CKH_IBM_EP11_FIPSPIN, ep11_data->fips_pin, sizeof(ep11_data->fips_pin)); if (rc != CKR_OK) { TRACE_ERROR("%s get_pin(FIPS) failed: 0x%lx\n", __func__, rc); OCK_SYSLOG(LOG_ERR, "%s: Error: A FIPS-PIN is required for FIPS_SESSION_MODE.\n", __func__); goto done; } ep11_data->fips_pin_valid = TRUE; } if (ep11_data->vhsm_mode && !ep11_data->vhsm_pin_valid) { rc = get_pin(tokdata, session, CKH_IBM_EP11_VHSMPIN, ep11_data->vhsm_pin, sizeof(ep11_data->vhsm_pin)); if (rc != CKR_OK) { TRACE_ERROR("%s get_pin(VHSM) failed: 0x%lx\n", __func__, rc); OCK_SYSLOG(LOG_ERR, "%s: Error: A VHSM-PIN is required for VHSM_MODE.\n", __func__); goto done; } ep11_data->vhsm_pin_valid = TRUE; } data.tokdata = tokdata; data.ep11_session = ep11_session; rc = handle_all_ep11_cards(&ep11_data->target_list, ep11_login_handler, &data); if (rc != CKR_OK) { TRACE_ERROR("%s handle_all_ep11_cards failed: 0x%lx\n", __func__, rc); goto done; } if (ep11_data->vhsm_mode || ep11_data->fips_session_mode) { ep11_data->session_refcount++; ep11_data->incr_session_refcount(tokdata); TRACE_DEVEL("%s global session refcount: %u\n", __func__, ep11_data->get_session_refcount(tokdata)); TRACE_DEVEL("%s session refcount: %u\n", __func__, ep11_data->session_refcount); cnt_incr = TRUE; } if (ep11_data->strict_mode) { if (ep11_session == NULL || !ep11_session->pin_blob_valid) { rc = CKR_DEVICE_ERROR; TRACE_ERROR("%s no pinblob available\n", __func__); goto done; } rc = create_ep11_object(tokdata, &handle, ep11_session->session_id, PUBLIC_SESSION_ID_LENGTH, ep11_session->session_pin_blob, sizeof(ep11_session->session_pin_blob), ep11_session->serial_numbers, ep11_session->num_serial_numbers, &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_data->vhsm_pin_blob_valid) { rc = CKR_DEVICE_ERROR; TRACE_ERROR("%s no VHSM pinblob available\n", __func__); goto done; } } if (ep11_data->fips_session_mode) { if (!ep11_data->fips_pin_blob_valid) { rc = CKR_DEVICE_ERROR; TRACE_ERROR("%s no FIPS pinblob available\n", __func__); goto done; } } done: if (rc != CKR_OK) { if ((ep11_session != NULL && ep11_session->pin_blob_valid) || ep11_data->vhsm_pin_blob_valid || ep11_data->fips_pin_blob_valid) { if (cnt_incr) { if (ep11_data->session_refcount > 0) ep11_data->session_refcount--; ep11_data->decr_session_refcount(tokdata); } data.tokdata = tokdata; data.ep11_session = ep11_session; rc2 = handle_all_ep11_cards(&ep11_data->target_list, ep11_logout_handler, &data); if (rc2 != CKR_OK) TRACE_ERROR("%s handle_all_ep11_cards failed: 0x%lx\n", __func__, rc2); } if (ep11_data->strict_mode && ep11_session != NULL && ep11_session->session_object != CK_INVALID_HANDLE && ep11_session->num_serial_numbers == 0) { 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 != NULL) { free_ep11_session(ep11_session); session->private_data = NULL; } TRACE_ERROR("%s: failed: 0x%lx\n", __func__, rc); } if (ep11_data->vhsm_mode || ep11_data->fips_session_mode) { if (pthread_mutex_unlock(&ep11_data->session_mutex)) { TRACE_ERROR("%s Failed to unlock session lock\n", __func__); } } done_no_lock: if (helper_session != CK_INVALID_HANDLE) { rc2 = ep11_close_helper_session(tokdata, &handle, FALSE); if (rc2 != CKR_OK) TRACE_ERROR("%s ep11_close_helper_session failed: 0x%lx\n", __func__, rc2); } return rc; } CK_RV ep11tok_logout_session(STDLL_TokData_t *tokdata, SESSION *session, CK_BBOOL in_fork_initializer) { ep11_private_data_t *ep11_data = tokdata->private_data; ep11_session_t *ep11_session = (ep11_session_t *)session->private_data; CK_RV rc = CKR_OK, rc2; ST_SESSION_HANDLE handle = { .slotID = session->session_info.slotID, .sessionh = session->handle }; CK_SESSION_HANDLE helper_session = CK_INVALID_HANDLE; login_logout_data_t data = { 0 }; TRACE_INFO("%s session=%lu\n", __func__, session->handle); if (!ep11_data->strict_mode && !ep11_data->vhsm_mode && !ep11_data->fips_session_mode) return CKR_OK; if (session->session_info.flags & CKF_EP11_HELPER_SESSION) return CKR_OK; if (in_fork_initializer) goto free_session; 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_data->strict_mode && ep11_session == NULL) { TRACE_INFO("%s CKR_USER_NOT_LOGGED_IN\n", __func__); rc = CKR_USER_NOT_LOGGED_IN; goto done_no_lock; } if (ep11_data->vhsm_mode || ep11_data->fips_session_mode) { if (pthread_mutex_lock(&ep11_data->session_mutex)) { TRACE_ERROR("%s Failed to lock session lock\n", __func__); rc = CKR_CANT_LOCK; goto done_no_lock; } if (ep11_data->session_refcount > 0) ep11_data->session_refcount--; ep11_data->decr_session_refcount(tokdata); TRACE_DEVEL("%s global session refcount: %u\n", __func__, ep11_data->get_session_refcount(tokdata)); TRACE_DEVEL("%s session refcount: %u\n", __func__, ep11_data->session_refcount); } data.tokdata = tokdata; data.ep11_session = ep11_session; rc = handle_all_ep11_cards(&ep11_data->target_list, ep11_logout_handler, &data); if (rc != CKR_OK) TRACE_ERROR("%s handle_all_ep11_cards failed: 0x%lx\n", __func__, rc); if (ep11_data->strict_mode && ep11_session != NULL && ep11_session->session_object != CK_INVALID_HANDLE) { if (ep11_session->num_serial_numbers == 0) { rc = SC_DestroyObject(tokdata, &handle, ep11_session->session_object); if (rc != CKR_OK) TRACE_ERROR("%s SC_DestroyObject failed: 0x%lx\n", __func__, rc); } else { rc = update_ep11_object(tokdata, &handle, ep11_session->session_object, ep11_session->serial_numbers, ep11_session->num_serial_numbers); if (rc != CKR_OK) TRACE_ERROR("%s update_ep11_object failed: 0x%lx\n", __func__, rc); } } free_session: if (ep11_session != NULL) { free_ep11_session(ep11_session); session->private_data = NULL; } if (ep11_data->vhsm_mode || ep11_data->fips_session_mode) { if (ep11_data->session_refcount == 0) { ep11_data->vhsm_pin_blob_valid = FALSE; memset(ep11_data->vhsm_pin_blob, 0, sizeof(ep11_data->vhsm_pin_blob)); ep11_data->fips_pin_blob_valid = FALSE; memset(ep11_data->fips_pin_blob, 0, sizeof(ep11_data->fips_pin_blob)); } if (pthread_mutex_unlock(&ep11_data->session_mutex)) { TRACE_ERROR("%s Failed to unlock session lock\n", __func__); } } done_no_lock: if (helper_session != CK_INVALID_HANDLE) { rc2 = ep11_close_helper_session(tokdata, &handle, in_fork_initializer); if (rc2 != CKR_OK) TRACE_ERROR("%s ep11_close_helper_session failed: 0x%lx\n", __func__, rc2); } return rc; } opencryptoki-opencryptoki-451d99c/usr/lib/ep11_stdll/ep11_specific.c000066400000000000000000026441171520105705100254510ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2001-2023 * * 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 #define OCK_NO_EP11_DEFINES #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 "pqc_defs.h" #include "p11util.h" #include "events.h" #include "cfgparser.h" #include "configuration.h" #include "hsm_mk_change.h" #include "constant_time.h" #include #include #include #include #include #include #include #include #include #include #ifdef DEBUG #include #endif #include #include #include "ep11_specific.h" #ifndef NO_PKEY #include "pkey_utils.h" #endif 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 CK_RV ep11tok_pkcs11_mech_translate(STDLL_TokData_t *tokdata, CK_MECHANISM_TYPE type, CK_MECHANISM_TYPE* ep11_type); static CK_RV ep11tok_pkcs11_mgf_translate(STDLL_TokData_t *tokdata, CK_RSA_PKCS_MGF_TYPE mgf, CK_RSA_PKCS_MGF_TYPE* ep11_mgf); static CK_RV ep11tok_pkcs11_keytype_translate(STDLL_TokData_t *tokdata, CK_KEY_TYPE keytype, CK_KEY_TYPE* ep11_keytype); 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; 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; m_Login_t dll_m_Login; m_Logout_t dll_m_Logout; m_LoginExtended_t dll_m_LoginExtended; m_LogoutExtended_t dll_m_LogoutExtended; 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; xcpa_cmdblock_t dll_xcpa_cmdblock; static xcpa_queryblock_t dll_xcpa_queryblock; xcpa_internal_rv_t dll_xcpa_internal_rv; m_get_xcp_info_t dll_m_get_xcp_info; const char manuf[] = "IBM"; const char model[] = "EP11"; const char descr[] = "IBM EP11 token"; const char label[] = "ep11tok"; static CK_BBOOL ep11tok_ec_curve_supported2(STDLL_TokData_t *tokdata, TEMPLATE *template, const struct _ec **curve); 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(STDLL_TokData_t *tokdata, 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); static CK_RV ep11tok_get_ep11_library_version(CK_VERSION *lib_version); static void free_card_versions(ep11_card_version_t *card_version); static int check_card_version(STDLL_TokData_t *tokdata, CK_ULONG card_type, CK_ULONG apply_to_firmware_version_only, 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); static int check_required_versions(STDLL_TokData_t *tokdata, const version_req_t req[], CK_ULONG num_req); 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); static CK_RV obj_opaque_2_reenc_blob(STDLL_TokData_t *tokdata, OBJECT *key_obj, CK_BYTE **blob, size_t *blobsize); static CK_RV file_fgets(const char *fname, char *buf, size_t buflen); /* 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 cex6p_oaep_support = { .major = 6, .minor = 7 }; static const version_req_t oaep_req_versions[] = { { .card_type = 6, .min_firmware_version = &cex6p_oaep_support } }; #define NUM_OAEP_REQ (sizeof(oaep_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)) static const CK_VERSION ibm_cex8p_kyber_support = { .major = 8, .minor = 9 }; static const version_req_t ibm_kyber_req_versions[] = { { .card_type = 8, .min_firmware_version = &ibm_cex8p_kyber_support } }; #define NUM_KYBER_REQ (sizeof(ibm_kyber_req_versions) / sizeof(version_req_t)) static const CK_VERSION ibm_cex8p_ml_dsa_kem_support_v9 = { .major = 9, .minor = 6 }; static const CK_VERSION ibm_cex8p_ml_dsa_kem_support_v8 = { .major = 8, .minor = 39 }; static const version_req_t ibm_mldsa_kem_req_versions[] = { { .card_type = 8, .apply_to_firmware_version_only = 8, .min_firmware_version = &ibm_cex8p_ml_dsa_kem_support_v8 }, { .card_type = 8, .apply_to_firmware_version_only = 9, .min_firmware_version = &ibm_cex8p_ml_dsa_kem_support_v9 } }; #define NUM_ML_DSA_KEM_REQ (sizeof(ibm_mldsa_kem_req_versions) / sizeof(version_req_t)) static const CK_VERSION ibm_cex6p_reencrypt_single_support = { .major = 6, .minor = 15 }; static const CK_VERSION ibm_cex7p_reencrypt_single_support = { .major = 7, .minor = 21 }; static const version_req_t reencrypt_single_req_versions[] = { { .card_type = 6, .min_firmware_version = &ibm_cex6p_reencrypt_single_support }, { .card_type = 7, .min_firmware_version = &ibm_cex7p_reencrypt_single_support } }; #define NUM_REENCRYPT_SINGLE_REQ (sizeof(reencrypt_single_req_versions) / \ sizeof(version_req_t)) #ifndef NO_PKEY static const CK_VERSION ibm_cex7p_cpacf_wrap_support = { .major = 7, .minor = 15 }; static const version_req_t ibm_cpacf_wrap_req_versions[] = { { .card_type = 7, .min_firmware_version = &ibm_cex7p_cpacf_wrap_support } }; #define NUM_CPACF_WRAP_REQ (sizeof(ibm_cpacf_wrap_req_versions) / sizeof(version_req_t)) #endif /* NO_PKEY */ static const CK_ULONG ibm_cex_ab_ecdh_api_version = 3; static const version_req_t ibm_ab_ecdh_req_versions[] = { { .card_type = 7, .min_firmware_API_version = &ibm_cex_ab_ecdh_api_version} }; #define NUM_AB_ECDH_REQ (sizeof(ibm_ab_ecdh_req_versions) / sizeof(version_req_t)) static const CK_VERSION ibm_cex6p_btc_support = { .major = 6, .minor = 15 }; static const CK_VERSION ibm_cex7p_btc_support = { .major = 7, .minor = 21 }; static const version_req_t ibm_btc_req_versions[] = { { .card_type = 6, .min_firmware_version = &ibm_cex6p_btc_support }, { .card_type = 7, .min_firmware_version = &ibm_cex7p_btc_support } }; #define NUM_BTC_REQ (sizeof(ibm_btc_req_versions) / sizeof(version_req_t)) static const CK_VERSION ibm_cex6p_ecdsa_other_support = { .major = 6, .minor = 15 }; static const CK_VERSION ibm_cex7p_ecdsa_other_support = { .major = 7, .minor = 21 }; static const version_req_t ibm_ecdsa_other_req_versions[] = { { .card_type = 6, .min_firmware_version = &ibm_cex6p_ecdsa_other_support }, { .card_type = 7, .min_firmware_version = &ibm_cex7p_ecdsa_other_support } }; #define NUM_ECDSA_OTHER_REQ (sizeof(ibm_ecdsa_other_req_versions) / \ sizeof(version_req_t)) static const CK_VERSION ibm_cex7p_bls_support = { .major = 7, .minor = 39 }; static const CK_VERSION ibm_cex8p_bls_support = { .major = 8, .minor = 31 }; static const version_req_t ibm_bls_req_versions[] = { { .card_type = 7, .min_firmware_version = &ibm_cex7p_bls_support }, { .card_type = 8, .min_firmware_version = &ibm_cex8p_bls_support } }; #define NUM_BLS_REQ (sizeof(ibm_bls_req_versions) / \ sizeof(version_req_t)) static CK_RV update_ep11_attrs_from_blob(STDLL_TokData_t *tokdata, SESSION *session, OBJECT *key_obj, CK_BBOOL aes_xts); /* 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) } static void trace_attributes(const char *func, const char *heading, CK_ATTRIBUTE_PTR attrs, CK_ULONG num_attrs) { CK_ULONG i; #ifndef DEBUG UNUSED(func); UNUSED(heading); UNUSED(attrs); UNUSED(num_attrs); #endif if (trace.level < TRACE_LEVEL_DEBUG) return; TRACE_DEBUG("%s: %s\n", func, heading); for (i = 0; i < num_attrs; i++) { TRACE_DEBUG_DUMPATTR(&attrs[i]); } } static CK_RV cleanse_attribute(TEMPLATE *template, CK_ATTRIBUTE_TYPE attr_type) { CK_ATTRIBUTE *attr; if (template_attribute_get_non_empty(template, attr_type, &attr) != CKR_OK) return CKR_FUNCTION_FAILED; OPENSSL_cleanse(attr->pValue, attr->ulValueLen); return CKR_OK; } static CK_RV check_expected_mkvp(STDLL_TokData_t *tokdata, CK_BYTE *blob, size_t blobsize, CK_BBOOL *new_wk) { ep11_private_data_t *ep11_data = tokdata->private_data; CK_BYTE *wkid; CK_RV rc; if (new_wk != NULL) *new_wk = FALSE; rc = ep11tok_extract_blob_info(blob, blobsize, NULL, &wkid, NULL, NULL); if (rc != CKR_OK || wkid == NULL) { TRACE_ERROR("ep11tok_extract_blob_info failed\n"); return CKR_FUNCTION_FAILED; } if (memcmp(wkid, ep11_data->expected_wkvp, XCP_WKID_BYTES) != 0) { /* If an MK change operation is active, also allow the new WK */ if (ep11_data->mk_change_active && memcmp(wkid, ep11_data->new_wkvp, XCP_WKID_BYTES) == 0) { TRACE_DEBUG("The key is wrapped by the new WK\n"); if (new_wk != NULL) *new_wk = TRUE; return CKR_OK; } TRACE_ERROR("The key's wrapping key verification pattern does not " "match the expected EP11 wrapping key\n"); TRACE_DEBUG_DUMP("WKVP of key: ", wkid, XCP_WKID_BYTES); TRACE_DEBUG_DUMP("Expected WKVP: ", (CK_BYTE *)ep11_data->expected_wkvp, XCP_WKID_BYTES); OCK_SYSLOG(LOG_ERR, "The key's wrapping key verification pattern does " "not match the expected EP11 wrapping key\n"); return CKR_DEVICE_ERROR; } return CKR_OK; } static CK_BBOOL ep11_pqc_strength_supported(ep11_target_info_t *target_info, CK_MECHANISM_TYPE mech, const struct pqc_oid *oid) { CK_ULONG strength; switch (mech) { case CKM_IBM_DILITHIUM: switch (oid->keyform) { case CK_IBM_DILITHIUM_KEYFORM_ROUND2_65: strength = XCP_PQC_S_DILITHIUM_R2_65; break; case CK_IBM_DILITHIUM_KEYFORM_ROUND2_87: strength = XCP_PQC_S_DILITHIUM_R2_87; break; case CK_IBM_DILITHIUM_KEYFORM_ROUND3_44: strength = XCP_PQC_S_DILITHIUM_R3_44; break; case CK_IBM_DILITHIUM_KEYFORM_ROUND3_65: strength = XCP_PQC_S_DILITHIUM_R3_65; break; case CK_IBM_DILITHIUM_KEYFORM_ROUND3_87: strength = XCP_PQC_S_DILITHIUM_R3_87; break; default: TRACE_DEVEL("Dilithium keyform %lu not supported by EP11\n", oid->keyform); return FALSE; } break; case CKM_IBM_KYBER: switch (oid->keyform) { case CK_IBM_KYBER_KEYFORM_ROUND2_768: strength = XCP_PQC_S_KYBER_R2_768; break; case CK_IBM_KYBER_KEYFORM_ROUND2_1024: strength = XCP_PQC_S_KYBER_R2_1024; break; default: TRACE_DEVEL("Kyber keyform %lu not supported by EP11\n", oid->keyform); return FALSE; } break; case CKM_IBM_ML_DSA: case CKM_IBM_ML_DSA_KEY_PAIR_GEN: case CKM_ML_DSA: case CKM_ML_DSA_KEY_PAIR_GEN: switch (oid->keyform) { case CKP_ML_DSA_44: strength = XCP_PQC_S_ML_DSA_44; break; case CKP_ML_DSA_65: strength = XCP_PQC_S_ML_DSA_65; break; case CKP_ML_DSA_87: strength = XCP_PQC_S_ML_DSA_87; break; default: TRACE_DEVEL("ML-DSA keyform %lu not supported by EP11\n", oid->keyform); return FALSE; } break; case CKM_IBM_ML_KEM: case CKM_IBM_ML_KEM_KEY_PAIR_GEN: case CKM_ML_KEM: case CKM_ML_KEM_KEY_PAIR_GEN: switch (oid->keyform) { case CKP_ML_KEM_512: strength = XCP_PQC_S_ML_KEM_512; break; case CKP_ML_KEM_768: strength = XCP_PQC_S_ML_KEM_768; break; case CKP_ML_KEM_1024: strength = XCP_PQC_S_ML_KEM_1024; break; default: TRACE_DEVEL("ML-KEM keyform %lu not supported by EP11\n", oid->keyform); return FALSE; } break; default: return FALSE; } if ((target_info->pqc_strength[PQC_BYTE_NO(strength)] & PQC_BIT_MASK(strength)) == 0) { TRACE_DEVEL("Keyform %lu not supported by configured APQNs\n", oid->keyform); return FALSE; } return TRUE; } static CK_BBOOL ep11_pqc_obj_strength_supported(ep11_target_info_t *target_info, CK_MECHANISM_TYPE mech, OBJECT *key_obj) { const struct pqc_oid *oid; switch (mech) { case CKM_IBM_DILITHIUM: case CKM_IBM_KYBER: case CKM_IBM_ML_DSA: case CKM_IBM_ML_DSA_KEY_PAIR_GEN: case CKM_IBM_ML_KEM: case CKM_IBM_ML_KEM_KEY_PAIR_GEN: case CKM_ML_DSA_KEY_PAIR_GEN: case CKM_ML_DSA: case CKM_ML_KEM_KEY_PAIR_GEN: case CKM_ML_KEM: break; default: return TRUE; } if (key_obj == NULL) return FALSE; oid = pqc_get_keyform_mode(key_obj->template, mech); if (oid == NULL) { TRACE_DEVEL("No keyform/mode found in key object\n"); return FALSE; } return ep11_pqc_strength_supported(target_info, mech, oid); } /** * Return true if PKEY_MODE DISABLED is set in the token specific * config file, false otherwise. */ static CK_BBOOL ep11tok_pkey_option_disabled(STDLL_TokData_t *tokdata) { ep11_private_data_t *ep11_data = tokdata->private_data; if (ep11_data->pkey_mode == PKEY_MODE_DISABLED) return CK_TRUE; return CK_FALSE; } #ifndef NO_PKEY /** * Callback function used by handle_all_ep11_cards() for creating a protected * key via the given APQN (adaper,domain). * Note that this function only works with an ep11 host lib v3 or later, * because since v3 the target is a numeric value and we can OR the * XCP_TGTFL_SET_SCMD flag with it. Before calling this function, it has been * checked if running with v3 or later and the CPACF_WRAP mechanism is * supported by the hw. */ static CK_RV ep11tok_pkey_wrap_handler(uint_32 adapter, uint_32 domain, void *handler_data) { CK_BYTE iv[16] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 }; CK_MECHANISM mech = { CKM_IBM_CPACF_WRAP, &iv, sizeof(iv) }; pkey_wrap_handler_data_t *data = (pkey_wrap_handler_data_t *) handler_data; ep11_private_data_t *ep11_data; target_t target = 0; CK_RV ret = CKR_OK; CK_BBOOL retry = FALSE; CK_BYTE *blob; CK_ULONG bloblen; CK_BBOOL blobretry = FALSE; login_logout_data_t lldata; const CK_VERSION ver40 = { .major = 4, .minor = 0 }; uint64_t flags = 0; if (data->wrap_was_successful) goto done; ep11_data = data->tokdata->private_data; if (compare_ck_version(&ep11_data->ep11_lib_version, &ver40) <= 0) flags |= XCP_MFL_PROBE; ret = get_ep11_target_for_apqn(adapter, domain, &target, flags); if (ret != CKR_OK) goto done; /* Create the protected key via CKM_IBM_CPACF_WRAP */ blob = data->secure_key; bloblen = data->secure_key_len; repeat: ret = dll_m_WrapKey(blob, bloblen, NULL, 0, NULL, 0, &mech, data->pkey_buf, data->pkey_buflen_p, target | XCP_TGTFL_SET_SCMD); if ((ret == CKR_SESSION_CLOSED || ret == CKR_PIN_INCORRECT) && retry == FALSE && data->ep11_session != NULL) { /* Re-login the EP11 session and retry once */ lldata.tokdata = data->tokdata; lldata.ep11_session = data->ep11_session; ret = ep11_login_handler(adapter, domain, &lldata); if (ret == CKR_OK) { retry = TRUE; goto repeat; } } if (ep11_data->mk_change_active && blobretry == FALSE && ret == CKR_IBM_WKID_MISMATCH && data->secure_key_reenc != NULL) { blob = data->secure_key_reenc; bloblen = data->secure_key_reenc_len; blobretry = TRUE; goto repeat; } if (data->aes_xts && ret == CKR_OK) { /* Create the protected key via CKM_IBM_CPACF_WRAP */ retry = FALSE; blobretry = FALSE; blob = data->secure_key2; bloblen = data->secure_key_len2; repeat2: ret = dll_m_WrapKey(blob, bloblen, NULL, 0, NULL, 0, &mech, data->pkey_buf2, data->pkey_buflen_p2, target | XCP_TGTFL_SET_SCMD); if ((ret == CKR_SESSION_CLOSED || ret == CKR_PIN_INCORRECT) && retry == FALSE && data->ep11_session != NULL) { /* Re-login the EP11 session and retry once */ lldata.tokdata = data->tokdata; lldata.ep11_session = data->ep11_session; ret = ep11_login_handler(adapter, domain, &lldata); if (ret == CKR_OK) { retry = TRUE; goto repeat2; } } if (ep11_data->mk_change_active && blobretry == FALSE && ret == CKR_IBM_WKID_MISMATCH && data->secure_key_reenc2 != NULL) { blob = data->secure_key_reenc2; bloblen = data->secure_key_reenc_len2; blobretry = TRUE; goto repeat2; } } if (ret == CKR_OK) data->wrap_was_successful = CK_TRUE; free_ep11_target_for_apqn(target); done: /* Always return ok, calling function loops over this handler until * data->wrap_was_successful = true, or no more APQN left. * Pass back error in handler data anyway. */ data->wrap_error = ret; return CKR_OK; } /** * Creates a protected key from the given secure key object via the ep11 lib * CKM_IBM_CPACF_WRAP mechanism. */ static CK_RV ep11tok_pkey_skey2pkey(STDLL_TokData_t *tokdata, SESSION *session, CK_ATTRIBUTE *skey_attr, CK_ATTRIBUTE *skey_reenc_attr, CK_ATTRIBUTE **pkey_attr, CK_BBOOL aes_xts) { ep11_private_data_t *ep11_data = tokdata->private_data; CK_ATTRIBUTE *tmp_attr = NULL; CK_BYTE ep11_buf[sizeof(wrapped_key_t)]; size_t ep11_buflen = sizeof(ep11_buf); CK_BYTE ep11_buf2[sizeof(wrapped_key_t)]; size_t ep11_buflen2 = sizeof(ep11_buf2); pkey_wrap_handler_data_t pkey_wrap_handler_data; wrapped_key_t *wk, *wk2; uint64_t token_size = 0; uint8_t wrapped_key[EP11_MAX_WRAPPED_KEY_SIZE * 2]; ep11_target_info_t *target_info = NULL; CK_ULONG retry_count = 0; CK_RV ret; target_info = get_target_info(tokdata); if (target_info == NULL) return CKR_FUNCTION_FAILED; /* Create the protected key via CKM_IBM_CPACF_WRAP */ memset(&pkey_wrap_handler_data, 0, sizeof(pkey_wrap_handler_data_t)); pkey_wrap_handler_data.tokdata = tokdata; if (session != NULL) pkey_wrap_handler_data.ep11_session = (ep11_session_t *)session->private_data; pkey_wrap_handler_data.secure_key = skey_attr->pValue; pkey_wrap_handler_data.secure_key_len = skey_attr->ulValueLen; if (skey_reenc_attr != NULL) { pkey_wrap_handler_data.secure_key_reenc = skey_reenc_attr->pValue; pkey_wrap_handler_data.secure_key_reenc_len = skey_reenc_attr->ulValueLen; } pkey_wrap_handler_data.pkey_buf = (CK_BYTE *)&ep11_buf; pkey_wrap_handler_data.pkey_buflen_p = &ep11_buflen; pkey_wrap_handler_data.aes_xts = FALSE; if (aes_xts) { pkey_wrap_handler_data.secure_key_len = skey_attr->ulValueLen / 2; pkey_wrap_handler_data.secure_key2 = (CK_BYTE *)skey_attr->pValue + skey_attr->ulValueLen / 2; pkey_wrap_handler_data.secure_key_len2 = skey_attr->ulValueLen / 2; if (skey_reenc_attr != NULL) { pkey_wrap_handler_data.secure_key_reenc_len = skey_reenc_attr->ulValueLen / 2; pkey_wrap_handler_data.secure_key_reenc2 = (CK_BYTE *)skey_reenc_attr->pValue + skey_reenc_attr->ulValueLen / 2; pkey_wrap_handler_data.secure_key_reenc_len2 = skey_reenc_attr->ulValueLen / 2; } pkey_wrap_handler_data.pkey_buf2 = (CK_BYTE *)&ep11_buf2; pkey_wrap_handler_data.pkey_buflen_p2 = &ep11_buflen2; pkey_wrap_handler_data.aes_xts = TRUE; } retry: if (target_info->single_apqn) { /* If in single APQN mode, call handler for that single APQN only */ RETRY_SINGLE_APQN_START(tokdata, ret) pkey_wrap_handler_data.wrap_error = CKR_OK; ep11tok_pkey_wrap_handler(target_info->adapter, target_info->domain, &pkey_wrap_handler_data); ret = pkey_wrap_handler_data.wrap_error; RETRY_SINGLE_APQN_END(ret, tokdata, target_info) } else { ret = handle_all_ep11_cards(&ep11_data->target_list, ep11tok_pkey_wrap_handler, &pkey_wrap_handler_data); } if (ret != CKR_OK || !pkey_wrap_handler_data.wrap_was_successful) { if (pkey_wrap_handler_data.wrap_error == CKR_KEY_NEEDED && retry_count < 10) { /* * The EP11 host library v4.2 or later may return CKR_KEY_NEEDED * at m_WrapKey() with mechanism CKM_IBM_CPACF_WRAP to indicate * that the firmware is not yet ready to derive a protected key. * Sleep 500 msec and retry up to 10 times. */ TRACE_DEVEL("CKM_IBM_CPACF_WRAP failed with CKR_KEY_NEEDED, retry\n"); usleep(500000); retry_count++; goto retry; } TRACE_ERROR("handle_all_ep11_cards failed or no APQN could do the wrap.\n"); ret = CKR_FUNCTION_FAILED; goto done; } /* Check ep11 wrapped key struct version and length. We currently only * support/expect version 0x0001 structs. */ wk = (wrapped_key_t *) &ep11_buf; if (ep11_buflen != sizeof(wrapped_key_t) || wk->version != EP11_WRAPPED_KEY_VERSION_1) { TRACE_ERROR("invalid ep11 wrapped key struct length %ld\n", ep11_buflen); ret = CKR_FUNCTION_FAILED; goto done; } /* Check if returned key type is what we expect: * - 0x1 = AES with bit length 128, 192 and 256 * - 0x2 = 2DES and 3DES * - 0x3 = EC-P with bit length 192, 224, 256, 384 and 521 * - 0x4 = ED25519 and ED448 */ switch (wk->wrapped_key_type) { case EP11_WRAPPED_KEY_TYPE_AES: case EP11_WRAPPED_KEY_TYPE_EC: case EP11_WRAPPED_KEY_TYPE_ED: break; default: TRACE_ERROR("Got unexpected CPACF key type %d from firmware\n", wk->wrapped_key_type); ret = CKR_FUNCTION_FAILED; goto done; } if (wk->token_size > sizeof(wrapped_key)) { TRACE_ERROR("Buffer too small\n"); ret = CKR_BUFFER_TOO_SMALL; goto done; } token_size = wk->token_size; /* copy wrapped key to wrapped_key variable to create CKA_IBM_OPAQUE_PKEY */ memcpy(wrapped_key, wk->wrapped_key, wk->token_size); if (aes_xts) { /* Check ep11 wrapped key struct version and length. We currently only * support/expect version 0x0001 structs. */ wk2 = (wrapped_key_t *) &ep11_buf2; if (ep11_buflen2 != sizeof(wrapped_key_t) || wk2->version != EP11_WRAPPED_KEY_VERSION_1) { TRACE_ERROR("invalid ep11 wrapped key struct length %ld\n", ep11_buflen2); ret = CKR_FUNCTION_FAILED; goto done; } /* Check if returned key type is what we expect: * - 0x1 = AES with bit length 128 and 256 */ switch (wk2->wrapped_key_type) { case EP11_WRAPPED_KEY_TYPE_AES: break; default: TRACE_ERROR("Got unexpected CPACF key type %d from firmware\n", wk->wrapped_key_type); ret = CKR_FUNCTION_FAILED; goto done; } if (wk2->token_size > sizeof(wrapped_key) - wk->token_size) { TRACE_ERROR("Wrapped key size too big\n"); ret = CKR_BUFFER_TOO_SMALL; goto done; } token_size += wk2->token_size; memcpy(wrapped_key + wk->token_size, wk2->wrapped_key, wk2->token_size); } /* Build new attribute for protected key */ ret = build_attribute(CKA_IBM_OPAQUE_PKEY, wrapped_key, token_size, &tmp_attr); if (ret != CKR_OK) { TRACE_ERROR("build_attribute failed with rc=0x%lx\n", ret); ret = CKR_FUNCTION_FAILED;; goto done; } ret = CKR_OK; done: *pkey_attr = tmp_attr; put_target_info(tokdata, target_info); return ret; } /** * Save the current firmware master key verification pattern in the tokdata: * create a dummy test key, transform it into a protected key, and store the MK * verification pattern in the tokdata. */ static CK_RV ep11tok_pkey_get_firmware_mk_vp(STDLL_TokData_t *tokdata, SESSION *session) { CK_BBOOL btrue = CK_TRUE; CK_ULONG len = AES_KEY_SIZE_256; CK_MECHANISM mech = {CKM_AES_KEY_GEN, NULL_PTR, 0}; CK_ATTRIBUTE tmpl[] = { {CKA_VALUE_LEN, &len, sizeof(CK_ULONG)}, {CKA_IBM_PROTKEY_EXTRACTABLE, &btrue, sizeof(btrue)}, }; CK_ULONG tmpl_len = sizeof(tmpl) / sizeof(CK_ATTRIBUTE); ep11_private_data_t *ep11_data = tokdata->private_data; ep11_session_t *ep11_session; CK_BYTE csum[MAX_CSUMSIZE]; size_t csum_l = sizeof(csum); CK_BYTE blob[MAX_BLOBSIZE]; size_t blobsize = sizeof(blob); CK_BYTE blob_reenc[MAX_BLOBSIZE]; CK_ATTRIBUTE *pkey_attr = NULL, *blob_attr = NULL, *blob_reenc_attr = NULL; ep11_target_info_t* target_info = NULL; unsigned char *ep11_pin_blob = NULL; CK_ULONG ep11_pin_blob_len = 0; CK_RV ret = CKR_OK; if (ep11tok_pkey_option_disabled(tokdata)) return CKR_OK; if (pthread_mutex_lock(&ep11_data->pkey_mutex)) { TRACE_ERROR("%s Failed to lock pkey lock\n", __func__); return CKR_CANT_LOCK; } if (ep11_data->pkey_wrap_support_checked) goto unlock; if (session == NULL) { target_info = get_target_info(tokdata); if (target_info == NULL) { ret = CKR_FUNCTION_FAILED; goto unlock; } } /* Check if CPACF_WRAP mech supported */ if (ep11tok_is_mechanism_supported(tokdata, CKM_IBM_CPACF_WRAP) != CKR_OK) { TRACE_INFO("CKM_IBM_CPACF_WRAP not supported on this system.\n"); ret = CKR_FUNCTION_NOT_SUPPORTED; goto done; } memset(&ep11_data->pkey_mk_vp, 0, PKEY_MK_VP_LENGTH); trace_attributes(__func__, "Generate prot. test key:", tmpl, tmpl_len); if (session != NULL) { ep11_session = (ep11_session_t *)session->private_data; ep11_get_pin_blob(tokdata, ep11_session, FALSE, FALSE, &ep11_pin_blob, &ep11_pin_blob_len); } /* Create an AES testkey with CKA_IBM_PROTKEY_EXTRACTABLE */ if (session != NULL) { RETRY_SESSION_SINGLE_APQN_START(ret, tokdata) RETRY_REENC_CREATE_KEY_START() ret = dll_m_GenerateKey(&mech, tmpl, tmpl_len, ep11_pin_blob, ep11_pin_blob_len, blob, &blobsize, csum, &csum_l, target_info->target); RETRY_REENC_CREATE_KEY_END(tokdata, NULL, target_info, blob, blob_reenc, blobsize, ret) RETRY_SESSION_SINGLE_APQN_END(ret, tokdata, session) } else { RETRY_SINGLE_APQN_START(tokdata, ret) RETRY_REENC_CREATE_KEY_START() ret = dll_m_GenerateKey(&mech, tmpl, tmpl_len, ep11_pin_blob, ep11_pin_blob_len, blob, &blobsize, csum, &csum_l, target_info->target); RETRY_REENC_CREATE_KEY_END(tokdata, NULL, target_info, blob, blob_reenc, blobsize, ret) RETRY_SINGLE_APQN_END(ret, tokdata, target_info) } if (ret != CKR_OK) { TRACE_ERROR("dll_m_GenerateKey failed with rc=0x%lx\n",ret); goto done; } if (check_expected_mkvp(tokdata, blob, blobsize, NULL) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); ret = CKR_DEVICE_ERROR; goto done; } /* Build attribute for secure key blob */ ret = build_attribute(CKA_IBM_OPAQUE, blob, blobsize, &blob_attr); if (ret != CKR_OK) { TRACE_ERROR("build_attribute CKA_IBM_OPAQUE failed with rc=0x%lx\n", ret); goto done; } if (ep11_data->mk_change_active) { ret = build_attribute(CKA_IBM_OPAQUE_REENC, blob_reenc, blobsize, &blob_reenc_attr); if (ret != CKR_OK) { TRACE_ERROR("build_attribute CKA_IBM_OPAQUE_REENC failed with rc=0x%lx\n", ret); goto done; } } /* * Create a protected key from this blob to obtain the LPAR MK vp. When * this function returns ok, we have a 64 byte pkey value: 32 bytes * encrypted key + 32 bytes vp. */ ret = ep11tok_pkey_skey2pkey(tokdata, NULL, blob_attr, blob_reenc_attr, &pkey_attr, FALSE); if (ret != CKR_OK) { /* * Could not transform secure key into protected key, pkey support is * not available. * We are just running without protected key support, i.e. the * pkey_wrap_supported flag in tokdata remains off, but the * pkey_wrap_support_checked flag is turned on */ OCK_SYSLOG(LOG_WARNING, "%s: Warning: Could not get mk_vp, protected key support is " "not available.\n", __func__); TRACE_WARNING("%s: Could not get mk_vp, protected key support is not " "available.\n", __func__); ret = CKR_OK; goto done; } memcpy(&ep11_data->pkey_mk_vp, (CK_BYTE *)pkey_attr->pValue + AES_KEY_SIZE_256, PKEY_MK_VP_LENGTH); __sync_or_and_fetch(&ep11_data->pkey_wrap_supported, 1); done: if (blob_attr) free(blob_attr); if (blob_reenc_attr) free(blob_reenc_attr); if (pkey_attr) free(pkey_attr); put_target_info(tokdata, target_info); __sync_or_and_fetch(&ep11_data->pkey_wrap_support_checked, 1); unlock: if (pthread_mutex_unlock(&ep11_data->pkey_mutex)) { TRACE_ERROR("%s Failed to lock pkey lock\n", __func__); } return ret; } /** * Return true, if the given key obj has a valid protected key, i.e. its * verification pattern matches the one of the current master key. */ static CK_BBOOL ep11tok_pkey_is_valid(STDLL_TokData_t *tokdata, OBJECT *key_obj) { ep11_private_data_t *ep11_data = tokdata->private_data; CK_ATTRIBUTE *pkey_attr = NULL; int vp_offset; CK_BBOOL ret = CK_FALSE; if (template_attribute_get_non_empty(key_obj->template, CKA_IBM_OPAQUE_PKEY, &pkey_attr) == CKR_OK) { if (pkey_attr->ulValueLen >= AES_KEY_SIZE_128 + PKEY_MK_VP_LENGTH) { vp_offset = pkey_attr->ulValueLen - PKEY_MK_VP_LENGTH; if (pthread_mutex_lock(&ep11_data->pkey_mutex)) { TRACE_ERROR("%s Failed to lock pkey lock\n", __func__); goto done; } if (memcmp((CK_BYTE *)pkey_attr->pValue + vp_offset, &ep11_data->pkey_mk_vp, PKEY_MK_VP_LENGTH) == 0) { ret = CK_TRUE; } if (pthread_mutex_unlock(&ep11_data->pkey_mutex)) { TRACE_ERROR("%s Failed to unlock pkey lock\n", __func__); } } } done: return ret; } /** * Create a new protected key for the given key obj and update attribute * CKA_IBM_OPAQUE with the new pkey. */ static CK_RV ep11tok_pkey_update(STDLL_TokData_t *tokdata, SESSION *session, OBJECT *key_obj, CK_BBOOL aes_xts) { ep11_private_data_t *ep11_data = tokdata->private_data; CK_ATTRIBUTE *skey_attr = NULL; CK_ATTRIBUTE *skey_reenc_attr = NULL; CK_ATTRIBUTE *pkey_attr = NULL; CK_RV ret; int vp_offset; int num_retries = 0; /* Get secure key from obj */ if (template_attribute_get_non_empty(key_obj->template, CKA_IBM_OPAQUE, &skey_attr) != CKR_OK) { TRACE_ERROR("This key has no blob: should not occur!\n"); ret = CKR_FUNCTION_FAILED; goto done; } if (ep11_data->mk_change_active) { /* Try to get CKA_IBM_OPAQUE_REENC, ignore if it fails */ template_attribute_get_non_empty(key_obj->template, CKA_IBM_OPAQUE_REENC, &skey_reenc_attr); } retry: /* Transform the secure key into a protected key */ ret = ep11tok_pkey_skey2pkey(tokdata, session, skey_attr, skey_reenc_attr, &pkey_attr, aes_xts); if (ret != CKR_OK) { TRACE_ERROR("protected key creation failed with rc=0x%lx\n",ret); goto done; } if (pthread_mutex_lock(&ep11_data->pkey_mutex)) { TRACE_ERROR("%s Failed to lock pkey lock\n", __func__); ret = CKR_CANT_LOCK; goto done; } /* * Check if the new pkey's verification pattern matches the one in * ep11_data. This should always be the case, except there was a live * guest relocation (LGR) in the middle of the process. */ vp_offset = pkey_attr->ulValueLen - PKEY_MK_VP_LENGTH; if (memcmp(&ep11_data->pkey_mk_vp, (CK_BYTE *)pkey_attr->pValue + vp_offset, PKEY_MK_VP_LENGTH) != 0) { TRACE_ERROR("vp of this pkey does not match with the one in ep11_data\n"); ret = CKR_FUNCTION_FAILED; } if (aes_xts) { /* * Check if the new pkey's verification pattern matches the one in * ep11_data. This should always be the case, except there was a live * guest relocation (LGR) in the middle of the process. * AES XTS has two keys, two keys are concatenated. * Second key is checked above and the first key is checked here */ vp_offset = pkey_attr->ulValueLen / 2 - PKEY_MK_VP_LENGTH; if (memcmp(&ep11_data->pkey_mk_vp, (CK_BYTE *)pkey_attr->pValue + vp_offset, PKEY_MK_VP_LENGTH) != 0) { TRACE_ERROR("vp of this pkey does not match with the one in ep11_data\n"); ret = CKR_FUNCTION_FAILED; } } /* * Recreating the firmware mkvp via ep11tok_pkey_get_firmware_mk_vp below * does only work when pkey_wrap_support_checked is 0. Set it to 0 while * the mutex lock is still obtained. */ if (ret != CKR_OK) __sync_and_and_fetch(&ep11_data->pkey_wrap_support_checked, 0); if (pthread_mutex_unlock(&ep11_data->pkey_mutex)) { TRACE_ERROR("%s Failed to unlock pkey lock\n", __func__); } if (ret != CKR_OK) { /* * Verification pattern does not match. Create it again and retry. * If there was an LGR, this op now takes place on the new system * and should succeed. */ ret = ep11tok_pkey_get_firmware_mk_vp(tokdata, session); if (ret != CKR_OK) goto done; num_retries++; if (num_retries < PKEY_CONVERT_KEY_RETRIES) { if (pkey_attr != NULL) free(pkey_attr); TRACE_DEVEL("%s VP mismatch probably due to LGR, retry %d of %d ...\n", __func__, num_retries, PKEY_CONVERT_KEY_RETRIES); goto retry; } } if (ret != CKR_OK) goto done; /* * Now update the key obj. If it's a token obj, it will be also updated * in the repository. */ ret = pkey_update_and_save(tokdata, key_obj, &pkey_attr); if (ret != CKR_OK) { TRACE_ERROR("pkey_update_and_save failed with rc=0x%lx\n", ret); goto done; } ret = CKR_OK; done: if (pkey_attr != NULL) free(pkey_attr); return ret; } /** * Returns true if the session is ok for creating protected keys, false * otherwise. The session must be read/write for token objects, and not public * nor SO for private objects. */ static CK_BBOOL ep11tok_pkey_session_ok_for_obj(SESSION *session, OBJECT *key_obj) { if (object_is_token_object(key_obj) && (session->session_info.flags & CKF_RW_SESSION) == 0) return CK_FALSE; if (object_is_private(key_obj)) { switch (session->session_info.state) { case CKS_RO_PUBLIC_SESSION: case CKS_RW_PUBLIC_SESSION: case CKS_RW_SO_FUNCTIONS: return CK_FALSE; default: break; } } return CK_TRUE; } /* * Returns true if the given key object is eligible to get a protected key * attribute, false otherwise. */ static CK_RV ep11tok_pkey_obj_eligible_for_pkey_support( ep11_private_data_t *ep11_data, OBJECT *key_obj) { if (object_is_attr_bound(key_obj) || !ep11_data->pkey_wrap_supported || !object_is_pkey_extractable(key_obj)) { return CKR_FUNCTION_NOT_SUPPORTED; } if (!ep11_data->pkey_combined_extract_supported && object_is_extractable(key_obj)) { TRACE_ERROR("Combined extract not supported, but CKA_EXTRACTABLE " "and CKA_IBM_PROTKEY_EXTRACTABLE are both TRUE\n"); return CKR_TEMPLATE_INCONSISTENT; } return CKR_OK; } /** * Checks if the preconditions for using the related protected key of * the given secure key object are met. The caller of this routine must * have a READ_LOCK on the key object. * * The routine internally creates a protected key and adds it to the key_obj, * if the machine supports pkeys, the key is eligible for pkey support, does * not already have a valid pkey, and other conditions, like r/w session, are * fulfilled. As adding a protected key to the key_obj involves unlocking and * re-locking, the key blob, or any other attribute of the key, that was * retrieved via h_opaque_2_blob before calling this function might be no more * valid in a parallel environment. * * Therefore, the following return codes tell the calling function how to * proceed: * * @return CKR_OK: * a protected key was possibly created successfully and everything * is fine to use pkey support. In this case the protected key * shall be used, but a previously obtained key blob or other attr * might be invalid, because of a possible unlock/re-lock of the * key_obj. * * CKR_FUNCTION_NOT_SUPPORTED: * The system, session or key do not allow to use pkey support, but * no attempt was made to create a protected key. So the key blob, * or any other attr, is still valid and a fallback into the ep11 * path is ok. * * all others: * An internal error occurred and it was possibly attempted to create * a protected key for the object. In this case, the key blob, or * any other attr, might be no longer valid in a parallel environment * and the ep11 fallback is not possible anymore. The calling * function shall return with an error in this case. */ CK_RV ep11tok_pkey_check(STDLL_TokData_t *tokdata, SESSION *session, OBJECT *key_obj, CK_MECHANISM *mech) { ep11_private_data_t *ep11_data = tokdata->private_data; CK_ATTRIBUTE *opaque_attr = NULL; CK_RV ret = CKR_FUNCTION_NOT_SUPPORTED; /* Check if CPACF supports the operation implied by this key and mech */ if (!pkey_op_supported_by_cpacf(ep11_data->msa_level, mech, key_obj->template)) goto done; /* Check config option */ switch (ep11_data->pkey_mode) { case PKEY_MODE_DISABLED: goto done; break; case PKEY_MODE_DEFAULT: case PKEY_MODE_ENABLE4NONEXTR: case PKEY_MODE_ENABLE4EXTR: case PKEY_MODE_ENABLE4ALL: /* Use existing pkeys, re-create invalid pkeys, and also create new * pkeys for secret/private keys that do not already have one. EC * public keys that are pkey-extractable, can always be used via CPACF * as there is no protected key involved.*/ if (pkey_is_ec_public_key(key_obj->template) && object_is_pkey_extractable(key_obj)) { ret = CKR_OK; goto done; } /* Ensure the firmware master key verification pattern is available */ if (ep11tok_pkey_get_firmware_mk_vp(tokdata, session) != CKR_OK) goto done; ret = ep11tok_pkey_obj_eligible_for_pkey_support(ep11_data, key_obj); if (ret != CKR_OK) goto done; if (template_attribute_get_non_empty(key_obj->template, CKA_IBM_OPAQUE_PKEY, &opaque_attr) != CKR_OK || !ep11tok_pkey_is_valid(tokdata, key_obj)) { /* this key has either no pkey attr, or it is not valid, * try to create one, if the session state allows it */ if (!ep11tok_pkey_session_ok_for_obj(session, key_obj)) goto done; ret = ep11tok_pkey_update(tokdata, session, key_obj, mech->mechanism == CKM_AES_XTS); if (ret != CKR_OK) { TRACE_ERROR("error updating the %s protected key, rc=0x%lx\n", mech->mechanism == CKM_AES_XTS ? "AES XTS" : "AES", ret); if (ret == CKR_FUNCTION_NOT_SUPPORTED) ret = CKR_FUNCTION_FAILED; goto done; } } break; default: /* should not occur */ TRACE_ERROR("PKEY_MODE %i unsupported.\n", ep11_data->pkey_mode); ret = CKR_FUNCTION_FAILED; goto done; break; } ret = CKR_OK; done: return ret; } /** * Wrapper function around ep11tok_pkey_check for the case where we don't * have a key object. This function is called externally from new_host.c. * Returns CKR_OK if pkey usage is OK, CKR_FUNCTION_NOT_SUPPORTED if pkey * is not supported, or any other return code in case of an error. In such * cases the calling function should itself return with an error, because * neither the secure key nor the protected key path will work. */ CK_RV ep11tok_pkey_usage_ok(STDLL_TokData_t *tokdata, SESSION *session, CK_OBJECT_HANDLE hkey, CK_MECHANISM *mech) { size_t keyblobsize = 0; CK_BYTE *keyblob; OBJECT *key_obj; CK_RV ret; ret = h_opaque_2_blob(tokdata, hkey, &keyblob, &keyblobsize, &key_obj, READ_LOCK); if (ret != CKR_OK) { TRACE_ERROR("%s no blob ret=0x%lx\n", __func__, ret); return ret; } ret = ep11tok_pkey_check(tokdata, session, key_obj, mech); object_put(tokdata, key_obj, TRUE); key_obj = NULL; return ret; } CK_RV ep11tok_pkey_check_aes_xts(STDLL_TokData_t *tokdata, OBJECT *key_obj, CK_MECHANISM_TYPE type) { ep11_private_data_t *ep11_data = tokdata->private_data; if (ep11tok_is_mechanism_supported(tokdata, type) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); return CKR_MECHANISM_INVALID; } if (ep11tok_pkey_obj_eligible_for_pkey_support(ep11_data, key_obj) != CKR_OK) { TRACE_ERROR("Key not eligible for pkey support\n"); return CKR_TEMPLATE_INCONSISTENT; } return CKR_OK; } CK_RV ep11tok_pkey_add_protkey_attr_to_tmpl(TEMPLATE *tmpl) { CK_ATTRIBUTE *pkey_attr = NULL; CK_BBOOL btrue = CK_TRUE, bfalse = CK_FALSE; CK_RV ret; if (!template_attribute_find(tmpl, CKA_IBM_PROTKEY_EXTRACTABLE, &pkey_attr)) { ret = build_attribute(CKA_IBM_PROTKEY_EXTRACTABLE, &btrue, sizeof(CK_BBOOL), &pkey_attr); if (ret != CKR_OK) { TRACE_ERROR("build_attribute failed with ret=0x%lx\n", ret); goto done; } ret = template_update_attribute(tmpl, pkey_attr); if (ret != CKR_OK) { TRACE_ERROR("update_attribute failed with ret=0x%lx\n", ret); free(pkey_attr); goto done; } ret = build_attribute(CKA_IBM_PROTKEY_NEVER_EXTRACTABLE, &bfalse, sizeof(CK_BBOOL), &pkey_attr); if (ret != CKR_OK) { TRACE_ERROR("build_attribute failed with ret=0x%lx\n", ret); goto done; } ret = template_update_attribute(tmpl, pkey_attr); if (ret != CKR_OK) { TRACE_ERROR("update_attribute failed with ret=0x%lx\n", ret); free(pkey_attr); goto done; } } ret = CKR_OK; done: return ret; } static CK_RV ep11tok_pkey_convert_key(STDLL_TokData_t *tokdata, SESSION *session, OBJECT *key_obj, CK_BBOOL xts_mode, CK_BYTE *protkey, CK_ULONG *protkey_len) { ep11_private_data_t *ep11_data = tokdata->private_data; int num_retries = 0, vp_offset1, vp_offset2; CK_ATTRIBUTE *skey_reenc_attr = NULL; CK_ATTRIBUTE *skey_attr = NULL; CK_ATTRIBUTE *pkey_attr = NULL; CK_RV rc, rc2; /* Try to obtain a write lock on the key_obj */ rc = object_unlock(key_obj); if (rc != CKR_OK) { TRACE_ERROR("object_unlock failed, rc=0x%lx\n", rc); goto done; } rc = object_lock(key_obj, WRITE_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Could not obtain write lock.\n"); goto done; } /* * The key_obj could be modified between unlock and lock. Therefore get * the attribute when we have the write lock here. */ if (template_attribute_get_non_empty(key_obj->template, CKA_IBM_OPAQUE, &skey_attr) != CKR_OK) { TRACE_ERROR("This key has no blob: should not occur!\n"); rc = CKR_FUNCTION_FAILED; goto done; } if (ep11_data->mk_change_active) { /* Try to get CKA_IBM_OPAQUE_REENC, ignore if it fails */ template_attribute_get_non_empty(key_obj->template, CKA_IBM_OPAQUE_REENC, &skey_reenc_attr); } retry: /* Convert secure key to protected key. */ rc = ep11tok_pkey_skey2pkey(tokdata, session, skey_attr, skey_reenc_attr, &pkey_attr, xts_mode); if (rc != CKR_OK) { TRACE_ERROR("protkey creation failed, rc=0x%lx\n", rc); goto unlock; } /* * In case of XTS, check if the wkvp's of the two keys are identical. * An LGR could have happened between the creation of the two keys. */ if (xts_mode) { vp_offset1 = pkey_attr->ulValueLen / 2 - PKEY_MK_VP_LENGTH; vp_offset2 = pkey_attr->ulValueLen - PKEY_MK_VP_LENGTH; if (memcmp((CK_BYTE *)pkey_attr->pValue + vp_offset1, (CK_BYTE *)pkey_attr->pValue + vp_offset2, PKEY_MK_VP_LENGTH) != 0) { num_retries++; if (num_retries < PKEY_CONVERT_KEY_RETRIES) { TRACE_DEVEL("%s vp of xts key 1 does not match with vp of " "xts key 2, retry %d of %d ...\n", __func__, num_retries, PKEY_CONVERT_KEY_RETRIES); goto retry; } rc = CKR_FUNCTION_FAILED; goto unlock; } } /* * Save new protkey attr in key_obj. This happens only in memory, * works also for r/o sessions. */ rc = template_update_attribute(key_obj->template, pkey_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed, rc=0x%lx\n", rc); goto unlock; } /* If we have an r/w session, also save obj to disk. */ if (ep11tok_pkey_session_ok_for_obj(session, key_obj)) { if (object_is_token_object(key_obj)) { rc = object_mgr_save_token_object(tokdata, key_obj); if (rc != CKR_OK) { TRACE_ERROR("Could not save token obj to repository, rc=0x%lx.\n", rc); goto unlock; } } } /* Update wkvp in EP11 private data. */ if (pthread_mutex_lock(&ep11_data->pkey_mutex)) { TRACE_ERROR("%s Failed to lock pkey lock\n", __func__); rc = CKR_CANT_LOCK; goto unlock; } memcpy(&ep11_data->pkey_mk_vp, (CK_BYTE *)pkey_attr->pValue + pkey_attr->ulValueLen - PKEY_MK_VP_LENGTH, PKEY_MK_VP_LENGTH); if (pthread_mutex_unlock(&ep11_data->pkey_mutex)) { TRACE_ERROR("%s Failed to lock pkey lock\n", __func__); } /* Pass back new protkey. Need to do this before unlocking the obj. */ if (*protkey_len < pkey_attr->ulValueLen) { rc = CKR_BUFFER_TOO_SMALL; goto unlock; } memcpy(protkey, pkey_attr->pValue, pkey_attr->ulValueLen); *protkey_len = pkey_attr->ulValueLen; unlock: rc2 = object_unlock(key_obj); if (rc2 != CKR_OK) { TRACE_ERROR("object_unlock failed, rc=0x%lx\n", rc2); if (rc == CKR_OK) rc = rc2; goto done; } rc2 = object_lock(key_obj, READ_LOCK); if (rc2 != CKR_OK) { TRACE_ERROR("object_lock for READ failed, rc=0x%lx\n", rc2); if (rc == CKR_OK) rc = rc2; goto done; } done: return rc; } #endif /* NO_PKEY */ CK_RV ep11tok_extract_blob_info(CK_BYTE *blob, CK_ULONG blob_len, CK_BBOOL *is_spki, CK_BYTE **wkid, CK_BYTE** session_id, XCP_Attr_t **bool_attrs) { CK_BYTE *data; CK_ULONG data_len, field_len, ofs, i; blob_attr_header_t *hdr; /* From EP11 structure document section 7.4.1 SPKI with MAC */ const struct { const char* field; CK_ULONG min_len; CK_BYTE **ptr; } fields[] = { { "WKID", XCP_WKID_BYTES, wkid }, { "SessionID", XCP_WK_BYTES, session_id }, { "Salt", XCP_SPKISALT_BYTES, NULL }, { "Mode", XCP_BLOBCLRMODE_BYTES, NULL }, { "Attrs", sizeof(blob_attr_header_t) + XCP_BLOBCLRATTR_BYTES, (CK_BYTE **)&hdr }, { NULL, 0, NULL }, }; /* * Check if MACed SPKI or key/state blob. From the EP11 structure document: * Session identifiers are guaranteed not to have 0x30 as their first * byte. This allows a single-byte check to differentiate between blobs * starting with session identifiers, and MACed SPKIs, which may be * used as blobs under other conditions. * Key blobs start with the session identifier (32 bytes). * SPKIs start with a DER encoded SPKI, which itself starts with a SEQUENCE * denoted by 0x30 followed by the DER encoded length of the SPKI. */ if (blob_len > 5 && blob[0] == 0x30 && ber_decode_SEQUENCE(blob, blob_len, &data, &data_len, &field_len) == CKR_OK) { /* It is a SPKI, fields follow as OCTET STRINGs right after SPKI data */ if (blob_len < field_len) { TRACE_ERROR("MACed SPKI is too small\n"); return CKR_FUNCTION_FAILED; } if (is_spki != NULL) *is_spki = TRUE; if (blob_len == field_len) { TRACE_DEVEL("Raw-SPKI (non-MACed), no info to return\n"); if (wkid != NULL) *wkid = NULL; if (session_id != NULL) *session_id = NULL; if (bool_attrs != NULL) *bool_attrs = NULL; return CKR_OK; } ofs = field_len; for (i = 0; fields[i].field != NULL; i++) { if (ofs + 2 + fields[i].min_len > blob_len) { TRACE_ERROR("MACed SPKI is too small to contain field %s\n", fields[i].field); return CKR_FUNCTION_FAILED; } if (ber_decode_OCTET_STRING(blob + ofs, blob_len - ofs, &data, &data_len, &field_len) != CKR_OK) { TRACE_ERROR("Failed to decode MACed SPKI field %s\n", fields[i].field); return CKR_FUNCTION_FAILED; } if (data_len < fields[i].min_len || ofs + field_len > blob_len) { TRACE_ERROR("MACed SPKI field %s is too small\n", fields[i].field); return CKR_FUNCTION_FAILED; } if (fields[i].ptr != NULL) *fields[i].ptr = data; ofs += field_len; } if (hdr->version != EP11_BLOB_ATTR_HDR_VERSION) { TRACE_ERROR("MACed SPKI attributes heder is invalid\n"); return CKR_FUNCTION_FAILED; } if (bool_attrs != NULL) *bool_attrs = (XCP_Attr_t*)&data[sizeof(blob_attr_header_t) + 4]; } else { /* It is a key blob */ if (blob_len < EP11_BLOB_VERSION_OFFSET + sizeof(uint16_t) || *(uint16_t *)&blob[EP11_BLOB_VERSION_OFFSET] != EP11_BLOB_VERSION) { TRACE_ERROR("Key blob is too small or is invalid\n"); return CKR_FUNCTION_FAILED; } if (is_spki != NULL) *is_spki = FALSE; if (wkid != NULL) *wkid = &blob[EP11_BLOB_WKID_OFFSET]; if (session_id != NULL) *session_id = blob; if (bool_attrs != NULL) *bool_attrs = (XCP_Attr_t *)&blob[EP11_BLOB_BOOL_ATTR_OFFSET]; } return CKR_OK; } static const struct { XCP_Attr_t ep11_attr; CK_ATTRIBUTE_TYPE pkcs11_attr; CK_BBOOL can_set_to_false; /* allow to restrict key usage */ CK_BBOOL can_set_to_true; /* allow to lift key usage */ } ep11_pkcs11_attr_map[] = { { XCP_BLOB_EXTRACTABLE, CKA_EXTRACTABLE, TRUE, FALSE }, { XCP_BLOB_NEVER_EXTRACTABLE, CKA_NEVER_EXTRACTABLE, FALSE, FALSE }, { XCP_BLOB_MODIFIABLE, CKA_MODIFIABLE, TRUE, FALSE }, { XCP_BLOB_NEVER_MODIFIABLE, CKA_IBM_NEVER_MODIFIABLE, FALSE, FALSE }, { XCP_BLOB_RESTRICTABLE, CKA_IBM_RESTRICTABLE, FALSE, FALSE }, { XCP_BLOB_ATTRBOUND, CKA_IBM_ATTRBOUND, FALSE, FALSE }, { XCP_BLOB_USE_AS_DATA, CKA_IBM_USE_AS_DATA, TRUE, TRUE }, { XCP_BLOB_SIGN, CKA_SIGN, TRUE, TRUE }, { XCP_BLOB_DECRYPT, CKA_DECRYPT, TRUE, TRUE }, { XCP_BLOB_ENCRYPT, CKA_ENCRYPT, TRUE, TRUE }, { XCP_BLOB_DERIVE, CKA_DERIVE, TRUE, TRUE }, { XCP_BLOB_UNWRAP, CKA_UNWRAP, TRUE, TRUE }, { XCP_BLOB_WRAP, CKA_WRAP, TRUE, TRUE }, { XCP_BLOB_VERIFY, CKA_VERIFY, TRUE, TRUE }, { XCP_BLOB_TRUSTED, CKA_TRUSTED, TRUE, FALSE }, { XCP_BLOB_WRAP_W_TRUSTED, CKA_WRAP_WITH_TRUSTED , TRUE, TRUE}, { XCP_BLOB_PROTKEY_EXTRACTABLE, CKA_IBM_PROTKEY_EXTRACTABLE, TRUE, FALSE }, { XCP_BLOB_PROTKEY_NEVER_EXTRACTABLE, CKA_IBM_PROTKEY_NEVER_EXTRACTABLE, FALSE, FALSE }, { 0, 0, 0, 0 }, }; static void ep11tok_endecaps_combine_attrs(TEMPLATE *tmpl, CK_KEY_TYPE keytype, CK_OBJECT_CLASS class, CK_ATTRIBUTE_TYPE pkcs11_attr, CK_BBOOL *user_val) { CK_ATTRIBUTE *attr; switch (keytype) { case CKK_RSA: /* RSA: Combine WRAP and ENCAPS, UNWRAP and DECAPS */ if (pkcs11_attr == CKA_WRAP && class == CKO_PUBLIC_KEY && template_attribute_find(tmpl, CKA_ENCAPSULATE, &attr) && attr->ulValueLen == sizeof(CK_BBOOL) && attr->pValue != NULL) { TRACE_DEVEL("%s RSA pub key: CKA_WRAP (%d) = CKA_WRAP (%d) OR " "CKA_ENCAPSULATE (%d)\n", __func__, *user_val | *((CK_BBOOL *)attr->pValue), *user_val, *((CK_BBOOL *)attr->pValue)); *user_val |= *((CK_BBOOL *)attr->pValue); } if (pkcs11_attr == CKA_UNWRAP && class == CKO_PRIVATE_KEY && template_attribute_find(tmpl, CKA_DECAPSULATE, &attr) && attr->ulValueLen == sizeof(CK_BBOOL) && attr->pValue != NULL) { TRACE_DEVEL("%s RSA prv key: CKA_UNWRAP (%d) = CKA_UNWRAP (%d) OR " "CKA_DECAPSULATE (%d)\n", __func__, *user_val | *((CK_BBOOL *)attr->pValue), *user_val, *((CK_BBOOL *)attr->pValue)); *user_val |= *((CK_BBOOL *)attr->pValue); } break; case CKK_EC: case CKK_EC_MONTGOMERY: case CKK_DH: case CKK_ML_KEM: /* EC/DH/ML-KEM: Combine DERIVE and ENCAPS and DECAPS */ if (pkcs11_attr == CKA_DERIVE) { if (class == CKO_PUBLIC_KEY && template_attribute_find(tmpl, CKA_ENCAPSULATE, &attr) && attr->ulValueLen == sizeof(CK_BBOOL) && attr->pValue != NULL) { TRACE_DEVEL("%s EC/DH/ML-KEM pub key: CKA_DERIVE (%d) = " "CKA_DERIVE (%d) OR CKA_ENCAPSULATE (%d)\n", __func__, *user_val | *((CK_BBOOL *)attr->pValue), *user_val, *((CK_BBOOL *)attr->pValue)); *user_val |= *((CK_BBOOL *)attr->pValue); } if (class == CKO_PRIVATE_KEY && template_attribute_find(tmpl, CKA_DECAPSULATE, &attr) && attr->ulValueLen == sizeof(CK_BBOOL) && attr->pValue != NULL) { TRACE_DEVEL("%s EC/DH/ML-KEM prv key: CKA_DERIVE (%d) = " "CKA_DERIVE (%d) OR CKA_DECAPSULATE (%d)\n", __func__, *user_val | *((CK_BBOOL *)attr->pValue), *user_val, *((CK_BBOOL *)attr->pValue)); *user_val |= *((CK_BBOOL *)attr->pValue); } } break; } } static CK_RV ep11tok_endecaps_combine_attrs_import(TEMPLATE *tmpl, CK_KEY_TYPE keytype, CK_OBJECT_CLASS class, CK_BBOOL add_always, CK_BBOOL wrap, CK_BBOOL unwrap, CK_BBOOL derive) { CK_ATTRIBUTE *attr; CK_RV rc; switch (keytype) { case CKK_RSA: /* RSA: Set ENCAPS = WRAP, DECAPS = UNWRAP */ if(class == CKO_PUBLIC_KEY && (add_always || !template_attribute_find(tmpl, CKA_ENCAPSULATE, &attr))) { TRACE_DEVEL("%s RSA pub key: Add CKA_ENCAPSULATE = CKA_WRAP " "(%d)\n", __func__, wrap); rc = template_build_update_attribute(tmpl, CKA_ENCAPSULATE, &wrap, sizeof(CK_BBOOL)); if (rc != CKR_OK) { TRACE_ERROR("template_build_update_attribute (CKA_ENCAPSULATE) " "failed (rc=0x%lx)\n", rc); return rc; } } if (class == CKO_PRIVATE_KEY && (add_always || !template_attribute_find(tmpl, CKA_DECAPSULATE, &attr))) { TRACE_DEVEL("%s RSA prv key: Add CKA_DECAPSULATE = CKA_UNWRAP " "(%d)\n", __func__, unwrap); rc = template_build_update_attribute(tmpl, CKA_DECAPSULATE, &unwrap, sizeof(CK_BBOOL)); if (rc != CKR_OK) { TRACE_ERROR("template_build_update_attribute (CKA_DECAPSULATE) " "failed (rc=0x%lx)\n", rc); return rc; } } break; case CKK_EC: case CKK_EC_MONTGOMERY: case CKK_DH: case CKK_ML_KEM: /* EC/DH/ML-KEM: Set ENCAPS = DERIVE, DECAPS = DERIVE */ if(class == CKO_PUBLIC_KEY && (add_always || !template_attribute_find(tmpl, CKA_ENCAPSULATE, &attr))) { TRACE_DEVEL("%s EC/DH/ML-KEM pub key: Add CKA_ENCAPSULATE = " "CKA_DERIVE (%d)\n", __func__, derive); rc = template_build_update_attribute(tmpl, CKA_ENCAPSULATE, &derive, sizeof(CK_BBOOL)); if (rc != CKR_OK) { TRACE_ERROR("template_build_update_attribute (CKA_ENCAPSULATE) " "failed (rc=0x%lx)\n", rc); return rc; } } if (class == CKO_PRIVATE_KEY && (add_always || !template_attribute_find(tmpl, CKA_DECAPSULATE, &attr))) { TRACE_DEVEL("%s EC/DH/ML-KEM prv key: Add CKA_DECAPSULATE = " "CKA_DERIVE (%d)\n", __func__, derive); rc = template_build_update_attribute(tmpl, CKA_DECAPSULATE, &derive, sizeof(CK_BBOOL)); if (rc != CKR_OK) { TRACE_ERROR("template_build_update_attribute (CKA_DECAPSULATE) " "failed (rc=0x%lx)\n", rc); return rc; } } break; } return CKR_OK; } static CK_RV ep11tok_check_blob_import_attrs(STDLL_TokData_t *tokdata, CK_OBJECT_CLASS class, TEMPLATE *tmpl, CK_BYTE *blob, CK_ULONG blob_len) { CK_ULONG keytype, i; XCP_Attr_t *bool_attrs = NULL, *bool_attrs2 = NULL; CK_ATTRIBUTE *attr; CK_BBOOL is_spki, blob_val, user_val, new_blob_val; CK_BBOOL wrap = CK_FALSE, unwrap = CK_FALSE, derive = CK_FALSE; CK_RV rc; UNUSED(tokdata); rc = template_attribute_get_ulong(tmpl, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("CKA_KEY_TYPE not found\n"); return CKR_TEMPLATE_INCOMPLETE; } rc = ep11tok_extract_blob_info(blob, keytype == CKK_AES_XTS ? blob_len / 2 : blob_len, &is_spki, NULL, NULL, &bool_attrs); if (rc != CKR_OK) { TRACE_ERROR("ep11tok_extract_blob_info failed\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } if (keytype == CKK_AES_XTS) { rc = ep11tok_extract_blob_info(blob + blob_len / 2, blob_len / 2, NULL, NULL, NULL, &bool_attrs2); if (rc != CKR_OK) { TRACE_ERROR("ep11tok_extract_blob_info failed\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } if (*bool_attrs != *bool_attrs2) { TRACE_ERROR("AES-XTS keys are inconsistent\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } } if (is_spki) { /* It's a (MACed) SPKI blob */ if (class != CKO_PUBLIC_KEY) { TRACE_ERROR("SPKI-blob is only allowed for public keys\n"); return CKR_TEMPLATE_INCONSISTENT; } if (bool_attrs == NULL) { TRACE_DEVEL("Raw-SPKI (non-MACed), no attributes to check\n"); return CKR_OK; } TRACE_DEVEL("MACed-SPKI boolean attrs: 0x%08x\n", *bool_attrs); } else { /* It's a key blob */ if (class != CKO_PRIVATE_KEY && class != CKO_SECRET_KEY) { TRACE_ERROR("Key-blob is only allowed for private or secret keys\n"); return CKR_TEMPLATE_INCONSISTENT; } TRACE_DEVEL("Key-Blob boolean attrs: 0x%08x\n", *bool_attrs); } for (i = 0; ep11_pkcs11_attr_map[i].ep11_attr != 0; i++) { blob_val = (*bool_attrs & ep11_pkcs11_attr_map[i].ep11_attr) != 0 ? CK_TRUE : CK_FALSE; if (template_attribute_find(tmpl, ep11_pkcs11_attr_map[i].pkcs11_attr, &attr) && attr->ulValueLen == sizeof(CK_BBOOL) && attr->pValue != NULL) { user_val = *((CK_BBOOL *)attr->pValue); new_blob_val = user_val; ep11tok_endecaps_combine_attrs(tmpl, keytype, class, ep11_pkcs11_attr_map[i].pkcs11_attr, &new_blob_val); if (blob_val != new_blob_val) { /* User supplied attribute is different than in blob */ if ((*bool_attrs & XCP_BLOB_MODIFIABLE) == 0) { TRACE_ERROR("Attribute %s=%s in template can not be " "applied to the blob because the blob has " "CKA_MODIFIABLE=FALSE\n", p11_get_cka(ep11_pkcs11_attr_map[i].pkcs11_attr), new_blob_val ? "TRUE" : "FALSE"); return CKR_ATTRIBUTE_VALUE_INVALID; } if ((new_blob_val == FALSE && ep11_pkcs11_attr_map[i].can_set_to_false) || (new_blob_val == TRUE && ep11_pkcs11_attr_map[i].can_set_to_true)) { /* * Update of attr is allowed. Use the original user value, * any adjustments done by ep11tok_endecaps_combine_attrs() * should not be reflected in template. Later on * import_blob_update_attrs() will do the same adjustments * again and update the blob attributes as needed. */ blob_val = user_val; } else { TRACE_ERROR("Attribute %s=%s in template conflicts with " "blob attribute setting %s\n", p11_get_cka(ep11_pkcs11_attr_map[i].pkcs11_attr), new_blob_val ? "TRUE" : "FALSE", blob_val ? "TRUE" : "FALSE"); return CKR_ATTRIBUTE_VALUE_INVALID; } } else { /* * After adjustment by ep11tok_endecaps_combine_attrs(), the * user supplied attribute is the same as in the blob. Still, * use the original user value, any adjustments done by * ep11tok_endecaps_combine_attrs() should not be reflected in * template. */ blob_val = user_val; } } if (ep11_pkcs11_attr_map[i].pkcs11_attr == CKA_WRAP) wrap = blob_val; if (ep11_pkcs11_attr_map[i].pkcs11_attr == CKA_UNWRAP) unwrap = blob_val; if (ep11_pkcs11_attr_map[i].pkcs11_attr == CKA_DERIVE) derive = blob_val; rc = template_build_update_attribute(tmpl, ep11_pkcs11_attr_map[i].pkcs11_attr, &blob_val, sizeof(blob_val)); if (rc != CKR_OK) { TRACE_ERROR("template_build_update_attribute failed for %s\n", p11_get_cka(ep11_pkcs11_attr_map[i].pkcs11_attr)); return rc; } } /* * Set CKA_ENCAPSULATE/CKA_DECAPSULATE according to combined attrs, if not * already specified by user in the template. */ rc = ep11tok_endecaps_combine_attrs_import(tmpl, keytype, class, FALSE, wrap, unwrap, derive); if (rc != CKR_OK) { TRACE_ERROR("ep11tok_endecaps_combine_attrs_import failed\n"); return rc; } return CKR_OK; } /** * This function is called whenever a new object is created. It sets * attribute CKA_IBM_PROTKEY_EXTRACTABLE according to the PKEY_MODE token * option. * If the FORCE_SENSITIVE token option is enabled, it sets attribute * CKA_SENSITIVE to TRUE for secret keys (CKO_SECRET_KEY) if it is not * specified in the template. For private keys (CKO_PRIVATE_KEY) it always * sets CKA_SENSITIVE to TRUE if it is not specified in the template, * regardless of the FORCE_SENSITIVE option. */ CK_RV token_specific_set_attrs_for_new_object(STDLL_TokData_t *tokdata, CK_OBJECT_CLASS class, CK_ULONG mode, TEMPLATE *tmpl) { ep11_private_data_t *ep11_data = tokdata->private_data; CK_ATTRIBUTE *sensitive_attr = NULL, *opaque = NULL; CK_BBOOL sensitive, extractable, pkey_extractable, btrue = CK_TRUE; #ifndef NO_PKEY CK_ATTRIBUTE *ecp_attr = NULL; CK_BBOOL add_pkey_extractable = CK_FALSE; CK_MECHANISM mech = { CKM_ECDSA, NULL, 0 }; #endif CK_RV ret; UNUSED(mode); if (class != CKO_SECRET_KEY && class != CKO_PRIVATE_KEY && class != CKO_PUBLIC_KEY) return CKR_OK; if (mode == MODE_CREATE && template_attribute_find(tmpl, CKA_IBM_OPAQUE, &opaque) == TRUE && opaque->ulValueLen > 0 && opaque->pValue != NULL) { /* Check for conflicting attrs in to-be-imported blob and template */ ret = ep11tok_check_blob_import_attrs(tokdata, class, tmpl, (CK_BYTE*)opaque->pValue, opaque->ulValueLen); if (ret != CKR_OK) { TRACE_ERROR("ep11tok_check_blob_import_attrs failed ret=0x%lx\n", ret); goto done; } } if (class == CKO_PRIVATE_KEY || (class == CKO_SECRET_KEY && ep11_data->cka_sensitive_default_true)) { /* private key, or secret key and FORCE_SENSITIVE is enabled */ ret = template_attribute_get_bool(tmpl, CKA_SENSITIVE, &sensitive); if (ret == CKR_TEMPLATE_INCOMPLETE) { /* Not in template, supply default (TRUE) */ ret = build_attribute(CKA_SENSITIVE, &btrue, sizeof(CK_BBOOL), &sensitive_attr); if (ret != CKR_OK) { TRACE_ERROR("build_attribute failed with ret=0x%lx\n", ret); goto done; } ret = template_update_attribute(tmpl, sensitive_attr); if (ret != CKR_OK) { TRACE_ERROR("update_attribute failed with ret=0x%lx\n", ret); free(sensitive_attr); goto done; } } } if (!ep11_data->pkey_combined_extract_supported) { ret = template_attribute_get_bool(tmpl, CKA_EXTRACTABLE, &extractable); if (ret != CKR_OK) extractable = FALSE; ret = template_attribute_get_bool(tmpl, CKA_IBM_PROTKEY_EXTRACTABLE, &pkey_extractable); if (ret != CKR_OK) pkey_extractable = FALSE; if (extractable && pkey_extractable) { /* The EP11 call would return CKR_FUNCTION_CANCELED in that case */ TRACE_ERROR("Combined extract not supported, but CKA_EXTRACTABLE " "and CKA_IBM_PROTKEY_EXTRACTABLE are both TRUE\n"); ret = CKR_TEMPLATE_INCONSISTENT; goto done; } } #ifndef NO_PKEY switch (ep11_data->pkey_mode) { case PKEY_MODE_DISABLED: /* Nothing to do */ break; case PKEY_MODE_DEFAULT: /* If the application did not specify pkey-extractable, all keys get * pkey-extractable=false. This was already set by default, so * nothing to do here. */ break; case PKEY_MODE_ENABLE4NONEXTR: /* If the application did not specify pkey-extractable, all * non-extractable secret/private keys and all EC public keys where * CPACF supports the related curve, get pkey-extractable=true */ switch (class) { case CKO_PUBLIC_KEY: if (template_attribute_get_non_empty(tmpl, CKA_EC_PARAMS, &ecp_attr) == CKR_OK && pkey_op_supported_by_cpacf(ep11_data->msa_level, &mech, tmpl)) add_pkey_extractable = CK_TRUE; /* Note that the explicit parm CKM_ECDSA just tells the * function that it's not AES here. It covers all EC and ED * mechs */ break; default: ret = template_attribute_get_bool(tmpl, CKA_EXTRACTABLE, &extractable); if (ret == CKR_OK && !extractable) add_pkey_extractable = CK_TRUE; break; } break; case PKEY_MODE_ENABLE4EXTR: /* If the application did not specify CKA_IBM_PROTKEY_EXTRACTABLE in * its template, new keys of any type with CKA_EXTRACTABLE=true get * CKA_IBM_PROTKEY_EXTRACTABLE=true and a protected key is automatically * created at first use of the key. */ switch (class) { case CKO_PUBLIC_KEY: if (template_attribute_get_non_empty(tmpl, CKA_EC_PARAMS, &ecp_attr) == CKR_OK && pkey_op_supported_by_cpacf(ep11_data->msa_level, &mech, tmpl)) add_pkey_extractable = CK_TRUE; /* Note that the explicit parm CKM_ECDSA just tells the * function that it's not AES here. It covers all EC and ED * mechs */ break; default: ret = template_attribute_get_bool(tmpl, CKA_EXTRACTABLE, &extractable); if (ret == CKR_OK && extractable) add_pkey_extractable = CK_TRUE; break; } break; case PKEY_MODE_ENABLE4ALL: /* If the application did not specify CKA_IBM_PROTKEY_EXTRACTABLE in * its template, new keys of any type, regardless of CKA_EXTRACTABLE, * get CKA_IBM_PROTKEY_EXTRACTABLE=true and a protected key is * automatically created at first use of the key. */ switch (class) { case CKO_PUBLIC_KEY: if (template_attribute_get_non_empty(tmpl, CKA_EC_PARAMS, &ecp_attr) == CKR_OK && pkey_op_supported_by_cpacf(ep11_data->msa_level, &mech, tmpl)) add_pkey_extractable = CK_TRUE; /* Note that the explicit parm CKM_ECDSA just tells the * function that it's not AES here. It covers all EC and ED * mechs */ break; default: add_pkey_extractable = CK_TRUE; break; } break; default: TRACE_ERROR("PKEY_MODE %i unsupported.\n", ep11_data->pkey_mode); ret = CKR_FUNCTION_FAILED; goto done; break; } if (add_pkey_extractable) { ret = ep11tok_pkey_add_protkey_attr_to_tmpl(tmpl); if (ret != CKR_OK) goto done; } #endif /* NO_PKEY */ ret = CKR_OK; done: return ret; } #ifdef NO_PKEY CK_RV ep11tok_pkey_usage_ok(STDLL_TokData_t *tokdata, SESSION *session, CK_OBJECT_HANDLE hkey, CK_MECHANISM *mech) { UNUSED(tokdata); UNUSED(session); UNUSED(hkey); UNUSED(mech); return CKR_FUNCTION_NOT_SUPPORTED; } #endif /* NO_PKEY */ static CK_RV check_ab_supported(CK_KEY_TYPE type) { switch(type) { case CKK_AES: case CKK_DES2: case CKK_DES3: case CKK_GENERIC_SECRET: case CKK_RSA: case CKK_EC: case CKK_DSA: case CKK_DH: return CKR_OK; default: TRACE_ERROR("%s key type not supported for ab: 0x%lx\n", __func__, type); return CKR_TEMPLATE_INCONSISTENT; } } static CK_RV check_ab_pair(CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount, CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount) { CK_RV rc; CK_BBOOL abpub = FALSE, abpriv = FALSE; rc = get_bool_attribute_by_type(pPublicKeyTemplate, ulPublicKeyAttributeCount, CKA_IBM_ATTRBOUND, &abpub); if (rc != CKR_OK && rc != CKR_TEMPLATE_INCOMPLETE) { TRACE_ERROR("Failed to retrieve CKA_IBM_ATTRBOUND attribute from public template. rc=0x%lx\n", rc); return rc; } rc = get_bool_attribute_by_type(pPrivateKeyTemplate, ulPrivateKeyAttributeCount, CKA_IBM_ATTRBOUND, &abpriv); if (rc != CKR_OK && rc != CKR_TEMPLATE_INCOMPLETE) { TRACE_ERROR("Failed to retrieve CKA_IBM_ATTRBOUND attribute from private template. rc=0x%lx\n", rc); return rc; } if (abpub != abpriv) { TRACE_ERROR("Only one of the key pair is attribute bound.\n"); return CKR_TEMPLATE_INCONSISTENT; } return CKR_OK; } static CK_RV check_ab_kek_type(TEMPLATE *tmpl, CK_RV errval) { CK_KEY_TYPE kektype; CK_OBJECT_CLASS class; CK_RV rc; rc = template_attribute_get_ulong(tmpl, CKA_KEY_TYPE, &kektype); if (rc != CKR_OK) { TRACE_ERROR("Invalid key type attribute\n"); return rc; } rc = template_attribute_get_ulong(tmpl, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("Invalid object class attribute\n"); return rc; } if (kektype != CKK_RSA && class != CKO_SECRET_KEY) { TRACE_ERROR("KEK key type %ld not supported for AB wrap/unwrap\n", kektype); return errval; } return rc; } static CK_RV check_ab_attributes(CK_ATTRIBUTE *attrs, CK_ULONG attrs_len, CK_OBJECT_CLASS kc) { CK_RV rc; CK_BBOOL attrbound = FALSE, sensitive = FALSE; if (kc != CKO_PUBLIC_KEY) { rc = get_bool_attribute_by_type(attrs, attrs_len, CKA_IBM_ATTRBOUND, &attrbound); if (rc != CKR_OK && rc != CKR_TEMPLATE_INCOMPLETE) return rc; rc = get_bool_attribute_by_type(attrs, attrs_len, CKA_SENSITIVE, &sensitive); if (rc != CKR_OK && rc != CKR_TEMPLATE_INCOMPLETE) return rc; if (attrbound && !sensitive) { TRACE_ERROR("Attribute bound key not sensitive!"); return CKR_TEMPLATE_INCONSISTENT; } } return CKR_OK; } static CK_RV check_ab_wrap(STDLL_TokData_t * tokdata, CK_BYTE **sblob, size_t *sblob_len, OBJECT **sobj, OBJECT *key_obj, OBJECT *wrap_key_obj, CK_MECHANISM_PTR mech, SESSION *sess) { CK_RV rc; CK_BBOOL abkey, abwrapkey, absignkey, signsignkey; *sobj = 0; *sblob = 0; *sblob_len = ~0; rc = template_attribute_get_bool(key_obj->template, CKA_IBM_ATTRBOUND, &abkey); if (rc == CKR_TEMPLATE_INCOMPLETE) { abkey = FALSE; rc = CKR_OK; } else if (rc != CKR_OK) { TRACE_ERROR("Invalid CKA_IBM_ATTRBOUND attribute on key to wrap\n"); return rc; } rc = template_attribute_get_bool(wrap_key_obj->template, CKA_IBM_ATTRBOUND, &abwrapkey); if (rc == CKR_TEMPLATE_INCOMPLETE) { abwrapkey = FALSE; rc = CKR_OK; } else if (rc != CKR_OK) { TRACE_ERROR("Invalid CKA_IBM_ATTRBOUND attribute on wrapping key\n"); return rc; } if (abwrapkey) { if (!abkey) { TRACE_ERROR("Wrapping key is AB, but target key not\n"); return CKR_KEY_NOT_WRAPPABLE; } /* Here, only AB wrapping can be used. Check mechanism and parameters. */ if (mech->mechanism != CKM_IBM_ATTRIBUTEBOUND_WRAP){ TRACE_ERROR("AB key wrapping attempt without CKM_IBM_ATTRIBUTEBOUND_WRAP"); return CKR_MECHANISM_INVALID; } if (sizeof(CK_IBM_ATTRIBUTEBOUND_WRAP_PARAMS) != mech->ulParameterLen) { TRACE_ERROR("AB key wrapping attempt with invalid mechanism parameter"); return CKR_MECHANISM_PARAM_INVALID; } rc = check_ab_kek_type(wrap_key_obj->template, CKR_WRAPPING_KEY_TYPE_INCONSISTENT); if (rc != CKR_OK) return rc; rc = h_opaque_2_blob(tokdata, ((CK_IBM_ATTRIBUTEBOUND_WRAP_PARAMS *)mech->pParameter)->hSignVerifyKey, sblob, sblob_len, sobj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to get sign key for AB wrapping\n"); return rc; } rc = tokdata->policy->is_key_allowed(tokdata->policy, &(*sobj)->strength, sess); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: AB wrap signing key too weak\n"); goto out; } rc = template_attribute_get_bool((*sobj)->template, CKA_IBM_ATTRBOUND, &absignkey); if (rc != CKR_OK || !absignkey) { TRACE_ERROR("AB-Wrap: sign key not AB\n"); rc = CKR_KEY_FUNCTION_NOT_PERMITTED; goto out; } rc = template_attribute_get_bool((*sobj)->template, CKA_SIGN, &signsignkey); if (rc != CKR_OK || !signsignkey) { TRACE_ERROR("AB-Wrap: sign key not able to sign\n"); rc = CKR_KEY_FUNCTION_NOT_PERMITTED; goto out; } } else if (abkey) { TRACE_ERROR("Target key is AB, but wrapping key is not\n"); return CKR_KEY_FUNCTION_NOT_PERMITTED; } out: if (rc != CKR_OK && *sobj) { object_put(tokdata, *sobj, TRUE); *sobj = 0; *sblob = 0; *sblob_len = ~0; } return rc; } static CK_RV check_ab_unwrap(STDLL_TokData_t * tokdata, CK_BYTE **vblob, size_t *vblob_len, OBJECT **vobj, OBJECT *unwrap_key_obj, CK_ATTRIBUTE_PTR attrs, CK_ULONG attrs_len, CK_MECHANISM_PTR mech, CK_BBOOL *isab, SESSION *sess) { CK_RV rc; CK_BBOOL abkey, abunwrapkey, abverifykey, verifyverifykey; *vobj = 0; *vblob = 0; *vblob_len = ~0; *isab = FALSE; rc = template_attribute_get_bool(unwrap_key_obj->template, CKA_IBM_ATTRBOUND, &abunwrapkey); if (rc == CKR_TEMPLATE_INCOMPLETE) { abunwrapkey = FALSE; rc = CKR_OK; } else if (rc != CKR_OK) { return rc; } rc = get_bool_attribute_by_type(attrs, attrs_len, CKA_IBM_ATTRBOUND, &abkey); if (rc == CKR_TEMPLATE_INCOMPLETE) { abkey = FALSE; rc = CKR_OK; } else if (rc != CKR_OK) { return rc; } if (mech->mechanism == CKM_IBM_ATTRIBUTEBOUND_WRAP) { *isab = TRUE; if (mech->ulParameterLen != sizeof(CK_IBM_ATTRIBUTEBOUND_WRAP_PARAMS)) { TRACE_ERROR("Unwrapping AB key with invalid mechanism\n"); return CKR_MECHANISM_PARAM_INVALID; } if (!abkey) { TRACE_ERROR("CKM_IBM_ATTRIBUTEBOUND_WRAP with non-AB target\n"); return CKR_MECHANISM_INVALID; } if (!abunwrapkey) { TRACE_ERROR("CKM_IBM_ATTRIBUTEBOUND_WRAP with non-AB unwrap key\n"); return CKR_KEY_FUNCTION_NOT_PERMITTED; } /* extract verification key */ rc = h_opaque_2_blob(tokdata, ((CK_IBM_ATTRIBUTEBOUND_WRAP_PARAMS *)mech->pParameter)->hSignVerifyKey, vblob, vblob_len, vobj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to get verification key for AB wrapping\n"); return rc; } rc = tokdata->policy->is_key_allowed(tokdata->policy, &(*vobj)->strength, sess); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: AB verification key too weak\n"); goto out; } rc = template_attribute_get_bool((*vobj)->template, CKA_IBM_ATTRBOUND, &abverifykey); if (rc != CKR_OK || !abverifykey) { TRACE_ERROR("AB-Wrap: verification key not AB\n"); rc = CKR_KEY_FUNCTION_NOT_PERMITTED; goto out; } rc = template_attribute_get_bool((*vobj)->template, CKA_VERIFY, &verifyverifykey); if (rc != CKR_OK || !verifyverifykey) { TRACE_ERROR("AB-Unwrap: verification key not able to verify\n"); rc = CKR_KEY_FUNCTION_NOT_PERMITTED; goto out; } } else { if (abkey) { TRACE_ERROR("Unwrapping AB key without CKM_IBM_ATTRIBUTEBOUND_WRAP\n"); return CKR_MECHANISM_INVALID; } if (abunwrapkey) { TRACE_ERROR("Unwrap key AB key without CKM_IBM_ATTRIBUTEBOUND_WRAP\n"); return CKR_MECHANISM_INVALID; } } out: if (rc != CKR_OK && *vobj) { object_put(tokdata, *vobj, TRUE); *vobj = 0; *vblob = 0; *vblob_len = ~0; } return rc; } /* Has to be called either with WRITE_LOCK on @obj, or before the object is * made publicly available via object_mgr_create_final. Since this function * updates the attributes of the object, we would get race conditions * otherwise. */ static CK_RV ab_unwrap_update_template(STDLL_TokData_t * tokdata, SESSION * session, CK_BYTE *blob, size_t blob_len, OBJECT *obj, CK_KEY_TYPE keytype, CK_OBJECT_CLASS class) { CK_RV rc; CK_BBOOL trusted, encrypt, decrypt, wrap, unwrap, sign, sign_recover, verify, verify_recover, derive, extractable, local, never_extractable, modifiable, wrap_with_trusted; CK_ULONG valuelen; CK_KEY_TYPE template_keytype; CK_ATTRIBUTE attrs[] = { {CKA_TRUSTED, &trusted, sizeof(trusted)}, {CKA_ENCRYPT, &encrypt, sizeof(encrypt)}, {CKA_DECRYPT, &decrypt, sizeof(decrypt)}, {CKA_WRAP, &wrap, sizeof(wrap)}, {CKA_UNWRAP, &unwrap, sizeof(unwrap)}, {CKA_SIGN, &sign, sizeof(sign)}, {CKA_SIGN_RECOVER, &sign_recover, sizeof(sign_recover)}, {CKA_VERIFY, &verify, sizeof(verify)}, {CKA_VERIFY_RECOVER, &verify_recover, sizeof(verify_recover)}, {CKA_DERIVE, &derive, sizeof(derive)}, {CKA_EXTRACTABLE, &extractable, sizeof(extractable)}, {CKA_LOCAL, &local, sizeof(local)}, {CKA_NEVER_EXTRACTABLE, &never_extractable, sizeof(extractable)}, {CKA_MODIFIABLE, &modifiable, sizeof(modifiable)}, {CKA_WRAP_WITH_TRUSTED, &wrap_with_trusted, sizeof(wrap_with_trusted)}, {CKA_KEY_TYPE, &template_keytype, sizeof(template_keytype)}, {CKA_VALUE_LEN, &valuelen, sizeof(valuelen)}, }; CK_ULONG num_attrs = sizeof(attrs) / sizeof(CK_ATTRIBUTE); CK_ULONG i; CK_ATTRIBUTE *attr; CK_BBOOL cktrue = TRUE; CK_BYTE *useblob = NULL; size_t useblob_len = 0; switch (keytype) { case CKK_GENERIC_SECRET: case CKK_AES: break; default: num_attrs -= 1; /* No CKA_VALUE_LEN attribute */ break; } RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_BLOB_START(tokdata, target_info, obj, blob, blob_len, useblob, useblob_len, rc) rc = dll_m_GetAttributeValue(useblob, useblob_len, attrs, num_attrs, target_info->target); RETRY_REENC_BLOB_END(tokdata, target_info, useblob, useblob_len, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { TRACE_ERROR("Retrieving attributes from AB unwrapped key failed, rc=0x%lx\n", rc); return rc; } if (template_keytype != keytype) { TRACE_ERROR("Template specifies different key type than the AB key (0x%08lx vs 0x%08lx)\n", template_keytype, keytype); return CKR_TEMPLATE_INCONSISTENT; } for (i = 0; i < sizeof(attrs) / sizeof(CK_ATTRIBUTE); ++i) { if (attrs[i].type == CKA_VALUE_LEN) { switch (keytype) { case CKK_GENERIC_SECRET: case CKK_AES: break; default: continue; } } rc = build_attribute(attrs[i].type, attrs[i].pValue, attrs[i].ulValueLen, &attr); if (rc != CKR_OK) { TRACE_ERROR("failed to build attribute (rc=0x%lx)\n", rc); return rc; } rc = template_update_attribute(obj->template, attr); if (rc != CKR_OK) { free(attr); attr = NULL; TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n", __func__, rc); return rc; } } /* force sensitive */ rc = build_attribute(CKA_SENSITIVE, &cktrue, sizeof(CK_BBOOL), &attr); if (rc != CKR_OK) { TRACE_ERROR("failed to build attribute (rc=0x%lx)\n", rc); return rc; } rc = template_update_attribute(obj->template, attr); if (rc != CKR_OK) { free(attr); attr = NULL; TRACE_ERROR("%s failed to force template sensitive; rc=0x%08lx\n", __func__, rc); return rc; } /* Set CKA_ENCAPSULATE/CKA_DECAPSULATE according to combined attrs */ rc = ep11tok_endecaps_combine_attrs_import(obj->template, keytype, class, TRUE, wrap, unwrap, derive); if (rc != CKR_OK) { TRACE_ERROR("ep11tok_endecaps_combine_attrs_import failed\n"); return rc; } return rc; } static CK_RV force_ab_sensitive(CK_ATTRIBUTE_PTR *p_attrs, CK_ULONG *p_attrs_len, CK_KEY_TYPE type) { CK_RV rc; CK_BBOOL cktrue = TRUE, abvalue, sensitive; rc = get_bool_attribute_by_type(*p_attrs, *p_attrs_len, CKA_IBM_ATTRBOUND, &abvalue); if (rc == CKR_OK && abvalue) { rc = check_ab_supported(type); if (rc != CKR_OK) return rc; /* An AB key => make sure it is sensitive */ rc = get_bool_attribute_by_type(*p_attrs, *p_attrs_len, CKA_SENSITIVE, &sensitive); if (rc == CKR_OK) { if (!sensitive) { /* Template specifies CKA_SENSITIVE == CKA_FALSE so is * inconsistent for AB keys */ rc = CKR_TEMPLATE_INCONSISTENT; } } else if (rc == CKR_TEMPLATE_INCOMPLETE) { /* CKA_SENSITIVE not in template */ rc = add_to_attribute_array(p_attrs, p_attrs_len, CKA_SENSITIVE, &cktrue, sizeof(cktrue)); } } else if (rc == CKR_TEMPLATE_INCOMPLETE) { /* Not an AB key */ rc = CKR_OK; } return rc; } static CK_RV check_ab_derive_attributes(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_ATTRIBUTE_PTR *attrs, CK_ULONG *attrs_len) { CK_BBOOL abgoal, abbase; CK_RV rc; rc = template_attribute_get_bool(tmpl, CKA_IBM_ATTRBOUND, &abbase); if (rc == CKR_TEMPLATE_INCOMPLETE) { abbase = FALSE; rc = CKR_OK; } else if (rc != CKR_OK) { TRACE_ERROR("Invalid CKA_IBM_ATTRBOUND attribute on base key (rc=0x%lx)\n", rc); return rc; } if (abbase && check_required_versions(tokdata, ibm_ab_ecdh_req_versions, NUM_AB_ECDH_REQ) < 1) return CKR_MECHANISM_INVALID; rc = get_bool_attribute_by_type(*attrs, *attrs_len, CKA_IBM_ATTRBOUND, &abgoal); if (rc == CKR_OK && abgoal) { /* We want to derive an AB key */ if (!abbase) { TRACE_ERROR("Attempt to derive AB key from non-AB key\n"); rc = CKR_TEMPLATE_INCONSISTENT; } } else if (rc == CKR_TEMPLATE_INCOMPLETE) { rc = CKR_OK; /* AB setting defaulted => if AB base key, derive AB key */ if (abbase) { rc = add_to_attribute_array(attrs, attrs_len, CKA_IBM_ATTRBOUND, (CK_BYTE *) &abbase, sizeof(abbase)); } } return rc; } 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, int curve_type) { 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 }; CK_ULONG check_types_gen_sec_sensitive[] = { CKA_SIGN, CKA_VERIFY, 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: switch (kt) { case CKK_GENERIC_SECRET: case CKK_SHA_1_HMAC: case CKK_SHA224_HMAC: case CKK_SHA256_HMAC: case CKK_SHA384_HMAC: case CKK_SHA512_HMAC: case CKK_SHA3_224_HMAC: case CKK_SHA3_256_HMAC: case CKK_SHA3_384_HMAC: case CKK_SHA3_512_HMAC: case CKK_SHA512_224_HMAC: case CKK_SHA512_256_HMAC: 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); } break; default: 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; } 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 */ if (kt == CKK_EC && curve_type == MONTGOMERY_CURVE) attr_cnt = 0; } 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, CKK_IBM_PQC_DILITHIUM, CKK_IBM_PQC_KYBER, CKK_IBM_ML_DSA, CKK_IBM_ML_KEM, CKK_ML_DSA, and CKK_ML_KEM */ 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 */ if (kt == CKK_EC && curve_type == MONTGOMERY_CURVE) attr_cnt = 0; } 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, CKK_IBM_PQC_KYBER and * CKK_IBM_ML_DSA, CKK_IBM_ML_KEM, CKK_ML_DSA, and CKK_ML_KEM */ 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 check_ab_attributes(*p_attrs, *p_attrs_len, kc); cleanup: if (rc) { free_attribute_array(*p_attrs, *p_attrs_len); *p_attrs = NULL; *p_attrs_len = 0; } return rc; } static CK_RV check_key_restriction(OBJECT *key_obj, CK_ATTRIBUTE_TYPE type) { CK_RV rc; CK_BBOOL flag; rc = template_attribute_get_bool(key_obj->template, type, &flag); if (rc == CKR_ATTRIBUTE_VALUE_INVALID) return rc; if (rc != CKR_OK) { TRACE_ERROR("Could not find attribute 0x%lx for the key.\n", type); return CKR_KEY_FUNCTION_NOT_PERMITTED; } if (flag != TRUE) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_FUNCTION_NOT_PERMITTED)); return CKR_KEY_FUNCTION_NOT_PERMITTED; } return CKR_OK; } #define UNKNOWN_MECHANISM 0xFFFFFFFF /* for logging, debugging */ static const char *ep11_get_ckm(STDLL_TokData_t *tokdata, CK_ULONG mechanism) { const struct mechrow *row; switch (mechanism) { case CKM_IBM_CPACF_WRAP: /* * CKM_IBM_CPACF_WRAP is only supported/known inside the EP11 token * code, but not externally, thus it is not in the mechtable. */ return "CKM_IBM_CPACF_WRAP"; default: break; } row = tokdata->mechtable_funcs->p_row_from_num(mechanism); if (row) return row->string; TRACE_WARNING("%s unknown mechanism %lx\n", __func__, mechanism); return "UNKNOWN"; } static CK_ULONG ep11_get_mechanisms_by_name(STDLL_TokData_t *tokdata, const char *name) { const struct mechrow *row; row = tokdata->mechtable_funcs->p_row_from_str(name); if (row) return row->numeric; TRACE_WARNING("%s unknown mechanism name '%s'\n", __func__, name); return UNKNOWN_MECHANISM; } static CK_RV read_adapter_config_file(STDLL_TokData_t * tokdata, const char *conf_name); static CK_RV read_cp_filter_config_file(STDLL_TokData_t *tokdata, const char *conf_name, cp_config_t ** cp_config); 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; } } /** * This function covers some specific restrictions of the ep11 hostlib, i.e. * passing these attrs to the ep11 hostlib would cause an error. */ static CK_BBOOL attr_applicable_for_ep11(STDLL_TokData_t * tokdata, CK_ATTRIBUTE *attr, CK_KEY_TYPE ktype, CK_OBJECT_CLASS class, int curve_type, CK_MECHANISM_PTR mech) { ep11_private_data_t *ep11_data = tokdata->private_data; /* On older cards, CKA_IBM_PROTKEY_EXTRACTABLE might cause errors, so filter * it out when the CPACF_WRAP mechanism is not supported on this system */ if (attr->type == CKA_IBM_PROTKEY_EXTRACTABLE && ep11_data->pkey_wrap_supported == 0) return CK_FALSE; /* EP11 does not support sign/verify recover */ if (attr->type == CKA_SIGN_RECOVER || attr->type == CKA_VERIFY_RECOVER) return CK_FALSE; /* EP11 does not support encapsulate/decapsulate recover */ if (attr->type == CKA_ENCAPSULATE || attr->type == CKA_DECAPSULATE) return CK_FALSE; switch (ktype) { case CKK_RSA: if (class == CKO_PRIVATE_KEY && attr->type == CKA_PUBLIC_EXPONENT) return CK_FALSE; if (attr->type == CKA_DERIVE) return CK_FALSE; break; case CKK_EC: if (class == CKO_PRIVATE_KEY && attr->type == CKA_EC_PARAMS && mech->mechanism != CKM_IBM_BTC_DERIVE) return CK_FALSE; if (attr->type == CKA_ENCRYPT || attr->type == CKA_DECRYPT || attr->type == CKA_WRAP || attr->type == CKA_UNWRAP) return CK_FALSE; /* Montgomery curves cannot be used for sign/verify */ if (class == CKO_PRIVATE_KEY && curve_type == MONTGOMERY_CURVE && attr->type == CKA_SIGN) return CK_FALSE; if (class == CKO_PUBLIC_KEY && curve_type == MONTGOMERY_CURVE && attr->type == CKA_VERIFY) return CK_FALSE; /* Edwards curves cannot be used for derive (except for CKM_IBM_BTC_DERIVE) */ if (curve_type == EDWARDS_CURVE && attr->type == CKA_DERIVE && mech->mechanism != CKM_IBM_BTC_DERIVE) return CK_FALSE; break; case CKK_DSA: if (attr->type == CKA_ENCRYPT || attr->type == CKA_DECRYPT || attr->type == CKA_WRAP || attr->type == CKA_UNWRAP || attr->type == CKA_DERIVE) return CK_FALSE; if (attr->type == CKA_PRIME || attr->type == CKA_SUBPRIME || attr->type == CKA_BASE) return CK_FALSE; break; case CKK_DH: if (attr->type == CKA_ENCRYPT || attr->type == CKA_DECRYPT || attr->type == CKA_WRAP || attr->type == CKA_UNWRAP || attr->type == CKA_SIGN || attr->type == CKA_VERIFY) return CK_FALSE; if (attr->type == CKA_BASE || attr->type == CKA_PRIME) return CK_FALSE; break; case CKK_IBM_PQC_DILITHIUM: if (attr->type == CKA_ENCRYPT || attr->type == CKA_DECRYPT || attr->type == CKA_WRAP || attr->type == CKA_UNWRAP || attr->type == CKA_DERIVE || attr->type == CKA_IBM_DILITHIUM_KEYFORM || attr->type == CKA_IBM_DILITHIUM_MODE) return CK_FALSE; break; case CKK_IBM_PQC_KYBER: if (attr->type == CKA_SIGN || attr->type == CKA_VERIFY || attr->type == CKA_WRAP || attr->type == CKA_UNWRAP || attr->type == CKA_IBM_KYBER_KEYFORM || attr->type == CKA_IBM_KYBER_MODE) return CK_FALSE; break; case CKK_IBM_ML_DSA: /* CKA_IBM_PARAMETER_SET will be added later */ if (attr->type == CKA_ENCRYPT || attr->type == CKA_DECRYPT || attr->type == CKA_WRAP || attr->type == CKA_UNWRAP || attr->type == CKA_DERIVE || attr->type == CKA_IBM_PARAMETER_SET) return CK_FALSE; break; case CKK_IBM_ML_KEM: /* CKA_IBM_PARAMETER_SET will be added later */ if (attr->type == CKA_SIGN || attr->type == CKA_VERIFY || attr->type == CKA_WRAP || attr->type == CKA_UNWRAP || attr->type == CKA_ENCRYPT || attr->type == CKA_DECRYPT || attr->type == CKA_IBM_PARAMETER_SET) return CK_FALSE; break; case CKK_ML_DSA: /* CKA_PARAMETER_SET will be added later */ if (attr->type == CKA_ENCRYPT || attr->type == CKA_DECRYPT || attr->type == CKA_WRAP || attr->type == CKA_UNWRAP || attr->type == CKA_DERIVE || attr->type == CKA_PARAMETER_SET) return CK_FALSE; break; case CKK_ML_KEM: /* CKA_PARAMETER_SET will be added later */ if (attr->type == CKA_SIGN || attr->type == CKA_VERIFY || attr->type == CKA_WRAP || attr->type == CKA_UNWRAP || attr->type == CKA_ENCRYPT || attr->type == CKA_DECRYPT || attr->type == CKA_PARAMETER_SET) return CK_FALSE; break; default: break; } return CK_TRUE; } struct endecap_combine_attrs_data { CK_BBOOL wrap_found; CK_BBOOL wrap; CK_BBOOL unwrap_found; CK_BBOOL unwrap; CK_BBOOL derive_found; CK_BBOOL derive; CK_BBOOL encaps_found; CK_BBOOL encaps; CK_BBOOL decaps_found; CK_BBOOL decaps; }; static CK_RV ep11tok_endecaps_combine_attrs_collect( CK_ATTRIBUTE *attr, struct endecap_combine_attrs_data* data) { switch (attr->type) { case CKA_WRAP: if (attr->ulValueLen != sizeof(CK_BBOOL) || attr->pValue == NULL) return CKR_ATTRIBUTE_VALUE_INVALID; /* Remember value for later, but do not add now */ data->wrap = *(CK_BBOOL *)attr->pValue; data->wrap_found = CK_TRUE; return CKR_OK; case CKA_UNWRAP: if (attr->ulValueLen != sizeof(CK_BBOOL) || attr->pValue == NULL) return CKR_ATTRIBUTE_VALUE_INVALID; /* Remember value for later, but do not add now */ data->unwrap = *(CK_BBOOL *)attr->pValue; data->unwrap_found = CK_TRUE; return CKR_OK; case CKA_DERIVE: if (attr->ulValueLen != sizeof(CK_BBOOL) || attr->pValue == NULL) return CKR_ATTRIBUTE_VALUE_INVALID; /* Remember value for later, but do not add now */ data->derive = *(CK_BBOOL *)attr->pValue; data->derive_found = CK_TRUE; return CKR_OK; case CKA_ENCAPSULATE: if (attr->ulValueLen != sizeof(CK_BBOOL) || attr->pValue == NULL) return CKR_ATTRIBUTE_VALUE_INVALID; /* Remember value for later, but do not add now */ data->encaps = *(CK_BBOOL *)attr->pValue; data->encaps_found = CK_TRUE; return CKR_OK; case CKA_DECAPSULATE: if (attr->ulValueLen != sizeof(CK_BBOOL) || attr->pValue == NULL) return CKR_ATTRIBUTE_VALUE_INVALID; /* Remember value for later, but do not add now */ data->decaps = *(CK_BBOOL *)attr->pValue; data->decaps_found = CK_TRUE; return CKR_OK; } return CKR_ATTRIBUTE_TYPE_INVALID; } static CK_RV ep11tok_endecaps_combine_attrs_apply( STDLL_TokData_t *tokdata, CK_OBJECT_CLASS class, CK_KEY_TYPE keytype, int curve_type, CK_MECHANISM *mech, CK_ATTRIBUTE **p_attrs, CK_ULONG *p_attrs_len, struct endecap_combine_attrs_data* data) { CK_ATTRIBUTE wrap_attr = { CKA_WRAP, &data->wrap, sizeof(CK_BBOOL) }; CK_ATTRIBUTE unwrap_attr = { CKA_UNWRAP, &data->unwrap, sizeof(CK_BBOOL) }; CK_ATTRIBUTE derive_attr = { CKA_DERIVE, &data->derive, sizeof(CK_BBOOL) }; CK_RV rc; switch (keytype) { case CKK_RSA: /* RSA: Combine Encaps and Wrap, Decaps and Unwrap */ if (data->encaps_found && class == CKO_PUBLIC_KEY) { TRACE_DEVEL("%s RSA pub key: CKA_WRAP (%d) = CKA_WRAP (%d) OR " "CKA_ENCAPSULATE (%d)\n", __func__, data->wrap | data->encaps, data->wrap, data->encaps); data->wrap |= data->encaps; data->wrap_found = CK_TRUE; } if (data->decaps_found && class == CKO_PRIVATE_KEY) { TRACE_DEVEL("%s RSA prv key: CKA_UNWRAP (%d) = CKA_UNWRAP (%d) OR " "CKA_DECAPSULATE (%d)\n", __func__, data->unwrap | data->decaps, data->unwrap, data->decaps); data->unwrap |= data->decaps; data->unwrap_found = CK_TRUE; } break; case CKK_EC: case CKK_EC_MONTGOMERY: case CKK_DH: case CKK_ML_KEM: /* EC/DH/ML-KEM: Combine Encaps and Derive, Decaps and Derive */ if (data->encaps_found && class == CKO_PUBLIC_KEY) { TRACE_DEVEL("%s EC/DH/ML-KEM pub key: CKA_DERIVE (%d) = CKA_DERIVE " "(%d) OR CKA_ENCAPSULATE (%d)\n", __func__, data->derive | data->encaps, data->derive, data->encaps); data->derive |= data->encaps; data->derive_found = CK_TRUE; } if (data->decaps_found && class == CKO_PRIVATE_KEY) { TRACE_DEVEL("%s EC/DH/ML-KEM prv key: CKA_DERIVE (%d) = CKA_DERIVE " "(%d) OR CKA_DECAPSULATE (%d)\n", __func__, data->derive | data->decaps, data->derive, data->decaps); data->derive |= data->decaps; data->derive_found = CK_TRUE; } break; } if (data->wrap_found && attr_applicable_for_ep11(tokdata, &wrap_attr, keytype, class, curve_type, mech)) { rc = add_to_attribute_array(p_attrs, p_attrs_len, CKA_WRAP, &data->wrap, sizeof(CK_BBOOL)); if (rc != CKR_OK) { TRACE_ERROR("Adding attribute failed (CKA_WRAP) rc=0x%lx\n", rc); return rc; } } if (data->unwrap_found && attr_applicable_for_ep11(tokdata, &unwrap_attr, keytype, class, curve_type, mech)) { rc = add_to_attribute_array(p_attrs, p_attrs_len, CKA_UNWRAP, &data->unwrap, sizeof(CK_BBOOL)); if (rc != CKR_OK) { TRACE_ERROR("Adding attribute failed (CKA_UNWRAP) rc=0x%lx\n", rc); return rc; } } if (data->derive_found && attr_applicable_for_ep11(tokdata, &derive_attr, keytype, class, curve_type, mech)) { rc = add_to_attribute_array(p_attrs, p_attrs_len, CKA_DERIVE, &data->derive, sizeof(CK_BBOOL)); if (rc != CKR_OK) { TRACE_ERROR("Adding attribute failed (CKA_DERIVE) rc=0x%lx\n", rc); return rc; } } return CKR_OK; } /* * Build an array of attributes to be passed to EP11. Some attributes are * handled 'read-only' by EP11, and would cause an error if passed to EP11. */ static CK_RV build_ep11_attrs(STDLL_TokData_t * tokdata, TEMPLATE *template, CK_ATTRIBUTE_PTR *p_attrs, CK_ULONG_PTR p_attrs_len, CK_KEY_TYPE ktype, CK_OBJECT_CLASS class, int curve_type, CK_MECHANISM_PTR mech) { DL_NODE *node; CK_ATTRIBUTE_PTR attr; CK_RV rc; CK_ULONG value_len = 0; CK_KEY_TYPE key_type; struct endecap_combine_attrs_data combine_attr_data = { 0 }; node = template->attribute_list; while (node != NULL) { attr = node->data; rc = ep11tok_endecaps_combine_attrs_collect(attr, &combine_attr_data); if (rc == CKR_OK) goto next; /* EP11 handles this as 'read only' and reports an error if specified */ switch (attr->type) { case CKA_NEVER_EXTRACTABLE: case CKA_IBM_PROTKEY_NEVER_EXTRACTABLE: case CKA_LOCAL: break; case CKA_KEY_TYPE: if (attr->ulValueLen != sizeof(CK_KEY_TYPE) || attr->pValue == NULL) return CKR_ATTRIBUTE_VALUE_INVALID; key_type = *(CK_KEY_TYPE *)attr->pValue; ep11tok_pkcs11_keytype_translate(tokdata, key_type, &key_type); if (key_type == CKK_AES_XTS && ktype == CKK_AES) key_type = CKK_AES; rc = add_to_attribute_array(p_attrs, p_attrs_len, attr->type, (CK_BYTE *)&key_type, sizeof(key_type)); if (rc != CKR_OK) { TRACE_ERROR("Adding attribute failed type=0x%lx rc=0x%lx\n", attr->type, rc); return rc; } break; case CKA_VALUE_LEN: if (attr->ulValueLen != sizeof(CK_ULONG) || attr->pValue == NULL) return CKR_ATTRIBUTE_VALUE_INVALID; value_len = *(CK_ULONG *)attr->pValue; if (ktype == CKK_AES_XTS) value_len /= 2; rc = add_to_attribute_array(p_attrs, p_attrs_len, attr->type, (CK_BYTE *)&value_len, sizeof(value_len)); if (rc != CKR_OK) { TRACE_ERROR("Adding attribute failed type=0x%lx rc=0x%lx\n", attr->type, rc); return rc; } break; /* EP11 does not like empty (zero length) attributes of that types */ case CKA_PUBLIC_KEY_INFO: if (attr->ulValueLen == 0) break; /* Fallthrough */ default: if (attr->ulValueLen > 0 && attr->pValue == NULL) return CKR_ATTRIBUTE_VALUE_INVALID; if (attr_applicable_for_ep11(tokdata, attr, ktype, class, curve_type, mech)) { rc = add_to_attribute_array(p_attrs, p_attrs_len, attr->type, attr->pValue, attr->ulValueLen); if (rc != CKR_OK) { TRACE_ERROR("Adding attribute failed type=0x%lx rc=0x%lx\n", attr->type, rc); return rc; } } } next: node = node->next; } rc = ep11tok_endecaps_combine_attrs_apply(tokdata, class, ktype, curve_type, mech, p_attrs, p_attrs_len, &combine_attr_data); if (rc != CKR_OK) { TRACE_ERROR("ep11tok_endecaps_combine_attrs_apply failed: 0x%lx\n", rc); return rc; } return CKR_OK; } /* 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, unsigned char *blobreenc, 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 }; 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; CK_ATTRIBUTE *chk_attr = NULL; unsigned char *ep11_pin_blob = NULL; CK_ULONG ep11_pin_blob_len = 0; ep11_session_t *ep11_session = (ep11_session_t *) sess->private_data; CK_BYTE *wrap_blob; /* tell ep11 the attributes the user specified */ rc = build_ep11_attrs(tokdata, key_obj->template, &p_attrs, &attrs_len, ktype, CKO_SECRET_KEY, -1, &mech); if (rc != CKR_OK) goto rawkey_2_blob_end; 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_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_WRAPBLOB_START(tokdata, target_info, wrap_blob) rc = dll_m_EncryptSingle(wrap_blob, ep11_data->raw2key_wrap_blob_l, &mech, key, ksize, cipher, &clen, target_info->target); RETRY_REENC_WRAPBLOB_END(tokdata, target_info, wrap_blob, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, sess) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, sess); 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, -1); if (rc != CKR_OK) { TRACE_ERROR("%s RSA/EC check private key attributes failed with " "rc=0x%lx\n", __func__, rc); goto rawkey_2_blob_end; } trace_attributes(__func__, "Import sym.:", new_p_attrs, new_attrs_len); ep11_get_pin_blob(tokdata, ep11_session, object_is_session_object(key_obj), object_is_private(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_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_WRAPBLOB_START(tokdata, target_info, wrap_blob) RETRY_REENC_CREATE_KEY_START() rc = dll_m_UnwrapKey(cipher, clen, wrap_blob, ep11_data->raw2key_wrap_blob_l, NULL, ~0, ep11_pin_blob, ep11_pin_blob_len, &mech, new_p_attrs, new_attrs_len, blob, blen, csum, &cslen, target_info->target); RETRY_REENC_CREATE_KEY_END(tokdata, sess, target_info, blob, blobreenc, *blen, rc) RETRY_REENC_WRAPBLOB_END(tokdata, target_info, wrap_blob, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, sess) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, sess); TRACE_ERROR("%s unwrap blen=%zd rc=0x%lx\n", __func__, *blen, rc); goto rawkey_2_blob_end; } else { TRACE_INFO("%s unwrap blen=%zd rc=0x%lx\n", __func__, *blen, rc); if (cslen >= EP11_CSUMSIZE) { /* First 3 bytes of csum is the check value */ rc = build_attribute(CKA_CHECK_VALUE, csum, EP11_CSUMSIZE, &chk_attr); if (rc != CKR_OK) { TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc); goto rawkey_2_blob_end; } rc = template_update_attribute(key_obj->template, chk_attr); if (rc != CKR_OK) { TRACE_ERROR("%s template_update_attribute failed with " "rc=0x%lx\n", __func__, rc); goto rawkey_2_blob_end; } chk_attr = NULL; } } 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); if (chk_attr != NULL) free(chk_attr); return rc; } /* random number generator */ CK_RV token_specific_rng(STDLL_TokData_t * tokdata, CK_BYTE * output, CK_ULONG bytes) { ep11_target_info_t* target_info; CK_RV rc; target_info = get_target_info(tokdata); if (target_info == NULL) return CKR_FUNCTION_FAILED; RETRY_SINGLE_APQN_START(tokdata, rc) rc = dll_m_GenerateRandom(output, bytes, target_info->target); RETRY_SINGLE_APQN_END(rc, tokdata, target_info) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, NULL); TRACE_ERROR("%s output=%p bytes=%lu rc=0x%lx\n", __func__, (void *)output, bytes, rc); } put_target_info(tokdata, target_info); 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, SESSION *sess) { ep11_private_data_t *ep11_data = tokdata->private_data; ep11_session_t *ep11_session = (ep11_session_t *)sess->private_data; unsigned char *ep11_pin_blob = NULL; CK_ULONG ep11_pin_blob_len = 0; CK_MECHANISM mech = { CKM_AES_KEY_GEN, NULL_PTR, 0 }; CK_BYTE csum[MAX_CSUMSIZE]; size_t csum_l = sizeof(csum); CK_ULONG len = 32; CK_BBOOL cktrue = 1; CK_ATTRIBUTE wrap_tmpl[] = { { CKA_VALUE_LEN, &len, sizeof(CK_ULONG) }, { CKA_WRAP, &cktrue, sizeof(cktrue) }, { CKA_UNWRAP, &cktrue, sizeof(cktrue) }, { CKA_ENCRYPT, &cktrue, sizeof(cktrue) }, { CKA_DECRYPT, &cktrue, sizeof(cktrue) }, { CKA_EXTRACTABLE, &cktrue, sizeof(cktrue) }, }; CK_ULONG wrap_tmpl_len = sizeof(wrap_tmpl) / sizeof(CK_ATTRIBUTE); CK_RV rc = CKR_OK; if (pthread_mutex_lock(&ep11_data->raw2key_wrap_blob_mutex)) { TRACE_ERROR("%s Failed to lock Wrap-Blob lock\n", __func__); return CKR_CANT_LOCK; } 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); goto out_unlock; } trace_attributes(__func__, "Generate wrap blog key:", wrap_tmpl, wrap_tmpl_len); ep11_get_pin_blob(tokdata, ep11_session, FALSE, FALSE, &ep11_pin_blob, &ep11_pin_blob_len); ep11_data->raw2key_wrap_blob_l = sizeof(ep11_data->raw2key_wrap_blob); RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_CREATE_KEY_START() rc = dll_m_GenerateKey(&mech, wrap_tmpl, wrap_tmpl_len, ep11_pin_blob, ep11_pin_blob_len, ep11_data->raw2key_wrap_blob, &ep11_data->raw2key_wrap_blob_l, csum, &csum_l, target_info->target); RETRY_REENC_CREATE_KEY_END(tokdata, NULL, target_info, ep11_data->raw2key_wrap_blob, ep11_data->raw2key_wrap_blob_reenc, ep11_data->raw2key_wrap_blob_l, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, sess) if (rc != CKR_OK) { TRACE_ERROR("%s end raw2key_wrap_blob_l=0x%zx rc=0x%lx\n", __func__, ep11_data->raw2key_wrap_blob_l, rc); goto out; } else { TRACE_INFO("%s end raw2key_wrap_blob_l=0x%zx rc=0x%lx\n", __func__, ep11_data->raw2key_wrap_blob_l, rc); } if (check_expected_mkvp(tokdata, ep11_data->raw2key_wrap_blob, ep11_data->raw2key_wrap_blob_l, NULL) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); rc = CKR_DEVICE_ERROR; } out: 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__); rc = CKR_DEVICE_ERROR; } 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_DEVICE_ERROR; } out_unlock: if (pthread_mutex_unlock(&ep11_data->raw2key_wrap_blob_mutex)) { TRACE_ERROR("%s Failed to unlock Wrap-Blob lock\n", __func__); } if (rc != CKR_OK) ep11_data->raw2key_wrap_blob_l = 0; return rc; } #ifdef EP11_HSMSIM #define DLOPEN_FLAGS RTLD_NOW | RTLD_DEEPBIND #else #define DLOPEN_FLAGS RTLD_NOW #endif static void *ep11_load_host_lib(void) { void *lib_ep11; char *ep11_lib_name; char *errstr; ep11_lib_name = secure_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_V4; 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_V4, EP11SHAREDLIB_V3); /* Try version 3 instead */ 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[.4][.3|.2|.1]' [%s]\n", __func__, EP11SHAREDLIB, errstr); TRACE_ERROR("%s Error loading shared library '%s[.4][.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_cmdblock) = dlsym(hdl, "xcpa_cmdblock"); *(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; } /* * The following are only available since EP11 host library version 4.1. * Ignore if they fail to load. */ *(void **)(&dll_m_LoginExtended) = dlsym(hdl, "m_LoginExtended"); *(void **)(&dll_m_LogoutExtended) = dlsym(hdl, "m_LogoutExtended"); if (dll_m_LoginExtended == NULL || dll_m_LogoutExtended == NULL) { dll_m_LoginExtended = NULL; dll_m_LogoutExtended = 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_V4); default_libica = 1; libica->library = dlopen(ep11_data->digest_libica_path, RTLD_NOW); if (libica->library == NULL) { strcpy(ep11_data->digest_libica_path, ICASHAREDLIB_V3); libica->library = dlopen(ep11_data->digest_libica_path, RTLD_NOW); } } else { libica->library = dlopen(ep11_data->digest_libica_path, 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_fips_status) = dlsym(libica->library, "ica_fips_status"); if (libica->ica_fips_status != NULL && libica->ica_fips_status() > ICA_FIPS_MODE) { TRACE_WARNING("%s: libica FIPS selftests failed, disable use of libica\n", __func__); } else { *(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 } *(void **)(&libica->ica_cleanup) = dlsym(libica->library, "ica_cleanup"); /* 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; } static CK_BBOOL ep11tok_is_sel_guest(void) { char buf[20]; CK_RV rc; if (access(SYSFS_SEL_GUEST, R_OK) != 0) return FALSE; rc = file_fgets(SYSFS_SEL_GUEST, buf, sizeof(buf)); if (rc != CKR_OK) return FALSE; return (buf[0] == '1'); } CK_RV ep11tok_init(STDLL_TokData_t * tokdata, CK_SLOT_ID SlotNumber, char *conf_name) { CK_RV rc; ep11_private_data_t *ep11_data; #ifndef EP11_HSMSIM const CK_VERSION ver4_1 = { .major = 4, .minor = 0x10 }; #endif TRACE_INFO("ep11 %s slot=%lu running\n", __func__, SlotNumber); /* Request the API layer to lock against HSM-MK-change state changes. */ rc = init_hsm_mk_change_lock(tokdata); if (rc != CKR_OK) { TRACE_ERROR("init_hsm_mk_change_lock failed.\n"); goto error; } ep11_data = calloc(1, sizeof(ep11_private_data_t)); if (ep11_data == NULL) return CKR_HOST_MEMORY; if (pthread_rwlock_init(&ep11_data->target_rwlock, NULL) != 0) { TRACE_DEVEL("Target Lock init failed.\n"); OCK_SYSLOG(LOG_ERR, "%s: Failed to initialize the target lock\n", __func__); rc = CKR_CANT_LOCK; free(ep11_data); goto error; } 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); goto error; } /* dynamically load in the ep11 shared library */ ep11_data->lib_ep11 = ep11_load_host_lib(); if (ep11_data->lib_ep11 == NULL) { rc = CKR_FUNCTION_FAILED; goto error; } rc = ep11_resolve_lib_sym(ep11_data->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_library_version(&ep11_data->ep11_lib_version); if (rc != CKR_OK) { TRACE_ERROR("%s Failed to get the Ep11 library version " "(ep11tok_get_ep11_library_version rc=0x%lx)\n", __func__, rc); OCK_SYSLOG(LOG_ERR, "%s: Failed to get the EP11 library version " "rc=0x%lx\n", __func__, rc); goto error; } TRACE_INFO("%s Host library version: %d.%d.%d\n", __func__, ep11_data->ep11_lib_version.major, (ep11_data->ep11_lib_version.minor & 0xF0) >> 4, (ep11_data->ep11_lib_version.minor & 0x0F)); #ifndef EP11_HSMSIM if (ep11_data->fips_session_mode) { if (compare_ck_version(&ep11_data->ep11_lib_version, &ver4_1) < 0 || dll_m_LoginExtended == NULL || dll_m_LogoutExtended == NULL) { TRACE_ERROR("%s EP11 host library does not support LoginExtended " "but this is required for FIPS-session mode\n", __func__); OCK_SYSLOG(LOG_ERR, "The EP11 host library does not support LoginExtended " "but this is required for FIPS-session mode\n"); rc = CKR_DEVICE_ERROR; goto error; } } #endif rc = ep11tok_mk_change_check_pending_ops(tokdata); if (rc != CKR_OK) { TRACE_ERROR("%s Failed to check for pending HSM MK change operations " "rc=0x%lx\n", __func__, rc); OCK_SYSLOG(LOG_ERR, "Slot %lu: Failed to check for pending HSM MK " "change operations rc=0x%lx\n", tokdata->slot_id, rc); goto error; } rc = refresh_target_info(tokdata, FALSE); if (rc != CKR_OK) { TRACE_ERROR("%s Failed to get the target info (refresh_target_info " "rc=0x%lx)\n", __func__, rc); OCK_SYSLOG(LOG_ERR, "%s: Failed to get the target info rc=0x%lx\n", __func__, rc); goto error; } if (ep11_data->digest_libica) { rc = ep11tok_load_libica(tokdata); if (rc != CKR_OK) goto error; } #ifndef NO_PKEY ep11_data->msa_level = get_msa_level(); TRACE_INFO("MSA level = %i\n", ep11_data->msa_level); #endif if (pthread_mutex_init(&ep11_data->raw2key_wrap_blob_mutex, NULL) != 0) { TRACE_ERROR("Initializing Wrap-Blob lock failed.\n"); rc = CKR_CANT_LOCK; goto error; } ep11_data->raw2key_wrap_blob_l = 0; if (pthread_mutex_init(&ep11_data->pkey_mutex, NULL) != 0) { TRACE_ERROR("Initializing PKEY lock failed.\n"); rc = CKR_CANT_LOCK; goto error; } #ifndef NO_PKEY if (!ep11tok_pkey_option_disabled(tokdata) && !ep11_data->fips_session_mode) { rc = ep11tok_pkey_get_firmware_mk_vp(tokdata, NULL); if (rc != CKR_OK && rc != CKR_FUNCTION_NOT_SUPPORTED) goto error; } #endif /* NO_PKEY */ if (ep11_data->vhsm_mode || ep11_data->fips_session_mode) { if (ep11tok_is_sel_guest() && ( #ifndef EP11_HSMSIM compare_ck_version(&ep11_data->ep11_lib_version, &ver4_1) < 0 || #endif ep11_data->target_info->used_firmware_API_version < 6)) { TRACE_ERROR("Strict-session or VHSM mode requires an EP11 " "host library >= v4.1 and API ordinal >= 6 when " "running in a Secure Execution for Linux guest\n"); OCK_SYSLOG(LOG_ERR, "Slot %lu: Strict-session or VHSM mode " "requires an EP11 host library >= v4.1 and API ordinal " ">= 6 when running in a Secure Execution for Linux " "guest\n", tokdata->slot_id); rc = CKR_FUNCTION_FAILED; goto error; } if (pthread_mutex_init(&ep11_data->session_mutex, NULL) != 0) { TRACE_ERROR("Initializing session lock failed.\n"); rc = CKR_CANT_LOCK; goto error; } } ep11_data->get_session_refcount = tokdata->tokspec_counter.get_tokspec_count; ep11_data->incr_session_refcount = tokdata->tokspec_counter.incr_tokspec_count; ep11_data->decr_session_refcount = tokdata->tokspec_counter.decr_tokspec_count; TRACE_INFO("%s init done successfully\n", __func__); return CKR_OK; error: ep11tok_final(tokdata, FALSE); TRACE_INFO("%s init failed with rc: 0x%lx\n", __func__, rc); return rc; } CK_RV ep11tok_final(STDLL_TokData_t * tokdata, CK_BBOOL in_fork_initializer) { ep11_private_data_t *ep11_data = tokdata->private_data; TRACE_INFO("ep11 %s running\n", __func__); if (ep11_data != NULL) { if (ep11_data->target_info != NULL) { if (dll_m_rm_module != NULL) dll_m_rm_module(NULL, ep11_data->target_info->target); free_card_versions(ep11_data->target_info->card_versions); free((void* )ep11_data->target_info); } pthread_rwlock_destroy(&ep11_data->target_rwlock); pthread_mutex_destroy(&ep11_data->raw2key_wrap_blob_mutex); if (ep11_data->vhsm_mode || ep11_data->fips_session_mode) pthread_mutex_destroy(&ep11_data->session_mutex); pthread_mutex_destroy(&ep11_data->pkey_mutex); free_cp_config(ep11_data->cp_config); if (ep11_data->libica.ica_cleanup != NULL && !in_fork_initializer) ep11_data->libica.ica_cleanup(); if (ep11_data->libica.library != NULL && !in_fork_initializer) dlclose(ep11_data->libica.library); if (ep11_data->lib_ep11 != NULL && !in_fork_initializer) dlclose(ep11_data->lib_ep11); if (ep11_data->mk_change_apqns != NULL) free(ep11_data->mk_change_apqns); free(ep11_data); tokdata->private_data = NULL; } return CKR_OK; } static CK_RV check_add_spki_attr(STDLL_TokData_t *tokdata, CK_ATTRIBUTE_PTR attr, CK_KEY_TYPE keytype, int curve_type, CK_ATTRIBUTE_PTR *attrs, CK_ULONG *attrs_len) { CK_MECHANISM mech = { CKM_IBM_TRANSPORTKEY, 0, 0 }; CK_BBOOL bool_value; CK_RV rc; if (!attr_applicable_for_ep11(tokdata, attr, keytype, CKO_PUBLIC_KEY, curve_type, &mech)) return CKR_OK; switch (attr->type) { case CKA_ENCRYPT: case CKA_VERIFY: case CKA_VERIFY_RECOVER: if (attr->ulValueLen != sizeof(CK_BOOL) || attr->pValue == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; } /* * 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(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); return rc; } break; case CKA_EXTRACTABLE: case CKA_MODIFIABLE: case CKA_DERIVE: case CKA_WRAP: case CKA_TRUSTED: case CKA_IBM_RESTRICTABLE: case CKA_IBM_ATTRBOUND: if (attr->ulValueLen > 0 && attr->pValue == NULL) { return CKR_ATTRIBUTE_VALUE_INVALID; } rc = add_to_attribute_array(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); return rc; } break; default: break; } return CKR_OK; } /* * Makes a public key blob which is a MACed SPKI of the public key. * Either pub_key_obj or pub_key_attrs/pub_key_attrs_len must be specified * to supply the public key attributes. */ static CK_RV make_maced_spki(STDLL_TokData_t *tokdata, SESSION *sess, OBJECT *pub_key_obj, CK_ATTRIBUTE *pub_key_attrs, CK_ULONG pub_key_attrs_len, CK_BYTE *spki, CK_ULONG spki_len, CK_BYTE *maced_spki, CK_BYTE *maced_spki_reenc, CK_ULONG *maced_spki_len, int curve_type) { unsigned char *ep11_pin_blob = NULL; CK_ULONG ep11_pin_blob_len = 0; 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; DL_NODE *node; CK_BYTE csum[MAX_BLOBSIZE]; CK_ULONG cslen = sizeof(csum); CK_KEY_TYPE keytype; CK_BBOOL is_private, is_session; CK_BYTE *tmp; CK_ULONG i, tmp_len, seq_len; CK_RV rc; if (spki_len < 6 || ber_decode_SEQUENCE(spki, spki_len, &tmp, &tmp_len, &seq_len) != CKR_OK) { TRACE_ERROR("%s Its not an SPKI\n", __func__); return CKR_FUNCTION_FAILED; } if (seq_len < spki_len) spki_len = seq_len; if (pub_key_obj != NULL) { rc = template_attribute_get_ulong(pub_key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto make_maced_spki_end; } ep11tok_pkcs11_keytype_translate(tokdata, keytype, &keytype); is_private = object_is_private(pub_key_obj); is_session = object_is_session_object(pub_key_obj); /* * 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) { rc = check_add_spki_attr(tokdata, node->data, keytype, curve_type, &p_attrs, &attrs_len); if (rc != CKR_OK) goto make_maced_spki_end; node = node->next; } } else { rc = get_ulong_attribute_by_type(pub_key_attrs, pub_key_attrs_len, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto make_maced_spki_end; } ep11tok_pkcs11_keytype_translate(tokdata, keytype, &keytype); is_private = ep11_is_private_object(pub_key_attrs, pub_key_attrs_len); is_session = ep11_is_session_object(pub_key_attrs, pub_key_attrs_len); /* * m_UnwrapKey with CKM_IBM_TRANSPORTKEY allows boolean attributes only * to be added to MACed-SPKIs */ for (i = 0; i < pub_key_attrs_len; i++) { rc = check_add_spki_attr(tokdata, &pub_key_attrs[i], keytype, curve_type, &p_attrs, &attrs_len); if (rc != CKR_OK) goto make_maced_spki_end; } } trace_attributes(__func__, "MACed SPKI import:", p_attrs, attrs_len); ep11_get_pin_blob(tokdata, ep11_session, is_session, is_private, &ep11_pin_blob, &ep11_pin_blob_len); RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_CREATE_KEY_START() rc = dll_m_UnwrapKey(spki, spki_len, NULL, 0, NULL, 0, ep11_pin_blob, ep11_pin_blob_len, &mech, p_attrs, attrs_len, maced_spki, maced_spki_len, csum, &cslen, target_info->target); RETRY_REENC_CREATE_KEY_END(tokdata, sess, target_info, maced_spki, maced_spki_reenc, *maced_spki_len, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, sess) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, sess); 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; } /** * Determine the curve type from the given template. * * @return a valid curve_type if successful * -1 if no CKA_ECDSA_PARAMS found in template */ static int get_curve_type_from_template(TEMPLATE *tmpl) { CK_ATTRIBUTE *ec_params; int i, curve_type = -1; CK_RV ret; ret = template_attribute_get_non_empty(tmpl, CKA_EC_PARAMS, &ec_params); if (ret != CKR_OK) { TRACE_ERROR("Could not find CKA_EC_PARAMS for the key.\n"); return curve_type; } for (i = 0; i < NUMEC; i++) { if (der_ec_supported[i].data_size == ec_params->ulValueLen && memcmp(ec_params->pValue, der_ec_supported[i].data, ec_params->ulValueLen) == 0) { curve_type = der_ec_supported[i].curve_type; break; } } return curve_type; } static int get_curve_type_from_spki(CK_BYTE *spki, CK_ULONG spki_len) { CK_BYTE *algid = NULL; CK_ULONG algid_len; CK_BYTE *algid_ECBase = NULL; CK_BYTE *param = NULL; CK_ULONG param_len; CK_BYTE *pubkey = NULL; CK_ULONG pubkey_len; CK_ULONG field_len, len, i; CK_RV rc; rc = ber_decode_SPKI(spki, spki_len, &algid, &algid_len, ¶m, ¶m_len, &pubkey, &pubkey_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_SPKI failed\n"); return -1; } /* * Check if 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, der_AlgIdECBaseLen, &algid_ECBase, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_SEQUENCE failed\n"); return -1; } if (memcmp(algid, algid_ECBase, len) != 0) { /* Not an EC SPKI, ignore */ return -1; } for (i = 0; i < NUMEC; i++) { if (der_ec_supported[i].data_size == param_len && memcmp(param, der_ec_supported[i].data, param_len) == 0) { return der_ec_supported[i].curve_type; } } return -1; } static CK_RV import_edwards_montgomery_preprocess(CK_BYTE *ec_spki, CK_ULONG ec_spki_len, CK_BYTE **spki, CK_ULONG *spki_len, TEMPLATE *tmpl, CK_KEY_TYPE keytype, CK_BBOOL is_public) { CK_BYTE *algid = NULL; CK_ULONG algid_len; CK_ATTRIBUTE ec_point, params; CK_RV rc; rc = ber_decode_SPKI(ec_spki, ec_spki_len, &algid, &algid_len, (CK_BYTE **)¶ms.pValue, ¶ms.ulValueLen, (CK_BYTE **)&ec_point.pValue, &ec_point.ulValueLen); if (rc != CKR_OK) { TRACE_ERROR("%s ber_decode_SPKI rc=0x%lx\n", __func__, rc); return rc; } rc = ber_encode_ECPublicKey(FALSE, spki, spki_len, ¶ms, &ec_point, keytype); if (rc != CKR_OK) { TRACE_ERROR("%s ber_encode_ECPublicKey rc=0x%lx\n", __func__, rc); return rc; } if (is_public) { rc = template_build_update_attribute(tmpl, CKA_EC_POINT, ec_point.pValue, ec_point.ulValueLen); if (rc != CKR_OK) { TRACE_ERROR("%s template_build_update_attribute rc=0x%lx\n", __func__, rc); free(*spki); *spki = NULL; return rc; } } return CKR_OK; } /* import a AES-XTS key, that is, make a blob for a AES XTS key * that was not created by EP11 hardware, encrypt the key by the wrap key, * unwrap it by the wrap key */ static CK_RV import_aes_xts_key(STDLL_TokData_t *tokdata, SESSION *sess, OBJECT *aes_xts_key_obj, CK_BYTE *blob, CK_BYTE *blobreenc, size_t *blob_size) { 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]; size_t blob_size2 = *blob_size; CK_MECHANISM mech = { CKM_AES_CBC_PAD, iv, AES_BLOCK_SIZE }; 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; CK_ATTRIBUTE *attr = NULL; unsigned char *ep11_pin_blob = NULL; CK_ULONG ep11_pin_blob_len = 0; ep11_session_t *ep11_session = (ep11_session_t*) sess->private_data; CK_BYTE *wrap_blob; CK_BBOOL blob_new_mk = CK_FALSE, blob2_new_mk; rc = template_attribute_get_non_empty(aes_xts_key_obj->template, CKA_VALUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); return rc; } if (memcmp(attr->pValue, ((CK_BYTE *)attr->pValue) + attr->ulValueLen / 2, attr->ulValueLen / 2) == 0) { TRACE_ERROR("The 2 key parts of an AES-XTS key can not be the same\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } /* tell ep11 the attributes the user specified */ rc = build_ep11_attrs(tokdata, aes_xts_key_obj->template, &p_attrs, &attrs_len, CKK_AES, CKO_SECRET_KEY, -1, &mech); if (rc != CKR_OK) goto import_aes_xts_key_end; #ifndef NO_PKEY rc = ep11tok_pkey_check_aes_xts(tokdata, aes_xts_key_obj, CKM_AES_XTS); #else rc = CKR_FUNCTION_NOT_SUPPORTED; #endif if (rc != CKR_OK) { TRACE_ERROR("%s EP11 AES XTS is not supported: rc=0x%lx\n", __func__, rc); goto import_aes_xts_key_end; } rc = check_key_attributes(tokdata, CKK_AES, CKO_SECRET_KEY, p_attrs, attrs_len, &new_p_attrs, &new_attrs_len, -1); if (rc != CKR_OK) { TRACE_ERROR("%s AES XTS check private key attributes failed with " "rc=0x%lx\n", __func__, rc); goto import_aes_xts_key_end; } trace_attributes(__func__, "Import sym.:", new_p_attrs, new_attrs_len); ep11_get_pin_blob(tokdata, ep11_session, object_is_session_object(aes_xts_key_obj), object_is_private(aes_xts_key_obj), &ep11_pin_blob, &ep11_pin_blob_len); retry: 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_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_WRAPBLOB_START(tokdata, target_info, wrap_blob) rc = dll_m_EncryptSingle(wrap_blob, ep11_data->raw2key_wrap_blob_l, &mech, attr->pValue, attr->ulValueLen / 2, cipher, &clen, target_info->target); RETRY_REENC_WRAPBLOB_END(tokdata, target_info, wrap_blob, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, sess) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, sess); TRACE_ERROR("%s encrypt ksize=0x%lx clen=0x%lx rc=0x%lx\n", __func__, attr->ulValueLen / 2, clen, rc); goto import_aes_xts_key_end; } else { TRACE_INFO("%s encrypt ksize=0x%lx clen=0x%lx rc=0x%lx\n", __func__, attr->ulValueLen / 2, clen, rc); } /* the encrypted key is decrypted and a blob is built, * card accepts only blobs as keys */ RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_WRAPBLOB_START(tokdata, target_info, wrap_blob) RETRY_REENC_CREATE_KEY_START() rc = dll_m_UnwrapKey(cipher, clen, wrap_blob, ep11_data->raw2key_wrap_blob_l, NULL, ~0, ep11_pin_blob, ep11_pin_blob_len, &mech, new_p_attrs, new_attrs_len, blob, blob_size, csum, &cslen, target_info->target); RETRY_REENC_CREATE_KEY_END(tokdata, sess, target_info, blob, blobreenc, *blob_size, rc) RETRY_REENC_WRAPBLOB_END(tokdata, target_info, wrap_blob, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, sess) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, sess); TRACE_ERROR("%s unwrap blen=%zd rc=0x%lx\n", __func__, *blob_size, rc); goto import_aes_xts_key_end; } else { TRACE_INFO("%s unwrap blen=%zd rc=0x%lx\n", __func__, *blob_size, rc); } if (ep11_data->mk_change_active) blob_new_mk = ep11tok_is_blob_new_wkid(tokdata, blob, *blob_size); memset(cipher, 0, sizeof(cipher)); /* * calls the ep11 lib (which in turns sends the request to the card), * all m_ function are ep11 functions */ RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_WRAPBLOB_START(tokdata, target_info, wrap_blob) rc = dll_m_EncryptSingle(wrap_blob, ep11_data->raw2key_wrap_blob_l, &mech, ((CK_BYTE *)attr->pValue) + attr->ulValueLen / 2, attr->ulValueLen / 2, cipher, &clen, target_info->target); RETRY_REENC_WRAPBLOB_END(tokdata, target_info, wrap_blob, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, sess) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, sess); TRACE_ERROR("%s encrypt ksize=0x%lx clen=0x%lx rc=0x%lx\n", __func__, attr->ulValueLen / 2, clen, rc); goto import_aes_xts_key_end; } else { TRACE_INFO("%s encrypt ksize=0x%lx clen=0x%lx rc=0x%lx\n", __func__, attr->ulValueLen / 2, clen, rc); } trace_attributes(__func__, "Import sym.:", new_p_attrs, new_attrs_len); /* update the remaining buffer size in blob */ blob_size2 = blob_size2 - *blob_size; /* the encrypted key is decrypted and a blob is built, * card accepts only blobs as keys */ RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_WRAPBLOB_START(tokdata, target_info, wrap_blob) RETRY_REENC_CREATE_KEY_START() rc = dll_m_UnwrapKey(cipher, clen, wrap_blob, ep11_data->raw2key_wrap_blob_l, NULL, ~0, ep11_pin_blob, ep11_pin_blob_len, &mech, new_p_attrs, new_attrs_len, blob + *blob_size, &blob_size2, csum, &cslen, target_info->target); RETRY_REENC_CREATE_KEY_END(tokdata, sess, target_info, blob + *blob_size, blobreenc + *blob_size, blob_size2, rc) RETRY_REENC_WRAPBLOB_END(tokdata, target_info, wrap_blob, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, sess) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, sess); TRACE_ERROR("%s unwrap blen=%zd rc=0x%lx\n", __func__, blob_size2, rc); goto import_aes_xts_key_end; } else { TRACE_INFO("%s unwrap blen=%zd rc=0x%lx\n", __func__, blob_size2, rc); } if (ep11_data->mk_change_active) { blob2_new_mk = ep11tok_is_blob_new_wkid(tokdata, blob + *blob_size, blob_size2); if (blob_new_mk != blob2_new_mk) { /* * New MK has been set after importing key 1 but before * importing key 2 */ if (blob2_new_mk == TRUE) { /* * Key 2 was created with new MK, key 1 with old MK. * Key 2 already has blob and reenc_blob with new MK, * Key 1 has blob with old MK, and blob_reenc with new MK. * Supply blob_reenc with new MK in blob also. */ memcpy(blob, blobreenc, *blob_size); } else { /* * Key 1 was created with new MK, but key 2 with old MK. * This can happen when the single APQN with new MK went offline * and a new single APQN with old MK is selected after creating * key 1 but before creating key 2. Since there is no key1 blob * with old MK, we need to re-create both keys (both with old * MK now). */ goto retry; } } } /* update the concatenated blobsize */ *blob_size = *blob_size + blob_size2; cleanse_attribute(aes_xts_key_obj->template, CKA_VALUE); import_aes_xts_key_end: if (rc != CKR_OK) cleanse_attribute(aes_xts_key_obj->template, CKA_VALUE); 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 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, CK_BYTE *blobreenc, size_t *blob_size, CK_BYTE *spki, size_t *spki_size) { ep11_private_data_t *ep11_data = tokdata->private_data; CK_RV rc; 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); 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_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 *wrap_blob; memcpy(iv, "1234567812345678", AES_BLOCK_SIZE); /* need class for private/public key info */ rc = template_attribute_get_ulong(rsa_key_obj->template, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); return rc; } /* m_Unwrap builds key blob in the card, * tell ep11 the attributes the user specified for that key. */ rc = build_ep11_attrs(tokdata, rsa_key_obj->template, &p_attrs, &attrs_len, CKK_RSA, class, -1, &mech_w); if (rc != CKR_OK) goto import_RSA_key_end; if (class != CKO_PRIVATE_KEY) { /* an imported public RSA key, we need a SPKI for it. */ CK_ATTRIBUTE *modulus; CK_ATTRIBUTE *publ_exp; rc = template_attribute_get_non_empty(rsa_key_obj->template, CKA_MODULUS, &modulus); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); goto import_RSA_key_end; } rc = template_attribute_get_non_empty(rsa_key_obj->template, CKA_PUBLIC_EXPONENT, &publ_exp); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_PUBLIC_EXPONENT for the key.\n"); 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, NULL, 0, data, data_len, blob, blobreenc, blob_size, -1); if (rc != CKR_OK) { TRACE_ERROR("%s failed to make a MACed-SPKI rc=0x%lx\n", __func__, rc); goto import_RSA_key_end; } *spki_size = 0; /* common code will extract SPKI from object */ } else { /* imported private RSA key goes here */ rc = rsa_priv_check_and_swap_pq(rsa_key_obj->template); if (rc != CKR_OK) { TRACE_DEVEL("%s RSA check and swap failed\n", __func__); goto import_RSA_key_end; } /* extract the secret data to be wrapped * since this is AES_CBC_PAD, padding is done in mechanism. */ 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_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_WRAPBLOB_START(tokdata, target_info, wrap_blob) rc = dll_m_EncryptSingle(wrap_blob, ep11_data->raw2key_wrap_blob_l, &mech_w, data, data_len, cipher, &cipher_l, target_info->target); RETRY_REENC_WRAPBLOB_END(tokdata, target_info, wrap_blob, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, sess) TRACE_INFO("%s wrapping wrap key rc=0x%lx cipher_l=0x%lx\n", __func__, rc, cipher_l); 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, -1); 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; } trace_attributes(__func__, "RSA import:", new_p_attrs, new_attrs_len); ep11_get_pin_blob(tokdata, ep11_session, object_is_session_object(rsa_key_obj), object_is_private(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_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_WRAPBLOB_START(tokdata, target_info, wrap_blob) RETRY_REENC_CREATE_KEY_START() rc = dll_m_UnwrapKey(cipher, cipher_l, wrap_blob, ep11_data->raw2key_wrap_blob_l, NULL, ~0, ep11_pin_blob, ep11_pin_blob_len, &mech_w, new_p_attrs, new_attrs_len, blob, blob_size, spki, spki_size, target_info->target); RETRY_REENC_CREATE_KEY_END(tokdata, sess, target_info, blob, blobreenc, *blob_size, rc) RETRY_REENC_WRAPBLOB_END(tokdata, target_info, wrap_blob, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, sess) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, sess); 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, CK_BYTE *blobreenc, size_t *blob_size, CK_BYTE *spki, size_t *spki_size, CK_KEY_TYPE keytype) { ep11_private_data_t *ep11_data = tokdata->private_data; CK_RV rc; 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); 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_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; const struct _ec *curve = NULL; CK_BYTE *wrap_blob; CK_BYTE *spki2 = NULL; CK_ULONG spki_buf_len = *spki_size, spki2_len = 0; memcpy(iv, "1234567812345678", AES_BLOCK_SIZE); /* need class for private/public key info */ rc = template_attribute_get_ulong(ec_key_obj->template, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); return rc; } if (!ep11tok_ec_curve_supported2(tokdata, ec_key_obj->template, &curve)) { TRACE_ERROR("Curve not supported.\n"); return CKR_CURVE_NOT_SUPPORTED; } /* m_Unwrap builds key blob in the card, * tell ep11 the attributes the user specified for that key. */ rc = build_ep11_attrs(tokdata, ec_key_obj->template, &p_attrs, &attrs_len, CKK_EC, class, (int)curve->curve_type, &mech_w); if (rc != CKR_OK) goto import_EC_key_end; 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; rc = template_attribute_get_non_empty(ec_key_obj->template, CKA_EC_PARAMS, &ec_params); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_EC_PARAMS for the key.\n"); goto import_EC_key_end; } rc = template_attribute_get_non_empty(ec_key_obj->template, CKA_EC_POINT, &ec_point_attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_EC_POINT for the key.\n"); goto import_EC_key_end; } switch (keytype) { case CKK_EC: /* CKA_EC_POINT is an BER encoded OCTET STRING. Extract it. */ rc = ber_decode_OCTET_STRING((CK_BYTE *)ec_point_attr->pValue, ec_point_attr->ulValueLen, &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; } break; case CKK_EC_EDWARDS: case CKK_EC_MONTGOMERY: /* Edwards/Montgomery has a raw EC-point, no need to uncompress */ ecpoint = ec_point_attr->pValue; ecpoint_len = ec_point_attr->ulValueLen; break; default: return CKR_KEY_TYPE_INCONSISTENT; } /* 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. */ rc = ber_encode_ECPublicKey(FALSE, &data, &data_len, ec_params, &ec_point_uncompr, CKK_EC); 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, NULL, 0, data, data_len, blob, blobreenc, blob_size, (int)curve->curve_type); if (rc != CKR_OK) { TRACE_ERROR("%s failed to make a MACed-SPKI rc=0x%lx\n", __func__, rc); goto import_EC_key_end; } *spki_size = 0; /* common code will extract SPKI from object */ } 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 = ec_priv_wrap_get_data(ec_key_obj->template, FALSE, &data, &data_len, CKK_EC); if (rc != CKR_OK) { TRACE_DEVEL("%s EC wrap get data failed\n", __func__); goto import_EC_key_end; } /* encrypt */ RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_WRAPBLOB_START(tokdata, target_info, wrap_blob) rc = dll_m_EncryptSingle(wrap_blob, ep11_data->raw2key_wrap_blob_l, &mech_w, data, data_len, cipher, &cipher_l, target_info->target); RETRY_REENC_WRAPBLOB_END(tokdata, target_info, wrap_blob, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, sess) TRACE_INFO("%s wrapping wrap key rc=0x%lx cipher_l=0x%lx\n", __func__, rc, cipher_l); 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, (int)curve->curve_type); 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; } trace_attributes(__func__, "EC import:", new_p_attrs, new_attrs_len); ep11_get_pin_blob(tokdata, ep11_session, object_is_session_object(ec_key_obj), object_is_private(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_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_WRAPBLOB_START(tokdata, target_info, wrap_blob) RETRY_REENC_CREATE_KEY_START() rc = dll_m_UnwrapKey(cipher, cipher_l, wrap_blob, ep11_data->raw2key_wrap_blob_l, NULL, ~0, ep11_pin_blob, ep11_pin_blob_len, &mech_w, new_p_attrs, new_attrs_len, blob, blob_size, spki, spki_size, target_info->target); RETRY_REENC_CREATE_KEY_END(tokdata, sess, target_info, blob, blobreenc, *blob_size, rc) RETRY_REENC_WRAPBLOB_END(tokdata, target_info, wrap_blob, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, sess) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, sess); 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); } if (keytype == CKK_EC_EDWARDS || keytype == CKK_EC_MONTGOMERY) { /* Edwards/Montomery has a different SPKI and EC-point format */ rc = import_edwards_montgomery_preprocess(spki, *spki_size, &spki2, &spki2_len, ec_key_obj->template, keytype, FALSE); if (rc != CKR_OK) { TRACE_ERROR("%s import_edwards_montgomery_preprocess " "rc=0x%lx\n", __func__, rc); return rc; } if (spki2_len > spki_buf_len) { TRACE_ERROR("%s SPKI buffer is too small\n", __func__); free(spki2); return CKR_BUFFER_TOO_SMALL; } memcpy(spki, spki2, spki2_len); *spki_size = spki2_len; free(spki2); } 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, CK_BYTE *blobreenc, size_t *blob_size, CK_BYTE *spki, size_t *spki_size) { ep11_private_data_t *ep11_data = tokdata->private_data; CK_RV rc; 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); 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_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 *wrap_blob; memcpy(iv, "1234567812345678", AES_BLOCK_SIZE); /* need class for private/public key info */ rc = template_attribute_get_ulong(dsa_key_obj->template, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); return rc; } /* m_Unwrap builds key blob in the card, * tell ep11 the attributes the user specified for that key. */ rc = build_ep11_attrs(tokdata, dsa_key_obj->template, &p_attrs, &attrs_len, CKK_DSA, class, -1, &mech_w); if (rc != CKR_OK) goto import_DSA_key_end; 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; rc = template_attribute_get_non_empty(dsa_key_obj->template, CKA_PRIME, &prime); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_PRIME for the key.\n"); goto import_DSA_key_end; } rc = template_attribute_get_non_empty(dsa_key_obj->template, CKA_SUBPRIME, &subprime); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_SUBPRIME for the key.\n"); goto import_DSA_key_end; } rc = template_attribute_get_non_empty(dsa_key_obj->template, CKA_BASE, &base); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_BASE for the key.\n"); goto import_DSA_key_end; } rc = template_attribute_get_non_empty(dsa_key_obj->template, CKA_VALUE, &value); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); goto import_DSA_key_end; } /* * Builds the DER encoding (ansi_x962) SPKI. */ 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, NULL, 0, data, data_len, blob, blobreenc, blob_size, -1); if (rc != CKR_OK) { TRACE_ERROR("%s failed to make a MACed-SPKI rc=0x%lx\n", __func__, rc); goto import_DSA_key_end; } *spki_size = 0; /* common code will extract SPKI from object */ } 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_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_WRAPBLOB_START(tokdata, target_info, wrap_blob) rc = dll_m_EncryptSingle(wrap_blob, ep11_data->raw2key_wrap_blob_l, &mech_w, data, data_len, cipher, &cipher_l, target_info->target); RETRY_REENC_WRAPBLOB_END(tokdata, target_info, wrap_blob, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, sess) TRACE_INFO("%s wrapping wrap key rc=0x%lx cipher_l=0x%lx\n", __func__, rc, cipher_l); 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, -1); 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; } trace_attributes(__func__, "DSA import:", new_p_attrs, new_attrs_len); ep11_get_pin_blob(tokdata, ep11_session, object_is_session_object(dsa_key_obj), object_is_private(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_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_WRAPBLOB_START(tokdata, target_info, wrap_blob) RETRY_REENC_CREATE_KEY_START() rc = dll_m_UnwrapKey(cipher, cipher_l, wrap_blob, ep11_data->raw2key_wrap_blob_l, NULL, ~0, ep11_pin_blob, ep11_pin_blob_len, &mech_w, new_p_attrs, new_attrs_len, blob, blob_size, spki, spki_size, target_info->target); RETRY_REENC_CREATE_KEY_END(tokdata, sess, target_info, blob, blobreenc, *blob_size, rc) RETRY_REENC_WRAPBLOB_END(tokdata, target_info, wrap_blob, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, sess) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, sess); 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, CK_BYTE *blobreenc, size_t *blob_size, CK_BYTE *spki, size_t *spki_size) { ep11_private_data_t *ep11_data = tokdata->private_data; CK_RV rc; 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); 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_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 *wrap_blob; memcpy(iv, "1234567812345678", AES_BLOCK_SIZE); /* need class for private/public key info */ rc = template_attribute_get_ulong(dh_key_obj->template, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); return rc; } /* m_Unwrap builds key blob in the card, * tell ep11 the attributes the user specified for that key. */ rc = build_ep11_attrs(tokdata, dh_key_obj->template, &p_attrs, &attrs_len, CKK_DH, class, -1, &mech_w); if (rc != CKR_OK) goto import_DH_key_end; 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; rc = template_attribute_get_non_empty(dh_key_obj->template, CKA_PRIME, &prime); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_PRIME for the key.\n"); goto import_DH_key_end; } rc = template_attribute_get_non_empty(dh_key_obj->template, CKA_BASE, &base); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_BASE for the key.\n"); goto import_DH_key_end; } rc = template_attribute_get_non_empty(dh_key_obj->template, CKA_VALUE, &value); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); goto import_DH_key_end; } /* * Builds the DER encoding (ansi_x962) SPKI. */ 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, NULL, 0, data, data_len, blob, blobreenc, blob_size, -1); if (rc != CKR_OK) { TRACE_ERROR("%s failed to make a MACed-SPKI rc=0x%lx\n", __func__, rc); goto import_DH_key_end; } *spki_size = 0; /* common code will extract SPKI from object */ } else { CK_ATTRIBUTE *value; CK_ATTRIBUTE *value_bits; CK_ULONG num_bits; /* 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; } rc = template_attribute_get_non_empty(dh_key_obj->template, CKA_VALUE, &value); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); goto import_DH_key_end; } num_bits = value->ulValueLen * 8; /* encrypt */ RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_WRAPBLOB_START(tokdata, target_info, wrap_blob) rc = dll_m_EncryptSingle(wrap_blob, ep11_data->raw2key_wrap_blob_l, &mech_w, data, data_len, cipher, &cipher_l, target_info->target); RETRY_REENC_WRAPBLOB_END(tokdata, target_info, wrap_blob, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, sess) TRACE_INFO("%s wrapping wrap key rc=0x%lx cipher_l=0x%lx\n", __func__, rc, cipher_l); 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, -1); 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; } trace_attributes(__func__, "DH import:", new_p_attrs, new_attrs_len); ep11_get_pin_blob(tokdata, ep11_session, object_is_session_object(dh_key_obj), object_is_private(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_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_WRAPBLOB_START(tokdata, target_info, wrap_blob) RETRY_REENC_CREATE_KEY_START() rc = dll_m_UnwrapKey(cipher, cipher_l, wrap_blob, ep11_data->raw2key_wrap_blob_l, NULL, ~0, ep11_pin_blob, ep11_pin_blob_len, &mech_w, new_p_attrs, new_attrs_len, blob, blob_size, spki, spki_size, target_info->target); RETRY_REENC_CREATE_KEY_END(tokdata, sess, target_info, blob, blobreenc, *blob_size, rc) RETRY_REENC_WRAPBLOB_END(tokdata, target_info, wrap_blob, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, sess) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, sess); 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); } rc = build_attribute(CKA_VALUE_BITS, (CK_BYTE *)&num_bits, sizeof(num_bits), &value_bits); if (rc != CKR_OK) { TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc); goto import_DH_key_end; } rc = template_update_attribute(dh_key_obj->template, value_bits); if (rc != CKR_OK) { TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n", __func__, rc); free(value_bits); goto import_DH_key_end; } 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 PQC keys and * SPKIs for public imported PQC keys. * Similar to rawkey_2_blob, but keys must follow a standard BER encoding. */ static CK_RV import_pqc_key(STDLL_TokData_t *tokdata, SESSION *sess, OBJECT *pqc_key_obj, CK_KEY_TYPE keytype, CK_BYTE *blob, CK_BYTE *blobreenc, size_t *blob_size, CK_BYTE *spki, size_t *spki_size) { ep11_private_data_t *ep11_data = tokdata->private_data; CK_RV rc; 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); 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_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_ATTRIBUTE *value_attr = NULL; CK_BBOOL data_alloced = TRUE; const struct pqc_oid *oid; const char *key_type_str; CK_MECHANISM_TYPE pqc_mech; CK_BYTE *wrap_blob; switch (keytype) { case CKK_IBM_PQC_DILITHIUM: key_type_str = "Dilithium"; pqc_mech = CKM_IBM_DILITHIUM; break; case CKK_IBM_PQC_KYBER: key_type_str = "Kyber"; pqc_mech = CKM_IBM_KYBER; break; case CKK_IBM_ML_DSA: key_type_str = "ML-DSA"; pqc_mech = CKM_IBM_ML_DSA; break; case CKK_IBM_ML_KEM: key_type_str = "ML-KEM"; pqc_mech = CKM_IBM_ML_KEM; break; case CKK_ML_DSA: key_type_str = "ML-DSA"; pqc_mech = CKM_ML_DSA; break; case CKK_ML_KEM: key_type_str = "ML-KEM"; pqc_mech = CKM_ML_KEM; break; default: TRACE_ERROR("Invalid key type provided for %s\n ", __func__); return CKR_KEY_TYPE_INCONSISTENT; } memcpy(iv, "1234567812345678", AES_BLOCK_SIZE); /* need class for secret/public key info */ rc = template_attribute_get_ulong(pqc_key_obj->template, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); return rc; } /* m_Unwrap builds key blob in the card, * tell ep11 the attributes the user specified for that key. */ rc = build_ep11_attrs(tokdata, pqc_key_obj->template, &p_attrs, &attrs_len, keytype, class, -1, &mech_w); if (rc != CKR_OK) goto done; if (class != CKO_PRIVATE_KEY) { /* Make an SPKI for the public PQC key */ /* A public PQC key must either have a CKA_VALUE containing * the SPKI (IBM specific key types only), or must have a keyform/mode * value and the individual attributes */ if (keytype != CKK_ML_DSA && keytype != CKK_ML_KEM && template_attribute_find(pqc_key_obj->template, CKA_VALUE, &value_attr) && value_attr->ulValueLen > 0 && value_attr ->pValue != NULL) { /* CKA_VALUE with SPKI */ data = value_attr->pValue; data_len = value_attr->ulValueLen; data_alloced = FALSE; /* * Decode SPKI and add public key attributes. This also adds the * keyform and mode attributes to the template. */ rc = pqc_priv_unwrap_get_data(pqc_key_obj->template, keytype, data, data_len, FALSE); if (rc != CKR_OK) { TRACE_ERROR("Failed to decode SPKI from CKA_VALUE.\n"); goto done; } } else { /* Individual attributes */ rc = pqc_publ_get_spki(pqc_key_obj->template, keytype, FALSE, &data, &data_len, FALSE); 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); } /* Ensure both, keyform and mode attributes are added */ oid = pqc_get_keyform_mode(pqc_key_obj->template, pqc_mech); if (oid == NULL) { rc = CKR_TEMPLATE_INCOMPLETE; goto done; } rc = pqc_add_keyform_mode(pqc_key_obj->template, oid, pqc_mech); if (rc != CKR_OK) { TRACE_ERROR("pqc_add_keyform_mode failed\n"); goto done; } if (keytype != CKK_ML_DSA && keytype != CKK_ML_KEM) { /* * Add SPKI as CKA_VALUE to public key (z/OS ICSF compatibility) */ rc = build_attribute(CKA_VALUE, data, data_len, &value_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto done; } rc = template_update_attribute(pqc_key_obj->template, value_attr); if (rc != CKR_OK) { TRACE_ERROR("%s template_update_attribute failed with " "rc=0x%lx\n", __func__, rc); free(value_attr); goto done; } value_attr = NULL; } } /* 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, pqc_key_obj, NULL, 0, data, data_len, blob, blobreenc, blob_size, -1); if (rc != CKR_OK) { TRACE_ERROR("%s failed to make a MACed-SPKI rc=0x%lx\n", __func__, rc); goto done; } *spki_size = 0; /* common code will extract SPKI from object */ } else { /* imported private PQC key goes here */ /* A public PQC key must either have a CKA_VALUE containing * the PKCS#8 encoded private key (IBM specific key types only), or * must have a keyform/mode value and the individual attributes */ if (keytype != CKK_ML_DSA && keytype != CKK_ML_KEM && template_attribute_find(pqc_key_obj->template, CKA_VALUE, &value_attr) && value_attr->ulValueLen > 0 && value_attr ->pValue != NULL) { /* CKA_VALUE with PKCS#8 */ data = value_attr->pValue; data_len = value_attr->ulValueLen; data_alloced = FALSE; /* Decode PKCS#8 private key and add key attributes */ rc = pqc_priv_unwrap(pqc_key_obj->template, keytype, data, data_len, FALSE); if (rc != CKR_OK) { TRACE_ERROR("Failed to decode private key from CKA_VALUE.\n"); goto done; } } else { /* Extract the secret data to be wrapped since this is AES_CBC_PAD, * padding is done in mechanism. This also adds the keyform and mode * attributes to the template. */ rc = pqc_priv_wrap_get_data(pqc_key_obj->template, keytype, FALSE, &data, &data_len); if (rc != CKR_OK) { TRACE_DEVEL("%s %s wrap get data failed\n", __func__, key_type_str); goto done; } /* Ensure both, keyform and mode attributes are added */ oid = pqc_get_keyform_mode(pqc_key_obj->template, pqc_mech); if (oid == NULL) { rc = CKR_TEMPLATE_INCOMPLETE; goto done; } rc = pqc_add_keyform_mode(pqc_key_obj->template, oid, pqc_mech); if (rc != CKR_OK) { TRACE_ERROR("pqc_add_keyform_mode failed\n"); goto done; } } /* encrypt */ RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_WRAPBLOB_START(tokdata, target_info, wrap_blob) if (ep11_pqc_obj_strength_supported(target_info, pqc_mech, pqc_key_obj)) rc = dll_m_EncryptSingle(wrap_blob, ep11_data->raw2key_wrap_blob_l, &mech_w, data, data_len, cipher, &cipher_l, target_info->target); else rc = CKR_KEY_SIZE_RANGE; RETRY_REENC_WRAPBLOB_END(tokdata, target_info, wrap_blob, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, sess) TRACE_INFO("%s wrapping wrap key rc=0x%lx cipher_l=0x%lx\n", __func__, rc, cipher_l); 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, keytype, CKO_PRIVATE_KEY, p_attrs, attrs_len, &new_p_attrs, &new_attrs_len, -1); if (rc != CKR_OK) { TRACE_ERROR("%s EC check private key attributes failed with " "rc=0x%lx\n", __func__, rc); goto done; } trace_attributes(__func__, "PQC import:", new_p_attrs, new_attrs_len); ep11_get_pin_blob(tokdata, ep11_session, object_is_session_object(pqc_key_obj), object_is_private(pqc_key_obj), &ep11_pin_blob, &ep11_pin_blob_len); /* calls the card, it decrypts the private PQC key, * reads its BER format and builds a blob. */ RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_WRAPBLOB_START(tokdata, target_info, wrap_blob) RETRY_REENC_CREATE_KEY_START() rc = dll_m_UnwrapKey(cipher, cipher_l, wrap_blob, ep11_data->raw2key_wrap_blob_l, NULL, ~0, ep11_pin_blob, ep11_pin_blob_len, &mech_w, new_p_attrs, new_attrs_len, blob, blob_size, spki, spki_size, target_info->target); RETRY_REENC_CREATE_KEY_END(tokdata, sess, target_info, blob, blobreenc, *blob_size, rc) RETRY_REENC_WRAPBLOB_END(tokdata, target_info, wrap_blob, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, sess) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, sess); 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); } switch (keytype) { case CKK_IBM_ML_DSA: case CKK_IBM_ML_KEM: case CKK_ML_DSA: case CKK_ML_KEM: /* * ML-DSA/ML-KEM private key does not contain the public key, * get pub key attrs from SPKI */ rc = pqc_priv_unwrap_get_data(pqc_key_obj->template, keytype, spki, *spki_size, FALSE); if (rc != CKR_OK) { TRACE_ERROR("Failed to decode public key from SPKI.\n"); goto done; } break; } cleanse_attribute(pqc_key_obj->template, CKA_VALUE); switch (keytype) { case CKK_IBM_PQC_DILITHIUM: case CKK_IBM_ML_DSA: cleanse_attribute(pqc_key_obj->template, CKA_IBM_ML_DSA_SEED); cleanse_attribute(pqc_key_obj->template, CKA_IBM_ML_DSA_TR); cleanse_attribute(pqc_key_obj->template, CKA_IBM_ML_DSA_S1); cleanse_attribute(pqc_key_obj->template, CKA_IBM_ML_DSA_S2); cleanse_attribute(pqc_key_obj->template, CKA_IBM_ML_DSA_T0); cleanse_attribute(pqc_key_obj->template, CKA_IBM_ML_DSA_PRIVATE_SEED); break; case CKK_IBM_PQC_KYBER: case CKK_IBM_ML_KEM: cleanse_attribute(pqc_key_obj->template, CKA_IBM_ML_KEM_SK); cleanse_attribute(pqc_key_obj->template, CKA_IBM_ML_KEM_PRIVATE_SEED); break; case CKK_ML_DSA: case CKK_ML_KEM: cleanse_attribute(pqc_key_obj->template, CKA_VALUE); break; } } done: if (data_alloced && 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; } static CK_RV import_blob_private_public(STDLL_TokData_t *tokdata, SESSION *sess, OBJECT *obj, CK_KEY_TYPE keytype, CK_BYTE *spki, CK_ULONG spki_len, CK_BBOOL is_public) { CK_ULONG data_len, raw_spki_len, spki2_len = 0; CK_BYTE *data, *spki2 = NULL; const struct _ec *curve; CK_RV rc; UNUSED(tokdata); UNUSED(sess); /* Decode SPKI and add the respective public key attributes */ switch (keytype) { case CKK_EC: case CKK_EC_EDWARDS: case CKK_EC_MONTGOMERY: rc = ec_priv_unwrap_get_data(obj->template, spki, spki_len, is_public, CKK_EC); break; case CKK_RSA: rc = rsa_priv_unwrap_get_data(obj->template, spki, spki_len, is_public); break; case CKK_DSA: rc = dsa_priv_unwrap_get_data(obj->template, spki, spki_len, is_public); break; case CKK_DH: rc = dh_priv_unwrap_get_data(obj->template, spki, spki_len, is_public); break; case CKK_IBM_PQC_DILITHIUM: case CKK_IBM_PQC_KYBER: case CKK_IBM_ML_DSA: case CKK_IBM_ML_KEM: case CKK_ML_DSA: case CKK_ML_KEM: rc = pqc_priv_unwrap_get_data(obj->template, keytype, spki, spki_len, is_public); break; default: TRACE_ERROR("%s Key type 0x%lx not supported\n", __func__, keytype); return CKR_FUNCTION_FAILED; } if (rc != 0) { TRACE_ERROR("%s xxx_priv_unwrap_get_data rc=0x%lx\n", __func__, rc); return rc; } switch (keytype) { case CKK_EC_EDWARDS: case CKK_EC_MONTGOMERY: /* Edwards/Montomery has a different SPKI and EC-point format */ rc = import_edwards_montgomery_preprocess(spki, spki_len, &spki2, &spki2_len, obj->template, keytype, is_public); if (rc != CKR_OK) { TRACE_ERROR("%s import_edwards_montgomery_preprocess " "rc=0x%lx\n", __func__, rc); return rc; } spki = spki2; spki_len = spki2_len; /* fallthrough */ case CKK_EC: if (!ep11tok_ec_curve_supported2(tokdata, obj->template, &curve)) { TRACE_ERROR("Curve not supported.\n"); return CKR_CURVE_NOT_SUPPORTED; } break; } /* SPKI is a MACed SPKI, get length of SPKI part only */ rc = ber_decode_SEQUENCE(spki, spki_len, &data, &data_len, &raw_spki_len); if (rc != CKR_OK) { TRACE_ERROR("%s ber_decode_SEQUENCE failed rc=0x%lx\n", __func__, rc); goto out; } /* Add SPKI as CKA_PUBLIC_KEY_INFO */ rc = template_build_update_attribute(obj->template, CKA_PUBLIC_KEY_INFO, spki, raw_spki_len); if (rc != CKR_OK) { TRACE_ERROR("%s template_build_update_attribute failed with rc=0x%lx\n", __func__, rc); goto out; } out: if (spki2 != NULL) free(spki2); return rc; } static CK_RV import_blob_secret(STDLL_TokData_t *tokdata, SESSION *sess, OBJECT *obj, CK_KEY_TYPE keytype, CK_ULONG value_len) { CK_BYTE *zero; CK_RV rc; UNUSED(tokdata); UNUSED(sess); switch (keytype) { case CKK_AES: case CKK_AES_XTS: case CKK_GENERIC_SECRET: case CKK_SHA_1_HMAC: case CKK_SHA224_HMAC: case CKK_SHA256_HMAC: case CKK_SHA384_HMAC: case CKK_SHA512_HMAC: case CKK_SHA3_224_HMAC: case CKK_SHA3_256_HMAC: case CKK_SHA3_384_HMAC: case CKK_SHA3_512_HMAC: case CKK_SHA512_224_HMAC: case CKK_SHA512_256_HMAC: rc = template_build_update_attribute(obj->template, CKA_VALUE_LEN, (CK_BYTE *)&value_len, sizeof(value_len)); if (rc != CKR_OK) { TRACE_ERROR("%s template_build_update_attribute failed with " "rc=0x%lx\n", __func__, rc); return rc; } /* Add all zero CKA_VALUE (needed by object_mgr_add) */ zero = calloc(1, value_len); if (zero == NULL) { TRACE_ERROR("%s Failed to allocate dummy buffer of %lu bytes\n", __func__, value_len); return CKR_HOST_MEMORY; } rc = template_build_update_attribute(obj->template, CKA_VALUE, zero, value_len); free(zero); if (rc != CKR_OK) { TRACE_ERROR("%s template_build_update_attribute failed with " "rc=0x%lx\n", __func__, rc); return rc; } break; } return CKR_OK; } static CK_RV import_blob_update_attrs(STDLL_TokData_t *tokdata, SESSION *sess, OBJECT *obj, XCP_Attr_t *bool_attrs, CK_OBJECT_CLASS class, CK_KEY_TYPE keytype) { CK_ATTRIBUTE *attr; CK_ULONG i; CK_BBOOL blob_val, user_val; TEMPLATE *tmpl; CK_RV rc = CKR_OK; tmpl = calloc(1, sizeof(TEMPLATE)); if (tmpl == NULL) { TRACE_ERROR("%s allocate template failed\n", __func__); return CKR_HOST_MEMORY; } for (i = 0; ep11_pkcs11_attr_map[i].ep11_attr != 0; i++) { blob_val = (*bool_attrs & ep11_pkcs11_attr_map[i].ep11_attr) != 0 ? CK_TRUE : CK_FALSE; if (template_attribute_find(obj->template, ep11_pkcs11_attr_map[i].pkcs11_attr, &attr) && attr->ulValueLen == sizeof(CK_BBOOL) && attr->pValue != NULL) { user_val = *((CK_BBOOL *)attr->pValue); ep11tok_endecaps_combine_attrs(obj->template, keytype, class, ep11_pkcs11_attr_map[i].pkcs11_attr, &user_val); if (blob_val != user_val && ((user_val == FALSE && ep11_pkcs11_attr_map[i].can_set_to_false) || (user_val == TRUE && ep11_pkcs11_attr_map[i].can_set_to_true))) { /* Attribute was updated, add it */ rc = template_build_update_attribute(tmpl, attr->type, (CK_BYTE *)&user_val, sizeof(user_val)); if (rc != CKR_OK) { TRACE_ERROR("%s template_build_update_attribute failed " "rc=0x%lx\n", __func__, rc); goto out; } } } } if (tmpl->attribute_list != NULL) { if ((*bool_attrs & XCP_BLOB_MODIFIABLE) == 0) { TRACE_ERROR("%s The blob has CKA_MODIFIABLE=FALSE, attributes can not " "be modified\n", __func__); rc = CKR_ATTRIBUTE_VALUE_INVALID; goto out; } /* Check if the attributes are allowed to be modified that way */ rc = template_validate_attributes(tokdata, tmpl, class, keytype, MODE_MODIFY); if (rc != CKR_OK) { TRACE_ERROR("%s template_validate_attributes failed rc=0x%lx\n", __func__, rc); goto out; } rc = token_specific_set_attribute_values(tokdata, sess, obj, tmpl); if (rc != CKR_OK) { TRACE_ERROR("%s token_specific_set_attribute_values failed " "rc=0x%lx\n", __func__, rc); goto out; } rc = template_merge(obj->template, &tmpl); if (rc != CKR_OK) { TRACE_ERROR("%s template_merge failed rc=0x%lx\n", __func__, rc); goto out; } } out: if (tmpl != NULL) template_free(tmpl); return rc; } struct check_uv_session_data { STDLL_TokData_t *tokdata; CK_BYTE *session_id; CK_BBOOL found; }; static CK_RV check_uv_session_handler(uint_32 adapter, uint_32 domain, void *handler_data) { struct check_uv_session_data *data = handler_data; CK_MECHANISM mech = { CKM_AES_KEY_GEN, NULL_PTR, 0 }; CK_BYTE blob[MAX_BLOBSIZE]; CK_BYTE csum[MAX_CSUMSIZE]; size_t csum_l = sizeof(csum), blob_l = sizeof(blob); CK_ULONG len = 32; CK_BBOOL cktrue = 1; CK_ATTRIBUTE wrap_tmpl[] = { { CKA_VALUE_LEN, &len, sizeof(CK_ULONG) }, { CKA_WRAP, &cktrue, sizeof(cktrue) }, { CKA_UNWRAP, &cktrue, sizeof(cktrue) }, { CKA_ENCRYPT, &cktrue, sizeof(cktrue) }, { CKA_DECRYPT, &cktrue, sizeof(cktrue) }, { CKA_EXTRACTABLE, &cktrue, sizeof(cktrue) }, }; CK_ULONG wrap_tmpl_len = sizeof(wrap_tmpl) / sizeof(CK_ATTRIBUTE); target_t target = 0; CK_BYTE *uv_session = NULL; CK_RV rc; if (data->found) /* Already found a matching UV session */ return CKR_OK; rc = get_ep11_target_for_apqn(adapter, domain, &target, 0); if (rc != CKR_OK) return rc; /* Generate a temporary key on this APQN to get its UV session */ rc = dll_m_GenerateKey(&mech, wrap_tmpl, wrap_tmpl_len, NULL, 0, blob, &blob_l, csum, &csum_l, target); if (rc != CKR_OK) { TRACE_DEVEL("%s Failed to generate temporary AES key on APQN %02X.%04X " "rc=0x%lx\n", __func__, adapter, domain, rc); /* Ignore the error, APQN might be offline, etc */ rc = CKR_OK; goto out; } if (check_expected_mkvp(data->tokdata, blob, blob_l, NULL) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); rc = CKR_DEVICE_ERROR; goto out; } rc = ep11tok_extract_blob_info(blob, blob_l, NULL, NULL, &uv_session, NULL); if (rc != CKR_OK) { TRACE_ERROR("ep11tok_extract_blob_info failed\n"); goto out; } if (uv_session != NULL && data->session_id != NULL && memcmp(data->session_id, uv_session, XCP_WK_BYTES) == 0) { TRACE_DEVEL("Session matches the UV session of APQN %02X.%04X\n", adapter, domain); data->found = TRUE; } out: free_ep11_target_for_apqn(target); return rc; } static CK_RV import_blob(STDLL_TokData_t *tokdata, SESSION *sess, OBJECT *obj, CK_OBJECT_CLASS class, CK_KEY_TYPE keytype, CK_BYTE *blob, CK_ULONG blob_len) { ep11_private_data_t *ep11_data = tokdata->private_data; ep11_session_t *ep11_session = (ep11_session_t *)sess->private_data; CK_BYTE *ep11_pin_blob = NULL; CK_ULONG ep11_pin_blob_len = 0; CK_BBOOL is_new_mk, is_new_mk2, is_spki; XCP_Attr_t *bool_attrs = NULL; CK_BYTE *session_id = NULL, *session_id2 = NULL, *exp_session = NULL; const CK_BYTE zero_session[XCP_WK_BYTES] = { 0 }; CK_BYTE maced_spki[MAX_BLOBSIZE]; CK_BYTE blob_reenc[MAX_BLOBSIZE]; CK_ULONG maced_spki_len = sizeof(maced_spki); ep11_target_info_t* target_info; int curve_type; CK_BYTE *useblob = NULL, *blob2; size_t useblob_len = 0, blob1_len, blob2_len; CK_KEY_TYPE blob_type = CK_UNAVAILABLE_INFORMATION; CK_KEY_TYPE blob_type2 = CK_UNAVAILABLE_INFORMATION; CK_KEY_TYPE exp_keytype; CK_ULONG value_len, value_len2, stdcomp, stdcomp2; CK_BYTE buf[MAX_BLOBSIZE]; CK_ATTRIBUTE get_attr_pub[] = { { CKA_KEY_TYPE, &blob_type, sizeof(blob_type) }, }; CK_ULONG get_attr_pub_num = sizeof(get_attr_pub) / sizeof(CK_ATTRIBUTE); CK_ATTRIBUTE get_attr_priv[] = { { CKA_KEY_TYPE, &blob_type, sizeof(blob_type) }, { CKA_IBM_STD_COMPLIANCE1, &stdcomp, sizeof(stdcomp) }, { CKA_PUBLIC_KEY_INFO, &buf, sizeof(buf) }, }; CK_ULONG get_attr_priv_num = sizeof(get_attr_priv) / sizeof(CK_ATTRIBUTE); CK_ATTRIBUTE get_attr_sec[] = { { CKA_KEY_TYPE, &blob_type, sizeof(blob_type) }, { CKA_VALUE_LEN, &value_len, sizeof(value_len) }, { CKA_IBM_STD_COMPLIANCE1, &stdcomp, sizeof(stdcomp) }, }; CK_ULONG get_attr_sec_num = sizeof(get_attr_sec) / sizeof(CK_ATTRIBUTE); CK_ATTRIBUTE *get_attr = NULL; CK_ULONG get_attr_num = 0; CK_ATTRIBUTE get_attr2[] = { { CKA_KEY_TYPE, &blob_type2, sizeof(blob_type2) }, { CKA_VALUE_LEN, &value_len2, sizeof(value_len2) }, { CKA_IBM_STD_COMPLIANCE1, &stdcomp2, sizeof(stdcomp2) }, }; CK_ULONG get_attr2_num = sizeof(get_attr2) / sizeof(CK_ATTRIBUTE); CK_BBOOL in_sel_guest = FALSE; struct check_uv_session_data uv_data; CK_RV rc; rc = ep11tok_extract_blob_info(blob, keytype == CKK_AES_XTS ? blob_len / 2 : blob_len, &is_spki, NULL, &session_id, &bool_attrs); if (rc != CKR_OK) { TRACE_ERROR("ep11tok_extract_blob_info failed\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } if (keytype == CKK_AES_XTS) { rc = ep11tok_extract_blob_info(blob + blob_len / 2, blob_len / 2, NULL, NULL, &session_id2, NULL); if (rc != CKR_OK) { TRACE_ERROR("ep11tok_extract_blob_info failed\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } #ifndef NO_PKEY rc = ep11tok_pkey_check_aes_xts(tokdata, obj, CKM_AES_XTS); #else rc = CKR_FUNCTION_NOT_SUPPORTED; #endif if (rc != CKR_OK) { TRACE_ERROR("%s EP11 AES XTS is not supported: rc=0x%lx\n", __func__, rc); return rc; } } if (is_spki && class != CKO_PUBLIC_KEY) { TRACE_ERROR("Key blob is an SPKI but import is not for a public key\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } if (!is_spki && class == CKO_PUBLIC_KEY) { TRACE_ERROR("Public key import requres a SPKI.\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } if (is_spki && session_id == NULL) { /* Raw (un-MACed) SPKI: MAC it */ curve_type = get_curve_type_from_spki(blob, blob_len); rc = make_maced_spki(tokdata, sess, obj, NULL, 0, blob, blob_len, maced_spki, blob_reenc, &maced_spki_len, curve_type); if (rc != CKR_OK) { TRACE_ERROR("make_maced_spki failed\n"); return rc; } rc = template_build_update_attribute(obj->template, CKA_IBM_OPAQUE, maced_spki, maced_spki_len); if (rc != CKR_OK) { TRACE_ERROR("template_build_update_attribute failed for " "CKA_IBM_OPAQUE\n"); return rc; } blob = maced_spki; blob_len = maced_spki_len; } ep11_get_pin_blob(tokdata, ep11_session, object_is_session_object(obj), object_is_private(obj), &ep11_pin_blob, &ep11_pin_blob_len); if (ep11_pin_blob == NULL) { /* * In a secure execution guest keys might be bound to the ultravisor * session. Get the UV session ID (if any) from the wrap blob. * Note that if multipe domains of the same card(s) are available, * then each domain uses its own ultravisor session. */ rc = ep11tok_extract_blob_info(ep11_data->raw2key_wrap_blob, ep11_data->raw2key_wrap_blob_l, NULL, NULL, &exp_session, NULL); if (rc != CKR_OK) { TRACE_ERROR("extract_blob_info failed for wrap blob\n"); return rc; } if (memcmp(exp_session, zero_session, XCP_WK_BYTES) == 0) exp_session = NULL; /* No UV session, not running in an SEL guest */ else in_sel_guest = TRUE; /* Running in an SEL guest */ } else { exp_session = ep11_pin_blob; } /* Check if session bound and if so for valid session */ if (session_id == NULL || memcmp(session_id, zero_session, XCP_WK_BYTES) == 0) session_id = NULL; if (keytype == CKK_AES_XTS && memcmp(session_id2, zero_session, XCP_WK_BYTES) == 0) session_id2 = NULL; if (keytype == CKK_AES_XTS) { /* * AES-XTS key pair: either both are not session bound, * or both are bound to the same session. */ if ((session_id == NULL && session_id2 != NULL) || (session_id != NULL && session_id2 == NULL)) { TRACE_ERROR("AES-XTS key blob is inconsistent\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } if (session_id != NULL && session_id2 != NULL && !in_sel_guest && memcmp(session_id, session_id2, XCP_WK_BYTES) != 0) { TRACE_ERROR("AES-XTS key blob is inconsistent\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } } if (exp_session == NULL && session_id != NULL) { TRACE_ERROR("Key blob must not be session bound\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } if (exp_session != NULL && session_id == NULL) { TRACE_ERROR("Key blob must be session bound, but it is not\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } if (exp_session != NULL && session_id != NULL && !in_sel_guest && memcmp(exp_session, session_id, XCP_WK_BYTES) != 0) { TRACE_ERROR("Key blob is bound to an unexpected session\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } if (exp_session != NULL && session_id != NULL && in_sel_guest) { uv_data.tokdata = tokdata; uv_data.session_id = session_id; uv_data.found = FALSE; rc = handle_all_ep11_cards(&ep11_data->target_list, check_uv_session_handler, &uv_data); if (rc != CKR_OK) { TRACE_ERROR("handle_all_ep11_cards failed for check UV session\n"); return rc; } if (!uv_data.found) { TRACE_ERROR("Key blob is not bound to an expected UV session\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } if (keytype == CKK_AES_XTS && session_id2 != NULL) { uv_data.tokdata = tokdata; uv_data.session_id = session_id2; uv_data.found = FALSE; rc = handle_all_ep11_cards(&ep11_data->target_list, check_uv_session_handler, &uv_data); if (rc != CKR_OK) { TRACE_ERROR("handle_all_ep11_cards failed for check UV " "session (2nd AES-XTS key)\n"); return rc; } if (!uv_data.found) { TRACE_ERROR("2nd key of AES-XTS key blob is not bound to an " "expected UV session\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } } } /* Check for valid master key */ if (check_expected_mkvp(tokdata, blob, keytype == CKK_AES_XTS ? blob_len / 2 : blob_len, &is_new_mk) != CKR_OK) { TRACE_ERROR("Key blob has an invalid WKVP\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } if (keytype == CKK_AES_XTS) { if (check_expected_mkvp(tokdata, blob + blob_len / 2, blob_len / 2, &is_new_mk2) != CKR_OK) { TRACE_ERROR("Key blob has an invalid WKVP\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } if (is_new_mk != is_new_mk2) { TRACE_ERROR("AES-XTS key blob is inconsistent\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } } if (ep11_data->mk_change_active) { if (is_new_mk) { /* Blob has new WK already: supply it in reencblob as well */ TRACE_DEVEL("%s Key blob has new WK\n", __func__); memcpy(blob_reenc, blob, blob_len); } else { target_info = get_target_info(tokdata); if (target_info == NULL) return CKR_FUNCTION_FAILED; /* Key has old WK, re-encipher it */ TRACE_DEVEL("%s Key blob has old WK, reencipher it\n", __func__); rc = ep11tok_reencipher_blob(tokdata, sess, &target_info, blob, keytype == CKK_AES_XTS ? blob_len / 2 : blob_len, blob_reenc); if (rc == CKR_OK && keytype == CKK_AES_XTS) { rc = ep11tok_reencipher_blob(tokdata, sess, &target_info, blob + blob_len / 2,blob_len / 2, blob_reenc + blob_len / 2); } put_target_info(tokdata, target_info); if (rc != CKR_OK) { TRACE_ERROR("%s new WK has just been activated, can not " "reencipher key blob\n", __func__); return CKR_ATTRIBUTE_VALUE_INVALID; } } rc = template_build_update_attribute(obj->template, CKA_IBM_OPAQUE_REENC, blob_reenc, blob_len); if (rc != CKR_OK) { TRACE_ERROR("template_build_update_attribute failed for " "CKA_IBM_OPAQUE_REENC\n"); return rc; } } switch (class) { case CKO_PUBLIC_KEY: get_attr = get_attr_pub; get_attr_num = get_attr_pub_num; break; case CKO_PRIVATE_KEY: get_attr = get_attr_priv; get_attr_num = get_attr_priv_num; break; case CKO_SECRET_KEY: get_attr = get_attr_sec; get_attr_num = get_attr_sec_num; break; default: return CKR_KEY_TYPE_INCONSISTENT; } /* Get Key type and SPKI for private keys */ blob1_len = keytype == CKK_AES_XTS ? blob_len / 2 : blob_len; RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_BLOB_START(tokdata, target_info, obj, blob, blob1_len, useblob, useblob_len, rc) rc = dll_m_GetAttributeValue(useblob, useblob_len, get_attr, get_attr_num, target_info->target); RETRY_REENC_BLOB_END(tokdata, target_info, useblob, useblob_len, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, sess) if (rc == CKR_OK && keytype == CKK_AES_XTS) { blob2 = blob + blob_len / 2; blob2_len = blob_len / 2; RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_BLOB_START(tokdata, target_info, obj, blob2, blob2_len, useblob, useblob_len, rc) rc = dll_m_GetAttributeValue(useblob, useblob_len, get_attr2, get_attr2_num, target_info->target); RETRY_REENC_BLOB_END(tokdata, target_info, useblob, useblob_len, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, sess) } if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, NULL); TRACE_ERROR("%s m_GetAttributeValue failed rc=0x%lx\n", __func__, rc); if (class == CKO_PRIVATE_KEY && rc != CKR_SESSION_CLOSED) { /* This is most likely due to a missing EP11 firmware fix */ TRACE_DEVEL("%s possibly caused by missing EP11 firmware fix?\n", __func__); return CKR_PUBLIC_KEY_INVALID; /* Indicate this situation */ } return rc; } exp_keytype = keytype; ep11tok_pkcs11_keytype_translate(tokdata, exp_keytype, &exp_keytype); if (keytype != CKK_AES_XTS && blob_type != exp_keytype) { TRACE_ERROR("%s Key blob is not of the expected type: 0x%lx expectd " "0x%lx\n", __func__, blob_type, exp_keytype); if (blob_type == 0x80ffffff || blob_type == CK_UNAVAILABLE_INFORMATION) return CKR_PUBLIC_KEY_INVALID; /* Old firmware indication */ return CKR_KEY_TYPE_INCONSISTENT; } if (keytype == CKK_AES_XTS) { if ((blob_type != blob_type2 || value_len != value_len2 || stdcomp != stdcomp2)) { TRACE_ERROR("AES-XTS key blob is inconsistent\n"); if (blob_type2 == 0x80ffffff || blob_type2 == CK_UNAVAILABLE_INFORMATION) return CKR_PUBLIC_KEY_INVALID; /* Old firmware indication */ return CKR_ATTRIBUTE_VALUE_INVALID; } value_len *= 2; if (blob_type != CKK_AES) { TRACE_ERROR("%s Key blob is not of the expected type: 0x%lx " "expectd 0x%x\n", __func__, blob_type, CKK_AES); return CKR_KEY_TYPE_INCONSISTENT; } } switch (class) { case CKO_PUBLIC_KEY: rc = import_blob_private_public(tokdata, sess, obj, keytype, blob, blob_len, TRUE); if (rc != CKR_OK) { TRACE_ERROR("%s import_blob_public failed rc=0x%lx\n", __func__, rc); return rc; } break; case CKO_PRIVATE_KEY: rc = import_blob_private_public(tokdata, sess, obj, keytype, get_attr_priv[get_attr_priv_num - 1].pValue, get_attr_priv[get_attr_priv_num - 1].ulValueLen, FALSE); if (rc != CKR_OK) { TRACE_ERROR("%s import_blob_public failed rc=0x%lx\n", __func__, rc); return rc; } break; case CKO_SECRET_KEY: rc = import_blob_secret(tokdata, sess, obj, keytype, value_len); if (rc != CKR_OK) { TRACE_ERROR("%s import_blob_secret failed rc=0x%lx\n", __func__, rc); return rc; } break; } if (class != CKO_PUBLIC_KEY) { rc = template_build_update_attribute(obj->template, CKA_IBM_STD_COMPLIANCE1, (CK_BYTE *)&stdcomp, sizeof(stdcomp)); if (rc != CKR_OK) { TRACE_ERROR("%s template_build_update_attribute failed rc=0x%lx\n", __func__, rc); return rc; } /* Set CKA_ALWAYS_SENSITIVE and CKA_NEVER_EXTRACTABLE */ rc = key_mgr_apply_always_sensitive_never_extractable_attrs(tokdata, obj); if (rc != CKR_OK) { TRACE_ERROR("%s key_mgr_apply_always_sensitive_never_extractable_attrs " "failed with rc=0x%lx\n", __func__, rc); return rc; } } /* check if bool attrs are changed during import, and apply if so */ rc = import_blob_update_attrs(tokdata, sess, obj, bool_attrs, class, keytype); if (rc != CKR_OK) { TRACE_ERROR("%s import_blob_update_attrs failed with rc=0x%lx\n", __func__, rc); return rc; } return CKR_OK; } CK_RV token_specific_object_add(STDLL_TokData_t * tokdata, SESSION * sess, OBJECT * obj) { ep11_private_data_t *ep11_data = tokdata->private_data; CK_KEY_TYPE keytype; CK_ATTRIBUTE *attr = NULL; CK_BYTE blob[MAX_BLOBSIZE]; CK_BYTE blobreenc[MAX_BLOBSIZE]; size_t blobsize = sizeof(blob); CK_BYTE spki[MAX_BLOBSIZE]; size_t spkisize = sizeof(spki); CK_RV rc; CK_ULONG class; CK_BBOOL attrbound; CK_BYTE *temp; CK_ULONG temp_len; /* get key type */ rc = template_attribute_get_ulong(obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { /* not a key, so nothing to do. Just return. */ return CKR_OK; } /* Check that we do not try to create an attribute bound private key. */ /* need class for private/public key info */ rc = template_attribute_get_ulong(obj->template, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); return rc; } rc = template_attribute_get_bool(obj->template, CKA_IBM_ATTRBOUND, &attrbound); if (rc == CKR_TEMPLATE_INCOMPLETE) { attrbound = false; } else if (rc != CKR_OK) { TRACE_ERROR("Incomplete CKA_IBM_ATTRBOUND attribute for the key.\n"); return rc; } if (class != CKO_PUBLIC_KEY && attrbound) { TRACE_ERROR("Cannot create attribute bound private key via C_CreateObject.\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } /* Ensure the wrap blob is available */ rc = make_wrapblob(tokdata, sess); if (rc != CKR_OK) { TRACE_ERROR("%s make_wrapblob rc=0x%lx\n", __func__, rc); return rc; } #ifndef NO_PKEY /* Ensure the firmware master key verification pattern is available */ rc = ep11tok_pkey_get_firmware_mk_vp(tokdata, sess); if (rc != CKR_OK && rc != CKR_FUNCTION_NOT_SUPPORTED) return rc; #endif /* NO_PKEY */ memset(blob, 0, sizeof(blob)); memset(blobreenc, 0, sizeof(blobreenc)); /* Check for key blob import */ if (template_attribute_find(obj->template, CKA_IBM_OPAQUE, &attr) && attr->ulValueLen > 0 && attr->pValue != NULL) { rc = import_blob(tokdata, sess, obj, class, keytype, (CK_BYTE *)attr->pValue, attr->ulValueLen); if (rc != CKR_OK) { TRACE_ERROR("%s import_blob rc=0x%lx\n", __func__, rc); return rc; } return CKR_OK; } /* only these keys can be imported */ switch (keytype) { case CKK_RSA: rc = import_RSA_key(tokdata, sess, obj, blob, blobreenc, &blobsize, spki, &spkisize); if (rc != CKR_OK) { TRACE_ERROR("%s import RSA key rc=0x%lx blobsize=0x%zx\n", __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: case CKK_EC_EDWARDS: case CKK_EC_MONTGOMERY: rc = import_EC_key(tokdata, sess, obj, blob, blobreenc, &blobsize, spki, &spkisize, keytype); 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, blobreenc, &blobsize, spki, &spkisize); 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, blobreenc, &blobsize, spki, &spkisize); 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: case CKK_IBM_PQC_KYBER: case CKK_IBM_ML_DSA: case CKK_IBM_ML_KEM: case CKK_ML_DSA: case CKK_ML_KEM: rc = import_pqc_key(tokdata, sess, obj, keytype, blob, blobreenc, &blobsize, spki, &spkisize); if (rc != CKR_OK) { TRACE_ERROR("%s import PQC key kytype=0x%lx rc=0x%lx blobsize=0x%zx\n", __func__, keytype, rc, blobsize); return rc; } TRACE_INFO("%s import PQC key kytype=0x%lx rc=0x%lx blobsize=0x%zx\n", __func__, keytype, rc, blobsize); break; case CKK_DES2: case CKK_DES3: case CKK_AES: case CKK_GENERIC_SECRET: case CKK_SHA_1_HMAC: case CKK_SHA224_HMAC: case CKK_SHA256_HMAC: case CKK_SHA384_HMAC: case CKK_SHA512_HMAC: case CKK_SHA3_224_HMAC: case CKK_SHA3_256_HMAC: case CKK_SHA3_384_HMAC: case CKK_SHA3_512_HMAC: case CKK_SHA512_224_HMAC: case CKK_SHA512_256_HMAC: /* get key value */ rc = template_attribute_get_non_empty(obj->template, CKA_VALUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); return rc; } /* 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, blobreenc, &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; case CKK_AES_XTS: rc = import_aes_xts_key(tokdata, sess, obj, blob, blobreenc, &blobsize); if (rc != CKR_OK) { TRACE_ERROR("%s import AES XTS key rc=0x%lx blobsize=0x%zx\n", __func__, rc, blobsize); return rc; } TRACE_INFO("%s import AES XTS key rc=0x%lx blobsize=0x%zx\n", __func__, rc, blobsize); break; default: return CKR_KEY_FUNCTION_NOT_PERMITTED; } if (check_expected_mkvp(tokdata, blob, keytype == CKK_AES_XTS ? blobsize / 2 : blobsize, NULL) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } if (keytype == CKK_AES_XTS) { if (check_expected_mkvp(tokdata, blob + blobsize / 2, blobsize / 2, NULL) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } } /* 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); free(attr); return rc; } if (ep11_data->mk_change_active) { rc = build_attribute(CKA_IBM_OPAQUE_REENC, blobreenc, blobsize, &attr); if (rc != CKR_OK) { TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc); return rc; } rc = template_update_attribute(obj->template, attr); if (rc != CKR_OK) { TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n", __func__, rc); free(attr); return rc; } } if (spkisize > 0 && (class == CKO_PRIVATE_KEY || class == CKO_PUBLIC_KEY)) { /* spki may be a MACed SPKI, get length of SPKI part only */ rc = ber_decode_SEQUENCE(spki, spkisize, &temp, &temp_len, &spkisize); if (rc != CKR_OK) { TRACE_ERROR("%s ber_decode_SEQUENCE failed rc=0x%lx\n", __func__, rc); return rc; } rc = build_attribute(CKA_PUBLIC_KEY_INFO, spki, spkisize, &attr); if (rc != CKR_OK) { TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc); return rc; } rc = template_update_attribute(obj->template, attr); if (rc != CKR_OK) { TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n", __func__, rc); free(attr); return rc; } } rc = update_ep11_attrs_from_blob(tokdata, sess, obj, (keytype == CKK_AES_XTS)); if (rc != CKR_OK) { TRACE_ERROR("%s update_ep11_attrs_from_blob failed with rc=0x%lx\n", __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, CK_BBOOL count_statistics, CK_ULONG operation) { ep11_private_data_t *ep11_data = tokdata->private_data; CK_BYTE blob[MAX_BLOBSIZE], blob2[MAX_BLOBSIZE]; CK_BYTE reenc_blob[MAX_BLOBSIZE], reenc_blob2[MAX_BLOBSIZE]; size_t blobsize = sizeof(blob); size_t blobsize2 = sizeof(blob2); CK_BYTE csum[MAX_CSUMSIZE], csum2[MAX_CSUMSIZE];; size_t csum_len = sizeof(csum), csum2_len = sizeof(csum2); CK_ATTRIBUTE *attr = NULL; OBJECT *key_obj = NULL; CK_ULONG ktype; CK_ULONG class; CK_ATTRIBUTE_PTR new_attrs = NULL; CK_ATTRIBUTE_PTR new_attrs2 = NULL; CK_ULONG new_attrs_len = 0, new_attrs2_len = 0; CK_RV rc; CK_BOOL xts = FALSE, mapped_mech = FALSE; 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_MECHANISM mech2 = {0, NULL, 0}; CK_BBOOL blob_new_mk = FALSE, blob2_new_mk = FALSE; CK_ULONG mode; memset(blob, 0, sizeof(blob)); memset(reenc_blob, 0, sizeof(reenc_blob)); memset(csum, 0, sizeof(csum)); memset(blob2, 0, sizeof(blob2)); memset(csum2, 0, sizeof(csum2)); switch (operation) { case OP_KEYGEN: mode = MODE_KEYGEN; break; case OP_ENCAPSULATE: mode = MODE_ENCAPS; break; default: TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } /* Get the keytype to use when creating the key object */ rc = pkcs_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, -1); if (rc != CKR_OK) { TRACE_ERROR("%s check secret key attributes failed: rc=0x%lx\n", __func__, rc); goto error; } #ifndef NO_PKEY /* Ensure the firmware master key verification pattern is available */ rc = ep11tok_pkey_get_firmware_mk_vp(tokdata, session); if (rc != CKR_OK && rc != CKR_FUNCTION_NOT_SUPPORTED) goto error; #endif /* NO_PKEY */ rc = object_mgr_create_skel(tokdata, session, new_attrs, new_attrs_len, mode, 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_ep11_attrs(tokdata, key_obj->template, &new_attrs2, &new_attrs2_len, ktype, CKO_SECRET_KEY, -1, mech); if (rc != CKR_OK) { TRACE_ERROR("%s build_ep11_attrs failed with rc=0x%lx\n", __func__, rc); goto error; } switch (mech->mechanism){ case CKM_AES_XTS_KEY_GEN: xts = TRUE; mech2.mechanism = CKM_AES_KEY_GEN; mapped_mech = TRUE; #ifndef NO_PKEY rc = ep11tok_pkey_check_aes_xts(tokdata, key_obj, mech->mechanism); #else rc = CKR_FUNCTION_NOT_SUPPORTED; #endif if (rc != CKR_OK) { TRACE_ERROR("%s EP11 AES XTS is not supported: rc=0x%lx\n", __func__, rc); goto error; } break; case CKM_SHA_1_KEY_GEN: case CKM_SHA224_KEY_GEN: case CKM_SHA256_KEY_GEN: case CKM_SHA384_KEY_GEN: case CKM_SHA512_KEY_GEN: case CKM_SHA512_224_KEY_GEN: case CKM_SHA512_256_KEY_GEN: case CKM_SHA3_224_KEY_GEN: case CKM_SHA3_256_KEY_GEN: case CKM_SHA3_384_KEY_GEN: case CKM_SHA3_512_KEY_GEN: rc = ep11tok_pkcs11_mech_translate(tokdata, mech->mechanism, &mech2.mechanism); if (rc != CKR_OK) { TRACE_ERROR("%s ep11tok_pkcs11_mech_translate failed: rc=0x%lx\n", __func__, rc); goto error; } mapped_mech = TRUE; break; } trace_attributes(__func__, "Generate key:", new_attrs2, new_attrs2_len); ep11_get_pin_blob(tokdata, ep11_session, ep11_is_session_object(attrs, attrs_len), ep11_is_private_object(attrs, attrs_len), &ep11_pin_blob, &ep11_pin_blob_len); retry: RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_CREATE_KEY_START() rc = dll_m_GenerateKey(mapped_mech ? &mech2 : mech, new_attrs2, new_attrs2_len, ep11_pin_blob, ep11_pin_blob_len, blob, &blobsize, csum, &csum_len, target_info->target); RETRY_REENC_CREATE_KEY_END(tokdata, session, target_info, blob, reenc_blob, blobsize, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); TRACE_ERROR("%s m_GenerateKey rc=0x%lx mech='%s' attrs_len=0x%lx\n", __func__, rc, ep11_get_ckm(tokdata, mech->mechanism), attrs_len); goto error; } TRACE_INFO("%s m_GenerateKey rc=0x%lx mech='%s' attrs_len=0x%lx\n", __func__, rc, ep11_get_ckm(tokdata, mech->mechanism), attrs_len); if (check_expected_mkvp(tokdata, blob, blobsize, &blob_new_mk) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); rc = CKR_DEVICE_ERROR; goto error; } if (xts) { retry_xts: RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_CREATE_KEY_START() rc = dll_m_GenerateKey(&mech2, new_attrs2, new_attrs2_len, ep11_pin_blob, ep11_pin_blob_len, blob2, &blobsize2, csum2, &csum2_len, target_info->target); RETRY_REENC_CREATE_KEY_END(tokdata, session, target_info, blob2, reenc_blob2, blobsize2, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); TRACE_ERROR("%s m_GenerateKey rc=0x%lx mech='%s' attrs_len=0x%lx\n", __func__, rc, ep11_get_ckm(tokdata, mech->mechanism), attrs_len); goto error; } TRACE_INFO("%s m_GenerateKey rc=0x%lx mech='%s' attrs_len=0x%lx\n", __func__, rc, ep11_get_ckm(tokdata, mech->mechanism), attrs_len); if (check_expected_mkvp(tokdata, blob2, blobsize2, &blob2_new_mk) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); rc = CKR_DEVICE_ERROR; goto error; } if (ep11_data->mk_change_active && blob_new_mk != blob2_new_mk) { /* * New MK has been set after generating key 1 but before * generating key 2 */ if (blob2_new_mk == TRUE) { /* * Key 2 was created with new MK, key 1 with old MK. * Key 2 already has blob and reenc_blob with new MK, * Key 1 has blob with old MK, and blob_reenc with new MK. * Supply blob_reenc with new MK in blob also. */ memcpy(blob, reenc_blob, blobsize); } else { /* * Key 1 was created with new MK, but key 2 with old MK. * This can happen when the single APQN with new MK went offline * and a new single APQN with old MK is selected after creating * key 1 but before creating key 2. Since there is no key1 blob * with old MK, we need to re-create both keys (both with old * MK now). */ goto retry; } } /* Compare check sums to ensure the 2 key parts are not the same */ if (csum_len == csum2_len && memcmp(csum, csum2, csum_len) == 0) goto retry_xts; if (blobsize + blobsize2 > MAX_BLOBSIZE) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto error; } memcpy(blob + blobsize, blob2, blobsize2); if (ep11_data->mk_change_active) memcpy(reenc_blob + blobsize, reenc_blob2, blobsize2); blobsize = blobsize + blobsize2; } 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; } attr = NULL; if (ep11_data->mk_change_active) { rc = build_attribute(CKA_IBM_OPAQUE_REENC, reenc_blob, blobsize, &attr); if (rc != CKR_OK) { TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc); goto error; } rc = template_update_attribute(key_obj->template, attr); if (rc != CKR_OK) { TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n", __func__, rc); goto error; } attr = NULL; } rc = update_ep11_attrs_from_blob(tokdata, session, key_obj, xts); if (rc != CKR_OK) { TRACE_ERROR("%s update_ep11_attrs_from_blob failed with rc=0x%lx\n", __func__, rc); goto error; } if (!xts && csum_len >= EP11_CSUMSIZE) { /* First 3 bytes of csum is the check value */ rc = build_attribute(CKA_CHECK_VALUE, csum, EP11_CSUMSIZE, &attr); if (rc != CKR_OK) { TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc); goto error; } rc = template_update_attribute(key_obj->template, attr); if (rc != CKR_OK) { TRACE_ERROR("%s template_update_attribute failed with " "rc=0x%lx\n", __func__, rc); goto error; } attr = NULL; } /* add CKA_KEY_GEN_MECHANISM */ rc = build_attribute(CKA_KEY_GEN_MECHANISM, (CK_BYTE *)&mech->mechanism, sizeof(CK_MECHANISM_TYPE), &attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto error; } rc = template_update_attribute(key_obj->template, attr); if (rc != CKR_OK) { TRACE_ERROR("%s template_update_attribute failed with " "rc=0x%lx\n", __func__, rc); goto error; } attr = NULL; /* Set CKA_ALWAYS_SENSITIVE and CKA_NEVER_EXTRACTABLE */ rc = key_mgr_apply_always_sensitive_never_extractable_attrs(tokdata, key_obj); if (rc != CKR_OK) { TRACE_ERROR("%s key_mgr_apply_always_sensitive_never_extractable_attrs " "failed with rc=0x%lx\n", __func__, rc); goto error; } /* key should be fully constructed. * Assign an object handle and store key. * Enforce policy. */ 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; } if (count_statistics) INC_COUNTER(tokdata, session, mech, key_obj, POLICY_STRENGTH_IDX_0); goto done; error: if (key_obj) object_free(key_obj); if (attr != NULL) free(attr); *handle = 0; done: if (new_attrs) free_attribute_array(new_attrs, new_attrs_len); if (new_attrs2) free_attribute_array(new_attrs2, new_attrs2_len); return rc; } CK_BBOOL ep11tok_libica_digest_available(STDLL_TokData_t *tokdata, 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_SHA3_224: case CKM_IBM_SHA3_224: use_libica = ep11_data->libica.ica_sha3_224 != NULL; break; case CKM_SHA3_256: case CKM_IBM_SHA3_256: use_libica = ep11_data->libica.ica_sha3_256 != NULL; break; case CKM_SHA3_384: case CKM_IBM_SHA3_384: use_libica = ep11_data->libica.ica_sha3_384 != NULL; break; case CKM_SHA3_512: 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(tokdata, 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; case CKM_SHA3_224: case CKM_SHA3_224_RSA_PKCS: case CKM_ECDSA_SHA3_224: *digest_mech = CKM_SHA3_224; break; case CKM_SHA3_256: case CKM_SHA3_256_RSA_PKCS: case CKM_ECDSA_SHA3_256: *digest_mech = CKM_SHA3_256; break; case CKM_SHA3_384: case CKM_SHA3_384_RSA_PKCS: case CKM_ECDSA_SHA3_384: *digest_mech = CKM_SHA3_384; break; case CKM_SHA3_512: case CKM_SHA3_512_RSA_PKCS: case CKM_ECDSA_SHA3_512: *digest_mech = CKM_SHA3_512; break; default: return CKR_MECHANISM_INVALID; } return CKR_OK; } static CK_BBOOL ep11tok_ec_curve_supported2(STDLL_TokData_t *tokdata, TEMPLATE *template, const struct _ec **curve) { ep11_private_data_t *ep11_data = tokdata->private_data; CK_RV rc; CK_ATTRIBUTE *attr = NULL; CK_KEY_TYPE key_type; int i, status; const CK_VERSION ver3 = { .major = 3, .minor = 0 }; const CK_VERSION ver4_1_2 = { .major = 4, .minor = 0x12 }; *curve = NULL; rc = template_attribute_get_non_empty(template, CKA_ECDSA_PARAMS, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_ECDSA_PARAMS for the key.\n"); return CK_FALSE; } rc = template_attribute_get_ulong(template, CKA_KEY_TYPE, &key_type); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); return CK_FALSE; } for (i = 0; i < NUMEC; i++) { if (der_ec_supported[i].data_size == attr->ulValueLen && (memcmp(attr->pValue, der_ec_supported[i].data, attr->ulValueLen) == 0)) { *curve = &der_ec_supported[i]; break; } } if (*curve == NULL) { TRACE_DEVEL("%s EC curve not supported\n", __func__); return CK_FALSE; } switch ((*curve)->curve_type) { case PRIME_CURVE: case BRAINPOOL_CURVE: case KOBLITZ_CURVE: if (key_type != CKK_EC) { TRACE_INFO("%s Curve only supported for key type CKK_EC\n", __func__); return CK_FALSE; } break; case BLS12_381_CURVE: if (key_type != CKK_EC) { TRACE_INFO("%s Curve only supported for key type CKK_EC\n", __func__); return CK_FALSE; } if (compare_ck_version(&ep11_data->ep11_lib_version, &ver4_1_2) < 0) { TRACE_INFO("%s Curve requires host library version 4.1.2 or later\n", __func__); return CK_FALSE; } status = check_required_versions(tokdata, ibm_bls_req_versions, NUM_BLS_REQ); if (status != 1) { TRACE_INFO("%s Curve not supported due to mixed firmware versions\n", __func__); return CK_FALSE; } break; case MONTGOMERY_CURVE: case EDWARDS_CURVE: if ((*curve)->curve_type == MONTGOMERY_CURVE && key_type != CKK_EC_MONTGOMERY && key_type != CKK_EC) { TRACE_INFO("%s Curve only supported for key type " "CKK_EC_MONTGOMERY or CKK_EC\n", __func__); return CK_FALSE; } if ((*curve)->curve_type == EDWARDS_CURVE && key_type != CKK_EC_EDWARDS && key_type != CKK_EC) { TRACE_INFO("%s Curve only supported for key type CKK_EC_EDWARDS " "or CKK_EC\n", __func__); return CK_FALSE; } if (compare_ck_version(&ep11_data->ep11_lib_version, &ver3) < 0) { TRACE_INFO("%s Curve requires host library version 3 or later\n", __func__); return CK_FALSE; } status = check_required_versions(tokdata, edwards_req_versions, NUM_EDWARDS_REQ); if (status != 1) { TRACE_INFO("%s Curve not supported due to mixed firmware versions\n", __func__); return CK_FALSE; } break; default: TRACE_DEVEL("%s EC curve not supported\n", __func__); return CK_FALSE; } return CK_TRUE; } static CK_BBOOL ep11tok_ec_curve_supported(STDLL_TokData_t *tokdata, CK_OBJECT_HANDLE hKey) { CK_RV rc; OBJECT *key_obj; CK_BBOOL ret; const struct _ec *curve = NULL; 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; } ret = ep11tok_ec_curve_supported2(tokdata, key_obj->template, &curve); object_put(tokdata, key_obj, TRUE); key_obj = NULL; return ret; } 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: case CKM_ECDSA_SHA3_224: case CKM_ECDSA_SHA3_256: case CKM_ECDSA_SHA3_384: case CKM_ECDSA_SHA3_512: if (!ep11tok_ec_curve_supported(tokdata, hKey)) return CK_FALSE; break; } return ep11tok_libica_digest_available(tokdata, ep11_data, digest_mech); } CK_RV ep11tok_libica_digest(STDLL_TokData_t *tokdata, 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(tokdata, 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_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_SHA3_256: 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_SHA3_384: 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_SHA3_512: 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(tokdata, 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(tokdata, 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 * 2, sizeof(libica_sha_context_t)); size_t usestate_len = 0; CK_BYTE *state, *usestate; libica_sha_context_t *libica_ctx; ep11_target_info_t* target_info; CK_MECHANISM ep11_mech = *mech; state = calloc(state_len, 1); /* freed by dig_mgr.c */ if (!state) { TRACE_ERROR("%s Memory allocation failed\n", __func__); return CKR_HOST_MEMORY; } target_info = get_target_info(tokdata); if (target_info == NULL) { free(state); return CKR_FUNCTION_FAILED; } if (ep11tok_libica_digest_available(tokdata, 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 { ep11tok_pkcs11_mech_translate(tokdata, mech->mechanism, &ep11_mech.mechanism); /* * state is allocated large enough to hold 2 times the max state blob. * Initially use the first half only. The second half is for the * re-enciphered state blob (if mk change is active). */ state_len /= 2; RETRY_SINGLE_APQN_START(tokdata, rc) RETRY_UPDATE_BLOB_START(tokdata, target_info, state, state_len, state + state_len, state_len, usestate, usestate_len) rc = dll_m_DigestInit(usestate, &usestate_len, &ep11_mech, target_info->target); if (rc == CKR_OK && retry == 1) { /* * Initially, the real state_len is unknown, and is set to * allocated state size / 2. When the state was created on * an APQN with new WK set already, move the state to the * final place, which is state + usestate_len, where * usestate_len now is the real state size. */ memmove(state + usestate_len, state + state_len, usestate_len); } state_len = usestate_len; RETRY_UPDATE_BLOB_END(tokdata, NULL, target_info, state, state_len, state + state_len, state_len, usestate, usestate_len, rc) RETRY_SINGLE_APQN_END(rc, tokdata, target_info) } put_target_info(tokdata, target_info); 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 * 2; /* current and re-enciphered state */ 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; ep11_target_info_t* target_info; CK_BYTE *state; size_t state_len; target_info = get_target_info(tokdata); if (target_info == NULL) return CKR_FUNCTION_FAILED; if (ep11tok_libica_digest_available(tokdata, ep11_data, c->mech.mechanism)) { rc = ep11tok_libica_digest(tokdata, 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 { RETRY_SINGLE_APQN_START(tokdata, rc) RETRY_UPDATE_BLOB_START(tokdata, target_info, c->context, c->context_len / 2, c->context + (c->context_len / 2), c->context_len / 2, state, state_len) rc = dll_m_Digest(state, state_len, in_data, in_data_len, out_data, out_data_len, target_info->target); RETRY_UPDATE_BLOB_END(tokdata, NULL, target_info, c->context, c->context_len / 2, c->context + (c->context_len / 2), c->context_len / 2, state, state_len, rc) RETRY_SINGLE_APQN_END(rc, tokdata, target_info) } if (rc != CKR_OK) { 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); } put_target_info(tokdata, target_info); 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; ep11_target_info_t* target_info; CK_BYTE *state; size_t state_len; target_info = get_target_info(tokdata); if (target_info == NULL) return CKR_FUNCTION_FAILED; if (ep11tok_libica_digest_available(tokdata, 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(tokdata, 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(tokdata, 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 { RETRY_SINGLE_APQN_START(tokdata, rc) RETRY_UPDATE_BLOB_START(tokdata, target_info, c->context, c->context_len / 2, c->context + (c->context_len / 2), c->context_len / 2, state, state_len) rc = dll_m_DigestUpdate(state, state_len, in_data, in_data_len, target_info->target); RETRY_UPDATE_BLOB_END(tokdata, NULL, target_info, c->context, c->context_len / 2, c->context + (c->context_len / 2), c->context_len / 2, state, state_len, rc) RETRY_SINGLE_APQN_END(rc, tokdata, target_info) } out: 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); } put_target_info(tokdata, target_info); 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; ep11_target_info_t* target_info; CK_BYTE *state; size_t state_len; target_info = get_target_info(tokdata); if (target_info == NULL) return CKR_FUNCTION_FAILED; if (ep11tok_libica_digest_available(tokdata, ep11_data, c->mech.mechanism)) { rc = ep11tok_libica_digest(tokdata, 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 { RETRY_SINGLE_APQN_START(tokdata, rc) RETRY_UPDATE_BLOB_START(tokdata, target_info, c->context, c->context_len / 2, c->context + (c->context_len / 2), c->context_len / 2, state, state_len) rc = dll_m_DigestFinal(state, state_len, out_data, out_data_len, target_info->target); RETRY_UPDATE_BLOB_END(tokdata, NULL, target_info, c->context, c->context_len / 2, c->context + (c->context_len / 2), c->context_len / 2, state, state_len, rc) RETRY_SINGLE_APQN_END(rc, tokdata, target_info) } if (rc != CKR_OK) { 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); } put_target_info(tokdata, target_info); 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) { CK_RV rc; size_t keyblobsize = 0; CK_BYTE *keyblob; CK_MECHANISM mech; CK_BYTE *useblob = NULL; size_t useblobsize = 0; 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_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_BLOB_START(tokdata, target_info, key_obj, keyblob, keyblobsize, useblob, useblobsize, rc) rc = dll_m_SignSingle(useblob, useblobsize, &mech, in_data, in_data_len, out_data, out_data_len, target_info->target); RETRY_REENC_BLOB_END(tokdata, target_info, useblob, useblobsize, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); TRACE_ERROR("%s rc=0x%lx\n", __func__, rc); } 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) { CK_RV rc; CK_BYTE *spki; size_t spki_len = 0; CK_MECHANISM mech; CK_BYTE *useblob = NULL; size_t useblob_len = 0; 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_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_BLOB_START(tokdata, target_info, key_obj, spki, spki_len, useblob, useblob_len, rc) rc = dll_m_VerifySingle(useblob, useblob_len, &mech, in_data, in_data_len, signature, sig_len, target_info->target); RETRY_REENC_BLOB_END(tokdata, target_info, useblob, useblob_len, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); TRACE_ERROR("%s rc=0x%lx\n", __func__, rc); } 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) { CK_RV rc; size_t keyblobsize = 0; CK_BYTE *keyblob; OBJECT *key_obj; CK_MECHANISM mech; CK_BYTE *useblob = NULL; size_t useblobsize = 0; 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_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_BLOB_START(tokdata, target_info, key_obj, keyblob, keyblobsize, useblob, useblobsize, rc) rc = dll_m_SignSingle(useblob, useblobsize, &mech, in_data, in_data_len, sig, sig_len, target_info->target); RETRY_REENC_BLOB_END(tokdata, target_info, useblob, useblobsize, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); TRACE_ERROR("%s rc=0x%lx\n", __func__, rc); } 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) { CK_RV rc; CK_BYTE *spki; size_t spki_len = 0; OBJECT *key_obj; CK_MECHANISM mech; CK_BYTE *useblob = NULL; size_t useblob_len = 0; 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_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_BLOB_START(tokdata, target_info, key_obj, spki, spki_len, useblob, useblob_len, rc) rc = dll_m_VerifySingle(useblob, useblob_len, &mech, in_data, in_data_len, signature, sig_len, target_info->target); RETRY_REENC_BLOB_END(tokdata, target_info, useblob, useblob_len, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); TRACE_ERROR("%s rc=0x%lx\n", __func__, rc); } 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 ) { #ifndef NO_PKEY SIGN_VERIFY_CONTEXT *ctx = &(session->sign_ctx); #endif CK_RV rc; size_t keyblobsize = 0; CK_BYTE *keyblob; CK_MECHANISM mech; CK_BYTE *useblob = NULL; size_t useblobsize = 0; 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; } #ifndef NO_PKEY rc = ep11tok_pkey_check(tokdata, session, key_obj, &ctx->mech); switch (rc) { case CKR_OK: rc = pkey_ec_sign(tokdata, session, key_obj, in_data, in_data_len, out_data, out_data_len, NULL, ep11tok_pkey_convert_key); goto done; case CKR_FUNCTION_NOT_SUPPORTED: break; default: goto done; } #endif /* NO_PKEY */ mech.mechanism = CKM_ECDSA; mech.pParameter = NULL; mech.ulParameterLen = 0; RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_BLOB_START(tokdata, target_info, key_obj, keyblob, keyblobsize, useblob, useblobsize, rc) rc = dll_m_SignSingle(useblob, useblobsize, &mech, in_data, in_data_len, out_data, out_data_len, target_info->target); RETRY_REENC_BLOB_END(tokdata, target_info, useblob, useblobsize, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); TRACE_ERROR("%s rc=0x%lx\n", __func__, rc); } else { TRACE_INFO("%s rc=0x%lx\n", __func__, rc); } #ifndef NO_PKEY done: #endif 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 ) { #ifndef NO_PKEY SIGN_VERIFY_CONTEXT *ctx = &(session->verify_ctx); #endif CK_RV rc; CK_BYTE *spki; size_t spki_len = 0; CK_MECHANISM mech; CK_BYTE *useblob = NULL; size_t useblob_len = 0; 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; } #ifndef NO_PKEY rc = ep11tok_pkey_check(tokdata, session, key_obj, &ctx->mech); switch (rc) { case CKR_OK: rc = pkey_ec_verify(key_obj, in_data, in_data_len, out_data, out_data_len); goto done; case CKR_FUNCTION_NOT_SUPPORTED: break; default: goto done; } #endif /* NO_PKEY */ mech.mechanism = CKM_ECDSA; mech.pParameter = NULL; mech.ulParameterLen = 0; RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_BLOB_START(tokdata, target_info, key_obj, spki, spki_len, useblob, useblob_len, rc) rc = dll_m_VerifySingle(useblob, useblob_len, &mech, in_data, in_data_len, out_data, out_data_len, target_info->target); RETRY_REENC_BLOB_END(tokdata, target_info, useblob, useblob_len, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); TRACE_ERROR("%s rc=0x%lx\n", __func__, rc); } else { TRACE_INFO("%s rc=0x%lx\n", __func__, rc); } #ifndef NO_PKEY done: #endif return rc; } static CK_RV ep11tok_ec_edwards_mech_preprocess(STDLL_TokData_t *tokdata, OBJECT *key_obj, CK_MECHANISM *mech, CK_MECHANISM *ep11_mech) { CK_EDDSA_PARAMS* eddsa_params = NULL; CK_ATTRIBUTE *attr; CK_ULONG i; const struct _ec *curve = NULL; CK_RV rc; UNUSED(tokdata); if (mech->ulParameterLen == sizeof(CK_EDDSA_PARAMS) && mech->pParameter != NULL) { eddsa_params = mech->pParameter; if (eddsa_params->ulContextDataLen != 0 || eddsa_params->pContextData != NULL) { TRACE_ERROR("EP11 does not support a non-empty context\n"); return CKR_MECHANISM_PARAM_INVALID; } if (eddsa_params->phFlag) { TRACE_ERROR("EP11 does not support pre-hash\n"); return CKR_MECHANISM_PARAM_INVALID; } } rc = template_attribute_get_non_empty(key_obj->template, CKA_EC_PARAMS, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_EC_PARAMS for the key.\n"); return rc; } for (i = 0; i < NUMEC; i++) { if (der_ec_supported[i].data_size == attr->ulValueLen && (memcmp(attr->pValue, der_ec_supported[i].data, attr->ulValueLen) == 0)) { curve = &der_ec_supported[i]; break; } } if (curve == NULL || curve->curve_type != EDWARDS_CURVE) { TRACE_ERROR("Must be a Edwards curve\n"); return CKR_CURVE_NOT_SUPPORTED; } switch (curve->prime_bits) { case CURVE255: ep11_mech->mechanism = CKM_IBM_ED25519_SHA512; break; case CURVE448: if (eddsa_params == NULL) { TRACE_ERROR("Mechanism parameter is required for Ed448\n"); return CKR_MECHANISM_PARAM_INVALID; } ep11_mech->mechanism = CKM_IBM_ED448_SHA3; break; default: return CKR_CURVE_NOT_SUPPORTED; } ep11_mech->pParameter = NULL; ep11_mech->ulParameterLen = 0; return CKR_OK; } CK_RV token_specific_ec_edwards_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, CK_MECHANISM *mech) { CK_RV rc; size_t keyblobsize = 0; CK_BYTE *keyblob; CK_MECHANISM ep11_mech; CK_BYTE *useblob = NULL; size_t useblobsize = 0; rc = ep11tok_ec_edwards_mech_preprocess(tokdata, key_obj, mech, &ep11_mech); if (rc != CKR_OK) { TRACE_ERROR("%s ep11tok_ec_edwards_mech_preprocess failed rc=0x%lx\n", __func__, rc); return rc; } 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; } #ifndef NO_PKEY rc = ep11tok_pkey_check(tokdata, session, key_obj, mech); switch (rc) { case CKR_OK: rc = pkey_ed_sign(tokdata, session, key_obj, in_data, in_data_len, out_data, out_data_len, ep11tok_pkey_convert_key); goto done; case CKR_FUNCTION_NOT_SUPPORTED: break; default: goto done; } #endif /* NO_PKEY */ RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_BLOB_START(tokdata, target_info, key_obj, keyblob, keyblobsize, useblob, useblobsize, rc) rc = dll_m_SignSingle(useblob, useblobsize, &ep11_mech, in_data, in_data_len, out_data, out_data_len, target_info->target); RETRY_REENC_BLOB_END(tokdata, target_info, useblob, useblobsize, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); TRACE_ERROR("%s rc=0x%lx\n", __func__, rc); } else { TRACE_INFO("%s rc=0x%lx\n", __func__, rc); } #ifndef NO_PKEY done: #endif return rc; } CK_RV token_specific_ec_edwards_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, CK_MECHANISM *mech) { CK_RV rc; CK_BYTE *spki; size_t spki_len = 0; CK_MECHANISM ep11_mech; CK_BYTE *useblob = NULL; size_t useblob_len = 0; rc = ep11tok_ec_edwards_mech_preprocess(tokdata, key_obj, mech, &ep11_mech); if (rc != CKR_OK) { TRACE_ERROR("%s ep11tok_ec_edwards_mech_preprocess failed rc=0x%lx\n", __func__, rc); return rc; } 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; } #ifndef NO_PKEY rc = ep11tok_pkey_check(tokdata, session, key_obj, mech); switch (rc) { case CKR_OK: rc = pkey_ed_verify(key_obj, in_data, in_data_len, out_data, out_data_len, CKK_EC_EDWARDS); goto done; case CKR_FUNCTION_NOT_SUPPORTED: break; default: goto done; } #endif /* NO_PKEY */ RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_BLOB_START(tokdata, target_info, key_obj, spki, spki_len, useblob, useblob_len, rc) rc = dll_m_VerifySingle(useblob, useblob_len, &ep11_mech, in_data, in_data_len, out_data, out_data_len, target_info->target); RETRY_REENC_BLOB_END(tokdata, target_info, useblob, useblob_len, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); TRACE_ERROR("%s rc=0x%lx\n", __func__, rc); } else { TRACE_INFO("%s rc=0x%lx\n", __func__, rc); } #ifndef NO_PKEY done: #endif return rc; } CK_RV token_specific_reencrypt_single(STDLL_TokData_t *tokdata, SESSION *session, ENCR_DECR_CONTEXT *decr_ctx, CK_MECHANISM *decr_mech, OBJECT *decr_key_obj, ENCR_DECR_CONTEXT *encr_ctx, CK_MECHANISM *encr_mech, OBJECT *encr_key_obj, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len) { CK_RV rc; CK_BYTE *decr_key, *encr_key; size_t decr_key_len = 0, encr_key_len = 0; int status; CK_BYTE *decr_useblob = NULL, *encr_useblob = NULL; size_t decr_useblob_len = 0, encr_useblob_len = 0; UNUSED(decr_ctx); UNUSED(encr_ctx); if (dll_m_ReencryptSingle == NULL) return CKR_FUNCTION_NOT_SUPPORTED; status = check_required_versions(tokdata, reencrypt_single_req_versions, NUM_REENCRYPT_SINGLE_REQ); if (status != 1) return CKR_FUNCTION_NOT_SUPPORTED; rc = obj_opaque_2_blob(tokdata, decr_key_obj, &decr_key, &decr_key_len); if (rc != CKR_OK) { TRACE_ERROR("%s no decr-blob rc=0x%lx\n", __func__, rc); return rc; } rc = obj_opaque_2_blob(tokdata, encr_key_obj, &encr_key, &encr_key_len); if (rc != CKR_OK) { TRACE_ERROR("%s no encrr-blob rc=0x%lx\n", __func__, rc); return rc; } RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_BLOB2_START(tokdata, target_info, decr_key_obj, decr_key, decr_key_len, decr_useblob, decr_useblob_len, encr_key_obj, encr_key, encr_key_len, encr_useblob, encr_useblob_len, rc) rc = dll_m_ReencryptSingle(decr_useblob, decr_useblob_len, encr_useblob, encr_useblob_len, decr_mech, encr_mech, in_data, in_data_len, out_data, out_data_len, target_info->target); RETRY_REENC_BLOB2_END(tokdata, target_info, decr_useblob, decr_useblob_len, encr_useblob, encr_useblob_len, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); TRACE_ERROR("%s rc=0x%lx\n", __func__, rc); } else { TRACE_INFO("%s rc=0x%lx\n", __func__, rc); } return rc; } #ifndef NO_PKEY /** * This routine is currently only used when the operation is performed using * a protected key. Therefore we don't have (and don't need) an ep11 * fallback here. */ CK_RV token_specific_aes_ecb(STDLL_TokData_t *tokdata, SESSION *sess, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, OBJECT *key_obj, CK_BYTE encrypt) { return pkey_aes_ecb(tokdata, sess, key_obj, in_data, in_data_len, out_data, out_data_len, encrypt, ep11tok_pkey_convert_key); } /** * This routine is currently only used when the operation is performed using * a protected key. Therefore we don't have (and don't need) an ep11 * fallback here. */ CK_RV token_specific_aes_cbc(STDLL_TokData_t *tokdata, SESSION *sess, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, OBJECT *key_obj, CK_BYTE *init_v, CK_BYTE encrypt) { return pkey_aes_cbc(tokdata, sess, key_obj, init_v, in_data, in_data_len, out_data, out_data_len, encrypt, ep11tok_pkey_convert_key); } /** * This routine is currently only used when the operation is performed using * a protected key. Therefore we don't have (and don't need) an ep11 * fallback here. */ CK_RV token_specific_aes_cmac(STDLL_TokData_t *tokdata, SESSION *session, CK_BYTE *message, CK_ULONG message_len, OBJECT *key_obj, CK_BYTE *iv, CK_BBOOL first, CK_BBOOL last, CK_VOID_PTR *context) { CK_RV rc; UNUSED(context); if (first && last) rc = pkey_aes_cmac(tokdata, session, key_obj, message, message_len, iv, NULL, ep11tok_pkey_convert_key); else if (!last) rc = pkey_aes_cmac(tokdata, session, key_obj, message, message_len, NULL, iv, ep11tok_pkey_convert_key); else // last rc = pkey_aes_cmac(tokdata, session, key_obj, message, message_len, iv, iv, ep11tok_pkey_convert_key); return rc; } /** * This routine is currently only used when the operation is performed using * a protected key. Therefore we don't have (and don't need) an ep11 * fallback here. */ CK_RV token_specific_aes_xts(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, CK_BYTE *init_v, CK_BBOOL encrypt, CK_BBOOL initial, CK_BBOOL final, CK_BYTE *iv) { return pkey_aes_xts(tokdata, session, key_obj, init_v, in_data, in_data_len, out_data, out_data_len, encrypt, initial, final, iv, ep11tok_pkey_convert_key); } #endif /* NO_PKEY */ struct EP11_KEM_MECH { CK_MECHANISM mech; struct XCP_KYBER_KEM_PARAMS params; CK_ULONG blob_len; CK_BYTE blob[MAX_BLOBSIZE]; CK_BYTE reencblob[MAX_BLOBSIZE]; }; static CK_RV ep11tok_ml_kem_mech_pre_process(STDLL_TokData_t *tokdata, CK_MECHANISM *mech, struct EP11_KEM_MECH *mech_ep11, OBJECT **secret_key_obj, CK_BBOOL use_reenc_blob) { CK_IBM_ML_KEM_PARAMS *ml_kem_params; CK_RV rc; ml_kem_params = mech->pParameter; if (mech->ulParameterLen != sizeof(CK_IBM_ML_KEM_PARAMS)) { TRACE_ERROR("Mechanism parameter length not as expected\n"); return CKR_MECHANISM_PARAM_INVALID; } if (ml_kem_params->ulVersion != CK_IBM_ML_KEM_VERSION) { TRACE_ERROR("Unsupported version in ML-KEM mechanism param\n"); return CKR_MECHANISM_PARAM_INVALID; } mech_ep11->mech.mechanism = mech->mechanism; ep11tok_pkcs11_mech_translate(tokdata, mech_ep11->mech.mechanism, &mech_ep11->mech.mechanism); mech_ep11->mech.pParameter = &mech_ep11->params; mech_ep11->mech.ulParameterLen = sizeof(mech_ep11->params); memset(&mech_ep11->params, 0, sizeof(mech_ep11->params)); mech_ep11->params.version = XCP_KYBER_KEM_VERSION; mech_ep11->params.mode = ml_kem_params->mode; mech_ep11->params.kdf = ml_kem_params->kdf; mech_ep11->params.prepend = ml_kem_params->bPrepend; mech_ep11->params.pSharedData = ml_kem_params->pSharedData; mech_ep11->params.ulSharedDataLen = ml_kem_params->ulSharedDataLen; switch (ml_kem_params->mode) { case CK_IBM_ML_KEM_ENCAPSULATE: if (ml_kem_params->ulCipherLen > 0 && ml_kem_params->pCipher == NULL) { TRACE_ERROR("Unsupported cipher buffer in ML-KEM mechnism param " "cannot be NULL\n"); return CKR_MECHANISM_PARAM_INVALID; } mech_ep11->params.pCipher = NULL; mech_ep11->params.ulCipherLen = 0; /* Cipher is returned in 2nd output param of m_DeriveKey */ break; case CK_IBM_KEM_DECAPSULATE: mech_ep11->params.pCipher = ml_kem_params->pCipher; mech_ep11->params.ulCipherLen = ml_kem_params->ulCipherLen; break; default: TRACE_ERROR("Unsupported mode in ML-KEM mechanism param\n"); return CKR_MECHANISM_PARAM_INVALID; } if (ml_kem_params->hSecret != CK_INVALID_HANDLE) { if (*secret_key_obj != NULL) { object_put(tokdata, *secret_key_obj, TRUE); *secret_key_obj = NULL; } rc = h_opaque_2_blob(tokdata, ml_kem_params->hSecret, &mech_ep11->params.pBlob, &mech_ep11->params.ulBlobLen, secret_key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("h_opaque_2_blob failed hSecret=0x%lx\n", ml_kem_params->hSecret); return rc; } if (use_reenc_blob) { rc = obj_opaque_2_reenc_blob(tokdata, *secret_key_obj, &mech_ep11->params.pBlob, &mech_ep11->params.ulBlobLen); if (rc != CKR_OK && rc != CKR_TEMPLATE_INCOMPLETE) { TRACE_ERROR("obj_opaque_2_reenc_blob failed hSecret=0x%lx\n", ml_kem_params->hSecret); return rc; } } } return CKR_OK; } static CK_RV ep11tok_ml_kem_mech_post_process(STDLL_TokData_t *tokdata, CK_MECHANISM *mech, CK_BYTE *csum, CK_ULONG cslen) { CK_IBM_ML_KEM_PARAMS *ml_kem_params; CK_ULONG cipher_len; UNUSED(tokdata); ml_kem_params = mech->pParameter; if (mech->ulParameterLen != sizeof(CK_IBM_ML_KEM_PARAMS)) { TRACE_ERROR("Mechanism parameter length not as expected\n"); return CKR_MECHANISM_PARAM_INVALID; } if (ml_kem_params->mode != CK_IBM_ML_KEM_ENCAPSULATE) return CKR_OK; /* * For encapsulate: * Generated cipher is returned in csum prepended with the checksum of * the generated symmetric key and its bit count (in total 7 bytes). */ if (cslen < EP11_CSUMSIZE + 4) { TRACE_ERROR("%s returned cipher size is invalid: %lu\n", __func__, cslen); return CKR_FUNCTION_FAILED; } cipher_len = cslen - (EP11_CSUMSIZE + 4); if (ml_kem_params->ulCipherLen < cipher_len) { TRACE_ERROR("%s Cipher buffer in ML-KEM mechanism param too small, required: %lu\n", __func__, cipher_len); ml_kem_params->ulCipherLen = cipher_len; OPENSSL_cleanse(&csum[EP11_CSUMSIZE + 4], cipher_len); return CKR_BUFFER_TOO_SMALL; } memcpy(ml_kem_params->pCipher, &csum[EP11_CSUMSIZE + 4], cipher_len); ml_kem_params->ulCipherLen = cipher_len; OPENSSL_cleanse(&csum[EP11_CSUMSIZE + 4], cipher_len); return CKR_OK; } static CK_RV ep11tok_ml_kem_with_ecdh_mech_pre_process( STDLL_TokData_t *tokdata, SESSION *session, CK_MECHANISM *mech, struct EP11_KEM_MECH *mech_ep11, CK_BBOOL use_reenc_blob) { ep11_private_data_t *ep11_data = tokdata->private_data; ep11_session_t *ep11_session = (ep11_session_t *) session->private_data; CK_IBM_ML_KEM_WITH_ECDH_PARAMS *ml_kem_params; CK_BYTE *ec_key_blob = NULL; CK_ULONG ec_key_blob_len = 0; OBJECT *ec_key_obj = NULL; CK_ATTRIBUTE *ec_parms_attr = NULL; CK_ULONG privlen, ecpoint_len; CK_BYTE *ecpoint = NULL; CK_BBOOL allocated = FALSE; CK_ECDH1_DERIVE_PARAMS ecdh_params = { 0 }; CK_OBJECT_CLASS class = CKO_SECRET_KEY; CK_KEY_TYPE keytype = CKK_GENERIC_SECRET; CK_BBOOL ck_true = CK_TRUE; CK_MECHANISM ecdh_mech = { CKM_ECDH1_DERIVE, &ecdh_params, sizeof(ecdh_params) }; CK_ATTRIBUTE ecdh_attrs[] = { { CKA_CLASS, &class, sizeof(class) }, { CKA_KEY_TYPE, &keytype, sizeof(keytype) }, { CKA_VALUE_LEN, &privlen, sizeof(privlen) }, { CKA_IBM_USE_AS_DATA, &ck_true, sizeof(ck_true) }, }; CK_ULONG ecdh_attrs_len = sizeof(ecdh_attrs) / sizeof(CK_ATTRIBUTE); ep11_target_info_t* target_info; unsigned char *ep11_pin_blob = NULL; CK_ULONG ep11_pin_blob_len = 0; CK_BYTE csum[MAX_BLOBSIZE]; CK_ULONG cslen = sizeof(csum); CK_BYTE *useblob; size_t useblobsize; CK_RV rc; ml_kem_params = mech->pParameter; if (mech->ulParameterLen != sizeof(CK_IBM_ML_KEM_WITH_ECDH_PARAMS)) { TRACE_ERROR("Mechanism parameter length not as expected\n"); rc = CKR_MECHANISM_PARAM_INVALID; goto out; } /* Prepare ML-KEM mechanism and parameter */ mech_ep11->mech.mechanism = CKM_IBM_ML_KEM; mech_ep11->mech.pParameter = &mech_ep11->params; mech_ep11->mech.ulParameterLen = sizeof(mech_ep11->params); memset(&mech_ep11->params, 0, sizeof(mech_ep11->params)); mech_ep11->params.version = XCP_KYBER_KEM_VERSION; mech_ep11->params.mode = ml_kem_params->mode; mech_ep11->params.kdf = ml_kem_params->kdf; mech_ep11->params.prepend = FALSE; mech_ep11->params.pSharedData = ml_kem_params->pSharedData; mech_ep11->params.ulSharedDataLen = ml_kem_params->ulSharedDataLen; switch (ml_kem_params->mode) { case CK_IBM_ML_KEM_ENCAPSULATE: if (ml_kem_params->ulCipherLen > 0 && ml_kem_params->pCipher == NULL) { TRACE_ERROR("Unsupported cipher buffer in ML-KEM mechnism param " "cannot be NULL\n"); rc = CKR_MECHANISM_PARAM_INVALID; goto out; } mech_ep11->params.pCipher = NULL; mech_ep11->params.ulCipherLen = 0; /* Cipher is returned in 2nd output param of m_DeriveKey */ break; case CK_IBM_KEM_DECAPSULATE: mech_ep11->params.pCipher = ml_kem_params->pCipher; mech_ep11->params.ulCipherLen = ml_kem_params->ulCipherLen; break; default: TRACE_ERROR("Unsupported mode in ML-KEM mechanism param\n"); rc = CKR_MECHANISM_PARAM_INVALID; goto out; } /* Prepare for ECDH */ rc = h_opaque_2_blob(tokdata, ml_kem_params->hECPrivateKey, &ec_key_blob, &ec_key_blob_len, &ec_key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("%s failed hSecret=0x%lx\n", __func__, ml_kem_params->hECPrivateKey); goto out; } /* 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. * Also, the EP11 host library only accepts EC points in uncompressed * form, so uncompress it if in compressed or hybrid form. */ rc = get_ecsiglen(ec_key_obj, &privlen); privlen /= 2; if (rc != CKR_OK) { TRACE_ERROR("%s get_ecsiglen failed\n", __func__); goto out; } rc = template_attribute_get_non_empty(ec_key_obj->template, CKA_EC_PARAMS, &ec_parms_attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_EC_PARAMS in EC key\n"); goto out; } rc = ec_point_uncompressed_from_public_data(ml_kem_params->pPublicData, ml_kem_params->ulPublicDataLen, privlen, (CK_BYTE *) ec_parms_attr->pValue, ec_parms_attr->ulValueLen, TRUE, &allocated, &ecpoint, &ecpoint_len); if (rc != CKR_OK) { TRACE_DEVEL("ec_point_uncompressed_from_public_data failed\n"); goto out; } ecdh_params.kdf = CKD_IBM_HYBRID_NULL; ecdh_params.pPublicData = ecpoint; ecdh_params.ulPublicDataLen = ecpoint_len; ecdh_params.pSharedData = NULL; ecdh_params.ulSharedDataLen = 0; rc = tokdata->policy->is_mech_allowed(tokdata->policy, &ecdh_mech, &ec_key_obj->strength, POLICY_CHECK_DERIVE, session); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: derive key\n"); goto out; } if (!key_object_is_mechanism_allowed(ec_key_obj->template, ecdh_mech.mechanism)) { TRACE_ERROR("Mechanism not allowed per CKA_ALLOWED_MECHANISMS.\n"); rc = CKR_MECHANISM_INVALID; goto out; } /* * 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. */ target_info = get_target_info(tokdata); if (target_info == NULL) { rc = CKR_FUNCTION_FAILED; goto out; } if (target_info->used_firmware_API_version <= 2) { ecdh_mech.pParameter = ecpoint; ecdh_mech.ulParameterLen = ecpoint_len; } put_target_info(tokdata, target_info); /* Perform the ECDH */ ep11_get_pin_blob(tokdata, ep11_session, CK_TRUE, CK_TRUE, &ep11_pin_blob, &ep11_pin_blob_len); mech_ep11->blob_len = sizeof(mech_ep11->blob); RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_BLOB_START(tokdata, target_info, ec_key_obj, ec_key_blob, ec_key_blob_len, useblob, useblobsize, rc) RETRY_REENC_CREATE_KEY_START() if (ep11_pqc_obj_strength_supported(target_info, ecdh_mech.mechanism, ec_key_obj)) rc = dll_m_DeriveKey(&ecdh_mech, ecdh_attrs, ecdh_attrs_len, useblob, useblobsize, NULL, 0, ep11_pin_blob, ep11_pin_blob_len, mech_ep11->blob, &mech_ep11->blob_len, csum, &cslen, target_info->target); else rc = CKR_KEY_SIZE_RANGE; RETRY_REENC_CREATE_KEY_END(tokdata, session, target_info, mech_ep11->blob, mech_ep11->reencblob, mech_ep11->blob_len, rc) RETRY_REENC_BLOB_END(tokdata, target_info, useblob, useblobsize, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); TRACE_ERROR("%s m_DeriveKey failed rc=0x%lx \n", __func__, rc); goto out; } if (check_expected_mkvp(tokdata, mech_ep11->blob, mech_ep11->blob_len, NULL) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); rc = CKR_DEVICE_ERROR; goto out; } /* Set derived blob into KEM mechanism param */ mech_ep11->params.pBlob = (use_reenc_blob && ep11_data->mk_change_active) ? mech_ep11->reencblob : mech_ep11->blob; mech_ep11->params.ulBlobLen = mech_ep11->blob_len; out: if (allocated && ecpoint != NULL) free(ecpoint); object_put(tokdata, ec_key_obj, TRUE); ec_key_obj = NULL; return rc; } static CK_RV ep11tok_ml_kem_with_ecdh_mech_post_process( STDLL_TokData_t *tokdata, CK_MECHANISM *mech, CK_BYTE *csum, CK_ULONG cslen) { CK_IBM_ML_KEM_WITH_ECDH_PARAMS *ml_kem_params; CK_ULONG cipher_len; UNUSED(tokdata); ml_kem_params = mech->pParameter; if (mech->ulParameterLen != sizeof(CK_IBM_ML_KEM_WITH_ECDH_PARAMS)) { TRACE_ERROR("Mechanism parameter length not as expected\n"); return CKR_MECHANISM_PARAM_INVALID; } if (ml_kem_params->mode != CK_IBM_ML_KEM_ENCAPSULATE) return CKR_OK; /* * For encapsulate: * Generated cipher is returned in csum prepended with the checksum of * the generated symmetric key and its bit count (in total 7 bytes). */ if (cslen < EP11_CSUMSIZE + 4) { TRACE_ERROR("%s returned cipher size is invalid: %lu\n", __func__, cslen); return CKR_FUNCTION_FAILED; } cipher_len = cslen - (EP11_CSUMSIZE + 4); if (ml_kem_params->ulCipherLen < cipher_len) { TRACE_ERROR("%s Cipher buffer in ML-KEM mechanism param too small, required: %lu\n", __func__, cipher_len); ml_kem_params->ulCipherLen = cipher_len; OPENSSL_cleanse(&csum[EP11_CSUMSIZE + 4], cipher_len); return CKR_BUFFER_TOO_SMALL; } memcpy(ml_kem_params->pCipher, &csum[EP11_CSUMSIZE + 4], cipher_len); ml_kem_params->ulCipherLen = cipher_len; OPENSSL_cleanse(&csum[EP11_CSUMSIZE + 4], cipher_len); return CKR_OK; } struct EP11_BLS12_MECH { CK_MECHANISM mech; struct XCP_EC_AGGREGATE_PARAMS param; }; static CK_RV ep11tok_bls_mech_pre_process(STDLL_TokData_t *tokdata, CK_MECHANISM *mech, struct EP11_BLS12_MECH *mech_ep11, void** pAggrElements, SESSION *session, CK_BBOOL use_reenc_blob) { CK_IBM_ECDSA_OTHER_BLS_PARAMS *param; CK_RV rc; CK_ULONG i; CK_BYTE *concat_pubkey_spki = NULL; CK_BYTE *keyblob_temp = NULL; size_t keyblobsize_temp = 0, size_comp = 0; OBJECT *temp_obj = NULL; CK_ULONG keytype, class; int curve_type; if (mech->ulParameterLen != sizeof(CK_IBM_ECDSA_OTHER_BLS_PARAMS)) { TRACE_ERROR("Mechanism parameter length not as expected\n"); return CKR_MECHANISM_PARAM_INVALID; } mech_ep11->mech.mechanism = mech->mechanism; mech_ep11->mech.pParameter = &mech_ep11->param; mech_ep11->mech.ulParameterLen = sizeof(mech_ep11->param); memset(&mech_ep11->param, 0, sizeof(mech_ep11->param)); mech_ep11->param.version = 0; mech_ep11->param.mode = CK_IBM_EC_AGG_BLS12_381_PKEY; param = (CK_IBM_ECDSA_OTHER_BLS_PARAMS *)mech->pParameter; if (param->elementSize != sizeof(CK_OBJECT_HANDLE_PTR)) { TRACE_ERROR("Invalid element size %lu\n", param->elementSize); return CKR_MECHANISM_PARAM_INVALID; } if (param->numElements > CK_IBM_BLS_MAX_AGGREGATIONS) { TRACE_ERROR("Invalid number of elements %lu\n", param->numElements); return CKR_MECHANISM_PARAM_INVALID; } if (param->numElements > 0) { rc = h_opaque_2_blob(tokdata, *(CK_OBJECT_HANDLE_PTR)param->pAggrElements[0], &keyblob_temp, &keyblobsize_temp, &temp_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("%s h_opaque_2_blob failed for pub key index 0\n", __func__); rc = CKR_MECHANISM_PARAM_INVALID; goto error; } rc = tokdata->policy->is_key_allowed(tokdata->policy, &temp_obj->strength, session); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: aggregate with index 0\n"); rc = CKR_MECHANISM_PARAM_INVALID; goto error; } size_comp = keyblobsize_temp; rc = template_attribute_get_ulong(temp_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Invalid key type attribute with index 0 \n"); rc = CKR_MECHANISM_PARAM_INVALID; goto error; } rc = template_attribute_get_ulong(temp_obj->template, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key with index 0.\n"); rc = CKR_MECHANISM_PARAM_INVALID; goto error; } curve_type = get_curve_type_from_template(temp_obj->template); if (keytype != CKK_EC || curve_type != BLS12_381_CURVE || class != CKO_PUBLIC_KEY) { TRACE_ERROR("Incorrect Key type or Curve or Public key index 0.\n"); rc = CKR_MECHANISM_PARAM_INVALID; goto error; } if (use_reenc_blob) { rc = obj_opaque_2_reenc_blob(tokdata, temp_obj, &keyblob_temp, &keyblobsize_temp); if (rc != CKR_OK && rc != CKR_TEMPLATE_INCOMPLETE) { TRACE_ERROR("obj_opaque_2_reenc_blob failed pub_key index 0\n"); goto error; } } concat_pubkey_spki = malloc(param->numElements * keyblobsize_temp); if (concat_pubkey_spki == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto error; } memcpy(concat_pubkey_spki, keyblob_temp, keyblobsize_temp); object_put(tokdata, temp_obj, TRUE); temp_obj = NULL; for (i = 1; i < param->numElements; i++) { rc = h_opaque_2_blob(tokdata, *(CK_OBJECT_HANDLE_PTR)param->pAggrElements[i], &keyblob_temp, &keyblobsize_temp, &temp_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("%s h_opaque_2_blob failed pub_key index = 0%lu\n", __func__, i); rc = CKR_MECHANISM_PARAM_INVALID; goto error; } rc = tokdata->policy->is_key_allowed(tokdata->policy, &temp_obj->strength, session); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: aggregate with index = 0%lu\n", i); rc = CKR_MECHANISM_PARAM_INVALID; goto error; } if (size_comp != keyblobsize_temp) { TRACE_ERROR("Blob size not matching with index = 0%lu\n", i); rc = CKR_MECHANISM_PARAM_INVALID; goto error; } rc = template_attribute_get_ulong(temp_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Invalid key type attribute with index = 0%lu\n", i); rc = CKR_MECHANISM_PARAM_INVALID; goto error; } rc = template_attribute_get_ulong(temp_obj->template, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key with " "index = 0%lu\n", i); rc = CKR_MECHANISM_PARAM_INVALID; goto error; } curve_type = get_curve_type_from_template(temp_obj->template); if (keytype != CKK_EC || curve_type != BLS12_381_CURVE || class != CKO_PUBLIC_KEY) { TRACE_ERROR("Incorrect Key type or Curve or Public key with " "index = 0%lu\n", i); rc = CKR_MECHANISM_PARAM_INVALID; goto error; } if (use_reenc_blob) { rc = obj_opaque_2_reenc_blob(tokdata, temp_obj, &keyblob_temp, &keyblobsize_temp); if (rc != CKR_OK && rc != CKR_TEMPLATE_INCOMPLETE) { TRACE_ERROR("obj_opaque_2_reenc_blob failed for pub key " "index = 0x%lx\n", *(CK_OBJECT_HANDLE_PTR)param->pAggrElements[0]); goto error; } } memcpy(concat_pubkey_spki + i * keyblobsize_temp, keyblob_temp, keyblobsize_temp); object_put(tokdata, temp_obj, TRUE); temp_obj = NULL; } } mech_ep11->param.perElementSize = keyblobsize_temp; mech_ep11->param.pElements = concat_pubkey_spki; mech_ep11->param.ulElementsLen = (param->numElements * keyblobsize_temp); *pAggrElements = mech_ep11->param.pElements; return CKR_OK; error: object_put(tokdata, temp_obj, TRUE); temp_obj = NULL; if (concat_pubkey_spki != NULL) free(concat_pubkey_spki); return rc; } static CK_RV ep11tok_btc_mech_pre_process(STDLL_TokData_t *tokdata, OBJECT *key_obj, CK_ATTRIBUTE **new_attrs, CK_ULONG *new_attrs_len) { CK_ATTRIBUTE *ec_params; CK_ULONG i, privlen; CK_RV rc; UNUSED(tokdata); /* * CKM_IBM_BTC_DERIVE requires CKA_VALUE_LEN to specify the byte length * of the to be derived EC key. CKA_VALUE_LEN is dependent on the * curve used. * CKA_VALUE_LEN can not be already in the user supplied template, * since this is not allowed by the key template check routines. */ rc = template_attribute_get_non_empty(key_obj->template, CKA_EC_PARAMS, &ec_params); if (rc != CKR_OK) { TRACE_ERROR("CKA_EC_PARAMS is required in derive template\n"); return rc; } for (i = 0; i < NUMEC; i++) { if (der_ec_supported[i].data_size == ec_params->ulValueLen && memcmp(ec_params->pValue, der_ec_supported[i].data, ec_params->ulValueLen) == 0) { privlen = (der_ec_supported[i].len_bits + 7) / 8; rc = add_to_attribute_array(new_attrs, new_attrs_len, CKA_VALUE_LEN, (CK_BYTE_PTR)&privlen, sizeof(privlen)); if (rc != CKR_OK) { TRACE_ERROR("Adding attribute failed type=CKA_VALUE_LEN " "rc=0x%lx\n", rc); return rc; } break; } } return CKR_OK; } static CK_RV ep11tok_btc_mech_post_process(STDLL_TokData_t *tokdata, SESSION *session, CK_MECHANISM *mech, CK_ULONG class, CK_ULONG ktype, OBJECT *key_obj, CK_BYTE *blob, CK_ULONG bloblen, CK_BYTE *csum, CK_ULONG cslen) { CK_IBM_BTC_DERIVE_PARAMS *btc_params = NULL; CK_BYTE *spki = NULL; CK_ULONG spki_length = 0; CK_BYTE buf[MAX_BLOBSIZE]; CK_ATTRIBUTE get_attr[1] = {{ CKA_PUBLIC_KEY_INFO, &buf, sizeof(buf) }}; CK_ATTRIBUTE *spki_attr = NULL; CK_BBOOL allocated = FALSE; CK_RV rc = CKR_OK; CK_BYTE *useblob = NULL; size_t useblob_len = 0; if (mech->ulParameterLen != sizeof(CK_IBM_BTC_DERIVE_PARAMS) || mech->pParameter == NULL) { TRACE_ERROR("%s Param NULL or len for %s wrong: %lu\n", __func__, ep11_get_ckm(tokdata, mech->mechanism), mech->ulParameterLen); return CKR_MECHANISM_PARAM_INVALID; } btc_params = (CK_IBM_BTC_DERIVE_PARAMS *)mech->pParameter; if (btc_params != NULL && btc_params->pChainCode != NULL && cslen >= CK_IBM_BTC_CHAINCODE_LENGTH) { memcpy(btc_params->pChainCode, csum, CK_IBM_BTC_CHAINCODE_LENGTH); btc_params->ulChainCodeLen = CK_IBM_BTC_CHAINCODE_LENGTH; } switch (class) { case CKO_PUBLIC_KEY: /* Derived blob is an SPKI, extract public EC key attributes */ rc = ec_priv_unwrap_get_data(key_obj->template, blob, bloblen, TRUE, CKK_EC); if (rc != CKR_OK) { TRACE_ERROR("%s ec_priv_unwrap_get_data failed with " "rc=0x%lx\n", __func__, rc); return rc; } /* Extract the SPKI and add CKA_PUBLIC_KEY_INFO to key */ rc = publ_key_get_spki(key_obj->template, ktype, FALSE, &spki, &spki_length, FALSE); if (rc != CKR_OK) { TRACE_DEVEL("publ_key_get_spki failed\n"); return rc; } allocated = TRUE; break; case CKO_PRIVATE_KEY: RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_BLOB_START(tokdata, target_info, key_obj, blob, bloblen, useblob, useblob_len, rc) rc = dll_m_GetAttributeValue(useblob, useblob_len, get_attr, 1, target_info->target); RETRY_REENC_BLOB_END(tokdata, target_info, useblob, useblob_len, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) /* Only newer EP11 libs support this, ignore if error */ if (rc != CKR_OK) return CKR_OK; spki = get_attr[0].pValue; spki_length = get_attr[0].ulValueLen; break; default: /* do nothing */ return CKR_OK; } rc = build_attribute(CKA_PUBLIC_KEY_INFO, spki, spki_length, &spki_attr); if (rc != CKR_OK) { TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc); goto out; } rc = template_update_attribute(key_obj->template, spki_attr); if (rc != CKR_OK) { TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n", __func__, rc); free(spki_attr); goto out; } out: if (allocated && spki != NULL) free(spki); return rc; } static CK_RV ep11tok_sha_key_derive_mech_pre_process(STDLL_TokData_t *tokdata, OBJECT *base_key_obj, OBJECT *derived_key_obj, CK_MECHANISM *mech, CK_ULONG keytype) { CK_RV rc; CK_ULONG hsize, value_len = 0; CK_ATTRIBUTE *attr; CK_BBOOL battr; UNUSED(tokdata); /* * As per PKCS#11 standard: * - If no length or key type is provided in the template, then the key * produced by this mechanism will be a generic secret key. Its length * will be the output size of the used digest. * - If no key type is provided in the template, but a length is, then the * key produced by this mechanism will be a generic secret key of the * specified length. * - If no length was provided in the template, but a key type is, then * that key type must have a well-defined length. If it does, then the * key produced by this mechanism will be of the type specified in the * template. If it doesn’t, an error will be returned. * - If both a key type and a length are provided in the template, the * length must be compatible with that key type. The key produced by * this mechanism will be of the specified type and length. */ switch (mech->mechanism) { case CKM_SHA1_KEY_DERIVATION: hsize = SHA1_HASH_SIZE; break; case CKM_SHA224_KEY_DERIVATION: hsize = SHA224_HASH_SIZE; break; case CKM_SHA256_KEY_DERIVATION: hsize = SHA256_HASH_SIZE; break; case CKM_SHA384_KEY_DERIVATION: hsize = SHA384_HASH_SIZE; break; case CKM_SHA512_KEY_DERIVATION: hsize = SHA512_HASH_SIZE; break; case CKM_SHA512_224_KEY_DERIVATION: hsize = SHA224_HASH_SIZE; break; case CKM_SHA512_256_KEY_DERIVATION: hsize = SHA256_HASH_SIZE; break; default: TRACE_ERROR("%s invalid mechanism 0x%lx\n", __func__, mech->mechanism); return CKR_MECHANISM_INVALID; } rc = template_attribute_get_ulong(derived_key_obj->template, CKA_VALUE_LEN, &value_len); if (rc != CKR_OK && rc != CKR_TEMPLATE_INCOMPLETE) { TRACE_ERROR("%s error getting CKA_VALUE_LEN rc=0x%lx\n", __func__, rc); return rc; } if (value_len == 0) { value_len = hsize; } else if (value_len > hsize) { TRACE_ERROR("%s CKA_VALUE_LEN is too large\n", __func__); return CKR_TEMPLATE_INCONSISTENT; } switch (keytype) { case CKK_GENERIC_SECRET: case CKK_SHA_1_HMAC: case CKK_SHA224_HMAC: case CKK_SHA256_HMAC: case CKK_SHA384_HMAC: case CKK_SHA512_HMAC: case CKK_SHA3_224_HMAC: case CKK_SHA3_256_HMAC: case CKK_SHA3_384_HMAC: case CKK_SHA3_512_HMAC: case CKK_SHA512_224_HMAC: case CKK_SHA512_256_HMAC: break; case CKK_DES: case CKK_DES2: case CKK_DES3: value_len = 0; break; case CKK_AES: switch (value_len) { case 16: case 24: case 32: break; default: TRACE_ERROR("%s CKA_VALUE_LEN improper for AES\n", __func__); return CKR_TEMPLATE_INCONSISTENT; } break; case CKK_AES_XTS: switch (value_len) { case 32: case 64: break; default: TRACE_ERROR("%s CKA_VALUE_LEN improper for AES-XTS\n", __func__); return CKR_TEMPLATE_INCONSISTENT; } break; default: TRACE_ERROR("%s invalid key type 0x%lx\n", __func__, keytype); return CKR_TEMPLATE_INCONSISTENT; } if (value_len > 0) { rc = build_attribute(CKA_VALUE_LEN, (CK_BYTE *)&value_len, sizeof(value_len), &attr); if (rc != CKR_OK) { TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc); return rc; } rc = template_update_attribute(derived_key_obj->template, attr); if (rc != CKR_OK) { TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n", __func__, rc); free(attr); return rc; } } /* * As per PKCS#11 standard: * - If the base key has its CKA_ALWAYS_SENSITIVE attribute set to CK_FALSE, * then the derived key will as well. If the base key has its * CKA_ALWAYS_SENSITIVE attribute set to CK_TRUE, then the derived key * has its CKA_ALWAYS_SENSITIVE attribute set to the same value as its * CKA_SENSITIVE attribute. * - Similarly, if the base key has its CKA_NEVER_EXTRACTABLE attribute * set to CK_FALSE, then the derived key will, too. If the base key has * its CKA_NEVER_EXTRACTABLE attribute set to CK_TRUE, then the derived * key has its CKA_NEVER_EXTRACTABLE attribute set to the opposite value * from its CKA_EXTRACTABLE attribute. */ rc = template_attribute_get_bool(base_key_obj->template, CKA_ALWAYS_SENSITIVE, &battr); if (rc != CKR_OK && rc != CKR_TEMPLATE_INCOMPLETE) { TRACE_ERROR("%s error getting CKA_ALWAYS_SENSITIVE rc=0x%lx\n", __func__, rc); return rc; } if (battr == CK_TRUE) { rc = template_attribute_get_bool(derived_key_obj->template, CKA_SENSITIVE, &battr); if (rc != CKR_OK && rc != CKR_TEMPLATE_INCOMPLETE) { TRACE_ERROR("%s error getting CKA_SENSITIVE rc=0x%lx\n", __func__, rc); return rc; } } rc = build_attribute(CKA_ALWAYS_SENSITIVE, (CK_BYTE *)&battr, sizeof(battr), &attr); if (rc != CKR_OK) { TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc); return rc; } rc = template_update_attribute(derived_key_obj->template, attr); if (rc != CKR_OK) { TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n", __func__, rc); free(attr); return rc; } rc = template_attribute_get_bool(base_key_obj->template, CKA_NEVER_EXTRACTABLE, &battr); if (rc != CKR_OK && rc != CKR_TEMPLATE_INCOMPLETE) { TRACE_ERROR("%s error getting CKA_NEVER_EXTRACTABLE rc=0x%lx\n", __func__, rc); return rc; } if (battr == CK_TRUE) { rc = template_attribute_get_bool(derived_key_obj->template, CKA_EXTRACTABLE, &battr); if (rc != CKR_OK && rc != CKR_TEMPLATE_INCOMPLETE) { TRACE_ERROR("%s error getting CKA_EXTRACTABLE rc=0x%lx\n", __func__, rc); return rc; } battr = !battr; } rc = build_attribute(CKA_NEVER_EXTRACTABLE, (CK_BYTE *)&battr, sizeof(battr), &attr); if (rc != CKR_OK) { TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc); return rc; } rc = template_update_attribute(derived_key_obj->template, attr); if (rc != CKR_OK) { TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n", __func__, rc); free(attr); return rc; } return CKR_OK; } CK_RV is_ec_aggregate_mechanism(CK_MECHANISM_PTR pMechanism) { return (pMechanism->mechanism == CKM_IBM_EC_AGGREGATE); } static CK_RV ep11tok_ec_montgomery_mech_preprocess(STDLL_TokData_t *tokdata, OBJECT *base_key_obj, CK_MECHANISM *mech, CK_MECHANISM *ep11_mech) { CK_KEY_TYPE keytype; CK_ATTRIBUTE *attr; CK_ULONG i; const struct _ec *curve = NULL; CK_RV rc; UNUSED(tokdata); if (mech->mechanism != CKM_ECDH1_DERIVE) { *ep11_mech = *mech; return CKR_OK; } rc = template_attribute_get_ulong(base_key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Invalid key type attribute\n"); return rc; } if (keytype != CKK_EC_MONTGOMERY) { *ep11_mech = *mech; return CKR_OK; } rc = template_attribute_get_non_empty(base_key_obj->template, CKA_EC_PARAMS, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_EC_PARAMS for the key.\n"); return rc; } for (i = 0; i < NUMEC; i++) { if (der_ec_supported[i].data_size == attr->ulValueLen && (memcmp(attr->pValue, der_ec_supported[i].data, attr->ulValueLen) == 0)) { curve = &der_ec_supported[i]; break; } } if (curve == NULL || curve->curve_type != MONTGOMERY_CURVE) { TRACE_ERROR("Must be a Montgomery curve\n"); return CKR_CURVE_NOT_SUPPORTED; } switch (curve->prime_bits) { case CURVE255: ep11_mech->mechanism = CKM_IBM_EC_X25519; break; case CURVE448: ep11_mech->mechanism = CKM_IBM_EC_X448; break; default: return CKR_CURVE_NOT_SUPPORTED; } ep11_mech->pParameter = mech->pParameter; ep11_mech->ulParameterLen = mech->ulParameterLen; return CKR_OK; } CK_RV ep11tok_ibm_ed_mont_mech_check_keytype(OBJECT *key_obj) { CK_KEY_TYPE keytype; CK_RV rc; rc = template_attribute_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find attribute CKA_KEY_TYPE for the key.\n"); return CKR_TEMPLATE_INCOMPLETE; } if (keytype != CKK_EC) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); return CKR_KEY_TYPE_INCONSISTENT; } return CKR_OK; } CK_RV ep11tok_derive_key(STDLL_TokData_t *tokdata, SESSION *session, CK_MECHANISM_PTR mech, CK_OBJECT_HANDLE hBaseKey, CK_OBJECT_HANDLE_PTR handle, CK_ATTRIBUTE_PTR attrs, CK_ULONG attrs_len, CK_BBOOL count_statistics, CK_ULONG operation) { ep11_private_data_t *ep11_data = tokdata->private_data; CK_RV rc; CK_BYTE *keyblob; size_t keyblobsize; CK_BYTE newblob[MAX_BLOBSIZE]; CK_BYTE newblobreenc[MAX_BLOBSIZE]; size_t newblobsize = sizeof(newblob); CK_BYTE csum[MAX_BLOBSIZE]; CK_ULONG cslen = sizeof(csum); CK_ATTRIBUTE *opaque_attr = NULL, *chk_attr = NULL, *ec_parms_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 = NULL; CK_ECDH1_DERIVE_PARAMS ecdh1_parms2; CK_MECHANISM ecdh1_mech, ecdh1_mech2, ecdh1_mech3; CK_BYTE *ecpoint = NULL; CK_ULONG ecpoint_len, field_len, key_len = 0; CK_ATTRIBUTE *new_attrs1 = NULL, *new_attrs2 = NULL; CK_ULONG new_attrs1_len = 0, new_attrs2_len = 0; CK_ULONG privlen; int curve_type; CK_BBOOL allocated = FALSE; ep11_target_info_t* target_info; CK_ULONG used_firmware_API_version; CK_MECHANISM_PTR mech_orig = mech; struct EP11_KEM_MECH mech_ep11; struct EP11_BLS12_MECH mech_bls = { 0 }; void *pAggrElements = NULL; struct objstrength objstrength; OBJECT *kem_secret_obj = NULL; CK_KEY_TYPE keytype; CK_BYTE *useblob = NULL; size_t useblobsize = 0; int retry_mech_param_blob = 0; CK_ULONG mode; int policy_check; CK_ATTRIBUTE_TYPE apply_tmpl_attr; memset(newblob, 0, sizeof(newblob)); memset(newblobreenc, 0, sizeof(newblobreenc)); switch (operation) { case OP_DERIVE: policy_check = POLICY_CHECK_DERIVE; mode = MODE_DERIVE; apply_tmpl_attr = CKA_DERIVE_TEMPLATE; break; case OP_ENCAPSULATE: policy_check = POLICY_CHECK_ENCAPS; mode = MODE_ENCAPS; apply_tmpl_attr = CKA_ENCAPSULATE_TEMPLATE; break; case OP_DECAPSULATE: policy_check = POLICY_CHECK_DECAPS; mode = MODE_DECAPS; apply_tmpl_attr = CKA_DECAPSULATE_TEMPLATE; break; default: TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } if (mech->mechanism == CKM_ECDH1_DERIVE || mech->mechanism == CKM_IBM_EC_X25519 || mech->mechanism == CKM_IBM_EC_X448) { if (mech->ulParameterLen != sizeof(CK_ECDH1_DERIVE_PARAMS) || mech->pParameter == NULL) { TRACE_ERROR("%s Param NULL or len for %s wrong: %lu\n", __func__, ep11_get_ckm(tokdata, 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. * Also, the EP11 host library only accepts EC points in uncompressed * form, so uncompress it if in compressed or hybrid form. */ if (ecdh1_parms->pPublicData != NULL && ecdh1_parms->ulPublicDataLen > 0) { ecdh1_parms2 = *ecdh1_parms; if (mech->mechanism == CKM_ECDH1_DERIVE) { rc = h_opaque_2_blob(tokdata, hBaseKey, &keyblob, &keyblobsize, &base_key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("%s failed hBaseKey=0x%lx\n", __func__, hBaseKey); return rc; } rc = template_attribute_get_ulong(base_key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Invalid key type attribute\n"); goto error; } switch (keytype) { case CKK_EC: rc = get_ecsiglen(base_key_obj, &privlen); privlen /= 2; if (rc != CKR_OK) { TRACE_ERROR("%s get_ecsiglen failed\n", __func__); goto error; } rc = template_attribute_get_non_empty(base_key_obj->template, CKA_EC_PARAMS, &ec_parms_attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_EC_PARAMS in base key\n"); goto error; } rc = ec_point_uncompressed_from_public_data( ecdh1_parms->pPublicData, ecdh1_parms->ulPublicDataLen, privlen, (CK_BYTE *) ec_parms_attr->pValue, ec_parms_attr->ulValueLen, TRUE, &allocated, &ecpoint, &ecpoint_len); if (rc != CKR_OK) { TRACE_DEVEL("ec_point_from_public_data failed\n"); goto error; } break; case CKK_EC_MONTGOMERY: /* Montgomery uses a raw EC point */ ecpoint = ecdh1_parms->pPublicData; ecpoint_len = ecdh1_parms->ulPublicDataLen; break; default: TRACE_ERROR("Invalid key type attribute\n"); rc = CKR_KEY_TYPE_INCONSISTENT; goto error; } object_put(tokdata, base_key_obj, TRUE); base_key_obj = NULL; } else { rc = ber_decode_OCTET_STRING(ecdh1_parms->pPublicData, ecdh1_parms->ulPublicDataLen, &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 */ 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. */ target_info = get_target_info(tokdata); if (target_info == NULL) { rc = CKR_FUNCTION_FAILED; goto error; } used_firmware_API_version = target_info->used_firmware_API_version; put_target_info(tokdata, target_info); if (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); rc = CKR_MECHANISM_PARAM_INVALID; goto error; } if (ecdh1_parms->pSharedData != NULL || ecdh1_parms->ulSharedDataLen > 0) { TRACE_ERROR("%s Shared data for CKM_ECDH1_DERIVE not " "supported\n", __func__); rc = CKR_MECHANISM_PARAM_INVALID; goto error; } ecdh1_mech.mechanism = mech->mechanism; ecdh1_mech.pParameter = ecdh1_parms->pPublicData; ecdh1_mech.ulParameterLen = ecdh1_parms->ulPublicDataLen; mech = &ecdh1_mech; } } if (!is_ec_aggregate_mechanism(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); goto error; } rc = template_attribute_get_ulong(base_key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Invalid key type attribute\n"); goto error; } if (mech->mechanism == CKM_AES_XTS || keytype == CKK_AES_XTS) { TRACE_ERROR("%s Key derive with AES-XTS is not supported\n", __func__); rc = CKR_KEY_TYPE_INCONSISTENT; goto error; } rc = tokdata->policy->is_mech_allowed(tokdata->policy, mech_orig, &base_key_obj->strength, policy_check, session); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: derive key\n"); goto error; } if (!key_object_is_mechanism_allowed(base_key_obj->template, mech_orig->mechanism)) { TRACE_ERROR("Mechanism not allowed per CKA_ALLOWED_MECHANISMS.\n"); rc = CKR_MECHANISM_INVALID; goto error; } /* Get the keytype to use when creating the key object */ rc = pkcs_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; } if (ktype == CKK_AES_XTS) { TRACE_ERROR("%s Deriving an AES-XTS key is not supported\n", __func__); rc = CKR_KEY_TYPE_INCONSISTENT; goto error; } } else { ktype = CKK_EC; class = CKO_PUBLIC_KEY; objstrength.strength = POLICY_STRENGTH_IDX_192; objstrength.siglen = CK_IBM_BLS12_381_SIGN_LEN * 8; objstrength.allowed = CK_TRUE; rc = tokdata->policy->is_mech_allowed(tokdata->policy, mech_orig, &objstrength, policy_check, session); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: derive key\n"); goto error; } } rc = check_key_attributes(tokdata, ktype, class, attrs, attrs_len, &new_attrs, &new_attrs_len, -1); if (rc != CKR_OK) { TRACE_ERROR("%s Check key attributes for derived key failed with " "rc=0x%lx\n", __func__, rc); goto error; } if (!is_ec_aggregate_mechanism(mech)) { rc = check_ab_derive_attributes(tokdata, base_key_obj->template, &new_attrs, &new_attrs_len); if (rc != CKR_OK) { TRACE_ERROR("%s Attribute bound attribute violation on derive key: " "rc=0x%lx\n", __func__, rc); goto error; } } if (mech->mechanism == CKM_ECDH1_DERIVE || mech->mechanism == CKM_IBM_EC_X25519 || mech->mechanism == CKM_IBM_EC_X448) { /* Determine derived key length */ rc = template_attribute_get_non_empty(base_key_obj->template, CKA_EC_PARAMS, &ec_parms_attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_EC_PARAMS in base key\n"); goto error; } /* Get CKA_VALUE_LEN if , otherwise key_len remains 0 */ get_ulong_attribute_by_type(new_attrs, new_attrs_len, CKA_VALUE_LEN, &key_len); rc = ecdh_get_derived_key_size(0, ec_parms_attr->pValue, ec_parms_attr->ulValueLen, ecdh1_parms->kdf, ktype, key_len, &key_len); if (rc != CKR_OK) { TRACE_ERROR("Can not determine the derived key length\n"); goto error; } /* Add CKA_VALUE_LEN attribute, since EP11 needs this attribute */ if (get_attribute_by_type(new_attrs, new_attrs_len, CKA_VALUE_LEN) == NULL) { rc = add_to_attribute_array(&new_attrs, &new_attrs_len, CKA_VALUE_LEN, (CK_BYTE *)&key_len, sizeof(CK_ULONG)); if (rc != CKR_OK) { TRACE_ERROR("add_to_attribute_array failed\n"); goto error; } } } if (!is_ec_aggregate_mechanism(mech)) { rc = force_ab_sensitive(&new_attrs, &new_attrs_len, ktype); if (rc != CKR_OK) { TRACE_ERROR("%s force attribute bound key sensitive failed: " "rc=0x%lx\n",__func__, rc); goto error; } rc = key_object_apply_template_attr(base_key_obj->template, apply_tmpl_attr, new_attrs, new_attrs_len, &new_attrs1, &new_attrs1_len); if (rc != CKR_OK) { TRACE_DEVEL("key_object_apply_template_attr failed.\n"); goto error; } } #ifndef NO_PKEY /* Ensure the firmware master key verification pattern is available */ rc = ep11tok_pkey_get_firmware_mk_vp(tokdata, session); if (rc != CKR_OK && rc != CKR_FUNCTION_NOT_SUPPORTED) goto error; #endif /* NO_PKEY */ /* Start creating the key object */ rc = object_mgr_create_skel(tokdata, session, !is_ec_aggregate_mechanism(mech) ? new_attrs1 : new_attrs, !is_ec_aggregate_mechanism(mech) ? new_attrs1_len : new_attrs_len, mode, 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; } switch (mech->mechanism) { case CKM_SHA1_KEY_DERIVATION: case CKM_SHA224_KEY_DERIVATION: case CKM_SHA256_KEY_DERIVATION: case CKM_SHA384_KEY_DERIVATION: case CKM_SHA512_KEY_DERIVATION: case CKM_SHA512_224_KEY_DERIVATION: case CKM_SHA512_256_KEY_DERIVATION: rc = ep11tok_sha_key_derive_mech_pre_process(tokdata, base_key_obj, key_obj, mech, ktype); if (rc != CKR_OK) goto error; break; default: break; } curve_type = get_curve_type_from_template(key_obj->template); rc = build_ep11_attrs(tokdata, key_obj->template, &new_attrs2, &new_attrs2_len, ktype, class, curve_type, mech); if (rc != CKR_OK) { TRACE_ERROR("%s build_ep11_attrs failed with rc=0x%lx\n", __func__, rc); goto error; } do_retry: switch (mech_orig->mechanism) { case CKM_IBM_EC_AGGREGATE: rc = ep11tok_bls_mech_pre_process(tokdata, mech_orig, &mech_bls, &pAggrElements, session, retry_mech_param_blob != 0); if (rc != CKR_OK) goto error; mech = &mech_bls.mech; break; case CKM_IBM_BTC_DERIVE: rc = ep11tok_btc_mech_pre_process(tokdata, key_obj, &new_attrs2, &new_attrs2_len); if (rc != CKR_OK) goto error; break; case CKM_IBM_KYBER: case CKM_IBM_ML_KEM: case CKM_ML_KEM: rc = ep11tok_ml_kem_mech_pre_process(tokdata, mech_orig, &mech_ep11, &kem_secret_obj, retry_mech_param_blob != 0); if (rc != CKR_OK) goto error; mech = &mech_ep11.mech; break; case CKM_IBM_ML_KEM_WITH_ECDH: rc = ep11tok_ml_kem_with_ecdh_mech_pre_process(tokdata, session, mech_orig, &mech_ep11, retry_mech_param_blob != 0); if (rc != CKR_OK) goto error; mech = &mech_ep11.mech; break; case CKM_IBM_EC_X25519: case CKM_IBM_EC_X448: rc = ep11tok_ibm_ed_mont_mech_check_keytype(base_key_obj); if (rc != CKR_OK) return rc; break; case CKM_ECDH1_DERIVE: rc = ep11tok_ec_montgomery_mech_preprocess(tokdata, base_key_obj, mech, &ecdh1_mech3); if (rc != CKR_OK) return rc; mech = &ecdh1_mech3; break; default: break; } trace_attributes(__func__, "Derive:", new_attrs2, new_attrs2_len); ep11_get_pin_blob(tokdata, ep11_session, ep11_is_session_object(attrs, attrs_len), ep11_is_private_object(attrs, attrs_len), &ep11_pin_blob, &ep11_pin_blob_len); RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_BLOB_START(tokdata, target_info, base_key_obj, keyblob, keyblobsize, useblob, useblobsize, rc) RETRY_REENC_CREATE_KEY_START() if (ep11_pqc_obj_strength_supported(target_info, mech_orig->mechanism, base_key_obj)) rc = dll_m_DeriveKey(mech, new_attrs2, new_attrs2_len, useblob, useblobsize, NULL, 0, ep11_pin_blob, ep11_pin_blob_len, newblob, &newblobsize, csum, &cslen, target_info->target); else rc = CKR_KEY_SIZE_RANGE; RETRY_REENC_CREATE_KEY_END(tokdata, session, target_info, newblob, newblobreenc, newblobsize, rc) RETRY_REENC_BLOB_END(tokdata, target_info, useblob, useblobsize, rc) /* * Special handling for mechs where mech param contains a blob: * If blob in mech param causes CKR_IBM_WKID_MISMATCH then retry the * whole operation including preprocessing. This will then cause the * blob in the mech param to be the reenciphered one. */ if (rc == CKR_IBM_WKID_MISMATCH && (mech == &mech_ep11.mech || mech == &mech_bls.mech) && ep11_data->mk_change_active) { TRACE_DEVEL("Blob in mech param and WKID mismatch -> retry\n"); retry_mech_param_blob++; } else { retry_mech_param_blob = 0; } RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (retry_mech_param_blob == 1) /* Retry only once */ goto do_retry; if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); 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); if (check_expected_mkvp(tokdata, newblob, newblobsize, NULL) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); rc = CKR_DEVICE_ERROR; goto error; } 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; } opaque_attr = NULL; if (class == CKO_SECRET_KEY || class == CKO_PRIVATE_KEY) { rc = update_ep11_attrs_from_blob(tokdata, session, key_obj, FALSE); if (rc != CKR_OK) { TRACE_ERROR("%s update_ep11_attrs_from_blob failed with rc=0x%lx\n", __func__, rc); goto error; } } switch (mech_orig->mechanism) { case CKM_IBM_BTC_DERIVE: rc = ep11tok_btc_mech_post_process(tokdata, session, mech, class, ktype, key_obj, newblob, newblobsize, csum, cslen); if (rc != CKR_OK) goto error; break; case CKM_IBM_KYBER: case CKM_IBM_ML_KEM: case CKM_ML_KEM: rc = ep11tok_ml_kem_mech_post_process(tokdata, mech_orig, csum, cslen); if (rc != CKR_OK) goto error; break; case CKM_IBM_ML_KEM_WITH_ECDH: rc = ep11tok_ml_kem_with_ecdh_mech_post_process(tokdata, mech_orig, csum, cslen); if (rc != CKR_OK) goto error; break; default: break; } if (ep11_data->mk_change_active) { rc = build_attribute(CKA_IBM_OPAQUE_REENC, newblobreenc, newblobsize, &opaque_attr); if (rc != CKR_OK) { TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc); goto error; } rc = template_update_attribute(key_obj->template, opaque_attr); if (rc != CKR_OK) { TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n", __func__, rc); goto error; } opaque_attr = NULL; } if (class == CKO_SECRET_KEY && cslen >= EP11_CSUMSIZE) { /* First 3 bytes of csum is the check value */ rc = build_attribute(CKA_CHECK_VALUE, csum, EP11_CSUMSIZE, &chk_attr); 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, chk_attr); if (rc != CKR_OK) { TRACE_ERROR("%s template_update_attribute failed with " "rc=0x%lx\n", __func__, rc); goto error; } chk_attr = NULL; } /* key should be fully constructed. * Assign an object handle and store key. * Enforce policy. */ 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; } if (count_statistics) INC_COUNTER(tokdata, session, mech_orig, base_key_obj, is_ec_aggregate_mechanism(mech) ? POLICY_STRENGTH_IDX_192 : POLICY_STRENGTH_IDX_0); goto out; error: if (key_obj) object_free(key_obj); *handle = 0; out: if (opaque_attr != NULL) free(opaque_attr); if (chk_attr != NULL) free(chk_attr); if (new_attrs) free_attribute_array(new_attrs, new_attrs_len); if (new_attrs1) free_attribute_array(new_attrs1, new_attrs1_len); if (new_attrs2) free_attribute_array(new_attrs2, new_attrs2_len); if (allocated && ecpoint != NULL) free(ecpoint); if (pAggrElements != NULL) free(pAggrElements); object_put(tokdata, base_key_obj, TRUE); base_key_obj = NULL; object_put(tokdata, kem_secret_obj, TRUE); kem_secret_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) { ep11_private_data_t *ep11_data = tokdata->private_data; CK_RV rc; CK_BYTE publblob[MAX_BLOBSIZE]; CK_BYTE publblobreenc[MAX_BLOBSIZE]; size_t publblobsize = sizeof(publblob); CK_BYTE privblob[MAX_BLOBSIZE]; CK_BYTE privblobreenc[MAX_BLOBSIZE]; size_t privblobsize = sizeof(privblob); CK_ATTRIBUTE *prime_attr = NULL; CK_ATTRIBUTE *base_attr = NULL; CK_ATTRIBUTE *opaque_attr = NULL; CK_ATTRIBUTE *value_attr = NULL; CK_ATTRIBUTE *attr = NULL; CK_ATTRIBUTE_PTR dh_pPublicKeyTemplate = NULL; CK_ULONG dh_ulPublicKeyAttributeCount = 0; CK_ATTRIBUTE_PTR dh_pPrivateKeyTemplate = NULL; CK_ULONG dh_ulPrivateKeyAttributeCount = 0; 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, value_bits = 0; unsigned char *priv_ep11_pin_blob = NULL; CK_ULONG priv_ep11_pin_blob_len = 0; unsigned char *publ_ep11_pin_blob = NULL; CK_ULONG publ_ep11_pin_blob_len = 0; ep11_session_t *ep11_session = (ep11_session_t *) sess->private_data; CK_ATTRIBUTE *new_publ_attrs = NULL, *new_priv_attrs = NULL; CK_ULONG new_publ_attrs_len = 0, new_priv_attrs_len = 0; CK_ULONG spki_len; /* 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; memset(&dh_pgs, 0, sizeof(dh_pgs)); memset(publblob, 0, sizeof(publblob)); memset(publblobreenc, 0, sizeof(publblobreenc)); memset(privblob, 0, sizeof(privblob)); memset(privblobreenc, 0, sizeof(privblobreenc)); rc = build_ep11_attrs(tokdata, publ_tmpl, &dh_pPublicKeyTemplate, &dh_ulPublicKeyAttributeCount, CKK_DH, CKO_PUBLIC_KEY, -1, pMechanism); if (rc != CKR_OK) { TRACE_ERROR("%s build_ep11_attrs failed with rc=0x%lx\n", __func__, rc); goto dh_generate_keypair_end; } rc = build_ep11_attrs(tokdata, priv_tmpl, &dh_pPrivateKeyTemplate, &dh_ulPrivateKeyAttributeCount, CKK_DH, CKO_PRIVATE_KEY, -1, pMechanism); if (rc != CKR_OK) { TRACE_ERROR("%s build_ep11_attrs failed with rc=0x%lx\n", __func__, rc); goto dh_generate_keypair_end; } rc = check_key_attributes(tokdata, CKK_DH, CKO_PUBLIC_KEY, dh_pPublicKeyTemplate, dh_ulPublicKeyAttributeCount, &new_publ_attrs, &new_publ_attrs_len, -1); 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, dh_pPrivateKeyTemplate, dh_ulPrivateKeyAttributeCount, &new_priv_attrs, &new_priv_attrs_len, -1); 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; } /* card does not want CKA_PRIME/CKA_BASE in template but in dh_pgs */ rc = template_attribute_get_non_empty(publ_tmpl, CKA_PRIME, &prime_attr); if (rc != CKR_OK) { TRACE_ERROR("%s DH No CKA_PRIME attribute found\n", __func__); goto dh_generate_keypair_end; } rc = template_attribute_get_non_empty(publ_tmpl, CKA_BASE, &base_attr); if (rc != CKR_OK) { TRACE_ERROR("%s DH No CKA_BASE attribute found\n", __func__); goto dh_generate_keypair_end; } dh_pgs.pg = malloc(prime_attr->ulValueLen * 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, prime_attr->ulValueLen * 2); /* copy CKA_PRIME value */ memcpy(dh_pgs.pg, prime_attr->pValue, prime_attr->ulValueLen); /* copy CKA_BASE value, it must have leading zeros * if it is shorter than CKA_PRIME */ memcpy(dh_pgs.pg + prime_attr->ulValueLen + (prime_attr->ulValueLen - base_attr->ulValueLen), base_attr->pValue, base_attr->ulValueLen); dh_pgs.pg_bytes = prime_attr->ulValueLen * 2; #ifdef DEBUG TRACE_DEBUG("%s P:\n", __func__); TRACE_DEBUG_DUMP(" ", &dh_pgs.pg[0], prime_attr->ulValueLen); TRACE_DEBUG("%s G:\n", __func__); TRACE_DEBUG_DUMP(" ", &dh_pgs.pg[prime_attr->ulValueLen], prime_attr->ulValueLen); #endif rc = add_to_attribute_array(&new_publ_attrs, &new_publ_attrs_len, CKA_IBM_STRUCT_PARAMS, dh_pgs.pg, dh_pgs.pg_bytes); if (rc != CKR_OK) { TRACE_ERROR("%s add_to_attribute_array failed with rc=0x%lx\n", __func__, rc); 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); free(attr); 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); free(attr); goto dh_generate_keypair_end; } trace_attributes(__func__, "DH public key attributes:", new_publ_attrs, new_publ_attrs_len); trace_attributes(__func__, "DH private key attributes:", new_priv_attrs, new_priv_attrs_len); ep11_get_pin_blob(tokdata, ep11_session, ep11_is_session_object(new_priv_attrs, new_priv_attrs_len), ep11_is_private_object(new_priv_attrs, new_priv_attrs_len), &priv_ep11_pin_blob, &priv_ep11_pin_blob_len); ep11_get_pin_blob(tokdata, ep11_session, ep11_is_session_object(new_publ_attrs, new_publ_attrs_len), ep11_is_private_object(new_publ_attrs, new_publ_attrs_len), &publ_ep11_pin_blob, &publ_ep11_pin_blob_len); RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_CREATE_KEY2_START() rc = dll_m_GenerateKeyPair(pMechanism, new_publ_attrs, new_publ_attrs_len, new_priv_attrs, new_priv_attrs_len, priv_ep11_pin_blob, priv_ep11_pin_blob_len, privblob, &privblobsize, publblob, &publblobsize, target_info->target); RETRY_REENC_CREATE_KEY2_END(tokdata, sess, target_info, privblob, privblobreenc, privblobsize, publblob, publblobreenc, publblobsize, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, sess) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, sess); 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, prime_attr->ulValueLen, publblobsize, privblobsize); if (check_expected_mkvp(tokdata, privblob, privblobsize, NULL) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); rc = CKR_DEVICE_ERROR; goto dh_generate_keypair_end; } if (priv_ep11_pin_blob != publ_ep11_pin_blob) { /* Re-create the MACed SPKI with the desired EP11 session */ spki_len = publblobsize; publblobsize = sizeof(publblob); rc = make_maced_spki(tokdata, sess, NULL, new_publ_attrs, new_publ_attrs_len, publblob, spki_len, publblob, publblobreenc, &publblobsize, -1); if (rc != CKR_OK) { TRACE_ERROR("%s failed to re-make a MACed-SPKI rc=0x%lx\n", __func__, rc); goto dh_generate_keypair_end; } } if (check_expected_mkvp(tokdata, publblob, publblobsize, NULL) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); rc = CKR_DEVICE_ERROR; goto dh_generate_keypair_end; } /* 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); free(opaque_attr); goto dh_generate_keypair_end; } if (ep11_data->mk_change_active) { rc = build_attribute(CKA_IBM_OPAQUE_REENC, publblobreenc, publblobsize, &opaque_attr); if (rc != CKR_OK) { TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc); goto dh_generate_keypair_end; } rc = template_update_attribute(publ_tmpl, opaque_attr); if (rc != CKR_OK) { TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n", __func__, rc); free(opaque_attr); goto dh_generate_keypair_end; } } rc = build_attribute(CKA_IBM_OPAQUE, privblob, privblobsize, &opaque_attr); if (rc != CKR_OK) { TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc); goto dh_generate_keypair_end; } rc = template_update_attribute(priv_tmpl, opaque_attr); if (rc != CKR_OK) { TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n", __func__, rc); free(opaque_attr); goto dh_generate_keypair_end; } if (ep11_data->mk_change_active) { rc = build_attribute(CKA_IBM_OPAQUE_REENC, privblobreenc, privblobsize, &opaque_attr); if (rc != CKR_OK) { TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc); goto dh_generate_keypair_end; } rc = template_update_attribute(priv_tmpl, opaque_attr); if (rc != CKR_OK) { TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n", __func__, rc); free(opaque_attr); goto dh_generate_keypair_end; } } #ifdef DEBUG TRACE_DEBUG("%s DH SPKI\n", __func__); TRACE_DEBUG_DUMP(" ", publblob, publblobsize); #endif /* CKA_VALUE of the public key must hold 'y' */ rc = ber_decode_SPKI(publblob, publblobsize, &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, bit_str_len, &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]); 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); free(value_attr); goto dh_generate_keypair_end; } /* Supply CKA_VALUE_BITS to private key if not present or zero */ if (template_attribute_get_ulong(priv_tmpl, CKA_VALUE_BITS, &value_bits) != CKR_OK || value_bits == 0) { value_bits = data_len * 8; /* private key is same length as pub key */ rc = build_attribute(CKA_VALUE_BITS, (CK_BYTE *)&data_len, sizeof(value_bits), &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(priv_tmpl, value_attr); if (rc != CKR_OK) { TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n", __func__, rc); free(value_attr); goto dh_generate_keypair_end; } } dh_generate_keypair_end: 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); if (new_publ_attrs) free_attribute_array(new_publ_attrs, new_publ_attrs_len); if (new_priv_attrs) free_attribute_array(new_priv_attrs, new_priv_attrs_len); return rc; } static CK_RV dsa_generate_keypair(STDLL_TokData_t *tokdata, SESSION *sess, CK_MECHANISM_PTR pMechanism, TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl) { ep11_private_data_t *ep11_data = tokdata->private_data; CK_RV rc; CK_BYTE publblob[MAX_BLOBSIZE]; CK_BYTE publblobreenc[MAX_BLOBSIZE]; size_t publblobsize = sizeof(publblob); CK_BYTE privblob[MAX_BLOBSIZE]; CK_BYTE privblobreenc[MAX_BLOBSIZE]; size_t privblobsize = sizeof(privblob); CK_ATTRIBUTE *prime_attr = NULL; CK_ATTRIBUTE *sub_prime_attr = NULL; CK_ATTRIBUTE *base_attr = NULL; CK_ATTRIBUTE *opaque_attr = NULL; CK_ATTRIBUTE *value_attr = NULL; CK_ATTRIBUTE *attr = 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 *priv_ep11_pin_blob = NULL; CK_ULONG priv_ep11_pin_blob_len = 0; unsigned char *publ_ep11_pin_blob = NULL; CK_ULONG publ_ep11_pin_blob_len = 0; ep11_session_t *ep11_session = (ep11_session_t *) sess->private_data; CK_ATTRIBUTE *new_publ_attrs = NULL, *new_priv_attrs = NULL; CK_ULONG new_publ_attrs_len = 0, new_priv_attrs_len = 0; CK_ULONG spki_len; /* 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; memset(&dsa_pqgs, 0, sizeof(dsa_pqgs)); memset(publblob, 0, sizeof(publblob)); memset(publblobreenc, 0, sizeof(publblobreenc)); memset(privblob, 0, sizeof(privblob)); memset(privblobreenc, 0, sizeof(privblobreenc)); rc = build_ep11_attrs(tokdata, publ_tmpl, &dsa_pPublicKeyTemplate, &dsa_ulPublicKeyAttributeCount, CKK_DSA, CKO_PUBLIC_KEY, -1, pMechanism); if (rc != CKR_OK) { TRACE_ERROR("%s build_ep11_attrs failed with rc=0x%lx\n", __func__, rc); goto dsa_generate_keypair_end; } rc = build_ep11_attrs(tokdata, priv_tmpl, &dsa_pPrivateKeyTemplate, &dsa_ulPrivateKeyAttributeCount, CKK_DSA, CKO_PRIVATE_KEY, -1, pMechanism); if (rc != CKR_OK) { TRACE_ERROR("%s build_ep11_attrs failed with rc=0x%lx\n", __func__, rc); goto dsa_generate_keypair_end; } rc = check_key_attributes(tokdata, CKK_DSA, CKO_PUBLIC_KEY, dsa_pPublicKeyTemplate, dsa_ulPublicKeyAttributeCount, &new_publ_attrs, &new_publ_attrs_len, -1); if (rc != CKR_OK) { TRACE_ERROR("%s DSA 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, dsa_pPrivateKeyTemplate, dsa_ulPrivateKeyAttributeCount, &new_priv_attrs, &new_priv_attrs_len, -1); if (rc != CKR_OK) { TRACE_ERROR("%s DSA check private key attributes failed with " "rc=0x%lx\n", __func__, rc); goto dsa_generate_keypair_end; } /* * card does not want CKA_PRIME/CKA_BASE/CKA_SUBPRIME in template but in * dsa_pqgs */ rc = template_attribute_get_non_empty(publ_tmpl, CKA_PRIME, &prime_attr); if (rc != CKR_OK) { TRACE_ERROR("%s DSA No CKA_PRIME attribute found\n", __func__); goto dsa_generate_keypair_end; } rc = template_attribute_get_non_empty(publ_tmpl, CKA_SUBPRIME, &sub_prime_attr); if (rc != CKR_OK) { TRACE_ERROR("%s DSA No CKA_SUBPRIME attribute found\n", __func__); goto dsa_generate_keypair_end; } rc = template_attribute_get_non_empty(publ_tmpl, CKA_BASE, &base_attr); if (rc != CKR_OK) { TRACE_ERROR("%s DSA No CKA_BASE attribute found\n", __func__); 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(prime_attr->ulValueLen * 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, prime_attr->ulValueLen * 3); memcpy(dsa_pqgs.pqg, prime_attr->pValue, prime_attr->ulValueLen); memcpy(dsa_pqgs.pqg + prime_attr->ulValueLen + (prime_attr->ulValueLen - sub_prime_attr->ulValueLen), sub_prime_attr->pValue, sub_prime_attr->ulValueLen); memcpy(dsa_pqgs.pqg + 2 * prime_attr->ulValueLen + (prime_attr->ulValueLen - base_attr->ulValueLen), base_attr->pValue, base_attr->ulValueLen); dsa_pqgs.pqg_bytes = prime_attr->ulValueLen * 3; #ifdef DEBUG TRACE_DEBUG("%s P:\n", __func__); TRACE_DEBUG_DUMP(" ", &dsa_pqgs.pqg[0], prime_attr->ulValueLen); TRACE_DEBUG("%s Q:\n", __func__); TRACE_DEBUG_DUMP(" ", &dsa_pqgs.pqg[prime_attr->ulValueLen], prime_attr->ulValueLen); TRACE_DEBUG("%s G:\n", __func__); TRACE_DEBUG_DUMP(" ", &dsa_pqgs.pqg[2 * prime_attr->ulValueLen], prime_attr->ulValueLen); #endif rc = add_to_attribute_array(&new_publ_attrs, &new_publ_attrs_len, CKA_IBM_STRUCT_PARAMS, dsa_pqgs.pqg, dsa_pqgs.pqg_bytes); if (rc != CKR_OK) { TRACE_ERROR("%s add_to_attribute_array failed with rc=0x%lx\n", __func__, rc); 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); free(attr); goto dsa_generate_keypair_end; } rc = build_attribute(CKA_SUBPRIME, 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); free(attr); 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); free(attr); goto dsa_generate_keypair_end; } trace_attributes(__func__, "DSA public key attributes:", new_publ_attrs, new_publ_attrs_len); trace_attributes(__func__, "DSA private key attributes:", new_priv_attrs, new_priv_attrs_len); ep11_get_pin_blob(tokdata, ep11_session, ep11_is_session_object(new_priv_attrs, new_priv_attrs_len), ep11_is_private_object(new_priv_attrs, new_priv_attrs_len), &priv_ep11_pin_blob, &priv_ep11_pin_blob_len); ep11_get_pin_blob(tokdata, ep11_session, ep11_is_session_object(new_publ_attrs, new_publ_attrs_len), ep11_is_private_object(new_publ_attrs, new_publ_attrs_len), &publ_ep11_pin_blob, &publ_ep11_pin_blob_len); RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_CREATE_KEY2_START() rc = dll_m_GenerateKeyPair(pMechanism, new_publ_attrs, new_publ_attrs_len, new_priv_attrs, new_priv_attrs_len, priv_ep11_pin_blob, priv_ep11_pin_blob_len, privblob, &privblobsize, publblob, &publblobsize, target_info->target); RETRY_REENC_CREATE_KEY2_END(tokdata, sess, target_info, privblob, privblobreenc, privblobsize, publblob, publblobreenc, publblobsize, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, sess) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, sess); TRACE_ERROR("%s m_GenerateKeyPair failed with rc=0x%lx\n", __func__, rc); goto dsa_generate_keypair_end; } TRACE_INFO("%s rc=0x%lx plen=%zd publblobsize=0x%zx privblobsize=0x%zx\n", __func__, rc, prime_attr->ulValueLen, publblobsize, privblobsize); if (check_expected_mkvp(tokdata, privblob, privblobsize, NULL) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); rc = CKR_DEVICE_ERROR; goto dsa_generate_keypair_end; } if (priv_ep11_pin_blob != publ_ep11_pin_blob) { /* Re-create the MACed SPKI with the desired EP11 session */ spki_len = publblobsize; publblobsize = sizeof(publblob); rc = make_maced_spki(tokdata, sess, NULL, new_publ_attrs, new_publ_attrs_len, publblob, spki_len, publblob, publblobreenc, &publblobsize, -1); if (rc != CKR_OK) { TRACE_ERROR("%s failed to re-make a MACed-SPKI rc=0x%lx\n", __func__, rc); goto dsa_generate_keypair_end; } } if (check_expected_mkvp(tokdata, publblob, publblobsize, NULL) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); rc = CKR_DEVICE_ERROR; goto dsa_generate_keypair_end; } 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); free(opaque_attr); goto dsa_generate_keypair_end; } if (ep11_data->mk_change_active) { rc = build_attribute(CKA_IBM_OPAQUE_REENC, publblobreenc, publblobsize, &opaque_attr); if (rc != CKR_OK) { TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc); goto dsa_generate_keypair_end; } rc = template_update_attribute(publ_tmpl, opaque_attr); if (rc != CKR_OK) { TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n", __func__, rc); free(opaque_attr); goto dsa_generate_keypair_end; } } rc = build_attribute(CKA_IBM_OPAQUE, privblob, privblobsize, &opaque_attr); if (rc != CKR_OK) { TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc); goto dsa_generate_keypair_end; } rc = template_update_attribute(priv_tmpl, opaque_attr); if (rc != CKR_OK) { TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n", __func__, rc); free(opaque_attr); goto dsa_generate_keypair_end; } if (ep11_data->mk_change_active) { rc = build_attribute(CKA_IBM_OPAQUE_REENC, privblobreenc, privblobsize, &opaque_attr); if (rc != CKR_OK) { TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc); goto dsa_generate_keypair_end; } rc = template_update_attribute(priv_tmpl, opaque_attr); if (rc != CKR_OK) { TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n", __func__, rc); free(opaque_attr); goto dsa_generate_keypair_end; } } /* set CKA_VALUE of the public key, first get key from SPKI */ rc = ber_decode_SPKI(publblob, publblobsize, &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, bit_str_len, &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); free(value_attr); goto dsa_generate_keypair_end; } dsa_generate_keypair_end: 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); if (new_publ_attrs) free_attribute_array(new_publ_attrs, new_publ_attrs_len); if (new_priv_attrs) free_attribute_array(new_priv_attrs, new_priv_attrs_len); 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) { ep11_private_data_t *ep11_data = tokdata->private_data; CK_RV rc; CK_ATTRIBUTE *attr = NULL; CK_ATTRIBUTE *n_attr = NULL; CK_BYTE privkey_blob[MAX_BLOBSIZE]; CK_BYTE privkey_blobreenc[MAX_BLOBSIZE]; size_t privkey_blob_len = sizeof(privkey_blob); unsigned char spki[MAX_BLOBSIZE]; unsigned char spkireenc[MAX_BLOBSIZE]; size_t spki_len = sizeof(spki); CK_ULONG bit_str_len; CK_BYTE *key; CK_BYTE *data, *oid, *parm; CK_ULONG data_len, oid_len, parm_len; CK_ULONG field_len; CK_ULONG ktype; unsigned char *priv_ep11_pin_blob = NULL; CK_ULONG priv_ep11_pin_blob_len = 0; unsigned char *publ_ep11_pin_blob = NULL; CK_ULONG publ_ep11_pin_blob_len = 0; ep11_session_t *ep11_session = (ep11_session_t *) sess->private_data; CK_ATTRIBUTE *new_publ_attrs = NULL, *new_priv_attrs = NULL; CK_ULONG new_publ_attrs_len = 0, new_priv_attrs_len = 0; CK_ATTRIBUTE *new_publ_attrs2 = NULL, *new_priv_attrs2 = NULL; CK_ULONG new_publ_attrs2_len = 0, new_priv_attrs2_len = 0; const struct _ec *curve = NULL; CK_ULONG raw_spki_len; CK_MECHANISM ep11_mech = *pMechanism; CK_BBOOL allocated = CK_FALSE; ep11tok_pkcs11_mech_translate(tokdata, pMechanism->mechanism, &ep11_mech.mechanism); if (pMechanism->mechanism == CKM_EC_KEY_PAIR_GEN || pMechanism->mechanism == CKM_EC_EDWARDS_KEY_PAIR_GEN || pMechanism->mechanism == CKM_EC_MONTGOMERY_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; } if (ktype == CKK_EC) { if (!ep11tok_ec_curve_supported2(tokdata, publ_tmpl, &curve)) { TRACE_ERROR("Curve not supported.\n"); return CKR_CURVE_NOT_SUPPORTED; } } rc = build_ep11_attrs(tokdata, publ_tmpl, &new_publ_attrs, &new_publ_attrs_len, ktype, CKO_PUBLIC_KEY, curve != NULL ? curve->curve_type : -1, &ep11_mech); if (rc != CKR_OK) { TRACE_ERROR("%s build_ep11_attrs failed with rc=0x%lx\n", __func__, rc); goto error; } rc = build_ep11_attrs(tokdata, priv_tmpl, &new_priv_attrs, &new_priv_attrs_len, ktype, CKO_PRIVATE_KEY, curve != NULL ? curve->curve_type : -1, &ep11_mech); if (rc != CKR_OK) { TRACE_ERROR("%s build_ep11_attrs failed with rc=0x%lx\n", __func__, rc); goto error; } rc = check_key_attributes(tokdata, ktype, CKO_PUBLIC_KEY, new_publ_attrs, new_publ_attrs_len, &new_publ_attrs2, &new_publ_attrs2_len, curve != NULL ? curve->curve_type : -1); 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, new_priv_attrs, new_priv_attrs_len, &new_priv_attrs2, &new_priv_attrs2_len, curve != NULL ? curve->curve_type : -1); if (rc != CKR_OK) { TRACE_ERROR("%s RSA/EC check private key attributes failed with " "rc=0x%lx\n", __func__, rc); goto error; } trace_attributes(__func__, "RSA/EC public key attributes:", new_publ_attrs2, new_publ_attrs2_len); trace_attributes(__func__, "RSA/EC private key attributes:", new_priv_attrs2, new_priv_attrs2_len); ep11_get_pin_blob(tokdata, ep11_session, ep11_is_session_object(new_priv_attrs2, new_priv_attrs2_len), ep11_is_private_object(new_priv_attrs2, new_priv_attrs2_len), &priv_ep11_pin_blob, &priv_ep11_pin_blob_len); ep11_get_pin_blob(tokdata, ep11_session, ep11_is_session_object(new_publ_attrs, new_publ_attrs_len), ep11_is_private_object(new_publ_attrs, new_publ_attrs_len), &publ_ep11_pin_blob, &publ_ep11_pin_blob_len); RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_CREATE_KEY2_START() rc = dll_m_GenerateKeyPair(&ep11_mech, new_publ_attrs2, new_publ_attrs2_len, new_priv_attrs2, new_priv_attrs2_len, priv_ep11_pin_blob, priv_ep11_pin_blob_len, privkey_blob, &privkey_blob_len, spki, &spki_len, target_info->target); RETRY_REENC_CREATE_KEY2_END(tokdata, sess, target_info, privkey_blob, privkey_blobreenc, privkey_blob_len, spki, spkireenc, spki_len, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, sess) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, sess); TRACE_ERROR("%s m_GenerateKeyPair rc=0x%lx spki_len=0x%zx " "privkey_blob_len=0x%zx mech='%s'\n", __func__, rc, spki_len, privkey_blob_len, ep11_get_ckm(tokdata, ep11_mech.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(tokdata, ep11_mech.mechanism)); if (check_expected_mkvp(tokdata, privkey_blob, privkey_blob_len, NULL) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); rc = CKR_DEVICE_ERROR; goto error; } if (spki_len > MAX_BLOBSIZE || privkey_blob_len > MAX_BLOBSIZE) { TRACE_ERROR("%s blobsize error\n", __func__); rc = CKR_KEY_INDIGESTIBLE; goto error; } if (priv_ep11_pin_blob != publ_ep11_pin_blob) { /* Re-create the MACed SPKI with the desired EP11 session */ raw_spki_len = spki_len; spki_len = sizeof(spki); rc = make_maced_spki(tokdata, sess, NULL, new_publ_attrs, new_publ_attrs_len, spki, raw_spki_len, spki, spkireenc, &spki_len, curve != NULL ? curve->curve_type : -1); if (rc != CKR_OK) { TRACE_ERROR("%s failed to re-make a MACed-SPKI rc=0x%lx\n", __func__, rc); goto error; } } if (check_expected_mkvp(tokdata, spki, spki_len, NULL) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); rc = CKR_DEVICE_ERROR; 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); free(attr); goto error; } if (ep11_data->mk_change_active) { rc = build_attribute(CKA_IBM_OPAQUE_REENC, spkireenc, spki_len, &attr); if (rc != CKR_OK) { TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc); goto error; } rc = template_update_attribute(publ_tmpl, attr); if (rc != CKR_OK) { TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n", __func__, rc); free(attr); goto error; } } rc = build_attribute(CKA_IBM_OPAQUE, privkey_blob, privkey_blob_len, &attr); if (rc != CKR_OK) { TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc); goto error; } rc = template_update_attribute(priv_tmpl, attr); if (rc != CKR_OK) { TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n", __func__, rc); free(attr); goto error; } if (ep11_data->mk_change_active) { rc = build_attribute(CKA_IBM_OPAQUE_REENC, privkey_blobreenc, privkey_blob_len, &attr); if (rc != CKR_OK) { TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc); goto error; } rc = template_update_attribute(priv_tmpl, attr); if (rc != CKR_OK) { TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n", __func__, rc); free(attr); goto error; } } if (ep11_mech.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, spki_len, &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 /* * Edwards and Montgomery keys have a raw EC-point, but EC keys have * it as BER encoded OCTET STRING */ if (pMechanism->mechanism != CKM_EC_EDWARDS_KEY_PAIR_GEN && pMechanism->mechanism != CKM_EC_MONTGOMERY_KEY_PAIR_GEN) { /* 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; } allocated = TRUE; } rc = build_attribute(CKA_EC_POINT, data, data_len, &attr); if (allocated) 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); free(attr); goto error; } /* copy CKA_EC_PARAMS/CKA_ECDSA_PARAMS to private template */ rc = template_attribute_get_non_empty(publ_tmpl, CKA_EC_PARAMS, &attr); if (rc == CKR_OK) { 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); free(n_attr); goto error; } } rc = template_attribute_get_non_empty(publ_tmpl, CKA_ECDSA_PARAMS, &attr); if (rc == CKR_OK) { 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); free(n_attr); 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; CK_ULONG modulus_len, publ_exp_len; rc = ber_decode_SPKI(spki, spki_len, &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, bit_str_len, &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; modulus_len = bit_str_len - field_len + data_len; rc = ber_decode_INTEGER(modulus, modulus_len, &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); free(attr); goto error; } /* read public exponent */ publ_exp = modulus + field_len; publ_exp_len = bit_str_len - field_len; rc = ber_decode_INTEGER(publ_exp, publ_exp_len, &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); free(attr); goto error; } } error: if (new_publ_attrs) free_attribute_array(new_publ_attrs, new_publ_attrs_len); if (new_priv_attrs) free_attribute_array(new_priv_attrs, new_priv_attrs_len); if (new_publ_attrs2) free_attribute_array(new_publ_attrs2, new_publ_attrs2_len); if (new_priv_attrs2) free_attribute_array(new_priv_attrs2, new_priv_attrs2_len); return rc; } static CK_RV pqc_generate_keypair(STDLL_TokData_t *tokdata, SESSION *sess, CK_MECHANISM_PTR pMechanism, TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl) { ep11_private_data_t *ep11_data = tokdata->private_data; CK_RV rc; CK_ATTRIBUTE *attr = NULL; CK_BYTE privkey_blob[MAX_BLOBSIZE]; CK_BYTE privkey_blobreenc[MAX_BLOBSIZE]; size_t privkey_blob_len = sizeof(privkey_blob); unsigned char spki[MAX_BLOBSIZE]; unsigned char spkireenc[MAX_BLOBSIZE]; size_t spki_len = sizeof(spki); CK_ULONG ktype; unsigned char *priv_ep11_pin_blob = NULL; CK_ULONG priv_ep11_pin_blob_len = 0; unsigned char *publ_ep11_pin_blob = NULL; CK_ULONG publ_ep11_pin_blob_len = 0; ep11_session_t *ep11_session = (ep11_session_t *) sess->private_data; CK_ATTRIBUTE *new_publ_attrs = NULL, *new_priv_attrs = NULL; CK_ULONG new_publ_attrs_len = 0, new_priv_attrs_len = 0; CK_ATTRIBUTE *new_publ_attrs2 = NULL, *new_priv_attrs2 = NULL; CK_ULONG new_publ_attrs2_len = 0, new_priv_attrs2_len = 0; const struct pqc_oid *pqc_oid; const char *key_type_str; CK_ULONG raw_spki_len; CK_ATTRIBUTE_TYPE param_attr; CK_BYTE *param_val; CK_ULONG param_len; CK_MECHANISM ep11_mech = *pMechanism; ep11tok_pkcs11_mech_translate(tokdata, pMechanism->mechanism, &ep11_mech.mechanism); switch (pMechanism->mechanism) { case CKM_IBM_DILITHIUM: key_type_str = "Dilithium"; ktype = CKK_IBM_PQC_DILITHIUM; break; case CKM_IBM_KYBER: key_type_str = "Kyber"; ktype = CKK_IBM_PQC_KYBER; break; case CKM_IBM_ML_DSA_KEY_PAIR_GEN: key_type_str = "ML-DSA"; ktype = CKK_IBM_ML_DSA; break; case CKM_IBM_ML_KEM_KEY_PAIR_GEN: key_type_str = "ML-KEM"; ktype = CKK_IBM_ML_KEM; break; case CKM_ML_DSA_KEY_PAIR_GEN: key_type_str = "ML-DSA"; ktype = CKK_ML_DSA; break; case CKM_ML_KEM_KEY_PAIR_GEN: key_type_str = "ML-KEM"; ktype = CKK_ML_KEM; break; default: TRACE_ERROR("Invalid mechanism provided for %s\n ", __func__); return CKR_MECHANISM_INVALID; } rc = build_ep11_attrs(tokdata, publ_tmpl, &new_publ_attrs, &new_publ_attrs_len, ktype, CKO_PUBLIC_KEY, -1, &ep11_mech); if (rc != CKR_OK) { TRACE_ERROR("%s build_ep11_attrs failed with rc=0x%lx\n", __func__, rc); goto error; } rc = build_ep11_attrs(tokdata, priv_tmpl, &new_priv_attrs, &new_priv_attrs_len, ktype, CKO_PRIVATE_KEY, -1, &ep11_mech); if (rc != CKR_OK) { TRACE_ERROR("%s build_ep11_attrs failed with rc=0x%lx\n", __func__, rc); goto error; } pqc_oid = pqc_get_keyform_mode(publ_tmpl, pMechanism->mechanism); if (pqc_oid == NULL) pqc_oid = pqc_get_keyform_mode(priv_tmpl, pMechanism->mechanism); if (pqc_oid == NULL) { switch (pMechanism->mechanism) { case CKM_IBM_DILITHIUM: pqc_oid = find_pqc_by_keyform(dilithium_oids, CK_IBM_DILITHIUM_KEYFORM_ROUND2_65); break; case CKM_IBM_KYBER: pqc_oid = find_pqc_by_keyform(kyber_oids, CK_IBM_KYBER_KEYFORM_ROUND2_1024); break; case CKM_IBM_ML_DSA_KEY_PAIR_GEN: case CKM_IBM_ML_KEM_KEY_PAIR_GEN: case CKM_ML_DSA_KEY_PAIR_GEN: case CKM_ML_KEM_KEY_PAIR_GEN: /* No default for ML-DSA and ML-KEM */ /* fallthrough */ default: /* pqc_oid stays NULL */ break; } } if (pqc_oid == NULL) { TRACE_ERROR("%s Failed to determine %s OID\n", __func__, key_type_str); rc = CKR_FUNCTION_FAILED; goto error; } TRACE_INFO("%s Generate %s key with keyform %lu\n", __func__, key_type_str, pqc_oid->keyform); switch (pMechanism->mechanism) { case CKM_IBM_DILITHIUM: case CKM_IBM_KYBER: param_attr = CKA_IBM_PQC_PARAMS; param_val = (CK_BYTE *)pqc_oid->oid; param_len = pqc_oid->oid_len; break; case CKM_IBM_ML_DSA_KEY_PAIR_GEN: case CKM_IBM_ML_KEM_KEY_PAIR_GEN: case CKM_ML_DSA_KEY_PAIR_GEN: case CKM_ML_KEM_KEY_PAIR_GEN: param_attr = CKA_IBM_PARAMETER_SET; param_val = (CK_BYTE *)&pqc_oid->keyform; param_len = sizeof(pqc_oid->keyform); break; default: return CKR_MECHANISM_INVALID; } rc = add_to_attribute_array(&new_publ_attrs, &new_publ_attrs_len, param_attr, param_val, param_len); if (rc != CKR_OK) { TRACE_ERROR("%s add_to_attribute_array failed with rc=0x%lx\n", __func__, rc); goto error; } rc = add_to_attribute_array(&new_priv_attrs, &new_priv_attrs_len, param_attr, param_val, param_len); if (rc != CKR_OK) { TRACE_ERROR("%s add_to_attribute_array failed with rc=0x%lx\n", __func__, rc); goto error; } rc = check_key_attributes(tokdata, ktype, CKO_PUBLIC_KEY, new_publ_attrs, new_publ_attrs_len, &new_publ_attrs2, &new_publ_attrs2_len, -1); if (rc != CKR_OK) { TRACE_ERROR("%s %s check public key attributes failed with " "rc=0x%lx\n", __func__, key_type_str, rc); goto error; } rc = check_key_attributes(tokdata, ktype, CKO_PRIVATE_KEY, new_priv_attrs, new_priv_attrs_len, &new_priv_attrs2, &new_priv_attrs2_len, -1); if (rc != CKR_OK) { TRACE_ERROR("%s %s check private key attributes failed with " "rc=0x%lx\n", __func__, key_type_str, rc); goto error; } trace_attributes(__func__, "PQC public key attributes:", new_publ_attrs2, new_publ_attrs2_len); trace_attributes(__func__, "PQC private key attributes:", new_priv_attrs2, new_priv_attrs2_len); ep11_get_pin_blob(tokdata, ep11_session, ep11_is_session_object(new_priv_attrs2, new_priv_attrs2_len), ep11_is_private_object(new_priv_attrs2, new_priv_attrs2_len), &priv_ep11_pin_blob, &priv_ep11_pin_blob_len); ep11_get_pin_blob(tokdata, ep11_session, ep11_is_session_object(new_publ_attrs, new_publ_attrs_len), ep11_is_private_object(new_publ_attrs, new_publ_attrs_len), &publ_ep11_pin_blob, &publ_ep11_pin_blob_len); RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_CREATE_KEY2_START() if (ep11_pqc_strength_supported(target_info, pMechanism->mechanism, pqc_oid)) rc = dll_m_GenerateKeyPair(&ep11_mech, new_publ_attrs2, new_publ_attrs2_len, new_priv_attrs2, new_priv_attrs2_len, priv_ep11_pin_blob, priv_ep11_pin_blob_len, privkey_blob, &privkey_blob_len, spki, &spki_len, target_info->target); else rc = CKR_KEY_SIZE_RANGE; RETRY_REENC_CREATE_KEY2_END(tokdata, sess, target_info, privkey_blob, privkey_blobreenc, privkey_blob_len, spki, spkireenc, spki_len, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, sess) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, sess); TRACE_ERROR("%s m_GenerateKeyPair rc=0x%lx spki_len=0x%zx " "privkey_blob_len=0x%zx mech='%s'\n", __func__, rc, spki_len, privkey_blob_len, ep11_get_ckm(tokdata, ep11_mech.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(tokdata, ep11_mech.mechanism)); if (check_expected_mkvp(tokdata, privkey_blob, privkey_blob_len, NULL) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); rc = CKR_DEVICE_ERROR; goto error; } if (spki_len > MAX_BLOBSIZE || privkey_blob_len > MAX_BLOBSIZE) { TRACE_ERROR("%s blobsize error\n", __func__); rc = CKR_KEY_INDIGESTIBLE; goto error; } if (priv_ep11_pin_blob != publ_ep11_pin_blob) { /* Re-create the MACed SPKI with the desired EP11 session */ raw_spki_len = spki_len; spki_len = sizeof(spki); rc = make_maced_spki(tokdata, sess, NULL, new_publ_attrs, new_publ_attrs_len, spki, raw_spki_len, spki, spkireenc, &spki_len, -1); if (rc != CKR_OK) { TRACE_ERROR("%s failed to re-make a MACed-SPKI rc=0x%lx\n", __func__, rc); goto error; } } if (check_expected_mkvp(tokdata, spki, spki_len, NULL) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); rc = CKR_DEVICE_ERROR; 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); free(attr); goto error; } if (ep11_data->mk_change_active) { rc = build_attribute(CKA_IBM_OPAQUE_REENC, spkireenc, spki_len, &attr); if (rc != CKR_OK) { TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc); goto error; } rc = template_update_attribute(publ_tmpl, attr); if (rc != CKR_OK) { TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n", __func__, rc); free(attr); goto error; } } rc = build_attribute(CKA_IBM_OPAQUE, privkey_blob, privkey_blob_len, &attr); if (rc != CKR_OK) { TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc); goto error; } rc = template_update_attribute(priv_tmpl, attr); if (rc != CKR_OK) { TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n", __func__, rc); free(attr); goto error; } if (ep11_data->mk_change_active) { rc = build_attribute(CKA_IBM_OPAQUE_REENC, privkey_blobreenc, privkey_blob_len, &attr); if (rc != CKR_OK) { TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc); goto error; } rc = template_update_attribute(priv_tmpl, attr); if (rc != CKR_OK) { TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n", __func__, rc); free(attr); goto error; } } /* Decode SPKI */ rc = pqc_priv_unwrap_get_data(publ_tmpl, ktype, spki, spki_len, TRUE); if (rc != CKR_OK) { TRACE_ERROR("%s pqc_priv_unwrap_get_data with rc=0x%lx\n", __func__, rc); goto error; } rc = pqc_priv_unwrap_get_data(priv_tmpl, ktype, spki, spki_len, FALSE); if (rc != CKR_OK) { TRACE_ERROR("%s pqc_priv_unwrap_get_data with rc=0x%lx\n", __func__, rc); goto error; } error: if (new_publ_attrs) free_attribute_array(new_publ_attrs, new_publ_attrs_len); if (new_priv_attrs) free_attribute_array(new_priv_attrs, new_priv_attrs_len); if (new_publ_attrs2) free_attribute_array(new_publ_attrs2, new_publ_attrs2_len); if (new_priv_attrs2) free_attribute_array(new_priv_attrs2, new_priv_attrs2_len); 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_BBOOL count_statistics, CK_ULONG operation) { 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; CK_BYTE *spki = NULL; CK_ULONG spki_length = 0; CK_ULONG mode; switch (operation) { case OP_KEYGEN: mode = MODE_KEYGEN; break; case OP_ENCAPSULATE: mode = MODE_ENCAPS; break; default: TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } /* Get the keytype to use when creating the key object */ rc = pkcs_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 = pkcs_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; } rc = check_ab_pair(pPublicKeyTemplate, ulPublicKeyAttributeCount, pPrivateKeyTemplate, ulPrivateKeyAttributeCount); if (rc != CKR_OK) goto error; #ifndef NO_PKEY /* Ensure the firmware master key verification pattern is available */ rc = ep11tok_pkey_get_firmware_mk_vp(tokdata, sess); if (rc != CKR_OK && rc != CKR_FUNCTION_NOT_SUPPORTED) goto error; #endif /* NO_PKEY */ /* Now build the skeleton key. */ rc = object_mgr_create_skel(tokdata, sess, pPublicKeyTemplate, ulPublicKeyAttributeCount, mode, 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, 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); break; case CKM_EC_KEY_PAIR_GEN: /* takes same parameters as RSA */ case CKM_EC_EDWARDS_KEY_PAIR_GEN: case CKM_EC_MONTGOMERY_KEY_PAIR_GEN: 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); break; case CKM_DSA_KEY_PAIR_GEN: rc = dsa_generate_keypair(tokdata, sess, pMechanism, public_key_obj->template, private_key_obj->template); break; case CKM_IBM_DILITHIUM: case CKM_IBM_KYBER: case CKM_IBM_ML_DSA_KEY_PAIR_GEN: case CKM_IBM_ML_KEM_KEY_PAIR_GEN: case CKM_ML_DSA_KEY_PAIR_GEN: case CKM_ML_KEM_KEY_PAIR_GEN: rc = pqc_generate_keypair(tokdata, sess, pMechanism, public_key_obj->template, private_key_obj->template); break; default: TRACE_ERROR("%s invalid mech %s\n", __func__, ep11_get_ckm(tokdata, 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); } rc = update_ep11_attrs_from_blob(tokdata, sess, private_key_obj, FALSE); if (rc != CKR_OK) { TRACE_ERROR("%s update_ep11_attrs_from_blob failed with rc=0x%lx\n", __func__, rc); goto error; } rc = update_ep11_attrs_from_blob(tokdata, sess, public_key_obj, FALSE); if (rc != CKR_OK) { TRACE_ERROR("%s update_ep11_attrs_from_blob failed with rc=0x%lx\n", __func__, rc); goto error; } /* 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; } n_attr = NULL; } 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; } n_attr = NULL; } /* add CKA_KEY_GEN_MECHANISM */ rc = build_attribute(CKA_KEY_GEN_MECHANISM, (CK_BYTE *)&pMechanism->mechanism, sizeof(CK_MECHANISM_TYPE), &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(public_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; } n_attr = NULL; rc = build_attribute(CKA_KEY_GEN_MECHANISM, (CK_BYTE *)&pMechanism->mechanism, sizeof(CK_MECHANISM_TYPE), &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; } n_attr = NULL; /* Extract the SPKI and add CKA_PUBLIC_KEY_INFO to both keys */ rc = publ_key_get_spki(public_key_obj->template, publ_ktype, FALSE, &spki, &spki_length, FALSE); if (rc != CKR_OK) { TRACE_DEVEL("publ_key_get_spki failed\n"); goto error; } rc = build_attribute(CKA_PUBLIC_KEY_INFO, spki, spki_length, &n_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto error; } rc = template_update_attribute(public_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; } n_attr = NULL; rc = build_attribute(CKA_PUBLIC_KEY_INFO, spki, spki_length, &n_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); 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; } n_attr = NULL; free(spki); spki = NULL; /* Set CKA_ALWAYS_SENSITIVE and CKA_NEVER_EXTRACTABLE */ rc = key_mgr_apply_always_sensitive_never_extractable_attrs(tokdata, private_key_obj); if (rc != CKR_OK) { TRACE_ERROR("%s key_mgr_apply_always_sensitive_never_extractable_attrs " "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; } /* Enforce policy */ 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; } if (count_statistics) INC_COUNTER(tokdata, sess, pMechanism, private_key_obj, POLICY_STRENGTH_IDX_0); return rc; error: if (public_key_obj) object_free(public_key_obj); if (private_key_obj) object_free(private_key_obj); if (spki != NULL) free(spki); if (n_attr != NULL) free(n_attr); *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; CK_RV rc; UNUSED(tokdata); /* blob already exists */ rc = template_attribute_get_non_empty(key_obj->template, CKA_IBM_OPAQUE, &attr); if (rc == CKR_OK) { *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 rc; } } /* Returns a re-enciphered blob for a key object. * The passed key_obj must hold the READ lock! */ static CK_RV obj_opaque_2_reenc_blob(STDLL_TokData_t *tokdata, OBJECT *key_obj, CK_BYTE **blob, size_t *blobsize) { CK_ATTRIBUTE *attr = NULL; CK_RV rc; UNUSED(tokdata); /* blob already exists */ rc = template_attribute_get_non_empty(key_obj->template, CKA_IBM_OPAQUE_REENC, &attr); if (rc == CKR_OK) { *blob = attr->pValue; *blobsize = (size_t) attr->ulValueLen; TRACE_INFO("%s reenc blob found blobsize=0x%zx\n", __func__, *blobsize); return CKR_OK; } else { TRACE_INFO("%s no reenc blob\n", __func__); return rc; } } /* Returns a blob for a key handle. * The blob is created if none was build yet. * The caller must put the returned kobj when no longer needed. * 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; } /** * Initializes the sign/verify context for the two IBM-specific Edwards * curves. Common mechanisms using Edwards curves are introduced with * PKCS#11 3.0 and support for these will be added in common code at a later * time. Let's keep support for IBM-specific ED curves local to the EP11 token, * because they are only supported here. */ CK_RV ep11tok_sign_verify_init_ibm_ed(STDLL_TokData_t *tokdata, SESSION *sess, SIGN_VERIFY_CONTEXT *ctx, CK_MECHANISM *mech, CK_OBJECT_HANDLE key, CK_BBOOL sign, CK_BBOOL checkauth) { OBJECT *key_obj = 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; } /* Check 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; } ctx->auth_required = FALSE; if (checkauth) { rc = key_object_is_always_authenticate(key_obj->template, &ctx->auth_required); if (rc != CKR_OK) { TRACE_ERROR("key_object_is_always_authenticate failed\n"); goto done; } } if (sign) { rc = template_attribute_get_bool(key_obj->template, CKA_SIGN, &flag); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_SIGN for the key.\n"); rc = CKR_KEY_FUNCTION_NOT_PERMITTED; goto done; } } else { rc = template_attribute_get_bool(key_obj->template, CKA_VERIFY, &flag); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VERIFY for the key.\n"); rc = CKR_KEY_FUNCTION_NOT_PERMITTED; goto done; } } if (flag != TRUE) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_FUNCTION_NOT_PERMITTED)); rc = CKR_KEY_FUNCTION_NOT_PERMITTED; goto done; } if (!key_object_is_mechanism_allowed(key_obj->template, mech->mechanism)) { TRACE_ERROR("Mechanism not allowed per CKA_ALLOWED_MECHANISMS.\n"); rc = CKR_MECHANISM_INVALID; goto done; } if (mech->ulParameterLen != 0) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } rc = template_attribute_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); goto done; } if (keytype != CKK_EC) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); rc = CKR_KEY_TYPE_INCONSISTENT; goto done; } /* Check key class: must be either a private or public key */ rc = template_attribute_get_ulong(key_obj->template, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); goto done; } if (sign) { if (class != CKO_PRIVATE_KEY) { TRACE_ERROR("This operation requires a private key.\n"); rc = CKR_KEY_FUNCTION_NOT_PERMITTED; goto done; } } else { 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 = 0; ctx->context = NULL; ctx->key = key; ctx->mech.mechanism = mech->mechanism; ctx->mech.pParameter = NULL; ctx->mech.ulParameterLen = 0; ctx->multi_init = FALSE; ctx->multi = FALSE; ctx->active = TRUE; ctx->recover = FALSE; ctx->pkey_active = FALSE; rc = CKR_OK; done: object_put(tokdata, key_obj, TRUE); key_obj = NULL; return rc; } CK_RV ep11tok_hmac_mech_check_keytype(CK_MECHANISM_TYPE mech, OBJECT *key_obj) { CK_KEY_TYPE keytype, exp_keytype, alt_keytype; CK_RV rc; rc = template_attribute_get_ulong(key_obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find attribute CKA_KEY_TYPE for the key.\n"); return CKR_TEMPLATE_INCOMPLETE; } rc = pkcsget_keytype_for_mech(mech, &exp_keytype, &alt_keytype); if (rc != CKR_OK) { TRACE_ERROR("pkcsget_keytype_for_mech failed.\n"); return rc; } if (keytype != exp_keytype && keytype != alt_keytype) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); return CKR_KEY_TYPE_INCONSISTENT; } return CKR_OK; } CK_RV ep11tok_check_single_mech_key(STDLL_TokData_t *tokdata, SESSION * session, CK_MECHANISM *mech, CK_OBJECT_HANDLE key, CK_ULONG operation, CK_BBOOL *auth_required) { OBJECT *key_obj = NULL; size_t blob_len = 0; CK_BYTE *blob; CK_ATTRIBUTE_TYPE type; CK_BBOOL flag; int policy_op; const char *str_op; CK_RV rc; switch (operation) { case OP_ENCRYPT_INIT: policy_op = POLICY_CHECK_ENCRYPT; type = CKA_ENCRYPT; str_op = "encrypt"; break; case OP_DECRYPT_INIT: policy_op = POLICY_CHECK_DECRYPT; type = CKA_DECRYPT; str_op = "decrypt"; break; case OP_SIGN_INIT: policy_op = POLICY_CHECK_SIGNATURE; type = CKA_SIGN; str_op = "sign"; break; case OP_VERIFY_INIT: policy_op = POLICY_CHECK_VERIFY; type = CKA_VERIFY; str_op = "verify"; break; default: TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); return CKR_ARGUMENTS_BAD; } 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; } rc = template_attribute_get_bool(key_obj->template, type, &flag); if (rc != CKR_OK) { TRACE_ERROR("Could not find attribute 0x%lx for the key (op: %s).\n", type, str_op); rc = CKR_KEY_FUNCTION_NOT_PERMITTED; goto error; } if (flag != TRUE) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_FUNCTION_NOT_PERMITTED)); rc = CKR_KEY_FUNCTION_NOT_PERMITTED; goto error; } if (!key_object_is_mechanism_allowed(key_obj->template, mech->mechanism)) { TRACE_ERROR("Mechanism not allowed per CKA_ALLOWED_MECHANISMS.\n"); rc = CKR_MECHANISM_INVALID; goto error; } rc = tokdata->policy->is_mech_allowed(tokdata->policy, mech, &key_obj->strength, policy_op, session); if (rc != CKR_OK) { TRACE_ERROR("POLICY_VIOLATION on %s initialization\n", str_op); goto error; } if (auth_required != NULL) { rc = key_object_is_always_authenticate(key_obj->template, auth_required); if (rc != CKR_OK) { TRACE_ERROR("key_object_is_always_authenticate failed\n"); goto error; } } switch (mech->mechanism) { 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_SHA3_224_HMAC: case CKM_SHA3_256_HMAC: case CKM_SHA3_384_HMAC: case CKM_SHA3_512_HMAC: case CKM_IBM_SHA3_224_HMAC: case CKM_IBM_SHA3_256_HMAC: case CKM_IBM_SHA3_384_HMAC: case CKM_IBM_SHA3_512_HMAC: rc = ep11tok_hmac_mech_check_keytype(mech->mechanism, key_obj); if (rc != CKR_OK) goto error; break; } INC_COUNTER(tokdata, session, mech, key_obj, POLICY_STRENGTH_IDX_0); error: object_put(tokdata, key_obj, TRUE); key_obj = NULL; return rc; } struct ECDSA_OTHER_MECH_PARAM { CK_MECHANISM mech; ECSG_Var_t param; }; static CK_RV ep11tok_ecdsa_other_mech_adjust(CK_MECHANISM *mech, struct ECDSA_OTHER_MECH_PARAM *mech_ep11) { CK_IBM_ECDSA_OTHER_PARAMS *param; if (mech->mechanism != CKM_IBM_ECDSA_OTHER) return CKR_MECHANISM_INVALID; if (mech->ulParameterLen != sizeof(CK_IBM_ECDSA_OTHER_PARAMS) || mech->pParameter == NULL) { TRACE_ERROR("%s Invalid mechanism param for CKM_IBM_ECDSA_OTHER\n", __func__); return CKR_MECHANISM_PARAM_INVALID; } mech_ep11->mech.mechanism = CKM_IBM_ECDSA_OTHER; mech_ep11->mech.pParameter = &mech_ep11->param; mech_ep11->mech.ulParameterLen = sizeof(mech_ep11->param); param = (CK_IBM_ECDSA_OTHER_PARAMS *)mech->pParameter; switch (param->submechanism) { case CKM_IBM_ECSDSA_RAND: mech_ep11->param = ECSG_IBM_ECSDSA_S256; break; case CKM_IBM_ECSDSA_COMPR_MULTI: mech_ep11->param = ECSG_IBM_ECSDSA_COMPR_MULTI; break; case CKM_IBM_BLS: mech_ep11->param = ECSG_IBM_BLS; break; default: TRACE_ERROR("%s Invalid sub mechanism for CKM_IBM_ECDSA_OTHER: %lu\n", __func__, param->submechanism); return CKR_MECHANISM_PARAM_INVALID; } return CKR_OK; } static CK_RV ep11tok_bls_mech_pre_process_signsingle( CK_MECHANISM *mech, struct EP11_BLS12_MECH *mech_ep11, void ** pAggrElemets) { CK_IBM_ECDSA_OTHER_BLS_PARAMS *param; CK_ULONG i; CK_BYTE *aggrsignature = NULL; if (mech->ulParameterLen != sizeof(CK_IBM_ECDSA_OTHER_BLS_PARAMS)) { TRACE_ERROR("Mechanism parameter length not as expected\n"); return CKR_MECHANISM_PARAM_INVALID; } param = (CK_IBM_ECDSA_OTHER_BLS_PARAMS *)mech->pParameter; if (param->elementSize != CK_IBM_BLS12_381_SIGN_LEN) { TRACE_ERROR("Invalid element size %lu\n", param->elementSize); return CKR_MECHANISM_PARAM_INVALID; } if (param->numElements > CK_IBM_BLS_MAX_AGGREGATIONS) { TRACE_ERROR("Invalid number of elements %lu\n", param->numElements); return CKR_MECHANISM_PARAM_INVALID; } mech_ep11->mech.mechanism = mech->mechanism; mech_ep11->mech.pParameter = &mech_ep11->param; mech_ep11->mech.ulParameterLen = sizeof(mech_ep11->param); memset(&mech_ep11->param, 0, sizeof(mech_ep11->param)); mech_ep11->param.version = 0; mech_ep11->param.mode = CK_IBM_EC_AGG_BLS12_381_SIGN; mech_ep11->param.perElementSize = param->elementSize; mech_ep11->param.ulElementsLen = param->elementSize * param->numElements; aggrsignature = malloc(param->elementSize * param->numElements); if (aggrsignature == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); return CKR_HOST_MEMORY; } for (i = 0; i < param->numElements ; i++) { memcpy(aggrsignature + i * mech_ep11->param.perElementSize, (CK_BYTE_PTR)param->pAggrElements[i], mech_ep11->param.perElementSize); } mech_ep11->param.pElements = aggrsignature; *pAggrElemets = mech_ep11->param.pElements; return CKR_OK; } struct RSA_OAEP_MECH_PARAM { CK_MECHANISM mech; CK_RSA_PKCS_OAEP_PARAMS param; }; static CK_RV ep11tok_rsa_oaep_mech_adjust(STDLL_TokData_t *tokdata, CK_MECHANISM *mech, struct RSA_OAEP_MECH_PARAM *mech_ep11) { if (mech->mechanism != CKM_RSA_PKCS_OAEP) return CKR_MECHANISM_INVALID; if (mech->ulParameterLen != sizeof(CK_RSA_PKCS_OAEP_PARAMS) || mech->pParameter == NULL) { TRACE_ERROR("%s Invalid mechanism param for CKM_RSA_PKCS_OAEP\n", __func__); return CKR_MECHANISM_PARAM_INVALID; } mech_ep11->mech.mechanism = mech->mechanism; mech_ep11->mech.pParameter = &mech_ep11->param; mech_ep11->mech.ulParameterLen = sizeof(mech_ep11->param); memcpy(&mech_ep11->param, mech->pParameter, sizeof(mech_ep11->param)); ep11tok_pkcs11_mech_translate(tokdata, mech_ep11->param.hashAlg, &mech_ep11->param.hashAlg); ep11tok_pkcs11_mgf_translate(tokdata, mech_ep11->param.mgf, &mech_ep11->param.mgf); return CKR_OK; } CK_BBOOL ep11tok_is_common_code_derive_mech(CK_MECHANISM *mech) { switch (mech->mechanism) { case CKM_PUB_KEY_FROM_PRIV_KEY: return CK_TRUE; default: return CK_FALSE; } } CK_BBOOL ep11tok_is_common_code_sign_verify_mech(CK_MECHANISM *mech) { switch (mech->mechanism) { case CKM_ML_DSA: return CK_TRUE; default: return CK_FALSE; } } CK_BOOL ep11tok_mech_single_only(CK_MECHANISM *mech) { switch (mech->mechanism) { case CKM_IBM_ECDSA_OTHER: case CKM_IBM_KYBER: case CKM_RSA_PKCS: case CKM_RSA_PKCS_OAEP: case CKM_RSA_PKCS_PSS: case CKM_RSA_X9_31: case CKM_ECDSA: case CKM_DSA: case CKM_IBM_ED25519_SHA512: case CKM_IBM_ED448_SHA3: case CKM_EDDSA: case CKM_IBM_DILITHIUM: case CKM_IBM_EC_AGGREGATE: case CKM_IBM_ML_DSA: return CK_TRUE; default: return CK_FALSE; } } CK_RV ep11tok_sign_init(STDLL_TokData_t * tokdata, SESSION * session, CK_MECHANISM * mech, CK_BBOOL recover_mode, CK_OBJECT_HANDLE key, CK_BBOOL checkauth) { 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 * 2; CK_BYTE *ep11_sign_state = calloc(ep11_sign_state_l, 1); struct ECDSA_OTHER_MECH_PARAM mech_ep11; CK_BYTE *useblob, *usestate; size_t useblobsize, usestate_len; CK_ULONG strength_index = POLICY_STRENGTH_IDX_0; CK_MECHANISM ep11_mech; 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); free(ep11_sign_state); return rc; } rc = tokdata->policy->is_mech_allowed(tokdata->policy, mech, &key_obj->strength, POLICY_CHECK_SIGNATURE, session); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: Sign init\n"); free(ep11_sign_state); goto done; } if (!key_object_is_mechanism_allowed(key_obj->template, mech->mechanism)) { TRACE_ERROR("Mechanism not allowed per CKA_ALLOWED_MECHANISMS.\n"); rc = CKR_MECHANISM_INVALID; free(ep11_sign_state); goto done; } #ifndef NO_PKEY rc = ep11tok_pkey_check(tokdata, session, key_obj, mech); switch (rc) { case CKR_OK: strength_index = key_obj->strength.strength; /* * Release obj lock, sign_mgr_init or ep11tok_sign_verify_init_ibm_ed * may re-acquire the lock */ object_put(tokdata, key_obj, TRUE); key_obj = NULL; /* Note that Edwards curves in general are not yet supported in * opencryptoki. These two special IBM specific ED mechs are only * supported by the ep11token, so let's keep them local here. */ if (mech->mechanism == CKM_IBM_ED25519_SHA512 || mech->mechanism == CKM_IBM_ED448_SHA3) rc = ep11tok_sign_verify_init_ibm_ed(tokdata, session, ctx, mech, key, CK_TRUE, checkauth); else /* Policy already checked. */ rc = sign_mgr_init(tokdata, session, ctx, mech, recover_mode, key, FALSE, checkauth); if (rc == CKR_OK) ctx->pkey_active = TRUE; /* Regardless of the rc goto done here, because ep11tok_pkey_check * could have unlocked/relocked the obj so that the blob is no more * valid. */ free(ep11_sign_state); goto done; case CKR_FUNCTION_NOT_SUPPORTED: /* ep11 fallback */ break; default: free(ep11_sign_state); goto done; } #endif /* NO_PKEY */ switch (mech->mechanism) { case CKM_IBM_ECDSA_OTHER: rc = ep11tok_ecdsa_other_mech_adjust(mech, &mech_ep11); if (rc != CKR_OK) { free(ep11_sign_state); goto done; } mech = &mech_ep11.mech; 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: case CKM_SHA3_224_HMAC: case CKM_SHA3_256_HMAC: case CKM_SHA3_384_HMAC: case CKM_SHA3_512_HMAC: case CKM_IBM_SHA3_224_HMAC: case CKM_IBM_SHA3_256_HMAC: case CKM_IBM_SHA3_384_HMAC: case CKM_IBM_SHA3_512_HMAC: rc = ep11tok_hmac_mech_check_keytype(mech->mechanism, key_obj); if (rc != CKR_OK) { free(ep11_sign_state); goto done; } break; case CKM_IBM_ED25519_SHA512: case CKM_IBM_ED448_SHA3: rc = ep11tok_ibm_ed_mont_mech_check_keytype(key_obj); if (rc != CKR_OK) { free(ep11_sign_state); goto done; } break; } if (checkauth) { rc = key_object_is_always_authenticate(key_obj->template, &ctx->auth_required); if (rc != CKR_OK) { TRACE_ERROR("key_object_is_always_authenticate failed\n"); free(ep11_sign_state); goto done; } } ep11_mech = *mech; ep11tok_pkcs11_mech_translate(tokdata, mech->mechanism, &ep11_mech.mechanism); /* * state is allocated large enough to hold 2 times the max state blob. * Initially use the first half only. The second half is for the * re-enciphered state blob (if mk change is active). */ ep11_sign_state_l /= 2; RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_BLOB_STATE_START(tokdata, target_info, key_obj, keyblob, keyblobsize, useblob, useblobsize, ep11_sign_state, ep11_sign_state + ep11_sign_state_l, ep11_sign_state_l, usestate, usestate_len, rc) if (ep11_pqc_obj_strength_supported(target_info, ep11_mech.mechanism, key_obj)) rc = dll_m_SignInit(usestate, &usestate_len, &ep11_mech, useblob, useblobsize, target_info->target); else rc = CKR_KEY_SIZE_RANGE; if (rc == CKR_OK && retry == 1) { /* * Initially, the real state_len is unknown, and is set to * allocated state size / 2. When the state was created on * an APQN with new WK set already, move the state to the * final place, which is state + usestate_len, where * usestate_len now is the real state size. */ memmove(ep11_sign_state + usestate_len, ep11_sign_state + ep11_sign_state_l, usestate_len); } ep11_sign_state_l = usestate_len; RETRY_REENC_BLOB_STATE_END(tokdata, session, target_info, keyblob, keyblobsize, useblob, useblobsize, ep11_sign_state, ep11_sign_state + ep11_sign_state_l, ep11_sign_state_l, usestate, usestate_len, TRUE, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); TRACE_ERROR("%s rc=0x%lx blobsize=0x%zx key=0x%lx mech=0x%lx\n", __func__, rc, keyblobsize, key, ep11_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 * 2; /* current and re-enciphered state */ ctx->pkey_active = FALSE; if (mech != &ctx->mech) { /* deferred init dup'ed mech already */ ctx->mech.mechanism = mech->mechanism; if (mech->ulParameterLen > 0 && mech->pParameter != NULL) { ctx->mech.pParameter = (CK_BYTE *) malloc(mech->ulParameterLen); if (ctx->mech.pParameter == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; sign_mgr_cleanup(tokdata, session, ctx); goto done; } memcpy(ctx->mech.pParameter, mech->pParameter, mech->ulParameterLen); ctx->mech.ulParameterLen = mech->ulParameterLen; } } TRACE_INFO("%s rc=0x%lx blobsize=0x%zx key=0x%lx mech=0x%lx\n", __func__, rc, keyblobsize, key, ep11_mech.mechanism); } done: if (rc == CKR_OK) INC_COUNTER(tokdata, session, mech, key_obj, strength_index); 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) { #ifdef NO_PKEY UNUSED(length_only); #endif CK_RV rc; SIGN_VERIFY_CONTEXT *ctx = &session->sign_ctx; size_t keyblobsize = 0; CK_BYTE *keyblob; OBJECT *key_obj = NULL; CK_BYTE *state; size_t state_len; rc = h_opaque_2_blob(tokdata, ctx->key, &keyblob, &keyblobsize, &key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("%s h_opaque_2_blob, rc=0x%lx\n", __func__, rc); return rc; } #ifndef NO_PKEY if (ctx->pkey_active) { /* Note that Edwards curves in general are not yet supported in * opencryptoki. These two special IBM specific ED mechs are only * supported by the ep11token, so let's keep them local here. */ if (ctx->mech.mechanism == CKM_IBM_ED25519_SHA512 || ctx->mech.mechanism == CKM_IBM_ED448_SHA3) { rc = pkey_ed_sign(tokdata, session, key_obj, in_data, in_data_len, signature, sig_len, ep11tok_pkey_convert_key); } else { /* Release obj lock, sign_mgr_sign may re-acquire the lock */ object_put(tokdata, key_obj, TRUE); key_obj = NULL; rc = sign_mgr_sign(tokdata, session, length_only, ctx, in_data, in_data_len, signature, sig_len); } goto done; /* no ep11 fallback possible */ } #endif /* NO_PKEY */ RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_UPDATE_BLOB_START(tokdata, target_info, ctx->context, ctx->context_len / 2, ctx->context + (ctx->context_len / 2), ctx->context_len / 2, state, state_len) rc = dll_m_Sign(state, state_len, in_data, in_data_len, signature, sig_len, target_info->target); RETRY_UPDATE_BLOB_END(tokdata, session, target_info, ctx->context, ctx->context_len / 2, ctx->context + (ctx->context_len / 2), ctx->context_len / 2, state, state_len, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); TRACE_ERROR("%s rc=0x%lx\n", __func__, rc); } else { TRACE_INFO("%s rc=0x%lx\n", __func__, rc); } #ifndef NO_PKEY done: #endif object_put(tokdata, key_obj, TRUE); key_obj = NULL; return rc; } CK_RV ep11tok_sign_update(STDLL_TokData_t * tokdata, SESSION * session, CK_BYTE * in_data, CK_ULONG in_data_len) { CK_RV rc; SIGN_VERIFY_CONTEXT *ctx = &session->sign_ctx; size_t keyblobsize = 0; CK_BYTE *keyblob; OBJECT *key_obj = NULL; CK_BYTE *state; size_t state_len; if (!in_data || !in_data_len) return CKR_OK; if (ctx->pkey_active) { rc = sign_mgr_sign_update(tokdata, session, ctx, in_data, in_data_len); goto done; /* no ep11 fallback possible */ } rc = h_opaque_2_blob(tokdata, ctx->key, &keyblob, &keyblobsize, &key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("%s h_opaque_2_blob, rc=0x%lx\n", __func__, rc); return rc; } RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_UPDATE_BLOB_START(tokdata, target_info, ctx->context, ctx->context_len / 2, ctx->context + (ctx->context_len / 2), ctx->context_len / 2, state, state_len) rc = dll_m_SignUpdate(state, state_len, in_data, in_data_len, target_info->target); RETRY_UPDATE_BLOB_END(tokdata, session, target_info, ctx->context, ctx->context_len / 2, ctx->context + (ctx->context_len / 2), ctx->context_len / 2, state, state_len, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); 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_sign_final(STDLL_TokData_t * tokdata, SESSION * session, CK_BBOOL length_only, CK_BYTE * signature, CK_ULONG * sig_len) { CK_RV rc; SIGN_VERIFY_CONTEXT *ctx = &session->sign_ctx; size_t keyblobsize = 0; CK_BYTE *keyblob; OBJECT *key_obj = NULL; CK_BYTE *state; size_t state_len; if (ctx->pkey_active) { rc = sign_mgr_sign_final(tokdata, session, length_only, ctx, signature, sig_len); goto done; /* no ep11 fallback possible */ } rc = h_opaque_2_blob(tokdata, ctx->key, &keyblob, &keyblobsize, &key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("%s h_opaque_2_blob, rc=0x%lx\n", __func__, rc); return rc; } RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_UPDATE_BLOB_START(tokdata, target_info, ctx->context, ctx->context_len / 2, ctx->context + (ctx->context_len / 2), ctx->context_len / 2, state, state_len) rc = dll_m_SignFinal(state, state_len, signature, sig_len, target_info->target); RETRY_UPDATE_BLOB_END(tokdata, session, target_info, ctx->context, ctx->context_len / 2, ctx->context + (ctx->context_len / 2), ctx->context_len / 2, state, state_len, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); 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_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; struct ECDSA_OTHER_MECH_PARAM mech_ep11 = { 0 }; struct EP11_BLS12_MECH mech_bls; void *pAggrElements = NULL; CK_BYTE *useblob = NULL; size_t useblobsize = 0; CK_MECHANISM ep11_mech; if (!is_ec_aggregate_mechanism(mech)) { 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; } rc = tokdata->policy->is_mech_allowed(tokdata->policy, mech, &key_obj->strength, POLICY_CHECK_SIGNATURE, session); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: Sign single\n"); goto done; } if (!key_object_is_mechanism_allowed(key_obj->template, mech->mechanism)) { TRACE_ERROR("Mechanism not allowed per CKA_ALLOWED_MECHANISMS.\n"); rc = CKR_MECHANISM_INVALID; goto done; } } switch (mech->mechanism) { case CKM_IBM_ECDSA_OTHER: rc = ep11tok_ecdsa_other_mech_adjust(mech, &mech_ep11); if (rc != CKR_OK) goto done; mech = &mech_ep11.mech; 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: case CKM_SHA3_224_HMAC: case CKM_SHA3_256_HMAC: case CKM_SHA3_384_HMAC: case CKM_SHA3_512_HMAC: case CKM_IBM_SHA3_224_HMAC: case CKM_IBM_SHA3_256_HMAC: case CKM_IBM_SHA3_384_HMAC: case CKM_IBM_SHA3_512_HMAC: rc = ep11tok_hmac_mech_check_keytype(mech->mechanism, key_obj); if (rc != CKR_OK) goto done; break; case CKM_IBM_EC_AGGREGATE: rc = ep11tok_bls_mech_pre_process_signsingle(mech, &mech_bls, &pAggrElements); if (rc != CKR_OK) goto done; mech = &mech_bls.mech; break; case CKM_EDDSA: rc = ep11tok_ec_edwards_mech_preprocess(tokdata, key_obj, mech, &ep11_mech); if (rc != CKR_OK) goto done; mech = &ep11_mech; break; } ep11_mech = *mech; ep11tok_pkcs11_mech_translate(tokdata, mech->mechanism, &ep11_mech.mechanism); RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_BLOB_START(tokdata, target_info, key_obj, keyblob, keyblobsize, useblob, useblobsize, rc) if (ep11_pqc_obj_strength_supported(target_info, ep11_mech.mechanism, key_obj)) rc = dll_m_SignSingle(useblob, useblobsize, &ep11_mech, in_data, in_data_len, signature, sig_len, target_info->target); else rc = CKR_KEY_SIZE_RANGE; RETRY_REENC_BLOB_END(tokdata, target_info, useblob, useblobsize, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); TRACE_ERROR("%s rc=0x%lx\n", __func__, rc); } else { TRACE_INFO("%s rc=0x%lx\n", __func__, rc); } /* Currently EP11 is returning 96 bytes as the BLS signature length, * but this needs to be updated to 192 bytes. */ if (length_only && mech->mechanism == CKM_IBM_ECDSA_OTHER) { if (mech_ep11.param == ECSG_IBM_BLS && *sig_len == CK_IBM_BLS12_381_SIGN_LEN / 2) *sig_len = CK_IBM_BLS12_381_SIGN_LEN; } done: object_put(tokdata, key_obj, TRUE); key_obj = NULL; if (pAggrElements != NULL) free(pAggrElements); return rc; } CK_RV ep11tok_verify_init(STDLL_TokData_t * tokdata, SESSION * session, CK_MECHANISM * mech, CK_BBOOL recover_mode, CK_OBJECT_HANDLE key) { 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 * 2; CK_BYTE *ep11_sign_state = calloc(ep11_sign_state_l, 1); struct ECDSA_OTHER_MECH_PARAM mech_ep11; CK_BYTE *useblob, *usestate; size_t useblob_len, usestate_len; CK_ULONG strength_index = POLICY_STRENGTH_IDX_0; CK_MECHANISM ep11_mech; 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); free(ep11_sign_state); return rc; } rc = tokdata->policy->is_mech_allowed(tokdata->policy, mech, &key_obj->strength, POLICY_CHECK_VERIFY, session); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: Verify init\n"); free(ep11_sign_state); goto done; } if (!key_object_is_mechanism_allowed(key_obj->template, mech->mechanism)) { TRACE_ERROR("Mechanism not allowed per CKA_ALLOWED_MECHANISMS.\n"); rc = CKR_MECHANISM_INVALID; free(ep11_sign_state); goto done; } /* * 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); free(ep11_sign_state); goto done; } #ifndef NO_PKEY rc = ep11tok_pkey_check(tokdata, session, key_obj, mech); switch (rc) { case CKR_OK: strength_index = key_obj->strength.strength; /* * Release obj lock, verify_mgr_init or ep11tok_sign_verify_init_ibm_ed * may re-acquire the lock */ object_put(tokdata, key_obj, TRUE); key_obj = NULL; /* Note that Edwards curves in general are not yet supported in * opencryptoki. These two special IBM specific ED mechs are only * supported by the ep11token, so let's keep them local here. */ if (mech->mechanism == CKM_IBM_ED25519_SHA512 || mech->mechanism == CKM_IBM_ED448_SHA3) rc = ep11tok_sign_verify_init_ibm_ed(tokdata, session, ctx, mech, key, CK_FALSE, CK_FALSE); else /* Policy already checked */ rc = verify_mgr_init(tokdata, session, ctx, mech, CK_FALSE, key, FALSE); if (rc == CKR_OK) ctx->pkey_active = TRUE; /* Regardless of the rc goto done here, because ep11tok_pkey_check * could have unlocked/relocked the obj so that the blob is no more * valid. */ free(ep11_sign_state); goto done; case CKR_FUNCTION_NOT_SUPPORTED: /* ep11 fallback */ break; default: free(ep11_sign_state); goto done; } #endif /* NO_PKEY */ switch (mech->mechanism) { case CKM_IBM_ECDSA_OTHER: rc = ep11tok_ecdsa_other_mech_adjust(mech, &mech_ep11); if (rc != CKR_OK) { free(ep11_sign_state); goto done; } mech = &mech_ep11.mech; 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: case CKM_SHA3_224_HMAC: case CKM_SHA3_256_HMAC: case CKM_SHA3_384_HMAC: case CKM_SHA3_512_HMAC: case CKM_IBM_SHA3_224_HMAC: case CKM_IBM_SHA3_256_HMAC: case CKM_IBM_SHA3_384_HMAC: case CKM_IBM_SHA3_512_HMAC: rc = ep11tok_hmac_mech_check_keytype(mech->mechanism, key_obj); if (rc != CKR_OK) { free(ep11_sign_state); goto done; } break; case CKM_IBM_ED25519_SHA512: case CKM_IBM_ED448_SHA3: rc = ep11tok_ibm_ed_mont_mech_check_keytype(key_obj); if (rc != CKR_OK) { free(ep11_sign_state); goto done; } break; } ep11_mech = *mech; ep11tok_pkcs11_mech_translate(tokdata, mech->mechanism, &ep11_mech.mechanism); /* * state is allocated large enough to hold 2 times the max state blob. * Initially use the first half only. The second half is for the * re-enciphered state blob (if mk change is active). */ ep11_sign_state_l /= 2; RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_BLOB_STATE_START(tokdata, target_info, key_obj, spki, spki_len, useblob, useblob_len, ep11_sign_state, ep11_sign_state + ep11_sign_state_l, ep11_sign_state_l, usestate, usestate_len, rc) if (ep11_pqc_obj_strength_supported(target_info, ep11_mech.mechanism, key_obj)) rc = dll_m_VerifyInit(usestate, &usestate_len, &ep11_mech, useblob, useblob_len, target_info->target); else rc = CKR_KEY_SIZE_RANGE; if (rc == CKR_OK && retry == 1) { /* * Initially, the real state_len is unknown, and is set to * allocated state size / 2. When the state was created on * an APQN with new WK set already, move the state to the * final place, which is state + usestate_len, where * usestate_len now is the real state size. */ memmove(ep11_sign_state + usestate_len, ep11_sign_state + ep11_sign_state_l, usestate_len); } ep11_sign_state_l = usestate_len; RETRY_REENC_BLOB_STATE_END(tokdata, session, target_info, spki, spki_len, useblob, useblob_len, ep11_sign_state, ep11_sign_state + ep11_sign_state_l, ep11_sign_state_l, usestate, usestate_len, TRUE, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); 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, ep11_mech.mechanism); free(ep11_sign_state); } else { ctx->key = key; ctx->active = TRUE; ctx->context = ep11_sign_state; ctx->context_len = ep11_sign_state_l * 2; /* current and re-enciphered state */ ctx->pkey_active = FALSE; if (mech != &ctx->mech) { /* deferred init dup'ed mech already */ ctx->mech.mechanism = mech->mechanism; if (mech->ulParameterLen > 0 && mech->pParameter != NULL) { ctx->mech.pParameter = (CK_BYTE *) malloc(mech->ulParameterLen); if (ctx->mech.pParameter == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; verify_mgr_cleanup(tokdata, session, ctx); goto done; } memcpy(ctx->mech.pParameter, mech->pParameter, mech->ulParameterLen); ctx->mech.ulParameterLen = mech->ulParameterLen; } } 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, ep11_mech.mechanism); } done: if (rc == CKR_OK) INC_COUNTER(tokdata, session, mech, key_obj, strength_index); 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) { CK_RV rc; SIGN_VERIFY_CONTEXT *ctx = &session->verify_ctx; size_t keyblobsize = 0; CK_BYTE *keyblob; OBJECT *key_obj = NULL; CK_BYTE *state; size_t state_len; rc = h_opaque_2_blob(tokdata, ctx->key, &keyblob, &keyblobsize, &key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("%s h_opaque_2_blob, rc=0x%lx\n", __func__, rc); return rc; } #ifndef NO_PKEY if (ctx->pkey_active) { /* Note that Edwards curves in general are not yet supported in * opencryptoki. These two special IBM specific ED mechs are only * supported by the ep11token, so let's keep them local here. */ if (ctx->mech.mechanism == CKM_IBM_ED25519_SHA512 || ctx->mech.mechanism == CKM_IBM_ED448_SHA3) { rc = pkey_ed_verify(key_obj, in_data, in_data_len, signature, sig_len, CKK_EC); } else { /* Release obj lock, verify_mgr_verify may re-acquire the lock */ object_put(tokdata, key_obj, TRUE); key_obj = NULL; rc = verify_mgr_verify(tokdata, session, ctx, in_data, in_data_len, signature, sig_len); } goto done; /* no ep11 fallback possible */ } #endif /* NO_PKEY */ RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_UPDATE_BLOB_START(tokdata, target_info, ctx->context, ctx->context_len / 2, ctx->context + (ctx->context_len / 2), ctx->context_len / 2, state, state_len) rc = dll_m_Verify(state, state_len, in_data, in_data_len, signature, sig_len, target_info->target); RETRY_UPDATE_BLOB_END(tokdata, session, target_info, ctx->context, ctx->context_len / 2, ctx->context + (ctx->context_len / 2), ctx->context_len / 2, state, state_len, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); TRACE_ERROR("%s rc=0x%lx\n", __func__, rc); } else { TRACE_INFO("%s rc=0x%lx\n", __func__, rc); } #ifndef NO_PKEY done: #endif object_put(tokdata, key_obj, TRUE); key_obj = NULL; return rc; } CK_RV ep11tok_verify_update(STDLL_TokData_t * tokdata, SESSION * session, CK_BYTE * in_data, CK_ULONG in_data_len) { CK_RV rc; SIGN_VERIFY_CONTEXT *ctx = &session->verify_ctx; size_t keyblobsize = 0; CK_BYTE *keyblob; OBJECT *key_obj = NULL; CK_BYTE *state; size_t state_len; if (!in_data || !in_data_len) return CKR_OK; if (ctx->pkey_active) { rc = verify_mgr_verify_update(tokdata, session, ctx, in_data, in_data_len); goto done; /* no ep11 fallback possible */ } rc = h_opaque_2_blob(tokdata, ctx->key, &keyblob, &keyblobsize, &key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("%s h_opaque_2_blob, rc=0x%lx\n", __func__, rc); return rc; } RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_UPDATE_BLOB_START(tokdata, target_info, ctx->context, ctx->context_len / 2, ctx->context + (ctx->context_len / 2), ctx->context_len / 2, state, state_len) rc = dll_m_VerifyUpdate(state, state_len, in_data, in_data_len, target_info->target); RETRY_UPDATE_BLOB_END(tokdata, session, target_info, ctx->context, ctx->context_len / 2, ctx->context + (ctx->context_len / 2), ctx->context_len / 2, state, state_len, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); 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_verify_final(STDLL_TokData_t * tokdata, SESSION * session, CK_BYTE * signature, CK_ULONG sig_len) { CK_RV rc; SIGN_VERIFY_CONTEXT *ctx = &session->verify_ctx; size_t keyblobsize = 0; CK_BYTE *keyblob; OBJECT *key_obj = NULL; CK_BYTE *state; size_t state_len; if (ctx->pkey_active) { rc = verify_mgr_verify_final(tokdata, session, ctx, signature, sig_len); goto done; /* no ep11 fallback possible */ } rc = h_opaque_2_blob(tokdata, ctx->key, &keyblob, &keyblobsize, &key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("%s h_opaque_2_blob, rc=0x%lx\n", __func__, rc); return rc; } RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_UPDATE_BLOB_START(tokdata, target_info, ctx->context, ctx->context_len / 2, ctx->context + (ctx->context_len / 2), ctx->context_len / 2, state, state_len) rc = dll_m_VerifyFinal(state, state_len, signature, sig_len, target_info->target); RETRY_UPDATE_BLOB_END(tokdata, session, target_info, ctx->context, ctx->context_len / 2, ctx->context + (ctx->context_len / 2), ctx->context_len / 2, state, state_len, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); 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_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; struct ECDSA_OTHER_MECH_PARAM mech_ep11; CK_BYTE *useblob = NULL; size_t useblob_len = 0; CK_MECHANISM ep11_mech; 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; } rc = tokdata->policy->is_mech_allowed(tokdata->policy, mech, &key_obj->strength, POLICY_CHECK_VERIFY, session); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: Verify single\n"); goto done; } if (!key_object_is_mechanism_allowed(key_obj->template, mech->mechanism)) { TRACE_ERROR("Mechanism not allowed per CKA_ALLOWED_MECHANISMS.\n"); rc = CKR_MECHANISM_INVALID; goto done; } /* * 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; } switch (mech->mechanism) { case CKM_IBM_ECDSA_OTHER: rc = ep11tok_ecdsa_other_mech_adjust(mech, &mech_ep11); if (rc != CKR_OK) goto done; mech = &mech_ep11.mech; 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: case CKM_SHA3_224_HMAC: case CKM_SHA3_256_HMAC: case CKM_SHA3_384_HMAC: case CKM_SHA3_512_HMAC: case CKM_IBM_SHA3_224_HMAC: case CKM_IBM_SHA3_256_HMAC: case CKM_IBM_SHA3_384_HMAC: case CKM_IBM_SHA3_512_HMAC: rc = ep11tok_hmac_mech_check_keytype(mech->mechanism, key_obj); if (rc != CKR_OK) goto done; break; case CKM_EDDSA: rc = ep11tok_ec_edwards_mech_preprocess(tokdata, key_obj, mech, &ep11_mech); if (rc != CKR_OK) goto done; mech = &ep11_mech; break; } ep11_mech = *mech; ep11tok_pkcs11_mech_translate(tokdata, mech->mechanism, &ep11_mech.mechanism); RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_BLOB_START(tokdata, target_info, key_obj, spki, spki_len, useblob, useblob_len, rc) if (ep11_pqc_obj_strength_supported(target_info, ep11_mech.mechanism, key_obj)) rc = dll_m_VerifySingle(useblob, useblob_len, &ep11_mech, in_data, in_data_len, signature, sig_len, target_info->target); else rc = CKR_KEY_SIZE_RANGE; RETRY_REENC_BLOB_END(tokdata, target_info, useblob, useblob_len, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); TRACE_ERROR("%s rc=0x%lx\n", __func__, rc); } else { TRACE_INFO("%s rc=0x%lx\n", __func__, rc); } done: object_put(tokdata, key_obj, TRUE); key_obj = NULL; return rc; } CK_RV token_specific_ml_dsa_sign(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, const struct pqc_oid *oid, CK_MECHANISM *mech, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *signature, CK_ULONG *signature_len, OBJECT *key_obj, CK_BBOOL final_part) { size_t keyblobsize = 0; CK_BYTE *keyblob; CK_BYTE *useblob = NULL; size_t useblobsize = 0; CK_IBM_SIGN_ADDITIONAL_CONTEXT ep11_mech_param; CK_MECHANISM ep11_mech = { CKM_IBM_ML_DSA, &ep11_mech_param, sizeof(ep11_mech_param) }; CK_BYTE *tmp; CK_RV rc; if (mech->mechanism != CKM_ML_DSA) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); return CKR_MECHANISM_INVALID; } if (!final_part || (sess->sign_ctx.context != NULL && in_data_len > 0)) { /* Collect the input data in the context */ if (in_data_len == 0) return CKR_OK; tmp = (CK_BYTE *)realloc(sess->sign_ctx.context, sess->sign_ctx.context_len + in_data_len); if (tmp == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); return CKR_HOST_MEMORY; } memcpy(tmp + sess->sign_ctx.context_len, in_data, in_data_len); sess->sign_ctx.context = tmp; sess->sign_ctx.context_len += in_data_len; if (!final_part) return CKR_OK; } if (sess->sign_ctx.context != NULL && sess->sign_ctx.context_len > 0) { in_data = sess->sign_ctx.context; in_data_len = sess->sign_ctx.context_len; } rc = obj_opaque_2_blob(tokdata, key_obj, &keyblob, &keyblobsize); if (rc != CKR_OK) { TRACE_ERROR("%s no key-blob rc=0x%lx\n", __func__, rc); return rc; } rc = ml_dsa_translate_ibm_sign_mech_param_from_sign( (CK_SIGN_ADDITIONAL_CONTEXT *)mech->pParameter, &ep11_mech_param); if (rc != CKR_OK) { TRACE_ERROR("ml_dsa_translate_ibm_sign_mech_param_from_sign failed\n"); return rc; } RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_BLOB_START(tokdata, target_info, key_obj, keyblob, keyblobsize, useblob, useblobsize, rc) if (ep11_pqc_strength_supported(target_info, ep11_mech.mechanism, oid)) rc = dll_m_SignSingle(useblob, useblobsize, &ep11_mech, in_data, in_data_len, signature, signature_len, target_info->target); else rc = CKR_KEY_SIZE_RANGE; RETRY_REENC_BLOB_END(tokdata, target_info, useblob, useblobsize, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, sess) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, sess); TRACE_ERROR("%s rc=0x%lx\n", __func__, rc); } else { TRACE_INFO("%s rc=0x%lx\n", __func__, rc); } if (final_part && sess->sign_ctx.context != NULL && !length_only) { free(sess->sign_ctx.context); sess->sign_ctx.context = NULL; sess->sign_ctx.context_len = 0; } return rc; } CK_RV token_specific_ml_dsa_verify(STDLL_TokData_t *tokdata, SESSION *sess, const struct pqc_oid *oid, CK_MECHANISM *mech, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *signature, CK_ULONG signature_len, OBJECT *key_obj, CK_BBOOL final_part) { size_t keyblobsize = 0; CK_BYTE *keyblob; CK_BYTE *useblob = NULL; size_t useblobsize = 0; CK_IBM_SIGN_ADDITIONAL_CONTEXT ep11_mech_param; CK_MECHANISM ep11_mech = { CKM_IBM_ML_DSA, &ep11_mech_param, sizeof(ep11_mech_param) }; CK_BYTE *tmp; CK_RV rc; if (mech->mechanism != CKM_ML_DSA) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); return CKR_MECHANISM_INVALID; } if (!final_part || (sess->verify_ctx.context != NULL && in_data_len > 0)) { /* Collect the input data in the context */ if (in_data_len == 0) return CKR_OK; tmp = (CK_BYTE *)realloc(sess->verify_ctx.context, sess->verify_ctx.context_len + in_data_len); if (tmp == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); return CKR_HOST_MEMORY; } memcpy(tmp + sess->verify_ctx.context_len, in_data, in_data_len); sess->verify_ctx.context = tmp; sess->verify_ctx.context_len += in_data_len; if (!final_part) return CKR_OK; } if (sess->verify_ctx.context != NULL && sess->verify_ctx.context_len > 0) { in_data = sess->verify_ctx.context; in_data_len = sess->verify_ctx.context_len; } rc = obj_opaque_2_blob(tokdata, key_obj, &keyblob, &keyblobsize); if (rc != CKR_OK) { TRACE_ERROR("%s no key-blob rc=0x%lx\n", __func__, rc); return rc; } rc = ml_dsa_translate_ibm_sign_mech_param_from_sign( (CK_SIGN_ADDITIONAL_CONTEXT *)mech->pParameter, &ep11_mech_param); if (rc != CKR_OK) { TRACE_ERROR("ml_dsa_translate_ibm_sign_mech_param_from_sign failed\n"); return rc; } RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_BLOB_START(tokdata, target_info, key_obj, keyblob, keyblobsize, useblob, useblobsize, rc) if (ep11_pqc_strength_supported(target_info, ep11_mech.mechanism, oid)) rc = dll_m_VerifySingle(useblob, useblobsize, &ep11_mech, in_data, in_data_len, signature, signature_len, target_info->target); else rc = CKR_KEY_SIZE_RANGE; RETRY_REENC_BLOB_END(tokdata, target_info, useblob, useblobsize, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, sess) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, sess); TRACE_ERROR("%s rc=0x%lx\n", __func__, rc); } else { TRACE_INFO("%s rc=0x%lx\n", __func__, rc); } if (final_part && sess->verify_ctx.context != NULL) { free(sess->verify_ctx.context); sess->verify_ctx.context = NULL; sess->verify_ctx.context_len = 0; } 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) { CK_RV rc = CKR_OK; ENCR_DECR_CONTEXT *ctx = &session->decr_ctx; CK_BBOOL length_only = (output_part == NULL ? CK_TRUE : CK_FALSE); size_t keyblobsize = 0; CK_BYTE *keyblob; OBJECT *key_obj = NULL; CK_BYTE *state; size_t state_len; if (ctx->pkey_active) { rc = decr_mgr_decrypt_final(tokdata, session, length_only, ctx, output_part, p_output_part_len); goto done; /* no ep11 fallback possible */ } rc = h_opaque_2_blob(tokdata, ctx->key, &keyblob, &keyblobsize, &key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("%s h_opaque_2_blob, rc=0x%lx\n", __func__, rc); return rc; } RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_UPDATE_BLOB_START(tokdata, target_info, ctx->context, ctx->context_len / 2, ctx->context + (ctx->context_len / 2), ctx->context_len / 2, state, state_len) rc = dll_m_DecryptFinal(state, state_len, output_part, p_output_part_len, target_info->target); RETRY_UPDATE_BLOB_END(tokdata, session, target_info, ctx->context, ctx->context_len / 2, ctx->context + (ctx->context_len / 2), ctx->context_len / 2, state, state_len, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) rc = constant_time_select(constant_time_eq(rc, CKR_OK), ep11_error_to_pkcs11_error(rc, session), rc); if (!is_rsa_mechanism(ctx->mech.mechanism)) { if (rc != CKR_OK) { 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(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 rc = CKR_OK; ENCR_DECR_CONTEXT *ctx = &session->decr_ctx; CK_BBOOL length_only = (output_data == NULL ? CK_TRUE : CK_FALSE); size_t keyblobsize = 0; CK_BYTE *keyblob; OBJECT *key_obj = NULL; CK_BYTE *state; size_t state_len; if (ctx->pkey_active) { rc = decr_mgr_decrypt(tokdata, session, length_only, ctx, input_data, input_data_len, output_data, p_output_data_len); goto done; /* no ep11 fallback possible */ } rc = h_opaque_2_blob(tokdata, ctx->key, &keyblob, &keyblobsize, &key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("%s h_opaque_2_blob, rc=0x%lx\n", __func__, rc); return rc; } RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_UPDATE_BLOB_START(tokdata, target_info, ctx->context, ctx->context_len / 2, ctx->context + (ctx->context_len / 2), ctx->context_len / 2, state, state_len) rc = dll_m_Decrypt(state, state_len, input_data, input_data_len, output_data, p_output_data_len, target_info->target); RETRY_UPDATE_BLOB_END(tokdata, session, target_info, ctx->context, ctx->context_len / 2, ctx->context + (ctx->context_len / 2), ctx->context_len / 2, state, state_len, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) rc = constant_time_select(constant_time_eq(rc, CKR_OK), ep11_error_to_pkcs11_error(rc, session), rc); if (!is_rsa_mechanism(ctx->mech.mechanism)) { if (rc != CKR_OK) { 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_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 rc = CKR_OK; ENCR_DECR_CONTEXT *ctx = &session->decr_ctx; CK_BBOOL length_only = (output_part == NULL ? CK_TRUE : CK_FALSE); size_t keyblobsize = 0; CK_BYTE *keyblob; OBJECT *key_obj = NULL; CK_BYTE *state; size_t state_len; if (!input_part || !input_part_len) { *p_output_part_len = 0; return CKR_OK; /* nothing to update, keep context */ } if (ctx->pkey_active) { rc = decr_mgr_decrypt_update(tokdata, session, length_only, ctx, input_part, input_part_len, output_part, p_output_part_len); goto done; /* no ep11 fallback possible */ } rc = h_opaque_2_blob(tokdata, ctx->key, &keyblob, &keyblobsize, &key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("%s h_opaque_2_blob, rc=0x%lx\n", __func__, rc); return rc; } RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_UPDATE_BLOB_START(tokdata, target_info, ctx->context, ctx->context_len / 2, ctx->context + (ctx->context_len / 2), ctx->context_len / 2, state, state_len) rc = dll_m_DecryptUpdate(state, state_len, input_part, input_part_len, output_part, p_output_part_len, target_info->target); RETRY_UPDATE_BLOB_END(tokdata, session, target_info, ctx->context, ctx->context_len / 2, ctx->context + (ctx->context_len / 2), ctx->context_len / 2, state, state_len, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) rc = constant_time_select(constant_time_eq(rc, CKR_OK), ep11_error_to_pkcs11_error(rc, session), rc); if (!is_rsa_mechanism(ctx->mech.mechanism)) { if (rc != CKR_OK) { 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_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; CK_BYTE *useblob = NULL; size_t useblobsize = 0; struct RSA_OAEP_MECH_PARAM rsa_oaep_mech_ep11; 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; } if (!key_object_is_mechanism_allowed(key_obj->template, mech->mechanism)) { TRACE_ERROR("Mechanism not allowed per CKA_ALLOWED_MECHANISMS.\n"); rc = CKR_MECHANISM_INVALID; goto done; } rc = tokdata->policy->is_mech_allowed(tokdata->policy, mech, &key_obj->strength, POLICY_CHECK_DECRYPT, session); if (rc != CKR_OK) { TRACE_ERROR("POLICY_VIOLATION on decrypt single\n"); goto done; } if (mech->mechanism == CKM_RSA_PKCS_OAEP) { rc = ep11tok_rsa_oaep_mech_adjust(tokdata, mech, &rsa_oaep_mech_ep11); if (rc != CKR_OK) goto done; mech = &rsa_oaep_mech_ep11.mech; } RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_BLOB_START(tokdata, target_info, key_obj, keyblob, keyblobsize, useblob, useblobsize, rc) if (ep11_pqc_obj_strength_supported(target_info, mech->mechanism, key_obj)) rc = dll_m_DecryptSingle(useblob, useblobsize, mech, input_data, input_data_len, output_data, p_output_data_len, target_info->target); else rc = CKR_KEY_SIZE_RANGE; RETRY_REENC_BLOB_END(tokdata, target_info, useblob, useblobsize, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) rc = constant_time_select(constant_time_eq(rc, CKR_OK), ep11_error_to_pkcs11_error(rc, session), rc); if (rc != CKR_OK) { 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_encrypt_final(STDLL_TokData_t * tokdata, SESSION * session, CK_BYTE_PTR output_part, CK_ULONG_PTR p_output_part_len) { CK_RV rc = CKR_OK; ENCR_DECR_CONTEXT *ctx = &session->encr_ctx; CK_BBOOL length_only = (output_part == NULL ? CK_TRUE : CK_FALSE); size_t keyblobsize = 0; CK_BYTE *keyblob; OBJECT *key_obj = NULL; CK_BYTE *state; size_t state_len; if (ctx->pkey_active) { rc = encr_mgr_encrypt_final(tokdata, session, length_only, ctx, output_part, p_output_part_len); goto done; /* no ep11 fallback possible */ } rc = h_opaque_2_blob(tokdata, ctx->key, &keyblob, &keyblobsize, &key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("%s h_opaque_2_blob, rc=0x%lx\n", __func__, rc); return rc; } RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_UPDATE_BLOB_START(tokdata, target_info, ctx->context, ctx->context_len / 2, ctx->context + (ctx->context_len / 2), ctx->context_len / 2, state, state_len) rc = dll_m_EncryptFinal(state, state_len, output_part, p_output_part_len, target_info->target); RETRY_UPDATE_BLOB_END(tokdata, session, target_info, ctx->context, ctx->context_len / 2, ctx->context + (ctx->context_len / 2), ctx->context_len / 2, state, state_len, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); 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_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 rc = CKR_OK; ENCR_DECR_CONTEXT *ctx = &session->encr_ctx; CK_BBOOL length_only = (output_data == NULL ? CK_TRUE : CK_FALSE); size_t keyblobsize = 0; CK_BYTE *keyblob; OBJECT *key_obj = NULL; CK_BYTE *state; size_t state_len; if (ctx->pkey_active) { rc = encr_mgr_encrypt(tokdata, session, length_only, ctx, input_data, input_data_len, output_data, p_output_data_len); goto done; /* no ep11 fallback possible */ } rc = h_opaque_2_blob(tokdata, ctx->key, &keyblob, &keyblobsize, &key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("%s h_opaque_2_blob, rc=0x%lx\n", __func__, rc); return rc; } RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_UPDATE_BLOB_START(tokdata, target_info, ctx->context, ctx->context_len / 2, ctx->context + (ctx->context_len / 2), ctx->context_len / 2, state, state_len) rc = dll_m_Encrypt(state, state_len, input_data, input_data_len, output_data, p_output_data_len, target_info->target); RETRY_UPDATE_BLOB_END(tokdata, session, target_info, ctx->context, ctx->context_len / 2, ctx->context + (ctx->context_len / 2), ctx->context_len / 2, state, state_len, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); 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_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 rc = CKR_OK; ENCR_DECR_CONTEXT *ctx = &session->encr_ctx; CK_BBOOL length_only = (output_part == NULL ? CK_TRUE : CK_FALSE); size_t keyblobsize = 0; CK_BYTE *keyblob; OBJECT *key_obj = NULL; CK_BYTE *state; size_t state_len; if (!input_part || !input_part_len) { *p_output_part_len = 0; return CKR_OK; /* nothing to update, keep context */ } if (ctx->pkey_active) { rc = encr_mgr_encrypt_update(tokdata, session, length_only, ctx, input_part, input_part_len, output_part, p_output_part_len); goto done; /* no ep11 fallback possible */ } rc = h_opaque_2_blob(tokdata, ctx->key, &keyblob, &keyblobsize, &key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("%s h_opaque_2_blob, rc=0x%lx\n", __func__, rc); return rc; } RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_UPDATE_BLOB_START(tokdata, target_info, ctx->context, ctx->context_len / 2, ctx->context + (ctx->context_len / 2), ctx->context_len / 2, state, state_len) rc = dll_m_EncryptUpdate(state, state_len, input_part, input_part_len, output_part, p_output_part_len, target_info->target); RETRY_UPDATE_BLOB_END(tokdata, session, target_info, ctx->context, ctx->context_len / 2, ctx->context + (ctx->context_len / 2), ctx->context_len / 2, state, state_len, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); 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_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; CK_BYTE *useblob = NULL; size_t useblobsize = 0; struct RSA_OAEP_MECH_PARAM rsa_oaep_mech_ep11; 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; } if (!key_object_is_mechanism_allowed(key_obj->template, mech->mechanism)) { TRACE_ERROR("Mechanism not allowed per CKA_ALLOWED_MECHANISMS.\n"); rc = CKR_MECHANISM_INVALID; goto done; } rc = tokdata->policy->is_mech_allowed(tokdata->policy, mech, &key_obj->strength, POLICY_CHECK_ENCRYPT, session); if (rc != CKR_OK) { TRACE_ERROR("POLICY_VIOLATION on encrypt single\n"); goto done; } /* * 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; } if (mech->mechanism == CKM_RSA_PKCS_OAEP) { rc = ep11tok_rsa_oaep_mech_adjust(tokdata, mech, &rsa_oaep_mech_ep11); if (rc != CKR_OK) goto done; mech = &rsa_oaep_mech_ep11.mech; } RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_BLOB_START(tokdata, target_info, key_obj, keyblob, keyblobsize, useblob, useblobsize, rc) if (ep11_pqc_obj_strength_supported(target_info, mech->mechanism, key_obj)) rc = dll_m_EncryptSingle(useblob, useblobsize, mech, input_data, input_data_len, output_data, p_output_data_len, target_info->target); else rc = CKR_KEY_SIZE_RANGE; RETRY_REENC_BLOB_END(tokdata, target_info, useblob, useblobsize, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); TRACE_ERROR("%s rc=0x%lx\n", __func__, rc); } 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, CK_BBOOL checkauth) { 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 * 2; CK_BYTE *ep11_state; CK_BYTE *useblob, *usestate; size_t useblob_len, usestate_len; CK_ULONG strength_index = POLICY_STRENGTH_IDX_0; struct RSA_OAEP_MECH_PARAM rsa_oaep_mech_ep11; ep11_state = calloc(ep11_state_l, 1); /* freed by encr/decr_mgr.c */ if (!ep11_state) { TRACE_ERROR("%s Memory allocation failed\n", __func__); return CKR_HOST_MEMORY; } 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 (!key_object_is_mechanism_allowed(key_obj->template, mech->mechanism)) { TRACE_ERROR("Mechanism not allowed per CKA_ALLOWED_MECHANISMS.\n"); rc = CKR_MECHANISM_INVALID; goto error; } rc = tokdata->policy->is_mech_allowed(tokdata->policy, mech, &key_obj->strength, op == DECRYPT ? POLICY_CHECK_DECRYPT : POLICY_CHECK_ENCRYPT, session); if (rc != CKR_OK) { TRACE_ERROR("POLICY_VIOLATION on encrypt/decrypt initialization\n"); goto error; } #ifndef NO_PKEY rc = ep11tok_pkey_check(tokdata, session, key_obj, mech); switch (rc) { case CKR_OK: strength_index = key_obj->strength.strength; /* Release obj lock, encr/decr_mgr_init may re-acquire the lock */ object_put(tokdata, key_obj, TRUE); key_obj = NULL; if (op == DECRYPT) { /* Policy and always-auth already checked */ rc = decr_mgr_init(tokdata, session, &session->decr_ctx, OP_DECRYPT_INIT, mech, key, FALSE, checkauth); } else { /* Policy already checked */ rc = encr_mgr_init(tokdata, session, &session->encr_ctx, OP_ENCRYPT_INIT, mech, key, FALSE); } if (rc == CKR_OK) { if (op == DECRYPT) (&session->decr_ctx)->pkey_active = TRUE; else (&session->encr_ctx)->pkey_active = TRUE; } /* Regardless of the rc goto done here, because ep11tok_pkey_check * could have unlocked/relocked the obj so that the blob is no more * valid. */ free(ep11_state); goto done; case CKR_FUNCTION_NOT_SUPPORTED: /* if mechanism is AES XTS, return error else fallback to ep11 path */ if (mech->mechanism == CKM_AES_XTS) { TRACE_ERROR("EP11 AES XTS mech is supported only for protected keys\n"); rc = CKR_KEY_UNEXTRACTABLE; free(ep11_state); goto done; } break; default: /* internal error or lock problem */ free(ep11_state); goto done; } #endif /* NO_PKEY */ if (mech->mechanism == CKM_RSA_PKCS_OAEP) { rc = ep11tok_rsa_oaep_mech_adjust(tokdata, mech, &rsa_oaep_mech_ep11); if (rc != CKR_OK) goto error; mech = &rsa_oaep_mech_ep11.mech; } /* * ep11_state is allocated large enough to hold 2 times the max state blob. * Initially use the first half only. The second half is for the * re-enciphered state blob (if mk change is active). */ ep11_state_l /= 2; if (op == DECRYPT) { ENCR_DECR_CONTEXT *ctx = &session->decr_ctx; if (checkauth) { rc = key_object_is_always_authenticate(key_obj->template, &ctx->auth_required); if (rc != CKR_OK) { TRACE_ERROR("key_object_is_always_authenticate failed\n"); goto error; } } RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_BLOB_STATE_START(tokdata, target_info, key_obj, blob, blob_len, useblob, useblob_len, ep11_state, ep11_state + ep11_state_l, ep11_state_l, usestate, usestate_len, rc) rc = dll_m_DecryptInit(usestate, &usestate_len, mech, useblob, useblob_len, target_info->target); if (rc == CKR_OK && retry == 1) { /* * Initially, the real state_len is unknown, and is set to * allocated state size / 2. When the state was created on * an APQN with new WK set already, move the state to the * final place, which is state + usestate_len, where * usestate_len now is the real state size. */ memmove(ep11_state + usestate_len, ep11_state + ep11_state_l, usestate_len); } ep11_state_l = usestate_len; RETRY_REENC_BLOB_STATE_END(tokdata, session, target_info, blob, blob_len, useblob, useblob_len, ep11_state, ep11_state + ep11_state_l, ep11_state_l, usestate, usestate_len, TRUE, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) ctx->key = key; ctx->active = TRUE; ctx->context = ep11_state; ctx->context_len = ep11_state_l * 2; /* current and re-enciphered state */ ctx->pkey_active = FALSE; if (mech != &ctx->mech) { /* deferred init dup'ed mech already */ ctx->mech.mechanism = mech->mechanism; if (mech->ulParameterLen > 0 && mech->pParameter != NULL) { ctx->mech.pParameter = (CK_BYTE *) malloc(mech->ulParameterLen); if (ctx->mech.pParameter == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; decr_mgr_cleanup(tokdata, session, ctx); goto done; } memcpy(ctx->mech.pParameter, mech->pParameter, mech->ulParameterLen); ctx->mech.ulParameterLen = mech->ulParameterLen; } } if (rc != CKR_OK) { decr_mgr_cleanup(tokdata, session, 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_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_BLOB_STATE_START(tokdata, target_info, key_obj, blob, blob_len, useblob, useblob_len, ep11_state, ep11_state + ep11_state_l, ep11_state_l, usestate, usestate_len, rc) rc = dll_m_EncryptInit(usestate, &usestate_len, mech, useblob, useblob_len, target_info->target); if (rc == CKR_OK && retry == 1) { /* * Initially, the real state_len is unknown, and is set to * allocated state size / 2. When the state was created on * an APQN with new WK set already, move the state to the * final place, which is state + usestate_len, where * usestate_len now is the real state size. */ memmove(ep11_state + usestate_len, ep11_state + ep11_state_l, usestate_len); } ep11_state_l = usestate_len; RETRY_REENC_BLOB_STATE_END(tokdata, session, target_info, blob, blob_len, useblob, useblob_len, ep11_state, ep11_state + ep11_state_l, ep11_state_l, usestate, usestate_len, TRUE, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) ctx->key = key; ctx->active = TRUE; ctx->context = ep11_state; ctx->context_len = ep11_state_l * 2; /* current and re-enciphered state */ ctx->pkey_active = FALSE; if (mech != &ctx->mech) { /* deferred init dup'ed mech already */ ctx->mech.mechanism = mech->mechanism; if (mech->ulParameterLen > 0 && mech->pParameter != NULL) { ctx->mech.pParameter = (CK_BYTE *) malloc(mech->ulParameterLen); if (ctx->mech.pParameter == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; encr_mgr_cleanup(tokdata, session, ctx); goto done; } memcpy(ctx->mech.pParameter, mech->pParameter, mech->ulParameterLen); ctx->mech.ulParameterLen = mech->ulParameterLen; } } if (rc != CKR_OK) { encr_mgr_cleanup(tokdata, session, 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); } } done: if (rc == CKR_OK) INC_COUNTER(tokdata, session, mech, key_obj, strength_index); 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, FALSE); 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_BBOOL checkauth) { 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, checkauth); 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, CK_BBOOL count_statistics) { CK_RV rc; CK_BYTE *wrapping_blob = NULL, *use_wrapping_blob = NULL; size_t wrapping_blob_len = 0, use_wrapping_blob_len = 0; CK_OBJECT_CLASS class; CK_BYTE *wrap_target_blob, *use_wrap_target_blob; size_t wrap_target_blob_len, use_wrap_target_blob_len; int size_query = 0; OBJECT *key_obj = NULL, *wrap_key_obj = NULL, *sobj = NULL; CK_BYTE *sign_blob = NULL, *use_sign_blob = NULL; size_t sign_blob_len = 0, use_sign_blob_len = 0; CK_KEY_TYPE ktype; /* 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; } rc = template_attribute_get_ulong(wrap_key_obj->template, CKA_KEY_TYPE, &ktype); if (rc != CKR_OK) { TRACE_ERROR("Invalid key type attribute\n"); goto done; } if (mech->mechanism == CKM_AES_XTS || ktype == CKK_AES_XTS) { TRACE_ERROR("%s Key wrap with AES-XTS is not supported\n", __func__); rc = CKR_KEY_TYPE_INCONSISTENT; goto done; } if (!key_object_is_mechanism_allowed(wrap_key_obj->template, mech->mechanism)) { TRACE_ERROR("Mechanism not allowed per CKA_ALLOWED_MECHANISMS.\n"); rc = CKR_MECHANISM_INVALID; goto done; } /* 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); goto done; } rc = template_attribute_get_ulong(key_obj->template, CKA_KEY_TYPE, &ktype); if (rc != CKR_OK) { TRACE_ERROR("Invalid key type attribute\n"); goto done; } switch (ktype) { case CKK_AES_XTS: case CKK_EC_EDWARDS: case CKK_EC_MONTGOMERY: TRACE_ERROR("%s Wrapping an key of type 0x%lx is not supported\n", __func__, ktype); rc = CKR_KEY_NOT_WRAPPABLE; goto done; default: break; } rc = tokdata->policy->is_mech_allowed(tokdata->policy, mech, &wrap_key_obj->strength, POLICY_CHECK_WRAP, session); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: key wrap\n"); goto done; } rc = tokdata->policy->is_key_allowed(tokdata->policy, &key_obj->strength, session); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: key wrap\n"); goto done; } if (!key_object_wrap_template_matches(wrap_key_obj->template, key_obj->template)) { TRACE_ERROR("Wrap template does not match.\n"); rc = CKR_KEY_HANDLE_INVALID; goto done; } rc = check_ab_wrap(tokdata, &sign_blob, &sign_blob_len, &sobj, key_obj, wrap_key_obj, mech, session); if (rc != CKR_OK) { TRACE_ERROR("AB wrapping check failed (rc=0x%lx).\n", rc); 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. */ rc = template_attribute_get_ulong(key_obj->template, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); goto done; } if (class != 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_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_BLOB3_START(tokdata, target_info, key_obj, wrap_target_blob, wrap_target_blob_len, use_wrap_target_blob, use_wrap_target_blob_len, wrap_key_obj, wrapping_blob, wrapping_blob_len, use_wrapping_blob, use_wrapping_blob_len, sobj, sign_blob, sign_blob_len, use_sign_blob, use_sign_blob_len, rc) rc = dll_m_WrapKey(use_wrap_target_blob, use_wrap_target_blob_len, use_wrapping_blob, use_wrapping_blob_len, use_sign_blob, use_sign_blob_len, mech, wrapped_key, p_wrapped_key_len, target_info->target); RETRY_REENC_BLOB3_END(tokdata, target_info, use_wrap_target_blob, use_wrap_target_blob_len, use_wrapping_blob, use_wrapping_blob_len, use_sign_blob, use_sign_blob_len, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { TRACE_ERROR("%s m_WrapKey failed with rc=0x%lx\n", __func__, rc); } 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); } done: if (rc == CKR_OK && !size_query && count_statistics) INC_COUNTER(tokdata, session, mech, wrap_key_obj, POLICY_STRENGTH_IDX_0); if (size_query) free(wrapped_key); object_put(tokdata, wrap_key_obj, TRUE); wrap_key_obj = NULL; object_put(tokdata, key_obj, TRUE); key_obj = NULL; object_put(tokdata, sobj, TRUE); sobj = 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, CK_ULONG operation) { ep11_private_data_t *ep11_data = tokdata->private_data; CK_RV rc; CK_BYTE *wrapping_blob, *use_wrapping_blob, *temp; size_t wrapping_blob_len, use_wrapping_blob_len; CK_BYTE csum[MAX_BLOBSIZE]; CK_ULONG cslen = sizeof(csum), temp_len; OBJECT *key_obj = NULL; CK_BYTE keyblob[MAX_BLOBSIZE]; CK_BYTE keyblobreenc[MAX_BLOBSIZE]; size_t keyblobsize = sizeof(keyblob); CK_ATTRIBUTE *attr = NULL; CK_ULONG i; CK_ULONG ktype; CK_ULONG class; CK_ULONG len; CK_ATTRIBUTE_PTR new_attrs = NULL, tmp_attrs = NULL; CK_ULONG new_attrs_len = 0, tmp_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; CK_ATTRIBUTE *new_attrs2 = NULL; CK_ULONG new_attrs2_len = 0; CK_BBOOL isab; CK_BYTE *verifyblob = NULL, *use_verifyblob = NULL; size_t verifyblobsize = 0, use_verifyblobsize = 0; OBJECT *vobj = NULL; CK_KEY_TYPE keytype; CK_ULONG mode; int policy_check; CK_ATTRIBUTE_TYPE apply_tmpl_attr; switch (operation) { case OP_UNWRAP: mode = MODE_UNWRAP; apply_tmpl_attr = CKA_UNWRAP_TEMPLATE; policy_check = POLICY_CHECK_UNWRAP; break; case OP_DECAPSULATE: mode = MODE_DECAPS; apply_tmpl_attr = CKA_DECAPSULATE_TEMPLATE; policy_check = POLICY_CHECK_DECAPS; break; default: TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto done; } /* 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; } rc = template_attribute_get_ulong(kobj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Invalid key type attribute\n"); goto done; } if (mech->mechanism == CKM_AES_XTS || keytype == CKK_AES_XTS) { TRACE_ERROR("%s Key unwrap with AES-XTS is not supported\n", __func__); rc = CKR_KEY_TYPE_INCONSISTENT; goto done; } rc = tokdata->policy->is_mech_allowed(tokdata->policy, mech, &kobj->strength, policy_check, session); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: key unwrap\n"); goto done; } 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); } if (!key_object_is_mechanism_allowed(kobj->template, mech->mechanism)) { TRACE_ERROR("Mechanism not allowed per CKA_ALLOWED_MECHANISMS.\n"); rc = CKR_MECHANISM_INVALID; goto error; } memset(keyblob, 0, sizeof(keyblob)); memset(keyblobreenc, 0, sizeof(keyblobreenc)); /*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 *) keytype_attr->pValue) { case CKK_AES_XTS: case CKK_EC_EDWARDS: case CKK_EC_MONTGOMERY: TRACE_ERROR("%s Unwrapping an key of type 0x%lx is not supported\n", __func__, *(CK_KEY_TYPE *)keytype_attr->pValue); rc = CKR_KEY_NOT_WRAPPABLE; goto error; default: break; } rc = check_ab_unwrap(tokdata, &verifyblob, &verifyblobsize, &vobj, kobj, attrs, attrs_len, mech, &isab, session); if (rc != CKR_OK) { TRACE_ERROR("check_ab_unwrap failed with rc=0x%08lx\n", rc); goto error; } if (isab) { rc = check_ab_kek_type(kobj->template, CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT); if (rc != CKR_OK) goto error; /* AB unwrapping is taking care of all the boolean usage flags. * No need to check attributes, just need to duplicate the array. */ rc = dup_attribute_array(attrs,attrs_len, &new_attrs, &new_attrs_len); if (rc != CKR_OK) goto error; } else { switch (*(CK_OBJECT_CLASS *) 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, -1); 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, -1); 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, -1); 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; } tmp_attrs = new_attrs; tmp_attrs_len = new_attrs_len; new_attrs = NULL; new_attrs_len = 0; rc = key_object_apply_template_attr(kobj->template, apply_tmpl_attr, tmp_attrs, tmp_attrs_len, &new_attrs, &new_attrs_len); free_attribute_array(tmp_attrs, tmp_attrs_len); if (rc != CKR_OK) { TRACE_DEVEL("key_object_apply_template_attr failed.\n"); goto done; } /* Get the keytype to use when creating the key object */ rc = pkcs_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; } if (ktype == CKK_AES_XTS) { TRACE_ERROR("%s Unwrapping an AES-XTS key is not supported\n", __func__); rc = CKR_KEY_TYPE_INCONSISTENT; goto done; } #ifndef NO_PKEY /* Ensure the firmware master key verification pattern is available */ rc = ep11tok_pkey_get_firmware_mk_vp(tokdata, session); if (rc != CKR_OK && rc != CKR_FUNCTION_NOT_SUPPORTED) goto error; #endif /* NO_PKEY */ /* Start creating the key object */ rc = object_mgr_create_skel(tokdata, session, new_attrs, new_attrs_len, mode, 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_ep11_attrs(tokdata, key_obj->template, &new_attrs2, &new_attrs2_len, ktype, *(CK_OBJECT_CLASS *) cla_attr->pValue, -1, mech); if (rc != CKR_OK) { TRACE_ERROR("%s build_ep11_attrs failed with rc=0x%lx\n", __func__, rc); goto error; } trace_attributes(__func__, "Unwrap:", new_attrs2, new_attrs2_len); ep11_get_pin_blob(tokdata, ep11_session, ep11_is_session_object(attrs, attrs_len), ep11_is_private_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_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_BLOB2_START(tokdata, target_info, kobj, wrapping_blob, wrapping_blob_len, use_wrapping_blob, use_wrapping_blob_len, vobj, verifyblob, verifyblobsize, use_verifyblob, use_verifyblobsize, rc) RETRY_REENC_CREATE_KEY_START() rc = dll_m_UnwrapKey(wrapped_key, wrapped_key_len, use_wrapping_blob, use_wrapping_blob_len, use_verifyblob, use_verifyblobsize, ep11_pin_blob, ep11_pin_blob_len, mech, new_attrs2, new_attrs2_len, keyblob, &keyblobsize, csum, &cslen, target_info->target); RETRY_REENC_CREATE_KEY_END(tokdata, session, target_info, keyblob, keyblobreenc, keyblobsize, rc) RETRY_REENC_BLOB2_END(tokdata, target_info, use_wrapping_blob, use_wrapping_blob_len, use_verifyblob, use_verifyblobsize, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); 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); if (check_expected_mkvp(tokdata, keyblob, keyblobsize, NULL) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); rc = CKR_DEVICE_ERROR; goto error; } 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; } attr = NULL; if (ep11_data->mk_change_active) { rc = build_attribute(CKA_IBM_OPAQUE_REENC, keyblobreenc, keyblobsize, &attr); if (rc != CKR_OK) { TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc); goto error; } rc = template_update_attribute(key_obj->template, attr); if (rc != CKR_OK) { TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n", __func__, rc); goto error; } attr = NULL; } if (isab) { rc = ab_unwrap_update_template(tokdata, session, keyblob, keyblobsize, key_obj, *(CK_KEY_TYPE *)keytype_attr->pValue, *(CK_OBJECT_CLASS *)cla_attr->pValue); if (rc != CKR_OK) { TRACE_ERROR("ab_unwrap_update_template failed with rc=0x%08lx\n", rc); goto error; } } rc = update_ep11_attrs_from_blob(tokdata, session, key_obj, FALSE); if (rc != CKR_OK) { TRACE_ERROR("%s update_ep11_attrs_from_blob failed with rc=0x%lx\n", __func__, rc); goto error; } switch (*(CK_OBJECT_CLASS *) cla_attr->pValue) { case CKO_SECRET_KEY: /* card provides bit length in csum last 4 bytes big endian */ if (cslen < EP11_CSUMSIZE + 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); switch (*(CK_KEY_TYPE *) keytype_attr->pValue) { case CKK_AES: case CKK_GENERIC_SECRET: case CKK_SHA_1_HMAC: case CKK_SHA224_HMAC: case CKK_SHA256_HMAC: case CKK_SHA384_HMAC: case CKK_SHA512_HMAC: case CKK_SHA3_224_HMAC: case CKK_SHA3_256_HMAC: case CKK_SHA3_384_HMAC: case CKK_SHA3_512_HMAC: case CKK_SHA512_224_HMAC: case CKK_SHA512_256_HMAC: 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; } attr = NULL; break; } /* First 3 bytes of csum is the check value */ rc = build_attribute(CKA_CHECK_VALUE, csum, EP11_CSUMSIZE, &attr); if (rc != CKR_OK) { TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc); goto error; } rc = template_update_attribute(key_obj->template, attr); if (rc != CKR_OK) { TRACE_ERROR("%s template_update_attribute failed with " "rc=0x%lx\n", __func__, rc); goto error; } attr = NULL; 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 = ec_priv_unwrap_get_data(key_obj->template, csum, cslen, FALSE, CKK_EC); break; case CKK_RSA: rc = rsa_priv_unwrap_get_data(key_obj->template, csum, cslen, FALSE); break; case CKK_DSA: rc = dsa_priv_unwrap_get_data(key_obj->template, csum, cslen, FALSE); break; case CKK_DH: rc = dh_priv_unwrap_get_data(key_obj->template, csum, cslen, FALSE); break; case CKK_IBM_PQC_DILITHIUM: case CKK_IBM_PQC_KYBER: case CKK_IBM_ML_DSA: case CKK_IBM_ML_KEM: case CKK_ML_DSA: case CKK_ML_KEM: rc = pqc_priv_unwrap_get_data(key_obj->template, *(CK_KEY_TYPE *)keytype_attr->pValue, csum, cslen, FALSE); break; default: TRACE_ERROR("%s unsupported key type=0x%lx\n", __func__, rc); rc = CKR_KEY_TYPE_INCONSISTENT; goto error; } if (rc != 0) { TRACE_ERROR("%s xxx_priv_unwrap_get_data rc=0x%lx\n", __func__, *(CK_KEY_TYPE *) keytype_attr->pValue); goto error; } /* csum is a MACed SPKI, get length of SPKI part only */ rc = ber_decode_SEQUENCE(csum, cslen, &temp, &temp_len, &cslen); if (rc != CKR_OK) { TRACE_ERROR("%s ber_decode_SEQUENCE failed rc=0x%lx\n", __func__, rc); goto error; } rc = build_attribute(CKA_PUBLIC_KEY_INFO, csum, cslen, &attr); if (rc != CKR_OK) { TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc); goto error; } rc = template_update_attribute(key_obj->template, attr); if (rc != CKR_OK) { TRACE_ERROR("%s template_update_attribute failed with " "rc=0x%lx\n", __func__, rc); goto error; } attr = NULL; break; } /* key should be fully constructed. * Assign an object handle and store key. * Enforce policy. */ 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; } INC_COUNTER(tokdata, session, mech, kobj, POLICY_STRENGTH_IDX_0); goto done; error: if (key_obj) object_free(key_obj); if (attr != NULL) free(attr); *p_key = 0; done: if (new_attrs) free_attribute_array(new_attrs, new_attrs_len); if (new_attrs2) free_attribute_array(new_attrs2, new_attrs2_len); object_put(tokdata, kobj, TRUE); object_put(tokdata, vobj, TRUE); kobj = NULL; return rc; } CK_RV token_specific_encapsulate_rsa_sym_keygen(STDLL_TokData_t *tokdata, SESSION *sess, CK_MECHANISM *mech, CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE *handle) { CK_RV rc; rc = tokdata->policy->is_mech_allowed(tokdata->policy, mech, NULL, POLICY_CHECK_ENCAPS, sess); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: Key generation mechanism not " "allowed\n"); return rc; } return ep11tok_generate_key(tokdata, sess, mech, pTemplate, ulCount, handle, FALSE, OP_ENCAPSULATE); } CK_RV token_specific_encapsulate_rsa_key_wrap(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, CK_MECHANISM *mech, CK_OBJECT_HANDLE wrapping_key, CK_OBJECT_HANDLE key, CK_BYTE *wrapped_key, CK_ULONG *wrapped_key_len) { UNUSED(length_only); return ep11tok_wrap_key(tokdata, sess, mech, wrapping_key, key, wrapped_key, wrapped_key_len, FALSE); } CK_RV token_specific_encapsulate_rsa_key_unwrap(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) { return ep11tok_unwrap_key(tokdata, sess, mech, pTemplate, ulCount, wrapped_key, wrapped_key_len, unwrapping_key, unwrapped_key, OP_DECAPSULATE); } CK_RV token_specific_encapsulate_dh_ecdh_key_pair_gen( 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, CK_OBJECT_HANDLE *priv_key) { CK_RV rc; rc = tokdata->policy->is_mech_allowed(tokdata->policy, mech, NULL, POLICY_CHECK_ENCAPS, sess); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: Keypair generation mechanism not " "allowed\n"); return rc; } return ep11tok_generate_key_pair(tokdata, sess, mech, publ_tmpl, publ_count, priv_tmpl, priv_count, publ_key, priv_key, FALSE, OP_ENCAPSULATE); } CK_RV token_specific_en_decapsulate_dh_ecdh_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_ULONG operation) { return ep11tok_derive_key(tokdata, sess, mech, base_key, derived_key, pTemplate, ulCount, FALSE, operation); } CK_RV token_specific_ml_kem_encapsulate_key(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, const struct pqc_oid *oid, CK_MECHANISM *mech, OBJECT *key_obj, CK_ATTRIBUTE *pTemplate, CK_ULONG ulAttributeCount, CK_BYTE *pCiphertext, CK_ULONG *pulCiphertextLen, CK_KEY_TYPE keytype, CK_ULONG keylen, CK_OBJECT_HANDLE *phKey) { CK_IBM_ML_KEM_PARAMS ep11_mech_param = { 0 }; CK_MECHANISM ep11_mech = { mech->mechanism, &ep11_mech_param, sizeof(ep11_mech_param) }; CK_OBJECT_HANDLE htmp = CK_INVALID_HANDLE; CK_RV rc; UNUSED(oid); UNUSED(keytype); UNUSED(keylen); if (mech->mechanism != CKM_ML_KEM) return CKR_MECHANISM_INVALID; /* Translate to Derive using orig mech but IBM-specific ML-KEM mech param */ ep11_mech_param.ulVersion = CK_IBM_ML_KEM_VERSION; ep11_mech_param.mode = CK_IBM_ML_KEM_ENCAPSULATE; ep11_mech_param.kdf = CKD_NULL; ep11_mech_param.pCipher = pCiphertext; ep11_mech_param.ulCipherLen = *pulCiphertextLen; ep11_mech_param.hSecret = CK_INVALID_HANDLE; if (length_only && phKey == NULL) phKey = &htmp; rc = ep11tok_derive_key(tokdata, sess, &ep11_mech, key_obj->map_handle, phKey, pTemplate, ulAttributeCount, FALSE, OP_ENCAPSULATE); if (length_only && rc == CKR_BUFFER_TOO_SMALL) rc = CKR_OK; *pulCiphertextLen = ep11_mech_param.ulCipherLen; return rc; } CK_RV token_specific_ml_kem_decapsulate_key(STDLL_TokData_t *tokdata, SESSION *sess, const struct pqc_oid *oid, CK_MECHANISM *mech, OBJECT *key_obj, CK_ATTRIBUTE *pTemplate, CK_ULONG ulAttributeCount, CK_BYTE *pCiphertext, CK_ULONG ulCiphertextLen, CK_KEY_TYPE keytype, CK_ULONG keylen, CK_OBJECT_HANDLE *phKey) { CK_IBM_ML_KEM_PARAMS ep11_mech_param = { 0 }; CK_MECHANISM ep11_mech = { mech->mechanism, &ep11_mech_param, sizeof(ep11_mech_param) }; UNUSED(oid); UNUSED(keytype); UNUSED(keylen); if (mech->mechanism != CKM_ML_KEM) return CKR_MECHANISM_INVALID; /* Translate to Derive using orig mech but IBM-specific ML-KEM mech param */ ep11_mech_param.ulVersion = CK_IBM_ML_KEM_VERSION; ep11_mech_param.mode = CK_IBM_ML_KEM_DECAPSULATE; ep11_mech_param.kdf = CKD_NULL; ep11_mech_param.pCipher = pCiphertext; ep11_mech_param.ulCipherLen = ulCiphertextLen; ep11_mech_param.hSecret = CK_INVALID_HANDLE; return ep11tok_derive_key(tokdata, sess, &ep11_mech, key_obj->map_handle, phKey, pTemplate, ulAttributeCount, FALSE, OP_DECAPSULATE); } static const CK_MECHANISM_TYPE ep11_supported_mech_list[] = { CKM_AES_CBC, CKM_AES_CBC_PAD, CKM_AES_CMAC, CKM_AES_ECB, CKM_AES_XTS, CKM_AES_KEY_GEN, CKM_AES_XTS_KEY_GEN, CKM_DES2_KEY_GEN, CKM_DES3_CBC, CKM_DES3_CBC_PAD, CKM_DES3_CMAC, CKM_DES3_ECB, CKM_DES3_KEY_GEN, CKM_DH_PKCS_DERIVE, CKM_DH_PKCS_KEY_PAIR_GEN, CKM_DSA, CKM_DSA_KEY_PAIR_GEN, CKM_DSA_SHA1, CKM_EC_KEY_PAIR_GEN, CKM_ECDH1_DERIVE, CKM_ECDSA, CKM_ECDSA_SHA1, CKM_ECDSA_SHA224, CKM_ECDSA_SHA256, CKM_ECDSA_SHA384, CKM_ECDSA_SHA512, CKM_IBM_CMAC, CKM_IBM_DILITHIUM, CKM_IBM_EC_X25519, CKM_IBM_EC_X448, CKM_IBM_ED25519_SHA512, CKM_IBM_ED448_SHA3, CKM_IBM_KYBER, CKM_IBM_ML_DSA, CKM_IBM_ML_DSA_KEY_PAIR_GEN, CKM_IBM_ML_KEM, CKM_IBM_ML_KEM_KEY_PAIR_GEN, CKM_IBM_ML_KEM_WITH_ECDH, CKM_IBM_SHA3_224, CKM_IBM_SHA3_224_HMAC, CKM_IBM_SHA3_256, CKM_IBM_SHA3_256_HMAC, CKM_IBM_SHA3_384, CKM_IBM_SHA3_384_HMAC, CKM_IBM_SHA3_512, CKM_IBM_SHA3_512_HMAC, CKM_IBM_CPACF_WRAP, CKM_PBE_SHA1_DES3_EDE_CBC, CKM_RSA_PKCS, CKM_RSA_PKCS_KEY_PAIR_GEN, CKM_RSA_PKCS_OAEP, CKM_RSA_PKCS_PSS, CKM_RSA_X9_31, CKM_RSA_X9_31_KEY_PAIR_GEN, CKM_SHA1_KEY_DERIVATION, CKM_SHA1_RSA_PKCS, CKM_SHA1_RSA_PKCS_PSS, CKM_SHA1_RSA_X9_31, CKM_SHA224, CKM_SHA224_HMAC, CKM_SHA224_KEY_DERIVATION, CKM_SHA224_RSA_PKCS, CKM_SHA224_RSA_PKCS_PSS, CKM_SHA256, CKM_SHA256_HMAC, CKM_SHA256_KEY_DERIVATION, CKM_SHA256_RSA_PKCS, CKM_SHA256_RSA_PKCS_PSS, CKM_SHA384, CKM_SHA384_HMAC, CKM_SHA384_KEY_DERIVATION, CKM_SHA384_RSA_PKCS, CKM_SHA384_RSA_PKCS_PSS, CKM_SHA512, CKM_SHA512_224, CKM_SHA512_224_HMAC, CKM_SHA512_224_KEY_DERIVATION, CKM_SHA512_256, CKM_SHA512_256_HMAC, CKM_SHA512_256_KEY_DERIVATION, CKM_SHA512_HMAC, CKM_SHA512_KEY_DERIVATION, CKM_SHA512_RSA_PKCS, CKM_SHA512_RSA_PKCS_PSS, CKM_SHA_1, CKM_SHA_1_HMAC, CKM_GENERIC_SECRET_KEY_GEN, CKM_IBM_ATTRIBUTEBOUND_WRAP, CKM_IBM_ECDSA_OTHER, CKM_IBM_BTC_DERIVE, CKM_IBM_EC_AGGREGATE, CKM_EC_EDWARDS_KEY_PAIR_GEN, CKM_EC_MONTGOMERY_KEY_PAIR_GEN, CKM_EDDSA, CKM_ML_DSA_KEY_PAIR_GEN, CKM_ML_DSA, CKM_ML_KEM_KEY_PAIR_GEN, CKM_ML_KEM, CKM_PUB_KEY_FROM_PRIV_KEY, }; static const CK_ULONG supported_mech_list_len = (sizeof(ep11_supported_mech_list) / sizeof(CK_MECHANISM_TYPE)); struct mech_translate { CK_MECHANISM_TYPE pkcs11_mech; CK_MECHANISM_TYPE ep11_mech; }; /* Translate PKCS#11 mechs to mechs supported by EP11 */ static const struct mech_translate pkcs11_mechanism_translation[] = { { CKM_SHA3_224, CKM_IBM_SHA3_224 }, { CKM_SHA3_224_HMAC, CKM_IBM_SHA3_224_HMAC }, { CKM_SHA3_256, CKM_IBM_SHA3_256 }, { CKM_SHA3_256_HMAC, CKM_IBM_SHA3_256_HMAC }, { CKM_SHA3_384, CKM_IBM_SHA3_384 }, { CKM_SHA3_384_HMAC, CKM_IBM_SHA3_384_HMAC }, { CKM_SHA3_512, CKM_IBM_SHA3_512 }, { CKM_SHA3_512_HMAC, CKM_IBM_SHA3_512_HMAC }, { CKM_SHA_1_KEY_GEN, CKM_GENERIC_SECRET_KEY_GEN }, { CKM_SHA224_KEY_GEN, CKM_GENERIC_SECRET_KEY_GEN }, { CKM_SHA256_KEY_GEN, CKM_GENERIC_SECRET_KEY_GEN }, { CKM_SHA384_KEY_GEN, CKM_GENERIC_SECRET_KEY_GEN }, { CKM_SHA512_KEY_GEN, CKM_GENERIC_SECRET_KEY_GEN }, { CKM_SHA512_224_KEY_GEN, CKM_GENERIC_SECRET_KEY_GEN }, { CKM_SHA512_256_KEY_GEN, CKM_GENERIC_SECRET_KEY_GEN }, { CKM_SHA3_224_KEY_GEN, CKM_GENERIC_SECRET_KEY_GEN }, { CKM_SHA3_256_KEY_GEN, CKM_GENERIC_SECRET_KEY_GEN }, { CKM_SHA3_384_KEY_GEN, CKM_GENERIC_SECRET_KEY_GEN }, { CKM_SHA3_512_KEY_GEN, CKM_GENERIC_SECRET_KEY_GEN }, { CKM_EC_EDWARDS_KEY_PAIR_GEN, CKM_EC_KEY_PAIR_GEN }, { CKM_EC_MONTGOMERY_KEY_PAIR_GEN, CKM_EC_KEY_PAIR_GEN }, { CKM_ML_DSA_KEY_PAIR_GEN, CKM_IBM_ML_DSA_KEY_PAIR_GEN }, { CKM_ML_DSA, CKM_IBM_ML_DSA }, { CKM_ML_KEM_KEY_PAIR_GEN, CKM_IBM_ML_KEM_KEY_PAIR_GEN }, { CKM_ML_KEM, CKM_IBM_ML_KEM }, }; static const CK_ULONG pkcs11_mechanism_translation_len = (sizeof(pkcs11_mechanism_translation) / sizeof(struct mech_translate)); struct mgf_translate { CK_RSA_PKCS_MGF_TYPE pkcs11_mgf; CK_RSA_PKCS_MGF_TYPE ep11_mgf; }; /* Translate PKCS#11 v3.0 SHA3 MGFs to IBM-specific SHA3 MGFs */ static const struct mgf_translate pkcs11_mgf_translation[] = { { CKG_MGF1_SHA3_224, CKG_IBM_MGF1_SHA3_224 }, { CKG_MGF1_SHA3_256, CKG_IBM_MGF1_SHA3_256 }, { CKG_MGF1_SHA3_384, CKG_IBM_MGF1_SHA3_384 }, { CKG_MGF1_SHA3_512, CKG_IBM_MGF1_SHA3_512 }, }; static const CK_ULONG pkcs11_mgf_translation_len = (sizeof(pkcs11_mgf_translation) / sizeof(struct mgf_translate)); struct keytype_translate { CK_KEY_TYPE pkcs11_keytype; CK_KEY_TYPE ep11_keytype; }; /* Translate PKCS#11 key types to key types supported by EP11 */ static const struct keytype_translate pkcs11_keytype_translation[] = { { CKK_SHA_1_HMAC, CKK_GENERIC_SECRET }, { CKK_SHA224_HMAC, CKK_GENERIC_SECRET }, { CKK_SHA256_HMAC, CKK_GENERIC_SECRET }, { CKK_SHA384_HMAC, CKK_GENERIC_SECRET }, { CKK_SHA512_HMAC, CKK_GENERIC_SECRET }, { CKK_SHA512_224_HMAC, CKK_GENERIC_SECRET }, { CKK_SHA512_256_HMAC, CKK_GENERIC_SECRET }, { CKK_SHA3_224_HMAC, CKK_GENERIC_SECRET }, { CKK_SHA3_256_HMAC, CKK_GENERIC_SECRET }, { CKK_SHA3_384_HMAC, CKK_GENERIC_SECRET }, { CKK_SHA3_512_HMAC, CKK_GENERIC_SECRET }, { CKK_EC_EDWARDS, CKK_EC }, { CKK_EC_MONTGOMERY, CKK_EC }, { CKK_ML_DSA, CKK_IBM_ML_DSA }, { CKK_ML_KEM, CKK_IBM_ML_KEM }, }; static const CK_ULONG pkcs11_keytype_translation_len = (sizeof(pkcs11_keytype_translation) / sizeof(struct keytype_translate)); static CK_RV ep11tok_pkcs11_mech_translate(STDLL_TokData_t *tokdata, CK_MECHANISM_TYPE type, CK_MECHANISM_TYPE* ep11_type) { CK_ULONG i; for (i = 0; i < pkcs11_mechanism_translation_len; i++) { if (type == pkcs11_mechanism_translation[i].pkcs11_mech) { TRACE_DEVEL("%s Mech '%s' is backed by '%s'\n", __func__, ep11_get_ckm(tokdata, pkcs11_mechanism_translation[i].pkcs11_mech), ep11_get_ckm(tokdata, pkcs11_mechanism_translation[i].ep11_mech)); *ep11_type = pkcs11_mechanism_translation[i].ep11_mech; return CKR_OK; } } return CKR_MECHANISM_INVALID; } static CK_RV ep11tok_pkcs11_mgf_translate(STDLL_TokData_t *tokdata, CK_RSA_PKCS_MGF_TYPE mgf, CK_RSA_PKCS_MGF_TYPE* ep11_mgf) { CK_ULONG i; UNUSED(tokdata); for (i = 0; i < pkcs11_mgf_translation_len; i++) { if (mgf == pkcs11_mgf_translation[i].pkcs11_mgf) { TRACE_DEVEL("%s MGF 0x%lx is backed by 0x%lx\n", __func__, pkcs11_mgf_translation[i].pkcs11_mgf, pkcs11_mgf_translation[i].ep11_mgf); *ep11_mgf = pkcs11_mgf_translation[i].ep11_mgf; return CKR_OK; } } return CKR_MECHANISM_INVALID; } static CK_RV ep11tok_pkcs11_keytype_translate(STDLL_TokData_t *tokdata, CK_KEY_TYPE keytype, CK_KEY_TYPE* ep11_keytype) { CK_ULONG i; UNUSED(tokdata); for (i = 0; i < pkcs11_keytype_translation_len; i++) { if (keytype == pkcs11_keytype_translation[i].pkcs11_keytype) { TRACE_DEVEL("%s Keytype 0x%lx is backed by 0x%lx\n", __func__, pkcs11_keytype_translation[i].pkcs11_keytype, pkcs11_keytype_translation[i].ep11_keytype); *ep11_keytype = pkcs11_keytype_translation[i].ep11_keytype; return CKR_OK; } } return CKR_KEY_TYPE_INCONSISTENT; } /* Note: Do not move this function inside ep11tok_is_mechanism_supported since that would introduce an endless loop. Also do not use it in ep11tok_get_mechanism_info for the same reason. */ static CK_RV ep11tok_check_policy_for_mech(STDLL_TokData_t *tokdata, CK_MECHANISM_TYPE mech, CK_MECHANISM_INFO_PTR pinfo) { CK_RV rc; if (tokdata->policy->active == CK_FALSE) return CKR_OK; rc = ep11tok_get_mechanism_info(tokdata, mech, pinfo); if (rc != CKR_OK) return rc; return tokdata->policy->update_mech_info(tokdata->policy, mech, pinfo); } static CK_RV ep11tok_mechanism_list_add_translated( STDLL_TokData_t * tokdata, CK_MECHANISM_TYPE_PTR pMechanismList, CK_ULONG_PTR pulCount, CK_ULONG size) { CK_ULONG i; for (i = 0; i < pkcs11_mechanism_translation_len; i++) { if (ep11tok_is_mechanism_supported(tokdata, pkcs11_mechanism_translation[i].pkcs11_mech) != CKR_OK) continue; if (pMechanismList != NULL && *pulCount < size) pMechanismList[*pulCount] = pkcs11_mechanism_translation[i].pkcs11_mech; *pulCount += 1; } return CKR_OK; } struct sha_combined { CK_MECHANISM_TYPE combined_mech; CK_MECHANISM_TYPE hash_mech; CK_MECHANISM_TYPE base_mech; }; /* * Note: For RSA-PSS, EP11 requires that the data-hash function is the same * as the 'mgf' and 'hashalg' fields in the mechanism parameter. * So CKM_SHA3_nnn_RSA_PKCS_PSS would need to use CKM_[IBM_]SHA3_nnn and * CKG_[IBM_]MGF1_SHA3_nnn. However, EP11 currently does not support the SHA3 * algorithms for the RSA-PSS mechanism parameter (only for RSA-OAEP). * Thus CKM_SHA3_nnn_RSA_PKCS_PSS can not be supported with SHA3 hashing, * even though the data hashing would be performed by libica. */ static const struct sha_combined sha3_combined_libica_only_mechs[] = { { CKM_SHA3_224_RSA_PKCS, CKM_IBM_SHA3_224, CKM_RSA_PKCS }, { CKM_SHA3_256_RSA_PKCS, CKM_IBM_SHA3_256, CKM_RSA_PKCS }, { CKM_SHA3_384_RSA_PKCS, CKM_IBM_SHA3_384, CKM_RSA_PKCS }, { CKM_SHA3_512_RSA_PKCS, CKM_IBM_SHA3_512, CKM_RSA_PKCS }, { CKM_ECDSA_SHA3_224, CKM_IBM_SHA3_224, CKM_ECDSA }, { CKM_ECDSA_SHA3_256, CKM_IBM_SHA3_256, CKM_ECDSA }, { CKM_ECDSA_SHA3_384, CKM_IBM_SHA3_384, CKM_ECDSA }, { CKM_ECDSA_SHA3_512, CKM_IBM_SHA3_512, CKM_ECDSA }, }; static const CK_ULONG sha3_combined_libica_only_mechs_len = (sizeof(sha3_combined_libica_only_mechs) / sizeof(struct sha_combined)); static const struct sha_combined *ep11tok_find_sha3_combined_libica_only_mech( STDLL_TokData_t *tokdata, CK_MECHANISM_TYPE type) { ep11_private_data_t *ep11_data = tokdata->private_data; CK_ULONG i; for (i = 0; i < sha3_combined_libica_only_mechs_len; i++) { if (type == sha3_combined_libica_only_mechs[i].combined_mech) { /* Only supported if hash mech is available via libica */ if (!ep11tok_libica_digest_available(tokdata, ep11_data, sha3_combined_libica_only_mechs[i].hash_mech)) continue; TRACE_DEVEL("%s Mech '%s' is a combined libica-only mech backed by " "'%s' and '%s'\n", __func__, ep11_get_ckm(tokdata, type), ep11_get_ckm(tokdata, sha3_combined_libica_only_mechs[i].hash_mech), ep11_get_ckm(tokdata, sha3_combined_libica_only_mechs[i].base_mech)); return &sha3_combined_libica_only_mechs[i]; } } return NULL; } static CK_RV ep11tok_mechanism_list_add_sha3_combined( STDLL_TokData_t *tokdata, CK_MECHANISM_TYPE_PTR pMechanismList, CK_ULONG_PTR pulCount, CK_ULONG size) { ep11_private_data_t *ep11_data = tokdata->private_data; CK_ULONG i; for (i = 0; i < sha3_combined_libica_only_mechs_len; i++) { if (ep11tok_is_mechanism_supported(tokdata, sha3_combined_libica_only_mechs[i].hash_mech) != CKR_OK || ep11tok_is_mechanism_supported(tokdata, sha3_combined_libica_only_mechs[i].base_mech) != CKR_OK) continue; /* Only add if hash mech is available via libica */ if (!ep11tok_libica_digest_available(tokdata, ep11_data, sha3_combined_libica_only_mechs[i].hash_mech)) continue; if (pMechanismList != NULL && *pulCount < size) pMechanismList[*pulCount] = sha3_combined_libica_only_mechs[i].combined_mech; *pulCount += 1; } return CKR_OK; } /* 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) { CK_RV rc = 0; CK_ULONG counter = 0, size = 0; CK_MECHANISM_TYPE_PTR mlist = NULL; CK_MECHANISM_TYPE_PTR tmp; CK_ULONG i; ep11_target_info_t* target_info; CK_MECHANISM_INFO info; target_info = get_target_info(tokdata); if (target_info == NULL) return CKR_FUNCTION_FAILED; /* size query */ if (pMechanismList == NULL) { RETRY_SINGLE_APQN_START(tokdata, rc) rc = dll_m_GetMechanismList(0, pMechanismList, pulCount, target_info->target); RETRY_SINGLE_APQN_END(rc, tokdata, target_info) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, NULL); TRACE_ERROR("%s bad rc=0x%lx from m_GetMechanismList() #1\n", __func__, rc); goto out; } /* 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 { tmp = (CK_MECHANISM_TYPE *) realloc(mlist, sizeof(CK_MECHANISM_TYPE) * counter); if (!tmp) { TRACE_ERROR("%s Memory allocation failed\n", __func__); rc = CKR_HOST_MEMORY; goto out; } mlist = tmp; RETRY_SINGLE_APQN_START(tokdata, rc) rc = dll_m_GetMechanismList(0, mlist, &counter, target_info->target); RETRY_SINGLE_APQN_END(rc, tokdata, target_info) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, NULL); TRACE_ERROR("%s bad rc=0x%lx from m_GetMechanismList() #2\n", __func__, rc); if (rc != CKR_BUFFER_TOO_SMALL) goto out; } /* counter was updated in case of CKR_BUFFER_TOO_SMALL */ *pulCount = counter; } while (rc == CKR_BUFFER_TOO_SMALL); for (i = 0; i < counter; i++) { if (mlist[i] == CKM_IBM_CPACF_WRAP) { /* Internal mechanisms should not be exposed. */ *pulCount = *pulCount - 1; } else if (ep11tok_is_mechanism_supported(tokdata, mlist[i]) != CKR_OK) { /* banned mech found, * decrement reported list size */ *pulCount = *pulCount - 1; } else if (ep11tok_check_policy_for_mech(tokdata, mlist[i], &info) != CKR_OK) { TRACE_DEVEL("Policy blocks mechanism 0x%lx!\n", mlist[i]); *pulCount -= 1; } } if (ep11tok_is_mechanism_supported(tokdata, CKM_AES_XTS) == CKR_OK && ep11tok_is_mechanism_supported(tokdata, CKM_AES_XTS_KEY_GEN) == CKR_OK) { *pulCount += 2; } rc = ep11tok_mechanism_list_add_translated(tokdata, pMechanismList, pulCount, 0); if (rc != CKR_OK) goto out; rc = ep11tok_mechanism_list_add_sha3_combined(tokdata, pMechanismList, pulCount, 0); if (rc != CKR_OK) goto out; if (ep11tok_is_mechanism_supported(tokdata, CKM_IBM_ML_KEM) == CKR_OK && ep11tok_is_mechanism_supported(tokdata, CKM_ECDH1_DERIVE) == CKR_OK) { *pulCount += 1; } if (ep11tok_is_mechanism_supported(tokdata, CKM_IBM_ED25519_SHA512) == CKR_OK && ep11tok_is_mechanism_supported(tokdata, CKM_IBM_ED448_SHA3) == CKR_OK) { *pulCount += 1; } if (ep11tok_is_mechanism_supported(tokdata, CKM_PUB_KEY_FROM_PRIV_KEY) == CKR_OK) *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 */ RETRY_SINGLE_APQN_START(tokdata, rc) rc = dll_m_GetMechanismList(0, mlist, &counter, target_info->target); RETRY_SINGLE_APQN_END(rc, tokdata, target_info) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, NULL); TRACE_ERROR("%s bad rc=0x%lx from m_GetMechanismList() #3\n", __func__, rc); goto out; } /* * 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 { tmp = (CK_MECHANISM_TYPE *) realloc(mlist, sizeof(CK_MECHANISM_TYPE) * counter); if (!tmp) { TRACE_ERROR("%s Memory allocation failed\n", __func__); rc = CKR_HOST_MEMORY; goto out; } mlist = tmp; /* all the card has */ RETRY_SINGLE_APQN_START(tokdata, rc) rc = dll_m_GetMechanismList(0, mlist, &counter, target_info->target); RETRY_SINGLE_APQN_END(rc, tokdata, target_info) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, NULL); TRACE_ERROR("%s bad rc=0x%lx from m_GetMechanismList() #4\n", __func__, rc); if (rc != CKR_BUFFER_TOO_SMALL) goto out; } } 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(tokdata, mlist[i])); /* copy only mechanisms not banned */ *pulCount = 0; for (i = 0; i < counter; i++) { if (mlist[i] == CKM_IBM_CPACF_WRAP) /* Internal mechanisms should not be exposed. */ continue; if (ep11tok_check_policy_for_mech(tokdata, mlist[i], &info) != CKR_OK) { TRACE_DEVEL("Policy blocks mechanism 0x%lx!\n", mlist[i]); continue; } if (ep11tok_is_mechanism_supported(tokdata, mlist[i]) == CKR_OK) { if (*pulCount < size) pMechanismList[*pulCount] = mlist[i]; *pulCount = *pulCount + 1; } } if (ep11tok_is_mechanism_supported(tokdata, CKM_AES_XTS) == CKR_OK && ep11tok_is_mechanism_supported(tokdata, CKM_AES_XTS_KEY_GEN) == CKR_OK) { if (*pulCount < size) pMechanismList[*pulCount] = CKM_AES_XTS_KEY_GEN; *pulCount = *pulCount + 1; if (*pulCount < size) pMechanismList[*pulCount] = CKM_AES_XTS; *pulCount = *pulCount + 1; } rc = ep11tok_mechanism_list_add_translated(tokdata, pMechanismList, pulCount, size); if (*pulCount > size) rc = CKR_BUFFER_TOO_SMALL; if (rc != CKR_OK) goto out; rc = ep11tok_mechanism_list_add_sha3_combined(tokdata, pMechanismList, pulCount, size); if (rc != CKR_OK) goto out; if (ep11tok_is_mechanism_supported(tokdata, CKM_IBM_ML_KEM) == CKR_OK && ep11tok_is_mechanism_supported(tokdata, CKM_ECDH1_DERIVE) == CKR_OK) { if (*pulCount < size) pMechanismList[*pulCount] = CKM_IBM_ML_KEM_WITH_ECDH; *pulCount = *pulCount + 1; } if (*pulCount > size) rc = CKR_BUFFER_TOO_SMALL; if (ep11tok_is_mechanism_supported(tokdata, CKM_IBM_ED25519_SHA512) == CKR_OK && ep11tok_is_mechanism_supported(tokdata, CKM_IBM_ED448_SHA3) == CKR_OK) { if (*pulCount < size) pMechanismList[*pulCount] = CKM_EDDSA; *pulCount = *pulCount + 1; } if (*pulCount > size) rc = CKR_BUFFER_TOO_SMALL; if (ep11tok_is_mechanism_supported(tokdata, CKM_PUB_KEY_FROM_PRIV_KEY) == CKR_OK) { if (*pulCount < size) pMechanismList[*pulCount] = CKM_PUB_KEY_FROM_PRIV_KEY; *pulCount = *pulCount + 1; } } out: if (mlist) free(mlist); put_target_info(tokdata, target_info); 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; const CK_VERSION ver1_3 = { .major = 1, .minor = 0x30 }; const CK_VERSION ver3 = { .major = 3, .minor = 0 }; const CK_VERSION ver3_1 = { .major = 3, .minor = 0x10 }; const CK_VERSION ver4 = { .major = 4, .minor = 0 }; const CK_VERSION ver4_1_2 = { .major = 4, .minor = 0x12 }; const CK_VERSION ver4_2 = { .major = 4, .minor = 0x20 }; CK_BBOOL found = FALSE; CK_ULONG i; int status; CK_RV rc = CKR_OK; ep11_target_info_t* target_info; CK_MECHANISM_TYPE orig_mech = type; const struct sha_combined *comb_mech; comb_mech = ep11tok_find_sha3_combined_libica_only_mech(tokdata, type); if (comb_mech != NULL && ep11tok_is_mechanism_supported(tokdata, comb_mech->hash_mech) == CKR_OK) type = comb_mech->base_mech; ep11tok_pkcs11_mech_translate(tokdata, type, &type); for (i = 0; i < supported_mech_list_len; i++) { if (type == ep11_supported_mech_list[i]) { found = TRUE; break; } } if (!found) { TRACE_INFO("%s Mech '%s' not suppported\n", __func__, ep11_get_ckm(tokdata, type)); return CKR_MECHANISM_INVALID; } target_info = get_target_info(tokdata); if (target_info == NULL) return CKR_FUNCTION_FAILED; if (check_cps_for_mechanism(tokdata, ep11_data->cp_config, type, target_info->control_points, target_info->control_points_len, target_info->max_control_point_index) != CKR_OK) { TRACE_INFO("%s Mech '%s' banned due to control point\n", __func__, ep11_get_ckm(tokdata, orig_mech)); rc = CKR_MECHANISM_INVALID; goto out; } 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 old card or mixed firmware versions\n", __func__, ep11_get_ckm(tokdata, orig_mech)); rc = CKR_MECHANISM_INVALID; goto out; } 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) { rc = CKR_MECHANISM_INVALID; goto out; } status = check_required_versions(tokdata, oaep_req_versions, NUM_OAEP_REQ); if (status != 1) { TRACE_INFO("%s Mech '%s' banned due to old card or mixed firmware versions\n", __func__, ep11_get_ckm(tokdata, orig_mech)); rc = CKR_MECHANISM_INVALID; goto out; } 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 old card or mixed firmware versions\n", __func__, ep11_get_ckm(tokdata, orig_mech)); rc = CKR_MECHANISM_INVALID; goto out; } 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 old card or mixed firmware versions\n", __func__, ep11_get_ckm(tokdata, orig_mech)); rc = CKR_MECHANISM_INVALID; goto out; } break; case CKM_IBM_EC_X25519: case CKM_IBM_ED25519_SHA512: case CKM_IBM_EC_X448: 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(tokdata, orig_mech)); rc = CKR_MECHANISM_INVALID; goto out; } status = check_required_versions(tokdata, edwards_req_versions, NUM_EDWARDS_REQ); if (status != 1) { TRACE_INFO("%s Mech '%s' banned due to old card or mixed firmware versions\n", __func__, ep11_get_ckm(tokdata, orig_mech)); rc = CKR_MECHANISM_INVALID; goto out; } 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(tokdata, orig_mech)); rc = CKR_MECHANISM_INVALID; goto out; } status = check_required_versions(tokdata, ibm_dilithium_req_versions, NUM_DILITHIUM_REQ); if (status != 1) { TRACE_INFO("%s Mech '%s' banned due to old card or mixed firmware versions\n", __func__, ep11_get_ckm(tokdata, orig_mech)); rc = CKR_MECHANISM_INVALID; goto out; } break; case CKM_IBM_KYBER: if (compare_ck_version(&ep11_data->ep11_lib_version, &ver4) < 0) { TRACE_INFO("%s Mech '%s' banned due to host library version\n", __func__, ep11_get_ckm(tokdata, orig_mech)); rc = CKR_MECHANISM_INVALID; goto out; } status = check_required_versions(tokdata, ibm_kyber_req_versions, NUM_KYBER_REQ); if (status != 1) { TRACE_INFO("%s Mech '%s' banned due to old card or mixed firmware versions\n", __func__, ep11_get_ckm(tokdata, orig_mech)); rc = CKR_MECHANISM_INVALID; goto out; } break; case CKM_IBM_ML_DSA: case CKM_IBM_ML_DSA_KEY_PAIR_GEN: case CKM_IBM_ML_KEM: case CKM_IBM_ML_KEM_KEY_PAIR_GEN: case CKM_ML_DSA_KEY_PAIR_GEN: case CKM_ML_DSA: case CKM_ML_KEM_KEY_PAIR_GEN: case CKM_ML_KEM: if (compare_ck_version(&ep11_data->ep11_lib_version, &ver4_2) < 0) { TRACE_INFO("%s Mech '%s' banned due to host library version\n", __func__, ep11_get_ckm(tokdata, orig_mech)); rc = CKR_MECHANISM_INVALID; goto out; } status = check_required_versions(tokdata, ibm_mldsa_kem_req_versions, NUM_ML_DSA_KEM_REQ); if (status != 1) { TRACE_INFO("%s Mech '%s' banned due to old card or mixed firmware versions\n", __func__, ep11_get_ckm(tokdata, orig_mech)); rc = CKR_MECHANISM_INVALID; goto out; } break; #ifndef NO_PKEY case CKM_IBM_CPACF_WRAP: 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(tokdata, orig_mech)); rc = CKR_MECHANISM_INVALID; goto out; } status = check_required_versions(tokdata, ibm_cpacf_wrap_req_versions, NUM_CPACF_WRAP_REQ); if (status != 1) { TRACE_INFO("%s Mech '%s' banned due to old card or mixed firmware versions\n", __func__, ep11_get_ckm(tokdata, orig_mech)); rc = CKR_MECHANISM_INVALID; goto out; } break; #endif /* NO_PKEY */ case CKM_IBM_BTC_DERIVE: if (compare_ck_version(&ep11_data->ep11_lib_version, &ver3_1) < 0) { TRACE_INFO("%s Mech '%s' banned due to host library version\n", __func__, ep11_get_ckm(tokdata, orig_mech)); rc = CKR_MECHANISM_INVALID; goto out; } status = check_required_versions(tokdata, ibm_btc_req_versions, NUM_BTC_REQ); if (status != 1) { TRACE_INFO("%s Mech '%s' banned due to old card or mixed firmware versions\n", __func__, ep11_get_ckm(tokdata, orig_mech)); rc = CKR_MECHANISM_INVALID; goto out; } break; case CKM_IBM_ECDSA_OTHER: if (compare_ck_version(&ep11_data->ep11_lib_version, &ver3_1) < 0) { TRACE_INFO("%s Mech '%s' banned due to host library version\n", __func__, ep11_get_ckm(tokdata, orig_mech)); rc = CKR_MECHANISM_INVALID; goto out; } status = check_required_versions(tokdata, ibm_ecdsa_other_req_versions, NUM_ECDSA_OTHER_REQ); if (status != 1) { TRACE_INFO("%s Mech '%s' banned due to old card or mixed firmware versions\n", __func__, ep11_get_ckm(tokdata, orig_mech)); rc = CKR_MECHANISM_INVALID; goto out; } break; case CKM_IBM_EC_AGGREGATE: if (compare_ck_version(&ep11_data->ep11_lib_version, &ver4_1_2) < 0) { TRACE_INFO("%s Mech '%s' banned due to host library version\n", __func__, ep11_get_ckm(tokdata, orig_mech)); rc = CKR_MECHANISM_INVALID; goto out; } status = check_required_versions(tokdata, ibm_bls_req_versions, NUM_BLS_REQ); if (status != 1) { TRACE_INFO("%s Mech '%s' banned due to old card or mixed firmware versions\n", __func__, ep11_get_ckm(tokdata, orig_mech)); rc = CKR_MECHANISM_INVALID; goto out; } break; case CKM_AES_XTS: case CKM_AES_XTS_KEY_GEN: if ((ep11_data->pkey_wrap_support_checked && !ep11_data->pkey_wrap_supported) || ep11tok_pkey_option_disabled(tokdata) || ep11_data->msa_level < 4 || ep11tok_is_mechanism_supported(tokdata, CKM_IBM_CPACF_WRAP) != CKR_OK || ep11tok_is_mechanism_supported(tokdata, CKM_AES_KEY_GEN) != CKR_OK) { TRACE_INFO("%s Mech '%s' not suppported\n", __func__, ep11_get_ckm(tokdata, orig_mech)); rc = CKR_MECHANISM_INVALID; goto out; } break; case CKM_IBM_ML_KEM_WITH_ECDH: if (ep11tok_is_mechanism_supported(tokdata, CKM_IBM_ML_KEM) != CKR_OK || ep11tok_is_mechanism_supported(tokdata, CKM_ECDH1_DERIVE) != CKR_OK) { TRACE_INFO("%s Mech '%s' not suppported\n", __func__, ep11_get_ckm(tokdata, orig_mech)); rc = CKR_MECHANISM_INVALID; goto out; } break; } out: put_target_info(tokdata, target_info); return rc; } 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) { CK_RV rc; int status; ep11_target_info_t* target_info; const struct sha_combined *comb_mech; CK_MECHANISM_TYPE orig_type = type; 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(tokdata, type)); return rc; } ep11tok_pkcs11_mech_translate(tokdata, type, &type); /* Get base-mech for combined libica-only mechanism */ comb_mech = ep11tok_find_sha3_combined_libica_only_mech(tokdata, type); if(comb_mech != NULL) type = comb_mech->base_mech; target_info = get_target_info(tokdata); if (target_info == NULL) return CKR_FUNCTION_FAILED; switch (orig_type) { case CKM_AES_XTS: pInfo->ulMinKeySize = 32; pInfo->ulMaxKeySize = 64; pInfo->flags = (CK_FLAGS)(CKF_ENCRYPT|CKF_DECRYPT); break; case CKM_AES_XTS_KEY_GEN: pInfo->ulMinKeySize = 32; pInfo->ulMaxKeySize = 64; pInfo->flags = (CK_FLAGS)(CKF_HW|CKF_GENERATE); break; case CKM_EC_EDWARDS_KEY_PAIR_GEN: case CKM_EC_MONTGOMERY_KEY_PAIR_GEN: pInfo->ulMinKeySize = 255; pInfo->ulMaxKeySize = 448; pInfo->flags = (CK_FLAGS)(CKF_GENERATE_KEY_PAIR | CKF_EC_OID | CKF_EC_F_P | CKF_EC_COMPRESS); break; case CKM_EDDSA: pInfo->ulMinKeySize = 255; pInfo->ulMaxKeySize = 448; pInfo->flags = (CK_FLAGS)(CKF_SIGN | CKF_VERIFY | CKF_EC_OID | CKF_EC_F_P | CKF_EC_COMPRESS); break; case CKM_PUB_KEY_FROM_PRIV_KEY: pInfo->ulMinKeySize = 0; pInfo->ulMaxKeySize = 0; pInfo->flags = (CK_FLAGS)(CKF_DERIVE); break; default: if (type == CKM_IBM_ML_KEM_WITH_ECDH) type = CKM_IBM_ML_KEM; RETRY_SINGLE_APQN_START(tokdata, rc) rc = dll_m_GetMechanismInfo(0, type, pInfo, target_info->target); RETRY_SINGLE_APQN_END(rc, tokdata, target_info) break; } put_target_info(tokdata, target_info); 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 (orig_type) { case CKM_RSA_PKCS: case CKM_RSA_PKCS_OAEP: /* En/Decapsulate is not known by EP11, but we support it anyway */ if (pInfo->flags & CKF_WRAP) pInfo->flags |= CKF_ENCAPSULATE; if (pInfo->flags & CKF_UNWRAP) pInfo->flags |= CKF_DECAPSULATE; /* fallthrough */ case CKM_RSA_PKCS_KEY_PAIR_GEN: case CKM_RSA_X9_31_KEY_PAIR_GEN: case CKM_RSA_PKCS_PSS: 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_SHA3_256_RSA_PKCS: case CKM_SHA3_224_RSA_PKCS: case CKM_SHA3_384_RSA_PKCS: case CKM_SHA3_512_RSA_PKCS: 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: case CKM_SHA3_224_HMAC: case CKM_SHA3_256_HMAC: case CKM_SHA3_384_HMAC: case CKM_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; case CKM_GENERIC_SECRET_KEY_GEN: /* Older EP11 firmware may report CKF_DERIVE, mask it */ pInfo->flags &= ~CKF_DERIVE; break; case CKM_SHA1_KEY_DERIVATION: pInfo->ulMinKeySize = 8; pInfo->ulMaxKeySize = SHA1_HASH_SIZE * 8; break; case CKM_SHA224_KEY_DERIVATION: pInfo->ulMinKeySize = 8; pInfo->ulMaxKeySize = SHA224_HASH_SIZE * 8; break; case CKM_SHA256_KEY_DERIVATION: pInfo->ulMinKeySize = 8; pInfo->ulMaxKeySize = SHA256_HASH_SIZE * 8; break; case CKM_SHA384_KEY_DERIVATION: pInfo->ulMinKeySize = 8; pInfo->ulMaxKeySize = SHA384_HASH_SIZE * 8; break; case CKM_SHA512_KEY_DERIVATION: pInfo->ulMinKeySize = 8; pInfo->ulMaxKeySize = SHA512_HASH_SIZE * 8; break; case CKM_SHA512_224_KEY_DERIVATION: pInfo->ulMinKeySize = 8; pInfo->ulMaxKeySize = SHA224_HASH_SIZE * 8; break; case CKM_SHA512_256_KEY_DERIVATION: pInfo->ulMinKeySize = 8; pInfo->ulMaxKeySize = SHA256_HASH_SIZE * 8; break; case CKM_ECDH1_DERIVE: case CKM_DH_PKCS_DERIVE: /* En/Decapsulate is not known by EP11, but we support it anyway */ if (pInfo->flags & CKF_DERIVE) pInfo->flags |= CKF_ENCAPSULATE | CKF_DECAPSULATE; break; case CKM_ML_KEM: /* En/Decapsulate is not known by EP11, but we support it anyway */ if (pInfo->flags & CKF_DERIVE) pInfo->flags |= CKF_ENCAPSULATE | CKF_DECAPSULATE; pInfo->flags &= ~CKF_DERIVE; /* Don't report CKF_DERIVE */ break; default: ; /* do not touch */ } #endif /* DEFENSIVE_MECHLIST */ /* * EP11 only supports uncompressed EC public keys, but the EP11 token * also supports compressed EC public keys, by uncompressing them before * passing them to EP11. Thus, for all mechanisms that have the * CKF_EC_UNCOMPRESS flag set, also set CKF_EC_COMPRESS. */ if (pInfo->flags & CKF_EC_UNCOMPRESS) pInfo->flags |= CKF_EC_COMPRESS; return tokdata->policy->update_mech_info(tokdata->policy, type, pInfo); } static CK_RV ep11_config_add_apqn(ep11_private_data_t *ep11_data, struct ConfigNumPairNode *pair, const char *fname) { if (pair->value1 > 255) { OCK_SYSLOG(LOG_ERR, "%s: Error: Expected valid adapter" " number, found '%lu' in config file '%s' at line %d\n", __func__, pair->value1, fname, pair->base.line); TRACE_ERROR(" Error: Expected valid adapter number, found '%lu' in " "config file '%s' at line %d\n", pair->value1, fname, pair->base.line); return CKR_ARGUMENTS_BAD; } if (pair->value2 > 255) { OCK_SYSLOG(LOG_ERR, "%s: Error: Expected valid domain" " number, found '%lu' in config file '%s' at line %d\n", __func__, pair->value2, fname, pair->base.line); TRACE_ERROR(" Error: Expected valid domain number, found '%lu' in " "config file '%s' at line %d\n", pair->value2, fname, pair->base.line); return CKR_ARGUMENTS_BAD; } if (ep11_data->target_list.length >= MAX_APQN) { OCK_SYSLOG(LOG_ERR,"%s: Error: Too many APQNs in config " "file '%s' (max %d)\n", __func__, fname, (int) MAX_APQN); TRACE_ERROR("Too many APQNs in config file '%s' (max %d)\n", fname, (int) MAX_APQN); return CKR_BUFFER_TOO_SMALL; } ep11_data->target_list.apqns[ep11_data->target_list.length * 2] = pair->value1; ep11_data->target_list.apqns[ep11_data->target_list.length * 2 + 1] = pair->value2; ep11_data->target_list.length++; return CKR_OK; } void ep11_config_parse_error(int line, int col, const char *msg) { OCK_SYSLOG(LOG_ERR, "Error parsing EP11 config file: line %d column %d: %s\n", line, col, msg); TRACE_ERROR("Error parsing EP11 config file: line %d column %d: %s\n", line, col, msg); } void ep11_config_error_token(const char *fname, const char *key, int line, const char *expected) { if (expected != NULL) { OCK_SYSLOG(LOG_ERR, "Error parsing config file '%s': unexpected token " "'%s' at line %d, expected %s\n", fname, key != NULL ? key : "(none)", line, expected); TRACE_ERROR("Error parsing config file '%s': unexpected token " " '%s' at line %d, expected %s\n", fname, key != NULL ? key : "(none)", line, expected); } else { OCK_SYSLOG(LOG_ERR, "Error parsing config file '%s': " "unexpected token '%s' at line %d\n", fname, key != NULL ? key : "(none)", line); TRACE_ERROR("Error parsing config file '%s': unexpected token " "'%s' at line %d\n", fname, key != NULL ? key : "(none)", line); } } static void ep11_config_error_eof(const char *fname, const char *expected) { if (expected != NULL) { OCK_SYSLOG(LOG_ERR, "Error: Unexpected end of file found in config " "file '%s', expected %s\n", fname, expected); TRACE_ERROR("Error: Unexpected end of file found in config file '%s', " "expected %s\\n", fname, expected); } else { OCK_SYSLOG(LOG_ERR, "Error: Unexpected end of file found in config " "file '%s'\n", fname); TRACE_ERROR("Error: Unexpected end of file found in config file '%s'\n", fname); } } CK_RV ep11_config_next(struct ConfigBaseNode **c, unsigned typemask, const char *fname, const char *expected) { *c = (*c)->next; if (*c == NULL) { ep11_config_error_eof(fname, expected); return CKR_FUNCTION_FAILED; } if (!confignode_hastype(*c, typemask)) { ep11_config_error_token(fname, (*c)->key, (*c)->line, expected); return CKR_FUNCTION_FAILED; } return CKR_OK; } static CK_RV ep11_config_set_cpfilter(ep11_private_data_t *ep11_data, const char *fname, const char *strval) { if (strlen(strval) > sizeof(ep11_data->cp_filter_config_filename) - 1) { TRACE_ERROR("%s CP-Filter config file name is too long: '%s'\n", __func__, strval); OCK_SYSLOG(LOG_ERR, "%s: Error: CP-Filter config file name '%s' is " "too long in config file '%s'\n", __func__, strval, fname); return CKR_FUNCTION_FAILED; } strncpy(ep11_data->cp_filter_config_filename, strval, sizeof(ep11_data->cp_filter_config_filename) - 1); ep11_data->cp_filter_config_filename[ sizeof(ep11_data->cp_filter_config_filename) - 1] = '\0'; return CKR_OK; } static CK_RV ep11_config_set_pkey_mode(ep11_private_data_t *ep11_data, const char *fname, const char *strval) { if (strcmp(strval, "DISABLED") == 0) ep11_data->pkey_mode = PKEY_MODE_DISABLED; #ifndef NO_PKEY else if (strcmp(strval, "DEFAULT") == 0) ep11_data->pkey_mode = PKEY_MODE_DEFAULT; else if (strcmp(strval, "ENABLE4NONEXTR") == 0) ep11_data->pkey_mode = PKEY_MODE_ENABLE4NONEXTR; else if (strcmp(strval, "ENABLE4EXTR") == 0) ep11_data->pkey_mode = PKEY_MODE_ENABLE4EXTR; else if (strcmp(strval, "ENABLE4ALL") == 0) ep11_data->pkey_mode = PKEY_MODE_ENABLE4ALL; #endif /* NO_PKEY */ else { TRACE_ERROR("%s unsupported PKEY mode : '%s'\n", __func__, strval); OCK_SYSLOG(LOG_ERR,"%s: Error: unsupported PKEY mode '%s' " "in config file '%s'\n", __func__, strval, fname); return CKR_FUNCTION_FAILED; } return CKR_OK; } static CK_RV ep11_config_set_libica(ep11_private_data_t *ep11_data, const char *fname, const char *strval) { if (strcmp(strval, "OFF") == 0) { ep11_data->digest_libica = 0; } else if (strcmp(strval, "DEFAULT") == 0) { ep11_data->digest_libica = 1; strcpy(ep11_data->digest_libica_path, ""); } else { if (strlen(strval) > sizeof(ep11_data->digest_libica_path)-1) { TRACE_ERROR("%s libica path is too long: '%s'\n", __func__, strval); OCK_SYSLOG(LOG_ERR,"%s: Error: libica path '%s' is too long" " in config file '%s'\n", __func__, strval, fname); return CKR_FUNCTION_FAILED; } ep11_data->digest_libica = 1; strncpy(ep11_data->digest_libica_path, strval, sizeof(ep11_data->digest_libica_path)-1); ep11_data->digest_libica_path[ sizeof(ep11_data->digest_libica_path)-1] = '\0'; } return CKR_OK; } static CK_RV ep11_config_set_wkvp(ep11_private_data_t *ep11_data, const char *fname, const char *strval) { unsigned int i, val; if (strncasecmp(strval, "0x", 2) == 0) strval += 2; if (strlen(strval) < sizeof(ep11_data->expected_wkvp) * 2) { TRACE_ERROR("%s expected WKVP is too short: '%s', expected %lu hex " "characters in config file '%s'\n", __func__, strval, sizeof(ep11_data->expected_wkvp) * 2, fname); OCK_SYSLOG(LOG_ERR,"%s: Error: expected WKVP is too short: '%s', " "expected %lu hex characters in config file '%s'\n", __func__, strval, sizeof(ep11_data->expected_wkvp) * 2, fname); return CKR_FUNCTION_FAILED; } if (strlen(strval) > sizeof(ep11_data->expected_wkvp) * 2) { TRACE_INFO("%s only the first %lu characters of the expected WKVP in " "config file '%s' are used: %s\n", __func__, sizeof(ep11_data->expected_wkvp) * 2, fname, strval); OCK_SYSLOG(LOG_INFO,"%s: Info: only the first %lu characters of the " "expected WKVP in config file '%s' are used: %s\n", __func__, sizeof(ep11_data->expected_wkvp) * 2, fname, strval); } for (i = 0; i < sizeof(ep11_data->expected_wkvp); i++) { if (sscanf(strval + (i * 2), "%02x", &val) != 1) { TRACE_ERROR("%s failed to parse expected WKVP: '%s' at character " "%u in config file '%s'\n", __func__, strval, (i * 2), fname); OCK_SYSLOG(LOG_ERR,"%s: Error: failed to parse expected WKVP: '%s' " "at character %u in config file '%s'\n", __func__, strval, (i * 2), fname); return CKR_FUNCTION_FAILED; } ep11_data->expected_wkvp[i] = val; } ep11_data->expected_wkvp_set = 1; TRACE_DEBUG_DUMP("Expected WKVP: ", ep11_data->expected_wkvp, sizeof(ep11_data->expected_wkvp)); return CKR_OK; } static CK_RV 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, k; int whitemode = 0; int anymode = 0; /* Since the ep11 token config contains the path to libica that * will later be dlopen()ed, we cannot use a token config * directory from an untrusted environment. */ char *conf_dir = secure_getenv("OCK_EP11_TOKEN_DIR"); char fname[PATH_MAX]; CK_RV rc = CKR_OK; char *cfg_dir; char cfgname[2*PATH_MAX + 1]; struct ConfigBaseNode *c, *e, *config = NULL; struct ConfigBareConstNode *bare; struct ConfigNumPairListNode *list; struct ConfigBareStringConstNode *barestr; const char *strval; if (tokdata->initialized) return CKR_OK; memset(fname, 0, PATH_MAX); /* via environment 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) { 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 CKR_FUNCTION_FAILED; } TRACE_INFO("%s EP 11 token config file is '%s'\n", __func__, fname); rc = parse_configlib_file(ap_fp, &config, ep11_config_parse_error, 0); fclose(ap_fp); if (rc != 0) { TRACE_ERROR("Error parsing config file '%s'\n", fname); return CKR_FUNCTION_FAILED; } strncpy(ep11_data->token_config_filename, fname, sizeof(ep11_data->token_config_filename)); ep11_data->token_config_filename[ sizeof(ep11_data->token_config_filename) - 1] = '\0'; ep11_data->target_list.length = 0; #ifndef NO_PKEY ep11_data->pkey_mode = PKEY_MODE_DEFAULT; #else ep11_data->pkey_mode = PKEY_MODE_DISABLED; #endif /* Default to use default libica library for digests */ ep11_data->digest_libica = 1; strcpy(ep11_data->digest_libica_path, ""); /* Analyse the parsed config elements * please note, we still accept the LOGLEVEL entry * for compatibility reasons but just ignore it. */ confignode_foreach(c, config, i) { TRACE_DEBUG("Config node: '%s' type: %u line: %u\n", c->key, c->type, c->line); if (confignode_hastype(c, CT_FILEVERSION)) { TRACE_DEBUG("Config file version: '%s'\n", confignode_to_fileversion(c)->base.key); continue; } if (confignode_hastype(c, CT_STRINGVAL) || confignode_hastype(c, CT_BAREVAL)) { /* New style (key = value) tokens */ strval = confignode_getstr(c); if (strcmp(c->key, "CPFILTER") == 0) { rc = ep11_config_set_cpfilter(ep11_data, fname, strval); if (rc != CKR_OK) break; continue; } if (strcmp(c->key, "PKEY_MODE") == 0) { rc = ep11_config_set_pkey_mode(ep11_data, fname, strval); if (rc != CKR_OK) break; continue; } if (strcmp(c->key, "DIGEST_LIBICA") == 0) { rc = ep11_config_set_libica(ep11_data, fname, strval); if (rc != CKR_OK) break; continue; } if (strcmp(c->key, "EXPECTED_WKVP") == 0) { rc = ep11_config_set_wkvp(ep11_data, fname, strval); if (rc != CKR_OK) break; continue; } } if (confignode_hastype(c, CT_NUMPAIRLIST)) { list = confignode_to_numpairlist(c); if ((strcmp(list->base.key, "APQN_WHITELIST") != 0 && strcmp(list->base.key, "APQN_ALLOWLIST") != 0) || strcmp(list->end, "END") != 0) { ep11_config_error_token(fname, list->base.key, list->base.line, "APQN_ALLOWLIST ... END"); rc = CKR_FUNCTION_FAILED; break; } whitemode = 1; confignode_foreach(e, list->value, k) { if (!confignode_hastype(e, CT_NUMPAIR)) { ep11_config_error_token(fname, e->key, e->line, "pair of NUMBERs"); rc = CKR_FUNCTION_FAILED; break; } rc = ep11_config_add_apqn(ep11_data, confignode_to_numpair(e), fname); if (rc != CKR_OK) break; } if (rc != CKR_OK) break; continue; } if (!confignode_hastype(c, CT_BARECONST)) { ep11_config_error_token(fname, c->key, c->line, NULL); rc = CKR_FUNCTION_FAILED; break; } bare = confignode_to_bareconst(c); if (strcmp(bare->base.key, "APQN_ANY") == 0) { anymode = 1; continue; } if (strcmp(bare->base.key, "FORCE_SENSITIVE") == 0) { ep11_data->cka_sensitive_default_true = 1; continue; } if (strcmp(bare->base.key, "CPFILTER") == 0) { rc = ep11_config_next(&c, CT_BARECONST | CT_BARESTRINGCONST, fname, "CP-Filter config file name"); if (rc != CKR_OK) break; if (confignode_hastype(c, CT_BARECONST)) strval = confignode_to_bareconst(c)->base.key; else strval = confignode_to_barestringconst(c)->base.key; rc = ep11_config_set_cpfilter(ep11_data, fname,strval); if (rc != CKR_OK) break; continue; } if (strcmp(bare->base.key, "STRICT_MODE") == 0) { ep11_data->strict_mode = 1; continue; } if (strcmp(bare->base.key, "VHSM_MODE") == 0) { ep11_data->vhsm_mode = 1; continue; } if (strcmp(bare->base.key, "FIPS_SESSION_MODE") == 0) { ep11_data->fips_session_mode = 1; continue; } if (strcmp(bare->base.key, "OPTIMIZE_SINGLE_PART_OPERATIONS") == 0) { ep11_data->optimize_single_ops = 1; continue; } if (strcmp(bare->base.key, "PKEY_MODE") == 0) { rc = ep11_config_next(&c, CT_BARECONST, fname, "PKEY mode"); if (rc != CKR_OK) break; rc = ep11_config_set_pkey_mode(ep11_data, fname, confignode_to_bareconst(c)->base.key); if (rc != CKR_OK) break; continue; } if (strcmp(bare->base.key, "DIGEST_LIBICA") == 0) { rc = ep11_config_next(&c, CT_BARECONST | CT_BARESTRINGCONST, fname, "libica path, 'DEFAULT', or 'OFF'"); if (rc != CKR_OK) break; if (confignode_hastype(c, CT_BARECONST)) strval = confignode_to_bareconst(c)->base.key; else strval = confignode_to_barestringconst(c)->base.key; rc = ep11_config_set_libica(ep11_data, fname,strval); if (rc != CKR_OK) break; continue; } if (strcmp(bare->base.key, "USE_PRANDOM") == 0) { token_specific.t_rng = NULL; continue; } if (strcmp(bare->base.key, "EXPECTED_WKVP") == 0) { rc = ep11_config_next(&c, CT_BARESTRINGCONST, fname, "WKID as quoted hex string"); if (rc != CKR_OK) break; barestr = confignode_to_barestringconst(c); rc = ep11_config_set_wkvp(ep11_data, fname, barestr->base.key); if (rc != CKR_OK) break; continue; } ep11_config_error_token(fname, c->key, c->line, NULL); rc = CKR_FUNCTION_FAILED; break; } confignode_deepfree(config); if (rc != CKR_OK) return rc; /* do some checks: */ if (ep11_data->fips_session_mode && (ep11_data->strict_mode || ep11_data->vhsm_mode)) { TRACE_ERROR("%s FIPS_SESSION_MODE can not be enabled together with " "STRICT_MODE or VHSM_MODE\n", __func__); OCK_SYSLOG(LOG_ERR, "%s: FIPS_SESSION_MODE can not be enabled together " "with STRICT_MODE or VHSM_MODE in config file '%s'\n", __func__, fname); return CKR_FUNCTION_FAILED; } if (!(whitemode || anymode)) { TRACE_ERROR("%s At least one APQN mode needs to be present in " "config file: APQN_ALLOWLIST 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_ALLOWLIST or APQN_ANY\n", __func__, fname); return CKR_FUNCTION_FAILED; } else if (whitemode && anymode) { TRACE_ERROR("%s Only one APQN mode can be present in config file:" " APQN_ALLOWLIST or APQN_ANY\n", __func__); OCK_SYSLOG(LOG_ERR, "%s: Error: Only one APQN mode can be present in" " config file '%s': APQN_ALLOWLIST or APQN_ANY\n", __func__, fname); return CKR_FUNCTION_FAILED; } 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); return CKR_FUNCTION_FAILED; } } /* log the whitelist of APQNs */ if (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 */ 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(tokdata, ep11_data->cp_filter_config_filename, &ep11_data->cp_config); return rc; } static CK_RV read_cp_filter_config_file(STDLL_TokData_t *tokdata, const char *conf_name, cp_config_t ** cp_config) { CK_RV rc = CKR_OK; 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 CKR_OK; } 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 = CKR_FUNCTION_FAILED; goto out_fclose; } } cp = (cp_config_t *) malloc(sizeof(cp_config_t)); if (cp == NULL) { TRACE_ERROR("%s Out of memory.\n", __func__); rc = CKR_HOST_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(tokdata, 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 = CKR_FUNCTION_FAILED; 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 = CKR_HOST_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(tokdata, 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_ALLOW_NONSESSION), CONSTINFO(XCP_CPB_ALG_EC_25519), CONSTINFO(XCP_CPB_ALG_EC_SECGCRV), CONSTINFO(XCP_CPB_ALG_NBSI2017), CONSTINFO(XCP_CPB_CPACF_PK), CONSTINFO(XCP_CPB_ALG_PQC_DILITHIUM), CONSTINFO(XCP_CPB_ALG_PQC), CONSTINFO(XCP_CPB_BTC), CONSTINFO(XCP_CPB_ECDSA_OTHER), CONSTINFO(XCP_CPB_ALG_NFIPS2021), CONSTINFO(XCP_CPB_ALG_NFIPS2024), CONSTINFO(XCP_CPB_COMPAT_LEGACY_SHA3), CONSTINFO(XCP_CPB_DSA_PARAMETER_GEN), CONSTINFO(XCP_CPB_DERIVE_NON_AB_KEYS), CONSTINFO(XCP_CPB_ALLOW_LOGIN_PRE_F2021), CONSTINFO(XCP_CPB_ALG_RSA_OAEP), CONSTINFO(XCP_CPB_ALLOW_COMBINED_EXTRACT), CONSTINFO(XCP_CPB_ALG_EC_PAIRING_FRIENDLY), CONSTINFO(XCP_CPB_ALG_DILITHIUM), CONSTINFO(XCP_CPB_ALG_KYBER), CONSTINFO(XCP_CPB_ALG_ML_DSA), CONSTINFO(XCP_CPB_ALG_ML_KEM), }; #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(STDLL_TokData_t *tokdata, cp_config_t * cp_config, CK_MECHANISM_TYPE mech, unsigned char *cp, size_t cp_len, size_t max_cp_index) { UNUSED(tokdata); 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(tokdata, 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(tokdata, mech)); return CKR_MECHANISM_INVALID; } mech_cfg = mech_cfg->next; } } cp_cfg = cp_cfg->next; } 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) { 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; } CK_BBOOL is_apqn_online(uint_32 card, uint_32 domain) { char fname[290]; char buf[250]; CK_RV rc; #ifdef EP11_HSMSIM return CK_TRUE; #endif sprintf(fname, "%s/card%02x/%02x.%04x/online", SYSFS_DEVICES_AP, card, card, domain); rc = file_fgets(fname, buf, sizeof(buf)); if (rc != CKR_OK) return CK_FALSE; if (strcmp(buf, "1") != 0) return CK_FALSE; sprintf(fname, "%s/card%02x/%02x.%04x/config", SYSFS_DEVICES_AP, card, card, domain); rc = file_fgets(fname, buf, sizeof(buf)); if (rc == CKR_OK && strcmp(buf, "1") != 0) return CK_FALSE; sprintf(fname, "%s/card%02x/%02x.%04x/chkstop", SYSFS_DEVICES_AP, card, card, domain); rc = file_fgets(fname, buf, sizeof(buf)); if (rc == CKR_OK && strcmp(buf, "0") != 0) return CK_FALSE; return CK_TRUE; } 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/config", SYSFS_DEVICES_AP, name); rc = file_fgets(fname, buf, sizeof(buf)); if (rc == CKR_OK && strcmp(buf, "1") != 0) return CKR_FUNCTION_FAILED; sprintf(fname, "%s%s/chkstop", SYSFS_DEVICES_AP, name); rc = file_fgets(fname, buf, sizeof(buf)); if (rc == CKR_OK && strcmp(buf, "0") != 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; } 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 or APQN_ALLOWLIST 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; CK_RV rc = 0; long len; 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, 0); if (rc != CKR_OK) return rc; memset(cmd, 0, sizeof(cmd)); len = dll_xcpa_queryblock(cmd, sizeof(cmd), XCP_ADMQ_DOM_CTRLPOINTS, (uint64_t) adapter << 32 | domain, NULL, 0); if (len < 0) { TRACE_ERROR("%s xcpa_queryblock failed: rc=%ld\n", __func__, len); rc = CKR_DEVICE_ERROR; goto out; } clen = len; memset(rsp, 0, sizeof(rsp)); rlen = sizeof(rsp); rc = dll_m_admin(rsp, &rlen, NULL, NULL, cmd, clen, NULL, 0, target); if (rc != CKR_OK) { TRACE_ERROR("%s m_admin rc=%ld\n", __func__, rc); goto out; } memset(&rb, 0, sizeof(rb)); len = dll_xcpa_internal_rv(rsp, rlen, &rb, &rc); if (len < 0 || rc != 0) { TRACE_ERROR("%s xcpa_internal_rv failed: rc=%ld len=%ld\n", __func__, rc, len); 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 { STDLL_TokData_t *tokdata; 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; CK_BBOOL error; CK_BBOOL allow_combined_extract; } 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; ep11_private_data_t *ep11_data = data->tokdata->private_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); TRACE_DEBUG("Max control point index: %lu\n", max_cp_index); #endif if (data->first) { data->first_adapter = adapter; data->first_domain = domain; /* Apply CP bits 0 to max_cp_index only */ for (i = 0; i <= max_cp_index; i++) { data->combined_cp[CP_BYTE_NO(i)] &= (cp[CP_BYTE_NO(i)] | ~CP_BIT_MASK(i)); } memcpy(data->first_cp, cp, sizeof(data->first_cp)); 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 <= max_cp_index; i++) { /* Apply CP bits 0 to max_cp_index only */ data->combined_cp[CP_BYTE_NO(i)] &= (cp[CP_BYTE_NO(i)] | ~CP_BIT_MASK(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); } } /* Combined extract is only supported if all APQNs support it */ if (max_cp_index < XCP_CPB_ALLOW_COMBINED_EXTRACT || (cp[CP_BYTE_NO(XCP_CPB_ALLOW_COMBINED_EXTRACT)] & CP_BIT_MASK(XCP_CPB_ALLOW_COMBINED_EXTRACT)) == 0) { data->allow_combined_extract = CK_FALSE; if (ep11_data->pkey_mode == PKEY_MODE_ENABLE4EXTR || ep11_data->pkey_mode == PKEY_MODE_ENABLE4ALL) { TRACE_ERROR("Control point setting for adapter %02X.%04X does not " "allow combined extract, but PKEY_MODE ENABLE4EXTR or " "ENABLE4ALL specified in ep11 token config file.\n", adapter, domain); OCK_SYSLOG(LOG_ERR, "Control point setting for adapter %02X.%04X does not " "allow combined extract, but PKEY_MODE ENABLE4EXTR or " "ENABLE4ALL specified in ep11 token config file.\n", adapter, domain); data->error = TRUE; } } /* Check FIPS-session related CPs for non-FIPS-session mode */ if (!ep11_data->fips_session_mode) { if (max_cp_index >= XCP_CPB_ALLOW_NONSESSION && (cp[CP_BYTE_NO(XCP_CPB_ALLOW_NONSESSION)] & CP_BIT_MASK(XCP_CPB_ALLOW_NONSESSION)) == 0) { TRACE_WARNING("%s Adapter %02X.%04X has control point " "XCP_CPB_ALLOW_NONSESSION off, but FIPS-session mode " "is not enabled\n", __func__, adapter, domain); OCK_SYSLOG(LOG_ERR, "Adapter %02X.%04X has control point " "XCP_CPB_ALLOW_NONSESSION off, but FIPS-session mode " "is not enabled\n", adapter, domain); data->error = TRUE; } if (max_cp_index >= XCP_CPB_ALLOW_LOGIN_PRE_F2021 && (cp[CP_BYTE_NO(XCP_CPB_ALLOW_LOGIN_PRE_F2021)] & CP_BIT_MASK(XCP_CPB_ALLOW_LOGIN_PRE_F2021)) == 0) { TRACE_WARNING("%s Adapter %02X.%04X has control point " "XCP_CPB_ALLOW_LOGIN_PRE_F2021 off, but FIPS-session " "mode is not enabled\n", __func__, adapter, domain); OCK_SYSLOG(LOG_ERR, "Adapter %02X.%04X has control point " "XCP_CPB_ALLOW_LOGIN_PRE_F2021 off, but FIPS-session " "mode is not enabled\n", adapter, domain); data->error = TRUE; } } 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.tokdata = tokdata; /* * Turn all CPs ON by default, so that newer control points that are unknown * to older cards default to ON. CPs being OFF disable functionality. */ memset(data.combined_cp, 0xff, sizeof(data.combined_cp)); data.allow_combined_extract = CK_TRUE; 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); TRACE_DEBUG("Max control point index: %lu\n", data.max_cp_index); print_control_points(cp, *cp_len, data.max_cp_index); #endif if (data.allow_combined_extract == CK_FALSE) __sync_or_and_fetch(&ep11_data->pkey_combined_extract_supported, 0); else __sync_or_and_fetch(&ep11_data->pkey_combined_extract_supported, 1); return data.error ? CKR_DEVICE_ERROR : CKR_OK; } 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; } static CK_RV check_apqn_for_fips_session_mode(uint_32 adapter, uint_32 domain, target_t target) { CK_BYTE func_bit_mask[16] = { 0 }; CK_ULONG func_bit_mask_len = sizeof(func_bit_mask); uint32_t *res = NULL; CK_ULONG reslen = 0; CK_ULONG i; uint32_t caps = 0; CK_BBOOL alg_found = FALSE, ktype_found = FALSE; CK_RV rc; /* Check if module supports Login/LogoutExtended */ rc = dll_m_get_xcp_info(&func_bit_mask, &func_bit_mask_len, CK_IBM_XCPQ_MODULE, CK_IBM_XCPMSQ_FNLIST, target); if (rc != CKR_OK) { TRACE_ERROR("%s Failed to query function list from adapter %02X.%04X\n", __func__, adapter, domain); /* card may no longer be online, so ignore this error situation */ return CKR_OK; } TRACE_DEBUG("Function bitmask of %02X.%04X:\n", adapter, domain); TRACE_DEBUG_DUMP("", func_bit_mask, func_bit_mask_len); if (func_bit_mask_len <= (__FNID_LoginExtended / 8) || (func_bit_mask[__FNID_LoginExtended / 8] & (0x80 >> (__FNID_LoginExtended % 8))) == 0 || (func_bit_mask[__FNID_LogoutExtended / 8] & (0x80 >> (__FNID_LogoutExtended % 8))) == 0) { TRACE_ERROR("%s Adapter %02X.%04X does not support LoginExtended " "or LogoutExtended but this is required by " "FIPS-session mode\n", __func__, adapter, domain); OCK_SYSLOG(LOG_ERR, "Adapter %02X.%04X does not support LoginExtended " "or LogoutExtended but this is required by " "FIPS-session mode\n", adapter, domain); return CKR_DEVICE_ERROR; } /* Check extended capabilities for Login Algorithm and importer key type */ reslen = sizeof(caps); rc = dll_m_get_xcp_info(&caps, &reslen, CK_IBM_XCPQ_EXT_CAPS, 0, target); if (rc != CKR_OK || reslen != sizeof(caps)) { TRACE_ERROR("%s Failed to query extended capabilities from adapter %02X.%04X\n", __func__, adapter, domain); return CKR_DEVICE_ERROR; } reslen = caps * sizeof(uint32_t) * 2; res = calloc(1, reslen); if (res == NULL) { TRACE_ERROR("%s Memory allocation failed\n", __func__); return CKR_HOST_MEMORY; } rc = dll_m_get_xcp_info(res, &reslen, CK_IBM_XCPQ_EXT_CAPLIST, 0, target); if (rc != CKR_OK) { TRACE_ERROR("%s Failed to query extended capabilities from adapter %02X.%04X\n", __func__, adapter, domain); rc = CKR_DEVICE_ERROR; goto out; } for (i = 0; i < reslen / 4; i += 2) { switch (res[i]) { case CK_IBM_XCPXQ_LOGIN_ALG: if (res[i + 1] & (0x80000000 >> XCP_LOGIN_ALG_F2021)) alg_found = TRUE; break; case CK_IBM_XCPXQ_LOGIN_KEYTYPES: if (res[i + 1] & (0x80000000 >> XCP_LOGIN_IMPR_EC_P521)) ktype_found = TRUE; break; } } if (!alg_found) { TRACE_ERROR("%s Adapter %02X.%04X does not support the FIPS " "login algorithm but this is required by " "FIPS-session mode\n", __func__, adapter, domain); OCK_SYSLOG(LOG_ERR, "Adapter %02X.%04X does not support the FIPS " "login algorithm but this is required by " "FIPS-session mode\n", adapter, domain); rc = CKR_DEVICE_ERROR; } if (!ktype_found) { TRACE_ERROR("%s Adapter %02X.%04X does not support the P521 " "login importer key type but this is required by " "FIPS-session mode\n", __func__, adapter, domain); OCK_SYSLOG(LOG_ERR, "Adapter %02X.%04X does not support the P521 " "login importer key type but this is required by " "FIPS-session mode\n", adapter, domain); rc = CKR_DEVICE_ERROR; } out: free(res); return rc; } typedef struct query_version { STDLL_TokData_t *tokdata; ep11_target_info_t *target_info; CK_CHAR serialNumber[16]; CK_BBOOL first; CK_BBOOL error; CK_BYTE pqc_strength[PQC_BYTES]; } 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; ep11_private_data_t *ep11_data = qv->tokdata->private_data; CK_IBM_XCP_INFO xcp_info; CK_ULONG xcp_info_len = sizeof(xcp_info); CK_BYTE pqc_strength[PQC_BYTES] = { 0 }; CK_ULONG pqc_strength_len = sizeof(pqc_strength); CK_RV rc; target_t target; CK_ULONG card_type, i; ep11_card_version_t *card_version; rc = get_ep11_target_for_apqn(adapter, domain, &target, 0); 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->target_info->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; #ifdef EP11_HSMSIM #ifdef EP11_HSMSIM_FW_API card_version->firmware_API_version = EP11_HSMSIM_FW_API; #else card_version->firmware_API_version = xcp_info.firmwareApi; #endif #else card_version->firmware_API_version = xcp_info.firmwareApi; #endif #ifdef EP11_HSMSIM #ifdef EP11_HSMSIM_FW_VER_MAJOR card_version->firmware_version.major = EP11_HSMSIM_FW_VER_MAJOR; #ifdef EP11_HSMSIM_FW_VER_MINOR card_version->firmware_version.minor = EP11_HSMSIM_FW_VER_MINOR; #else card_version->firmware_version.minor = 0; #endif #else card_version->firmware_version = xcp_info.firmwareVersion; #endif #else card_version->firmware_version = xcp_info.firmwareVersion; #endif card_version->next = qv->target_info->card_versions; qv->target_info->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; } 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; } } if (qv->first) memcpy(qv->serialNumber, xcp_info.serialNumber, sizeof(qv->serialNumber)); /* Query for PQC strength support. If the PQC strength query is not available only Dilithium 6-5 round 2 is available. */ rc = dll_m_get_xcp_info(&pqc_strength, &pqc_strength_len, CK_IBM_XCPQ_PQC_STRENGTHS, 0, target); if (rc != CKR_OK) { TRACE_DEVEL("%s Failed to query PQC-strength from adapter %02X.%04X\n", __func__, adapter, domain); /* Only R2_65 is available */ pqc_strength[PQC_BYTE_NO(XCP_PQC_S_DILITHIUM_R2_65)] |= PQC_BIT_MASK(XCP_PQC_S_DILITHIUM_R2_65); rc = CKR_OK; } TRACE_DEBUG("PQC-strength of %02X.%04X:\n", adapter, domain); TRACE_DEBUG_DUMP("", pqc_strength, sizeof(qv->pqc_strength)); if (qv->first) { memcpy(qv->pqc_strength, pqc_strength, sizeof(qv->pqc_strength)); } else { for (i = 0; i < sizeof(qv->pqc_strength); i++) qv->pqc_strength[i] &= pqc_strength[i]; } qv->first = FALSE; if (ep11_data->fips_session_mode) { rc = check_apqn_for_fips_session_mode(adapter, domain, target); if (rc != CKR_OK) { qv->error = TRUE; rc = CKR_OK; } } 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; } #ifdef EP11_HSMSIM #ifdef EP11_HSMSIM_HOSTLIB_VER_MAJOR host_version &= 0x0000FFFF; host_version |= (EP11_HSMSIM_HOSTLIB_VER_MAJOR << 16); #endif #ifdef EP11_HSMSIM_HOSTLIB_VER_MINOR host_version &= 0xFFFF0000; host_version |= (EP11_HSMSIM_HOSTLIB_VER_MINOR << 8); #endif #endif TRACE_DEVEL("%s host_version=0x08%x\n", __func__, host_version); lib_version->major = (host_version & 0x00FF0000) >> 16; /* Minor is 4 bits release number and 4 bits modification level */ lib_version->minor = (host_version & 0x00000F00) >> 4 | (host_version & 0x0000000F); if ((host_version & 0x0000F000) != 0) { lib_version->minor |= 0xF0; TRACE_DEVEL("%s relelase > 15, treating as 15\n", __func__); } if ((host_version & 0x000000F0) != 0) { lib_version->minor |= 0x0F; TRACE_DEVEL("%s modification level > 15, treating as 15\n", __func__); } /* * 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_target_info_t *target_info) { ep11_private_data_t *ep11_data = tokdata->private_data; ep11_card_version_t *card_version; query_version_t qv; CK_ULONG i; CK_RV rc; memset(&qv, 0, sizeof(qv)); qv.tokdata = tokdata; qv.target_info = target_info; 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(target_info->serialNumber, qv.serialNumber, sizeof(target_info->serialNumber)); TRACE_INFO("%s Serial number: %.16s\n", __func__, target_info->serialNumber); /* EP11 host lib version <= 2 only support API version 2 */ if (ep11_data->ep11_lib_version.major <= 2) target_info->used_firmware_API_version = 2; else target_info->used_firmware_API_version = 0; card_version = target_info->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 (target_info->used_firmware_API_version == 0) target_info->used_firmware_API_version = card_version->firmware_API_version; else target_info->used_firmware_API_version = MIN(target_info->used_firmware_API_version, card_version->firmware_API_version); card_version = card_version->next; } TRACE_INFO("%s Used Firmware API: %lu\n", __func__, target_info->used_firmware_API_version); memcpy(target_info->pqc_strength, qv.pqc_strength, sizeof(qv.pqc_strength)); TRACE_INFO("Combined PQC-strength:\n"); for (i = 1; i <= XCP_PQC_MAX; i++) { TRACE_INFO(" Strength %lu: %d\n", i, (qv.pqc_strength[PQC_BYTE_NO(i)] & PQC_BIT_MASK(i)) != 0); } 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; } } typedef struct query_wkvp { ep11_private_data_t *ep11_data; ep11_target_info_t *target_info; CK_BBOOL error; } query_wkvp_t; const unsigned char ep11_zero_mkvp[XCP_WKID_BYTES] = { 0 }; static CK_RV wkvp_query_handler(uint_32 adapter, uint_32 domain, void *handler_data) { query_wkvp_t *qw = (query_wkvp_t *)handler_data; CK_IBM_DOMAIN_INFO domain_info; CK_ULONG domain_info_len = sizeof(domain_info); CK_RV rc; target_t target; /* * If an MK change operation is active, the current APQN must be part * of the operation, even if it is offline (this only applies to an * APQN_ALLOWLIST configuration, for a APQN_ANY configuration, we will only * be called for currently online APQNs anyway). */ if (qw->ep11_data->mk_change_active && !hsm_mk_change_apqns_find(qw->ep11_data->mk_change_apqns, qw->ep11_data->num_mk_change_apqns, adapter, domain)) { TRACE_ERROR("APQN %02X.%04X is used by the EP11 token, but it is " "not part of the active MK change operation '%s'\n", adapter, domain, qw->ep11_data->mk_change_op); OCK_SYSLOG(LOG_ERR, "APQN %02X.%04X is used by the EP11 token, but " "it is not part of the active MK change operation '%s'\n", adapter, domain, qw->ep11_data->mk_change_op); qw->error = TRUE; return CKR_OK; } rc = get_ep11_target_for_apqn(adapter, domain, &target, 0); if (rc != CKR_OK) return rc; rc = dll_m_get_xcp_info(&domain_info, &domain_info_len, CK_IBM_XCPQ_DOMAIN, 0, target); if (rc != CKR_OK) { TRACE_ERROR("%s Failed to query domain info from APQN %02X.%04X\n", __func__, adapter, domain); /* card may no longer be online, so ignore this error situation */ rc = CKR_OK; goto out; } if ((domain_info.flags & CK_IBM_DOM_CURR_WK) == 0) { TRACE_ERROR("%s No EP11 wrapping key is set on APQN %02X.%04X\n", __func__, adapter, domain); OCK_SYSLOG(LOG_ERR, "%s No EP11 wrapping key is set on APQN %02X.%04X\n", __func__, adapter, domain); qw->error = TRUE; rc = CKR_OK; goto out; } TRACE_DEBUG("%s WKVP of APQN %02X.%04X:\n", __func__, adapter, domain); TRACE_DEBUG_DUMP("full WKVP: ", domain_info.wk, sizeof(domain_info.wk)); if ((domain_info.flags & CK_IBM_DOM_COMMITTED_NWK) != 0) { TRACE_DEBUG_DUMP("New WKVP: ", domain_info.nextwk, sizeof(domain_info.nextwk)); /* New WK must be the expected new WK if a MK change op is ongoing */ if (qw->ep11_data->mk_change_active && memcmp(domain_info.nextwk, qw->ep11_data->new_wkvp, XCP_WKID_BYTES) != 0) { TRACE_ERROR("New EP11 wrapping key on APQN %02X.%04X does not " "match the expected wrapping key of the active MK " "change operation '%s'\n", adapter, domain, qw->ep11_data->mk_change_op); OCK_SYSLOG(LOG_ERR, "New EP11 wrapping key on APQN %02X.%04X does " "not match the expected wrapping key of the active " "HSM MK change operation '%s'\n", adapter, domain, qw->ep11_data->mk_change_op); qw->error = TRUE; rc = CKR_OK; goto out; } } else { /* * No new WK loaded: current WK must be the expected new WK if a MK * change op is ongoing */ if (qw->ep11_data->mk_change_active && memcmp(domain_info.wk, qw->ep11_data->new_wkvp, XCP_WKID_BYTES) != 0) { TRACE_ERROR("Current EP11 wrapping key on APQN %02X.%04X does not " "match the expected new wrapping key of the active MK " "change operation '%s'\n", adapter, domain, qw->ep11_data->mk_change_op); OCK_SYSLOG(LOG_ERR, "Current EP11 wrapping key on APQN %02X.%04X " "does not match the expected new wrapping key of the " "active HSM MK change operation '%s'\n", adapter, domain, qw->ep11_data->mk_change_op); /* * Report error only if not within the pkcshsm_mk_change tool * process. Otherwise the MK change operation could not be canceled * when the new WK register has already been cleared by HSM admin. */ if (strcmp(program_invocation_short_name, "pkcshsm_mk_change") != 0) { qw->error = TRUE; rc = CKR_OK; goto out; } } } /* * If an MK change operation is pending, the current WK may already * be the new WK of the operation. */ if (qw->ep11_data->mk_change_active && memcmp(domain_info.wk, qw->ep11_data->new_wkvp, XCP_WKID_BYTES) == 0) { TRACE_DEBUG("%s APQN %02X.%04X already has the new WK\n", __func__, adapter, domain); rc = CKR_OK; goto out; } if (qw->ep11_data->expected_wkvp_set == FALSE && memcmp(qw->ep11_data->expected_wkvp, ep11_zero_mkvp, XCP_WKID_BYTES) == 0) { /* zero expected MKVP, copy current one */ memcpy(qw->ep11_data->expected_wkvp, domain_info.wk, XCP_WKID_BYTES); } else { if (memcmp(domain_info.wk, qw->ep11_data->expected_wkvp, XCP_WKID_BYTES) != 0) { TRACE_ERROR("EP11 wrapping key on APQN %02X.%04X does not " "match the %s wrapping key\n", adapter, domain, qw->ep11_data->expected_wkvp_set ? "expected" : "other APQN's"); OCK_SYSLOG(LOG_ERR, "EP11 wrapping key on APQN %02X.%04X does not " "match the %s wrapping key\n", adapter, domain, qw->ep11_data->expected_wkvp_set ? "expected" : "other APQN's"); qw->error = TRUE; rc = CKR_OK; goto out; } } out: free_ep11_target_for_apqn(target); return rc; } static CK_RV ep11tok_check_wkvps(STDLL_TokData_t *tokdata, ep11_target_info_t *target_info) { ep11_private_data_t *ep11_data = tokdata->private_data; query_wkvp_t qw; CK_RV rc; memset(&qw, 0, sizeof(qw)); qw.ep11_data = ep11_data; qw.target_info = target_info; rc = handle_all_ep11_cards(&ep11_data->target_list, wkvp_query_handler, &qw); if (rc != CKR_OK) { TRACE_ERROR("%s handle_all_ep11_cards failed: rc=0x%lx\n", __func__, rc); return rc; } if (qw.error) { TRACE_ERROR("%s Errors occurred during WKVP query\n", __func__); return CKR_DEVICE_ERROR; } if (ep11_data->expected_wkvp_set == FALSE) { /* * If a MK change operation is active, and all APQNs have the new WK * already, use the new WK as the queried one. */ if (ep11_data->mk_change_active && memcmp(ep11_data->expected_wkvp, ep11_zero_mkvp, XCP_WKID_BYTES) == 0) { TRACE_DEBUG("%s All APQNs already have the new WK\n",__func__); memcpy(ep11_data->expected_wkvp, ep11_data->new_wkvp, XCP_WKID_BYTES); } TRACE_DEBUG_DUMP("WKVP (queried): ", ep11_data->expected_wkvp, XCP_WKID_BYTES); } else { TRACE_DEBUG_DUMP("WKVP (config): ", ep11_data->expected_wkvp, XCP_WKID_BYTES); } return CKR_OK; } CK_RV token_specific_get_token_info(STDLL_TokData_t *tokdata, CK_TOKEN_INFO_PTR pInfo) { ep11_private_data_t *ep11_data = tokdata->private_data; ep11_target_info_t* target_info; target_info = get_target_info(tokdata); if (target_info == NULL) return CKR_FUNCTION_FAILED; /* * report the EP11 firmware version as hardware version, and * the EP11 host library version as firmware version */ if (target_info->card_versions != NULL) pInfo->hardwareVersion = target_info->card_versions->firmware_version; pInfo->firmwareVersion = ep11_data->ep11_lib_version; pInfo->firmwareVersion.minor >>= 4; /* report release, skip mod-level */ memcpy(pInfo->serialNumber, target_info->serialNumber, sizeof(pInfo->serialNumber)); put_target_info(tokdata, target_info); return CKR_OK; } /** * 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) { 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; ep11_target_info_t* target_info; int status; target_info = get_target_info(tokdata); if (target_info == NULL) return CKR_FUNCTION_FAILED; for (i = 0; i < num_req; i++) { status = check_card_version(tokdata, req[i].card_type, req[i].apply_to_firmware_version_only, 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 = target_info->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 = target_info->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. */ status = 1; if (req_not_fullfilled == CK_TRUE) status = -1; goto out; } 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. */ status = 0; if (req_fullfilled == CK_TRUE) status = -1; goto out; } else { /* All of the cards that are present fulfill the requirements */ status = 1; goto out; } out: put_target_info(tokdata, target_info); return status; } /** * 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, CK_ULONG apply_to_firmware_version_only, 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; ep11_target_info_t* target_info; int status = 1; 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; } } target_info = get_target_info(tokdata); if (target_info == NULL) return -1; card_version = target_info->card_versions; while (card_version != NULL) { if (card_version->card_type == card_type && (apply_to_firmware_version_only == 0 || apply_to_firmware_version_only == card_version->firmware_version.major)) break; card_version = card_version->next; } if (card_version == NULL) { status = -1; goto out; } 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__); status = 0; goto out; } } 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__); status = 0; goto out; } } out: put_target_info(tokdata, target_info); return status; } static CK_RV ep11tok_setup_target(STDLL_TokData_t *tokdata, ep11_target_info_t *target_info) { ep11_private_data_t *ep11_data = tokdata->private_data; struct XCP_Module module; CK_RV rc = CKR_OK; 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 (target_info->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; } target_info->target = (target_t)&ep11_data->target_list; return CKR_OK; } if (target_info->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; } target_info->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 = target_info->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, &target_info->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, &target_info->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); dll_m_rm_module(NULL, target_info->target); return CKR_FUNCTION_FAILED; } } return CKR_OK; } CK_RV get_ep11_target_for_apqn(uint_32 adapter, uint_32 domain, target_t *target, uint64_t flags) { 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 | flags; 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; } 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); } } struct single_target_data { ep11_private_data_t *ep11_data; int found; int new_wk_found; uint_32 adapter; uint_32 domain; }; static CK_RV setup_single_target_handler(uint_32 adapter, uint_32 domain, void *handler_data) { struct single_target_data *std = (struct single_target_data *)handler_data; CK_IBM_DOMAIN_INFO domain_info; CK_ULONG domain_info_len = sizeof(domain_info); CK_RV rc; target_t target; int target_allocated = 0; if (!std->new_wk_found) { /* Check if this APQN has the new WK loaded */ rc = get_ep11_target_for_apqn(adapter, domain, &target, 0); if (rc != CKR_OK) return rc; target_allocated = 1; rc = dll_m_get_xcp_info(&domain_info, &domain_info_len, CK_IBM_XCPQ_DOMAIN, 0, target); if (rc != CKR_OK) { TRACE_ERROR("%s Failed to query domain info from APQN %02X.%04X\n", __func__, adapter, domain); /* card may no longer be online, so ignore this error situation */ goto out; } if ((domain_info.flags & CK_IBM_DOM_CURR_WK) == 0) { TRACE_ERROR("%s No EP11 wrapping key is set on APQN %02X.%04X\n", __func__, adapter, domain); goto out; } if (memcmp(domain_info.wk, std->ep11_data->new_wkvp, XCP_WKID_BYTES) == 0) { std->adapter = adapter; std->domain = domain; std->new_wk_found = 1; std->found = 1; TRACE_DEVEL("%s Select APQN %02X.%04X with new WK set\n", __func__, adapter, domain); } } if (!std->found && !std->new_wk_found) { std->adapter = adapter; std->domain = domain; std->found = 1; TRACE_DEVEL("%s Select APQN %02X.%04X\n", __func__, adapter, domain); } out: if (target_allocated) free_ep11_target_for_apqn(target); return CKR_OK; } static CK_RV ep11tok_setup_single_target(STDLL_TokData_t *tokdata, ep11_target_info_t *target_info, CK_BBOOL wait_for_new_wk) { ep11_private_data_t *ep11_data = tokdata->private_data; struct single_target_data std; CK_RV rc; int retries = 0; retry: memset(&std, 0, sizeof(std)); std.ep11_data = ep11_data; /* Search for an online APQN that preferably has the new WK set already */ rc = handle_all_ep11_cards(&ep11_data->target_list, setup_single_target_handler, &std); if (rc != CKR_OK) { TRACE_ERROR("%s handle_all_ep11_cards failed: rc=0x%lx\n", __func__, rc); return rc; } if (!std.found) { TRACE_ERROR("%s no online APQN found\n",__func__); return CKR_DEVICE_ERROR;; } if (wait_for_new_wk && !std.new_wk_found) { TRACE_DEVEL("%s no APQN with new MK set found, retry in 1 second\n", __func__); retries++; if (retries > 3600) /* Retry for max 1 hour */ return CKR_DEVICE_ERROR; sleep(1); goto retry; } rc = get_ep11_target_for_apqn(std.adapter, std.domain, &target_info->target, 0); if (rc != CKR_OK) return rc; target_info->single_apqn = 1; target_info->adapter = std.adapter; target_info->domain = std.domain; target_info->single_apqn_has_new_wk = std.new_wk_found; OCK_SYSLOG(LOG_INFO, "Slot %lu: A concurrent HSM master key change " "operation (%s) is active, EP11 token uses a single APQN: " "%02X.%04X\n", tokdata->slot_id, ep11_data->mk_change_op, std.adapter, std.domain); return CKR_OK; } /** * This function is called when the attributes of a key object are changed, or * if the object is copied by means of C_CopyObject. In case attributes * CKA_TOKEN and/or CKA_PRIVATE are changed (only allowed during C_CopyObject), * special checking is required in regards of session bound keys. * In case strict session mode, VHSM mode or FIPS session mode is active, * the changed attributes may cause the key object to be expected to be bound * to a different EP11 session as it currently is. Check if the key object * is bound to the expected session, and fail if not. */ CK_RV ep11tok_set_attrs_check_session(STDLL_TokData_t *tokdata, SESSION *session, OBJECT* obj, TEMPLATE *new_tmpl) { ep11_session_t *ep11_session = (ep11_session_t *)session->private_data; unsigned char *cur_ep11_pin_blob = NULL; CK_ULONG cur_ep11_pin_blob_len = 0; unsigned char *new_ep11_pin_blob = NULL; CK_ULONG new_ep11_pin_blob_len = 0; CK_BBOOL cur_token, cur_private, new_token, new_private; CK_RV rc; cur_token = !object_is_session_object(obj); cur_private = object_is_private(obj); new_token = cur_token; rc = template_attribute_get_bool(new_tmpl, CKA_TOKEN, &new_token); if (rc != CKR_OK && rc != CKR_TEMPLATE_INCOMPLETE) return rc; new_private = cur_private; rc = template_attribute_get_bool(new_tmpl, CKA_PRIVATE, &new_private); if (rc != CKR_OK && rc != CKR_TEMPLATE_INCOMPLETE) return rc; if (cur_token == new_token && cur_private == new_private) return CKR_OK; /* CKA_TOKEN and/or CKA_PRIVATE is changed, check the session */ ep11_get_pin_blob(tokdata, ep11_session, !cur_token, cur_private, &cur_ep11_pin_blob, &cur_ep11_pin_blob_len); ep11_get_pin_blob(tokdata, ep11_session, !new_token, new_private, &new_ep11_pin_blob, &new_ep11_pin_blob_len); if (new_ep11_pin_blob != cur_ep11_pin_blob) { TRACE_ERROR("Attribute change would cause the key to be bound to a " "different session. Change is rejected\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } return CKR_OK; } CK_RV token_specific_set_attribute_values(STDLL_TokData_t *tokdata, SESSION *session, OBJECT *obj, TEMPLATE *new_tmpl) { ep11_private_data_t *ep11_data = tokdata->private_data; CK_OBJECT_CLASS class; CK_KEY_TYPE ktype; size_t keyblobsize = 0, reencblobsize = 0; CK_BYTE *keyblob, *reencblob = NULL; DL_NODE *node; CK_ATTRIBUTE *ibm_opaque_attr = NULL, *ibm_opaque_reenc_attr = NULL; CK_ATTRIBUTE_PTR attributes = NULL; CK_ULONG num_attributes = 0; CK_ATTRIBUTE *attr; struct endecap_combine_attrs_data combine_attr_data = { 0 }; CK_MECHANISM tmp_mech = { (CK_MECHANISM_TYPE)-1, NULL, 0 }; CK_RV rc; rc = template_attribute_get_ulong(obj->template, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("%s CKA_CLASS is missing\n", __func__); return rc; } switch (class) { case CKO_SECRET_KEY: case CKO_PRIVATE_KEY: case CKO_PUBLIC_KEY: break; default: /* Not a key, nothing to do */ return CKR_OK; } rc = template_attribute_get_ulong(obj->template, CKA_KEY_TYPE, &ktype); if (rc != CKR_OK) { TRACE_ERROR("%s CKA_KEY_TYPE is missing\n", __func__); return rc; } rc = obj_opaque_2_blob(tokdata, obj, &keyblob, &keyblobsize); if (rc != CKR_OK) { TRACE_ERROR("%s no key-blob rc=0x%lx\n", __func__, rc); return rc; } if (ep11_data->mk_change_active) { rc = obj_opaque_2_reenc_blob(tokdata, obj, &reencblob, &reencblobsize); if (rc == CKR_TEMPLATE_INCOMPLETE) { TRACE_DEVEL("%s no reenc key-blob, use old key-blob\n", __func__); reencblob = keyblob; reencblobsize = keyblobsize; rc = CKR_OK; } if (rc != CKR_OK) { TRACE_ERROR("%s failed to get reenc key-blob rc=0x%lx\n", __func__, rc); return rc; } } rc = ep11tok_set_attrs_check_session(tokdata, session, obj, new_tmpl); if (rc != CKR_OK) { TRACE_ERROR("%s ep11tok_set_attrs_check_session rc=0x%lx\n", __func__, rc); return rc; } #ifndef NO_PKEY /* Ensure the firmware master key verification pattern is available */ rc = ep11tok_pkey_get_firmware_mk_vp(tokdata, session); if (rc != CKR_OK && rc != CKR_FUNCTION_NOT_SUPPORTED) return rc; #endif /* NO_PKEY */ template_attribute_get_bool(obj->template, CKA_WRAP, &combine_attr_data.wrap); template_attribute_get_bool(obj->template, CKA_UNWRAP, &combine_attr_data.unwrap); template_attribute_get_bool(obj->template, CKA_DERIVE, &combine_attr_data.derive); node = new_tmpl->attribute_list; while (node) { attr = (CK_ATTRIBUTE *)node->data; rc = ep11tok_endecaps_combine_attrs_collect(attr, &combine_attr_data); if (rc == CKR_OK) goto next; /* EP11 can set certain boolean attributes only */ switch (attr->type) { case CKA_VERIFY: case CKA_VERIFY_RECOVER: case CKA_ENCRYPT: /* Can not restrict public key for verify and encrypt */ if (class == CKO_PUBLIC_KEY) break; /* Fallthrough */ case CKA_EXTRACTABLE: case CKA_MODIFIABLE: case CKA_SIGN: case CKA_SIGN_RECOVER: case CKA_DECRYPT: case CKA_WRAP_WITH_TRUSTED: case CKA_TRUSTED: case CKA_IBM_RESTRICTABLE: case CKA_IBM_USE_AS_DATA: rc = add_to_attribute_array(&attributes, &num_attributes, attr->type, attr->pValue, attr->ulValueLen); if (rc != CKR_OK) { TRACE_ERROR("%s add_to_attribute_array failed rc=0x%lx\n", __func__, rc); goto out; } break; #ifndef NO_PKEY case CKA_IBM_PROTKEY_EXTRACTABLE: if (ep11_data->pkey_wrap_supported) { rc = add_to_attribute_array(&attributes, &num_attributes, attr->type, attr->pValue, attr->ulValueLen); if (rc != CKR_OK) { TRACE_ERROR("%s add_to_attribute_array failed rc=0x%lx\n", __func__, rc); goto out; } } break; #endif /* NO_PKEY */ default: /* Either non-boolean, or read-only */ break; } next: node = node->next; } rc = ep11tok_endecaps_combine_attrs_apply(tokdata, class, ktype, -1, &tmp_mech, &attributes, &num_attributes, &combine_attr_data); if (rc != CKR_OK) { TRACE_ERROR("ep11tok_endecaps_combine_attrs_apply failed: 0x%lx\n", rc); return rc; } if (attributes != NULL && num_attributes > 0) { rc = build_attribute(CKA_IBM_OPAQUE, keyblob, keyblobsize, &ibm_opaque_attr); if (rc != CKR_OK) { TRACE_ERROR("%s build_attribute failed rc=0x%lx\n", __func__, rc); goto out; } if (reencblob != NULL) { rc = build_attribute(CKA_IBM_OPAQUE_REENC, reencblob, reencblobsize, &ibm_opaque_reenc_attr); if (rc != CKR_OK) { TRACE_ERROR("%s build_attribute failed rc=0x%lx\n", __func__, rc); goto out; } } RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_UPDATE_BLOB_START(tokdata, target_info, ibm_opaque_attr->pValue, ktype != CKK_AES_XTS ? ibm_opaque_attr->ulValueLen : ibm_opaque_attr->ulValueLen / 2, ibm_opaque_reenc_attr != NULL ? ibm_opaque_reenc_attr->pValue : NULL, ibm_opaque_reenc_attr != NULL ? (ktype != CKK_AES_XTS ? ibm_opaque_reenc_attr->ulValueLen : ibm_opaque_reenc_attr->ulValueLen / 2) : 0, keyblob, keyblobsize); rc = dll_m_SetAttributeValue(keyblob, keyblobsize, attributes, num_attributes, target_info->target); RETRY_UPDATE_BLOB_END(tokdata, session, target_info, ibm_opaque_attr->pValue, ktype != CKK_AES_XTS ? ibm_opaque_attr->ulValueLen : ibm_opaque_attr->ulValueLen / 2, ibm_opaque_reenc_attr != NULL ? ibm_opaque_reenc_attr->pValue : NULL, ibm_opaque_reenc_attr != NULL ? (ktype != CKK_AES_XTS ? ibm_opaque_reenc_attr->ulValueLen : ibm_opaque_reenc_attr->ulValueLen / 2) : 0, keyblob, keyblobsize, rc); RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, NULL); TRACE_ERROR("%s m_SetAttributeValue failed rc=0x%lx\n", __func__, rc); goto out; } if (ktype == CKK_AES_XTS) { RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_UPDATE_BLOB_START(tokdata, target_info, (CK_BYTE *)ibm_opaque_attr->pValue + (ibm_opaque_attr->ulValueLen / 2), ibm_opaque_attr->ulValueLen / 2, ibm_opaque_reenc_attr != NULL ? (CK_BYTE *)ibm_opaque_reenc_attr->pValue + (ibm_opaque_reenc_attr->ulValueLen / 2) : NULL, ibm_opaque_reenc_attr != NULL ? ibm_opaque_reenc_attr->ulValueLen / 2 : 0, keyblob, keyblobsize); rc = dll_m_SetAttributeValue(keyblob, keyblobsize, attributes, num_attributes, target_info->target); RETRY_UPDATE_BLOB_END(tokdata, session, target_info, (CK_BYTE *)ibm_opaque_attr->pValue + (ibm_opaque_attr->ulValueLen / 2), ibm_opaque_attr->ulValueLen / 2, ibm_opaque_reenc_attr != NULL ? (CK_BYTE *)ibm_opaque_reenc_attr->pValue + (ibm_opaque_reenc_attr->ulValueLen / 2) : NULL, ibm_opaque_reenc_attr != NULL ? ibm_opaque_reenc_attr->ulValueLen / 2 : 0, keyblob, keyblobsize, rc); RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, NULL); TRACE_ERROR("%s m_SetAttributeValue failed rc=0x%lx\n", __func__, rc); goto out; } } rc = template_update_attribute(new_tmpl, ibm_opaque_attr); if (rc != CKR_OK) { TRACE_ERROR("%s template_update_attribute failed rc=0x%lx\n", __func__, rc); goto out; } ibm_opaque_attr = NULL; if (ibm_opaque_reenc_attr != NULL) { rc = template_update_attribute(new_tmpl, ibm_opaque_reenc_attr); if (rc != CKR_OK) { TRACE_ERROR("%s template_update_attribute failed rc=0x%lx\n", __func__, rc); goto out; } ibm_opaque_reenc_attr = NULL; } } out: if (attributes) free_attribute_array(attributes, num_attributes); if (ibm_opaque_attr != NULL) free(ibm_opaque_attr); if (ibm_opaque_reenc_attr != NULL) free(ibm_opaque_reenc_attr); return rc; } /* * ATTENTION: This function is called in a separate thread. All actions * performed by this function must be thread save and use locks to lock * against concurrent access by other threads. */ static CK_RV ep11tok_handle_apqn_event(STDLL_TokData_t *tokdata, unsigned int event_type, event_udev_apqn_data_t *apqn_data) { ep11_private_data_t *ep11_data = tokdata->private_data; CK_BBOOL found = FALSE; CK_RV rc = CKR_OK; char name[20]; int i; /* Is it one of the configured APQNs ?*/ if (ep11_data->target_list.length > 0) { /* APQN_WHITELIST or APQN_ALLOWLIST is specified */ for (i = 0; i < ep11_data->target_list.length; i++) { if (ep11_data->target_list.apqns[2 * i] == apqn_data->card && ep11_data->target_list.apqns[2 * i + 1] == apqn_data->domain) { found = TRUE; break; } } } else { /* APQN_ANY is specified */ found = TRUE; if (event_type == EVENT_TYPE_APQN_ADD) { snprintf(name, sizeof(name), "card%02x", apqn_data->card); if (is_card_ep11_and_online(name) != CKR_OK) found = FALSE; /* Not an EP11 APQN */ } } if (!found) return CKR_OK; TRACE_DEVEL("%s Refreshing target infos due to event for APQN %02x.%04x\n", __func__, apqn_data->card, apqn_data->domain); rc = refresh_target_info(tokdata, FALSE); if (rc != CKR_OK) { TRACE_DEVEL("%s Failed to get the target infos (refresh_target_info " "rc=0x%lx)\n", __func__, rc); if (__sync_fetch_and_or(&ep11_data->inconsistent, 1) == 0) { TRACE_ERROR("EP11 APQN setup is inconsistent, all crypto operations " "will fail from now on\n"); OCK_SYSLOG(LOG_ERR, "EP11 APQN setup is inconsistent, all crypto " "operations will fail from now on\n"); } return rc; } if (__sync_fetch_and_and(&ep11_data->inconsistent, 0) != 0) { TRACE_INFO("EP11 APQN setup is now consistent again\n"); OCK_SYSLOG(LOG_INFO, "EP11 APQN setup is now consistent again\n"); } /* Re-check after APQN set change if CPACF_WRAP mech is supported */ if (ep11tok_is_mechanism_supported(tokdata, CKM_IBM_CPACF_WRAP) != CKR_OK) { TRACE_INFO("CKM_IBM_CPACF_WRAP not supported on this system.\n"); if (pthread_mutex_lock(&ep11_data->pkey_mutex)) { TRACE_ERROR("%s Failed to lock pkey lock\n", __func__); return CKR_CANT_LOCK; } /* Disable pkey */ __sync_and_and_fetch(&ep11_data->pkey_wrap_supported, 0); __sync_and_and_fetch(&ep11_data->pkey_wrap_support_checked, 1); if (pthread_mutex_unlock(&ep11_data->pkey_mutex)) { TRACE_ERROR("%s Failed to lock pkey lock\n", __func__); } } else if (ep11_data->pkey_wrap_supported == 0 && !ep11tok_pkey_option_disabled(tokdata)) { if (pthread_mutex_lock(&ep11_data->pkey_mutex)) { TRACE_ERROR("%s Failed to lock pkey lock\n", __func__); return CKR_CANT_LOCK; } /* Will be re-checked at next usage attempt */ __sync_and_and_fetch(&ep11_data->pkey_wrap_support_checked, 0); if (pthread_mutex_unlock(&ep11_data->pkey_mutex)) { TRACE_ERROR("%s Failed to lock pkey lock\n", __func__); } } return CKR_OK; } /* * Called by the event thread, on receipt of an event. * * ATTENTION: This function is called in a separate thread. All actions * performed by this function must be thread save and use locks to lock * against concurrent access by other threads. */ CK_RV token_specific_handle_event(STDLL_TokData_t *tokdata, unsigned int event_type, unsigned int event_flags, const char *payload, unsigned int payload_len) { UNUSED(event_flags); switch (event_type) { case EVENT_TYPE_APQN_ADD: case EVENT_TYPE_APQN_REMOVE: if (payload_len != sizeof(event_udev_apqn_data_t)) return CKR_FUNCTION_FAILED; return ep11tok_handle_apqn_event(tokdata, event_type, (event_udev_apqn_data_t *)payload); case EVENT_TYPE_MK_CHANGE_INITIATE_QUERY: case EVENT_TYPE_MK_CHANGE_REENCIPHER: case EVENT_TYPE_MK_CHANGE_FINALIZE_QUERY: case EVENT_TYPE_MK_CHANGE_FINALIZE: case EVENT_TYPE_MK_CHANGE_CANCEL_QUERY: case EVENT_TYPE_MK_CHANGE_CANCEL: return ep11tok_handle_mk_change_event(tokdata, event_type, event_flags, payload, payload_len); default: return CKR_FUNCTION_NOT_SUPPORTED; } return CKR_OK; } /* * Refreshes the target info using the currently configured and available * APQNs. Registers the newly allocated target info as the current one in a * thread save way and gives back the previous one so that it is release when * no longer used (i.e. by a concurrently running thread). */ CK_RV refresh_target_info(STDLL_TokData_t *tokdata, CK_BBOOL wait_for_new_wk) { ep11_private_data_t *ep11_data = tokdata->private_data; volatile ep11_target_info_t *prev_info; ep11_target_info_t *target_info; CK_RV rc; target_info = calloc(1, sizeof(ep11_target_info_t)); if (target_info == NULL) { TRACE_ERROR("%s Memory allocation failed\n", __func__); return CKR_HOST_MEMORY; } target_info->ref_count = 1; /* Get and check the WKVPs freshly with the current set of APQNs */ rc = ep11tok_check_wkvps(tokdata, target_info); if (rc != CKR_OK) goto error; /* Get the version info freshly with the current set of APQNs */ rc = ep11tok_get_ep11_version(tokdata, target_info); if (rc != CKR_OK) goto error; /* Get the control points freshly with the current set of APQNs */ target_info->control_points_len = sizeof(target_info->control_points); rc = get_control_points(tokdata, target_info->control_points, &target_info->control_points_len, &target_info->max_control_point_index); if (rc != CKR_OK) goto error; if (ep11_data->mk_change_active) { /* MK change active: Setup a single APQN target */ rc = ep11tok_setup_single_target(tokdata, target_info, wait_for_new_wk); if (rc != CKR_OK) goto error; } else { /* Setup the group target freshly with the current set of APQNs */ rc = ep11tok_setup_target(tokdata, target_info); if (rc != CKR_OK) goto error; } /* Set the new one as the current one (locked against concurrent get's) */ if (pthread_rwlock_wrlock(&ep11_data->target_rwlock) != 0) { TRACE_DEVEL("Target Write-Lock failed.\n"); rc = CKR_CANT_LOCK; goto error; } prev_info = ep11_data->target_info; ep11_data->target_info = target_info; if (pthread_rwlock_unlock(&ep11_data->target_rwlock) != 0) { TRACE_DEVEL("Target Unlock failed.\n"); return CKR_CANT_LOCK; } /* Release the previous one */ if (prev_info != NULL) put_target_info(tokdata, (ep11_target_info_t *)prev_info); return CKR_OK; error: free_card_versions(target_info->card_versions); free((void *)target_info); return rc; } /* * Get the current EP11 target info. * Do NOT use the ep11_data->target_info directly, always get a copy using * this function. This will increment the reference count of the target info, * and return the current target info in a thread save way. * When no longer needed, put it back using put_target_info(). */ ep11_target_info_t *get_target_info(STDLL_TokData_t *tokdata) { ep11_private_data_t *ep11_data = tokdata->private_data; volatile ep11_target_info_t *target_info; #ifdef DEBUG unsigned long ref_count; #endif /* * Lock until we have obtained the current target info and have * increased the reference counter */ if (pthread_rwlock_rdlock(&ep11_data->target_rwlock) != 0) { TRACE_DEVEL("Target Read-Lock failed.\n"); return NULL; } target_info = *((void * volatile *)&ep11_data->target_info); if (target_info == NULL) { TRACE_ERROR("%s: target_info is NULL\n", __func__); if (pthread_rwlock_unlock(&ep11_data->target_rwlock) != 0) TRACE_DEVEL("Target Unlock failed.\n"); return NULL; } #ifdef DEBUG ref_count = __sync_add_and_fetch(&target_info->ref_count, 1); TRACE_DEBUG("%s: target_info: %p ref_count: %lu\n", __func__, (void *)target_info, ref_count); #else __sync_add_and_fetch(&target_info->ref_count, 1); #endif if (pthread_rwlock_unlock(&ep11_data->target_rwlock) != 0) { TRACE_DEVEL("Target Unlock failed.\n"); return NULL; } return (ep11_target_info_t *)target_info; } /* * Give back an EP11 target info. This will decrement the reference count, * and will free it if the reference count reaches zero. */ void put_target_info(STDLL_TokData_t *tokdata, ep11_target_info_t *target_info) { ep11_private_data_t *ep11_data = tokdata->private_data; unsigned long ref_count; if (target_info == NULL) return; if (target_info->ref_count > 0) { ref_count = __sync_sub_and_fetch(&target_info->ref_count, 1); TRACE_DEBUG("%s: target_info: %p ref_count: %lu\n", __func__, (void *)target_info, ref_count); } else { TRACE_WARNING("%s: target_info: %p ref_count already 0.\n", __func__, (void *)target_info); ref_count = 0; } if (ref_count == 0 && target_info != ep11_data->target_info) { TRACE_DEBUG("%s: target_info: %p is freed\n", __func__, (void *)target_info); if (dll_m_rm_module != NULL) dll_m_rm_module(NULL, target_info->target); free_card_versions(target_info->card_versions); free(target_info); } } /* * Must be called either with WRITE_LOCK on the object that owns the template * specified as @tmpl, or before the object is made publicly available via * object_mgr_create_final. */ static CK_RV update_ep11_attrs_from_blob(STDLL_TokData_t *tokdata, SESSION *session, OBJECT *key_obj, CK_BBOOL aes_xts) { ep11_private_data_t *ep11_data = tokdata->private_data; CK_BBOOL restr = CK_FALSE; /*, never_mod = CK_FALSE; */ CK_BBOOL attrb = CK_FALSE, useasdata = CK_FALSE; CK_BBOOL pkeyextr = CK_FALSE, pkeyneverextr = CK_FALSE; CK_ULONG stdcomp1 = 0; CK_ATTRIBUTE *attr, *blob_attr = NULL; CK_RV rc = CKR_OK; CK_ULONG i; CK_BYTE *useblob = NULL, *blob; CK_OBJECT_CLASS class; size_t usebloblen = 0; CK_ATTRIBUTE ibm_attrs[] = { { CKA_IBM_RESTRICTABLE, &restr, sizeof(restr) }, /* Skip CKA_IBM_NEVER_MODIFIABLE for now, it causes CKR_ARGUMENTS_BAD { CKA_IBM_NEVER_MODIFIABLE, &never_mod, sizeof(never_mod) }, */ { CKA_IBM_USE_AS_DATA, &useasdata, sizeof(useasdata) }, { CKA_IBM_ATTRBOUND, &attrb, sizeof(attrb) }, { CKA_IBM_STD_COMPLIANCE1, &stdcomp1, sizeof(stdcomp1) }, /* PROTKEY attributes must be the last 2 */ { CKA_IBM_PROTKEY_EXTRACTABLE, &pkeyextr, sizeof(pkeyextr) }, { CKA_IBM_PROTKEY_NEVER_EXTRACTABLE, &pkeyneverextr, sizeof(pkeyneverextr) }, }; CK_ULONG num_ibm_attrs = sizeof(ibm_attrs) / sizeof(CK_ATTRIBUTE); if (template_attribute_get_ulong(key_obj->template, CKA_CLASS, &class) != CKR_OK) { TRACE_ERROR("This key has no CKA_CLASS: should not occur!\n"); return CKR_FUNCTION_FAILED; } if (!ep11_data->pkey_wrap_supported || class == CKO_PUBLIC_KEY) num_ibm_attrs -= 2; if (template_attribute_get_non_empty(key_obj->template, CKA_IBM_OPAQUE, &blob_attr) != CKR_OK) { TRACE_ERROR("This key has no CKA_IBM_OPAQUE: should not occur!\n"); return CKR_FUNCTION_FAILED; } blob = blob_attr->pValue; RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) RETRY_REENC_BLOB_START(tokdata, target_info, key_obj, blob, blob_attr->ulValueLen, useblob, usebloblen, rc) rc = dll_m_GetAttributeValue(useblob, aes_xts ? usebloblen / 2 : usebloblen, ibm_attrs, num_ibm_attrs, target_info->target); RETRY_REENC_BLOB_END(tokdata, target_info, useblob, usebloblen, rc) RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, NULL); TRACE_ERROR("%s m_GetAttributeValue failed rc=0x%lx\n", __func__, rc); return rc; } /* Set/Update all available attributes in the object's template */ for (i = 0; i < num_ibm_attrs; i++) { if (ibm_attrs[i].ulValueLen == CK_UNAVAILABLE_INFORMATION) { TRACE_DEVEL("%s Attribute 0x%lx not available\n", __func__, ibm_attrs[i].type); continue; } rc = build_attribute(ibm_attrs[i].type, ibm_attrs[i].pValue, ibm_attrs[i].ulValueLen, &attr); if (rc != CKR_OK) { TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc); return rc; } rc = template_update_attribute(key_obj->template, attr); if (rc != CKR_OK) { free(attr); TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n", __func__, rc); return rc; } } return CKR_OK; } CK_RV token_specific_check_obj_access(STDLL_TokData_t *tokdata, OBJECT *obj, CK_BBOOL create) { ep11_private_data_t *ep11_data = tokdata->private_data; CK_OBJECT_CLASS class; CK_RV rc; UNUSED(create); if (ep11_data->fips_session_mode == 0) return CKR_OK; rc = template_attribute_get_ulong(obj->template, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("Class attribute not found\n"); return rc; } switch (class) { case CKO_SECRET_KEY: case CKO_PUBLIC_KEY: case CKO_PRIVATE_KEY: break; default: return CKR_OK; } if (!session_mgr_user_session_exists(tokdata)) return CKR_USER_NOT_LOGGED_IN; return CKR_OK; } opencryptoki-opencryptoki-451d99c/usr/lib/ep11_stdll/ep11_specific.h000066400000000000000000002373471520105705100254570ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2015-2023 * * 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 #include "ep11_func.h" #include "configuration.h" #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wstrict-prototypes" #include #pragma GCC diagnostic pop #include #define EP11SHAREDLIB_NAME "OCK_EP11_LIBRARY" #define EP11SHAREDLIB_V4 "libep11.so.4" #define EP11SHAREDLIB_V3 "libep11.so.3" #define EP11SHAREDLIB_V2 "libep11.so.2" #define EP11SHAREDLIB_V1 "libep11.so.1" #define EP11SHAREDLIB "libep11.so" #define EP11_DEFAULT_CFG_FILE "ep11tok.conf" #define EP11_DEFAULT_CPFILTER_FILE "ep11cpfilter.conf" /* largest blobsize ever seen is about 5k (for 4096 mod bits RSA keys) */ /* Attribute bound keys can be larger */ #define MAX_BLOBSIZE (8192 * 2) #define MAX_CSUMSIZE 64 #define EP11_CSUMSIZE 3 #define MAX_DIGEST_STATE_BYTES 1024 #define MAX_CRYPT_STATE_BYTES 12288 #define MAX_SIGN_STATE_BYTES 12288 #define MAX_APQN 256 #define EP11_BLOB_WKID_OFFSET 32 #define EP11_BLOB_BOOL_ATTR_OFFSET 52 /* second 32 bits of bool attr field */ #define EP11_BLOB_VERSION_OFFSET 64 #define EP11_BLOB_VERSION 0x1234 typedef struct { uint32_t version : 4, reserved : 4, num_int_attrs : 8, num_varlen_attrs : 4, wordcount_varlen_attrs : 12; } __attribute__ ((packed)) blob_attr_header_t; #define EP11_BLOB_ATTR_HDR_VERSION 1 typedef struct cp_mech_config { CK_MECHANISM_TYPE mech; struct cp_mech_config *next; } cp_mech_config_t; typedef struct cp_config { unsigned long int cp; cp_mech_config_t *mech; struct cp_config *next; } cp_config_t; #define MAX_RETRY_COUNT 100 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; 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; CK_ULONG apply_to_firmware_version_only; } version_req_t; typedef CK_CHAR ep11_serialno_t[16]; typedef struct { SESSION *session; CK_BYTE session_id[SHA256_HASH_SIZE]; CK_BBOOL pin_blob_valid; CK_BYTE session_pin_blob[XCP_PINBLOB_BYTES]; CK_OBJECT_HANDLE session_object; ep11_serialno_t *serial_numbers; CK_ULONG num_serial_numbers; } ep11_session_t; typedef struct { STDLL_TokData_t *tokdata; ep11_session_t *ep11_session; CK_BBOOL relogin; } login_logout_data_t; typedef struct { CK_SLOT_ID_32 slot_id; /* Slot number as BE32 */ CK_BYTE purpose[12]; } __attribute__ ((packed)) session_nonce_t; #define DEFAULT_EP11_PIN " " #define VHSM_NONCE_PURPOSE "VHSM-session" #define FIPS_NONCE_PURPOSE "FIPS-session" #define CKH_IBM_EP11_SESSION CKH_VENDOR_DEFINED + 1 #define CKH_IBM_EP11_VHSMPIN CKH_VENDOR_DEFINED + 2 #define CKH_IBM_EP11_FIPSPIN CKH_VENDOR_DEFINED + 3 #define EP11_PINBLOB_MARKER_OFS 4 #define EP11_PINBLOB_V0_MARKER 0xaa #define EP11_PINBLOB_V1_MARKER 0xab #define PUBLIC_SESSION_ID_LENGTH 16 #define CKF_EP11_HELPER_SESSION 0x80000000 /* Definitions for loading libica dynamically */ #define ICASHAREDLIB_V4 "libica.so.4" #define ICASHAREDLIB_V3 "libica.so.3" 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 void (*ica_cleanup_t) (void); typedef int (*ica_fips_status_t) (void); 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 ica_cleanup_t ica_cleanup; ica_fips_status_t ica_fips_status; } 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 */ #define PKEY_MK_VP_LENGTH 32 #define PKEY_MODE_DISABLED 0 #define PKEY_MODE_DEFAULT 1 #define PKEY_MODE_ENABLE4NONEXTR 2 #define PKEY_MODE_ENABLE4EXTR 3 #define PKEY_MODE_ENABLE4ALL 4 #define PQC_BYTE_NO(idx) (((idx) - 1) / 8) #define PQC_BIT_IN_BYTE(idx) (((idx - 1)) % 8) #define PQC_BIT_MASK(idx) (0x80 >> PQC_BIT_IN_BYTE(idx)) #define PQC_BYTES ((((XCP_PQC_MAX / 32) * 32) + 32) / 8) typedef struct { volatile unsigned long ref_count; target_t target; ep11_card_version_t *card_versions; CK_ULONG used_firmware_API_version; unsigned char control_points[XCP_CP_BYTES]; size_t control_points_len; size_t max_control_point_index; CK_CHAR serialNumber[16]; CK_BYTE pqc_strength[PQC_BYTES]; int single_apqn; uint_32 adapter; /* set if single_apqn = 1 */ uint_32 domain; /* set if single_apqn = 1 */ volatile int single_apqn_has_new_wk; } ep11_target_info_t; typedef struct { char token_config_filename[PATH_MAX]; ep11_target_t target_list; CK_BYTE raw2key_wrap_blob[MAX_BLOBSIZE]; CK_BYTE raw2key_wrap_blob_reenc[MAX_BLOBSIZE]; size_t raw2key_wrap_blob_l; pthread_mutex_t raw2key_wrap_blob_mutex; int cka_sensitive_default_true; char cp_filter_config_filename[PATH_MAX]; cp_config_t *cp_config; int strict_mode; int vhsm_mode; int fips_session_mode; int optimize_single_ops; int pkey_mode; volatile int pkey_combined_extract_supported; volatile int pkey_wrap_supported; int pkey_wrap_support_checked; char pkey_mk_vp[PKEY_MK_VP_LENGTH]; pthread_mutex_t pkey_mutex; int msa_level; int digest_libica; char digest_libica_path[PATH_MAX]; unsigned char expected_wkvp[XCP_WKID_BYTES]; int expected_wkvp_set; volatile int mk_change_active; char mk_change_op[8]; /* set if mk_change_active = 1 */ unsigned char new_wkvp[XCP_WKID_BYTES]; /* set if mk_change_active = 1 */ struct apqn *mk_change_apqns; /* set if mk_change_active = 1 */ unsigned int num_mk_change_apqns; /* set if mk_change_active = 1 */ int inconsistent; libica_t libica; void *lib_ep11; CK_VERSION ep11_lib_version; volatile ep11_target_info_t *target_info; pthread_rwlock_t target_rwlock; CK_BYTE vhsm_pin[XCP_MAX_PINBYTES]; CK_BBOOL vhsm_pin_valid; CK_BYTE vhsm_pin_blob[XCP_PINBLOB_BYTES]; CK_BBOOL vhsm_pin_blob_valid; CK_BYTE fips_pin[XCP_MAX_PINBYTES]; CK_BBOOL fips_pin_valid; CK_BYTE fips_pin_blob[XCP_PINBLOB_V1_BYTES]; CK_BBOOL fips_pin_blob_valid; uint32 session_refcount; uint32_t (*get_session_refcount)(STDLL_TokData_t *tokdata); void (*incr_session_refcount)(STDLL_TokData_t *tokdata); void (*decr_session_refcount)(STDLL_TokData_t *tokdata); pthread_mutex_t session_mutex; } ep11_private_data_t; #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)) #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 #define SYSFS_SEL_GUEST "/sys/firmware/uv/prot_virt_guest" typedef struct { STDLL_TokData_t *tokdata; ep11_session_t *ep11_session; CK_BBOOL wrap_was_successful; CK_RV wrap_error; CK_VOID_PTR secure_key; CK_ULONG secure_key_len; CK_VOID_PTR secure_key_reenc; CK_ULONG secure_key_reenc_len; CK_BYTE *pkey_buf; size_t *pkey_buflen_p; /* for AES XTS processing */ CK_VOID_PTR secure_key2; CK_ULONG secure_key_len2; CK_VOID_PTR secure_key_reenc2; CK_ULONG secure_key_reenc_len2; CK_BYTE *pkey_buf2; size_t *pkey_buflen_p2; CK_BBOOL aes_xts; } pkey_wrap_handler_data_t; /* A wrapped key can have max 132 bytes for an EC-p521 key */ #define EP11_MAX_WRAPPED_KEY_SIZE (2 * (521 / 8 + 1)) #define EP11_WRAPPED_KEY_VERSION_1 0x0001 #define EP11_WRAPPED_KEY_TYPE_AES 0x1 #define EP11_WRAPPED_KEY_TYPE_DES 0x2 #define EP11_WRAPPED_KEY_TYPE_EC 0x3 #define EP11_WRAPPED_KEY_TYPE_ED 0x4 typedef struct { uint16_t version; uint8_t res0[16]; uint32_t wrapped_key_type; uint32_t bit_length; uint64_t token_size; uint8_t res1[8]; uint8_t wrapped_key[EP11_MAX_WRAPPED_KEY_SIZE]; uint8_t res2[50]; } __attribute__((packed)) wrapped_key_t; extern m_DigestSingle_t dll_m_DigestSingle; extern m_Login_t dll_m_Login; extern m_Logout_t dll_m_Logout; extern m_LoginExtended_t dll_m_LoginExtended; extern m_LogoutExtended_t dll_m_LogoutExtended; extern m_get_xcp_info_t dll_m_get_xcp_info; extern m_admin_t dll_m_admin; extern xcpa_cmdblock_t dll_xcpa_cmdblock; extern xcpa_internal_rv_t dll_xcpa_internal_rv; typedef CK_RV(*adapter_handler_t) (uint_32 adapter, uint_32 domain, void *handler_data); CK_RV handle_all_ep11_cards(ep11_target_t * ep11_targets, adapter_handler_t handler, void *handler_data); CK_BBOOL is_apqn_online(uint_32 card, uint_32 domain); CK_BOOL ep11_is_session_object(CK_ATTRIBUTE_PTR attrs, CK_ULONG attrs_len); CK_BOOL ep11_is_private_object(CK_ATTRIBUTE_PTR attrs, CK_ULONG attrs_len); CK_RV ep11tok_relogin_session(STDLL_TokData_t *tokdata, SESSION *session); void ep11_get_pin_blob(STDLL_TokData_t *tokdata, ep11_session_t *ep11_session, CK_BOOL is_session_obj, CK_BOOL is_private_obj, CK_BYTE **pin_blob, CK_ULONG *pin_blob_len); CK_RV ep11_login_handler(uint_32 adapter, uint_32 domain, void *handler_data); ep11_target_info_t *get_target_info(STDLL_TokData_t *tokdata); void put_target_info(STDLL_TokData_t *tokdata, ep11_target_info_t *target_info); CK_RV refresh_target_info(STDLL_TokData_t *tokdata, CK_BBOOL wait_for_new_wk); CK_RV get_ep11_target_for_apqn(uint_32 adapter, uint_32 domain, target_t *target, uint64_t flags); void free_ep11_target_for_apqn(target_t target); CK_RV ep11_error_to_pkcs11_error(CK_RV rc, SESSION *session); CK_BBOOL ep11tok_libica_digest_available(STDLL_TokData_t *tokdata, ep11_private_data_t *ep11_data, CK_MECHANISM_TYPE mech); CK_RV ep11tok_libica_digest(STDLL_TokData_t *tokdata, 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_RV ep11tok_handle_mk_change_event(STDLL_TokData_t *tokdata, unsigned int event_type, unsigned int event_flags, const char *payload, unsigned int payload_len); CK_RV ep11tok_mk_change_check_pending_ops(STDLL_TokData_t *tokdata); CK_BBOOL ep11tok_is_blob_new_wkid(STDLL_TokData_t *tokdata, CK_BYTE *blob, CK_ULONG blob_len); CK_RV ep11tok_reencipher_blob(STDLL_TokData_t *tokdata, SESSION *session, ep11_target_info_t **target_info, CK_BYTE *blob, CK_ULONG blob_len, CK_BYTE *new_blob); void ep11_config_parse_error(int line, int col, const char *msg); void ep11_config_error_token(const char *fname, const char *key, int line, const char *expected); CK_RV ep11_config_next(struct ConfigBaseNode **c, unsigned typemask, const char *fname, const char *expected); 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_BBOOL in_fork_initializer); 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_BBOOL count_statistics, CK_ULONG operation); CK_RV is_ec_aggregate_mechanism(CK_MECHANISM_PTR pMechanism); 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_BBOOL count_statistics, CK_ULONG operation); 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_BBOOL count_statistics, CK_ULONG operation); CK_RV ep11tok_check_single_mech_key(STDLL_TokData_t *tokdata, SESSION * session, CK_MECHANISM *mech, CK_OBJECT_HANDLE key, CK_ULONG operation, CK_BBOOL *auth_required); CK_BOOL ep11tok_mech_single_only(CK_MECHANISM *mech); CK_BBOOL ep11tok_is_common_code_derive_mech(CK_MECHANISM *mech); CK_BBOOL ep11tok_is_common_code_sign_verify_mech(CK_MECHANISM *mech); CK_RV ep11tok_sign_init(STDLL_TokData_t * tokdata, SESSION * session, CK_MECHANISM * mech, CK_BBOOL recover_mode, CK_OBJECT_HANDLE key, CK_BBOOL checkauth); 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_BBOOL checkauth); 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_BBOOL count_statistics); 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_ULONG operation); CK_RV ep11tok_login_session(STDLL_TokData_t * tokdata, SESSION * session); CK_RV ep11tok_logout_session(STDLL_TokData_t * tokdata, SESSION * session, CK_BBOOL in_fork_initializer); 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); CK_RV ep11tok_copy_firmware_info(STDLL_TokData_t *tokdata, CK_TOKEN_INFO_PTR pInfo); CK_RV ep11tok_pkey_usage_ok(STDLL_TokData_t *tokdata, SESSION *session, CK_OBJECT_HANDLE hkey, CK_MECHANISM *mech); CK_RV ep11tok_set_operation_state(STDLL_TokData_t *tokdata, SESSION *session); CK_RV do_LoginExtended(XCP_LoginAlgorithm_t alg, XCP_LoginImporter_t imp_keytype, const CK_BYTE *pin, CK_ULONG pin_len, const CK_BYTE *nonce, CK_ULONG nonce_len, CK_BYTE *pin_blob, CK_ULONG *pin_blob_len, const CK_BYTE *parent_session_id, target_t target); CK_RV do_LogoutExtended(XCP_LoginAlgorithm_t alg, XCP_LoginImporter_t imp_keytype, const CK_BYTE *pin, CK_ULONG pin_len, const CK_BYTE *nonce, CK_ULONG nonce_len, target_t target); CK_RV ep11tok_extract_blob_info(CK_BYTE *blob, CK_ULONG blob_len, CK_BBOOL *is_spki, CK_BYTE **wkvp, CK_BYTE** session_id, XCP_Attr_t **bool_attrs); /* * Macros to enclose EP11 library calls involving session bound blobs. * If the EP11 token is in an inconsistent state, fail with CKR_DEVICE_ERROR. * Obtain a target_info to be used with the EP11 library call. * If in single-APQN mode, and that APQN went offline, select another APQN and * retry the library call. * In case of EP11 library function failed with CKR_SESSION_CLOSED or * CKR_PIN_INCORRECT, relogin all APQNs and retry the library call. */ #define RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) \ do { \ ep11_target_info_t* target_info; \ int retry_count; \ CK_RV rc2; \ if (((ep11_private_data_t *) \ (tokdata)->private_data)->inconsistent) { \ (rc) = CKR_DEVICE_ERROR; \ TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); \ break; \ } \ target_info = get_target_info((tokdata)); \ if (target_info == NULL) { \ (rc) = CKR_FUNCTION_FAILED; \ break; \ } \ for (retry_count = 0; \ target_info != NULL && \ retry_count < MAX_RETRY_COUNT; \ retry_count ++) { #define RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) \ if ((target_info) == NULL) \ break; \ if (target_info->single_apqn && \ ((rc) == CKR_IBM_TARGET_INVALID || \ ((rc) == CKR_FUNCTION_FAILED && \ !is_apqn_online(target_info->adapter, \ target_info->domain)))) { \ /* Single APQN went offline, select other */\ TRACE_DEVEL("%s single APQN went offline\n",\ __func__); \ put_target_info((tokdata), target_info); \ target_info = NULL; \ (rc) = refresh_target_info((tokdata), \ FALSE); \ if ((rc) != CKR_OK) \ break; \ target_info = get_target_info((tokdata)); \ if (target_info == NULL) { \ (rc) = CKR_FUNCTION_FAILED; \ break; \ } \ continue; \ } \ if ((rc) != CKR_SESSION_CLOSED && \ (rc) != CKR_PIN_INCORRECT) \ break; \ rc2 = ep11tok_relogin_session((tokdata), \ (session)); \ if (rc2 != CKR_OK) { \ (rc) = rc2; \ break; \ } \ } \ put_target_info((tokdata), target_info); \ } while (0); /* * Macros to enclose EP11 library calls not involving session bound blobs, and * with given target_info. * If the EP11 token is in an inconsistent state, fail with CKR_DEVICE_ERROR. * If in single-APQN mode, and that APQN went offline, select another APQN and * retry the library call. */ #define RETRY_SINGLE_APQN_START(tokdata, rc) \ do { \ int retry_count; \ if (((ep11_private_data_t *) \ (tokdata)->private_data)->inconsistent) { \ (rc) = CKR_DEVICE_ERROR; \ TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); \ break; \ } \ for (retry_count = 0; \ retry_count < MAX_RETRY_COUNT; \ retry_count ++) { #define RETRY_SINGLE_APQN_END(rc, tokdata, target_info) \ if ((target_info) == NULL) \ break; \ if ((target_info)->single_apqn && \ ((rc) == CKR_IBM_TARGET_INVALID || \ ((rc) == CKR_FUNCTION_FAILED && \ !is_apqn_online((target_info)->adapter, \ (target_info)->domain)))) { \ /* Single APQN went offline, select other */\ TRACE_DEVEL("%s single APQN went offline\n",\ __func__); \ put_target_info((tokdata), (target_info)); \ target_info = NULL; \ (rc) = refresh_target_info((tokdata), \ FALSE); \ if ((rc) != CKR_OK) \ break; \ (target_info) = get_target_info((tokdata)); \ if ((target_info) == NULL) { \ (rc) = CKR_FUNCTION_FAILED; \ break; \ } \ continue; \ } \ break; \ } \ } while (0); /* * Macros to enclose EP11 library calls with 1, 2 or 3 key blobs as argument. * If a master key change is active, and the single APQN has the new WK, * obtain and use the re-enciphered blob(s) from CKA_IBM_OPAQUE_REENC from * the key object(s). * If a master key change is active, and the EP11 library call fails with * CKR_IBM_WKID_MISMATCH and the used blob(s) are enciphered with the new WK, * then select a new single APQN that has the new WK. If no available APQN has * the new WK, wait until on at least one the new WK gets activated. * In case the blob(s) are enciphered with the old WK, then obtain the * re-enciphered blob(s) from CKA_IBM_OPAQUE_REENC from the key object(s) * and retry the library call. * If the retry was successful, indicate that the single APQN has the new WK. */ #define RETRY_REENC_BLOB_START(tokdata, target_info, obj, blob, blobsize,\ useblob, useblobsize, rc) \ RETRY_REENC_BLOB3_START(tokdata, target_info, obj, blob, \ blobsize, useblob, useblobsize, \ NULL, blob, blobsize, blob, \ blobsize, NULL, blob, blobsize, \ blob, blobsize, rc) #define RETRY_REENC_BLOB_END(tokdata, target_info, useblob, useblobsize, \ rc) \ RETRY_REENC_BLOB3_END(tokdata, target_info, useblob, \ useblobsize, NULL, 0, NULL, 0, rc) #define RETRY_REENC_BLOB2_START(tokdata, target_info, obj1, blob1, \ blobsize1, useblob1, useblobsize1, \ obj2, blob2, blobsize2, useblob2, \ useblobsize2, rc) \ RETRY_REENC_BLOB3_START(tokdata, target_info, obj1, \ blob1, blobsize1, useblob1, \ useblobsize1, obj2, blob2, \ blobsize2, useblob2, \ useblobsize2, NULL, blob1, \ blobsize1, blob1, blobsize1, rc) #define RETRY_REENC_BLOB2_END(tokdata, target_info, useblob1, \ useblobsize1, useblob2, useblobsize2, rc) \ RETRY_REENC_BLOB3_END(tokdata, target_info, useblob1, \ useblobsize1, useblob2, \ useblobsize2, NULL, 0, rc) #define RETRY_REENC_BLOB3_START(tokdata, target_info, obj1, blob1, \ blobsize1, useblob1, useblobsize1, \ obj2, blob2, blobsize2, useblob2, \ useblobsize2, obj3, blob3, blobsize3, \ useblob3, useblobsize3, rc) \ do { \ int retry = 0; \ do { \ if (((ep11_private_data_t *)(tokdata)-> \ private_data)->mk_change_active && \ ((target_info)->single_apqn_has_new_wk || \ retry == 1)) { \ /* New WK is set on single APQN */ \ TRACE_DEVEL("%s single APQN has new WK\n", \ __func__); \ if (obj1 != NULL) { \ (rc) = obj_opaque_2_reenc_blob((tokdata),\ (obj1), &(useblob1),\ &(useblobsize1)); \ if ((rc) == CKR_TEMPLATE_INCOMPLETE) { \ (useblob1) = (blob1); \ (useblobsize1) = (blobsize1); \ } else if ((rc) != CKR_OK) { \ TRACE_ERROR( \ "%s reenc blob1 invalid\n", \ __func__); \ break; \ } \ } \ if (obj2 != NULL) { \ (rc) = obj_opaque_2_reenc_blob((tokdata),\ (obj2), &(useblob2),\ &(useblobsize2)); \ if ((rc) == CKR_TEMPLATE_INCOMPLETE) { \ (useblob2) = (blob2); \ (useblobsize2) = (blobsize2); \ } else if ((rc) != CKR_OK) { \ TRACE_ERROR( \ "%s reenc blob2 invalid\n", \ __func__); \ break; \ } \ } \ if (obj3 != NULL) { \ (rc) = obj_opaque_2_reenc_blob((tokdata),\ (obj3), &(useblob3),\ &(useblobsize3)); \ if ((rc) == CKR_TEMPLATE_INCOMPLETE) { \ (useblob3) = (blob3); \ (useblobsize3) = (blobsize3); \ } else if ((rc) != CKR_OK) { \ TRACE_ERROR( \ "%s reenc blob3 invalid\n", \ __func__); \ break; \ } \ } \ retry = 1; \ } else { \ if (obj1 != NULL) { \ (useblob1) = (blob1); \ (useblobsize1) = (blobsize1); \ } \ if (obj2 != NULL) { \ (useblob2) = (blob2); \ (useblobsize2) = (blobsize2); \ } \ if (obj3 != NULL) { \ (useblob3) = (blob3); \ (useblobsize3) = (blobsize3); \ } \ } #define RETRY_REENC_BLOB3_END(tokdata, target_info, useblob1, \ useblobsize1, useblob2, useblobsize2, \ useblob3, useblobsize3, rc) \ if (((ep11_private_data_t *)(tokdata)-> \ private_data)->mk_change_active && \ retry == 0 && \ (rc) == CKR_IBM_WKID_MISMATCH) { \ if ((useblob1 != NULL && \ ep11tok_is_blob_new_wkid((tokdata), \ (useblob1), (useblobsize1))) || \ (useblob2 != NULL && \ ep11tok_is_blob_new_wkid((tokdata), \ (useblob2), (useblobsize2))) || \ (useblob3 != NULL && \ ep11tok_is_blob_new_wkid((tokdata), \ (useblob3), (useblobsize3)))) { \ /* blob has new WK, but single APQN not. Wait until other single APQN with new WK set is available */ \ TRACE_DEVEL("%s WKID mismatch, blob has "\ "new WK, retry with new " \ "single APQN with new WK, " \ "wait if required\n", \ __func__); \ put_target_info((tokdata), \ (target_info)); \ (target_info) = NULL; \ (rc) = refresh_target_info((tokdata), \ TRUE); \ if ((rc) != CKR_OK) \ break; \ (target_info) = \ get_target_info((tokdata)); \ if ((target_info) == NULL) { \ (rc) = CKR_FUNCTION_FAILED; \ break; \ } \ continue; \ } \ /* Single APQN seems to now have new WK */ \ TRACE_DEVEL("%s WKID mismatch, retry with " \ "reenc-blob(s)\n", __func__); \ retry = 1; \ continue; \ } \ if (((ep11_private_data_t *)(tokdata)-> \ private_data)->mk_change_active && \ retry == 1 && \ (rc) != CKR_IBM_WKID_MISMATCH && \ (rc) != CKR_IBM_TARGET_INVALID && \ (rc) != CKR_FUNCTION_FAILED) { \ /* retry with re-enciphered blob worked */ \ TRACE_DEVEL("%s single APQN has new WK\n", \ __func__); \ __sync_or_and_fetch( \ &(target_info)->single_apqn_has_new_wk, \ 1); \ } \ break; \ } while (1); \ } while (0); /* * Macros to enclose EP11 library calls with the wrap-blob as argument. * If a master key change is active, and the single APQN has the new WK, * obtain and use the re-enciphered wrap-blob. * If a master key change is active, and the EP11 library call fails with * CKR_IBM_WKID_MISMATCH and the used wrap blob is enciphered with the new WK, * then select a new single APQN that has the new WK. If no available APQN has * the new WK, wait until on at least one the new WK gets activated. * In case the used wrap blob is enciphered with the old WK, then obtain the * re-enciphered wrap-blob and retry the library call. * If the retry was successful, indicate that the single APQN has the new WK. */ #define RETRY_REENC_WRAPBLOB_START(tokdata, target_info, useblob) \ do { \ int retry = 0; \ do { \ if (((ep11_private_data_t *)(tokdata)-> \ private_data)->mk_change_active && \ (target_info)->single_apqn_has_new_wk && \ retry == 0) { \ /* New WK is already set on single APQN */ \ TRACE_DEVEL("%s single APQN has new WK\n", \ __func__); \ (useblob) = ((ep11_private_data_t *) \ (tokdata)->private_data)-> \ raw2key_wrap_blob_reenc; \ retry = 1; \ } else { \ (useblob) = ((ep11_private_data_t *) \ (tokdata)->private_data)-> \ raw2key_wrap_blob; \ } #define RETRY_REENC_WRAPBLOB_END(tokdata, target_info, useblob, rc) \ if (((ep11_private_data_t *)(tokdata)-> \ private_data)->mk_change_active && \ retry == 0 && \ (rc) == CKR_IBM_WKID_MISMATCH) { \ if (ep11tok_is_blob_new_wkid((tokdata), \ (useblob), \ ((ep11_private_data_t *) \ (tokdata)->private_data)-> \ raw2key_wrap_blob_l)) { \ /* blob has new WK, but single APQN not. Wait until other single APQN with new WK set is available */ \ TRACE_DEVEL("%s WKID mismatch, blob has "\ "new WK, retry with new " \ "single APQN with new WK, " \ "wait if required\n", \ __func__); \ put_target_info((tokdata), \ (target_info)); \ (target_info) = NULL; \ (rc) = refresh_target_info((tokdata), \ TRUE); \ if ((rc) != CKR_OK) \ break; \ (target_info) = \ get_target_info((tokdata)); \ if ((target_info) == NULL) { \ (rc) = CKR_FUNCTION_FAILED; \ break; \ } \ continue; \ } \ /* Single APQN seems to now have new WK */ \ TRACE_DEVEL("%s WKID mismatch, retry with " \ "reenc-wrap-blob\n", __func__); \ (useblob) = ((ep11_private_data_t *) \ (tokdata)->private_data)-> \ raw2key_wrap_blob_reenc; \ retry = 1; \ continue; \ } \ if (((ep11_private_data_t *)(tokdata)-> \ private_data)->mk_change_active && \ retry == 1 && \ (rc) != CKR_IBM_WKID_MISMATCH && \ (rc) != CKR_IBM_TARGET_INVALID && \ (rc) != CKR_FUNCTION_FAILED) { \ /* retry with re-enciphered blob worked */ \ TRACE_DEVEL("%s single APQN has new WK\n", \ __func__); \ __sync_or_and_fetch( \ &(target_info)->single_apqn_has_new_wk, \ 1); \ } \ break; \ } while (1); \ } while (0); /* * Macros to enclose EP11 library calls with a blob as argument that gets * updated by the EP11 library call. * If a master key change is active, and the single APQN has the new WK, * use the re-enciphered blob for the EP11 library call. * If a master key change is active, and the EP11 library call fails with * CKR_IBM_WKID_MISMATCH use the re-enciphered blob and retry the library call. * Also indicate that the single APQN has the new WK. * If a master key change is active, and the EP11 library call was successful * when using the old blob, re-encipher the (potentially updated) blob. * When re-enciphering fails with CKR_IBM_WK_NOT_INITIALIZED, because the * new WK was just activated on the single APQN, indicate that the single APQN * has the new WK, and retry the EP11 library call with the (still unchanged) * re-enciphered blob (which then will be potentially updated by the EP11 * library call). */ #define RETRY_UPDATE_BLOB_START(tokdata, target_info, blob, blobsize, \ reencblob, reencblobsize, \ useblob, useblobsize) \ do { \ CK_RV rc2; \ int retry = 0; \ do { \ if (((ep11_private_data_t *)(tokdata)-> \ private_data)->mk_change_active && \ ((target_info)->single_apqn_has_new_wk || \ retry == 1)) { \ /* New WK is set on single APQN */ \ TRACE_DEVEL("%s single APQN has new WK\n", \ __func__); \ (useblob) = (reencblob); \ (useblobsize) = (reencblobsize); \ retry = 1; \ } else { \ (useblob) = (blob); \ (useblobsize) = (blobsize); \ } #define RETRY_UPDATE_BLOB_END(tokdata, session, target_info, blob, \ blobsize, reencblob, reencblobsize, \ useblob, useblobsize, rc) \ if (((ep11_private_data_t *)(tokdata)-> \ private_data)->mk_change_active && \ retry == 0 && \ (rc) == CKR_IBM_WKID_MISMATCH) { \ if (ep11tok_is_blob_new_wkid((tokdata), \ (useblob), (useblobsize))) { \ /* blob has new WK, but single APQN not. Wait until other single APQN with new WK set is available */ \ TRACE_DEVEL("%s WKID mismatch, blob has "\ "new WK, retry with new " \ "single APQN with new WK, " \ "wait if required\n", \ __func__); \ put_target_info((tokdata), \ (target_info)); \ (target_info) = NULL; \ (rc) = refresh_target_info((tokdata), \ TRUE); \ if ((rc) != CKR_OK) \ break; \ (target_info) = \ get_target_info((tokdata)); \ if ((target_info) == NULL) { \ (rc) = CKR_FUNCTION_FAILED; \ break; \ } \ continue; \ } \ /* Single APQN seems to now have new WK */ \ TRACE_DEVEL("%s single APQN has new WK\n", \ __func__); \ retry = 1; \ continue; \ } \ if (((ep11_private_data_t *)(tokdata)-> \ private_data)->mk_change_active && \ retry == 0 && \ (rc) != CKR_IBM_WKID_MISMATCH && \ (rc) != CKR_IBM_TARGET_INVALID && \ (rc) != CKR_FUNCTION_FAILED) { \ /* Op worked, re-encipher updated blob */ \ TRACE_DEVEL("%s reencipher updated blob\n", \ __func__); \ if ((blobsize) != (reencblobsize)) { \ TRACE_ERROR("%s reencblobsize wrong \n", \ __func__); \ (rc) = CKR_ARGUMENTS_BAD; \ break; \ } \ rc2 = ep11tok_reencipher_blob((tokdata), \ (session), \ &(target_info),\ (blob), \ (blobsize), \ (reencblob)); \ if (rc2 == CKR_IBM_WK_NOT_INITIALIZED) { \ /* Single APQN now has new WK */ \ TRACE_DEVEL("%s WKID mismatch on " \ "reencipher, retry\n", __func__); \ retry = 1; \ continue; \ } \ if (rc2 != CKR_OK) { \ (rc) = CKR_DEVICE_ERROR; \ TRACE_ERROR("%s\n", \ ock_err(ERR_DEVICE_ERROR)); \ break; \ } \ } \ if (((ep11_private_data_t *)(tokdata)-> \ private_data)->mk_change_active && \ retry == 1 && \ (rc) != CKR_IBM_WKID_MISMATCH && \ (rc) != CKR_IBM_TARGET_INVALID && \ (rc) != CKR_FUNCTION_FAILED) { \ /* retry with re-enciphered blob worked */ \ TRACE_DEVEL("%s single APQN has new WK\n", \ __func__); \ __sync_or_and_fetch( \ &(target_info)->single_apqn_has_new_wk, \ 1); \ /* old blob is no longer valid, replace with * re-enciphered blob */ \ if ((blobsize) != (useblobsize)) { \ TRACE_ERROR("%s useblobsize wrong \n", \ __func__); \ (rc) = CKR_ARGUMENTS_BAD; \ break; \ } \ memcpy((blob), (useblob), (blobsize)); \ } \ break; \ } while (1); \ } while (0); /* * Macros to enclose EP11 library calls with a key blob and a state blob as * arguments where the state blob gets updated by the EP11 library call. * If a master key change is active, and the single APQN has the new WK, * obtain and use the re-enciphered key blob CKA_IBM_OPAQUE_REENC from * the key object, and also use the re-enciphered state blob(s) for the EP11 * library call. * If a master key change is active, and the EP11 library call fails with * CKR_IBM_WKID_MISMATCH use the re-enciphered blobs and retry the library * call. * If the retry was successful, indicate that the single APQN has the new WK. * If a master key change is active, and the EP11 library call was successful * when using the old blobs, re-encipher the (potentially updated) state blob. * When re-enciphering fails with CKR_IBM_WK_NOT_INITIALIZED, because the * new WK was just activated on the single APQN, indicate that the single APQN * has the new WK, and retry the EP11 library call with the (still unchanged) * re-enciphered state blob (which then will be potentially updated by the EP11 * library call). */ #define RETRY_REENC_BLOB_STATE_START(tokdata, target_info, obj, blob, \ blobsize, useblob, useblobsize, \ stateblob, reencstate, \ stateblobsize, usestate, \ usestatesize, rc) \ do { \ int retry = 0; \ do { \ if (((ep11_private_data_t *)(tokdata)-> \ private_data)->mk_change_active && \ ((target_info)->single_apqn_has_new_wk || \ retry == 1)) { \ /* New WK is set on single APQN */ \ TRACE_DEVEL("%s single APQN has new WK\n", \ __func__); \ (rc) = obj_opaque_2_reenc_blob((tokdata), \ (obj), &(useblob), &(useblobsize));\ if ((rc) == CKR_TEMPLATE_INCOMPLETE) { \ (useblob) = (blob); \ (useblobsize) = (blobsize); \ } else if ((rc) != CKR_OK) { \ TRACE_ERROR("%s reenc blob invalid\n", \ __func__); \ break; \ } \ (usestate) = (reencstate); \ retry = 1; \ } else { \ (useblob) = (blob); \ (useblobsize) = (blobsize); \ (usestate) = (stateblob); \ } \ (usestatesize) = (stateblobsize); #define RETRY_REENC_BLOB_STATE_END(tokdata, session, target_info, \ blob, blobsize, \ useblob, useblobsize, stateblob, \ reencstate, stateblobsize, usestate, \ usestatesize, newstate, rc) \ if (((ep11_private_data_t *)(tokdata)-> \ private_data)->mk_change_active && \ retry == 0 && \ (rc) == CKR_IBM_WKID_MISMATCH) { \ if (ep11tok_is_blob_new_wkid((tokdata), \ (useblob), (useblobsize)) || \ ep11tok_is_blob_new_wkid((tokdata), \ (usestate), (usestatesize))) { \ /* blob has new WK, but single APQN not. Wait until other single APQN with new WK set is available */ \ TRACE_DEVEL("%s WKID mismatch, blob has "\ "new WK, retry with new " \ "single APQN with new WK, " \ "wait if required\n", \ __func__); \ put_target_info((tokdata), \ (target_info)); \ (target_info) = NULL; \ (rc) = refresh_target_info((tokdata), \ TRUE); \ if ((rc) != CKR_OK) \ break; \ (target_info) = \ get_target_info((tokdata)); \ if ((target_info) == NULL) { \ (rc) = CKR_FUNCTION_FAILED; \ break; \ } \ continue; \ } \ /* Single APQN seems to now have new WK */ \ TRACE_DEVEL("%s WKID mismatch, retry with " \ "reenc-blob\n", __func__); \ retry = 1; \ continue; \ } \ if (((ep11_private_data_t *)(tokdata)-> \ private_data)->mk_change_active && \ retry == 1 && \ (((newstate) && (rc) == CKR_OK) || \ (!(newstate) && \ (rc) != CKR_IBM_WKID_MISMATCH && \ (rc) != CKR_IBM_TARGET_INVALID && \ (rc) != CKR_FUNCTION_FAILED))) { \ /* retry with re-enciphered blob worked */ \ TRACE_DEVEL("%s single APQN has new WK\n", \ __func__); \ __sync_or_and_fetch( \ &(target_info)->single_apqn_has_new_wk, \ 1); \ /* old blobs are no longer valid, replace with * re-enciphered blobs */ \ if ((blobsize) != (useblobsize)) { \ TRACE_ERROR("%s useblobsize wrong \n", \ __func__); \ (rc) = CKR_ARGUMENTS_BAD; \ break; \ } \ memcpy((blob), (useblob), (blobsize)); \ if ((stateblobsize) != (usestatesize)) { \ TRACE_ERROR("%s usestatesize wrong \n", \ __func__); \ (rc) = CKR_ARGUMENTS_BAD; \ break; \ } \ memcpy((stateblob), (usestate), \ (stateblobsize)); \ } \ if (((ep11_private_data_t *)(tokdata)-> \ private_data)->mk_change_active && \ retry == 0 && \ (((newstate) && (rc) == CKR_OK) || \ (!(newstate) && \ (rc) != CKR_IBM_WKID_MISMATCH && \ (rc) != CKR_IBM_TARGET_INVALID && \ (rc) != CKR_FUNCTION_FAILED))) { \ /* worked, re-encipher updated state blob */ \ TRACE_DEVEL("%s reencipher updated state " \ "blob\n", __func__); \ rc2 = ep11tok_reencipher_blob((tokdata), \ (session), \ &(target_info), \ (stateblob), \ (stateblobsize), \ (reencstate)); \ if (rc2 == CKR_IBM_WK_NOT_INITIALIZED) { \ /* Single APQN now has new WK */ \ TRACE_DEVEL("%s WKID mismatch on " \ "reencipher, retry\n", \ __func__); \ __sync_or_and_fetch(&(target_info)-> \ single_apqn_has_new_wk,\ 1); \ continue; \ } \ if (rc2 != CKR_OK) { \ (rc) = CKR_DEVICE_ERROR; \ TRACE_ERROR("%s\n", \ ock_err(ERR_DEVICE_ERROR)); \ break; \ } \ } \ break; \ } while (1); \ } while (0); /* * Macros to enclose EP11 library calls that create 1 or 2 key blobs as output. * If a master key change is active, and the key blob(s) were created with the * new WK, copy them to the re-enciphered blob(s) and indicate that the * single APQN has the new WK. * If a master key change is active, and the key blob(s) were created with the * old WK, re-encipher the key blob(s). * If re-enciphering fails with CKR_IBM_WK_NOT_INITIALIZED, because the new WK * was just activated on the single APQN, indicate that the single APQN has * the new WK, and retry the EP11 library call. This creates new key blob(s) * that are then enciphered with the new WK. */ #define RETRY_REENC_CREATE_KEY_START() \ RETRY_REENC_CREATE_KEY2_START() #define RETRY_REENC_CREATE_KEY_END(tokdata, session, target_info, blob, \ reencblob, blobsize, rc) \ RETRY_REENC_CREATE_KEY2_END(tokdata, session, \ target_info, blob, \ reencblob, blobsize, blob, \ reencblob, 0, rc) #define RETRY_REENC_CREATE_KEY2_START() \ do { \ do { \ #define RETRY_REENC_CREATE_KEY2_END(tokdata, session, target_info, blob1,\ reencblob1, blobsize1, blob2, \ reencblob2, blobsize2, rc) \ if (((ep11_private_data_t *)(tokdata)-> \ private_data)->mk_change_active && \ (rc) == CKR_OK) { \ /* Key creation successful */ \ if (ep11tok_is_blob_new_wkid((tokdata), \ (blob1), (blobsize1)) || \ ((blobsize2) > 0 && \ ep11tok_is_blob_new_wkid((tokdata), \ (blob2), (blobsize2)))) { \ /* Key created with new WK already: supply it in reencblob as well */ \ TRACE_DEVEL("%s new key has new WK\n", \ __func__); \ memcpy((reencblob1), (blob1), \ (blobsize1)); \ if ((blobsize2) > 0) \ memcpy((reencblob2), (blob2), \ (blobsize2)); \ __sync_or_and_fetch(&(target_info)-> \ single_apqn_has_new_wk, \ 1); \ } else { \ /* created with old WK, re-encipher it */\ TRACE_DEVEL("%s new key has old WK, " \ "reencipher it\n", __func__);\ (rc) = ep11tok_reencipher_blob((tokdata),\ (session), \ &(target_info), (blob1), \ (blobsize1), (reencblob1)); \ if ((rc) == CKR_IBM_WK_NOT_INITIALIZED) {\ /* Single APQN now has new WK, repeat key creation. */ \ TRACE_DEVEL("%s WKID mismatch on " \ "reencipher, retry\n", \ __func__); \ continue; \ } \ if ((rc) != CKR_OK) { \ (rc) = CKR_DEVICE_ERROR; \ TRACE_ERROR("%s\n", \ ock_err(ERR_DEVICE_ERROR)); \ break; \ } \ if ((blobsize2) > 0) { \ (rc) = ep11tok_reencipher_blob( \ (tokdata), (session), \ &(target_info), \ (blob2), (blobsize2), \ (reencblob2)); \ if ((rc) == \ CKR_IBM_WK_NOT_INITIALIZED) {\ /* Single APQN now has new WK, repeat key creation. */ \ TRACE_DEVEL("%s WKID mismatch " \ "on reencipher, retry\n",\ __func__); \ continue; \ } \ if ((rc) != CKR_OK) { \ (rc) = CKR_DEVICE_ERROR; \ TRACE_ERROR("%s\n", \ ock_err(ERR_DEVICE_ERROR)); \ break; \ } \ } \ } \ } \ break; \ } while (1); \ } while (0); #endif opencryptoki-opencryptoki-451d99c/usr/lib/ep11_stdll/ep11_stdll.mk000066400000000000000000000053471520105705100251650ustar00rootroot00000000000000nobase_lib_LTLIBRARIES += opencryptoki/stdll/libpkcs11_ep11.la EXTRA_DIST += usr/lib/ep11_stdll/ep11tok.conf usr/lib/ep11_stdll/ep11cpfilter.conf noinst_HEADERS += \ usr/lib/ep11_stdll/ep11.h usr/lib/ep11_stdll/ep11adm.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 \ -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 -I${top_builddir}/usr/lib/api \ -I${srcdir}/usr/lib/api -I${top_builddir}/usr/lib/config \ -I${srcdir}/usr/lib/config -I${srcdir}/usr/lib/hsm_mk_change \ -I${top_builddir}/usr/lib/hsm_mk_change opencryptoki_stdll_libpkcs11_ep11_la_LDFLAGS = \ -shared -Wl,-z,defs,-Bsymbolic -lc -lpthread -lcrypto -lrt \ -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/common/profile_obj.c \ usr/lib/common/dlist.c usr/lib/common/mech_pqc.c \ usr/lib/ep11_stdll/new_host.c usr/lib/common/mech_openssl.c \ usr/lib/ep11_stdll/ep11_specific.c \ usr/lib/ep11_stdll/ep11_session.c \ usr/lib/ep11_stdll/ep11_login.c \ usr/lib/ep11_stdll/ep11_mkchange.c \ usr/lib/common/utility_common.c usr/lib/common/ec_supported.c \ usr/lib/api/policyhelper.c usr/lib/config/configuration.c \ usr/lib/config/cfgparse.y usr/lib/config/cfglex.l \ usr/lib/common/pqc_supported.c \ usr/lib/hsm_mk_change/hsm_mk_change.c \ usr/lib/common/btree.c usr/lib/common/sess_mgr.c if !NO_PKEY opencryptoki_stdll_libpkcs11_ep11_la_SOURCES += \ usr/lib/common/pkey_utils.c endif opencryptoki-opencryptoki-451d99c/usr/lib/ep11_stdll/ep11adm.h000066400000000000000000001561431520105705100242660ustar00rootroot00000000000000/* * (C) Copyright IBM Corp. 2012, 2025 * * 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 * *---------------------------------------------------------------------- * EP11 service mail address: EP11SERV@de.ibm.com * * Use this mail address for Bugs and Comments with the EP11 product. *---------------------------------------------------------------------- */ #if ! defined(__xcpadm_h__) #define __xcpadm_h__ #if !defined(INT64_MIN) #error "We need 32/64-bit types, please include before this file." #endif #if !defined(XCP_SERIALNR_CHARS) #error "We need types, please include before this file." #endif //------------------------------------- // flags common to all functions that have a flag parameter // #define XCP_ADMFL_DOMAIN 1 // query/command targets domain not full card #define XCP_ADMFL_FORCE 0x80 // force an action otherwise canceled //------------------------------------- // error codes returned by administrative functions // for common error codes see the XCP_E* defines in ep11.h // if not noted otherwise a function returns XCP_OK for successfully completion // see the header of the functions for more details about the errors // // generic administrative errors #define XCP_ADMERR_MIN ((long)(1UL<<(sizeof(long)*8-1))) /* all error codes > XCP_ADMERR_MIN. */ #define XCP_ADMERR_QUERY_FAILED (XCP_ADMERR_MIN+0x101) #define XCP_ADMERR_NOT_ENOUGH_SIGNATURES (XCP_ADMERR_MIN+0x102) #define XCP_ADMERR_SIGNING_CB_FAILED (XCP_ADMERR_MIN+0x103) #define XCP_ADMERR_COMMAND_FAILED (XCP_ADMERR_MIN+0x104) #define XCP_ADMERR_CARD_CPS_QUERY (XCP_ADMERR_MIN+0x105) #define XCP_ADMERR_CMD_UNEXPECTED_RV (XCP_ADMERR_MIN+0x106) #define XCP_ADMERR_COMPLIANCE_MODE_CONFLICT (XCP_ADMERR_MIN+0x107) #define XCP_ADMERR_NEEDS_FORCE (XCP_ADMERR_MIN+0x108) #define XCP_ADMERR_CTR_SIZE_INVALID (XCP_ADMERR_MIN+0x109) // signerinfo related errors #define XCP_ADMERR_SI_HSH_MECH_UNSUPPORTED (XCP_ADMERR_MIN+0x151) #define XCP_ADMERR_SI_SIG_MECH_UNSUPPORTED (XCP_ADMERR_MIN+0x152) #define XCP_ADMERR_SI_OID_MECH_MISMATCH (XCP_ADMERR_MIN+0x153) #define XCP_ADMERR_SI_SIG_EMPTY (XCP_ADMERR_MIN+0x154) #define XCP_ADMERR_SI_SIZE (XCP_ADMERR_MIN+0x155) // recipientinfo related errors #define XCP_ADMERR_RI_ENC_EMPTY (XCP_ADMERR_MIN+0x181) #define XCP_ADMERR_RI_UKM_INVALID (XCP_ADMERR_MIN+0x182) #define XCP_ADMERR_RI_IMPR_INVALID (XCP_ADMERR_MIN+0x183) #define XCP_ADMERR_RI_RSA_ALG_INVALID (XCP_ADMERR_MIN+0x184) #define XCP_ADMERR_RI_KWRAPSIZE_INVALID (XCP_ADMERR_MIN+0x185) #define XCP_ADMERR_RI_ECPUB_INVALID (XCP_ADMERR_MIN+0x186) #define XCP_ADMERR_RI_SKI_INVALID (XCP_ADMERR_MIN+0x187) #define XCP_ADMERR_RI_RSA_OID_INVALID (XCP_ADMERR_MIN+0x188) #define XCP_ADMERR_RI_EC_OID_INVALID (XCP_ADMERR_MIN+0x189) #define XCP_ADMERR_RI_VERSION_INVALID (XCP_ADMERR_MIN+0x18a) #define XCP_ADMERR_RI_KWRAPALG_INVALID (XCP_ADMERR_MIN+0x18b) #define DOMAIN_MASK_LENGTH XCP_DOMAINS/8 // space for 256 domains //------------------------------------- // Key-Part-Holder template // contain credentials of a key-part holder. Those credentials // can be file based and/or smart card based references. struct KPH { const unsigned char *cert; // certificate size_t clen; // certificate length const char *id; // private key const char *pw; // private key passphrase const char *kpfname; // filename of the key-part char scard; // indicates a smart card user char ski_id; // subject key identifier ID int rdr_id; // smart card reader number char kp_id; // key-part ID uint64_t sigmech; // signature mechenism const char *padmode; // padding mode } ; //------------------------------------- // Export WK Request template (including preamble for import state command) // // requesting 2-of-n keyparts // // append n certificate sections and load with XCP_ADM_IMPORT_STATE command // certificate sections are ASN.1 octet strings starting with a 2-Byte tag // value of 0x1d followed by the four Byte certificate index followed by the // certificate: // 0x04,0x82,0x02,0x32, // 0x00,0x1d, // 0x00,0x00,0x00,0x01, // ...cert data... // static const unsigned char expreqhdr[] = { 0x00,0x00,0x00,XCP_FILEID_EXPREQUEST, /* export file id */ 0x00,0x00,0x00,0x00, /* offset, 0 for full file */ 0x00,0x00,0x00,0x00, /* length of part following */ 0x30,0x82,0x00,0x00, } ; //------------------------------------- // admin response structure 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; // #define XCP_ADMRESP_INIT0 { 0,0,0, {0},{0},{0}, {0}, CKR_OK, 0, NULL,0, } //------------------------------------- // listing of CP modes with their respective sets of control points that are // either required or prohibited // // the CPs that can never be turned on are not included in any compliance // modes prohibited list (see XCP_CPB_ALG_RAW_RSA, XCP_CPB_KEYSZ_BELOW80BIT, // XCP_CPB_KEYSZ_HMAC_ANY, XCP_CPB_SKIP_KEYTESTS and XCP_CPB_ALG_NBSI2009) // static const struct { uint32_t mode; const char *name; unsigned int num_prohibited; XCP_CPbit_t prohibited[ XCP_CPCOUNT ]; unsigned int num_required; XCP_CPbit_t required[ XCP_CPCOUNT ]; } ep11_cpt_modes[] = { { XCP_ADMS_FIPS2009, "fips2009", // default mode, can't be left 0, { }, 0, { }, }, { XCP_ADMS_FIPS2011, "fips2011", 3, { XCP_CPB_ALG_NFIPS2011, XCP_CPB_KEYSZ_80BIT, XCP_CPB_KEYSZ_RSA65536, }, 0, { }, }, { XCP_ADMS_BSI2009, "bsi2009", 2, { XCP_CPB_ALG_NBSI2009, XCP_CPB_NON_ATTRBOUND }, 0, { }, }, { XCP_ADMS_BSI2011, "bsi2011", 3, { XCP_CPB_ALG_NBSI2011, XCP_CPB_NON_ATTRBOUND, XCP_CPB_KEYSZ_80BIT }, 0, { }, }, { XCP_ADMS_BSICC2017, "bsicc2017", 12, { XCP_CPB_NON_ATTRBOUND, XCP_CPB_RNG_SEED, XCP_CPB_KEYSZ_RSA65536, XCP_CPB_USER_SET_TRUSTED, XCP_CPB_ALG_SKIP_CROSSCHK, XCP_CPB_WRAP_CRYPT_KEYS, XCP_CPB_SIGN_CRYPT_KEYS, XCP_CPB_WRAP_SIGN_KEYS, XCP_CPB_USER_SET_ATTRBOUND, XCP_CPB_ALLOW_PASSPHRASE, XCP_CPB_WRAP_STRONGER_KEY, XCP_CPB_WRAP_WITH_RAW_SPKI }, 27, { XCP_CPB_SIGN_ASYMM, XCP_CPB_ENCRYPT_SYMM, XCP_CPB_DECRYPT_ASYMM, XCP_CPB_DECRYPT_SYMM, XCP_CPB_WRAP_ASYMM, XCP_CPB_WRAP_SYMM, XCP_CPB_UNWRAP_ASYMM, XCP_CPB_UNWRAP_SYMM, XCP_CPB_KEYGEN_ASYMM, XCP_CPB_KEYGEN_SYMM, XCP_CPB_RETAINKEYS, XCP_CPB_MODIFY_OBJECTS, XCP_CPB_ALG_NBSI2009, XCP_CPB_KEYSZ_80BIT, XCP_CPB_KEYSZ_112BIT, XCP_CPB_KEYSZ_128BIT, XCP_CPB_KEYSZ_192BIT, XCP_CPB_KEYSZ_256BIT, XCP_CPB_ALG_RSA, XCP_CPB_ALG_DSA, XCP_CPB_ALG_EC, XCP_CPB_ALG_EC_BPOOLCRV, XCP_CPB_ALG_EC_NISTCRV, XCP_CPB_ALG_NFIPS2011, XCP_CPB_ALG_NBSI2011, XCP_CPB_ALG_DH, XCP_CPB_DERIVE }, }, { XCP_ADMS_FIPS2021, "fips2021", 17, { XCP_CPB_ALG_NFIPS2011, XCP_CPB_KEYSZ_80BIT, XCP_CPB_KEYSZ_RSA65536, XCP_CPB_ALG_NFIPS2021, XCP_CPB_ALG_EC_25519, XCP_CPB_ALG_PQC, XCP_CPB_BTC, XCP_CPB_ECDSA_OTHER, XCP_CPB_ALLOW_NONSESSION, XCP_CPB_ALG_EC_SECGCRV, XCP_CPB_ALG_EC_BPOOLCRV, XCP_CPB_COMPAT_LEGACY_SHA3, XCP_CPB_DSA_PARAMETER_GEN, XCP_CPB_WRAP_ASYMM, XCP_CPB_UNWRAP_ASYMM, XCP_CPB_ALLOW_LOGIN_PRE_F2021, XCP_CPB_ALG_RSA_OAEP }, 0, { }, }, { XCP_ADMS_FIPS2024, "fips2024", 18, { XCP_CPB_ALG_NFIPS2011, XCP_CPB_KEYSZ_80BIT, XCP_CPB_KEYSZ_RSA65536, XCP_CPB_ALG_NFIPS2021, XCP_CPB_ALG_EC_25519, XCP_CPB_ALG_PQC, XCP_CPB_BTC, XCP_CPB_ECDSA_OTHER, XCP_CPB_ALLOW_NONSESSION, XCP_CPB_ALG_EC_SECGCRV, XCP_CPB_ALG_EC_BPOOLCRV, XCP_CPB_ALG_NFIPS2024, XCP_CPB_COMPAT_LEGACY_SHA3, XCP_CPB_DSA_PARAMETER_GEN, XCP_CPB_WRAP_ASYMM, XCP_CPB_UNWRAP_ASYMM, XCP_CPB_ALLOW_LOGIN_PRE_F2021, XCP_CPB_ALG_RSA_OAEP }, 0, { }, // XCP_ADMC_ADM_FIPS2021 is not reported here as it is not set with // control points } } ; //------------------------------------- // Structure to collect all relevant data for state export/import // // statefname: file name of the serialized state data // restrict_mode: restriction mode // set to 0 -> no restriction (complete state export) // set to 1 -> XCP_STDATA_DOMAIN (domain data only) // set to 2 -> XCP_STDATA_NONSENSITIVE (non sensitive data) // domainmask: mask of domains to export/import // struct STATESAVE { const char *statefname; unsigned int restrict_mode; unsigned char domainmask[DOMAIN_MASK_LENGTH]; } ; //------------------------------------- // callback function prototype definition for library functions // that have to send sign commands but are not fixed on how // to generate the signatures // they take two parameters: // 1. a function pointer to the callback function // 2. a void pointer to an arbitrary data structure that gets directly // pass through to the call back function in the signopts parm // // should return >0 if requested signatures generated successfully // =0 not enough signatures could be generated // <0 anything else fails // typedef long (*xcpa_admin_signs_cb_t)(unsigned char *sigs, size_t slen, const unsigned char *data, size_t dlen, const void *signopts) ; //------------------------------------- // build a query block to (blk,blen), querying 'fn' // (payload,plen) copied to query block if non-NULL // // *minf used for module ID and transaction counter // ignored for commands where those fields are ignored // // returns written bytecount; size query if blk is NULL // <0 if anything fails // // Possible error return codes: // XCP_ETARGET: a group target is supplied // XCP_ESIZE: the payload is too big, the output buffer is too small or the // size of the query block can not be represented in a single // byte // This restriction will be lifted in the future if a need arises // long xcpa_queryblock(unsigned char *blk, size_t blen, unsigned int fn, target_t domain, const unsigned char *payload, size_t plen) ; //------------------------------------- // build a query block to (blk,blen), querying 'fn' // (payload,plen) copied to query block if non-NULL // // *minf used for module ID and transaction counter // ignored for commands where those fields are ignored // // returns written bytecount; size query if blk is NULL // <0 if anything fails // // Possible error return codes: // XCP_EARG: an argument is missing // XCP_ESIZE: the output buffer is too small // XCP_ADMERR_CTR_SIZE_INVALID: the transaction counter overflows // 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) ; //------------------------------------- // construct the DER encapsulation of cert replacement as follows (blk): // SEQUENCE { // OCTET STRING ski // OCTET STRING cert // } // // returns size of constructed sequence in success case. // <0 if anything fails // // Possible error return codes: // XCP_EARG: an argument is missing // XCP_ESIZE: blen is not big enough // long xcpa_certreplace(unsigned char *blk, size_t blen, const unsigned char *ski, size_t slen, const unsigned char *cert, size_t clen) ; //------------------------------------- // Queries the current/next WK for the given target // // WK Hash is returned in (*wk, wlen) on success if wk is not NULL // // returns >0 (bytecount) if present // 0 if valid but no current WK // <0 if anything failed // // Possible error return codes: // XCP_ERESPONSE: the domain info request failed // XCP_ADMERR_QUERY_FAILED: the WK query failed // XCP_ESIZE: the output buffer is too small // // Uses xcpa_queryblock() - See function header for possible return codes // long xcpa_query_wk(unsigned char *wk, size_t wlen, int type, target_t target) ; //------------------------------------- // get current module ID, transaction counter to *blk // performs card or module query, depending on 'is_card' // // copies all fields except 'payload', which will be left NULL // // basic sanity check on 'target' with NULL blk (SNH if target is present) // // flags e.g. domain or card, see XCP_ADMFL_... constants // // returns <0 if anything fails // 0 otherwise // // Possible error return codes: // XCP_ERESPONSE: outer return value is not CKR_OK. // XCP_ADMERR_QUERY_FAILED: inner return value indicated an error. See the // reason code for more information. // // Uses xcpa_queryblock() - See function header for possible return codes // long xcpa_state(struct XCPadmresp *blk, target_t target, unsigned int flags) ; //------------------------------------- // gets current instance id for domain // // returns <0 if query failed // 0 otherwise, setting *inst if non-NULL // // see xcpa_state() for possible error return values // long xcpa_dom_instance(uint32_t *inst, target_t target) ; //------------------------------------- // submit query/command block from (req,reqlen), optionally with signature/s // verify that return value (internal or external) matches exprv // // returns >0 if (rsp1,rsp1len) has been written. returns response size // 0 if size query (rsp1 is NULL) which was successful // (setting *rsp1len) if expecting CKR_OK OR // if encountered expected error, and not returning results // <0 otherwise // // points non-NULL rb to response, within (rsp1, rsp1len) if successful // non-NULL rv is updated to retrieved PKCS#11 result // // msg, rb, rv, (rsp2,rsp2len), (sigs,slen) are optional // non-NULL msg is used for annotating debug messages (not viewable by // customers) // (rsp2,rsp2len) contains reason code if provided by backend // // Possible error return codes: // XCP_EARG: missing arguments // XCP_ADMERR_CMD_UNEXPECTED_RV: the outer/inner rv does not match the // expected rv. see *rv for more information // XCP_EINVALID: transport error or invalid formated response // (unexpected) // long xcpa_admin_call(unsigned char *rsp1, size_t *rsp1len, unsigned char *rsp2, size_t *rsp2len, const unsigned char *req, size_t reqlen, const unsigned char *sigs, size_t slen, target_t target, const char *msg, struct XCPadmresp *rb, CK_RV *rv, CK_RV exprv) ; //------------------------------------- // flags >0 domain, otherwise card // // (*val) set to the requested integer attribute value // // returns 0 with the request int attr for the given target (card/domain) // <0 if something fails // // Possible error return codes: // XCP_EARG: bad arguments // // Uses xcpa_query_admin_attrs() - See function header for possible return codes // long xcpa_admin_attr(target_t target, unsigned int flags, XCP_AdmAttr_t attr, uint32_t *val) ; //------------------------------------- // flags e.g. domain or card, see XCP_ADMFL_... constants // // sets *mode to the operating mode of card/domain // // returns <0 if query failed // 0 if still imprinting, setting *mode to full word // >0 if out of imprint mode, setting *mode to full word // // See for possible error return codes xcpa_query_admin_attrs() // long xcpa_admin_attr_mode (target_t target, unsigned int flags, uint32_t *mode) ; //------------------------------------- // flags >0 domain, otherwise card // // Sets *perms to the permissions of card/domain // // returns <0 if query failed // 0 if 1-sign not allowed, setting *perms to full word // >0 if 1-sign allowed, setting *perms to full word // // See for possible error return codes xcpa_query_admin_attrs() // long xcpa_admin_attr_perms (target_t target, unsigned int flags, uint32_t *perms) ; //------------------------------------- // if *val is non-NULL, and index 'idx' is found, *val is set to its value // // updates a32[] entries which are within bounds, ignoring others // // returns 0 with val and a32 set when non-NULL // <0 if something fails // // Possible error return codes: // XCP_EARG: attrs is NULL or alen is too small // long xcpa_report_attrs_field (const unsigned char *attrs, size_t alen, uint32_t *a32, unsigned int acount, uint32_t idx, uint32_t *val) ; //------------------------------------- // returns bytecount written to (attrs,alen), which is 8*attribute count // size query with NULL attrs, ignoring alen // // a32[] is updated if non-NULL and has sufficient entries; // fails if a32 is non-NULL but acount is too low // indexes interpreted as one-based (attr indexes intentionally skip 0), // a32[] transformed back to zero-based representation // // *rb updated to current state, if non-NULL // // flags e.g. domain or card, see XCP_ADMFL_... constants // // Possible error return codes: // XCP_ADMERR_QUERY_FAILED: query failed (with reason code in *rb if non NULL) // XCP_EINVALID: response from card could not be correctly parsed // // Uses xcpa_queryblock() - See function header for possible return codes // long xcpa_query_admin_attrs(target_t target, unsigned char *attrs, size_t alen, uint32_t *a32, unsigned int acount, struct XCPadmresp *rb, unsigned int flags) ; //------------------------------------- // set attributes from pre-formated set-attr field in (attrs,alen) // // (*attrs, attributes to set // alen) // (sign_cb, provide the callback for generating signatures, // signopts) may be NULL if no signatures required, // see xcpl_admin_signs // flags e.g. domain or card, see XCP_ADMFL_... constants // exprv the expected return value to check for // // updates *rb if not NULL // // returns 0 on success (expected RV met) // <0 on failure // // Other possible return codes // XCP_ADMERR_SIGNING_CB_FAILED: signing callback failed // XCP_ADMERR_NOT_ENOUGH_SIGNATURES: not enough signatures to fulfill // threshold value // XCP_ADMERR_CMD_UNEXPECTED_RV: see reason code in *rb if non NULL // // uses xcpa_cmdblock() - see function header for more return codes // uses xcpa_state() if rb is NULL, see the function for possible return codes // uses xcpa_admin_call() - see function header for more return codes // // See rb->reason for the reason code in an error case. // long xcpa_set_admin_attrs(target_t target, unsigned char *attrs, size_t alen, struct XCPadmresp *rb, unsigned int flags, xcpa_admin_signs_cb_t sign_cb, const void *signopts, CK_RV exprv) ; //------------------------------------- // set single attribute // // (idx, val) attribute index and value to set // (sign_cb, // signopts) provide the callback for generating signatures, // may be NULL if no signatures required, // see xcpl_admin_signs // flags e.g. domain or card, see XCP_ADMFL_... constants // exprv the expected return value to check for // // updates *rb if not NULL // // returns 0 on success (expected RV met) // <0 on failure // // Other possible return codes // XCP_ADMERR_SIGNING_CB_FAILED: signing callback failed // XCP_ADMERR_NOT_ENOUGH_SIGNATURES: not enough signatures to fulfill // threshold value // XCP_ADMERR_CMD_UNEXPECTED_RV: see reason code in *rb if non NULL // // uses xcpa_cmdblock() - see function header for more return codes // uses xcpa_state() if rb is NULL, see the function for possible return codes // uses xcpa_admin_call() - see function header for more return codes // // See rb->reason for the reason code in an error case. // long xcpa_set_admin_attr(target_t target, uint32_t idx, uint32_t val, struct XCPadmresp *rb, unsigned int flags, xcpa_admin_signs_cb_t sign_cb, const void *signopts, CK_RV exprv) ; //------------------------------------- // returns bytecount written to (cps,cplen) // // *cps is updated if non-NULL and has sufficient size, see XCP_CP_BYTES // // *rb updated to current state, if non-NULL // // flags, must have domain, see XCP_ADMFL_... constants // // returns size of control points, if query was successful // <0 on failure // // uses xcpa_state() if rb is NULL, see the function for possible rc's // // Other possible return codes // XCP_ADMERR_CARD_CPS_QUERY: trying to get card control points which are // not supported // XCP_ADMERR_QUERY_FAILED: the CP query failed (see the reason code) // XCP_ESIZE: cplen is not large enough (cplen reason for the reason code in an error case. // long xcpa_set_cps(target_t target, const unsigned char *cps, /* XCP_CP_BYTES */ struct XCPadmresp *rb, unsigned int flags, xcpa_admin_signs_cb_t sign_cb, const void *signopts, CK_RV exprv) ; //------------------------------------- // get compliance mode from CP set (see ep11_cpt_modes[] for possible compliance // modes) // can not check for administrative compliance modes // // cps CP set of XCP_CP_BYTES length, see xcpa_query_cps // // returns >0 compliance mode (see XCP_ADMS_...) // // does not verify CP set // uint32_t xcpa_cps2compliance(const unsigned char *cps /* XCP_CP_BYTES */) ; //------------------------------------- // set compliance mode (domain only) // // mode compliance mode(s) to set (see XCP_ADMS_...) // (sign_cb, // signopts) provide the callback for generating signatures, // may be NULL if no signatures required, // see xcpl_admin_signs // flags e.g. domain or card, see XCP_ADMFL_... constants // exprv the expected return value to check for // // returns 0 on success // <0 on failure // // See xcpa_query_cps() and xcpa_set_cps() for possible error return codes // // updates *rb if not NULL // long xcpa_set_compliance(target_t target, uint64_t mode, struct XCPadmresp *rb, unsigned int flags, xcpa_admin_signs_cb_t sign_cb, const void *signopts) ; //-------------------------------------- // is bit number bitidx set in big-endian bitmask? // returns 0/1, not in-bitmask power-of-two value // // bitidx is zero-based; 0 -> 0x80 of first byte, 1 -> 0x40 of first byte etc. // // tolerates missing/too-small bitmask, which does not contain any set bits // static inline int xcpa_bitmask_has_bit(const unsigned char *bm, size_t bmbytes, const unsigned int bitidx) { return (bm && bmbytes && (bmbytes > bitidx / 8)) ? !!(bm[ bitidx /8 ] & ((unsigned char) 0x80 >> (bitidx %8))) : 0; } //-------------------------------------- // set bit number bitidx in big-endian bitmask to 0 (set==0) or 1 (set!=0) // returns 0/1, not in-bitmask/bit set // // bitidx is zero-based; 0 -> 0x80 of first byte, 1 -> 0x40 of first byte etc. // // tolerates missing/too-small bitmask // static inline int xcpa_bitmask_set_bit(unsigned char *bm, size_t bmbytes, const unsigned int bitidx, const unsigned int set) { if (!bm || !bmbytes || (bmbytes <= bitidx / 8)) return 0; if (set) bm[ bitidx /8 ] |= ((unsigned char) 0x80 >> (bitidx %8)); else bm[ bitidx /8 ] &= ~((unsigned char) 0x80 >> (bitidx %8)); return 1; } //------------------------------------- // test if specified CPbit is set // // returns 0/1, not in-bitmask power-of-two value // bitidx is zero-based; 0 -> 0x80 of first byte, 1 -> 0x40 of first byte etc. // // tolerates missing/too-small bitmask, which does not contain any set bits // static inline int xcpa_cpb_is_set(const unsigned char cps[ XCP_CP_BYTES ], const unsigned int cpbit) { return xcpa_bitmask_has_bit(cps, XCP_CP_BYTES, cpbit); } //------------------------------------- // enables a specific CP for the given CPs field, // do nothing if cps is NULL or cpbit greater than XCP_CPBITS_MAX // static inline void xcpa_cpb_add(unsigned char cps[ XCP_CP_BYTES ], const unsigned int cpbit) { if ((NULL != cps) && (XCP_CPBITS_MAX >= cpbit)) cps[ cpbit /8 ] |= (unsigned char) (0x80 >> (cpbit %8)); } //------------------------------------- // enable a specific CP for the given CPs field, // do nothing if cps is NULL or cpbit greater than XCP_CPBITS_MAX // static inline void xcpa_cpb_del(unsigned char cps[ XCP_CP_BYTES ], const unsigned int cpbit) { if ((NULL != cps) && (XCP_CPBITS_MAX >= cpbit)) cps[ cpbit /8 ] &= ~((unsigned char) (0x80 >> (cpbit %8))); } //------------------------------------- // call with full-sized CP bitmask (XCP_CP_BYTES) // returns 0/1, not bit position // #define CPB_IS_SET(cps, cpbit) xcpa_cpb_is_set((cps), (cpbit)) // call with full-sized CP bitmask (XCP_CP_BYTES) // returns 0/1 // #define CPB_ADD(cps, cpbit) xcpa_cpb_add((cps), (cpbit)) // call with full-sized CP bitmask (XCP_CP_BYTES) // returns 0/1 // #define CPB_DEL(cps, cpbit) xcpa_cpb_del((cps), (cpbit)) //------------------------------------- // supported size for user key material #define XCP_RI_UKM_BYTES 40 // // key import typedef struct Encrdkey { // EC only: RSA recipients must keep these lengths 0 // // largest supported curve: P-521 unsigned char srcprivate[ 66 ]; /* private key (PKCS#8) */ size_t sprivlen; /* priv. key byte count */ unsigned char *oid; /* EC curve OID */ size_t olen; /* EC curve OID length */ unsigned char srcpublic[ 1+66+66 ]; /* originator public point */ size_t splen; /* pub. point bytecount */ unsigned char ukm[ XCP_RI_UKM_BYTES ]; /* user keymaterial */ size_t ulen; // // /EC-only parameters // importer information const unsigned char *spki; size_t spkilen; unsigned char ski[ XCP_CERTHASH_BYTES ]; int ktype; /* one of the wire-specified types */ CK_MECHANISM *alg; /* currently, ignored */ unsigned char wrap_alg[25]; /* AES Key Wrap algorithm OID */ // largest supported importer type: 4096-bit RSA unsigned char raw[ 4096/8 ]; /* actual encrypted bytes */ size_t rlen; } *Encrdkey_t; //------------------------------------- // Recipient info used for encrypted key part transport // typedef struct Recipient_info { uint32_t version; /* struct version */ unsigned char data[ 1024 ]; /* ASN.1 encoded recipient info */ size_t dlen; /* length of recipient info */ } *Recipient_info_t; //------------------------------------- // turn user key material (UKM), target key bitcount, wrapping alg into // RFC 3278 SharedInfo structure // // We currently only support UKMs of size where the compound has a single-byte // size (i.e., <=0x7f bytes). This is an arbitrary limitation, and may be // removed in the future. // // kbits,wrapalg currently only take default zero (0->256, 0->AES256/wrap) // size restriction on ulen, see above // // returns written size, or failure if anything is invalid // size query (sinfo == NULL) returns exact size, not a conservative estimate // // Other possible return codes // XCP_ADMERR_RI_KWRAPSIZE_INVALID: invalid key wrap size (not zero or 256) // XCP_ADMERR_RI_KWRAPALG_INVALID: invalid key wrap algorithm (not zero) // XCP_ADMERR_RI_UKM_INVALID: invalid user key material (size) // XCP_ESIZE: too small output buffer // long xcp_rcptinfo_sharedinfo(unsigned char *sinfo, size_t slen, const unsigned char *ukm, size_t ulen, unsigned int kbits, int wrapalg) ; //------------------------------------- // creates RecipientInfo ASN.1 sequence (asn) from encr structure following RFC // 3852 for RSA and RFC 5753 for EC // // verifies if a known importer key is used and if the SPKI does match // the importer key type // // returns size of created rcptinfo if RecipientInfo could be created // <0 if an error occurred // // Other possible return codes // XCP_EARG: if encr is missing // XCP_ADMERR_RI_IMPR_INVALID: if the importer type or the key import structure // encr is not supported / invalid // long xcp_rcptinfo (unsigned char *asn, size_t alen, const struct Encrdkey *encr, const CK_MECHANISM *encrmech) ; //------------------------------------- // reads ASN.1 formatted RecipientInfo (asn) and turns it into rinfo structure // // returns size of RecipientInfo if asn could be read and rinfo (if non NULL) // could be filled. Otherwise return failure. // // Note: Depending on the ASN.1 information xcp_rcptinfo_read() may not // necessarily update all available fields of the Encrdkey structure. // It will not wipe the Encrdkey structure before, hence it may contain // unfilled sections. It's recommended to provide a zeroized Encrdkey struct. // // possible error return codes: // XCP_EARG: missing RecipientInfo // XCP_EINVALD: invalid ASN.1 formated sequence // XCP_ADMERR_RI_VERSION_INVALID: invalid rcptinfo version // XCP_ADMERR_RI_SKI_INVALID: SKI (size) invalid // XCP_ADMERR_RI_RSA_OID_INVALID: No valid RSA OID (unsupported or invalid) // XCP_ADMERR_RI_EC_OID_INVALID: No valid EC OID (unsupported or invalid) // XCP_ADMERR_RI_IMPR_INVALID: Public key size does not match supporte // importer key type // XCP_ADMERR_RI_ECPUB_INVALID: invalid public key bit string // XCP_ESIZE: EC public key is bigger then the Encrdkey // structure can encompass // long xcp_rcptinfo_read (struct Encrdkey *rinfo, const unsigned char *asn, size_t alen) ; //------------------------------------- // construct administrative request for key part import: // // xcpAdminReq ::= SEQUENCE // functionId OCTET STRING, -- m_admin() // domain OCTET STRING, -- raw domain (wire 6.2) (4 bytes) // administrative OCTET STRING encapsulates { // command xcpAdminBlk // } // signatures OCTET STRING { // -- signerInfo/s, without encapsulating SET OF // } // // returns size of created request if successfully // <0 if an error occurred // // Other possible return codes // XCP_EARG: arguments are missing // XCP_ESIZE: output buffer is too small or olen/slen are too big // long xcpa_import_keypart (unsigned char *out, size_t olen, const unsigned char *cmdblk, size_t clen, const unsigned char *sig, size_t slen, const struct XCPadmresp *minf, const target_t target) ; //------------------------------------- // construct single import piece: one command block with one recipientInfo // to be signed by one admin // xcpa_import_keypart() turns this block and its signature into final form // // restrictions: RSA keys must have 2048, 3072 or 4096-bit modulus with exponent // 0x10001. EC must be one of the supported importers // // SPKI used only to find out importer key type; SKI identifies recipient // both must be already imported into *key // // module info (minf) must be identical to all simultaneously imported parts // // tctr is transaction counter; if non-NULL, must be XCP_ADMCTR_BYTES // otherwise derived from minf // // returns length of ASN.1 formated command block if successful, otherwise error // // possible error return codes: // XCP_EARG: missing parameters // XCP_ADMERR_RI_ENC_EMPTY: spki not supplied within Encrdkey struture // XCP_ADMERR_RI_IMPR_INVALID: importer key type invalid / unsupported or does // not match SPKI // // uses xcpa_cmdblock() - see function header for more return codes // long xcpa_import_cmdblock (unsigned char *out, size_t olen, const struct Encrdkey *key, const struct XCPadmresp *minf, const unsigned char *tctr) ; //------------------------------------- // Validate if EC OID does match any supported EC importer type // Sets importer type in type if not NULL // // Return 0 if no match and 1 for match and XCP_EARG if an OID is not supplied int xcp_valid_ec_oid2imprtype(XCP_IMPRKEY_t *type, const unsigned char *oid, size_t olen) ; //------------------------------------- // Matches importer type to EC OID // Sets EC OID in oid if not NULL // // Returns 0 if no match and 1 for match int xcp_valid_ec_imprtype2oid(const unsigned char **oid, size_t *olen, XCP_IMPRKEY_t type) ; //------------------------------------- // parse embedded return value from response, writes to *rv if non-NULL // (outside envelope always reports CKR_OK, unless infrastructure failed) // // possible error return codes: // XCP_EINVALID: response is malformed or contents invalid // XCP_EARG: arguments are missing // long xcpa_internal_rv(const unsigned char *rsp, size_t rlen, struct XCPadmresp *rspblk, CK_RV *rv) ; //------------------------------------- // returns net bytecount (full T+L+V) if start of (asn,alen) is full tag // 0 if invalid // // sets *voffs to T+L bytecount if non-NULL // size_t xcpa_asn_tag(size_t *voffs, const unsigned char *asn, size_t alen); //------------------------------------- // return raw bytecount of ASN.1 SEQ // return XCP_EINVALID if malformed and XCP_ESIZE if ASN.1 lengths are not // correct // long xcpa_asn_bytes(const void *asn, size_t alen); //------------------------------------- // return offset of value in ASN.1 SEQ // return XCP_EINVALID if malformed and XCP_ESIZE if ASN.1 lengths are not // correct // long xcpa_asn_value_offset(const void *asn, size_t alen) ; //------------------------------------- // nonzero tag is compared to that of (asn,alen) // returns T+L+V bytecount in case of success // XCP_EINVALID if asn is malformed // XCP_EARG if asn or alen arguments are invalid // XCP_ESIZE if ASN.1 lengths are not correct // long xcpa_asn_tlv (const void *asn, size_t alen, unsigned int tag, size_t *voffset, size_t *vbytes); //------------------------------------- // DH ASN.1 SEQ's need to be split up, since we only need public value (X) // full input is (potentially MACed) DH SPKI // // SEQUENCE { // SEQUENCE { // ...OID, P, G /* not verified */ // } // BIT STRING { /* 0 unused bits -> single-byte 00 before INT // INTEGER { // Y /* reminder: possibly with leading zero/es */ // } // } // } // // bits is derived from SEQUENCE if 0 (not currently used/supported!) // must be full bytes, otherwise (no partial-byte moduluses supported) // // returns >0 if recognized; X is at (pub+offs, length) // 0 if input appears to be invalid // size_t xcpa_dh_asn2y(const unsigned char *pub, size_t plen, size_t *offs); //------------------------------------- // parses public value (Y) from Diffie-Hellman public key (ASN) // accepts MACed public keys // // sets *offs to offset of Y within (asn,alen) if non-NULL // // returns >0 if parsing successful (raw bytecount of public value) // 0 if anything failed, logging reason // size_t xcpa_dh_pub2y(size_t *offs, const unsigned char *asn, size_t alen); //------------------------------------- // EC ASN.1 SEQ's need to be split up, since we only need public value (X) // full input is (potentially MACed) DH SPKI // // SEQUENCE { // SEQUENCE { // OID(EC) // OID(curve) /* not verified */ // } // BIT STRING { /* 0 unused bits -> single-byte 00 before INT // Y /* raw value */ // } // } // // bits is derived from SEQUENCE if 0 (not currently used/supported!) // must be full bytes, otherwise (no partial-byte moduluses supported) // // returns >0 if recognized; X is at (pub+offs, length) // 0 if input appears to be invalid // size_t xcpa_ec_asn2y(const unsigned char *pub, size_t plen, size_t *offs); //------------------------------------- // parses public value (Y) from EC public key (ASN) // accepts MACed public keys // // sets *offs to offset of Y within (asn,alen) if non-NULL // // returns >0 if parsing successful (raw bytecount of public value) // 0 if anything failed, logging reason // size_t xcpa_ec_pub2y(size_t *offs, const unsigned char *asn, size_t alen); //------------------------------------- // generates the export request in an ASN.1 structure // reuired for export wk or export state // // asn pointer to the resulting ASN.1 buffer // alen max. ASN.1 buffer len // certs pointer to the KPH certificates // ccnt number of KPHs // exportstate set to 0 if exportwk is requested // set to 1 if exportstate is requested // statesave contains properties for exportstate // restriction_mask mask of exportwk restrictions long xcpa_fill_export_req(unsigned char *asn, size_t alen, const struct KPH *certs, unsigned int ccnt, int exportstate, struct STATESAVE *statesave, uint32_t restriction_mask); //------------------------------------- // Constructs key part file with ASN.1 envelope // writes output to (*reqprep, reqpreplen) // // domainmask target domain mask // kphs keypart holder certificates // kcnt number of kphs // ekps contains re-encrypted keyparts // reqprep output buffer // reqpreplen output length // headerinfo set to 0 if no header info requested // set to 1 if header info requested // // returns 0 if successful // <0 if something fails long xcpa_construct_keypart_file(unsigned char *domainmask, const struct KPH *kphs, const struct Encrdkey *ekps, unsigned int kcnt, unsigned char *reqprep, size_t *reqpreplen, unsigned int headerinfo); //------------------------------------- // Enable export WK permission // // target target domain // sign_cb provide the callback for generating signatures // may be NULL if no signatures required // signopts number of signatures requested long xcpa_enable_exportwk(target_t target, xcpa_admin_signs_cb_t sign_cb, const void *signopts); //------------------------------------- // Enable export state permission // // target target module/domain // sign_cb provide the callback for generating signatures // may be NULL if no signatures required // signopts number of signatures requested // long xcpa_enable_export_state(target_t target, xcpa_admin_signs_cb_t sign_cb, const void *signopts); //------------------------------------- // Enable import WK permission // // target target domain // sign_cb provide the callback for generating signatures // may be NULL if no signatures required // signopts number of signatures requested long xcpa_enable_importwk(target_t target, xcpa_admin_signs_cb_t sign_cb, const void *signopts); //------------------------------------- // Enable import state permission // // target target module/domain // sign_cb provide the callback for generating signatures // may be NULL if no signatures required // signopts number of signatures requested // long xcpa_enable_import_state(target_t target, xcpa_admin_signs_cb_t sign_cb, const void *signopts); //------------------------------------- // Export the domain WK of the given target // writes output to (*resp, resplen) // // target addresses target module/domain // wktype indicates either current or next WK // keyparts pointer to the encrypted keyparts // keypartlen length of encrypted keyparts // request pointer to the export request data // requestlen length of request data // sign_cb provide the callback for generating signatures // may be NULL if no signatures required // signopts number of signatures requested long xcpa_export_wk(target_t target, int wktype, unsigned char *keyparts, size_t *keypartlen, const unsigned char *request, size_t requestlen, xcpa_admin_signs_cb_t sign_cb, const void *signopts); //------------------------------------- // Export the state of the given target // writes output to (*state/statelen, tkps/tkpslen) // // target addresses target module/domain // state pointer to exported state data // statelen length of exported state data // keyparts pointer to transport keyparts // keypartlen length of transport keyparts // request pointer to the export request // requestlen length of export request // sign_cb provide the callback for generating signatures // may be NULL if no signatures required // signopts number of signatures requested // long xcpa_export_state(target_t target, unsigned char *state, size_t *statelen, unsigned char *tkps, size_t *tkplen, const unsigned char *request, size_t requestlen, xcpa_admin_signs_cb_t sign_cb, const void *signopts); //------------------------------------- // Import a domain WK (from recipient info) to the given target // // target addresses target module/domain // rinfo contains recipient infos // ricnt number of recipient infos // wkvp WK verification pattern // sign_cb provide the callback for generating signatures // may be NULL if no signatures required // signopts number of signatures requested long xcpa_import_wk_rcptinfo(target_t target, struct Recipient_info *rinfo, unsigned int ricnt, const unsigned char *wkvp, xcpa_admin_signs_cb_t sign_cb, const void *signopts); //------------------------------------- // Import a domain WK (from ekps struct) to the given target // // target addresses target module/domain // ekps contains re-encrypted keyparts // kcnt number of keyparts // wkvp WK verification pattern // sign_cb provide the callback for generating signatures // may be NULL if no signatures required // signopts number of signatures requested long xcpa_import_wk(target_t target, const struct Encrdkey *ekps, unsigned int kcnt, const unsigned char *wkvp, xcpa_admin_signs_cb_t sign_cb, const void *signopts); //------------------------------------- // Import module state data to a target // // target addresses target module // domainmask list of affected domains // ekps contains re-encrypted keyparts // kpcnt number of keyparts // state module state data // statelen state data len // sign_cb provide the callback for generating signatures // may be NULL if no signatures required // signopts number of signatures requested // long xcpa_import_state(target_t target, unsigned char *domainmask, unsigned char *state, size_t statelen, struct Encrdkey *ekps, unsigned int kpcnt, xcpa_admin_signs_cb_t sign_cb, const void *signopts); //------------------------------------- // Commit a domain WK of the given target // // target addresses target module/domain // wkvp WK verification pattern // sign_cb provide the callback for generating signatures // may be NULL if no signatures required // signopts number of signatures requested long xcpa_commit_wk(target_t target, const unsigned char *wkvp, xcpa_admin_signs_cb_t sign_cb, const void *signopts); //------------------------------------- // Finalize a domain WK of the given target // // target addresses target module/domain // wkvp WK verification pattern long xcpa_finalize_wk(target_t target, const unsigned char *wkvp); //------------------------------------- // Generate a random WK for the given target // // target addresses target module/domain // wkvp WK verification pattern // sign_cb provide the callback for generating signatures // may be NULL if no signatures required // signopts number of signatures requested long xcpa_gen_random_wk(target_t target, unsigned char *wkvp, xcpa_admin_signs_cb_t sign_cb, const void *signopts); //------------------------------------- // SKI-based SignerInfo form // // 30(02(03) // v3: signer identified by SKI // 80(...SKI...) // 30(...digest OID...) // 30(...signature_alg OID...) // 04(...signature...) // ) // // we construct ASN.1 following these rules: // 1. lengths, except that of the signature, are single-byte (<127) // - this is true for all forms we support // 2. signature and whole SEQUENCE use two-byte length fields (82 xx yy) // 3. version is minimal-encoded // 4. OIDs always contain trailing NULL (05 00) // - we tolerate the lack of this, see si_read below // sigmech may be a combined hash+sign mechanism, then hashmech is ignored // // placeholder 'signature' is added if sig is NULL: siglen is bytecount then // // if encoding a generic 'rsaEncryption' mode, use CKM_RSA_X_509 and // separate hash in hashmech // // returns length of ASN.1 formated SignerInfo if successful, otherwise failure // // possible error return codes: // XCP_EARG: missing arguments or bad ski length // XCP_ADMERR_SI_SIZE: bad signature length // XCP_ESIZE: other lengths are over the 127 limit // or output buffer too small // XCP_ADMERR_SI_SIG_MECH_UNSUPPORTED: unsupported signature mechanism // XCP_ADMERR_SI_HSH_MECH_UNSUPPORTED: unsupported hash mechanism // XCP_ADMERR_SI_OID_MECH_MISMATCH: mismatch between signature and hash // mechanism // long xcp_signerinfo (unsigned char *asn, size_t alen, const unsigned char *ski, size_t skilen, /* signer */ const unsigned char *sig, size_t siglen, const CK_MECHANISM *sigmech, const CK_MECHANISM *hashmech) ; //------------------------------------- // checks if valid and parses signer info into components // // (ski,skilen) and (sig,siglen) are within (sinfo,silen), if set // // returns signerinfo struct bytecount if successful // // possible error return codes: // XCP_EARG: missing arguments // XCP_EINVALID: could not read signerinfo // XCP_ADMERR_SI_SIG_EMPTY: no signature present // XCP_ADMERR_SI_SIG_MECH_UNSUPPORTED: unsupported signature mechanism // XCP_ADMERR_SI_HSH_MECH_UNSUPPORTED: unsupported hash mechanism // XCP_ADMERR_SI_OID_MECH_MISMATCH: mismatch between signature and hash // mechanism // // no length checks on signature or SKI, other than checking both for non-empty // long xcp_signerinfo_read (const unsigned char *sinfo, size_t silen, const unsigned char **ski, size_t *skilen, const unsigned char **sig, size_t *siglen, const unsigned char **hoid, size_t *hoidlen, const unsigned char **soid, size_t *soidlen, CK_MECHANISM *signmech, CK_MECHANISM *hashmech) ; //------------------------------------- // given an SPKI, return its raw public key (which hashes into the SKI): // // SEQUENCE { // SEQUENCE ... -- type information (which we do not parse) // BIT STRING { -- SKI base is net content of this BIT STRING // -- without leading byte (==unused bits' count) // SEQUENCE { -- capture this T+L+V (or raw public value for EC key) // ... // } // } // // returns SKI-base bytecount, setting *ski to start of SKI base, if non-NULL // XCP_EINVALID if input does not look like an SPKI // XCP_EARG if missing arguments // // note: we do not verify other details of SPKI; caller must do so // long xcp_spki2pubkey (const unsigned char **bitstr, const unsigned char *spki, size_t slen) ; /* * Parse the list of indices and ranges and construct corresponding bitmask * args pointer to a comma separated list of indices * (ranges of indices are also allowed) * mask pointer to an 32 byte array that represents our domain mask * masksize bit-length of the mask */ int xcp_args2mask(char *args, unsigned char *mask, int masksize); /* * Fills in 'file-ID', 'offset' and 'length' parameter into the file header * hdr pointer to the file header * hlen length of the header * fileid fileid to refer the file type * offset offset of data pointer * bytes number of bytes to transfer */ int xcpa_write_filepart_hdr(unsigned char *hdr, size_t hlen, uint32_t fileid, uint32_t offset, uint32_t bytes); /* reads partial data from target/fileid * returning payload to res, rlen * * returns >0 on success (bytecount) * 0 if file access failed (not available, etc.) * <0 if anything unexpected failed */ long xcpa_query_filepart(unsigned char *res, size_t rlen, const unsigned char *hdr, size_t hlen, target_t target, CK_RV exprv); /* reads complete data from target/fileid * returning payload to res, rlen * * returns >0 on success (bytecount) * 0 if file access failed (not available, etc.) * <0 if anything unexpected failed */ long xcpa_query_full_file(unsigned char *res, size_t rlen, target_t target, unsigned int fileid, unsigned int block); /* writes data to internal files * takes data, dlen to write to target/fileid * * returns >0 if results have been all written * <0 if anything unexpected failed */ long xcpa_write_full_file(target_t target, xcpa_admin_signs_cb_t sign_cb, const void *signopts, const unsigned char *data, size_t dlen, unsigned int fileid, unsigned int block); long xcpa_remove_file(target_t target, unsigned int fileid, xcpa_admin_signs_cb_t sign_cb, const void *signopts); /* brute-force section parser: enumerate all encrypted-KP sections * * returns >0 offset of full OCTET STRING T+L+V section * 0 when there are no more sections * <0 if encoding is invalid (which SNH) * * sets *kpidx to index (sub-type) of keypart found if not NULL * * since external compound is SEQUENCE, it can't match KP at offset 0 * therefore, comparing > is correct */ long xcpa_kp_next_section(const unsigned char *kps, size_t kplen, unsigned long idx, uint32_t *kpidx); /* retrieve recipient infos from keypart sections * * returns >0 number of recipient infos found * <0 if anything failed */ long xcpa_kps_retrieve_rcptinfo(struct Recipient_info *rcpti, unsigned int rimax, const unsigned char *kpexport, size_t kplen); /* * report domain compliance * * returns compliance bitmask if successful and 0 if anything failed * (as zero is invalid as we always have a default compliance active) * */ uint64_t get_dom_compl(target_t target); #endif /* !defined(__xcpadm_h__) */ opencryptoki-opencryptoki-451d99c/usr/lib/ep11_stdll/ep11cpfilter.conf000066400000000000000000000150221520105705100260210ustar00rootroot00000000000000# # 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_SHA3_224_HMAC, CKM_SHA3_256_HMAC,CKM_SHA3_384_HMAC, CKM_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_SHA3_224_HMAC, CKM_SHA3_256_HMAC,CKM_SHA3_384_HMAC, CKM_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_SHA3_224_RSA_PKCS, CKM_SHA3_256_RSA_PKCS, CKM_SHA3_384_RSA_PKCS, CKM_SHA3_512_RSA_PKCS, 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, CKM_ECDSA_SHA3_224, CKM_ECDSA_SHA3_256, CKM_ECDSA_SHA3_384, CKM_ECDSA_SHA3_512 # 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, CKM_AES_XTS #decrypt with private keys XCP_CPB_DECRYPT_ASYMM: CKM_RSA_PKCS, CKM_RSA_PKCS_OAEP # 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, CKM_AES_XTS # 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 XCP_CPB_KEYGEN_SYMM: CKM_AES_KEY_GEN, CKM_DES2_KEY_GEN, CKM_DES3_KEY_GEN, CKM_PBE_SHA1_DES3_EDE_CBC, CKM_DES_KEY_GEN, CKM_GENERIC_SECRET_KEY_GEN, CKM_AES_XTS_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, CKM_RSA_PKCS_OAEP # DSA private-key use XCP_CPB_ALG_DSA: 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, CKM_ECDSA_SHA3_224, CKM_ECDSA_SHA3_256, CKM_ECDSA_SHA3_384, CKM_ECDSA_SHA3_512 # Diffie-Hellman use (private keys) XCP_CPB_ALG_DH: CKM_ECDH1_DERIVE, 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_X25519, CKM_IBM_ED25519_SHA512, CKM_IBM_EC_X448, 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, CKM_SHA3_224_RSA_PKCS, CKM_SHA3_256_RSA_PKCS, CKM_SHA3_384_RSA_PKCS, CKM_SHA3_512_RSA_PKCS #enable support of Dilithium and Kyber XCP_CPB_ALG_PQC: CKM_IBM_DILITHIUM, CKM_IBM_KYBER, CKM_IBM_ML_DSA, CKM_IBM_ML_KEM #enable support of Dilithium XCP_CPB_ALG_DILITHIUM: CKM_IBM_DILITHIUM #enable support of Kyber XCP_CPB_ALG_KYBER: CKM_IBM_KYBER #enable support of ML-DSA XCP_CPB_ALG_ML_DSA: CKM_IBM_ML_DSA, CKM_IBM_ML_DSA_KEY_PAIR_GEN #enable support of ML-KEM XCP_CPB_ALG_ML_KEM: CKM_IBM_ML_KEM, CKM_IBM_ML_KEM_KEY_PAIR_GEN, CKM_IBM_ML_KEM_WITH_ECDH # enable BTC-related functionality XCP_CPB_BTC: CKM_IBM_BTC_DERIVE # enable non-ECDSA/non-EdDSA elliptic curve signature algorithms XCP_CPB_ECDSA_OTHER: CKM_IBM_ECDSA_OTHER # allow non-FIPS-approved algs (2021) XCP_CPB_ALG_NFIPS2021: CKM_RSA_PKCS, CKM_SHA1_RSA_PKCS, CKM_SHA1_RSA_PKCS_PSS, CKM_SHA1_RSA_X9_31, CKM_DSA_SHA1, CKM_ECDSA_SHA1, CKM_DES_KEY_GEN, CKM_DES_ECB, CKM_DES_CBC, CKM_DES_CBC_PAD, CKM_DES2_KEY_GEN, CKM_DES3_KEY_GEN, CKM_DES3_ECB, CKM_DES3_CBC, CKM_DES3_MAC, CKM_DES3_MAC_GENERAL, CKM_DES3_CBC_PAD, CKM_DES3_CMAC_GENERAL, CKM_DES3_CMAC, CKM_DES_OFB64, CKM_DES_CFB64, CKM_DES_CFB8, CKM_SHA_1_HMAC, CKM_SHA_1_HMAC_GENERAL, CKM_SHA1_KEY_DERIVATION # allow non-FIPS-approved algs (2024) XCP_CPB_ALG_NFIPS2024: CKM_RSA_PKCS, CKM_SHA1_RSA_PKCS, CKM_SHA1_RSA_PKCS_PSS, CKM_SHA1_RSA_X9_31, CKM_DSA_SHA1, CKM_ECDSA_SHA1, CKM_DES_KEY_GEN, CKM_DES_ECB, CKM_DES_CBC, CKM_DES_CBC_PAD, CKM_DES2_KEY_GEN, CKM_DES3_KEY_GEN, CKM_DES3_ECB, CKM_DES3_CBC, CKM_DES3_MAC, CKM_DES3_MAC_GENERAL, CKM_DES3_CBC_PAD, CKM_DES3_CMAC_GENERAL, CKM_DES3_CMAC, CKM_DES_OFB64, CKM_DES_CFB64, CKM_DES_CFB8, CKM_SHA_1_HMAC, CKM_SHA_1_HMAC_GENERAL, CKM_SHA1_KEY_DERIVATION # allow RSA OAEP XCP_CPB_ALG_RSA_OAEP: CKM_RSA_PKCS_OAEP opencryptoki-opencryptoki-451d99c/usr/lib/ep11_stdll/ep11tok.conf000066400000000000000000000166411520105705100250160ustar00rootroot00000000000000# # 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 using # the APQN_ALLOWLIST or APQN_ANY keywords, see below. All other # settings are optional. # # -------------------------------------------------------------------------- # # 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 with CKA_PRIVATE=TRUE 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. # The strict-mode mode can not be enabled together with the FIPS-session mode. # # -------------------------------------------------------------------------- # # In VHSM-mode (virtual-HSM), all keys with CKA_PRIVATE=TRUE generated by # the EP11 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 VHSM-mode mode can not be enabled together with the FIPS-session mode. # # VHSM_MODE # # -------------------------------------------------------------------------- # # In FIPS-session mode a USER session is required to be able to access any kind # of key objects, regardless of the setting of the CKA_PRIVATE and CKA_TOKEN # attributes. That is, a C_Login must be performed with the USER pin to be able # to create or use key objects. Furthermore all keys generated by the # EP11 token will strictly belong to the EP11 token that created it. # Every EP11 token requires a FIPS-pin to be set using the pkcsep11_session # tool. In FIPS-sesion mode, a FIPS approved algorithm is used to login the # session into the EP11 adapter(s). This requires certain firmware support # from the adapter(s) as well as from the EP11 host library. # The FIPS-session mode can not be enabled together with strict-mode or # VHSM-mode. # # FIPS_SESSION_MODE # # -------------------------------------------------------------------------- # # 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 # # -------------------------------------------------------------------------- # # To optimize encrypt/decrypt and sign/verify performance, a corresponding # protected key can be created for AES and EC secure keys and added to the # secure key. # This protected key is then used for certain mechanisms via CPACF, instead of # performing the function via the EP11 coprocessor. # IBM specific boolean attribute CKA_IBM_PROTKEY_EXTRACTABLE must be true to # make a key eligible for protected key support. CKA_IBM_PROTKEY_EXTRACTABLE # and CKA_EXTRACTABLE cannot both be true. The default value of # CKA_IBM_PROTKEY_EXTRACTABLE is false. # # AES-XTS related mechanisms are only available if the PKEY_MODE option is not # disabled and additional hardware and firmware prerequisites are met. AES-XTS # is not supported via the EP11 coprocessor itself. # # PKEY_MODE DISABLED | DEFAULT | ENABLE4NONEXTR | ENABLE4EXTR | ENABLE4ALL # # DISABLED : Protected key support disabled. All key operations # are performed via EP11 coprocessor, even if a # given key object has a protected key. # # DEFAULT : If the application did not specify CKA_EXTRACTABLE # or CKA_IBM_PROTKEY_EXTRACTABLE, new keys get default # values for CKA_EXTRACTABLE (true) and # CKA_IBM_PROTKEY_EXTRACTABLE (false). # # ENABLE4NONEXTR : If the application specified CKA_EXTRACTABLE=false, # but not CKA_IBM_PROTKEY_EXTRACTABLE, new keys get # CKA_IBM_PROTKEY_EXTRACTABLE=true internally. # # Control point 75 (XCP_CPB_ALLOW_COMBINED_EXTRACT) must be enabled for all # APQNs accessible by the token for the following parameters. # # ENABLE4EXTR : If the application did not specify # CKA_IBM_PROTKEY_EXTRACTABLE in its template, new keys # of any type with CKA_EXTRACTABLE=true get # CKA_IBM_PROTKEY_EXTRACTABLE=true and a protected key # is automatically created at first use of the key. # # ENABLE4ALL : If the application did not specify # CKA_IBM_PROTKEY_EXTRACTABLE in its template, new keys # of any type, regardless of the CKA_EXTRACTABLE # attribute, get CKA_IBM_PROTKEY_EXTRACTABLE=true and # a protected key is automatically created at first # use of the key. # # -------------------------------------------------------------------------- # # Specify the expected wrapping key verification pattern. When specified, all # APQNs configured for the token must have been set up with this wrapping key # verification pattern. # You can use the TKE or ep11info to query the current wrapping key verification # pattern of an APQN: # ep11info -m -d -D # You can also find the wrapping key verification pattern for EP11 APQNs # in sysfs: 'cat /sys/bus/ap/devices/./mkvps' # # EXPECTED_WKVP "" # # -------------------------------------------------------------------------- # # There are 2 ways to specify the crypto adapters: # 1) explicitly list of adapter/domain pairs # # APQN_ALLOWLIST # 8 13 # 10 13 # END # # The adapter and domain may be given in decimal, # octal (with leading 0) or hexadecimal (with leading 0x): # # APQN_ALLOWLIST # 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 opencryptoki-opencryptoki-451d99c/usr/lib/ep11_stdll/new_host.c000066400000000000000000005064651520105705100246650ustar00rootroot00000000000000/* * 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 #include #include #include #include #include #include #include #include #define OCK_NO_EP11_DEFINES #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 "attributes.h" #include "ep11_specific.h" #include "constant_time.h" #include "../api/apiproto.h" #include "../api/policy.h" void SC_SetFunctionList(void); CK_RV SC_Logout(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession); 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]; CK_BBOOL newdatastore; policy_t policy = sltp->TokData->policy; /* set trace info */ set_trace(t); rc = bt_init(&sltp->TokData->sess_btree, free); rc |= bt_init(&sltp->TokData->object_map_btree, free); rc |= bt_init(&sltp->TokData->sess_obj_btree, call_object_free); rc |= bt_init(&sltp->TokData->priv_token_obj_btree, call_object_free); rc |= bt_init(&sltp->TokData->publ_token_obj_btree, call_object_free); if (rc != CKR_OK) { TRACE_ERROR("Btree init failed\n"); rc = CKR_FUNCTION_FAILED; goto done; } if (strlen(sinfp->tokname)) { if (ock_snprintf(abs_tokdir_name, PATH_MAX, "%s/%s", CONFIG_PATH, sinfp->tokname) != 0) { TRACE_ERROR("abs_tokdir_name buffer overflow\n"); rc = CKR_FUNCTION_FAILED; } else { TRACE_DEVEL("Token directory: %s\n", abs_tokdir_name); rc = init_data_store(sltp->TokData, (char *) abs_tokdir_name, sltp->TokData->data_store, sizeof(sltp->TokData->data_store)); } } else { rc = init_data_store(sltp->TokData, (char *) PK_DIR, sltp->TokData->data_store, sizeof(sltp->TokData->data_store)); } if (rc != CKR_OK) { TRACE_ERROR("init_data_store failed with buffer error.\n"); goto done; } sltp->TokData->version = sinfp->version; TRACE_DEVEL("Token version: %u.%u\n", (unsigned int)(sinfp->version >> 16), (unsigned int)(sinfp->version & 0xffff)); /* Check token store encryption against policy */ newdatastore = sinfp->version >= TOK_NEW_DATA_STORE ? CK_TRUE : CK_FALSE; rc = policy->check_token_store(policy, newdatastore, token_specific.data_store.encryption_algorithm, SlotNumber, &sltp->TokData->store_strength); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: Token cannot load since data store encryption is too weak for policy.\n"); goto done; } /* 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); final_data_store(sltp->TokData); 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; final_data_store(sltp->TokData); 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); final_data_store(sltp->TokData); bt_destroy(&sltp->TokData->sess_btree); bt_destroy(&sltp->TokData->object_map_btree); bt_destroy(&sltp->TokData->sess_obj_btree); bt_destroy(&sltp->TokData->priv_token_obj_btree); bt_destroy(&sltp->TokData->publ_token_obj_btree); } } 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, &in_fork_initializer); } 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); detach_shm(tokdata, in_fork_initializer); /* close spin lock file */ CloseXProcLock(tokdata); rc = ep11tok_final(tokdata, in_fork_initializer); if (rc != CKR_OK) { TRACE_ERROR("Token specific final call failed.\n"); return rc; } final_data_store(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); if (token_specific.t_get_token_info != NULL) rc = token_specific.t_get_token_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(tokdata, 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 (rc != CKR_OK) { TRACE_DEVEL("compute_sha1 failed.\n"); goto done; } 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 = compute_PKCS5_PBKDF2_HMAC(tokdata, pPin, ulPinLen, dat->so_login_salt, 64, dat->so_login_it, EVP_sha512(), 256 / 8, login_key); if (rc != CKR_OK) { TRACE_DEVEL("PBKDF2 failed.\n"); 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; tokdata->nv_token_data->token_info.flags &= ~(CKF_USER_PIN_INITIALIZED | CKF_USER_PIN_LOCKED | CKF_USER_PIN_FINAL_TRY | CKF_USER_PIN_COUNT_LOW); 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 = 0, wrap_it = 0; 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_reset_error(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 = compute_PKCS5_PBKDF2_HMAC(tokdata, pPin, ulPinLen, login_salt, 64, login_it, EVP_sha512(), 256 / 8, login_key); if (rc != CKR_OK) { TRACE_DEVEL("PBKDF2 failed.\n"); goto done; } wrap_it = USER_KDF_WRAP_IT; memcpy(wrap_salt, USER_KDF_WRAP_PURPOSE, 32); rng_generate(tokdata, wrap_salt + 32, 32); rc = compute_PKCS5_PBKDF2_HMAC(tokdata, pPin, ulPinLen, wrap_salt, 64, wrap_it, EVP_sha512(), 256 / 8, wrap_key); if (rc != CKR_OK) { TRACE_DEVEL("PBKDF2 failed.\n"); 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_reset_error(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 = compute_PKCS5_PBKDF2_HMAC(tokdata, pNewPin, ulNewLen, login_salt, 64, login_it, EVP_sha512(), 256 / 8, new_login_key); if (rc != CKR_OK) { TRACE_DEVEL("PBKDF2 failed.\n"); goto done; } wrap_it = USER_KDF_WRAP_IT; memcpy(wrap_salt, USER_KDF_WRAP_PURPOSE, 32); rng_generate(tokdata, wrap_salt + 32, 32); rc = compute_PKCS5_PBKDF2_HMAC(tokdata, pNewPin, ulNewLen, wrap_salt, 64, wrap_it, EVP_sha512(), 256 / 8, new_wrap_key); if (rc != CKR_OK) { TRACE_DEVEL("PBKDF2 failed.\n"); goto done; } rc = compute_PKCS5_PBKDF2_HMAC(tokdata, pOldPin, ulOldLen, dat->user_login_salt, 64, dat->user_login_it, EVP_sha512(), 256 / 8, old_login_key); if (rc != CKR_OK) { TRACE_DEVEL("PBKDF2 failed.\n"); goto done; } rc = compute_PKCS5_PBKDF2_HMAC(tokdata, pNewPin, ulNewLen, dat->user_login_salt, 64, dat->user_login_it, EVP_sha512(), 256 / 8, new_login_key_old_salt); if (rc != CKR_OK) { TRACE_DEVEL("PBKDF2 failed.\n"); 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 = compute_PKCS5_PBKDF2_HMAC(tokdata, pNewPin, ulNewLen, login_salt, 64, login_it, EVP_sha512(), 256 / 8, new_login_key); if (rc != CKR_OK) { TRACE_DEVEL("PBKDF2 failed.\n"); goto done; } wrap_it = SO_KDF_WRAP_IT; memcpy(wrap_salt, SO_KDF_WRAP_PURPOSE, 32); rng_generate(tokdata, wrap_salt + 32, 32); rc = compute_PKCS5_PBKDF2_HMAC(tokdata, pNewPin, ulNewLen, wrap_salt, 64, wrap_it, EVP_sha512(), 256 / 8, new_wrap_key); if (rc != CKR_OK) { TRACE_DEVEL("PBKDF2 failed.\n"); goto done; } rc = compute_PKCS5_PBKDF2_HMAC(tokdata, pOldPin, ulOldLen, dat->so_login_salt, 64, dat->so_login_it, EVP_sha512(), 256 / 8, old_login_key); if (rc != CKR_OK) { TRACE_DEVEL("PBKDF2 failed.\n"); goto done; } rc = compute_PKCS5_PBKDF2_HMAC(tokdata, pNewPin, ulNewLen, dat->so_login_salt, 64, dat->so_login_it, EVP_sha512(), 256 / 8, new_login_key_old_salt); if (rc != CKR_OK) { TRACE_DEVEL("PBKDF2 failed.\n"); 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_reset_error(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) { CK_BBOOL in_fork_initializer = FALSE; UNUSED(node_idx); if (p3 != NULL) in_fork_initializer = *(CK_BBOOL *)p3; ep11tok_logout_session(tokdata, (SESSION *) node_value, in_fork_initializer); } 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; } if (session_mgr_so_session_exists(tokdata) || session_mgr_user_session_exists(tokdata)) { sess = session_mgr_find_reset_error(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, in_fork_initializer); if (rc != CKR_OK) { TRACE_ERROR("ep11tok_logout_session failed: rc=0x%lx\n", 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_reset_error(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(tokdata, 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_reset_error(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(tokdata, sess, hEncryptionKey, hAuthenticationKey, pOperationState, ulOperationStateLen); if (rc != CKR_OK) { TRACE_DEVEL("session_mgr_set_op_state() failed.\n"); goto done; } rc = ep11tok_set_operation_state(tokdata, sess); if (rc != CKR_OK) { TRACE_DEVEL("ep11tok_set_operation_state() failed.\n"); goto done; } done: TRACE_INFO("C_SetOperationState: rc = 0x%08lx, sess = %lu\n", rc, sSession->sessionh); if (sess != NULL) session_mgr_put(tokdata, sess); return rc; } CK_RV SC_SessionCancel(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, CK_FLAGS flags) { 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 = session_mgr_cancel(tokdata, sess, flags); done: TRACE_INFO("SC_SessionCancel: sess = %lu\n", 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_reset_error(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 */ switch (userType) { case 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; } break; case 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; } break; case CKU_CONTEXT_SPECIFIC: /* * Although not explicitly required by the PKCS#11 standard, check that * a USER session exists. C_Login with CKU_CONTEXT_SPECIFIC is performed * due to CKA_ALWAYS_AUTHENTICATE=TRUE on a key used with an operation. * CKA_ALWAYS_AUTHENTICATE=TRUE is only allowed for keys of class * CKO_PRIVATE_KEY that have CKA_PRIVATE=TRUE. Key objects with * CKA_PRIVATE=TRUE can only be accessed in a USER session, so a * C_Login with CKU_CONTEXT_SPECIFIC can also only happen when a USER * session exists. */ if (!session_mgr_user_session_exists(tokdata)) { TRACE_ERROR("%s\n", ock_err(ERR_USER_NOT_LOGGED_IN)); rc = CKR_USER_NOT_LOGGED_IN; } if (!(sess->sign_ctx.active && sess->sign_ctx.auth_required) && !(sess->decr_ctx.active && sess->decr_ctx.auth_required)) { TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); rc = CKR_OPERATION_NOT_INITIALIZED; } break; default: rc = CKR_USER_TYPE_INVALID; TRACE_ERROR("%s\n", ock_err(ERR_USER_TYPE_INVALID)); break; } if (rc != CKR_OK) goto done; dat = &tokdata->nv_token_data->dat; switch (userType) { case CKU_USER: if (*flags & CKF_USER_PIN_LOCKED) { TRACE_ERROR("%s\n", ock_err(ERR_PIN_LOCKED)); rc = CKR_PIN_LOCKED; goto done; } if (!(*flags & CKF_USER_PIN_INITIALIZED)) { TRACE_ERROR("%s\n", ock_err(ERR_USER_PIN_NOT_INITIALIZED)); rc = CKR_USER_PIN_NOT_INITIALIZED; 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 (rc != CKR_OK) { TRACE_DEVEL("compute_sha1 failed.\n"); goto done; } 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 = compute_PKCS5_PBKDF2_HMAC(tokdata, pPin, ulPinLen, dat->user_login_salt, 64, dat->user_login_it, EVP_sha512(), 256 / 8, login_key); if (rc != CKR_OK) { TRACE_DEVEL("PBKDF2 failed.\n"); goto done; } rc = compute_PKCS5_PBKDF2_HMAC(tokdata, pPin, ulPinLen, dat->user_wrap_salt, 64, dat->user_wrap_it, EVP_sha512(), 256 / 8, wrap_key); if (rc != CKR_OK) { TRACE_DEVEL("PBKDF2 failed.\n"); 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; } break; case CKU_SO: 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 (rc != CKR_OK) { TRACE_DEVEL("compute_sha1 failed.\n"); goto done; } 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 = compute_PKCS5_PBKDF2_HMAC(tokdata, pPin, ulPinLen, dat->so_login_salt, 64, dat->so_login_it, EVP_sha512(), 256 / 8, login_key); if (rc != CKR_OK) { TRACE_DEVEL("PBKDF2 failed.\n"); goto done; } rc = compute_PKCS5_PBKDF2_HMAC(tokdata, pPin, ulPinLen, dat->so_wrap_salt, 64, dat->so_wrap_it, EVP_sha512(), 256 / 8, wrap_key); if (rc != CKR_OK) { TRACE_DEVEL("PBKDF2 failed.\n"); 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"); } break; case CKU_CONTEXT_SPECIFIC: if (*flags & CKF_USER_PIN_LOCKED) { TRACE_ERROR("%s\n", ock_err(ERR_PIN_LOCKED)); rc = CKR_PIN_LOCKED; goto done; } if (!(*flags & CKF_USER_PIN_INITIALIZED)) { TRACE_ERROR("%s\n", ock_err(ERR_USER_PIN_NOT_INITIALIZED)); rc = CKR_USER_PIN_NOT_INITIALIZED; goto done; } if (tokdata->version < TOK_NEW_DATA_STORE) { rc = compute_sha1(tokdata, pPin, ulPinLen, hash_sha); if (rc != CKR_OK) { TRACE_DEVEL("compute_sha1 failed.\n"); goto done; } 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); } else { rc = compute_PKCS5_PBKDF2_HMAC(tokdata, pPin, ulPinLen, dat->user_login_salt, 64, dat->user_login_it, EVP_sha512(), 256 / 8, login_key); if (rc != CKR_OK) { TRACE_DEVEL("PBKDF2 failed.\n"); 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); } /* * Reset flag in operation context to indicate that a login has been * successfully performed */ if (sess->sign_ctx.active && sess->sign_ctx.auth_required) sess->sign_ctx.auth_required = FALSE; if (sess->decr_ctx.active && sess->decr_ctx.auth_required) sess->decr_ctx.auth_required = FALSE; break; default: rc = CKR_USER_TYPE_INVALID; TRACE_ERROR("%s\n", ock_err(ERR_USER_TYPE_INVALID)); goto done; } done: if (rc == CKR_OK && userType != CKU_CONTEXT_SPECIFIC) { rc = session_mgr_login_all(tokdata, userType); if (rc != CKR_OK) TRACE_DEVEL("session_mgr_login_all failed.\n"); } if (rc == CKR_OK && userType != CKU_CONTEXT_SPECIFIC) { bt_for_each_node(tokdata, &tokdata->sess_btree, _ep11tok_login_session, &rc); if (rc != CKR_OK) TRACE_DEVEL("_ep11tok_login_session failed.\n"); } /* * PKCS#11 states for failing C_Login with user type CKU_CONTEXT_SPECIFIC: * '... repeated failed re-authentication attempts may cause the PIN to be * locked. C_Login returns in this case CKR_PIN_LOCKED and this also logs * the user out from the token' */ if (userType == CKU_CONTEXT_SPECIFIC && rc == CKR_PIN_INCORRECT && pin_locked(&sess->session_info, tokdata->nv_token_data->token_info.flags)) { TRACE_DEVEL("USER pin now locked, logout the user\n"); SC_Logout(tokdata, sSession); rc = CKR_PIN_LOCKED; } 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_reset_error(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_reset_error(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; } /* Enforces policy */ rc = object_mgr_add(tokdata, sess, pTemplate, ulCount, phObject, MODE_CREATE); 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 && pTemplate[i].ulValueLen == sizeof(CK_ULONG) && pTemplate[i].pValue != NULL) { 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_reset_error(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; } /* Enforces policy */ 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_reset_error(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_reset_error(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_reset_error(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 val[4]; CK_ULONG i; attr = pTemplate; for (i = 0; i < ulCount && attr != NULL; i++, attr++) { TRACE_DEBUG("%lu: Attribute type: 0x%08lx, Value Length: %lu\n", i, attr->type, attr->ulValueLen); if (rc == CKR_OK && attr->ulValueLen != CK_UNAVAILABLE_INFORMATION) { if (attr->ulValueLen >= sizeof(val) && attr->pValue != NULL) { memset(val, 0, sizeof(val)); memcpy(val, attr->pValue, attr->ulValueLen > sizeof(val) ? sizeof(val) : attr->ulValueLen); TRACE_DEBUG("First 4 bytes: %02x %02x %02x %02x\n", val[0], val[1], val[2], val[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_reset_error(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_BYTE val[4]; CK_ULONG i; attr = pTemplate; for (i = 0; i < ulCount && attr != NULL; i++, attr++) { TRACE_DEBUG("%lu: Attribute type: 0x%08lx, Value Length: %lu\n", i, attr->type, attr->ulValueLen); if (attr->ulValueLen >= sizeof(val) && attr->pValue != NULL) { memset(val, 0, sizeof(val)); memcpy(val, attr->pValue, attr->ulValueLen > sizeof(val) ? sizeof(val) : attr->ulValueLen); TRACE_DEBUG("First 4 bytes: %02x %02x %02x %02x\n", val[0], val[1], val[2], val[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_reset_error(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_BYTE val[4]; CK_ULONG i; attr = pTemplate; for (i = 0; i < ulCount && attr != NULL; i++, attr++) { TRACE_DEBUG("%lu: Attribute type: 0x%08lx, Value Length: %lu\n", i, attr->type, attr->ulValueLen); if (attr->ulValueLen >= sizeof(val) && attr->pValue != NULL) { memset(val, 0, sizeof(val)); memcpy(val, attr->pValue, attr->ulValueLen > sizeof(val) ? sizeof(val) : attr->ulValueLen); TRACE_DEBUG("First 4 bytes: %02x %02x %02x %02x\n", val[0], val[1], val[2], val[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_reset_error(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_reset_error(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; } sess = session_mgr_find_reset_error(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 (pMechanism == NULL) { /* As per PKCS#11 v3.0 Init with NULL pMechanism cancels operation */ rc = session_mgr_cancel(tokdata, sess, CKF_ENCRYPT); goto done; } rc = valid_mech(tokdata, pMechanism); if (rc != CKR_OK) 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; rc = ep11tok_pkey_usage_ok(tokdata, sess, hKey, pMechanism); if (rc != CKR_OK && rc != CKR_FUNCTION_NOT_SUPPORTED) { /* CKR_FUNCTION_NOT_SUPPORTED indicates pkey support is not available, but the ep11 fallback can be tried */ goto done; } if ((ep11tok_optimize_single_ops(tokdata) || ep11tok_mech_single_only(pMechanism)) && rc == CKR_FUNCTION_NOT_SUPPORTED) { /* 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. */ rc = ep11tok_check_single_mech_key(tokdata, sess, pMechanism, hKey, OP_ENCRYPT_INIT, NULL); if (rc != CKR_OK) goto done; sess->encr_ctx.init_pending = TRUE; sess->encr_ctx.active = TRUE; sess->encr_ctx.key = hKey; sess->encr_ctx.mech.mechanism = pMechanism->mechanism; if (pMechanism->pParameter && pMechanism->ulParameterLen > 0) { sess->encr_ctx.mech.pParameter = malloc(pMechanism->ulParameterLen); if (sess->encr_ctx.mech.pParameter) { memcpy(sess->encr_ctx.mech.pParameter, pMechanism->pParameter, pMechanism->ulParameterLen); sess->encr_ctx.mech.ulParameterLen = pMechanism->ulParameterLen; } else { TRACE_ERROR("%s Memory allocation failed\n", __func__); rc = CKR_HOST_MEMORY; encr_mgr_cleanup(tokdata, sess, &sess->encr_ctx); goto done; } } else { sess->encr_ctx.mech.pParameter = NULL; sess->encr_ctx.mech.ulParameterLen = 0; } } 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_reset_error(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; } rc = ep11tok_pkey_usage_ok(tokdata, sess, sess->encr_ctx.key, &sess->encr_ctx.mech); if (rc != CKR_OK && rc != CKR_FUNCTION_NOT_SUPPORTED) { /* CKR_FUNCTION_NOT_SUPPORTED indicates pkey support is not available, but the ep11 fallback can be tried */ goto done; } if ((ep11tok_optimize_single_ops(tokdata) || ep11tok_mech_single_only(&sess->encr_ctx.mech)) && rc == CKR_FUNCTION_NOT_SUPPORTED) { 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(tokdata, sess, &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_reset_error(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 || ep11tok_mech_single_only(&sess->encr_ctx.mech)) { 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(tokdata, sess, &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_reset_error(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 || ep11tok_mech_single_only(&sess->encr_ctx.mech)) { 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(tokdata, sess, &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; } sess = session_mgr_find_reset_error(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 (pMechanism == NULL) { /* As per PKCS#11 v3.0 Init with NULL pMechanism cancels operation */ rc = session_mgr_cancel(tokdata, sess, CKF_DECRYPT); goto done; } rc = valid_mech(tokdata, pMechanism); if (rc != CKR_OK) 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; rc = ep11tok_pkey_usage_ok(tokdata, sess, hKey, pMechanism); if (rc != CKR_OK && rc != CKR_FUNCTION_NOT_SUPPORTED) { /* CKR_FUNCTION_NOT_SUPPORTED indicates pkey support is not available, but the ep11 fallback can be tried */ goto done; } if ((ep11tok_optimize_single_ops(tokdata) || ep11tok_mech_single_only(pMechanism)) && rc == CKR_FUNCTION_NOT_SUPPORTED) { /* 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. */ rc = ep11tok_check_single_mech_key(tokdata, sess, pMechanism, hKey, OP_DECRYPT_INIT, &sess->decr_ctx.auth_required); if (rc != CKR_OK) goto done; sess->decr_ctx.init_pending = TRUE; sess->decr_ctx.active = TRUE; sess->decr_ctx.key = hKey; sess->decr_ctx.mech.mechanism = pMechanism->mechanism; if (pMechanism->pParameter && pMechanism->ulParameterLen > 0) { sess->decr_ctx.mech.pParameter = malloc(pMechanism->ulParameterLen); if (sess->decr_ctx.mech.pParameter) { memcpy(sess->decr_ctx.mech.pParameter, pMechanism->pParameter, pMechanism->ulParameterLen); sess->decr_ctx.mech.ulParameterLen = pMechanism->ulParameterLen; } else { TRACE_ERROR("%s Memory allocation failed\n", __func__); rc = CKR_HOST_MEMORY; decr_mgr_cleanup(tokdata, sess, &sess->decr_ctx); goto done; } } else { sess->decr_ctx.mech.pParameter = NULL; sess->decr_ctx.mech.ulParameterLen = 0; } } else { rc = ep11tok_decrypt_init(tokdata, sess, pMechanism, hKey, TRUE); 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; unsigned int mask; 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_reset_error(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 (sess->decr_ctx.auth_required == TRUE) { TRACE_ERROR("%s\n", ock_err(ERR_USER_NOT_LOGGED_IN)); rc = CKR_USER_NOT_LOGGED_IN; 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; } rc = ep11tok_pkey_usage_ok(tokdata, sess, sess->decr_ctx.key, &sess->decr_ctx.mech); if (rc != CKR_OK && rc != CKR_FUNCTION_NOT_SUPPORTED) { /* CKR_FUNCTION_NOT_SUPPORTED indicates pkey support is not available, but the ep11 fallback can be tried */ goto done; } if ((ep11tok_optimize_single_ops(tokdata) || ep11tok_mech_single_only(&sess->decr_ctx.mech)) && rc == CKR_FUNCTION_NOT_SUPPORTED) { rc = ep11tok_decrypt_single(tokdata, sess, &sess->decr_ctx.mech, length_only, sess->decr_ctx.key, pEncryptedData, ulEncryptedDataLen, pData, pulDataLen); /* (!is_rsa_mechanism(sess->decr_ctx.mech.mechanism) && rc != CKR_OK) */ mask = constant_time_is_zero( is_rsa_mechanism(sess->decr_ctx.mech.mechanism)); mask &= ~constant_time_eq(rc, CKR_OK); if (mask) TRACE_DEVEL("ep11tok_decrypt_single() failed.\n"); } else { rc = ep11tok_decrypt(tokdata, sess, pEncryptedData, ulEncryptedDataLen, pData, pulDataLen); /* (!is_rsa_mechanism(sess->decr_ctx.mech.mechanism) && rc != CKR_OK) */ mask = constant_time_is_zero( is_rsa_mechanism(sess->decr_ctx.mech.mechanism)); mask &= ~constant_time_eq(rc, CKR_OK); if (mask) TRACE_DEVEL("ep11tok_decrypt() failed.\n"); } done: /* (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) */ mask = ~constant_time_eq(rc, CKR_OK); mask |= constant_time_is_zero(length_only); mask &= ~constant_time_eq(rc, CKR_BUFFER_TOO_SMALL); if (mask) { if (sess) decr_mgr_cleanup(tokdata, sess, &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; unsigned int mask; 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_reset_error(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 || ep11tok_mech_single_only(&sess->decr_ctx.mech)) { TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); rc = CKR_OPERATION_NOT_INITIALIZED; goto done; } if (sess->decr_ctx.auth_required == TRUE) { TRACE_ERROR("%s\n", ock_err(ERR_USER_NOT_LOGGED_IN)); rc = CKR_USER_NOT_LOGGED_IN; 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, FALSE); 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); /* (!is_rsa_mechanism(sess->decr_ctx.mech.mechanism) && rc != CKR_OK) */ mask = constant_time_is_zero( is_rsa_mechanism(sess->decr_ctx.mech.mechanism)); mask &= ~constant_time_eq(rc, CKR_OK); if (mask) TRACE_DEVEL("ep11tok_decrypt_update() failed.\n"); done: /* (rc != CKR_OK && rc != CKR_BUFFER_TOO_SMALL */ mask = ~constant_time_eq(rc, CKR_OK); mask &= ~constant_time_eq(rc, CKR_BUFFER_TOO_SMALL); if (mask) { if (sess) decr_mgr_cleanup(tokdata, sess, &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; unsigned int mask; 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_reset_error(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 || ep11tok_mech_single_only(&sess->decr_ctx.mech)) { TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); rc = CKR_OPERATION_NOT_INITIALIZED; goto done; } if (sess->decr_ctx.auth_required == TRUE) { TRACE_ERROR("%s\n", ock_err(ERR_USER_NOT_LOGGED_IN)); rc = CKR_USER_NOT_LOGGED_IN; 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); /* (!is_rsa_mechanism(sess->decr_ctx.mech.mechanism) && rc != CKR_OK) */ mask = constant_time_is_zero( is_rsa_mechanism(sess->decr_ctx.mech.mechanism)); mask &= ~constant_time_eq(rc, CKR_OK); if (mask) TRACE_DEVEL("ep11tok_decrypt_final() failed.\n"); done: /* (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) */ mask = ~constant_time_eq(rc, CKR_OK); mask |= constant_time_is_zero(length_only); mask &= ~constant_time_eq(rc, CKR_BUFFER_TOO_SMALL); if (mask) { if (sess) decr_mgr_cleanup(tokdata, sess, &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; } sess = session_mgr_find_reset_error(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 (pMechanism == NULL) { /* As per PKCS#11 v3.0 Init with NULL pMechanism cancels operation */ rc = session_mgr_cancel(tokdata, sess, CKF_DIGEST); goto done; } rc = valid_mech(tokdata, pMechanism); if (rc != CKR_OK) goto done; rc = tokdata->policy->is_mech_allowed(tokdata->policy, pMechanism, NULL, POLICY_CHECK_DIGEST, sess); if (rc != CKR_OK) { TRACE_ERROR("POLICY_VIOLATION on digest initialization\n"); goto done; } if (sess->digest_ctx.active == TRUE) { TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); rc = CKR_OPERATION_ACTIVE; goto done; } sess->digest_ctx.count_statistics = TRUE; /* Policy already checked. */ rc = digest_mgr_init(tokdata, sess, &sess->digest_ctx, pMechanism, FALSE); 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_reset_error(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_reset_error(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_reset_error(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; struct objstrength objstrength; 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_reset_error(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 (pMechanism == NULL) { /* As per PKCS#11 v3.0 Init with NULL pMechanism cancels operation */ rc = session_mgr_cancel(tokdata, sess, CKF_SIGN); goto done; } rc = valid_mech(tokdata, pMechanism); if (rc != CKR_OK) 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_is_common_code_sign_verify_mech(pMechanism) || ep11tok_libica_mech_available(tokdata, pMechanism->mechanism, hKey)) { sess->sign_ctx.count_statistics = TRUE; rc = sign_mgr_init(tokdata, sess, &sess->sign_ctx, pMechanism, FALSE, hKey, TRUE, TRUE); 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 (!is_ec_aggregate_mechanism(pMechanism)) { rc = ep11tok_pkey_usage_ok(tokdata, sess, hKey, pMechanism); if (rc != CKR_OK && rc != CKR_FUNCTION_NOT_SUPPORTED) { /* CKR_FUNCTION_NOT_SUPPORTED indicates pkey support is not available, but the ep11 fallback can be tried */ goto done; } } else { /* No pkey support for aggregate mechs */ rc = CKR_FUNCTION_NOT_SUPPORTED; } if ((ep11tok_optimize_single_ops(tokdata) || ep11tok_mech_single_only(pMechanism)) && rc == CKR_FUNCTION_NOT_SUPPORTED) { /* 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. */ if (!is_ec_aggregate_mechanism(pMechanism)) { rc = ep11tok_check_single_mech_key(tokdata, sess, pMechanism, hKey, OP_SIGN_INIT, &sess->sign_ctx.auth_required); if (rc != CKR_OK) goto done; } else { /* resetting rc to OK */ rc = CKR_OK; sess->sign_ctx.key = CK_INVALID_HANDLE; objstrength.strength = POLICY_STRENGTH_IDX_192; objstrength.siglen = CK_IBM_BLS12_381_SIGN_LEN * 8; objstrength.allowed = CK_TRUE; rc = tokdata->policy->is_mech_allowed(tokdata->policy, pMechanism, &objstrength, POLICY_CHECK_SIGNATURE, sess); if (rc != CKR_OK) { TRACE_ERROR("POLICY_VIOLATION on sign initialization\n"); goto done; } INC_COUNTER(tokdata, sess, pMechanism, NULL, POLICY_STRENGTH_IDX_192); } sess->sign_ctx.init_pending = TRUE; sess->sign_ctx.active = TRUE; if (!is_ec_aggregate_mechanism(pMechanism)) sess->sign_ctx.key = hKey; else sess->sign_ctx.key = CK_INVALID_HANDLE; sess->sign_ctx.mech.mechanism = pMechanism->mechanism; if (pMechanism->pParameter && pMechanism->ulParameterLen > 0) { sess->sign_ctx.mech.pParameter = malloc(pMechanism->ulParameterLen); if (sess->sign_ctx.mech.pParameter) { memcpy(sess->sign_ctx.mech.pParameter, pMechanism->pParameter, pMechanism->ulParameterLen); sess->sign_ctx.mech.ulParameterLen = pMechanism->ulParameterLen; /* Deep copy mechanism parameter, if required */ switch (pMechanism->mechanism) { case CKM_IBM_ML_DSA: rc = ibm_ml_dsa_dup_param(pMechanism->pParameter, sess->sign_ctx.mech.pParameter, pMechanism->ulParameterLen); if (rc != CKR_OK) { TRACE_ERROR("ibm_ml_dsa_dup_param failed\n"); sign_mgr_cleanup(tokdata, sess, &sess->sign_ctx); goto done; } break; default: break; } } else { TRACE_ERROR("%s Memory allocation failed\n", __func__); rc = CKR_HOST_MEMORY; sign_mgr_cleanup(tokdata, sess, &sess->sign_ctx); goto done; } } else { sess->sign_ctx.mech.pParameter = NULL; sess->sign_ctx.mech.ulParameterLen = 0; } switch (pMechanism->mechanism) { case CKM_IBM_EC_AGGREGATE: rc = ec_agg_dup_param((CK_IBM_ECDSA_OTHER_BLS_PARAMS *)pMechanism->pParameter, (CK_IBM_ECDSA_OTHER_BLS_PARAMS *)sess->sign_ctx.mech.pParameter); if (rc != CKR_OK) { TRACE_ERROR("ec_agg_dup_param failed\n"); goto done; } break; } } else { rc = ep11tok_sign_init(tokdata, sess, pMechanism, FALSE, hKey, TRUE); 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; } sess = session_mgr_find_reset_error(tokdata, sSession->sessionh); if (!sess) { TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); rc = CKR_SESSION_HANDLE_INVALID; goto done; } if (!is_ec_aggregate_mechanism(&sess->sign_ctx.mech)) { if (!pData || !pulSignatureLen) { TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); rc = CKR_ARGUMENTS_BAD; 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 (sess->sign_ctx.auth_required == TRUE) { TRACE_ERROR("%s\n", ock_err(ERR_USER_NOT_LOGGED_IN)); rc = CKR_USER_NOT_LOGGED_IN; goto done; } if (!pSignature) length_only = TRUE; if (ep11tok_is_common_code_sign_verify_mech(&sess->sign_ctx.mech) || 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 (!is_ec_aggregate_mechanism(&sess->sign_ctx.mech)) { rc = ep11tok_pkey_usage_ok(tokdata, sess, sess->sign_ctx.key, &sess->sign_ctx.mech); if (rc != CKR_OK && rc != CKR_FUNCTION_NOT_SUPPORTED) { /* CKR_FUNCTION_NOT_SUPPORTED indicates pkey support is not available, but the ep11 fallback can be tried */ goto done; } } else { rc = CKR_FUNCTION_NOT_SUPPORTED; } if ((ep11tok_optimize_single_ops(tokdata) || ep11tok_mech_single_only(&sess->sign_ctx.mech)) && rc == CKR_FUNCTION_NOT_SUPPORTED) { 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)) { if (sess != NULL) sign_mgr_cleanup(tokdata, sess, &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; } sess = session_mgr_find_reset_error(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) { TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); rc = CKR_ARGUMENTS_BAD; goto done; } if (sess->sign_ctx.active == FALSE || ep11tok_mech_single_only(&sess->sign_ctx.mech)) { TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); rc = CKR_OPERATION_NOT_INITIALIZED; goto done; } if (sess->sign_ctx.auth_required == TRUE) { TRACE_ERROR("%s\n", ock_err(ERR_USER_NOT_LOGGED_IN)); rc = CKR_USER_NOT_LOGGED_IN; goto done; } if (ep11tok_is_common_code_sign_verify_mech(&sess->sign_ctx.mech) || 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, FALSE); 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 && sess != NULL) sign_mgr_cleanup(tokdata, sess, &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; } sess = session_mgr_find_reset_error(tokdata, sSession->sessionh); if (!sess) { TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); rc = CKR_SESSION_HANDLE_INVALID; goto done; } if (!pulSignatureLen) { TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); rc = CKR_ARGUMENTS_BAD; goto done; } if (sess->sign_ctx.active == FALSE || ep11tok_mech_single_only(&sess->sign_ctx.mech)) { TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); rc = CKR_OPERATION_NOT_INITIALIZED; goto done; } if (sess->sign_ctx.auth_required == TRUE) { TRACE_ERROR("%s\n", ock_err(ERR_USER_NOT_LOGGED_IN)); rc = CKR_USER_NOT_LOGGED_IN; goto done; } if (!pSignature) length_only = TRUE; if (ep11tok_is_common_code_sign_verify_mech(&sess->sign_ctx.mech) || 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)) { if (sess != NULL) sign_mgr_cleanup(tokdata, sess, &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; } static CK_RV VerifyInit(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey, 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; } sess = session_mgr_find_reset_error(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 (pMechanism == NULL) { /* As per PKCS#11 v3.0 Init with NULL pMechanism cancels operation */ rc = session_mgr_cancel(tokdata, sess, CKF_VERIFY); goto done; } rc = valid_mech(tokdata, pMechanism); if (rc != CKR_OK) goto done; if (sess->verify_ctx.active == TRUE) { rc = CKR_OPERATION_ACTIVE; TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); goto done; } if (pSignature != NULL && ulSignatureLen != 0) { /* Save signature in context for later verification */ sess->verify_ctx.saved_signature = malloc(ulSignatureLen); if (sess->verify_ctx.saved_signature == NULL) { rc = CKR_HOST_MEMORY; TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); goto done; } memcpy(sess->verify_ctx.saved_signature, pSignature, ulSignatureLen); sess->verify_ctx.saved_signature_len = ulSignatureLen; } if (ep11tok_is_common_code_sign_verify_mech(pMechanism) || ep11tok_libica_mech_available(tokdata, pMechanism->mechanism, hKey)) { sess->verify_ctx.count_statistics = TRUE; rc = verify_mgr_init(tokdata, sess, &sess->verify_ctx, pMechanism, FALSE, hKey, TRUE); if (rc != CKR_OK) TRACE_DEVEL("verify_mgr_init() failed.\n"); goto done; } sess->verify_ctx.multi_init = FALSE; sess->verify_ctx.multi = FALSE; rc = ep11tok_pkey_usage_ok(tokdata, sess, hKey, pMechanism); if (rc != CKR_OK && rc != CKR_FUNCTION_NOT_SUPPORTED) { /* CKR_FUNCTION_NOT_SUPPORTED indicates pkey support is not available, but the ep11 fallback can be tried */ goto done; } if ((ep11tok_optimize_single_ops(tokdata) || ep11tok_mech_single_only(pMechanism)) && rc == CKR_FUNCTION_NOT_SUPPORTED) { /* 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. */ rc = ep11tok_check_single_mech_key(tokdata, sess, pMechanism, hKey, OP_VERIFY_INIT, NULL); if (rc != CKR_OK) goto done; 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; if (pMechanism->pParameter && pMechanism->ulParameterLen > 0) { sess->verify_ctx.mech.pParameter = malloc(pMechanism->ulParameterLen); if (sess->verify_ctx.mech.pParameter) { memcpy(sess->verify_ctx.mech.pParameter, pMechanism->pParameter, pMechanism->ulParameterLen); sess->verify_ctx.mech.ulParameterLen = pMechanism->ulParameterLen; /* Deep copy mechanism parameter, if required */ switch (pMechanism->mechanism) { case CKM_IBM_ML_DSA: rc = ibm_ml_dsa_dup_param(pMechanism->pParameter, sess->verify_ctx.mech.pParameter, pMechanism->ulParameterLen); if (rc != CKR_OK) { TRACE_ERROR("ibm_ml_dsa_dup_param failed\n"); verify_mgr_cleanup(tokdata, sess, &sess->verify_ctx); goto done; } break; default: break; } } else { TRACE_ERROR("%s Memory allocation failed\n", __func__); rc = CKR_HOST_MEMORY; verify_mgr_cleanup(tokdata, sess, &sess->verify_ctx); goto done; } } else { sess->verify_ctx.mech.pParameter = NULL; sess->verify_ctx.mech.ulParameterLen = 0; } } 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_Verify%sInit: rc = 0x%08lx, sess = %ld, mech = 0x%lx\n", pSignature != NULL && ulSignatureLen != 0 ? "Signature" : "", 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_VerifyInit(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { return VerifyInit(tokdata, sSession, pMechanism, hKey, NULL, 0); } static CK_RV 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; } sess = session_mgr_find_reset_error(tokdata, sSession->sessionh); if (!sess) { TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); rc = CKR_SESSION_HANDLE_INVALID; goto done; } if (!pData) { TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); rc = CKR_ARGUMENTS_BAD; 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 (sess->verify_ctx.saved_signature == NULL && pSignature == NULL) { /* Operation was initialized with C_VerifyInit() */ TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); rc = CKR_ARGUMENTS_BAD; goto done; } if (sess->verify_ctx.saved_signature != NULL && pSignature != NULL) { /* Operation was initialized with C_VerifySignatureInit() */ TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); rc = CKR_OPERATION_NOT_INITIALIZED; goto done; } if (ep11tok_is_common_code_sign_verify_mech(&sess->verify_ctx.mech) || 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, sess->verify_ctx.saved_signature != NULL ? sess->verify_ctx.saved_signature : pSignature, sess->verify_ctx.saved_signature != NULL ? sess->verify_ctx.saved_signature_len : 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; } rc = ep11tok_pkey_usage_ok(tokdata, sess, sess->verify_ctx.key, &sess->verify_ctx.mech); if (rc != CKR_OK && rc != CKR_FUNCTION_NOT_SUPPORTED) { /* CKR_FUNCTION_NOT_SUPPORTED indicates pkey support is not available, but the ep11 fallback can be tried */ goto done; } if ((ep11tok_optimize_single_ops(tokdata) || ep11tok_mech_single_only(&sess->verify_ctx.mech)) && rc == CKR_FUNCTION_NOT_SUPPORTED) { rc = ep11tok_verify_single(tokdata, sess, &sess->verify_ctx.mech, sess->verify_ctx.key, pData, ulDataLen, sess->verify_ctx.saved_signature != NULL ? sess->verify_ctx.saved_signature : pSignature, sess->verify_ctx.saved_signature != NULL ? sess->verify_ctx.saved_signature_len : ulSignatureLen); if (rc != CKR_OK) TRACE_DEVEL("ep11tok_verify_single() failed.\n"); } else { rc = ep11tok_verify(tokdata, sess, pData, ulDataLen, sess->verify_ctx.saved_signature != NULL ? sess->verify_ctx.saved_signature : pSignature, sess->verify_ctx.saved_signature != NULL ? sess->verify_ctx.saved_signature_len : ulSignatureLen); if (rc != CKR_OK) TRACE_DEVEL("ep11tok_verify() failed.\n"); } done: if (sess != NULL) verify_mgr_cleanup(tokdata, sess, &sess->verify_ctx); TRACE_INFO("C_Verify%s: rc = 0x%08lx, sess = %ld, datalen = %lu\n", pSignature == NULL ? "Signature" : "", rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, ulDataLen); 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) { return Verify(tokdata, sSession, pData, ulDataLen, pSignature, ulSignatureLen); } static CK_RV VerifyUpdate(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen, CK_BBOOL verify_message) { 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_reset_error(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) { TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); rc = CKR_ARGUMENTS_BAD; goto done; } if (sess->verify_ctx.active == FALSE || ep11tok_mech_single_only(&sess->verify_ctx.mech)) { rc = CKR_OPERATION_NOT_INITIALIZED; TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); goto done; } if ((sess->verify_ctx.saved_signature != NULL) != verify_message) { rc = CKR_OPERATION_NOT_INITIALIZED; TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); goto done; } if (ep11tok_is_common_code_sign_verify_mech(&sess->verify_ctx.mech) || 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 && sess != NULL) verify_mgr_cleanup(tokdata, sess, &sess->verify_ctx); TRACE_INFO("C_Verify%sUpdate: rc = 0x%08lx, sess = %ld, datalen = %lu\n", (sess != NULL && sess->verify_ctx.saved_signature != NULL) ? "Signature" : "", rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, ulPartLen); 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) { return VerifyUpdate(tokdata, sSession, pPart, ulPartLen, FALSE); } static CK_RV 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; } sess = session_mgr_find_reset_error(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 || ep11tok_mech_single_only(&sess->verify_ctx.mech)) { rc = CKR_OPERATION_NOT_INITIALIZED; TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); goto done; } if (pSignature == NULL && sess->verify_ctx.saved_signature == NULL) { /* Operation was initialized with C_VerifyInit() */ rc = CKR_OPERATION_NOT_INITIALIZED; TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); goto done; } if (pSignature != NULL && sess->verify_ctx.saved_signature != NULL) { /* Operation was initialized with C_VerifySignatureInit() */ rc = CKR_OPERATION_NOT_INITIALIZED; TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); goto done; } if (ep11tok_is_common_code_sign_verify_mech(&sess->verify_ctx.mech) || ep11tok_libica_mech_available(tokdata, sess->verify_ctx.mech.mechanism, sess->verify_ctx.key)) { rc = verify_mgr_verify_final(tokdata, sess, &sess->verify_ctx, sess->verify_ctx.saved_signature != NULL ? sess->verify_ctx.saved_signature : pSignature, sess->verify_ctx.saved_signature != NULL ? sess->verify_ctx.saved_signature_len : 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, sess->verify_ctx.saved_signature != NULL ? sess->verify_ctx.saved_signature : pSignature, sess->verify_ctx.saved_signature != NULL ? sess->verify_ctx.saved_signature_len : ulSignatureLen); if (rc != CKR_OK) TRACE_DEVEL("ep11tok_verify_final() failed.\n"); done: if (sess != NULL) verify_mgr_cleanup(tokdata, sess, &sess->verify_ctx); TRACE_INFO("C_Verify%sFinal: rc = 0x%08lx, sess = %ld\n", pSignature == NULL ? "Signature" : "", rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle); 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) { if (pSignature == NULL || ulSignatureLen == 0) { TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); return CKR_ARGUMENTS_BAD; } return VerifyFinal(tokdata, sSession, pSignature, ulSignatureLen); } 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_VerifySignatureInit(STDLL_TokData_t *tokdata, ST_SESSION_T *sSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen) { if (pSignature == NULL || ulSignatureLen == 0) { TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); return CKR_ARGUMENTS_BAD; } return VerifyInit(tokdata, sSession, pMechanism, hKey, pSignature, ulSignatureLen); } CK_RV SC_VerifySignature(STDLL_TokData_t *tokdata, ST_SESSION_T *sSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen) { return Verify(tokdata, sSession, pData, ulDataLen, NULL, 0); } CK_RV SC_VerifySignatureUpdate(STDLL_TokData_t *tokdata, ST_SESSION_T *sSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen) { return VerifyUpdate(tokdata, sSession, pPart, ulPartLen, TRUE); } CK_RV SC_VerifySignatureFinal(STDLL_TokData_t *tokdata, ST_SESSION_T *sSession) { return VerifyFinal(tokdata, sSession, NULL, 0); } 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) { CK_RV rc; rc = SC_EncryptUpdate(tokdata, sSession, pPart, ulPartLen, pEncryptedPart, pulEncryptedPartLen); if (rc != CKR_OK || pEncryptedPart == NULL) goto out; rc = SC_DigestUpdate(tokdata, sSession, pPart, ulPartLen); out: return rc; } 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) { CK_RV rc; rc = SC_DecryptUpdate(tokdata, sSession, pEncryptedPart, ulEncryptedPartLen, pPart, pulPartLen); if (rc != CKR_OK || pPart == NULL) goto out; rc = SC_DigestUpdate(tokdata, sSession, pPart, *pulPartLen); out: return rc; } 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) { CK_RV rc; rc = SC_EncryptUpdate(tokdata, sSession, pPart, ulPartLen, pEncryptedPart, pulEncryptedPartLen); if (rc != CKR_OK || pEncryptedPart == NULL) goto out; rc = SC_SignUpdate(tokdata, sSession, pPart, ulPartLen); out: return rc; } 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) { CK_RV rc; rc = SC_DecryptUpdate(tokdata, sSession, pEncryptedPart, ulEncryptedPartLen, pPart, pulPartLen); if (rc != CKR_OK || pPart == NULL) goto out; rc = SC_VerifyUpdate(tokdata, sSession, pPart, *pulPartLen); out: return rc; } 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_reset_error(tokdata, sSession->sessionh); if (!sess) { TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); rc = CKR_SESSION_HANDLE_INVALID; goto done; } rc = tokdata->policy->is_mech_allowed(tokdata->policy, pMechanism, NULL, POLICY_CHECK_KEYGEN, sess); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: Key generation mechanism not allowed\n"); 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, TRUE, OP_KEYGEN); 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_BYTE val[4]; CK_ULONG i; attr = pTemplate; for (i = 0; i < ulCount && attr != NULL; i++, attr++) { TRACE_DEBUG("%lu: Attribute type: 0x%08lx, Value Length: %lu\n", i, attr->type, attr->ulValueLen); if (attr->ulValueLen >= sizeof(val) && attr->pValue != NULL) { memset(val, 0, sizeof(val)); memcpy(val, attr->pValue, attr->ulValueLen > sizeof(val) ? sizeof(val) : attr->ulValueLen); TRACE_DEBUG("First 4 bytes: %02x %02x %02x %02x\n", val[0], val[1], val[2], val[3]); } } #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_reset_error(tokdata, sSession->sessionh); if (!sess) { TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); rc = CKR_SESSION_HANDLE_INVALID; goto done; } rc = tokdata->policy->is_mech_allowed(tokdata->policy, pMechanism, NULL, POLICY_CHECK_KEYGEN, sess); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: Keypair generation mechanism not allowed\n"); 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, TRUE, OP_KEYGEN); 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; 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; for (i = 0; i < ulPublicKeyAttributeCount && attr != NULL; i++, attr++) { TRACE_DEBUG_DUMPATTR(attr); } TRACE_DEBUG("Private Template:\n"); attr = pPrivateKeyTemplate; for (i = 0; i < ulPrivateKeyAttributeCount && attr != NULL; i++, attr++) { TRACE_DEBUG_DUMPATTR(attr); } #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_reset_error(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, TRUE); 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_reset_error(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, OP_UNWRAP); 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 val[4]; CK_ULONG i; attr = pTemplate; for (i = 0; i < ulCount && attr != NULL; i++, attr++) { TRACE_DEBUG("%lu: Attribute type: 0x%08lx, Value Length: %lu\n", i, attr->type, attr->ulValueLen); if (attr->ulValueLen >= sizeof(val) && attr->pValue != NULL) { memset(val, 0, sizeof(val)); memcpy(val, attr->pValue, attr->ulValueLen > sizeof(val) ? sizeof(val) : attr->ulValueLen); TRACE_DEBUG("First 4 bytes: %02x %02x %02x %02x\n", val[0], val[1], val[2], val[3]); } } #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_reset_error(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 (ep11tok_is_common_code_derive_mech(pMechanism)) { rc = key_mgr_derive_key(tokdata, sess, pMechanism, hBaseKey, phKey, pTemplate, ulCount, TRUE, OP_DERIVE); if (rc != CKR_OK) TRACE_DEVEL("key_mgr_derive_key() failed.\n"); } else { rc = ep11tok_derive_key(tokdata, sess, pMechanism, hBaseKey, phKey, pTemplate, ulCount, TRUE, OP_DERIVE); 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 val[4]; 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; for (i = 0; i < ulCount && attr != NULL; i++, attr++) { TRACE_DEBUG("%lu: Attribute type: 0x%08lx, Value Length: %lu\n", i, attr->type, attr->ulValueLen); if (attr->ulValueLen >= sizeof(val) && attr->pValue != NULL) { memset(val, 0, sizeof(val)); memcpy(val, attr->pValue, attr->ulValueLen > sizeof(val) ? sizeof(val) : attr->ulValueLen); TRACE_DEBUG("First 4 bytes: %02x %02x %02x %02x\n", val[0], val[1], val[2], val[3]); } } #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_reset_error(tokdata, sSession->sessionh); if (!sess) { TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); rc = CKR_SESSION_HANDLE_INVALID; goto done; } if (ulRandomLen == 0) 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; } CK_RV SC_EncapsulateKey(STDLL_TokData_t *tokdata, ST_SESSION_T *sSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hPublicKey, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, CK_BYTE_PTR pCiphertext, CK_ULONG_PTR pulCiphertextLen, CK_OBJECT_HANDLE_PTR phKey) { 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 || !pulCiphertextLen) { 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; if (!pCiphertext) length_only = TRUE; sess = session_mgr_find_reset_error(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_encapsulate_key(tokdata, sess, length_only, pMechanism, hPublicKey, pTemplate, ulAttributeCount, pCiphertext, pulCiphertextLen, phKey, TRUE); if (rc != CKR_OK) TRACE_DEVEL("key_mgr_encapsulate_key() failed.\n"); done: TRACE_INFO("SC_EncapsulateKey: rc = 0x%08lx, sess = %ld, priv key = %lu, " "ciphertext = %lu, encpsed key = %lu\n", rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, hPublicKey, (pulCiphertextLen ? *pulCiphertextLen : 0), (phKey ? *phKey : 0)); if (sess != NULL) session_mgr_put(tokdata, sess); return rc; } CK_RV SC_DecapsulateKey(STDLL_TokData_t *tokdata, ST_SESSION_T *sSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hPrivateKey, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, CK_BYTE_PTR pCiphertext, CK_ULONG ulCiphertextLen, 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 || !pCiphertext) { 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_reset_error(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_decapsulate_key(tokdata, sess, pMechanism, hPrivateKey, pTemplate, ulAttributeCount, pCiphertext, ulCiphertextLen, phKey, TRUE); if (rc != CKR_OK) TRACE_DEVEL("key_mgr_decapsulate_key() failed.\n"); done: TRACE_INFO("SC_DecapsulateKey: rc = 0x%08lx, sess = %ld, pub key = %lu, " "encpsed key = %lu\n", rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, hPrivateKey, (phKey ? *phKey : 0)); if (sess != NULL) session_mgr_put(tokdata, sess); return rc; } CK_RV SC_IBM_ReencryptSingle(STDLL_TokData_t *tokdata, ST_SESSION_T *sSession, CK_MECHANISM_PTR pDecrMech, CK_OBJECT_HANDLE hDecrKey, CK_MECHANISM_PTR pEncrMech, CK_OBJECT_HANDLE hEncrKey, CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen, CK_BYTE_PTR pReencryptedData, CK_ULONG_PTR pulReencryptedDataLen) { 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 (!pDecrMech || !pEncrMech) { TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); rc = CKR_ARGUMENTS_BAD; goto done; } sess = session_mgr_find_reset_error(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, pDecrMech); if (rc != CKR_OK) goto done; rc = valid_mech(tokdata, pEncrMech); if (rc != CKR_OK) goto done; if (pDecrMech->mechanism == CKM_AES_XTS || pEncrMech->mechanism == CKM_AES_XTS) { TRACE_ERROR("IBM_ReencryptSingle with AES-XTS is not supported\n"); rc = CKR_MECHANISM_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 || sess->encr_ctx.active == TRUE) { rc = CKR_OPERATION_ACTIVE; TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); goto done; } sess->decr_ctx.count_statistics = TRUE; sess->encr_ctx.count_statistics = TRUE; rc = encr_mgr_reencrypt_single(tokdata, sess, &sess->decr_ctx, pDecrMech, hDecrKey, &sess->encr_ctx, pEncrMech, hEncrKey, pEncryptedData, ulEncryptedDataLen, pReencryptedData, pulReencryptedDataLen); if (rc != CKR_OK) TRACE_DEVEL("encr_mgr_reencrypt_single() failed.\n"); done: TRACE_INFO("SC_IBM_ReencryptSingle: rc = 0x%08lx, sess = %ld, " "decrmech = 0x%lx, encrmech = 0x%lx\n", rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, (pDecrMech ? pDecrMech->mechanism : (CK_ULONG)-1), (pEncrMech ? pEncrMech->mechanism : (CK_ULONG)-1)); if (sess != NULL) session_mgr_put(tokdata, sess); return rc; } CK_RV SC_HandleEvent(STDLL_TokData_t *tokdata, unsigned int event_type, unsigned int event_flags, const char *payload, unsigned int payload_len) { CK_RV rc; if (token_specific.t_handle_event == NULL) return CKR_FUNCTION_NOT_SUPPORTED; rc = token_specific.t_handle_event(tokdata, event_type, event_flags, payload, payload_len); TRACE_INFO("SC_HandleEvent: rc = 0x%08lx, event_type = 0x%08x, " "event_flags = 0x%08x\n", rc, event_type, event_flags); return rc; } 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 = SC_DigestEncryptUpdate; function_list.ST_DecryptDigestUpdate = SC_DecryptDigestUpdate; function_list.ST_SignEncryptUpdate = SC_SignEncryptUpdate; function_list.ST_DecryptVerifyUpdate = 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; function_list.ST_SessionCancel = SC_SessionCancel; function_list.ST_EncapsulateKey = SC_EncapsulateKey; function_list.ST_DecapsulateKey = SC_DecapsulateKey; function_list.ST_VerifySignatureInit = SC_VerifySignatureInit; function_list.ST_VerifySignature = SC_VerifySignature; function_list.ST_VerifySignatureUpdate = SC_VerifySignatureUpdate; function_list.ST_VerifySignatureFinal = SC_VerifySignatureFinal; function_list.ST_IBM_ReencryptSingle = SC_IBM_ReencryptSingle; function_list.ST_HandleEvent = SC_HandleEvent; } opencryptoki-opencryptoki-451d99c/usr/lib/ep11_stdll/tok_struct.h000066400000000000000000000157121520105705100252330ustar00rootroot00000000000000/* * 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", TRUE, // secure key token // 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_get_token_info, &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, &token_specific_ec_edwards_sign, &token_specific_ec_edwards_verify, NULL, // ec_generate_keypair NULL, // ec_edwards_generate_keypair NULL, // ec_montgomery_generate_keypair NULL, // ecdh_derive NULL, // ecdh_derive_kdf // 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, // SHAKE derive NULL, // shake_key_derive // 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_xts_key_gen #ifndef NO_PKEY &token_specific_aes_ecb, &token_specific_aes_cbc, #else 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 NO_PKEY &token_specific_aes_cmac, &token_specific_aes_xts, // aes_xts #else NULL, // aes_cmac NULL, // aes_xts #endif NULL, // aes_key_wrap // DSA NULL, // dsa_generate_keypair, NULL, // dsa_sign NULL, // dsa_verify // PQC NULL, // ibm_ml_dsa_generate_keypair NULL, // ibm_ml_dsa_sign NULL, // ibm_ml_dsa_verify NULL, // ibm_ml_kem_generate_keypair NULL, // ibm_ml_kem_derive NULL, // ml_dsa_generate_keypair &token_specific_ml_dsa_sign, &token_specific_ml_dsa_verify, NULL, // ml_kem_generate_keypair &token_specific_ml_kem_encapsulate_key, &token_specific_ml_kem_decapsulate_key, NULL, // get_mechanism_list NULL, // get mechanism_info &token_specific_object_add, NULL, // key_wrap NULL, // key_unwrap &token_specific_encapsulate_rsa_sym_keygen, &token_specific_encapsulate_rsa_key_wrap, &token_specific_encapsulate_rsa_key_unwrap, &token_specific_encapsulate_dh_ecdh_key_pair_gen, &token_specific_en_decapsulate_dh_ecdh_derive_key, &token_specific_reencrypt_single, &token_specific_set_attribute_values, &token_specific_set_attrs_for_new_object, &token_specific_handle_event, &token_specific_check_obj_access, }; #endif opencryptoki-opencryptoki-451d99c/usr/lib/hsm_mk_change/000077500000000000000000000000001520105705100234665ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/usr/lib/hsm_mk_change/hsm_mk_change.c000066400000000000000000000642421520105705100264250ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2022 * * This program is provided under the terms of the Common Public License, * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this * software constitutes recipient's acceptance of CPL-1.0 terms which can be * found in the file LICENSE file or at * https://opensource.org/licenses/cpl1.0.php */ #include #include #include #include #include #include #include #include #include #include "slotmgr.h" #include "platform.h" #ifdef OCK_TOOL #include "pkcs_utils.h" #else #include "trace.h" #endif #include "hsm_mk_change.h" #include "pkcs32.h" struct hsm_mk_change_op_hdr { char id[6]; uint32_t state; /* stored in big endian */ }; struct hsm_mkvp_hdr { uint32_t type; /* stored in big endian */ uint32_t mkvp_len; /* stored in big endian */ /* Followed by mkvp_len bytes MKVP. */ }; static int hsm_mk_change_lock_fd = -1; CK_RV hsm_mk_change_lock_create(void) { struct group *grp; #if defined(_AIX) /* * AIX needs the fd that is passed to flock to be opened in different modes * for different lock types - shared locks need O_RDONLY, while exclusive * locks need O_WRONLY. Since the lock type is decided at runtime, we need * to be able to handle both. */ const mode_t mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); const int open_flags = O_RDWR; #else const mode_t mode = (S_IRUSR | S_IRGRP); const int open_flags = O_RDONLY; #endif if (hsm_mk_change_lock_fd == -1) hsm_mk_change_lock_fd = open(OCK_HSM_MK_CHANGE_LOCK_FILE, open_flags); if (hsm_mk_change_lock_fd == -1) { hsm_mk_change_lock_fd = open(OCK_HSM_MK_CHANGE_LOCK_FILE, (O_CREAT | open_flags), mode); if (hsm_mk_change_lock_fd != -1) { if (fchmod(hsm_mk_change_lock_fd, mode) == -1) { TRACE_ERROR("%s fchmod(%s): %s\n", __func__, OCK_HSM_MK_CHANGE_LOCK_FILE, strerror(errno)); goto error; } grp = getgrnam(PKCS_GROUP); if (grp != NULL) { if (fchown(hsm_mk_change_lock_fd, -1, grp->gr_gid) == -1) { TRACE_ERROR("%s fchown(%s): %s\n", __func__, OCK_HSM_MK_CHANGE_LOCK_FILE, strerror(errno)); goto error; } } else { TRACE_ERROR("%s getgrnam(): %s\n", __func__, strerror(errno)); goto error; } } else { TRACE_ERROR("%s open(%s): %s\n", __func__, OCK_HSM_MK_CHANGE_LOCK_FILE, strerror(errno)); goto error; } } return CKR_OK; error: if (hsm_mk_change_lock_fd != -1) close(hsm_mk_change_lock_fd); return CKR_CANT_LOCK; } void hsm_mk_change_lock_destroy(void) { if (hsm_mk_change_lock_fd != -1) close(hsm_mk_change_lock_fd); hsm_mk_change_lock_fd = -1; } CK_RV hsm_mk_change_lock(int exclusive) { if (hsm_mk_change_lock_fd == -1) return CKR_CANT_LOCK; if (flock(hsm_mk_change_lock_fd, exclusive ? LOCK_EX : LOCK_SH) != 0) { TRACE_ERROR("%s flock(%s, %s): %s\n", __func__, OCK_HSM_MK_CHANGE_LOCK_FILE, exclusive ? "LOCK_EX" : "LOCK_SH", strerror(errno)); return CKR_CANT_LOCK; } return CKR_OK; } CK_RV hsm_mk_change_unlock(void) { if (hsm_mk_change_lock_fd == -1) return CKR_CANT_LOCK; if (flock(hsm_mk_change_lock_fd, LOCK_UN) != 0) { TRACE_ERROR("%s flock(%s, LOCK_UN): %s\n", __func__, OCK_HSM_MK_CHANGE_LOCK_FILE, strerror(errno)); return CKR_CANT_LOCK; } return CKR_OK; } CK_RV hsm_mk_change_apqns_flatten(const struct apqn *apqns, unsigned int num_apqns, unsigned char *buff, size_t *buff_len) { size_t len = sizeof(uint32_t) + num_apqns * sizeof(struct apqn); struct apqn *apqn; unsigned int i; if (buff == NULL) { *buff_len = len; return CKR_OK; } if (*buff_len < len) { TRACE_ERROR("buffer too small\n"); return CKR_BUFFER_TOO_SMALL; } *buff_len = len; TRACE_DEBUG("Num APQNs: %u\n", num_apqns); *((uint32_t *)buff) = htobe32(num_apqns); buff += sizeof(uint32_t); for (i = 0; i < num_apqns; i++) { TRACE_DEBUG("APQN %d: %02x.%04x\n", i, apqns[i].card, apqns[i].domain); apqn = (struct apqn *)buff; apqn->card = htobe16(apqns[i].card); apqn->domain = htobe16(apqns[i].domain); buff += sizeof(struct apqn); } return CKR_OK; } CK_RV hsm_mk_change_apqns_unflatten(const unsigned char *buff, size_t buff_len, size_t *bytes_read, struct apqn **apqns, unsigned int *num_apqns) { struct apqn *apqn; unsigned int i; CK_RV rc; if (buff_len < sizeof(uint32_t)) { TRACE_ERROR("buffer too small\n"); return CKR_BUFFER_TOO_SMALL; } *num_apqns = be32toh(*((uint32_t *)buff)); buff += sizeof(uint32_t); *bytes_read = sizeof(uint32_t); TRACE_DEBUG("Num APQNs: %u\n", *num_apqns); if (*num_apqns > 0) { *apqns = calloc(*num_apqns, sizeof(struct apqn)); if (*apqns == NULL) { TRACE_ERROR("malloc failed\n"); *num_apqns = 0; return CKR_HOST_MEMORY; } } if (buff_len < sizeof(uint32_t) + *num_apqns * sizeof(struct apqn)) { TRACE_ERROR("buffer too small\n"); rc = CKR_BUFFER_TOO_SMALL; goto error; } for (i = 0; i < *num_apqns; i++) { apqn = (struct apqn *)buff; (*apqns)[i].card = be16toh(apqn->card); (*apqns)[i].domain = be16toh(apqn->domain); buff += sizeof(struct apqn); *bytes_read += sizeof(struct apqn); TRACE_DEBUG("APQN %d: %02x.%04x\n", i, (*apqns)[i].card, (*apqns)[i].domain); } return CKR_OK; error: free(*apqns); *apqns = NULL; *num_apqns = 0; return rc; } int hsm_mk_change_apqns_find(const struct apqn *apqns, unsigned int num_apqns, unsigned short card, unsigned short domain) { unsigned int i; for (i = 0; i < num_apqns; i++) { if (apqns[i].card == card && apqns[i].domain == domain) return 1; } return 0; } void hsm_mk_change_mkvps_clean(struct hsm_mkvp *mkvps, unsigned int num_mkvps) { unsigned int i; for (i = 0; i < num_mkvps; i++) { if (mkvps[i].mkvp != NULL) free(mkvps[i].mkvp); } memset(mkvps, 0, num_mkvps * sizeof(struct hsm_mkvp)); } CK_RV hsm_mk_change_mkvps_flatten(const struct hsm_mkvp *mkvps, unsigned int num_mkvps, unsigned char *buff, size_t *buff_len) { size_t len = sizeof(uint32_t); struct hsm_mkvp_hdr *hdr; unsigned int i; for (i = 0; i < num_mkvps; i++) len += sizeof(struct hsm_mkvp_hdr) + mkvps[i].mkvp_len; if (buff == NULL) { *buff_len = len; return CKR_OK; } if (*buff_len < len) { TRACE_ERROR("buffer too small\n"); return CKR_BUFFER_TOO_SMALL; } *buff_len = len; TRACE_DEBUG("Num MKVPs: %u\n", num_mkvps); *((uint32_t *)buff) = htobe32(num_mkvps); buff += sizeof(uint32_t); for (i = 0; i < num_mkvps; i++) { TRACE_DEBUG("MKVP %d: type: %d len %u\n", i, mkvps[i].type, mkvps[i].mkvp_len); TRACE_DEBUG_DUMP("MKVP: ", mkvps[i].mkvp, mkvps[i].mkvp_len); hdr = (struct hsm_mkvp_hdr *)buff; hdr->type = htobe32(mkvps[i].type); hdr->mkvp_len = htobe32(mkvps[i].mkvp_len); buff += sizeof(struct hsm_mkvp_hdr); memcpy(buff, mkvps[i].mkvp, mkvps[i].mkvp_len); buff += mkvps[i].mkvp_len; } return CKR_OK; } CK_RV hsm_mk_change_mkvps_unflatten(const unsigned char *buff, size_t buff_len, size_t *bytes_read, struct hsm_mkvp **mkvps, unsigned int *num_mkvps) { struct hsm_mkvp_hdr *hdr; unsigned int i; CK_RV rc; if (buff_len < sizeof(uint32_t)) { TRACE_ERROR("buffer too small\n"); return CKR_BUFFER_TOO_SMALL; } *num_mkvps = be32toh(*((uint32_t *)buff)); buff += sizeof(uint32_t); buff_len -= sizeof(uint32_t); *bytes_read = sizeof(uint32_t); TRACE_DEBUG("Num MKVPs: %u\n", *num_mkvps); if (*num_mkvps > 0) { *mkvps = calloc(*num_mkvps, sizeof(struct hsm_mkvp)); if (*mkvps == NULL) { TRACE_ERROR("malloc failed\n"); *num_mkvps = 0; return CKR_HOST_MEMORY; } } for (i = 0; i < *num_mkvps; i++) { if (buff_len < sizeof(struct hsm_mkvp_hdr)) { TRACE_ERROR("buffer too small\n"); rc = CKR_BUFFER_TOO_SMALL; goto error; } hdr = (struct hsm_mkvp_hdr *)buff; (*mkvps)[i].type = be32toh(hdr->type); (*mkvps)[i].mkvp_len = be32toh(hdr->mkvp_len); buff += sizeof(struct hsm_mkvp_hdr); buff_len -= sizeof(struct hsm_mkvp_hdr); *bytes_read += sizeof(struct hsm_mkvp_hdr); if (buff_len < (*mkvps)[i].mkvp_len) { TRACE_ERROR("buffer too small\n"); rc = CKR_BUFFER_TOO_SMALL; goto error; } (*mkvps)[i].mkvp = calloc(1, (*mkvps)[i].mkvp_len); if ((*mkvps)[i].mkvp == NULL) { TRACE_ERROR("malloc failed\n"); rc = CKR_HOST_MEMORY; goto error; } memcpy((*mkvps)[i].mkvp, buff, (*mkvps)[i].mkvp_len); buff += (*mkvps)[i].mkvp_len; buff_len -= (*mkvps)[i].mkvp_len; *bytes_read += (*mkvps)[i].mkvp_len; TRACE_DEBUG("MKVP %d: type: %d len %u\n", i, (*mkvps)[i].type, (*mkvps)[i].mkvp_len); TRACE_DEBUG_DUMP("MKVP: ", (*mkvps)[i].mkvp, (*mkvps)[i].mkvp_len); } return CKR_OK; error: hsm_mk_change_mkvps_clean(*mkvps, *num_mkvps); free(*mkvps); *mkvps = NULL; *num_mkvps = 0; return rc; } const unsigned char *hsm_mk_change_mkvps_find(const struct hsm_mkvp *mkvps, unsigned int num_mkvps, enum hsm_mk_type type, unsigned int mkvp_len) { unsigned int i; for (i = 0; i < num_mkvps; i++) { if (mkvps[i].type == type && (mkvp_len == 0 || mkvps[i].mkvp_len == mkvp_len)) return mkvps[i].mkvp; } return NULL; } void hsm_mk_change_info_clean(struct hsm_mk_change_info *info) { unsigned int i; if (info->apqns != NULL) free(info->apqns); if (info->mkvps != NULL) { for (i = 0; i < info->num_mkvps; i++) { if (info->mkvps[i].mkvp != NULL) free(info->mkvps[i].mkvp); } free(info->mkvps); } memset(info, 0, sizeof(*info)); } CK_RV hsm_mk_change_info_flatten(const struct hsm_mk_change_info *info, unsigned char *buff, size_t *buff_len) { size_t apqns_len, mkvps_len; CK_RV rc; rc = hsm_mk_change_apqns_flatten(info->apqns, info->num_apqns, NULL, &apqns_len); if (rc != CKR_OK) return rc; rc = hsm_mk_change_mkvps_flatten(info->mkvps, info->num_mkvps, NULL, &mkvps_len); if (rc != CKR_OK) return rc; if (buff == NULL) { *buff_len = apqns_len + mkvps_len; return CKR_OK; } if (*buff_len < apqns_len + mkvps_len) { TRACE_ERROR("buffer too small\n"); return CKR_BUFFER_TOO_SMALL; } *buff_len = apqns_len + mkvps_len; rc = hsm_mk_change_apqns_flatten(info->apqns, info->num_apqns, buff, &apqns_len); if (rc != CKR_OK) return rc; rc = hsm_mk_change_mkvps_flatten(info->mkvps, info->num_mkvps, buff + apqns_len, &mkvps_len); if (rc != CKR_OK) return rc; return CKR_OK; } CK_RV hsm_mk_change_info_unflatten(const unsigned char *buff, size_t buff_len, size_t *bytes_read, struct hsm_mk_change_info *info) { size_t apqns_read = 0, mkvps_read = 0; CK_RV rc; hsm_mk_change_info_clean(info); rc = hsm_mk_change_apqns_unflatten(buff, buff_len, &apqns_read, &info->apqns, &info->num_apqns); if (rc != CKR_OK) { hsm_mk_change_info_clean(info); return rc; } rc = hsm_mk_change_mkvps_unflatten(buff + apqns_read, buff_len - apqns_read, &mkvps_read, &info->mkvps, &info->num_mkvps); if (rc != CKR_OK) { hsm_mk_change_info_clean(info); return rc; } *bytes_read = apqns_read + mkvps_read; return CKR_OK; } CK_RV hsm_mk_change_slots_flatten(const CK_SLOT_ID *slots, unsigned int num_slots, unsigned char *buff, size_t *buff_len) { size_t len = sizeof(uint32_t) + num_slots * sizeof(CK_SLOT_ID_32); CK_SLOT_ID_32 *slot; unsigned int i; if (buff == NULL) { *buff_len = len; return CKR_OK; } if (*buff_len < len) { TRACE_ERROR("buffer too small\n"); return CKR_BUFFER_TOO_SMALL; } *buff_len = len; TRACE_DEBUG("Num Slots: %u\n", num_slots); *((uint32_t *)buff) = htobe32(num_slots); buff += sizeof(uint32_t); for (i = 0; i < num_slots; i++) { TRACE_DEBUG("Slot %d: %lu\n", i, slots[i]); slot = (CK_SLOT_ID_32 *)buff; *slot = htobe32(slots[i]); buff += sizeof(CK_SLOT_ID_32); } return CKR_OK; } CK_RV hsm_mk_change_slots_unflatten(const unsigned char *buff, size_t buff_len, size_t *bytes_read, CK_SLOT_ID **slots, unsigned int *num_slots) { CK_SLOT_ID_32 *slot; unsigned int i; CK_RV rc; if (buff_len < sizeof(uint32_t)) { TRACE_ERROR("buffer too small\n"); return CKR_BUFFER_TOO_SMALL; } *num_slots = be32toh(*((uint32_t *)buff)); buff += sizeof(uint32_t); *bytes_read = sizeof(uint32_t); TRACE_DEBUG("Num Slots: %u\n", *num_slots); if (*num_slots > 0) { *slots = calloc(*num_slots, sizeof(CK_SLOT_ID)); if (*slots == NULL) { TRACE_ERROR("malloc failed\n"); *num_slots = 0; return CKR_HOST_MEMORY; } } if (buff_len < sizeof(uint32_t) + *num_slots * sizeof(CK_SLOT_ID_32)) { TRACE_ERROR("buffer too small\n"); rc = CKR_BUFFER_TOO_SMALL; goto error; } for (i = 0; i < *num_slots; i++) { slot = (CK_SLOT_ID_32 *)buff; (*slots)[i] = be32toh(*slot); buff += sizeof(CK_SLOT_ID_32); *bytes_read += sizeof(CK_SLOT_ID_32); TRACE_DEBUG("Slot %d: %lu\n", i, (*slots)[i]); } return CKR_OK; error: free(*slots); *slots = NULL; *num_slots = 0; return rc; } void hsm_mk_change_op_clean(struct hsm_mk_change_op *op) { hsm_mk_change_info_clean(&op->info); if (op->slots != NULL) free(op->slots); memset(op, 0, sizeof(*op)); } static void hsm_mk_change_op_set_perm(int file) { struct group *grp; // Set absolute permissions or rw-rw---- fchmod(file, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); grp = getgrnam(PKCS_GROUP); // Obtain the group id if (grp) { // set ownership to pkcs11 group if (fchown(file, -1, grp->gr_gid) != 0) { goto error; } } else { goto error; } return; error: TRACE_DEVEL("Unable to set permissions on file.\n"); } static FILE* hsm_mk_change_op_open(const char *id, CK_SLOT_ID slot_id, const char *mode) { char hsm_mk_change_file[PATH_MAX]; FILE *fp; if (slot_id != (CK_SLOT_ID)-1) { if (ock_snprintf(hsm_mk_change_file, PATH_MAX, "%s/%s-%lu", OCK_HSM_MK_CHANGE_PATH, id, slot_id) != 0) { TRACE_ERROR("HSM_MK_CHANGE directory path buffer overflow\n"); return NULL; } } else { if (ock_snprintf(hsm_mk_change_file, PATH_MAX, "%s/%s", OCK_HSM_MK_CHANGE_PATH, id) != 0) { TRACE_ERROR("HSM_MK_CHANGE directory path buffer overflow\n"); return NULL; } } TRACE_DEVEL("file to open: %s mode: %s\n", hsm_mk_change_file, mode); /* CWE-59 fix: Use fopen_nofollow to prevent symlink attacks */ fp = fopen_nofollow(hsm_mk_change_file, mode); if (fp == NULL) { if (errno == ELOOP) TRACE_ERROR("Refusing to follow symlink: %s\n", hsm_mk_change_file); else TRACE_ERROR("%s fopen(%s, %s): %s\n", __func__, hsm_mk_change_file, mode, strerror(errno)); } return fp; } CK_RV hsm_mk_change_op_save(const struct hsm_mk_change_op *op) { struct hsm_mk_change_op_hdr *op_hdr; size_t info_len = 0, slots_len, len; unsigned char *buff = NULL; FILE *fp = NULL; CK_RV rc = CKR_OK; rc = hsm_mk_change_info_flatten(&op->info, NULL, &info_len); if (rc != CKR_OK) return rc; rc = hsm_mk_change_slots_flatten(op->slots, op->num_slots, NULL, &slots_len); if (rc != CKR_OK) return rc; len = sizeof(struct hsm_mk_change_op_hdr) + info_len + slots_len; buff = calloc(1, len); if (buff == NULL) { TRACE_ERROR("malloc failed\n"); return CKR_HOST_MEMORY; } TRACE_DEBUG("Id: %s\n", op->id); TRACE_DEBUG("State: %d\n", op->state); op_hdr = (struct hsm_mk_change_op_hdr *)buff; memcpy(op_hdr->id, op->id, sizeof(op_hdr->id)); op_hdr->state = htobe32(op->state); rc = hsm_mk_change_info_flatten(&op->info, buff + sizeof(*op_hdr), &info_len); if (rc != CKR_OK) goto out; rc = hsm_mk_change_slots_flatten(op->slots, op->num_slots, buff + sizeof(*op_hdr) + info_len, &slots_len); if (rc != CKR_OK) goto out; fp = hsm_mk_change_op_open(op->id, -1, "w"); if (fp == NULL) { rc = CKR_FUNCTION_FAILED; goto out; } hsm_mk_change_op_set_perm(fileno(fp)); if (fwrite(buff, len, 1, fp) != 1) { TRACE_ERROR("fwrite(%s): %s\n", op->id, strerror(errno)); rc = CKR_FUNCTION_FAILED; goto out; } out: free(buff); if (fp != NULL) fclose(fp); return rc; } CK_RV hsm_mk_change_op_load(const char *id, struct hsm_mk_change_op *op) { struct hsm_mk_change_op_hdr *op_hdr; struct stat sb; size_t len, info_read = 0, slots_read; FILE *fp; unsigned char *buff = NULL; CK_RV rc = CKR_OK; hsm_mk_change_op_clean(op); fp = hsm_mk_change_op_open(id, -1, "r"); if (fp == NULL) return CKR_FUNCTION_FAILED; if (fstat(fileno(fp), &sb)) { TRACE_ERROR("fstat(%s): %s\n", op->id, strerror(errno)); rc = CKR_FUNCTION_FAILED; goto out; } len = sb.st_size; buff = calloc(1, len); if (buff == NULL) { TRACE_ERROR("malloc failed\n"); rc = CKR_HOST_MEMORY; goto out; } if (fread(buff, len, 1, fp) != 1) { TRACE_ERROR("fread(%s): %s\n", op->id, strerror(errno)); rc = CKR_FUNCTION_FAILED; goto out; } op_hdr = (struct hsm_mk_change_op_hdr *)buff; memcpy(op->id, op_hdr->id, sizeof(op_hdr->id)); op->state = htobe32(op_hdr->state); len -= sizeof(*op_hdr); TRACE_DEBUG("Id: %s\n", op->id); TRACE_DEBUG("State: %d\n", op->state); rc = hsm_mk_change_info_unflatten(buff + sizeof(*op_hdr), len, &info_read, &op->info); if (rc != CKR_OK) goto out; rc = hsm_mk_change_slots_unflatten(buff + sizeof(*op_hdr) + info_read, len - info_read, &slots_read, &op->slots, &op->num_slots); if (rc != CKR_OK) goto out; if (info_read + slots_read != len) { TRACE_ERROR("Not all data read for file %s: len: %zu read: %zu\n", op->id, len, info_read + slots_read); rc = CKR_FUNCTION_FAILED; goto out; } out: if (rc != CKR_OK) hsm_mk_change_op_clean(op); if (buff != NULL) free(buff); fclose(fp); return rc; } CK_RV hsm_mk_change_op_create(struct hsm_mk_change_op *op) { char hsm_mk_change_file[PATH_MAX]; int fd; CK_RV rc; if (ock_snprintf(hsm_mk_change_file, PATH_MAX, "%s/XXXXXX", OCK_HSM_MK_CHANGE_PATH) != 0) { TRACE_ERROR("HSM_MK_CHANGE directory path buffer overflow\n"); return CKR_FUNCTION_FAILED; } fd = mkstemp(hsm_mk_change_file); if (fd < 0) { TRACE_ERROR("mkstemp(%s) failed with: %s\n", hsm_mk_change_file, strerror(errno)); rc = CKR_FUNCTION_FAILED; goto out; } close(fd); /* written and permissions set by hsm_mk_change_op_save */ TRACE_DEVEL("created file: %s\n", hsm_mk_change_file); memcpy(op->id, &hsm_mk_change_file[strlen(hsm_mk_change_file) - 6], 6); rc = hsm_mk_change_op_save(op); out: return rc; } CK_RV hsm_mk_change_token_mkvps_save(const char *id, CK_SLOT_ID slot_id, const struct hsm_mkvp *mkvps, unsigned int num_mkvps) { size_t len = 0; unsigned char *buff = NULL; FILE *fp = NULL; CK_RV rc = CKR_OK; rc = hsm_mk_change_mkvps_flatten(mkvps, num_mkvps, NULL, &len); if (rc != CKR_OK) return rc; buff = calloc(1, len); if (buff == NULL) { TRACE_ERROR("malloc failed\n"); return CKR_HOST_MEMORY; } rc = hsm_mk_change_mkvps_flatten(mkvps, num_mkvps, buff, &len); if (rc != CKR_OK) goto out; fp = hsm_mk_change_op_open(id, slot_id, "w"); if (fp == NULL) { rc = CKR_FUNCTION_FAILED; goto out; } hsm_mk_change_op_set_perm(fileno(fp)); if (fwrite(buff, len, 1, fp) != 1) { TRACE_ERROR("fwrite(%s-%lu): %s\n", id, slot_id, strerror(errno)); rc = CKR_FUNCTION_FAILED; goto out; } out: free(buff); if (fp != NULL) fclose(fp); return rc; } CK_RV hsm_mk_change_token_mkvps_load(const char *id, CK_SLOT_ID slot_id, struct hsm_mkvp **mkvps, unsigned int *num_mkvps) { struct stat sb; size_t len, read = 0; FILE *fp; unsigned char *buff = NULL; CK_RV rc = CKR_OK; fp = hsm_mk_change_op_open(id, slot_id, "r"); if (fp == NULL) return CKR_FUNCTION_FAILED; if (fstat(fileno(fp), &sb)) { TRACE_ERROR("fstat(%s-%lu): %s\n", id, slot_id, strerror(errno)); rc = CKR_FUNCTION_FAILED; goto out; } len = sb.st_size; buff = calloc(1, len); if (buff == NULL) { TRACE_ERROR("malloc failed\n"); rc = CKR_HOST_MEMORY; goto out; } if (fread(buff, len, 1, fp) != 1) { TRACE_ERROR("fread(%s-%lu): %s\n", id, slot_id, strerror(errno)); rc = CKR_FUNCTION_FAILED; goto out; } rc = hsm_mk_change_mkvps_unflatten(buff, len, &read, mkvps, num_mkvps); if (rc != CKR_OK) goto out; if (read != len) { TRACE_ERROR("Not all data read for file %s-%lu: len: %zu read: %zu\n", id, slot_id, len, read); rc = CKR_FUNCTION_FAILED; hsm_mk_change_mkvps_clean(*mkvps, *num_mkvps); goto out; } out: if (buff != NULL) free(buff); fclose(fp); return rc; } CK_RV hsm_mk_change_op_remove(const char *id) { char hsm_mk_change_file[PATH_MAX]; struct dirent **namelist = NULL; CK_RV rc = CKR_OK; int n, i; n = scandir(OCK_HSM_MK_CHANGE_PATH, &namelist, NULL, alphasort); if (n == -1) { TRACE_ERROR("scandir(%s) failed with: %s\n", OCK_HSM_MK_CHANGE_PATH, strerror(errno)); return CKR_FUNCTION_FAILED; } for (i = 0; i < n ; i++) { if (namelist[i]->d_name[0] == '.') continue; if (strncmp(namelist[i]->d_name, id, strlen(id)) != 0) continue; if (ock_snprintf(hsm_mk_change_file, PATH_MAX, "%s/%s", OCK_HSM_MK_CHANGE_PATH, namelist[i]->d_name) != 0) { TRACE_ERROR("HSM_MK_CHANGE file path buffer overflow\n"); rc = CKR_FUNCTION_FAILED; break; } TRACE_DEVEL("remove %s\n", hsm_mk_change_file); if (remove(hsm_mk_change_file) != 0) { TRACE_ERROR("remove(%s) failed with: %s\n", hsm_mk_change_file, strerror(errno)); rc = CKR_FUNCTION_FAILED; break; } } for (i = 0; i < n ; i++) free(namelist[i]); free(namelist); return rc; } CK_RV hsm_mk_change_op_iterate(CK_RV (*cb)(struct hsm_mk_change_op *op, void *private), void *private) { struct hsm_mk_change_op op; struct dirent **namelist = NULL; CK_RV rc = CKR_OK; int n, i; memset(&op, 0, sizeof(op)); n = scandir(OCK_HSM_MK_CHANGE_PATH, &namelist, NULL, alphasort); if (n == -1) { TRACE_ERROR("scandir(%s) failed with: %s\n", OCK_HSM_MK_CHANGE_PATH, strerror(errno)); return CKR_FUNCTION_FAILED; } for (i = 0; i < n ; i++) { if (namelist[i]->d_name[0] == '.') continue; if (strlen(namelist[i]->d_name) > 6 && namelist[i]->d_name[6] == '-') continue; rc = hsm_mk_change_op_load(namelist[i]->d_name, &op); if (rc != CKR_OK) break; rc = cb(&op, private); hsm_mk_change_op_clean(&op); if (rc != CKR_OK) break; } for (i = 0; i < n ; i++) free(namelist[i]); free(namelist); return rc; } opencryptoki-opencryptoki-451d99c/usr/lib/hsm_mk_change/hsm_mk_change.h000066400000000000000000000111511520105705100264210ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2022 * * This program is provided under the terms of the Common Public License, * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this * software constitutes recipient's acceptance of CPL-1.0 terms which can be * found in the file LICENSE file or at * https://opensource.org/licenses/cpl1.0.php */ #ifndef HSM_MK_CHANGE_H #define HSM_MK_CHANGE_H enum hsm_mk_change_state { HSM_MK_CH_STATE_INITIAL = 0, HSM_MK_CH_STATE_REENCIPHERING = 10, /* Tokens are reenciphering the keys */ HSM_MK_CH_STATE_REENCIPHERED = 11, /* Keys are reenciphered */ HSM_MK_CH_STATE_FINALIZING = 20, /* Tokens are finalizing the MK change */ HSM_MK_CH_STATE_CANCELING = 30, /* Tokens are canceling the MK change */ HSM_MK_CH_STATE_ERROR = 100, }; struct apqn { unsigned short card; unsigned short domain; }; enum hsm_mk_type { HSM_MK_TYPE_EP11 = 1, HSM_MK_TYPE_CCA_SYM = 2, HSM_MK_TYPE_CCA_ASYM = 3, HSM_MK_TYPE_CCA_AES = 4, HSM_MK_TYPE_CCA_APKA = 5, }; #define HSM_MK_TYPE_MAX HSM_MK_TYPE_CCA_APKA struct hsm_mkvp { enum hsm_mk_type type; unsigned int mkvp_len; unsigned char *mkvp; }; struct hsm_mk_change_info { unsigned int num_apqns; struct apqn *apqns; unsigned int num_mkvps; struct hsm_mkvp *mkvps; }; struct hsm_mk_change_op { char id[7]; enum hsm_mk_change_state state; struct hsm_mk_change_info info; CK_SLOT_ID *slots; unsigned int num_slots; }; CK_RV hsm_mk_change_apqns_flatten(const struct apqn *apqns, unsigned int num_apqns, unsigned char *buff, size_t *buff_len); CK_RV hsm_mk_change_apqns_unflatten(const unsigned char *buff, size_t buff_len, size_t *bytes_read, struct apqn **apqns, unsigned int *num_apqns); int hsm_mk_change_apqns_find(const struct apqn *apqns, unsigned int num_apqns, unsigned short card, unsigned short domain); void hsm_mk_change_mkvps_clean(struct hsm_mkvp *mkvps, unsigned int num_mkvps); CK_RV hsm_mk_change_mkvps_flatten(const struct hsm_mkvp *mkvps, unsigned int num_mkvps, unsigned char *buff, size_t *buff_len); CK_RV hsm_mk_change_mkvps_unflatten(const unsigned char *buff, size_t buff_len, size_t *bytes_read, struct hsm_mkvp **mkvps, unsigned int *num_mkvps); const unsigned char *hsm_mk_change_mkvps_find(const struct hsm_mkvp *mkvps, unsigned int num_mkvps, enum hsm_mk_type type, unsigned int mkvp_len); void hsm_mk_change_info_clean(struct hsm_mk_change_info *info); CK_RV hsm_mk_change_info_flatten(const struct hsm_mk_change_info *info, unsigned char *buff, size_t *buff_len); CK_RV hsm_mk_change_info_unflatten(const unsigned char *buff, size_t buff_len, size_t *bytes_read, struct hsm_mk_change_info *info); CK_RV hsm_mk_change_slots_flatten(const CK_SLOT_ID *slots, unsigned int num_slots, unsigned char *buff, size_t *buff_len); CK_RV hsm_mk_change_slots_unflatten(const unsigned char *buff, size_t buff_len, size_t *bytes_read, CK_SLOT_ID **slots, unsigned int *num_slots); void hsm_mk_change_op_clean(struct hsm_mk_change_op *op); CK_RV hsm_mk_change_op_save(const struct hsm_mk_change_op *op); CK_RV hsm_mk_change_op_load(const char *id, struct hsm_mk_change_op *op); CK_RV hsm_mk_change_op_create(struct hsm_mk_change_op *op); CK_RV hsm_mk_change_op_remove(const char *id); CK_RV hsm_mk_change_op_iterate(CK_RV (*cb)(struct hsm_mk_change_op *op, void *private), void *private); CK_RV hsm_mk_change_token_mkvps_save(const char *id, CK_SLOT_ID slot_id, const struct hsm_mkvp *mkvps, unsigned int num_mkvps); CK_RV hsm_mk_change_token_mkvps_load(const char *id, CK_SLOT_ID slot_id, struct hsm_mkvp **mkvps, unsigned int *num_mkvps); CK_RV hsm_mk_change_lock_create(void); void hsm_mk_change_lock_destroy(void); CK_RV hsm_mk_change_lock(int exclusive); CK_RV hsm_mk_change_unlock(void); #endif opencryptoki-opencryptoki-451d99c/usr/lib/hsm_mk_change/hsm_mk_change.mk000066400000000000000000000000701520105705100265770ustar00rootroot00000000000000noinst_HEADERS += usr/lib/hsm_mk_change/hsm_mk_change.h opencryptoki-opencryptoki-451d99c/usr/lib/ica_s390_stdll/000077500000000000000000000000001520105705100234175ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/usr/lib/ica_s390_stdll/ica_s390_stdll.mk000066400000000000000000000042511520105705100264660ustar00rootroot00000000000000nobase_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 -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 \ -I${top_builddir}/usr/lib/api -I${srcdir}/usr/lib/api opencryptoki_stdll_libpkcs11_ica_la_LDFLAGS = \ $(LCRYPTO) $(ICA_LIB_DIRS) -nostartfiles -shared \ -Wl,-z,defs,-Bsymbolic -Wl,-soname,$@ -lc -lpthread -lica -ldl \ -lcrypto -lrt -llber \ -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/common/profile_obj.c usr/lib/common/attributes.c \ usr/lib/ica_s390_stdll/ica_specific.c usr/lib/common/dlist.c \ usr/lib/common/mech_openssl.c usr/lib/common/mech_pqc.c \ usr/lib/common/utility_common.c usr/lib/common/ec_supported.c \ usr/lib/api/policyhelper.c usr/lib/common/pqc_supported.c \ usr/lib/common/btree.c usr/lib/common/sess_mgr.c if !HAVE_ALT_FIX_FOR_CVE_2022_4304 opencryptoki_stdll_libpkcs11_ica_la_SOURCES += \ usr/lib/ica_s390_stdll/rsa_sup_mul.c endif opencryptoki-opencryptoki-451d99c/usr/lib/ica_s390_stdll/ica_specific.c000066400000000000000000010411251520105705100261700ustar00rootroot00000000000000/* * 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 #include #include #include "pkcs11types.h" #include "p11util.h" #include "defs.h" #include "host_defs.h" #include "h_extern.h" #include "trace.h" #include "pkcs_utils.h" #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wstrict-prototypes" #include #pragma GCC diagnostic pop #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 #include #define ICA_MAX_MECH_LIST_ENTRIES 154 typedef struct { void *libica_dso; ica_adapter_handle_t adapter_handle; int ica_ec_support_available; int ica_ec_keygen_available; int ica_ec_signverify_available; int ica_ec_derive_available; int ica_ec_edwards_support_available; int ica_ec_edwards_keygen_available; int ica_ec_edwards_signverify_available; int ica_ec_montgomery_support_available; int ica_ec_montgomery_keygen_available; int ica_ec_montgomery_derive_available; int ica_rsa_keygen_available; int ica_rsa_endecrypt_available; int ica_rsa_no_small_pub_exp; int ica_p_rng_available; int ica_sha1_available; int ica_sha2_available; int ica_sha512_224_available; int ica_sha512_256_available; int ica_sha3_available; int ica_shake_available; int ica_aes_available; int ica_new_gcm_available; int ica_des_available; int ica_des3_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 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); #endif typedef void (*ica_cleanup_t) (void); typedef unsigned int (*ica_aes_xts_ex_t)(const unsigned char *in_data, unsigned char *out_data, unsigned long data_length, unsigned char *key1, unsigned char *key2, unsigned int key_length, unsigned char *tweak, unsigned char *iv, unsigned int direction); typedef void (*ica_allow_external_gcm_iv_in_fips_mode_t)(int allow); typedef int (*ica_fips_status_t)(void); #ifndef NO_EC #ifndef NID_X25519 #define NID_X25519 1034 #define NID_X448 1035 #endif #ifndef NID_ED25519 #define NID_ED25519 1087 #define NID_ED448 1088 #endif #ifndef X25519_KEYGEN typedef struct ica_x25519_ctx ICA_X25519_CTX; typedef struct ica_x448_ctx ICA_X448_CTX; typedef struct ica_ed25519_ctx ICA_ED25519_CTX; typedef struct ica_ed448_ctx ICA_ED448_CTX; #endif typedef int (*ica_x25519_ctx_new_t)(ICA_X25519_CTX **ctx); typedef int (*ica_x448_ctx_new_t)(ICA_X448_CTX **ctx); typedef int (*ica_ed25519_ctx_new_t)(ICA_ED25519_CTX **ctx); typedef int (*ica_ed448_ctx_new_t)(ICA_ED448_CTX **ctx); typedef int (*ica_x25519_key_set_t)(ICA_X25519_CTX *ctx, const unsigned char priv[32], const unsigned char pub[32]); typedef int (*ica_x448_key_set_t)(ICA_X448_CTX *ctx, const unsigned char priv[56], const unsigned char pub[56]); typedef int (*ica_ed25519_key_set_t)(ICA_ED25519_CTX *ctx, const unsigned char priv[32], const unsigned char pub[32]); typedef int (*ica_ed448_key_set_t)(ICA_ED448_CTX *ctx, const unsigned char priv[57], const unsigned char pub[57]); typedef int (*ica_x25519_key_get_t)(ICA_X25519_CTX *ctx, unsigned char priv[32], unsigned char pub[32]); typedef int (*ica_x448_key_get_t)(ICA_X448_CTX *ctx, unsigned char priv[56], unsigned char pub[56]); typedef int (*ica_ed25519_key_get_t)(ICA_ED25519_CTX *ctx, unsigned char priv[32], unsigned char pub[32]); typedef int (*ica_ed448_key_get_t)(ICA_ED448_CTX *ctx, unsigned char priv[57], unsigned char pub[57]); typedef int (*ica_x25519_key_gen_t)(ICA_X25519_CTX *ctx); typedef int (*ica_x448_key_gen_t)(ICA_X448_CTX *ctx); typedef int (*ica_ed25519_key_gen_t)(ICA_ED25519_CTX *ctx); typedef int (*ica_ed448_key_gen_t)(ICA_ED448_CTX *ctx); typedef int (*ica_x25519_derive_t)(ICA_X25519_CTX *ctx, unsigned char shared_secret[32], const unsigned char peer_pub[32]); typedef int (*ica_x448_derive_t)(ICA_X448_CTX *ctx, unsigned char shared_secret[56], const unsigned char peer_pub[56]); typedef int (*ica_ed25519_sign_t)(ICA_ED25519_CTX *ctx, unsigned char sig[64], const unsigned char *msg, size_t msglen); typedef int (*ica_ed448_sign_t)(ICA_ED448_CTX *ctx, unsigned char sig[114], const unsigned char *msg, size_t msglen); typedef int (*ica_ed25519_verify_t)(ICA_ED25519_CTX *ctx, const unsigned char sig[64], const unsigned char *msg, size_t msglen); typedef int (*ica_ed448_verify_t)(ICA_ED448_CTX *ctx, const unsigned char sig[114], const unsigned char *msg, size_t msglen); typedef int (*ica_x25519_ctx_del_t)(ICA_X25519_CTX **ctx); typedef int (*ica_x448_ctx_del_t)(ICA_X448_CTX **ctx); typedef int (*ica_ed25519_ctx_del_t)(ICA_ED25519_CTX **ctx); typedef int (*ica_ed448_ctx_del_t)(ICA_ED448_CTX **ctx); #endif /* * These symbols loaded from libica via dlsym() can be static, even if * multiple instances of the ICA token are used. The libica library loaded * via dlopen will return the same symbols when loaded multiple times, but * reference counts the library. * When unloading the library, dlclose unloads the library only when the * reference count of the library is zero. Thus, these symbols are valid until * the library got finally unloaded. */ #ifndef NO_EC 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; #endif static ica_cleanup_t p_ica_cleanup; static ica_aes_xts_ex_t p_ica_aes_xts_ex; static ica_allow_external_gcm_iv_in_fips_mode_t p_ica_allow_external_gcm_iv_in_fips_mode; static ica_fips_status_t p_ica_fips_status; #ifndef NO_EC static ica_x25519_ctx_new_t p_ica_x25519_ctx_new; static ica_x448_ctx_new_t p_ica_x448_ctx_new; static ica_ed25519_ctx_new_t p_ica_ed25519_ctx_new; static ica_ed448_ctx_new_t p_ica_ed448_ctx_new; static ica_x25519_key_set_t p_ica_x25519_key_set; static ica_x448_key_set_t p_ica_x448_key_set; static ica_ed25519_key_set_t p_ica_ed25519_key_set; static ica_ed448_key_set_t p_ica_ed448_key_set; static ica_x25519_key_get_t p_ica_x25519_key_get; static ica_x448_key_get_t p_ica_x448_key_get; static ica_ed25519_key_get_t p_ica_ed25519_key_get; static ica_ed448_key_get_t p_ica_ed448_key_get; static ica_x25519_key_gen_t p_ica_x25519_key_gen; static ica_x448_key_gen_t p_ica_x448_key_gen; static ica_ed25519_key_gen_t p_ica_ed25519_key_gen; static ica_ed448_key_gen_t p_ica_ed448_key_gen; static ica_x25519_derive_t p_ica_x25519_derive; static ica_x448_derive_t p_ica_x448_derive; static ica_ed25519_sign_t p_ica_ed25519_sign; static ica_ed448_sign_t p_ica_ed448_sign; static ica_ed25519_verify_t p_ica_ed25519_verify; static ica_ed448_verify_t p_ica_ed448_verify; static ica_x25519_ctx_del_t p_ica_x25519_ctx_del; static ica_x448_ctx_del_t p_ica_x448_ctx_del; static ica_ed25519_ctx_del_t p_ica_ed25519_ctx_del; static ica_ed448_ctx_del_t p_ica_ed448_ctx_del; #endif static CK_RV mech_list_ica_initialize(STDLL_TokData_t *tokdata); #ifndef NO_EC #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; } static CK_RV ecc_edwards_25519_support_in_libica_available(void) { if (p_ica_ed25519_ctx_new != NULL && p_ica_ed25519_key_set != NULL && p_ica_ed25519_key_get != NULL && p_ica_ed25519_key_gen != NULL && p_ica_ed25519_sign != NULL && p_ica_ed25519_verify != NULL && p_ica_ed25519_ctx_del != NULL) return 1; return 0; } static CK_RV ecc_edwards_448_support_in_libica_available(void) { if (p_ica_ed448_ctx_new != NULL && p_ica_ed448_key_set != NULL && p_ica_ed448_key_get != NULL && p_ica_ed448_key_gen != NULL && p_ica_ed448_sign != NULL && p_ica_ed448_verify != NULL && p_ica_ed448_ctx_del != NULL) return 1; return 0; } static CK_RV ecc_montgomery_25519_support_in_libica_available(void) { if (p_ica_x25519_ctx_new != NULL && p_ica_x25519_key_set != NULL && p_ica_x25519_key_get != NULL && p_ica_x25519_key_gen != NULL && p_ica_x25519_derive != NULL && p_ica_x25519_ctx_del != NULL) return 1; return 0; } static CK_RV ecc_montgomery_448_support_in_libica_available(void) { if (p_ica_x448_ctx_new != NULL && p_ica_x448_key_set != NULL && p_ica_x448_key_get != NULL && p_ica_x448_key_gen != NULL && p_ica_x448_derive != NULL && p_ica_x448_ctx_del != NULL) return 1; return 0; } static CK_RV ecc_edwards_support_in_libica_available(void) { return ecc_edwards_25519_support_in_libica_available() && ecc_edwards_448_support_in_libica_available(); } static CK_RV ecc_montgomery_support_in_libica_available(void) { return ecc_montgomery_25519_support_in_libica_available() && ecc_montgomery_448_support_in_libica_available(); } #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 #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 *sha_context, unsigned char *output_data); static ica_sha3_224_t p_ica_sha3_224; #endif #ifdef SHA3_256 typedef unsigned int (*ica_sha3_256_t)(unsigned int message_part, unsigned int input_length, unsigned char *input_data, sha3_256_context_t *sha_context, unsigned char *output_data); static ica_sha3_256_t p_ica_sha3_256; #endif #ifdef SHA3_384 typedef unsigned int (*ica_sha3_384_t)(unsigned int message_part, unsigned int input_length, unsigned char *input_data, sha3_384_context_t *sha_context, unsigned char *output_data); static ica_sha3_384_t p_ica_sha3_384; #endif #ifdef SHA3_512 typedef unsigned int (*ica_sha3_512_t)(unsigned int message_part, unsigned int input_length, unsigned char *input_data, sha3_512_context_t *sha_context, unsigned char *output_data); static ica_sha3_512_t p_ica_sha3_512; #endif #ifdef SHAKE128 typedef unsigned int (*ica_shake_128_t)(unsigned int message_part, uint64_t input_length, const unsigned char *input_data, shake_128_context_t *shake_128_context, unsigned char *output_data, unsigned int output_length); static ica_shake_128_t p_ica_shake_128; #endif #ifdef SHAKE256 typedef unsigned int (*ica_shake_256_t)(unsigned int message_part, uint64_t input_length, const unsigned char *input_data, shake_256_context_t *shake_128_context, unsigned char *output_data, unsigned int output_length); static ica_shake_256_t p_ica_shake_256; #endif #ifndef HAVE_ALT_FIX_FOR_CVE2022_4304 int ossl_bn_rsa_do_unblind(const unsigned char *intermediate, const BIGNUM *unblind, const unsigned char *to_mod, unsigned char *buf, int num, BN_MONT_CTX *m_ctx, BN_ULONG n0); #endif struct phdr_cb_data { void *handle; }; static int phdr_callback(struct dl_phdr_info *info, size_t size, void *data) { int j; unsigned long start, end; struct phdr_cb_data *d = data; unsigned long myaddr = (unsigned long)&ica_open_adapter; UNUSED(size); for (j = 0; j < info->dlpi_phnum; j++) { /* Only consider loadable program segments */ if (info->dlpi_phdr[j].p_type == PT_LOAD) { start = info->dlpi_addr + info->dlpi_phdr[j].p_vaddr; end = start + info->dlpi_phdr[j].p_memsz; if (start <= myaddr && myaddr < end) { /* Get library handle of already loaded libica */ d->handle = dlopen(info->dlpi_name, RTLD_NOW | RTLD_NOLOAD); break; } } } return 0; } static CK_RV load_libica(ica_private_data_t *ica_data) { struct phdr_cb_data data = { .handle = NULL }; /* Find already loaded libica that it was linked with */ dl_iterate_phdr(phdr_callback, &data); if (data.handle == NULL) { TRACE_ERROR("%s: Failed to find libica: %s\n", __func__, dlerror()); return CKR_FUNCTION_FAILED; } ica_data->libica_dso = data.handle; #ifndef NO_EC /* Try to resolve all needed functions for ecc support */ BIND(ica_data->libica_dso, ica_ec_key_new); BIND(ica_data->libica_dso, ica_ec_key_init); BIND(ica_data->libica_dso, ica_ec_key_generate); BIND(ica_data->libica_dso, ica_ecdh_derive_secret); BIND(ica_data->libica_dso, ica_ecdsa_sign); BIND(ica_data->libica_dso, ica_ecdsa_verify); BIND(ica_data->libica_dso, ica_ec_key_get_public_key); BIND(ica_data->libica_dso, ica_ec_key_get_private_key); BIND(ica_data->libica_dso, ica_ec_key_free); #endif #ifdef SHA512_224 BIND(ica_data->libica_dso, ica_sha512_224); #endif #ifdef SHA512_256 BIND(ica_data->libica_dso, ica_sha512_256); #endif #ifdef SHA3_224 BIND(ica_data->libica_dso, ica_sha3_224); #endif #ifdef SHA3_256 BIND(ica_data->libica_dso, ica_sha3_256); #endif #ifdef SHA3_384 BIND(ica_data->libica_dso, ica_sha3_384); #endif #ifdef SHA3_512 BIND(ica_data->libica_dso, ica_sha3_512); #endif #ifdef SHAKE128 BIND(ica_data->libica_dso, ica_shake_128); #endif #ifdef SHAKE256 BIND(ica_data->libica_dso, ica_shake_256); #endif BIND(ica_data->libica_dso, ica_cleanup); BIND(ica_data->libica_dso, ica_aes_xts_ex); /* * Allow external AES-GCM IV when libica runs in FIPS mode. * ica_allow_external_gcm_iv_in_fips_mode() is not always present and only * available with newer libraries. */ BIND(ica_data->libica_dso, ica_allow_external_gcm_iv_in_fips_mode); if (p_ica_allow_external_gcm_iv_in_fips_mode != NULL) p_ica_allow_external_gcm_iv_in_fips_mode(1); BIND(ica_data->libica_dso, ica_fips_status); #ifndef NO_EC BIND(ica_data->libica_dso, ica_x25519_ctx_new); BIND(ica_data->libica_dso, ica_x448_ctx_new); BIND(ica_data->libica_dso, ica_ed25519_ctx_new); BIND(ica_data->libica_dso, ica_ed448_ctx_new); BIND(ica_data->libica_dso, ica_x25519_key_set); BIND(ica_data->libica_dso, ica_x448_key_set); BIND(ica_data->libica_dso, ica_ed25519_key_set); BIND(ica_data->libica_dso, ica_ed448_key_set); BIND(ica_data->libica_dso, ica_x25519_key_get); BIND(ica_data->libica_dso, ica_x448_key_get); BIND(ica_data->libica_dso, ica_ed25519_key_get); BIND(ica_data->libica_dso, ica_ed448_key_get); BIND(ica_data->libica_dso, ica_x25519_key_gen); BIND(ica_data->libica_dso, ica_x448_key_gen); BIND(ica_data->libica_dso, ica_ed25519_key_gen); BIND(ica_data->libica_dso, ica_ed448_key_gen); BIND(ica_data->libica_dso, ica_x25519_derive); BIND(ica_data->libica_dso, ica_x448_derive); BIND(ica_data->libica_dso, ica_ed25519_sign); BIND(ica_data->libica_dso, ica_ed448_sign); BIND(ica_data->libica_dso, ica_ed25519_verify); BIND(ica_data->libica_dso, ica_ed448_verify); BIND(ica_data->libica_dso, ica_x25519_ctx_del); BIND(ica_data->libica_dso, ica_x448_ctx_del); BIND(ica_data->libica_dso, ica_ed25519_ctx_del); BIND(ica_data->libica_dso, ica_ed448_ctx_del); #endif return CKR_OK; } CK_RV token_specific_rng(STDLL_TokData_t *tokdata, CK_BYTE *output, CK_ULONG bytes) { ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; CK_RV rc = CKR_FUNCTION_FAILED; if (ica_data->ica_p_rng_available) { if (pthread_mutex_lock(&rngmtx)) { TRACE_ERROR("ICA Rng Lock failed.\n"); return CKR_CANT_LOCK; } rc = ica_random_number_generate((unsigned int)bytes, output); if (rc != 0) ica_data->ica_p_rng_available = FALSE; pthread_mutex_unlock(&rngmtx); } if (!ica_data->ica_p_rng_available) rc = local_rng(output, bytes); return rc; } 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(ica_data); if (rc != CKR_OK) goto out; #ifndef NO_EC ica_data->ica_ec_support_available = ecc_support_in_libica_available(); ica_data->ica_ec_edwards_support_available = ecc_edwards_support_in_libica_available(); ica_data->ica_ec_montgomery_support_available = ecc_montgomery_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; } rc = ock_generic_filter_mechanism_list(tokdata, ica_data->mech_list, ica_data->mech_list_len, &(tokdata->mech_list), &(tokdata->mech_list_len)); if (rc != CKR_OK) { TRACE_ERROR("Mechanism filtering failed! rc = 0x%lx\n", rc); return rc; } 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; TRACE_INFO("ica %s running\n", __func__); ica_close_adapter(ica_data->adapter_handle); if (p_ica_cleanup != NULL && !in_fork_initializer) p_ica_cleanup(); if (ica_data->libica_dso != NULL && !in_fork_initializer) dlclose(ica_data->libica_dso); free(tokdata->mech_list); free(ica_data); tokdata->private_data = NULL; return CKR_OK; } typedef struct { struct openssl_ex_data openssl_ex_data; /* This must be the first field ! */ ica_rsa_key_mod_expo_t *modexpoKey; ica_rsa_key_crt_t *crtKey; ICA_EC_KEY *eckey; unsigned int ec_privlen; void *ed_x_ctx; int ed_x_nid; BN_BLINDING *blinding; BN_MONT_CTX *blinding_mont_ctx; #ifndef HAVE_ALT_FIX_FOR_CVE2022_4304 BN_ULONG blinding_mont_ctx_n0; #endif } ica_ex_data_t; void ica_free_ex_data(OBJECT *obj, void *ex_data, size_t ex_data_len) { ica_ex_data_t *data = ex_data; if (ex_data == NULL || ex_data_len < sizeof(ica_ex_data_t)) return; if (data->modexpoKey != NULL) { free(data->modexpoKey->modulus); free(data->modexpoKey->exponent); free(data->modexpoKey); data->modexpoKey = NULL; } if (data->crtKey != NULL) { free(data->crtKey->p); free(data->crtKey->q); free(data->crtKey->dp); free(data->crtKey->dq); free(data->crtKey->qInverse); free(data->crtKey); data->crtKey = NULL; } if (data->eckey != NULL) { p_ica_ec_key_free(data->eckey); data->eckey = NULL; data->ec_privlen = 0; } if (data->blinding != NULL) { BN_BLINDING_free(data->blinding); data->blinding = NULL; } if (data->blinding_mont_ctx != NULL) { BN_MONT_CTX_free(data->blinding_mont_ctx); data->blinding_mont_ctx = NULL; } #ifndef HAVE_ALT_FIX_FOR_CVE2022_4304 data->blinding_mont_ctx_n0 = 0; #endif openssl_free_ex_data(obj, ex_data, ex_data_len); } static CK_BBOOL ica_need_wr_lock_rsa_pubkey(OBJECT *obj, void *ex_data, size_t ex_data_len) { ica_ex_data_t *data = ex_data; UNUSED(obj); if (ex_data == NULL || ex_data_len < sizeof(ica_ex_data_t)) return FALSE; return data->modexpoKey == NULL; } static CK_BBOOL ica_need_wr_lock_rsa_privkey(OBJECT *obj, void *ex_data, size_t ex_data_len) { ica_ex_data_t *data = ex_data; UNUSED(obj); if (ex_data == NULL || ex_data_len < sizeof(ica_ex_data_t)) return FALSE; if (data->blinding == NULL || data->blinding_mont_ctx == NULL) return TRUE; return data->modexpoKey == NULL && data->crtKey == NULL; } static CK_BBOOL ica_need_wr_lock_ec_key(OBJECT *obj, void *ex_data, size_t ex_data_len) { ica_ex_data_t *data = ex_data; UNUSED(obj); if (ex_data == NULL || ex_data_len < sizeof(ica_ex_data_t)) return FALSE; return data->eckey == NULL; } // count_ones_in_byte: for use in adjust_des_key_parity_bits below static CK_BYTE count_ones_in_byte(CK_BYTE byte) { 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, TEMPLATE *tmpl, CK_BYTE **des_key, CK_ULONG *len, CK_ULONG keysize, CK_BBOOL *is_opaque) { UNUSED(tmpl); *des_key = malloc(keysize); if (*des_key == NULL) return CKR_HOST_MEMORY; *len = keysize; *is_opaque = FALSE; // 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 (keysize == (3 * DES_KEY_SIZE)) { rng_generate(tokdata, *des_key, keysize); adjust_des_key_parity_bits(*des_key, keysize, ODD_PARITY); } else { do { rng_generate(tokdata, *des_key, keysize); adjust_des_key_parity_bits(*des_key, keysize, 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) { ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; CK_RV rc; CK_ATTRIBUTE *attr = NULL; if (!ica_data->ica_des_available) return openssl_specific_des_ecb(tokdata, in_data, in_data_len, out_data, out_data_len, key, encrypt); /* * checks for input and output data length and block sizes * are already being carried out in mech_des.c * so we skip those */ rc = template_attribute_get_non_empty(key->template, CKA_VALUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); return rc; } 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) { ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; CK_RV rc; CK_ATTRIBUTE *attr = NULL; if (!ica_data->ica_des_available) return openssl_specific_des_cbc(tokdata, in_data, in_data_len, out_data, out_data_len, key, init_v, encrypt); /* * 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 rc = template_attribute_get_non_empty(key->template, CKA_VALUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); return rc; } 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) { ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; CK_RV rc; CK_ATTRIBUTE *attr = NULL; CK_KEY_TYPE keytype; CK_BYTE key_value[3 * DES_KEY_SIZE]; if (!ica_data->ica_des3_available) return openssl_specific_tdes_ecb(tokdata, in_data, in_data_len, out_data, out_data_len, key, encrypt); /* * 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_get_ulong(key->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key\n"); return rc; } // get the key value rc = template_attribute_get_non_empty(key->template, CKA_VALUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key\n"); return rc; } 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) { ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; CK_RV rc; CK_ATTRIBUTE *attr = NULL; CK_KEY_TYPE keytype; CK_BYTE key_value[3 * DES_KEY_SIZE]; if (!ica_data->ica_des3_available) return openssl_specific_tdes_cbc(tokdata, in_data, in_data_len, out_data, out_data_len, key, init_v, encrypt); /* * 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_get_ulong(key->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key\n"); return rc; } // get the key value rc = template_attribute_get_non_empty(key->template, CKA_VALUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key\n"); return rc; } 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) { ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; CK_RV rc; CK_ATTRIBUTE *attr = NULL; if (!ica_data->ica_des3_available) return openssl_specific_tdes_ofb(tokdata, in_data, data_len, out_data, key, iv, direction); rc = template_attribute_get_non_empty(key->template, CKA_VALUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key\n"); return rc; } 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) { ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; CK_RV rc; CK_ATTRIBUTE *attr = NULL; if (!ica_data->ica_des3_available) return openssl_specific_tdes_cfb(tokdata, in_data, data_len, out_data, key, iv, cfb_len, direction); rc = template_attribute_get_non_empty(key->template, CKA_VALUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key\n"); return rc; } 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) { ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; CK_RV rc; CK_ATTRIBUTE *attr = NULL; CK_KEY_TYPE keytype; CK_BYTE key_value[3 * DES_KEY_SIZE]; if (!ica_data->ica_des3_available) return openssl_specific_tdes_mac(tokdata, message, message_len, key, mac); // get the key type rc = template_attribute_get_ulong(key->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key\n"); return rc; } // get the key value rc = template_attribute_get_non_empty(key->template, CKA_VALUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key\n"); return rc; } 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) { ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; CK_RV rc; CK_ATTRIBUTE *attr = NULL; CK_KEY_TYPE keytype; CK_BYTE key_value[3 * DES_KEY_SIZE]; if (!ica_data->ica_des3_available) return openssl_specific_tdes_cmac(tokdata, message, message_len, key, mac, first, last, ctx); if (key == NULL) return CKR_ARGUMENTS_BAD; // get the key type rc = template_attribute_get_ulong(key->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key\n"); return rc; } // get the key value rc = template_attribute_get_non_empty(key->template, CKA_VALUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key\n"); return rc; } 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; } int ica_sha_supported(STDLL_TokData_t *tokdata, CK_MECHANISM_TYPE mech) { ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; switch (mech) { case CKM_SHA_1: return ica_data->ica_sha1_available; case CKM_SHA224: case CKM_SHA256: case CKM_SHA384: case CKM_SHA512: return ica_data->ica_sha2_available; case CKM_SHA512_224: return ica_data->ica_sha512_224_available; case CKM_SHA512_256: return ica_data->ica_sha512_256_available; case CKM_SHA3_224: case CKM_SHA3_256: case CKM_SHA3_384: case CKM_SHA3_512: case CKM_IBM_SHA3_224: case CKM_IBM_SHA3_256: case CKM_IBM_SHA3_384: case CKM_IBM_SHA3_512: return ica_data->ica_sha3_available; case CKM_SHAKE_128_KEY_DERIVATION: case CKM_SHAKE_256_KEY_DERIVATION: return ica_data->ica_shake_available; default: return FALSE; } } /* * 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; if (!ica_sha_supported(tokdata, mech->mechanism)) return openssl_specific_sha_init(tokdata, ctx, mech); 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; #ifdef SHA3_224 case CKM_SHA3_224: case CKM_IBM_SHA3_224: devctxsize = sizeof(sha3_224_context_t); break; #endif #ifdef SHA3_256 case CKM_SHA3_256: case CKM_IBM_SHA3_256: devctxsize = sizeof(sha3_256_context_t); break; #endif #ifdef SHA3_384 case CKM_SHA3_384: case CKM_IBM_SHA3_384: devctxsize = sizeof(sha3_384_context_t); break; #endif #ifdef SHA3_512 case CKM_SHA3_512: case CKM_IBM_SHA3_512: devctxsize = sizeof(sha3_512_context_t); break; #endif default: return CKR_MECHANISM_INVALID; } /* (re)alloc ctx in one memory area */ if (ctx->context) { free(ctx->context); ctx->context_free_func = NULL; } 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 #ifdef SHA3_224 case CKM_SHA3_224: case CKM_IBM_SHA3_224: sc->hash_len = SHA3_224_HASH_SIZE; sc->hash_blksize = SHA3_224_BLOCK_SIZE; break; #endif #ifdef SHA3_256 case CKM_SHA3_256: case CKM_IBM_SHA3_256: sc->hash_len = SHA3_256_HASH_SIZE; sc->hash_blksize = SHA3_256_BLOCK_SIZE; break; #endif #ifdef SHA3_384 case CKM_SHA3_384: case CKM_IBM_SHA3_384: sc->hash_len = SHA3_384_HASH_SIZE; sc->hash_blksize = SHA3_384_BLOCK_SIZE; break; #endif #ifdef SHA3_512 case CKM_SHA3_512: case CKM_IBM_SHA3_512: sc->hash_len = SHA3_512_HASH_SIZE; sc->hash_blksize = SHA3_512_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; if (!ctx) return CKR_OPERATION_NOT_INITIALIZED; if (!ica_sha_supported(tokdata, ctx->mech.mechanism)) return openssl_specific_sha(tokdata, ctx, in_data, in_data_len, out_data, out_data_len); if (!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 #ifdef SHA3_224 case CKM_SHA3_224: case CKM_IBM_SHA3_224: { sha3_224_context_t *ica_sha3_ctx = (sha3_224_context_t *) dev_ctx; if (p_ica_sha3_224 == NULL) return CKR_MECHANISM_INVALID; rc = p_ica_sha3_224(sc->message_part, in_data_len, in_data, ica_sha3_ctx, sc->hash); break; } #endif #ifdef SHA3_256 case CKM_SHA3_256: case CKM_IBM_SHA3_256: { sha3_256_context_t *ica_sha3_ctx = (sha3_256_context_t *) dev_ctx; if (p_ica_sha3_256 == NULL) return CKR_MECHANISM_INVALID; rc = p_ica_sha3_256(sc->message_part, in_data_len, in_data, ica_sha3_ctx, sc->hash); break; } #endif #ifdef SHA3_384 case CKM_SHA3_384: case CKM_IBM_SHA3_384: { sha3_384_context_t *ica_sha3_ctx = (sha3_384_context_t *) dev_ctx; if (p_ica_sha3_384 == NULL) return CKR_MECHANISM_INVALID; rc = p_ica_sha3_384(sc->message_part, in_data_len, in_data, ica_sha3_ctx, sc->hash); break; } #endif #ifdef SHA3_512 case CKM_SHA3_512: case CKM_IBM_SHA3_512: { sha3_512_context_t *ica_sha3_ctx = (sha3_512_context_t *) dev_ctx; if (p_ica_sha3_512 == NULL) return CKR_MECHANISM_INVALID; rc = p_ica_sha3_512(sc->message_part, in_data_len, in_data, ica_sha3_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 #ifdef SHA3_224 case CKM_SHA3_224: case CKM_IBM_SHA3_224: { sha3_224_context_t *ica_sha_ctx = (sha3_224_context_t *) dev_ctx; if (p_ica_sha3_224 == NULL) return CKR_MECHANISM_INVALID; if (ica_sha_ctx->runningLength == 0) sc->message_part = SHA_MSG_PART_FIRST; else sc->message_part = SHA_MSG_PART_MIDDLE; ret = p_ica_sha3_224(sc->message_part, data_len, data, ica_sha_ctx, sc->hash); break; } #endif #ifdef SHA3_256 case CKM_SHA3_256: case CKM_IBM_SHA3_256: { sha3_256_context_t *ica_sha_ctx = (sha3_256_context_t *) dev_ctx; if (p_ica_sha3_256 == NULL) return CKR_MECHANISM_INVALID; if (ica_sha_ctx->runningLength == 0) sc->message_part = SHA_MSG_PART_FIRST; else sc->message_part = SHA_MSG_PART_MIDDLE; ret = p_ica_sha3_256(sc->message_part, data_len, data, ica_sha_ctx, sc->hash); break; } #endif #ifdef SHA3_384 case CKM_SHA3_384: case CKM_IBM_SHA3_384: { sha3_384_context_t *ica_sha_ctx = (sha3_384_context_t *) dev_ctx; if (p_ica_sha3_384 == 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_sha3_384(sc->message_part, data_len, data, ica_sha_ctx, sc->hash); break; } #endif #ifdef SHA3_512 case CKM_SHA3_512: case CKM_IBM_SHA3_512: { sha3_512_context_t *ica_sha_ctx = (sha3_512_context_t *) dev_ctx; if (p_ica_sha3_512 == 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_sha3_512(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; if (!ctx) return CKR_OPERATION_NOT_INITIALIZED; if (!ica_sha_supported(tokdata, ctx->mech.mechanism)) return openssl_specific_sha_update(tokdata, ctx, in_data, in_data_len); if (!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; if (!ctx) return CKR_OPERATION_NOT_INITIALIZED; if (!ica_sha_supported(tokdata, ctx->mech.mechanism)) return openssl_specific_sha_final(tokdata, ctx, out_data, out_data_len); if (!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 #ifdef SHA3_224 case CKM_SHA3_224: case CKM_IBM_SHA3_224: { sha3_224_context_t *ica_sha3_ctx = (sha3_224_context_t *) dev_ctx; if (p_ica_sha3_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_sha3_ctx->runningLength == 0) sc->message_part = SHA_MSG_PART_ONLY; rc = p_ica_sha3_224(sc->message_part, sc->tail_len, sc->tail, ica_sha3_ctx, sc->hash); break; } #endif #ifdef SHA3_256 case CKM_SHA3_256: case CKM_IBM_SHA3_256: { sha3_256_context_t *ica_sha3_ctx = (sha3_256_context_t *) dev_ctx; if (p_ica_sha3_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_sha3_ctx->runningLength == 0) sc->message_part = SHA_MSG_PART_ONLY; rc = p_ica_sha3_256(sc->message_part, sc->tail_len, sc->tail, ica_sha3_ctx, sc->hash); break; } #endif #ifdef SHA3_384 case CKM_SHA3_384: case CKM_IBM_SHA3_384: { sha3_384_context_t *ica_sha3_ctx = (sha3_384_context_t *) dev_ctx; if (p_ica_sha3_384 == 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_sha3_ctx->runningLengthLow == 0 && ica_sha3_ctx->runningLengthHigh == 0) sc->message_part = SHA_MSG_PART_ONLY; rc = p_ica_sha3_384(sc->message_part, sc->tail_len, sc->tail, ica_sha3_ctx, sc->hash); break; } #endif #ifdef SHA3_512 case CKM_SHA3_512: case CKM_IBM_SHA3_512: { sha3_512_context_t *ica_sha3_ctx = (sha3_512_context_t *) dev_ctx; if (p_ica_sha3_512 == 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_sha3_ctx->runningLengthLow == 0 && ica_sha3_ctx->runningLengthHigh == 0) sc->message_part = SHA_MSG_PART_ONLY; rc = p_ica_sha3_512(sc->message_part, sc->tail_len, sc->tail, ica_sha3_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; } static CK_RV ica_specific_shake_key_derive(STDLL_TokData_t *tokdata, SESSION *sess, CK_MECHANISM *mech, OBJECT *base_key_obj, CK_KEY_TYPE base_key_type, OBJECT *derived_key_obj, CK_KEY_TYPE derived_key_type, CK_ULONG derived_key_len) { CK_ATTRIBUTE *base_key_value = NULL; CK_ATTRIBUTE *value_attr = NULL, *vallen_attr = NULL; CK_BYTE *derived_key_value = NULL; CK_RV rc; UNUSED(tokdata); UNUSED(sess); UNUSED(base_key_type); rc = template_attribute_get_non_empty(base_key_obj->template, CKA_VALUE, &base_key_value); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the base key.\n"); return rc; } derived_key_value = malloc(derived_key_len); if (derived_key_value == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto out; } switch (mech->mechanism) { case CKM_SHAKE_128_KEY_DERIVATION: { shake_128_context_t shake_128_context; rc = p_ica_shake_128(SHA_MSG_PART_ONLY, base_key_value->ulValueLen, base_key_value->pValue, &shake_128_context, derived_key_value, derived_key_len); rc = rc != 0 ? CKR_FUNCTION_FAILED : CKR_OK; } break; case CKM_SHAKE_256_KEY_DERIVATION: { shake_256_context_t shake_256_context; rc = p_ica_shake_256(SHA_MSG_PART_ONLY, base_key_value->ulValueLen, base_key_value->pValue, &shake_256_context, derived_key_value, derived_key_len); rc = rc != 0 ? CKR_FUNCTION_FAILED : CKR_OK; } break; default: TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); rc = CKR_MECHANISM_INVALID; } if (rc != CKR_OK) goto out; rc = build_attribute(CKA_VALUE, derived_key_value, derived_key_len, &value_attr); if (rc != CKR_OK) { TRACE_ERROR("Failed to build the attribute from CKA_VALUE, rc=0x%lx.\n", rc); goto out; } switch (derived_key_type) { case CKK_GENERIC_SECRET: case CKK_SHA_1_HMAC: case CKK_SHA224_HMAC: case CKK_SHA256_HMAC: case CKK_SHA384_HMAC: case CKK_SHA512_HMAC: case CKK_SHA3_224_HMAC: case CKK_SHA3_256_HMAC: case CKK_SHA3_384_HMAC: case CKK_SHA3_512_HMAC: case CKK_SHA512_224_HMAC: case CKK_SHA512_256_HMAC: case CKK_AES: case CKK_AES_XTS: /* Supply CKA_VALUE_LEN since this is required for those key types */ rc = build_attribute(CKA_VALUE_LEN, (CK_BYTE*)&derived_key_len, sizeof(derived_key_len), &vallen_attr); if (rc != CKR_OK) { TRACE_ERROR("Failed to build the attribute from CKA_VALUE_LEN, " "rc=0x%lx.\n", rc); goto out; } break; case CKK_DES: if (des_check_weak_key(derived_key_value)) { TRACE_ERROR("Derived key is a weak DES key\n"); rc = CKR_FUNCTION_FAILED; goto out; } break; default: break; } rc = template_update_attribute(derived_key_obj->template, value_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto out; } value_attr = NULL; if (vallen_attr != NULL) { rc = template_update_attribute(derived_key_obj->template, vallen_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto out; } vallen_attr = NULL; } out: if (derived_key_value != NULL) { OPENSSL_cleanse(derived_key_value, derived_key_len); free(derived_key_value); } if (value_attr != NULL) free(value_attr); if (vallen_attr != NULL) free(vallen_attr); return rc; } CK_RV token_specific_shake_key_derive(STDLL_TokData_t *tokdata, SESSION *sess, CK_MECHANISM *mech, OBJECT *base_key_obj, CK_KEY_TYPE base_key_type, OBJECT *derived_key_obj, CK_KEY_TYPE derived_key_type, CK_ULONG derived_key_len) { if (!ica_sha_supported(tokdata, mech->mechanism)) return openssl_specific_shake_key_derive(tokdata, sess, mech, base_key_obj, base_key_type, derived_key_obj, derived_key_type, derived_key_len); return ica_specific_shake_key_derive(tokdata, sess, mech, base_key_obj, base_key_type, derived_key_obj, derived_key_type, derived_key_len); } #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 == sizeof(CK_ULONG) && (*(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: if (modexpokey != NULL) { 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_length/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 + 1) / 2)) || (prime2->ulValueLen > ((crtkey->key_length + 1) / 2)) || (exp1->ulValueLen > ((crtkey->key_length + 1) / 2)) || (exp2->ulValueLen > ((crtkey->key_length + 1) / 2)) || (coeff->ulValueLen > ((crtkey->key_length + 1) / 2))) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); goto err_crtkey; } crtkey->p = (unsigned char *) calloc(1, ((crtkey->key_length + 1) / 2) + 8); if (crtkey->p == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); goto err_crtkey; } ptr = crtkey->p + ((crtkey->key_length + 1) / 2) + 8 - prime1->ulValueLen; memcpy(ptr, prime1->pValue, prime1->ulValueLen); crtkey->q = (unsigned char *) calloc(1, (crtkey->key_length + 1) / 2); if (crtkey->q == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); goto err_crtkey; } ptr = crtkey->q + ((crtkey->key_length + 1) / 2) - prime2->ulValueLen; memcpy(ptr, prime2->pValue, prime2->ulValueLen); crtkey->dp = (unsigned char *) calloc(1, ((crtkey->key_length + 1) / 2) + 8); if (crtkey->dp == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); goto err_crtkey; } ptr = crtkey->dp + ((crtkey->key_length + 1) / 2) + 8 - exp1->ulValueLen; memcpy(ptr, exp1->pValue, exp1->ulValueLen); crtkey->dq = (unsigned char *) calloc(1, (crtkey->key_length + 1) / 2); if (crtkey->dq == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); goto err_crtkey; } ptr = crtkey->dq + ((crtkey->key_length + 1) / 2) - exp2->ulValueLen; memcpy(ptr, exp2->pValue, exp2->ulValueLen); crtkey->qInverse = (unsigned char *) calloc(1, ((crtkey->key_length + 1) / 2) + 8); if (crtkey->qInverse == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); goto err_crtkey; } ptr = crtkey->qInverse + ((crtkey->key_length + 1) / 2) + 8 - coeff->ulValueLen; memcpy(ptr, coeff->pValue, coeff->ulValueLen); /* If p < q, swap and recalculate now */ if (ica_rsa_crt_key_check(crtkey) > 1) { TRACE_ERROR("ica_rsa_crt_key_check failed\n"); goto err_crtkey; } return crtkey; } err_crtkey: free(crtkey->p); free(crtkey->q); free(crtkey->dp); free(crtkey->dq); free(crtkey->qInverse); free(crtkey); return NULL; } static CK_RV rsa_calc_private_exponent(ica_rsa_key_mod_expo_t *publKey, ica_rsa_key_crt_t *privKey, TEMPLATE *priv_tmpl) { BIGNUM *d, *e = NULL, *p = NULL, *q = NULL; CK_ATTRIBUTE *attr = NULL; int len; CK_BYTE *buff = NULL; CK_RV rc = CKR_OK; d = BN_secure_new(); e = BN_secure_new(); p = BN_secure_new(); q = BN_secure_new(); if (d == NULL || e == NULL || p == NULL || q == NULL) { TRACE_DEVEL("BN_secure_new failed\n"); rc = CKR_HOST_MEMORY; goto done; } /* * Calculate Ï•(n) = (p − 1) * (q − 1) = n − p − q + 1. * Then d = e ^−1 mod Ï•(n) */ if (BN_bin2bn(publKey->modulus, publKey->key_length, d) == NULL || BN_bin2bn(publKey->exponent, publKey->key_length, e) == NULL || BN_bin2bn(privKey->p + 8, privKey->key_length / 2, p) == NULL || BN_bin2bn(privKey->q, privKey->key_length / 2, q) == NULL) { TRACE_DEVEL("BN_bin2bn failed\n"); rc = CKR_FUNCTION_FAILED; goto done; } if (BN_sub(d, d, p) != 1 || BN_sub(d, d, q) != 1 || BN_add_word(d, 1) != 1 || BN_mod_inverse(d, e, d, NULL) == NULL) { TRACE_DEVEL("BN_sub/BN_add_word/BN_mod_inverse failed\n"); rc = CKR_FUNCTION_FAILED; goto done; } len = BN_num_bytes(d); buff = calloc(len, 1); if (buff == NULL) { TRACE_DEVEL("calloc failed\n"); rc = CKR_HOST_MEMORY; goto done; } if (BN_bn2bin(d, buff) != len) { TRACE_DEVEL("BN_bn2bin failed\n"); rc = CKR_FUNCTION_FAILED; goto done; } rc = build_attribute(CKA_PRIVATE_EXPONENT, buff, len, &attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto done; } rc = template_update_attribute(priv_tmpl, attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto done; } attr = NULL; done: if (d != NULL) BN_clear_free(d); if (e != NULL) BN_clear_free(e); if (p != NULL) BN_clear_free(p); if (q != NULL) BN_clear_free(q); if (buff != NULL) free(buff); if (attr != NULL) free(attr); return rc; } // static CK_RV ica_specific_rsa_keygen(STDLL_TokData_t *tokdata, 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; unsigned int try = 0; rc = template_attribute_get_ulong(publ_tmpl, CKA_MODULUS_BITS, &mod_bits); if (rc != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); return CKR_TEMPLATE_INCOMPLETE; // should never happen } rc = template_attribute_get_non_empty(publ_tmpl, CKA_PUBLIC_EXPONENT, &publ_exp); if (rc != CKR_OK) { 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)); rc = CKR_TEMPLATE_INCONSISTENT; goto pubkey_cleanup; } /* Check if small public exponents are allowed */ if (ica_data->ica_rsa_no_small_pub_exp && *((unsigned long *) ptr) != 0 && *((unsigned long *) ptr) < 65537) { TRACE_ERROR("No small RSA public exponents allowed\n"); rc = CKR_KEY_SIZE_RANGE; goto pubkey_cleanup; } /* 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 + 1) / 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 + 1) / 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 + 1) / 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 + 1) / 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 + 1) / 2) + 8); if (privKey->qInverse == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto privkey_cleanup; } retry: try++; rc = ica_rsa_key_generate_crt(ica_data->adapter_handle, (unsigned int) mod_bits, publKey, privKey); switch (rc) { case 0: rc = CKR_OK; break; case EINVAL: TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); rc = CKR_ARGUMENTS_BAD; goto privkey_cleanup; break; case ENODEV: TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); rc = CKR_FUNCTION_NOT_SUPPORTED; goto privkey_cleanup; break; case EPERM: TRACE_ERROR("%s\n", ock_err(ERR_KEY_SIZE_RANGE)); rc = CKR_KEY_SIZE_RANGE; goto privkey_cleanup; break; default: TRACE_ERROR("%s (try %u)\n", ock_err(ERR_FUNCTION_FAILED), try); rc = CKR_FUNCTION_FAILED; if (try <= 10) goto retry; goto privkey_cleanup; break; } /* 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; } rc = template_update_attribute(publ_tmpl, attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto privkey_cleanup; } attr = NULL; // 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; } rc = template_update_attribute(publ_tmpl, attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto privkey_cleanup; } attr = 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 privkey_cleanup; } rc = template_update_attribute(publ_tmpl, attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto privkey_cleanup; } attr = NULL; // // 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; } rc = template_update_attribute(priv_tmpl, attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto privkey_cleanup; } attr = NULL; // 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; } rc = template_update_attribute(priv_tmpl, attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto privkey_cleanup; } attr = NULL; /* Calculate the private exponent and add it */ rc = rsa_calc_private_exponent(publKey, privKey, priv_tmpl); if (rc != CKR_OK) { TRACE_ERROR("rsa_calc_private_exponent failed\n"); goto privkey_cleanup; } // exponent 1: d mod(p-1) // tmpsize = (privKey->key_length + 1) / 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; } rc = template_update_attribute(priv_tmpl, attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto privkey_cleanup; } attr = NULL; // exponent 2: d mod(q-1) // tmpsize = (privKey->key_length + 1) / 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; } rc = template_update_attribute(priv_tmpl, attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto privkey_cleanup; } attr = NULL; // prime #1: p // tmpsize = (privKey->key_length + 1) / 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; } rc = template_update_attribute(priv_tmpl, attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto privkey_cleanup; } attr = NULL; // prime #2: q // tmpsize = (privKey->key_length + 1) / 2; ptr = p11_bigint_trim(privKey->q, &tmpsize); rc = build_attribute(CKA_PRIME_2, ptr, tmpsize, &attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto privkey_cleanup; } rc = template_update_attribute(priv_tmpl, attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto privkey_cleanup; } attr = NULL; // CRT coefficient: q_inverse mod(p) // tmpsize = (privKey->key_length + 1) / 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; } rc= template_update_attribute(priv_tmpl, attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); goto privkey_cleanup; } attr = NULL; 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); if (attr != NULL) free(attr); return rc; } CK_RV token_specific_rsa_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 rc = CKR_FUNCTION_FAILED; if (ica_data->ica_rsa_keygen_available) { rc = ica_specific_rsa_keygen(tokdata, publ_tmpl, priv_tmpl); if (rc == CKR_FUNCTION_NOT_SUPPORTED) ica_data->ica_rsa_keygen_available = FALSE; } if (!ica_data->ica_rsa_keygen_available) rc = openssl_specific_rsa_keygen(publ_tmpl, priv_tmpl); if (rc != CKR_OK) TRACE_DEVEL("ica/openssl_specific_rsa_keygen failed\n"); return rc; } /* * ICA token private data used by mod-expo callback function for generating the * blinding factor by BN_BLINDING_create_param() or within BN_BLINDING_update() * when a new blinding factor is generated after 32 requests. * This variable must be thread local! */ static __thread ica_private_data_t *ica_blinding_private_data = NULL; static int ica_blinding_bn_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx) { ica_private_data_t *ica_data = ica_blinding_private_data; ica_rsa_key_mod_expo_t ica_mode_expo; unsigned char *buffer, *in, *out; size_t size; int rc = 0; if (ica_data == NULL) return 0; size = BN_num_bytes(m); buffer = calloc(1, 4 * size); if (buffer == NULL) { TRACE_ERROR("Failed to allocate a buffer for libica mod-expo\n"); goto out; } ica_mode_expo.key_length = size; ica_mode_expo.modulus = buffer; ica_mode_expo.exponent = buffer + size; in = buffer + 2 * size; out = buffer + 3 * size; if (BN_bn2binpad(a, in, size) == -1 || BN_bn2binpad(p, ica_mode_expo.exponent, size) == -1 || BN_bn2binpad(m, ica_mode_expo.modulus, size) == -1) { TRACE_ERROR("BN_bn2binpad failed\n"); goto out; } rc = ica_rsa_mod_expo(ica_data->adapter_handle, in, &ica_mode_expo, out); if (rc != 0) { TRACE_ERROR("ica_rsa_mod_expo failed with: %s\n", strerror(rc)); rc = 0; goto out; } if (BN_bin2bn(out, size, r) == NULL) { TRACE_ERROR("BN_bin2bn failed\n"); goto out; } rc = 1; out: if (buffer != NULL) { OPENSSL_cleanse(buffer, 4 * size); free(buffer); } /* Use software fallback if libica operation failed */ return rc != 1 ? BN_mod_exp_mont(r, a, p, m, ctx, m_ctx) : 1; } #ifndef HAVE_ALT_FIX_FOR_CVE2022_4304 #ifdef SIXTY_FOUR_BIT_LONG #define BN_MASK2 (0xffffffffffffffffL) #endif #ifdef SIXTY_FOUR_BIT #define BN_MASK2 (0xffffffffffffffffLL) #endif #ifdef THIRTY_TWO_BIT #error "Not supported" #endif static CK_RV ica_calc_blinding_mont_ctx_n0(STDLL_TokData_t *tokdata, ica_ex_data_t *ex_data, BN_CTX *bn_ctx, CK_ATTRIBUTE *modulus) { BIGNUM *R = NULL, *Ri = NULL, *tmod = NULL; BN_ULONG word; UNUSED(tokdata); /* Calculate blinding_mont_ctx_n0, BN_MONT_CTX is opaque */ R = BN_CTX_get(bn_ctx); Ri = BN_CTX_get(bn_ctx); tmod = BN_CTX_get(bn_ctx); if (R == NULL || Ri == NULL || tmod == NULL) { TRACE_ERROR("BN_CTX_get failed\n"); return CKR_FUNCTION_FAILED; } BN_zero(R); if (!BN_set_bit(R, BN_BITS2)) { TRACE_ERROR("BN_set_bit failed\n"); return CKR_FUNCTION_FAILED; } memcpy(&word, ((CK_BYTE *)modulus->pValue) + modulus->ulValueLen - sizeof(BN_ULONG), sizeof(word)); if (!BN_set_word(tmod, word)) { TRACE_ERROR("BN_set_word failed\n"); return CKR_FUNCTION_FAILED; } if (BN_is_one(tmod)) BN_zero(Ri); else if ((BN_mod_inverse(Ri, R, tmod, bn_ctx)) == NULL) { TRACE_ERROR("BN_mod_inverse failed\n"); return CKR_FUNCTION_FAILED; } if (!BN_lshift(Ri, Ri, BN_BITS2)) { TRACE_ERROR("BN_lshift failed\n"); return CKR_FUNCTION_FAILED; } if (!BN_is_zero(Ri)) { if (!BN_sub_word(Ri, 1)) { TRACE_ERROR("BN_sub_word failed\n"); return CKR_FUNCTION_FAILED; } } else { if (!BN_set_word(Ri, BN_MASK2)) { TRACE_ERROR("BN_set_word failed\n"); return CKR_FUNCTION_FAILED; } } if (!BN_div(Ri, NULL, Ri, tmod, bn_ctx)) { TRACE_ERROR("BN_div failed\n"); return CKR_FUNCTION_FAILED; } ex_data->blinding_mont_ctx_n0 = BN_get_word(Ri); return CKR_OK; } #endif static CK_RV ica_blinding_setup(STDLL_TokData_t *tokdata, OBJECT *key_obj, ica_ex_data_t *ex_data, BN_CTX *bn_ctx) { ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; CK_ATTRIBUTE *modulus = NULL, *pub_exp = NULL; CK_RV rc = CKR_OK; BIGNUM *n, *e; /* Get modulus a BIGNUM */ rc = template_attribute_get_non_empty(key_obj->template, CKA_MODULUS, &modulus); if (rc != CKR_OK) { TRACE_ERROR("Failed to get CKA_MODULUS\n"); goto done; } n = BN_CTX_get(bn_ctx); if (n == NULL || BN_bin2bn(modulus->pValue, modulus->ulValueLen, n) == NULL) { TRACE_ERROR("BN_CTX_get/BN_bin2bn failed for modulus\n"); rc = CKR_FUNCTION_FAILED; goto done; } /* Get public exponent a BIGNUM */ rc = template_attribute_get_non_empty(key_obj->template, CKA_PUBLIC_EXPONENT, &pub_exp); if (rc != CKR_OK) { TRACE_ERROR("Failed to get CKA_PUBLIC_EXPONENT\n"); goto done; } e = BN_CTX_get(bn_ctx); if (e == NULL || BN_bin2bn(pub_exp->pValue, pub_exp->ulValueLen, e) == NULL) { TRACE_ERROR("BN_CTX_get/BN_bin2bn failed for publ-exponent\n"); rc = CKR_FUNCTION_FAILED; goto done; } BN_set_flags(n, BN_FLG_CONSTTIME); /* Create Montgomery context */ ex_data->blinding_mont_ctx = BN_MONT_CTX_new(); if (ex_data->blinding_mont_ctx == NULL) { TRACE_ERROR("BN_MONT_CTX_new failed\n"); rc = CKR_FUNCTION_FAILED; goto done; } if (BN_MONT_CTX_set(ex_data->blinding_mont_ctx, n, bn_ctx) != 1) { TRACE_ERROR("BN_MONT_CTX_set failed\n"); rc = CKR_FUNCTION_FAILED; BN_MONT_CTX_free(ex_data->blinding_mont_ctx); ex_data->blinding_mont_ctx = NULL; goto done; } #ifndef HAVE_ALT_FIX_FOR_CVE2022_4304 rc = ica_calc_blinding_mont_ctx_n0(tokdata, ex_data, bn_ctx, modulus); if (rc != CKR_OK) { TRACE_ERROR("ica_calc_blinding_mont_ctx_n0 failed\n"); goto done; } #endif /* * BN_BLINDING_create_param() calls the ica_blinding_bn_mod_exp() * callback which needs to know the ICA token private data. */ ica_blinding_private_data = ica_data; ex_data->blinding = BN_BLINDING_create_param(NULL, e, n, bn_ctx, ica_blinding_bn_mod_exp, ex_data->blinding_mont_ctx); if (ex_data->blinding == NULL) { TRACE_ERROR("BN_BLINDING_create_param failed\n"); rc = CKR_FUNCTION_FAILED; BN_MONT_CTX_free(ex_data->blinding_mont_ctx); ex_data->blinding_mont_ctx = NULL; goto done; } done: return rc; } static CK_RV ica_blinding_convert(STDLL_TokData_t *tokdata, ica_ex_data_t *ex_data, BN_CTX *bn_ctx, CK_BYTE *in_data, CK_BYTE *out_data, CK_ULONG data_len, BIGNUM **unblind) { ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; BIGNUM *bn_data = NULL; int ret; bn_data = BN_CTX_get(bn_ctx); if (bn_data == NULL || BN_bin2bn(in_data, data_len, bn_data) == NULL) { TRACE_ERROR("BN_CTX_get/BN_bin2bn failed\n"); return CKR_FUNCTION_FAILED; } *unblind = BN_CTX_get(bn_ctx); if (*unblind == NULL) { TRACE_ERROR("BN_CTX_get failed for unblind factor\n"); return CKR_FUNCTION_FAILED; } BN_set_flags(*unblind, BN_FLG_CONSTTIME); if (!BN_BLINDING_lock(ex_data->blinding)) { TRACE_ERROR("BN_BLINDING_lock failed\n"); return CKR_FUNCTION_FAILED; } /* BN_BLINDING_convert_ex() calls BN_BLINDING_update() which may call * BN_BLINDING_create_param() to generate a new blinding factor. This * calls the ica_blinding_bn_mod_exp() callback which needs to know * the ICA token private data. */ ica_blinding_private_data = ica_data; ret = BN_BLINDING_convert_ex(bn_data, *unblind, ex_data->blinding, bn_ctx); BN_BLINDING_unlock(ex_data->blinding); if(ret != 1) { TRACE_ERROR("BN_BLINDING_convert_ex failed\n"); return CKR_FUNCTION_FAILED; } if (BN_bn2binpad(bn_data, out_data, data_len) != (int)data_len) { TRACE_ERROR("BN_bn2binpad failed\n"); return CKR_FUNCTION_FAILED; } return CKR_OK; } static CK_RV ica_blinding_invert(STDLL_TokData_t *tokdata, OBJECT *key_obj, ica_ex_data_t *ex_data, BN_CTX *bn_ctx, CK_BYTE *in_data, CK_BYTE *out_data, CK_ULONG data_len, BIGNUM *unblind) { #ifdef HAVE_ALT_FIX_FOR_CVE2022_4304 int rc; BIGNUM *bn_data = NULL; UNUSED(tokdata); UNUSED(key_obj); bn_data = BN_CTX_get(bn_ctx); if (bn_data == NULL || BN_bin2bn(in_data, data_len, bn_data) == NULL) { TRACE_ERROR("BN_CTX_get/BN_bin2bn failed\n"); return CKR_FUNCTION_FAILED; } BN_set_flags(bn_data, BN_FLG_CONSTTIME); /* * BN_BLINDING_invert_ex is constant-time since OpenSSL commit * https://github.com/openssl/openssl/commit/f06ef1657a3d4322153b26231a7afa3d55724e52 * "Alternative fix for CVE-2022-4304". Care must be taken that bn_data * has flag BN_FLG_CONSTTIME set. * * Commits for OpenSSL releases: * - OpenSSL 1.1.1u: * https://github.com/openssl/openssl/commit/3f499b24f3bcd66db022074f7e8b4f6ee266a3ae * - OpenSSL 3.0.9: * https://github.com/openssl/openssl/commit/a00d757d9ca212994625d1a02c81cc5edd27e13b * - OpenSSl 3.1.1: * https://github.com/openssl/openssl/commit/550a16247e899363ef973aa08623f9b19bb636fb */ rc = BN_BLINDING_invert_ex(bn_data, unblind, ex_data->blinding, bn_ctx); if (rc != 1) { TRACE_ERROR("BN_BLINDING_invert_ex failed\n"); return CKR_FUNCTION_FAILED; } if (BN_bn2binpad(bn_data, out_data, data_len) != (int)data_len) { TRACE_ERROR("BN_bn2binpad failed\n"); return CKR_FUNCTION_FAILED; } return CKR_OK; #else CK_ATTRIBUTE *modulus = NULL; int rc; UNUSED(tokdata); UNUSED(bn_ctx); /* Get modulus */ rc = template_attribute_get_non_empty(key_obj->template, CKA_MODULUS, &modulus); if (rc != CKR_OK) { TRACE_ERROR("Failed to get CKA_MODULUS\n"); return rc; } if (modulus->ulValueLen != data_len) { TRACE_ERROR("Size of data is not size of modulus\n"); return CKR_FUNCTION_FAILED; } rc = ossl_bn_rsa_do_unblind(in_data, unblind, modulus->pValue, out_data, data_len, ex_data->blinding_mont_ctx, ex_data->blinding_mont_ctx_n0); if (rc <= 0) { TRACE_ERROR("ossl_bn_rsa_do_unblind failed\n"); return CKR_FUNCTION_FAILED; } return CKR_OK; #endif } // // static CK_RV ica_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; ica_ex_data_t *ex_data = NULL; CK_ATTRIBUTE *modulus = NULL; CK_ATTRIBUTE *pub_exp = NULL; CK_ATTRIBUTE *mod_bits = NULL; ica_rsa_key_mod_expo_t *publKey = NULL; CK_RV rc; rc = openssl_get_ex_data(key_obj, (void **)&ex_data, sizeof(ica_ex_data_t), ica_need_wr_lock_rsa_pubkey, ica_free_ex_data); if (rc != CKR_OK) return rc; if (ex_data->modexpoKey == NULL) { /* mech_sra.c:ckm_rsa_encrypt accepts only CKO_PUBLIC_KEY */ template_attribute_get_non_empty(key_obj->template, CKA_MODULUS, &modulus); template_attribute_get_non_empty(key_obj->template, CKA_MODULUS_BITS, &mod_bits); template_attribute_get_non_empty(key_obj->template, CKA_PUBLIC_EXPONENT, &pub_exp); ex_data->modexpoKey = rsa_convert_mod_expo_key(modulus, mod_bits, pub_exp); if (ex_data->modexpoKey == NULL) { TRACE_ERROR("rsa_convert_mod_expo_key failed\n"); rc = CKR_FUNCTION_FAILED; goto done; } } publKey = ex_data->modexpoKey; /* in_data must be in big endian format. 'in_data' size in bits must not * exceed the bit length of the key, and size in bytes must * 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 done; } rc = ica_rsa_mod_expo(ica_data->adapter_handle, in_data, publKey, out_data); switch (rc) { case 0: rc = CKR_OK; break; case EINVAL: TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); rc = CKR_ARGUMENTS_BAD; break; case ENODEV: TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); rc = CKR_FUNCTION_NOT_SUPPORTED; break; case EPERM: TRACE_ERROR("%s\n", ock_err(ERR_KEY_SIZE_RANGE)); rc = CKR_KEY_SIZE_RANGE; break; default: TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; break; } done: object_ex_data_unlock(key_obj); return rc; } // // static CK_RV ica_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; ica_ex_data_t *ex_data = NULL; 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; BN_CTX *bn_ctx = NULL; BIGNUM *unblind = NULL; unsigned char *buff = NULL; CK_RV rc; rc = openssl_get_ex_data(key_obj, (void **)&ex_data, sizeof(ica_ex_data_t), ica_need_wr_lock_rsa_privkey, ica_free_ex_data); if (rc != CKR_OK) return rc; if (ex_data->modexpoKey == NULL && ex_data->crtKey == NULL) { /* mech_rsa.c:ckm_rsa_decrypt accepts only CKO_PRIVATE_KEY, * but Private Key can have 2 representations (see PKCS#1): * - Modulus + private exponent * - p, q, dp, dq and qInv (CRT format) * The former should use ica_rsa_key_mod_expo_t and the latter * ica_rsa_key_crt_t. Detect what representation this * key_obj has and use the proper convert function */ template_attribute_get_non_empty(key_obj->template, CKA_MODULUS, &modulus); template_attribute_get_non_empty(key_obj->template, CKA_PRIVATE_EXPONENT, &priv_exp); template_attribute_get_non_empty(key_obj->template, CKA_PRIME_1, &prime1); template_attribute_get_non_empty(key_obj->template, CKA_PRIME_2, &prime2); template_attribute_get_non_empty(key_obj->template, CKA_EXPONENT_1, &exp1); template_attribute_get_non_empty(key_obj->template, CKA_EXPONENT_2, &exp2); template_attribute_get_non_empty(key_obj->template, CKA_COEFFICIENT, &coeff); /* Need to check for CRT Key format *BEFORE* check for mod_expo key, * that's because opencryptoki *HAS* a CKA_PRIVATE_EXPONENT attribute * even in CRT keys (but with zero length) */ if (modulus && prime1 && prime2 && exp1 && exp2 && coeff) { /* ica_rsa_key_crt_t representation */ ex_data->crtKey = rsa_convert_crt_key(modulus, prime1, prime2, exp1, exp2, coeff); if (ex_data->crtKey == NULL) { TRACE_ERROR("rsa_convert_crt_key failed\n"); rc = CKR_FUNCTION_FAILED; goto done; } /* same check as above */ if (ex_data->crtKey->key_length != in_data_len) { TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); rc = CKR_ENCRYPTED_DATA_LEN_RANGE; goto done; } } else if (modulus && priv_exp) { /* ica_rsa_key_mod_expo_t representation */ ex_data->modexpoKey = rsa_convert_mod_expo_key(modulus, NULL, priv_exp); if (ex_data->modexpoKey == NULL) { TRACE_ERROR("rsa_convert_mod_expo_key failed\n"); rc = CKR_FUNCTION_FAILED; goto done; } /* in_data must be in big endian format. Size in bits must not * exceed the bit length of the key, and size in bytes must * be the same */ if (ex_data->modexpoKey->key_length != in_data_len) { TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); rc = CKR_ENCRYPTED_DATA_LEN_RANGE; goto done; } } else { /* should never happen */ TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } } crtKey = ex_data->crtKey; modexpoKey = ex_data->modexpoKey; bn_ctx = BN_CTX_new(); if (bn_ctx == NULL) { TRACE_ERROR("BN_CTX_new failed\n"); rc = CKR_FUNCTION_FAILED; goto done; } if (ex_data->blinding == NULL || ex_data->blinding_mont_ctx == NULL) { rc = ica_blinding_setup(tokdata, key_obj, ex_data, bn_ctx); if (rc != CKR_OK) { TRACE_ERROR("ica_blinding_setup failed\n"); rc = CKR_FUNCTION_FAILED; goto done; } } buff = malloc(in_data_len * 2); if (buff == NULL) { TRACE_ERROR("Failed to allocate blinding buffer\n"); rc = CKR_HOST_MEMORY; goto done; } rc = ica_blinding_convert(tokdata, ex_data, bn_ctx, in_data, buff, in_data_len, &unblind); if (rc != CKR_OK) { TRACE_ERROR("ica_blinding_convert\n"); goto done; } if (crtKey != NULL) { rc = ica_rsa_crt(ica_data->adapter_handle, buff, crtKey, buff + in_data_len); } else { rc = ica_rsa_mod_expo(ica_data->adapter_handle, buff, modexpoKey, buff + in_data_len); } switch (rc) { case 0: rc = CKR_OK; break; case EINVAL: TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); rc = CKR_ARGUMENTS_BAD; break; case ENODEV: TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); rc = CKR_FUNCTION_NOT_SUPPORTED; break; case EPERM: TRACE_ERROR("%s\n", ock_err(ERR_KEY_SIZE_RANGE)); rc = CKR_KEY_SIZE_RANGE; break; default: TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; break; } if (rc != CKR_OK) goto done; rc = ica_blinding_invert(tokdata, key_obj, ex_data, bn_ctx, buff + in_data_len, out_data, in_data_len, unblind); if (rc != CKR_OK) { TRACE_ERROR("ica_blinding_invert\n"); goto done; } done: object_ex_data_unlock(key_obj); if (bn_ctx != NULL) BN_CTX_free(bn_ctx); if (buff != NULL) { OPENSSL_cleanse(buff, in_data_len * 2); free(buff); } return rc; } 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_RV rc = CKR_FUNCTION_FAILED; if (ica_data->ica_rsa_endecrypt_available) { rc = ica_specific_rsa_encrypt(tokdata, in_data, in_data_len, out_data, key_obj); if (rc == CKR_FUNCTION_NOT_SUPPORTED) ica_data->ica_rsa_endecrypt_available = FALSE; } if (!ica_data->ica_rsa_endecrypt_available) rc = openssl_specific_rsa_encrypt(tokdata, in_data, in_data_len, out_data, key_obj); 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_RV rc = CKR_FUNCTION_FAILED; if (ica_data->ica_rsa_endecrypt_available) { rc = ica_specific_rsa_decrypt(tokdata, in_data, in_data_len, out_data, key_obj); if (rc == CKR_FUNCTION_NOT_SUPPORTED) ica_data->ica_rsa_endecrypt_available = FALSE; } if (!ica_data->ica_rsa_endecrypt_available) rc = openssl_specific_rsa_decrypt(tokdata, in_data, in_data_len, out_data, key_obj); return rc; } static CK_BBOOL save_data_in_context(CK_BYTE *in_data, CK_ULONG in_data_len, CK_ULONG tag_data_len, AES_GCM_CONTEXT *context, CK_BYTE encrypt, CK_ULONG total, CK_ULONG *remain) { 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; return CK_TRUE; } } 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; return CK_TRUE; } } return CK_FALSE; } #ifdef AES_GCM_KMA static void new_gcm_specific_aes_gcm_free(STDLL_TokData_t *tokdata, struct _SESSION *sess, CK_BYTE *context, CK_ULONG context_len) { AES_GCM_CONTEXT *ctx = (AES_GCM_CONTEXT *)context; UNUSED(tokdata); UNUSED(sess); UNUSED(context_len); if (ctx == NULL) return; if ((kma_ctx *)ctx->ulClen != NULL) ica_aes_gcm_kma_ctx_free((kma_ctx *)ctx->ulClen); free(context); } CK_RV new_gcm_specific_aes_gcm_init(STDLL_TokData_t *tokdata, SESSION *sess, ENCR_DECR_CONTEXT *ctx, CK_MECHANISM *mech, CK_BYTE *key_value, CK_ULONG key_len, CK_BYTE encrypt) { CK_GCM_PARAMS *aes_gcm_param = NULL; AES_GCM_CONTEXT *context = NULL; kma_ctx *gcm_ctx; CK_RV rc; UNUSED(tokdata); UNUSED(sess); /* allocate libica gcm context for KMA instruction */ gcm_ctx = ica_aes_gcm_kma_ctx_new(); if (!gcm_ctx) return CKR_HOST_MEMORY; /* initialize gcm context */ aes_gcm_param = (CK_GCM_PARAMS *)mech->pParameter; rc = ica_aes_gcm_kma_init(encrypt, aes_gcm_param->pIv, aes_gcm_param->ulIvLen, key_value, key_len, gcm_ctx); if (rc != 0) { TRACE_ERROR("ica_aes_gcm_kma_init failed, rc=%ld.\n",rc); ica_aes_gcm_kma_ctx_free(gcm_ctx); rc = CKR_FUNCTION_FAILED; goto done; } /* set new ica gcm context in ENCR_DECR_CONTEXT, mis-use ulClen field */ context = (AES_GCM_CONTEXT *)ctx->context; context->ulClen = (CK_ULONG)gcm_ctx; ctx->state_unsaveable = CK_TRUE; ctx->context_free_func = new_gcm_specific_aes_gcm_free; done: return rc; } CK_RV new_gcm_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) { AES_GCM_CONTEXT *context = NULL; CK_GCM_PARAMS *aes_gcm_param = NULL; kma_ctx *gcm_ctx = NULL; CK_BYTE *tag_data, *auth_data; CK_ULONG auth_data_len, tag_data_len; CK_RV rc; UNUSED(tokdata); UNUSED(sess); context = (AES_GCM_CONTEXT *)ctx->context; gcm_ctx = (kma_ctx *)context->ulClen; 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 = out_data + in_data_len; tag_data_len = (aes_gcm_param->ulTagBits + 7) / 8; /* perform one-part encryption/decryption */ rc = ica_aes_gcm_kma_update(in_data, out_data, encrypt ? in_data_len : in_data_len - tag_data_len, auth_data, auth_data_len, 1, 1, gcm_ctx); if (rc != 0) { TRACE_ERROR("ica_aes_gcm_kma_update failed, rc=%ld.\n", rc); *out_data_len = 0; rc = CKR_FUNCTION_FAILED; goto done; } if (encrypt) { /* encrypt: provide authentication tag and append it to out_data */ rc = ica_aes_gcm_kma_get_tag(tag_data, tag_data_len, gcm_ctx); if (rc == 0) { *out_data_len = in_data_len + tag_data_len; } else { TRACE_ERROR("ica_aes_gcm_kma_get_tag failed, rc=%ld.\n", rc); *out_data_len = 0; rc = CKR_FUNCTION_FAILED; goto done; } } else { /* decrypt: verify tag, which is appended to encrypted data */ tag_data = in_data + in_data_len - tag_data_len; rc = ica_aes_gcm_kma_verify_tag(tag_data, tag_data_len, gcm_ctx); if (rc == 0) { *out_data_len = in_data_len - tag_data_len; } else { TRACE_ERROR("ica_aes_gcm_kma_verify_tag failed, rc=%ld.\n", rc); *out_data_len = 0; rc = CKR_FUNCTION_FAILED; goto done; } } done: ica_aes_gcm_kma_ctx_free(gcm_ctx); context->ulClen = (CK_ULONG)0; return rc; } CK_RV new_gcm_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) { AES_GCM_CONTEXT *context = NULL; CK_GCM_PARAMS *aes_gcm_param = NULL; kma_ctx *gcm_ctx = NULL; CK_BYTE *auth_data, *buffer = NULL; CK_ULONG total, tag_data_len, remain, auth_data_len, out_len; CK_RV rc; UNUSED(tokdata); UNUSED(sess); context = (AES_GCM_CONTEXT *)ctx->context; gcm_ctx = (kma_ctx *)context->ulClen; 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; total = context->len + in_data_len; /* if there isn't enough data to make a block, just save it */ if (save_data_in_context(in_data, in_data_len, tag_data_len, context, encrypt, total, &remain)) { *out_data_len = 0; return CKR_OK; } /* At least we have 1 block */ 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("plaintext length (%ld bytes).\n", in_data_len); rc = ica_aes_gcm_kma_update(buffer, out_data, out_len, auth_data, auth_data_len, 1, 0, gcm_ctx); /* 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 decryption 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); memmove(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_kma_update(buffer, out_data, out_len, auth_data, auth_data_len, 1, 0, gcm_ctx); } if (rc != 0) { TRACE_ERROR("ica_aes_gcm_kma_update failed, rc=%ld.\n", rc); rc = CKR_FUNCTION_FAILED; goto done; } *out_data_len = out_len; done: if (buffer) free(buffer); return rc; } CK_RV new_gcm_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; AES_GCM_CONTEXT *context = NULL; CK_GCM_PARAMS *aes_gcm_param = NULL; kma_ctx *gcm_ctx = NULL; CK_BYTE *final_tag_data; CK_ULONG tag_data_len; CK_BYTE tmp_tag[16]; UNUSED(tokdata); UNUSED(sess); context = (AES_GCM_CONTEXT *)ctx->context; gcm_ctx = (kma_ctx *)context->ulClen; aes_gcm_param = (CK_GCM_PARAMS *)ctx->mech.pParameter; tag_data_len = (aes_gcm_param->ulTagBits + 7) / 8; if (encrypt) { if (context->len != 0) { /* Perform final update with rest of data to calculate final tag */ rc = ica_aes_gcm_kma_update(context->data, out_data, context->len, NULL, 0, 1,1, gcm_ctx); if (rc != 0) { TRACE_ERROR("ica_aes_gcm_kma_update failed, rc=%ld\n",rc); rc = CKR_FUNCTION_FAILED; goto done; } *out_data_len = context->len + tag_data_len; } else { /* Perform final update without data to calculate final tag */ rc = ica_aes_gcm_kma_update(NULL, NULL, 0, NULL, 0, 1, 1, gcm_ctx); if (rc != 0) { TRACE_ERROR("ica_aes_gcm_kma_update failed, rc=%ld\n",rc); rc = CKR_FUNCTION_FAILED; goto done; } *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_kma_get_tag(tmp_tag, tag_data_len, gcm_ctx); if (rc != 0) { TRACE_ERROR("ica_aes_gcm_kma_get_tag failed, rc=%ld.\n", rc); rc = CKR_FUNCTION_FAILED; goto done; } memcpy(out_data + context->len, tmp_tag, tag_data_len); } else { /* decrypt */ if (context->len > tag_data_len) { /* Perform final update with rest of data to calculate final tag */ rc = ica_aes_gcm_kma_update(context->data, out_data, context->len - tag_data_len, NULL, 0, 1, 1, gcm_ctx); if (rc != 0) { TRACE_ERROR("ica_aes_gcm_kma_update failed, rc=%ld.\n",rc); rc = CKR_FUNCTION_FAILED; goto done; } *out_data_len = context->len - tag_data_len; } else if (context->len == tag_data_len) { /* remaining data are tag data */ *out_data_len = 0; /* Perform final update without data to calculate final tag */ rc = ica_aes_gcm_kma_update(NULL, NULL, 0, NULL, 0, 1, 1, gcm_ctx); if (rc != 0) { TRACE_ERROR("ica_aes_gcm_kma_update failed, rc=%ld.\n",rc); rc = CKR_FUNCTION_FAILED; goto done; } } 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_kma_verify_tag(final_tag_data, tag_data_len, gcm_ctx); if (rc != 0) { TRACE_ERROR("ica_aes_gcm_kma_verify_tag failed, rc=%ld.\n", rc); rc = CKR_FUNCTION_FAILED; } } done: ica_aes_gcm_kma_ctx_free(gcm_ctx); context->ulClen = (CK_ULONG)0; return rc; } #endif 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) { return openssl_specific_rsa_pkcs_encrypt(tokdata, in_data, in_data_len, out_data, out_data_len, key_obj, os_specific_rsa_encrypt); } 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) { return openssl_specific_rsa_pkcs_decrypt(tokdata, in_data, in_data_len, out_data, out_data_len, key_obj, os_specific_rsa_decrypt); } 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) { return openssl_specific_rsa_pkcs_sign(tokdata, sess, in_data, in_data_len, out_data, out_data_len, key_obj, os_specific_rsa_decrypt); } 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) { return openssl_specific_rsa_pkcs_verify(tokdata, sess, in_data, in_data_len, signature, sig_len, key_obj, os_specific_rsa_encrypt); } 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) { return openssl_specific_rsa_pkcs_verify_recover(tokdata, signature, sig_len, out_data, out_data_len, key_obj, os_specific_rsa_encrypt); } 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) { return openssl_specific_rsa_pss_sign(tokdata, sess, ctx, in_data, in_data_len, sig, sig_len, os_specific_rsa_decrypt); } 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) { return openssl_specific_rsa_pss_verify(tokdata, sess, ctx, in_data, in_data_len, signature, sig_len, os_specific_rsa_encrypt); } 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) { return openssl_specific_rsa_x509_encrypt(tokdata, in_data, in_data_len, out_data, out_data_len, key_obj, os_specific_rsa_encrypt); } 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) { return openssl_specific_rsa_x509_decrypt(tokdata, in_data, in_data_len, out_data, out_data_len, key_obj, os_specific_rsa_decrypt); } 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) { return openssl_specific_rsa_x509_sign(tokdata, in_data, in_data_len, out_data, out_data_len, key_obj, os_specific_rsa_decrypt); } 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) { return openssl_specific_rsa_x509_verify(tokdata, in_data, in_data_len, signature, sig_len, key_obj, os_specific_rsa_encrypt); } 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) { return openssl_specific_rsa_x509_verify_recover(tokdata, signature, sig_len, out_data, out_data_len, key_obj, os_specific_rsa_encrypt); } 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) { return openssl_specific_rsa_oaep_encrypt(tokdata, ctx, in_data, in_data_len, out_data, out_data_len, hash, hlen, os_specific_rsa_encrypt); } 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) { return openssl_specific_rsa_oaep_decrypt(tokdata, ctx, in_data, in_data_len, out_data, out_data_len, hash, hlen, os_specific_rsa_decrypt); } CK_RV token_specific_aes_key_gen(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_BYTE **key, CK_ULONG *len, CK_ULONG keysize, CK_BBOOL *is_opaque) { UNUSED(tmpl); *key = malloc(keysize); if (*key == NULL) return CKR_HOST_MEMORY; *len = keysize; *is_opaque = FALSE; return rng_generate(tokdata, *key, keysize); } CK_RV token_specific_aes_xts_key_gen(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_BYTE **key, CK_ULONG *len, CK_ULONG keysize, CK_BBOOL *is_opaque) { CK_RV rc; UNUSED(tmpl); *key = malloc(keysize); if (*key == NULL) return CKR_HOST_MEMORY; *len = keysize; *is_opaque = FALSE; do { rc = rng_generate(tokdata, *key, keysize); if (rc != CKR_OK) return rc; } while (memcmp(*key, (*key) + keysize / 2, keysize / 2) == 0); return CKR_OK; } CK_RV token_specific_aes_ecb(STDLL_TokData_t *tokdata, SESSION *sess, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, OBJECT *key, CK_BYTE encrypt) { ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; int rc = CKR_OK; CK_ATTRIBUTE *attr = NULL; UNUSED(sess); if (!ica_data->ica_aes_available) return openssl_specific_aes_ecb(tokdata, in_data, in_data_len, out_data, out_data_len, key, encrypt); /* * 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_get_non_empty(key->template, CKA_VALUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); return rc; } 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, SESSION *sess, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, OBJECT *key, CK_BYTE *init_v, CK_BYTE encrypt) { ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; CK_RV rc; CK_ATTRIBUTE *attr = NULL; UNUSED(sess); if (!ica_data->ica_aes_available) return openssl_specific_aes_cbc(tokdata, in_data, in_data_len, out_data, out_data_len, key, init_v, encrypt); /* * 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_get_non_empty(key->template, CKA_VALUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); return rc; } 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) { ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; CK_RV rc; CK_ATTRIBUTE *attr = NULL; if (!ica_data->ica_aes_available) return openssl_specific_aes_ctr(tokdata, in_data, in_data_len, out_data, out_data_len, key, counterblock, counter_width, encrypt); /* * 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 rc = template_attribute_get_non_empty(key->template, CKA_VALUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); return rc; } 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) { ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; 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; if (!ica_data->ica_aes_available) return openssl_specific_aes_gcm_init(tokdata, sess, ctx, mech, key, encrypt); /* 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_get_non_empty(key_obj->template, CKA_VALUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); goto done; } #ifdef AES_GCM_KMA if (ica_data->ica_new_gcm_available) { rc = new_gcm_specific_aes_gcm_init(tokdata, sess, ctx, mech, attr->pValue, attr->ulValueLen, encrypt); goto done; } #endif /* 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) { ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; 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; if (!ica_data->ica_aes_available) return openssl_specific_aes_gcm(tokdata, sess, ctx, in_data, in_data_len, out_data, out_data_len, encrypt); #ifdef AES_GCM_KMA if (ica_data->ica_new_gcm_available) return new_gcm_specific_aes_gcm(tokdata, sess, ctx, in_data, in_data_len, out_data, out_data_len, encrypt); #endif /* * 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 */ rc = template_attribute_get_non_empty(key->template, CKA_VALUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); 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 = %ld.\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) { ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; 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; if (!ica_data->ica_aes_available) return openssl_specific_aes_gcm_update(tokdata, sess, ctx, in_data, in_data_len, out_data, out_data_len, encrypt); #ifdef AES_GCM_KMA if (ica_data->ica_new_gcm_available) return new_gcm_specific_aes_gcm_update(tokdata, sess, ctx, in_data, in_data_len, out_data, out_data_len, encrypt); #endif 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 (save_data_in_context(in_data, in_data_len, tag_data_len, context, encrypt, total, &remain)) { *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 */ rc = template_attribute_get_non_empty(key->template, CKA_VALUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); 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("plaintext 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); memmove(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 = %ld.\n", rc); rc = CKR_FUNCTION_FAILED; goto done; } (*out_data_len) = out_len; context->ulClen += out_len; /* AAD only processed in first update sequence, * 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) { ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; 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; if (!ica_data->ica_aes_available) return openssl_specific_aes_gcm_final(tokdata, sess, ctx, out_data, out_data_len, encrypt); #ifdef AES_GCM_KMA if (ica_data->ica_new_gcm_available) return new_gcm_specific_aes_gcm_final(tokdata, sess, ctx, out_data, out_data_len, encrypt); #endif /* 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; } rc = template_attribute_get_non_empty(key->template, CKA_VALUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); 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 = %ld.\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 = %ld.\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) { #if OPENSSL_VERSION_PREREQ(3, 0) || OPENSSL_VERSION_NUMBER >= 0x101010cfL ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; #endif CK_RV rc; CK_ATTRIBUTE *attr = NULL; #if OPENSSL_VERSION_PREREQ(3, 0) || OPENSSL_VERSION_NUMBER >= 0x101010cfL /* * AES-OFB/CFB currently only works with >= OpenSSl 3.0 or >= OpenSSL 1.1.1l, * due to a bug in OpenSSL <= 1.1.1k in s390x_aes_ofb_cipher() not updating * the IV in the context. */ if (!ica_data->ica_aes_available) return openssl_specific_aes_ofb(tokdata, in_data, in_data_len, out_data, key, init_v, direction); #else UNUSED(tokdata); #endif rc = template_attribute_get_non_empty(key->template, CKA_VALUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); return rc; } 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) { #if OPENSSL_VERSION_PREREQ(3, 0) || OPENSSL_VERSION_NUMBER >= 0x101010cfL ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; #endif CK_RV rc; CK_ATTRIBUTE *attr = NULL; #if OPENSSL_VERSION_PREREQ(3, 0) || OPENSSL_VERSION_NUMBER >= 0x101010cfL /* * AES-OFB/CFB currently only works with >= OpenSSl 3.0 or >= OpenSSL 1.1.1l, * due to a bug in OpenSSL <= 1.1.1k in s390x_aes_ofb_cipher() not updating * the IV in the context. */ if (!ica_data->ica_aes_available) return openssl_specific_aes_cfb(tokdata, in_data, in_data_len, out_data, key, init_v, lcfb, direction); #else UNUSED(tokdata); #endif rc = template_attribute_get_non_empty(key->template, CKA_VALUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); return rc; } 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) { ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; CK_RV rc; CK_ATTRIBUTE *attr = NULL; if (!ica_data->ica_aes_available) return openssl_specific_aes_mac(tokdata, message, message_len, key, mac); rc = template_attribute_get_non_empty(key->template, CKA_VALUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); return rc; } 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, SESSION *session, CK_BYTE *message, CK_ULONG message_len, OBJECT *key, CK_BYTE *mac, CK_BBOOL first, CK_BBOOL last, CK_VOID_PTR *ctx) { ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; CK_RV rc; CK_ATTRIBUTE *attr = NULL; UNUSED(session); if (!ica_data->ica_aes_available) return openssl_specific_aes_cmac(tokdata, message, message_len, key, mac, first, last, ctx); if (key == NULL) return CKR_ARGUMENTS_BAD; rc = template_attribute_get_non_empty(key->template, CKA_VALUE, &attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); return rc; } 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; } CK_RV token_specific_aes_xts(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 *tweak, CK_BOOL encrypt, CK_BBOOL initial, CK_BBOOL final, CK_BYTE* iv) { UNUSED(sess); ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; CK_ATTRIBUTE *key_attr; CK_RV rc; UNUSED(tokdata); if (!ica_data->ica_aes_available || p_ica_aes_xts_ex == NULL) return openssl_specific_aes_xts(tokdata, in_data, in_data_len, out_data, out_data_len, key_obj, tweak, encrypt, initial, final, iv); /* Full block size unless final call */ if (!final && (in_data_len % AES_BLOCK_SIZE) != 0) return CKR_DATA_LEN_RANGE; /* Final block must be at least one full block */ if (final && in_data_len < AES_BLOCK_SIZE) return CKR_DATA_LEN_RANGE; if (out_data == NULL) { *out_data_len = in_data_len; return CKR_OK; } if (*out_data_len < in_data_len) return CKR_BUFFER_TOO_SMALL; rc = template_attribute_get_non_empty(key_obj->template, CKA_VALUE, &key_attr); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); return rc; } rc = p_ica_aes_xts_ex(in_data, out_data, in_data_len, key_attr->pValue, (unsigned char *)key_attr->pValue + key_attr->ulValueLen / 2, key_attr->ulValueLen / 2, initial ? tweak : NULL, iv, encrypt ? ICA_ENCRYPT : ICA_DECRYPT); if (rc == 0) { *out_data_len = in_data_len; } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; } return rc; } typedef struct _REF_MECH_LIST_ELEMENT { CK_ULONG lica_idx; /* 0 means its a combined mechanism */ CK_MECHANISM_TYPE mech_type; CK_MECHANISM_INFO mech_info; } REF_MECH_LIST_ELEMENT; static const REF_MECH_LIST_ELEMENT ref_mech_list[] = { {RSA_KEY_GEN_ME, CKM_RSA_PKCS_KEY_PAIR_GEN, {512, 4096, CKF_GENERATE_KEY_PAIR} }, {P_RNG, CKM_DES_KEY_GEN, {8, 8, CKF_GENERATE}}, {P_RNG, CKM_DES3_KEY_GEN, {24, 24, CKF_GENERATE}}, {RSA_ME, CKM_RSA_PKCS, {512, 4096, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP | CKF_SIGN | CKF_VERIFY | CKF_SIGN_RECOVER | CKF_VERIFY_RECOVER | CKF_ENCAPSULATE | CKF_DECAPSULATE} }, {0, CKM_SHA1_RSA_PKCS, {512, 4096, CKF_SIGN | CKF_VERIFY}}, {0, CKM_SHA224_RSA_PKCS, {512, 4096, CKF_SIGN | CKF_VERIFY}}, {0, CKM_SHA256_RSA_PKCS, {512, 4096, CKF_SIGN | CKF_VERIFY}}, {0, CKM_SHA384_RSA_PKCS, {512, 4096, CKF_SIGN | CKF_VERIFY}}, {0, CKM_SHA512_RSA_PKCS, {512, 4096, CKF_SIGN | CKF_VERIFY}}, {0, CKM_SHA3_224_RSA_PKCS, {512, 4096, CKF_SIGN | CKF_VERIFY}}, {0, CKM_SHA3_256_RSA_PKCS, {512, 4096, CKF_SIGN | CKF_VERIFY}}, {0, CKM_SHA3_384_RSA_PKCS, {512, 4096, CKF_SIGN | CKF_VERIFY}}, {0, CKM_SHA3_512_RSA_PKCS, {512, 4096, CKF_SIGN | CKF_VERIFY}}, #if !(NOX509) {RSA_ME, 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 {0, CKM_RSA_PKCS_OAEP, {512, 4096, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP | CKF_ENCAPSULATE | CKF_DECAPSULATE} }, {0, CKM_RSA_PKCS_PSS, {512, 4096, CKF_SIGN | CKF_VERIFY}}, {0, CKM_SHA1_RSA_PKCS_PSS, {512, 4096, CKF_SIGN | CKF_VERIFY}}, {0, CKM_SHA224_RSA_PKCS_PSS, {512, 4096, CKF_SIGN | CKF_VERIFY}}, {0, CKM_SHA256_RSA_PKCS_PSS, {512, 4096, CKF_SIGN | CKF_VERIFY}}, {0, CKM_SHA384_RSA_PKCS_PSS, {512, 4096, CKF_SIGN | CKF_VERIFY}}, {0, CKM_SHA512_RSA_PKCS_PSS, {512, 4096, CKF_SIGN | CKF_VERIFY}}, {0, CKM_SHA3_224_RSA_PKCS_PSS, {512, 4096, CKF_SIGN | CKF_VERIFY}}, {0, CKM_SHA3_256_RSA_PKCS_PSS, {512, 4096, CKF_SIGN | CKF_VERIFY}}, {0, CKM_SHA3_384_RSA_PKCS_PSS, {512, 4096, CKF_SIGN | CKF_VERIFY}}, {0, CKM_SHA3_512_RSA_PKCS_PSS, {512, 4096, CKF_SIGN | CKF_VERIFY}}, {0, CKM_RSA_AES_KEY_WRAP, {512, 4096, CKF_WRAP | CKF_UNWRAP}}, {DES_ECB, CKM_DES_ECB, {8, 8, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP} }, {DES_CBC, CKM_DES_CBC, {8, 8, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP} }, {DES_CBC, CKM_DES_CBC_PAD, {8, 8, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP} }, {DES3_ECB, CKM_DES3_ECB, {24, 24, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP} }, {DES3_ECB, CKM_DES3_CBC, {24, 24, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP} }, {DES3_CBC, CKM_DES3_CBC_PAD, {24, 24, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP} }, {DES3_CMAC, CKM_DES3_MAC, {24, 24, CKF_SIGN | CKF_VERIFY}}, {DES3_CMAC, CKM_DES3_MAC_GENERAL, {24, 24, CKF_SIGN | CKF_VERIFY}}, {DES3_CMAC, CKM_DES3_CMAC, {16, 24, CKF_SIGN | CKF_VERIFY}}, {DES3_CMAC, CKM_DES3_CMAC_GENERAL, {16, 24, CKF_SIGN | CKF_VERIFY}}, {DES_CFB, CKM_DES_CFB8, {8, 8, CKF_ENCRYPT | CKF_DECRYPT}}, {DES_OFB, CKM_DES_OFB64, {8, 8, CKF_ENCRYPT | CKF_DECRYPT}}, {DES_CFB, CKM_DES_CFB64, {8, 8, CKF_ENCRYPT | CKF_DECRYPT}}, {SHA1, CKM_SHA_1, {0, 0, CKF_DIGEST}}, {SHA1, CKM_SHA_1_HMAC, {80, 2048, CKF_SIGN | CKF_VERIFY}}, {SHA1, CKM_SHA_1_HMAC_GENERAL, {80, 2048, CKF_SIGN | CKF_VERIFY}}, {SHA1, CKM_SHA1_KEY_DERIVATION, {8, 160, CKF_DERIVE}}, {SHA224, CKM_SHA224, {0, 0, CKF_DIGEST}}, {SHA224, CKM_SHA224_HMAC, {112, 2048, CKF_SIGN | CKF_VERIFY}}, {SHA224, CKM_SHA224_HMAC_GENERAL, {112, 2048, CKF_SIGN | CKF_VERIFY}}, {SHA224, CKM_SHA224_KEY_DERIVATION, {8, 224, CKF_DERIVE}}, {SHA256, CKM_SHA256, {0, 0, CKF_DIGEST}}, {SHA256, CKM_SHA256_HMAC, {128, 2048, CKF_SIGN | CKF_VERIFY}}, {SHA256, CKM_SHA256_HMAC_GENERAL, {128, 2048, CKF_SIGN | CKF_VERIFY}}, {SHA256, CKM_SHA256_KEY_DERIVATION, {8, 256, CKF_DERIVE}}, {SHA384, CKM_SHA384, {0, 0, CKF_DIGEST}}, {SHA384, CKM_SHA384_HMAC, {192, 2048, CKF_SIGN | CKF_VERIFY}}, {SHA384, CKM_SHA384_HMAC_GENERAL, {192, 2048, CKF_SIGN | CKF_VERIFY}}, {SHA384, CKM_SHA384_KEY_DERIVATION, {8, 384, CKF_DERIVE}}, {SHA512, CKM_SHA512, {0, 0, CKF_DIGEST}}, {SHA512, CKM_SHA512_HMAC, {256, 2048, CKF_SIGN | CKF_VERIFY}}, {SHA512, CKM_SHA512_HMAC_GENERAL, {256, 2048, CKF_SIGN | CKF_VERIFY}}, {SHA512, CKM_SHA512_KEY_DERIVATION, {8, 512, CKF_DERIVE}}, #ifdef SHA512_224 {SHA512_224, CKM_SHA512_224, {0, 0, CKF_HW | CKF_DIGEST}}, {SHA512_224, CKM_SHA512_224_HMAC, {112, 2048, CKF_SIGN | CKF_VERIFY}}, {SHA512_224, CKM_SHA512_224_HMAC_GENERAL, {112, 2048, CKF_SIGN | CKF_VERIFY}}, {SHA512_224, CKM_SHA512_224_KEY_DERIVATION, {8, 224, CKF_DERIVE}}, #endif #ifdef SHA512_256 {SHA512_256, CKM_SHA512_256, {0, 0, CKF_HW | CKF_DIGEST}}, {SHA512_256, CKM_SHA512_256_HMAC, {128, 2048, CKF_SIGN | CKF_VERIFY}}, {SHA512_256, CKM_SHA512_256_HMAC_GENERAL, {128, 2048, CKF_SIGN | CKF_VERIFY}}, {SHA512_256, CKM_SHA512_256_KEY_DERIVATION, {8, 256, CKF_DERIVE}}, #endif #ifdef SHA3_224 {SHA3_224, CKM_SHA3_224, {0, 0, CKF_HW | CKF_DIGEST}}, {SHA3_224, CKM_SHA3_224_HMAC, {112, 2048, CKF_SIGN | CKF_VERIFY}}, {SHA3_224, CKM_SHA3_224_HMAC_GENERAL, {112, 2048, CKF_SIGN | CKF_VERIFY}}, {SHA3_224, CKM_SHA3_224_KEY_DERIVATION, {8, 224, CKF_DERIVE}}, {SHA3_224, CKM_IBM_SHA3_224, {0, 0, CKF_HW | CKF_DIGEST}}, {SHA3_224, CKM_IBM_SHA3_224_HMAC, {112, 2048, CKF_SIGN | CKF_VERIFY}}, #endif #ifdef SHA3_256 {SHA3_256, CKM_SHA3_256, {0, 0, CKF_HW | CKF_DIGEST}}, {SHA3_256, CKM_SHA3_256_HMAC, {128, 2048, CKF_SIGN | CKF_VERIFY}}, {SHA3_256, CKM_SHA3_256_HMAC_GENERAL, {128, 2048, CKF_SIGN | CKF_VERIFY}}, {SHA3_256, CKM_SHA3_256_KEY_DERIVATION, {8, 256, CKF_DERIVE}}, {SHA3_256, CKM_IBM_SHA3_256, {0, 0, CKF_HW | CKF_DIGEST}}, {SHA3_256, CKM_IBM_SHA3_256_HMAC, {128, 2048, CKF_SIGN | CKF_VERIFY}}, #endif #ifdef SHA3_384 {SHA3_384, CKM_SHA3_384, {0, 0, CKF_HW | CKF_DIGEST}}, {SHA3_384, CKM_SHA3_384_HMAC, {192, 2048, CKF_SIGN | CKF_VERIFY}}, {SHA3_384, CKM_SHA3_384_HMAC_GENERAL, {192, 2048, CKF_SIGN | CKF_VERIFY}}, {SHA3_384, CKM_SHA3_384_KEY_DERIVATION, {8, 384, CKF_DERIVE}}, {SHA3_384, CKM_IBM_SHA3_384, {0, 0, CKF_HW | CKF_DIGEST}}, {SHA3_384, CKM_IBM_SHA3_384_HMAC, {192, 2048, CKF_SIGN | CKF_VERIFY}}, #endif #ifdef SHA3_512 {SHA3_512, CKM_SHA3_512, {0, 0, CKF_HW | CKF_DIGEST}}, {SHA3_512, CKM_SHA3_512_HMAC, {256, 2048, CKF_SIGN | CKF_VERIFY}}, {SHA3_512, CKM_SHA3_512_HMAC_GENERAL, {256, 2048, CKF_SIGN | CKF_VERIFY}}, {SHA3_512, CKM_SHA3_512_KEY_DERIVATION, {8, 512, CKF_DERIVE}}, {SHA3_512, CKM_IBM_SHA3_512, {0, 0, CKF_HW | CKF_DIGEST}}, {SHA3_512, CKM_IBM_SHA3_512_HMAC, {256, 2048, CKF_SIGN | CKF_VERIFY}}, #endif #if !(NOMD5) {53, CKM_MD5, {0, 0, CKF_DIGEST}}, {54, CKM_MD5_HMAC, {8, 2048, CKF_SIGN | CKF_VERIFY}}, {55, CKM_MD5_HMAC_GENERAL, {8, 2048, CKF_SIGN | CKF_VERIFY}}, #endif #ifdef SHAKE128 {SHAKE128, CKM_SHAKE_128_KEY_DERIVATION, {8, 2048, CKF_DERIVE}}, #endif #ifdef SHAKE256 {SHAKE256, CKM_SHAKE_256_KEY_DERIVATION, {8, 2048, CKF_DERIVE}}, #endif {P_RNG, CKM_AES_KEY_GEN, {16, 32, CKF_GENERATE}}, {P_RNG, CKM_AES_XTS_KEY_GEN, {32, 64, CKF_GENERATE}}, {AES_ECB, CKM_AES_ECB, {16, 32, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP} }, {AES_CBC, CKM_AES_CBC, {16, 32, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP} }, {AES_CBC, CKM_AES_CBC_PAD, {16, 32, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP} }, {AES_OFB, CKM_AES_OFB, {16, 32, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP} }, {AES_CFB, CKM_AES_CFB8, {16, 32, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP} }, {AES_CFB, CKM_AES_CFB64, {16, 32, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP} }, {AES_CFB, CKM_AES_CFB128, {16, 32, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP} }, {AES_CTR, CKM_AES_CTR, {16, 32, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP} }, {AES_GCM, CKM_AES_GCM, {16, 32, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}}, {AES_CMAC, CKM_AES_MAC, {16, 32, CKF_SIGN | CKF_VERIFY}}, {AES_CMAC, CKM_AES_MAC_GENERAL, {16, 32, CKF_SIGN | CKF_VERIFY}}, {AES_CMAC, CKM_AES_CMAC, {16, 32, CKF_SIGN | CKF_VERIFY}}, {AES_CMAC, CKM_AES_CMAC_GENERAL, {16, 32, CKF_SIGN | CKF_VERIFY}}, {AES_XTS, CKM_AES_XTS, {32, 64, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP} }, {AES_ECB, CKM_AES_KEY_WRAP, {32, 64, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}}, {AES_ECB, CKM_AES_KEY_WRAP_PAD, {32, 64, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}}, {AES_ECB, CKM_AES_KEY_WRAP_KWP, {32, 64, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}}, {AES_ECB, CKM_AES_KEY_WRAP_PKCS7, {32, 64, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}}, {P_RNG, CKM_GENERIC_SECRET_KEY_GEN, {80, 2048, CKF_GENERATE}}, {P_RNG, CKM_SHA_1_KEY_GEN, {80, 2048, CKF_GENERATE}}, {P_RNG, CKM_SHA224_KEY_GEN, {80, 2048, CKF_GENERATE}}, {P_RNG, CKM_SHA256_KEY_GEN, {80, 2048, CKF_GENERATE}}, {P_RNG, CKM_SHA384_KEY_GEN, {80, 2048, CKF_GENERATE}}, {P_RNG, CKM_SHA512_KEY_GEN, {80, 2048, CKF_GENERATE}}, {P_RNG, CKM_SHA512_224_KEY_GEN, {80, 2048, CKF_GENERATE}}, {P_RNG, CKM_SHA512_256_KEY_GEN, {80, 2048, CKF_GENERATE}}, {P_RNG, CKM_SHA3_224_KEY_GEN, {80, 2048, CKF_GENERATE}}, {P_RNG, CKM_SHA3_256_KEY_GEN, {80, 2048, CKF_GENERATE}}, {P_RNG, CKM_SHA3_384_KEY_GEN, {80, 2048, CKF_GENERATE}}, {P_RNG, CKM_SHA3_512_KEY_GEN, {80, 2048, CKF_GENERATE}}, #ifndef NO_EC {EC_DH, CKM_ECDH1_DERIVE, {160, 521, CKF_DERIVE | CKF_EC_OID | CKF_EC_F_P | CKF_EC_UNCOMPRESS | CKF_EC_COMPRESS | CKF_ENCAPSULATE | CKF_DECAPSULATE} }, {EC_DSA_SIGN, CKM_ECDSA, {160, 521, CKF_SIGN | CKF_VERIFY | CKF_EC_OID | CKF_EC_F_P | CKF_EC_UNCOMPRESS | CKF_EC_COMPRESS} }, {0, CKM_ECDSA_SHA1, {160, 521, CKF_SIGN | CKF_VERIFY | CKF_EC_OID | CKF_EC_F_P | CKF_EC_UNCOMPRESS | CKF_EC_COMPRESS} }, {0, CKM_ECDSA_SHA224, {160, 521, CKF_SIGN | CKF_VERIFY | CKF_EC_OID | CKF_EC_F_P | CKF_EC_UNCOMPRESS | CKF_EC_COMPRESS} }, {0, CKM_ECDSA_SHA256, {160, 521, CKF_SIGN | CKF_VERIFY | CKF_EC_OID | CKF_EC_F_P | CKF_EC_UNCOMPRESS | CKF_EC_COMPRESS} }, {0, CKM_ECDSA_SHA384, {160, 521, CKF_SIGN | CKF_VERIFY | CKF_EC_OID | CKF_EC_F_P | CKF_EC_UNCOMPRESS | CKF_EC_COMPRESS} }, {0, CKM_ECDSA_SHA512, {160, 521, CKF_SIGN | CKF_VERIFY | CKF_EC_OID | CKF_EC_F_P | CKF_EC_UNCOMPRESS | CKF_EC_COMPRESS} }, {0, CKM_ECDSA_SHA3_224, {160, 521, CKF_SIGN | CKF_VERIFY | CKF_EC_OID | CKF_EC_F_P | CKF_EC_UNCOMPRESS | CKF_EC_COMPRESS} }, {0, CKM_ECDSA_SHA3_256, {160, 521, CKF_SIGN | CKF_VERIFY | CKF_EC_OID | CKF_EC_F_P | CKF_EC_UNCOMPRESS | CKF_EC_COMPRESS} }, {0, CKM_ECDSA_SHA3_384, {160, 521, CKF_SIGN | CKF_VERIFY | CKF_EC_OID | CKF_EC_F_P | CKF_EC_UNCOMPRESS | CKF_EC_COMPRESS} }, {0, CKM_ECDSA_SHA3_512, {160, 521, CKF_SIGN | CKF_VERIFY | CKF_EC_OID | CKF_EC_F_P | CKF_EC_UNCOMPRESS | CKF_EC_COMPRESS} }, {EC_KGEN, CKM_EC_KEY_PAIR_GEN, {160, 521, CKF_GENERATE_KEY_PAIR | CKF_EC_OID | CKF_EC_F_P | CKF_EC_UNCOMPRESS | CKF_EC_COMPRESS} }, {EC_DH, CKM_ECDH_AES_KEY_WRAP, {160, 521, CKF_WRAP | CKF_UNWRAP | CKF_EC_OID | CKF_EC_F_P | CKF_EC_UNCOMPRESS | CKF_EC_COMPRESS}}, #if OPENSSL_VERSION_PREREQ(3, 0) #if defined ED25519_KEYGEN && ED448_KEYGEN {ED25519_KEYGEN, CKM_EC_EDWARDS_KEY_PAIR_GEN, {255, 448, CKF_GENERATE_KEY_PAIR | CKF_EC_OID | CKF_EC_F_P | CKF_EC_COMPRESS} }, #endif #if defined X25519_KEYGEN && X448_KEYGEN {X25519_KEYGEN, CKM_EC_MONTGOMERY_KEY_PAIR_GEN, {255, 448, CKF_GENERATE_KEY_PAIR | CKF_EC_OID | CKF_EC_F_P | CKF_EC_COMPRESS} }, #endif #if defined ED25519_SIGN && ED448_SIGN {ED25519_SIGN, CKM_EDDSA, {255, 448, CKF_SIGN | CKF_VERIFY | CKF_EC_OID | CKF_EC_F_P | CKF_EC_COMPRESS} }, {ED25519_SIGN, CKM_ECDH_X_AES_KEY_WRAP, {255, 448, CKF_WRAP | CKF_UNWRAP | CKF_EC_OID | CKF_EC_F_P | CKF_EC_COMPRESS} }, #endif #endif #endif {0, CKM_PUB_KEY_FROM_PRIV_KEY, { 0, 0, CKF_DERIVE}}, }; 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, NULL); } 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, NULL); } 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_BBOOL isMechanismHW(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 ica_data->mech_list[i].mech_info.flags & CKF_HW; } return FALSE; } #define KEY_SIZE_512 0x01 #define KEY_SIZE_1024 0x02 #define KEY_SIZE_2048 0x04 #define KEY_SIZE_4096 0x08 #define RSA_NO_SMALL_EXP 0x00010000 /* e >= 65537 */ static void adjust_rsa_key_sizes(unsigned int mask, CK_MECHANISM_INFO *mech_info) { CK_ULONG min = 0, max = 0; mask &= (KEY_SIZE_512 | KEY_SIZE_1024 | KEY_SIZE_2048 | KEY_SIZE_4096); if (mask == 0) return; if (mask & KEY_SIZE_512) min = 512; else if (mask & KEY_SIZE_1024) min = 1024; else if (mask & KEY_SIZE_2048) min = 2048; else if (mask & KEY_SIZE_4096) min = 4096; max = min; if (mask & KEY_SIZE_4096) max = 4096; else if (mask & KEY_SIZE_2048) max = 2048; else if (mask & KEY_SIZE_1024) max = 1024; else if (mask & KEY_SIZE_512) max = 512; if (min > mech_info->ulMinKeySize) mech_info->ulMinKeySize = min; if (max < mech_info->ulMaxKeySize) mech_info->ulMaxKeySize = max; } static CK_RV addMechanismToList(STDLL_TokData_t *tokdata, CK_ULONG mechanism, CK_BBOOL hw, unsigned int rsa_keysize_mask) { ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; CK_ULONG ret; CK_ULONG refIdx = 0; if (isMechanismAvailable(tokdata, mechanism)) return CKR_OK; 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 & (~CKF_HW)) | (hw ? CKF_HW : 0); 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; adjust_rsa_key_sizes(rsa_keysize_mask, &ica_data->mech_list[ica_data->mech_list_len].mech_info); 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, rsa_props = 0; unsigned int ica_specific_mech_list_len; CK_ULONG tmp, ulActMechCtr, ulPreDefMechCtr, refIdx; CK_BBOOL rsa_hw, ec_hw, sha_hw; /* * Add mechanisms where we have a SW fallback unconditionally, but only * if libica is not in FIPS mode. If libica is in FIPS mode, the loop below * will add those mechanisms that libica supports and that are FIPS * approved. Mechanisms that are not FIPS approved will not be added, even * if there is a SW fallback. Because the SW fallback is OpenSSL-based, * and OpenSSL is most likely also in FIPS mode in this case, the SW * fallback would also fail if using an algorithm that is not FIPS approved. */ if (p_ica_fips_status == NULL || p_ica_fips_status() == 0) { #if !(NOMD5) addMechanismToList(tokdata, CKM_MD5, 0, 0); addMechanismToList(tokdata, CKM_MD5_HMAC, 0, 0); addMechanismToList(tokdata, CKM_MD5_HMAC_GENERAL, 0, 0); #endif /* We have RSA support (SW) in any case, regardless if libica supports it */ addMechanismToList(tokdata, CKM_RSA_PKCS_KEY_PAIR_GEN, 0, 0); addMechanismToList(tokdata, CKM_RSA_PKCS, 0, 0); #if !(NOX509) addMechanismToList(tokdata, CKM_RSA_X_509, 0, 0); #endif /* We have EC support (SW) in any case, regardless if libica supports it */ addMechanismToList(tokdata, CKM_EC_KEY_PAIR_GEN, 0, 0); addMechanismToList(tokdata, CKM_ECDSA, 0, 0); /* We have SHA support (SW) in any case, regardless if libica supports it */ addMechanismToList(tokdata, CKM_SHA_1, 0, 0); addMechanismToList(tokdata, CKM_SHA224, 0, 0); addMechanismToList(tokdata, CKM_SHA256, 0, 0); addMechanismToList(tokdata, CKM_SHA384, 0, 0); addMechanismToList(tokdata, CKM_SHA512, 0, 0); #ifdef NID_sha512_224WithRSAEncryption addMechanismToList(tokdata, CKM_SHA512_224, 0, 0); #endif #ifdef NID_sha512_256WithRSAEncryption addMechanismToList(tokdata, CKM_SHA512_256, 0, 0); #endif #ifdef NID_sha3_224 addMechanismToList(tokdata, CKM_SHA3_224, 0, 0); addMechanismToList(tokdata, CKM_IBM_SHA3_224, 0, 0); #endif #ifdef NID_sha3_256 addMechanismToList(tokdata, CKM_SHA3_256, 0, 0); addMechanismToList(tokdata, CKM_IBM_SHA3_256, 0, 0); #endif #ifdef NID_sha3_384 addMechanismToList(tokdata, CKM_SHA3_384, 0, 0); addMechanismToList(tokdata, CKM_IBM_SHA3_384, 0, 0); #endif #ifdef NID_sha3_512 addMechanismToList(tokdata, CKM_SHA3_512, 0, 0); addMechanismToList(tokdata, CKM_IBM_SHA3_512, 0, 0); #endif /* We have AES support (SW) in any case, regardless if libica supports it */ addMechanismToList(tokdata, CKM_AES_ECB, 0, 0); addMechanismToList(tokdata, CKM_AES_CBC, 0, 0); addMechanismToList(tokdata, CKM_AES_CBC_PAD, 0, 0); addMechanismToList(tokdata, CKM_AES_CTR, 0, 0); #if OPENSSL_VERSION_PREREQ(3, 0) || OPENSSL_VERSION_NUMBER >= 0x101010cfL /* * AES-OFB/CFB currently only works with >= OpenSSl 3.0 or >= OpenSSL 1.1.1l, * due to a bug in OpenSSL <= 1.1.1k in s390x_aes_ofb_cipher() not updating * the IV in the context. */ addMechanismToList(tokdata, CKM_AES_OFB, 0, 0); addMechanismToList(tokdata, CKM_AES_CFB8, 0, 0); /* CFB64 is not supported as SW fallback */ addMechanismToList(tokdata, CKM_AES_CFB128, 0, 0); #endif addMechanismToList(tokdata, CKM_AES_GCM, 0, 0); addMechanismToList(tokdata, CKM_AES_MAC, 0, 0); addMechanismToList(tokdata, CKM_AES_MAC_GENERAL, 0, 0); addMechanismToList(tokdata, CKM_AES_CMAC, 0, 0); addMechanismToList(tokdata, CKM_AES_CMAC_GENERAL, 0, 0); /* We have DES/3DES support (SW) in any case, regardless if libica supports it */ addMechanismToList(tokdata, CKM_DES_ECB, 0, 0); addMechanismToList(tokdata, CKM_DES_CBC, 0, 0); addMechanismToList(tokdata, CKM_DES_CBC_PAD, 0, 0); addMechanismToList(tokdata, CKM_DES3_ECB, 0, 0); addMechanismToList(tokdata, CKM_DES3_CBC, 0, 0); addMechanismToList(tokdata, CKM_DES3_CBC_PAD, 0, 0); addMechanismToList(tokdata, CKM_DES_OFB64, 0, 0); addMechanismToList(tokdata, CKM_DES_CFB8, 0, 0); addMechanismToList(tokdata, CKM_DES_CFB64, 0, 0); addMechanismToList(tokdata, CKM_DES3_MAC, 0, 0); addMechanismToList(tokdata, CKM_DES3_MAC_GENERAL, 0, 0); addMechanismToList(tokdata, CKM_DES3_CMAC, 0, 0); addMechanismToList(tokdata, CKM_DES3_CMAC_GENERAL, 0, 0); } /* * We have RNG support (SW) in any case, regardless if libica supports it, * and independent of FIPS mode */ addMechanismToList(tokdata, CKM_GENERIC_SECRET_KEY_GEN, 0, 0); addMechanismToList(tokdata, CKM_DES_KEY_GEN, 0, 0); addMechanismToList(tokdata, CKM_DES3_KEY_GEN, 0, 0); addMechanismToList(tokdata, CKM_AES_KEY_GEN, 0, 0); addMechanismToList(tokdata, CKM_AES_XTS_KEY_GEN, 0, 0); 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; /* Remember if libica supports RSA mechanisms (HW or SW) */ if (libica_func_list[i].mech_mode_id == RSA_KEY_GEN_ME) { ica_data->ica_rsa_keygen_available = TRUE; if (libica_func_list[i].property != 0) { rsa_props = libica_func_list[i].property; ica_data->ica_rsa_no_small_pub_exp = ((rsa_props & RSA_NO_SMALL_EXP) != 0); } } if (libica_func_list[i].mech_mode_id == RSA_ME) { ica_data->ica_rsa_endecrypt_available = TRUE; if (libica_func_list[i].property != 0) rsa_props = libica_func_list[i].property; } /* Remember if libica supports RNG mechanisms (HW or SW) */ if (libica_func_list[i].mech_mode_id == P_RNG) ica_data->ica_p_rng_available = TRUE; #ifndef NO_EC /* Remember if libica supports EC mechanisms (HW or SW) */ if (ica_data->ica_ec_support_available) { if (libica_func_list[i].mech_mode_id == EC_KGEN) ica_data->ica_ec_keygen_available = TRUE; if (libica_func_list[i].mech_mode_id == EC_DSA_SIGN) ica_data->ica_ec_signverify_available = TRUE; if (libica_func_list[i].mech_mode_id == EC_DH) ica_data->ica_ec_derive_available = TRUE; } if (ica_data->ica_ec_edwards_support_available) { if (libica_func_list[i].mech_mode_id == ED25519_KEYGEN) ica_data->ica_ec_edwards_keygen_available = TRUE; if (libica_func_list[i].mech_mode_id == ED25519_SIGN) ica_data->ica_ec_edwards_signverify_available = TRUE; } if (ica_data->ica_ec_montgomery_support_available) { if (libica_func_list[i].mech_mode_id == X25519_KEYGEN) ica_data->ica_ec_montgomery_keygen_available = TRUE; if (libica_func_list[i].mech_mode_id == X25519_DERIVE) ica_data->ica_ec_montgomery_derive_available = TRUE; } #endif /* Remember if libica supports SHA mechanisms (HW or SW) */ if (libica_func_list[i].mech_mode_id == SHA1) ica_data->ica_sha1_available = TRUE; if (libica_func_list[i].mech_mode_id == SHA512) ica_data->ica_sha2_available = TRUE; #ifdef SHA512_224 if (libica_func_list[i].mech_mode_id == SHA512_224) ica_data->ica_sha512_224_available = TRUE; #endif #ifdef SHA512_256 if (libica_func_list[i].mech_mode_id == SHA512_256) ica_data->ica_sha512_256_available = TRUE; #endif #ifdef SHA3_512 if (libica_func_list[i].mech_mode_id == SHA3_512) ica_data->ica_sha3_available = TRUE; #endif #ifdef SHAKE256 if (libica_func_list[i].mech_mode_id == SHAKE256) ica_data->ica_shake_available = TRUE; #endif /* Remember if libica supports AES mechanisms (HW or SW) */ if (libica_func_list[i].mech_mode_id == AES_CBC) ica_data->ica_aes_available = TRUE; #ifdef AES_GCM_KMA /* Remember if libica supports the new AES-GCM API (z14 and later) */ if (libica_func_list[i].mech_mode_id == AES_GCM_KMA) ica_data->ica_new_gcm_available = TRUE; #endif /* Remember if libica supports DES/3DES mechanisms (HW or SW) */ if (libica_func_list[i].mech_mode_id == DES_CBC) ica_data->ica_des_available = TRUE; if (libica_func_list[i].mech_mode_id == DES3_CBC) ica_data->ica_des3_available = TRUE; /* --- 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, ulActMechCtr = (CK_ULONG)-1; 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 & (ICA_FLAG_DHW | ICA_FLAG_SHW)) ? CKF_HW : 0) | (ref_mech_list[refIdx].mech_info.flags & (~CKF_HW)); 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; if (libica_func_list[i].mech_mode_id == RSA_KEY_GEN_ME || libica_func_list[i].mech_mode_id == RSA_ME) adjust_rsa_key_sizes(rsa_props, &ica_data->mech_list[ica_data->mech_list_len].mech_info); if (libica_func_list[i].mech_mode_id == AES_XTS && p_ica_aes_xts_ex == NULL) ica_data->mech_list[ica_data->mech_list_len].mech_info.flags &= (~CKF_HW); ica_data->mech_list_len++; } else { /* replace existing entry */ ica_data->mech_list[ulActMechCtr].mech_info.flags = ((libica_func_list[i].flags & (ICA_FLAG_DHW | ICA_FLAG_SHW)) ? CKF_HW : 0) | (ref_mech_list[refIdx].mech_info.flags & (~CKF_HW)); if (libica_func_list[i].mech_mode_id == RSA_KEY_GEN_ME || libica_func_list[i].mech_mode_id == RSA_ME) adjust_rsa_key_sizes(rsa_props, &ica_data->mech_list[ulActMechCtr].mech_info); if (libica_func_list[i].mech_mode_id == AES_XTS && p_ica_aes_xts_ex == NULL) ica_data->mech_list[ulActMechCtr].mech_info.flags &= (~CKF_HW); } refIdx++; } } /* * check if special combined mechanisms are supported * if SHAnnn and RSA is available -> insert CKM_SHAnnn_RSA_PKCS[_PSS] * if MD2 and RSA is available -> insert CKM_MD2_RSA_PKCS * if MD5 and RSA is available -> insert CKM_MD5_RSA_PKCS * if SHAnnn and EC is available -> insert CKM_ECDSA_SHAnnn * if SHAnnn and EC is available -> insert CKM_ECDH1_DERIVE * if SHAnnn is available -> insert CKM_SHAxxx_HMAC[_GENERAL] */ rsa_hw = isMechanismHW(tokdata, CKM_RSA_PKCS); sha_hw = isMechanismHW(tokdata, CKM_SHA_1); if (isMechanismAvailable(tokdata, CKM_SHA_1) && isMechanismAvailable(tokdata, CKM_SHA224) && isMechanismAvailable(tokdata, CKM_SHA256) && isMechanismAvailable(tokdata, CKM_SHA384) && isMechanismAvailable(tokdata, CKM_SHA512)) { addMechanismToList(tokdata, CKM_RSA_PKCS_OAEP, 0, rsa_props); addMechanismToList(tokdata, CKM_RSA_PKCS_PSS, 0, rsa_props); } if (isMechanismAvailable(tokdata, CKM_SHA_1) && isMechanismAvailable(tokdata, CKM_RSA_PKCS)) addMechanismToList(tokdata, CKM_SHA1_RSA_PKCS, rsa_hw && sha_hw, rsa_props); if (isMechanismAvailable(tokdata, CKM_SHA224) && isMechanismAvailable(tokdata, CKM_RSA_PKCS)) addMechanismToList(tokdata, CKM_SHA224_RSA_PKCS, rsa_hw && sha_hw, rsa_props); if (isMechanismAvailable(tokdata, CKM_SHA256) && isMechanismAvailable(tokdata, CKM_RSA_PKCS)) addMechanismToList(tokdata, CKM_SHA256_RSA_PKCS, rsa_hw && sha_hw, rsa_props); if (isMechanismAvailable(tokdata, CKM_SHA384) && isMechanismAvailable(tokdata, CKM_RSA_PKCS)) addMechanismToList(tokdata, CKM_SHA384_RSA_PKCS, rsa_hw && sha_hw, rsa_props); if (isMechanismAvailable(tokdata, CKM_SHA512) && isMechanismAvailable(tokdata, CKM_RSA_PKCS)) addMechanismToList(tokdata, CKM_SHA512_RSA_PKCS, rsa_hw && sha_hw, rsa_props); if (isMechanismAvailable(tokdata, CKM_SHA3_224) && isMechanismAvailable(tokdata, CKM_RSA_PKCS)) addMechanismToList(tokdata, CKM_SHA3_224_RSA_PKCS, rsa_hw && sha_hw, rsa_props); if (isMechanismAvailable(tokdata, CKM_SHA3_256) && isMechanismAvailable(tokdata, CKM_RSA_PKCS)) addMechanismToList(tokdata, CKM_SHA3_256_RSA_PKCS, rsa_hw && sha_hw, rsa_props); if (isMechanismAvailable(tokdata, CKM_SHA3_384) && isMechanismAvailable(tokdata, CKM_RSA_PKCS)) addMechanismToList(tokdata, CKM_SHA3_384_RSA_PKCS, rsa_hw && sha_hw, rsa_props); if (isMechanismAvailable(tokdata, CKM_SHA3_512) && isMechanismAvailable(tokdata, CKM_RSA_PKCS)) addMechanismToList(tokdata, CKM_SHA3_512_RSA_PKCS, rsa_hw && sha_hw, rsa_props); #if !(NOMD2 ) if (isMechanismAvailable(tokdata, CKM_MD2) && isMechanismAvailable(tokdata, CKM_RSA_PKCS)) addMechanismToList(tokdata, CKM_MD2_RSA_PKCS, rsa_hw && sha_hw, rsa_props); #endif if (isMechanismAvailable(tokdata, CKM_MD5) && isMechanismAvailable(tokdata, CKM_RSA_PKCS)) addMechanismToList(tokdata, CKM_MD5_RSA_PKCS, rsa_hw && sha_hw, rsa_props); if (isMechanismAvailable(tokdata, CKM_SHA_1) && isMechanismAvailable(tokdata, CKM_RSA_PKCS_PSS)) addMechanismToList(tokdata, CKM_SHA1_RSA_PKCS_PSS, rsa_hw && sha_hw, rsa_props); if (isMechanismAvailable(tokdata, CKM_SHA224) && isMechanismAvailable(tokdata, CKM_RSA_PKCS_PSS)) addMechanismToList(tokdata, CKM_SHA224_RSA_PKCS_PSS, rsa_hw && sha_hw, rsa_props); if (isMechanismAvailable(tokdata, CKM_SHA256) && isMechanismAvailable(tokdata, CKM_RSA_PKCS_PSS)) addMechanismToList(tokdata, CKM_SHA256_RSA_PKCS_PSS, rsa_hw && sha_hw, rsa_props); if (isMechanismAvailable(tokdata, CKM_SHA384) && isMechanismAvailable(tokdata, CKM_RSA_PKCS_PSS)) addMechanismToList(tokdata, CKM_SHA384_RSA_PKCS_PSS, rsa_hw && sha_hw, rsa_props); if (isMechanismAvailable(tokdata, CKM_SHA512) && isMechanismAvailable(tokdata, CKM_RSA_PKCS_PSS)) addMechanismToList(tokdata, CKM_SHA512_RSA_PKCS_PSS, rsa_hw && sha_hw, rsa_props); if (isMechanismAvailable(tokdata, CKM_SHA3_224) && isMechanismAvailable(tokdata, CKM_RSA_PKCS_PSS)) addMechanismToList(tokdata, CKM_SHA3_224_RSA_PKCS_PSS, rsa_hw && sha_hw, rsa_props); if (isMechanismAvailable(tokdata, CKM_SHA3_256) && isMechanismAvailable(tokdata, CKM_RSA_PKCS_PSS)) addMechanismToList(tokdata, CKM_SHA3_256_RSA_PKCS_PSS, rsa_hw && sha_hw, rsa_props); if (isMechanismAvailable(tokdata, CKM_SHA3_384) && isMechanismAvailable(tokdata, CKM_RSA_PKCS_PSS)) addMechanismToList(tokdata, CKM_SHA3_384_RSA_PKCS_PSS, rsa_hw && sha_hw, rsa_props); if (isMechanismAvailable(tokdata, CKM_SHA3_512) && isMechanismAvailable(tokdata, CKM_RSA_PKCS_PSS)) addMechanismToList(tokdata, CKM_SHA3_512_RSA_PKCS_PSS, rsa_hw && sha_hw, rsa_props); if (isMechanismAvailable(tokdata, CKM_AES_KEY_GEN) && isMechanismAvailable(tokdata, CKM_RSA_PKCS_OAEP) && isMechanismAvailable(tokdata, CKM_AES_KEY_WRAP_KWP)) addMechanismToList(tokdata, CKM_RSA_AES_KEY_WRAP, 0, rsa_props); ec_hw = isMechanismHW(tokdata, CKM_ECDSA); if (isMechanismAvailable(tokdata, CKM_SHA_1) && isMechanismAvailable(tokdata, CKM_ECDSA)) addMechanismToList(tokdata, CKM_ECDSA_SHA1, ec_hw && sha_hw, 0); if (isMechanismAvailable(tokdata, CKM_SHA224) && isMechanismAvailable(tokdata, CKM_ECDSA)) addMechanismToList(tokdata, CKM_ECDSA_SHA224, ec_hw && sha_hw, 0); if (isMechanismAvailable(tokdata, CKM_SHA256) && isMechanismAvailable(tokdata, CKM_ECDSA)) addMechanismToList(tokdata, CKM_ECDSA_SHA256, ec_hw && sha_hw, 0); if (isMechanismAvailable(tokdata, CKM_SHA384) && isMechanismAvailable(tokdata, CKM_ECDSA)) addMechanismToList(tokdata, CKM_ECDSA_SHA384, ec_hw && sha_hw, 0); if (isMechanismAvailable(tokdata, CKM_SHA512) && isMechanismAvailable(tokdata, CKM_ECDSA)) addMechanismToList(tokdata, CKM_ECDSA_SHA512, ec_hw && sha_hw, 0); if (isMechanismAvailable(tokdata, CKM_SHA3_224) && isMechanismAvailable(tokdata, CKM_ECDSA)) addMechanismToList(tokdata, CKM_ECDSA_SHA3_224, ec_hw && sha_hw, 0); if (isMechanismAvailable(tokdata, CKM_SHA3_256) && isMechanismAvailable(tokdata, CKM_ECDSA)) addMechanismToList(tokdata, CKM_ECDSA_SHA3_256, ec_hw && sha_hw, 0); if (isMechanismAvailable(tokdata, CKM_SHA3_384) && isMechanismAvailable(tokdata, CKM_ECDSA)) addMechanismToList(tokdata, CKM_ECDSA_SHA3_384, ec_hw && sha_hw, 0); if (isMechanismAvailable(tokdata, CKM_SHA3_512) && isMechanismAvailable(tokdata, CKM_ECDSA)) addMechanismToList(tokdata, CKM_ECDSA_SHA3_512, ec_hw && sha_hw, 0); if (isMechanismAvailable(tokdata, CKM_EC_KEY_PAIR_GEN) && isMechanismAvailable(tokdata, CKM_SHA_1) && isMechanismAvailable(tokdata, CKM_SHA224) && isMechanismAvailable(tokdata, CKM_SHA256) && isMechanismAvailable(tokdata, CKM_SHA384) && isMechanismAvailable(tokdata, CKM_SHA512)) addMechanismToList(tokdata, CKM_ECDH1_DERIVE, ec_hw && sha_hw, 0); if (isMechanismAvailable(tokdata, CKM_EC_KEY_PAIR_GEN) && isMechanismAvailable(tokdata, CKM_ECDH1_DERIVE) && isMechanismAvailable(tokdata, CKM_AES_KEY_WRAP_KWP)) addMechanismToList(tokdata, CKM_ECDH_AES_KEY_WRAP, ec_hw && sha_hw, 0); if (isMechanismAvailable(tokdata, CKM_SHA_1)) { addMechanismToList(tokdata, CKM_SHA_1_HMAC, sha_hw, 0); addMechanismToList(tokdata, CKM_SHA_1_HMAC_GENERAL, sha_hw, 0); addMechanismToList(tokdata, CKM_SHA1_KEY_DERIVATION, sha_hw, 0); addMechanismToList(tokdata, CKM_SHA_1_KEY_GEN, sha_hw, 0); } if (isMechanismAvailable(tokdata, CKM_SHA224)) { addMechanismToList(tokdata, CKM_SHA224_HMAC, sha_hw, 0); addMechanismToList(tokdata, CKM_SHA224_HMAC_GENERAL, sha_hw, 0); addMechanismToList(tokdata, CKM_SHA224_KEY_DERIVATION, sha_hw, 0); addMechanismToList(tokdata, CKM_SHA224_KEY_GEN, sha_hw, 0); } if (isMechanismAvailable(tokdata, CKM_SHA256)) { addMechanismToList(tokdata, CKM_SHA256_HMAC, sha_hw, 0); addMechanismToList(tokdata, CKM_SHA256_HMAC_GENERAL, sha_hw, 0); addMechanismToList(tokdata, CKM_SHA256_KEY_DERIVATION, sha_hw, 0); addMechanismToList(tokdata, CKM_SHA256_KEY_GEN, sha_hw, 0); } if (isMechanismAvailable(tokdata, CKM_SHA384)) { addMechanismToList(tokdata, CKM_SHA384_HMAC, sha_hw, 0); addMechanismToList(tokdata, CKM_SHA384_HMAC_GENERAL, sha_hw, 0); addMechanismToList(tokdata, CKM_SHA384_KEY_DERIVATION, sha_hw, 0); addMechanismToList(tokdata, CKM_SHA384_KEY_GEN, sha_hw, 0); } if (isMechanismAvailable(tokdata, CKM_SHA512)) { addMechanismToList(tokdata, CKM_SHA512_HMAC, sha_hw, 0); addMechanismToList(tokdata, CKM_SHA512_HMAC_GENERAL, sha_hw, 0); addMechanismToList(tokdata, CKM_SHA512_KEY_DERIVATION, sha_hw, 0); addMechanismToList(tokdata, CKM_SHA512_KEY_GEN, sha_hw, 0); } #ifdef NID_sha512_224WithRSAEncryption if (isMechanismAvailable(tokdata, CKM_SHA512_224)) { addMechanismToList(tokdata, CKM_SHA512_224_HMAC, sha_hw, 0); addMechanismToList(tokdata, CKM_SHA512_224_HMAC_GENERAL, sha_hw, 0); addMechanismToList(tokdata, CKM_SHA512_224_KEY_DERIVATION, sha_hw, 0); addMechanismToList(tokdata, CKM_SHA512_224_KEY_GEN, sha_hw, 0); } #endif #ifdef NID_sha512_256WithRSAEncryption if (isMechanismAvailable(tokdata, CKM_SHA512_256)) { addMechanismToList(tokdata, CKM_SHA512_256_HMAC, sha_hw, 0); addMechanismToList(tokdata, CKM_SHA512_256_HMAC_GENERAL, sha_hw, 0); addMechanismToList(tokdata, CKM_SHA512_256_KEY_DERIVATION, sha_hw, 0); addMechanismToList(tokdata, CKM_SHA512_256_KEY_GEN, sha_hw, 0); } #endif #ifdef NID_sha3_224 if (isMechanismAvailable(tokdata, CKM_IBM_SHA3_224)) addMechanismToList(tokdata, CKM_IBM_SHA3_224_HMAC, sha_hw, 0); if (isMechanismAvailable(tokdata, CKM_SHA3_224)) { addMechanismToList(tokdata, CKM_SHA3_224_HMAC, sha_hw, 0); addMechanismToList(tokdata, CKM_SHA3_224_HMAC_GENERAL, sha_hw, 0); addMechanismToList(tokdata, CKM_SHA3_224_KEY_DERIVATION, sha_hw, 0); addMechanismToList(tokdata, CKM_SHA3_224_KEY_GEN, sha_hw, 0); } #endif #ifdef NID_sha3_256 if (isMechanismAvailable(tokdata, CKM_IBM_SHA3_256)) addMechanismToList(tokdata, CKM_IBM_SHA3_256_HMAC, sha_hw, 0); if (isMechanismAvailable(tokdata, CKM_SHA3_256)) { addMechanismToList(tokdata, CKM_SHA3_256_HMAC, sha_hw, 0); addMechanismToList(tokdata, CKM_SHA3_256_HMAC_GENERAL, sha_hw, 0); addMechanismToList(tokdata, CKM_SHA3_256_KEY_DERIVATION, sha_hw, 0); addMechanismToList(tokdata, CKM_SHA3_256_KEY_GEN, sha_hw, 0); } #endif #ifdef NID_sha3_384 if (isMechanismAvailable(tokdata, CKM_IBM_SHA3_384)) addMechanismToList(tokdata, CKM_IBM_SHA3_384_HMAC, sha_hw, 0); if (isMechanismAvailable(tokdata, CKM_SHA3_384)) { addMechanismToList(tokdata, CKM_SHA3_384_HMAC, sha_hw, 0); addMechanismToList(tokdata, CKM_SHA3_384_HMAC_GENERAL, sha_hw, 0); addMechanismToList(tokdata, CKM_SHA3_384_KEY_DERIVATION, sha_hw, 0); addMechanismToList(tokdata, CKM_SHA3_384_KEY_GEN, sha_hw, 0); } #endif #ifdef NID_sha3_512 if (isMechanismAvailable(tokdata, CKM_IBM_SHA3_512)) addMechanismToList(tokdata, CKM_IBM_SHA3_512_HMAC, sha_hw, 0); if (isMechanismAvailable(tokdata, CKM_SHA3_512)) { addMechanismToList(tokdata, CKM_SHA3_512_HMAC, sha_hw, 0); addMechanismToList(tokdata, CKM_SHA3_512_HMAC_GENERAL, sha_hw, 0); addMechanismToList(tokdata, CKM_SHA3_512_KEY_DERIVATION, sha_hw, 0); addMechanismToList(tokdata, CKM_SHA3_512_KEY_GEN, sha_hw, 0); } #endif addMechanismToList(tokdata, CKM_PUB_KEY_FROM_PRIV_KEY, 0, 0); /* 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_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_get_ulong(tmpl, CKA_VALUE_LEN, &key_length); if (rc != CKR_OK) { TRACE_ERROR("CKA_VALUE_LEN missing in (HMAC) key template\n"); return CKR_TEMPLATE_INCOMPLETE; } //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"); free(value_attr); } 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; rv = template_update_attribute(tmpl, attr); if (rv != CKR_OK) { free(attr); return rv; } 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 }; static const CK_BYTE curve25519[] = { 0x06, 0x03, 0x2B, 0x65, 0x6E }; static const CK_BYTE curve448[] = { 0x06, 0x03, 0x2B, 0x65, 0x6F }; static const CK_BYTE ed25519[] = { 0x06, 0x03, 0x2B, 0x65, 0x70 }; static const CK_BYTE ed448[] = { 0x06, 0x03, 0x2B, 0x65, 0x71 }; 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; else if (is_equal(oid, oid_length, (unsigned char *) &curve25519, sizeof(curve25519))) return NID_X25519; else if (is_equal(oid, oid_length, (unsigned char *) &curve448, sizeof(curve448))) return NID_X448; else if (is_equal(oid, oid_length, (unsigned char *) &ed25519, sizeof(ed25519))) return NID_ED25519; else if (is_equal(oid, oid_length, (unsigned char *) &ed448, sizeof(ed448))) return NID_ED448; return -1; } static CK_RV ica_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; } ret = template_attribute_get_non_empty(publ_tmpl, CKA_EC_PARAMS, &attr); if (ret != CKR_OK) { 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) { switch (rc) { case EPERM: TRACE_ERROR("ica_ec_key_generate() failed with rc=EPERM, probably curve not supported by openssl.\n"); ret = CKR_CURVE_NOT_SUPPORTED; break; case ENODEV: TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); ret = CKR_FUNCTION_NOT_SUPPORTED; break; default: TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); ret = CKR_FUNCTION_FAILED; break; } 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_EC_PARAMS to private template also */ ret = build_update_attribute(priv_tmpl, CKA_EC_PARAMS, attr->pValue, attr->ulValueLen); if (ret != 0) { TRACE_ERROR("build_update_attribute for CKA_EC_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_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 rc = CKR_FUNCTION_FAILED; if (ica_data->ica_ec_keygen_available) { rc = ica_specific_ec_generate_keypair(tokdata, publ_tmpl, priv_tmpl); if (rc == CKR_FUNCTION_NOT_SUPPORTED) ica_data->ica_ec_keygen_available = FALSE; } if (!ica_data->ica_ec_keygen_available) rc = openssl_specific_ec_generate_keypair(tokdata, publ_tmpl, priv_tmpl, CKM_EC_KEY_PAIR_GEN); return rc; } static int ica_ed_x_ctx_new(int nid, void **ctx) { switch (nid) { case NID_ED25519: return p_ica_ed25519_ctx_new((ICA_ED25519_CTX**)ctx); case NID_ED448: return p_ica_ed448_ctx_new((ICA_ED448_CTX**)ctx); case NID_X25519: return p_ica_x25519_ctx_new((ICA_X25519_CTX**)ctx); case NID_X448: return p_ica_x448_ctx_new((ICA_X448_CTX**)ctx); default: TRACE_ERROR("Not an Edwards or Montgomery curve.\n"); return EPERM; } } static int ica_ed_x_ctx_del(int nid, void **ctx) { switch (nid) { case NID_ED25519: return p_ica_ed25519_ctx_del((ICA_ED25519_CTX**)ctx); case NID_ED448: return p_ica_ed448_ctx_del((ICA_ED448_CTX**)ctx); case NID_X25519: return p_ica_x25519_ctx_del((ICA_X25519_CTX**)ctx); case NID_X448: return p_ica_x448_ctx_del((ICA_X448_CTX**)ctx); default: TRACE_ERROR("Not an Edwards or Montgomery curve.\n"); return EPERM; } } static int ica_ed_x_key_gen(int nid, void *ctx) { switch (nid) { case NID_ED25519: return p_ica_ed25519_key_gen((ICA_ED25519_CTX*)ctx); case NID_ED448: return p_ica_ed448_key_gen((ICA_ED448_CTX*)ctx); case NID_X25519: return p_ica_x25519_key_gen((ICA_X25519_CTX*)ctx); case NID_X448: return p_ica_x448_key_gen((ICA_X448_CTX*)ctx); default: TRACE_ERROR("Not an Edwards or Montgomery curve.\n"); return EPERM; } } static int ica_ed_x_key_get(int nid, void *ctx, CK_BYTE* priv, CK_BYTE *pub, CK_ULONG *len) { switch (nid) { case NID_ED25519: if (*len < 32) return EINVAL; *len = 32; return p_ica_ed25519_key_get((ICA_ED25519_CTX*)ctx, priv, pub); case NID_ED448: if (*len < 57) return EINVAL; *len = 57; return p_ica_ed448_key_get((ICA_ED448_CTX*)ctx, priv, pub); case NID_X25519: if (*len < 32) return EINVAL; *len = 32; return p_ica_x25519_key_get((ICA_X25519_CTX*)ctx, priv, pub); case NID_X448: if (*len < 56) return EINVAL; *len = 56; return p_ica_x448_key_get((ICA_X448_CTX*)ctx, priv, pub); default: TRACE_ERROR("Not an Edwards or Montgomery curve.\n"); return EPERM; } } static int ica_ed_x_key_set(int nid, void *ctx, CK_BYTE* priv, CK_BYTE *pub, CK_ULONG len) { switch (nid) { case NID_ED25519: if (len != 32) return EINVAL; return p_ica_ed25519_key_set((ICA_ED25519_CTX*)ctx, priv, pub); case NID_ED448: if (len != 57) return EINVAL; return p_ica_ed448_key_set((ICA_ED448_CTX*)ctx, priv, pub); case NID_X25519: if (len != 32) return EINVAL; return p_ica_x25519_key_set((ICA_X25519_CTX*)ctx, priv, pub); case NID_X448: if (len != 56) return EINVAL; return p_ica_x448_key_set((ICA_X448_CTX*)ctx, priv, pub); default: TRACE_ERROR("Not an Edwards or Montgomery curve.\n"); return EPERM; } } static int ica_eddsa_sign(int nid, void *ctx, CK_BYTE *sig, CK_ULONG *sig_len, CK_BYTE *msg, CK_ULONG msg_len) { switch (nid) { case NID_ED25519: if (*sig_len < 64) return EINVAL; *sig_len = 64; return p_ica_ed25519_sign((ICA_ED25519_CTX*)ctx, sig, msg, msg_len); case NID_ED448: if (*sig_len < 114) return EINVAL; *sig_len = 114; return p_ica_ed448_sign((ICA_ED448_CTX*)ctx, sig, msg, msg_len); default: TRACE_ERROR("Not an Edwards or Montgomery curve.\n"); return EPERM; } } static int ica_eddsa_verify(int nid, void *ctx, CK_BYTE *sig, CK_ULONG sig_len, CK_BYTE *msg, CK_ULONG msg_len) { switch (nid) { case NID_ED25519: if (sig_len != 64) return EINVAL; return p_ica_ed25519_verify((ICA_ED25519_CTX*)ctx, sig, msg, msg_len); case NID_ED448: if (sig_len != 114) return EINVAL; return p_ica_ed448_verify((ICA_ED448_CTX*)ctx, sig, msg, msg_len); default: TRACE_ERROR("Not an Edwards or Montgomery curve.\n"); return EPERM; } } static int ica_x_derive(int nid, void *ctx, CK_BYTE *shared_secret, CK_BYTE *peer_pubkey, CK_ULONG key_len) { switch (nid) { case NID_X25519: if (key_len != 32) return EINVAL; return p_ica_x25519_derive((ICA_X25519_CTX*)ctx, shared_secret, peer_pubkey); case NID_X448: if (key_len != 56) return EINVAL; return p_ica_x448_derive((ICA_X448_CTX*)ctx, shared_secret, peer_pubkey); break; default: TRACE_ERROR("Not an Edwards or Montgomery curve.\n"); return EPERM; } } static CK_RV ica_specific_ec_edwards_montgomery_generate_keypair( STDLL_TokData_t *tokdata, TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl, CK_MECHANISM_TYPE mech) { ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; CK_RV ret = CKR_OK; CK_ATTRIBUTE *attr = NULL; void *ctx = NULL; CK_BYTE priv[57], pub [57]; CK_ULONG key_len = sizeof(priv); int rc, nid; ret = template_attribute_get_non_empty(publ_tmpl, CKA_EC_PARAMS, &attr); if (ret != CKR_OK) { 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; } switch (nid) { case NID_ED25519: case NID_ED448: if (mech != CKM_EC_EDWARDS_KEY_PAIR_GEN) { TRACE_ERROR("Edwards curve only supported with " "CKM_EC_EDWARDS_KEY_PAIR_GEN.\n"); return CKR_CURVE_NOT_SUPPORTED; } if (!ica_data->ica_ec_edwards_keygen_available) { TRACE_ERROR("EC-Edwards support is not available in Libica\n"); return CKR_FUNCTION_NOT_SUPPORTED; } break; case NID_X25519: case NID_X448: if (mech != CKM_EC_MONTGOMERY_KEY_PAIR_GEN) { TRACE_ERROR("Montgomery curve only supported with " "CKM_EC_MONTGOMERY_KEY_PAIR_GEN.\n"); return CKR_CURVE_NOT_SUPPORTED; } if (!ica_data->ica_ec_montgomery_keygen_available) { TRACE_ERROR("EC-Montgomery support is not available in Libica\n"); return CKR_FUNCTION_NOT_SUPPORTED; } break; default: TRACE_ERROR("Not an Edwards or Montgomery curve.\n"); return CKR_CURVE_NOT_SUPPORTED; } /* Create ICA_ED/Xxxx_CTX object */ rc = ica_ed_x_ctx_new(nid, &ctx); if (rc != 0) { TRACE_ERROR("ica_ed_x_ctx_new failed.\n"); return CKR_FUNCTION_FAILED; } /* Generate key data for this key object */ rc = ica_ed_x_key_gen(nid, ctx); if (rc != 0) { TRACE_ERROR("ica_ed_x_key_gen() failed with rc = %d \n", rc); ret = CKR_FUNCTION_FAILED; goto end; } /* Get the key material */ rc = ica_ed_x_key_get(nid, ctx, priv, pub, &key_len); if (rc != 0) { TRACE_ERROR("ica_ed_x_key_get failed with rc=%d.\n", rc); ret = CKR_FUNCTION_FAILED; goto end; } /* Return public key (X, Y) via CKA_EC_POINT */ ret = build_update_attribute(publ_tmpl, CKA_EC_POINT, pub, key_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 */ ret = build_update_attribute(priv_tmpl, CKA_VALUE, priv, key_len); if (ret != 0) { TRACE_ERROR("build_update_attribute for (D) failed, rc=0x%lx\n", ret); goto end; } /* Add CKA_EC_PARAMS to private template also */ ret = build_update_attribute(priv_tmpl, CKA_EC_PARAMS, attr->pValue, attr->ulValueLen); if (ret != 0) { TRACE_ERROR("build_update_attribute for CKA_EC_PARAMS failed, " "rc=0x%lx\n", ret); goto end; } ret = CKR_OK; end: ica_ed_x_ctx_del(nid, &ctx); return ret; } CK_RV token_specific_ec_edwards_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 rc = CKR_FUNCTION_FAILED; if (ica_data->ica_ec_edwards_keygen_available) { rc = ica_specific_ec_edwards_montgomery_generate_keypair( tokdata, publ_tmpl, priv_tmpl, CKM_EC_EDWARDS_KEY_PAIR_GEN); if (rc == CKR_FUNCTION_NOT_SUPPORTED) ica_data->ica_ec_edwards_keygen_available = FALSE; } if (!ica_data->ica_ec_edwards_keygen_available) rc = openssl_specific_ec_generate_keypair(tokdata, publ_tmpl, priv_tmpl, CKM_EC_EDWARDS_KEY_PAIR_GEN); return rc; } CK_RV token_specific_ec_montgomery_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 rc = CKR_FUNCTION_FAILED; if (ica_data->ica_ec_montgomery_keygen_available) { rc = ica_specific_ec_edwards_montgomery_generate_keypair( tokdata, publ_tmpl, priv_tmpl, CKM_EC_MONTGOMERY_KEY_PAIR_GEN); if (rc == CKR_FUNCTION_NOT_SUPPORTED) ica_data->ica_ec_montgomery_keygen_available = FALSE; } if (!ica_data->ica_ec_montgomery_keygen_available) rc = openssl_specific_ec_generate_keypair(tokdata, publ_tmpl, priv_tmpl, CKM_EC_MONTGOMERY_KEY_PAIR_GEN); return rc; } /** * 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(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(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; } static CK_RV ica_prepare_ec_key(OBJECT *key_obj, ICA_EC_KEY **eckey, unsigned int *privlen, int *nid) { CK_RV ret = CKR_OK; CK_ATTRIBUTE *attr; /* Get CKA_EC_PARAMS from template */ ret = template_attribute_get_non_empty(key_obj->template, CKA_EC_PARAMS, &attr); if (ret != CKR_OK) { 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; } return CKR_OK; } static CK_RV ica_build_ec_priv_key(OBJECT *key_obj, ICA_EC_KEY **eckey, unsigned int *privlen) { CK_RV ret = CKR_OK; CK_ATTRIBUTE *attr; unsigned char *d = NULL; int rc, nid; /* Prepare the ICA key */ ret = ica_prepare_ec_key(key_obj, eckey, privlen, &nid); if (ret != CKR_OK) { TRACE_ERROR("ica_prepare_ec_key() failed with rc = 0x%lx. \n", ret); return ret; } /* Get private key from template via CKA_VALUE */ ret = template_attribute_get_non_empty(key_obj->template, CKA_VALUE, &attr); if (ret != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); ret = CKR_TEMPLATE_INCOMPLETE; goto end; } /* Add zero padding if needed */ if (*privlen > attr->ulValueLen) { d = calloc(*privlen, 1); if (d == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); ret = CKR_HOST_MEMORY; goto end; } memcpy(d + *privlen - attr->ulValueLen, attr->pValue, attr->ulValueLen); } /* Initialize ICA_EC_KEY with private key (D) */ rc = p_ica_ec_key_init(NULL, NULL, d != NULL ? d : attr->pValue, *eckey); if (rc != 0) { switch (rc) { case ENODEV: TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); ret = CKR_FUNCTION_NOT_SUPPORTED; break; case EPERM: TRACE_ERROR("ica_ec_key_init() failed with rc=EPERM, probably curve not supported by openssl.\n"); ret = CKR_CURVE_NOT_SUPPORTED; break; default: TRACE_ERROR("ica_ec_key_init() failed with rc = %d \n", rc); ret = CKR_FUNCTION_FAILED; break; } goto end; } end: if (ret != CKR_OK) { p_ica_ec_key_free(*eckey); *eckey = NULL; } if (d != NULL) free(d); return ret; } static CK_RV ica_build_ec_pub_key(OBJECT *key_obj, ICA_EC_KEY **eckey, unsigned int *privlen) { CK_RV ret = CKR_OK; CK_ATTRIBUTE *attr; 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; /* Prepare the ICA key */ ret = ica_prepare_ec_key(key_obj, eckey, privlen, &nid); if (ret != CKR_OK) { TRACE_ERROR("ica_prepare_ec_key() failed with rc = 0x%lx. \n", ret); return ret; } /* Get public key (X,Y) from template via CKA_EC_POINT */ ret = template_attribute_get_non_empty(key_obj->template, CKA_EC_POINT, &attr); if (ret != CKR_OK) { 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(attr->pValue, attr->ulValueLen, &ecpoint, &ecpoint_len, &field_len); if (ret != CKR_OK || field_len != attr->ulValueLen) { TRACE_DEVEL("ber_decode_OCTET_STRING failed\n"); ret = CKR_ATTRIBUTE_VALUE_INVALID; 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) { switch (rc) { case ENODEV: TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); ret = CKR_FUNCTION_NOT_SUPPORTED; break; case EPERM: TRACE_ERROR("ica_ec_key_init() failed with rc=EPERM, probably curve not supported by openssl.\n"); ret = CKR_CURVE_NOT_SUPPORTED; break; default: TRACE_ERROR("ica_ec_key_init() failed with rc = %d \n", rc); ret = CKR_FUNCTION_FAILED; break; } goto end; } end: if (ret != CKR_OK) { p_ica_ec_key_free(*eckey); *eckey = NULL; } return ret; } static CK_RV ica_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; ica_ex_data_t *ex_data = NULL; CK_RV ret = CKR_OK; ICA_EC_KEY *eckey; unsigned int privlen; int rc; 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; } rc = openssl_get_ex_data(key_obj, (void **)&ex_data, sizeof(ica_ex_data_t), ica_need_wr_lock_ec_key, ica_free_ex_data); if (rc != CKR_OK) return rc; if (ex_data->eckey == NULL) { /* Get the private key */ ret = ica_build_ec_priv_key(key_obj, &ex_data->eckey, &ex_data->ec_privlen); if (ret != CKR_OK) { TRACE_ERROR("ica_build_ec_priv_key() failed with rc = 0x%lx. \n", ret); goto end; } } eckey = ex_data->eckey; privlen = ex_data->ec_privlen; /* Create signature */ rc = p_ica_ecdsa_sign(ica_data->adapter_handle, eckey, (unsigned char *) in_data, (unsigned int) in_data_len, (unsigned char *) out_data, 2 * privlen); if (rc != 0) { switch (rc) { case ENODEV: TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); ret = CKR_FUNCTION_NOT_SUPPORTED; break; default: TRACE_ERROR("ica_ecdsa_sign() failed with rc = %d. \n", rc); ret = CKR_FUNCTION_FAILED; break; } goto end; } *out_data_len = 2 * privlen; ret = CKR_OK; end: object_ex_data_unlock(key_obj); 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 rc = CKR_FUNCTION_FAILED; if (ica_data->ica_ec_signverify_available) { rc = ica_specific_ec_sign(tokdata, sess, in_data, in_data_len, out_data, out_data_len, key_obj); if (rc == CKR_FUNCTION_NOT_SUPPORTED) ica_data->ica_ec_signverify_available = FALSE; } if (!ica_data->ica_ec_signverify_available) rc = openssl_specific_ec_sign(tokdata, sess, in_data, in_data_len, out_data, out_data_len, key_obj); return rc; } static CK_RV ica_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; ica_ex_data_t *ex_data = NULL; CK_RV ret = CKR_OK; ICA_EC_KEY *eckey; unsigned int privlen; int rc; UNUSED(sess); if (!ica_data->ica_ec_support_available) { TRACE_ERROR("ECC support is not available in Libica\n"); return CKR_FUNCTION_NOT_SUPPORTED; } rc = openssl_get_ex_data(key_obj, (void **)&ex_data, sizeof(ica_ex_data_t), ica_need_wr_lock_ec_key, ica_free_ex_data); if (rc != CKR_OK) return rc; if (ex_data->eckey == NULL) { /* Get the public key */ ret = ica_build_ec_pub_key(key_obj, &ex_data->eckey, &ex_data->ec_privlen); if (ret != CKR_OK) { TRACE_ERROR("ica_build_ec_pub_key() failed with rc = 0x%lx. \n", ret); goto end; } } eckey = ex_data->eckey; privlen = ex_data->ec_privlen; /* Signature length ok? */ if (signature_len != 2 * privlen) { TRACE_ERROR("Supplied signature length mismatch: " "supplied length = %ld, length from libica = %i\n", signature_len, 2 * privlen); ret = CKR_SIGNATURE_LEN_RANGE; 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 ENODEV: TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); ret = CKR_FUNCTION_NOT_SUPPORTED; 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: object_ex_data_unlock(key_obj); return ret; } 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 rc = CKR_FUNCTION_FAILED; if (ica_data->ica_ec_signverify_available) { rc = ica_specific_ec_verify(tokdata, sess, in_data, in_data_len, signature, signature_len, key_obj); if (rc == CKR_FUNCTION_NOT_SUPPORTED) ica_data->ica_ec_signverify_available = FALSE; } if (!ica_data->ica_ec_signverify_available) rc = openssl_specific_ec_verify(tokdata, sess, in_data, in_data_len, signature, signature_len, key_obj); return rc; } static CK_RV ica_prepare_ec_edwards_montgomery_ctx(OBJECT *key_obj, void **ed_x_ctx, int *nid) { CK_RV ret = CKR_OK; CK_ATTRIBUTE *attr; int rc; /* Get CKA_EC_PARAMS from template */ ret = template_attribute_get_non_empty(key_obj->template, CKA_EC_PARAMS, &attr); if (ret != CKR_OK) { 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; } switch (*nid) { case NID_ED25519: case NID_ED448: case NID_X25519: case NID_X448: break; default: TRACE_ERROR("Must be an Edwards or Montgomery curve.\n"); return CKR_CURVE_NOT_SUPPORTED; } /* Create Ed/X context object */ rc = ica_ed_x_ctx_new(*nid, ed_x_ctx); if (rc != 0) { TRACE_ERROR("ica_ed_x_ctx_new() failed for curve %i.\n", *nid); return CKR_FUNCTION_FAILED; } return CKR_OK; } static CK_RV ica_build_ec_edwards_montgomery_priv_ctx(OBJECT *key_obj, void **ed_x_ctx, int *nid) { CK_RV ret = CKR_OK; CK_ATTRIBUTE *attr; int rc; /* Prepare the ICA context */ ret = ica_prepare_ec_edwards_montgomery_ctx(key_obj, ed_x_ctx, nid); if (ret != CKR_OK) { TRACE_ERROR("ica_prepare_ec_edwards_montgomery_ctx() failed with " "rc = 0x%lx. \n", ret); return ret; } /* Get private key from template via CKA_VALUE */ ret = template_attribute_get_non_empty(key_obj->template, CKA_VALUE, &attr); if (ret != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); ret = CKR_TEMPLATE_INCOMPLETE; goto end; } /* Initialize Ed/X with private key (D) */ rc = ica_ed_x_key_set(*nid, *ed_x_ctx, attr->pValue, NULL, attr->ulValueLen); if (rc != 0) { TRACE_ERROR("ica_ed_x_key_set() failed with rc = %d \n", rc); ret = CKR_FUNCTION_FAILED; goto end; } end: if (ret != CKR_OK) { ica_ed_x_ctx_del(*nid, ed_x_ctx); *ed_x_ctx = NULL; *nid = NID_undef; } return ret; } static CK_RV ica_build_ec_edwards_montgomery_pub_ctx(OBJECT *key_obj, void **ed_x_ctx, int *nid) { CK_RV ret = CKR_OK; CK_ATTRIBUTE *attr; int rc; /* Prepare the ICA context */ ret = ica_prepare_ec_edwards_montgomery_ctx(key_obj, ed_x_ctx, nid); if (ret != CKR_OK) { TRACE_ERROR("ica_prepare_ec_edwards_montgomery_ctx() failed with " "rc = 0x%lx. \n", ret); return ret; } /* Get public key from template via CKA_EC_POINT */ ret = template_attribute_get_non_empty(key_obj->template, CKA_EC_POINT, &attr); if (ret != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); ret = CKR_TEMPLATE_INCOMPLETE; goto end; } /* Initialize Ed/X with public key (X, Y) */ rc = ica_ed_x_key_set(*nid, *ed_x_ctx, NULL, attr->pValue, attr->ulValueLen); if (rc != 0) { TRACE_ERROR("ica_ed_x_key_set() failed with rc = %d \n", rc); ret = CKR_FUNCTION_FAILED; goto end; } end: if (ret != CKR_OK) { ica_ed_x_ctx_del(*nid, ed_x_ctx); *ed_x_ctx = NULL; *nid = NID_undef; } return ret; } static CK_RV ica_check_ec_edwards_mech_param(OBJECT *key_obj, CK_MECHANISM *mech) { CK_EDDSA_PARAMS* eddsa_params = NULL; CK_ATTRIBUTE *attr; CK_RV ret; int nid; if (mech->ulParameterLen == sizeof(CK_EDDSA_PARAMS) && mech->pParameter != NULL) { eddsa_params = mech->pParameter; if (eddsa_params->ulContextDataLen != 0 || eddsa_params->pContextData != NULL) { TRACE_ERROR("ICA does not support a non-empty context\n"); return CKR_MECHANISM_PARAM_INVALID; } if (eddsa_params->phFlag) { TRACE_ERROR("ICA does not support pre-hash\n"); return CKR_MECHANISM_PARAM_INVALID; } } /* Get CKA_EC_PARAMS from template */ ret = template_attribute_get_non_empty(key_obj->template, CKA_EC_PARAMS, &attr); if (ret != CKR_OK) { 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; } switch (nid) { case NID_ED25519: break; case NID_ED448: if (eddsa_params == NULL) { TRACE_ERROR("Mechanism parameter is required for Ed448\n"); return CKR_MECHANISM_PARAM_INVALID; } break; default: TRACE_ERROR("Not an edwards curve.\n"); return CKR_CURVE_NOT_SUPPORTED; } return CKR_OK; } static CK_RV ica_specific_ec_edwards_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_MECHANISM *mech) { ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; ica_ex_data_t *ex_data = NULL; CK_RV ret = CKR_OK; int rc; UNUSED(sess); UNUSED(mech); if (!ica_data->ica_ec_edwards_support_available) { TRACE_ERROR("EC-Edwards support is not available in Libica\n"); return CKR_FUNCTION_NOT_SUPPORTED; } rc = openssl_get_ex_data(key_obj, (void **)&ex_data, sizeof(ica_ex_data_t), ica_need_wr_lock_ec_key, ica_free_ex_data); if (rc != CKR_OK) return rc; if (ex_data->ed_x_ctx == NULL) { /* Get the private key */ ret = ica_build_ec_edwards_montgomery_priv_ctx(key_obj, &ex_data->ed_x_ctx, &ex_data->ed_x_nid); if (ret != CKR_OK) { TRACE_ERROR("ica_build_ec_edwards_montgomery_priv_ctx() failed " "with rc = 0x%lx. \n", ret); goto end; } } /* Create signature */ rc = ica_eddsa_sign(ex_data->ed_x_nid, ex_data->ed_x_ctx, out_data, out_data_len, in_data, in_data_len); if (rc != 0) { switch (rc) { case ENODEV: TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); ret = CKR_FUNCTION_NOT_SUPPORTED; break; default: TRACE_ERROR("ica_eddsa_sign() failed with rc = %d. \n", rc); ret = CKR_FUNCTION_FAILED; break; } goto end; } ret = CKR_OK; end: object_ex_data_unlock(key_obj); return ret; } CK_RV token_specific_ec_edwards_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_MECHANISM *mech) { ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; CK_RV rc; rc = ica_check_ec_edwards_mech_param(key_obj, mech); if (rc != CKR_OK) return rc; if (ica_data->ica_ec_edwards_signverify_available) { rc = ica_specific_ec_edwards_sign(tokdata, sess, in_data, in_data_len, out_data, out_data_len, key_obj, mech); if (rc == CKR_FUNCTION_NOT_SUPPORTED) ica_data->ica_ec_edwards_signverify_available = FALSE; } if (!ica_data->ica_ec_edwards_signverify_available) rc = openssl_specific_ec_edwards_sign(tokdata, sess, in_data, in_data_len, out_data, out_data_len, key_obj, mech); return rc; } static CK_RV ica_specific_ec_edwards_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, CK_MECHANISM *mech) { ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; ica_ex_data_t *ex_data = NULL; CK_RV ret = CKR_OK; int rc; UNUSED(sess); UNUSED(mech); if (!ica_data->ica_ec_support_available) { TRACE_ERROR("ECC support is not available in Libica\n"); return CKR_FUNCTION_NOT_SUPPORTED; } rc = openssl_get_ex_data(key_obj, (void **)&ex_data, sizeof(ica_ex_data_t), ica_need_wr_lock_ec_key, ica_free_ex_data); if (rc != CKR_OK) return rc; if (ex_data->ed_x_ctx == NULL) { /* Get the public key */ ret = ica_build_ec_edwards_montgomery_pub_ctx(key_obj, &ex_data->ed_x_ctx, &ex_data->ed_x_nid); if (ret != CKR_OK) { TRACE_ERROR("ica_build_ec_edwards_montgomery_pub_ctx() failed with " "rc = 0x%lx. \n", ret); goto end; } } /* Verify signature */ rc = ica_eddsa_verify(ex_data->ed_x_nid, ex_data->ed_x_ctx, signature, signature_len, in_data, in_data_len); switch (rc) { case 0: ret = CKR_OK; break; case ENODEV: TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); ret = CKR_FUNCTION_NOT_SUPPORTED; break; default: TRACE_ERROR("ica_eddsa_verify() returned invalid signature, " "rc = %d. \n", rc); ret = CKR_SIGNATURE_INVALID; break; } end: object_ex_data_unlock(key_obj); return ret; } CK_RV token_specific_ec_edwards_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, CK_MECHANISM *mech) { ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; CK_RV rc; rc = ica_check_ec_edwards_mech_param(key_obj, mech); if (rc != CKR_OK) return rc; if (ica_data->ica_ec_edwards_signverify_available) { rc = ica_specific_ec_edwards_verify(tokdata, sess, in_data, in_data_len, signature, signature_len, key_obj, mech); if (rc == CKR_FUNCTION_NOT_SUPPORTED) ica_data->ica_ec_edwards_signverify_available = FALSE; } if (!ica_data->ica_ec_edwards_signverify_available) rc = openssl_specific_ec_edwards_verify(tokdata, sess, in_data, in_data_len, signature, signature_len, key_obj, mech); return rc; } static CK_RV ica_specific_montgomery_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, int nid) { ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; CK_RV ret = CKR_OK; void *ctx = NULL; int rc; UNUSED(tokdata); *secret_value_len = 0; if (!ica_data->ica_ec_montgomery_support_available) { TRACE_ERROR("EC-Montgomery support is not available in Libica\n"); return CKR_FUNCTION_NOT_SUPPORTED; } /* Create ICA object with private key */ rc = ica_ed_x_ctx_new(nid, &ctx); if (rc != 0) { TRACE_ERROR("ica_ed_x_ctx_new() failed for curve %i.\n", nid); return CKR_FUNCTION_FAILED; } rc = ica_ed_x_key_set(nid, ctx, priv_bytes, NULL, priv_length); if (rc != 0) { TRACE_ERROR("ica_ed_x_key_set() failed with rc = %d \n", rc); ret = CKR_FUNCTION_FAILED; goto end; } /* Calculate shared secret z */ rc = ica_x_derive(nid, ctx, secret_value, pub_bytes, pub_length); if (rc != 0) { switch (rc) { case ENODEV: TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); ret = CKR_FUNCTION_NOT_SUPPORTED; break; case EPERM: TRACE_ERROR("ica_x_derive() failed with rc=EPERM, probably curve " "not supported by openssl.\n"); ret = CKR_CURVE_NOT_SUPPORTED; break; default: TRACE_ERROR("ica_x_derive() failed with rc = %d. \n", rc); ret = CKR_FUNCTION_FAILED; break; } goto end; } *secret_value_len = priv_length; ret = CKR_OK; end: ica_ed_x_ctx_del(nid, &ctx); return ret; } static CK_RV ica_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 = NULL; CK_ULONG ecpoint_len; CK_BBOOL allocated = FALSE; /* 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; } switch (nid) { case NID_X25519: case NID_X448: return ica_specific_montgomery_ecdh_pkcs_derive(tokdata, priv_bytes, priv_length, pub_bytes, pub_length, secret_value, secret_value_len, nid); case NID_ED25519: case NID_ED448: return CKR_CURVE_NOT_SUPPORTED; default: break; } *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; } /* 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; } ret = ec_point_from_public_data(pub_bytes, pub_length, privlen, TRUE, &allocated, &ecpoint, &ecpoint_len); if (ret != CKR_OK) { TRACE_DEVEL("ec_point_from_public_data failed\n"); 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\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) { switch (rc) { case ENODEV: TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); ret = CKR_FUNCTION_NOT_SUPPORTED; break; case EPERM: TRACE_ERROR("ica_ecdh_derive_secret() failed with rc=EPERM, probably curve not supported by openssl.\n"); ret = CKR_CURVE_NOT_SUPPORTED; break; default: TRACE_ERROR("ica_ecdh_derive_secret() failed with rc = %d. \n", rc); ret = CKR_FUNCTION_FAILED; break; } goto end; } *secret_value_len = privlen; ret = CKR_OK; end: if (allocated && ecpoint != NULL) free(ecpoint); p_ica_ec_key_free(privkey); p_ica_ec_key_free(pubkey); 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, CK_BBOOL cofactor_mode) { ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; CK_RV rc = CKR_FUNCTION_FAILED; if (cofactor_mode) { TRACE_ERROR("ECDH with cofactor mode is not supported. \n"); return CKR_MECHANISM_INVALID; } if (ica_data->ica_ec_derive_available) { rc = ica_specific_ecdh_pkcs_derive(tokdata, priv_bytes, priv_length, pub_bytes, pub_length, secret_value, secret_value_len, oid, oid_length); if (rc == CKR_FUNCTION_NOT_SUPPORTED) ica_data->ica_ec_derive_available = FALSE; } if (!ica_data->ica_ec_derive_available) rc = openssl_specific_ecdh_pkcs_derive(tokdata, priv_bytes, priv_length, pub_bytes, pub_length, secret_value, secret_value_len, oid, oid_length, FALSE); return rc; } #endif CK_RV token_specific_object_add(STDLL_TokData_t *tokdata, SESSION *sess, OBJECT *obj) { ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; CK_ATTRIBUTE *value = NULL; CK_OBJECT_CLASS class; CK_KEY_TYPE keytype; #ifndef NO_EC ICA_EC_KEY *ica_eckey = NULL; unsigned int privlen; void *ctx = NULL; int nid = NID_undef; EVP_PKEY *ossl_eckey = NULL; #endif CK_RV rc; UNUSED(sess); #ifdef NO_EC UNUSED(ica_data); #endif rc = template_attribute_get_ulong(obj->template, CKA_CLASS, &class); if (rc != CKR_OK) return CKR_OK; rc = template_attribute_get_ulong(obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) return CKR_OK; switch (keytype) { #ifndef NO_EC case CKK_EC: if (ica_data->ica_ec_keygen_available) { /* Check if libica supports the curve */ switch (class) { case CKO_PRIVATE_KEY: rc = ica_build_ec_priv_key(obj, &ica_eckey, &privlen); if (ica_eckey != NULL) p_ica_ec_key_free(ica_eckey); return rc; case CKO_PUBLIC_KEY: rc = ica_build_ec_pub_key(obj, &ica_eckey, &privlen); if (ica_eckey != NULL) p_ica_ec_key_free(ica_eckey); return rc; default: return CKR_KEY_TYPE_INCONSISTENT; } } else { /* Check if OpenSSL supports the curve */ rc = openssl_make_ec_key_from_template(obj->template, &ossl_eckey); if (ossl_eckey != NULL) EVP_PKEY_free(ossl_eckey); return rc; } return CKR_OK; case CKK_EC_EDWARDS: case CKK_EC_MONTGOMERY: if ((keytype == CKK_EC_EDWARDS && ica_data->ica_ec_edwards_keygen_available) || (keytype == CKK_EC_MONTGOMERY && ica_data->ica_ec_montgomery_keygen_available)) { /* Check if libica supports Edwards/Montgomery */ switch (class) { case CKO_PRIVATE_KEY: rc = ica_build_ec_edwards_montgomery_priv_ctx(obj, &ctx, &nid); if (ctx != NULL) ica_ed_x_ctx_del(nid, &ctx); if (rc != CKR_OK) return rc; break; case CKO_PUBLIC_KEY: rc = ica_build_ec_edwards_montgomery_pub_ctx(obj, &ctx, &nid); if (ctx != NULL) ica_ed_x_ctx_del(nid, &ctx); if (rc != CKR_OK) return rc; break; default: return CKR_KEY_TYPE_INCONSISTENT; } switch (nid) { case NID_ED25519: case NID_ED448: if (keytype != CKK_EC_EDWARDS) { TRACE_ERROR("Edwards curve only supported with " "CKK_EC_EDWARDS key type.\n"); return CKR_CURVE_NOT_SUPPORTED; } break; case NID_X25519: case NID_X448: if (keytype != CKK_EC_MONTGOMERY) { TRACE_ERROR("Montgomery curve only supported with " "CKK_EC_MONTGOMERY key type.\n"); return CKR_CURVE_NOT_SUPPORTED; } break; default: return CKR_CURVE_NOT_SUPPORTED; } } else { /* Check if OpenSSL supports the curve */ rc = openssl_make_ec_key_from_template(obj->template, &ossl_eckey); if (ossl_eckey != NULL) EVP_PKEY_free(ossl_eckey); return rc; } return CKR_OK; #endif case CKK_AES_XTS: rc = template_attribute_get_non_empty(obj->template, CKA_VALUE, &value); if (rc != CKR_OK) { TRACE_ERROR("Failed to get CKA_VALUE\n"); return rc; } if (memcmp(value->pValue, ((CK_BYTE *)value->pValue) + value->ulValueLen / 2, value->ulValueLen / 2) == 0) { TRACE_ERROR("The 2 key parts of an AES-XTS key can not be the same\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } return CKR_OK; default: return CKR_OK; } } CK_RV token_specific_get_token_info(STDLL_TokData_t *tokdata, CK_TOKEN_INFO_PTR pInfo) { libica_version_info ver; int rc; UNUSED(tokdata); rc = ica_get_version(&ver); if (rc != 0) { TRACE_ERROR("ica_get_version failed with %i\n", rc); return CKR_FUNCTION_FAILED; } pInfo->firmwareVersion.major = ver.major_version; pInfo->firmwareVersion.minor = ver.minor_version; pInfo->hardwareVersion.major = pInfo->firmwareVersion.major; pInfo->hardwareVersion.minor = pInfo->firmwareVersion.minor; return CKR_OK; } opencryptoki-opencryptoki-451d99c/usr/lib/ica_s390_stdll/rsa_sup_mul.c000066400000000000000000000462111520105705100261200ustar00rootroot00000000000000/* * Copyright 2022-2023 The OpenSSL Project Authors. All Rights Reserved. * Copyright 2023 International Business Machines Corp. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html * * Copied from OpenSSL crypto/bn/rsa_sup_mul.c and modified to fit to * the OpenCrptoki environment. Note that in OpenSSL the file * crypto/bn/rsa_sup_mul.c does no longer exist, it was removed with commit * https://github.com/openssl/openssl/commit/4209ce68d8fe8b1506494efa03d378d05baf9ff8. * * Changes include: * - The intermediate message and the modulus are supplied as byte arrays * instead of BIGNUMs. The code has been adjusted to handle byte arrays as * input. * - Remove parameters 'BN_CTX ctx' and 'BN_BLINDING *blinding' since they are * not used. * - Includes have been adjusted to only include external OpenSSL headers. * - Remove access to internal fields of BN_BLINDING. * - Remove access to internal fields of BIGNUM. Function BN_to_limb() is * replaced by BN_bn2binpad(). Note that the only BIGNUM is containing the * unblinding factor. The message (and the modulus) are passed in in byte * arrays, and thus do not need to be converted. * - The ICA token only works on Linux on IBM Z, and it's big endian and 64 bit. */ #include #include #include #include #include #include #include #include "constant_time.h" #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-function" #define DECLARE_IS_ENDIAN #define IS_LITTLE_ENDIAN 0 #define IS_BIG_ENDIAN 1 # ifndef INT128_MAX # if defined(__SIZEOF_INT128__) && __SIZEOF_INT128__ == 16 typedef __int128_t int128_t; typedef __uint128_t uint128_t; # define INT128_MIN __MININT__(int128_t) # define INT128_MAX __MAXINT__(int128_t) # define UINT128_MAX __MAXUINT__(uint128_t) # endif # endif # if BN_BYTES == 8 typedef uint64_t limb_t; # if defined(__SIZEOF_INT128__) && __SIZEOF_INT128__ == 16 typedef uint128_t limb2_t; # define HAVE_LIMB2_T # endif # define LIMB_BIT_SIZE 64 # define LIMB_BYTE_SIZE 8 # else # error "Not supported" # endif static inline void memcpy_r_allign(void *dest, int dest_bs, const void *src, int src_bs, int size) { memcpy((unsigned char *)dest + (dest_bs - size), (unsigned char *)src + (src_bs - size), size); } /* * For multiplication we're using schoolbook multiplication, * so if we have two numbers, each with 6 "digits" (words) * the multiplication is calculated as follows: * A B C D E F * x I J K L M N * -------------- * N*F * N*E * N*D * N*C * N*B * N*A * M*F * M*E * M*D * M*C * M*B * M*A * L*F * L*E * L*D * L*C * L*B * L*A * K*F * K*E * K*D * K*C * K*B * K*A * J*F * J*E * J*D * J*C * J*B * J*A * I*F * I*E * I*D * I*C * I*B * + I*A * ========================== * N*B N*D N*F * + N*A N*C N*E * + M*B M*D M*F * + M*A M*C M*E * + L*B L*D L*F * + L*A L*C L*E * + K*B K*D K*F * + K*A K*C K*E * + J*B J*D J*F * + J*A J*C J*E * + I*B I*D I*F * + I*A I*C I*E * * 1+1 1+3 1+5 * 1+0 1+2 1+4 * 0+1 0+3 0+5 * 0+0 0+2 0+4 * * 0 1 2 3 4 5 6 * which requires n^2 multiplications and 2n full length additions * as we can keep every other result of limb multiplication in two separate * limbs */ #if defined HAVE_LIMB2_T static ossl_inline void _mul_limb(limb_t *hi, limb_t *lo, limb_t a, limb_t b) { limb2_t t; /* * this is idiomatic code to tell compiler to use the native mul * those three lines will actually compile to single instruction */ t = (limb2_t)a * b; *hi = t >> LIMB_BIT_SIZE; *lo = (limb_t)t; } #elif (BN_BYTES == 8) && (defined _MSC_VER) # if defined(_M_X64) /* * on x86_64 (x64) we can use the _umul128 intrinsic to get one `mul` * instruction to get both high and low 64 bits of the multiplication. * https://learn.microsoft.com/en-us/cpp/intrinsics/umul128?view=msvc-140 */ #include #pragma intrinsic(_umul128) static ossl_inline void _mul_limb(limb_t *hi, limb_t *lo, limb_t a, limb_t b) { *lo = _umul128(a, b, hi); } # elif defined(_M_ARM64) || defined (_M_IA64) /* * We can't use the __umulh() on x86_64 as then msvc generates two `mul` * instructions; so use this more portable intrinsic on platforms that * don't support _umul128 (like aarch64 (ARM64) or ia64) * https://learn.microsoft.com/en-us/cpp/intrinsics/umulh?view=msvc-140 */ #include static ossl_inline void _mul_limb(limb_t *hi, limb_t *lo, limb_t a, limb_t b) { *lo = a * b; *hi = __umulh(a, b); } # else # error Only x64, ARM64 and IA64 supported. # endif /* defined(_M_X64) */ #else /* * if the compiler doesn't have either a 128bit data type nor a "return * high 64 bits of multiplication" */ static ossl_inline void _mul_limb(limb_t *hi, limb_t *lo, limb_t a, limb_t b) { limb_t a_low = (limb_t)(uint32_t)a; limb_t a_hi = a >> 32; limb_t b_low = (limb_t)(uint32_t)b; limb_t b_hi = b >> 32; limb_t p0 = a_low * b_low; limb_t p1 = a_low * b_hi; limb_t p2 = a_hi * b_low; limb_t p3 = a_hi * b_hi; uint32_t cy = (uint32_t)(((p0 >> 32) + (uint32_t)p1 + (uint32_t)p2) >> 32); *lo = p0 + (p1 << 32) + (p2 << 32); *hi = p3 + (p1 >> 32) + (p2 >> 32) + cy; } #endif /* add two limbs with carry in, return carry out */ static ossl_inline limb_t _add_limb(limb_t *ret, limb_t a, limb_t b, limb_t carry) { limb_t carry1, carry2, t; /* * `c = a + b; if (c < a)` is idiomatic code that makes compilers * use add with carry on assembly level */ *ret = a + carry; if (*ret < a) carry1 = 1; else carry1 = 0; t = *ret; *ret = t + b; if (*ret < t) carry2 = 1; else carry2 = 0; return carry1 + carry2; } /* * add two numbers of the same size, return overflow * * add a to b, place result in ret; all arrays need to be n limbs long * return overflow from addition (0 or 1) */ static ossl_inline limb_t add(limb_t *ret, limb_t *a, limb_t *b, size_t n) { limb_t c = 0; ossl_ssize_t i; for(i = n - 1; i > -1; i--) c = _add_limb(&ret[i], a[i], b[i], c); return c; } /* * return number of limbs necessary for temporary values * when multiplying numbers n limbs large */ static ossl_inline size_t mul_limb_numb(size_t n) { return 2 * n * 2; } /* * multiply two numbers of the same size * * multiply a by b, place result in ret; a and b need to be n limbs long * ret needs to be 2*n limbs long, tmp needs to be mul_limb_numb(n) limbs * long */ static void limb_mul(limb_t *ret, limb_t *a, limb_t *b, size_t n, limb_t *tmp) { limb_t *r_odd, *r_even; size_t i, j, k; r_odd = tmp; r_even = &tmp[2 * n]; memset(ret, 0, 2 * n * sizeof(limb_t)); for (i = 0; i < n; i++) { for (k = 0; k < i + n + 1; k++) { r_even[k] = 0; r_odd[k] = 0; } for (j = 0; j < n; j++) { /* * place results from even and odd limbs in separate arrays so that * we don't have to calculate overflow every time we get individual * limb multiplication result */ if (j % 2 == 0) _mul_limb(&r_even[i + j], &r_even[i + j + 1], a[i], b[j]); else _mul_limb(&r_odd[i + j], &r_odd[i + j + 1], a[i], b[j]); } /* * skip the least significant limbs when adding multiples of * more significant limbs (they're zero anyway) */ add(ret, ret, r_even, n + i + 1); add(ret, ret, r_odd, n + i + 1); } } /* modifies the value in place by performing a right shift by one bit */ static ossl_inline void rshift1(limb_t *val, size_t n) { limb_t shift_in = 0, shift_out = 0; size_t i; for (i = 0; i < n; i++) { shift_out = val[i] & 1; val[i] = shift_in << (LIMB_BIT_SIZE - 1) | (val[i] >> 1); shift_in = shift_out; } } /* extend the LSB of flag to all bits of limb */ static ossl_inline limb_t mk_mask(limb_t flag) { flag |= flag << 1; flag |= flag << 2; flag |= flag << 4; flag |= flag << 8; flag |= flag << 16; #if (LIMB_BYTE_SIZE == 8) flag |= flag << 32; #endif return flag; } /* * copy from either a or b to ret based on flag * when flag == 0, then copies from b * when flag == 1, then copies from a */ static ossl_inline void cselect(limb_t flag, limb_t *ret, limb_t *a, limb_t *b, size_t n) { /* * would be more efficient with non volatile mask, but then gcc * generates code with jumps */ volatile limb_t mask; size_t i; mask = mk_mask(flag); for (i = 0; i < n; i++) { #if (LIMB_BYTE_SIZE == 8) ret[i] = constant_time_select_64(mask, a[i], b[i]); #else ret[i] = constant_time_select_32(mask, a[i], b[i]); #endif } } static limb_t _sub_limb(limb_t *ret, limb_t a, limb_t b, limb_t borrow) { limb_t borrow1, borrow2, t; /* * while it doesn't look constant-time, this is idiomatic code * to tell compilers to use the carry bit from subtraction */ *ret = a - borrow; if (*ret > a) borrow1 = 1; else borrow1 = 0; t = *ret; *ret = t - b; if (*ret > t) borrow2 = 1; else borrow2 = 0; return borrow1 + borrow2; } /* * place the result of a - b into ret, return the borrow bit. * All arrays need to be n limbs long */ static limb_t sub(limb_t *ret, limb_t *a, limb_t *b, size_t n) { limb_t borrow = 0; ossl_ssize_t i; for (i = n - 1; i > -1; i--) borrow = _sub_limb(&ret[i], a[i], b[i], borrow); return borrow; } /* return the number of limbs necessary to allocate for the mod() tmp operand */ static ossl_inline size_t mod_limb_numb(size_t anum, size_t modnum) { return (anum + modnum) * 3; } /* * calculate a % mod, place the result in ret * size of a is defined by anum, size of ret and mod is modnum, * size of tmp is returned by mod_limb_numb() */ static void mod(limb_t *ret, limb_t *a, size_t anum, limb_t *mod, size_t modnum, limb_t *tmp) { limb_t *atmp, *modtmp, *rettmp; limb_t res; size_t i; memset(tmp, 0, mod_limb_numb(anum, modnum) * LIMB_BYTE_SIZE); atmp = tmp; modtmp = &tmp[anum + modnum]; rettmp = &tmp[(anum + modnum) * 2]; for (i = modnum; i 0; i--, rp--) { v = _mul_add_limb(rp, mod, modnum, rp[modnum-1] * ni0, tmp2); v = v + carry + rp[-1]; carry |= (v != rp[-1]); carry &= (v <= rp[-1]); rp[-1] = v; } /* perform the final reduction by mod... */ carry -= sub(ret, rp, mod, modnum); /* ...conditionally */ cselect(carry, ret, rp, ret, modnum); } #if LIMB_BYTE_SIZE == 8 static ossl_inline uint64_t be64(uint64_t host) { uint64_t big = 0; DECLARE_IS_ENDIAN; if (!IS_LITTLE_ENDIAN) return host; big |= (host & 0xff00000000000000) >> 56; big |= (host & 0x00ff000000000000) >> 40; big |= (host & 0x0000ff0000000000) >> 24; big |= (host & 0x000000ff00000000) >> 8; big |= (host & 0x00000000ff000000) << 8; big |= (host & 0x0000000000ff0000) << 24; big |= (host & 0x000000000000ff00) << 40; big |= (host & 0x00000000000000ff) << 56; return big; } #else /* Not all platforms have htobe32(). */ static ossl_inline uint32_t be32(uint32_t host) { uint32_t big = 0; DECLARE_IS_ENDIAN; if (!IS_LITTLE_ENDIAN) return host; big |= (host & 0xff000000) >> 24; big |= (host & 0x00ff0000) >> 8; big |= (host & 0x0000ff00) << 8; big |= (host & 0x000000ff) << 24; return big; } #endif /* * We assume that intermediate and unblind are used similar to * BN_BLINDING_invert_ex() arguments. * to_mod is RSA modulus. * buf and num is the serialization buffer and its length. * num is always the RSA modulus size. * * Here we use classic/Montgomery multiplication and modulo. After the calculation finished * we serialize the new structure instead of BIGNUMs taking endianness into account. */ int ossl_bn_rsa_do_unblind(const unsigned char *intermediate, const BIGNUM *unblind, const unsigned char *to_mod, unsigned char *buf, int num, BN_MONT_CTX *m_ctx, BN_ULONG n0) { limb_t *l_im = NULL, *l_mul = NULL, *l_mod = NULL; limb_t *l_ret = NULL, *l_tmp = NULL, l_buf; size_t l_im_count = 0, l_mul_count = 0, l_size = 0, l_mod_count = 0; size_t l_tmp_count = 0; int ret = 0; size_t i; unsigned char *tmp; l_im_count = (num + LIMB_BYTE_SIZE - 1) / LIMB_BYTE_SIZE; l_mul_count = (BN_num_bytes(unblind) + LIMB_BYTE_SIZE - 1) / LIMB_BYTE_SIZE; l_mod_count = (num + LIMB_BYTE_SIZE - 1) / LIMB_BYTE_SIZE; l_size = l_im_count > l_mul_count ? l_im_count : l_mul_count; if (l_size * LIMB_BYTE_SIZE == (size_t)num) l_im = (limb_t *)intermediate; else l_im = OPENSSL_zalloc(l_size * LIMB_BYTE_SIZE); l_mul = OPENSSL_zalloc(l_size * LIMB_BYTE_SIZE); if (l_mod_count * LIMB_BYTE_SIZE == (size_t)num) l_mod = (limb_t *)to_mod; else l_mod = OPENSSL_zalloc(l_mod_count * LIMB_BYTE_SIZE); if ((l_im == NULL) || (l_mul == NULL) || (l_mod == NULL)) goto err; if (l_im != (limb_t *)intermediate) memcpy_r_allign(l_im, l_size * LIMB_BYTE_SIZE, intermediate, num, num); BN_bn2binpad(unblind, (unsigned char *)l_mul, l_size * LIMB_BYTE_SIZE); if (l_mod != (limb_t *)to_mod) memcpy_r_allign(l_mod, l_mod_count * LIMB_BYTE_SIZE, to_mod, num, num); l_ret = OPENSSL_malloc(2 * l_size * LIMB_BYTE_SIZE); if (m_ctx != NULL) { l_tmp_count = mul_limb_numb(l_size) > mod_montgomery_limb_numb(l_mod_count) ? mul_limb_numb(l_size) : mod_montgomery_limb_numb(l_mod_count); l_tmp = OPENSSL_malloc(l_tmp_count * LIMB_BYTE_SIZE); } else { l_tmp_count = mul_limb_numb(l_size) > mod_limb_numb(2 * l_size, l_mod_count) ? mul_limb_numb(l_size) : mod_limb_numb(2 * l_size, l_mod_count); l_tmp = OPENSSL_malloc(l_tmp_count * LIMB_BYTE_SIZE); } if ((l_ret == NULL) || (l_tmp == NULL)) goto err; if (m_ctx != NULL) { limb_mul(l_ret, l_im, l_mul, l_size, l_tmp); mod_montgomery(l_ret, l_ret, 2 * l_size, l_mod, l_mod_count, n0, l_tmp); } else { limb_mul(l_ret, l_im, l_mul, l_size, l_tmp); mod(l_ret, l_ret, 2 * l_size, l_mod, l_mod_count, l_tmp); } memset(buf, 0, num); tmp = buf; for (i = 0; i < l_mod_count; i++) { #if LIMB_BYTE_SIZE == 8 l_buf = be64(l_ret[i]); #else l_buf = be32(l_ret[i]); #endif if (i == 0) { int delta = LIMB_BYTE_SIZE - ((l_mod_count * LIMB_BYTE_SIZE) - num); memcpy(tmp, ((char *)&l_buf) + LIMB_BYTE_SIZE - delta, delta); tmp += delta; } else { memcpy(tmp, &l_buf, LIMB_BYTE_SIZE); tmp += LIMB_BYTE_SIZE; } } ret = num; err: if (l_im != (limb_t *)intermediate) OPENSSL_free(l_im); OPENSSL_free(l_mul); if (l_mod != (limb_t *)to_mod) OPENSSL_free(l_mod); OPENSSL_free(l_tmp); OPENSSL_free(l_ret); return ret; } #pragma GCC diagnostic pop opencryptoki-opencryptoki-451d99c/usr/lib/ica_s390_stdll/tok_struct.h000066400000000000000000000140021520105705100257660ustar00rootroot00000000000000/* * 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", FALSE, // 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_get_token_info, &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_edwards_sign, &token_specific_ec_edwards_verify, &token_specific_ec_generate_keypair, &token_specific_ec_edwards_generate_keypair, &token_specific_ec_montgomery_generate_keypair, &token_specific_ecdh_pkcs_derive, NULL, // ecdh_derive_kdf #else NULL, NULL, NULL, NULL, NULL, 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, // SHAKE derive &token_specific_shake_key_derive, //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 &token_specific_aes_key_gen, &token_specific_aes_xts_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, &token_specific_aes_xts, NULL, // aes_key_wrap // DSA NULL, // dsa_generate_keypair NULL, // dsa_sign NULL, // dsa_verify // PQC NULL, // ibm_ml_dsa_generate_keypair NULL, // ibm_ml_dsa_sign NULL, // ibm_ml_dsa_verify NULL, // ibm_ml_kem_generate_keypair NULL, // ibm_ml_kem_derive NULL, // ml_dsa_generate_keypair NULL, // ml_dsa_sign NULL, // ml_dsa_verify NULL, // ml_kem_generate_keypair NULL, // ml_kem_encapsulate_key NULL, // ml_kem_decapsulate_key &token_specific_get_mechanism_list, &token_specific_get_mechanism_info, &token_specific_object_add, NULL, // key_wrap NULL, // key_unwrap NULL, // encapsulate_rsa_sym_keygen NULL, // encapsulate_rsa_key_wrap NULL, // encapsulate_rsa_key_unwrap NULL, // encapsulate_dh_ecdh_key_pair_gen NULL, // en_decapsulate_dh_ecdh_derive_key NULL, // reencrypt_single NULL, // set_attribute_values NULL, // set_attrs_for_new_object NULL, // handle_event NULL, // check_obj_access }; #endif opencryptoki-opencryptoki-451d99c/usr/lib/icsf_stdll/000077500000000000000000000000001520105705100230315ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/usr/lib/icsf_stdll/icsf.c000066400000000000000000003311701520105705100241260ustar00rootroot00000000000000/* * 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) * */ #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) 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 rc; } 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 rc; } } 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 rc; } 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 rc; } 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 rc; } } 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 rc; } } 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 rc; } } 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 rc; } } 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 rc; } rc = icsf_force_ldap_v3(*ld); if (rc != 0) return rc; /* Initialize TLS */ rc = icsf_set_sasl_params(*ld, cert, key, ca, ca_dir); if (rc != 0) return rc; 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 rc; } 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: %zu\n", handle_len); return -1; } if ((rule_array_len % ICSF_RULE_ITEM_LEN)) { TRACE_ERROR("Invalid rule array length: %zu\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_HW_FEATURE_TYPE: case CKA_KEY_GEN_MECHANISM: case CKA_VALUE_LEN: case CKA_VALUE_BITS: case CKA_MODULUS_BITS: case CKA_PRIME_BITS: case CKA_SUBPRIME_BITS: case CKA_CERTIFICATE_CATEGORY: case CKA_JAVA_MIDP_SECURITY_DOMAIN: return 1; } return 0; } static CK_RV find_ulong_attribute(CK_ATTRIBUTE *attrs, CK_ULONG attrs_len, CK_ATTRIBUTE_TYPE type, CK_ULONG *value) { CK_ULONG i; for (i = 0; i < attrs_len; i++) { if (attrs[i].type == type) { /* Check size */ if (attrs[i].ulValueLen != sizeof(*value) || attrs[i].pValue == NULL) return CKR_ATTRIBUTE_VALUE_INVALID; /* Get value */ *value = *((CK_ULONG *) attrs[i].pValue); } } return CKR_FUNCTION_FAILED; } /* * 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; CK_OBJECT_CLASS class = CK_UNAVAILABLE_INFORMATION; find_ulong_attribute(attrs, attrs_len, CKA_CLASS, &class); for (i = 0; i < attrs_len; i++) { /* Filter attributes not supported by ICSF */ switch (class) { case CKO_CERTIFICATE: switch (attrs[i].type) { case CKA_START_DATE: case CKA_END_DATE: case CKA_PUBLIC_KEY_INFO: case CKA_CHECK_VALUE: case CKA_NAME_HASH_ALGORITHM: case CKA_HASH_OF_SUBJECT_PUBLIC_KEY: continue; /* ignore this attribute */ default: break; } break; default: break; } if (!is_numeric_attr(attrs[i].type)) { /* Non numeric attributes are encode as octet strings */ if (attrs[i].type & CKA_VENDOR_DEFINED) continue; if (ber_printf(ber, "{ito}", attrs[i].type, 0 | LBER_CLASS_CONTEXT, attrs[i].pValue ? attrs[i].pValue : "", attrs[i].ulValueLen) < 0) { goto encode_error; } } else { long value; unsigned long mask = 0; /* `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. */ if (attrs[i].ulValueLen < sizeof(long)) 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) || mech->pParameter == NULL) { TRACE_ERROR("Invalid mechanism parameter NULL or 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_SHA224_HMAC: return "SHA-224"; case CKM_SHA256_HMAC: return "SHA-256"; case CKM_SHA384_HMAC: return "SHA-384"; case CKM_SHA512_HMAC: return "SHA-512"; case CKM_SHA3_224_HMAC: return "SHA3-224"; case CKM_SHA3_256_HMAC: return "SHA3-256"; case CKM_SHA3_384_HMAC: return "SHA3-384"; case CKM_SHA3_512_HMAC: return "SHA3-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_SHA224_RSA_PKCS: if (arg) return "SHA-224 VER-RSA"; else return "SHA-224 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_ECDSA_SHA224: if (arg) return "SHA-224 VER-EC"; else return "SHA-224 SIGN-EC"; case CKM_ECDSA_SHA256: if (arg) return "SHA-256 VER-EC"; else return "SHA-256 SIGN-EC"; case CKM_ECDSA_SHA384: if (arg) return "SHA-384 VER-EC"; else return "SHA-384 SIGN-EC"; case CKM_ECDSA_SHA512: if (arg) return "SHA-512 VER-EC"; else return "SHA-512 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, size_t *p_block_size) { size_t 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_SHA224_RSA_PKCS: case CKM_SHA256_RSA_PKCS: case CKM_DSA_SHA1: case CKM_ECDSA_SHA1: case CKM_ECDSA_SHA224: case CKM_ECDSA_SHA256: block_size = SHA1_BLOCK_SIZE; break; case CKM_SHA384_RSA_PKCS: case CKM_SHA512_RSA_PKCS: case CKM_ECDSA_SHA384: case CKM_ECDSA_SHA512: 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 || mech->pParameter == NULL) { TRACE_ERROR("Invalid mechanism parameter NULL or 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 = (size_t)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 *reason) { int attrtype; struct berval attrbval = { 0, NULL }; ber_int_t intval; unsigned int i; CK_ULONG found = 0; ber_tag_t tag; int rc = 0; CK_BBOOL *attr_set = NULL; attr_set = calloc(attrs_len, sizeof(CK_BBOOL)); if (attr_set == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); goto decode_error; } 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 = 8; *reason = 3003; /* CKR_BUFFER_TOO_SMALL */ attrs[i].ulValueLen = CK_UNAVAILABLE_INFORMATION; goto decode_error; } attr_set[i] = TRUE; /* keep count of how many are found. */ found++; } if (attrbval.bv_val != NULL) ber_memfree(attrbval.bv_val); attrbval.bv_val = NULL; /* 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 = 8; *reason = 3029; /* CKR_ATTRIBUTE_TYPE_INVALID */ /* Update those attributes that have not been found */ for (i = 0; i < attrs_len; i++) { if (attr_set[i] == FALSE) attrs[i].ulValueLen = CK_UNAVAILABLE_INFORMATION; } } free(attr_set); return rc; decode_error: TRACE_ERROR("Failed to decode message.\n"); if (attrbval.bv_val != NULL) ber_memfree(attrbval.bv_val); if (attr_set != NULL) free(attr_set); if (rc == 0) { rc = 8; *reason = 0; /* CKR_FUNCTION_FAILED */ } return rc; } int icsf_get_attribute(LDAP * ld, int *reason, BerElement **cached_result, struct icsf_object_record *object, CK_ATTRIBUTE * attrs, CK_ULONG attrs_len) { char handle[ICSF_HANDLE_LEN]; BerElement *msg = NULL; BerElement *result = NULL; int rc = 0, allocated = 0; CHECK_ARG_NON_NULL(ld); CHECK_ARG_NON_NULL(attrs); CHECK_ARG_NON_NULL(object); if (cached_result == NULL || *cached_result == NULL) { 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; } if (cached_result != NULL) { *cached_result = ber_dup(result); if (*cached_result == NULL) { TRACE_ERROR("ber_dup failed.\n"); goto cleanup; } allocated = 1; } } else { result = ber_dup(*cached_result); if (result == NULL) { TRACE_DEVEL("ber_dup failed.\n"); goto cleanup; } } /* 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, reason); if (rc < 0) { TRACE_ERROR("Failed to decode message.\n"); goto cleanup; } cleanup: if (msg) ber_free(msg, 1); if (result) ber_free(result, cached_result == NULL ? 1 : 0); if (rc != 0 && allocated && cached_result != NULL && *cached_result != NULL) { ber_free(*cached_result, 1); *cached_result = NULL; } 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; ber_int_t iv_len = 0; char *iv = ""; 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; } iv = mech->pParameter; iv_len = mech->ulParameterLen; 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, "oio", wrapping_handle, sizeof(wrapping_handle), wrapped_key != NULL ? (ber_int_t)*p_wrapped_key_len : USHRT_MAX, iv, iv_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_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; ber_int_t iv_len = 0; char *iv = ""; 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; } iv = mech->pParameter; iv_len = mech->ulParameterLen; 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, "oo", wrapped_key, wrapped_key_len, iv, iv_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 (sig == NULL && sig_len != NULL) *sig_len = 0; 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 != NULL && *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 && sig != NULL) 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}; CK_ECDH1_DERIVE_PARAMS *ecdh_params = NULL; struct berval kdfCode = { 0, NULL }; struct berval sharedData = { 0, NULL }; CK_BYTE kdf = 0; 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; case CKM_ECDH1_DERIVE: strpad(rule_array, "EC-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_DVKInputParmsList ::= SEQUENCE { * kdfCode OCTET STRING, * sharedData OCTET STRING, * EC-DH_publicValue 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) { 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; case CKM_ECDH1_DERIVE: ecdh_params = (CK_ECDH1_DERIVE_PARAMS *)mech->pParameter; kdf = ecdh_params->kdf; kdfCode.bv_val = (char *)&kdf; kdfCode.bv_len = sizeof(kdf); sharedData.bv_val = (char *)ecdh_params->pSharedData; sharedData.bv_len = ecdh_params->ulSharedDataLen; publicValue.bv_val = (char *)ecdh_params->pPublicData; publicValue.bv_len = ecdh_params->ulPublicDataLen; if (ber_printf(msg, "t{OOO}", 2 | LBER_CLASS_CONTEXT | LBER_CONSTRUCTED, &kdfCode, &sharedData, &publicValue) < 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]; ber_memfree(bvParam.bv_val); } } 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; } opencryptoki-opencryptoki-451d99c/usr/lib/icsf_stdll/icsf.h000066400000000000000000000240361520105705100241330ustar00rootroot00000000000000/* * 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 100 /* 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, size_t *p_block_size); int icsf_get_attribute(LDAP * ld, int *reason, BerElement **cached_result, 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 opencryptoki-opencryptoki-451d99c/usr/lib/icsf_stdll/icsf_config.h000066400000000000000000000020661520105705100254570ustar00rootroot00000000000000/* * 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; }; static CK_RV parse_config_file(const char *conf_name, CK_SLOT_ID slot_id, struct icsf_config *data); #endif opencryptoki-opencryptoki-451d99c/usr/lib/icsf_stdll/icsf_specific.c000066400000000000000000005574141520105705100260060ustar00rootroot00000000000000/* * 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. * */ #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" #include "../api/policy.h" #include "cfgparser.h" #include "configuration.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_SHA224_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_SHA224, {0, 0, CKF_HW | CKF_DIGEST}}, {CKM_SHA224_HMAC, {0, 0, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {CKM_SHA256, {0, 0, CKF_HW | CKF_DIGEST}}, {CKM_SHA256_HMAC, {0, 0, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {CKM_SHA384, {0, 0, CKF_HW | CKF_DIGEST}}, {CKM_SHA384_HMAC, {0, 0, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {CKM_SHA512, {0, 0, CKF_HW | CKF_DIGEST}}, {CKM_SHA512_HMAC, {0, 0, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {CKM_SHA3_224, {0, 0, CKF_HW | CKF_DIGEST}}, /* {CKM_SHA3_224_HMAC, {0, 0, CKF_HW | CKF_SIGN | CKF_VERIFY}}, */ {CKM_SHA3_256, {0, 0, CKF_HW | CKF_DIGEST}}, /* {CKM_SHA3_256_HMAC, {0, 0, CKF_HW | CKF_SIGN | CKF_VERIFY}}, */ {CKM_SHA3_384, {0, 0, CKF_HW | CKF_DIGEST}}, /* {CKM_SHA3_384_HMAC, {0, 0, CKF_HW | CKF_SIGN | CKF_VERIFY}}, */ {CKM_SHA3_512, {0, 0, CKF_HW | CKF_DIGEST}}, /* {CKM_SHA3_512_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_OID | CKF_EC_UNCOMPRESS}}, {CKM_ECDSA_SHA224, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY | CKF_EC_F_P | CKF_EC_OID | CKF_EC_UNCOMPRESS}}, {CKM_ECDSA_SHA256, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY | CKF_EC_F_P | CKF_EC_OID | CKF_EC_UNCOMPRESS}}, {CKM_ECDSA_SHA384, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY | CKF_EC_F_P | CKF_EC_OID | CKF_EC_UNCOMPRESS}}, {CKM_ECDSA_SHA512, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY | CKF_EC_F_P | CKF_EC_OID | CKF_EC_UNCOMPRESS}}, {CKM_ECDSA, {160, 521, CKF_HW | CKF_SIGN | CKF_VERIFY | CKF_EC_F_P | CKF_EC_OID | CKF_EC_UNCOMPRESS}}, {CKM_EC_KEY_PAIR_GEN, {160, 521, CKF_HW | CKF_GENERATE_KEY_PAIR | CKF_EC_F_P | CKF_EC_OID | CKF_EC_UNCOMPRESS}}, {CKM_ECDH1_DERIVE, {160, 521, CKF_HW | CKF_DERIVE | CKF_EC_OID | CKF_EC_F_P | 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_PRE_MASTER_KEY_GEN, {48, 48, CKF_HW | CKF_GENERATE}}, {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; struct objstrength strength; }; /* * 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; }; struct icsf_policy_attr { LDAP *ld; struct icsf_object_record *icsf_object; unsigned int attr_count; BerElement *get_attrs_result; }; int icsf_to_ock_err(int icsf_return_code, int icsf_reason_code); static CK_RV icsf_policy_get_attr(void *data, CK_ATTRIBUTE_TYPE type, CK_ATTRIBUTE **attr) { CK_RV rc; int reason; struct icsf_policy_attr *d = data; CK_ATTRIBUTE *a; CK_ATTRIBUTE s = { .type = type, .ulValueLen = 0, .pValue = NULL }; rc = icsf_get_attribute(d->ld, &reason, &d->get_attrs_result, d->icsf_object, &s, 1); if (rc != CKR_OK) { TRACE_DEVEL("icsf_get_attribute failed\n"); rc = icsf_to_ock_err(rc, reason); goto done; } if (s.ulValueLen == CK_UNAVAILABLE_INFORMATION) { TRACE_DEVEL("Size information for attribute 0x%lx not available\n", type); rc = CKR_FUNCTION_FAILED; goto done; } a = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + s.ulValueLen); if (!a) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto done; } a->type = type; a->ulValueLen = s.ulValueLen; a->pValue = (CK_BYTE *) a + sizeof(CK_ATTRIBUTE); rc = icsf_get_attribute(d->ld, &reason, &d->get_attrs_result, d->icsf_object, a, 1); if (rc != CKR_OK) { TRACE_DEVEL("icsf_get_attribute failed\n"); free(a); rc = icsf_to_ock_err(rc, reason); goto done; } *attr = a; d->attr_count++; done: if (d->attr_count == 0 && d->get_attrs_result != NULL) { ber_free(d->get_attrs_result, 1); d->get_attrs_result = NULL; } return rc; } static void icsf_policy_free_attr(void *data, CK_ATTRIBUTE *attr) { struct icsf_policy_attr *d = data; free(attr); if (d->attr_count > 0) { d->attr_count--; if (d->attr_count == 0 && d->get_attrs_result != NULL) { ber_free(d->get_attrs_result, 1); d->get_attrs_result = NULL; } } } /* * 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 3009: return CKR_TEMPLATE_INCONSISTENT; 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; } rc = ock_generic_filter_mechanism_list(tokdata, icsf_mech_list, icsf_mech_list_len, &(tokdata->mech_list), &(tokdata->mech_list_len)); if (rc != CKR_OK) { TRACE_ERROR("Mechanism filtering failed! rc = 0x%lx\n", rc); return rc; } icsf_data = calloc(1, sizeof(icsf_private_data_t)); if (icsf_data == NULL) return CKR_HOST_MEMORY; list_init(&icsf_data->sessions); if (pthread_mutex_init(&icsf_data->sess_list_mutex, NULL) != 0) { TRACE_ERROR("Initializing session list lock failed.\n"); free(icsf_data); return CKR_CANT_LOCK; } if (bt_init(&icsf_data->objects, free) != CKR_OK) { TRACE_ERROR("BTree init failed.\n"); pthread_mutex_destroy(&icsf_data->sess_list_mutex); free(icsf_data); return CKR_FUNCTION_FAILED; } tokdata->private_data = icsf_data; rc = XProcLock(tokdata); 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; } static void config_parse_error(int line, int col, const char *msg) { TRACE_ERROR("Error parsing config file: line %d column %d: %s\n", line, col, msg); } static struct icsf_config out_config; static char out_str_mech[64] = ""; struct ref { char *key; char *addr; size_t len; int required; }; static 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 }, }; static const size_t refs_len = sizeof(refs)/sizeof(*refs); 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; } static CK_RV config_parse_slot(const char *config_file, struct ConfigIdxStructNode *slot) { struct ConfigBaseNode *c; int i; size_t k; char *str; TRACE_DEVEL("Slot: %lu\n", slot->idx); confignode_foreach(c, slot->value, i) { TRACE_DEVEL("Config node: '%s' type: %u line: %u\n", c->key, c->type, c->line); str = confignode_getstr(c); if (str != NULL) { for (k = 0; k < refs_len; k++) { if (!strcasecmp(refs[k].key, c->key)) { strncpy(refs[k].addr, str, refs[k].len); refs[k].addr[refs[k].len - 1] = '\0'; goto found; } } TRACE_ERROR("Error parsing config file '%s': unexpected token '%s' " "at line %d: \n", config_file, c->key, c->line); return CKR_FUNCTION_FAILED; found: continue; } TRACE_ERROR("Error parsing config file '%s': unexpected token '%s' " "at line %d: \n", config_file, c->key, c->line); return CKR_FUNCTION_FAILED; } return CKR_OK; } static CK_RV parse_config_file(const char *conf_name, CK_SLOT_ID slot_id, struct icsf_config *data) { FILE *file; struct ConfigBaseNode *c, *config = NULL; struct ConfigIdxStructNode *slot; CK_RV ret = CKR_OK; int i; file = fopen(conf_name, "r"); if (file == NULL) { TRACE_ERROR("Error opening config file '%s': %s\n", conf_name, strerror(errno)); return CKR_FUNCTION_FAILED; } ret = parse_configlib_file(file, &config, config_parse_error, 0); fclose(file); if (ret != 0) { TRACE_ERROR("Error parsing config file '%s'\n", conf_name); ret = CKR_FUNCTION_FAILED; goto done; } confignode_foreach(c, config, i) { TRACE_DEVEL("Config node: '%s' type: %u line: %u\n", c->key, c->type, c->line); if (confignode_hastype(c, CT_IDX_STRUCT)) { slot = confignode_to_idxstruct(c); if (strcmp(slot->base.key, "slot") == 0 && slot->idx == slot_id) { ret = config_parse_slot(conf_name, slot); if (ret != 0) break; continue; } TRACE_ERROR("Error parsing config file '%s': unexpected token '%s' " "at line %d: \n", conf_name, c->key, c->line); ret = -1; break; } TRACE_ERROR("Error parsing config file '%s': unexpected token '%s' " "at line %d: \n", conf_name, c->key, c->line); ret = CKR_FUNCTION_FAILED; break; } if (ret != CKR_OK) goto done; if (check_keys(conf_name)) { ret = CKR_FUNCTION_FAILED; goto done; } /* 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); ret = CKR_FUNCTION_FAILED; goto done; } /* 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 done: confignode_deepfree(config); return ret; } 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) != 1) { 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[PATH_MAX]; if (slot_id >= NUMBER_SLOTS_MANAGED) { TRACE_ERROR("Invalid slot ID: %lu\n", slot_id); return CKR_FUNCTION_FAILED; } if (get_pk_dir(tokdata, shm_id, PATH_MAX) == NULL) { TRACE_ERROR("pk_dir buffer overflow"); return CKR_FUNCTION_FAILED; } 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, 0660, (void **) &ptr, len, 1, tokdata->tokgroup); 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); 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"); return rc; } /* 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; XProcUnLock(tokdata); return rc; } memcpy(&data, slot_data[slot_id], sizeof(data)); rc = XProcUnLock(tokdata); if (rc != CKR_OK) { TRACE_ERROR("Failed to release process lock.\n"); return rc; } 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 fname[PATH_MAX]; /* Load master key */ if (get_pk_dir(tokdata, fname, PATH_MAX) == NULL) { TRACE_ERROR("pk_dir buffer overflow\n"); return CKR_FUNCTION_FAILED; } if (PATH_MAX - strlen(fname) > strlen("/MK_SO")) { strcat(fname, "/MK_SO"); } else { TRACE_ERROR("MK_SO buffer overflow\n"); return CKR_FUNCTION_FAILED; } if (get_masterkey(tokdata, 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(tokdata, 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) { if (get_pk_dir(tokdata, pk_dir_buf, PATH_MAX) == NULL) { TRACE_ERROR("pk_dir_buf overflow\n"); return CKR_FUNCTION_FAILED; } if (ock_snprintf(fname, PATH_MAX, "%s/MK_USER", pk_dir_buf) != 0) { TRACE_ERROR("MK_USER filename buffer overflow\n"); return CKR_FUNCTION_FAILED; } if (unlink(fname) && errno == ENOENT) TRACE_WARNING("Failed to remove \"%s\".\n", fname); /* Load master key */ if (ock_snprintf(fname, PATH_MAX, "%s/MK_SO", pk_dir_buf) != 0) { TRACE_ERROR("MK_SO filename buffer overflow\n"); return CKR_FUNCTION_FAILED; } if (get_masterkey(tokdata, 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(tokdata, 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; } if ((tokdata->statistics->flags & STATISTICS_FLAG_COUNT_INTERNAL) != 0) tokdata->statistics->increment_func(tokdata->statistics, tokdata->slot_id, &tokdata->store_strength.mk_keygen, tokdata->store_strength.mk_strength); /* Save racf password using the new master key */ if (secure_racf(tokdata, racf_pass, racf_pass_len, mk, mk_len, tokdata->data_store)) { 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; tokdata->nv_token_data->token_info.flags &= ~(CKF_USER_PIN_INITIALIZED | CKF_USER_PIN_LOCKED | CKF_USER_PIN_FINAL_TRY | CKF_USER_PIN_COUNT_LOW); if (slot_data[slot_id]->mech == ICSF_CFG_MECH_SIMPLE) { /* Save master key */ if (secure_masterkey(tokdata, 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 (rc != CKR_OK) goto done; 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) { if (get_pk_dir(tokdata, pk_dir_buf, PATH_MAX) == NULL) { TRACE_ERROR("pk_dir_buf overflow\n"); return CKR_FUNCTION_FAILED; } if (ock_snprintf(fname, PATH_MAX, "%s/MK_USER", pk_dir_buf) != 0) { TRACE_ERROR("MK_USER filename buffer overflow\n"); return CKR_FUNCTION_FAILED; } rc = secure_masterkey(tokdata, 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]; /* 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) { if (get_pk_dir(tokdata, fname, PATH_MAX) == NULL) { TRACE_ERROR("pk_dir buffer overflow\n"); return CKR_FUNCTION_FAILED; } if (PATH_MAX - strlen(fname) > strlen("/MK_USER")) { strcat(fname, "/MK_USER"); } else { TRACE_ERROR("MK_USER buffer overflow\n"); return CKR_FUNCTION_FAILED; } rc = secure_masterkey(tokdata, 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 */ if (get_pk_dir(tokdata, fname, PATH_MAX) == NULL) { TRACE_ERROR("pk_dir buffer overflow\n"); return CKR_FUNCTION_FAILED; } if (PATH_MAX - strlen(fname) > strlen("/MK_SO")) { strcat(fname, "/MK_SO"); } else { TRACE_ERROR("MK_SO buffer overflow\n"); return CKR_FUNCTION_FAILED; } rc = secure_masterkey(tokdata, 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); rc = 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, 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 != 0) { 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 != 0) { 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; } if (pthread_mutex_lock(&icsf_data->sess_list_mutex)) { TRACE_ERROR("Failed to lock mutex.\n"); return CKR_FUNCTION_FAILED; } /* 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); if (pthread_mutex_unlock(&icsf_data->sess_list_mutex)) { TRACE_ERROR("Mutex Unlock Failed.\n"); rc = CKR_FUNCTION_FAILED; } 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; free(tokdata->mech_list); } 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; 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) { if (get_pk_dir(tokdata, fname, PATH_MAX) == NULL) { TRACE_ERROR("pk_dir buffer overflow\n"); rc = CKR_FUNCTION_FAILED; goto done; } if (PATH_MAX - strlen(fname) > strlen("/MK_USER")) { strcat(fname, "/MK_USER"); } else { TRACE_ERROR("MK_USER buffer overflow\n"); rc = CKR_FUNCTION_FAILED; goto done; } rc = get_masterkey(tokdata, 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 */ if (get_pk_dir(tokdata, fname, PATH_MAX) == NULL) { TRACE_ERROR("pk_dir buffer overflow\n"); rc = CKR_FUNCTION_FAILED; goto done; } if (PATH_MAX - strlen(fname) > strlen("/MK_SO")) { strcat(fname, "/MK_SO"); } else { TRACE_ERROR("MK_SO buffer overflow\n"); rc = CKR_FUNCTION_FAILED; goto done; } rc = get_masterkey(tokdata, 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, NULL, &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; } memcpy(&mapping_dst->strength, &mapping_src->strength, sizeof(struct objstrength)); /* 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; struct icsf_policy_attr pattr = { 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; } /* Policy check */ pattr.ld = session_state->ld; pattr.icsf_object = &mapping->icsf_object; rc = tokdata->policy->store_object_strength(tokdata->policy, &mapping->strength, icsf_policy_get_attr, &pattr, icsf_policy_free_attr, session); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: Object too weak\n"); 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: case CKM_TLS_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; struct icsf_policy_attr pattr = { 0 }; /* 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; } pattr.ld = session_state->ld; pattr.icsf_object = &pub_key_mapping->icsf_object; rc = tokdata->policy->store_object_strength(tokdata->policy, &pub_key_mapping->strength, icsf_policy_get_attr, &pattr, icsf_policy_free_attr, session); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: Public key too weak\n"); goto done; } pattr.icsf_object = &priv_key_mapping->icsf_object; rc = tokdata->policy->store_object_strength(tokdata->policy, &priv_key_mapping->strength, icsf_policy_get_attr, &pattr, icsf_policy_free_attr, session); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: Private key too weak\n"); 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: if (rc == CKR_OK && tokdata->statistics->increment_func != NULL) tokdata->statistics->increment_func(tokdata->statistics, session->session_info.slotID, mech, priv_key_mapping->strength.strength); 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; struct icsf_policy_attr pattr = { 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; } pattr.ld = session_state->ld; pattr.icsf_object = &mapping->icsf_object; rc = tokdata->policy->store_object_strength(tokdata->policy, &mapping->strength, icsf_policy_get_attr, &pattr, icsf_policy_free_attr, session); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: Public key too weak\n"); 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 (rc == CKR_OK && tokdata->statistics->increment_func != NULL && mapping != NULL) tokdata->statistics->increment_func(tokdata->statistics, session->session_info.slotID, mech, mapping->strength.strength); 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; } rc = tokdata->policy->is_mech_allowed(tokdata->policy, mech, &mapping->strength, POLICY_CHECK_ENCRYPT, session); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: encrypt init\n"); goto done; } /** 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 && tokdata->statistics->increment_func != NULL) tokdata->statistics->increment_func(tokdata->statistics, session->session_info.slotID, mech, mapping->strength.strength); if (rc != CKR_OK) free_encr_ctx(encr_ctx); bt_put_node_value(&icsf_data->objects, mapping); mapping = NULL; 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), output_data_len; 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. */ output_data_len = *p_output_data_len; 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, &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, &output_data_len); } *p_output_data_len = 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), output_part_len; 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); if (input_part_len > remaining) memcpy(buffer + multi_part_ctx->used_data_len, input_part, input_part_len - remaining); /* Encrypt data using remote token. */ output_part_len = *p_output_part_len; rc = icsf_secret_key_encrypt(session_state->ld, &reason, &mapping->icsf_object, &encr_ctx->mech, chaining, buffer, total - remaining, (char *)output_part, &output_part_len, chain_data, &chain_data_len); *p_output_part_len = output_part_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) { if (input_part_len > 0) 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), output_part_len; 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. */ output_part_len = *p_output_part_len; 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, &output_part_len, chain_data, &chain_data_len); *p_output_part_len = output_part_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; } rc = tokdata->policy->is_mech_allowed(tokdata->policy, mech, &mapping->strength, POLICY_CHECK_DECRYPT, session); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: decrypt init\n"); goto done; } /** 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 && tokdata->statistics->increment_func != NULL) tokdata->statistics->increment_func(tokdata->statistics, session->session_info.slotID, mech, mapping->strength.strength); if (rc != CKR_OK) free_encr_ctx(decr_ctx); bt_put_node_value(&icsf_data->objects, mapping); mapping = NULL; 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), output_data_len; 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. */ output_data_len = *p_output_data_len; 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, &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, &output_data_len); } *p_output_data_len = 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), output_part_len; 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); if (input_part_len > remaining) memcpy(buffer + multi_part_ctx->used_data_len, input_part, input_part_len - remaining); /* Decrypt data using remote token. */ output_part_len = *p_output_part_len; rc = icsf_secret_key_decrypt(session_state->ld, &reason, &mapping->icsf_object, &decr_ctx->mech, chaining, buffer, total - remaining, (char *)output_part, &output_part_len, chain_data, &chain_data_len); *p_output_part_len = output_part_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)) { if (input_part_len > 0) 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), output_part_len; 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. */ output_part_len = *p_output_part_len; 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, &output_part_len, chain_data, &chain_data_len); *p_output_part_len = output_part_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; BerElement *cached_result = 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, &cached_result, &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, &cached_result, &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; } if (cached_result != NULL) ber_free(cached_result, 1); 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, NULL, &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; struct icsf_policy_attr pattr = { 0 }; /* 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]; /* Policy check */ pattr.ld = session_state->ld; pattr.icsf_object = &new_mapping->icsf_object; rc = tokdata->policy->store_object_strength( tokdata->policy, &new_mapping->strength, icsf_policy_get_attr, &pattr, icsf_policy_free_attr, sess); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: Object too weak\n"); goto done; } 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_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; case CKM_SHA3_224_HMAC: return SHA3_224_HASH_SIZE; case CKM_SHA3_256_HMAC: return SHA3_256_HASH_SIZE; case CKM_SHA3_384_HMAC: return SHA3_384_HASH_SIZE; case CKM_SHA3_512_HMAC: return SHA3_512_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; } rc = tokdata->policy->is_mech_allowed(tokdata->policy, mech, &mapping->strength, POLICY_CHECK_SIGNATURE, session); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: Sign init\n"); goto done; } /* 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_SHA224_HMAC: case CKM_SHA256_HMAC: case CKM_SHA384_HMAC: case CKM_SHA512_HMAC: case CKM_SHA3_224_HMAC: case CKM_SHA3_256_HMAC: case CKM_SHA3_384_HMAC: case CKM_SHA3_512_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) || mech->pParameter == NULL) { 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_SHA224_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: case CKM_ECDSA_SHA224: case CKM_ECDSA_SHA256: case CKM_ECDSA_SHA384: case CKM_ECDSA_SHA512: /* 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 (rc == CKR_OK && tokdata->statistics->increment_func != NULL) tokdata->statistics->increment_func(tokdata->statistics, session->session_info.slotID, mech, mapping->strength.strength); 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), slen; 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_SHA224_HMAC: case CKM_SHA256_HMAC: case CKM_SHA384_HMAC: case CKM_SHA512_HMAC: case CKM_SHA3_224_HMAC: case CKM_SHA3_256_HMAC: case CKM_SHA3_384_HMAC: case CKM_SHA3_512_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; } slen = *sig_len; rc = icsf_hmac_sign(session_state->ld, &reason, &mapping->icsf_object, &ctx->mech, "ONLY", (char *)in_data, in_data_len, (char *)signature, &slen, chain_data, &chain_data_len); *sig_len = slen; 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: slen = *sig_len; rc = icsf_private_key_sign(session_state->ld, &reason, FALSE, &mapping->icsf_object, &ctx->mech, (char *)in_data, in_data_len, (char *)signature, &slen); *sig_len = slen; 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_SHA224_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: case CKM_ECDSA_SHA224: case CKM_ECDSA_SHA256: case CKM_ECDSA_SHA384: case CKM_ECDSA_SHA512: 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 = CKR_ARGUMENTS_BAD; goto done; } switch (ctx->mech.mechanism) { case CKM_MD5_HMAC: case CKM_SHA_1_HMAC: case CKM_SHA224_HMAC: case CKM_SHA256_HMAC: case CKM_SHA384_HMAC: case CKM_SHA512_HMAC: case CKM_SHA3_224_HMAC: case CKM_SHA3_256_HMAC: case CKM_SHA3_384_HMAC: case CKM_SHA3_512_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_SHA224_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: case CKM_ECDSA_SHA224: case CKM_ECDSA_SHA256: case CKM_ECDSA_SHA384: case CKM_ECDSA_SHA512: /* 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) { if (in_data_len > 0) 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); if (out_len > 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), slen; 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 = CKR_ARGUMENTS_BAD; goto done; } switch (ctx->mech.mechanism) { case CKM_MD5_HMAC: case CKM_SHA_1_HMAC: case CKM_SHA224_HMAC: case CKM_SHA256_HMAC: case CKM_SHA384_HMAC: case CKM_SHA512_HMAC: case CKM_SHA3_224_HMAC: case CKM_SHA3_256_HMAC: case CKM_SHA3_384_HMAC: case CKM_SHA3_512_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; } slen = *sig_len; rc = icsf_hmac_sign(session_state->ld, &reason, &mapping->icsf_object, &ctx->mech, multi_part_ctx->initiated ? "LAST" : "ONLY", "", 0, (char *)signature, &slen, chain_data, &chain_data_len); *sig_len = slen; if (rc != 0) rc = icsf_to_ock_err(rc, reason); break; case CKM_MD5_RSA_PKCS: case CKM_SHA1_RSA_PKCS: case CKM_SHA224_RSA_PKCS: case CKM_SHA256_RSA_PKCS: case CKM_SHA384_RSA_PKCS: case CKM_SHA512_RSA_PKCS: case CKM_DSA_SHA1: case CKM_ECDSA_SHA1: case CKM_ECDSA_SHA224: case CKM_ECDSA_SHA256: case CKM_ECDSA_SHA384: case CKM_ECDSA_SHA512: /* 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; } rc = tokdata->policy->is_mech_allowed(tokdata->policy, mech, &mapping->strength, POLICY_CHECK_VERIFY, session); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: Sign init\n"); goto done; } /* 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_SHA224_HMAC: case CKM_SHA256_HMAC: case CKM_SHA384_HMAC: case CKM_SHA512_HMAC: case CKM_SHA3_224_HMAC: case CKM_SHA3_256_HMAC: case CKM_SHA3_384_HMAC: case CKM_SHA3_512_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) || mech->pParameter == NULL) { 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_SHA224_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: case CKM_ECDSA_SHA224: case CKM_ECDSA_SHA256: case CKM_ECDSA_SHA384: case CKM_ECDSA_SHA512: /* 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 (rc == CKR_OK && tokdata->statistics->increment_func != NULL) tokdata->statistics->increment_func(tokdata->statistics, session->session_info.slotID, mech, mapping->strength.strength); 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), slen; 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_SHA224_HMAC: case CKM_SHA256_HMAC: case CKM_SHA384_HMAC: case CKM_SHA512_HMAC: case CKM_SHA3_224_HMAC: case CKM_SHA3_256_HMAC: case CKM_SHA3_384_HMAC: case CKM_SHA3_512_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: slen = sig_len; rc = icsf_public_key_verify(session_state->ld, &reason, FALSE, &mapping->icsf_object, &ctx->mech, (char *)in_data, in_data_len, (char *)signature, &slen); sig_len = slen; if (rc != 0) rc = icsf_to_ock_err(rc, reason); break; case CKM_MD5_RSA_PKCS: case CKM_SHA1_RSA_PKCS: case CKM_SHA224_RSA_PKCS: case CKM_SHA256_RSA_PKCS: case CKM_SHA384_RSA_PKCS: case CKM_SHA512_RSA_PKCS: case CKM_DSA_SHA1: case CKM_ECDSA_SHA1: case CKM_ECDSA_SHA224: case CKM_ECDSA_SHA256: case CKM_ECDSA_SHA384: case CKM_ECDSA_SHA512: 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 = CKR_ARGUMENTS_BAD; goto done; } switch (ctx->mech.mechanism) { case CKM_MD5_HMAC: case CKM_SHA_1_HMAC: case CKM_SHA224_HMAC: case CKM_SHA256_HMAC: case CKM_SHA384_HMAC: case CKM_SHA512_HMAC: case CKM_SHA3_224_HMAC: case CKM_SHA3_256_HMAC: case CKM_SHA3_384_HMAC: case CKM_SHA3_512_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_SHA224_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: case CKM_ECDSA_SHA224: case CKM_ECDSA_SHA256: case CKM_ECDSA_SHA384: case CKM_ECDSA_SHA512: /* 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) { if (in_data_len > 0) 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); if (out_len > 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 = CKR_ARGUMENTS_BAD; goto done; } switch (ctx->mech.mechanism) { case CKM_MD5_HMAC: case CKM_SHA_1_HMAC: case CKM_SHA224_HMAC: case CKM_SHA256_HMAC: case CKM_SHA384_HMAC: case CKM_SHA512_HMAC: case CKM_SHA3_224_HMAC: case CKM_SHA3_256_HMAC: case CKM_SHA3_384_HMAC: case CKM_SHA3_512_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_SHA224_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: case CKM_ECDSA_SHA224: case CKM_ECDSA_SHA256: case CKM_ECDSA_SHA384: case CKM_ECDSA_SHA512: /* 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; } rc = tokdata->policy->is_mech_allowed(tokdata->policy, mech, &wrapping_key_mapping->strength, POLICY_CHECK_WRAP, session); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: Wrap init\n"); goto done; } rc = tokdata->policy->is_key_allowed(tokdata->policy, &key_mapping->strength, session); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: Wrap init\n"); 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 || mech->pParameter == NULL) { TRACE_ERROR("Invalid mechanism parameter NULL or 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 (rc == CKR_OK && tokdata->statistics->increment_func != NULL) tokdata->statistics->increment_func(tokdata->statistics, session->session_info.slotID, mech, wrapping_key_mapping->strength.strength); 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; struct icsf_policy_attr pattr = { 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; } rc = tokdata->policy->is_mech_allowed(tokdata->policy, mech, &wrapping_key_mapping->strength, POLICY_CHECK_UNWRAP, session); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: Unwrap init\n"); goto done; } /* 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 || mech->pParameter == NULL) { TRACE_ERROR("Invalid mechanism parameter NULL or 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; } pattr.ld = session_state->ld; pattr.icsf_object = &key_mapping->icsf_object; rc = tokdata->policy->store_object_strength(tokdata->policy, &key_mapping->strength, icsf_policy_get_attr, &pattr, icsf_policy_free_attr, session); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: Unwrapped key too weak\n"); 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 (rc == CKR_OK && tokdata->statistics->increment_func != NULL) tokdata->statistics->increment_func(tokdata->statistics, session->session_info.slotID, mech, wrapping_key_mapping->strength.strength); 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; struct icsf_policy_attr pattr = { 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; } rc = tokdata->policy->is_mech_allowed(tokdata->policy, mech, &base_key_mapping->strength, POLICY_CHECK_DERIVE, session); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: Derive key\n"); 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); if (rc) { rc = icsf_to_ock_err(rc, reason); goto done; } pattr.ld = session_state->ld; pattr.icsf_object = &mappings[0]->icsf_object; rc = tokdata->policy->store_object_strength(tokdata->policy, &mappings[0]->strength, icsf_policy_get_attr, &pattr, icsf_policy_free_attr, session); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: Derived key too weak\n"); goto done; } } 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; } pattr.ld = session_state->ld; for (i = 0; i < 4; ++i) { pattr.icsf_object = &mappings[i]->icsf_object; rc = tokdata->policy->store_object_strength(tokdata->policy, &mappings[i]->strength, icsf_policy_get_attr, &pattr, icsf_policy_free_attr, session); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: Derived key too weak\n"); 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 (rc == CKR_OK && tokdata->statistics->increment_func != NULL) tokdata->statistics->increment_func(tokdata->statistics, session->session_info.slotID, mech, base_key_mapping->strength.strength); 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; } CK_RV token_specific_sha_init(STDLL_TokData_t *tokdata, DIGEST_CONTEXT *ctx, CK_MECHANISM *mech) { return openssl_specific_sha_init(tokdata, ctx, mech); } 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) { return openssl_specific_sha(tokdata, ctx, in_data, in_data_len, out_data, out_data_len); } CK_RV token_specific_sha_update(STDLL_TokData_t *tokdata, DIGEST_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len) { return openssl_specific_sha_update(tokdata, ctx, in_data, in_data_len); } CK_RV token_specific_sha_final(STDLL_TokData_t *tokdata, DIGEST_CONTEXT *ctx, CK_BYTE *out_data, CK_ULONG *out_data_len) { return openssl_specific_sha_final(tokdata, ctx, out_data, out_data_len); } opencryptoki-opencryptoki-451d99c/usr/lib/icsf_stdll/icsf_specific.h000066400000000000000000000204421520105705100257750ustar00rootroot00000000000000/* * 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 opencryptoki-opencryptoki-451d99c/usr/lib/icsf_stdll/icsf_stdll.mk000066400000000000000000000046021520105705100255120ustar00rootroot00000000000000nobase_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 opencryptoki_stdll_libpkcs11_icsf_la_CFLAGS = \ -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 \ -I${top_builddir}/usr/lib/icsf_stdll \ -I${top_builddir}/usr/lib/api -I${srcdir}/usr/lib/api \ -I${top_builddir}/usr/lib/config -I${srcdir}/usr/lib/config 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/common/profile_obj.c \ usr/lib/common/dlist.c usr/lib/icsf_stdll/pbkdf.c \ usr/lib/icsf_stdll/icsf_specific.c usr/lib/common/mech_pqc.c \ usr/lib/icsf_stdll/icsf.c usr/lib/common/utility_common.c \ usr/lib/common/ec_supported.c usr/lib/api/policyhelper.c \ usr/lib/config/configuration.c usr/lib/common/pqc_supported.c \ usr/lib/config/cfgparse.y usr/lib/config/cfglex.l \ usr/lib/common/mech_openssl.c \ usr/lib/common/btree.c usr/lib/common/sess_mgr.c usr/lib/icsf_stdll/icsf_specific.$(OBJEXT): usr/lib/config/cfgparse.h opencryptoki-opencryptoki-451d99c/usr/lib/icsf_stdll/new_host.c000066400000000000000000003431541520105705100250350ustar00rootroot00000000000000/* * 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 #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 "attributes.h" #include "icsf_specific.h" #include "constant_time.h" #include "../api/apiproto.h" #include "../api/policy.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, NULL); 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]; CK_BBOOL newdatastore; policy_t policy = sltp->TokData->policy; /* set trace info */ set_trace(t); rc = bt_init(&sltp->TokData->sess_btree, free); rc |= bt_init(&sltp->TokData->object_map_btree, free); rc |= bt_init(&sltp->TokData->sess_obj_btree, call_object_free); rc |= bt_init(&sltp->TokData->priv_token_obj_btree, call_object_free); rc |= bt_init(&sltp->TokData->publ_token_obj_btree, call_object_free); if (rc != CKR_OK) { TRACE_ERROR("Btree init failed\n"); rc = CKR_FUNCTION_FAILED; goto done; } if (strlen(sinfp->tokname)) { if (ock_snprintf(abs_tokdir_name, PATH_MAX, "%s/%s", CONFIG_PATH, sinfp->tokname) != 0) { TRACE_ERROR("abs_tokdir_name buffer overflow\n"); rc = CKR_FUNCTION_FAILED; } else { TRACE_DEVEL("Token directory: %s\n", abs_tokdir_name); rc = init_data_store(sltp->TokData, (char *) abs_tokdir_name, sltp->TokData->data_store, sizeof(sltp->TokData->data_store)); } } else { rc = init_data_store(sltp->TokData, (char *) PK_DIR, sltp->TokData->data_store, sizeof(sltp->TokData->data_store)); } if (rc != CKR_OK) { TRACE_ERROR("init_data_store failed with buffer error.\n"); goto done; } sltp->TokData->version = sinfp->version; TRACE_DEVEL("Token version: %u.%u\n", (unsigned int)(sinfp->version >> 16), (unsigned int)(sinfp->version & 0xffff)); /* Check token store encryption against policy */ newdatastore = sinfp->version >= TOK_NEW_DATA_STORE ? CK_TRUE : CK_FALSE; rc = policy->check_token_store(policy, newdatastore, token_specific.data_store.encryption_algorithm, SlotNumber, &sltp->TokData->store_strength); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: Token cannot load since data store encryption is too weak for policy.\n"); goto done; } /* 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); final_data_store(sltp->TokData); 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; final_data_store(sltp->TokData); 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); final_data_store(sltp->TokData); bt_destroy(&sltp->TokData->sess_btree); bt_destroy(&sltp->TokData->object_map_btree); bt_destroy(&sltp->TokData->sess_obj_btree); bt_destroy(&sltp->TokData->priv_token_obj_btree); bt_destroy(&sltp->TokData->publ_token_obj_btree); } } 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); 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); 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); if (token_specific.t_get_token_info != NULL) rc = token_specific.t_get_token_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 = ock_generic_get_mechanism_list(tokdata, pMechList, count, NULL); if (rc == CKR_OK) { /* To accomodate certain special cases, we may need to * make adjustments to the token's mechanism list. */ mechanism_list_transformations(tokdata, 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, NULL); 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_reset_error(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_reset_error(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_reset_error(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_reset_error(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_reset_error(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(tokdata, 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_reset_error(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(tokdata, 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_SessionCancel(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, CK_FLAGS flags) { 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 = session_mgr_cancel(tokdata, sess, flags); done: TRACE_INFO("SC_SessionCancel: sess = %lu\n", 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_reset_error(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; } if (!(*flags & CKF_USER_PIN_INITIALIZED)) { TRACE_ERROR("%s\n", ock_err(ERR_USER_PIN_NOT_INITIALIZED)); rc = CKR_USER_PIN_NOT_INITIALIZED; 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_reset_error(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_reset_error(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 && pTemplate[i].ulValueLen == sizeof(CK_ULONG) && pTemplate[i].pValue != NULL) { 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_reset_error(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_reset_error(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_reset_error(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_reset_error(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 val[4]; CK_ULONG i; attr = pTemplate; for (i = 0; i < ulCount && attr != NULL; i++, attr++) { TRACE_DEBUG("%lu: Attribute type: 0x%08lx, Value Length: %lu\n", i, attr->type, attr->ulValueLen); if (rc == CKR_OK && attr->ulValueLen != CK_UNAVAILABLE_INFORMATION) { if (attr->ulValueLen >= sizeof(val) && attr->pValue != NULL) { memset(val, 0, sizeof(val)); memcpy(val, attr->pValue, attr->ulValueLen > sizeof(val) ? sizeof(val) : attr->ulValueLen); TRACE_DEBUG("First 4 bytes: %02x %02x %02x %02x\n", val[0], val[1], val[2], val[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_reset_error(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_BYTE val[4]; CK_ULONG i; attr = pTemplate; for (i = 0; i < ulCount && attr != NULL; i++, attr++) { TRACE_DEBUG("%lu: Attribute type: 0x%08lx, Value Length: %lu\n", i, attr->type, attr->ulValueLen); if (attr->ulValueLen >= sizeof(val) && attr->pValue != NULL) { memset(val, 0, sizeof(val)); memcpy(val, attr->pValue, attr->ulValueLen > sizeof(val) ? sizeof(val) : attr->ulValueLen); TRACE_DEBUG("First 4 bytes: %02x %02x %02x %02x\n", val[0], val[1], val[2], val[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_reset_error(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_BYTE val[4]; CK_ULONG i; attr = pTemplate; for (i = 0; i < ulCount && attr != NULL; i++, attr++) { TRACE_DEBUG("%lu: Attribute type: 0x%08lx, Value Length: %lu\n", i, attr->type, attr->ulValueLen); if (attr->ulValueLen >= sizeof(val) && attr->pValue != NULL) { memset(val, 0, sizeof(val)); memcpy(val, attr->pValue, attr->ulValueLen > sizeof(val) ? sizeof(val) : attr->ulValueLen); TRACE_DEBUG("First 4 bytes: %02x %02x %02x %02x\n", val[0], val[1], val[2], val[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_reset_error(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_reset_error(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; } sess = session_mgr_find_reset_error(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 (pMechanism == NULL) { /* As per PKCS#11 v3.0 Init with NULL pMechanism cancels operation */ rc = session_mgr_cancel(tokdata, sess, CKF_ENCRYPT); goto done; } rc = valid_mech(tokdata, pMechanism, CKF_ENCRYPT); if (rc != CKR_OK) 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_reset_error(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(tokdata, sess, &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_reset_error(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(tokdata, sess, &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_reset_error(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(tokdata, sess, &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; } sess = session_mgr_find_reset_error(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 (pMechanism == NULL) { /* As per PKCS#11 v3.0 Init with NULL pMechanism cancels operation */ rc = session_mgr_cancel(tokdata, sess, CKF_DECRYPT); goto done; } rc = valid_mech(tokdata, pMechanism, CKF_DECRYPT); if (rc != CKR_OK) 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; unsigned int mask; 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_reset_error(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); /* (!is_rsa_mechanism(sess->decr_ctx.mech.mechanism) && rc != CKR_OK) */ mask = constant_time_is_zero( is_rsa_mechanism(sess->decr_ctx.mech.mechanism)); mask &= ~constant_time_eq(rc, CKR_OK); if (mask) TRACE_DEVEL("icsftok_decrypt() failed.\n"); done: /* (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) */ mask = ~constant_time_eq(rc, CKR_OK); mask |= constant_time_is_zero(length_only); mask &= ~constant_time_eq(rc, CKR_BUFFER_TOO_SMALL); if (mask) { if (sess) decr_mgr_cleanup(tokdata, sess, &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; unsigned int mask; 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_reset_error(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); /* (!is_rsa_mechanism(sess->decr_ctx.mech.mechanism) && rc != CKR_OK) */ mask = constant_time_is_zero( is_rsa_mechanism(sess->decr_ctx.mech.mechanism)); mask &= ~constant_time_eq(rc, CKR_OK); if (mask) TRACE_DEVEL("icsftok_decrypt_update() failed.\n"); done: /* (rc != CKR_OK && rc != CKR_BUFFER_TOO_SMALL */ mask = ~constant_time_eq(rc, CKR_OK); mask &= ~constant_time_eq(rc, CKR_BUFFER_TOO_SMALL); if (mask) { if (sess) decr_mgr_cleanup(tokdata, sess, &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; unsigned int mask; 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_reset_error(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); /* (!is_rsa_mechanism(sess->decr_ctx.mech.mechanism) && rc != CKR_OK) */ mask = constant_time_is_zero( is_rsa_mechanism(sess->decr_ctx.mech.mechanism)); mask &= ~constant_time_eq(rc, CKR_OK); if (mask) TRACE_DEVEL("icsftok_decrypt_final() failed.\n"); done: /* (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) */ mask = ~constant_time_eq(rc, CKR_OK); mask |= constant_time_is_zero(length_only); mask &= ~constant_time_eq(rc, CKR_BUFFER_TOO_SMALL); if (mask) { if (sess) decr_mgr_cleanup(tokdata, sess, &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; } sess = session_mgr_find_reset_error(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 (pMechanism == NULL) { /* As per PKCS#11 v3.0 Init with NULL pMechanism cancels operation */ rc = session_mgr_cancel(tokdata, sess, CKF_DIGEST); goto done; } rc = valid_mech(tokdata, pMechanism, CKF_DIGEST); if (rc != CKR_OK) goto done; if (sess->digest_ctx.active == TRUE) { TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); rc = CKR_OPERATION_ACTIVE; goto done; } sess->digest_ctx.count_statistics = TRUE; rc = digest_mgr_init(tokdata, sess, &sess->digest_ctx, pMechanism, TRUE); 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_reset_error(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_reset_error(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_reset_error(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_reset_error(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; } sess = session_mgr_find_reset_error(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 (pMechanism == NULL) { /* As per PKCS#11 v3.0 Init with NULL pMechanism cancels operation */ rc = session_mgr_cancel(tokdata, sess, CKF_SIGN); goto done; } rc = valid_mech(tokdata, pMechanism, CKF_SIGN); if (rc != CKR_OK) 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; } sess = session_mgr_find_reset_error(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 || !pulSignatureLen) { TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); rc = CKR_ARGUMENTS_BAD; 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 = 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)) { if (sess != NULL) sign_mgr_cleanup(tokdata, sess, &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; } sess = session_mgr_find_reset_error(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) { TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); rc = CKR_ARGUMENTS_BAD; 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 = icsftok_sign_update(tokdata, sess, pPart, ulPartLen); if (rc != CKR_OK) TRACE_DEVEL("icsftok_sign_update() failed.\n"); done: if (rc != CKR_OK && sess != NULL) sign_mgr_cleanup(tokdata, sess, &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; } sess = session_mgr_find_reset_error(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 (!pulSignatureLen) { TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); rc = CKR_ARGUMENTS_BAD; 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 = 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)) { if (sess != NULL) sign_mgr_cleanup(tokdata, sess, &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; } static CK_RV VerifyInit(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey, 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; } sess = session_mgr_find_reset_error(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 (pMechanism == NULL) { /* As per PKCS#11 v3.0 Init with NULL pMechanism cancels operation */ rc = session_mgr_cancel(tokdata, sess, CKF_VERIFY); goto done; } rc = valid_mech(tokdata, pMechanism, CKF_VERIFY); if (rc != CKR_OK) goto done; if (sess->verify_ctx.active == TRUE) { rc = CKR_OPERATION_ACTIVE; TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); goto done; } if (pSignature != NULL && ulSignatureLen != 0) { /* Save signature in context for later verification */ sess->verify_ctx.saved_signature = malloc(ulSignatureLen); if (sess->verify_ctx.saved_signature == NULL) { rc = CKR_HOST_MEMORY; TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); goto done; } memcpy(sess->verify_ctx.saved_signature, pSignature, ulSignatureLen); sess->verify_ctx.saved_signature_len = ulSignatureLen; } rc = icsftok_verify_init(tokdata, sess, pMechanism, hKey); if (rc != CKR_OK) TRACE_DEVEL("icsftok_verify_init() failed.\n"); done: TRACE_INFO("C_Verify%sInit: rc = 0x%08lx, sess = %ld, mech = 0x%lx\n", pSignature != NULL && ulSignatureLen != 0 ? "Signature" : "", 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_VerifyInit(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { return VerifyInit(tokdata, sSession, pMechanism, hKey, NULL, 0); } static CK_RV 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; } sess = session_mgr_find_reset_error(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) { TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); rc = CKR_ARGUMENTS_BAD; 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 (sess->verify_ctx.saved_signature == NULL && pSignature == NULL) { /* Operation was initialized with C_VerifyInit() */ TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); rc = CKR_ARGUMENTS_BAD; goto done; } if (sess->verify_ctx.saved_signature != NULL && pSignature != NULL) { /* Operation was initialized with C_VerifySignatureInit() */ TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); rc = CKR_OPERATION_NOT_INITIALIZED; goto done; } rc = icsftok_verify(tokdata, sess, pData, ulDataLen, sess->verify_ctx.saved_signature != NULL ? sess->verify_ctx.saved_signature : pSignature, sess->verify_ctx.saved_signature != NULL ? sess->verify_ctx.saved_signature_len : ulSignatureLen); if (rc != CKR_OK) TRACE_DEVEL("icsftok_verify() failed.\n"); done: if (sess != NULL) verify_mgr_cleanup(tokdata, sess, &sess->verify_ctx); TRACE_INFO("C_Verify%s: rc = 0x%08lx, sess = %ld, datalen = %lu\n", pSignature == NULL ? "Signature" : "", rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, ulDataLen); 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) { return Verify(tokdata, sSession, pData, ulDataLen, pSignature, ulSignatureLen); } static CK_RV VerifyUpdate(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen, CK_BBOOL verify_message) { 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_reset_error(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) { TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); rc = CKR_ARGUMENTS_BAD; 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 ((sess->verify_ctx.saved_signature != NULL) != verify_message) { 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 && sess != NULL) verify_mgr_cleanup(tokdata, sess, &sess->verify_ctx); TRACE_INFO("C_Verify%sUpdate: rc = 0x%08lx, sess = %ld, datalen = %lu\n", (sess != NULL && sess->verify_ctx.saved_signature != NULL) ? "Signature" : "", rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, ulPartLen); 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) { return VerifyUpdate(tokdata, sSession, pPart, ulPartLen, FALSE); } static CK_RV 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; } sess = session_mgr_find_reset_error(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; } if (pSignature == NULL && sess->verify_ctx.saved_signature == NULL) { /* Operation was initialized with C_VerifyInit() */ rc = CKR_OPERATION_NOT_INITIALIZED; TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); goto done; } if (pSignature != NULL && sess->verify_ctx.saved_signature != NULL) { /* Operation was initialized with C_VerifySignatureInit() */ rc = CKR_OPERATION_NOT_INITIALIZED; TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); goto done; } rc = icsftok_verify_final(tokdata, sess, sess->verify_ctx.saved_signature != NULL ? sess->verify_ctx.saved_signature : pSignature, sess->verify_ctx.saved_signature != NULL ? sess->verify_ctx.saved_signature_len : ulSignatureLen); if (rc != CKR_OK) TRACE_DEVEL("icsftok_verify_final() failed.\n"); done: if (sess != NULL) verify_mgr_cleanup(tokdata, sess, &sess->verify_ctx); TRACE_INFO("C_Verify%sFinal: rc = 0x%08lx, sess = %ld\n", pSignature == NULL ? "Signature" : "", rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle); 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) { if (pSignature == NULL || ulSignatureLen == 0) { TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); return CKR_ARGUMENTS_BAD; } return VerifyFinal(tokdata, sSession, pSignature, ulSignatureLen); } 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_VerifySignatureInit(STDLL_TokData_t *tokdata, ST_SESSION_T *sSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen) { if (pSignature == NULL || ulSignatureLen == 0) { TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); return CKR_ARGUMENTS_BAD; } return VerifyInit(tokdata, sSession, pMechanism, hKey, pSignature, ulSignatureLen); } CK_RV SC_VerifySignature(STDLL_TokData_t *tokdata, ST_SESSION_T *sSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen) { return Verify(tokdata, sSession, pData, ulDataLen, NULL, 0); } CK_RV SC_VerifySignatureUpdate(STDLL_TokData_t *tokdata, ST_SESSION_T *sSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen) { return VerifyUpdate(tokdata, sSession, pPart, ulPartLen, TRUE); } CK_RV SC_VerifySignatureFinal(STDLL_TokData_t *tokdata, ST_SESSION_T *sSession) { return VerifyFinal(tokdata, sSession, NULL, 0); } 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) { CK_RV rc; rc = SC_EncryptUpdate(tokdata, sSession, pPart, ulPartLen, pEncryptedPart, pulEncryptedPartLen); if (rc != CKR_OK || pEncryptedPart == NULL) goto out; rc = SC_DigestUpdate(tokdata, sSession, pPart, ulPartLen); out: return rc; } 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) { CK_RV rc; rc = SC_DecryptUpdate(tokdata, sSession, pEncryptedPart, ulEncryptedPartLen, pPart, pulPartLen); if (rc != CKR_OK || pPart == NULL) goto out; rc = SC_DigestUpdate(tokdata, sSession, pPart, *pulPartLen); out: return rc; } 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) { CK_RV rc; rc = SC_EncryptUpdate(tokdata, sSession, pPart, ulPartLen, pEncryptedPart, pulEncryptedPartLen); if (rc != CKR_OK || pEncryptedPart == NULL) goto out; rc = SC_SignUpdate(tokdata, sSession, pPart, ulPartLen); out: return rc; } 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) { CK_RV rc; rc = SC_DecryptUpdate(tokdata, sSession, pEncryptedPart, ulEncryptedPartLen, pPart, pulPartLen); if (rc != CKR_OK || pPart == NULL) goto out; rc = SC_VerifyUpdate(tokdata, sSession, pPart, *pulPartLen); out: return rc; } 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_reset_error(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 = tokdata->policy->is_mech_allowed(tokdata->policy, pMechanism, NULL, POLICY_CHECK_KEYGEN, sess); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: Key generation mechanism not allowed\n"); 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 = 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_BYTE val[4]; CK_ULONG i; attr = pTemplate; for (i = 0; i < ulCount && attr != NULL; i++, attr++) { TRACE_DEBUG("%lu: Attribute type: 0x%08lx, Value Length: %lu\n", i, attr->type, attr->ulValueLen); if (attr->ulValueLen >= sizeof(val) && attr->pValue != NULL) { memset(val, 0, sizeof(val)); memcpy(val, attr->pValue, attr->ulValueLen > sizeof(val) ? sizeof(val) : attr->ulValueLen); TRACE_DEBUG("First 4 bytes: %02x %02x %02x %02x\n", val[0], val[1], val[2], val[3]); } } #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_reset_error(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 = tokdata->policy->is_mech_allowed(tokdata->policy, pMechanism, NULL, POLICY_CHECK_KEYGEN, sess); if (rc != CKR_OK) { TRACE_ERROR("POLICY VIOLATION: Keypair generation mechanism not allowed\n"); 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 = 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; 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; for (i = 0; i < ulPublicKeyAttributeCount && attr != NULL; i++, attr++) { TRACE_DEBUG_DUMPATTR(attr); } TRACE_DEBUG("Private Template:\n"); attr = pPrivateKeyTemplate; for (i = 0; i < ulPrivateKeyAttributeCount && attr != NULL; i++, attr++) { TRACE_DEBUG_DUMPATTR(attr); } #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_reset_error(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_reset_error(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 val[4]; CK_ULONG i; attr = pTemplate; for (i = 0; i < ulCount && attr != NULL; i++, attr++) { TRACE_DEBUG("%lu: Attribute type: 0x%08lx, Value Length: %lu\n", i, attr->type, attr->ulValueLen); if (attr->ulValueLen >= sizeof(val) && attr->pValue != NULL) { memset(val, 0, sizeof(val)); memcpy(val, attr->pValue, attr->ulValueLen > sizeof(val) ? sizeof(val) : attr->ulValueLen); TRACE_DEBUG("First 4 bytes: %02x %02x %02x %02x\n", val[0], val[1], val[2], val[3]); } } #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 && pMechanism->mechanism != CKM_TLS_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_reset_error(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 val[4]; CK_ULONG i; if (rc == CKR_OK) { switch (pMechanism->mechanism) { case CKM_SSL3_KEY_AND_MAC_DERIVE: case CKM_TLS_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; for (i = 0; i < ulCount && attr != NULL; i++, attr++) { TRACE_DEBUG("%lu: Attribute type: 0x%08lx, Value Length: %lu\n", i, attr->type, attr->ulValueLen); if (attr->ulValueLen >= sizeof(val) && attr->pValue != NULL) { memset(val, 0, sizeof(val)); memcpy(val, attr->pValue, attr->ulValueLen > sizeof(val) ? sizeof(val) : attr->ulValueLen); TRACE_DEBUG("First 4 bytes: %02x %02x %02x %02x\n", val[0], val[1], val[2], val[3]); } } #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_reset_error(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 (ulRandomLen == 0) 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; } CK_RV SC_EncapsulateKey(STDLL_TokData_t *tokdata, ST_SESSION_T *sSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hPublicKey, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, CK_BYTE_PTR pCiphertext, CK_ULONG_PTR pulCiphertextLen, CK_OBJECT_HANDLE_PTR phKey) { 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 || !pulCiphertextLen) { TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); rc = CKR_ARGUMENTS_BAD; goto done; } rc = valid_mech(tokdata, pMechanism, CKF_ENCAPSULATE); if (rc != CKR_OK) goto done; if (!pCiphertext) length_only = TRUE; sess = session_mgr_find_reset_error(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_encapsulate_key(tokdata, sess, length_only, pMechanism, hPublicKey, pTemplate, ulAttributeCount, pCiphertext, pulCiphertextLen, phKey, TRUE); if (rc != CKR_OK) TRACE_DEVEL("key_mgr_encapsulate_key() failed.\n"); done: TRACE_INFO("SC_EncapsulateKey: rc = 0x%08lx, sess = %ld, priv key = %lu, " "ciphertext = %lu, encpsed key = %lu\n", rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, hPublicKey, (pulCiphertextLen ? *pulCiphertextLen : 0), (phKey ? *phKey : 0)); if (sess != NULL) session_mgr_put(tokdata, sess); return rc; } CK_RV SC_DecapsulateKey(STDLL_TokData_t *tokdata, ST_SESSION_T *sSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hPrivateKey, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, CK_BYTE_PTR pCiphertext, CK_ULONG ulCiphertextLen, 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 || !pCiphertext) { TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); rc = CKR_ARGUMENTS_BAD; goto done; } rc = valid_mech(tokdata, pMechanism, CKF_DECAPSULATE); if (rc != CKR_OK) goto done; sess = session_mgr_find_reset_error(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_decapsulate_key(tokdata, sess, pMechanism, hPrivateKey, pTemplate, ulAttributeCount, pCiphertext, ulCiphertextLen, phKey, TRUE); if (rc != CKR_OK) TRACE_DEVEL("key_mgr_decapsulate_key() failed.\n"); done: TRACE_INFO("SC_DecapsulateKey: rc = 0x%08lx, sess = %ld, pub key = %lu, " "encpsed key = %lu\n", rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, hPrivateKey, (phKey ? *phKey : 0)); if (sess != NULL) session_mgr_put(tokdata, sess); return rc; } CK_RV SC_IBM_ReencryptSingle(STDLL_TokData_t *tokdata, ST_SESSION_T *sSession, CK_MECHANISM_PTR pDecrMech, CK_OBJECT_HANDLE hDecrKey, CK_MECHANISM_PTR pEncrMech, CK_OBJECT_HANDLE hEncrKey, CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen, CK_BYTE_PTR pReencryptedData, CK_ULONG_PTR pulReencryptedDataLen) { SESSION *sess = NULL; CK_RV rc = CKR_OK; UNUSED(hDecrKey); UNUSED(hEncrKey); UNUSED(pEncryptedData); UNUSED(ulEncryptedDataLen); UNUSED(pReencryptedData); UNUSED(pulReencryptedDataLen); if (tokdata->initialized == FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); rc = CKR_CRYPTOKI_NOT_INITIALIZED; goto done; } if (!pDecrMech || !pEncrMech) { TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); rc = CKR_ARGUMENTS_BAD; goto done; } sess = session_mgr_find_reset_error(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, pDecrMech, CKF_DECRYPT); if (rc != CKR_OK) goto done; rc = valid_mech(tokdata, pEncrMech, CKF_ENCRYPT); 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->decr_ctx.active == TRUE || sess->encr_ctx.active == TRUE) { rc = CKR_OPERATION_ACTIVE; TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); goto done; } rc = CKR_FUNCTION_NOT_SUPPORTED; done: TRACE_INFO("SC_IBM_ReencryptSingle: rc = 0x%08lx, sess = %ld, " "decrmech = 0x%lx, encrmech = 0x%lx\n", rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, (pDecrMech ? pDecrMech->mechanism : (CK_ULONG)-1), (pEncrMech ? pEncrMech->mechanism : (CK_ULONG)-1)); if (sess != NULL) session_mgr_put(tokdata, sess); return rc; } CK_RV SC_HandleEvent(STDLL_TokData_t *tokdata, unsigned int event_type, unsigned int event_flags, const char *payload, unsigned int payload_len) { CK_RV rc; if (token_specific.t_handle_event == NULL) return CKR_FUNCTION_NOT_SUPPORTED; rc = token_specific.t_handle_event(tokdata, event_type, event_flags, payload, payload_len); TRACE_INFO("SC_HandleEvent: rc = 0x%08lx, event_type = 0x%08x, " "event_flags = 0x%08x\n", rc, event_type, event_flags); return rc; } 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 = SC_DigestEncryptUpdate; function_list.ST_DecryptDigestUpdate = SC_DecryptDigestUpdate; function_list.ST_SignEncryptUpdate = SC_SignEncryptUpdate; function_list.ST_DecryptVerifyUpdate = 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; function_list.ST_SessionCancel = SC_SessionCancel; function_list.ST_EncapsulateKey = SC_EncapsulateKey; function_list.ST_DecapsulateKey = SC_DecapsulateKey; function_list.ST_VerifySignatureInit = SC_VerifySignatureInit; function_list.ST_VerifySignature = SC_VerifySignature; function_list.ST_VerifySignatureUpdate = SC_VerifySignatureUpdate; function_list.ST_VerifySignatureFinal = SC_VerifySignatureFinal; function_list.ST_IBM_ReencryptSingle = SC_IBM_ReencryptSingle; function_list.ST_HandleEvent = SC_HandleEvent; } opencryptoki-opencryptoki-451d99c/usr/lib/icsf_stdll/pbkdf.c000066400000000000000000000511371520105705100242720ustar00rootroot00000000000000/* * 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 #include #include #include "pkcs11types.h" #include "defs.h" #include "host_defs.h" #include "h_extern.h" #include "pbkdf.h" #include "trace.h" #include "platform.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, const char *group) { struct stat sb; struct group *grp; if (group == NULL || group[0] == '\0') group = PKCS_GROUP; if (fstat(file, &sb) != 0) { TRACE_DEVEL("fstat failed: %s\n", strerror(errno)); return CKR_FUNCTION_FAILED; } grp = getgrnam(group); if (grp == NULL) { TRACE_DEVEL("getgrnam(%s) failed: %s\n", group, strerror(errno)); return CKR_FUNCTION_FAILED; } /* Set absolute permissions or rw-rw----, if not already as expected */ if ((sb.st_mode & ~S_IFMT) != (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)) { if (fchmod(file, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) != 0) { TRACE_DEVEL("fchmod(rw-rw----) failed: %s\n", strerror(errno)); return CKR_FUNCTION_FAILED; } } /* set ownership to pkcs11 group, if not already as expected */ if (sb.st_gid != grp->gr_gid) { if (fchown(file, -1, grp->gr_gid) != 0) { TRACE_DEVEL("fchown(-1, %s) failed: %s\n", group, strerror(errno)); return CKR_FUNCTION_FAILED; } } return CKR_OK; } CK_RV encrypt_aes(STDLL_TokData_t *tokdata, CK_BYTE * inbuf, int inbuflen, CK_BYTE * dkey, CK_BYTE * iv, CK_BYTE * outbuf, int *outbuflen, CK_BBOOL wrap) { const EVP_CIPHER *cipher = EVP_aes_256_cbc(); int tmplen; EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); if (!EVP_EncryptInit_ex(ctx, cipher, NULL, dkey, iv)) { TRACE_ERROR("EVP_EncryptInit_ex failed.\n"); return CKR_FUNCTION_FAILED; } 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); if (tokdata != NULL && (tokdata->statistics->flags & STATISTICS_FLAG_COUNT_INTERNAL) != 0) { if (wrap) tokdata->statistics->increment_func(tokdata->statistics, tokdata->slot_id, &tokdata->store_strength.wrap_crypt, tokdata->store_strength.wrap_strength); else tokdata->statistics->increment_func(tokdata->statistics, tokdata->slot_id, &tokdata->store_strength.mk_crypt, tokdata->store_strength.mk_strength); } return CKR_OK; } CK_RV decrypt_aes(STDLL_TokData_t *tokdata, CK_BYTE * inbuf, int inbuflen, CK_BYTE * dkey, CK_BYTE * iv, CK_BYTE * outbuf, int *outbuflen, CK_BBOOL unwrap) { int size; const EVP_CIPHER *cipher = EVP_aes_256_cbc(); EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); if (!EVP_DecryptInit_ex(ctx, cipher, NULL, dkey, iv)) { TRACE_ERROR("EVP_DecryptInit_ex failed.\n"); return CKR_FUNCTION_FAILED; } 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); if (tokdata != NULL && (tokdata->statistics->flags & STATISTICS_FLAG_COUNT_INTERNAL) != 0) { if (unwrap) tokdata->statistics->increment_func(tokdata->statistics, tokdata->slot_id, &tokdata->store_strength.wrap_crypt, tokdata->store_strength.wrap_strength); else tokdata->statistics->increment_func(tokdata->statistics, tokdata->slot_id, &tokdata->store_strength.mk_crypt, tokdata->store_strength.mk_strength); } return CKR_OK; } CK_RV get_masterkey(STDLL_TokData_t *tokdata, 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, version; 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(&version, sizeof(CK_ULONG_32), 1, fp); if (ret != 1) { fclose(fp); TRACE_ERROR("fread failed.\n"); return CKR_FUNCTION_FAILED; } /* * Version 1 files did not have the version field, thus the first field read * is the total length. If the first field is not a known version number, * we assume it is an old version file. For an old version file, the total * length is 64 bytes, this is it is much higher than the version number. */ if (version == ICSF_MK_FILE_VERSION) { /* New version file detected */ ret = fread(&totallen, sizeof(CK_ULONG_32), 1, fp); if (ret != 1) { fclose(fp); TRACE_ERROR("fread failed.\n"); return CKR_FUNCTION_FAILED; } } else { TRACE_DEVEL("Old version master key file detected\n"); totallen = version; } 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; if (version == ICSF_MK_FILE_VERSION) rc = pbkdf_openssl(tokdata, pin, pinlen, salt, dkey, dkeysize); else rc = pbkdf_old(tokdata, 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(tokdata, outbuf, datasize, dkey, salt, masterkey, len, CK_TRUE); 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(STDLL_TokData_t *tokdata, CK_BYTE * masterkey, CK_ULONG mklen, CK_BYTE * racfpwd, int *racflen) { char fname[PATH_MAX]; 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 ... */ snprintf(fname, sizeof(fname), "%s/%s", tokdata->data_store, RACFFILE); if ((stat(fname, &statbuf) < 0) && (errno == ENOENT)) { TRACE_ERROR("File does not exist.\n"); return CKR_FUNCTION_FAILED; } /* if file exists, open it */ fp = fopen(fname, "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(tokdata, outbuf, datasize, masterkey, iv, racfpwd, racflen, CK_FALSE); /* 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_openssl(STDLL_TokData_t *tokdata, CK_BYTE *password, CK_ULONG len, CK_BYTE *salt, CK_BYTE *dkey, CK_ULONG klen) { const CK_MECHANISM mech = { CKM_PKCS5_PBKD2, NULL, 0 }; const CK_MECHANISM mech2 = { CKM_SHA256_HMAC, NULL, 0 }; int rc; if (!password || !salt || len > INT_MAX || klen > INT_MAX) { TRACE_ERROR("Invalid function argument(s).\n"); return CKR_FUNCTION_FAILED; } rc = PKCS5_PBKDF2_HMAC((char *)password, len, salt, SALTSIZE, ITERATIONS, EVP_sha256(), klen, dkey); if (rc != 1) { TRACE_ERROR("PBKDF2 failed.\n"); return CKR_FUNCTION_FAILED; } if (tokdata != NULL && (tokdata->statistics->flags & STATISTICS_FLAG_COUNT_INTERNAL) != 0) { tokdata->statistics->increment_func(tokdata->statistics, tokdata->slot_id, &mech, POLICY_STRENGTH_IDX_0); if ((tokdata->statistics->flags & STATISTICS_FLAG_COUNT_IMPLICIT) != 0) { /* * We use CKM_PKCS5_PBKD2 with CKP_PKCS5_PBKD2_HMAC_SHA256. * Use strength 0 because the HMAC key is the pin, and it is max * 8 char (i.e. 64 bit) long, which is way below 112 bit anyway. */ tokdata->statistics->increment_func(tokdata->statistics, tokdata->slot_id, &mech2, POLICY_STRENGTH_IDX_0); } } return CKR_OK; } CK_RV pbkdf_old(STDLL_TokData_t *tokdata, 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; const CK_MECHANISM mech = { CKM_PKCS5_PBKD2, NULL, 0 }; const CK_MECHANISM mech2 = { CKM_SHA256_HMAC, NULL, 0 }; /* 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: if (rc == CKR_OK && tokdata != NULL && (tokdata->statistics->flags & STATISTICS_FLAG_COUNT_INTERNAL) != 0) { tokdata->statistics->increment_func(tokdata->statistics, tokdata->slot_id, &mech, POLICY_STRENGTH_IDX_0); if ((tokdata->statistics->flags & STATISTICS_FLAG_COUNT_IMPLICIT) != 0) { /* * We use CKM_PKCS5_PBKD2 with CKP_PKCS5_PBKD2_HMAC_SHA256. * Use strength 0 because the HMAC key is the pin, and it is max * 8 char (i.e. 64 bit) long, which is way below 112 bit anyway. */ tokdata->statistics->increment_func(tokdata->statistics, tokdata->slot_id, &mech2, POLICY_STRENGTH_IDX_0); } } return rc; } CK_RV secure_racf(STDLL_TokData_t *tokdata, CK_BYTE * racf, CK_ULONG racflen, CK_BYTE * key, CK_ULONG keylen, const char *tokname) { 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; char fname[PATH_MAX]; 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(tokdata, racf, racflen, key, iv, output, &outputlen, CK_FALSE); 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; snprintf(fname, sizeof(fname), "%s/%s/%s", CONFIG_PATH, tokname, RACFFILE); /* CWE-59 fix: Use fopen_nofollow to prevent symlink attacks */ fp = fopen_nofollow(fname, "w"); if (!fp) { if (errno == ELOOP) TRACE_ERROR("Refusing to follow symlink: %s\n", fname); else TRACE_ERROR("fopen failed: %s\n", strerror(errno)); return CKR_FUNCTION_FAILED; } /* set permisions on the file */ rc = set_perms(fileno(fp), tokdata != NULL ? tokdata->tokgroup : NULL); 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(STDLL_TokData_t *tokdata, 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, version; 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_openssl(tokdata, 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(tokdata, masterkey, len, dkey, salt, output, &outputlen, CK_TRUE); 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. version field * 2. total length = salt + encrypted data * 3. salt (always SALTSIZE) * 4. encrypted data */ /* get the total length */ totallen = outputlen + SALTSIZE; /* CWE-59 fix: Use fopen_nofollow to prevent symlink attacks */ fp = fopen_nofollow(fname, "w"); if (!fp) { if (errno == ELOOP) TRACE_ERROR("Refusing to follow symlink: %s\n", fname); else TRACE_ERROR("fopen failed: %s\n", strerror(errno)); return CKR_FUNCTION_FAILED; } /* set permisions on the file */ rc = set_perms(fileno(fp), tokdata != NULL ? tokdata->tokgroup : NULL); 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 (always new version format) */ version = ICSF_MK_FILE_VERSION; (void) fwrite(&version, sizeof(CK_ULONG_32), 1, fp); (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; } opencryptoki-opencryptoki-451d99c/usr/lib/icsf_stdll/pbkdf.h000066400000000000000000000045671520105705100243040ustar00rootroot00000000000000/* * 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 // same define in pkcsconf #define ENCRYPT_SIZE 96 // PIN_SIZE + AES_BLOCK_SIZE (for padding) /* * SP 800-132 recommends a minimum iteration count of 1000. * so lets try that for now... */ #define ITERATIONS 1000 #define RACFFILE "RACF" #define ICSF_MK_FILE_VERSION 2 CK_RV get_randombytes(unsigned char *output, int bytes); CK_RV encrypt_aes(STDLL_TokData_t *tokdata, CK_BYTE * racfpwd, int racflen, CK_BYTE * dkey, CK_BYTE * iv, CK_BYTE * outbuf, int *outbuflen, CK_BBOOL wrap); CK_RV decrypt_aes(STDLL_TokData_t *tokdata, CK_BYTE * edata, int edatalen, CK_BYTE * dkey, CK_BYTE * iv, CK_BYTE * ddata, int *ddatalen, CK_BBOOL unwrap); CK_RV get_racf(STDLL_TokData_t *tokdata, CK_BYTE * mk, CK_ULONG mklen, CK_BYTE * racfpwd, int *racflen); CK_RV get_masterkey(STDLL_TokData_t *tokdata, CK_BYTE *pin, CK_ULONG pinlen, const char *fname, CK_BYTE *masterkey, int *len); CK_RV pbkdf_old(STDLL_TokData_t *tokdata, CK_BYTE * passwd, CK_ULONG passwdlen, CK_BYTE * salt, CK_BYTE * dkey, CK_ULONG klen); CK_RV pbkdf_openssl(STDLL_TokData_t *tokdata, CK_BYTE *password, CK_ULONG len, CK_BYTE *salt, CK_BYTE *dkey, CK_ULONG klen); CK_RV secure_racf(STDLL_TokData_t *tokdata, CK_BYTE * racfpwd, CK_ULONG racflen, CK_BYTE * mk, CK_ULONG mklen, const char *tokname); CK_RV secure_masterkey(STDLL_TokData_t *tokdata, CK_BYTE * masterkey, CK_ULONG len, CK_BYTE * pin, CK_ULONG pinlen, const char *fname); #endif opencryptoki-opencryptoki-451d99c/usr/lib/icsf_stdll/tok_struct.h000066400000000000000000000150001520105705100253770ustar00rootroot00000000000000/* * 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", FALSE, // 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, // get_token_info 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_edwards_sign NULL, // ec_edwards_verify NULL, // ec_generate_keypair NULL, // ec_edwards_generate_keypair NULL, // ec_montgomery_generate_keypair NULL, // ecdh_derive NULL, // ecdh_derive_kdf // 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, // SHAKE derive NULL, // shake_key_derive //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_xts_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 NULL, // aes_xts NULL, // aes_key_wrap // DSA NULL, // dsa_generate_keypair NULL, // dsa_sign NULL, // dsa_verify // PQC NULL, // ibm_ml_dsa_generate_keypair NULL, // ibm_ml_dsa_sign NULL, // ibm_ml_dsa_verify NULL, // ibm_ml_kem_generate_keypair NULL, // ibm_ml_kem_derive NULL, // ml_dsa_generate_keypair NULL, // ml_dsa_sign NULL, // ml_dsa_verify NULL, // ml_kem_generate_keypair NULL, // ml_kem_encapsulate_key NULL, // ml_kem_decapsulate_key NULL, // get_mechanism_list NULL, // get_mechanism_info NULL, // object_add NULL, // key_wrap NULL, // key_unwrap NULL, // encapsulate_rsa_sym_keygen NULL, // encapsulate_rsa_key_wrap NULL, // encapsulate_rsa_key_unwrap NULL, // encapsulate_dh_ecdh_key_pair_gen NULL, // en_decapsulate_dh_ecdh_derive_key NULL, // reencrypt_single NULL, // set_attribute_values NULL, // set_attrs_for_new_object NULL, // handle_event NULL, // check_obj_access }; #endif opencryptoki-opencryptoki-451d99c/usr/lib/lib.mk000066400000000000000000000010521520105705100220000ustar00rootroot00000000000000if 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 include usr/lib/config/config.mk include usr/lib/hsm_mk_change/hsm_mk_change.mk opencryptoki-opencryptoki-451d99c/usr/lib/soft_stdll/000077500000000000000000000000001520105705100230605ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/usr/lib/soft_stdll/soft_specific.c000066400000000000000000002463721520105705100260620ustar00rootroot00000000000000/* * 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 #include "platform.h" #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 #if OPENSSL_VERSION_PREREQ(3, 0) #include #include #include #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, OPENSSL_RSA_MAX_MODULUS_BITS, 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}}, {CKM_RSA_PKCS, {512, OPENSSL_RSA_MAX_MODULUS_BITS, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP | CKF_SIGN | CKF_VERIFY | CKF_SIGN_RECOVER | CKF_VERIFY_RECOVER | CKF_ENCAPSULATE | CKF_DECAPSULATE}}, {CKM_SHA1_RSA_PKCS, {512, OPENSSL_RSA_MAX_MODULUS_BITS, CKF_SIGN | CKF_VERIFY}}, {CKM_SHA224_RSA_PKCS, {512, OPENSSL_RSA_MAX_MODULUS_BITS, CKF_SIGN|CKF_VERIFY}}, {CKM_SHA256_RSA_PKCS, {512, OPENSSL_RSA_MAX_MODULUS_BITS, CKF_SIGN | CKF_VERIFY}}, {CKM_SHA384_RSA_PKCS, {512, OPENSSL_RSA_MAX_MODULUS_BITS, CKF_SIGN | CKF_VERIFY}}, {CKM_SHA512_RSA_PKCS, {512, OPENSSL_RSA_MAX_MODULUS_BITS, CKF_SIGN | CKF_VERIFY}}, {CKM_SHA3_224_RSA_PKCS, {512, OPENSSL_RSA_MAX_MODULUS_BITS, CKF_SIGN | CKF_VERIFY}}, {CKM_SHA3_256_RSA_PKCS, {512, OPENSSL_RSA_MAX_MODULUS_BITS, CKF_SIGN | CKF_VERIFY}}, {CKM_SHA3_384_RSA_PKCS, {512, OPENSSL_RSA_MAX_MODULUS_BITS, CKF_SIGN | CKF_VERIFY}}, {CKM_SHA3_512_RSA_PKCS, {512, OPENSSL_RSA_MAX_MODULUS_BITS, CKF_SIGN | CKF_VERIFY}}, {CKM_RSA_PKCS_PSS, {512, OPENSSL_RSA_MAX_MODULUS_BITS, CKF_SIGN | CKF_VERIFY}}, {CKM_SHA1_RSA_PKCS_PSS, {512, OPENSSL_RSA_MAX_MODULUS_BITS, CKF_SIGN | CKF_VERIFY}}, {CKM_SHA224_RSA_PKCS_PSS, {512, OPENSSL_RSA_MAX_MODULUS_BITS, CKF_SIGN | CKF_VERIFY}}, {CKM_SHA256_RSA_PKCS_PSS, {512, OPENSSL_RSA_MAX_MODULUS_BITS, CKF_SIGN | CKF_VERIFY}}, {CKM_SHA384_RSA_PKCS_PSS, {512, OPENSSL_RSA_MAX_MODULUS_BITS, CKF_SIGN | CKF_VERIFY}}, {CKM_SHA512_RSA_PKCS_PSS, {512, OPENSSL_RSA_MAX_MODULUS_BITS, CKF_SIGN | CKF_VERIFY}}, {CKM_SHA3_224_RSA_PKCS_PSS, {512, OPENSSL_RSA_MAX_MODULUS_BITS, CKF_SIGN | CKF_VERIFY}}, {CKM_SHA3_256_RSA_PKCS_PSS, {512, OPENSSL_RSA_MAX_MODULUS_BITS, CKF_SIGN | CKF_VERIFY}}, {CKM_SHA3_384_RSA_PKCS_PSS, {512, OPENSSL_RSA_MAX_MODULUS_BITS, CKF_SIGN | CKF_VERIFY}}, {CKM_SHA3_512_RSA_PKCS_PSS, {512, OPENSSL_RSA_MAX_MODULUS_BITS, CKF_SIGN | CKF_VERIFY}}, #if !(NOX509) {CKM_RSA_X_509, {512, OPENSSL_RSA_MAX_MODULUS_BITS, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP | CKF_SIGN | CKF_VERIFY | CKF_SIGN_RECOVER | CKF_VERIFY_RECOVER}}, #endif {CKM_RSA_PKCS_OAEP, {512, OPENSSL_RSA_MAX_MODULUS_BITS, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP | CKF_ENCAPSULATE | CKF_DECAPSULATE}}, #if !(NOMD2) {CKM_MD2_RSA_PKCS, {512, OPENSSL_RSA_MAX_MODULUS_BITS, CKF_SIGN | CKF_VERIFY}}, #endif #if !(NOMD5) {CKM_MD5_RSA_PKCS, {512, OPENSSL_RSA_MAX_MODULUS_BITS, CKF_SIGN | CKF_VERIFY}}, #endif {CKM_RSA_AES_KEY_WRAP, {512, OPENSSL_RSA_MAX_MODULUS_BITS, CKF_WRAP | CKF_UNWRAP}}, #if !(NODSA) {CKM_DSA, {512, 1024, CKF_SIGN | CKF_VERIFY}}, #endif /* Begin code contributed by Corrent corp. */ #if !(NODH) {CKM_DH_PKCS_DERIVE, {512, 8192, CKF_DERIVE | CKF_ENCAPSULATE | CKF_DECAPSULATE}}, {CKM_DH_PKCS_KEY_PAIR_GEN, {512, 8192, 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}}, {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_DES_OFB64, {24, 24, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}}, {CKM_DES_CFB8, {24, 24, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}}, {CKM_DES_CFB64, {24, 24, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}}, {CKM_DES3_MAC, {16, 24, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {CKM_DES3_MAC_GENERAL, {16, 24, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {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, {80, 2048, CKF_SIGN | CKF_VERIFY}}, {CKM_SHA_1_HMAC_GENERAL, {80, 2048, CKF_SIGN | CKF_VERIFY}}, {CKM_SHA1_KEY_DERIVATION, {8, 160, CKF_DERIVE}}, #endif {CKM_SHA224, {0, 0, CKF_DIGEST}}, {CKM_SHA224_HMAC, {112, 2048, CKF_SIGN|CKF_VERIFY}}, {CKM_SHA224_HMAC_GENERAL, {112, 2048, CKF_SIGN|CKF_VERIFY}}, {CKM_SHA224_KEY_DERIVATION, {8, 224, CKF_DERIVE}}, {CKM_SHA256, {0, 0, CKF_DIGEST}}, {CKM_SHA256_HMAC, {128, 2048, CKF_SIGN | CKF_VERIFY}}, {CKM_SHA256_HMAC_GENERAL, {128, 2048, CKF_SIGN | CKF_VERIFY}}, {CKM_SHA256_KEY_DERIVATION, {8, 256, CKF_DERIVE}}, {CKM_SHA384, {0, 0, CKF_DIGEST}}, {CKM_SHA384_HMAC, {192, 2048, CKF_SIGN | CKF_VERIFY}}, {CKM_SHA384_HMAC_GENERAL, {192, 2048, CKF_SIGN | CKF_VERIFY}}, {CKM_SHA384_KEY_DERIVATION, {8, 384, CKF_DERIVE}}, {CKM_SHA512, {0, 0, CKF_DIGEST}}, {CKM_SHA512_HMAC, {256, 2048, CKF_SIGN | CKF_VERIFY}}, {CKM_SHA512_HMAC_GENERAL, {256, 2048, CKF_SIGN | CKF_VERIFY}}, {CKM_SHA512_KEY_DERIVATION, {8, 512, CKF_DERIVE}}, #ifdef NID_sha512_224WithRSAEncryption {CKM_SHA512_224, {0, 0, CKF_DIGEST}}, {CKM_SHA512_224_HMAC, {112, 2048, CKF_SIGN | CKF_VERIFY}}, {CKM_SHA512_224_HMAC_GENERAL, {112, 2048, CKF_SIGN | CKF_VERIFY}}, {CKM_SHA512_224_KEY_DERIVATION, {8, 224, CKF_DERIVE}}, #endif #ifdef NID_sha512_256WithRSAEncryption {CKM_SHA512_256, {0, 0, CKF_DIGEST}}, {CKM_SHA512_256_HMAC, {128, 2048, CKF_SIGN | CKF_VERIFY}}, {CKM_SHA512_256_HMAC_GENERAL, {128, 2048, CKF_SIGN | CKF_VERIFY}}, {CKM_SHA512_256_KEY_DERIVATION, {8, 256, CKF_DERIVE}}, #endif #ifdef NID_sha3_224 {CKM_SHA3_224, {0, 0, CKF_DIGEST}}, {CKM_SHA3_224_HMAC, {112, 2048, CKF_SIGN | CKF_VERIFY}}, {CKM_SHA3_224_HMAC_GENERAL, {112, 2048, CKF_SIGN | CKF_VERIFY}}, {CKM_SHA3_224_KEY_DERIVATION, {8, 224, CKF_DERIVE}}, {CKM_IBM_SHA3_224, {0, 0, CKF_DIGEST}}, {CKM_IBM_SHA3_224_HMAC, {112, 2048, CKF_SIGN | CKF_VERIFY}}, #endif #ifdef NID_sha3_256 {CKM_SHA3_256, {0, 0, CKF_DIGEST}}, {CKM_SHA3_256_HMAC, {128, 2048, CKF_SIGN | CKF_VERIFY}}, {CKM_SHA3_256_HMAC_GENERAL, {128, 2048, CKF_SIGN | CKF_VERIFY}}, {CKM_SHA3_256_KEY_DERIVATION, {8, 256, CKF_DERIVE}}, {CKM_IBM_SHA3_256, {0, 0, CKF_DIGEST}}, {CKM_IBM_SHA3_256_HMAC, {128, 2048, CKF_SIGN | CKF_VERIFY}}, #endif #ifdef NID_sha3_384 {CKM_SHA3_384, {0, 0, CKF_DIGEST}}, {CKM_SHA3_384_HMAC, {192, 2048, CKF_SIGN | CKF_VERIFY}}, {CKM_SHA3_384_HMAC_GENERAL, {192, 2048, CKF_SIGN | CKF_VERIFY}}, {CKM_SHA3_384_KEY_DERIVATION, {8, 384, CKF_DERIVE}}, {CKM_IBM_SHA3_384, {0, 0, CKF_DIGEST}}, {CKM_IBM_SHA3_384_HMAC, {192, 2048, CKF_SIGN | CKF_VERIFY}}, #endif #ifdef NID_sha3_512 {CKM_SHA3_512, {0, 0, CKF_DIGEST}}, {CKM_SHA3_512_HMAC, {256, 2048, CKF_SIGN | CKF_VERIFY}}, {CKM_SHA3_512_HMAC_GENERAL, {256, 2048, CKF_SIGN | CKF_VERIFY}}, {CKM_SHA3_512_KEY_DERIVATION, {8, 512, CKF_DERIVE}}, {CKM_IBM_SHA3_512, {0, 0, CKF_DIGEST}}, {CKM_IBM_SHA3_512_HMAC, {256, 2048, CKF_SIGN | CKF_VERIFY}}, #endif #if !(NOMD2) {CKM_MD2, {0, 0, CKF_DIGEST}}, {CKM_MD2_HMAC, {8, 2048, CKF_SIGN | CKF_VERIFY}}, {CKM_MD2_HMAC_GENERAL, {8, 2048, CKF_SIGN | CKF_VERIFY}}, #endif #if !(NOMD5) {CKM_MD5, {0, 0, CKF_DIGEST}}, {CKM_MD5_HMAC, {8, 2048, CKF_SIGN | CKF_VERIFY}}, {CKM_MD5_HMAC_GENERAL, {8, 2048, CKF_SIGN | CKF_VERIFY}}, #endif {CKM_SHAKE_128_KEY_DERIVATION, {8, 2048, CKF_DERIVE}}, {CKM_SHAKE_256_KEY_DERIVATION, {8, 2048, CKF_DERIVE}}, {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_XTS_KEY_GEN, {32, 64, 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_CTR, {16, 32, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}}, #if OPENSSL_VERSION_PREREQ(3, 0) || OPENSSL_VERSION_NUMBER >= 0x101010cfL /* * AES-OFB currently only works with >= OpenSSl 3.0, or >= OpenSSL 1.1.1l, * due to a bug in OpenSSL <= 1.1.1k in s390x_aes_ofb_cipher() not updating * the IV in the context. */ {CKM_AES_OFB, {16, 32, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}}, {CKM_AES_CFB8, {16, 32, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}}, {CKM_AES_CFB128, {16, 32, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}}, #endif {CKM_AES_GCM, {16, 32, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}}, {CKM_AES_MAC, {16, 32, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {CKM_AES_MAC_GENERAL, {16, 32, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {CKM_AES_CMAC, {16, 32, CKF_SIGN | CKF_VERIFY}}, {CKM_AES_CMAC_GENERAL, {16, 32, CKF_SIGN | CKF_VERIFY}}, {CKM_AES_XTS, {32, 64, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}}, {CKM_AES_KEY_WRAP, {32, 64, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}}, {CKM_AES_KEY_WRAP_PAD, {32, 64, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}}, {CKM_AES_KEY_WRAP_KWP, {32, 64, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}}, {CKM_AES_KEY_WRAP_PKCS7, {32, 64, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}}, {CKM_GENERIC_SECRET_KEY_GEN, {80, 2048, CKF_GENERATE}}, {CKM_SHA_1_KEY_GEN, {80, 2048, CKF_GENERATE}}, {CKM_SHA224_KEY_GEN, {80, 2048, CKF_GENERATE}}, {CKM_SHA256_KEY_GEN, {80, 2048, CKF_GENERATE}}, {CKM_SHA384_KEY_GEN, {80, 2048, CKF_GENERATE}}, {CKM_SHA512_KEY_GEN, {80, 2048, CKF_GENERATE}}, {CKM_SHA512_224_KEY_GEN, {80, 2048, CKF_GENERATE}}, {CKM_SHA512_256_KEY_GEN, {80, 2048, CKF_GENERATE}}, {CKM_SHA3_224_KEY_GEN, {80, 2048, CKF_GENERATE}}, {CKM_SHA3_256_KEY_GEN, {80, 2048, CKF_GENERATE}}, {CKM_SHA3_384_KEY_GEN, {80, 2048, CKF_GENERATE}}, {CKM_SHA3_512_KEY_GEN, {80, 2048, CKF_GENERATE}}, #if !(NO_EC) {CKM_EC_KEY_PAIR_GEN, {160, 521, CKF_GENERATE_KEY_PAIR | CKF_EC_OID | CKF_EC_F_P | CKF_EC_UNCOMPRESS | CKF_EC_COMPRESS}}, {CKM_ECDSA, {160, 521, CKF_SIGN | CKF_VERIFY | CKF_EC_OID | CKF_EC_F_P | CKF_EC_UNCOMPRESS | CKF_EC_COMPRESS}}, {CKM_ECDSA_SHA1, {160, 521, CKF_SIGN | CKF_VERIFY | CKF_EC_OID | CKF_EC_F_P | CKF_EC_UNCOMPRESS | CKF_EC_COMPRESS}}, {CKM_ECDSA_SHA224, {160, 521, CKF_SIGN | CKF_VERIFY | CKF_EC_OID | CKF_EC_F_P | CKF_EC_UNCOMPRESS | CKF_EC_COMPRESS}}, {CKM_ECDSA_SHA256, {160, 521, CKF_SIGN | CKF_VERIFY | CKF_EC_OID | CKF_EC_F_P | CKF_EC_UNCOMPRESS | CKF_EC_COMPRESS}}, {CKM_ECDSA_SHA384, {160, 521, CKF_SIGN | CKF_VERIFY | CKF_EC_OID | CKF_EC_F_P | CKF_EC_UNCOMPRESS | CKF_EC_COMPRESS}}, {CKM_ECDSA_SHA512, {160, 521, CKF_SIGN | CKF_VERIFY | CKF_EC_OID | CKF_EC_F_P | CKF_EC_UNCOMPRESS | CKF_EC_COMPRESS}}, {CKM_ECDSA_SHA3_224, {160, 521, CKF_SIGN | CKF_VERIFY | CKF_EC_OID | CKF_EC_F_P | CKF_EC_UNCOMPRESS | CKF_EC_COMPRESS}}, {CKM_ECDSA_SHA3_256, {160, 521, CKF_SIGN | CKF_VERIFY | CKF_EC_OID | CKF_EC_F_P | CKF_EC_UNCOMPRESS | CKF_EC_COMPRESS}}, {CKM_ECDSA_SHA3_384, {160, 521, CKF_SIGN | CKF_VERIFY | CKF_EC_OID | CKF_EC_F_P | CKF_EC_UNCOMPRESS | CKF_EC_COMPRESS}}, {CKM_ECDSA_SHA3_512, {160, 521, CKF_SIGN | CKF_VERIFY | CKF_EC_OID | CKF_EC_F_P | CKF_EC_UNCOMPRESS | CKF_EC_COMPRESS}}, {CKM_ECDH1_DERIVE, {160, 521, CKF_DERIVE | CKF_EC_OID | CKF_EC_F_P | CKF_EC_UNCOMPRESS | CKF_EC_COMPRESS | CKF_ENCAPSULATE | CKF_DECAPSULATE}}, {CKM_ECDH1_COFACTOR_DERIVE, {160, 521, CKF_DERIVE | CKF_EC_OID | CKF_EC_F_P | CKF_EC_UNCOMPRESS | CKF_EC_COMPRESS | CKF_ENCAPSULATE | CKF_DECAPSULATE}}, {CKM_ECDH_AES_KEY_WRAP, {160, 521, CKF_WRAP | CKF_UNWRAP | CKF_EC_OID | CKF_EC_F_P | CKF_EC_UNCOMPRESS | CKF_EC_COMPRESS}}, {CKM_ECDH_COF_AES_KEY_WRAP, {160, 521, CKF_WRAP | CKF_UNWRAP | CKF_EC_OID | CKF_EC_F_P | CKF_EC_UNCOMPRESS | CKF_EC_COMPRESS}}, #endif #if OPENSSL_VERSION_PREREQ(3, 0) {CKM_EC_EDWARDS_KEY_PAIR_GEN, {255, 448, CKF_GENERATE_KEY_PAIR | CKF_EC_OID | CKF_EC_F_P | CKF_EC_COMPRESS}}, {CKM_EC_MONTGOMERY_KEY_PAIR_GEN, {255, 448, CKF_GENERATE_KEY_PAIR | CKF_EC_OID | CKF_EC_F_P | CKF_EC_COMPRESS}}, {CKM_EDDSA, {255, 448, CKF_SIGN | CKF_VERIFY | CKF_EC_OID | CKF_EC_F_P | CKF_EC_COMPRESS}}, {CKM_ECDH_X_AES_KEY_WRAP, {255, 448, CKF_WRAP | CKF_UNWRAP | CKF_EC_OID | CKF_EC_F_P | CKF_EC_COMPRESS}}, {CKM_IBM_DILITHIUM, {256, 256, CKF_GENERATE_KEY_PAIR | CKF_SIGN | CKF_VERIFY}}, {CKM_IBM_ML_DSA_KEY_PAIR_GEN, {1312, 2592, CKF_GENERATE_KEY_PAIR}}, {CKM_IBM_ML_DSA, {1312, 2592, CKF_SIGN | CKF_VERIFY}}, {CKM_IBM_ML_KEM_KEY_PAIR_GEN, {800, 1568, CKF_GENERATE_KEY_PAIR}}, {CKM_IBM_ML_KEM, {800, 1568, CKF_DERIVE}}, {CKM_IBM_ML_KEM_WITH_ECDH, {800, 1568, CKF_DERIVE}}, {CKM_ML_DSA_KEY_PAIR_GEN, {1312, 2592, CKF_GENERATE_KEY_PAIR}}, {CKM_ML_DSA, {1312, 2592, CKF_SIGN | CKF_VERIFY}}, #ifdef OSSL_SIGNATURE_PARAM_MESSAGE_ENCODING {CKM_HASH_ML_DSA, {1312, 2592, CKF_SIGN | CKF_VERIFY}}, {CKM_HASH_ML_DSA_SHA224, {1312, 2592, CKF_SIGN | CKF_VERIFY}}, {CKM_HASH_ML_DSA_SHA256, {1312, 2592, CKF_SIGN | CKF_VERIFY}}, {CKM_HASH_ML_DSA_SHA384, {1312, 2592, CKF_SIGN | CKF_VERIFY}}, {CKM_HASH_ML_DSA_SHA512, {1312, 2592, CKF_SIGN | CKF_VERIFY}}, {CKM_HASH_ML_DSA_SHA3_224, {1312, 2592, CKF_SIGN | CKF_VERIFY}}, {CKM_HASH_ML_DSA_SHA3_256, {1312, 2592, CKF_SIGN | CKF_VERIFY}}, {CKM_HASH_ML_DSA_SHA3_384, {1312, 2592, CKF_SIGN | CKF_VERIFY}}, {CKM_HASH_ML_DSA_SHA3_512, {1312, 2592, CKF_SIGN | CKF_VERIFY}}, {CKM_HASH_ML_DSA_SHAKE128, {1312, 2592, CKF_SIGN | CKF_VERIFY}}, {CKM_HASH_ML_DSA_SHAKE256, {1312, 2592, CKF_SIGN | CKF_VERIFY}}, #endif {CKM_ML_KEM_KEY_PAIR_GEN, {800, 1568, CKF_GENERATE_KEY_PAIR}}, {CKM_ML_KEM, {800, 1568, CKF_ENCAPSULATE | CKF_DECAPSULATE}}, #endif {CKM_PUB_KEY_FROM_PRIV_KEY, {0, 0, CKF_DERIVE }}, }; static const CK_ULONG soft_mech_list_len = (sizeof(soft_mech_list) / sizeof(MECH_LIST_ELEMENT)); struct soft_private_data { #if OPENSSL_VERSION_PREREQ(3, 0) OSSL_PROVIDER *oqs_provider; CK_BBOOL supports_dilithium; CK_BBOOL supports_ml_dsa; CK_BBOOL supports_ml_kem; #else void *dummy; #endif }; CK_RV token_specific_init(STDLL_TokData_t *tokdata, CK_SLOT_ID SlotNumber, char *conf_name) { struct soft_private_data *soft_private; #if OPENSSL_VERSION_PREREQ(3, 0) const struct pqc_oid *oid; #endif CK_RV rc; UNUSED(conf_name); TRACE_INFO("soft %s slot=%lu running\n", __func__, SlotNumber); rc = ock_generic_filter_mechanism_list(tokdata, soft_mech_list, soft_mech_list_len, &(tokdata->mech_list), &(tokdata->mech_list_len)); if (rc != CKR_OK) { TRACE_ERROR("Mechanism filtering failed! rc = 0x%lx\n", rc); goto error; } soft_private = calloc(1, sizeof(*soft_private)); if (soft_private == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto error; } #if OPENSSL_VERSION_PREREQ(3, 0) /* * Try to load the 'oqsprovider'. This optional provider must be installed * and configured separately, it does not come with OpenSSL 3.x by default. * If loading the 'oqsprovider' fails, this is not an error, it just means * that the soft token may not support any quantum safe mechanisms, if not * also OpenSSL >= 3.5 is use, which has built-in support for ML-DSA. */ soft_private->oqs_provider = OSSL_PROVIDER_load(NULL, "oqsprovider"); if (soft_private->oqs_provider == NULL) { TRACE_DEVEL("OSSL_PROVIDER_load for 'oqsprovider' failed, no quantum " "safe mechanisms are supported.\n"); ERR_pop_to_mark(); }; oid = find_pqc_by_keyform(dilithium_oids, CK_IBM_DILITHIUM_KEYFORM_ROUND3_44); if (oid != NULL && openssl_get_pqc_oid_name(oid)!= NULL) soft_private->supports_dilithium = CK_TRUE; oid = find_pqc_by_keyform(ml_dsa_oids, CKP_ML_DSA_44); if (oid != NULL && openssl_get_pqc_oid_name(oid)!= NULL) soft_private->supports_ml_dsa = CK_TRUE; oid = find_pqc_by_keyform(ml_dsa_oids, CKP_ML_KEM_512); if (oid != NULL && openssl_get_pqc_oid_name(oid)!= NULL) soft_private->supports_ml_kem = CK_TRUE; #endif tokdata->private_data = soft_private; return CKR_OK; error: token_specific_final(tokdata, FALSE); return rc; } CK_RV token_specific_final(STDLL_TokData_t *tokdata, CK_BBOOL in_fork_initializer) { struct soft_private_data *soft_private = tokdata->private_data; UNUSED(in_fork_initializer); TRACE_INFO("soft %s running\n", __func__); if (tokdata->mech_list != NULL) free(tokdata->mech_list); if (soft_private != NULL) { #if OPENSSL_VERSION_PREREQ(3, 0) if (soft_private->oqs_provider != NULL) OSSL_PROVIDER_unload(soft_private->oqs_provider); soft_private->oqs_provider = NULL; #endif free(soft_private); tokdata->private_data = NULL; } return CKR_OK; } static CK_BBOOL token_specific_filter_mechanism(STDLL_TokData_t *tokdata, CK_MECHANISM_TYPE mechanism, CK_MECHANISM_INFO *info) { #if OPENSSL_VERSION_PREREQ(3, 0) struct soft_private_data *soft_private = tokdata->private_data; #else UNUSED(tokdata); #endif UNUSED(info); switch(mechanism) { #if OPENSSL_VERSION_PREREQ(3, 0) case CKM_IBM_DILITHIUM: return soft_private->supports_dilithium; case CKM_IBM_ML_DSA_KEY_PAIR_GEN: case CKM_IBM_ML_DSA: case CKM_ML_DSA_KEY_PAIR_GEN: case CKM_ML_DSA: case CKM_HASH_ML_DSA: case CKM_HASH_ML_DSA_SHA224: case CKM_HASH_ML_DSA_SHA256: case CKM_HASH_ML_DSA_SHA384: case CKM_HASH_ML_DSA_SHA512: case CKM_HASH_ML_DSA_SHA3_224: case CKM_HASH_ML_DSA_SHA3_256: case CKM_HASH_ML_DSA_SHA3_384: case CKM_HASH_ML_DSA_SHA3_512: case CKM_HASH_ML_DSA_SHAKE128: case CKM_HASH_ML_DSA_SHAKE256: return soft_private->supports_ml_dsa; case CKM_IBM_ML_KEM_KEY_PAIR_GEN: case CKM_IBM_ML_KEM: case CKM_IBM_ML_KEM_WITH_ECDH: case CKM_ML_KEM_KEY_PAIR_GEN: case CKM_ML_KEM: return soft_private->supports_ml_kem; #endif default: return CK_TRUE; } } CK_RV token_specific_des_key_gen(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_BYTE **des_key, CK_ULONG *len, CK_ULONG keysize, CK_BBOOL *is_opaque) { UNUSED(tmpl); *des_key = malloc(keysize); if (*des_key == NULL) return CKR_HOST_MEMORY; *len = keysize; *is_opaque = FALSE; // 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 (keysize == (3 * DES_KEY_SIZE)) { rng_generate(tokdata, *des_key, keysize); } else { do { rng_generate(tokdata, *des_key, keysize);; } 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) { return openssl_specific_des_ecb(tokdata, in_data, in_data_len, out_data, out_data_len, key, encrypt); } 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) { return openssl_specific_des_cbc(tokdata, in_data, in_data_len, out_data, out_data_len, key, init_v, encrypt); } 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) { return openssl_specific_tdes_ecb(tokdata, in_data, in_data_len, out_data, out_data_len, key, encrypt); } 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) { return openssl_specific_tdes_cbc(tokdata, in_data, in_data_len, out_data, out_data_len, key, init_v, encrypt); } 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 *init_v, uint_32 direction) { return openssl_specific_tdes_ofb(tokdata, in_data, data_len, out_data, key, init_v, direction); } 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 *init_v, uint_32 cfb_len, uint_32 direction) { return openssl_specific_tdes_cfb(tokdata, in_data, data_len, out_data, key, init_v, cfb_len, direction); } CK_RV token_specific_tdes_mac(STDLL_TokData_t *tokdata, CK_BYTE *message, CK_ULONG message_len, OBJECT *key, CK_BYTE *mac) { return openssl_specific_tdes_mac(tokdata, message, message_len, key, mac); } 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) { return openssl_specific_tdes_cmac(tokdata, message, message_len, key, mac, first, last, ctx); } CK_RV token_specific_rsa_generate_keypair(STDLL_TokData_t *tokdata, TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl) { UNUSED(tokdata); return openssl_specific_rsa_keygen(publ_tmpl, priv_tmpl); } 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) { return openssl_specific_rsa_pkcs_encrypt(tokdata, in_data, in_data_len, out_data, out_data_len, key_obj, openssl_specific_rsa_encrypt); } 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) { return openssl_specific_rsa_pkcs_decrypt(tokdata, in_data, in_data_len, out_data, out_data_len, key_obj, openssl_specific_rsa_decrypt); } 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) { return openssl_specific_rsa_pkcs_sign(tokdata, sess, in_data, in_data_len, out_data, out_data_len, key_obj, openssl_specific_rsa_decrypt); } 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) { return openssl_specific_rsa_pkcs_verify(tokdata, sess, in_data, in_data_len, signature, sig_len, key_obj, openssl_specific_rsa_encrypt); } 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) { return openssl_specific_rsa_pkcs_verify_recover(tokdata, signature, sig_len, out_data, out_data_len, key_obj, openssl_specific_rsa_encrypt); } 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) { return openssl_specific_rsa_pss_sign(tokdata, sess, ctx, in_data, in_data_len, sig, sig_len, openssl_specific_rsa_decrypt); } 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) { return openssl_specific_rsa_pss_verify(tokdata, sess, ctx, in_data, in_data_len, signature, sig_len, openssl_specific_rsa_encrypt); } 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) { return openssl_specific_rsa_x509_encrypt(tokdata, in_data, in_data_len, out_data, out_data_len, key_obj, openssl_specific_rsa_encrypt); } 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) { return openssl_specific_rsa_x509_decrypt(tokdata, in_data, in_data_len, out_data, out_data_len, key_obj, openssl_specific_rsa_decrypt); } 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) { return openssl_specific_rsa_x509_sign(tokdata, in_data, in_data_len, out_data, out_data_len, key_obj, openssl_specific_rsa_decrypt); } 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) { return openssl_specific_rsa_x509_verify(tokdata, in_data, in_data_len, signature, sig_len, key_obj, openssl_specific_rsa_encrypt); } 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) { return openssl_specific_rsa_x509_verify_recover(tokdata, signature, sig_len, out_data, out_data_len, key_obj, openssl_specific_rsa_encrypt); } 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) { return openssl_specific_rsa_oaep_encrypt(tokdata, ctx, in_data, in_data_len, out_data, out_data_len, hash, hlen, openssl_specific_rsa_encrypt); } 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) { return openssl_specific_rsa_oaep_decrypt(tokdata, ctx, in_data, in_data_len, out_data, out_data_len, hash, hlen, openssl_specific_rsa_decrypt); } CK_RV token_specific_aes_key_gen(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_BYTE **key, CK_ULONG *len, CK_ULONG keysize, CK_BBOOL *is_opaque) { UNUSED(tmpl); *key = malloc(keysize); if (*key == NULL) return CKR_HOST_MEMORY; *len = keysize; *is_opaque = FALSE; return rng_generate(tokdata, *key, keysize); } CK_RV token_specific_aes_xts_key_gen(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_BYTE **key, CK_ULONG *len, CK_ULONG keysize, CK_BBOOL *is_opaque) { CK_RV rc; UNUSED(tmpl); *key = malloc(keysize); if (*key == NULL) return CKR_HOST_MEMORY; *len = keysize; *is_opaque = FALSE; do { rc = rng_generate(tokdata, *key, keysize); if (rc != CKR_OK) return rc; } while (memcmp(*key, (*key) + keysize / 2, keysize / 2) == 0); return CKR_OK; } CK_RV token_specific_aes_ecb(STDLL_TokData_t *tokdata, SESSION *sess, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, OBJECT *key, CK_BYTE encrypt) { UNUSED(sess); return openssl_specific_aes_ecb(tokdata, in_data, in_data_len, out_data, out_data_len, key, encrypt); } CK_RV token_specific_aes_cbc(STDLL_TokData_t *tokdata, SESSION *sess, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, OBJECT *key, CK_BYTE *init_v, CK_BYTE encrypt) { UNUSED(sess); return openssl_specific_aes_cbc(tokdata, in_data, in_data_len, out_data, out_data_len, key, init_v, encrypt); } 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) { return openssl_specific_aes_ctr(tokdata, in_data, in_data_len, out_data, out_data_len, key, counterblock, counter_width, 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) { return openssl_specific_aes_ofb(tokdata, in_data, in_data_len, out_data, key, init_v, direction); } 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 cfb_len, uint_32 direction) { return openssl_specific_aes_cfb(tokdata, in_data, in_data_len, out_data, key, init_v, cfb_len, direction); } 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) { return openssl_specific_aes_gcm_init(tokdata, sess, ctx, mech, key, encrypt); } 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) { return openssl_specific_aes_gcm(tokdata, sess, ctx, in_data, in_data_len, out_data, out_data_len, encrypt); } 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) { return openssl_specific_aes_gcm_update(tokdata, sess, ctx, in_data, in_data_len, out_data, out_data_len, encrypt); } 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) { return openssl_specific_aes_gcm_final(tokdata, sess, ctx, out_data, out_data_len, encrypt); } CK_RV token_specific_aes_mac(STDLL_TokData_t *tokdata, CK_BYTE *message, CK_ULONG message_len, OBJECT *key, CK_BYTE *mac) { return openssl_specific_aes_mac(tokdata, message, message_len, key, mac); } CK_RV token_specific_aes_cmac(STDLL_TokData_t *tokdata, SESSION *session, CK_BYTE *message, CK_ULONG message_len, OBJECT *key, CK_BYTE *mac, CK_BBOOL first, CK_BBOOL last, CK_VOID_PTR *ctx) { UNUSED(session); return openssl_specific_aes_cmac(tokdata, message, message_len, key, mac, first, last, ctx); } CK_RV token_specific_aes_xts(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 *tweak, CK_BOOL encrypt, CK_BBOOL initial, CK_BBOOL final, CK_BYTE* iv) { UNUSED(sess); return openssl_specific_aes_xts(tokdata, in_data, in_data_len, out_data, out_data_len, key_obj, tweak, encrypt, initial, final, iv); } CK_RV token_specific_aes_key_wrap(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 *iv, CK_ULONG iv_len, CK_BBOOL encrypt, CK_BBOOL pad) { UNUSED(sess); return openssl_specific_aes_key_wrap(tokdata, in_data, in_data_len, out_data, out_data_len, key_obj, iv, iv_len, encrypt, pad); } /* 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 = CKR_OK; BIGNUM *bn_z, *bn_y, *bn_x, *bn_p, *bn_tmp; BN_CTX *ctx = NULL; UNUSED(tokdata); // Create and Init the BIGNUM structures. bn_y = BN_new(); bn_x = BN_secure_new(); bn_p = BN_new(); bn_z = BN_new(); bn_tmp = BN_new(); if (bn_z == NULL || bn_p == NULL || bn_x == NULL || bn_y == NULL || bn_tmp == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto out; } // Initialize context ctx = BN_CTX_new(); if (ctx == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto out; } // Add data into these new BN structures if (BN_bin2bn((unsigned char *) y, y_len, bn_y) == NULL || BN_bin2bn((unsigned char *) x, x_len, bn_x) == NULL || BN_bin2bn((unsigned char *) p, p_len, bn_p) == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto out; } if (BN_mod_exp(bn_z, bn_y, bn_x, bn_p, ctx) == 0) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto out; } /* Error if z <= 1 or z = p - 1 as per SP800-56Ar3 Section 5.7.1.1 */ if (BN_copy(bn_tmp, bn_p) == NULL || !BN_sub_word(bn_tmp, 1) || BN_cmp(bn_z, BN_value_one()) <= 0 || BN_cmp(bn_z, bn_tmp) == 0) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto out; } /* Derived secret is the same number of bytes as the modulus p */ if (*z_len < (CK_ULONG)BN_num_bytes(bn_p)) { TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); rc = CKR_BUFFER_TOO_SMALL; goto out; } *z_len = BN_num_bytes(bn_p); if (BN_bn2binpad(bn_z, z, *z_len) <= 0) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto out; } out: if (bn_y != NULL) BN_free(bn_y); if (bn_x != NULL) BN_clear_free(bn_x); if (bn_p != NULL) BN_free(bn_p); if (bn_z != NULL) BN_free(bn_z); if (bn_tmp != NULL) BN_free(bn_tmp); if (ctx != NULL) BN_CTX_free(ctx); return rc; } /* 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_RV rv; 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 = NULL, *temp_byte2 = NULL; CK_ULONG temp_bn_len, value_bits; #if !OPENSSL_VERSION_PREREQ(3, 0) DH *dh = NULL; #else EVP_PKEY_CTX *pctx = NULL; OSSL_PARAM_BLD *tmpl = NULL; OSSL_PARAM *osparams = NULL; #endif BIGNUM *bn_p = NULL; BIGNUM *bn_g = NULL; #if !OPENSSL_VERSION_PREREQ(3, 0) const BIGNUM *temp_bn = NULL; #else BIGNUM *temp_bn = NULL; #endif EVP_PKEY *params = NULL, *pkey = NULL; EVP_PKEY_CTX *ctx = NULL; UNUSED(tokdata); rv = template_attribute_get_non_empty(publ_tmpl, CKA_PRIME, &prime_attr); if (rv != CKR_OK) { TRACE_ERROR("Could not find CKA_PRIME for the key.\n"); goto done; } rv = template_attribute_get_non_empty(publ_tmpl, CKA_BASE, &base_attr); if (rv != CKR_OK) { TRACE_ERROR("Could not find CKA_BASE for the key.\n"); goto done; } if ((prime_attr->ulValueLen > 1024) || (prime_attr->ulValueLen < 64)) { TRACE_ERROR("CKA_PRIME attribute value is invalid.\n"); rv = CKR_ATTRIBUTE_VALUE_INVALID; goto done; } // Create and init BIGNUM structs bn_p = BN_new(); bn_g = BN_new(); if (bn_g == NULL || bn_p == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rv = CKR_HOST_MEMORY; goto done; } // Convert from strings to BIGNUMs BN_bin2bn((unsigned char *) prime_attr->pValue, prime_attr->ulValueLen, bn_p); BN_bin2bn((unsigned char *) base_attr->pValue, base_attr->ulValueLen, bn_g); #if !OPENSSL_VERSION_PREREQ(3, 0) dh = DH_new(); if (dh == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rv = CKR_FUNCTION_FAILED; goto done; } DH_set0_pqg(dh, bn_p, NULL, bn_g); /* bn_p and bn_q freed together with dh */ bn_p = NULL; bn_g = NULL; /* CKA_VALUE_BITS is optional */ if (template_attribute_get_ulong(priv_tmpl, CKA_VALUE_BITS, &value_bits) == CKR_OK && value_bits > 0) DH_set_length(dh, value_bits); params = EVP_PKEY_new(); if (params == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rv = CKR_HOST_MEMORY; goto done; } if (EVP_PKEY_assign_DH(params, dh) != 1) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rv = CKR_FUNCTION_FAILED; goto done; } dh = NULL; /* freed together with params */ #else tmpl = OSSL_PARAM_BLD_new(); if (tmpl == NULL) { rv = CKR_HOST_MEMORY; goto done; } if (!OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_FFC_P, bn_p) || !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_FFC_G, bn_g)) { rv = CKR_FUNCTION_FAILED; goto done; } /* CKA_VALUE_BITS is optional */ if (template_attribute_get_ulong(priv_tmpl, CKA_VALUE_BITS, &value_bits) == CKR_OK) { if (!OSSL_PARAM_BLD_push_long(tmpl, OSSL_PKEY_PARAM_DH_PRIV_LEN, value_bits)) { rv = CKR_FUNCTION_FAILED; goto done; } } osparams = OSSL_PARAM_BLD_to_param(tmpl); if (osparams == NULL) { rv = CKR_FUNCTION_FAILED; goto done; } pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_DH, NULL); if (pctx == NULL) { rv = CKR_FUNCTION_FAILED; goto done; } if (!EVP_PKEY_fromdata_init(pctx) || !EVP_PKEY_fromdata(pctx, ¶ms, EVP_PKEY_PUBLIC_KEY, osparams)) { rv = CKR_FUNCTION_FAILED; goto done; } #endif ctx = EVP_PKEY_CTX_new(params, NULL); if (ctx == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rv = CKR_HOST_MEMORY; goto done; } if (EVP_PKEY_keygen_init(ctx) != 1 || EVP_PKEY_keygen(ctx, &pkey) != 1 #if !OPENSSL_VERSION_PREREQ(3, 0) /* dh is freed together with pkey */ || (dh = (DH *)EVP_PKEY_get0_DH(pkey)) == NULL) { #else ) { #endif TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rv = CKR_FUNCTION_FAILED; goto done; } // Extract the public and private key components from the DH struct, // and insert them in the publ_tmpl and priv_tmpl // // pub_key // #if !OPENSSL_VERSION_PREREQ(3, 0) DH_get0_key(dh, &temp_bn, NULL); #else if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PUB_KEY, &temp_bn)) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rv = CKR_FUNCTION_FAILED; goto done; } #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 rv = build_attribute(CKA_VALUE, temp_byte, temp_bn_len, &temp_attr); if (rv != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto done; } rv = template_update_attribute(publ_tmpl, temp_attr); if (rv != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); free(temp_attr); goto done; } #if OPENSSL_VERSION_PREREQ(3, 0) BN_free(temp_bn); temp_bn = NULL; #endif // // priv_key // #if !OPENSSL_VERSION_PREREQ(3, 0) DH_get0_key(dh, NULL, &temp_bn); #else if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY, &temp_bn)) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rv = CKR_FUNCTION_FAILED; goto done; } #endif temp_bn_len = BN_num_bytes(temp_bn); temp_byte2 = malloc(temp_bn_len); temp_bn_len = BN_bn2bin(temp_bn, temp_byte2); // in bytes rv = build_attribute(CKA_VALUE, temp_byte2, temp_bn_len, &temp_attr); OPENSSL_cleanse(temp_byte2, temp_bn_len); if (rv != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto done; } rv = template_update_attribute(priv_tmpl, temp_attr); if (rv != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); free(temp_attr); goto done; } #if OPENSSL_VERSION_PREREQ(3, 0) BN_free(temp_bn); temp_bn = NULL; #endif // Update CKA_VALUE_BITS attribute in the private key value_bits_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_ULONG)); if (value_bits_attr == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rv = CKR_HOST_MEMORY; goto done; } 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; rv = template_update_attribute(priv_tmpl, value_bits_attr); if (rv != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); free(temp_attr); goto done; } // Add prime and base to the private key template rv = build_attribute(CKA_PRIME, (unsigned char *) prime_attr->pValue, prime_attr->ulValueLen, &temp_attr); // in bytes if (rv != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto done; } rv = template_update_attribute(priv_tmpl, temp_attr); if (rv != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); free(temp_attr); goto done; } rv = build_attribute(CKA_BASE, (unsigned char *) base_attr->pValue, base_attr->ulValueLen, &temp_attr); // in bytes if (rv != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto done; } rv = template_update_attribute(priv_tmpl, temp_attr); if (rv != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); free(temp_attr); goto done; } rv = CKR_OK; done: if (bn_g != NULL) BN_free(bn_g); if (bn_p != NULL) BN_free(bn_p); if (pkey != NULL) EVP_PKEY_free(pkey); if (ctx != NULL) EVP_PKEY_CTX_free(ctx); if (params != NULL) EVP_PKEY_free(params); free(temp_byte); free(temp_byte2); #if OPENSSL_VERSION_PREREQ(3, 0) if (pctx != NULL) EVP_PKEY_CTX_free(pctx); if (tmpl != NULL) OSSL_PARAM_BLD_free(tmpl); if (osparams != NULL) OSSL_PARAM_free(osparams); if (temp_bn != NULL) BN_free(temp_bn); #endif return rv; } /* 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, &token_specific_filter_mechanism); } 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, &token_specific_filter_mechanism); } CK_RV token_specific_sha_init(STDLL_TokData_t *tokdata, DIGEST_CONTEXT *ctx, CK_MECHANISM *mech) { return openssl_specific_sha_init(tokdata, ctx, mech); } 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) { return openssl_specific_sha(tokdata, ctx, in_data, in_data_len, out_data, out_data_len); } CK_RV token_specific_sha_update(STDLL_TokData_t *tokdata, DIGEST_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len) { return openssl_specific_sha_update(tokdata, ctx, in_data, in_data_len); } CK_RV token_specific_sha_final(STDLL_TokData_t *tokdata, DIGEST_CONTEXT *ctx, CK_BYTE *out_data, CK_ULONG *out_data_len) { return openssl_specific_sha_final(tokdata, ctx, out_data, out_data_len); } CK_RV token_specific_shake_key_derive(STDLL_TokData_t *tokdata, SESSION *sess, CK_MECHANISM *mech, OBJECT *base_key_obj, CK_KEY_TYPE base_key_type, OBJECT *derived_key_obj, CK_KEY_TYPE derived_key_type, CK_ULONG derived_key_len) { return openssl_specific_shake_key_derive(tokdata, sess, mech, base_key_obj, base_key_type, derived_key_obj, derived_key_type, derived_key_len); } CK_RV token_specific_hmac_sign_init(STDLL_TokData_t *tokdata, SESSION *sess, CK_MECHANISM *mech, CK_OBJECT_HANDLE Hkey) { return openssl_specific_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 openssl_specific_hmac_init(tokdata, &sess->verify_ctx, mech, Hkey); } 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 openssl_specific_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 openssl_specific_hmac(&sess->verify_ctx, in_data, in_data_len, signature, &sig_len, FALSE); } 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 openssl_specific_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 openssl_specific_hmac_update(&sess->verify_ctx, in_data, in_data_len, FALSE); } CK_RV token_specific_hmac_sign_final(STDLL_TokData_t *tokdata, SESSION *sess, CK_BYTE *signature, CK_ULONG *sig_len) { UNUSED(tokdata); return openssl_specific_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 openssl_specific_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 *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_get_ulong(tmpl, CKA_VALUE_LEN, &key_length); if (rc != CKR_OK) { TRACE_ERROR("CKA_VALUE_LEN missing in (HMAC) key template\n"); return CKR_TEMPLATE_INCOMPLETE; } //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. 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"); free(gkey); } return rc; } #ifndef NO_EC CK_RV token_specific_ec_generate_keypair(STDLL_TokData_t *tokdata, TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl) { return openssl_specific_ec_generate_keypair(tokdata, publ_tmpl, priv_tmpl, CKM_EC_KEY_PAIR_GEN); } CK_RV token_specific_ec_edwards_generate_keypair(STDLL_TokData_t *tokdata, TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl) { return openssl_specific_ec_generate_keypair(tokdata, publ_tmpl, priv_tmpl, CKM_EC_EDWARDS_KEY_PAIR_GEN); } CK_RV token_specific_ec_montgomery_generate_keypair(STDLL_TokData_t *tokdata, TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl) { return openssl_specific_ec_generate_keypair(tokdata, publ_tmpl, priv_tmpl, CKM_EC_MONTGOMERY_KEY_PAIR_GEN); } 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) { return openssl_specific_ec_sign(tokdata, sess, in_data, in_data_len, out_data, out_data_len, key_obj); } 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) { return openssl_specific_ec_verify(tokdata, sess, in_data, in_data_len, signature, signature_len, key_obj); } CK_RV token_specific_ec_edwards_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_MECHANISM *mech) { return openssl_specific_ec_edwards_sign(tokdata, sess, in_data, in_data_len, out_data, out_data_len, key_obj, mech); } CK_RV token_specific_ec_edwards_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, CK_MECHANISM * mech) { return openssl_specific_ec_edwards_verify(tokdata, sess, in_data, in_data_len, signature, signature_len, key_obj, mech); } 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, CK_BBOOL cofactor_mode) { return openssl_specific_ecdh_pkcs_derive(tokdata, priv_bytes, priv_length, pub_bytes, pub_length, secret_value, secret_value_len, oid, oid_length, cofactor_mode); } #endif #if OPENSSL_VERSION_PREREQ(3, 0) static CK_RV import_pqc_key(STDLL_TokData_t *tokdata, OBJECT *obj, CK_KEY_TYPE keytype) { const struct pqc_oid *oid = NULL; const char *alg_name; CK_ATTRIBUTE *attr = NULL; CK_OBJECT_CLASS class; CK_BYTE *data = NULL; CK_ULONG data_len; CK_MECHANISM_TYPE mech; EVP_PKEY *pkey = NULL; size_t pub_len = 0; CK_BYTE *pub_key = NULL; CK_RV rc; switch (keytype) { case CKK_IBM_DILITHIUM: mech = CKM_IBM_DILITHIUM; break; case CKK_IBM_ML_DSA: mech = CKM_IBM_ML_DSA; break; case CKK_IBM_ML_KEM: mech = CKM_IBM_ML_KEM; break; case CKK_ML_DSA: mech = CKM_ML_DSA; break; case CKK_ML_KEM: mech = CKM_ML_KEM; break; default: return CKR_KEY_TYPE_INCONSISTENT; } if (!token_specific_filter_mechanism(tokdata, mech, NULL)) return CKR_MECHANISM_INVALID; rc = template_attribute_get_ulong(obj->template, CKA_CLASS, &class); if (rc != CKR_OK) return CKR_OK; switch (keytype) { case CKK_IBM_DILITHIUM: case CKK_IBM_KYBER: case CKK_IBM_ML_DSA: case CKK_IBM_ML_KEM: /* A clear IBM Dilithium key must either have a CKA_VALUE containing * the SPKI or PKCS#8 encoded private key, or must have a keyform/mode * value and the individual attributes. * A clear ML-DSA or ML-KEM key must have a CKA_VALUE containing the SPKI * or PKCS#8 encoded private key. Individual key attributes are not used. */ if (template_attribute_find(obj->template, CKA_VALUE, &attr) == TRUE && attr->ulValueLen > 0 && attr->pValue != NULL) { switch (class) { case CKO_PRIVATE_KEY: /* Private key in PKCS#8 form is present in CKA_VALUE */ rc = pqc_priv_unwrap(obj->template, keytype, attr->pValue, attr->ulValueLen, FALSE); if (rc != CKR_OK) { TRACE_ERROR("Failed to decode private key from " "CKA_VALUE.\n"); return rc; } break; case CKO_PUBLIC_KEY: /* Public key in SPKI form is present in CKA_VALUE */ rc = pqc_priv_unwrap_get_data(obj->template, keytype, attr->pValue, attr->ulValueLen, FALSE); if (rc != CKR_OK) { TRACE_ERROR("Failed to decode public key from " "CKA_VALUE.\n"); return rc; } break; default: return CKR_TEMPLATE_INCONSISTENT; } } else { /* Add CKA_VALUE with PKCS#8 or SPKI */ switch (class) { case CKO_PRIVATE_KEY: rc = pqc_priv_wrap_get_data(obj->template, keytype, FALSE, &data, &data_len); if (rc != CKR_OK) { TRACE_ERROR("Failed to encode private key.\n"); return rc; } break; case CKO_PUBLIC_KEY: rc = pqc_publ_get_spki(obj->template, keytype, FALSE, &data, &data_len, FALSE); if (rc != CKR_OK) { TRACE_ERROR("Failed to encode public key.\n"); return rc; } break; default: return CKR_TEMPLATE_INCONSISTENT; } rc = build_attribute(CKA_VALUE, data, data_len, &attr); OPENSSL_cleanse(data, data_len); free(data); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute CKA_VALUE failed\n"); return rc; } rc = template_update_attribute(obj->template, attr); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute CKA_VALUE failed.\n"); free(attr); return rc; } } break; default: /* ML-DSA and ML-KEM have raw key components in CKA_VALUE */ break; } oid = pqc_get_keyform_mode(obj->template, mech); if (oid == NULL) { TRACE_ERROR("%s Failed to determine PQC OID\n", __func__); return CKR_TEMPLATE_INCOMPLETE; } alg_name = openssl_get_pqc_oid_name(oid); if (alg_name == NULL) { TRACE_ERROR("PQC key form is not supported by oqsprovider or " "OpenSSL\n"); return CKR_KEY_SIZE_RANGE; } if (class == CKO_PRIVATE_KEY && (keytype == CKK_IBM_ML_DSA || keytype == CKK_IBM_ML_KEM)) { /* * Try to add public key attributes if IBM ML-DSA or IBM ML-KEM * private key. */ rc = openssl_make_pqc_key_from_template(obj->template, oid, mech, TRUE, alg_name, &pkey); if (rc != CKR_OK) return rc; rc = openssl_get_key_from_pkey(pkey, OSSL_PKEY_PARAM_PUB_KEY, &pub_key, &pub_len, FALSE); EVP_PKEY_free(pkey); if (rc == CKR_OK) { rc = pqc_unpack_pub_key(pub_key, pub_len, oid, mech, obj->template); free(pub_key); if (rc != CKR_OK) { TRACE_ERROR("pqc_unpack_pub_key failed for pub key\n"); return rc; } } } rc = pqc_add_keyform_mode(obj->template, oid, mech); if (rc != CKR_OK) { TRACE_ERROR("pqc_add_keyform_mode failed\n"); return rc; } return CKR_OK; } #endif CK_RV token_specific_object_add(STDLL_TokData_t * tokdata, SESSION * sess, OBJECT * obj) { CK_ATTRIBUTE *value = NULL; CK_KEY_TYPE keytype; #ifndef NO_EC EVP_PKEY *ec_key = NULL; #endif CK_RV rc; #if !OPENSSL_VERSION_PREREQ(3, 0) UNUSED(tokdata); #endif UNUSED(sess); rc = template_attribute_get_ulong(obj->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) return CKR_OK; switch (keytype) { #ifndef NO_EC case CKK_EC: case CKK_EC_EDWARDS: case CKK_EC_MONTGOMERY: /* Check if OpenSSL supports the curve */ rc = openssl_make_ec_key_from_template(obj->template, &ec_key); if (ec_key != NULL) EVP_PKEY_free(ec_key); return rc; #endif case CKK_AES_XTS: rc = template_attribute_get_non_empty(obj->template, CKA_VALUE, &value); if (rc != CKR_OK) { TRACE_ERROR("Failed to get CKA_VALUE\n"); return rc; } if (memcmp(value->pValue, ((CK_BYTE *)value->pValue) + value->ulValueLen / 2, value->ulValueLen / 2) == 0) { TRACE_ERROR("The 2 key parts of an AES-XTS key can not be the same\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } return CKR_OK; #if OPENSSL_VERSION_PREREQ(3, 0) case CKK_IBM_DILITHIUM: case CKK_IBM_ML_DSA: case CKK_IBM_ML_KEM: case CKK_ML_DSA: case CKK_ML_KEM: return import_pqc_key(tokdata, obj, keytype); #endif default: return CKR_OK; } } CK_RV token_specific_set_attrs_for_new_object(STDLL_TokData_t *tokdata, CK_OBJECT_CLASS class, CK_ULONG mode, TEMPLATE *tmpl) { CK_KEY_TYPE keytype; EVP_PKEY *pkey = NULL; CK_RV rc; #if OPENSSL_VERSION_PREREQ(3, 0) const struct pqc_oid *oid = NULL; const char *alg_name; CK_MECHANISM_TYPE mech; #else UNUSED(tokdata); UNUSED(class); #endif if (mode != MODE_UNWRAPPED) return CKR_OK; rc = template_attribute_get_ulong(tmpl, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) return CKR_OK; switch (keytype) { case CKK_DES: case CKK_DES3: case CKK_AES: case CKK_AES_XTS: case CKK_GENERIC_SECRET: case CKK_SHA_1_HMAC: case CKK_SHA224_HMAC: case CKK_SHA256_HMAC: case CKK_SHA384_HMAC: case CKK_SHA512_HMAC: case CKK_SHA3_224_HMAC: case CKK_SHA3_256_HMAC: case CKK_SHA3_384_HMAC: case CKK_SHA3_512_HMAC: case CKK_SHA512_224_HMAC: case CKK_SHA512_256_HMAC: #if !(NODH) case CKK_DH: #endif #if !(NODSA) case CKK_DSA: #endif case CKK_RSA: return CKR_OK; #ifndef NO_EC case CKK_EC: case CKK_EC_EDWARDS: case CKK_EC_MONTGOMERY: /* Check if OpenSSL supports the curve */ rc = openssl_make_ec_key_from_template(tmpl, &pkey); if (pkey != NULL) EVP_PKEY_free(pkey); return rc; #endif #if OPENSSL_VERSION_PREREQ(3, 0) case CKK_IBM_DILITHIUM: case CKK_IBM_ML_DSA: case CKK_IBM_ML_KEM: case CKK_ML_DSA: case CKK_ML_KEM: switch (keytype) { case CKK_IBM_DILITHIUM: mech = CKM_IBM_DILITHIUM; break; case CKK_IBM_ML_DSA: mech = CKM_IBM_ML_DSA; break; case CKK_IBM_ML_KEM: mech = CKM_IBM_ML_KEM; break; case CKK_ML_DSA: mech = CKM_ML_DSA; break; case CKK_ML_KEM: mech = CKM_ML_KEM; break; default: return CKR_KEY_TYPE_INCONSISTENT; } if (!token_specific_filter_mechanism(tokdata, mech, NULL)) return CKR_MECHANISM_INVALID; oid = pqc_get_keyform_mode(tmpl, mech); if (oid == NULL) { TRACE_ERROR("%s Failed to determine dilithium OID\n", __func__); return CKR_TEMPLATE_INCOMPLETE; } alg_name = openssl_get_pqc_oid_name(oid); if (alg_name == NULL) { TRACE_ERROR("Dilithium key form is not supported by oqsprovider\n"); return CKR_KEY_SIZE_RANGE; } /* Check if the oqsprovider or OpenSSL supports the variant */ rc = openssl_make_pqc_key_from_template(tmpl, oid, mech, class == CKO_PRIVATE_KEY, alg_name, &pkey); if (pkey != NULL) EVP_PKEY_free(pkey); return rc; #endif default: return CKR_KEY_TYPE_INCONSISTENT; } } #if OPENSSL_VERSION_PREREQ(3, 0) CK_RV token_specific_ibm_ml_dsa_generate_keypair(STDLL_TokData_t *tokdata, CK_MECHANISM *mech, const struct pqc_oid *oid, TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl) { if (!token_specific_filter_mechanism(tokdata, mech->mechanism, NULL)) return CKR_MECHANISM_INVALID; return openssl_specific_pqc_generate_keypair(tokdata, oid, mech, publ_tmpl, priv_tmpl); } CK_RV token_specific_ibm_ml_dsa_sign(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, const struct pqc_oid *oid, CK_MECHANISM *mech, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *signature, CK_ULONG *signature_len, OBJECT *key_obj) { if (!token_specific_filter_mechanism(tokdata, mech->mechanism, NULL)) return CKR_MECHANISM_INVALID; return openssl_specific_pqc_sign(tokdata, sess, length_only, oid, mech, in_data, in_data_len, signature, signature_len, key_obj, TRUE); } CK_RV token_specific_ibm_ml_dsa_verify(STDLL_TokData_t *tokdata, SESSION *sess, const struct pqc_oid *oid, CK_MECHANISM *mech, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *signature, CK_ULONG signature_len, OBJECT *key_obj) { if (!token_specific_filter_mechanism(tokdata, mech->mechanism, NULL)) return CKR_MECHANISM_INVALID; return openssl_specific_pqc_verify(tokdata, sess, oid, mech, in_data, in_data_len, signature, signature_len, key_obj, TRUE); } CK_RV token_specific_ibm_ml_kem_generate_keypair(STDLL_TokData_t *tokdata, CK_MECHANISM *mech, const struct pqc_oid *oid, TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl) { if (!token_specific_filter_mechanism(tokdata, mech->mechanism, NULL)) return CKR_MECHANISM_INVALID; return openssl_specific_pqc_generate_keypair(tokdata, oid, mech, publ_tmpl, priv_tmpl); } CK_RV token_specific_ibm_ml_kem_derive(STDLL_TokData_t *tokdata, SESSION *sess, const struct pqc_oid *oid, CK_MECHANISM *mech, OBJECT *base_object, CK_OBJECT_CLASS base_key_class, CK_KEY_TYPE base_key_type, OBJECT *derived_object, CK_KEY_TYPE derived_key_type, CK_ULONG derived_keylen) { if (!token_specific_filter_mechanism(tokdata, mech->mechanism, NULL)) return CKR_MECHANISM_INVALID; return openssl_specific_pqc_kem_derive(tokdata, sess, oid, mech, base_object, base_key_class, base_key_type, derived_object, derived_key_type, derived_keylen); } CK_RV token_specific_ml_dsa_generate_keypair(STDLL_TokData_t *tokdata, const struct pqc_oid *oid, TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl) { CK_MECHANISM mech = { CKM_ML_DSA_KEY_PAIR_GEN, NULL, 0 }; if (!token_specific_filter_mechanism(tokdata, mech.mechanism, NULL)) return CKR_MECHANISM_INVALID; return openssl_specific_pqc_generate_keypair(tokdata, oid, &mech, publ_tmpl, priv_tmpl); } CK_RV token_specific_ml_dsa_sign(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, const struct pqc_oid *oid, CK_MECHANISM *mech, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *signature, CK_ULONG *signature_len, OBJECT *key_obj, CK_BBOOL final_part) { if (!token_specific_filter_mechanism(tokdata, mech->mechanism, NULL)) return CKR_MECHANISM_INVALID; return openssl_specific_pqc_sign(tokdata, sess, length_only, oid, mech, in_data, in_data_len, signature, signature_len, key_obj, final_part); } CK_RV token_specific_ml_dsa_verify(STDLL_TokData_t *tokdata, SESSION *sess, const struct pqc_oid *oid, CK_MECHANISM *mech, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *signature, CK_ULONG signature_len, OBJECT *key_obj, CK_BBOOL final_part) { if (!token_specific_filter_mechanism(tokdata, mech->mechanism, NULL)) return CKR_MECHANISM_INVALID; return openssl_specific_pqc_verify(tokdata, sess, oid, mech, in_data, in_data_len, signature, signature_len, key_obj, final_part); } CK_RV token_specific_ml_kem_generate_keypair(STDLL_TokData_t *tokdata, const struct pqc_oid *oid, TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl) { CK_MECHANISM mech = { CKM_ML_KEM_KEY_PAIR_GEN, NULL, 0 }; if (!token_specific_filter_mechanism(tokdata, mech.mechanism, NULL)) return CKR_MECHANISM_INVALID; return openssl_specific_pqc_generate_keypair(tokdata, oid, &mech, publ_tmpl, priv_tmpl); } CK_RV token_specific_ml_kem_encapsulate_key(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, const struct pqc_oid *oid, CK_MECHANISM *mech, OBJECT *key_obj, CK_ATTRIBUTE *pTemplate, CK_ULONG ulAttributeCount, CK_BYTE *pCiphertext, CK_ULONG *pulCiphertextLen, CK_KEY_TYPE keytype, CK_ULONG keylen, CK_OBJECT_HANDLE *phKey) { if (!token_specific_filter_mechanism(tokdata, mech->mechanism, NULL)) return CKR_MECHANISM_INVALID; return openssl_specific_pqc_encapsulate_key(tokdata, sess, length_only, oid, mech, key_obj, pTemplate, ulAttributeCount, pCiphertext, pulCiphertextLen, keytype, keylen, phKey); } CK_RV token_specific_ml_kem_decapsulate_key(STDLL_TokData_t *tokdata, SESSION *sess, const struct pqc_oid *oid, CK_MECHANISM *mech, OBJECT *key_obj, CK_ATTRIBUTE *pTemplate, CK_ULONG ulAttributeCount, CK_BYTE *pCiphertext, CK_ULONG ulCiphertextLen, CK_KEY_TYPE keytype, CK_ULONG keylen, CK_OBJECT_HANDLE *phKey) { if (!token_specific_filter_mechanism(tokdata, mech->mechanism, NULL)) return CKR_MECHANISM_INVALID; return openssl_specific_pqc_decapsulate_key(tokdata, sess, oid, mech, key_obj, pTemplate, ulAttributeCount, pCiphertext, ulCiphertextLen, keytype, keylen, phKey); } #endif CK_RV token_specific_get_token_info(STDLL_TokData_t *tokdata, CK_TOKEN_INFO_PTR pInfo) { UNUSED(tokdata); /* OpenSSL_version_num returns the version as 0xMNN00PP0 */ pInfo->firmwareVersion.major = (OpenSSL_version_num() & 0xF0000000) >> 28; pInfo->firmwareVersion.minor = (OpenSSL_version_num() & 0x0FF00000) >> 20; pInfo->hardwareVersion.major = pInfo->firmwareVersion.major; pInfo->hardwareVersion.minor = pInfo->firmwareVersion.minor; return CKR_OK; } opencryptoki-opencryptoki-451d99c/usr/lib/soft_stdll/soft_stdll.mk000066400000000000000000000042421520105705100255700ustar00rootroot00000000000000nobase_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 \ -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\" -I${top_builddir}/usr/lib/api \ -I${srcdir}/usr/lib/api if AIX opencryptoki_stdll_libpkcs11_sw_la_LDFLAGS = -qmkshrobj -lc \ -lpthread -lcrypto -lrt -Wl,-bnoautoexp -Wl,-bstatic,-llber,-bdynamic \ -export-symbols ${srcdir}/opencryptoki_tok.map.sym else opencryptoki_stdll_libpkcs11_sw_la_LDFLAGS = \ -shared -Wl,-z,defs,-Bsymbolic -lc -lpthread -lcrypto -lrt \ -llber -Wl,--version-script=${srcdir}/opencryptoki_tok.map endif 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/common/profile_obj.c \ usr/lib/soft_stdll/soft_specific.c usr/lib/common/attributes.c \ usr/lib/common/dlist.c usr/lib/common/mech_openssl.c \ usr/lib/common/utility_common.c usr/lib/common/ec_supported.c \ usr/lib/api/policyhelper.c usr/lib/common/pqc_supported.c \ usr/lib/common/btree.c usr/lib/common/sess_mgr.c \ usr/lib/common/mech_pqc.c opencryptoki-opencryptoki-451d99c/usr/lib/soft_stdll/tok_struct.h000066400000000000000000000167651520105705100254510ustar00rootroot00000000000000/* * 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", FALSE, // 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_get_token_info, 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, &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_edwards_sign, &token_specific_ec_edwards_verify, &token_specific_ec_generate_keypair, &token_specific_ec_edwards_generate_keypair, &token_specific_ec_montgomery_generate_keypair, &token_specific_ecdh_pkcs_derive, NULL, // ecdh_derive_kdf #else NULL, // ec_sign NULL, // ec_verify NULL, // ec_edwards_sign NULL, // ec_edwards_verify NULL, // ec_generate_keypair NULL, // ec_edwards_generate_keypair NULL, // ec_montgomery_generate_keypair NULL, // ecdh_derive NULL, // ecdh_derive_kdf #endif /* 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, // SHAKE derive &token_specific_shake_key_derive, // 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 &token_specific_aes_key_gen, &token_specific_aes_xts_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, &token_specific_aes_xts, &token_specific_aes_key_wrap, // DSA NULL, // dsa_generate_keypair NULL, // dsa_sign NULL, // dsa_verify // PQC #if OPENSSL_VERSION_PREREQ(3, 0) &token_specific_ibm_ml_dsa_generate_keypair, &token_specific_ibm_ml_dsa_sign, &token_specific_ibm_ml_dsa_verify, &token_specific_ibm_ml_kem_generate_keypair, &token_specific_ibm_ml_kem_derive, &token_specific_ml_dsa_generate_keypair, &token_specific_ml_dsa_sign, &token_specific_ml_dsa_verify, &token_specific_ml_kem_generate_keypair, &token_specific_ml_kem_encapsulate_key, &token_specific_ml_kem_decapsulate_key, #else NULL, // ibm_ml_dsa_generate_keypair NULL, // ibm_ml_dsa_sign NULL, // ibm_ml_dsa_verify NULL, // ibm_ml_kem_generate_keypair NULL, // ibm_ml_kem_derive NULL, // ml_dsa_generate_keypair NULL, // ml_dsa_sign NULL, // ml_dsa_verify NULL, // ml_kem_generate_keypair NULL, // ml_kem_encapsulate_key NULL, // ml_kem_decapsulate_key #endif &token_specific_get_mechanism_list, &token_specific_get_mechanism_info, &token_specific_object_add, NULL, // key_wrap NULL, // key_unwrap NULL, // encapsulate_rsa_sym_keygen NULL, // encapsulate_rsa_key_wrap NULL, // encapsulate_rsa_key_unwrap NULL, // encapsulate_dh_ecdh_key_pair_gen NULL, // en_decapsulate_dh_ecdh_derive_key NULL, // reencrypt_single NULL, // set_attribute_values &token_specific_set_attrs_for_new_object, NULL, // handle_event NULL, // check_obj_access }; #endif opencryptoki-opencryptoki-451d99c/usr/lib/tpm_stdll/000077500000000000000000000000001520105705100227055ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/usr/lib/tpm_stdll/defs.h000066400000000000000000000012541520105705100240010ustar00rootroot00000000000000/* * 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 opencryptoki-opencryptoki-451d99c/usr/lib/tpm_stdll/tok_struct.h000066400000000000000000000142721520105705100252650ustar00rootroot00000000000000/* * 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", TRUE, // 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 NULL, // get_token_info &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_edwards_sign NULL, // ec_edwards_verify NULL, // ec_generate_keypair NULL, // ec_edwards_generate_keypair NULL, // ec_montgomery_generate_keypair NULL, // ecdh_derive NULL, // ecdh_derive_kdf NULL, // dh_pkcs_derive NULL, // dh_pkcs_key_pair_gen // SHA NULL, // sha_init NULL, // sha NULL, // sha_update NULL, // sha_final // SHAKE derive NULL, // shake_key_derive // 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, NULL, // aes_xts_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 NULL, // aes_xts NULL, // aes_key_wrap // DSA NULL, // dsa_generate_keypair NULL, // dsa_sign NULL, // dsa_verify // PQC NULL, // ibm_ml_dsa_generate_keypair NULL, // ibm_ml_dsa_sign NULL, // ibm_ml_dsa_verify NULL, // ibm_ml_kem_generate_keypair NULL, // ibm_ml_kem_derive NULL, // ml_dsa_generate_keypair NULL, // ml_dsa_sign NULL, // ml_dsa_verify NULL, // ml_kem_generate_keypair NULL, // ml_kem_encapsulate_key NULL, // ml_kem_decapsulate_key &token_specific_get_mechanism_list, &token_specific_get_mechanism_info, NULL, // object_add &token_specific_key_wrap, &token_specific_key_unwrap, NULL, // encapsulate_rsa_sym_keygen NULL, // encapsulate_rsa_key_wrap NULL, // encapsulate_rsa_key_unwrap NULL, // encapsulate_dh_ecdh_key_pair_gen NULL, // en_decapsulate_dh_ecdh_derive_key NULL, // reencrypt_single NULL, // set_attribute_values NULL, // set_attrs_for_new_object NULL, // handle_event NULL, // check_obj_access }; opencryptoki-opencryptoki-451d99c/usr/lib/tpm_stdll/tpm_openssl.c000066400000000000000000000165261520105705100254260ustar00rootroot00000000000000/* * 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" #if OPENSSL_VERSION_PREREQ(3, 0) #include #endif #ifdef DEBUG void openssl_print_errors(void) { #if !OPENSSL_VERSION_PREREQ(3, 0) ERR_load_ERR_strings(); #endif ERR_load_crypto_strings(); ERR_print_errors_fp(stderr); } #endif EVP_PKEY *openssl_gen_key(STDLL_TokData_t *tokdata) { int rc = 0, counter = 0; char buf[32]; EVP_PKEY *pkey = NULL; EVP_PKEY_CTX *ctx = NULL; BIGNUM *bne = NULL; token_specific_rng(tokdata, (CK_BYTE *) buf, 32); RAND_seed(buf, 32); regen_rsa_key: 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); goto err; } ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL); if (ctx == NULL) goto err; if (EVP_PKEY_keygen_init(ctx) <= 0 || EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, 2048) <= 0 #if !OPENSSL_VERSION_PREREQ(3, 0) || EVP_PKEY_CTX_set_rsa_keygen_pubexp(ctx, bne) <= 0) { #else || EVP_PKEY_CTX_set1_rsa_keygen_pubexp(ctx, bne) <= 0) { #endif fprintf(stderr, "Error generating user's RSA key\n"); ERR_load_crypto_strings(); ERR_print_errors_fp(stderr); goto err; } #if !OPENSSL_VERSION_PREREQ(3, 0) bne = NULL; // will be freed as part of the context #else BN_free(bne); bne = NULL; #endif if (EVP_PKEY_keygen(ctx, &pkey) <= 0) { fprintf(stderr, "Error generating user's RSA key\n"); ERR_load_crypto_strings(); ERR_print_errors_fp(stderr); goto err; } EVP_PKEY_CTX_free(ctx); ctx = EVP_PKEY_CTX_new(pkey, NULL); if (ctx == NULL) goto err; rc = (EVP_PKEY_check(ctx) == 1 ? 1 : 0); switch (rc) { case 0: /* rsa is not a valid RSA key */ counter++; if (counter == KEYGEN_RETRY) { TRACE_DEVEL("Tried %d times to generate a " "valid RSA key, failed.\n", KEYGEN_RETRY); goto err; } 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; } if (ctx != NULL) EVP_PKEY_CTX_free(ctx); if (bne != NULL) BN_free(bne); return pkey; err: if (pkey != NULL) EVP_PKEY_free(pkey); if (ctx != NULL) EVP_PKEY_CTX_free(ctx); if (bne != NULL) BN_free(bne); return NULL; } int openssl_write_key(STDLL_TokData_t * tokdata, EVP_PKEY *pkey, 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; } if (ock_snprintf(loc, PATH_MAX, "%s/%s/%s", tokdata->pk_dir, pw->pw_name, filename) != 0) { TRACE_ERROR("key path too long\n"); return -1; } b = BIO_new_file(loc, "w"); if (!b) { TRACE_ERROR("Error opening file for write: %s\n", loc); return -1; } if (!PEM_write_bio_PrivateKey(b, pkey, 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, EVP_PKEY **ret) { BIO *b = NULL; EVP_PKEY *pkey = 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; } if (ock_snprintf(loc, PATH_MAX, "%s/%s/%s", tokdata->pk_dir, pw->pw_name, filename) != 0) { TRACE_ERROR("key file name too long\n"); return CKR_FUNCTION_FAILED; } /* 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 ((pkey = PEM_read_bio_PrivateKey(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 = pkey; return CKR_OK; } int openssl_get_modulus_and_prime(EVP_PKEY *pkey, unsigned int *size_n, unsigned char *n, unsigned int *size_p, unsigned char *p) { #if !OPENSSL_VERSION_PREREQ(3, 0) const BIGNUM *n_tmp = NULL, *p_tmp = NULL; RSA *rsa; #else BIGNUM *n_tmp = NULL, *p_tmp = NULL; #endif int len; #if !OPENSSL_VERSION_PREREQ(3, 0) rsa = EVP_PKEY_get0_RSA(pkey); /* get the modulus from the RSA object */ RSA_get0_key(rsa, &n_tmp, NULL, NULL); if ((len = BN_bn2bin(n_tmp, n)) <= 0) { DEBUG_openssl_print_errors(); return -1; } *size_n = len; /* get one of the primes from the RSA object */ RSA_get0_factors(rsa, &p_tmp, NULL); if ((len = BN_bn2bin(p_tmp, p)) <= 0) { DEBUG_openssl_print_errors(); return -1; } *size_p = len; #else if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_N, &n_tmp) || (len = BN_bn2bin(n_tmp, n)) <= 0) { DEBUG_openssl_print_errors(); BN_free(n_tmp); return -1; } *size_n = len; BN_free(n_tmp); p_tmp = BN_secure_new(); if (p_tmp == NULL || !EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_FACTOR1, &p_tmp) || (len = BN_bn2bin(p_tmp, p)) <= 0) { DEBUG_openssl_print_errors(); BN_clear_free(p_tmp); return -1; } *size_p = len; BN_clear_free(p_tmp); #endif return 0; } opencryptoki-opencryptoki-451d99c/usr/lib/tpm_stdll/tpm_specific.c000066400000000000000000003551001520105705100255220ustar00rootroot00000000000000/* * 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. * */ #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 { /* 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->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; 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 if (get_pk_dir(tokdata, fname, PATH_MAX) == NULL) { TRACE_ERROR("pk_dir buffer overflow\n"); return CKR_FUNCTION_FAILED; } if (stat(fname, &statbuf) < 0) { if (mkdir(fname, S_IRUSR | S_IWUSR | S_IXUSR) == -1) { TRACE_ERROR("mkdir(%s): %s\n", fname, strerror(errno)); return CKR_FUNCTION_FAILED; } } // now create userdir/TOK_OBJ if it doesn't exist if (ock_snprintf(path_buf, PATH_MAX, "%s/%s", fname, PK_LITE_OBJ_DIR) != 0) { TRACE_ERROR("userdir/TOK_OBJ path name overflow\n"); return CKR_FUNCTION_FAILED; } 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)); if (tpm_data == NULL) { TRACE_ERROR("calloc failed\n"); return CKR_HOST_MEMORY; } 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); free(tpm_data); 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); Tspi_Context_Close(tpm_data->tspContext); free(tpm_data); 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); Tspi_Context_Close(tpm_data->tspContext); free(tpm_data); 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; 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 */ rc = template_attribute_get_ulong(obj->template, CKA_KEY_TYPE, &key_type); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key\n"); goto done; } if (key_type != CKK_RSA) { TRACE_ERROR("Bad key type!\n"); rc = CKR_FUNCTION_FAILED; goto done; } rc = template_attribute_get_ulong(obj->template, CKA_CLASS, &class); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_CLASS for the key\n"); goto done; } 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 */ rc = template_attribute_get_non_empty(obj->template, CKA_PRIME_1, &prime_attr); if (rc != CKR_OK) { rc = template_attribute_get_non_empty(obj->template, CKA_PRIME_2, &prime_attr); if (rc != CKR_OK) { 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 */ rc = template_attribute_get_non_empty(obj->template, CKA_MODULUS, &attr); if (rc != CKR_OK) { TRACE_ERROR("Couldn't find a required attribute of " "key object\n"); 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 */ rc = template_attribute_get_non_empty(obj->template, CKA_MODULUS, &attr); if (rc != CKR_OK) { TRACE_ERROR("Couldn't find a required attribute of " "key object\n"); 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; } rc = template_update_attribute(obj->template, new_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); free(new_attr); Tspi_Context_FreeMemory(tpm_data->tspContext, rgbBlob); goto done; } 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; } rc = template_update_attribute(priv_key_obj->template, new_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); free(new_attr); Tspi_Context_FreeMemory(tpm_data->tspContext, rgbBlob); Tspi_Context_FreeMemory(tpm_data->tspContext, rgbPrivBlob); free(key_id); object_free(priv_key_obj); return rc; } 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; } rc = template_update_attribute(priv_key_obj->template, new_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); free(new_attr); Tspi_Context_FreeMemory(tpm_data->tspContext, rgbBlob); Tspi_Context_FreeMemory(tpm_data->tspContext, rgbPrivBlob); object_free(priv_key_obj); return rc; } 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; } rc = template_update_attribute(priv_key_obj->template, new_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); free(new_attr); Tspi_Context_FreeMemory(tpm_data->tspContext, rgbPrivBlob); object_free(priv_key_obj); return rc; } 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; } rc = template_update_attribute(priv_key_obj->template, new_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); free(new_attr); object_free(priv_key_obj); return rc; } /* 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; } rc = template_update_attribute(priv_key_obj->template, new_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); free(new_attr); object_free(priv_key_obj); return rc; } /* 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; } rc = template_update_attribute(priv_key_obj->template, new_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); free(new_attr); object_free(priv_key_obj); return rc; } /* 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; } rc = template_update_attribute(priv_key_obj->template, new_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); free(new_attr); object_free(priv_key_obj); return rc; } 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; } rc = template_update_attribute(priv_key_obj->template, new_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); free(new_attr); object_free(priv_key_obj); return rc; } 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; } rc = template_update_attribute(pub_key_obj->template, new_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); free(new_attr); object_free(pub_key_obj); goto done; } /* 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; } rc = template_update_attribute(pub_key_obj->template, new_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); free(new_attr); object_free(pub_key_obj); goto done; } 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; EVP_PKEY *pkey; unsigned int size_n, size_p; unsigned char n[256], p[256]; /* all sw generated keys are 2048 bits */ if ((pkey = openssl_gen_key(tokdata)) == NULL) return CKR_HOST_MEMORY; if (openssl_get_modulus_and_prime(pkey, &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, pkey, TPMTOK_PRIV_ROOT_KEY_FILE, pPin)) { TRACE_DEVEL("openssl_write_key failed.\n"); EVP_PKEY_free(pkey); return CKR_FUNCTION_FAILED; } EVP_PKEY_free(pkey); /* 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; EVP_PKEY *pkey; unsigned int size_n, size_p; unsigned char n[256], p[256]; /* all sw generated keys are 2048 bits */ if ((pkey = openssl_gen_key(tokdata)) == NULL) return CKR_HOST_MEMORY; if (openssl_get_modulus_and_prime(pkey, &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, pkey, TPMTOK_PUB_ROOT_KEY_FILE, pPin)) { TRACE_DEVEL("openssl_write_key\n"); EVP_PKEY_free(pkey); return CKR_FUNCTION_FAILED; } EVP_PKEY_free(pkey); 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; EVP_PKEY *pkey; 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, &pkey))) { 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(pkey, &size_n, n, &size_p, p) != 0) { TRACE_DEVEL("openssl_get_modulus_and_prime failed\n"); EVP_PKEY_free(pkey); 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); EVP_PKEY_free(pkey); return rc; } EVP_PKEY_free(pkey); 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 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); 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; EVP_PKEY *pkey_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, &pkey_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, pkey_root, TPMTOK_PRIV_ROOT_KEY_FILE, pNewPin); if (rc != CKR_OK) { EVP_PKEY_free(pkey_root); TRACE_DEVEL("openssl_write_key failed\n"); return CKR_FUNCTION_FAILED; } EVP_PKEY_free(pkey_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, &pkey_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, pkey_root, TPMTOK_PUB_ROOT_KEY_FILE, pNewPin); if (rc != CKR_OK) { EVP_PKEY_free(pkey_root); TRACE_DEVEL("openssl_write_key failed\n"); return CKR_FUNCTION_FAILED; } EVP_PKEY_free(pkey_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, TEMPLATE *tmpl, CK_BYTE **des_key, CK_ULONG *len, CK_ULONG keysize, CK_BBOOL *is_opaque) { UNUSED(tmpl); *des_key = malloc(keysize); if (*des_key == NULL) return CKR_HOST_MEMORY; *len = keysize; *is_opaque = FALSE; // 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 (keysize == (3 * DES_KEY_SIZE)) { rng_generate(tokdata, *des_key, keysize); } else { do { rng_generate(tokdata, *des_key, keysize); } 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) { return openssl_specific_des_ecb(tokdata, in_data, in_data_len, out_data, out_data_len, key, encrypt); } 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) { return openssl_specific_des_cbc(tokdata, in_data, in_data_len, out_data, out_data_len, key, init_v, encrypt); } 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) { return openssl_specific_tdes_ecb(tokdata, in_data, in_data_len, out_data, out_data_len, key, encrypt); } 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) { return openssl_specific_tdes_cbc(tokdata, in_data, in_data_len, out_data, out_data_len, key, init_v, encrypt); } /* 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; } rc = template_update_attribute(publ_tmpl, new_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); free(new_attr); 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; } rc = template_update_attribute(priv_tmpl, new_attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); free(new_attr); return rc; } 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_get_non_empty(key_obj->template, CKA_MODULUS, &modulus); if (rc != CKR_OK) 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_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; } rc = template_attribute_get_ulong(publ_tmpl, CKA_MODULUS_BITS, &mod_bits); if (rc != CKR_OK) { TRACE_ERROR("Could not find CKA_MODULUS_BITS for the key\n"); return rc; // should never happen } 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; } rc = template_update_attribute(priv_tmpl, attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); free(attr); Tspi_Context_FreeMemory(tpm_data->tspContext, rgbBlob); return rc; } 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; } rc = template_update_attribute(publ_tmpl, attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); free(attr); Tspi_Context_FreeMemory(tpm_data->tspContext, rgbBlob); return rc; } 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; } rc = template_update_attribute(publ_tmpl, attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); free(attr); Tspi_Context_FreeMemory(tpm_data->tspContext, rgbBlob); return rc; } /* 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; } rc = template_update_attribute(priv_tmpl, attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); free(attr); Tspi_Context_FreeMemory(tpm_data->tspContext, rgbBlob); return rc; } 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; } rc = template_update_attribute(priv_tmpl, attr); if (rc != CKR_OK) { TRACE_ERROR("template_update_attribute failed\n"); free(attr); return rc; } /* 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_get_non_empty(key_obj->template, CKA_IBM_OPAQUE, &attr); if (rc != CKR_OK) { /* 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_get_non_empty(key_obj->template, CKA_IBM_OPAQUE, &attr); if (rc != CKR_OK) { 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 */ rc = template_attribute_get_non_empty(key_obj->template, CKA_ENC_AUTHDATA, &attr); if (rc == CKR_OK) { 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, TEMPLATE *tmpl, CK_BYTE **key, CK_ULONG *len, CK_ULONG keysize, CK_BBOOL *is_opaque) { UNUSED(tmpl); *key = malloc(keysize); if (*key == NULL) return CKR_HOST_MEMORY; *len = keysize; *is_opaque = FALSE; return rng_generate(tokdata, *key, keysize); } CK_RV token_specific_aes_ecb(STDLL_TokData_t *tokdata, SESSION *session, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, OBJECT *key, CK_BYTE encrypt) { UNUSED(session); return openssl_specific_aes_ecb(tokdata, in_data, in_data_len, out_data, out_data_len, key, encrypt); } CK_RV token_specific_aes_cbc(STDLL_TokData_t *tokdata, SESSION *session, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, OBJECT *key, CK_BYTE *init_v, CK_BYTE encrypt) { UNUSED(session); return openssl_specific_aes_cbc(tokdata, in_data, in_data_len, out_data, out_data_len, key, init_v, encrypt); } 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, NULL); } 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, NULL); } int token_specific_creatlock(STDLL_TokData_t *tokdata) { 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; const char *group; /* 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); group = tokdata->tokgroup; if (group == NULL || group[0] == '\0') group = PKCS_GROUP; grp = getgrnam(group); if (grp == NULL) { OCK_SYSLOG(LOG_ERR, "getgrname(%s): %s\n", group, strerror(errno)); TRACE_ERROR("getgrname(%s): %s\n", group, strerror(errno)); goto err; } 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)); TRACE_ERROR("Directory(%s) missing: %s\n", lockdir, strerror(errno)); goto err; } /* set ownership to euid, and token group */ if (chown(lockdir, geteuid(), grp->gr_gid) != 0) { OCK_SYSLOG(LOG_ERR, "Failed to set owner:group ownership on " "'%s' directory\n", lockdir); TRACE_ERROR("Failed to set owner:group ownership on '%s' " "directory\n", lockdir); goto err; } /* mkdir does not set group permission right, set explicitly here */ if (chmod(lockdir, S_IRWXU | S_IRWXG) != 0) { OCK_SYSLOG(LOG_ERR, "Failed to change permissions on '%s' " "directory\n", lockdir); TRACE_ERROR("Failed to change permissions on '%s' directory\n", lockdir); goto err; } } else if (ret != 0) { OCK_SYSLOG(LOG_ERR, "Could not stat directory '%s': %s\n", lockdir, strerror(errno)); TRACE_ERROR("Could not stat directory '%s': %s\n", lockdir, strerror(errno)); goto err; } else if (statbuf.st_gid != grp->gr_gid) { OCK_SYSLOG(LOG_ERR, "Directory '%s' is not owned by token group " "'%s'\n", lockdir, group); TRACE_ERROR("Directory '%s' is not owned by token group '%s'\n", lockdir, group); 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; } CK_RV token_specific_key_wrap(STDLL_TokData_t *tokdata, SESSION *session, CK_MECHANISM *mech, CK_BBOOL length_only, OBJECT *wrapping_key, OBJECT *key, CK_BYTE *wrapped_key, CK_ULONG *wrapped_key_len, CK_BBOOL *not_opaque) { CK_OBJECT_CLASS class; CK_KEY_TYPE keytype; CK_RV rc; UNUSED(tokdata); UNUSED(session); UNUSED(length_only); UNUSED(wrapped_key); UNUSED(wrapped_key_len); rc = template_attribute_get_ulong(wrapping_key->template, CKA_CLASS, &class); if (rc != CKR_OK) return rc; if (class != CKO_SECRET_KEY) return CKR_KEY_NOT_WRAPPABLE; rc = template_attribute_get_ulong(key->template, CKA_CLASS, &class); if (rc != CKR_OK) return rc; if (class != CKO_SECRET_KEY) return CKR_KEY_NOT_WRAPPABLE; rc = template_attribute_get_ulong(wrapping_key->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) return rc; switch (mech->mechanism) { case CKM_DES_ECB: case CKM_DES_CBC: case CKM_DES_CBC_PAD: if (keytype != CKK_DES) return CKR_WRAPPING_KEY_TYPE_INCONSISTENT; break; case CKM_DES3_ECB: case CKM_DES3_CBC: case CKM_DES3_CBC_PAD: if (keytype != CKK_DES2 && keytype != CKK_DES3) return CKR_WRAPPING_KEY_TYPE_INCONSISTENT; break; case CKM_AES_ECB: case CKM_AES_CBC: case CKM_AES_CBC_PAD: if (keytype != CKK_AES) return CKR_WRAPPING_KEY_TYPE_INCONSISTENT; break; default: return CKR_KEY_NOT_WRAPPABLE; } rc = template_attribute_get_ulong(key->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) return rc; switch (keytype) { case CKK_DES: case CKK_DES2: case CKK_DES3: case CKK_AES: case CKK_GENERIC_SECRET: break; default: return CKR_KEY_NOT_WRAPPABLE; } /* Symmetric keys are not opaque, so we can let common code do the wrap */ *not_opaque = TRUE; return CKR_OK; } CK_RV token_specific_key_unwrap(STDLL_TokData_t *tokdata, SESSION *session, CK_MECHANISM *mech, CK_BYTE *wrapped_key, CK_ULONG wrapped_key_len, OBJECT *unwrapping_key, OBJECT *unwrapped_key, CK_BBOOL *not_opaque) { CK_OBJECT_CLASS class; CK_KEY_TYPE keytype; CK_RV rc; UNUSED(tokdata); UNUSED(session); UNUSED(wrapped_key); UNUSED(wrapped_key_len); rc = template_attribute_get_ulong(unwrapping_key->template, CKA_CLASS, &class); if (rc != CKR_OK) return rc; if (class != CKO_SECRET_KEY) return CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT; rc = template_attribute_get_ulong(unwrapped_key->template, CKA_CLASS, &class); if (rc != CKR_OK) return rc; if (class != CKO_SECRET_KEY) return CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT; rc = template_attribute_get_ulong(unwrapping_key->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) return rc; switch (mech->mechanism) { case CKM_DES_ECB: case CKM_DES_CBC: case CKM_DES_CBC_PAD: if (keytype != CKK_DES) return CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT; break; case CKM_DES3_ECB: case CKM_DES3_CBC: case CKM_DES3_CBC_PAD: if (keytype != CKK_DES2 && keytype != CKK_DES3) return CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT; break; case CKM_AES_ECB: case CKM_AES_CBC: case CKM_AES_CBC_PAD: if (keytype != CKK_AES) return CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT; break; default: return CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT; } rc = template_attribute_get_ulong(unwrapped_key->template, CKA_KEY_TYPE, &keytype); if (rc != CKR_OK) return rc; switch (keytype) { case CKK_DES: case CKK_DES2: case CKK_DES3: case CKK_AES: case CKK_GENERIC_SECRET: break; default: return CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT; } /* Symmetric keys are not opaque, so we can let common code do the unwrap */ *not_opaque = TRUE; return CKR_OK; } opencryptoki-opencryptoki-451d99c/usr/lib/tpm_stdll/tpm_specific.h000066400000000000000000000061121520105705100255230ustar00rootroot00000000000000/* * 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 EVP_PKEY *openssl_gen_key(STDLL_TokData_t *); int openssl_write_key(STDLL_TokData_t *, EVP_PKEY *, char *, CK_BYTE *); CK_RV openssl_read_key(STDLL_TokData_t *, char *, CK_BYTE *, EVP_PKEY **); int openssl_get_modulus_and_prime(EVP_PKEY *, 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 opencryptoki-opencryptoki-451d99c/usr/lib/tpm_stdll/tpm_stdll.mk000066400000000000000000000040551520105705100252440ustar00rootroot00000000000000nobase_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 -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\" \ -I${top_builddir}/usr/lib/api -I${srcdir}/usr/lib/api opencryptoki_stdll_libpkcs11_tpm_la_LDFLAGS = \ -shared -Wl,-z,defs,-Bsymbolic -lcrypto -ltspi -lpthread -lrt \ -llber -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/common/profile_obj.c \ usr/lib/tpm_stdll/tpm_specific.c usr/lib/common/attributes.c \ usr/lib/tpm_stdll/tpm_openssl.c usr/lib/tpm_stdll/tpm_util.c \ usr/lib/common/dlist.c usr/lib/common/mech_openssl.c \ usr/lib/common/utility_common.c usr/lib/common/ec_supported.c \ usr/lib/api/policyhelper.c usr/lib/common/pqc_supported.c \ usr/lib/common/btree.c usr/lib/common/sess_mgr.c \ usr/lib/common/mech_pqc.c opencryptoki-opencryptoki-451d99c/usr/lib/tpm_stdll/tpm_util.c000066400000000000000000000210141520105705100247040ustar00rootroot00000000000000/* * 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_RV rv; CK_ATTRIBUTE *publ_exp_attr; CK_BYTE pubexp_bytes[] = { 1, 0, 1 }; CK_ULONG publ_exp, rc = 1; rv = template_attribute_get_non_empty(tmpl, CKA_PUBLIC_EXPONENT, &publ_exp_attr); if (rv != CKR_OK) { TRACE_ERROR("Couldn't find public exponent attribute.\n"); return rv; } 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; } opencryptoki-opencryptoki-451d99c/usr/sbin/000077500000000000000000000000001520105705100210705ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/usr/sbin/p11kmip/000077500000000000000000000000001520105705100223525ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/usr/sbin/p11kmip/kmipclient/000077500000000000000000000000001520105705100245115ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/usr/sbin/p11kmip/kmipclient/README.md000066400000000000000000000015331520105705100257720ustar00rootroot00000000000000## The p11kmip tool The p11kmip tool uses slightly modified libkmipclient code from the s390-tools package as a static library to interface with a KMIP server: - [https://github.com/ibm-s390-linux/s390-tools/tree/master/libkmipclient](https://github.com/ibm-s390-linux/s390-tools/tree/master/libkmipclient) - [https://github.com/ibm-s390-linux/s390-tools/tree/master/include/kmipclient](https://github.com/ibm-s390-linux/s390-tools/tree/master/include/kmipclient) Modifications were done to fit to the OpenCrptoki environment, and to be able to build the libkmipclient library without support for KMIP over HTTPS, as well as without support for JSON and XML encoding. The p11kmip tool currently only uses KMIP TTLV encoding over plain TLS. The license of the libkmipclient source files were changed from MIT to Common Public License, version 1.0 (CPL-1.0). opencryptoki-opencryptoki-451d99c/usr/sbin/p11kmip/kmipclient/attribute.c000066400000000000000000003621231520105705100266670ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021-2024 * * 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 _DEFAULT_SOURCE #include #include #include #include #include "kmip.h" #include "names.h" /** * Constructs a Template Attribute node (KMIP v1.x): * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Template-Attribute Yes Structure v1.x only * Name No Structure v1.x only * ... may be repeated * Attribute No Structure v1.x only * ... may be repeated * * Also applies to Common Template-Attribute, Private Key Template-Attribute, * Public Key Template-Attribute. * * @param tag the template-attribute tag * @param num_names the number of names in the array (can be 0) * @param names array of name nodes * @param num_attrs the number of attributes in the array (can be 0) * @param attrs array of attribute nodes * * @returns the allocated node, or NULL in case of an error. * The reference counts of the nodes specified as parameters which are added to * the newly allocated node are increased. The caller must free its reference * via kmip_node_free() if no longer needed. */ static struct kmip_node *kmip_new_template_attribute_v1( enum kmip_tag tag, unsigned int num_names, struct kmip_node **names, unsigned int num_attrs, struct kmip_node **attrs) { struct kmip_node *tmpl; unsigned int i; int rc; if (num_names > 0 && names == NULL) return NULL; if (num_attrs > 0 && attrs == NULL) return NULL; switch (tag) { case KMIP_TAG_TEMPLATE_ATTRIBUTE: case KMIP_TAG_COMMON_TEMPLATE_ATTRIBUTE: case KMIP_TAG_PRIVATE_KEY_TEMPLATE_ATTRIBUTE: case KMIP_TAG_PUBLIC_KEY_TEMPLATE_ATTRIBUTE: break; default: return NULL; } tmpl = kmip_node_new_structure_va(KMIP_TAG_TEMPLATE_ATTRIBUTE, NULL, 0); if (tmpl == NULL) return NULL; for (i = 0; i < num_names; i++) { rc = kmip_node_add_structure_element(tmpl, names[i]); if (rc != 0) goto error; } for (i = 0; i < num_attrs; i++) { rc = kmip_node_add_structure_element(tmpl, attrs[i]); if (rc != 0) goto error; } return tmpl; error: kmip_node_free(tmpl); return NULL; } /** * Gets information from a Template Attribute node (KMIP v1.x): * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Template-Attribute Yes Structure v1.x only * Name No Structure v1.x only * ... may be repeated * Attribute No Structure v1.x only * ... may be repeated * * Also applies to Common Template-Attribute, Private Key Template-Attribute, * Public Key Template-Attribute. * * @param node the KMIP node * @param num_names On return: The number of names (can be NULL) * @param name_index the index of the name item to return * @param name On return: the name item of the specified index. * Function returns -ENOENT if no name is available. * Can be NULL, then no name entry is returned. * @param num_attrs On return: The number of attributes (can be NULL) * @param attr_index the index of the attribute item to return * @param attr On return: the attribute item of the specified * index. Function returns -ENOENT if no attribute is * available. Can be NULL, then no attribute entry is * returned. * * @returns 0 on success, or a negative errno in case of an error. * The reference count of the returned nodes is increased. The caller must * free the node via kmip_node_free() when no longer needed. */ static int kmip_get_template_attribute_v1(const struct kmip_node *node, unsigned int *num_names, unsigned int name_index, struct kmip_node **name, unsigned int *num_attrs, unsigned int attr_index, struct kmip_node **attr) { if (node == NULL) return -EINVAL; switch (kmip_node_get_tag(node)) { case KMIP_TAG_TEMPLATE_ATTRIBUTE: case KMIP_TAG_COMMON_TEMPLATE_ATTRIBUTE: case KMIP_TAG_PRIVATE_KEY_TEMPLATE_ATTRIBUTE: case KMIP_TAG_PUBLIC_KEY_TEMPLATE_ATTRIBUTE: break; default: return -EBADMSG; } if (num_names != NULL) *num_names = kmip_node_get_structure_element_by_tag_count( node, KMIP_TAG_NAME); if (name != NULL) { *name = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_NAME, name_index); if (*name == NULL) return -ENOENT; } if (num_attrs != NULL) *num_attrs = kmip_node_get_structure_element_by_tag_count( node, KMIP_TAG_ATTRIBUTE); if (attr != NULL) { *attr = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_ATTRIBUTE, attr_index); if (*attr == NULL) { if (name != NULL && *name != NULL) { kmip_node_free(*name); *name = NULL; } return -ENOENT; } } return 0; } /** * Constructs an Attribute node (KMIP v1.x): * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Attribute Yes Structure v1.x only * Attribute Name Yes Text String v1.x only * Attribute Index No Integer v1.x only * Attribute Value Yes v1.x only * * @param name the name of the attribute * @param index the index of the attribute. If < 0 then this field * is omitted * @param value the attribute value node * * @returns the allocated node, or NULL in case of an error. * The reference counts of the nodes specified as parameters which are added to * the newly allocated node are increased. The caller must free its reference * via kmip_node_free() if no longer needed. */ static struct kmip_node *kmip_new_attribute_v1(const char *name, int32_t index, struct kmip_node *value) { struct kmip_node *attr = NULL, *nam, *idx = NULL; if (name == NULL || value == NULL) return NULL; nam = kmip_node_new_text_string(KMIP_TAG_ATTRIBUTE_NAME, NULL, name); if (index >= 0) idx = kmip_node_new_integer(KMIP_TAG_ATTRIBUTE_INDEX, NULL, index); if (nam == NULL || (index >= 0 && idx == NULL)) goto out; attr = kmip_node_new_structure_va(KMIP_TAG_ATTRIBUTE, NULL, 3, nam, idx, value); out: kmip_node_free(nam); kmip_node_free(idx); return attr; } /** * Gets the information from an Attribute node (KMIP v1.x): * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Attribute Yes Structure v1.x only * Attribute Name Yes Text String v1.x only * Attribute Index No Integer v1.x only * Attribute Value Yes v1.x only * * @param node the KMIP node * @param name On return: the attribute name (can be NULL) * @param index On return: the attribute index (can be NULL) * @param value On return: the attribute value (can be NULL) * * @returns 0 on success, or a negative errno in case of an error * The reference count of the returned nodes is increased. The caller must * free the node via kmip_node_free() when no longer needed. */ static int kmip_get_attribute_v1(const struct kmip_node *node, const char **name, int32_t *index, struct kmip_node **value) { struct kmip_node *nam, *idx, *val; int rc = 0; if (node == NULL) return -EINVAL; if (kmip_node_get_tag(node) != KMIP_TAG_ATTRIBUTE) return -EBADMSG; nam = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_ATTRIBUTE_NAME, 0); idx = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_ATTRIBUTE_INDEX, 0); val = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_ATTRIBUTE_VALUE, 0); if (nam == NULL || val == NULL) { rc = -EBADMSG; goto out; } if (name != NULL) *name = kmip_node_get_text_string(nam); if (index != NULL) *index = (idx != NULL ? kmip_node_get_integer(idx) : 0); if (value != NULL) *value = val; out: kmip_node_free(nam); kmip_node_free(idx); if (value == NULL || rc != 0) kmip_node_free(val); return rc; } /** * Constructs a (Vendor) Attribute node (KMIP v2.x): * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Attribute Yes Structure v2.x only * Vendor Identification Yes Text String v2.x only * Attribute Name Yes Text String v2.x only * Attribute Value Yes v2.x only * * @param vendor_id the vendor identification of the attribute * @param name the name of the attribute * @param value the attribute value node * * @returns the allocated node, or NULL in case of an error. * The reference counts of the nodes specified as parameters which are added to * the newly allocated node are increased. The caller must free its reference * via kmip_node_free() if no longer needed. */ struct kmip_node *kmip_new_vendor_attribute(const char *vendor_id, const char *name, struct kmip_node *value) { struct kmip_node *attr = NULL, *nam, *vend = NULL; if (vendor_id == NULL || name == NULL || value == NULL) return NULL; vend = kmip_node_new_text_string(KMIP_TAG_VENDOR_IDENTIFICATION, NULL, vendor_id); nam = kmip_node_new_text_string(KMIP_TAG_ATTRIBUTE_NAME, NULL, name); if (nam == NULL || vend == NULL) goto out; attr = kmip_node_new_structure_va(KMIP_TAG_ATTRIBUTE, NULL, 3, vend, nam, value); out: kmip_node_free(nam); kmip_node_free(vend); return attr; } /** * Gets the information from a (Vendor) Attribute node (KMIP v2.x): * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Attribute Yes Structure v2.x only * Vendor Identification Yes Text String v2.x only * Attribute Name Yes Text String v2.x only * Attribute Value Yes v2.x only * * @param node the KMIP node * @param vendor_id On return: the vendor identification (can be NULL) * @param name On return: the attribute name (can be NULL) * @param value On return: the attribute value (can be NULL) * * @returns 0 on success, or a negative errno in case of an error * The reference count of the returned nodes is increased. The caller must * free the node via kmip_node_free() when no longer needed. */ int kmip_get_vendor_attribute(const struct kmip_node *node, const char **vendor_id, const char **name, struct kmip_node **value) { struct kmip_node *vend, *nam, *val; int rc = 0; if (node == NULL) return -EINVAL; if (kmip_node_get_tag(node) != KMIP_TAG_ATTRIBUTE) return -EBADMSG; vend = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_VENDOR_IDENTIFICATION, 0); nam = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_ATTRIBUTE_NAME, 0); val = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_ATTRIBUTE_VALUE, 0); if (vend == NULL || nam == NULL || val == NULL) { rc = -EBADMSG; goto out; } if (vendor_id != NULL) *vendor_id = kmip_node_get_text_string(vend); if (name != NULL) *name = kmip_node_get_text_string(nam); if (value != NULL) *value = val; out: kmip_node_free(vend); kmip_node_free(nam); if (value == NULL || rc != 0) kmip_node_free(val); return rc; } /** * Constructs an Attributes node (KMIP v2.x): * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Attributes Yes Structure v2.x only * No v2.x only * ... may be repeated * * Also applies to Common Attributes, Private Key Attributes, * Public Key Attributes * * @param tag the attributes tag * @param attrs_count the number of attributes following (can be 0) * @param attrs the array of attributes * * @returns the allocated node, or NULL in case of an error. * The reference counts of the nodes specified as parameters which are added to * the newly allocated node are increased. The caller must free its reference * via kmip_node_free() if no longer needed. */ static struct kmip_node *kmip_new_attributes_v2(enum kmip_tag tag, unsigned int attrs_count, struct kmip_node **attrs) { switch (tag) { case KMIP_TAG_ATTRIBUTES: case KMIP_TAG_COMMON_ATTRIBUTES: case KMIP_TAG_PRIVATE_KEY_ATTRIBUTES: case KMIP_TAG_PUBLIC_KEY_ATTRIBUTES: break; default: return NULL; } return kmip_node_new_structure(KMIP_TAG_ATTRIBUTES, NULL, attrs_count, attrs); } /** * Gets the information from an Attributes node (KMIP v2.x): * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Attributes Yes Structure v2.x only * No v2.x only * ... may be repeated * * Also applies to Common Attributes, Private Key Attributes, * Public Key Attributes * * @param node the KMIP node * @param num_attrs On return: The number of attributes (can be NULL) * @param attr_index the index of the attribute to return * @param value On return: the attribute item of the specified * index. Function returns -ENOENT if no attribute is * available. Can be NULL, then no attribute entry is * returned. * * @returns 0 on success, or a negative errno in case of an error * The reference count of the returned nodes is increased. The caller must * free the node via kmip_node_free() when no longer needed. */ static int kmip_get_attributes_v2(const struct kmip_node *node, unsigned int *num_attrs, unsigned int attr_index, struct kmip_node **attr) { if (node == NULL) return -EINVAL; switch (kmip_node_get_tag(node)) { case KMIP_TAG_ATTRIBUTES: case KMIP_TAG_COMMON_ATTRIBUTES: case KMIP_TAG_PRIVATE_KEY_ATTRIBUTES: case KMIP_TAG_PUBLIC_KEY_ATTRIBUTES: break; default: return -EBADMSG; } if (num_attrs != NULL) *num_attrs = kmip_node_get_structure_element_count(node); if (attr == NULL) return 0; *attr = kmip_node_get_structure_element_by_index(node, attr_index); if (*attr == NULL) return -ENOENT; return 0; } /** * Split a KMIP v1.x custom attribute name into a vendor-id and attribute * name for a KMIP v2.x vendor attribute. * * @param name the custom attribute name. This string is being * modified during splitting. If the contents is still * needed, the caller should copy it first. * @param vendor_id On return: the vendor-ID string. This point to * inside the passed name string from the 1st argument. * @param attr_name On return: the vendor attribute name string. * This point to inside the passed name string from * the 1st argument. * * @returns 0 on success, or a negative errno in case of an error */ static int kmip_split_v1_custom_attr_name(char *name, char **vendor_id, char **attr_name) { char *tok; if (name == NULL || vendor_id == NULL || attr_name == NULL) return -EINVAL; /* * KMIP v1.x custom attribute names in the form 'x|y--' * are transformed into a KMIP v2.x vendor attribute with vendor id * and name . If no vendor id is found, then the vendor * id is set to 'x' or 'y', and the name is the remaining name string. */ if (strncmp(name, "x-", 2) != 0 && strncmp(name, "y-", 2) != 0) return -EBADMSG; name[1] = 0; tok = strchr(name + 2, '-'); if (tok != NULL) { *tok = 0; *vendor_id = name + 2; *attr_name = tok + 1; } else { *vendor_id = name; *attr_name = name + 2; } return 0; } /** * Builds a KMIP v1.x custom attribute name from a KMIP v2.x vendor-id and * attribute name. * * @param vendor_id the vendor-ID string * @param attr_name the vendor attribute name string * * @returns a newly allocated custom attribute name string, or NULL in case of * an error. The returned string must be freed by the caller. */ char *kmip_build_v1_custom_attr_name(const char *vendor_id, const char *attr_name) { char *custom_name = NULL; int rc; if (vendor_id == NULL || attr_name == NULL) return NULL; if (strcmp(vendor_id, "x") == 0 || strcmp(vendor_id, "y") == 0) rc = asprintf(&custom_name, "%s-%s", vendor_id, attr_name); else rc = asprintf(&custom_name, "x-%s-%s", vendor_id, attr_name); if (rc <= 0 || custom_name == NULL) return NULL; return custom_name; } /** * Converts a KMIP v1.x Attribute into a KMIP v2.x Attribute * * @param v1_attr the KMIP v1.x attribute to convert * @param v2_attr On return: the KMIP v2.x attribute * * @returns 0 on success, or a negative errno in case of an error */ int kmip_v2_attr_from_v1_attr(struct kmip_node *v1_attr, struct kmip_node **v2_attr) { char *copy, *vendor_id, *attr_name; struct kmip_node *value, *cloned_value; enum kmip_tag v2_tag; const char *name; int rc; if (v1_attr == NULL || v2_attr == NULL) return -EINVAL; rc = kmip_get_attribute_v1(v1_attr, &name, NULL, &value); if (rc != 0) return rc; if (strncmp(name, "x-", 2) == 0 || strncmp(name, "y-", 2) == 0) { /* Special handling for Custom Attribute */ copy = strdup(name); if (copy == NULL) { kmip_node_free(value); return -ENOMEM; } rc = kmip_split_v1_custom_attr_name(copy, &vendor_id, &attr_name); if (rc != 0) { kmip_node_free(value); free(copy); return rc; } cloned_value = kmip_node_clone(value); kmip_node_free(value); if (cloned_value == NULL) { free(copy); return -ENOMEM; } *v2_attr = kmip_new_vendor_attribute(vendor_id, attr_name, cloned_value); free(copy); kmip_node_free(cloned_value); return 0; } v2_tag = kmip_attr_tag_by_v1_attr_name(name); if (v2_tag == 0) { kmip_node_free(value); return -EBADMSG; } cloned_value = kmip_node_clone(value); kmip_node_free(value); if (cloned_value == NULL) return -ENOMEM; cloned_value->tag = v2_tag; *v2_attr = cloned_value; return 0; } /** * Converts a KMIP v2.x Attribute into a KMIP v1.x Attribute * * @param v2_attr the KMIP v2.x attribute to convert * @param v1_attr On return: the KMIP v1.x attribute * * @returns 0 on success, or a negative errno in case of an error */ int kmip_v1_attr_from_v2_attr(struct kmip_node *v2_attr, struct kmip_node **v1_attr) { struct kmip_node *attr_value, *cloned_value; const char *attr_name, *vendor_id; char *custom_name; int rc; if (v2_attr == NULL || v1_attr == NULL) return -EINVAL; if (v2_attr->tag == KMIP_TAG_ATTRIBUTE) { /* Special handling for v2.x Vendor Attribute */ rc = kmip_get_vendor_attribute(v2_attr, &vendor_id, &attr_name, &attr_value); if (rc != 0) return rc; custom_name = kmip_build_v1_custom_attr_name(vendor_id, attr_name); if (custom_name == NULL) { kmip_node_free(attr_value); return -EBADMSG; } cloned_value = kmip_node_clone(attr_value); kmip_node_free(attr_value); if (cloned_value == NULL) { free(custom_name); return -ENOMEM; } *v1_attr = kmip_new_attribute_v1(custom_name, -1, cloned_value); kmip_node_free(cloned_value); free(custom_name); if (*v1_attr == NULL) return -ENOMEM; return 0; } attr_name = kmip_v1_attr_name_by_tag(v2_attr->tag); if (attr_name == NULL) return -EBADMSG; cloned_value = kmip_node_clone(v2_attr); if (cloned_value == NULL) return -ENOMEM; /* Modify the cloned v2 attr and use it as value of the v1 attr */ cloned_value->tag = KMIP_TAG_ATTRIBUTE_VALUE; *v1_attr = kmip_new_attribute_v1(attr_name, -1, cloned_value); kmip_node_free(cloned_value); if (*v1_attr == NULL) return -ENOMEM; return 0; } /** * Constructs an Attributes node (KMIP v2.x) or a Template Attribute node * (KMIP v1.x) from a list of attributes in KMIP v2.x style, dependent on the * protocol version specified: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Attributes Yes Structure v2.x only * No v2.x only * ... may be repeated * * Also applies to Common Attributes, Private Key Attributes, * Public Key Attributes * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Template-Attribute Yes Structure v1.x only * Name No Structure v1.x only * ... may be repeated * Attribute No Structure v1.x only * ... may be repeated * * Also applies to Common Template-Attribute, Private Key Template-Attribute, * Public Key Template-Attribute. * * @param version the protocol version. If null, the current default * protocol version is used. * @param v2_tag the attributes tag * @param attrs_count the number of attributes following * @param v2_attrs the array of attributes (as KMIP v2.x attributes) * * @returns the allocated node, or NULL in case of an error. * The reference counts of the nodes specified as parameters which are added to * the newly allocated node are increased. The caller must free its reference * via kmip_node_free() if no longer needed. */ struct kmip_node *kmip_new_attributes(const struct kmip_version *version, enum kmip_tag v2_tag, unsigned int attrs_count, struct kmip_node **v2_attrs) { struct kmip_node *attrs = NULL, *attr; struct kmip_node **v1_attrs = NULL; enum kmip_tag v1_tag = 0; unsigned int i; int rc; if (version == NULL) version = kmip_get_default_protocol_version(); if (version->major == 1) { /* KMIP v1.x: translate v1-tag to v2-tag */ switch (v2_tag) { case KMIP_TAG_ATTRIBUTES: v1_tag = KMIP_TAG_TEMPLATE_ATTRIBUTE; break; case KMIP_TAG_COMMON_ATTRIBUTES: v1_tag = KMIP_TAG_COMMON_TEMPLATE_ATTRIBUTE; break; case KMIP_TAG_PRIVATE_KEY_ATTRIBUTES: v1_tag = KMIP_TAG_PRIVATE_KEY_TEMPLATE_ATTRIBUTE; break; case KMIP_TAG_PUBLIC_KEY_ATTRIBUTES: v1_tag = KMIP_TAG_PUBLIC_KEY_TEMPLATE_ATTRIBUTE; break; default: return NULL; } if (attrs_count > 0) { v1_attrs = calloc(attrs_count, sizeof(struct kmip_node *)); if (v1_attrs == NULL) return NULL; } for (i = 0; i < attrs_count; i++) { attr = v2_attrs[i]; if (attr == NULL) goto error; rc = kmip_v1_attr_from_v2_attr(attr, &v1_attrs[i]); if (rc != 0) goto error; } attrs = kmip_new_template_attribute_v1(v1_tag, 0, NULL, attrs_count, v1_attrs); error: for (i = 0; i < attrs_count; i++) { if (v1_attrs[i] == NULL) continue; kmip_node_free(v1_attrs[i]); } if (v1_attrs != NULL) free(v1_attrs); } else { /* KMIP >= v2.0 */ attrs = kmip_new_attributes_v2(v2_tag, attrs_count, v2_attrs); } return attrs; } /** * Constructs an Attributes node (KMIP v2.x) or a Template Attribute node * (KMIP v1.x) from a list of attributes in KMIP v2.x style, dependent on the * protocol version specified: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Attributes Yes Structure v2.x only * No v2.x only * ... may be repeated * * Also applies to Common Attributes, Private Key Attributes, * Public Key Attributes * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Template-Attribute Yes Structure v1.x only * Name No Structure v1.x only * ... may be repeated * Attribute No Structure v1.x only * ... may be repeated * * Also applies to Common Template-Attribute, Private Key Template-Attribute, * Public Key Template-Attribute. * * @param version the protocol version. If null, the current default * protocol version is used. * @param v2_tag the attributes tag * @param attrs_count the number of attributes following * @param the attributes (as KMIP v2.x attribute) * * @returns the allocated node, or NULL in case of an error. * The reference counts of the nodes specified as parameters which are added to * the newly allocated node are increased. The caller must free its reference * via kmip_node_free() if no longer needed. */ struct kmip_node *kmip_new_attributes_va(const struct kmip_version *version, enum kmip_tag v2_tag, unsigned int attrs_count, ...) { struct kmip_node *ret, **attrs = NULL; unsigned int i, k; va_list ap; if (attrs_count > 0) { attrs = calloc(attrs_count, sizeof(struct kmip_node *)); if (attrs == NULL) return NULL; } va_start(ap, attrs_count); for (i = 0, k = 0; i < attrs_count; i++) { attrs[k] = va_arg(ap, struct kmip_node *); if (attrs[k] != NULL) k++; } va_end(ap); ret = kmip_new_attributes(version, v2_tag, k, attrs); if (attrs != NULL) free(attrs); return ret; } /** * Gets the information from an Attributes node (KMIP v2.x) or a Template * Attribute node (KMIP v1.x). The returned attribute is always in KMIP v2.x * style. * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Attributes Yes Structure v2.x only * No v2.x only * ... may be repeated * * Also applies to Common Attributes, Private Key Attributes, * Public Key Attributes * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Template-Attribute Yes Structure v1.x only * Name No Structure v1.x only * ... may be repeated * Attribute No Structure v1.x only * ... may be repeated * * Also applies to Common Template-Attribute, Private Key Template-Attribute, * Public Key Template-Attribute. * * @param node the KMIP node * @param num_attrs On return: the number of attributes (can be NULL). * @param attr_index the index of the attribute to return * @param value On return: the attribute item of the specified index * (as a KMIP v2.x attribute). * Function returns -ENOENT if no attribute is * available. Can be NULL, then no attribute entry is * returned. * * @returns 0 on success, or a negative errno in case of an error * The reference count of the returned nodes is increased. The caller must * free the node via kmip_node_free() when no longer needed. */ int kmip_get_attributes(const struct kmip_node *node, unsigned int *num_attrs, unsigned int attr_index, struct kmip_node **attr) { struct kmip_node *v1_attr, *v2_attr; int rc; if (node == NULL) return -EINVAL; switch (kmip_node_get_tag(node)) { case KMIP_TAG_TEMPLATE_ATTRIBUTE: case KMIP_TAG_COMMON_TEMPLATE_ATTRIBUTE: case KMIP_TAG_PRIVATE_KEY_TEMPLATE_ATTRIBUTE: case KMIP_TAG_PUBLIC_KEY_TEMPLATE_ATTRIBUTE: /* KMIP v1.x template attributes */ if (attr == NULL) { rc = kmip_get_template_attribute_v1(node, NULL, 0, NULL, num_attrs, 0, NULL); return rc; } rc = kmip_get_template_attribute_v1(node, NULL, 0, NULL, num_attrs, attr_index, &v1_attr); if (rc != 0) return rc; rc = kmip_v2_attr_from_v1_attr(v1_attr, &v2_attr); kmip_node_free(v1_attr); if (rc != 0) return rc; *attr = v2_attr; break; case KMIP_TAG_ATTRIBUTES: case KMIP_TAG_COMMON_ATTRIBUTES: case KMIP_TAG_PRIVATE_KEY_ATTRIBUTES: case KMIP_TAG_PUBLIC_KEY_ATTRIBUTES: /* KMIP v2.x attributes */ rc = kmip_get_attributes_v2(node, num_attrs, attr_index, attr); if (rc != 0) return rc; break; default: return -EBADMSG; } return 0; } /** * Constructs an Attribute Reference node (KMIP v2.x): * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Attribute Reference Yes Enumeration v2.x only * or * Attribute Reference Yes Structure v2.x only * Vendor Identification Yes Text String v2.x only * Attribute Name Yes Text String v2.x only * * @param attr_tag the attribute tag * @param vendor_id the vendor identification of the attribute * @param name the name of the attribute * * Either the attr_tag or the vendor_id and name can be specified, but not both. * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_attribute_reference(enum kmip_tag attr_tag, const char *vendor_id, const char *name) { struct kmip_node *ref = NULL, *nam, *vend = NULL; if (attr_tag == 0 && (vendor_id == NULL || name == NULL)) return NULL; if (attr_tag != 0 && (vendor_id != NULL || name != NULL)) return NULL; if (attr_tag != 0) return kmip_node_new_enumeration(KMIP_TAG_ATTRIBUTE_REFERENCE, NULL, attr_tag); vend = kmip_node_new_text_string(KMIP_TAG_VENDOR_IDENTIFICATION, NULL, vendor_id); nam = kmip_node_new_text_string(KMIP_TAG_ATTRIBUTE_NAME, NULL, name); if (nam == NULL || vend == NULL) goto out; ref = kmip_node_new_structure_va(KMIP_TAG_ATTRIBUTE_REFERENCE, NULL, 2, vend, nam); out: kmip_node_free(nam); kmip_node_free(vend); return ref; } /** * Gets the information from a Attribute Reference node (KMIP v2.x): * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Attribute Reference Yes Enumeration v2.x only * or * Attribute Reference Yes Structure v2.x only * Vendor Identification Yes Text String v2.x only * Attribute Name Yes Text String v2.x only * * @param node the KMIP node * @param attr_tag On return: The attribute tag (can be NULL) * @param vendor_id On return: the vendor identification (can be NULL) * @param name On return: the attribute name (can be NULL) * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_attribute_reference(const struct kmip_node *node, enum kmip_tag *attr_tag, const char **vendor_id, const char **name) { struct kmip_node *vend, *nam; int rc = 0; if (node == NULL) return -EINVAL; if (kmip_node_get_tag(node) != KMIP_TAG_ATTRIBUTE_REFERENCE) return -EBADMSG; if (kmip_node_get_type(node) == KMIP_TYPE_ENUMERATION) { if (attr_tag != NULL) *attr_tag = kmip_node_get_enumeration(node); if (vendor_id != NULL) vendor_id = NULL; if (name != NULL) *name = NULL; return 0; } if (kmip_node_get_type(node) != KMIP_TYPE_STRUCTURE) return -EBADMSG; if (attr_tag != NULL) *attr_tag = 0; vend = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_VENDOR_IDENTIFICATION, 0); nam = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_ATTRIBUTE_NAME, 0); if (vend == NULL || nam == NULL) { rc = -EBADMSG; goto out; } if (vendor_id != NULL) *vendor_id = kmip_node_get_text_string(vend); if (name != NULL) *name = kmip_node_get_text_string(nam); out: kmip_node_free(vend); kmip_node_free(nam); return rc; } /** * Constructs an Current or New Attribute node (KMIP v2.x): * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Current Attribute Yes Structure v2.x only * or * New Attribute Yes Structure v2.x only * * @param new_attr if true a New Attribute structure, if false a * Current Attribute structure is created * @param attr the KMIP v2.x attribute * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_current_new_attribute(bool new_attr, struct kmip_node *attr) { enum kmip_tag tag; if (attr == NULL) return NULL; tag = (new_attr ? KMIP_TAG_NEW_ATTRIBUTE : KMIP_TAG_CURRENT_ATTRIBUTE); return kmip_node_new_structure_va(tag, NULL, 1, attr); } /** * Constructs an Attribute Name node (KMIP v1.x) from a KMIP v2.x Attribute * Reference: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Attribute Name Yes Text String v1.x only * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Attribute Reference Yes Enumeration v2.x only * or * Attribute Reference Yes Structure v2.x only * Vendor Identification Yes Text String v2.x only * Attribute Name Yes Text String v2.x only * * @param v2_attr_ref the attribute reference node (as of KMIP v2.x) * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_attribute_name_v1( const struct kmip_node *v2_attr_ref) { const char *vendor_id = NULL, *attr_name = NULL; enum kmip_tag attr_tag = 0; struct kmip_node *ret; char *name = NULL; int rc; rc = kmip_get_attribute_reference(v2_attr_ref, &attr_tag, &vendor_id, &attr_name); if (rc != 0) return NULL; if (attr_tag != 0) { attr_name = kmip_v1_attr_name_by_tag(attr_tag); if (attr_name == NULL) return NULL; return kmip_node_new_text_string(KMIP_TAG_ATTRIBUTE_NAME, NULL, attr_name); } if (vendor_id == NULL || attr_name == NULL) return NULL; /* Special handling for v2.x Vendor Attribute */ name = kmip_build_v1_custom_attr_name(vendor_id, attr_name); if (name == NULL) return NULL; ret = kmip_node_new_text_string(KMIP_TAG_ATTRIBUTE_NAME, NULL, name); free(name); return ret; } /** * Gets the information from an Attribute Name node (KMIP v1.x) and returns * a KMIP v2.x Attribute Reference: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Attribute Name Yes Text String v1.x only * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Attribute Reference Yes Enumeration v2.x only * or * Attribute Reference Yes Structure v2.x only * Vendor Identification Yes Text String v2.x only * Attribute Name Yes Text String v2.x only * * @param node the KMIP node * @param v2_attr_ref On return: the attribute reference node (as of * KMIP v2.x) * * @returns 0 on success, or a negative errno in case of an error. * The reference count of the returned nodes is increased. The caller must * free the node via kmip_node_free() when no longer needed. */ int kmip_get_attribute_name_v1(const struct kmip_node *node, struct kmip_node **v2_attr_ref) { char *copy, *vendor_id, *attr_name; enum kmip_tag attr_tag; const char *name; int rc; if (node == NULL || v2_attr_ref == NULL) return -EINVAL; if (kmip_node_get_tag(node) != KMIP_TAG_ATTRIBUTE_NAME) return -EBADMSG; name = kmip_node_get_text_string(node); if (name == NULL) return -EBADMSG; if (strncmp(name, "x-", 2) == 0 || strncmp(name, "y-", 2) == 0) { /* Special handling for Custom Attribute */ copy = strdup(name); if (copy == NULL) return -ENOMEM; rc = kmip_split_v1_custom_attr_name(copy, &vendor_id, &attr_name); if (rc != 0) { free(copy); return rc; } *v2_attr_ref = kmip_new_attribute_reference(0, vendor_id, attr_name); free(copy); if (*v2_attr_ref == NULL) return -ENOMEM; return 0; } attr_tag = kmip_attr_tag_by_v1_attr_name(name); if (attr_tag == 0) return -EBADMSG; *v2_attr_ref = kmip_new_attribute_reference(attr_tag, NULL, NULL); if (*v2_attr_ref == NULL) return -ENOMEM; return 0; } /** * Constructs a Unique Identifier attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Unique Identifier Yes Text String v1.0 * Enumeration v2.0 * Integer v2.0 * * @param text_id the unique identifier as text string (or NULL) * @param enum_id the unique identifier as enumeration (or 0) * @param int_id the unique identifier as integer * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_unique_identifier(const char *text_id, enum kmip_unique_identifier enum_id, int32_t int_id) { if (text_id != NULL && enum_id != 0) return NULL; if (text_id != NULL) return kmip_node_new_text_string(KMIP_TAG_UNIQUE_IDENTIFIER, NULL, text_id); if (enum_id != 0) return kmip_node_new_enumeration(KMIP_TAG_UNIQUE_IDENTIFIER, NULL, enum_id); return kmip_node_new_integer(KMIP_TAG_UNIQUE_IDENTIFIER, NULL, int_id); } /** * Gets the information from a Unique Identifier attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Unique Identifier Yes Text String v1.0 * Enumeration v2.0 * Integer v2.0 * * @param node the KMIP node * @param text_id the unique identifier as text string (can be NULL) * @param enum_id the unique identifier as enumeration (can be NULL) * @param int_id the unique identifier as integer (can be NULL) * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_unique_identifier(const struct kmip_node *node, const char **text_id, enum kmip_unique_identifier *enum_id, int32_t *int_id) { if (node == NULL) return -EBADMSG; if (kmip_node_get_tag(node) != KMIP_TAG_UNIQUE_IDENTIFIER) return -EBADMSG; if (text_id != NULL) { if (kmip_node_get_type(node) == KMIP_TYPE_TEXT_STRING) *text_id = kmip_node_get_text_string(node); else *text_id = NULL; } if (enum_id != NULL) { if (kmip_node_get_type(node) == KMIP_TYPE_ENUMERATION) *enum_id = kmip_node_get_enumeration(node); else *enum_id = 0; } if (int_id != NULL) { if (kmip_node_get_type(node) == KMIP_TYPE_INTEGER) *int_id = kmip_node_get_integer(node); else *int_id = 0; } return 0; } /** * Constructs a Name attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Name Yes Structure v1.0 * Name Value Yes Text String v1.0 * Name Type Yes Enumeration v1.0 * * @param value the value of the name * @param type the type of the name * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_name(const char *value, enum kmip_name_type type) { struct kmip_node *name = NULL, *val, *typ; if (value == NULL) return NULL; val = kmip_node_new_text_string(KMIP_TAG_NAME_VALUE, NULL, value); typ = kmip_node_new_enumeration(KMIP_TAG_NAME_TYPE, NULL, type); if (val == NULL || typ == NULL) goto out; name = kmip_node_new_structure_va(KMIP_TAG_NAME, NULL, 2, val, typ); out: kmip_node_free(val); kmip_node_free(typ); return name; } /** * Gets the information from a Name attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Name Yes Structure v1.0 * Name Value Yes Text String v1.0 * Name Type Yes Enumeration v1.0 * * @param node the KMIP node * @param value On return: the name value (can be NULL) * @param type On return: the name type (can be NULL) * * @returns 0 on success, or a negative errno in case of an error * The reference count of the returned nodes is increased. The caller must * free the node via kmip_node_free() when no longer needed. */ int kmip_get_name(const struct kmip_node *node, const char **value, enum kmip_name_type *type) { struct kmip_node *val, *typ; int rc = 0; if (node == NULL) return -EINVAL; if (kmip_node_get_tag(node) != KMIP_TAG_NAME) return -EBADMSG; val = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_NAME_VALUE, 0); typ = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_NAME_TYPE, 0); if (val == NULL || typ == NULL) { rc = -EBADMSG; goto out; } if (value != NULL) *value = kmip_node_get_text_string(val); if (type != NULL) *type = kmip_node_get_enumeration(typ); out: kmip_node_free(val); kmip_node_free(typ); return rc; } /** * Constructs a Alternative Name attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Alternative Name Yes Structure v1.2 * Alternative Name Value Yes Text String v1.2 * Alternative Name Type Yes Enumeration v1.2 * * @param value the value of the alternative name * @param type the type of the alternative name * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_alternative_name(const char *value, enum kmip_alternative_name_type type) { struct kmip_node *name = NULL, *val, *typ; if (value == NULL) return NULL; val = kmip_node_new_text_string(KMIP_TAG_ALTERNATE_NAME_VALUE, NULL, value); typ = kmip_node_new_enumeration(KMIP_TAG_ALTERNATE_NAME_TYPE, NULL, type); if (val == NULL || typ == NULL) goto out; name = kmip_node_new_structure_va(KMIP_TAG_ALTERNATE_NAME, NULL, 2, val, typ); out: kmip_node_free(val); kmip_node_free(typ); return name; } /** * Gets the information from an Alternative Name attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Alternative Name Yes Structure v1.2 * Alternative Name Value Yes Text String v1.2 * Alternative Name Type Yes Enumeration v1.2 * * @param node the KMIP node * @param value On return: the alternative name value (can be NULL) * @param type On return: the alternative name type (can be NULL) * * @returns 0 on success, or a negative errno in case of an error * The reference count of the returned nodes is increased. The caller must * free the node via kmip_node_free() when no longer needed. */ int kmip_get_alternative_name(const struct kmip_node *node, const char **value, enum kmip_alternative_name_type *type) { struct kmip_node *val, *typ; int rc = 0; if (node == NULL) return -EINVAL; if (kmip_node_get_tag(node) != KMIP_TAG_ALTERNATE_NAME) return -EBADMSG; val = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_ALTERNATE_NAME_VALUE, 0); typ = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_ALTERNATE_NAME_TYPE, 0); if (val == NULL || typ == NULL) { rc = -EBADMSG; goto out; } if (value != NULL) *value = kmip_node_get_text_string(val); if (type != NULL) *type = kmip_node_get_enumeration(typ); out: kmip_node_free(val); kmip_node_free(typ); return rc; } /** * Constructs a Object Type attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Object Type Yes Enumeration v1.0 * * @param obj_type the object type * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_object_type(enum kmip_object_type obj_type) { return kmip_node_new_enumeration(KMIP_TAG_OBJECT_TYPE, NULL, obj_type); } /** * Gets the information from a Object Type attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Object Type Yes Enumeration v1.0 * * * @param node the KMIP node * @param obj_type the object type * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_object_type(const struct kmip_node *node, enum kmip_object_type *obj_type) { if (node == NULL || obj_type == NULL) return -EBADMSG; if (kmip_node_get_tag(node) != KMIP_TAG_OBJECT_TYPE) return -EBADMSG; *obj_type = kmip_node_get_enumeration(node); return 0; } /** * Constructs a Cryptographic Algorithm attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Cryptographic Algorithm Yes Enumeration v1.0 * * @param algo the cryptographic algorithm * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_cryptographic_algorithm(enum kmip_crypto_algo algo) { return kmip_node_new_enumeration(KMIP_TAG_CRYPTOGRAPHIC_ALGORITHM, NULL, algo); } /** * Gets the information from a Cryptographic Algorithm attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Cryptographic Algorithm Yes Enumeration v1.0 * * * @param node the KMIP node * @param algo the cryptographic algorithm * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_cryptographic_algorithm(const struct kmip_node *node, enum kmip_crypto_algo *algo) { if (node == NULL || algo == NULL) return -EBADMSG; if (kmip_node_get_tag(node) != KMIP_TAG_CRYPTOGRAPHIC_ALGORITHM) return -EBADMSG; *algo = kmip_node_get_enumeration(node); return 0; } /** * Constructs a Cryptographic Length attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Cryptographic Length Yes Integer v1.0 * * @param length the cryptographic length * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_cryptographic_length(int32_t length) { return kmip_node_new_integer(KMIP_TAG_CRYPTOGRAPHIC_LENGTH, NULL, length); } /** * Gets the information from a Cryptographic Length attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Cryptographic Length Yes Integer v1.0 * * * @param node the KMIP node * @param length the cryptographic length * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_cryptographic_length(const struct kmip_node *node, int32_t *length) { if (node == NULL || length == NULL) return -EBADMSG; if (kmip_node_get_tag(node) != KMIP_TAG_CRYPTOGRAPHIC_LENGTH) return -EBADMSG; *length = kmip_node_get_integer(node); return 0; } /** * Constructs a Certificate Type attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Certificate Type Yes Enumeration v1.0 * * @param type the certificate type * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_certificate_type(enum kmip_certificate_type type) { return kmip_node_new_enumeration(KMIP_TAG_CERTIFICATE_TYPE, NULL, type); } /** * Gets the information from a Certificate Type attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Certificate Type Yes Enumeration v1.0 * * * @param node the KMIP node * @param type the certificate type * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_certificate_type(const struct kmip_node *node, enum kmip_certificate_type *type) { if (node == NULL || type == NULL) return -EBADMSG; if (kmip_node_get_tag(node) != KMIP_TAG_CERTIFICATE_TYPE) return -EBADMSG; *type = kmip_node_get_enumeration(node); return 0; } /** * Constructs a Cryptographic Usage Mask attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Cryptographic Usage Mask Yes Integer v1.0 * * @param usage_mask the cryptographic usage mask * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_cryptographic_usage_mask(int32_t usage_mask) { return kmip_node_new_integer(KMIP_TAG_CRYPTOGRAPHIC_USAGE_MASK, NULL, usage_mask); } /** * Gets the information from a Cryptographic Usage Mask attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Cryptographic Usage Mask Yes Integer v1.0 * * * @param node the KMIP node * @param usage_mask the cryptographic usage mask * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_cryptographic_usage_mask(const struct kmip_node *node, int32_t *usage_mask) { if (node == NULL || usage_mask == NULL) return -EBADMSG; if (kmip_node_get_tag(node) != KMIP_TAG_CRYPTOGRAPHIC_USAGE_MASK) return -EBADMSG; *usage_mask = kmip_node_get_integer(node); return 0; } /** * Constructs a State attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * State Yes Enumeration v1.0 * * @param state the state * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_state(enum kmip_state state) { return kmip_node_new_enumeration(KMIP_TAG_STATE, NULL, state); } /** * Gets the information from a State attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * State Yes Enumeration v1.0 * * * @param node the KMIP node * @param state the state * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_state(const struct kmip_node *node, enum kmip_state *state) { if (node == NULL || state == NULL) return -EBADMSG; if (kmip_node_get_tag(node) != KMIP_TAG_STATE) return -EBADMSG; *state = kmip_node_get_enumeration(node); return 0; } /** * Constructs a Initial Date attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Initial Date Yes Date-Time v1.0 * * @param date the date * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_initial_date(int64_t date) { return kmip_node_new_enumeration(KMIP_TAG_INITIAL_DATE, NULL, date); } /** * Gets the information from a Initial Date attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Initial Date Yes Date-Time v1.0 * * * @param node the KMIP node * @param date the date * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_initial_date(const struct kmip_node *node, int64_t *date) { if (node == NULL || date == NULL) return -EBADMSG; if (kmip_node_get_tag(node) != KMIP_TAG_INITIAL_DATE) return -EBADMSG; *date = kmip_node_get_date_time(node); return 0; } /** * Constructs a Activation Date attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Activation Date Yes Date-Time v1.0 * * @param date the date * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_activation_date(int64_t date) { return kmip_node_new_enumeration(KMIP_TAG_ACTIVATION_DATE, NULL, date); } /** * Gets the information from a Activation Date attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Activation Date Yes Date-Time v1.0 * * * @param node the KMIP node * @param date the date * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_activation_date(const struct kmip_node *node, int64_t *date) { if (node == NULL || date == NULL) return -EBADMSG; if (kmip_node_get_tag(node) != KMIP_TAG_ACTIVATION_DATE) return -EBADMSG; *date = kmip_node_get_date_time(node); return 0; } /** * Constructs a Deactivation Date attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Deactivation Date Yes Date-Time v1.0 * * @param date the date * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_deactivation_date(int64_t date) { return kmip_node_new_enumeration(KMIP_TAG_DEACTIVATION_DATE, NULL, date); } /** * Gets the information from a Deactivation Date attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Deactivation Date Yes Date-Time v1.0 * * * @param node the KMIP node * @param date the date * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_deactivation_date(const struct kmip_node *node, int64_t *date) { if (node == NULL || date == NULL) return -EBADMSG; if (kmip_node_get_tag(node) != KMIP_TAG_DEACTIVATION_DATE) return -EBADMSG; *date = kmip_node_get_date_time(node); return 0; } /** * Constructs a Destroy Date attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Destroy Date Yes Date-Time v1.0 * * @param date the date * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_destroy_date(int64_t date) { return kmip_node_new_enumeration(KMIP_TAG_DESTROY_DATE, NULL, date); } /** * Gets the information from a Destroy Date attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Destroy Date Yes Date-Time v1.0 * * * @param node the KMIP node * @param date the date * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_destroy_date(const struct kmip_node *node, int64_t *date) { if (node == NULL || date == NULL) return -EBADMSG; if (kmip_node_get_tag(node) != KMIP_TAG_DESTROY_DATE) return -EBADMSG; *date = kmip_node_get_date_time(node); return 0; } /** * Constructs a Compromise Date attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Compromise Date Yes Date-Time v1.0 * * @param date the date * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_compromise_date(int64_t date) { return kmip_node_new_enumeration(KMIP_TAG_COMPROMIZE_DATE, NULL, date); } /** * Gets the information from a Compromise Date attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Compromise Date Yes Date-Time v1.0 * * * @param node the KMIP node * @param date the date * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_compromise_date(const struct kmip_node *node, int64_t *date) { if (node == NULL || date == NULL) return -EBADMSG; if (kmip_node_get_tag(node) != KMIP_TAG_COMPROMIZE_DATE) return -EBADMSG; *date = kmip_node_get_date_time(node); return 0; } /** * Constructs a Compromise Occurrence Date attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Compromise Occurrence Date Yes Date-Time v1.0 * * @param date the date * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_compromise_occurrence_date(int64_t date) { return kmip_node_new_enumeration(KMIP_TAG_COMPROMISE_OCCURRENCE_DATE, NULL, date); } /** * Gets the information from a Compromise Occurrence Date attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Compromise Occurrence Date Yes Date-Time v1.0 * * * @param node the KMIP node * @param date the date * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_compromise_occurrence_date(const struct kmip_node *node, int64_t *date) { if (node == NULL || date == NULL) return -EBADMSG; if (kmip_node_get_tag(node) != KMIP_TAG_COMPROMISE_OCCURRENCE_DATE) return -EBADMSG; *date = kmip_node_get_date_time(node); return 0; } /** * Constructs a Last Change Date attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Last Change Date Yes Date-Time v1.0 * * @param date the date * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_last_change_date(int64_t date) { return kmip_node_new_enumeration(KMIP_TAG_LAST_CHANGE_DATE, NULL, date); } /** * Gets the information from a Last Change Date attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Last Change Date Yes Date-Time v1.0 * * * @param node the KMIP node * @param date the date * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_last_change_date(const struct kmip_node *node, int64_t *date) { if (node == NULL || date == NULL) return -EBADMSG; if (kmip_node_get_tag(node) != KMIP_TAG_LAST_CHANGE_DATE) return -EBADMSG; *date = kmip_node_get_date_time(node); return 0; } /** * Constructs a Original Creation Date attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Original Creation Date Yes Date-Time v1.0 * * @param date the date * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_original_creation_date(int64_t date) { return kmip_node_new_enumeration(KMIP_TAG_ORIGINAL_CREATION_DATE, NULL, date); } /** * Gets the information from a Original Creation Date attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Original Creation Date Yes Date-Time v1.0 * * * @param node the KMIP node * @param date the date * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_original_creation_date(const struct kmip_node *node, int64_t *date) { if (node == NULL || date == NULL) return -EBADMSG; if (kmip_node_get_tag(node) != KMIP_TAG_ORIGINAL_CREATION_DATE) return -EBADMSG; *date = kmip_node_get_date_time(node); return 0; } /** * Constructs a Archive Date attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Archive Date Yes Date-Time v1.0 * * @param date the date * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_archive_date(int64_t date) { return kmip_node_new_enumeration(KMIP_TAG_ARCHIVE_DATE, NULL, date); } /** * Gets the information from a Archive Date attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Archive Date Yes Date-Time v1.0 * * * @param node the KMIP node * @param date the date * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_archive_date(const struct kmip_node *node, int64_t *date) { if (node == NULL || date == NULL) return -EBADMSG; if (kmip_node_get_tag(node) != KMIP_TAG_ARCHIVE_DATE) return -EBADMSG; *date = kmip_node_get_date_time(node); return 0; } /** * Constructs a Process Start Date attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Process Start Date Yes Date-Time v1.0 * * @param date the date * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_process_start_date(int64_t date) { return kmip_node_new_enumeration(KMIP_TAG_PROCESS_START_DATE, NULL, date); } /** * Gets the information from a Process Start Date attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Process Start Date Yes Date-Time v1.0 * * * @param node the KMIP node * @param date the date * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_process_start_date(const struct kmip_node *node, int64_t *date) { if (node == NULL || date == NULL) return -EBADMSG; if (kmip_node_get_tag(node) != KMIP_TAG_PROCESS_START_DATE) return -EBADMSG; *date = kmip_node_get_date_time(node); return 0; } /** * Constructs a Protect Stop Date attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Protect Stop Date Yes Date-Time v1.0 * * @param date the date * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_protect_stop_date(int64_t date) { return kmip_node_new_enumeration(KMIP_TAG_PROTECT_STOP_DATE, NULL, date); } /** * Gets the information from a Protect Stop Date attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Protect Stop Date Yes Date-Time v1.0 * * @param node the KMIP node * @param date the date * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_protect_stop_date(const struct kmip_node *node, int64_t *date) { if (node == NULL || date == NULL) return -EBADMSG; if (kmip_node_get_tag(node) != KMIP_TAG_PROTECT_STOP_DATE) return -EBADMSG; *date = kmip_node_get_date_time(node); return 0; } /** * Constructs a Cryptographic Parameters attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Cryptographic Parameters Structure v1.0 * Block Cipher Mode No Enumeration v1.0 * Padding Method No Enumeration v1.0 * Hashing Algorithm No Enumeration v1.0 * Key Role Type No Enumeration v1.0 * Digital Signature Algorithm No Enumeration v1.2 * Cryptographic Algorithm No Enumeration v1.2 * Random IV No Boolean v1.2 * IV Length No Integer v1.2 * Tag Length No Integer v1.2 * Fixed Field Length No Integer v1.2 * Invocation Field Length No Integer v1.2 * Counter Length No Integer v1.2 * Initial Counter Value No Integer v1.2 * Salt Length No Integer v1.4 * Mask Generator No Enumeration v1.4 * Mask Generator Hashing Alg No Enumeration v1.4 * P Source No Byte String v1.4 * Trailer Field No Integer v1.4 * * @param version the protocol version. If null, the current default * protocol version is used. * @param mode the block cipher mode (ignored if 0) * @param padding the padding method (ignored if 0) * @param hash_algo the hashing algorithm (ignored if 0) * @param key_role the key role type (ignored if 0) * @param signature_algo the signature algorithm (ignored if 0) * @param crypto_algo the cryptographic algorithm (ignored if 0) * @param random_iv true if a random IV is used (ignored if NULL) * @param iv_length the IV length (ignored if NULL) * @param tag_length the tag length (ignored if NULL) * @param fixed_field_length the fixed field length (ignored if NULL) * @param invoc_field_length the invocation field length (ignored if NULL) * @param counter_length the counter length (ignored if NULL) * @param init_counter_value the initial counter value (ignored if NULL) * @param salt_length the salt length (ignored if NULL) * @param mgf the mask generator (ignored if 0) * @param mgf_hash_algo the mask generator hash algorithm (ignored if 0) * @param trailer_field the trailer field (ignored if NULL) * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_cryptographic_parameters( const struct kmip_version *version, enum kmip_block_cipher_mode mode, enum kmip_padding_method padding, enum kmip_hashing_algo hash_algo, enum kmip_key_role_type key_role, enum kmip_signature_algo signature_algo, enum kmip_crypto_algo crypto_algo, bool *random_iv, int32_t *iv_length, int32_t *tag_length, int32_t *fixed_field_length, int32_t *invoc_field_length, int32_t *counter_length, int32_t *init_counter_value, int32_t *salt_length, enum kmip_mask_generator mgf, enum kmip_hashing_algo mgf_hash_algo, int32_t *trailer_field) { struct kmip_node *icv = NULL, *salt = NULL, *mg = NULL, *mghash = NULL; struct kmip_node *ret = NULL, *cmod = NULL, *pad = NULL, *hash = NULL; struct kmip_node *krl = NULL, *sig = NULL, *algo = NULL, *riv = NULL; struct kmip_node *iv = NULL, *tag = NULL, *ffl = NULL, *ifl = NULL; struct kmip_node *cnt = NULL, *trl = NULL; if (version == NULL) version = kmip_get_default_protocol_version(); if (mode != 0) { cmod = kmip_node_new_enumeration(KMIP_TAG_BLOCK_CIPHER_MODE, NULL, mode); if (cmod == NULL) goto out; } if (padding != 0) { pad = kmip_node_new_enumeration(KMIP_TAG_PADDING_METHOD, NULL, padding); if (pad == NULL) goto out; } if (hash_algo != 0) { hash = kmip_node_new_enumeration(KMIP_TAG_HASHING_ALGORITHM, NULL, hash_algo); if (hash == NULL) goto out; } if (key_role != 0) { krl = kmip_node_new_enumeration(KMIP_TAG_KEY_ROLE_TYPE, NULL, key_role); if (krl == NULL) goto out; } if (version->major == 1 && version->minor < 2) goto create; if (signature_algo != 0) { sig = kmip_node_new_enumeration( KMIP_TAG_DIGITAL_SIGNATURE_ALGORITHM, NULL, signature_algo); if (sig == NULL) goto out; } if (crypto_algo != 0) { algo = kmip_node_new_enumeration( KMIP_TAG_CRYPTOGRAPHIC_ALGORITHM, NULL, crypto_algo); if (algo == NULL) goto out; } if (random_iv != NULL) { riv = kmip_node_new_boolean(KMIP_TAG_RANDOM_IV, NULL, *random_iv); if (riv == NULL) goto out; } if (iv_length != NULL) { iv = kmip_node_new_integer(KMIP_TAG_IV_LENGTH, NULL, *iv_length); if (iv == NULL) goto out; } if (tag_length != NULL) { tag = kmip_node_new_integer(KMIP_TAG_TAG_LENGTH, NULL, *tag_length); if (tag == NULL) goto out; } if (fixed_field_length != NULL) { ffl = kmip_node_new_integer(KMIP_TAG_FIXED_FIELD_LENGTH, NULL, *fixed_field_length); if (ffl == NULL) goto out; } if (invoc_field_length != NULL) { ifl = kmip_node_new_integer(KMIP_TAG_INVOCATION_FIELD_LENGTH, NULL, *invoc_field_length); if (ifl == NULL) goto out; } if (counter_length != NULL) { cnt = kmip_node_new_integer(KMIP_TAG_COUNTER_LENGTH, NULL, *counter_length); if (cnt == NULL) goto out; } if (init_counter_value != NULL) { icv = kmip_node_new_integer(KMIP_TAG_INITIAL_COUNTER_VALUE, NULL, *init_counter_value); if (icv == NULL) goto out; } if (version->major == 1 && version->minor < 4) goto create; if (salt_length != NULL) { salt = kmip_node_new_integer(KMIP_TAG_SALT_LENGTH, NULL, *salt_length); if (salt == NULL) goto out; } if (mgf != 0) { mg = kmip_node_new_enumeration(KMIP_TAG_MASK_GENERATOR, NULL, mgf); if (mg == NULL) goto out; } if (mgf_hash_algo != 0) { mghash = kmip_node_new_enumeration( KMIP_TAG_MASK_GENERATOR_HASHING_ALGORITHM, NULL, mgf_hash_algo); if (mghash == NULL) goto out; } if (trailer_field != NULL) { trl = kmip_node_new_integer(KMIP_TAG_TRAILER_FIELD, NULL, *trailer_field); if (trl == NULL) goto out; } create: ret = kmip_node_new_structure_va(KMIP_TAG_CRYPTOGRAPHIC_PARAMETERS, NULL, 17, cmod, pad, hash, krl, sig, algo, riv, iv, tag, ffl, ifl, cnt, icv, salt, mg, mghash, trl); out: kmip_node_free(cmod); kmip_node_free(pad); kmip_node_free(hash); kmip_node_free(krl); kmip_node_free(sig); kmip_node_free(algo); kmip_node_free(riv); kmip_node_free(iv); kmip_node_free(tag); kmip_node_free(ffl); kmip_node_free(ifl); kmip_node_free(cnt); kmip_node_free(icv); kmip_node_free(salt); kmip_node_free(mg); kmip_node_free(mghash); kmip_node_free(trl); return ret; } /** * Gets information from a Cryptographic Parameter attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Cryptographic Parameters Structure v1.0 * Block Cipher Mode No Enumeration v1.0 * Padding Method No Enumeration v1.0 * Hashing Algorithm No Enumeration v1.0 * Key Role Type No Enumeration v1.0 * Digital Signature Algorithm No Enumeration v1.2 * Cryptographic Algorithm No Enumeration v1.2 * Random IV No Boolean v1.2 * IV Length No Integer v1.2 * Tag Length No Integer v1.2 * Fixed Field Length No Integer v1.2 * Invocation Field Length No Integer v1.2 * Counter Length No Integer v1.2 * Initial Counter Value No Integer v1.2 * Salt Length No Integer v1.4 * Mask Generator No Enumeration v1.4 * Mask Generator Hashing Alg No Enumeration v1.4 * P Source No Byte String v1.4 * Trailer Field No Integer v1.4 * * @param node the KMIP node * @param mode On return: the block cipher mode (0 if not avail, * can be NULL) * @param padding On return: the padding method (0 if not avail, * can be NULL) * @param hash_algo On return: the hashing algorithm (0 if not avail, * can be NULL) * @param key_role On return: the key role type (0 if not avail, * can be NULL) * @param signature_algo On return: the signature algorithm (0 if not avail, * can be NULL) * @param crypto_algo On return: the cryptographic algorithm (0 if not * avail, can be NULL) * @param random_iv On return: true if a random IV is used (false if * not avail, can be NULL) * @param iv_length On return: the IV length (-1 if not avail, can be * NULL) * @param tag_length On return: the tag length (-1 if not avail, can be * NULL) * @param fixed_field_length On return: the fixed field length (-1 if not avail, * can be NULL) * @param invoc_field_length On return: the invocation field length (-1 if not * avail, can be NULL) * @param counter_length On return: the counter length (-1 if not avail, * can be NULL) * @param init_counter_value On return: the initial counter value (0 if not * avail, can be NULL) * @param salt_length On return: the salt length (-1 if not avail, * can be NULL) * @param mgf On return: the mask generator (0 if not avail, * can be NULL) * @param mgf_hash_algo On return: the mask generator hash algorithm (0 if * not avail, can be NULL) * @param trailer_field On return: the trailer field (0 if not avail, * can be NULL) * * @returns 0 on success, or a negative errno in case of an error. * The reference count of the returned nodes is increased. The caller must * free the node via kmip_node_free() when no longer needed. */ int kmip_get_cryptographic_parameter(const struct kmip_node *node, enum kmip_block_cipher_mode *mode, enum kmip_padding_method *padding, enum kmip_hashing_algo *hash_algo, enum kmip_key_role_type *key_role, enum kmip_signature_algo *signature_algo, enum kmip_crypto_algo *crypto_algo, bool *random_iv, int32_t *iv_length, int32_t *tag_length, int32_t *fixed_field_length, int32_t *invoc_field_length, int32_t *counter_length, int32_t *init_counter_value, int32_t *salt_length, enum kmip_mask_generator *mgf, enum kmip_hashing_algo *mgf_hash_algo, int32_t *trailer_field) { struct kmip_node *n; if (node == NULL) return -EINVAL; if (kmip_node_get_tag(node) != KMIP_TAG_CRYPTOGRAPHIC_PARAMETERS) return -EBADMSG; if (mode != NULL) { n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_BLOCK_CIPHER_MODE, 0); *mode = (n != NULL ? kmip_node_get_enumeration(n) : 0); kmip_node_free(n); } if (padding != NULL) { n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_PADDING_METHOD, 0); *padding = (n != NULL ? kmip_node_get_enumeration(n) : 0); kmip_node_free(n); } if (hash_algo != NULL) { n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_HASHING_ALGORITHM, 0); *hash_algo = (n != NULL ? kmip_node_get_enumeration(n) : 0); kmip_node_free(n); } if (key_role != NULL) { n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_KEY_ROLE_TYPE, 0); *key_role = (n != NULL ? kmip_node_get_enumeration(n) : 0); kmip_node_free(n); } if (signature_algo != NULL) { n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_DIGITAL_SIGNATURE_ALGORITHM, 0); *signature_algo = (n != NULL ? kmip_node_get_enumeration(n) : 0); kmip_node_free(n); } if (crypto_algo != NULL) { n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_CRYPTOGRAPHIC_ALGORITHM, 0); *crypto_algo = (n != NULL ? kmip_node_get_enumeration(n) : 0); kmip_node_free(n); } if (random_iv != NULL) { n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_RANDOM_IV, 0); *random_iv = (n != NULL ? kmip_node_get_boolean(n) : false); kmip_node_free(n); } if (iv_length != NULL) { n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_IV_LENGTH, 0); *iv_length = (n != NULL ? kmip_node_get_integer(n) : -1); kmip_node_free(n); } if (tag_length != NULL) { n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_TAG_LENGTH, 0); *tag_length = (n != NULL ? kmip_node_get_integer(n) : -1); kmip_node_free(n); } if (fixed_field_length != NULL) { n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_FIXED_FIELD_LENGTH, 0); *fixed_field_length = (n != NULL ? kmip_node_get_integer(n) : -1); kmip_node_free(n); } if (invoc_field_length != NULL) { n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_INVOCATION_FIELD_LENGTH, 0); *invoc_field_length = (n != NULL ? kmip_node_get_integer(n) : -1); kmip_node_free(n); } if (counter_length != NULL) { n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_COUNTER_LENGTH, 0); *counter_length = (n != NULL ? kmip_node_get_integer(n) : -1); kmip_node_free(n); } if (init_counter_value != NULL) { n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_INITIAL_COUNTER_VALUE, 0); *init_counter_value = (n != NULL ? kmip_node_get_integer(n) : 0); kmip_node_free(n); } if (salt_length != NULL) { n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_SALT_LENGTH, 0); *salt_length = (n != NULL ? kmip_node_get_integer(n) : -1); kmip_node_free(n); } if (mgf != NULL) { n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_MASK_GENERATOR, 0); *mgf = (n != NULL ? kmip_node_get_enumeration(n) : 0); kmip_node_free(n); } if (mgf_hash_algo != NULL) { n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_MASK_GENERATOR_HASHING_ALGORITHM, 0); *mgf_hash_algo = (n != NULL ? kmip_node_get_enumeration(n) : 0); kmip_node_free(n); } if (trailer_field != NULL) { n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_TRAILER_FIELD, 0); *trailer_field = (n != NULL ? kmip_node_get_integer(n) : 0); kmip_node_free(n); } return 0; } /** * Constructs a Cryptographic Domain Parameters attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Cryptographic Domain Params Yes Structure v1.0 * Qlength No Integer v1.0 * Recommended Curve No Enumeration v1.0 * * @param qlength the Q length (ignored of <= 0) * @param curve the curve (ignored if 0) * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_cryptographic_domain_parameters( int32_t qlength, enum kmip_recommended_curve curve) { struct kmip_node *ret = NULL, *qlen = NULL, *crv = NULL; if (qlength > 0) { qlen = kmip_node_new_integer(KMIP_TAG_Q_LENGTH, NULL, qlength); if (qlen == NULL) goto out; } if (curve != 0) { crv = kmip_node_new_enumeration(KMIP_TAG_RECOMMENDED_CURVE, NULL, curve); if (crv == NULL) goto out; } ret = kmip_node_new_structure_va( KMIP_TAG_CRYPTOGRAPHIC_DOMAIN_PARAMETERS, NULL, 2, qlen, crv); out: kmip_node_free(qlen); kmip_node_free(crv); return ret; } /** * Gets the information from a Cryptographic Domain Parameters attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Cryptographic Domain Params Yes Structure v1.0 * Qlength No Integer v1.0 * Recommended Curve No Enumeration v1.0 * * @param node the KMIP node * @param qlength On return: the Q length (-1 if not avail, can be * NULL) * @param curve On return: the curve (0 if not avail, can be NULL) * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_cryptographic_domain_parameters(const struct kmip_node *node, int32_t *qlength, enum kmip_recommended_curve *curve) { struct kmip_node *n; if (node == NULL) return -EINVAL; if (kmip_node_get_tag(node) != KMIP_TAG_CRYPTOGRAPHIC_DOMAIN_PARAMETERS) return -EBADMSG; if (qlength != NULL) { n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_Q_LENGTH, 0); *qlength = (n != NULL ? kmip_node_get_integer(n) : -1); kmip_node_free(n); } if (curve != NULL) { n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_RECOMMENDED_CURVE, 0); *curve = (n != NULL ? kmip_node_get_enumeration(n) : 0); kmip_node_free(n); } return 0; } /** * Constructs a Digital Signature Algorithm attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Digital Signature Algorithm Yes Enumeration v1.2 * * @param signature_algo the signature algorithm * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_digital_signature_algorithm( enum kmip_signature_algo signature_algo) { return kmip_node_new_enumeration(KMIP_TAG_DIGITAL_SIGNATURE_ALGORITHM, NULL, signature_algo); } /** * Gets the information from a Digital Signature Algorithm attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Digital Signature Algorithm Yes Enumeration v1.2 * * @param node the KMIP node * @param signature_algo the signature algorithm * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_digital_signature_algorithm(const struct kmip_node *node, enum kmip_signature_algo *signature_algo) { if (node == NULL || signature_algo == NULL) return -EBADMSG; if (kmip_node_get_tag(node) != KMIP_TAG_DIGITAL_SIGNATURE_ALGORITHM) return -EBADMSG; *signature_algo = kmip_node_get_enumeration(node); return 0; } /** * Constructs a Object Group attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Object Group Yes Text String v1.0 * * @param group the object group * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_object_group(const char *group) { return kmip_node_new_text_string(KMIP_TAG_OBJECT_GROUP, NULL, group); } /** * Gets the information from a Object Group attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Object Group Yes Text String v1.0 * * @param node the KMIP node * @param group the object group * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_object_group(const struct kmip_node *node, const char **group) { if (node == NULL || group == NULL) return -EBADMSG; if (kmip_node_get_tag(node) != KMIP_TAG_OBJECT_GROUP) return -EBADMSG; *group = kmip_node_get_text_string(node); return 0; } /** * Constructs a Revocation Reason attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Revocation Reason Yes Structure v1.0 * Revocation Reason Code Yes Enumeration v1.0 * Revocation Message No Text String v1.0 * * @param reason the revocation reason code * @param message the revocation message (can be NULL) * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_revocation_reason(enum kmip_revoke_reason reason, const char *message) { struct kmip_node *ret = NULL, *rsn, *msg = NULL; rsn = kmip_node_new_enumeration(KMIP_TAG_REVOCATION_REASON_CODE, NULL, reason); if (rsn == NULL) goto out; if (message != NULL) { msg = kmip_node_new_text_string(KMIP_TAG_REVOCATION_MESSAGE, NULL, message); if (msg == NULL) goto out; } ret = kmip_node_new_structure_va(KMIP_TAG_REVOCATION_REASON, NULL, 2, rsn, msg); out: kmip_node_free(rsn); kmip_node_free(msg); return ret; } /** * Gets the information from a Revocation Reason attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Revocation Reason Yes Structure v1.0 * Revocation Reason Code Yes Enumeration v1.0 * Revocation Message No Text String v1.0 * * @param node the KMIP node * @param reason the revocation reason code * @param message the revocation message (can be NULL) * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_revocation_reason(const struct kmip_node *node, enum kmip_revoke_reason *reason, const char **message) { struct kmip_node *n; if (node == NULL || reason == NULL) return -EINVAL; if (kmip_node_get_tag(node) != KMIP_TAG_REVOCATION_REASON) return -EBADMSG; n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_REVOCATION_REASON_CODE, 0); if (n == NULL) return -EBADMSG; *reason = kmip_node_get_enumeration(n); kmip_node_free(n); if (message != NULL) { n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_REVOCATION_MESSAGE, 0); *message = (n != NULL ? kmip_node_get_text_string(n) : NULL); kmip_node_free(n); } return 0; } /** * Constructs a Contact Information attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Contact Information Yes Text String v1.0 * * @param contact the contact information * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_contact_information(const char *contact) { return kmip_node_new_text_string(KMIP_TAG_CONTACT_INFORMATION, NULL, contact); } /** * Gets the information from a Contact Information attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Contact Information Yes Text String v1.0 * * @param node the KMIP node * @param contact the contact information * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_contact_information(const struct kmip_node *node, const char **contact) { if (node == NULL || contact == NULL) return -EBADMSG; if (kmip_node_get_tag(node) != KMIP_TAG_CONTACT_INFORMATION) return -EBADMSG; *contact = kmip_node_get_text_string(node); return 0; } /** * Constructs a Description attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Description Yes Text String v1.4 * * @param description the description * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_description(const char *description) { return kmip_node_new_text_string(KMIP_TAG_DESCRIPTION, NULL, description); } /** * Gets the information from a Description attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Description Yes Text String v1.4 * * @param node the KMIP node * @param description the description * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_description(const struct kmip_node *node, const char **description) { if (node == NULL || description == NULL) return -EBADMSG; if (kmip_node_get_tag(node) != KMIP_TAG_DESCRIPTION) return -EBADMSG; *description = kmip_node_get_text_string(node); return 0; } /** * Constructs a Comment attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Comment Yes Text String v1.4 * * @param comment the comment * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_comment(const char *comment) { return kmip_node_new_text_string(KMIP_TAG_COMMENT, NULL, comment); } /** * Gets the information from a Comment attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Comment Yes Text String v1.4 * * @param node the KMIP node * @param comment the comment * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_comment(const struct kmip_node *node, const char **comment) { if (node == NULL || comment == NULL) return -EBADMSG; if (kmip_node_get_tag(node) != KMIP_TAG_COMMENT) return -EBADMSG; *comment = kmip_node_get_text_string(node); return 0; } /** * Constructs a Key Format Type attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Key Format Type Yes Enumeration v2.0 * * @param type the key format type * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_key_format_type(enum kmip_key_format_type type) { return kmip_node_new_enumeration(KMIP_TAG_KEY_FORMAT_TYPE, NULL, type); } /** * Gets the information from a Key Format Type attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Key Format Type Yes Enumeration v2.0 * * @param node the KMIP node * @param type the key format type * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_key_format_type(const struct kmip_node *node, enum kmip_key_format_type *type) { if (node == NULL || type == NULL) return -EBADMSG; if (kmip_node_get_tag(node) != KMIP_TAG_KEY_FORMAT_TYPE) return -EBADMSG; *type = kmip_node_get_enumeration(node); return 0; } /** * Constructs a Protection Level attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Protection Level Yes Enumeration v2.0 * * @param level the protection level * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_protection_level(enum kmip_protection_level level) { return kmip_node_new_enumeration(KMIP_TAG_PROTECTION_LEVEL, NULL, level); } /** * Gets the information from a Protection Level attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Protection Level Yes Enumeration v2.0 * * @param node the KMIP node * @param level the protection level * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_protection_level(const struct kmip_node *node, enum kmip_protection_level *level) { if (node == NULL || level == NULL) return -EBADMSG; if (kmip_node_get_tag(node) != KMIP_TAG_PROTECTION_LEVEL) return -EBADMSG; *level = kmip_node_get_enumeration(node); return 0; } /** * Constructs a Protection Period attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Protection Period Yes Interval v2.0 * * @param period the protection period * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_protection_period(uint32_t period) { return kmip_node_new_interval(KMIP_TAG_PROTECTION_PERIOD, NULL, period); } /** * Gets the information from a Protection Period attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Protection Period Yes Interval v2.0 * * @param node the KMIP node * @param period the protection period * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_protection_period(const struct kmip_node *node, uint32_t *period) { if (node == NULL || period == NULL) return -EBADMSG; if (kmip_node_get_tag(node) != KMIP_TAG_PROTECTION_PERIOD) return -EBADMSG; *period = kmip_node_get_interval(node); return 0; } /** * Constructs a Protection Storage Mask attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Protection Storage Mask Yes Integer v2.0 * * @param protection_mask the protection mask * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_protection_storage_mask(int32_t protection_mask) { return kmip_node_new_integer(KMIP_TAG_PROTECTION_STORAGE_MASK, NULL, protection_mask); } /** * Gets the information from a Protection Storage Mask attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Protection Storage Mask Yes Integer v2.0 * * @param node the KMIP node * @param protection_mask the protection mask * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_protection_storage_mask(const struct kmip_node *node, int32_t *protection_mask) { if (node == NULL || protection_mask == NULL) return -EBADMSG; if (kmip_node_get_tag(node) != KMIP_TAG_PROTECTION_STORAGE_MASK) return -EBADMSG; *protection_mask = kmip_node_get_integer(node); return 0; } /** * Constructs a Fresh attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Fresh Yes Boolean v1.2 * * @param fresh the fresh value * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_fresh(bool fresh) { return kmip_node_new_boolean(KMIP_TAG_FRESH, NULL, fresh); } /** * Gets the information from a Fresh attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Fresh Yes Boolean v1.2 * * @param node the KMIP node * @param fresh the fresh value * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_fresh(const struct kmip_node *node, bool *fresh) { if (node == NULL || fresh == NULL) return -EBADMSG; if (kmip_node_get_tag(node) != KMIP_TAG_FRESH) return -EBADMSG; *fresh = kmip_node_get_boolean(node); return 0; } /** * Constructs a Key Value Present attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Key Value Present Yes Boolean v1.2 * * @param present the present value * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_key_value_present(bool present) { return kmip_node_new_boolean(KMIP_TAG_KEY_VALUE_PRESENT, NULL, present); } /** * Gets the information from a Key Value Present attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Key Value Present Yes Boolean v1.2 * * @param node the KMIP node * @param present the present value * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_key_value_present(const struct kmip_node *node, bool *present) { if (node == NULL || present == NULL) return -EBADMSG; if (kmip_node_get_tag(node) != KMIP_TAG_KEY_VALUE_PRESENT) return -EBADMSG; *present = kmip_node_get_boolean(node); return 0; } /** * Constructs a Short Unique Identifier attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Short Unique Identifier Yes Byte String v2.0 * * @param short_uid the short unique identifier * @param short_uid_len the length of the short unique identifier * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_short_unique_identifier( const unsigned char *short_uid, uint32_t short_uid_len) { return kmip_node_new_byte_string(KMIP_TAG_SHORT_UNIQUE_IDENTIFIER, NULL, short_uid, short_uid_len); } /** * Gets the information from a Short Unique Identifier attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Short Unique Identifier Yes Byte String v2.0 * * @param node the KMIP node * @param short_uid the short unique identifier * @param short_uid_len the length of the short unique identifier * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_short_unique_identifier(const struct kmip_node *node, const unsigned char **short_uid, uint32_t *short_uid_len) { if (node == NULL || short_uid == NULL || short_uid_len == NULL) return -EBADMSG; if (kmip_node_get_tag(node) != KMIP_TAG_SHORT_UNIQUE_IDENTIFIER) return -EBADMSG; *short_uid = kmip_node_get_byte_string(node, short_uid_len); return 0; } /** * Constructs a Application Specific Information attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Application Specific Info. Yes Structure v1.0 * Application Namespace Yes Text String v1.0 * Application Data Yes/No Text String v1.0 * * @param name_space the application namespace * @param data the application data * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_application_specific_information( const char *name_space, const char *data) { struct kmip_node *ret = NULL, *ns, *d = NULL; if (name_space == NULL) return NULL; ns = kmip_node_new_text_string(KMIP_TAG_APPLICATION_NAMESPACE, NULL, name_space); if (ns == NULL) goto out; if (data != NULL) { d = kmip_node_new_text_string(KMIP_TAG_APPLICATION_DATA, NULL, data); if (d == NULL) goto out; } ret = kmip_node_new_structure_va(KMIP_TAG_APPLICATION_DATA, NULL, 2, ns, d); out: kmip_node_free(ns); kmip_node_free(d); return ret; } /** * Gets the information from a Application Specific Information attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Application Specific Info. Yes Structure v1.0 * Application Namespace Yes Text String v1.0 * Application Data Yes/No Text String v1.0 * * @param node the KMIP node * @param name_space the application namespace * @param data the application data (can be NULL) * * @returns 0 on success, or a negative errno in case of an error * The reference count of the returned nodes is increased. The caller must * free the node via kmip_node_free() when no longer needed. */ int kmip_get_application_specific_information(const struct kmip_node *node, const char **name_space, const char **data) { struct kmip_node *n; if (node == NULL || name_space == NULL) return -EINVAL; if (kmip_node_get_tag(node) != KMIP_TAG_APPLICATION_DATA) return -EBADMSG; n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_APPLICATION_NAMESPACE, 0); if (n == NULL) return -EBADMSG; *name_space = kmip_node_get_text_string(n); kmip_node_free(n); if (data != NULL) { n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_APPLICATION_DATA, 0); if (n == NULL) return -EBADMSG; *data = kmip_node_get_text_string(n); kmip_node_free(n); } return 0; } /** * Constructs a Key Value Location attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Key Value Location Yes Structure v1.2 * Key Value Location Value Yes Text String v1.2 * Key Value Location Type Yes Enumeration v1.2 * * @param value the value of the key value location * @param type the type of the key value location * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_key_value_location(const char *value, enum kmip_key_value_location_type type) { struct kmip_node *name = NULL, *val, *typ; if (value == NULL) return NULL; val = kmip_node_new_text_string(KMIP_TAG_KEY_VALUE_LOCATION_VALUE, NULL, value); typ = kmip_node_new_enumeration(KMIP_TAG_KEY_VALUE_LOCATION_TYPE, NULL, type); if (val == NULL || typ == NULL) goto out; name = kmip_node_new_structure_va(KMIP_TAG_KEY_VALUE_LOCATION, NULL, 2, val, typ); out: kmip_node_free(val); kmip_node_free(typ); return name; } /** * Gets the information from a Key Value Location attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Key Value Location Yes Structure v1.2 * Key Value Location Value Yes Text String v1.2 * Key Value Location Type Yes Enumeration v1.2 * * @param node the KMIP node * @param value the value of the key value location * @param type the type of the key value location * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_key_value_location(const struct kmip_node *node, const char **value, enum kmip_key_value_location_type *type) { struct kmip_node *val, *typ; int rc = 0; if (node == NULL) return -EINVAL; if (kmip_node_get_tag(node) != KMIP_TAG_KEY_VALUE_LOCATION) return -EBADMSG; val = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_KEY_VALUE_LOCATION_VALUE, 0); typ = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_KEY_VALUE_LOCATION_TYPE, 0); if (val == NULL || typ == NULL) { rc = -EBADMSG; goto out; } if (value != NULL) *value = kmip_node_get_text_string(val); if (type != NULL) *type = kmip_node_get_enumeration(typ); out: kmip_node_free(val); kmip_node_free(typ); return rc; } /** * Constructs a Digest attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Digest Yes Structure v1.0 * Hashing Algorithm Yes Enumeration v1.0 * Digest Value Yes Byte String v1.0 * * @param hash_algo the hashing algorithm * @param digest the digest value * @param digest_len the digest length * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_digest(enum kmip_hashing_algo hash_algo, const unsigned char *digest, uint32_t digest_len) { struct kmip_node *ret = NULL, *algo, *val; if (digest == NULL || digest_len == 0) return NULL; algo = kmip_node_new_enumeration(KMIP_TAG_HASHING_ALGORITHM, NULL, hash_algo); val = kmip_node_new_byte_string(KMIP_TAG_DIGEST_VALUE, NULL, digest, digest_len); if (algo == NULL || val == NULL) goto out; ret = kmip_node_new_structure_va(KMIP_TAG_DIGEST, NULL, 2, algo, val); out: kmip_node_free(algo); kmip_node_free(val); return ret; } /** * Gets the information from a Digest attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Digest Yes Structure v1.0 * Hashing Algorithm Yes Enumeration v1.0 * Digest Value Yes Byte String v1.0 * * @param node the KMIP node * @param hash_algo the hashing algorithm (can be NULL) * @param digest the digest value (can be NULL) * @param digest_len the digest length (can be NULL) * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_digest(const struct kmip_node *node, enum kmip_hashing_algo *hash_algo, const unsigned char **digest, uint32_t *digest_len) { struct kmip_node *algo, *val; int rc = 0; if (node == NULL) return -EINVAL; if (kmip_node_get_tag(node) != KMIP_TAG_DIGEST) return -EBADMSG; algo = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_HASHING_ALGORITHM, 0); val = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_DIGEST_VALUE, 0); if (algo == NULL || val == NULL) { rc = -EBADMSG; goto out; } if (hash_algo != NULL) *hash_algo = kmip_node_get_enumeration(algo); if (digest != NULL) *digest = kmip_node_get_byte_string(val, digest_len); out: kmip_node_free(algo); kmip_node_free(val); return rc; } /** * Constructs a Sensitive attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Sensitive Yes Boolean v1.4 * * @param sensitive the sensitive value * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_sensitive(bool sensitive) { return kmip_node_new_boolean(KMIP_TAG_SENSITIVE, NULL, sensitive); } /** * Gets the information from a Sensitive attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Sensitive Yes Boolean v1.4 * * @param node the KMIP node * @param sensitive the sensitive value * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_sensitive(const struct kmip_node *node, bool *sensitive) { if (node == NULL || sensitive == NULL) return -EBADMSG; if (kmip_node_get_tag(node) != KMIP_TAG_SENSITIVE) return -EBADMSG; *sensitive = kmip_node_get_boolean(node); return 0; } /** * Constructs a Always Sensitive attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Always Sensitive Yes Boolean v1.4 * * @param sensitive the sensitive value * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_always_sensitive(bool sensitive) { return kmip_node_new_boolean(KMIP_TAG_ALWAYS_SENSITIVE, NULL, sensitive); } /** * Gets the information from a Always Sensitive attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Always Sensitive Yes Boolean v1.4 * * @param node the KMIP node * @param sensitive the sensitive value * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_always_sensitive(const struct kmip_node *node, bool *sensitive) { if (node == NULL || sensitive == NULL) return -EBADMSG; if (kmip_node_get_tag(node) != KMIP_TAG_ALWAYS_SENSITIVE) return -EBADMSG; *sensitive = kmip_node_get_boolean(node); return 0; } /** * Constructs a Extractable attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Extractable Yes Boolean v1.4 * * @param extractable the extractable value * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_extractable(bool extractable) { return kmip_node_new_boolean(KMIP_TAG_EXTRACTABLE, NULL, extractable); } /** * Gets the information from a Extractable attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Extractable Yes Boolean v1.4 * * @param node the KMIP node * @param extractable the extractable value * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_extractable(const struct kmip_node *node, bool *extractable) { if (node == NULL || extractable == NULL) return -EBADMSG; if (kmip_node_get_tag(node) != KMIP_TAG_EXTRACTABLE) return -EBADMSG; *extractable = kmip_node_get_boolean(node); return 0; } /** * Constructs a Never Extractable attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Never Extractable Yes Boolean v1.4 * * @param extractable the extractable value * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_never_extractable(bool extractable) { return kmip_node_new_boolean(KMIP_TAG_NEVER_EXTRACTABLE, NULL, extractable); } /** * Gets the information from a Never Extractable attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Never Extractable Yes Boolean v1.4 * * @param node the KMIP node * @param extractable the extractable value * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_never_extractable(const struct kmip_node *node, bool *extractable) { if (node == NULL || extractable == NULL) return -EBADMSG; if (kmip_node_get_tag(node) != KMIP_TAG_NEVER_EXTRACTABLE) return -EBADMSG; *extractable = kmip_node_get_boolean(node); return 0; } /** * Constructs a Link attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Link Yes Structure v1.0 * Link Type Yes Enumeration v1.0 * Linked Object Identifier Yes Text String v1.0 * Enumeration v2.0 * Integer v2.0 * * @param type the link type * @param obj_id the linked object identifier * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_link(enum kmip_link_type type, struct kmip_node *obj_id) { struct kmip_node *ret = NULL, *typ; if (obj_id == NULL) return NULL; typ = kmip_node_new_enumeration(KMIP_TAG_LINK_TYPE, NULL, type); if (typ == NULL) return NULL; ret = kmip_node_new_structure_va(KMIP_TAG_LINK, NULL, 2, typ, obj_id); kmip_node_free(typ); return ret; } /** * Gets the information from a Link attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Link Yes Structure v1.0 * Link Type Yes Enumeration v1.0 * Linked Object Identifier Yes Text String v1.0 * Enumeration v2.0 * Integer v2.0 * * @param node the KMIP node * @param type the link type * @param obj_id the linked object identifier * * @returns 0 on success, or a negative errno in case of an error * The reference count of the returned nodes is increased. The caller must * free the node via kmip_node_free() when no longer needed. */ int kmip_get_link(const struct kmip_node *node, enum kmip_link_type *type, struct kmip_node **obj_id) { struct kmip_node *n; if (type == NULL || obj_id == NULL) return -EINVAL; if (kmip_node_get_tag(node) != KMIP_TAG_LINK) return -EBADMSG; n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_LINK_TYPE, 0); if (n == NULL) return -EBADMSG; *type = kmip_node_get_enumeration(n); kmip_node_free(n); *obj_id = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_LINKED_OBJECT_IDENTIFIER, 0); if (*obj_id == NULL) return -EBADMSG; return 0; } /** * Constructs a Linked Object Identifier attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Linked Object Identifier Yes Text String v1.0 * Enumeration v2.0 * Integer v2.0 * * @param text_id the linked identifier as text string (or NULL) * @param enum_id the linked identifier as enumeration (or 0) * @param int_id the linked identifier as integer * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_linked_object_identifier(const char *text_id, enum kmip_unique_identifier enum_id, int32_t int_id) { if (text_id != NULL && enum_id != 0) return NULL; if (text_id != NULL) return kmip_node_new_text_string( KMIP_TAG_LINKED_OBJECT_IDENTIFIER, NULL, text_id); if (enum_id != 0) return kmip_node_new_enumeration( KMIP_TAG_LINKED_OBJECT_IDENTIFIER, NULL, enum_id); return kmip_node_new_integer(KMIP_TAG_LINKED_OBJECT_IDENTIFIER, NULL, int_id); } /** * Gets the information from a Linked Object Identifier attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Linked Object Identifier Yes Text String v1.0 * Enumeration v2.0 * Integer v2.0 * * @param node the KMIP node * @param text_id the linked identifier as text string (can be NULL) * @param enum_id the linked identifier as enumeration (can be NULL) * @param int_id the linked identifier as integer (can be NULL) * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_linked_object_identifier(const struct kmip_node *node, const char **text_id, enum kmip_unique_identifier *enum_id, int32_t *int_id) { if (node == NULL) return -EBADMSG; if (kmip_node_get_tag(node) != KMIP_TAG_LINKED_OBJECT_IDENTIFIER) return -EBADMSG; if (text_id != NULL) { if (kmip_node_get_type(node) == KMIP_TYPE_TEXT_STRING) *text_id = kmip_node_get_text_string(node); else *text_id = NULL; } if (enum_id != NULL) { if (kmip_node_get_type(node) == KMIP_TYPE_ENUMERATION) *enum_id = kmip_node_get_enumeration(node); else *enum_id = 0; } if (int_id != NULL) { if (kmip_node_get_type(node) == KMIP_TYPE_INTEGER) *int_id = kmip_node_get_integer(node); else *int_id = 0; } return 0; } /** * Constructs a Operation Policy Name attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Operation Policy Name Yes Text String v1.x only * * @param policy the policy name * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_operation_policy_name(const char *policy) { return kmip_node_new_text_string(KMIP_TAG_OPERATION_POLICY_NAME, NULL, policy); } /** * Gets the information from a Operation Policy Name attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Operation Policy Name Yes Text String v1.x only * * @param node the KMIP node * @param policy the policy name * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_operation_policy_name(const struct kmip_node *node, const char **policy) { if (node == NULL || policy == NULL) return -EBADMSG; if (kmip_node_get_tag(node) != KMIP_TAG_OPERATION_POLICY_NAME) return -EBADMSG; *policy = kmip_node_get_text_string(node); return 0; } /** * Constructs a Lease Time attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Lease Time Yes Interval v1.0 * * @param lease_time the lease time * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_lease_time(uint32_t lease_time) { return kmip_node_new_interval(KMIP_TAG_LEASE_TIME, NULL, lease_time); } /** * Gets the information from a Lease Time attribute node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Lease Time Yes Interval v1.0 * * @param node the KMIP node * @param lease_time the lease time * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_lease_time(const struct kmip_node *node, uint32_t *lease_time) { if (node == NULL || lease_time == NULL) return -EBADMSG; if (kmip_node_get_tag(node) != KMIP_TAG_LEASE_TIME) return -EBADMSG; *lease_time = kmip_node_get_interval(node); return 0; } opencryptoki-opencryptoki-451d99c/usr/sbin/p11kmip/kmipclient/https.c000066400000000000000000000560661520105705100260340ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021-2024 * * 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 #ifdef HAVE_LIBCURL #include #include #include #include "kmip.h" #include "utils.h" #ifdef UNUSED #elif defined(__GNUC__) # define UNUSED(x) UNUSED_ ## x __attribute__((unused)) #else # define UNUSED(x) x #endif #define HTTP_HDR_CONTENT_TYPE "Content-Type:" #define CURL_ERROR_CHECK(rc, text, debug, label) \ do { \ if ((rc) != CURLE_OK) { \ kmip_debug((debug), "%s: %s", (text), \ curl_easy_strerror((rc))); \ goto label; \ } \ } while (0) struct curl_sslctx_cb_data { const struct kmip_connection *conn; bool debug; }; struct curl_write_cb_data { const struct kmip_connection *conn; bool error; bool debug; union { #ifdef HAVE_LIBJSONC struct { json_tokener *tok; json_object *resp_obj; } json; #endif #ifdef HAVE_LIBXML2 struct { xmlParserCtxtPtr ctx; } xml; #endif struct { BIO *resp_mem_bio; } ttlv; } u; }; #ifdef HAVE_LIBJSONC #define json u.json #endif #ifdef HAVE_LIBXML2 #define xml u.xml #endif #define ttlv u.ttlv struct curl_header_cb_data { const struct kmip_connection *conn; bool error; bool debug; }; /** * Initializes a new HTTPS connection to a KMIP server. * * @param connn The KMIP connection * @param debug if true, debug messages are printed * * @returns 0 in case of success, or a negative errno value */ int kmip_connection_https_init(struct kmip_connection *conn, bool debug) { const char *content_type, *accept, *server, *tok; const struct curl_tlssessioninfo *info = NULL; bool port_found = false; struct stat sb; int rc; if (conn == NULL) return -EINVAL; if (strncmp(conn->config.server, "https://", 8) != 0) { kmip_debug(debug, "Server must start with 'https://'"); return -EINVAL; } /* Find port (if any) and beginning of uri */ server = conn->config.server + 8; if (*server == '[') { /* IPv6 address enclosed in square brackets */ tok = strchr(server, ']'); if (tok == NULL) { kmip_debug(debug, "malformed IPv6 address"); return -EINVAL; } tok++; port_found = (*tok == ':'); } else { /* hostname or IPv4 address */ tok = strchr(server, ':'); port_found = (tok != NULL); } conn->https.curl = curl_easy_init(); if (conn->https.curl == NULL) { kmip_debug(debug, "curl_easy_init failed"); return -EIO; } /* * The CURLOPT_SSL_CTX_FUNCTION callback only works with the OpenSSL * curl backend. Check that OpenSSL is the current curl backend. */ rc = curl_easy_getinfo(conn->https.curl, CURLINFO_TLS_SSL_PTR, &info); CURL_ERROR_CHECK(rc, "curl_easy_getinfo CURLINFO_TLS_SSL_PTR", debug, out); if (info->backend != CURLSSLBACKEND_OPENSSL) { kmip_debug(debug, "libcurl is not using the OpenSSL backend"); rc = -EIO; goto out; } rc = curl_easy_setopt(conn->https.curl, CURLOPT_VERBOSE, debug ? 1 : 0); CURL_ERROR_CHECK(rc, "curl_easy_setopt CURLOPT_VERBOSE", debug, out); rc = curl_easy_setopt(conn->https.curl, CURLOPT_URL, conn->config.server); CURL_ERROR_CHECK(rc, "curl_easy_setopt CURLOPT_URL", debug, out); if (!port_found) { rc = curl_easy_setopt(conn->https.curl, CURLOPT_PORT, KMIP_DEFAULT_HTTPS_PORT_NUM); CURL_ERROR_CHECK(rc, "curl_easy_setopt CURLOPT_URL", debug, out); } rc = curl_easy_setopt(conn->https.curl, CURLOPT_SSL_VERIFYPEER, conn->config.tls_verify_peer ? 1L : 0L); CURL_ERROR_CHECK(rc, "curl_easy_setopt CURLOPT_SSL_VERIFYPEER", debug, out); rc = curl_easy_setopt(conn->https.curl, CURLOPT_SSL_VERIFYHOST, conn->config.tls_verify_host ? 2L : 0L); CURL_ERROR_CHECK(rc, "curl_easy_setopt CURLOPT_SSL_VERIFYHOST", debug, out); if (conn->config.tls_ca != NULL) { if (stat(conn->config.tls_ca, &sb) != 0) { rc = -errno; kmip_debug(debug, "stat failed on '%s': %s", conn->config.tls_ca, strerror(-rc)); goto out; } if (S_ISDIR(sb.st_mode)) { rc = curl_easy_setopt(conn->https.curl, CURLOPT_CAPATH, conn->config.tls_ca); CURL_ERROR_CHECK(rc, "curl_easy_setopt CURLOPT_CAPATH", debug, out); } else { rc = curl_easy_setopt(conn->https.curl, CURLOPT_CAINFO, conn->config.tls_ca); CURL_ERROR_CHECK(rc, "curl_easy_setopt CURLOPT_CAINFO", debug, out); } } if (conn->config.tls_issuer_cert != NULL) { rc = curl_easy_setopt(conn->https.curl, CURLOPT_ISSUERCERT, conn->config.tls_issuer_cert); CURL_ERROR_CHECK(rc, "curl_easy_setopt CURLOPT_ISSUERCERT", debug, out); } if (conn->config.tls_pinned_pubkey != NULL) { rc = curl_easy_setopt(conn->https.curl, CURLOPT_PINNEDPUBLICKEY, conn->config.tls_pinned_pubkey); CURL_ERROR_CHECK(rc, "curl_easy_setopt CURLOPT_PINNEDPUBLICKEY", debug, out); } rc = curl_easy_setopt(conn->https.curl, CURLOPT_FOLLOWLOCATION, 0L); CURL_ERROR_CHECK(rc, "curl_easy_setopt CURLOPT_FOLLOWLOCATION", debug, out); if (conn->config.tls_cipher_list != NULL) { rc = curl_easy_setopt(conn->https.curl, CURLOPT_SSL_CIPHER_LIST, conn->config.tls_cipher_list); CURL_ERROR_CHECK(rc, "curl_easy_setopt CURLOPT_SSL_CIPHER_LIST", debug, out); } if (conn->config.tls13_cipher_list != NULL) { rc = curl_easy_setopt(conn->https.curl, CURLOPT_TLS13_CIPHERS, conn->config.tls13_cipher_list); CURL_ERROR_CHECK(rc, "curl_easy_setopt CURLOPT_TLS13_CIPHERS", debug, out); } switch (conn->config.encoding) { case KMIP_ENCODING_TTLV: content_type = "Content-Type: application/octet-stream"; accept = "Accept: application/octet-stream"; break; #ifdef HAVE_LIBJSONC case KMIP_ENCODING_JSON: content_type = "Content-Type: application/json;charset=UTF-8"; accept = "Accept: application/json"; break; #endif #ifdef HAVE_LIBXML2 case KMIP_ENCODING_XML: content_type = "Content-Type: text/xml;charset=UTF-8"; accept = "Accept: text/xml"; break; #endif default: kmip_debug(debug, "invalid encoding: %d", conn->config.encoding); rc = -EINVAL; goto out; } conn->https.headers = curl_slist_append(conn->https.headers, content_type); if (conn->https.headers == NULL) { kmip_debug(debug, "curl_slist_append failed"); rc = -ENOMEM; goto out; } conn->https.headers = curl_slist_append(conn->https.headers, accept); if (conn->https.headers == NULL) { kmip_debug(debug, "curl_slist_append failed"); rc = -ENOMEM; goto out; } conn->https.headers = curl_slist_append(conn->https.headers, "Accept-Charset: UTF-8"); if (conn->https.headers == NULL) { kmip_debug(debug, "curl_slist_append failed"); rc = -ENOMEM; goto out; } /* Disable "Expect: 100-continue" */ conn->https.headers = curl_slist_append(conn->https.headers, "Expect:"); if (conn->https.headers == NULL) { kmip_debug(debug, "curl_slist_append failed"); rc = -ENOMEM; goto out; } /* As per KMIP HTTPS profile: Cache-Control: no-cache */ conn->https.headers = curl_slist_append(conn->https.headers, "Cache-Control: no-cache"); if (conn->https.headers == NULL) { kmip_debug(debug, "curl_slist_append failed"); rc = -ENOMEM; goto out; } rc = curl_easy_setopt(conn->https.curl, CURLOPT_HTTPHEADER, conn->https.headers); CURL_ERROR_CHECK(rc, "curl_easy_setopt CURLOPT_HTTPHEADER", debug, out); rc = 0; out: if (rc != 0) kmip_connection_https_term(conn); return rc; } /** * This callback called before the SSL handshake is performed. * It sets the client certificate and private key into the context. * It also adds a pinned server certificate to the SSL certificate store, so * that it is treated as trusted, although it might be self-signed. */ static CURLcode mkip_connection_https_sslctx_cb(CURL *UNUSED(curl), void *sslctx, void *parm) { struct curl_sslctx_cb_data *sslctx_cb = parm; SSL_CTX *ssl_ctx = (SSL_CTX *)sslctx; const struct kmip_connection *conn; X509_STORE *store; X509 *cert = NULL; FILE *fp; int rc; if (ssl_ctx == NULL || sslctx_cb == NULL || sslctx_cb->conn == NULL) return CURLE_ABORTED_BY_CALLBACK; conn = sslctx_cb->conn; if (SSL_CTX_use_certificate_file(sslctx, conn->config.tls_client_cert, SSL_FILETYPE_PEM) != 1) { kmip_debug(sslctx_cb->debug, "Failed to load the client " "certificate '%s'", conn->config.tls_client_cert); if (sslctx_cb->debug) ERR_print_errors_fp(stderr); return CURLE_ABORTED_BY_CALLBACK; } if (SSL_CTX_use_PrivateKey(ssl_ctx, conn->config.tls_client_key) != 1) { kmip_debug(sslctx_cb->debug, "Failed to set the client key"); if (sslctx_cb->debug) ERR_print_errors_fp(stderr); return CURLE_ABORTED_BY_CALLBACK; } if (conn->config.tls_server_cert == NULL) return CURLE_OK; store = SSL_CTX_get_cert_store(ssl_ctx); if (store == NULL) { kmip_debug(sslctx_cb->debug, "Failed to get SSL Store"); if (sslctx_cb->debug) ERR_print_errors_fp(stderr); return CURLE_ABORTED_BY_CALLBACK; } fp = fopen(conn->config.tls_server_cert, "r"); if (fp == NULL) { rc = -errno; kmip_debug(sslctx_cb->debug, "Failed to read server cert '%s': %s", conn->config.tls_server_cert, strerror(-rc)); return CURLE_ABORTED_BY_CALLBACK; } cert = PEM_read_X509(fp, NULL, NULL, NULL); fclose(fp); if (cert == NULL) { kmip_debug(sslctx_cb->debug, "Failed to read the server " "certificate from file '%s'", conn->config.tls_server_cert); if (sslctx_cb->debug) ERR_print_errors_fp(stderr); return CURLE_ABORTED_BY_CALLBACK; } if (sslctx_cb->debug) { kmip_debug(sslctx_cb->debug, "Pinned server certificate:"); X509_print_ex_fp(stderr, cert, XN_FLAG_COMPAT, X509_FLAG_COMPAT); } rc = X509_STORE_add_cert(store, cert); if (rc != 1) { kmip_debug(sslctx_cb->debug, "Failed to add server " "certificate to SSL Store"); if (sslctx_cb->debug) ERR_print_errors_fp(stderr); X509_free(cert); return CURLE_ABORTED_BY_CALLBACK; } X509_free(cert); return CURLE_OK; } /** * Callback called during curl_easy_perform() to handle received headers. * Check for the expected response content type. */ static size_t mkip_connection_https_header_cb(void *contents, size_t size, size_t nmemb, void *userp) { struct curl_header_cb_data *cb = (struct curl_header_cb_data *)userp; size_t num = size * nmemb; const char *content_type; char *hdr = contents; size_t ofs; char *val; if (num < strlen(HTTP_HDR_CONTENT_TYPE)) goto out; if (strncasecmp(hdr, HTTP_HDR_CONTENT_TYPE, strlen(HTTP_HDR_CONTENT_TYPE)) != 0) goto out; ofs = strlen(HTTP_HDR_CONTENT_TYPE); val = hdr + ofs; while (*val == ' ' && ofs < num) { ofs++; val++; } if (ofs >= num) goto out; switch (cb->conn->config.encoding) { case KMIP_ENCODING_TTLV: content_type = "application/octet-stream"; break; #ifdef HAVE_LIBJSONC case KMIP_ENCODING_JSON: content_type = "application/json"; break; #endif #ifdef HAVE_LIBXML2 case KMIP_ENCODING_XML: content_type = "text/xml"; break; #endif default: return 0; } if (num - ofs >= strlen(content_type) && strncasecmp(val, content_type, strlen(content_type)) == 0) goto out; cb->error = true; kmip_debug(cb->debug, "Unexpected response Content-Type: %.*s", (int)(num - ofs), val); return 0; out: return num; } /** * Callback called during curl_easy_perform() to handle received data. * Parse the (potentially partial) KMIP data. */ static size_t mkip_connection_https_write_cb(void *contents, size_t size, size_t nmemb, void *userp) { struct curl_write_cb_data *cb = (struct curl_write_cb_data *)userp; #ifdef HAVE_LIBJSONC enum json_tokener_error jerr; #endif size_t num = size * nmemb; #ifdef HAVE_LIBXML2 int rc; #endif switch (cb->conn->config.encoding) { case KMIP_ENCODING_TTLV: kmip_debug(cb->debug, "Response Data (TTLV): %lu bytes", num); if (cb->debug) kmip_print_dump(__func__, (unsigned char *)contents, num, 2); if (BIO_write(cb->ttlv.resp_mem_bio, contents, num) != (int)num) { cb->error = true; kmip_debug(cb->debug, "BIO_write failed"); return 0; } break; #ifdef HAVE_LIBJSONC case KMIP_ENCODING_JSON: kmip_debug(cb->debug, "Response Data (JSON):"); kmip_debug(cb->debug, " ->%*s<-", (int)num, (char *)contents); if (cb->json.resp_obj != NULL) { kmip_debug(cb->debug, "JSON data already complete, but " "additional data received"); cb->error = true; return 0; } cb->json.resp_obj = json_tokener_parse_ex(cb->json.tok, (const char *)contents, num); if (cb->json.resp_obj == NULL) { jerr = json_tokener_get_error(cb->json.tok); if (jerr == json_tokener_continue) goto out; cb->error = true; kmip_debug(cb->debug, "json_tokener_parse_ex failed: %s", json_tokener_error_desc(jerr)); return 0; } break; #endif #ifdef HAVE_LIBXML2 case KMIP_ENCODING_XML: kmip_debug(cb->debug, "Response Data (XML):"); kmip_debug(cb->debug, " ->%*s<-", (int)num, (char *)contents); rc = xmlParseChunk(cb->xml.ctx, (const char *)contents, num, 0); if (rc != XML_ERR_OK) { cb->error = true; kmip_debug(cb->debug, "xmlParseChunk failed: %d", rc); return 0; } break; #endif } #ifdef HAVE_LIBJSONC out: #endif return num; } /** * Perform a request over the KMIP connection * * @param conn the KMIP connection * @param request the request to send * @param response On return: the received response. Must be freed by * the caller. * * @param debug if true, debug messages are printed * * @returns 0 in case of success, or a negative errno value */ int kmip_connection_https_perform(struct kmip_connection *conn, struct kmip_node *request, struct kmip_node **response, bool debug) { struct curl_sslctx_cb_data sslctx_cb = { 0 }; struct curl_header_cb_data header_cb = { 0 }; struct curl_write_cb_data write_cb = { 0 }; char error_str[CURL_ERROR_SIZE] = { 0 }; #ifdef HAVE_LIBJSONC json_object *req_json_obj = NULL; #endif #ifdef HAVE_LIBXML2 xmlNode *req_xml_obj = NULL; xmlDoc *req_xml_doc = NULL; #endif BIO *req_mem_bio = NULL; char *req_buff = NULL; int req_buff_size = 0; long status_code; size_t size; int rc; if (conn == NULL || request == NULL || response == NULL) return -EINVAL; *response = NULL; rc = curl_easy_setopt(conn->https.curl, CURLOPT_ERRORBUFFER, error_str); CURL_ERROR_CHECK(rc, "curl_easy_setopt CURLOPT_ERRORBUFFER", debug, out); /* Setup SSL Context callback */ sslctx_cb.conn = conn; sslctx_cb.debug = debug; rc = curl_easy_setopt(conn->https.curl, CURLOPT_SSL_CTX_FUNCTION, mkip_connection_https_sslctx_cb); CURL_ERROR_CHECK(rc, "curl_easy_setopt " "CURLOPT_SSL_CTX_FUNCTION", debug, out); rc = curl_easy_setopt(conn->https.curl, CURLOPT_SSL_CTX_DATA, &sslctx_cb); CURL_ERROR_CHECK(rc, "curl_easy_setopt CURLOPT_SSL_CTX_DATA", debug, out); /* Setup write callback to handle received data */ write_cb.conn = conn; write_cb.debug = debug; switch (conn->config.encoding) { case KMIP_ENCODING_TTLV: write_cb.ttlv.resp_mem_bio = BIO_new(BIO_s_mem()); if (write_cb.ttlv.resp_mem_bio == NULL) { kmip_debug(debug, "BIO_new failed"); rc = -ENOMEM; goto out; } break; #ifdef HAVE_LIBJSONC case KMIP_ENCODING_JSON: write_cb.json.tok = json_tokener_new(); if (write_cb.json.tok == NULL) { kmip_debug(debug, "json_tokener_new failed"); rc = -EIO; goto out; } break; #endif #ifdef HAVE_LIBXML2 case KMIP_ENCODING_XML: write_cb.xml.ctx = xmlCreatePushParserCtxt(NULL, NULL, NULL, 0, NULL); if (write_cb.xml.ctx == NULL) { kmip_debug(debug, "xmlCreatePushParserCtxt failed"); rc = -EIO; goto out; } break; #endif } rc = curl_easy_setopt(conn->https.curl, CURLOPT_WRITEFUNCTION, mkip_connection_https_write_cb); CURL_ERROR_CHECK(rc, "curl_easy_setopt CURLOPT_WRITEFUNCTION", debug, out); rc = curl_easy_setopt(conn->https.curl, CURLOPT_WRITEDATA, (void *)&write_cb); CURL_ERROR_CHECK(rc, "curl_easy_setopt CURLOPT_WRITEDATA", debug, out); /* Setup header callback to check content type */ header_cb.conn = conn; header_cb.debug = debug; rc = curl_easy_setopt(conn->https.curl, CURLOPT_HEADERFUNCTION, mkip_connection_https_header_cb); CURL_ERROR_CHECK(rc, "curl_easy_setopt CURLOPT_HEADERFUNCTION", debug, out); rc = curl_easy_setopt(conn->https.curl, CURLOPT_HEADERDATA, (void *)&header_cb); CURL_ERROR_CHECK(rc, "curl_easy_setopt CURLOPT_HEADERDATA", debug, out); /* Setup POST request and post data */ rc = curl_easy_setopt(conn->https.curl, CURLOPT_CUSTOMREQUEST, "POST"); CURL_ERROR_CHECK(rc, "curl_easy_setopt CURLOPT_CUSTOMREQUEST", debug, out); rc = curl_easy_setopt(conn->https.curl, CURLOPT_POST, 1L); CURL_ERROR_CHECK(rc, "curl_easy_setopt CURLOPT_POST", debug, out); switch (conn->config.encoding) { case KMIP_ENCODING_TTLV: req_mem_bio = BIO_new(BIO_s_mem()); if (req_mem_bio == NULL) { kmip_debug(debug, "BIO_new failed"); rc = -ENOMEM; goto out; } rc = kmip_encode_ttlv(request, req_mem_bio, &size, debug); if (rc != 0) { kmip_debug(debug, "kmip_encode_ttlv failed"); goto out; } req_buff_size = BIO_get_mem_data(req_mem_bio, &req_buff); kmip_debug(debug, "Request Data (TTLV): %d bytes", req_buff_size); if (debug) kmip_print_dump(__func__, (unsigned char *)req_buff, req_buff_size, 2); break; #ifdef HAVE_LIBJSONC case KMIP_ENCODING_JSON: rc = kmip_encode_json(request, &req_json_obj, debug); if (rc != 0) { kmip_debug(debug, "kmip_encode_json failed"); goto out; } /* * The memory returned by json_object_to_json_string_ext * is freed when the JSON object is freed. */ req_buff = (char *)json_object_to_json_string_ext(req_json_obj, JSON_C_TO_STRING_PLAIN | JSON_C_TO_STRING_NOSLASHESCAPE); if (req_buff == NULL) { kmip_debug(debug, "json_object_to_json_string_ext failed"); rc = -EIO; goto out; } req_buff_size = strlen(req_buff); kmip_debug(debug, "Request Data (JSON):"); kmip_debug(debug, " ->%*s<-", req_buff_size, req_buff); break; #endif #ifdef HAVE_LIBXML2 case KMIP_ENCODING_XML: req_xml_doc = xmlNewDoc((xmlChar *)"1.0"); if (req_xml_doc == NULL) { kmip_debug(debug, "xmlNewDoc failed"); rc = -EIO; goto out; } rc = kmip_encode_xml(request, &req_xml_obj, debug); if (rc != 0) { kmip_debug(debug, "kmip_encode_xml failed"); goto out; } xmlDocSetRootElement(req_xml_doc, req_xml_obj); req_xml_obj = NULL; xmlDocDumpFormatMemoryEnc(req_xml_doc, (xmlChar **)&req_buff, &req_buff_size, "UTF-8", 0); if (req_buff == NULL || req_buff_size == 0) { kmip_debug(debug, "xmlDocDumpFormatMemoryEnc failed"); rc = -EIO; goto out; } kmip_debug(debug, "Request Data (XML):"); kmip_debug(debug, " ->%*s<-", req_buff_size, req_buff); break; #endif } rc = curl_easy_setopt(conn->https.curl, CURLOPT_POSTFIELDSIZE, req_buff_size); CURL_ERROR_CHECK(rc, "curl_easy_setopt CURLOPT_POSTFIELDSIZE", debug, out); rc = curl_easy_setopt(conn->https.curl, CURLOPT_POSTFIELDS, req_buff); CURL_ERROR_CHECK(rc, "curl_easy_setopt CURLOPT_POSTFIELDS", debug, out); /* Perform the request */ rc = curl_easy_perform(conn->https.curl); if (rc != CURLE_OK) { kmip_debug(debug, "curl_easy_perform for '%s' failed: %s", conn->config.server, curl_easy_strerror(rc)); kmip_debug(debug, "Error: %s", error_str); if (header_cb.error) { kmip_debug(debug, "Unexpected Content-Type"); rc = -EBADMSG; } if (write_cb.error) { kmip_debug(debug, "JSON/XML parsing failed"); rc = -EBADMSG; } rc = -EIO; goto out; } /* Check response */ rc = curl_easy_getinfo(conn->https.curl, CURLINFO_RESPONSE_CODE, &status_code); CURL_ERROR_CHECK(rc, "curl_easy_getinfo CURLINFO_RESPONSE_CODE", debug, out); kmip_debug(debug, "HTTP status code: %d", status_code); if (status_code != 200) { rc = -EBADMSG; goto out; } /* Process received data */ switch (conn->config.encoding) { case KMIP_ENCODING_TTLV: rc = kmip_decode_ttlv(write_cb.ttlv.resp_mem_bio, NULL, response, debug); if (rc != 0) { kmip_debug(debug, "kmip_decode_ttlv failed"); goto out; } break; #ifdef HAVE_LIBJSONC case KMIP_ENCODING_JSON: if (write_cb.json.resp_obj == NULL) { kmip_debug(debug, "JSON content not wellformed"); rc = -EBADMSG; goto out; } rc = kmip_decode_json(write_cb.json.resp_obj, NULL, response, debug); if (rc != 0) { kmip_debug(debug, "kmip_decode_json failed"); goto out; } break; #endif #ifdef HAVE_LIBXML2 case KMIP_ENCODING_XML: rc = xmlParseChunk(write_cb.xml.ctx, "", 0, 1); if (rc != XML_ERR_OK || !write_cb.xml.ctx->wellFormed || write_cb.xml.ctx->myDoc == NULL) { kmip_debug(debug, "XML content not wellformed"); rc = -EBADMSG; goto out; } rc = kmip_decode_xml(xmlDocGetRootElement( write_cb.xml.ctx->myDoc), NULL, response, debug); if (rc != 0) { kmip_debug(debug, "kmip_decode_xml failed"); goto out; } break; #endif } rc = 0; out: /* Cleanup */ switch (conn->config.encoding) { case KMIP_ENCODING_TTLV: if (req_mem_bio != NULL) BIO_free(req_mem_bio); if (write_cb.ttlv.resp_mem_bio != NULL) BIO_free(write_cb.ttlv.resp_mem_bio); break; #ifdef HAVE_LIBJSONC case KMIP_ENCODING_JSON: if (write_cb.json.tok != NULL) json_tokener_free(write_cb.json.tok); if (write_cb.json.resp_obj != NULL) json_object_put(write_cb.json.resp_obj); if (req_json_obj != NULL) json_object_put(req_json_obj); break; #endif #ifdef HAVE_LIBXML2 case KMIP_ENCODING_XML: if (write_cb.xml.ctx != NULL) { xmlFreeDoc(write_cb.xml.ctx->myDoc); xmlFreeParserCtxt(write_cb.xml.ctx); } if (req_xml_doc != NULL) xmlFreeDoc(req_xml_doc); if (req_xml_obj != NULL) xmlFreeNode(req_xml_obj); if (req_buff != NULL) xmlFree(req_buff); break; #endif } if (rc != 0 && *response != NULL) { kmip_node_free(*response); *response = NULL; } curl_easy_setopt(conn->https.curl, CURLOPT_SSL_CTX_FUNCTION, NULL); curl_easy_setopt(conn->https.curl, CURLOPT_SSL_CTX_DATA, NULL); curl_easy_setopt(conn->https.curl, CURLOPT_WRITEFUNCTION, NULL); curl_easy_setopt(conn->https.curl, CURLOPT_WRITEDATA, NULL); curl_easy_setopt(conn->https.curl, CURLOPT_HEADERFUNCTION, NULL); curl_easy_setopt(conn->https.curl, CURLOPT_HEADERDATA, NULL); curl_easy_setopt(conn->https.curl, CURLOPT_ERRORBUFFER, NULL); curl_easy_setopt(conn->https.curl, CURLOPT_POSTFIELDS, NULL); curl_easy_setopt(conn->https.curl, CURLOPT_POSTFIELDSIZE, -1); return rc; } /** * Terminates a HTTPS KMIP connection. * * @param conn the KMIP connection to free */ void kmip_connection_https_term(struct kmip_connection *conn) { if (conn == NULL) return; if (conn->https.curl != NULL) curl_easy_cleanup(conn->https.curl); conn->https.curl = NULL; if (conn->https.headers != NULL) curl_slist_free_all(conn->https.headers); conn->https.headers = NULL; } #endif opencryptoki-opencryptoki-451d99c/usr/sbin/p11kmip/kmipclient/json.c000066400000000000000000000373261520105705100256410ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021-2024 * * 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 #ifdef HAVE_LIBCURL #ifdef HAVE_LIBJSONC #include "kmip.h" #include "names.h" #include "utils.h" #define KMIP_JSON_TAG "tag" #define KMIP_JSON_NAME "name" #define KMIP_JSON_TYPE "type" #define KMIP_JSON_VALUE "value" /** * Decode a KMIP node from the data in a JSON object using the JSON encoding. * * @param obj the JSON object to decode * @param parent the parent node or NULL if no parent exists. * @param node On return: the decoded node. The newly allocated * node has a reference count of 1. * @param debug if true, debug messages are printed * * @returns 0 in case of success, or a negative errno value */ int kmip_decode_json(const json_object *obj, struct kmip_node *parent, struct kmip_node **node, bool debug) { json_object *tag_obj, *type_obj, *value_obj, *name_obj; enum kmip_tag tag, v1_attr_tag = 0; enum json_type value_type; struct kmip_node *n, *e; const char *str; int rc, num, i; int64_t int64; if (obj == NULL || node == NULL) return -EINVAL; if (!json_object_is_type(obj, json_type_object)) { kmip_debug(debug, "Object is not a JSON object"); return -EINVAL; } n = calloc(1, sizeof(struct kmip_node)); if (n == NULL) { kmip_debug(debug, "calloc failed"); return -ENOMEM; } n->ref_count = 1; tag_obj = json_object_object_get(obj, KMIP_JSON_TAG); if (tag_obj == NULL || !json_object_is_type(tag_obj, json_type_string)) { kmip_debug(debug, "Missing or invalid '%s' in JSON object", KMIP_JSON_TAG); rc = -EBADMSG; goto out; } str = json_object_get_string(tag_obj); n->tag = kmip_tag_by_name_or_hex(str); if (n->tag == 0) { kmip_debug(debug, "Unknown 'tag' in JSON object: '%s'", str); rc = -EBADMSG; goto out; } name_obj = json_object_object_get(obj, KMIP_JSON_NAME); if (name_obj != NULL) { if (!json_object_is_type(name_obj, json_type_string)) { kmip_debug(debug, "Invalid '%s' in JSON object", KMIP_JSON_NAME); rc = -EBADMSG; goto out; } n->name = strdup(json_object_get_string(tag_obj)); } type_obj = json_object_object_get(obj, KMIP_JSON_TYPE); if (type_obj == NULL) { n->type = KMIP_TYPE_STRUCTURE; } else { if (!json_object_is_type(type_obj, json_type_string)) { kmip_debug(debug, "Missing or invalid '%s' in JSON object", KMIP_JSON_TYPE); rc = -EBADMSG; goto out; } str = json_object_get_string(type_obj); n->type = kmip_type_by_name_or_hex(str); if (n->type == 0) { kmip_debug(debug, "Unknown 'type' in JSON object: '%s'", str); rc = -EBADMSG; goto out; } } value_obj = json_object_object_get(obj, KMIP_JSON_VALUE); if (value_obj == NULL) { kmip_debug(debug, "Missing '%s' in JSON object", KMIP_JSON_VALUE); rc = -EBADMSG; goto out; } value_type = json_object_get_type(value_obj); /* * KMIP v1.x attribute values may be Enumerations or Integer Masks. * To correctly decode them, we need to know the tag. This is contained * in a Attribute Name node, which is an element of our parent node. */ if (n->tag == KMIP_TAG_ATTRIBUTE_VALUE) v1_attr_tag = kmip_find_v1_attribute_name_tag(parent); tag = (v1_attr_tag != 0 ? v1_attr_tag : n->tag); kmip_debug(debug, "tag: 0x%x type: 0x%x value_type: %d,", n->tag, n->type, value_type); switch (n->type) { case KMIP_TYPE_STRUCTURE: switch (value_type) { case json_type_null: break; case json_type_array: num = json_object_array_length(value_obj); for (i = 0; i < num; i++) { rc = kmip_decode_json( json_object_array_get_idx(value_obj, i), n, &e, debug); if (rc != 0) { kmip_debug(debug, "Failed to parse " "array element %d", i); goto out; } rc = kmip_node_add_structure_element(n, e); kmip_node_free(e); if (rc != 0) { kmip_debug(debug, "kmip_node_structure_add_element " "failed: rc: %d", rc); goto out; } } break; default: kmip_debug(debug, "Invalid JSON type %d for node type " "0x%x", value_type, n->type); rc = -EBADMSG; goto out; } break; case KMIP_TYPE_INTEGER: case KMIP_TYPE_LONG_INTEGER: switch (value_type) { case json_type_int: case json_type_double: int64 = json_object_get_int64(value_obj); break; case json_type_string: str = json_object_get_string(value_obj); if (n->type == KMIP_TYPE_INTEGER && kmip_is_tag_mask(tag)) { rc = kmip_parse_mask(tag, str, '|', &int64); if (rc != 0) { kmip_debug(debug, "Failed to parse " "mask string '%s'", str); goto out; } } else { rc = kmip_parse_hex_int(str, &int64); if (rc != 0) { kmip_debug(debug, "Failed to parse " "hex string '%s'", str); goto out; } } break; default: kmip_debug(debug, "Invalid JSON type %d for node type " "0x%x", value_type, n->type); rc = -EBADMSG; goto out; } if (n->type == KMIP_TYPE_INTEGER) n->integer_value = int64; else n->long_value = int64; break; case KMIP_TYPE_INTERVAL: switch (value_type) { case json_type_int: case json_type_double: n->interval_value = json_object_get_int64(value_obj); break; case json_type_string: str = json_object_get_string(value_obj); rc = kmip_parse_hex_int(str, &int64); if (rc != 0) { kmip_debug(debug, "Failed to parse " "hex string '%s'", str); goto out; } n->interval_value = int64; break; default: kmip_debug(debug, "Invalid JSON type %d for node type " "0x%x", value_type, n->type); rc = -EBADMSG; goto out; } break; case KMIP_TYPE_BIG_INTEGER: switch (value_type) { case json_type_int: case json_type_double: int64 = htobe64(json_object_get_int64(value_obj)); rc = kmip_decode_bignum((const unsigned char *)&int64, sizeof(int64), &n->big_integer_value); if (rc != 0) { kmip_debug(debug, "kmip_decode_bignum failed"); goto out; } break; case json_type_string: str = json_object_get_string(value_obj); rc = kmip_parse_bignum(str, true, &n->big_integer_value); if (rc != 0) { kmip_debug(debug, "Failed to parse bignum string '%s'", str); goto out; } break; default: kmip_debug(debug, "Invalid JSON type %d for node type " "0x%x", value_type, n->type); rc = -EBADMSG; goto out; } break; case KMIP_TYPE_ENUMERATION: switch (value_type) { case json_type_int: case json_type_double: n->enumeration_value = json_object_get_int64(value_obj); break; case json_type_string: str = json_object_get_string(value_obj); rc = kmip_enum_value_by_tag_name_or_hex(tag, str, &n->enumeration_value); if (rc != 0) { kmip_debug(debug, "Failed to parse enumeration '%s'", str); goto out; } break; default: kmip_debug(debug, "Invalid JSON type %d for node type " "0x%x", value_type, n->type); rc = -EBADMSG; goto out; } break; case KMIP_TYPE_BOOLEAN: switch (value_type) { case json_type_boolean: n->boolean_value = json_object_get_boolean(value_obj); break; case json_type_string: str = json_object_get_string(value_obj); rc = kmip_parse_hex_int(str, &int64); if (rc != 0) { kmip_debug(debug, "Failed to parse hex string '%s'", str); goto out; } n->boolean_value = (int64 != 0); break; default: kmip_debug(debug, "Invalid JSON type %d for node type " "0x%x", value_type, n->type); rc = -EBADMSG; goto out; } break; case KMIP_TYPE_TEXT_STRING: switch (value_type) { case json_type_string: n->text_value = strdup( json_object_get_string(value_obj)); if (n->text_value == NULL) { rc = -ENOMEM; goto out; } n->length = strlen(n->text_value); break; default: kmip_debug(debug, "Invalid JSON type %d for node type " "0x%x", value_type, n->type); rc = -EBADMSG; goto out; } break; case KMIP_TYPE_BYTE_STRING: switch (value_type) { case json_type_string: str = json_object_get_string(value_obj); rc = kmip_parse_hex(str, false, &n->bytes_value, &n->length); if (rc != 0) { kmip_debug(debug, "Failed to parse hex string '%s'", str); goto out; } break; default: kmip_debug(debug, "Invalid JSON type %d for node type " "0x%x", value_type, n->type); rc = -EBADMSG; goto out; } break; case KMIP_TYPE_DATE_TIME: switch (value_type) { case json_type_int: case json_type_double: n->date_time_value = json_object_get_int64(value_obj); break; case json_type_string: str = json_object_get_string(value_obj); rc = kmip_parse_timestamp(str, &n->date_time_value); if (rc != 0) { kmip_debug(debug, "Failed to parse time stamp '%s'", str); goto out; } break; default: kmip_debug(debug, "Invalid JSON type %d for node type " "0x%x", value_type, n->type); rc = -EBADMSG; goto out; } break; case KMIP_TYPE_DATE_TIME_EXTENDED: switch (value_type) { case json_type_int: case json_type_double: n->date_time_ext_value = json_object_get_int64(value_obj); break; case json_type_string: str = json_object_get_string(value_obj); rc = kmip_parse_hex_int(str, &int64); if (rc != 0) { kmip_debug(debug, "Failed to parse hex string '%s'", str); goto out; } n->date_time_ext_value = int64; break; default: kmip_debug(debug, "Invalid JSON type %d for node type " "0x%x", value_type, n->type); rc = -EBADMSG; goto out; } break; default: kmip_debug(debug, "unknown type: 0x%x", n->type); rc = -EBADMSG; goto out; } *node = n; rc = 0; out: if (rc != 0) kmip_node_free(n); return rc; } /** * Encode a KMIP node into a JSON object using the JSON encoding. * * @param node the node to encode * @param obj On return: the JSON object * @param debug if true, debug messages are printed * * @returns 0 in case of success, or a negative errno value */ int kmip_encode_json(const struct kmip_node *node, json_object **obj, bool debug) { json_object *ret_obj = NULL, *memb_obj, *elem_obj; enum kmip_tag tag, v1_attr_tag = 0; struct kmip_node *element; char outstr[200] = { 0 }; const char *str; int64_t int64; struct tm *tm; char *tmp; char *s; int rc; if (node == NULL || obj == NULL) return -EINVAL; kmip_debug(debug, "tag: 0x%x type: 0x%x", node->tag, node->type); ret_obj = json_object_new_object(); if (ret_obj == NULL) { kmip_debug(debug, "Failed to allocate a JSON object"); return -ENOMEM; } memb_obj = json_object_new_string( kmip_tag_name_or_hex_by_tag(node->tag, outstr)); if (memb_obj == NULL) { kmip_debug(debug, "Failed to build JSON object for tag"); rc = -ENOMEM; goto out; } rc = json_object_object_add(ret_obj, KMIP_JSON_TAG, memb_obj); if (rc != 0) { kmip_debug(debug, "Failed to add JSON object for tag"); rc = -EIO; goto out; } if (node->name != NULL) { memb_obj = json_object_new_string(node->name); if (memb_obj == NULL) { kmip_debug(debug, "Failed to build JSON object for name"); rc = -ENOMEM; goto out; } rc = json_object_object_add(ret_obj, KMIP_JSON_NAME, memb_obj); if (rc != 0) { kmip_debug(debug, "Failed to add JSON object for name"); rc = -EIO; goto out; } } if (node->type != KMIP_TYPE_STRUCTURE) { str = kmip_type_name_by_type(node->type); if (str == NULL) { kmip_debug(debug, "unknown type 0x%x", node->type); rc = -EINVAL; goto out; } memb_obj = json_object_new_string(str); if (memb_obj == NULL) { kmip_debug(debug, "Failed to build JSON object for type"); rc = -ENOMEM; goto out; } rc = json_object_object_add(ret_obj, KMIP_JSON_TYPE, memb_obj); if (rc != 0) { kmip_debug(debug, "Failed to add JSON object for type"); rc = -EIO; goto out; } } /* * KMIP v1.x attribute values may be Enumerations or Integer Masks. * To correctly encode them, we need to know the tag. This is contained * in a Attribute Name node, which is an element of our parent node. */ if (node->tag == KMIP_TAG_ATTRIBUTE_VALUE) v1_attr_tag = kmip_find_v1_attribute_name_tag(node->parent); tag = (v1_attr_tag != 0 ? v1_attr_tag : node->tag); switch (node->type) { case KMIP_TYPE_STRUCTURE: memb_obj = json_object_new_array(); if (memb_obj == NULL) { kmip_debug(debug, "Failed to build JSON object for value array"); rc = -ENOMEM; goto out; } element = node->structure_value; while (element != NULL) { rc = kmip_encode_json(element, &elem_obj, debug); if (rc != 0) { kmip_debug(debug, "kmip_encode_json failed"); goto out; } rc = json_object_array_add(memb_obj, elem_obj); if (rc != 0) { kmip_debug(debug, "json_object_array_add failed"); rc = EIO; goto out; } element = element->next; } break; case KMIP_TYPE_INTEGER: if (kmip_is_tag_mask(tag) && node->integer_value != 0) { rc = kmip_format_mask(tag, node->integer_value, '|', &tmp); if (rc != 0) { kmip_debug(debug, "kmip_format_mask failed"); goto out; } memb_obj = json_object_new_string(tmp); free(tmp); } else { memb_obj = json_object_new_int(node->integer_value); } break; case KMIP_TYPE_INTERVAL: memb_obj = json_object_new_int(node->interval_value); break; case KMIP_TYPE_LONG_INTEGER: case KMIP_TYPE_DATE_TIME_EXTENDED: if (node->type == KMIP_TYPE_LONG_INTEGER) int64 = node->long_value; else int64 = node->date_time_ext_value; /* any values >= 2^52 must be represented as hex strings */ if (int64 < 4503599627370496 && int64 > -4503599627370496) { memb_obj = json_object_new_int64(int64); } else { rc = kmip_format_hex((const unsigned char *)&int64, sizeof(int64), true, &tmp); if (rc != 0) { kmip_debug(debug, "kmip_format_hex failed"); goto out; } memb_obj = json_object_new_string(tmp); free(tmp); } break; case KMIP_TYPE_BIG_INTEGER: rc = kmip_format_bignum(node->big_integer_value, true, &s); if (rc != 0) { kmip_debug(debug, "kmip_format_bignum failed"); goto out; } memb_obj = json_object_new_string(s); free(s); break; case KMIP_TYPE_ENUMERATION: str = kmip_enum_name_by_tag_value(tag, node->enumeration_value); if (str != NULL) memb_obj = json_object_new_string(str); else memb_obj = json_object_new_int(node->enumeration_value); break; case KMIP_TYPE_BOOLEAN: memb_obj = json_object_new_boolean(node->boolean_value); break; case KMIP_TYPE_TEXT_STRING: memb_obj = json_object_new_string(node->text_value); break; case KMIP_TYPE_BYTE_STRING: rc = kmip_format_hex(node->bytes_value, node->length, false, &s); if (rc != 0) { kmip_debug(debug, "kmip_format_hex_long failed"); goto out; } memb_obj = json_object_new_string(s); free(s); break; case KMIP_TYPE_DATE_TIME: tm = gmtime((time_t *)&node->date_time_value); strftime(outstr, sizeof(outstr), KMIP_ISO8601_TIMESTAMP_UTC, tm); memb_obj = json_object_new_string(outstr); break; default: kmip_debug(debug, "unknown type: 0x%x", node->type); rc = -EINVAL; goto out; } if (memb_obj == NULL) { rc = -ENOMEM; goto out; } rc = json_object_object_add(ret_obj, KMIP_JSON_VALUE, memb_obj); if (rc != 0) { kmip_debug(debug, "Failed to add JSON object for value"); rc = -EIO; goto out; } rc = 0; *obj = ret_obj; out: if (rc != 0) json_object_put(ret_obj); return rc; } #endif #endif opencryptoki-opencryptoki-451d99c/usr/sbin/p11kmip/kmipclient/key.c000066400000000000000000001304441520105705100254530ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021-2024 * * 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 _DEFAULT_SOURCE #include #include #include #include #include "kmip.h" #include "names.h" /** * Constructs a Key Block node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Key Block Structure v1.0 * Key Format Type Yes Enumeration v1.0 * Key Compression Type No Enumeration v1.0 * Key Value Yes various v1.0 * Cryptographic Algorithm Yes Enumeration v1.0 * Cryptographic Length Yes Integer v1.0 * Key Wrapping Data No Structure v1.0 * * @param format_type the key format type * @param format_type the key compression type (if 0 it is ignored) * @param key_value the key value node * @param algorithm the key algorithm (if 0 it is ignored) * @param length the cryptographic length (if <= 0 it is ignored) * @param wrappig_data the key wrapping data (can be NULL) * * @returns the allocated node, or NULL in case of an error. * The reference counts of the nodes specified as parameters which are added to * the newly allocated node are increased. The caller must free its reference * via kmip_node_free() if no longer needed. */ struct kmip_node *kmip_new_key_block(enum kmip_key_format_type format_type, enum kmip_key_compression_type compr_type, struct kmip_node *key_value, enum kmip_crypto_algo algorithm, int32_t length, struct kmip_node *wrappig_data) { struct kmip_node *ret = NULL, *fmt, *cmp = NULL, *algo = NULL; struct kmip_node *len = NULL; if (format_type == 0 || key_value == NULL) return NULL; fmt = kmip_node_new_enumeration(KMIP_TAG_KEY_FORMAT_TYPE, NULL, format_type); if (fmt == NULL) goto out; if (compr_type != 0) { cmp = kmip_node_new_enumeration(KMIP_TAG_KEY_COMPRESSION_TYPE, NULL, compr_type); if (cmp == NULL) goto out; } if (algorithm != 0) { algo = kmip_node_new_enumeration( KMIP_TAG_CRYPTOGRAPHIC_ALGORITHM, NULL, algorithm); if (algo == NULL) goto out; } if (length > 0) { len = kmip_node_new_integer(KMIP_TAG_CRYPTOGRAPHIC_LENGTH, NULL, length); if (len == NULL) goto out; } ret = kmip_node_new_structure_va(KMIP_TAG_KEY_BLOCK, NULL, 6, fmt, cmp, key_value, algo, len, wrappig_data); out: kmip_node_free(fmt); kmip_node_free(cmp); kmip_node_free(algo); kmip_node_free(len); return ret; } /** * Gets information from a Key Block node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Key Block Structure v1.0 * Key Format Type Yes Enumeration v1.0 * Key Compression Type No Enumeration v1.0 * Key Value Yes various v1.0 * Cryptographic Algorithm Yes Enumeration v1.0 * Cryptographic Length Yes Integer v1.0 * Key Wrapping Data No Structure v1.0 * * @param node the KMIP node * @param format_type On return: the key format type * @param format_type On return: the key compression type (0 if not avail, * can be NULL) * @param key_value On return: the key value node (can be NULL) * @param algorithm On return: the key algorithm (0 if not avail, can * be NULL) * @param length On return: the cryptographic length (0 if not avail, * can be NULL) * @param wrappig_data On return: the key wrapping data (can be NULL) * * @returns 0 on success, or a negative errno in case of an error. * The reference count of the returned nodes is increased. The caller must * free the node via kmip_node_free() when no longer needed. */ int kmip_get_key_block(const struct kmip_node *node, enum kmip_key_format_type *format_type, enum kmip_key_compression_type *compr_type, struct kmip_node **key_value, enum kmip_crypto_algo *algorithm, int32_t *length, struct kmip_node **wrappig_data) { struct kmip_node *n; if (node == NULL) return -EINVAL; if (kmip_node_get_tag(node) != KMIP_TAG_KEY_BLOCK) return -EBADMSG; if (format_type != NULL) { n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_KEY_FORMAT_TYPE, 0); if (n == NULL) return -EBADMSG; *format_type = kmip_node_get_enumeration(n); kmip_node_free(n); } if (compr_type != NULL) { n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_KEY_COMPRESSION_TYPE, 0); if (n != NULL) *compr_type = kmip_node_get_enumeration(n); else *compr_type = 0; kmip_node_free(n); } if (algorithm != NULL) { n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_CRYPTOGRAPHIC_ALGORITHM, 0); if (n != NULL) *algorithm = kmip_node_get_enumeration(n); else *algorithm = 0; kmip_node_free(n); } if (length != NULL) { n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_CRYPTOGRAPHIC_LENGTH, 0); if (n != NULL) *length = kmip_node_get_integer(n); else *length = -1; kmip_node_free(n); } if (key_value != NULL) { *key_value = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_KEY_VALUE, 0); if (*key_value == NULL) return -EBADMSG; } if (wrappig_data != NULL) *wrappig_data = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_KEY_WRAPPING_DATA, 0); return 0; } /** * Constructs a Key Value node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Key Value Structure v1.0 * Key Material Yes various v1.0 * Attribute No Structure v1.x only * ... may be repeated * Attributes No Structure v2.x only * * @param version the protocol version. If null, the current default * protocol version is used. * @param key_material the key material node * @param attrs_count the number of attributes following (can be 0) * @param v2_attrs the array of attributes (as KMIP v2.x attribute) * * @returns the allocated node, or NULL in case of an error. * The reference counts of the nodes specified as parameters which are added to * the newly allocated node are increased. The caller must free its reference * via kmip_node_free() if no longer needed. */ struct kmip_node *kmip_new_key_value(const struct kmip_version *version, struct kmip_node *key_material, unsigned int attrs_count, struct kmip_node **v2_attrs) { struct kmip_node *ret = NULL, *v2_attr, *v1_attr, *attrs = NULL; unsigned int i; int rc; if (key_material == NULL) return NULL; if (attrs_count > 0 && v2_attrs == NULL) return NULL; if (version == NULL) version = kmip_get_default_protocol_version(); if (version->major == 1) { /* KMIP v1.x */ ret = kmip_node_new_structure_va(KMIP_TAG_KEY_VALUE, NULL, 1, key_material); if (ret == NULL) return NULL; for (i = 0; i < attrs_count; i++) { v2_attr = v2_attrs[i]; if (v2_attr == NULL) continue; rc = kmip_v1_attr_from_v2_attr(v2_attr, &v1_attr); if (rc != 0) goto error; rc = kmip_node_add_structure_element(ret, v1_attr); kmip_node_free(v1_attr); if (rc != 0) goto error; } } else { /* KMIP >= v2.0 */ if (attrs_count > 0) { attrs = kmip_new_attributes(version, KMIP_TAG_ATTRIBUTES, attrs_count, v2_attrs); if (attrs == NULL) return NULL; } ret = kmip_node_new_structure_va(KMIP_TAG_KEY_VALUE, NULL, 2, key_material, attrs); kmip_node_free(attrs); } return ret; error: kmip_node_free(ret); return NULL; } /** * Constructs a Key Value node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Key Value Structure v1.0 * Key Material Yes various v1.0 * Attribute No Structure v1.x only * ... may be repeated * Attributes No Structure v2.x only * * @param version the protocol version. If null, the current default * protocol version is used. * @param key_material the key material node * @param attrs_count the number of attributes following (can be 0) * @param the attributes (as KMIP v2.x attribute) * * @returns the allocated node, or NULL in case of an error. * The reference counts of the nodes specified as parameters which are added to * the newly allocated node are increased. The caller must free its reference * via kmip_node_free() if no longer needed. */ struct kmip_node *kmip_new_key_value_va(const struct kmip_version *version, struct kmip_node *key_material, unsigned int attrs_count, ...) { struct kmip_node *ret, **attrs = NULL; unsigned int i, k; va_list ap; if (attrs_count > 0) { attrs = calloc(attrs_count, sizeof(struct kmip_node *)); if (attrs == NULL) return NULL; } va_start(ap, attrs_count); for (i = 0, k = 0; i < attrs_count; i++) { attrs[k] = va_arg(ap, struct kmip_node *); if (attrs[k] != NULL) k++; } va_end(ap); ret = kmip_new_key_value(version, key_material, k, attrs); if (attrs != NULL) free(attrs); return ret; } /** *Gets information from a Key Value node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Key Value (wrapped key value) Byte String v1.0 * Key Value (plaintext key value) Structure v1.0 * Key Material Yes various v1.0 * Attribute No Structure v1.x only * ... may be repeated * Attributes No Structure v2.x only * * @param node the KMIP node * @param key_material On return: the key material node (can be NULL) * @param num_attrs On return: the number of attributes (can be NULL). * @param index the index of the attribute to get * @param v2_attr On return: the attribute (as v2.x attribute) at the * specified index. Function returns -ENOENT if no * attribute is available at the index. * * @returns 0 on success, or a negative errno in case of an error. * The reference count of the returned nodes is increased. The caller must * free the node via kmip_node_free() when no longer needed. */ int kmip_get_key_value(const struct kmip_node *node, struct kmip_node **key_material, unsigned int *num_attrs, unsigned int index, struct kmip_node **v2_attr) { struct kmip_node *attr; int rc; if (node == NULL) return -EINVAL; if (kmip_node_get_tag(node) != KMIP_TAG_KEY_VALUE) return -EBADMSG; if (key_material != NULL) { switch (kmip_node_get_type(node)) { case KMIP_TYPE_BYTE_STRING: /* Wrapped key value */ *key_material = (struct kmip_node *)node; kmip_node_upref(*key_material); break; case KMIP_TYPE_STRUCTURE: /* plaintext key value */ *key_material = kmip_node_get_structure_element_by_index(node, 0); if (*key_material == NULL) return -EBADMSG; switch (kmip_node_get_type(*key_material)) { case KMIP_TYPE_BYTE_STRING: /* Raw, Opaque, PKCS1, PKCS8, ECPrivateKey */ break; case KMIP_TYPE_STRUCTURE: /* Transparent key formats */ switch (kmip_node_get_tag(*key_material)) { /* Transparent key formats: TAG_KEY_MATERIAL */ case KMIP_TAG_KEY_MATERIAL: break; default: rc = -EBADMSG; goto error; } break; default: rc = -EBADMSG; goto error; } break; default: return -EBADMSG; } } if (v2_attr == NULL || kmip_node_get_type(node) != KMIP_TYPE_STRUCTURE) return 0; attr = kmip_node_get_structure_element_by_index(node, 1); if (attr == NULL) { rc = -ENOENT; goto error; } if (kmip_node_get_tag(attr) == KMIP_TAG_ATTRIBUTES) { /* Its already a KMIP v2.x attributes structure */ rc = kmip_get_attributes(attr, num_attrs, index, v2_attr); kmip_node_free(attr); if (rc != 0) goto error; return 0; } /* Must be a KMIP v1.x attribute then */ kmip_node_free(attr); if (num_attrs != NULL) *num_attrs = kmip_node_get_structure_element_count(node) - 1; if (v2_attr == NULL) return 0; attr = kmip_node_get_structure_element_by_index(node, index + 1); if (attr == NULL) { rc = -ENOENT; goto error; } rc = kmip_v2_attr_from_v1_attr(attr, v2_attr); kmip_node_free(attr); if (rc != 0) goto error; return 0; error: if (key_material != NULL) { kmip_node_free(*key_material); *key_material = NULL; } return rc; } /** * Constructs a Key Wrapping Data node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Key Wrapping Data Structure v1.0 * Wrapping Method Yes Enumeration v1.0 * Encryption Key Information No Structure v1.0 * MAC/Signature Key Info. No Structure v1.0 * MAC/Signature No Byte String v1.0 * IV/Counter/Nonce No Byte String v1.0 * Encoding Option No Enumeration v1.2 * * @param version the protocol version. If null, the current default * protocol version is used. * @param wrap_method the key wrapping method * @param encr_key_info the encryption key info node (can be NULL) * @param mac_sign_key_info the MAC/Sign key info node (can be NULL) * @param mac_signature MAC/signature (can be NULL) * @param mac_signature_len the length of the MAC/Signature * @param iv_counter_nonce IV/Counter/Nonce (can be NULL) * @param iv_counter_nonce_len the length of theIV/Counter/Nonce * @param encoding the encoding option (can be 0, defaults to TTLV) * * @returns the allocated node, or NULL in case of an error. * The reference counts of the nodes specified as parameters which are added to * the newly allocated node are increased. The caller must free its reference * via kmip_node_free() if no longer needed. */ struct kmip_node *kmip_new_key_wrapping_data( const struct kmip_version *version, enum kmip_wrapping_method wrap_method, struct kmip_node *encr_key_info, struct kmip_node *mac_sign_key_info, const unsigned char *mac_signature, uint32_t mac_signature_len, const unsigned char *iv_counter_nonce, uint32_t iv_counter_nonce_len, enum kmip_encoding_option encoding) { struct kmip_node *ret = NULL, *wmeth, *mac = NULL, *iv = NULL; struct kmip_node *enc = NULL; if (wrap_method == 0) return NULL; if (version == NULL) version = kmip_get_default_protocol_version(); wmeth = kmip_node_new_enumeration(KMIP_TAG_WRAPPING_METHOD, NULL, wrap_method); if (wmeth == NULL) goto out; if (mac_signature != NULL && mac_signature_len > 0) { mac = kmip_node_new_byte_string(KMIP_TAG_MAC_SIGNATURE, NULL, mac_signature, mac_signature_len); if (mac == NULL) goto out; } if (iv_counter_nonce != NULL && iv_counter_nonce_len > 0) { iv = kmip_node_new_byte_string(KMIP_TAG_IV_COUNTER_NONCE, NULL, iv_counter_nonce, iv_counter_nonce_len); if (iv == NULL) goto out; } if (encoding != 0 && (version->major > 1 || (version->major == 1 && version->minor > 1))) { enc = kmip_node_new_enumeration(KMIP_TAG_ENCODING_OPTION, NULL, encoding); if (enc == NULL) goto out; } ret = kmip_node_new_structure_va(KMIP_TAG_KEY_WRAPPING_DATA, NULL, 6, wmeth, encr_key_info, mac_sign_key_info, mac, iv, enc); out: kmip_node_free(wmeth); kmip_node_free(mac); kmip_node_free(iv); kmip_node_free(enc); return ret; } /** *Gets information from a Key Wrapping Data node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Key Wrapping Data Structure v1.0 * Wrapping Method Yes Enumeration v1.0 * Encryption Key Information No Structure v1.0 * MAC/Signature Key Info. No Structure v1.0 * MAC/Signature No Byte String v1.0 * IV/Counter/Nonce No Byte String v1.0 * Encoding Option No Enumeration v1.2 * * @param node the KMIP node * @param wrap_method On return: the key wrapping method (can be NULL) * @param encr_key_info On return: the encryption key info node * (can be NULL) * @param mac_sign_key_info On return: the MAC/Sign key info node (can be NULL) * @param mac_signature On return: MAC/signature (can be NULL) * @param mac_signature_len On return: the length of the MAC/Signature * (can be NULL) * @param iv_counter_nonce On return: IV/Counter/Nonce (can be NULL) * @param iv_counter_nonce_len On return: the length of theIV/Counter/Nonce * (can be NULL) * @param encoding On return: the encoding option (can be NULL) * * @returns 0 on success, or a negative errno in case of an error. * The reference count of the returned nodes is increased. The caller must * free the node via kmip_node_free() when no longer needed. */ int kmip_get_key_wrapping_data(const struct kmip_node *node, enum kmip_wrapping_method *wrap_method, struct kmip_node **encr_key_info, struct kmip_node **mac_sign_key_info, const unsigned char **mac_signature, uint32_t *mac_signature_len, const unsigned char **iv_counter_nonce, uint32_t *iv_counter_nonce_len, enum kmip_encoding_option *encoding) { struct kmip_node *n; if (node == NULL) return -EINVAL; if (kmip_node_get_tag(node) != KMIP_TAG_KEY_WRAPPING_DATA) return -EBADMSG; if (wrap_method != NULL) { n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_WRAPPING_METHOD, 0); if (n == NULL) return -EBADMSG; *wrap_method = kmip_node_get_enumeration(n); kmip_node_free(n); } if (mac_signature != NULL && mac_signature_len != NULL) { n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_MAC_SIGNATURE, 0); if (n != NULL) { *mac_signature = kmip_node_get_byte_string(n, mac_signature_len); } else { *mac_signature = NULL; *mac_signature_len = 0; } kmip_node_free(n); } if (iv_counter_nonce != NULL && iv_counter_nonce_len != NULL) { n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_IV_COUNTER_NONCE, 0); if (n != NULL) { *iv_counter_nonce = kmip_node_get_byte_string(n, iv_counter_nonce_len); } else { *iv_counter_nonce = NULL; *iv_counter_nonce_len = 0; } kmip_node_free(n); } if (encoding != NULL) { n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_ENCODING_OPTION, 0); *encoding = (n != NULL ? kmip_node_get_enumeration(n) : 0); kmip_node_free(n); } if (encr_key_info != NULL) *encr_key_info = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_ENCRYPTION_KEY_INFORMATION, 0); if (mac_sign_key_info != NULL) *mac_sign_key_info = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_MAC_SIGNATURE_KEY_INFORMATION, 0); return 0; } /** * Constructs a Key Wrapping Specification node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Key Wrapping Specification Structure v1.0 * Wrapping Method Yes Enumeration v1.0 * Encryption Key Information No Structure v1.0 * MAC/Signature Key Info. No Structure v1.0 * Attribute Name No Text String v1.0 * ... may be repeated * Encoding Option No Enumeration v1.2 * * @param version the protocol version. If null, the current default * protocol version is used. * @param wrap_method the key wrapping method * @param encr_key_info the encryption key info node (can be NULL) * @param mac_sign_key_info the MAC/Sign key info node (can be NULL) * @param encoding the encoding option (can be 0, defaults to TTLV) * @param attr_name_count the number of attribute names following * @param attr_names the array of attributes names (as const char *) * * @returns the allocated node, or NULL in case of an error. * The reference counts of the nodes specified as parameters which are added to * the newly allocated node are increased. The caller must free its reference * via kmip_node_free() if no longer needed. */ struct kmip_node *kmip_new_key_wrapping_specification( const struct kmip_version *version, enum kmip_wrapping_method wrap_method, struct kmip_node *encr_key_info, struct kmip_node *mac_sign_key_info, enum kmip_encoding_option encoding, unsigned int attr_name_count, const char **attr_names) { struct kmip_node *ret = NULL, *wmeth, *enc = NULL, *name; unsigned int i; int rc; if (wrap_method == 0) return NULL; if (version == NULL) version = kmip_get_default_protocol_version(); wmeth = kmip_node_new_enumeration(KMIP_TAG_WRAPPING_METHOD, NULL, wrap_method); if (wmeth == NULL) goto out; ret = kmip_node_new_structure_va(KMIP_TAG_KEY_WRAPPING_SPECIFICATION, NULL, 3, wmeth, encr_key_info, mac_sign_key_info); for (i = 0; i < attr_name_count; i++) { if (attr_names[i] == NULL) continue; name = kmip_node_new_text_string(KMIP_TAG_ATTRIBUTE_NAME, NULL, attr_names[i]); if (name == NULL) goto error; rc = kmip_node_add_structure_element(ret, name); kmip_node_free(name); if (rc != 0) goto error; } if (encoding != 0 && (version->major > 1 || (version->major == 1 && version->minor > 1))) { enc = kmip_node_new_enumeration(KMIP_TAG_ENCODING_OPTION, NULL, encoding); if (enc == NULL) goto error; rc = kmip_node_add_structure_element(ret, enc); if (rc != 0) goto error; } goto out; error: kmip_node_free(ret); ret = NULL; out: kmip_node_free(wmeth); kmip_node_free(enc); return ret; } /** * Constructs a Key Wrapping Specification node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Key Wrapping Specification Structure v1.0 * Wrapping Method Yes Enumeration v1.0 * Encryption Key Information No Structure v1.0 * MAC/Signature Key Info. No Structure v1.0 * Attribute Name No Text String v1.0 * ... may be repeated * Encoding Option No Enumeration v1.2 * * @param version the protocol version. If null, the current default * protocol version is used. * @param wrap_method the key wrapping method * @param encr_key_info the encryption key info node (can be NULL) * @param mac_sign_key_info the MAC/Sign key info node (can be NULL) * @param encoding the encoding option (can be 0, defaults to TTLV) * @param attr_name_count the number of atribute names following * @param the attributes names (as const char *) * * @returns the allocated node, or NULL in case of an error. * The reference counts of the nodes specified as parameters which are added to * the newly allocated node are increased. The caller must free its reference * via kmip_node_free() if no longer needed. */ struct kmip_node *kmip_new_key_wrapping_specification_va( const struct kmip_version *version, enum kmip_wrapping_method wrap_method, struct kmip_node *encr_key_info, struct kmip_node *mac_sign_key_info, enum kmip_encoding_option encoding, unsigned int attr_name_count, ...) { const char **names = NULL; struct kmip_node *ret; unsigned int i; va_list ap; if (attr_name_count > 0) { names = calloc(attr_name_count, sizeof(const char *)); if (names == NULL) return NULL; } va_start(ap, attr_name_count); for (i = 0; i < attr_name_count; i++) names[i] = va_arg(ap, const char *); va_end(ap); ret = kmip_new_key_wrapping_specification(version, wrap_method, encr_key_info, mac_sign_key_info, encoding, attr_name_count, names); if (names != NULL) free(names); return ret; } /** *Gets information from a Key Wrapping Specification node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Key Wrapping Specification Structure v1.0 * Wrapping Method Yes Enumeration v1.0 * Encryption Key Information No Structure v1.0 * MAC/Signature Key Info. No Structure v1.0 * Attribute Name No Text String v1.0 * ... may be repeated * Encoding Option No Enumeration v1.2 * * @param node the KMIP node * @param wrap_method On return: the key wrapping method (can be NULL) * @param encr_key_info On return: the encryption key info node * (can be NULL) * @param mac_sign_key_info On return: the MAC/Sign key info node (can be NULL) * @param encoding On return: the encoding option (can be NULL) * @param num_attr_names On return: the number of attributes (can be NULL). * @param attr_name_index The index of the attribute name to return * @param attr_name On return: the attribute name at the specified index * (can be NULL). Function returns -ENOENT if no name * is available at the index. * * @returns 0 on success, or a negative errno in case of an error. * The reference count of the returned nodes is increased. The caller must * free the node via kmip_node_free() when no longer needed. */ int kmip_get_key_wrapping_specification(const struct kmip_node *node, enum kmip_wrapping_method *wrap_method, struct kmip_node **encr_key_info, struct kmip_node **mac_sign_key_info, enum kmip_encoding_option *encoding, unsigned int *num_attr_names, unsigned int attr_name_index, const char **attr_name) { struct kmip_node *n; if (node == NULL) return -EINVAL; if (kmip_node_get_tag(node) != KMIP_TAG_KEY_WRAPPING_SPECIFICATION) return -EBADMSG; if (wrap_method != NULL) { n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_WRAPPING_METHOD, 0); if (n == NULL) return -EBADMSG; *wrap_method = kmip_node_get_enumeration(n); kmip_node_free(n); } if (encoding != NULL) { n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_ENCODING_OPTION, 0); *encoding = (n != NULL ? kmip_node_get_enumeration(n) : 0); kmip_node_free(n); } if (num_attr_names != NULL) *num_attr_names = kmip_node_get_structure_element_by_tag_count( node, KMIP_TAG_ATTRIBUTE_NAME); if (attr_name != NULL) { n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_ATTRIBUTE_NAME, attr_name_index); if (n == NULL) return -ENOENT; *attr_name = kmip_node_get_text_string(n); kmip_node_free(n); } if (encr_key_info != NULL) *encr_key_info = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_ENCRYPTION_KEY_INFORMATION, 0); if (mac_sign_key_info != NULL) *mac_sign_key_info = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_MAC_SIGNATURE_KEY_INFORMATION, 0); return 0; } /** * Constructs a Encryption Key Information or MAC/Signature Key Information * node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Key Information Structure v1.0 * Unique Identifier Yes Text String v1.0 * Enumeration v2.0 * Integer v2.0 * Cryptographic Parameters No Structure v1.0 * * @param mac_sign if true a MAC/Signature Key Information node is * created, otherwise a Encryption Key Information * node. * @param unique_id the unique ID node * @param crypto_params the cryptographic parameters node (can be NULL) * * @returns the allocated node, or NULL in case of an error. * The reference counts of the nodes specified as parameters which are added to * the newly allocated node are increased. The caller must free its reference * via kmip_node_free() if no longer needed. */ struct kmip_node *kmip_new_key_info(bool mac_sign, struct kmip_node *unique_id, struct kmip_node *crypto_params) { enum kmip_tag tag; if (unique_id == NULL) return NULL; tag = (mac_sign ? KMIP_TAG_MAC_SIGNATURE_KEY_INFORMATION : KMIP_TAG_ENCRYPTION_KEY_INFORMATION); return kmip_node_new_structure_va(tag, NULL, 2, unique_id, crypto_params); } /** * Gets the information from an Encryption Key Information or MAC/Signature Key * Information node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Key Information Structure v1.0 * Unique Identifier Yes Text String v1.0 * Enumeration v2.0 * Integer v2.0 * Cryptographic Parameters No Structure v1.0 * * @param node the KMIP node * @param unique_id On return: the unique ID node (can be NULL) * @param crypto_params On return: the cryptographic parameters node (can * be NULL) * * @returns 0 on success, or a negative errno in case of an error * The reference count of the returned nodes is increased. The caller must * free the node via kmip_node_free() when no longer needed. */ int kmip_get_key_info(const struct kmip_node *node, struct kmip_node **unique_id, struct kmip_node **crypto_params) { if (node == NULL) return -EINVAL; if (kmip_node_get_tag(node) != KMIP_TAG_ENCRYPTION_KEY_INFORMATION && kmip_node_get_tag(node) != KMIP_TAG_MAC_SIGNATURE_KEY_INFORMATION) return -EBADMSG; if (unique_id != NULL) { *unique_id = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_UNIQUE_IDENTIFIER, 0); if (*unique_id == NULL) return -EBADMSG; } if (crypto_params != NULL) *crypto_params = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_CRYPTOGRAPHIC_PARAMETERS, 0); return 0; } /** * Constructs a Transparent Symmetric Key node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Key Material Structure v1.0 * Key Yes Byte String v1.0 * * @param key the key * @param key_length the key length * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_transparent_symmetric_key(const unsigned char *key, uint32_t key_length) { struct kmip_node *k, *ret; if (key == NULL || key_length == 0) return NULL; k = kmip_node_new_byte_string(KMIP_TAG_KEY, NULL, key, key_length); if (k == NULL) return NULL; ret = kmip_node_new_structure_va(KMIP_TAG_KEY_MATERIAL, NULL, 1, k); kmip_node_free(k); return ret; } /** * Gets the information from a Transparent Symmetric Key node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Key Material Structure v1.0 * Key Yes Byte String v1.0 * * @param node the KMIP node * @param key On return: the key * @param key_length On return: the key length * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_transparent_symmetric_key(const struct kmip_node *node, const unsigned char **key, uint32_t *key_length) { struct kmip_node *k; if (node == NULL || key == NULL || key_length == NULL) return -EINVAL; if (kmip_node_get_tag(node) != KMIP_TAG_KEY_MATERIAL) return -EBADMSG; k = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_KEY, 0); if (k == NULL) return -EBADMSG; *key = kmip_node_get_byte_string(k, key_length); kmip_node_free(k); return 0; } /** * Constructs a Transparent RSA Public Key node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Key Material Structure v1.0 * Modulus Yes Big Integer v1.0 * Public Exponent Yes Big Integer v1.0 * * @param modulus the modulus as OpenSSL BIGNUM * @param pub_ext the public exponent as OpenSSL BIGNUM * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_transparent_rsa_public_key(const BIGNUM *modulus, const BIGNUM *pub_exp) { struct kmip_node *mod, *exp, *ret = NULL; if (modulus == NULL || pub_exp == NULL) return NULL; mod = kmip_node_new_bigint(KMIP_TAG_MODULUS, NULL, modulus); exp = kmip_node_new_bigint(KMIP_TAG_PUBLIC_EXPONENT, NULL, pub_exp); if (mod == NULL || exp == NULL) goto out; ret = kmip_node_new_structure_va(KMIP_TAG_KEY_MATERIAL, NULL, 2, mod, exp); out: kmip_node_free(mod); kmip_node_free(exp); return ret; } /** * Gets the information from a Transparent RSA Public Key node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Key Material Structure v1.0 * Modulus Yes Big Integer v1.0 * Public Exponent Yes Big Integer v1.0 * * @param node the KMIP node * @param modulus On return: the modulus as OpenSSL BIGNUM * @param pub_ext On return: the public exponent as OpenSSL BIGNUM * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_transparent_rsa_public_key(const struct kmip_node *node, const BIGNUM **modulus, const BIGNUM **pub_exp) { struct kmip_node *n; if (node == NULL || modulus == NULL || pub_exp == NULL) return -EINVAL; if (kmip_node_get_tag(node) != KMIP_TAG_KEY_MATERIAL) return -EBADMSG; n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_MODULUS, 0); if (n == NULL) return -EBADMSG; *modulus = kmip_node_get_bigint(n); kmip_node_free(n); n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_PUBLIC_EXPONENT, 0); if (n == NULL) return -EBADMSG; *pub_exp = kmip_node_get_bigint(n); kmip_node_free(n); return 0; } /** * Constructs a PKCS#1 Public Key node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Key Material Byte String v1.0 * * @param pub_key the public key as OpenSSL PKEY * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_pkcs1_public_key(EVP_PKEY *pub_key) { struct kmip_node *ret = NULL; unsigned char *buf = NULL; int len; if (pub_key == NULL) return NULL; len = i2d_PublicKey(pub_key, &buf); if (len <= 0) return NULL; ret = kmip_node_new_byte_string(KMIP_TAG_KEY_MATERIAL, NULL, buf, len); OPENSSL_free(buf); return ret; } /** * Gets the information from a PKCS#1 Public Key node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Key Material Byte String v1.0 * * @param node the KMIP node * @param algo the algorithm of the key * @param pub_key On return: the public key as OpenSSL PKEY. Must be * freed by the caller using EVP_PKEY_free() when no * longer needed. * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_pkcs1_public_key(const struct kmip_node *node, enum kmip_crypto_algo algo, EVP_PKEY **pub_key) { const unsigned char *buf; uint32_t len = 0; int type; if (node == NULL || pub_key == NULL) return -EINVAL; if (kmip_node_get_tag(node) != KMIP_TAG_KEY_MATERIAL) return -EBADMSG; buf = kmip_node_get_byte_string(node, &len); if (buf == NULL || len == 0) return -EBADMSG; switch (algo) { case KMIP_CRYPTO_ALGO_RSA: type = EVP_PKEY_RSA; break; case KMIP_CRYPTO_ALGO_DSA: type = EVP_PKEY_DSA; break; case KMIP_CRYPTO_ALGO_ECDSA: type = EVP_PKEY_EC; break; default: return -EINVAL; } *pub_key = d2i_PublicKey(type, NULL, &buf, len); if (*pub_key == NULL) return -EIO; return 0; } /** * Constructs a PKCS#8 Public Key node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Key Material Byte String v1.0 * * @param pub_key the public key as OpenSSL PKEY * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_pkcs8_public_key(EVP_PKEY *pub_key) { struct kmip_node *ret = NULL; unsigned char *buf = NULL; int len; if (pub_key == NULL) return NULL; len = i2d_PUBKEY(pub_key, &buf); if (len <= 0) return NULL; ret = kmip_node_new_byte_string(KMIP_TAG_KEY_MATERIAL, NULL, buf, len); OPENSSL_free(buf); return ret; } /** * Gets the information from a PKCS#8 Public Key node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Key Material Byte String v1.0 * * @param node the KMIP node * @param pub_key On return: the public key as OpenSSL PKEY. Must be * freed by the caller using EVP_PKEY_free() when no * longer needed. * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_pkcs8_public_key(const struct kmip_node *node, EVP_PKEY **pub_key) { const unsigned char *buf; uint32_t len = 0; if (node == NULL || pub_key == NULL) return -EINVAL; if (kmip_node_get_tag(node) != KMIP_TAG_KEY_MATERIAL) return -EBADMSG; buf = kmip_node_get_byte_string(node, &len); if (buf == NULL || len == 0) return -EBADMSG; *pub_key = d2i_PUBKEY(NULL, &buf, len); if (*pub_key == NULL) return -EIO; return 0; } /** * Constructs a Raw Key node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Key Material Byte String v1.0 * * @param key the raw key * @param key_len the length of the key * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_raw_key(const unsigned char *key, uint32_t key_len) { if (key == NULL) return NULL; return kmip_node_new_byte_string(KMIP_TAG_KEY_MATERIAL, NULL, key, key_len); } /** * Gets the information from a Raw Key node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Key Material Byte String v1.0 * * @param node the KMIP node * @param key On return: the raw key * @param key_len On return: the length of the key * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_raw_key(const struct kmip_node *node, const unsigned char **key, uint32_t *key_len) { if (node == NULL || key == NULL) return -EINVAL; if (kmip_node_get_tag(node) != KMIP_TAG_KEY_MATERIAL) return -EBADMSG; *key = kmip_node_get_byte_string(node, key_len); if (*key == NULL) return -EBADMSG; return 0; } /** * Constructs a Symmetric Key node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Symmetric Key Structure v1.0 * Key Block Yes Structure v1.0 * * @param keyblock the key block node * * @returns the allocated node, or NULL in case of an error. * The reference counts of the nodes specified as parameters which are added to * the newly allocated node are increased. The caller must free its reference * via kmip_node_free() if no longer needed. */ struct kmip_node *kmip_new_symmetric_key(struct kmip_node *keyblock) { if (keyblock == NULL) return NULL; return kmip_node_new_structure_va(KMIP_TAG_SYMMETRIC_KEY, NULL, 1, keyblock); } /** * Gets the information from a Symmetric Key node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Symmetric Key Structure v1.0 * Key Block Yes Structure v1.0 * * @param node the KMIP node * @param keyblock On return: the key block node * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_symmetric_key(const struct kmip_node *node, struct kmip_node **keyblock) { if (node == NULL || keyblock == NULL) return -EINVAL; if (kmip_node_get_tag(node) != KMIP_TAG_SYMMETRIC_KEY) return -EBADMSG; *keyblock = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_KEY_BLOCK, 0); if (*keyblock == NULL) return -EBADMSG; return 0; } /** * Constructs a Public Key node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Public Key Structure v1.0 * Key Block Yes Structure v1.0 * * @param keyblock the key block node * * @returns the allocated node, or NULL in case of an error. * The reference counts of the nodes specified as parameters which are added to * the newly allocated node are increased. The caller must free its reference * via kmip_node_free() if no longer needed. */ struct kmip_node *kmip_new_public_key(struct kmip_node *keyblock) { if (keyblock == NULL) return NULL; return kmip_node_new_structure_va(KMIP_TAG_PUBLIC_KEY, NULL, 1, keyblock); } /** * Gets the information from a Public Key node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Public Key Structure v1.0 * Key Block Yes Structure v1.0 * * @param node the KMIP node * @param keyblock On return: the key block node * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_public_key(const struct kmip_node *node, struct kmip_node **keyblock) { if (node == NULL || keyblock == NULL) return -EINVAL; if (kmip_node_get_tag(node) != KMIP_TAG_PUBLIC_KEY) return -EBADMSG; *keyblock = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_KEY_BLOCK, 0); if (*keyblock == NULL) return -EBADMSG; return 0; } opencryptoki-opencryptoki-451d99c/usr/sbin/p11kmip/kmipclient/kmip.c000066400000000000000000001217321520105705100256230ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021-2024 * * 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 _DEFAULT_SOURCE #include #include #include #include #include #include "kmip.h" #include "utils.h" void __attribute__ ((constructor)) kmip_init(void); void __attribute__ ((destructor)) kmip_exit(void); /** * Constructs a new KMIP node with the specified tag and type, and an optional * name. The newly allocated node has a reference count of 1. * * @param tag the tag of the new node * @param name Optional: the name of the node (only used with JSON * or XML encoding). Can be NULL. * @param type the type of the new node * * @returns the allocated node, or NULL in case of an error */ static struct kmip_node *kmip_node_new(enum kmip_tag tag, const char *name, enum kmip_type type) { struct kmip_node *node; node = calloc(1, sizeof(struct kmip_node)); if (node == NULL) return NULL; node->ref_count = 1; node->tag = tag; node->type = type; if (name != NULL) { node->name = strdup(name); if (node->name == NULL) { free(node); return NULL; } } return node; } /** * Returns the tag of a KMIP node * * @param node the KMIP node * * @returns the tag */ enum kmip_tag kmip_node_get_tag(const struct kmip_node *node) { if (node == NULL) return 0; return node->tag; } /** * Returns the type of a KMIP node * * @param node the KMIP node * * @returns the type */ enum kmip_type kmip_node_get_type(const struct kmip_node *node) { if (node == NULL) return 0; return node->type; } /** * Returns the name of a KMIP node * * @param node the KMIP node * * @returns a copy of the name. The caller must free the returnd string. */ char *kmip_node_get_name(const struct kmip_node *node) { if (node == NULL) return NULL; if (node->name == NULL) return NULL; return strdup(node->name); } /** * Constructs a new KMIP node of type structure with the specified tag, and an * optional name, and the elements. The reference count of each added element is * increased. * * @param tag the tag of the new node * @param name Optional: the name of the node (only used with JSON * or XML encoding). Can be NULL. * @param num_elements the number of elements to add * @param elements the array elements to add. * * @returns the allocated node, or NULL in case of an error */ struct kmip_node *kmip_node_new_structure(enum kmip_tag tag, const char *name, unsigned int num_elements, struct kmip_node **elements) { struct kmip_node *node; int rc; node = kmip_node_new(tag, name, KMIP_TYPE_STRUCTURE); if (node == NULL) return NULL; rc = kmip_node_add_structure_elements(node, num_elements, elements); if (rc != 0) { kmip_node_free(node); return NULL; } return node; } /** * Constructs a new KMIP node of type structure with the specified tag, and an * optional name, and the elements. The reference count of each added element is * increased. * * @param tag the tag of the new node * @param name Optional: the name of the node (only used with JSON * or XML encoding). Can be NULL. * @param num_elements the number of elements following as variable args * @param the elements to add. Elements may be NULL, those * are skipped * * @returns the allocated node, or NULL in case of an error */ struct kmip_node *kmip_node_new_structure_va(enum kmip_tag tag, const char *name, unsigned int num_elements, ...) { struct kmip_node *node, **elements = NULL; unsigned int i; va_list ap; if (num_elements > 0) { elements = calloc(num_elements, sizeof(struct kmip_node *)); if (elements == NULL) return NULL; } va_start(ap, num_elements); for (i = 0; i < num_elements; i++) elements[i] = va_arg(ap, struct kmip_node *); va_end(ap); node = kmip_node_new_structure(tag, name, num_elements, elements); if (elements != NULL) free(elements); return node; } /** * Add an element to a KMIP node (which must be of type KMIP_TYPE_STRUCTURE). * The element is added as the last element. The reference count of the added * element is increased. * * @param node the structure node to add the element to * @param element the element to add * * @returns 0 in case of success, or a negative errno value */ int kmip_node_add_structure_element(struct kmip_node *node, struct kmip_node *element) { if (node == NULL || element == NULL) return -EINVAL; return kmip_node_add_structure_elements(node, 1, &element); } /** * Add elements to a KMIP node (which must be of type KMIP_TYPE_STRUCTURE). * The elements are added after the last element. The reference count of the * added elements is increased. * * @param node the structure node to add the element to * @param num_elements the number of elements to add * @param elements the array elements to add * * @returns 0 in case of success, or a negative errno value */ int kmip_node_add_structure_elements(struct kmip_node *node, unsigned int num_elements, struct kmip_node **elements) { struct kmip_node *element, *last; unsigned int i; if (node == NULL || (num_elements > 0 && elements == NULL)) return -EINVAL; if (node->type != KMIP_TYPE_STRUCTURE) return -EINVAL; if (node->structure_value == NULL) { last = NULL; } else { last = node->structure_value; while (last->next != NULL) last = last->next; } for (i = 0; i < num_elements; i++) { element = elements[i]; if (element == NULL) continue; kmip_node_upref(element); element->parent = node; element->next = NULL; if (last == NULL) node->structure_value = element; else last->next = element; last = element; } return 0; } /** * Returns the number of elements of a KMIP node of type structure * * @param node the KMIP node * * @returns the number of elements, or -1 if the node is not of type structure */ unsigned int kmip_node_get_structure_element_count(const struct kmip_node *node) { struct kmip_node *element; unsigned int i; if (node == NULL) return -1; if (node->type != KMIP_TYPE_STRUCTURE) return -1; element = node->structure_value; for (i = 0; element != NULL; i++) element = element->next; return i; } /** * Returns an element of a KMIP node of type structure * * @param node the KMIP node * @param index the index of the element to return * * @returns the element or NULL if no element is available at the specified * index, or the node is not of type structure. * The reference count of the returned element is increased. The caller must * free the element via kmip_node_free() when no longer needed. */ struct kmip_node *kmip_node_get_structure_element_by_index( const struct kmip_node *node, unsigned int index) { struct kmip_node *element; unsigned int i; if (node == NULL) return NULL; if (node->type != KMIP_TYPE_STRUCTURE) return NULL; element = node->structure_value; for (i = 0; i < index && element != NULL; i++) element = element->next; if (element != NULL) kmip_node_upref(element); return element; } /** * Returns the number of elements of a KMIP node of type structure of a * certain tag * * @param node the KMIP node * @param tag the tag to find * * @returns the number of elements, or -1 if the node is not of type structure */ unsigned int kmip_node_get_structure_element_by_tag_count( const struct kmip_node *node, enum kmip_tag tag) { struct kmip_node *element; unsigned int i; if (node == NULL) return -1; if (node->type != KMIP_TYPE_STRUCTURE) return -1; element = node->structure_value; for (i = 0; element != NULL; element = element->next) { if (element->tag != tag) continue; i++; } return i; } /** * Find a structure element by its tag. If multiple elements with the matching * tag are found, then the num'th one is returned. * * @param node the structure node to find the elements in * @param tag the tag to find * @param index the index of elements with the same tag to return. * * @returns the element node, or NULL if no element with the tag was found. * The reference count of the returned element is increased. The caller must * free the element via kmip_node_free() when no longer needed. */ struct kmip_node *kmip_node_get_structure_element_by_tag( const struct kmip_node *node, enum kmip_tag tag, unsigned int index) { struct kmip_node *e; if (node == NULL) return NULL; if (node->type != KMIP_TYPE_STRUCTURE) return NULL; e = node->structure_value; while (e != NULL) { if (e->tag == tag) { if (index == 0) { kmip_node_upref(e); return e; } index--; } e = e->next; } return NULL; } /** * Constructs a new KMIP node of type integer with the specified tag, and an * optional name, and the integer value * * @param tag the tag of the new node * @param name Optional: the name of the node (only used with JSON * or XML encoding). Can be NULL. * @param value the value * * @returns the allocated node, or NULL in case of an error */ struct kmip_node *kmip_node_new_integer(enum kmip_tag tag, const char *name, int32_t value) { struct kmip_node *node; node = kmip_node_new(tag, name, KMIP_TYPE_INTEGER); if (node == NULL) return NULL; node->integer_value = value; node->length = sizeof(int32_t); return node; } /** * Returns the value of a KMIP node of type integer * * @param node the KMIP node * * @returns the value of the node, or 0 if the node is not of type integer */ int32_t kmip_node_get_integer(const struct kmip_node *node) { if (node == NULL) return 0; if (node->type != KMIP_TYPE_INTEGER) return 0; return node->integer_value; } /** * Constructs a new KMIP node of type long integer with the specified tag, and * an optional name, and the long integer value * * @param tag the tag of the new node * @param name Optional: the name of the node (only used with JSON * or XML encoding). Can be NULL. * @param value the value * * @returns the allocated node, or NULL in case of an error */ struct kmip_node *kmip_node_new_long(enum kmip_tag tag, const char *name, int64_t value) { struct kmip_node *node; node = kmip_node_new(tag, name, KMIP_TYPE_LONG_INTEGER); if (node == NULL) return NULL; node->long_value = value; node->length = sizeof(int64_t); return node; } /** * Returns the value of a KMIP node of type long integer * * @param node the KMIP node * * @returns the value of the node, or 0 if the node is not of type long integer */ int64_t kmip_node_get_long(const struct kmip_node *node) { if (node == NULL) return 0; if (node->type != KMIP_TYPE_LONG_INTEGER) return 0; return node->long_value; } /** * Constructs a new KMIP node of type big integer with the specified tag, and * an optional name, and the big integer value * * @param tag the tag of the new node * @param name Optional: the name of the node (only used with JSON * or XML encoding). Can be NULL. * @param value the value as OpenSSL BIGNUM (can be NULL) * * @returns the allocated node, or NULL in case of an error */ struct kmip_node *kmip_node_new_bigint(enum kmip_tag tag, const char *name, const BIGNUM *value) { struct kmip_node *node; node = kmip_node_new(tag, name, KMIP_TYPE_BIG_INTEGER); if (node == NULL) return NULL; if (value != NULL) { node->big_integer_value = BN_dup(value); node->length = kmip_encode_bignum_length(value); } return node; } /** * Returns the value of a KMIP node of type big integer * * @param node the KMIP node * * @returns the value of the node, or NULL if the node is not of type big * integer, or no BIGNUM is set. The returned BIGNUM still belongs to the node, * and must not be freed by the caller. It is freed together with the node it * was obtained from. */ const BIGNUM *kmip_node_get_bigint(const struct kmip_node *node) { if (node == NULL) return NULL; if (node->type != KMIP_TYPE_BIG_INTEGER) return NULL; return node->big_integer_value; } /** * Constructs a new KMIP node of type enumeration with the specified tag, and * an optional name, and the enumeration value * * @param tag the tag of the new node * @param name Optional: the name of the node (only used with JSON * or XML encoding). Can be NULL. * @param enumeration the enumeration value * * @returns the allocated node, or NULL in case of an error */ struct kmip_node *kmip_node_new_enumeration(enum kmip_tag tag, const char *name, uint32_t enumeration) { struct kmip_node *node; node = kmip_node_new(tag, name, KMIP_TYPE_ENUMERATION); if (node == NULL) return NULL; node->enumeration_value = enumeration; node->length = sizeof(uint32_t); return node; } /** * Returns the value of a KMIP node of type enumeration * * @param node the KMIP node * * @returns the value of the node, or 0 if the node is not of type enumeration */ uint32_t kmip_node_get_enumeration(const struct kmip_node *node) { if (node == NULL) return 0; if (node->type != KMIP_TYPE_ENUMERATION) return 0; return node->enumeration_value; } /** * Constructs a new KMIP node of type boolean with the specified tag, and * an optional name, and the boolean value * * @param tag the tag of the new node * @param name Optional: the name of the node (only used with JSON * or XML encoding). Can be NULL. * @param value the value * * @returns the allocated node, or NULL in case of an error */ struct kmip_node *kmip_node_new_boolean(enum kmip_tag tag, const char *name, bool value) { struct kmip_node *node; node = kmip_node_new(tag, name, KMIP_TYPE_BOOLEAN); if (node == NULL) return NULL; node->boolean_value = value; node->length = sizeof(uint64_t); return node; } /** * Returns the value of a KMIP node of type boolean * * @param node the KMIP node * * @returns the value of the node, or 0 if the node is not of type boolean */ bool kmip_node_get_boolean(const struct kmip_node *node) { if (node == NULL) return false; if (node->type != KMIP_TYPE_BOOLEAN) return false; return node->boolean_value; } /** * Constructs a new KMIP node of type text string with the specified tag, and * an optional name, and the text string value * * @param tag the tag of the new node * @param name Optional: the name of the node (only used with JSON * or XML encoding). Can be NULL. * @param value the value (can be NULL) * * @returns the allocated node, or NULL in case of an error */ struct kmip_node *kmip_node_new_text_string(enum kmip_tag tag, const char *name, const char *value) { struct kmip_node *node; node = kmip_node_new(tag, name, KMIP_TYPE_TEXT_STRING); if (node == NULL) return NULL; if (value != NULL) { node->text_value = strdup(value); if (node->text_value == NULL) { free(node); return NULL; } node->length = strlen(value); } return node; } /** * Returns the value of a KMIP node of type text string * * @param node the KMIP node * * @returns the value of the node, or NULL if the node is not of type text * string or no string is set. The returned string still belongs to the node, * and must not be freed by the caller. It is freed together with the node it * was obtained from. */ const char *kmip_node_get_text_string(const struct kmip_node *node) { if (node == NULL) return NULL; if (node->type != KMIP_TYPE_TEXT_STRING) return NULL; return node->text_value; } /** * Constructs a new KMIP node of type byte string with the specified tag, and * an optional name, and the byte string value * * @param tag the tag of the new node * @param name Optional: the name of the node (only used with JSON * or XML encoding). Can be NULL. * @param value the byte string (can be NULL) * @param length the length of the byte string * * @returns the allocated node, or NULL in case of an error */ struct kmip_node *kmip_node_new_byte_string(enum kmip_tag tag, const char *name, const unsigned char *value, uint32_t length) { struct kmip_node *node; node = kmip_node_new(tag, name, KMIP_TYPE_BYTE_STRING); if (node == NULL) return NULL; if (value != NULL && length > 0) { node->bytes_value = malloc(length); if (node->bytes_value == NULL) { free(node); return NULL; } memcpy(node->bytes_value, value, length); node->length = length; } return node; } /** * Returns the value of a KMIP node of type byte string * * @param node the KMIP node * @param length On return, the length of the byte string * * @returns the value of the node, or NULL if the node is not of type byte * string or no string is set. The returned string still belongs to the node, * and must not be freed by the caller. It is freed together with the node it * was obtained from. */ const unsigned char *kmip_node_get_byte_string(const struct kmip_node *node, uint32_t *length) { if (node == NULL) return NULL; if (node->type != KMIP_TYPE_BYTE_STRING) return NULL; if (length != NULL) *length = node->length; return node->bytes_value; } /** * Constructs a new KMIP node of type date and time with the specified tag, and * an optional name, and the date and time value * * @param tag the tag of the new node * @param name Optional: the name of the node (only used with JSON * or XML encoding). Can be NULL. * @param value the value * * @returns the allocated node, or NULL in case of an error */ struct kmip_node *kmip_node_new_date_time(enum kmip_tag tag, const char *name, int64_t value) { struct kmip_node *node; node = kmip_node_new(tag, name, KMIP_TYPE_DATE_TIME); if (node == NULL) return NULL; node->date_time_value = value; node->length = sizeof(int64_t); return node; } /** * Returns the value of a KMIP node of type date and time * * @param node the KMIP node * * @returns the value of the node, or 0 if the node is not of type date and time */ int64_t kmip_node_get_date_time(const struct kmip_node *node) { if (node == NULL) return 0; if (node->type != KMIP_TYPE_DATE_TIME) return 0; return node->date_time_value; } /** * Constructs a new KMIP node of type interval with the specified tag, and * an optional name, and the interval value * * @param tag the tag of the new node * @param name Optional: the name of the node (only used with JSON * or XML encoding). Can be NULL. * @param value the value * * @returns the allocated node, or NULL in case of an error */ struct kmip_node *kmip_node_new_interval(enum kmip_tag tag, const char *name, uint32_t value) { struct kmip_node *node; node = kmip_node_new(tag, name, KMIP_TYPE_INTERVAL); if (node == NULL) return NULL; node->interval_value = value; node->length = sizeof(uint32_t); return node; } /** * Returns the value of a KMIP node of type interval * * @param node the KMIP node * * @returns the value of the node, or 0 if the node is not of type interval */ uint32_t kmip_node_get_interval(const struct kmip_node *node) { if (node == NULL) return 0; if (node->type != KMIP_TYPE_INTERVAL) return 0; return node->interval_value; } /** * Constructs a new KMIP node of type date and time extended with the specified * tag, and an optional name, and the date and time value * * @param tag the tag of the new node * @param name Optional: the name of the node (only used with JSON * or XML encoding). Can be NULL. * @param value the value * * @returns the allocated node, or NULL in case of an error */ struct kmip_node *kmip_node_new_date_time_ext(enum kmip_tag tag, const char *name, int64_t value) { struct kmip_node *node; node = kmip_node_new(tag, name, KMIP_TYPE_DATE_TIME_EXTENDED); if (node == NULL) return NULL; node->date_time_ext_value = value; node->length = sizeof(int64_t); return node; } /** * Returns the value of a KMIP node of type date and time extended * * @param node the KMIP node * * @returns the value of the node, or 0 if the node is not of type date and time * extended */ int64_t kmip_node_get_date_time_ext(const struct kmip_node *node) { if (node == NULL) return 0; if (node->type != KMIP_TYPE_DATE_TIME_EXTENDED) return 0; return node->date_time_ext_value; } /** * Clones (copies) a KMIP node with all its data and elements (in case of a * structure node). * * @param node the KMIP node to clone * * @returns the cloned node, or NULL in case of an error */ struct kmip_node *kmip_node_clone(const struct kmip_node *node) { struct kmip_node *clone, *element, *cloned_element; int rc; clone = kmip_node_new(node->tag, node->name, node->type); if (clone == NULL) return NULL; switch (clone->type) { case KMIP_TYPE_STRUCTURE: element = node->structure_value; while (element != NULL) { cloned_element = kmip_node_clone(element); if (cloned_element == NULL) goto error; rc = kmip_node_add_structure_element(clone, cloned_element); kmip_node_free(cloned_element); if (rc != 0) goto error; element = element->next; } break; case KMIP_TYPE_INTEGER: clone->integer_value = node->integer_value; break; case KMIP_TYPE_LONG_INTEGER: clone->long_value = node->long_value; break; case KMIP_TYPE_BIG_INTEGER: clone->big_integer_value = BN_dup(node->big_integer_value); if (clone->big_integer_value == NULL) goto error; break; case KMIP_TYPE_ENUMERATION: clone->enumeration_value = node->enumeration_value; break; case KMIP_TYPE_BOOLEAN: clone->boolean_value = node->boolean_value; break; case KMIP_TYPE_TEXT_STRING: if (node->text_value != NULL) { clone->text_value = strdup(node->text_value); if (node->text_value == NULL) goto error; clone->length = strlen(clone->text_value); } break; case KMIP_TYPE_BYTE_STRING: if (node->bytes_value != NULL && node->length > 0) { clone->bytes_value = malloc(node->length); if (clone->bytes_value == NULL) goto error; memcpy(clone->bytes_value, node->bytes_value, node->length); clone->length = node->length; } break; case KMIP_TYPE_DATE_TIME: clone->date_time_value = node->date_time_value; break; case KMIP_TYPE_INTERVAL: clone->interval_value = node->interval_value; break; case KMIP_TYPE_DATE_TIME_EXTENDED: clone->date_time_ext_value = node->date_time_ext_value; break; default: goto error; } return clone; error: kmip_node_free(clone); return NULL; } /** * Increments the reference count of a KMIP node * * @param node the node to increase the reference count for */ void kmip_node_upref(struct kmip_node *node) { if (node == NULL) return; __sync_add_and_fetch((unsigned long *)&node->ref_count, 1); } /** * Free a KMIP node, including its value (structure elements, etc) * * @param node the node to free */ void kmip_node_free(struct kmip_node *node) { struct kmip_node *element, *next; unsigned long ref_count = 0; if (node == NULL) return; if (node->ref_count > 0) ref_count = __sync_sub_and_fetch( (unsigned long *)&node->ref_count, 1); if (ref_count > 0) return; switch (node->type) { case KMIP_TYPE_STRUCTURE: element = node->structure_value; while (element != NULL) { next = element->next; /* * Unchain the element from the parent and next element, * even if the element itself might not be freed (due * to reference count). But the parent is freed, and * thus the chain of elements is not longer existent. */ element->parent = NULL; element->next = NULL; kmip_node_free(element); element = next; } break; case KMIP_TYPE_BIG_INTEGER: BN_free(node->big_integer_value); break; case KMIP_TYPE_TEXT_STRING: free(node->text_value); break; case KMIP_TYPE_BYTE_STRING: free(node->bytes_value); break; default: break; } free(node->name); free(node); } static struct kmip_version default_protocol_version = { .major = KMIP_DEFAULT_PROTOCOL_VERSION_MAJOR, .minor = KMIP_DEFAULT_PROTOCOL_VERSION_MINOR }; /** * Sets the default KMIP protocol version * * @param version the version to set */ void kmip_set_default_protocol_version(const struct kmip_version *version) { if (version == NULL) return; default_protocol_version.major = version->major; default_protocol_version.minor = version->minor; } /** * Sets the default KMIP protocol version * * @returns the default KMIP protocol version */ const struct kmip_version *kmip_get_default_protocol_version(void) { return &default_protocol_version; } /** * Constructs a new connection to a KMIP server using the specified connection * configuration. The strings specified in the configuration are copied into the * newly allocated connection, they can be freed by the caller after the new * connection has been allocated. The reference count in the PKEY specified * in the configuration is increased. The caller can free its PKEY as needed. * * @param config the connection configuration * @param connection On return: a newly allocated KMIP connection * @param debug if true, debug messages are printed * * @returns 0 in case of success, or a negative errno value */ int kmip_connection_new(const struct kmip_conn_config *config, struct kmip_connection **connection, bool debug) { struct kmip_connection *conn = NULL; int rc; if (config == NULL || connection == NULL) return -EINVAL; *connection = NULL; switch (config->encoding) { case KMIP_ENCODING_TTLV: /* TTLV can be used with both, plain-TLS and HTTPS */ switch (config->transport) { case KMIP_TRANSPORT_PLAIN_TLS: #ifdef HAVE_LIBCURL case KMIP_TRANSPORT_HTTPS: #endif break; default: kmip_debug(debug, "Invalid transport: %d", config->transport); return -EINVAL; } break; #ifdef HAVE_LIBCURL #ifdef HAVE_LIBJSONC case KMIP_ENCODING_JSON: #endif #ifdef HAVE_LIBXML2 case KMIP_ENCODING_XML: #endif #if defined HAVE_LIBJSONC || defined HAVE_LIBXML2 /* JSON/XML can only be used with HTTPS */ switch (config->transport) { case KMIP_TRANSPORT_PLAIN_TLS: kmip_debug(debug, "JSON/XML encode can only be used " "with HTTPS transport"); return -EINVAL; #ifdef HAVE_LIBCURL case KMIP_TRANSPORT_HTTPS: #endif break; default: kmip_debug(debug, "Invalid transport: %d", config->transport); return -EINVAL; } break; #endif #endif default: kmip_debug(debug, "Invalid encoding: %d", config->encoding); return -EINVAL; } if (config->server == NULL) { kmip_debug(debug, "KMIP Server must be specified"); return -EINVAL; } if (config->tls_client_key == NULL) { kmip_debug(debug, "Client key must be specified"); return -EINVAL; } if (config->tls_client_cert == NULL) { kmip_debug(debug, "Client certificate must be specified"); return -EINVAL; } conn = calloc(1, sizeof(struct kmip_connection)); if (conn == NULL) { kmip_debug(debug, "calloc failed"); return -ENOMEM; } conn->config.encoding = config->encoding; conn->config.transport = config->transport; kmip_debug(debug, "encoding: %d", conn->config.encoding); kmip_debug(debug, "transport: %d", conn->config.transport); conn->config.server = strdup(config->server); if (conn->config.server == NULL) { kmip_debug(debug, "strdup failed"); rc = -ENOMEM; goto out; } kmip_debug(debug, "server: '%s'", conn->config.server); conn->config.tls_client_key = config->tls_client_key; if (EVP_PKEY_up_ref(conn->config.tls_client_key) != 1) { kmip_debug(debug, "EVP_PKEY_up_ref failed"); rc = -EIO; goto out; } kmip_debug(debug, "client key: %p", conn->config.tls_client_key); conn->config.tls_client_cert = strdup(config->tls_client_cert); if (conn->config.tls_client_cert == NULL) { kmip_debug(debug, "strdup failed"); rc = -ENOMEM; goto out; } kmip_debug(debug, "client cert: '%s'", conn->config.tls_client_cert); if (config->tls_ca != NULL) { conn->config.tls_ca = strdup(config->tls_ca); if (conn->config.tls_ca == NULL) { kmip_debug(debug, "strdup failed"); rc = -ENOMEM; goto out; } kmip_debug(debug, "CA: '%s'", conn->config.tls_ca); } if (config->tls_issuer_cert != NULL) { conn->config.tls_issuer_cert = strdup(config->tls_issuer_cert); if (conn->config.tls_issuer_cert == NULL) { kmip_debug(debug, "strdup failed"); rc = -ENOMEM; goto out; } kmip_debug(debug, "issuer cert: '%s'", conn->config.tls_issuer_cert); } if (config->tls_pinned_pubkey != NULL) { conn->config.tls_pinned_pubkey = strdup(config->tls_pinned_pubkey); if (conn->config.tls_pinned_pubkey == NULL) { kmip_debug(debug, "strdup failed"); rc = -ENOMEM; goto out; } kmip_debug(debug, "pinned pubkey: '%s'", conn->config.tls_pinned_pubkey); } if (config->tls_server_cert != NULL) { conn->config.tls_server_cert = strdup(config->tls_server_cert); if (conn->config.tls_server_cert == NULL) { kmip_debug(debug, "strdup failed"); rc = -ENOMEM; goto out; } kmip_debug(debug, "server cert: '%s'", conn->config.tls_server_cert); } conn->config.tls_verify_peer = config->tls_verify_peer; conn->config.tls_verify_host = config->tls_verify_host; kmip_debug(debug, "verify peer: %d", conn->config.tls_verify_peer); kmip_debug(debug, "verify host: %d", conn->config.tls_verify_host); if (config->tls_cipher_list != NULL) { conn->config.tls_cipher_list = strdup(config->tls_cipher_list); if (conn->config.tls_cipher_list == NULL) { kmip_debug(debug, "strdup failed"); rc = -ENOMEM; goto out; } kmip_debug(debug, "TLS cipher list: '%s'", conn->config.tls_cipher_list); } if (config->tls13_cipher_list != NULL) { conn->config.tls13_cipher_list = strdup(config->tls13_cipher_list); if (conn->config.tls13_cipher_list == NULL) { kmip_debug(debug, "strdup failed"); rc = -ENOMEM; goto out; } kmip_debug(debug, "TLSv1.3 cipher list: '%s'", conn->config.tls13_cipher_list); } switch (conn->config.transport) { case KMIP_TRANSPORT_PLAIN_TLS: rc = kmip_connection_tls_init(conn, debug); if (rc != 0) { kmip_debug(debug, "kmip_connection_tls_init failed"); goto out; } break; #ifdef HAVE_LIBCURL case KMIP_TRANSPORT_HTTPS: rc = kmip_connection_https_init(conn, debug); if (rc != 0) { kmip_debug(debug, "kmip_connection_https_init failed"); goto out; } break; #endif default: kmip_debug(debug, "Invalid transport: %d", conn->config.transport); rc = -EINVAL; goto out; } *connection = conn; rc = 0; out: if (rc != 0) kmip_connection_free(conn); return rc; } /** * Perform a request over the KMIP connection * * @param connection the KMIP connection * @param request the request to send * @param response On return: the received response. Must be freed by * the caller. * * @param debug if true, debug messages are printed * * @returns 0 in case of success, or a negative errno value */ int kmip_connection_perform(struct kmip_connection *connection, struct kmip_node *request, struct kmip_node **response, bool debug) { int rc; if (connection == NULL || request == NULL || response == NULL) return -EINVAL; kmip_debug(debug, "KMIP Request:"); kmip_node_dump(request, debug); switch (connection->config.transport) { case KMIP_TRANSPORT_PLAIN_TLS: rc = kmip_connection_tls_perform(connection, request, response, debug); break; #ifdef HAVE_LIBCURL case KMIP_TRANSPORT_HTTPS: rc = kmip_connection_https_perform(connection, request, response, debug); break; #endif default: return -EINVAL; } if (rc == 0 && *response != NULL) { kmip_debug(debug, "KMIP Response:"); kmip_node_dump(*response, debug); } return rc; } /** * Terminates and frees a KMIP connection. * * @param connection the KMIP connection to free */ void kmip_connection_free(struct kmip_connection *connection) { if (connection == NULL) return; switch (connection->config.transport) { case KMIP_TRANSPORT_PLAIN_TLS: kmip_connection_tls_term(connection); break; #ifdef HAVE_LIBCURL case KMIP_TRANSPORT_HTTPS: kmip_connection_https_term(connection); break; #endif default: break; } free((void *)connection->config.server); EVP_PKEY_free(connection->config.tls_client_key); free((void *)connection->config.tls_client_cert); if (connection->config.tls_ca != NULL) free((void *)connection->config.tls_ca); if (connection->config.tls_issuer_cert != NULL) free((void *)connection->config.tls_issuer_cert); if (connection->config.tls_pinned_pubkey != NULL) free((void *)connection->config.tls_pinned_pubkey); if (connection->config.tls_server_cert != NULL) free((void *)connection->config.tls_server_cert); if (connection->config.tls_cipher_list != NULL) free((void *)connection->config.tls_cipher_list); if (connection->config.tls13_cipher_list != NULL) free((void *)connection->config.tls13_cipher_list); free(connection); } /** * Retrieves the serevr's certificate, public key and certificate chain * * @param server the KMIP server. * For Plain-TLS transport, only the hostname and * optional port number. * For HTTPS transport, an URL in the form * 'https://hostname[:port]/uri' * @param transport the transport mode * @param ca Optional: File name of the CA bundle PEM file, or a * name of a directory the multiple CA certificates. * If this is NULL, then the default system path for * CA certificates is used. * @param client_key the client key as an OpenSSL PKEY object. * @param client_cert File name of the client certificate PEM file * @param server_cert_pem File name of a PEM file into which the server * certificate is written. If NULL then ignored. * @param server_pubkey_pem File name of a PEM file into which the server * public key is written. If NULL then ignored. * @param cert_chain_pem File name of a PEM file into which the certificate * chain (excluding the server certificate) is written. * If NULL then ignored. * @param verified On return: If the server 's certificate has been * verified using the CA specification (if ca = NULL: * default system CAs, otherwise path or file to CAs). * @param debug if true, debug messages are printed * * @returns 0 in case of success, or a negative errno value */ int kmip_connection_get_server_cert(const char *server, enum kmip_transport transport, const char *ca, EVP_PKEY *client_key, const char *client_cert, const char *server_cert_pem, const char *server_pubkey_pem, const char *cert_chain_pem, bool *verified, bool debug) { struct kmip_conn_config config = { 0 }; struct kmip_connection *conn = NULL; int rc, numcerts, i; char *hostname = NULL; #ifdef HAVE_LIBCURL int port_found = 0; char *tok, *tok2; #endif STACK_OF(X509) *chain; bool do_verify = true; FILE *fp = NULL; X509 *cert; if (server == NULL || client_key == NULL || client_cert == NULL) return -EINVAL; config.encoding = KMIP_ENCODING_TTLV; config.transport = KMIP_TRANSPORT_PLAIN_TLS; config.tls_ca = ca; config.tls_client_key = client_key; config.tls_client_cert = client_cert; config.tls_verify_host = false; config.tls_verify_peer = false; config.tls_cipher_list = NULL; config.tls13_cipher_list = NULL; #ifdef HAVE_LIBCURL if (transport == KMIP_TRANSPORT_HTTPS) { if (strncmp(server, "https://", 8) != 0) { kmip_debug(debug, "Server must start with 'https://'"); return -EINVAL; } server += 8; /* Find port (if any) and beginning of uri */ if (*server == '[') { /* IPv6 address enclosed in square brackets */ tok = strchr(server, ']'); if (tok == NULL) { kmip_debug(debug, "malformed IPv6 address"); return -EINVAL; } tok++; if (*tok == ':') { port_found = 1; tok2 = strchr(tok, '/'); if (tok2 == NULL) tok2 = tok + strlen(tok); } else { tok2 = strchr(tok, '/'); if (tok2 == NULL) tok2 = tok + strlen(tok); } } else { /* hostname or IPv4 address */ tok = strchr(server, ':'); if (tok != NULL) { port_found = 1; tok2 = strchr(tok, '/'); if (tok2 == NULL) tok2 = tok + strlen(tok); } else { tok2 = strchr(server, '/'); if (tok2 == NULL) tok2 = (char *)server + strlen(server); } } hostname = calloc(1, tok2 - server + (!port_found ? 5 : 1)); if (hostname == NULL) { kmip_debug(debug, "calloc failed"); return -ENOMEM; } strncpy(hostname, server, tok2 - server); if (!port_found) { strcat(hostname, ":"); strcat(hostname, KMIP_DEFAULT_HTTPS_PORT); } config.server = hostname; } else { #else if (transport == KMIP_TRANSPORT_PLAIN_TLS) { #endif config.server = server; } retry: config.tls_verify_peer = do_verify; rc = kmip_connection_new(&config, &conn, debug); if (rc != 0) { kmip_debug(debug, "kmip_connection_new failed (do_verify: %d)", do_verify); if (do_verify) { /* * If peer verification failed (e.g. due to a self * signed server certificate), try again without peer * verification. */ do_verify = false; goto retry; } goto out; } if (verified != NULL) *verified = do_verify; chain = SSL_get_peer_cert_chain(conn->plain_tls.ssl); if (chain == NULL) { kmip_debug(debug, "SSL_get_peer_cert_chain failed"); rc = -EIO; goto out; } numcerts = sk_X509_num(chain); for (i = 0; i < numcerts; i++) { cert = sk_X509_value(chain, i); if (cert == NULL) break; if (debug) { kmip_debug(debug, "%d. Certificate:", i); X509_print_ex_fp(stderr, cert, XN_FLAG_COMPAT, X509_FLAG_COMPAT); } if (i == 0 && server_cert_pem != NULL) { fp = fopen(server_cert_pem, "w"); if (fp == NULL) { rc = -errno; kmip_debug(debug, "Failed to open %s for write", server_cert_pem, strerror(-rc)); goto out; } if (PEM_write_X509(fp, cert) != 1) { kmip_debug(debug, "PEM_write_X509 failed to " "write to %s", server_cert_pem); rc = -EIO; goto out; } fclose(fp); fp = NULL; if (server_pubkey_pem != NULL) { fp = fopen(server_pubkey_pem, "w"); if (fp == NULL) { rc = -errno; kmip_debug(debug, "Failed to open %s " "for write", server_pubkey_pem, strerror(-rc)); goto out; } if (PEM_write_PUBKEY(fp, X509_get0_pubkey(cert)) != 1) { kmip_debug(debug, "PEM_write_PUBKEY " "failed to write to %s", server_pubkey_pem); rc = -EIO; goto out; } fclose(fp); fp = NULL; } continue; } if (i > 0 && cert_chain_pem != NULL) { if (fp == NULL) fp = fopen(cert_chain_pem, "w"); if (fp == NULL) { rc = -errno; kmip_debug(debug, "Failed to open %s for write", cert_chain_pem, strerror(-rc)); goto out; } if (PEM_write_X509(fp, cert) != 1) { kmip_debug(debug, "PEM_write_X509 failed to " "write to %s", cert_chain_pem); rc = -EIO; goto out; } } } rc = 0; out: if (fp != NULL) fclose(fp); if (conn != NULL) kmip_connection_free(conn); if (hostname != NULL) free(hostname); return rc; } /** * Library constructor */ void __attribute__ ((constructor)) kmip_init(void) { #ifdef HAVE_LIBCURL CURLsslset rc; /* * Ensure that curl uses OpenSSL as SSL backend. If curl has already * been itialized by the calling application, the backend can't be * changed anymore, but we continue anyway. However, it will later be * checked if curl uses the OpenSSL backend, and a HTTPS connection * will fail if it is not using the OpenSSL backend. */ rc = curl_global_sslset(CURLSSLBACKEND_OPENSSL, NULL, NULL); if (rc != CURLSSLSET_OK && rc != CURLSSLSET_TOO_LATE) errx(EXIT_FAILURE, "libkmipclient: libcurl was not built with " "the OpenSSL backend"); curl_global_init(CURL_GLOBAL_ALL); #endif } /** * Library destructor */ void __attribute__ ((destructor)) kmip_exit(void) { #ifdef HAVE_LIBCURL curl_global_cleanup(); #endif } opencryptoki-opencryptoki-451d99c/usr/sbin/p11kmip/kmipclient/kmip.h000066400000000000000000000102321520105705100256200ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021-2024 * * 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 KMIP_H #define KMIP_H #include #include #include #include #ifdef HAVE_LIBCURL #ifdef HAVE_LIBJSONC #include #endif #ifdef HAVE_LIBXML2 #include #include #endif #include #endif #include "kmipclient.h" #include "platform.h" /* KMIP Connection related structures */ #define KMIP_DEFAULT_PROTOCOL_VERSION_MAJOR 1 #define KMIP_DEFAULT_PROTOCOL_VERSION_MINOR 0 struct kmip_connection { struct kmip_conn_config config; union { struct { SSL_CTX *ssl_ctx; SSL *ssl; BIO *bio; } plain_tls; #ifdef HAVE_LIBCURL struct { CURL **curl; struct curl_slist *headers; } https; #endif } u; }; #define plain_tls u.plain_tls #ifdef HAVE_LIBCURL #define https u.https #endif /* KMIP node related structures */ struct kmip_node { enum kmip_tag tag; enum kmip_type type; unsigned int length; char *name; /* optional, only used for JSON and XML encoding */ union { struct kmip_node *structure_value; int32_t integer_value; int64_t long_value; BIGNUM *big_integer_value; uint32_t enumeration_value; bool boolean_value; char *text_value; unsigned char *bytes_value; int64_t date_time_value; uint32_t interval_value; int64_t date_time_ext_value; } u; struct kmip_node *parent; struct kmip_node *next; volatile unsigned long ref_count; }; #define structure_value u.structure_value #define integer_value u.integer_value #define long_value u.long_value #define big_integer_value u.big_integer_value #define enumeration_value u.enumeration_value #define boolean_value u.boolean_value #define text_value u.text_value #define bytes_value u.bytes_value #define date_time_value u.date_time_value #define interval_value u.interval_value #define date_time_ext_value u.date_time_ext_value /* Attribute related internal functions */ int kmip_v2_attr_from_v1_attr(struct kmip_node *v1_attr, struct kmip_node **v2_attr); int kmip_v1_attr_from_v2_attr(struct kmip_node *v2_attr, struct kmip_node **v1_attr); char *kmip_build_v1_custom_attr_name(const char *vendor_id, const char *attr_name); struct kmip_node *kmip_new_attribute_name_v1( const struct kmip_node *v2_attr_ref); int kmip_get_attribute_name_v1(const struct kmip_node *node, struct kmip_node **v2_attr_ref); /* Connection related internal functions */ int kmip_connection_tls_init(struct kmip_connection *connection, bool debug); int kmip_connection_tls_perform(struct kmip_connection *connection, struct kmip_node *request, struct kmip_node **response, bool debug); void kmip_connection_tls_term(struct kmip_connection *connection); #ifdef HAVE_LIBCURL int kmip_connection_https_init(struct kmip_connection *connection, bool debug); int kmip_connection_https_perform(struct kmip_connection *connection, struct kmip_node *request, struct kmip_node **response, bool debug); void kmip_connection_https_term(struct kmip_connection *connection); #endif /* KIMP decoding and encoding internal functions */ int kmip_decode_ttlv(BIO *bio, size_t *size, struct kmip_node **node, bool debug); int kmip_encode_ttlv(struct kmip_node *node, BIO *bio, size_t *size, bool debug); #ifdef HAVE_LIBCURL #ifdef HAVE_LIBJSONC int kmip_decode_json(const json_object *obj, struct kmip_node *parent, struct kmip_node **node, bool debug); int kmip_encode_json(const struct kmip_node *node, json_object **obj, bool debug); #endif #ifdef HAVE_LIBXML2 int kmip_decode_xml(const xmlNode *xml, struct kmip_node *parent, struct kmip_node **node, bool debug); int kmip_encode_xml(const struct kmip_node *node, xmlNode **xml, bool debug); #endif #endif #endif opencryptoki-opencryptoki-451d99c/usr/sbin/p11kmip/kmipclient/kmipclient.h000066400000000000000000002664521520105705100270400ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021-2024 * * 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 LIB_KMIPCLIENT_H #define LIB_KMIPCLIENT_H #include #include #include enum kmip_tag { KMIP_TAG_ACTIVATION_DATE = 0x420001, KMIP_TAG_APPLICATION_DATA = 0x420002, KMIP_TAG_APPLICATION_NAMESPACE = 0x420003, KMIP_TAG_APPLICATION_SPECIFIC_INFORMATION = 0x420004, KMIP_TAG_ARCHIVE_DATE = 0x420005, /* deprecated since v1.1 */ KMIP_TAG_ASYNCHRONOUS_CORRELATION_VALUE = 0x420006, KMIP_TAG_ASYNCHRONOUS_INDICATOR = 0x420007, KMIP_TAG_ATTRIBUTE = 0x420008, KMIP_TAG_ATTRIBUTE_INDEX = 0x420009, /* v1.x only */ KMIP_TAG_ATTRIBUTE_NAME = 0x42000A, KMIP_TAG_ATTRIBUTE_VALUE = 0x42000B, KMIP_TAG_AUTHENTICATION = 0x42000C, KMIP_TAG_BATCH_COUNT = 0x42000D, KMIP_TAG_BATCH_ERROR_CONTINUATION_OPTION = 0x42000E, KMIP_TAG_BATCH_ITEM = 0x42000F, KMIP_TAG_BATCH_ORDER_OPTION = 0x420010, KMIP_TAG_BLOCK_CIPHER_MODE = 0x420011, KMIP_TAG_CANCELATION_RESULT = 0x420012, KMIP_TAG_CERTIFICATE = 0x420013, KMIP_TAG_CERTIFICATE_IDENTIFIER = 0x420014, /* deprecated since v1.1 */ KMIP_TAG_CERTIFICATE_ISSUER = 0x420015, /* deprecated since v1.1 */ KMIP_TAG_CERTIFICATE_ISSUER_ALTERNATIVE_NAME = 0x420016, /* deprecated since v1.1 */ KMIP_TAG_CERTIFICATE_ISSUER_DISTINGUISHED_NAME = 0x420017, /* deprecated since v1.1 */ KMIP_TAG_CERTIFICATE_REQUEST = 0x420018, KMIP_TAG_CERTIFICATE_REQUEST_TYPE = 0x420019, KMIP_TAG_CERTIFICATE_SUBJECT = 0x42001A, /* deprecated since v1.1 */ KMIP_TAG_CERTIFICATE_SUBJECT_ALTERNATIVE_NAME = 0x42001B, /* deprecated since v1.1 */ KMIP_TAG_CERTIFICATE_SUBJECT_DISTINGUISHED_NAME = 0x42001C, /* deprecated since v1.1 */ KMIP_TAG_CERTIFICATE_TYPE = 0x42001D, KMIP_TAG_CERTIFICATE_VALUE = 0x42001E, KMIP_TAG_COMMON_TEMPLATE_ATTRIBUTE = 0x42001F, /* v1.x only */ KMIP_TAG_COMPROMIZE_DATE = 0x420020, KMIP_TAG_COMPROMISE_OCCURRENCE_DATE = 0x420021, KMIP_TAG_CONTACT_INFORMATION = 0x420022, KMIP_TAG_CREDENTIAL = 0x420023, KMIP_TAG_CREDENTIAL_TYPE = 0x420024, KMIP_TAG_CREDENTIAL_VALUE = 0x420025, KMIP_TAG_CRITICALITY_INDICATOR = 0x420026, KMIP_TAG_CRT_Coefficient = 0x420027, KMIP_TAG_CRYPTOGRAPHIC_ALGORITHM = 0x420028, KMIP_TAG_CRYPTOGRAPHIC_DOMAIN_PARAMETERS = 0x420029, KMIP_TAG_CRYPTOGRAPHIC_LENGTH = 0x42002A, KMIP_TAG_CRYPTOGRAPHIC_PARAMETERS = 0x42002B, KMIP_TAG_CRYPTOGRAPHIC_USAGE_MASK = 0x42002C, KMIP_TAG_CUSTOM_ATTRIBUTE = 0x42002D, /* v1.x only */ KMIP_TAG_D = 0x42002E, KMIP_TAG_DEACTIVATION_DATE = 0x42002F, KMIP_TAG_DERIVATION_DATE = 0x420030, KMIP_TAG_DERIVATION_DATA = 0x420031, KMIP_TAG_DERIVATION_PARAMETERS = 0x420032, KMIP_TAG_DESTROY_DATE = 0x420033, KMIP_TAG_DIGEST = 0x420034, KMIP_TAG_DIGEST_VALUE = 0x420035, KMIP_TAG_ENCRYPTION_KEY_INFORMATION = 0x420036, KMIP_TAG_G = 0x420037, KMIP_TAG_HASHING_ALGORITHM = 0x420038, KMIP_TAG_INITIAL_DATE = 0x420039, KMIP_TAG_INITIALIZATION_VECTOR = 0x42003A, KMIP_TAG_ISSUER = 0x42003B, /* deprecated since v1.1 */ KMIP_TAG_ITERATION_COUNT = 0x42003C, KMIP_TAG_IV_COUNTER_NONCE = 0x42003D, KMIP_TAG_J = 0x42003E, KMIP_TAG_KEY = 0x42003F, KMIP_TAG_KEY_BLOCK = 0x420040, KMIP_TAG_KEY_COMPRESSION_TYPE = 0x420041, KMIP_TAG_KEY_FORMAT_TYPE = 0x420042, KMIP_TAG_KEY_MATERIAL = 0x420043, KMIP_TAG_KEY_PART_IDENTIFIER = 0x420044, KMIP_TAG_KEY_VALUE = 0x420045, KMIP_TAG_KEY_WRAPPING_DATA = 0x420046, KMIP_TAG_KEY_WRAPPING_SPECIFICATION = 0x420047, KMIP_TAG_LAST_CHANGE_DATE = 0x420048, KMIP_TAG_LEASE_TIME = 0x420049, KMIP_TAG_LINK = 0x42004A, KMIP_TAG_LINK_TYPE = 0x42004B, KMIP_TAG_LINKED_OBJECT_IDENTIFIER = 0x42004C, KMIP_TAG_MAC_SIGNATURE = 0x42004D, KMIP_TAG_MAC_SIGNATURE_KEY_INFORMATION = 0x42004E, KMIP_TAG_MAXIMUM_ITEMS = 0x42004F, KMIP_TAG_MAXIMUM_RESPONSE_SIZE = 0x420050, KMIP_TAG_MESSAGE_EXTENSION = 0x420051, KMIP_TAG_MODULUS = 0x420052, KMIP_TAG_NAME = 0x420053, KMIP_TAG_NAME_TYPE = 0x420054, KMIP_TAG_NAME_VALUE = 0x420055, KMIP_TAG_OBJECT_GROUP = 0x420056, KMIP_TAG_OBJECT_TYPE = 0x420057, KMIP_TAG_OFFSET = 0x420058, KMIP_TAG_OPAQUE_DATA_TYPE = 0x420059, KMIP_TAG_OPAQUE_DATA_VALUE = 0x42005A, KMIP_TAG_OPAQUE_OBJECT = 0x42005B, KMIP_TAG_OPERATION = 0x42005C, KMIP_TAG_OPERATION_POLICY_NAME = 0x42005D, /* deprecated since v1.3 */ KMIP_TAG_P = 0x42005E, KMIP_TAG_PADDING_METHOD = 0x42005F, KMIP_TAG_PRIME_EXPONENT_P = 0x420060, KMIP_TAG_PRIME_EXPONENT_Q = 0x420061, KMIP_TAG_PRIME_FIELD_SIZE = 0x420062, KMIP_TAG_PRIVATE_EXPONENT = 0x420063, KMIP_TAG_PRIVATE_KEY = 0x420064, KMIP_TAG_PRIVATE_KEY_TEMPLATE_ATTRIBUTE = 0x420065, /* v1.x only */ KMIP_TAG_PRIVATE_KEY_UNIQUE_IDENTIFIER = 0x420066, KMIP_TAG_PROCESS_START_DATE = 0x420067, KMIP_TAG_PROTECT_STOP_DATE = 0x420068, KMIP_TAG_PROTOCOL_VERSION = 0x420069, KMIP_TAG_PROTOCOL_VERSION_MAJOR = 0x42006A, KMIP_TAG_PROTOCOL_VERSION_MINOR = 0x42006B, KMIP_TAG_PUBLIC_EXPONENT = 0x42006C, KMIP_TAG_PUBLIC_KEY = 0x42006D, KMIP_TAG_PUBLIC_KEY_TEMPLATE_ATTRIBUTE = 0x42006E, /* v1.x only */ KMIP_TAG_PUBLIC_KEY_UNIQUE_IDENTIFIER = 0x42006F, KMIP_TAG_PUT_FUNCTION = 0x420070, KMIP_TAG_Q = 0x420071, KMIP_TAG_Q_STRING = 0x420072, KMIP_TAG_Q_LENGTH = 0x420073, KMIP_TAG_QUERY_FUNCTION = 0x420074, KMIP_TAG_RECOMMENDED_CURVE = 0x420075, KMIP_TAG_REPLACED_UNIQUE_IDENTIFIER = 0x420076, KMIP_TAG_REQUEST_HEADER = 0x420077, KMIP_TAG_REQUEST_MESSAGE = 0x420078, KMIP_TAG_REQUEST_PAYLOAD = 0x420079, KMIP_TAG_RESPONSE_HEADER = 0x42007A, KMIP_TAG_RESPONSE_MESSAGE = 0x42007B, KMIP_TAG_RESPONSE_PAYLOAD = 0x42007C, KMIP_TAG_RESULT_MESSAGE = 0x42007D, KMIP_TAG_RESULT_REASON = 0x42007E, KMIP_TAG_RESULT_STATUS = 0x42007F, KMIP_TAG_REVOCATION_MESSAGE = 0x420080, KMIP_TAG_REVOCATION_REASON = 0x420081, KMIP_TAG_REVOCATION_REASON_CODE = 0x420082, KMIP_TAG_KEY_ROLE_TYPE = 0x420083, KMIP_TAG_SALT = 0x420084, KMIP_TAG_SECRET_DATA = 0x420085, KMIP_TAG_SECRET_DATA_TYPE = 0x420086, KMIP_TAG_SERIAL_NUMBER = 0x420087, /* deprecated since v1.1 */ KMIP_TAG_SERVER_INFORMATION = 0x420088, KMIP_TAG_SPLIT_KEY = 0x420089, KMIP_TAG_SPLIT_KEY_METHOD = 0x42008A, KMIP_TAG_SPLIT_KEY_PARTS = 0x42008B, KMIP_TAG_SPLIT_KEY_THRESHOLD = 0x42008C, KMIP_TAG_STATE = 0x42008D, KMIP_TAG_STORAGE_STATUS_MASK = 0x42008E, KMIP_TAG_SYMMETRIC_KEY = 0x42008F, KMIP_TAG_TEMPLATE = 0x420090, /* v1.x only */ KMIP_TAG_TEMPLATE_ATTRIBUTE = 0x420091, /* v1.x only */ KMIP_TAG_TIME_STAMP = 0x420092, KMIP_TAG_UNIQUE_BATCH_ITEM_ID = 0x420093, KMIP_TAG_UNIQUE_IDENTIFIER = 0x420094, KMIP_TAG_USAGE_LIMITS = 0x420095, KMIP_TAG_USAGE_LIMITS_COUNT = 0x420096, KMIP_TAG_USAGE_LIMITS_TOTAL = 0x420097, KMIP_TAG_USAGE_LIMITS_UNIT = 0x420098, KMIP_TAG_USERNAME = 0x420099, KMIP_TAG_VALIDITY_DATE = 0x42009A, KMIP_TAG_VALIDITY_INDICATOR = 0x42009B, KMIP_TAG_VENDOR_EXTENSION = 0x42009C, KMIP_TAG_VENDOR_IDENTIFICATION = 0x42009D, KMIP_TAG_WRAPPING_METHOD = 0x42009E, KMIP_TAG_X = 0x42009F, KMIP_TAG_Y = 0x4200A0, KMIP_TAG_PASSWORD = 0x4200A1, KMIP_TAG_DEVICE_IDENTIFIER = 0x4200A2, /* since v1.2 */ KMIP_TAG_ENCODING_OPTION = 0x4200A3, /* since v1.2 */ KMIP_TAG_EXTENSION_INFORMATION = 0x4200A4, /* since v1.2 */ KMIP_TAG_EXTENSION_NAME = 0x4200A5, /* since v1.2 */ KMIP_TAG_EXTENSION_TAG = 0x4200A6, /* since v1.2 */ KMIP_TAG_EXTENSION_TYPE = 0x4200A7, /* since v1.2 */ KMIP_TAG_FRESH = 0x4200A8, /* since v1.2 */ KMIP_TAG_MACHINE_IDENTIFIER = 0x4200A9, /* since v1.2 */ KMIP_TAG_MEDIA_IDENTIFIER = 0x4200AA, /* since v1.2 */ KMIP_TAG_NETWORK_IDENTIFIER = 0x4200AB, /* since v1.2 */ KMIP_TAG_OBJECT_GROUP_MEMBER = 0x4200AC, /* since v1.2 */ KMIP_TAG_CERTIFICATE_LENGTH = 0x4200AD, /* since v1.2 */ KMIP_TAG_DIGITAL_SIGNATURE_ALGORITHM = 0x4200AE, /* since v1.2 */ KMIP_TAG_CERTIFICATE_SERIAL_NUMBER = 0x4200AF, /* since v1.2 */ KMIP_TAG_DEVICE_SERIAL_NUMBER = 0x4200B0, /* since v1.2 */ KMIP_TAG_ISSUER_ALTERNATE_NAME = 0x4200B1, /* since v1.2 */ KMIP_TAG_ISSUER_DISTINGUISHED_NAME = 0x4200B2, /* since v1.2 */ KMIP_TAG_SUBJECT_ALTERNATE_NAME = 0x4200B3, /* since v1.2 */ KMIP_TAG_SUBJECT_DISTINGUISHED_NAME = 0x4200B4, /* since v1.2 */ KMIP_TAG_X_509_CERTIFICATE_IDENTIFIER = 0x4200B5, /* since v1.2 */ KMIP_TAG_X_509_CERTIFICATE_ISSUER = 0x4200B6, /* since v1.2 */ KMIP_TAG_X_509_CERTIFICATE_SUBJECT = 0x4200B7, /* since v1.2 */ KMIP_TAG_KEY_VALUE_LOCATION = 0x4200B8, /* since v1.2 */ KMIP_TAG_KEY_VALUE_LOCATION_VALUE = 0x4200B9, /* since v1.2 */ KMIP_TAG_KEY_VALUE_LOCATION_TYPE = 0x4200BA, /* since v1.2 */ KMIP_TAG_KEY_VALUE_PRESENT = 0x4200BB, /* since v1.2 */ KMIP_TAG_ORIGINAL_CREATION_DATE = 0x4200BC, /* since v1.2 */ KMIP_TAG_PGP_KEY = 0x4200BD, /* since v1.2 */ KMIP_TAG_PGP_KEY_VERSION = 0x4200BE, /* since v1.2 */ KMIP_TAG_ALTERNATE_NAME = 0x4200BF, /* since v1.2 */ KMIP_TAG_ALTERNATE_NAME_VALUE = 0x4200C0, /* since v1.2 */ KMIP_TAG_ALTERNATE_NAME_TYPE = 0x4200C1, /* since v1.2 */ KMIP_TAG_DATA = 0x4200C2, /* since v1.2 */ KMIP_TAG_SIGNATURE_DATA = 0x4200C3, /* since v1.2 */ KMIP_TAG_DATA_LENGTH = 0x4200C4, /* since v1.2 */ KMIP_TAG_RANDOM_IV = 0x4200C5, /* since v1.2 */ KMIP_TAG_MAC_DATA = 0x4200C6, /* since v1.2 */ KMIP_TAG_ATTESTATION_TYPE = 0x4200C7, /* since v1.2 */ KMIP_TAG_NONCE = 0x4200C8, /* since v1.2 */ KMIP_TAG_NONCE_ID = 0x4200C9, /* since v1.2 */ KMIP_TAG_NONCE_VALUE = 0x4200CA, /* since v1.2 */ KMIP_TAG_ATTESTATION_MEASUREMENT = 0x4200CB, /* since v1.2 */ KMIP_TAG_ATTESTATION_ASSERTION = 0x4200CC, /* since v1.2 */ KMIP_TAG_IV_LENGTH = 0x4200CD, /* since v1.2 */ KMIP_TAG_TAG_LENGTH = 0x4200CE, /* since v1.2 */ KMIP_TAG_FIXED_FIELD_LENGTH = 0x4200CF, /* since v1.2 */ KMIP_TAG_COUNTER_LENGTH = 0x4200D0, /* since v1.2 */ KMIP_TAG_INITIAL_COUNTER_VALUE = 0x4200D1, /* since v1.2 */ KMIP_TAG_INVOCATION_FIELD_LENGTH = 0x4200D2, /* since v1.2 */ KMIP_TAG_ATTESTATION_CAPABLE_INDICATOR = 0x4200D3, /* since v1.2 */ KMIP_TAG_OFFSET_ITEMS = 0x4200D4, /* since v1.3 */ KMIP_TAG_LOCATED_ITEMS = 0x4200D5, /* since v1.3 */ KMIP_TAG_CORRELATION_VALUE = 0x4200D6, /* since v1.3 */ KMIP_TAG_INIT_INDICATOR = 0x4200D7, /* since v1.3 */ KMIP_TAG_FINAL_INDICATOR = 0x4200D8, /* since v1.3 */ KMIP_TAG_RNG_PARAMETERS = 0x4200D9, /* since v1.3 */ KMIP_TAG_RNG_ALGORITHM = 0x4200DA, /* since v1.3 */ KMIP_TAG_DRBG_ALGORITHM = 0x4200DB, /* since v1.3 */ KMIP_TAG_FIPS186_VARIANT = 0x4200DC, /* since v1.3 */ KMIP_TAG_PREDICTION_RESISTANCE = 0x4200DD, /* since v1.3 */ KMIP_TAG_RANDOM_NUMBER_GENERATOR = 0x4200DE, /* since v1.3 */ KMIP_TAG_VALIDATION_INFORMATION = 0x4200DF, /* since v1.3 */ KMIP_TAG_VALIDATION_AUTHORITY_TYPE = 0x4200E0, /* since v1.3 */ KMIP_TAG_VALIDATION_AUTHORITY_COUNTRY = 0x4200E1, /* since v1.3 */ KMIP_TAG_VALIDATION_AUTHORITY_URI = 0x4200E2, /* since v1.3 */ KMIP_TAG_VALIDATION_VERSION_MAJOR = 0x4200E3, /* since v1.3 */ KMIP_TAG_VALIDATION_VERSION_MINOR = 0x4200E4, /* since v1.3 */ KMIP_TAG_VALIDATION_TYPE = 0x4200E5, /* since v1.3 */ KMIP_TAG_VALIDATION_LEVEL = 0x4200E6, /* since v1.3 */ KMIP_TAG_VALIDATION_CERTIFICATE_IDENTIFIER = 0x4200E7, /* since v1.3 */ KMIP_TAG_VALIDATION_CERTIFICATE_URI = 0x4200E8, /* since v1.3 */ KMIP_TAG_VALIDATION_VENDOR_URI = 0x4200E9, /* since v1.3 */ KMIP_TAG_VALIDATION_PROFILE = 0x4200EA, /* since v1.3 */ KMIP_TAG_PROFILE_INFORMATION = 0x4200EB, /* since v1.3 */ KMIP_TAG_PROFILE_NAME = 0x4200EC, /* since v1.3 */ KMIP_TAG_SERVER_URI = 0x4200ED, /* since v1.3 */ KMIP_TAG_SERVER_PORT = 0x4200EE, /* since v1.3 */ KMIP_TAG_STREAMING_CAPABILITY = 0x4200EF, /* since v1.3 */ KMIP_TAG_ASYNCHRONOUS_CAPABILITY = 0x4200F0, /* since v1.3 */ KMIP_TAG_ATTESTATION_CAPABILITY = 0x4200F1, /* since v1.3 */ KMIP_TAG_UNWRAP_MODE = 0x4200F2, /* since v1.3 */ KMIP_TAG_DESTROY_ACTION = 0x4200F3, /* since v1.3 */ KMIP_TAG_SHREDDING_ALGORITHM = 0x4200F4, /* since v1.3 */ KMIP_TAG_RNG_MODE = 0x4200F5, /* since v1.3 */ KMIP_TAG_CLIENT_REGISTRATION_METHOD = 0x4200F6, /* since v1.3 */ KMIP_TAG_CAPABILITY_INFORMATION = 0x4200F7, /* since v1.3 */ KMIP_TAG_KEY_WRAP_TYPE = 0x4200F8, /* since v1.4 */ KMIP_TAG_BATCH_UNDO_CAPABILITY = 0x4200F9, /* since v1.4 */ KMIP_TAG_BATCH_CONTINUE_CAPABILITY = 0x4200FA, /* since v1.4 */ KMIP_TAG_PKCS_12_FRIENDLY_NAME = 0x4200FB, /* since v1.4 */ KMIP_TAG_DESCRIPTION = 0x4200FC, /* since v1.4 */ KMIP_TAG_COMMENT = 0x4200FD, /* since v1.4 */ KMIP_TAG_AUTHENTICATED_ENCRYPTION_ADDITIONAL_DATA = 0x4200FE, /* since v1.4 */ KMIP_TAG_AUTHENTICTAED_ENCRYPTION_TAG = 0x4200FF, /* since v1.4 */ KMIP_TAG_SALT_LENGTH = 0x420100, /* since v1.4 */ KMIP_TAG_MASK_GENERATOR = 0x420101, /* since v1.4 */ KMIP_TAG_MASK_GENERATOR_HASHING_ALGORITHM = 0x420102, /* since v1.4 */ KMIP_TAG_P_SOURCE = 0x420103, /* since v1.4 */ KMIP_TAG_TRAILER_FIELD = 0x420104, /* since v1.4 */ KMIP_TAG_CLIENT_CORRELATION_VALUE = 0x420105, /* since v1.4 */ KMIP_TAG_SERVER_CORRELATION_VALUE = 0x420106, /* since v1.4 */ KMIP_TAG_DIGESTED_DATA = 0x420107, /* since v1.4 */ KMIP_TAG_CERTIFICATE_SUBJECT_CN = 0x420108, /* since v1.4 */ KMIP_TAG_CERTIFICATE_SUBJECT_O = 0x420109, /* since v1.4 */ KMIP_TAG_CERTIFICATE_SUBJECT_OU = 0x42010A, /* since v1.4 */ KMIP_TAG_CERTIFICATE_SUBJECT_EMAIL = 0x42010B, /* since v1.4 */ KMIP_TAG_CERTIFICATE_SUBJECT_C = 0x42010C, /* since v1.4 */ KMIP_TAG_CERTIFICATE_SUBJECT_ST = 0x42010D, /* since v1.4 */ KMIP_TAG_CERTIFICATE_SUBJECT_L = 0x42010E, /* since v1.4 */ KMIP_TAG_CERTIFICATE_SUBJECT_UID = 0x42010F, /* since v1.4 */ KMIP_TAG_CERTIFICATE_SUBJECT_SERIAL_NUMBER = 0x420110, /* since v1.4 */ KMIP_TAG_CERTIFICATE_SUBJECT_TITLE = 0x420111, /* since v1.4 */ KMIP_TAG_CERTIFICATE_SUBJECT_DC = 0x420112, /* since v1.4 */ KMIP_TAG_CERTIFICATE_SUBJECT_DN_QUALIFIER = 0x420113, /* since v1.4 */ KMIP_TAG_CERTIFICATE_ISSUER_CN = 0x420114, /* since v1.4 */ KMIP_TAG_CERTIFICATE_ISSUER_O = 0x420115, /* since v1.4 */ KMIP_TAG_CERTIFICATE_ISSUER_OU = 0x420116, /* since v1.4 */ KMIP_TAG_CERTIFICATE_ISSUER_EMAIL = 0x420117, /* since v1.4 */ KMIP_TAG_CERTIFICATE_ISSUER_C = 0x420118, /* since v1.4 */ KMIP_TAG_CERTIFICATE_ISSUER_ST = 0x420119, /* since v1.4 */ KMIP_TAG_CERTIFICATE_ISSUER_L = 0x42011A, /* since v1.4 */ KMIP_TAG_CERTIFICATE_ISSUER_UID = 0x42011B, /* since v1.4 */ KMIP_TAG_CERTIFICATE_ISSUER_SERIAL_NUMBER = 0x42011C, /* since v1.4 */ KMIP_TAG_CERTIFICATE_ISSUER_TITLE = 0x42011D, /* since v1.4 */ KMIP_TAG_CERTIFICATE_ISSUER_DC = 0x42011E, /* since v1.4 */ KMIP_TAG_CERTIFICATE_ISSUER_DN_QUALIFIER = 0x42011F, /* since v1.4 */ KMIP_TAG_SENSITIVE = 0x420120, /* since v1.4 */ KMIP_TAG_ALWAYS_SENSITIVE = 0x420121, /* since v1.4 */ KMIP_TAG_EXTRACTABLE = 0x420122, /* since v1.4 */ KMIP_TAG_NEVER_EXTRACTABLE = 0x420123, /* since v1.4 */ KMIP_TAG_REPLACE_EXISTING = 0x420124, /* since v1.4 */ KMIP_TAG_ATTRIBUTES = 0x420125, /* since v2.0 */ KMIP_TAG_COMMON_ATTRIBUTES = 0x420126, /* since v2.0 */ KMIP_TAG_PRIVATE_KEY_ATTRIBUTES = 0x420127, /* since v2.0 */ KMIP_TAG_PUBLIC_KEY_ATTRIBUTES = 0x420128, /* since v2.0 */ KMIP_TAG_EXTENSION_ENUMERATION = 0x420129, /* since v2.0 */ KMIP_TAG_EXTENSION_ATTRIBUTE = 0x42012A, /* since v2.0 */ KMIP_TAG_EXTENSION_PARENT_STRUCTURE_TAG = 0x42012B, /* since v2.0 */ KMIP_TAG_EXTENSION_DESCRIPTION = 0x42012C, /* since v2.0 */ KMIP_TAG_SERVER_NAME = 0x42012D, /* since v2.0 */ KMIP_TAG_SERVER_SERIAL_NUMBER = 0x42012E, /* since v2.0 */ KMIP_TAG_SERVER_VERSION = 0x42012F, /* since v2.0 */ KMIP_TAG_SERVER_LOAD = 0x420130, /* since v2.0 */ KMIP_TAG_PRODUCT_NAME = 0x420131, /* since v2.0 */ KMIP_TAG_BUILD_LEVEL = 0x420132, /* since v2.0 */ KMIP_TAG_BUILD_DATE = 0x420133, /* since v2.0 */ KMIP_TAG_CLUSTER_INFO = 0x420134, /* since v2.0 */ KMIP_TAG_ALTERNATE_FAILOVER_ENDPOINTS = 0x420135, /* since v2.0 */ KMIP_TAG_SHORT_UNIQUE_IDENTIFIER = 0x420136, /* since v2.0 */ KMIP_TAG_TAG = 0x420138, /* since v2.0 */ KMIP_TAG_CERTIFICATE_REQUEST_UNIQUE_IDENTIFIER = 0x420139, /* since v2.0 */ KMIP_TAG_NIST_KEY_TYPE = 0x42013A, /* since v2.0 */ KMIP_TAG_ATTRIBUTE_REFERENCE = 0x42013B, /* since v2.0 */ KMIP_TAG_CURRENT_ATTRIBUTE = 0x42013C, /* since v2.0 */ KMIP_TAG_NEW_ATTRIBUTE = 0x42013D, /* since v2.0 */ KMIP_TAG_CERTIFICATE_REQUEST_VALUE = 0x420140, /* since v2.0 */ KMIP_TAG_LOG_MESSAGE = 0x420141, /* since v2.0 */ KMIP_TAG_PROFILE_VERSION = 0x420142, /* since v2.0 */ KMIP_TAG_PROFILE_VERSION_MAJOR = 0x420143, /* since v2.0 */ KMIP_TAG_PROFILE_VERSION_MINOR = 0x420144, /* since v2.0 */ KMIP_TAG_PROTECTION_LEVEL = 0x420145, /* since v2.0 */ KMIP_TAG_PROTECTION_PERIOD = 0x420146, /* since v2.0 */ KMIP_TAG_QUANTUM_SAFE = 0x420147, /* since v2.0 */ KMIP_TAG_QUANTUM_SAFE_CAPABILITY = 0x420148, /* since v2.0 */ KMIP_TAG_TICKET = 0x420149, /* since v2.0 */ KMIP_TAG_TICKET_TYPE = 0x42014A, /* since v2.0 */ KMIP_TAG_TICKET_VALUE = 0x42014B, /* since v2.0 */ KMIP_TAG_REQUEST_COUNT = 0x42014C, /* since v2.0 */ KMIP_TAG_RIGHTS = 0x42014D, /* since v2.0 */ KMIP_TAG_OBJECTS = 0x42014E, /* since v2.0 */ KMIP_TAG_OPERATIONS = 0x42014F, /* since v2.0 */ KMIP_TAG_RIGHT = 0x420150, /* since v2.0 */ KMIP_TAG_ENDPOINT_ROLE = 0x420151, /* since v2.0 */ KMIP_TAG_DEFAULTS_INFORMATION = 0x420152, /* since v2.0 */ KMIP_TAG_OBJECT_DEFAULTS = 0x420153, /* since v2.0 */ KMIP_TAG_EPHEMERAL = 0x420154, /* since v2.0 */ KMIP_TAG_SERVER_HASHED_PASSWORD = 0x420155, /* since v2.0 */ KMIP_TAG_ONE_TIME_PASSWORD = 0x420156, /* since v2.0 */ KMIP_TAG_HASHED_PASSWORD = 0x420157, /* since v2.0 */ KMIP_TAG_ADJUSTMENT_TYPE = 0x420158, /* since v2.0 */ KMIP_TAG_PKCS_11_INTERFACE = 0x420159, /* since v2.0 */ KMIP_TAG_PKCS_11_FUNCTION = 0x42015A, /* since v2.0 */ KMIP_TAG_PKCS_11_INPUT_PARAMETERS = 0x42015B, /* since v2.0 */ KMIP_TAG_PKCS_11_OUTPUT_PARAMETERS = 0x42015C, /* since v2.0 */ KMIP_TAG_PKCS_11_RETURN_CODE = 0x42015D, /* since v2.0 */ KMIP_TAG_PROTECTION_STORAGE_MASK = 0x42015E, /* since v2.0 */ KMIP_TAG_PROTECTION_STORAGE_MASKS = 0x42015F, /* since v2.0 */ KMIP_TAG_INTEROP_FUNCTION = 0x420160, /* since v2.0 */ KMIP_TAG_INTEROP_IDENTIFIER = 0x420161, /* since v2.0 */ KMIP_TAG_ADJUSTMENT_VALUE = 0x420162, /* since v2.0 */ KMIP_TAG_COMMON_PROTECTION_STORAGE_MASKS = 0x420163, /* since v2.0 */ KMIP_TAG_PRIVATE_PROTECTION_STORAGE_MASKS = 0x420164, /* since v2.0 */ KMIP_TAG_PUBLIC_PROTECTION_STORAGE_MASKS = 0x420165, /* since v2.0 */ KMIP_TAG_OBJECT_GROUPS = 0x420166, /* since v2.1 */ KMIP_TAG_OBJECT_TYPES = 0x420167, /* since v2.1 */ KMIP_TAG_CONSTRAINTS = 0x420168, /* since v2.1 */ KMIP_TAG_CONSTRAINT = 0x420169, /* since v2.1 */ KMIP_TAG_ROTATE_INTERVAL = 0x42016A, /* since v2.1 */ KMIP_TAG_ROTATE_AUTOMATIC = 0x42016B, /* since v2.1 */ KMIP_TAG_ROTATE_OFFSET = 0x42016C, /* since v2.1 */ KMIP_TAG_ROTATE_DATE = 0x42016D, /* since v2.1 */ KMIP_TAG_ROTATE_GENERATION = 0x42016E, /* since v2.1 */ KMIP_TAG_ROTATE_NAME = 0x42016F, /* since v2.1 */ KMIP_TAG_ROTATE_NAME_VALUE = 0x420170, /* since v2.1 */ KMIP_TAG_ROTATE_NAME_TYPE = 0x420171, /* since v2.1 */ KMIP_TAG_ROTATE_LATEST = 0x420172, /* since v2.1 */ KMIP_TAG_ASYNCHRONOUS_REQUEST = 0x420173, /* since v2.1 */ KMIP_TAG_SUBMISSION_DATE = 0x420174, /* since v2.1 */ KMIP_TAG_PROCESSING_STAGE = 0x420175, /* since v2.1 */ KMIP_TAG_ASYNCHRONOUS_CORRELATION_VALUES = 0x420176, /* since v2.1 */ }; enum kmip_type { KMIP_TYPE_STRUCTURE = 0x01, KMIP_TYPE_INTEGER = 0x02, KMIP_TYPE_LONG_INTEGER = 0x03, KMIP_TYPE_BIG_INTEGER = 0x04, KMIP_TYPE_ENUMERATION = 0x05, KMIP_TYPE_BOOLEAN = 0x06, KMIP_TYPE_TEXT_STRING = 0x07, KMIP_TYPE_BYTE_STRING = 0x08, KMIP_TYPE_DATE_TIME = 0x09, KMIP_TYPE_INTERVAL = 0x0A, KMIP_TYPE_DATE_TIME_EXTENDED = 0x0B, /* Since v2.0 */ }; enum kmip_operation { KMIP_OPERATION_CREATE = 0x01, KMIP_OPERATION_CREATE_KEY_PAIR = 0x02, KMIP_OPERATION_REGISTER = 0x03, KMIP_OPERATION_RE_KEY = 0x04, KMIP_OPERATION_DERIVE_KEY = 0x05, KMIP_OPERATION_CERTIFY = 0x06, KMIP_OPERATION_RE_CERTIFY = 0x07, KMIP_OPERATION_LOCATE = 0x08, KMIP_OPERATION_CHECK = 0x09, KMIP_OPERATION_GET = 0x0A, KMIP_OPERATION_GET_ATTRIBUTES = 0x0B, KMIP_OPERATION_GET_ATTRIBUTE_LIST = 0x0C, KMIP_OPERATION_ADD_ATTRIBUTE = 0x0D, KMIP_OPERATION_MODIFY_ATTRIBUTE = 0x0E, KMIP_OPERATION_DELETE_ATTRIBUTE = 0x0F, KMIP_OPERATION_OBTAIN_LEASE = 0x10, KMIP_OPERATION_GET_USAGE_ALLOCATION = 0x11, KMIP_OPERATION_ACTIVATE = 0x12, KMIP_OPERATION_REVOKE = 0x13, KMIP_OPERATION_DESTROY = 0x14, KMIP_OPERATION_ARCHIVE = 0x15, KMIP_OPERATION_RECOVER = 0x16, KMIP_OPERATION_VALIDATE = 0x17, KMIP_OPERATION_QUERY = 0x18, KMIP_OPERATION_CANCEL = 0x19, KMIP_OPERATION_POLL = 0x1A, KMIP_OPERATION_NOTIFY = 0x1B, KMIP_OPERATION_PUT = 0x1C, KMIP_OPERATION_RE_KEY_KEY_PAIR = 0x1D, /* since v1.2 */ KMIP_OPERATION_DISCOVER_VERSIONS = 0x1E, /* since v1.2 */ KMIP_OPERATION_ENCRYPT = 0x1F, /* since v1.2 */ KMIP_OPERATION_DECRYPT = 0x20, /* since v1.2 */ KMIP_OPERATION_SIGN = 0x21, /* since v1.2 */ KMIP_OPERATION_SIGNATURE_VERIFY = 0x22, /* since v1.2 */ KMIP_OPERATION_MAC = 0x23, /* since v1.2 */ KMIP_OPERATION_MAC_VERIFY = 0x24, /* since v1.2 */ KMIP_OPERATION_RNG_RETRIEVE = 0x25, /* since v1.2 */ KMIP_OPERATION_RNG_SEED = 0x26, /* since v1.2 */ KMIP_OPERATION_HASH = 0x27, /* since v1.2 */ KMIP_OPERATION_CREATE_SPLIT_KEY = 0x28, /* since v1.2 */ KMIP_OPERATION_JOIN_SPLIT_KEY = 0x29, /* since v1.2 */ KMIP_OPERATION_IMPORT = 0x2A, /* since v1.4 */ KMIP_OPERATION_EXPORT = 0x2B, /* since v1.4 */ KMIP_OPERATION_LOG = 0x2C, /* since v2.0 */ KMIP_OPERATION_LOGIN = 0x2D, /* since v2.0 */ KMIP_OPERATION_LOGOUT = 0x2E, /* since v2.0 */ KMIP_OPERATION_DELEGATE_LOGIN = 0x2F, /* since v2.0 */ KMIP_OPERATION_ADJUST_ATTRIBUTE = 0x30, /* since v2.0 */ KMIP_OPERATION_SET_ATTRIBUTE = 0x31, /* since v2.0 */ KMIP_OPERATION_SET_ENDPOINT_ROLE = 0x32, /* since v2.0 */ KMIP_OPERATION_PKS_11 = 0x33, /* since v2.0 */ KMIP_OPERATION_INTEROP = 0x34, /* since v2.0 */ KMIP_OPERATION_RE_PROVISION = 0x35, /* since v2.0 */ KMIP_OPERATION_SET_DEFAULTS = 0x36, /* since v2.1 */ KMIP_OPERATION_SET_CONSTRAINTS = 0x37, /* since v2.1 */ KMIP_OPERATION_GET_CONSTRAINTS = 0x38, /* since v2.1 */ KMIP_OPERATION_QUERY_ASYNCHRONOUS_REQUESTS = 0x39, /* since v2.1 */ KMIP_OPERATION_PROCESS = 0x3A, /* since v2.1 */ KMIP_OPERATION_PING = 0x3B, /* since v2.1 */ }; enum kmip_batch_error_cont_option { KMIP_BATCH_ERR_CONT_CONTINUE = 0x01, KMIP_BATCH_ERR_CONT_STOP = 0x02, KMIP_BATCH_ERR_CONT_UNDO = 0x03, }; enum kmip_crypto_usage_mask { KMIP_CRY_USAGE_MASK_SIGN = 0x00000001, KMIP_CRY_USAGE_MASK_VERIFY = 0x00000002, KMIP_CRY_USAGE_MASK_ENCRYPT = 0x00000004, KMIP_CRY_USAGE_MASK_DECRYPT = 0x00000008, KMIP_CRY_USAGE_MASK_WRAP_KEY = 0x00000010, KMIP_CRY_USAGE_MASK_UNWRAP_KEY = 0x00000020, KMIP_CRY_USAGE_MASK_EXPORT = 0x00000040, /* v1.x only */ KMIP_CRY_USAGE_MASK_MAC_GENERATE = 0x00000080, KMIP_CRY_USAGE_MASK_MAC_VERIFY = 0x00000100, KMIP_CRY_USAGE_MASK_DERIVE_KEY = 0x00000200, KMIP_CRY_USAGE_MASK_CONTENT_COMMITMENT = 0x00000400, /* v1.x only */ KMIP_CRY_USAGE_MASK_KEY_AGREEMENT = 0x00000800, KMIP_CRY_USAGE_MASK_CERTIFICATE_SIGN = 0x00001000, KMIP_CRY_USAGE_MASK_CLR_SIGN = 0x00002000, KMIP_CRY_USAGE_MASK_GENERATE_CRYPTOGRAM = 0x00004000, /* v1.x only */ KMIP_CRY_USAGE_MASK_VALIDATE_CRYPTOGRAM = 0x00008000, /* v1.x only */ KMIP_CRY_USAGE_MASK_TRANSLATE_ENCRYPT = 0x00010000, /* v1.x only */ KMIP_CRY_USAGE_MASK_TRANSLATE_DECRYPT = 0x00020000, /* v1.x only */ KMIP_CRY_USAGE_MASK_TRANSLATE_WRAP = 0x00040000, /* v1.x only */ KMIP_CRY_USAGE_MASK_TRANSLATE_UNWRAP = 0x00080000, /* v1.x only */ KMIP_CRY_USAGE_MASK_AUTHENTICATE = 0x00100000, /* since v2.0 */ KMIP_CRY_USAGE_MASK_UNRESTRICTED = 0x00200000, /* since v2.0 */ KMIP_CRY_USAGE_MASK_FPE_ENCRYPT = 0x00400000, /* since v2.0 */ KMIP_CRY_USAGE_MASK_FPE_DECRYPT = 0x00800000, /* since v2.0 */ }; enum kmip_result_status { KMIP_RESULT_STATUS_SUCCESS = 0x00, KMIP_RESULT_STATUS_OPERATION_FAILED = 0x01, KMIP_RESULT_STATUS_OPERATION_PENDING = 0x02, KMIP_RESULT_STATUS_OPERATION_UNDONE = 0x03, }; enum kmip_result_reason { KMIP_RESULT_REASON_ITEM_NOT_FOUND = 0x01, KMIP_RESULT_REASON_RESPONSE_TOO_LARGE = 0x02, KMIP_RESULT_REASON_AUTH_NOT_SUCCESSFUL = 0x03, KMIP_RESULT_REASON_INVALID_MESSAGE = 0x04, KMIP_RESULT_REASON_OPERATION_NOT_SUCCESSFUL = 0x05, KMIP_RESULT_REASON_MISSING_DATA = 0x06, KMIP_RESULT_REASON_INVALIUD_FIELD = 0x07, KMIP_RESULT_REASON_FEATURE_NOT_SUPPORTED = 0x08, KMIP_RESULT_REASON_OP_CANCELED_BY_REQUESTOR = 0x09, KMIP_RESULT_REASON_CRYPTOGRAPHIC_FAILURE = 0x0A, KMIP_RESULT_REASON_ILLEGAL_OPERATION = 0x0B, /* v 1.x only */ KMIP_RESULT_REASON_PERMISSION_DENIED = 0x0C, KMIP_RESULT_REASON_OBJECT_ARCHIVED = 0x0D, KMIP_RESULT_REASON_INDEX_OUT_OF_BOUNDS = 0x0E, /* v 1.x only */ KMIP_RESULT_REASON_APP_NAMESPACE_NOT_SUPPORTED = 0x0F, KMIP_RESULT_REASON_KEY_FORMAT_TYPE_NOT_SUPPORTED = 0x10, KMIP_RESULT_REASON_KEY_COMPRESSION_TYPE_NOT_SUPPORTED = 0x11, KMIP_RESULT_REASON_ENCODING_OPTION_ERROR = 0x12, /* since v1.2 */ KMIP_RESULT_REASON_KEY_VALUE_NOT_PRESENT = 0x13, /* since v1.2 */ KMIP_RESULT_REASON_ATTESTATION_REQUIRED = 0x14, /* since v1.2 */ KMIP_RESULT_REASON_ATTESTATION_FAILED = 0x15, /* since v1.2 */ KMIP_RESULT_REASON_SENSITIVE = 0x16, /* since v1.4 */ KMIP_RESULT_REASON_NOT_EXTRACTABLE = 0x17, /* since v1.4 */ KMIP_RESULT_REASON_OBJECT_ALREADY_EXISTS = 0x18, /* since v1.4 */ KMIP_RESULT_REASON_INVALID_TICKET = 0x19, /* since v2.0 */ KMIP_RESULT_REASON_USAGE_LIMIT_EXCEEDED = 0x1A, /* since v2.0 */ KMIP_RESULT_REASON_NUMERIC_RANGE = 0x1B, /* since v2.0 */ KMIP_RESULT_REASON_INVALID_DATA_TYPE = 0x1C, /* since v2.0 */ KMIP_RESULT_REASON_READ_ONLY_ATTRIBUTE = 0x1D, /* since v2.0 */ KMIP_RESULT_REASON_MULTI_VALUED_ATTRIBUTE = 0x1E, /* since v2.0 */ KMIP_RESULT_REASON_UNSUPPORTED_ATTRIBUTE = 0x1F, /* since v2.0 */ KMIP_RESULT_REASON_ATTRIBUTE_INSTANCE_NOT_FOUND = 0x20, /* since v2.0 */ KMIP_RESULT_REASON_ATTRIBUTE_NOT_FOUND = 0x21, /* since v2.0 */ KMIP_RESULT_REASON_ATTRIBUTE_READ_ONLY = 0x22, /* since v2.0 */ KMIP_RESULT_REASON_ATTRIBUTE_SINGLE_VALUED = 0x23, /* since v2.0 */ KMIP_RESULT_REASON_BAD_CRYPTOGRAPHIC_PARAMETERS = 0x24, /* since v2.0 */ KMIP_RESULT_REASON_BAD_PASSWORD = 0x25, /* since v2.0 */ KMIP_RESULT_REASON_CODEC_ERROR = 0x26, /* since v2.0 */ KMIP_RESULT_REASON_ILLEGAL_OBJECT_TYPE = 0x28, /* since v2.0 */ KMIP_RESULT_REASON_INCOMPATIBLE_CRYPTO_USAGE_MASK = 0x29, /* since v2.0 */ KMIP_RESULT_REASON_INTERNAL_SERVER_ERROR = 0x2A, /* since v2.0 */ KMIP_RESULT_REASON_INVALID_ASYNC_CORRELATION_VALUE = 0x2B, /* since v2.0 */ KMIP_RESULT_REASON_INVALID_ATTRIBUTE = 0x2C, /* since v2.0 */ KMIP_RESULT_REASON_INVALID_ATTRIBUTE_VALUE = 0x2D, /* since v2.0 */ KMIP_RESULT_REASON_INVALID_CORRELATION_VALUE = 0x2E, /* since v2.0 */ KMIP_RESULT_REASON_INVALID_CSR = 0x2F, /* since v2.0 */ KMIP_RESULT_REASON_INVALID_OBJECT_TYPE = 0x30, /* since v2.0 */ KMIP_RESULT_REASON_KEY_WRAP_TYPE_NOT_SUPPORTED = 0x32, /* since v2.0 */ KMIP_RESULT_REASON_MISSING_INITIALIZATION_VECTOR = 0x34, /* since v2.0 */ KMIP_RESULT_REASON_NOT_UNIQUE_NAME_ATTRIBUTE = 0x35, /* since v2.0 */ KMIP_RESULT_REASON_OBJECT_DESTROYED = 0x36, /* since v2.0 */ KMIP_RESULT_REASON_OBJECT_NOT_FOUND = 0x37, /* since v2.0 */ KMIP_RESULT_REASON_NOT_AUTHORISED = 0x39, /* since v2.0 */ KMIP_RESULT_REASON_SERVER_LIMIT_EXCEEDED = 0x3A, /* since v2.0 */ KMIP_RESULT_REASON_UNKNOWN_ENUMERATION = 0x3B, /* since v2.0 */ KMIP_RESULT_REASON_UNKNOWN_MESSAGE_EXTENSION = 0x3C, /* since v2.0 */ KMIP_RESULT_REASON_UNKNOWN_TAG = 0x3D, /* since v2.0 */ KMIP_RESULT_REASON_UNSUPPORTED_CRYPTO_PARAMETERS = 0x3E, /* since v2.0 */ KMIP_RESULT_REASON_UNSUPPORTED_PROTOCOL_VERSION = 0x3F, /* since v2.0 */ KMIP_RESULT_REASON_WRAPPING_OBJECT_ARCHIVED = 0x40, /* since v2.0 */ KMIP_RESULT_REASON_WRAPPING_OBJECT_DESTROYED = 0x41, /* since v2.0 */ KMIP_RESULT_REASON_WRAPPING_OBJECT_NOT_FOUND = 0x42, /* since v2.0 */ KMIP_RESULT_REASON_WRONG_KEY_LIFECYCLE_STATE = 0x43, /* since v2.0 */ KMIP_RESULT_REASON_PROTECTION_STORAGE_UNAVAILABLE = 0x44, /* since v2.0 */ KMIP_RESULT_REASON_PKCS_11_CODE_ERROR = 0x45, /* since v2.0 */ KMIP_RESULT_REASON_PKCS_11_INVALID_FUNCTION = 0x46, /* since v2.0 */ KMIP_RESULT_REASON_PKCS_11_INVALID_INTERFACE = 0x47, /* since v2.0 */ KMIP_RESULT_REASON_PRIVATE_PROT_STORAGE_UNAVAILABLE = 0x48, /* since v2.0 */ KMIP_RESULT_REASON_PUBLIC_PROT_STORAGE_UNAVAILABLE = 0x49, /* since v2.0 */ KMIP_RESULT_REASON_UNKNOWN_OBJECT_GROUP = 0x4A, /* since v2.1 */ KMIP_RESULT_REASON_CONSTRAINT_VIOLATION = 0x4B, /* since v2.1 */ KMIP_RESULT_REASON_DUPLICATE_PROCESS_REQUEST = 0x4C, /* since v2.1 */ KMIP_RESULT_REASON_GENERAL_FAILURE = 0x100, }; enum kmip_query_function { KMIP_QUERY_OPERATIONS = 0x01, KMIP_QUERY_OBJECTS = 0x02, KMIP_QUERY_SERVER_INFORMATION = 0x03, KMIP_QUERY_APPLICATION_NAMESPACES = 0x04, /* since v1.2 */ KMIP_QUERY_EXTENSION_LIST = 0x05, /* since v1.2 */ KMIP_QUERY_EXTENSION_MAP = 0x06, /* since v1.2 */ KMIP_QUERY_ATTESTATION_TYPES = 0x07, /* since v1.2 */ KMIP_QUERY_QUERY_RNGS = 0x08, /* since v1.3 */ KMIP_QUERY_VALIDATIONS = 0x09, /* since v1.3 */ KMIP_QUERY_PROFILES = 0x0A, /* since v1.3 */ KMIP_QUERY_CAPABILITIES = 0x0B, /* since v1.3 */ KMIP_QUERY_CLIENT_REGISTRATION_METHODS = 0x0C, /* since v1.3 */ KMIP_QUERY_DEFAULTS_INFORMATION = 0x0D, /* since v2.0 */ KMIP_QUERY_STORAGE_PROTECTION_MASKS = 0x0E, /* since v2.0 */ }; enum kmip_name_type { KMIP_NAME_TYPE_UNINTERPRETED_TEXT_STRING = 0x01, KMIP_NAME_TYPE_URI = 0x02, }; enum kmip_alternative_name_type { KMIP_ALT_NAME_TYPE_UNINTERPRETED_TEXT_STRING = 0x01, KMIP_ALT_NAME_TYPE_URI = 0x02, KMIP_ALT_NAME_TYPE_OBJECT_SERIAL_NUMBER = 0x03, KMIP_ALT_NAME_TYPE_EMAIL_ADDRESS = 0x04, KMIP_ALT_NAME_TYPE_DNS_NAME = 0x05, KMIP_ALT_NAME_TYPE_X_500_DISTINGUISHED_NAME = 0x06, KMIP_ALT_NAME_TYPE_IP_ADDRESS = 0x07, }; enum kmip_unique_identifier { KMIP_UNIQUE_ID_ID_PLACEHOLDER = 0x01, /* since v2.0 */ KMIP_UNIQUE_ID_CERTIFY = 0x02, /* since v2.0 */ KMIP_UNIQUE_ID_CREATE = 0x03, /* since v2.0 */ KMIP_UNIQUE_ID_CREATE_KEY_PAIR = 0x04, /* since v2.0 */ KMIP_UNIQUE_ID_CREATE_KEY_PAIR_PRIVATE = 0x05, /* since v2.0 */ KMIP_UNIQUE_ID_CREATE_KEY_PAIR_PUBLIC = 0x06, /* since v2.0 */ KMIP_UNIQUE_ID_CREATE_SPLIT_KEY = 0x07, /* since v2.0 */ KMIP_UNIQUE_ID_DERIVE_KEY = 0x08, /* since v2.0 */ KMIP_UNIQUE_ID_IMPORT = 0x09, /* since v2.0 */ KMIP_UNIQUE_ID_JOIN_SPLIT_KEY = 0x0A, /* since v2.0 */ KMIP_UNIQUE_ID_LOCATE = 0x0B, /* since v2.0 */ KMIP_UNIQUE_ID_REGISTER = 0x0C, /* since v2.0 */ KMIP_UNIQUE_ID_RE_KEY = 0x0D, /* since v2.0 */ KMIP_UNIQUE_ID_RE_CERTIFY = 0x0E, /* since v2.0 */ KMIP_UNIQUE_ID_RE_KEY_KEY_PAIR = 0x0F, /* since v2.0 */ KMIP_UNIQUE_ID_RE_KEY_KEY_PAIR_PRIVATE = 0x10, /* since v2.0 */ KMIP_UNIQUE_ID_RE_KEY_KEY_PAIR_PUBLIC = 0x11, /* since v2.0 */ }; enum kmip_object_type { KMIP_OBJECT_TYPE_CERTIFICATE = 0x01, KMIP_OBJECT_TYPE_SYMMETRIC_KEY = 0x02, KMIP_OBJECT_TYPE_PUBLIC_KEY = 0x03, KMIP_OBJECT_TYPE_PRIVATE_KEY = 0x04, KMIP_OBJECT_TYPE_SPLIT_KEY = 0x05, KMIP_OBJECT_TYPE_TEMPLATE = 0x06, /* v1.x only */ KMIP_OBJECT_TYPE_SECRET_DATA = 0x07, KMIP_OBJECT_TYPE_OPAQUE_OBJECT = 0x08, KMIP_OBJECT_TYPE_PGP_KEY = 0x09, /* since v1.2 */ KMIP_OBJECT_TYPE_CERTIFICATE_REQUEST = 0x0A, /* since v2.0 */ }; enum kmip_crypto_algo { KMIP_CRYPTO_ALGO_DES = 0x01, KMIP_CRYPTO_ALGO_3DES = 0x02, KMIP_CRYPTO_ALGO_AES = 0x03, KMIP_CRYPTO_ALGO_RSA = 0x04, KMIP_CRYPTO_ALGO_DSA = 0x05, KMIP_CRYPTO_ALGO_ECDSA = 0x06, KMIP_CRYPTO_ALGO_HMAC_SHA1 = 0x07, KMIP_CRYPTO_ALGO_HMAC_SHA224 = 0x08, KMIP_CRYPTO_ALGO_HMAC_SHA256 = 0x09, KMIP_CRYPTO_ALGO_HMAC_SHA384 = 0x0A, KMIP_CRYPTO_ALGO_HMAC_SHA512 = 0x0B, KMIP_CRYPTO_ALGO_HMAC_MD5 = 0x0C, KMIP_CRYPTO_ALGO_DH = 0x0D, KMIP_CRYPTO_ALGO_ECDH = 0x0E, KMIP_CRYPTO_ALGO_ECMQV = 0x0F, KMIP_CRYPTO_ALGO_BLOWFISH = 0x10, KMIP_CRYPTO_ALGO_CAMELLIA = 0x11, KMIP_CRYPTO_ALGO_CAST5 = 0x12, KMIP_CRYPTO_ALGO_IDEA = 0x13, KMIP_CRYPTO_ALGO_MARS = 0x14, KMIP_CRYPTO_ALGO_RC2 = 0x15, KMIP_CRYPTO_ALGO_RC4 = 0x16, KMIP_CRYPTO_ALGO_RC5 = 0x17, KMIP_CRYPTO_ALGO_SKIPJACK = 0x18, KMIP_CRYPTO_ALGO_TWOFISH = 0x19, KMIP_CRYPTO_ALGO_EC = 0x1A, /* since v1.2 */ KMIP_CRYPTO_ALGO_ONE_TIME_PAD = 0x1B, /* since v1.3 */ KMIP_CRYPTO_ALGO_CHACHA20 = 0x1C, /* since v1.4 */ KMIP_CRYPTO_ALGO_POLY1305 = 0x1D, /* since v1.4 */ KMIP_CRYPTO_ALGO_CHACHA20_POLY1305 = 0x1E, /* since v1.4 */ KMIP_CRYPTO_ALGO_SHA3_224 = 0x1F, /* since v1.4 */ KMIP_CRYPTO_ALGO_SHA3_256 = 0x20, /* since v1.4 */ KMIP_CRYPTO_ALGO_SHA3_384 = 0x21, /* since v1.4 */ KMIP_CRYPTO_ALGO_SHA3_512 = 0x22, /* since v1.4 */ KMIP_CRYPTO_ALGO_HMAC_SHA3_224 = 0x23, /* since v1.4 */ KMIP_CRYPTO_ALGO_HMAC_SHA3_256 = 0x24, /* since v1.4 */ KMIP_CRYPTO_ALGO_HMAC_SHA3_384 = 0x25, /* since v1.4 */ KMIP_CRYPTO_ALGO_HMAC_SHA3_512 = 0x26, /* since v1.4 */ KMIP_CRYPTO_ALGO_SHAKE_128 = 0x27, /* since v1.4 */ KMIP_CRYPTO_ALGO_SHAKE_256 = 0x28, /* since v1.4 */ KMIP_CRYPTO_ALGO_ARIA = 0x29, /* since v2.0 */ KMIP_CRYPTO_ALGO_SEED = 0x2A, /* since v2.0 */ KMIP_CRYPTO_ALGO_SM2 = 0x2B, /* since v2.0 */ KMIP_CRYPTO_ALGO_SM3 = 0x2C, /* since v2.0 */ KMIP_CRYPTO_ALGO_SM4 = 0x2D, /* since v2.0 */ KMIP_CRYPTO_ALGO_GOST_R34_10_2012 = 0x2E, /* since v2.0 */ KMIP_CRYPTO_ALGO_GOST_R34_11_2012 = 0x2F, /* since v2.0 */ KMIP_CRYPTO_ALGO_GOST_R34_13_2015 = 0x30, /* since v2.0 */ KMIP_CRYPTO_ALGO_GOST_28147_89 = 0x31, /* since v2.0 */ KMIP_CRYPTO_ALGO_XMSS = 0x32, /* since v2.0 */ KMIP_CRYPTO_ALGO_SPHINCS_256 = 0x33, /* since v2.0 */ KMIP_CRYPTO_ALGO_MCELIECE = 0x34, /* since v2.0 */ KMIP_CRYPTO_ALGO_MCELIECE_6960119 = 0x35, /* since v2.0 */ KMIP_CRYPTO_ALGO_MCELIECE_8192128 = 0x36, /* since v2.0 */ KMIP_CRYPTO_ALGO_ED25519 = 0x37, /* since v2.0 */ KMIP_CRYPTO_ALGO_ED448 = 0x38, /* since v2.0 */ }; enum kmip_certificate_type { KMIP_CERTIFICATE_TYPE_X_509 = 0x01, KMIP_CERTIFICATE_TYPE_PGP = 0x02, }; enum kmip_state { KMIP_STATE_PRE_ACTIVE = 0x01, KMIP_STATE_ACTIVE = 0x02, KMIP_STATE_DEACTIVATED = 0x03, KMIP_STATE_COMPROMISED = 0x04, KMIP_STATE_DESTROYED = 0x05, KMIP_STATE_DESTROYED_COMPROMISED = 0x06, }; enum kmip_protection_storage_mask { KMIP_PROT_STORAGE_MASK_SOFTWARE = 0x00000001, KMIP_PROT_STORAGE_MASK_HARDWARE = 0x00000002, KMIP_PROT_STORAGE_MASK_ON_PROCESSOR = 0x00000004, KMIP_PROT_STORAGE_MASK_ON_SYSTEM = 0x00000008, KMIP_PROT_STORAGE_MASK_OFF_SYSTEM = 0x00000010, KMIP_PROT_STORAGE_MASK_HYPERVISOR = 0x00000020, KMIP_PROT_STORAGE_MASK_OPERATING_SYSTEM = 0x00000040, KMIP_PROT_STORAGE_MASK_CONTAINER = 0x00000080, KMIP_PROT_STORAGE_MASK_ON_PREMISES = 0x00000100, KMIP_PROT_STORAGE_MASK_OFF_PREMISES = 0x00000200, KMIP_PROT_STORAGE_MASK_SELF_MANAGED = 0x00000400, KMIP_PROT_STORAGE_MASK_OUTSOURCED = 0x00000800, KMIP_PROT_STORAGE_MASK_VALIDATED = 0x00001000, KMIP_PROT_STORAGE_MASK_SAME_JURISDICATION = 0x00002000, }; enum kmip_revoke_reason { KMIP_REVOK_RSN_UNSPECIFIED = 0x01, KMIP_REVOK_RSN_KEY_COMPROMISE = 0x02, KMIP_REVOK_RSN_CA_COMPROMISE = 0x03, KMIP_REVOK_RSN_AFFILIATION_CHANGED = 0x04, KMIP_REVOK_RSN_SUPERSEDED = 0x05, KMIP_REVOK_RSN_CESSATION_OF_OPERATION = 0x06, KMIP_REVOK_RSN_PRIVILEGE_WITHDRAWN = 0x07, }; enum kmip_object_group_member { KMIP_OBJ_GROUP_MEMBER_FRESH = 0x01, KMIP_OBJ_GROUP_MEMBER_DEFAULT = 0x02, }; enum kmip_storage_status_mask { KMIP_STORAGE_STATUS_MASK_ONLINE = 0x01, KMIP_STORAGE_STATUS_MASK_ARCHIVAL = 0x02, KMIP_STORAGE_STATUS_MASK_DESTTROYED = 0x04, }; enum kmip_key_format_type { KMIP_KEY_FORMAT_TYPE_RAW = 0x01, KMIP_KEY_FORMAT_TYPE_OPAQUE = 0x02, KMIP_KEY_FORMAT_TYPE_PKCS_1 = 0x03, KMIP_KEY_FORMAT_TYPE_PKCS_8 = 0x04, KMIP_KEY_FORMAT_TYPE_X_509 = 0x05, KMIP_KEY_FORMAT_TYPE_EC_PRIVATE_KEY = 0x06, KMIP_KEY_FORMAT_TYPE_TRANSPARENT_SYMMETRIC_KEY = 0x07, KMIP_KEY_FORMAT_TYPE_TRANSPARENT_DSA_PRIVATE_KEY = 0x08, KMIP_KEY_FORMAT_TYPE_TRANSPARENT_DSA_PUBLIC_KEY = 0x09, KMIP_KEY_FORMAT_TYPE_TRANSPARENT_RSA_PRIVATE_KEY = 0x0A, KMIP_KEY_FORMAT_TYPE_TRANSPARENT_RSA_PUBLIC_KEY = 0x0B, KMIP_KEY_FORMAT_TYPE_TRANSPARENT_DH_PRIVATE_KEY = 0x0C, KMIP_KEY_FORMAT_TYPE_TRANSPARENT_DH_PUBLIC_KEY = 0x0D, KMIP_KEY_FORMAT_TYPE_TRANSPARENT_ECDSA_PRIVATE_KEY = 0x0E, /* deprecated since v1.3 */ KMIP_KEY_FORMAT_TYPE_TRANSPARENT_ECDSA_PUBLIC_KEY = 0x0F, /* deprecated since v1.3 */ KMIP_KEY_FORMAT_TYPE_TRANSPARENT_ECDH_PRIVATE_KEY = 0x10, /* deprecated since v1.3 */ KMIP_KEY_FORMAT_TYPE_TRANSPARENT_ECDH_PUBLIC_KEY = 0x11, /* deprecated since v1.3 */ KMIP_KEY_FORMAT_TYPE_TRANSPARENT_ECMQV_PRIVATE_KEY = 0x12, /* deprecated since v1.3 */ KMIP_KEY_FORMAT_TYPE_TRANSPARENT_ECMQV_PUBLIC_KEY = 0x13, /* deprecated since v1.3 */ KMIP_KEY_FORMAT_TYPE_TRANSPARENT_EC_PRIVATE_KEY = 0x14, /* since v1.3 */ KMIP_KEY_FORMAT_TYPE_TRANSPARENT_EC_PUBLIC_KEY = 0x15, /* since v1.3 */ KMIP_KEY_FORMAT_TYPE_PKCS_12 = 0x16, /* since v1.4 */ KMIP_KEY_FORMAT_TYPE_PKCS_10 = 0x17, /* since v2.0 */ }; enum kmip_key_compression_type { KMIP_KEY_COMPRESSION_TYPE_EC_PUBKEY_UNCOMPRESSED = 0x01, KMIP_KEY_COMPRESSION_TYPE_EC_PUBKEY_COMPRESSED_PRIME = 0x02, KMIP_KEY_COMPRESSION_TYPE_EC_PUBKEY_COMPRESSED_CHAR2 = 0x03, KMIP_KEY_COMPRESSION_TYPE_EC_PUBKEY_HYBID = 0x04, }; enum kmip_wrapping_method { KMIP_WRAPPING_METHOD_ENCRYPT = 0x01, KMIP_WRAPPING_METHOD_MAC_SIGN = 0x02, KMIP_WRAPPING_METHOD_ENCRYPT_THEN_MAC_SIGN = 0x03, KMIP_WRAPPING_METHOD_MAC_SIGN_THEN_ENCRYPT = 0x04, KMIP_WRAPPING_METHOD_TR_31 = 0x05, }; enum kmip_key_wrap_type { KMIP_KEY_WRAP_TYPE_NOT_WRAPPED = 0x01, KMIP_KEY_WRAP_TYPE_AS_REGISTERED = 0x02, }; enum kmip_block_cipher_mode { KMIP_BLOCK_CIPHER_MODE_CBC = 0x01, KMIP_BLOCK_CIPHER_MODE_ECB = 0x02, KMIP_BLOCK_CIPHER_MODE_PCBC = 0x03, KMIP_BLOCK_CIPHER_MODE_CFB = 0x04, KMIP_BLOCK_CIPHER_MODE_OFB = 0x05, KMIP_BLOCK_CIPHER_MODE_CTR = 0x06, KMIP_BLOCK_CIPHER_MODE_CMAC = 0x07, KMIP_BLOCK_CIPHER_MODE_CCM = 0x08, KMIP_BLOCK_CIPHER_MODE_GCM = 0x09, KMIP_BLOCK_CIPHER_MODE_CBC_MAC = 0x0A, KMIP_BLOCK_CIPHER_MODE_XTS = 0x0B, KMIP_BLOCK_CIPHER_MODE_AES_KEY_WRAP_PADDING = 0x0C, KMIP_BLOCK_CIPHER_MODE_NIST_KEY_WRAP = 0x0D, KMIP_BLOCK_CIPHER_MODE_X9_102_AESKW = 0x0E, KMIP_BLOCK_CIPHER_MODE_X9_102_TDKW = 0x0F, KMIP_BLOCK_CIPHER_MODE_X9_102_AKW1 = 0x10, KMIP_BLOCK_CIPHER_MODE_X9_102_AKW2 = 0x11, KMIP_BLOCK_CIPHER_MODE_AEAD = 0x12, /* since v1.4 */ }; enum kmip_padding_method { KMIP_PADDING_METHOD_NONE = 0x01, KMIP_PADDING_METHOD_OAEP = 0x02, KMIP_PADDING_METHOD_PKCS5 = 0x03, KMIP_PADDING_METHOD_SSL3 = 0x04, KMIP_PADDING_METHOD_ZEROS = 0x05, KMIP_PADDING_METHOD_ANSI_X9_23 = 0x06, KMIP_PADDING_METHOD_ISO_10126 = 0x07, KMIP_PADDING_METHOD_PKCS_1_5 = 0x08, KMIP_PADDING_METHOD_X9_31 = 0x09, KMIP_PADDING_METHOD_PSS = 0x0A, }; enum kmip_hashing_algo { KMIP_HASHING_ALGO_MD2 = 0x01, KMIP_HASHING_ALGO_MD4 = 0x02, KMIP_HASHING_ALGO_MD5 = 0x03, KMIP_HASHING_ALGO_SHA_1 = 0x04, KMIP_HASHING_ALGO_SHA_224 = 0x05, KMIP_HASHING_ALGO_SHA_256 = 0x06, KMIP_HASHING_ALGO_SHA_384 = 0x07, KMIP_HASHING_ALGO_SHA_512 = 0x08, KMIP_HASHING_ALGO_RIPEMD_160 = 0x09, KMIP_HASHING_ALGO_TIGER = 0x0A, KMIP_HASHING_ALGO_WIRLPOOL = 0x0B, KMIP_HASHING_ALGO_SHA_512_224 = 0x0C, /* since v1.2 */ KMIP_HASHING_ALGO_SHA_512_256 = 0x0D, /* since v1.2 */ KMIP_HASHING_ALGO_SHA_3_224 = 0x0E, /* since v1.4 */ KMIP_HASHING_ALGO_SHA_3_256 = 0x0F, /* since v1.4 */ KMIP_HASHING_ALGO_SHA_3_384 = 0x10, /* since v1.4 */ KMIP_HASHING_ALGO_SHA_3_512 = 0x11, /* since v1.4 */ }; enum kmip_key_role_type { KMIP_KEY_ROLE_TYPE_BDK = 0x01, KMIP_KEY_ROLE_TYPE_CVK = 0x02, KMIP_KEY_ROLE_TYPE_DEK = 0x03, KMIP_KEY_ROLE_TYPE_KMAC = 0x04, KMIP_KEY_ROLE_TYPE_MKSMC = 0x05, KMIP_KEY_ROLE_TYPE_MKSMI = 0x06, KMIP_KEY_ROLE_TYPE_MKDAC = 0x07, KMIP_KEY_ROLE_TYPE_MKDN = 0x08, KMIP_KEY_ROLE_TYPE_MKCP = 0x09, KMIP_KEY_ROLE_TYPE_MKOTH = 0x0A, KMIP_KEY_ROLE_TYPE_KEK = 0x0B, KMIP_KEY_ROLE_TYPE_MAC16609 = 0x0C, KMIP_KEY_ROLE_TYPE_MAC97971 = 0x0D, KMIP_KEY_ROLE_TYPE_MAC97972 = 0x0E, KMIP_KEY_ROLE_TYPE_MAC97973 = 0x0F, KMIP_KEY_ROLE_TYPE_MAC97974 = 0x10, KMIP_KEY_ROLE_TYPE_MAC97975 = 0x11, KMIP_KEY_ROLE_TYPE_ZPK = 0x12, KMIP_KEY_ROLE_TYPE_PVKIBM = 0x13, KMIP_KEY_ROLE_TYPE_PVKPVV = 0x14, KMIP_KEY_ROLE_TYPE_PVKOTH = 0x15, KMIP_KEY_ROLE_TYPE_DUKPT = 0x16, /* since v1.4 */ KMIP_KEY_ROLE_TYPE_IV = 0x17, /* since v1.4 */ KMIP_KEY_ROLE_TYPE_TRKBK = 0x18, /* since v1.4 */ }; enum kmip_signature_algo { KMIP_SIGNATURE_ALGO_MD2_WITH_RSA_ENCRYPTION = 0x01, /* since v1.2 */ KMIP_SIGNATURE_ALGO_MD5_WITH_RSA_ENCRYPTION = 0x02, /* since v1.2 */ KMIP_SIGNATURE_ALGO_SHA_1_WITH_RSA_ENCRYPTION = 0x03, /* since v1.2 */ KMIP_SIGNATURE_ALGO_SHA_224_WITH_RSA_ENCRYPTION = 0x04, /* since v1.2 */ KMIP_SIGNATURE_ALGO_SHA_256_WITH_RSA_ENCRYPTION = 0x05, /* since v1.2 */ KMIP_SIGNATURE_ALGO_SHA_384_WITH_RSA_ENCRYPTION = 0x06, /* since v1.2 */ KMIP_SIGNATURE_ALGO_SHA_512_WITH_RSA_ENCRYPTION = 0x07, /* since v1.2 */ KMIP_SIGNATURE_ALGO_RSASSA_PSS = 0x08, /* since v1.2 */ KMIP_SIGNATURE_ALGO_DSA_WITH_SHA_1 = 0x09, /* since v1.2 */ KMIP_SIGNATURE_ALGO_DSA_WITH_SHA_244 = 0x0A, /* since v1.2 */ KMIP_SIGNATURE_ALGO_DSA_WITH_SHA_256 = 0x0B, /* since v1.2 */ KMIP_SIGNATURE_ALGO_ECDSA_WITH_SHA_1 = 0x0C, /* since v1.2 */ KMIP_SIGNATURE_ALGO_ECDSA_WITH_SHA_224 = 0x0D, /* since v1.2 */ KMIP_SIGNATURE_ALGO_ECDSA_WITH_SHA_256 = 0x0E, /* since v1.2 */ KMIP_SIGNATURE_ALGO_ECDSA_WITH_SHA_384 = 0x0F, /* since v1.2 */ KMIP_SIGNATURE_ALGO_ECDSA_WITH_SHA_512 = 0x10, /* since v1.2 */ KMIP_SIGNATURE_ALGO_SHA3_256_WITH_RSA_ENCRYPTION = 0x11, /* since v1.4 */ KMIP_SIGNATURE_ALGO_SHA3_385_WITH_RSA_ENCRYPTION = 0x12, /* since v1.4 */ KMIP_SIGNATURE_ALGO_SHA3_512_WITH_RSA_ENCRYPTION = 0x13, /* since v1.4 */ }; enum kmip_mask_generator { KMIP_MASK_GENERATOR_MGF1 = 0x01, /* since v1.4 */ }; enum kmip_encoding_option { KMIP_ENCODING_OPTION_NO = 0x01, /* since v1.2 */ KMIP_ENCODING_OPTION_TTLV = 0x02, /* since v1.2 */ }; enum kmip_recommended_curve { KMIP_REC_CURVE_P_192 = 0x01, KMIP_REC_CURVE_K_163 = 0x02, KMIP_REC_CURVE_B_163 = 0x03, KMIP_REC_CURVE_P_224 = 0x04, KMIP_REC_CURVE_K_223 = 0x05, KMIP_REC_CURVE_B_223 = 0x06, KMIP_REC_CURVE_P_256 = 0x07, KMIP_REC_CURVE_K_283 = 0x08, KMIP_REC_CURVE_B_283 = 0x09, KMIP_REC_CURVE_P_384 = 0x0A, KMIP_REC_CURVE_K_409 = 0x0B, KMIP_REC_CURVE_B_409 = 0x0C, KMIP_REC_CURVE_P_521 = 0x0D, KMIP_REC_CURVE_K_571 = 0x0E, KMIP_REC_CURVE_B_571 = 0x0F, KMIP_REC_CURVE_SECP112R1 = 0x10, /* since v1.2 */ KMIP_REC_CURVE_SECP112R2 = 0x11, /* since v1.2 */ KMIP_REC_CURVE_SECP128R1 = 0x12, /* since v1.2 */ KMIP_REC_CURVE_SECP128R2 = 0x13, /* since v1.2 */ KMIP_REC_CURVE_SECP160K1 = 0x14, /* since v1.2 */ KMIP_REC_CURVE_SECP160R1 = 0x15, /* since v1.2 */ KMIP_REC_CURVE_SECP160R2 = 0x16, /* since v1.2 */ KMIP_REC_CURVE_SECP192K1 = 0x17, /* since v1.2 */ KMIP_REC_CURVE_SECP224K1 = 0x18, /* since v1.2 */ KMIP_REC_CURVE_SECP256K1 = 0x19, /* since v1.2 */ KMIP_REC_CURVE_SECT113R1 = 0x1A, /* since v1.2 */ KMIP_REC_CURVE_SECT113R2 = 0x1B, /* since v1.2 */ KMIP_REC_CURVE_SECT131R1 = 0x1C, /* since v1.2 */ KMIP_REC_CURVE_SECT131R2 = 0x1D, /* since v1.2 */ KMIP_REC_CURVE_SECT163R1 = 0x1E, /* since v1.2 */ KMIP_REC_CURVE_SECT193R1 = 0x1F, /* since v1.2 */ KMIP_REC_CURVE_SECT193R2 = 0x20, /* since v1.2 */ KMIP_REC_CURVE_SECT239K1 = 0x21, /* since v1.2 */ KMIP_REC_CURVE_ANSIX9P192V2 = 0x22, /* since v1.2 */ KMIP_REC_CURVE_ANSIX9P192V3 = 0x23, /* since v1.2 */ KMIP_REC_CURVE_ANSIX9P239V1 = 0x24, /* since v1.2 */ KMIP_REC_CURVE_ANSIX9P239V2 = 0x25, /* since v1.2 */ KMIP_REC_CURVE_ANSIX9P239V3 = 0x26, /* since v1.2 */ KMIP_REC_CURVE_ANSIX9C2PNB163V1 = 0x27, /* since v1.2 */ KMIP_REC_CURVE_ANSIX9C2PNB163V2 = 0x28, /* since v1.2 */ KMIP_REC_CURVE_ANSIX9C2PNB163V3 = 0x29, /* since v1.2 */ KMIP_REC_CURVE_ANSIX9C2PNB176V1 = 0x2A, /* since v1.2 */ KMIP_REC_CURVE_ANSIX9C2TNB191V1 = 0x2B, /* since v1.2 */ KMIP_REC_CURVE_ANSIX9C2TNB191V2 = 0x2C, /* since v1.2 */ KMIP_REC_CURVE_ANSIX9C2TNB191V3 = 0x2D, /* since v1.2 */ KMIP_REC_CURVE_ANSIX9C2PNB208W1 = 0x2E, /* since v1.2 */ KMIP_REC_CURVE_ANSIX9C2TNB239V1 = 0x2F, /* since v1.2 */ KMIP_REC_CURVE_ANSIX9C2TNB239V2 = 0x30, /* since v1.2 */ KMIP_REC_CURVE_ANSIX9C2TNB239V3 = 0x31, /* since v1.2 */ KMIP_REC_CURVE_ANSIX9C2PNB272W1 = 0x32, /* since v1.2 */ KMIP_REC_CURVE_ANSIX9C2PNB304W1 = 0x33, /* since v1.2 */ KMIP_REC_CURVE_ANSIX9C2TNB359V1 = 0x34, /* since v1.2 */ KMIP_REC_CURVE_ANSIX9C2PNB368W1 = 0x35, /* since v1.2 */ KMIP_REC_CURVE_ANSIX9C2TNB431R1 = 0x36, /* since v1.2 */ KMIP_REC_CURVE_BRAINPOOLP160R1 = 0x37, /* since v1.2 */ KMIP_REC_CURVE_BRAINPOOLP160T1 = 0x38, /* since v1.2 */ KMIP_REC_CURVE_BRAINPOOLP192R1 = 0x39, /* since v1.2 */ KMIP_REC_CURVE_BRAINPOOLP192T1 = 0x3A, /* since v1.2 */ KMIP_REC_CURVE_BRAINPOOLP224R1 = 0x3B, /* since v1.2 */ KMIP_REC_CURVE_BRAINPOOLP224T1 = 0x3C, /* since v1.2 */ KMIP_REC_CURVE_BRAINPOOLP256R1 = 0x3D, /* since v1.2 */ KMIP_REC_CURVE_BRAINPOOLP256T1 = 0x3E, /* since v1.2 */ KMIP_REC_CURVE_BRAINPOOLP320R1 = 0x3F, /* since v1.2 */ KMIP_REC_CURVE_BRAINPOOLP320T1 = 0x40, /* since v1.2 */ KMIP_REC_CURVE_BRAINPOOLP384R1 = 0x41, /* since v1.2 */ KMIP_REC_CURVE_BRAINPOOLP384T1 = 0x42, /* since v1.2 */ KMIP_REC_CURVE_BRAINPOOLP512R1 = 0x43, /* since v1.2 */ KMIP_REC_CURVE_BRAINPOOLP512T1 = 0x44, /* since v1.2 */ KMIP_REC_CURVE_CURVE25519 = 0x45, /* since v2.0 */ KMIP_REC_CURVE_CURVE448 = 0x46, /* since v2.0 */ }; enum kmip_protection_level { KMIP_PROTECTION_LEVEL_HIGH = 0x01, /* since v2.0 */ KMIP_PROTECTION_LEVEL_LOW = 0x02, /* since v2.0 */ }; enum kmip_key_value_location_type { KMIP_KEY_VAL_LOC_TYPE_UNINTERPRETED_TEXT_STRING = 0x01, KMIP_KEY_VAL_LOC_TYPE_URI = 0x02, }; enum kmip_link_type { KMIP_LINK_TYPE_CERTIFICATE = 0x0101, KMIP_LINK_TYPE_PUBLIC_KEY = 0x0102, KMIP_LINK_TYPE_PRIVATE_KEY = 0x0103, KMIP_LINK_TYPE_DERIVATION_BASE_OBJECT = 0x0104, KMIP_LINK_TYPE_DERIVED_KEY = 0x0105, KMIP_LINK_TYPE_REPLACEMENT_OBJECT = 0x0106, KMIP_LINK_TYPE_REPLACED_OBJECT = 0x0107, KMIP_LINK_TYPE_PARENT = 0x0108, /* since v1.2 */ KMIP_LINK_TYPE_CHILD = 0x0109, /* since v1.2 */ KMIP_LINK_TYPE_PREVIOUS = 0x010A, /* since v1.2 */ KMIP_LINK_TYPE_NEXT = 0x010B, /* since v1.2 */ KMIP_LINK_TYPE_PKCS_12_CERTIFICATE = 0x010C, /* since v1.4 */ KMIP_LINK_TYPE_PKCS_12_PASSWORD = 0x010D, /* since v1.4 */ KMIP_LINK_TYPE_WRAPPING_KEY = 0x010E, /* since v2.0 */ }; enum kmip_client_registration_method { KMIP_CLIENT_REG_METH_UNSPECIFIED = 0x01, /* since v1.3 */ KMIP_CLIENT_REG_METH_SERVER_PRE_GENERATED = 0x02, /* since v1.3 */ KMIP_CLIENT_REG_METH_SERVER_ON_DEMAND = 0x03, /* since v1.3 */ KMIP_CLIENT_REG_METH_CLIENT_GENERATED = 0x04, /* since v1.3 */ KMIP_CLIENT_REG_METH_CLIENT_REGISTERED = 0x05, /* since v1.3 */ }; enum kmip_rng_algorithm { KMIP_RNG_ALGO_UNSPECIFIED = 0x01, /* since v1.3 */ KMIP_RNG_ALGO_FIPS_186_2 = 0x02, /* since v1.3 */ KMIP_RNG_ALGO_DRBG = 0x03, /* since v1.3 */ KMIP_RNG_ALGO_NRBG = 0x04, /* since v1.3 */ KMIP_RNG_ALGO_ANSI_X9_31 = 0x05, /* since v1.3 */ KMIP_RNG_ALGO_ANSI_X9_62 = 0x06, /* since v1.3 */ }; enum kmip_drbg_algorithm { KMIP_DRBG_ALGO_UNSPECIFIED = 0x01, /* since v1.3 */ KMIP_DRBG_ALGO_DUAL_EC = 0x02, /* since v1.3 */ KMIP_DRBG_ALGO_HASH = 0x03, /* since v1.3 */ KMIP_DRBG_ALGO_HMAC = 0x04, /* since v1.3 */ KMIP_DRBG_ALGO_CTR = 0x05, /* since v1.3 */ }; enum kmip_fips186_variation { KMIP_FIPS186_VARI_UNSPECIFIED = 0x01, /* since v1.3 */ KMIP_FIPS186_VARI_GP_X_ORIGINAL = 0x02, /* since v1.3 */ KMIP_FIPS186_VARI_GP_X_CHANGE_NOTICE = 0x03, /* since v1.3 */ KMIP_FIPS186_VARI_X_ORIGINAL = 0x04, /* since v1.3 */ KMIP_FIPS186_VARI_X_CHANGE_NOTICE = 0x05, /* since v1.3 */ KMIP_FIPS186_VARI_K_ORIGINAL = 0x06, /* since v1.3 */ KMIP_FIPS186_VARI_K_CHANGE_NOTICE = 0x07, /* since v1.3 */ }; enum kmip_validation_authority_type { KMIP_VALIDATION_AUTH_TYPE_UNSPECIFIED = 0x01, /* since v1.3 */ KMIP_VALIDATION_AUTH_TYPE_NIST_CMVP = 0x02, /* since v1.3 */ KMIP_VALIDATION_AUTH_TYPE_COMMON_CRITERIA = 0x03, /* since v1.3 */ }; enum kmip_validation_type { KMIP_VALIDATION_TYPE_UNSPECIFIED = 0x01, /* since v1.3 */ KMIP_VALIDATION_TYPE_HARDWARE = 0x02, /* since v1.3 */ KMIP_VALIDATION_TYPE_SOFTWARE = 0x03, /* since v1.3 */ KMIP_VALIDATION_TYPE_FIRMWARE = 0x04, /* since v1.3 */ KMIP_VALIDATION_TYPE_HYBRID = 0x05, /* since v1.3 */ }; enum kmip_unwrap_mode { KMIP_UNWRAP_MODE_UNSPECIFIED = 0x01, /* since v1.3 */ KMIP_UNWRAP_MODE_PROCESSED = 0x02, /* since v1.3 */ KMIP_UNWRAP_MODE_NOT_PROCESSED = 0x03, /* since v1.3 */ }; enum kmip_destroy_action { KMIP_DESTROY_ACTION_UNSPECIFIED = 0x01, /* since v1.3 */ KMIP_DESTROY_ACTION_KEY_MATERIAL_DELETED = 0x02, /* since v1.3 */ KMIP_DESTROY_ACTION_KEY_MATERIAL_SHREDDED = 0x03, /* since v1.3 */ KMIP_DESTROY_ACTION_META_DATA_DELETED = 0x04, /* since v1.3 */ KMIP_DESTROY_ACTION_META_DATA_SHREDDED = 0x05, /* since v1.3 */ KMIP_DESTROY_ACTION_DELETED = 0x06, /* since v1.3 */ KMIP_DESTROY_ACTION_SHREDDED = 0x07, /* since v1.3 */ }; enum kmip_shredding_algorithm { KMIP_SHREDDING_ALGO_UNSPECIFIED = 0x01, /* since v1.3 */ KMIP_SHREDDING_ALGO_CRYPTOGRAPHIC = 0x02, /* since v1.3 */ KMIP_SHREDDING_ALGO_UNSUPPORTED = 0x03, /* since v1.3 */ }; enum kmip_rng_mode { KMIP_RNG_MODE_UNSPECIFIED = 0x01, /* since v1.3 */ KMIP_RNG_MODE_SHARED_INSTANTIATION = 0x02, /* since v1.3 */ KMIP_RNG_MODE_NON_SHARED_INSTANCIATION = 0x03, /* since v1.3 */ }; enum kmip_KMIP_PROFILE_s { KMIP_PROFILE_BASELINE_SERVER_BASIC_KMIP_V1_2 = 0x0001, KMIP_PROFILE_BASELINE_SERVER_TLS_V1_2_KMIP_V1_2 = 0x0002, KMIP_PROFILE_BASELINE_CLIENT_BASIC_KMIP_V1_2 = 0x0003, KMIP_PROFILE_BASELINE_CLIENT_TLS_V1_2_KMIP_V1_2 = 0x0004, KMIP_PROFILE_COMPLETE_SERVER_BASIC_KMIP_V1_2 = 0x0005, KMIP_PROFILE_COMPLETE_SERVER_TLS_V1_2_KMIP_V1_2 = 0x0006, KMIP_PROFILE_TAPE_LIBRARY_CLIENT_KMIP_V1_0 = 0x0007, KMIP_PROFILE_TAPE_LIBRARY_CLIENT_KMIP_V1_1 = 0x0008, KMIP_PROFILE_TAPE_LIBRARY_CLIENT_KMIP_V1_2 = 0x0009, KMIP_PROFILE_TAPE_LIBRARY_SERVER_KMIP_V1_0 = 0x000A, KMIP_PROFILE_TAPE_LIBRARY_SERVER_KMIP_V1_1 = 0x000B, KMIP_PROFILE_TAPE_LIBRARY_SERVER_KMIP_V1_2 = 0x000C, KMIP_PROFILE_SYMMETRIC_KEY_LIFECYCLE_CLIENT_KMIP_V1_0 = 0x000D, KMIP_PROFILE_SYMMETRIC_KEY_LIFECYCLE_CLIENT_KMIP_V1_1 = 0x000E, KMIP_PROFILE_SYMMETRIC_KEY_LIFECYCLE_CLIENT_KMIP_V1_2 = 0x000F, KMIP_PROFILE_SYMMETRIC_KEY_LIFECYCLE_SERVER_KMIP_V1_0 = 0x0010, KMIP_PROFILE_SYMMETRIC_KEY_LIFECYCLE_SERVER_KMIP_V1_1 = 0x0011, KMIP_PROFILE_SYMMETRIC_KEY_LIFECYCLE_SERVER_KMIP_V1_2 = 0x0012, KMIP_PROFILE_ASYMMETRIC_KEY_LIFECYCLE_CLIENT_KMIP_V1_0 = 0x0013, KMIP_PROFILE_ASYMMETRIC_KEY_LIFECYCLE_CLIENT_KMIP_V1_1 = 0x0014, KMIP_PROFILE_ASYMMETRIC_KEY_LIFECYCLE_CLIENT_KMIP_V1_2 = 0x0015, KMIP_PROFILE_ASYMMETRIC_KEY_LIFECYCLE_SERVER_KMIP_V1_0 = 0x0016, KMIP_PROFILE_ASYMMETRIC_KEY_LIFECYCLE_SERVER_KMIP_V1_1 = 0x0017, KMIP_PROFILE_ASYMMETRIC_KEY_LIFECYCLE_SERVER_KMIP_V1_2 = 0x0018, KMIP_PROFILE_BASIC_CRYPTOGRAPHIC_CLIENT_KMIP_V1_2 = 0x0019, KMIP_PROFILE_BASIC_CRYPTOGRAPHIC_SERVER_KMIP_V1_2 = 0x001A, KMIP_PROFILE_ADVANCED_CRYPTOGRAPHIC_CLIENT_KMIP_V1_2 = 0x001B, KMIP_PROFILE_ADVANCED_CRYPTOGRAPHIC_SERVER_KMIP_V1_2 = 0x001C, KMIP_PROFILE_RNG_CRYPTOGRAPHIC_CLIENT_KMIP_V1_2 = 0x001D, KMIP_PROFILE_RNG_CRYPTOGRAPHIC_SERVER_KMIP_V1_2 = 0x001E, KMIP_PROFILE_BASIC_SYMMETRIC_KEY_FOUNDRY_CLIENT_KMIP_V1_0 = 0x001F, KMIP_PROFILE_INTERMEDIATE_SYMMETRIC_KEY_FOUNDRY_CLIENT_KMIP_V1_0 = 0x0020, KMIP_PROFILE_ADVANCED_SYMMETRIC_KEY_FOUNDRY_CLIENT_KMIP_V1_0 = 0x0021, KMIP_PROFILE_BASIC_SYMMETRIC_KEY_FOUNDRY_CLIENT_KMIP_V1_1 = 0x0022, KMIP_PROFILE_INTERMEDIATE_SYMMETRIC_KEY_FOUNDRY_CLIENT_KMIP_V1_1 = 0x0023, KMIP_PROFILE_ADVANCED_SYMMETRIC_KEY_FOUNDRY_CLIENT_KMIP_V1_1 = 0x0024, KMIP_PROFILE_BASIC_SYMMETRIC_KEY_FOUNDRY_CLIENT_KMIP_V1_2 = 0x0025, KMIP_PROFILE_INTERMEDIATE_SYMMETRIC_KEY_FOUNDRY_CLIENT_KMIP_V1_2 = 0x0026, KMIP_PROFILE_ADVANCED_SYMMETRIC_KEY_FOUNDRY_CLIENT_KMIP_V1_2 = 0x0027, KMIP_PROFILE_SYMMETRIC_KEY_FOUNDRY_SERVER_KMIP_V1_0 = 0x0028, KMIP_PROFILE_SYMMETRIC_KEY_FOUNDRY_SERVER_KMIP_V1_1 = 0x0029, KMIP_PROFILE_SYMMETRIC_KEY_FOUNDRY_SERVER_KMIP_V1_2 = 0x002A, KMIP_PROFILE_OPAQUE_MANAGED_OBJECT_STORE_CLIENT_KMIP_V1_0 = 0x002B, KMIP_PROFILE_OPAQUE_MANAGED_OBJECT_STORE_CLIENT_KMIP_V1_1 = 0x002C, KMIP_PROFILE_OPAQUE_MANAGED_OBJECT_STORE_CLIENT_KMIP_V1_2 = 0x002D, KMIP_PROFILE_OPAQUE_MANAGED_OBJECT_STORE_SERVER_KMIP_V1_0 = 0x002E, KMIP_PROFILE_OPAQUE_MANAGED_OBJECT_STORE_SERVER_KMIP_V1_1 = 0x002F, KMIP_PROFILE_OPAQUE_MANAGED_OBJECT_STORE_SERVER_KMIP_V1_2 = 0x0030, KMIP_PROFILE_SUITE_B_MINLOS_128_CLIENT_KMIP_V1_0 = 0x0031, KMIP_PROFILE_SUITE_B_MINLOS_128_CLIENT_KMIP_V1_1 = 0x0032, KMIP_PROFILE_SUITE_B_MINLOS_128_CLIENT_KMIP_V1_2 = 0x0033, KMIP_PROFILE_SUITE_B_MINLOS_128_SERVER_KMIP_V1_0 = 0x0034, KMIP_PROFILE_SUITE_B_MINLOS_128_SERVER_KMIP_V1_1 = 0x0035, KMIP_PROFILE_SUITE_B_MINLOS_128_SERVER_KMIP_V1_2 = 0x0036, KMIP_PROFILE_SUITE_B_MINLOS_192_CLIENT_KMIP_V1_0 = 0x0037, KMIP_PROFILE_SUITE_B_MINLOS_192_CLIENT_KMIP_V1_1 = 0x0038, KMIP_PROFILE_SUITE_B_MINLOS_192_CLIENT_KMIP_V1_2 = 0x0039, KMIP_PROFILE_SUITE_B_MINLOS_192_SERVER_KMIP_V1_0 = 0x003A, KMIP_PROFILE_SUITE_B_MINLOS_192_SERVER_KMIP_V1_1 = 0x003B, KMIP_PROFILE_SUITE_B_MINLOS_192_SERVER_KMIP_V1_2 = 0x003C, KMIP_PROFILE_STORAGE_ARRAY_WITH_SELF_ENCRYPTING_DRIVE_CLIENT_KMIP_V1_0 = 0x003D, KMIP_PROFILE_STORAGE_ARRAY_WITH_SELF_ENCRYPTING_DRIVE_CLIENT_KMIP_V1_1 = 0x003E, KMIP_PROFILE_STORAGE_ARRAY_WITH_SELF_ENCRYPTING_DRIVE_CLIENT_KMIP_V1_2 = 0x003F, KMIP_PROFILE_STORAGE_ARRAY_WITH_SELF_ENCRYPTING_DRIVE_SERVER_KMIP_V1_0 = 0x0040, KMIP_PROFILE_STORAGE_ARRAY_WITH_SELF_ENCRYPTING_DRIVE_SERVER_KMIP_V1_1 = 0x0041, KMIP_PROFILE_STORAGE_ARRAY_WITH_SELF_ENCRYPTING_DRIVE_SERVER_KMIP_V1_2 = 0x0042, KMIP_PROFILE_HTTPS_CLIENT_KMIP_V1_0 = 0x0043, KMIP_PROFILE_HTTPS_CLIENT_KMIP_V1_1 = 0x0044, KMIP_PROFILE_HTTPS_CLIENT_KMIP_V1_2 = 0x0045, KMIP_PROFILE_HTTPS_SERVER_KMIP_V1_0 = 0x0046, KMIP_PROFILE_HTTPS_SERVER_KMIP_V1_1 = 0x0047, KMIP_PROFILE_HTTPS_SERVER_KMIP_V1_2 = 0x0048, KMIP_PROFILE_JSON_CLIENT_KMIP_V1_0 = 0x0049, KMIP_PROFILE_JSON_CLIENT_KMIP_V1_1 = 0x004A, KMIP_PROFILE_JSON_CLIENT_KMIP_V1_2 = 0x004B, KMIP_PROFILE_JSON_SERVER_KMIP_V1_0 = 0x004C, KMIP_PROFILE_JSON_SERVER_KMIP_V1_1 = 0x004D, KMIP_PROFILE_JSON_SERVER_KMIP_V1_2 = 0x004E, KMIP_PROFILE_XML_CLIENT_KMIP_V1_0 = 0x004F, KMIP_PROFILE_XML_CLIENT_KMIP_V1_1 = 0x0050, KMIP_PROFILE_XML_CLIENT_KMIP_V1_2 = 0x0051, KMIP_PROFILE_XML_SERVER_KMIP_V1_0 = 0x0052, KMIP_PROFILE_XML_SERVER_KMIP_V1_1 = 0x0053, KMIP_PROFILE_XML_SERVER_KMIP_V1_2 = 0x0054, KMIP_PROFILE_BASELINE_SERVER_BASIC_KMIP_V1_3 = 0x0055, KMIP_PROFILE_BASELINE_SERVER_TLS_V1_2_KMIP_V1_3 = 0x0056, KMIP_PROFILE_BASELINE_CLIENT_BASIC_KMIP_V1_3 = 0x0057, KMIP_PROFILE_BASELINE_CLIENT_TLS_V1_2_KMIP_V1_3 = 0x0058, KMIP_PROFILE_COMPLETE_SERVER_BASIC_KMIP_V1_3 = 0x0059, KMIP_PROFILE_COMPLETE_SERVER_TLS_V1_2_KMIP_V1_3 = 0x005A, KMIP_PROFILE_TAPE_LIBRARY_CLIENT_KMIP_V1_3 = 0x005B, KMIP_PROFILE_TAPE_LIBRARY_SERVER_KMIP_V1_3 = 0x005C, KMIP_PROFILE_SYMMETRIC_KEY_LIFECYCLE_CLIENT_KMIP_V1_3 = 0x005D, KMIP_PROFILE_SYMMETRIC_KEY_LIFECYCLE_SERVER_KMIP_V1_3 = 0x005E, KMIP_PROFILE_ASYMMETRIC_KEY_LIFECYCLE_CLIENT_KMIP_V1_3 = 0x005F, KMIP_PROFILE_ASYMMETRIC_KEY_LIFECYCLE_SERVER_KMIP_V1_3 = 0x0060, KMIP_PROFILE_BASIC_CRYPTOGRAPHIC_CLIENT_KMIP_V1_3 = 0x0061, KMIP_PROFILE_BASIC_CRYPTOGRAPHIC_SERVER_KMIP_V1_3 = 0x0062, KMIP_PROFILE_ADVANCED_CRYPTOGRAPHIC_CLIENT_KMIP_V1_3 = 0x0063, KMIP_PROFILE_ADVANCED_CRYPTOGRAPHIC_SERVER_KMIP_V1_3 = 0x0064, KMIP_PROFILE_RNG_CRYPTOGRAPHIC_CLIENT_KMIP_V1_3 = 0x0065, KMIP_PROFILE_RNG_CRYPTOGRAPHIC_SERVER_KMIP_V1_3 = 0x0066, KMIP_PROFILE_BASIC_SYMMETRIC_KEY_FOUNDRY_CLIENT_KMIP_V1_3 = 0x0067, KMIP_PROFILE_INTERMEDIATE_SYMMETRIC_KEY_FOUNDRY_CLIENT_KMIP_V1_3 = 0x0068, KMIP_PROFILE_ADVANCED_SYMMETRIC_KEY_FOUNDRY_CLIENT_KMIP_V1_3 = 0x0069, KMIP_PROFILE_SYMMETRIC_KEY_FOUNDRY_SERVER_KMIP_V1_3 = 0x006A, KMIP_PROFILE_OPAQUE_MANAGED_OBJECT_STORE_CLIENT_KMIP_V1_3 = 0x006B, KMIP_PROFILE_OPAQUE_MANAGED_OBJECT_STORE_SERVER_KMIP_V1_3 = 0x006C, KMIP_PROFILE_SUITE_B_MINLOS_128_CLIENT_KMIP_V1_3 = 0x006D, KMIP_PROFILE_SUITE_B_MINLOS_128_SERVER_KMIP_V1_3 = 0x006E, KMIP_PROFILE_SUITE_B_MINLOS_192_CLIENT_KMIP_V1_3 = 0x006F, KMIP_PROFILE_SUITE_B_MINLOS_192_SERVER_KMIP_V1_3 = 0x0070, KMIP_PROFILE_STORAGE_ARRAY_WITH_SELF_ENCRYPTING_DRIVE_CLIENT_KMIP_V1_3 = 0x0071, KMIP_PROFILE_STORAGE_ARRAY_WITH_SELF_ENCRYPTING_DRIVE_SERVER_KMIP_V1_3 = 0x0072, KMIP_PROFILE_HTTPS_CLIENT_KMIP_V1_3 = 0x0073, KMIP_PROFILE_HTTPS_SERVER_KMIP_V1_3 = 0x0074, KMIP_PROFILE_JSON_CLIENT_KMIP_V1_3 = 0x0075, KMIP_PROFILE_JSON_SERVER_KMIP_V1_3 = 0x0076, KMIP_PROFILE_XML_CLIENT_KMIP_V1_3 = 0x0077, KMIP_PROFILE_XML_SERVER_KMIP_V1_3 = 0x0078, KMIP_PROFILE_BASELINE_SERVER_BASIC_KMIP_V1_4 = 0x0079, KMIP_PROFILE_BASELINE_SERVER_TLS_V1_2_KMIP_V1_4 = 0x007A, KMIP_PROFILE_BASELINE_CLIENT_BASIC_KMIP_V1_4 = 0x007B, KMIP_PROFILE_BASELINE_CLIENT_TLS_V1_2_KMIP_V1_4 = 0x007C, KMIP_PROFILE_COMPLETE_SERVER_BASIC_KMIP_V1_4 = 0x007D, KMIP_PROFILE_COMPLETE_SERVER_TLS_V1_2_KMIP_V1_4 = 0x007E, KMIP_PROFILE_TAPE_LIBRARY_CLIENT_KMIP_V1_4 = 0x007F, KMIP_PROFILE_TAPE_LIBRARY_SERVER_KMIP_V1_4 = 0x0080, KMIP_PROFILE_SYMMETRIC_KEY_LIFECYCLE_CLIENT_KMIP_V1_4 = 0x0081, KMIP_PROFILE_SYMMETRIC_KEY_LIFECYCLE_SERVER_KMIP_V1_4 = 0x0082, KMIP_PROFILE_ASYMMETRIC_KEY_LIFECYCLE_CLIENT_KMIP_V1_4 = 0x0083, KMIP_PROFILE_ASYMMETRIC_KEY_LIFECYCLE_SERVER_KMIP_V1_4 = 0x0084, KMIP_PROFILE_BASIC_CRYPTOGRAPHIC_CLIENT_KMIP_V1_4 = 0x0085, KMIP_PROFILE_BASIC_CRYPTOGRAPHIC_SERVER_KMIP_V1_4 = 0x0086, KMIP_PROFILE_ADVANCED_CRYPTOGRAPHIC_CLIENT_KMIP_V1_4 = 0x0087, KMIP_PROFILE_ADVANCED_CRYPTOGRAPHIC_SERVER_KMIP_V1_4 = 0x0088, KMIP_PROFILE_RNG_CRYPTOGRAPHIC_CLIENT_KMIP_V1_4 = 0x0089, KMIP_PROFILE_RNG_CRYPTOGRAPHIC_SERVER_KMIP_V1_4 = 0x008A, KMIP_PROFILE_BASIC_SYMMETRIC_KEY_FOUNDRY_CLIENT_KMIP_V1_4 = 0x008B, KMIP_PROFILE_INTERMEDIATE_SYMMETRIC_KEY_FOUNDRY_CLIENT_KMIP_V1_4 = 0x008C, KMIP_PROFILE_ADVANCED_SYMMETRIC_KEY_FOUNDRY_CLIENT_KMIP_V1_4 = 0x008D, KMIP_PROFILE_SYMMETRIC_KEY_FOUNDRY_SERVER_KMIP_V1_4 = 0x008E, KMIP_PROFILE_OPAQUE_MANAGED_OBJECT_STORE_CLIENT_KMIP_V1_4 = 0x008F, KMIP_PROFILE_OPAQUE_MANAGED_OBJECT_STORE_SERVER_KMIP_V1_4 = 0x0090, KMIP_PROFILE_SUITE_B_MINLOS_128_CLIENT_KMIP_V1_4 = 0x0091, KMIP_PROFILE_SUITE_B_MINLOS_128_SERVER_KMIP_V1_4 = 0x0092, KMIP_PROFILE_SUITE_B_MINLOS_192_CLIENT_KMIP_V1_4 = 0x0093, KMIP_PROFILE_SUITE_B_MINLOS_192_SERVER_KMIP_V1_4 = 0x0094, KMIP_PROFILE_STORAGE_ARRAY_WITH_SELF_ENCRYPTING_DRIVE_CLIENT_KMIP_V1_4 = 0x0095, KMIP_PROFILE_STORAGE_ARRAY_WITH_SELF_ENCRYPTING_DRIVE_SERVER_KMIP_V1_4 = 0x0096, KMIP_PROFILE_HTTPS_CLIENT_KMIP_V1_4 = 0x0097, KMIP_PROFILE_HTTPS_SERVER_KMIP_V1_4 = 0x0098, KMIP_PROFILE_JSON_CLIENT_KMIP_V1_4 = 0x0099, KMIP_PROFILE_JSON_SERVER_KMIP_V1_4 = 0x009A, KMIP_PROFILE_XML_CLIENT_KMIP_V1_4 = 0x009B, KMIP_PROFILE_XML_SERVER_KMIP_V1_4 = 0x009C, KMIP_PROFILE_COMPLETE_SERVER_BASIC = 0x0104, KMIP_PROFILE_COMPLETE_SERVER_TLS_V1_2 = 0x0105, KMIP_PROFILE_TAPE_LIBRARY_CLIENT = 0x0106, KMIP_PROFILE_TAPE_LIBRARY_SERVER = 0x0107, KMIP_PROFILE_SYMMETRIC_KEY_LIFECYCLE_CLIENT = 0x0108, KMIP_PROFILE_SYMMETRIC_KEY_LIFECYCLE_SERVER = 0x0109, KMIP_PROFILE_ASYMMETRIC_KEY_LIFECYCLE_CLIENT = 0x010A, KMIP_PROFILE_ASYMMETRIC_KEY_LIFECYCLE_SERVER = 0x010B, KMIP_PROFILE_BASIC_CRYPTOGRAPHIC_CLIENT = 0x010C, KMIP_PROFILE_BASIC_CRYPTOGRAPHIC_SERVER = 0x010D, KMIP_PROFILE_ADVANCED_CRYPTOGRAPHIC_CLIENT = 0x010E, KMIP_PROFILE_ADVANCED_CRYPTOGRAPHIC_SERVER = 0x010F, KMIP_PROFILE_RNG_CRYPTOGRAPHIC_CLIENT = 0x0110, KMIP_PROFILE_RNG_CRYPTOGRAPHIC_SERVER = 0x0111, KMIP_PROFILE_BASIC_SYMMETRIC_KEY_FOUNDRY_CLIENT = 0x0112, KMIP_PROFILE_INTERMEDIATE_SYMMETRIC_KEY_FOUNDRY_CLIENT = 0x0113, KMIP_PROFILE_ADVANCED_SYMMETRIC_KEY_FOUNDRY_CLIENT = 0x0114, KMIP_PROFILE_SYMMETRIC_KEY_FOUNDRY_SERVER = 0x0115, KMIP_PROFILE_OPAQUE_MANAGED_OBJECT_STORE_CLIENT = 0x0116, KMIP_PROFILE_OPAQUE_MANAGED_OBJECT_STORE_SERVER = 0x0117, KMIP_PROFILE_STORAGE_ARRAY_WITH_SELF_ENCRYPTING_DRIVE_CLIENT = 0x011C, KMIP_PROFILE_STORAGE_ARRAY_WITH_SELF_ENCRYPTING_DRIVE_SERVER = 0x011D, KMIP_PROFILE_HTTPS_CLIENT = 0x011E, KMIP_PROFILE_HTTPS_SERVER = 0x011F, KMIP_PROFILE_JSON_CLIENT = 0x0120, KMIP_PROFILE_JSON_SERVER = 0x0121, KMIP_PROFILE_XML_CLIENT = 0x0122, KMIP_PROFILE_XML_SERVER = 0x0123, KMIP_PROFILE_AES_XTS_CLIENT = 0x0124, KMIP_PROFILE_AES_XTS_SERVER = 0x0125, KMIP_PROFILE_QUANTUM_SAFE_CLIENT = 0x0126, KMIP_PROFILE_QUANTUM_SAFE_SERVER = 0x0127, KMIP_PROFILE_PKCS_11_CLIENT = 0x0128, KMIP_PROFILE_PKCS_11_SERVER = 0x0129, KMIP_PROFILE_BASELINE_CLIENT = 0x012A, KMIP_PROFILE_BASELINE_SERVER = 0x012B, KMIP_PROFILE_COMPLETE_SERVER = 0x012C, }; struct kmip_version { int32_t major; int32_t minor; }; enum kmip_encoding { KMIP_ENCODING_TTLV = 1, #ifdef HAVE_LIBCURL #ifdef HAVE_LIBJSONC KMIP_ENCODING_JSON = 2, /* Only via HTTPS transport */ #endif #ifdef HAVE_LIBXML2 KMIP_ENCODING_XML = 3, /* Only via HTTPS transport */ #endif #endif }; enum kmip_transport { KMIP_TRANSPORT_PLAIN_TLS = 1, #ifdef HAVE_LIBCURL KMIP_TRANSPORT_HTTPS = 2, #endif }; #define KMIP_DEFAULT_PLAIN_TLS_PORT "5696" #define KMIP_DEFAULT_PLAIN_TLS_PORT_NUM 5696 #ifdef HAVE_LIBCURL #define KMIP_DEFAULT_HTTPS_PORT "5696" #define KMIP_DEFAULT_HTTPS_PORT_NUM 5696 #endif struct kmip_conn_config { /** Encoding used for the KMIP messages */ enum kmip_encoding encoding; /** Transport method used to deliver KMIP messages */ enum kmip_transport transport; /** * The KMIP server. * For Plain-TLS transport, only the hostname and optional port number. * For HTTPS transport, an URL in the form * 'https://hostname[:port]/uri' */ const char *server; /** The client key as an OpenSSL PKEY object. */ EVP_PKEY *tls_client_key; /** File name of the client certificate PEM file */ const char *tls_client_cert; /** * Optional: File name of the CA bundle PEM file, or a name of a * directory the multiple CA certificates. If this is NULL, then the * default system path for CA certificates is used */ const char *tls_ca; /** * Optional: File name of a PEM file holding a CA certificate of the * issuer */ const char *tls_issuer_cert; /** * Optional: File name of a PEM file containing the servers pinned * public key. Public key pinning requires that verify_peer or * verify_host (or both) is true. */ const char *tls_pinned_pubkey; /** * Optional: File name of a PEM file containing the server's * certificate. This can be used to allow peer verification with * self-signed server certificates */ const char *tls_server_cert; /** If true, the peer certificate is verified */ bool tls_verify_peer; /** * If true, that the server certificate is for the server it is known * as (i.e. the hostname in the url) */ bool tls_verify_host; /** * Optional: A list of ciphers for TLSv1.2 and below. This is a colon * separated list of cipher strings. The format of the string is * described in * https://www.openssl.org/docs/man1.1.1/man1/ciphers.html */ const char *tls_cipher_list; /** * Optional: A list of ciphers for TLSv1.3. This is a colon separated * list of TLSv1.3 ciphersuite names in order of preference. Valid * TLSv1.3 ciphersuite names are: * - TLS_AES_128_GCM_SHA256 * - TLS_AES_256_GCM_SHA384 * - TLS_CHACHA20_POLY1305_SHA256 * - TLS_AES_128_CCM_SHA256 * - TLS_AES_128_CCM_8_SHA256 */ const char *tls13_cipher_list; }; /* Opaque KMIP node and connection structures */ struct kmip_connection; struct kmip_node; /* Generic KMIP node constructors/destructors and getters */ struct kmip_node *kmip_node_clone(const struct kmip_node *node); void kmip_node_upref(struct kmip_node *node); void kmip_node_free(struct kmip_node *node); enum kmip_tag kmip_node_get_tag(const struct kmip_node *node); enum kmip_type kmip_node_get_type(const struct kmip_node *node); char *kmip_node_get_name(const struct kmip_node *node); void kmip_node_dump(struct kmip_node *node, bool debug); struct kmip_node *kmip_node_new_structure(enum kmip_tag tag, const char *name, unsigned int num_elements, struct kmip_node **elements); struct kmip_node *kmip_node_new_structure_va(enum kmip_tag tag, const char *name, unsigned int num_elements, ...); unsigned int kmip_node_get_structure_element_count( const struct kmip_node *node); struct kmip_node *kmip_node_get_structure_element_by_index( const struct kmip_node *node, unsigned int index); unsigned int kmip_node_get_structure_element_by_tag_count( const struct kmip_node *node, enum kmip_tag tag); struct kmip_node *kmip_node_get_structure_element_by_tag( const struct kmip_node *node, enum kmip_tag tag, unsigned int index); int kmip_node_add_structure_element(struct kmip_node *node, struct kmip_node *element); int kmip_node_add_structure_elements(struct kmip_node *node, unsigned int num_elements, struct kmip_node **elements); struct kmip_node *kmip_node_new_integer(enum kmip_tag tag, const char *name, int32_t value); int32_t kmip_node_get_integer(const struct kmip_node *node); struct kmip_node *kmip_node_new_long(enum kmip_tag tag, const char *name, int64_t value); int64_t kmip_node_get_long(const struct kmip_node *node); struct kmip_node *kmip_node_new_bigint(enum kmip_tag tag, const char *name, const BIGNUM *value); const BIGNUM *kmip_node_get_bigint(const struct kmip_node *node); struct kmip_node *kmip_node_new_enumeration(enum kmip_tag tag, const char *name, uint32_t enumeration); uint32_t kmip_node_get_enumeration(const struct kmip_node *node); struct kmip_node *kmip_node_new_boolean(enum kmip_tag tag, const char *name, bool value); bool kmip_node_get_boolean(const struct kmip_node *node); struct kmip_node *kmip_node_new_text_string(enum kmip_tag tag, const char *name, const char *value); const char *kmip_node_get_text_string(const struct kmip_node *node); struct kmip_node *kmip_node_new_byte_string(enum kmip_tag tag, const char *name, const unsigned char *value, uint32_t length); const unsigned char *kmip_node_get_byte_string(const struct kmip_node *node, uint32_t *length); struct kmip_node *kmip_node_new_date_time(enum kmip_tag tag, const char *name, int64_t value); int64_t kmip_node_get_date_time(const struct kmip_node *node); struct kmip_node *kmip_node_new_interval(enum kmip_tag tag, const char *name, uint32_t value); uint32_t kmip_node_get_interval(const struct kmip_node *node); struct kmip_node *kmip_node_new_date_time_ext(enum kmip_tag tag, const char *name, int64_t value); int64_t kmip_node_get_date_time_ext(const struct kmip_node *node); /* Generic functions */ void kmip_set_default_protocol_version(const struct kmip_version *version); const struct kmip_version *kmip_get_default_protocol_version(void); /* Request related functions */ struct kmip_node *kmip_new_protocol_version(const struct kmip_version *version); struct kmip_node *kmip_new_profile_version(const struct kmip_version *version); struct kmip_node *kmip_new_request_header(const struct kmip_version *version, int32_t max_response_size, const char *client_corr_value, const char *server_corr_value, bool asynchronous, struct kmip_node *authentication, enum kmip_batch_error_cont_option batch_err_opt, bool batch_order_option, int32_t batch_count); struct kmip_node *kmip_new_request_batch_item(enum kmip_operation operation, unsigned char *batch_id, uint32_t batch_id_length, struct kmip_node *payload); struct kmip_node *kmip_new_request(struct kmip_node *request_header, int32_t batch_count, struct kmip_node **batch_items); struct kmip_node *kmip_new_request_va(struct kmip_node *request_header, int32_t batch_count, ...); struct kmip_node *kmip_new_query_request_payload(unsigned int query_count, const enum kmip_query_function *functions); struct kmip_node *kmip_new_query_request_payload_va(unsigned int query_count, ...); struct kmip_node *kmip_new_discover_versions_payload(int version_count, const struct kmip_version *versions); struct kmip_node *kmip_new_discover_versions_payload_va(int version_count, ...); struct kmip_node *kmip_new_protection_storage_masks(unsigned int masks_count, int32_t *masks); struct kmip_node *kmip_new_protection_storage_masks_va(unsigned int masks_count, ...); struct kmip_node *kmip_new_create_request_payload( const struct kmip_version *version, enum kmip_object_type obj_type, struct kmip_node *prot_storage_masks, unsigned int attrs_count, struct kmip_node **attrs); struct kmip_node *kmip_new_create_request_payload_va( const struct kmip_version *version, enum kmip_object_type obj_type, struct kmip_node *prot_storage_masks, unsigned int attrs_count, ...); struct kmip_node *kmip_new_get_attribute_list_request_payload( struct kmip_node *unique_id); struct kmip_node *kmip_new_get_attributes_request_payload( const struct kmip_version *version, struct kmip_node *unique_id, unsigned int num_attrs, struct kmip_node **attr_refs); struct kmip_node *kmip_new_get_attributes_request_payload_va( const struct kmip_version *version, struct kmip_node *unique_id, unsigned int num_attrs, ...); struct kmip_node *kmip_new_add_attribute_request_payload( const struct kmip_version *version, struct kmip_node *unique_id, struct kmip_node *v2_attr); struct kmip_node *kmip_new_modify_attribute_request_payload( const struct kmip_version *version, struct kmip_node *unique_id, struct kmip_node *v2_current, struct kmip_node *v2_attr); struct kmip_node *kmip_new_set_attribute_v2_request_payload( struct kmip_node *unique_id, struct kmip_node *v2_attr); struct kmip_node *kmip_new_delete_attribute_request_payload( const struct kmip_version *version, struct kmip_node *unique_id, struct kmip_node *v2_current, struct kmip_node *attr_ref); struct kmip_node *kmip_new_activate_request_payload( struct kmip_node *unique_id); struct kmip_node *kmip_new_destroy_request_payload(struct kmip_node *unique_id); struct kmip_node *kmip_new_archive_request_payload(struct kmip_node *unique_id); struct kmip_node *kmip_new_recover_request_payload(struct kmip_node *unique_id); struct kmip_node *kmip_new_revoke_request_payload(struct kmip_node *unique_id, enum kmip_revoke_reason rsn, const char *message, uint64_t compromise_date); struct kmip_node *kmip_new_locate_request_payload( const struct kmip_version *version, int32_t max_items, int32_t offset_items, enum kmip_storage_status_mask storage_status, enum kmip_object_group_member obj_group, unsigned int attrs_count, struct kmip_node **attrs); struct kmip_node *kmip_new_locate_request_payload_va( const struct kmip_version *version, int32_t max_items, int32_t offset_items, enum kmip_storage_status_mask storage_status, enum kmip_object_group_member obj_group, unsigned int attrs_count, ...); struct kmip_node *kmip_new_register_request_payload( const struct kmip_version *version, enum kmip_object_type obj_type, struct kmip_node *object, struct kmip_node *prot_storage_masks, unsigned int attrs_count, struct kmip_node **attrs); struct kmip_node *kmip_new_register_request_payload_va( const struct kmip_version *version, enum kmip_object_type obj_type, struct kmip_node *object, struct kmip_node *prot_storage_masks, unsigned int attrs_count, ...); struct kmip_node *kmip_new_get_request_payload( const struct kmip_version *version, struct kmip_node *unique_id, enum kmip_key_format_type format_type, enum kmip_key_wrap_type wrap_type, enum kmip_key_compression_type compr_type, struct kmip_node *wrap_specification); /* Response related functions */ int kmip_get_protocol_version(const struct kmip_node *node, struct kmip_version *version); int kmip_get_profile_version(const struct kmip_node *node, struct kmip_version *version); int kmip_get_response_header(const struct kmip_node *node, struct kmip_version *version, int64_t *time_stamp, const char **client_corr_value, const char **server_corr_value, int32_t *batch_count); int kmip_get_response_batch_item(const struct kmip_node *node, enum kmip_operation *operation, const unsigned char **batch_id, uint32_t *batch_id_length, enum kmip_result_status *status, enum kmip_result_reason *reason, const char **message, const unsigned char **async_corr_value, uint32_t *async_corr_value_len, struct kmip_node **payload); int kmip_get_response(const struct kmip_node *node, struct kmip_node **response_header, unsigned int batch_index, struct kmip_node **batch_item); int kmip_get_query_response_payload(const struct kmip_node *node, enum kmip_query_function query_function, unsigned int *num_results, unsigned int result_index, struct kmip_node **result); int kmip_get_discover_versions_response_payload(const struct kmip_node *node, unsigned int *num_versions, unsigned int index, struct kmip_version *version); int kmip_get_create_response_payload(const struct kmip_node *node, enum kmip_object_type *obj_type, struct kmip_node **unique_id, unsigned int *num_attrs, unsigned int attr_index, struct kmip_node **attribute); int kmip_get_get_attribute_list_response_payload(const struct kmip_node *node, struct kmip_node **unique_id, unsigned int *num_attr_refs, unsigned int index, struct kmip_node **attr_ref); int kmip_get_get_attributes_response_payload(const struct kmip_node *node, struct kmip_node **unique_id, unsigned int *num_attrs, unsigned int index, struct kmip_node **v2_attr); int kmip_get_add_attribute_response_payload(const struct kmip_node *node, struct kmip_node **unique_id, struct kmip_node **v2_attr); int kmip_get_modify_attribute_response_payload(const struct kmip_node *node, struct kmip_node **unique_id, struct kmip_node **v2_attr); int kmip_get_set_attribute_v2_response_payload(const struct kmip_node *node, struct kmip_node **unique_id); int kmip_get_delete_attribute_response_payload(const struct kmip_node *node, struct kmip_node **unique_id, struct kmip_node **v2_attr); int kmip_get_activate_response_payload(const struct kmip_node *node, struct kmip_node **unique_id); int kmip_get_destroy_response_payload(const struct kmip_node *node, struct kmip_node **unique_id); int kmip_get_archive_response_payload(const struct kmip_node *node, struct kmip_node **unique_id); int kmip_get_recover_response_payload(const struct kmip_node *node, struct kmip_node **unique_id); int kmip_get_revoke_response_payload(const struct kmip_node *node, struct kmip_node **unique_id); int kmip_get_activate_response_payload(const struct kmip_node *node, struct kmip_node **unique_id); int kmip_get_locate_response_payload(const struct kmip_node *node, int32_t *located_items, unsigned int *num_items, unsigned int index, struct kmip_node **unique_id); int kmip_get_register_response_payload(const struct kmip_node *node, struct kmip_node **unique_id, unsigned int *num_attrs, unsigned int attr_index, struct kmip_node **attribute); int kmip_get_get_response_payload(const struct kmip_node *node, enum kmip_object_type *obj_type, struct kmip_node **unique_id, struct kmip_node **object); /* Attribute related functions */ struct kmip_node *kmip_new_attributes(const struct kmip_version *version, enum kmip_tag v2_tag, unsigned int attrs_count, struct kmip_node **v2_attrs); struct kmip_node *kmip_new_attributes_va(const struct kmip_version *version, enum kmip_tag v2_tag, unsigned int attrs_count, ...); int kmip_get_attributes(const struct kmip_node *node, unsigned int *num_attrs, unsigned int attr_index, struct kmip_node **attr); struct kmip_node *kmip_new_vendor_attribute(const char *vendor_id, const char *name, struct kmip_node *value); int kmip_get_vendor_attribute(const struct kmip_node *node, const char **vendor_id, const char **name, struct kmip_node **value); struct kmip_node *kmip_new_attribute_reference(enum kmip_tag attr_tag, const char *vendor_id, const char *name); int kmip_get_attribute_reference(const struct kmip_node *node, enum kmip_tag *attr_tag, const char **vendor_id, const char **name); struct kmip_node *kmip_new_current_new_attribute(bool new_attr, struct kmip_node *attr); struct kmip_node *kmip_new_unique_identifier(const char *text_id, enum kmip_unique_identifier enum_id, int32_t int_id); int kmip_get_unique_identifier(const struct kmip_node *node, const char **text_id, enum kmip_unique_identifier *enum_id, int32_t *int_id); struct kmip_node *kmip_new_name(const char *value, enum kmip_name_type type); int kmip_get_name(const struct kmip_node *node, const char **value, enum kmip_name_type *type); struct kmip_node *kmip_new_alternative_name(const char *value, enum kmip_alternative_name_type type); int kmip_get_alternative_name(const struct kmip_node *node, const char **value, enum kmip_alternative_name_type *type); struct kmip_node *kmip_new_object_type(enum kmip_object_type obj_type); int kmip_get_object_type(const struct kmip_node *node, enum kmip_object_type *obj_type); struct kmip_node *kmip_new_cryptographic_algorithm(enum kmip_crypto_algo algo); int kmip_get_cryptographic_algorithm(const struct kmip_node *node, enum kmip_crypto_algo *algo); struct kmip_node *kmip_new_cryptographic_length(int32_t length); int kmip_get_cryptographic_length(const struct kmip_node *node, int32_t *length); struct kmip_node *kmip_new_certificate_type(enum kmip_certificate_type type); int kmip_get_certificate_type(const struct kmip_node *node, enum kmip_certificate_type *type); struct kmip_node *kmip_new_cryptographic_usage_mask(int32_t usage_mask); int kmip_get_cryptographic_usage_mask(const struct kmip_node *node, int32_t *usage_mask); struct kmip_node *kmip_new_state(enum kmip_state state); int kmip_get_state(const struct kmip_node *node, enum kmip_state *state); struct kmip_node *kmip_new_initial_date(int64_t date); int kmip_get_initial_date(const struct kmip_node *node, int64_t *date); struct kmip_node *kmip_new_activation_date(int64_t date); int kmip_get_activation_date(const struct kmip_node *node, int64_t *date); struct kmip_node *kmip_new_deactivation_date(int64_t date); int kmip_get_deactivation_date(const struct kmip_node *node, int64_t *date); struct kmip_node *kmip_new_destroy_date(int64_t date); int kmip_get_destroy_date(const struct kmip_node *node, int64_t *date); struct kmip_node *kmip_new_compromise_date(int64_t date); int kmip_get_compromise_date(const struct kmip_node *node, int64_t *date); struct kmip_node *kmip_new_compromise_occurrence_date(int64_t date); int kmip_get_compromise_occurrence_date(const struct kmip_node *node, int64_t *date); struct kmip_node *kmip_new_last_change_date(int64_t date); int kmip_get_last_change_date(const struct kmip_node *node, int64_t *date); struct kmip_node *kmip_new_original_creation_date(int64_t date); int kmip_get_original_creation_date(const struct kmip_node *node, int64_t *date); struct kmip_node *kmip_new_archive_date(int64_t date); int kmip_get_archive_date(const struct kmip_node *node, int64_t *date); struct kmip_node *kmip_new_process_start_date(int64_t date); int kmip_get_process_start_date(const struct kmip_node *node, int64_t *date); struct kmip_node *kmip_new_protect_stop_date(int64_t date); int kmip_get_protect_stop_date(const struct kmip_node *node, int64_t *date); struct kmip_node *kmip_new_cryptographic_parameters( const struct kmip_version *version, enum kmip_block_cipher_mode mode, enum kmip_padding_method padding, enum kmip_hashing_algo hash_algo, enum kmip_key_role_type key_role, enum kmip_signature_algo signature_algo, enum kmip_crypto_algo crypto_algo, bool *random_iv, int32_t *iv_length, int32_t *tag_length, int32_t *fixed_field_length, int32_t *invoc_field_length, int32_t *counter_length, int32_t *init_counter_value, int32_t *salt_length, enum kmip_mask_generator mgf, enum kmip_hashing_algo mgf_hash_algo, int32_t *trailer_field); int kmip_get_cryptographic_parameter(const struct kmip_node *node, enum kmip_block_cipher_mode *mode, enum kmip_padding_method *padding, enum kmip_hashing_algo *hash_algo, enum kmip_key_role_type *key_role, enum kmip_signature_algo *signature_algo, enum kmip_crypto_algo *crypto_algo, bool *random_iv, int32_t *iv_length, int32_t *tag_length, int32_t *fixed_field_length, int32_t *invoc_field_length, int32_t *counter_length, int32_t *init_counter_value, int32_t *salt_length, enum kmip_mask_generator *mgf, enum kmip_hashing_algo *mgf_hash_algo, int32_t *trailer_field); struct kmip_node *kmip_new_cryptographic_domain_parameters( int32_t qlength, enum kmip_recommended_curve curve); int kmip_get_cryptographic_domain_parameters(const struct kmip_node *node, int32_t *qlength, enum kmip_recommended_curve *curve); struct kmip_node *kmip_new_digital_signature_algorithm( enum kmip_signature_algo signature_algo); int kmip_get_digital_signature_algorithm(const struct kmip_node *node, enum kmip_signature_algo *signature_algo); struct kmip_node *kmip_new_object_group(const char *group); int kmip_get_object_group(const struct kmip_node *node, const char **group); struct kmip_node *kmip_new_revocation_reason(enum kmip_revoke_reason reason, const char *message); int kmip_get_revocation_reason(const struct kmip_node *node, enum kmip_revoke_reason *reason, const char **message); struct kmip_node *kmip_new_contact_information(const char *contact); int kmip_get_contact_information(const struct kmip_node *node, const char **contact); struct kmip_node *kmip_new_description(const char *description); int kmip_get_description(const struct kmip_node *node, const char **description); struct kmip_node *kmip_new_comment(const char *comment); int kmip_get_comment(const struct kmip_node *node, const char **comment); struct kmip_node *kmip_new_key_format_type(enum kmip_key_format_type type); int kmip_get_key_format_type(const struct kmip_node *node, enum kmip_key_format_type *type); struct kmip_node *kmip_new_protection_level(enum kmip_protection_level level); int kmip_get_protection_level(const struct kmip_node *node, enum kmip_protection_level *level); struct kmip_node *kmip_new_protection_period(uint32_t period); int kmip_get_protection_period(const struct kmip_node *node, uint32_t *period); struct kmip_node *kmip_new_protection_storage_mask(int32_t protection_mask); int kmip_get_protection_storage_mask(const struct kmip_node *node, int32_t *protection_mask); struct kmip_node *kmip_new_fresh(bool fresh); int kmip_get_fresh(const struct kmip_node *node, bool *fresh); struct kmip_node *kmip_new_key_value_present(bool present); int kmip_get_key_value_present(const struct kmip_node *node, bool *present); struct kmip_node *kmip_new_short_unique_identifier( const unsigned char *short_uid, uint32_t short_uid_len); int kmip_get_short_unique_identifier(const struct kmip_node *node, const unsigned char **short_uid, uint32_t *short_uid_len); struct kmip_node *kmip_new_application_specific_information( const char *name_space, const char *data); int kmip_get_application_specific_information(const struct kmip_node *node, const char **name_space, const char **data); struct kmip_node *kmip_new_key_value_location(const char *value, enum kmip_key_value_location_type type); int kmip_get_key_value_location(const struct kmip_node *node, const char **value, enum kmip_key_value_location_type *type); struct kmip_node *kmip_new_digest(enum kmip_hashing_algo hash_algo, const unsigned char *digest, uint32_t digest_len); int kmip_get_digest(const struct kmip_node *node, enum kmip_hashing_algo *hash_algo, const unsigned char **digest, uint32_t *digest_len); struct kmip_node *kmip_new_sensitive(bool sensitive); int kmip_get_sensitive(const struct kmip_node *node, bool *sensitive); struct kmip_node *kmip_new_always_sensitive(bool sensitive); int kmip_get_always_sensitive(const struct kmip_node *node, bool *sensitive); struct kmip_node *kmip_new_extractable(bool extractable); int kmip_get_extractable(const struct kmip_node *node, bool *extractable); struct kmip_node *kmip_new_never_extractable(bool extractable); int kmip_get_never_extractable(const struct kmip_node *node, bool *extractable); struct kmip_node *kmip_new_link(enum kmip_link_type type, struct kmip_node *obj_id); int kmip_get_link(const struct kmip_node *node, enum kmip_link_type *type, struct kmip_node **obj_id); struct kmip_node *kmip_new_linked_object_identifier(const char *text_id, enum kmip_unique_identifier enum_id, int32_t int_id); int kmip_get_linked_object_identifier(const struct kmip_node *node, const char **text_id, enum kmip_unique_identifier *enum_id, int32_t *int_id); struct kmip_node *kmip_new_operation_policy_name(const char *policy); int kmip_get_operation_policy_name(const struct kmip_node *node, const char **policy); struct kmip_node *kmip_new_lease_time(uint32_t lease_time); int kmip_get_lease_time(const struct kmip_node *node, uint32_t *lease_time); /* Key related functions */ struct kmip_node *kmip_new_key_block(enum kmip_key_format_type format_type, enum kmip_key_compression_type compr_type, struct kmip_node *key_value, enum kmip_crypto_algo algorithm, int32_t length, struct kmip_node *wrappig_data); int kmip_get_key_block(const struct kmip_node *node, enum kmip_key_format_type *format_type, enum kmip_key_compression_type *compr_type, struct kmip_node **key_value, enum kmip_crypto_algo *algorithm, int32_t *length, struct kmip_node **wrappig_data); struct kmip_node *kmip_new_key_value(const struct kmip_version *version, struct kmip_node *key_material, unsigned int attrs_count, struct kmip_node **v2_attrs); struct kmip_node *kmip_new_key_value_va(const struct kmip_version *version, struct kmip_node *key_material, unsigned int attrs_count, ...); int kmip_get_key_value(const struct kmip_node *node, struct kmip_node **key_material, unsigned int *num_attrs, unsigned int index, struct kmip_node **v2_attr); struct kmip_node *kmip_new_key_wrapping_data( const struct kmip_version *version, enum kmip_wrapping_method wrap_method, struct kmip_node *encr_key_info, struct kmip_node *mac_sign_key_info, const unsigned char *mac_signature, uint32_t mac_signature_len, const unsigned char *iv_counter_nonce, uint32_t iv_counter_nonce_len, enum kmip_encoding_option encoding); int kmip_get_key_wrapping_data(const struct kmip_node *node, enum kmip_wrapping_method *wrap_method, struct kmip_node **encr_key_info, struct kmip_node **mac_sign_key_info, const unsigned char **mac_signature, uint32_t *mac_signature_len, const unsigned char **iv_counter_nonce, uint32_t *iv_counter_nonce_len, enum kmip_encoding_option *encoding); struct kmip_node *kmip_new_key_wrapping_specification( const struct kmip_version *version, enum kmip_wrapping_method wrap_method, struct kmip_node *encr_key_info, struct kmip_node *mac_sign_key_info, enum kmip_encoding_option encoding, unsigned int attr_name_count, const char **attr_names); struct kmip_node *kmip_new_key_wrapping_specification_va( const struct kmip_version *version, enum kmip_wrapping_method wrap_method, struct kmip_node *encr_key_info, struct kmip_node *mac_sign_key_info, enum kmip_encoding_option encoding, unsigned int attr_name_count, ...); int kmip_get_key_wrapping_specification(const struct kmip_node *node, enum kmip_wrapping_method *wrap_method, struct kmip_node **encr_key_info, struct kmip_node **mac_sign_key_info, enum kmip_encoding_option *encoding, unsigned int *num_attr_names, unsigned int attr_name_index, const char **attr_name); struct kmip_node *kmip_new_key_info(bool mac_sign, struct kmip_node *unique_id, struct kmip_node *crypto_params); int kmip_get_key_info(const struct kmip_node *node, struct kmip_node **unique_id, struct kmip_node **crypto_params); struct kmip_node *kmip_new_transparent_symmetric_key(const unsigned char *key, uint32_t key_length); int kmip_get_transparent_symmetric_key(const struct kmip_node *node, const unsigned char **key, uint32_t *key_length); struct kmip_node *kmip_new_transparent_rsa_public_key(const BIGNUM *modulus, const BIGNUM *pub_exp); int kmip_get_transparent_rsa_public_key(const struct kmip_node *node, const BIGNUM **modulus, const BIGNUM **pub_exp); struct kmip_node *kmip_new_pkcs1_public_key(EVP_PKEY *pub_key); int kmip_get_pkcs1_public_key(const struct kmip_node *node, enum kmip_crypto_algo algo, EVP_PKEY **pub_key); struct kmip_node *kmip_new_pkcs8_public_key(EVP_PKEY *pub_key); int kmip_get_pkcs8_public_key(const struct kmip_node *node, EVP_PKEY **pub_key); struct kmip_node *kmip_new_raw_key(const unsigned char *key, uint32_t key_len); int kmip_get_raw_key(const struct kmip_node *node, const unsigned char **key, uint32_t *key_len); struct kmip_node *kmip_new_symmetric_key(struct kmip_node *keyblock); int kmip_get_symmetric_key(const struct kmip_node *node, struct kmip_node **keyblock); struct kmip_node *kmip_new_public_key(struct kmip_node *keyblock); int kmip_get_public_key(const struct kmip_node *node, struct kmip_node **keyblock); /* Connection related functions */ int kmip_connection_new(const struct kmip_conn_config *config, struct kmip_connection **connection, bool debug); int kmip_connection_perform(struct kmip_connection *connection, struct kmip_node *request, struct kmip_node **response, bool debug); void kmip_connection_free(struct kmip_connection *connection); int kmip_connection_get_server_cert(const char *server, enum kmip_transport transport, const char *ca, EVP_PKEY *client_key, const char *client_cert, const char *server_cert_pem, const char *server_pubkey_pem, const char *cert_chain_pem, bool *verified, bool debug); #endif opencryptoki-opencryptoki-451d99c/usr/sbin/p11kmip/kmipclient/kmipclient.mk000066400000000000000000000020051520105705100271760ustar00rootroot00000000000000noinst_LIBRARIES = usr/sbin/p11kmip/kmipclient/libkmipclient.a noinst_HEADERS += usr/sbin/p11kmip/kmipclient/kmipclient.h \ usr/sbin/p11kmip/kmipclient/kmip.h \ usr/sbin/p11kmip/kmipclient/names.h \ usr/sbin/p11kmip/kmipclient/utils.h usr_sbin_p11kmip_kmipclient_libkmipclient_a_CFLAGS = \ -DLINUX -DPROGRAM_NAME=\"$(@)\" \ -I${srcdir}/usr/sbin/p11kmip/kmipclient \ -I${srcdir}/usr/lib/common usr_sbin_p11kmip_kmipclient_libkmipclient_a_SOURCES = \ usr/sbin/p11kmip/kmipclient/attribute.c \ usr/sbin/p11kmip/kmipclient/https.c \ usr/sbin/p11kmip/kmipclient/json.c \ usr/sbin/p11kmip/kmipclient/key.c \ usr/sbin/p11kmip/kmipclient/kmip.c \ usr/sbin/p11kmip/kmipclient/names.c \ usr/sbin/p11kmip/kmipclient/request.c \ usr/sbin/p11kmip/kmipclient/response.c \ usr/sbin/p11kmip/kmipclient/tls.c \ usr/sbin/p11kmip/kmipclient/ttlv.c \ usr/sbin/p11kmip/kmipclient/utils.c \ usr/sbin/p11kmip/kmipclient/xml.c EXTRA_DIST += usr/sbin/p11kmip/kmipclient/README.md opencryptoki-opencryptoki-451d99c/usr/sbin/p11kmip/kmipclient/names.c000066400000000000000000003147761520105705100260020ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021-2024 * * 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 _DEFAULT_SOURCE #include #include #include "names.h" #include "utils.h" static const struct kmip_enum kmip_tags[] = { { .val = KMIP_TAG_ACTIVATION_DATE, .name = "ActivationDate" }, { .val = KMIP_TAG_APPLICATION_DATA, .name = "ApplicationData" }, { .val = KMIP_TAG_APPLICATION_NAMESPACE, .name = "ApplicationNamespace" }, { .val = KMIP_TAG_APPLICATION_SPECIFIC_INFORMATION, .name = "ApplicationSpecificInformation" }, { .val = KMIP_TAG_ARCHIVE_DATE, .name = "ArchiveDate" }, { .val = KMIP_TAG_ASYNCHRONOUS_CORRELATION_VALUE, .name = "AsynchronousCorrelationValue" }, { .val = KMIP_TAG_ASYNCHRONOUS_INDICATOR, .name = "AsynchronousIndicator" }, { .val = KMIP_TAG_ATTRIBUTE, .name = "Attribute" }, { .val = KMIP_TAG_ATTRIBUTE_INDEX, .name = "AttributeIndex" }, { .val = KMIP_TAG_ATTRIBUTE_NAME, .name = "AttributeName" }, { .val = KMIP_TAG_ATTRIBUTE_VALUE, .name = "AttributeValue" }, { .val = KMIP_TAG_AUTHENTICATION, .name = "Authentication" }, { .val = KMIP_TAG_BATCH_COUNT, .name = "BatchCount" }, { .val = KMIP_TAG_BATCH_ERROR_CONTINUATION_OPTION, .name = "BatchErrorContinuationOption" }, { .val = KMIP_TAG_BATCH_ITEM, .name = "BatchItem" }, { .val = KMIP_TAG_BATCH_ORDER_OPTION, .name = "BatchOrderOption" }, { .val = KMIP_TAG_BLOCK_CIPHER_MODE, .name = "BlockCipherMode" }, { .val = KMIP_TAG_CANCELATION_RESULT, .name = "CancelationResult" }, { .val = KMIP_TAG_CERTIFICATE, .name = "Certificate" }, { .val = KMIP_TAG_CERTIFICATE_IDENTIFIER, .name = "CertificateIndentifyer" }, { .val = KMIP_TAG_CERTIFICATE_ISSUER, .name = "CertificateIssuer" }, { .val = KMIP_TAG_CERTIFICATE_ISSUER_ALTERNATIVE_NAME, .name = "CertificateIssuerAlternativeName" }, { .val = KMIP_TAG_CERTIFICATE_ISSUER_DISTINGUISHED_NAME, .name = "CertificateIssuerDistinguishedName" }, { .val = KMIP_TAG_CERTIFICATE_REQUEST, .name = "CertificateRequest" }, { .val = KMIP_TAG_CERTIFICATE_REQUEST_TYPE, .name = "CertificateRequestType" }, { .val = KMIP_TAG_CERTIFICATE_SUBJECT, .name = "CertificateSubject" }, { .val = KMIP_TAG_CERTIFICATE_SUBJECT_ALTERNATIVE_NAME, .name = "CertificateSubjectAlternativeName" }, { .val = KMIP_TAG_CERTIFICATE_TYPE, .name = "CertificateType" }, { .val = KMIP_TAG_CERTIFICATE_VALUE, .name = "CertificateValue" }, { .val = KMIP_TAG_COMMON_TEMPLATE_ATTRIBUTE, .name = "CommonTemplateAttribute" }, { .val = KMIP_TAG_COMPROMIZE_DATE, .name = "CompromizeDate" }, { .val = KMIP_TAG_COMPROMISE_OCCURRENCE_DATE, .name = "CompromiseOccurrenceDate" }, { .val = KMIP_TAG_CONTACT_INFORMATION, .name = "ContactInformation" }, { .val = KMIP_TAG_CREDENTIAL, .name = "Credential" }, { .val = KMIP_TAG_CREDENTIAL_TYPE, .name = "CredentialType" }, { .val = KMIP_TAG_CREDENTIAL_VALUE, .name = "CredentialValue" }, { .val = KMIP_TAG_CRITICALITY_INDICATOR, .name = "CriticalityIndicator" }, { .val = KMIP_TAG_CRT_Coefficient, .name = "CrtCoefficient" }, { .val = KMIP_TAG_CRYPTOGRAPHIC_ALGORITHM, .name = "CryptographicAlgorithm" }, { .val = KMIP_TAG_CRYPTOGRAPHIC_DOMAIN_PARAMETERS, .name = "CryptographicDomainParameters" }, { .val = KMIP_TAG_CRYPTOGRAPHIC_LENGTH, .name = "CryptographicLength" }, { .val = KMIP_TAG_CRYPTOGRAPHIC_PARAMETERS, .name = "CryptographicParameters" }, { .val = KMIP_TAG_CRYPTOGRAPHIC_USAGE_MASK, .name = "CryptographicUsageMask" }, { .val = KMIP_TAG_CUSTOM_ATTRIBUTE, .name = "CustomAttribute" }, { .val = KMIP_TAG_D, .name = "D" }, { .val = KMIP_TAG_DEACTIVATION_DATE, .name = "DeactivationDate" }, { .val = KMIP_TAG_DERIVATION_DATE, .name = "DerivationDate" }, { .val = KMIP_TAG_DERIVATION_DATA, .name = "DerivationData" }, { .val = KMIP_TAG_DERIVATION_PARAMETERS, .name = "DerivationParameters" }, { .val = KMIP_TAG_DESTROY_DATE, .name = "DestroyDate" }, { .val = KMIP_TAG_DIGEST, .name = "Digest" }, { .val = KMIP_TAG_DIGEST_VALUE, .name = "DigestValue" }, { .val = KMIP_TAG_ENCRYPTION_KEY_INFORMATION, .name = "EncryptionKeyInformation" }, { .val = KMIP_TAG_G, .name = "G" }, { .val = KMIP_TAG_HASHING_ALGORITHM, .name = "HashingAlgorithm" }, { .val = KMIP_TAG_INITIAL_DATE, .name = "InitialDate" }, { .val = KMIP_TAG_INITIALIZATION_VECTOR, .name = "InitializationVector" }, { .val = KMIP_TAG_ISSUER, .name = "Issuer" }, { .val = KMIP_TAG_ITERATION_COUNT, .name = "IterationCount" }, { .val = KMIP_TAG_IV_COUNTER_NONCE, .name = "IvCounterNonce" }, { .val = KMIP_TAG_J, .name = "J" }, { .val = KMIP_TAG_KEY, .name = "Key" }, { .val = KMIP_TAG_KEY_BLOCK, .name = "KeyBlock" }, { .val = KMIP_TAG_KEY_COMPRESSION_TYPE, .name = "KeyCompressionType" }, { .val = KMIP_TAG_KEY_FORMAT_TYPE, .name = "KeyFormatType" }, { .val = KMIP_TAG_KEY_MATERIAL, .name = "KeyMaterial" }, { .val = KMIP_TAG_KEY_PART_IDENTIFIER, .name = "KeyPartIdentifier" }, { .val = KMIP_TAG_KEY_VALUE, .name = "KeyValue" }, { .val = KMIP_TAG_KEY_WRAPPING_DATA, .name = "KeyWrappingData" }, { .val = KMIP_TAG_KEY_WRAPPING_SPECIFICATION, .name = "KeyWrappingSpecification" }, { .val = KMIP_TAG_LAST_CHANGE_DATE, .name = "LastChangeDate" }, { .val = KMIP_TAG_LEASE_TIME, .name = "LeaseTime" }, { .val = KMIP_TAG_LINK, .name = "Link" }, { .val = KMIP_TAG_LINK_TYPE, .name = "LinkType" }, { .val = KMIP_TAG_LINKED_OBJECT_IDENTIFIER, .name = "LinkedObjectIdentifier" }, { .val = KMIP_TAG_MAC_SIGNATURE, .name = "MACSignature" }, { .val = KMIP_TAG_MAC_SIGNATURE_KEY_INFORMATION, .name = "MACSignatureKeyInformation" }, { .val = KMIP_TAG_MAXIMUM_ITEMS, .name = "MaximumItems" }, { .val = KMIP_TAG_MAXIMUM_RESPONSE_SIZE, .name = "MaximumResponseSize" }, { .val = KMIP_TAG_MESSAGE_EXTENSION, .name = "MessageExtension" }, { .val = KMIP_TAG_MODULUS, .name = "Modulus" }, { .val = KMIP_TAG_NAME, .name = "Name" }, { .val = KMIP_TAG_NAME_TYPE, .name = "NameType" }, { .val = KMIP_TAG_NAME_VALUE, .name = "NameValue" }, { .val = KMIP_TAG_OBJECT_GROUP, .name = "ObjectGroup" }, { .val = KMIP_TAG_OBJECT_TYPE, .name = "ObjectType" }, { .val = KMIP_TAG_OFFSET, .name = "Offset" }, { .val = KMIP_TAG_OPAQUE_DATA_TYPE, .name = "OpaqueDataType" }, { .val = KMIP_TAG_OPAQUE_DATA_VALUE, .name = "OpaqueDataValue" }, { .val = KMIP_TAG_OPAQUE_OBJECT, .name = "OpaqueObject" }, { .val = KMIP_TAG_OPERATION, .name = "Operation" }, { .val = KMIP_TAG_OPERATION_POLICY_NAME, .name = "OperationPolicyName" }, { .val = KMIP_TAG_P, .name = "P" }, { .val = KMIP_TAG_PADDING_METHOD, .name = "PaddingMethod" }, { .val = KMIP_TAG_PRIME_EXPONENT_P, .name = "PrimeExponentP" }, { .val = KMIP_TAG_PRIME_EXPONENT_Q, .name = "PrimeExponentQ" }, { .val = KMIP_TAG_PRIME_FIELD_SIZE, .name = "PrimeFieldSize" }, { .val = KMIP_TAG_PRIVATE_EXPONENT, .name = "PrivateExponent" }, { .val = KMIP_TAG_PRIVATE_KEY, .name = "PrivateKey" }, { .val = KMIP_TAG_PRIVATE_KEY_TEMPLATE_ATTRIBUTE, .name = "PrivateKeyTemplateAttribute" }, { .val = KMIP_TAG_PRIVATE_KEY_UNIQUE_IDENTIFIER, .name = "PrivateKeyUniqueIdentifier" }, { .val = KMIP_TAG_PROCESS_START_DATE, .name = "ProcessStartDate" }, { .val = KMIP_TAG_PROTECT_STOP_DATE, .name = "ProtectStopDate" }, { .val = KMIP_TAG_PROTOCOL_VERSION, .name = "ProtocolVersion" }, { .val = KMIP_TAG_PROTOCOL_VERSION_MAJOR, .name = "ProtocolVersionMajor" }, { .val = KMIP_TAG_PROTOCOL_VERSION_MINOR, .name = "ProtocolVersionMinor" }, { .val = KMIP_TAG_PUBLIC_EXPONENT, .name = "PublicExponent" }, { .val = KMIP_TAG_PUBLIC_KEY, .name = "PublicKey" }, { .val = KMIP_TAG_PUBLIC_KEY_TEMPLATE_ATTRIBUTE, .name = "PublicKeyTemplateAttribute" }, { .val = KMIP_TAG_PUBLIC_KEY_UNIQUE_IDENTIFIER, .name = "PublicKeyUniqueIdentifier" }, { .val = KMIP_TAG_PUT_FUNCTION, .name = "PutFunction" }, { .val = KMIP_TAG_Q, .name = "Q" }, { .val = KMIP_TAG_Q_STRING, .name = "QString" }, { .val = KMIP_TAG_Q_LENGTH, .name = "QLength" }, { .val = KMIP_TAG_QUERY_FUNCTION, .name = "QueryFunction" }, { .val = KMIP_TAG_RECOMMENDED_CURVE, .name = "RecommendedCurve" }, { .val = KMIP_TAG_REPLACED_UNIQUE_IDENTIFIER, .name = "ReplacedUniqueIdentifier" }, { .val = KMIP_TAG_REQUEST_HEADER, .name = "RequestHeader" }, { .val = KMIP_TAG_REQUEST_MESSAGE, .name = "RequestMessage" }, { .val = KMIP_TAG_REQUEST_PAYLOAD, .name = "RequestPayload" }, { .val = KMIP_TAG_RESPONSE_HEADER, .name = "ResponseHeader" }, { .val = KMIP_TAG_RESPONSE_MESSAGE, .name = "ResponseMessage" }, { .val = KMIP_TAG_RESPONSE_PAYLOAD, .name = "ResponsePayload" }, { .val = KMIP_TAG_RESULT_MESSAGE, .name = "ResultMessage" }, { .val = KMIP_TAG_RESULT_REASON, .name = "ResultReason" }, { .val = KMIP_TAG_RESULT_STATUS, .name = "ResultStatus" }, { .val = KMIP_TAG_REVOCATION_MESSAGE, .name = "RevocationMessage" }, { .val = KMIP_TAG_REVOCATION_REASON, .name = "RevocationReason" }, { .val = KMIP_TAG_REVOCATION_REASON_CODE, .name = "RevocationReasonCode" }, { .val = KMIP_TAG_KEY_ROLE_TYPE, .name = "KeyRoleType" }, { .val = KMIP_TAG_SALT, .name = "Salt" }, { .val = KMIP_TAG_SECRET_DATA, .name = "SecretData" }, { .val = KMIP_TAG_SECRET_DATA_TYPE, .name = "SecretDataType" }, { .val = KMIP_TAG_SERIAL_NUMBER, .name = "SerialNumber" }, { .val = KMIP_TAG_SERVER_INFORMATION, .name = "ServerInformation" }, { .val = KMIP_TAG_SPLIT_KEY, .name = "SplitKey" }, { .val = KMIP_TAG_SPLIT_KEY_METHOD, .name = "SplitKeyMethod" }, { .val = KMIP_TAG_SPLIT_KEY_PARTS, .name = "SplitKeyParts" }, { .val = KMIP_TAG_SPLIT_KEY_THRESHOLD, .name = "SplitKeyThreshold" }, { .val = KMIP_TAG_STATE, .name = "State" }, { .val = KMIP_TAG_STORAGE_STATUS_MASK, .name = "StorageStatusMask" }, { .val = KMIP_TAG_SYMMETRIC_KEY, .name = "SymmetricKey" }, { .val = KMIP_TAG_TEMPLATE, .name = "Template" }, { .val = KMIP_TAG_TEMPLATE_ATTRIBUTE, .name = "TemplateAttribute" }, { .val = KMIP_TAG_TIME_STAMP, .name = "TimeStamp" }, { .val = KMIP_TAG_UNIQUE_BATCH_ITEM_ID, .name = "UniqueBatchItemId" }, { .val = KMIP_TAG_UNIQUE_IDENTIFIER, .name = "UniqueIdentifier" }, { .val = KMIP_TAG_USAGE_LIMITS, .name = "UsageLimits" }, { .val = KMIP_TAG_USAGE_LIMITS_COUNT, .name = "UsageLimitsCount" }, { .val = KMIP_TAG_USAGE_LIMITS_TOTAL, .name = "UsageLimitsTotal" }, { .val = KMIP_TAG_USAGE_LIMITS_UNIT, .name = "UsageLimitsUnit" }, { .val = KMIP_TAG_USERNAME, .name = "Username" }, { .val = KMIP_TAG_VALIDITY_DATE, .name = "ValidityDate" }, { .val = KMIP_TAG_VALIDITY_INDICATOR, .name = "ValidityIndicator" }, { .val = KMIP_TAG_VENDOR_EXTENSION, .name = "VendorExtension" }, { .val = KMIP_TAG_VENDOR_IDENTIFICATION, .name = "VendorIdentification" }, { .val = KMIP_TAG_WRAPPING_METHOD, .name = "WrappingMethod" }, { .val = KMIP_TAG_X, .name = "X" }, { .val = KMIP_TAG_Y, .name = "Y" }, { .val = KMIP_TAG_PASSWORD, .name = "Password" }, { .val = KMIP_TAG_DEVICE_IDENTIFIER, .name = "DeviceIdentifier" }, { .val = KMIP_TAG_ENCODING_OPTION, .name = "EncodingOption" }, { .val = KMIP_TAG_EXTENSION_INFORMATION, .name = "ExtensionInformation" }, { .val = KMIP_TAG_EXTENSION_NAME, .name = "ExtensionName" }, { .val = KMIP_TAG_EXTENSION_TAG, .name = "ExtensionTag" }, { .val = KMIP_TAG_EXTENSION_TYPE, .name = "ExtensionType" }, { .val = KMIP_TAG_FRESH, .name = "Fresh" }, { .val = KMIP_TAG_MACHINE_IDENTIFIER, .name = "MachineIdentifier" }, { .val = KMIP_TAG_MEDIA_IDENTIFIER, .name = "MediaIdentifier" }, { .val = KMIP_TAG_NETWORK_IDENTIFIER, .name = "NetworkIdentifier" }, { .val = KMIP_TAG_OBJECT_GROUP_MEMBER, .name = "ObjectGroupMember" }, { .val = KMIP_TAG_CERTIFICATE_LENGTH, .name = "CertificateLength" }, { .val = KMIP_TAG_DIGITAL_SIGNATURE_ALGORITHM, .name = "DigitalSignatureAlgorithm" }, { .val = KMIP_TAG_CERTIFICATE_SERIAL_NUMBER, .name = "CertificateSerialNumber" }, { .val = KMIP_TAG_DEVICE_SERIAL_NUMBER, .name = "DeviceSerialNumber" }, { .val = KMIP_TAG_ISSUER_ALTERNATE_NAME, .name = "IssuerAlternateName" }, { .val = KMIP_TAG_ISSUER_DISTINGUISHED_NAME, .name = "IssuerDistinguishedName" }, { .val = KMIP_TAG_SUBJECT_ALTERNATE_NAME, .name = "SubjectAlternateName" }, { .val = KMIP_TAG_SUBJECT_DISTINGUISHED_NAME, .name = "SubjectDistinguishedName" }, { .val = KMIP_TAG_X_509_CERTIFICATE_IDENTIFIER, .name = "X_509CertificateIdentifier" }, { .val = KMIP_TAG_X_509_CERTIFICATE_ISSUER, .name = "X_509CertificateIssuer" }, { .val = KMIP_TAG_X_509_CERTIFICATE_SUBJECT, .name = "X_509CertificateSubject" }, { .val = KMIP_TAG_KEY_VALUE_LOCATION, .name = "KeyValueLocation" }, { .val = KMIP_TAG_KEY_VALUE_LOCATION_VALUE, .name = "KeyValueLocationValue" }, { .val = KMIP_TAG_KEY_VALUE_LOCATION_TYPE, .name = "KeyValueLocationType" }, { .val = KMIP_TAG_KEY_VALUE_PRESENT, .name = "KeyValuePresent" }, { .val = KMIP_TAG_ORIGINAL_CREATION_DATE, .name = "OriginalCreationDate" }, { .val = KMIP_TAG_PGP_KEY, .name = "PGPKey" }, { .val = KMIP_TAG_PGP_KEY_VERSION, .name = "PGPKeyVersion" }, { .val = KMIP_TAG_ALTERNATE_NAME, .name = "AlternateName" }, { .val = KMIP_TAG_ALTERNATE_NAME_VALUE, .name = "AlternateNameValue" }, { .val = KMIP_TAG_ALTERNATE_NAME_TYPE, .name = "AlternateNameType" }, { .val = KMIP_TAG_DATA, .name = "Data" }, { .val = KMIP_TAG_SIGNATURE_DATA, .name = "SignatureData" }, { .val = KMIP_TAG_DATA_LENGTH, .name = "DataLength" }, { .val = KMIP_TAG_RANDOM_IV, .name = "RandomIV" }, { .val = KMIP_TAG_MAC_DATA, .name = "MACData" }, { .val = KMIP_TAG_ATTESTATION_TYPE, .name = "AttestationType" }, { .val = KMIP_TAG_NONCE, .name = "Nonce" }, { .val = KMIP_TAG_NONCE_ID, .name = "NonceId" }, { .val = KMIP_TAG_NONCE_VALUE, .name = "NonceValue" }, { .val = KMIP_TAG_ATTESTATION_MEASUREMENT, .name = "AttestationMeasurement" }, { .val = KMIP_TAG_ATTESTATION_ASSERTION, .name = "AttestationAssertion" }, { .val = KMIP_TAG_IV_LENGTH, .name = "IVLength" }, { .val = KMIP_TAG_TAG_LENGTH, .name = "TagLength" }, { .val = KMIP_TAG_FIXED_FIELD_LENGTH, .name = "FixedFieldLength" }, { .val = KMIP_TAG_COUNTER_LENGTH, .name = "CounterLength" }, { .val = KMIP_TAG_INITIAL_COUNTER_VALUE, .name = "InitialCounterValue" }, { .val = KMIP_TAG_INVOCATION_FIELD_LENGTH, .name = "InvocationFieldLength" }, { .val = KMIP_TAG_ATTESTATION_CAPABLE_INDICATOR, .name = "AttestationCapableIndicator" }, { .val = KMIP_TAG_OFFSET_ITEMS, .name = "OffsetItems" }, { .val = KMIP_TAG_LOCATED_ITEMS, .name = "LocatedItems" }, { .val = KMIP_TAG_CORRELATION_VALUE, .name = "CorrelationValue" }, { .val = KMIP_TAG_INIT_INDICATOR, .name = "InitIndicator" }, { .val = KMIP_TAG_FINAL_INDICATOR, .name = "FinalIndicator" }, { .val = KMIP_TAG_RNG_PARAMETERS, .name = "RNGParameters" }, { .val = KMIP_TAG_RNG_ALGORITHM, .name = "RNGAlgorithm" }, { .val = KMIP_TAG_DRBG_ALGORITHM, .name = "DRBGAlgorithm" }, { .val = KMIP_TAG_FIPS186_VARIANT, .name = "Fips186Variant" }, { .val = KMIP_TAG_PREDICTION_RESISTANCE, .name = "PredictionResistance" }, { .val = KMIP_TAG_RANDOM_NUMBER_GENERATOR, .name = "RandomNumberGenerator" }, { .val = KMIP_TAG_VALIDATION_INFORMATION, .name = "ValidationInformation" }, { .val = KMIP_TAG_VALIDATION_AUTHORITY_TYPE, .name = "ValidationAuthorityType" }, { .val = KMIP_TAG_VALIDATION_AUTHORITY_COUNTRY, .name = "ValidationAuthorityCountry" }, { .val = KMIP_TAG_VALIDATION_AUTHORITY_URI, .name = "ValidationAuthorityURI" }, { .val = KMIP_TAG_VALIDATION_VERSION_MAJOR, .name = "ValidationVersionMajor" }, { .val = KMIP_TAG_VALIDATION_VERSION_MINOR, .name = "ValidationVersionMinor" }, { .val = KMIP_TAG_VALIDATION_TYPE, .name = "ValidationType" }, { .val = KMIP_TAG_VALIDATION_LEVEL, .name = "ValidationLevel" }, { .val = KMIP_TAG_VALIDATION_CERTIFICATE_IDENTIFIER, .name = "ValidationCertificateIdentifier" }, { .val = KMIP_TAG_VALIDATION_CERTIFICATE_URI, .name = "ValidationCertificateURI" }, { .val = KMIP_TAG_VALIDATION_VENDOR_URI, .name = "ValidationVendorURI" }, { .val = KMIP_TAG_VALIDATION_PROFILE, .name = "ValidationProfile" }, { .val = KMIP_TAG_PROFILE_INFORMATION, .name = "ProfileInformation" }, { .val = KMIP_TAG_PROFILE_NAME, .name = "ProfileName" }, { .val = KMIP_TAG_SERVER_URI, .name = "ServerURI" }, { .val = KMIP_TAG_SERVER_PORT, .name = "ServerPort" }, { .val = KMIP_TAG_STREAMING_CAPABILITY, .name = "StreamingCapability" }, { .val = KMIP_TAG_ASYNCHRONOUS_CAPABILITY, .name = "AsynchronousCapability" }, { .val = KMIP_TAG_ATTESTATION_CAPABILITY, .name = "AttestationCapability" }, { .val = KMIP_TAG_UNWRAP_MODE, .name = "UnwrapMode" }, { .val = KMIP_TAG_DESTROY_ACTION, .name = "DestroyAction" }, { .val = KMIP_TAG_SHREDDING_ALGORITHM, .name = "ShreddingAlgorithm" }, { .val = KMIP_TAG_RNG_MODE, .name = "RNGMode" }, { .val = KMIP_TAG_CLIENT_REGISTRATION_METHOD, .name = "ClientRegistrationMethod" }, { .val = KMIP_TAG_CAPABILITY_INFORMATION, .name = "CapabilityInformation" }, { .val = KMIP_TAG_KEY_WRAP_TYPE, .name = "KeyWrapType" }, { .val = KMIP_TAG_BATCH_UNDO_CAPABILITY, .name = "BatchUndoCapability" }, { .val = KMIP_TAG_BATCH_CONTINUE_CAPABILITY, .name = "BatchContinueCapability" }, { .val = KMIP_TAG_PKCS_12_FRIENDLY_NAME, .name = "PKCS_12FriendlyName" }, { .val = KMIP_TAG_DESCRIPTION, .name = "Description" }, { .val = KMIP_TAG_COMMENT, .name = "Comment" }, { .val = KMIP_TAG_AUTHENTICATED_ENCRYPTION_ADDITIONAL_DATA, .name = "AuthenticatedEncryptionAdditionalDat" }, { .val = KMIP_TAG_AUTHENTICTAED_ENCRYPTION_TAG, .name = "AuthentictaedEncryptionTag" }, { .val = KMIP_TAG_SALT_LENGTH, .name = "SaltLength" }, { .val = KMIP_TAG_MASK_GENERATOR, .name = "MaskGenerator" }, { .val = KMIP_TAG_MASK_GENERATOR_HASHING_ALGORITHM, .name = "MaskGeneratorHashingAlgorithm" }, { .val = KMIP_TAG_P_SOURCE, .name = "PSource" }, { .val = KMIP_TAG_TRAILER_FIELD, .name = "TrailerField" }, { .val = KMIP_TAG_CLIENT_CORRELATION_VALUE, .name = "ClientCorrelationValue" }, { .val = KMIP_TAG_SERVER_CORRELATION_VALUE, .name = "ServerCorrelationValue" }, { .val = KMIP_TAG_DIGESTED_DATA, .name = "DigestedData" }, { .val = KMIP_TAG_CERTIFICATE_SUBJECT_CN, .name = "CertificateSubjectCN" }, { .val = KMIP_TAG_CERTIFICATE_SUBJECT_O, .name = "CertificateSubjectO" }, { .val = KMIP_TAG_CERTIFICATE_SUBJECT_OU, .name = "CertificateSubjectOU" }, { .val = KMIP_TAG_CERTIFICATE_SUBJECT_EMAIL, .name = "CertificateSubjectEmail" }, { .val = KMIP_TAG_CERTIFICATE_SUBJECT_C, .name = "CertificateSubjectC" }, { .val = KMIP_TAG_CERTIFICATE_SUBJECT_ST, .name = "CertificateSubjectST" }, { .val = KMIP_TAG_CERTIFICATE_SUBJECT_L, .name = "CertificateSubjectL" }, { .val = KMIP_TAG_CERTIFICATE_SUBJECT_UID, .name = "CertificateSubjectUID" }, { .val = KMIP_TAG_CERTIFICATE_SUBJECT_SERIAL_NUMBER, .name = "CertificateSubjectSerialNumber" }, { .val = KMIP_TAG_CERTIFICATE_SUBJECT_TITLE, .name = "CertificateSubjectTitle" }, { .val = KMIP_TAG_CERTIFICATE_SUBJECT_DC, .name = "CertificateSubjectDC" }, { .val = KMIP_TAG_CERTIFICATE_SUBJECT_DN_QUALIFIER, .name = "CertificateSubjectDNQualifier" }, { .val = KMIP_TAG_CERTIFICATE_ISSUER_CN, .name = "CertificateIssuerCN" }, { .val = KMIP_TAG_CERTIFICATE_ISSUER_O, .name = "CertificateIssuerO" }, { .val = KMIP_TAG_CERTIFICATE_ISSUER_OU, .name = "CertificateIssuerOU" }, { .val = KMIP_TAG_CERTIFICATE_ISSUER_EMAIL, .name = "CertificateIssuerEmail" }, { .val = KMIP_TAG_CERTIFICATE_ISSUER_C, .name = "CertificateIssuerC" }, { .val = KMIP_TAG_CERTIFICATE_ISSUER_ST, .name = "CertificateIssuerST" }, { .val = KMIP_TAG_CERTIFICATE_ISSUER_L, .name = "CertificateIssuerL" }, { .val = KMIP_TAG_CERTIFICATE_ISSUER_UID, .name = "CertificateIssuerUID" }, { .val = KMIP_TAG_CERTIFICATE_ISSUER_SERIAL_NUMBER, .name = "CertificateIssuerSerialNumber" }, { .val = KMIP_TAG_CERTIFICATE_ISSUER_TITLE, .name = "CertificateIssuerTitle" }, { .val = KMIP_TAG_CERTIFICATE_ISSUER_DC, .name = "CertificateIssuerDC" }, { .val = KMIP_TAG_CERTIFICATE_ISSUER_DN_QUALIFIER, .name = "CertificateIssuerDNQualifier" }, { .val = KMIP_TAG_SENSITIVE, .name = "Sensitive" }, { .val = KMIP_TAG_ALWAYS_SENSITIVE, .name = "AlwaysSensitive" }, { .val = KMIP_TAG_EXTRACTABLE, .name = "Extractable" }, { .val = KMIP_TAG_NEVER_EXTRACTABLE, .name = "NeverExtractable" }, { .val = KMIP_TAG_REPLACE_EXISTING, .name = "ReplaceExisting" }, { .val = KMIP_TAG_ATTRIBUTES, .name = "Attributes" }, { .val = KMIP_TAG_COMMON_ATTRIBUTES, .name = "CommonAttributes" }, { .val = KMIP_TAG_PRIVATE_KEY_ATTRIBUTES, .name = "PrivateKeyAttributes" }, { .val = KMIP_TAG_PUBLIC_KEY_ATTRIBUTES, .name = "PublicKeyAttributes" }, { .val = KMIP_TAG_EXTENSION_ENUMERATION, .name = "ExtensionEnumeration" }, { .val = KMIP_TAG_EXTENSION_ATTRIBUTE, .name = "ExtensionAttribute" }, { .val = KMIP_TAG_EXTENSION_PARENT_STRUCTURE_TAG, .name = "ExtensionParentStructureTag" }, { .val = KMIP_TAG_EXTENSION_DESCRIPTION, .name = "ExtensionDescription" }, { .val = KMIP_TAG_SERVER_NAME, .name = "ServerName" }, { .val = KMIP_TAG_SERVER_SERIAL_NUMBER, .name = "ServerSerialNumber" }, { .val = KMIP_TAG_SERVER_VERSION, .name = "ServerVersion" }, { .val = KMIP_TAG_SERVER_LOAD, .name = "ServerLoad" }, { .val = KMIP_TAG_PRODUCT_NAME, .name = "ProductName" }, { .val = KMIP_TAG_BUILD_LEVEL, .name = "BuildLevel" }, { .val = KMIP_TAG_BUILD_DATE, .name = "BuildDate" }, { .val = KMIP_TAG_CLUSTER_INFO, .name = "ClusterInfo" }, { .val = KMIP_TAG_ALTERNATE_FAILOVER_ENDPOINTS, .name = "AlternateFailoverEndpoints" }, { .val = KMIP_TAG_SHORT_UNIQUE_IDENTIFIER, .name = "ShortUniqueIdentifier" }, { .val = KMIP_TAG_TAG, .name = "Tag" }, { .val = KMIP_TAG_CERTIFICATE_REQUEST_UNIQUE_IDENTIFIER, .name = "CertificateRequestUniqueIdentifier" }, { .val = KMIP_TAG_NIST_KEY_TYPE, .name = "NISTKeyType" }, { .val = KMIP_TAG_ATTRIBUTE_REFERENCE, .name = "AttributeReference" }, { .val = KMIP_TAG_CURRENT_ATTRIBUTE, .name = "CurrentAttribute" }, { .val = KMIP_TAG_NEW_ATTRIBUTE, .name = "NewAttribute" }, { .val = KMIP_TAG_CERTIFICATE_REQUEST_VALUE, .name = "CertificateRequestValue" }, { .val = KMIP_TAG_LOG_MESSAGE, .name = "LogMessage" }, { .val = KMIP_TAG_PROFILE_VERSION, .name = "ProfileVersion" }, { .val = KMIP_TAG_PROFILE_VERSION_MAJOR, .name = "ProfileVersionMajor" }, { .val = KMIP_TAG_PROFILE_VERSION_MINOR, .name = "ProfileVersionMinor" }, { .val = KMIP_TAG_PROTECTION_LEVEL, .name = "ProtectionLevel" }, { .val = KMIP_TAG_PROTECTION_PERIOD, .name = "ProtectionPeriod" }, { .val = KMIP_TAG_QUANTUM_SAFE, .name = "QuantumSafe" }, { .val = KMIP_TAG_QUANTUM_SAFE_CAPABILITY, .name = "QuantumSafeCapability" }, { .val = KMIP_TAG_TICKET, .name = "Ticket" }, { .val = KMIP_TAG_TICKET_TYPE, .name = "TicketType" }, { .val = KMIP_TAG_TICKET_VALUE, .name = "TicketValue" }, { .val = KMIP_TAG_REQUEST_COUNT, .name = "RequestCount" }, { .val = KMIP_TAG_RIGHTS, .name = "Rights" }, { .val = KMIP_TAG_OBJECTS, .name = "Objects" }, { .val = KMIP_TAG_OPERATIONS, .name = "Operations" }, { .val = KMIP_TAG_RIGHT, .name = "Right" }, { .val = KMIP_TAG_ENDPOINT_ROLE, .name = "EndpointRole" }, { .val = KMIP_TAG_DEFAULTS_INFORMATION, .name = "DefaultsInformation" }, { .val = KMIP_TAG_OBJECT_DEFAULTS, .name = "ObjectDefaults" }, { .val = KMIP_TAG_EPHEMERAL, .name = "Ephemeral" }, { .val = KMIP_TAG_SERVER_HASHED_PASSWORD, .name = "ServerHashedPassword" }, { .val = KMIP_TAG_ONE_TIME_PASSWORD, .name = "OneTimePassword" }, { .val = KMIP_TAG_HASHED_PASSWORD, .name = "HashedPassword" }, { .val = KMIP_TAG_ADJUSTMENT_TYPE, .name = "AdjustmentType" }, { .val = KMIP_TAG_PKCS_11_INTERFACE, .name = "PKCS_11Interface" }, { .val = KMIP_TAG_PKCS_11_FUNCTION, .name = "PKCS_11Function" }, { .val = KMIP_TAG_PKCS_11_INPUT_PARAMETERS, .name = "PKCS_11InputParameters" }, { .val = KMIP_TAG_PKCS_11_OUTPUT_PARAMETERS, .name = "PKCS_11OutputParameters" }, { .val = KMIP_TAG_PKCS_11_RETURN_CODE, .name = "PKCS_11ReturnCode" }, { .val = KMIP_TAG_PROTECTION_STORAGE_MASK, .name = "ProtectionStorageMask" }, { .val = KMIP_TAG_PROTECTION_STORAGE_MASKS, .name = "ProtectionStorageMasks" }, { .val = KMIP_TAG_INTEROP_FUNCTION, .name = "InteropFunction" }, { .val = KMIP_TAG_INTEROP_IDENTIFIER, .name = "InteropIdentifier" }, { .val = KMIP_TAG_ADJUSTMENT_VALUE, .name = "AdjustmentValue" }, { .val = KMIP_TAG_COMMON_PROTECTION_STORAGE_MASKS, .name = "CommonProtectionStorageMasks" }, { .val = KMIP_TAG_PRIVATE_PROTECTION_STORAGE_MASKS, .name = "PrivateProtectionStorageMasks" }, { .val = KMIP_TAG_PUBLIC_PROTECTION_STORAGE_MASKS, .name = "PublicProtectionStorageMasks" }, { .val = KMIP_TAG_OBJECT_GROUPS, .name = "ObjectGroups" }, { .val = KMIP_TAG_OBJECT_TYPES, .name = "ObjectTypes" }, { .val = KMIP_TAG_CONSTRAINTS, .name = "Constraints" }, { .val = KMIP_TAG_CONSTRAINT, .name = "Constraint" }, { .val = KMIP_TAG_ROTATE_INTERVAL, .name = "RotateInterval" }, { .val = KMIP_TAG_ROTATE_AUTOMATIC, .name = "RotateAutomatic" }, { .val = KMIP_TAG_ROTATE_OFFSET, .name = "RotateOffset" }, { .val = KMIP_TAG_ROTATE_DATE, .name = "RotateDate" }, { .val = KMIP_TAG_ROTATE_GENERATION, .name = "RotateGeneration" }, { .val = KMIP_TAG_ROTATE_NAME, .name = "RotateName" }, { .val = KMIP_TAG_ROTATE_NAME_VALUE, .name = "RotateNameValue" }, { .val = KMIP_TAG_ROTATE_NAME_TYPE, .name = "RotateNameType" }, { .val = KMIP_TAG_ROTATE_LATEST, .name = "RotateLatest" }, { .val = KMIP_TAG_ASYNCHRONOUS_REQUEST, .name = "AsynchronousRequest" }, { .val = KMIP_TAG_SUBMISSION_DATE, .name = "SubmissionDate" }, { .val = KMIP_TAG_PROCESSING_STAGE, .name = "ProcessingStage" }, { .val = KMIP_TAG_ASYNCHRONOUS_CORRELATION_VALUES, .name = "AsynchronousCorrelationValues" }, { .val = 0, .name = NULL }, }; static const struct kmip_enum kmip_types[] = { { .val = KMIP_TYPE_STRUCTURE, .name = "Structure" }, { .val = KMIP_TYPE_INTEGER, .name = "Integer" }, { .val = KMIP_TYPE_LONG_INTEGER, .name = "LongInteger" }, { .val = KMIP_TYPE_BIG_INTEGER, .name = "BigInteger" }, { .val = KMIP_TYPE_ENUMERATION, .name = "Enumeration" }, { .val = KMIP_TYPE_BOOLEAN, .name = "Boolean" }, { .val = KMIP_TYPE_TEXT_STRING, .name = "TextString" }, { .val = KMIP_TYPE_BYTE_STRING, .name = "ByteString" }, { .val = KMIP_TYPE_DATE_TIME, .name = "DateTime" }, { .val = KMIP_TYPE_INTERVAL, .name = "Interval" }, { .val = KMIP_TYPE_DATE_TIME_EXTENDED, .name = "DateTimeExtended" }, { .val = 0, .name = NULL }, }; static const struct kmip_enum kmip_operations[] = { { .val = KMIP_OPERATION_CREATE, .name = "Create" }, { .val = KMIP_OPERATION_CREATE_KEY_PAIR, .name = "CreateKeyPair" }, { .val = KMIP_OPERATION_REGISTER, .name = "Register" }, { .val = KMIP_OPERATION_RE_KEY, .name = "ReKey" }, { .val = KMIP_OPERATION_DERIVE_KEY, .name = "DeriveKey" }, { .val = KMIP_OPERATION_CERTIFY, .name = "Certify" }, { .val = KMIP_OPERATION_RE_CERTIFY, .name = "ReCertify" }, { .val = KMIP_OPERATION_LOCATE, .name = "Locate" }, { .val = KMIP_OPERATION_CHECK, .name = "Check" }, { .val = KMIP_OPERATION_GET, .name = "Get" }, { .val = KMIP_OPERATION_GET_ATTRIBUTES, .name = "GetAttributes" }, { .val = KMIP_OPERATION_GET_ATTRIBUTE_LIST, .name = "GetAttributeList" }, { .val = KMIP_OPERATION_ADD_ATTRIBUTE, .name = "AddAttribute" }, { .val = KMIP_OPERATION_MODIFY_ATTRIBUTE, .name = "ModifyAttribute" }, { .val = KMIP_OPERATION_DELETE_ATTRIBUTE, .name = "DeleteAttribute" }, { .val = KMIP_OPERATION_OBTAIN_LEASE, .name = "ObtainLease" }, { .val = KMIP_OPERATION_GET_USAGE_ALLOCATION, .name = "GetUsageAllocation" }, { .val = KMIP_OPERATION_ACTIVATE, .name = "Activate" }, { .val = KMIP_OPERATION_REVOKE, .name = "Revoke" }, { .val = KMIP_OPERATION_DESTROY, .name = "Destroy" }, { .val = KMIP_OPERATION_ARCHIVE, .name = "Archive" }, { .val = KMIP_OPERATION_RECOVER, .name = "Recover" }, { .val = KMIP_OPERATION_VALIDATE, .name = "Validate" }, { .val = KMIP_OPERATION_QUERY, .name = "Query" }, { .val = KMIP_OPERATION_CANCEL, .name = "Cancel" }, { .val = KMIP_OPERATION_POLL, .name = "Poll" }, { .val = KMIP_OPERATION_NOTIFY, .name = "Notify" }, { .val = KMIP_OPERATION_PUT, .name = "Put" }, { .val = KMIP_OPERATION_RE_KEY_KEY_PAIR, .name = "ReKeyKeyPair" }, { .val = KMIP_OPERATION_DISCOVER_VERSIONS, .name = "DiscoverVersions" }, { .val = KMIP_OPERATION_ENCRYPT, .name = "Encrypt" }, { .val = KMIP_OPERATION_DECRYPT, .name = "Decrypt" }, { .val = KMIP_OPERATION_SIGN, .name = "Sign" }, { .val = KMIP_OPERATION_SIGNATURE_VERIFY, .name = "SignatureVerify" }, { .val = KMIP_OPERATION_MAC, .name = "MAC" }, { .val = KMIP_OPERATION_MAC_VERIFY, .name = "MACVerify" }, { .val = KMIP_OPERATION_RNG_RETRIEVE, .name = "RNGRetrieve" }, { .val = KMIP_OPERATION_RNG_SEED, .name = "RNGSeed" }, { .val = KMIP_OPERATION_HASH, .name = "Hash" }, { .val = KMIP_OPERATION_CREATE_SPLIT_KEY, .name = "CreateSplitKey" }, { .val = KMIP_OPERATION_JOIN_SPLIT_KEY, .name = "JoinSplitKey" }, { .val = KMIP_OPERATION_IMPORT, .name = "Import" }, { .val = KMIP_OPERATION_EXPORT, .name = "Export" }, { .val = KMIP_OPERATION_LOG, .name = "Log" }, { .val = KMIP_OPERATION_LOGIN, .name = "Login" }, { .val = KMIP_OPERATION_LOGOUT, .name = "Logout" }, { .val = KMIP_OPERATION_DELEGATE_LOGIN, .name = "DelegateLogin" }, { .val = KMIP_OPERATION_ADJUST_ATTRIBUTE, .name = "AdjustAttribute" }, { .val = KMIP_OPERATION_SET_ATTRIBUTE, .name = "SetAttribute" }, { .val = KMIP_OPERATION_SET_ENDPOINT_ROLE, .name = "SetEndpointRole" }, { .val = KMIP_OPERATION_PKS_11, .name = "PKCS_11" }, { .val = KMIP_OPERATION_INTEROP, .name = "Interop" }, { .val = KMIP_OPERATION_RE_PROVISION, .name = "ReProvision" }, { .val = KMIP_OPERATION_SET_DEFAULTS, .name = "SetDefaults" }, { .val = KMIP_OPERATION_SET_CONSTRAINTS, .name = "SetConstraints" }, { .val = KMIP_OPERATION_GET_CONSTRAINTS, .name = "GetConstraints" }, { .val = KMIP_OPERATION_QUERY_ASYNCHRONOUS_REQUESTS, .name = "QueryAsynchronousRequests" }, { .val = KMIP_OPERATION_PROCESS, .name = "Process" }, { .val = KMIP_OPERATION_PING, .name = "Ping" }, { .val = 0, .name = NULL }, }; static const struct kmip_enum kmip_batch_error_cont_options[] = { { .val = KMIP_BATCH_ERR_CONT_CONTINUE, .name = "Continue" }, { .val = KMIP_BATCH_ERR_CONT_STOP, .name = "Stop" }, { .val = KMIP_BATCH_ERR_CONT_UNDO, .name = "Undo" }, { .val = 0, .name = NULL }, }; static const struct kmip_enum kmip_crypto_usage_masks[] = { { .val = KMIP_CRY_USAGE_MASK_SIGN, .name = "Sign" }, { .val = KMIP_CRY_USAGE_MASK_VERIFY, .name = "Verify" }, { .val = KMIP_CRY_USAGE_MASK_ENCRYPT, .name = "Encrypt" }, { .val = KMIP_CRY_USAGE_MASK_DECRYPT, .name = "Decrypt" }, { .val = KMIP_CRY_USAGE_MASK_WRAP_KEY, .name = "WrapKey" }, { .val = KMIP_CRY_USAGE_MASK_UNWRAP_KEY, .name = "UnwrapKey" }, { .val = KMIP_CRY_USAGE_MASK_EXPORT, .name = "Export" }, { .val = KMIP_CRY_USAGE_MASK_MAC_GENERATE, .name = "MACGenerate" }, { .val = KMIP_CRY_USAGE_MASK_MAC_VERIFY, .name = "MACVerify" }, { .val = KMIP_CRY_USAGE_MASK_DERIVE_KEY, .name = "DeriveKey" }, { .val = KMIP_CRY_USAGE_MASK_CONTENT_COMMITMENT, .name = "ContentCommitmentNonRepudiation" }, { .val = KMIP_CRY_USAGE_MASK_KEY_AGREEMENT, .name = "KeyAgreement" }, { .val = KMIP_CRY_USAGE_MASK_CERTIFICATE_SIGN, .name = "CertificateSign" }, { .val = KMIP_CRY_USAGE_MASK_CLR_SIGN, .name = "CRLSign" }, { .val = KMIP_CRY_USAGE_MASK_GENERATE_CRYPTOGRAM, .name = "GenerateCryptogram" }, { .val = KMIP_CRY_USAGE_MASK_VALIDATE_CRYPTOGRAM, .name = "ValidateCryptogram" }, { .val = KMIP_CRY_USAGE_MASK_TRANSLATE_ENCRYPT, .name = "TranslateEncrypt" }, { .val = KMIP_CRY_USAGE_MASK_TRANSLATE_DECRYPT, .name = "TranslateDecrypt" }, { .val = KMIP_CRY_USAGE_MASK_TRANSLATE_WRAP, .name = "TranslateWrap" }, { .val = KMIP_CRY_USAGE_MASK_TRANSLATE_UNWRAP, .name = "TranslateUnwrap" }, { .val = KMIP_CRY_USAGE_MASK_AUTHENTICATE, .name = "Authenticate" }, { .val = KMIP_CRY_USAGE_MASK_UNRESTRICTED, .name = "Unrestricted" }, { .val = KMIP_CRY_USAGE_MASK_FPE_ENCRYPT, .name = "FPEEncrypt" }, { .val = KMIP_CRY_USAGE_MASK_FPE_DECRYPT, .name = "FPEDecrypt" }, { .val = 0, .name = NULL }, }; static const struct kmip_enum kmip_result_statuses[] = { { .val = KMIP_RESULT_STATUS_SUCCESS, .name = "Success" }, { .val = KMIP_RESULT_STATUS_OPERATION_FAILED, .name = "OperationFailed" }, { .val = KMIP_RESULT_STATUS_OPERATION_PENDING, .name = "OperationPending" }, { .val = KMIP_RESULT_STATUS_OPERATION_UNDONE, .name = "OperationUndone" }, { .val = 0, .name = NULL }, }; static const struct kmip_enum kmip_result_reasons[] = { { .val = KMIP_RESULT_REASON_ITEM_NOT_FOUND, .name = "ItemNotFound" }, { .val = KMIP_RESULT_REASON_RESPONSE_TOO_LARGE, .name = "ResponseTooLarge" }, { .val = KMIP_RESULT_REASON_AUTH_NOT_SUCCESSFUL, .name = "AuthenticationNotSuccessful" }, { .val = KMIP_RESULT_REASON_INVALID_MESSAGE, .name = "InvalidMessage" }, { .val = KMIP_RESULT_REASON_OPERATION_NOT_SUCCESSFUL, .name = "OperationNotSupported" }, { .val = KMIP_RESULT_REASON_MISSING_DATA, .name = "MissingData" }, { .val = KMIP_RESULT_REASON_INVALIUD_FIELD, .name = "InvalidField" }, { .val = KMIP_RESULT_REASON_FEATURE_NOT_SUPPORTED, .name = "FeatureNotSupported" }, { .val = KMIP_RESULT_REASON_OP_CANCELED_BY_REQUESTOR, .name = "OperationCanceledByRequeste" }, { .val = KMIP_RESULT_REASON_CRYPTOGRAPHIC_FAILURE, .name = "CryptographicFailure" }, { .val = KMIP_RESULT_REASON_ILLEGAL_OPERATION, .name = "IllegalOperation" }, { .val = KMIP_RESULT_REASON_PERMISSION_DENIED, .name = "PermissionDenied" }, { .val = KMIP_RESULT_REASON_OBJECT_ARCHIVED, .name = "ObjectArchived" }, { .val = KMIP_RESULT_REASON_INDEX_OUT_OF_BOUNDS, .name = "IndexOutOfBounds" }, { .val = KMIP_RESULT_REASON_APP_NAMESPACE_NOT_SUPPORTED, .name = "ApplicationNamespaceNotSupported" }, { .val = KMIP_RESULT_REASON_KEY_FORMAT_TYPE_NOT_SUPPORTED, .name = "KeyFormatTypeNotSupported" }, { .val = KMIP_RESULT_REASON_KEY_COMPRESSION_TYPE_NOT_SUPPORTED, .name = "KeyCompressionTypeNotSupported" }, { .val = KMIP_RESULT_REASON_ENCODING_OPTION_ERROR, .name = "EncodingOptionError" }, { .val = KMIP_RESULT_REASON_KEY_VALUE_NOT_PRESENT, .name = "KeyValueNotPresent" }, { .val = KMIP_RESULT_REASON_ATTESTATION_REQUIRED, .name = "AttestationRequired" }, { .val = KMIP_RESULT_REASON_ATTESTATION_FAILED, .name = "AttestationFailed" }, { .val = KMIP_RESULT_REASON_SENSITIVE, .name = "Sensitive" }, { .val = KMIP_RESULT_REASON_NOT_EXTRACTABLE, .name = "NotExtractable" }, { .val = KMIP_RESULT_REASON_OBJECT_ALREADY_EXISTS, .name = "ObjectAlreadyExists" }, { .val = KMIP_RESULT_REASON_INVALID_TICKET, .name = "InvalidTicket" }, { .val = KMIP_RESULT_REASON_USAGE_LIMIT_EXCEEDED, .name = "UsageLimitExceeded" }, { .val = KMIP_RESULT_REASON_NUMERIC_RANGE, .name = "NumericRange" }, { .val = KMIP_RESULT_REASON_INVALID_DATA_TYPE, .name = "InvalidDataType" }, { .val = KMIP_RESULT_REASON_READ_ONLY_ATTRIBUTE, .name = "ReadOnlyAttribute" }, { .val = KMIP_RESULT_REASON_MULTI_VALUED_ATTRIBUTE, .name = "MultiValuedAttribute" }, { .val = KMIP_RESULT_REASON_UNSUPPORTED_ATTRIBUTE, .name = "UnsupportedAttribute" }, { .val = KMIP_RESULT_REASON_ATTRIBUTE_INSTANCE_NOT_FOUND, .name = "AttributeInstanceNotFound" }, { .val = KMIP_RESULT_REASON_ATTRIBUTE_NOT_FOUND, .name = "AttributeNotFound" }, { .val = KMIP_RESULT_REASON_ATTRIBUTE_READ_ONLY, .name = "AttributeReadOnly" }, { .val = KMIP_RESULT_REASON_ATTRIBUTE_SINGLE_VALUED, .name = "AttributeSingleValued" }, { .val = KMIP_RESULT_REASON_BAD_CRYPTOGRAPHIC_PARAMETERS, .name = "BadCryptographicParameters" }, { .val = KMIP_RESULT_REASON_BAD_PASSWORD, .name = "BadPassword" }, { .val = KMIP_RESULT_REASON_CODEC_ERROR, .name = "CodecError" }, { .val = KMIP_RESULT_REASON_ILLEGAL_OBJECT_TYPE, .name = "IllegalObjectType" }, { .val = KMIP_RESULT_REASON_INCOMPATIBLE_CRYPTO_USAGE_MASK, .name = "IncompatibleCryptographicUsageMask" }, { .val = KMIP_RESULT_REASON_INTERNAL_SERVER_ERROR, .name = "InternalServerError" }, { .val = KMIP_RESULT_REASON_INVALID_ASYNC_CORRELATION_VALUE, .name = "InvalidAsynchronousCorrelationValue" }, { .val = KMIP_RESULT_REASON_INVALID_ATTRIBUTE, .name = "InvalidAttribute" }, { .val = KMIP_RESULT_REASON_INVALID_ATTRIBUTE_VALUE, .name = "InvalidAttributeValue" }, { .val = KMIP_RESULT_REASON_INVALID_CORRELATION_VALUE, .name = "InvalidCorrelationValue" }, { .val = KMIP_RESULT_REASON_INVALID_CSR, .name = "InvalidCSR" }, { .val = KMIP_RESULT_REASON_INVALID_OBJECT_TYPE, .name = "InvalidObjectType" }, { .val = KMIP_RESULT_REASON_KEY_WRAP_TYPE_NOT_SUPPORTED, .name = "KeyWrapTypeNotSupported" }, { .val = KMIP_RESULT_REASON_MISSING_INITIALIZATION_VECTOR, .name = "MissingInitializationVector" }, { .val = KMIP_RESULT_REASON_NOT_UNIQUE_NAME_ATTRIBUTE, .name = "NonUniqueNameAttribute" }, { .val = KMIP_RESULT_REASON_OBJECT_DESTROYED, .name = "ObjectDestroyed" }, { .val = KMIP_RESULT_REASON_OBJECT_NOT_FOUND, .name = "ObjectNotFound" }, { .val = KMIP_RESULT_REASON_NOT_AUTHORISED, .name = "NotAuthorised" }, { .val = KMIP_RESULT_REASON_SERVER_LIMIT_EXCEEDED, .name = "ServerLimitExceeded" }, { .val = KMIP_RESULT_REASON_UNKNOWN_ENUMERATION, .name = "UnknownEnumeration" }, { .val = KMIP_RESULT_REASON_UNKNOWN_MESSAGE_EXTENSION, .name = "UnknownMessageExtension" }, { .val = KMIP_RESULT_REASON_UNKNOWN_TAG, .name = "UnknownTag" }, { .val = KMIP_RESULT_REASON_UNSUPPORTED_CRYPTO_PARAMETERS, .name = "UnsupportedCryptographicParameters" }, { .val = KMIP_RESULT_REASON_UNSUPPORTED_PROTOCOL_VERSION, .name = "UnsupportedProtocolVersion" }, { .val = KMIP_RESULT_REASON_WRAPPING_OBJECT_ARCHIVED, .name = "WrappingObjectArchived" }, { .val = KMIP_RESULT_REASON_WRAPPING_OBJECT_DESTROYED, .name = "WrappingObjectDestroyed" }, { .val = KMIP_RESULT_REASON_WRAPPING_OBJECT_NOT_FOUND, .name = "WrappingObjectNotFound" }, { .val = KMIP_RESULT_REASON_WRONG_KEY_LIFECYCLE_STATE, .name = "WrongKeyLifecycleState" }, { .val = KMIP_RESULT_REASON_PROTECTION_STORAGE_UNAVAILABLE, .name = "ProtectionStorageUnavailable" }, { .val = KMIP_RESULT_REASON_PKCS_11_CODE_ERROR, .name = "PKCS_11CodecError" }, { .val = KMIP_RESULT_REASON_PKCS_11_INVALID_FUNCTION, .name = "PKCS_11InvalidFunction" }, { .val = KMIP_RESULT_REASON_PKCS_11_INVALID_INTERFACE, .name = "PKCS_11InvalidInterface" }, { .val = KMIP_RESULT_REASON_PRIVATE_PROT_STORAGE_UNAVAILABLE, .name = "PrivateProtectionStorageUnavailable" }, { .val = KMIP_RESULT_REASON_PUBLIC_PROT_STORAGE_UNAVAILABLE, .name = "PublicProtectionStorageUnavailable" }, { .val = KMIP_RESULT_REASON_UNKNOWN_OBJECT_GROUP, .name = "UnknownObjectGroup" }, { .val = KMIP_RESULT_REASON_CONSTRAINT_VIOLATION, .name = "ConstraintViolation" }, { .val = KMIP_RESULT_REASON_DUPLICATE_PROCESS_REQUEST, .name = "DuplicateProcessRequest" }, { .val = KMIP_RESULT_REASON_GENERAL_FAILURE, .name = "GeneralFailure" }, { .val = 0, .name = NULL }, }; static const struct kmip_enum kmip_query_functions[] = { { .val = KMIP_QUERY_OPERATIONS, .name = "QueryOperations" }, { .val = KMIP_QUERY_OBJECTS, .name = "QueryObjects" }, { .val = KMIP_QUERY_SERVER_INFORMATION, .name = "QueryServerInformation" }, { .val = KMIP_QUERY_APPLICATION_NAMESPACES, .name = "QueryApplicationNamespaces" }, { .val = KMIP_QUERY_EXTENSION_LIST, .name = "QueryExtensionList" }, { .val = KMIP_QUERY_EXTENSION_MAP, .name = "QueryExtensionMap" }, { .val = KMIP_QUERY_ATTESTATION_TYPES, .name = "QueryAttestationTypes" }, { .val = KMIP_QUERY_QUERY_RNGS, .name = "QueryRNGs" }, { .val = KMIP_QUERY_VALIDATIONS, .name = "QueryValidations" }, { .val = KMIP_QUERY_PROFILES, .name = "QueryProfiles" }, { .val = KMIP_QUERY_CAPABILITIES, .name = "QueryCapabilities" }, { .val = KMIP_QUERY_CLIENT_REGISTRATION_METHODS, .name = "QueryClientRegistrationMethods" }, { .val = KMIP_QUERY_DEFAULTS_INFORMATION, .name = "QueryDefaultsInformation" }, { .val = KMIP_QUERY_STORAGE_PROTECTION_MASKS, .name = "QueryStorageProtectionMasks" }, { .val = 0, .name = NULL }, }; static const struct kmip_enum kmip_name_types[] = { { .val = KMIP_NAME_TYPE_UNINTERPRETED_TEXT_STRING, .name = "UninterpretedTextString" }, { .val = KMIP_NAME_TYPE_URI, .name = "URI" }, { .val = 0, .name = NULL }, }; static const struct kmip_enum kmip_alternate_name_types[] = { { .val = KMIP_ALT_NAME_TYPE_UNINTERPRETED_TEXT_STRING, .name = "UninterpretedTextString" }, { .val = KMIP_ALT_NAME_TYPE_URI, .name = "URI" }, { .val = KMIP_ALT_NAME_TYPE_OBJECT_SERIAL_NUMBER, .name = "ObjectSerialNumber" }, { .val = KMIP_ALT_NAME_TYPE_EMAIL_ADDRESS, .name = "EmailAddress" }, { .val = KMIP_ALT_NAME_TYPE_DNS_NAME, .name = "DNSName" }, { .val = KMIP_ALT_NAME_TYPE_X_500_DISTINGUISHED_NAME, .name = "X_500DistinguishedName" }, { .val = KMIP_ALT_NAME_TYPE_IP_ADDRESS, .name = "IPAddress" }, { .val = 0, .name = NULL }, }; static const struct kmip_enum kmip_unique_identifiers[] = { { .val = KMIP_UNIQUE_ID_ID_PLACEHOLDER, .name = "IDPlaceholder" }, { .val = KMIP_UNIQUE_ID_CERTIFY, .name = "Certify" }, { .val = KMIP_UNIQUE_ID_CREATE, .name = "Create" }, { .val = KMIP_UNIQUE_ID_CREATE_KEY_PAIR, .name = "CreateKeyPair" }, { .val = KMIP_UNIQUE_ID_CREATE_KEY_PAIR_PRIVATE, .name = "CreateKeyPairPrivateKey" }, { .val = KMIP_UNIQUE_ID_CREATE_KEY_PAIR_PUBLIC, .name = "CreateKeyPairPublicKey" }, { .val = KMIP_UNIQUE_ID_CREATE_SPLIT_KEY, .name = "CreateSplitKey" }, { .val = KMIP_UNIQUE_ID_DERIVE_KEY, .name = "DeriveKey" }, { .val = KMIP_UNIQUE_ID_IMPORT, .name = "Import" }, { .val = KMIP_UNIQUE_ID_JOIN_SPLIT_KEY, .name = "JoinSplitKey" }, { .val = KMIP_UNIQUE_ID_LOCATE, .name = "Locate" }, { .val = KMIP_UNIQUE_ID_REGISTER, .name = "Register" }, { .val = KMIP_UNIQUE_ID_RE_KEY, .name = "ReKey" }, { .val = KMIP_UNIQUE_ID_RE_CERTIFY, .name = "ReCertify" }, { .val = KMIP_UNIQUE_ID_RE_KEY_KEY_PAIR, .name = "ReKeyKeyPair" }, { .val = KMIP_UNIQUE_ID_RE_KEY_KEY_PAIR_PRIVATE, .name = "ReKeyKeyPairPrivateKey" }, { .val = KMIP_UNIQUE_ID_RE_KEY_KEY_PAIR_PUBLIC, .name = "ReKeyKeyPairPublicKey" }, { .val = 0, .name = NULL }, }; static const struct kmip_enum kmip_object_types[] = { { .val = KMIP_OBJECT_TYPE_CERTIFICATE, .name = "Certificate" }, { .val = KMIP_OBJECT_TYPE_SYMMETRIC_KEY, .name = "SymmetricKey" }, { .val = KMIP_OBJECT_TYPE_PUBLIC_KEY, .name = "PublicKey" }, { .val = KMIP_OBJECT_TYPE_PRIVATE_KEY, .name = "PrivateKey" }, { .val = KMIP_OBJECT_TYPE_SPLIT_KEY, .name = "SplitKey" }, { .val = KMIP_OBJECT_TYPE_TEMPLATE, .name = "Template" }, { .val = KMIP_OBJECT_TYPE_SECRET_DATA, .name = "SecretData" }, { .val = KMIP_OBJECT_TYPE_OPAQUE_OBJECT, .name = "OpaqueObject" }, { .val = KMIP_OBJECT_TYPE_PGP_KEY, .name = "PGPKey" }, { .val = KMIP_OBJECT_TYPE_CERTIFICATE_REQUEST, .name = "CertificateRequest" }, { .val = 0, .name = NULL }, }; static const struct kmip_enum kmip_crypto_algos[] = { { .val = KMIP_CRYPTO_ALGO_DES, .name = "DES" }, { .val = KMIP_CRYPTO_ALGO_3DES, .name = "3DES" }, { .val = KMIP_CRYPTO_ALGO_AES, .name = "AES" }, { .val = KMIP_CRYPTO_ALGO_RSA, .name = "RSA" }, { .val = KMIP_CRYPTO_ALGO_DSA, .name = "DSA" }, { .val = KMIP_CRYPTO_ALGO_ECDSA, .name = "ECDSA" }, { .val = KMIP_CRYPTO_ALGO_HMAC_SHA1, .name = "HMAC_SHA1" }, { .val = KMIP_CRYPTO_ALGO_HMAC_SHA224, .name = "HMAC_SHA224" }, { .val = KMIP_CRYPTO_ALGO_HMAC_SHA256, .name = "HMAC_SHA256" }, { .val = KMIP_CRYPTO_ALGO_HMAC_SHA384, .name = "HMAC_SHA384" }, { .val = KMIP_CRYPTO_ALGO_HMAC_SHA512, .name = "HMAC_SHA512" }, { .val = KMIP_CRYPTO_ALGO_HMAC_MD5, .name = "HMAC_MD5" }, { .val = KMIP_CRYPTO_ALGO_DH, .name = "DH" }, { .val = KMIP_CRYPTO_ALGO_ECDH, .name = "ECDH" }, { .val = KMIP_CRYPTO_ALGO_ECMQV, .name = "ECMQV" }, { .val = KMIP_CRYPTO_ALGO_BLOWFISH, .name = "Blowfish" }, { .val = KMIP_CRYPTO_ALGO_CAMELLIA, .name = "Camellia" }, { .val = KMIP_CRYPTO_ALGO_CAST5, .name = "CAST5" }, { .val = KMIP_CRYPTO_ALGO_IDEA, .name = "IDEA" }, { .val = KMIP_CRYPTO_ALGO_MARS, .name = "MARS" }, { .val = KMIP_CRYPTO_ALGO_RC2, .name = "RC2" }, { .val = KMIP_CRYPTO_ALGO_RC4, .name = "RC4" }, { .val = KMIP_CRYPTO_ALGO_RC5, .name = "RC5" }, { .val = KMIP_CRYPTO_ALGO_SKIPJACK, .name = "SKIPJACK" }, { .val = KMIP_CRYPTO_ALGO_TWOFISH, .name = "Twofish" }, { .val = KMIP_CRYPTO_ALGO_EC, .name = "EC" }, { .val = KMIP_CRYPTO_ALGO_ONE_TIME_PAD, .name = "OneTimePad" }, { .val = KMIP_CRYPTO_ALGO_CHACHA20, .name = "ChaCha20" }, { .val = KMIP_CRYPTO_ALGO_POLY1305, .name = "Poly1305" }, { .val = KMIP_CRYPTO_ALGO_CHACHA20_POLY1305, .name = "ChaCha20Poly1305" }, { .val = KMIP_CRYPTO_ALGO_SHA3_224, .name = "SHA3_224" }, { .val = KMIP_CRYPTO_ALGO_SHA3_256, .name = "SHA3_256" }, { .val = KMIP_CRYPTO_ALGO_SHA3_384, .name = "SHA3_384" }, { .val = KMIP_CRYPTO_ALGO_SHA3_512, .name = "SHA3_512" }, { .val = KMIP_CRYPTO_ALGO_HMAC_SHA3_224, .name = "HMAC_SHA3_224" }, { .val = KMIP_CRYPTO_ALGO_HMAC_SHA3_256, .name = "HMAC_SHA3_256" }, { .val = KMIP_CRYPTO_ALGO_HMAC_SHA3_384, .name = "HMAC_SHA3_384" }, { .val = KMIP_CRYPTO_ALGO_HMAC_SHA3_512, .name = "HMAC_SHA3_512" }, { .val = KMIP_CRYPTO_ALGO_SHAKE_128, .name = "SHAKE_128" }, { .val = KMIP_CRYPTO_ALGO_SHAKE_256, .name = "SHAKE_256" }, { .val = KMIP_CRYPTO_ALGO_ARIA, .name = "ARIA" }, { .val = KMIP_CRYPTO_ALGO_SEED, .name = "SEED" }, { .val = KMIP_CRYPTO_ALGO_SM2, .name = "SM2" }, { .val = KMIP_CRYPTO_ALGO_SM3, .name = "SM3" }, { .val = KMIP_CRYPTO_ALGO_SM4, .name = "SM4" }, { .val = KMIP_CRYPTO_ALGO_GOST_R34_10_2012, .name = "GOSTR34_10_2012" }, { .val = KMIP_CRYPTO_ALGO_GOST_R34_11_2012, .name = "GOSTR34_11_2012" }, { .val = KMIP_CRYPTO_ALGO_GOST_R34_13_2015, .name = "GOSTR34_13_2015" }, { .val = KMIP_CRYPTO_ALGO_GOST_28147_89, .name = "GOST28147_89" }, { .val = KMIP_CRYPTO_ALGO_XMSS, .name = "XMSS" }, { .val = KMIP_CRYPTO_ALGO_SPHINCS_256, .name = "SPHINCS_256" }, { .val = KMIP_CRYPTO_ALGO_MCELIECE, .name = "McEliece" }, { .val = KMIP_CRYPTO_ALGO_MCELIECE_6960119, .name = "McEliece_6960119" }, { .val = KMIP_CRYPTO_ALGO_MCELIECE_8192128, .name = "McEliece_8192128" }, { .val = KMIP_CRYPTO_ALGO_ED25519, .name = "Ed25519" }, { .val = KMIP_CRYPTO_ALGO_ED448, .name = "Ed448" }, { .val = 0, .name = NULL }, }; static const struct kmip_enum kmip_certificate_types[] = { { .val = KMIP_CERTIFICATE_TYPE_X_509, .name = "X_509" }, { .val = KMIP_CERTIFICATE_TYPE_PGP, .name = "PGP" }, { .val = 0, .name = NULL }, }; static const struct kmip_enum kmip_states[] = { { .val = KMIP_STATE_PRE_ACTIVE, .name = "PreActive" }, { .val = KMIP_STATE_ACTIVE, .name = "Active" }, { .val = KMIP_STATE_DEACTIVATED, .name = "Deactivated" }, { .val = KMIP_STATE_COMPROMISED, .name = "Compromised" }, { .val = KMIP_STATE_DESTROYED, .name = "Destroyed" }, { .val = KMIP_STATE_DESTROYED_COMPROMISED, .name = "DestroyedCompromised" }, { .val = 0, .name = NULL }, }; static const struct kmip_enum kmip_protection_storage_masks[] = { { .val = KMIP_PROT_STORAGE_MASK_SOFTWARE, .name = "Software" }, { .val = KMIP_PROT_STORAGE_MASK_HARDWARE, .name = "Hardware" }, { .val = KMIP_PROT_STORAGE_MASK_ON_PROCESSOR, .name = "OnProcessor" }, { .val = KMIP_PROT_STORAGE_MASK_ON_SYSTEM, .name = "OnSystem" }, { .val = KMIP_PROT_STORAGE_MASK_OFF_SYSTEM, .name = "OffSystem" }, { .val = KMIP_PROT_STORAGE_MASK_HYPERVISOR, .name = "Hypervisor" }, { .val = KMIP_PROT_STORAGE_MASK_OPERATING_SYSTEM, .name = "OperatingSystem" }, { .val = KMIP_PROT_STORAGE_MASK_CONTAINER, .name = "Container" }, { .val = KMIP_PROT_STORAGE_MASK_ON_PREMISES, .name = "OnPremises" }, { .val = KMIP_PROT_STORAGE_MASK_OFF_PREMISES, .name = "OffPremises" }, { .val = KMIP_PROT_STORAGE_MASK_SELF_MANAGED, .name = "SelfManaged" }, { .val = KMIP_PROT_STORAGE_MASK_OUTSOURCED, .name = "Outsourced" }, { .val = KMIP_PROT_STORAGE_MASK_VALIDATED, .name = "Validated" }, { .val = KMIP_PROT_STORAGE_MASK_SAME_JURISDICATION, .name = "SameJurisdiction" }, { .val = 0, .name = NULL }, }; static const struct kmip_enum kmip_revoke_reasons[] = { { .val = KMIP_REVOK_RSN_UNSPECIFIED, .name = "Unspecified" }, { .val = KMIP_REVOK_RSN_KEY_COMPROMISE, .name = "KeyCompromise" }, { .val = KMIP_REVOK_RSN_CA_COMPROMISE, .name = "CACompromise" }, { .val = KMIP_REVOK_RSN_AFFILIATION_CHANGED, .name = "AffiliationChanged" }, { .val = KMIP_REVOK_RSN_SUPERSEDED, .name = "Superseded" }, { .val = KMIP_REVOK_RSN_CESSATION_OF_OPERATION, .name = "CessationOfOperation" }, { .val = KMIP_REVOK_RSN_PRIVILEGE_WITHDRAWN, .name = "PrivilegeWithdrawn" }, { .val = 0, .name = NULL }, }; static const struct kmip_enum kmip_object_group_members[] = { { .val = KMIP_OBJ_GROUP_MEMBER_FRESH, .name = "GroupMemberFresh" }, { .val = KMIP_OBJ_GROUP_MEMBER_DEFAULT, .name = "GroupMemberDefault" }, { .val = 0, .name = NULL }, }; static const struct kmip_enum kmip_storage_status_masks[] = { { .val = KMIP_STORAGE_STATUS_MASK_ONLINE, .name = "OnLineStorage" }, { .val = KMIP_STORAGE_STATUS_MASK_ARCHIVAL, .name = "ArchivalStorage" }, { .val = KMIP_STORAGE_STATUS_MASK_DESTTROYED, .name = "DestroyedStorage" }, { .val = 0, .name = NULL }, }; static const struct kmip_enum kmip_key_format_types[] = { { .val = KMIP_KEY_FORMAT_TYPE_RAW, .name = "Raw" }, { .val = KMIP_KEY_FORMAT_TYPE_OPAQUE, .name = "Opaque" }, { .val = KMIP_KEY_FORMAT_TYPE_PKCS_1, .name = "PKCS_1" }, { .val = KMIP_KEY_FORMAT_TYPE_PKCS_8, .name = "PKCS_8" }, { .val = KMIP_KEY_FORMAT_TYPE_X_509, .name = "X_509" }, { .val = KMIP_KEY_FORMAT_TYPE_EC_PRIVATE_KEY, .name = "ECPrivateKey" }, { .val = KMIP_KEY_FORMAT_TYPE_TRANSPARENT_SYMMETRIC_KEY, .name = "TransparentSymmetricKey" }, { .val = KMIP_KEY_FORMAT_TYPE_TRANSPARENT_DSA_PRIVATE_KEY, .name = "TransparentDSAPrivateKey" }, { .val = KMIP_KEY_FORMAT_TYPE_TRANSPARENT_DSA_PUBLIC_KEY, .name = "TransparentDSAPublicKey" }, { .val = KMIP_KEY_FORMAT_TYPE_TRANSPARENT_RSA_PRIVATE_KEY, .name = "TransparentRSAPrivateKey" }, { .val = KMIP_KEY_FORMAT_TYPE_TRANSPARENT_RSA_PUBLIC_KEY, .name = "TransparentRSAPublicKey" }, { .val = KMIP_KEY_FORMAT_TYPE_TRANSPARENT_DH_PRIVATE_KEY, .name = "TransparentDHPrivateKey" }, { .val = KMIP_KEY_FORMAT_TYPE_TRANSPARENT_DH_PUBLIC_KEY, .name = "TransparentDHPublicKey" }, { .val = KMIP_KEY_FORMAT_TYPE_TRANSPARENT_ECDSA_PRIVATE_KEY, .name = "TransparentECDSAPrivateKey" }, { .val = KMIP_KEY_FORMAT_TYPE_TRANSPARENT_ECDSA_PUBLIC_KEY, .name = "TransparentECDSAPublicKey" }, { .val = KMIP_KEY_FORMAT_TYPE_TRANSPARENT_ECDH_PRIVATE_KEY, .name = "TransparentECDHPrivateKey" }, { .val = KMIP_KEY_FORMAT_TYPE_TRANSPARENT_ECDH_PUBLIC_KEY, .name = "TransparentECDHPublicKey" }, { .val = KMIP_KEY_FORMAT_TYPE_TRANSPARENT_ECMQV_PRIVATE_KEY, .name = "TransparentECMQVPrivateKey" }, { .val = KMIP_KEY_FORMAT_TYPE_TRANSPARENT_ECMQV_PUBLIC_KEY, .name = "TransparentECMQVPublicKey" }, { .val = KMIP_KEY_FORMAT_TYPE_TRANSPARENT_EC_PRIVATE_KEY, .name = "TransparentECPrivateKey" }, { .val = KMIP_KEY_FORMAT_TYPE_TRANSPARENT_EC_PUBLIC_KEY, .name = "TransparentECPublicKey" }, { .val = KMIP_KEY_FORMAT_TYPE_PKCS_12, .name = "PKCS_12" }, { .val = KMIP_KEY_FORMAT_TYPE_PKCS_10, .name = "PKCS_10" }, { .val = 0, .name = NULL }, }; static const struct kmip_enum kmip_key_compression_types[] = { { .val = KMIP_KEY_COMPRESSION_TYPE_EC_PUBKEY_UNCOMPRESSED, .name = "ECPublicKeyTypeUncompressed" }, { .val = KMIP_KEY_COMPRESSION_TYPE_EC_PUBKEY_COMPRESSED_PRIME, .name = "ECPublicKeyTypeX9_62CompressedPrime" }, { .val = KMIP_KEY_COMPRESSION_TYPE_EC_PUBKEY_COMPRESSED_CHAR2, .name = "ECPublicKeyTypeX9_62CompressedChar2" }, { .val = KMIP_KEY_COMPRESSION_TYPE_EC_PUBKEY_HYBID, .name = "ECPublicKeyTypeX9_62Hybrid" }, { .val = 0, .name = NULL }, }; static const struct kmip_enum kmip_wrapping_methods[] = { { .val = KMIP_WRAPPING_METHOD_ENCRYPT, .name = "Encrypt" }, { .val = KMIP_WRAPPING_METHOD_MAC_SIGN, .name = "MAC_sign" }, { .val = KMIP_WRAPPING_METHOD_ENCRYPT_THEN_MAC_SIGN, .name = "EncryptThenMAC_sign" }, { .val = KMIP_WRAPPING_METHOD_MAC_SIGN_THEN_ENCRYPT, .name = "MAC_signThenEncrypt" }, { .val = KMIP_WRAPPING_METHOD_TR_31, .name = "TR_31" }, { .val = 0, .name = NULL }, }; static const struct kmip_enum kmip_key_wrap_types[] = { { .val = KMIP_KEY_WRAP_TYPE_NOT_WRAPPED, .name = "NotWrapped" }, { .val = KMIP_KEY_WRAP_TYPE_AS_REGISTERED, .name = "AsRegistered" }, { .val = 0, .name = NULL }, }; static const struct kmip_enum kmip_block_cipher_modes[] = { { .val = KMIP_BLOCK_CIPHER_MODE_CBC, .name = "CBC" }, { .val = KMIP_BLOCK_CIPHER_MODE_ECB, .name = "ECB" }, { .val = KMIP_BLOCK_CIPHER_MODE_PCBC, .name = "PCBC" }, { .val = KMIP_BLOCK_CIPHER_MODE_CFB, .name = "CFB" }, { .val = KMIP_BLOCK_CIPHER_MODE_OFB, .name = "OFB" }, { .val = KMIP_BLOCK_CIPHER_MODE_CTR, .name = "CTR" }, { .val = KMIP_BLOCK_CIPHER_MODE_CMAC, .name = "CMAC" }, { .val = KMIP_BLOCK_CIPHER_MODE_CCM, .name = "CCM" }, { .val = KMIP_BLOCK_CIPHER_MODE_GCM, .name = "GCM" }, { .val = KMIP_BLOCK_CIPHER_MODE_CBC_MAC, .name = "CBC_MAC" }, { .val = KMIP_BLOCK_CIPHER_MODE_XTS, .name = "XTS" }, { .val = KMIP_BLOCK_CIPHER_MODE_AES_KEY_WRAP_PADDING, .name = "AESKeyWrapPadding" }, { .val = KMIP_BLOCK_CIPHER_MODE_NIST_KEY_WRAP, .name = "NISTKeyWrap" }, { .val = KMIP_BLOCK_CIPHER_MODE_X9_102_AESKW, .name = "X9_102AESKW" }, { .val = KMIP_BLOCK_CIPHER_MODE_X9_102_TDKW, .name = "X9_102TDKW" }, { .val = KMIP_BLOCK_CIPHER_MODE_X9_102_AKW1, .name = "X9_102AKW1" }, { .val = KMIP_BLOCK_CIPHER_MODE_X9_102_AKW2, .name = "X9_102AKW2" }, { .val = KMIP_BLOCK_CIPHER_MODE_AEAD, .name = "AEAD" }, { .val = 0, .name = NULL }, }; static const struct kmip_enum kmip_padding_methods[] = { { .val = KMIP_PADDING_METHOD_NONE, .name = "None" }, { .val = KMIP_PADDING_METHOD_OAEP, .name = "OAEP" }, { .val = KMIP_PADDING_METHOD_PKCS5, .name = "PKCS5" }, { .val = KMIP_PADDING_METHOD_SSL3, .name = "SSL3" }, { .val = KMIP_PADDING_METHOD_ZEROS, .name = "Zeros" }, { .val = KMIP_PADDING_METHOD_ANSI_X9_23, .name = "ANSIX9_23" }, { .val = KMIP_PADDING_METHOD_ISO_10126, .name = "ISO10126" }, { .val = KMIP_PADDING_METHOD_PKCS_1_5, .name = "PKCS1V1_5" }, { .val = KMIP_PADDING_METHOD_X9_31, .name = "X9_31" }, { .val = KMIP_PADDING_METHOD_PSS, .name = "PSS" }, { .val = 0, .name = NULL }, }; static const struct kmip_enum kmip_hashing_algos[] = { { .val = KMIP_HASHING_ALGO_MD2, .name = "MD2" }, { .val = KMIP_HASHING_ALGO_MD4, .name = "MD4" }, { .val = KMIP_HASHING_ALGO_MD5, .name = "MD5" }, { .val = KMIP_HASHING_ALGO_SHA_1, .name = "SHA_1" }, { .val = KMIP_HASHING_ALGO_SHA_224, .name = "SHA_224" }, { .val = KMIP_HASHING_ALGO_SHA_256, .name = "SHA_256" }, { .val = KMIP_HASHING_ALGO_SHA_384, .name = "SHA_384" }, { .val = KMIP_HASHING_ALGO_SHA_512, .name = "SHA_512" }, { .val = KMIP_HASHING_ALGO_RIPEMD_160, .name = "RIPEMD_160" }, { .val = KMIP_HASHING_ALGO_TIGER, .name = "Tiger" }, { .val = KMIP_HASHING_ALGO_WIRLPOOL, .name = "Whirlpool" }, { .val = KMIP_HASHING_ALGO_SHA_512_224, .name = "SHA_512_224" }, { .val = KMIP_HASHING_ALGO_SHA_512_256, .name = "SHA_512_256" }, { .val = KMIP_HASHING_ALGO_SHA_3_224, .name = "SHA3_224" }, { .val = KMIP_HASHING_ALGO_SHA_3_256, .name = "SHA3_256" }, { .val = KMIP_HASHING_ALGO_SHA_3_384, .name = "SHA3_384" }, { .val = KMIP_HASHING_ALGO_SHA_3_512, .name = "SHA3_512" }, { .val = 0, .name = NULL }, }; static const struct kmip_enum kmip_key_role_types[] = { { .val = KMIP_KEY_ROLE_TYPE_BDK, .name = "BDK" }, { .val = KMIP_KEY_ROLE_TYPE_CVK, .name = "CVK" }, { .val = KMIP_KEY_ROLE_TYPE_DEK, .name = "DEK" }, { .val = KMIP_KEY_ROLE_TYPE_KMAC, .name = "KMAC" }, { .val = KMIP_KEY_ROLE_TYPE_MKSMC, .name = "MKSMC" }, { .val = KMIP_KEY_ROLE_TYPE_MKSMI, .name = "MKSMI" }, { .val = KMIP_KEY_ROLE_TYPE_MKDAC, .name = "_MKDAC" }, { .val = KMIP_KEY_ROLE_TYPE_MKDN, .name = "MKDN" }, { .val = KMIP_KEY_ROLE_TYPE_MKCP, .name = "MKCP" }, { .val = KMIP_KEY_ROLE_TYPE_MKOTH, .name = "MKOTH" }, { .val = KMIP_KEY_ROLE_TYPE_KEK, .name = "KEK" }, { .val = KMIP_KEY_ROLE_TYPE_MAC16609, .name = "MAC16609" }, { .val = KMIP_KEY_ROLE_TYPE_MAC97971, .name = "MAC97971" }, { .val = KMIP_KEY_ROLE_TYPE_MAC97972, .name = "MAC97972" }, { .val = KMIP_KEY_ROLE_TYPE_MAC97973, .name = "MAC97973" }, { .val = KMIP_KEY_ROLE_TYPE_MAC97974, .name = "MAC97974" }, { .val = KMIP_KEY_ROLE_TYPE_MAC97975, .name = "MAC97975" }, { .val = KMIP_KEY_ROLE_TYPE_ZPK, .name = "ZPK" }, { .val = KMIP_KEY_ROLE_TYPE_PVKIBM, .name = "PVKIBM" }, { .val = KMIP_KEY_ROLE_TYPE_PVKPVV, .name = "PVKPVV" }, { .val = KMIP_KEY_ROLE_TYPE_PVKOTH, .name = "PVKOTH" }, { .val = KMIP_KEY_ROLE_TYPE_DUKPT, .name = "DUKPT" }, { .val = KMIP_KEY_ROLE_TYPE_IV, .name = "IV" }, { .val = KMIP_KEY_ROLE_TYPE_TRKBK, .name = "TRKBK" }, { .val = 0, .name = NULL }, }; static const struct kmip_enum kmip_sinature_algos[] = { { .val = KMIP_SIGNATURE_ALGO_MD2_WITH_RSA_ENCRYPTION, .name = "MD2WithRSAEncryption" }, { .val = KMIP_SIGNATURE_ALGO_MD5_WITH_RSA_ENCRYPTION, .name = "MD5WithRSAEncryption" }, { .val = KMIP_SIGNATURE_ALGO_SHA_1_WITH_RSA_ENCRYPTION, .name = "SHA_1WithRSAEncryption" }, { .val = KMIP_SIGNATURE_ALGO_SHA_224_WITH_RSA_ENCRYPTION, .name = "SHA_244WithRSAEncryption" }, { .val = KMIP_SIGNATURE_ALGO_SHA_256_WITH_RSA_ENCRYPTION, .name = "SHA_256WithRSAEncryption" }, { .val = KMIP_SIGNATURE_ALGO_SHA_384_WITH_RSA_ENCRYPTION, .name = "SHA_384WithRSAEncryption" }, { .val = KMIP_SIGNATURE_ALGO_SHA_512_WITH_RSA_ENCRYPTION, .name = "SHA_512WithRSAEncryption" }, { .val = KMIP_SIGNATURE_ALGO_RSASSA_PSS, .name = "RSASSA_PSS" }, { .val = KMIP_SIGNATURE_ALGO_DSA_WITH_SHA_1, .name = "DSAWithSHA_1" }, { .val = KMIP_SIGNATURE_ALGO_DSA_WITH_SHA_244, .name = "DSAWithSHA224" }, { .val = KMIP_SIGNATURE_ALGO_DSA_WITH_SHA_256, .name = "DSAWithSHA256" }, { .val = KMIP_SIGNATURE_ALGO_ECDSA_WITH_SHA_1, .name = "ECDSAWithSHA_1" }, { .val = KMIP_SIGNATURE_ALGO_ECDSA_WITH_SHA_224, .name = "ECDSAWithSHA224" }, { .val = KMIP_SIGNATURE_ALGO_ECDSA_WITH_SHA_256, .name = "ECDSAWithSHA256" }, { .val = KMIP_SIGNATURE_ALGO_ECDSA_WITH_SHA_384, .name = "ECDSAWithSHA384" }, { .val = KMIP_SIGNATURE_ALGO_ECDSA_WITH_SHA_512, .name = "ECDSAWithSHA512" }, { .val = KMIP_SIGNATURE_ALGO_SHA3_256_WITH_RSA_ENCRYPTION, .name = "SHA3_256WithRSAEncryption" }, { .val = KMIP_SIGNATURE_ALGO_SHA3_385_WITH_RSA_ENCRYPTION, .name = "SHA3_384WithRSAEncryption" }, { .val = KMIP_SIGNATURE_ALGO_SHA3_512_WITH_RSA_ENCRYPTION, .name = "SHA3_512WithRSAEncryption" }, { .val = 0, .name = NULL }, }; static const struct kmip_enum kmip_mask_generators[] = { { .val = KMIP_MASK_GENERATOR_MGF1, .name = "MGF1" }, { .val = 0, .name = NULL }, }; static const struct kmip_enum kmip_encoding_options[] = { { .val = KMIP_ENCODING_OPTION_NO, .name = "NoEncoding" }, { .val = KMIP_ENCODING_OPTION_TTLV, .name = "TTLVEncoding" }, { .val = 0, .name = NULL }, }; static const struct kmip_enum kmip_recommended_cuurves[] = { { .val = KMIP_REC_CURVE_P_192, .name = "P192" }, { .val = KMIP_REC_CURVE_K_163, .name = "K163" }, { .val = KMIP_REC_CURVE_B_163, .name = "B163" }, { .val = KMIP_REC_CURVE_P_224, .name = "P224" }, { .val = KMIP_REC_CURVE_K_223, .name = "K223" }, { .val = KMIP_REC_CURVE_B_223, .name = "B223" }, { .val = KMIP_REC_CURVE_P_256, .name = "P256" }, { .val = KMIP_REC_CURVE_K_283, .name = "K283" }, { .val = KMIP_REC_CURVE_B_283, .name = "B283" }, { .val = KMIP_REC_CURVE_P_384, .name = "P384" }, { .val = KMIP_REC_CURVE_K_409, .name = "K409" }, { .val = KMIP_REC_CURVE_B_409, .name = "B409" }, { .val = KMIP_REC_CURVE_P_521, .name = "P521" }, { .val = KMIP_REC_CURVE_K_571, .name = "K571" }, { .val = KMIP_REC_CURVE_B_571, .name = "B571" }, { .val = KMIP_REC_CURVE_SECP112R1, .name = "Secp112r1" }, { .val = KMIP_REC_CURVE_SECP112R2, .name = "Secp112r2" }, { .val = KMIP_REC_CURVE_SECP128R1, .name = "Secp128r1" }, { .val = KMIP_REC_CURVE_SECP128R2, .name = "Secp128r2" }, { .val = KMIP_REC_CURVE_SECP160K1, .name = "Secp160k1" }, { .val = KMIP_REC_CURVE_SECP160R1, .name = "Secp160r1" }, { .val = KMIP_REC_CURVE_SECP160R2, .name = "Secp160r2" }, { .val = KMIP_REC_CURVE_SECP192K1, .name = "Secp192k1" }, { .val = KMIP_REC_CURVE_SECP224K1, .name = "Secp224k1" }, { .val = KMIP_REC_CURVE_SECP256K1, .name = "Secp256k1" }, { .val = KMIP_REC_CURVE_SECT113R1, .name = "Sect113r1" }, { .val = KMIP_REC_CURVE_SECT113R2, .name = "Sect113r2" }, { .val = KMIP_REC_CURVE_SECT131R1, .name = "Sect131r1" }, { .val = KMIP_REC_CURVE_SECT131R2, .name = "Sect131r2" }, { .val = KMIP_REC_CURVE_SECT163R1, .name = "Sect163r1" }, { .val = KMIP_REC_CURVE_SECT193R1, .name = "Sect193r1" }, { .val = KMIP_REC_CURVE_SECT193R2, .name = "Sect193r2" }, { .val = KMIP_REC_CURVE_SECT239K1, .name = "Sect239k1" }, { .val = KMIP_REC_CURVE_ANSIX9P192V2, .name = "Ansix9p192v2" }, { .val = KMIP_REC_CURVE_ANSIX9P192V3, .name = "Ansix9p192v3" }, { .val = KMIP_REC_CURVE_ANSIX9P239V1, .name = "Ansix9p239v1" }, { .val = KMIP_REC_CURVE_ANSIX9P239V2, .name = "Ansix9p239v2" }, { .val = KMIP_REC_CURVE_ANSIX9P239V3, .name = "Ansix9p239v3" }, { .val = KMIP_REC_CURVE_ANSIX9C2PNB163V1, .name = "Ansix9c2pnb163v1" }, { .val = KMIP_REC_CURVE_ANSIX9C2PNB163V2, .name = "Ansix9c2pnb163v2" }, { .val = KMIP_REC_CURVE_ANSIX9C2PNB163V3, .name = "Ansix9c2pnb163v3" }, { .val = KMIP_REC_CURVE_ANSIX9C2PNB176V1, .name = "Ansix9c2pnb176v1" }, { .val = KMIP_REC_CURVE_ANSIX9C2TNB191V1, .name = "Ansix9c2tnb191v1" }, { .val = KMIP_REC_CURVE_ANSIX9C2TNB191V2, .name = "Ansix9c2tnb191v2" }, { .val = KMIP_REC_CURVE_ANSIX9C2TNB191V3, .name = "Ansix9c2tnb191v3" }, { .val = KMIP_REC_CURVE_ANSIX9C2PNB208W1, .name = "Ansix9c2pnb208w1" }, { .val = KMIP_REC_CURVE_ANSIX9C2TNB239V1, .name = "Ansix9c2tnb239v1" }, { .val = KMIP_REC_CURVE_ANSIX9C2TNB239V2, .name = "Ansix9c2tnb239v2" }, { .val = KMIP_REC_CURVE_ANSIX9C2TNB239V3, .name = "Ansix9c2tnb239v3" }, { .val = KMIP_REC_CURVE_ANSIX9C2PNB272W1, .name = "Ansix9c2pnb272w1" }, { .val = KMIP_REC_CURVE_ANSIX9C2PNB304W1, .name = "Ansix9c2pnb304w1" }, { .val = KMIP_REC_CURVE_ANSIX9C2TNB359V1, .name = "Ansix9c2tnb359v1" }, { .val = KMIP_REC_CURVE_ANSIX9C2PNB368W1, .name = "Ansix9c2pnb368w1" }, { .val = KMIP_REC_CURVE_ANSIX9C2TNB431R1, .name = "Ansix9c2tnb431r1" }, { .val = KMIP_REC_CURVE_BRAINPOOLP160R1, .name = "Brainpoolp160r1" }, { .val = KMIP_REC_CURVE_BRAINPOOLP160T1, .name = "Brainpoolp160t1" }, { .val = KMIP_REC_CURVE_BRAINPOOLP192R1, .name = "Brainpoolp192r1" }, { .val = KMIP_REC_CURVE_BRAINPOOLP192T1, .name = "Brainpoolp192t1" }, { .val = KMIP_REC_CURVE_BRAINPOOLP224R1, .name = "Brainpoolp224r1" }, { .val = KMIP_REC_CURVE_BRAINPOOLP224T1, .name = "Brainpoolp224t1" }, { .val = KMIP_REC_CURVE_BRAINPOOLP256R1, .name = "Brainpoolp256r1" }, { .val = KMIP_REC_CURVE_BRAINPOOLP256T1, .name = "Brainpoolp256t1" }, { .val = KMIP_REC_CURVE_BRAINPOOLP320R1, .name = "Brainpoolp320r1" }, { .val = KMIP_REC_CURVE_BRAINPOOLP320T1, .name = "Brainpoolp320t1" }, { .val = KMIP_REC_CURVE_BRAINPOOLP384R1, .name = "Brainpoolp384r1" }, { .val = KMIP_REC_CURVE_BRAINPOOLP384T1, .name = "Brainpoolp384t1" }, { .val = KMIP_REC_CURVE_BRAINPOOLP512R1, .name = "Brainpoolp512r1" }, { .val = KMIP_REC_CURVE_BRAINPOOLP512T1, .name = "Brainpoolp512t1" }, { .val = KMIP_REC_CURVE_CURVE25519, .name = "Curve25519" }, { .val = KMIP_REC_CURVE_CURVE448, .name = "Curve448" }, { .val = 0, .name = NULL }, }; static const struct kmip_enum kmip_protection_levels[] = { { .val = KMIP_PROTECTION_LEVEL_HIGH, .name = "High" }, { .val = KMIP_PROTECTION_LEVEL_LOW, .name = "Low" }, { .val = 0, .name = NULL }, }; static const struct kmip_enum kmip_key_value_location_types[] = { { .val = KMIP_KEY_VAL_LOC_TYPE_UNINTERPRETED_TEXT_STRING, .name = "UninterpretedTextString" }, { .val = KMIP_KEY_VAL_LOC_TYPE_URI, .name = "URI" }, { .val = 0, .name = NULL }, }; static const struct kmip_enum kmip_link_types[] = { { .val = KMIP_LINK_TYPE_CERTIFICATE, .name = "CertificateLink" }, { .val = KMIP_LINK_TYPE_PUBLIC_KEY, .name = "PublicKeyLink" }, { .val = KMIP_LINK_TYPE_PRIVATE_KEY, .name = "PrivateKeyLink" }, { .val = KMIP_LINK_TYPE_DERIVATION_BASE_OBJECT, .name = "DerivationBaseObjectLink" }, { .val = KMIP_LINK_TYPE_DERIVED_KEY, .name = "DerivedKeyLink" }, { .val = KMIP_LINK_TYPE_REPLACEMENT_OBJECT, .name = "ReplacementObjectLink" }, { .val = KMIP_LINK_TYPE_REPLACED_OBJECT, .name = "ReplacedObjectLink" }, { .val = KMIP_LINK_TYPE_PARENT, .name = "ParentLink" }, { .val = KMIP_LINK_TYPE_CHILD, .name = "ChildLink" }, { .val = KMIP_LINK_TYPE_PREVIOUS, .name = "PreviousLink" }, { .val = KMIP_LINK_TYPE_NEXT, .name = "NextLink" }, { .val = KMIP_LINK_TYPE_PKCS_12_CERTIFICATE, .name = "PKCS_12CertificateLink" }, { .val = KMIP_LINK_TYPE_PKCS_12_PASSWORD, .name = "PKCS_12PasswordLink" }, { .val = KMIP_LINK_TYPE_WRAPPING_KEY, .name = "WrappingKeyLink" }, { .val = 0, .name = NULL }, }; static const struct kmip_enum kmip_client_registration_methods[] = { { .val = KMIP_CLIENT_REG_METH_UNSPECIFIED, .name = "Unspecified" }, { .val = KMIP_CLIENT_REG_METH_SERVER_PRE_GENERATED, .name = "ServerPreGenerated" }, { .val = KMIP_CLIENT_REG_METH_SERVER_ON_DEMAND, .name = "ServerOnDemand" }, { .val = KMIP_CLIENT_REG_METH_CLIENT_GENERATED, .name = "ClientGenerated" }, { .val = KMIP_CLIENT_REG_METH_CLIENT_REGISTERED, .name = "ClientRegistered" }, { .val = 0, .name = NULL }, }; static const struct kmip_enum kmip_rng_algorithms[] = { { .val = KMIP_RNG_ALGO_UNSPECIFIED, .name = "Unspecified" }, { .val = KMIP_RNG_ALGO_FIPS_186_2, .name = "FIPS186_2" }, { .val = KMIP_RNG_ALGO_DRBG, .name = "DRBG" }, { .val = KMIP_RNG_ALGO_NRBG, .name = "NRBG" }, { .val = KMIP_RNG_ALGO_ANSI_X9_31, .name = "ANSIX9_31" }, { .val = KMIP_RNG_ALGO_ANSI_X9_62, .name = "ANSIX9_62" }, { .val = 0, .name = NULL }, }; static const struct kmip_enum kmip_drbg_algorithms[] = { { .val = KMIP_DRBG_ALGO_UNSPECIFIED, .name = "Unspecified" }, { .val = KMIP_DRBG_ALGO_DUAL_EC, .name = "Dual_EC" }, { .val = KMIP_DRBG_ALGO_HASH, .name = "Hash" }, { .val = KMIP_DRBG_ALGO_HMAC, .name = "HMAC" }, { .val = KMIP_DRBG_ALGO_CTR, .name = "CTR" }, { .val = 0, .name = NULL }, }; static const struct kmip_enum kmip_fips186_variations[] = { { .val = KMIP_FIPS186_VARI_UNSPECIFIED, .name = "Unspecified" }, { .val = KMIP_FIPS186_VARI_GP_X_ORIGINAL, .name = "GPxOriginal" }, { .val = KMIP_FIPS186_VARI_GP_X_CHANGE_NOTICE, .name = "GPxChangeNotice" }, { .val = KMIP_FIPS186_VARI_X_ORIGINAL, .name = "XOriginal" }, { .val = KMIP_FIPS186_VARI_X_CHANGE_NOTICE, .name = "XChangeNotice" }, { .val = KMIP_FIPS186_VARI_K_ORIGINAL, .name = "KOriginal" }, { .val = KMIP_FIPS186_VARI_K_CHANGE_NOTICE, .name = "KChangeNotice" }, { .val = 0, .name = NULL }, }; static const struct kmip_enum kmip_validation_authority_types[] = { { .val = KMIP_VALIDATION_AUTH_TYPE_UNSPECIFIED, .name = "Unspecified" }, { .val = KMIP_VALIDATION_AUTH_TYPE_NIST_CMVP, .name = "NISTCMVP" }, { .val = KMIP_VALIDATION_AUTH_TYPE_COMMON_CRITERIA, .name = "CommonCriteria" }, { .val = 0, .name = NULL }, }; static const struct kmip_enum kmip_validation_types[] = { { .val = KMIP_VALIDATION_TYPE_UNSPECIFIED, .name = "Unspecified" }, { .val = KMIP_VALIDATION_TYPE_HARDWARE, .name = "Hardware" }, { .val = KMIP_VALIDATION_TYPE_SOFTWARE, .name = "Software" }, { .val = KMIP_VALIDATION_TYPE_FIRMWARE, .name = "Firmware" }, { .val = KMIP_VALIDATION_TYPE_HYBRID, .name = "Hybrid" }, { .val = 0, .name = NULL }, }; static const struct kmip_enum kmip_unwrap_modes[] = { { .val = KMIP_UNWRAP_MODE_UNSPECIFIED, .name = "Unspecified" }, { .val = KMIP_UNWRAP_MODE_PROCESSED, .name = "Processed" }, { .val = KMIP_UNWRAP_MODE_NOT_PROCESSED, .name = "NotProcessed" }, { .val = 0, .name = NULL }, }; static const struct kmip_enum kmip_destroy_actions[] = { { .val = KMIP_DESTROY_ACTION_UNSPECIFIED, .name = "Unspecified" }, { .val = KMIP_DESTROY_ACTION_KEY_MATERIAL_DELETED, .name = "KeyMaterialDeleted" }, { .val = KMIP_DESTROY_ACTION_KEY_MATERIAL_SHREDDED, .name = "KeyMaterialShredded" }, { .val = KMIP_DESTROY_ACTION_META_DATA_DELETED, .name = "MetaDataDeleted" }, { .val = KMIP_DESTROY_ACTION_META_DATA_SHREDDED, .name = "MetaDataShredded" }, { .val = KMIP_DESTROY_ACTION_DELETED, .name = "Deleted" }, { .val = KMIP_DESTROY_ACTION_SHREDDED, .name = "Shredded" }, { .val = 0, .name = NULL }, }; static const struct kmip_enum kmip_shredding_algorithms[] = { { .val = KMIP_SHREDDING_ALGO_UNSPECIFIED, .name = "Unspecified" }, { .val = KMIP_SHREDDING_ALGO_CRYPTOGRAPHIC, .name = "Cryptographic" }, { .val = KMIP_SHREDDING_ALGO_UNSUPPORTED, .name = "Unsupported" }, { .val = 0, .name = NULL }, }; static const struct kmip_enum kmip_rng_modes[] = { { .val = KMIP_RNG_MODE_UNSPECIFIED, .name = "Unspecified" }, { .val = KMIP_RNG_MODE_SHARED_INSTANTIATION, .name = "SharedInstantiation" }, { .val = KMIP_RNG_MODE_NON_SHARED_INSTANCIATION, .name = "NonSharedInstantiation" }, { .val = 0, .name = NULL }, }; static const struct kmip_enum kmip_profile_names[] = { { .val = KMIP_PROFILE_BASELINE_SERVER_BASIC_KMIP_V1_2, .name = "BaselineServerBasicKMIPV1_2" }, { .val = KMIP_PROFILE_BASELINE_SERVER_TLS_V1_2_KMIP_V1_2, .name = "BaselineServerTLSV1_2KMIPV1_2" }, { .val = KMIP_PROFILE_BASELINE_CLIENT_BASIC_KMIP_V1_2, .name = "BaselineClientBasicKMIPV1_2" }, { .val = KMIP_PROFILE_BASELINE_CLIENT_TLS_V1_2_KMIP_V1_2, .name = "BaselineClientTLSV1_2KMIPV1_2" }, { .val = KMIP_PROFILE_COMPLETE_SERVER_BASIC_KMIP_V1_2, .name = "CompleteServerBasicKMIPV1_2" }, { .val = KMIP_PROFILE_COMPLETE_SERVER_TLS_V1_2_KMIP_V1_2, .name = "CompleteServerTLSV1_2KMIPV1_2" }, { .val = KMIP_PROFILE_TAPE_LIBRARY_CLIENT_KMIP_V1_0, .name = "TapeLibraryClientKMIPV1_0" }, { .val = KMIP_PROFILE_TAPE_LIBRARY_CLIENT_KMIP_V1_1, .name = "TapeLibraryClientKMIPV1_1" }, { .val = KMIP_PROFILE_TAPE_LIBRARY_CLIENT_KMIP_V1_2, .name = "TapeLibraryClientKMIPV1_2" }, { .val = KMIP_PROFILE_TAPE_LIBRARY_SERVER_KMIP_V1_0, .name = "TapeLibraryServerKMIPV1_0" }, { .val = KMIP_PROFILE_TAPE_LIBRARY_SERVER_KMIP_V1_1, .name = "TapeLibraryServerKMIPV1_1" }, { .val = KMIP_PROFILE_TAPE_LIBRARY_SERVER_KMIP_V1_2, .name = "TapeLibraryServerKMIPV1_2" }, { .val = KMIP_PROFILE_SYMMETRIC_KEY_LIFECYCLE_CLIENT_KMIP_V1_0, .name = "SymmetricKeyLifecycleClientKMIPV1_0" }, { .val = KMIP_PROFILE_SYMMETRIC_KEY_LIFECYCLE_CLIENT_KMIP_V1_1, .name = "SymmetricKeyLifecycleClientKMIPV1_1" }, { .val = KMIP_PROFILE_SYMMETRIC_KEY_LIFECYCLE_CLIENT_KMIP_V1_2, .name = "SymmetricKeyLifecycleClientKMIPV1_2" }, { .val = KMIP_PROFILE_SYMMETRIC_KEY_LIFECYCLE_SERVER_KMIP_V1_0, .name = "SymmetricKeyLifecycleServerKMIPV1_0" }, { .val = KMIP_PROFILE_SYMMETRIC_KEY_LIFECYCLE_SERVER_KMIP_V1_1, .name = "SymmetricKeyLifecycleServerKMIPV1_1" }, { .val = KMIP_PROFILE_SYMMETRIC_KEY_LIFECYCLE_SERVER_KMIP_V1_2, .name = "SymmetricKeyLifecycleServerKMIPV1_2" }, { .val = KMIP_PROFILE_ASYMMETRIC_KEY_LIFECYCLE_CLIENT_KMIP_V1_0, .name = "AsymmetricKeyLifecycleClientKMIPV1_0" }, { .val = KMIP_PROFILE_ASYMMETRIC_KEY_LIFECYCLE_CLIENT_KMIP_V1_1, .name = "AsymmetricKeyLifecycleClientKMIPV1_1" }, { .val = KMIP_PROFILE_ASYMMETRIC_KEY_LIFECYCLE_CLIENT_KMIP_V1_2, .name = "AsymmetricKeyLifecycleClientKMIPV1_2" }, { .val = KMIP_PROFILE_ASYMMETRIC_KEY_LIFECYCLE_SERVER_KMIP_V1_0, .name = "AsymmetricKeyLifecycleServerKMIPV1_0" }, { .val = KMIP_PROFILE_ASYMMETRIC_KEY_LIFECYCLE_SERVER_KMIP_V1_1, .name = "AsymmetricKeyLifecycleServerKMIPV1_1" }, { .val = KMIP_PROFILE_ASYMMETRIC_KEY_LIFECYCLE_SERVER_KMIP_V1_2, .name = "AsymmetricKeyLifecycleServerKMIPV1_2" }, { .val = KMIP_PROFILE_BASIC_CRYPTOGRAPHIC_CLIENT_KMIP_V1_2, .name = "BasicCryptographicClientKMIPV1_2" }, { .val = KMIP_PROFILE_BASIC_CRYPTOGRAPHIC_SERVER_KMIP_V1_2, .name = "BasicCryptographicServerKMIPV1_2" }, { .val = KMIP_PROFILE_ADVANCED_CRYPTOGRAPHIC_CLIENT_KMIP_V1_2, .name = "AdvancedCryptographicClientKMIPV1_2" }, { .val = KMIP_PROFILE_ADVANCED_CRYPTOGRAPHIC_SERVER_KMIP_V1_2, .name = "AdvancedCryptographicServerKMIPV1_2" }, { .val = KMIP_PROFILE_RNG_CRYPTOGRAPHIC_CLIENT_KMIP_V1_2, .name = "RNGCryptographicClientKMIPV1_2" }, { .val = KMIP_PROFILE_RNG_CRYPTOGRAPHIC_SERVER_KMIP_V1_2, .name = "RNGCryptographicServerKMIPV1_2" }, { .val = KMIP_PROFILE_BASIC_SYMMETRIC_KEY_FOUNDRY_CLIENT_KMIP_V1_0, .name = "BasicSymmetricKeyFoundryClientKMIPV1_0" }, { .val = KMIP_PROFILE_INTERMEDIATE_SYMMETRIC_KEY_FOUNDRY_CLIENT_KMIP_V1_0, .name = "IntermediateSymmetricKeyFoundryClientKMIPV1_0" }, { .val = KMIP_PROFILE_ADVANCED_SYMMETRIC_KEY_FOUNDRY_CLIENT_KMIP_V1_0, .name = "AdvancedSymmetricKeyFoundryClientKMIPV1_0" }, { .val = KMIP_PROFILE_BASIC_SYMMETRIC_KEY_FOUNDRY_CLIENT_KMIP_V1_1, .name = "BasicSymmetricKeyFoundryClientKMIPV1_1" }, { .val = KMIP_PROFILE_INTERMEDIATE_SYMMETRIC_KEY_FOUNDRY_CLIENT_KMIP_V1_1, .name = "IntermediateSymmetricKeyFoundryClientKMIPV1_1" }, { .val = KMIP_PROFILE_ADVANCED_SYMMETRIC_KEY_FOUNDRY_CLIENT_KMIP_V1_1, .name = "AdvancedSymmetricKeyFoundryClientKMIPV1_1" }, { .val = KMIP_PROFILE_BASIC_SYMMETRIC_KEY_FOUNDRY_CLIENT_KMIP_V1_2, .name = "BasicSymmetricKeyFoundryClientKMIPV1_2" }, { .val = KMIP_PROFILE_INTERMEDIATE_SYMMETRIC_KEY_FOUNDRY_CLIENT_KMIP_V1_2, .name = "IntermediateSymmetricKeyFoundryClientKMIPV1_2" }, { .val = KMIP_PROFILE_ADVANCED_SYMMETRIC_KEY_FOUNDRY_CLIENT_KMIP_V1_2, .name = "AdvancedSymmetricKeyFoundryClientKMIPV1_2" }, { .val = KMIP_PROFILE_SYMMETRIC_KEY_FOUNDRY_SERVER_KMIP_V1_0, .name = "SymmetricKeyFoundryServerKMIPV1_0" }, { .val = KMIP_PROFILE_SYMMETRIC_KEY_FOUNDRY_SERVER_KMIP_V1_1, .name = "SymmetricKeyFoundryServerKMIPV1_1" }, { .val = KMIP_PROFILE_SYMMETRIC_KEY_FOUNDRY_SERVER_KMIP_V1_2, .name = "SymmetricKeyFoundryServerKMIPV1_2" }, { .val = KMIP_PROFILE_OPAQUE_MANAGED_OBJECT_STORE_CLIENT_KMIP_V1_0, .name = "OpaqueManagedObjectStoreClientKMIPV1_0" }, { .val = KMIP_PROFILE_OPAQUE_MANAGED_OBJECT_STORE_CLIENT_KMIP_V1_1, .name = "OpaqueManagedObjectStoreClientKMIPV1_1" }, { .val = KMIP_PROFILE_OPAQUE_MANAGED_OBJECT_STORE_CLIENT_KMIP_V1_2, .name = "OpaqueManagedObjectStoreClientKMIPV1_2" }, { .val = KMIP_PROFILE_OPAQUE_MANAGED_OBJECT_STORE_SERVER_KMIP_V1_0, .name = "OpaqueManagedObjectStoreServerKMIPV1_0" }, { .val = KMIP_PROFILE_OPAQUE_MANAGED_OBJECT_STORE_SERVER_KMIP_V1_1, .name = "OpaqueManagedObjectStoreServerKMIPV1_1" }, { .val = KMIP_PROFILE_OPAQUE_MANAGED_OBJECT_STORE_SERVER_KMIP_V1_2, .name = "OpaqueManagedObjectStoreServerKMIPV1_2" }, { .val = KMIP_PROFILE_SUITE_B_MINLOS_128_CLIENT_KMIP_V1_0, .name = "SuiteBMinLOS_128ClientKMIPV1_0" }, { .val = KMIP_PROFILE_SUITE_B_MINLOS_128_CLIENT_KMIP_V1_1, .name = "SuiteBMinLOS_128ClientKMIPV1_1" }, { .val = KMIP_PROFILE_SUITE_B_MINLOS_128_CLIENT_KMIP_V1_2, .name = "SuiteBMinLOS_128ClientKMIPV1_2" }, { .val = KMIP_PROFILE_SUITE_B_MINLOS_128_SERVER_KMIP_V1_0, .name = "SuiteBMinLOS_128ServerKMIPV1_0" }, { .val = KMIP_PROFILE_SUITE_B_MINLOS_128_SERVER_KMIP_V1_1, .name = "SuiteBMinLOS_128ServerKMIPV1_1" }, { .val = KMIP_PROFILE_SUITE_B_MINLOS_128_SERVER_KMIP_V1_2, .name = "SuiteBMinLOS_128ServerKMIPV1_2" }, { .val = KMIP_PROFILE_SUITE_B_MINLOS_192_CLIENT_KMIP_V1_0, .name = "SuiteBMinLOS_192ClientKMIPV1_0" }, { .val = KMIP_PROFILE_SUITE_B_MINLOS_192_CLIENT_KMIP_V1_1, .name = "SuiteBMinLOS_192ClientKMIPV1_1" }, { .val = KMIP_PROFILE_SUITE_B_MINLOS_192_CLIENT_KMIP_V1_2, .name = "SuiteBMinLOS_192ClientKMIPV1_2" }, { .val = KMIP_PROFILE_SUITE_B_MINLOS_192_SERVER_KMIP_V1_0, .name = "SuiteBMinLOS_192ServerKMIPV1_0" }, { .val = KMIP_PROFILE_SUITE_B_MINLOS_192_SERVER_KMIP_V1_1, .name = "SuiteBMinLOS_192ServerKMIPV1_1" }, { .val = KMIP_PROFILE_SUITE_B_MINLOS_192_SERVER_KMIP_V1_2, .name = "SuiteBMinLOS_192ServerKMIPV1_2" }, { .val = KMIP_PROFILE_STORAGE_ARRAY_WITH_SELF_ENCRYPTING_DRIVE_CLIENT_KMIP_V1_0, .name = "StorageArrayWithSelfEncryptingDriveClientKMIPV1_0" }, { .val = KMIP_PROFILE_STORAGE_ARRAY_WITH_SELF_ENCRYPTING_DRIVE_CLIENT_KMIP_V1_1, .name = "StorageArrayWithSelfEncryptingDriveClientKMIPV1_1" }, { .val = KMIP_PROFILE_STORAGE_ARRAY_WITH_SELF_ENCRYPTING_DRIVE_CLIENT_KMIP_V1_2, .name = "StorageArrayWithSelfEncryptingDriveClientKMIPV1_2" }, { .val = KMIP_PROFILE_STORAGE_ARRAY_WITH_SELF_ENCRYPTING_DRIVE_SERVER_KMIP_V1_0, .name = "StorageArrayWithSelfEncryptingDriveServerKMIPV1_0" }, { .val = KMIP_PROFILE_STORAGE_ARRAY_WITH_SELF_ENCRYPTING_DRIVE_SERVER_KMIP_V1_1, .name = "StorageArrayWithSelfEncryptingDriveServerKMIPV1_1" }, { .val = KMIP_PROFILE_STORAGE_ARRAY_WITH_SELF_ENCRYPTING_DRIVE_SERVER_KMIP_V1_2, .name = "StorageArrayWithSelfEncryptingDriveServerKMIPV1_2" }, { .val = KMIP_PROFILE_HTTPS_CLIENT_KMIP_V1_0, .name = "HTTPSClientKMIPV1_0" }, { .val = KMIP_PROFILE_HTTPS_CLIENT_KMIP_V1_1, .name = "HTTPSClientKMIPV1_1" }, { .val = KMIP_PROFILE_HTTPS_CLIENT_KMIP_V1_2, .name = "HTTPSClientKMIPV1_2" }, { .val = KMIP_PROFILE_HTTPS_SERVER_KMIP_V1_0, .name = "HTTPSServerKMIPV1_0" }, { .val = KMIP_PROFILE_HTTPS_SERVER_KMIP_V1_1, .name = "HTTPSServerKMIPV1_1" }, { .val = KMIP_PROFILE_HTTPS_SERVER_KMIP_V1_2, .name = "HTTPSServerKMIPV1_2" }, { .val = KMIP_PROFILE_JSON_CLIENT_KMIP_V1_0, .name = "JSONClientKMIPV1_0" }, { .val = KMIP_PROFILE_JSON_CLIENT_KMIP_V1_1, .name = "JSONClientKMIPV1_1" }, { .val = KMIP_PROFILE_JSON_CLIENT_KMIP_V1_2, .name = "JSONClientKMIPV1_2" }, { .val = KMIP_PROFILE_JSON_SERVER_KMIP_V1_0, .name = "JSONServerKMIPV1_0" }, { .val = KMIP_PROFILE_JSON_SERVER_KMIP_V1_1, .name = "JSONServerKMIPV1_1" }, { .val = KMIP_PROFILE_JSON_SERVER_KMIP_V1_2, .name = "JSONServerKMIPV1_2" }, { .val = KMIP_PROFILE_XML_CLIENT_KMIP_V1_0, .name = "XMLClientKMIPV1_0" }, { .val = KMIP_PROFILE_XML_CLIENT_KMIP_V1_1, .name = "XMLClientKMIPV1_1" }, { .val = KMIP_PROFILE_XML_CLIENT_KMIP_V1_2, .name = "XMLClientKMIPV1_2" }, { .val = KMIP_PROFILE_XML_SERVER_KMIP_V1_0, .name = "XMLServerKMIPV1_0" }, { .val = KMIP_PROFILE_XML_SERVER_KMIP_V1_1, .name = "XMLServerKMIPV1_1" }, { .val = KMIP_PROFILE_XML_SERVER_KMIP_V1_2, .name = "XMLServerKMIPV1_2" }, { .val = KMIP_PROFILE_BASELINE_SERVER_BASIC_KMIP_V1_3, .name = "BaselineServerBasicKMIPV1_3" }, { .val = KMIP_PROFILE_BASELINE_SERVER_TLS_V1_2_KMIP_V1_3, .name = "BaselineServerTLSV1_2KMIPV1_3" }, { .val = KMIP_PROFILE_BASELINE_CLIENT_BASIC_KMIP_V1_3, .name = "BaselineClientBasicKMIPV1_3" }, { .val = KMIP_PROFILE_BASELINE_CLIENT_TLS_V1_2_KMIP_V1_3, .name = "BaselineClientTLSV1_2KMIPV1_3" }, { .val = KMIP_PROFILE_COMPLETE_SERVER_BASIC_KMIP_V1_3, .name = "CompleteServerBasicKMIPV1_3" }, { .val = KMIP_PROFILE_COMPLETE_SERVER_TLS_V1_2_KMIP_V1_3, .name = "CompleteServerTLSV1_2KMIPV1_3" }, { .val = KMIP_PROFILE_TAPE_LIBRARY_CLIENT_KMIP_V1_3, .name = "TapeLibraryClientKMIPV1_3" }, { .val = KMIP_PROFILE_TAPE_LIBRARY_SERVER_KMIP_V1_3, .name = "TapeLibraryServerKMIPV1_3" }, { .val = KMIP_PROFILE_SYMMETRIC_KEY_LIFECYCLE_CLIENT_KMIP_V1_3, .name = "SymmetricKeyLifecycleClientKMIPV1_3" }, { .val = KMIP_PROFILE_SYMMETRIC_KEY_LIFECYCLE_SERVER_KMIP_V1_3, .name = "SymmetricKeyLifecycleServerKMIPV1_3" }, { .val = KMIP_PROFILE_ASYMMETRIC_KEY_LIFECYCLE_CLIENT_KMIP_V1_3, .name = "AsymmetricKeyLifecycleClientKMIPV1_3" }, { .val = KMIP_PROFILE_ASYMMETRIC_KEY_LIFECYCLE_SERVER_KMIP_V1_3, .name = "AsymmetricKeyLifecycleServerKMIPV1_3" }, { .val = KMIP_PROFILE_BASIC_CRYPTOGRAPHIC_CLIENT_KMIP_V1_3, .name = "BasicCryptographicClientKMIPV1_3" }, { .val = KMIP_PROFILE_BASIC_CRYPTOGRAPHIC_SERVER_KMIP_V1_3, .name = "BasicCryptographicServerKMIPV1_3" }, { .val = KMIP_PROFILE_ADVANCED_CRYPTOGRAPHIC_CLIENT_KMIP_V1_3, .name = "AdvancedCryptographicClientKMIPV1_3" }, { .val = KMIP_PROFILE_ADVANCED_CRYPTOGRAPHIC_SERVER_KMIP_V1_3, .name = "AdvancedCryptographicServerKMIPV1_3" }, { .val = KMIP_PROFILE_RNG_CRYPTOGRAPHIC_CLIENT_KMIP_V1_3, .name = "RNGCryptographicClientKMIPV1_3" }, { .val = KMIP_PROFILE_RNG_CRYPTOGRAPHIC_SERVER_KMIP_V1_3, .name = "RNGCryptographicServerKMIPV1_3" }, { .val = KMIP_PROFILE_BASIC_SYMMETRIC_KEY_FOUNDRY_CLIENT_KMIP_V1_3, .name = "BasicSymmetricKeyFoundryClientKMIPV1_3" }, { .val = KMIP_PROFILE_INTERMEDIATE_SYMMETRIC_KEY_FOUNDRY_CLIENT_KMIP_V1_3, .name = "IntermediateSymmetricKeyFoundryClientKMIPV1_3" }, { .val = KMIP_PROFILE_ADVANCED_SYMMETRIC_KEY_FOUNDRY_CLIENT_KMIP_V1_3, .name = "AdvancedSymmetricKeyFoundryClientKMIPV1_3" }, { .val = KMIP_PROFILE_SYMMETRIC_KEY_FOUNDRY_SERVER_KMIP_V1_3, .name = "SymmetricKeyFoundryServerKMIPV1_3" }, { .val = KMIP_PROFILE_OPAQUE_MANAGED_OBJECT_STORE_CLIENT_KMIP_V1_3, .name = "OpaqueManagedObjectStoreClientKMIPV1_3" }, { .val = KMIP_PROFILE_OPAQUE_MANAGED_OBJECT_STORE_SERVER_KMIP_V1_3, .name = "OpaqueManagedObjectStoreServerKMIPV1_3" }, { .val = KMIP_PROFILE_SUITE_B_MINLOS_128_CLIENT_KMIP_V1_3, .name = "SuiteBMinLOS_128ClientKMIPV1_3" }, { .val = KMIP_PROFILE_SUITE_B_MINLOS_128_SERVER_KMIP_V1_3, .name = "SuiteBMinLOS_128ServerKMIPV1_3" }, { .val = KMIP_PROFILE_SUITE_B_MINLOS_192_CLIENT_KMIP_V1_3, .name = "SuiteBMinLOS_192ClientKMIPV1_3" }, { .val = KMIP_PROFILE_SUITE_B_MINLOS_192_SERVER_KMIP_V1_3, .name = "SuiteBMinLOS_192ServerKMIPV1_3" }, { .val = KMIP_PROFILE_STORAGE_ARRAY_WITH_SELF_ENCRYPTING_DRIVE_CLIENT_KMIP_V1_3, .name = "StorageArrayWithSelfEncryptingDriveClientKMIPV1_3" }, { .val = KMIP_PROFILE_STORAGE_ARRAY_WITH_SELF_ENCRYPTING_DRIVE_SERVER_KMIP_V1_3, .name = "StorageArrayWithSelfEncryptingDriveServerKMIPV1_3" }, { .val = KMIP_PROFILE_HTTPS_CLIENT_KMIP_V1_3, .name = "HTTPSClientKMIPV1_3" }, { .val = KMIP_PROFILE_HTTPS_SERVER_KMIP_V1_3, .name = "HTTPSServerKMIPV1_3" }, { .val = KMIP_PROFILE_JSON_CLIENT_KMIP_V1_3, .name = "JSONClientKMIPV1_3" }, { .val = KMIP_PROFILE_JSON_SERVER_KMIP_V1_3, .name = "JSONServerKMIPV1_3" }, { .val = KMIP_PROFILE_XML_CLIENT_KMIP_V1_3, .name = "XMLClientKMIPV1_3" }, { .val = KMIP_PROFILE_XML_SERVER_KMIP_V1_3, .name = "XMLServerKMIPV1_3" }, { .val = KMIP_PROFILE_BASELINE_SERVER_BASIC_KMIP_V1_4, .name = "BaselineServerBasicKMIPV1_4" }, { .val = KMIP_PROFILE_BASELINE_SERVER_TLS_V1_2_KMIP_V1_4, .name = "BaselineServerTLSV1_2KMIPV1_4" }, { .val = KMIP_PROFILE_BASELINE_CLIENT_BASIC_KMIP_V1_4, .name = "BaselineClientBasicKMIPV1_4" }, { .val = KMIP_PROFILE_BASELINE_CLIENT_TLS_V1_2_KMIP_V1_4, .name = "BaselineClientTLSV1_2KMIPV1_4" }, { .val = KMIP_PROFILE_COMPLETE_SERVER_BASIC_KMIP_V1_4, .name = "CompleteServerBasicKMIPV1_4" }, { .val = KMIP_PROFILE_COMPLETE_SERVER_TLS_V1_2_KMIP_V1_4, .name = "CompleteServerTLSV1_2KMIPV1_4" }, { .val = KMIP_PROFILE_TAPE_LIBRARY_CLIENT_KMIP_V1_4, .name = "TapeLibraryClientKMIPV1_4" }, { .val = KMIP_PROFILE_TAPE_LIBRARY_SERVER_KMIP_V1_4, .name = "TapeLibraryServerKMIPV1_4" }, { .val = KMIP_PROFILE_SYMMETRIC_KEY_LIFECYCLE_CLIENT_KMIP_V1_4, .name = "SymmetricKeyLifecycleClientKMIPV1_4" }, { .val = KMIP_PROFILE_SYMMETRIC_KEY_LIFECYCLE_SERVER_KMIP_V1_4, .name = "SymmetricKeyLifecycleServerKMIPV1_4" }, { .val = KMIP_PROFILE_ASYMMETRIC_KEY_LIFECYCLE_CLIENT_KMIP_V1_4, .name = "AsymmetricKeyLifecycleClientKMIPV1_4" }, { .val = KMIP_PROFILE_ASYMMETRIC_KEY_LIFECYCLE_SERVER_KMIP_V1_4, .name = "AsymmetricKeyLifecycleServerKMIPV1_4" }, { .val = KMIP_PROFILE_BASIC_CRYPTOGRAPHIC_CLIENT_KMIP_V1_4, .name = "BasicCryptographicClientKMIPV1_4" }, { .val = KMIP_PROFILE_BASIC_CRYPTOGRAPHIC_SERVER_KMIP_V1_4, .name = "BasicCryptographicServerKMIPV1_4" }, { .val = KMIP_PROFILE_ADVANCED_CRYPTOGRAPHIC_CLIENT_KMIP_V1_4, .name = "AdvancedCryptographicClientKMIPV1_4" }, { .val = KMIP_PROFILE_ADVANCED_CRYPTOGRAPHIC_SERVER_KMIP_V1_4, .name = "AdvancedCryptographicServerKMIPV1_4" }, { .val = KMIP_PROFILE_RNG_CRYPTOGRAPHIC_CLIENT_KMIP_V1_4, .name = "RNGCryptographicClientKMIPV1_4" }, { .val = KMIP_PROFILE_RNG_CRYPTOGRAPHIC_SERVER_KMIP_V1_4, .name = "RNGCryptographicServerKMIPV1_4" }, { .val = KMIP_PROFILE_BASIC_SYMMETRIC_KEY_FOUNDRY_CLIENT_KMIP_V1_4, .name = "BasicSymmetricKeyFoundryClientKMIPV1_4" }, { .val = KMIP_PROFILE_INTERMEDIATE_SYMMETRIC_KEY_FOUNDRY_CLIENT_KMIP_V1_4, .name = "IntermediateSymmetricKeyFoundryClientKMIPV1_4" }, { .val = KMIP_PROFILE_ADVANCED_SYMMETRIC_KEY_FOUNDRY_CLIENT_KMIP_V1_4, .name = "AdvancedSymmetricKeyFoundryClientKMIPV1_4" }, { .val = KMIP_PROFILE_SYMMETRIC_KEY_FOUNDRY_SERVER_KMIP_V1_4, .name = "SymmetricKeyFoundryServerKMIPV1_4" }, { .val = KMIP_PROFILE_OPAQUE_MANAGED_OBJECT_STORE_CLIENT_KMIP_V1_4, .name = "OpaqueManagedObjectStoreClientKMIPV1_4" }, { .val = KMIP_PROFILE_OPAQUE_MANAGED_OBJECT_STORE_SERVER_KMIP_V1_4, .name = "OpaqueManagedObjectStoreServerKMIPV1_4" }, { .val = KMIP_PROFILE_SUITE_B_MINLOS_128_CLIENT_KMIP_V1_4, .name = "SuiteBMinLOS_128ClientKMIPV1_4" }, { .val = KMIP_PROFILE_SUITE_B_MINLOS_128_SERVER_KMIP_V1_4, .name = "SuiteBMinLOS_128ServerKMIPV1_4" }, { .val = KMIP_PROFILE_SUITE_B_MINLOS_192_CLIENT_KMIP_V1_4, .name = "SuiteBMinLOS_192ClientKMIPV1_4" }, { .val = KMIP_PROFILE_SUITE_B_MINLOS_192_SERVER_KMIP_V1_4, .name = "SuiteBMinLOS_192ServerKMIPV1_4" }, { .val = KMIP_PROFILE_STORAGE_ARRAY_WITH_SELF_ENCRYPTING_DRIVE_CLIENT_KMIP_V1_4, .name = "StorageArrayWithSelfEncryptingDriveClientKMIPV1_4" }, { .val = KMIP_PROFILE_STORAGE_ARRAY_WITH_SELF_ENCRYPTING_DRIVE_SERVER_KMIP_V1_4, .name = "StorageArrayWithSelfEncryptingDriveServerKMIPV1_4" }, { .val = KMIP_PROFILE_HTTPS_CLIENT_KMIP_V1_4, .name = "HTTPSClientKMIPV1_4" }, { .val = KMIP_PROFILE_HTTPS_SERVER_KMIP_V1_4, .name = "HTTPSServerKMIPV1_4" }, { .val = KMIP_PROFILE_JSON_CLIENT_KMIP_V1_4, .name = "JSONClientKMIPV1_4" }, { .val = KMIP_PROFILE_JSON_SERVER_KMIP_V1_4, .name = "JSONServerKMIPV1_4" }, { .val = KMIP_PROFILE_XML_CLIENT_KMIP_V1_4, .name = "XMLClientKMIPV1_4" }, { .val = KMIP_PROFILE_XML_SERVER_KMIP_V1_4, .name = "XMLServerKMIPV1_4" }, { .val = KMIP_PROFILE_COMPLETE_SERVER_BASIC, .name = "CompleteServerBasic" }, { .val = KMIP_PROFILE_COMPLETE_SERVER_TLS_V1_2, .name = "CompleteServerTLSV1_2" }, { .val = KMIP_PROFILE_TAPE_LIBRARY_CLIENT, .name = "TapeLibraryClient" }, { .val = KMIP_PROFILE_TAPE_LIBRARY_SERVER, .name = "TapeLibraryServer" }, { .val = KMIP_PROFILE_SYMMETRIC_KEY_LIFECYCLE_CLIENT, .name = "SymmetricKeyLifecycleClient" }, { .val = KMIP_PROFILE_SYMMETRIC_KEY_LIFECYCLE_SERVER, .name = "SymmetricKeyLifecycleServer" }, { .val = KMIP_PROFILE_ASYMMETRIC_KEY_LIFECYCLE_CLIENT, .name = "AsymmetricKeyLifecycleClient" }, { .val = KMIP_PROFILE_ASYMMETRIC_KEY_LIFECYCLE_SERVER, .name = "AsymmetricKeyLifecycleServer" }, { .val = KMIP_PROFILE_BASIC_CRYPTOGRAPHIC_CLIENT, .name = "BasicCryptographicClient" }, { .val = KMIP_PROFILE_BASIC_CRYPTOGRAPHIC_SERVER, .name = "BasicCryptographicServer" }, { .val = KMIP_PROFILE_ADVANCED_CRYPTOGRAPHIC_CLIENT, .name = "AdvancedCryptographicClient" }, { .val = KMIP_PROFILE_ADVANCED_CRYPTOGRAPHIC_SERVER, .name = "AdvancedCryptographicServer" }, { .val = KMIP_PROFILE_RNG_CRYPTOGRAPHIC_CLIENT, .name = "RNGCryptographicClient" }, { .val = KMIP_PROFILE_RNG_CRYPTOGRAPHIC_SERVER, .name = "RNGCryptographicServer" }, { .val = KMIP_PROFILE_BASIC_SYMMETRIC_KEY_FOUNDRY_CLIENT, .name = "BasicSymmetricKeyFoundryClient" }, { .val = KMIP_PROFILE_INTERMEDIATE_SYMMETRIC_KEY_FOUNDRY_CLIENT, .name = "IntermediateSymmetricKeyFoundryClient" }, { .val = KMIP_PROFILE_ADVANCED_SYMMETRIC_KEY_FOUNDRY_CLIENT, .name = "AdvancedSymmetricKeyFoundryClient" }, { .val = KMIP_PROFILE_SYMMETRIC_KEY_FOUNDRY_SERVER, .name = "SymmetricKeyFoundryServer" }, { .val = KMIP_PROFILE_OPAQUE_MANAGED_OBJECT_STORE_CLIENT, .name = "OpaqueManagedObjectStoreClient" }, { .val = KMIP_PROFILE_OPAQUE_MANAGED_OBJECT_STORE_SERVER, .name = "OpaqueManagedObjectStoreServer" }, { .val = KMIP_PROFILE_STORAGE_ARRAY_WITH_SELF_ENCRYPTING_DRIVE_CLIENT, .name = "StorageArrayWithSelfEncryptingDriveClient" }, { .val = KMIP_PROFILE_STORAGE_ARRAY_WITH_SELF_ENCRYPTING_DRIVE_SERVER, .name = "StorageArrayWithSelfEncryptingDriveServer" }, { .val = KMIP_PROFILE_HTTPS_CLIENT, .name = "HTTPSClient" }, { .val = KMIP_PROFILE_HTTPS_SERVER, .name = "HTTPSServer" }, { .val = KMIP_PROFILE_JSON_CLIENT, .name = "JSONClient" }, { .val = KMIP_PROFILE_JSON_SERVER, .name = "JSONServer" }, { .val = KMIP_PROFILE_XML_CLIENT, .name = "XMLClient" }, { .val = KMIP_PROFILE_XML_SERVER, .name = "XMLServer" }, { .val = KMIP_PROFILE_AES_XTS_CLIENT, .name = "AESXTSClient" }, { .val = KMIP_PROFILE_AES_XTS_SERVER, .name = "AESXTSServer" }, { .val = KMIP_PROFILE_QUANTUM_SAFE_CLIENT, .name = "QuantumSafeClient" }, { .val = KMIP_PROFILE_QUANTUM_SAFE_SERVER, .name = "QuantumSafeServer" }, { .val = KMIP_PROFILE_PKCS_11_CLIENT, .name = "PKCS_11Client" }, { .val = KMIP_PROFILE_PKCS_11_SERVER, .name = "PKCS_11Server" }, { .val = KMIP_PROFILE_BASELINE_CLIENT, .name = "BaselineClient" }, { .val = KMIP_PROFILE_BASELINE_SERVER, .name = "BaselineServer" }, { .val = KMIP_PROFILE_COMPLETE_SERVER, .name = "CompleteServer" }, { .val = 0, .name = NULL }, }; struct kmip_enum_info { enum kmip_tag tag; const struct kmip_enum *enum_info; bool is_mask; }; static const struct kmip_enum_info enum_info[] = { { .tag = KMIP_TAG_ATTRIBUTE_REFERENCE, .enum_info = kmip_tags, .is_mask = false }, { .tag = KMIP_TAG_OPERATION, .enum_info = kmip_operations, .is_mask = false }, { .tag = KMIP_TAG_BATCH_ERROR_CONTINUATION_OPTION, .enum_info = kmip_batch_error_cont_options, .is_mask = false }, { .tag = KMIP_TAG_CRYPTOGRAPHIC_USAGE_MASK, .enum_info = kmip_crypto_usage_masks, .is_mask = true }, { .tag = KMIP_TAG_RESULT_STATUS, .enum_info = kmip_result_statuses, .is_mask = false }, { .tag = KMIP_TAG_RESULT_REASON, .enum_info = kmip_result_reasons, .is_mask = false }, { .tag = KMIP_TAG_QUERY_FUNCTION, .enum_info = kmip_query_functions, .is_mask = false }, { .tag = KMIP_TAG_NAME_TYPE, .enum_info = kmip_name_types, .is_mask = false }, { .tag = KMIP_TAG_ALTERNATE_NAME_TYPE, .enum_info = kmip_alternate_name_types, .is_mask = false }, { .tag = KMIP_TAG_UNIQUE_IDENTIFIER, .enum_info = kmip_unique_identifiers, .is_mask = false }, { .tag = KMIP_TAG_OBJECT_TYPE, .enum_info = kmip_object_types, .is_mask = false }, { .tag = KMIP_TAG_CRYPTOGRAPHIC_ALGORITHM, .enum_info = kmip_crypto_algos, .is_mask = false }, { .tag = KMIP_TAG_CERTIFICATE_TYPE, .enum_info = kmip_certificate_types, .is_mask = false }, { .tag = KMIP_TAG_STATE, .enum_info = kmip_states, .is_mask = false }, { .tag = KMIP_TAG_PROTECTION_STORAGE_MASK, .enum_info = kmip_protection_storage_masks, .is_mask = true }, { .tag = KMIP_TAG_REVOCATION_REASON_CODE, .enum_info = kmip_revoke_reasons, .is_mask = false }, { .tag = KMIP_TAG_OBJECT_GROUP_MEMBER, .enum_info = kmip_object_group_members, .is_mask = false }, { .tag = KMIP_TAG_STORAGE_STATUS_MASK, .enum_info = kmip_storage_status_masks, .is_mask = true }, { .tag = KMIP_TAG_KEY_FORMAT_TYPE, .enum_info = kmip_key_format_types, .is_mask = false }, { .tag = KMIP_TAG_KEY_COMPRESSION_TYPE, .enum_info = kmip_key_compression_types, .is_mask = false }, { .tag = KMIP_TAG_WRAPPING_METHOD, .enum_info = kmip_wrapping_methods, .is_mask = false }, { .tag = KMIP_TAG_KEY_WRAP_TYPE, .enum_info = kmip_key_wrap_types, .is_mask = false }, { .tag = KMIP_TAG_BLOCK_CIPHER_MODE, .enum_info = kmip_block_cipher_modes, .is_mask = false }, { .tag = KMIP_TAG_PADDING_METHOD, .enum_info = kmip_padding_methods, .is_mask = false }, { .tag = KMIP_TAG_HASHING_ALGORITHM, .enum_info = kmip_hashing_algos, .is_mask = false }, { .tag = KMIP_TAG_MASK_GENERATOR_HASHING_ALGORITHM, .enum_info = kmip_hashing_algos, .is_mask = false }, { .tag = KMIP_TAG_KEY_ROLE_TYPE, .enum_info = kmip_key_role_types, .is_mask = false }, { .tag = KMIP_TAG_DIGITAL_SIGNATURE_ALGORITHM, .enum_info = kmip_sinature_algos, .is_mask = false }, { .tag = KMIP_TAG_MASK_GENERATOR, .enum_info = kmip_mask_generators, .is_mask = false }, { .tag = KMIP_TAG_ENCODING_OPTION, .enum_info = kmip_encoding_options, .is_mask = false }, { .tag = KMIP_TAG_RECOMMENDED_CURVE, .enum_info = kmip_recommended_cuurves, .is_mask = false }, { .tag = KMIP_TAG_PROTECTION_LEVEL, .enum_info = kmip_protection_levels, .is_mask = false }, { .tag = KMIP_TAG_KEY_VALUE_LOCATION_TYPE, .enum_info = kmip_key_value_location_types, .is_mask = false }, { .tag = KMIP_TAG_LINK_TYPE, .enum_info = kmip_link_types, .is_mask = false }, { .tag = KMIP_TAG_CLIENT_REGISTRATION_METHOD, .enum_info = kmip_client_registration_methods, .is_mask = false }, { .tag = KMIP_TAG_RNG_ALGORITHM, .enum_info = kmip_rng_algorithms, .is_mask = false }, { .tag = KMIP_TAG_DRBG_ALGORITHM, .enum_info = kmip_drbg_algorithms, .is_mask = false }, { .tag = KMIP_TAG_FIPS186_VARIANT, .enum_info = kmip_fips186_variations, .is_mask = false }, { .tag = KMIP_TAG_VALIDATION_AUTHORITY_TYPE, .enum_info = kmip_validation_authority_types, .is_mask = false }, { .tag = KMIP_TAG_VALIDATION_TYPE, .enum_info = kmip_validation_types, .is_mask = false }, { .tag = KMIP_TAG_UNWRAP_MODE, .enum_info = kmip_unwrap_modes, .is_mask = false }, { .tag = KMIP_TAG_DESTROY_ACTION, .enum_info = kmip_destroy_actions, .is_mask = false }, { .tag = KMIP_TAG_SHREDDING_ALGORITHM, .enum_info = kmip_shredding_algorithms, .is_mask = false }, { .tag = KMIP_TAG_RNG_MODE, .enum_info = kmip_rng_modes, .is_mask = false }, { .tag = KMIP_TAG_PROFILE_NAME, .enum_info = kmip_profile_names, .is_mask = false }, { .tag = 0, .enum_info = NULL, .is_mask = false }, }; static const struct kmip_enum kmip_v1_attribute_names[] = { { .val = KMIP_TAG_UNIQUE_IDENTIFIER, .name = "Unique Identifier" }, { .val = KMIP_TAG_NAME, .name = "Name" }, { .val = KMIP_TAG_OBJECT_TYPE, .name = "Object Type" }, { .val = KMIP_TAG_CRYPTOGRAPHIC_ALGORITHM, .name = "Cryptographic Algorithm" }, { .val = KMIP_TAG_CRYPTOGRAPHIC_DOMAIN_PARAMETERS, .name = "Cryptographic Domain Parameters" }, { .val = KMIP_TAG_CRYPTOGRAPHIC_LENGTH, .name = "Cryptographic Length" }, { .val = KMIP_TAG_CRYPTOGRAPHIC_PARAMETERS, .name = "Cryptographic Parameters" }, { .val = KMIP_TAG_CERTIFICATE_TYPE, .name = "Certificate Type" }, { .val = KMIP_TAG_CERTIFICATE_IDENTIFIER, .name = "Certificate Identifier" }, { .val = KMIP_TAG_CERTIFICATE_ISSUER, .name = "Certificate Issuer" }, { .val = KMIP_TAG_CERTIFICATE_SUBJECT, .name = "Certificate Subject" }, { .val = KMIP_TAG_DIGEST, .name = "Digest" }, { .val = KMIP_TAG_OPERATION_POLICY_NAME, .name = "Operation Policy Name" }, { .val = KMIP_TAG_CRYPTOGRAPHIC_USAGE_MASK, .name = "Cryptographic Usage Mask" }, { .val = KMIP_TAG_LEASE_TIME, .name = "Lease Time" }, { .val = KMIP_TAG_USAGE_LIMITS, .name = "Usage Limits" }, { .val = KMIP_TAG_STATE, .name = "State" }, { .val = KMIP_TAG_INITIAL_DATE, .name = "Initial Date" }, { .val = KMIP_TAG_ACTIVATION_DATE, .name = "Activation Date" }, { .val = KMIP_TAG_PROCESS_START_DATE, .name = "Process Start Date" }, { .val = KMIP_TAG_PROTECT_STOP_DATE, .name = "Protect Stop Date" }, { .val = KMIP_TAG_DEACTIVATION_DATE, .name = "Deactivation Date" }, { .val = KMIP_TAG_DESTROY_DATE, .name = "Destroy Date" }, { .val = KMIP_TAG_COMPROMISE_OCCURRENCE_DATE, .name = "Compromise Occurrence Date" }, { .val = KMIP_TAG_COMPROMIZE_DATE, .name = "Compromise Date" }, { .val = KMIP_TAG_REVOCATION_REASON, .name = "Revocation Reason" }, { .val = KMIP_TAG_ARCHIVE_DATE, .name = "Archive Date" }, { .val = KMIP_TAG_OBJECT_GROUP, .name = "Object Group" }, { .val = KMIP_TAG_LINK, .name = "Link" }, { .val = KMIP_TAG_APPLICATION_SPECIFIC_INFORMATION, .name = "Application Specific Information" }, { .val = KMIP_TAG_CONTACT_INFORMATION, .name = "Contact Information" }, { .val = KMIP_TAG_LAST_CHANGE_DATE, .name = "Last Change Date" }, { .val = KMIP_TAG_CUSTOM_ATTRIBUTE, .name = "Custom Attribute" }, { .val = KMIP_TAG_ALTERNATE_NAME, .name = "Alternative Name" }, { .val = KMIP_TAG_KEY_VALUE_PRESENT, .name = "Key Value Present" }, { .val = KMIP_TAG_KEY_VALUE_LOCATION, .name = "Key Value Location" }, { .val = KMIP_TAG_ORIGINAL_CREATION_DATE, .name = "Original Creation Date" }, { .val = KMIP_TAG_RANDOM_NUMBER_GENERATOR, .name = "Random Number Generator" }, { .val = KMIP_TAG_PKCS_12_FRIENDLY_NAME, .name = "PKCS#12 Friendly Name" }, { .val = KMIP_TAG_DESCRIPTION, .name = "Description" }, { .val = KMIP_TAG_COMMENT, .name = "Comment" }, { .val = KMIP_TAG_SENSITIVE, .name = "Sensitive" }, { .val = KMIP_TAG_ALWAYS_SENSITIVE, .name = "Always Sensitive" }, { .val = KMIP_TAG_EXTRACTABLE, .name = "Extractable" }, { .val = KMIP_TAG_NEVER_EXTRACTABLE, .name = "Never Extractable" }, /* * KMIP v2.x attribute names (just for reference, will most likely * not appear in a v1.x attribute list */ { .val = KMIP_TAG_CERTIFICATE_SUBJECT_CN, .name = "Certificate Subject CN" }, { .val = KMIP_TAG_CERTIFICATE_SUBJECT_O, .name = "Certificate Subject O" }, { .val = KMIP_TAG_CERTIFICATE_SUBJECT_OU, .name = "Certificate Subject OU" }, { .val = KMIP_TAG_CERTIFICATE_SUBJECT_EMAIL, .name = "Certificate Subject Email" }, { .val = KMIP_TAG_CERTIFICATE_SUBJECT_C, .name = "Certificate Subject C" }, { .val = KMIP_TAG_CERTIFICATE_SUBJECT_ST, .name = "Certificate Subject ST" }, { .val = KMIP_TAG_CERTIFICATE_SUBJECT_L, .name = "Certificate Subject L" }, { .val = KMIP_TAG_CERTIFICATE_SUBJECT_UID, .name = "Certificate Subject UID" }, { .val = KMIP_TAG_CERTIFICATE_SUBJECT_SERIAL_NUMBER, .name = "Certificate Subject Serial Number" }, { .val = KMIP_TAG_CERTIFICATE_SUBJECT_TITLE, .name = "Certificate Subject Title" }, { .val = KMIP_TAG_CERTIFICATE_SUBJECT_DC, .name = "Certificate Subject DC" }, { .val = KMIP_TAG_CERTIFICATE_SUBJECT_DN_QUALIFIER, .name = "Certificate Subject DN Qualifier" }, { .val = KMIP_TAG_CERTIFICATE_ISSUER_CN, .name = "Certificate Issuer CN" }, { .val = KMIP_TAG_CERTIFICATE_ISSUER_O, .name = "Certificate Issuer O" }, { .val = KMIP_TAG_CERTIFICATE_ISSUER_OU, .name = "Certificate Issuer OU" }, { .val = KMIP_TAG_CERTIFICATE_ISSUER_EMAIL, .name = "Certificate Issuer Email" }, { .val = KMIP_TAG_CERTIFICATE_ISSUER_C, .name = "Certificate Issuer C" }, { .val = KMIP_TAG_CERTIFICATE_ISSUER_ST, .name = "Certificate Issuer ST" }, { .val = KMIP_TAG_CERTIFICATE_ISSUER_L, .name = "Certificate Issuer L" }, { .val = KMIP_TAG_CERTIFICATE_ISSUER_UID, .name = "Certificate Issuer UID" }, { .val = KMIP_TAG_CERTIFICATE_ISSUER_SERIAL_NUMBER, .name = "Certificate Issuer Serial Number" }, { .val = KMIP_TAG_CERTIFICATE_ISSUER_TITLE, .name = "Certificate Issuer Title" }, { .val = KMIP_TAG_CERTIFICATE_ISSUER_DC, .name = "Certificate Issuer DC" }, { .val = KMIP_TAG_CERTIFICATE_ISSUER_DN_QUALIFIER, .name = "Certificate Issuer DN Qualifier" }, { .val = KMIP_TAG_CERTIFICATE_TYPE, .name = "Certificate Type" }, { .val = KMIP_TAG_CERTIFICATE_LENGTH, .name = "Certificate Length" }, { .val = KMIP_TAG_DIGITAL_SIGNATURE_ALGORITHM, .name = "Digital Signature Algorithm" }, { .val = KMIP_TAG_FRESH, .name = "Fresh" }, { .val = KMIP_TAG_KEY_FORMAT_TYPE, .name = "Key Format Type" }, { .val = KMIP_TAG_NIST_KEY_TYPE, .name = "NIST Key Type" }, { .val = KMIP_TAG_OPAQUE_DATA_TYPE, .name = "Opaque Data Type" }, { .val = KMIP_TAG_PROTECTION_LEVEL, .name = "Protection Level" }, { .val = KMIP_TAG_PROTECTION_PERIOD, .name = "Protection Period" }, { .val = KMIP_TAG_PROTECTION_STORAGE_MASK, .name = "Protection Storage Mask" }, { .val = KMIP_TAG_QUANTUM_SAFE, .name = "Quantum Safe" }, { .val = KMIP_TAG_SHORT_UNIQUE_IDENTIFIER, .name = "Short Unique Identifier" }, { .val = KMIP_TAG_ATTRIBUTE, .name = "Vendor Attribute" }, { .val = KMIP_TAG_X_509_CERTIFICATE_IDENTIFIER, .name = "X.509 Certificate Identifier" }, { .val = KMIP_TAG_X_509_CERTIFICATE_ISSUER, .name = "X.509 Certificate Issuer" }, { .val = KMIP_TAG_X_509_CERTIFICATE_SUBJECT, .name = "X.509 Certificate Subject" }, { .val = 0, .name = NULL }, }; /** * Return the name of the enumeration value, or NULL if the value is unknown */ static const char *kmip_enum_name_by_value(const struct kmip_enum *info, uint32_t val) { unsigned int i; for (i = 0; info[i].name != NULL; i++) { if (info[i].val == val) return info[i].name; } return NULL; } /** * Return the enumeration value specified as enumeration name, or in hex * notation. */ int kmip_enum_value_by_name_or_hex(const struct kmip_enum *info, const char *name, uint32_t *value) { unsigned int i; int64_t val; int rc; if (name == NULL || value == NULL) return -EINVAL; for (i = 0; info[i].name != NULL; i++) { if (strcmp(info[i].name, name) == 0) { *value = info[i].val; return 0; } } rc = kmip_parse_hex_int(name, &val); if (rc != 0) return rc; *value = val; return 0; } /* * Get the name of an enumeration value belonging to the specified tag */ const char *kmip_enum_name_by_tag_value(enum kmip_tag tag, uint32_t val) { int i; for (i = 0; enum_info[i].enum_info != NULL; i++) { if (enum_info[i].tag != tag) continue; return kmip_enum_name_by_value(enum_info[i].enum_info, val); } return NULL; } /** * Return the enumeration value belonging to the specified tag, specified as * enumeration name, or in hex notation. */ int kmip_enum_value_by_tag_name_or_hex(enum kmip_tag tag, const char *name, uint32_t *value) { int64_t val; int i, rc; if (name == NULL || value == NULL) return -EINVAL; for (i = 0; enum_info[i].enum_info != NULL; i++) { if (enum_info[i].tag != tag) continue; return kmip_enum_value_by_name_or_hex(enum_info[i].enum_info, name, value); } rc = kmip_parse_hex_int(name, &val); if (rc != 0) return rc; *value = val; return 0; } /** * Return the name of the tag, or NULL if the tag is unknown */ const char *kmip_tag_name_by_tag(enum kmip_tag tag) { return kmip_enum_name_by_value(kmip_tags, tag); } /** * Return the name or the hex representation of the tag */ const char *kmip_tag_name_or_hex_by_tag(enum kmip_tag tag, char tmp_buff[20]) { const char *str; str = kmip_enum_name_by_value(kmip_tags, tag); if (str == NULL) { sprintf(tmp_buff, "0x%06x", tag); str = tmp_buff; } return str; } /** * Return the tag value specified as tag name, or in hex notation. Returns 0 * in case of an error. */ enum kmip_tag kmip_tag_by_name_or_hex(const char *name) { uint32_t val; int rc; rc = kmip_enum_value_by_name_or_hex(kmip_tags, name, &val); if (rc != 0) return 0; return val; } /** * Return the name of the type, or NULL if the type is unknown */ const char *kmip_type_name_by_type(enum kmip_type type) { return kmip_enum_name_by_value(kmip_types, type); } /** * Return the type value specified as type name, or in hex notation. Returns 0 * in case of an error. */ enum kmip_type kmip_type_by_name_or_hex(const char *name) { uint32_t val; int rc; rc = kmip_enum_value_by_name_or_hex(kmip_types, name, &val); if (rc != 0) return 0; return val; } /** * Return the KMIP v1.x attribute name of the tag, or NULL if the tag is unknown */ const char *kmip_v1_attr_name_by_tag(enum kmip_tag attr_tag) { return kmip_enum_name_by_value(kmip_v1_attribute_names, attr_tag); } /** * Return the attribute tag value specified as KMIP v1.x attribute name. * Returns 0 in case of an error. */ enum kmip_tag kmip_attr_tag_by_v1_attr_name(const char *name) { uint32_t val; int rc; rc = kmip_enum_value_by_name_or_hex(kmip_v1_attribute_names, name, &val); if (rc != 0) return 0; return val; } /** * Returns true if the tag is a mask */ bool kmip_is_tag_mask(enum kmip_tag tag) { int i; for (i = 0; enum_info[i].enum_info != NULL; i++) { if (enum_info[i].tag != tag) continue; return enum_info[i].is_mask; } return false; } /** * Returns the enumeration info for the specified tag, or NULL, if the tag * is not associated with an enumeration. */ const struct kmip_enum *kmip_enum_info_by_tag(enum kmip_tag tag) { int i; for (i = 0; enum_info[i].enum_info != NULL; i++) { if (enum_info[i].tag != tag) continue; return enum_info[i].enum_info; } return NULL; } opencryptoki-opencryptoki-451d99c/usr/sbin/p11kmip/kmipclient/names.h000066400000000000000000000025111520105705100257640ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021-2024 * * 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 NAMES_H #define NAMES_H #include #include "kmip.h" struct kmip_enum { uint32_t val; const char *name; }; const struct kmip_enum *kmip_enum_info_by_tag(enum kmip_tag tag); bool kmip_is_tag_mask(enum kmip_tag tag); int kmip_enum_value_by_name_or_hex(const struct kmip_enum *info, const char *name, uint32_t *value); const char *kmip_enum_name_by_tag_value(enum kmip_tag tag, uint32_t val); int kmip_enum_value_by_tag_name_or_hex(enum kmip_tag tag, const char *name, uint32_t *value); const char *kmip_tag_name_by_tag(enum kmip_tag tag); const char *kmip_tag_name_or_hex_by_tag(enum kmip_tag tag, char tmp_buff[20]); enum kmip_tag kmip_tag_by_name_or_hex(const char *name); const char *kmip_type_name_by_type(enum kmip_type type); enum kmip_type kmip_type_by_name_or_hex(const char *name); const char *kmip_v1_attr_name_by_tag(enum kmip_tag attr_tag); enum kmip_tag kmip_attr_tag_by_v1_attr_name(const char *name); #endif opencryptoki-opencryptoki-451d99c/usr/sbin/p11kmip/kmipclient/request.c000066400000000000000000001614011520105705100263500ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021-2024 * * 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 _DEFAULT_SOURCE #include #include #include "kmip.h" #include "names.h" /** * Constructs a Protocol Version node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Protocol Version Structure v1.0 * Protocol Version Major Yes Integer v1.0 * Protocol Version Minor Yes Integer v1.0 * * @param version the protocol version * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_protocol_version(const struct kmip_version *version) { struct kmip_node *ret = NULL, *maj, *min; if (version == NULL) return NULL; maj = kmip_node_new_integer(KMIP_TAG_PROTOCOL_VERSION_MAJOR, NULL, version->major); min = kmip_node_new_integer(KMIP_TAG_PROTOCOL_VERSION_MINOR, NULL, version->minor); if (maj == NULL || min == NULL) goto out; ret = kmip_node_new_structure_va(KMIP_TAG_PROTOCOL_VERSION, NULL, 2, maj, min); out: kmip_node_free(maj); kmip_node_free(min); return ret; } /** * Constructs a Profile Version node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Profile Version Structure v1.0 * Profile Version Major Yes Integer v1.0 * Profile Version Minor Yes Integer v1.0 * * @param version the profile version * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_profile_version(const struct kmip_version *version) { struct kmip_node *ret = NULL, *maj, *min; if (version == NULL) return NULL; maj = kmip_node_new_integer(KMIP_TAG_PROFILE_VERSION_MAJOR, NULL, version->major); min = kmip_node_new_integer(KMIP_TAG_PROFILE_VERSION_MINOR, NULL, version->minor); if (maj == NULL || min == NULL) goto out; ret = kmip_node_new_structure_va(KMIP_TAG_PROFILE_VERSION, NULL, 2, maj, min); out: kmip_node_free(maj); kmip_node_free(min); return ret; } /** * Constructs a Request Header node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Request Header Yes Structure v1.0 * Protocol Version Yes Structure v1.0 * Maximum Response Size No Integer v1.0 * Client Correlation Value No Text String v1.4 * Server Correlation Value No Text String v1.4 * Asynchronous Indicator No Boolean v1.0 * Attestation Capable Indic. No Boolean v1.2 * Attestation Type No Enumeration v1.2 * ... may be repeated * Authentication No Structure v1.0 * Batch Error Cont. Option No Enumeration v1.0 * Batch Order Option No Boolean v1.0 * Time Stamp No Date Time v1.0 * Batch Count Yes Integer v1.0 * * @param version the protocol version. If NULL, the default * protocol version is used * @param max_response_size the maximum response size. Ignored if <= 0. * @param client_corr_value the client correlation value. Ignored if NULL. * @param server_corr_value the server correlation value. Ignored if NULL. * @param asynchronous if true the request is asynchronous * @param authentication the authentication node (can be NULL) * @param batch_err_opt the batch error continuation option. Ignored if 0, * or if batch_count is less than 2. * @param batch_order_option the batch order option (true = execute in order) * @param batch_count the batch count * * @returns the allocated node, or NULL in case of an error. * The reference counts of the nodes specified as parameters which are added to * the newly allocated node are increased. The caller must free its reference * via kmip_node_free() if no longer needed. */ struct kmip_node *kmip_new_request_header(const struct kmip_version *version, int32_t max_response_size, const char *client_corr_value, const char *server_corr_value, bool asynchronous, struct kmip_node *authentication, enum kmip_batch_error_cont_option batch_err_opt, bool batch_order_option, int32_t batch_count) { struct kmip_node *ret = NULL, *err = NULL, *async = NULL, *tim = NULL; struct kmip_node *max = NULL, *cnt = NULL, *ord = NULL, *ver = NULL; struct kmip_node *ccorr = NULL, *scorr = NULL; if (version == NULL) version = kmip_get_default_protocol_version(); ver = kmip_new_protocol_version(version); if (ver == NULL) goto out; if (max_response_size > 0) { max = kmip_node_new_integer(KMIP_TAG_MAXIMUM_RESPONSE_SIZE, NULL, max_response_size); if (max == NULL) goto out; } if (version->major == 1 && version->minor <= 3) { client_corr_value = NULL; server_corr_value = NULL; } if (client_corr_value) { ccorr = kmip_node_new_text_string( KMIP_TAG_CLIENT_CORRELATION_VALUE, NULL, client_corr_value); if (ccorr == NULL) goto out; } if (server_corr_value) { scorr = kmip_node_new_text_string( KMIP_TAG_SERVER_CORRELATION_VALUE, NULL, server_corr_value); if (scorr == NULL) goto out; } if (asynchronous) { async = kmip_node_new_boolean(KMIP_TAG_ASYNCHRONOUS_INDICATOR, NULL, asynchronous); if (async == NULL) goto out; } if (batch_err_opt != 0 && batch_count > 1) { err = kmip_node_new_enumeration( KMIP_TAG_BATCH_ERROR_CONTINUATION_OPTION, NULL, batch_err_opt); if (err == NULL) goto out; } ord = kmip_node_new_boolean(KMIP_TAG_BATCH_ORDER_OPTION, NULL, batch_order_option); if (ord == NULL) goto out; tim = kmip_node_new_date_time(KMIP_TAG_TIME_STAMP, NULL, time(NULL)); if (tim == NULL) goto out; cnt = kmip_node_new_integer(KMIP_TAG_BATCH_COUNT, NULL, batch_count); if (cnt == NULL) goto out; ret = kmip_node_new_structure_va(KMIP_TAG_REQUEST_HEADER, NULL, 10, ver, max, ccorr, scorr, authentication, async, err, ord, tim, cnt); out: kmip_node_free(ver); kmip_node_free(max); kmip_node_free(ccorr); kmip_node_free(scorr); kmip_node_free(async); kmip_node_free(err); kmip_node_free(ord); kmip_node_free(tim); kmip_node_free(cnt); return ret; } /** * Constructs a Request Batch Item node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Batch Item Yes Structure v1.0 * Operation Yes Enumeration v1.0 * Ephemeral No Boolean v2.0 * Unique Batch Item ID No Byte String v1.0 * Request Payload Yes Structure v1.0 * Message Extension No Structure v1.0 * * @param operation the operation * @param authentication A batch_id (can be NULL, req. if batch count > 0) * @param batch_id_length the size of the batch ID * @param payload the payload node * * @returns the allocated node, or NULL in case of an error. * The reference counts of the nodes specified as parameters which are added to * the newly allocated node are increased. The caller must free its reference * via kmip_node_free() if no longer needed. */ struct kmip_node *kmip_new_request_batch_item(enum kmip_operation operation, unsigned char *batch_id, uint32_t batch_id_length, struct kmip_node *payload) { struct kmip_node *ret = NULL, *op, *bid = NULL; if (payload == NULL) return NULL; op = kmip_node_new_enumeration(KMIP_TAG_OPERATION, NULL, operation); if (op == NULL) return NULL; if (batch_id != NULL && batch_id_length > 0) { bid = kmip_node_new_byte_string(KMIP_TAG_UNIQUE_BATCH_ITEM_ID, NULL, batch_id, batch_id_length); if (bid == NULL) goto out; } ret = kmip_node_new_structure_va(KMIP_TAG_BATCH_ITEM, NULL, 3, op, bid, payload); out: kmip_node_free(op); kmip_node_free(bid); return ret; } /** * Constructs a Request Message node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Request Message Yes Structure v1.0 * Request Header Yes Structure v1.0 * Batch Item Yes Structure v1.0 * ... may be repeated * * @param request_header the request header node * @param batch_count the number of batch items to add * @parambatch_items array of batch items * * @returns the allocated node, or NULL in case of an error. * The reference counts of the nodes specified as parameters which are added to * the newly allocated node are increased. The caller must free its reference * via kmip_node_free() if no longer needed. */ struct kmip_node *kmip_new_request(struct kmip_node *request_header, int32_t batch_count, struct kmip_node **batch_items) { struct kmip_node *ret; int rc = 0; if (request_header == NULL) return NULL; ret = kmip_node_new_structure_va(KMIP_TAG_REQUEST_MESSAGE, NULL, 1, request_header); if (ret == NULL) return NULL; rc = kmip_node_add_structure_elements(ret, batch_count, batch_items); if (rc != 0) goto error; return ret; error: kmip_node_free(ret); return NULL; } /** * Constructs a Request Message node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Request Message Yes Structure v1.0 * Request Header Yes Structure v1.0 * Batch Item Yes Structure v1.0 * ... may be repeated * * @param request_header the request header node * @param batch_count the number of batch items following * @param batch items (struct kmip_node *) * * @returns the allocated node, or NULL in case of an error. * The reference counts of the nodes specified as parameters which are added to * the newly allocated node are increased. The caller must free its reference * via kmip_node_free() if no longer needed. */ struct kmip_node *kmip_new_request_va(struct kmip_node *request_header, int32_t batch_count, ...) { struct kmip_node *ret, **bis = NULL; va_list ap; int32_t i; if (request_header == NULL) return NULL; if (batch_count > 0) { bis = calloc(batch_count, sizeof(struct kmip_node *)); if (bis == NULL) return NULL; } va_start(ap, batch_count); for (i = 0; i < batch_count; i++) bis[i] = va_arg(ap, struct kmip_node *); va_end(ap); ret = kmip_new_request(request_header, batch_count, bis); if (bis != NULL) free(bis); return ret; } /** * Constructs a Query request payload: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Query Function Yes Enumeration v1.0 * ... may be repeated * * @param query_count the number of query function items following * @param functions query function items * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_query_request_payload(unsigned int query_count, const enum kmip_query_function *functions) { struct kmip_node *rpl, *qf = NULL; unsigned int i; int rc = 0; if (query_count > 0 && functions == NULL) return NULL; rpl = kmip_node_new_structure_va(KMIP_TAG_REQUEST_PAYLOAD, NULL, 0); if (rpl == NULL) return NULL; for (i = 0; i < query_count; i++) { qf = kmip_node_new_enumeration(KMIP_TAG_QUERY_FUNCTION, NULL, functions[i]); if (qf == NULL) goto error; rc = kmip_node_add_structure_element(rpl, qf); if (rc != 0) break; kmip_node_free(qf); qf = NULL; } if (rc != 0) goto error; return rpl; error: kmip_node_free(rpl); kmip_node_free(qf); return NULL; } /** * Constructs a Query request payload: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Query Function Yes Enumeration v1.0 * ... may be repeated * * @param query_count the number of query function items following * @param query items (enum kmip_query_function) * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_query_request_payload_va(unsigned int query_count, ...) { enum kmip_query_function *qfs = NULL; struct kmip_node *rpl; unsigned int i; va_list ap; if (query_count > 0) { qfs = calloc(query_count, sizeof(enum kmip_query_function)); if (qfs == NULL) return NULL; } va_start(ap, query_count); for (i = 0; i < query_count; i++) qfs[i] = va_arg(ap, enum kmip_query_function); va_end(ap); rpl = kmip_new_query_request_payload(query_count, qfs); if (qfs != NULL) free(qfs); return rpl; } static const struct kmip_version kmip_versions[] = { { .major = 1, .minor = 0 }, { .major = 1, .minor = 1 }, { .major = 1, .minor = 2 }, { .major = 1, .minor = 3 }, { .major = 1, .minor = 4 }, { .major = 2, .minor = 0 }, { .major = 2, .minor = 1 }, }; /** * Constructs a Discover Versions request payload: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Protocol Version No Structure v1.2 * ... may be repeated * * @param version_count the number of version items following. If -1 then * all currently supported versions are added. * @param versions array of version items * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_discover_versions_payload(int version_count, const struct kmip_version *versions) { struct kmip_node *rpl, *ver = NULL; int rc = 0; int i; if (version_count > 0 && versions == NULL) return NULL; rpl = kmip_node_new_structure_va(KMIP_TAG_REQUEST_PAYLOAD, NULL, 0); if (rpl == NULL) return NULL; if (version_count < 0) { versions = kmip_versions; version_count = sizeof(kmip_versions) / sizeof(struct kmip_version); } for (i = 0; i < version_count; i++) { ver = kmip_new_protocol_version(&versions[i]); if (ver == NULL) goto error; rc = kmip_node_add_structure_element(rpl, ver); if (rc != 0) break; kmip_node_free(ver); ver = NULL; } if (rc != 0) goto error; return rpl; error: kmip_node_free(rpl); kmip_node_free(ver); return NULL; } /** * Constructs a Discover Versions request payload: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Protocol Version No Structure v1.2 * ... may be repeated * * @param version_count the number of version items following. If -1 then * all currently supported versions are added. * @param version items (struct kmip_version) * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_discover_versions_payload_va(int version_count, ...) { struct kmip_version *versions = NULL; struct kmip_node *rpl; va_list ap; int i; if (version_count > 0) { versions = calloc(version_count, sizeof(struct kmip_version)); if (versions == NULL) return NULL; } va_start(ap, version_count); for (i = 0; i < version_count; i++) versions[i] = *va_arg(ap, struct kmip_version *); va_end(ap); rpl = kmip_new_discover_versions_payload(version_count, versions); if (versions != NULL) free(versions); return rpl; } /** * Constructs a Protection Storage Masks node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Protection Storage Masks Yes Structure v2.0 * Protection Storage Mask Yes Integer v2.0 * ... may be repeated * * @param masks_count the number of protection storage masks * @param masks array of mask items * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_protection_storage_masks(unsigned int masks_count, int32_t *masks) { struct kmip_node *ret, *psm; unsigned int i; int rc = 0; if (masks_count > 0 && masks == NULL) return NULL; ret = kmip_node_new_structure_va(KMIP_TAG_PROTECTION_STORAGE_MASKS, NULL, 0); if (ret == NULL) return NULL; for (i = 0; i < masks_count; i++) { psm = kmip_node_new_integer(KMIP_TAG_PROTECTION_STORAGE_MASK, NULL, masks[i]); if (psm == NULL) break; rc = kmip_node_add_structure_element(ret, psm); if (rc != 0) break; kmip_node_free(psm); psm = NULL; } if (rc != 0) goto error; return ret; error: kmip_node_free(ret); kmip_node_free(psm); return NULL; } /** * Constructs a Protection Storage Masks node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Protection Storage Masks Yes Structure v2.0 * Protection Storage Mask Yes Integer v2.0 * ... may be repeated * * @param masks_count the number of protection storage masks following * @param mask items (int32_t) * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_protection_storage_masks_va(unsigned int masks_count, ...) { int32_t *masks = NULL; struct kmip_node *ret; unsigned int i; va_list ap; if (masks_count > 0) { masks = calloc(masks_count, sizeof(int32_t)); if (masks == NULL) return NULL; } va_start(ap, masks_count); for (i = 0; i < masks_count; i++) masks[i] = va_arg(ap, int32_t); va_end(ap); ret = kmip_new_protection_storage_masks(masks_count, masks); if (masks != NULL) free(masks); return ret; } /** * Constructs a Create request payload: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Object Type Yes Enumeration v1.0 * Template-Attribute Yes(v1.x) Structure v1.x only * Attributes Yes(v2.x) Structure v2.x only * Protection Storage Masks No Structure v2.x * * @param version the protocol version. If null, the current default * protocol version is used. * @param obj_type the object type to create * @paran prot_storage_masks the protection storage masks (can be NULL) * @param attrs_count the number of attributes following (can be 0) * @param attrs the array of attributes (as KMIP v2.x attribute) * * @returns the allocated node, or NULL in case of an error. * The reference counts of the nodes specified as parameters which are added to * the newly allocated node are increased. The caller must free its reference * via kmip_node_free() if no longer needed. */ struct kmip_node *kmip_new_create_request_payload( const struct kmip_version *version, enum kmip_object_type obj_type, struct kmip_node *prot_storage_masks, unsigned int attrs_count, struct kmip_node **attrs) { struct kmip_node *rpl = NULL, *otyp = NULL, *att; if (attrs_count > 0 && attrs == NULL) return NULL; if (version == NULL) version = kmip_get_default_protocol_version(); otyp = kmip_new_object_type(obj_type); if (otyp == NULL) return NULL; if (version->major < 2) prot_storage_masks = NULL; att = kmip_new_attributes(version, KMIP_TAG_ATTRIBUTES, attrs_count, attrs); if (att == NULL) goto out; rpl = kmip_node_new_structure_va(KMIP_TAG_REQUEST_PAYLOAD, NULL, 3, otyp, att, prot_storage_masks); out: kmip_node_free(otyp); kmip_node_free(att); return rpl; } /** * Constructs a Create request payload: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Object Type Yes Enumeration v1.0 * Template-Attribute Yes(v1.x) Structure v1.x only * Attributes Yes(v2.x) Structure v2.x only * Protection Storage Masks No Structure v2.x * * @param version the protocol version. If null, the current default * protocol version is used. * @param obj_type the object type to create * @paran prot_storage_masks the protection storage masks (can be NULL) * @param attrs_count the number of attributes following (can be 0) * @param the attributes (as KMIP v2.x attribute) * * @returns the allocated node, or NULL in case of an error. * The reference counts of the nodes specified as parameters which are added to * the newly allocated node are increased. The caller must free its reference * via kmip_node_free() if no longer needed. */ struct kmip_node *kmip_new_create_request_payload_va( const struct kmip_version *version, enum kmip_object_type obj_type, struct kmip_node *prot_storage_masks, unsigned int attrs_count, ...) { struct kmip_node *ret, **attrs = NULL; unsigned int i, k; va_list ap; if (attrs_count > 0) { attrs = calloc(attrs_count, sizeof(struct kmip_node *)); if (attrs == NULL) return NULL; } va_start(ap, attrs_count); for (i = 0, k = 0; i < attrs_count; i++) { attrs[k] = va_arg(ap, struct kmip_node *); if (attrs[k] != NULL) k++; } va_end(ap); ret = kmip_new_create_request_payload(version, obj_type, prot_storage_masks, k, attrs); if (attrs != NULL) free(attrs); return ret; } /** * Constructs a Get Attribute List request payload: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Unique Identifier No Text String v1.0 * Enumeration v2.0 * Integer v2.0 * * @param unique_id the unique id of the object to address (can be NULL) * * @returns the allocated node, or NULL in case of an error. * The reference counts of the nodes specified as parameters which are added to * the newly allocated node are increased. The caller must free its reference * via kmip_node_free() if no longer needed. */ struct kmip_node *kmip_new_get_attribute_list_request_payload( struct kmip_node *unique_id) { struct kmip_node *rpl; rpl = kmip_node_new_structure_va(KMIP_TAG_REQUEST_PAYLOAD, NULL, 1, unique_id); return rpl; } /** * Constructs a Get Attributes request payload: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Unique Identifier No Text String v1.0 * Enumeration v2.0 * Integer v2.0 * Attribute Name No Text String v1.x only * ... may be repeated * Attribute Reference No Enumeration v2.x only * Structure v2.x only * ... may be repeated * * @param version the protocol version. If null, the current default * protocol version is used. * @param unique_id the unique id of the object to address * @param num_attrs number of attribute references following * @param attr_refs array of attribute references (struct kmip_node *) * * @returns the allocated node, or NULL in case of an error. * The reference counts of the nodes specified as parameters which are added to * the newly allocated node are increased. The caller must free its reference * via kmip_node_free() if no longer needed. */ struct kmip_node *kmip_new_get_attributes_request_payload( const struct kmip_version *version, struct kmip_node *unique_id, unsigned int num_attrs, struct kmip_node **attr_refs) { struct kmip_node *rpl, *v2_attr_ref, *v1_attr_name; unsigned int i; int rc = 0; if (num_attrs > 0 && attr_refs == NULL) return NULL; if (version == NULL) version = kmip_get_default_protocol_version(); rpl = kmip_node_new_structure_va(KMIP_TAG_REQUEST_PAYLOAD, NULL, 1, unique_id); for (i = 0; i < num_attrs; i++) { v2_attr_ref = attr_refs[i]; if (v2_attr_ref == NULL) continue; if (version->major == 1) { /* KMIP v1.x */ v1_attr_name = kmip_new_attribute_name_v1(v2_attr_ref); if (v1_attr_name == NULL) { rc = -EBADMSG; break; } rc = kmip_node_add_structure_element(rpl, v1_attr_name); kmip_node_free(v1_attr_name); } else { /* KMIP >= v2.0 */ rc = kmip_node_add_structure_element(rpl, v2_attr_ref); } if (rc != 0) break; } if (rc != 0) goto error; return rpl; error: kmip_node_free(rpl); return NULL; } /** * Constructs a Get Attributes request payload: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Unique Identifier No Text String v1.0 * Enumeration v2.0 * Integer v2.0 * Attribute Name No Text String v1.x only * ... may be repeated * Attribute Reference No Enumeration v2.x only * Structure v2.x only * ... may be repeated * * @param version the protocol version. If null, the current default * protocol version is used. * @param unique_id the unique id of the object to address * @param num_attrs number of attribute references following * @param attribute references (struct kmip_node *) * * @returns the allocated node, or NULL in case of an error. * The reference counts of the nodes specified as parameters which are added to * the newly allocated node are increased. The caller must free its reference * via kmip_node_free() if no longer needed. */ struct kmip_node *kmip_new_get_attributes_request_payload_va( const struct kmip_version *version, struct kmip_node *unique_id, unsigned int num_attrs, ...) { struct kmip_node *ret, **attr_refs = NULL; unsigned int i, k; va_list ap; if (num_attrs > 0) { attr_refs = calloc(num_attrs, sizeof(struct kmip_node *)); if (attr_refs == NULL) return NULL; } va_start(ap, num_attrs); for (i = 0, k = 0; i < num_attrs; i++) { attr_refs[k] = va_arg(ap, struct kmip_node *); if (attr_refs[k] != NULL) k++; } va_end(ap); ret = kmip_new_get_attributes_request_payload(version, unique_id, k, attr_refs); if (attr_refs != NULL) free(attr_refs); return ret; } /** * Constructs a Add Attribute request payload: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Unique Identifier No Text String v1.0 * Enumeration v2.0 * Integer v2.0 * Attribute Yes Structure v1.x only * or * New Attribute Yes Structure v2.x only * * @param version the protocol version. If null, the current default * protocol version is used. * @param unique_id the unique id of the object to address * @param v2_attr the attribute to add (as KMIP v2.x attribute) * * @returns the allocated node, or NULL in case of an error. * The reference counts of the nodes specified as parameters which are added to * the newly allocated node are increased. The caller must free its reference * via kmip_node_free() if no longer needed. */ struct kmip_node *kmip_new_add_attribute_request_payload( const struct kmip_version *version, struct kmip_node *unique_id, struct kmip_node *v2_attr) { struct kmip_node *rpl, *new_attr, *v1_attr; int rc; if (v2_attr == NULL) return NULL; if (version == NULL) version = kmip_get_default_protocol_version(); if (version->major == 1) { /* KMIP v1.x */ rc = kmip_v1_attr_from_v2_attr(v2_attr, &v1_attr); if (rc != 0) return NULL; rpl = kmip_node_new_structure_va(KMIP_TAG_REQUEST_PAYLOAD, NULL, 2, unique_id, v1_attr); kmip_node_free(v1_attr); } else { /* KMIP >= v2.0 */ new_attr = kmip_new_current_new_attribute(true, v2_attr); if (new_attr == NULL) return NULL; rpl = kmip_node_new_structure_va(KMIP_TAG_REQUEST_PAYLOAD, NULL, 2, unique_id, new_attr); kmip_node_free(new_attr); } return rpl; } /** * Constructs a Modify Attribute request payload: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Unique Identifier No Text String v1.0 * Enumeration v2.0 * Integer v2.0 * Attribute Yes Structure v1.x only * or * Current Attribute No Structure v2.x only * New Attribute Yes Structure v2.x only * * @param version the protocol version. If null, the current default * protocol version is used. * @param unique_id the unique id of the object to address * @param v2_current the current attribute (as KMIP v2.x attribute). * Can be NULL, ignored for KMIP v1.x. * @param v2_attr the attribute to modify (as KMIP v2.x attribute) * * @returns the allocated node, or NULL in case of an error. * The reference counts of the nodes specified as parameters which are added to * the newly allocated node are increased. The caller must free its reference * via kmip_node_free() if no longer needed. */ struct kmip_node *kmip_new_modify_attribute_request_payload( const struct kmip_version *version, struct kmip_node *unique_id, struct kmip_node *v2_current, struct kmip_node *v2_attr) { struct kmip_node *rpl, *new_attr, *cur_attr = NULL, *v1_attr; int rc; if (v2_attr == NULL) return NULL; if (version == NULL) version = kmip_get_default_protocol_version(); if (version->major == 1) { /* KMIP v1.x */ rc = kmip_v1_attr_from_v2_attr(v2_attr, &v1_attr); if (rc != 0) return NULL; rpl = kmip_node_new_structure_va(KMIP_TAG_REQUEST_PAYLOAD, NULL, 2, unique_id, v1_attr); kmip_node_free(v1_attr); } else { /* KMIP >= v2.0 */ new_attr = kmip_new_current_new_attribute(true, v2_attr); if (new_attr == NULL) return NULL; if (v2_current != NULL) { cur_attr = kmip_new_current_new_attribute(false, v2_current); if (cur_attr == NULL) { kmip_node_free(new_attr); return NULL; } } rpl = kmip_node_new_structure_va(KMIP_TAG_REQUEST_PAYLOAD, NULL, 3, unique_id, cur_attr, new_attr); kmip_node_free(new_attr); if (cur_attr != NULL) kmip_node_free(cur_attr); } return rpl; } /** * Constructs a Set Attribute request payload: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Unique Identifier No Text String v1.0 * Enumeration v2.0 * Integer v2.0 * New Attribute Yes Structure v2.x only * * KMIP v1.x does not have a Set Attribute operation. * * @param unique_id the unique id of the object to address * @param v2_attr the attribute to set (as KMIP v2.x attribute) * * @returns the allocated node, or NULL in case of an error. * The reference counts of the nodes specified as parameters which are added to * the newly allocated node are increased. The caller must free its reference * via kmip_node_free() if no longer needed. */ struct kmip_node *kmip_new_set_attribute_v2_request_payload( struct kmip_node *unique_id, struct kmip_node *v2_attr) { struct kmip_node *rpl, *new_attr; if (v2_attr == NULL) return NULL; new_attr = kmip_new_current_new_attribute(true, v2_attr); if (new_attr == NULL) return NULL; rpl = kmip_node_new_structure_va(KMIP_TAG_REQUEST_PAYLOAD, NULL, 2, unique_id, new_attr); kmip_node_free(new_attr); return rpl; } /** * Constructs a Delete Attribute request payload: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Unique Identifier No Text String v1.0 * Enumeration v2.0 * Integer v2.0 * Attribute Name Yes Text String v1.x only * Attribute Index No Integer v1.x only * or * Current Attribute No Structure v2.x only * Attribute Reference No Structure v2.x only * * @param version the protocol version. If null, the current default * protocol version is used. * @param unique_id the unique id of the object to address * @param v2_current the current attribute (as KMIP v2.x attribute). * Can be NULL. * @param attr_ref the attribute to modify (as KMIP v2.x attribute * reference). Either v2_current or attr_ref can be * specified. * * @returns the allocated node, or NULL in case of an error. * The reference counts of the nodes specified as parameters which are added to * the newly allocated node are increased. The caller must free its reference * via kmip_node_free() if no longer needed. */ struct kmip_node *kmip_new_delete_attribute_request_payload( const struct kmip_version *version, struct kmip_node *unique_id, struct kmip_node *v2_current, struct kmip_node *attr_ref) { struct kmip_node *rpl, *cur_attr = NULL, *nam = NULL; const char *vendor_id, *attr_name, *name; char *custom_name = NULL; int rc; if (v2_current != NULL && attr_ref != NULL) return NULL; if (v2_current == NULL && attr_ref == NULL) return NULL; if (version == NULL) version = kmip_get_default_protocol_version(); if (version->major == 1) { /* KMIP v1.x */ if (v2_current != NULL) { if (kmip_node_get_tag(v2_current) == KMIP_TAG_ATTRIBUTE) { /* Special handling for v2.x Vendor Attribute */ rc = kmip_get_vendor_attribute(v2_current, &vendor_id, &attr_name, NULL); if (rc != 0) return NULL; custom_name = kmip_build_v1_custom_attr_name( vendor_id, attr_name); if (custom_name == NULL) return NULL; name = custom_name; } else { name = kmip_v1_attr_name_by_tag( kmip_node_get_tag(v2_current)); } nam = kmip_node_new_text_string(KMIP_TAG_ATTRIBUTE_NAME, NULL, name); if (custom_name != NULL) free(custom_name); } else if (attr_ref != NULL) { nam = kmip_new_attribute_name_v1(attr_ref); } if (nam == NULL) return NULL; rpl = kmip_node_new_structure_va(KMIP_TAG_REQUEST_PAYLOAD, NULL, 2, unique_id, nam); kmip_node_free(nam); } else { /* KMIP >= v2.0 */ if (v2_current != NULL) { cur_attr = kmip_new_current_new_attribute(false, v2_current); if (cur_attr == NULL) return NULL; } rpl = kmip_node_new_structure_va(KMIP_TAG_REQUEST_PAYLOAD, NULL, 3, unique_id, cur_attr, attr_ref); if (cur_attr != NULL) kmip_node_free(cur_attr); } return rpl; } /** * Constructs an Activate request payload: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Unique Identifier No Text String v1.0 * Enumeration v2.0 * Integer v2.0 * * @param unique_id the unique id of the object to address * * @returns the allocated node, or NULL in case of an error. * The reference counts of the nodes specified as parameters which are added to * the newly allocated node are increased. The caller must free its reference * via kmip_node_free() if no longer needed. */ struct kmip_node *kmip_new_activate_request_payload(struct kmip_node *unique_id) { return kmip_node_new_structure_va(KMIP_TAG_REQUEST_PAYLOAD, NULL, 1, unique_id); } /** * Constructs an Destroy request payload: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Unique Identifier No Text String v1.0 * Enumeration v2.0 * Integer v2.0 * * @param unique_id the unique id of the object to address * * @returns the allocated node, or NULL in case of an error. * The reference counts of the nodes specified as parameters which are added to * the newly allocated node are increased. The caller must free its reference * via kmip_node_free() if no longer needed. */ struct kmip_node *kmip_new_destroy_request_payload(struct kmip_node *unique_id) { return kmip_node_new_structure_va(KMIP_TAG_REQUEST_PAYLOAD, NULL, 1, unique_id); } /** * Constructs an Archive request payload: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Unique Identifier No Text String v1.0 * Enumeration v2.0 * Integer v2.0 * * @param unique_id the unique id of the object to address * * @returns the allocated node, or NULL in case of an error. * The reference counts of the nodes specified as parameters which are added to * the newly allocated node are increased. The caller must free its reference * via kmip_node_free() if no longer needed. */ struct kmip_node *kmip_new_archive_request_payload(struct kmip_node *unique_id) { return kmip_node_new_structure_va(KMIP_TAG_REQUEST_PAYLOAD, NULL, 1, unique_id); } /** * Constructs an Recover request payload: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Unique Identifier No Text String v1.0 * Enumeration v2.0 * Integer v2.0 * * @param unique_id the unique id of the object to address * * @returns the allocated node, or NULL in case of an error. * The reference counts of the nodes specified as parameters which are added to * the newly allocated node are increased. The caller must free its reference * via kmip_node_free() if no longer needed. */ struct kmip_node *kmip_new_recover_request_payload(struct kmip_node *unique_id) { return kmip_node_new_structure_va(KMIP_TAG_REQUEST_PAYLOAD, NULL, 1, unique_id); } /** * Constructs an Revoke request payload: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Unique Identifier No Text String v1.0 * Enumeration v2.0 * Integer v2.0 * Revocation Reason Yes Structure v1.0 * Revocation Reason Code Yes Enumeration v1.0 * Revocation Message No Text String v1.0 * Compromise Occurrence Date No Date Time v1.0 * * @param unique_id the unique id of the object to address * @param rsn the revocation reason * @param message the revocation message (can be NULL) * @param compromise_date the date when he compromise happened (can be 0) * * @returns the allocated node, or NULL in case of an error. * The reference counts of the nodes specified as parameters which are added to * the newly allocated node are increased. The caller must free its reference * via kmip_node_free() if no longer needed. */ struct kmip_node *kmip_new_revoke_request_payload(struct kmip_node *unique_id, enum kmip_revoke_reason rsn, const char *message, uint64_t compromise_date) { struct kmip_node *rsn_code, *reason = NULL, *rsn_msg = NULL; struct kmip_node *rpl = NULL, *date = NULL; rsn_code = kmip_node_new_enumeration(KMIP_TAG_REVOCATION_REASON_CODE, NULL, rsn); if (rsn_code == NULL) return NULL; if (message != NULL) { rsn_msg = kmip_node_new_text_string(KMIP_TAG_REVOCATION_MESSAGE, NULL, message); if (rsn_msg == NULL) goto out; } reason = kmip_node_new_structure_va(KMIP_TAG_REVOCATION_REASON, NULL, 2, rsn_code, rsn_msg); if (reason == NULL) goto out; switch (rsn) { case KMIP_REVOK_RSN_KEY_COMPROMISE: case KMIP_REVOK_RSN_CA_COMPROMISE: if (compromise_date != 0) { date = kmip_node_new_date_time( KMIP_TAG_COMPROMISE_OCCURRENCE_DATE, NULL, compromise_date); if (date == NULL) goto out; } break; default: /*Compromise date is ignored on other reasons */ break; } rpl = kmip_node_new_structure_va(KMIP_TAG_REQUEST_PAYLOAD, NULL, 3, unique_id, reason, date); out: kmip_node_free(rsn_code); kmip_node_free(rsn_msg); kmip_node_free(reason); kmip_node_free(date); return rpl; } /** * Constructs an Locate request payload: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Maximum Items No Integer v1.0 * Offset Items No Integer v1.3 * Storage Status Mask No Integer v1.0 * Object Group Member No Enumeration v1.2 * Attribute No Structure v1.x only * ... may be repeated * Attributes Yes Structure v2.x only * * @param version the protocol version. If null, the current default * protocol version is used. * @param max_items the maximum numbers of items to return. If <= 0 * then no limit is assumed. * @param offset_items the number of items to skip If <= 0 then no offset * is assumed. Ignored for KMIP <= v1.2. * @param storage_status the storage status filter. If 0, then no filter is * used and only on-line objects are returned. * @param obj_group the object group filter. If 0 then no object group * filter is used. Ignored for KMIP <= v1.1. * @param attrs_count the number of attributes following (can be 0) * @param attrs the array of attributes (as KMIP v2.x attribute) * * @returns the allocated node, or NULL in case of an error. * The reference counts of the nodes specified as parameters which are added to * the newly allocated node are increased. The caller must free its reference * via kmip_node_free() if no longer needed. */ struct kmip_node *kmip_new_locate_request_payload( const struct kmip_version *version, int32_t max_items, int32_t offset_items, enum kmip_storage_status_mask storage_status, enum kmip_object_group_member obj_group, unsigned int attrs_count, struct kmip_node **attrs) { struct kmip_node *max = NULL, *ofs = NULL, *stm = NULL, *grp = NULL; struct kmip_node *rpl = NULL, *att, *v2_attr, *v1_attr; unsigned int i; int rc; if (attrs_count > 0 && attrs == NULL) return NULL; if (version == NULL) version = kmip_get_default_protocol_version(); if (max_items > 0) { max = kmip_node_new_integer(KMIP_TAG_MAXIMUM_ITEMS, NULL, max_items); if (max == NULL) return NULL; } if (offset_items > 0 && (version->major > 1 || (version->major == 1 && version->minor > 2))) { ofs = kmip_node_new_integer(KMIP_TAG_OFFSET_ITEMS, NULL, offset_items); if (ofs == NULL) goto out; } if (storage_status != 0) { stm = kmip_node_new_integer(KMIP_TAG_STORAGE_STATUS_MASK, NULL, storage_status); if (stm == NULL) goto out; } if (obj_group > 0 && (version->major > 1 || version->minor > 1)) { grp = kmip_node_new_enumeration(KMIP_TAG_OBJECT_GROUP_MEMBER, NULL, obj_group); if (grp == NULL) goto out; } if (version->major == 1) { /* KMIP v1.x */ rpl = kmip_node_new_structure_va(KMIP_TAG_REQUEST_PAYLOAD, NULL, 4, max, ofs, stm, grp); if (rpl == NULL) goto out; for (i = 0; i < attrs_count; i++) { v2_attr = attrs[i]; if (v2_attr == NULL) continue; rc = kmip_v1_attr_from_v2_attr(v2_attr, &v1_attr); if (rc != 0) goto error; rc = kmip_node_add_structure_element(rpl, v1_attr); kmip_node_free(v1_attr); if (rc != 0) goto error; } } else { /* KMIP >= v2.0 */ att = kmip_new_attributes(version, KMIP_TAG_ATTRIBUTES, attrs_count, attrs); if (att == NULL) goto out; rpl = kmip_node_new_structure_va(KMIP_TAG_REQUEST_PAYLOAD, NULL, 5, max, ofs, stm, grp, att); kmip_node_free(att); } goto out; error: kmip_node_free(rpl); rpl = NULL; out: kmip_node_free(max); kmip_node_free(ofs); kmip_node_free(stm); kmip_node_free(grp); return rpl; } /** * Constructs an Locate request payload: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Maximum Items No Integer v1.0 * Offset Items No Integer v1.3 * Storage Status Mask No Integer v1.0 * Object Group Member No Enumeration v1.2 * Attribute No Structure v1.x only * ... may be repeated * Attributes Yes Structure v2.x only * * @param version the protocol version. If null, the current default * protocol version is used. * @param max_items the maximum numbers of items to return. If <= 0 * then no limit is assumed. * @param offset_items the number of items to skip If <= 0 then no offset * is assumed. Ignored for KMIP <= v1.2. * @param storage_status the storage status filter. If 0, then no filter is * used and only on-line objects are returned. * @param obj_group the object group filter. If 0 then no object group * filter is used. Ignored for KMIP <= v1.1. * @param attrs_count the number of attributes following (can be 0) * @param the attributes (as KMIP v2.x attribute) * * @returns the allocated node, or NULL in case of an error. * The reference counts of the nodes specified as parameters which are added to * the newly allocated node are increased. The caller must free its reference * via kmip_node_free() if no longer needed. */ struct kmip_node *kmip_new_locate_request_payload_va( const struct kmip_version *version, int32_t max_items, int32_t offset_items, enum kmip_storage_status_mask storage_status, enum kmip_object_group_member obj_group, unsigned int attrs_count, ...) { struct kmip_node *ret, **attrs = NULL; unsigned int i, k; va_list ap; if (attrs_count > 0) { attrs = calloc(attrs_count, sizeof(struct kmip_node *)); if (attrs == NULL) return NULL; } va_start(ap, attrs_count); for (i = 0, k = 0; i < attrs_count; i++) { attrs[k] = va_arg(ap, struct kmip_node *); if (attrs[k] != NULL) k++; } va_end(ap); ret = kmip_new_locate_request_payload(version, max_items, offset_items, storage_status, obj_group, k, attrs); if (attrs != NULL) free(attrs); return ret; } /** * Constructs an Register request payload: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Object Type Yes Enumeration v1.0 * Template-Attribute Yes(v1.x) Structure v1.x only * Attributes Yes(v2.x) Structure v2.x only * Yes Structure v1.0 * Protection Storage Masks No Structure v2.x * * @param version the protocol version. If null, the current default * protocol version is used. * @param obj_type the object type to register * @param object the object to register * @paran prot_storage_masks the protection storage masks (can be NULL) * @param attrs_count the number of attributes following (can be 0) * @param attrs the array of attributes (as KMIP v2.x attribute) * * @returns the allocated node, or NULL in case of an error. * The reference counts of the nodes specified as parameters which are added to * the newly allocated node are increased. The caller must free its reference * via kmip_node_free() if no longer needed. */ struct kmip_node *kmip_new_register_request_payload( const struct kmip_version *version, enum kmip_object_type obj_type, struct kmip_node *object, struct kmip_node *prot_storage_masks, unsigned int attrs_count, struct kmip_node **attrs) { struct kmip_node *rpl = NULL, *otyp = NULL, *att; if (object == NULL) return NULL; if (attrs_count > 0 && attrs == NULL) return NULL; if (version == NULL) version = kmip_get_default_protocol_version(); otyp = kmip_new_object_type(obj_type); if (otyp == NULL) return NULL; if (version->major < 2) prot_storage_masks = NULL; att = kmip_new_attributes(version, KMIP_TAG_ATTRIBUTES, attrs_count, attrs); if (att == NULL) goto out; rpl = kmip_node_new_structure_va(KMIP_TAG_REQUEST_PAYLOAD, NULL, 4, otyp, att, object, prot_storage_masks); out: kmip_node_free(otyp); kmip_node_free(att); return rpl; } /** * Constructs an Register request payload: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Object Type Yes Enumeration v1.0 * Template-Attribute Yes(v1.x) Structure v1.x only * Attributes Yes(v2.x) Structure v2.x only * Yes Structure v1.0 * Protection Storage Masks No Structure v2.x * * @param version the protocol version. If null, the current default * protocol version is used. * @param obj_type the object type to register * @param object the object to register * @paran prot_storage_masks the protection storage masks (can be NULL) * @param attrs_count the number of attributes following (can be 0) * @param the attributes (as KMIP v2.x attribute) * * @returns the allocated node, or NULL in case of an error. * The reference counts of the nodes specified as parameters which are added to * the newly allocated node are increased. The caller must free its reference * via kmip_node_free() if no longer needed. */ struct kmip_node *kmip_new_register_request_payload_va( const struct kmip_version *version, enum kmip_object_type obj_type, struct kmip_node *object, struct kmip_node *prot_storage_masks, unsigned int attrs_count, ...) { struct kmip_node *ret, **attrs = NULL; unsigned int i, k; va_list ap; if (attrs_count > 0) { attrs = calloc(attrs_count, sizeof(struct kmip_node *)); if (attrs == NULL) return NULL; } va_start(ap, attrs_count); for (i = 0, k = 0; i < attrs_count; i++) { attrs[k] = va_arg(ap, struct kmip_node *); if (attrs[k] != NULL) k++; } va_end(ap); ret = kmip_new_register_request_payload(version, obj_type, object, prot_storage_masks, k, attrs); if (attrs != NULL) free(attrs); return ret; } /** * Constructs an Get request payload: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Unique Identifier No Text String v1.0 * Enumeration v2.0 * Integer v2.0 * Key Format Type No Enumeration v1.0 * Key Wrap Type No Enumeration v1.4 * Key Compression Type No Enumeration v1.0 * Key Wrapping Specification No Structure v1.0 * * @param version the protocol version. If null, the current default * protocol version is used. * @param unique_id the unique id of the object to get * @param format_type the format type of the key (ignored if 0) * @paran wrap_type the wrap type (ignored if 0) * @param compr_type the compression type (ignored if 0) * @param wrap_specification the key wrapping specification node (can be NULL) * * @returns the allocated node, or NULL in case of an error. * The reference counts of the nodes specified as parameters which are added to * the newly allocated node are increased. The caller must free its reference * via kmip_node_free() if no longer needed. */ struct kmip_node *kmip_new_get_request_payload( const struct kmip_version *version, struct kmip_node *unique_id, enum kmip_key_format_type format_type, enum kmip_key_wrap_type wrap_type, enum kmip_key_compression_type compr_type, struct kmip_node *wrap_specification) { struct kmip_node *rpl = NULL, *fmt = NULL, *wt = NULL, *cmpt = NULL; if (version == NULL) version = kmip_get_default_protocol_version(); if (format_type != 0) { fmt = kmip_node_new_enumeration(KMIP_TAG_KEY_FORMAT_TYPE, NULL, format_type); if (fmt == NULL) goto out; } if (wrap_type != 0 && (version->major > 1 || (version->major == 1 && version->minor > 3))) { wt = kmip_node_new_enumeration(KMIP_TAG_KEY_WRAP_TYPE, NULL, wrap_type); if (wt == NULL) goto out; } if (compr_type != 0) { cmpt = kmip_node_new_enumeration(KMIP_TAG_KEY_COMPRESSION_TYPE, NULL, compr_type); if (cmpt == NULL) goto out; } rpl = kmip_node_new_structure_va(KMIP_TAG_REQUEST_PAYLOAD, NULL, 5, unique_id, fmt, wt, cmpt, wrap_specification); out: kmip_node_free(fmt); kmip_node_free(wt); kmip_node_free(cmpt); return rpl; } opencryptoki-opencryptoki-451d99c/usr/sbin/p11kmip/kmipclient/response.c000066400000000000000000001316051520105705100265210ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021-2024 * * 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 _DEFAULT_SOURCE #include #include #include "kmip.h" /** * Gets the version information from a Protocol Version node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Protocol Version Structure v1.0 * Protocol Version Major Yes Integer v1.0 * Protocol Version Minor Yes Integer v1.0 * * @param node the KMIP node * @param version On return: the protocol version * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_protocol_version(const struct kmip_node *node, struct kmip_version *version) { struct kmip_node *maj, *min; int rc = 0; if (node == NULL || version == NULL) return -EINVAL; if (kmip_node_get_tag(node) != KMIP_TAG_PROTOCOL_VERSION) return -EBADMSG; maj = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_PROTOCOL_VERSION_MAJOR, 0); min = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_PROTOCOL_VERSION_MINOR, 0); if (maj == NULL || min == NULL) { rc = -EBADMSG; goto out; } version->major = kmip_node_get_integer(maj); version->minor = kmip_node_get_integer(min); out: kmip_node_free(maj); kmip_node_free(min); return rc; } /** * Gets the version information from a Profile Version node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Profile Version Structure v1.0 * Profile Version Major Yes Integer v1.0 * Profile Version Minor Yes Integer v1.0 * * @param node the KMIP node * @param version On return: the profile version * * @returns 0 on success, or a negative errno in case of an error */ int kmip_get_profile_version(const struct kmip_node *node, struct kmip_version *version) { struct kmip_node *maj, *min; int rc = 0; if (node == NULL || version == NULL) return -EINVAL; if (kmip_node_get_tag(node) != KMIP_TAG_PROFILE_VERSION) return -EBADMSG; maj = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_PROFILE_VERSION_MAJOR, 0); min = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_PROFILE_VERSION_MINOR, 0); if (maj == NULL || min == NULL) { rc = -EBADMSG; goto out; } version->major = kmip_node_get_integer(maj); version->minor = kmip_node_get_integer(min); out: kmip_node_free(maj); kmip_node_free(min); return rc; } /** * Gets information from a Response Header node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Response Header Yes Structure v1.0 * Protocol Version Yes Structure v1.0 * Time Stamp No Date Time v1.0 * Nonce No Structure v1.2 * Server Hashed Password No Byte String v2.0 * Attestation Type No Enumeration v1.2 * ... may be repeated * Client Correlation Value No Text String v1.4 * Server Correlation Value No Text String v1.4 * Batch Count Yes Integer v1.0 * * @param node the KMIP node * @param version the protocol version (can be NULL) * @param time_stamp the time stamp (can be NULL) * @param client_corr_value the client correlation value. Can be NULL. * @param server_corr_value the server correlation value. Can be NULL. * @param batch_count the batch count (can be NULL) * * @returns 0 on success, or a negative errno in case of an error. * The reference count of the returned node is increased. The caller must * free the node via kmip_node_free() when no longer needed. */ int kmip_get_response_header(const struct kmip_node *node, struct kmip_version *version, int64_t *time_stamp, const char **client_corr_value, const char **server_corr_value, int32_t *batch_count) { struct kmip_node *n; int rc; if (node == NULL) return -EINVAL; if (kmip_node_get_tag(node) != KMIP_TAG_RESPONSE_HEADER) return -EBADMSG; if (time_stamp != NULL) { n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_TIME_STAMP, 0); if (n == NULL) return -EBADMSG; *time_stamp = kmip_node_get_date_time(n); kmip_node_free(n); } if (batch_count != NULL) { n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_BATCH_COUNT, 0); if (n == NULL) return -EBADMSG; *batch_count = kmip_node_get_integer(n); kmip_node_free(n); } if (version != NULL) { n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_PROTOCOL_VERSION, 0); if (n == NULL) return -EBADMSG; rc = kmip_get_protocol_version(n, version); kmip_node_free(n); if (rc != 0) return rc; } if (client_corr_value != NULL) { n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_CLIENT_CORRELATION_VALUE, 0); if (n == NULL) return -EBADMSG; *client_corr_value = kmip_node_get_text_string(n); kmip_node_free(n); } if (server_corr_value != NULL) { n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_SERVER_CORRELATION_VALUE, 0); if (n == NULL) return -EBADMSG; *server_corr_value = kmip_node_get_text_string(n); kmip_node_free(n); } return 0; } /** * Gets information from a Response Batch Item node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Batch Item Yes Structure v1.0 * Operation Yes Enumeration v1.0 * Unique Batch Item ID No Byte String v1.0 * Result Status Yes Enumeration v1.0 * Result Reason No/Yes Enumeration v1.0 * Result Message No/Yes Text String v1.0 * Asynchronous Correl. Value No/Yes Byte String v1.0 * Response Payload Yes Structure v1.0 * Message Extension No Structure v1.0 * * @param node the KMIP node * @param operation the operation (can be NULL) * @param batch_id the batch ID (can be NULL) * @param batch_id_length the batch ID length (can be NULL) * @param status the result status (can be NULL) * @param reason the result reason (can be NULL) * @param message the result message (can be NULL) * @param async_corr_value the asynchronous correlation value (can be NULL) * @param async_corr_value_len the length if the async corr. value (can be NULL) * @param payload the response payload (can be NULL) * * @returns 0 on success, or a negative errno in case of an error. * The reference count of the returned node is increased. The caller must * free the node via kmip_node_free() when no longer needed. */ int kmip_get_response_batch_item(const struct kmip_node *node, enum kmip_operation *operation, const unsigned char **batch_id, uint32_t *batch_id_length, enum kmip_result_status *status, enum kmip_result_reason *reason, const char **message, const unsigned char **async_corr_value, uint32_t *async_corr_value_len, struct kmip_node **payload) { struct kmip_node *n; if (node == NULL) return -EINVAL; if (kmip_node_get_tag(node) != KMIP_TAG_BATCH_ITEM) return -EBADMSG; if (operation != NULL) { n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_OPERATION, 0); if (n == NULL) return -EBADMSG; *operation = kmip_node_get_enumeration(n); kmip_node_free(n); } if (batch_id != NULL) { n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_UNIQUE_BATCH_ITEM_ID, 0); if (n == NULL) { *batch_id = NULL; if (batch_id_length != NULL) *batch_id_length = 0; } else { *batch_id = kmip_node_get_byte_string(n, batch_id_length); kmip_node_free(n); } } if (status != NULL) { n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_RESULT_STATUS, 0); if (n == NULL) return -EBADMSG; *status = kmip_node_get_enumeration(n); kmip_node_free(n); } if (reason != NULL) { n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_RESULT_REASON, 0); *reason = (n == NULL ? 0 : kmip_node_get_enumeration(n)); kmip_node_free(n); } if (message != NULL) { n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_RESULT_MESSAGE, 0); *message = (n == NULL ? NULL : kmip_node_get_text_string(n)); kmip_node_free(n); } if (async_corr_value != NULL) { n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_ASYNCHRONOUS_CORRELATION_VALUE, 0); if (n != NULL) { *async_corr_value = kmip_node_get_byte_string(n, async_corr_value_len); } else { *async_corr_value = NULL; if (async_corr_value_len != NULL) *async_corr_value_len = 0; } kmip_node_free(n); } if (payload != NULL) *payload = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_RESPONSE_PAYLOAD, 0); return 0; } /** * Gets information from a Response Message node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Response Message Yes Structure v1.0 * Response Header Yes Structure v1.0 * Batch Item Yes Structure v1.0 * ... may be repeated * * @param node the KMIP node * @param response_header the response header (can be NULL) * @param batch_index the index of the response batch item to return * @param batch_item the batch item (can be NULL) * @returns 0 on success, or a negative errno in case of an error. * The reference count of the returned nodes is increased. The caller must * free the node via kmip_node_free() when no longer needed. */ int kmip_get_response(const struct kmip_node *node, struct kmip_node **response_header, unsigned int batch_index, struct kmip_node **batch_item) { if (node == NULL) return -EINVAL; if (kmip_node_get_tag(node) != KMIP_TAG_RESPONSE_MESSAGE) return -EBADMSG; if (response_header != NULL) { *response_header = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_RESPONSE_HEADER, 0); if (*response_header == NULL) return -EBADMSG; } if (batch_item != NULL) *batch_item = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_BATCH_ITEM, batch_index); return 0; } struct kmip_query_info { enum kmip_query_function query_function; enum kmip_tag result_tag; }; static const struct kmip_query_info query_info[] = { { .query_function = KMIP_QUERY_OPERATIONS, .result_tag = KMIP_TAG_OPERATION, }, { .query_function = KMIP_QUERY_OBJECTS, .result_tag = KMIP_TAG_OBJECT_TYPE, }, { .query_function = KMIP_QUERY_SERVER_INFORMATION, .result_tag = KMIP_TAG_VENDOR_IDENTIFICATION, }, { .query_function = KMIP_QUERY_SERVER_INFORMATION, .result_tag = KMIP_TAG_SERVER_INFORMATION, }, { .query_function = KMIP_QUERY_APPLICATION_NAMESPACES, .result_tag = KMIP_TAG_APPLICATION_NAMESPACE, }, { .query_function = KMIP_QUERY_EXTENSION_LIST, .result_tag = KMIP_TAG_EXTENSION_INFORMATION, }, { .query_function = KMIP_QUERY_EXTENSION_MAP, .result_tag = KMIP_TAG_EXTENSION_INFORMATION, }, { .query_function = KMIP_QUERY_ATTESTATION_TYPES, .result_tag = KMIP_TAG_ATTESTATION_TYPE, }, { .query_function = KMIP_QUERY_QUERY_RNGS, .result_tag = KMIP_TAG_RNG_PARAMETERS, }, { .query_function = KMIP_QUERY_VALIDATIONS, .result_tag = KMIP_TAG_VALIDATION_INFORMATION, }, { .query_function = KMIP_QUERY_PROFILES, .result_tag = KMIP_TAG_PROFILE_INFORMATION, }, { .query_function = KMIP_QUERY_CAPABILITIES, .result_tag = KMIP_TAG_CAPABILITY_INFORMATION, }, { .query_function = KMIP_QUERY_CLIENT_REGISTRATION_METHODS, .result_tag = KMIP_TAG_CLIENT_REGISTRATION_METHOD, }, { .query_function = KMIP_QUERY_DEFAULTS_INFORMATION, .result_tag = KMIP_TAG_DEFAULTS_INFORMATION, }, { .query_function = KMIP_QUERY_STORAGE_PROTECTION_MASKS, .result_tag = KMIP_TAG_PROTECTION_STORAGE_MASKS, }, { .query_function = 0, .result_tag = 0, }, }; /** * Gets information from a Query response payload node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Operation No Enumeration v1.0 * ... may be repeated * Object Type No Enumeration v1.0 * ... may be repeated * Vendor Identification No Text String v1.0 * Server Information No Structure v1.0 * Application Namespace No Text String v1.0 * ... may be repeated * Extension Information No Structure v1.2 * ... may be repeated * Attestation Type No Enumeration v1.2 * ... may be repeated * RNG Parameters No Structure v1.3 * ... may be repeated * Profile Information No Structure v1.3 * ... may be repeated * Validation Information No Structure v1.3 * ... may be repeated * Capability Information No Structure v1.3 * ... may be repeated * Client Registration Method No Enumeration v1.3 * ... may be repeated * Defaults Information No Structure v2.0 * Protection Storage Masks No Structure v2.0 * * @param node the KMIP node * @param query_function the query function to get the results for * @param num_results On return: the number of result items of the * specified query function (can be NULL). * @param result_index the index of the query result item to return * @param result On return: the query result item of the specified * query function and index. Function returns -ENOENT * if no result is available. Can be NULL. * * @returns 0 on success, or a negative errno in case of an error. * The reference count of the returned node is increased. The caller must * free the node via kmip_node_free() when no longer needed. */ int kmip_get_query_response_payload(const struct kmip_node *node, enum kmip_query_function query_function, unsigned int *num_results, unsigned int result_index, struct kmip_node **result) { enum kmip_tag result_tag = 0; unsigned int i; if (node == NULL) return -EINVAL; if (kmip_node_get_tag(node) != KMIP_TAG_RESPONSE_PAYLOAD) return -EBADMSG; for (i = 0; query_info[i].query_function != 0; i++) { if (query_info[i].query_function == query_function) { result_tag = query_info[i].result_tag; break; } } if (result_tag == 0) return -EBADMSG; if (num_results != NULL) { *num_results = kmip_node_get_structure_element_by_tag_count( node, result_tag); /* * KMIP_QUERY_SERVER_INFORMATION may return 2 different result * tags, count both of them. */ if (query_function == KMIP_QUERY_SERVER_INFORMATION) { *num_results += kmip_node_get_structure_element_by_tag_count( node, KMIP_TAG_SERVER_INFORMATION); } } if (result == NULL) return 0; *result = kmip_node_get_structure_element_by_tag(node, result_tag, result_index); if (*result == NULL) { /* * KMIP_QUERY_SERVER_INFORMATION may return 2 different result * tags, return both of them. */ if (query_function == KMIP_QUERY_SERVER_INFORMATION) { if (result_index > 0) result_index -= 1; *result = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_SERVER_INFORMATION, result_index); if (*result != NULL) return 0; } return -ENOENT; } return 0; } /** * Gets information from a Discover Versions response payload node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Protocol Version No Structure v1.2 * ... may be repeated * * @param node the KMIP node * @param num_versions On return: the number of versions (can be NULL) * @param index the index of the version item to return * @param version On return: the version item of the specified * index. Function returns -ENOENT if no version is * available at that index. (can be NULL). * * @returns 0 on success, or a negative errno in case of an error. */ int kmip_get_discover_versions_response_payload(const struct kmip_node *node, unsigned int *num_versions, unsigned int index, struct kmip_version *version) { struct kmip_node *n; int rc; if (node == NULL) return -EINVAL; if (kmip_node_get_tag(node) != KMIP_TAG_RESPONSE_PAYLOAD) return -EBADMSG; if (num_versions != NULL) *num_versions = kmip_node_get_structure_element_count(node); if (version == NULL) return 0; n = kmip_node_get_structure_element_by_index(node, index); if (n == NULL) return -ENOENT; rc = kmip_get_protocol_version(n, version); kmip_node_free(n); return rc; } /** * Gets information from a Create response payload node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Object Type Yes Enumeration v1.0 * Unique Identifier Yes Text String v1.0 * Enumeration v2.0 * Integer v2.0 * Template-Attribute No Structure v1.x only * * * @param node the KMIP node * @param obj_type the object type of the created object (can be NULL) * @param unique_id the unique id node (can be NULL) * @param num_attrs On return: the number of attributes (can be NULL). * @param attr_index the index of the attribute to get * @param attributes the attribute (implicitly set by the server) at the * specified index (as v2.x attributes) (can be NULL) * * @returns 0 on success, or a negative errno in case of an error. * The reference count of the returned nodes is increased. The caller must * free the node via kmip_node_free() when no longer needed. */ int kmip_get_create_response_payload(const struct kmip_node *node, enum kmip_object_type *obj_type, struct kmip_node **unique_id, unsigned int *num_attrs, unsigned int attr_index, struct kmip_node **attribute) { struct kmip_node *n; int rc; if (node == NULL) return -EINVAL; if (kmip_node_get_tag(node) != KMIP_TAG_RESPONSE_PAYLOAD) return -EBADMSG; if (obj_type != NULL) { n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_OBJECT_TYPE, 0); if (n == NULL) return -EBADMSG; *obj_type = kmip_node_get_enumeration(n); kmip_node_free(n); } if (unique_id != NULL) *unique_id = kmip_node_get_structure_element_by_tag( node, KMIP_TAG_UNIQUE_IDENTIFIER, 0); if (attribute == NULL && num_attrs == NULL) return 0; n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_TEMPLATE_ATTRIBUTE, 0); if (n == NULL) { if (num_attrs != NULL) *num_attrs = 0; if (attribute == NULL) return 0; rc = -ENOENT; goto error; } rc = kmip_get_attributes(n, num_attrs, attr_index, attribute); kmip_node_free(n); if (rc != 0) goto error; return 0; error: if (unique_id != NULL) { kmip_node_free(*unique_id); *unique_id = NULL; } return rc; } /** * Gets information from a Get Attribute List response payload node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Unique Identifier Yes Text String v1.0 * Enumeration v2.0 * Integer v2.0 * Attribute Name Yes Text String v1.x only * ... may be repeated * Attribute Reference Yes Enumeration v2.x only * Structure v2.x only * ... may be repeated * * @param node the KMIP node * @param unique_id the unique id node (can be NULL) * @param num_attr_refs On return: the number of attribute references * (can be NULL). * @param index the index of the attribute reference to get * @param attr_ref the attribute (as v2.x attribute reference) at the * specified index. Function returns -ENOENT if no * attribute is available at the index. * * @returns 0 on success, or a negative errno in case of an error. * The reference count of the returned nodes is increased. The caller must * free the node via kmip_node_free() when no longer needed. */ int kmip_get_get_attribute_list_response_payload(const struct kmip_node *node, struct kmip_node **unique_id, unsigned int *num_attr_refs, unsigned int index, struct kmip_node **attr_ref) { struct kmip_node *n; int rc; if (node == NULL) return -EINVAL; if (kmip_node_get_tag(node) != KMIP_TAG_RESPONSE_PAYLOAD) return -EBADMSG; if (unique_id != NULL) *unique_id = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_UNIQUE_IDENTIFIER, 0); if (num_attr_refs != NULL) *num_attr_refs = kmip_node_get_structure_element_count(node) - 1; if (attr_ref == NULL) return 0; n = kmip_node_get_structure_element_by_index(node, index + 1); if (n == NULL) { if (unique_id != NULL) { kmip_node_free(*unique_id); *unique_id = NULL; } return -ENOENT; } if (kmip_node_get_tag(n) == KMIP_TAG_ATTRIBUTE_REFERENCE) { /* Its already a KMIP v2.x attribute reference */ *attr_ref = n; return 0; } /* Must be a KMIP v1.x attribute name then */ rc = kmip_get_attribute_name_v1(n, attr_ref); kmip_node_free(n); if (rc != 0) { if (unique_id != NULL) { kmip_node_free(*unique_id); *unique_id = NULL; } return rc; } return 0; } /** * Gets information from a Get Attributes response payload node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Unique Identifier Yes Text String v1.0 * Enumeration v2.0 * Integer v2.0 * Attribute No Structure v1.x only * ... may be repeated * Attributes Yes Structure v2.x only * * @param node the KMIP node * @param unique_id the unique id node (can be NULL) * @param num_attrs On return: the number of attributes (can be NULL). * @param index the index of the attribute to get * @param v2_attr the attribute (as v2.x attribute) at the * specified index. Function returns -ENOENT if no * attribute is available at the index. * * @returns 0 on success, or a negative errno in case of an error. * The reference count of the returned nodes is increased. The caller must * free the node via kmip_node_free() when no longer needed. */ int kmip_get_get_attributes_response_payload(const struct kmip_node *node, struct kmip_node **unique_id, unsigned int *num_attrs, unsigned int index, struct kmip_node **v2_attr) { struct kmip_node *attr; int rc; if (node == NULL) return -EINVAL; if (kmip_node_get_tag(node) != KMIP_TAG_RESPONSE_PAYLOAD) return -EBADMSG; if (unique_id != NULL) *unique_id = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_UNIQUE_IDENTIFIER, 0); if (v2_attr == NULL && num_attrs == NULL) return 0; attr = kmip_node_get_structure_element_by_index(node, 1); if (attr == NULL) { if (num_attrs != NULL) *num_attrs = 0; if (v2_attr == NULL) return 0; rc = -ENOENT; goto error; } if (kmip_node_get_tag(attr) == KMIP_TAG_ATTRIBUTES) { /* Its already a KMIP v2.x attributes structure */ rc = kmip_get_attributes(attr, num_attrs, index, v2_attr); kmip_node_free(attr); if (rc != 0) goto error; return 0; } /* Must be a KMIP v1.x attribute then */ kmip_node_free(attr); if (num_attrs != NULL) *num_attrs = kmip_node_get_structure_element_count(node) - 1; if (v2_attr == NULL) return 0; attr = kmip_node_get_structure_element_by_index(node, index + 1); if (attr == NULL) { rc = -ENOENT; goto error; } rc = kmip_v2_attr_from_v1_attr(attr, v2_attr); kmip_node_free(attr); if (rc != 0) goto error; return 0; error: if (unique_id != NULL) { kmip_node_free(*unique_id); *unique_id = NULL; } return rc; } /** * Gets information from a response payload node that include a unique id and * an attribute. * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Unique Identifier Yes Text String v1.0 * Enumeration v2.0 * Integer v2.0 * Attribute Yes Structure v1.x only * * @param node the KMIP node * @param unique_id the unique id node (can be NULL) * @param v2_attr the added attribute (as v2.x attribute). * For KMIP v1.y no attribute is returned. * * @returns 0 on success, or a negative errno in case of an error. * The reference count of the returned nodes is increased. The caller must * free the node via kmip_node_free() when no longer needed. */ static int kmip_get_unique_id_attribute_response_payload( const struct kmip_node *node, struct kmip_node **unique_id, struct kmip_node **v2_attr) { struct kmip_node *attr; int rc; if (node == NULL) return -EINVAL; if (kmip_node_get_tag(node) != KMIP_TAG_RESPONSE_PAYLOAD) return -EBADMSG; if (unique_id != NULL) *unique_id = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_UNIQUE_IDENTIFIER, 0); if (v2_attr == NULL) return 0; /* KMIP v2.x does not send a attribute in the reply, but v1.x does */ attr = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_ATTRIBUTE, 0); if (attr == NULL) { *v2_attr = NULL; return 0; } rc = kmip_v2_attr_from_v1_attr(attr, v2_attr); kmip_node_free(attr); if (rc != 0) goto error; return 0; error: if (unique_id != NULL) { kmip_node_free(*unique_id); *unique_id = NULL; } return rc; } /** * Gets information from a Add Attribute response payload node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Unique Identifier Yes Text String v1.0 * Enumeration v2.0 * Integer v2.0 * Attribute Yes Structure v1.x only * * @param node the KMIP node * @param unique_id the unique id node (can be NULL) * @param v2_attr the added attribute (as v2.x attribute). * For KMIP v1.y no attribute is returned. * * @returns 0 on success, or a negative errno in case of an error. * The reference count of the returned nodes is increased. The caller must * free the node via kmip_node_free() when no longer needed. */ int kmip_get_add_attribute_response_payload(const struct kmip_node *node, struct kmip_node **unique_id, struct kmip_node **v2_attr) { return kmip_get_unique_id_attribute_response_payload(node, unique_id, v2_attr); } /** * Gets information from a Modify Attribute response payload node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Unique Identifier Yes Text String v1.0 * Enumeration v2.0 * Integer v2.0 * Attribute Yes Structure v1.x only * * @param node the KMIP node * @param unique_id the unique id node (can be NULL) * @param v2_attr the modified attribute (as v2.x attribute). * For KMIP v1.y no attribute is returned. * * @returns 0 on success, or a negative errno in case of an error. * The reference count of the returned nodes is increased. The caller must * free the node via kmip_node_free() when no longer needed. */ int kmip_get_modify_attribute_response_payload(const struct kmip_node *node, struct kmip_node **unique_id, struct kmip_node **v2_attr) { return kmip_get_unique_id_attribute_response_payload(node, unique_id, v2_attr); } /** * Gets information from a Set Attribute response payload node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Unique Identifier Yes Text String v1.0 * Enumeration v2.0 * Integer v2.0 * * KMIP v1.x does not have a Set Attribute operation. * * @param node the KMIP node * @param unique_id the unique id node (can be NULL) * * @returns 0 on success, or a negative errno in case of an error. * The reference count of the returned nodes is increased. The caller must * free the node via kmip_node_free() when no longer needed. */ int kmip_get_set_attribute_v2_response_payload(const struct kmip_node *node, struct kmip_node **unique_id) { return kmip_get_unique_id_attribute_response_payload(node, unique_id, NULL); } /** * Gets information from a Delete Attribute response payload node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Unique Identifier Yes Text String v1.0 * Enumeration v2.0 * Integer v2.0 * Attribute Yes Structure v1.x only * * @param node the KMIP node * @param unique_id the unique id node (can be NULL) * @param v2_attr the modified attribute (as v2.x attribute). * For KMIP v1.y no attribute is returned. * * @returns 0 on success, or a negative errno in case of an error. * The reference count of the returned nodes is increased. The caller must * free the node via kmip_node_free() when no longer needed. */ int kmip_get_delete_attribute_response_payload(const struct kmip_node *node, struct kmip_node **unique_id, struct kmip_node **v2_attr) { return kmip_get_unique_id_attribute_response_payload(node, unique_id, v2_attr); } /** * Gets information from a response payload node that only includes a unique id: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Unique Identifier Yes Text String v1.0 * Enumeration v2.0 * Integer v2.0 * * @param node the KMIP node * @param unique_id the unique id node (can be NULL) * * @returns 0 on success, or a negative errno in case of an error. * The reference count of the returned nodes is increased. The caller must * free the node via kmip_node_free() when no longer needed. */ static int kmip_get_unique_id_response_payload(const struct kmip_node *node, struct kmip_node **unique_id) { if (node == NULL) return -EINVAL; if (kmip_node_get_tag(node) != KMIP_TAG_RESPONSE_PAYLOAD) return -EBADMSG; if (unique_id != NULL) *unique_id = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_UNIQUE_IDENTIFIER, 0); return 0; } /** * Gets information from a Activate response payload node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Unique Identifier Yes Text String v1.0 * Enumeration v2.0 * Integer v2.0 * * @param node the KMIP node * @param unique_id the unique id node (can be NULL) * * @returns 0 on success, or a negative errno in case of an error. * The reference count of the returned nodes is increased. The caller must * free the node via kmip_node_free() when no longer needed. */ int kmip_get_activate_response_payload(const struct kmip_node *node, struct kmip_node **unique_id) { return kmip_get_unique_id_response_payload(node, unique_id); } /** * Gets information from a Destroy response payload node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Unique Identifier Yes Text String v1.0 * Enumeration v2.0 * Integer v2.0 * * @param node the KMIP node * @param unique_id the unique id node (can be NULL) * * @returns 0 on success, or a negative errno in case of an error. * The reference count of the returned nodes is increased. The caller must * free the node via kmip_node_free() when no longer needed. */ int kmip_get_destroy_response_payload(const struct kmip_node *node, struct kmip_node **unique_id) { return kmip_get_unique_id_response_payload(node, unique_id); } /** * Gets information from a Archive response payload node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Unique Identifier Yes Text String v1.0 * Enumeration v2.0 * Integer v2.0 * * @param node the KMIP node * @param unique_id the unique id node (can be NULL) * * @returns 0 on success, or a negative errno in case of an error. * The reference count of the returned nodes is increased. The caller must * free the node via kmip_node_free() when no longer needed. */ int kmip_get_archive_response_payload(const struct kmip_node *node, struct kmip_node **unique_id) { return kmip_get_unique_id_response_payload(node, unique_id); } /** * Gets information from a Recover response payload node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Unique Identifier Yes Text String v1.0 * Enumeration v2.0 * Integer v2.0 * * @param node the KMIP node * @param unique_id the unique id node (can be NULL) * * @returns 0 on success, or a negative errno in case of an error. * The reference count of the returned nodes is increased. The caller must * free the node via kmip_node_free() when no longer needed. */ int kmip_get_recover_response_payload(const struct kmip_node *node, struct kmip_node **unique_id) { return kmip_get_unique_id_response_payload(node, unique_id); } /** * Gets information from a Revoke response payload node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Unique Identifier Yes Text String v1.0 * Enumeration v2.0 * Integer v2.0 * * @param node the KMIP node * @param unique_id the unique id node (can be NULL) * * @returns 0 on success, or a negative errno in case of an error. * The reference count of the returned nodes is increased. The caller must * free the node via kmip_node_free() when no longer needed. */ int kmip_get_revoke_response_payload(const struct kmip_node *node, struct kmip_node **unique_id) { return kmip_get_unique_id_response_payload(node, unique_id); } /** * Gets information from a Locate response payload node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Located Items No Integer v2.0 * Unique Identifier Yes Text String v1.0 * Enumeration v2.0 * Integer v2.0 * ... may be repated * * @param node the KMIP node * @param located_items On return: the total number of located items. * Only available since KMIP v2.x. If not available, * it is returned as -1. May be NULL. * @param num_items On return: the returned number of located items. * May be NULL. * @param index The index of the returned item. * @param unique_id the unique id node at the specified index. * Function returns -ENOENT if no item is available at * the index. May be NULL. * * @returns 0 on success, or a negative errno in case of an error. * The reference count of the returned nodes is increased. The caller must * free the node via kmip_node_free() when no longer needed. */ int kmip_get_locate_response_payload(const struct kmip_node *node, int32_t *located_items, unsigned int *num_items, unsigned int index, struct kmip_node **unique_id) { struct kmip_node *n; if (node == NULL) return -EINVAL; if (kmip_node_get_tag(node) != KMIP_TAG_RESPONSE_PAYLOAD) return -EBADMSG; if (located_items != NULL) { n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_LOCATED_ITEMS, 0); *located_items = (n != NULL ? kmip_node_get_integer(n) : -1); kmip_node_free(n); } if (num_items != NULL) *num_items = kmip_node_get_structure_element_by_tag_count(node, KMIP_TAG_UNIQUE_IDENTIFIER); if (unique_id != NULL) { *unique_id = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_UNIQUE_IDENTIFIER, index); if (*unique_id == NULL) return -ENOENT; } return 0; } /** * Gets information from a Register response payload node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Unique Identifier Yes Text String v1.0 * Enumeration v2.0 * Integer v2.0 * Template-Attribute No Structure v1.x only * * * @param node the KMIP node * @param obj_type the object type of the created object (can be NULL) * @param unique_id the unique id node (can be NULL) * @param num_attrs On return: the number of attributes (can be NULL). * @param attr_index the index of the attribute to get * @param attributes the attribute (implicitly set by the server) at the * specified index (as v2.x attributes) (can be NULL) * * @returns 0 on success, or a negative errno in case of an error. * The reference count of the returned nodes is increased. The caller must * free the node via kmip_node_free() when no longer needed. */ int kmip_get_register_response_payload(const struct kmip_node *node, struct kmip_node **unique_id, unsigned int *num_attrs, unsigned int attr_index, struct kmip_node **attribute) { struct kmip_node *attrs; int rc; if (node == NULL) return -EINVAL; if (kmip_node_get_tag(node) != KMIP_TAG_RESPONSE_PAYLOAD) return -EBADMSG; if (unique_id != NULL) *unique_id = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_UNIQUE_IDENTIFIER, 0); if (attribute == NULL && num_attrs == NULL) return 0; attrs = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_TEMPLATE_ATTRIBUTE, 0); if (attrs == NULL) { if (num_attrs != NULL) *num_attrs = 0; if (attribute == NULL) return 0; rc = -ENOENT; goto error; } rc = kmip_get_attributes(attrs, num_attrs, attr_index, attribute); kmip_node_free(attrs); if (rc != 0) goto error; return 0; error: if (unique_id != NULL) { kmip_node_free(*unique_id); *unique_id = NULL; } return rc; } /** * Gets information from a Get response payload node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Object Type Yes Enumeration v1.0 * Unique Identifier Yes Text String v1.0 * Enumeration v2.0 * Integer v2.0 * Yes Structure v1.0 * * @param node the KMIP node * @param obj_type the object type of the created object (can be NULL) * @param unique_id the unique id node (can be NULL) * @param object the object (can be NULL) * * @returns 0 on success, or a negative errno in case of an error. * The reference count of the returned nodes is increased. The caller must * free the node via kmip_node_free() when no longer needed. */ int kmip_get_get_response_payload(const struct kmip_node *node, enum kmip_object_type *obj_type, struct kmip_node **unique_id, struct kmip_node **object) { struct kmip_node *n; int rc = 0; if (node == NULL) return -EINVAL; if (kmip_node_get_tag(node) != KMIP_TAG_RESPONSE_PAYLOAD) return -EBADMSG; if (obj_type != NULL) { n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_OBJECT_TYPE, 0); if (n == NULL) return -EBADMSG; *obj_type = kmip_node_get_enumeration(n); kmip_node_free(n); } if (unique_id != NULL) { *unique_id = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_UNIQUE_IDENTIFIER, 0); if (*unique_id == NULL) return -EBADMSG; } if (object == NULL) return 0; *object = kmip_node_get_structure_element_by_index(node, 2); if (*object == NULL) { rc = -EBADMSG; goto error; } switch (kmip_node_get_tag(*object)) { case KMIP_TAG_CERTIFICATE: case KMIP_TAG_CERTIFICATE_REQUEST: case KMIP_TAG_OPAQUE_OBJECT: case KMIP_TAG_PGP_KEY: case KMIP_TAG_PRIVATE_KEY: case KMIP_TAG_PUBLIC_KEY: case KMIP_TAG_SECRET_DATA: case KMIP_TAG_SYMMETRIC_KEY: break; default: kmip_node_free(*object); *object = NULL; rc = -EBADMSG; goto error; } return 0; error: if (unique_id != NULL && *unique_id != NULL) { kmip_node_free(*unique_id); *unique_id = NULL; } return rc; } opencryptoki-opencryptoki-451d99c/usr/sbin/p11kmip/kmipclient/tls.c000066400000000000000000000314011520105705100254560ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021-2024 * * 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 "kmip.h" #include "utils.h" #ifndef OPENSSL_VERSION_PREREQ #if defined(OPENSSL_VERSION_MAJOR) && defined(OPENSSL_VERSION_MINOR) #define OPENSSL_VERSION_PREREQ(maj, min) \ ((OPENSSL_VERSION_MAJOR << 16) + \ OPENSSL_VERSION_MINOR >= ((maj) << 16) + (min)) #else #define OPENSSL_VERSION_PREREQ(maj, min) \ (OPENSSL_VERSION_NUMBER >= (((maj) << 28) | \ ((min) << 20))) #endif #endif /** * Verify the pinned public key of the server of a plain TLS KMIP connection * * @param conn the KMIP connection to free * @param cert_pubkey the server certificate's public key * @param debug if true, debug messages are printed */ static int kmip_connection_tls_verify_pinned_pubkey( struct kmip_connection *conn, EVP_PKEY *cert_pubkey, bool debug) { EVP_PKEY *pinned_key = NULL; int rc = 0; FILE *fp; fp = fopen(conn->config.tls_pinned_pubkey, "r"); if (fp == NULL) { rc = -errno; kmip_debug(debug, "Failed to read pinned public key '%s': %s", conn->config.tls_pinned_pubkey, strerror(-rc)); return rc; } pinned_key = PEM_read_PUBKEY(fp, NULL, NULL, NULL); fclose(fp); if (pinned_key == NULL) { kmip_debug(debug, "PEM_read_PUBKEY failed: '%s'", conn->config.tls_pinned_pubkey); if (debug) ERR_print_errors_fp(stderr); return -EIO; } #if !OPENSSL_VERSION_PREREQ(3, 0) if (EVP_PKEY_cmp(pinned_key, cert_pubkey) != 1) { #else if (EVP_PKEY_eq(pinned_key, cert_pubkey) != 1) { #endif kmip_debug(debug, "Server public key does not match the pinned " "public key '%s'", conn->config.tls_pinned_pubkey); rc = -EPERM; } EVP_PKEY_free(pinned_key); return rc; } /** * Verify the pinned server certificate key of the server of a plain TLS KMIP * connection * * @param conn the KMIP connection to free * @param server_cert the server certificate * @param debug if true, debug messages are printed */ static int kmip_connection_tls_verify_pinned_cert( struct kmip_connection *conn, X509 *server_cert, bool debug) { X509 *pinned_cert = NULL; int rc = 0; FILE *fp; fp = fopen(conn->config.tls_server_cert, "r"); if (fp == NULL) { rc = -errno; kmip_debug(debug, "Failed to read pinned server cert: %s", conn->config.tls_server_cert, strerror(-rc)); return rc; } pinned_cert = PEM_read_X509(fp, NULL, NULL, NULL); fclose(fp); if (pinned_cert == NULL) { kmip_debug(debug, "PEM_read_X509 failed: '%s'", conn->config.tls_server_cert); if (debug) ERR_print_errors_fp(stderr); return -EIO; } if (X509_cmp(pinned_cert, server_cert) != 0) { kmip_debug(debug, "Server certificate does not match the " "pinned certificate '%s'", conn->config.tls_server_cert); rc = -EPERM; } X509_free(pinned_cert); return rc; } /** * Verify the issuer certificate key of the server of a plain TLS KMIP * connection * * @param conn the KMIP connection to free * @param server_cert the server certificate * @param debug if true, debug messages are printed */ static int kmip_connection_tls_verify_issuer_cert( struct kmip_connection *conn, X509 *server_cert, bool debug) { X509 *issuer_cert = NULL; int rc = 0; FILE *fp; fp = fopen(conn->config.tls_issuer_cert, "r"); if (fp == NULL) { rc = -errno; kmip_debug(debug, "Failed to read issuer cert '%s': %s", conn->config.tls_issuer_cert, strerror(-rc)); return rc; } issuer_cert = PEM_read_X509(fp, NULL, NULL, NULL); fclose(fp); if (issuer_cert == NULL) { kmip_debug(debug, "PEM_read_X509 failed: '%s'", conn->config.tls_issuer_cert); if (debug) ERR_print_errors_fp(stderr); return -EIO; } if (X509_check_issued(issuer_cert, server_cert) != X509_V_OK) { kmip_debug(debug, "The server certificate was not issued by " "certificate '%s'", conn->config.tls_issuer_cert); rc = -EPERM; } X509_free(issuer_cert); return rc; } /** * Verify the server of a plain TLS KMIP connection * * @param conn the KMIP connection to free * @param debug if true, debug messages are printed */ static int kmip_connection_tls_verify_server(struct kmip_connection *conn, bool debug) { X509 *server_cert; int rc; server_cert = SSL_get_peer_certificate(conn->plain_tls.ssl); if (server_cert == NULL) { kmip_debug(debug, "SSL_get_peer_certificate failed"); if (debug) ERR_print_errors_fp(stderr); rc = -EIO; goto out; } if (conn->config.tls_issuer_cert != NULL) { rc = kmip_connection_tls_verify_issuer_cert(conn, server_cert, debug); if (rc != 0) { kmip_debug(debug, "kmip_connection_tls_verify_issuer_cert " "failed"); goto out; } } if (conn->config.tls_server_cert != NULL) { rc = kmip_connection_tls_verify_pinned_cert(conn, server_cert, debug); if (rc != 0) { kmip_debug(debug, "kmip_connection_tls_verify_pinned_cert " "failed"); goto out; } } if (conn->config.tls_pinned_pubkey != NULL) { rc = kmip_connection_tls_verify_pinned_pubkey(conn, X509_get0_pubkey(server_cert), debug); if (rc != 0) { kmip_debug(debug, "kmip_connection_tls_pinned_pubkey failed"); goto out; } } rc = 0; out: if (server_cert != NULL) X509_free(server_cert); return rc; } /** * Initializes a new plain TLS connection to a KMIP server. * * @param conn The KMIP connection * @param debug if true, debug messages are printed * * @returns 0 in case of success, or a negative errno value */ int kmip_connection_tls_init(struct kmip_connection *conn, bool debug) { char *hostname = NULL, *port = NULL, *tok; struct stat sb; int rc; if (conn == NULL) return -EINVAL; conn->plain_tls.ssl_ctx = SSL_CTX_new(TLS_client_method()); if (conn->plain_tls.ssl_ctx == NULL) { kmip_debug(debug, "SSL_CTX_new failed"); if (debug) ERR_print_errors_fp(stderr); return -EIO; } if (SSL_CTX_use_certificate_file(conn->plain_tls.ssl_ctx, conn->config.tls_client_cert, SSL_FILETYPE_PEM) != 1) { kmip_debug(debug, "Loading the client certificate from '%s' " "failed", conn->config.tls_client_cert); if (debug) ERR_print_errors_fp(stderr); rc = -EIO; goto out; } if (SSL_CTX_use_PrivateKey(conn->plain_tls.ssl_ctx, conn->config.tls_client_key) != 1) { kmip_debug(debug, "Setting the client key from PKEY %p " "failed", conn->config.tls_client_key); if (debug) ERR_print_errors_fp(stderr); rc = -EIO; goto out; } if (conn->config.tls_ca != NULL) { if (stat(conn->config.tls_ca, &sb) != 0) { rc = -errno; kmip_debug(debug, "stat failed on '%s': %s", conn->config.tls_ca, strerror(-rc)); goto out; } if (S_ISDIR(sb.st_mode)) { if (SSL_CTX_load_verify_locations( conn->plain_tls.ssl_ctx, NULL, conn->config.tls_ca) != 1) { kmip_debug(debug, "Setting the verify location " "to '%s' failed", conn->config.tls_ca); if (debug) ERR_print_errors_fp(stderr); rc = -EIO; goto out; } } else { if (SSL_CTX_load_verify_locations( conn->plain_tls.ssl_ctx, conn->config.tls_ca, NULL) != 1) { kmip_debug(debug, "Setting the verify location " "to '%s' failed", conn->config.tls_ca); if (debug) ERR_print_errors_fp(stderr); rc = -EIO; goto out; } } } conn->plain_tls.bio = BIO_new_buffer_ssl_connect(conn->plain_tls.ssl_ctx); if (conn->plain_tls.bio == NULL) { kmip_debug(debug, "BIO_new_ssl_connect failed"); if (debug) ERR_print_errors_fp(stderr); rc = -EIO; goto out; } BIO_get_ssl(conn->plain_tls.bio, &conn->plain_tls.ssl); if (conn->plain_tls.ssl == NULL) { kmip_debug(debug, "BIO_get_ssl failed"); if (debug) ERR_print_errors_fp(stderr); rc = -EIO; goto out; } hostname = strdup(conn->config.server); if (hostname == NULL) { kmip_debug(debug, "strdup failed"); rc = -ENOMEM; goto out; } /* Split port number from hostname, if specified */ if (hostname[0] == '[') { /* IPv6 address enclosed in square brackets */ tok = strchr(hostname, ']'); if (tok == NULL) { kmip_debug(debug, "malformed IPv6 address"); rc = -EINVAL; goto out; } tok++; if (*tok == ':') { port = tok + 1; *tok = 0; } } else { /* hostname or IPv4 address */ tok = strchr(hostname, ':'); if (tok != NULL) { port = tok + 1; *tok = 0; } } kmip_debug(debug, "hostname: '%s'", hostname); if (port == NULL) { port = KMIP_DEFAULT_PLAIN_TLS_PORT; kmip_debug(debug, "port: default (%s)", port); } else { kmip_debug(debug, "port: %s", port); } if (conn->config.tls_verify_host) { SSL_set_hostflags(conn->plain_tls.ssl, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS); #if OPENSSL_VERSION_PREREQ(4, 0) if (SSL_set1_ipaddr(conn->plain_tls.ssl, hostname) != 1 && SSL_set1_dnsname(conn->plain_tls.ssl, hostname) != 1) { kmip_debug(debug, "SSL_set1_ipaddr/dnsname failed"); #else if (SSL_set1_host(conn->plain_tls.ssl, hostname) != 1) { kmip_debug(debug, "SSL_set1_host failed"); #endif if (debug) ERR_print_errors_fp(stderr); rc = -EIO; goto out; } } SSL_set_verify(conn->plain_tls.ssl, (conn->config.tls_verify_peer || conn->config.tls_verify_host) ? SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL); if (conn->config.tls_cipher_list != NULL) { if (SSL_set_cipher_list(conn->plain_tls.ssl, conn->config.tls_cipher_list) != 1) { kmip_debug(debug, "SSL_set_cipher_list failed"); if (debug) ERR_print_errors_fp(stderr); rc = -EIO; goto out; } } if (conn->config.tls13_cipher_list != NULL) { if (SSL_set_ciphersuites(conn->plain_tls.ssl, conn->config.tls13_cipher_list) != 1) { kmip_debug(debug, "SSL_set_ciphersuites failed"); if (debug) ERR_print_errors_fp(stderr); rc = -EIO; goto out; } } SSL_set_mode(conn->plain_tls.ssl, SSL_MODE_AUTO_RETRY); BIO_set_conn_hostname(conn->plain_tls.bio, hostname); BIO_set_conn_port(conn->plain_tls.bio, port); if (BIO_do_connect(conn->plain_tls.bio) != 1) { kmip_debug(debug, "BIO_do_connect failed"); if (debug) ERR_print_errors_fp(stderr); rc = -EIO; goto out; } kmip_debug(debug, "TLS connection established using %s", SSL_get_cipher_name(conn->plain_tls.ssl)); rc = kmip_connection_tls_verify_server(conn, debug); if (rc != 0) { kmip_debug(debug, "kmip_connection_tls_verify_server failed"); if (debug) ERR_print_errors_fp(stderr); rc = -EIO; goto out; } rc = 0; out: if (rc != 0) kmip_connection_tls_term(conn); if (hostname != NULL) free(hostname); return rc; } /** * Perform a request over the KMIP connection * * @param conn n the KMIP connection * @param request the request to send * @param response On return: the received response. Must be freed by * the caller. * * @param debug if true, debug messages are printed * * @returns 0 in case of success, or a negative errno value */ int kmip_connection_tls_perform(struct kmip_connection *conn, struct kmip_node *request, struct kmip_node **response, bool debug) { size_t size; int rc; if (conn == NULL || request == NULL || response == NULL) return -EINVAL; *response = NULL; /* Send out the request */ rc = kmip_encode_ttlv(request, conn->plain_tls.bio, &size, debug); if (rc != 0) { kmip_debug(debug, "kmip_encode_ttlv failed"); goto out; } if (BIO_flush(conn->plain_tls.bio) != 1) { kmip_debug(debug, "BIO_flush failed"); goto out; } kmip_debug(debug, "%lu bytes sent", size); /* receive the response */ rc = kmip_decode_ttlv(conn->plain_tls.bio, NULL, response, debug); if (rc != 0 || *response == NULL) { kmip_debug(debug, "kmip_decode_ttlv failed"); goto out; } rc = 0; out: if (rc != 0) { if (BIO_reset(conn->plain_tls.bio) != 1) kmip_debug(debug, "BIO_reset failed"); } return rc; } /** * Terminates a plain TLS KMIP connection. * * @param conn the KMIP connection to free */ void kmip_connection_tls_term(struct kmip_connection *conn) { if (conn == NULL) return; if (conn->plain_tls.bio != NULL) { BIO_ssl_shutdown(conn->plain_tls.bio); BIO_free_all(conn->plain_tls.bio); } if (conn->plain_tls.ssl_ctx != NULL) SSL_CTX_free(conn->plain_tls.ssl_ctx); conn->plain_tls.bio = NULL; conn->plain_tls.ssl_ctx = NULL; conn->plain_tls.ssl = NULL; } opencryptoki-opencryptoki-451d99c/usr/sbin/p11kmip/kmipclient/ttlv.c000066400000000000000000000273671520105705100256650ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021-2024 * * 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 "kmip.h" #include "utils.h" #define KMIP_TTLV_HEADER_LENGTH 8 #define KMIP_TTLV_BLOCK_LENGTH 8 /** * Decode a KMIP node from the data in BIO using the TTLV encoding. * * @param bio the OpenSSL bio to read the data from * @param size Optional: If not NULL: * On entry: The number of bytes available to read * On return: decremented by the number of bytes read * If NULL, it is assumed that we can read from bio * as many bytes as needed. * @param node On return: the decoded node. The newly allocated * node has a reference count of 1. * @param debug if true, debug messages are printed * * @returns 0 in case of success, or a negative errno value */ int kmip_decode_ttlv(BIO *bio, size_t *size, struct kmip_node **node, bool debug) { unsigned char padding[KMIP_TTLV_BLOCK_LENGTH]; unsigned char ttlv[KMIP_TTLV_HEADER_LENGTH]; size_t value_len, pad_len; struct kmip_node *n, *e; void *value = NULL; uint32_t int32; uint64_t int64; int rc; if (bio == NULL || node == NULL) return -EINVAL; if (size != NULL) kmip_debug(debug, "size: %lu", *size); else kmip_debug(debug, "size: unknown"); if (size != NULL && *size < sizeof(ttlv)) { kmip_debug(debug, "length %u > available size %lu", sizeof(ttlv), *size); return -EMSGSIZE; } if (BIO_read(bio, ttlv, sizeof(ttlv)) != sizeof(ttlv)) { kmip_debug(debug, "BIO_read failed"); return -EIO; } if (size != NULL) *size -= sizeof(ttlv); n = calloc(1, sizeof(struct kmip_node)); if (n == NULL) { kmip_debug(debug, "calloc failed"); return -ENOMEM; } n->ref_count = 1; /* Tag: 3-byte binary unsigned integer, transmitted big endian */ n->tag |= (uint32_t)(ttlv[0] << 16); n->tag |= (uint32_t)(ttlv[1] << 8); n->tag |= (uint32_t)(ttlv[2]); /* Type: 1 byte containing a coded value that indicates the data type */ n->type = ttlv[3]; /* Length: 32-bit binary integer, transmitted big-endian */ n->length |= (uint32_t)(ttlv[4] << 24); n->length |= (uint32_t)(ttlv[5] << 16); n->length |= (uint32_t)(ttlv[6] << 8); n->length |= (uint32_t)(ttlv[7]); kmip_debug(debug, "tag: 0x%x type: 0x%x, length: %u", n->tag, n->type, n->length); switch (n->type) { case KMIP_TYPE_STRUCTURE: value_len = n->length; break; case KMIP_TYPE_BIG_INTEGER: case KMIP_TYPE_TEXT_STRING: case KMIP_TYPE_BYTE_STRING: value_len = n->length; value = calloc(1, value_len + 1); if (value == NULL) { kmip_debug(debug, "calloc failed"); rc = -ENOMEM; goto out; } break; case KMIP_TYPE_INTEGER: case KMIP_TYPE_ENUMERATION: case KMIP_TYPE_INTERVAL: value_len = sizeof(int32); value = &int32; break; case KMIP_TYPE_LONG_INTEGER: case KMIP_TYPE_BOOLEAN: case KMIP_TYPE_DATE_TIME: case KMIP_TYPE_DATE_TIME_EXTENDED: value_len = sizeof(int64); value = &int64; break; default: kmip_debug(debug, "unknown type: 0x%x", n->type); rc = -EBADMSG; goto out; } if (n->length != value_len) { kmip_debug(debug, "length %u not as expected (%lu)", n->length, value_len); rc = -EBADMSG; goto out; } if (size != NULL && *size < n->length) { kmip_debug(debug, "length %u > available size %lu", n->length, *size); rc = -EMSGSIZE; goto out; } if (n->type != KMIP_TYPE_STRUCTURE && value_len > 0) { if (BIO_read(bio, value, value_len) != (int)value_len) { kmip_debug(debug, "BIO_read failed"); rc = -EIO; goto out; } } if (size != NULL) *size -= value_len; if ((value_len % KMIP_TTLV_BLOCK_LENGTH) != 0) { pad_len = KMIP_TTLV_BLOCK_LENGTH - (value_len % KMIP_TTLV_BLOCK_LENGTH); kmip_debug(debug, "pad_len: %lu", pad_len); if (BIO_read(bio, padding, pad_len) != (int)pad_len) { kmip_debug(debug, "BIO_read failed (padding)"); rc = -EIO; goto out; } if (size != NULL) *size -= pad_len; } switch (n->type) { case KMIP_TYPE_STRUCTURE: while (value_len > 0) { rc = kmip_decode_ttlv(bio, &value_len, &e, debug); if (rc != 0) { kmip_debug(debug, "kmip_decode_ttlv failed: " "rc: %d", rc); goto out; } rc = kmip_node_add_structure_element(n, e); kmip_node_free(e); if (rc != 0) { kmip_debug(debug, "kmip_node_structure_add_element " "failed: rc: %d", rc); goto out; } } break; case KMIP_TYPE_INTEGER: n->integer_value = be32toh(int32); break; case KMIP_TYPE_LONG_INTEGER: n->long_value = be64toh(int64); break; case KMIP_TYPE_BIG_INTEGER: rc = kmip_decode_bignum(value, value_len, &n->big_integer_value); if (rc != 0) { kmip_debug(debug, "kmip_decode_bignum failed"); goto out; } free(value); value = NULL; break; case KMIP_TYPE_ENUMERATION: n->enumeration_value = be32toh(int32); break; case KMIP_TYPE_BOOLEAN: n->boolean_value = int64 != 0; break; case KMIP_TYPE_TEXT_STRING: n->text_value = value; break; case KMIP_TYPE_BYTE_STRING: n->bytes_value = value; break; case KMIP_TYPE_DATE_TIME: n->date_time_value = be64toh(int64); break; case KMIP_TYPE_INTERVAL: n->interval_value = be32toh(int32); break; case KMIP_TYPE_DATE_TIME_EXTENDED: n->date_time_ext_value = be64toh(int64); break; default: kmip_debug(debug, "unknown type: 0x%x", n->type); rc = -EBADMSG; goto out; } *node = n; rc = 0; out: if (rc != 0) { switch (n->type) { case KMIP_TYPE_BIG_INTEGER: case KMIP_TYPE_TEXT_STRING: case KMIP_TYPE_BYTE_STRING: free(value); break; default: break; } kmip_node_free(n); } return rc; } /** * Gets the length of the value part of a KMIP node (in TTLV encoding) */ static int kmip_node_get_length(struct kmip_node *node, size_t *length) { struct kmip_node *element; size_t len; int rc; if (node == NULL || length == NULL) return -EINVAL; switch (node->type) { case KMIP_TYPE_STRUCTURE: *length = 0; element = node->structure_value; while (element != NULL) { rc = kmip_node_get_length(element, &len); if (rc != 0) return rc; *length += KMIP_TTLV_HEADER_LENGTH + len; if ((len % KMIP_TTLV_BLOCK_LENGTH) != 0) *length += KMIP_TTLV_BLOCK_LENGTH - (len % KMIP_TTLV_BLOCK_LENGTH); element = element->next; } break; case KMIP_TYPE_INTEGER: case KMIP_TYPE_ENUMERATION: case KMIP_TYPE_INTERVAL: *length = sizeof(int32_t); break; case KMIP_TYPE_LONG_INTEGER: case KMIP_TYPE_BOOLEAN: case KMIP_TYPE_DATE_TIME: case KMIP_TYPE_DATE_TIME_EXTENDED: *length = sizeof(int64_t); break; case KMIP_TYPE_BIG_INTEGER: *length = kmip_encode_bignum_length(node->big_integer_value); /* BIG INTEGERS must be a multiple of 8 bytes long */ if ((*length % KMIP_BIG_INTEGER_BLOCK_LENGTH) != 0) *length += KMIP_BIG_INTEGER_BLOCK_LENGTH - (*length % KMIP_BIG_INTEGER_BLOCK_LENGTH); break; case KMIP_TYPE_BYTE_STRING: *length = node->length; break; case KMIP_TYPE_TEXT_STRING: if (node->text_value != NULL) *length = strlen(node->text_value); else *length = 0; break; default: return -EINVAL; } return 0; } /** * Encode a KMIP node into a BIO using the TTLV encoding. * * @param node the node to encode * @param bio the OpenSSL bio to write the data to * @param size On return: the number of bytes written to BIO * @param debug if true, debug messages are printed * * @returns 0 in case of success, or a negative errno value */ int kmip_encode_ttlv(struct kmip_node *node, BIO *bio, size_t *size, bool debug) { const unsigned char padding[KMIP_TTLV_BLOCK_LENGTH] = { 0 }; unsigned char ttlv[KMIP_TTLV_HEADER_LENGTH]; size_t len, elem_len, value_len, pad_len; struct kmip_node *element; void *value = NULL; uint32_t int32; uint64_t int64; int rc; if (bio == NULL || node == NULL || size == NULL) return -EINVAL; kmip_debug(debug, "tag: 0x%x type: 0x%x, length: %u", node->tag, node->type, node->length); *size = 0; /* Update node's length field to match node's current data */ rc = kmip_node_get_length(node, &len); if (rc != 0) { kmip_debug(debug, "kmip_node_get_length failed"); return rc; } node->length = len; /* Tag: 3-byte binary unsigned integer, transmitted big endian */ ttlv[0] = (node->tag & 0xff0000) >> 16; ttlv[1] = (node->tag & 0xff00) >> 8; ttlv[2] = (node->tag & 0xff); /* Type: 1 byte containing a coded value that indicates the data type */ ttlv[3] = node->type; /* Length: 32-bit binary integer, transmitted big-endian */ ttlv[4] = (node->length & 0xff000000) >> 24; ttlv[5] = (node->length & 0xff0000) >> 16; ttlv[6] = (node->length & 0xff00) >> 8; ttlv[7] = (node->length & 0xff); if (BIO_write(bio, ttlv, sizeof(ttlv)) != sizeof(ttlv)) { kmip_debug(debug, "BIO_write failed"); return -EIO; } *size += sizeof(ttlv); switch (node->type) { case KMIP_TYPE_STRUCTURE: value_len = 0; element = node->structure_value; while (element != NULL) { rc = kmip_encode_ttlv(element, bio, &elem_len, debug); if (rc != 0) { kmip_debug(debug, "kmip_encode_ttlv failed"); return rc; } value_len += elem_len; element = element->next; } if (value_len != node->length) { kmip_debug(debug, "written length %lu not as expected " "(%u)", len, node->length); return -EIO; } break; case KMIP_TYPE_INTEGER: int32 = htobe32(node->integer_value); value_len = sizeof(int32); value = &int32; break; case KMIP_TYPE_LONG_INTEGER: int64 = htobe64(node->long_value); value_len = sizeof(int64); value = &int64; break; case KMIP_TYPE_BIG_INTEGER: value_len = node->length; /* was already calculated above */ value = malloc(value_len); if (value == NULL) { kmip_debug(debug, "malloc failed"); return -ENOMEM; } rc = kmip_encode_bignum(node->big_integer_value, value, value_len); if (rc != 0) { kmip_debug(debug, "kmip_encode_bignum failed"); goto out; } break; case KMIP_TYPE_ENUMERATION: int32 = htobe32(node->enumeration_value); value_len = sizeof(int32); value = &int32; break; case KMIP_TYPE_BOOLEAN: int64 = node->boolean_value ? 1 : 0; value_len = sizeof(int64); value = &int64; break; case KMIP_TYPE_TEXT_STRING: value_len = node->length; value = node->text_value; break; case KMIP_TYPE_BYTE_STRING: value_len = node->length; value = node->bytes_value; break; case KMIP_TYPE_DATE_TIME: int64 = htobe64(node->date_time_value); value_len = sizeof(int64); value = &int64; break; case KMIP_TYPE_INTERVAL: int32 = htobe32(node->interval_value); value_len = sizeof(int32); value = &int32; break; case KMIP_TYPE_DATE_TIME_EXTENDED: int64 = htobe64(node->date_time_ext_value); value_len = sizeof(int64); value = &int64; break; default: kmip_debug(debug, "unknown type: 0x%x", node->type); return -EINVAL; } if (value != NULL) { if (BIO_write(bio, value, value_len) != (int)value_len) { kmip_debug(debug, "BIO_write failed"); rc = -EIO; goto out; } } *size += value_len; if ((value_len % KMIP_TTLV_BLOCK_LENGTH) != 0) { pad_len = KMIP_TTLV_BLOCK_LENGTH - (value_len % KMIP_TTLV_BLOCK_LENGTH); kmip_debug(debug, "pad_len: %lu", pad_len); if (BIO_write(bio, padding, pad_len) != (int)pad_len) { kmip_debug(debug, "BIO_write failed (padding)"); rc = -EIO; goto out; } *size += pad_len; } kmip_debug(debug, "size: %lu", *size); rc = 0; out: if (node->type == KMIP_TYPE_BIG_INTEGER) free(value); return rc; } opencryptoki-opencryptoki-451d99c/usr/sbin/p11kmip/kmipclient/utils.c000066400000000000000000000360511520105705100260220ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021-2024 * * 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 _DEFAULT_SOURCE #include #include #include #include #include #include "utils.h" #include "names.h" /** * Print a debug message */ void kmip_print_debug(const char *func, const char *fmt, ...) { char tmp_fmt[200]; va_list ap; if (snprintf(tmp_fmt, sizeof(tmp_fmt), "DBG: %s: %s", func, fmt) > (int)sizeof(tmp_fmt)) return; va_start(ap, fmt); vwarnx(tmp_fmt, ap); va_end(ap); } /** * Parse a decimal string into a 64 bit signed value */ int kmip_parse_decimal_int(const char *str, int64_t *val) { long long v; char *endptr; if (str == NULL) return -EINVAL; errno = 0; v = strtoll(str, &endptr, 10); if ((errno == ERANGE && (v == LLONG_MAX || v == LLONG_MIN)) || (errno != 0 && v == 0)) return -EBADMSG; if (endptr == str || *endptr != 0) return -EBADMSG; *val = v; return 0; } /** * Parse a decimal string into a 64 bit unsigned value */ int kmip_parse_decimal_uint(const char *str, uint64_t *val) { unsigned long long v; char *endptr; if (str == NULL) return -EINVAL; errno = 0; v = strtoull(str, &endptr, 10); if ((errno == ERANGE && (v == 0 || v == ULLONG_MAX)) || (errno != 0 && v == 0)) return -EBADMSG; if (endptr == str || *endptr != 0) return -EBADMSG; *val = v; return 0; } /** * Parse a hex string into a 64 bit signed value */ int kmip_parse_hex_int(const char *str, int64_t *val) { long long v; char *endptr; if (str == NULL) return -EINVAL; if (strncmp(str, "0x", 2) != 0) return -EBADMSG; errno = 0; v = strtoll(str, &endptr, 16); if ((errno == ERANGE && (v == LLONG_MAX || v == LLONG_MIN)) || (errno != 0 && v == 0)) return -EBADMSG; if (endptr == str || *endptr != 0) return -EBADMSG; *val = v; return 0; } /** * Parse a hex string into a variable length signed big integer. * On return, val and length is set. The buffer returned in val must be freed * by the caller. */ int kmip_parse_hex(const char *str, bool has_prefix, unsigned char **val, uint32_t *length) { unsigned char *buf; BIGNUM *b = NULL; int len; if (str == NULL) return -EINVAL; if (has_prefix && strncmp(str, "0x", 2) != 0) return -EBADMSG; len = BN_hex2bn(&b, str + (has_prefix ? 2 : 0)); if (len <= 0) return -EBADMSG; if (len < (int)strlen(str) - (has_prefix ? 2 : 0)) return -EBADMSG; len = len / 2 + (len % 2 > 0 ? 1 : 0); buf = calloc(1, len); if (buf == NULL) { BN_free(b); return -ENOMEM; } if (BN_bn2binpad(b, buf, len) != len) { BN_free(b); free(buf); return -EIO; } *val = buf; *length = len; BN_free(b); return 0; } /** * Format a hex string from the byte array specified in val. The caller must * free the returned str. */ int kmip_format_hex(const unsigned char *val, uint32_t length, bool prefix, char **str) { uint32_t str_len, i; char tmp[4]; char *ret; str_len = length * 2 + (prefix ? 2 : 0) + 1; ret = calloc(1, str_len); if (ret == NULL) return -ENOMEM; if (prefix) strcat(ret, "0x"); for (i = 0; i < length; i++) { sprintf(tmp, "%02x", val[i]); strcat(ret, tmp); } *str = ret; return 0; } /** * Parse a hex string into a big number. * On return, val and length is set. The buffer returned in val must be freed * by the caller. */ int kmip_parse_bignum(const char *str, bool has_prefix, BIGNUM **bn) { unsigned char *buf; uint32_t len; int rc; if (str == NULL) return -EINVAL; rc = kmip_parse_hex(str, has_prefix, &buf, &len); if (rc != 0) return rc; rc = kmip_decode_bignum(buf, len, bn); free(buf); return rc; } /** * Format a hex string from a big number. The caller must free the returned str. */ int kmip_format_bignum(const BIGNUM *bn, bool prefix, char **str) { unsigned char *buf; uint32_t len; int rc; len = kmip_encode_bignum_length(bn); /* BIG INTEGERS must be a multiple of 8 bytes long */ if ((len % KMIP_BIG_INTEGER_BLOCK_LENGTH) != 0) len += KMIP_BIG_INTEGER_BLOCK_LENGTH - (len % KMIP_BIG_INTEGER_BLOCK_LENGTH); buf = malloc(len); if (buf == NULL) return -ENOMEM; rc = kmip_encode_bignum(bn, buf, len); if (rc != 0) { free(buf); return -EIO; } rc = kmip_format_hex(buf, len, prefix, str); free(buf); return rc; } /** * Decode a binary big integer in two's complement form into an OpenSSL BIGNUM. */ int kmip_decode_bignum(const unsigned char *data, uint32_t length, BIGNUM **bn) { unsigned char *tmp = (unsigned char *)data; int i, neg = 0, rc = 0; if (data == NULL || bn == NULL) return -EINVAL; if (data[0] & 0x80) { neg = 1; tmp = calloc(1, length); if (tmp == NULL) return -ENOMEM; for (i = 0; i < (int)length; i++) tmp[i] = ~data[i]; for (i = length - 1; i >= 0; i--) { tmp[i]++; if (tmp[i] != 0x00) break; } } *bn = BN_bin2bn(tmp, length, NULL); if (*bn == NULL) { rc = -EIO; goto out; } BN_set_negative(*bn, neg); out: if (neg) free(tmp); return rc; } /** * Returns the length required by a binary big integer in two's complement form */ uint32_t kmip_encode_bignum_length(const BIGNUM *bn) { uint32_t length; if (bn == NULL) return 0; length = BN_num_bytes(bn); if (BN_is_negative(bn) && BN_is_bit_set(bn, (length * 8) - 1)) length += 1; return length; } /** * Encode an OpenSSL BIGNUM to a binary big integer in two's complement form, * in the desired length. */ int kmip_encode_bignum(const BIGNUM *bn, unsigned char *data, uint32_t length) { int i; if (bn == NULL || data == NULL) return -EINVAL; if (BN_bn2binpad(bn, data, length) != (int)length) return -EIO; if (BN_is_negative(bn)) { for (i = 0; i < (int)length; i++) data[i] = ~data[i]; for (i = length - 1; i >= 0; i--) { data[i]++; if (data[i] != 0x00) break; } } return 0; } /** * Parse a timestamp in ISO8601 format and return it as time_t value */ int kmip_parse_timestamp(const char *str, int64_t *val) { struct tm tm = { 0 }; char *p; int rc; rc = kmip_parse_hex_int(str, val); if (rc == 0) return 0; if (rc != -EBADMSG) return rc; p = strptime(str, KMIP_ISO8601_TIMESTAMP_TZ, &tm); if (p == NULL) p = strptime(str, KMIP_ISO8601_TIMESTAMP, &tm); if (p == NULL || *p != 0) return -EBADMSG; #if !defined(_AIX) /* Adjust according to the parsed time zone */ tm.tm_sec -= tm.tm_gmtoff; tm.tm_gmtoff = 0; tm.tm_isdst = 0; *val = (time_t)timegm(&tm); #endif return 0; } /** * Parses a mask specification of the specified tag and separator character */ int kmip_parse_mask(enum kmip_tag tag, const char *str, char separator, int64_t *val) { const struct kmip_enum *info; char *save_ptr, *s, *tok; char delimiter[2]; uint32_t enum_val; int rc = 0; info = kmip_enum_info_by_tag(tag); if (info == NULL) return kmip_parse_hex_int(str, val); *val = 0; s = strdup(str); if (s == NULL) return -ENOMEM; delimiter[0] = separator; delimiter[1] = 0; tok = strtok_r(s, delimiter, &save_ptr); while (tok != NULL) { rc = kmip_enum_value_by_name_or_hex(info, tok, &enum_val); if (rc != 0) break; *val |= enum_val; tok = strtok_r(NULL, delimiter, &save_ptr); } free(s); return rc; } static int kmip_append_string(char **str, int *str_len, char separator, const char *append) { int new_len; char *tmp; if (str == NULL || str_len == NULL) return -EINVAL; if (*str == NULL) *str_len = 0; new_len = *str_len; if (*str == NULL) new_len++; else if (separator != 0) new_len++; if (append != NULL) new_len += strlen(append); tmp = realloc(*str, new_len); if (tmp == NULL) return -ENOMEM; if (*str == NULL) memset(tmp, 0, new_len); else if (separator != 0) strncat(tmp, &separator, 1); if (append != NULL) strcat(tmp, append); *str = tmp; *str_len = new_len; return 0; } /** * Format a mask specification of the specified tag and separator character */ int kmip_format_mask(enum kmip_tag tag, int32_t value, char separator, char **str) { const struct kmip_enum *info; int rc = 0, i, s_len = 0; char *s = NULL, *tmp; info = kmip_enum_info_by_tag(tag); if (info == NULL || value == 0) return kmip_format_hex((const unsigned char *)&value, sizeof(value), true, str); /* Process all known mask bits */ for (i = 0; value != 0 && info[i].name != NULL; i++) { if (value & info[i].val) { rc = kmip_append_string(&s, &s_len, separator, info[i].name); if (rc != 0) goto out; value &= ~info[i].val; } } /* Any bits left in the value? */ if (value != 0) { rc = kmip_format_hex((const unsigned char *)&value, sizeof(value), true, &tmp); if (rc != 0) goto out; rc = kmip_append_string(&s, &s_len, separator, tmp); free(tmp); if (rc != 0) goto out; } *str = s; out: if (rc != 0) free(s); return rc; } void kmip_print_dump(const char *func, unsigned char *data, size_t size, unsigned int indent) { char outstr[200], hexstr[4]; size_t i; if (data == NULL) return; strcpy(outstr, ""); for (i = 0; i < size; i++) { sprintf(hexstr, "%02x ", data[i]); strcat(outstr, hexstr); if (i % 16 == 15) { kmip_print_debug(func, "%*s%s", indent, "", outstr); strcpy(outstr, ""); } } if (i % 16 != 0) kmip_print_debug(func, "%*s%s", indent, "", outstr); } static void kmip_print_bignum(const char *func, const BIGNUM *bn, unsigned int indent) { unsigned char *buf; uint32_t len; int rc; if (bn == NULL) return; len = kmip_encode_bignum_length(bn); buf = malloc(len); if (buf == NULL) return; rc = kmip_encode_bignum(bn, buf, len); if (rc != 0) { free(buf); return; } kmip_print_dump(func, buf, len, indent); free(buf); } static void kmip_node_dump_int(struct kmip_node *node, unsigned int indent) { enum kmip_tag tag, v1_attr_tag = 0; struct kmip_node *element; char outstr[200] = { 0 }; struct tm *tm; const char *s; char *tmp; time_t t; int rc; if (node == NULL) return; s = kmip_tag_name_by_tag(node->tag); kmip_print_debug("kmip_node_dump", "%*sTag: %s (0x%x)", indent, "", s ? s : "UNKNOWN", node->tag); s = kmip_type_name_by_type(node->type); kmip_print_debug("kmip_node_dump", "%*s Type: %s (0x%x)", indent, "", s ? s : "UNKNOWN", node->type); if (node->name != NULL) kmip_print_debug("kmip_node_dump", "%*s Name: %s", indent, "", node->name); /* * KMIP v1.x attribute values may be Enumerations or Integer Masks. * To correctly print them, we need to know the tag. This is contained * in a Attribute Name node, which is an element of our parent node. */ if (node->tag == KMIP_TAG_ATTRIBUTE_VALUE) v1_attr_tag = kmip_find_v1_attribute_name_tag(node->parent); tag = (v1_attr_tag != 0 ? v1_attr_tag : node->tag); switch (node->type) { case KMIP_TYPE_STRUCTURE: kmip_print_debug("kmip_node_dump", "%*s Elements (%u):", indent, "", kmip_node_get_structure_element_count(node)); element = node->structure_value; while (element != NULL) { kmip_node_dump_int(element, indent + 4); element = element->next; } break; case KMIP_TYPE_INTEGER: if (kmip_is_tag_mask(tag)) { rc = kmip_format_mask(tag, node->integer_value, '|', &tmp); if (rc == 0) { kmip_print_debug("kmip_node_dump", "%*s " "Value: %s (0x%x)", indent, "", tmp, node->integer_value); free(tmp); break; } } kmip_print_debug("kmip_node_dump", "%*s Value: %d (0x%x)", indent, "", node->integer_value, node->integer_value); break; case KMIP_TYPE_LONG_INTEGER: kmip_print_debug("kmip_node_dump", "%*s Value: %ld (0x%lx)", indent, "", node->long_value, node->long_value); break; case KMIP_TYPE_BIG_INTEGER: kmip_print_debug("kmip_node_dump", "%*s Value: (%u bytes)", indent, "", kmip_encode_bignum_length( node->big_integer_value)); kmip_print_bignum("kmip_node_dump", node->big_integer_value, indent + 4); break; case KMIP_TYPE_ENUMERATION: s = kmip_enum_name_by_tag_value(tag, node->enumeration_value); kmip_print_debug("kmip_node_dump", "%*s Value: %s (0x%x)", indent, "", s ? s : "UNKNOWN", node->enumeration_value); break; case KMIP_TYPE_BOOLEAN: kmip_print_debug("kmip_node_dump", "%*s Value: %s", indent, "", node->boolean_value ? "True" : "False"); break; case KMIP_TYPE_TEXT_STRING: kmip_print_debug("kmip_node_dump", "%*s Value: '%s' " "(%u characters)", indent, "", node->text_value, strlen(node->text_value)); break; case KMIP_TYPE_BYTE_STRING: kmip_print_debug("kmip_node_dump", "%*s Value: (%u bytes)", indent, "", node->length); kmip_print_dump("kmip_node_dump", node->bytes_value, node->length, indent + 4); break; case KMIP_TYPE_DATE_TIME: tm = gmtime((time_t *)&node->date_time_value); if (tm != NULL) strftime(outstr, sizeof(outstr), KMIP_ISO8601_TIMESTAMP_UTC, tm); else strcpy(outstr, "INVALID"); kmip_print_debug("kmip_node_dump", "%*s Value: %s (0x%lx)", indent, "", outstr, node->date_time_value); break; case KMIP_TYPE_INTERVAL: kmip_print_debug("kmip_node_dump", "%*s Value: %d (0x%x)", indent, "", node->interval_value, node->interval_value); break; case KMIP_TYPE_DATE_TIME_EXTENDED: t = (time_t)node->date_time_ext_value / 1000000; tm = gmtime(&t); if (tm != NULL) strftime(outstr, sizeof(outstr), KMIP_ISO8601_TIMESTAMP_UTC, tm); else strcpy(outstr, "INVALID"); kmip_print_debug("kmip_node_dump", "%*s Value: %s %lu (0x%lx)", indent, "", outstr, node->date_time_ext_value % 1000000, node->date_time_ext_value); break; default: break; } } /** * Dump a KMIP node * * @param node the node to free * @param debug if false, the function is a no-op */ void kmip_node_dump(struct kmip_node *node, bool debug) { if (node == NULL || !debug) return; kmip_node_dump_int(node, 0); } /** * Find a KMIP v1.x Attribute Name node in the elements of the specified parent * node, and return the tag value of the attribute name. * * @param parent the parent node of the attribute name and value * * @returns the tag value of the attribute name, or 0 if not found, or unknown * attribute name */ enum kmip_tag kmip_find_v1_attribute_name_tag(struct kmip_node *parent) { struct kmip_node *e; if (parent == NULL) return 0; if (parent->tag != KMIP_TAG_ATTRIBUTE) return 0; if (parent->type != KMIP_TYPE_STRUCTURE) return 0; e = parent->structure_value; while (e != NULL) { /* * A KMIP v2.x Vendor Attribute looks similar to a KMIP v1.x * Attribute, but has a Vendor Identification node. If we find * a Vendor Identification node, then it can't be a KMIP v1.x * Attribute. */ if (e->tag == KMIP_TAG_VENDOR_IDENTIFICATION && e->type == KMIP_TYPE_TEXT_STRING) return 0; if (e->tag == KMIP_TAG_ATTRIBUTE_NAME && e->type == KMIP_TYPE_TEXT_STRING) return kmip_attr_tag_by_v1_attr_name(e->text_value); e = e->next; } return 0; } opencryptoki-opencryptoki-451d99c/usr/sbin/p11kmip/kmipclient/utils.h000066400000000000000000000040371520105705100260260ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021-2024 * * 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 UTILS_H #define UTILS_H #include #include #include #include "kmip.h" #define KMIP_BIG_INTEGER_BLOCK_LENGTH 8 #define KMIP_ISO8601_TIMESTAMP_UTC "%FT%TZ" #define KMIP_ISO8601_TIMESTAMP_TZ "%FT%T%z" #define KMIP_ISO8601_TIMESTAMP "%FT%T" #define kmip_debug(debug, ...) \ do { \ if (debug) \ kmip_print_debug(__func__, __VA_ARGS__); \ } while (0) void kmip_print_debug(const char *func, const char *fmt, ...); void kmip_print_dump(const char *func, unsigned char *data, size_t size, unsigned int indent); int kmip_parse_decimal_int(const char *str, int64_t *val); int kmip_parse_decimal_uint(const char *str, uint64_t *val); int kmip_parse_hex_int(const char *str, int64_t *val); int kmip_parse_hex(const char *str, bool has_prefix, unsigned char **val, uint32_t *length); int kmip_format_hex(const unsigned char *val, uint32_t length, bool prefix, char **str); int kmip_parse_bignum(const char *str, bool has_prefix, BIGNUM **bn); int kmip_format_bignum(const BIGNUM *bn, bool prefix, char **str); int kmip_decode_bignum(const unsigned char *data, uint32_t length, BIGNUM **bn); uint32_t kmip_encode_bignum_length(const BIGNUM *bn); int kmip_encode_bignum(const BIGNUM *bn, unsigned char *data, uint32_t length); int kmip_parse_timestamp(const char *str, int64_t *val); int kmip_parse_mask(enum kmip_tag tag, const char *str, char separator, int64_t *val); int kmip_format_mask(enum kmip_tag tag, int32_t value, char separator, char **str); void kmip_node_dump(struct kmip_node *node, bool debug); enum kmip_tag kmip_find_v1_attribute_name_tag(struct kmip_node *parent); #endif opencryptoki-opencryptoki-451d99c/usr/sbin/p11kmip/kmipclient/xml.c000066400000000000000000000300541520105705100254570ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021-2024 * * 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 #ifdef HAVE_LIBCURL #ifdef HAVE_LIBXML2 #include "kmip.h" #include "names.h" #include "utils.h" #define KMIP_XML_TTLV "TTLV" #define KMIP_XML_TAG "tag" #define KMIP_XML_NAME "name" #define KMIP_XML_TYPE "type" #define KMIP_XML_VALUE "value" /** * Decode a KMIP node from the data in the XML node using the XML encoding. * * @param xml the XML node to decode * @param parent the parent node or NULL if no parent exists. * @param node On return: the decoded node.The newly allocated * node has a reference count of 1. * @param debug if true, debug messages are printed * * @returns 0 in case of success, or a negative errno value */ int kmip_decode_xml(const xmlNode *xml, struct kmip_node *parent, struct kmip_node **node, bool debug) { char *tag_attr = NULL, *name_attr = NULL, *type_attr = NULL; enum kmip_tag tag, v1_attr_tag = 0; char *tag_name, *value_attr = NULL; struct kmip_node *n = NULL, *e; uint64_t uint64; xmlNode *child; int64_t int64; int rc = 0, i; if (xml == NULL || node == NULL) return -EINVAL; if (xml->type != XML_ELEMENT_NODE) { kmip_debug(debug, "Invalid XML node type: %d", xml->type); return -EINVAL; } n = calloc(1, sizeof(struct kmip_node)); if (n == NULL) { kmip_debug(debug, "calloc failed"); return -ENOMEM; } n->ref_count = 1; if (strcmp((char *)xml->name, KMIP_XML_TTLV) == 0) { tag_attr = (char *)xmlGetProp(xml, (xmlChar *)KMIP_XML_TAG); if (tag_attr == NULL) { kmip_debug(debug, "Missing '%s' attribute in XML node", KMIP_XML_TAG); rc = -EBADMSG; goto out; } tag_name = tag_attr; } else { tag_name = (char *)xml->name; } n->tag = kmip_tag_by_name_or_hex(tag_name); if (n->tag == 0) { kmip_debug(debug, "Unknown 'tag' in XML object: '%s'", tag_name); rc = -EBADMSG; goto out; } name_attr = (char *)xmlGetProp(xml, (xmlChar *)KMIP_XML_NAME); if (name_attr != NULL) n->name = strdup(name_attr); type_attr = (char *)xmlGetProp(xml, (xmlChar *)KMIP_XML_TYPE); if (type_attr == NULL) { n->type = KMIP_TYPE_STRUCTURE; } else { n->type = kmip_type_by_name_or_hex(type_attr); if (n->type == 0) { kmip_debug(debug, "Unknown 'type' in XML object: '%s'", type_attr); rc = -EBADMSG; goto out; } } value_attr = (char *)xmlGetProp(xml, (xmlChar *)KMIP_XML_VALUE); if (n->type != KMIP_TYPE_STRUCTURE && value_attr == NULL) { kmip_debug(debug, "Missing '%s' attribute in XML node", KMIP_XML_VALUE); rc = -EBADMSG; goto out; } /* * KMIP v1.x attribute values may be Enumerations or Integer Masks. * To correctly decode them, we need to know the tag. This is contained * in a Attribute Name node, which is an element of our parent node. */ if (n->tag == KMIP_TAG_ATTRIBUTE_VALUE) v1_attr_tag = kmip_find_v1_attribute_name_tag(parent); tag = (v1_attr_tag != 0 ? v1_attr_tag : n->tag); kmip_debug(debug, "tag: 0x%x type: 0x%x", n->tag, n->type); switch (n->type) { case KMIP_TYPE_STRUCTURE: for (child = xml->children, i = 0; child != NULL; child = child->next, i++) { if (child->type != XML_ELEMENT_NODE) continue; rc = kmip_decode_xml(child, n, &e, debug); if (rc != 0) { kmip_debug(debug, "Failed to parse child " "element %d", i); goto out; } rc = kmip_node_add_structure_element(n, e); kmip_node_free(e); if (rc != 0) { kmip_debug(debug, "kmip_node_structure_add_element " "failed: rc: %d", rc); goto out; } } break; case KMIP_TYPE_INTEGER: case KMIP_TYPE_LONG_INTEGER: case KMIP_TYPE_DATE_TIME_EXTENDED: if (n->type == KMIP_TYPE_INTEGER && kmip_is_tag_mask(tag)) { rc = kmip_parse_mask(tag, value_attr, ' ', &int64); if (rc != 0) { kmip_debug(debug, "Failed to parse " "mask string '%s'", value_attr); goto out; } } else { rc = kmip_parse_decimal_int(value_attr, &int64); if (rc != 0) { kmip_debug(debug, "Failed to parse " "decimal string '%s'", value_attr); goto out; } } switch (n->type) { case KMIP_TYPE_INTEGER: n->integer_value = int64; break; case KMIP_TYPE_LONG_INTEGER: n->long_value = int64; break; case KMIP_TYPE_DATE_TIME_EXTENDED: n->date_time_ext_value = int64; break; default: break; } break; case KMIP_TYPE_INTERVAL: rc = kmip_parse_decimal_uint(value_attr, &uint64); if (rc != 0) { kmip_debug(debug, "Failed to parse " "decimal string '%s'", value_attr); goto out; } n->interval_value = uint64; break; case KMIP_TYPE_BIG_INTEGER: rc = kmip_parse_bignum(value_attr, false, &n->big_integer_value); if (rc != 0) { kmip_debug(debug, "Failed to parse bignum string '%s'", value_attr); goto out; } break; case KMIP_TYPE_ENUMERATION: rc = kmip_enum_value_by_tag_name_or_hex(tag, value_attr, &n->enumeration_value); if (rc != 0) { kmip_debug(debug, "Failed to parse enumeration '%s'", value_attr); goto out; } break; case KMIP_TYPE_BOOLEAN: n->boolean_value = (strcmp(value_attr, "true") == 0 || strcmp(value_attr, "1") == 0); break; case KMIP_TYPE_TEXT_STRING: n->text_value = strdup(value_attr); if (n->text_value == NULL) { rc = -ENOMEM; goto out; } n->length = strlen(n->text_value); break; case KMIP_TYPE_BYTE_STRING: rc = kmip_parse_hex(value_attr, false, &n->bytes_value, &n->length); if (rc != 0) { kmip_debug(debug, "Failed to parse hex string '%s'", value_attr); goto out; } break; case KMIP_TYPE_DATE_TIME: rc = kmip_parse_timestamp(value_attr, &n->date_time_value); if (rc != 0) { kmip_debug(debug, "Failed to parse time stamp '%s'", value_attr); goto out; } break; default: kmip_debug(debug, "unknown type: 0x%x", n->type); rc = -EBADMSG; goto out; } *node = n; rc = 0; out: if (rc != 0 && n != NULL) kmip_node_free(n); if (tag_attr != NULL) xmlFree(tag_attr); if (name_attr != NULL) xmlFree(name_attr); if (type_attr != NULL) xmlFree(type_attr); if (value_attr != NULL) xmlFree(value_attr); return rc; } /** * Encode a KMIP node into an XML node using the XML encoding. * * @param node the node to encode * @param xml On return: the XML node * @param debug if true, debug messages are printed * * @returns 0 in case of success, or a negative errno value */ int kmip_encode_xml(const struct kmip_node *node, xmlNode **xml, bool debug) { enum kmip_tag tag, v1_attr_tag = 0; xmlNode *ret_xml = NULL, *elem_xml; struct kmip_node *element; const char *tag_name; char tmp_str[50]; const char *str; struct tm *tm; xmlAttr *attr; char *tmp; int rc; if (node == NULL || xml == NULL) return -EINVAL; kmip_debug(debug, "tag: 0x%x type: 0x%x", node->tag, node->type); tag_name = kmip_tag_name_by_tag(node->tag); if (tag_name != NULL) ret_xml = xmlNewNode(NULL, (xmlChar *)tag_name); else ret_xml = xmlNewNode(NULL, (xmlChar *)KMIP_XML_TTLV); if (ret_xml == NULL) { kmip_debug(debug, "Failed to allocate a XML node"); return -ENOMEM; } if (tag_name == NULL) { sprintf(tmp_str, "0x%06x", node->tag); attr = xmlSetProp(ret_xml, (xmlChar *)KMIP_XML_TAG, (xmlChar *)tmp_str); if (attr == NULL) { kmip_debug(debug, "Failed to add '%s' attribute to XML node", KMIP_XML_TAG); rc = -ENOMEM; goto out; } if (node->name != NULL) { attr = xmlSetProp(ret_xml, (xmlChar *)KMIP_XML_NAME, (xmlChar *)node->name); if (attr == NULL) { kmip_debug(debug, "Failed to add '%s' " "attribute to XML node", KMIP_XML_NAME); rc = -ENOMEM; goto out; } } } if (node->type != KMIP_TYPE_STRUCTURE) { str = kmip_type_name_by_type(node->type); if (str == NULL) { kmip_debug(debug, "unknown type 0x%x", node->type); rc = -EINVAL; goto out; } attr = xmlSetProp(ret_xml, (xmlChar *)KMIP_XML_TYPE, (xmlChar *)str); if (attr == NULL) { kmip_debug(debug, "Failed to add '%s' attribute to XML node", KMIP_XML_TYPE); rc = -ENOMEM; goto out; } } /* * KMIP v1.x attribute values may be Enumerations or Integer Masks. * To correctly encode them, we need to know the tag. This is contained * in a Attribute Name node, which is an element of our parent node. */ if (node->tag == KMIP_TAG_ATTRIBUTE_VALUE) v1_attr_tag = kmip_find_v1_attribute_name_tag(node->parent); tag = (v1_attr_tag != 0 ? v1_attr_tag : node->tag); switch (node->type) { case KMIP_TYPE_STRUCTURE: element = node->structure_value; while (element != NULL) { rc = kmip_encode_xml(element, &elem_xml, debug); if (rc != 0) { kmip_debug(debug, "kmip_encode_xml failed"); goto out; } if (xmlAddChild(ret_xml, elem_xml) == NULL) { kmip_debug(debug, "xmlAddChild failed"); rc = -EIO; goto out; } element = element->next; } attr = NULL; break; case KMIP_TYPE_INTEGER: if (kmip_is_tag_mask(tag) && node->integer_value != 0) { rc = kmip_format_mask(tag, node->integer_value, ' ', &tmp); if (rc != 0) { kmip_debug(debug, "kmip_format_mask failed"); goto out; } attr = xmlSetProp(ret_xml, (xmlChar *)KMIP_XML_VALUE, (xmlChar *)tmp); free(tmp); } else { sprintf(tmp_str, "%d", node->integer_value); attr = xmlSetProp(ret_xml, (xmlChar *)KMIP_XML_VALUE, (xmlChar *)tmp_str); } break; case KMIP_TYPE_INTERVAL: sprintf(tmp_str, "%u", node->interval_value); attr = xmlSetProp(ret_xml, (xmlChar *)KMIP_XML_VALUE, (xmlChar *)tmp_str); break; case KMIP_TYPE_LONG_INTEGER: sprintf(tmp_str, "%ld", node->long_value); attr = xmlSetProp(ret_xml, (xmlChar *)KMIP_XML_VALUE, (xmlChar *)tmp_str); break; case KMIP_TYPE_BIG_INTEGER: rc = kmip_format_bignum(node->big_integer_value, false, &tmp); if (rc != 0) { kmip_debug(debug, "kmip_format_bignum failed"); goto out; } attr = xmlSetProp(ret_xml, (xmlChar *)KMIP_XML_VALUE, (xmlChar *)tmp); free(tmp); break; case KMIP_TYPE_ENUMERATION: str = kmip_enum_name_by_tag_value(tag, node->enumeration_value); if (str != NULL) { attr = xmlSetProp(ret_xml, (xmlChar *)KMIP_XML_VALUE, (xmlChar *)str); } else { sprintf(tmp_str, "0x%08x", node->enumeration_value); attr = xmlSetProp(ret_xml, (xmlChar *)KMIP_XML_VALUE, (xmlChar *)tmp_str); } break; case KMIP_TYPE_BOOLEAN: attr = xmlSetProp(ret_xml, (xmlChar *)KMIP_XML_VALUE, (xmlChar *)(node->boolean_value ? "true" : "false")); break; case KMIP_TYPE_TEXT_STRING: attr = xmlSetProp(ret_xml, (xmlChar *)KMIP_XML_VALUE, (xmlChar *)node->text_value); break; case KMIP_TYPE_BYTE_STRING: rc = kmip_format_hex(node->bytes_value, node->length, false, &tmp); if (rc != 0) { kmip_debug(debug, "kmip_format_hex_long failed"); goto out; } attr = xmlSetProp(ret_xml, (xmlChar *)KMIP_XML_VALUE, (xmlChar *)tmp); free(tmp); break; case KMIP_TYPE_DATE_TIME: tm = gmtime((time_t *)&node->date_time_value); strftime(tmp_str, sizeof(tmp_str), KMIP_ISO8601_TIMESTAMP_UTC, tm); attr = xmlSetProp(ret_xml, (xmlChar *)KMIP_XML_VALUE, (xmlChar *)tmp_str); break; case KMIP_TYPE_DATE_TIME_EXTENDED: sprintf(tmp_str, "%ld", node->date_time_ext_value); attr = xmlSetProp(ret_xml, (xmlChar *)KMIP_XML_VALUE, (xmlChar *)tmp_str); break; default: kmip_debug(debug, "unknown type: 0x%x", node->type); rc = -EINVAL; goto out; } if (attr == NULL && node->type != KMIP_TYPE_STRUCTURE) { kmip_debug(debug, "Failed to add '%s' " "attribute to XML node", KMIP_XML_VALUE); rc = -ENOMEM; goto out; } rc = 0; *xml = ret_xml; out: if (rc != 0) xmlFreeNode(ret_xml); return rc; } #endif #endif opencryptoki-opencryptoki-451d99c/usr/sbin/p11kmip/p11kmip.c000066400000000000000000004570301520105705100240110ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2001-2022 * * This program is provided under the terms of the Common Public License, * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this * 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 defined(_AIX) const char *__progname = "p11kmip"; #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "platform.h" #include "p11kmip.h" #include "p11util.h" #include "pin_prompt.h" #include "cfgparser.h" #include "configuration.h" #include "mechtable.h" #include "defs.h" #include "uri.h" #if OPENSSL_VERSION_PREREQ(3, 0) #include #include #include #include #include #endif /*****************************************************************************/ /* Global Variables */ /*****************************************************************************/ /* KMIP */ struct kmip_connection *kmip_conn = NULL; struct kmip_conn_config *kmip_conf = NULL; struct kmip_version kmip_vers; enum kmip_key_format_type kmip_wrap_key_format; enum kmip_crypto_algo kmip_wrap_key_alg; uint kmip_wrap_key_size; enum kmip_padding_method kmip_wrap_padding_method; enum kmip_hashing_algo kmip_wrap_hash_alg; /* Configuration */ static struct ConfigBaseNode *p11kmip_cfg = NULL; /* Environment variables */ static CK_SLOT_ID env_pkcs_slot = (CK_SLOT_ID)-1; static char *env_pkcs_pin = NULL; static char *env_kmip_hostname = NULL; static char *env_kmip_client_cert = NULL; static char *env_kmip_client_key = NULL; /* Options */ static bool opt_help = false; static bool opt_version = false; static bool opt_verbose = false; static bool opt_short = false; static bool opt_quiet = false; static CK_SLOT_ID opt_slot = (CK_SLOT_ID)-1; static char *opt_pin = NULL; static bool opt_force_pin_prompt = false; static char *opt_kmip_hostname = NULL; static char *opt_kmip_client_cert = NULL; static char *opt_kmip_client_key = NULL; static bool opt_tls_verify_hostname = false; static bool opt_tls_no_verify_cert = false; static bool opt_tls_trust_server = false; static char *opt_wrap_label = NULL; static char *opt_wrap_attrs = NULL; static char *opt_wrap_id = NULL; static char *opt_target_label = NULL; static char *opt_target_attrs = NULL; static char *opt_target_id = NULL; static CK_ULONG opt_target_length = (CK_ULONG)-1; static char *opt_unwrap_label = NULL; static bool opt_gen_targkey = false; static bool opt_retr_wrapkey = false; static bool opt_send_wrapkey = false; static char *opt_pem_password = NULL; static bool opt_force_pem_pwd_prompt = false; /*****************************************************************************/ /* Function Prototypes */ /*****************************************************************************/ /* Config */ /* KMIP Remote Function Prototypes */ static CK_RV p11kmip_locate_remote_key(const char *label, CK_OBJECT_CLASS class, CK_KEY_TYPE keytype, struct kmip_node **obj_uid); static CK_RV p11kmip_register_remote_public_key( const struct p11tool_objtype *keytype, CK_OBJECT_HANDLE wrapping_pubkey, const char *wrapping_key_label, struct kmip_node **key_uid); static CK_RV p11kmip_register_remote_wrapped_key( const struct p11tool_objtype *wrapped_keytype, CK_ULONG wrapped_key_length, const CK_BYTE *wrapped_key_blob, const char *wrapped_key_label, struct kmip_node *wrapkey_uid, struct kmip_node **key_uid); static CK_RV p11kmip_retrieve_remote_public_key( const struct p11tool_objtype *public_keytype, struct kmip_node *pubkey_uid, EVP_PKEY ** pub_key); static CK_RV p11kmip_retrieve_remote_wrapped_key( struct kmip_node *wrapping_key_uid, const struct p11tool_objtype *wrapped_keytype, CK_ULONG *wrapped_keysize, struct kmip_node *wrapped_key_uid, unsigned long *wrapped_key_length, CK_BYTE ** wrapped_key_blob); static CK_RV p11kmip_generate_remote_secret_key( const struct p11tool_objtype *keytype, CK_ULONG keysize, const char *secret_key_label, struct kmip_node **secret_key_uid); static CK_RV p11kmip_digest_remote_key(struct kmip_node *key_uid, enum kmip_hashing_algo *digest_alg, CK_BYTE * digest, u_int32_t * digest_len); /* PKCS#11 Local Function Prototypes*/ static CK_RV p11kmip_unwrap_local_secret_key( CK_OBJECT_HANDLE wrapping_key_handle, const struct p11tool_objtype *wrapped_keytype, unsigned long wrapped_key_length, CK_BYTE * wrapped_key_blob, char *wrapped_key_label, CK_ATTRIBUTE_PTR wrapped_key_attrs, CK_ULONG wrapped_key_num_attrs, CK_OBJECT_HANDLE_PTR unwrapped_key_handle); static CK_RV p11kmip_wrap_local_secret_key( CK_OBJECT_HANDLE wrapping_key_handle, CK_OBJECT_HANDLE secret_key_handle, CK_ULONG_PTR wrapped_key_length, CK_BYTE ** wrapped_key_blob); static CK_RV p11kmip_create_local_public_key( const struct p11tool_objtype *public_keytype, EVP_PKEY *pub_key, char *public_key_label, CK_ATTRIBUTE_PTR public_key_attrs, CK_ULONG public_key_num_attrs, CK_OBJECT_HANDLE_PTR public_key_handle); static CK_RV p11kmip_find_local_key(const struct p11tool_objtype *keytype, CK_OBJECT_CLASS class, const char *label, const char *id, CK_OBJECT_HANDLE *key); static CK_RV p11kmip_digest_local_key(CK_BYTE_PTR digest, CK_ULONG_PTR digestLen, CK_OBJECT_HANDLE key, CK_MECHANISM_PTR digestMech); /* P11 function prototypes */ static bool opt_slot_is_set(const struct p11tool_arg *arg); static bool opt_targkey_length_is_set(const struct p11tool_arg *arg); static CK_RV p11kmip_import_key(void); static CK_RV p11kmip_export_key(void); static CK_RV p11kmip_export_local_rsa_pkey( const struct p11tool_objtype *keytype, EVP_PKEY ** pkey, bool private, CK_OBJECT_HANDLE key, const char *label); /* KMIP function prototypes */ static int perform_kmip_request2(enum kmip_operation operation1, struct kmip_node *req_pl1, struct kmip_node **resp_pl1, enum kmip_result_status *status1, enum kmip_result_reason *reason1, enum kmip_operation operation2, struct kmip_node *req_pl2, struct kmip_node **resp_pl2, enum kmip_result_status *status2, enum kmip_result_reason *reason2, enum kmip_batch_error_cont_option batch_err_opt); static int perform_kmip_request(enum kmip_operation operation, struct kmip_node *req_pl, struct kmip_node **resp_pl, enum kmip_result_status *status, enum kmip_result_reason *reason); static int discover_kmip_versions(struct kmip_version *version); static struct kmip_node *build_custom_attr(const char *name, const char *value); static struct kmip_node *build_description_attr(const char *description); /*****************************************************************************/ /* Static Structure Declarations */ /*****************************************************************************/ /* Key object structure declarations */ static const struct p11tool_objtype p11kmip_aes_keytype = { .name = "AES", .type = CKK_AES, .ck_name = "CKK_AES", .keygen_mech = {.mechanism = CKM_AES_KEY_GEN,}, .is_asymmetric = false, .sign_verify = true, .encrypt_decrypt = true, .wrap_unwrap = true, .derive = true, .encaps_decaps = false, .filter_attr = CKA_KEY_TYPE, .filter_value = CKK_AES, .keysize_attr = CKA_VALUE_LEN, }; static const struct p11tool_objtype p11kmip_rsa_keytype = { .name = "RSA", .type = CKK_RSA, .ck_name = "CKK_RSA", .keygen_mech = {.mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN,}, .is_asymmetric = true, .sign_verify = true, .encrypt_decrypt = true, .wrap_unwrap = true, .derive = false, .encaps_decaps = false, .filter_attr = CKA_KEY_TYPE, .filter_value = CKK_RSA, .keysize_attr = CKA_MODULUS, .keysize_attr_value_len = true, .export_asym_pkey = p11kmip_export_local_rsa_pkey, }; /* Commandline interface structure declarations */ static const struct p11tool_opt p11kmip_generic_opts[] = { {.short_opt = 'h', .long_opt = "help", .required = false, .arg = {.type = ARG_TYPE_PLAIN, .required = false, .value.plain = &opt_help,}, .description = "Print this help, then exit."}, {.short_opt = 'v', .long_opt = "version", .required = false, .arg = {.type = ARG_TYPE_PLAIN, .required = false, .value.plain = &opt_version,}, .description = "Print version information, then exit."}, {.short_opt = 'd', .long_opt = "debug", .required = false, .arg = {.type = ARG_TYPE_PLAIN, .required = false, .value.plain = &opt_verbose,}, .description = "Increase debug information."}, {.short_opt = 'q', .long_opt = "quiet", .required = false, .arg = {.type = ARG_TYPE_PLAIN, .required = false, .value.plain = &opt_quiet,}, .description = "Suppress messages."}, {.short_opt = 'r', .long_opt = "short", .required = false, .arg = {.type = ARG_TYPE_PLAIN, .required = false, .value.plain = &opt_short,}, .description = "Print shortened results."}, {.short_opt = 0, .long_opt = NULL,}, }; #define PKCS11_OPTS \ { .short_opt = 's', .long_opt = "slot", .required = false, \ .arg = { .type = ARG_TYPE_NUMBER, .required = true, \ .value.number = &opt_slot, .is_set = opt_slot_is_set, \ .name = "SLOT", }, \ .description = "The PKCS#11 slot ID.", }, \ { .short_opt = 'p', .long_opt = "pin", .required = false, \ .arg = { .type = ARG_TYPE_STRING, .required = true, \ .value.string = &opt_pin, .name = "USER-PIN" }, \ .description = "The PKCS#11 user pin. If this option is not specified, " \ "and environment variable PKCS11_USER_PIN is not set, " \ "then you will be prompted for the PIN.", }, \ { .short_opt = 0, .long_opt = "force-pin-prompt", .required = false, \ .long_opt_val = OPT_FORCE_PIN_PROMPT, \ .arg = { .type = ARG_TYPE_PLAIN, .required = false, \ .value.plain = &opt_force_pin_prompt, }, \ .description = "Enforce user PIN prompt, even if environment variable " \ "PKCS11_USER_PIN is set, or the '-p'/'--pin' option is " \ "specified.", } #define KMIP_OPTS \ { .short_opt = 0, .long_opt = "kmip-host", .required = false, \ .long_opt_val = OPT_KMIP_HOSTNAME, \ .arg = { .type = ARG_TYPE_STRING, .required = true, \ .value.string = &opt_kmip_hostname, \ .name = "HOSTNAME" }, \ .description = "The hostname of the KMIP server to use (optional).", }, \ { .short_opt = 0, .long_opt = "kmip-client-cert", .required = false, \ .long_opt_val = OPT_KMIP_CLIENT_CERT, \ .arg = { .type = ARG_TYPE_STRING, .required = true, \ .value.string = &opt_kmip_client_cert, \ .name = "CERT-PATH" }, \ .description = "The path to the TLS client certificate to use for the " \ "KMIP connection (optional).", }, \ { .short_opt = 0, .long_opt = "kmip-client-key", .required = false, \ .long_opt_val = OPT_KMIP_CLIENT_KEY, \ .arg = { .type = ARG_TYPE_STRING, .required = true, \ .value.string = &opt_kmip_client_key, \ .name = "KEY-PATH" }, \ .description = "The path to the TLS client private key to use for the " \ "KMIP connection (optional).", }, \ { .short_opt = 0, .long_opt = "pem-password", .required = false, \ .long_opt_val = OPT_PEM_PASSWORD, \ .arg = { .type = ARG_TYPE_STRING, .required = true, \ .value.string = &opt_pem_password, \ .name = "PEM-PASSWORD" }, \ .description = "The password for the client key PEM file, if required" \ " (optional).", }, \ { .short_opt = 0, .long_opt = "force-pem-password-prompt", \ .required = false, .long_opt_val = OPT_FORCE_PEM_PWD_PROMPT, \ .arg = { .type = ARG_TYPE_PLAIN, .required = false, \ .value.plain = &opt_force_pem_pwd_prompt, }, \ .description = "Force a prompt for the client key PEM file" \ " (optional).", }, \ { .short_opt = 0, .long_opt = "tls-verify-hostname", \ .long_opt_val = OPT_TLS_VERIFY_HOSTNAME, \ .required = false, .arg = { .type = ARG_TYPE_PLAIN, .required = false, \ .value.plain = &opt_tls_verify_hostname, }, \ .description = "Enforce verification of the KMIP server hostname.", }, \ { .short_opt = 0, .long_opt = "tls-no-verify-server-cert", \ .long_opt_val = OPT_TLS_NO_VERIFY_CERT, \ .required = false, .arg = { .type = ARG_TYPE_PLAIN, .required = false, \ .value.plain = &opt_tls_no_verify_cert, }, \ .description = "Skip verification of KMIP server TLS certificate.", }, \ { .short_opt = 0, .long_opt = "tls-trust-server-cert", \ .long_opt_val = OPT_TLS_TRUST_CERT, \ .required = false, .arg = { .type = ARG_TYPE_PLAIN, .required = false, \ .value.plain = &opt_tls_trust_server, }, \ .description = "Perform verification of KMIP server TLS certificate, " \ "but do not prompt user for trust of this server.", } \ static const struct p11tool_arg p11kmip_import_key_args[] = { {.name = NULL}, }; static const struct p11tool_arg p11kmip_export_key_args[] = { {.name = NULL}, }; static const struct p11tool_opt p11kmip_import_key_opts[] = { PKCS11_OPTS, KMIP_OPTS, {.short_opt = 'w', .long_opt = "wrapkey-label", .required = true, .arg = {.type = ARG_TYPE_STRING, .required = true, .value.string = &opt_wrap_label, .name = "WRAPKEY-LABEL",}, .description = "The label of the key to be used for wrapping.",}, {.short_opt = 't', .long_opt = "targkey-label", .required = true, .arg = {.type = ARG_TYPE_STRING, .required = true, .value.string = &opt_target_label, .name = "TARGKEY-LABEL",}, .description = "The label of the target key to be imported from the " "KMIP server.",}, {.short_opt = 0, .long_opt = "targkey-attrs", .required = false, .long_opt_val = OPT_TARGKEY_ATTRS, .arg = {.type = ARG_TYPE_STRING, .required = true, .value.string = &opt_target_attrs, .name = "TARGKEY-ATTRS",}, .description = "The boolean attributes to set for the target key " "after it has been imported (optional):" " P M B Y S X K. " "Specify a set of these letters without any " "blanks in between. See below for the meaning " "of the attribute letters. Restrictions on " "attribute values may apply.",}, {.short_opt = 0, .long_opt = "targkey-id", .required = false, .long_opt_val = OPT_TARGKEY_ID, .arg = {.type = ARG_TYPE_STRING, .required = true, .value.string = &opt_target_id, .name = "TARGKEY-ID",}, .description = "The value to be set for the CKA_ID attribute of " "the imported target key (optional)",}, {.short_opt = 'u', .long_opt = "unwrapkey-label", .required = false, .arg = {.type = ARG_TYPE_STRING, .required = true, .value.string = &opt_unwrap_label, .name = "UNWRAPKEY-LABEL",}, .description = "The label of the private key in the PKCS#11 " "slot to be used for unwrapping the target key, " "if different from the label of the wrapping key used " "for wrapping (optional).",}, {.short_opt = 0, .long_opt = "send-wrapkey", .required = false, .long_opt_val = OPT_SEND_WRAPKEY, .arg = {.type = ARG_TYPE_PLAIN, .required = false, .value.plain = &opt_send_wrapkey,}, .description = "If specified, registers a wrapping key from the " "PKCS#11 slot with the KMIP server and uses it for wrapping. In " "this case, the label specified by the 'wrapkey-label' option is used to " "select the local wrapping key to be sent, and the wrapping key is " "registered with a name attribute value of the label on the " "KMIP server.",}, {.short_opt = 0, .long_opt = "gen-targkey", .required = false, .long_opt_val = OPT_GEN_TARGKEY, .arg = {.type = ARG_TYPE_PLAIN, .required = false, .value.plain = &opt_gen_targkey,}, .description = "If specified, the target key to be imported is " "first created on the KMIP server. Currently only" " supports AES keys.",}, { .short_opt = 0, .long_opt = "targkey-length", .required = false, .long_opt_val = OPT_TARGKEY_LEN, .arg = { .type = ARG_TYPE_NUMBER, .required = true, .value.number = &opt_target_length, .is_set = opt_targkey_length_is_set, .name = "LENGTH", }, .description = "The length in bits of the target key being generated. " "Must be one of 128, 192, or 256. Only valid" " with option 'gen-targkey'. Defaults to 256.",}, {.short_opt = 0, .long_opt = NULL,}, }; static const struct p11tool_opt p11kmip_export_key_opts[] = { PKCS11_OPTS, KMIP_OPTS, {.short_opt = 'w', .long_opt = "wrapkey-label", .required = true, .arg = {.type = ARG_TYPE_STRING, .required = true, .value.string = &opt_wrap_label, .name = "WRAPKEY-LABEL",}, .description = "The label of the wrapping key to be used for wrapping. " "Must exist on the KMIP server, and must exist " "in the PKCS#11 repository unless specified with " "option '--retr-wrapkey'.",}, {.short_opt = 't', .long_opt = "targkey-label", .required = true, .arg = {.type = ARG_TYPE_STRING, .required = true, .value.string = &opt_target_label, .name = "TARGKEY-LABEL",}, .description = "The label of the target key to be exported to the " "KMIP server. Must exist in the PKCS#11 repository. " "This label will be used as the name attribute of " "the exported key.",}, {.short_opt = 0, .long_opt = "retr-wrapkey", .required = false, .long_opt_val = OPT_RETR_WRAPKEY, .arg = {.type = ARG_TYPE_PLAIN, .required = false, .value.plain = &opt_retr_wrapkey,}, .description = "If specified, the wrapping key to be used for " "wrapping is first retrieved from the KMIP server and " "stored in the PKCS#11 repository. The new key is stored " "using the same label specified in the " "'wrapkey-label' option.",}, {.short_opt = 0, .long_opt = "wrapkey-attrs", .required = false, .long_opt_val = OPT_WRAPKEY_ATTRS, .arg = {.type = ARG_TYPE_STRING, .required = true, .value.string = &opt_wrap_attrs, .name = "WRAPKEY-ATTRS",}, .description = "The boolean attributes to set for the wrapping key " "after it has been imported (optional). Only compatible " " with the '--retr-wrapkey' option:" " P M B Y S X K H. " "Specify a set of these letters without any " "blanks in between. See below for the meaning " "of the attribute letters. Restrictions on " "attribute values may apply.",}, {.short_opt = 0, .long_opt = "wrapkey-id", .required = false, .long_opt_val = OPT_WRAPKEY_ID, .arg = {.type = ARG_TYPE_STRING, .required = true, .value.string = &opt_wrap_id, .name = "WRAPKEY-ID",}, .description = "The value to be set for the CKA_ID attribute of " "the imported wrapping key. Only compatible with the " "'--retr-wrapkey' option.",}, {.short_opt = 0, .long_opt = NULL,}, }; static const struct p11tool_cmd p11kmip_commands[] = { {.cmd = "import-key", .cmd_short1 = "import", .cmd_short2 = "imp", .func = p11kmip_import_key, .opts = p11kmip_import_key_opts, .args = p11kmip_import_key_args, .description = "Import a key from a KMIP server.", /*.help = print_generate_import_key_attr_help, */ .session_flags = CKF_SERIAL_SESSION | CKF_RW_SESSION,}, {.cmd = "export-key", .cmd_short1 = "export", .cmd_short2 = "exp", .func = p11kmip_export_key, .opts = p11kmip_export_key_opts, .args = p11kmip_export_key_args, .description = "Export a key into a KMIP server.", /*.help = print_generate_import_key_attr_help, */ .session_flags = CKF_SERIAL_SESSION | CKF_RW_SESSION,}, {.cmd = NULL, .func = NULL}, }; /* PKCS#11 attribute declarations */ static const struct p11tool_attr p11kmip_bool_attrs[] = { DECLARE_BOOL_ATTR(CKA_PRIVATE, 'P', true, true, true, true), DECLARE_BOOL_ATTR(CKA_MODIFIABLE, 'M', true, true, true, true), DECLARE_BOOL_ATTR(CKA_COPYABLE, 'B', true, true, true, true), DECLARE_BOOL_ATTR(CKA_DESTROYABLE, 'Y', true, true, true, true), DECLARE_BOOL_ATTR(CKA_SENSITIVE, 'S', true, false, true, true), DECLARE_BOOL_ATTR(CKA_EXTRACTABLE, 'X', true, false, true, true), DECLARE_BOOL_ATTR(CKA_TOKEN, 'H', true, true, true, false), DECLARE_BOOL_ATTR(CKA_IBM_PROTKEY_EXTRACTABLE, 'K', true, false, true, true), {.name = NULL,}, }; /* KMIP connection structure declarations */ static struct kmip_conn_config kmip_default_config = { /** Encoding used for the KMIP messages */ .encoding = KMIP_ENCODING_TTLV, /** Transport method used to deliver KMIP messages */ .transport = KMIP_TRANSPORT_PLAIN_TLS, /** * The KMIP server. * For Plain-TLS transport, only the hostname and optional port number. */ .server = "0.0.0.0:5696", /** The client key as an OpenSSL PKEY object. */ .tls_client_key = NULL, /** File name of the client certificate PEM file */ .tls_client_cert = NULL, /** * Optional: File name of the CA bundle PEM file, or a name of a * directory the multiple CA certificates. If this is NULL, then the * default system path for CA certificates is used */ .tls_ca = NULL, /** * Optional: File name of a PEM file holding a CA certificate of the * issuer */ .tls_issuer_cert = NULL, /** * Optional: File name of a PEM file containing the servers pinned * wrapping key. Wrapping key pinning requires that verify_peer or * verify_host (or both) is true. */ .tls_pinned_pubkey = NULL, /** * Optional: File name of a PEM file containing the server's * certificate. This can be used to allow peer verification with * self-signed server certificates */ .tls_server_cert = NULL, /** If true, the peer certificate is verified */ .tls_verify_peer = true, /** * If true, that the server certificate is for the server it is known * as (i.e. the hostname in the url) */ .tls_verify_host = false, /** * Optional: A list of ciphers for TLSv1.2 and below. This is a colon * separated list of cipher strings. The format of the string is * described in * https://www.openssl.org/docs/man1.1.1/man1/ciphers.html */ .tls_cipher_list = NULL, /** * Optional: A list of ciphers for TLSv1.3. This is a colon separated * list of TLSv1.3 ciphersuite names in order of preference. Valid * TLSv1.3 ciphersuite names are: * - TLS_AES_128_GCM_SHA256 * - TLS_AES_256_GCM_SHA384 * - TLS_CHACHA20_POLY1305_SHA256 * - TLS_AES_128_CCM_SHA256 * - TLS_AES_128_CCM_8_SHA256 */ .tls13_cipher_list = NULL }; /* KMIP request structure declarations */ /*****************************************************************************/ /* Functions */ /*****************************************************************************/ /* Utility functions */ static CK_KEY_TYPE get_p11_alg_from_kmip(enum kmip_crypto_algo kmip_alg) { if (kmip_alg >= P11KMIP_KMIP_TO_P11_ALG_TABLE_LENGTH) { return P11KMIP_P11_UNKNOWN_ALG; } return P11KMIP_KMIP_TO_P11_ALG_TABLE[kmip_alg]; } static enum kmip_crypto_algo get_kmip_alg_from_p11(CK_KEY_TYPE p11_alg) { if (p11_alg >= P11KMIP_P11_TO_KMIP_ALG_TABLE_LENGTH) { return P11KMIP_KMIP_UNKNOWN_ALG; } return P11KMIP_P11_TO_KMIP_ALG_TABLE[p11_alg]; } static CK_OBJECT_CLASS get_p11_obj_class_from_kmip( enum kmip_object_type kmip_obj) { if (kmip_obj >= P11KMIP_KMIP_TO_P11_OBJ_TABLE_LENGTH) { return P11KMIP_P11_UNKNOWN_OBJ; } return P11KMIP_KMIP_TO_P11_OBJ_TABLE[kmip_obj]; } static enum kmip_object_type get_kmip_obj_class_from_p11( CK_OBJECT_CLASS p11_obj) { if (p11_obj >= P11KMIP_P11_TO_KMIP_OBJ_TABLE_LENGTH) { return P11KMIP_KMIP_UNKNOWN_OBJ; } return P11KMIP_P11_TO_KMIP_OBJ_TABLE[p11_obj]; } static CK_MECHANISM_TYPE get_p11_hash_mech_from_kmip_hash_algo( enum kmip_hashing_algo kmip_hash_alg) { CK_MECHANISM_TYPE p11_hash_mech = P11KMIP_P11_UNKNOWN_HASH; if (kmip_hash_alg < P11KMIP_KMIP_TO_P11_HASH_TABLE_LENGTH) { p11_hash_mech = P11KMIP_KMIP_TO_P11_HASH_TABLE[kmip_hash_alg]; } return p11_hash_mech; } static enum kmip_crypto_usage_mask get_kmip_usage_mask_p11( const struct p11tool_objtype *keytype) { /* Gnarly bitwise chain to turn on the appropriate flags for key usage */ enum kmip_crypto_usage_mask usage_mask = 0; if (keytype->encrypt_decrypt) usage_mask |= (KMIP_CRY_USAGE_MASK_ENCRYPT | KMIP_CRY_USAGE_MASK_DECRYPT); if (keytype->sign_verify) usage_mask |= (KMIP_CRY_USAGE_MASK_SIGN | KMIP_CRY_USAGE_MASK_VERIFY); if (keytype->wrap_unwrap) usage_mask |= (KMIP_CRY_USAGE_MASK_WRAP_KEY | KMIP_CRY_USAGE_MASK_UNWRAP_KEY); if (keytype->derive) usage_mask |= KMIP_CRY_USAGE_MASK_DERIVE_KEY; return usage_mask; } static bool opt_slot_is_set(const struct p11tool_arg *arg) { return (*arg->value.number != (CK_ULONG)-1); } static bool opt_targkey_length_is_set(const struct p11tool_arg *arg) { return (*arg->value.number != (CK_ULONG)-1); } /*****************************************************************************/ /* Environment Variable Functions */ /*****************************************************************************/ static CK_RV parse_env_vars(void) { char *loc_env_pkcs_slot; loc_env_pkcs_slot = getenv(PKCS11_SLOT_ID_ENV_NAME); if (loc_env_pkcs_slot != NULL) { /* * * ATOI gives 0 on an invalid string, but 0 is a valid * slot ID, so no error checking to be done */ env_pkcs_slot = atoi(loc_env_pkcs_slot); } env_pkcs_pin = getenv(PKCS11_USER_PIN_ENV_NAME); env_kmip_hostname = getenv(KMIP_HOSTNAME_ENV_NAME); env_kmip_client_cert = getenv(KMIP_CLIENT_CERT_ENV_NAME); env_kmip_client_key = getenv(KMIP_CLIENT_KEY_ENV_NAME); return CKR_OK; } /*****************************************************************************/ /* Configuration File Functions */ /*****************************************************************************/ static void parse_config_file_error_hook(int line, int col, const char *msg) { warnx("Parse error: %d:%d: %s", line, col, msg); } static CK_RV parse_config_file(void) { FILE *fp = NULL; char *file_loc = getenv(P11KMIP_CONF_FILE_ENV_NAME); char pathname[PATH_MAX]; struct passwd *pw; if (file_loc != NULL) { fp = fopen(file_loc, "r"); if (fp == NULL) { warnx("Cannot read config file '%s' " "(specified via env variable %s): %s", file_loc, P11KMIP_CONF_FILE_ENV_NAME, strerror(errno)); return CKR_GENERAL_ERROR; } } else { pw = getpwuid(geteuid()); if (pw != NULL) { snprintf(pathname, sizeof(pathname), "%s/.%s", pw->pw_dir, P11KMIP_CONFIG_FILE_NAME); file_loc = pathname; fp = fopen(file_loc, "r"); } if (fp == NULL) { file_loc = P11KMIP_DEFAULT_CONFIG_FILE; fp = fopen(file_loc, "r"); if (fp == NULL) { warnx("Cannot read config file '%s': %s", file_loc, strerror(errno)); return CKR_GENERAL_ERROR; } } } if (parse_configlib_file(fp, &p11kmip_cfg, parse_config_file_error_hook, 0)) { warnx("Failed to parse config file '%s'", file_loc); fclose(fp); return CKR_DATA_INVALID; } fclose(fp); return CKR_OK; } /*****************************************************************************/ /* KMIP Connection Functions */ /*****************************************************************************/ #if OPENSSL_VERSION_PREREQ(3, 0) static int p11kmip_ui_read(UI *ui, UI_STRING *uis) { char pem_password[500]; int len, rc = 0; len = p11tool_pem_password_cb(pem_password, sizeof(pem_password), 0, UI_get0_user_data(ui)); if (len > 0) rc = (UI_set_result_ex(ui, uis, pem_password, len) == 0) ? 1 : 0; OPENSSL_cleanse(pem_password, sizeof(pem_password)); return rc; } #endif static CK_RV read_client_key(const char *tls_client_key_path, EVP_PKEY **pkey) { struct p11tool_pem_password_cb_data cb_data = { 0 }; #if OPENSSL_VERSION_PREREQ(3, 0) OSSL_STORE_CTX *sctx = NULL; OSSL_STORE_INFO *info = NULL; UI_METHOD *ui_method = NULL; CK_RV rc = CKR_OK; #else BIO *tls_client_key_bio = NULL; #endif cb_data.pem_file_name = tls_client_key_path; cb_data.pem_password = opt_pem_password; cb_data.env_var_name = KMIP_PEM_PASSWORD_ENV_NAME; cb_data.force_prompt = opt_force_pem_pwd_prompt; #if OPENSSL_VERSION_PREREQ(3, 0) ui_method = UI_create_method("p11kmip-ui-method"); if (ui_method == NULL || UI_method_set_reader(ui_method, p11kmip_ui_read) != 0) { warnx("Failed to setup a UI-Method"); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } sctx = OSSL_STORE_open(tls_client_key_path, ui_method, &cb_data, NULL, NULL); if (sctx == NULL) { warnx("Unable to open the store for '%s' for TLS client key", tls_client_key_path); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } while (!OSSL_STORE_eof(sctx)) { info = OSSL_STORE_load(sctx); if (info == NULL) break; if (OSSL_STORE_INFO_get_type(info) == OSSL_STORE_INFO_PKEY) break; OSSL_STORE_INFO_free(info); info = NULL; } if (info == NULL) { warnx("No key found for '%s'", tls_client_key_path); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } *pkey = OSSL_STORE_INFO_get1_PKEY(info); done: if (ui_method != NULL) UI_destroy_method(ui_method); if (info != NULL) OSSL_STORE_INFO_free(info); if (sctx != NULL) OSSL_STORE_close(sctx); return rc; #else tls_client_key_bio = BIO_new_file(tls_client_key_path, "r"); if (tls_client_key_bio == NULL) { warnx("Unable to open '%s' for TLS client key", tls_client_key_path); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); return CKR_FUNCTION_FAILED; } *pkey = PEM_read_bio_PrivateKey(tls_client_key_bio, NULL, p11tool_pem_password_cb, &cb_data); BIO_free(tls_client_key_bio); if (*pkey == NULL) { ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); return CKR_FUNCTION_FAILED; } return CKR_OK; #endif } /** * @brief Uses the contents of the config file and the * commandline arguments to construct the configuration * for the KMIP connection. For optional fields it will * use default values if none are found; for required fields * it will throw an error if they are missing. * * global p11kmip_cfg (input) * global kmip_conf (output) * global kmip_wrap_key_format (output) * global kmip_wrap_key_alg (output) * global kmip_wrap_key_size (output) * global kmip_padding_method (output) * global kmip_hashing_algo (output) * * @return CK_RV */ static CK_RV build_kmip_config(void) { CK_RV rc; int f; struct ConfigBaseNode *c = NULL, *host = NULL, *tls_client_cert = NULL, *tls_client_key = NULL, *wrap_key_format = NULL, *wrap_key_algorithm = NULL, *wrap_key_size = NULL, *wrap_pad_method = NULL, *wrap_hash_algo = NULL; struct ConfigStructNode *structnode = NULL; bool found = false; char *tls_client_key_path = NULL; rc = CKR_OK; /* Populate the kmip_config global with static defaults */ kmip_conf = &kmip_default_config; /** * The lack of a config file, by itself, is not fatal, * because all the required information can potentially * be provided through commandline arguments */ if (p11kmip_cfg != NULL) { /* Iterate the configuration node(s) */ confignode_foreach(c, p11kmip_cfg, f) { if (!confignode_hastype(c, CT_STRUCT) || strcmp(c->key, P11KMIP_CONFIG_KEYWORD_KMIP) != 0) { continue; } else if (found) { warnx("Syntax error in config file:" "'%s' specified multiple times", P11KMIP_CONFIG_KEYWORD_KMIP); rc = CKR_ARGUMENTS_BAD; goto done; } found = true; structnode = confignode_to_struct(c); host = confignode_find(structnode->value, P11KMIP_CONFIG_KEYWORD_HOST); tls_client_cert = confignode_find(structnode->value, P11KMIP_CONFIG_KEYWORD_CLIENT_CERT); tls_client_key = confignode_find(structnode->value, P11KMIP_CONFIG_KEYWORD_CLIENT_KEY); wrap_key_format = confignode_find(structnode->value, P11KMIP_CONFIG_KEYWORD_WRAP_KEY_FMT); wrap_key_algorithm = confignode_find(structnode->value, P11KMIP_CONFIG_KEYWORD_WRAP_KEY_ALG); wrap_key_size = confignode_find(structnode->value, P11KMIP_CONFIG_KEYWORD_WRAP_KEY_SIZE); wrap_pad_method = confignode_find(structnode->value, P11KMIP_CONFIG_KEYWORD_WRAP_PAD_MTHD); wrap_hash_algo = confignode_find(structnode->value, P11KMIP_CONFIG_KEYWORD_WRAP_HASH_ALG); /** * Ensure all the fields are the right type and were specified * with the right combinations */ if (host != NULL && !confignode_hastype(host, CT_STRINGVAL)) { warnx("Syntax error in config file: " "Missing '%s' in attribute at line %hu", P11KMIP_CONFIG_KEYWORD_HOST, c->line); rc = CKR_ARGUMENTS_BAD; goto done; } if (tls_client_cert != NULL && !confignode_hastype(tls_client_cert, CT_STRINGVAL)) { warnx("Syntax error in config file:" " Missing '%s' in attribute at line %hu", P11KMIP_CONFIG_KEYWORD_CLIENT_CERT, c->line); rc = CKR_ARGUMENTS_BAD; goto done; } if (tls_client_key != NULL && !confignode_hastype(tls_client_key, CT_STRINGVAL)) { warnx("Syntax error in config file:" " Missing '%s' in attribute at line %hu", P11KMIP_CONFIG_KEYWORD_CLIENT_KEY, c->line); rc = CKR_ARGUMENTS_BAD; goto done; } if (wrap_key_format != NULL && !confignode_hastype(wrap_key_format, CT_STRINGVAL)) { warnx("Syntax error in config file:" " Missing '%s' in attribute at line %hu", P11KMIP_CONFIG_KEYWORD_WRAP_KEY_FMT, c->line); rc = CKR_ARGUMENTS_BAD; goto done; } if (wrap_key_algorithm != NULL && !confignode_hastype(wrap_key_algorithm, CT_STRINGVAL)) { warnx("Syntax error in config file:" " Missing '%s' in attribute at line %hu", P11KMIP_CONFIG_KEYWORD_WRAP_KEY_ALG, c->line); rc = CKR_ARGUMENTS_BAD; goto done; } if (wrap_key_size != NULL && !confignode_hastype(wrap_key_size, CT_INTVAL)) { warnx("Syntax error in config file:" " Missing '%s' in attribute at line %hu", P11KMIP_CONFIG_KEYWORD_WRAP_KEY_SIZE, c->line); rc = CKR_ARGUMENTS_BAD; goto done; } if (wrap_pad_method != NULL && !confignode_hastype(wrap_pad_method, CT_STRINGVAL)) { warnx("Syntax error in config file:" " Missing '%s' in attribute at line %hu", P11KMIP_CONFIG_KEYWORD_WRAP_PAD_MTHD, c->line); rc = CKR_ARGUMENTS_BAD; goto done; } if (wrap_hash_algo != NULL && !confignode_hastype(wrap_hash_algo, CT_STRINGVAL)) { warnx("Syntax error in config file:" " Missing '%s' in attribute at line %hu", P11KMIP_CONFIG_KEYWORD_WRAP_HASH_ALG, c->line); rc = CKR_ARGUMENTS_BAD; goto done; } } if (host != NULL) { kmip_conf->server = confignode_to_stringval(host)->value; } if (tls_client_cert != NULL) { kmip_conf->tls_client_cert = confignode_to_stringval(tls_client_cert)->value; } if (tls_client_key != NULL) { tls_client_key_path = confignode_to_stringval(tls_client_key)->value; } if (wrap_key_format != NULL) { if (strcmp(confignode_to_stringval(wrap_key_format)->value, P11KMIP_CONFIG_VALUE_FMT_PKCS1) == 0) { kmip_wrap_key_format = KMIP_KEY_FORMAT_TYPE_PKCS_1; } else if (strcmp(confignode_to_stringval(wrap_key_format)->value, P11KMIP_CONFIG_VALUE_FMT_PKCS8) == 0) { kmip_wrap_key_format = KMIP_KEY_FORMAT_TYPE_PKCS_8; } else if (strcmp(confignode_to_stringval(wrap_key_format)->value, P11KMIP_CONFIG_VALUE_FMT_TRANSPARENT) == 0) { kmip_wrap_key_format = KMIP_KEY_FORMAT_TYPE_TRANSPARENT_RSA_PUBLIC_KEY; } else { warnx("Syntax error in config file:" " Invalid value '%s' specified for key word '%s's", confignode_to_stringval(wrap_key_format)->value, P11KMIP_CONFIG_KEYWORD_WRAP_KEY_FMT); rc = CKR_ARGUMENTS_BAD; goto done; } } else { warnx("Wrapping key format not found in config file"); rc = CKR_ARGUMENTS_BAD; goto done; } if (wrap_key_algorithm != NULL) { if (strcmp(confignode_to_stringval(wrap_key_algorithm)->value, P11KMIP_CONFIG_VALUE_KEY_ALG_RSA) == 0) { kmip_wrap_key_alg = KMIP_CRYPTO_ALGO_RSA; } else { warnx("Syntax error in config file:" " Invalid value '%s' specified for key word '%s's", confignode_to_stringval(wrap_key_algorithm)->value, P11KMIP_CONFIG_KEYWORD_WRAP_KEY_ALG); rc = CKR_ARGUMENTS_BAD; goto done; } } else { warnx("Wrapping key algorithm not found in config file"); rc = CKR_ARGUMENTS_BAD; goto done; } if (wrap_key_size != NULL) { kmip_wrap_key_size = confignode_to_intval(wrap_key_size)->value; } else { warnx("Wrapping key length not found in config file"); rc = CKR_ARGUMENTS_BAD; goto done; } if (wrap_pad_method != NULL) { if (strcmp(confignode_to_stringval(wrap_pad_method)->value, P11KMIP_CONFIG_VALUE_METHD_PKCS15) == 0) { kmip_wrap_padding_method = KMIP_PADDING_METHOD_PKCS_1_5; } else if (strcmp(confignode_to_stringval(wrap_pad_method)->value, P11KMIP_CONFIG_VALUE_METHD_OAEP) == 0) { kmip_wrap_padding_method = KMIP_PADDING_METHOD_OAEP; } else { warnx("Syntax error in config file:" " Invalid value '%s' specified for key word '%s's", confignode_to_stringval(wrap_pad_method)->value, P11KMIP_CONFIG_KEYWORD_WRAP_PAD_MTHD); rc = CKR_ARGUMENTS_BAD; goto done; } } else { warnx("Wrap padding method not found in config file"); rc = CKR_ARGUMENTS_BAD; goto done; } if (wrap_hash_algo != NULL) { if (strcmp(confignode_to_stringval(wrap_hash_algo)->value, P11KMIP_CONFIG_VALUE_HSH_ALG_SHA_1) == 0) { kmip_wrap_hash_alg = KMIP_HASHING_ALGO_SHA_1; } else if (strcmp(confignode_to_stringval(wrap_hash_algo)->value, P11KMIP_CONFIG_VALUE_HSH_ALG_SHA_256) == 0) { kmip_wrap_hash_alg = KMIP_HASHING_ALGO_SHA_256; } else { warnx("Syntax error in config file:" " Invalid value '%s' specified for key word '%s's", confignode_to_stringval(wrap_hash_algo)->value, P11KMIP_CONFIG_KEYWORD_WRAP_HASH_ALG); rc = CKR_ARGUMENTS_BAD; goto done; } } else { // Wrap hashing method is only required with padding method OAEP if (kmip_wrap_padding_method == KMIP_PADDING_METHOD_OAEP) { warnx("Wrap hashing algorithm not found in config file"); rc = CKR_ARGUMENTS_BAD; goto done; } } } /* Environment variables have priority over configuration file settings */ if (env_kmip_hostname != NULL) kmip_conf->server = env_kmip_hostname; if (env_kmip_client_cert != NULL) kmip_conf->tls_client_cert = env_kmip_client_cert; if (env_kmip_client_key != NULL) tls_client_key_path = env_kmip_client_key; /** * Command line options have priority over environment * variables and configuration options */ if (opt_kmip_hostname != NULL) kmip_conf->server = opt_kmip_hostname; if (opt_kmip_client_cert != NULL) kmip_conf->tls_client_cert = opt_kmip_client_cert; if (opt_kmip_client_key != NULL) tls_client_key_path = opt_kmip_client_key; if (opt_tls_no_verify_cert) kmip_conf->tls_verify_peer = false; if (opt_tls_verify_hostname) kmip_conf->tls_verify_host = true; /** * Now that we have the final path for the tls_client_key, * read in the contents */ rc = read_client_key(tls_client_key_path, &kmip_conf->tls_client_key); if (rc != CKR_OK) { warnx("Unable to extract TLS client key from '%s'", tls_client_key_path); goto done; } if (kmip_conf->tls_client_key == NULL || kmip_conf->tls_client_cert == NULL) { warnx("TLS client key or client certificate was not" " provided through configuration or command line options"); rc = CKR_FUNCTION_FAILED; goto done; } done: return rc; } static void free_kmip_config(void) { if (kmip_conf->tls_client_key != NULL) EVP_PKEY_free(kmip_conf->tls_client_key); } /** * Check if the certificate is a self signed certificate, and if it is expired * or not yet valid. * * @param cert_file the file name of the PEM file containing the cert * @param self_signed on return: true if the cert is a self signed cert * @param valid on return: false if the cert is expired or not yet * valid * * @returns 0 on success, a negative errno in case of an error. */ int p11kmip_check_certificate(const char *cert_file, bool *self_signed, bool *valid) { X509 *cert; FILE *fp; int rc; fp = fopen(cert_file, "r"); if (fp == NULL) { rc = CKR_GENERAL_ERROR; warnx("Failed to open certificate PEM file '%s': " "%s", cert_file, strerror(-rc)); return rc; } cert = PEM_read_X509(fp, NULL, NULL, NULL); fclose(fp); if (cert == NULL) { warnx("Failed to read certificate PEM file '%s'", cert_file); return -EIO; } *self_signed = (X509_NAME_cmp(X509_get_subject_name(cert), X509_get_issuer_name(cert)) == 0); #if OPENSSL_VERSION_PREREQ(4, 0) *valid = X509_check_certificate_times(NULL, cert, NULL); #else *valid = (X509_cmp_current_time(X509_get0_notBefore(cert)) < 0 && X509_cmp_current_time(X509_get0_notAfter(cert)) > 0); #endif X509_free(cert); return 0; } /** * Print the certificate(s) contained in the specified PEM file. * * @param cert_pem the file name of the PEM file to print * * @returns -EIO if the file could not be opened. -ENOENT if the PEM file * does not contain any certificates. 0 if success. */ int p11kmip_print_certificates(const char *cert_pem) { int rc = -ENOENT; X509 *cert; FILE *fp; if (cert_pem == NULL) return -EINVAL; fp = fopen(cert_pem, "r"); if (fp == NULL) { warnx("File '%s': %s", cert_pem, strerror(errno)); return -EIO; } while (1) { cert = PEM_read_X509(fp, NULL, NULL, NULL); if (cert == NULL) break; X509_print_ex_fp(stdout, cert, 0, X509_FLAG_NO_EXTENSIONS); X509_free(cert); rc = 0; } fclose(fp); return rc; } /** * @brief Builds the configuration for the KMIP connection, * opens the KMIP connection, and determines the version of * the server. * * global kmip_conf (output) * global kmip_conn (output) * global kmip_vers (output) * * @return CK_RV */ static CK_RV init_kmip(void) { int rc = 0; CK_RV rv = CKR_OK; bool verified = false, self_signed = false, valid = false; rc = build_kmip_config(); if (rc != CKR_OK) goto done; rc = kmip_connection_get_server_cert(kmip_conf->server, kmip_conf->transport, kmip_conf->tls_ca, kmip_conf->tls_client_key, kmip_conf->tls_client_cert, P11KMIP_SERVER_CERT_PATH, P11KMIP_SERVER_PKEY_PATH, NULL, &verified, opt_verbose); if (rc != 0) { warnx("Failed to retrieve KMIP server certificate"); rv = CKR_GENERAL_ERROR; goto done; } rc = p11kmip_check_certificate(P11KMIP_SERVER_CERT_PATH, &self_signed, &valid); if (rc != 0) { warnx("Failed to check KMIP server certificate '%s'", P11KMIP_SERVER_CERT_PATH); rv = CKR_GENERAL_ERROR; goto done; } if (!valid) printf("ATTENTION: The certificate is expired or not yet " "valid.\n"); if (self_signed) printf("ATTENTION: The certificate is self-signed " "and thus could not be verified.\n"); if (!verified) { if (!opt_tls_no_verify_cert) { warnx("The certificate could not be " "verified using the system's " "CA certificates. Use option " "'--tls-no-verify-server-cert' to " "connect to this server anyway."); rv = CKR_GENERAL_ERROR;; goto done; } } if (opt_tls_trust_server == false) { rc = p11kmip_print_certificates(P11KMIP_SERVER_CERT_PATH); if (rc != 0) { warnx("Failed to print KMIP server certificate '%s'", P11KMIP_SERVER_CERT_PATH); rv = CKR_GENERAL_ERROR; goto done; } printf("Is this the KMIP server you intend to connect to? [y/N] "); if (p11tool_prompt_user("Is this the KMIP server you intend to connect " "to? [y/N] ", "yn") != 'y') { warnx("Operation aborted by user"); rv = CKR_CANCEL; goto done; } } rc = kmip_connection_new(kmip_conf, &kmip_conn, opt_verbose); if (rc != 0) { warnx("Failed to initialize connection to KMIP server"); rv = CKR_GENERAL_ERROR; goto done; } rc = discover_kmip_versions(&kmip_vers); if (rc != 0) { warnx("DISCOVER-VERSION failed, retry " "with KMIP v1.2"); kmip_vers.major = 1; kmip_vers.minor = 2; kmip_set_default_protocol_version(&kmip_version_1_2); rc = discover_kmip_versions(&kmip_vers); if (rc != 0) { warnx("KMIP server version <1.2 not supported"); rv = CKR_GENERAL_ERROR; goto done; } } kmip_set_default_protocol_version(&kmip_vers); printf("KMIP server version: %d.%d\n", kmip_vers.major, kmip_vers.minor); done: return rv; } /** * @brief Closes and frees the KMIP connection and the * KMIP configuration structure */ static void term_kmip(void) { if (kmip_conn != NULL) kmip_connection_free(kmip_conn); if (kmip_conf != NULL) free_kmip_config(); } /*****************************************************************************/ /* KMIP Compatibility Functions */ /*****************************************************************************/ /** * Discovers the KMIP protocol versions that the KMIP server supports * * @param version On return : the highest KMIP version that the server * and the KMIP client supports * * @returns 0 on success, a negative errno in case of an error. */ static int discover_kmip_versions(struct kmip_version *version) { struct kmip_node *req_pl = NULL, *resp_pl = NULL; enum kmip_result_status discover_status = 0; enum kmip_result_reason discover_reason = 0; int rc = 0; req_pl = kmip_new_discover_versions_payload(-1, NULL); if (req_pl == NULL) { rc = CKR_HOST_MEMORY; warnx("Allocate KMIP node failed"); goto out; } rc = perform_kmip_request(KMIP_OPERATION_DISCOVER_VERSIONS, req_pl, &resp_pl, &discover_status, &discover_reason); if (rc) { warnx("Failed to request KMIP version from server"); goto out; } rc = kmip_get_discover_versions_response_payload(resp_pl, NULL, 0, version); if (rc != 0) { warnx("Failed to get discover version response"); rc = CKR_GENERAL_ERROR; goto out; } out: kmip_node_free(req_pl); kmip_node_free(resp_pl); return rc; } /** * Returns true if the KMIP server supports the 'Sensitive' attribute. * This is dependent on the profile settings, and the used KMIP protocol * version (>= v1.4). * * @param ph the plugin handle * * @return true or false */ static bool supports_sensitive_attr(void) { if (kmip_vers.major <= 1) return false; if (kmip_vers.major == 1 && kmip_vers.minor < 4) return false; return true; } /** * Returns the name of the enumeration value. * * @param values the list of enumeration values * @param value the value * * @returns a constant string */ static const char *_enum_value_to_str(const struct kmip_enum_name *values, uint32_t value) { unsigned int i; for (i = 0; values[i].name != NULL; i++) { if (values[i].value == value) return values[i].name; } return "UNKNOWN"; } /*****************************************************************************/ /* KMIP Request Functions */ /*****************************************************************************/ /** * Build Custom/Vendor attribute according to the Custom attribute style of the * profile. * * @param name the attribute name * @param value the attribute value * * @returns the attribute node or NULL in case of an error. */ static struct kmip_node *build_custom_attr(const char *name, const char *value) { struct kmip_node *attr = NULL, *text; char *v1_name = NULL; text = kmip_node_new_text_string(KMIP_TAG_ATTRIBUTE_VALUE, NULL, value); if(asprintf(&v1_name, "kmip-%s", name) <= 0) { warnx("asprintf failed"); goto out; } attr = kmip_new_vendor_attribute("x", v1_name, text); free(v1_name); out: kmip_node_free(text); return attr; } static struct kmip_node *build_description_attr(const char *description) { /** * So on the one hand, we don't support KMIP version <1.2 at all * but on the other hand, SKLM doesn't appear to support description * or comment attributes. Only making a custom description attribute * is valid */ return build_custom_attr("description", description); } /** * Check a KMIP response and extract information from it. * * @param resp the response KMIP node * @param batch_item the batch item index (staring at 0) * @param operation the operation (to verify the batch item) * @param payload On return : the payload of this batch item * * @returns 0 on success, a negative errno in case of an error. */ static int check_kmip_response(struct kmip_node *resp, int32_t batch_item, enum kmip_operation operation, struct kmip_node **payload, enum kmip_result_status *status, enum kmip_result_reason *reason) { struct kmip_node *resp_hdr = NULL, *resp_bi = NULL; const char *message = NULL; int32_t batch_count; int rc; rc = kmip_get_response(resp, &resp_hdr, 0, NULL); if (rc != 0) { warnx("Get KMIP response header failed"); goto out; } rc = kmip_get_response_header(resp_hdr, NULL, NULL, NULL, NULL, &batch_count); if (rc != 0) { warnx("Get KMIP response header infos failed"); goto out; } if (batch_item >= batch_count) { rc = -EBADMSG; warnx("Response contains less batch items than expected"); goto out; } rc = kmip_get_response(resp, NULL, batch_item, &resp_bi); if (rc != 0) { warnx("Get KMIP response batch item failed"); goto out; } rc = kmip_get_response_batch_item(resp_bi, NULL, NULL, NULL, status, reason, &message, NULL, NULL, payload); if (rc != 0) { warnx("Get KMIP response status infos failed"); goto out; } if (status[0] != KMIP_RESULT_STATUS_SUCCESS) { warnx("KMIP Request failed: Operation: '%s', " "Status: '%s', Reason: '%s', Message: '%s'", _enum_value_to_str(required_operations, operation), _enum_value_to_str(kmip_result_statuses, status[0]), _enum_value_to_str(kmip_result_reasons, reason[0]), message ? message : "(none)"); rc = -EBADMSG; goto out; } out: kmip_node_free(resp_hdr); kmip_node_free(resp_bi); return rc; } /** * Build a KMIP request with the up to 2 operations and payloads * * @param operation1 The 1st operation to perform * @param req_pl1 the request payload of the 1st operation * @param operation2 The 2nd operation to perform (or 0) * @param req_pl2 the request payload of the 2nd operation (or NULL) * @param req On return: the created request. * @param batch_err_opt Batch error option * * @returns 0 on success, a negative errno in case of an error. */ static int build_kmip_request2(enum kmip_operation operation1, struct kmip_node *req_pl1, enum kmip_operation operation2, struct kmip_node *req_pl2, struct kmip_node **req, enum kmip_batch_error_cont_option batch_err_opt) { struct kmip_node *req_bi1 = NULL, *req_bi2 = NULL, *req_hdr = NULL; int rc = 0; req_bi1 = kmip_new_request_batch_item(operation1, NULL, 0, req_pl1); if (req_bi1 == NULL) { rc = CKR_HOST_MEMORY; warnx("Allocate KMIP node failed"); goto out; } if (operation2 != 0) { req_bi2 = kmip_new_request_batch_item(operation2, NULL, 0, req_pl2); if (req_bi2 == NULL) { rc = CKR_HOST_MEMORY; warnx("Allocate KMIP node failed"); goto out; } } req_hdr = kmip_new_request_header(NULL, 0, NULL, NULL, false, NULL, batch_err_opt, true, operation2 != 0 ? 2 : 1); if (req_hdr == NULL) { rc = CKR_HOST_MEMORY; warnx("Allocate KMIP node failed"); goto out; } *req = kmip_new_request_va(req_hdr, 2, req_bi1, req_bi2); if (*req == NULL) { rc = CKR_HOST_MEMORY; warnx("Allocate KMIP node failed"); goto out; } out: kmip_node_free(req_bi1); kmip_node_free(req_bi2); kmip_node_free(req_hdr); return rc; } /** * Perform a KMIP request with up to 2 operations and payloads. * Returns the response payloads. * * @param operation1 The 1st operation to perform * @param req_pl1 the request payload if the 1st operation * @param resp_pl 1 On return: the response payload. * @param operation2 The 2nd operation to perform (or zero) * @param req_pl2 the request payload of the 2nd operation (or NULL) * @param resp_pl2 On return: the response payload. * @param batch_err_opt Batch error option * * @returns 0 on success, a negative errno in case of an error. */ static int perform_kmip_request2(enum kmip_operation operation1, struct kmip_node *req_pl1, struct kmip_node **resp_pl1, enum kmip_result_status *status1, enum kmip_result_reason *reason1, enum kmip_operation operation2, struct kmip_node *req_pl2, struct kmip_node **resp_pl2, enum kmip_result_status *status2, enum kmip_result_reason *reason2, enum kmip_batch_error_cont_option batch_err_opt) { struct kmip_node *req = NULL, *resp = NULL; int rc; rc = build_kmip_request2(operation1, req_pl1, operation2, req_pl2, &req, batch_err_opt); if (rc != 0) goto out; rc = kmip_connection_perform(kmip_conn, req, &resp, opt_verbose); if (rc != 0) { goto out; } rc = check_kmip_response(resp, 0, operation1, resp_pl1, status1, reason1); if (rc != 0 && batch_err_opt == KMIP_BATCH_ERR_CONT_CONTINUE && operation2 != 0) { rc = 0; } if (rc != 0) goto out; if (operation2 != 0) { rc = check_kmip_response(resp, 1, operation2, resp_pl2, status2, reason2); if (rc != 0) goto out; } out: kmip_node_free(req); kmip_node_free(resp); return rc; } /** * Perform a KMIP request with the specified operation and payload. Returns the * response payload. * * @param operation The operation to perform * @param req_pl the request payload * @param resp_pl On return: the response payload. * * @returns 0 on success, a negative errno in case of an error. */ static int perform_kmip_request(enum kmip_operation operation, struct kmip_node *req_pl, struct kmip_node **resp_pl, enum kmip_result_status *status, enum kmip_result_reason *reason) { return perform_kmip_request2(operation, req_pl, resp_pl, status, reason, 0, NULL, NULL, NULL, NULL, KMIP_BATCH_ERR_CONT_STOP); } /*****************************************************************************/ /* PKCS#11 Key Type Functions */ /*****************************************************************************/ static bool aes_is_attr_applicable(const struct p11tool_objtype *keytype, const struct p11tool_attr *attr) { UNUSED(keytype); if (attr->type == CKA_TOKEN) return false; return true; } /*****************************************************************************/ /* PKCS#11 Crypto Adapter Utility Functions */ /*****************************************************************************/ /* Commands */ /** * Registers a wrapping key with a KMIP server, retrieves a target key from * the KMIP server wrapped with that wrapping key, and then unwraps and imports * the target key locally * * global opt_wrap_label wrapping key label * global opt_send_wrapkey flag to register wrapping key * with KMIP server (optional) * global opt_unwrap_label unwrapping key label (optional) * global opt_target_label target key label * global opt_target_id CKA_ID for target key (optional) * global opt_target_attrs boolean attributes for target key (optional) * global opt_gen_targkey flag for KMIP server to generate * target key (optional) * * @return CK_RV */ static CK_RV p11kmip_import_key(void) { CK_RV rc; CK_OBJECT_HANDLE wrapping_pubkey, wrapping_privkey, unwrapped_key_handle; const struct p11tool_objtype *pubkey_keytype, *privkey_keytype; const struct p11tool_objtype *secret_keytype; struct kmip_node *wrap_pubkey_uid = NULL, *secret_key_uid = NULL; CK_BYTE *wrapped_key_blob = NULL; unsigned long wrapped_key_length = 0; CK_ATTRIBUTE *wrapped_key_attrs = NULL; CK_ULONG wrapped_key_num_attrs = 0, local_key_digest_len = 0; u_int32_t remote_key_digest_len = 0; CK_BYTE_PTR local_key_digest = NULL, remote_key_digest = NULL; enum kmip_hashing_algo digest_alg = 0; struct CK_MECHANISM digest_mech = { 0 }; CK_ULONG secret_keysize = P11KMIP_DEFAULT_AES_KEY_LENGTH; /** * Until we support algorithms beyond RSA and AES, using these hard-coded * key types are sufficient */ pubkey_keytype = &p11kmip_rsa_keytype; privkey_keytype = &p11kmip_rsa_keytype; secret_keytype = &p11kmip_aes_keytype; /* Validate and set target key length */ if (opt_target_length != (CK_ULONG)-1) { switch (opt_target_length) { case 128: case 192: case 256: break; default: warnx("Invalid length set for target key:" " %ld", opt_target_length); rc = CKR_GENERAL_ERROR; goto done; } secret_keysize = (opt_target_length / 8); } /* Parse the attrs and id options up front to fail fast */ if (opt_target_attrs != NULL) { rc = p11tool_parse_boolean_attrs(secret_keytype, p11kmip_bool_attrs, opt_target_attrs, &wrapped_key_attrs, &wrapped_key_num_attrs, false, false, aes_is_attr_applicable); if (rc != CKR_OK) { warnx("Failed to parse boolean attributes for target key"); goto done; } } if (opt_target_id != NULL) { rc = p11tool_parse_id(opt_target_id, &wrapped_key_attrs, &wrapped_key_num_attrs); if (rc != CKR_OK) { warnx("Failed to parse ID for target key"); goto done; } } rc = p11kmip_find_local_key(pubkey_keytype, CKO_PUBLIC_KEY, opt_wrap_label, NULL, &wrapping_pubkey); if (rc != CKR_OK) { warnx("Failed to wrapping key with label '%s'", opt_wrap_label); goto done; } if (opt_unwrap_label != NULL) { rc = p11kmip_find_local_key(privkey_keytype, CKO_PRIVATE_KEY, opt_unwrap_label, NULL, &wrapping_privkey); if (rc != CKR_OK) { warnx("Failed to find unwrapping key with label '%s'", opt_unwrap_label); goto done; } } else { rc = p11kmip_find_local_key(privkey_keytype, CKO_PRIVATE_KEY, opt_wrap_label, NULL, &wrapping_privkey); if (rc != CKR_OK) { warnx("Failed to find unwrapping key with label '%s'", opt_unwrap_label); goto done; } } /* If we were unable to locate the key on the server, */ if (wrap_pubkey_uid == NULL) { /* If we were told to send the wrapkey, send it */ if (opt_send_wrapkey) { /* Next we send the wrapping key to the server */ rc = p11kmip_register_remote_public_key(pubkey_keytype, wrapping_pubkey, opt_wrap_label, &wrap_pubkey_uid); if (rc != CKR_OK) { warnx("Failed to register wrapping key '%s' on server", opt_wrap_label); goto done; } } else { rc = p11kmip_locate_remote_key(opt_wrap_label, CKO_PUBLIC_KEY, pubkey_keytype->type, &wrap_pubkey_uid); if (rc != CKR_OK) { warnx("Error while locating wrapping key on KMIP server"); goto done; } } } if (opt_gen_targkey) { /* If we were told to generate a new key, do so */ rc = p11kmip_generate_remote_secret_key(secret_keytype, secret_keysize, opt_target_label, &secret_key_uid); if (rc != CKR_OK) { warnx("Error creating target key on KMIP server"); goto done; } } else { /* Else attempt to find the one we were given */ rc = p11kmip_locate_remote_key(opt_target_label, CKO_SECRET_KEY, secret_keytype->type, &secret_key_uid); if (rc != CKR_OK) { warnx("Error while locating target key on KMIP server"); goto done; } /* If we didn't find it, throw an error */ if (secret_key_uid == NULL) { warnx("Did not find target key '%s' on server", opt_target_label); rc = CKR_ARGUMENTS_BAD; goto done; } } rc = p11kmip_retrieve_remote_wrapped_key(wrap_pubkey_uid, secret_keytype, &secret_keysize, secret_key_uid, &wrapped_key_length, &wrapped_key_blob); if (wrapped_key_blob == NULL) { warnx("Failed to retrieve wrapped key"); rc = CKR_ARGUMENTS_BAD; goto done; } /* Lastly we unwrap and import the retrieved key */ rc = p11kmip_unwrap_local_secret_key(wrapping_privkey, secret_keytype, wrapped_key_length, wrapped_key_blob, opt_target_label, wrapped_key_attrs, wrapped_key_num_attrs, &unwrapped_key_handle); if (rc != CKR_OK) { if (p11tool_is_rejected_by_policy(rc, p11tool_pkcs11_session)) { warnx("Unwrap and import key is rejected by policy"); goto done; } warnx("Failed to unwrap and import key"); goto done; } /* Display digests of the retrieved keys */ if (!opt_quiet) { remote_key_digest_len = 32; remote_key_digest = malloc(remote_key_digest_len); rc = p11kmip_digest_remote_key(secret_key_uid, &digest_alg, remote_key_digest, &remote_key_digest_len); if (rc != CKR_OK) { warnx("Obtaining digest of KMIP key failed"); goto done; } /* The same hashing algorithm should produce a digest of the same len */ local_key_digest_len = remote_key_digest_len; local_key_digest = malloc(local_key_digest_len); digest_mech.mechanism = get_p11_hash_mech_from_kmip_hash_algo(digest_alg); rc = p11kmip_digest_local_key(local_key_digest, &local_key_digest_len, unwrapped_key_handle, &digest_mech); if (rc != CKR_OK && rc != CKR_KEY_INDIGESTIBLE) { warnx("Obtaining digest of PKCS#11 key failed"); goto done; } if (opt_short) { printf("%s:", opt_target_label); if (rc == CKR_KEY_INDIGESTIBLE) { printf(""); rc = CKR_OK; } else { print_hex(local_key_digest, (int) local_key_digest_len); } printf("\n"); printf("%s:", kmip_node_get_text_string(secret_key_uid)); print_hex(remote_key_digest, (int) remote_key_digest_len); printf("\n"); } else { printf(" Target key\n"); printf(" PKCS#11 Label...%s\n", opt_target_label); printf(" PKCS#11 Digest.."); if (rc == CKR_KEY_INDIGESTIBLE) { printf(""); rc = CKR_OK; } else { print_hex(local_key_digest, (int) local_key_digest_len); } printf("\n"); printf(" KMIP UID........%s\n", kmip_node_get_text_string(secret_key_uid)); printf(" KMIP Digest....."); print_hex(remote_key_digest, (int) remote_key_digest_len); printf("\n"); printf(" Wrapping key\n"); printf(" PKCS#11 Label...%s\n", opt_wrap_label); printf(" KMIP UID........%s\n", kmip_node_get_text_string(wrap_pubkey_uid)); } } done: kmip_node_free(wrap_pubkey_uid); kmip_node_free(secret_key_uid); if (local_key_digest != NULL) free(local_key_digest); if (remote_key_digest != NULL) free(remote_key_digest); if (wrapped_key_blob != NULL) free(wrapped_key_blob); p11tool_free_attributes(wrapped_key_attrs, wrapped_key_num_attrs); return rc; } static CK_RV p11kmip_export_key(void) { CK_RV rc; CK_OBJECT_HANDLE wrapping_pubkey, secret_key_handle; const struct p11tool_objtype *pubkey_keytype, *secret_keytype; struct kmip_node *wrap_pubkey_uid = NULL, *secret_key_uid = NULL; CK_BYTE *wrapped_key_blob = NULL; unsigned long wrapped_key_length; EVP_PKEY *pub_key = NULL; CK_ATTRIBUTE *wrapping_key_attrs = NULL; CK_ULONG wrapping_key_num_attrs = 0, local_key_digest_len = 0; u_int32_t remote_key_digest_len = 0; CK_BYTE_PTR local_key_digest = NULL, remote_key_digest = NULL; enum kmip_hashing_algo digest_alg = 0; struct CK_MECHANISM digest_mech = { 0 }; /** * Until we support algorithms beyond RSA and AES, using these hard-coded * key types are sufficient */ pubkey_keytype = &p11kmip_rsa_keytype; secret_keytype = &p11kmip_aes_keytype; /* Parse the attrs and id options up front to fail fast */ if (opt_wrap_attrs != NULL) { rc = p11tool_parse_boolean_attrs(secret_keytype, p11kmip_bool_attrs, opt_wrap_attrs, &wrapping_key_attrs, &wrapping_key_num_attrs, false, false, NULL); if (rc != CKR_OK) { warnx("Failed to parse boolean attributes for wrapping key"); goto done; } } if (opt_wrap_id != NULL) { rc = p11tool_parse_id(opt_wrap_id, &wrapping_key_attrs, &wrapping_key_num_attrs); if (rc != CKR_OK) { warnx("Failed to parse ID for wrapping key"); goto done; } } /** * We must locate the KMIP wrapping key to obtain its UID, even if * we intend to utilize a local PKCS#11 wrapping key for the actual * wrapping. */ rc = p11kmip_locate_remote_key(opt_wrap_label, CKO_PUBLIC_KEY, pubkey_keytype->type, &wrap_pubkey_uid); if (rc != CKR_OK) { warnx("Error while locating wrapping key on KMIP server"); goto done; } /* If we didn't find it, throw an error */ if (wrap_pubkey_uid == NULL) { warnx("Did not find wrapping key '%s' on server", opt_wrap_label); rc = CKR_FUNCTION_FAILED; goto done; } if (opt_retr_wrapkey) { /** * If we were told to retrieve the wrapping key, * go through the process of importing the key * material into the PKCS#11 repository */ rc = p11kmip_retrieve_remote_public_key(pubkey_keytype, wrap_pubkey_uid, &pub_key); if (rc != CKR_OK) { warnx("Failed to retrieve wrapping key from KMIP server"); goto done; } rc = p11kmip_create_local_public_key(pubkey_keytype, pub_key, opt_wrap_label, wrapping_key_attrs, wrapping_key_num_attrs, &wrapping_pubkey); if (rc != CKR_OK) { if (p11tool_is_rejected_by_policy(rc, p11tool_pkcs11_session)) { warnx("Failed to create wrapping key '%s' due to policy", opt_wrap_label); goto done; } warnx("Failed to create wrapping key '%s'", opt_wrap_label); goto done; } } else { /** * Else we expect it to already exist in the repository with * the same label as the remote key */ rc = p11kmip_find_local_key(pubkey_keytype, CKO_PUBLIC_KEY, opt_wrap_label, opt_wrap_id, &wrapping_pubkey); if (rc != CKR_OK) { warnx("Failed to locate wrapping key '%s'", opt_wrap_label); goto done; } } rc = p11kmip_find_local_key(secret_keytype, CKO_SECRET_KEY, opt_target_label, opt_target_id, &secret_key_handle); if (rc != CKR_OK) { warnx("Failed to find local target key '%s'", opt_target_label); goto done; } rc = p11kmip_wrap_local_secret_key(wrapping_pubkey, secret_key_handle, &wrapped_key_length, &wrapped_key_blob); if (rc != CKR_OK) { if (p11tool_is_rejected_by_policy(rc, p11tool_pkcs11_session)) { warnx("Wrap local target key is rejected by policy"); goto done; } warnx("Failed to wrap local target key"); goto done; } rc = p11kmip_register_remote_wrapped_key(secret_keytype, wrapped_key_length, wrapped_key_blob, opt_target_label, wrap_pubkey_uid, &secret_key_uid); if (rc != CKR_OK) { warnx("Failed to register wrapped target key with server"); goto done; } /* Display digests of the retrieved keys */ if (!opt_quiet) { remote_key_digest_len = 32; remote_key_digest = malloc(remote_key_digest_len); rc = p11kmip_digest_remote_key(secret_key_uid, &digest_alg, remote_key_digest, &remote_key_digest_len); if (rc != CKR_OK) { warnx("Obtaining digest of KMIP key failed"); goto done; } /* The same hashing algorithm should produce a digest of the same len */ local_key_digest_len = remote_key_digest_len; local_key_digest = malloc(local_key_digest_len); digest_mech.mechanism = get_p11_hash_mech_from_kmip_hash_algo(digest_alg); rc = p11kmip_digest_local_key(local_key_digest, &local_key_digest_len, secret_key_handle, &digest_mech); if (rc != CKR_OK && rc != CKR_KEY_INDIGESTIBLE) { warnx("Obtaining digest of PKCS#11 key failed"); goto done; } if (opt_short) { printf("%s:", opt_target_label); if (rc == CKR_KEY_INDIGESTIBLE) { printf(""); rc = CKR_OK; } else { print_hex(local_key_digest, (int) local_key_digest_len); } printf("\n"); printf("%s:", kmip_node_get_text_string(secret_key_uid)); print_hex(remote_key_digest, (int) remote_key_digest_len); printf("\n"); } else { printf(" Target key\n"); printf(" PKCS#11 Label...%s\n", opt_target_label); printf(" PKCS#11 Digest.."); if (rc == CKR_KEY_INDIGESTIBLE) { printf(""); rc = CKR_OK; } else { print_hex(local_key_digest, (int) local_key_digest_len); } printf("\n"); printf(" KMIP UID........%s\n", kmip_node_get_text_string(secret_key_uid)); printf(" KMIP Digest....."); print_hex(remote_key_digest, (int) remote_key_digest_len); printf("\n"); printf(" Wrapping Key\n"); printf(" PKCS#11 Label...%s\n", opt_wrap_label); printf(" KMIP UID........%s\n", kmip_node_get_text_string(wrap_pubkey_uid)); } } done: kmip_node_free(wrap_pubkey_uid); kmip_node_free(secret_key_uid); if (wrapped_key_blob != NULL) free(wrapped_key_blob); if (local_key_digest != NULL) free(local_key_digest); if (remote_key_digest != NULL) free(remote_key_digest); if (pub_key != NULL) EVP_PKEY_free(pub_key); p11tool_free_attributes(wrapping_key_attrs, wrapping_key_num_attrs); return rc; } /***************************************************************************/ /* Functions for Manipulating Local PKCS#11 Adapter */ /***************************************************************************/ static CK_RV p11kmip_export_local_rsa_pkey( const struct p11tool_objtype *keytype, EVP_PKEY **pkey, bool private, CK_OBJECT_HANDLE key, const char *label) { BIGNUM *bn_n = NULL, *bn_e = NULL, *bn_d = NULL, *bn_iqmp = NULL; BIGNUM *bn_p = NULL, *bn_q = NULL, *bn_dmp1 = NULL, *bn_dmq1 = NULL; #if OPENSSL_VERSION_PREREQ(3, 0) EVP_PKEY_CTX *pctx = NULL; OSSL_PARAM_BLD *tmpl = NULL; OSSL_PARAM *params = NULL; #else RSA *rsa = NULL; #endif CK_RV rc; rc = p11tool_get_bignum_attr(key, CKA_MODULUS, &bn_n); if (rc == CKR_ATTRIBUTE_SENSITIVE) goto done; if (rc != CKR_OK) { warnx("Failed to retrieve attribute CKA_MODULUS from %s key " "object \"%s\": 0x%lX: %s", keytype->name, label, rc, p11_get_ckr(rc)); goto done; } rc = p11tool_get_bignum_attr(key, CKA_PUBLIC_EXPONENT, &bn_e); if (rc == CKR_ATTRIBUTE_SENSITIVE) goto done; if (rc != CKR_OK) { warnx("Failed to retrieve attribute CKA_PUBLIC_EXPONENT from %s key " "object \"%s\": 0x%lX: %s", keytype->name, label, rc, p11_get_ckr(rc)); goto done; } if (private) { rc = p11tool_get_bignum_attr(key, CKA_PRIVATE_EXPONENT, &bn_d); if (rc == CKR_ATTRIBUTE_SENSITIVE) goto done; rc = p11tool_get_bignum_attr(key, CKA_PRIME_1, &bn_p); if (rc == CKR_ATTRIBUTE_SENSITIVE) goto done; rc = p11tool_get_bignum_attr(key, CKA_PRIME_2, &bn_q); if (rc == CKR_ATTRIBUTE_SENSITIVE) goto done; rc = p11tool_get_bignum_attr(key, CKA_EXPONENT_1, &bn_dmp1); if (rc == CKR_ATTRIBUTE_SENSITIVE) goto done; rc = p11tool_get_bignum_attr(key, CKA_EXPONENT_2, &bn_dmq1); if (rc == CKR_ATTRIBUTE_SENSITIVE) goto done; rc = p11tool_get_bignum_attr(key, CKA_COEFFICIENT, &bn_iqmp); if (rc == CKR_ATTRIBUTE_SENSITIVE) goto done; } #if !OPENSSL_VERSION_PREREQ(3, 0) rsa = RSA_new(); if (rsa == NULL) { warnx("RSA_new failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } if (RSA_set0_key(rsa, bn_n, bn_e, bn_d) != 1) { warnx("RSA_set0_key failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } bn_n = bn_e = bn_d = NULL; if (private) { if (RSA_set0_factors(rsa, bn_p, bn_q) != 1) { warnx("RSA_set0_factors failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } bn_p = bn_q = NULL; if (RSA_set0_crt_params(rsa, bn_dmp1, bn_dmq1, bn_iqmp) != 1) { warnx("RSA_set0_crt_params failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } bn_dmp1 = bn_dmq1 = bn_iqmp = NULL; } *pkey = EVP_PKEY_new(); if (*pkey == NULL) { warnx("EVP_PKEY_new failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } if (EVP_PKEY_assign_RSA(*pkey, rsa) != 1) { warnx("EVP_PKEY_assign_RSA failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } rsa = NULL; #else tmpl = OSSL_PARAM_BLD_new(); if (tmpl == NULL) { warnx("OSSL_PARAM_BLD_new failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } if (!OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_RSA_N, bn_n) || !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_RSA_E, bn_e)) { warnx("OSSL_PARAM_BLD_push_BN failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } if (private) { if (!OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_RSA_D, bn_d) || !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_RSA_FACTOR1, bn_p) || !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_RSA_FACTOR2, bn_q) || !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_RSA_EXPONENT1, bn_dmp1) || !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_RSA_EXPONENT2, bn_dmq1) || !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_RSA_COEFFICIENT1, bn_iqmp)) { warnx("OSSL_PARAM_BLD_push_BN failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } } params = OSSL_PARAM_BLD_to_param(tmpl); if (params == NULL) { warnx("OSSL_PARAM_BLD_to_param failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL); if (pctx == NULL) { warnx("EVP_PKEY_CTX_new_id failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } if (!EVP_PKEY_fromdata_init(pctx) || !EVP_PKEY_fromdata(pctx, pkey, private ? EVP_PKEY_KEYPAIR : EVP_PKEY_PUBLIC_KEY, params)) { warnx("EVP_PKEY_fromdata_init/EVP_PKEY_fromdata failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } #endif done: if (bn_n != NULL) BN_free(bn_n); if (bn_e != NULL) BN_free(bn_e); if (bn_d != NULL) BN_free(bn_d); if (bn_p != NULL) BN_free(bn_p); if (bn_q != NULL) BN_free(bn_q); if (bn_dmp1 != NULL) BN_free(bn_dmp1); if (bn_dmq1 != NULL) BN_free(bn_dmq1); if (bn_iqmp != NULL) BN_free(bn_iqmp); #if !OPENSSL_VERSION_PREREQ(3, 0) if (rsa != NULL) RSA_free(rsa); #else if (pctx != NULL) EVP_PKEY_CTX_free(pctx); if (tmpl != NULL) OSSL_PARAM_BLD_free(tmpl); if (params != NULL) OSSL_PARAM_free(params); #endif if (rc != CKR_OK && *pkey != NULL) { EVP_PKEY_free(*pkey); *pkey = NULL; } return rc; } static CK_RV p11kmip_unwrap_local_secret_key( CK_OBJECT_HANDLE wrapping_key_handle, const struct p11tool_objtype *wrapped_keytype, unsigned long wrapped_key_length, CK_BYTE *wrapped_key_blob, char *wrapped_key_label, CK_ATTRIBUTE_PTR wrapped_key_attrs, CK_ULONG wrapped_key_num_attrs, CK_OBJECT_HANDLE_PTR unwrapped_key_handle) { CK_MECHANISM mech = { 0 }; CK_RSA_PKCS_OAEP_PARAMS oaep_param = { 0 }; CK_BBOOL ck_true = true; CK_RV rc; size_t i = 0; CK_OBJECT_CLASS key_class = wrapped_keytype->is_asymmetric ? CKO_PRIVATE_KEY : CKO_SECRET_KEY; CK_KEY_TYPE key_type = wrapped_keytype->type; CK_ATTRIBUTE_PTR unwrapped_template = NULL; CK_ULONG unwrapped_templatecount = 0; /* Build the template for the default attribute */ rc = p11tool_add_attribute(CKA_TOKEN, &ck_true, sizeof(ck_true), &unwrapped_template, &unwrapped_templatecount); rc += p11tool_add_attribute(CKA_SENSITIVE, &ck_true, sizeof(ck_true), &unwrapped_template, &unwrapped_templatecount); rc += p11tool_add_attribute(CKA_CLASS, &key_class, sizeof(key_class), &unwrapped_template, &unwrapped_templatecount); rc += p11tool_add_attribute(CKA_KEY_TYPE, &key_type, sizeof(key_type), &unwrapped_template, &unwrapped_templatecount); rc += p11tool_add_attribute(CKA_ENCRYPT, &ck_true, sizeof(ck_true), &unwrapped_template, &unwrapped_templatecount); rc += p11tool_add_attribute(CKA_DECRYPT, &ck_true, sizeof(ck_true), &unwrapped_template, &unwrapped_templatecount); rc += p11tool_add_attribute(CKA_SIGN, &ck_true, sizeof(ck_true), &unwrapped_template, &unwrapped_templatecount); rc += p11tool_add_attribute(CKA_VERIFY, &ck_true, sizeof(ck_true), &unwrapped_template, &unwrapped_templatecount); rc += p11tool_add_attribute(CKA_IBM_PROTKEY_EXTRACTABLE, &ck_true, sizeof(ck_true), &unwrapped_template, &unwrapped_templatecount); rc += p11tool_add_attribute(CKA_LABEL, wrapped_key_label, strlen((char *) wrapped_key_label), &unwrapped_template, &unwrapped_templatecount); if (rc != CKR_OK) goto done; /** * Copy in any additional attributes passed in by caller while overwriting * non-default values that were specified */ for (i = 0; i < wrapped_key_num_attrs; i++) { if (wrapped_key_attrs[i].type == CKA_TOKEN) { memcpy(wrapped_key_attrs[0].pValue, wrapped_key_attrs[i].pValue, wrapped_key_attrs[i].ulValueLen); } else if (wrapped_key_attrs[i].type == CKA_SENSITIVE) { memcpy(wrapped_key_attrs[1].pValue, wrapped_key_attrs[i].pValue, wrapped_key_attrs[i].ulValueLen); } else { rc = p11tool_add_attribute(wrapped_key_attrs[i].type, wrapped_key_attrs[i].pValue, wrapped_key_attrs[i].ulValueLen, &unwrapped_template, &unwrapped_templatecount); if (rc != CKR_OK) goto done; } } switch (kmip_wrap_padding_method) { case KMIP_PADDING_METHOD_PKCS_1_5: mech.mechanism = CKM_RSA_PKCS; break; case KMIP_PADDING_METHOD_OAEP: mech.mechanism = CKM_RSA_PKCS_OAEP; mech.pParameter = &oaep_param; mech.ulParameterLen = sizeof(oaep_param); switch (kmip_wrap_hash_alg) { case KMIP_HASHING_ALGO_SHA_1: oaep_param.hashAlg = CKM_SHA_1; oaep_param.mgf = CKG_MGF1_SHA1; break; case KMIP_HASHING_ALGO_SHA_256: oaep_param.hashAlg = CKM_SHA256; oaep_param.mgf = CKG_MGF1_SHA256; break; default: warnx("Unsupported hashing algorithm: %d", (int) kmip_wrap_hash_alg); return CKR_ARGUMENTS_BAD; } break; default: warnx("Unsupported padding method: %d", (int) kmip_wrap_padding_method); return CKR_ARGUMENTS_BAD; } rc = p11tool_pkcs11_funcs->C_UnwrapKey(p11tool_pkcs11_session, &mech, wrapping_key_handle, wrapped_key_blob, wrapped_key_length, unwrapped_template, unwrapped_templatecount, unwrapped_key_handle); done: p11tool_free_attributes(unwrapped_template, unwrapped_templatecount); return rc; } static CK_RV p11kmip_wrap_local_secret_key(CK_OBJECT_HANDLE wrapping_key_handle, CK_OBJECT_HANDLE secret_key_handle, CK_ULONG_PTR wrapped_key_length, CK_BYTE **wrapped_key_blob) { CK_MECHANISM mech = { 0 }; CK_RSA_PKCS_OAEP_PARAMS oaep_param = { 0 }; CK_RV rc; switch (kmip_wrap_padding_method) { case KMIP_PADDING_METHOD_PKCS_1_5: mech.mechanism = CKM_RSA_PKCS; break; case KMIP_PADDING_METHOD_OAEP: mech.mechanism = CKM_RSA_PKCS_OAEP; mech.pParameter = &oaep_param; mech.ulParameterLen = sizeof(oaep_param); switch (kmip_wrap_hash_alg) { case KMIP_HASHING_ALGO_SHA_1: oaep_param.hashAlg = CKM_SHA_1; oaep_param.mgf = CKG_MGF1_SHA1; break; case KMIP_HASHING_ALGO_SHA_256: oaep_param.hashAlg = CKM_SHA256; oaep_param.mgf = CKG_MGF1_SHA256; break; default: warnx("Unsupported hashing algorithm: %d", (int) kmip_wrap_hash_alg); return CKR_ARGUMENTS_BAD; } break; default: warnx("Unsupported padding method: %d", (int) kmip_wrap_padding_method); return CKR_ARGUMENTS_BAD; } /* wrap key (length only) */ rc = p11tool_pkcs11_funcs->C_WrapKey(p11tool_pkcs11_session, &mech, wrapping_key_handle, secret_key_handle, NULL, wrapped_key_length); if (rc != CKR_OK) { if (p11tool_is_rejected_by_policy(rc, p11tool_pkcs11_session)) { warnx("Unable to determine length of wrapped key object due to " "policy rejection"); return CKR_GENERAL_ERROR; } warnx("Unable to determine length of wrapped key object"); return CKR_GENERAL_ERROR; } *wrapped_key_blob = malloc(sizeof(CK_BYTE) * (*wrapped_key_length)); if (*wrapped_key_blob == NULL) { warnx("Unable to allocated storage for wrapped key blob"); return CKR_HOST_MEMORY; } /* Wrap key blob */ rc = p11tool_pkcs11_funcs->C_WrapKey(p11tool_pkcs11_session, &mech, wrapping_key_handle, secret_key_handle, *wrapped_key_blob, wrapped_key_length); return rc; } static CK_RV p11kmip_create_local_public_key( const struct p11tool_objtype *public_keytype, EVP_PKEY *pub_key, char *public_key_label, CK_ATTRIBUTE_PTR public_key_attrs, CK_ULONG public_key_num_attrs, CK_OBJECT_HANDLE_PTR public_key_handle) { CK_BBOOL ck_true = true; CK_RV rc; size_t i = 0; #if !OPENSSL_VERSION_PREREQ(3, 0) const RSA *rsa; const BIGNUM *bn_n = NULL, *bn_e = NULL; #else BIGNUM *bn_n = NULL, *bn_e = NULL; #endif CK_OBJECT_CLASS key_class = CKO_PUBLIC_KEY; CK_KEY_TYPE key_type = public_keytype->type; CK_ULONG public_templatecount = 0; CK_ATTRIBUTE_PTR public_template = NULL; #if !OPENSSL_VERSION_PREREQ(3, 0) rsa = EVP_PKEY_get0_RSA(pub_key); if (rsa == NULL) { warnx("Failed to get wrapping key params"); rc = CKR_FUNCTION_FAILED; goto done; } RSA_get0_key(rsa, &bn_n, &bn_e, NULL); if (bn_n == NULL || bn_e == NULL) { warnx("Failed to get wrapping key params"); rc = CKR_FUNCTION_FAILED; goto done; } #else if (!EVP_PKEY_get_bn_param(pub_key, OSSL_PKEY_PARAM_RSA_N, &bn_n) || !EVP_PKEY_get_bn_param(pub_key, OSSL_PKEY_PARAM_RSA_E, &bn_e)) { warnx("Failed to get wrapping key params"); rc = CKR_FUNCTION_FAILED; goto done; } #endif /* Add default attributes attributes */ rc = p11tool_add_attribute(CKA_TOKEN, &ck_true, sizeof(ck_true), &public_template, &public_templatecount); rc += p11tool_add_attribute(CKA_CLASS, &key_class, sizeof(key_class), &public_template, &public_templatecount); rc += p11tool_add_attribute(CKA_KEY_TYPE, &key_type, sizeof(key_type), &public_template, &public_templatecount); rc += p11tool_add_attribute(CKA_LABEL, public_key_label, strlen((char *) public_key_label), &public_template, &public_templatecount); if (rc != CKR_OK) goto done; /** * Copy in any additional attributes passed in by caller while overwriting * non-default values that were specified */ for (i = 0; i < public_key_num_attrs; i++) { /* Handle non-default value */ if (public_key_attrs[i].type == CKA_TOKEN) { memcpy(public_template[0].pValue, public_key_attrs[i].pValue, public_key_attrs[i].ulValueLen); } else { rc = p11tool_add_attribute(public_key_attrs[i].type, public_key_attrs[i].pValue, public_key_attrs[i].ulValueLen, &public_template, &public_templatecount); if (rc != CKR_OK) goto done; } } rc = p11tool_add_bignum_attr(CKA_MODULUS, bn_n, &public_template, &public_templatecount); if (rc != CKR_OK) goto done; rc = p11tool_add_bignum_attr(CKA_PUBLIC_EXPONENT, bn_e, &public_template, &public_templatecount); if (rc != CKR_OK) goto done; rc = p11tool_pkcs11_funcs->C_CreateObject(p11tool_pkcs11_session, public_template, public_templatecount, public_key_handle); done: p11tool_free_attributes(public_template, public_templatecount); #if OPENSSL_VERSION_PREREQ(3, 0) BN_free(bn_n); BN_free(bn_e); #endif return rc; } /** * Finds a key matching the label or id, or the class or filter attribute * of the key type, or any combination thereof. Expects to find exactly one * key matching these criteria, and returns it in the key parameter. * * @param keytype attributes and class of key * @param label label of key * @param id id of key * @param key handle return if key is found * global p11tool_pkcs11_funcs used to call PKCS11 functions * * @return CK_RV */ static CK_RV p11kmip_find_local_key( const struct p11tool_objtype *keytype, CK_OBJECT_CLASS class, const char *label, const char *id, CK_OBJECT_HANDLE *key) { CK_RV rc; CK_ATTRIBUTE *attrs = NULL; CK_ULONG num_attrs = 0; const CK_BBOOL ck_true = CK_TRUE; CK_OBJECT_HANDLE keys[FIND_OBJECTS_COUNT]; CK_ULONG num_keys; rc = p11tool_add_attribute(CKA_TOKEN, &ck_true, sizeof(ck_true), &attrs, &num_attrs); if (rc != CKR_OK) goto done; if (keytype != NULL) { /* Set the filter attribute, if applicable */ if (keytype->filter_attr != (CK_ATTRIBUTE_TYPE)-1) { rc = p11tool_add_attribute(keytype->filter_attr, &keytype->filter_value, sizeof(keytype->filter_value), &attrs, &num_attrs); if (rc != CKR_OK) goto done; } /* Set an attribute for the class to give us more granularity */ rc = p11tool_add_attribute(CKA_CLASS, &class, sizeof(class), &attrs, &num_attrs); if (rc != CKR_OK) goto done; } if (label != NULL) { rc = p11tool_add_attribute(CKA_LABEL, label, strlen((char *) label), &attrs, &num_attrs); if (rc != CKR_OK) goto done; } if (id != NULL) { rc = p11tool_parse_id((char *) id, &attrs, &num_attrs); if (rc != CKR_OK) return rc; } rc = p11tool_pkcs11_funcs->C_FindObjectsInit(p11tool_pkcs11_session, attrs, num_attrs); if (rc != CKR_OK) { warnx("Failed to initialize the find operation:" " C_FindObjectsInit: 0x%lX: %s", rc, p11_get_ckr(rc)); goto done; } memset(keys, 0, sizeof(keys)); num_keys = 0; rc = p11tool_pkcs11_funcs->C_FindObjects(p11tool_pkcs11_session, keys, FIND_OBJECTS_COUNT, &num_keys); if (rc != CKR_OK) { warnx("Failed to find objects: C_FindObjects: 0x%lX: %s", rc, p11_get_ckr(rc)); goto done; } rc = p11tool_pkcs11_funcs->C_FindObjectsFinal(p11tool_pkcs11_session); if (rc != CKR_OK) { warnx("Failed to finalize the find operation:" " C_FindObjectsFinal: 0x%lX: %s", rc, p11_get_ckr(rc)); goto done; } if (num_keys == 0) { rc = CKR_FUNCTION_FAILED; warnx("Failed to find key matching label '%s'", label); goto done; } else if (num_keys > 1) { rc = CKR_FUNCTION_FAILED; warnx("Found multiple keys matching label '%s'", label); goto done; } /* Write back the key handle */ *key = keys[0]; done: p11tool_free_attributes(attrs, num_attrs); return rc; } static CK_RV p11kmip_digest_local_key(CK_BYTE_PTR digest, CK_ULONG_PTR digestLen, CK_OBJECT_HANDLE key, CK_MECHANISM_PTR digestMech) { CK_RV rc; rc = p11tool_pkcs11_funcs->C_DigestInit(p11tool_pkcs11_session, digestMech); if (rc != CKR_OK) { if (p11tool_is_rejected_by_policy(rc, p11tool_pkcs11_session)) { warnx("Initialize PKCS#11 digest is rejected by policy"); return rc; } warnx("Failed to initialize PKCS#11 digest"); return rc; } rc = p11tool_pkcs11_funcs->C_DigestKey(p11tool_pkcs11_session, key); if (rc != CKR_OK) { if (p11tool_is_rejected_by_policy(rc, p11tool_pkcs11_session)) warnx("Digest PKCS#11 key is rejected by policy"); if (rc != CKR_KEY_INDIGESTIBLE) warnx("Failed to digest PKCS#11 key"); return rc; } rc = p11tool_pkcs11_funcs->C_DigestFinal(p11tool_pkcs11_session, digest, digestLen); if (p11tool_is_rejected_by_policy(rc, p11tool_pkcs11_session)) warnx("Digest PKCS#11 key is rejected by policy"); return rc; } /***************************************************************************/ /* Functions for Manipulating a Remote KMIP Server */ /***************************************************************************/ static CK_RV p11kmip_locate_remote_key(const char *label, CK_OBJECT_CLASS class, CK_KEY_TYPE keytype, struct kmip_node **obj_uid) { struct kmip_node *req_pl = NULL, *resp_pl = NULL, *item_uid = NULL, *last_uid = NULL; struct kmip_node **attrs = NULL; enum kmip_result_status locate_status = 0; enum kmip_result_reason locate_reason = 0; enum kmip_object_type obj_type = P11KMIP_KMIP_UNKNOWN_OBJ; enum kmip_crypto_algo key_alg = P11KMIP_KMIP_UNKNOWN_ALG; size_t num_attrs, num_objs; size_t i, k; CK_RV rc = CKR_OK; /* Label */ num_attrs = 1; /* Reconcile constants for PKCS#11 to KMIP */ obj_type = get_kmip_obj_class_from_p11(class); if (obj_type == P11KMIP_KMIP_UNKNOWN_OBJ) { warnx("Unknown object class"); rc = CKR_FUNCTION_NOT_SUPPORTED; goto out; } num_attrs++; key_alg = get_kmip_alg_from_p11(keytype); if (key_alg == P11KMIP_KMIP_UNKNOWN_ALG) { warnx("Unknown key algorithm"); rc = CKR_FUNCTION_NOT_SUPPORTED; goto out; } num_attrs++; attrs = calloc(num_attrs, sizeof(struct kmip_node *)); k = 0; /* Set the label */ attrs[k] = kmip_new_name((char *) label, KMIP_NAME_TYPE_UNINTERPRETED_TEXT_STRING); if (attrs[k] == NULL) { rc = CKR_HOST_MEMORY; warnx("Allocate KMIP node failed"); goto out; } k++; /* Set the object type */ attrs[k] = kmip_new_object_type(obj_type); if (attrs[k] == NULL) { rc = CKR_HOST_MEMORY; warnx("Allocate KMIP node failed"); goto out; } k++; /* Set the key algorithm */ attrs[k] = kmip_new_cryptographic_algorithm(key_alg); if (attrs[k] == NULL) { rc = CKR_HOST_MEMORY; warnx("Allocate KMIP node failed"); goto out; } k++; req_pl = kmip_new_locate_request_payload(NULL, 0, 0, 0, 0, num_attrs, attrs); if (req_pl == NULL) { rc = CKR_HOST_MEMORY; warnx("Allocate KMIP node failed"); goto out; } rc = perform_kmip_request(KMIP_OPERATION_LOCATE, req_pl, &resp_pl, &locate_status, &locate_reason); if (rc != 0) { rc = CKR_GENERAL_ERROR; goto out; } num_objs = 0; for (i = 0;; i++) { rc = kmip_get_locate_response_payload(resp_pl, NULL, NULL, i, &item_uid); if (rc != 0) break; num_objs++; last_uid = item_uid; } if (num_objs == 0) { rc = CKR_OK; } else if (num_objs == 1) { rc = CKR_OK; *obj_uid = last_uid; } else { rc = CKR_FUNCTION_FAILED; warnx("Unable to uniquely identify wrapping key on KMIP server"); } out: if (attrs != NULL) { for (i = 0; i < num_attrs; i++) kmip_node_free(attrs[i]); free(attrs); } kmip_node_free(req_pl); kmip_node_free(resp_pl); kmip_node_free(item_uid); return rc; } /** * @brief * * @param wrapping_pubkey * @param wrapkey_label * global kmip_connection * * @return CK_RV */ static CK_RV p11kmip_register_remote_public_key( const struct p11tool_objtype *keytype, CK_OBJECT_HANDLE wrapping_pubkey, const char *wrapping_key_label, struct kmip_node **key_uid) { EVP_PKEY *pkey = NULL; struct kmip_node *kobj = NULL, *name_attr = NULL, *unique_id = NULL; struct kmip_node *reg_req = NULL, *reg_resp = NULL, *descr_attr = NULL; struct kmip_node *key = NULL, *kval = NULL, *kblock = NULL; struct kmip_node *umask_attr = NULL, *cparams_attr = NULL; struct kmip_node *act_req = NULL, *act_resp = NULL; #if !OPENSSL_VERSION_PREREQ(3, 0) const BIGNUM *modulus = NULL, *pub_exp = NULL; #else BIGNUM *modulus = NULL, *pub_exp = NULL; #endif char *description = NULL; struct utsname utsname; enum kmip_result_status reg_status = 0, act_status = 0; enum kmip_result_reason reg_reason = 0, act_reason = 0; int rc; /* Export the wrapping key from PKCS#11 into an OpenSSL EVP Key */ if (keytype->export_asym_pkey != NULL) { rc = keytype->export_asym_pkey(keytype, &pkey, false, wrapping_pubkey, wrapping_key_label); if (rc != CKR_OK) { warnx("Failed to export '%s' to EVP key", wrapping_key_label); goto out; } } else { warnx("Function to export '%s' to EVP unavailable", wrapping_key_label); rc = CKR_FUNCTION_NOT_SUPPORTED; goto out; } switch (kmip_wrap_key_format) { case KMIP_KEY_FORMAT_TYPE_PKCS_1: key = kmip_new_pkcs1_public_key(pkey); break; case KMIP_KEY_FORMAT_TYPE_PKCS_8: key = kmip_new_pkcs8_public_key(pkey); break; case KMIP_KEY_FORMAT_TYPE_TRANSPARENT_RSA_PUBLIC_KEY: #if !OPENSSL_VERSION_PREREQ(3, 0) modulus = RSA_get0_n(EVP_PKEY_get0_RSA(pkey)); pub_exp = RSA_get0_e(EVP_PKEY_get0_RSA(pkey)); #else EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_N, &modulus); EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_E, &pub_exp); #endif if (modulus == NULL || pub_exp == NULL) { warnx("Failed to get RSA wrapping key parts"); rc = CKR_GENERAL_ERROR; goto out; } key = kmip_new_transparent_rsa_public_key(modulus, pub_exp); break; default: warnx("Unsupported wrapping key format: %d", kmip_wrap_key_format); rc = CKR_ARGUMENTS_BAD; goto out; } if (key == NULL) { warnx("Allocate KMIP node failed"); rc = CKR_HOST_MEMORY; goto out; } kval = kmip_new_key_value_va(NULL, key, 0); if (kval == NULL) { warnx("Allocate KMIP node failed"); rc = CKR_HOST_MEMORY; goto out; } kblock = kmip_new_key_block(kmip_wrap_key_format, 0, kval, kmip_wrap_key_alg, kmip_wrap_key_size, NULL); if (kblock == NULL) { warnx("Allocate KMIP node failed"); rc = CKR_HOST_MEMORY; goto out; } kobj = kmip_new_public_key(kblock); if (kobj == NULL) { warnx("Allocate KMIP node failed"); rc = CKR_HOST_MEMORY; goto out; } if (wrapping_key_label != NULL) { name_attr = kmip_new_name(wrapping_key_label, KMIP_NAME_TYPE_UNINTERPRETED_TEXT_STRING); if (name_attr == NULL) { warnx("Allocate KMIP node failed"); rc = CKR_HOST_MEMORY; goto out; } } umask_attr = kmip_new_cryptographic_usage_mask(KMIP_CRY_USAGE_MASK_ENCRYPT | KMIP_CRY_USAGE_MASK_WRAP_KEY); if (umask_attr == NULL) { warnx("Allocate KMIP node failed"); rc = CKR_HOST_MEMORY; goto out; } cparams_attr = kmip_new_cryptographic_parameters( NULL, 0, kmip_wrap_padding_method, kmip_wrap_padding_method == KMIP_PADDING_METHOD_OAEP ? kmip_wrap_hash_alg : 0, KMIP_KEY_ROLE_TYPE_KEK, 0, kmip_wrap_key_alg, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, kmip_wrap_padding_method == KMIP_PADDING_METHOD_OAEP ? KMIP_MASK_GENERATOR_MGF1 : 0, kmip_wrap_padding_method == KMIP_PADDING_METHOD_OAEP ? kmip_wrap_hash_alg : 0, NULL); if (cparams_attr == NULL) { warnx("Allocate KMIP node failed"); rc = CKR_HOST_MEMORY; goto out; } if (uname(&utsname) != 0) { rc = CKR_GENERAL_ERROR; warnx("Failed to obtain the system's " "hostname: %s", strerror(-rc)); goto out; } if (asprintf(&description, "Wrapping key for PKCS#11 client on system %s", utsname.nodename) <= 0) { rc = CKR_GENERAL_ERROR; warnx("asprintf failed"); goto out; }; descr_attr = build_description_attr(description); free(description); if (descr_attr == NULL) { warnx("Allocate KMIP node failed"); rc = CKR_HOST_MEMORY; goto out; } reg_req = kmip_new_register_request_payload_va(NULL, KMIP_OBJECT_TYPE_PUBLIC_KEY, kobj, NULL, 4, name_attr, umask_attr, cparams_attr, descr_attr); if (reg_req == NULL) { warnx("Allocate KMIP node failed"); rc = CKR_HOST_MEMORY; goto out; } act_req = kmip_new_activate_request_payload(NULL); /* ID placeholder */ if (act_req == NULL) { warnx("Allocate KMIP node failed"); rc = CKR_HOST_MEMORY; goto out; } rc = perform_kmip_request2(KMIP_OPERATION_REGISTER, reg_req, ®_resp, ®_status, ®_reason, KMIP_OPERATION_ACTIVATE, act_req, &act_resp, &act_status, &act_reason, KMIP_BATCH_ERR_CONT_STOP); if (rc != 0) { rc = CKR_GENERAL_ERROR; goto out; } rc = kmip_get_register_response_payload(reg_resp, &unique_id, NULL, 0, NULL); if (rc != 0) { warnx("Failed to get key unique-id"); goto out; } *key_uid = unique_id; out: kmip_node_free(key); kmip_node_free(kval); kmip_node_free(kblock); kmip_node_free(kobj); kmip_node_free(name_attr); kmip_node_free(umask_attr); kmip_node_free(cparams_attr); kmip_node_free(descr_attr); kmip_node_free(reg_req); kmip_node_free(reg_resp); kmip_node_free(act_req); kmip_node_free(act_resp); EVP_PKEY_free(pkey); #if OPENSSL_VERSION_PREREQ(3, 0) if (modulus != NULL) BN_free(modulus); if (pub_exp != NULL) BN_free(pub_exp); #endif return rc; } static CK_RV p11kmip_register_remote_wrapped_key( const struct p11tool_objtype *wrapped_keytype, CK_ULONG wrapped_key_length, const CK_BYTE *wrapped_key_blob, const char *wrapped_key_label, struct kmip_node *wrapkey_uid, struct kmip_node **key_uid) { struct kmip_node *kobj = NULL, *name_attr = NULL, *unique_id = NULL; struct kmip_node *reg_req = NULL, *reg_resp = NULL, *descr_attr = NULL; struct kmip_node *kval = NULL, *enc_cparams = NULL, *enc_kinfo = NULL, *kblock = NULL, *wrap_data = NULL; struct kmip_node *umask_attr = NULL, *cparams_attr = NULL; struct kmip_node *act_req = NULL, *act_resp = NULL; enum kmip_crypto_algo wrapped_key_algo; char *description = NULL; struct utsname utsname; enum kmip_result_status reg_status = 0, act_status = 0; enum kmip_result_reason reg_reason = 0, act_reason = 0; int rc; wrapped_key_algo = get_kmip_alg_from_p11(wrapped_keytype->type); enc_cparams = kmip_new_cryptographic_parameters( NULL, 0, kmip_wrap_padding_method, kmip_wrap_padding_method == KMIP_PADDING_METHOD_OAEP ? kmip_wrap_hash_alg : 0, 0, 0, kmip_wrap_key_alg, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, kmip_wrap_padding_method == KMIP_PADDING_METHOD_OAEP ? KMIP_MASK_GENERATOR_MGF1 : 0, kmip_wrap_padding_method == KMIP_PADDING_METHOD_OAEP ? kmip_wrap_hash_alg : 0, NULL); if (enc_cparams == NULL) { warnx("Allocate KMIP node failed"); rc = CKR_HOST_MEMORY; goto out; } enc_kinfo = kmip_new_key_info(false, wrapkey_uid, enc_cparams); if (enc_kinfo == NULL) { warnx("Allocate KMIP node failed"); rc = CKR_HOST_MEMORY; goto out; } wrap_data = kmip_new_key_wrapping_data(NULL, KMIP_WRAPPING_METHOD_ENCRYPT, enc_kinfo, NULL, NULL, 0, NULL, 0, KMIP_ENCODING_OPTION_NO); if (wrap_data == NULL) { warnx("Allocate KMIP node failed"); rc = CKR_HOST_MEMORY; goto out; } kval = kmip_node_new_byte_string(KMIP_TAG_KEY_VALUE, NULL, wrapped_key_blob, wrapped_key_length); if (kval == NULL) { warnx("Allocate KMIP node failed"); rc = CKR_HOST_MEMORY; goto out; } kblock = kmip_new_key_block(KMIP_KEY_FORMAT_TYPE_RAW, 0, kval, wrapped_key_algo, 0, wrap_data); if (kblock == NULL) { warnx("Allocate KMIP node failed"); rc = CKR_HOST_MEMORY; goto out; } kobj = kmip_new_symmetric_key(kblock); if (kobj == NULL) { warnx("Allocate KMIP node failed"); rc = CKR_HOST_MEMORY; goto out; } if (wrapped_key_label != NULL) { name_attr = kmip_new_name(wrapped_key_label, KMIP_NAME_TYPE_UNINTERPRETED_TEXT_STRING); if (name_attr == NULL) { warnx("Allocate KMIP node failed"); rc = CKR_HOST_MEMORY; goto out; } } umask_attr = kmip_new_cryptographic_usage_mask(KMIP_CRY_USAGE_MASK_ENCRYPT | KMIP_CRY_USAGE_MASK_DECRYPT); if (umask_attr == NULL) { warnx("Allocate KMIP node failed"); rc = CKR_HOST_MEMORY; goto out; } cparams_attr = kmip_new_cryptographic_parameters( NULL, 0, 0, 0, 0, 0, KMIP_CRYPTO_ALGO_AES, false, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, NULL); if (cparams_attr == NULL) { warnx("Allocate KMIP node failed"); rc = CKR_HOST_MEMORY; goto out; } if (uname(&utsname) != 0) { rc = CKR_GENERAL_ERROR; warnx("Failed to obtain the system's " "hostname: %s", strerror(-rc)); goto out; } if (asprintf(&description, "Target key for PKCS#11 client on system %s", utsname.nodename) <= 0) { rc = CKR_GENERAL_ERROR; warnx("asprintf failed"); goto out; } descr_attr = build_description_attr(description); free(description); if (descr_attr == NULL) { warnx("Allocate KMIP node failed"); rc = CKR_HOST_MEMORY; goto out; } reg_req = kmip_new_register_request_payload_va(NULL, KMIP_OBJECT_TYPE_SYMMETRIC_KEY, kobj, NULL, 3, name_attr, umask_attr, cparams_attr); if (reg_req == NULL) { warnx("Allocate KMIP node failed"); rc = CKR_HOST_MEMORY; goto out; } act_req = kmip_new_activate_request_payload(NULL); /* ID placeholder */ if (act_req == NULL) { warnx("Allocate KMIP node failed"); rc = CKR_HOST_MEMORY; goto out; } rc = perform_kmip_request2(KMIP_OPERATION_REGISTER, reg_req, ®_resp, ®_status, ®_reason, KMIP_OPERATION_ACTIVATE, act_req, &act_resp, &act_status, &act_reason, KMIP_BATCH_ERR_CONT_STOP); if (rc != 0) { rc = CKR_GENERAL_ERROR; goto out; } rc = kmip_get_register_response_payload(reg_resp, &unique_id, NULL, 0, NULL); if (rc != 0) { warnx("Failed to get key unique-id"); rc = CKR_GENERAL_ERROR; goto out; } *key_uid = unique_id; out: kmip_node_free(enc_cparams); kmip_node_free(enc_kinfo); kmip_node_free(wrap_data); kmip_node_free(kval); kmip_node_free(kblock); kmip_node_free(kobj); kmip_node_free(name_attr); kmip_node_free(umask_attr); kmip_node_free(cparams_attr); kmip_node_free(descr_attr); kmip_node_free(reg_req); kmip_node_free(reg_resp); kmip_node_free(act_req); kmip_node_free(act_resp); return rc; } /** * Sends a request to a KMIP server to retrieve a target key wrapped in a * wrapping key. Expects the wrapping key to already be available on the server. * * @param wrapped_key_label label of the target key * @param wrapping_key_label label of the wrapping key * @param wrapped_key_blob on output, a buffer containing the wrapped * key material of the target key * global kmip_connection structure for KMIP server connection * * @return CK_RV */ static CK_RV p11kmip_retrieve_remote_wrapped_key( struct kmip_node *wrapping_key_uid, const struct p11tool_objtype *wrapped_keytype, CK_ULONG *wrapped_keysize, struct kmip_node *wrapped_key_uid, unsigned long *wrapped_key_length, CK_BYTE **wrapped_key_blob) { struct kmip_node *cparams = NULL, *wrap_id = NULL, *wkey_info = NULL; struct kmip_node *wrap_spec = NULL, *req_pl = NULL, *resp_pl = NULL; struct kmip_node *uid = NULL, *kobj = NULL, *kblock = NULL; struct kmip_node *kval = NULL, *wrap = NULL, *key = NULL; struct kmip_node *wkinfo = NULL, *wcparms = NULL; enum kmip_hashing_algo halgo, mgfhalgo; enum kmip_wrapping_method wmethod; enum kmip_key_format_type ftype; enum kmip_padding_method pmeth; enum kmip_encoding_option enc; enum kmip_mask_generator mgf; enum kmip_object_type otype; enum kmip_crypto_algo algo; const unsigned char *kdata; uint32_t klen; int32_t bits; CK_OBJECT_CLASS wrapped_key_class; CK_KEY_TYPE wrapped_key_alg; enum kmip_result_status status = 0; enum kmip_result_reason reason = 0; int rc = 0; if (wrapped_keytype->is_asymmetric) { warnx("Unsupported object class"); rc = CKR_GENERAL_ERROR; goto out; } cparams = kmip_new_cryptographic_parameters( NULL, 0, kmip_wrap_padding_method, kmip_wrap_padding_method == KMIP_PADDING_METHOD_OAEP ? kmip_wrap_hash_alg : 0, KMIP_KEY_ROLE_TYPE_KEK, 0, kmip_wrap_key_alg, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, kmip_wrap_padding_method == KMIP_PADDING_METHOD_OAEP ? KMIP_MASK_GENERATOR_MGF1 : 0, kmip_wrap_padding_method == KMIP_PADDING_METHOD_OAEP ? kmip_wrap_hash_alg : 0, NULL); if (cparams == NULL) { warnx("Allocate KMIP node failed"); rc = CKR_HOST_MEMORY; goto out; } wkey_info = kmip_new_key_info(false, wrapping_key_uid, cparams); if (wkey_info == NULL) { warnx("Allocate KMIP node failed"); rc = CKR_HOST_MEMORY; goto out; } wrap_spec = kmip_new_key_wrapping_specification_va(NULL, KMIP_WRAPPING_METHOD_ENCRYPT, wkey_info, NULL, KMIP_ENCODING_OPTION_NO, 0); if (wrap_spec == NULL) { warnx("Allocate KMIP node failed"); rc = CKR_HOST_MEMORY; goto out; } req_pl = kmip_new_get_request_payload(NULL, wrapped_key_uid, KMIP_KEY_FORMAT_TYPE_RAW, 0, 0, wrap_spec); if (req_pl == NULL) { warnx("Allocate KMIP node failed"); rc = CKR_HOST_MEMORY; goto out; } rc = perform_kmip_request(KMIP_OPERATION_GET, req_pl, &resp_pl, &status, &reason); if (rc != 0) { rc = CKR_GENERAL_ERROR; goto out; } rc = kmip_get_get_response_payload(resp_pl, &otype, NULL, &kobj); if (rc != 0) { warnx("Failed to get wrapped key"); rc = CKR_GENERAL_ERROR; goto out; } wrapped_key_class = get_p11_obj_class_from_kmip(otype); if (wrapped_key_class != (wrapped_keytype->is_asymmetric ? CKO_PRIVATE_KEY : CKO_SECRET_KEY)) { warnx("Key is not the correct object class"); rc = CKR_GENERAL_ERROR; goto out; } rc = kmip_get_symmetric_key(kobj, &kblock); if (rc) { warnx("Failed to get symmetric key"); goto out; } rc = kmip_get_key_block(kblock, &ftype, NULL, &kval, &algo, &bits, &wrap); if (rc) { warnx("Failed to get key block"); goto out; } if (ftype != KMIP_KEY_FORMAT_TYPE_RAW) { warnx("Key format is not RAW"); rc = CKR_ARGUMENTS_BAD; goto out; } wrapped_key_alg = get_p11_alg_from_kmip(algo); if (wrapped_key_alg != wrapped_keytype->type) { warnx("Key algorithm is incorrect"); } rc = kmip_get_key_wrapping_data(wrap, &wmethod, &wkinfo, NULL, NULL, NULL, NULL, NULL, &enc); if (rc) { warnx("Failed to get wrapping data"); goto out; } if (wmethod != KMIP_WRAPPING_METHOD_ENCRYPT) { warnx("Wrapping method is not 'Encrypt'"); rc = CKR_ARGUMENTS_BAD; goto out; } if (enc != KMIP_ENCODING_OPTION_NO) { rc = CKR_ARGUMENTS_BAD; warnx("Encoding is not 'No encoding'"); goto out; } rc = kmip_get_key_info(wkinfo, NULL, &wcparms); if (rc) { warnx("Failed to get wrap key infos"); goto out; } rc = kmip_get_cryptographic_parameter(wcparms, NULL, &pmeth, &halgo, NULL, NULL, &algo, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &mgf, &mgfhalgo, NULL); if (rc != 0) { warnx("Failed to get crypto params"); goto out; } if (algo != kmip_wrap_key_alg) { rc = CKR_ARGUMENTS_BAD; warnx("wrap algorithm is not as expected"); goto out; } if (pmeth != kmip_wrap_padding_method) { rc = CKR_ARGUMENTS_BAD; warnx("padding method is not as expected"); goto out; } if (kmip_wrap_padding_method == KMIP_PADDING_METHOD_OAEP) { if (halgo != kmip_wrap_hash_alg) { rc = CKR_ARGUMENTS_BAD; warnx("hashing algorithm is not as expected"); goto out; } if (mgf != KMIP_MASK_GENERATOR_MGF1) { rc = CKR_ARGUMENTS_BAD; warnx("OAEP MGF is not as expected"); goto out; } if (mgfhalgo != kmip_wrap_hash_alg) { rc = CKR_ARGUMENTS_BAD; warnx("MGF hashing algorithm is not as expected"); goto out; } } rc = kmip_get_key_value(kval, &key, NULL, 0, NULL); if (rc) { warnx("Failed to get key value"); goto out; } kdata = kmip_node_get_byte_string(key, &klen); if (kdata == NULL) { rc = CKR_HOST_MEMORY; warnx("Failed to get key data"); goto out; } /** * 'bits' should contain the length of the unwrapped key * while the 'klen' contains the length of the wrapped blob */ *wrapped_keysize = (CK_ULONG)(bits / 8); *wrapped_key_blob = malloc(klen); *wrapped_key_length = klen; memcpy(*wrapped_key_blob, kdata, klen); out: kmip_node_free(cparams); kmip_node_free(wrap_id); kmip_node_free(wkey_info); kmip_node_free(wrap_spec); kmip_node_free(uid); kmip_node_free(req_pl); kmip_node_free(resp_pl); kmip_node_free(kobj); kmip_node_free(kblock); kmip_node_free(kval); kmip_node_free(wrap); kmip_node_free(wkinfo); kmip_node_free(wcparms); kmip_node_free(key); return rc; } /** * Sends a request to a KMIP server to retrieve a wrapping key of the given * key type and label * * @param keytype used to specify the algorithm of the wrapping key * @param public_key_label the label of the wrapping key on the remote server * @param pkey an EVP format wrapping key object which the retrieved * key is written into * * @return CK_RV */ static CK_RV p11kmip_retrieve_remote_public_key( const struct p11tool_objtype *public_keytype, struct kmip_node *pubkey_uid, EVP_PKEY **pub_key) { struct kmip_node *cparams = NULL, *wrap_id = NULL, *wkey_info = NULL; struct kmip_node *wrap_spec = NULL, *req_pl = NULL, *resp_pl = NULL; struct kmip_node *uid = NULL, *kobj = NULL, *kblock = NULL; struct kmip_node *kval = NULL, *wrap = NULL, *key = NULL; struct kmip_node *wkinfo = NULL, *wcparms = NULL; #if !OPENSSL_VERSION_PREREQ(3, 0) const BIGNUM **modulus_ptr = NULL, **pub_exp_ptr = NULL; BIGNUM *modulus = NULL, *pub_exp = NULL; RSA *rsa_key = NULL; #else const BIGNUM **modulus_ptr = NULL, **pub_exp_ptr = NULL; #endif enum kmip_key_format_type ftype; enum kmip_object_type otype; enum kmip_crypto_algo algo; int32_t bits; CK_OBJECT_CLASS public_key_class; CK_KEY_TYPE public_key_alg; enum kmip_result_status status = 0; enum kmip_result_reason reason = 0; int rc = 0; if (!public_keytype->is_asymmetric) { warnx("Unsupported object class"); rc = CKR_GENERAL_ERROR; goto out; } if (public_keytype->type != CKK_RSA) { warnx("Unsupported wrapping key algorithm"); rc = CKR_GENERAL_ERROR; goto out; } req_pl = kmip_new_get_request_payload(NULL, pubkey_uid, kmip_wrap_key_format, 0, 0, NULL); if (req_pl == NULL) { warnx("Allocate KMIP node failed"); rc = CKR_HOST_MEMORY; goto out; } rc = perform_kmip_request(KMIP_OPERATION_GET, req_pl, &resp_pl, &status, &reason); if (rc != 0) { rc = CKR_GENERAL_ERROR; goto out; } rc = kmip_get_get_response_payload(resp_pl, &otype, NULL, &kobj); if (rc != 0) { warnx("Failed to get wrapped key"); rc = CKR_GENERAL_ERROR; goto out; } public_key_class = get_p11_obj_class_from_kmip(otype); if (public_key_class != CKO_PUBLIC_KEY) { warnx("Invalid class"); rc = CKR_GENERAL_ERROR; goto out; } rc = kmip_get_public_key(kobj, &kblock); if (rc) { warnx("Failed to get wrapping key"); rc = CKR_GENERAL_ERROR; goto out; } rc = kmip_get_key_block(kblock, &ftype, NULL, &kval, &algo, &bits, NULL); if (rc) { warnx("Failed to get key block"); rc = CKR_GENERAL_ERROR; goto out; } if (ftype != kmip_wrap_key_format) { warnx("Key format is not RAW"); rc = CKR_GENERAL_ERROR; goto out; } public_key_alg = get_p11_alg_from_kmip(algo); if (public_key_alg != public_keytype->type) { warnx("Key algorithm is incorrect"); } rc = kmip_get_key_value(kval, &key, NULL, 0, NULL); if (rc) { warnx("Failed to get key value"); rc = CKR_GENERAL_ERROR; goto out; } switch (kmip_wrap_key_format) { case KMIP_KEY_FORMAT_TYPE_PKCS_1: rc = kmip_get_pkcs1_public_key(key, algo, pub_key); if (rc != CKR_OK) { warnx("Failed to get RSA wrapping key parts"); rc = CKR_FUNCTION_FAILED; goto out; } break; case KMIP_KEY_FORMAT_TYPE_PKCS_8: rc = kmip_get_pkcs8_public_key(key, pub_key); if (rc != CKR_OK) { warnx("Failed to get RSA wrapping key parts"); rc = CKR_FUNCTION_FAILED; goto out; } break; case KMIP_KEY_FORMAT_TYPE_TRANSPARENT_RSA_PUBLIC_KEY: rc = kmip_get_transparent_rsa_public_key(key, modulus_ptr, pub_exp_ptr); if (rc != CKR_OK) { warnx("Failed to get RSA wrapping key parts"); rc = CKR_FUNCTION_FAILED; goto out; } #if !OPENSSL_VERSION_PREREQ(3, 0) rsa_key = RSA_new(); if (rsa_key == NULL) { warnx("RSA_new failed."); rc = CKR_FUNCTION_FAILED; goto out; } modulus = BN_copy(modulus, *modulus_ptr); if (modulus == NULL) { warnx("Copying modulus failed"); rc = CKR_FUNCTION_FAILED; goto out; } pub_exp = BN_copy(pub_exp, *pub_exp_ptr); if (pub_exp == NULL) { warnx("Copying public exponent failed"); rc = CKR_FUNCTION_FAILED; goto out; } if (RSA_set0_key(rsa_key, modulus, pub_exp, NULL)) { warnx("RSA_set0_key failed."); rc = CKR_FUNCTION_FAILED; goto out; } if (EVP_PKEY_set1_RSA(*pub_key, (struct rsa_st *) rsa_key)) { warnx("RSA_PKEY_set1_RSA failed."); rc = CKR_FUNCTION_FAILED; goto out; } #else EVP_PKEY_set_bn_param(*pub_key, OSSL_PKEY_PARAM_RSA_N, *modulus_ptr); EVP_PKEY_set_bn_param(*pub_key, OSSL_PKEY_PARAM_RSA_E, *pub_exp_ptr); #endif break; default: warnx("Unsupported wrapping key format: %d", kmip_wrap_key_format); rc = CKR_ARGUMENTS_BAD; goto out; } out: kmip_node_free(cparams); kmip_node_free(wrap_id); kmip_node_free(wkey_info); kmip_node_free(wrap_spec); kmip_node_free(uid); kmip_node_free(req_pl); kmip_node_free(resp_pl); kmip_node_free(kobj); kmip_node_free(kblock); kmip_node_free(kval); kmip_node_free(wrap); kmip_node_free(wkinfo); kmip_node_free(wcparms); kmip_node_free(key); #if !OPENSSL_VERSION_PREREQ(3, 0) if (rsa_key != NULL) RSA_free(rsa_key); #endif return rc; } static CK_RV p11kmip_generate_remote_secret_key( const struct p11tool_objtype *keytype, CK_ULONG keysize, const char *secret_key_label, struct kmip_node **secret_key_uid) { struct kmip_node *act_req = NULL, *act_resp = NULL, *unique_id = NULL; struct kmip_node **attrs = NULL, *crea_req = NULL, *crea_resp = NULL; enum kmip_result_status crea_status = 0, act_status = 0; enum kmip_result_reason crea_reason = 0, act_reason = 0; unsigned int num_attrs, i, idx = 0; enum kmip_crypto_algo secret_alg = P11KMIP_KMIP_UNKNOWN_ALG; int rc = 0; num_attrs = 4 + (supports_sensitive_attr()? 1 : 0); attrs = calloc(num_attrs, sizeof(struct kmip_node *)); secret_alg = get_kmip_alg_from_p11(keytype->type); if (secret_alg == P11KMIP_KMIP_UNKNOWN_ALG) { warnx("Invalid key type being generated"); rc = CKR_FUNCTION_NOT_SUPPORTED; goto out; } attrs[idx] = kmip_new_cryptographic_algorithm(secret_alg); if (attrs[idx] == NULL) { warnx("Allocate KMIP node failed"); rc = CKR_HOST_MEMORY; goto out; } idx++; /* Cryptographic length wants it in bits */ attrs[idx] = kmip_new_cryptographic_length(keysize * 8); if (attrs[idx] == NULL) { warnx("Allocate KMIP node failed"); rc = CKR_HOST_MEMORY; goto out; } idx++; attrs[idx] = kmip_new_cryptographic_usage_mask(get_kmip_usage_mask_p11(keytype)); if (attrs[idx] == NULL) { warnx("Allocate KMIP node failed"); rc = CKR_HOST_MEMORY; goto out; } idx++; if (supports_sensitive_attr()) { attrs[idx] = kmip_new_sensitive(true); if (attrs[idx] == NULL) { warnx("Allocate KMIP node failed"); rc = CKR_HOST_MEMORY; goto out; } idx++; } attrs[idx] = kmip_new_name(secret_key_label, KMIP_NAME_TYPE_UNINTERPRETED_TEXT_STRING); if (attrs[idx] == NULL) { warnx("Allocate KMIP node failed"); rc = CKR_HOST_MEMORY; goto out; } idx++; crea_req = kmip_new_create_request_payload(NULL, KMIP_OBJECT_TYPE_SYMMETRIC_KEY, NULL, num_attrs, attrs); if (crea_req == NULL) { warnx("Allocate KMIP node failed"); rc = CKR_HOST_MEMORY; goto out; } act_req = kmip_new_activate_request_payload(NULL); /* ID placeholder */ if (act_req == NULL) { warnx("Allocate KMIP node failed"); rc = CKR_HOST_MEMORY; goto out; } rc = perform_kmip_request2(KMIP_OPERATION_CREATE, crea_req, &crea_resp, &crea_status, &crea_reason, KMIP_OPERATION_ACTIVATE, act_req, &act_resp, &act_status, &act_reason, KMIP_BATCH_ERR_CONT_STOP); if (rc != 0) { rc = CKR_GENERAL_ERROR; goto out; } rc = kmip_get_create_response_payload(crea_resp, NULL, &unique_id, NULL, 0, NULL); if (rc != CKR_OK) { warnx("Failed to get key unique-id"); rc = CKR_GENERAL_ERROR; goto out; } *secret_key_uid = unique_id; out: if (attrs != NULL) { for (i = 0; i < num_attrs; i++) kmip_node_free(attrs[i]); free(attrs); } kmip_node_free(crea_req); kmip_node_free(crea_resp); kmip_node_free(act_req); kmip_node_free(act_resp); return rc; } /** * @brief * * @param key_uid the UUID of the key to retrieve the buffer * for. Required. * @param digest_alg on output, the hashing algorithm used by * the digest. May be set to NULL. * @param digest the buffer to write the digest * into. Must be allocated by the caller. * May be set to NULL. * @param digest_len on input, the length of the digest buffer. * On output, the length of the digest * copied to the buffer. * * Returns an error if the buffer is not large enough. * * @return CK_RV */ static CK_RV p11kmip_digest_remote_key(struct kmip_node *key_uid, enum kmip_hashing_algo *digest_alg, CK_BYTE *digest, u_int32_t *digest_len) { struct kmip_node *attr_list_req = NULL, *attr_list_resp = NULL; struct kmip_node *get_attr_req = NULL, *get_attr_resp = NULL; struct kmip_node *attr_ref = NULL, *attr_ref_copy = NULL; struct kmip_node *digest_attr = NULL; const CK_BYTE *l_digest = NULL; u_int32_t l_digest_len = 0; enum kmip_hashing_algo l_digest_alg = 0; unsigned int num_attr_refs = 0, i = 0; enum kmip_tag attr_tag = 0; enum kmip_result_status attr_list_status, get_attr_status = 0; enum kmip_result_reason attr_list_reason, get_attr_reason = 0; CK_RV rc = CKR_OK; /* Get the attribute list */ attr_list_req = kmip_new_get_attribute_list_request_payload(key_uid); if (attr_list_req == NULL) { warnx("Allocate KMIP node failed"); rc = CKR_HOST_MEMORY; goto out; } rc = perform_kmip_request(KMIP_OPERATION_GET_ATTRIBUTE_LIST, attr_list_req, &attr_list_resp, &attr_list_status, &attr_list_reason); if (rc) { /* Handle Failure */ rc = CKR_FUNCTION_FAILED; warnx("Failed to KMIP object get attribute list"); goto out; } /* Confirm there's a "digest" attribute in the list */ rc = kmip_get_get_attribute_list_response_payload(attr_list_resp, NULL, &num_attr_refs, 0, NULL); if (rc != 0) { warnx("Retrieving KMIP attribute failed."); rc = CKR_FUNCTION_FAILED; goto out; } for (i = 0; i < num_attr_refs; i++) { kmip_node_free(attr_ref); rc = kmip_get_get_attribute_list_response_payload(attr_list_resp, NULL, NULL, i, &attr_ref); if (rc != 0) { warnx("Retrieving KMIP attribute failed."); rc = CKR_FUNCTION_FAILED; goto out; } if (attr_ref == NULL) { warnx("Retrieving KMIP attribute failed."); rc = CKR_FUNCTION_FAILED; goto out; } rc = kmip_get_attribute_reference(attr_ref, &attr_tag, NULL, NULL); if (rc) { warnx("Retrieving KMIP attribute failed."); rc = CKR_FUNCTION_FAILED; goto out; } if (attr_tag == KMIP_TAG_DIGEST) break; } if (i == num_attr_refs) { warnx("Failed to get KMIP object attribute list"); rc = CKR_ARGUMENTS_BAD; goto out; } /* Get the digest attribute */ attr_ref_copy = kmip_node_clone(attr_ref); if (attr_ref_copy == NULL) { warnx("Clone KMIP node failed"); rc = CKR_HOST_MEMORY; goto out; } get_attr_req = kmip_new_get_attributes_request_payload_va(NULL, key_uid, 1, attr_ref_copy); if (get_attr_req == NULL) { warnx("Allocate KMIP node failed"); rc = CKR_HOST_MEMORY; goto out; } rc = perform_kmip_request(KMIP_OPERATION_GET_ATTRIBUTES, get_attr_req, &get_attr_resp, &get_attr_status, &get_attr_reason); if (rc) { /* Handle Failure */ rc = CKR_FUNCTION_FAILED; warnx("Failed to get KMIP object attribute"); goto out; } num_attr_refs = 0; rc = kmip_get_get_attributes_response_payload(get_attr_resp, NULL, &num_attr_refs, 0, &digest_attr); if (rc) { /* Handle Failure */ rc = CKR_FUNCTION_FAILED; warnx("Failed to get KMIP object attribute"); goto out; } /* We should have recieved exactly 1 attribute reference */ if (num_attr_refs != 1) { rc = CKR_FUNCTION_FAILED; warnx("Unexpected number of attributes " "returned from get attributes request"); goto out; } rc = kmip_get_digest(digest_attr, &l_digest_alg, &l_digest, &l_digest_len); if (rc) { rc = CKR_FUNCTION_FAILED; warnx("Failed to get digest from KMIP digest attribute"); goto out; } if (digest != NULL) { /* Confirm the caller provided us a large enough buffer */ if (l_digest_len > *digest_len) { rc = CKR_BUFFER_TOO_SMALL; warnx("Digest buffer could not contain digest value"); goto out; } /* Now we can safely copy */ memcpy(digest, l_digest, l_digest_len); } *digest_len = l_digest_len; *digest_alg = l_digest_alg; out: kmip_node_free(attr_ref); kmip_node_free(attr_ref_copy); kmip_node_free(attr_list_req); kmip_node_free(attr_list_resp); kmip_node_free(get_attr_req); kmip_node_free(get_attr_resp); kmip_node_free(digest_attr); return rc; } /***************************************************************************/ /* Functions for Manipulating a Remote KMIP Server */ /***************************************************************************/ static CK_RV get_slot(CK_SLOT_ID *slot) { int f; struct ConfigBaseNode *c, *cfg_slot; struct ConfigStructNode *structnode; bool found = false; *slot = opt_slot; /* If not set by option, fallback to env variable */ if (*slot == (CK_SLOT_ID)-1) *slot = env_pkcs_slot; /* If not set by env variable, fallback to conf file */ if (*slot == (CK_SLOT_ID)-1) { if (p11kmip_cfg != NULL) { /* Iterate the configuration node(s) */ confignode_foreach(c, p11kmip_cfg, f) { if (!confignode_hastype(c, CT_STRUCT) || strcmp(c->key, P11KMIP_CONFIG_KEYWORD_PKCS11) != 0) { continue; } else if (found) { warnx("Syntax error in config file:" " '%s' specified multiple times", P11KMIP_CONFIG_KEYWORD_PKCS11); return CKR_ARGUMENTS_BAD; } found = true; structnode = confignode_to_struct(c); cfg_slot = confignode_find(structnode->value, P11KMIP_CONFIG_KEYWORD_PKCS_SLOT); if (cfg_slot != NULL && !confignode_hastype(cfg_slot, CT_INTVAL)) { warnx("Syntax error in config file:" " Missing '%s' in attribute at line %hu", P11KMIP_CONFIG_KEYWORD_WRAP_KEY_SIZE, c->line); return CKR_ARGUMENTS_BAD; } if (cfg_slot != NULL) { *slot = confignode_to_intval(cfg_slot)->value; } } } } if (*slot == (CK_SLOT_ID)-1) { warnx("The PKCS#11 slot ID must be specified"); return CKR_ARGUMENTS_BAD; } return CKR_OK; } int main(int argc, char *argv[]) { const struct p11tool_cmd *command = NULL; CK_SLOT_ID slot; CK_RV rc = CKR_OK; /* Get p11kmip command (if any) */ if (argc >= 2 && strncmp(argv[1], "-", 1) != 0) { command = p11tool_find_command(p11kmip_commands, argv[1]); if (command == NULL) { warnx("Invalid command '%s'", argv[1]); rc = CKR_ARGUMENTS_BAD; goto done; } argc--; argv = &argv[1]; } /* Get command arguments (if any) */ rc = p11tool_parse_cmd_arguments(command, &argc, &argv); if (rc != CKR_OK) goto done; /* Get generic and command specific options (if any) */ rc = p11tool_parse_cmd_options(command, p11kmip_generic_opts, argc, argv); if (rc != CKR_OK) goto done; if (opt_help) { if (command == NULL) p11tool_print_help("p11kmip", p11kmip_commands, p11kmip_generic_opts, PRINT_INDENT_POS); else p11tool_print_command_help("p11kmip",command, p11kmip_generic_opts, PRINT_INDENT_POS); goto done; } if (opt_version) { p11tool_print_version("p11kmip"); goto done; } if (command == NULL) { warnx("A command is required. Use '-h'/'--help' to see the list of " "supported commands"); rc = CKR_ARGUMENTS_BAD; goto done; } rc = p11tool_check_required_args(command->args); if (rc != CKR_OK) goto done; rc = p11tool_check_required_cmd_opts(command->opts, command->args, p11kmip_generic_opts); if (rc != CKR_OK) goto done; rc = parse_env_vars(); if (rc != CKR_OK) goto done; rc = parse_config_file(); if (rc != CKR_OK) goto done; rc = init_kmip(); if (rc != CKR_OK) goto done; rc = get_slot(&slot); if (rc != CKR_OK) goto done; opt_slot = slot; if (opt_pin == NULL) opt_pin = env_pkcs_pin; rc = p11tool_init_pkcs11(command, false, opt_pin, opt_force_pin_prompt, false, false, slot, NULL); if (rc != CKR_OK) goto done; /* Run the command */ rc = command->func(); if (rc != CKR_OK) { warnx("Failed to perform the '%s' command: %s", command->cmd, p11_get_ckr(rc)); goto done; } done: term_kmip(); p11tool_term_pkcs11(); if (p11kmip_cfg != NULL) confignode_deepfree(p11kmip_cfg); return rc; } opencryptoki-opencryptoki-451d99c/usr/sbin/p11kmip/p11kmip.conf000066400000000000000000000005161520105705100245050ustar00rootroot00000000000000kmip { host = "0.0.0.0:5696" tls_client_cert = "/tmp/certs/client_certificate_jane_doe.pem" tls_client_key = "/tmp/certs/client_key_jane_doe.pem" wrap_key_format = "PKCS1" wrap_key_algorithm = "RSA" wrap_key_size = 2048 wrap_padding_method = "PKCS1.5" wrap_hashing_algorithm = "SHA-1" } pkcs11 { slot = 0 }opencryptoki-opencryptoki-451d99c/usr/sbin/p11kmip/p11kmip.h000066400000000000000000000377621520105705100240240ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2001-2022 * * This program is provided under the terms of the Common Public License, * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this * 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 P11KMIP_H_ #define P11KMIP_H_ #include "p11tool.h" #include "ec_curves.h" #include #define P11KMIP_DEFAULT_PKCS11_LIB "libopencryptoki.so"; #define P11KMIP_CONFIG_FILE_NAME "p11kmip.conf" #define P11KMIP_DEFAULT_CONFIG_FILE OCK_CONFDIR "/" P11KMIP_CONFIG_FILE_NAME #define P11KMIP_SERVER_CERT_PATH "/tmp/p11kmip-server-cert-tmp.pem" #define P11KMIP_SERVER_PKEY_PATH "/tmp/p11kmip-server-pubkey-tmp.pem" #define P11KMIP_PKCSLIB_ENV_NAME "PKCSLIB" #define P11KMIP_CONF_FILE_ENV_NAME "P11KMIP_CONF_FILE" #define PKCS11_SLOT_ID_ENV_NAME "PKCS11_SLOT_ID" #define KMIP_HOSTNAME_ENV_NAME "KMIP_HOSTNAME" #define KMIP_CLIENT_CERT_ENV_NAME "KMIP_CLIENT_CERT" #define KMIP_CLIENT_KEY_ENV_NAME "KMIP_CLIENT_KEY" #define KMIP_PEM_PASSWORD_ENV_NAME "KMIP_PEM_PASSWORD" #define P11KMIP_CONFIG_KEYWORD_KMIP "kmip" #define P11KMIP_CONFIG_KEYWORD_PKCS11 "pkcs11" #define P11KMIP_CONFIG_KEYWORD_HOST "host" #define P11KMIP_CONFIG_KEYWORD_PORT "port" #define P11KMIP_CONFIG_KEYWORD_CLIENT_CERT "tls_client_cert" #define P11KMIP_CONFIG_KEYWORD_CLIENT_KEY "tls_client_key" #define P11KMIP_CONFIG_KEYWORD_WRAP_KEY_FMT "wrap_key_format" #define P11KMIP_CONFIG_KEYWORD_WRAP_KEY_ALG "wrap_key_algorithm" #define P11KMIP_CONFIG_KEYWORD_WRAP_KEY_SIZE "wrap_key_size" #define P11KMIP_CONFIG_KEYWORD_WRAP_PAD_MTHD "wrap_padding_method" #define P11KMIP_CONFIG_KEYWORD_WRAP_HASH_ALG "wrap_hashing_algorithm" #define P11KMIP_CONFIG_KEYWORD_PKCS_SLOT "slot" #define P11KMIP_CONFIG_VALUE_KEY_ALG_RSA "RSA" #define P11KMIP_CONFIG_VALUE_FMT_PKCS1 "PKCS1" #define P11KMIP_CONFIG_VALUE_FMT_PKCS8 "PKCS8" #define P11KMIP_CONFIG_VALUE_FMT_TRANSPARENT "TransparentPublicKey" #define P11KMIP_CONFIG_VALUE_METHD_PKCS15 "PKCS1.5" #define P11KMIP_CONFIG_VALUE_METHD_OAEP "OAEP" #define P11KMIP_CONFIG_VALUE_HSH_ALG_SHA_1 "SHA-1" #define P11KMIP_CONFIG_VALUE_HSH_ALG_SHA_256 "SHA-256" #define UNUSED(var) ((void)(var)) #define OPT_FORCE_PIN_PROMPT 256 #define OPT_PEM_PASSWORD 257 #define OPT_FORCE_PEM_PWD_PROMPT 258 #define OPT_SEND_WRAPKEY 259 #define OPT_RETR_WRAPKEY 260 #define OPT_GEN_TARGKEY 261 #define OPT_KMIP_HOSTNAME 262 #define OPT_KMIP_CLIENT_CERT 263 #define OPT_KMIP_CLIENT_KEY 264 #define OPT_KMIP_PEM_PASSWORD 265 #define OPT_TLS_VERIFY_HOSTNAME 266 #define OPT_TLS_NO_VERIFY_CERT 267 #define OPT_TLS_TRUST_CERT 268 #define OPT_TARGKEY_ATTRS 269 #define OPT_TARGKEY_ID 270 #define OPT_TARGKEY_LEN 271 #define OPT_WRAPKEY_ATTRS 272 #define OPT_WRAPKEY_ID 273 #define PRINT_INDENT_POS 45 #define FIND_OBJECTS_COUNT 64 #define LIST_KEYTYPE_CELL_SIZE 22 #define MAX_SYM_CLEAR_KEY_SIZE 64 #define P11KMIP_DEFAULT_AES_KEY_LENGTH 32 #define P11KMIP_P11_UNKNOWN_ALG 0xFFFFFFFF #define P11KMIP_KMIP_UNKNOWN_ALG 0xFF #define P11KMIP_KMIP_TO_P11_ALG_TABLE_LENGTH 14 #define P11KMIP_P11_TO_KMIP_ALG_TABLE_LENGTH 32 static const CK_KEY_TYPE P11KMIP_KMIP_TO_P11_ALG_TABLE[] = { P11KMIP_P11_UNKNOWN_ALG, CKK_DES, CKK_DES3, CKK_AES, CKK_RSA, CKK_DSA, CKK_ECDSA, P11KMIP_P11_UNKNOWN_ALG, // KMIP_CRYPTO_ALGO_HMAC_SHA1 P11KMIP_P11_UNKNOWN_ALG, // KMIP_CRYPTO_ALGO_HMAC_SHA224 P11KMIP_P11_UNKNOWN_ALG, // KMIP_CRYPTO_ALGO_HMAC_SHA256 P11KMIP_P11_UNKNOWN_ALG, // KMIP_CRYPTO_ALGO_HMAC_SHA384 P11KMIP_P11_UNKNOWN_ALG, // KMIP_CRYPTO_ALGO_HMAC_SHA512 P11KMIP_P11_UNKNOWN_ALG, // KMIP_CRYPTO_ALGO_HMAC_MD5 CKK_DH }; static const enum kmip_crypto_algo P11KMIP_P11_TO_KMIP_ALG_TABLE[] = { KMIP_CRYPTO_ALGO_RSA, KMIP_CRYPTO_ALGO_DSA, KMIP_CRYPTO_ALGO_DH, KMIP_CRYPTO_ALGO_EC, P11KMIP_KMIP_UNKNOWN_ALG, // CKK_X9_42_DH P11KMIP_KMIP_UNKNOWN_ALG, // CKK_KEA P11KMIP_KMIP_UNKNOWN_ALG, // Undefined P11KMIP_KMIP_UNKNOWN_ALG, // Undefined P11KMIP_KMIP_UNKNOWN_ALG, // Undefined P11KMIP_KMIP_UNKNOWN_ALG, // Undefined P11KMIP_KMIP_UNKNOWN_ALG, // Undefined P11KMIP_KMIP_UNKNOWN_ALG, // Undefined P11KMIP_KMIP_UNKNOWN_ALG, // Undefined P11KMIP_KMIP_UNKNOWN_ALG, // Undefined P11KMIP_KMIP_UNKNOWN_ALG, // Undefined P11KMIP_KMIP_UNKNOWN_ALG, // Undefined P11KMIP_KMIP_UNKNOWN_ALG, // CKK_GENERIC_SECRET KMIP_CRYPTO_ALGO_RC2, KMIP_CRYPTO_ALGO_RC4, KMIP_CRYPTO_ALGO_DES, P11KMIP_KMIP_UNKNOWN_ALG, // CKK_DES2 KMIP_CRYPTO_ALGO_3DES, P11KMIP_KMIP_UNKNOWN_ALG, // CKK_CAST P11KMIP_KMIP_UNKNOWN_ALG, // CKK_CAST3 KMIP_CRYPTO_ALGO_CAST5, KMIP_CRYPTO_ALGO_RC5, KMIP_CRYPTO_ALGO_IDEA, KMIP_CRYPTO_ALGO_SKIPJACK, P11KMIP_KMIP_UNKNOWN_ALG, // CKK_BATON P11KMIP_KMIP_UNKNOWN_ALG, // CKK_JUNIPER P11KMIP_KMIP_UNKNOWN_ALG, // CKK_CDMF KMIP_CRYPTO_ALGO_AES }; #define P11KMIP_P11_UNKNOWN_OBJ 0xFFFFFFFF #define P11KMIP_KMIP_UNKNOWN_OBJ 0xFF #define P11KMIP_KMIP_TO_P11_OBJ_TABLE_LENGTH 10 #define P11KMIP_P11_TO_KMIP_OBJ_TABLE_LENGTH 10 static const CK_OBJECT_CLASS P11KMIP_KMIP_TO_P11_OBJ_TABLE[] = { P11KMIP_P11_UNKNOWN_OBJ, // Undefined CKO_CERTIFICATE, CKO_SECRET_KEY, CKO_PUBLIC_KEY, CKO_PRIVATE_KEY, P11KMIP_P11_UNKNOWN_OBJ, // KMIP_OBJECT_TYPE_SPLIT_KEY P11KMIP_P11_UNKNOWN_OBJ, // KMIP_OBJECT_TYPE_TEMPLATE P11KMIP_P11_UNKNOWN_OBJ, // KMIP_OBJECT_TYPE_SECRET_DATA P11KMIP_P11_UNKNOWN_OBJ, // KMIP_OBJECT_TYPE_OPAQUE_OBJECT P11KMIP_P11_UNKNOWN_OBJ, // KMIP_OBJECT_TYPE_PGP_KEY P11KMIP_P11_UNKNOWN_OBJ // KMIP_OBJECT_TYPE_CERTIFICATE_REQUEST }; static const enum kmip_object_type P11KMIP_P11_TO_KMIP_OBJ_TABLE[] = { P11KMIP_KMIP_UNKNOWN_OBJ, // CKO_DATA KMIP_OBJECT_TYPE_CERTIFICATE, KMIP_OBJECT_TYPE_PUBLIC_KEY, KMIP_OBJECT_TYPE_PRIVATE_KEY, KMIP_OBJECT_TYPE_SYMMETRIC_KEY, P11KMIP_KMIP_UNKNOWN_OBJ, // CKO_HW_FEATURE P11KMIP_KMIP_UNKNOWN_OBJ, // CKO_DOMAIN_PARAMETERS P11KMIP_KMIP_UNKNOWN_OBJ, // Undefined P11KMIP_KMIP_UNKNOWN_OBJ, // Undefined P11KMIP_KMIP_UNKNOWN_OBJ, // Undefined P11KMIP_KMIP_UNKNOWN_OBJ // CKO_PROFILE }; #define P11KMIP_P11_UNKNOWN_HASH 0xFFFFFFFF #define P11KMIP_KMIP_TO_P11_HASH_TABLE_LENGTH 18 static const CK_MECHANISM_TYPE P11KMIP_KMIP_TO_P11_HASH_TABLE[] = { P11KMIP_P11_UNKNOWN_HASH, // kmip_hashing_algo enums are 1-indexed CKM_MD2, P11KMIP_P11_UNKNOWN_HASH, //MD4 CKM_MD5, CKM_SHA_1, CKM_SHA224, CKM_SHA256, CKM_SHA384, CKM_SHA512, CKM_RIPEMD160, P11KMIP_P11_UNKNOWN_HASH, // TIGER P11KMIP_P11_UNKNOWN_HASH, //WHIRLPOOL CKM_SHA512_224, CKM_SHA512_256, CKM_SHA3_224, CKM_SHA3_256, CKM_SHA3_384, CKM_SHA3_512, }; struct kmip_enum_name { uint32_t value; const char *name; }; static const struct kmip_enum_name required_operations[] = { {.value = KMIP_OPERATION_QUERY,.name = "Query"}, {.value = KMIP_OPERATION_CREATE,.name = "Create"}, {.value = KMIP_OPERATION_REGISTER,.name = "Register"}, {.value = KMIP_OPERATION_ACTIVATE,.name = "Activate"}, {.value = KMIP_OPERATION_REVOKE,.name = "Revoke"}, {.value = KMIP_OPERATION_DESTROY,.name = "Destroy"}, {.value = KMIP_OPERATION_GET,.name = "Get"}, {.value = KMIP_OPERATION_LOCATE,.name = "Locate"}, {.value = KMIP_OPERATION_GET_ATTRIBUTE_LIST, .name = "Get Attribute List"}, {.value = KMIP_OPERATION_GET_ATTRIBUTES, .name = "Get Attributes"}, {.value = KMIP_OPERATION_ADD_ATTRIBUTE, .name = "Add Attribute"}, {.value = KMIP_OPERATION_DELETE_ATTRIBUTE, .name = "Delete Attribute"}, {.value = 0,.name = NULL}, }; static const struct kmip_enum_name required_objtypes[] = { {.value = KMIP_OBJECT_TYPE_SYMMETRIC_KEY,.name = "Symmetric Key"}, {.value = KMIP_OBJECT_TYPE_PUBLIC_KEY,.name = "Public Key"}, {.value = 0,.name = NULL}, }; static const struct kmip_version kmip_version_1_0 = { .major = 1,.minor = 0, }; static const struct kmip_version kmip_version_1_2 = { .major = 1,.minor = 2, }; static const struct kmip_enum_name kmip_result_statuses[] = { {.value = KMIP_RESULT_STATUS_SUCCESS,.name = "Success"}, {.value = KMIP_RESULT_STATUS_OPERATION_FAILED, .name = "Operation Failed"}, {.value = KMIP_RESULT_STATUS_OPERATION_PENDING, .name = "Operation Pending"}, {.value = KMIP_RESULT_STATUS_OPERATION_UNDONE, .name = "Operation Undone"}, {.value = 0,.name = NULL}, }; static const struct kmip_enum_name kmip_result_reasons[] = { {.value = KMIP_RESULT_REASON_ITEM_NOT_FOUND, .name = "Item Not Found"}, {.value = KMIP_RESULT_REASON_RESPONSE_TOO_LARGE, .name = "Response Too Large"}, {.value = KMIP_RESULT_REASON_AUTH_NOT_SUCCESSFUL, .name = "Authentication Not Successful"}, {.value = KMIP_RESULT_REASON_INVALID_MESSAGE, .name = "Invalid Message"}, {.value = KMIP_RESULT_REASON_OPERATION_NOT_SUCCESSFUL, .name = "Operation Not Supported"}, {.value = KMIP_RESULT_REASON_MISSING_DATA,.name = "Missing Data"}, {.value = KMIP_RESULT_REASON_INVALIUD_FIELD,.name = "Invalid Field"}, {.value = KMIP_RESULT_REASON_FEATURE_NOT_SUPPORTED, .name = "Feature Not Supported"}, {.value = KMIP_RESULT_REASON_OP_CANCELED_BY_REQUESTOR, .name = "Operation Canceled By Requeste"}, {.value = KMIP_RESULT_REASON_CRYPTOGRAPHIC_FAILURE, .name = "Cryptographic Failure"}, {.value = KMIP_RESULT_REASON_ILLEGAL_OPERATION, .name = "Illegal Operation"}, {.value = KMIP_RESULT_REASON_PERMISSION_DENIED, .name = "Permission Denied"}, {.value = KMIP_RESULT_REASON_OBJECT_ARCHIVED, .name = "Object Archived"}, {.value = KMIP_RESULT_REASON_INDEX_OUT_OF_BOUNDS, .name = "Index Out Of Bounds"}, {.value = KMIP_RESULT_REASON_APP_NAMESPACE_NOT_SUPPORTED, .name = "Application Namespace Not Supported"}, {.value = KMIP_RESULT_REASON_KEY_FORMAT_TYPE_NOT_SUPPORTED, .name = "Key Format Type Not Supported"}, {.value = KMIP_RESULT_REASON_KEY_COMPRESSION_TYPE_NOT_SUPPORTED, .name = "Key Compression Type Not Supported"}, {.value = KMIP_RESULT_REASON_ENCODING_OPTION_ERROR, .name = "Encoding Option Error"}, {.value = KMIP_RESULT_REASON_KEY_VALUE_NOT_PRESENT, .name = "Key Value Not Present"}, {.value = KMIP_RESULT_REASON_ATTESTATION_REQUIRED, .name = "Attestation Required"}, {.value = KMIP_RESULT_REASON_ATTESTATION_FAILED, .name = "Attestation Failed"}, {.value = KMIP_RESULT_REASON_SENSITIVE,.name = "Sensitive"}, {.value = KMIP_RESULT_REASON_NOT_EXTRACTABLE, .name = "Not Extractable"}, {.value = KMIP_RESULT_REASON_OBJECT_ALREADY_EXISTS, .name = "Object Already Exists"}, {.value = KMIP_RESULT_REASON_INVALID_TICKET, .name = "Invalid Ticket"}, {.value = KMIP_RESULT_REASON_USAGE_LIMIT_EXCEEDED, .name = "Usage Limit Exceeded"}, {.value = KMIP_RESULT_REASON_NUMERIC_RANGE,.name = "Numeric Range"}, {.value = KMIP_RESULT_REASON_INVALID_DATA_TYPE, .name = "Invalid Data Type"}, {.value = KMIP_RESULT_REASON_READ_ONLY_ATTRIBUTE, .name = "Read Only Attribute"}, {.value = KMIP_RESULT_REASON_MULTI_VALUED_ATTRIBUTE, .name = "Multi Valued Attribute"}, {.value = KMIP_RESULT_REASON_UNSUPPORTED_ATTRIBUTE, .name = "Unsupported Attribute"}, {.value = KMIP_RESULT_REASON_ATTRIBUTE_INSTANCE_NOT_FOUND, .name = "Attribute Instance Not Found"}, {.value = KMIP_RESULT_REASON_ATTRIBUTE_NOT_FOUND, .name = "Attribute Not Found"}, {.value = KMIP_RESULT_REASON_ATTRIBUTE_READ_ONLY, .name = "Attribute Read Only"}, {.value = KMIP_RESULT_REASON_ATTRIBUTE_SINGLE_VALUED, .name = "Attribute Single Valued"}, {.value = KMIP_RESULT_REASON_BAD_CRYPTOGRAPHIC_PARAMETERS, .name = "Bad Cryptographic Parameters"}, {.value = KMIP_RESULT_REASON_BAD_PASSWORD,.name = "Bad Password"}, {.value = KMIP_RESULT_REASON_CODEC_ERROR,.name = "Codec Error"}, {.value = KMIP_RESULT_REASON_ILLEGAL_OBJECT_TYPE, .name = "Illegal Object Type"}, {.value = KMIP_RESULT_REASON_INCOMPATIBLE_CRYPTO_USAGE_MASK, .name = "Incompatible Cryptographic Usage Mask"}, {.value = KMIP_RESULT_REASON_INTERNAL_SERVER_ERROR, .name = "Internal Server Error"}, {.value = KMIP_RESULT_REASON_INVALID_ASYNC_CORRELATION_VALUE, .name = "Invalid Asynchronous Correlation Value"}, {.value = KMIP_RESULT_REASON_INVALID_ATTRIBUTE, .name = "Invalid Attribute"}, {.value = KMIP_RESULT_REASON_INVALID_ATTRIBUTE_VALUE, .name = "Invalid Attribute Value"}, {.value = KMIP_RESULT_REASON_INVALID_CORRELATION_VALUE, .name = "Invalid Correlation Value"}, {.value = KMIP_RESULT_REASON_INVALID_CSR,.name = "Invalid CSR"}, {.value = KMIP_RESULT_REASON_INVALID_OBJECT_TYPE, .name = "Invalid Object Type"}, {.value = KMIP_RESULT_REASON_KEY_WRAP_TYPE_NOT_SUPPORTED, .name = "Key Wrap Type Not Supported"}, {.value = KMIP_RESULT_REASON_MISSING_INITIALIZATION_VECTOR, .name = "Missing Initialization Vector"}, {.value = KMIP_RESULT_REASON_NOT_UNIQUE_NAME_ATTRIBUTE, .name = "Non Unique Name Attribute"}, {.value = KMIP_RESULT_REASON_OBJECT_DESTROYED, .name = "Object Destroyed"}, {.value = KMIP_RESULT_REASON_OBJECT_NOT_FOUND, .name = "Object Not Found"}, {.value = KMIP_RESULT_REASON_NOT_AUTHORISED, .name = "Not Authorised"}, {.value = KMIP_RESULT_REASON_SERVER_LIMIT_EXCEEDED, .name = "Server Limit Exceeded"}, {.value = KMIP_RESULT_REASON_UNKNOWN_ENUMERATION, .name = "Unknown Enumeration"}, {.value = KMIP_RESULT_REASON_UNKNOWN_MESSAGE_EXTENSION, .name = "Unknown Message Extension"}, {.value = KMIP_RESULT_REASON_UNKNOWN_TAG,.name = "Unknown Tag"}, {.value = KMIP_RESULT_REASON_UNSUPPORTED_CRYPTO_PARAMETERS, .name = "Unsupported Cryptographic Parameters"}, {.value = KMIP_RESULT_REASON_UNSUPPORTED_PROTOCOL_VERSION, .name = "Unsupported Protocol Version"}, {.value = KMIP_RESULT_REASON_WRAPPING_OBJECT_ARCHIVED, .name = "Wrapping Object Archived"}, {.value = KMIP_RESULT_REASON_WRAPPING_OBJECT_DESTROYED, .name = "Wrapping Object Destroyed"}, {.value = KMIP_RESULT_REASON_WRAPPING_OBJECT_NOT_FOUND, .name = "Wrapping Object Not Found"}, {.value = KMIP_RESULT_REASON_WRONG_KEY_LIFECYCLE_STATE, .name = "Wrong Key Lifecycle State"}, {.value = KMIP_RESULT_REASON_PROTECTION_STORAGE_UNAVAILABLE, .name = "Protection Storage Unavailable"}, {.value = KMIP_RESULT_REASON_PKCS_11_CODE_ERROR, .name = "PKCS#11 Codec Error"}, {.value = KMIP_RESULT_REASON_PKCS_11_INVALID_FUNCTION, .name = "PKCS#11 Invalid Function"}, {.value = KMIP_RESULT_REASON_PKCS_11_INVALID_INTERFACE, .name = "PKCS#11 Invalid Interface"}, {.value = KMIP_RESULT_REASON_PRIVATE_PROT_STORAGE_UNAVAILABLE, .name = "Private Protection Storage Unavailable"}, {.value = KMIP_RESULT_REASON_PUBLIC_PROT_STORAGE_UNAVAILABLE, .name = "Public Protection Storage Unavailable"}, {.value = KMIP_RESULT_REASON_UNKNOWN_OBJECT_GROUP, .name = "Unknown Object Group"}, {.value = KMIP_RESULT_REASON_CONSTRAINT_VIOLATION, .name = "Constraint Violation"}, {.value = KMIP_RESULT_REASON_DUPLICATE_PROCESS_REQUEST, .name = "Duplicate Process Request"}, {.value = KMIP_RESULT_REASON_GENERAL_FAILURE, .name = "General Failure"}, {.value = 0,.name = NULL}, }; #define print_hex(x, y) \ do { \ unsigned char *hex = x; \ int i; \ for (i = 0; i < y; i++) { \ printf("%02x", hex[i]); \ } \ } while (0) #endif opencryptoki-opencryptoki-451d99c/usr/sbin/p11kmip/p11kmip.mk000066400000000000000000000024311520105705100241650ustar00rootroot00000000000000include usr/sbin/p11kmip/kmipclient/kmipclient.mk sbin_PROGRAMS += usr/sbin/p11kmip/p11kmip noinst_HEADERS += usr/sbin/p11kmip/p11kmip.h usr_sbin_p11kmip_p11kmip_LDADD = usr/sbin/p11kmip/kmipclient/libkmipclient.a \ -ldl -lcrypto -lssl if AIX usr_sbin_p11kmip_p11kmip_LDFLAGS = -Wl,-blibpath:$(libdir)/opencryptoki:$(libdir)/opencryptoki/stdll:/usr/lib:/usr/lib64 endif EXTRA_DIST += usr/sbin/p11kmip/p11kmip.conf usr_sbin_p11kmip_p11kmip_CFLAGS = -DLINUX -DPROGRAM_NAME=\"$(@)\" \ -I${srcdir}/usr/include -I${srcdir}/usr/lib/common \ -I${srcdir}/usr/sbin/p11kmip -I${srcdir}/usr/lib/config \ -I${top_builddir}/usr/lib/config -I${top_builddir}/usr/lib/api \ -I${srcdir}/usr/lib/api -I${srcdir}/usr/sbin/p11sak if !AIX usr_sbin_p11kmip_p11kmip_CFLAGS += -DLINUX endif usr_sbin_p11kmip_p11kmip_SOURCES = usr/lib/common/p11util.c \ usr/sbin/p11kmip/p11kmip.c usr/lib/common/pin_prompt.c \ usr/lib/config/configuration.c usr/lib/common/uri.c \ usr/lib/common/buffer.c usr/sbin/p11sak/p11tool.c \ usr/lib/config/cfgparse.y usr/lib/config/cfglex.l if AIX usr_sbin_p11kmip_p11kmip_SOURCES += usr/lib/common/aix/err.c \ usr/lib/common/aix/getopt_long.c endif nodist_usr_sbin_p11kmip_p11kmip_SOURCES = usr/lib/api/mechtable.c usr/sbin/p11kmip/p11kmip.$(OBJEXT): usr/lib/config/cfgparse.h opencryptoki-opencryptoki-451d99c/usr/sbin/p11sak/000077500000000000000000000000001520105705100221705ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/usr/sbin/p11sak/p11sak.c000066400000000000000000015551011520105705100234440ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2001-2022 * * This program is provided under the terms of the Common Public License, * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this * 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 defined(_AIX) const char *__progname = "p11sak"; #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define P11SAK_DECLARE_CURVES #include "p11sak.h" #include "p11util.h" #include "pin_prompt.h" #include "cfgparser.h" #include "configuration.h" #include "mechtable.h" #include "defs.h" #include "pqc_defs.h" #if OPENSSL_VERSION_PREREQ(3, 0) #include #include #include #ifndef OSSL_PKEY_PARAM_ML_DSA_SEED #define OSSL_PKEY_PARAM_ML_DSA_SEED "seed" #endif #ifndef OSSL_PKEY_PARAM_ML_KEM_SEED #define OSSL_PKEY_PARAM_ML_KEM_SEED "seed" #endif #endif static CK_RV p11sak_generate_key(void); static CK_RV p11sak_list_key(void); static CK_RV p11sak_remove_key(void); static CK_RV p11sak_set_key_attr(void); static CK_RV p11sak_copy_key(void); static CK_RV p11sak_import_key(void); static CK_RV p11sak_export_key(void); static CK_RV p11sak_extract_key_pubkey(void); static void print_generate_import_key_attr_help(void); static void print_list_key_attr_help(void); static void print_set_copy_extract_key_attr_help(void); static void print_remove_key_help(void); static CK_RV p11sak_list_cert(void); static CK_RV p11sak_remove_cert(void); static CK_RV p11sak_set_cert_attr(void); static CK_RV p11sak_copy_cert(void); static CK_RV p11sak_import_cert(void); static CK_RV p11sak_export_cert(void); static CK_RV p11sak_extract_cert_pubkey(void); static void print_import_cert_attr_help(void); static void print_list_cert_attr_help(void); static void print_set_copy_cert_attr_help(void); static void print_remove_cert_help(void); static void print_extract_cert_pubkey_help(void); static struct ConfigBaseNode *p11sak_cfg = NULL; static bool opt_help = false; static bool opt_version = false; CK_SLOT_ID opt_slot = (CK_SLOT_ID)-1; static char *opt_pin = NULL; static bool opt_force_pin_prompt = false; static bool opt_no_login = false; bool opt_so = false; struct p11tool_enum_value *opt_keytype = NULL; static struct p11tool_enum_value *opt_certtype = NULL; static CK_ULONG opt_keybits_num = 0; static struct p11tool_enum_value *opt_keybits = NULL; static struct p11tool_enum_value *opt_group = NULL; static char *opt_pem_file = NULL; static struct p11tool_enum_value *opt_curve = NULL; static struct p11tool_enum_value *opt_pqc_version = NULL; char *opt_label = NULL; bool opt_force = false; static CK_ULONG opt_exponent = 0; char *opt_attr = NULL; char *opt_id = NULL; static bool opt_long = false; static bool opt_detailed_uri = false; static char *opt_sort = NULL; static char *opt_new_attr = NULL; static char *opt_new_label = NULL; static char *opt_new_id = NULL; char *opt_file = NULL; static char *opt_pem_password = NULL; static bool opt_force_pem_pwd_prompt = false; static bool opt_encrypted_pem = false; static bool opt_opaque = false; static struct p11tool_enum_value *opt_asym_kind = NULL; static bool opt_spki = false; static bool opt_der = false; static bool opt_cacert = false; static bool opt_uri_pem = false; static bool opt_uri_pin_value = false; static char *opt_uri_pin_source = NULL; static bool opt_oqsprovider_pem = false; static bool opt_hsm_mkvp = false; static bool opt_ep11_session_id = false; char *opt_kek_label = NULL; char *opt_kek_id = NULL; bool opt_raw = false; struct p11tool_enum_value *opt_wrap_mech = NULL; static bool opt_slot_is_set(const struct p11tool_arg *arg); static CK_RV generic_get_key_size(const struct p11tool_objtype *keytype, void *private, CK_ULONG *keysize); static CK_RV generic_add_secret_attrs(const struct p11tool_objtype *keytype, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, void *private); static CK_ULONG generic_keysize_adjust(const struct p11tool_objtype *keytype, CK_ULONG keysize); static CK_RV aes_get_key_size(const struct p11tool_objtype *keytype, void *private, CK_ULONG *keysize); static CK_RV aes_add_secret_attrs(const struct p11tool_objtype *keytype, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, void *private); static CK_ULONG aes_keysize_adjust(const struct p11tool_objtype *keytype, CK_ULONG keysize); static CK_ULONG aes_xts_keysize_adjust(const struct p11tool_objtype *keytype, CK_ULONG keysize); static CK_ULONG rsa_keysize_adjust(const struct p11tool_objtype *keytype, CK_ULONG keysize); static CK_ULONG dh_keysize_adjust(const struct p11tool_objtype *keytype, CK_ULONG keysize); static CK_ULONG dsa_keysize_adjust(const struct p11tool_objtype *keytype, CK_ULONG keysize); static CK_RV rsa_get_key_size(const struct p11tool_objtype *keytype, void *private, CK_ULONG *keysize); static CK_RV rsa_add_public_attrs(const struct p11tool_objtype *keytype, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, void *private); static CK_RV ec_get_key_size(const struct p11tool_objtype *keytype, void *private, CK_ULONG *keysize); static CK_RV ec_add_public_attrs(const struct p11tool_objtype *keytype, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, void *private); static CK_RV dh_prepare(const struct p11tool_objtype *keytype, void **private); static void dh_cleanup(const struct p11tool_objtype *keytype, void *private); static CK_RV dh_get_key_size(const struct p11tool_objtype *keytype, void *private, CK_ULONG *keysize); static CK_RV dh_add_public_attrs(const struct p11tool_objtype *keytype, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, void *private); static CK_RV dh_add_private_attrs(const struct p11tool_objtype *keytype, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, void *private); static CK_RV dsa_prepare(const struct p11tool_objtype *keytype, void **private); static void dsa_cleanup(const struct p11tool_objtype *keytype, void *private); static CK_RV dsa_get_key_size(const struct p11tool_objtype *keytype, void *private, CK_ULONG *keysize); static CK_RV dsa_add_public_attrs(const struct p11tool_objtype *keytype, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, void *private); static CK_RV ibm_dilithium_add_public_attrs( const struct p11tool_objtype *keytype, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, void *private); static CK_RV ibm_kyber_add_public_attrs(const struct p11tool_objtype *keytype, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, void *private); static CK_RV ibm_ml_dsa_kem_add_public_attrs( const struct p11tool_objtype *keytype, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, void *private); static CK_RV ml_dsa_kem_add_public_attrs(const struct p11tool_objtype *keytype, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, void *private); static CK_RV p11sak_import_check_des_keysize( const struct p11tool_objtype *keytype, CK_ULONG keysize); static CK_RV p11sak_import_check_3des_keysize( const struct p11tool_objtype *keytype, CK_ULONG keysize); static CK_RV p11sak_import_check_generic_keysize( const struct p11tool_objtype *keytype, CK_ULONG keysize); static CK_RV p11sak_import_check_aes_keysize( const struct p11tool_objtype *keytype, CK_ULONG keysize); static CK_RV p11sak_import_check_aes_xts_keysize( const struct p11tool_objtype *keytype, CK_ULONG keysize); static CK_RV p11sak_import_sym_clear_des_3des_aes_generic( const struct p11tool_objtype *keytype, CK_BYTE *data, CK_ULONG data_len, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs); static CK_RV p11sak_import_rsa_pkey(const struct p11tool_objtype *keytype, EVP_PKEY *pkey, bool private, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs); static CK_RV p11sak_import_cert_attrs(const struct p11tool_objtype *certtype, X509 *x509, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs); static CK_RV p11sak_import_x509_attrs(const struct p11tool_objtype *certtype, X509 *x509, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs); static CK_RV p11sak_import_dh_pkey(const struct p11tool_objtype *keytype, EVP_PKEY *pkey, bool private, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs); static CK_RV p11sak_import_dsa_pkey(const struct p11tool_objtype *keytype, EVP_PKEY *pkey, bool private, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs); static CK_RV p11sak_import_ec_pkey(const struct p11tool_objtype *keytype, EVP_PKEY *pkey, bool private, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs); static CK_RV p11sak_import_dilithium_kyber_pem_data( const struct p11tool_objtype *keytype, unsigned char *data, size_t data_len, bool private, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs); static CK_RV p11sak_import_dilithium_ml_dsa_pkey(const struct p11tool_objtype *keytype, EVP_PKEY *pkey, bool private, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs); static CK_RV p11sak_import_ibm_ml_kem_pkey( const struct p11tool_objtype *keytype, EVP_PKEY *pkey, bool private, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs); static CK_RV p11sak_import_ml_dsa_pkey(const struct p11tool_objtype *keytype, EVP_PKEY *pkey, bool private, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs); static CK_RV p11sak_import_ml_kem_pkey(const struct p11tool_objtype *keytype, EVP_PKEY *pkey, bool private, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs); static CK_RV p11sak_export_sym_clear_des_3des_aes_generic( const struct p11tool_objtype *keytype, CK_BYTE **data, CK_ULONG* data_len, CK_OBJECT_HANDLE key, const char *label); static CK_RV p11sak_export_rsa_pkey(const struct p11tool_objtype *keytype, EVP_PKEY **pkey, bool private, CK_OBJECT_HANDLE key, const char *label); static CK_RV p11sak_export_dh_pkey(const struct p11tool_objtype *keytype, EVP_PKEY **pkey, bool private, CK_OBJECT_HANDLE key, const char *label); static CK_RV p11sak_export_dsa_pkey(const struct p11tool_objtype *keytype, EVP_PKEY **pkey, bool private, CK_OBJECT_HANDLE key, const char *label); static CK_RV p11sak_export_ec_pkey(const struct p11tool_objtype *keytype, EVP_PKEY **pkey, bool private, CK_OBJECT_HANDLE key, const char *label); static CK_RV p11sak_export_dilithium_kyber_pem_data( const struct p11tool_objtype *keytype, CK_BYTE **data, CK_ULONG *data_len, bool private, CK_OBJECT_HANDLE key, const char *label); static CK_RV p11sak_export_dilithium_ml_dsa_pkey(const struct p11tool_objtype *keytype, EVP_PKEY **pkey, bool private, CK_OBJECT_HANDLE key, const char *label); static CK_RV p11sak_export_ibm_ml_kem_pkey( const struct p11tool_objtype *keytype, EVP_PKEY **pkey, bool private, CK_OBJECT_HANDLE key, const char *label); static CK_RV p11sak_export_ml_dsa_pkey(const struct p11tool_objtype *keytype, EVP_PKEY **pkey, bool private, CK_OBJECT_HANDLE key, const char *label); static CK_RV p11sak_export_ml_kem_pkey(const struct p11tool_objtype *keytype, EVP_PKEY **pkey, bool private, CK_OBJECT_HANDLE key, const char *label); static CK_RV p11sak_export_x509(const struct p11tool_objtype *certtype, CK_BYTE **data, CK_ULONG *data_len, CK_OBJECT_HANDLE cert, const char *label); static CK_RV p11sak_extract_x509_pk(const struct p11tool_objtype *certtype, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, CK_OBJECT_HANDLE cert, const char* label); static void print_attr_array_attr(const char *attr, const CK_ATTRIBUTE *val, int indent, bool sensitive); static void print_key_type_attr(const char *attr, const CK_ATTRIBUTE *val, int indent, bool sensitive); static void print_cert_type_attr(const char *attr, const CK_ATTRIBUTE *val, int indent, bool sensitive); static void p11sak_print_mkvp_cca_short(const struct p11tool_token_info *info, const CK_BYTE *secure_key, CK_ULONG secure_key_len, const char *separator); static void p11sak_print_mkvp_cca_long(const struct p11tool_token_info *info, const CK_BYTE *secure_key, CK_ULONG secure_key_len, int indent); static void p11sak_print_mkvp_ep11_short(const struct p11tool_token_info *info, const CK_BYTE *secure_key, CK_ULONG secure_key_len, const char *separator); static void p11sak_print_mkvp_ep11_long(const struct p11tool_token_info *info, const CK_BYTE *secure_key, CK_ULONG secure_key_len, int indent); static void p11sak_print_session_id_ep11_short( const struct p11tool_token_info *info, const CK_BYTE *secure_key, CK_ULONG secure_key_len); static void p11sak_print_session_id_ep11_long( const struct p11tool_token_info *info, const CK_BYTE *secure_key, CK_ULONG secure_key_len, int indent); #define DECLARE_CERT_ATTRS \ { .name = "CKA_LABEL", .type = CKA_LABEL, \ .secret = true, .public = true, .private = true, .settable = true, \ .print_long = p11tool_print_utf8_attr, }, \ { .name = "CKA_CLASS", .type = CKA_CLASS, \ .secret = true, .public = true, .private = true, .settable = false, \ .print_long = p11tool_print_class_attr, }, \ { .name = "CKA_CERTIFICATE_TYPE", .type = CKA_CERTIFICATE_TYPE, \ .secret = true, .public = true, .private = true, .settable = false, \ .print_long = print_cert_type_attr, }, \ { .name = "CKA_CERTIFICATE_CATEGORY", .type = CKA_CERTIFICATE_CATEGORY, \ .secret = true, .public = true, .private = true, .settable = false, \ .print_long = p11tool_print_cert_category_attr, }, \ { .name = "CKA_CHECK_VALUE", .type = CKA_CHECK_VALUE, \ .secret = true, .public = true, .private = true, .settable = true, \ .print_long = p11tool_print_byte_array_attr, }, \ { .name = "CKA_START_DATE", .type = CKA_START_DATE, \ .secret = true, .public = true, .private = true, .settable = true, \ .print_long = p11tool_print_date_attr, }, \ { .name = "CKA_END_DATE", .type = CKA_END_DATE, \ .secret = true, .public = true, .private = true, .settable = true, \ .print_long = p11tool_print_date_attr, }, \ { .name = "CKA_PUBLIC_KEY_INFO", .type = CKA_PUBLIC_KEY_INFO, \ .secret = true, .public = true, .private = true, .settable = true, \ .print_long = p11tool_print_byte_array_attr, } static const struct p11tool_attr p11sak_x509_attrs[] = { DECLARE_CERT_ATTRS, { .name = "CKA_SUBJECT", .type = CKA_SUBJECT, .secret = true, .public = true, .private = true, .settable = true, .print_long = p11tool_print_x509_name_attr, }, { .name = "CKA_ID", .type = CKA_ID, .secret = true, .public = true, .private = true, .settable = true, .print_long = p11tool_print_byte_array_attr, }, { .name = "CKA_ISSUER", .type = CKA_ISSUER, .secret = true, .public = true, .private = true, .settable = true, .print_long = p11tool_print_x509_name_attr, }, { .name = "CKA_SERIAL_NUMBER", .type = CKA_SERIAL_NUMBER, .secret = true, .public = false, .private = false, .settable = true, .print_long = p11tool_print_x509_serial_number_attr, }, { .name = "CKA_VALUE", .type = CKA_VALUE, .secret = true, .public = false, .private = false, .settable = true, .print_long = p11tool_print_x509_attr, }, { .name = "CKA_NAME_HASH_ALGORITHM", .type = CKA_NAME_HASH_ALGORITHM, .secret = true, .public = false, .private = false, .settable = true, .print_long = p11tool_print_mech_attr, }, { .name = "CKA_HASH_OF_SUBJECT_PUBLIC_KEY", .type = CKA_HASH_OF_SUBJECT_PUBLIC_KEY, .secret = true, .public = false, .private = false, .settable = true, .print_long = p11tool_print_byte_array_attr, }, { .name = "CKA_HASH_OF_ISSUER_PUBLIC_KEY", .type = CKA_HASH_OF_ISSUER_PUBLIC_KEY, .secret = true, .public = false, .private = false, .settable = true, .print_long = p11tool_print_byte_array_attr, }, { .name = "CKA_URL", .type = CKA_URL, .secret = true, .public = false, .private = false, .settable = true, .print_long = p11tool_print_utf8_attr, }, { .name = "CKA_JAVA_MIDP_SECURITY_DOMAIN", .type = CKA_JAVA_MIDP_SECURITY_DOMAIN, .secret = true, .public = false, .private = false, .settable = true, .print_long = p11tool_print_java_midp_secdom_attr, }, { .name = NULL }, }; #define DECLARE_KEY_ATTRS \ { .name = "CKA_LABEL", .type = CKA_LABEL, \ .secret = true, .public = true, .private = true, .settable = true, \ .print_long = p11tool_print_utf8_attr, }, \ { .name = "CKA_CLASS", .type = CKA_CLASS, \ .secret = true, .public = true, .private = true, .settable = false, \ .print_long = p11tool_print_class_attr, }, \ { .name = "CKA_KEY_TYPE", .type = CKA_KEY_TYPE, \ .secret = true, .public = true, .private = true, .settable = false, \ .print_long = print_key_type_attr, }, \ { .name = "CKA_ID", .type = CKA_ID, \ .secret = true, .public = true, .private = true, .settable = true, \ .print_long = p11tool_print_byte_array_attr, }, \ { .name = "CKA_START_DATE", .type = CKA_START_DATE, \ .secret = true, .public = true, .private = true, .settable = true, \ .print_long = p11tool_print_date_attr, }, \ { .name = "CKA_END_DATE", .type = CKA_END_DATE, \ .secret = true, .public = true, .private = true, .settable = true, \ .print_long = p11tool_print_date_attr, }, \ { .name = "CKA_KEY_GEN_MECHANISM", .type = CKA_KEY_GEN_MECHANISM, \ .secret = true, .public = true, .private = true, .settable = true, \ .print_long = p11tool_print_mech_attr, }, \ { .name = "CKA_ALLOWED_MECHANISMS", .type = CKA_ALLOWED_MECHANISMS, \ .secret = true, .public = true, .private = true, .settable = true, \ .print_long = p11tool_print_mech_array_attr, } #define DECLARE_SECRET_KEY_ATTRS \ { .name = "CKA_CHECK_VALUE", .type = CKA_CHECK_VALUE, \ .secret = true, .public = false, .private = false, .settable = true, \ .print_long = p11tool_print_byte_array_attr, }, \ { .name = "CKA_WRAP_TEMPLATE", .type = CKA_WRAP_TEMPLATE, \ .secret = true, .public = true, .private = false, .settable = true, \ .print_long = print_attr_array_attr, }, \ { .name = "CKA_UNWRAP_TEMPLATE", .type = CKA_UNWRAP_TEMPLATE, \ .secret = true, .public = false, .private = true, .settable = true, \ .print_long = print_attr_array_attr, }, \ { .name = "CKA_DERIVE_TEMPLATE", .type = CKA_DERIVE_TEMPLATE, \ .secret = true, .public = false, .private = true, .settable = true, \ .print_long = print_attr_array_attr, } #define DECLARE_PUBLIC_KEY_ATTRS \ { .name = "CKA_SUBJECT", .type = CKA_SUBJECT, \ .secret = true, .public = false, .private = true, .settable = true, \ .print_long = p11tool_print_x509_name_attr, }, \ { .name = "CKA_WRAP_TEMPLATE", .type = CKA_WRAP_TEMPLATE, \ .secret = true, .public = true, .private = false, .settable = true, \ .print_long = print_attr_array_attr, }, \ { .name = "CKA_PUBLIC_KEY_INFO", .type = CKA_PUBLIC_KEY_INFO, \ .secret = false, .public = true, .private = true, .settable = true, \ .print_long = p11tool_print_byte_array_attr, }, \ { .name = "CKA_ENCAPSULATE_TEMPLATE", .type = CKA_ENCAPSULATE_TEMPLATE, \ .secret = false, .public = true, .private = false, .settable = true, \ .print_long = print_attr_array_attr, } #define DECLARE_PRIVATE_KEY_ATTRS \ { .name = "CKA_SUBJECT", .type = CKA_SUBJECT, \ .secret = true, .public = false, .private = true, .settable = true, \ .print_long = p11tool_print_x509_name_attr, }, \ { .name = "CKA_UNWRAP_TEMPLATE", .type = CKA_UNWRAP_TEMPLATE, \ .secret = true, .public = false, .private = true, .settable = true, \ .print_long = print_attr_array_attr, }, \ { .name = "CKA_PUBLIC_KEY_INFO", .type = CKA_PUBLIC_KEY_INFO, \ .secret = false, .public = true, .private = true, .settable = true, \ .print_long = p11tool_print_byte_array_attr, }, \ { .name = "CKA_DERIVE_TEMPLATE", .type = CKA_DERIVE_TEMPLATE, \ .secret = true, .public = false, .private = true, .settable = true, \ .print_long = print_attr_array_attr, }, \ { .name = "CKA_DECAPSULATE_TEMPLATE", .type = CKA_DECAPSULATE_TEMPLATE, \ .secret = false, .public = false, .private = true, .settable = true, \ .print_long = print_attr_array_attr, } static const struct p11tool_attr p11sak_des_attrs[] = { DECLARE_KEY_ATTRS, DECLARE_SECRET_KEY_ATTRS, { .name = "CKA_VALUE", .type = CKA_VALUE, .secret = true, .public = false, .private = false, .settable = true, .print_long = p11tool_print_byte_array_attr, }, { .name = NULL }, }; static const struct p11tool_attr p11sak_3des_attrs[] = { DECLARE_KEY_ATTRS, DECLARE_SECRET_KEY_ATTRS, { .name = "CKA_VALUE", .type = CKA_VALUE, .secret = true, .public = false, .private = false, .settable = true, .print_long = p11tool_print_byte_array_attr, }, { .name = NULL }, }; static const struct p11tool_attr p11sak_generic_attrs[] = { DECLARE_KEY_ATTRS, DECLARE_SECRET_KEY_ATTRS, { .name = "CKA_VALUE", .type = CKA_VALUE, .secret = true, .public = false, .private = false, .settable = true, .print_long = p11tool_print_byte_array_attr, }, { .name = "CKA_VALUE_LEN", .type = CKA_VALUE_LEN, .secret = true, .public = false, .private = false, .settable = true, .print_long = p11tool_print_ulong_attr, }, { .name = NULL }, }; static const struct p11tool_attr p11sak_aes_attrs[] = { DECLARE_KEY_ATTRS, DECLARE_SECRET_KEY_ATTRS, { .name = "CKA_VALUE", .type = CKA_VALUE, .secret = true, .public = false, .private = false, .settable = true, .print_long = p11tool_print_byte_array_attr, }, { .name = "CKA_VALUE_LEN", .type = CKA_VALUE_LEN, .secret = true, .public = false, .private = false, .settable = true, .print_long = p11tool_print_ulong_attr, }, { .name = NULL }, }; #define DECLARE_PUBLIC_RSA_ATTRS \ { .name = "CKA_MODULUS", .type = CKA_MODULUS, \ .secret = false, .public = true, .private = true, .settable = true, \ .print_long = p11tool_print_byte_array_attr, }, \ { .name = "CKA_MODULUS_BITS", .type = CKA_MODULUS_BITS, \ .secret = false, .public = true, .private = true, .settable = true, \ .print_long = p11tool_print_ulong_attr, }, \ { .name = "CKA_PUBLIC_EXPONENT", .type = CKA_PUBLIC_EXPONENT, \ .secret = false, .public = true, .private = true, .settable = true, \ .print_long = p11tool_print_byte_array_attr, } static const struct p11tool_attr p11sak_public_rsa_attrs[] = { DECLARE_KEY_ATTRS, DECLARE_PUBLIC_KEY_ATTRS, DECLARE_PUBLIC_RSA_ATTRS, { .name = NULL }, }; static const struct p11tool_attr p11sak_private_rsa_attrs[] = { DECLARE_KEY_ATTRS, DECLARE_PRIVATE_KEY_ATTRS, DECLARE_PUBLIC_RSA_ATTRS, { .name = "CKA_PRIVATE_EXPONENT", .type = CKA_PRIVATE_EXPONENT, .secret = false, .public = false, .private = true, .settable = true, .print_long = p11tool_print_byte_array_attr, }, { .name = "CKA_PRIME_1", .type = CKA_PRIME_1, .secret = false, .public = false, .private = true, .settable = true, .print_long = p11tool_print_byte_array_attr, }, { .name = "CKA_PRIME_2", .type = CKA_PRIME_2, .secret = false, .public = false, .private = true, .settable = true, .print_long = p11tool_print_byte_array_attr, }, { .name = "CKA_EXPONENT_1", .type = CKA_EXPONENT_1, .secret = false, .public = false, .private = true, .settable = true, .print_long = p11tool_print_byte_array_attr, }, { .name = "CKA_EXPONENT_2", .type = CKA_EXPONENT_2, .secret = false, .public = false, .private = true, .settable = true, .print_long = p11tool_print_byte_array_attr, }, { .name = "CKA_COEFFICIENT", .type = CKA_COEFFICIENT, .secret = false, .public = false, .private = true, .settable = true, .print_long = p11tool_print_byte_array_attr, }, { .name = NULL }, }; #define DECLARE_DH_ATTRS \ { .name = "CKA_PRIME", .type = CKA_PRIME, \ .secret = false, .public = true, .private = true, .settable = true, \ .print_long = p11tool_print_byte_array_attr, }, \ { .name = "CKA_BASE", .type = CKA_BASE, \ .secret = false, .public = true, .private = true, .settable = true, \ .print_long = p11tool_print_byte_array_attr, }, \ { .name = "CKA_VALUE", .type = CKA_VALUE, \ .secret = false, .public = true, .private = true, .settable = true, \ .print_long = p11tool_print_byte_array_attr, } static const struct p11tool_attr p11sak_public_dh_attrs[] = { DECLARE_KEY_ATTRS, DECLARE_PUBLIC_KEY_ATTRS, DECLARE_DH_ATTRS, { .name = NULL }, }; static const struct p11tool_attr p11sak_private_dh_attrs[] = { DECLARE_KEY_ATTRS, DECLARE_PRIVATE_KEY_ATTRS, DECLARE_DH_ATTRS, { .name = "CKA_VALUE_BITS", .type = CKA_VALUE_BITS, .secret = false, .public = false, .private = true, .settable = true, .print_long = p11tool_print_ulong_attr, }, { .name = NULL }, }; #define DECLARE_DSA_ATTRS \ { .name = "CKA_PRIME", .type = CKA_PRIME, \ .secret = false, .public = true, .private = true, .settable = true, \ .print_long = p11tool_print_byte_array_attr, }, \ { .name = "CKA_SUBPRIME", .type = CKA_SUBPRIME, \ .secret = false, .public = true, .private = true, .settable = true, \ .print_long = p11tool_print_byte_array_attr, }, \ { .name = "CKA_BASE", .type = CKA_BASE, \ .secret = false, .public = true, .private = true, .settable = true, \ .print_long = p11tool_print_byte_array_attr, }, \ { .name = "CKA_VALUE", .type = CKA_VALUE, \ .secret = false, .public = true, .private = true, .settable = true, \ .print_long = p11tool_print_byte_array_attr, } static const struct p11tool_attr p11sak_public_dsa_attrs[] = { DECLARE_KEY_ATTRS, DECLARE_PUBLIC_KEY_ATTRS, DECLARE_DSA_ATTRS, { .name = NULL }, }; static const struct p11tool_attr p11sak_private_dsa_attrs[] = { DECLARE_KEY_ATTRS, DECLARE_PRIVATE_KEY_ATTRS, DECLARE_DSA_ATTRS, { .name = NULL }, }; #define DECLARE_EC_ATTRS \ { .name = "CKA_EC_PARAMS", .type = CKA_EC_PARAMS, \ .secret = false, .public = true, .private = true, .settable = true, \ .print_long = p11tool_print_oid_attr, } static const struct p11tool_attr p11sak_public_ec_attrs[] = { DECLARE_KEY_ATTRS, DECLARE_PUBLIC_KEY_ATTRS, DECLARE_EC_ATTRS, { .name = "CKA_EC_POINT", .type = CKA_EC_POINT, .secret = false, .public = true, .private = false, .settable = true, .print_long = p11tool_print_byte_array_attr, }, { .name = NULL }, }; static const struct p11tool_attr p11sak_private_ec_attrs[] = { DECLARE_KEY_ATTRS, DECLARE_PRIVATE_KEY_ATTRS, DECLARE_EC_ATTRS, { .name = "CKA_VALUE", .type = CKA_VALUE, .secret = false, .public = false, .private = true, .settable = true, .print_long = p11tool_print_byte_array_attr, }, { .name = NULL }, }; #define DECLARE_PUBLIC_IBM_DILITHIUM_ATTRS \ { .name = "CKA_IBM_DILITHIUM_KEYFORM", .type = CKA_IBM_DILITHIUM_KEYFORM, \ .secret = false, .public = true, .private = true, .settable = true, \ .print_long = p11tool_print_ibm_dilithium_keyform_attr, }, \ { .name = "CKA_IBM_DILITHIUM_MODE", .type = CKA_IBM_DILITHIUM_MODE, \ .secret = false, .public = true, .private = true, .settable = true, \ .print_long = p11tool_print_oid_attr, }, \ { .name = "CKA_IBM_DILITHIUM_RHO", .type = CKA_IBM_DILITHIUM_RHO, \ .secret = false, .public = true, .private = true, .settable = true, \ .print_long = p11tool_print_byte_array_attr, }, \ { .name = "CKA_IBM_DILITHIUM_T1", .type = CKA_IBM_DILITHIUM_T1, \ .secret = false, .public = true, .private = true, .settable = true, \ .print_long = p11tool_print_byte_array_attr, } static const struct p11tool_attr p11sak_public_ibm_dilithium_attrs[] = { DECLARE_KEY_ATTRS, DECLARE_PUBLIC_KEY_ATTRS, DECLARE_PUBLIC_IBM_DILITHIUM_ATTRS, { .name = "CKA_VALUE", .type = CKA_VALUE, .secret = false, .public = true, .private = false, .settable = true, .print_long = p11tool_print_byte_array_attr, }, { .name = NULL }, }; static const struct p11tool_attr p11sak_private_ibm_dilithium_attrs[] = { DECLARE_KEY_ATTRS, DECLARE_PRIVATE_KEY_ATTRS, DECLARE_PUBLIC_IBM_DILITHIUM_ATTRS, { .name = "CKA_VALUE", .type = CKA_VALUE, .secret = false, .public = false, .private = true, .settable = true, .print_long = p11tool_print_byte_array_attr, }, { .name = "CKA_IBM_DILITHIUM_SEED", .type = CKA_IBM_DILITHIUM_SEED, .secret = false, .public = false, .private = true, .settable = true, .print_long = p11tool_print_byte_array_attr, }, { .name = "CKA_IBM_DILITHIUM_TR", .type = CKA_IBM_DILITHIUM_TR, .secret = false, .public = false, .private = true, .settable = true, .print_long = p11tool_print_byte_array_attr, }, { .name = "CKA_IBM_DILITHIUM_S1", .type = CKA_IBM_DILITHIUM_S1, .secret = false, .public = false, .private = true, .settable = true, .print_long = p11tool_print_byte_array_attr, }, { .name = "CKA_IBM_DILITHIUM_S2", .type = CKA_IBM_DILITHIUM_S2, .secret = false, .public = false, .private = true, .settable = true, .print_long = p11tool_print_byte_array_attr, }, { .name = "CKA_IBM_DILITHIUM_T0", .type = CKA_IBM_DILITHIUM_T0, .secret = false, .public = false, .private = true, .settable = true, .print_long = p11tool_print_byte_array_attr, }, { .name = NULL }, }; #define DECLARE_PUBLIC_IBM_KYBER_ATTRS \ { .name = "CKA_IBM_KYBER_KEYFORM", .type = CKA_IBM_KYBER_KEYFORM, \ .secret = false, .public = true, .private = true, .settable = true, \ .print_long = p11tool_print_ibm_kyber_keyform_attr, }, \ { .name = "CKA_IBM_KYBER_MODE", .type = CKA_IBM_KYBER_MODE, \ .secret = false, .public = true, .private = true, .settable = true, \ .print_long = p11tool_print_oid_attr, }, \ { .name = "CKA_IBM_KYBER_PK", .type = CKA_IBM_KYBER_PK, \ .secret = false, .public = true, .private = true, .settable = true, \ .print_long = p11tool_print_byte_array_attr, } static const struct p11tool_attr p11sak_public_ibm_kyber_attrs[] = { DECLARE_KEY_ATTRS, DECLARE_PUBLIC_KEY_ATTRS, DECLARE_PUBLIC_IBM_KYBER_ATTRS, { .name = "CKA_VALUE", .type = CKA_VALUE, .secret = false, .public = true, .private = false, .settable = true, .print_long = p11tool_print_byte_array_attr, }, { .name = NULL }, }; static const struct p11tool_attr p11sak_private_ibm_kyber_attrs[] = { DECLARE_KEY_ATTRS, DECLARE_PRIVATE_KEY_ATTRS, DECLARE_PUBLIC_IBM_KYBER_ATTRS, { .name = "CKA_VALUE", .type = CKA_VALUE, .secret = false, .public = false, .private = true, .settable = true, .print_long = p11tool_print_byte_array_attr, }, { .name = "CKA_IBM_KYBER_SK", .type = CKA_IBM_KYBER_SK, .secret = false, .public = false, .private = true, .settable = true, .print_long = p11tool_print_byte_array_attr, }, { .name = NULL }, }; #define DECLARE_PUBLIC_PRIVATE_IBM_ML_DSA_ATTRS \ { .name = "CKA_IBM_PARAMETER_SET", .type = CKA_IBM_PARAMETER_SET, \ .secret = false, .public = true, .private = true, .settable = true, \ .print_long = p11tool_print_ibm_ml_dsa_parameter_set_attr, }, \ { .name = "CKA_IBM_ML_DSA_RHO", .type = CKA_IBM_ML_DSA_RHO, \ .secret = false, .public = true, .private = true, .settable = true, \ .print_long = p11tool_print_byte_array_attr, }, \ { .name = "CKA_IBM_ML_DSA_T1", .type = CKA_IBM_ML_DSA_T1, \ .secret = false, .public = true, .private = true, .settable = true, \ .print_long = p11tool_print_byte_array_attr, } static const struct p11tool_attr p11sak_public_ibm_ml_dsa_attrs[] = { DECLARE_KEY_ATTRS, DECLARE_PUBLIC_KEY_ATTRS, DECLARE_PUBLIC_PRIVATE_IBM_ML_DSA_ATTRS, { .name = "CKA_VALUE", .type = CKA_VALUE, .secret = false, .public = true, .private = false, .settable = true, .print_long = p11tool_print_byte_array_attr, }, { .name = NULL }, }; static const struct p11tool_attr p11sak_private_ibm_ml_dsa_attrs[] = { DECLARE_KEY_ATTRS, DECLARE_PRIVATE_KEY_ATTRS, DECLARE_PUBLIC_PRIVATE_IBM_ML_DSA_ATTRS, { .name = "CKA_VALUE", .type = CKA_VALUE, .secret = false, .public = false, .private = true, .settable = true, .print_long = p11tool_print_byte_array_attr, }, { .name = "CKA_IBM_ML_DSA_SEED", .type = CKA_IBM_ML_DSA_SEED, .secret = false, .public = false, .private = true, .settable = true, .print_long = p11tool_print_byte_array_attr, }, { .name = "CKA_IBM_ML_DSA_TR", .type = CKA_IBM_ML_DSA_TR, .secret = false, .public = false, .private = true, .settable = true, .print_long = p11tool_print_byte_array_attr, }, { .name = "CKA_IBM_ML_DSA_S1", .type = CKA_IBM_ML_DSA_S1, .secret = false, .public = false, .private = true, .settable = true, .print_long = p11tool_print_byte_array_attr, }, { .name = "CKA_IBM_ML_DSA_S2", .type = CKA_IBM_ML_DSA_S2, .secret = false, .public = false, .private = true, .settable = true, .print_long = p11tool_print_byte_array_attr, }, { .name = "CKA_IBM_ML_DSA_T0", .type = CKA_IBM_ML_DSA_T0, .secret = false, .public = false, .private = true, .settable = true, .print_long = p11tool_print_byte_array_attr, }, { .name = "CKA_IBM_ML_DSA_PRIVATE_SEED", .type = CKA_IBM_ML_DSA_PRIVATE_SEED, .secret = false, .public = false, .private = true, .settable = true, .print_long = p11tool_print_byte_array_attr, }, { .name = NULL }, }; #define DECLARE_PUBLIC_PRIVATE_IBM_ML_KEM_ATTRS \ { .name = "CKA_IBM_PARAMETER_SET", .type = CKA_IBM_PARAMETER_SET, \ .secret = false, .public = true, .private = true, .settable = true, \ .print_long = p11tool_print_ibm_ml_kem_parameter_set_attr, }, \ { .name = "CKA_IBM_ML_KEM_PK", .type = CKA_IBM_ML_KEM_PK, \ .secret = false, .public = true, .private = true, .settable = true, \ .print_long = p11tool_print_byte_array_attr, } static const struct p11tool_attr p11sak_public_ibm_ml_kem_attrs[] = { DECLARE_KEY_ATTRS, DECLARE_PUBLIC_KEY_ATTRS, DECLARE_PUBLIC_PRIVATE_IBM_ML_KEM_ATTRS, { .name = "CKA_VALUE", .type = CKA_VALUE, .secret = false, .public = true, .private = false, .settable = true, .print_long = p11tool_print_byte_array_attr, }, { .name = NULL }, }; static const struct p11tool_attr p11sak_private_ibm_ml_kem_attrs[] = { DECLARE_KEY_ATTRS, DECLARE_PRIVATE_KEY_ATTRS, DECLARE_PUBLIC_PRIVATE_IBM_ML_KEM_ATTRS, { .name = "CKA_VALUE", .type = CKA_VALUE, .secret = false, .public = false, .private = true, .settable = true, .print_long = p11tool_print_byte_array_attr, }, { .name = "CKA_IBM_ML_KEM_SK", .type = CKA_IBM_ML_KEM_SK, .secret = false, .public = false, .private = true, .settable = true, .print_long = p11tool_print_byte_array_attr, }, { .name = "CKA_IBM_ML_KEM_PRIVATE_SEED", .type = CKA_IBM_ML_KEM_PRIVATE_SEED, .secret = false, .public = false, .private = true, .settable = true, .print_long = p11tool_print_byte_array_attr, }, { .name = NULL }, }; #define DECLARE_PUBLIC_PRIVATE_ML_DSA_ATTRS \ { .name = "CKA_PARAMETER_SET", .type = CKA_PARAMETER_SET, \ .secret = false, .public = true, .private = true, .settable = true, \ .print_long = p11tool_print_ibm_ml_dsa_parameter_set_attr, } static const struct p11tool_attr p11sak_public_ml_dsa_attrs[] = { DECLARE_KEY_ATTRS, DECLARE_PUBLIC_KEY_ATTRS, DECLARE_PUBLIC_PRIVATE_ML_DSA_ATTRS, { .name = "CKA_VALUE", .type = CKA_VALUE, .secret = false, .public = true, .private = false, .settable = true, .print_long = p11tool_print_byte_array_attr, }, { .name = NULL }, }; static const struct p11tool_attr p11sak_private_ml_dsa_attrs[] = { DECLARE_KEY_ATTRS, DECLARE_PRIVATE_KEY_ATTRS, DECLARE_PUBLIC_PRIVATE_ML_DSA_ATTRS, { .name = "CKA_VALUE", .type = CKA_VALUE, .secret = false, .public = false, .private = true, .settable = true, .print_long = p11tool_print_byte_array_attr, }, { .name = "CKA_SEED", .type = CKA_SEED, .secret = false, .public = false, .private = true, .settable = true, .print_long = p11tool_print_byte_array_attr, }, { .name = NULL }, }; #define DECLARE_PUBLIC_PRIVATE_ML_KEM_ATTRS \ { .name = "CKA_PARAMETER_SET", .type = CKA_PARAMETER_SET, \ .secret = false, .public = true, .private = true, .settable = true, \ .print_long = p11tool_print_ibm_ml_kem_parameter_set_attr, } static const struct p11tool_attr p11sak_public_ml_kem_attrs[] = { DECLARE_KEY_ATTRS, DECLARE_PUBLIC_KEY_ATTRS, DECLARE_PUBLIC_PRIVATE_ML_KEM_ATTRS, { .name = "CKA_VALUE", .type = CKA_VALUE, .secret = false, .public = true, .private = false, .settable = true, .print_long = p11tool_print_byte_array_attr, }, { .name = NULL }, }; static const struct p11tool_attr p11sak_private_ml_kem_attrs[] = { DECLARE_KEY_ATTRS, DECLARE_PRIVATE_KEY_ATTRS, DECLARE_PUBLIC_PRIVATE_ML_KEM_ATTRS, { .name = "CKA_VALUE", .type = CKA_VALUE, .secret = false, .public = false, .private = true, .settable = true, .print_long = p11tool_print_byte_array_attr, }, { .name = "CKA_SEED", .type = CKA_SEED, .secret = false, .public = false, .private = true, .settable = true, .print_long = p11tool_print_byte_array_attr, }, { .name = NULL }, }; static const struct p11tool_objtype p11sak_des_keytype = { .obj_typestr = "key", .obj_liststr = "Key", .name = "DES", .type = CKK_DES, .ck_name = "CKK_DES", .keygen_mech = { .mechanism = CKM_DES_KEY_GEN, }, .is_asymmetric = false, .sign_verify = true, .encrypt_decrypt = true, .wrap_unwrap = true, .derive = true, .encaps_decaps = false, .filter_attr = CKA_KEY_TYPE, .filter_value = CKK_DES, .keysize_attr = (CK_ATTRIBUTE_TYPE)-1, .secret_attrs = p11sak_des_attrs, .import_check_sym_keysize = p11sak_import_check_des_keysize, .import_sym_clear = p11sak_import_sym_clear_des_3des_aes_generic, .export_sym_clear = p11sak_export_sym_clear_des_3des_aes_generic, }; static const struct p11tool_objtype p11sak_3des_keytype = { .obj_typestr = "key", .obj_liststr = "Key", .name = "3DES", .type = CKK_DES3, .ck_name = "CKK_DES3", .keygen_mech = { .mechanism = CKM_DES3_KEY_GEN, }, .is_asymmetric = false, .sign_verify = true, .encrypt_decrypt = true, .wrap_unwrap = true, .derive = true, .encaps_decaps = false, .filter_attr = CKA_KEY_TYPE, .filter_value = CKK_DES3, .keysize_attr = (CK_ATTRIBUTE_TYPE)-1, .secret_attrs = p11sak_3des_attrs, .import_check_sym_keysize = p11sak_import_check_3des_keysize, .import_sym_clear = p11sak_import_sym_clear_des_3des_aes_generic, .export_sym_clear = p11sak_export_sym_clear_des_3des_aes_generic, }; static const struct p11tool_objtype p11sak_generic_keytype = { .obj_typestr = "key", .obj_liststr = "Key", .name = "GENERIC", .type = CKK_GENERIC_SECRET, .ck_name = "CKK_GENERIC_SECRET", .keygen_mech = { .mechanism = CKM_GENERIC_SECRET_KEY_GEN, }, .is_asymmetric = false, .keygen_get_key_size = generic_get_key_size, .keygen_add_secret_attrs = generic_add_secret_attrs, .sign_verify = true, .encrypt_decrypt = false, .wrap_unwrap = false, .derive = true, .encaps_decaps = false, .filter_attr = CKA_KEY_TYPE, .filter_value = CKK_GENERIC_SECRET, .keysize_attr = CKA_VALUE_LEN, .key_keysize_adjust = generic_keysize_adjust, .secret_attrs = p11sak_generic_attrs, .import_check_sym_keysize = p11sak_import_check_generic_keysize, .import_sym_clear = p11sak_import_sym_clear_des_3des_aes_generic, .export_sym_clear = p11sak_export_sym_clear_des_3des_aes_generic, }; static const struct p11tool_objtype p11sak_sha_1_hmac_keytype = { .obj_typestr = "key", .obj_liststr = "Key", .name = "SHA-1-HMAC", .type = CKK_SHA_1_HMAC, .ck_name = "CKK_SHA_1_HMAC", .keygen_mech = { .mechanism = CKM_SHA_1_KEY_GEN, }, .is_asymmetric = false, .keygen_get_key_size = generic_get_key_size, .keygen_add_secret_attrs = generic_add_secret_attrs, .sign_verify = true, .encrypt_decrypt = false, .wrap_unwrap = false, .derive = true, .encaps_decaps = false, .filter_attr = CKA_KEY_TYPE, .filter_value = CKK_SHA_1_HMAC, .keysize_attr = CKA_VALUE_LEN, .key_keysize_adjust = generic_keysize_adjust, .secret_attrs = p11sak_generic_attrs, .import_check_sym_keysize = p11sak_import_check_generic_keysize, .import_sym_clear = p11sak_import_sym_clear_des_3des_aes_generic, .export_sym_clear = p11sak_export_sym_clear_des_3des_aes_generic, }; static const struct p11tool_objtype p11sak_sha224_hmac_keytype = { .obj_typestr = "key", .obj_liststr = "Key", .name = "SHA224-HMAC", .type = CKK_SHA224_HMAC, .ck_name = "CKK_SHA224_HMAC", .keygen_mech = { .mechanism = CKM_SHA224_KEY_GEN, }, .is_asymmetric = false, .keygen_get_key_size = generic_get_key_size, .keygen_add_secret_attrs = generic_add_secret_attrs, .sign_verify = true, .encrypt_decrypt = false, .wrap_unwrap = false, .derive = true, .encaps_decaps = false, .filter_attr = CKA_KEY_TYPE, .filter_value = CKK_SHA224_HMAC, .keysize_attr = CKA_VALUE_LEN, .key_keysize_adjust = generic_keysize_adjust, .secret_attrs = p11sak_generic_attrs, .import_check_sym_keysize = p11sak_import_check_generic_keysize, .import_sym_clear = p11sak_import_sym_clear_des_3des_aes_generic, .export_sym_clear = p11sak_export_sym_clear_des_3des_aes_generic, }; static const struct p11tool_objtype p11sak_sha256_hmac_keytype = { .obj_typestr = "key", .obj_liststr = "Key", .name = "SHA256-HMAC", .type = CKK_SHA256_HMAC, .ck_name = "CKK_SHA256_HMAC", .keygen_mech = { .mechanism = CKM_SHA256_KEY_GEN, }, .is_asymmetric = false, .keygen_get_key_size = generic_get_key_size, .keygen_add_secret_attrs = generic_add_secret_attrs, .sign_verify = true, .encrypt_decrypt = false, .wrap_unwrap = false, .derive = true, .encaps_decaps = false, .filter_attr = CKA_KEY_TYPE, .filter_value = CKK_SHA256_HMAC, .keysize_attr = CKA_VALUE_LEN, .key_keysize_adjust = generic_keysize_adjust, .secret_attrs = p11sak_generic_attrs, .import_check_sym_keysize = p11sak_import_check_generic_keysize, .import_sym_clear = p11sak_import_sym_clear_des_3des_aes_generic, .export_sym_clear = p11sak_export_sym_clear_des_3des_aes_generic, }; static const struct p11tool_objtype p11sak_sha384_hmac_keytype = { .obj_typestr = "key", .obj_liststr = "Key", .name = "SHA384-HMAC", .type = CKK_SHA384_HMAC, .ck_name = "CKK_SHA384_HMAC", .keygen_mech = { .mechanism = CKM_SHA384_KEY_GEN, }, .is_asymmetric = false, .keygen_get_key_size = generic_get_key_size, .keygen_add_secret_attrs = generic_add_secret_attrs, .sign_verify = true, .encrypt_decrypt = false, .wrap_unwrap = false, .derive = true, .encaps_decaps = false, .filter_attr = CKA_KEY_TYPE, .filter_value = CKK_SHA384_HMAC, .keysize_attr = CKA_VALUE_LEN, .key_keysize_adjust = generic_keysize_adjust, .secret_attrs = p11sak_generic_attrs, .import_check_sym_keysize = p11sak_import_check_generic_keysize, .import_sym_clear = p11sak_import_sym_clear_des_3des_aes_generic, .export_sym_clear = p11sak_export_sym_clear_des_3des_aes_generic, }; static const struct p11tool_objtype p11sak_sha512_hmac_keytype = { .obj_typestr = "key", .obj_liststr = "Key", .name = "SHA512-HMAC", .type = CKK_SHA512_HMAC, .ck_name = "CKK_SHA512_HMAC", .keygen_mech = { .mechanism = CKM_SHA512_KEY_GEN, }, .is_asymmetric = false, .keygen_get_key_size = generic_get_key_size, .keygen_add_secret_attrs = generic_add_secret_attrs, .sign_verify = true, .encrypt_decrypt = false, .wrap_unwrap = false, .derive = true, .encaps_decaps = false, .filter_attr = CKA_KEY_TYPE, .filter_value = CKK_SHA512_HMAC, .keysize_attr = CKA_VALUE_LEN, .key_keysize_adjust = generic_keysize_adjust, .secret_attrs = p11sak_generic_attrs, .import_check_sym_keysize = p11sak_import_check_generic_keysize, .import_sym_clear = p11sak_import_sym_clear_des_3des_aes_generic, .export_sym_clear = p11sak_export_sym_clear_des_3des_aes_generic, }; static const struct p11tool_objtype p11sak_sha512_224_hmac_keytype = { .obj_typestr = "key", .obj_liststr = "Key", .name = "SHA512/224-HMAC", .type = CKK_SHA512_224_HMAC, .ck_name = "CKK_SHA512_224_HMAC", .keygen_mech = { .mechanism = CKM_SHA512_224_KEY_GEN, }, .is_asymmetric = false, .keygen_get_key_size = generic_get_key_size, .keygen_add_secret_attrs = generic_add_secret_attrs, .sign_verify = true, .encrypt_decrypt = false, .wrap_unwrap = false, .derive = true, .encaps_decaps = false, .filter_attr = CKA_KEY_TYPE, .filter_value = CKK_SHA512_224_HMAC, .keysize_attr = CKA_VALUE_LEN, .key_keysize_adjust = generic_keysize_adjust, .secret_attrs = p11sak_generic_attrs, .import_check_sym_keysize = p11sak_import_check_generic_keysize, .import_sym_clear = p11sak_import_sym_clear_des_3des_aes_generic, .export_sym_clear = p11sak_export_sym_clear_des_3des_aes_generic, }; static const struct p11tool_objtype p11sak_sha512_256_hmac_keytype = { .obj_typestr = "key", .obj_liststr = "Key", .name = "SHA512/256-HMAC", .type = CKK_SHA512_256_HMAC, .ck_name = "CKK_SHA512_256_HMAC", .keygen_mech = { .mechanism = CKM_SHA512_256_KEY_GEN, }, .is_asymmetric = false, .keygen_get_key_size = generic_get_key_size, .keygen_add_secret_attrs = generic_add_secret_attrs, .sign_verify = true, .encrypt_decrypt = false, .wrap_unwrap = false, .derive = true, .encaps_decaps = false, .filter_attr = CKA_KEY_TYPE, .filter_value = CKK_SHA512_256_HMAC, .keysize_attr = CKA_VALUE_LEN, .key_keysize_adjust = generic_keysize_adjust, .secret_attrs = p11sak_generic_attrs, .import_check_sym_keysize = p11sak_import_check_generic_keysize, .import_sym_clear = p11sak_import_sym_clear_des_3des_aes_generic, .export_sym_clear = p11sak_export_sym_clear_des_3des_aes_generic, }; static const struct p11tool_objtype p11sak_sha3_224_hmac_keytype = { .obj_typestr = "key", .obj_liststr = "Key", .name = "SHA3-224-HMAC", .type = CKK_SHA3_224_HMAC, .ck_name = "CKK_SHA3_224_HMAC", .keygen_mech = { .mechanism = CKM_SHA3_224_KEY_GEN, }, .is_asymmetric = false, .keygen_get_key_size = generic_get_key_size, .keygen_add_secret_attrs = generic_add_secret_attrs, .sign_verify = true, .encrypt_decrypt = false, .wrap_unwrap = false, .derive = true, .encaps_decaps = false, .filter_attr = CKA_KEY_TYPE, .filter_value = CKK_SHA3_224_HMAC, .keysize_attr = CKA_VALUE_LEN, .key_keysize_adjust = generic_keysize_adjust, .secret_attrs = p11sak_generic_attrs, .import_check_sym_keysize = p11sak_import_check_generic_keysize, .import_sym_clear = p11sak_import_sym_clear_des_3des_aes_generic, .export_sym_clear = p11sak_export_sym_clear_des_3des_aes_generic, }; static const struct p11tool_objtype p11sak_sha3_256_hmac_keytype = { .obj_typestr = "key", .obj_liststr = "Key", .name = "SHA3-256-HMAC", .type = CKK_SHA3_256_HMAC, .ck_name = "CKK_SHA3_256_HMAC", .keygen_mech = { .mechanism = CKM_SHA3_256_KEY_GEN, }, .is_asymmetric = false, .keygen_get_key_size = generic_get_key_size, .keygen_add_secret_attrs = generic_add_secret_attrs, .sign_verify = true, .encrypt_decrypt = false, .wrap_unwrap = false, .derive = true, .encaps_decaps = false, .filter_attr = CKA_KEY_TYPE, .filter_value = CKK_SHA3_256_HMAC, .keysize_attr = CKA_VALUE_LEN, .key_keysize_adjust = generic_keysize_adjust, .secret_attrs = p11sak_generic_attrs, .import_check_sym_keysize = p11sak_import_check_generic_keysize, .import_sym_clear = p11sak_import_sym_clear_des_3des_aes_generic, .export_sym_clear = p11sak_export_sym_clear_des_3des_aes_generic, }; static const struct p11tool_objtype p11sak_sha3_384_hmac_keytype = { .obj_typestr = "key", .obj_liststr = "Key", .name = "SHA3-384-HMAC", .type = CKK_SHA3_384_HMAC, .ck_name = "CKK_SHA3_384_HMAC", .keygen_mech = { .mechanism = CKM_SHA3_384_KEY_GEN, }, .is_asymmetric = false, .keygen_get_key_size = generic_get_key_size, .keygen_add_secret_attrs = generic_add_secret_attrs, .sign_verify = true, .encrypt_decrypt = false, .wrap_unwrap = false, .derive = true, .encaps_decaps = false, .filter_attr = CKA_KEY_TYPE, .filter_value = CKK_SHA3_384_HMAC, .keysize_attr = CKA_VALUE_LEN, .key_keysize_adjust = generic_keysize_adjust, .secret_attrs = p11sak_generic_attrs, .import_check_sym_keysize = p11sak_import_check_generic_keysize, .import_sym_clear = p11sak_import_sym_clear_des_3des_aes_generic, .export_sym_clear = p11sak_export_sym_clear_des_3des_aes_generic, }; static const struct p11tool_objtype p11sak_sha3_512_hmac_keytype = { .obj_typestr = "key", .obj_liststr = "Key", .name = "SHA3-512-HMAC", .type = CKK_SHA3_512_HMAC, .ck_name = "CKK_SHA3_512_HMAC", .keygen_mech = { .mechanism = CKM_SHA3_512_KEY_GEN, }, .is_asymmetric = false, .keygen_get_key_size = generic_get_key_size, .keygen_add_secret_attrs = generic_add_secret_attrs, .sign_verify = true, .encrypt_decrypt = false, .wrap_unwrap = false, .derive = true, .encaps_decaps = false, .filter_attr = CKA_KEY_TYPE, .filter_value = CKK_SHA3_512_HMAC, .keysize_attr = CKA_VALUE_LEN, .key_keysize_adjust = generic_keysize_adjust, .secret_attrs = p11sak_generic_attrs, .import_check_sym_keysize = p11sak_import_check_generic_keysize, .import_sym_clear = p11sak_import_sym_clear_des_3des_aes_generic, .export_sym_clear = p11sak_export_sym_clear_des_3des_aes_generic, }; static const struct p11tool_objtype p11sak_aes_keytype = { .obj_typestr = "key", .obj_liststr = "Key", .name = "AES", .type = CKK_AES, .ck_name = "CKK_AES", .keygen_mech = { .mechanism = CKM_AES_KEY_GEN, }, .is_asymmetric = false, .keygen_get_key_size = aes_get_key_size, .keygen_add_secret_attrs = aes_add_secret_attrs, .sign_verify = true, .encrypt_decrypt = true, .wrap_unwrap = true, .derive = true, .encaps_decaps = false, .filter_attr = CKA_KEY_TYPE, .filter_value = CKK_AES, .keysize_attr = CKA_VALUE_LEN, .key_keysize_adjust = aes_keysize_adjust, .secret_attrs = p11sak_aes_attrs, .import_check_sym_keysize = p11sak_import_check_aes_keysize, .import_sym_clear = p11sak_import_sym_clear_des_3des_aes_generic, .export_sym_clear = p11sak_export_sym_clear_des_3des_aes_generic, }; static const struct p11tool_objtype p11sak_aes_xts_keytype = { .obj_typestr = "key", .obj_liststr = "Key", .name = "AES-XTS", .type = CKK_AES_XTS, .ck_name = "CKK_AES_XTS", .keygen_mech = { .mechanism = CKM_AES_XTS_KEY_GEN, }, .is_asymmetric = false, .keygen_get_key_size = aes_get_key_size, .keygen_add_secret_attrs = aes_add_secret_attrs, .sign_verify = true, .encrypt_decrypt = true, .wrap_unwrap = true, .derive = true, .encaps_decaps = false, .filter_attr = CKA_KEY_TYPE, .filter_value = CKK_AES_XTS, .keysize_attr = CKA_VALUE_LEN, .key_keysize_adjust = aes_xts_keysize_adjust, .secret_attrs = p11sak_aes_attrs, .import_check_sym_keysize = p11sak_import_check_aes_xts_keysize, .import_sym_clear = p11sak_import_sym_clear_des_3des_aes_generic, .export_sym_clear = p11sak_export_sym_clear_des_3des_aes_generic, }; static const struct p11tool_objtype p11sak_rsa_keytype = { .obj_typestr = "key", .obj_liststr = "Key", .pkey_type = EVP_PKEY_RSA, .name = "RSA", .type = CKK_RSA, .ck_name = "CKK_RSA", .keygen_mech = { .mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN, }, .is_asymmetric = true, .keygen_get_key_size = rsa_get_key_size, .keygen_add_public_attrs = rsa_add_public_attrs, .sign_verify = true, .encrypt_decrypt = true, .wrap_unwrap = true, .derive = true, .encaps_decaps = true, .filter_attr = CKA_KEY_TYPE, .filter_value = CKK_RSA, .keysize_attr = CKA_MODULUS, .keysize_attr_value_len = true, .key_keysize_adjust = rsa_keysize_adjust, .public_attrs = p11sak_public_rsa_attrs, .private_attrs = p11sak_private_rsa_attrs, .import_asym_pkey = p11sak_import_rsa_pkey, .export_asym_pkey = p11sak_export_rsa_pkey, }; static const struct p11tool_objtype p11sak_dh_keytype = { .obj_typestr = "key", .obj_liststr = "Key", .pkey_type = EVP_PKEY_DH, .name = "DH", .type = CKK_DH, .ck_name = "CKK_DH", .keygen_mech = { .mechanism = CKM_DH_PKCS_KEY_PAIR_GEN, }, .is_asymmetric = true, .keygen_prepare = dh_prepare, .keygen_cleanup = dh_cleanup, .keygen_get_key_size = dh_get_key_size, .keygen_add_public_attrs = dh_add_public_attrs, .keygen_add_private_attrs = dh_add_private_attrs, .sign_verify = false, .encrypt_decrypt = false, .wrap_unwrap = false, .derive = true, .encaps_decaps = true, .filter_attr = CKA_KEY_TYPE, .filter_value = CKK_DH, .keysize_attr = CKA_PRIME, .keysize_attr_value_len = true, .key_keysize_adjust = dh_keysize_adjust, .public_attrs = p11sak_public_dh_attrs, .private_attrs = p11sak_private_dh_attrs, .import_asym_pkey = p11sak_import_dh_pkey, .export_asym_pkey = p11sak_export_dh_pkey, }; static const struct p11tool_objtype p11sak_dsa_keytype = { .obj_typestr = "key", .obj_liststr = "Key", .pkey_type = EVP_PKEY_DSA, .name = "DSA", .type = CKK_DSA, .ck_name = "CKK_DSA", .keygen_mech = { .mechanism = CKM_DSA_KEY_PAIR_GEN, }, .is_asymmetric = true, .keygen_prepare = dsa_prepare, .keygen_cleanup = dsa_cleanup, .keygen_get_key_size = dsa_get_key_size, .keygen_add_public_attrs = dsa_add_public_attrs, .sign_verify = true, .encrypt_decrypt = false, .wrap_unwrap = false, .derive = true, .encaps_decaps = false, .filter_attr = CKA_KEY_TYPE, .filter_value = CKK_DSA, .keysize_attr = CKA_PRIME, .keysize_attr_value_len = true, .key_keysize_adjust = dsa_keysize_adjust, .public_attrs = p11sak_public_dsa_attrs, .private_attrs = p11sak_private_dsa_attrs, .import_asym_pkey = p11sak_import_dsa_pkey, .export_asym_pkey = p11sak_export_dsa_pkey, }; static const struct p11tool_objtype p11sak_ec_keytype = { .obj_typestr = "key", .obj_liststr = "Key", .pkey_type = EVP_PKEY_EC, .name = "EC", .type = CKK_EC, .ck_name = "CKK_EC", .keygen_mech = { .mechanism = CKM_EC_KEY_PAIR_GEN, }, .is_asymmetric = true, .keygen_get_key_size = ec_get_key_size, .keygen_add_public_attrs = ec_add_public_attrs, .sign_verify = true, .encrypt_decrypt = false, .wrap_unwrap = false, .derive = true, .encaps_decaps = true, .filter_attr = CKA_KEY_TYPE, .filter_value = CKK_EC, .keysize_attr = (CK_ATTRIBUTE_TYPE)-1, .public_attrs = p11sak_public_ec_attrs, .private_attrs = p11sak_private_ec_attrs, .import_asym_pkey = p11sak_import_ec_pkey, .export_asym_pkey = p11sak_export_ec_pkey, }; static const struct p11tool_objtype p11sak_ec_edwards_keytype = { .obj_typestr = "key", .obj_liststr = "Key", .name = "EC-Edwards", .type = CKK_EC_EDWARDS, .ck_name = "CKK_EC_EDWARDS", .keygen_mech = { .mechanism = CKM_EC_EDWARDS_KEY_PAIR_GEN, }, .is_asymmetric = true, .keygen_get_key_size = ec_get_key_size, .keygen_add_public_attrs = ec_add_public_attrs, .sign_verify = true, .encrypt_decrypt = false, .wrap_unwrap = false, .derive = true, .encaps_decaps = false, .filter_attr = CKA_KEY_TYPE, .filter_value = CKK_EC_EDWARDS, .keysize_attr = (CK_ATTRIBUTE_TYPE)-1, .public_attrs = p11sak_public_ec_attrs, .private_attrs = p11sak_private_ec_attrs, .import_asym_pkey = p11sak_import_ec_pkey, .export_asym_pkey = p11sak_export_ec_pkey, }; static const struct p11tool_objtype p11sak_ec_montgomery_keytype = { .obj_typestr = "key", .obj_liststr = "Key", .name = "EC-Montgomery", .type = CKK_EC_MONTGOMERY, .ck_name = "CKK_EC_MONTGOMERY", .keygen_mech = { .mechanism = CKM_EC_MONTGOMERY_KEY_PAIR_GEN, }, .is_asymmetric = true, .keygen_get_key_size = ec_get_key_size, .keygen_add_public_attrs = ec_add_public_attrs, .sign_verify = true, .encrypt_decrypt = false, .wrap_unwrap = false, .derive = true, .encaps_decaps = true, .filter_attr = CKA_KEY_TYPE, .filter_value = CKK_EC_MONTGOMERY, .keysize_attr = (CK_ATTRIBUTE_TYPE)-1, .public_attrs = p11sak_public_ec_attrs, .private_attrs = p11sak_private_ec_attrs, .import_asym_pkey = p11sak_import_ec_pkey, .export_asym_pkey = p11sak_export_ec_pkey, }; static const struct p11tool_objtype p11sak_ibm_dilithium_keytype = { .obj_typestr = "key", .obj_liststr = "Key", .name = "IBM-Dilithium", .type = CKK_IBM_PQC_DILITHIUM, .ck_name = "CKK_IBM_PQC_DILITHIUM", .supports_oqsprovider_pem = true, .keygen_mech = { .mechanism = CKM_IBM_DILITHIUM, }, .is_asymmetric = true, .keygen_add_public_attrs = ibm_dilithium_add_public_attrs, .sign_verify = true, .encrypt_decrypt = false, .wrap_unwrap = false, .derive = true, .encaps_decaps = false, .filter_attr = CKA_KEY_TYPE, .filter_value = CKK_IBM_PQC_DILITHIUM, .keysize_attr = (CK_ATTRIBUTE_TYPE)-1, .public_attrs = p11sak_public_ibm_dilithium_attrs, .private_attrs = p11sak_private_ibm_dilithium_attrs, .import_asym_pem_data = p11sak_import_dilithium_kyber_pem_data, .import_asym_pkey = p11sak_import_dilithium_ml_dsa_pkey, .export_asym_pem_data = p11sak_export_dilithium_kyber_pem_data, .export_asym_pkey = p11sak_export_dilithium_ml_dsa_pkey, .pem_name_private = "IBM-DILITHIUM PRIVATE KEY", .pem_name_public = "IBM-DILITHIUM PUBLIC KEY", }; static const struct p11tool_objtype p11sak_ibm_kyber_keytype = { .obj_typestr = "key", .obj_liststr = "Key", .name = "IBM-Kyber", .type = CKK_IBM_PQC_KYBER, .ck_name = "CKK_IBM_PQC_KYBER", .keygen_mech = { .mechanism = CKM_IBM_KYBER, }, .is_asymmetric = true, .keygen_add_public_attrs = ibm_kyber_add_public_attrs, .sign_verify = false, .encrypt_decrypt = true, .wrap_unwrap = false, .derive = true, .encaps_decaps = false, .filter_attr = CKA_KEY_TYPE, .filter_value = CKK_IBM_PQC_KYBER, .keysize_attr = (CK_ATTRIBUTE_TYPE)-1, .public_attrs = p11sak_public_ibm_kyber_attrs, .private_attrs = p11sak_private_ibm_kyber_attrs, .import_asym_pem_data = p11sak_import_dilithium_kyber_pem_data, .export_asym_pem_data = p11sak_export_dilithium_kyber_pem_data, .pem_name_private = "IBM-KYBER PRIVATE KEY", .pem_name_public = "IBM-KYBER PUBLIC KEY", }; static const struct p11tool_objtype p11sak_ibm_ml_dsa_keytype = { .obj_typestr = "key", .obj_liststr = "Key", .name = "IBM-ML-DSA", .type = CKK_IBM_ML_DSA, .ck_name = "CKK_IBM_ML_DSA", .keygen_mech = { .mechanism = CKM_IBM_ML_DSA_KEY_PAIR_GEN, }, .is_asymmetric = true, .keygen_add_public_attrs = ibm_ml_dsa_kem_add_public_attrs, .sign_verify = true, .encrypt_decrypt = false, .wrap_unwrap = false, .derive = true, .encaps_decaps = false, .filter_attr = CKA_KEY_TYPE, .filter_value = CKK_IBM_ML_DSA, .keysize_attr = (CK_ATTRIBUTE_TYPE)-1, .public_attrs = p11sak_public_ibm_ml_dsa_attrs, .private_attrs = p11sak_private_ibm_ml_dsa_attrs, .import_asym_pkey = p11sak_import_dilithium_ml_dsa_pkey, .export_asym_pkey = p11sak_export_dilithium_ml_dsa_pkey, }; static const struct p11tool_objtype p11sak_ibm_ml_kem_keytype = { .obj_typestr = "key", .obj_liststr = "Key", .name = "IBM-ML-KEM", .type = CKK_IBM_ML_KEM, .ck_name = "CKK_IBM_ML_KEM", .keygen_mech = { .mechanism = CKM_IBM_ML_KEM_KEY_PAIR_GEN, }, .is_asymmetric = true, .keygen_add_public_attrs = ibm_ml_dsa_kem_add_public_attrs, .sign_verify = false, .encrypt_decrypt = false, .wrap_unwrap = false, .derive = true, .encaps_decaps = false, .filter_attr = CKA_KEY_TYPE, .filter_value = CKK_IBM_ML_KEM, .keysize_attr = (CK_ATTRIBUTE_TYPE)-1, .public_attrs = p11sak_public_ibm_ml_kem_attrs, .private_attrs = p11sak_private_ibm_ml_kem_attrs, .import_asym_pkey = p11sak_import_ibm_ml_kem_pkey, .export_asym_pkey = p11sak_export_ibm_ml_kem_pkey, }; static const struct p11tool_objtype p11sak_ml_dsa_keytype = { .obj_typestr = "key", .obj_liststr = "Key", .name = "ML-DSA", .type = CKK_ML_DSA, .ck_name = "CKK_ML_DSA", .keygen_mech = { .mechanism = CKM_ML_DSA_KEY_PAIR_GEN, }, .is_asymmetric = true, .keygen_add_public_attrs = ml_dsa_kem_add_public_attrs, .sign_verify = true, .encrypt_decrypt = false, .wrap_unwrap = false, .derive = true, .encaps_decaps = false, .filter_attr = CKA_KEY_TYPE, .filter_value = CKK_ML_DSA, .keysize_attr = (CK_ATTRIBUTE_TYPE)-1, .public_attrs = p11sak_public_ml_dsa_attrs, .private_attrs = p11sak_private_ml_dsa_attrs, .import_asym_pkey = p11sak_import_ml_dsa_pkey, .export_asym_pkey = p11sak_export_ml_dsa_pkey, }; static const struct p11tool_objtype p11sak_ml_kem_keytype = { .obj_typestr = "key", .obj_liststr = "Key", .name = "ML-KEM", .type = CKK_ML_KEM, .ck_name = "CKK_ML_KEM", .keygen_mech = { .mechanism = CKM_ML_KEM_KEY_PAIR_GEN, }, .is_asymmetric = true, .keygen_add_public_attrs = ml_dsa_kem_add_public_attrs, .sign_verify = false, .encrypt_decrypt = false, .wrap_unwrap = false, .derive = true, .encaps_decaps = true, .filter_attr = CKA_KEY_TYPE, .filter_value = CKK_ML_KEM, .keysize_attr = (CK_ATTRIBUTE_TYPE)-1, .public_attrs = p11sak_public_ml_kem_attrs, .private_attrs = p11sak_private_ml_kem_attrs, .import_asym_pkey = p11sak_import_ml_kem_pkey, .export_asym_pkey = p11sak_export_ml_kem_pkey, }; static const struct p11tool_objtype p11sak_secret_keytype = { .obj_typestr = "key", .obj_liststr = "Key", .name = "Secret", .is_asymmetric = false, .filter_attr = CKA_CLASS, .filter_value = CKO_SECRET_KEY, }; static const struct p11tool_objtype p11sak_public_keytype = { .obj_typestr = "key", .obj_liststr = "Key", .name = "Public", .is_asymmetric = true, .filter_attr = CKA_CLASS, .filter_value = CKO_PUBLIC_KEY, }; static const struct p11tool_objtype p11sak_private_keytype = { .obj_typestr = "key", .obj_liststr = "Key", .name = "Private", .is_asymmetric = true, .filter_attr = CKA_CLASS, .filter_value = CKO_PRIVATE_KEY, }; static const struct p11tool_objtype p11sak_all_keytype = { .obj_typestr = "key", .obj_liststr = "Key", .name = "All", .filter_attr = (CK_ATTRIBUTE_TYPE)-1, }; static const struct p11tool_objtype p11sak_x509_certtype = { .obj_typestr = "certificate", .obj_liststr = "Certificate", .name = "X.509", .type = CKC_X_509, .ck_name = "CKC_X_509", .filter_attr = CKA_CERTIFICATE_TYPE, .filter_value = CKC_X_509, .cert_attrs = p11sak_x509_attrs, .import_x509_data = p11sak_import_x509_attrs, .export_x509_data = p11sak_export_x509, .extract_x509_pubkey = p11sak_extract_x509_pk, }; const struct p11tool_objtype *p11sak_keytypes[] = { &p11sak_des_keytype, &p11sak_3des_keytype, &p11sak_generic_keytype, &p11sak_sha_1_hmac_keytype, &p11sak_sha224_hmac_keytype, &p11sak_sha256_hmac_keytype, &p11sak_sha384_hmac_keytype, &p11sak_sha512_hmac_keytype, &p11sak_sha512_224_hmac_keytype, &p11sak_sha512_256_hmac_keytype, &p11sak_sha3_224_hmac_keytype, &p11sak_sha3_256_hmac_keytype, &p11sak_sha3_384_hmac_keytype, &p11sak_sha3_512_hmac_keytype, &p11sak_aes_keytype, &p11sak_aes_xts_keytype, &p11sak_rsa_keytype, &p11sak_dh_keytype, &p11sak_dsa_keytype, &p11sak_ec_keytype, &p11sak_ec_edwards_keytype, &p11sak_ec_montgomery_keytype, &p11sak_ibm_dilithium_keytype, &p11sak_ibm_kyber_keytype, &p11sak_ibm_ml_dsa_keytype, &p11sak_ibm_ml_kem_keytype, &p11sak_ml_dsa_keytype, &p11sak_ml_kem_keytype, NULL, }; static const struct p11tool_objtype *p11sak_certtypes[] = { &p11sak_x509_certtype, NULL, }; static const struct p11tool_opt p11sak_generic_opts[] = { { .short_opt = 'h', .long_opt = "help", .required = false, .arg = { .type = ARG_TYPE_PLAIN, .required = false, .value.plain = &opt_help, }, .description = "Print this help, then exit." }, { .short_opt = 'v', .long_opt = "version", .required = false, .arg = { .type = ARG_TYPE_PLAIN, .required = false, .value.plain = &opt_version, }, .description = "Print version information, then exit."}, { .short_opt = 0, .long_opt = NULL, }, }; #define PKCS11_OPTS \ { .short_opt = 's', .long_opt = "slot", .required = true, \ .arg = { .type = ARG_TYPE_NUMBER, .required = true, \ .value.number = &opt_slot, .is_set = opt_slot_is_set, \ .name = "SLOT", }, \ .description = "The PKCS#11 slot ID.", }, \ { .short_opt = 'p', .long_opt = "pin", .required = false, \ .arg = { .type = ARG_TYPE_STRING, .required = true, \ .value.string = &opt_pin, .name = "USER-PIN" }, \ .description = "The PKCS#11 user PIN. If this option is not specified, " \ "and environment variable PKCS11_USER_PIN is not set, " \ "then you are prompted for the PIN. If the '--so' " \ "option is specified, specify the SO PIN, or supply " \ "the SO PIN via environment variable PKCS11_SO_PIN.", }, \ { .short_opt = 0, .long_opt = "force-pin-prompt", .required = false, \ .long_opt_val = OPT_FORCE_PIN_PROMPT, \ .arg = { .type = ARG_TYPE_PLAIN, .required = false, \ .value.plain = &opt_force_pin_prompt, }, \ .description = "Enforce user PIN prompt, even if environment variable " \ "PKCS11_USER_PIN is set, or the '-p'/'--pin' option is " \ "specified.", }, \ { .short_opt = 'N', .long_opt = "no-login", .required = false, \ .arg = { .type = ARG_TYPE_PLAIN, .required = false, \ .value.plain = &opt_no_login, }, \ .description = "Do not login the session. This means that only public " \ "token objects (CKA_PRIVATE=FALSE) can be accessed.", }, \ { .short_opt = 0, .long_opt = "so", .required = false, \ .long_opt_val = OPT_SO, \ .arg = { .type = ARG_TYPE_PLAIN, .required = false, \ .value.plain = &opt_so, }, \ .description = "Login as SO (security officer). Option '-p'/'--pin' " \ "must specify the SO PIN, or if the '-p'/'--pin' option " \ "is not specified, environment variable PKCS11_SO_PIN " \ "is used. If PKCS11_SO_PIN is not set, then you are " \ "prompted for the SO PIN. SO can only access public " \ "token objects (CKA_PRIVATE=FALSE).", } #define KEY_FILTER_OPTS \ { .short_opt = 'L', .long_opt = "label", .required = false, \ .arg = { .type = ARG_TYPE_STRING, .required = true, \ .value.string = &opt_label, .name = "LABEL", }, \ .description = "Filter the keys by label (optional). You can use " \ "wildcards ('*' and '?') in the label specification. To " \ "specify a wildcard character that should not be treated "\ "as a wildcard, it must be escaped using a backslash " \ "('\\*' or '\\?'). Also, a backslash character that " \ "should not be treated a an escape character must be " \ "escaped ('\\\\').", }, \ { .short_opt = 'i', .long_opt = "id", .required = false, \ .arg = { .type = ARG_TYPE_STRING, .required = true, \ .value.string = &opt_id, .name = "ID", }, \ .description = "Filter the keys by ID (optional). Specify a hex string " \ "(not prefixed with 0x) of any number of bytes.", }, \ { .short_opt = 'a', .long_opt = "attr", .required = false, \ .arg = { .type = ARG_TYPE_STRING, .required = true, \ .value.string = &opt_attr, .name = "ATTRS", }, \ .description = "Filter the key by its boolean attribute values:\n" \ "P L M B Y R E D G C V O W U S A X N T I H J Q K Z " \ "(optional). Specify a set of these letters without any " \ "blanks in between. See below for the meaning of the " \ "attribute letters. Attributes that are not specified " \ "are not used to filter the keys.", } #define CERT_FILTER_OPTS \ { .short_opt = 'L', .long_opt = "label", .required = false, \ .arg = { .type = ARG_TYPE_STRING, .required = true, \ .value.string = &opt_label, .name = "LABEL", }, \ .description = "Filter the certificates by label (optional). You can use "\ "wildcards ('*' and '?') in the label specification. To " \ "specify a wildcard character that should not be treated "\ "as a wildcard, it must be escaped using a backslash " \ "('\\*' or '\\?'). Also, a backslash character that " \ "should not be treated a an escape character must be " \ "escaped ('\\\\').", }, \ { .short_opt = 'i', .long_opt = "id", .required = false, \ .arg = { .type = ARG_TYPE_STRING, .required = true, \ .value.string = &opt_id, .name = "ID", }, \ .description = "Filter the certificates by ID (optional). Specify a hex "\ "string (not prefixed with 0x) of any number of bytes.", },\ { .short_opt = 'a', .long_opt = "attr", .required = false, \ .arg = { .type = ARG_TYPE_STRING, .required = true, \ .value.string = &opt_attr, .name = "ATTRS", }, \ .description = "Filter the certificate by its boolean attribute values: "\ "P M B Y T (optional). " \ "Specify a set of these letters without any blanks in " \ "between. See below for the meaning of the attribute " \ "letters. Attributes that are not specified are not " \ "used to filter the certificates.", } #define KEYGEN_KEYTYPES(args_prefix) \ { .value = "des", .args = NULL, \ .private = { .ptr = &p11sak_des_keytype, }, }, \ { .value = "3des", .args = NULL, \ .private = { .ptr = &p11sak_3des_keytype }, }, \ { .value = "generic", .args = args_prefix##_generic_args, \ .private = { .ptr = &p11sak_generic_keytype }, }, \ { .value = "sha-1-hmac", .args = args_prefix##_generic_args, \ .private = { .ptr = &p11sak_sha_1_hmac_keytype }, }, \ { .value = "sha224-hmac", .args = args_prefix##_generic_args, \ .private = { .ptr = &p11sak_sha224_hmac_keytype }, }, \ { .value = "sha256-hmac", .args = args_prefix##_generic_args, \ .private = { .ptr = &p11sak_sha256_hmac_keytype }, }, \ { .value = "sha384-hmac", .args = args_prefix##_generic_args, \ .private = { .ptr = &p11sak_sha384_hmac_keytype }, }, \ { .value = "sha512-hmac", .args = args_prefix##_generic_args, \ .private = { .ptr = &p11sak_sha512_hmac_keytype }, }, \ { .value = "sha512/224-hmac", .args = args_prefix##_generic_args, \ .private = { .ptr = &p11sak_sha512_224_hmac_keytype }, }, \ { .value = "sha512/256-hmac", .args = args_prefix##_generic_args, \ .private = { .ptr = &p11sak_sha512_256_hmac_keytype }, }, \ { .value = "sha3-224-hmac", .args = args_prefix##_generic_args, \ .private = { .ptr = &p11sak_sha3_224_hmac_keytype }, }, \ { .value = "sha3-256-hmac", .args = args_prefix##_generic_args, \ .private = { .ptr = &p11sak_sha3_256_hmac_keytype }, }, \ { .value = "sha3-384-hmac", .args = args_prefix##_generic_args, \ .private = { .ptr = &p11sak_sha3_384_hmac_keytype }, }, \ { .value = "sha3-512-hmac", .args = args_prefix##_generic_args, \ .private = { .ptr = &p11sak_sha3_512_hmac_keytype }, }, \ { .value = "aes", .args = args_prefix##_aes_args, \ .private = { .ptr = &p11sak_aes_keytype }, }, \ { .value = "aes-xts", .args = args_prefix##_aes_xts_args, \ .private = { .ptr = &p11sak_aes_xts_keytype }, }, \ { .value = "rsa", .args = args_prefix##_rsa_args, \ .private = { .ptr = &p11sak_rsa_keytype }, }, \ { .value = "dh", .args = args_prefix##_dh_args, \ .private = { .ptr = &p11sak_dh_keytype }, }, \ { .value = "dsa", .args = args_prefix##_dsa_args, \ .private = { .ptr = &p11sak_dsa_keytype }, }, \ { .value = "ec", .args = args_prefix##_ec_args, \ .private = { .ptr = &p11sak_ec_keytype }, }, \ { .value = "ec-edwards", .args = args_prefix##_ec_edwards_args, \ .private = { .ptr = &p11sak_ec_edwards_keytype }, }, \ { .value = "ec-montgomery", .args = args_prefix##_ec_montgomery_args, \ .private = { .ptr = &p11sak_ec_montgomery_keytype }, }, \ { .value = "ibm-dilithium", .args = args_prefix##_ibm_dilithium_args, \ .private = { .ptr = &p11sak_ibm_dilithium_keytype }, }, \ { .value = "ibm-kyber", .args = args_prefix##_ibm_kyber_args, \ .private = { .ptr = &p11sak_ibm_kyber_keytype }, }, \ { .value = "ibm-ml-dsa", .args = args_prefix##_ibm_ml_dsa_args, \ .private = { .ptr = &p11sak_ibm_ml_dsa_keytype }, }, \ { .value = "ibm-ml-kem", .args = args_prefix##_ibm_ml_kem_args, \ .private = { .ptr = &p11sak_ibm_ml_kem_keytype }, }, \ { .value = "ml-dsa", .args = args_prefix##_ml_dsa_args, \ .private = { .ptr = &p11sak_ml_dsa_keytype }, }, \ { .value = "ml-kem", .args = args_prefix##_ml_kem_args, \ .private = { .ptr = &p11sak_ml_kem_keytype }, } #define GROUP_KEYTYPES \ { .value = "public", .args = NULL, \ .private = { .ptr = &p11sak_public_keytype }, }, \ { .value = "private", .args = NULL, \ .private = { .ptr = &p11sak_private_keytype }, }, \ { .value = "secret", .args = NULL, \ .private = { .ptr = &p11sak_secret_keytype }, }, \ { .value = "all", .args = NULL, \ .private = { .ptr = &p11sak_all_keytype }, } #define GROUP_CERTTYPES \ { .value = "x509", .args = NULL, \ .private = { .ptr = &p11sak_x509_certtype }, } static const struct p11tool_opt p11sak_generate_key_opts[] = { PKCS11_OPTS, { .short_opt = 'L', .long_opt = "label", .required = true, .arg = { .type = ARG_TYPE_STRING, .required = true, .value.string = &opt_label, .name = "LABEL", }, .description = "The label of the key to be generated. For asymmetric " "keys set individual labels for public and private key, " "separated by a colon (':'): 'PUB_LABEL:PRIV_LABEL'. If " "only one label is specified for an asymmetric key, the " "label is automatically extended by ':pub' and ':prv' for " "the public and private keys respectively. To use the " "same label for public and private keys specify the equal " "sign ('=') for the private key label part: " "'LABEL:='.", }, { .short_opt = 'a', .long_opt = "attr", .required = false, .arg = { .type = ARG_TYPE_STRING, .required = true, .value.string = &opt_attr, .name = "ATTRS", }, .description = "The boolean attributes to set for the key:\n" "P M B Y R E D G C V O W U S X T I H J Q K (optional). " "Specify a set of these letters without any blanks in " "between. See below for the meaning of the attribute " "letters. For asymmetric keys set individual key " "attributes for public and private key separated by a " "colon (':'): 'PUB-ATTRS:PRIV-ATTRS'.", }, { .short_opt = 'i', .long_opt = "id", .required = false, .arg = { .type = ARG_TYPE_STRING, .required = true, .value.string = &opt_id, .name = "ID", }, .description = "The ID of the key to be generated. Specify a hex string " "(not prefixed with 0x) of any number of bytes. For " "asymmetric keys the same ID is set for both, the public " "and the private key.", }, { .short_opt = 0, .long_opt = NULL, }, }; static const struct p11tool_arg p11sak_generate_generic_args[] = { { .name = "KEYBITS", .type = ARG_TYPE_NUMBER, .required = true, .value.number = &opt_keybits_num, .description = "Size of the generic key in bits.", }, { .name = NULL, }, }; static const struct p11tool_enum_value p11sak_aes_keybits[] = { { .value = "128", .args = NULL, .private = { .num = 128 }, }, { .value = "192", .args = NULL, .private = { .num = 192 }, }, { .value = "256", .args = NULL, .private = { .num = 256 }, }, { .value = NULL, }, }; static const struct p11tool_arg p11sak_generate_aes_args[] = { { .name = "KEYBITS", .type = ARG_TYPE_ENUM, .required = true, .enum_values = p11sak_aes_keybits, .value.enum_value = &opt_keybits, .description = "Size of the AES key in bits:", }, { .name = NULL, }, }; static const struct p11tool_enum_value p11sak_aes_xts_keybits[] = { { .value = "128", .args = NULL, .private = { .num = 128 * 2 }, }, { .value = "256", .args = NULL, .private = { .num = 256 * 2 }, }, { .value = NULL, }, }; static const struct p11tool_arg p11sak_generate_aes_xts_args[] = { { .name = "KEYBITS", .type = ARG_TYPE_ENUM, .required = true, .enum_values = p11sak_aes_xts_keybits, .value.enum_value = &opt_keybits, .description = "Size of the AES-XTS key in bits:", }, { .name = NULL, }, }; #define STRINGIFY(a) _STRINGIFY(a) #define _STRINGIFY(a) #a static const struct p11tool_arg p11sak_generate_rsa_args[] = { { .name = "KEYBITS", .type = ARG_TYPE_NUMBER, .required = true, .value.number = &opt_keybits_num, .description = "Size of the RSA key in bits. Must be from 512 to " STRINGIFY(OPENSSL_RSA_MAX_MODULUS_BITS) " and a " "multiple of 8 bits. Typical key sizes are 512, 1024, " "2048, 4096, or 8192.", }, { .name = "PUBL-EXP", .type = ARG_TYPE_NUMBER, .required = false, .value.number = &opt_exponent, .description = "The public exponent for RSA (optional).", }, { .name = NULL, }, }; static const struct p11tool_enum_value p11sak_dh_group[] = { { .value = "ffdhe2048", .args = NULL, .private = { .num = NID_ffdhe2048 }, }, { .value = "ffdhe3072", .args = NULL, .private = { .num = NID_ffdhe3072 }, }, { .value = "ffdhe4096", .args = NULL, .private = { .num = NID_ffdhe4096 }, }, { .value = "ffdhe6144", .args = NULL, .private = { .num = NID_ffdhe6144 }, }, { .value = "ffdhe8192", .args = NULL, .private = { .num = NID_ffdhe6144 }, }, #ifdef NID_modp_1536 { .value = "modp1536", .args = NULL, .private = { .num = NID_modp_1536 }, }, #endif #ifdef NID_modp_2048 { .value = "modp2048", .args = NULL, .private = { .num = NID_modp_2048 }, }, #endif #ifdef NID_modp_3072 { .value = "modp3072", .args = NULL, .private = { .num = NID_modp_3072 }, }, #endif #ifdef NID_modp_4096 { .value = "modp4096", .args = NULL, .private = { .num = NID_modp_4096 }, }, #endif #ifdef NID_modp_6144 { .value = "modp6144", .args = NULL, .private = { .num = NID_modp_6144 }, }, #endif #ifdef NID_modp_8192 { .value = "modp8192", .args = NULL, .private = { .num = NID_modp_8192 }, }, #endif { .value = "DH-PARAM-PEM-FILE", .args = NULL, .private = { .num = 0 }, .any_value = &opt_pem_file, }, { .value = NULL, }, }; static const struct p11tool_arg p11sak_generate_dh_args[] = { { .name = "GROUP", .type = ARG_TYPE_ENUM, .required = true, .enum_values = p11sak_dh_group, .value.enum_value = &opt_group, .description = "The Diffie-Hellman FFC group name " "or the name of a DH parameters PEM file:", }, { .name = "PRIV-BITS", .type = ARG_TYPE_NUMBER, .required = false, .value.number = &opt_keybits_num, .description = "Size of the DH private key in bits (optional).",}, { .name = NULL, }, }; static const struct p11tool_arg p11sak_generate_dsa_args[] = { { .name = "DSA-PARAM-PEM-FILE", .type = ARG_TYPE_STRING, .required = true, .value.string = &opt_pem_file, .description = "The name of a DSA parameters PEM file.", }, { .name = NULL, }, }; #define DECLARE_CURVE_INFO(name, size) \ static const struct curve_info name ## _info = { \ .oid = name, .oid_len = sizeof(name), .bitsize = size, \ } #define DECLARE_CURVE_VALUE(name) \ { .value = # name, .args = NULL, .private = { .ptr = &name ## _info, }, } #define DECLARE_CURVE_VALUE2(name, def) \ { .value = # name, .args = NULL, .private = { .ptr = &def ## _info, }, } DECLARE_CURVE_INFO(prime256v1, 256); DECLARE_CURVE_INFO(prime192v1, 192); DECLARE_CURVE_INFO(secp224r1, 224); DECLARE_CURVE_INFO(secp384r1, 384); DECLARE_CURVE_INFO(secp521r1, 521); DECLARE_CURVE_INFO(secp256k1, 256); DECLARE_CURVE_INFO(brainpoolP160r1, 160); DECLARE_CURVE_INFO(brainpoolP160t1, 160); DECLARE_CURVE_INFO(brainpoolP192r1, 192); DECLARE_CURVE_INFO(brainpoolP192t1, 192); DECLARE_CURVE_INFO(brainpoolP224r1, 224); DECLARE_CURVE_INFO(brainpoolP224t1, 224); DECLARE_CURVE_INFO(brainpoolP256r1, 256); DECLARE_CURVE_INFO(brainpoolP256t1, 256); DECLARE_CURVE_INFO(brainpoolP320r1, 320); DECLARE_CURVE_INFO(brainpoolP320t1, 320); DECLARE_CURVE_INFO(brainpoolP384r1, 384); DECLARE_CURVE_INFO(brainpoolP384t1, 384); DECLARE_CURVE_INFO(brainpoolP512r1, 512); DECLARE_CURVE_INFO(brainpoolP512t1, 512); DECLARE_CURVE_INFO(curve25519, 256); DECLARE_CURVE_INFO(curve448, 448); DECLARE_CURVE_INFO(ed25519, 256); DECLARE_CURVE_INFO(ed448, 448); DECLARE_CURVE_INFO(bls12_381, 384); static const struct p11tool_enum_value p11sak_ec_curves[] = { DECLARE_CURVE_VALUE(prime256v1), DECLARE_CURVE_VALUE(prime192v1), DECLARE_CURVE_VALUE(secp224r1), DECLARE_CURVE_VALUE(secp384r1), DECLARE_CURVE_VALUE(secp521r1), DECLARE_CURVE_VALUE(secp256k1), DECLARE_CURVE_VALUE(brainpoolP160r1), DECLARE_CURVE_VALUE(brainpoolP160t1), DECLARE_CURVE_VALUE(brainpoolP192r1), DECLARE_CURVE_VALUE(brainpoolP192t1), DECLARE_CURVE_VALUE(brainpoolP224r1), DECLARE_CURVE_VALUE(brainpoolP224t1), DECLARE_CURVE_VALUE(brainpoolP256r1), DECLARE_CURVE_VALUE(brainpoolP256t1), DECLARE_CURVE_VALUE(brainpoolP320r1), DECLARE_CURVE_VALUE(brainpoolP320t1), DECLARE_CURVE_VALUE(brainpoolP384r1), DECLARE_CURVE_VALUE(brainpoolP384t1), DECLARE_CURVE_VALUE(brainpoolP512r1), DECLARE_CURVE_VALUE(brainpoolP512t1), DECLARE_CURVE_VALUE(curve25519), DECLARE_CURVE_VALUE(curve448), DECLARE_CURVE_VALUE(ed25519), DECLARE_CURVE_VALUE(ed448), DECLARE_CURVE_VALUE2(bls12-381, bls12_381), { .value = NULL, }, }; static const struct p11tool_enum_value p11sak_ec_edwards_curves[] = { DECLARE_CURVE_VALUE(ed25519), DECLARE_CURVE_VALUE(ed448), { .value = NULL, }, }; static const struct p11tool_enum_value p11sak_ec_montgomery_curves[] = { DECLARE_CURVE_VALUE(curve25519), DECLARE_CURVE_VALUE(curve448), { .value = NULL, }, }; static const struct p11tool_arg p11sak_generate_ec_args[] = { { .name = "CURVE", .type = ARG_TYPE_ENUM, .required = true, .enum_values = p11sak_ec_curves, .value.enum_value = &opt_curve, .description = "The curve name. One of the following:", }, { .name = NULL, }, }; static const struct p11tool_arg p11sak_generate_ec_edwards_args[] = { { .name = "CURVE", .type = ARG_TYPE_ENUM, .required = true, .enum_values = p11sak_ec_edwards_curves, .value.enum_value = &opt_curve, .description = "The curve name. One of the following:", }, { .name = NULL, }, }; static const struct p11tool_arg p11sak_generate_ec_montgomery_args[] = { { .name = "CURVE", .type = ARG_TYPE_ENUM, .required = true, .enum_values = p11sak_ec_montgomery_curves, .value.enum_value = &opt_curve, .description = "The curve name. One of the following:", }, { .name = NULL, }, }; static const struct p11tool_arg p11sak_generate_ibm_dilithium_args[] = { { .name = "VERSION", .type = ARG_TYPE_ENUM, .required = true, .enum_values = p11tool_ibm_dilithium_versions, .value.enum_value = &opt_pqc_version, .description = "The version of the IBM Dilithium key pair:", }, { .name = NULL, }, }; static const struct p11tool_arg p11sak_generate_ibm_kyber_args[] = { { .name = "VERSION", .type = ARG_TYPE_ENUM, .required = true, .enum_values = p11tool_ibm_kyber_versions, .value.enum_value = &opt_pqc_version, .description = "The version of the IBM Kyber key pair:", }, { .name = NULL, }, }; static const struct p11tool_arg p11sak_generate_ibm_ml_dsa_args[] = { { .name = "VERSION", .type = ARG_TYPE_ENUM, .required = true, .enum_values = p11tool_ibm_ml_dsa_versions, .value.enum_value = &opt_pqc_version, .description = "The version of the IBM ML-DSA key pair:", }, { .name = NULL, }, }; static const struct p11tool_arg p11sak_generate_ibm_ml_kem_args[] = { { .name = "VERSION", .type = ARG_TYPE_ENUM, .required = true, .enum_values = p11tool_ibm_ml_kem_versions, .value.enum_value = &opt_pqc_version, .description = "The version of the IBM ML-KEM key pair:", }, { .name = NULL, }, }; static const struct p11tool_arg p11sak_generate_ml_dsa_args[] = { { .name = "VERSION", .type = ARG_TYPE_ENUM, .required = true, .enum_values = p11tool_ml_dsa_versions, .value.enum_value = &opt_pqc_version, .description = "The version of the ML-DSA key pair:", }, { .name = NULL, }, }; static const struct p11tool_arg p11sak_generate_ml_kem_args[] = { { .name = "VERSION", .type = ARG_TYPE_ENUM, .required = true, .enum_values = p11tool_ml_kem_versions, .value.enum_value = &opt_pqc_version, .description = "The version of the ML-KEM key pair:", }, { .name = NULL, }, }; static const struct p11tool_enum_value p11sak_generate_key_keytypes[] = { KEYGEN_KEYTYPES(p11sak_generate), { .value = NULL, }, }; static const struct p11tool_arg p11sak_generate_key_args[] = { { .name = "KEYTYPE", .type = ARG_TYPE_ENUM, .required = true, .enum_values = p11sak_generate_key_keytypes, .value.enum_value = &opt_keytype, .description = "The type of the key. One of the following:", }, { .name = NULL }, }; static const struct p11tool_opt p11sak_list_key_opts[] = { PKCS11_OPTS, KEY_FILTER_OPTS, { .short_opt = 'l', .long_opt = "long", .required = false, .arg = { .type = ARG_TYPE_PLAIN, .required = false, .value.plain = &opt_long, }, .description = "List keys in long (detailed) format.", }, { .short_opt = 0, .long_opt = "detailed-uri", .required = false, .long_opt_val = OPT_DETAILED_URI, .arg = { .type = ARG_TYPE_PLAIN, .required = false, .value.plain = &opt_detailed_uri, }, .description = "Show detailed PKCS#11 URI.", }, { .short_opt = 'm', .long_opt = "hsm-mkvp", .required = false, .arg = { .type = ARG_TYPE_PLAIN, .required = false, .value.plain = &opt_hsm_mkvp, }, .description = "Show the HSM master key verification patterns (MKVPs) of " "the key objects. Only valid for secure key tokens, such " "as the CCA and EP11 tokens.", }, { .short_opt = 'e', .long_opt = "ep11-session-id", .required = false, .arg = { .type = ARG_TYPE_PLAIN, .required = false, .value.plain = &opt_ep11_session_id, }, .description = "Show the EP11 session-IDs of the key objects. Only valid " "for an EP11 token.", }, { .short_opt = 'S', .long_opt = "sort", .required = false, .arg = { .type = ARG_TYPE_STRING, .required = true, .value.string = &opt_sort, .name = "SORT-SPEC" }, .description = "Sort the keys by label, key type, object class, and/or " "key size. Specify a sort selection of up to 4 fields, " "each represented by its corresponding letter, separated " "by comma (','):\n" "- label: 'l'\n" "- key type: 'k'\n" "- object class: 'c'\n" "- key size: 's'\n" " The sort order ('a' = ascending (default), 'd' = " "descending) can be appended to the field designator by " "a colon (':').\n" "Example: 'l:a,k:d' sorts by label in ascending order " "and then by key type in descending order.", }, { .short_opt = 0, .long_opt = NULL, }, }; static const struct p11tool_opt p11sak_list_cert_opts[] = { PKCS11_OPTS, CERT_FILTER_OPTS, { .short_opt = 'l', .long_opt = "long", .required = false, .arg = { .type = ARG_TYPE_PLAIN, .required = false, .value.plain = &opt_long, }, .description = "List certificates in long (detailed) format.", }, { .short_opt = 0, .long_opt = "detailed-uri", .required = false, .long_opt_val = OPT_DETAILED_URI, .arg = { .type = ARG_TYPE_PLAIN, .required = false, .value.plain = &opt_detailed_uri, }, .description = "Show detailed PKCS#11 URI.", }, { .short_opt = 'S', .long_opt = "sort", .required = false, .arg = { .type = ARG_TYPE_STRING, .required = true, .value.string = &opt_sort, .name = "SORT-SPEC" }, .description = "Sort the certs by label and/or subject common name (CN). " "Specify a sort selection of up to 2 fields, " "each represented by its corresponding letter, separated " "by comma (','):\n" "- label: 'l'\n" "- subj common name: 'n'\n" "The sort order ('a' = ascending (default), 'd' = " "descending) can be appended to the field designator by " "a colon (':').\n" "Example: 'l:a,n:d' sorts by label in ascending order " "and then by common name in descending order.", }, { .short_opt = 0, .long_opt = NULL, }, }; #define null_generic_args NULL #define null_aes_args NULL #define null_aes_xts_args NULL #define null_rsa_args NULL #define null_dh_args NULL #define null_dsa_args NULL #define null_ec_args NULL #define null_ec_edwards_args NULL #define null_ec_montgomery_args NULL #define null_ibm_dilithium_args NULL #define null_ibm_kyber_args NULL #define null_ibm_ml_dsa_args NULL #define null_ibm_ml_kem_args NULL #define null_ml_dsa_args NULL #define null_ml_kem_args NULL static const struct p11tool_enum_value p11sak_list_remove_set_copy_export_key_keytypes[] = { KEYGEN_KEYTYPES(null), GROUP_KEYTYPES, { .value = NULL, }, }; static const struct p11tool_enum_value p11sak_private_key_keytypes[] = { { .value = "rsa", .args = NULL, .private = { .ptr = &p11sak_rsa_keytype }, }, { .value = "dh", .args = NULL, .private = { .ptr = &p11sak_dh_keytype }, }, { .value = "dsa", .args = NULL, .private = { .ptr = &p11sak_dsa_keytype }, }, { .value = "ec", .args = NULL, .private = { .ptr = &p11sak_ec_keytype }, }, { .value = "ec-edwards", .args = NULL, .private = { .ptr = &p11sak_ec_edwards_keytype }, }, { .value = "ec-montgomery", .args = NULL, .private = { .ptr = &p11sak_ec_montgomery_keytype }, }, { .value = "ibm-dilithium", .args = NULL, .private = { .ptr = &p11sak_ibm_dilithium_keytype }, }, { .value = "ibm-kyber", .args = NULL, .private = { .ptr = &p11sak_ibm_kyber_keytype }, }, { .value = "ibm-ml-dsa", .args = NULL, .private = { .ptr = &p11sak_ibm_ml_dsa_keytype }, }, { .value = "ibm-ml-kem", .args = NULL, .private = { .ptr = &p11sak_ibm_ml_kem_keytype }, }, { .value = "ml-dsa", .args = NULL, .private = { .ptr = &p11sak_ml_dsa_keytype }, }, { .value = "ml-kem", .args = NULL, .private = { .ptr = &p11sak_ml_kem_keytype }, }, { .value = "private", .args = NULL, .private = { .ptr = &p11sak_private_keytype }, }, { .value = "all", .args = NULL, .private = { .ptr = &p11sak_all_keytype }, }, { .value = NULL, }, }; static const struct p11tool_enum_value p11sak_list_remove_set_copy_export_cert_certtypes[] = { GROUP_CERTTYPES, { .value = NULL, }, }; static const struct p11tool_arg p11sak_list_key_args[] = { { .name = "KEYTYPE", .type = ARG_TYPE_ENUM, .required = false, .enum_values = p11sak_list_remove_set_copy_export_key_keytypes, .value.enum_value = &opt_keytype, .description = "The type of the keys to list (optional). If no key type " "is specified, all key types are listed.", }, { .name = NULL }, }; static const struct p11tool_arg p11sak_list_cert_args[] = { { .name = "CERTTYPE", .type = ARG_TYPE_ENUM, .required = false, .enum_values = p11sak_list_remove_set_copy_export_cert_certtypes, .value.enum_value = &opt_certtype, .description = "The type of the certificates to list (optional). If no " "certificate type is specified, certificate type x509 " "is used, because currently no other certificate types " "are supported.", }, { .name = NULL }, }; static const struct p11tool_opt p11sak_remove_key_opts[] = { PKCS11_OPTS, KEY_FILTER_OPTS, { .short_opt = 'f', .long_opt = "force", .required = false, .arg = { .type = ARG_TYPE_PLAIN, .required = false, .value.plain = &opt_force, }, .description = "Do not prompt for a confirmation to remove a key. " "Use with care, all keys matching the filter are " "removed!", }, { .short_opt = 0, .long_opt = NULL, }, }; static const struct p11tool_opt p11sak_remove_cert_opts[] = { PKCS11_OPTS, CERT_FILTER_OPTS, { .short_opt = 'f', .long_opt = "force", .required = false, .arg = { .type = ARG_TYPE_PLAIN, .required = false, .value.plain = &opt_force, }, .description = "Do not prompt for a confirmation to remove a certificate. " "Use with care, all certificates matching the filter are " "removed!", }, { .short_opt = 0, .long_opt = NULL, }, }; static const struct p11tool_arg p11sak_remove_key_args[] = { { .name = "KEYTYPE", .type = ARG_TYPE_ENUM, .required = false, .enum_values = p11sak_list_remove_set_copy_export_key_keytypes, .value.enum_value = &opt_keytype, .description = "The type of the keys to select for removal (optional). " "If no key type is specified, all key types are " "selected.", }, { .name = NULL }, }; static const struct p11tool_arg p11sak_remove_cert_args[] = { { .name = "CERTTYPE", .type = ARG_TYPE_ENUM, .required = false, .enum_values = p11sak_list_remove_set_copy_export_cert_certtypes, .value.enum_value = &opt_certtype, .description = "The type of the certificates to select for removal " "(optional). If no certificate type is specified, " "certificate type x509 is used, because currently no " "other certificate types are supported.", }, { .name = NULL }, }; static const struct p11tool_opt p11sak_set_key_attr_opts[] = { PKCS11_OPTS, KEY_FILTER_OPTS, { .short_opt = 'f', .long_opt = "force", .required = false, .arg = { .type = ARG_TYPE_PLAIN, .required = false, .value.plain = &opt_force, }, .description = "Do not prompt for a confirmation to set the attributes " "of a key. Use with care, all keys matching the filter " "are changed!", }, { .short_opt = 'A', .long_opt = "new-attr", .required = false, .arg = { .type = ARG_TYPE_STRING, .required = true, .value.string = &opt_new_attr, .name = "ATTRS", }, .description = "The boolean attributes to set for the key (optional):\n" "P M B Y R E D G C V O W U S X T I J Q K. " "Specify a set of these letters without any blanks in " "between. See below for the meaning of the attribute " "letters. Restrictions on attribute values may apply.", }, { .short_opt = 'l', .long_opt = "new-label", .required = false, .arg = { .type = ARG_TYPE_STRING, .required = true, .value.string = &opt_new_label, .name = "LABEL", }, .description = "The new label to set for the key (optional).", }, { .short_opt = 'I', .long_opt = "new-id", .required = false, .arg = { .type = ARG_TYPE_STRING, .required = true, .value.string = &opt_new_id, .name = "ID", }, .description = "The new ID to set for the key (optional).", }, { .short_opt = 0, .long_opt = NULL, }, }; static const struct p11tool_opt p11sak_set_cert_attr_opts[] = { PKCS11_OPTS, CERT_FILTER_OPTS, { .short_opt = 'f', .long_opt = "force", .required = false, .arg = { .type = ARG_TYPE_PLAIN, .required = false, .value.plain = &opt_force, }, .description = "Do not prompt for a confirmation to set the attributes " "of a certificate. Use with care, all certificates " "matching the filter are changed!", }, { .short_opt = 'A', .long_opt = "new-attr", .required = false, .arg = { .type = ARG_TYPE_STRING, .required = true, .value.string = &opt_new_attr, .name = "ATTRS", }, .description = "The boolean attributes to set for the certificate " "(optional): P M B Y. " "Specify a set of these letters without any blanks in " "between. See below for the meaning of the attribute " "letters. Restrictions on attribute values may apply.", }, { .short_opt = 'l', .long_opt = "new-label", .required = false, .arg = { .type = ARG_TYPE_STRING, .required = true, .value.string = &opt_new_label, .name = "LABEL", }, .description = "The new label to set for the certificate (optional).", }, { .short_opt = 'I', .long_opt = "new-id", .required = false, .arg = { .type = ARG_TYPE_STRING, .required = true, .value.string = &opt_new_id, .name = "ID", }, .description = "The new ID to set for the certificate (optional).", }, { .short_opt = 0, .long_opt = NULL, }, }; static const struct p11tool_arg p11sak_set_key_attr_args[] = { { .name = "KEYTYPE", .type = ARG_TYPE_ENUM, .required = false, .enum_values = p11sak_list_remove_set_copy_export_key_keytypes, .value.enum_value = &opt_keytype, .description = "The type of the keys to select for update (optional). " "If no key type is specified, all key types are " "selected.", }, { .name = NULL }, }; static const struct p11tool_arg p11sak_set_cert_attr_args[] = { { .name = "CERTTYPE", .type = ARG_TYPE_ENUM, .required = false, .enum_values = p11sak_list_remove_set_copy_export_cert_certtypes, .value.enum_value = &opt_certtype, .description = "The type of the certificates to select for update " "(optional). If no certificate type is specified, " "certificate type x509 is used, because currently no " "other certificate types are supported.", }, { .name = NULL }, }; static const struct p11tool_opt p11sak_copy_key_opts[] = { PKCS11_OPTS, KEY_FILTER_OPTS, { .short_opt = 'f', .long_opt = "force", .required = false, .arg = { .type = ARG_TYPE_PLAIN, .required = false, .value.plain = &opt_force, }, .description = "Do not prompt for a confirmation to copy a key. Use with " "care, all keys matching the filter are copied!", }, { .short_opt = 'A', .long_opt = "new-attr", .required = false, .arg = { .type = ARG_TYPE_STRING, .required = true, .value.string = &opt_new_attr, .name = "ATTRS", }, .description = "The boolean attributes to set for the copied key " "(optional):\n P L M B Y R E D G C V O W U S A X N T I J " "Q. Specify a set of these letters without any blanks in " "between. See below for the meaning of the attribute " "letters. Restrictions on attribute values may apply.", }, { .short_opt = 'l', .long_opt = "new-label", .required = false, .arg = { .type = ARG_TYPE_STRING, .required = true, .value.string = &opt_new_label, .name = "LABEL", }, .description = "The new label to set for the copied key (optional).", }, { .short_opt = 'I', .long_opt = "new-id", .required = false, .arg = { .type = ARG_TYPE_STRING, .required = true, .value.string = &opt_new_id, .name = "ID", }, .description = "The new ID to set for the copied key (optional).", }, { .short_opt = 0, .long_opt = NULL, }, }; static const struct p11tool_opt p11sak_copy_cert_opts[] = { PKCS11_OPTS, CERT_FILTER_OPTS, { .short_opt = 'f', .long_opt = "force", .required = false, .arg = { .type = ARG_TYPE_PLAIN, .required = false, .value.plain = &opt_force, }, .description = "Do not prompt for a confirmation to copy a certificate. " "Use with care, all certificates matching the filter " "are copied!", }, { .short_opt = 'A', .long_opt = "new-attr", .required = false, .arg = { .type = ARG_TYPE_STRING, .required = true, .value.string = &opt_new_attr, .name = "ATTRS", }, .description = "The boolean attributes to set for the copied certificate " "(optional): P M B Y. " "Specify a set of these letters without any blanks in " "between. See below for the meaning of the attribute " "letters. Restrictions on attribute values may apply.", }, { .short_opt = 'l', .long_opt = "new-label", .required = false, .arg = { .type = ARG_TYPE_STRING, .required = true, .value.string = &opt_new_label, .name = "LABEL", }, .description = "The new label to set for the copied certificate " "(optional).", }, { .short_opt = 'I', .long_opt = "new-id", .required = false, .arg = { .type = ARG_TYPE_STRING, .required = true, .value.string = &opt_new_id, .name = "ID", }, .description = "The new ID to set for the copied certificate (optional).", }, { .short_opt = 0, .long_opt = NULL, }, }; static const struct p11tool_arg p11sak_copy_key_args[] = { { .name = "KEYTYPE", .type = ARG_TYPE_ENUM, .required = false, .enum_values = p11sak_list_remove_set_copy_export_key_keytypes, .value.enum_value = &opt_keytype, .description = "The type of the keys to select for copying (optional). " "If no key type is specified, all key types are " "selected.", }, { .name = NULL }, }; static const struct p11tool_arg p11sak_copy_cert_args[] = { { .name = "CERTTYPE", .type = ARG_TYPE_ENUM, .required = false, .enum_values = p11sak_list_remove_set_copy_export_cert_certtypes, .value.enum_value = &opt_keytype, .description = "The type of the certificates to select for copying " "(optional). If no certificate type is specified, " "certificate type x509 is used, because currently no " "other certificate types are supported.", }, { .name = NULL }, }; static const struct p11tool_opt p11sak_import_key_opts[] = { PKCS11_OPTS, { .short_opt = 'L', .long_opt = "label", .required = true, .arg = { .type = ARG_TYPE_STRING, .required = true, .value.string = &opt_label, .name = "LABEL", }, .description = "The label of the key to be imported.", }, { .short_opt = 'a', .long_opt = "attr", .required = false, .arg = { .type = ARG_TYPE_STRING, .required = true, .value.string = &opt_attr, .name = "ATTRS", }, .description = "The boolean attributes to set for the key:\n" "P M B Y R E D G C V O W U S X T I H J Q K (optional). " "Specify a set of these letters without any blanks in " "between. See below for the meaning of the attribute " "letters.", }, { .short_opt = 'i', .long_opt = "id", .required = false, .arg = { .type = ARG_TYPE_STRING, .required = true, .value.string = &opt_id, .name = "ID", }, .description = "The ID of the key to be imported. Specify a hex string " "(not prefixed with 0x) of any number of bytes.", }, { .short_opt = 'F', .long_opt = "file", .required = true, .arg = { .type = ARG_TYPE_STRING, .required = true, .value.string = &opt_file, .name = "FILENAME", }, .description = "The file name of the file that contains the key to be " "imported. For symmetric keys, this is a binary file " "containing the key material in clear. For asymmetric " "keys, this is an OpenSSL PEM file containing a " "public or private key. PEM files can optionally be " "password protected. Specify the PEM password with the " "'-P'/'--pem-password' option or environment variable " "P11SAK_PEM_PASSWORD. If the PEM file is password " "protected, but no PEM password is specified, you are " "prompted for the PEM password.", }, { .short_opt = 'P', .long_opt = "pem-password", .required = false, .arg = { .type = ARG_TYPE_STRING, .required = true, .value.string = &opt_pem_password, .name = "PASSWORD", }, .description = "The password of the PEM file specified with the " "'-F'/'--file' option. If the PEM file is password " "protected, but this option is not specified, nor " "environment variable P11SAK_PEM_PASSWORD is set, you " "are prompted for the PEM password.", }, { .short_opt = 0, .long_opt = "force-pem-pwd-prompt", .required = false, .long_opt_val = OPT_FORCE_PEM_PWD_PROMPT, .arg = { .type = ARG_TYPE_PLAIN, .required = false, .value.plain = &opt_force_pem_pwd_prompt, }, .description = "Enforce PEM password prompt, even if environment " "variable P11SAK_PEM_PASSWORD is set, or the " "'-P'/'--pem-password' option is specified.", }, { .short_opt = 'o', .long_opt = "opaque", .required = false, .arg = { .type = ARG_TYPE_PLAIN, .required = false, .value.plain = &opt_opaque, }, .description = "The key material in the file specified with the " "'-F'/'--file' option is an opaque secure key blob. " "Not all tokens support this.", }, { .short_opt = 0, .long_opt = "oqsprovider-pem", .required = false, .long_opt_val = OPT_OQSPROVIDER_PEM, .arg = { .type = ARG_TYPE_PLAIN, .required = false, .value.plain = &opt_oqsprovider_pem, }, .description = "The key material in the PEM file specified with the " "'-F'/'--file' option is in the 'oqsprovider' format. " "This option is only valid for the 'ibm-dilithium' " "keytype. PEM files in 'oqsprovider' format are only " "supported when the 'oqsprovider' has been configured " "with OpenSSL 3.0 or later. This is an experimental " "feature, it may change in an incompatible way in the " "future!", }, { .short_opt = 0, .long_opt = NULL, }, }; static const struct p11tool_opt p11sak_import_cert_opts[] = { PKCS11_OPTS, { .short_opt = 'L', .long_opt = "label", .required = true, .arg = { .type = ARG_TYPE_STRING, .required = true, .value.string = &opt_label, .name = "LABEL", }, .description = "The label of the certificate to be imported.", }, { .short_opt = 'a', .long_opt = "attr", .required = false, .arg = { .type = ARG_TYPE_STRING, .required = true, .value.string = &opt_attr, .name = "ATTRS", }, .description = "The boolean attributes to set for the certificate: " "P M B Y (optional). " "Specify a set of these letters without any blanks in " "between. See below for the meaning of the attribute " "letters.", }, { .short_opt = 'i', .long_opt = "id", .required = false, .arg = { .type = ARG_TYPE_STRING, .required = true, .value.string = &opt_id, .name = "ID", }, .description = "The ID of the certificate to be imported. Specify a hex " "string (not prefixed with 0x) of any number of bytes.", }, { .short_opt = 'F', .long_opt = "file", .required = true, .arg = { .type = ARG_TYPE_STRING, .required = true, .value.string = &opt_file, .name = "FILENAME", }, .description = "The file name of the file that contains the certificate " "to be imported. Supported input formats are PEM and binary " "(DER-encoded). The format is automatically detected.", }, { .short_opt = 'C', .long_opt = "ca-cert", .required = false, .arg = { .type = ARG_TYPE_PLAIN, .required = false, .value.plain = &opt_cacert, }, .description = "The certificate is a Certificate Authority (CA) " "certificate.", }, { .short_opt = 0, .long_opt = NULL, }, }; static const struct p11tool_enum_value p11sak_import_asym_types[] = { { .value = "public", .args = NULL, .private = { .num = false }, }, { .value = "private", .args = NULL, .private = { .num = true }, }, { .value = NULL, }, }; static const struct p11tool_arg p11sak_import_asym_args[] = { { .name = "KIND", .type = ARG_TYPE_ENUM, .required = true, .enum_values = p11sak_import_asym_types, .value.enum_value = &opt_asym_kind, .description = "The kind of the asymmetric key to import.", }, { .name = NULL, }, }; #define IMPORT_KEYTYPES(asym_args) \ { .value = "des", .args = NULL, \ .private = { .ptr = &p11sak_des_keytype, }, }, \ { .value = "3des", .args = NULL, \ .private = { .ptr = &p11sak_3des_keytype }, }, \ { .value = "generic", .args = NULL, \ .private = { .ptr = &p11sak_generic_keytype }, }, \ { .value = "sha-1-hmac", .args = NULL, \ .private = { .ptr = &p11sak_sha_1_hmac_keytype }, }, \ { .value = "sha224-hmac", .args = NULL, \ .private = { .ptr = &p11sak_sha224_hmac_keytype }, }, \ { .value = "sha256-hmac", .args = NULL, \ .private = { .ptr = &p11sak_sha256_hmac_keytype }, }, \ { .value = "sha384-hmac", .args = NULL, \ .private = { .ptr = &p11sak_sha384_hmac_keytype }, }, \ { .value = "sha512-hmac", .args = NULL, \ .private = { .ptr = &p11sak_sha512_hmac_keytype }, }, \ { .value = "sha512/224-hmac", .args = NULL, \ .private = { .ptr = &p11sak_sha512_224_hmac_keytype }, }, \ { .value = "sha512/256-hmac", .args = NULL, \ .private = { .ptr = &p11sak_sha512_256_hmac_keytype }, }, \ { .value = "sha3-224-hmac", .args = NULL, \ .private = { .ptr = &p11sak_sha3_224_hmac_keytype }, }, \ { .value = "sha3-256-hmac", .args = NULL, \ .private = { .ptr = &p11sak_sha3_256_hmac_keytype }, }, \ { .value = "sha3-384-hmac", .args = NULL, \ .private = { .ptr = &p11sak_sha3_384_hmac_keytype }, }, \ { .value = "sha3-512-hmac", .args = NULL, \ .private = { .ptr = &p11sak_sha3_512_hmac_keytype }, }, \ { .value = "aes", .args = NULL, \ .private = { .ptr = &p11sak_aes_keytype }, }, \ { .value = "aes-xts", .args = NULL, \ .private = { .ptr = &p11sak_aes_xts_keytype }, }, \ { .value = "rsa", .args = asym_args, \ .private = { .ptr = &p11sak_rsa_keytype }, }, \ { .value = "dh", .args = asym_args, \ .private = { .ptr = &p11sak_dh_keytype }, }, \ { .value = "dsa", .args = asym_args, \ .private = { .ptr = &p11sak_dsa_keytype }, }, \ { .value = "ec", .args = asym_args, \ .private = { .ptr = &p11sak_ec_keytype }, }, \ { .value = "ec-edwards", .args = asym_args, \ .private = { .ptr = &p11sak_ec_edwards_keytype }, }, \ { .value = "ec-montgomery", .args = asym_args, \ .private = { .ptr = &p11sak_ec_montgomery_keytype }, }, \ { .value = "ibm-dilithium", .args = asym_args, \ .private = { .ptr = &p11sak_ibm_dilithium_keytype }, }, \ { .value = "ibm-kyber", .args = asym_args, \ .private = { .ptr = &p11sak_ibm_kyber_keytype }, }, \ { .value = "ibm-ml-dsa", .args = asym_args, \ .private = { .ptr = &p11sak_ibm_ml_dsa_keytype }, }, \ { .value = "ibm-ml-kem", .args = asym_args, \ .private = { .ptr = &p11sak_ibm_ml_kem_keytype }, }, \ { .value = "ml-dsa", .args = asym_args, \ .private = { .ptr = &p11sak_ml_dsa_keytype }, }, \ { .value = "ml-kem", .args = asym_args, \ .private = { .ptr = &p11sak_ml_kem_keytype }, } static const struct p11tool_enum_value p11sak_import_key_keytypes[] = { IMPORT_KEYTYPES(p11sak_import_asym_args), { .value = NULL, }, }; #define IMPORT_CERTTYPES \ { .value = "x509", .args = NULL, \ .private = { .ptr = &p11sak_x509_certtype, }, } static const struct p11tool_enum_value p11sak_import_cert_certtypes[] = { IMPORT_CERTTYPES, { .value = NULL, }, }; static const struct p11tool_arg p11sak_import_key_args[] = { { .name = "KEYTYPE", .type = ARG_TYPE_ENUM, .required = true, .enum_values = p11sak_import_key_keytypes, .value.enum_value = &opt_keytype, .description = "The type of the key. One of the following:", }, { .name = NULL }, }; static const struct p11tool_arg p11sak_import_cert_args[] = { { .name = "CERTTYPE", .type = ARG_TYPE_ENUM, .required = true, .enum_values = p11sak_import_cert_certtypes, .value.enum_value = &opt_certtype, .description = "The type of the certificate. One of the following:", }, { .name = NULL }, }; static const struct p11tool_opt p11sak_export_key_opts[] = { PKCS11_OPTS, KEY_FILTER_OPTS, { .short_opt = 'f', .long_opt = "force", .required = false, .arg = { .type = ARG_TYPE_PLAIN, .required = false, .value.plain = &opt_force, }, .description = "Do not prompt for a confirmation to export a key. " "Use with care, all keys matching the filter are " "exported! See the description of the '-F'/'--file' " "option about what happens when multiple keys match the " "filter and are exported into the same file.", }, { .short_opt = 'F', .long_opt = "file", .required = true, .arg = { .type = ARG_TYPE_STRING, .required = true, .value.string = &opt_file, .name = "FILENAME", }, .description = "The file name of the file to which the keys to be " "exported are written to. For symmetric keys, this is a " "binary file where the key material in clear is written " "to. For asymmetric keys, this is an OpenSSL PEM file " "where the public or private keys are written to. If " "multiple asymmetric keys match the filter, the keys " "are appended to the PEM file specified with the " "'-F'/'--file' option. If multiple symmetric keys or a " "mixture of asymmetric and symmetric keys match the " "filter, then you are prompted to confirm to overwrite " "the previously created file, unless the '-f'\'--force' " "option is specified.", }, { .short_opt = 'e', .long_opt = "encrypted-pem", .required = false, .arg = { .type = ARG_TYPE_PLAIN, .required = false, .value.plain = &opt_encrypted_pem, }, .description = "Encrypt the PEM file using AES-CBC with an AES 256 bit " "key derived from a password via PBKDF2. The PEM password " "can be specified with the '-P'/'--pem-password' option, " "or via environment variable P11SAK_PEM_PASSWORD, " "otherwise you are prompted for the PEM password. This " "option is only valid for exporting private keys. It is " "not allowed when exporting SPKIs, opaque secure key " "blobs, or URI-PEMs, and it is ignored when exporting " "public or secret keys.", }, { .short_opt = 'P', .long_opt = "pem-password", .required = false, .arg = { .type = ARG_TYPE_STRING, .required = true, .value.string = &opt_pem_password, .name = "PASSWORD", }, .description = "The password used to to encrypt the PEM file specified " "with the '-F'/'--file' option. If PEM file is to be " "encrypted, but this option is not specified, nor " "environment variable P11SAK_PEM_PASSWORD is set, you " "are prompted for the PEM password.", }, { .short_opt = 0, .long_opt = "force-pem-pwd-prompt", .required = false, .long_opt_val = OPT_FORCE_PEM_PWD_PROMPT, .arg = { .type = ARG_TYPE_PLAIN, .required = false, .value.plain = &opt_force_pem_pwd_prompt, }, .description = "Enforce PEM password prompt, even if environment " "variable P11SAK_PEM_PASSWORD is set, or the " "'-P'/'--pem-password' option is specified.", }, { .short_opt = 'o', .long_opt = "opaque", .required = false, .arg = { .type = ARG_TYPE_PLAIN, .required = false, .value.plain = &opt_opaque, }, .description = "The key's opaque secure key blob is written to the file " "specified with the '-F'/'--file' option. Not all tokens " "support this.", }, { .short_opt = 'S', .long_opt = "spki", .required = false, .arg = { .type = ARG_TYPE_PLAIN, .required = false, .value.plain = &opt_spki, }, .description = "Export the Subject Public Key Info (SPKI) from the " "CKA_PUBLIC_KEY_INFO attribute of an asymmetric private " "key instead of its private key material. This option can " "only be used with private keys.", }, { .short_opt = 'u', .long_opt = "uri-pem", .required = false, .arg = { .type = ARG_TYPE_PLAIN, .required = false, .value.plain = &opt_uri_pem, }, .description = "Export the key's PKCS#11 URI in PEM form instead of the " "key material. Such an URI-PEM file can then be used with " "the pkcs11-provider (https://github.com/latchset/" "pkcs11-provider).", }, { .short_opt = 0, .long_opt = "uri-pin-value", .required = false, .long_opt_val = OPT_URI_PIN_VALUE, .arg = { .type = ARG_TYPE_PLAIN, .required = false, .value.plain = &opt_uri_pin_value, }, .description = "When exporting the key's PKCS#11 URI in PEM form, " "include the PKCS#11 user PIN value in the URI using " "the 'pin-value' query attribute. This reveals the " "PKCS#11 user PIN in clear, use with care! " "This option can only be used together with the " "'-u'/'--uri-pem' option, and when options " "'-N'/'--no-login' and '--so' are not specified.", }, { .short_opt = 0, .long_opt = "uri-pin-source", .required = false, .long_opt_val = OPT_URI_PIN_SOURCE, .arg = { .type = ARG_TYPE_STRING, .required = true, .value.string = &opt_uri_pin_source, .name = "FILENAME" }, .description = "When exporting the key's PKCS#11 URI in PEM form, " "include the 'pin-source' query attribute in the URI, " "referencing the file name specified with this option. " "The PKCS#11 user PIN value is written into that file as " "part of the export operation. This reveals the PKCS#11 " "user PIN in clear, use with care! Adjust the file " "permissions of the specified file so that it can only be " "read by the desired user(s). " "This option can only be used together with the " "'-u'/'--uri-pem' option, and when options " "'-N'/'--no-login' and '--so' are not specified.", }, { .short_opt = 0, .long_opt = "oqsprovider-pem", .required = false, .long_opt_val = OPT_OQSPROVIDER_PEM, .arg = { .type = ARG_TYPE_PLAIN, .required = false, .value.plain = &opt_oqsprovider_pem, }, .description = "The key material shall be exported in the 'oqsprovider' " "format into the PEM file specified with the " "'-F'/'--file' option. PEM files in 'oqsprovider' format " "are only supported when the 'oqsprovider' has been " "configured with OpenSSL 3.0 or later. This is an " "experimental feature, it may change in an incompatible " "way in the future!", }, { .short_opt = 0, .long_opt = NULL, }, }; static const struct p11tool_opt p11sak_extract_pubkey_opts[] = { PKCS11_OPTS, KEY_FILTER_OPTS, { .short_opt = 'f', .long_opt = "force", .required = false, .arg = { .type = ARG_TYPE_PLAIN, .required = false, .value.plain = &opt_force, }, .description = "Do not prompt for a confirmation to extract public keys. " "Use with care, public keys of all private keys matching " "the filter are extracted!", }, { .short_opt = 'A', .long_opt = "new-attr", .required = false, .arg = { .type = ARG_TYPE_STRING, .required = true, .value.string = &opt_new_attr, .name = "ATTRS", }, .description = "The boolean attributes to set for the extracted public " "key (optional): P M B Y R E D G C V O W U S X T I J Q K. " "Specify a set of these letters without any blanks in " "between. See below for the meaning of the attribute " "letters. Restrictions on attribute values may apply.", }, { .short_opt = 'l', .long_opt = "new-label", .required = false, .arg = { .type = ARG_TYPE_STRING, .required = true, .value.string = &opt_new_label, .name = "LABEL", }, .description = "The new label to set for the extracted public key (optional). " "If no new label is specified, the new label is derived " "from the private key label by appending '_pubkey'.", }, { .short_opt = 'I', .long_opt = "new-id", .required = false, .arg = { .type = ARG_TYPE_STRING, .required = true, .value.string = &opt_new_id, .name = "ID", }, .description = "The new ID to set for the extracted public key (optional).", }, { .short_opt = 0, .long_opt = NULL, }, }; static const struct p11tool_opt p11sak_export_cert_opts[] = { PKCS11_OPTS, CERT_FILTER_OPTS, { .short_opt = 'f', .long_opt = "force", .required = false, .arg = { .type = ARG_TYPE_PLAIN, .required = false, .value.plain = &opt_force, }, .description = "Do not prompt for a confirmation to export a certificate. " "Use with care, all certificates matching the filter are " "exported! If it's a PEM file, multiple certificates can " "be exported to the same file. If it's a binary file, " "each subsequent export overwrites the previous data " "in the output file. You are prompted to confirm to " "overwrite the previously created file, unless the " "[--force|-f] option is specified.", }, { .short_opt = 'F', .long_opt = "file", .required = true, .arg = { .type = ARG_TYPE_STRING, .required = true, .value.string = &opt_file, .name = "FILENAME", }, .description = "The file name of the file to which the certificates to be " "exported are written to. Supported output formats " "are PEM and binary (DER-encoded).",}, { .short_opt = 'D', .long_opt = "der", .required = false, .arg = { .type = ARG_TYPE_PLAIN, .required = false, .value.plain = &opt_der, }, .description = "The certificate is written to the file in binary " "(DER-encoded) form. Default is PEM.", }, { .short_opt = 'u', .long_opt = "uri-pem", .required = false, .arg = { .type = ARG_TYPE_PLAIN, .required = false, .value.plain = &opt_uri_pem, }, .description = "Export the certifcate's PKCS#11 URI in PEM form instead " "of the certificate material. Such an URI-PEM file can " "then be used with the pkcs11-provider (https://github.com" "/latchset/pkcs11-provider).", }, { .short_opt = 0, .long_opt = "uri-pin-value", .required = false, .long_opt_val = OPT_URI_PIN_VALUE, .arg = { .type = ARG_TYPE_PLAIN, .required = false, .value.plain = &opt_uri_pin_value, }, .description = "When exporting the certifcate's PKCS#11 URI in PEM form, " "include the PKCS#11 user PIN value in the URI using " "the 'pin-value' query attribute. This reveals the " "PKCS#11 user PIN in clear, use with care! " "This option can only be used together with the " "'-u'/'--uri-pem' option, and when options " "'-N'/'--no-login' and '--so' are not specified.", }, { .short_opt = 0, .long_opt = "uri-pin-source", .required = false, .long_opt_val = OPT_URI_PIN_SOURCE, .arg = { .type = ARG_TYPE_STRING, .required = true, .value.string = &opt_uri_pin_source, .name = "FILENAME" }, .description = "When exporting the certifcate's PKCS#11 URI in PEM form, " "include the 'pin-source' query attribute in the URI, " "referencing the file name specified with this option. " "The PKCS#11 user PIN value is written into that file as " "part of the export operation. This reveals the PKCS#11 " "user PIN in clear, use with care! Adjust the file " "permissions of the specified file so that it can only be " "read by the desired user(s). " "This option can only be used together with the " "'-u'/'--uri-pem' option, and when options " "'-N'/'--no-login' and '--so' are not specified.", }, { .short_opt = 0, .long_opt = NULL, }, }; static const struct p11tool_opt p11sak_extract_cert_pubkey_opts[] = { PKCS11_OPTS, CERT_FILTER_OPTS, { .short_opt = 'f', .long_opt = "force", .required = false, .arg = { .type = ARG_TYPE_PLAIN, .required = false, .value.plain = &opt_force, }, .description = "Do not prompt for a confirmation to extract public keys. " "Use with care, public keys of all certificates matching " "the filter are extracted!", }, { .short_opt = 'A', .long_opt = "new-attr", .required = false, .arg = { .type = ARG_TYPE_STRING, .required = true, .value.string = &opt_new_attr, .name = "ATTRS", }, .description = "The boolean attributes to set for the extracted public " "key (optional): P M B Y R E D G C V O W U S X T I J Q K. " "Specify a set of these letters without any blanks in " "between. See below for the meaning of the attribute " "letters. Restrictions on attribute values may apply.", }, { .short_opt = 'l', .long_opt = "new-label", .required = false, .arg = { .type = ARG_TYPE_STRING, .required = true, .value.string = &opt_new_label, .name = "LABEL", }, .description = "The new label to set for the extracted public key (optional). " "If no new label is specified, the new label is derived " "from the certificate label by appending '_pubkey'.", }, { .short_opt = 'I', .long_opt = "new-id", .required = false, .arg = { .type = ARG_TYPE_STRING, .required = true, .value.string = &opt_new_id, .name = "ID", }, .description = "The new ID to set for the extracted public key (optional).", }, { .short_opt = 0, .long_opt = NULL, }, }; static const struct p11tool_arg p11sak_export_key_args[] = { { .name = "KEYTYPE", .type = ARG_TYPE_ENUM, .required = false, .enum_values = p11sak_list_remove_set_copy_export_key_keytypes, .value.enum_value = &opt_keytype, .description = "The type of the keys to select for export (optional). " "If no key type is specified, all key types are " "selected.", }, { .name = NULL }, }; static const struct p11tool_arg p11sak_extract_pubkey_args[] = { { .name = "KEYTYPE", .type = ARG_TYPE_ENUM, .required = false, .enum_values = p11sak_private_key_keytypes, .value.enum_value = &opt_keytype, .description = "The type of the private keys to select for public key " "extraction (optional). If no key type is specified, all " "private key types are selected.", }, { .name = NULL }, }; static const struct p11tool_arg p11sak_export_cert_args[] = { { .name = "CERTTYPE", .type = ARG_TYPE_ENUM, .required = false, .enum_values = p11sak_list_remove_set_copy_export_cert_certtypes, .value.enum_value = &opt_certtype, .description = "The type of the certificates to select for export " "(optional). If no certificate type is specified, " "certificate type x509 is used, because currently no " "other certificate types are supported.", }, { .name = NULL }, }; static const struct p11tool_arg p11sak_extract_cert_pubkey_args[] = { { .name = "CERTTYPE", .type = ARG_TYPE_ENUM, .required = false, .enum_values = p11sak_list_remove_set_copy_export_cert_certtypes, .value.enum_value = &opt_certtype, .description = "The type of the certificates to select for public key " "extraction (optional). If no certificate type is specified, " "certificate type x509 is used, because currently no " "other certificate types are supported.", }, { .name = NULL }, }; #define KEK_SELECT_OPTS \ { .short_opt = 'K', .long_opt = "kek-label", .required = false, \ .arg = { .type = ARG_TYPE_STRING, .required = true, \ .value.string = &opt_kek_label, .name = "LABEL", }, \ .description = "Select the key encrypting key (KEK) by label. Only keys "\ "with the right object class and key type that fit to " \ "the wrapping mechanism are selected. You can use " \ "wildcards ('*' and '?') in the kek-label specification. "\ "To specify a wildcard character that should not be " \ "treated as a wildcard, it must be escaped using a " \ "backslash ('\\*' or '\\?'). Also, a backslash character "\ "that should not be treated a an escape character must " \ "be escaped ('\\\\'). If multiple key objects match then "\ "you are prompted to confirm to use the desired key " \ "object.", }, \ { .short_opt = 'k', .long_opt = "kek-id", .required = false, \ .arg = { .type = ARG_TYPE_STRING, .required = true, \ .value.string = &opt_kek_id, .name = "ID", }, \ .description = "Select the key encrypting key (KEK) by ID. Only keys " \ "with the right object class and key type that fit to " \ "the wrapping mechanism are selected. Specify a hex " \ "string (not prefixed with 0x) of any number of bytes. " \ "If multiple key objects match then you are prompted to " \ "confirm to use the desired key object.", } static const struct p11tool_opt p11sak_wrap_key_opts[] = { PKCS11_OPTS, KEK_SELECT_OPTS, KEY_FILTER_OPTS, { .short_opt = 'f', .long_opt = "force", .required = false, .arg = { .type = ARG_TYPE_PLAIN, .required = false, .value.plain = &opt_force, }, .description = "Do not prompt for a confirmation to use a key as KEK or " "to wrap a key. Use with care, all keys matching the " "filter are wrapped!", }, { .short_opt = 'F', .long_opt = "file", .required = true, .arg = { .type = ARG_TYPE_STRING, .required = true, .value.string = &opt_file, .name = "FILENAME", }, .description = "The file name of the file to which the wrapped key " "material is written to. By default this is a PEM file " "using a p11sak-specific type and a header that contains " "information about the wrapping mechanism and mechanism " "parameters (if any). If option '-R'/'--raw' is specified " "then the file is a raw binary file and the raw wrapped " "key material is written to it.", }, { .short_opt = 'R', .long_opt = "raw", .required = false, .arg = { .type = ARG_TYPE_PLAIN, .required = false, .value.plain = &opt_raw, }, .description = "Store the wrapped key material as raw bytes into the " "file specified with the '-F'/'--file' option.", }, { .short_opt = 0, .long_opt = NULL, }, }; static const struct p11tool_enum_value p11sak_wrap_key_keytypes[] = { KEYGEN_KEYTYPES(null), { .value = "private", .args = NULL, .private = { .ptr = &p11sak_private_keytype }, }, { .value = "secret", .args = NULL, .private = { .ptr = &p11sak_secret_keytype }, }, { .value = "all", .args = NULL, .private = { .ptr = &p11sak_all_keytype }, }, { .value = NULL, }, }; static const struct p11tool_arg p11sak_wrap_key_args[] = { { .name = "WRAP-MECH", .type = ARG_TYPE_ENUM, .required = true, .enum_values = p11sak_wrap_mech_values, .value.enum_value = &opt_wrap_mech, .description = "The key wrapping mechanism to use for wrapping the key. " "Dependent on the key wrapping mechanism, additional " "options may be supported to specify mechanism " "parameters.", }, { .name = "KEYTYPE", .type = ARG_TYPE_ENUM, .required = false, .enum_values = p11sak_wrap_key_keytypes, .value.enum_value = &opt_keytype, .description = "The type of the keys to select for wrapping (optional). " "If no key type is specified, all key types are " "selected.", }, { .name = NULL }, }; static const struct p11tool_opt p11sak_unwrap_key_opts[] = { PKCS11_OPTS, KEK_SELECT_OPTS, { .short_opt = 'f', .long_opt = "force", .required = false, .arg = { .type = ARG_TYPE_PLAIN, .required = false, .value.plain = &opt_force, }, .description = "Do not prompt for a confirmation to use a key as KEK.", }, { .short_opt = 'L', .long_opt = "label", .required = true, .arg = { .type = ARG_TYPE_STRING, .required = true, .value.string = &opt_label, .name = "LABEL", }, .description = "The label of the unwrapped key.", }, { .short_opt = 'a', .long_opt = "attr", .required = false, .arg = { .type = ARG_TYPE_STRING, .required = true, .value.string = &opt_attr, .name = "ATTRS", }, .description = "The boolean attributes to set for the unwrapped key:\n" "P M B Y R E D G C V O W U S X T I H J Q K (optional). " "Specify a set of these letters without any blanks in " "between. See below for the meaning of the attribute " "letters.", }, { .short_opt = 'i', .long_opt = "id", .required = false, .arg = { .type = ARG_TYPE_STRING, .required = true, .value.string = &opt_id, .name = "ID", }, .description = "The ID of the unwrapped key. Specify a hex string " "(not prefixed with 0x) of any number of bytes.", }, { .short_opt = 'F', .long_opt = "file", .required = true, .arg = { .type = ARG_TYPE_STRING, .required = true, .value.string = &opt_file, .name = "FILENAME", }, .description = "The file name of the file containing the wrapped key " "material. By default this is a PEM file using a p11sak-" "specific type and a header that contains information " "about the wrapping mechanism and mechanism parameters " "(if any). If option '-R'/'--raw' is specified then the " "file is a raw binary file and the raw wrapped key " "material is contained.", }, { .short_opt = 'R', .long_opt = "raw", .required = false, .arg = { .type = ARG_TYPE_PLAIN, .required = false, .value.plain = &opt_raw, }, .description = "Read the wrapped key material as raw bytes from the file " "specified with the '-F'/'--file' option.", }, { .short_opt = 0, .long_opt = NULL, }, }; static const struct p11tool_enum_value p11sak_unwrap_key_keytypes[] = { IMPORT_KEYTYPES(NULL), { .value = NULL, }, }; static const struct p11tool_arg p11sak_unwrap_key_args[] = { { .name = "WRAP-MECH", .type = ARG_TYPE_ENUM, .required = false, .enum_values = p11sak_wrap_mech_values, .value.enum_value = &opt_wrap_mech, .description = "The key wrapping mechanism to use for unwrapping the " "key. This argument is only required when option " "'-R'/'--raw' is specified. Dependent on the key wrapping " "mechanism, additional options may be supported to " "specify mechanism parameters.", }, { .name = "KEYTYPE", .type = ARG_TYPE_ENUM, .required = false, .enum_values = p11sak_unwrap_key_keytypes, .value.enum_value = &opt_keytype, .description = "The type of the key. This argument is only required when " "option '-R'/'--raw' is specified. One of the " "following:", }, { .name = NULL }, }; static const struct p11tool_cmd p11sak_commands[] = { { .cmd = "generate-key", .cmd_short1 = "gen-key", .cmd_short2 = "gen", .func = p11sak_generate_key, .opts = p11sak_generate_key_opts, .args = p11sak_generate_key_args, .description = "Generate a key.", .help = print_generate_import_key_attr_help, .session_flags = CKF_SERIAL_SESSION | CKF_RW_SESSION, }, { .cmd = "list-key", .cmd_short1 = "ls-key", .cmd_short2 = "ls", .func = p11sak_list_key, .opts = p11sak_list_key_opts, .args = p11sak_list_key_args, .description = "List keys in the repository.", .help = print_list_key_attr_help, .session_flags = CKF_SERIAL_SESSION, }, { .cmd = "remove-key", .cmd_short1 = "rm-key", .cmd_short2 = "rm", .func = p11sak_remove_key, .opts = p11sak_remove_key_opts, .args = p11sak_remove_key_args, .description = "Delete keys in the repository.", .help = print_remove_key_help, .session_flags = CKF_SERIAL_SESSION | CKF_RW_SESSION, }, { .cmd = "set-key-attr", .cmd_short1 = "set-key", .cmd_short2 = "set", .func = p11sak_set_key_attr, .opts = p11sak_set_key_attr_opts, .args = p11sak_set_key_attr_args, .description = "Set attributes of keys in the repository.", .help = print_set_copy_extract_key_attr_help, .session_flags = CKF_SERIAL_SESSION | CKF_RW_SESSION, }, { .cmd = "copy-key", .cmd_short1 = "copy", .cmd_short2 = "cp", .func = p11sak_copy_key, .opts = p11sak_copy_key_opts, .args = p11sak_copy_key_args, .description = "Copy keys in the repository.", .help = print_set_copy_extract_key_attr_help, .session_flags = CKF_SERIAL_SESSION | CKF_RW_SESSION, }, { .cmd = "import-key", .cmd_short1 = "import", .cmd_short2 = "imp", .func = p11sak_import_key, .opts = p11sak_import_key_opts, .args = p11sak_import_key_args, .description = "Import a key from a binary file or PEM file.", .help = print_generate_import_key_attr_help, .session_flags = CKF_SERIAL_SESSION | CKF_RW_SESSION, }, { .cmd = "export-key", .cmd_short1 = "export", .cmd_short2 = "exp", .func = p11sak_export_key, .opts = p11sak_export_key_opts, .args = p11sak_export_key_args, .description = "Export keys to a binary file or PEM file.", .session_flags = CKF_SERIAL_SESSION, }, { .cmd = "extract-pubkey", .cmd_short1 = "extr-pubkey", .cmd_short2 = "expub", .func = p11sak_extract_key_pubkey, .opts = p11sak_extract_pubkey_opts, .args = p11sak_extract_pubkey_args, .description = "Extract the public key from private keys in the repository.", .help = print_set_copy_extract_key_attr_help, .session_flags = CKF_SERIAL_SESSION | CKF_RW_SESSION, }, { .cmd = "list-cert", .cmd_short1 = "ls-cert", .cmd_short2 = "lsc", .func = p11sak_list_cert, .opts = p11sak_list_cert_opts, .args = p11sak_list_cert_args, .description = "List certificates in the repository.", .help = print_list_cert_attr_help, .session_flags = CKF_SERIAL_SESSION, }, { .cmd = "remove-cert", .cmd_short1 = "rm-cert", .cmd_short2 = "rmc", .func = p11sak_remove_cert, .opts = p11sak_remove_cert_opts, .args = p11sak_remove_cert_args, .description = "Delete certificates in the repository.", .help = print_remove_cert_help, .session_flags = CKF_SERIAL_SESSION | CKF_RW_SESSION, }, { .cmd = "set-cert-attr", .cmd_short1 = "set-cert", .cmd_short2 = "setc", .func = p11sak_set_cert_attr, .opts = p11sak_set_cert_attr_opts, .args = p11sak_set_cert_attr_args, .description = "Set attributes of certificates in the repository.", .help = print_set_copy_cert_attr_help, .session_flags = CKF_SERIAL_SESSION | CKF_RW_SESSION, }, { .cmd = "copy-cert", .cmd_short1 = "copyc", .cmd_short2 = "cpc", .func = p11sak_copy_cert, .opts = p11sak_copy_cert_opts, .args = p11sak_copy_cert_args, .description = "Copy certificates in the repository.", .help = print_set_copy_cert_attr_help, .session_flags = CKF_SERIAL_SESSION | CKF_RW_SESSION, }, { .cmd = "import-cert", .cmd_short1 = "importc", .cmd_short2 = "impc", .func = p11sak_import_cert, .opts = p11sak_import_cert_opts, .args = p11sak_import_cert_args, .description = "Import a certificate from a binary file or PEM file.", .help = print_import_cert_attr_help, .session_flags = CKF_SERIAL_SESSION | CKF_RW_SESSION, }, { .cmd = "export-cert", .cmd_short1 = "exportc", .cmd_short2 = "expc", .func = p11sak_export_cert, .opts = p11sak_export_cert_opts, .args = p11sak_export_cert_args, .description = "Export certificates to a binary file or PEM file.", .session_flags = CKF_SERIAL_SESSION, }, { .cmd = "extract-cert-pubkey", .cmd_short1 = "extrc-pubkey", .cmd_short2 = "excpub", .func = p11sak_extract_cert_pubkey, .opts = p11sak_extract_cert_pubkey_opts, .args = p11sak_extract_cert_pubkey_args, .description = "Extract the public key from certificates in the repository.", .help = print_extract_cert_pubkey_help, .session_flags = CKF_SERIAL_SESSION | CKF_RW_SESSION, }, { .cmd = "wrap-key", .cmd_short1 = "wrap", .func = p11sak_wrap_key, .opts = p11sak_wrap_key_opts, .args = p11sak_wrap_key_args, .description = "Export a key by wrapping it with a key encrypting key. " "Only private and secret keys can be wrapped.", .help = print_wrap_key_help, .session_flags = CKF_SERIAL_SESSION | CKF_RW_SESSION, }, { .cmd = "unwrap-key", .cmd_short1 = "unwrap", .func = p11sak_unwrap_key, .opts = p11sak_unwrap_key_opts, .args = p11sak_unwrap_key_args, .description = "Import a key by unwrapping it with a key encrypting key. " "Only private and secret keys can be unwrapped.", .help = print_unwrap_key_help, .session_flags = CKF_SERIAL_SESSION | CKF_RW_SESSION, }, { .cmd = NULL, .func = NULL }, }; const struct p11tool_attr p11sak_bool_attrs[] = { DECLARE_BOOL_ATTR(CKA_PRIVATE, 'P', true, true, true, true), DECLARE_BOOL_ATTR(CKA_LOCAL, 'L', true, true, true, false), DECLARE_BOOL_ATTR(CKA_MODIFIABLE, 'M', true, true, true, true), DECLARE_BOOL_ATTR(CKA_COPYABLE, 'B', true, true, true, true), DECLARE_BOOL_ATTR(CKA_DESTROYABLE, 'Y', true, true, true, true), DECLARE_BOOL_ATTR(CKA_DERIVE, 'R', true, true, true, true), DECLARE_BOOL_ATTR(CKA_ENCRYPT, 'E', true, true, false, true), DECLARE_BOOL_ATTR(CKA_DECRYPT, 'D', true, false, true, true), DECLARE_BOOL_ATTR(CKA_SIGN, 'G', true, false, true, true), DECLARE_BOOL_ATTR(CKA_SIGN_RECOVER, 'C', false, false, true, true), DECLARE_BOOL_ATTR(CKA_VERIFY, 'V', true, true, false, true), DECLARE_BOOL_ATTR(CKA_VERIFY_RECOVER, 'O', false, true, false, true), DECLARE_BOOL_ATTR(CKA_WRAP, 'W', true, true, false, true), DECLARE_BOOL_ATTR(CKA_UNWRAP, 'U', true, false, true, true), DECLARE_BOOL_ATTR(CKA_SENSITIVE, 'S', true, false, true, true), DECLARE_BOOL_ATTR(CKA_ALWAYS_SENSITIVE, 'A', true, false, true, false), DECLARE_BOOL_ATTR(CKA_EXTRACTABLE, 'X', true, false, true, true), DECLARE_BOOL_ATTR(CKA_NEVER_EXTRACTABLE, 'N', true, false, true, false), DECLARE_BOOL_ATTR_SO(CKA_TRUSTED, 'T', true, true, false, true, true), DECLARE_BOOL_ATTR(CKA_WRAP_WITH_TRUSTED, 'I', true, false, true, true), DECLARE_BOOL_ATTR(CKA_ALWAYS_AUTHENTICATE, 'H', false, false, true, true), DECLARE_BOOL_ATTR(CKA_ENCAPSULATE, 'J', false, true, false, true), DECLARE_BOOL_ATTR(CKA_DECAPSULATE, 'Q', false, false, true, true), DECLARE_BOOL_ATTR(CKA_IBM_PROTKEY_EXTRACTABLE, 'K', true, false, true, true), DECLARE_BOOL_ATTR(CKA_IBM_PROTKEY_NEVER_EXTRACTABLE, 'Z', true, false, true, false), { .name = NULL, }, }; static const struct p11tool_attr p11sak_bool_cert_attrs[] = { DECLARE_BOOL_ATTR(CKA_PRIVATE, 'P', true, true, true, true), DECLARE_BOOL_ATTR(CKA_MODIFIABLE, 'M', true, true, true, true), DECLARE_BOOL_ATTR(CKA_COPYABLE, 'B', true, true, true, true), DECLARE_BOOL_ATTR(CKA_DESTROYABLE, 'Y', true, true, true, true), DECLARE_BOOL_ATTR_SO(CKA_TRUSTED, 'T', true, true, true, true, true), { .name = NULL, }, }; static const struct p11sak_custom_attr_type custom_attr_types[] = { { .type = P11SAK_CONFIG_TYPE_BOOL, .print_long = p11tool_print_bool_attr_long, }, { .type = P11SAK_CONFIG_TYPE_ULONG, .print_long = p11tool_print_ulong_attr, }, { .type = P11SAK_CONFIG_TYPE_BYTE, .print_long = p11tool_print_byte_array_attr, }, { .type = P11SAK_CONFIG_TYPE_DATE, .print_long = p11tool_print_date_attr, }, { .type = NULL, }, }; static const struct p11tool_token_info p11sak_known_tokens[] = { { .type = TOKTYPE_CCA, .manufacturer = "IBM", .model = "CCA", .mkvp_size = 8, .mktype_cell_size = 8, .secure_key_attr = CKA_IBM_OPAQUE, .print_mkvp_short = p11sak_print_mkvp_cca_short, .print_mkvp_long = p11sak_print_mkvp_cca_long, }, { .type = TOKTYPE_EP11, .manufacturer = "IBM", .model = "EP11", .mkvp_size = 16, .mktype_cell_size = 8, .session_id_size = 32, .secure_key_attr = CKA_IBM_OPAQUE, .print_mkvp_short = p11sak_print_mkvp_ep11_short, .print_mkvp_long = p11sak_print_mkvp_ep11_long, .print_session_id_short = p11sak_print_session_id_ep11_short, .print_session_id_long = p11sak_print_session_id_ep11_long, }, { .type = TOKTYPE_UNKNOWN, }, }; #if defined(_AIX) static void *global_private = NULL; #endif static void print_import_cert_attr_help(void) { const struct p11tool_attr *attr; printf("ATTRIBUTES:\n"); for (attr = p11sak_bool_cert_attrs; attr->name != NULL; attr++) { if (attr->settable) printf(" '%c': %s%s\n", attr->letter, attr->name, attr->so_set_to_true ? " (can be set to TRUE by SO only)" : ""); } printf("\n"); printf(" "); p11tool_print_indented("An uppercase letter sets the corresponding " "attribute to CK_TRUE, a lower case letter to " "CK_FALSE.\n" "If an attribute is not set explicitly, its default " "value is used.\n" "Not all attributes may be accepted for all " "certificate types.\n" "Attribute CKA_TOKEN is always set to CK_TRUE.", 4); printf("\n"); } static void print_generate_import_key_attr_help(void) { const struct p11tool_attr *attr; printf("ATTRIBUTES:\n"); for (attr = p11sak_bool_attrs; attr->name != NULL; attr++) { if (attr->settable) printf(" '%c': %s%s\n", attr->letter, attr->name, attr->so_set_to_true ? " (can be set to TRUE by SO only)" : ""); } printf("\n"); printf(" "); p11tool_print_indented("An uppercase letter sets the corresponding " "attribute to CK_TRUE, a lower case letter to " "CK_FALSE.\n" "If an attribute is not set explicitly, its default " "value is used.\n" "Not all attributes may be accepted for all key " "types.\n" "Attribute CKA_TOKEN is always set to CK_TRUE.", 4); printf("\n"); } static void print_list_key_attr_help(void) { const struct p11tool_attr *attr; printf("ATTRIBUTES:\n"); for (attr = p11sak_bool_attrs; attr->name != NULL; attr++) printf(" '%c': %s\n", attr->letter, attr->name); printf("\n"); printf(" "); p11tool_print_indented("Not all attributes may be defined for all key " "types.\n" "Attribute CKA_TOKEN is always CK_TRUE for all keys " "listed.", 4); printf("\n"); } static void print_list_cert_attr_help(void) { const struct p11tool_attr *attr; printf("ATTRIBUTES:\n"); for (attr = p11sak_bool_cert_attrs; attr->name != NULL; attr++) printf(" '%c': %s\n", attr->letter, attr->name); printf("\n"); printf(" "); p11tool_print_indented("Not all attributes may be defined for all " "certificate types.\n" "Attribute CKA_TOKEN is always CK_TRUE for all " "certificates listed.", 4); printf("\n"); } static void print_remove_key_help(void) { const struct p11tool_attr *attr; printf("ATTRIBUTES:\n"); for (attr = p11sak_bool_attrs; attr->name != NULL; attr++) printf(" '%c': %s\n", attr->letter, attr->name); printf("\n"); printf(" "); p11tool_print_indented("Not all attributes may be defined for all key " "types.", 4); printf("\n"); } static void print_set_copy_extract_key_attr_help(void) { const struct p11tool_attr *attr; printf("ATTRIBUTES:\n"); for (attr = p11sak_bool_attrs; attr->name != NULL; attr++) printf(" '%c': %s%s\n", attr->letter, attr->name, attr->so_set_to_true ? " (can be set to TRUE by SO only)" : ""); printf("\n"); printf(" "); p11tool_print_indented("Keys can be filtered by all attributes, setting " "is possible for all except L A N Z. T can be set " "to TRUE by SO only.\n" "An uppercase letter sets the corresponding " "attribute to CK_TRUE, a lower case letter to " "CK_FALSE.\n" "If an attribute is not set explicitly, its value " "is not changed.\n" "Not all attributes may be allowed to be changed " "for all key types, or to all values.\n", 4); printf("\n"); } static void print_set_copy_cert_attr_help(void) { const struct p11tool_attr *attr; printf("ATTRIBUTES:\n"); for (attr = p11sak_bool_cert_attrs; attr->name != NULL; attr++) printf(" '%c': %s%s\n", attr->letter, attr->name, attr->so_set_to_true ? " (can be set to TRUE by SO only)" : ""); printf("\n"); printf(" "); p11tool_print_indented("Certificates can be filtered by all attributes, " "setting is also possible for all, but T can be set " "to TRUE by SO only.\n" "An uppercase letter sets the corresponding " "attribute to CK_TRUE, a lower case letter to " "CK_FALSE.\n" "If an attribute is not set explicitly, its value " "is not changed.\n" "Not all attributes may be allowed to be changed " "for all certificate types, or to all values.\n", 4); printf("\n"); } static void print_remove_cert_help(void) { const struct p11tool_attr *attr; printf("ATTRIBUTES:\n"); for (attr = p11sak_bool_cert_attrs; attr->name != NULL; attr++) printf(" '%c': %s\n", attr->letter, attr->name); printf("\n"); printf(" "); p11tool_print_indented("Not all attributes may be defined for all " "certificate types.", 4); printf("\n"); } static void print_extract_cert_pubkey_help(void) { const struct p11tool_attr *attr; printf("ATTRIBUTES (for filtering):\n"); for (attr = p11sak_bool_cert_attrs; attr->name != NULL; attr++) printf(" '%c': %s\n", attr->letter, attr->name); printf("\n"); printf(" "); p11tool_print_indented("When filtering certificates, use lowercase letters " "to include only certificates where the related " "attribute value is equal to CK_FALSE, use " "uppercase letters if the related attribute shall " "be CK_TRUE.\n", 4); printf("ATTRIBUTES (for setting):\n"); for (attr = p11sak_bool_attrs; attr->name != NULL; attr++) { if (attr->settable) printf(" '%c': %s%s\n", attr->letter, attr->name, attr->so_set_to_true ? " (can be set to TRUE by SO only)" : ""); } printf("\n"); printf(" "); p11tool_print_indented("When setting attributes for extracted public keys, " "use uppercase letters to set the corresponding " "attribute to CK_TRUE, lowercase letters to " "CK_FALSE.\n" "If an attribute is not set explicitly, its value " "is set to its default.\n" "Not all attributes may be allowed to be set for " "all public keys, or to all values.\n", 4); printf("\n"); } static bool opt_slot_is_set(const struct p11tool_arg *arg) { return (*arg->value.number != (CK_ULONG)-1); } static CK_RV generic_get_key_size(const struct p11tool_objtype *keytype, void *private, CK_ULONG *keysize) { UNUSED(private); UNUSED(keytype); *keysize = opt_keybits_num; return CKR_OK; } static CK_RV generic_add_secret_attrs(const struct p11tool_objtype *keytype, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, void *private) { CK_ULONG value_len = opt_keybits_num / 8; UNUSED(private); UNUSED(keytype); return p11tool_add_attribute(CKA_VALUE_LEN, &value_len, sizeof(value_len), attrs, num_attrs); } static CK_ULONG generic_keysize_adjust(const struct p11tool_objtype *keytype, CK_ULONG keysize) { UNUSED(keytype); return keysize * 8; } static CK_RV aes_get_key_size(const struct p11tool_objtype *keytype, void *private, CK_ULONG *keysize) { UNUSED(private); UNUSED(keytype); *keysize = opt_keybits->private.num / 8; return CKR_OK; } static CK_RV aes_add_secret_attrs(const struct p11tool_objtype *keytype, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, void *private) { CK_ULONG value_len = opt_keybits->private.num / 8; UNUSED(private); UNUSED(keytype); return p11tool_add_attribute(CKA_VALUE_LEN, &value_len, sizeof(value_len), attrs, num_attrs); } static CK_ULONG aes_keysize_adjust(const struct p11tool_objtype *keytype, CK_ULONG keysize) { UNUSED(keytype); return keysize * 8; } static CK_ULONG aes_xts_keysize_adjust(const struct p11tool_objtype *keytype, CK_ULONG keysize) { UNUSED(keytype); return (keysize * 8) / 2; } static CK_ULONG rsa_keysize_adjust(const struct p11tool_objtype *keytype, CK_ULONG keysize) { UNUSED(keytype); return keysize * 8; } static CK_ULONG dh_keysize_adjust(const struct p11tool_objtype *keytype, CK_ULONG keysize) { UNUSED(keytype); return keysize * 8; } static CK_ULONG dsa_keysize_adjust(const struct p11tool_objtype *keytype, CK_ULONG keysize) { UNUSED(keytype); return keysize * 8; } static CK_RV rsa_get_key_size(const struct p11tool_objtype *keytype, void *private, CK_ULONG *keysize) { UNUSED(private); UNUSED(keytype); if ((opt_keybits_num % 8) != 0 || opt_keybits_num < 512 || opt_keybits_num > OPENSSL_RSA_MAX_MODULUS_BITS) { warnx("The RSA key size of '%lu' is not valid", opt_keybits_num); return CKR_ARGUMENTS_BAD; } *keysize = opt_keybits_num; return CKR_OK; } static CK_RV rsa_add_public_attrs(const struct p11tool_objtype *keytype, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, void *private) { CK_RV rc; CK_BYTE *b; CK_ULONG val; unsigned int i; UNUSED(private); UNUSED(keytype); rc = rsa_get_key_size(keytype, NULL, &val); if (rc != CKR_OK) return rc; rc = p11tool_add_attribute(CKA_MODULUS_BITS, &val, sizeof(val), attrs, num_attrs); if (rc != CKR_OK) return rc; if (opt_exponent != 0) { /* Convert CK_ULONG to big-endian byte array */ val = htobe64(opt_exponent); for (i = 0, b = (CK_BYTE *)&val; i < sizeof(val) && *b == 0; i++, b++) ; rc = p11tool_add_attribute(CKA_PUBLIC_EXPONENT, b, sizeof(val) - i, attrs, num_attrs); if (rc != CKR_OK) return rc; } return CKR_OK; } static CK_RV ec_get_key_size(const struct p11tool_objtype *keytype, void *private, CK_ULONG *keysize) { const struct curve_info *curve = opt_curve->private.ptr; UNUSED(private); UNUSED(keytype); *keysize = curve->bitsize; return CKR_OK; } static CK_RV ec_add_public_attrs(const struct p11tool_objtype *keytype, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, void *private) { const struct curve_info *curve = opt_curve->private.ptr; UNUSED(private); UNUSED(keytype); return p11tool_add_attribute(CKA_EC_PARAMS, curve->oid, curve->oid_len, attrs, num_attrs); } static CK_RV dh_dsa_read_params_pem(const char *pem_file, bool is_dsa, EVP_PKEY **pkey) { CK_RV rc = CKR_OK; EVP_PKEY *param = NULL; BIO *f; f = BIO_new_file(pem_file, "r"); if (f == NULL) { warnx("Failed to open PEM file '%s'.", pem_file); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); return CKR_ARGUMENTS_BAD; } param = PEM_read_bio_Parameters(f, NULL); if (param == NULL || EVP_PKEY_base_id(param) != (is_dsa ? EVP_PKEY_DSA : EVP_PKEY_DH)) { warnx("Failed to read %s PEM file '%s'.", is_dsa ? "DSA" : "DH", pem_file); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } *pkey = param; param = NULL; done: BIO_free(f); if (param != NULL) EVP_PKEY_free(param); return rc; } static CK_RV dh_group_params(int group_nid, EVP_PKEY **pkey) { EVP_PKEY_CTX *ctx = NULL; EVP_PKEY *param = NULL; CK_RV rc = CKR_OK; ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_DH, NULL); if (ctx == NULL) { warnx("Failed to set up an EVP context for DH."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); return CKR_FUNCTION_FAILED; } if (EVP_PKEY_paramgen_init(ctx) <= 0) { warnx("Failed to initialize a DH paramgen context."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } if (EVP_PKEY_CTX_set_dh_nid(ctx, group_nid) <= 0) { warnx("Failed to set group for DH paramgen context."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } if (EVP_PKEY_paramgen(ctx, ¶m) <= 0) { warnx("Failed to generate the DH params."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } *pkey = param; param = NULL; done: if (param != NULL) EVP_PKEY_free(param); EVP_PKEY_CTX_free(ctx); return rc; } static CK_RV dh_dsa_add_public_attrs(CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, EVP_PKEY *pkey, bool is_dsa) { CK_RV rc = CKR_OK; #if OPENSSL_VERSION_PREREQ(3, 0) BIGNUM *bn_p = NULL, *bn_q = NULL, *bn_g = NULL; #else const DH *dh; const DSA *dsa; const BIGNUM *bn_p = NULL, *bn_q = NULL, *bn_g = NULL; #endif #if OPENSSL_VERSION_PREREQ(3, 0) if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_FFC_P, &bn_p) || (is_dsa && !EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_FFC_Q, &bn_q)) || !EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_FFC_G, &bn_g)) { warnx("Failed to get the %s params.", is_dsa ? "DSA" : "DH"); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } #else if (is_dsa) { dsa = EVP_PKEY_get0_DSA(pkey); if (dsa == NULL) { warnx("Failed to get the DSA params."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } DSA_get0_pqg(dsa, &bn_p, &bn_q, &bn_g); if (bn_p == NULL || (dsa && bn_q == NULL) || bn_g == NULL) { warnx("Failed to get the DSA params."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } } else { dh = EVP_PKEY_get0_DH(pkey); if (dh == NULL) { warnx("Failed to get the DH params."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } DH_get0_pqg(dh, &bn_p, NULL, &bn_g); if (bn_p == NULL || bn_g == NULL) { warnx("Failed to get the DH params."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } } #endif rc = p11tool_add_bignum_attr(CKA_PRIME, bn_p, attrs, num_attrs); if (rc != CKR_OK) goto done; if (is_dsa) { rc = p11tool_add_bignum_attr(CKA_SUBPRIME, bn_q, attrs, num_attrs); if (rc != CKR_OK) goto done; } rc = p11tool_add_bignum_attr(CKA_BASE, bn_g, attrs, num_attrs); if (rc != CKR_OK) goto done; done: #if OPENSSL_VERSION_PREREQ(3, 0) if (bn_p != NULL) BN_free(bn_p); if (bn_q != NULL) BN_free(bn_q); if (bn_g != NULL) BN_free(bn_g); #endif return rc; } static CK_RV dh_prepare(const struct p11tool_objtype *keytype, void **private) { CK_RV rc; EVP_PKEY *pkey = NULL; UNUSED(keytype); if (opt_pem_file != NULL) rc = dh_dsa_read_params_pem(opt_pem_file, false, &pkey); else rc = dh_group_params(opt_group->private.num, &pkey); if (rc != CKR_OK) return rc; *private = pkey; return CKR_OK; } static void dh_cleanup(const struct p11tool_objtype *keytype, void *private) { EVP_PKEY *pkey = private; UNUSED(keytype); EVP_PKEY_free(pkey); } static CK_RV dh_get_key_size(const struct p11tool_objtype *keytype, void *private, CK_ULONG *keysize) { EVP_PKEY *pkey = private; CK_RV rc = CKR_OK; #if OPENSSL_VERSION_PREREQ(3, 0) BIGNUM *bn_p = NULL; #else const DH *dh; const BIGNUM *bn_p = NULL; #endif UNUSED(keytype); #if OPENSSL_VERSION_PREREQ(3, 0) if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_FFC_P, &bn_p)) { warnx("Failed to get the DH params."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } #else dh = EVP_PKEY_get0_DH(pkey); if (dh == NULL) { warnx("Failed to get the DH params."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } DH_get0_pqg(dh, &bn_p, NULL, NULL); if (bn_p == NULL) { warnx("Failed to get the DH params."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } #endif *keysize = BN_num_bits(bn_p); done: #if OPENSSL_VERSION_PREREQ(3, 0) if (bn_p != NULL) BN_free(bn_p); #endif return rc; } static CK_RV dh_add_public_attrs(const struct p11tool_objtype *keytype, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, void *private) { EVP_PKEY *pkey = private; UNUSED(keytype); return dh_dsa_add_public_attrs(attrs, num_attrs, pkey, false); } static CK_RV dh_add_private_attrs(const struct p11tool_objtype *keytype, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, void *private) { UNUSED(private); UNUSED(keytype); if (opt_keybits_num == 0) return CKR_OK; return p11tool_add_attribute(CKA_VALUE_BITS, &opt_keybits_num, sizeof(opt_keybits_num), attrs, num_attrs); } static CK_RV dsa_prepare(const struct p11tool_objtype *keytype, void **private) { CK_RV rc; EVP_PKEY *pkey = NULL; UNUSED(keytype); rc = dh_dsa_read_params_pem(opt_pem_file, true, &pkey); if (rc != CKR_OK) return rc; *private = pkey; return CKR_OK; } static void dsa_cleanup(const struct p11tool_objtype *keytype, void *private) { EVP_PKEY *pkey = private; UNUSED(keytype); EVP_PKEY_free(pkey); } static CK_RV dsa_get_key_size(const struct p11tool_objtype *keytype, void *private, CK_ULONG *keysize) { EVP_PKEY *pkey = private; CK_RV rc = CKR_OK; #if OPENSSL_VERSION_PREREQ(3, 0) BIGNUM *bn_p = NULL; #else const DSA *dsa; const BIGNUM *bn_p = NULL; #endif UNUSED(keytype); #if OPENSSL_VERSION_PREREQ(3, 0) if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_FFC_P, &bn_p)) { warnx("Failed to get the DSA params."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } #else dsa = EVP_PKEY_get0_DSA(pkey); if (dsa == NULL) { warnx("Failed to get the DSA params."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } DSA_get0_pqg(dsa, &bn_p, NULL, NULL); if (bn_p == NULL) { warnx("Failed to get the DSA params."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } #endif *keysize = BN_num_bits(bn_p); done: #if OPENSSL_VERSION_PREREQ(3, 0) if (bn_p != NULL) BN_free(bn_p); #endif return rc; } static CK_RV dsa_add_public_attrs(const struct p11tool_objtype *keytype, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, void *private) { EVP_PKEY *pkey = private; UNUSED(keytype); return dh_dsa_add_public_attrs(attrs, num_attrs, pkey, true); } static CK_RV ibm_dilithium_add_public_attrs( const struct p11tool_objtype *keytype, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, void *private) { UNUSED(private); UNUSED(keytype); return p11tool_add_attribute(CKA_IBM_DILITHIUM_KEYFORM, &opt_pqc_version->private.num, sizeof(opt_pqc_version->private.num), attrs, num_attrs); } static CK_RV ibm_kyber_add_public_attrs(const struct p11tool_objtype *keytype, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, void *private) { UNUSED(private); UNUSED(keytype); return p11tool_add_attribute(CKA_IBM_KYBER_KEYFORM, &opt_pqc_version->private.num, sizeof(opt_pqc_version->private.num), attrs, num_attrs); } static CK_RV ibm_ml_dsa_kem_add_public_attrs( const struct p11tool_objtype *keytype, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, void *private) { UNUSED(private); UNUSED(keytype); return p11tool_add_attribute(CKA_IBM_PARAMETER_SET, &opt_pqc_version->private.num, sizeof(opt_pqc_version->private.num), attrs, num_attrs); } static CK_RV ml_dsa_kem_add_public_attrs(const struct p11tool_objtype *keytype, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, void *private) { UNUSED(private); UNUSED(keytype); return p11tool_add_attribute(CKA_PARAMETER_SET, &opt_pqc_version->private.num, sizeof(opt_pqc_version->private.num), attrs, num_attrs); } static CK_RV parse_key_pair_label(const char *label, char **pub_label, char** priv_label) { char *pub = NULL; char *priv = NULL; unsigned int i; for (i = 0; i < strlen(label); i++) { if (label[i] == '\\') { i++; /* skip escaped character */ continue; } if (label[i] == ':') { if (!(pub = strndup(label, i))) { warnx("Failed to allocate memory for pub label"); return CKR_HOST_MEMORY; } if (!(priv = strdup(&label[i + 1]))) { warnx("Failed to allocate memory for priv label"); free(pub); return CKR_HOST_MEMORY; } break; } } if (pub != NULL && priv != NULL) { if (strcmp(priv, "=") == 0) { free(priv); if (!(priv = strdup(pub))) { warnx("Failed to allocate memory for priv label"); free(pub); return CKR_HOST_MEMORY; } } } else { if (!(pub = malloc(strlen(label) + 5))) { warnx("Failed to allocate memory for pub label"); return CKR_HOST_MEMORY; } pub = strcpy(pub, label); pub = strcat(pub, ":pub"); if (!(priv = malloc(strlen(label) + 5))) { warnx("Failed to allocate memory for priv label"); free(pub); return CKR_HOST_MEMORY; } priv = strcpy(priv, label); priv = strcat(priv, ":prv"); } for (i = 0; i < strlen(pub); i++) { if (pub[i] == '\\') memmove(&pub[i], &pub[i + 1], strlen(&pub[i + 1]) + 1); } for (i = 0; i < strlen(priv); i++) { if (priv[i] == '\\') memmove(&priv[i], &priv[i + 1], strlen(&priv[i + 1]) + 1); } *pub_label = pub; *priv_label = priv; return CKR_OK; } static CK_RV parse_key_pair_attrs(const char *attrs, char **pub_attrs, char** priv_attrs) { char *ch, *pub, *priv; if (attrs == NULL) { *pub_attrs = NULL; *priv_attrs = NULL; return CKR_OK; } ch = strchr(attrs, ':'); if (ch == NULL) { pub = strdup(attrs); priv = strdup(attrs); } else { pub = strndup(attrs, ch - attrs); priv = strdup(ch + 1); } if (pub == NULL || priv == NULL) { warnx("Failed to allocate memory for pub/priv labels"); free(pub); free(priv); return CKR_HOST_MEMORY; } *pub_attrs = pub; *priv_attrs = priv; return CKR_OK; } const struct p11tool_objtype *find_keytype(CK_KEY_TYPE ktype) { const struct p11tool_objtype **kt; for (kt = p11sak_keytypes; *kt != NULL; kt++) { if ((*kt)->type == ktype) return *kt; } return NULL; } static const struct p11tool_objtype *find_keytype_by_pkey(int pkey_type) { const struct p11tool_objtype **kt; if (pkey_type == NID_undef) return NULL; for (kt = p11sak_keytypes; *kt != NULL; kt++) { switch (pkey_type) { #if OPENSSL_VERSION_PREREQ(3, 0) case EVP_PKEY_ED25519: case EVP_PKEY_ED448: if ((*kt)->type == CKK_EC_EDWARDS) return *kt; break; case EVP_PKEY_X25519: case EVP_PKEY_X448: if ((*kt)->type == CKK_EC_MONTGOMERY) return *kt; break; #endif default: if ((*kt)->pkey_type == pkey_type) return *kt; break; } } return NULL; } #if OPENSSL_VERSION_PREREQ(3, 0) static const struct pqc_oid *pqc_oid_from_pkey(EVP_PKEY *pkey, const struct pqc_oid *pqc_oids, bool show_err_msg) { const char *alg_name; ASN1_OBJECT *obj = NULL; const struct pqc_oid *oid = NULL; CK_BYTE *val = NULL; int val_len; int nid; alg_name = EVP_PKEY_get0_type_name(pkey); if (alg_name == NULL) { warnx("Failed to obtain the key type of the imported key"); return NULL; } nid = OBJ_ln2nid(alg_name); if (nid == NID_undef) { warnx("OBJ_ln2nid failed for '%s'", alg_name); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); return NULL; } obj = OBJ_nid2obj(nid); if (obj == NULL) { warnx("OBJ_nid2obj failed for NID %d ('%s')", nid, alg_name); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); return NULL; } val_len = i2d_ASN1_OBJECT(obj, &val); if (val_len <= 0) { warnx("i2d_ASN1_OBJECT failed for algorithm '%s'", alg_name); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); goto done; } oid = find_pqc_by_oid(pqc_oids, val, val_len); if (oid == NULL && show_err_msg) warnx("Algorithm '%s' is not supported by p11sak", alg_name); OPENSSL_free(val); done: ASN1_OBJECT_free(obj); return oid; } #endif static const struct p11tool_objtype *find_certtype(CK_KEY_TYPE ktype) { const struct p11tool_objtype **kt; for (kt = p11sak_certtypes; *kt != NULL; kt++) { if ((*kt)->type == ktype) return *kt; } return NULL; } static CK_RV get_obj_infos(CK_OBJECT_HANDLE obj, CK_OBJECT_CLASS *class, CK_ULONG *otype, CK_ULONG *keysize, char** label, char** typestr, const struct p11tool_objtype **objtype, char **common_name) { CK_RV rc; CK_OBJECT_CLASS class_val = 0; CK_ULONG otype_val = 0; const struct p11tool_objtype *objtype_val; CK_ULONG keysize_val = 0; char *label_val = NULL; char *common_name_val = NULL; rc = p11tool_get_label_value(obj, &label_val); if (rc != CKR_OK) return rc; rc = p11tool_get_class_and_type_values(obj, label_val, &class_val, &otype_val); if (rc != CKR_OK) { free(label_val); return rc; } switch (class_val) { case CKO_SECRET_KEY: case CKO_PUBLIC_KEY: case CKO_PRIVATE_KEY: objtype_val = find_keytype(otype_val); if (objtype_val == NULL) { warnx("Object \"%s\" has an unsupported type: %lu", label_val, otype_val); free(label_val); return CKR_KEY_TYPE_INCONSISTENT; } if (keysize != NULL) { rc = p11tool_get_keysize_value(obj, label_val, objtype_val, &keysize_val); if (rc != CKR_OK) { free(label_val); return rc; } *keysize = keysize_val; } break; case CKO_CERTIFICATE: objtype_val = find_certtype(otype_val); if (objtype_val == NULL) { warnx("Object \"%s\" has an unsupported type: %lu", label_val, otype_val); free(label_val); return CKR_KEY_TYPE_INCONSISTENT; } if (common_name != NULL) { rc = p11tool_get_common_name_value(obj, label_val, &common_name_val); if (rc != CKR_OK) { free(label_val); free(common_name_val); return rc; } *common_name = common_name_val; } break; default: /* Should not occur */ warnx("Object \"%s\" has an unsupported class: %lu", label_val, class_val); free(label_val); return CKR_KEY_TYPE_INCONSISTENT; break; } if (class != NULL) *class = class_val; if (otype != NULL) *otype = otype_val; if (objtype != NULL) *objtype = objtype_val; if (typestr != NULL) { rc = p11tool_get_typestr_value(class_val, keysize_val, objtype_val, label_val, typestr); if (rc != CKR_OK) { free(label_val); return rc; } } if (label != NULL) *label = label_val; else free(label_val); return CKR_OK; } static int iterate_compare(const void *a, const void *b, void *private) { struct p11sak_iterate_compare_data *data = private; const CK_OBJECT_HANDLE *obj1 = a; const CK_OBJECT_HANDLE *obj2 = b; int result = 0; CK_RV rc; if (data->rc != CKR_OK) return 0; rc = data->compare_obj(*obj1, *obj2, &result, data->private); if (rc != CKR_OK) data->rc = rc; return result; } #if defined(_AIX) static int iterate_compare_aix(const void *a, const void *b) { return iterate_compare(a, b, global_private); } #endif CK_RV iterate_objects(const struct p11tool_objtype *objtype, const char *label_filter, const char *id_filter, const char *attr_filter, enum p11tool_objclass objclass, CK_RV (*compare_obj)(CK_OBJECT_HANDLE obj1, CK_OBJECT_HANDLE obj2, int *result, void *private), CK_RV (*handle_obj)(CK_OBJECT_HANDLE obj, CK_OBJECT_CLASS class, const struct p11tool_objtype *objtype, CK_ULONG keysize, const char *typestr, const char* label, const char *common_name, void *private), void *private) { CK_RV rc, rc2; CK_ATTRIBUTE *attrs = NULL; CK_ULONG num_attrs = 0; const CK_BBOOL ck_true = CK_TRUE; CK_OBJECT_HANDLE objs[FIND_OBJECTS_COUNT]; CK_ULONG i, num_objs; bool manual_filtering = false; CK_OBJECT_CLASS class; CK_KEY_TYPE ktype; CK_ULONG keysize = 0; char *label = NULL; char *typestr = NULL; char *common_name = NULL; const struct p11tool_objtype *type; CK_OBJECT_HANDLE *matched_objs = NULL, *tmp; CK_ULONG num_matched_objs = 0; CK_ULONG alloc_matched_objs = 0; struct p11sak_iterate_compare_data data; rc = p11tool_add_attribute(CKA_TOKEN, &ck_true, sizeof(ck_true), &attrs, &num_attrs); if (rc != CKR_OK) goto done; if (objtype != NULL && objtype->filter_attr != (CK_ATTRIBUTE_TYPE)-1) { rc = p11tool_add_attribute(objtype->filter_attr, &objtype->filter_value, sizeof(objtype->filter_value), &attrs, &num_attrs); if (rc != CKR_OK) goto done; } if (label_filter != NULL) { manual_filtering = (strpbrk(label_filter, "*?\\") != NULL); if (!manual_filtering) { /* add label filter only if no escapes are used */ rc = p11tool_add_attribute(CKA_LABEL, label_filter, strlen(label_filter), &attrs, &num_attrs); if (rc != CKR_OK) goto done; } } if (id_filter != NULL) { rc = p11tool_parse_id(id_filter, &attrs, &num_attrs); if (rc != CKR_OK) goto done; } if (attr_filter != NULL) { rc = p11tool_parse_boolean_attrs(NULL, p11sak_bool_attrs, opt_attr, &attrs, &num_attrs, false, opt_so, NULL); if (rc != CKR_OK) goto done; } rc = p11tool_pkcs11_funcs->C_FindObjectsInit(p11tool_pkcs11_session, attrs, num_attrs); if (rc != CKR_OK) { warnx("Failed to initialize the find operation: C_FindObjectsInit: 0x%lX: %s", rc, p11_get_ckr(rc)); goto done; } while (1) { memset(objs, 0, sizeof(objs)); num_objs = 0; rc = p11tool_pkcs11_funcs->C_FindObjects(p11tool_pkcs11_session, objs, FIND_OBJECTS_COUNT, &num_objs); if (rc != CKR_OK) { warnx("Failed to find objects: C_FindObjects: 0x%lX: %s", rc, p11_get_ckr(rc)); goto done_find; } if (num_objs == 0) break; for (i = 0; i < num_objs; i++) { if (!p11tool_objclass_expected(objs[i], objclass)) continue; if (manual_filtering) { rc = p11tool_get_label_value(objs[i], &label); if (rc != CKR_OK) break; if (fnmatch(label_filter, label, 0) != 0) goto next; } if (num_matched_objs >= alloc_matched_objs) { tmp = realloc(matched_objs, (alloc_matched_objs + FIND_OBJECTS_COUNT) * sizeof(CK_OBJECT_HANDLE)); if (tmp == NULL) { warnx("Failed to allocate a list of matched objects."); rc = CKR_HOST_MEMORY; goto done_find; } matched_objs = tmp; alloc_matched_objs += FIND_OBJECTS_COUNT; } matched_objs[num_matched_objs++] = objs[i]; next: if (label != NULL) free(label); label = NULL; } } done_find: rc2 = p11tool_pkcs11_funcs->C_FindObjectsFinal(p11tool_pkcs11_session); if (rc2 != CKR_OK) { warnx("Failed to finalize the find operation: C_FindObjectsFinal: 0x%lX: %s", rc2, p11_get_ckr(rc2)); if (rc == CKR_OK) rc = rc2; } if (rc != CKR_OK) goto done; if (compare_obj != NULL && num_matched_objs > 0) { data.compare_obj = compare_obj; data.private = private; data.rc = CKR_OK; #if defined(_AIX) global_private = &data; qsort(matched_objs, num_matched_objs, sizeof(CK_OBJECT_HANDLE), iterate_compare_aix); #else qsort_r(matched_objs, num_matched_objs, sizeof(CK_OBJECT_HANDLE), iterate_compare, &data); #endif rc = data.rc; if (rc != CKR_OK) goto done; } for (i = 0; i < num_matched_objs; i++) { rc = get_obj_infos(matched_objs[i], &class, &ktype, &keysize, &label, &typestr, &type, &common_name); if (rc != CKR_OK) break; rc = handle_obj(matched_objs[i], class, type, keysize, typestr, label, common_name, private); if (rc != CKR_OK) break; if (label != NULL) free(label); label = NULL; if (typestr != NULL) free(typestr); typestr = NULL; if (common_name != NULL) free(common_name); common_name = NULL; } done: p11tool_free_attributes(attrs, num_attrs); if (label != NULL) free(label); if (typestr != NULL) free(typestr); if (common_name != NULL) free(common_name); if (matched_objs != NULL) free(matched_objs); return rc; } static CK_RV p11sak_generate_key(void) { const struct p11tool_objtype *keytype; void *private = NULL; CK_RV rc = CKR_OK; CK_ULONG keysize = 0; char *pub_label = NULL, *priv_label = NULL; char *pub_attrs = NULL, *priv_attrs = NULL; CK_ATTRIBUTE *secret_attrs = NULL; CK_ULONG num_secret_attrs = 0; CK_ATTRIBUTE *public_attrs = NULL; CK_ULONG num_public_attrs = 0; CK_ATTRIBUTE *private_attrs = NULL; CK_ULONG num_private_attrs = 0; CK_OBJECT_HANDLE pub_key, priv_key, secret_key; if (opt_keytype == NULL || opt_keytype->private.ptr == NULL) return CKR_ARGUMENTS_BAD; keytype = opt_keytype->private.ptr; if (keytype->keygen_prepare != NULL) { rc = keytype->keygen_prepare(keytype, &private); if (rc != CKR_OK) { warnx("Failed to prepare key type %s: 0x%lX: %s", keytype->name, rc, p11_get_ckr(rc)); return rc; } } if (keytype->keygen_get_key_size != NULL) { rc = keytype->keygen_get_key_size(keytype, private, &keysize); if (rc != CKR_OK) { warnx("Failed to get key size for key type %s: 0x%lX: %s", keytype->name, rc, p11_get_ckr(rc)); goto done; } } rc = p11tool_check_keygen_mech_supported(opt_slot, keytype->keygen_mech.mechanism, keytype->is_asymmetric, keysize); if (rc != CKR_OK) goto done; if (keytype->is_asymmetric) { rc = parse_key_pair_label(opt_label, &pub_label, &priv_label); if (rc != CKR_OK) goto done; rc = parse_key_pair_attrs(opt_attr, &pub_attrs, &priv_attrs); if (rc != CKR_OK) goto done; rc = p11tool_add_attributes(keytype, p11sak_bool_attrs, &public_attrs, &num_public_attrs, pub_label, pub_attrs, opt_id, false, opt_so, keytype->keygen_add_public_attrs, private, p11tool_public_attr_applicable); if (rc != CKR_OK) goto done; rc = p11tool_add_attributes(keytype, p11sak_bool_attrs, &private_attrs, &num_private_attrs, priv_label, priv_attrs, opt_id, true, opt_so, keytype->keygen_add_private_attrs, private, p11tool_private_attr_applicable); if (rc != CKR_OK) goto done; } else { rc = p11tool_add_attributes(keytype, p11sak_bool_attrs, &secret_attrs, &num_secret_attrs, opt_label, opt_attr, opt_id, true, opt_so, keytype->keygen_add_secret_attrs, private, p11tool_secret_attr_applicable); if (rc != CKR_OK) goto done; } if (keytype->is_asymmetric) rc = p11tool_pkcs11_funcs->C_GenerateKeyPair(p11tool_pkcs11_session, (CK_MECHANISM *)&keytype->keygen_mech, public_attrs, num_public_attrs, private_attrs, num_private_attrs, &pub_key, &priv_key); else rc = p11tool_pkcs11_funcs->C_GenerateKey(p11tool_pkcs11_session, (CK_MECHANISM *)&keytype->keygen_mech, secret_attrs, num_secret_attrs, &secret_key); if (rc != CKR_OK) { if (p11tool_is_rejected_by_policy(rc, p11tool_pkcs11_session)) { if (keysize == 0) warnx("Key generation of a %s key is rejected by policy", keytype->name); else warnx("Key generation of a %s key of size %lu is rejected by policy", keytype->name, keysize); } else { if (keysize == 0) warnx("Key generation of a %s key failed: 0x%lX: %s", keytype->name, rc, p11_get_ckr(rc)); else warnx("Key generation of a %s key of size %lu failed: 0x%lX: %s", keytype->name, keysize, rc, p11_get_ckr(rc)); } goto done; } if (keytype->is_asymmetric) printf("Successfully generated a %s key pair with labels \"%s\":\"%s\".\n", keytype->name, pub_label, priv_label); else printf("Successfully generated a %s key with label \"%s\".\n", keytype->name, opt_label); done: if (keytype->keygen_cleanup != NULL) keytype->keygen_cleanup(keytype, private); if (pub_label != NULL) free(pub_label); if (priv_label != NULL) free(priv_label); if (pub_attrs != NULL) free(pub_attrs); if (priv_attrs != NULL) free(priv_attrs); p11tool_free_attributes(secret_attrs, num_secret_attrs); p11tool_free_attributes(public_attrs, num_public_attrs); p11tool_free_attributes(private_attrs, num_private_attrs); return rc; } static void print_key_type_attr(const char *attr, const CK_ATTRIBUTE *val, int indent, bool sensitive) { const struct p11tool_objtype *ktype; const char *name = NULL; if ((val->ulValueLen == CK_UNAVAILABLE_INFORMATION && !sensitive) || val->ulValueLen != sizeof(CK_KEY_TYPE)) return; if (sensitive) { printf("%*s%s: [sensitive]\n", indent, "", attr); return; } ktype = find_keytype(*(CK_KEY_TYPE *)(val->pValue)); if (ktype != NULL) name = ktype->ck_name; if (name != NULL) printf("%*s%s: %s (0x%lX)\n", indent, "", attr, name, *(CK_KEY_TYPE *)(val->pValue)); else printf("%*s%s: 0x%lX\n", indent, "", attr, *(CK_KEY_TYPE *)(val->pValue)); } static void print_cert_type_attr(const char *attr, const CK_ATTRIBUTE *val, int indent, bool sensitive) { const struct p11tool_objtype *ctype; const char *name = NULL; if ((val->ulValueLen == CK_UNAVAILABLE_INFORMATION && !sensitive) || val->ulValueLen != sizeof(CK_CERTIFICATE_TYPE)) return; if (sensitive) { printf("%*s%s: [sensitive]\n", indent, "", attr); return; } ctype = find_certtype(*(CK_CERTIFICATE_TYPE *)(val->pValue)); if (ctype != NULL) name = ctype->ck_name; if (name != NULL) printf("%*s%s: %s (0x%lX)\n", indent, "", attr, name, *(CK_CERTIFICATE_TYPE *)(val->pValue)); else printf("%*s%s: 0x%lX\n", indent, "", attr, *(CK_CERTIFICATE_TYPE *)(val->pValue)); } static const struct p11tool_attr *find_attribute(CK_ATTRIBUTE_TYPE type) { const struct p11tool_attr *attr; const struct p11tool_objtype **keytype; for (attr = p11sak_bool_attrs; attr->name != NULL; attr++) { if (attr->type == type) return attr; } for (keytype = p11sak_keytypes; *keytype != NULL; keytype++) { for (attr = (*keytype)->secret_attrs; attr != NULL && attr->name != NULL; attr++) { if (attr->type == type) return attr; } for (attr = (*keytype)->public_attrs; attr != NULL && attr->name != NULL; attr++) { if (attr->type == type) return attr; } for (attr = (*keytype)->private_attrs; attr != NULL && attr->name != NULL; attr++) { if (attr->type == type) return attr; } } for (keytype = p11sak_certtypes; *keytype != NULL; keytype++) { for (attr = (*keytype)->cert_attrs; attr != NULL && attr->name != NULL; attr++) { if (attr->type == type) return attr; } } return NULL; } static void print_attr_array_attr(const char *attr, const CK_ATTRIBUTE *val, int indent, bool sensitive) { const struct p11tool_attr *a; unsigned int i, num; if (val->ulValueLen == CK_UNAVAILABLE_INFORMATION || (val->ulValueLen % sizeof(CK_ATTRIBUTE)) != 0) return; if (sensitive) { printf("%*s%s: [sensitive]\n", indent, "", attr); } else { num = val->ulValueLen / sizeof(CK_ATTRIBUTE); printf("%*s%s: %u attributes\n", indent, "", attr, num); for (i = 0; i < num; i++) { a = find_attribute(((CK_ATTRIBUTE *)(val->pValue))[i].type); if (a == NULL || a->print_long == NULL) printf("%*s%s: [attribute not supported]", indent + 4, "", p11_get_cka(((CK_ATTRIBUTE *)(val->pValue))[i].type)); else a->print_long(p11_get_cka( ((CK_ATTRIBUTE *)(val->pValue))[i].type), &((CK_ATTRIBUTE *)(val->pValue))[i], indent + 4, false); } } } static void print_custom_attrs(CK_OBJECT_HANDLE key, const struct p11tool_attr *standard_attrs, int indent) { CK_RV rc; int f; struct ConfigBaseNode *c, *name, *id, *type; struct ConfigStructNode *structnode; const struct p11sak_custom_attr_type *atype; const struct p11tool_attr *attr; CK_ATTRIBUTE val; bool skip; confignode_foreach(c, p11sak_cfg, f) { if (!confignode_hastype(c, CT_STRUCT) || strcmp(c->key, P11SAK_CONFIG_KEYWORD_ATTRIBUTE) != 0) continue; structnode = confignode_to_struct(c); name = confignode_find(structnode->value, P11SAK_CONFIG_KEYWORD_NAME); id = confignode_find(structnode->value, P11SAK_CONFIG_KEYWORD_ID); type = confignode_find(structnode->value, P11SAK_CONFIG_KEYWORD_TYPE); if (name == NULL || !confignode_hastype(name, CT_BAREVAL)) { warnx("Sytax error in config file: Missing '%s' in attribute at line %hu\n", P11SAK_CONFIG_KEYWORD_NAME, c->line); return; } if (id == NULL || !confignode_hastype(id, CT_INTVAL)) { warnx("Sytax error in config file: Missing '%s' in attribute at line %hu\n", P11SAK_CONFIG_KEYWORD_ID, c->line); return; } if (type == NULL || !confignode_hastype(type, CT_BAREVAL)) { warnx("Sytax error in config file: Missing '%s' in attribute at line %hu\n", P11SAK_CONFIG_KEYWORD_TYPE, c->line); return; } for (atype = custom_attr_types; atype->type != NULL; atype ++) { if (strcmp(atype->type, confignode_to_bareval(type)->value) == 0) break; } if (atype->type == NULL) { warnx("Sytax error in config file: Invalid '%s' value in attribute at line %hu\n", P11SAK_CONFIG_KEYWORD_TYPE, c->line); return; } /* Ignore any standard attributes also defined in the config file */ for (skip = false, attr = standard_attrs; attr != NULL && attr->name != NULL; attr++) { if (attr->type == confignode_to_intval(id)->value) { skip = true; break; } } if (skip) continue; val.type = confignode_to_intval(id)->value; val.ulValueLen = 0; val.pValue = NULL; rc = p11tool_get_attribute(key, &val); if (rc != CKR_OK && rc != CKR_ATTRIBUTE_SENSITIVE) continue; atype->print_long(confignode_to_bareval(name)->value, &val, indent, rc == CKR_ATTRIBUTE_SENSITIVE); if (p11tool_is_attr_array_attr(&val)) p11tool_free_attr_array_attr(&val); if (val.pValue != NULL) free(val.pValue); } } static void print_obj_attrs(CK_OBJECT_HANDLE key, CK_OBJECT_CLASS class, const struct p11tool_objtype *objtype, int indent) { const struct p11tool_attr *attrs, *attr; CK_ATTRIBUTE val; CK_RV rc; switch (class) { case CKO_SECRET_KEY: attrs = objtype->secret_attrs; break; case CKO_PUBLIC_KEY: attrs = objtype->public_attrs; break; case CKO_PRIVATE_KEY: attrs = objtype->private_attrs; break; case CKO_CERTIFICATE: attrs = objtype->cert_attrs; break; default: attrs = NULL; break; } for (attr = attrs; attr != NULL && attr->name != NULL; attr++) { val.type = attr->type; val.ulValueLen = 0; val.pValue = NULL; rc = p11tool_get_attribute(key, &val); if (rc != CKR_OK && rc != CKR_ATTRIBUTE_SENSITIVE) continue; attr->print_long(attr->name, &val, indent, rc == CKR_ATTRIBUTE_SENSITIVE); if (p11tool_is_attr_array_attr(&val)) p11tool_free_attr_array_attr(&val); if (val.pValue != NULL) free(val.pValue); } print_custom_attrs(key, attrs, indent); } static CK_RV print_boolean_attrs(CK_OBJECT_HANDLE obj, CK_OBJECT_CLASS class, const struct p11tool_objtype *objtype, const char *typestr, const char* label, struct p11sak_list_data *data) { const struct p11tool_attr *attr; bool applicable; CK_ULONG i; CK_RV rc; rc = p11tool_pkcs11_funcs->C_GetAttributeValue(p11tool_pkcs11_session, obj, data->bool_attrs, data->num_bool_attrs); if (rc != CKR_OK && rc != CKR_ATTRIBUTE_TYPE_INVALID) { warnx("Failed to get boolean attributes for %s %s \"%s\": 0x%lX: %s", typestr, objtype->obj_typestr, label, rc, p11_get_ckr(rc)); return rc; } for (attr = data->attrs, i = 0; attr->name != NULL; attr++, i++) { switch (class) { case CKO_SECRET_KEY: applicable = p11tool_secret_attr_applicable(objtype, attr); break; case CKO_PUBLIC_KEY: applicable = p11tool_public_attr_applicable(objtype, attr); break; case CKO_PRIVATE_KEY: applicable = p11tool_private_attr_applicable(objtype, attr); break; case CKO_CERTIFICATE: applicable = p11tool_cert_attr_applicable(objtype, attr); break; default: applicable = false; break; } if (data->bool_attrs[i].ulValueLen == CK_UNAVAILABLE_INFORMATION) applicable = false; if (opt_long) { if (!applicable) continue; attr->print_long(attr->name, &data->bool_attrs[i], 8, false); } else { attr->print_short(&data->bool_attrs[i], applicable); } } return CKR_OK; } static const CK_BYTE *p11sak_get_cca_wkvp(const struct p11tool_token_info *info, const CK_BYTE *secure_key, CK_ULONG secure_key_len, const char **mktype) { const struct cca_token_header *header = (const struct cca_token_header *)secure_key; CK_ULONG mkvp_offset = 0; if (secure_key_len <= sizeof(*header)) return NULL; /* * For token format, values and offsets, see manual "Common Cryptographic * Architecture Application Programmer's Guide" chapter 20 "Key token * formats" */ if (header->id == 0x01 && (header->version == 0x00 || header->version == 0x01)) { /* Internal secure CCA DES DATA key with exact 64 bytes */ mkvp_offset = sizeof(*header); *mktype = "CCA SYM"; } else if (header->id == 0x01 && header->version == 0x04) { /* Internal secure CCA AES DATA key with exact 64 bytes */ mkvp_offset = sizeof(*header); *mktype = "CCA AES"; } else if (header->id == 0x01 && header->version == 0x05) { /* Internal variable length secure CCA key */ if (secure_key_len < be16toh(header->len) || secure_key_len < 42) return NULL; if (secure_key[41] == 0x02 && be16toh(*((uint16_t*)(&secure_key[42]))) == 0x0001) { /* Internal variable length secure CCA AES CIPHER key */ mkvp_offset = 10; *mktype = "CCA AES"; } else if (secure_key[41] == 0x03 && be16toh(*((uint16_t*)(&secure_key[42]))) == 0x0002) { /* Internal variable length secure CCA HMAC key */ mkvp_offset = 10; *mktype = "CCA AES"; } else { return NULL; } } else if (header->id == 0x1f) { /* Internal secure CCA private key */ if (secure_key_len < be16toh(header->len)) return NULL; if (secure_key[sizeof(*header)] == 0x30) { /* Internal secure CCA private RSA key, ME format */ mkvp_offset = sizeof(*header) + 104; *mktype = "CCA APKA"; } else if (secure_key[sizeof(*header)] == 0x31) { /* Internal secure CCA private RSA key, CRT format */ mkvp_offset = sizeof(*header) + 116; *mktype = "CCA APKA"; } else if (secure_key[sizeof(*header)] == 0x20) { /* Internal secure CCA private ECC key */ mkvp_offset = sizeof(*header) + 16; *mktype = "CCA APKA"; } else if (secure_key[sizeof(*header)] == 0x50) { /* Internal secure CCA private QSA key */ mkvp_offset = sizeof(*header) + 118; *mktype = "CCA APKA"; } else { return NULL; } } else { return NULL; } if (secure_key_len < mkvp_offset + info->mkvp_size) return NULL; return &secure_key[mkvp_offset]; } static void p11sak_print_mkvp_cca_short(const struct p11tool_token_info *info, const CK_BYTE *secure_key, CK_ULONG secure_key_len, const char *separator) { unsigned int i; const CK_BYTE *mkvp; const char *mktype = NULL; mkvp = p11sak_get_cca_wkvp(info, secure_key, secure_key_len, &mktype); if (mkvp == NULL) { printf("%-*s | %-*s", MAX(LIST_MKVP_MIN_CELL_SIZE, info->mkvp_size * 2), "-", MAX(LIST_MKTYPE_MIN_CELL_SIZE, info->mktype_cell_size), "-"); return; } for (i = 0; i < info->mkvp_size; i++) printf("%02X", mkvp[i]); for (i = info->mkvp_size * 2; i < LIST_MKVP_MIN_CELL_SIZE; i++) printf(" "); printf("%s%-*s", separator, MAX(LIST_MKTYPE_MIN_CELL_SIZE, info->mktype_cell_size), mktype); } static void p11sak_print_mkvp_cca_long(const struct p11tool_token_info *info, const CK_BYTE *secure_key, CK_ULONG secure_key_len, int indent) { unsigned int i; const CK_BYTE *mkvp; const char *mktype = NULL; mkvp = p11sak_get_cca_wkvp(info, secure_key, secure_key_len, &mktype); if (mkvp == NULL) return; printf("%*sMKVP: ", indent, ""); for (i = 0; i < info->mkvp_size; i++) printf("%02X", mkvp[i]); printf(" (%s)\n", mktype); } static CK_RV p11sak_get_ep11_get_spki_len(const CK_BYTE *secure_key, CK_ULONG secure_key_len, CK_ULONG *spki_len) { CK_ULONG len, i, val = 0; /* * From the EP11 structure document: * Session identifiers are guaranteed not to have 0x30 as their first * byte. This allows a single-byte check to differentiate between blobs * starting with session identifiers, and MACed SPKIs, which may be * used as blobs under other conditions. * Key and state blobs start with the session identifier (32 bytes). * SPKIs start with a DER encoded SPKI, which itself stars with a SEQUENCE * denoted by 0x30 followed by the DER encoded length of the SPKI. */ if (secure_key_len > 5 && secure_key[0] == 0x30) { len = secure_key[1] & 0x7F; if (secure_key[1] & 0x80) { /* long form, len contains number of length bytes */ if (len > 4) return CKR_FUNCTION_FAILED; for (i = 0; i < len; i++) { if (i > 0) val <<= 8; val |= secure_key[2 + i]; } *spki_len = 2 + len + val; } else { /* short form */ *spki_len = 2 + len; } return CKR_OK; } /* No SPKI */ *spki_len = 0; return CKR_OK; } static const CK_BYTE *p11sak_get_ep11_wkvp(const struct p11tool_token_info *info, const CK_BYTE *secure_key, CK_ULONG secure_key_len) { CK_ULONG spki_len, wkid_len; if (p11sak_get_ep11_get_spki_len(secure_key, secure_key_len, &spki_len) != CKR_OK) return NULL; if (spki_len > 0) { /* An OCTET STRING with short form length must follow */ if (secure_key_len < spki_len + 2 || secure_key[spki_len] != 0x04) return NULL; wkid_len = secure_key[spki_len + 1]; if (wkid_len != info->mkvp_size) return NULL; return &secure_key[spki_len + 2]; } /* Secure key */ if (secure_key_len <= EP11_WKVP_OFFSET + info->mkvp_size) return NULL; return &secure_key[EP11_WKVP_OFFSET]; } static void p11sak_print_mkvp_ep11_short(const struct p11tool_token_info *info, const CK_BYTE *secure_key, CK_ULONG secure_key_len, const char *separator) { unsigned int i; const CK_BYTE *wkvp; wkvp = p11sak_get_ep11_wkvp(info, secure_key, secure_key_len); if (wkvp == NULL) { printf("%-*s | %-*s", MAX(LIST_MKVP_MIN_CELL_SIZE, info->mkvp_size * 2), "-", MAX(LIST_MKTYPE_MIN_CELL_SIZE, info->mktype_cell_size), "-"); return; } for (i = 0; i < info->mkvp_size; i++) printf("%02X", wkvp[i]); for (i = info->mkvp_size * 2; i < LIST_MKVP_MIN_CELL_SIZE; i++) printf(" "); printf("%s%-*s", separator, MAX(LIST_MKTYPE_MIN_CELL_SIZE, info->mktype_cell_size), "EP11-WK"); } static void p11sak_print_mkvp_ep11_long(const struct p11tool_token_info *info, const CK_BYTE *secure_key, CK_ULONG secure_key_len, int indent) { unsigned int i; const CK_BYTE *wkvp; wkvp = p11sak_get_ep11_wkvp(info, secure_key, secure_key_len); if (wkvp == NULL) return; printf("%*sMKVP: ", indent, ""); for (i = 0; i < info->mkvp_size; i++) printf("%02X", wkvp[i]); printf(" (EP11-WK)\n"); } static const CK_BYTE *p11sak_get_ep11_session_id( const struct p11tool_token_info *info, const CK_BYTE *secure_key, CK_ULONG secure_key_len) { CK_ULONG spki_len, wkid_len, sess_id_len; if (p11sak_get_ep11_get_spki_len(secure_key, secure_key_len, &spki_len) != CKR_OK) return NULL; if (spki_len > 0) { /* An OCTET STRING with short form length must follow */ if (secure_key_len < spki_len + 2 || secure_key[spki_len] != 0x04) return NULL; wkid_len = secure_key[spki_len + 1]; if (wkid_len != info->mkvp_size) return NULL; /* An OCTET STRING with short form length must follow */ if (secure_key_len < spki_len + 2 + wkid_len + 2 || secure_key[spki_len + 2 + wkid_len] != 0x04) return NULL; sess_id_len = secure_key[spki_len + 2 + wkid_len + 1]; if (sess_id_len != info->session_id_size) return NULL; return &secure_key[spki_len + 2 + wkid_len + 2]; } /* Secure key */ if (secure_key_len <= EP11_SESSION_ID_OFFSET + info->session_id_size) return NULL; return &secure_key[EP11_SESSION_ID_OFFSET]; } static const CK_BYTE ep11_null_session[32] = { 0 }; static void p11sak_print_session_id_ep11_short( const struct p11tool_token_info *info, const CK_BYTE *secure_key, CK_ULONG secure_key_len) { unsigned int i; const CK_BYTE *session_id; session_id = p11sak_get_ep11_session_id(info, secure_key, secure_key_len); if (session_id == NULL || memcmp(session_id, ep11_null_session, sizeof(ep11_null_session)) == 0) { printf("%-*s", MAX(LIST_SESS_MIN_CELL_SIZE, info->session_id_size * 2), "-"); return; } for (i = 0; i < info->session_id_size; i++) printf("%02X", session_id[i]); for (i = info->session_id_size * 2; i < LIST_SESS_MIN_CELL_SIZE; i++) printf(" "); } static void p11sak_print_session_id_ep11_long( const struct p11tool_token_info *info, const CK_BYTE *secure_key, CK_ULONG secure_key_len, int indent) { unsigned int i; const CK_BYTE *session_id; session_id = p11sak_get_ep11_session_id(info, secure_key, secure_key_len); if (session_id == NULL) return; if (memcmp(session_id, ep11_null_session, sizeof(ep11_null_session)) == 0) { printf("%*sSession-ID: [none]\n", indent, ""); return; } printf("%*sSession-ID: ", indent, ""); for (i = 0; i < info->session_id_size; i++) printf("%02X", session_id[i]); printf("\n"); } static CK_RV handle_obj_list(CK_OBJECT_HANDLE key, CK_OBJECT_CLASS class, const struct p11tool_objtype *objtype, CK_ULONG keysize, const char *typestr, const char* label, const char *common_name, void *private) { struct p11sak_list_data *data = private; struct p11_uri *uri = NULL; CK_ATTRIBUTE secure_key_attr = { 0 }; CK_RV rc; UNUSED(keysize); rc = p11tool_pkcs11_funcs->C_GetAttributeValue(p11tool_pkcs11_session, key, data->bool_attrs, data->num_bool_attrs); if (rc != CKR_OK && rc != CKR_ATTRIBUTE_TYPE_INVALID) { warnx("Failed to get boolean attributes for %s %s \"%s\": 0x%lX: %s", typestr, objtype->obj_typestr, label, rc, p11_get_ckr(rc)); return rc; } if ((opt_hsm_mkvp || opt_ep11_session_id) && p11tool_token_info != NULL) { /* Get secure key attr, ignore if key does not have that attribute */ secure_key_attr.type = p11tool_token_info->secure_key_attr; rc = p11tool_get_attribute(key, &secure_key_attr); if (rc != CKR_OK && rc != CKR_ATTRIBUTE_TYPE_INVALID) { warnx("Failed to retrieve attribute %s from object " "\"%s\": 0x%lX: %s", p11_get_ckm(&mechtable_funcs, secure_key_attr.type), label, rc, p11_get_ckr(rc)); return rc; } } if (opt_long) { rc = p11tool_prepare_uri(key, &class, objtype, typestr, label, opt_detailed_uri, opt_slot, &uri); if (rc != CKR_OK) goto done; printf("Label: \"%s\"\n", label); printf(" URI: %s\n", p11_uri_format(uri)); printf(" %s: %s\n", objtype->obj_liststr, typestr); if (opt_hsm_mkvp && p11tool_token_info != NULL && secure_key_attr.pValue != NULL && secure_key_attr.ulValueLen > 0) { p11tool_token_info->print_mkvp_long(p11tool_token_info, secure_key_attr.pValue, secure_key_attr.ulValueLen, 4); } if (opt_ep11_session_id && p11tool_token_info != NULL && secure_key_attr.pValue != NULL && secure_key_attr.ulValueLen > 0 && p11tool_token_info->print_session_id_long != NULL) { p11tool_token_info->print_session_id_long(p11tool_token_info, secure_key_attr.pValue, secure_key_attr.ulValueLen, 4); } printf(" Attributes:\n"); printf(" CKA_TOKEN: CK_TRUE\n"); } else { printf("| "); } if (!opt_long && opt_hsm_mkvp && p11tool_token_info != NULL) { if (secure_key_attr.pValue != NULL && secure_key_attr.ulValueLen > 0) p11tool_token_info->print_mkvp_short(p11tool_token_info, secure_key_attr.pValue, secure_key_attr.ulValueLen, " | "); else printf("%-*s | %-*s", MAX(LIST_MKVP_MIN_CELL_SIZE, p11tool_token_info->mkvp_size * 2), "-", MAX(LIST_MKTYPE_MIN_CELL_SIZE, p11tool_token_info->mktype_cell_size), "-"); printf(" "); } else if (!opt_long && opt_ep11_session_id && p11tool_token_info != NULL) { if (secure_key_attr.pValue != NULL && secure_key_attr.ulValueLen > 0 && p11tool_token_info->print_session_id_short != NULL) p11tool_token_info->print_session_id_short(p11tool_token_info, secure_key_attr.pValue, secure_key_attr.ulValueLen); else printf("%-*s", MAX(LIST_SESS_MIN_CELL_SIZE, p11tool_token_info->session_id_size * 2), "-"); printf(" "); } else { rc = print_boolean_attrs(key, class, objtype, typestr, label, data); if (rc != CKR_OK) goto done; } if (opt_long) print_obj_attrs(key, class, objtype, 8); else { if (data->objclass != OBJCLASS_CERTIFICATE) { printf("| %*s | \"%s\"\n", LIST_KEYTYPE_CELL_SIZE, typestr, label); } else { char display_name[LIST_CERT_CN_CELL_SIZE + 1] = { 0 }; int len = strlen(common_name); if (len > LIST_CERT_CN_CELL_SIZE) { strncpy(display_name, common_name, LIST_CERT_CN_CELL_SIZE - 3); strcat(display_name, "..."); } else { strcpy(display_name, common_name); } printf("| %*s | %*s | \"%s\"\n", LIST_CERTTYPE_CELL_SIZE, typestr, LIST_CERT_CN_CELL_SIZE, display_name, label); } } data->num_displayed++; rc = CKR_OK; done: if (uri != NULL) { if (uri->obj_id[0].pValue != NULL) free(uri->obj_id[0].pValue); p11_uri_free(uri); } if (secure_key_attr.pValue != NULL) free(secure_key_attr.pValue); return rc; } static CK_RV p11sak_list_obj_compare(CK_OBJECT_HANDLE obj1, CK_OBJECT_HANDLE obj2, int *result, void *private) { struct p11sak_list_data *data = private; CK_OBJECT_CLASS class1, class2; CK_KEY_TYPE ktype1, ktype2; CK_ULONG keysize1 = 0, keysize2 = 0; char *label1 = NULL, *label2 = NULL; char *cn1 = NULL, *cn2 = NULL; CK_RV rc; int i; *result = 0; rc = get_obj_infos(obj1, &class1, &ktype1, &keysize1, &label1, NULL, NULL, &cn1); if (rc != CKR_OK) goto done; rc = get_obj_infos(obj2, &class2, &ktype2, &keysize2, &label2, NULL, NULL, &cn2); if (rc != CKR_OK) goto done; for (i = 0; i < MAX_SORT_FIELDS; i++) { switch (data->sort_info[i].field) { case SORT_LABEL: if (label1 == NULL || label2 == NULL) break; *result = strcmp(label1, label2); break; case SORT_KEYTYPE: *result = (long)ktype1 - (long)ktype2; break; case SORT_CLASS: *result = (long)class1 - (long)class2; break; case SORT_KEYSIZE: *result = (long)keysize1 - (long)keysize2; break; case SORT_CN: if (cn1 == NULL || cn2 == NULL) break; *result = strcmp(cn1, cn2); break; case SORT_NONE: default: break; } if (data->sort_info[i].descending) *result = -*result; if (*result != 0) break; } done: if (label1 != NULL) free(label1); if (label2 != NULL) free(label2); if (cn1 != NULL) free(cn1); if (cn2 != NULL) free(cn2); return rc; } static CK_RV parse_sort_specification(const char *sort_spec, struct p11sak_list_data *data) { CK_RV rc = CKR_OK; char *tok; unsigned int i = 0; char *spec; spec = strdup(sort_spec); if (spec == NULL) { warnx("Failed to allocate the sort specification string."); return CKR_HOST_MEMORY; } tok = strtok(spec, ","); while (tok != NULL) { if (i >= MAX_SORT_FIELDS) { warnx("Too many sort field designators."); rc = CKR_ARGUMENTS_BAD; goto done; } switch (data->objclass) { case OBJCLASS_CERTIFICATE: switch (tolower(*tok)) { case 'l': data->sort_info[i].field = SORT_LABEL; break; case 'n': data->sort_info[i].field = SORT_CN; break; default: warnx("Invalid sort field designator: '%c'.", *tok); rc = CKR_ARGUMENTS_BAD; goto done; } break; case OBJCLASS_KEY: switch (tolower(*tok)) { case 'l': data->sort_info[i].field = SORT_LABEL; break; case 'k': data->sort_info[i].field = SORT_KEYTYPE; break; case 'c': data->sort_info[i].field = SORT_CLASS; break; case 's': data->sort_info[i].field = SORT_KEYSIZE; break; default: warnx("Invalid sort field designator: '%c'.", *tok); rc = CKR_ARGUMENTS_BAD; goto done; } break; default: warnx("Cannot sort objects of class %d", data->objclass); rc = CKR_ARGUMENTS_BAD; goto done; } tok++; if (*tok == ':') { tok++; switch (tolower(*tok)) { case 'a': data->sort_info[i].descending = false; break; case 'd': data->sort_info[i].descending = true; break; default: warnx("Invalid sort order designator: '%c'.", *tok); rc = CKR_ARGUMENTS_BAD; goto done; } tok++; if (*tok != '\0') { warnx("Invalid character(s) after sort order designator: '%s'.", tok); rc = CKR_ARGUMENTS_BAD; goto done; } } else if (*tok == '\0') { data->sort_info[i].descending = false; } else { warnx("Invalid character(s) after sort field designator: '%s'.", tok); rc = CKR_ARGUMENTS_BAD; goto done; } tok = strtok(NULL, ","); i++; } done: free(spec); return rc; } static CK_RV p11sak_list_key(void) { const struct p11tool_objtype *keytype = NULL; const struct p11tool_attr *attr; struct p11sak_list_data data = { 0 }; unsigned int i; CK_BYTE *attr_data = NULL; CK_RV rc; if (opt_keytype != NULL) keytype = opt_keytype->private.ptr; if (opt_hsm_mkvp && p11tool_token_info == NULL) { warnx("Option '-m'/'--hsm-mkvp' can only be used with secure key " "tokens"); rc = CKR_ARGUMENTS_BAD; goto done; } if (opt_ep11_session_id && (p11tool_token_info == NULL || (p11tool_token_info != NULL && p11tool_token_info->type != TOKTYPE_EP11))) { warnx("Option '-e'/'--ep11-session-id' can only be used with an EP11 " "token"); rc = CKR_ARGUMENTS_BAD; goto done; } if (!opt_long && opt_hsm_mkvp && opt_ep11_session_id) { warnx("Either '-m'/'--hsm-mkvp' or '-e'/'--ep11-session-id' can can be " "specified, unless '-l'/'--long' is also specified"); rc = CKR_ARGUMENTS_BAD; goto done; } for (attr = p11sak_bool_attrs, data.num_bool_attrs = 0; attr->name != NULL; attr++, data.num_bool_attrs++) ; attr_data = calloc(data.num_bool_attrs, sizeof(CK_BBOOL)); data.bool_attrs = calloc(data.num_bool_attrs, sizeof(CK_ATTRIBUTE)); if (attr_data == NULL || data.bool_attrs == NULL) { warnx("Failed to allocate memory for the attributes"); rc = CKR_HOST_MEMORY; goto done; } for (attr = p11sak_bool_attrs, i = 0; attr->name != NULL; attr++, i++) { data.bool_attrs[i].type = attr->type; data.bool_attrs[i].ulValueLen = sizeof(CK_BBOOL); data.bool_attrs[i].pValue = &attr_data[i]; } data.attrs = p11sak_bool_attrs; data.objclass = OBJCLASS_KEY; if (opt_sort) { rc = parse_sort_specification(opt_sort, &data); if (rc != CKR_OK) goto done; } if (opt_hsm_mkvp && !opt_long) { printf("| MASTER KEY VERIFICATION PATTERN "); for(i = LIST_MKVP_MIN_CELL_SIZE; i < p11tool_token_info->mkvp_size * 2; i++) printf(" "); printf(" | %-*s ", MAX(LIST_MKTYPE_MIN_CELL_SIZE, p11tool_token_info->mktype_cell_size), "MK TYPE"); printf("| %*s | LABEL\n", LIST_KEYTYPE_CELL_SIZE, "KEY TYPE"); printf("|-"); for(i = 0; i < MAX(LIST_MKVP_MIN_CELL_SIZE, p11tool_token_info->mkvp_size * 2); i++) printf("-"); printf("-+-"); for (i = 0; i < MAX(LIST_MKTYPE_MIN_CELL_SIZE, p11tool_token_info->mktype_cell_size); i++) printf("-"); printf("-+-"); for (i = 0; i < LIST_KEYTYPE_CELL_SIZE; i++) printf("-"); printf("-+--------------------\n"); } else if (opt_ep11_session_id && !opt_long) { printf("| EP11 SESSION ID "); for(i = LIST_SESS_MIN_CELL_SIZE; i < p11tool_token_info->session_id_size * 2; i++) printf(" "); printf(" | %*s | LABEL\n", LIST_KEYTYPE_CELL_SIZE, "KEY TYPE"); printf("|-"); for(i = 0; i < MAX(LIST_SESS_MIN_CELL_SIZE, p11tool_token_info->session_id_size * 2); i++) printf("-"); printf("-+-"); for (i = 0; i < LIST_KEYTYPE_CELL_SIZE; i++) printf("-"); printf("-+--------------------\n"); } else if (!opt_long) { printf("| "); for (attr = p11sak_bool_attrs; attr->name != NULL; attr++) printf("%c ", attr->letter); printf("| %*s | LABEL\n", LIST_KEYTYPE_CELL_SIZE, "KEY TYPE"); printf("|-"); for (attr = p11sak_bool_attrs; attr->name != NULL; attr++) printf("--"); printf("+-"); for (i = 0; i < LIST_KEYTYPE_CELL_SIZE; i++) printf("-"); printf("-+--------------------\n"); } rc = iterate_objects(keytype, opt_label, opt_id, opt_attr, OBJCLASS_KEY, opt_sort != NULL ? p11sak_list_obj_compare : NULL, handle_obj_list, &data); if (rc != CKR_OK) { warnx("Failed to iterate over key objects for key type %s: 0x%lX: %s", keytype != NULL ? keytype->name : "All", rc, p11_get_ckr(rc)); goto done; } printf("\n"); printf("%lu key(s) displayed\n", data.num_displayed); done: if (data.bool_attrs != NULL) free(data.bool_attrs); if (attr_data != NULL) free(attr_data); return rc; } static CK_RV p11sak_list_cert(void) { const struct p11tool_objtype *certtype = NULL; const struct p11tool_attr *attr; struct p11sak_list_data data = { 0 }; unsigned int i; CK_BYTE *attr_data = NULL; CK_RV rc; if (opt_certtype != NULL) certtype = opt_certtype->private.ptr; for (attr = p11sak_bool_cert_attrs, data.num_bool_attrs = 0; attr->name != NULL; attr++, data.num_bool_attrs++) ; attr_data = calloc(data.num_bool_attrs, sizeof(CK_BBOOL)); data.bool_attrs = calloc(data.num_bool_attrs, sizeof(CK_ATTRIBUTE)); if (attr_data == NULL || data.bool_attrs == NULL) { warnx("Failed to allocate memory for the attributes"); rc = CKR_HOST_MEMORY; goto done; } for (attr = p11sak_bool_cert_attrs, i = 0; attr->name != NULL; attr++, i++) { data.bool_attrs[i].type = attr->type; data.bool_attrs[i].ulValueLen = sizeof(CK_BBOOL); data.bool_attrs[i].pValue = &attr_data[i]; } data.attrs = p11sak_bool_cert_attrs; data.objclass = OBJCLASS_CERTIFICATE; if (opt_sort) { rc = parse_sort_specification(opt_sort, &data); if (rc != CKR_OK) goto done; } if (!opt_long) { printf("| "); for (attr = p11sak_bool_cert_attrs; attr->name != NULL; attr++) printf("%c ", attr->letter); printf("| %*s | SUBJECT-CN | LABEL\n", LIST_CERTTYPE_CELL_SIZE, "CERT TYPE"); printf("|-"); for (attr = p11sak_bool_cert_attrs; attr->name != NULL; attr++) printf("--"); printf("+-"); for (i = 0; i < LIST_CERTTYPE_CELL_SIZE; i++) printf("-"); printf("-+------------------------+-------------------------\n"); } rc = iterate_objects(certtype, opt_label, opt_id, opt_attr, OBJCLASS_CERTIFICATE, opt_sort != NULL ? p11sak_list_obj_compare : NULL, handle_obj_list, &data); if (rc != CKR_OK) { warnx("Failed to iterate over certificate objects for type %s: 0x%lX: %s", certtype != NULL ? certtype->name : "All", rc, p11_get_ckr(rc)); goto done; } printf("\n"); printf("%lu certificate(s) displayed\n", data.num_displayed); done: if (data.bool_attrs != NULL) free(data.bool_attrs); if (attr_data != NULL) free(attr_data); return rc; } static CK_RV handle_obj_remove(CK_OBJECT_HANDLE key, CK_OBJECT_CLASS class, const struct p11tool_objtype *keytype, CK_ULONG keysize, const char *typestr, const char* label, const char *common_name, void *private) { struct p11sak_remove_data *data = private; char *msg = NULL; char ch; CK_RV rc; UNUSED(class); UNUSED(keysize); UNUSED(common_name); if (data->skip_all) { data->num_skipped++; return CKR_OK; } if (!data->remove_all) { if (asprintf(&msg, "Are you sure you want to remove %s %s object \"%s\" [y/n/a/c]? ", typestr, keytype->obj_typestr, label) < 0 || msg == NULL) { warnx("Failed to allocate memory for a message"); return CKR_HOST_MEMORY; } ch = p11tool_prompt_user(msg, "ynac"); free(msg); switch (ch) { case 'n': data->num_skipped++; return CKR_OK; case 'c': case '\0': data->skip_all = true; data->num_skipped++; return CKR_OK; case 'a': data->remove_all = true; break; default: break; } } rc = p11tool_pkcs11_funcs->C_DestroyObject(p11tool_pkcs11_session, key); if (rc != CKR_OK) { warnx("Failed to remove %s %s object \"%s\": C_DestroyObject: 0x%lX: %s", typestr, keytype->obj_typestr, label, rc, p11_get_ckr(rc)); data->num_failed++; return CKR_OK; } printf("Successfully removed %s %s object \"%s\".\n", typestr, keytype->obj_typestr, label); data->num_removed++; return CKR_OK; } static CK_RV p11sak_remove_key(void) { const struct p11tool_objtype *keytype = NULL; struct p11sak_remove_data data = { 0 }; CK_RV rc; if (opt_keytype != NULL) keytype = opt_keytype->private.ptr; data.remove_all = opt_force; rc = iterate_objects(keytype, opt_label, opt_id, opt_attr, OBJCLASS_KEY, NULL, handle_obj_remove, &data); if (rc != CKR_OK) { warnx("Failed to iterate over key objects for key type %s: 0x%lX: %s", keytype != NULL ? keytype->name : "All", rc, p11_get_ckr(rc)); return rc; } printf("%lu key object(s) removed.\n", data.num_removed); if (data.num_skipped > 0) printf("%lu key object(s) skipped.\n", data.num_skipped); if (data.num_failed > 0) printf("%lu key object(s) failed to remove.\n", data.num_failed); return data.num_failed == 0 ? CKR_OK : CKR_FUNCTION_FAILED; } static CK_RV p11sak_remove_cert(void) { const struct p11tool_objtype *certtype = NULL; struct p11sak_remove_data data = { 0 }; CK_RV rc; if (opt_certtype != NULL) certtype = opt_certtype->private.ptr; data.remove_all = opt_force; rc = iterate_objects(certtype, opt_label, opt_id, opt_attr, OBJCLASS_CERTIFICATE, NULL, handle_obj_remove, &data); if (rc != CKR_OK) { warnx("Failed to iterate over certificate objects for type %s: 0x%lX: %s", certtype != NULL ? certtype->name : "All", rc, p11_get_ckr(rc)); return rc; } printf("%lu certificate object(s) removed.\n", data.num_removed); if (data.num_skipped > 0) printf("%lu certificate object(s) skipped.\n", data.num_skipped); if (data.num_failed > 0) printf("%lu certificate object(s) failed to remove.\n", data.num_failed); return data.num_failed == 0 ? CKR_OK : CKR_FUNCTION_FAILED; } static CK_RV handle_obj_set_attr(CK_OBJECT_HANDLE obj, CK_OBJECT_CLASS class, const struct p11tool_objtype *objtype, CK_ULONG keysize, const char *typestr, const char* label, const char *common_name, void *private) { struct p11sak_set_attr_data *data = private; CK_ATTRIBUTE *attrs = NULL; CK_ULONG num_attrs = 0; char *msg = NULL; char ch; CK_RV rc; bool (*attr_applicable)(const struct p11tool_objtype *objtype, const struct p11tool_attr *attr); UNUSED(keysize); UNUSED(common_name); if (data->skip_all) { data->num_skipped++; return CKR_OK; } if (!data->set_all) { if (asprintf(&msg, "Are you sure you want to change %s %s object \"%s\" [y/n/a/c]? ", typestr, objtype->obj_typestr, label) < 0 || msg == NULL) { warnx("Failed to allocate memory for a message"); return CKR_HOST_MEMORY; } ch = p11tool_prompt_user(msg, "ynac"); free(msg); switch (ch) { case 'n': data->num_skipped++; return CKR_OK; case 'c': case '\0': data->skip_all = true; data->num_skipped++; return CKR_OK; case 'a': data->set_all = true; break; default: break; } } switch (class) { case CKO_SECRET_KEY: attr_applicable = p11tool_secret_attr_applicable; break; case CKO_PUBLIC_KEY: attr_applicable = p11tool_public_attr_applicable; break; case CKO_PRIVATE_KEY: attr_applicable = p11tool_private_attr_applicable; break; case CKO_CERTIFICATE: attr_applicable = p11tool_cert_attr_applicable; break; default: warnx("Object \"%s\" has an unsupported object class: %lu", label, class); rc = CKR_KEY_TYPE_INCONSISTENT; goto done; } if (opt_new_attr != NULL) { rc = p11tool_parse_boolean_attrs(objtype, p11sak_bool_attrs, opt_new_attr, &attrs, &num_attrs, true, opt_so, attr_applicable); if (rc != CKR_OK) { data->num_failed++; goto done; } if (num_attrs == 0) { warnx("None of the specified attributes apply to %s %s object \"%s\".", typestr, objtype->obj_typestr, label); data->num_skipped++; goto done; } } if (opt_new_label != NULL) { rc = p11tool_add_attribute(CKA_LABEL, opt_new_label, strlen(opt_new_label), &attrs, &num_attrs); if (rc != CKR_OK) { warnx("Failed to add %s %s attribute CKA_LABEL: 0x%lX: %s", objtype->name, objtype->obj_typestr, rc, p11_get_ckr(rc)); goto done; } } if (opt_new_id != NULL) { rc = p11tool_parse_id(opt_new_id, &attrs, &num_attrs); if (rc != CKR_OK) goto done; } rc = p11tool_pkcs11_funcs->C_SetAttributeValue(p11tool_pkcs11_session, obj, attrs, num_attrs); if (rc != CKR_OK) { warnx("Failed to change %s %s object \"%s\": C_SetAttributeValue: 0x%lX: %s", typestr, objtype->obj_typestr, label, rc, p11_get_ckr(rc)); data->num_failed++; rc = CKR_OK; goto done; } printf("Successfully changed %s %s object \"%s\".\n", typestr, objtype->obj_typestr, label); data->num_set++; done: p11tool_free_attributes(attrs, num_attrs); return rc; } static CK_RV p11sak_set_key_attr(void) { const struct p11tool_objtype *keytype = NULL; struct p11sak_set_attr_data data = { 0 }; CK_RV rc; if (opt_keytype != NULL) keytype = opt_keytype->private.ptr; if (opt_new_attr == NULL && opt_new_label == NULL && opt_new_id == NULL) { warnx("At least one of the following options must be specified:"); warnx("'-A'/'--new-attr', '-l'/'--new-label', or '-I'/'--new-id'"); return CKR_ARGUMENTS_BAD; } data.set_all = opt_force; rc = iterate_objects(keytype, opt_label, opt_id, opt_attr, OBJCLASS_KEY, NULL, handle_obj_set_attr, &data); if (rc != CKR_OK) { warnx("Failed to iterate over key objects for key type %s: 0x%lX: %s", keytype != NULL ? keytype->name : "All", rc, p11_get_ckr(rc)); return rc; } printf("%lu key object(s) updated.\n", data.num_set); if (data.num_skipped > 0) printf("%lu key object(s) skipped.\n", data.num_skipped); if (data.num_failed > 0) printf("%lu key object(s) failed to update.\n", data.num_failed); return data.num_failed == 0 ? CKR_OK : CKR_FUNCTION_FAILED; } static CK_RV p11sak_set_cert_attr(void) { const struct p11tool_objtype *certtype = NULL; struct p11sak_set_attr_data data = { 0 }; CK_RV rc; if (opt_certtype != NULL) certtype = opt_certtype->private.ptr; if (opt_new_attr == NULL && opt_new_label == NULL && opt_new_id == NULL) { warnx("At least one of the following options must be specified:"); warnx("'-A'/'--new-attr', '-l'/'--new-label', or '-I'/'--new-id'"); return CKR_ARGUMENTS_BAD; } data.set_all = opt_force; rc = iterate_objects(certtype, opt_label, opt_id, opt_attr, OBJCLASS_CERTIFICATE, NULL, handle_obj_set_attr, &data); if (rc != CKR_OK) { warnx("Failed to iterate over certificate objects for cert type %s: 0x%lX: %s", certtype != NULL ? certtype->name : "All", rc, p11_get_ckr(rc)); return rc; } printf("%lu certificate object(s) updated.\n", data.num_set); if (data.num_skipped > 0) printf("%lu certificate object(s) skipped.\n", data.num_skipped); if (data.num_failed > 0) printf("%lu certificate object(s) failed to update.\n", data.num_failed); return data.num_failed == 0 ? CKR_OK : CKR_FUNCTION_FAILED; } static CK_RV handle_obj_copy(CK_OBJECT_HANDLE key, CK_OBJECT_CLASS class, const struct p11tool_objtype *objtype, CK_ULONG keysize, const char *typestr, const char* label, const char *common_name, void *private) { struct p11sak_copy_data *data = private; CK_ATTRIBUTE *attrs = NULL; CK_ULONG num_attrs = 0; CK_OBJECT_HANDLE new_key = CK_INVALID_HANDLE; char *msg = NULL; char ch; CK_RV rc; bool (*attr_applicable)(const struct p11tool_objtype *objtype, const struct p11tool_attr *attr); UNUSED(keysize); UNUSED(common_name); if (data->skip_all) { data->num_skipped++; return CKR_OK; } if (!data->copy_all) { if (asprintf(&msg, "Are you sure you want to copy %s %s object \"%s\" [y/n/a/c]? ", objtype->obj_typestr, typestr, label) < 0 || msg == NULL) { warnx("Failed to allocate memory for a message"); return CKR_HOST_MEMORY; } ch = p11tool_prompt_user(msg, "ynac"); free(msg); switch (ch) { case 'n': data->num_skipped++; return CKR_OK; case 'c': case '\0': data->skip_all = true; data->num_skipped++; return CKR_OK; case 'a': data->copy_all = true; break; default: break; } } switch (class) { case CKO_SECRET_KEY: attr_applicable = p11tool_secret_attr_applicable; break; case CKO_PUBLIC_KEY: attr_applicable = p11tool_public_attr_applicable; break; case CKO_PRIVATE_KEY: attr_applicable = p11tool_private_attr_applicable; break; case CKO_CERTIFICATE: attr_applicable = p11tool_cert_attr_applicable; break; default: warnx("Object \"%s\" has an unsupported object class: %lu", label, class); rc = CKR_KEY_TYPE_INCONSISTENT; goto done; } if (opt_new_attr != NULL) { rc = p11tool_parse_boolean_attrs(objtype, p11sak_bool_attrs, opt_new_attr, &attrs, &num_attrs, true, opt_so, attr_applicable); if (rc != CKR_OK) { data->num_failed++; goto done; } } if (opt_new_label != NULL) { rc = p11tool_add_attribute(CKA_LABEL, opt_new_label, strlen(opt_new_label), &attrs, &num_attrs); if (rc != CKR_OK) { warnx("Failed to add %s %s attribute CKA_LABEL: 0x%lX: %s", objtype->name, objtype->obj_typestr, rc, p11_get_ckr(rc)); data->num_failed++; goto done; } } if (opt_new_id != NULL) { rc = p11tool_parse_id(opt_new_id, &attrs, &num_attrs); if (rc != CKR_OK) { data->num_failed++; goto done; } } rc = p11tool_pkcs11_funcs->C_CopyObject(p11tool_pkcs11_session, key, attrs, num_attrs, &new_key); if (rc != CKR_OK) { warnx("Failed to copy %s key object \"%s\": C_CopyObject: 0x%lX: %s", typestr, label, rc, p11_get_ckr(rc)); data->num_failed++; rc = CKR_OK; goto done; } printf("Successfully copied %s key object \"%s\".\n", typestr, label); data->num_copied++; done: p11tool_free_attributes(attrs, num_attrs); return rc; } static CK_RV p11sak_copy_key(void) { const struct p11tool_objtype *keytype = NULL; struct p11sak_copy_data data = { 0 }; CK_RV rc; if (opt_keytype != NULL) keytype = opt_keytype->private.ptr; data.copy_all = opt_force; rc = iterate_objects(keytype, opt_label, opt_id, opt_attr, OBJCLASS_KEY, NULL, handle_obj_copy, &data); if (rc != CKR_OK) { warnx("Failed to iterate over key objects for key type %s: 0x%lX: %s", keytype != NULL ? keytype->name : "All", rc, p11_get_ckr(rc)); return rc; } printf("%lu key object(s) copied.\n", data.num_copied); if (data.num_skipped > 0) printf("%lu key object(s) skipped.\n", data.num_skipped); if (data.num_failed > 0) printf("%lu key object(s) failed to copy.\n", data.num_failed); return data.num_failed == 0 ? CKR_OK : CKR_FUNCTION_FAILED; } static CK_RV p11sak_copy_cert(void) { const struct p11tool_objtype *certtype = NULL; struct p11sak_copy_data data = { 0 }; CK_RV rc; if (opt_keytype != NULL) certtype = opt_keytype->private.ptr; data.copy_all = opt_force; rc = iterate_objects(certtype, opt_label, opt_id, opt_attr, OBJCLASS_CERTIFICATE, NULL, handle_obj_copy, &data); if (rc != CKR_OK) { warnx("Failed to iterate over certificate objects for type %s: 0x%lX: %s", certtype != NULL ? certtype->name : "All", rc, p11_get_ckr(rc)); return rc; } printf("%lu certificate object(s) copied.\n", data.num_copied); if (data.num_skipped > 0) printf("%lu certificate object(s) skipped.\n", data.num_skipped); if (data.num_failed > 0) printf("%lu certificate object(s) failed to copy.\n", data.num_failed); return data.num_failed == 0 ? CKR_OK : CKR_FUNCTION_FAILED; } static CK_RV p11sak_import_check_des_keysize( const struct p11tool_objtype *keytype, CK_ULONG keysize) { if (keysize != 8) { warnx("Size of %s key is invalid, expected 8 bytes", keytype->name); return CKR_ARGUMENTS_BAD; } return CKR_OK; } static CK_RV p11sak_import_check_3des_keysize( const struct p11tool_objtype *keytype, CK_ULONG keysize) { if (keysize != 24) { warnx("Size of %s key is invalid, expected 24 bytes", keytype->name); return CKR_ARGUMENTS_BAD; } return CKR_OK; } static CK_RV p11sak_import_check_generic_keysize( const struct p11tool_objtype *keytype, CK_ULONG keysize) { if (keysize == 0) { warnx("Size of %s key is invalid, expected at least one byte", keytype->name); return CKR_ARGUMENTS_BAD; } return CKR_OK; } static CK_RV p11sak_import_check_aes_keysize( const struct p11tool_objtype *keytype, CK_ULONG keysize) { if (keysize != 16 && keysize != 24 && keysize != 32) { warnx("Size of %s key is invalid, expected 16, 24, or 32 bytes", keytype->name); return CKR_ARGUMENTS_BAD; } return CKR_OK; } static CK_RV p11sak_import_check_aes_xts_keysize( const struct p11tool_objtype *keytype, CK_ULONG keysize) { if (keysize != 32 && keysize != 64) { warnx("Size of %s key is invalid, expected 32 or 64 bytes", keytype->name); return CKR_ARGUMENTS_BAD; } return CKR_OK; } static CK_RV p11sak_import_sym_clear_des_3des_aes_generic( const struct p11tool_objtype *keytype, CK_BYTE *data, CK_ULONG data_len, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs) { UNUSED(keytype); return p11tool_add_attribute(CKA_VALUE, data, data_len, attrs, num_attrs); } /* * Imports the common attrs applicable for CKO_CERTIFICATE */ static CK_RV p11sak_import_cert_attrs(const struct p11tool_objtype *certtype, X509 *x509, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs) { const ASN1_TIME *not_before, *not_after; CK_BYTE *value_buf = NULL; CK_BYTE check_buf[20]; CK_DATE start_date, end_date; EVP_PKEY *pkey = NULL; CK_BYTE *spki = NULL; int spki_len, value_len; EVP_MD_CTX *ctx = NULL; unsigned int digest_len; CK_RV rc = CKR_OK; UNUSED(certtype); /* CKA_START_DATE: CK_DATE struct of certificate start date */ not_before = X509_get0_notBefore(x509); rc = p11tool_ASN1_TIME2date(not_before, &start_date); if (rc != CKR_OK) goto done; /* CKA_END_DATE: CK_DATE struct of certificate end date */ not_after = X509_get0_notAfter(x509); rc = p11tool_ASN1_TIME2date(not_after, &end_date); if (rc != CKR_OK) goto done; /* CKA_PUBLIC_KEY_INFO: DER-encoding of the SubjectPublicKeyInfo */ pkey = X509_get_pubkey(x509); if (pkey == NULL) { warnx("509_get_pubkey failed to get the EVP_PKEY from X509"); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } spki_len = i2d_PUBKEY(pkey, &spki); if (spki_len <= 0) { warnx("openssl i2d_PUBKEY failed to create spki from EVP_PKEY"); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } /* CKA_VALUE: only needed for CKA_CHECK_VALUE below */ value_len = i2d_X509(x509, &value_buf); if (value_len <= 0) { warnx("i2d_X509 failed to convert the x509 into a buffer for cert's CKA_VALUE"); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_HOST_MEMORY; goto done; } /* CKA_CHECK_VALUE: first 3 bytes of the SHA-1 hash of CKA_VALUE */ ctx = EVP_MD_CTX_new(); if (ctx == NULL) { warnx("Error creating MD_CTX for CKA_CHECK_VALUE"); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } if (!EVP_DigestInit(ctx, EVP_sha1()) || !EVP_DigestUpdate(ctx, value_buf, value_len) || !EVP_DigestFinal(ctx, check_buf, &digest_len)) { warnx("Error creating sha1 hash for CKA_CHECK_VALUE"); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } /* Add attributes */ rc = p11tool_add_attribute(CKA_CERTIFICATE_TYPE, &certtype->type, sizeof(certtype->type), attrs, num_attrs); rc += p11tool_add_attribute(CKA_START_DATE, &start_date, sizeof(CK_DATE), attrs, num_attrs); rc += p11tool_add_attribute(CKA_END_DATE, &end_date, sizeof(CK_DATE), attrs, num_attrs); rc += p11tool_add_attribute(CKA_PUBLIC_KEY_INFO, spki, spki_len, attrs, num_attrs); rc += p11tool_add_attribute(CKA_CHECK_VALUE, check_buf, 3, attrs, num_attrs); if (rc != CKR_OK) { warnx("Failed to add attributes for imported certificate."); rc = CKR_FUNCTION_FAILED; goto done; } rc = CKR_OK; done: if (pkey != NULL) EVP_PKEY_free(pkey); if (ctx != NULL) EVP_MD_CTX_free(ctx); if (spki != NULL) OPENSSL_free(spki); if (value_buf != NULL) OPENSSL_free(value_buf); return rc; } /* * Imports attributes for X.509 public key certificates */ static CK_RV p11sak_import_x509_attrs(const struct p11tool_objtype *certtype, X509 *x509, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs) { ASN1_INTEGER *serialno; unsigned char *serial_buf = NULL; #if OPENSSL_VERSION_PREREQ(4, 0) const X509_NAME *name; #else X509_NAME *name; #endif const unsigned char *subj_name = NULL, *issuer_name = NULL; size_t subj_name_len, issuer_name_len; CK_BYTE *value_buf = NULL; EVP_PKEY *pkey = NULL; unsigned char *spki = NULL; unsigned char spki_hash[32]; CK_ULONG spki_hash_len; int spki_len, serial_len, value_len; EVP_MD_CTX *ctx = NULL; CK_MECHANISM_TYPE name_hash_algo = CKM_SHA256; unsigned int hash_len; CK_RV rc = CKR_OK; UNUSED(certtype); /* CKA_SUBJECT: DER-encoding of the cert subject name */ name = X509_get_subject_name(x509); if (!X509_NAME_get0_der(name, &subj_name, &subj_name_len)) { warnx("OpenSSL X509_NAME_get0_der failed to return the certificate's subj name"); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } /* CKA_ISSUER: DER-encoding of the cert issuer name */ name = X509_get_issuer_name(x509); if (!X509_NAME_get0_der(name, &issuer_name, &issuer_name_len)) { warnx("OpenSSL X509_NAME_get0_der failed to return the certificate's issuer name"); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } /* CKA_SERIAL_NUMBER: serial number */ serialno = X509_get_serialNumber(x509); serial_len = i2d_ASN1_INTEGER(serialno, &serial_buf); if (serial_len <= 0 || serial_buf == NULL) { warnx("i2d_ASN1_INTEGER failed for the certificate's serial no"); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_HOST_MEMORY; goto done; } /* CKA_VALUE: BER-encoding of certificate */ value_len = i2d_X509(x509, &value_buf); if (value_len <= 0) { warnx("OPENSSL_malloc failed to convert the x509 into a buffer for the certificate's CKA_VALUE"); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_HOST_MEMORY; goto done; } /* CKA_PUBLIC_KEY_INFO: only needed for CKA_HASH_OF_SUBJECT_PUBLIC_KEY */ pkey = X509_get_pubkey(x509); if (pkey == NULL) { warnx("X509_get_pubkey failed to get the EVP_PKEY from X509"); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } spki_len = i2d_PUBKEY(pkey, &spki); if (spki_len <= 0) { warnx("OpenSSL i2d_PUBKEY failed to create spki from EVP_PKEY"); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } /* CKA_HASH_OF_SUBJECT_PUBLIC_KEY: Hash of the subject public key. * Hash algorithm is defined by CKA_NAME_HASH_ALGORITHM */ ctx = EVP_MD_CTX_new(); if (ctx == NULL) { warnx("Error creating MD_CTX for CKA_HASH_OF_SUBJECT_PUBLIC_KEY"); rc = CKR_FUNCTION_FAILED; goto done; } if (!EVP_DigestInit(ctx, EVP_sha256()) || !EVP_DigestUpdate(ctx, spki, spki_len) || !EVP_DigestFinal(ctx, spki_hash, &hash_len)) { warnx("Error creating sha256 hash for CKA_HASH_OF_SUBJECT_PUBLIC_KEY"); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } spki_hash_len = hash_len; /* Add attributes */ rc = p11tool_add_attribute(CKA_SUBJECT, subj_name, subj_name_len, attrs, num_attrs); rc += p11tool_add_attribute(CKA_ISSUER, issuer_name, issuer_name_len, attrs, num_attrs); rc += p11tool_add_attribute(CKA_SERIAL_NUMBER, serial_buf, serial_len, attrs, num_attrs); rc += p11tool_add_attribute(CKA_VALUE, value_buf, value_len, attrs, num_attrs); rc += p11tool_add_attribute(CKA_NAME_HASH_ALGORITHM, &name_hash_algo, sizeof(CK_MECHANISM_TYPE), attrs, num_attrs); rc += p11tool_add_attribute(CKA_HASH_OF_SUBJECT_PUBLIC_KEY, spki_hash, spki_hash_len, attrs, num_attrs); if (rc != CKR_OK) { warnx("Failed to add attributes for imported certificate."); rc = CKR_FUNCTION_FAILED; goto done; } rc = CKR_OK; done: if (serial_buf != NULL) OPENSSL_free(serial_buf); if (value_buf != NULL) OPENSSL_free(value_buf); if (spki != NULL) OPENSSL_free(spki); if (pkey != NULL) EVP_PKEY_free(pkey); if (ctx != NULL) EVP_MD_CTX_free(ctx); return rc; } static CK_RV p11sak_extract_x509_pk(const struct p11tool_objtype *certtype, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, CK_OBJECT_HANDLE cert, const char *label) { const struct p11tool_objtype *keytype; CK_ATTRIBUTE attr = { CKA_VALUE, NULL, 0 }; CK_ATTRIBUTE id_attr = { CKA_ID, NULL, 0 }; const CK_BYTE *tmp_ptr; const unsigned char *subj_name = NULL; #if OPENSSL_VERSION_PREREQ(4, 0) const X509_NAME *name = NULL; #else X509_NAME *name = NULL; #endif size_t subj_name_len; char *pubkey_label = NULL; X509 *x509 = NULL; EVP_PKEY *pkey = NULL; CK_OBJECT_CLASS key_class = CKO_PUBLIC_KEY; CK_BBOOL btrue = CK_TRUE; CK_RV rc; int pkey_type; #if OPENSSL_VERSION_PREREQ(3, 0) const struct pqc_oid *oid; #endif rc = p11tool_get_attribute(cert, &attr); if (rc != CKR_OK) { warnx("Failed to retrieve attribute CKA_VALUE from %s certificate " "object \"%s\": 0x%lX: %s", certtype->name, label, rc, p11_get_ckr(rc)); return rc; } tmp_ptr = attr.pValue; x509 = d2i_X509(NULL, &tmp_ptr, attr.ulValueLen); if (x509 == NULL) { warnx("OpenSSL d2i_X509 failed to get X509 from CKA_VALUE."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } pkey = X509_get_pubkey(x509); if (pkey == NULL) { warnx("OpenSSL X509_get_pubkey failed to get certificate's public key."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } name = X509_get_subject_name(x509); if (!X509_NAME_get0_der(name, &subj_name, &subj_name_len)) { warnx("OpenSSL X509_NAME_get0_der failed to return the certificate's subj name"); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } pkey_type = EVP_PKEY_base_id(pkey); if (pkey_type == EVP_PKEY_RSA_PSS) pkey_type = EVP_PKEY_RSA; keytype = find_keytype_by_pkey(pkey_type); #if OPENSSL_VERSION_PREREQ(3, 0) if (keytype == NULL && pkey_type == NID_undef) { oid = pqc_oid_from_pkey(pkey, dilithium_oids, false); if (oid != NULL) { keytype = &p11sak_ibm_dilithium_keytype; } else { oid = pqc_oid_from_pkey(pkey, ml_dsa_oids, false); if (oid != NULL) keytype = &p11sak_ml_dsa_keytype; } } #endif if (keytype == NULL || keytype->import_asym_pkey == NULL) { warnx("Key type %s cannot be extracted from a certificate.", OBJ_nid2ln(pkey_type)); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_NOT_SUPPORTED; goto done; } rc = keytype->import_asym_pkey(keytype, pkey, CK_FALSE, attrs, num_attrs); if (rc != CKR_OK) { warnx("Failed to import %s public key from %s certificate " "object \"%s\": 0x%lX: %s", keytype->name, certtype->name, label, rc, p11_get_ckr(rc)); goto done; } /* If no new label parm specified, derive new label from cert label */ if (opt_new_label == NULL) { if (asprintf(&pubkey_label, "%s_pubkey", label) < 0 || pubkey_label == NULL) { warnx("Failed to allocate memory for new public key label."); rc = CKR_HOST_MEMORY; goto done; } rc = p11tool_add_attribute(CKA_LABEL, pubkey_label, strlen(pubkey_label), attrs, num_attrs); if (rc != CKR_OK) { warnx("Failed to add attributes for extracted certificate's public key."); goto done; } } /* If no new ID is specified, try to use ID from certificate */ if (opt_new_id == NULL) { rc = p11tool_get_attribute(cert, &id_attr); if (rc == CKR_OK && id_attr.ulValueLen > 0) { rc = p11tool_add_attribute(CKA_ID, id_attr.pValue, id_attr.ulValueLen, attrs, num_attrs); if (rc != CKR_OK) { warnx("Failed to add attributes for extracted certificate's public key."); goto done; } } } rc = p11tool_add_attribute(CKA_CLASS, &key_class, sizeof(CK_OBJECT_CLASS), attrs, num_attrs); rc += p11tool_add_attribute(CKA_KEY_TYPE, &keytype->type, sizeof(CK_KEY_TYPE), attrs, num_attrs); rc += p11tool_add_attribute(CKA_TOKEN, &btrue, sizeof(CK_BBOOL), attrs, num_attrs); rc += p11tool_add_attribute(CKA_SUBJECT, subj_name, subj_name_len, attrs, num_attrs); if (rc != CKR_OK) { warnx("Failed to add attributes for extracted certificate's public key."); rc = CKR_FUNCTION_FAILED; goto done; } rc = CKR_OK; done: if (attr.pValue != NULL) free(attr.pValue); if (id_attr.pValue != NULL) free(id_attr.pValue); if (x509 != NULL) X509_free(x509); if (pkey != NULL) EVP_PKEY_free(pkey); if (pubkey_label != NULL) free(pubkey_label); return rc; } static CK_RV p11sak_import_rsa_pkey(const struct p11tool_objtype *keytype, EVP_PKEY *pkey, bool private, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs) { CK_RV rc = CKR_OK; #if OPENSSL_VERSION_PREREQ(3, 0) BIGNUM *bn_n = NULL, *bn_e = NULL, *bn_d = NULL; BIGNUM *bn_p = NULL, *bn_q = NULL; BIGNUM *bn_dmp1 = NULL, *bn_dmq1 = NULL, *bn_iqmp = NULL; #else const RSA *rsa; const BIGNUM *bn_n = NULL, *bn_e = NULL, *bn_d = NULL; const BIGNUM *bn_p = NULL, *bn_q = NULL; const BIGNUM *bn_dmp1 = NULL, *bn_dmq1 = NULL, *bn_iqmp = NULL; #endif if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA && EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA_PSS) { warnx("PEM file '%s' does not contain an %s %s key.", opt_file, keytype->name, private ? "private" : "public"); return CKR_FUNCTION_FAILED; } #if OPENSSL_VERSION_PREREQ(3, 0) if (private) { bn_d = BN_secure_new(); bn_p = BN_secure_new(); bn_q = BN_secure_new(); bn_dmp1 = BN_secure_new(); bn_dmq1 = BN_secure_new(); bn_iqmp = BN_secure_new(); if (bn_d == NULL || bn_p == NULL || bn_q == NULL || bn_dmp1 == NULL || bn_dmq1 == NULL || bn_iqmp == NULL) { warnx("Failed to allocate OpenSSL BIGNUM"); rc = CKR_HOST_MEMORY; goto done; } } if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_N, &bn_n) || !EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_E, &bn_e) || (private && (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_D, &bn_d) || !EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_FACTOR1, &bn_p) || !EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_FACTOR2, &bn_q) || !EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_EXPONENT1, &bn_dmp1) || !EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_EXPONENT2, &bn_dmq1) || !EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_COEFFICIENT1, &bn_iqmp)))) { warnx("Failed to get the %s params.", keytype->name); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } #else rsa = EVP_PKEY_get0_RSA(pkey); if (rsa == NULL) { warnx("Failed to get the %s params.", keytype->name); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } RSA_get0_key(rsa, &bn_n, &bn_e, private ? &bn_d : NULL); if (private) { RSA_get0_factors(rsa, &bn_p, &bn_q); RSA_get0_crt_params(rsa, &bn_dmp1, &bn_dmq1, &bn_iqmp); } if (bn_n == NULL || bn_e == NULL || (private && (bn_d == NULL || bn_p == NULL || bn_q == NULL || bn_dmp1 == NULL || bn_dmq1 == NULL || bn_iqmp == NULL))) { warnx("Failed to get the %s params.", keytype->name); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } #endif rc = p11tool_add_bignum_attr(CKA_MODULUS, bn_n, attrs, num_attrs); if (rc != CKR_OK) goto done; rc = p11tool_add_bignum_attr(CKA_PUBLIC_EXPONENT, bn_e, attrs, num_attrs); if (rc != CKR_OK) goto done; if (private) { rc = p11tool_add_bignum_attr(CKA_PRIVATE_EXPONENT, bn_d, attrs, num_attrs); if (rc != CKR_OK) goto done; rc = p11tool_add_bignum_attr(CKA_PRIME_1, bn_p, attrs, num_attrs); if (rc != CKR_OK) goto done; rc = p11tool_add_bignum_attr(CKA_PRIME_2, bn_q, attrs, num_attrs); if (rc != CKR_OK) goto done; rc = p11tool_add_bignum_attr(CKA_EXPONENT_1, bn_dmp1, attrs, num_attrs); if (rc != CKR_OK) goto done; rc = p11tool_add_bignum_attr(CKA_EXPONENT_2, bn_dmq1, attrs, num_attrs); if (rc != CKR_OK) goto done; rc = p11tool_add_bignum_attr(CKA_COEFFICIENT, bn_iqmp, attrs, num_attrs); if (rc != CKR_OK) goto done; } done: #if OPENSSL_VERSION_PREREQ(3, 0) if (bn_n != NULL) BN_free(bn_n); if (bn_e != NULL) BN_free(bn_e); if (bn_d != NULL) BN_clear_free(bn_d); if (bn_p != NULL) BN_clear_free(bn_p); if (bn_q != NULL) BN_clear_free(bn_q); if (bn_dmp1 != NULL) BN_clear_free(bn_dmp1); if (bn_dmq1 != NULL) BN_clear_free(bn_dmq1); if (bn_iqmp != NULL) BN_clear_free(bn_iqmp); #endif return rc; } static CK_RV p11sak_import_dh_pkey(const struct p11tool_objtype *keytype, EVP_PKEY *pkey, bool private, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs) { CK_RV rc = CKR_OK; #if OPENSSL_VERSION_PREREQ(3, 0) BIGNUM *bn_p = NULL, *bn_g = NULL, *bn_pub = NULL, *bn_priv = NULL; #else const DH *dh; const BIGNUM *bn_p = NULL, *bn_g = NULL, *bn_pub = NULL, *bn_priv = NULL; #endif if (EVP_PKEY_base_id(pkey) != EVP_PKEY_DH) { warnx("PEM file '%s' does not contain an %s %s key.", opt_file, keytype->name, private ? "private" : "public"); return CKR_FUNCTION_FAILED; } #if OPENSSL_VERSION_PREREQ(3, 0) if (private) { bn_priv = BN_secure_new(); if (bn_priv == NULL) { warnx("Failed to allocate OpenSSL BIGNUM"); rc = CKR_HOST_MEMORY; goto done; } } if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_FFC_P, &bn_p) || !EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_FFC_G, &bn_g) || (!private && !EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PUB_KEY, &bn_pub)) || (private && !EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY, &bn_priv))) { warnx("Failed to get the %s params.", keytype->name); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } #else dh = EVP_PKEY_get0_DH(pkey); if (dh == NULL) { warnx("Failed to get the %s params.", keytype->name); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } DH_get0_pqg(dh, &bn_p, NULL, &bn_g); DH_get0_key(dh, !private ? &bn_pub : NULL, private ? &bn_priv : NULL); if (bn_p == NULL || bn_g == NULL || (!private && bn_pub == NULL) || (private && bn_priv == NULL)) { warnx("Failed to get the %s params.", keytype->name); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } #endif rc = p11tool_add_bignum_attr(CKA_PRIME, bn_p, attrs, num_attrs); if (rc != CKR_OK) goto done; rc = p11tool_add_bignum_attr(CKA_BASE, bn_g, attrs, num_attrs); if (rc != CKR_OK) goto done; rc = p11tool_add_bignum_attr(CKA_VALUE, private ? bn_priv : bn_pub, attrs, num_attrs); if (rc != CKR_OK) goto done; done: #if OPENSSL_VERSION_PREREQ(3, 0) if (bn_p != NULL) BN_free(bn_p); if (bn_g != NULL) BN_free(bn_g); if (bn_pub != NULL) BN_free(bn_pub); if (bn_priv != NULL) BN_clear_free(bn_priv); #endif return rc; } static CK_RV p11sak_import_dsa_pkey(const struct p11tool_objtype *keytype, EVP_PKEY *pkey, bool private, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs) { CK_RV rc = CKR_OK; #if OPENSSL_VERSION_PREREQ(3, 0) BIGNUM *bn_p = NULL, *bn_q = NULL, *bn_g = NULL; BIGNUM *bn_pub = NULL, *bn_priv = NULL; #else const DSA *dsa; const BIGNUM *bn_p = NULL, *bn_q = NULL, *bn_g = NULL; const BIGNUM *bn_pub = NULL, *bn_priv = NULL; #endif if (EVP_PKEY_base_id(pkey) != EVP_PKEY_DSA) { warnx("PEM file '%s' does not contain an %s %s key.", opt_file, keytype->name, private ? "private" : "public"); return CKR_FUNCTION_FAILED; } #if OPENSSL_VERSION_PREREQ(3, 0) if (private) { bn_priv = BN_secure_new(); if (bn_priv == NULL) { warnx("Failed to allocate OpenSSL BIGNUM"); rc = CKR_HOST_MEMORY; goto done; } } if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_FFC_P, &bn_p) || !EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_FFC_Q, &bn_q) || !EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_FFC_G, &bn_g) || (!private && !EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PUB_KEY, &bn_pub)) || (private && !EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY, &bn_priv))) { warnx("Failed to get the %s params.", keytype->name); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } #else dsa = EVP_PKEY_get0_DSA(pkey); if (dsa == NULL) { warnx("Failed to get the %s params.", keytype->name); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } DSA_get0_pqg(dsa, &bn_p, &bn_q, &bn_g); DSA_get0_key(dsa, !private ? &bn_pub : NULL, private ? &bn_priv : NULL); if (bn_p == NULL || bn_q == NULL || bn_g == NULL || (!private && bn_pub == NULL) || (private && bn_priv == NULL)) { warnx("Failed to get the %s params.", keytype->name); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } #endif rc = p11tool_add_bignum_attr(CKA_PRIME, bn_p, attrs, num_attrs); if (rc != CKR_OK) goto done; rc = p11tool_add_bignum_attr(CKA_SUBPRIME, bn_q, attrs, num_attrs); if (rc != CKR_OK) goto done; rc = p11tool_add_bignum_attr(CKA_BASE, bn_g, attrs, num_attrs); if (rc != CKR_OK) goto done; rc = p11tool_add_bignum_attr(CKA_VALUE, private ? bn_priv : bn_pub, attrs, num_attrs); if (rc != CKR_OK) goto done; done: #if OPENSSL_VERSION_PREREQ(3, 0) if (bn_p != NULL) BN_free(bn_p); if (bn_q != NULL) BN_free(bn_q); if (bn_g != NULL) BN_free(bn_g); if (bn_pub != NULL) BN_free(bn_pub); if (bn_priv != NULL) BN_clear_free(bn_priv); #endif return rc; } #if OPENSSL_VERSION_PREREQ(3, 0) static CK_RV p11sak_import_ecx_pkey(const struct p11tool_objtype *keytype, int pkey_type, EVP_PKEY *pkey, bool private, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs) { CK_RV rc = CKR_OK; unsigned char priv[100] = { 0 }; size_t priv_len = 0; unsigned char point[300] = { 0 }; unsigned char *point_ptr; size_t point_len = 0; ASN1_OBJECT *obj = NULL; unsigned char *ec_params = NULL; int ec_params_len; if ((!private && /* leave 3 bytes space for DER encoding */ !EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_PUB_KEY, point + 3, sizeof(point) - 3, &point_len)) || (private && !EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY, priv, sizeof(priv), &priv_len))) { warnx("Failed to get the %s params.", keytype->name); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } obj = OBJ_nid2obj(pkey_type); if (obj == NULL) { warnx("OBJ_nid2obj failed for curve nid %d.", pkey_type); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } ec_params_len = i2d_ASN1_OBJECT(obj, &ec_params); if (ec_params_len <= 0 || ec_params == NULL) { warnx("i2d_ASN1_OBJECT failed for curve nid %d.", pkey_type); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } rc = p11tool_add_attribute(CKA_EC_PARAMS, ec_params, ec_params_len, attrs, num_attrs); if (rc != CKR_OK) goto done; if (private) { rc = p11tool_add_attribute(CKA_VALUE, priv, priv_len, attrs, num_attrs); if (rc != CKR_OK) goto done; } else { if (keytype->type == CKK_EC) { /* EC: CKA_EC_POINT needs DER encoded EC point */ if (point_len < 0x80) { point[1] = 0x04; /* OCTET-STRING */ point[2] = point_len & 0x7f; point_len += 2; point_ptr = &point[1]; } else if (point_len < 0x0100) { point[0] = 0x04; /* OCTET-STRING */ point[1] = 0x81; /* 1 byte length field */ point[2] = point_len & 0xff; point_len += 3; point_ptr = &point[0]; } else { warnx("EC point is too long."); rc = CKR_FUNCTION_FAILED; goto done; } } else { /* Edwards/Montgomery use raw EC point */ point_ptr = &point[3]; } rc = p11tool_add_attribute(CKA_EC_POINT, point_ptr, point_len, attrs, num_attrs); if (rc != CKR_OK) goto done; } done: if (obj != NULL) ASN1_OBJECT_free(obj); if (ec_params != NULL) OPENSSL_free(ec_params); return rc; } #endif static CK_RV p11sak_import_ec_pkey(const struct p11tool_objtype *keytype, EVP_PKEY *pkey, bool private, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs) { CK_RV rc = CKR_OK; #if OPENSSL_VERSION_PREREQ(3, 0) BIGNUM *bn_priv = NULL; char group[200] = { 0 }; EC_GROUP *ec_group = NULL; unsigned char point[200] = { 0 }; const OSSL_PARAM params[2] = { OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, group, sizeof(group) -1), OSSL_PARAM_END, }; #else const EC_KEY *ec; const EC_GROUP *ec_group = NULL; const BIGNUM *bn_priv = NULL; const EC_POINT *ec_point = NULL; unsigned char *point = NULL; #endif unsigned char *point_ptr; size_t point_len = 0; ASN1_OBJECT *obj = NULL; unsigned char *ec_params = NULL; int ec_params_len, type; type = EVP_PKEY_base_id(pkey); switch (type) { case EVP_PKEY_EC: if (keytype->type != CKK_EC) { warnx("PEM file '%s' contains an EC %s key, but a %s %s key is " "expected.", opt_file, private ? "private" : "public", keytype->name, private ? "private" : "public"); return CKR_ARGUMENTS_BAD; } break; #if OPENSSL_VERSION_PREREQ(3, 0) case EVP_PKEY_ED25519: case EVP_PKEY_ED448: if (keytype->type != CKK_EC && keytype->type != CKK_EC_EDWARDS) { warnx("PEM file '%s' contains an EC-Edwards %s key, but a %s %s " "key is expected.", opt_file, private ? "private" : "public", keytype->name, private ? "private" : "public"); return CKR_ARGUMENTS_BAD; } return p11sak_import_ecx_pkey(keytype, type, pkey, private, attrs, num_attrs); case EVP_PKEY_X25519: case EVP_PKEY_X448: if (keytype->type != CKK_EC && keytype->type != CKK_EC_MONTGOMERY) { warnx("PEM file '%s' contains an EC-Montgomery %s key, but a %s %s " "key is expected.", opt_file, private ? "private" : "public", keytype->name, private ? "private" : "public"); return CKR_ARGUMENTS_BAD; } return p11sak_import_ecx_pkey(keytype, type, pkey, private, attrs, num_attrs); #endif default: warnx("PEM file '%s' does not contain an %s %s key.", opt_file, keytype->name, private ? "private" : "public"); return CKR_FUNCTION_FAILED; } #if OPENSSL_VERSION_PREREQ(3, 0) if (private) { bn_priv = BN_secure_new(); if (bn_priv == NULL) { warnx("Failed to allocate OpenSSL BIGNUM"); rc = CKR_HOST_MEMORY; goto done; } } if (!EVP_PKEY_get_utf8_string_param(pkey, OSSL_PKEY_PARAM_GROUP_NAME, group, sizeof(group), NULL) || (!private && /* leave 3 bytes space for DER encoding */ !EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, point + 3, sizeof(point) - 3, &point_len)) || (private && !EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY, &bn_priv))) { warnx("Failed to get the %s params.", keytype->name); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } ec_group = EC_GROUP_new_from_params(params, NULL, NULL); if (ec_group == NULL) { warnx("EC_GROUP_new_from_params failed for curve '%s'.", group); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } #else ec = EVP_PKEY_get0_EC_KEY(pkey); if (ec == NULL) { warnx("Failed to get the %s params.", keytype->name); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } ec_group = EC_KEY_get0_group(ec); if (private) bn_priv = EC_KEY_get0_private_key(ec); else ec_point = EC_KEY_get0_public_key(ec); if (ec_group == NULL || (!private && ec_point == NULL) || (private && bn_priv == NULL)) { warnx("Failed to get the %s params.", keytype->name); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } if (!private) { point_len = EC_POINT_point2oct(ec_group, ec_point, POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL); if (point_len == 0) { warnx("EC_POINT_point2oct failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } /* Leave 3 bytes space for DER encoding of OCTET-STRING */ point = calloc(3 + point_len, 1); if (point == NULL) { warnx("Failed to allocate buffer for EC point."); rc = CKR_HOST_MEMORY; goto done; } if (EC_POINT_point2oct(ec_group, ec_point, POINT_CONVERSION_UNCOMPRESSED, point + 3, point_len, NULL) != point_len) { warnx("EC_POINT_point2oct failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } } #endif obj = OBJ_nid2obj(EC_GROUP_get_curve_name(ec_group)); if (obj == NULL) { warnx("OBJ_nid2obj failed for curve nid %d.", EC_GROUP_get_curve_name(ec_group)); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } ec_params_len = i2d_ASN1_OBJECT(obj, &ec_params); if (ec_params_len <= 0 || ec_params == NULL) { warnx("i2d_ASN1_OBJECT failed for curve nid %d.", EC_GROUP_get_curve_name(ec_group)); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } rc = p11tool_add_attribute(CKA_EC_PARAMS, ec_params, ec_params_len, attrs, num_attrs); if (rc != CKR_OK) goto done; if (private) { rc = p11tool_add_bignum_attr(CKA_VALUE, bn_priv, attrs, num_attrs); if (rc != CKR_OK) goto done; } else { /* CKA_EC_POINT needs DER encoded EC point */ if (point_len < 0x80) { point[1] = 0x04; /* OCTET-STRING */ point[2] = point_len & 0x7f; point_len += 2; point_ptr = &point[1]; } else if (point_len < 0x0100) { point[0] = 0x04; /* OCTET-STRING */ point[1] = 0x81; /* 1 byte length field */ point[2] = point_len & 0xff; point_len += 3; point_ptr = &point[0]; } else { warnx("EC point is too long."); rc = CKR_FUNCTION_FAILED; goto done; } rc = p11tool_add_attribute(CKA_EC_POINT, point_ptr, point_len, attrs, num_attrs); if (rc != CKR_OK) goto done; } done: #if OPENSSL_VERSION_PREREQ(3, 0) if (bn_priv != NULL) BN_clear_free(bn_priv); if (ec_group != NULL) EC_GROUP_free(ec_group); #else if (point != NULL) free(point); #endif if (obj != NULL) ASN1_OBJECT_free(obj); if (ec_params != NULL) OPENSSL_free(ec_params); return rc; } static CK_RV p11sak_import_dilithium_kyber_pem_data( const struct p11tool_objtype *keytype, unsigned char *data, size_t data_len, bool private, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs) { UNUSED(keytype); UNUSED(private); return p11tool_add_attribute(CKA_VALUE, data, data_len, attrs, num_attrs); } static CK_RV p11sak_import_dilithium_ml_dsa_pkey( const struct p11tool_objtype *keytype, EVP_PKEY *pkey, bool private, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs) { #if OPENSSL_VERSION_PREREQ(3, 0) const struct pqc_oid *oid; size_t priv_len = 0, pub_len = 0; CK_BYTE *priv_key = NULL, *pub_key = NULL; CK_ULONG ofs; size_t seed_len = 0; CK_BYTE *priv_seed = NULL; CK_RV rc; UNUSED(keytype); oid = pqc_oid_from_pkey(pkey, keytype->type == CKK_IBM_PQC_DILITHIUM ? dilithium_oids : ml_dsa_oids, true); if (oid == NULL) return CKR_FUNCTION_FAILED; /* Add keyform and attribute */ rc = p11tool_add_attribute(keytype->type == CKK_IBM_PQC_DILITHIUM ? CKA_IBM_DILITHIUM_KEYFORM : CKA_IBM_PARAMETER_SET, &oid->keyform, sizeof(oid->keyform), attrs, num_attrs); if (rc != CKR_OK) goto out; if (private) { rc = p11tool_get_octet_string_param_from_pkey(pkey, OSSL_PKEY_PARAM_PRIV_KEY, &priv_key, &priv_len, FALSE); if (rc != CKR_OK) goto out; if (priv_len != oid->len_info.ml_dsa.rho_len + oid->len_info.ml_dsa.seed_len + oid->len_info.ml_dsa.tr_len + oid->len_info.ml_dsa.s1_len + oid->len_info.ml_dsa.s2_len + oid->len_info.ml_dsa.t0_len) { warnx("Size of private %s key is not valid.", keytype->name); rc = CKR_FUNCTION_FAILED; goto out; } ofs = 0; rc = p11tool_add_attribute(CKA_IBM_ML_DSA_RHO, priv_key + ofs, oid->len_info.ml_dsa.rho_len, attrs, num_attrs); if (rc != CKR_OK) goto out; ofs += oid->len_info.ml_dsa.rho_len; rc = p11tool_add_attribute(CKA_IBM_ML_DSA_SEED, priv_key + ofs, oid->len_info.ml_dsa.seed_len, attrs, num_attrs); if (rc != CKR_OK) goto out; ofs += oid->len_info.ml_dsa.seed_len; rc = p11tool_add_attribute(CKA_IBM_ML_DSA_TR, priv_key + ofs, oid->len_info.ml_dsa.tr_len, attrs, num_attrs); if (rc != CKR_OK) goto out; ofs += oid->len_info.ml_dsa.tr_len; rc = p11tool_add_attribute(CKA_IBM_ML_DSA_S1, priv_key + ofs, oid->len_info.ml_dsa.s1_len, attrs, num_attrs); if (rc != CKR_OK) goto out; ofs += oid->len_info.ml_dsa.s1_len; rc = p11tool_add_attribute(CKA_IBM_ML_DSA_S2, priv_key + ofs, oid->len_info.ml_dsa.s2_len, attrs, num_attrs); if (rc != CKR_OK) goto out; ofs += oid->len_info.ml_dsa.s2_len; rc = p11tool_add_attribute(CKA_IBM_ML_DSA_T0, priv_key + ofs, oid->len_info.ml_dsa.t0_len, attrs, num_attrs); if (rc != CKR_OK) goto out; /* Try to get private seed, but ignore if it is not available */ rc = p11tool_get_octet_string_param_from_pkey(pkey, OSSL_PKEY_PARAM_ML_DSA_SEED, &priv_seed, &seed_len, TRUE); if (rc != CKR_OK) goto out; if (priv_seed != NULL && seed_len == oid->len_info.ml_dsa.priv_seed_len) { rc = p11tool_add_attribute(CKA_IBM_ML_DSA_PRIVATE_SEED, priv_seed, seed_len, attrs, num_attrs); if (rc != CKR_OK) goto out; } } rc = p11tool_get_octet_string_param_from_pkey(pkey, OSSL_PKEY_PARAM_PUB_KEY, &pub_key, &pub_len, FALSE); if (rc != CKR_OK) goto out; if (pub_len != oid->len_info.ml_dsa.rho_len + oid->len_info.ml_dsa.t1_len) { warnx("Size of public %s key is not valid.", keytype->name); rc = CKR_FUNCTION_FAILED; goto out; } ofs = 0; rc = p11tool_add_attribute(CKA_IBM_ML_DSA_RHO, pub_key + ofs, oid->len_info.ml_dsa.rho_len, attrs, num_attrs); if (rc != CKR_OK) goto out; ofs += oid->len_info.ml_dsa.rho_len; rc = p11tool_add_attribute(CKA_IBM_ML_DSA_T1, pub_key + ofs, oid->len_info.ml_dsa.t1_len, attrs, num_attrs); if (rc != CKR_OK) goto out; out: if (priv_key != NULL) { OPENSSL_cleanse(priv_key, priv_len); free(priv_key); } if (pub_key != NULL) free(pub_key); return rc; #else UNUSED(keytype); UNUSED(pkey); UNUSED(private); UNUSED(attrs); UNUSED(num_attrs); warnx("Importing an 'oqsprovider' format PEM file is only supported with " "OpenSSL 3.0 or later."); return CKR_FUNCTION_NOT_SUPPORTED; #endif } static CK_RV p11sak_import_ibm_ml_kem_pkey( const struct p11tool_objtype *keytype, EVP_PKEY *pkey, bool private, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs) { #if OPENSSL_VERSION_PREREQ(3, 0) const struct pqc_oid *oid; size_t priv_len = 0, pub_len = 0; CK_BYTE *priv_key = NULL, *pub_key = NULL; size_t seed_len = 0; CK_BYTE *priv_seed = NULL; CK_RV rc; UNUSED(keytype); oid = pqc_oid_from_pkey(pkey, ml_kem_oids, true); if (oid == NULL) return CKR_FUNCTION_FAILED; /* Add Parameter-set and attribute */ rc = p11tool_add_attribute(CKA_IBM_PARAMETER_SET, &oid->keyform, sizeof(oid->keyform), attrs, num_attrs); if (rc != CKR_OK) goto out; if (private) { rc = p11tool_get_octet_string_param_from_pkey(pkey, OSSL_PKEY_PARAM_PRIV_KEY, &priv_key, &priv_len, FALSE); if (rc != CKR_OK) goto out; if (priv_len != oid->len_info.ml_kem.sk_len) { warnx("Size of private %s key is not valid.", keytype->name); rc = CKR_FUNCTION_FAILED; goto out; } rc = p11tool_add_attribute(CKA_IBM_ML_KEM_SK, priv_key, oid->len_info.ml_kem.sk_len, attrs, num_attrs); if (rc != CKR_OK) goto out; rc = p11tool_get_octet_string_param_from_pkey(pkey, OSSL_PKEY_PARAM_ML_KEM_SEED, &priv_seed, &seed_len, TRUE); if (rc != CKR_OK) goto out; if (priv_seed != NULL && seed_len == oid->len_info.ml_kem.priv_seed_len) { rc = p11tool_add_attribute(CKA_IBM_ML_KEM_PRIVATE_SEED, priv_seed, seed_len, attrs, num_attrs); if (rc != CKR_OK) goto out; } } rc = p11tool_get_octet_string_param_from_pkey(pkey, OSSL_PKEY_PARAM_PUB_KEY, &pub_key, &pub_len, FALSE); if (rc != CKR_OK) goto out; if (pub_len != oid->len_info.ml_kem.pk_len) { warnx("Size of public %s key is not valid.", keytype->name); rc = CKR_FUNCTION_FAILED; goto out; } rc = p11tool_add_attribute(CKA_IBM_ML_KEM_PK, pub_key, oid->len_info.ml_kem.pk_len, attrs, num_attrs); if (rc != CKR_OK) goto out; out: if (priv_key != NULL) { OPENSSL_cleanse(priv_key, priv_len); free(priv_key); } if (pub_key != NULL) free(pub_key); return rc; #else UNUSED(keytype); UNUSED(pkey); UNUSED(private); UNUSED(attrs); UNUSED(num_attrs); warnx("Importing an 'oqsprovider' format PEM file is only supported with " "OpenSSL 3.0 or later."); return CKR_FUNCTION_NOT_SUPPORTED; #endif } static CK_RV p11sak_import_ml_dsa_pkey(const struct p11tool_objtype *keytype, EVP_PKEY *pkey, bool private, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs) { #if OPENSSL_VERSION_PREREQ(3, 0) const struct pqc_oid *oid; size_t priv_len = 0, pub_len = 0; CK_BYTE *priv_key = NULL, *pub_key = NULL; size_t seed_len = 0; CK_BYTE *priv_seed = NULL; CK_RV rc; UNUSED(keytype); oid = pqc_oid_from_pkey(pkey, ml_dsa_oids, true); if (oid == NULL) return CKR_FUNCTION_FAILED; /* Add keyform and attribute */ rc = p11tool_add_attribute(CKA_PARAMETER_SET, &oid->keyform, sizeof(oid->keyform), attrs, num_attrs); if (rc != CKR_OK) goto out; if (private) { rc = p11tool_get_octet_string_param_from_pkey(pkey, OSSL_PKEY_PARAM_PRIV_KEY, &priv_key, &priv_len, FALSE); if (rc != CKR_OK) goto out; if (priv_len != oid->len_info.ml_dsa.rho_len + oid->len_info.ml_dsa.seed_len + oid->len_info.ml_dsa.tr_len + oid->len_info.ml_dsa.s1_len + oid->len_info.ml_dsa.s2_len + oid->len_info.ml_dsa.t0_len) { warnx("Size of private %s key is not valid.", keytype->name); rc = CKR_FUNCTION_FAILED; goto out; } rc = p11tool_add_attribute(CKA_VALUE, priv_key, priv_len, attrs, num_attrs); if (rc != CKR_OK) goto out; /* Try to get private seed, but ignore if it is not available */ rc = p11tool_get_octet_string_param_from_pkey(pkey, OSSL_PKEY_PARAM_ML_DSA_SEED, &priv_seed, &seed_len, TRUE); if (rc != CKR_OK) goto out; if (priv_seed != NULL && seed_len == oid->len_info.ml_dsa.priv_seed_len) { rc = p11tool_add_attribute(CKA_SEED, priv_seed, seed_len, attrs, num_attrs); if (rc != CKR_OK) goto out; } } else { rc = p11tool_get_octet_string_param_from_pkey(pkey, OSSL_PKEY_PARAM_PUB_KEY, &pub_key, &pub_len, FALSE); if (rc != CKR_OK) goto out; if (pub_len != oid->len_info.ml_dsa.rho_len + oid->len_info.ml_dsa.t1_len) { warnx("Size of public %s key is not valid.", keytype->name); rc = CKR_FUNCTION_FAILED; goto out; } rc = p11tool_add_attribute(CKA_VALUE, pub_key, pub_len, attrs, num_attrs); if (rc != CKR_OK) goto out; } out: if (priv_key != NULL) { OPENSSL_cleanse(priv_key, priv_len); free(priv_key); } if (pub_key != NULL) free(pub_key); return rc; #else UNUSED(keytype); UNUSED(pkey); UNUSED(private); UNUSED(attrs); UNUSED(num_attrs); warnx("Importing an 'oqsprovider' format PEM file is only supported with " "OpenSSL 3.0 or later."); return CKR_FUNCTION_NOT_SUPPORTED; #endif } static CK_RV p11sak_import_ml_kem_pkey(const struct p11tool_objtype *keytype, EVP_PKEY *pkey, bool private, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs) { #if OPENSSL_VERSION_PREREQ(3, 0) const struct pqc_oid *oid; size_t priv_len = 0, pub_len = 0; CK_BYTE *priv_key = NULL, *pub_key = NULL; size_t seed_len = 0; CK_BYTE *priv_seed = NULL; CK_RV rc; UNUSED(keytype); oid = pqc_oid_from_pkey(pkey, ml_kem_oids, true); if (oid == NULL) return CKR_FUNCTION_FAILED; /* Add Parameter-set and attribute */ rc = p11tool_add_attribute(CKA_PARAMETER_SET, &oid->keyform, sizeof(oid->keyform), attrs, num_attrs); if (rc != CKR_OK) goto out; if (private) { rc = p11tool_get_octet_string_param_from_pkey(pkey, OSSL_PKEY_PARAM_PRIV_KEY, &priv_key, &priv_len, FALSE); if (rc != CKR_OK) goto out; if (priv_len != oid->len_info.ml_kem.sk_len) { warnx("Size of private %s key is not valid.", keytype->name); rc = CKR_FUNCTION_FAILED; goto out; } rc = p11tool_add_attribute(CKA_VALUE, priv_key, priv_len, attrs, num_attrs); if (rc != CKR_OK) goto out; rc = p11tool_get_octet_string_param_from_pkey(pkey, OSSL_PKEY_PARAM_ML_KEM_SEED, &priv_seed, &seed_len, TRUE); if (rc != CKR_OK) goto out; if (priv_seed != NULL && seed_len == oid->len_info.ml_kem.priv_seed_len) { rc = p11tool_add_attribute(CKA_SEED, priv_seed, seed_len, attrs, num_attrs); if (rc != CKR_OK) goto out; } } else { rc = p11tool_get_octet_string_param_from_pkey(pkey, OSSL_PKEY_PARAM_PUB_KEY, &pub_key, &pub_len, FALSE); if (rc != CKR_OK) goto out; if (pub_len != oid->len_info.ml_kem.pk_len) { warnx("Size of public %s key is not valid.", keytype->name); rc = CKR_FUNCTION_FAILED; goto out; } rc = p11tool_add_attribute(CKA_VALUE, pub_key, pub_len, attrs, num_attrs); if (rc != CKR_OK) goto out; } out: if (priv_key != NULL) { OPENSSL_cleanse(priv_key, priv_len); free(priv_key); } if (pub_key != NULL) free(pub_key); return rc; #else UNUSED(keytype); UNUSED(pkey); UNUSED(private); UNUSED(attrs); UNUSED(num_attrs); warnx("Importing an 'oqsprovider' format PEM file is only supported with " "OpenSSL 3.0 or later."); return CKR_FUNCTION_NOT_SUPPORTED; #endif } static CK_RV p11sak_x509_from_pem_file(X509 **x509) { struct p11tool_pem_password_cb_data cb_data = { 0 }; BIO *bio = NULL; X509 *x = NULL; CK_RV rc; cb_data.pem_file_name = opt_file; cb_data.pem_password = opt_pem_password; cb_data.env_var_name = PKCS11_PEM_PASSWORD_ENV_NAME; cb_data.force_prompt = opt_force_pem_pwd_prompt; bio = BIO_new_file(opt_file, "r"); if (bio == NULL) { warnx("Failed to open file '%s'", opt_file); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_ARGUMENTS_BAD; goto done; } x = PEM_read_bio_X509(bio, NULL, p11tool_pem_password_cb, &cb_data); if (x == NULL) { rc = CKR_FUNCTION_FAILED; goto done; } *x509 = x; rc = CKR_OK; done: if (bio != NULL) BIO_free(bio); return rc; } static CK_RV p11sak_x509_from_der_file(X509 **x509) { CK_BYTE *value; CK_ULONG value_len; const CK_BYTE *tmp_value; X509 *x; struct stat sb; FILE *fp = NULL; CK_RV rc; if (stat(opt_file, &sb) != 0) { warnx("Failed to access file '%s': %s", opt_file, strerror(errno)); return CKR_ARGUMENTS_BAD; } value_len = sb.st_size; value = malloc(value_len); if (value == NULL) { warnx("Cannot malloc %ld bytes for DER file contents.", value_len); return CKR_HOST_MEMORY; } fp = fopen(opt_file, "r"); if (fp == NULL) { warnx("Failed to open file '%s': %s", opt_file, strerror(errno)); rc = CKR_ARGUMENTS_BAD; goto done; } if (fread(value, value_len, 1, fp) != 1) { warnx("Failed to read from file '%s': %s", opt_file, strerror(errno)); rc = CKR_FUNCTION_FAILED; goto done; } tmp_value = (CK_BYTE *)value; x = d2i_X509(NULL, &tmp_value, value_len); if (x == NULL) { warnx("d2i_X509 failed to decode contents from file '%s'", opt_file); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } *x509 = x; rc = CKR_OK; done: if (fp != NULL) fclose(fp); if (value != NULL) free(value); return rc; } static CK_RV p11sak_import_opaque_key(const struct p11tool_objtype *keytype, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs) { CK_BYTE *value; CK_ULONG value_len; struct stat sb; FILE *fp; CK_RV rc = CKR_OK; UNUSED(keytype); if (stat(opt_file, &sb) != 0) { warnx("Failed to access file '%s': %s", opt_file, strerror(errno)); return CKR_FUNCTION_FAILED; } value_len = sb.st_size; value = malloc(value_len); if (value == NULL) { warnx("Failed to allocate a buffer for the opaque key"); return CKR_FUNCTION_FAILED; } fp = fopen(opt_file, "r"); if (fp == NULL) { warnx("Failed to open file '%s': %s", opt_file, strerror(errno)); rc = CKR_FUNCTION_FAILED; goto done; } if (fread(value, value_len, 1, fp) != 1) { warnx("Failed to read from file '%s': %s", opt_file, strerror(errno)); rc = CKR_FUNCTION_FAILED; goto done; } rc = p11tool_add_attribute(CKA_IBM_OPAQUE, value, value_len, attrs, num_attrs); if (rc != CKR_OK) goto done; done: if (value != NULL) { OPENSSL_cleanse(value, value_len); free(value); } if (fp != NULL) fclose(fp); return rc; } static CK_RV p11sak_import_asym_key(const struct p11tool_objtype *keytype, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs) { struct p11tool_pem_password_cb_data cb_data = { 0 }; EVP_PKEY *pkey = NULL; CK_RV rc = CKR_OK; unsigned char *data = NULL; long data_len = 0; char *header = NULL; BIO *bio; int ret; cb_data.pem_file_name = opt_file; cb_data.pem_password = opt_pem_password; cb_data.env_var_name = PKCS11_PEM_PASSWORD_ENV_NAME; cb_data.force_prompt = opt_force_pem_pwd_prompt; bio = BIO_new_file(opt_file, "r"); if (bio == NULL) { warnx("Failed to open PEM file '%s'.", opt_file); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); return CKR_FUNCTION_FAILED; } if (keytype->import_asym_pkey != NULL && (!keytype->supports_oqsprovider_pem || (opt_oqsprovider_pem && keytype->supports_oqsprovider_pem))) { if (opt_asym_kind->private.num) pkey = PEM_read_bio_PrivateKey(bio, NULL, p11tool_pem_password_cb, &cb_data); else pkey = PEM_read_bio_PUBKEY(bio, NULL, p11tool_pem_password_cb, &cb_data); if (pkey == NULL) { warnx("Failed to read PEM file '%s'.%s", opt_file, opt_oqsprovider_pem ? " Is the 'oqsprovider' configured?" : ""); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } rc = keytype->import_asym_pkey(keytype, pkey, opt_asym_kind->private.num, attrs, num_attrs); if (rc != CKR_OK) goto done; } else if (keytype->import_asym_pem_data != NULL) { ret = PEM_bytes_read_bio(&data, &data_len, &header, opt_asym_kind->private.num ? keytype->pem_name_private : keytype->pem_name_public, bio, p11tool_pem_password_cb, &cb_data); if (ret != 1) { warnx("Failed to read PEM file '%s'.", opt_file); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } rc = keytype->import_asym_pem_data(keytype, data, data_len, opt_asym_kind->private.num, attrs, num_attrs); if (rc != CKR_OK) goto done; } else { warnx("No support for importing %s key from PEM file '%s'", keytype->name, opt_file); rc = CKR_ARGUMENTS_BAD; goto done; } done: BIO_free(bio); if (pkey != NULL) EVP_PKEY_free(pkey); if (data != NULL) OPENSSL_clear_free(data, data_len); if (header != NULL) OPENSSL_free(header); return rc; } static CK_RV p11sak_import_sym_key(const struct p11tool_objtype *keytype, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs) { CK_BYTE data[MAX_SYM_CLEAR_KEY_SIZE]; CK_ULONG data_len; struct stat sb; FILE *fp; CK_RV rc; if (keytype->import_sym_clear == NULL) { warnx("No support for importing %s key from file '%s'", keytype->name, opt_file); return CKR_ARGUMENTS_BAD; } if (stat(opt_file, &sb) != 0) { warnx("Failed to access file '%s': %s", opt_file, strerror(errno)); return CKR_FUNCTION_FAILED; } data_len = sb.st_size; if (keytype->import_check_sym_keysize != NULL) { rc = keytype->import_check_sym_keysize(keytype, data_len); if (rc != CKR_OK) return rc; } if (data_len > (CK_ULONG)sizeof(data)) { warnx("Size of %s key is too large", keytype->name); return CKR_ARGUMENTS_BAD; } fp = fopen(opt_file, "r"); if (fp == NULL) { warnx("Failed to open file '%s': %s", opt_file, strerror(errno)); return CKR_FUNCTION_FAILED; } if (fread(data, data_len, 1, fp) != 1) { warnx("Failed to read from file '%s': %s", opt_file, strerror(errno)); fclose(fp); return CKR_FUNCTION_FAILED; } fclose(fp); rc = keytype->import_sym_clear(keytype, data, data_len, attrs, num_attrs); OPENSSL_cleanse(data, sizeof(data)); return rc; } static CK_RV p11sak_import_key(void) { const struct p11tool_objtype *keytype; CK_ATTRIBUTE *attrs = NULL; CK_ULONG num_attrs = 0; CK_OBJECT_CLASS class; CK_OBJECT_HANDLE key; CK_RV rc; if (opt_keytype == NULL || opt_keytype->private.ptr == NULL) return CKR_ARGUMENTS_BAD; keytype = opt_keytype->private.ptr; if (opt_oqsprovider_pem && !keytype->supports_oqsprovider_pem) { warnx("Option '--oqsprovider-pem' is not supported for keytype '%s'.", keytype->name); return CKR_ARGUMENTS_BAD; } class = keytype->is_asymmetric ? (opt_asym_kind->private.num ? CKO_PRIVATE_KEY : CKO_PUBLIC_KEY) : CKO_SECRET_KEY; rc = p11tool_add_attribute(CKA_CLASS, &class, sizeof(class), &attrs, &num_attrs); if (rc != CKR_OK) goto done; rc = p11tool_add_attribute(CKA_KEY_TYPE, &keytype->type, sizeof(keytype->type), &attrs, &num_attrs); if (rc != CKR_OK) goto done; rc = p11tool_add_attributes(keytype, p11sak_bool_attrs, &attrs, &num_attrs, opt_label, opt_attr, opt_id, !keytype->is_asymmetric || (keytype->is_asymmetric && opt_asym_kind->private.num), opt_so, NULL, NULL, keytype->is_asymmetric ? (opt_asym_kind->private.num ? p11tool_private_attr_applicable : p11tool_public_attr_applicable) : p11tool_secret_attr_applicable); if (rc != CKR_OK) goto done; if (opt_opaque) rc = p11sak_import_opaque_key(keytype, &attrs, &num_attrs); else if (keytype->is_asymmetric) rc = p11sak_import_asym_key(keytype, &attrs, &num_attrs); else rc = p11sak_import_sym_key(keytype, &attrs, &num_attrs); if (rc != CKR_OK) goto done; rc = p11tool_pkcs11_funcs->C_CreateObject(p11tool_pkcs11_session, attrs, num_attrs, &key); if (rc != CKR_OK) { if (p11tool_is_rejected_by_policy(rc, p11tool_pkcs11_session)) warnx("Key import of a %s key is rejected by policy", keytype->name); else warnx("Key import of a %s key failed: 0x%lX: %s", keytype->name, rc, p11_get_ckr(rc)); goto done; } printf("Successfully imported a %s key with label \"%s\".\n", keytype->name, opt_label); done: p11tool_free_attributes(attrs, num_attrs); return rc; } static bool has_ibm_opaque_attr(CK_OBJECT_HANDLE key) { CK_RV rc; CK_ATTRIBUTE attr = { CKA_IBM_OPAQUE, NULL, 0 }; rc = p11tool_pkcs11_funcs->C_GetAttributeValue(p11tool_pkcs11_session, key, &attr, 1); if (rc == CKR_ATTRIBUTE_SENSITIVE) return true; if (rc != CKR_OK) return false; return true; } static CK_RV p11sak_export_sym_clear_des_3des_aes_generic( const struct p11tool_objtype *keytype, CK_BYTE **data, CK_ULONG* data_len, CK_OBJECT_HANDLE key, const char *label) { CK_ATTRIBUTE attr = { CKA_VALUE, NULL, 0 }; CK_RV rc; rc = p11tool_get_attribute(key, &attr); if (rc == CKR_ATTRIBUTE_SENSITIVE) return rc; if (rc != CKR_OK) { warnx("Failed to retrieve attribute CKA_VALUE from %s key " "object \"%s\": 0x%lX: %s", keytype->name, label, rc, p11_get_ckr(rc)); return rc; } *data = attr.pValue; *data_len = attr.ulValueLen; return CKR_OK; } static CK_RV p11sak_export_rsa_pkey(const struct p11tool_objtype *keytype, EVP_PKEY **pkey, bool private, CK_OBJECT_HANDLE key, const char *label) { BIGNUM *bn_n = NULL, *bn_e = NULL, *bn_d = NULL, *bn_iqmp = NULL; BIGNUM *bn_p = NULL, *bn_q = NULL, *bn_dmp1 = NULL, *bn_dmq1 = NULL; #if OPENSSL_VERSION_PREREQ(3, 0) EVP_PKEY_CTX *pctx = NULL; OSSL_PARAM_BLD *tmpl = NULL; OSSL_PARAM *params = NULL; #else RSA *rsa = NULL; #endif CK_RV rc; rc = p11tool_get_bignum_attr(key, CKA_MODULUS, &bn_n); if (rc == CKR_ATTRIBUTE_SENSITIVE) goto done; if (rc != CKR_OK) { warnx("Failed to retrieve attribute CKA_MODULUS from %s key " "object \"%s\": 0x%lX: %s", keytype->name, label, rc, p11_get_ckr(rc)); goto done; } rc = p11tool_get_bignum_attr(key, CKA_PUBLIC_EXPONENT, &bn_e); if (rc == CKR_ATTRIBUTE_SENSITIVE) goto done; if (rc != CKR_OK) { warnx("Failed to retrieve attribute CKA_PUBLIC_EXPONENT from %s key " "object \"%s\": 0x%lX: %s", keytype->name, label, rc, p11_get_ckr(rc)); goto done; } if (private) { bn_d = BN_secure_new(); bn_p = BN_secure_new(); bn_q = BN_secure_new(); bn_dmp1 = BN_secure_new(); bn_dmq1 = BN_secure_new(); bn_iqmp = BN_secure_new(); if (bn_d == NULL || bn_p == NULL || bn_q == NULL || bn_dmp1 == NULL || bn_dmq1 == NULL || bn_iqmp == NULL) { warnx("Failed to allocate OpenSSL BIGNUM"); rc = CKR_HOST_MEMORY; goto done; } rc = p11tool_get_bignum_attr(key, CKA_PRIVATE_EXPONENT, &bn_d); if (rc == CKR_ATTRIBUTE_SENSITIVE) goto done; rc = p11tool_get_bignum_attr(key, CKA_PRIME_1, &bn_p); if (rc == CKR_ATTRIBUTE_SENSITIVE) goto done; rc = p11tool_get_bignum_attr(key, CKA_PRIME_2, &bn_q); if (rc == CKR_ATTRIBUTE_SENSITIVE) goto done; rc = p11tool_get_bignum_attr(key, CKA_EXPONENT_1, &bn_dmp1); if (rc == CKR_ATTRIBUTE_SENSITIVE) goto done; rc = p11tool_get_bignum_attr(key, CKA_EXPONENT_2, &bn_dmq1); if (rc == CKR_ATTRIBUTE_SENSITIVE) goto done; rc = p11tool_get_bignum_attr(key, CKA_COEFFICIENT, &bn_iqmp); if (rc == CKR_ATTRIBUTE_SENSITIVE) goto done; } #if !OPENSSL_VERSION_PREREQ(3, 0) rsa = RSA_new(); if (rsa == NULL) { warnx("RSA_new failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } if (RSA_set0_key(rsa, bn_n, bn_e, bn_d) != 1) { warnx("RSA_set0_key failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } bn_n = bn_e = bn_d = NULL; if (private) { if (RSA_set0_factors(rsa, bn_p, bn_q) != 1) { warnx("RSA_set0_factors failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } bn_p = bn_q = NULL; if (RSA_set0_crt_params(rsa, bn_dmp1, bn_dmq1, bn_iqmp) != 1) { warnx("RSA_set0_crt_params failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } bn_dmp1 = bn_dmq1 = bn_iqmp = NULL; } *pkey = EVP_PKEY_new(); if (*pkey == NULL) { warnx("EVP_PKEY_new failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } if (EVP_PKEY_assign_RSA(*pkey, rsa) != 1) { warnx("EVP_PKEY_assign_RSA failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } rsa = NULL; #else tmpl = OSSL_PARAM_BLD_new(); if (tmpl == NULL) { warnx("OSSL_PARAM_BLD_new failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } if (!OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_RSA_N, bn_n) || !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_RSA_E, bn_e)) { warnx("OSSL_PARAM_BLD_push_BN failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } if (private) { if (!OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_RSA_D, bn_d) || !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_RSA_FACTOR1, bn_p) || !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_RSA_FACTOR2, bn_q) || !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_RSA_EXPONENT1, bn_dmp1) || !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_RSA_EXPONENT2, bn_dmq1) || !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_RSA_COEFFICIENT1, bn_iqmp)) { warnx("OSSL_PARAM_BLD_push_BN failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } } params = OSSL_PARAM_BLD_to_param(tmpl); if (params == NULL) { warnx("OSSL_PARAM_BLD_to_param failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL); if (pctx == NULL) { warnx("EVP_PKEY_CTX_new_id failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } if (!EVP_PKEY_fromdata_init(pctx) || !EVP_PKEY_fromdata(pctx, pkey, private ? EVP_PKEY_KEYPAIR : EVP_PKEY_PUBLIC_KEY, params)) { warnx("EVP_PKEY_fromdata_init/EVP_PKEY_fromdata failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } #endif done: if (bn_n != NULL) BN_free(bn_n); if (bn_e != NULL) BN_free(bn_e); if (bn_d != NULL) BN_clear_free(bn_d); if (bn_p != NULL) BN_clear_free(bn_p); if (bn_q != NULL) BN_clear_free(bn_q); if (bn_dmp1 != NULL) BN_clear_free(bn_dmp1); if (bn_dmq1 != NULL) BN_clear_free(bn_dmq1); if (bn_iqmp != NULL) BN_clear_free(bn_iqmp); #if !OPENSSL_VERSION_PREREQ(3, 0) if (rsa != NULL) RSA_free(rsa); #else if (pctx != NULL) EVP_PKEY_CTX_free(pctx); if (tmpl != NULL) OSSL_PARAM_BLD_free(tmpl); if (params != NULL) OSSL_PARAM_free(params); #endif if (rc != CKR_OK && *pkey != NULL) { EVP_PKEY_free(*pkey); *pkey = NULL; } return rc; } static CK_RV p11sak_export_dh_pkey(const struct p11tool_objtype *keytype, EVP_PKEY **pkey, bool private, CK_OBJECT_HANDLE key, const char *label) { BIGNUM *bn_p = NULL, *bn_g = NULL, *bn_pub = NULL, *bn_priv = NULL; #if OPENSSL_VERSION_PREREQ(3, 0) EVP_PKEY_CTX *pctx = NULL; OSSL_PARAM_BLD *tmpl = NULL; OSSL_PARAM *params = NULL; #else DH *dh = NULL; #endif CK_RV rc; rc = p11tool_get_bignum_attr(key, CKA_PRIME, &bn_p); if (rc == CKR_ATTRIBUTE_SENSITIVE) goto done; if (rc != CKR_OK) { warnx("Failed to retrieve attribute CKA_PRIME from %s key " "object \"%s\": 0x%lX: %s", keytype->name, label, rc, p11_get_ckr(rc)); goto done; } rc = p11tool_get_bignum_attr(key, CKA_BASE, &bn_g); if (rc == CKR_ATTRIBUTE_SENSITIVE) goto done; if (rc != CKR_OK) { warnx("Failed to retrieve attribute CKA_BASE from %s key " "object \"%s\": 0x%lX: %s", keytype->name, label, rc, p11_get_ckr(rc)); goto done; } if (private) { bn_priv = BN_secure_new(); if (bn_priv == NULL) { warnx("Failed to allocate OpenSSL BIGNUM"); rc = CKR_HOST_MEMORY; goto done; } } rc = p11tool_get_bignum_attr(key, CKA_VALUE, private ? &bn_priv : &bn_pub); if (rc == CKR_ATTRIBUTE_SENSITIVE) goto done; if (rc != CKR_OK) { warnx("Failed to retrieve attribute CKA_VALUE from %s key " "object \"%s\": 0x%lX: %s", keytype->name, label, rc, p11_get_ckr(rc)); goto done; } #if !OPENSSL_VERSION_PREREQ(3, 0) dh = DH_new(); if (dh == NULL) { warnx("DH_new failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } if (DH_set0_pqg(dh, bn_p, NULL, bn_g) != 1) { warnx("DH_set0_pqg failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } bn_p = bn_g = NULL; if (DH_set0_key(dh, bn_pub, bn_priv) != 1) { warnx("DH_set0_key failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } bn_pub = bn_priv = NULL; *pkey = EVP_PKEY_new(); if (*pkey == NULL) { warnx("EVP_PKEY_new failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } if (EVP_PKEY_assign_DH(*pkey, dh) != 1) { warnx("EVP_PKEY_assign_DH failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } dh = NULL; #else tmpl = OSSL_PARAM_BLD_new(); if (tmpl == NULL) { warnx("OSSL_PARAM_BLD_new failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } if (!OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_FFC_P, bn_p) || !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_FFC_G, bn_g) || (!private && !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_PUB_KEY, bn_pub)) || (private && !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_PRIV_KEY, bn_priv))) { warnx("OSSL_PARAM_BLD_push_BN failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } params = OSSL_PARAM_BLD_to_param(tmpl); if (params == NULL) { warnx("OSSL_PARAM_BLD_to_param failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_DH, NULL); if (pctx == NULL) { warnx("EVP_PKEY_CTX_new_id failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } if (!EVP_PKEY_fromdata_init(pctx) || !EVP_PKEY_fromdata(pctx, pkey, private ? EVP_PKEY_KEYPAIR : EVP_PKEY_PUBLIC_KEY, params)) { warnx("EVP_PKEY_fromdata_init/EVP_PKEY_fromdata failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } #endif done: if (bn_p != NULL) BN_free(bn_p); if (bn_g != NULL) BN_free(bn_g); if (bn_priv != NULL) BN_clear_free(bn_priv); if (bn_pub != NULL) BN_free(bn_pub); #if !OPENSSL_VERSION_PREREQ(3, 0) if (dh != NULL) DH_free(dh); #else if (pctx != NULL) EVP_PKEY_CTX_free(pctx); if (tmpl != NULL) OSSL_PARAM_BLD_free(tmpl); if (params != NULL) OSSL_PARAM_free(params); #endif if (rc != CKR_OK && *pkey != NULL) { EVP_PKEY_free(*pkey); *pkey = NULL; } return rc; } static CK_RV p11sak_export_dsa_pkey(const struct p11tool_objtype *keytype, EVP_PKEY **pkey, bool private, CK_OBJECT_HANDLE key, const char *label) { BIGNUM *bn_p = NULL, *bn_q = NULL, *bn_g = NULL; BIGNUM *bn_pub = NULL, *bn_priv = NULL; #if OPENSSL_VERSION_PREREQ(3, 0) EVP_PKEY_CTX *pctx = NULL; OSSL_PARAM_BLD *tmpl = NULL; OSSL_PARAM *params = NULL; #else DSA *dsa = NULL; #endif CK_RV rc; rc = p11tool_get_bignum_attr(key, CKA_PRIME, &bn_p); if (rc == CKR_ATTRIBUTE_SENSITIVE) goto done; if (rc != CKR_OK) { warnx("Failed to retrieve attribute CKA_PRIME from %s key " "object \"%s\": 0x%lX: %s", keytype->name, label, rc, p11_get_ckr(rc)); goto done; } rc = p11tool_get_bignum_attr(key, CKA_SUBPRIME, &bn_q); if (rc == CKR_ATTRIBUTE_SENSITIVE) goto done; if (rc != CKR_OK) { warnx("Failed to retrieve attribute CKA_SUBPRIME from %s key " "object \"%s\": 0x%lX: %s", keytype->name, label, rc, p11_get_ckr(rc)); goto done; } rc = p11tool_get_bignum_attr(key, CKA_BASE, &bn_g); if (rc == CKR_ATTRIBUTE_SENSITIVE) goto done; if (rc != CKR_OK) { warnx("Failed to retrieve attribute CKA_BASE from %s key " "object \"%s\": 0x%lX: %s", keytype->name, label, rc, p11_get_ckr(rc)); goto done; } if (private) { bn_priv = BN_secure_new(); if (bn_priv == NULL) { warnx("Failed to allocate OpenSSL BIGNUM"); rc = CKR_HOST_MEMORY; goto done; } } rc = p11tool_get_bignum_attr(key, CKA_VALUE, private ? &bn_priv : &bn_pub); if (rc == CKR_ATTRIBUTE_SENSITIVE) goto done; if (rc != CKR_OK) { warnx("Failed to retrieve attribute CKA_VALUE from %s key " "object \"%s\": 0x%lX: %s", keytype->name, label, rc, p11_get_ckr(rc)); goto done; } #if !OPENSSL_VERSION_PREREQ(3, 0) dsa = DSA_new(); if (dsa == NULL) { warnx("DSA_new failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } if (DSA_set0_pqg(dsa, bn_p, bn_q, bn_g) != 1) { warnx("DSA_set0_pqg failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } bn_p = bn_q = bn_g = NULL; if (DSA_set0_key(dsa, bn_pub, bn_priv) != 1) { warnx("DSA_set0_key failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } bn_pub = bn_priv = NULL; *pkey = EVP_PKEY_new(); if (*pkey == NULL) { warnx("EVP_PKEY_new failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } if (EVP_PKEY_assign_DSA(*pkey, dsa) != 1) { warnx("EVP_PKEY_assign_DSA failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } dsa = NULL; #else tmpl = OSSL_PARAM_BLD_new(); if (tmpl == NULL) { warnx("OSSL_PARAM_BLD_new failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } if (!OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_FFC_P, bn_p) || !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_FFC_Q, bn_q) || !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_FFC_G, bn_g) || (!private && !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_PUB_KEY, bn_pub)) || (private && !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_PRIV_KEY, bn_priv))) { warnx("OSSL_PARAM_BLD_push_BN failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } params = OSSL_PARAM_BLD_to_param(tmpl); if (params == NULL) { warnx("OSSL_PARAM_BLD_to_param failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_DSA, NULL); if (pctx == NULL) { warnx("EVP_PKEY_CTX_new_id failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } if (!EVP_PKEY_fromdata_init(pctx) || !EVP_PKEY_fromdata(pctx, pkey, private ? EVP_PKEY_KEYPAIR : EVP_PKEY_PUBLIC_KEY, params)) { warnx("EVP_PKEY_fromdata_init/EVP_PKEY_fromdata failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } #endif done: if (bn_p != NULL) BN_free(bn_p); if (bn_q != NULL) BN_free(bn_q); if (bn_g != NULL) BN_free(bn_g); if (bn_priv != NULL) BN_clear_free(bn_priv); if (bn_pub != NULL) BN_free(bn_pub); #if !OPENSSL_VERSION_PREREQ(3, 0) if (dsa != NULL) DSA_free(dsa); #else if (pctx != NULL) EVP_PKEY_CTX_free(pctx); if (tmpl != NULL) OSSL_PARAM_BLD_free(tmpl); if (params != NULL) OSSL_PARAM_free(params); #endif if (rc != CKR_OK && *pkey != NULL) { EVP_PKEY_free(*pkey); *pkey = NULL; } return rc; } static CK_RV x509_to_pem(X509 *cert, CK_BYTE **data, CK_ULONG *data_len) { BIO *bio = NULL; BUF_MEM *bptr; CK_BYTE *pem = NULL; int bio_len; CK_RV rc; bio = BIO_new(BIO_s_mem()); if (bio == NULL) return CKR_HOST_MEMORY; if (!PEM_write_bio_X509(bio, cert)) { ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } BIO_get_mem_ptr(bio, &bptr); bio_len = bptr->length; pem = malloc(bio_len); if (pem == NULL) { rc = CKR_HOST_MEMORY; goto done; } if (BIO_read(bio, pem, bio_len) != bio_len) { ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } *data = pem; *data_len = bio_len; rc = CKR_OK; done: if (bio != NULL) BIO_free(bio); return rc; } static CK_RV p11sak_export_x509(const struct p11tool_objtype *certtype, CK_BYTE **data, CK_ULONG *data_len, CK_OBJECT_HANDLE cert, const char *label) { CK_ATTRIBUTE attr = { CKA_VALUE, NULL, 0 }; const CK_BYTE *tmp_value; X509* x509; CK_RV rc; rc = p11tool_get_attribute(cert, &attr); if (rc != CKR_OK) { warnx("Failed to retrieve attribute CKA_VALUE from %s certificate " "object \"%s\": 0x%lX: %s", certtype->name, label, rc, p11_get_ckr(rc)); return rc; } if (opt_der) { *data = attr.pValue; *data_len = attr.ulValueLen; } else { tmp_value = (CK_BYTE *)attr.pValue; x509 = d2i_X509(NULL, &tmp_value, attr.ulValueLen); if (x509 == NULL) { warnx("Failed to convert CKA_VALUE from %s certificate " "object \"%s\" to X509 object.", certtype->name, label); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; if (attr.pValue != NULL) free(attr.pValue); goto done; } rc = x509_to_pem(x509, data, data_len); X509_free(x509); if (attr.pValue != NULL) free(attr.pValue); if (rc != CKR_OK) { warnx("Failed to convert X509 from %s certificate " "object \"%s\" to PEM form.", certtype->name, label); rc = CKR_FUNCTION_FAILED; goto done; } } rc = CKR_OK; done: return rc; } #if OPENSSL_VERSION_PREREQ(3, 0) static CK_RV p11sak_export_ecx_pkey(const struct p11tool_objtype *keytype, int type, EVP_PKEY **pkey, bool private, CK_OBJECT_HANDLE key, const char *label) { CK_ATTRIBUTE value_attr = { CKA_VALUE, NULL, 0 }; CK_ATTRIBUTE ecpoint_attr = { CKA_EC_POINT, NULL, 0 }; EVP_PKEY_CTX *pctx = NULL; OSSL_PARAM_BLD *tmpl = NULL; OSSL_PARAM *params = NULL; CK_BYTE *ecpoint = NULL; CK_ULONG ecpoint_len = 0; CK_RV rc; if (private) { rc = p11tool_get_attribute(key, &value_attr); if (rc == CKR_ATTRIBUTE_SENSITIVE) goto done; if (rc != CKR_OK) { warnx("Failed to retrieve attribute CKA_VALUE from %s key " "object \"%s\": 0x%lX: %s", keytype->name, label, rc, p11_get_ckr(rc)); goto done; } } else { rc = p11tool_get_attribute(key, &ecpoint_attr); if (rc == CKR_ATTRIBUTE_SENSITIVE) goto done; if (rc != CKR_OK) { warnx("Failed to retrieve attribute CKA_EC_POINT from %s key " "object \"%s\": 0x%lX: %s", keytype->name, label, rc, p11_get_ckr(rc)); goto done; } ecpoint = (CK_BYTE*)ecpoint_attr.pValue; ecpoint_len = ecpoint_attr.ulValueLen; if (keytype->type == CKK_EC) { /* remove octet string BER encoding */ if ((ecpoint[1] & 0x80) == 0) { ecpoint += 2; ecpoint_len -= 2; } else { ecpoint += 2 + (ecpoint[1] & 0x7f); ecpoint_len -= 3 + (ecpoint[1] & 0x7f); } } } tmpl = OSSL_PARAM_BLD_new(); if (tmpl == NULL) { warnx("OSSL_PARAM_BLD_new failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } if (private) { if (!OSSL_PARAM_BLD_push_octet_string(tmpl, OSSL_PKEY_PARAM_PRIV_KEY, value_attr.pValue, value_attr.ulValueLen)) { warnx("OSSL_PARAM_BLD_push_octet_string failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } } else { if (!OSSL_PARAM_BLD_push_octet_string(tmpl, OSSL_PKEY_PARAM_PUB_KEY, ecpoint, ecpoint_len)) { warnx("OSSL_PARAM_BLD_push_octet_string failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } } params = OSSL_PARAM_BLD_to_param(tmpl); if (params == NULL) { warnx("OSSL_PARAM_BLD_to_param failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } pctx = EVP_PKEY_CTX_new_id(type, NULL); if (pctx == NULL) { warnx("EVP_PKEY_CTX_new_id failed for type %d.", type); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } if (!EVP_PKEY_fromdata_init(pctx) || !EVP_PKEY_fromdata(pctx, pkey, private ? EVP_PKEY_KEYPAIR : EVP_PKEY_PUBLIC_KEY, params)) { warnx("EVP_PKEY_fromdata_init/EVP_PKEY_fromdata for type %d failed.", type); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } done: if (ecpoint_attr.pValue != NULL) free(ecpoint_attr.pValue); if (value_attr.pValue != NULL) free(value_attr.pValue); if (pctx != NULL) EVP_PKEY_CTX_free(pctx); if (tmpl != NULL) OSSL_PARAM_BLD_free(tmpl); if (params != NULL) OSSL_PARAM_free(params); if (private && ecpoint != NULL) OPENSSL_free(ecpoint); if (rc != CKR_OK && *pkey != NULL) { EVP_PKEY_free(*pkey); *pkey = NULL; } return rc; } #endif static CK_RV p11sak_export_ec_pkey(const struct p11tool_objtype *keytype, EVP_PKEY **pkey, bool private, CK_OBJECT_HANDLE key, const char *label) { BIGNUM *bn_priv = NULL; CK_ATTRIBUTE ecparams_attr = { CKA_EC_PARAMS, NULL, 0 }; CK_ATTRIBUTE ecpoint_attr = { CKA_EC_POINT, NULL, 0 }; #if OPENSSL_VERSION_PREREQ(3, 0) EVP_PKEY_CTX *pctx = NULL; OSSL_PARAM_BLD *tmpl = NULL; OSSL_PARAM *params = NULL; EC_GROUP *group = NULL; #else EC_KEY *ec = NULL; #endif CK_BYTE *ecpoint = NULL; CK_ULONG ecpoint_len = 0; EC_POINT *point = NULL; const unsigned char *oid; ASN1_OBJECT *obj = NULL; int nid; CK_RV rc; rc = p11tool_get_attribute(key, &ecparams_attr); if (rc == CKR_ATTRIBUTE_SENSITIVE) goto done; if (rc != CKR_OK) { warnx("Failed to retrieve attribute CKA_EC_PARAMS from %s key " "object \"%s\": 0x%lX: %s", keytype->name, label, rc, p11_get_ckr(rc)); goto done; } oid = ecparams_attr.pValue; obj = d2i_ASN1_OBJECT(NULL, &oid, ecparams_attr.ulValueLen); if (obj == NULL || oid != (CK_BYTE *)ecparams_attr.pValue + ecparams_attr.ulValueLen) { warnx("Curve of %s key object \"%s\" not supported by OpenSSL.", keytype->name, label); goto done; } nid = OBJ_obj2nid(obj); ASN1_OBJECT_free(obj); if (ecparams_attr.pValue != NULL) free(ecparams_attr.pValue); ecparams_attr.pValue = NULL; ecparams_attr.ulValueLen = 0; switch (nid) { #if OPENSSL_VERSION_PREREQ(3, 0) case NID_X25519: case NID_ED25519: case NID_X448: case NID_ED448: return p11sak_export_ecx_pkey(keytype, nid, pkey, private, key, label); #endif default: break; } if (private) { bn_priv = BN_secure_new(); if (bn_priv == NULL) { warnx("Failed to allocate OpenSSL BIGNUM"); rc = CKR_HOST_MEMORY; goto done; } rc = p11tool_get_bignum_attr(key, CKA_VALUE, &bn_priv); if (rc == CKR_ATTRIBUTE_SENSITIVE) goto done; if (rc != CKR_OK) { warnx("Failed to retrieve attribute CKA_VALUE from %s key " "object \"%s\": 0x%lX: %s", keytype->name, label, rc, p11_get_ckr(rc)); goto done; } } else { rc = p11tool_get_attribute(key, &ecpoint_attr); if (rc == CKR_ATTRIBUTE_SENSITIVE) goto done; if (rc != CKR_OK) { warnx("Failed to retrieve attribute CKA_EC_POINT from %s key " "object \"%s\": 0x%lX: %s", keytype->name, label, rc, p11_get_ckr(rc)); goto done; } /* remove octet string BER encoding */ ecpoint = (CK_BYTE*)ecpoint_attr.pValue; ecpoint_len = ecpoint_attr.ulValueLen; if ((ecpoint[1] & 0x80) == 0) { ecpoint += 2; ecpoint_len -= 2; } else { ecpoint += 2 + (ecpoint[1] & 0x7f); ecpoint_len -= 3 + (ecpoint[1] & 0x7f); } } #if !OPENSSL_VERSION_PREREQ(3, 0) ec = EC_KEY_new_by_curve_name(nid); if (ec == NULL) { warnx("EC_KEY_new_by_curve_name failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } if (private) { if (EC_KEY_set_private_key(ec, bn_priv) != 1) { warnx("EC_KEY_set_private_key failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } bn_priv = NULL; point = EC_POINT_new(EC_KEY_get0_group(ec)); if (point == NULL) { warnx("EC_POINT_new failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } if (!EC_POINT_mul(EC_KEY_get0_group(ec), point, EC_KEY_get0_private_key(ec), NULL, NULL, NULL)) { warnx("EC_POINT_mul failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } if (!EC_KEY_set_public_key(ec, point)) { warnx("EC_KEY_set_public_key failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } } else { if (!EC_KEY_oct2key(ec, ecpoint, ecpoint_len, NULL)) { warnx("EC_KEY_oct2key failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } } *pkey = EVP_PKEY_new(); if (*pkey == NULL) { warnx("EVP_PKEY_new failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } if (EVP_PKEY_assign_EC_KEY(*pkey, ec) != 1) { warnx("EVP_PKEY_assign_EC failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } ec = NULL; #else tmpl = OSSL_PARAM_BLD_new(); if (tmpl == NULL) { warnx("OSSL_PARAM_BLD_new failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } if (!OSSL_PARAM_BLD_push_utf8_string(tmpl, OSSL_PKEY_PARAM_GROUP_NAME, OBJ_nid2sn(nid), 0)) { warnx("OSSL_PARAM_BLD_push_BN failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } if (private) { group = EC_GROUP_new_by_curve_name(nid); if (group == NULL) { warnx("EC_GROUP_new_by_curve_name failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } point = EC_POINT_new(group); if (point == NULL) { warnx("EC_POINT_new failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } if (!EC_POINT_mul(group, point, bn_priv, NULL, NULL, NULL)) { warnx("EC_POINT_mul failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } ecpoint_len = EC_POINT_point2buf(group, point, EC_GROUP_get_point_conversion_form(group), &ecpoint, NULL); if (ecpoint_len == 0) { warnx("EC_POINT_point2buf failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } if (!OSSL_PARAM_BLD_push_octet_string(tmpl, OSSL_PKEY_PARAM_PUB_KEY, ecpoint, ecpoint_len) || !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_PRIV_KEY, bn_priv)) { warnx("OSSL_PARAM_BLD_push_BN failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } } else { if (!OSSL_PARAM_BLD_push_octet_string(tmpl, OSSL_PKEY_PARAM_PUB_KEY, ecpoint, ecpoint_len)) { warnx("OSSL_PARAM_BLD_push_BN failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } } params = OSSL_PARAM_BLD_to_param(tmpl); if (params == NULL) { warnx("OSSL_PARAM_BLD_to_param failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL); if (pctx == NULL) { warnx("EVP_PKEY_CTX_new_id failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } if (!EVP_PKEY_fromdata_init(pctx) || !EVP_PKEY_fromdata(pctx, pkey, private ? EVP_PKEY_KEYPAIR : EVP_PKEY_PUBLIC_KEY, params)) { warnx("EVP_PKEY_fromdata_init/EVP_PKEY_fromdata failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } #endif done: if (bn_priv != NULL) BN_clear_free(bn_priv); if (ecparams_attr.pValue != NULL) free(ecparams_attr.pValue); if (ecpoint_attr.pValue != NULL) free(ecpoint_attr.pValue); if (point != NULL) EC_POINT_free(point); #if !OPENSSL_VERSION_PREREQ(3, 0) if (ec != NULL) EC_KEY_free(ec); #else if (pctx != NULL) EVP_PKEY_CTX_free(pctx); if (tmpl != NULL) OSSL_PARAM_BLD_free(tmpl); if (params != NULL) OSSL_PARAM_free(params); if (group != NULL) EC_GROUP_free(group); if (private && ecpoint != NULL) OPENSSL_free(ecpoint); #endif if (rc != CKR_OK && *pkey != NULL) { EVP_PKEY_free(*pkey); *pkey = NULL; } return rc; } static CK_RV p11sak_export_dilithium_kyber_pem_data( const struct p11tool_objtype *keytype, CK_BYTE **data, CK_ULONG *data_len, bool private, CK_OBJECT_HANDLE key, const char *label) { CK_ATTRIBUTE attr = { CKA_VALUE, NULL, 0 }; CK_RV rc; UNUSED(private); rc = p11tool_get_attribute(key, &attr); if (rc == CKR_ATTRIBUTE_SENSITIVE) { warnx("%s key object \"%s\" is sensitive and can not be exported.", keytype->name, label); return rc; } if (rc != CKR_OK) { warnx("Failed to retrieve attribute CKA_VALUE from %s key " "object \"%s\": 0x%lX: %s", keytype->name, label, rc, p11_get_ckr(rc)); return rc; } *data = attr.pValue; *data_len = attr.ulValueLen; return CKR_OK; } #if OPENSSL_VERSION_PREREQ(3, 0) static const char *get_openssl_pqc_oid_name(const struct pqc_oid *oid) { const CK_BYTE *poid = oid->oid; ASN1_OBJECT *obj = NULL; int nid; if (d2i_ASN1_OBJECT(&obj, &poid, oid->oid_len) == NULL) return NULL; nid = OBJ_obj2nid(obj); ASN1_OBJECT_free(obj); if (nid == NID_undef) return NULL; return OBJ_nid2ln(nid); } #endif static CK_RV p11sak_export_dilithium_ml_dsa_pkey( const struct p11tool_objtype *keytype, EVP_PKEY **pkey, bool private, CK_OBJECT_HANDLE key, const char *label) { #if OPENSSL_VERSION_PREREQ(3, 0) CK_ULONG keyform = 0; CK_ATTRIBUTE keyform_attr = { CKA_IBM_DILITHIUM_KEYFORM, &keyform, sizeof(keyform) }; CK_ATTRIBUTE parameter_set_attr = { CKA_IBM_PARAMETER_SET, &keyform, sizeof(keyform) }; CK_ATTRIBUTE priv_attrs[] = { { CKA_IBM_ML_DSA_RHO, NULL, 0 }, { CKA_IBM_ML_DSA_SEED, NULL, 0 }, { CKA_IBM_ML_DSA_TR, NULL, 0 }, { CKA_IBM_ML_DSA_S1, NULL, 0 }, { CKA_IBM_ML_DSA_S2, NULL, 0 }, { CKA_IBM_ML_DSA_T0, NULL, 0 }, { CKA_IBM_ML_DSA_PRIVATE_SEED, NULL, 0 }, }; CK_ATTRIBUTE pub_attrs[] = { { CKA_IBM_ML_DSA_RHO, NULL, 0 }, { CKA_IBM_ML_DSA_T1, NULL, 0 }, }; const struct pqc_oid *oid; const char *alg_name; EVP_PKEY_CTX *pctx = NULL; OSSL_PARAM_BLD *bld = NULL; OSSL_PARAM *params = NULL; CK_ULONG priv_len = 0, pub_len = 0, seed_len = 0, ofs; CK_BYTE *priv_key = NULL, *pub_key = NULL, *priv_seed = NULL; CK_RV rc; rc = p11tool_get_attribute(key, keytype->type == CKK_IBM_PQC_DILITHIUM ? &keyform_attr : ¶meter_set_attr); if (rc != CKR_OK) { warnx("Failed to retrieve attribute %s from %s " "key object \"%s\": 0x%lX: %s", keytype->type == CKK_IBM_PQC_DILITHIUM ? "CKA_IBM_DILITHIUM_KEYFORM" : "CKA_IBM_PARAMETER_SET", keytype->name, label, rc, p11_get_ckr(rc)); return rc; } oid = find_pqc_by_keyform(keytype->type == CKK_IBM_PQC_DILITHIUM ? dilithium_oids : ml_dsa_oids, keyform); if (oid == NULL) { warnx("%s keyform '%lu' is not supported by p11sak.", keytype->name, keyform); return CKR_FUNCTION_FAILED; } alg_name = get_openssl_pqc_oid_name(oid); if (alg_name == NULL) { warnx("%s keyform '%lu' is not supported by OpenSSL. " "Is the 'oqsprovider' configured (for OpenSSL < version 3.5)?", keytype->name, keyform); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); return CKR_FUNCTION_FAILED; } if (private) { priv_len = oid->len_info.ml_dsa.rho_len + oid->len_info.ml_dsa.seed_len + oid->len_info.ml_dsa.tr_len + oid->len_info.ml_dsa.s1_len + oid->len_info.ml_dsa.s2_len + oid->len_info.ml_dsa.t0_len; priv_key = calloc(1, priv_len); if (priv_key == NULL) { warnx("Failed to allocate buffer for private key."); rc = CKR_HOST_MEMORY; goto out; } if (keytype->type == CKK_IBM_ML_DSA) { seed_len = oid->len_info.ml_dsa.priv_seed_len; priv_seed = calloc(1, seed_len); if (priv_seed == NULL) { warnx("Failed to allocate buffer for private seed."); rc = CKR_HOST_MEMORY; goto out; } } ofs = 0; priv_attrs[0].pValue = priv_key + ofs; priv_attrs[0].ulValueLen = oid->len_info.ml_dsa.rho_len; ofs += oid->len_info.ml_dsa.rho_len; priv_attrs[1].pValue = priv_key + ofs; priv_attrs[1].ulValueLen = oid->len_info.ml_dsa.seed_len; ofs += oid->len_info.ml_dsa.seed_len; priv_attrs[2].pValue = priv_key + ofs; priv_attrs[2].ulValueLen = oid->len_info.ml_dsa.tr_len; ofs += oid->len_info.ml_dsa.tr_len; priv_attrs[3].pValue = priv_key + ofs; priv_attrs[3].ulValueLen = oid->len_info.ml_dsa.s1_len; ofs += oid->len_info.ml_dsa.s1_len; priv_attrs[4].pValue = priv_key + ofs; priv_attrs[4].ulValueLen = oid->len_info.ml_dsa.s2_len; ofs += oid->len_info.ml_dsa.s2_len; priv_attrs[5].pValue = priv_key + ofs; priv_attrs[5].ulValueLen = oid->len_info.ml_dsa.t0_len; if (keytype->type == CKK_IBM_ML_DSA) { priv_attrs[6].pValue = priv_seed; priv_attrs[6].ulValueLen = oid->len_info.ml_dsa.priv_seed_len; } rc = p11tool_pkcs11_funcs->C_GetAttributeValue(p11tool_pkcs11_session, key, priv_attrs, keytype->type == CKK_IBM_ML_DSA ? 7 : 6); if (rc == CKR_ATTRIBUTE_SENSITIVE) goto out; if (rc != CKR_OK) { warnx("Failed to retrieve private key attributes from %s key " "object \"%s\": 0x%lX: %s", keytype->name, label, rc, p11_get_ckr(rc)); goto out; } if (priv_attrs[0].ulValueLen != oid->len_info.ml_dsa.rho_len || priv_attrs[1].ulValueLen != oid->len_info.ml_dsa.seed_len || priv_attrs[2].ulValueLen != oid->len_info.ml_dsa.tr_len || priv_attrs[3].ulValueLen != oid->len_info.ml_dsa.s1_len || priv_attrs[4].ulValueLen != oid->len_info.ml_dsa.s2_len || priv_attrs[5].ulValueLen != oid->len_info.ml_dsa.t0_len) { warnx("Failed to retrieve private key attributes from %s key " "object \"%s\": Private key component lengths are wrong.", keytype->name, label); rc = CKR_FUNCTION_FAILED; goto out; } if (keytype->type == CKK_IBM_ML_DSA && priv_attrs[6].ulValueLen != oid->len_info.ml_dsa.priv_seed_len && priv_attrs[6].ulValueLen != 0) { warnx("Failed to retrieve private key attributes from %s key " "object \"%s\": Private key component lengths are wrong.", keytype->name, label); rc = CKR_FUNCTION_FAILED; goto out; } seed_len = priv_attrs[6].ulValueLen; } pub_len = oid->len_info.ml_dsa.rho_len + oid->len_info.ml_dsa.t1_len; pub_key = calloc(1, pub_len); if (pub_key == NULL) { warnx("Failed to allocate buffer for public key."); rc = CKR_HOST_MEMORY; goto out; } ofs = 0; pub_attrs[0].pValue = pub_key + ofs; pub_attrs[0].ulValueLen = oid->len_info.ml_dsa.rho_len; ofs += oid->len_info.ml_dsa.rho_len; pub_attrs[1].pValue = pub_key + ofs; pub_attrs[1].ulValueLen = oid->len_info.ml_dsa.t1_len; rc = p11tool_pkcs11_funcs->C_GetAttributeValue(p11tool_pkcs11_session, key, pub_attrs, 2); if (rc == CKR_ATTRIBUTE_SENSITIVE) goto out; if (rc != CKR_OK) { warnx("Failed to retrieve public key attributes from %s key " "object \"%s\": 0x%lX: %s", keytype->name, label, rc, p11_get_ckr(rc)); goto out; } if (pub_attrs[0].ulValueLen != oid->len_info.ml_dsa.rho_len || pub_attrs[1].ulValueLen != oid->len_info.ml_dsa.t1_len) { warnx("Failed to retrieve public key attributes from %s key " "object \"%s\": Public key component lengths are wrong.", keytype->name, label); rc = CKR_FUNCTION_FAILED; goto out; } pctx = EVP_PKEY_CTX_new_from_name(NULL, alg_name, NULL); if (pctx == NULL) { warnx("EVP_PKEY_CTX_new_from_name failed for '%s'. " "Is the 'oqsprovider' configured (for OpenSSL < version 3.5)?", alg_name); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto out; } bld = OSSL_PARAM_BLD_new(); if (bld == NULL) { warnx("OSSL_PARAM_BLD_new failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_HOST_MEMORY; goto out; } if (private) { if (OSSL_PARAM_BLD_push_octet_string(bld, OSSL_PKEY_PARAM_PRIV_KEY, priv_key, priv_len) != 1) { warnx("OSSL_PARAM_BLD_push_octet_string failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto out; } /* Try to set private seed, but ignore if it is not available */ if (p11tool_check_settable_fromdata_params(pctx, OSSL_PKEY_PARAM_ML_KEM_SEED) && seed_len > 0) { if (OSSL_PARAM_BLD_push_octet_string(bld, OSSL_PKEY_PARAM_ML_DSA_SEED, priv_seed, seed_len) != 1) { warnx("OSSL_PARAM_BLD_push_octet_string failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto out; } } } if (OSSL_PARAM_BLD_push_octet_string(bld, OSSL_PKEY_PARAM_PUB_KEY, pub_key, pub_len) != 1) { warnx("OSSL_PARAM_BLD_push_octet_string failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto out; } params = OSSL_PARAM_BLD_to_param(bld); if (params == NULL) { warnx("OSSL_PARAM_BLD_to_param failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto out; } if (EVP_PKEY_fromdata_init(pctx) != 1) { warnx("EVP_PKEY_fromdata_init failed for '%s'.", alg_name); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto out; } if (EVP_PKEY_fromdata(pctx, pkey, private ? EVP_PKEY_KEYPAIR : EVP_PKEY_PUBLIC_KEY, params) != 1) { warnx("EVP_PKEY_fromdata failed for '%s'.", alg_name); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto out; } out: if (priv_key != NULL) { OPENSSL_cleanse(priv_key, priv_len); free(priv_key); } if (priv_seed != NULL) { OPENSSL_cleanse(priv_seed, seed_len); free(priv_seed); } if (pub_key != NULL) free(pub_key); if (pctx != NULL) EVP_PKEY_CTX_free(pctx); if (bld != NULL) OSSL_PARAM_BLD_free(bld); if (params != NULL) OSSL_PARAM_free(params); return rc; #else UNUSED(keytype); UNUSED(pkey); UNUSED(private); UNUSED(key); UNUSED(label); warnx("Exporting an 'oqsprovider' format PEM file is only supported with " "OpenSSL 3.0 or later."); return CKR_FUNCTION_NOT_SUPPORTED; #endif } static CK_RV p11sak_export_ibm_ml_kem_pkey( const struct p11tool_objtype *keytype, EVP_PKEY **pkey, bool private, CK_OBJECT_HANDLE key, const char *label) { #if OPENSSL_VERSION_PREREQ(3, 0) CK_ULONG parameter_set = 0; CK_ATTRIBUTE parameter_set_attr = { CKA_IBM_PARAMETER_SET, ¶meter_set, sizeof(parameter_set) }; CK_ATTRIBUTE priv_attrs[] = { { CKA_IBM_ML_KEM_SK, NULL, 0 }, { CKA_IBM_ML_KEM_PRIVATE_SEED, NULL, 0 }, }; CK_ATTRIBUTE pub_attrs[] = { { CKA_IBM_ML_KEM_PK, NULL, 0 }, }; const struct pqc_oid *oid; const char *alg_name; EVP_PKEY_CTX *pctx = NULL; OSSL_PARAM_BLD *bld = NULL; OSSL_PARAM *params = NULL; CK_ULONG priv_len = 0, pub_len = 0, seed_len = 0; CK_BYTE *priv_key = NULL, *pub_key = NULL, *priv_seed = NULL; CK_RV rc; rc = p11tool_get_attribute(key, ¶meter_set_attr); if (rc != CKR_OK) { warnx("Failed to retrieve attribute CKA_IBM_PARAMETER_SET from %s " "key object \"%s\": 0x%lX: %s", keytype->name, label, rc, p11_get_ckr(rc)); return rc; } oid = find_pqc_by_keyform(ml_kem_oids, parameter_set); if (oid == NULL) { warnx("%s parameter set '%lu' is not supported by p11sak.", keytype->name, parameter_set); return CKR_FUNCTION_FAILED; } alg_name = get_openssl_pqc_oid_name(oid); if (alg_name == NULL) { warnx("%s parameter set '%lu' is not supported by OpenSSL. " "Is the 'oqsprovider' configured (for OpenSSL < version 3.5)?", keytype->name, parameter_set); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); return CKR_FUNCTION_FAILED; } if (private) { priv_len = oid->len_info.ml_kem.sk_len; priv_key = calloc(1, priv_len); if (priv_key == NULL) { warnx("Failed to allocate buffer for private key."); rc = CKR_HOST_MEMORY; goto out; } seed_len = oid->len_info.ml_kem.priv_seed_len; priv_seed = calloc(1, seed_len); if (priv_seed == NULL) { warnx("Failed to allocate buffer for private seed."); rc = CKR_HOST_MEMORY; goto out; } priv_attrs[0].pValue = priv_key; priv_attrs[0].ulValueLen = oid->len_info.ml_kem.sk_len; priv_attrs[1].pValue = priv_seed; priv_attrs[1].ulValueLen = oid->len_info.ml_kem.priv_seed_len; rc = p11tool_pkcs11_funcs->C_GetAttributeValue(p11tool_pkcs11_session, key, priv_attrs, 2); if (rc == CKR_ATTRIBUTE_SENSITIVE) goto out; if (rc != CKR_OK) { warnx("Failed to retrieve private key attributes from %s key " "object \"%s\": 0x%lX: %s", keytype->name, label, rc, p11_get_ckr(rc)); goto out; } if (priv_attrs[0].ulValueLen != oid->len_info.ml_kem.sk_len || (priv_attrs[1].ulValueLen != oid->len_info.ml_kem.priv_seed_len && priv_attrs[1].ulValueLen != 0)) { warnx("Failed to retrieve private key attributes from %s key " "object \"%s\": Private key component lengths are wrong.", keytype->name, label); rc = CKR_FUNCTION_FAILED; goto out; } seed_len = priv_attrs[1].ulValueLen; } pub_len = oid->len_info.ml_kem.pk_len; pub_key = calloc(1, pub_len); if (pub_key == NULL) { warnx("Failed to allocate buffer for public key."); rc = CKR_HOST_MEMORY; goto out; } pub_attrs[0].pValue = pub_key; pub_attrs[0].ulValueLen = oid->len_info.ml_kem.pk_len; rc = p11tool_pkcs11_funcs->C_GetAttributeValue(p11tool_pkcs11_session, key, pub_attrs, 1); if (rc == CKR_ATTRIBUTE_SENSITIVE) goto out; if (rc != CKR_OK) { warnx("Failed to retrieve public key attributes from %s key " "object \"%s\": 0x%lX: %s", keytype->name, label, rc, p11_get_ckr(rc)); goto out; } if (pub_attrs[0].ulValueLen != oid->len_info.ml_kem.pk_len) { warnx("Failed to retrieve public key attributes from %s key " "object \"%s\": Public key component lengths are wrong.", keytype->name, label); rc = CKR_FUNCTION_FAILED; goto out; } pctx = EVP_PKEY_CTX_new_from_name(NULL, alg_name, NULL); if (pctx == NULL) { warnx("EVP_PKEY_CTX_new_from_name failed for '%s'. " "Is the 'oqsprovider' configured (for OpenSSL < version 3.5)?", alg_name); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto out; } bld = OSSL_PARAM_BLD_new(); if (bld == NULL) { warnx("OSSL_PARAM_BLD_new failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_HOST_MEMORY; goto out; } if (private) { if (OSSL_PARAM_BLD_push_octet_string(bld, OSSL_PKEY_PARAM_PRIV_KEY, priv_key, priv_len) != 1) { warnx("OSSL_PARAM_BLD_push_octet_string failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto out; } /* Try to set private seed, but ignore if it is not available */ if (p11tool_check_settable_fromdata_params(pctx, OSSL_PKEY_PARAM_ML_KEM_SEED) && seed_len > 0) { if (OSSL_PARAM_BLD_push_octet_string(bld, OSSL_PKEY_PARAM_ML_KEM_SEED, priv_seed, seed_len) != 1) { warnx("OSSL_PARAM_BLD_push_octet_string failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto out; } } } if (OSSL_PARAM_BLD_push_octet_string(bld, OSSL_PKEY_PARAM_PUB_KEY, pub_key, pub_len) != 1) { warnx("OSSL_PARAM_BLD_push_octet_string failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto out; } params = OSSL_PARAM_BLD_to_param(bld); if (params == NULL) { warnx("OSSL_PARAM_BLD_to_param failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto out; } if (EVP_PKEY_fromdata_init(pctx) != 1) { warnx("EVP_PKEY_fromdata_init failed for '%s'.", alg_name); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto out; } if (EVP_PKEY_fromdata(pctx, pkey, private ? EVP_PKEY_KEYPAIR : EVP_PKEY_PUBLIC_KEY, params) != 1) { warnx("EVP_PKEY_fromdata failed for '%s'.", alg_name); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto out; } out: if (priv_key != NULL) { OPENSSL_cleanse(priv_key, priv_len); free(priv_key); } if (pub_key != NULL) free(pub_key); if (pctx != NULL) EVP_PKEY_CTX_free(pctx); if (bld != NULL) OSSL_PARAM_BLD_free(bld); if (params != NULL) OSSL_PARAM_free(params); return rc; #else UNUSED(keytype); UNUSED(pkey); UNUSED(private); UNUSED(key); UNUSED(label); warnx("Exporting an 'oqsprovider' format PEM file is only supported with " "OpenSSL 3.0 or later."); return CKR_FUNCTION_NOT_SUPPORTED; #endif } static CK_RV p11sak_export_ml_dsa_pkey(const struct p11tool_objtype *keytype, EVP_PKEY **pkey, bool private, CK_OBJECT_HANDLE key, const char *label) { #if OPENSSL_VERSION_PREREQ(3, 0) CK_ULONG parameter_set = 0; CK_ATTRIBUTE parameter_set_attr = { CKA_PARAMETER_SET, ¶meter_set, sizeof(parameter_set) }; CK_ATTRIBUTE priv_attrs[] = { { CKA_VALUE, NULL, 0 }, { CKA_SEED, NULL, 0 }, }; CK_ATTRIBUTE pub_attrs[] = { { CKA_VALUE, NULL, 0 }, }; const struct pqc_oid *oid; const char *alg_name; EVP_PKEY_CTX *pctx = NULL; OSSL_PARAM_BLD *bld = NULL; OSSL_PARAM *params = NULL; CK_ULONG priv_len = 0, pub_len = 0, seed_len = 0; CK_BYTE *priv_key = NULL, *pub_key = NULL, *priv_seed = NULL; CK_RV rc; rc = p11tool_get_attribute(key, ¶meter_set_attr); if (rc != CKR_OK) { warnx("Failed to retrieve attribute CKA_PARAMETER_SET from %s " "key object \"%s\": 0x%lX: %s", keytype->name, label, rc, p11_get_ckr(rc)); return rc; } oid = find_pqc_by_keyform(ml_dsa_oids, parameter_set); if (oid == NULL) { warnx("%s parameter set '%lu' is not supported by p11sak.", keytype->name, parameter_set); return CKR_FUNCTION_FAILED; } alg_name = get_openssl_pqc_oid_name(oid); if (alg_name == NULL) { warnx("%s parameter set '%lu' is not supported by OpenSSL. " "Is the 'oqsprovider' configured (for OpenSSL < version 3.5)?", keytype->name, parameter_set); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); return CKR_FUNCTION_FAILED; } if (private) { priv_len = oid->len_info.ml_dsa.rho_len + oid->len_info.ml_dsa.seed_len + oid->len_info.ml_dsa.tr_len + oid->len_info.ml_dsa.s1_len + oid->len_info.ml_dsa.s2_len + oid->len_info.ml_dsa.t0_len; priv_key = calloc(1, priv_len); if (priv_key == NULL) { warnx("Failed to allocate buffer for private key."); rc = CKR_HOST_MEMORY; goto out; } seed_len = oid->len_info.ml_dsa.priv_seed_len; priv_seed = calloc(1, seed_len); if (priv_seed == NULL) { warnx("Failed to allocate buffer for private seed."); rc = CKR_HOST_MEMORY; goto out; } priv_attrs[0].pValue = priv_key; priv_attrs[0].ulValueLen = priv_len; priv_attrs[1].pValue = priv_seed; priv_attrs[1].ulValueLen = seed_len; rc = p11tool_pkcs11_funcs->C_GetAttributeValue(p11tool_pkcs11_session, key, priv_attrs, 2); if (rc == CKR_ATTRIBUTE_SENSITIVE) goto out; if (rc != CKR_OK) { warnx("Failed to retrieve private key attributes from %s key " "object \"%s\": 0x%lX: %s", keytype->name, label, rc, p11_get_ckr(rc)); goto out; } if (priv_attrs[0].ulValueLen != priv_len || (priv_attrs[1].ulValueLen != seed_len && priv_attrs[1].ulValueLen != 0)) { warnx("Failed to retrieve private key attributes from %s key " "object \"%s\": Private key component lengths are wrong.", keytype->name, label); rc = CKR_FUNCTION_FAILED; goto out; } seed_len = priv_attrs[1].ulValueLen; } else { pub_len = oid->len_info.ml_dsa.rho_len + oid->len_info.ml_dsa.t1_len; pub_key = calloc(1, pub_len); if (pub_key == NULL) { warnx("Failed to allocate buffer for public key."); rc = CKR_HOST_MEMORY; goto out; } pub_attrs[0].pValue = pub_key; pub_attrs[0].ulValueLen = pub_len; rc = p11tool_pkcs11_funcs->C_GetAttributeValue(p11tool_pkcs11_session, key, pub_attrs, 1); if (rc == CKR_ATTRIBUTE_SENSITIVE) goto out; if (rc != CKR_OK) { warnx("Failed to retrieve public key attributes from %s key " "object \"%s\": 0x%lX: %s", keytype->name, label, rc, p11_get_ckr(rc)); goto out; } if (pub_attrs[0].ulValueLen != pub_len) { warnx("Failed to retrieve public key attributes from %s key " "object \"%s\": Public key component lengths are wrong.", keytype->name, label); rc = CKR_FUNCTION_FAILED; goto out; } } pctx = EVP_PKEY_CTX_new_from_name(NULL, alg_name, NULL); if (pctx == NULL) { warnx("EVP_PKEY_CTX_new_from_name failed for '%s'. " "Is the 'oqsprovider' configured (for OpenSSL < version 3.5)?", alg_name); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto out; } bld = OSSL_PARAM_BLD_new(); if (bld == NULL) { warnx("OSSL_PARAM_BLD_new failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_HOST_MEMORY; goto out; } if (private) { if (OSSL_PARAM_BLD_push_octet_string(bld, OSSL_PKEY_PARAM_PRIV_KEY, priv_key, priv_len) != 1) { warnx("OSSL_PARAM_BLD_push_octet_string failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto out; } /* Try to set private seed, but ignore if it is not available */ if (p11tool_check_settable_fromdata_params(pctx, OSSL_PKEY_PARAM_ML_DSA_SEED) && seed_len > 0) { if (OSSL_PARAM_BLD_push_octet_string(bld, OSSL_PKEY_PARAM_ML_DSA_SEED, priv_seed, seed_len) != 1) { warnx("OSSL_PARAM_BLD_push_octet_string failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto out; } } } else { if (OSSL_PARAM_BLD_push_octet_string(bld, OSSL_PKEY_PARAM_PUB_KEY, pub_key, pub_len) != 1) { warnx("OSSL_PARAM_BLD_push_octet_string failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto out; } } params = OSSL_PARAM_BLD_to_param(bld); if (params == NULL) { warnx("OSSL_PARAM_BLD_to_param failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto out; } if (EVP_PKEY_fromdata_init(pctx) != 1) { warnx("EVP_PKEY_fromdata_init failed for '%s'.", alg_name); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto out; } if (EVP_PKEY_fromdata(pctx, pkey, private ? EVP_PKEY_KEYPAIR : EVP_PKEY_PUBLIC_KEY, params) != 1) { warnx("EVP_PKEY_fromdata failed for '%s'.", alg_name); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto out; } out: if (priv_key != NULL) { OPENSSL_cleanse(priv_key, priv_len); free(priv_key); } if (pub_key != NULL) free(pub_key); if (pctx != NULL) EVP_PKEY_CTX_free(pctx); if (bld != NULL) OSSL_PARAM_BLD_free(bld); if (params != NULL) OSSL_PARAM_free(params); return rc; #else UNUSED(keytype); UNUSED(pkey); UNUSED(private); UNUSED(key); UNUSED(label); warnx("Exporting an 'oqsprovider' format PEM file is only supported with " "OpenSSL 3.0 or later."); return CKR_FUNCTION_NOT_SUPPORTED; #endif } static CK_RV p11sak_export_ml_kem_pkey(const struct p11tool_objtype *keytype, EVP_PKEY **pkey, bool private, CK_OBJECT_HANDLE key, const char *label) { #if OPENSSL_VERSION_PREREQ(3, 0) CK_ULONG parameter_set = 0; CK_ATTRIBUTE parameter_set_attr = { CKA_PARAMETER_SET, ¶meter_set, sizeof(parameter_set) }; CK_ATTRIBUTE priv_attrs[] = { { CKA_VALUE, NULL, 0 }, { CKA_SEED, NULL, 0 }, }; CK_ATTRIBUTE pub_attrs[] = { { CKA_VALUE, NULL, 0 }, }; const struct pqc_oid *oid; const char *alg_name; EVP_PKEY_CTX *pctx = NULL; OSSL_PARAM_BLD *bld = NULL; OSSL_PARAM *params = NULL; CK_ULONG priv_len = 0, pub_len = 0, seed_len = 0; CK_BYTE *priv_key = NULL, *pub_key = NULL, *priv_seed = NULL; CK_RV rc; rc = p11tool_get_attribute(key, ¶meter_set_attr); if (rc != CKR_OK) { warnx("Failed to retrieve attribute CKA_PARAMETER_SET from %s " "key object \"%s\": 0x%lX: %s", keytype->name, label, rc, p11_get_ckr(rc)); return rc; } oid = find_pqc_by_keyform(ml_kem_oids, parameter_set); if (oid == NULL) { warnx("%s parameter set '%lu' is not supported by p11sak.", keytype->name, parameter_set); return CKR_FUNCTION_FAILED; } alg_name = get_openssl_pqc_oid_name(oid); if (alg_name == NULL) { warnx("%s parameter set '%lu' is not supported by OpenSSL. " "Is the 'oqsprovider' configured (for OpenSSL < version 3.5)?", keytype->name, parameter_set); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); return CKR_FUNCTION_FAILED; } if (private) { priv_len = oid->len_info.ml_kem.sk_len; priv_key = calloc(1, priv_len); if (priv_key == NULL) { warnx("Failed to allocate buffer for private key."); rc = CKR_HOST_MEMORY; goto out; } seed_len = oid->len_info.ml_kem.priv_seed_len; priv_seed = calloc(1, seed_len); if (priv_seed == NULL) { warnx("Failed to allocate buffer for private seed."); rc = CKR_HOST_MEMORY; goto out; } priv_attrs[0].pValue = priv_key; priv_attrs[0].ulValueLen = oid->len_info.ml_kem.sk_len; priv_attrs[1].pValue = priv_seed; priv_attrs[1].ulValueLen = oid->len_info.ml_kem.priv_seed_len; rc = p11tool_pkcs11_funcs->C_GetAttributeValue(p11tool_pkcs11_session, key, priv_attrs, 2); if (rc == CKR_ATTRIBUTE_SENSITIVE) goto out; if (rc != CKR_OK) { warnx("Failed to retrieve private key attributes from %s key " "object \"%s\": 0x%lX: %s", keytype->name, label, rc, p11_get_ckr(rc)); goto out; } if (priv_attrs[0].ulValueLen != oid->len_info.ml_kem.sk_len || (priv_attrs[1].ulValueLen != oid->len_info.ml_kem.priv_seed_len && priv_attrs[1].ulValueLen != 0)) { warnx("Failed to retrieve private key attributes from %s key " "object \"%s\": Private key component lengths are wrong.", keytype->name, label); rc = CKR_FUNCTION_FAILED; goto out; } seed_len = priv_attrs[1].ulValueLen; } else { pub_len = oid->len_info.ml_kem.pk_len; pub_key = calloc(1, pub_len); if (pub_key == NULL) { warnx("Failed to allocate buffer for public key."); rc = CKR_HOST_MEMORY; goto out; } pub_attrs[0].pValue = pub_key; pub_attrs[0].ulValueLen = oid->len_info.ml_kem.pk_len; rc = p11tool_pkcs11_funcs->C_GetAttributeValue(p11tool_pkcs11_session, key, pub_attrs, 1); if (rc == CKR_ATTRIBUTE_SENSITIVE) goto out; if (rc != CKR_OK) { warnx("Failed to retrieve public key attributes from %s key " "object \"%s\": 0x%lX: %s", keytype->name, label, rc, p11_get_ckr(rc)); goto out; } if (pub_attrs[0].ulValueLen != oid->len_info.ml_kem.pk_len) { warnx("Failed to retrieve public key attributes from %s key " "object \"%s\": Public key component lengths are wrong.", keytype->name, label); rc = CKR_FUNCTION_FAILED; goto out; } } pctx = EVP_PKEY_CTX_new_from_name(NULL, alg_name, NULL); if (pctx == NULL) { warnx("EVP_PKEY_CTX_new_from_name failed for '%s'. " "Is the 'oqsprovider' configured (for OpenSSL < version 3.5)?", alg_name); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto out; } bld = OSSL_PARAM_BLD_new(); if (bld == NULL) { warnx("OSSL_PARAM_BLD_new failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_HOST_MEMORY; goto out; } if (private) { if (OSSL_PARAM_BLD_push_octet_string(bld, OSSL_PKEY_PARAM_PRIV_KEY, priv_key, priv_len) != 1) { warnx("OSSL_PARAM_BLD_push_octet_string failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto out; } /* Try to set private seed, but ignore if it is not available */ if (p11tool_check_settable_fromdata_params(pctx, OSSL_PKEY_PARAM_ML_KEM_SEED) && seed_len > 0) { if (OSSL_PARAM_BLD_push_octet_string(bld, OSSL_PKEY_PARAM_ML_KEM_SEED, priv_seed, seed_len) != 1) { warnx("OSSL_PARAM_BLD_push_octet_string failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto out; } } } else { if (OSSL_PARAM_BLD_push_octet_string(bld, OSSL_PKEY_PARAM_PUB_KEY, pub_key, pub_len) != 1) { warnx("OSSL_PARAM_BLD_push_octet_string failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto out; } } params = OSSL_PARAM_BLD_to_param(bld); if (params == NULL) { warnx("OSSL_PARAM_BLD_to_param failed."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto out; } if (EVP_PKEY_fromdata_init(pctx) != 1) { warnx("EVP_PKEY_fromdata_init failed for '%s'.", alg_name); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto out; } if (EVP_PKEY_fromdata(pctx, pkey, private ? EVP_PKEY_KEYPAIR : EVP_PKEY_PUBLIC_KEY, params) != 1) { warnx("EVP_PKEY_fromdata failed for '%s'.", alg_name); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto out; } out: if (priv_key != NULL) { OPENSSL_cleanse(priv_key, priv_len); free(priv_key); } if (pub_key != NULL) free(pub_key); if (pctx != NULL) EVP_PKEY_CTX_free(pctx); if (bld != NULL) OSSL_PARAM_BLD_free(bld); if (params != NULL) OSSL_PARAM_free(params); return rc; #else UNUSED(keytype); UNUSED(pkey); UNUSED(private); UNUSED(key); UNUSED(label); warnx("Exporting an 'oqsprovider' format PEM file is only supported with " "OpenSSL 3.0 or later."); return CKR_FUNCTION_NOT_SUPPORTED; #endif } static CK_RV p11sak_export_spki(const struct p11tool_objtype *keytype, CK_OBJECT_HANDLE key, const char *typestr, const char* label, BIO* bio) { CK_ATTRIBUTE attr = { CKA_PUBLIC_KEY_INFO, NULL, 0 }; CK_RV rc; int ret; UNUSED(keytype); rc = p11tool_get_attribute(key, &attr); if (rc == CKR_ATTRIBUTE_SENSITIVE) return rc; if (rc != CKR_OK) { warnx("Failed to retrieve attribute CKA_PUBLIC_KEY_INFO from %s key " "object \"%s\": 0x%lX: %s", typestr, label, rc, p11_get_ckr(rc)); return rc; } ret = PEM_write_bio(bio, PEM_STRING_PUBLIC, "", attr.pValue, attr.ulValueLen); if (ret <= 0) { warnx("Failed to write SPKI of %s key object \"%s\" to PEM file '%s'.", typestr, label, opt_file); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } done: free(attr.pValue); return rc; } static CK_RV p11sak_export_opaque_key(const struct p11tool_objtype *keytype, CK_OBJECT_HANDLE key, const char *typestr, const char* label, BIO* bio) { CK_ATTRIBUTE attr = { CKA_IBM_OPAQUE, NULL, 0 }; CK_RV rc; UNUSED(keytype); rc = p11tool_get_attribute(key, &attr); if (rc == CKR_ATTRIBUTE_SENSITIVE) return rc; if (rc != CKR_OK) { warnx("Failed to retrieve attribute CKA_IBM_OPAQUE from %s key " "object \"%s\": 0x%lX: %s", typestr, label, rc, p11_get_ckr(rc)); return rc; } if (BIO_write(bio, attr.pValue, attr.ulValueLen) != (int)attr.ulValueLen) { warnx("Failed to write to file '%s'.", opt_file); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } done: free(attr.pValue); return rc; } static CK_ULONG ber_encode_len(CK_ULONG data_len, CK_BYTE *out) { CK_ULONG ret = 0; if (data_len < 128) { ret = 1; if (out != NULL) out[0] = (CK_BYTE)(data_len & 0x7f); } else if (data_len < 256) { ret = 2; if (out != NULL) { out[0] = 0x81; out[1] = (CK_BYTE)(data_len & 0xff); } } else if (data_len < (1 << 16)) { ret = 3; if (out != NULL) { out[0] = 0x82; out[1] = (CK_BYTE)((data_len >> 8) & 0xff); out[2] = (CK_BYTE)(data_len & 0xff); } } return ret; } static CK_RV p11sak_export_uri_pem(const struct p11tool_objtype *keytype, CK_OBJECT_HANDLE key, CK_OBJECT_CLASS class, const char *typestr, const char *msgtype, const char* label, BIO* bio) { struct p11_uri *uri = NULL; const char *uri_str; CK_ULONG descr_len, uri_len, total_len, ofs = 0; CK_BYTE *data = NULL; CK_RV rc; int ret; rc = p11tool_prepare_uri(key, &class, keytype, typestr, label, opt_detailed_uri, opt_slot, &uri); if (rc != CKR_OK) goto done; if (opt_uri_pin_value) uri->pin_value = p11tool_pin; else if (opt_uri_pin_source != NULL) uri->pin_source = opt_uri_pin_source; uri_str = p11_uri_format(uri); descr_len = 1 + ber_encode_len(strlen(PKCS11_URI_DESCRIPTION), NULL) + strlen(PKCS11_URI_DESCRIPTION); uri_len = 1 + ber_encode_len(strlen(uri_str), NULL) + strlen(uri_str); total_len = 1 + ber_encode_len(descr_len + uri_len, NULL) + descr_len + uri_len; data = calloc(total_len, 1); if (data == NULL) { warnx("Failed to allocate a buffer for the URI-PEM data"); rc = CKR_HOST_MEMORY; goto done; } data[ofs++] = 0x30; /* SEQUENE */ ofs += ber_encode_len(descr_len + uri_len, &data[ofs]); data[ofs++] = 0x1a; /* VISIBLE STRING */ ofs += ber_encode_len(strlen(PKCS11_URI_DESCRIPTION), &data[ofs]); memcpy(&data[ofs], PKCS11_URI_DESCRIPTION, strlen(PKCS11_URI_DESCRIPTION)); ofs += strlen(PKCS11_URI_DESCRIPTION); data[ofs++] = 0x0c; /* UTF8 STRING */ ofs += ber_encode_len(strlen(uri_str), &data[ofs]); memcpy(&data[ofs], uri_str, strlen(uri_str)); ofs += strlen(uri_str); ret = PEM_write_bio(bio, PKCS11_URI_PEM_NAME, "", data, total_len); if (ret <= 0) { warnx("Failed to write %s %s object \"%s\" to URI-PEM file '%s'.", typestr, msgtype, label, opt_file); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } done: if (uri != NULL) { if (uri->obj_id[0].pValue != NULL) free(uri->obj_id[0].pValue); p11_uri_free(uri); } if (data != NULL) { OPENSSL_cleanse(data, total_len); free(data); } return rc; } static CK_RV p11sak_export_asym_key(const struct p11tool_objtype *keytype, CK_OBJECT_HANDLE key, bool private, const char *typestr, const char* label, BIO* bio) { struct p11tool_pem_password_cb_data cb_data = { 0 }; EVP_PKEY *pkey = NULL; CK_BYTE *data = NULL; CK_ULONG data_len = 0; CK_RV rc = CKR_OK; int ret; if (private && has_ibm_opaque_attr(key)) { warnx("%s key object \"%s\" contains an opaque secure key blob and " "can not be exported in clear.", typestr, label); warnx("Use option '-o'/'--opaque' to export the opaque secure key blob " "instead."); return CKR_KEY_UNEXTRACTABLE; } if (opt_oqsprovider_pem && !keytype->supports_oqsprovider_pem) { warnx("Option '--oqsprovider-pem' is not supported for keytype '%s'.", keytype->name); return CKR_ARGUMENTS_BAD; } if (keytype->export_asym_pkey != NULL && (!keytype->supports_oqsprovider_pem || (opt_oqsprovider_pem && keytype->supports_oqsprovider_pem))) { if (opt_encrypted_pem && !private) { warnx("Option '-e'/'--encrypted-pem' is specified but is ignored " "for exporting %s key \"%s\".", typestr, label); } rc = keytype->export_asym_pkey(keytype, &pkey, private, key, label); if (rc != CKR_OK) goto done; cb_data.pem_file_name = opt_file; cb_data.pem_password = opt_pem_password; cb_data.env_var_name = PKCS11_PEM_PASSWORD_ENV_NAME; cb_data.force_prompt = opt_force_pem_pwd_prompt; if (private) ret = PEM_write_bio_PrivateKey(bio, pkey, opt_encrypted_pem ? EVP_aes_256_cbc() : NULL, NULL, 0, p11tool_pem_password_cb, &cb_data); else ret = PEM_write_bio_PUBKEY(bio, pkey); if (ret != 1) { warnx("Failed to write %s key object \"%s\" to PEM file '%s'.", typestr, label, opt_file); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } } else if (keytype->export_asym_pem_data != NULL) { if (opt_encrypted_pem) { warnx("Option '-e'/'--encrypted-pem' is specified but is ignored " "for exporting %s key \"%s\".", typestr, label); } rc = keytype->export_asym_pem_data(keytype, &data, &data_len, private, key, label); if (rc != CKR_OK) goto done; ret = PEM_write_bio(bio, private ? keytype->pem_name_private : keytype->pem_name_public, "", data, data_len); if (ret <= 0) { warnx("Failed to write %s key object \"%s\" to PEM file '%s'.", typestr, label, opt_file); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } } else { warnx("No support for exporting %s key object \"%s\" to a PEM " "file '%s'", typestr, label, opt_file); rc = CKR_ARGUMENTS_BAD; goto done; } done: if (pkey != NULL) EVP_PKEY_free(pkey); if (data != NULL) { OPENSSL_cleanse(data, data_len); free(data); } return rc; } static CK_RV p11sak_export_sym_key(const struct p11tool_objtype *keytype, CK_OBJECT_HANDLE key, const char *typestr, const char* label, BIO* bio) { CK_BYTE *data = NULL; CK_ULONG data_len = 0; CK_RV rc; if (opt_encrypted_pem) { warnx("Option '-e'/'--encrypted-pem' is specified but is ignored for " "exporting %s key \"%s\".", typestr, label); } if (keytype->export_sym_clear == NULL) { warnx("No support for exporting %s key object \"%s\" to file '%s'", typestr, label, opt_file); return CKR_ARGUMENTS_BAD; } if (has_ibm_opaque_attr(key)) { warnx("%s key object \"%s\" contains an opaque secure key blob and " "can not be exported in clear.", typestr, label); warnx("Use option '-o'/'--opaque' to export the opaque secure key blob " "instead."); return CKR_KEY_UNEXTRACTABLE; } rc = keytype->export_sym_clear(keytype, &data, &data_len, key, label); if (rc != CKR_OK) goto done; if (BIO_write(bio, data, data_len) != (int)data_len) { warnx("Failed to write to file '%s'.", opt_file); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } done: if (data != NULL) { OPENSSL_cleanse(data, data_len); free(data); } return rc; } static CK_RV p11sak_key_extract_pubkey(const struct p11tool_objtype *keytype, CK_OBJECT_HANDLE key, const char *typestr, const char* label) { CK_OBJECT_HANDLE pubkey; CK_ATTRIBUTE spki = { CKA_PUBLIC_KEY_INFO, NULL, 0 }; CK_ATTRIBUTE id_attr = { CKA_ID, NULL, 0 }; const unsigned char *p; CK_ATTRIBUTE *attrs = NULL; CK_ULONG num_attrs = 0; EVP_PKEY *pkey = NULL; char *pubkey_label = NULL; CK_OBJECT_CLASS key_class = CKO_PUBLIC_KEY; CK_BBOOL btrue = CK_TRUE; CK_RV rc; CK_MECHANISM pub_from_priv_mech = { CKM_PUB_KEY_FROM_PRIV_KEY, NULL, 0 }; CK_BBOOL pub_from_priv_supported; CK_BBOOL derive_val = CK_FALSE; CK_ATTRIBUTE derive = { CKA_DERIVE, &derive_val, sizeof(derive_val) }; pub_from_priv_supported = (p11tool_check_pub_from_priv_mech_supported(opt_slot) == CKR_OK); rc = p11tool_get_attribute(key, &derive); if (rc != CKR_OK || derive_val == CK_FALSE) pub_from_priv_supported = CK_FALSE; if (opt_new_attr != NULL) { rc = p11tool_parse_boolean_attrs(keytype, p11sak_bool_attrs, opt_new_attr, &attrs, &num_attrs, true, opt_so, p11tool_public_attr_applicable); if (rc != CKR_OK) goto done; if (num_attrs == 0) { warnx("None of the specified attributes apply to a public key object."); rc = CKR_ARGUMENTS_BAD; goto done; } } if (opt_new_label != NULL) { rc = p11tool_add_attribute(CKA_LABEL, opt_new_label, strlen(opt_new_label), &attrs, &num_attrs); if (rc != CKR_OK) { warnx("Failed to add %s key attribute CKA_LABEL: 0x%lX: %s", keytype->name, rc, p11_get_ckr(rc)); goto done; } } if (!pub_from_priv_supported) { if (opt_new_id != NULL) { rc = p11tool_parse_id(opt_new_id, &attrs, &num_attrs); if (rc != CKR_OK) goto done; } rc = p11tool_get_attribute(key, &spki); if (rc != CKR_OK) { warnx("Failed to retrieve attribute CKA_PUBLIC_KEY_INFO from %s " "key object \"%s\": 0x%lX: %s", typestr, label, rc, p11_get_ckr(rc)); goto done; } if (keytype->import_asym_pem_data != NULL) { rc = keytype->import_asym_pem_data(keytype, (unsigned char *)spki.pValue, spki.ulValueLen, false, &attrs, &num_attrs); } else if (keytype->import_asym_pkey != NULL) { p = spki.pValue; pkey = d2i_PUBKEY(NULL, &p, spki.ulValueLen); if (pkey == NULL) { warnx("OpenSSL d2i_PUBKEY failed to get PKEY from SPKI."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } rc = keytype->import_asym_pkey(keytype, pkey, false, &attrs, &num_attrs); } else { warnx("No support for extracting %s public key", keytype->name); rc = CKR_ARGUMENTS_BAD; } if (rc != CKR_OK) goto done; } /* If no new label parm specified, derive new label from key label */ if (opt_new_label == NULL) { if (asprintf(&pubkey_label, "%s_pubkey", label) < 0 || pubkey_label == NULL) { warnx("Failed to allocate memory for new public key label."); rc = CKR_HOST_MEMORY; goto done; } rc = p11tool_add_attribute(CKA_LABEL, pubkey_label, strlen(pubkey_label), &attrs, &num_attrs); if (rc != CKR_OK) { warnx("Failed to add attributes for extracted key's public key."); goto done; } } /* If no new ID is specified, try to use ID from certificate */ if (opt_new_id == NULL) { rc = p11tool_get_attribute(key, &id_attr); if (rc == CKR_OK && id_attr.ulValueLen > 0) { rc = p11tool_add_attribute(CKA_ID, id_attr.pValue, id_attr.ulValueLen, &attrs, &num_attrs); if (rc != CKR_OK) { warnx("Failed to add attributes for extracted key's public key."); goto done; } } } rc = p11tool_add_attribute(CKA_CLASS, &key_class, sizeof(CK_OBJECT_CLASS), &attrs, &num_attrs); rc += p11tool_add_attribute(CKA_KEY_TYPE, &keytype->type, sizeof(CK_KEY_TYPE), &attrs, &num_attrs); rc += p11tool_add_attribute(CKA_TOKEN, &btrue, sizeof(CK_BBOOL), &attrs, &num_attrs); if (rc != CKR_OK) { warnx("Failed to add attributes for extracted key's public key."); rc = CKR_FUNCTION_FAILED; goto done; } if (!pub_from_priv_supported) { rc = p11tool_pkcs11_funcs->C_CreateObject(p11tool_pkcs11_session, attrs, num_attrs, &pubkey); } else { rc = p11tool_pkcs11_funcs->C_DeriveKey(p11tool_pkcs11_session, &pub_from_priv_mech, key, attrs, num_attrs, &pubkey); } if (rc != CKR_OK) { if (p11tool_is_rejected_by_policy(rc, p11tool_pkcs11_session)) warnx("Public key extraction of a %s key is rejected by policy", keytype->name); else warnx("Public key extraction of a %s key failed: 0x%lX: %s", keytype->name, rc, p11_get_ckr(rc)); goto done; } done: p11tool_free_attributes(attrs, num_attrs); if (spki.pValue != NULL) free(spki.pValue); if (id_attr.pValue != NULL) free(id_attr.pValue); if (pkey != NULL) EVP_PKEY_free(pkey); if (pubkey_label != NULL) free(pubkey_label); return rc; } static CK_RV p11sak_cert_extract_pubkey(const struct p11tool_objtype *certtype, CK_OBJECT_HANDLE cert, const char *typestr, const char* label) { CK_OBJECT_HANDLE pubkey; CK_ATTRIBUTE *attrs = NULL; CK_ULONG num_attrs = 0; CK_RV rc; UNUSED(typestr); if (opt_new_attr != NULL) { rc = p11tool_parse_boolean_attrs(certtype, p11sak_bool_attrs, opt_new_attr, &attrs, &num_attrs, true, opt_so, p11tool_public_attr_applicable); if (rc != CKR_OK) goto done; if (num_attrs == 0) { warnx("None of the specified attributes apply to a public key object."); rc = CKR_ARGUMENTS_BAD; goto done; } } if (opt_new_label != NULL) { rc = p11tool_add_attribute(CKA_LABEL, opt_new_label, strlen(opt_new_label), &attrs, &num_attrs); if (rc != CKR_OK) { warnx("Failed to add %s key attribute CKA_LABEL: 0x%lX: %s", certtype->name, rc, p11_get_ckr(rc)); goto done; } } if (opt_new_id != NULL) { rc = p11tool_parse_id(opt_new_id, &attrs, &num_attrs); if (rc != CKR_OK) goto done; } rc = certtype->extract_x509_pubkey(certtype, &attrs, &num_attrs, cert, label); if (rc != CKR_OK) { warnx("Failed to extract public key from certificate object: 0x%lx: %s", rc, p11_get_ckr(rc)); goto done; } rc = p11tool_pkcs11_funcs->C_CreateObject(p11tool_pkcs11_session, attrs, num_attrs, &pubkey); if (rc != CKR_OK) { if (p11tool_is_rejected_by_policy(rc, p11tool_pkcs11_session)) warnx("Public key extraction of a %s certificate is rejected by " "policy", certtype->name); else warnx("Public key extraction of a %s certificate failed: 0x%lX: %s", certtype->name, rc, p11_get_ckr(rc)); goto done; } done: p11tool_free_attributes(attrs, num_attrs); return rc; } static CK_RV handle_key_export(CK_OBJECT_HANDLE key, CK_OBJECT_CLASS class, const struct p11tool_objtype *keytype, CK_ULONG keysize, const char *typestr, const char* label, const char *common_name, void *private) { struct p11sak_export_data *data = private; char *msg = NULL; BIO *bio; bool overwrite = false; char ch; CK_RV rc; UNUSED(keysize); UNUSED(common_name); if (data->skip_all) { data->num_skipped++; return CKR_OK; } if (!data->export_all) { if (asprintf(&msg, "Are you sure you want to export %s key object \"%s\" [y/n/a/c]? ", typestr, label) < 0 || msg == NULL) { warnx("Failed to allocate memory for a message"); return CKR_HOST_MEMORY; } ch = p11tool_prompt_user(msg, "ynac"); free(msg); switch (ch) { case 'n': data->num_skipped++; return CKR_OK; case 'c': case '\0': data->skip_all = true; data->num_skipped++; return CKR_OK; case 'a': data->export_all = true; break; default: break; } } if (opt_spki && class != CKO_PRIVATE_KEY) { warnx("The '-S'/'--spki' option can only be used with private keys."); data->num_failed++; return CKR_OK; } if (opt_opaque && data->num_exported > 0) { printf("The last exported key was a binary opaque secure key blob, " "and the current\nkey is also to be exported as binary opaque " "secure key blob.\nIt can not be appended to the previously " "exported key(s).\n"); overwrite = true; } else if (keytype->is_asymmetric) { if (data->last_was_binary) { printf("The last exported key was a binary symmetric key, but " "the current\nkey is an asymmetric key to be exported in " "PEM format.\nIt can not be appended to the previously " "exported key(s).\n"); overwrite = true; } } else { if (data->last_was_binary) { printf("The last exported key was a binary symmetric key, and " "the current\nkey is also a symmetric key to be exported " "in binary.\nIt can not be appended to the previously " "exported key(s).\n"); overwrite = true; } else if (data->last_was_pem) { printf("The last exported key was an asymmetric key in PEM " "format, but the\ncurrent key is a symmetric key to be " "exported in binary.\nIt can not be appended to the " "previously exported key(s).\n"); overwrite = true; } } if (overwrite && !opt_force) { ch = p11tool_prompt_user("Overwrite the previously exported " "key(s) [y/n]? ", "yn"); switch (ch) { case 'n': data->num_skipped++; return CKR_OK; default: break; } } bio = BIO_new_file(opt_file, overwrite || data->num_exported == 0 ? "w" : "a"); if (bio == NULL) { warnx("Failed to open PEM file '%s'.", opt_file); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); data->num_failed++; return CKR_ARGUMENTS_BAD; } if (opt_opaque) rc = p11sak_export_opaque_key(keytype, key, typestr, label, bio); else if (opt_spki) rc = p11sak_export_spki(keytype, key, typestr, label, bio); else if (opt_uri_pem) rc = p11sak_export_uri_pem(keytype, key, class, typestr, "key", label, bio); else if (keytype->is_asymmetric) rc = p11sak_export_asym_key(keytype, key, class == CKO_PRIVATE_KEY, typestr, label, bio); else rc = p11sak_export_sym_key(keytype, key, typestr, label, bio); if (rc != CKR_OK) { if (rc == CKR_ATTRIBUTE_SENSITIVE) warnx("%s key object \"%s\" is sensitive and can not be exported.", typestr, label); data->num_failed++; rc = CKR_OK; goto done; } printf("Successfully exported %s key object \"%s\" to file '%s'.\n", typestr, label, opt_file); data->num_exported++; data->last_was_pem = (keytype->is_asymmetric && !opt_opaque) || opt_uri_pem; data->last_was_binary = (!keytype->is_asymmetric || opt_opaque) && !opt_uri_pem; done: BIO_free(bio); return rc; } static CK_RV handle_key_pubkey_extract(CK_OBJECT_HANDLE cert, CK_OBJECT_CLASS class, const struct p11tool_objtype *keytype, CK_ULONG keysize, const char *typestr, const char* label, const char *common_name, void *private) { struct p11sak_export_data *data = private; char *msg = NULL; char ch; CK_RV rc; UNUSED(keysize); UNUSED(common_name); if (class != CKO_PRIVATE_KEY) return CKR_OK; if (data->skip_all) { data->num_skipped++; return CKR_OK; } if (!data->export_all) { if (asprintf(&msg, "Are you sure you want to extract the public key from %s key object \"%s\" [y/n/a/c]? ", typestr, label) < 0 || msg == NULL) { warnx("Failed to allocate memory for a message"); return CKR_HOST_MEMORY; } ch = p11tool_prompt_user(msg, "ynac"); free(msg); switch (ch) { case 'n': data->num_skipped++; return CKR_OK; case 'c': case '\0': data->skip_all = true; data->num_skipped++; return CKR_OK; case 'a': data->export_all = true; break; default: break; } } rc = p11sak_key_extract_pubkey(keytype, cert, typestr, label); if (rc != CKR_OK) { data->num_failed++; rc = CKR_OK; goto done; } if (opt_new_label != NULL) printf("Successfully extracted the public key from %s key object \"%s\" into new token object \"%s\".\n", typestr, label, opt_new_label); else printf("Successfully extracted the public key from %s key object \"%s\" into new token object \"%s_pubkey\".\n", typestr, label, label); data->num_exported++; done: return rc; } static CK_RV handle_cert_export(CK_OBJECT_HANDLE cert, CK_OBJECT_CLASS class, const struct p11tool_objtype *certtype, CK_ULONG keysize, const char *typestr, const char* label, const char *common_name, void *private) { struct p11sak_export_data *data = private; char *msg = NULL; BIO *bio = NULL; bool overwrite = false; char ch; CK_BYTE *cert_data = NULL; CK_ULONG data_len = 0; CK_RV rc; UNUSED(class); UNUSED(keysize); UNUSED(common_name); if (data->skip_all) { data->num_skipped++; return CKR_OK; } if (!data->export_all) { if (asprintf(&msg, "Are you sure you want to export %s certificate object \"%s\" [y/n/a/c]? ", typestr, label) < 0 || msg == NULL) { warnx("Failed to allocate memory for a message"); return CKR_HOST_MEMORY; } ch = p11tool_prompt_user(msg, "ynac"); free(msg); switch (ch) { case 'n': data->num_skipped++; return CKR_OK; case 'c': case '\0': data->skip_all = true; data->num_skipped++; return CKR_OK; case 'a': data->export_all = true; break; default: break; } } if (opt_der && data->num_exported > 0) { printf("The last exported and current certificate are both in binary " "form.\nIt's not possible to write both into the same file.\n"); overwrite = true; } if (overwrite && !opt_force) { ch = p11tool_prompt_user("Overwrite the previously exported " "certificate(s) [y/n]? ", "yn"); switch (ch) { case 'n': data->num_skipped++; return CKR_OK; default: break; } } bio = BIO_new_file(opt_file, overwrite || data->num_exported == 0 ? "w" : "a"); if (bio == NULL) { warnx("Failed to open output file '%s'.", opt_file); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); data->num_failed++; return CKR_ARGUMENTS_BAD; } if (opt_uri_pem) { rc = p11sak_export_uri_pem(certtype, cert, class, typestr, "certificate", label, bio); if (rc != CKR_OK) { warnx("Failed to export certificate object into URI-PEM file, " "0x%lx: %s", rc, p11_get_ckr(rc)); data->num_failed++; rc = CKR_OK; goto done; } goto finish; } rc = certtype->export_x509_data(certtype, &cert_data, &data_len, cert, label); if (rc != CKR_OK) { warnx("Failed to export certificate object into X509 object, 0x%lx: %s", rc, p11_get_ckr(rc)); data->num_failed++; rc = CKR_OK; goto done; } if (BIO_write(bio, cert_data, data_len) != (int)data_len) { warnx("Failed to write to file '%s'.", opt_file); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); data->num_failed++; rc = CKR_OK; goto done; } finish: printf("Successfully exported %s certificate object \"%s\" to file '%s'.\n", typestr, label, opt_file); data->num_exported++; data->last_was_pem = !opt_der || opt_uri_pem; data->last_was_binary = opt_der && !opt_uri_pem; done: free(cert_data); if (bio != NULL) BIO_free(bio); return rc; } static CK_RV handle_cert_pubkey_extract(CK_OBJECT_HANDLE cert, CK_OBJECT_CLASS class, const struct p11tool_objtype *certtype, CK_ULONG keysize, const char *typestr, const char* label, const char *common_name, void *private) { struct p11sak_export_data *data = private; char *msg = NULL; char ch; CK_RV rc; UNUSED(class); UNUSED(keysize); UNUSED(common_name); if (data->skip_all) { data->num_skipped++; return CKR_OK; } if (!data->export_all) { if (asprintf(&msg, "Are you sure you want to extract the public key from %s certificate object \"%s\" [y/n/a/c]? ", typestr, label) < 0 || msg == NULL) { warnx("Failed to allocate memory for a message"); return CKR_HOST_MEMORY; } ch = p11tool_prompt_user(msg, "ynac"); free(msg); switch (ch) { case 'n': data->num_skipped++; return CKR_OK; case 'c': case '\0': data->skip_all = true; data->num_skipped++; return CKR_OK; case 'a': data->export_all = true; break; default: break; } } rc = p11sak_cert_extract_pubkey(certtype, cert, typestr, label); if (rc != CKR_OK) { data->num_failed++; rc = CKR_OK; goto done; } if (opt_new_label != NULL) printf("Successfully extracted the public key from %s certificate object \"%s\" into new token object \"%s\".\n", typestr, label, opt_new_label); else printf("Successfully extracted the public key from %s certificate object \"%s\" into new token object \"%s_pubkey\".\n", typestr, label, label); data->num_exported++; done: return rc; } static CK_RV p11sak_create_uri_pin_source(const char *pin_source, const char *pin) { FILE *fp; CK_RV rc = CKR_OK; fp = fopen(pin_source, "w"); if (fp == NULL) { warnx("Failed to open pin-source file '%s' for writing: %s", pin_source, strerror(errno)); return CKR_ARGUMENTS_BAD; } if (fchmod(fileno(fp), S_IRUSR | S_IWUSR) != 0) { warnx("Failed to set permissions of pin-source file '%s': %s", pin_source, strerror(errno)); rc = CKR_FUNCTION_FAILED; goto out; } if (fprintf(fp, "%s\n", pin) <= 0) { warnx("Failed to write to pin-source file '%s': %s", pin_source, strerror(errno)); rc = CKR_FUNCTION_FAILED; goto out; } out: fclose(fp); if (rc == CKR_OK) { printf("Successfully wrote PKCS#11 user PIN into '%s'.\n", pin_source); printf("Adjust the file permissions of that file so that it can only " "be read by the desired user(s).\n"); } return rc; } static CK_RV p11sak_export_key(void) { const struct p11tool_objtype *keytype = NULL; struct p11sak_export_data data = { 0 }; CK_RV rc; if (opt_keytype != NULL) keytype = opt_keytype->private.ptr; data.export_all = opt_force; if ((opt_opaque && opt_spki) || (opt_opaque && opt_uri_pem) || (opt_spki && opt_uri_pem)) { warnx("Either '-o'/'--opaque', '-S'/'--spki', or '-u'/'--uri-pem' can " "be specified."); return CKR_ARGUMENTS_BAD; } if (opt_uri_pin_value && !opt_uri_pem) { warnx("Option '--uri-pin-value' can only be specified together with " "the '-u'/'--uri-pem' option."); return CKR_ARGUMENTS_BAD; } if (opt_uri_pin_value && opt_no_login) { warnx("Option '--uri-pin-value' can not be specified together with " "the '-N'/'--no_login' option."); return CKR_ARGUMENTS_BAD; } if (opt_uri_pin_value && opt_so) { warnx("Option '--uri-pin-value' can not be specified together with " "the '--so' option."); return CKR_ARGUMENTS_BAD; } if (opt_uri_pin_source != NULL && !opt_uri_pem) { warnx("Option '--uri-pin-source' can only be specified together with " "the '-u'/'--uri-pem' option."); return CKR_ARGUMENTS_BAD; } if (opt_uri_pin_source != NULL && opt_no_login) { warnx("Option '--uri-pin-source' can not be specified together with " "the '-N'/'--no_login' option."); return CKR_ARGUMENTS_BAD; } if (opt_uri_pin_source != NULL && opt_so) { warnx("Option '--uri-pin-source' can not be specified together with " "the '--so' option."); return CKR_ARGUMENTS_BAD; } if (opt_encrypted_pem && (opt_spki || opt_opaque || opt_uri_pem)) { warnx("Option '-e'/'--encrypted-pem' can not be specified together " "with the '-o'/'--opaque', '-S'/'--spki', or '-u'/'--uri-pem' " "options"); return CKR_ARGUMENTS_BAD; } if (opt_pem_password != NULL && !opt_encrypted_pem) { warnx("Option '-P'/'--pem-password' can only be specified together " "with the '-e'/'--encrypted-pem' option."); return CKR_ARGUMENTS_BAD; } if (opt_force_pem_pwd_prompt && !opt_encrypted_pem) { warnx("Option '--force-pem-pwd-prompt' can only be specified together " "with the '-e'/'--encrypted-pem' option."); return CKR_ARGUMENTS_BAD; } if (opt_oqsprovider_pem && keytype != NULL && !keytype->supports_oqsprovider_pem) { warnx("Option '--oqsprovider-pem' is not supported for keytype '%s'.", keytype->name); return CKR_ARGUMENTS_BAD; } rc = iterate_objects(keytype, opt_label, opt_id, opt_attr, OBJCLASS_KEY, NULL, handle_key_export, &data); if (rc != CKR_OK) { warnx("Failed to iterate over key objects for key type %s: 0x%lX: %s", keytype != NULL ? keytype->name : "All", rc, p11_get_ckr(rc)); return rc; } if (opt_uri_pem && opt_uri_pin_source != NULL && p11tool_pin != NULL && data.num_exported > 0) { rc = p11sak_create_uri_pin_source(opt_uri_pin_source, p11tool_pin); return rc; } printf("%lu key object(s) exported.\n", data.num_exported); if (data.num_skipped > 0) printf("%lu key object(s) skipped.\n", data.num_skipped); if (data.num_failed > 0) printf("%lu key object(s) failed to export.\n", data.num_failed); return data.num_failed == 0 ? CKR_OK : CKR_FUNCTION_FAILED; } static CK_RV p11sak_extract_key_pubkey(void) { const struct p11tool_objtype *keytype = NULL; struct p11sak_export_data data = { 0 }; CK_RV rc; if (opt_keytype != NULL) keytype = opt_keytype->private.ptr; data.export_all = opt_force; rc = iterate_objects(keytype, opt_label, opt_id, opt_attr, OBJCLASS_KEY, NULL, handle_key_pubkey_extract, &data); if (rc != CKR_OK) { warnx("Failed to iterate over key objects for type %s: 0x%lX: %s", keytype != NULL ? keytype->name : "All", rc, p11_get_ckr(rc)); return rc; } printf("%lu public key object(s) extracted.\n", data.num_exported); if (data.num_skipped > 0) printf("%lu private key object(s) skipped.\n", data.num_skipped); if (data.num_failed > 0) printf("%lu private key object(s) failed to export the public key.\n", data.num_failed); return data.num_failed == 0 ? CKR_OK : CKR_FUNCTION_FAILED; } static CK_RV p11sak_export_cert(void) { const struct p11tool_objtype *certtype = NULL; struct p11sak_export_data data = { 0 }; CK_RV rc; if (opt_certtype != NULL) certtype = opt_certtype->private.ptr; data.export_all = opt_force; if (opt_der && opt_uri_pem) { warnx("Either '-D'/'--der' or '-u'/'--uri-pem' can be specified."); return CKR_ARGUMENTS_BAD; } if (opt_uri_pin_value && !opt_uri_pem) { warnx("Option '--uri-pin-value' can only be specified together with " "the '-u'/'--uri-pem' option."); return CKR_ARGUMENTS_BAD; } if (opt_uri_pin_value && opt_no_login) { warnx("Option '--uri-pin-value' can not be specified together with " "the '-N'/'--no_login' option."); return CKR_ARGUMENTS_BAD; } if (opt_uri_pin_value && opt_so) { warnx("Option '--uri-pin-value' can not be specified together with " "the '--so' option."); return CKR_ARGUMENTS_BAD; } if (opt_uri_pin_source != NULL && !opt_uri_pem) { warnx("Option '--uri-pin-source' can only be specified together with " "the '-u'/'--uri-pem' option."); return CKR_ARGUMENTS_BAD; } if (opt_uri_pin_source != NULL && opt_no_login) { warnx("Option '--uri-pin-source' can not be specified together with " "the '-N'/'--no_login' option."); return CKR_ARGUMENTS_BAD; } if (opt_uri_pin_source != NULL && opt_so) { warnx("Option '--uri-pin-source' can not be specified together with " "the '--so' option."); return CKR_ARGUMENTS_BAD; } rc = iterate_objects(certtype, opt_label, opt_id, opt_attr, OBJCLASS_CERTIFICATE, NULL, handle_cert_export, &data); if (rc != CKR_OK) { warnx("Failed to iterate over certificate objects for type %s: 0x%lX: %s", certtype != NULL ? certtype->name : "All", rc, p11_get_ckr(rc)); return rc; } if (opt_uri_pem && opt_uri_pin_source != NULL && p11tool_pin != NULL && data.num_exported > 0) { rc = p11sak_create_uri_pin_source(opt_uri_pin_source, p11tool_pin); return rc; } printf("%lu certificate object(s) exported.\n", data.num_exported); if (data.num_skipped > 0) printf("%lu certificate object(s) skipped.\n", data.num_skipped); if (data.num_failed > 0) printf("%lu certificate object(s) failed to export.\n", data.num_failed); return data.num_failed == 0 ? CKR_OK : CKR_FUNCTION_FAILED; } static CK_RV p11sak_import_cert(void) { const struct p11tool_objtype *certtype; CK_ATTRIBUTE *attrs = NULL; CK_ULONG num_attrs = 0; CK_OBJECT_CLASS class; CK_OBJECT_HANDLE cert; CK_RV rc; X509 *x509 = NULL; CK_CERTIFICATE_CATEGORY cert_category; if (opt_certtype == NULL || opt_certtype->private.ptr == NULL) return CKR_ARGUMENTS_BAD; certtype = opt_certtype->private.ptr; rc = p11sak_x509_from_pem_file(&x509); switch (rc) { case CKR_OK: break; case CKR_ARGUMENTS_BAD: return rc; default: rc = p11sak_x509_from_der_file(&x509); if (rc != CKR_OK) return rc; break; } class = CKO_CERTIFICATE; rc = p11tool_add_attribute(CKA_CLASS, &class, sizeof(class), &attrs, &num_attrs); if (rc != CKR_OK) goto done; rc = p11tool_add_attributes(certtype, p11sak_bool_attrs, &attrs, &num_attrs, opt_label, opt_attr, opt_id, FALSE, opt_so, NULL, NULL, p11tool_cert_attr_applicable); if (rc != CKR_OK) goto done; /* * Set CA-cert attribute dependent on input option or BasicConstraints CA * flag of the certificate */ if (opt_cacert || (X509_get_extension_flags(x509) & EXFLAG_CA) != 0) { cert_category = CK_CERTIFICATE_CATEGORY_AUTHORITY; rc = p11tool_add_attribute(CKA_CERTIFICATE_CATEGORY, &cert_category, sizeof(CK_CERTIFICATE_CATEGORY), &attrs, &num_attrs); if (rc != CKR_OK) { warnx("Failed to add %s attribute CKA_CERTIFICATE_CATEGORY: 0x%lX: %s", certtype->name, rc, p11_get_ckr(rc)); goto done; } } /* Set common attributes for all types of certificates */ rc = p11sak_import_cert_attrs(certtype, x509, &attrs, &num_attrs); if (rc != CKR_OK) goto done; /* Set attributes dependent on certificate type */ if (certtype->import_x509_data != NULL) { rc = certtype->import_x509_data(certtype, x509, &attrs, &num_attrs); if (rc != CKR_OK) goto done; } rc = p11tool_pkcs11_funcs->C_CreateObject(p11tool_pkcs11_session, attrs, num_attrs, &cert); if (rc != CKR_OK) { if (p11tool_is_rejected_by_policy(rc, p11tool_pkcs11_session)) warnx("Certificate import of a %s certificate is rejected by policy", certtype->name); else warnx("Certificate import of a %s certificate failed: 0x%lX: %s", certtype->name, rc, p11_get_ckr(rc)); goto done; } printf("Successfully imported a %s certificate with label \"%s\".\n", certtype->name, opt_label); done: p11tool_free_attributes(attrs, num_attrs); X509_free(x509); return rc; } static CK_RV p11sak_extract_cert_pubkey(void) { const struct p11tool_objtype *certtype = NULL; struct p11sak_export_data data = { 0 }; CK_RV rc; if (opt_certtype != NULL) certtype = opt_certtype->private.ptr; data.export_all = opt_force; rc = iterate_objects(certtype, opt_label, opt_id, opt_attr, OBJCLASS_CERTIFICATE, NULL, handle_cert_pubkey_extract, &data); if (rc != CKR_OK) { warnx("Failed to iterate over certificate objects for type %s: 0x%lX: %s", certtype != NULL ? certtype->name : "All", rc, p11_get_ckr(rc)); return rc; } printf("%lu public key object(s) extracted.\n", data.num_exported); if (data.num_skipped > 0) printf("%lu certificate object(s) skipped.\n", data.num_skipped); if (data.num_failed > 0) printf("%lu certificate object(s) failed to export the public key.\n", data.num_failed); return data.num_failed == 0 ? CKR_OK : CKR_FUNCTION_FAILED; } static void parse_config_file_error_hook(int line, int col, const char *msg) { warnx("Parse error: %d:%d: %s", line, col, msg); } static CK_RV parse_config_file(void) { FILE *fp = NULL; char *file_loc = getenv(P11SAK_DEFAULT_CONF_FILE_ENV_NAME); char pathname[PATH_MAX]; struct passwd *pw; if (file_loc != NULL) { fp = fopen(file_loc, "r"); if (fp == NULL) { warnx("Cannot read config file '%s' (specified via env variable %s): %s", file_loc, P11SAK_DEFAULT_CONF_FILE_ENV_NAME, strerror(errno)); warnx("Printing of custom attributes not available."); return CKR_OK; } } else { pw = getpwuid(geteuid()); if (pw != NULL) { snprintf(pathname, sizeof(pathname), "%s/.%s", pw->pw_dir, P11SAK_CONFIG_FILE_NAME); file_loc = pathname; fp = fopen(file_loc, "r"); } if (fp == NULL) { file_loc = P11SAK_DEFAULT_CONFIG_FILE; fp = fopen(file_loc, "r"); if (fp == NULL) { warnx("Cannot read config file '%s': %s", file_loc, strerror(errno)); warnx("Printing of custom attributes not available."); return CKR_OK; } } } if (parse_configlib_file(fp, &p11sak_cfg, parse_config_file_error_hook, 0)) { warnx("Failed to parse config file '%s'", file_loc); fclose(fp); return CKR_DATA_INVALID; } fclose(fp); return CKR_OK; } int main(int argc, char *argv[]) { const struct p11tool_cmd *command = NULL; CK_RV rc = CKR_OK; /* Get p11sak command (if any) */ if (argc >= 2 && strncmp(argv[1], "-", 1) != 0) { command = p11tool_find_command(p11sak_commands, argv[1]); if (command == NULL) { warnx("Invalid command '%s'", argv[1]); rc = CKR_ARGUMENTS_BAD; goto done; } argc--; argv = &argv[1]; } /* Get command arguments (if any) */ rc = p11tool_parse_cmd_arguments(command, &argc, &argv); if (rc != CKR_OK) goto done; /* Get generic and command specific options (if any) */ rc = p11tool_parse_cmd_options(command, p11sak_generic_opts, argc, argv); if (rc != CKR_OK) goto done; if (opt_help) { if (command == NULL) p11tool_print_help("p11sak", p11sak_commands, p11sak_generic_opts, PRINT_INDENT_POS); else p11tool_print_command_help("p11sak", command, p11sak_generic_opts, PRINT_INDENT_POS); goto done; } if (opt_version) { p11tool_print_version("p11sak"); goto done; } if (command == NULL) { warnx("A command is required. Use '-h'/'--help' to see the list of " "supported commands"); rc = CKR_ARGUMENTS_BAD; goto done; } rc = p11tool_check_required_args(command->args); if (rc != CKR_OK) goto done; rc = p11tool_check_required_cmd_opts(command->opts, command->args, p11sak_generic_opts); if (rc != CKR_OK) goto done; rc = p11tool_init_pkcs11(command, opt_no_login, opt_pin, opt_force_pin_prompt, opt_so, opt_uri_pem && (opt_uri_pin_value || opt_uri_pin_source != NULL), opt_slot, p11sak_known_tokens); if (rc != CKR_OK) goto done; rc = parse_config_file(); if (rc != CKR_OK) goto done; /* Run the command */ rc = command->func(); if (rc != CKR_OK) { warnx("Failed to perform the '%s' command: %s", command->cmd, p11_get_ckr(rc)); goto done; } done: p11tool_term_pkcs11(); if (p11sak_cfg != NULL) confignode_deepfree(p11sak_cfg); return rc; } opencryptoki-opencryptoki-451d99c/usr/sbin/p11sak/p11sak.h000066400000000000000000000224251520105705100234460ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2001-2025 * * 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 P11SAK_H_ #define P11SAK_H_ #include "p11tool.h" #include "ec_curves.h" #define PKCS11_PEM_PASSWORD_ENV_NAME "PKCS11_PEM_PASSWORD" #define P11SAK_DEFAULT_CONF_FILE_ENV_NAME "P11SAK_DEFAULT_CONF_FILE" #define P11SAK_CONFIG_FILE_NAME "p11sak_defined_attrs.conf" #define P11SAK_DEFAULT_CONFIG_FILE OCK_CONFDIR "/" P11SAK_CONFIG_FILE_NAME #define P11SAK_CONFIG_KEYWORD_ATTRIBUTE "attribute" #define P11SAK_CONFIG_KEYWORD_NAME "name" #define P11SAK_CONFIG_KEYWORD_ID "id" #define P11SAK_CONFIG_KEYWORD_TYPE "type" #define P11SAK_CONFIG_TYPE_BOOL "CK_BBOOL" #define P11SAK_CONFIG_TYPE_ULONG "CK_ULONG" #define P11SAK_CONFIG_TYPE_BYTE "CK_BYTE" #define P11SAK_CONFIG_TYPE_DATE "CK_DATE" #define UNUSED(var) ((void)(var)) #define OPT_FORCE_PIN_PROMPT 256 #define OPT_DETAILED_URI 257 #define OPT_FORCE_PEM_PWD_PROMPT 258 #define OPT_SO 259 #define OPT_URI_PIN_VALUE 260 #define OPT_URI_PIN_SOURCE 261 #define OPT_OQSPROVIDER_PEM 262 #define OPT_OAEP_HASH_ALG 263 #define OPT_OAEP_MGF_ALG 264 #define OPT_OAEP_SOURCE_DATA 265 #define OPT_AESKW_KEY_SIZE 266 #define OPT_ECDH_KDF_ALG 267 #define OPT_ECDH_SHARED_DATA 268 #define PRINT_INDENT_POS 35 #define FIND_OBJECTS_COUNT 64 #define LIST_KEYTYPE_CELL_SIZE 22 #define LIST_MKVP_MIN_CELL_SIZE 32 #define LIST_MKTYPE_MIN_CELL_SIZE 8 #define LIST_SESS_MIN_CELL_SIZE 16 #define LIST_CERTTYPE_CELL_SIZE 9 #define LIST_CERT_CN_CELL_SIZE 22 #define MAX_SYM_CLEAR_KEY_SIZE 64 #define PKCS11_URI_PEM_NAME "PKCS#11 PROVIDER URI" #define PKCS11_URI_DESCRIPTION "PKCS#11 Provider URI v1.0" struct p11sak_custom_attr_type { const char *type; void (*print_long)(const char *attr, const CK_ATTRIBUTE *val, int indent, bool sensitive); }; struct p11sak_iterate_compare_data { CK_RV (*compare_obj)(CK_OBJECT_HANDLE obj1, CK_OBJECT_HANDLE obj2, int *result, void *private); void *private; CK_RV rc; }; struct p11sak_remove_data { unsigned long num_removed; unsigned long num_skipped; unsigned long num_failed; bool remove_all; bool skip_all; }; enum p11sak_sort_field { SORT_NONE = 0, SORT_LABEL = 1, SORT_KEYTYPE = 2, SORT_CLASS = 3, SORT_KEYSIZE = 4, SORT_CN = 5, }; #define MAX_SORT_FIELDS 5 struct p11sak_sort_info { enum p11sak_sort_field field; bool descending; }; struct p11sak_list_data { unsigned long num_displayed; CK_ATTRIBUTE *bool_attrs; CK_ULONG num_bool_attrs; enum p11tool_objclass objclass; const struct p11tool_attr *attrs; struct p11sak_sort_info sort_info[MAX_SORT_FIELDS]; }; struct p11sak_set_attr_data { unsigned long num_set; unsigned long num_skipped; unsigned long num_failed; bool set_all; bool skip_all; }; struct p11sak_copy_data { unsigned long num_copied; unsigned long num_skipped; unsigned long num_failed; bool copy_all; bool skip_all; }; struct p11sak_export_data { unsigned long num_exported; unsigned long num_skipped; unsigned long num_failed; bool export_all; bool skip_all; bool last_was_pem; bool last_was_binary; }; struct curve_info { const CK_BYTE *oid; CK_ULONG oid_len; CK_ULONG bitsize; }; #ifdef P11SAK_DECLARE_CURVES static const CK_BYTE brainpoolP160r1[] = OCK_BRAINPOOL_P160R1; static const CK_BYTE brainpoolP160t1[] = OCK_BRAINPOOL_P160T1; static const CK_BYTE brainpoolP192r1[] = OCK_BRAINPOOL_P192R1; static const CK_BYTE brainpoolP192t1[] = OCK_BRAINPOOL_P192T1; static const CK_BYTE brainpoolP224r1[] = OCK_BRAINPOOL_P224R1; static const CK_BYTE brainpoolP224t1[] = OCK_BRAINPOOL_P224T1; static const CK_BYTE brainpoolP256r1[] = OCK_BRAINPOOL_P256R1; static const CK_BYTE brainpoolP256t1[] = OCK_BRAINPOOL_P256T1; static const CK_BYTE brainpoolP320r1[] = OCK_BRAINPOOL_P320R1; static const CK_BYTE brainpoolP320t1[] = OCK_BRAINPOOL_P320T1; static const CK_BYTE brainpoolP384r1[] = OCK_BRAINPOOL_P384R1; static const CK_BYTE brainpoolP384t1[] = OCK_BRAINPOOL_P384T1; static const CK_BYTE brainpoolP512r1[] = OCK_BRAINPOOL_P512R1; static const CK_BYTE brainpoolP512t1[] = OCK_BRAINPOOL_P512T1; static const CK_BYTE prime192v1[] = OCK_PRIME192V1; static const CK_BYTE secp224r1[] = OCK_SECP224R1; static const CK_BYTE prime256v1[] = OCK_PRIME256V1; static const CK_BYTE secp384r1[] = OCK_SECP384R1; static const CK_BYTE secp521r1[] = OCK_SECP521R1; static const CK_BYTE secp256k1[] = OCK_SECP256K1; static const CK_BYTE curve25519[] = OCK_CURVE25519; static const CK_BYTE curve448[] = OCK_CURVE448; static const CK_BYTE ed25519[] = OCK_ED25519; static const CK_BYTE ed448[] = OCK_ED448; static const CK_BYTE bls12_381[] = OCK_BLS12_381; #endif #define EP11_WKVP_OFFSET 32 #define EP11_SESSION_ID_OFFSET 0 struct cca_token_header { unsigned char id; unsigned char reserved1; unsigned short len; unsigned char version; unsigned char reserved2[3]; }; extern const struct p11tool_attr p11sak_bool_attrs[]; const struct p11tool_objtype *find_keytype(CK_KEY_TYPE ktype); CK_RV iterate_objects(const struct p11tool_objtype *objtype, const char *label_filter, const char *id_filter, const char *attr_filter, enum p11tool_objclass objclass, CK_RV (*compare_obj)(CK_OBJECT_HANDLE obj1, CK_OBJECT_HANDLE obj2, int *result, void *private), CK_RV (*handle_obj)(CK_OBJECT_HANDLE obj, CK_OBJECT_CLASS class, const struct p11tool_objtype *objtype, CK_ULONG keysize, const char *typestr, const char* label, const char *common_name, void *private), void *private); struct p11sak_select_kek_data { CK_BBOOL prompt; CK_OBJECT_CLASS kek_class; CK_BBOOL cancel; CK_ULONG count; CK_OBJECT_HANDLE kek_handle; }; struct p11sak_wrap_data { unsigned long num_wrapped; unsigned long num_skipped; unsigned long num_failed; bool wrap_all; bool skip_all; const struct p11sak_wrap_mech *wrap_mech; CK_OBJECT_HANDLE kek_handle; CK_MECHANISM mech; char *pem_header; }; struct p11sak_wrap_mech { const char *name; CK_MECHANISM_TYPE mech; CK_ULONG mech_param_size; CK_BBOOL mech_param_optional; CK_OBJECT_CLASS wrap_class; CK_OBJECT_CLASS unwrap_class; CK_KEY_TYPE key_type; CK_KEY_TYPE addl_key_type; CK_RV (*prepare_mech_param_from_opts)( const struct p11sak_wrap_mech *wrap_mech, CK_MECHANISM *mech); CK_RV (*prepare_mech_param_from_pem)( const struct p11sak_wrap_mech *wrap_mech, CK_MECHANISM *mech, char **pem_headers); void (*cleanup_mech_param)(const struct p11sak_wrap_mech *wrap_mech, CK_MECHANISM *mech); CK_RV (*prepare_pem_header)(const struct p11sak_wrap_mech *wrap_mech, char **pem_header); }; #define P11SAK_WRAP_PEM_NAME "P11SAK WRAPPED KEY" #define P11SAK_WRAP_PEM_HDR_ALG "WRAP-ALG" #define P11SAK_WRAP_PEM_HDR_KEY_TYPE "KEY-TYPE" #define P11SAK_WRAP_PEM_HDR_IV "IV" #define P11SAK_WRAP_PEM_HDR_IV_ZERO "00000000000000000000000000000000" #define P11SAK_WRAP_PEM_HDR_IV_DEFAULT "[default]" #define P11SAK_WRAP_PEM_HDR_OAEP_HASH_ALG "HASH-ALG" #define P11SAK_WRAP_PEM_HDR_OAEP_MGF_ALG "MGF-ALG" #define P11SAK_WRAP_PEM_HDR_OAEP_SOURCE "SOURCE-DATA" #define P11SAK_WRAP_PEM_HDR_OAEP_SOURCE_NONE "[none]" #define P11SAK_WRAP_PEM_HDR_AES_KEY_SIZE "AES-KEY-SIZE" #define P11SAK_WRAP_PEM_HDR_ECDH_KDF_ALG "KDF-ALG" #define P11SAK_WRAP_PEM_HDR_ECDH_SHARED "SHARED-DATA" #define P11SAK_WRAP_PEM_HDR_ECDH_SHARED_NONE "[none]" extern CK_SLOT_ID opt_slot; extern bool opt_so; extern bool opt_force; extern char *opt_label; extern char *opt_attr; extern char *opt_id; extern char *opt_file; extern char *opt_kek_label; extern char *opt_kek_id; extern bool opt_raw; extern struct p11tool_enum_value *opt_wrap_mech; extern struct p11tool_enum_value *opt_keytype; extern const struct p11tool_enum_value p11sak_wrap_mech_values[]; extern const struct p11tool_objtype *p11sak_keytypes[]; CK_RV p11sak_wrap_key(void); CK_RV p11sak_unwrap_key(void); void print_wrap_key_help(void); void print_unwrap_key_help(void); #endif opencryptoki-opencryptoki-451d99c/usr/sbin/p11sak/p11sak.mk000066400000000000000000000023471520105705100236270ustar00rootroot00000000000000sbin_PROGRAMS += usr/sbin/p11sak/p11sak noinst_HEADERS += usr/sbin/p11sak/p11sak.h usr/sbin/p11sak/p11tool.h EXTRA_DIST += usr/sbin/p11sak/p11sak_defined_attrs.conf usr_sbin_p11sak_p11sak_LDFLAGS = -ldl -lcrypto if AIX usr_sbin_p11sak_p11sak_LDFLAGS += -Wl,-blibpath:$(libdir)/opencryptoki:$(libdir)/opencryptoki/stdll:/usr/lib:/usr/lib64 endif usr_sbin_p11sak_p11sak_CFLAGS = -DPROGRAM_NAME=\"$(@)\" \ -I${srcdir}/usr/include -I${srcdir}/usr/lib/common \ -I${srcdir}/usr/sbin/p11sak -I${srcdir}/usr/lib/config \ -I${top_builddir}/usr/lib/config -I${top_builddir}/usr/lib/api \ -I${srcdir}/usr/lib/api if !AIX usr_sbin_p11sak_p11sak_CFLAGS += -DLINUX endif usr_sbin_p11sak_p11sak_SOURCES = usr/lib/common/p11util.c \ usr/sbin/p11sak/p11sak.c usr/lib/common/pin_prompt.c \ usr/lib/config/configuration.c usr/lib/common/uri.c \ usr/lib/common/buffer.c usr/lib/common/pqc_supported.c \ usr/lib/config/cfgparse.y usr/lib/config/cfglex.l \ usr/sbin/p11sak/p11tool.c usr/sbin/p11sak/p11sak_keywrap.c if AIX usr_sbin_p11sak_p11sak_SOURCES += usr/lib/common/aix/err.c \ usr/lib/common/aix/getopt_long.c endif nodist_usr_sbin_p11sak_p11sak_SOURCES = usr/lib/api/mechtable.c usr/sbin/p11sak/p11sak.$(OBJEXT): usr/lib/config/cfgparse.h opencryptoki-opencryptoki-451d99c/usr/sbin/p11sak/p11sak_defined_attrs.conf000066400000000000000000000006461520105705100270400ustar00rootroot00000000000000attribute { name = CKA_IBM_RESTRICTABLE id = 0x80010001 type = CK_BBOOL } attribute { name = CKA_IBM_ATTRBOUND id = 0x80010004 type = CK_BBOOL } attribute { name = CKA_IBM_USE_AS_DATA id = 0x80010008 type = CK_BBOOL } attribute { name = CKA_IBM_CCA_AES_KEY_MODE id = 0x800d0101 type = CK_ULONG } attribute { name = CKA_IBM_CCA_ML_DSA_KEY_MODE id = 0x800d0102 type = CK_ULONG } opencryptoki-opencryptoki-451d99c/usr/sbin/p11sak/p11sak_keywrap.c000066400000000000000000002047401520105705100252050ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2025 * * 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 defined(_AIX) const char *__progname = "p11sak"; #endif #include #include #include #include #include #include #define P11SAK_DECLARE_CURVES #include "p11sak.h" #include "p11util.h" #include "mechtable.h" #include "defs.h" #include #include static char *opt_iv = NULL; static struct p11tool_enum_value *opt_oaep_hash_alg = NULL; static struct p11tool_enum_value *opt_oaep_mgf_alg = NULL; static char *opt_oaep_source_data = NULL; static struct p11tool_enum_value *opt_aeskw_keybits = NULL; static struct p11tool_enum_value *opt_ecdh_kdf_alg = NULL; static char *opt_ecdh_shared_data = NULL; static CK_RV p11sak_aes_iv_prepare_mech_param_from_opts( const struct p11sak_wrap_mech *wrap_mech, CK_MECHANISM *mech); static CK_RV p11sak_aes_iv_prepare_mech_param_from_pem( const struct p11sak_wrap_mech *wrap_mech, CK_MECHANISM *mech, char **pem_headers); static CK_RV p11sak_aes_iv_prepare_pem_header( const struct p11sak_wrap_mech *wrap_mech, char **pem_header); static CK_RV p11sak_rsa_oaep_prepare_mech_param_from_opts( const struct p11sak_wrap_mech *wrap_mech, CK_MECHANISM *mech); static CK_RV p11sak_rsa_oaep_prepare_mech_param_from_pem( const struct p11sak_wrap_mech *wrap_mech, CK_MECHANISM *mech, char **pem_headers); static void p11sak_rsa_oaep_cleanup_mech_param( const struct p11sak_wrap_mech *wrap_mech, CK_MECHANISM *mech); static CK_RV p11sak_rsa_oaep_prepare_pem_header( const struct p11sak_wrap_mech *wrap_mech, char **pem_header); static CK_RV p11sak_rsa_aeskw_prepare_mech_param_from_opts( const struct p11sak_wrap_mech *wrap_mech, CK_MECHANISM *mech); static CK_RV p11sak_rsa_aeskw_prepare_mech_param_from_pem( const struct p11sak_wrap_mech *wrap_mech, CK_MECHANISM *mech, char **pem_headers); static void p11sak_rsa_aeskw_cleanup_mech_param( const struct p11sak_wrap_mech *wrap_mech, CK_MECHANISM *mech); static CK_RV p11sak_rsa_aeskw_prepare_pem_header( const struct p11sak_wrap_mech *wrap_mech, char **pem_header); static CK_RV p11sak_ecdh_aeskw_prepare_mech_param_from_opts( const struct p11sak_wrap_mech *wrap_mech, CK_MECHANISM *mech); static CK_RV p11sak_ecdh_aeskw_prepare_mech_param_from_pem( const struct p11sak_wrap_mech *wrap_mech, CK_MECHANISM *mech, char **pem_headers); static void p11sak_ecdh_aeskw_cleanup_mech_param( const struct p11sak_wrap_mech *wrap_mech, CK_MECHANISM *mech); static CK_RV p11sak_ecdh_aeskw_prepare_pem_header( const struct p11sak_wrap_mech *wrap_mech, char **pem_header); static const struct p11sak_wrap_mech p11sak_wrap_mech_aes_cbc = { .name = "AES-CBC-PAD", .mech = CKM_AES_CBC_PAD, .mech_param_size = AES_INIT_VECTOR_SIZE, .wrap_class = CKO_SECRET_KEY, .unwrap_class = CKO_SECRET_KEY, .key_type = CKK_AES, .addl_key_type = (CK_KEY_TYPE)-1, .prepare_mech_param_from_opts = p11sak_aes_iv_prepare_mech_param_from_opts, .prepare_mech_param_from_pem = p11sak_aes_iv_prepare_mech_param_from_pem, .prepare_pem_header = p11sak_aes_iv_prepare_pem_header, }; static const struct p11sak_wrap_mech p11sak_wrap_mech_aeskw_kwp = { .name = "AESKW-KWP", .mech = CKM_AES_KEY_WRAP_KWP, .mech_param_size = AES_KEY_WRAP_KWP_IV_SIZE, .mech_param_optional = CK_TRUE, .wrap_class = CKO_SECRET_KEY, .unwrap_class = CKO_SECRET_KEY, .key_type = CKK_AES, .addl_key_type = (CK_KEY_TYPE)-1, .prepare_mech_param_from_opts = p11sak_aes_iv_prepare_mech_param_from_opts, .prepare_mech_param_from_pem = p11sak_aes_iv_prepare_mech_param_from_pem, .prepare_pem_header = p11sak_aes_iv_prepare_pem_header, }; static const struct p11sak_wrap_mech p11sak_wrap_mech_aeskw_pkcs7 = { .name = "AESKW-PKCS7", .mech = CKM_AES_KEY_WRAP_PKCS7, .mech_param_size = AES_KEY_WRAP_IV_SIZE, .mech_param_optional = CK_TRUE, .wrap_class = CKO_SECRET_KEY, .unwrap_class = CKO_SECRET_KEY, .key_type = CKK_AES, .addl_key_type = (CK_KEY_TYPE)-1, .prepare_mech_param_from_opts = p11sak_aes_iv_prepare_mech_param_from_opts, .prepare_mech_param_from_pem = p11sak_aes_iv_prepare_mech_param_from_pem, .prepare_pem_header = p11sak_aes_iv_prepare_pem_header, }; static const struct p11sak_wrap_mech p11sak_wrap_mech_rsa_pkcs = { .name = "RSA-PKCS", .mech = CKM_RSA_PKCS, .mech_param_size = 0, .wrap_class = CKO_PUBLIC_KEY, .unwrap_class = CKO_PRIVATE_KEY, .key_type = CKK_RSA, .addl_key_type = (CK_KEY_TYPE)-1, }; static const struct p11sak_wrap_mech p11sak_wrap_mech_rsa_oaep = { .name = "RSA-OAEP", .mech = CKM_RSA_PKCS_OAEP, .mech_param_size = sizeof(CK_RSA_PKCS_OAEP_PARAMS), .wrap_class = CKO_PUBLIC_KEY, .unwrap_class = CKO_PRIVATE_KEY, .key_type = CKK_RSA, .addl_key_type = (CK_KEY_TYPE)-1, .prepare_mech_param_from_opts = p11sak_rsa_oaep_prepare_mech_param_from_opts, .prepare_mech_param_from_pem = p11sak_rsa_oaep_prepare_mech_param_from_pem, .cleanup_mech_param = p11sak_rsa_oaep_cleanup_mech_param, .prepare_pem_header = p11sak_rsa_oaep_prepare_pem_header, }; static const struct p11sak_wrap_mech p11sak_wrap_mech_rsa_aeskw = { .name = "RSA-AESKW", .mech = CKM_RSA_AES_KEY_WRAP, .mech_param_size = sizeof(CK_RSA_AES_KEY_WRAP_PARAMS), .wrap_class = CKO_PUBLIC_KEY, .unwrap_class = CKO_PRIVATE_KEY, .key_type = CKK_RSA, .addl_key_type = (CK_KEY_TYPE)-1, .prepare_mech_param_from_opts = p11sak_rsa_aeskw_prepare_mech_param_from_opts, .prepare_mech_param_from_pem = p11sak_rsa_aeskw_prepare_mech_param_from_pem, .cleanup_mech_param = p11sak_rsa_aeskw_cleanup_mech_param, .prepare_pem_header = p11sak_rsa_aeskw_prepare_pem_header, }; static const struct p11sak_wrap_mech p11sak_wrap_mech_ecdh_aeskw = { .name = "ECDH-AESKW", .mech = CKM_ECDH_AES_KEY_WRAP, .mech_param_size = sizeof(CK_ECDH_AES_KEY_WRAP_PARAMS), .wrap_class = CKO_PUBLIC_KEY, .unwrap_class = CKO_PRIVATE_KEY, .key_type = CKK_EC, .addl_key_type = CKK_EC_MONTGOMERY, .prepare_mech_param_from_opts = p11sak_ecdh_aeskw_prepare_mech_param_from_opts, .prepare_mech_param_from_pem = p11sak_ecdh_aeskw_prepare_mech_param_from_pem, .cleanup_mech_param = p11sak_ecdh_aeskw_cleanup_mech_param, .prepare_pem_header = p11sak_ecdh_aeskw_prepare_pem_header, }; static const struct p11sak_wrap_mech p11sak_wrap_mech_ecdh_cof_aeskw = { .name = "ECDH-COF-AESKW", .mech = CKM_ECDH_COF_AES_KEY_WRAP, .mech_param_size = sizeof(CK_ECDH_AES_KEY_WRAP_PARAMS), .wrap_class = CKO_PUBLIC_KEY, .unwrap_class = CKO_PRIVATE_KEY, .key_type = CKK_EC, .prepare_mech_param_from_opts = p11sak_ecdh_aeskw_prepare_mech_param_from_opts, .prepare_mech_param_from_pem = p11sak_ecdh_aeskw_prepare_mech_param_from_pem, .cleanup_mech_param = p11sak_ecdh_aeskw_cleanup_mech_param, .prepare_pem_header = p11sak_ecdh_aeskw_prepare_pem_header, }; static const struct p11sak_wrap_mech p11sak_wrap_mech_ecdh_x_aeskw = { .name = "ECDH-X-AESKW", .mech = CKM_ECDH_X_AES_KEY_WRAP, .mech_param_size = sizeof(CK_ECDH_AES_KEY_WRAP_PARAMS), .wrap_class = CKO_PUBLIC_KEY, .unwrap_class = CKO_PRIVATE_KEY, .key_type = CKK_EC_MONTGOMERY, .prepare_mech_param_from_opts = p11sak_ecdh_aeskw_prepare_mech_param_from_opts, .prepare_mech_param_from_pem = p11sak_ecdh_aeskw_prepare_mech_param_from_pem, .cleanup_mech_param = p11sak_ecdh_aeskw_cleanup_mech_param, .prepare_pem_header = p11sak_ecdh_aeskw_prepare_pem_header, }; static const struct p11tool_opt p11sak_wrap_mech_aes_cbc_opts[] = { { .short_opt = 'I', .long_opt = "iv", .required = false, .arg = { .type = ARG_TYPE_STRING, .required = true, .value.string = &opt_iv, .name = "IV", }, .description = "The initialization vector (IV) for the AES-CBC " "operation. Specify a hex string (not prefixed with 0x) " "of exactly 16 bytes. The default is to use 16 all zero " "bytes.", }, { .short_opt = 0, .long_opt = NULL, }, }; static const struct p11tool_opt p11sak_wrap_mech_aeskw_kwp_opts[] = { { .short_opt = 'I', .long_opt = "iv", .required = false, .arg = { .type = ARG_TYPE_STRING, .required = true, .value.string = &opt_iv, .name = "IV", }, .description = "The initialization vector (IV) for the AESKW-KWP " "operation. Specify a hex string (not prefixed with 0x) " "of exactly 4 bytes. If no IV is specified then the " "default IV as per AESKW-KWP specification is used.", }, { .short_opt = 0, .long_opt = NULL, }, }; static const struct p11tool_opt p11sak_wrap_mech_aeskw_pkcs7_opts[] = { { .short_opt = 'I', .long_opt = "iv", .required = false, .arg = { .type = ARG_TYPE_STRING, .required = true, .value.string = &opt_iv, .name = "IV", }, .description = "The initialization vector (IV) for the AESKW-PKCS7 " "operation. Specify a hex string (not prefixed with 0x) " "of exactly 8 bytes. If no IV is specified then the " "default IV as per AESKW-PKCS7 specification is used.", }, { .short_opt = 0, .long_opt = NULL, }, }; static const struct p11tool_enum_value p11sak_oaep_hash_algs[] = { { .value = "SHA-1", .args = NULL, .private = { .num = CKM_SHA_1 }, }, { .value = "SHA224", .args = NULL, .private = { .num = CKM_SHA224 }, }, { .value = "SHA256", .args = NULL, .private = { .num = CKM_SHA256 }, }, { .value = "SHA384", .args = NULL, .private = { .num = CKM_SHA384 }, }, { .value = "SHA512", .args = NULL, .private = { .num = CKM_SHA512 }, }, { .value = "SHA3-224", .args = NULL, .private = { .num = CKM_SHA3_224 }, }, { .value = "SHA3-256", .args = NULL, .private = { .num = CKM_SHA3_256 }, }, { .value = "SHA3-384", .args = NULL, .private = { .num = CKM_SHA3_384 }, }, { .value = "SHA3-512", .args = NULL, .private = { .num = CKM_SHA3_512 }, }, { .value = NULL, }, }; static const struct p11tool_enum_value p11sak_oaep_mgf_algs[] = { { .value = "SHA-1", .args = NULL, .private = { .num = CKG_MGF1_SHA1 }, }, { .value = "SHA224", .args = NULL, .private = { .num = CKG_MGF1_SHA224 }, }, { .value = "SHA256", .args = NULL, .private = { .num = CKG_MGF1_SHA256 }, }, { .value = "SHA384", .args = NULL, .private = { .num = CKG_MGF1_SHA384 }, }, { .value = "SHA512", .args = NULL, .private = { .num = CKG_MGF1_SHA512 }, }, { .value = "SHA3-224", .args = NULL, .private = { .num = CKG_MGF1_SHA3_224 }, }, { .value = "SHA3-256", .args = NULL, .private = { .num = CKG_MGF1_SHA3_256 }, }, { .value = "SHA3-384", .args = NULL, .private = { .num = CKG_MGF1_SHA3_384 }, }, { .value = "SHA3-512", .args = NULL, .private = { .num = CKG_MGF1_SHA3_512 }, }, { .value = NULL, }, }; static const struct p11tool_opt p11sak_wrap_mech_rsa_oaep_opts[] = { { .short_opt = 0, .long_opt = "hash-alg", .required = false, .long_opt_val = OPT_OAEP_HASH_ALG, .arg = { .type = ARG_TYPE_ENUM, .required = true, .name = "HASH-ALG", .value.enum_value = &opt_oaep_hash_alg, .enum_values = p11sak_oaep_hash_algs, }, .description = "The message digest algorithm used to calculate the " "digest of the OAEP encoding parameter. The default is " "to use the same algorithm as specified with option " "'--mgf-alg', or SHA256 if neither is specified. " "Possible algorithms are:", }, { .short_opt = 0, .long_opt = "mgf-alg", .required = false, .long_opt_val = OPT_OAEP_MGF_ALG, .arg = { .type = ARG_TYPE_ENUM, .required = true, .name = "MGF-ALG", .value.enum_value = &opt_oaep_mgf_alg, .enum_values = p11sak_oaep_mgf_algs, }, .description = "The mask generation function algorithm to use on the " "encoded block. The default is to use the same algorithm " "as specified with option '--hash-alg', or SHA256 if " "neither is specified. Possible algorithms are:", }, { .short_opt = 0, .long_opt = "source-data", .required = false, .long_opt_val = OPT_OAEP_SOURCE_DATA, .arg = { .type = ARG_TYPE_STRING, .required = true, .name = "SOURCE-DATA", .value.string = &opt_oaep_source_data, }, .description = "The source of the OAEP encoding parameter. Specify a hex " "string (not prefixed with 0x) of any number of bytes. " "The default is that no source data is used.", }, { .short_opt = 0, .long_opt = NULL, }, }; static const struct p11tool_enum_value p11sak_aeskw_keybits[] = { { .value = "128", .args = NULL, .private = { .num = 128 }, }, { .value = "192", .args = NULL, .private = { .num = 192 }, }, { .value = "256", .args = NULL, .private = { .num = 256 }, }, { .value = NULL, }, }; static const struct p11tool_opt p11sak_wrap_mech_rsa_aeskw_opts[] = { { .short_opt = 0, .long_opt = "aes-key-size", .required = false, .long_opt_val = OPT_AESKW_KEY_SIZE, .arg = { .type = ARG_TYPE_ENUM, .required = true, .name = "AES-KEYBITS", .value.enum_value = &opt_aeskw_keybits, .enum_values = p11sak_aeskw_keybits, }, .description = "The size of the temporary AES key in bits. The default " "is 256 bits. Possible key sizes are:", }, { .short_opt = 0, .long_opt = "hash-alg", .required = false, .long_opt_val = OPT_OAEP_HASH_ALG, .arg = { .type = ARG_TYPE_ENUM, .required = true, .name = "HASH-ALG", .value.enum_value = &opt_oaep_hash_alg, .enum_values = p11sak_oaep_hash_algs, }, .description = "The message digest algorithm used to calculate the " "digest of the OAEP encoding parameter. The default is " "to use the same algorithm as specified with option " "'--mgf-alg', or SHA256 if neither is specified. " "Possible algorithms are:", }, { .short_opt = 0, .long_opt = "mgf-alg", .required = false, .long_opt_val = OPT_OAEP_MGF_ALG, .arg = { .type = ARG_TYPE_ENUM, .required = true, .name = "MGF-ALG", .value.enum_value = &opt_oaep_mgf_alg, .enum_values = p11sak_oaep_mgf_algs, }, .description = "The mask generation function algorithm to use on the " "encoded block. The default is to use the same algorithm " "as specified with option '--hash-alg', or SHA256 if " "neither is specified. Possible algorithms are:", }, { .short_opt = 0, .long_opt = "source-data", .required = false, .long_opt_val = OPT_OAEP_SOURCE_DATA, .arg = { .type = ARG_TYPE_STRING, .required = true, .name = "SOURCE-DATA", .value.string = &opt_oaep_source_data, }, .description = "The source of the OAEP encoding parameter. Specify a hex " "string (not prefixed with 0x) of any number of bytes. " "The default is that no source data is used.", }, { .short_opt = 0, .long_opt = NULL, }, }; static const struct p11tool_enum_value p11sak_ecdh_kdf_algs[] = { { .value = "NULL", .args = NULL, .private = { .num = CKD_NULL}, }, { .value = "SHA-1", .args = NULL, .private = { .num = CKD_SHA1_KDF }, }, { .value = "SHA224", .args = NULL, .private = { .num = CKD_SHA224_KDF }, }, { .value = "SHA256", .args = NULL, .private = { .num = CKD_SHA256_KDF }, }, { .value = "SHA384", .args = NULL, .private = { .num = CKD_SHA384_KDF }, }, { .value = "SHA512", .args = NULL, .private = { .num = CKD_SHA512_KDF }, }, { .value = "SHA3-224", .args = NULL, .private = { .num = CKD_SHA3_224_KDF }, }, { .value = "SHA3-256", .args = NULL, .private = { .num = CKD_SHA3_256_KDF }, }, { .value = "SHA3-384", .args = NULL, .private = { .num = CKD_SHA3_384_KDF }, }, { .value = "SHA3-512", .args = NULL, .private = { .num = CKD_SHA3_512_KDF }, }, { .value = "SHA-1-SP800", .args = NULL, .private = { .num = CKD_SHA1_KDF_SP800 }, }, { .value = "SHA224-SP800", .args = NULL, .private = { .num = CKD_SHA224_KDF_SP800 }, }, { .value = "SHA256-SP800", .args = NULL, .private = { .num = CKD_SHA256_KDF_SP800 }, }, { .value = "SHA384-SP800", .args = NULL, .private = { .num = CKD_SHA384_KDF_SP800 }, }, { .value = "SHA512-SP800", .args = NULL, .private = { .num = CKD_SHA512_KDF_SP800 }, }, { .value = "SHA3-224-SP800", .args = NULL, .private = { .num = CKD_SHA3_224_KDF_SP800 }, }, { .value = "SHA3-256-SP800", .args = NULL, .private = { .num = CKD_SHA3_256_KDF_SP800 }, }, { .value = "SHA3-384-SP800", .args = NULL, .private = { .num = CKD_SHA3_384_KDF_SP800 }, }, { .value = "SHA3-512-SP800", .args = NULL, .private = { .num = CKD_SHA3_512_KDF_SP800 }, }, { .value = NULL, }, }; static const struct p11tool_opt p11sak_wrap_mech_ecdh_aeskw_opts[] = { { .short_opt = 0, .long_opt = "aes-key-size", .required = false, .long_opt_val = OPT_AESKW_KEY_SIZE, .arg = { .type = ARG_TYPE_ENUM, .required = true, .name = "AES-KEYBITS", .value.enum_value = &opt_aeskw_keybits, .enum_values = p11sak_aeskw_keybits, }, .description = "The size of the temporary AES key in bits. The default " "is 256 bits. Possible key sizes are:", }, { .short_opt = 0, .long_opt = "kdf-alg", .required = false, .long_opt_val = OPT_ECDH_KDF_ALG, .arg = { .type = ARG_TYPE_ENUM, .required = true, .name = "KDF-ALG", .value.enum_value = &opt_ecdh_kdf_alg, .enum_values = p11sak_ecdh_kdf_algs, }, .description = "The key derivation function algorithm used on the shared " "secret value to generate the internal AES key. The " "default is SHA256. Possible algorithms are:", }, { .short_opt = 0, .long_opt = "shared-data", .required = false, .long_opt_val = OPT_ECDH_SHARED_DATA, .arg = { .type = ARG_TYPE_STRING, .required = true, .name = "SHARED-DATA", .value.string = &opt_ecdh_shared_data, }, .description = "Some data shared between the two parties. Specify a hex " "string (not prefixed with 0x) of any number of bytes. " "The default is that no shared data is used.", }, { .short_opt = 0, .long_opt = NULL, }, }; const struct p11tool_enum_value p11sak_wrap_mech_values[] = { { .value = "aes-cbc-pad", .args = NULL, .opts = p11sak_wrap_mech_aes_cbc_opts, .description = "Use mechanism CKM_AES_CBC_PAD for key wrapping. " "Wrapping and unwrapping is done with an AES key.", .private = { .ptr = &p11sak_wrap_mech_aes_cbc, }, }, { .value = "aeskw-kwp", .args = NULL, .opts = p11sak_wrap_mech_aeskw_kwp_opts, .description = "Use mechanism CKM_AES_KEY_WRAP_KWP for key wrapping. " "Wrapping and unwrapping is done with an AES key.", .private = { .ptr = &p11sak_wrap_mech_aeskw_kwp, }, }, { .value = "aeskw-pkcs7", .args = NULL, .opts = p11sak_wrap_mech_aeskw_pkcs7_opts, .description = "Use mechanism CKM_AES_KEY_WRAP_PKCS7 for key wrapping. " "Wrapping and unwrapping is done with an AES key.", .private = { .ptr = &p11sak_wrap_mech_aeskw_pkcs7, }, }, { .value = "rsa-pkcs", .args = NULL, .opts = NULL, .description = "Use mechanism CKM_RSA_PKCS for key wrapping. " "Wrapping is done with an RSA public key, unwrapping is " "done with the corresponding RSA private key. Only keys " "whose key material size is up to the KEK's RSA modulus " "size minus 11 bytes can be wrapped with this mechanism.", .private = { .ptr = &p11sak_wrap_mech_rsa_pkcs, }, }, { .value = "rsa-oaep", .args = NULL, .opts = p11sak_wrap_mech_rsa_oaep_opts, .description = "Use mechanism CKM_RSA_PKCS_OAEP for key wrapping. " "Wrapping is done with an RSA public key, unwrapping is " "done with the corresponding RSA private key. Only keys " "whose key material size is up to the KEK's RSA modulus " "size minus 2 times the hash-alg digest size bytes minus " "2 bytes wrapped with this mechanism.", .private = { .ptr = &p11sak_wrap_mech_rsa_oaep, }, }, { .value = "rsa-aeskw", .args = NULL, .opts = p11sak_wrap_mech_rsa_aeskw_opts, .description = "Use mechanism CKM_RSA_AES_KEY_WRAP for key wrapping. " "Wrapping is done with an RSA public key, unwrapping is " "done with the corresponding RSA private key.", .private = { .ptr = &p11sak_wrap_mech_rsa_aeskw, }, }, { .value = "ecdh-aeskw", .args = NULL, .opts = p11sak_wrap_mech_ecdh_aeskw_opts, .description = "Use mechanism CKM_ECDH_AES_KEY_WRAP for key wrapping. " "Wrapping is done with an EC or EC-Montgomery public key, " "unwrapping is done with the corresponding EC or " "EC-Montgomery private key.", .private = { .ptr = &p11sak_wrap_mech_ecdh_aeskw, }, }, { .value = "ecdh-cof-aeskw", .args = NULL, .opts = p11sak_wrap_mech_ecdh_aeskw_opts, .description = "Use mechanism CKM_ECDH_COF_AES_KEY_WRAP for key " "wrapping. Wrapping is done with an EC public key, " "unwrapping is done with the corresponding EC private " "key.", .private = { .ptr = &p11sak_wrap_mech_ecdh_cof_aeskw, }, }, { .value = "ecdh-x-aeskw", .args = NULL, .opts = p11sak_wrap_mech_ecdh_aeskw_opts, .description = "Use mechanism CKM_ECDH_X_AES_KEY_WRAP for key wrapping. " "Wrapping is done with an EC-Montgomery public key, " "unwrapping is done with the corresponding " "EC-Montgomery private key.", .private = { .ptr = &p11sak_wrap_mech_ecdh_x_aeskw, }, }, { .value = NULL, }, }; static char *find_pem_header(char **headers, const char *name) { CK_ULONG i, len; char *tok; for (i = 0; headers[i] != NULL; i++) { tok = strchr(headers[i], ':'); if (tok == NULL || tok[1] != ' ') continue; len = tok - headers[i]; if (len != strlen(name) || strncmp(headers[i], name, len) != 0) continue; return headers[i] + len + 2; } return NULL; } static const struct p11sak_wrap_mech *find_wrap_mech_by_name(const char *name) { const struct p11tool_enum_value *val; for (val = p11sak_wrap_mech_values; val->value != NULL; val++) { if (strcasecmp(val->value, name) == 0) return val->private.ptr; } return NULL; } static const struct p11tool_objtype *find_keytype_by_name(const char *name) { const struct p11tool_objtype **kt; for (kt = p11sak_keytypes; *kt != NULL; kt++) { if (strcasecmp((*kt)->name, name) == 0) return *kt; } return NULL; } static CK_MECHANISM_TYPE find_hash_alg_by_name(const char *name) { const struct p11tool_enum_value *val; for (val = p11sak_oaep_hash_algs; val->value != NULL; val++) { if (strcasecmp(val->value, name) == 0) return val->private.num; } return (CK_MECHANISM_TYPE)-1; } static CK_RSA_PKCS_MGF_TYPE find_mgf_alg_by_name(const char *name) { const struct p11tool_enum_value *val; for (val = p11sak_oaep_mgf_algs; val->value != NULL; val++) { if (strcasecmp(val->value, name) == 0) return val->private.num; } return (CK_RSA_PKCS_MGF_TYPE)-1; } static CK_ULONG find_aeskw_keybits_by_name(const char *name) { const struct p11tool_enum_value *val; for (val = p11sak_aeskw_keybits; val->value != NULL; val++) { if (strcasecmp(val->value, name) == 0) return val->private.num; } return (CK_ULONG)-1; } static CK_EC_KDF_TYPE find_kdf_alg_by_name(const char *name) { const struct p11tool_enum_value *val; for (val = p11sak_ecdh_kdf_algs; val->value != NULL; val++) { if (strcasecmp(val->value, name) == 0) return val->private.num; } return (CK_EC_KDF_TYPE)-1; } static CK_RV p11sak_aes_iv_prepare_mech_param_from_opts( const struct p11sak_wrap_mech *wrap_mech, CK_MECHANISM *mech) { CK_BYTE *buf = NULL; CK_ULONG len = 0; CK_RV rc; if (opt_iv == NULL) { if (wrap_mech->mech_param_optional) { mech->pParameter = NULL; mech->ulParameterLen = 0; } else { memset(mech->pParameter, 0, mech->ulParameterLen); } return CKR_OK; } rc = p11tool_parse_hex(opt_iv, &buf, &len); if (rc != CKR_OK) return rc; if (len != mech->ulParameterLen) { warnx("Hex string specified as IV has an invalid length, expected " "%lu bytes.", mech->ulParameterLen); rc = CKR_ARGUMENTS_BAD; goto done; } memcpy(mech->pParameter, buf, mech->ulParameterLen); done: if (buf != NULL) free(buf); return rc; } static CK_RV p11sak_aes_iv_prepare_mech_param_from_pem( const struct p11sak_wrap_mech *wrap_mech, CK_MECHANISM *mech, char **pem_headers) { CK_BYTE *buf = NULL; CK_ULONG len = 0; char *iv = NULL; CK_RV rc = CKR_OK; if (opt_iv != NULL) { warnx("Option '-I'/'--iv' is ignored, using information from " "PEM file '%s'.", opt_file); } iv = find_pem_header(pem_headers, P11SAK_WRAP_PEM_HDR_IV); if (iv == NULL) { if (wrap_mech->mech_param_optional) iv = P11SAK_WRAP_PEM_HDR_IV_DEFAULT; else iv = P11SAK_WRAP_PEM_HDR_IV_ZERO; } if (strcasecmp(iv, P11SAK_WRAP_PEM_HDR_IV_DEFAULT) == 0) { mech->pParameter = NULL; mech->ulParameterLen = 0; } else if (strcasecmp(iv, P11SAK_WRAP_PEM_HDR_IV_ZERO) == 0) { memset(mech->pParameter, 0, mech->ulParameterLen); } else { rc = p11tool_parse_hex(iv, &buf, &len); if (rc != CKR_OK) return rc; if (len != mech->ulParameterLen) { warnx("Hex string specified as IV has an invalid length, expected " "%lu bytes.", mech->ulParameterLen); rc = CKR_ARGUMENTS_BAD; goto done; } memcpy(mech->pParameter, buf, mech->ulParameterLen); } done: if (buf != NULL) free(buf); return rc; } static CK_RV p11sak_aes_iv_prepare_pem_header( const struct p11sak_wrap_mech *wrap_mech, char **pem_header) { int len; char *iv = opt_iv; if (opt_iv == NULL) { if (wrap_mech->mech_param_optional) iv = P11SAK_WRAP_PEM_HDR_IV_DEFAULT; else iv = P11SAK_WRAP_PEM_HDR_IV_ZERO; } len = asprintf(pem_header, "%s: %s\n", P11SAK_WRAP_PEM_HDR_IV, iv); if (len <= 0) { warnx("Failed to allocate memory for a PEM header"); return CKR_HOST_MEMORY; } return CKR_OK; } static CK_RV p11sak_rsa_oaep_prepare_mech_param_from_opts( const struct p11sak_wrap_mech *wrap_mech, CK_MECHANISM *mech) { CK_RSA_PKCS_OAEP_PARAMS *oaep_param = mech->pParameter; CK_RV rc; UNUSED(wrap_mech); if (opt_oaep_hash_alg != NULL) { oaep_param->hashAlg = opt_oaep_hash_alg->private.num; } else if (opt_oaep_mgf_alg != NULL){ oaep_param->hashAlg = find_hash_alg_by_name(opt_oaep_mgf_alg->value); if (oaep_param->hashAlg == (CK_MECHANISM_TYPE)-1) { warnx("Invalid algorithm specified with option '--mgf-alg': %s", opt_oaep_mgf_alg->value); return CKR_ARGUMENTS_BAD; } } else { oaep_param->hashAlg = CKM_SHA256; } if (opt_oaep_mgf_alg != NULL) { oaep_param->mgf = opt_oaep_mgf_alg->private.num; } else if (opt_oaep_hash_alg != NULL) { oaep_param->mgf = find_mgf_alg_by_name(opt_oaep_hash_alg->value); if (oaep_param->mgf == (CK_MECHANISM_TYPE)-1) { warnx("Invalid algorithm specified with option '--hash-alg': %s", opt_oaep_hash_alg->value); return CKR_ARGUMENTS_BAD; } } else { oaep_param->mgf = CKG_MGF1_SHA256; } if (opt_oaep_source_data != NULL) { rc = p11tool_parse_hex(opt_oaep_source_data, (CK_BYTE **)&oaep_param->pSourceData, &oaep_param->ulSourceDataLen); if (rc != CKR_OK) return rc; oaep_param->source = CKZ_DATA_SPECIFIED; } else { oaep_param->source = 0; oaep_param->pSourceData = NULL; oaep_param->ulSourceDataLen = 0; } return CKR_OK; } static CK_RV p11sak_rsa_oaep_prepare_mech_param_from_pem( const struct p11sak_wrap_mech *wrap_mech, CK_MECHANISM *mech, char **pem_headers) { CK_RSA_PKCS_OAEP_PARAMS *oaep_param = mech->pParameter; char *hash_alg = NULL, *mgf_alg = NULL, *source_data = NULL; CK_RV rc; UNUSED(wrap_mech); if (opt_oaep_hash_alg != NULL) { warnx("Option '--hash-alg' is ignored, using information from " "PEM file '%s'.", opt_file); }; if (opt_oaep_mgf_alg != NULL) { warnx("Option '--mgf-alg' is ignored, using information from " "PEM file '%s'.", opt_file); }; if (opt_oaep_source_data != NULL) { warnx("Option '--source-data' is ignored, using information " "from PEM file '%s'.", opt_file); }; hash_alg = find_pem_header(pem_headers, P11SAK_WRAP_PEM_HDR_OAEP_HASH_ALG); mgf_alg = find_pem_header(pem_headers, P11SAK_WRAP_PEM_HDR_OAEP_MGF_ALG); source_data = find_pem_header(pem_headers, P11SAK_WRAP_PEM_HDR_OAEP_SOURCE); if (hash_alg != NULL) { oaep_param->hashAlg = find_hash_alg_by_name(hash_alg); if (oaep_param->hashAlg == (CK_MECHANISM_TYPE)-1) { warnx("Invalid hash algorithm '%s' in PEM file '%s'.", hash_alg, opt_file); return CKR_ARGUMENTS_BAD; } } else if (mgf_alg != NULL) { oaep_param->hashAlg = find_hash_alg_by_name(mgf_alg); if (oaep_param->hashAlg == (CK_MECHANISM_TYPE)-1) { warnx("Invalid mgf algorithm '%s' in PEM file '%s'.", mgf_alg, opt_file); return CKR_ARGUMENTS_BAD; } } else { oaep_param->hashAlg = CKM_SHA256; } if (mgf_alg != NULL) { oaep_param->mgf = find_mgf_alg_by_name(mgf_alg); if (oaep_param->mgf == (CK_RSA_PKCS_MGF_TYPE)-1) { warnx("Invalid mgf algorithm '%s' in PEM file '%s'.", mgf_alg, opt_file); return CKR_ARGUMENTS_BAD; } } else if (hash_alg != NULL) { oaep_param->mgf = find_mgf_alg_by_name(hash_alg); if (oaep_param->mgf == (CK_RSA_PKCS_MGF_TYPE)-1) { warnx("Invalid hash algorithm '%s' in PEM file '%s'.", hash_alg, opt_file); return CKR_ARGUMENTS_BAD; } } else { oaep_param->mgf = CKG_MGF1_SHA256; } if (source_data != NULL) { if (strcasecmp(source_data, P11SAK_WRAP_PEM_HDR_OAEP_SOURCE_NONE) == 0) { oaep_param->source = 0; oaep_param->pSourceData = NULL; oaep_param->ulSourceDataLen = 0; } else { rc = p11tool_parse_hex(source_data, (CK_BYTE **)&oaep_param->pSourceData, &oaep_param->ulSourceDataLen); if (rc != CKR_OK) return rc; oaep_param->source = CKZ_DATA_SPECIFIED; } } else { oaep_param->source = 0; oaep_param->pSourceData = NULL; oaep_param->ulSourceDataLen = 0; } return CKR_OK; } static void p11sak_rsa_oaep_cleanup_mech_param( const struct p11sak_wrap_mech *wrap_mech, CK_MECHANISM *mech) { CK_RSA_PKCS_OAEP_PARAMS *oaep_param = mech->pParameter; UNUSED(wrap_mech); if (oaep_param->pSourceData != NULL) free(oaep_param->pSourceData); } static CK_RV p11sak_rsa_oaep_prepare_pem_header( const struct p11sak_wrap_mech *wrap_mech, char **pem_header) { int len; UNUSED(wrap_mech); len = asprintf(pem_header, "%s: %s\n%s: %s\n%s: %s\n", P11SAK_WRAP_PEM_HDR_OAEP_HASH_ALG, opt_oaep_hash_alg != NULL ? opt_oaep_hash_alg->value : opt_oaep_mgf_alg != NULL ? opt_oaep_mgf_alg->value : "SHA256", P11SAK_WRAP_PEM_HDR_OAEP_MGF_ALG, opt_oaep_mgf_alg != NULL ? opt_oaep_mgf_alg->value : opt_oaep_hash_alg != NULL ? opt_oaep_hash_alg->value : "SHA256", P11SAK_WRAP_PEM_HDR_OAEP_SOURCE, opt_oaep_source_data != NULL ? opt_oaep_source_data : P11SAK_WRAP_PEM_HDR_OAEP_SOURCE_NONE); if (len <= 0) { warnx("Failed to allocate memory for a PEM header"); return CKR_HOST_MEMORY; } return CKR_OK; } static CK_RV p11sak_rsa_aeskw_prepare_mech_param_from_opts( const struct p11sak_wrap_mech *wrap_mech, CK_MECHANISM *mech) { CK_RSA_AES_KEY_WRAP_PARAMS *rsa_aeskw_param = mech->pParameter; CK_MECHANISM tmp_mech; CK_RV rc; UNUSED(wrap_mech); rsa_aeskw_param->pOAEPParams = calloc(1, sizeof(CK_RSA_PKCS_OAEP_PARAMS)); if (rsa_aeskw_param->pOAEPParams == NULL) { warnx("Failed to allocate memory for a mechanism parameter"); return CKR_HOST_MEMORY; } if (opt_aeskw_keybits != NULL) rsa_aeskw_param->ulAESKeyBits = opt_aeskw_keybits->private.num; else rsa_aeskw_param->ulAESKeyBits = 256; tmp_mech.mechanism = CKM_RSA_PKCS_OAEP; tmp_mech.pParameter = rsa_aeskw_param->pOAEPParams; tmp_mech.ulParameterLen = sizeof(CK_RSA_PKCS_OAEP_PARAMS); rc = p11sak_rsa_oaep_prepare_mech_param_from_opts(wrap_mech, &tmp_mech); if (rc != CKR_OK) { p11sak_rsa_aeskw_cleanup_mech_param(wrap_mech, mech); return rc; } return CKR_OK; } static CK_RV p11sak_rsa_aeskw_prepare_mech_param_from_pem( const struct p11sak_wrap_mech *wrap_mech, CK_MECHANISM *mech, char **pem_headers) { CK_RSA_AES_KEY_WRAP_PARAMS *rsa_aeskw_param = mech->pParameter; char *aes_key_size; CK_MECHANISM tmp_mech; CK_RV rc; UNUSED(wrap_mech); rsa_aeskw_param->pOAEPParams = calloc(1, sizeof(CK_RSA_PKCS_OAEP_PARAMS)); if (rsa_aeskw_param->pOAEPParams == NULL) { warnx("Failed to allocate memory for a mechanism parameter"); return CKR_HOST_MEMORY; } if (opt_aeskw_keybits != NULL) { warnx("Option '--aes-key-size' is ignored, using information " "from PEM file '%s'.", opt_file); }; aes_key_size = find_pem_header(pem_headers, P11SAK_WRAP_PEM_HDR_AES_KEY_SIZE); if (aes_key_size != NULL) { rsa_aeskw_param->ulAESKeyBits = find_aeskw_keybits_by_name(aes_key_size); if (rsa_aeskw_param->ulAESKeyBits == (CK_ULONG)-1) { warnx("Invalid AES key size '%s' in PEM file '%s'.", aes_key_size, opt_file); return CKR_ARGUMENTS_BAD; } } else { rsa_aeskw_param->ulAESKeyBits = 256; } tmp_mech.mechanism = CKM_RSA_PKCS_OAEP; tmp_mech.pParameter = rsa_aeskw_param->pOAEPParams; tmp_mech.ulParameterLen = sizeof(CK_RSA_PKCS_OAEP_PARAMS); rc = p11sak_rsa_oaep_prepare_mech_param_from_pem(wrap_mech, &tmp_mech, pem_headers); if (rc != CKR_OK) { p11sak_rsa_aeskw_cleanup_mech_param(wrap_mech, mech); return rc; } return CKR_OK; } static void p11sak_rsa_aeskw_cleanup_mech_param( const struct p11sak_wrap_mech *wrap_mech, CK_MECHANISM *mech) { CK_RSA_AES_KEY_WRAP_PARAMS *rsa_aeskw_param = mech->pParameter; CK_MECHANISM tmp_mech; UNUSED(wrap_mech); if (rsa_aeskw_param->pOAEPParams == NULL) return; tmp_mech.mechanism = CKM_RSA_PKCS_OAEP; tmp_mech.pParameter = rsa_aeskw_param->pOAEPParams; tmp_mech.ulParameterLen = sizeof(CK_RSA_PKCS_OAEP_PARAMS); p11sak_rsa_oaep_cleanup_mech_param(wrap_mech, &tmp_mech); free(rsa_aeskw_param->pOAEPParams); } static CK_RV p11sak_rsa_aeskw_prepare_pem_header( const struct p11sak_wrap_mech *wrap_mech, char **pem_header) { char *oaep_hdr = NULL; CK_RV rc; int len; UNUSED(wrap_mech); rc = p11sak_rsa_oaep_prepare_pem_header(wrap_mech, &oaep_hdr); if (rc != CKR_OK) return rc; len = asprintf(pem_header, "%s: %s\n%s", P11SAK_WRAP_PEM_HDR_AES_KEY_SIZE, opt_aeskw_keybits != NULL ? opt_aeskw_keybits->value : "256", oaep_hdr != NULL ? oaep_hdr : ""); if (oaep_hdr != NULL) free(oaep_hdr); if (len <= 0) { warnx("Failed to allocate memory for a PEM header"); return CKR_HOST_MEMORY; } return CKR_OK; } static CK_RV p11sak_ecdh_aeskw_prepare_mech_param_from_opts( const struct p11sak_wrap_mech *wrap_mech, CK_MECHANISM *mech) { CK_ECDH_AES_KEY_WRAP_PARAMS *ecdh_aeskw_param = mech->pParameter; CK_RV rc; UNUSED(wrap_mech); if (opt_aeskw_keybits != NULL) ecdh_aeskw_param->ulAESKeyBits = opt_aeskw_keybits->private.num; else ecdh_aeskw_param->ulAESKeyBits = 256; if (opt_ecdh_kdf_alg != NULL) ecdh_aeskw_param->kdf = opt_ecdh_kdf_alg->private.num; else ecdh_aeskw_param->kdf = CKD_SHA256_KDF; if (opt_ecdh_shared_data != NULL) { rc = p11tool_parse_hex(opt_ecdh_shared_data, (CK_BYTE **)&ecdh_aeskw_param->pSharedData, &ecdh_aeskw_param->ulSharedDataLen); if (rc != CKR_OK) return rc; } else { ecdh_aeskw_param->pSharedData = NULL; ecdh_aeskw_param->ulSharedDataLen = 0; } return CKR_OK; } static CK_RV p11sak_ecdh_aeskw_prepare_mech_param_from_pem( const struct p11sak_wrap_mech *wrap_mech, CK_MECHANISM *mech, char **pem_headers) { CK_ECDH_AES_KEY_WRAP_PARAMS *ecdh_aeskw_param = mech->pParameter; char *aes_key_size, *kdf_alg, *shared_data; CK_RV rc; UNUSED(wrap_mech); if (opt_aeskw_keybits != NULL) { warnx("Option '--aes-key-size' is ignored, using information " "from PEM file '%s'.", opt_file); }; if (opt_ecdh_kdf_alg != NULL) { warnx("Option '--kdf-alg' is ignored, using information " "from PEM file '%s'.", opt_file); }; if (opt_ecdh_shared_data != NULL) { warnx("Option '--shared-data' is ignored, using information " "from PEM file '%s'.", opt_file); }; aes_key_size = find_pem_header(pem_headers, P11SAK_WRAP_PEM_HDR_AES_KEY_SIZE); kdf_alg = find_pem_header(pem_headers, P11SAK_WRAP_PEM_HDR_ECDH_KDF_ALG); shared_data = find_pem_header(pem_headers, P11SAK_WRAP_PEM_HDR_ECDH_SHARED); if (aes_key_size != NULL) { ecdh_aeskw_param->ulAESKeyBits = find_aeskw_keybits_by_name(aes_key_size); if (ecdh_aeskw_param->ulAESKeyBits == (CK_ULONG)-1) { warnx("Invalid AES key size '%s' in PEM file '%s'.", aes_key_size, opt_file); return CKR_ARGUMENTS_BAD; } } else { ecdh_aeskw_param->ulAESKeyBits = 256; } if (kdf_alg != NULL) { ecdh_aeskw_param->kdf = find_kdf_alg_by_name(kdf_alg); if (ecdh_aeskw_param->kdf == (CK_MECHANISM_TYPE)-1) { warnx("Invalid kdf algorithm '%s' in PEM file '%s'.", kdf_alg, opt_file); return CKR_ARGUMENTS_BAD; } } else { ecdh_aeskw_param->kdf = CKD_SHA256_KDF; } if (shared_data != NULL) { if (strcasecmp(shared_data, P11SAK_WRAP_PEM_HDR_ECDH_SHARED_NONE) == 0) { ecdh_aeskw_param->pSharedData = NULL; ecdh_aeskw_param->ulSharedDataLen = 0; } else { rc = p11tool_parse_hex(shared_data, (CK_BYTE **)&ecdh_aeskw_param->pSharedData, &ecdh_aeskw_param->ulSharedDataLen); if (rc != CKR_OK) return rc; } } else { ecdh_aeskw_param->pSharedData = NULL; ecdh_aeskw_param->ulSharedDataLen = 0; } return CKR_OK; } static void p11sak_ecdh_aeskw_cleanup_mech_param( const struct p11sak_wrap_mech *wrap_mech, CK_MECHANISM *mech) { CK_ECDH_AES_KEY_WRAP_PARAMS *ecdh_aeskw_param = mech->pParameter; UNUSED(wrap_mech); if (ecdh_aeskw_param->pSharedData != NULL) free(ecdh_aeskw_param->pSharedData); } static CK_RV p11sak_ecdh_aeskw_prepare_pem_header( const struct p11sak_wrap_mech *wrap_mech, char **pem_header) { int len; UNUSED(wrap_mech); len = asprintf(pem_header, "%s: %s\n%s: %s\n%s: %s\n", P11SAK_WRAP_PEM_HDR_AES_KEY_SIZE, opt_aeskw_keybits != NULL ? opt_aeskw_keybits->value : "256", P11SAK_WRAP_PEM_HDR_ECDH_KDF_ALG, opt_ecdh_kdf_alg != NULL ? opt_ecdh_kdf_alg->value : "SHA256", P11SAK_WRAP_PEM_HDR_ECDH_SHARED, opt_ecdh_shared_data != NULL ? opt_ecdh_shared_data : P11SAK_WRAP_PEM_HDR_ECDH_SHARED_NONE); if (len <= 0) { warnx("Failed to allocate memory for a PEM header"); return CKR_HOST_MEMORY; } return CKR_OK; } static CK_RV handle_kek_select(CK_OBJECT_HANDLE key, CK_OBJECT_CLASS class, const struct p11tool_objtype *objtype, CK_ULONG keysize, const char *typestr, const char* label, const char *common_name, void *private) { struct p11sak_select_kek_data *data = private; char *msg = NULL; char ch; UNUSED(objtype); UNUSED(keysize); UNUSED(common_name); if (data->cancel) return CKR_OK; if (class != data->kek_class) return CKR_OK; data->count++; if (!data->prompt) { data->kek_handle = key; return CKR_OK; } if (data->kek_handle != CK_INVALID_HANDLE) return CKR_OK; if (opt_force) { data->kek_handle = key; return CKR_OK; } if (asprintf(&msg, "Use %s key object \"%s\" as key encrypting key (KEK) " "[y/n/c]? ", typestr, label) < 0 || msg == NULL) { warnx("Failed to allocate memory for a message"); return CKR_HOST_MEMORY; } ch = p11tool_prompt_user(msg, "ync"); free(msg); switch (ch) { case 'n': return CKR_OK; case 'c': case '\0': data->cancel = CK_TRUE; return CKR_OK; default: break; } data->kek_handle = key; return CKR_OK; } static CK_RV p11sak_select_kek(CK_OBJECT_CLASS kek_class, CK_KEY_TYPE kek_type, CK_KEY_TYPE addl_kek_type, CK_OBJECT_HANDLE *kek_handle) { struct p11sak_select_kek_data data = { 0 }; const struct p11tool_objtype *keytype, *addl_keytype = NULL; CK_RV rc; if (opt_kek_label == NULL && opt_kek_id == NULL) { warnx("At least one of the following options must be specified:"); warnx("'-K'/'--kek-label', r '-k'/'--kek-id'"); return CKR_ARGUMENTS_BAD; } data.prompt = CK_FALSE; data.kek_class = kek_class; data.count = 0; data.kek_handle = CK_INVALID_HANDLE; keytype = find_keytype(kek_type); if (addl_kek_type != (CK_KEY_TYPE)-1) addl_keytype = find_keytype(addl_kek_type); rc = iterate_objects(keytype, opt_kek_label, opt_kek_id, NULL, OBJCLASS_KEY, NULL, handle_kek_select, &data); if (rc != CKR_OK) { warnx("Failed to iterate over key objects: 0x%lX: %s", rc, p11_get_ckr(rc)); return rc; } if (addl_keytype != NULL) { rc = iterate_objects(addl_keytype, opt_kek_label, opt_kek_id, NULL, OBJCLASS_KEY, NULL, handle_kek_select, &data); if (rc != CKR_OK) { warnx("Failed to iterate over key objects: 0x%lX: %s", rc, p11_get_ckr(rc)); return rc; } } if (data.count > 1) { data.prompt = CK_TRUE; data.count = 0; data.cancel = CK_FALSE; data.kek_handle = CK_INVALID_HANDLE; rc = iterate_objects(keytype, opt_kek_label, opt_kek_id, NULL, OBJCLASS_KEY, NULL, handle_kek_select, &data); if (rc != CKR_OK) { warnx("Failed to iterate over key objects: 0x%lX: %s", rc, p11_get_ckr(rc)); return rc; } if (data.cancel) return CKR_CANCEL; if (data.kek_handle == CK_INVALID_HANDLE && addl_keytype != NULL) { rc = iterate_objects(addl_keytype, opt_kek_label, opt_kek_id, NULL, OBJCLASS_KEY, NULL, handle_kek_select, &data); if (rc != CKR_OK) { warnx("Failed to iterate over key objects: 0x%lX: %s", rc, p11_get_ckr(rc)); return rc; } if (data.cancel) return CKR_CANCEL; if (data.kek_handle != CK_INVALID_HANDLE) keytype = addl_keytype; } } if (data.kek_handle == CK_INVALID_HANDLE) { warnx("No %s%s%s%s key matched the specified KEK label or ID.", kek_class == CKO_SECRET_KEY ? "" : kek_class == CKO_PUBLIC_KEY ? "public " : "private ", keytype != NULL ? keytype->name : "", addl_keytype != NULL ? " or " : "", addl_keytype != NULL ? addl_keytype->name : ""); return CKR_ARGUMENTS_BAD; } *kek_handle = data.kek_handle; return CKR_OK; } static CK_RV p11sak_wrap_key_perform(struct p11sak_wrap_data *data, const struct p11tool_objtype *keytype, CK_OBJECT_HANDLE key, const char *typestr, const char* label, BIO *bio) { CK_ULONG len = 0; CK_BYTE *buf = NULL; char *hdr = NULL; CK_RV rc; rc = p11tool_pkcs11_funcs->C_WrapKey(p11tool_pkcs11_session, &data->mech, data->kek_handle, key, NULL, &len); if (rc != CKR_OK) { warnx("Failed to wrap %s key \"%s\": 0x%lX: %s", typestr, label, rc, p11_get_ckr(rc)); return rc; } buf = calloc(1, len); if (buf == NULL) { warnx("Failed to allocate memory for wrapped key"); return CKR_HOST_MEMORY; } rc = p11tool_pkcs11_funcs->C_WrapKey(p11tool_pkcs11_session, &data->mech, data->kek_handle, key, buf, &len); if (rc != CKR_OK) { warnx("Failed to wrap %s key \"%s\": 0x%lX: %s", typestr, label, rc, p11_get_ckr(rc)); return rc; } if (opt_raw) { if (BIO_write(bio, buf, len) != (int)len) { warnx("Failed to write to file '%s'.", opt_file); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } } else { if (asprintf(&hdr, "%s: %s\n%s", P11SAK_WRAP_PEM_HDR_KEY_TYPE, keytype->name, data->pem_header) <= 0) { warnx("Failed to allocate memory for a PEM header"); rc = CKR_HOST_MEMORY; goto done; } if (PEM_write_bio(bio, P11SAK_WRAP_PEM_NAME, hdr, buf, len) <= 0) { warnx("Failed to write to PEM file '%s'.", opt_file); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } } done: free(buf); if (hdr != NULL) free(hdr); return rc; } static CK_RV handle_obj_wrap(CK_OBJECT_HANDLE key, CK_OBJECT_CLASS class, const struct p11tool_objtype *objtype, CK_ULONG keysize, const char *typestr, const char* label, const char *common_name, void *private) { struct p11sak_wrap_data *data = private; char *msg = NULL; BIO *bio; bool overwrite = false; char ch; CK_RV rc; UNUSED(keysize); UNUSED(common_name); if (class == CKO_PUBLIC_KEY) return CKR_OK; if (data->skip_all) { data->num_skipped++; return CKR_OK; } if (!data->wrap_all) { if (asprintf(&msg, "Are you sure you want to wrap %s key object \"%s\"" " [y/n/a/c]? ", typestr, label) < 0 || msg == NULL) { warnx("Failed to allocate memory for a message"); return CKR_HOST_MEMORY; } ch = p11tool_prompt_user(msg, "ynac"); free(msg); switch (ch) { case 'n': data->num_skipped++; return CKR_OK; case 'c': case '\0': data->skip_all = true; data->num_skipped++; return CKR_OK; case 'a': data->wrap_all = true; break; default: break; } } if (opt_raw && data->num_wrapped > 0) { printf("The last wrapped key was stored as raw binary wrapped key " "material, and the current\nkey is also to be stored as raw " "binary wrapped key material.\nIt can not be appended to the " "previously wrapped key(s).\n"); overwrite = true; } if (overwrite && !opt_force) { ch = p11tool_prompt_user("Overwrite the previously wrapped key " "material [y/n]? ", "yn"); switch (ch) { case 'n': data->num_skipped++; return CKR_OK; default: break; } } bio = BIO_new_file(opt_file, overwrite || data->num_wrapped == 0 ? "w" : "a"); if (bio == NULL) { warnx("Failed to open file '%s'.", opt_file); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); data->num_failed++; return CKR_ARGUMENTS_BAD; } rc = p11sak_wrap_key_perform(data, objtype, key, typestr, label, bio); if (rc != CKR_OK) { switch (rc) { case CKR_KEY_UNEXTRACTABLE: warnx("%s key object \"%s\" is unextractable and can not be " "wrapped.", typestr, label); break; case CKR_KEY_NOT_WRAPPABLE: warnx("%s key object \"%s\" can not be wrapped.", typestr, label); break; } data->num_failed++; goto done; } printf("Successfully wrapped %s key object \"%s\" to file '%s'.\n", typestr, label, opt_file); data->num_wrapped++; done: BIO_free(bio); if (rc != CKR_OK && (overwrite || data->num_wrapped == 0)) remove(opt_file); return CKR_OK; } static CK_RV prepare_mech_param(const struct p11sak_wrap_mech *wrap_mech, CK_MECHANISM *mech, void **mech_param, char **pem_headers) { CK_RV rc = CKR_OK; if (wrap_mech->mech_param_size > 0) { *mech_param = calloc(1, wrap_mech->mech_param_size); if (*mech_param == NULL) { warnx("Failed to allocate memory for mechanism parameter"); return CKR_HOST_MEMORY; } } mech->mechanism = wrap_mech->mech; mech->ulParameterLen = wrap_mech->mech_param_size; mech->pParameter = *mech_param; if (wrap_mech->mech_param_size == 0) return CKR_OK; if (pem_headers != NULL) { if (wrap_mech->prepare_mech_param_from_pem != NULL) rc = wrap_mech->prepare_mech_param_from_pem(wrap_mech, mech, pem_headers); } else { if (wrap_mech->prepare_mech_param_from_opts != NULL) rc = wrap_mech->prepare_mech_param_from_opts(wrap_mech, mech); } if (rc != CKR_OK) { free(*mech_param); *mech_param = NULL; } return rc; } static void cleanup_mech_param(const struct p11sak_wrap_mech *wrap_mech, CK_MECHANISM *mech, void *mech_param) { if (mech_param == NULL) return; if (wrap_mech->cleanup_mech_param != NULL) wrap_mech->cleanup_mech_param(wrap_mech, mech); free(mech_param); } static CK_RV prepare_pem_header(const struct p11sak_wrap_mech *wrap_mech, char **pem_header) { CK_RV rc; char *param_hdr = NULL; int len; if (wrap_mech->prepare_pem_header != NULL) { rc = wrap_mech->prepare_pem_header(wrap_mech, ¶m_hdr); if (rc != CKR_OK) return rc; } len = asprintf(pem_header, "%s: %s\n%s", P11SAK_WRAP_PEM_HDR_ALG, wrap_mech->name, param_hdr != NULL ? param_hdr : ""); if (param_hdr != NULL) free(param_hdr); if (len <= 0) { warnx("Failed to allocate memory for a PEM header"); return CKR_HOST_MEMORY; } return CKR_OK; } CK_RV p11sak_wrap_key(void) { const struct p11tool_objtype *keytype = NULL; const struct p11sak_wrap_mech *wrap_mech = opt_wrap_mech->private.ptr; struct p11sak_wrap_data data = { 0 }; void *mech_param = NULL; CK_RV rc; if (opt_keytype != NULL) keytype = opt_keytype->private.ptr; rc = p11tool_check_wrap_mech_supported(opt_slot, wrap_mech->mech, CK_TRUE, CK_FALSE); if (rc != CKR_OK) return rc; rc = p11sak_select_kek(wrap_mech->wrap_class, wrap_mech->key_type, wrap_mech->addl_key_type, &data.kek_handle); if (rc != CKR_OK) return rc; rc = prepare_mech_param(wrap_mech, &data.mech, &mech_param, NULL); if (rc != CKR_OK) return rc; if (!opt_raw) { rc = prepare_pem_header(wrap_mech, &data.pem_header); if (rc != CKR_OK) return rc; } data.wrap_mech = wrap_mech; data.wrap_all = opt_force; rc = iterate_objects(keytype, opt_label, opt_id, opt_attr, OBJCLASS_KEY, NULL, handle_obj_wrap, &data); if (rc != CKR_OK) { warnx("Failed to iterate over key objects for key type %s: 0x%lX: %s", keytype != NULL ? keytype->name : "All", rc, p11_get_ckr(rc)); goto out; } printf("%lu key object(s) wrapped.\n", data.num_wrapped); if (data.num_skipped > 0) printf("%lu key object(s) skipped.\n", data.num_skipped); if (data.num_failed > 0) printf("%lu key object(s) failed to wrap.\n", data.num_failed); out: cleanup_mech_param(wrap_mech, &data.mech, mech_param); if (data.pem_header != NULL) free(data.pem_header); return rc != CKR_OK ? rc : data.num_failed == 0 ? CKR_OK : CKR_FUNCTION_FAILED; } static CK_RV read_wrapped_key(CK_BYTE **buf, CK_ULONG *len, char **pem_header) { char *pem_name = NULL; long pem_len; BIO *bio; CK_RV rc = CKR_OK; *buf = NULL; *len = 0; *pem_header = NULL; bio = BIO_new_file(opt_file, "r"); if (bio == NULL) { warnx("Failed to open file '%s'.", opt_file); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); return CKR_ARGUMENTS_BAD; } if (opt_raw) { rc = p11tool_bio_readall(bio, buf, len); if (rc != CKR_OK) { warnx("Failed to read file '%s'.", opt_file); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); goto done; } } else { do { if (pem_name != NULL) OPENSSL_free(pem_name); if (*pem_header != NULL) OPENSSL_free(*pem_header); if (*buf != NULL) OPENSSL_free(*buf); *buf = NULL; *len = 0; *pem_header = NULL; if (PEM_read_bio(bio, &pem_name, pem_header, buf, &pem_len) != 1) { warnx("Failed to read PEM file '%s'.", opt_file); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); rc = CKR_FUNCTION_FAILED; goto done; } *len = pem_len; } while (strcmp(pem_name, P11SAK_WRAP_PEM_NAME) != 0); } done: BIO_free(bio); if (pem_name != NULL) OPENSSL_free(pem_name); if (rc != CKR_OK && *pem_header != NULL) OPENSSL_free(*pem_header); if (rc != CKR_OK) OPENSSL_free(*buf); return rc; } static CK_RV process_pem_header(char *pem_header, const struct p11sak_wrap_mech **wrap_mech, const struct p11tool_objtype **keytype, CK_MECHANISM *mech, void **mech_param) { char **headers = NULL; char *wrap_alg_str, *keytype_str; CK_RV rc; rc = p11tool_split_by_delim(pem_header, "\n", &headers); if (rc != CKR_OK) return rc; wrap_alg_str = find_pem_header(headers, P11SAK_WRAP_PEM_HDR_ALG); if (wrap_alg_str == NULL) { warnx("No '%s' header line found in PEM file '%s'", P11SAK_WRAP_PEM_HDR_ALG, opt_file); rc = CKR_ARGUMENTS_BAD; goto done; } if (*wrap_mech != NULL) { warnx("Argument 'WRAP-MECH' is ignored, using information from " "PEM file '%s'.", opt_file); } *wrap_mech = find_wrap_mech_by_name(wrap_alg_str); if (*wrap_mech == NULL) { warnx("Wrap mechanism '%s' from PEM file '%s' is not valid", wrap_alg_str, opt_file); rc = CKR_ARGUMENTS_BAD; goto done; } keytype_str = find_pem_header(headers, P11SAK_WRAP_PEM_HDR_KEY_TYPE); if (keytype_str == NULL) { warnx("No '%s' header line found in PEM file '%s'", P11SAK_WRAP_PEM_HDR_KEY_TYPE, opt_file); rc = CKR_ARGUMENTS_BAD; goto done; } if (*keytype != NULL) { warnx("Argument 'KEYTYPE' is ignored, using information from " "PEM file '%s'.", opt_file); } *keytype = find_keytype_by_name(keytype_str); if (*keytype == NULL) { warnx("Key type '%s' from PEM file '%s' is not valid", keytype_str, opt_file); rc = CKR_ARGUMENTS_BAD; goto done; } rc = prepare_mech_param(*wrap_mech, mech, mech_param, headers); if (rc != CKR_OK) return rc; done: free(headers); return rc; } static CK_RV p11sak_unwrap_key_perform(const struct p11tool_objtype *keytype, CK_OBJECT_HANDLE kek_handle, CK_MECHANISM *mech, CK_BYTE *wrapped_key, CK_ULONG wrapped_key_len) { CK_ATTRIBUTE *attrs = NULL; CK_ULONG num_attrs = 0; CK_OBJECT_CLASS class; CK_OBJECT_HANDLE key_kandle; CK_RV rc; class = keytype->is_asymmetric ? CKO_PRIVATE_KEY : CKO_SECRET_KEY; rc = p11tool_add_attribute(CKA_CLASS, &class, sizeof(class), &attrs, &num_attrs); if (rc != CKR_OK) goto done; rc = p11tool_add_attribute(CKA_KEY_TYPE, &keytype->type, sizeof(keytype->type), &attrs, &num_attrs); if (rc != CKR_OK) goto done; rc = p11tool_add_attributes(keytype, p11sak_bool_attrs, &attrs, &num_attrs, opt_label, opt_attr, opt_id, CK_TRUE, opt_so, NULL, NULL, class == CKO_PRIVATE_KEY ? p11tool_private_attr_applicable : p11tool_secret_attr_applicable); if (rc != CKR_OK) goto done; rc = p11tool_pkcs11_funcs->C_UnwrapKey(p11tool_pkcs11_session, mech, kek_handle, wrapped_key, wrapped_key_len, attrs, num_attrs, &key_kandle); if (rc != CKR_OK) { warnx("Failed to unwrap %s key \"%s\": 0x%lX: %s", keytype->name, opt_label, rc, p11_get_ckr(rc)); goto done; } printf("Successfully unwrapped a %s key with label \"%s\".\n", keytype->name, opt_label); done: p11tool_free_attributes(attrs, num_attrs); return rc; } CK_RV p11sak_unwrap_key(void) { const struct p11sak_wrap_mech *wrap_mech = NULL; const struct p11tool_objtype *keytype = NULL; CK_OBJECT_HANDLE kek_handle = CK_INVALID_HANDLE; CK_MECHANISM mech = { 0 }; void *mech_param = NULL; char *pem_header = NULL; CK_BYTE *wrapped_key = NULL; CK_ULONG wrapped_key_len = 0; CK_RV rc; if (opt_wrap_mech != NULL) wrap_mech = opt_wrap_mech->private.ptr; if (opt_keytype != NULL) keytype = opt_keytype->private.ptr; rc = read_wrapped_key(&wrapped_key, &wrapped_key_len, &pem_header); if (rc != CKR_OK) return rc; if (opt_raw) { if (wrap_mech == NULL) { warnx("Argument 'WRAP-MECH' is required when '-R'/'--raw' is " "specified"); rc = CKR_ARGUMENTS_BAD; goto done; } if (keytype == NULL) { warnx("Argument 'KEYTYPE' is required when '-R'/'--raw' is " "specified"); rc = CKR_ARGUMENTS_BAD; goto done; } /* Get mechanism param from options only */ rc = prepare_mech_param(wrap_mech, &mech, &mech_param, NULL); if (rc != CKR_OK) goto done; } else { /* Get mechanism param from PEM file */ rc = process_pem_header(pem_header, &wrap_mech, &keytype, &mech, &mech_param); if (rc != CKR_OK) goto done; } rc = p11tool_check_wrap_mech_supported(opt_slot, wrap_mech->mech, CK_FALSE, CK_TRUE); if (rc != CKR_OK) goto done; rc = p11sak_select_kek(wrap_mech->unwrap_class, wrap_mech->key_type, wrap_mech->addl_key_type, &kek_handle); if (rc != CKR_OK) goto done; rc = p11sak_unwrap_key_perform(keytype, kek_handle, &mech, wrapped_key, wrapped_key_len); if (rc != CKR_OK) goto done; done: cleanup_mech_param(wrap_mech, &mech, mech_param); if (pem_header != NULL) OPENSSL_free(pem_header); OPENSSL_free(wrapped_key); return rc; } void print_wrap_key_help(void) { const struct p11tool_attr *attr; printf("ATTRIBUTES:\n"); for (attr = p11sak_bool_attrs; attr->name != NULL; attr++) printf(" '%c': %s\n", attr->letter, attr->name); printf("\n"); printf(" "); p11tool_print_indented("Not all attributes may be defined for all key " "types.", 4); printf("\n"); } void print_unwrap_key_help(void) { const struct p11tool_attr *attr; printf("ATTRIBUTES:\n"); for (attr = p11sak_bool_attrs; attr->name != NULL; attr++) { if (attr->settable) printf(" '%c': %s%s\n", attr->letter, attr->name, attr->so_set_to_true ? " (can be set to TRUE by SO only)" : ""); } printf("\n"); printf(" "); p11tool_print_indented("An uppercase letter sets the corresponding " "attribute to CK_TRUE, a lower case letter to " "CK_FALSE.\n" "If an attribute is not set explicitly, its default " "value is used.\n" "Not all attributes may be accepted for all key " "types.\n" "Attribute CKA_TOKEN is always set to CK_TRUE.", 4); printf("\n"); } opencryptoki-opencryptoki-451d99c/usr/sbin/p11sak/p11tool.c000066400000000000000000002534031520105705100236420ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2025 * * 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 "platform.h" #if !defined(_AIX) #include #endif /* _AIX */ #include #include #include #include "p11tool.h" #include "p11util.h" #include "pin_prompt.h" #include "mechtable.h" void *p11tool_pkcs11_lib = NULL; bool p11tool_pkcs11_initialized = false; CK_FUNCTION_LIST *p11tool_pkcs11_funcs = NULL; CK_SESSION_HANDLE p11tool_pkcs11_session = CK_INVALID_HANDLE; CK_INFO p11tool_pkcs11_info; CK_TOKEN_INFO p11tool_pkcs11_tokeninfo; const struct p11tool_token_info *p11tool_token_info = NULL; CK_SLOT_INFO p11tool_pkcs11_slotinfo; char *p11tool_pin = NULL; const struct p11tool_class p11tool_classes[] = { { .name = "CKO_DATA", .class = CKO_DATA, }, { .name = "CKO_CERTIFICATE", .class = CKO_CERTIFICATE, }, { .name = "CKO_PUBLIC_KEY", .class = CKO_PUBLIC_KEY, }, { .name = "CKO_PRIVATE_KEY", .class = CKO_PRIVATE_KEY, }, { .name = "CKO_SECRET_KEY", .class = CKO_SECRET_KEY, }, { .name = "CKO_HW_FEATURE", .class = CKO_HW_FEATURE, }, { .name = "CKO_DOMAIN_PARAMETERS", .class = CKO_DOMAIN_PARAMETERS, }, { .name = "CKO_PROFILE", .class = CKO_PROFILE, }, { .name = NULL, .class = 0, } }; const struct p11tool_enum_value p11tool_ibm_dilithium_versions[] = { { .value = "r2_65", .args = NULL, .private = { .num = CK_IBM_DILITHIUM_KEYFORM_ROUND2_65 }, }, { .value = "r2_87", .args = NULL, .private = { .num = CK_IBM_DILITHIUM_KEYFORM_ROUND2_87 }, }, { .value = "r3_44", .args = NULL, .private = { .num = CK_IBM_DILITHIUM_KEYFORM_ROUND3_44 }, }, { .value = "r3_65", .args = NULL, .private = { .num = CK_IBM_DILITHIUM_KEYFORM_ROUND3_65 }, }, { .value = "r3_87", .args = NULL, .private = { .num = CK_IBM_DILITHIUM_KEYFORM_ROUND3_87 }, }, { .value = NULL, }, }; const struct p11tool_enum_value p11tool_ibm_kyber_versions[] = { { .value = "r2_768", .args = NULL, .private = { .num = CK_IBM_KYBER_KEYFORM_ROUND2_768 }, }, { .value = "r2_1024", .args = NULL, .private = { .num = CK_IBM_KYBER_KEYFORM_ROUND2_1024 }, }, { .value = NULL, }, }; const struct p11tool_enum_value p11tool_ibm_ml_dsa_versions[] = { { .value = "44", .args = NULL, .private = { .num = CKP_IBM_ML_DSA_44 }, }, { .value = "65", .args = NULL, .private = { .num = CKP_IBM_ML_DSA_65 }, }, { .value = "87", .args = NULL, .private = { .num = CKP_IBM_ML_DSA_87 }, }, { .value = NULL, }, }; const struct p11tool_enum_value p11tool_ibm_ml_kem_versions[] = { { .value = "512", .args = NULL, .private = { .num = CKP_IBM_ML_KEM_512 }, }, { .value = "768", .args = NULL, .private = { .num = CKP_IBM_ML_KEM_768 }, }, { .value = "1024", .args = NULL, .private = { .num = CKP_IBM_ML_KEM_1024 }, }, { .value = NULL, }, }; const struct p11tool_enum_value p11tool_ml_dsa_versions[] = { { .value = "44", .args = NULL, .private = { .num = CKP_ML_DSA_44 }, }, { .value = "65", .args = NULL, .private = { .num = CKP_ML_DSA_65 }, }, { .value = "87", .args = NULL, .private = { .num = CKP_ML_DSA_87 }, }, { .value = NULL, }, }; const struct p11tool_enum_value p11tool_ml_kem_versions[] = { { .value = "512", .args = NULL, .private = { .num = CKP_ML_KEM_512 }, }, { .value = "768", .args = NULL, .private = { .num = CKP_ML_KEM_768 }, }, { .value = "1024", .args = NULL, .private = { .num = CKP_ML_KEM_1024 }, }, { .value = NULL, }, }; static bool p11tool_argument_is_set(const struct p11tool_arg *arg); const struct p11tool_cmd *p11tool_find_command(const struct p11tool_cmd *cmds, const char *cmd) { unsigned int i; for (i = 0; cmds[i].cmd != NULL; i++) { if (strcasecmp(cmd, cmds[i].cmd) == 0) return &cmds[i]; if (cmds[i].cmd_short1 != NULL && strcasecmp(cmd, cmds[i].cmd_short1) == 0) return &cmds[i]; if (cmds[i].cmd_short2 != NULL && strcasecmp(cmd, cmds[i].cmd_short2) == 0) return &cmds[i]; } return NULL; } static void p11tool_count_opts(const struct p11tool_opt *opts, unsigned int *optstring_len, unsigned int *longopts_count) { const struct p11tool_opt *opt; for (opt = opts; opt->short_opt != 0 || opt->long_opt != NULL; opt++) { if (opt->short_opt != 0) { (*optstring_len)++; if (opt->arg.type != ARG_TYPE_PLAIN) { (*optstring_len)++; if (!opt->arg.required) (*optstring_len)++; } } if (opt->long_opt != NULL) (*longopts_count)++; } } static CK_RV p11tool_build_opts(const struct p11tool_opt *opts, char *optstring, struct option *longopts) { const struct p11tool_opt *opt; unsigned int opts_idx, long_idx; opts_idx = strlen(optstring); for (long_idx = 0; longopts[long_idx].name != NULL; long_idx++) ; for (opt = opts; opt->short_opt != 0 || opt->long_opt != NULL; opt++) { if (opt->short_opt != 0) { optstring[opts_idx++] = opt->short_opt; if (opt->arg.type != ARG_TYPE_PLAIN) { optstring[opts_idx++] = ':'; if (!opt->arg.required) optstring[opts_idx++] = ':'; } } if (opt->long_opt != NULL) { longopts[long_idx].name = opt->long_opt; longopts[long_idx].has_arg = opt->arg.type != ARG_TYPE_PLAIN ? (opt->arg.required ? required_argument : optional_argument ) : no_argument; longopts[long_idx].flag = NULL; longopts[long_idx].val = opt->short_opt != 0 ? opt->short_opt : opt->long_opt_val; long_idx++; } } return CKR_OK; } static void p11tool_count_arg_opts(const struct p11tool_arg *args, unsigned int *optstring_len, unsigned int *longopts_count) { const struct p11tool_arg *arg; const struct p11tool_enum_value *val; for (arg = args; arg->name != NULL; arg++) { if (!p11tool_argument_is_set(arg)) continue; if (arg->type != ARG_TYPE_ENUM) continue; for (val = arg->enum_values; val->value != NULL; val++) { if (val->opts == NULL) continue; if (*arg->value.enum_value != val) continue; p11tool_count_opts(val->opts, optstring_len, longopts_count); if (val->args != NULL) p11tool_count_arg_opts(val->args, optstring_len, longopts_count); } } } static CK_RV p11tool_build_arg_opts(const struct p11tool_arg *args, char *optstring, struct option *longopts) { const struct p11tool_arg *arg; const struct p11tool_enum_value *val; CK_RV rc; for (arg = args; arg->name != NULL; arg++) { if (!p11tool_argument_is_set(arg)) continue; if (arg->type != ARG_TYPE_ENUM) continue; for (val = arg->enum_values; val->value != NULL; val++) { if (val->opts == NULL) continue; if (*arg->value.enum_value != val) continue; rc = p11tool_build_opts(val->opts, optstring, longopts); if (rc != CKR_OK) return rc; if (val->args != NULL) { rc = p11tool_build_arg_opts(val->args, optstring, longopts); if (rc != CKR_OK) return rc; } } } return CKR_OK; } static CK_RV p11tool_build_cmd_opts(const struct p11tool_opt *cmd_opts, const struct p11tool_opt *generic_opts, const struct p11tool_arg *cmd_args, char **optstring, struct option **longopts) { unsigned int optstring_len = 0, longopts_count = 0; CK_RV rc; p11tool_count_opts(generic_opts, &optstring_len, &longopts_count); if (cmd_opts != NULL) p11tool_count_opts(cmd_opts, &optstring_len, &longopts_count); if (cmd_args != NULL) p11tool_count_arg_opts(cmd_args, &optstring_len, &longopts_count); *optstring = calloc(1 + optstring_len + 1, 1); *longopts = calloc(longopts_count + 1, sizeof(struct option)); if (*optstring == NULL || *longopts == NULL) { rc = CKR_HOST_MEMORY; goto error; } (*optstring)[0] = ':'; /* Let getopt return ':' on missing argument */ rc = p11tool_build_opts(generic_opts, *optstring, *longopts); if (rc != CKR_OK) goto error; if (cmd_opts != NULL) { rc = p11tool_build_opts(cmd_opts, *optstring, *longopts); if (rc != CKR_OK) goto error; } if (cmd_args != NULL) { rc = p11tool_build_arg_opts(cmd_args, *optstring, *longopts); if (rc != CKR_OK) goto error; } return CKR_OK; error: if (*optstring != NULL) free(*optstring); *optstring = NULL; if (*longopts != NULL) free(*longopts); *longopts = NULL; return rc; } static CK_RV p11tool_process_plain_argument(const struct p11tool_arg *arg) { *arg->value.plain = true; return CKR_OK; } static CK_RV p11tool_process_string_argument(const struct p11tool_arg *arg, char *val) { *arg->value.string = val; return CKR_OK; } static CK_RV p11tool_process_enum_argument(const struct p11tool_arg *arg, char *val) { const struct p11tool_enum_value *enum_val, *any_val = NULL; for (enum_val = arg->enum_values; enum_val->value != NULL; enum_val++) { if (enum_val->any_value != NULL) { any_val = enum_val; } else if (arg->case_sensitive ? strcmp(val, enum_val->value) == 0 : strcasecmp(val, enum_val->value) == 0) { *arg->value.enum_value = (struct p11tool_enum_value *)enum_val; return CKR_OK; } } /* process ANY enumeration value after all others */ if (any_val != NULL) { *any_val->any_value = val; *arg->value.enum_value = (struct p11tool_enum_value *)any_val; return CKR_OK; } return CKR_ARGUMENTS_BAD; } static CK_RV p11tool_process_number_argument(const struct p11tool_arg *arg, char *val) { char *endptr; errno = 0; *arg->value.number = strtoul(val, &endptr, 0); if ((errno == ERANGE && *arg->value.number == ULONG_MAX) || (errno != 0 && *arg->value.number == 0) || endptr == val) { return CKR_ARGUMENTS_BAD; } return CKR_OK; } static CK_RV p11tool_processs_argument(const struct p11tool_arg *arg, char *val) { switch (arg->type) { case ARG_TYPE_PLAIN: return p11tool_process_plain_argument(arg); case ARG_TYPE_STRING: return p11tool_process_string_argument(arg, val); case ARG_TYPE_ENUM: return p11tool_process_enum_argument(arg, val); case ARG_TYPE_NUMBER: return p11tool_process_number_argument(arg, val); default: return CKR_ARGUMENTS_BAD; } } static bool p11tool_argument_is_set(const struct p11tool_arg *arg) { if (arg->is_set != NULL) return arg->is_set(arg); switch (arg->type) { case ARG_TYPE_PLAIN: return *arg->value.plain; case ARG_TYPE_STRING: return *arg->value.string != NULL; case ARG_TYPE_ENUM: return *arg->value.enum_value != NULL; case ARG_TYPE_NUMBER: return *arg->value.number != 0; default: return false; } } static void p11tool_option_arg_error(const struct p11tool_opt *opt, const char *arg) { if (opt->short_opt != 0 && opt->long_opt != NULL) warnx("Invalid argument '%s' for option '-%c/--%s'", arg, opt->short_opt, opt->long_opt); else if (opt->long_opt != NULL) warnx("Invalid argument '%s' for option '--%s'", arg, opt->long_opt); else warnx("Invalid argument '%s' for option '-%c'", arg, opt->short_opt); } static void p11tool_option_missing_error(const struct p11tool_opt *opt) { if (opt->short_opt != 0 && opt->long_opt != NULL) warnx("Option '-%c/--%s' is required but not specified", opt->short_opt, opt->long_opt); else if (opt->long_opt != NULL) warnx("Option '--%s is required but not specified'", opt->long_opt); else warnx("Option '-%c' is required but not specified", opt->short_opt); } static CK_RV p11tool_process_option(const struct p11tool_opt *opts, int ch, char *val) { const struct p11tool_opt *opt; CK_RV rc; for (opt = opts; opt->short_opt != 0 || opt->long_opt != NULL; opt++) { if (ch == (opt->short_opt != 0 ? opt->short_opt : opt->long_opt_val)) { rc = p11tool_processs_argument(&opt->arg, val); if (rc != CKR_OK) { p11tool_option_arg_error(opt, val); return rc; } return CKR_OK; } } return CKR_ARGUMENTS_BAD; } static CK_RV p11tool_process_arg_option(const struct p11tool_arg *args, int ch, char *value) { const struct p11tool_arg *arg; const struct p11tool_enum_value *val; CK_RV rc; for (arg = args; arg->name != NULL; arg++) { if (!p11tool_argument_is_set(arg)) continue; if (arg->type != ARG_TYPE_ENUM) continue; for (val = arg->enum_values; val->value != NULL; val++) { if (val->opts == NULL) continue; if (*arg->value.enum_value != val) continue; rc = p11tool_process_option(val->opts, ch, value); if (rc != CKR_OK) return rc; if (val->args != NULL) { rc = p11tool_process_arg_option(val->args, ch, value); if (rc != CKR_OK) return rc; } } } return CKR_OK; } static CK_RV p11tool_process_cmd_option(const struct p11tool_opt *cmd_opts, const struct p11tool_arg *cmd_args, const struct p11tool_opt *generic_opts, int opt, char *arg) { CK_RV rc; rc = p11tool_process_option(generic_opts, opt, arg); if (rc == CKR_OK) return CKR_OK; if (cmd_opts != NULL) { rc = p11tool_process_option(cmd_opts, opt, arg); if (rc == CKR_OK) return CKR_OK; } if (cmd_args != NULL) { rc = p11tool_process_arg_option(cmd_args, opt, arg); if (rc == CKR_OK) return CKR_OK; } return rc; } static CK_RV p11tool_check_required_opts(const struct p11tool_opt *opts) { const struct p11tool_opt *opt; CK_RV rc = CKR_OK; for (opt = opts; opt->short_opt != 0 || opt->long_opt != NULL; opt++) { if (opt->required && opt->arg.required && p11tool_argument_is_set(&opt->arg) == false) { p11tool_option_missing_error(opt); rc = CKR_ARGUMENTS_BAD; /* No break, report all missing options */ } } return rc; } static CK_RV p11tool_check_required_arg_opts(const struct p11tool_arg *args) { const struct p11tool_arg *arg; const struct p11tool_enum_value *val; CK_RV rc; for (arg = args; arg->name != NULL; arg++) { if (!p11tool_argument_is_set(arg)) continue; if (arg->type != ARG_TYPE_ENUM) continue; for (val = arg->enum_values; val->value != NULL; val++) { if (val->opts == NULL) continue; if (*arg->value.enum_value != val) continue; rc = p11tool_check_required_opts(val->opts); if (rc != CKR_OK) return rc; if (val->args != NULL) { rc = p11tool_check_required_arg_opts(val->args); if (rc != CKR_OK) return rc; } } } return CKR_OK; } CK_RV p11tool_check_required_cmd_opts(const struct p11tool_opt *cmd_opts, const struct p11tool_arg *cmd_args, const struct p11tool_opt *generic_opts) { CK_RV rc, rc2; rc = p11tool_check_required_opts(generic_opts); if (rc != CKR_OK) return rc; if (cmd_opts != NULL) { rc2 = p11tool_check_required_opts(cmd_opts); if (rc == CKR_OK) rc = rc2; } if (cmd_args != NULL) { rc2 = p11tool_check_required_arg_opts(cmd_args); if (rc == CKR_OK) rc = rc2; } return rc; } CK_RV p11tool_parse_cmd_options(const struct p11tool_cmd *cmd, const struct p11tool_opt *generic_opts, int argc, char *argv[]) { char *optstring = NULL; struct option *longopts = NULL; CK_RV rc; int c; rc = p11tool_build_cmd_opts(cmd != NULL ? cmd->opts : NULL, generic_opts, cmd != NULL ? cmd->args : NULL, &optstring, &longopts); if (rc != CKR_OK) goto done; opterr = 0; while (1) { c = getopt_long(argc, argv, optstring, longopts, NULL); if (c == -1) break; switch (c) { case ':': warnx("Option '%s' requires an argument", argv[optind - 1]); rc = CKR_ARGUMENTS_BAD; goto done; case '?': /* An invalid option has been specified */ if (optopt) warnx("Invalid option '-%c'", optopt); else warnx("Invalid option '%s'", argv[optind - 1]); rc = CKR_ARGUMENTS_BAD; goto done; default: rc = p11tool_process_cmd_option(cmd != NULL ? cmd->opts : NULL, cmd != NULL ? cmd->args : NULL, generic_opts, c, optarg); if (rc != CKR_OK) goto done; break; } } if (optind < argc) { warnx("Invalid argument '%s'", argv[optind]); rc = CKR_ARGUMENTS_BAD; goto done; } done: if (optstring != NULL) free(optstring); if (longopts != NULL) free(longopts); return rc; } CK_RV p11tool_check_required_args(const struct p11tool_arg *args) { const struct p11tool_arg *arg; CK_RV rc2, rc = CKR_OK; for (arg = args; arg != NULL && arg->name != NULL; arg++) { if (arg->required && p11tool_argument_is_set(arg) == false) { warnx("Argument '%s' is required but not specified", arg->name); rc = CKR_ARGUMENTS_BAD; /* No break, report all missing arguments */ } /* Check enumeration value specific arguments (if any) */ if (arg->type == ARG_TYPE_ENUM && *arg->value.enum_value != NULL && (*arg->value.enum_value)->args != NULL) { rc2 = p11tool_check_required_args((*arg->value.enum_value)->args); if (rc2 != CKR_OK) rc = rc2; /* No break, report all missing arguments */ } } return rc; } static CK_RV p11tool_parse_arguments(const struct p11tool_arg *args, int *argc, char **argv[]) { const struct p11tool_arg *arg; CK_RV rc = CKR_OK; for (arg = args; arg->name != NULL; arg++) { if (*argc < 2 || strncmp((*argv)[1], "-", 1) == 0) break; rc = p11tool_processs_argument(arg, (*argv)[1]); if (rc != CKR_OK) { if (rc == CKR_ARGUMENTS_BAD) warnx("Invalid argument '%s' for '%s'", (*argv)[1], arg->name); break; } (*argc)--; (*argv)++; /* Process enumeration value specific arguments (if any) */ if (arg->type == ARG_TYPE_ENUM && *arg->value.enum_value != NULL && (*arg->value.enum_value)->args != NULL) { rc = p11tool_parse_arguments((*arg->value.enum_value)->args, argc, argv); if (rc != CKR_OK) break; } } return rc; } CK_RV p11tool_parse_cmd_arguments(const struct p11tool_cmd *cmd, int *argc, char **argv[]) { if (cmd == NULL) return CKR_OK; return p11tool_parse_arguments(cmd->args, argc, argv); } void p11tool_print_indented(const char *str, int indent) { char *word, *line, *desc, *desc_ptr; int word_len, pos = indent; desc = desc_ptr = strdup(str); if (desc == NULL) return; line = strsep(&desc, "\n"); while (line != NULL) { word = strsep(&line, " "); pos = indent; while (word != NULL) { word_len = strlen(word); if (pos + word_len + 1 > MAX_PRINT_LINE_LENGTH) { printf("\n%*s", indent, ""); pos = indent; } if (pos == indent) printf("%s", word); else printf(" %s", word); pos += word_len + 1; word = strsep(&line, " "); } if (desc) printf("\n%*s", indent, ""); line = strsep(&desc, "\n"); } printf("\n"); free(desc_ptr); } static void p11tool_print_options_help(const struct p11tool_opt *opts, int indent_pos) { const struct p11tool_enum_value *val; const struct p11tool_opt *opt; char tmp[200]; int len; for (opt = opts; opt->short_opt != 0 || opt->long_opt != NULL; opt++) { if (opt->short_opt != 0 && opt->long_opt != NULL) len = snprintf(tmp, sizeof(tmp), "-%c, --%s", opt->short_opt, opt->long_opt); else if (opt->short_opt == 0 && opt->long_opt != NULL) len = snprintf(tmp, sizeof(tmp)," --%s", opt->long_opt); else len = snprintf(tmp, sizeof(tmp),"-%c", opt->short_opt); if (len >= (int)sizeof(tmp) || len < 0) { warnx("Error formatting option string. Skipping.\n"); continue; } if (opt->arg.type != ARG_TYPE_PLAIN) { if (opt->arg.required) snprintf(&tmp[len], sizeof(tmp) - len, " %s", opt->arg.name); else if (opt->long_opt == NULL) snprintf(&tmp[len], sizeof(tmp) - len, "[%s]", opt->arg.name); else snprintf(&tmp[len], sizeof(tmp) - len, "[=%s]", opt->arg.name); } printf(" %-*.*s ", indent_pos - 5, indent_pos - 5, tmp); p11tool_print_indented(opt->description, indent_pos); if (opt->arg.type == ARG_TYPE_ENUM) { for (val = opt->arg.enum_values; val->value != NULL; val++) { printf("%*s %s\n", indent_pos, "", val->value); } } } } static void p11tool_print_arguments_help(const struct p11tool_cmd *cmd, const struct p11tool_arg *args, int indent, int indent_pos) { const struct p11tool_arg *arg; const struct p11tool_enum_value *val; int width; bool newline = false; if (indent > 0) { for (arg = args; arg->name != NULL; arg++) { if (arg->required) printf(" %s", arg->name); else printf(" [%s]", arg->name); } printf("\n\n"); } for (arg = args; arg->name != NULL; arg++) { width = indent_pos - 5 - indent; if (width < (int)strlen(arg->name)) width = (int)strlen(arg->name); printf("%*s %-*.*s ", indent, "", width, width, arg->name); p11tool_print_indented(arg->description, indent_pos); newline = false; if (arg->type != ARG_TYPE_ENUM) continue; /* Enumeration: print possible values */ for (val = arg->enum_values; val->value != NULL; val++) { if (arg == cmd->args && p11tool_argument_is_set(arg) && *arg->value.enum_value != val) continue; newline = true; width = indent_pos - 9 - indent; if (width < (int)strlen(val->value)) width = (int)strlen(val->value); printf("%*s %-*.*s ", indent, "", width, width, val->value); if (val->description) { p11tool_print_indented(val->description, indent_pos); newline = false; } if (val->args != NULL) { p11tool_print_arguments_help(cmd, val->args, indent + 8, indent_pos); newline = false; } else if (val->description == NULL) { printf("\n"); } } } if (indent > 0 || newline) printf("\n"); } static void p11tool_print_argument_options_help(const struct p11tool_arg *args, int indent_pos) { const struct p11tool_arg *arg; const struct p11tool_enum_value *val; for (arg = args; arg->name != NULL; arg++) { if (arg->type != ARG_TYPE_ENUM) continue; for (val = arg->enum_values; val->value != NULL; val++) { if (val->opts == NULL) continue; if (p11tool_argument_is_set(arg) && *arg->value.enum_value != val) continue; printf("\nOPTIONS FOR ARGUMENT '%s' VALUE '%s':\n", arg->name, val->value); p11tool_print_options_help(val->opts, indent_pos); if (val->args != NULL) p11tool_print_argument_options_help(val->args, indent_pos); } } } void p11tool_print_help(const char *name, const struct p11tool_cmd *commands, const struct p11tool_opt *generic_opts, int indent_pos) { const struct p11tool_cmd *cmd; printf("\n"); printf("Usage: %s COMMAND [ARGS] [OPTIONS]\n", name); printf("\n"); printf("COMMANDS:\n"); for (cmd = commands; cmd->cmd != NULL; cmd++) { printf(" %-*.*s ", indent_pos - 5, indent_pos - 5, cmd->cmd); p11tool_print_indented(cmd->description, indent_pos); } printf("\n"); printf("COMMON OPTIONS\n"); p11tool_print_options_help(generic_opts, indent_pos); printf("\n"); printf("For more information use '%s COMMAND --help'.\n", name); printf("\n"); } void p11tool_print_command_help(const char *name, const struct p11tool_cmd *cmd, const struct p11tool_opt *generic_opts, int indent_pos) { printf("\n"); printf("Usage: %s %s [ARGS] [OPTIONS]\n", name, cmd->cmd); printf("\n"); printf("ARGS:\n"); p11tool_print_arguments_help(cmd, cmd->args, 0, indent_pos); printf("OPTIONS:\n"); p11tool_print_options_help(cmd->opts, indent_pos); p11tool_print_options_help(generic_opts, indent_pos); p11tool_print_argument_options_help(cmd->args, indent_pos); printf("\n"); if (cmd->help != NULL) cmd->help(); } void p11tool_print_version(const char *name) { printf("%s version %s\n", name, PACKAGE_VERSION); } void p11tool_print_bool_attr_short(const CK_ATTRIBUTE *val, bool applicable) { if (val->ulValueLen == CK_UNAVAILABLE_INFORMATION || val->ulValueLen != sizeof(CK_BBOOL)) applicable = false; printf("%c ", applicable ? (*(CK_BBOOL *)(val->pValue) ? '1' : '0') : '-'); } void p11tool_print_bool_attr_long(const char *attr, const CK_ATTRIBUTE *val, int indent, bool sensitive) { if ((val->ulValueLen == CK_UNAVAILABLE_INFORMATION && !sensitive)|| val->ulValueLen != sizeof(CK_BBOOL)) return; printf("%*s%s: %s\n", indent, "", attr, sensitive ? "[sensitive]" : *(CK_BBOOL *)(val->pValue) ? "CK_TRUE" : "CK_FALSE"); } void p11tool_print_utf8_attr(const char *attr, const CK_ATTRIBUTE *val, int indent, bool sensitive) { if (val->ulValueLen == CK_UNAVAILABLE_INFORMATION && !sensitive) return; if (sensitive) { printf("%*s%s: [sensitive]\n", indent, "", attr); } else if (val->ulValueLen == 0) { printf("%*s%s: [no value]\n", indent, "", attr); } else { printf("%*s%s: \"%.*s\"\n", indent, "", attr, (int)val->ulValueLen, (char *)val->pValue); } } void p11tool_print_java_midp_secdom_attr(const char *attr, const CK_ATTRIBUTE *val, int indent, bool sensitive) { CK_JAVA_MIDP_SECURITY_DOMAIN secdom; if (sensitive) { printf("%*s%s: [sensitive]\n", indent, "", attr); return; } else if (val->ulValueLen == 0) { printf("%*s%s: [no value]\n", indent, "", attr); return; } else if (val->ulValueLen != sizeof(CK_JAVA_MIDP_SECURITY_DOMAIN)) { return; } secdom = *(CK_JAVA_MIDP_SECURITY_DOMAIN *)(val->pValue); switch (secdom) { case CK_SECURITY_DOMAIN_UNSPECIFIED: printf("%*s%s: %s\n", indent, "", attr, "CK_SECURITY_DOMAIN_UNSPECIFIED"); break; case CK_SECURITY_DOMAIN_MANUFACTURER: printf("%*s%s: %s\n", indent, "", attr, "CK_SECURITY_DOMAIN_MANUFACTURER"); break; case CK_SECURITY_DOMAIN_OPERATOR: printf("%*s%s: %s\n", indent, "", attr, "CK_SECURITY_DOMAIN_OPERATOR"); break; case CK_SECURITY_DOMAIN_THIRD_PARTY: printf("%*s%s: %s\n", indent, "", attr, "CK_SECURITY_DOMAIN_THIRD_PARTY"); break; default: printf("%*s%s: 0x%lX\n", indent, "", attr, *(CK_JAVA_MIDP_SECURITY_DOMAIN *)(val->pValue)); break; } } void p11tool_print_cert_category_attr(const char *attr, const CK_ATTRIBUTE *val, int indent, bool sensitive) { CK_CERTIFICATE_CATEGORY category; if (sensitive) { printf("%*s%s: [sensitive]\n", indent, "", attr); return; } else if (val->ulValueLen == 0) { printf("%*s%s: [no value]\n", indent, "", attr); return; } else if (val->ulValueLen != sizeof(CK_CERTIFICATE_CATEGORY)) { return; } category = *(CK_CERTIFICATE_CATEGORY *)(val->pValue); switch (category) { case CK_CERTIFICATE_CATEGORY_UNSPECIFIED: printf("%*s%s: %s\n", indent, "", attr, "CK_CERTIFICATE_CATEGORY_UNSPECIFIED"); break; case CK_CERTIFICATE_CATEGORY_TOKEN_USER: printf("%*s%s: %s\n", indent, "", attr, "CK_CERTIFICATE_CATEGORY_TOKEN_USER"); break; case CK_CERTIFICATE_CATEGORY_AUTHORITY: printf("%*s%s: %s\n", indent, "", attr, "CK_CERTIFICATE_CATEGORY_AUTHORITY"); break; case CK_CERTIFICATE_CATEGORY_OTHER_ENTITY: printf("%*s%s: %s\n", indent, "", attr, "CK_CERTIFICATE_CATEGORY_OTHER_ENTITY"); break; default: printf("%*s%s: 0x%lX\n", indent, "", attr, *(CK_CERTIFICATE_CATEGORY *)(val->pValue)); break; } } void p11tool_print_dump(CK_BYTE *p, CK_ULONG len, int indent) { CK_ULONG i; for (i = 0; i < len; i++) { if (i % 16 == 0) printf("\n%*s%02X ", indent, "", p[i]); else printf("%02X ", p[i]); } printf("\n"); } void p11tool_print_byte_array_attr(const char *attr, const CK_ATTRIBUTE *val, int indent, bool sensitive) { if (val->ulValueLen == CK_UNAVAILABLE_INFORMATION && !sensitive) return; if (sensitive) { printf("%*s%s: [sensitive]\n", indent, "", attr); } else if (val->ulValueLen == 0) { printf("%*s%s: [no value]\n", indent, "", attr); } else { printf("%*s%s: len=%lu value:", indent, "", attr, val->ulValueLen); p11tool_print_dump((CK_BYTE *)val->pValue, val->ulValueLen, indent + 4); } } void p11tool_print_x509_name_attr(const char *attr, const CK_ATTRIBUTE *val, int indent, bool sensitive) { X509_NAME *name = NULL; const unsigned char *tmp_ptr; if (sensitive) { printf("%*s%s: [sensitive]\n", indent, "", attr); return; } else if (val->ulValueLen == 0) { printf("%*s%s: [no value]\n", indent, "", attr); return; } tmp_ptr = (const unsigned char *)val->pValue; name = d2i_X509_NAME(NULL, &tmp_ptr, val->ulValueLen); if (name != NULL) { char *oneline = X509_NAME_oneline(name, NULL, 0); if (oneline != NULL) { printf("%*s%s: %s\n", indent, "", attr, oneline); OPENSSL_free(oneline); } printf("%*s len=%lu value:", indent + 3, "", val->ulValueLen); p11tool_print_dump((CK_BYTE *)val->pValue, val->ulValueLen, indent + 4); } else { p11tool_print_byte_array_attr(attr, val, indent, false); } if (name != NULL) X509_NAME_free(name); } void p11tool_print_x509_attr(const char *attr, const CK_ATTRIBUTE *val, int indent, bool sensitive) { X509 *x509 = NULL; const unsigned char *tmp_ptr; char buf[256]; BIO *bio; if (sensitive) { printf("%*s%s: [sensitive]\n", indent, "", attr); return; } else if (val->ulValueLen == 0) { printf("%*s%s: [no value]\n", indent, "", attr); return; } bio = BIO_new(BIO_s_mem()); tmp_ptr = (const unsigned char *)val->pValue; x509 = d2i_X509(NULL, &tmp_ptr, val->ulValueLen); if (x509 != NULL) { printf("%*s%s: \n", indent, "", attr); if (bio != NULL) { X509_print(bio, x509); while (BIO_gets(bio, buf, sizeof(buf))) printf("%*s%s", indent + 4, "", buf); printf("%*s len=%lu value:", indent + 3, "", val->ulValueLen); } p11tool_print_dump((CK_BYTE *)val->pValue, val->ulValueLen, indent + 4); } else { p11tool_print_byte_array_attr(attr, val, indent, false); } if (bio != NULL) BIO_free(bio); if (x509 != NULL) X509_free(x509); } void p11tool_print_x509_serial_number_attr(const char *attr, const CK_ATTRIBUTE *val, int indent, bool sensitive) { ASN1_INTEGER *serialno = NULL; const unsigned char *tmp_ptr; BIGNUM *bn_serialno = NULL; CK_BYTE *serial_buf = NULL; CK_ULONG serial_len; if (sensitive) { printf("%*s%s: [sensitive]\n", indent, "", attr); return; } else if (val->ulValueLen == 0) { printf("%*s%s: [no value]\n", indent, "", attr); return; } tmp_ptr = (const unsigned char *)val->pValue; serialno = d2i_ASN1_INTEGER(NULL, &tmp_ptr, val->ulValueLen); if (serialno != NULL && (bn_serialno = ASN1_INTEGER_to_BN(serialno, NULL)) != NULL) { serial_len = BN_num_bytes(bn_serialno); serial_buf = OPENSSL_malloc(serial_len); if (serial_buf != NULL && BN_bn2bin(bn_serialno, serial_buf) == (int)serial_len) { printf("%*s%s: len=%lu value:", indent, "", attr, serial_len); p11tool_print_dump(serial_buf, serial_len, indent + 4); } else { p11tool_print_byte_array_attr(attr, val, indent, false); } } else { p11tool_print_byte_array_attr(attr, val, indent, false); } if (bn_serialno != NULL) BN_free(bn_serialno); if (serial_buf != NULL) OPENSSL_free(serial_buf); if (serialno != NULL) ASN1_INTEGER_free(serialno); } void p11tool_print_ulong_attr(const char *attr, const CK_ATTRIBUTE *val, int indent, bool sensitive) { if ((val->ulValueLen == CK_UNAVAILABLE_INFORMATION && !sensitive) || val->ulValueLen != sizeof(CK_ULONG)) return; if (sensitive) printf("%*s%s: [sensitive]\n", indent, "", attr); else printf("%*s%s: %lu (0x%lX)\n", indent, "", attr, *(CK_ULONG *)(val->pValue), *(CK_ULONG *)(val->pValue)); } void p11tool_print_date_attr(const char *attr, const CK_ATTRIBUTE *val, int indent, bool sensitive) { if ((val->ulValueLen == CK_UNAVAILABLE_INFORMATION && !sensitive) || val->ulValueLen != sizeof(CK_DATE)) return; if (sensitive) printf("%*s%s: [sensitive]\n", indent, "", attr); else printf("%*s%s: %.4s-%.2s-%.2s\n", indent, "", attr, ((CK_DATE *)(val->pValue))->year, ((CK_DATE *)(val->pValue))->month, ((CK_DATE *)(val->pValue))->day); } void p11tool_print_mech_attr(const char *attr, const CK_ATTRIBUTE *val, int indent, bool sensitive) { if ((val->ulValueLen == CK_UNAVAILABLE_INFORMATION && !sensitive) || val->ulValueLen != sizeof(CK_MECHANISM_TYPE)) return; if (sensitive) printf("%*s%s: [sensitive]\n", indent, "", attr); else if (*(CK_MECHANISM_TYPE *)(val->pValue) == CK_UNAVAILABLE_INFORMATION) printf("%*s%s: [information unavailable]\n", indent, "", attr); else printf("%*s%s: %s (0x%lX)\n", indent, "", attr, p11_get_ckm(&mechtable_funcs, *(CK_MECHANISM_TYPE *)(val->pValue)), *(CK_MECHANISM_TYPE *)(val->pValue)); } void p11tool_print_mech_array_attr(const char *attr, const CK_ATTRIBUTE *val, int indent, bool sensitive) { unsigned int i, num; if ((val->ulValueLen == CK_UNAVAILABLE_INFORMATION && !sensitive) || (val->ulValueLen % sizeof(CK_MECHANISM_TYPE)) != 0) return; if (sensitive) { printf("%*s%s: [sensitive]\n", indent, "", attr); } else { num = val->ulValueLen / sizeof(CK_MECHANISM_TYPE); if (num == 0 && val->type == CKA_ALLOWED_MECHANISMS) { printf("%*s%s: [no restriction]\n", indent, "", attr); return; } printf("%*s%s: %u mechanisms\n", indent, "", attr, num); for (i = 0; i < num; i++) { printf("%*s- %s (0x%lX)\n", indent + 4, "", p11_get_ckm(&mechtable_funcs, ((CK_MECHANISM_TYPE *)(val->pValue))[i]), ((CK_MECHANISM_TYPE *)(val->pValue))[i]); } } } void p11tool_print_oid(const CK_BYTE *oid, CK_ULONG oid_len, bool long_name) { ASN1_OBJECT *obj = NULL; char buf[250]; int nid; if (d2i_ASN1_OBJECT(&obj, &oid, oid_len) == NULL) { printf("[invalid object ID]"); return; } nid = OBJ_obj2nid(obj); if (OBJ_obj2txt(buf, sizeof(buf), obj, 1) <= 0) { printf("[error]"); ASN1_OBJECT_free(obj); return; } printf("oid=%s", buf); if (long_name && nid != NID_undef) printf(" (%s)", OBJ_nid2ln(nid)); ASN1_OBJECT_free(obj); } void p11tool_print_ibm_dilithium_keyform_attr(const char *attr, const CK_ATTRIBUTE *val, int indent, bool sensitive) { const struct p11tool_enum_value *eval; const char *name = "[unknown]"; if ((val->ulValueLen == CK_UNAVAILABLE_INFORMATION || val->ulValueLen != sizeof (CK_ULONG)) && !sensitive) return; if (sensitive) { printf("%*s%s: [sensitive]\n", indent, "", attr); } else if (val->ulValueLen == 0) { printf("%*s%s: [no value]\n", indent, "", attr); } else { for (eval = p11tool_ibm_dilithium_versions; eval->value != NULL; eval++) { if (eval->private.num == *(CK_ULONG *)(val->pValue)) { name = eval->value; break; } } printf("%*s%s: %s (0x%lX)\n", indent, "", attr, name, *(CK_ULONG *)(val->pValue)); } } void p11tool_print_ibm_kyber_keyform_attr(const char *attr, const CK_ATTRIBUTE *val, int indent, bool sensitive) { const struct p11tool_enum_value *eval; const char *name = "[unknown]"; if ((val->ulValueLen == CK_UNAVAILABLE_INFORMATION || val->ulValueLen != sizeof (CK_ULONG)) && !sensitive) return; if (sensitive) { printf("%*s%s: [sensitive]\n", indent, "", attr); } else if (val->ulValueLen == 0) { printf("%*s%s: [no value]\n", indent, "", attr); } else { for (eval = p11tool_ibm_kyber_versions; eval->value != NULL; eval++) { if (eval->private.num == *(CK_ULONG *)(val->pValue)) { name = eval->value; break; } } printf("%*s%s: %s (0x%lX)\n", indent, "", attr, name, *(CK_ULONG *)(val->pValue)); } } void p11tool_print_ibm_ml_dsa_parameter_set_attr(const char *attr, const CK_ATTRIBUTE *val, int indent, bool sensitive) { const struct p11tool_enum_value *eval; const char *name = "[unknown]"; if ((val->ulValueLen == CK_UNAVAILABLE_INFORMATION || val->ulValueLen != sizeof (CK_ULONG)) && !sensitive) return; if (sensitive) { printf("%*s%s: [sensitive]\n", indent, "", attr); } else if (val->ulValueLen == 0) { printf("%*s%s: [no value]\n", indent, "", attr); } else { for (eval = p11tool_ibm_ml_dsa_versions; eval->value != NULL; eval++) { if (eval->private.num == *(CK_ULONG *)(val->pValue)) { name = eval->value; break; } } printf("%*s%s: ML-DSA-%s (0x%lX)\n", indent, "", attr, name, *(CK_ULONG *)(val->pValue)); } } void p11tool_print_ibm_ml_kem_parameter_set_attr(const char *attr, const CK_ATTRIBUTE *val, int indent, bool sensitive) { const struct p11tool_enum_value *eval; const char *name = "[unknown]"; if ((val->ulValueLen == CK_UNAVAILABLE_INFORMATION || val->ulValueLen != sizeof (CK_ULONG)) && !sensitive) return; if (sensitive) { printf("%*s%s: [sensitive]\n", indent, "", attr); } else if (val->ulValueLen == 0) { printf("%*s%s: [no value]\n", indent, "", attr); } else { for (eval = p11tool_ibm_ml_kem_versions; eval->value != NULL; eval++) { if (eval->private.num == *(CK_ULONG *)(val->pValue)) { name = eval->value; break; } } printf("%*s%s: ML-KEM-%s (0x%lX)\n", indent, "", attr, name, *(CK_ULONG *)(val->pValue)); } } void p11tool_print_class_attr(const char *attr, const CK_ATTRIBUTE *val, int indent, bool sensitive) { const struct p11tool_class *cls; const char *name = NULL; if ((val->ulValueLen == CK_UNAVAILABLE_INFORMATION && !sensitive) || val->ulValueLen != sizeof(CK_OBJECT_CLASS)) return; if (sensitive) { printf("%*s%s: [sensitive]\n", indent, "", attr); return; } for (cls = p11tool_classes; cls->name != NULL; cls++) { if (*(CK_OBJECT_CLASS *)(val->pValue) == cls->class) { name = cls->name; break; } } if (name != NULL) printf("%*s%s: %s (0x%lX)\n", indent, "", attr, name, *(CK_OBJECT_CLASS *)(val->pValue)); else printf("%*s%s: 0x%lX\n", indent, "", attr, *(CK_OBJECT_CLASS *)(val->pValue)); } int p11tool_openssl_err_cb(const char *str, size_t len, void *u) { UNUSED(u); if (str[len - 1] == '\n') len--; warnx("OpenSSL error: %.*s", (int)len, str); return 1; } void p11tool_print_oid_attr(const char *attr, const CK_ATTRIBUTE *val, int indent, bool sensitive) { if (val->ulValueLen == CK_UNAVAILABLE_INFORMATION && !sensitive) return; if (sensitive) { printf("%*s%s: [sensitive]\n", indent, "", attr); } else if (val->ulValueLen == 0) { printf("%*s%s: [no value]\n", indent, "", attr); } else { printf("%*s%s: ", indent, "", attr); p11tool_print_oid(val->pValue, val->ulValueLen, true); printf(" len=%lu value:", val->ulValueLen); p11tool_print_dump((CK_BYTE *)val->pValue,val->ulValueLen, indent + 4); } } void p11tool_free_attributes(CK_ATTRIBUTE *attrs, CK_ULONG num_attrs) { CK_ULONG i; if (attrs == NULL) return; for (i = 0; i < num_attrs; i++) { if (attrs[i].pValue != NULL) { OPENSSL_cleanse(attrs[i].pValue, attrs[i].ulValueLen); free(attrs[i].pValue); } } free(attrs); } bool p11tool_is_attr_array_attr(CK_ATTRIBUTE *attr) { switch (attr->type) { case CKA_WRAP_TEMPLATE: case CKA_UNWRAP_TEMPLATE: case CKA_DERIVE_TEMPLATE: case CKA_ENCAPSULATE_TEMPLATE: case CKA_DECAPSULATE_TEMPLATE: return true; default: return false; } } void p11tool_free_attr_array_attr(CK_ATTRIBUTE *attr) { CK_ULONG i, num; CK_ATTRIBUTE *elem; num = attr->ulValueLen / sizeof(CK_ATTRIBUTE); for (i = 0, elem = attr->pValue; elem != NULL && i < num; i++, elem++) { if (elem->pValue != NULL) { if (p11tool_is_attr_array_attr(elem)) p11tool_free_attr_array_attr(elem); free(elem->pValue); elem->pValue = NULL; } } } CK_RV p11tool_alloc_attr_array_attr(CK_ATTRIBUTE *attr, bool *allocated) { CK_ULONG i, num; CK_ATTRIBUTE *elem; CK_RV rc; *allocated = false; num = attr->ulValueLen / sizeof(CK_ATTRIBUTE); for (i = 0, elem = attr->pValue; i < num; i++, elem++) { if (elem->ulValueLen > 0 && elem->pValue == NULL) { elem->pValue = calloc(elem->ulValueLen, 1); if (elem->pValue == NULL) { p11tool_free_attr_array_attr(attr); return CKR_HOST_MEMORY; } *allocated = true; continue; } if (p11tool_is_attr_array_attr(elem)) { rc = p11tool_alloc_attr_array_attr(elem, allocated); if (rc != CKR_OK) { p11tool_free_attr_array_attr(attr); return CKR_HOST_MEMORY; } } } return CKR_OK; } CK_RV p11tool_add_attribute(CK_ATTRIBUTE_TYPE type, const void *value, CK_ULONG value_len, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs) { CK_ATTRIBUTE *tmp; tmp = realloc(*attrs, (*num_attrs + 1) * sizeof(CK_ATTRIBUTE)); if (tmp == NULL) { warnx("Failed to allocate memory for attribute list"); return CKR_HOST_MEMORY; } *attrs = tmp; tmp[*num_attrs].type = type; tmp[*num_attrs].ulValueLen = value_len; tmp[*num_attrs].pValue = NULL; if (value_len != 0) { tmp[*num_attrs].pValue = malloc(value_len); if (tmp[*num_attrs].pValue == NULL) { warnx("Failed to allocate memory attribute to add to list"); return CKR_HOST_MEMORY; } memcpy(tmp[*num_attrs].pValue, value, value_len); } (*num_attrs)++; return CKR_OK; } CK_RV p11tool_add_bignum_attr(CK_ATTRIBUTE_TYPE type, const BIGNUM* bn, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs) { int len; CK_BYTE *buff = NULL; CK_RV rc; len = BN_num_bytes(bn); buff = calloc(len, 1); if (buff == NULL || len == 0) { warnx("Failed to allocate a buffer for a bignum"); if (buff != NULL) free(buff); return CKR_HOST_MEMORY; } if (BN_bn2bin(bn, buff) != len) { warnx("Failed to get a bignum."); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); free(buff); return CKR_FUNCTION_FAILED; } rc = p11tool_add_attribute(type, buff, len, attrs, num_attrs); free(buff); return rc; } CK_RV p11tool_add_attributes(const struct p11tool_objtype *objtype, const struct p11tool_attr *bool_attrs, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, const char *label, const char *attr_string, const char *id, bool is_sensitive, bool so, CK_RV (*add_attrs)( const struct p11tool_objtype *objtype, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, void *private), void *private, bool (*attr_applicable)( const struct p11tool_objtype *objtype, const struct p11tool_attr *attr)) { const CK_BBOOL ck_true = TRUE; bool found; CK_ULONG i; CK_RV rc; rc = p11tool_add_attribute(CKA_LABEL, label, strlen(label), attrs, num_attrs); if (rc != CKR_OK) { warnx("Failed to add %s key attribute CKA_LABEL: 0x%lX: %s", objtype->name, rc, p11_get_ckr(rc)); return rc; } rc = p11tool_add_attribute(CKA_TOKEN, &ck_true, sizeof(ck_true), attrs, num_attrs); if (rc != CKR_OK) { warnx("Failed to add %s key attribute CKA_TOKEN: 0x%lX: %s", objtype->name, rc, p11_get_ckr(rc)); return rc; } rc = p11tool_parse_boolean_attrs(objtype, bool_attrs, attr_string, attrs, num_attrs, true, so, attr_applicable); if (rc != CKR_OK) return rc; if (id != NULL) { rc = p11tool_parse_id(id, attrs, num_attrs); if (rc != CKR_OK) return rc; } if (add_attrs != NULL) { rc = add_attrs(objtype, attrs, num_attrs, private); if (rc != CKR_OK) { warnx("Failed to add %s key attributes: 0x%lX: %s", objtype->name, rc, p11_get_ckr(rc)); return rc; } } if (is_sensitive) { /* Add CKA_SENSITIVE=TRUE if its not already in attribute list */ for (i = 0, found = false; i < *num_attrs && !found; i++) { if ((*attrs)[i].type == CKA_SENSITIVE) found = true; } if (!found) { rc = p11tool_add_attribute(CKA_SENSITIVE, &ck_true, sizeof(ck_true), attrs, num_attrs); if (rc != CKR_OK) { warnx("Failed to add %s key attribute CKA_SENSITIVE: 0x%lX: %s", objtype->name, rc, p11_get_ckr(rc)); return rc; } } } return CKR_OK; } CK_RV p11tool_parse_hex(const char *id_string, CK_BYTE **buf, CK_ULONG *buflen) { CK_RV rc = CKR_OK; BIGNUM *b = NULL; int len; *buflen = 0; *buf = NULL; len = BN_hex2bn(&b, id_string); if (len < (int)strlen(id_string) || len == 0 || b == NULL) { warnx("Hex string '%s' is not valid", id_string); rc = CKR_ARGUMENTS_BAD; goto done; } len = len / 2 + (len % 2 > 0 ? 1 : 0); *buf = calloc(1, len); if (*buf == NULL) { warnx("Failed to allocate memory for buffer"); rc = CKR_HOST_MEMORY; goto done; } if (BN_bn2binpad(b, *buf, len) != len) { warnx("Failed to prepare the value for CKA_ID attribute"); rc = CKR_FUNCTION_FAILED; goto done; } *buflen = len; done: if (rc != CKR_OK && *buf != NULL) { free(*buf); *buf = NULL; } if (b != NULL) BN_free(b); return rc; } CK_RV p11tool_parse_id(const char *id_string, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs) { CK_BYTE *buf = NULL; CK_ULONG len; CK_RV rc; rc = p11tool_parse_hex(id_string, &buf, &len); if (rc != CKR_OK) return rc; rc = p11tool_add_attribute(CKA_ID, buf, len, attrs, num_attrs); if (rc != CKR_OK) { warnx("Failed to add attribute CKA_ID: 0x%lX: %s", rc, p11_get_ckr(rc)); goto done; } done: if (buf != NULL) free(buf); return rc; } const struct p11tool_attr *p11tool_find_attr_by_letter( const struct p11tool_attr *bool_attrs, char letter) { const struct p11tool_attr *attr; for (attr = bool_attrs; attr->name != NULL; attr++) { if (attr->letter == toupper(letter)) return attr; } return NULL; } CK_RV p11tool_parse_boolean_attrs(const struct p11tool_objtype *objtype, const struct p11tool_attr *bool_attrs, const char *attr_string, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, bool check_settable, bool so, bool (*attr_applicable)( const struct p11tool_objtype *objtype, const struct p11tool_attr *attr)) { const struct p11tool_attr *attr; unsigned int i = 0; CK_BBOOL val; CK_RV rc; if (attr_string == NULL) return CKR_OK; for (i = 0; attr_string[i] != '\0'; i++) { attr = p11tool_find_attr_by_letter(bool_attrs, attr_string[i]); if (attr == NULL) { warnx("Attribute '%c' is not valid", attr_string[i]); return CKR_ARGUMENTS_BAD; } /* silently ignore attributes that are not settable or not applicable */ if ((check_settable && !attr->settable) || (attr_applicable != NULL && objtype != NULL && !attr_applicable(objtype, attr))) continue; val = isupper(attr_string[i]) ? CK_TRUE : CK_FALSE; if (check_settable && attr->so_set_to_true && val == CK_TRUE && !so) { warnx("Attribute %s ('%c') can only be set to TRUE by SO", attr->name, attr->letter); return CKR_ARGUMENTS_BAD; } rc = p11tool_add_attribute(attr->type, &val, sizeof(val), attrs, num_attrs); if (rc != CKR_OK) return rc; } return CKR_OK; } CK_RV p11tool_get_attribute(CK_OBJECT_HANDLE key, CK_ATTRIBUTE *attr) { bool allocated; CK_RV rc; rc = p11tool_pkcs11_funcs->C_GetAttributeValue(p11tool_pkcs11_session, key, attr, 1); if (rc != CKR_OK) return rc; if (attr->pValue == NULL && attr->ulValueLen > 0) { attr->pValue = calloc(attr->ulValueLen, 1); if (attr->pValue == NULL) return CKR_HOST_MEMORY; rc = p11tool_pkcs11_funcs->C_GetAttributeValue(p11tool_pkcs11_session, key, attr, 1); } if (p11tool_is_attr_array_attr(attr) && rc == CKR_OK && attr->pValue != NULL && attr->ulValueLen > 0) { do { allocated = false; rc = p11tool_alloc_attr_array_attr(attr, &allocated); if (rc != CKR_OK) return rc; if (!allocated) break; rc = p11tool_pkcs11_funcs->C_GetAttributeValue( p11tool_pkcs11_session, key, attr, 1); } while (rc == CKR_OK); } return rc; } CK_RV p11tool_get_bignum_attr(CK_OBJECT_HANDLE key, CK_ATTRIBUTE_TYPE type, BIGNUM **bn) { CK_ATTRIBUTE attr; CK_RV rc; attr.type = type; attr.pValue = NULL; attr.ulValueLen = 0; if (p11tool_is_attr_array_attr(&attr)) return CKR_ATTRIBUTE_TYPE_INVALID; rc = p11tool_get_attribute(key, &attr); if (rc != CKR_OK) return rc; if (attr.ulValueLen == 0 || attr.pValue == NULL) return CKR_ATTRIBUTE_VALUE_INVALID; /* Caller may supply an already allocated BIGNUM, allocate if NULL. */ if (*bn == NULL) { *bn = BN_new(); if (*bn == NULL) { rc = CKR_HOST_MEMORY; goto done; } } if (BN_bin2bn((unsigned char *)attr.pValue, attr.ulValueLen, *bn) == NULL) { rc = CKR_FUNCTION_FAILED; BN_free(*bn); *bn = NULL; goto done; } done: OPENSSL_cleanse(attr.pValue, attr.ulValueLen); free(attr.pValue); return rc; } CK_RV p11tool_get_common_name_value(CK_OBJECT_HANDLE obj, char *label, char **common_name_value) { CK_ATTRIBUTE attr = { CKA_VALUE, NULL, 0 }; X509 *x509 = NULL; const CK_BYTE *tmp_ptr; char *subj = NULL, *cn_tmp, *cn_tmp2 = NULL; CK_RV rc; rc = p11tool_get_attribute(obj, &attr); if (rc != CKR_OK) { warnx("Failed to retrieve attribute CKA_VALUE from object " "\"%s\": 0x%lX: %s", label, rc, p11_get_ckr(rc)); return rc; } if (attr.ulValueLen == 0 || attr.ulValueLen == CK_UNAVAILABLE_INFORMATION) { *common_name_value = strdup("[not available]"); if (*common_name_value == NULL) { warnx("Failed to allocate memory for common_name_value " "for object \"%s\"", label); return CKR_HOST_MEMORY; } return CKR_OK; } tmp_ptr = attr.pValue; x509 = d2i_X509(NULL, &tmp_ptr, attr.ulValueLen); if (x509 == NULL) { *common_name_value = strdup("[not available]"); if (*common_name_value == NULL) { warnx("Failed to allocate memory for common_name_value " "for object \"%s\"", label); rc = CKR_HOST_MEMORY; } else { rc = CKR_OK; } goto done; } subj = X509_NAME_oneline(X509_get_subject_name(x509), NULL, 0); if (subj == NULL) { *common_name_value = strdup("[not available]"); if (*common_name_value == NULL) { warnx("Failed to allocate memory for common_name_value " "for object \"%s\"", label); rc = CKR_HOST_MEMORY; } else { rc = CKR_OK; } goto done; } *common_name_value = strdup(subj); if (*common_name_value == NULL) { warnx("Failed to allocate memory for common_name attribute" "for object \"%s\"", label); rc = CKR_HOST_MEMORY; goto done; } cn_tmp = strstr(subj, "/CN="); if (cn_tmp != NULL) { cn_tmp2 = *common_name_value; *common_name_value = strdup(cn_tmp + 4); if (*common_name_value == NULL) { warnx("Failed to allocate memory for common_name attribute" "for object \"%s\"", label); rc = CKR_HOST_MEMORY; goto done; } } rc = CKR_OK; done: free(attr.pValue); if (subj != NULL) OPENSSL_free(subj); if (x509 != NULL) X509_free(x509); if (cn_tmp2 != NULL) free(cn_tmp2); return rc; } CK_RV p11tool_get_keysize_value(CK_OBJECT_HANDLE obj, char *label, const struct p11tool_objtype *objtype_val, CK_ULONG *keysize_val) { CK_ATTRIBUTE keysize_attr; CK_RV rc; if (objtype_val->keysize_attr == (CK_ATTRIBUTE_TYPE)-1) { *keysize_val = 0; return CKR_OK; } keysize_attr.type = objtype_val->keysize_attr; if (!objtype_val->keysize_attr_value_len) { keysize_attr.ulValueLen = sizeof(*keysize_val); keysize_attr.pValue = keysize_val; } else { /* Query attribute length only */ keysize_attr.ulValueLen = 0; keysize_attr.pValue = NULL; } rc = p11tool_pkcs11_funcs->C_GetAttributeValue(p11tool_pkcs11_session, obj, &keysize_attr, 1); if (rc != CKR_OK) { warnx("Attribute %s is not available in object \"%s\"", p11_get_cka(keysize_attr.type), label); return rc; } if (objtype_val->keysize_attr_value_len) *keysize_val = keysize_attr.ulValueLen; if (objtype_val->key_keysize_adjust != NULL) *keysize_val = objtype_val->key_keysize_adjust(objtype_val, *keysize_val); return CKR_OK; } CK_RV p11tool_get_typestr_value(CK_OBJECT_CLASS class_val, CK_ULONG keysize_val, const struct p11tool_objtype *objtype_val, char *label, char **typestr) { int rv; switch (class_val) { case CKO_SECRET_KEY: if (keysize_val != 0) rv = asprintf(typestr, "%s %lu", objtype_val->name, keysize_val); else rv = asprintf(typestr, "%s", objtype_val->name); break; case CKO_PUBLIC_KEY: if (keysize_val != 0) rv = asprintf(typestr, "public %s %lu", objtype_val->name, keysize_val); else rv = asprintf(typestr, "public %s", objtype_val->name); break; case CKO_PRIVATE_KEY: if (keysize_val != 0) rv = asprintf(typestr, "private %s %lu", objtype_val->name, keysize_val); else rv = asprintf(typestr, "private %s", objtype_val->name); break; case CKO_CERTIFICATE: rv = asprintf(typestr, "%s", objtype_val->name); break; default: warnx("%s object \"%s\" has an unsupported %s class: %lu", objtype_val->obj_liststr, label, objtype_val->obj_typestr, class_val); return CKR_KEY_TYPE_INCONSISTENT; } if (*typestr == NULL || rv < 0) { warnx("Failed to allocate type string buffer"); return CKR_HOST_MEMORY; } return CKR_OK; } CK_RV p11tool_get_class_and_type_values(CK_OBJECT_HANDLE obj, char *label, CK_OBJECT_CLASS *class_val, CK_ULONG *otype_val) { CK_RV rc; CK_KEY_TYPE ktype_val = 0; CK_CERTIFICATE_TYPE ctype_val = 0; CK_ATTRIBUTE attrs[] = { { CKA_CLASS, class_val, sizeof(class_val) }, { CKA_KEY_TYPE, &ktype_val, sizeof(ktype_val) }, { CKA_CERTIFICATE_TYPE, &ctype_val, sizeof(ctype_val) }, }; const CK_ULONG num_attrs = sizeof(attrs) / sizeof(CK_ATTRIBUTE); rc = p11tool_pkcs11_funcs->C_GetAttributeValue(p11tool_pkcs11_session, obj, attrs, num_attrs); if (rc != CKR_OK && rc != CKR_ATTRIBUTE_TYPE_INVALID && rc != CKR_ATTRIBUTE_SENSITIVE) { warnx("Failed to get attributes: C_GetAttributeValue: 0x%lX: %s", rc, p11_get_ckr(rc)); return rc; } /* Class attribute must be available in any case. Others depend on object type: key or certificate */ if (attrs[0].ulValueLen == CK_UNAVAILABLE_INFORMATION) { warnx("Class attribute %s is not available in object \"%s\"", p11_get_cka(attrs[0].type), label); return CKR_TEMPLATE_INCOMPLETE; } if (attrs[1].ulValueLen != CK_UNAVAILABLE_INFORMATION) *otype_val = ktype_val; else if (attrs[2].ulValueLen != CK_UNAVAILABLE_INFORMATION) *otype_val = ctype_val; else { warnx("At least one of CKA_KEY_TYPE or CKA_CERTIFICATE_TYPE must " "be available in object \"%s\"", label); return CKR_TEMPLATE_INCOMPLETE; } return CKR_OK; } CK_RV p11tool_get_label_value(CK_OBJECT_HANDLE obj, char** label_value) { CK_ATTRIBUTE attr = { CKA_LABEL, NULL, 0 }; CK_RV rv; if (label_value == NULL) return CKR_ARGUMENTS_BAD; rv = p11tool_pkcs11_funcs->C_GetAttributeValue(p11tool_pkcs11_session, obj, &attr, 1); if (rv != CKR_OK && rv != CKR_ATTRIBUTE_TYPE_INVALID && rv != CKR_ATTRIBUTE_SENSITIVE) { warnx("Failed to get CKA_LABEL attribute (length only): " "C_GetAttributeValue: 0x%lX: %s", rv, p11_get_ckr(rv)); return rv; } if (attr.ulValueLen == 0 || attr.ulValueLen == CK_UNAVAILABLE_INFORMATION) { attr.pValue = strdup(""); if (attr.pValue == NULL) { warnx("Failed to allocate memory for label attribute"); return CKR_HOST_MEMORY; } else { goto done; } } attr.pValue = calloc(attr.ulValueLen + 1, 1); if (attr.pValue == NULL) { warnx("Failed to allocate memory for label attribute"); return CKR_HOST_MEMORY; } rv = p11tool_pkcs11_funcs->C_GetAttributeValue(p11tool_pkcs11_session, obj, &attr, 1); if (rv != CKR_OK) { warnx("Failed to get CKA_LABEL attribute: C_GetAttributeValue: 0x%lX: %s", rv, p11_get_ckr(rv)); free(attr.pValue); return rv; } done: *label_value = attr.pValue; return CKR_OK; } CK_BBOOL p11tool_objclass_expected(CK_OBJECT_HANDLE obj, enum p11tool_objclass objclass) { CK_OBJECT_CLASS class_val = 0; CK_ATTRIBUTE attr = { CKA_CLASS, &class_val, sizeof(class_val) }; CK_RV rv; rv = p11tool_get_attribute(obj, &attr); if (rv != CKR_OK) { warnx("Failed to get CKA_CLASS attribute: p11tool_get_attribute: 0x%lX: %s", rv, p11_get_ckr(rv)); return rv; } switch (objclass) { case OBJCLASS_KEY: if (class_val == CKO_SECRET_KEY || class_val == CKO_PUBLIC_KEY || class_val == CKO_PRIVATE_KEY) return CK_TRUE; break; case OBJCLASS_CERTIFICATE: if (class_val == CKO_CERTIFICATE) return CK_TRUE; break; default: break; } return CK_FALSE; } bool p11tool_attr_applicable_for_certtype( const struct p11tool_objtype *certtype, const struct p11tool_attr *attr) { UNUSED(certtype); switch (attr->type) { case CKA_PRIVATE: case CKA_MODIFIABLE: case CKA_COPYABLE: case CKA_DESTROYABLE: case CKA_TRUSTED: return true; default: break; } return false; } bool p11tool_attr_applicable_for_keytype(const struct p11tool_objtype *keytype, const struct p11tool_attr *attr) { switch (attr->type) { case CKA_SIGN: case CKA_SIGN_RECOVER: case CKA_VERIFY: case CKA_VERIFY_RECOVER: return keytype->sign_verify; case CKA_ENCRYPT: case CKA_DECRYPT: return keytype->encrypt_decrypt; case CKA_WRAP: case CKA_WRAP_WITH_TRUSTED: case CKA_UNWRAP: return keytype->wrap_unwrap; case CKA_DERIVE: return keytype->derive; case CKA_ENCAPSULATE: case CKA_DECAPSULATE: return keytype->encaps_decaps; default: return true; } } bool p11tool_cert_attr_applicable(const struct p11tool_objtype *certtype, const struct p11tool_attr *attr) { return p11tool_attr_applicable_for_certtype(certtype, attr); } bool p11tool_secret_attr_applicable(const struct p11tool_objtype *objtype, const struct p11tool_attr *attr) { return attr->secret && p11tool_attr_applicable_for_keytype(objtype, attr); } bool p11tool_public_attr_applicable(const struct p11tool_objtype *objtype, const struct p11tool_attr *attr) { return attr->public && p11tool_attr_applicable_for_keytype(objtype, attr); } bool p11tool_private_attr_applicable(const struct p11tool_objtype *objtype, const struct p11tool_attr *attr) { return attr->private && p11tool_attr_applicable_for_keytype(objtype, attr); } static const struct p11tool_token_info *p11tool_find_known_token( const CK_TOKEN_INFO *info, const struct p11tool_token_info *known_tokens) { unsigned int i; char manufacturer[sizeof(info->manufacturerID) + 1] = { 0 }; char model[sizeof(info->model) + 1] = { 0 }; char *ch; if (known_tokens == NULL) return NULL; memcpy(manufacturer, info->manufacturerID, sizeof(info->manufacturerID)); ch = strchr(manufacturer, ' '); if (ch != NULL) *ch = '\0'; memcpy(model, info->model, sizeof(info->model)); ch = strchr(model, ' '); if (ch != NULL) *ch = '\0'; for (i = 0; known_tokens[i].type != TOKTYPE_UNKNOWN; i++) { if (strcmp(manufacturer, known_tokens[i].manufacturer) == 0 && strcmp(model, known_tokens[i].model) == 0) return &known_tokens[i]; } return NULL; } static CK_RV p11tool_load_pkcs11_lib(void) { CK_RV rc; CK_RV (*getfunclist)(CK_FUNCTION_LIST_PTR_PTR ppFunctionList); const char *libname; libname = secure_getenv(P11TOOL_PKCSLIB_ENV_NAME); if (libname == NULL || strlen(libname) < 1) libname = P11TOOL_DEFAULT_PKCS11_LIB; p11tool_pkcs11_lib = dlopen(libname, DYNLIB_LDFLAGS); if (p11tool_pkcs11_lib == NULL) { warnx("Failed to load PKCS#11 library '%s': %s", libname, dlerror()); return CKR_FUNCTION_FAILED; } *(void**) (&getfunclist) = dlsym(p11tool_pkcs11_lib, "C_GetFunctionList"); if (getfunclist == NULL) { warnx("Failed to resolve symbol '%s' from PKCS#11 library '%s': %s", "C_GetFunctionList", libname, dlerror()); return CKR_FUNCTION_FAILED; } rc = getfunclist(&p11tool_pkcs11_funcs); if (rc != CKR_OK) { warnx("C_GetFunctionList() on PKCS#11 library '%s' failed with 0x%lX: " "%s)\n", libname, rc, p11_get_ckr(rc)); return CKR_FUNCTION_FAILED; } if (p11tool_pkcs11_funcs == NULL) { warnx("C_GetFunctionList() on PKCS#11 library '%s' failed\n", libname); return CKR_FUNCTION_FAILED; } return CKR_OK; } static CK_RV p11tool_open_pkcs11_session(CK_SLOT_ID slot, CK_FLAGS flags, const char *pin, CK_USER_TYPE user_type, const struct p11tool_token_info *known_tokens) { CK_RV rc; rc = p11tool_pkcs11_funcs->C_GetInfo(&p11tool_pkcs11_info); if (rc != CKR_OK) { warnx("Failed to getPKCS#11 info: C_GetInfo: 0x%lX: %s", rc, p11_get_ckr(rc)); return rc; } rc = p11tool_pkcs11_funcs->C_GetSlotInfo(slot, &p11tool_pkcs11_slotinfo); if (rc != CKR_OK) { warnx("Slot %lu is not available: C_GetSlotInfo: 0x%lX: %s", slot, rc, p11_get_ckr(rc)); return rc; } rc = p11tool_pkcs11_funcs->C_GetTokenInfo(slot, &p11tool_pkcs11_tokeninfo); if (rc != CKR_OK) { warnx("Token at slot %lu is not available: C_GetTokenInfo: 0x%lX: %s", slot, rc, p11_get_ckr(rc)); return rc; } p11tool_token_info = p11tool_find_known_token(&p11tool_pkcs11_tokeninfo, known_tokens); rc = p11tool_pkcs11_funcs->C_OpenSession(slot, flags, NULL, NULL, &p11tool_pkcs11_session); if (rc != CKR_OK) { warnx("Opening a session failed: C_OpenSession: 0x%lX: %s)", rc, p11_get_ckr(rc)); return rc; } if (pin != NULL) { rc = p11tool_pkcs11_funcs->C_Login(p11tool_pkcs11_session, user_type, (CK_CHAR *)pin, strlen(pin)); if (rc != CKR_OK && rc != CKR_USER_ALREADY_LOGGED_IN) { warnx("Login failed: C_Login: 0x%lX: %s", rc, p11_get_ckr(rc)); return rc; } } return CKR_OK; } static void p11tool_close_pkcs11_session(void) { CK_RV rc; rc = p11tool_pkcs11_funcs->C_Logout(p11tool_pkcs11_session); if (rc != CKR_OK && rc != CKR_USER_NOT_LOGGED_IN) warnx("C_Logout failed: 0x%lX: %s", rc, p11_get_ckr(rc)); rc = p11tool_pkcs11_funcs->C_CloseSession(p11tool_pkcs11_session); if (rc != CKR_OK) warnx("C_CloseSession failed: 0x%lX: %s", rc, p11_get_ckr(rc)); p11tool_pkcs11_session = CK_INVALID_HANDLE; } CK_RV p11tool_init_pkcs11(const struct p11tool_cmd *command, bool no_login, const char *pin, bool force_pin_prompt, bool so, bool remember_pin, CK_SLOT_ID slot, const struct p11tool_token_info *known_tokens) { CK_RV rc; char *buf_user_pin = NULL; if (command == NULL || command->session_flags == 0) return CKR_OK; if (no_login) { if (pin != NULL) { warnx("Option '-p'/'--pin' is not allowed with '-N'/'--no-login'"); return CKR_ARGUMENTS_BAD; } if (force_pin_prompt) { warnx("Option '--force-pin-prompt' is not allowed with " "'-N'/'--no-login'"); return CKR_ARGUMENTS_BAD; } if (so) { warnx("Option '--so' is not allowed with '-N'/'--no-login'"); return CKR_ARGUMENTS_BAD; } pin = NULL; } else { if (pin == NULL) pin = getenv(so ? PKCS11_SO_PIN_ENV_NAME : PKCS11_USER_PIN_ENV_NAME); if (force_pin_prompt || pin == NULL) pin = pin_prompt(&buf_user_pin, so ? "Please enter SO PIN: " : "Please enter user PIN: "); if (pin == NULL) return CKR_FUNCTION_FAILED; } if (!so && !no_login && remember_pin) { p11tool_pin = strdup(pin); if (p11tool_pin == NULL) { rc = CKR_HOST_MEMORY; goto done; } } rc = p11tool_load_pkcs11_lib(); if (rc != CKR_OK) goto done; rc = p11tool_pkcs11_funcs->C_Initialize(NULL); if (rc != CKR_OK && rc != CKR_CRYPTOKI_ALREADY_INITIALIZED) { warnx("C_Initialize failed: 0x%lX: %s", rc, p11_get_ckr(rc)); goto done; } p11tool_pkcs11_initialized = true; rc = p11tool_open_pkcs11_session(slot, command->session_flags | (so ? CKF_RW_SESSION : 0), pin, so ? CKU_SO : CKU_USER, known_tokens); if (rc != CKR_OK) goto done; done: pin_free(&buf_user_pin); return rc; } void p11tool_term_pkcs11(void) { CK_RV rc; if (p11tool_pkcs11_session != CK_INVALID_HANDLE) p11tool_close_pkcs11_session(); if (p11tool_pkcs11_funcs != NULL && p11tool_pkcs11_initialized) { rc = p11tool_pkcs11_funcs->C_Finalize(NULL); if (rc != CKR_OK) warnx("C_Finalize failed: 0x%lX: %s", rc, p11_get_ckr(rc)); } #ifndef WITH_SANITIZER if (p11tool_pkcs11_lib != NULL) dlclose(p11tool_pkcs11_lib); #endif p11tool_pkcs11_lib = NULL; p11tool_pkcs11_funcs = NULL; if (p11tool_pin != NULL) { OPENSSL_cleanse(p11tool_pin, strlen(p11tool_pin)); free(p11tool_pin); } } bool p11tool_is_rejected_by_policy(CK_RV ret_code, CK_SESSION_HANDLE session) { CK_SESSION_INFO info; CK_RV rc; if (ret_code != CKR_FUNCTION_FAILED) return false; rc = p11tool_pkcs11_funcs->C_GetSessionInfo(session, &info); if (rc != CKR_OK) { warnx("C_GetSessionInfo failed: 0x%lX: %s", rc, p11_get_ckr(rc)); return false; } return (info.ulDeviceError == CKR_POLICY_VIOLATION); } CK_RV p11tool_check_wrap_mech_supported(CK_SLOT_ID slot, CK_MECHANISM_TYPE mechanism, CK_BBOOL wrap, CK_BBOOL unwrap) { CK_MECHANISM_INFO mech_info; CK_RV rc; rc = p11tool_pkcs11_funcs->C_GetMechanismInfo(slot, mechanism, &mech_info); if (rc != CKR_OK) { warnx("Token in slot %lu does not support mechanism %s", slot, p11_get_ckm(&mechtable_funcs, mechanism)); return rc; } if (wrap && (mech_info.flags & CKF_WRAP) == 0) { warnx("Mechanism %s does not support to wrap keys", p11_get_ckm(&mechtable_funcs, mechanism)); return CKR_MECHANISM_INVALID; } if (unwrap && (mech_info.flags & CKF_UNWRAP) == 0) { warnx("Mechanism %s does not support to unwrap keys", p11_get_ckm(&mechtable_funcs, mechanism)); return CKR_MECHANISM_INVALID; } return CKR_OK; } CK_RV p11tool_check_keygen_mech_supported(CK_SLOT_ID slot, CK_MECHANISM_TYPE mechanism, bool is_asymmetric, CK_ULONG keysize) { CK_MECHANISM_INFO mech_info; CK_RV rc; rc = p11tool_pkcs11_funcs->C_GetMechanismInfo(slot, mechanism, &mech_info); if (rc != CKR_OK) { warnx("Token in slot %lu does not support mechanism %s", slot, p11_get_ckm(&mechtable_funcs, mechanism)); return rc; } if ((mech_info.flags & (is_asymmetric ? CKF_GENERATE_KEY_PAIR : CKF_GENERATE)) == 0) { warnx("Mechanism %s does not support to generate keys", p11_get_ckm(&mechtable_funcs, mechanism)); return CKR_MECHANISM_INVALID; } if (keysize != 0 && mech_info.ulMinKeySize != 0 && mech_info.ulMaxKeySize != 0) { if (keysize < mech_info.ulMinKeySize || keysize > mech_info.ulMaxKeySize) { warnx("Mechanism %s does not support to generate keys of size %lu", p11_get_ckm(&mechtable_funcs, mechanism), keysize); return CKR_KEY_SIZE_RANGE; } } return CKR_OK; } CK_RV p11tool_check_pub_from_priv_mech_supported(CK_SLOT_ID slot) { CK_MECHANISM_INFO mech_info; CK_RV rc; rc = p11tool_pkcs11_funcs->C_GetMechanismInfo(slot, CKM_PUB_KEY_FROM_PRIV_KEY, &mech_info); if (rc != CKR_OK) return rc; if ((mech_info.flags & CKF_DERIVE) == 0) return CKR_MECHANISM_INVALID; return CKR_OK; } char p11tool_prompt_user(const char *message, char* allowed_chars) { int len; size_t linelen = 0; char *line = NULL; char ch = '\0'; printf("%s", message); while (1) { len = getline(&line, &linelen, stdin); if (len == -1) break; if (strlen(line) == 2 && strpbrk(line, allowed_chars) != 0) { ch = line[0]; break; } warnx("Improper reply, try again"); } if (line != NULL) free(line); return ch; } int p11tool_pem_password_cb(char *buf, int size, int rwflag, void *userdata) { struct p11tool_pem_password_cb_data *data = userdata; const char *pem_password = data->pem_password; char *buf_pem_password = NULL; char *msg = NULL; int len; UNUSED(rwflag); UNUSED(userdata); if (pem_password == NULL) pem_password = getenv(data->env_var_name); if (data->force_prompt || pem_password == NULL) { if (asprintf(&msg, "Please enter %s for '%s': ", strncmp(data->pem_file_name, "pkcs11:", 7) == 0 ? "PKCS#11 user PIN" : "PEM password", data->pem_file_name) <= 0) { warnx("Failed to allocate memory for message"); return -1; } pem_password = pin_prompt(&buf_pem_password, msg); free(msg); if (pem_password == NULL) { warnx("Failed to prompt for PEM password"); return -1; } } len = strlen(pem_password); if (len > size) { warnx("PEM password is too long"); return -1; } strncpy(buf, pem_password, size); pin_free(&buf_pem_password); return len; } CK_RV p11tool_ASN1_TIME2date(const ASN1_TIME *asn1time, CK_DATE *date) { struct tm time; char tmp[40]; if (!ASN1_TIME_to_tm(asn1time, &time)) { warnx("ASN1_TIME_to_tm failed to convert the certificate's date"); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); return CKR_FUNCTION_FAILED; } snprintf(tmp, sizeof(tmp), "%04d%02d%02d", time.tm_year + 1900, time.tm_mon + 1, time.tm_mday); memcpy(date->year, tmp, 4); memcpy(date->month, tmp + 4, 2); memcpy(date->day, tmp + 4 + 2, 2); return CKR_OK; } #if OPENSSL_VERSION_PREREQ(3, 0) CK_BBOOL p11tool_check_settable_fromdata_params(EVP_PKEY_CTX *ctx, const char *name) { const OSSL_PARAM *settable, *p; settable = EVP_PKEY_fromdata_settable(ctx, EVP_PKEY_KEYPAIR); for (p = settable; p != NULL && p->key != NULL; p++) { if (strcmp(p->key, name) == 0) return TRUE; } return CK_FALSE; } CK_RV p11tool_get_octet_string_param_from_pkey(EVP_PKEY *pkey, const char *param, CK_BYTE **key, size_t *key_len, CK_BBOOL check) { const OSSL_PARAM *gettable, *p; CK_BBOOL found = FALSE; if (check) { gettable = EVP_PKEY_gettable_params(pkey); for (p = gettable; p != NULL && p->key != NULL; p++) { if (strcmp(p->key, param) == 0) { found = TRUE; break; } } if (!found) { *key = NULL; *key_len = 0; return CKR_OK; } } if (EVP_PKEY_get_octet_string_param(pkey, param, NULL, 0, key_len) != 1 || *key_len == OSSL_PARAM_UNMODIFIED) { warnx("EVP_PKEY_get_octet_string_param failed for '%s'\n", param); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); return CKR_FUNCTION_FAILED; } *key = calloc(1, *key_len); if (*key == NULL) { warnx("Failed to allocate buffer for '%s'\n", param); return CKR_HOST_MEMORY; } if (EVP_PKEY_get_octet_string_param(pkey, param, *key, *key_len, key_len) != 1) { warnx("EVP_PKEY_get_octet_string_param failed for '%s'\n", param); ERR_print_errors_cb(p11tool_openssl_err_cb, NULL); return CKR_FUNCTION_FAILED; } return CKR_OK; } #endif CK_RV p11tool_prepare_uri(CK_OBJECT_HANDLE key, CK_OBJECT_CLASS *class, const struct p11tool_objtype *objtype, const char *typestr, const char* label, bool detailed_uri, CK_SLOT_ID slot, struct p11_uri **uri) { struct p11_uri *u; CK_RV rc; u = p11_uri_new(); if (u == NULL) { warnx("Failed to allocate URI for %s %s \"%s\"", typestr, objtype->obj_typestr, label); return CKR_HOST_MEMORY; } if (detailed_uri) { /* include library and slot information only in detailed URIs */ u->info = &p11tool_pkcs11_info; u->slot_id = slot; u->slot_info = &p11tool_pkcs11_slotinfo; } u->token_info = &p11tool_pkcs11_tokeninfo; u->obj_class[0].ulValueLen = sizeof(*class); u->obj_class[0].pValue = class; u->obj_label[0].ulValueLen = label != NULL ? strlen(label) : 0; u->obj_label[0].pValue = (char *)label; rc = p11tool_get_attribute(key, &u->obj_id[0]); if (rc != CKR_OK) { warnx("Failed to get CKA_ID for %s %s \"%s\": 0x%lX: %s", typestr, objtype->obj_typestr, label, rc, p11_get_ckr(rc)); if (u->obj_id[0].pValue != NULL) free(u->obj_id[0].pValue); p11_uri_free(u); return rc; } *uri = u; return CKR_OK; } CK_RV p11tool_bio_readall(BIO *bio, CK_BYTE **buffer, CK_ULONG *read_len) { CK_ULONG ofs = 0, buf_len = 0; CK_BYTE *buf = NULL, *tmp; size_t read, left = 0; int ret; *buffer = NULL; *read_len = 0; do { if (left == 0) { buf_len += 1024; tmp = OPENSSL_realloc(buf, buf_len); if (tmp == NULL) { warnx("Failed to allocate a buffer for reading a file"); free(buf); return CKR_HOST_MEMORY; } buf = tmp; left = 1024; } ret = BIO_read_ex(bio, buf + ofs, left, &read); if (ret != 1) break; ofs += read; left -= read; } while(1); if (ofs == 0) { free(buf); return CKR_FUNCTION_FAILED; } *buffer = buf; *read_len = ofs; return CKR_OK; } CK_RV p11tool_split_by_delim(char *str, char *delim, char ***list) { char **l = NULL, **tmp; CK_ULONG num = 0, left = 0, ofs = 0; char *tok; char *save = NULL; do { tok = strtok_r(save == NULL ? str : NULL, delim, &save); if (left == 0) { num += 16; tmp = realloc(l, num * sizeof(char *)); if (tmp == NULL) { warnx("Failed to allocate a buffer for reading a file"); free(l); return CKR_HOST_MEMORY; } l = tmp; left = 16; } l[ofs] = tok; ofs++; left--; } while(tok != NULL); *list = l; return CKR_OK; } opencryptoki-opencryptoki-451d99c/usr/sbin/p11sak/p11tool.h000066400000000000000000000507211520105705100236450ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2025 * * 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 P11TOOL_H_ #define P11TOOL_H_ #include "platform.h" #if !defined(_AIX) #include #endif /* _AIX */ #include "pkcs11types.h" #include "defs.h" #include "uri.h" #include #define UNUSED(var) ((void)(var)) #define P11TOOL_DEFAULT_PKCS11_LIB OCK_API_LIBNAME; #define P11TOOL_PKCSLIB_ENV_NAME "PKCSLIB" #define PKCS11_USER_PIN_ENV_NAME "PKCS11_USER_PIN" #define PKCS11_SO_PIN_ENV_NAME "PKCS11_SO_PIN" #define MAX_PRINT_LINE_LENGTH 80 enum p11tool_arg_type { ARG_TYPE_PLAIN = 0, /* no argument */ ARG_TYPE_STRING = 1, ARG_TYPE_ENUM = 2, ARG_TYPE_NUMBER = 3, }; struct p11tool_enum_value { const char *value; const char *description; const struct p11tool_arg *args; const struct p11tool_opt *opts; union { const void *ptr; CK_ULONG num; } private; char **any_value; /* if this is not NULL then this enum value matches to any string, and the string is set into any_value */ }; struct p11tool_arg { const char *name; enum p11tool_arg_type type; bool required; bool case_sensitive; const struct p11tool_enum_value *enum_values; union { bool *plain; char **string; struct p11tool_enum_value **enum_value; CK_ULONG *number; } value; bool (*is_set)(const struct p11tool_arg *arg); const char *description; }; struct p11tool_opt { char short_opt; /* 0 if no short option is used */ const char *long_opt; /* NULL if no long option */ int long_opt_val; /* Used only if short_opt is 0 */ bool required; struct p11tool_arg arg; const char *description; }; struct p11tool_cmd { const char *cmd; const char *cmd_short1; const char *cmd_short2; CK_RV (*func)(void); const struct p11tool_opt *opts; const struct p11tool_arg *args; const char *description; void (*help)(void); CK_FLAGS session_flags; }; struct p11tool_attr { const char *name; CK_ATTRIBUTE_TYPE type; char letter; bool secret; bool public; bool private; bool settable; bool so_set_to_true; /* can only be set to TRUE by SO */ void (*print_short)(const CK_ATTRIBUTE *val, bool applicable); void (*print_long)(const char *attr, const CK_ATTRIBUTE *val, int indent, bool sensitive); }; #define DECLARE_BOOL_ATTR(attr, ch, sec, pub, priv, set) \ { .name = # attr, .type = attr, .letter = ch, \ .secret = sec, .public = pub, .private = priv, \ .settable = set, .print_short = p11tool_print_bool_attr_short, \ .print_long = p11tool_print_bool_attr_long, } #define DECLARE_BOOL_ATTR_SO(attr, ch, sec, pub, priv, set, so_set_true) \ { .name = # attr, .type = attr, .letter = ch, \ .secret = sec, .public = pub, .private = priv, \ .settable = set, .so_set_to_true = so_set_true, \ .print_short = p11tool_print_bool_attr_short, \ .print_long = p11tool_print_bool_attr_long, } struct p11tool_objtype { const char *obj_typestr; const char *obj_liststr; const char *name; CK_ULONG type; /* CK_KEY_TYPE or CK_CERTIFICATE_TYPE */ const char *ck_name; int pkey_type; /* OpenSSL PKEY_xxx type or 0 if not applicable */ bool supports_oqsprovider_pem; CK_MECHANISM keygen_mech; bool is_asymmetric; bool sign_verify; bool encrypt_decrypt; bool wrap_unwrap; bool derive; bool encaps_decaps; CK_RV (*keygen_prepare)(const struct p11tool_objtype *keytype, void **private); void (*keygen_cleanup)(const struct p11tool_objtype *keytype, void *private); CK_RV (*keygen_get_key_size)(const struct p11tool_objtype *keytype, void *private, CK_ULONG *keysize); CK_RV (*keygen_add_secret_attrs)(const struct p11tool_objtype *keytype, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, void *private); CK_RV (*keygen_add_public_attrs)(const struct p11tool_objtype *keytype, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, void *private); CK_RV (*keygen_add_private_attrs)(const struct p11tool_objtype *keytype, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, void *private); CK_ATTRIBUTE_TYPE filter_attr; CK_ULONG filter_value; CK_ATTRIBUTE_TYPE keysize_attr; CK_ULONG keysize_value; bool keysize_attr_value_len; CK_ULONG (*key_keysize_adjust)(const struct p11tool_objtype *keytype, CK_ULONG keysize); const struct p11tool_attr *secret_attrs; const struct p11tool_attr *public_attrs; const struct p11tool_attr *private_attrs; CK_RV (*import_check_sym_keysize)(const struct p11tool_objtype *keytype, CK_ULONG keysize); CK_RV (*import_sym_clear)(const struct p11tool_objtype *keytype, CK_BYTE *data, CK_ULONG data_len, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs); CK_RV (*import_asym_pkey)(const struct p11tool_objtype *keytype, EVP_PKEY *pkey, bool private, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs); CK_RV (*import_asym_pem_data)(const struct p11tool_objtype *keytype, unsigned char *data, size_t data_len, bool private, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs); CK_RV (*export_sym_clear)(const struct p11tool_objtype *keytype, CK_BYTE **data, CK_ULONG* data_len, CK_OBJECT_HANDLE key, const char *label); CK_RV (*export_asym_pkey)(const struct p11tool_objtype *keytype, EVP_PKEY **pkey, bool private, CK_OBJECT_HANDLE key, const char *label); CK_RV (*export_asym_pem_data)(const struct p11tool_objtype *keytype, CK_BYTE **data, CK_ULONG *data_len, bool private, CK_OBJECT_HANDLE key, const char *label); const char *pem_name_private; const char *pem_name_public; /* Following entries are for certificates */ const struct p11tool_attr *cert_attrs; CK_RV (*import_x509_data)(const struct p11tool_objtype *certtype, X509 *x509, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs); CK_RV (*export_x509_data)(const struct p11tool_objtype *certtype, CK_BYTE **data, CK_ULONG *data_len, CK_OBJECT_HANDLE cert, const char *label); CK_RV (*extract_x509_pubkey)(const struct p11tool_objtype *certtype, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, CK_OBJECT_HANDLE cert, const char * label); }; struct p11tool_class { const char *name; CK_OBJECT_CLASS class; }; enum p11tool_objclass { OBJCLASS_KEY = 0, OBJCLASS_CERTIFICATE = 1, }; enum p11tool_token_type { TOKTYPE_UNKNOWN = 0, TOKTYPE_CCA = 1, TOKTYPE_EP11 = 2, }; struct p11tool_token_info { enum p11tool_token_type type; const char *manufacturer; const char *model; unsigned int mkvp_size; unsigned int mktype_cell_size; unsigned int session_id_size; CK_ATTRIBUTE_TYPE secure_key_attr; void (*print_mkvp_long)(const struct p11tool_token_info *info, const CK_BYTE *secure_key, CK_ULONG secure_key_len, int indent); void (*print_mkvp_short)(const struct p11tool_token_info *info, const CK_BYTE *secure_key, CK_ULONG secure_key_len, const char *separator); void (*print_session_id_long)(const struct p11tool_token_info *info, const CK_BYTE *secure_key, CK_ULONG secure_key_len, int indent); void (*print_session_id_short)(const struct p11tool_token_info *info, const CK_BYTE *secure_key, CK_ULONG secure_key_len); }; extern void *p11tool_pkcs11_lib; extern bool p11tool_pkcs11_initialized; extern CK_FUNCTION_LIST *p11tool_pkcs11_funcs; extern CK_SESSION_HANDLE p11tool_pkcs11_session; extern CK_INFO p11tool_pkcs11_info; extern CK_TOKEN_INFO p11tool_pkcs11_tokeninfo; extern const struct p11tool_token_info *p11tool_token_info; extern CK_SLOT_INFO p11tool_pkcs11_slotinfo; extern char *p11tool_pin; extern const struct p11tool_class p11tool_classes[]; extern const struct p11tool_enum_value p11tool_ibm_dilithium_versions[]; extern const struct p11tool_enum_value p11tool_ibm_kyber_versions[]; extern const struct p11tool_enum_value p11tool_ibm_ml_dsa_versions[]; extern const struct p11tool_enum_value p11tool_ibm_ml_kem_versions[]; extern const struct p11tool_enum_value p11tool_ml_dsa_versions[]; extern const struct p11tool_enum_value p11tool_ml_kem_versions[]; const struct p11tool_cmd *p11tool_find_command(const struct p11tool_cmd *cmds, const char *cmd); CK_RV p11tool_parse_cmd_arguments(const struct p11tool_cmd *cmd, int *argc, char **argv[]); CK_RV p11tool_parse_cmd_options(const struct p11tool_cmd *cmd, const struct p11tool_opt *generic_opts, int argc, char *argv[]); CK_RV p11tool_check_required_args(const struct p11tool_arg *args); CK_RV p11tool_check_required_cmd_opts(const struct p11tool_opt *cmd_opts, const struct p11tool_arg *cmd_args, const struct p11tool_opt *generic_opts); void p11tool_print_indented(const char *str, int indent); void p11tool_print_help(const char *name, const struct p11tool_cmd *commands, const struct p11tool_opt *generic_opts, int indent_pos); void p11tool_print_command_help(const char *name, const struct p11tool_cmd *cmd, const struct p11tool_opt *generic_opts, int indent_pos); void p11tool_print_version(const char *name); void p11tool_print_bool_attr_short(const CK_ATTRIBUTE *val, bool applicable); void p11tool_print_bool_attr_long(const char *attr, const CK_ATTRIBUTE *val, int indent, bool sensitive); void p11tool_print_utf8_attr(const char *attr, const CK_ATTRIBUTE *val, int indent, bool sensitive); void p11tool_print_java_midp_secdom_attr(const char *attr, const CK_ATTRIBUTE *val, int indent, bool sensitive); void p11tool_print_cert_category_attr(const char *attr, const CK_ATTRIBUTE *val, int indent, bool sensitive); void p11tool_print_x509_name_attr(const char *attr, const CK_ATTRIBUTE *val, int indent, bool sensitive); void p11tool_print_x509_attr(const char *attr, const CK_ATTRIBUTE *val, int indent, bool sensitive); void p11tool_print_x509_serial_number_attr(const char *attr, const CK_ATTRIBUTE *val, int indent, bool sensitive); void p11tool_print_byte_array_attr(const char *attr, const CK_ATTRIBUTE *val, int indent, bool sensitive); void p11tool_print_ulong_attr(const char *attr, const CK_ATTRIBUTE *val, int indent, bool sensitive); void p11tool_print_date_attr(const char *attr, const CK_ATTRIBUTE *val, int indent, bool sensitive); void p11tool_print_mech_attr(const char *attr, const CK_ATTRIBUTE *val, int indent, bool sensitive); void p11tool_print_mech_array_attr(const char *attr, const CK_ATTRIBUTE *val, int indent, bool sensitive); void p11tool_print_class_attr(const char *attr, const CK_ATTRIBUTE *val, int indent, bool sensitive); void p11tool_print_oid_attr(const char *attr, const CK_ATTRIBUTE *val, int indent, bool sensitive); void p11tool_print_ibm_dilithium_keyform_attr(const char *attr, const CK_ATTRIBUTE *val, int indent, bool sensitive); void p11tool_print_ibm_kyber_keyform_attr(const char *attr, const CK_ATTRIBUTE *val, int indent, bool sensitive); void p11tool_print_ibm_ml_dsa_parameter_set_attr(const char *attr, const CK_ATTRIBUTE *val, int indent, bool sensitive); void p11tool_print_ibm_ml_kem_parameter_set_attr(const char *attr, const CK_ATTRIBUTE *val, int indent, bool sensitive); int p11tool_openssl_err_cb(const char *str, size_t len, void *u); void p11tool_free_attributes(CK_ATTRIBUTE *attrs, CK_ULONG num_attrs); bool p11tool_is_attr_array_attr(CK_ATTRIBUTE *attr); void p11tool_free_attr_array_attr(CK_ATTRIBUTE *attr); CK_RV p11tool_alloc_attr_array_attr(CK_ATTRIBUTE *attr, bool *allocated); CK_RV p11tool_add_attribute(CK_ATTRIBUTE_TYPE type, const void *value, CK_ULONG value_len, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs); CK_RV p11tool_add_bignum_attr(CK_ATTRIBUTE_TYPE type, const BIGNUM* bn, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs); CK_RV p11tool_add_attributes(const struct p11tool_objtype *objtype, const struct p11tool_attr *bool_attrs, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, const char *label, const char *attr_string, const char *id, bool is_sensitive, bool so, CK_RV (*add_attrs)( const struct p11tool_objtype *objtype, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, void *private), void *private, bool (*attr_applicable)( const struct p11tool_objtype *objtype, const struct p11tool_attr *attr)); CK_RV p11tool_parse_hex(const char *id_string, CK_BYTE **buf, CK_ULONG *buflen); CK_RV p11tool_parse_id(const char *id_string, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs); const struct p11tool_attr *p11tool_find_attr_by_letter( const struct p11tool_attr *bool_attrs, char letter); CK_RV p11tool_parse_boolean_attrs(const struct p11tool_objtype *objtype, const struct p11tool_attr *bool_attrs, const char *attr_string, CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, bool check_settable, bool so, bool (*attr_applicable)( const struct p11tool_objtype *objtype, const struct p11tool_attr *attr)); CK_RV p11tool_get_attribute(CK_OBJECT_HANDLE key, CK_ATTRIBUTE *attr); CK_RV p11tool_get_bignum_attr(CK_OBJECT_HANDLE key, CK_ATTRIBUTE_TYPE type, BIGNUM **bn); CK_RV p11tool_get_common_name_value(CK_OBJECT_HANDLE obj, char *label, char **common_name_value); CK_RV p11tool_get_keysize_value(CK_OBJECT_HANDLE obj, char *label, const struct p11tool_objtype *objtype_val, CK_ULONG *keysize_val); CK_RV p11tool_get_typestr_value(CK_OBJECT_CLASS class_val, CK_ULONG keysize_val, const struct p11tool_objtype *objtype_val, char *label, char **typestr); CK_RV p11tool_get_class_and_type_values(CK_OBJECT_HANDLE obj, char *label, CK_OBJECT_CLASS *class_val, CK_ULONG *otype_val); CK_RV p11tool_get_label_value(CK_OBJECT_HANDLE obj, char** label_value); CK_BBOOL p11tool_objclass_expected(CK_OBJECT_HANDLE obj, enum p11tool_objclass objclass); bool p11tool_attr_applicable_for_certtype( const struct p11tool_objtype *certtype, const struct p11tool_attr *attr); bool p11tool_attr_applicable_for_keytype(const struct p11tool_objtype *keytype, const struct p11tool_attr *attr); bool p11tool_cert_attr_applicable(const struct p11tool_objtype *certtype, const struct p11tool_attr *attr); bool p11tool_secret_attr_applicable(const struct p11tool_objtype *objtype, const struct p11tool_attr *attr); bool p11tool_public_attr_applicable(const struct p11tool_objtype *objtype, const struct p11tool_attr *attr); bool p11tool_private_attr_applicable(const struct p11tool_objtype *objtype, const struct p11tool_attr *attr); CK_RV p11tool_init_pkcs11(const struct p11tool_cmd *command, bool no_login, const char *pin, bool force_pin_prompt, bool so, bool remember_pin, CK_SLOT_ID slot, const struct p11tool_token_info *known_tokens); void p11tool_term_pkcs11(void); bool p11tool_is_rejected_by_policy(CK_RV ret_code, CK_SESSION_HANDLE session); CK_RV p11tool_check_wrap_mech_supported(CK_SLOT_ID slot, CK_MECHANISM_TYPE mechanism, CK_BBOOL wrap, CK_BBOOL unwrap); CK_RV p11tool_check_keygen_mech_supported(CK_SLOT_ID slot, CK_MECHANISM_TYPE mechanism, bool is_asymmetric, CK_ULONG keysize); CK_RV p11tool_check_pub_from_priv_mech_supported(CK_SLOT_ID slot); char p11tool_prompt_user(const char *message, char* allowed_chars); struct p11tool_pem_password_cb_data { const char *pem_file_name; const char *pem_password; const char *env_var_name; bool force_prompt; }; int p11tool_pem_password_cb(char *buf, int size, int rwflag, void *userdata); CK_RV p11tool_ASN1_TIME2date(const ASN1_TIME *asn1time, CK_DATE *date); CK_BBOOL p11tool_check_settable_fromdata_params(EVP_PKEY_CTX *ctx, const char *name); CK_RV p11tool_get_octet_string_param_from_pkey(EVP_PKEY *pkey, const char *param, CK_BYTE **key, size_t *key_len, CK_BBOOL check); CK_RV p11tool_prepare_uri(CK_OBJECT_HANDLE key, CK_OBJECT_CLASS *class, const struct p11tool_objtype *objtype, const char *typestr, const char* label, bool detailed_uri, CK_SLOT_ID slot, struct p11_uri **uri); CK_RV p11tool_bio_readall(BIO *bio, CK_BYTE **buffer, CK_ULONG *read_len); CK_RV p11tool_split_by_delim(char *str, char *delim, char ***list); #endif opencryptoki-opencryptoki-451d99c/usr/sbin/pkcscca/000077500000000000000000000000001520105705100224775ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/usr/sbin/pkcscca/pkcscca.c000066400000000000000000002074341520105705100242640ustar00rootroot00000000000000/* * 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. * */ #include #include #include #if defined(_AIX) #include #else #include #endif #include #include #include #include #include #include #include #include "platform.h" #include "pkcs11types.h" #include "sw_crypt.h" #include "defs.h" #include "host_defs.h" #include "local_types.h" #include "h_extern.h" #include "slotmgr.h" // for ock_snprintf #define OCK_TOOL #include "pkcs_utils.h" #include "pin_prompt.h" #include "pkcscca.h" const char manuf[] = "IBM"; const char model[] = "CCA"; const char descr[] = "IBM CCA Token"; const char label[] = "ccatok"; #if defined(_AIX) const char *__progname = "pkcscca"; #endif pkcs_trace_level_t trace_level = TRACE_LEVEL_NONE; token_spec_t token_specific; int v_level = 0; void *p11_lib = NULL; void (*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); void (*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); void (*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); void (*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); void (*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); void (*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); 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 }; static struct algo ibm_dilithium = {(CK_BYTE *)"RTCMK QSA ", (CK_BYTE *)"IBM Dilithium", 2 }; static struct algo ibm_ml_dsa = {(CK_BYTE *)"RTCMK QSA ", (CK_BYTE *)"IBM ML_DSA", 2 }; static struct algo ibm_ml_kem = {(CK_BYTE *)"RTCMK QSA ", (CK_BYTE *)"IBM ML-KEM", 2 }; static struct algo ml_dsa = {(CK_BYTE *)"RTCMK QSA ", (CK_BYTE *)"ML_DSA", 2 }; 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; } #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; ibm_opaque_attr = NULL; /* Provide dummy CKA_VAUE attribute in (clear) key size */ key_size = be16toh(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; value_attr = NULL; free(zero); return CKR_OK; cleanup: if (ibm_opaque_attr) free(ibm_opaque_attr); if (value_attr) free(value_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, const char *fname) { 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(NULL, data, &obj, CK_FALSE, data_len, fname); 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, const char *fname) { 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_CCA); 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, fname); 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, fname); if (rc) goto cleanup; } else { /* public token object */ rc = adjust_key_object_attributes(buf, size, &new_cipher, &new_cipher_len, fname); 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_level) printf("Failed to process %s\n", fname); fcount++; } else { if (v_level) printf("Processed %s.\n", fname); scount++; } } fclose(fp1); printf("Successfully migrated %d object(s).\n", scount); if (v_level && fcount) printf("Failed to migrate %d object(s).\n", fcount); return 0; } int load_masterkey(char *mkfile, const 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, master_key_len; struct stat statbuf; int ret; CK_RV rc; FILE *fp = NULL; if (stat((char *) mkfile, &statbuf) != 0) { print_error("Cannot find %s.\n", mkfile); return -1; } master_key_len = MASTER_KEY_SIZE; clear_len = cipher_len = (master_key_len + SHA1_HASH_SIZE + (DES_BLOCK_SIZE - 1)) & ~(DES_BLOCK_SIZE - 1); if ((CK_ULONG)statbuf.st_size > cipher_len) { /* * The CCA token used to have a secure master key length of 64, although * it uses clear keys for the master key in the meantime. The master key * length has an influence on the file size of the MK_SO and MK_USER * files when using the old pin encryption format. Use special handling * for such larger MK_SO files, and accept the larger length. Newly * written MK_SO files will use the clear key master key length, but we * need to be able to read larger files for backwards compatibility. */ master_key_len = MASTER_KEY_SIZE_CCA; clear_len = cipher_len = (master_key_len + 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_len, hash_sha); if (ret) { print_error("Failed to compute sha for masterkey.\n"); goto done; } if (memcmp(hash_sha, clear + master_key_len, 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_len); ret = 0; done: if (fp) fclose(fp); if (clear) free(clear); if (cipher) free(cipher); return ret; } CK_FUNCTION_LIST *p11_init(void) { CK_RV rv; CK_RV (*getfunclist)(CK_FUNCTION_LIST_PTR_PTR ppFunctionList); CK_FUNCTION_LIST *funcs = NULL; p11_lib = dlopen(OCK_API_LIBNAME, DYNLIB_LDFLAGS); if (p11_lib == NULL) { print_error("Couldn't get a handle to the PKCS#11 library."); return NULL; } *(void **)(&getfunclist) = dlsym(p11_lib, "C_GetFunctionList"); if (getfunclist == NULL) { print_error("Couldn't get the address of the C_GetFunctionList " "routine."); #ifndef WITH_SANITIZER dlclose(p11_lib); #endif return NULL; } rv = getfunclist(&funcs); if (rv != CKR_OK) { p11_error("C_GetFunctionList", rv); #ifndef WITH_SANITIZER dlclose(p11_lib); #endif return NULL; } rv = funcs->C_Initialize(NULL_PTR); if (rv != CKR_OK) { p11_error("C_Initialize", rv); #ifndef WITH_SANITIZER dlclose(p11_lib); #endif return NULL; } if (v_level) printf("PKCS#11 library initialized\n"); return funcs; } void p11_fini(CK_FUNCTION_LIST *funcs) { funcs->C_Finalize(NULL_PTR); #ifndef WITH_SANITIZER if (p11_lib) dlclose(p11_lib); #endif } /* Expect attribute array to have 3 entries, * 0 CKA_IBM_OPAQUE * 1 CKA_KEY_TYPE * 2 CKA_LABEL * 3 CKA_CLASS */ 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; CK_ULONG class = *(CK_ULONG *) attrs[3].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_AES_XTS: case CKK_DES: case CKK_DES2: case CKK_DES3: case CKK_EC: case CKK_GENERIC_SECRET: case CKK_RSA: case CKK_IBM_PQC_DILITHIUM: case CKK_IBM_ML_DSA: case CKK_IBM_ML_KEM: case CKK_ML_DSA: break; default: free(new_key); return 0; } new_key->type = key_type; new_key->class = class; 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->opaque_attr); 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_level) { char *type_name; switch (new_key->type) { case CKK_AES: type_name = AES_NAME; break; case CKK_AES_XTS: type_name = AES_XTS_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; case CKK_IBM_PQC_DILITHIUM: type_name = IBM_DILITHIUM_NAME; break; case CKK_IBM_ML_DSA: type_name = IBM_ML_DSA_NAME; break; case CKK_IBM_ML_KEM: type_name = IBM_ML_KEM_NAME; break; case CKK_ML_DSA: type_name = ML_DSA_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)}, }; CK_ATTRIBUTE attrs[] = { {CKA_IBM_OPAQUE, NULL, 0}, {CKA_KEY_TYPE, NULL, 0}, {CKA_LABEL, NULL, 0}, {CKA_CLASS, NULL, 0}, }; int i, rc, num_attrs = 4; /* Find all objects in the store */ rv = funcs->C_FindObjectsInit(sess, key_tmpl, 2); 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_level) 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, int masterkey) { 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; if (key->attr_len < 16 || key->opaque_attr[0] == 0x1e) { /* 0x1e: external PKA token */ printf("Skipping key, its a public key. label=%s, handle=%lu\n", key->label, key->handle); return 0; } if (strcmp((char *)algo.name, "RSA") == 0) { /* * RSA keys come in 2 flavors: RSA-CRT (using ASYM-MK) and RSA-AESC * (using APKA-MK) */ switch (masterkey) { case MK_ASYM: if (key->attr_len < 16 || key->opaque_attr[0] != 0x1f || /* 0x1f: internal PKA token */ key->opaque_attr[8] != 0x08) { /* 0x08: RSA-CRT priv key token */ printf("Skipping key, its not an old RSA key. label=%s, handle=%lu\n", key->label, key->handle); return 0; } break; case MK_APKA: if (key->attr_len < 16 || key->opaque_attr[0] != 0x1f || /* 0x1f: internal PKA token */ (key->opaque_attr[8] != 0x31 && /* 0x31: RSA-AESC priv key token */ key->opaque_attr[8] != 0x30)) { /* 0x30: RSA-AESM priv key token */ printf("Skipping key, its not an new RSA key. label=%s, handle=%lu\n", key->label, key->handle); return 0; } break; default: return 1; } } 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_level) { 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; long key_identifier_length; 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); if (key_identifier[0] == 0x01 && key_identifier[4] == 0x05 && key_identifier[41] == 0x02) { /* AES CIPHER key */ key_identifier_length = key->type == CKK_AES_XTS ? key->attr_len / 2 : 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; } if (key->type == CKK_AES_XTS) { key_identifier_length = key->attr_len / 2; CSNBKTC2(&return_code, &reason_code, &exit_data_length, NULL, &(algo.rule_array_count), algo.rule_array, &key_identifier_length, key_identifier + key_identifier_length); 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 { /* AES DATA key */ 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; } if (key->type == CKK_AES_XTS) { CSNBKTC(&return_code, &reason_code, &exit_data_length, NULL, &(algo.rule_array_count), algo.rule_array, key_identifier + (key->attr_len / 2)); 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; } } } if (v_level) { 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_level) { 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, int masterkey) { struct key *key; char *migrated_data; int rc; for (key = keys; key; key = key->next) { migrated_data = NULL; switch (key->type) { case CKK_AES: case CKK_AES_XTS: 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, masterkey); 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, masterkey); if (rc) count_failed->rsa++; else count->rsa++; break; case CKK_IBM_PQC_DILITHIUM: rc = cca_migrate_asymmetric(key, &migrated_data, ibm_dilithium, masterkey); if (rc) count_failed->ibm_dilithium++; else count->ibm_dilithium++; break; case CKK_IBM_ML_DSA: rc = cca_migrate_asymmetric(key, &migrated_data, ibm_ml_dsa, masterkey); if (rc) count_failed->ibm_ml_dsa++; else count->ibm_ml_dsa++; break; case CKK_IBM_ML_KEM: rc = cca_migrate_asymmetric(key, &migrated_data, ibm_ml_kem, masterkey); if (rc) count_failed->ibm_ml_kem++; else count->ibm_ml_kem++; break; case CKK_ML_DSA: rc = cca_migrate_asymmetric(key, &migrated_data, ml_dsa, masterkey); if (rc) count_failed->ml_dsa++; else count->ml_dsa++; 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, int masterkey) { 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, masterkey); 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 || migrated.ibm_dilithium || migrated.ibm_ml_dsa || migrated.ibm_ml_kem || migrated.ml_dsa) 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 (migrated.ibm_dilithium) printf("IBM Dilithium: %d. ", migrated.ibm_dilithium); if (migrated.ibm_ml_dsa) printf("IBM ML-DSA: %d. ", migrated.ibm_ml_dsa); if (migrated.ibm_ml_kem) printf("IBM ML-KEM: %d. ", migrated.ibm_ml_kem); if (migrated.ml_dsa) printf("ML-DSA: %d. ", migrated.ml_dsa); if (failed.aes || failed.des || failed.des2 || failed.des3 || failed.ecc || failed.hmac || failed.rsa || failed.ibm_dilithium || failed.ibm_ml_dsa || failed.ibm_ml_kem || failed.ml_dsa) 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); if (failed.ibm_dilithium) printf("IBM Dilithium: %d. ", failed.ibm_dilithium); if (failed.ibm_ml_dsa) printf("IBM ML-DSA: %d. ", failed.ibm_ml_dsa); if (failed.ibm_ml_kem) printf("IBM ML-KEM: %d. ", failed.ibm_ml_kem); if (failed.ml_dsa) printf("ML-DSA: %d. ", failed.ml_dsa); printf("\n"); } int migrate_wrapped_keys(CK_SLOT_ID slot_id, const char *userpin, int masterkey) { CK_FUNCTION_LIST *funcs; CK_KEY_TYPE key_type = 0; CK_SESSION_HANDLE sess; CK_RV rv; struct key_count count = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; struct key_count count_failed = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; int exit_code = 0, rc; funcs = p11_init(); if (!funcs) { return 2; } 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_level) printf("Search for AES keys\n"); key_type = CKK_AES; rc = migrate_keytype(funcs, sess, &key_type, &count, &count_failed, masterkey); if (rc) { goto done; } key_type = CKK_AES_XTS; rc = migrate_keytype(funcs, sess, &key_type, &count, &count_failed, masterkey); if (rc) { goto done; } if (v_level) printf("Search for HMAC keys\n"); key_type = CKK_GENERIC_SECRET; rc = migrate_keytype(funcs, sess, &key_type, &count, &count_failed, masterkey); if (rc) { goto done; } break; case MK_APKA: if (v_level) printf("Search for ECC keys\n"); key_type = CKK_EC; rc = migrate_keytype(funcs, sess, &key_type, &count, &count_failed, masterkey); if (rc) { goto done; } if (v_level) printf("Search for RSA keys\n"); key_type = CKK_RSA; rc = migrate_keytype(funcs, sess, &key_type, &count, &count_failed, masterkey); if (rc) { goto done; } if (v_level) printf("Search for IBM Dilithium keys\n"); key_type = CKK_IBM_PQC_DILITHIUM; rc = migrate_keytype(funcs, sess, &key_type, &count, &count_failed, masterkey); if (rc) { goto done; } if (v_level) printf("Search for IBM ML-DSA keys\n"); key_type = CKK_IBM_ML_DSA; rc = migrate_keytype(funcs, sess, &key_type, &count, &count_failed, masterkey); if (rc) { goto done; } if (v_level) printf("Search for IBM ML-KEM keys\n"); key_type = CKK_IBM_ML_KEM; rc = migrate_keytype(funcs, sess, &key_type, &count, &count_failed, masterkey); if (rc) { goto done; } if (v_level) printf("Search for ML-DSA keys\n"); key_type = CKK_ML_DSA; rc = migrate_keytype(funcs, sess, &key_type, &count, &count_failed, masterkey); if (rc) { goto done; } break; case MK_ASYM: if (v_level) printf("Search for old RSA keys\n"); key_type = CKK_RSA; rc = migrate_keytype(funcs, sess, &key_type, &count, &count_failed, masterkey); if (rc) { goto done; } break; case MK_SYM: if (v_level) printf("Search for DES keys\n"); key_type = CKK_DES; rc = migrate_keytype(funcs, sess, &key_type, &count, &count_failed, masterkey); if (rc) { goto done; } if (v_level) printf("Search for DES2 keys\n"); key_type = CKK_DES2; rc = migrate_keytype(funcs, sess, &key_type, &count, &count_failed, masterkey); if (rc) { goto done; } if (v_level) printf("Search for DES3 keys\n"); key_type = CKK_DES3; rc = migrate_keytype(funcs, sess, &key_type, &count, &count_failed, masterkey); 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; } /* @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_old_rsa(struct key *keys, unsigned int *count, unsigned int *count_failed) { long return_code, reason_code, exit_data_length = 0; long rule_array_count, source_len, target_len, zero_len = 0; unsigned char target_token[2500] = { 0 }; unsigned char rule_array[8]; struct key *key; for (key = keys; key; key = key->next) { if (key->attr_len < 16 || key->opaque_attr[0] != 0x1f || /* 0x1f: internal PKA token */ key->opaque_attr[8] != 0x08) { /* 0x08: RSA-CRT priv key token */ if (v_level) printf("Skipping RSA key, its not an old RSA key. label=%s, handle=%lu\n", key->label, key->handle); continue; } source_len = key->attr_len; target_len = sizeof(target_token); memset(target_token, 0, sizeof(target_token)); if (key->class == CKO_PUBLIC_KEY) { /* Extract public key only */ rule_array_count = 0; CSNDPKX(&return_code, &reason_code, &exit_data_length, NULL, &rule_array_count, rule_array, &source_len, key->opaque_attr, &target_len, target_token); if (return_code != CCA_SUCCESS) { cca_error("CSNDPKX (Public Key Token Extract)", return_code, reason_code); print_error("Migrating old RSA key failed. label=%s, handle=%lu", key->label, key->handle); (*count_failed)++; continue; } else if (v_level) { printf("Successfully migrated old RSA key. label=%s, handle=%lu\n", key->label, key->handle); } } else { /* Convert to RSA-AESC token type */ rule_array_count = 1; memcpy(rule_array, "INTDWAKW", 8); CSNDPKT(&return_code, &reason_code, &exit_data_length, NULL, &rule_array_count, rule_array, &source_len, key->opaque_attr, &zero_len, NULL, &zero_len, NULL, &target_len, target_token); if (return_code != CCA_SUCCESS) { cca_error("CSNDPKT (PKA Key Translate)", return_code, reason_code); print_error("Migrating old RSA key failed. label=%s, handle=%lu", key->label, key->handle); (*count_failed)++; continue; } else if (v_level) { printf("Successfully migrated old RSA key. label=%s, handle=%lu\n", key->label, key->handle); } } /* replace the original key with the migrated key */ free(key->opaque_attr); key->opaque_attr = malloc(target_len); if (key->opaque_attr == NULL) { print_error("Malloc of %ld bytes failed!", target_len); (*count_failed)++; continue; } memcpy(key->opaque_attr, target_token, target_len); key->attr_len = target_len; (*count)++; } return 0; } int migrate_old_rsa_keys(CK_SLOT_ID slot_id, const char *userpin) { CK_FUNCTION_LIST *funcs; CK_SESSION_HANDLE sess; CK_RV rv; unsigned int count = 0; unsigned int count_failed = 0; int exit_code = 0, rc; struct key *keys = NULL, *tmp, *to_free; CK_KEY_TYPE key_type = CKK_RSA; funcs = p11_init(); if (!funcs) { return 2; } 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; } if (v_level) printf("Search for RSA keys\n"); rc = find_wrapped_keys(funcs, sess, &key_type, &keys); if (rc) { exit_code = 8; goto done; } rc = cca_migrate_old_rsa(keys, &count, &count_failed); if (rc) { exit_code = 8; goto done; } rc = replace_keys(funcs, sess, keys); if (rc) { exit_code = 8; goto done; } printf("Successfully migrated: %u", count); if (count_failed) printf("\nFailed to migrate: %u", count_failed); printf("\n"); done: for (to_free = keys; to_free; to_free = tmp) { tmp = to_free->next; free(to_free->opaque_attr); free(to_free); } funcs->C_CloseSession(sess); finalize: p11_fini(funcs); return exit_code; } int migrate_version(const char *sopin, const char *userpin, unsigned char *data_store) { char masterkey[MASTER_KEY_SIZE_CCA]; 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_level) 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_CCA); 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_level) 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_CCA); 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_level) 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\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(" Migrate old RSA Keys:\t\t%s -m oldrsakeys -s SLOTID [OPTIONS] \n", progname); printf(" -m oldrsakeys\t\t\tConverts old RSA keys (RSA-CRT) to the new\n " "\t\t\t\tformat (RSA-AESC) and extracts the public key\n" "\t\t\t\tsection only from key objects containing the\n" "\t\t\t\tfull RSA key token\n"); printf(" -s, --slotid SLOTID\t\tPKCS slot number\n\n"); printf(" Options:\n"); printf(" -d, --datastore DATASTORE\tCCA token datastore location\n"); printf(" -v, --verbose LEVEL\t\tset verbose level (optional):\n"); printf("\t\t\t\tnone (default), error, warn, info, devel, debug\n"); return; } /** * translates the given verbose level string into a numeric verbose level. * Returns -1 if the string is invalid. */ static int verbose_str2level(char *str) { const char *tlevel[] = {"none", "error", "warn", "info", "devel", "debug"}; const int num = sizeof(tlevel) / sizeof(char *); int i; for (i = 0; i < num; i++) { if (strcmp(str, tlevel[i]) == 0) { return i; } } return -1; } int main(int argc, char **argv) { int ret = -1, opt = 0, masterkey = 0; int data_store_len = 0; CK_SLOT_ID slot_id = 0; const char *sopin = NULL, *userpin = NULL; char *buf_so = NULL, *buf_user = NULL; char *data_store = NULL; char *m_type = NULL; char *mk_type = NULL; void *lib_csulcca; int m_version = 0; int m_keys = 0; int m_rsakeys = 0; memset(&token_specific, 0, sizeof(token_specific)); 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:v:h", 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 (strcmp(mk_type, "aes") == 0) { masterkey = MK_AES; } else if (strcmp(mk_type, "apka") == 0) { masterkey = MK_APKA; } else if (strcmp(mk_type, "asym") == 0) { masterkey = MK_ASYM; } else if (strcmp(mk_type, "sym") == 0) { 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 (strcmp(m_type, "v2objectsv3") == 0) { m_version = 1; } else if (strcmp(m_type, "keys") == 0) { m_keys = 1; } else if (strcmp(m_type, "oldrsakeys") == 0) { m_rsakeys = 1; } else { print_error("unknown migration type (%s)\n", m_type); usage(argv[0]); return -1; } break; case 's': slot_id = atoi(optarg); break; case 'v': v_level = verbose_str2level(optarg); if (v_level < 0) { print_error("Invalid verbose level '%s' specified.\n", optarg); usage(argv[0]); return -1; } break; default: usage(argv[0]); return -1; } } /* check for missing parameters */ if (!m_version && !m_keys && !m_rsakeys) { 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 */ sopin = pin_prompt(&buf_so, "Enter the SO PIN: "); if (!sopin) { print_error("Could not get SO PIN.\n"); goto done; } /* get the USER pin to authorize migration */ userpin = pin_prompt(&buf_user, "Enter the USER PIN: "); if (!userpin) { print_error("Could not get USER PIN.\n"); goto done; } /* verify the SO and USER PINs entered. */ ret = verify_pins(data_store, sopin, strlen(sopin), userpin, strlen(userpin)); if (ret) goto done; lib_csulcca = dlopen(CCA_LIBRARY, (RTLD_GLOBAL | DYNLIB_LDFLAGS)); 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); } else if (m_rsakeys) { if (!slot_id) { print_error("missing slot number\n"); usage(argv[0]); return -1; } *(void **)(&CSNDPKT) = dlsym(lib_csulcca, "CSNDPKT"); *(void **)(&CSNDPKX) = dlsym(lib_csulcca, "CSNDPKX"); ret = migrate_old_rsa_keys(slot_id, userpin); } done: pin_free(&buf_so); pin_free(&buf_user); 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"; case CKR_ACTION_PROHIBITED: return "CKR_ACTION_PROHIBITED"; case CKR_AEAD_DECRYPT_FAILED: return "CKR_AEAD_DECRYPT_FAILED"; case CKR_NEW_PIN_MODE: return "CKR_NEW_PIN_MODE"; case CKR_NEXT_OTP: return "CKR_NEXT_OTP"; case CKR_EXCEEDED_MAX_ITERATIONS: return "CKR_EXCEEDED_MAX_ITERATIONS"; case CKR_FIPS_SELF_TEST_FAILED: return "CKR_FIPS_SELF_TEST_FAILED"; case CKR_LIBRARY_LOAD_FAILED: return "CKR_LIBRARY_LOAD_FAILED"; case CKR_PIN_TOO_WEAK: return "CKR_PIN_TOO_WEAK"; case CKR_PUBLIC_KEY_INVALID: return "CKR_PUBLIC_KEY_INVALID"; default: return "UNKNOWN"; } return "UNKNOWN"; } opencryptoki-opencryptoki-451d99c/usr/sbin/pkcscca/pkcscca.h000066400000000000000000000073301520105705100242620ustar00rootroot00000000000000/* * 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 #if defined(_AIX) #define CCA_LIBRARY "libcsufcca.a(sapi64)" #else #define CCA_LIBRARY "libcsulcca.so" #endif #define TOK_DATASTORE CONFIG_PATH "/ccatok" #define CCA_SUCCESS 0 #define AES_NAME "AES" #define AES_XTS_NAME "AES XTS" #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 IBM_DILITHIUM_NAME "IBM Dilithium" #define IBM_ML_DSA_NAME "IBM ML-DSA" #define IBM_ML_KEM_NAME "IBM ML-KEM" #define ML_DSA_NAME "ML-DSA" #define BAD_NAME "Unknown" #define MK_AES 1 #define MK_APKA 2 #define MK_ASYM 3 #define MK_SYM 4 #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(buf); 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) struct key { CK_OBJECT_HANDLE handle; CK_ULONG class; 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; int ibm_dilithium; int ibm_ml_dsa; int ibm_ml_kem; int ml_dsa; }; 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 opencryptoki-opencryptoki-451d99c/usr/sbin/pkcscca/pkcscca.mk000066400000000000000000000047141520105705100244450ustar00rootroot00000000000000sbin_PROGRAMS += usr/sbin/pkcscca/pkcscca noinst_HEADERS += usr/sbin/pkcscca/pkcscca.h noinst_HEADERS += usr/lib/common/defs.h noinst_HEADERS += usr/lib/common/host_defs.h noinst_HEADERS += usr/include/local_types.h noinst_HEADERS += usr/lib/common/h_extern.h noinst_HEADERS += usr/lib/common/pkcs_utils.h noinst_HEADERS += usr/lib/common/pin_prompt.h usr_sbin_pkcscca_pkcscca_LDFLAGS = -lcrypto -ldl -lrt -llber -lpthread if AIX usr_sbin_pkcscca_pkcscca_LDFLAGS += -lbsd -Wl,-blibpath:$(libdir)/opencryptoki:$(libdir)/opencryptoki/stdll:/usr/lib:/usr/lib64 endif usr_sbin_pkcscca_pkcscca_CFLAGS = \ -DSTDLL_NAME=\"pkcscca\" \ -DTOK_NEW_DATA_STORE=0x0003000c \ -DNODSA -DNODH \ -DOCK_NO_SET_PERM -DOCK_NO_LOCAL_RNG \ -I${srcdir}/usr/include \ -I${srcdir}/usr/lib/common \ -I${srcdir}/usr/sbin/pkcscca -I${top_builddir}/usr/lib/api \ -I${srcdir}/usr/lib/api usr_sbin_pkcscca_pkcscca_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/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/common/profile_obj.c usr/lib/common/attributes.c \ usr/lib/common/mech_rng.c usr/lib/common/pkcs_utils.c \ usr/lib/common/dlist.c usr/sbin/pkcscca/pkcscca.c \ usr/lib/common/utility_common.c usr/lib/common/ec_supported.c \ usr/lib/common/pin_prompt.c usr/lib/common/mech_openssl.c \ usr/lib/api/policyhelper.c usr/lib/common/pqc_supported.c \ usr/lib/common/btree.c usr/lib/common/sess_mgr.c \ usr/lib/common/mech_pqc.c nodist_usr_sbin_pkcscca_pkcscca_SOURCES = usr/lib/api/mechtable.c if AIX usr_sbin_pkcscca_pkcscca_SOURCES += usr/lib/common/aix/getopt_long.c nodist_usr_sbin_pkcscca_pkcscca_SOURCES += usr/lib/common/aix/getopt_long.c endif opencryptoki-opencryptoki-451d99c/usr/sbin/pkcsconf/000077500000000000000000000000001520105705100226765ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/usr/sbin/pkcsconf/pkcsconf.c000066400000000000000000001021111520105705100246440ustar00rootroot00000000000000/* * 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 "platform.h" #include "slotmgr.h" #include "pkcsconf_msg.h" #include "p11util.h" #include "defs.h" #include "mechtable.h" #include "uri.h" #include "pin_prompt.h" #if defined(_AIX) const char *__progname = "pkcsconf"; #endif #define LEEDS_DEFAULT_PIN "87654321" #define PIN_SIZE 80 #define BACK_SPACE 8 #define DELETE 127 #define LINE_FEED 10 #define CFG_UNUSED_1 0x0001 #define CFG_UNUSED_2 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 get_slot(char *); CK_RV display_pkcs11_info(void); CK_RV get_slot_list(CK_BOOL tokenPresent); CK_RV display_slot_info(int); CK_RV display_token_info(int); CK_RV display_mechanism_info(int); CK_RV init_token(int, const char *); CK_RV init_user_pin(int, const char *, const char *); CK_RV list_slot(int); CK_RV set_user_pin(int, CK_USER_TYPE, const char *, const char *); 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 int c, errflag = 0; const char *pin_user = NULL, *pin_so = NULL, *pin_new = NULL; char *buf_user = NULL, *buf_so = NULL, *buf_new = NULL; /* 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) { warnx("Must specify a single slot."); errflag++; } else { flags |= CFG_SLOT; in_slot = get_slot(optarg); if (in_slot < 0) { warnx("Must specify a decimal number as slot."); errflag++; } } break; case 'S': /* the SO pin */ if (pin_so) { warnx("Must specify a single SO PIN."); errflag++; } else { pin_so = optarg; } break; case 'U': /* the user pin */ if (pin_user) { warnx("Must specify a single user PIN."); errflag++; } else { pin_user = optarg; } break; case 'n': /* the new pin */ if (pin_new) { warnx("Must specify a single user PIN."); errflag++; } else { pin_new = optarg; } 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 (optind < argc) { warnx("unrecognized option --- '%s'", argv[optind]); errflag++; } 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((flags & (CFG_SLOT_INFO | CFG_LIST_SLOT)) == 0))) 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)) { warnx("Setting the SO and user PINs are mutually exclusive."); 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 (!pin_so) pin_so = pin_prompt(&buf_so, "Enter the SO PIN: "); rv = init_token(in_slot, pin_so); } /* 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 (!pin_so) pin_so = pin_prompt(&buf_so, "Enter the SO PIN: "); if (!pin_new) pin_new = pin_prompt_new(&buf_new, "Enter the new user PIN: ", "Re-enter the new user PIN: "); if (!pin_new) { warnx("Invalid new user pin"); rv = CKR_PIN_INVALID; goto done; } rv = init_user_pin(in_slot, pin_new, pin_so); /* partial cleanup/re-init for chained sub-functions */ pin_new = NULL; pin_free(&buf_new); } /* 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 (!pin_so) pin_so = pin_prompt(&buf_so, "Enter the SO PIN: "); if (!pin_new) pin_new = pin_prompt_new(&buf_new, "Enter the new SO PIN: ", "Re-enter the new SO PIN: "); if (!pin_new) { warnx("Invalid new so pin"); rv = CKR_PIN_INVALID; goto done; } rv = set_user_pin(in_slot, CKU_SO, pin_so, pin_new); /* partial cleanup/re-init for chained sub-functions */ pin_new = NULL; pin_free(&buf_new); } /* 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 (!pin_user) pin_user = pin_prompt(&buf_user, "Enter user PIN: "); if (!pin_new) pin_new = pin_prompt_new(&buf_new, "Enter the new user PIN: ", "Re-enter the new user PIN: "); if (!pin_new) { warnx("Invalid new user pin"); rv = CKR_PIN_INVALID; goto done; } rv = set_user_pin(in_slot, CKU_USER, pin_user, pin_new); } /* We are done, detach from shared memory, and free the memory we may have * allocated. */ done: pin_free(&buf_user); pin_free(&buf_so); pin_free(&buf_new); free(SlotList); if (FunctionPtr) FunctionPtr->C_Finalize(NULL); #ifndef WITH_SANITIZER if (dllPtr) dlclose(dllPtr); #endif return rv; } 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; } CK_RV check_user_and_group(void) { int i; uid_t euid; struct passwd *epw; struct group *grp; /* * Check for root user or Group PKCS#11 Membership. * Only these are allowed. */ euid = geteuid(); /* effective Root is ok */ if (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(PKCS_GROUP); if (grp == NULL) { return CKR_FUNCTION_FAILED; } if (getgid() == grp->gr_gid || getegid() == grp->gr_gid) return CKR_OK; /* Check if effective user is member of pkcs11 group */ epw = getpwuid(euid); for (i = 0; grp->gr_mem[i]; i++) { if ((epw && (strncmp(epw->pw_name, grp->gr_mem[i], strlen(epw->pw_name)) == 0))) return CKR_OK; } return CKR_FUNCTION_FAILED; } void print_info_uri(CK_INFO_PTR info) { struct p11_uri *uri; uri = p11_uri_new(); if (!uri) return; uri->info = info; printf("\tURI: %s\n", p11_uri_format(uri)); p11_uri_free(uri); uri = NULL; } 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) { warnx("Error getting PKCS#11 info: 0x%lX (%s)", 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); print_info_uri(&CryptokiInfo); return rc; } CK_RV get_slot_list(CK_BOOL tokenPresent) { CK_RV rc; // Return Code /* Find out how many tokens are present in slots */ rc = FunctionPtr->C_GetSlotList(tokenPresent, NULL_PTR, &SlotCount); if (rc != CKR_OK) { warnx("Error getting number of slots: 0x%lX (%s)", rc, p11_get_ckr(rc)); return rc; } if (SlotCount == 0) { warnx("C_GetSlotList returned 0 slots. Check that your tokens" " are installed correctly."); return -ENODEV; } /* Allocate enough space for the slots information */ SlotList = (CK_SLOT_ID_PTR) malloc(SlotCount * sizeof(CK_SLOT_ID)); rc = FunctionPtr->C_GetSlotList(tokenPresent, SlotList, &SlotCount); if (rc != CKR_OK) { warnx("Error getting slot list: 0x%lX (%s)", rc, p11_get_ckr(rc)); return rc; } return CKR_OK; } void display_mechanism_name(CK_MECHANISM_TYPE mech) { const struct mechrow *row = mechrow_from_numeric(mech); if (row) printf("(%s)", row->string); } 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 CK_ULONG i; /* For each slot find out how many mechanisms are supported */ rc = FunctionPtr->C_GetMechanismList(slot_id, NULL_PTR, &MechanismCount); if (rc != CKR_OK) { if (rc == CKR_TOKEN_NOT_PRESENT) return CKR_OK; warnx("Error getting number of mechanisms: 0x%lX (%s)", 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) { warnx("Error getting mechanisms list: 0x%lX (%s)", rc, p11_get_ckr(rc)); free(MechanismList); 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) { warnx("Error getting mechanisms info: 0x%lX (%s)", rc, p11_get_ckr(rc)); free(MechanismList); return rc; } printf("Mechanism #%lu\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 %c", SlotInfo->flags, SlotInfo->flags != 0 ? '(' : ' '); 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|"); if (SlotInfo->flags != 0) printf(")"); 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); } void print_slot_info_uri(int slot_id, CK_SLOT_INFO_PTR SlotInfo) { struct p11_uri *uri; uri = p11_uri_new(); if (!uri) return; uri->slot_id = slot_id; uri->slot_info = SlotInfo; printf("\tURI: %s\n", p11_uri_format(uri)); p11_uri_free(uri); uri = NULL; } 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) { warnx("Error getting slot info: 0x%lX (%s)", rc, p11_get_ckr(rc)); return rc; } print_slot_info(slot_id, &SlotInfo); print_slot_info_uri(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) { if (rc == CKR_TOKEN_NOT_PRESENT) return CKR_OK; warnx("Error getting slot info: 0x%lX (%s)", rc, p11_get_ckr(rc)); return rc; } print_slot_info(SlotList[lcv], &SlotInfo); print_slot_info_uri(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) { warnx("Error getting slot info: 0x%lX (%s)", 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) { warnx("Error getting slot info: 0x%lX (%s)", rc, p11_get_ckr(rc)); return rc; } /* Display the slot description */ printf("%lu:", 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|"); if (TokenInfo->flags & CKF_ERROR_STATE) printf("ERROR_STATE|"); if (TokenInfo->flags & CKF_SEED_RANDOM_REQUIRED) printf("SEED_RANDOM_REQUIRED|"); if (TokenInfo->flags & CKF_ASYNC_SESSION_SUPPORTED) printf("ASYNC_SESSION_SUPPORTED|"); 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); } void print_token_info_uri(const CK_TOKEN_INFO_PTR TokenInfo) { struct p11_uri *uri; uri = p11_uri_new(); if (!uri) return; uri->token_info = TokenInfo; printf("\tURI: %s\n", p11_uri_format(uri)); p11_uri_free(uri); uri = NULL; } 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) { warnx("Error getting token info: 0x%lX (%s)", rc, p11_get_ckr(rc)); return rc; } print_token_info(slot_id, &TokenInfo); print_token_info_uri(&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) { if (rc == CKR_TOKEN_NOT_PRESENT) return CKR_OK; warnx("Error getting token info: 0x%lX (%s)", rc, p11_get_ckr(rc)); return rc; } print_token_info(SlotList[lcv], &TokenInfo); print_token_info_uri(&TokenInfo); } return CKR_OK; } CK_RV init_token(int slot_id, const char *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_CHAR label[32], // What we want to set the Label of the card to enteredlabel[33]; // Max size of 32 + carriage return; /* 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, (CK_CHAR_PTR)pin, strlen(pin), label); if (rc != CKR_OK) { if (rc == CKR_PIN_INCORRECT) warnx("Incorrect PIN entered."); else warnx("Error initializing token: 0x%lX (%s)", rc, p11_get_ckr(rc)); return rc; } return CKR_OK; } CK_RV init_user_pin(int slot_id, const char *pin, const char *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 /* 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) { warnx("Error opening session: 0x%lX (%s)", rc, p11_get_ckr(rc)); 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, (CK_CHAR_PTR)sopin, strlen(sopin)); if (rc != CKR_OK) { if (rc == CKR_PIN_INCORRECT) warnx("Incorrect PIN entered."); else warnx("Error logging in: 0x%lX (%s)", rc, p11_get_ckr(rc)); return rc; } /* Call the function to Init the PIN */ rc = FunctionPtr->C_InitPIN(session_handle, (CK_CHAR_PTR)pin, strlen(pin)); if (rc != CKR_OK) warnx("Error setting PIN: 0x%lX (%s)", rc, p11_get_ckr(rc)); /* Logout so that others can use the PIN */ rc = FunctionPtr->C_Logout(session_handle); if (rc != CKR_OK) warnx("Error logging out: 0x%lX (%s)", rc, p11_get_ckr(rc)); /* Close the session */ rc = FunctionPtr->C_CloseSession(session_handle); if (rc != CKR_OK) { warnx("Error closing session: 0x%lX (%s)", rc, p11_get_ckr(rc)); return rc; } return CKR_OK; } CK_RV set_user_pin(int slot_id, CK_USER_TYPE user, const char *oldpin, const char *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 /* NOTE: This function is used for both the setting of the SO and USER pins, * the CK_USER_TYPE specifes which we are changing. */ /* 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) { warnx("Error opening session: 0x%lX (%s)", rc, p11_get_ckr(rc)); return rc; } /* Login to the session we just created as the pkcs11 passed in USER type */ rc = FunctionPtr->C_Login(session_handle, user, (CK_CHAR_PTR)oldpin, strlen(oldpin)); if (rc != CKR_OK) { if (rc == CKR_PIN_INCORRECT) warnx("Incorrect PIN entered."); else warnx("Error logging in: 0x%lX (%s)", rc, p11_get_ckr(rc)); return rc; } /* set the new PIN */ rc = FunctionPtr->C_SetPIN(session_handle, (CK_CHAR_PTR)oldpin, strlen(oldpin), (CK_CHAR_PTR)newpin, strlen(newpin)); if (rc != CKR_OK) warnx("Error setting PIN: 0x%lX (%s)\n", rc, p11_get_ckr(rc)); /* and of course clean up after ourselves */ rc = FunctionPtr->C_CloseSession(session_handle); if (rc != CKR_OK) { warnx("Error closing session: 0x%lX (%s)\n", rc, p11_get_ckr(rc)); return rc; } return CKR_OK; } CK_RV init(void) { CK_RV rc = CKR_OK; // Return Code void (*symPtr) (CK_FUNCTION_LIST_PTR_PTR ppFunctionList); // 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(OCK_API_LIBNAME, DYNLIB_LDFLAGS); if (!dllPtr) { warnx("Error loading PKCS#11 library"); warnx("dlopen error: %s", dlerror()); return -1; } /* Get the list of the PKCS11 functions this token support */ *(void **)(&symPtr) = dlsym(dllPtr, "C_GetFunctionList"); if (!symPtr) { warnx("Error getting function list, symbol not found, error: %s", dlerror()); return -1; } symPtr(&FunctionPtr); if (!FunctionPtr) { warnx("Error getting function list, C_GetFunctionList returned NULL"); return -1; } /* 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) { warnx("Error initializing the PKCS11 library: 0x%lX (%s)", 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"); } } return 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); } opencryptoki-opencryptoki-451d99c/usr/sbin/pkcsconf/pkcsconf.mk000066400000000000000000000015341520105705100250400ustar00rootroot00000000000000sbin_PROGRAMS += usr/sbin/pkcsconf/pkcsconf noinst_HEADERS += usr/sbin/pkcsconf/pkcsconf_msg.h usr_sbin_pkcsconf_pkcsconf_LDFLAGS = -lpthread -ldl -lcrypto if AIX usr_sbin_pkcsconf_pkcsconf_LDFLAGS += -Wl,-blibpath:$(libdir)/opencryptoki:$(libdir)/opencryptoki/stdll:/usr/lib:/usr/lib64 endif 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 -I${srcdir}/usr/lib/api \ -I${top_builddir}/usr/lib/api usr_sbin_pkcsconf_pkcsconf_SOURCES = \ usr/lib/common/p11util.c \ usr/lib/common/buffer.c \ usr/lib/common/uri.c \ usr/lib/common/pin_prompt.c \ usr/sbin/pkcsconf/pkcsconf.c if AIX usr_sbin_pkcsconf_pkcsconf_SOURCES += usr/lib/common/aix/err.c endif nodist_usr_sbin_pkcsconf_pkcsconf_SOURCES = usr/lib/api/mechtable.c opencryptoki-opencryptoki-451d99c/usr/sbin/pkcsconf/pkcsconf_msg.h000066400000000000000000000027751520105705100255360ustar00rootroot00000000000000/* * 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_ENCAPSULATE", CKF_ENCAPSULATE }, { "CKF_DECAPSULATE", CKF_DECAPSULATE }, { "CKF_EC_F_P", CKF_EC_F_P }, { "CKF_EC_F_2M", CKF_EC_F_2M }, { "CKF_EC_ECPARAMETERS", CKF_EC_ECPARAMETERS }, { "CKF_EC_OID", CKF_EC_OID }, { "CKF_EC_UNCOMPRESS", CKF_EC_UNCOMPRESS }, { "CKF_EC_COMPRESS", CKF_EC_COMPRESS }, { "CKF_EC_CURVENAME", CKF_EC_CURVENAME }, { "CKF_EXTENSION", CKF_EXTENSION }, { NULL_PTR, 0xFFFFFFFF } }; #endif opencryptoki-opencryptoki-451d99c/usr/sbin/pkcsep11_migrate/000077500000000000000000000000001520105705100242275ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/usr/sbin/pkcsep11_migrate/pkcsep11_migrate.c000066400000000000000000000456551520105705100275510ustar00rootroot00000000000000/* * 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. */ #include #include #include #include #include #include #include #include #define OCK_NO_EP11_DEFINES #include "../../include/pkcs11types.h" #include "../../lib/common/p11util.h" #include "../../lib/ep11_stdll/ep11_func.h" #include "pin_prompt.h" #define EP11SHAREDLIB_NAME "OCK_EP11_LIBRARY" #define EP11SHAREDLIB_V4 "libep11.so.4" #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]; 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; typedef struct { short format; short length; short apqns[512]; } __attribute__ ((packed)) ep11_target_t; #define BLOBSIZE 2048*4 static CK_RV ep11_reencrypt(target_t target, CK_BYTE *blob, CK_ULONG blob_len) { CK_BYTE req[BLOBSIZE]; CK_BYTE resp[BLOBSIZE]; CK_LONG req_len; size_t resp_len; struct XCPadmresp rb; struct XCPadmresp lrb; CK_RV rc; memset(&rb, 0, sizeof(rb)); memset(&lrb, 0, sizeof(lrb)); rb.domain = domain; lrb.domain = domain; resp_len = BLOBSIZE; req_len = _xcpa_cmdblock(req, BLOBSIZE, XCP_ADM_REENCRYPT, &rb, NULL, blob, blob_len); if (req_len < 0) { fprintf(stderr, "reencrypt cmd block construction failed\n"); return -4; } 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); return -5; } if (_xcpa_internal_rv(resp, resp_len, &lrb, &rc) < 0) { fprintf(stderr, "reencryption response malformed: %lx\n", rc); return -6; } if (rc != 0) { fprintf(stderr, "reencryption failed: %lx\n", rc); return -7; } if (blob_len != lrb.pllen) { fprintf(stderr, "reencryption blob size changed: %lx %lx %lx %lx\n", blob_len, lrb.pllen, resp_len, req_len); return -8; } memcpy(blob, lrb.payload, blob_len); return 0; } static int reencrypt(CK_SESSION_HANDLE session, CK_ULONG obj, CK_KEY_TYPE keytype, CK_BYTE *old, CK_ULONG old_len) { 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); } if (rc != CKR_OK) { fprintf(stderr, "reencryption C_GetAttributeValue failed: obj %lx rc: %lx\n", obj, rc); 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) { fprintf(stderr, "reencryption m_add_module failed: rc: %lx\n",rc); return -2; } } 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; } fprintf(stderr, "going to reencrpyt key %lx with blob len %lx: '%s'\n", obj, old_len, name); if (old_len > sizeof(blob)) { fprintf(stderr, "reencryption blob is too large: %lu\n", old_len); rc = -3; goto out; } blob_len = old_len; memcpy(blob, old, blob_len); if (keytype == CKK_AES_XTS) { /* An AES XTS key consists of 2 blobs concatenated to each other */ rc = ep11_reencrypt(target, blob, blob_len / 2); if (rc != 0) goto out; rc = ep11_reencrypt(target, blob + blob_len / 2, blob_len / 2); if (rc != 0) goto out; } else { rc = ep11_reencrypt(target, blob, blob_len); if (rc != 0) goto out; } 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 = -9; 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(void) { 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; } static int get_user_pin(CK_BYTE *dest) { int ret = -1; const char *userpin = NULL; char *buf_user = NULL; size_t userpinlen; userpin = pin_prompt(&buf_user, "Enter the USER PIN: "); if (!userpin) { fprintf(stderr, "Could not get USER PIN.\n"); goto out; } userpinlen = strlen(userpin); 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); goto out; } memcpy(dest, userpin, userpinlen + 1); ret = 0; out: pin_free(&buf_user); return ret; } static int do_GetFunctionList(void) { CK_RV rc; CK_RV (*func_list)(CK_FUNCTION_LIST_PTR_PTR ppFunctionList) = NULL; void *d; char *evar; char *evar_default = "libopencryptoki.so"; evar = secure_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) { void *lib_ep11; char *ep11_lib_name; char *errstr; ep11_lib_name = secure_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_V4; lib_ep11 = dlopen(ep11_lib_name, DLOPEN_FLAGS); if (lib_ep11 == NULL) { /* Try version 3 instead */ 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[.4|.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, keytype, (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; } opencryptoki-opencryptoki-451d99c/usr/sbin/pkcsep11_migrate/pkcsep11_migrate.mk000066400000000000000000000012331520105705100277160ustar00rootroot00000000000000sbin_PROGRAMS += usr/sbin/pkcsep11_migrate/pkcsep11_migrate usr_sbin_pkcsep11_migrate_pkcsep11_migrate_LDFLAGS = -lc -ldl -lpthread -lcrypto 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 -I${srcdir}/usr/lib/api \ -I${top_builddir}/usr/lib/api usr_sbin_pkcsep11_migrate_pkcsep11_migrate_SOURCES = \ usr/lib/common/p11util.c usr/lib/common/pin_prompt.c \ usr/sbin/pkcsep11_migrate/pkcsep11_migrate.c nodist_usr_sbin_pkcsep11_migrate_pkcsep11_migrate_SOURCES = \ usr/lib/api/mechtable.c opencryptoki-opencryptoki-451d99c/usr/sbin/pkcsep11_session/000077500000000000000000000000001520105705100242625ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/usr/sbin/pkcsep11_session/pkcsep11_session.c000066400000000000000000001161541520105705100276300ustar00rootroot00000000000000/* * 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define OCK_NO_EP11_DEFINES #include "pkcs11types.h" #include "defs.h" #include "host_defs.h" #include "h_extern.h" #include "ep11_specific.h" #include "pin_prompt.h" #include "p11util.h" #define EP11_SESSION_ID_SIZE 16 #define PKCS11_MAX_PIN_LEN 128 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, ep11_serialno_t *serial_numbers, CK_ULONG num_serial_numbers, pid_t pid, CK_DATE *date); CK_FUNCTION_LIST *funcs; m_init_t dll_m_init; 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 #define ACTION_FIPSPIN 4 #define ACTION_STATUS 5 static int get_user_pin(CK_BYTE *dest) { int ret = -1; const char *userpin; char *buf_user = NULL; userpin = pin_prompt(&buf_user, "Enter the USER PIN: "); if (!userpin) { fprintf(stderr, "Could not get USER PIN.\n"); goto out; } if (strlen(userpin) > PKCS11_MAX_PIN_LEN) { fprintf(stderr, "The USER PIN must be less than %d chars in length.\n", (int) PKCS11_MAX_PIN_LEN); goto out; } memcpy(dest, userpin, strlen(userpin) + 1); ret = 0; out: pin_free(&buf_user); return ret; } static int get_pin(CK_BYTE *dest, const char *name) { int ret = -1; const char *pin = NULL; char *buf = NULL; size_t pinlen; char *msg1 = NULL, *msg2 = NULL; if (asprintf(&msg1, "Enter the new %s: ", name) < 0 || asprintf(&msg2, "Re-enter the new %s: ", name) < 0) { fprintf(stderr, "Failed to allocate memory.\n"); goto out; } pin = pin_prompt_new(&buf, msg1, msg2); if (!pin) { fprintf(stderr, "Could not get %sN.\n", name); goto out; } pinlen = strlen(pin); if (pinlen < XCP_MIN_PINBYTES) { fprintf(stderr, "The %s must be at least %d chars in length.\n", name, (int) XCP_MIN_PINBYTES); goto out; } if (pinlen > XCP_MAX_PINBYTES) { fprintf(stderr, "The %s must be less than %d chars in length.\n", name, (int) XCP_MAX_PINBYTES); goto out; } memcpy(dest, pin, pinlen + 1); ret = 0; out: pin_free(&buf); if (msg1 != NULL) free(msg1); if(msg2 != NULL) free(msg2); return ret; } static int do_GetFunctionList(void) { CK_RV rc; CK_RV (*func_list)(CK_FUNCTION_LIST_PTR_PTR ppFunctionList) = NULL; void *d; char *evar; char *evar_default = "libopencryptoki.so"; evar = secure_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|fipspin|status [-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 if (strcmp(argv[1], "fipspin") == 0) { action = ACTION_FIPSPIN; } else if (strcmp(argv[1], "status") == 0) { action = ACTION_STATUS; } 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 (action == ACTION_STATUS) { printf("Argument '%s' not accepted for 'status' command\n", argv[i]); return -1; } 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 (action != ACTION_STATUS && 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 get_serial_number(target_t target, ep11_serialno_t serial_number) { CK_IBM_XCP_INFO xcp_info; CK_ULONG xcp_info_len = sizeof(xcp_info); CK_RV rc; rc = dll_m_get_xcp_info(&xcp_info, &xcp_info_len, CK_IBM_XCPQ_MODULE, 0, target); if (rc != CKR_OK) return rc; memcpy(serial_number, xcp_info.serialNumber, sizeof(ep11_serialno_t)); return CKR_OK; } static void remove_serial_number(ep11_serialno_t serial_number, ep11_serialno_t *serial_numbers, CK_ULONG *num_serial_numbers) { CK_ULONG i; CK_BOOL found = FALSE; for(i = 0; i < *num_serial_numbers; i++) { if (memcmp(serial_numbers[i], serial_number, sizeof(ep11_serialno_t)) == 0) { found = TRUE; break; } } if (!found) return; memmove(serial_numbers[i], serial_numbers[i + 1], (*num_serial_numbers - i) * sizeof(ep11_serialno_t)); memset(serial_numbers[*num_serial_numbers - 1], 0, sizeof(ep11_serialno_t)); (*num_serial_numbers)--; return; } struct logout_data { CK_BYTE *pin_blob; CK_ULONG pin_blob_size; ep11_serialno_t *serial_numbers; CK_ULONG num_serial_numbers; }; 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; struct logout_data *data = handler_data; ep11_serialno_t serial_number; 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 = get_serial_number(target, serial_number); if (rc != CKR_OK) { fprintf(stderr, "WARNING: Querying adapter %02X.%04X failed: 0x%lx [%s]\n", adapter, domain, rc, p11_get_ckr(rc)); error = rc; goto out; } rc = dll_m_Logout(data->pin_blob, data->pin_blob_size, 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; goto out; } remove_serial_number(serial_number, data->serial_numbers, &data->num_serial_numbers); out: 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/config", SYSFS_DEVICES_AP, name); rc = file_fgets(fname, buf, sizeof(buf)); if (rc == CKR_OK && strcmp(buf, "1") != 0) return CKR_FUNCTION_FAILED; sprintf(fname, "%s%s/chkstop", SYSFS_DEVICES_AP, name); rc = file_fgets(fname, buf, sizeof(buf)); if (rc == CKR_OK && strcmp(buf, "0") != 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; } 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 void print_session_info(CK_BYTE *session_id, CK_ULONG session_id_len, ep11_target_t *ep11_targets, ep11_serialno_t *serial_numbers, CK_ULONG num_serial_numbers, pid_t pid, CK_DATE *date) { CK_ULONG i; 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 (ep11_targets->length == 0) { printf("\tAPQNs:\tANY\n"); } else { printf("\tAPQNs:\n"); for (i = 0; i < (CK_ULONG)ep11_targets->length; i++) printf("\t\t%02X.%04X\n", ep11_targets->apqns[2 * i], ep11_targets->apqns[2 * i + 1]); } if (num_serial_numbers) { printf("\tAdapter serial numbers:\n"); for (i = 0; i < num_serial_numbers; i++) printf("\t\t%.16s\n", serial_numbers[i]); } } static CK_RV update_ep11_object(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE obj, ep11_target_t *ep11_targets, ep11_serialno_t *serial_numbers, CK_ULONG num_serial_numbers) {; CK_RV rc; CK_BYTE *app_data = NULL; CK_ULONG app_data_len; CK_ATTRIBUTE attr = { CKA_APPLICATION, NULL, 0 }; app_data_len = sizeof(ep11_target_t) + num_serial_numbers * sizeof(ep11_serialno_t); app_data = malloc(app_data_len); if (app_data == NULL) { fprintf(stderr, "Failed to allocate memory\n"); rc = CKR_HOST_MEMORY; goto out; } memcpy(app_data, ep11_targets, sizeof(ep11_target_t)); if (num_serial_numbers > 0) memcpy(app_data + sizeof(ep11_target_t), serial_numbers, num_serial_numbers * sizeof(ep11_serialno_t)); attr.pValue = app_data; attr.ulValueLen = app_data_len; rc = funcs->C_SetAttributeValue(session, obj, &attr, 1); if (rc != CKR_OK) { fprintf(stderr, "C_SetAttributeValue() rc = 0x%02lx [%s]\n", rc, p11_get_ckr(rc)); } out: if (app_data != NULL) free(app_data); return rc; } 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, ep11_serialno_t *serial_numbers, CK_ULONG num_serial_numbers, pid_t pid, CK_DATE *date) { CK_RV rc; struct logout_data data; CK_ULONG i; print_session_info(session_id, session_id_len, ep11_targets, serial_numbers, num_serial_numbers, pid, date); if (is_process_running(pid)) { printf("\tSession is not logged out, process %u is still running\n", pid); return CKR_OK; } error = CKR_OK; data.pin_blob = pin_blob; data.pin_blob_size = pin_blob_size; data.serial_numbers = serial_numbers; data.num_serial_numbers = num_serial_numbers; rc = handle_all_ep11_cards(ep11_targets, logout_handler, &data); 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, "\tWARNING: Not all APQNs were successfully logged out.\n"); if (!force) fprintf(stderr, "\t Session is not deleted. Specify -force to " "delete it anyway.\n"); } if ((error == CKR_OK && data.num_serial_numbers == 0) || force) { 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; } } else { rc = update_ep11_object(session, obj, ep11_targets, data.serial_numbers, data.num_serial_numbers); if (rc != CKR_OK) return rc; } if (!force) { if (data.num_serial_numbers == 0) { printf("\tSession logged out successfully\n"); count++; } else { fprintf(stderr, "\tWARNING: Session not logged out on the adapters with\n" "\t the following serial numbers:\n"); for (i = 0; i < data.num_serial_numbers; i++) printf("\t\t\t%.16s\n", data.serial_numbers[i]); fprintf(stderr, "\t Session is not deleted. Specify -force to " "delete it anyway.\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, ep11_serialno_t *serial_numbers, CK_ULONG num_serial_numbers, pid_t pid, CK_DATE *date) { UNUSED(session); UNUSED(obj); UNUSED(pin_blob); UNUSED(pin_blob_size); print_session_info(session_id, session_id_len, ep11_targets, serial_numbers, num_serial_numbers, pid, date); 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]; struct { ep11_target_t ep11_targets; ep11_serialno_t serial_numbers[MAX_APQN]; } app_data; CK_ULONG num_serial_numbers = 0; 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, &app_data, sizeof(app_data) }, // keep at index 2 { 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; } num_serial_numbers = (attrs[2].ulValueLen - sizeof(ep11_target_t)) / sizeof(ep11_serialno_t); /* 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), &app_data.ep11_targets, app_data.serial_numbers, num_serial_numbers, 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 ck_true = TRUE; CK_ATTRIBUTE session_template[] = { { CKA_CLASS, &class, sizeof(class) }, { CKA_TOKEN, &ck_true, sizeof(ck_true) }, { CKA_PRIVATE, &ck_true, sizeof(ck_true) }, { CKA_HIDDEN, &ck_true, sizeof(ck_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_pin_object(CK_SESSION_HANDLE session, CK_HW_FEATURE_TYPE type, 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_BBOOL ck_true = TRUE; CK_ATTRIBUTE vhsmpin_template[] = { { CKA_CLASS, &class, sizeof(class) }, { CKA_TOKEN, &ck_true, sizeof(ck_true) }, { CKA_PRIVATE, &ck_true, sizeof(ck_true) }, { CKA_HIDDEN, &ck_true, sizeof(ck_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 const char *hwtype2str(CK_HW_FEATURE_TYPE type) { switch (type) { case CKH_IBM_EP11_VHSMPIN: return "VHSM PIN"; case CKH_IBM_EP11_FIPSPIN: return "FIPS PIN"; default: return "unknown"; } } static CK_RV set_pin(CK_SESSION_HANDLE session, CK_HW_FEATURE_TYPE type) { CK_RV rc; CK_BYTE pin[XCP_MAX_PINBYTES + 1]; CK_OBJECT_HANDLE obj = CK_INVALID_HANDLE; CK_OBJECT_CLASS class = CKO_HW_FEATURE; char subject[200]; CK_BBOOL ck_true = TRUE; if (get_pin(pin, hwtype2str(type))) { fprintf(stderr, "get_pin() failed\n"); return CKR_FUNCTION_FAILED; } snprintf(subject, sizeof(subject), "EP11 %s Object", hwtype2str(type)); CK_ATTRIBUTE attrs[] = { { CKA_CLASS, &class, sizeof(class) }, { CKA_TOKEN, &ck_true, sizeof(ck_true) }, { CKA_PRIVATE, &ck_true, sizeof(ck_true) }, { CKA_HIDDEN, &ck_true, sizeof(ck_true) }, { CKA_HW_FEATURE_TYPE, &type, sizeof(type) }, { CKA_SUBJECT, &subject, strlen(subject) }, { CKA_VALUE, pin, strlen((char *)pin) }, }; rc = find_pin_object(session, type, &obj); if (rc != CKR_OK) { fprintf(stderr, "find_pin_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("%s successfully set.\n", hwtype2str(type)); return CKR_OK; } static CK_RV status_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; uint32_t *res = NULL; CK_ULONG reslen = 0; CK_ULONG i; uint32_t caps = 0; CK_RV rc; CK_BBOOL found = CK_FALSE; UNUSED(handler_data); 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) { fprintf(stderr, "dll_m_add_module (EXT_CAPLIST) failed: rc=0x%lx\n", rc); 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; } printf("APQN %02x.%04x:\n", adapter, domain); reslen = sizeof(caps); rc = dll_m_get_xcp_info(&caps, &reslen, CK_IBM_XCPQ_EXT_CAPS, 0, target); if (rc != CKR_OK || reslen != sizeof(caps)) { fprintf(stderr, "dll_m_get_xcp_info (EXT_CAPS) failed: rc=0x%lx\n", rc); goto done; } if (caps == 0) goto no_info; reslen = caps * sizeof(uint32_t) * 2; res = calloc(1, reslen); if (res == NULL) { fprintf(stderr, "Failed to allocate memory\n"); goto done; } rc = dll_m_get_xcp_info(res, &reslen, CK_IBM_XCPQ_EXT_CAPLIST, 0, target); if (rc != CKR_OK) { fprintf(stderr, "dll_m_get_xcp_info (EXT_CAPLIST) failed: rc=0x%lx\n", rc); goto done; } for (i = 0; i < reslen / 4; i += 2) { if (res[i] == CK_IBM_XCPXQ_MAX_SESSIONS) { printf(" Max Sessions: %u\n", res[i + 1]); found = CK_TRUE; } else if (res[i] == CK_IBM_XCPXQ_AVAIL_SESSIONS) { printf(" Available Sessions: %u\n", res[i + 1]); found = CK_TRUE; } } no_info: if (!found) printf(" Information not available\n"); done: if (dll_m_rm_module != NULL) dll_m_rm_module(&module, target); if (res != NULL) free(res); return CKR_OK; } static CK_RV show_ep11_status(void) { ep11_target_t any_target = { 0, 0, { 0 } }; CK_RV rc; rc = handle_all_ep11_cards(&any_target, status_handler, NULL); if (rc != CKR_OK) { fprintf(stderr, "handle_all_ep11_cards() rc = 0x%02lx [%s]\n", rc, p11_get_ckr(rc)); return rc; } 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) { void *lib_ep11; char *ep11_lib_name; char *errstr; ep11_lib_name = secure_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_V4; lib_ep11 = dlopen(ep11_lib_name, DLOPEN_FLAGS); if (lib_ep11 == NULL) { /* Try version 3 instead */ 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[.4|.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_init) = dlsym(lib_ep11, "m_init"); *(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_init == NULL || 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 = dll_m_init(); if (rc != CKR_OK) { fprintf(stderr, "ERROR dll_m_init() Failed, rx = 0x%0x\n", rc); return rc; } rc = get_ep11_library_version(&lib_version); if (rc != CKR_OK) return rc; if (action == ACTION_STATUS) { rc = show_ep11_status(); 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) goto done; rc = funcs->C_CancelFunction(hsess); if (rc != CKR_FUNCTION_NOT_PARALLEL) goto done; } if (!is_ep11_token(SLOT_ID)) { fprintf(stderr, "ERROR Slot %lu is not an EP11 token\n", SLOT_ID); rc = CKR_FUNCTION_FAILED; goto done; } 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; goto done; } 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)); goto done; } 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)); goto done; } switch (action) { case ACTION_SHOW: rc = show_sessions(session); break; case ACTION_LOGOUT: rc = logout_sessions(session); break; case ACTION_VHSMPIN: rc = set_pin(session, CKH_IBM_EP11_VHSMPIN); break; case ACTION_FIPSPIN: rc = set_pin(session, CKH_IBM_EP11_FIPSPIN); break; } funcs->C_Logout(session); done: funcs->C_CloseAllSessions(SLOT_ID); funcs->C_Finalize(NULL); return rc; } opencryptoki-opencryptoki-451d99c/usr/sbin/pkcsep11_session/pkcsep11_session.mk000066400000000000000000000014411520105705100300050ustar00rootroot00000000000000sbin_PROGRAMS += usr/sbin/pkcsep11_session/pkcsep11_session usr_sbin_pkcsep11_session_pkcsep11_session_LDFLAGS = -lc -ldl -lpthread -lcrypto 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 -I${srcdir}/usr/lib/api \ -I${top_builddir}/usr/lib/api -I${top_builddir}/usr/lib/config \ -I${srcdir}/usr/lib/config -I${top_builddir}/usr/lib/ep11_stdll \ -I${srcdir}/usr/lib/ep11_stdll usr_sbin_pkcsep11_session_pkcsep11_session_SOURCES = \ usr/lib/common/p11util.c usr/lib/common/pin_prompt.c \ usr/sbin/pkcsep11_session/pkcsep11_session.c nodist_usr_sbin_pkcsep11_session_pkcsep11_session_SOURCES = \ usr/lib/api/mechtable.c opencryptoki-opencryptoki-451d99c/usr/sbin/pkcshsm_mk_change/000077500000000000000000000000001520105705100245345ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/usr/sbin/pkcshsm_mk_change/pkcshsm_mk_change.c000066400000000000000000001461301520105705100303510ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2022 * * This program is provided under the terms of the Common Public License, * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this * software constitutes recipient's acceptance of CPL-1.0 terms which can be * found in the file LICENSE file or at * https://opensource.org/licenses/cpl1.0.php */ /* * pkcshsm_mk_change - A tool to manage and control the re-enciphering of * secure keys for a concurrent HSM master key change. */ #include "platform.h" #include #include #include #include #include #include #include #include #include "pkcs11types.h" #include "p11util.h" #include "event_client.h" #include "pkcs_utils.h" #include "hsm_mk_change.h" #include "pin_prompt.h" #if defined(_AIX) #include #define ELIBACC EINVAL const char *__progname = "pkcshsm_mk_change"; #endif #define CMD_REENCIPHER 1 #define CMD_FINALIZE 2 #define CMD_CANCEL 3 #define CMD_LIST 4 #define CCA_MKVP_LENGTH 8 #define EP11_WKVP_LENGTH 16 #define UNUSED(var) ((void)(var)) pkcs_trace_level_t trace_level = TRACE_LEVEL_NONE; static void *dll = NULL; static CK_FUNCTION_LIST *func_list = NULL; static int event_fd = -1; static struct apqn *apqns = NULL; static unsigned int num_apqns = 0; static const char *id = NULL; static unsigned char ep11_wkvp[EP11_WKVP_LENGTH] = { 0 }; static bool ep11_wkvp_set = false; static unsigned char cca_sym_mkvp[CCA_MKVP_LENGTH] = { 0 }; static bool cca_sym_mkvp_set = false; static unsigned char cca_asym_mkvp[CCA_MKVP_LENGTH] = { 0 }; static bool cca_asym_mkvp_set = false; static unsigned char cca_aes_mkvp[CCA_MKVP_LENGTH] = { 0 }; static bool cca_aes_mkvp_set = false; static unsigned char cca_apka_mkvp[CCA_MKVP_LENGTH] = { 0 }; static bool cca_apka_mkvp_set = false; struct token_info { CK_SLOT_ID id; bool present; CK_TOKEN_INFO info; bool affected; CK_SESSION_HANDLE session; }; CK_ULONG num_affected_slots = 0; CK_SLOT_ID_PTR affected_slots = NULL; static unsigned int num_tokens = 0; static struct token_info *tokens = NULL; struct hsm_mk_change_op op; struct hsm_mkvp mkvps[HSM_MK_TYPE_MAX]; static void usage(char *progname) { printf("Usage: %s COMMAND [OPTIONS]\n\n", progname); printf("Manage and control the re-enciphering of secure keys for a concurrent\n" "HSM master key change.\n\n"); printf("COMMAND:\n"); printf(" reencipher initiate a master key change operation for the\n" " specified APQNs and master key types and re-encipher\n" " all session and token key objects of the affected\n" " tokens.\n"); printf(" finalize finalize a master key change operation when the\n" " new master key has been activated on the APQNs.\n"); printf(" cancel cancel a master key change operation.\n"); printf(" list list currently active master key change operations.\n"); printf("\nOPTIONS:\n"); printf(" -a, --apqns APQNS specifies a comma separated list of APQNs for\n" " which a master key change is to be performed.\n" #if !defined(__s390__) " MUST be '0.0' on AIX, Linux on x64, and Linux on\n" " Power for operation to succeed.\n" #endif " Only valid with the 'reencipher' command.\n"); printf(" -e, --ep11-wkvp WKVP specifies the EP11 wrapping key verification pattern\n" " of the new, to be set EP11 wrapping key as a\n" " 16 bytes hex string.\n" " Only valid with the 'reencipher' command.\n"); printf(" -s, --cca-sym-mkvp MKVP specifies the CCA master key verification pattern\n" " of the new, to be set CCA SYM master key as a\n" " 8 bytes hex string.\n" " Only valid with the 'reencipher' command.\n"); printf(" -S, --cca-asym-mkvp MKVP specifies the CCA master key verification pattern\n" " of the new, to be set CCA ASYM master key as a\n" " 8 bytes hex string.\n" " Only valid with the 'reencipher' command.\n"); printf(" -A, --cca-aes-mkvp MKVP specifies the CCA master key verification pattern\n" " of the new, to be set CCA AES master key as a\n" " 8 bytes hex string.\n" " Only valid with the 'reencipher' command.\n"); printf(" -p, --cca-apka-mkvp MKVP specifies the CCA master key verification pattern\n" " of the new, to be set CCA APKA master key as a\n" " 8 bytes hex string.\n" " Only valid with the 'reencipher' command.\n"); printf(" -i, --id OPERATION-ID specifies the ID of the master key change operation\n" " to finalize, cancel, or list.\n"); printf(" -v, --verbose LEVEL set verbose level (optional):\n"); printf(" none (default), error, warn, info, devel, debug\n"); printf(" -h, --help display help information.\n"); return; } static int parse_apqn(char *apqn) { unsigned int card, domain, num; struct apqn *tmp; TRACE_DEVEL("APQN: '%s'\n", apqn); if (sscanf(apqn, "%x.%x%n", &card, &domain, (int *)&num) != 2 || num != strlen(apqn) || card > 0xff || domain > 0xFFFF) { warnx("Invalid APQN specification: %s", apqn); return EINVAL; } tmp = realloc(apqns, (num_apqns + 1) * sizeof(struct apqn)); if (tmp == NULL) { warnx("Failed to allocate memory for APQN list"); return ENOMEM; } tmp[num_apqns].card = card; tmp[num_apqns].domain = domain; num_apqns++; apqns = tmp; return 0; } static int parse_apqns(char *apqns) { char *saveptr, *tok; int rc = 0; TRACE_DEVEL("APQNs: '%s'\n", apqns); tok = strtok_r(apqns, ", ", &saveptr); while(tok != NULL) { rc = parse_apqn(tok); if (rc != 0) return rc; tok = strtok_r(NULL, ", ", &saveptr); } if (apqns == NULL || num_apqns == 0) { warnx("No APQNs specified with option -a/--apqns"); return EINVAL; } return 0; } static int parse_mkvp(char *mkvp_str, size_t min_size, unsigned char *mkvp, bool *set, const char *option) { unsigned int i, val; TRACE_DEVEL("MKVP: '%s'\n", mkvp_str); if (strncasecmp(mkvp_str, "0x", 2) == 0) mkvp_str += 2; if (strlen(mkvp_str) < min_size * 2) { warnx("option %s must specify at least %zu bytes", option, min_size); return EINVAL; } for (i = 0; i < min_size; i++) { if (sscanf(mkvp_str + (i * 2), "%02x", &val) != 1) { warnx("option %s does not specify a valid hex string", option); return EINVAL; } mkvp[i] = val; } if (strlen(mkvp_str) > min_size * 2) warnx("option %s specifies more than %zu bytes, remaining bytes are ignored", option, min_size); *set = true; return 0; } static const char *get_mk_type_string(enum hsm_mk_type mk_type) { switch (mk_type) { case HSM_MK_TYPE_EP11: return "EP11 WK"; case HSM_MK_TYPE_CCA_SYM: return"CCA SYM"; case HSM_MK_TYPE_CCA_ASYM: return"CCA ASYM"; case HSM_MK_TYPE_CCA_AES: return "CCA_AES"; case HSM_MK_TYPE_CCA_APKA: return "CCA APKA"; default: return "UNKNOWN"; } } static CK_RV check_intersecting_ops_cb(struct hsm_mk_change_op *other_op, void *private) { unsigned int i, k; bool *error = private; for (i = 0; i < op.info.num_apqns; i++) { if (hsm_mk_change_apqns_find(other_op->info.apqns, other_op->info.num_apqns, op.info.apqns[i].card, op.info.apqns[i].domain)) { /* Same APQN found */ for (k = 0; k < op.info.num_mkvps; k++) { if (hsm_mk_change_mkvps_find(other_op->info.mkvps, other_op->info.num_mkvps, op.info.mkvps[k].type, 0)) { /* Same MKVP type */ warnx("Operation '%s' also affects APQN %02X.%04X and MK type '%s'", other_op->id, apqns[i].card, apqns[i].domain, get_mk_type_string(op.info.mkvps[k].type)); *error = true; } } } } return CKR_OK; } static int check_intersecting_ops(void) { CK_RV rv; bool error = false; rv = hsm_mk_change_op_iterate(check_intersecting_ops_cb, &error); if (rv != CKR_OK) { warnx("Failed to iterate over active operations"); return EIO; } if (error != false) { warnx("Intersecting master key operations are active, aborting"); return EALREADY; } return 0; } static int check_tokens_present(void) { CK_ULONG i; bool all_present = true; ssize_t num_chars; char *buff = NULL; size_t buflen = 0; for (i = 0; i < num_tokens; i++) all_present &= tokens[i].present; if (all_present) return 0; printf("WARNING: The following slots have no token present:\n"); for (i = 0; i < num_tokens; i++) { if (tokens[i].present == false) printf(" Slot %lu\n", tokens[i].id); } printf("Reasons for a token not being present can be that a prereq of the token\n" "is not fulfilled, or the current user '%s' has no permissions to use\n" "the token, i.e. because it is not a member of the token's user group.\n\n", cuserid(NULL)); printf("ATTENTION: If you start a concurrent master key change operation while not\n" "all expected tokens are present, the key objects of those tokens may be lost,\n" "if the token would be affected by the master key change.\n"); printf("Continue [y/N]? "); fflush(stdout); num_chars = getline(&buff, &buflen, stdin); if (num_chars < 0 || strncmp(buff, "y", 1) != 0) { printf("Aborted by user.\n"); free(buff); return ECANCELED; } free(buff); return 0; } static int create_mk_change_op(void) { CK_RV rv; rv = hsm_mk_change_lock(true); if (rv != CKR_OK) { warnx("Failed to obtain lock"); return EIO; } rv = hsm_mk_change_op_create(&op); if (rv != CKR_OK) { warnx("Failed to create MK change operation file"); hsm_mk_change_unlock(); return EIO; } rv = hsm_mk_change_unlock(); if (rv != CKR_OK) { warnx("Failed to release lock"); hsm_mk_change_op_remove(op.id); return EIO; } return 0; } static int save_mk_change_op(void) { CK_RV rv; rv = hsm_mk_change_lock(true); if (rv != CKR_OK) { warnx("Failed to obtain lock"); return EIO; } rv = hsm_mk_change_op_save(&op); if (rv != CKR_OK) { warnx("Failed to save MK change operation file"); hsm_mk_change_unlock(); return EIO; } rv = hsm_mk_change_unlock(); if (rv != CKR_OK) { warnx("Failed to release lock"); return EIO; } return 0; } static int load_mk_change_op(const char *id) { CK_RV rv; rv = hsm_mk_change_lock(false); if (rv != CKR_OK) { warnx("Failed to obtain lock"); return EIO; } rv = hsm_mk_change_op_load(id, &op); if (rv != 0) { warnx("Failed to load MK change operation file"); hsm_mk_change_unlock(); return EIO; } rv = hsm_mk_change_unlock(); if (rv != 0) { warnx("Failed to release lock"); return EIO; } return 0; } static int remove_mk_change_op(void) { CK_RV rv; rv = hsm_mk_change_lock(true); if (rv != CKR_OK) { warnx("Failed to obtain lock"); return EIO; } rv = hsm_mk_change_op_remove(op.id); if (rv != CKR_OK) { warnx("Failed to remove MK change operation file(s)"); hsm_mk_change_unlock(); return EIO; } rv = hsm_mk_change_unlock(); if (rv != CKR_OK) { warnx("Failed to release lock"); return EIO; } return 0; } static int build_event_payload(unsigned char **payload, size_t *payload_len) { event_mk_change_data_t *hdr; size_t info_len = 0; CK_RV rv; rv = hsm_mk_change_info_flatten(&op.info, NULL, &info_len); if (rv != CKR_OK) { warnx("Failed to query size of event payload buffer"); return EIO; } *payload_len = sizeof(*hdr) + info_len; *payload = calloc(1, *payload_len); if (*payload == NULL) { warnx("Failed to allocate event payload buffer"); *payload_len = 0; return ENOMEM; } hdr = (event_mk_change_data_t *)*payload; strncpy(hdr->id, op.id, sizeof(hdr->id)); hdr->tool_pid = getpid(); hdr->flags = 0; rv = hsm_mk_change_info_flatten(&op.info, *payload + sizeof(*hdr), &info_len); if (rv != CKR_OK) { warnx("Failed to flatten operation info"); free(*payload); *payload = NULL; *payload_len = 0; return EIO; } return 0; } static int send_query_event(unsigned int event, const char *msg_cmd, CK_ULONG *num_affected_slots) { size_t payload_len; unsigned char *payload = NULL; struct event_destination dest; struct event_reply reply; CK_ULONG i, num_errors = 0; int rc = 0; TRACE_DEVEL("Event: 0x%08x\n", event); *num_affected_slots = 0; rc = build_event_payload(&payload, &payload_len); if (rc != 0) return rc; for (i = 0; i < num_tokens; i++) { if (tokens[i].present == false) continue; TRACE_DEVEL("Slot %lu\n", tokens[i].id); dest.process_id = getpid(); /* Send to current process only */ dest.token_type = EVENT_TOK_TYPE_CCA | EVENT_TOK_TYPE_EP11; memcpy(dest.token_label, tokens[i].info.label, sizeof(dest.token_label)); /* selected token only */ memset(&reply, 0, sizeof(reply)); rc = send_event(event_fd, event, EVENT_FLAGS_REPLY_REQ, payload_len, (char *)payload, &dest, &reply); if (rc != 0) { warnx("Failed to send event: %d", rc); rc = EIO; goto out; } TRACE_DEVEL("Positive: %lu\n", reply.positive_replies); TRACE_DEVEL("Negative: %lu\n", reply.negative_replies); TRACE_DEVEL("Not handled: %lu\n", reply.nothandled_replies); if (reply.positive_replies > 1 || reply.negative_replies > 1 || reply.nothandled_replies > 1) { warnx("More than one token responded to the query event for slot %lu", tokens[i].id); warnx("Possibly multiple tokens use the same label?"); rc = EIO; goto out; } if (reply.negative_replies == 1) { warnx("Token in slot %lu is unable to perform the %s.", tokens[i].id, msg_cmd); num_errors++; } if (reply.positive_replies == 1) { tokens[i].affected = true; (*num_affected_slots)++; } } TRACE_DEVEL("num_errors: %lu\n", num_errors); if (num_errors > 0) { warnx("At least one token is unable to perform the %s, aborting.", msg_cmd); rc = EINVAL; goto out; } TRACE_DEVEL("num_affected_slots: %lu\n", *num_affected_slots); out: free(payload); return rc; } static int query_tokens_initiate_mk_change(void) { CK_ULONG i, k; int rc; rc = send_query_event(EVENT_TYPE_MK_CHANGE_INITIATE_QUERY, "master key change", &num_affected_slots); if (rc != 0) return rc; if (num_affected_slots == 0) { warnx("No token is affected by this master key change, aborting"); return ECANCELED; } affected_slots = calloc(num_affected_slots, sizeof(CK_SLOT_ID)); if (affected_slots == NULL) { warnx("Failed to allocate list of affected slots"); return ENOMEM; } for (i = 0, k = 0; i < num_tokens && k < num_affected_slots; i++) { if (tokens[i].affected == true) { affected_slots[k] = tokens[i].id; k++; } } printf("The following tokens are affected by this master key change:\n"); for (i = 0; i < num_tokens; i++) { if (tokens[i].affected == true) printf(" Slot %lu: Label: %.32s\n", tokens[i].id, tokens[i].info.label); } return 0; } static int login_tokens(void) { char msg[200]; const char *userpin = NULL; char *buf_user = NULL; CK_ULONG i; int rc = 0; CK_RV rv; for (i = 0; i < num_tokens; i++) { if (tokens[i].affected == false) continue; TRACE_DEVEL("Slot %lu\n", tokens[i].id); snprintf(msg, sizeof(msg), "Enter the USER PIN for slot %lu: ", tokens[i].id); get_pin: userpin = pin_prompt(&buf_user, msg); if (userpin == NULL) { warnx("Aborted by user."); rc = ECANCELED; goto out; } if (strlen(userpin) == 0) { warnx("Empty pin entered, try again."); pin_free(&buf_user); goto get_pin; } rv = func_list->C_OpenSession(tokens[i].id, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL, NULL, &tokens[i].session); if (rv != CKR_OK) { warnx("Error opening an R/W session with slot %lu: 0x%lX (%s)", tokens[i].id, rv, p11_get_ckr(rv)); rc = EIO; goto out; } rv = func_list->C_Login(tokens[i].session, CKU_USER, (CK_CHAR_PTR)userpin, strlen(userpin)); if (rv != CKR_OK) { warnx("Error logging in for slot %lu: 0x%lX (%s)", tokens[i].id, rv, p11_get_ckr(rv)); rc = EINVAL; goto out; } pin_free(&buf_user); } out: pin_free(&buf_user); return rc; } static void logout_tokens(void) { CK_ULONG i; for (i = 0; i < num_tokens; i++) { if (tokens[i].affected == false) continue; if (tokens[i].session == CK_INVALID_HANDLE) continue; func_list->C_Logout(tokens[i].session); func_list->C_CloseAllSessions(tokens[i].id); } } static int reencipher_tokens(void) { size_t payload_len; unsigned char *payload = NULL; event_mk_change_data_t *hdr; struct event_destination dest; struct event_reply reply; int rc = 0; rc = build_event_payload(&payload, &payload_len); if (rc != 0) return rc; /* * Let all tokens re-encipher their session objects. * This activates the MK change operation for the processes. * New token objects will be re-enciphered by the processes, existing * token objects are not yet re-enciphered. Since the new WK is not yet * set/activated on the APQNs at that point in time, this does not matter. */ hdr = (event_mk_change_data_t *)payload; hdr->flags = EVENT_MK_CHANGE_FLAGS_NONE; dest.process_id = 0; dest.token_type = EVENT_TOK_TYPE_CCA | EVENT_TOK_TYPE_EP11; memset(dest.token_label, ' ', sizeof(dest.token_label)); memset(&reply, 0, sizeof(reply)); rc = send_event(event_fd, EVENT_TYPE_MK_CHANGE_REENCIPHER, EVENT_FLAGS_REPLY_REQ, payload_len, (char *)payload, &dest, &reply); if (rc != 0) { warnx("Failed to send event: %d", rc); rc = EIO; goto out; } TRACE_DEVEL("Positive: %lu\n", reply.positive_replies); TRACE_DEVEL("Negative: %lu\n", reply.negative_replies); TRACE_DEVEL("Not handled: %lu\n", reply.nothandled_replies); if (reply.negative_replies != 0 || reply.positive_replies == 0) goto cancel; /* * Let the tool process re-encipher the token objects. * After that, all objects are re-enciphered. */ hdr->flags = EVENT_MK_CHANGE_FLAGS_TOK_OBJS; dest.process_id = getpid(); /* Send to current process only */ dest.token_type = EVENT_TOK_TYPE_CCA | EVENT_TOK_TYPE_EP11; memset(dest.token_label, ' ', sizeof(dest.token_label)); memset(&reply, 0, sizeof(reply)); rc = send_event(event_fd, EVENT_TYPE_MK_CHANGE_REENCIPHER, EVENT_FLAGS_REPLY_REQ, payload_len, (char *)payload, &dest, &reply); if (rc != 0) { warnx("Failed to send event: %d", rc); rc = EIO; goto out; } TRACE_DEVEL("Positive: %lu\n", reply.positive_replies); TRACE_DEVEL("Negative: %lu\n", reply.negative_replies); TRACE_DEVEL("Not handled: %lu\n", reply.nothandled_replies); if (reply.negative_replies != 0 || reply.positive_replies == 0) goto cancel; out: free(payload); return rc; cancel: warnx("At least one token failed to perform the key re-encryption."); warnx("Check the syslog for details about the errors reported by the tokens."); /* Cancel the MK change operation */ op.state = HSM_MK_CH_STATE_CANCELING; rc = save_mk_change_op(); if (rc != 0) goto out; /* Let all tokens cancel their session object re-enciphering */ hdr->flags = EVENT_MK_CHANGE_FLAGS_NONE; dest.process_id = 0; dest.token_type = EVENT_TOK_TYPE_CCA | EVENT_TOK_TYPE_EP11; memset(dest.token_label, ' ', sizeof(dest.token_label)); rc = send_event(event_fd, EVENT_TYPE_MK_CHANGE_CANCEL, EVENT_FLAGS_REPLY_REQ, payload_len, (char *)payload, &dest, &reply); if (rc != 0) { warnx("Failed to send event: %d", rc); rc = EIO; goto out; } TRACE_DEVEL("Positive: %lu\n", reply.positive_replies); TRACE_DEVEL("Negative: %lu\n", reply.negative_replies); TRACE_DEVEL("Not handled: %lu\n", reply.nothandled_replies); if (reply.negative_replies != 0) warnx("At least one token failed to cancel the key re-encryption."); /* Let the tool process cancel the token object re-enciphering */ hdr->flags = EVENT_MK_CHANGE_FLAGS_TOK_OBJS_FINAL; dest.process_id = getpid(); /* Send to current process only */ dest.token_type = EVENT_TOK_TYPE_CCA | EVENT_TOK_TYPE_EP11; memset(dest.token_label, ' ', sizeof(dest.token_label)); rc = send_event(event_fd, EVENT_TYPE_MK_CHANGE_CANCEL, EVENT_FLAGS_REPLY_REQ, payload_len, (char *)payload, &dest, &reply); if (rc != 0) { warnx("Failed to send event: %d", rc); rc = EIO; goto out; } TRACE_DEVEL("Positive: %lu\n", reply.positive_replies); TRACE_DEVEL("Negative: %lu\n", reply.negative_replies); TRACE_DEVEL("Not handled: %lu\n", reply.nothandled_replies); if (reply.negative_replies != 0) warnx("At least one token failed to cancel the key re-encryption."); rc = remove_mk_change_op(); if (rc != 0) goto out; rc = EIO; goto out; } static int perform_reencipher(void) { unsigned int i; int rc; /* Setup the MK change operation */ TRACE_DEVEL("Num APQNs: %u\n", num_apqns); for (i = 0; i < num_apqns; i++) { TRACE_DEVEL("APQN: %02x.%04x\n", apqns[i].card, apqns[i].domain); } op.state = HSM_MK_CH_STATE_INITIAL; op.info.num_apqns = num_apqns; op.info.apqns = apqns; op.info.num_mkvps = 0; op.info.mkvps = mkvps; TRACE_DEVEL("EP11 WKVP set: %d\n", ep11_wkvp_set); if (ep11_wkvp_set) { TRACE_DEBUG_DUMP("EP11 WKVP: ", (CK_BYTE *)ep11_wkvp, EP11_WKVP_LENGTH); mkvps[op.info.num_mkvps].type = HSM_MK_TYPE_EP11; mkvps[op.info.num_mkvps].mkvp = ep11_wkvp; mkvps[op.info.num_mkvps].mkvp_len = EP11_WKVP_LENGTH; op.info.num_mkvps++; } TRACE_DEVEL("CCA SYM MKVP set: %d\n", cca_sym_mkvp_set); if (cca_sym_mkvp_set) { TRACE_DEBUG_DUMP("CCA SYM MKVP: ", (CK_BYTE *)cca_sym_mkvp, CCA_MKVP_LENGTH); mkvps[op.info.num_mkvps].type = HSM_MK_TYPE_CCA_SYM; mkvps[op.info.num_mkvps].mkvp = cca_sym_mkvp; mkvps[op.info.num_mkvps].mkvp_len = CCA_MKVP_LENGTH; op.info.num_mkvps++; } TRACE_DEVEL("CCA ASYM MKVP set: %d\n", cca_asym_mkvp_set); if (cca_asym_mkvp_set) { TRACE_DEBUG_DUMP("CCA ASYM MKVP: ", (CK_BYTE *)cca_asym_mkvp, CCA_MKVP_LENGTH); mkvps[op.info.num_mkvps].type = HSM_MK_TYPE_CCA_ASYM; mkvps[op.info.num_mkvps].mkvp = cca_asym_mkvp; mkvps[op.info.num_mkvps].mkvp_len = CCA_MKVP_LENGTH; op.info.num_mkvps++; } TRACE_DEVEL("CCA AES MKVP set: %d\n", cca_aes_mkvp_set); if (cca_aes_mkvp_set) { TRACE_DEBUG_DUMP("CCA SYM MKVP: ", (CK_BYTE *)cca_aes_mkvp, CCA_MKVP_LENGTH); mkvps[op.info.num_mkvps].type = HSM_MK_TYPE_CCA_AES; mkvps[op.info.num_mkvps].mkvp = cca_aes_mkvp; mkvps[op.info.num_mkvps].mkvp_len = CCA_MKVP_LENGTH; op.info.num_mkvps++; } TRACE_DEVEL("CCA APKA MKVP set: %d\n", cca_apka_mkvp_set); if (cca_apka_mkvp_set) { TRACE_DEBUG_DUMP("CCA SYM MKVP: ", (CK_BYTE *)cca_apka_mkvp, CCA_MKVP_LENGTH); mkvps[op.info.num_mkvps].type = HSM_MK_TYPE_CCA_APKA; mkvps[op.info.num_mkvps].mkvp = cca_apka_mkvp; mkvps[op.info.num_mkvps].mkvp_len = CCA_MKVP_LENGTH; op.info.num_mkvps++; } /* Check that no intersecting MK change operation is active */ rc = check_intersecting_ops(); if (rc != 0) return rc; /* Check that all tokens are present, warn & prompt user if not */ rc = check_tokens_present(); if (rc != 0) return rc; /* Create the MK change operation file */ rc = create_mk_change_op(); if (rc != 0) goto error; /* Query each token if it is affected by this MK change */ rc = query_tokens_initiate_mk_change(); if (rc != 0) goto error; /* Prompt for pin, login and open R/W session for each affected token */ rc = login_tokens(); if (rc != 0) goto error; /* Update MK operation with affected slots and state */ op.state = HSM_MK_CH_STATE_REENCIPHERING; op.num_slots = num_affected_slots; op.slots = affected_slots; rc = save_mk_change_op(); if (rc != 0) goto error; printf("Re-enciphering, please wait...\n"); /* Let each affected token reencipher its keys */ rc = reencipher_tokens(); if (rc != 0) goto error; printf("Completed.\n"); /* Update MK operation state */ op.state = HSM_MK_CH_STATE_REENCIPHERED; rc = save_mk_change_op(); if (rc != 0) goto error; printf("\nMaster key change operation '%s' created.\n\n", op.id); printf("Once the new master keys have been set/activated:\n"); printf(" - If you specified EXPECTED_MKVPS in your token configuration file(s),\n" " you must now replace the old MKVPs with the new MKVPs."); printf(" - Run 'pkcshsm_mk_change finalize --id %s' when the new master\n" " keys have been set/activated.\n", op.id); return 0; error: if (op.id[0] != '\0') { /* Try to remove just created MK operation */ hsm_mk_change_lock(true); hsm_mk_change_op_remove(op.id); hsm_mk_change_unlock(); } return rc; } static int finalize_cancel_tokens(unsigned int event, enum hsm_mk_change_state state, const char *msg_cmd) { size_t payload_len; unsigned char *payload = NULL; event_mk_change_data_t *hdr; struct event_destination dest; struct event_reply reply; int rc = 0; rc = build_event_payload(&payload, &payload_len); if (rc != 0) return rc; /* * Let the tool process cancel/finalize the token object re-enciphering. * Processes may still create new token objects at that time. */ hdr = (event_mk_change_data_t *)payload; hdr->flags = EVENT_MK_CHANGE_FLAGS_TOK_OBJS; dest.process_id = getpid(); /* Send to current process only */ dest.token_type = EVENT_TOK_TYPE_CCA | EVENT_TOK_TYPE_EP11; memset(dest.token_label, ' ', sizeof(dest.token_label)); memset(&reply, 0, sizeof(reply)); rc = send_event(event_fd, event, EVENT_FLAGS_REPLY_REQ, payload_len, (char *)payload, &dest, &reply); if (rc != 0) { warnx("Failed to send event: %d", rc); rc = EIO; goto out; } TRACE_DEVEL("Positive: %lu\n", reply.positive_replies); TRACE_DEVEL("Negative: %lu\n", reply.negative_replies); TRACE_DEVEL("Not handled: %lu\n", reply.nothandled_replies); if (reply.negative_replies != 0 || reply.positive_replies == 0) { warnx("At least one token failed to %s the master key change " "operation.", msg_cmd); warnx("Check the syslog for details about the errors reported by " "the tokens."); rc = EIO; goto out; } /* * Change state of MK change op. From now on, new processes will no longer * detect an active MK change operation. Any token objects created by such * new processes will use the new WK anyway, and will not have the * re-enciphered blob stored. Existing processes still running with the * MK change operation active using such token objects that have no * re-enciphered will use the normal blob, even though the MK change * operation might still be active and the new WK is set. */ op.state = state; rc = save_mk_change_op(); if (rc != 0) goto out; /* * Let all tokens cancel/finalize their session object re-enciphering. * This deactivates the MK change operation for the processes. */ hdr->flags = EVENT_MK_CHANGE_FLAGS_NONE; dest.process_id = 0; dest.token_type = EVENT_TOK_TYPE_CCA | EVENT_TOK_TYPE_EP11; memset(dest.token_label, ' ', sizeof(dest.token_label)); memset(&reply, 0, sizeof(reply)); rc = send_event(event_fd, event, EVENT_FLAGS_REPLY_REQ, payload_len, (char *)payload, &dest, &reply); if (rc != 0) { warnx("Failed to send event: %d", rc); rc = EIO; goto out; } TRACE_DEVEL("Positive: %lu\n", reply.positive_replies); TRACE_DEVEL("Negative: %lu\n", reply.negative_replies); TRACE_DEVEL("Not handled: %lu\n", reply.nothandled_replies); if (reply.negative_replies != 0 || reply.positive_replies == 0) { warnx("At least one token failed to %s the master key change " "operation.", msg_cmd); warnx("Check the syslog for details about the errors reported by " "the tokens."); rc = EIO; goto out; } /* * Let the tool process cancel/finalize the token object re-enciphering * again to re-encipher token objects created by processes after the * initial token-object re-enciphering, but before the tokens deactivated * the MK change operation. */ hdr->flags = EVENT_MK_CHANGE_FLAGS_TOK_OBJS_FINAL; dest.process_id = getpid(); /* Send to current process only */ dest.token_type = EVENT_TOK_TYPE_CCA | EVENT_TOK_TYPE_EP11; memset(dest.token_label, ' ', sizeof(dest.token_label)); memset(&reply, 0, sizeof(reply)); rc = send_event(event_fd, event, EVENT_FLAGS_REPLY_REQ, payload_len, (char *)payload, &dest, &reply); if (rc != 0) { warnx("Failed to send event: %d", rc); rc = EIO; goto out; } TRACE_DEVEL("Positive: %lu\n", reply.positive_replies); TRACE_DEVEL("Negative: %lu\n", reply.negative_replies); TRACE_DEVEL("Not handled: %lu\n", reply.nothandled_replies); if (reply.negative_replies != 0 || reply.positive_replies == 0) { warnx("At least one token failed to %s the master key change " "operation.", msg_cmd); warnx("Check the syslog for details about the errors reported by " "the tokens."); rc = EIO; goto out; } out: free(payload); return rc; } static int perform_finalize_cancel(bool cancel) { CK_RV rv; int rc, rc2; unsigned int i, k; CK_ULONG num_affected = 0; TRACE_DEVEL("ID: '%s'\n", id); rv = load_mk_change_op(id); if (rv != CKR_OK) { warnx("HSM master key change operation '%s' not found.", id); return ENOENT; } if (op.state != HSM_MK_CH_STATE_REENCIPHERED && op.state != HSM_MK_CH_STATE_ERROR ) { warnx("The HSM master key change operation '%s' is in a state where\n" "it can not be %s.", id, cancel ? "canceled": "finalized"); return EINVAL; } /* Check if all affected tokens are able to finalize/cancel */ rc = send_query_event(cancel ? EVENT_TYPE_MK_CHANGE_CANCEL_QUERY : EVENT_TYPE_MK_CHANGE_FINALIZE_QUERY, cancel ? "cancel action" : "finalize action", &num_affected); if (rc != 0) return rc; /* Ensure the affected slots are still the same */ if (num_affected != op.num_slots) { warnx("The list of slots affected by this master key change has changed\n" "since initiating this master key change operation."); return EINVAL; } for (i = 0, k = 0; i < num_tokens && k < num_affected; i++) { if (tokens[i].affected == true) { if (op.slots[k] != tokens[i].id) { warnx("The list of slots affected by this master key change has changed\n" "since initiating this master key change operation."); return EINVAL; } k++; } } /* Prompt for pin, login and open R/W session for each affected token */ rc = login_tokens(); if (rc != 0) return rc; printf("%s, please wait...\n", cancel ? "Canceling" : "Finalizing"); /* Start finalizing/canceling */ rc = finalize_cancel_tokens(cancel ? EVENT_TYPE_MK_CHANGE_CANCEL : EVENT_TYPE_MK_CHANGE_FINALIZE, cancel ? HSM_MK_CH_STATE_CANCELING : HSM_MK_CH_STATE_FINALIZING, cancel ? "cancel" : "finalize"); if (rc != 0) { /* Set error state */ op.state = HSM_MK_CH_STATE_ERROR; rc2 = save_mk_change_op(); if (rc2 != 0) return rc2; return rc; } /* Operation complete, remove it */ rc = remove_mk_change_op(); if (rc != 0) return rc; printf("\nMaster key change operation '%s' successfully %s.\n", op.id, cancel ? "canceled" : "finalized"); return 0; } static CK_RV perform_list_cb(struct hsm_mk_change_op *op, void *private) { unsigned int i, j, k; int *first = private; struct hsm_mkvp *mkvps = NULL; unsigned int num_mkvps = 0; CK_RV rc; if (*first) *first = FALSE; else printf("\n"); printf("Operation: %s\n", op->id); switch (op->state) { case HSM_MK_CH_STATE_INITIAL: printf(" State: Initial\n"); break; case HSM_MK_CH_STATE_REENCIPHERING: printf(" State: Re-enciphering of key objects ongoing\n"); break; case HSM_MK_CH_STATE_REENCIPHERED: printf(" State: Key objects have been re-enciphered,\n"); printf(" new master key(s) can now be set/activated\n"); break; case HSM_MK_CH_STATE_FINALIZING: printf(" State: Finalizing\n"); break; case HSM_MK_CH_STATE_CANCELING: printf(" State: Canceling\n"); break; case HSM_MK_CH_STATE_ERROR: printf(" State: Finalizing or canceling has errored\n"); break; default: printf(" State: Unknown\n"); break; } printf(" APQNs:\n"); for (i = 0; i < op->info.num_apqns; i++) { printf(" %02X.%04X\n", op->info.apqns[i].card, op->info.apqns[i].domain); } printf(" New master key verification patterns:\n"); for (i = 0; i < op->info.num_mkvps; i++) { switch (op->info.mkvps[i].type) { case HSM_MK_TYPE_EP11: printf(" Type: EP11\n"); break; case HSM_MK_TYPE_CCA_SYM: printf(" Type: CCA SYM\n"); break; case HSM_MK_TYPE_CCA_ASYM: printf(" Type: CCA ASYM\n"); break; case HSM_MK_TYPE_CCA_AES: printf(" Type: CCA AES\n"); break; case HSM_MK_TYPE_CCA_APKA: printf(" Type: CCA APKA\n"); break; } printf(" MKVP: "); for (k = 0; k < op->info.mkvps[i].mkvp_len; k++) printf("%02X", op->info.mkvps[i].mkvp[k]); printf("\n"); } printf(" Affected slots:\n"); for (i = 0; i < op->num_slots; i++) { printf(" Slot: %lu", op->slots[i]); for (k = 0; k < num_tokens; k++) { if (tokens[k].present && tokens[k].id == op->slots[i]) { printf(" Label: %.32s", tokens[k].info.label); break; } } printf("\n"); rc = hsm_mk_change_token_mkvps_load(op->id, op->slots[i], &mkvps, &num_mkvps); if (rc == CKR_OK && num_mkvps > 0) { printf(" Current master key verification patterns:\n"); for (j = 0; j < num_mkvps; j++) { switch (mkvps[j].type) { case HSM_MK_TYPE_EP11: printf(" Type: EP11\n"); break; case HSM_MK_TYPE_CCA_SYM: printf(" Type: CCA SYM\n"); break; case HSM_MK_TYPE_CCA_ASYM: printf(" Type: CCA ASYM\n"); break; case HSM_MK_TYPE_CCA_AES: printf(" Type: CCA AES\n"); break; case HSM_MK_TYPE_CCA_APKA: printf(" Type: CCA APKA\n"); break; } printf(" MKVP: "); for (k = 0; k < mkvps[j].mkvp_len; k++) printf("%02X", mkvps[j].mkvp[k]); printf("\n"); } hsm_mk_change_mkvps_clean(mkvps, num_mkvps); free(mkvps); } mkvps = NULL; num_mkvps = 0; } return CKR_OK; } static int perform_list(void) { CK_RV rv; int rc = 0; int first = TRUE; rv = hsm_mk_change_lock(false); if (rv != CKR_OK) { warnx("Failed to obtain lock"); return EIO; } if (id != NULL) { TRACE_DEVEL("ID: '%s'\n", id); rv = hsm_mk_change_op_load(id, &op); if (rv != CKR_OK) { warnx("HSM master key change operation '%s' not found.", id); rc = ENOENT; goto out; } rv = perform_list_cb(&op, &first); hsm_mk_change_op_clean(&op); if (rv != CKR_OK) { warnx("Failed to list HSM master key change operation '%s'.", id); rc = EIO; goto out; } } else { rv = hsm_mk_change_op_iterate(perform_list_cb, &first); if (rv != CKR_OK) { warnx("Failed to list HSM master key change operations."); rc = EIO; goto out; } } out: rv = hsm_mk_change_unlock(); if (rv != CKR_OK) { warnx("Failed to release lock"); return EIO; } return rc; } static int init_ock(void) { void (*sym_ptr)(CK_FUNCTION_LIST_PTR_PTR ppFunctionList); CK_RV rc; dll = dlopen(OCK_API_LIBNAME, DYNLIB_LDFLAGS); if (dll == NULL) { #if defined(_AIX) int err = errno; #else int err = ELIBACC; #endif warnx("Error loading PKCS#11 library: dlopen: %s", dlerror()); return err; } *(void **)(&sym_ptr) = dlsym(dll, "C_GetFunctionList"); if (sym_ptr == NULL) { #if defined(_AIX) int err = errno; #else int err = ELIBACC; #endif warnx("Error loading PKCS#11 library: dlsym(C_GetFunctionList): %s", dlerror()); #ifndef WITH_SANITIZER dlclose(dll); #endif dll = NULL; return err; } sym_ptr(&func_list); if (func_list == NULL) { warnx("Error getting function list from PKCS11 library"); #ifndef WITH_SANITIZER dlclose(dll); #endif dll = NULL; return ELIBACC; } rc = (func_list)->C_Initialize(NULL); if (rc != CKR_OK) { warnx("Error initializing the PKCS11 library: 0x%lX (%s)", rc, p11_get_ckr(rc)); #ifndef WITH_SANITIZER dlclose(dll); #endif dll = NULL; func_list = NULL; return ELIBACC; } TRACE_INFO("PKCS#11 library initialized successfully\n"); return 0; } static int get_token_infos(void) { CK_RV rc; CK_ULONG num_slots, i; CK_SLOT_ID_PTR slots; rc = func_list->C_GetSlotList(FALSE, NULL, &num_slots); if (rc != CKR_OK) { warnx("Error getting number of slots: 0x%lX (%s)", rc, p11_get_ckr(rc)); return EIO; } TRACE_DEVEL("Num Slots: %lu\n", num_slots); if (num_slots == 0) { warnx("C_GetSlotList returned 0 slots. Check that your tokens" " are installed correctly."); return EIO; } slots = calloc(num_slots, sizeof(CK_SLOT_ID)); if (slots == NULL) { warnx("Failed to allocate slot list"); return ENOMEM; } rc = func_list->C_GetSlotList(FALSE, slots, &num_slots); if (rc != CKR_OK) { warnx("Error getting slot list: 0x%lX (%s)", rc, p11_get_ckr(rc)); free(slots); return EIO; } num_tokens = num_slots; tokens = calloc(num_tokens, sizeof(struct token_info)); if (tokens == NULL) { warnx("Failed to allocate token list"); free(slots); return ENOMEM; } for (i = 0; i < num_slots; i++) { TRACE_DEVEL("Slot %lu: %lu\n", i, slots[i]); tokens[i].id = slots[i]; rc = func_list->C_GetTokenInfo(slots[i], &tokens[i].info); if (rc == CKR_TOKEN_NOT_PRESENT) { TRACE_DEVEL(" Token not present\n"); continue; } if (rc != CKR_OK) { warnx("Error getting token infos for slot %lu: 0x%lX (%s)", slots[i], rc, p11_get_ckr(rc)); return 1; } TRACE_DEVEL(" Label: %.32s\n", tokens[i].info.label); TRACE_DEVEL(" Manufacturer: %.32s\n", tokens[i].info.manufacturerID); TRACE_DEVEL(" Model: %.16s\n", tokens[i].info.model); TRACE_DEVEL(" Serial Number: %.16s\n", tokens[i].info.serialNumber); tokens[i].present = true; } free(slots); return 0; } void sig_handler(int signal) { UNUSED(signal); TRACE_DEVEL("Cntl-C ignored\n"); } static void setup_signal_handler(void (*handler)(int signal)) { struct sigaction int_act; /* Set a handler for SIGINT/SIGTERM */ memset(&int_act, 0, sizeof(int_act)); if (handler != NULL) int_act.sa_handler = handler; else int_act.sa_handler = SIG_DFL; sigaction(SIGINT, &int_act, NULL); sigaction(SIGTERM, &int_act, NULL); } static int initialize(int cmd) { int rc; CK_RV rv; setup_signal_handler(sig_handler); rv = hsm_mk_change_lock_create(); if (rv != CKR_OK) return EIO; rc = init_ock(); if (rc != 0) return rc; rc = get_token_infos(); if (rc != 0) return rc; if (cmd == CMD_LIST) return 0; event_fd = init_event_client(); if (event_fd < 0) { warnx("Failed to connect to pkcsslotd's event socket: %s", strerror(-event_fd)); rc = -event_fd; return rc; } TRACE_INFO("Event connection established\n"); return 0; } static void terminate(void) { if (tokens != NULL) { if (func_list != NULL) logout_tokens(); free(tokens); } if (affected_slots != NULL) free(affected_slots); if (apqns != NULL) free(apqns); if (event_fd >= 0) term_event_client(event_fd); if (dll != NULL) { if (func_list != NULL) func_list->C_Finalize(NULL); #ifndef WITH_SANITIZER dlclose(dll); #endif } hsm_mk_change_lock_destroy(); setup_signal_handler(NULL); } static int verbose_str2level(char *str) { const char *tlevel[] = {"none", "error", "warn", "info", "devel", "debug"}; const int num = sizeof(tlevel) / sizeof(char *); int i; for (i = 0; i < num; i++) { if (strcmp(str, tlevel[i]) == 0) { return i; } } return -1; } int main(int argc, char **argv) { int rc = 0, opt = 0; int cmd = 0; static const struct option long_opts[] = { {"apqns", required_argument, NULL, 'a'}, {"ep11-wkvp", required_argument, NULL, 'e'}, {"cca-sym-mkvp", required_argument, NULL, 's'}, {"cca-asym-mkvp", required_argument, NULL, 'S'}, {"cca-aes-mkvp", required_argument, NULL, 'A'}, {"cca-apka-mkvp", required_argument, NULL, 'p'}, {"id", required_argument, NULL, 'i'}, {"verbose", required_argument, NULL, 'v'}, {"help", no_argument, NULL, 'h'}, {0, 0, 0, 0} }; if (argc >=2 && *argv[1] != '-') { if (strcmp(argv[1], "reencipher") == 0) { cmd = CMD_REENCIPHER; } else if (strcmp(argv[1], "finalize") == 0) { cmd = CMD_FINALIZE; } else if (strcmp(argv[1], "cancel") == 0) { cmd = CMD_CANCEL; } else if (strcmp(argv[1], "list") == 0) { cmd = CMD_LIST; } else { warnx("unrecognized command '%s'", argv[1]); exit(EXIT_FAILURE); } argv++; argc--; } while ((opt = getopt_long(argc, argv, "a:e:s:S:A:p:i:v:h", long_opts, NULL)) != -1) { switch (opt) { case 'a': if (cmd != CMD_REENCIPHER) { warnx("option -a/--apqns is only valid for the 'reencipher' command"); exit(EXIT_FAILURE); } rc = parse_apqns(optarg); if (rc != 0) goto out; break; case 'e': if (cmd != CMD_REENCIPHER) { warnx("option -e/--ep11-wkvp is only valid for the 'reencipher' command"); exit(EXIT_FAILURE); } rc = parse_mkvp(optarg, EP11_WKVP_LENGTH, ep11_wkvp, &ep11_wkvp_set, "-e/--ep11-wkvp"); if (rc != 0) goto out; break; case 's': if (cmd != CMD_REENCIPHER) { warnx("option -s/--cca-sym-mkvp is only valid for the 'reencipher' command"); exit(EXIT_FAILURE); } rc = parse_mkvp(optarg, CCA_MKVP_LENGTH, cca_sym_mkvp, &cca_sym_mkvp_set, "-s/--cca-sym-mkvp"); if (rc != 0) goto out; break; case 'S': if (cmd != CMD_REENCIPHER) { warnx("option -S/--cca-asym-mkvp is only valid for the 'reencipher' command"); exit(EXIT_FAILURE); } rc = parse_mkvp(optarg, CCA_MKVP_LENGTH, cca_asym_mkvp, &cca_asym_mkvp_set, "-S/--cca-asym-mkvp"); if (rc != 0) goto out; break; case 'A': if (cmd != CMD_REENCIPHER) { warnx("option -A/--cca-aes-mkvp is only valid for the 'reencipher' command"); exit(EXIT_FAILURE); } rc = parse_mkvp(optarg, CCA_MKVP_LENGTH, cca_aes_mkvp, &cca_aes_mkvp_set, "-A/--cca-aes-mkvp"); if (rc != 0) goto out; break; case 'p': if (cmd != CMD_REENCIPHER) { warnx("option -p/--cca-apka-mkvp is only valid for the 'reencipher' command"); exit(EXIT_FAILURE); } rc = parse_mkvp(optarg, CCA_MKVP_LENGTH, cca_apka_mkvp, &cca_apka_mkvp_set, "-p/--cca-apka-mkvp"); if (rc != 0) goto out; break; case 'i': if (cmd != CMD_FINALIZE && cmd != CMD_CANCEL && cmd != CMD_LIST) { warnx("option -i/--id is only valid for the 'finalize', 'cancel or 'list' command"); exit(EXIT_FAILURE); } id = optarg; TRACE_DEVEL("ID: '%s'\n", id); break; case 'v': trace_level = verbose_str2level(optarg); if ((int)trace_level < 0) { warnx("Invalid verbose level '%s' specified.", optarg); exit(EXIT_FAILURE); } break; case 'h': usage(basename(argv[0])); exit(EXIT_SUCCESS); default: exit(EXIT_FAILURE); } } if (optind < argc) { warnx("unrecognized option '%s'", argv[optind]); exit(EXIT_FAILURE); } rc = initialize(cmd); if (rc != 0) goto out; switch (cmd) { case CMD_REENCIPHER: TRACE_DEVEL("Command: reencipher\n"); if (apqns == NULL || num_apqns == 0) { warnx("option -a/--apqns is required for the 'reencipher' command"); exit(EXIT_FAILURE); } if (!ep11_wkvp_set && !cca_sym_mkvp_set && !cca_asym_mkvp_set && !cca_aes_mkvp_set && !cca_apka_mkvp_set) { warnx("at least one master key verification pattern must be specified"); exit(EXIT_FAILURE); } rc = perform_reencipher(); break; case CMD_FINALIZE: TRACE_DEVEL("Command: finalize\n"); if (id == NULL) { warnx("option -i/--id is required for the 'finalize' command"); exit(EXIT_FAILURE); } rc = perform_finalize_cancel(false); break; case CMD_CANCEL: TRACE_DEVEL("Command: cancel\n"); if (id == NULL) { warnx("option -i/--id is required for the 'cancel' command"); exit(EXIT_FAILURE); } rc = perform_finalize_cancel(true); break; case CMD_LIST: TRACE_DEVEL("Command: list\n"); rc = perform_list(); break; default: TRACE_DEVEL("Command: %d\n", cmd); warnx("no command specified"); exit(EXIT_FAILURE); } out: terminate(); TRACE_DEVEL("rc: %d\n", rc); return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } opencryptoki-opencryptoki-451d99c/usr/sbin/pkcshsm_mk_change/pkcshsm_mk_change.mk000066400000000000000000000017311520105705100305330ustar00rootroot00000000000000sbin_PROGRAMS += usr/sbin/pkcshsm_mk_change/pkcshsm_mk_change usr_sbin_pkcshsm_mk_change_pkcshsm_mk_change_LDFLAGS = -lcrypto -ldl -lrt if AIX usr_sbin_pkcshsm_mk_change_pkcshsm_mk_change_LDFLAGS += -lbsd -Wl,-blibpath:$(libdir)/opencryptoki:$(libdir)/opencryptoki/stdll:/usr/lib:/usr/lib64 endif usr_sbin_pkcshsm_mk_change_pkcshsm_mk_change_CFLAGS = \ -DOCK_TOOL \ -DSTDLL_NAME=\"pkcshsm_mk_change\" \ -I${srcdir}/usr/include \ -I${srcdir}/usr/lib/common \ -I${srcdir}/usr/lib/api \ -I${top_builddir}/usr/lib/api \ -I${srcdir}/usr/lib/hsm_mk_change usr_sbin_pkcshsm_mk_change_pkcshsm_mk_change_SOURCES = \ usr/sbin/pkcshsm_mk_change/pkcshsm_mk_change.c \ usr/lib/common/p11util.c \ usr/lib/common/pkcs_utils.c \ usr/lib/common/event_client.c \ usr/lib/common/pin_prompt.c \ usr/lib/hsm_mk_change/hsm_mk_change.c if AIX usr_sbin_pkcshsm_mk_change_pkcshsm_mk_change_SOURCES += \ usr/lib/common/aix/err.c usr/lib/common/aix/getopt_long.c endif opencryptoki-opencryptoki-451d99c/usr/sbin/pkcsicsf/000077500000000000000000000000001520105705100226755ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/usr/sbin/pkcsicsf/pkcsicsf.c000066400000000000000000000540331520105705100246530ustar00rootroot00000000000000/* * 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. * */ #include #include #include #include #include #include #include #include #include #include #include #include "icsf.h" #include "slotmgr.h" #include "pbkdf.h" #include "defs.h" #include "cfgparser.h" #include "configuration.h" #include "pin_prompt.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 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; static int secure_racf_passwd(const char *racfpwd, unsigned int len, const char *tokname); static 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); } static int get_free_slot(struct ConfigBaseNode *config) { struct ConfigBaseNode *c; struct ConfigIdxStructNode *slot; CK_BBOOL slot_used[NUMBER_SLOTS_MANAGED] = { 0 }; int i; confignode_foreach(c, config, i) { if (confignode_hastype(c, CT_IDX_STRUCT)) { slot = confignode_to_idxstruct(c); if (strcmp(slot->base.key, "slot") == 0 && slot->idx < NUMBER_SLOTS_MANAGED) slot_used[slot->idx] = CK_TRUE; } } for (i = 0; i < NUMBER_SLOTS_MANAGED; i++) { if (slot_used[i] == CK_FALSE) return i; } return -1; } static 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(struct ConfigIdxStructNode *s, char *key, char *value) { struct ConfigStringValNode *v; if (!key || !value) return; v = confignode_allocstringvaldumpable(key, value, 0, NULL); if (v != NULL) confignode_append(s->value, &v->base); } static int add_token_config(const char *configname, struct icsf_token_record token, int slot) { struct ConfigIdxStructNode *s; struct ConfigEOCNode *eoc1, *eoc2; FILE *tfp; eoc1 = confignode_alloceoc(NULL, 0); eoc2 = confignode_alloceoc(NULL, 0); s = confignode_allocidxstructdumpable("slot", slot, (struct ConfigBaseNode *)eoc1, (struct ConfigBaseNode *)eoc2, 0, NULL); if (s == NULL || eoc1 == NULL || eoc2 == NULL) { if (s == NULL) { confignode_freeeoc(eoc1); confignode_freeeoc(eoc2); } confignode_deepfree(&s->base); fprintf(stderr, "Failed to add an entry for %s token\n", token.name); return -1; } /* add the info */ add_token_config_entry(s, "TOKEN_NAME", token.name); add_token_config_entry(s, "TOKEN_MANUFACTURE", token.manufacturer); add_token_config_entry(s, "TOKEN_MODEL", token.model); add_token_config_entry(s, "TOKEN_SERIAL", token.serial); add_token_config_entry(s, "MECH", (flags & CFG_MECH_SIMPLE) ? "SIMPLE" : "SASL"); /* add BIND info */ if (strcmp(mech, "simple") == 0) { add_token_config_entry(s, "BINDDN", binddn); add_token_config_entry(s, "URI", uri); } else { add_token_config_entry(s, "URI", uri); add_token_config_entry(s, "CERT", cert); add_token_config_entry(s, "CACERT", cacert); add_token_config_entry(s, "KEY", privkey); } /* create the token config file */ tfp = fopen(configname, "w"); if (tfp == NULL) { fprintf(stderr, "fopen failed, line %d: %s\n", __LINE__, strerror(errno)); confignode_deepfree(&s->base); return -1; } fchmod(fileno(tfp), S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); confignode_dump(tfp, &s->base, NULL, 2); fclose(tfp); confignode_deepfree(&s->base); return 0; } static void config_parse_error(int line, int col, const char *msg) { fprintf(stderr, "Error parsing config file: line %d column %d: %s\n", line, col, msg); } static struct ConfigBaseNode *config_parse(const char *config_file, CK_BBOOL track_comments) { FILE *file; struct ConfigBaseNode *config = NULL; int ret; file = fopen(config_file, "r"); if (file == NULL) return NULL; ret = parse_configlib_file(file, &config, config_parse_error, track_comments); fclose(file); if (ret != 0) return NULL; return config; } static int config_add_slotinfo(int num_of_slots, struct icsf_token_record *tokens) { int slot_id = -1; char configname[LINESIZ]; struct ConfigBaseNode *config = NULL; struct ConfigIdxStructNode *slot; struct ConfigBareValNode *stdll_val, *confname_val, *tokname_val; struct ConfigEOCNode *eoc1, *eoc2, *eoc3; FILE *fp = NULL; int i, rc; config = config_parse(OCK_CONFIG, TRUE); if (config == NULL) { fprintf(stderr, "failed to parse config file %s\n", OCK_CONFIG); 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++) { /* get the slot for next entry */ slot_id = get_free_slot(config); if (slot_id == -1) { fprintf(stderr, "No more free slot found\n"); confignode_deepfree(config); return 1; } if (strcmp(tokens[i].name, "HSM_MK_CHANGE") == 0) { fprintf(stderr, "Token name can not be 'HSM_MK_CHANGE'.\n"); confignode_deepfree(config); return 1; } /* 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], slot_id); 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 */ eoc1 = confignode_alloceoc(NULL, 0); eoc2 = confignode_alloceoc(NULL, 0); eoc3 = confignode_alloceoc(NULL, 0); slot = confignode_allocidxstructdumpable("slot", slot_id, (struct ConfigBaseNode *)eoc1, (struct ConfigBaseNode *)eoc2, 0, NULL); stdll_val = confignode_allocbarevaldumpable("stdll", STDLL, 0, NULL); confname_val = confignode_allocbarevaldumpable("confname", configname, 0, NULL); tokname_val = confignode_allocbarevaldumpable("tokname", tokens[i].name, 0, NULL); if (slot == NULL || stdll_val == NULL || confname_val == NULL || tokname_val == NULL || eoc1 == NULL || eoc2 == NULL || eoc3 == NULL) { fprintf(stderr, "Failed to add an entry for %s token: %s\n", tokens[i].name, strerror(errno)); remove_file(configname); if (slot == NULL) { confignode_freeeoc(eoc1); confignode_freeeoc(eoc2); } confignode_freeidxstruct(slot); confignode_freebareval(stdll_val); confignode_freebareval(confname_val); confignode_freebareval(tokname_val); confignode_freeeoc(eoc3); continue; } confignode_append(slot->value, &stdll_val->base); confignode_append(slot->value, &confname_val->base); confignode_append(slot->value, &tokname_val->base); confignode_append(config, &eoc3->base); confignode_append(config, &slot->base); } /* Open conf file for write */ fp = fopen(OCK_CONFIG, "w"); if (!fp) { fprintf(stderr, "fopen(%s) failed, errno=%s\n", OCK_CONFIG, strerror(errno)); confignode_deepfree(config); return -1; } fchmod(fileno(fp), S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); confignode_dump(fp, config, NULL, 2); fclose(fp); confignode_deepfree(config); return 0; } static 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; } static 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; } static void remove_racf_file(const char *tokname) { char fname[PATH_MAX]; /* remove the so and user files */ snprintf(fname, sizeof(fname), "%s/RACF", tokname); remove_file(fname); } static int retrieve_all(const char *racfpwd) { size_t tokenCount, i; struct icsf_token_record *previous = NULL; struct icsf_token_record tokens[MAX_RECORDS]; int rc; tokenCount = MAX_RECORDS; 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; } if (flags & CFG_MECH_SIMPLE) { /* when using simple auth, secure racf passwd. */ for (i = 0; i < tokenCount; i++) { rc = secure_racf_passwd(racfpwd, strlen(racfpwd), tokens[i].name); if (rc != 0) return rc; } } return 0; } static int secure_racf_passwd(const char *racfpwd, unsigned int len, const char *tokname) { const char *sopin; char *buf_so = NULL; unsigned char masterkey[AES_KEY_SIZE_256]; char fname[PATH_MAX]; struct stat sb; struct group *grp; int rc; grp = getgrnam(PKCS_GROUP); if (grp == NULL) { fprintf(stderr, "getgrname(%s): %s\n", PKCS_GROUP, strerror(errno)); rc = -1; goto cleanup; } /* Create the token directory, if not already existent */ snprintf(fname, sizeof(fname), "%s/%s", CONFIG_PATH, tokname); if (stat(fname, &sb) != 0 && errno == ENOENT) { if (mkdir(fname, S_IRWXU | S_IRWXG) != 0) { fprintf(stderr, "Failed to create token directory '%s': %s\n", fname, strerror(errno)); rc = -1; goto cleanup; } /* set ownership to euid, and token group */ if (chown(fname, geteuid(), grp->gr_gid) != 0) { fprintf(stderr, "Failed to set owner:group ownership on '%s' " "directory\n", fname); rc = -1; goto cleanup; } /* mkdir does not set group permission right, set explicitly here */ if (chmod(fname, S_IRWXU | S_IRWXG) != 0) { fprintf(stderr, "Failed to change permissions on '%s' directory\n", fname); rc = -1; goto cleanup; } } /* get the SO PIN */ sopin = pin_prompt(&buf_so, "Enter the SO PIN: "); if (!sopin) { 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(NULL, (CK_BYTE *)racfpwd, len, masterkey, AES_KEY_SIZE_256, tokname); 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/%s/MK_SO", CONFIG_PATH, tokname); rc = secure_masterkey(NULL, 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(tokname); rc = -1; goto cleanup; } cleanup: pin_free(&buf_so); return rc; } int main(int argc, char **argv) { const char *racfpwd = NULL; char *buf_racfpwd = NULL; 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 (strcmp(mech, 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]); /* 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]); if ((flags & CFG_ADD) && geteuid() != 0) { fprintf(stderr, "%s can only be used as root.\n", argv[0]); exit(-1); } /* get racf password if needed */ if ((flags & CFG_ADD) || (flags & CFG_LIST)) { if (flags & CFG_MECH_SIMPLE) { racfpwd = pin_prompt(&buf_racfpwd, "Enter the RACF passwd: "); if (!racfpwd) { fprintf(stderr, "Could not get RACF passwd.\n"); rc = -1; goto cleanup; } /* 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: %s (%d)\n", ldap_err2string(rc), rc); goto cleanup; } } /* Add token(s) */ if (flags & CFG_ADD) { if (strcmp(tokenname, "all") == 0) { rc = retrieve_all(racfpwd); 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), tokenname); 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); pin_free(&buf_racfpwd); return rc; } opencryptoki-opencryptoki-451d99c/usr/sbin/pkcsicsf/pkcsicsf.mk000066400000000000000000000014141520105705100250330ustar00rootroot00000000000000sbin_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 \ -I${srcdir}/usr/lib/config -I${top_builddir}/usr/lib/config \ -I${top_builddir}/usr/lib/api -I${srcdir}/usr/lib/api usr_sbin_pkcsicsf_pkcsicsf_SOURCES = \ usr/lib/icsf_stdll/icsf.c usr/lib/icsf_stdll/pbkdf.c \ usr/lib/common/trace.c usr/lib/common/pin_prompt.c \ usr/sbin/pkcsicsf/pkcsicsf.c usr/lib/config/configuration.c \ usr/lib/config/cfgparse.y usr/lib/config/cfglex.l usr/sbin/pkcsicsf/pkcsicsf.$(OBJEXT): usr/lib/config/cfgparse.h opencryptoki-opencryptoki-451d99c/usr/sbin/pkcsslotd/000077500000000000000000000000001520105705100230765ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/usr/sbin/pkcsslotd/daemon.c000066400000000000000000000014621520105705100245100ustar00rootroot00000000000000/* * 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)); } opencryptoki-opencryptoki-451d99c/usr/sbin/pkcsslotd/err.c000066400000000000000000000125021520105705100240320ustar00rootroot00000000000000/* * 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])); 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); } opencryptoki-opencryptoki-451d99c/usr/sbin/pkcsslotd/err.h000066400000000000000000000053441520105705100240450ustar00rootroot00000000000000/* * 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 */ 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); #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); #endif /* _SLOTD_ERR_H */ opencryptoki-opencryptoki-451d99c/usr/sbin/pkcsslotd/garbage_linux.c000066400000000000000000000416601520105705100260600ustar00rootroot00000000000000/* * 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" #include "pkcsslotd.h" #include "err.h" #if defined(_AIX) #include #endif #define PROC_BASE "/proc" #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 " "%lu by ID %lu", GCThread, 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 %lu is stopping the garbage collection " "thread (tid %lu)", 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: %lu 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 %lu 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 *pGlobalRWSessions = &(MemPtr->slot_global_rw_sessions[SlotIndex]); unsigned int *pGlobalTokspecCount = &(MemPtr->slot_global_tokspec_count[SlotIndex]); unsigned int *pProcSessions = &(pProc->slot_session_count[SlotIndex]); unsigned int *pProcRWSessions = &(pProc->slot_rw_session_count[SlotIndex]); unsigned int *pProcTokspecCount = &(pProc->slot_tokspec_count[SlotIndex]); if (*pProcSessions > 0) { #ifdef DEV DbgLog(DL2, "GC: Invalid pid (%d) is holding %u sessions " "open on slot %d. Global session count for this " "slot is %u", 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 %u sessions " "open on slot %d, but the global count for this " "slot is only %u", ProcIndex, pProc->proc_id, *pProcSessions, SlotIndex, *pGlobalSessions); #endif /* DEV */ *pGlobalSessions = 0; *pGlobalRWSessions = 0; } else { *pGlobalSessions -= *pProcSessions; *pGlobalRWSessions -= *pProcRWSessions; } *pProcSessions = 0; *pProcRWSessions = 0; } /* end if *pProcSessions */ if (*pGlobalTokspecCount > 0) { if (*pProcTokspecCount > *pGlobalTokspecCount) *pGlobalTokspecCount = 0; else *pGlobalTokspecCount -= *pProcTokspecCount; *pProcTokspecCount = 0; } } /* end for SlotIndex */ /* */ /* NULL out everything except the mutex */ /* */ pProc->inuse = CK_FALSE; pProc->proc_id = 0; pProc->slotmap = 0; pProc->blocking = 0; pProc->error = 0; 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) { #if defined(_AIX) struct psinfo psinfo; #else char buf[800 + 1]; // about 40 fields, 64-bit decimal is about 20 chars #endif char fbuf[800]; // about 40 fields, 64-bit decimal is about 20 chars char *tmp; int fd, num; #if defined(_AIX) sprintf(fbuf, "%s/%d/psinfo", PROC_BASE, pid); #else sprintf(fbuf, "%s/%d/stat", PROC_BASE, pid); #endif fflush(stdout); if ((fd = open(fbuf, O_RDONLY, 0)) == -1) return FALSE; #if defined(_AIX) num = read(fd, &psinfo, sizeof(psinfo)); #else num = read(fd, buf, 800); #endif close(fd); #if defined(_AIX) if (num != sizeof(psinfo)) return FALSE; /* on AIX only set those fields that are used by the caller */ p->pid = psinfo.pr_pid; p->start_time = psinfo.pr_start.tv_sec; p->flags = psinfo.pr_flag; p->state = 0; #else 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; #endif 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; proc_t *p; proc_t procstore; /* * If kill(pid, 0) returns -1 and errno/Err = ESRCH the pid doesn't exist. * In case of EPERM we assume that the process exist and try to read its * stats. */ if (kill(pid, 0) == -1) { Err = errno; if (Err == ESRCH) { /* The process was not found */ DbgLog(DL3, "IsValidProcessEntry: PID %lld was not found in the " "process table (kill() returned %s)", pid, SysConst(Err)); return FALSE; } else if (Err != EPERM) { /* 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 (!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 %lld started at %lu; " "registered at %ld", pid, p->start_time, RegTime); DbgLog(DL4, "IsValidProcessEntry: PID Returned %d flags at " "%#lx; state at %#x", p->pid, p->flags, p->state); } } return FALSE; } #endif // NO Garbage opencryptoki-opencryptoki-451d99c/usr/sbin/pkcsslotd/garbage_linux.h000066400000000000000000000060411520105705100260570ustar00rootroot00000000000000 /* * 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 opencryptoki-opencryptoki-451d99c/usr/sbin/pkcsslotd/log.c000066400000000000000000000426171520105705100240350ustar00rootroot00000000000000/* * 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 *buf * *************************************************************/ BOOL GetCurrentTimeString(char *buf) { /* 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(buf != NULL); time(&t); localtime_r(&t, &tm); asctime_r(&tm, buf); /* asctime_r puts a \n at the end, so we'll remove that */ buf[strlen(buf) - 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; /* truncate description to fit buffer */ snprintf(pInfo->Descrip, sizeof(pInfo->Descrip), "%s %s", pStuff->Label, ID); /* 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 *fmt, va_list ap) { char buf[PATH_MAX]; pLoggingFacilityInfo pInfo; int snres; if (fmt == 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; } } snres = vsnprintf(buf, PATH_MAX, fmt, ap); if (snres < 0 || snres >= PATH_MAX) { /* 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(buf) && (buf[strlen(buf) - 1] == '\n')) { buf[strlen(buf) - 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.%lu]: %s\n", pInfo->Descrip, getpid(), pthread_self(), buf); } } /* 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 timebuf[32]; /* Specs say 26-character array */ GetCurrentTimeString(timebuf); /* Date/Time stamp, descrip, Error message */ fprintf(fd, "%s %s[%d.%lu]: ", timebuf, pInfo->Descrip, getpid(), pthread_self()); fprintf(fd, "%s\n", buf); 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", buf); } 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; } 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; } opencryptoki-opencryptoki-451d99c/usr/sbin/pkcsslotd/log.h000066400000000000000000000060471520105705100240370ustar00rootroot00000000000000/* * 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 ************************************************************************/ #if !defined(_ALL_SOURCE) typedef unsigned int u_int32; #endif 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 */ opencryptoki-opencryptoki-451d99c/usr/sbin/pkcsslotd/mutex.c000066400000000000000000000056321520105705100244120ustar00rootroot00000000000000/* * 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; if (xplfd == -1) xplfd = open(OCK_API_LOCK_FILE, OPEN_MODE); if (xplfd == -1) { xplfd = open(OCK_API_LOCK_FILE, O_CREAT | OPEN_MODE, MODE_BITS); if (xplfd != -1) { if (fchmod(xplfd, MODE_BITS) == -1) { DbgLog(DL0, "%s:fchmod(%s):%s\n", __func__, OCK_API_LOCK_FILE, strerror(errno)); goto error; } grp = getgrnam(PKCS_GROUP); 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); unlink(OCK_API_LOCK_FILE); } 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; } opencryptoki-opencryptoki-451d99c/usr/sbin/pkcsslotd/opencryptoki.conf000066400000000000000000000020461520105705100264750ustar00rootroot00000000000000version opencryptoki-3.27 # The following defaults are defined: # hwversion = "0.0" # firmwareversion = "0.0" # description = Linux # manufacturer = IBM # usergroup = pkcs11 # # 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" # tokname = mytoken # tokversion = 3.12 # confname = myccatok.conf # usergroup = mygroup # } # # See man(5) opencryptoki.conf for further information. # slot 0 { stdll = libpkcs11_tpm.so tokversion = 3.12 } slot 1 { stdll = libpkcs11_ica.so tokversion = 3.12 } slot 2 { stdll = libpkcs11_cca.so confname = ccatok.conf tokversion = 3.12 } slot 3 { stdll = libpkcs11_sw.so tokversion = 3.12 } slot 4 { stdll = libpkcs11_ep11.so confname = ep11tok.conf tokversion = 3.12 } opencryptoki-opencryptoki-451d99c/usr/sbin/pkcsslotd/pkcsslotd.h000066400000000000000000000050631520105705100252610ustar00rootroot00000000000000/* * 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 */ int compute_sha256(char *buf, int buf_size, 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 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 init_socket_server(int event_support_disabled); int term_socket_server(void); int init_socket_data(Slot_Mgr_Socket_t *sp); int socket_connection_handler(int timeout_secs); #ifdef DEV void dump_socket_handler(void); #endif #endif /* _SLOTMGR_H */ opencryptoki-opencryptoki-451d99c/usr/sbin/pkcsslotd/pkcsslotd.mk000066400000000000000000000026771520105705100254510ustar00rootroot00000000000000sbin_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 EXTRA_DIST += usr/sbin/pkcsslotd/opencryptoki.conf usr_sbin_pkcsslotd_pkcsslotd_LDFLAGS = -lpthread -lcrypto if AIX usr_sbin_pkcsslotd_pkcsslotd_LDFLAGS += -Wl,-blibpath:$(libdir)/opencryptoki:$(libdir)/opencryptoki/stdll:/usr/lib:/usr/lib64 else usr_sbin_pkcsslotd_pkcsslotd_LDFLAGS += -lcap endif if HAVE_LIBUDEV usr_sbin_pkcsslotd_pkcsslotd_LDFLAGS += -ludev endif usr_sbin_pkcsslotd_pkcsslotd_CFLAGS = -DPROGRAM_NAME=\"$(@)\" \ -I${srcdir}/usr/include -I${srcdir}/usr/lib/common \ -I${top_builddir}/usr/lib/common \ -I${top_builddir}/usr/lib/api \ -I${srcdir}/usr/lib/config \ -I${top_builddir}/usr/lib/config 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/lib/config/configuration.c \ usr/lib/config/cfgparse.y usr/lib/config/cfglex.l if AIX usr_sbin_pkcsslotd_pkcsslotd_LDFLAGS += -lbsd endif nodist_usr_sbin_pkcsslotd_pkcsslotd_SOURCES = \ usr/lib/common/dlist.c usr/sbin/pkcsslotd/slotmgr.$(OBJEXT): usr/lib/config/cfgparse.h opencryptoki-opencryptoki-451d99c/usr/sbin/pkcsslotd/pkcsslotd_util.c000066400000000000000000000070111520105705100263040ustar00rootroot00000000000000/* * 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; memcpy(slot_info[id].usergroup, sinfo[id].usergroup, strlen(sinfo[id].usergroup)); slot_count++; } } *processed = slot_count; } opencryptoki-opencryptoki-451d99c/usr/sbin/pkcsslotd/shmem.c000066400000000000000000000230021520105705100243500ustar00rootroot00000000000000/* * 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 /* * getenv() is safe here since we will exclusively create the segment and * make sure only members of pkcs11 group can attach to it. */ 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(PKCS_GROUP); if (!grp) { ErrLog("Group %s does not exist ", PKCS_GROUP); 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); // Not safe to use this segment return FALSE; } } 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); // Not safe to use this segment return FALSE; } return TRUE; #else { #warning "EXPERIMENTAL" int fd; int i; char *buffer; grp = getgrnam(PKCS_GROUP); if (!grp) { ErrLog("Group \"%s\" does not exist! " "Opencryptoki setup is incorrect.", PKCS_GROUP); 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, %s): %s", __func__, MAPFILENAME, PKCS_GROUP, 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)); memset(sp->slot_global_rw_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; } opencryptoki-opencryptoki-451d99c/usr/sbin/pkcsslotd/signal.c000066400000000000000000000105661520105705100245270ustar00rootroot00000000000000/* * 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, 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 */ /* SIGPIPE - Don't want to exit. May happen when a connection to an admin * event sender or a process is closed before all events are delivered. */ static int SigsToIgnore[] = { SIGCHLD, SIGPIPE, }; /************************************************** * 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 #ifdef DEV dump_socket_handler(); #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); term_socket_server(); 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; } opencryptoki-opencryptoki-451d99c/usr/sbin/pkcsslotd/slotmgr.c000066400000000000000000001115641520105705100247410ustar00rootroot00000000000000/* * 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 */ #define _DEFAULT_SOURCE #include #include #include #include #include #include #include #include #include #include #include "log.h" #include "slotmgr.h" #include "pkcsslotd.h" #include "cfgparser.h" #include "configuration.h" #define OBJ_DIR "TOK_OBJ" #define SHA256_HASH_SIZE 32 #define DEF_MANUFID "IBM" #if defined(_AIX) #define DEF_SLOTDESC "AIX" #include #include #include #include #include #else #include #include #define DEF_SLOTDESC "Linux" #endif typedef char sha256_hash_entry[SHA256_HASH_SIZE]; sha256_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]; unsigned int NumberSlotsInDB = 0; int event_support_disabled = 0; Slot_Info_t_64 *psinfo; Slot_Mgr_Socket_t socketData; struct dircheckinfo_s { const char *dir; int mode; int owner_pkcsslotd; }; /* 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[4 * 8 + 4]; 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); } } int compute_sha256(char *buf, int buf_size, char *digest) { EVP_MD_CTX *md_ctx = NULL; unsigned int result_size; int rc; md_ctx = EVP_MD_CTX_create(); if (md_ctx == NULL) { fprintf(stderr, "EVP_MD_CTX_create() failed\n"); return -1; } rc = EVP_DigestInit(md_ctx, EVP_sha256()); 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; } #if defined(_AIX) /* * Naming is hard! What's called capabilities on Linux is called privileges * on AIX. To make matters worse, user privileges are also called privileges. */ int drop_capabilities(void) { privg_t priv_set; if (getppriv(-1, PRIV_MAXIMUM, priv_set, sizeof(priv_set)) == -1) { fprintf(stderr, "Failed to get process privileges: %s\n", strerror(errno)); return -1; } priv_clrall(priv_set); if (setppriv(-1, priv_set, priv_set, priv_set, priv_set) == -1) { fprintf(stderr, "Failed to set process privileges: %s\n", strerror(errno)); return -1; } DbgLog(DL0, "All privileges sucessfully dropped.\n"); return 0; } #else /* * Drop any effective and permitted capabilities (if any). * This function is called after initialization, but before becoming a daemon. */ int drop_capabilities(void) { cap_t caps; caps = cap_get_proc(); if (caps == NULL) { fprintf(stderr, "Failed to get process capabilities: %s\n", strerror(errno)); return -1; } if (cap_clear(caps) != 0) { fprintf(stderr, "Failed to clear capabilities: %s\n", strerror(errno)); cap_free(caps); return -1; } if (cap_set_proc(caps) != 0) { fprintf(stderr, "Failed to set process's capabilities: %s\n", strerror(errno)); cap_free(caps); return -1; } cap_free(caps); DbgLog(DL0, "Dropped all capabilities.\n"); return 0; } #endif /* * This function is called only when running as root user. * Change uid to 'pkcsslotd' and gid to 'pkcs11' and set the group access list * to the groups of user 'pkcsslotd'. * The setuid() call also drops all capabilities (effective and permitted). * The pkcsslotd is then restarted via execv() which applies the capabilities * of the executable file (if any) to the running process, just as if * pkcsslotd was started as pkcsslotd user right away. */ void drop_privileges(struct passwd *pwd) { char program[PATH_MAX + 1] = { 0, }; char* args[] = { program, NULL }; #if defined(_AIX) struct psinfo ps; char procpath[PATH_MAX + 1] = { NULL, }; int psfd; snprintf(procpath, PATH_MAX, "/proc/%lld/psinfo", getpid()); psfd = open(procpath, O_RDONLY); if (psfd == -1) { fprintf(stderr, "Failed to open procfs to read cmdname: %s\n", strerror(errno)); exit(1); } if (read(psfd, &ps, sizeof(ps)) == -1) { fprintf(stderr, "Failed to populate psinfo: %s\n", strerror(errno)); exit(1); } close(psfd); /* * Copies only argv[0], as maintained by the kernel. This is because * parameters are guaranteed to be separated by NULL, which is where strcpy * stops copying. */ strncpy(program, ps.pr_psargs, PATH_MAX); #else if (readlink("/proc/self/exe", program, PATH_MAX) == -1) { fprintf(stderr, "Failed to get executable file name: %s\n", strerror(errno)); exit(1); } #endif if (initgroups(pwd->pw_name, pwd->pw_gid) != 0) { fprintf(stderr, "Failed to set the group access list: %s\n", strerror(errno)); exit(1); } if (setgid(pwd->pw_gid) != 0) { fprintf(stderr, "Failed to set gid to '%s': %s\n", PKCS_GROUP, strerror(errno)); exit(1); } if (setuid(pwd->pw_uid) != 0) { fprintf(stderr, "Failed to set uid to '%s': %s\n", PKCSSLOTD_USER, strerror(errno)); exit(1); } DbgLog(DL0, "Changed uid from 'root' to '%s' and gid to '%s'.\n", PKCSSLOTD_USER, PKCS_GROUP); /* * Start pkcsslotd again as pkcsslotd user. This will also apply the * capabilities to those that are set for the executable file (if any). */ if (execv(program, args) != 0) { fprintf(stderr, "Failed to re-start pkcsslotd: %s\n", strerror(errno)); exit(1); } } /** This function does basic sanity checks to make sure the * eco system is in place for opencryptoki to run properly. **/ void run_sanity_checks(void) { int i, ec; uid_t uid; gid_t gid; struct passwd *pwd; struct group *grp; struct stat sbuf; struct dircheckinfo_s dircheck[] = { { RUN_DIR, S_IRWXU | S_IXGRP, 1 }, { LOCKDIR_PATH, S_IRWXU | S_IRWXG, 0 }, { OCK_LOGDIR, S_IRWXU | S_IRWXG, 0 }, { CONFIG_PATH, S_IRWXU | S_IRWXG, 0 }, { OCK_HSM_MK_CHANGE_PATH, S_IRWXU | S_IRWXG, 0 }, { NULL, 0, 0 }, }; /* check that the pkcsslotd user exists */ pwd = getpwnam(PKCSSLOTD_USER); if (pwd == NULL) { fprintf(stderr, "There is no '%s' user on this system.\n", PKCSSLOTD_USER); exit(1); } /* check that the pkcs11 group exists */ grp = getgrnam(PKCS_GROUP); if (!grp) { fprintf(stderr, "There is no '%s' group on this system.\n", PKCS_GROUP); exit(1); } /* check that our effective user id is pkcsslotd or root */ uid = geteuid(); if (uid != 0 && uid != pwd->pw_uid) { fprintf(stderr, "This daemon needs to be run under the '%s' " "or the 'root' user.\n", PKCSSLOTD_USER); exit(1); } /* check effective group id */ gid = getegid(); if (gid != 0 && gid != grp->gr_gid) { fprintf(stderr, "This daemon should have an effective group id of " "'root' or '%s'.\n", PKCS_GROUP); exit(1); } /* * Check if base directories exist. If not, create them. * Creation of the directory will only work if running as root. * The directories are usually created by tmpfiles.d during system startup. */ 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 or pkcsslotd, and pkcs11 group */ if (chown(dircheck[i].dir, dircheck[i].owner_pkcsslotd ? pwd->pw_uid : geteuid(), grp->gr_gid) != 0) { fprintf(stderr, "Failed to set owner:group ownership on %s directory\n", 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\n", dircheck[i].dir); exit(1); } } } if (uid == 0) drop_privileges(pwd); /* AIX setppriv handles this already */ #if !defined(_AIX) /* Do not allow execve() to grant additional privileges */ if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) != 0) { fprintf(stderr, "Failed to set NO_NEW_PRIVS flag: %s\n", strerror(errno)); exit(1); } #endif if (chdir(RUN_DIR) != 0) { fprintf(stderr, "Failed to set current directory: %s\n", strerror(errno)); exit(1); } } int is_duplicate(sha256_hash_entry hash, sha256_hash_entry *hash_table) { int i; for (i = 0; i < NUMBER_SLOTS_MANAGED; i++) { if (memcmp(hash_table[i], hash, sizeof(sha256_hash_entry)) == 0) return 1; } return 0; } int check_token_group(struct group *tok_grp) { struct group grp_buf, *pkcs11_grp = NULL; struct passwd *pwd; int i, k, err, found, rc = 0; long buf_size; char *buff = NULL; /* No further check if token group is 'pkcs11' */ if (strcmp(tok_grp->gr_name, PKCS_GROUP) == 0) return 0; /* * Must use getgrnam_r() here, because caller is using getgrnam() which * returns a pointer to a static area that would be reused/overwritten by * subsequent calls to getgrnam(). */ buf_size = sysconf(_SC_GETGR_R_SIZE_MAX); if (buf_size <= 0) { err = errno; fprintf(stderr, "sysconf(_SC_GETGR_R_SIZE_MAX) failed [errno=%s].\n", strerror(err)); return err; } retry: buff = calloc(1, buf_size); if (buff == NULL) { fprintf(stderr, "Failed to allocate a buffer of %ld bytes.\n", buf_size); return ENOMEM; } errno = 0; if (getgrnam_r(PKCS_GROUP, &grp_buf, buff, buf_size, &pkcs11_grp) != 0) { err = (errno != 0 ? errno : ENOENT); if (err == ERANGE && buf_size < 64 * 1024) { free(buff); buf_size *= 2; goto retry; } fprintf(stderr, "Group '%s' does not exist [errno=%s].\n", PKCS_GROUP, strerror(err)); rc = err; goto done; } /* Check that all group members are also a member of the 'pkcs11' group */ for (i = 0; tok_grp->gr_mem[i] != NULL; i++) { /* Check if user's primary group is the 'pkcs11' group */ errno = 0; pwd = getpwnam(tok_grp->gr_mem[i]); err = (errno != 0 ? errno : ENOENT); if (pwd == NULL) { fprintf(stderr, "USer '%s' does not exist [errno=%s].\n", tok_grp->gr_mem[i], strerror(err)); rc = EINVAL; /* Continue to display all missing users */ continue; } if (pwd->pw_gid != pkcs11_grp->gr_gid) { /* Check the users secondary groups */ for (k = 0, found = 0; pkcs11_grp->gr_mem[k] != NULL; k++) { if (strcmp(tok_grp->gr_mem[i], pkcs11_grp->gr_mem[k]) == 0) { found = 1; break; } } if (!found) { fprintf(stderr, "User '%s' is member of the token group '%s', " "but is not a member of the '%s' group.\n", tok_grp->gr_mem[i], tok_grp->gr_name, PKCS_GROUP); rc = EINVAL; /* Continue to display all missing users */ continue; } } } done: free(buff); return rc; } 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, err; mode_t proc_umask; char *tokdir = psinfo->tokname; char *tokgroup = psinfo->usergroup; char token_sha256_hash[SHA256_HASH_SIZE]; if (psinfo->present == FALSE) return 0; proc_umask = umask(0); if (strlen(tokgroup) == 0) tokgroup = PKCS_GROUP; /* get token group id */ uid = (int) geteuid(); errno = 0; grp = getgrnam(tokgroup); err = (errno != 0 ? errno : ENOENT); if (!grp) { fprintf(stderr, "Token group '%s' does not exist [errno=%s].\n", tokgroup, strerror(err)); return err; } else { grpid = grp->gr_gid; } rc = check_token_group(grp); if (rc) return rc; /* * Skip if no dedicated token directory is required. If no 'tokname' is * specified, the token directory name is not known, thus we can not check * or create it. */ if (!tokdir || strlen(tokdir) == 0) { /* * Build the SHA256 hash from the dll name prefixed with 'dll:' to * check for duplicate tokens with no 'tokname'. */ snprintf(tokendir, sizeof(tokendir), "dll:%s", psinfo->dll_location); rc = compute_sha256(tokendir, strlen(tokendir), token_sha256_hash); if (rc) { fprintf(stderr, "Error calculating SHA256 of token name!\n"); return -1; } /* check for duplicate token names */ if (is_duplicate(token_sha256_hash, tokname_hash_table)) { fprintf(stderr, "Duplicate token in slot %llu!\n", psinfo->slot_number); return -1; } /* add entry into hash table */ memcpy(tokname_hash_table[psinfo->slot_number], token_sha256_hash, SHA256_HASH_SIZE); return 0; } /* Check if the path length fits in the max path length (include 2 * / and 0) */ if (strlen(CONFIG_PATH) + strlen(tokdir) + strlen(OBJ_DIR) + 3 > PATH_MAX) { fprintf(stderr, "Path name for token object directory too long!\n"); return -1; } /* calculate SHA256 hash from token name */ rc = compute_sha256(tokdir, strlen(tokdir), token_sha256_hash); if (rc) { fprintf(stderr, "Error calculating SHA256 of token name!\n"); return -1; } /* check for duplicate token names */ if (is_duplicate(token_sha256_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_sha256_hash, SHA256_HASH_SIZE); /* Create token specific directory */ /* sprintf checked above */ sprintf(tokendir, "%s/%s", CONFIG_PATH, tokdir); rc = stat(tokendir, &sbuf); err = errno; if (rc != 0 && err == ENOENT) { if (strcmp(tokgroup, PKCS_GROUP) != 0) { fprintf(stderr, "Can not create token directory '%s' with a token group " "other than '%s'. You must create the token directory " "using the pkcstok_admin tool with the proper owner " "group.\n", tokendir, PKCS_GROUP); umask(proc_umask); return EACCES; } /* directory does not exist, create it */ rc = mkdir(tokendir, S_IRWXU | S_IRWXG); if (rc != 0) { fprintf(stderr, "Creating directory '%s' failed [errno=%s].\n", tokendir, strerror(errno)); umask(proc_umask); return rc; } rc = chown(tokendir, uid, grpid); if (rc != 0) { fprintf(stderr, "Could not set '%s' group permission [errno=%s].\n", PKCS_GROUP, strerror(errno)); umask(proc_umask); return rc; } } else if (rc != 0) { fprintf(stderr, "Could not stat directory '%s' [errno=%s].\n", tokendir, strerror(err)); umask(proc_umask); return err; } else if (sbuf.st_gid != grpid) { fprintf(stderr, "Directory '%s' is not owned by token group '%s'.\n", tokendir, tokgroup); umask(proc_umask); return EACCES; } /* * Can not check or create TOK_OBJ directory inside the token directory * if the token group is different than 'pkcs11', because the 'pkcsslotd' * user does not have permissions to access such a token directory. */ if (strcmp(tokgroup, PKCS_GROUP) != 0) { umask(proc_umask); return 0; } /* Create TOK_OBJ directory */ /* sprintf checked above */ sprintf(tokendir, "%s/%s/%s", CONFIG_PATH, tokdir, OBJ_DIR); rc = stat(tokendir, &sbuf); err = errno; if (rc != 0 && err == ENOENT) { /* directory does not exist, create it */ rc = mkdir(tokendir, S_IRWXU | S_IRWXG); if (rc != 0) { fprintf(stderr, "Creating directory '%s' failed [errno=%s].\n", tokendir, strerror(errno)); umask(proc_umask); return rc; } rc = chown(tokendir, uid, grpid); if (rc != 0) { fprintf(stderr, "Could not set '%s' group permission [errno=%s].\n", PKCS_GROUP, strerror(errno)); umask(proc_umask); return rc; } } else if (rc != 0) { fprintf(stderr, "Could not stat directory '%s' [errno=%s].\n", tokendir, strerror(err)); umask(proc_umask); return err; } else if (sbuf.st_gid != grpid) { fprintf(stderr, "Directory '%s' is not owned by token group '%s'.\n", tokendir, tokgroup); umask(proc_umask); return EACCES; } 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=%s].\n", PID_FILE_PATH, strerror(errno)); return -1; } fprintf(pidfile, "%d\n", (int) pid); fflush(pidfile); fclose(pidfile); InfoLog("PID file (" PID_FILE_PATH ") created"); return 0; } static void config_parse_error(int line, int col, const char *msg) { ErrLog("Error parsing config file: line %d column %d: %s\n", line, col, msg); } static int do_str(char *slotinfo, size_t size, const char* file, const char* tok, const char *val, char padding) { if (strlen(val) > size) { ErrLog("Error parsing config file '%s': %s has too many characters\n", file, tok); return -1; } memset(slotinfo, padding, size); memcpy(slotinfo, val, strlen(val)); return 0; } static int config_parse_slot(const char *config_file, struct ConfigIdxStructNode *slot) { struct ConfigBaseNode *c; int i, slot_no; unsigned int vers; #if defined(_AIX) char libname[1025] = {0, }; char toktype[5] = {0, }; char *substr = NULL; int idx = 0; #endif char *str = NULL; slot_no = slot->idx; DbgLog(DL3, "Slot: %d\n", slot_no); if (slot_no >= NUMBER_SLOTS_MANAGED) { ErrLog("Error parsing config file '%s': Slot number %d unsupported! " "Slot number has to be less than %d!\n", config_file, slot_no, NUMBER_SLOTS_MANAGED); return 1; } if (sinfo[slot_no].present) { ErrLog("Error parsing config file '%s': Duplicate slot number %d\n", config_file, slot_no); return 1; } memset(&sinfo[slot_no].slot_number, 0, sizeof(sinfo[slot_no].slot_number)); sinfo[slot_no].slot_number = slot_no; confignode_foreach(c, slot->value, i) { DbgLog(DL3, "Config node: '%s' type: %u line: %u\n", c->key, c->type, c->line); if (strcmp(c->key, "stdll") == 0 && (str = confignode_getstr(c)) != NULL) { #if defined(_AIX) /* * AIX bundles libraries as ranlib archives. The objects therefore * need to be loaded from within the library. Instead of modifying * the parser to handle the new string format, it's easier to just * build the string ourselves - this only happens at daemon init, * so performance isn't a concern here. */ substr = strrchr(str, '_'); if (substr == NULL) /* no '_', libname is malformed */ return 1; ++substr; while (*substr != '.' && idx < sizeof(toktype) - 1) { toktype[idx++] = (char)*substr; ++substr; } snprintf(libname, sizeof(libname), "libpkcs11_%s.a(libpkcs11_%s.so.0)", toktype, toktype); str = (char*)libname; #endif if (do_str((char *)&sinfo[slot_no].dll_location, sizeof(sinfo[slot_no].dll_location), config_file, c->key, str, 0)) return 1; sinfo[slot_no].present = TRUE; continue; } if (strcmp(c->key, "description") == 0 && (str = confignode_getstr(c)) != NULL) { if (do_str((char *)&sinfo[slot_no].pk_slot.slotDescription, sizeof(sinfo[slot_no].pk_slot.slotDescription), config_file, c->key, str, ' ')) return 1; continue; } if (strcmp(c->key, "manufacturer") == 0 && (str = confignode_getstr(c)) != NULL) { if (do_str((char *)&sinfo[slot_no].pk_slot.manufacturerID, sizeof(sinfo[slot_no].pk_slot.manufacturerID), config_file, c->key, str, ' ')) return 1; continue; } if (strcmp(c->key, "confname") == 0 && (str = confignode_getstr(c)) != NULL) { if (do_str((char *)&sinfo[slot_no].confname, sizeof(sinfo[slot_no].confname), config_file, c->key, str, 0)) return 1; continue; } if (strcmp(c->key, "tokname") == 0 && (str = confignode_getstr(c)) != NULL) { if (do_str((char *)&sinfo[slot_no].tokname, sizeof(sinfo[slot_no].tokname), config_file, c->key, str, 0)) return 1; continue; } if (strcmp(c->key, "hwversion") == 0 && confignode_getversion(c, &vers) == 0) { sinfo[slot_no].pk_slot.hardwareVersion.major = vers >> 16; sinfo[slot_no].pk_slot.hardwareVersion.minor = vers & 0xffffu; continue; } if (strcmp(c->key, "firmwareversion") == 0 && confignode_getversion(c, &vers) == 0) { sinfo[slot_no].pk_slot.firmwareVersion.major = vers >> 16; sinfo[slot_no].pk_slot.firmwareVersion.minor = vers & 0xffffu; continue; } if (strcmp(c->key, "tokversion") == 0 && confignode_getversion(c, &sinfo[slot_no].version) == 0) continue; if (strcmp(c->key, "usergroup") == 0 && (str = confignode_getstr(c)) != NULL) { if (do_str((char *)&sinfo[slot_no].usergroup, sizeof(sinfo[slot_no].usergroup), config_file, c->key, str, 0)) return 1; continue; } ErrLog("Error parsing config file '%s': unexpected token '%s' " "at line %d: \n", config_file, c->key, c->line); return 1; } /* set some defaults if user hasn't set these. */ if (!sinfo[slot_no].pk_slot.slotDescription[0]) { memset(&sinfo[slot_no].pk_slot.slotDescription[0], ' ', sizeof(sinfo[slot_no].pk_slot.slotDescription)); memcpy(&sinfo[slot_no].pk_slot.slotDescription[0], DEF_SLOTDESC, strlen(DEF_SLOTDESC)); } if (!sinfo[slot_no].pk_slot.manufacturerID[0]) { memset(&sinfo[slot_no].pk_slot.manufacturerID[0], ' ', sizeof(sinfo[slot_no].pk_slot.manufacturerID)); memcpy(&sinfo[slot_no].pk_slot.manufacturerID[0], DEF_MANUFID, strlen(DEF_MANUFID)); } NumberSlotsInDB++; return 0; } static int config_parse_statistics(const char *config_file, struct ConfigBareListNode *statistics) { struct ConfigBaseNode *c; int i; confignode_foreach(c, statistics->value, i) { DbgLog(DL3, "Config node: '%s' type: %u line: %u\n", c->key, c->type, c->line); if (c->type == CT_BARE && strcmp(c->key, "off") == 0) { socketData.flags &= ~(FLAG_STATISTICS_ENABLED | FLAG_STATISTICS_IMPLICIT | FLAG_STATISTICS_INTERNAL); continue; } if (c->type == CT_BARE && strcmp(c->key, "on") == 0) { socketData.flags |= FLAG_STATISTICS_ENABLED; continue; } if (c->type == CT_BARE && strcmp(c->key, "implicit") == 0) { socketData.flags |= FLAG_STATISTICS_IMPLICIT; continue; } if (c->type == CT_BARE && strcmp(c->key, "internal") == 0) { socketData.flags |= FLAG_STATISTICS_INTERNAL; continue; } ErrLog("Error parsing config file '%s': unexpected token '%s' " "at line %d: \n", config_file, c->key, c->line); return 1; } return 0; } static int config_parse(const char *config_file) { FILE *file; struct stat statbuf; struct ConfigBaseNode *c, *config = NULL; struct ConfigIdxStructNode *slot; struct ConfigBareListNode *statistics; int i, ret = 0; file = fopen(config_file, "r"); if (file == NULL) { ErrLog("Error opening config file '%s': %s\n", config_file, strerror(errno)); return -1; } if (fstat(fileno(file), &statbuf)) { ErrLog("Error get file information for config file '%s': %s\n", config_file, strerror(errno)); fclose(file); return -1; } if ((statbuf.st_mode & S_IWOTH)) { ErrLog("Config file %s is world writable, this is not accepted\n", config_file); fclose(file); return -1; } ret = parse_configlib_file(file, &config, config_parse_error, 0); fclose(file); if (ret != 0) { ErrLog("Error parsing config file '%s'\n", config_file); goto done; } confignode_foreach(c, config, i) { DbgLog(DL3, "Config node: '%s' type: %u line: %u\n", c->key, c->type, c->line); if (confignode_hastype(c, CT_FILEVERSION)) { DbgLog(DL0, "Config file version: '%s'\n", confignode_to_fileversion(c)->base.key); continue; } if (confignode_hastype(c, CT_BARECONST)) { if (strcmp(confignode_to_bareconst(c)->base.key, "disable-event-support") == 0) { event_support_disabled = 1; continue; } ErrLog("Error parsing config file '%s': unexpected token '%s' " "at line %d: \n", config_file, c->key, c->line); ret = -1; break; } if (confignode_hastype(c, CT_BARELIST)) { statistics = confignode_to_barelist(c); if (strcmp(statistics->base.key, "statistics") == 0) { ret = config_parse_statistics(config_file, statistics); if (ret != 0) break; continue; } ErrLog("Error parsing config file '%s': unexpected token '%s' " "at line %d: \n", config_file, c->key, c->line); ret = -1; break; } if (confignode_hastype(c, CT_IDX_STRUCT)) { slot = confignode_to_idxstruct(c); if (strcmp(slot->base.key, "slot") == 0) { ret = config_parse_slot(config_file, slot); if (ret != 0) break; continue; } ErrLog("Error parsing config file '%s': unexpected token '%s' " "at line %d: \n", config_file, c->key, c->line); ret = -1; break; } ErrLog("Error parsing config file '%s': unexpected token '%s' " "at line %d: \n", config_file, c->key, c->line); ret = -1; break; } done: confignode_deepfree(config); return ret; } static int teardown(int rc) { term_socket_server(); DestroyMutexes(); DetachFromSharedMemory(); DestroySharedMemory(); return rc; } static int setup_sock_data(void) { if (!init_socket_data(&socketData)) { DestroyMutexes(); DetachFromSharedMemory(); DestroySharedMemory(); return 6; } if (event_support_disabled) socketData.flags |= FLAG_EVENT_SUPPORT_DISABLED; /* Create customized token directories */ psinfo = &socketData.slot_info[0]; for (int i = 0; i < NUMBER_SLOTS_MANAGED; i++, psinfo++) { if (chk_create_tokdir(psinfo)) { DestroyMutexes(); DetachFromSharedMemory(); DestroySharedMemory(); return EACCES; } } /* setup completed successfully */ return 0; } static int setup_sock_server(void) { if (!init_socket_server(event_support_disabled)) { DestroyMutexes(); DetachFromSharedMemory(); DestroySharedMemory(); return 5; } /* setup completed successfully */ 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; /**********************************/ /* 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); } socketData.flags |= FLAG_STATISTICS_ENABLED; ret = config_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 ((ret = setup_sock_data()) != 0) return ret; #if !defined(_AIX) if ((ret = setup_sock_server()) != 0) return ret; #endif if (drop_capabilities() != 0) return 7; /* * Become a Daemon, if called for */ if (Daemon) { pid_t pid; if ((pid = fork()) < 0) { #if !defined(_AIX) term_socket_server(); #endif 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 } #if defined(_AIX) /* * Set up the socket server /after/ the fork on AIX. This is because * AIX closes the pollset fd before the fork, with no way of continuing * to use it in the child. Therefore, pollset needs to be initialised * ONLY in the client process to actually be useful. * Quoting from the manpage: * A process can call fork after calling pollset_create. The child process * will already have a pollset ID per pollset, but pollset_destroy, * pollset_ctl, pollset_query, and pollset_poll operations will fail with * an errno value of EACCES. */ if ((ret = setup_sock_server()) != 0) return ret; #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()) return teardown(8); /* ultimately 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) /* start garbage collection thread */ if (!StartGCThread(shmp)) return teardown(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 socket_connection_handler(10); } /************************************************************* * * Here we need to actually go through the processes and verify that they * 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 */ opencryptoki-opencryptoki-451d99c/usr/sbin/pkcsslotd/socket_server.c000066400000000000000000001776071520105705100261420ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2013, 2021 * * 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 #if defined(_AIX) #include #include #else #include #include #endif #if defined(__GNUC__) && __GNUC__ >= 7 || defined(__clang__) && __clang_major__ >= 12 #define FALL_THROUGH __attribute__ ((fallthrough)) #else #define FALL_THROUGH ((void)0) #endif #ifdef WITH_LIBUDEV #include #endif #include "log.h" #include "slotmgr.h" #include "pkcsslotd.h" #include "apictl.h" #include "dlist.h" #include "events.h" #define MAX_EPOLL_EVENTS 128 #ifdef WITH_LIBUDEV #define UDEV_RECV_BUFFFER_SIZE 512 * 1024 #define UDEV_SUBSYSTEM_AP "ap" #define UDEV_ACTION_BIND "bind" #define UDEV_ACTION_UNBIND "unbind" #define UDEV_ACTION_CHANGE "change" #define UDEV_ACTION_DEVTYPE_APQN "ap_queue" #define UDEV_PROPERTY_DEVTYPE "DEV_TYPE" #define UDEV_PROPERTY_CONFIG "CONFIG" #define UDEV_PROPERTY_ONLINE "ONLINE" #endif #if defined(_AIX) #define EPOLLHUP POLLHUP #define EPOLLERR POLLERR #define EPOLLIN POLLIN #define EPOLLOUT POLLOUT #endif struct epoll_info { int (* notify)(int events, void *private); void (* free)(void *private); void *private; unsigned long ref_count; }; struct listener_info { int socket; const char *file_path; int (* new_conn)(int socket, struct listener_info *listener); struct epoll_info ep_info; unsigned long num_clients; unsigned long max_num_clients; }; enum xfer_state { XFER_IDLE = 0, XFER_RECEIVE = 1, XFER_SEND = 2, }; struct client_info { int socket; int (* xfer_complete)(void *client); void (* hangup)(void *client); void (* free)(void *client); void *client; struct epoll_info ep_info; enum xfer_state xfer_state; char *xfer_buffer; size_t xfer_size; size_t xfer_offset; }; enum proc_state { PROC_INITIAL_SEND = 0, PROC_INITIAL_SEND2 = 1, PROC_WAIT_FOR_EVENT = 2, PROC_SEND_EVENT = 3, PROC_SEND_PAYLOAD = 4, PROC_RECEIVE_REPLY = 5, PROC_HANGUP = 6, }; struct proc_conn_info { struct client_info client_info; enum proc_state state; DL_NODE *events; struct event_info *event; event_reply_t reply; Slot_Mgr_Client_Cred_t client_cred; }; enum admin_state { ADMIN_RECEIVE_EVENT = 0, ADMIN_RECEIVE_PAYLOAD = 1, ADMIN_EVENT_DELIVERED = 2, ADMIN_SEND_REPLY = 3, ADMIN_WAIT_FOR_EVENT_LIMIT = 4, ADMIN_HANGUP = 5, }; struct admin_conn_info { struct client_info client_info; enum admin_state state; struct event_info *event; }; #ifdef WITH_LIBUDEV struct udev_mon { struct udev *udev; struct udev_monitor *mon; int socket; struct epoll_info ep_info; struct event_info *delayed_event; }; #endif struct event_info { event_msg_t event; char *payload; event_reply_t reply; unsigned long proc_ref_count; /* # of processes using this event */ struct admin_conn_info *admin_ref; /* Admin connection to send reply back */ }; #if defined(_AIX) static pollset_t pollset_fd = -1; #else static int epoll_fd = -1; #endif static struct listener_info proc_listener = { .socket = -1 }; static DL_NODE *proc_connections = NULL; static struct listener_info admin_listener = { .socket = -1 }; static DL_NODE *admin_connections = NULL; #ifdef WITH_LIBUDEV static struct udev_mon udev_mon = { .socket = -1 }; #endif static DL_NODE *pending_events = NULL; static unsigned long pending_events_count = 0; #define MAX_PENDING_EVENTS 1024 /* * Iterate over all connections in a safe way. Before actually iterating, * increment the ref count of ALL connections, because any processing may * cause any of the connections to be hang-up, and thus freed and removed * from the list. We need to make sure that while we are iterating over the * connections, none of them gets removed from the list. */ #define FOR_EACH_CONN_SAFE_BEGIN(list, conn) { \ DL_NODE *_node, *_next; \ _node = dlist_get_first(list); \ while (_node != NULL) { \ conn = _node->data; \ _next = dlist_next(_node); \ client_socket_get(&(conn)->client_info); \ _node = _next; \ } \ _node = dlist_get_first(list); \ while (_node != NULL) { \ conn = _node->data; \ _next = dlist_next(_node); #define FOR_EACH_CONN_SAFE_END(list, conn) \ _node = _next; \ } \ _node = dlist_get_first(list); \ while (_node != NULL) { \ conn = _node->data; \ _next = dlist_next(_node); \ client_socket_put(&(conn)->client_info); \ _node = _next; \ } \ } static void listener_socket_close(int socketfd, const char *file_path); static int listener_client_hangup(struct listener_info *listener); static void event_delivered(struct event_info *event); static int client_socket_notify(int events, void *private); static void client_socket_free(void *private); static int proc_xfer_complete(void *client); static int proc_start_deliver_event(struct proc_conn_info *conn); static int proc_deliver_event(struct proc_conn_info *conn, struct event_info *event); static int proc_event_delivered(struct proc_conn_info *conn, struct event_info *event); static inline void proc_get(struct proc_conn_info *conn); static inline void proc_put(struct proc_conn_info *conn); static void proc_hangup(void *client); static void proc_free(void *client); static int admin_xfer_complete(void *client); static void admin_event_limit_underrun(struct admin_conn_info *conn); static int admin_event_delivered(struct admin_conn_info *conn, struct event_info **event); static inline void admin_get(struct admin_conn_info *conn); static inline void admin_put(struct admin_conn_info *conn); static void admin_hangup(void *client); static void admin_free(void *client); #ifdef WITH_LIBUDEV static void udev_mon_term(struct udev_mon *udev_mon); static int udev_mon_notify(int events, void *private); #endif static void epoll_info_init(struct epoll_info *epoll_info, int (* notify)(int events, void *private), void (* free_cb)(void *private), void *private) { epoll_info->ref_count = 1; epoll_info->notify = notify; epoll_info->free = free_cb; epoll_info->private = private; } static void epoll_info_get(struct epoll_info *epoll_info) { epoll_info->ref_count++; DbgLog(DL3, "%s: private: %p, ref_count: %lu", __func__, epoll_info->private, epoll_info->ref_count); } static void epoll_info_put(struct epoll_info *epoll_info) { if (epoll_info->ref_count > 0) epoll_info->ref_count--; DbgLog(DL3, "%s: private: %p, ref_count: %lu", __func__, epoll_info->private, epoll_info->ref_count); if (epoll_info->ref_count == 0 && epoll_info->free != NULL) epoll_info->free(epoll_info->private); } static int client_socket_init(int socket, int (* xfer_complete)(void *client), void (* hangup)(void *client), void (* free_cb)(void *client), void *client, struct client_info *client_info) { #if defined(_AIX) struct poll_ctl_ext evt = { .version = 1, .command = PS_ADD, .events = POLLIN | POLLOUT | POLLET | POLLERR | POLLHUP | POLLRDNORM | POLLWRNORM, .fd = socket, .u.addr = &client_info->ep_info }; #else struct epoll_event evt; #endif int rc, err; if (xfer_complete == NULL || hangup == NULL) return -EINVAL; epoll_info_init(&client_info->ep_info, client_socket_notify, client_socket_free, client_info); client_info->socket = socket; client_info->xfer_complete = xfer_complete; client_info->hangup = hangup; client_info->free = free_cb; client_info->client = client; client_info->xfer_state = XFER_IDLE; rc = fcntl(socket, F_SETFL, O_NONBLOCK); if (rc < 0) { err = errno; InfoLog("%s: Failed to set client socket %d to non-blocking, errno " "%d (%s).", __func__, socket, err, strerror(err)); return -err; } #if defined(_AIX) evt.fd = socket; rc = pollset_ctl_ext(pollset_fd, &evt, 1); #else evt.events = EPOLLIN | EPOLLOUT | EPOLLRDHUP | EPOLLERR | EPOLLET; evt.data.ptr = &client_info->ep_info; rc = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, socket, &evt); #endif if (rc != 0) { err = errno; InfoLog("%s: Failed to add client socket %d to epoll, errno %d (%s).", __func__, socket, err, strerror(err)); close(socket); return -err; } return 0; } static inline void client_socket_get(struct client_info *client_info) { epoll_info_get(&client_info->ep_info); } static inline void client_socket_put(struct client_info *client_info) { epoll_info_put(&client_info->ep_info); } static void client_socket_term(struct client_info *client_info) { #if defined(_AIX) struct poll_ctl_ext evt = { .version = 1, .command = PS_DELETE, .events = NULL, /* ignored */ .fd = client_info->socket, .u.addr = NULL /* ignored */ }; pollset_ctl_ext(pollset_fd, &evt, 1); #else epoll_ctl(epoll_fd, EPOLL_CTL_DEL, client_info->socket, NULL); #endif close(client_info->socket); client_info->socket = -1; } static int client_socket_notify(int events, void *private) { struct client_info *client_info = private; ssize_t num; int rc, err, socket = client_info->socket; DbgLog(DL3, "%s: Epoll event on client %p socket %d: events: 0x%x xfer: %d", __func__, client_info, socket, events, client_info->xfer_state); if (socket < 0) return -ENOTCONN; if (events & (EPOLLHUP | EPOLLERR)) { DbgLog(DL3, "EPOLLHUP | EPOLLERR"); client_info->hangup(client_info->client); client_info = NULL; /* client_info may have been freed by now */ return 0; } if (client_info->xfer_state == XFER_RECEIVE && (events & EPOLLIN)) { DbgLog(DL3, "%s: EPOLLIN: buffer: %p size: %lu ofs: %lu", __func__, client_info->xfer_buffer, client_info->xfer_size, client_info->xfer_offset); num = read(client_info->socket, client_info->xfer_buffer + client_info->xfer_offset, client_info->xfer_size - client_info->xfer_offset); if (num <= 0) { err = errno; DbgLog(DL3, "%s: read failed with: num: %ld errno: %d (%s)", __func__, num, num < 0 ? err : 0, num < 0 ? strerror(err) : "none"); if (num < 0 && err == EWOULDBLOCK) return 0; /* Will be continued when socket becomes readable */ /* assume connection closed by peer */ client_info->hangup(client_info->client); client_info = NULL; /* client_info may have been freed by now */ return 0; } else { DbgLog(DL3, "%s: %lu bytes received", __func__, num); client_info->xfer_offset += num; DbgLog(DL3, "%s: %lu bytes left", __func__, client_info->xfer_size - client_info->xfer_offset); if (client_info->xfer_offset >= client_info->xfer_size) { client_info->xfer_state = XFER_IDLE; client_info->xfer_buffer = NULL; client_info->xfer_size = 0; client_info->xfer_offset = 0; client_socket_get(client_info); rc = client_info->xfer_complete(client_info->client); if (rc != 0) { InfoLog("%s: xfer_complete callback failed for client " "socket %d, rc: %d", __func__, socket, rc); client_info->hangup(client_info->client); } client_socket_put(client_info); client_info = NULL; /* client_info may have been freed by now */ return rc; } return 0; } } if (client_info->xfer_state == XFER_SEND && (events & EPOLLOUT)) { DbgLog(DL3, "%s: EPOLLOUT: buffer: %p size: %lu ofs: %lu", __func__, client_info->xfer_buffer, client_info->xfer_size, client_info->xfer_offset); num = write(client_info->socket, client_info->xfer_buffer + client_info->xfer_offset, client_info->xfer_size - client_info->xfer_offset); if (num < 0) { err = errno; DbgLog(DL3, "%s: write failed with: errno: %d (%s)", __func__, err, strerror(err)); if (err == EWOULDBLOCK) return 0; /* Will be continued when socket becomes writable */ /* assume connection closed by peer */ client_info->hangup(client_info->client); client_info = NULL; /* client_info may have been freed by now */ return 0; } else { DbgLog(DL3, "%s: %lu bytes sent", __func__, num); client_info->xfer_offset += num; DbgLog(DL3, "%s: %lu bytes left", __func__, client_info->xfer_size - client_info->xfer_offset); if (client_info->xfer_offset >= client_info->xfer_size) { client_info->xfer_state = XFER_IDLE; client_info->xfer_buffer = NULL; client_info->xfer_size = 0; client_info->xfer_offset = 0; client_socket_get(client_info); rc = client_info->xfer_complete(client_info->client); if (rc != 0) { InfoLog("%s: xfer_complete callback failed for client " "socket %d, rc: %d", __func__, socket, rc); client_info->hangup(client_info->client); } client_socket_put(client_info); client_info = NULL; /* client_info may have been freed by now */ return rc; } return 0; } } #if defined(_AIX) if (client_info->xfer_state == XFER_IDLE && (events == (POLLRDNORM | POLLWRNORM | POLLIN))) { DbgLog(DL3, "%s: Graceful shutdown, events 0x%x generated", __func__, events); /* No EPOLLHUP-behaviour is available on AIX */ client_info->hangup(client_info->client); client_info = NULL; /* freed on return to socket_connection_handler */ } #endif return 0; } static void client_socket_free(void *private) { struct client_info *client_info = private; DbgLog(DL3, "%s: %p", __func__, client_info); if (client_info->free != NULL) client_info->free(client_info->client); } static int client_socket_receive(struct client_info *client_info, void *buffer, size_t size) { if (client_info->socket < 0) return -ENOTCONN; client_info->xfer_state = XFER_RECEIVE; client_info->xfer_buffer = (char *)buffer; client_info->xfer_size = size; client_info->xfer_offset = 0; DbgLog(DL3, "%s: Start receive on client socket %d: buffer: %p size: %lu", __func__, client_info->socket, buffer, size); return client_socket_notify(EPOLLIN, client_info); } static int client_socket_send(struct client_info *client_info, void *buffer, size_t size) { if (client_info->socket < 0) return -ENOTCONN; client_info->xfer_state = XFER_SEND; client_info->xfer_buffer = (char *)buffer; client_info->xfer_size = size; client_info->xfer_offset = 0; DbgLog(DL3, "%s: Start send on client socket %d: buffer: %p size: %lu", __func__, client_info->socket, buffer, size); return client_socket_notify(EPOLLOUT, client_info); } static struct event_info *event_new(unsigned int payload_len, struct admin_conn_info *admin_conn) { struct event_info *event; event = calloc(1, sizeof(struct event_info)); if (event == NULL) { ErrLog("%s: Failed to allocate the event", __func__); return NULL; } event->event.version = EVENT_VERSION_1; event->event.payload_len = payload_len; if (payload_len > 0) { event->payload = malloc(payload_len); if (event->payload == NULL) { ErrLog("%s: Failed to allocate the event payload", __func__); free(event); return NULL; } } event->reply.version = EVENT_VERSION_1; if (admin_conn != NULL) admin_get(admin_conn); event->admin_ref = admin_conn; DbgLog(DL3, "%s: allocated event: %p", __func__, event); return event; } static void event_limit_underrun(void) { struct admin_conn_info *conn; DbgLog(DL3, "%s: pending_events_count: %lu", __func__, pending_events_count); #ifdef WITH_LIBUDEV /* Notify the udev monitor */ udev_mon_notify(EPOLLIN, &udev_mon); #endif /* Notify all admin connections */ FOR_EACH_CONN_SAFE_BEGIN(admin_connections, conn) { admin_event_limit_underrun(conn); } FOR_EACH_CONN_SAFE_END(admin_connections, conn) } static void event_free(struct event_info *event) { DbgLog(DL3, "%s: free event: %p", __func__, event); if (event->payload != NULL) free(event->payload); free(event); } static int event_add_to_pending_list(struct event_info *event) { DL_NODE *list; list = dlist_add_as_last(pending_events, event); if (list == NULL) { ErrLog("%s: failed add event to list of pending events", __func__); return -ENOMEM; } pending_events = list; pending_events_count++; return 0; } static void event_remove_from_pending_list(struct event_info *event) { DL_NODE *node; int trigger = 0; node = dlist_find(pending_events, event); if (node != NULL) { pending_events = dlist_remove_node(pending_events, node); if (pending_events_count >= MAX_PENDING_EVENTS) trigger = 1; if (pending_events_count > 0) pending_events_count--; if (trigger) event_limit_underrun(); } } static int event_start_deliver(struct event_info *event) { struct proc_conn_info *conn; int rc; DbgLog(DL3, "%s: event: %p", __func__, event); if (pending_events_count >= MAX_PENDING_EVENTS) { InfoLog("%s: Max pending events reached", __func__); return -ENOSPC; } /* Add event of the list of pending events */ rc = event_add_to_pending_list(event); if (rc != 0) return rc; /* * Need to increment the event's ref count here, proc_deliver_event() may * already complete the event delivery for one process, which then would * free the event but it needs to be passed to other processes here, too. */ event->proc_ref_count++; FOR_EACH_CONN_SAFE_BEGIN(proc_connections, conn) { rc = proc_deliver_event(conn, event); if (rc != 0) proc_hangup(conn); } FOR_EACH_CONN_SAFE_END(proc_connections, conn) event->proc_ref_count--; DbgLog(DL3, "%s: proc_ref_count: %lu", __func__, event->proc_ref_count); if (event->proc_ref_count == 0) event_delivered(event); return 0; } static void event_delivered(struct event_info *event) { struct admin_conn_info *conn; int rc; DbgLog(DL3, "%s: event: %p", __func__, event); event_remove_from_pending_list(event); /* Notify owning admin connection (if available), free otherwise */ if (event->admin_ref != NULL) { conn = event->admin_ref; admin_get(conn); rc = admin_event_delivered(conn, &event); if (rc != 0) { admin_hangup(conn); if (event != NULL) event_free(event); } admin_put(conn); } else { event_free(event); } } static int proc_new_conn(int socket, struct listener_info *listener) { struct proc_conn_info *conn; struct event_info *event; DL_NODE *list, *node; #if defined(_AIX) struct peercred_struct ucred; #else struct ucred ucred; #endif socklen_t len; int rc = 0; UNUSED(listener); DbgLog(DL0, "%s: Accepted connection from process: socket: %d", __func__, socket); conn = calloc(1, sizeof(struct proc_conn_info)); if (conn == NULL) { ErrLog("%s: Failed to to allocate memory for the process connection", __func__); return -ENOMEM; /* Caller will close socket */ } DbgLog(DL3, "%s: process conn: %p", __func__, conn); len = sizeof(ucred); #if defined(_AIX) rc = getsockopt(socket, SOL_SOCKET, SO_PEERID, &ucred, &len); #else rc = getsockopt(socket, SOL_SOCKET, SO_PEERCRED, &ucred, &len); #endif if (rc != 0 || len != sizeof(ucred)) { rc = -errno; ErrLog("%s: failed get credentials of peer process: %s", strerror(-rc), __func__); free(conn); conn = NULL; goto out; } #if defined(_AIX) DbgLog(DL3, "%s: process pid: %u euid: %u egid: %u", __func__, ucred.pid, ucred.euid, ucred.egid); #else DbgLog(DL3, "%s: process pid: %u uid: %u gid: %u", __func__, ucred.pid, ucred.uid, ucred.gid); #endif conn->client_cred.real_pid = ucred.pid; #if defined(_AIX) conn->client_cred.real_uid = ucred.euid; conn->client_cred.real_gid = ucred.egid; #else conn->client_cred.real_uid = ucred.uid; conn->client_cred.real_gid = ucred.gid; #endif /* Add currently pending events to this connection */ node = dlist_get_first(pending_events); while (node != NULL) { event = (struct event_info *)node->data; DbgLog(DL3, "%s: event: %p", __func__, event); list = dlist_add_as_last(conn->events, event); if (list == NULL) { ErrLog("%s: failed add event to list of process's pending events", __func__); rc = -ENOMEM; goto out; } conn->events = list; event->proc_ref_count++; node = dlist_next(node); } conn->state = PROC_INITIAL_SEND; rc = client_socket_init(socket, proc_xfer_complete, proc_hangup, proc_free, conn, &conn->client_info); if (rc != 0) goto out; /* Add it to the process connections list */ list = dlist_add_as_first(proc_connections, conn); if (list == NULL) { rc = -ENOMEM; goto out; } proc_connections = list; proc_get(conn); rc = client_socket_send(&conn->client_info, &conn->client_cred, sizeof(conn->client_cred)); proc_put(conn); conn = NULL; /* conn may have been freed by now */ out: if (rc != 0 && conn != NULL) { proc_hangup(conn); rc = 0; /* Don't return an error, we have already handled it */ } return rc; } static int proc_xfer_complete(void *client) { struct proc_conn_info *conn = client; int rc; DbgLog(DL0, "%s: Xfer completed: process: %p socket: %d state: %d", __func__, conn, conn->client_info.socket, conn->state); /* * A non-zero return code returned by this function causes the caller to * call proc_hangup(). Thus, no need to call proc_hangup() ourselves. */ switch (conn->state) { case PROC_INITIAL_SEND: conn->state = PROC_INITIAL_SEND2; rc = client_socket_send(&conn->client_info, &socketData, sizeof(socketData)); return rc; case PROC_INITIAL_SEND2: conn->state = PROC_WAIT_FOR_EVENT; rc = proc_start_deliver_event(conn); conn = NULL; /* conn may have been freed by now */ return rc; case PROC_WAIT_FOR_EVENT: /* handled in proc_start_deliver_event */ break; case PROC_SEND_EVENT: if (conn->event == NULL) { TraceLog("%s: No current event to handle", __func__); return -EINVAL; } if (conn->event->event.payload_len > 0) { conn->state = PROC_SEND_PAYLOAD; rc = client_socket_send(&conn->client_info, conn->event->payload, conn->event->event.payload_len); conn = NULL; /* conn may have been freed by now */ return rc; } FALL_THROUGH; /* fall through */ case PROC_SEND_PAYLOAD: if (conn->event == NULL) { TraceLog("%s: No current event to handle", __func__); return -EINVAL; } if (conn->event->event.flags & EVENT_FLAGS_REPLY_REQ) { conn->state = PROC_RECEIVE_REPLY; rc = client_socket_receive(&conn->client_info, &conn->reply, sizeof(conn->reply)); conn = NULL; /* conn may have been freed by now */ return rc; } FALL_THROUGH; /* fall through */ case PROC_RECEIVE_REPLY: if (conn->event == NULL) { TraceLog("%s: No current event to handle", __func__); return -EINVAL; } if (conn->event->event.flags & EVENT_FLAGS_REPLY_REQ) { if (conn->reply.version != EVENT_VERSION_1) { InfoLog("%s: Reply has a wrong version: %u", __func__, conn->reply.version); return -EINVAL; } /* Update reply counters in event */ conn->event->reply.positive_replies += conn->reply.positive_replies; conn->event->reply.negative_replies += conn->reply.negative_replies; conn->event->reply.nothandled_replies += conn->reply.nothandled_replies; } conn->state = PROC_WAIT_FOR_EVENT; rc = proc_event_delivered(conn, conn->event); conn = NULL; /* conn may have been freed by now */ return rc; case PROC_HANGUP: break; } return 0; } static int proc_start_deliver_event(struct proc_conn_info *conn) { DL_NODE *node; int rc; if (conn->state != PROC_WAIT_FOR_EVENT) return 0; node = dlist_get_first(conn->events); if (node == NULL) return 0; conn->event = node->data; memset(&conn->reply, 0, sizeof(conn->reply)); DbgLog(DL3, "%s: process: %p event: %p", __func__, conn, conn->event); conn->state = PROC_SEND_EVENT; rc = client_socket_send(&conn->client_info, &conn->event->event, sizeof(conn->event->event)); conn = NULL; /* conn may have been freed by now */ return rc; } static int proc_deliver_event(struct proc_conn_info *conn, struct event_info *event) { DL_NODE *list; int rc; DbgLog(DL3, "%s: process: %p event: %p", __func__, conn, event); if (conn->state == PROC_HANGUP) return 0; /* Add to process's event list and incr. reference count */ list = dlist_add_as_last(conn->events, event); if (list == NULL) { ErrLog("%s: failed add event to list of process's pending events", __func__); return -ENOMEM; } conn->events = list; event->proc_ref_count++; rc = proc_start_deliver_event(conn); return rc; } static int proc_event_delivered(struct proc_conn_info *conn, struct event_info *event) { DL_NODE *node; int rc; DbgLog(DL3, "%s: process: %p event: %p", __func__, conn, event); conn->event = NULL; /* Remove from process's event list and decr. reference count */ node = dlist_find(conn->events, event); if (node != NULL) { conn->events = dlist_remove_node(conn->events, node); event->proc_ref_count--; } DbgLog(DL3, "%s: proc_ref_count: %lu", __func__, event->proc_ref_count); if (event->proc_ref_count == 0) event_delivered(event); /* Deliver further pending events, if any */ rc = proc_start_deliver_event(conn); conn = NULL; /* conn may have been freed by now */ return rc; } static inline void proc_get(struct proc_conn_info *conn) { client_socket_get(&conn->client_info); } static inline void proc_put(struct proc_conn_info *conn) { client_socket_put(&conn->client_info); } static void proc_hangup(void *client) { struct proc_conn_info *conn = client; struct event_info *event; DL_NODE *node; DbgLog(DL0, "%s: process: %p socket: %d state: %d", __func__, conn, conn->client_info.socket, conn->state); if (conn->state == PROC_HANGUP) return; conn->state = PROC_HANGUP; /* Unlink all pending events */ while ((node = dlist_get_first(conn->events)) != NULL) { event = node->data; /* We did not handle this event */ event->reply.nothandled_replies++; proc_event_delivered(conn, event); } client_socket_term(&conn->client_info); proc_put(conn); } static void proc_free(void *client) { struct proc_conn_info *conn = client; DL_NODE *node; /* Remove it from the process connections list */ node = dlist_find(proc_connections, conn); if (node != NULL) { proc_connections = dlist_remove_node(proc_connections, node); listener_client_hangup(&proc_listener); } DbgLog(DL0, "%s: process: %p", __func__, conn); free(conn); } static int admin_new_conn(int socket, struct listener_info *listener) { struct admin_conn_info *conn; DL_NODE *list; int rc = 0; UNUSED(listener); DbgLog(DL0, "%s: Accepted connection from admin: socket: %d", __func__, socket); conn = calloc(1, sizeof(struct admin_conn_info)); if (conn == NULL) { ErrLog("%s: Failed to to allocate memory for the admin connection", __func__); return -ENOMEM; /* Caller will close socket */ } DbgLog(DL3, "%s: admin conn: %p", __func__, conn); conn->state = ADMIN_RECEIVE_EVENT; rc = client_socket_init(socket, admin_xfer_complete, admin_hangup, admin_free, conn, &conn->client_info); if (rc != 0) goto out; conn->event = event_new(0, conn); if (conn->event == NULL) { ErrLog("%s: Failed to allocate a new event", __func__); rc = -ENOMEM; goto out; } /* Add it to the admin connections list */ list = dlist_add_as_first(admin_connections, conn); if (list == NULL) { ErrLog("%s: Failed to add connection to list of admin connections", __func__); rc = -ENOMEM; goto out; } admin_connections = list; admin_get(conn); rc = client_socket_receive(&conn->client_info, &conn->event->event, sizeof(conn->event->event)); admin_put(conn); conn = NULL; /* conn may have been freed by now */ out: if (rc != 0 && conn != NULL) { admin_hangup(conn); rc = 0; /* Don't return an error, we have already handled it */ } return rc; } static int admin_xfer_complete(void *client) { struct admin_conn_info *conn = client; int rc; DbgLog(DL0, "%s: Xfer completed: admin: %p socket: %d state: %d", __func__, conn, conn->client_info.socket, conn->state); /* * A non-zero return code returned by this function causes the caller to * call admin_hangup(). Thus, no need to call admin_hangup() ourselves. */ if (conn->event == NULL) { TraceLog("%s: No current event", __func__); return -EINVAL; } switch (conn->state) { case ADMIN_RECEIVE_EVENT: /* We have received the event from the admin */ DbgLog(DL3, "%s: Event version: %u", __func__, conn->event->event.version); DbgLog(DL3, "%s: Event type: 0x%08x", __func__, conn->event->event.type); DbgLog(DL3, "%s: Event flags: 0x%08x", __func__, conn->event->event.flags); DbgLog(DL3, "%s: Event token_type: 0x%08x", __func__, conn->event->event.token_type); DbgLog(DL3, "%s: Event token_name: '%.32s'", __func__, conn->event->event.token_label); DbgLog(DL3, "%s: Event process_id: %u", __func__, conn->event->event.process_id); DbgLog(DL3, "%s: Event payload_len: %u", __func__, conn->event->event.payload_len); if (conn->event->event.version != EVENT_VERSION_1) { InfoLog("%s: Admin event has invalid version: %d", __func__, conn->event->event.version); return -EINVAL; } if (conn->event->event.payload_len > EVENT_MAX_PAYLOAD_LENGTH) { InfoLog("%s: Admin event payload is too large: %u", __func__, conn->event->event.payload_len); return -EMSGSIZE; } if (conn->event->event.payload_len > 0) { conn->event->payload = malloc(conn->event->event.payload_len); if (conn->event->payload == NULL) { ErrLog("%s: Failed to allocate the payload buffer", __func__); return -ENOMEM; } conn->state = ADMIN_RECEIVE_PAYLOAD; rc = client_socket_receive(&conn->client_info, conn->event->payload, conn->event->event.payload_len); conn = NULL; /* conn may have been freed by now */ return rc; } FALL_THROUGH; /* fall through */ case ADMIN_RECEIVE_PAYLOAD: /* We have received the payload (if any) from the admin */ conn->state = ADMIN_EVENT_DELIVERED; rc = event_start_deliver(conn->event); if (rc != 0) { if (rc == -ENOSPC) { /* Event limit reached, delay */ conn->state = ADMIN_WAIT_FOR_EVENT_LIMIT; return 0; } return rc; } break; case ADMIN_WAIT_FOR_EVENT_LIMIT: /* This state is handled in admin_event_limit_underrun() */ break; case ADMIN_EVENT_DELIVERED: /* This state is handled in admin_event_delivered() */ break; case ADMIN_SEND_REPLY: /* The reply has been sent to the admin */ if (conn->event->admin_ref != NULL) admin_put(conn->event->admin_ref); conn->event->admin_ref = NULL; event_free(conn->event); conn->event = event_new(0, conn); if (conn->event == NULL) { ErrLog("%s: Failed to allocate a new event", __func__); return -ENOMEM; } conn->state = ADMIN_RECEIVE_EVENT; rc = client_socket_receive(&conn->client_info, &conn->event->event, sizeof(conn->event->event)); conn = NULL; /* conn may have been freed by now */ return rc; case ADMIN_HANGUP: break; } return 0; } static void admin_event_limit_underrun(struct admin_conn_info *conn) { int rc; DbgLog(DL3, "%s: admin: %p state: %d", __func__, conn, conn->state); if (conn->state != ADMIN_WAIT_FOR_EVENT_LIMIT) return; conn->state = ADMIN_EVENT_DELIVERED; rc = event_start_deliver(conn->event); if (rc != 0) { if (rc == -ENOSPC) { /* Event limit reached, delay */ conn->state = ADMIN_WAIT_FOR_EVENT_LIMIT; return; } admin_hangup(conn); } } static int admin_event_delivered(struct admin_conn_info *conn, struct event_info **event) { int rc; DbgLog(DL3, "%s: admin: %p event: %p", __func__, conn, *event); /* * A non-zero return code returned by this function causes the caller to * call admin_hangup(). Thus, no need to call admin_hangup() ourselves. */ if (conn->state != ADMIN_EVENT_DELIVERED) { TraceLog("%s: wrong state: %d", __func__, conn->state); return -EINVAL; } if ((*event)->event.flags & EVENT_FLAGS_REPLY_REQ) { if (conn->event != *event) { TraceLog("%s: event not the current event", __func__); return -EINVAL; } DbgLog(DL3, "%s: Reply version: %u", __func__, (*event)->reply.version); DbgLog(DL3, "%s: Reply positive: %u", __func__, (*event)->reply.positive_replies); DbgLog(DL3, "%s: Reply negative: %u", __func__, (*event)->reply.negative_replies); DbgLog(DL3, "%s: Reply not-handled: %u", __func__, (*event)->reply.nothandled_replies); conn->state = ADMIN_SEND_REPLY; rc = client_socket_send(&conn->client_info, &(*event)->reply, sizeof((*event)->reply)); return rc; } /* No reply required, free the event, and receive the next one */ if ((*event)->admin_ref != NULL) admin_put((*event)->admin_ref); (*event)->admin_ref = NULL; event_free(*event); *event = NULL; conn->event = event_new(0, conn); if (conn->event == NULL) { ErrLog("%s: Failed to allocate a new event", __func__); return -ENOMEM; } conn->state = ADMIN_RECEIVE_EVENT; rc = client_socket_receive(&conn->client_info, &conn->event->event, sizeof(conn->event->event)); return rc; } static inline void admin_get(struct admin_conn_info *conn) { client_socket_get(&conn->client_info); } static inline void admin_put(struct admin_conn_info *conn) { client_socket_put(&conn->client_info); } static void admin_hangup(void *client) { struct admin_conn_info *conn = client; DbgLog(DL0, "%s: admin: %p socket: %d state: %d", __func__, conn, conn->client_info.socket, conn->state); if (conn->state == ADMIN_HANGUP) return; conn->state = ADMIN_HANGUP; /* Unlink pending event (if any) */ if (conn->event != NULL) { if (conn->event->admin_ref != NULL) admin_put(conn->event->admin_ref); conn->event->admin_ref = NULL; if (conn->event->proc_ref_count == 0) { event_remove_from_pending_list(conn->event); event_free(conn->event); } conn->event = NULL; } client_socket_term(&conn->client_info); admin_put(conn); } static void admin_free(void *client) { struct admin_conn_info *conn = client; DL_NODE *node; /* Remove it from the admin connections list */ node = dlist_find(admin_connections, conn); if (node != NULL) { admin_connections = dlist_remove_node(admin_connections, node); listener_client_hangup(&admin_listener); } DbgLog(DL0, "%s: admin: %p", __func__, conn); free(conn); } static int listener_socket_create(const char *file_path) { struct sockaddr_un address; struct group *grp; int listener_socket, err; #if defined(_AIX) listener_socket = socket(PF_UNIX, SOCK_STREAM, 0); #else listener_socket = socket(PF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0); #endif if (listener_socket < 0) { err = errno; ErrLog("%s: Failed to create listener socket, errno %d (%s).", __func__, err, strerror(err)); return -1; } #if defined(_AIX) int flags = fcntl(listener_socket, F_GETFL, 0); if (fcntl(listener_socket, F_SETFL, flags | O_NONBLOCK) == -1) { err = errno; ErrLog("%s: Failed to set NONBLOCK on listener socket, errno %d (%s).", __func__, err, strerror(err)); goto error; } #endif if (unlink(file_path) && errno != ENOENT) { err = errno; ErrLog("%s: Failed to unlink socket file, errno %d (%s).", __func__, err, strerror(err)); goto error; } memset(&address, 0, sizeof(struct sockaddr_un)); address.sun_family = AF_UNIX; strncpy(address.sun_path, file_path, sizeof(address.sun_path) - 1); address.sun_path[sizeof(address.sun_path) - 1] = '\0'; if (bind(listener_socket, (struct sockaddr *) &address, sizeof(struct sockaddr_un)) != 0) { err = errno; ErrLog("%s: Failed to bind to socket, errno %d (%s).", __func__, err, strerror(err)); goto error; } // make socket file part of the pkcs11 group, and write accessable // for that group grp = getgrnam(PKCS_GROUP); if (!grp) { ErrLog("%s: Group %s does not exist", __func__, PKCS_GROUP); goto error; } if (chown(file_path, -1, grp->gr_gid)) { err = errno; ErrLog("%s: Could not change file group on socket, errno %d (%s).", __func__, err, strerror(err)); goto error; } if (chmod(file_path, S_IRUSR | S_IRGRP | S_IWUSR | S_IWGRP)) { err = errno; ErrLog("%s: Could not change file permissions on socket, errno %d (%s).", __func__, err, strerror(err)); goto error; } if (listen(listener_socket, 20) != 0) { err = errno; ErrLog("%s: Failed to listen to socket, errno %d (%s).", __func__, err, strerror(err)); goto error; } return listener_socket; error: if (listener_socket >= 0) listener_socket_close(listener_socket, file_path); return -1; } static void listener_socket_close(int listener_socket, const char *file_path) { close(listener_socket); unlink(file_path); } static int listener_notify(int events, void *private) { struct listener_info *listener = private; struct sockaddr_un address; socklen_t address_length = sizeof(address); int client_socket, rc, err; if ((events & EPOLLIN) == 0) return 0; /* epoll is edge triggered. We must call accept until we get EWOULDBLOCK */ while (listener->num_clients < listener->max_num_clients) { client_socket = accept(listener->socket, (struct sockaddr *) &address, &address_length); if (client_socket < 0) { err = errno; if (err == EWOULDBLOCK) break; InfoLog("%s: Failed to accept connection on socket %d, errno %d (%s).", __func__, listener->socket, err, strerror(err)); return -err; } rc = listener->new_conn(client_socket, listener); if (rc != 0) { TraceLog("%s: new_conn callback failed for client socket %d, rc: %d", __func__, client_socket, rc); close(client_socket); continue; } listener->num_clients++; } return 0; } static int listener_client_hangup(struct listener_info *listener) { int rc, trigger = 0; if (listener->num_clients >= listener->max_num_clients) trigger = 1; /* We were at max clients, trigger accept now */ if (listener->num_clients > 0) listener->num_clients--; if (trigger && listener->num_clients < listener->max_num_clients) { rc = listener_notify(EPOLLIN, listener); if (rc != 0) return rc; } return 0; } static int listener_create(const char *file_path, struct listener_info *listener, int (* new_conn)(int socket, struct listener_info *listener), unsigned long max_num_clients) { #if defined(_AIX) struct poll_ctl_ext evt = { .version = 1, /* enable opaque data storage */ .command = PS_ADD, .events = POLLIN | POLLET, .fd = listener->socket, .u.addr = &listener->ep_info }; #else struct epoll_event evt; #endif int rc, err; if (listener == NULL || new_conn == NULL) return FALSE; memset(listener, 0, sizeof(*listener)); epoll_info_init(&listener->ep_info, listener_notify, NULL, listener); listener->file_path = file_path; listener->new_conn = new_conn; listener->max_num_clients = max_num_clients; listener->socket = listener_socket_create(file_path); if (listener->socket < 0) return FALSE; #if defined(_AIX) evt.fd = listener->socket; rc = pollset_ctl_ext(pollset_fd, &evt, 1); #else evt.events = EPOLLIN | EPOLLET; evt.data.ptr = &listener->ep_info; rc = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, listener->socket, &evt); #endif if (rc != 0) { err = errno; TraceLog("%s: Failed add listener socket %d to epoll, errno %d (%s).", __func__, listener->socket, err, strerror(err)); return FALSE; } return TRUE; } static void listener_term(struct listener_info *listener) { #if defined(_AIX) struct poll_ctl_ext evt = { .version = 1, .command = PS_DELETE, .fd = listener->socket, .u.addr = NULL /* unused */ }; #endif if (listener == NULL || listener->socket < 0) return; #if defined(_AIX) pollset_ctl_ext(pollset_fd, &evt, 1); #else epoll_ctl(epoll_fd, EPOLL_CTL_DEL, listener->socket, NULL); #endif listener_socket_close(listener->socket, listener->file_path); } #ifdef WITH_LIBUDEV static int udev_mon_init(const char *subsystem, struct udev_mon *udev_mon) { struct epoll_event evt; int rc, err; if (subsystem == NULL || udev_mon == NULL) return FALSE; udev_mon->delayed_event = 0; udev_mon->udev = udev_new(); if (udev_mon->udev == NULL) { ErrLog("%s: udev_new failed", __func__); goto error; } udev_mon->mon = udev_monitor_new_from_netlink(udev_mon->udev, "udev"); if (udev_mon->mon == NULL) { ErrLog("%s: udev_monitor_new_from_netlink failed", __func__); goto error; } /* * Try to increase the receive buffer size. This may fail if the required * privileges are not given. Ignore if it fails. */ udev_monitor_set_receive_buffer_size(udev_mon->mon, UDEV_RECV_BUFFFER_SIZE); rc = udev_monitor_filter_add_match_subsystem_devtype(udev_mon->mon, subsystem, NULL); if (rc != 0) { ErrLog("%s: udev_monitor_filter_add_match_subsystem_devtype failed: " "rc=%d", __func__, rc); goto error; } rc = udev_monitor_enable_receiving(udev_mon->mon); if (rc != 0) { ErrLog("%s: udev_monitor_enable_receiving failed: rc=%d", __func__, rc); goto error; } udev_mon->socket = udev_monitor_get_fd(udev_mon->mon); if (udev_mon->socket < 0) { ErrLog("%s: udev_monitor_get_fd failed", __func__); goto error; } epoll_info_init(&udev_mon->ep_info, udev_mon_notify, NULL, udev_mon); evt.events = EPOLLIN | EPOLLET; evt.data.ptr = &udev_mon->ep_info; rc = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, udev_mon->socket, &evt); if (rc != 0) { err = errno; ErrLog("%s: Failed add udev_mon socket %d to epoll, errno %d (%s).", __func__, udev_mon->socket, err, strerror(err)); goto error; } /* Epoll is edge triggered, thus try to receive once */ rc = udev_mon_notify(EPOLLIN, udev_mon); if (rc != 0) goto error; return TRUE; error: udev_mon_term(udev_mon); return FALSE; } static int udev_mon_handle_device(struct udev_mon *udev_mon, struct udev_device *dev) { const char *action, *devname, *devpath, *devtype, *dev_type_prop; const char *config_prop = NULL, *online_prop = NULL; unsigned int card, domain, dev_type = 0; struct event_info *event; event_udev_apqn_data_t *apqn_data; int rc; UNUSED(udev_mon); action = udev_device_get_action(dev); devname = udev_device_get_sysname(dev); devpath = udev_device_get_devpath(dev); devtype = udev_device_get_devtype(dev); dev_type_prop = udev_device_get_property_value(dev, UDEV_PROPERTY_DEVTYPE); config_prop = udev_device_get_property_value(dev, UDEV_PROPERTY_CONFIG); online_prop = udev_device_get_property_value(dev, UDEV_PROPERTY_ONLINE); if (action == NULL || devname == NULL || devpath == NULL || devtype == NULL) return 0; DbgLog(DL3, "%s: Uevent: ACTION=%s DEVNAME=%s DEVPATH=%s DEVTYPE=%s " "DEV_TYPE=%s CONFIG:%s ONLINE=%s", __func__, action, devname, devpath, devtype, dev_type_prop != NULL ? dev_type_prop : "", config_prop != NULL ? config_prop : "", online_prop != NULL ? online_prop : ""); /* We are only interested in bind, unbind, and change events ... */ if (strcmp(action, UDEV_ACTION_BIND) != 0 && strcmp(action, UDEV_ACTION_UNBIND) != 0 && strcmp(action, UDEV_ACTION_CHANGE) != 0) return 0; /* ... for an APQN device */ if (strcmp(devtype, UDEV_ACTION_DEVTYPE_APQN) != 0) return 0; if (sscanf(devname, "%x.%x", &card, &domain) != 2) { TraceLog("%s: failed to parse APQN from DEVNAME: %s", __func__, devname); return -EIO; } if (dev_type_prop != NULL) { if (sscanf(dev_type_prop, "%x", &dev_type) != 1) { TraceLog("%s: failed to parse DEV_TYPE: %s", __func__, dev_type_prop); return -EIO; } } event = event_new(sizeof(event_udev_apqn_data_t), NULL); if (event == NULL) { ErrLog("%s: failed to allocate an event", __func__); return -ENOMEM; } if (strcmp(udev_device_get_action(dev), UDEV_ACTION_CHANGE) == 0) { if (config_prop != NULL) { event->event.type = strcmp(config_prop, "1") == 0 ? EVENT_TYPE_APQN_ADD : EVENT_TYPE_APQN_REMOVE; } else if (online_prop != NULL) { event->event.type = strcmp(online_prop, "1") == 0 ? EVENT_TYPE_APQN_ADD : EVENT_TYPE_APQN_REMOVE; } else { event_free(event); return 0; } } else if (strcmp(udev_device_get_action(dev), UDEV_ACTION_BIND) == 0) { event->event.type = EVENT_TYPE_APQN_ADD; } else { event->event.type = EVENT_TYPE_APQN_REMOVE; } event->event.flags = EVENT_FLAGS_NONE; event->event.token_type = EVENT_TOK_TYPE_ALL; memset(event->event.token_label, ' ', sizeof(event->event.token_label)); apqn_data = (event_udev_apqn_data_t *)event->payload; apqn_data->card = card; apqn_data->domain = domain; apqn_data->device_type = dev_type; DbgLog(DL3, "%s: Event version: %u", __func__, event->event.version); DbgLog(DL3, "%s: Event type: 0x%08x", __func__, event->event.type); DbgLog(DL3, "%s: Event flags: 0x%08x", __func__, event->event.flags); DbgLog(DL3, "%s: Event token_type: 0x%08x", __func__, event->event.token_type); DbgLog(DL3, "%s: Event token_name: '%.32s'", __func__, event->event.token_label); DbgLog(DL3, "%s: Event process_id: %u", __func__, event->event.process_id); DbgLog(DL3, "%s: Event payload_len: %u", __func__, event->event.payload_len); DbgLog(DL3, "%s: Payload: card: %u", __func__, apqn_data->card); DbgLog(DL3, "%s: Payload: domain: %u", __func__, apqn_data->domain); DbgLog(DL3, "%s: Payload: dev.type: %u", __func__, apqn_data->device_type); rc = event_start_deliver(event); if (rc != 0) { if (rc == -ENOSPC) { /* Event limit reached, delay event delivery */ udev_mon->delayed_event = event; return -ENOSPC; } event_free(event); return rc; } return 0; } static int udev_mon_notify(int events, void *private) { struct udev_mon *udev_mon = private; struct udev_device *dev; struct event_info *event; int rc; DbgLog(DL3, "%s: Epoll event on udev_mon socket %d: events: 0x%x", __func__, udev_mon->socket, events); if (udev_mon->delayed_event != NULL) { /* Deliver delayed event first */ event = udev_mon->delayed_event; udev_mon->delayed_event = NULL; rc = event_start_deliver(event); if (rc != 0) { if (rc == -ENOSPC) { /* Event limit reached, delay event delivery */ udev_mon->delayed_event = event; return 0; } event_free(event); return rc; } } while (1) { dev = udev_monitor_receive_device(udev_mon->mon); if (dev == NULL) break; /* this is just like EWOULDBLOCK */ rc = udev_mon_handle_device(udev_mon, dev); if (rc != 0) TraceLog("%s: udev_mon_handle_device failed, rc: %d", __func__, rc); udev_device_unref(dev); /* If event limit reached, stop receiving more events */ if (rc == -ENOSPC) break; }; return 0; } static void udev_mon_term(struct udev_mon *udev_mon) { if (udev_mon == NULL) return; if (udev_mon->socket < 0) return; epoll_ctl(epoll_fd, EPOLL_CTL_DEL, udev_mon->socket, NULL); if (udev_mon->udev != NULL) udev_unref(udev_mon->udev); if (udev_mon->mon != NULL) udev_monitor_unref(udev_mon->mon); if (udev_mon->delayed_event != NULL) event_free(udev_mon->delayed_event); } #endif int init_socket_data(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("%s: Failed to populate slot info.", __func__); return FALSE; } return TRUE; } int socket_connection_handler(int timeout_secs) { #if defined(_AIX) struct pollfd_ext events[MAX_EPOLL_EVENTS]; #else struct epoll_event events[MAX_EPOLL_EVENTS]; #endif int num_events, i, rc = 0, err; struct epoll_info *info; do { #if defined(_AIX) num_events = pollset_poll_ext(pollset_fd, events, MAX_EPOLL_EVENTS, timeout_secs * 1000); #else num_events = epoll_wait(epoll_fd, events, MAX_EPOLL_EVENTS, timeout_secs * 1000); #endif if (num_events < 0) { err = errno; if (err == EINTR) continue; ErrLog("%s: epoll_wait failed, errno %d (%s).", __func__, err, strerror(err)); return FALSE; } /* * Inc ref count of all epoll_infos returned by epoll before handling * any of them via notify. The notify callback may hangup any of * the connections associated with the returned epoll_infos, and we * need to avoid them getting freed before we all handled them. */ for (i = 0; i < num_events; i++) #if defined(_AIX) epoll_info_get(events[i].u.addr); #else epoll_info_get(events[i].data.ptr); #endif for (i = 0; i < num_events; i++) { #if defined(_AIX) info = events[i].u.addr; #else info = events[i].data.ptr; #endif if (info == NULL || info->notify == NULL) continue; #if defined(_AIX) rc = info->notify(events[i].revents, info->private); #else rc = info->notify(events[i].events, info->private); #endif if (rc != 0) TraceLog("%s: notify callback failed, rc: %d", __func__, rc); epoll_info_put(info); } } while (num_events > 0 && rc == 0); /* num_events = 0: timeout */ return TRUE; } int init_socket_server(int event_support_disabled) { int err; #if defined(_AIX) pollset_fd = pollset_create(MAX_EPOLL_EVENTS); if (pollset_fd < 0) { #else epoll_fd = epoll_create1(0); if (epoll_fd < 0) { #endif err = errno; ErrLog("%s: Failed to open epoll socket, errno %d (%s).", __func__, err, strerror(err)); return FALSE; } if (!listener_create(PROC_SOCKET_FILE_PATH, &proc_listener, proc_new_conn, NUMBER_PROCESSES_ALLOWED)) { term_socket_server(); return FALSE; } if (!event_support_disabled) { if (!listener_create(ADMIN_SOCKET_FILE_PATH, &admin_listener, admin_new_conn, NUMBER_ADMINS_ALLOWED)) { term_socket_server(); return FALSE; } #ifdef WITH_LIBUDEV if (!udev_mon_init(UDEV_SUBSYSTEM_AP, &udev_mon)) { term_socket_server(); return FALSE; } #endif } DbgLog(DL0, "%s: Socket server started", __func__); return TRUE; } int term_socket_server(void) { DL_NODE *node, *next; #ifdef WITH_LIBUDEV udev_mon_term(&udev_mon); #endif listener_term(&proc_listener); listener_term(&admin_listener); node = dlist_get_first(proc_connections); while (node != NULL) { next = dlist_next(node); proc_hangup(node->data); node = next; } dlist_purge(proc_connections); node = dlist_get_first(admin_connections); while (node != NULL) { next = dlist_next(node); admin_hangup(node->data); node = next; } dlist_purge(admin_connections); node = dlist_get_first(pending_events); while (node != NULL) { next = dlist_next(node); event_free((struct event_info *)node->data); node = next; } dlist_purge(pending_events); #if defined(_AIX) if (pollset_fd >= 0) close(pollset_fd); pollset_fd = -1; #else if (epoll_fd >= 0) close(epoll_fd); epoll_fd = -1; #endif DbgLog(DL0, "%s: Socket server stopped", __func__); return TRUE; } #ifdef DEV static void dump_listener(struct listener_info *listener) { DbgLog(DL0, " socket: %d", listener->socket); DbgLog(DL0, " file_path: %s", listener->file_path); DbgLog(DL0, " ep_info.ref_count: %lu", listener->ep_info.ref_count); DbgLog(DL0, " num_clients: %lu", listener->num_clients); DbgLog(DL0, " max_num_clients: %lu", listener->max_num_clients); } static void dump_event_msg(event_msg_t *event, int indent) { DbgLog(DL0, "%*sevent version: %u", indent, "", event->version); DbgLog(DL0, "%*sevent type: %08x", indent, "", event->type); DbgLog(DL0, "%*sevent flags: %08x", indent, "", event->flags); DbgLog(DL0, "%*sevent token_type: %08x", indent, "", event->token_type); DbgLog(DL0, "%*sevent token_label: '%.32s'", indent, "", event->token_label); DbgLog(DL0, "%*sevent process_id: %lu", indent, "", event->process_id); DbgLog(DL0, "%*sevent payload_len: %u", indent, "", event->payload_len); } static void dump_event_reply(event_reply_t *reply, int indent) { DbgLog(DL0, "%*sreply version: %u", indent, "", reply->version); DbgLog(DL0, "%*sreply positive_replies: %u", indent, "", reply->positive_replies); DbgLog(DL0, "%*sreply negative_replies: %u", indent, "", reply->negative_replies); DbgLog(DL0, "%*sreply nothandled_replies: %u", indent, "", reply->nothandled_replies); } static void dump_event_info(struct event_info *event, int indent) { dump_event_msg(&event->event, indent); dump_event_reply(&event->reply, indent); DbgLog(DL0, "%*sproc_ref_count: %lu", indent, "", event->proc_ref_count); if (event->admin_ref != NULL) DbgLog(DL0, "%*sadmin_ref: %p", indent, "", event->admin_ref); else DbgLog(DL0, "%*sadmin_ref: None", indent, ""); } static void dump_proc_conn(struct proc_conn_info *proc_conn) { DL_NODE *node; unsigned long i; DbgLog(DL0, " socket: %d", proc_conn->client_info.socket); DbgLog(DL0, " state: %d", proc_conn->state); DbgLog(DL0, " ref-count: %lu", proc_conn->client_info.ep_info.ref_count); DbgLog(DL0, " xfer state: %d", proc_conn->client_info.xfer_state); DbgLog(DL0, " xfer size: %d", proc_conn->client_info.xfer_size); DbgLog(DL0, " xfer offset: %d", proc_conn->client_info.xfer_offset); DbgLog(DL0, " pending events:"); node = dlist_get_first(proc_conn->events); i = 1; while (node != NULL) { DbgLog(DL0, " event %lu (%p):", i, node->data); dump_event_info(node->data, 10); node = dlist_next(node); i++; } if (proc_conn->event != NULL) { DbgLog(DL0, " current event:"); dump_event_info(proc_conn->event, 8); DbgLog(DL0, " current reply:"); dump_event_reply(&proc_conn->reply, 8); } else { DbgLog(DL0, " current event: none"); } } static void dump_admin_conn(struct admin_conn_info *admin_conn) { DbgLog(DL0, " socket: %d", admin_conn->client_info.socket); DbgLog(DL0, " state: %d", admin_conn->state); DbgLog(DL0, " ref-count: %lu", admin_conn->client_info.ep_info.ref_count); DbgLog(DL0, " xfer state: %d", admin_conn->client_info.xfer_state); DbgLog(DL0, " xfer size: %d", admin_conn->client_info.xfer_size); DbgLog(DL0, " xfer offset: %d", admin_conn->client_info.xfer_offset); if (admin_conn->event != NULL) { DbgLog(DL0, " current event (%p):", admin_conn->event); dump_event_info(admin_conn->event, 8); } else { DbgLog(DL0, " current event: none"); } } #ifdef WITH_LIBUDEV void dump_udev_mon(struct udev_mon *udev_mon) { DbgLog(DL0, " socket: %d", udev_mon->socket); DbgLog(DL0, " udev: %p", udev_mon->udev); DbgLog(DL0, " mon: %p", udev_mon->mon); DbgLog(DL0, " ep_info.ref_count: %lu", udev_mon->ep_info.ref_count); if (udev_mon->delayed_event != NULL) { DbgLog(DL0, " delayed_event (%p):", udev_mon->delayed_event); dump_event_info(udev_mon->delayed_event, 6); } else { DbgLog(DL0, " delayed_event: node"); } } #endif void dump_socket_handler(void) { DL_NODE *node; unsigned long i; DbgLog(DL0, "%s: Dump of socket handler data:", __func__); #if defined(_AIX) DbgLog(DL0, " pollset_fd: %d", pollset_fd); #else DbgLog(DL0, " epoll_fd: %d", epoll_fd); #endif DbgLog(DL0, " proc_listener (%p): ", &proc_listener); dump_listener(&proc_listener); DbgLog(DL0, " proc_connections: "); node = dlist_get_first(proc_connections); i = 1; while (node != NULL) { DbgLog(DL0, " proc_connection %lu (%p): ", i, node->data); dump_proc_conn(node->data); i++; node = dlist_next(node); } DbgLog(DL0, " admin_listener (%p): ", &admin_listener); dump_listener(&admin_listener); DbgLog(DL0, " admin_connections: "); node = dlist_get_first(admin_connections); i = 1; while (node != NULL) { DbgLog(DL0, " admin_connection %lu (%p): ", i, node->data); dump_admin_conn(node->data); i++; node = dlist_next(node); } #ifdef WITH_LIBUDEV DbgLog(DL0, " udev_mon (%p): ", &udev_mon); dump_udev_mon(&udev_mon); #endif DbgLog(DL0, " pending events (%lu): ", pending_events_count); node = dlist_get_first(pending_events); i = 1; while (node != NULL) { DbgLog(DL0, " event %lu (%p): ", i, node->data); dump_event_info(node->data, 6); i++; node = dlist_next(node); } } #endif opencryptoki-opencryptoki-451d99c/usr/sbin/pkcsstats/000077500000000000000000000000001520105705100231075ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/usr/sbin/pkcsstats/pkcsstats.c000066400000000000000000000673701520105705100253070ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2021 * * 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 */ /* * pkcsstats - A tool to display mechanism usage statistics. * */ #include "platform.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(_AIX) #include const char *__progname = "pkcsstats"; #endif #include "platform.h" #include "statistics.h" #include "p11util.h" #define UNUSED(var) ((void)(var)) static void usage(char *progname) { printf("Usage: %s [OPTIONS]\n\n", progname); printf("Display mechanism usage statistics for openCryptoki.\n\n"); printf("OPTIONS:\n"); printf(" -U, --user USERID show the statistics from one user. (root user only)\n"); printf(" -S, --summary show the accumulated statistics from all users. (root user only)\n"); printf(" -A, --all show the statistic tables from all users. (root user only)\n"); printf(" -a, --all-mechs show all mechanisms, also those with all zero counters.\n"); printf(" -s, --slot SLOTID show the statistics from one slot only.\n"); printf(" -r, --reset set the own statistics to zero.\n"); printf(" -R, --reset-all reset the statistics from all users. (root user only)\n"); printf(" -d, --delete delete your own statistics.\n"); printf(" -D, --delete-all delete the statistics from all users. (root user only)\n"); printf(" -j, --json output the statistics in JSON format.\n"); printf(" -h, --help display help information.\n"); return; } static void make_shm_name(char *shm_name, size_t max_shm_len, int user_id) { int i; if (user_id == -1) snprintf(shm_name, max_shm_len - 1, "%s_stats", CONFIG_PATH); else snprintf(shm_name, max_shm_len - 1, "%s_stats_%d", CONFIG_PATH, user_id); for (i = 1; shm_name[i] != '\0'; i++) { if (shm_name[i] == '/') shm_name[i] = '.'; } if (shm_name[0] != '/') { memmove(&shm_name[1], &shm_name[0], strlen(shm_name) + 1); shm_name[0] = '/'; } } static int open_shm(uid_t user_id, const char *user_name, CK_ULONG num_slots, CK_BYTE **shm_data, CK_ULONG *shm_size) { char shm_name[PATH_MAX]; struct stat stat_buf; int shm_fd; make_shm_name(shm_name, sizeof(shm_name), user_id); shm_fd = shm_open(shm_name, O_RDWR, S_IRUSR | S_IWUSR); if (shm_fd == -1) { if (errno == ENOENT) warnx("No statistics are available for user '%s'", user_name); else warnx("Failed to open statistics for user '%s': shm_open('%s'): %s", user_name, shm_name, strerror(errno)); return 1; } if (fstat(shm_fd, &stat_buf)) { warnx("Failed to open statistics for user '%s': stat('%s'): %s", user_name, shm_name, strerror(errno)); close(shm_fd); return 1; } /* * If the shared memory segment does not belong to the user or does * not have correct permissions, do not use it. */ if (stat_buf.st_uid != user_id || (stat_buf.st_mode & ~S_IFMT) != (S_IRUSR | S_IWUSR)) { warnx("Failed to open statistics for user '%s': SHM '%s' has wrong mode/owner", user_name, shm_name); close(shm_fd); return 1; } *shm_size = num_slots * STAT_SLOT_SIZE; if ((CK_ULONG)stat_buf.st_size != *shm_size) { warnx("Failed to open statistics for user '%s': SHM '%s' has wrong size", user_name, shm_name); close(shm_fd); return 1; } *shm_data = (CK_BYTE *)mmap(NULL, *shm_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); close(shm_fd); if (*shm_data == MAP_FAILED) { warnx("Failed to open statistics for user '%s': mmap('%s'): %s", user_name, shm_name, strerror(errno)); return 1; } return 0; } static void close_shm(CK_BYTE *shm_data, CK_ULONG shm_size) { if (shm_data == NULL) return; munmap(shm_data, shm_size); } typedef int (*user_f)(int user_id, const char *user_name, void *private); static int for_all_users(user_f user_cb, void *cb_private) { #if defined(_AIX) return 0; #else char shm_prefix[PATH_MAX]; struct dirent *direntp; DIR *shmDir; struct passwd *pwd; int rc = 0, uid; char *endptr; make_shm_name(shm_prefix, sizeof(shm_prefix), -1); shmDir = opendir("/dev/shm"); if (shmDir == NULL) { warnx("Failed to open /dev/shm: %s", strerror(errno)); return 1; } while ((direntp = readdir(shmDir)) != NULL) { if(strstr(direntp->d_name, &shm_prefix[1]) != NULL) { errno = 0; uid = strtoul(&direntp->d_name[strlen(shm_prefix)], &endptr, 10); if ((errno == ERANGE && uid >= INT_MAX) || (errno != 0 && uid == 0) || *endptr != '\0') continue; if((pwd = getpwuid(uid)) == NULL) continue; rc = user_cb(uid, pwd->pw_name, cb_private); if (rc != 0) break; } } closedir(shmDir); return rc; #endif } typedef int (*slot_f)(CK_SLOT_ID slot_id, CK_BYTE *slot_data, CK_ULONG slot_size, void *private); static int for_all_slots(slot_f slot_cb, void *cb_private, CK_BYTE *shm_data, CK_ULONG shm_size, CK_ULONG num_slots, CK_SLOT_ID *slots, bool slot_id_specified, CK_SLOT_ID slot_id) { int rc = 0; CK_ULONG i; bool slot_found = false; for (i = 0; i < num_slots; i++) { if (slot_id_specified && slots[i] != slot_id) continue; slot_found = true; if ((i * STAT_SLOT_SIZE) + STAT_SLOT_SIZE > shm_size) break; rc = slot_cb(slots[i], &shm_data[i * STAT_SLOT_SIZE], STAT_SLOT_SIZE, cb_private); if (rc != 0) break; } if (slot_id_specified && !slot_found) { warnx("Slot %lu is not available", slot_id); return 1; } return rc; } static bool all_conters_zero(CK_BYTE *mech_data, CK_ULONG mech_size) { counter_t *counter = (counter_t *)mech_data; int i; for (i = 0; i < NUM_SUPPORTED_STRENGTHS + 1 && i * sizeof(counter_t) < mech_size; i++) { if (counter[i] != 0) return false; } return true; } typedef int (*mech_f)(CK_MECHANISM_TYPE mech, const char *mech_name, CK_BYTE *mech_data, CK_ULONG mech_size, CK_ULONG ofs, void *private); static int for_each_mech(mech_f mech_cb, void *cb_private, CK_BYTE *slot_data, CK_ULONG slot_size, bool all_mechs) { CK_ULONG i, ofs; int rc = -1; for (i = 0, ofs = 0; i < MECHTABLE_NUM_ELEMS; i++, ofs += STAT_MECH_SIZE) { if (ofs + STAT_MECH_SIZE > slot_size) break; if (!all_mechs && all_conters_zero(&slot_data[ofs], STAT_MECH_SIZE)) continue; rc = mech_cb(mechtable_rows[i].numeric, mechtable_rows[i].string, &slot_data[ofs], STAT_MECH_SIZE, ofs, cb_private); if (rc != 0) break; } return rc; } static int delete_shm(uid_t user_id, const char *user_name) { char shm_name[PATH_MAX]; int rc; make_shm_name(shm_name, sizeof(shm_name), user_id); rc = shm_unlink(shm_name); if (rc != 0) { if (errno == ENOENT) warnx("No statistics are available for user '%s'", user_name); else warnx("Failed to delete statistics for user '%s': shm_unlink('%s'): %s", user_name, shm_name, strerror(errno)); return 1; } printf("Deleted statistics for user '%s'\n", user_name); return 0; } static int delete_all_cb(int user_id, const char *user_name, void *private) { UNUSED(private); return delete_shm(user_id, user_name); } static int reset_slot_cb(CK_SLOT_ID slot_id, CK_BYTE *slot_data, CK_ULONG slot_size, void *private) { UNUSED(slot_id); UNUSED(private); memset(slot_data, 0, slot_size); return 0; } static int reset_shm(uid_t user_id, const char *user_name, CK_ULONG num_slots, CK_SLOT_ID *slots, bool slot_id_specified, CK_SLOT_ID slot_id) { int rc = 0; CK_BYTE *shm_data = NULL; CK_ULONG shm_size = 0; rc = open_shm(user_id, user_name, num_slots, &shm_data, &shm_size); if (rc != 0) return rc; rc = for_all_slots(reset_slot_cb, NULL, shm_data, shm_size, num_slots, slots, slot_id_specified, slot_id); if (rc == 0) { if (slot_id_specified) printf("Resetted statistics for user '%s' and slot %lu\n", user_name, slot_id); else printf("Resetted statistics for user '%s'\n", user_name); } close_shm(shm_data, shm_size); return rc; } struct reset_data { CK_ULONG num_slots; CK_SLOT_ID *slots; bool slot_id_specified; CK_SLOT_ID slot_id; }; static int reset_all_cb(int user_id, const char *user_name, void *private) { struct reset_data *rd = (struct reset_data *)private; return reset_shm(user_id, user_name, rd->num_slots, rd->slots, rd->slot_id_specified, rd->slot_id); } static int get_slot_infos(CK_FUNCTION_LIST_PTR func_list, CK_SLOT_ID **slots, CK_ULONG *num_slots) { CK_RV rc; rc = func_list->C_GetSlotList(FALSE, NULL, num_slots); if (rc != CKR_OK) { warnx("Error getting number of slots: 0x%lX (%s)\n", rc, p11_get_ckr(rc)); return 1; } if (*num_slots == 0) { warnx("C_GetSlotList returned 0 slots. Check that your tokens" " are installed correctly.\n"); return 1; } *slots = (CK_SLOT_ID_PTR) malloc(*num_slots * sizeof(CK_SLOT_ID)); rc = func_list->C_GetSlotList(FALSE, *slots, num_slots); if (rc != CKR_OK) { warnx("Error getting slot list: 0x%lX (%s)\n", rc, p11_get_ckr(rc)); return rc; } return 0; } int get_token_infos(CK_FUNCTION_LIST_PTR func_list, CK_SLOT_ID slot, char *label, size_t label_len, char *model, size_t model_len) { CK_TOKEN_INFO info; CK_RV rc; int i; rc = func_list->C_GetTokenInfo(slot, &info); if (rc == CKR_TOKEN_NOT_PRESENT) return -1; if (rc != CKR_OK) { warnx("Error getting token infos for slot %lu: 0x%lX (%s)\n", slot, rc, p11_get_ckr(rc)); return 1; } for (i = sizeof(info.label) - 1; i >= 0 && info.label[i] == ' '; i--) info.label[i] = '\0'; for (i = sizeof(info.model) - 1; i >= 0 && info.model[i] == ' '; i--) info.model[i] = '\0'; if (label_len > sizeof(info.label)) label_len = sizeof(info.label); strncpy(label, (char*)info.label, label_len); label[label_len - 1] = '\0'; if (model_len > sizeof(info.model)) model_len = sizeof(info.model); strncpy(model, (char*)info.model, model_len); model[model_len - 1] = '\0'; return 0; } struct display_mech { bool json; bool first_mech; }; static int display_mech_cb(CK_MECHANISM_TYPE mech, const char *mech_name, CK_BYTE *mech_data, CK_ULONG mech_size, CK_ULONG ofs, void *private) { counter_t *counter = (counter_t *)mech_data; struct display_mech *dm = private; int i; UNUSED(mech); UNUSED(ofs); if (dm->json && dm->first_mech == false) printf(","); if (dm->json) printf("\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"mechanism\": \"%s\",\n", mech_name); else printf("%-30s |", mech_name); for (i = 0; i < NUM_SUPPORTED_STRENGTHS + 1 && i * sizeof(counter_t) < mech_size; i++) { if (dm->json) printf("\t\t\t\t\t\t\t\"strength-%lu\": %lu%s\n", i == 0 ? 0 : supportedstrengths[NUM_SUPPORTED_STRENGTHS - i], counter[i], i == NUM_SUPPORTED_STRENGTHS ? "" : ","); else printf(" %15lu", counter[i]); } if (dm->json) printf("\t\t\t\t\t\t}"); else printf("\n"); dm->first_mech = false; return 0; } struct display_data { CK_FUNCTION_LIST *func_list; CK_ULONG num_slots; CK_SLOT_ID *slots; bool slot_id_specified; CK_SLOT_ID slot_id; bool all_mechs; bool json; bool first_user; bool first_slot; }; static void print_horizontal_line(void) { int i; printf("-------------------------------+"); for (i = 0; i < NUM_SUPPORTED_STRENGTHS + 1; i++) printf("----------------"); printf("-\n"); } static void print_header(void) { int i; print_horizontal_line(); printf("mechanism | strength 0 "); for (i = 0; i < NUM_SUPPORTED_STRENGTHS; i++) printf("strength %-5lu ", supportedstrengths[NUM_SUPPORTED_STRENGTHS - 1 - i]); printf("\n"); printf(" | or no key\n"); print_horizontal_line(); } static void print_footer(void) { print_horizontal_line(); printf("\n"); } static int display_slot_stats(CK_FUNCTION_LIST *func_list, CK_SLOT_ID slot, CK_BYTE *slot_data, CK_ULONG slot_size, bool all_mechs, bool json, bool *first) { char label[33], model[33]; struct display_mech dm; int rc; rc = get_token_infos(func_list, slot, label, sizeof(label), model, sizeof(model)); if (rc > 0) return rc; if (json && *first == false) printf(","); if (json) printf("\n\t\t\t\t{\n\t\t\t\t\t\"slot\": %lu,\n", slot); if (rc == 0) { if (json) { printf("\t\t\t\t\t\"token-present\": true,\n"); printf("\t\t\t\t\t\"label\": \"%s\",\n", label); printf("\t\t\t\t\t\"model\": \"%s\",\n", model); } else { printf("Slot: %lu (label: '%s' model: '%s')\n\n", slot, label, model); } } else { if (json) printf("\t\t\t\t\t\"token-present\": false,\n"); else printf("Slot: %lu (no token present)\n\n", slot); } if (json) printf("\t\t\t\t\t\"mechanisms\": ["); else print_header(); dm.json = json; dm.first_mech = true; rc = for_each_mech(display_mech_cb, &dm, slot_data, slot_size, all_mechs); if (rc < 0) { if (!json) printf("[no mechanisms were used] |\n"); } else if (rc != 0) { return rc; } if (json) printf("\n\t\t\t\t\t]\n\t\t\t\t}"); else print_footer(); *first = false; return 0; } static int display_slot_cb(CK_SLOT_ID slot_id, CK_BYTE *slot_data, CK_ULONG slot_size, void *private) { struct display_data *dd = private; return display_slot_stats(dd->func_list, slot_id, slot_data, slot_size, dd->all_mechs, dd->json, &dd->first_slot); } static int display_stats(int user_id, const char *user_name, struct display_data* dd) { int rc = 0; CK_BYTE *shm_data = NULL; CK_ULONG shm_size = 0; rc = open_shm(user_id, user_name, dd->num_slots, &shm_data, &shm_size); if (rc != 0) return rc; if (dd->json) { if (!dd->first_user) printf(",\n"); printf("\t\t{\n\t\t\t\"user\": \"%s\",\n\t\t\t\"slots\": [", user_name); } else { printf("User: %s\n\n", user_name); } dd->first_slot = true; rc = for_all_slots(display_slot_cb, dd, shm_data, shm_size, dd->num_slots, dd->slots, dd->slot_id_specified, dd->slot_id); if (dd->json) printf("\n\t\t\t]\n\t\t}"); dd->first_user = false; close_shm(shm_data, shm_size); return rc; } static int display_all_cb(int user_id, const char *user_name, void *private) { return display_stats(user_id, user_name, (struct display_data *)private); } struct summary_data { CK_ULONG num_slots; CK_SLOT_ID *slots; CK_BYTE *summary_data; CK_ULONG summary_size; CK_SLOT_ID slot_id; }; static int summary_mech_cb(CK_MECHANISM_TYPE mech, const char *mech_name, CK_BYTE *mech_data, CK_ULONG mech_size, CK_ULONG ofs, void *private) { struct summary_data *sd = private; counter_t *slot_counter = (counter_t *)mech_data; counter_t *sum_counter; int i; UNUSED(mech); UNUSED(mech_name); ofs += sd->slot_id * STAT_SLOT_SIZE; if (ofs + (NUM_SUPPORTED_STRENGTHS + 1) * sizeof(counter_t) > sd->summary_size) { warnx("Internal error: mechanism offset larger than summary size"); return 1; } sum_counter = (counter_t *)(&sd->summary_data[ofs]); for (i = 0; i < NUM_SUPPORTED_STRENGTHS + 1 && i * sizeof(counter_t) < mech_size; i++) sum_counter[i] += slot_counter[i]; return 0; } static int summary_slot_cb(CK_SLOT_ID slot_id, CK_BYTE *slot_data, CK_ULONG slot_size, void *private) { int rc; struct summary_data *sd = private; sd->slot_id = slot_id; rc = for_each_mech(summary_mech_cb, sd, slot_data, slot_size, true); return rc < 0 ? 0 : rc; } static int display_summary_cb(int user_id, const char *user_name, void *private) { struct summary_data *sd = private; int rc = 0; CK_BYTE *shm_data = NULL; CK_ULONG shm_size = 0; rc = open_shm(user_id, user_name, sd->num_slots, &shm_data, &shm_size); if (rc != 0) return rc; rc = for_all_slots(summary_slot_cb, sd, shm_data, shm_size, sd->num_slots, sd->slots, false, 0); close_shm(shm_data, shm_size); return rc; } static int display_summary(struct display_data* dd) { struct summary_data sd; int rc = 0; sd.num_slots = dd->num_slots; sd.slots = dd->slots; sd.summary_size = dd->num_slots * STAT_SLOT_SIZE; sd.summary_data = calloc(sd.summary_size, 1); if (sd.summary_data == NULL) { warnx("Failed to allocate the summary buffer"); return 1; } rc = for_all_users(display_summary_cb, &sd); if (rc != 0) goto done; if (dd->json) { if (!dd->first_user) printf(",\n"); printf("\t\t{\n\t\t\t\"user\": \"(all users)\",\n\t\t\t\"slots\": ["); } else { printf("Summary (all users):\n\n"); } dd->first_slot = true; rc = for_all_slots(display_slot_cb, dd, sd.summary_data, sd.summary_size, dd->num_slots, dd->slots, dd->slot_id_specified, dd->slot_id); if (dd->json) printf("\n\t\t\t]\n\t\t}"); done: free(sd.summary_data); return rc; } int init_ock(void **dll, CK_FUNCTION_LIST_PTR *func_list) { void (*sym_ptr)(CK_FUNCTION_LIST_PTR_PTR ppFunctionList); CK_RV rc; *dll = dlopen(OCK_API_LIBNAME, DYNLIB_LDFLAGS); if (*dll == NULL) { warnx("Error loading PKCS#11 library: dlopen: %s", dlerror()); return 1; } *(void **)(&sym_ptr) = dlsym(*dll, "C_GetFunctionList"); if (sym_ptr == NULL) { warnx("Error loading PKCS#11 library: dlsym(C_GetFunctionList): %s", dlerror()); #ifndef WITH_SANITIZER dlclose(*dll); #endif *dll = NULL; return 1; } sym_ptr(func_list); if (*func_list == NULL) { warnx("Error getting function list from PKCS11 library"); #ifndef WITH_SANITIZER dlclose(*dll); #endif *dll = NULL; return 1; } rc = (*func_list)->C_Initialize(NULL); if (rc != CKR_OK) { warnx("Error initializing the PKCS11 library: 0x%lX (%s)", rc, p11_get_ckr(rc)); #ifndef WITH_SANITIZER dlclose(*dll); #endif *dll = NULL; *func_list = NULL; return 1; } return 0; } static int print_json_start(void) { char timestamp[200]; struct utsname un; struct tm *tm; time_t t; time(&t); tm = gmtime(&t); /* ISO 8601 format: e.g. 2021-11-17T08:01:23Z (always UTC) */ strftime(timestamp, sizeof(timestamp), "%FT%TZ", tm); if (uname(&un) != 0) { warnx("Failed to obtain system information, uname: %s", strerror(errno)); return 1; } printf("{\n\t\"host\": {\n"); printf("\t\t\"nodename\": \"%s\",\n", un.nodename); printf("\t\t\"sysname\": \"%s\",\n", un.sysname); printf("\t\t\"release\": \"%s\",\n", un.release); printf("\t\t\"machine\": \"%s\",\n", un.machine); printf("\t\t\"date\": \"%s\"\n", timestamp); printf("\t},\n\t\"users\": [\n"); return 0; } int main(int argc, char **argv) { int opt = 0; struct passwd *pswd = NULL; int user_id = -1; char *user_name = NULL; bool summary = false, all_users = false, all_mechs = false; bool reset = false, reset_all = false; bool delete = false, delete_all = false; bool slot_id_specified = false; bool json = false, json_started = false; CK_SLOT_ID slot_id = 0; void *dll = NULL; CK_FUNCTION_LIST *func_list = NULL; CK_ULONG num_slots = 0; CK_SLOT_ID *slots = NULL; char *endptr; int rc = 0; struct display_data dd; struct reset_data rd; static const struct option long_opts[] = { {"user", required_argument, NULL, 'U'}, {"summary", no_argument, NULL, 'S'}, {"all", no_argument, NULL, 'A'}, {"all-mechs", no_argument, NULL, 'a'}, {"slot", required_argument, NULL, 's'}, {"reset", no_argument, NULL, 'r'}, {"reset-all", no_argument, NULL, 'R'}, {"delete", no_argument, NULL, 'd'}, {"delete-all", no_argument, NULL, 'D'}, {"json", no_argument, NULL, 'j'}, {"help", no_argument, NULL, 'h'}, {0, 0, 0, 0} }; while ((opt = getopt_long(argc, argv, "U:SAas:rRdDjh", long_opts, NULL)) != -1) { switch (opt) { case 'U': if ((pswd = getpwnam(optarg)) == NULL) { warnx("The username '%s' is not known on this system", optarg); return EXIT_FAILURE; } if(geteuid() != 0 && geteuid() != pswd->pw_uid) { warnx("You have no rights to display the statistics from other users"); return EXIT_FAILURE; } user_id = pswd->pw_uid; break; case 'S': #ifdef _AIX warnx("This option is unsupported on AIX; only showing statistics for current user."); #else if (geteuid() != 0) { warnx("You have no rights to display the statistics from all users"); return EXIT_FAILURE; } summary = true; #endif break; case 'A': #ifdef _AIX warnx("This option is unsupported on AIX; only using statistics for current user."); #else if (geteuid() != 0) { warnx("You have no rights to display the statistics from all users"); return EXIT_FAILURE; } all_users = true; #endif break; case 'a': all_mechs = true; break; case 's': errno = 0; slot_id = strtoul(optarg, &endptr, 10); if ((errno == ERANGE && slot_id == ULONG_MAX) || (errno != 0 && slot_id == 0)) { warnx("Slot parameter invalid: '%s'", optarg); exit(EXIT_FAILURE); } slot_id_specified = CK_TRUE; break; case 'r': reset = true; break; case 'R': #ifdef _AIX warnx("This option is unsupported on AIX; only showing statistics for current user."); #else if (geteuid() != 0) { warnx("You have no rights to reset the statistics from all users"); return EXIT_FAILURE; } reset_all = true; #endif break; case 'd': delete = true; break; case 'D': #ifdef _AIX warnx("This option is unsupported on AIX; only showing statistics for current user."); #else if (geteuid() != 0) { warnx("You have no rights to delete the statistics from all users"); return EXIT_FAILURE; } delete_all = true; #endif break; case 'j': json = true; break; case 'h': usage(basename(argv[0])); exit(EXIT_SUCCESS); default: exit(EXIT_FAILURE); } } if (optind < argc) { warnx("unrecognized option '%s'", argv[optind]); exit(EXIT_FAILURE); } if (user_id != -1 && all_users) { warnx("Options -u/--user and -A/--all can not be specified together"); exit(EXIT_FAILURE); } if (user_id == -1) { user_id = geteuid(); pswd = getpwuid(user_id); if (pswd == NULL) { warnx("Failed to get current user name"); exit(EXIT_FAILURE); } } user_name = strdup(pswd->pw_name); if (user_name == NULL) { warnx("Failed to get current user name"); exit(EXIT_FAILURE); } if (delete) { if (slot_id_specified) { warnx("Options -s/--slot and -d/--delete can not be specified together"); free(user_name); exit(EXIT_FAILURE); } rc = delete_shm(user_id, user_name); goto done; } if (delete_all) { if (slot_id_specified) { warnx("Options -s/--slot and -D/--delete-all can not be specified together"); free(user_name); exit(EXIT_FAILURE); } rc = for_all_users(delete_all_cb, NULL); goto done; } rc = init_ock(&dll, &func_list); if (rc != 0) goto done; rc = get_slot_infos(func_list, &slots, &num_slots); if (rc != 0) goto done; if (reset) { rc = reset_shm(user_id, user_name, num_slots, slots, slot_id_specified, slot_id); goto done; } if (reset_all) { rd.num_slots = num_slots; rd.slots = slots; rd.slot_id_specified = slot_id_specified; rd.slot_id = slot_id; rc = for_all_users(reset_all_cb, &rd); goto done; } if (json) { if (print_json_start() != 0) goto done; json_started = true; } dd.func_list = func_list; dd.num_slots = num_slots; dd.slots = slots; dd.slot_id_specified = slot_id_specified; dd.slot_id = slot_id; dd.all_mechs = all_mechs; dd.json = json; dd.first_user = true; if (all_users) { rc = for_all_users(display_all_cb, &dd); goto done; } else if (summary) { rc = display_summary(&dd); goto done; } else { rc = display_stats(user_id, user_name, &dd); goto done; } done: if (json && json_started) printf("\n\t]\n}\n"); if (slots != NULL) free(slots); if (dll != NULL) { func_list->C_Finalize(NULL); #ifndef WITH_SANITIZER dlclose(dll); #endif } free(user_name); return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } opencryptoki-opencryptoki-451d99c/usr/sbin/pkcsstats/pkcsstats.mk000066400000000000000000000013401520105705100254550ustar00rootroot00000000000000sbin_PROGRAMS += usr/sbin/pkcsstats/pkcsstats usr_sbin_pkcsstats_pkcsstats_LDFLAGS = -lcrypto -ldl -lrt usr_sbin_pkcsstats_pkcsstats_CFLAGS = \ -DOCK_TOOL \ -DSTDLL_NAME=\"pkcsstats\" \ -I${srcdir}/usr/include \ -I${srcdir}/usr/lib/common \ -I${srcdir}/usr/lib/api \ -I${top_builddir}/usr/lib/api usr_sbin_pkcsstats_pkcsstats_SOURCES = \ usr/sbin/pkcsstats/pkcsstats.c \ usr/lib/common/p11util.c \ usr/lib/api/supportedstrengths.c \ usr/lib/api/mechtable.c if AIX usr_sbin_pkcsstats_pkcsstats_SOURCES += usr/lib/common/aix/err.c \ usr/lib/common/aix/getopt_long.c usr_sbin_pkcsstats_pkcsstats_LDFLAGS += -Wl,-blibpath:$(libdir)/opencryptoki:$(libdir)/opencryptoki/stdll:/usr/lib:/usr/lib64 endif opencryptoki-opencryptoki-451d99c/usr/sbin/pkcstok_admin/000077500000000000000000000000001520105705100237165ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/usr/sbin/pkcstok_admin/pkcstok_admin.c000066400000000000000000000714141520105705100267170ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2024 * * This program is provided under the terms of the Common Public License, * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this * software constitutes recipient's acceptance of CPL-1.0 terms which can be * found in the file LICENSE file or at * https://opensource.org/licenses/cpl1.0.php */ /* * pkcstok_admin - A tool for administrating tokens, such as creating * directories, and changing the owner of a token. * */ #include "platform.h" #include #if defined(_AIX) #include #include const char *__progname = "pkcstok_admin"; #else #include #include #endif #include #include #include #include #include #include #include #include #include #include #include "slotmgr.h" #if defined(_AIX) #define SHM_PREFIX "/" #else #define SHM_PREFIX "/dev/shm/" #endif #define UNUSED(var) ((void)(var)) #define pr_verbose(...) do { \ if (verbose) \ warnx(__VA_ARGS__); \ } while (0) static bool verbose = false; static bool force = false; static void print_usage(const char *progname) { printf("\nUsage: %s COMMAND [OPTIONS]\n", progname); printf("\n COMMANDS:\n"); printf(" create Create a new token and its directories.\n"); printf(" chown Change the owner of the token.\n"); printf(" remove Remove a token and its directories.\n" " This also removes all token objects.\n" " Use with care!\n"); printf(" reset Reset a token to its initial state. This\n" " also resets all PINs and removes all token\n" " objects. Use with care!\n"); printf("\n OPTIONS:\n"); printf(" -t, --token TOKNAME The name of the token to operate on.\n" " This option is mandatory.\n"); printf(" -g, --group GROUP The name of the user group owning the token.\n" " This option is optional, the default is\n" " '%s'.\n", PKCS_GROUP); printf(" -f, --force Do not ask for confirmations. Use with care!\n"); printf(" -h, --help Print this help, then exit.\n"); printf(" -v, --version Print version information, then exit.\n"); printf(" -V, --verbose Print verbose messages.\n"); printf("\n"); } static void print_version(const char *progname) { printf("%s version %s\n", progname, PACKAGE_VERSION); } static bool pkcsslotd_running(void) { FILE *fp; char* endptr; long lpid; char fname[PATH_MAX]; char buf[PATH_MAX]; #if defined(_AIX) struct psinfo psinfo; #else char* first; #endif pr_verbose("Checking if pkcsslotd is running ..."); fp = fopen(PID_FILE_PATH, "r"); if (fp == NULL) { pr_verbose("Pid file '%s' not existent, pkcsslotd is not running", PID_FILE_PATH); return false; } if (fgets(buf, sizeof(buf), fp) == NULL) { pr_verbose("Cannot read pid file '%s': %s", PID_FILE_PATH, strerror(errno)); fclose(fp); return false; } fclose(fp); lpid = strtol(buf, &endptr, 10); if (*endptr != '\0' && *endptr != '\n') { pr_verbose("Failed to parse pid file '%s': %s", PID_FILE_PATH, buf); return false; } #if defined(_AIX) snprintf(fname, sizeof(fname), "/proc/%ld/psinfo", lpid); #else snprintf(fname, sizeof(fname), "/proc/%ld/cmdline", lpid); #endif fp = fopen(fname, "r"); if (fp == NULL) { pr_verbose("Stale pid file, pkcsslotd is not running"); return false; } #if defined(_AIX) if (fread(&psinfo, sizeof(psinfo), 1, fp) != 1) { #else if (fgets(buf, sizeof(buf), fp) == NULL) { #endif pr_verbose("Failed to read '%s'", fname); fclose(fp); return false; } fclose(fp); #if defined(_AIX) return (strstr(psinfo.pr_fname, "pkcsslotd") != NULL); #else first = strtok(buf, " "); return (first != NULL && strstr(first, "pkcsslotd") != NULL); #endif } static char prompt_user(const char *message, char* allowed_chars) { int len; size_t linelen = 0; char *line = NULL; char ch = '\0'; printf("%s", message); while (1) { len = getline(&line, &linelen, stdin); if (len == -1) break; if (strlen(line) == 2 && strpbrk(line, allowed_chars) != 0) { ch = line[0]; break; } warnx("Improper reply, try again"); } if (line != NULL) free(line); return ch; } static bool check_group(const char *group, struct group **grp_ret) { struct group grp_buf, *tok_grp, *pkcs11_grp = NULL; struct passwd *pwd; int i, k, err, found; long buf_size; char *buff = NULL; bool ret = true; if (group == NULL) group = PKCS_GROUP; pr_verbose("Checking group '%s'", group); errno = 0; tok_grp = getgrnam(group); err = (errno != 0 ? errno : ENOENT); if (tok_grp == NULL) { warnx("Group '%s' does not exist [errno=%s].", group, strerror(err)); return false; } if (grp_ret != NULL) *grp_ret = tok_grp; /* No further check if token group is 'pkcs11' */ if (strcmp(tok_grp->gr_name, PKCS_GROUP) == 0) return true; /* * Must use getgrnam_r() here, because getgrnam() used above returns a * pointer to a static area that would be reused/overwritten by * subsequent calls to getgrnam(). */ buf_size = sysconf(_SC_GETGR_R_SIZE_MAX); if (buf_size <= 0) { err = errno; warnx("sysconf(_SC_GETGR_R_SIZE_MAX) failed [errno=%s].", strerror(err)); return false; } retry: buff = calloc(1, buf_size); if (buff == NULL) { warnx("Failed to allocate a buffer of %ld bytes.", buf_size); return false; } errno = 0; if (getgrnam_r(PKCS_GROUP, &grp_buf, buff, buf_size, &pkcs11_grp) != 0) { err = (errno != 0 ? errno : ENOENT); if (err == ERANGE && buf_size < 64 * 1024) { free(buff); buf_size *= 2; goto retry; } warnx("Group '%s' does not exist [errno=%s].", PKCS_GROUP, strerror(err)); ret = false; goto done; } /* Check that all group members are also a member of the 'pkcs11' group */ for (i = 0; tok_grp->gr_mem[i] != NULL; i++) { pr_verbose("Checking user '%s'", tok_grp->gr_mem[i]); /* Check if user's primary group is the 'pkcs11' group */ errno = 0; pwd = getpwnam(tok_grp->gr_mem[i]); err = (errno != 0 ? errno : ENOENT); if (pwd == NULL) { warnx("User '%s' does not exist [errno=%s].\n", tok_grp->gr_mem[i], strerror(err)); ret = false; /* Continue to display all missing users */ continue; } if (pwd->pw_gid != pkcs11_grp->gr_gid) { /* Check the users secondary groups */ for (k = 0, found = 0; pkcs11_grp->gr_mem[k] != NULL; k++) { if (strcmp(tok_grp->gr_mem[i], pkcs11_grp->gr_mem[k]) == 0) { found = 1; break; } } if (!found) { warnx("User '%s' is member of the token group '%s', but is not a " "member of the '%s' group.", tok_grp->gr_mem[i], tok_grp->gr_name, PKCS_GROUP); ret = false; /* Continue to display all missing users */ continue; } } } done: free(buff); return ret; } static void print_config_example(const char *token, const char *group) { printf("Make sure that the slot definition in '%s'\n" "contains the token name '%s'", OCK_CONFIG, token); if (group != NULL) printf(" and the user group '%s'", group); printf(".\n"); printf("Example:\n"); printf(" slot \n"); printf(" {\n"); printf(" ...\n"); printf(" tokname = %s\n", token); if (group != NULL) printf(" usergroup = %s\n", group); printf(" }\n\n"); } static bool check_file_exists(const char *fname, bool directory) { struct stat sb; if (stat(fname, &sb) != 0) return false; if (directory && S_ISDIR(sb.st_mode)) return true; if (!directory && S_ISREG(sb.st_mode)) return true; return false; } static int set_file_permissions(const char *fname, const struct group *group, bool recursive) { struct stat sb; struct passwd *pwd; int err, i, rc, mode; bool found = false; uid_t uid = (uid_t)-1; DIR *dir; struct dirent *entry; char ent[PATH_MAX]; pr_verbose("Setting permissions for '%s' with group '%s'", fname, group->gr_name); /* CWE-59 fix: Use lstat to detect symlinks */ if (lstat(fname, &sb) != 0) { warnx("'%s' does not exist.", fname); return -1; } /* Only process regular files and directories (CWE-59 fix) */ if (!S_ISREG(sb.st_mode) && !S_ISDIR(sb.st_mode)) { warnx("Skipping '%s': not a regular file or directory.", fname); return 0; } if (sb.st_uid != 0) { /* owner is not root */ pwd = getpwuid(sb.st_uid); /* If pwd is NULL, found will stay false and root is set as owner */ for (i = 0; pwd != NULL && group->gr_mem[i] != NULL; i++) { if (strcmp(group->gr_mem[i], pwd->pw_name) == 0) { found = true; break; } } if (!found) uid = 0; /* set root as owner if prev owner is not in token group */ } /* Set absolute permissions or rw-rw---- / rwxrwx--- */ if (S_ISDIR(sb.st_mode)) mode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP; else mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; if (chmod(fname, mode) != 0) { err = errno; warnx("Failed to set permissions on '%s': %s", fname, strerror(err)); return -1; } /* Set owner to uid and token group */ if (chown(fname, uid, group->gr_gid) != 0) { err = errno; warnx("Failed to change the owner on '%s': %s", fname, strerror(err)); return -1; } if (recursive && S_ISDIR(sb.st_mode)) { dir = opendir(fname); if (dir == NULL) { err = errno; warnx("Failed to open directory '%s': %s", fname, strerror(err)); return -1; } /* set permissions recursively, skip the "." and ".." entries */ rc = 0; while ((entry = readdir(dir)) != NULL) { if (strncmp(entry->d_name, ".", 1) == 0) continue; snprintf(ent, PATH_MAX, "%s/%s", fname, entry->d_name); rc = set_file_permissions(ent, group, recursive); if (rc != 0) break; } closedir(dir); if (rc != 0) return rc; } return 0; } static int remove_recursive(const char *fname, bool only_content) { struct stat sb; DIR *dir; struct dirent *entry; int rc, err; char ent[PATH_MAX]; pr_verbose("Removing %s'%s'", only_content ? "the content of " : "", fname); if (stat(fname, &sb) != 0) { err = errno; if (err == ENOENT) { /* Removing a non-existing file is a no-op */ pr_verbose("'%s' does not exists.", fname); return 0; } warnx("Failed to stat '%s': %s.", fname, strerror(err)); return -1; } if (S_ISDIR(sb.st_mode)) { dir = opendir(fname); if (dir == NULL) { err = errno; warnx("Failed to open directory '%s': %s", fname, strerror(err)); return -1; } /* remove directory recursively, skip the "." and ".." entries */ rc = 0; while ((entry = readdir(dir)) != NULL) { if (strncmp(entry->d_name, ".", 1) == 0) continue; snprintf(ent, PATH_MAX, "%s/%s", fname, entry->d_name); rc = remove_recursive(ent, false); if (rc != 0) break; } closedir(dir); if (rc != 0) return rc; } if (!only_content) { rc = remove(fname); if (rc != 0) { err = errno; warnx("Failed to remove '%s': %s", fname, strerror(err)); return -1; } } return 0; } static int create_directory(const char *dirname, const struct group *group) { pr_verbose("Creating directory '%s'", dirname); if (mkdir(dirname, S_IRWXU | S_IRWXG) != 0) { warnx("Failed to create directory '%s': %s", dirname, strerror(errno)); return -1; } return set_file_permissions(dirname, group, false); } static int get_token_dir(const char *token, char *fpath, size_t fpath_size) { int len; len = snprintf(fpath, fpath_size, "%s/%s", CONFIG_PATH, token); if (len < 0 || (size_t)len >= fpath_size) { pr_verbose("Token directory name too long"); return -1; } pr_verbose("Token directory: %s", fpath); return 0; } static int get_token_object_dir(const char *token, char *fpath, size_t fpath_size) { int len; len = snprintf(fpath, fpath_size, "%s/%s/TOK_OBJ", CONFIG_PATH, token); if (len < 0 || (size_t)len >= fpath_size) { pr_verbose("Token object directory name too long"); return -1; } pr_verbose("Token object directory: %s", fpath); return 0; } static int get_token_lock_dir(const char *token, char *fpath, size_t fpath_size) { int len; len = snprintf(fpath, fpath_size, "%s/%s", LOCKDIR_PATH, token); if (len < 0 || (size_t)len >= fpath_size) { pr_verbose("Token lock directory name too long"); return -1; } pr_verbose("Lock directory: %s", fpath); return 0; } static int get_token_shm_name(const char *token, char *fpath, size_t fpath_size) { char tok_dir[PATH_MAX], *shmname = fpath; size_t len; bool verbose_save = verbose; int i, rc; verbose = false; rc = get_token_dir(token, tok_dir, sizeof(tok_dir)); verbose = verbose_save; if (rc != 0) { pr_verbose("Token directory name too long"); return rc; } len = strlen(tok_dir); /* Need a starting '/' */ if (tok_dir[0] != '/') len++; if (fpath_size < strlen(SHM_PREFIX) + len + 1) { pr_verbose("Token SHM name too long"); return -1; } i = 0; strcpy(shmname, SHM_PREFIX); shmname += strlen(SHM_PREFIX); if (tok_dir[0] == '/') i++; for (; tok_dir[i]; i++, shmname++) { if (tok_dir[i] == '/') *shmname = '.'; else *shmname = tok_dir[i]; } *shmname = '\0'; pr_verbose("Token SHM name: %s", fpath); return 0; } static int perform_create(const char *token, const char *group, const struct group *grp) { char tok_dir[PATH_MAX]; char tok_obj_dir[PATH_MAX]; char tok_lock_dir[PATH_MAX]; #if !defined(_AIX) char tok_shm[PATH_MAX]; #endif char *msg = NULL; char ch; /* get the token directories and files */ if (get_token_dir(token, tok_dir, sizeof(tok_dir)) != 0 || get_token_object_dir(token, tok_obj_dir, sizeof(tok_obj_dir)) != 0 || get_token_lock_dir(token, tok_lock_dir, sizeof(tok_lock_dir)) != 0 || #if defined(_AIX) FALSE) { #else get_token_shm_name(token, tok_shm, sizeof(tok_shm)) != 0) { #endif warnx("Failed to build name of token directory. Possibly name is too long."); return EXIT_FAILURE; } /* Check if the token or any artifacts of it exist already */ if (check_file_exists(tok_dir, true)) { warnx("The token directory for token '%s' exists already.", token); return EXIT_FAILURE; } if (check_file_exists(tok_lock_dir, true)) { warnx("The lock directory for token '%s' exists already.", token); return EXIT_FAILURE; } /* AIX does not expose POSIX shared memory segments under /dev/shm/ */ #if !defined(_AIX) if (check_file_exists(tok_shm, false)) { warnx("The shared memory segment for token '%s' exists already.", token); return EXIT_FAILURE; } #endif if (!force) { if (asprintf(&msg, "Create the token directories for token '%s' with " "owner group '%s' [y/n]? ", token, grp->gr_name) < 0 || msg == NULL) { warnx("Failed to allocate memory for a message"); return EXIT_FAILURE; } ch = prompt_user(msg, "yn"); free(msg); if (ch != 'y') return EXIT_FAILURE; } /* Create the token directories */ if (create_directory(tok_dir, grp) != 0 || create_directory(tok_obj_dir, grp) != 0 || create_directory(tok_lock_dir, grp) != 0) { /* Try to remove already created directories, but ignore errors */ rmdir(tok_obj_dir); rmdir(tok_dir); rmdir(tok_lock_dir); return EXIT_FAILURE; } printf("Token directories created successfully for token '%s'.\n\n", token); print_config_example(token, group); return EXIT_SUCCESS; } static int perform_chown(const char *token, const char *group, const struct group *grp) { char tok_dir[PATH_MAX]; char tok_obj_dir[PATH_MAX]; char tok_lock_dir[PATH_MAX]; char tok_shm[PATH_MAX]; char *msg = NULL; char ch; /* get the token directories and files */ if (get_token_dir(token, tok_dir, sizeof(tok_dir)) != 0 || get_token_object_dir(token, tok_obj_dir, sizeof(tok_obj_dir)) != 0 || get_token_lock_dir(token, tok_lock_dir, sizeof(tok_lock_dir)) != 0 || get_token_shm_name(token, tok_shm, sizeof(tok_shm)) != 0) { warnx("Failed to build name of token directory. Possibly name is too long."); return EXIT_FAILURE; } /* Check if the token or any artifacts of it exist already */ if (!check_file_exists(tok_dir, true)) { warnx("The token directory for token '%s' does not exist.", token); return EXIT_FAILURE; } if (!check_file_exists(tok_lock_dir, true)) { warnx("The lock directory for token '%s' does not exist.", token); return EXIT_FAILURE; } if (!force) { if (asprintf(&msg, "Change the owner of token '%s' to group '%s' " "[y/n]? ", token, grp->gr_name) < 0 || msg == NULL) { warnx("Failed to allocate memory for a message"); return EXIT_FAILURE; } ch = prompt_user(msg, "yn"); free(msg); if (ch != 'y') return EXIT_FAILURE; } if (set_file_permissions(tok_dir, grp, true) != 0 || set_file_permissions(tok_lock_dir, grp, true) != 0) { return EXIT_FAILURE; } #if defined(_AIX) /* * AIX does not expose POSIX shared memory segments under /dev/shm/, so * its owners can not be changed per file system. Remove (unlink) the * shared memory segment instead, the next application using the token will * re-create it with the desired owners and permissions. */ if (shm_unlink(tok_shm) != 0 && errno != ENOENT) { warnx("Failed to unlink the shared memory segment '%s': %s", tok_shm, strerror(errno)); return EXIT_FAILURE; } #else if (check_file_exists(tok_shm, false) && set_file_permissions(tok_shm, grp, false) != 0) { return EXIT_FAILURE; } #endif printf("Successfully changed the owner of the directories of token '%s'.\n\n", token); print_config_example(token, group); return EXIT_SUCCESS; } static int perform_remove(const char *token, const char *group, const struct group *grp) { char tok_dir[PATH_MAX]; char tok_lock_dir[PATH_MAX]; char tok_shm[PATH_MAX]; char *msg = NULL; char ch; UNUSED(group); UNUSED(grp); /* get the token directories and files */ if (get_token_dir(token, tok_dir, sizeof(tok_dir)) != 0 || get_token_lock_dir(token, tok_lock_dir, sizeof(tok_lock_dir)) != 0 || get_token_shm_name(token, tok_shm, sizeof(tok_shm)) != 0) { warnx("Failed to build name of token directory. Possibly name is too long."); return EXIT_FAILURE; } /* Check if the token or any artifacts of it exist already */ if (!check_file_exists(tok_dir, true)) { warnx("The token directory for token '%s' does not exist.", token); return EXIT_FAILURE; } if (!check_file_exists(tok_lock_dir, true)) { warnx("The lock directory for token '%s' does not exist.", token); return EXIT_FAILURE; } if (!force) { if (asprintf(&msg, "Remove the token directories of token '%s' and all " "its objects [y/n]? ", token) < 0 || msg == NULL) { warnx("Failed to allocate memory for a message"); return EXIT_FAILURE; } ch = prompt_user(msg, "yn"); free(msg); if (ch != 'y') return EXIT_FAILURE; } if (remove_recursive(tok_dir, false) != 0 || remove_recursive(tok_lock_dir, false) != 0) return EXIT_FAILURE; #if defined(_AIX) /* * AIX does not expose POSIX shared memory segments under /dev/shm/, so * it can not be removed per file system. Remove it using the shm_unlink() * call instead. */ if (shm_unlink(tok_shm) != 0 && errno != ENOENT) { warnx("Failed to unlink the shared memory segment '%s': %s", tok_shm, strerror(errno)); return EXIT_FAILURE; } #else if (remove_recursive(tok_shm, false) != 0) return EXIT_FAILURE; #endif printf("Successfully removed the directories of token '%s'.\n", token); printf("Make sure to also remove the corresponding slot definition in " "'%s'\n", OCK_CONFIG); return EXIT_SUCCESS; } static int perform_reset(const char *token, const char *group, const struct group *grp) { char tok_dir[PATH_MAX]; char tok_obj_dir[PATH_MAX]; char tok_shm[PATH_MAX]; char tok_MK_SO[PATH_MAX]; char tok_MK_USER[PATH_MAX]; char tok_NVTOK_DAT[PATH_MAX]; char *msg = NULL; char ch; int len; UNUSED(group); UNUSED(grp); /* get the token directories and files */ if (get_token_dir(token, tok_dir, sizeof(tok_dir)) != 0 || get_token_object_dir(token, tok_obj_dir, sizeof(tok_obj_dir)) != 0 || get_token_shm_name(token, tok_shm, sizeof(tok_shm)) != 0) { warnx("Failed to build name of token directory. Possibly name is too long."); return EXIT_FAILURE; } len = snprintf(tok_MK_SO, sizeof(tok_MK_SO), "%s/MK_SO", tok_dir); if (len < 0 || (size_t)len >= sizeof(tok_MK_SO)) { warnx("Failed to build name of token MK_SO. Possibly name is too long."); return EXIT_FAILURE; } len = snprintf(tok_MK_USER, sizeof(tok_MK_USER), "%s/MK_USER", tok_dir); if (len < 0 || (size_t)len >= sizeof(tok_MK_USER)) { warnx("Failed to build name of token MK_USER. Possibly name is too long."); return EXIT_FAILURE; } len = snprintf(tok_NVTOK_DAT, sizeof(tok_NVTOK_DAT), "%s/NVTOK.DAT", tok_dir); if (len < 0 || (size_t)len >= sizeof(tok_NVTOK_DAT)) { warnx("Failed to build name of token NVTOK.DAT. Possibly name is too long."); return EXIT_FAILURE; } /* Check if the token or any artifacts of it exist already */ if (!check_file_exists(tok_dir, true)) { warnx("The token directory for token '%s' does not exist.", token); return EXIT_FAILURE; } if (!force) { if (asprintf(&msg, "Reset token '%s' and its PINs and remove all its " "objects [y/n]? ", token) < 0 || msg == NULL) { warnx("Failed to allocate memory for a message"); return EXIT_FAILURE; } ch = prompt_user(msg, "yn"); free(msg); if (ch != 'y') return EXIT_FAILURE; } if (remove_recursive(tok_obj_dir, true) != 0 || remove_recursive(tok_MK_SO, false) != 0 || remove_recursive(tok_MK_USER, false) != 0 || remove_recursive(tok_NVTOK_DAT, false) != 0) return EXIT_FAILURE; #if defined(_AIX) /* * AIX does not expose POSIX shared memory segments under /dev/shm/, so * it can not be removed per file system. Remove it using the shm_unlink() * call instead. */ if (shm_unlink(tok_shm) != 0 && errno != ENOENT) { warnx("Failed to unlink the shared memory segment '%s': %s", tok_shm, strerror(errno)); return EXIT_FAILURE; } #else if (remove_recursive(tok_shm, false) != 0) return EXIT_FAILURE; #endif printf("Successfully resetted token '%s'.\n\n", token); printf("You must now initialize the token freshly using 'pkcsconf -I, set\n" "the SO pin using 'pkcsconf -P' and then initialize the USER pin\n" "using 'pkcsconf -u'.\n"); return EXIT_SUCCESS; } int main(int argc, char **argv) { int rc, opt = 0; const char *command = NULL; const char *token = NULL, *group = NULL; struct group *tok_grp = NULL; static const struct option long_opts[] = { {"token", required_argument, NULL, 't'}, {"group", required_argument, NULL, 'g'}, {"force", no_argument, NULL, 'f'}, {"help", no_argument, NULL, 'h'}, {"version", no_argument, NULL, 'v'}, {"verbose", no_argument, NULL, 'V'}, {0, 0, 0, 0} }; /* Get command (if any) */ if (argc >= 2 && strncmp(argv[1], "-", 1) != 0) { command = argv[1]; argc--; argv = &argv[1]; } while ((opt = getopt_long(argc, argv, ":t:g:hvV", long_opts, NULL)) != -1) { switch (opt) { case 't': token = optarg; break; case 'g': group = optarg; break; case 'V': verbose = true; break; case 'f': force = true; break; case 'h': print_usage(argv[0]); exit(EXIT_SUCCESS); case 'v': print_version(argv[0]); exit(EXIT_SUCCESS); case ':': warnx("Option '%s' requires an argument", argv[optind - 1]); exit(EXIT_FAILURE); case '?': /* An invalid option has been specified */ if (optopt) warnx("Invalid option '-%c'", optopt); else warnx("Invalid option '%s'", argv[optind - 1]); exit(EXIT_FAILURE); default: print_usage(argv[0]); exit(EXIT_FAILURE); } } if (command == NULL) { warnx("A command is required. Use '-h'/'--help' to see the list of " "supported commands"); rc = EXIT_FAILURE; goto out; } if (token == NULL) { warnx("Option '-t/--token' is required but not specified."); rc = EXIT_FAILURE; goto out; } if (strcmp(token, "HSM_MK_CHANGE") == 0) { warnx("The token name 'HSM_MK_CHANGE' is reserved and can not be used."); rc = EXIT_FAILURE; goto out; } /* Ensure we are running as root */ if (geteuid() != 0) { warnx("This utility can only be used as root"); rc = EXIT_FAILURE; goto out; } /* Check if pkcsslotd is running */ if (pkcsslotd_running()) { warnx("The pkcsslotd must be stopped before running this utility."); rc = EXIT_FAILURE; goto out; } pr_verbose("Command: %s", command); pr_verbose("Token: %s", token); pr_verbose("Group: %s", group != NULL ? group : "[omitted]"); if (!check_group(group, &tok_grp)) { rc = EXIT_FAILURE; goto out; } if (strcasecmp(command, "create") == 0) { rc = perform_create(token, group, tok_grp); } else if (strcasecmp(command, "chown") == 0) { rc = perform_chown(token, group, tok_grp); } else if (strcasecmp(command, "remove") == 0) { rc = perform_remove(token, group, tok_grp); } else if (strcasecmp(command, "reset") == 0) { rc = perform_reset(token, group, tok_grp); } else { warnx("Invalid command '%s'", command); rc = EXIT_FAILURE; goto out; } out: pr_verbose("Finished with rc=%d", rc); return rc; } opencryptoki-opencryptoki-451d99c/usr/sbin/pkcstok_admin/pkcstok_admin.mk000066400000000000000000000007761520105705100271070ustar00rootroot00000000000000sbin_PROGRAMS += usr/sbin/pkcstok_admin/pkcstok_admin usr_sbin_pkcstok_admin_pkcstok_admin_LDFLAGS = -lrt usr_sbin_pkcstok_admin_pkcstok_admin_CFLAGS = \ -DSTDLL_NAME=\"pkcstok_admin\" \ -I${srcdir}/usr/include \ -I${srcdir}/usr/lib/common \ -I${srcdir}/usr/sbin/pkcstok_admin usr_sbin_pkcstok_admin_pkcstok_admin_SOURCES = \ usr/sbin/pkcstok_admin/pkcstok_admin.c if AIX usr_sbin_pkcstok_admin_pkcstok_admin_SOURCES += \ usr/lib/common/aix/err.c \ usr/lib/common/aix/getopt_long.c endif opencryptoki-opencryptoki-451d99c/usr/sbin/pkcstok_migrate/000077500000000000000000000000001520105705100242565ustar00rootroot00000000000000opencryptoki-opencryptoki-451d99c/usr/sbin/pkcstok_migrate/pkcstok_migrate.c000066400000000000000000002460761520105705100276270ustar00rootroot00000000000000/* * COPYRIGHT (c) International Business Machines Corp. 2020 * * This program is provided under the terms of the Common Public License, * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this * software constitutes recipient's acceptance of CPL-1.0 terms which can be * found in the file LICENSE file or at * https://opensource.org/licenses/cpl1.0.php */ /* * pkcstok_migrate - A tool for migrating ICA, CCA, Soft, and EP11 token * repositories to 3.12 format. * */ #include #include #include #include #if defined(_AIX) #include #include const char *__progname = "pkcstok_migrate"; #else #include #include #endif #include #include #include #include #include #include #include #include #include #include #include #include "cfgparser.h" #include "configuration.h" #include "sw_crypt.h" #include "defs.h" #include "host_defs.h" #include "local_types.h" #include "h_extern.h" #include "slotmgr.h" // for ock_snprintf #include "platform.h" #define OCK_TOOL #include "pkcs_utils.h" #include "pin_prompt.h" #define TOKVERSION_00 0x00000000 #define TOKVERSION_312 0x0003000C #define TOKVERSION_312_STRING "3.12" #define INVALID_TOKEN "unknown/unsupported" #define HEADER_LEN 64 #define FOOTER_LEN 16 #define PKCSTOK_MIGRATE_MAX_PATH_LEN (PATH_MAX - 200) pkcs_trace_level_t trace_level = TRACE_LEVEL_NONE; static FILE *open_datastore_file(char *buf, size_t buflen, const char *datastore, const char *file, const char *mode) { FILE *res; if (ock_snprintf(buf, buflen, "%s/%s", datastore, file) != 0) { TRACE_ERROR("Path overflow for datastore file %s\n", file); return NULL; } /* CWE-59 fix: Use fopen_nofollow to prevent symlink attacks */ res = fopen_nofollow(buf, mode); if (!res) { if (errno == ELOOP) TRACE_ERROR("Refusing to follow symlink: %s\n", buf); else TRACE_ERROR("fopen(%s) failed, errno=%s\n", buf, strerror(errno)); } return res; } static FILE *open_tokenobject(char *buf, size_t buflen, const char *datastore, const char *tokenobj, const char *file, const char *mode) { FILE *res; if (ock_snprintf(buf, buflen, "%s/%s/%s", datastore, tokenobj, file) != 0) { TRACE_ERROR("Path overflow for token object file %s for token %s\n", file, tokenobj); return NULL; } /* CWE-59 fix: Use fopen_nofollow to prevent symlink attacks */ res = fopen_nofollow(buf, mode); if (!res) { if (errno == ELOOP) TRACE_ERROR("Refusing to follow symlink: %s\n", buf); else TRACE_ERROR("fopen(%s) failed, errno=%s\n", buf, strerror(errno)); } return res; } struct findstdll { char *stdll; size_t len; int slotnum; int activeslot; int error; }; struct parseupdate { FILE *f; int slotnum; int activeslot; int tokvers_added; int at_newline; }; /** * Make a 3.12 format OBJECT_PUB: * * struct OBJECT_PUB { * //-------------- <--+ * u32 tokversion; | 16-byte header * u8 private_flag; | * u8 reserved[7]; | * u32 object_len; | * //-------------- <--+ * u8 object[object_len]; | body * //-------------- <--+ * }; */ static CK_RV make_OBJECT_PUB_312(char **obj_new, unsigned int *obj_new_len, unsigned char *clear, unsigned int clear_len) { struct { uint32_t tokversion; uint8_t private_flag; uint8_t reserved[7]; uint32_t object_len; } header; uint32_t total_len; char *object; CK_RV ret; *obj_new = NULL; *obj_new_len = 0; /* Check parms */ if (!clear || clear_len == 0) { TRACE_ERROR("Error in parms.\n"); ret = CKR_ARGUMENTS_BAD; goto done; } /* Allocate memory for new OBJECT_PUB */ total_len = sizeof(header) + clear_len; object = malloc(total_len); if (object == NULL) { TRACE_ERROR("cannot malloc %d bytes.\n", total_len); ret = CKR_HOST_MEMORY; goto done; } /* Setup object */ memset(&header, 0, sizeof(header)); header.tokversion = htobe32(0x0003000C); header.private_flag = 0x00; header.object_len = htobe32(clear_len); memcpy(object, &header, sizeof(header)); memcpy(object + sizeof(header), clear, clear_len); *obj_new = object; *obj_new_len = total_len; ret = CKR_OK; done: return ret; } /** * This function migrates the public obj to the current format. */ static CK_RV migrate_public_token_object(const char *data_store, const char *name, unsigned char *data, unsigned long len, const char *token_group) { const char *tokobj = "TOK_OBJ"; char fname[PATH_MAX]; char *obj_new = NULL; unsigned int obj_new_len; FILE *fp = NULL; CK_RV ret = 0; /* Create new public object */ ret = make_OBJECT_PUB_312(&obj_new, &obj_new_len, data, len); if (ret != CKR_OK) { TRACE_ERROR("Cannot create an OBJECT_PUB_312, ret=%08lX.\n", ret); goto done; } /* Setup file name for new object */ fp = open_tokenobject(fname, sizeof(fname), data_store, tokobj, name, "w"); if (!fp) { ret = CKR_FUNCTION_FAILED; goto done; } ret = set_perm(fileno(fp), token_group); if (ret != CKR_OK) goto done; /* Save new object */ if (fwrite(obj_new, obj_new_len, 1, fp) != 1) { TRACE_ERROR("fwrite(%s) failed, errno=%s\n", fname, strerror(errno)); ret = CKR_FUNCTION_FAILED; goto done; } ret = CKR_OK; done: free(obj_new); if (fp) fclose(fp); return ret; } /** * Make a 3.12 format OBJECT_PRIV: * * struct OBJECT_PRIV { * u32 total_len; * --- auth ------- <--+ * u32 tokversion | 64-byte header * u8 private_flag | * u8 reserved[3] | * u8 key_wrapped[40] | * u8 iv[12] | * u32 object_len | * --- auth+enc --- <--+ * u8 object[object_len] | body * ---------------- <--+ * u8 tag[16] | 16-byte footer * ---------------- <--+ * } */ static CK_RV make_OBJECT_PRIV_312(unsigned char **obj_new, unsigned int *obj_new_len, const char *name, unsigned char *clear, unsigned int clear_len, const CK_BYTE *masterkey) { struct { uint32_t tokversion; uint8_t private_flag; uint8_t reserved[3]; uint8_t key_wrapped[40]; uint8_t iv[12]; uint32_t object_len; } header; unsigned char *object = NULL; CK_BYTE obj_key[32]; uint32_t total_len; CK_RV ret; *obj_new = NULL; *obj_new_len = 0; /* Check parms */ if (!name || !clear || clear_len == 0 || !masterkey) { TRACE_ERROR("Error in parms.\n"); ret = CKR_ARGUMENTS_BAD; goto done; } /* An obj name has by definition 8 chars */ if (strlen(name) != 8) { TRACE_ERROR("obj name %s does not have 8 chars, OBJ.IDX probably corrupted.\n", name); ret = CKR_ARGUMENTS_BAD; goto done; } /* Allocate memory for new OBJECT_PRIV */ total_len = sizeof(header) + clear_len + FOOTER_LEN; object = malloc(total_len); if (object == NULL) { TRACE_ERROR("cannot malloc %d bytes.\n", total_len); ret = CKR_HOST_MEMORY; goto done; } /* Create new object key */ ret = local_rng(obj_key, 32); if (ret != CKR_OK) { TRACE_ERROR("local_rng failed with ret=%08lX.\n", ret); goto done; } /* Setup header */ memset(&header, 0, sizeof(header)); header.tokversion = htobe32(0x0003000C); header.private_flag = 0x01; ret = aes_256_wrap(header.key_wrapped, obj_key, masterkey); if (ret != CKR_OK) { TRACE_ERROR("aes_256_wrap failed with ret=%08lX.\n", ret); goto done; } memcpy(header.iv, name, 8); header.iv[8] = 0; header.iv[9] = 0; header.iv[10] = 0; header.iv[11] = 1; header.object_len = htobe32(clear_len); memcpy(object, &header, HEADER_LEN); /* Encrypt body */ ret = aes_256_gcm_seal(object + HEADER_LEN, /* ciphertext */ object + HEADER_LEN + clear_len, /* tag */ object, HEADER_LEN, /* aad */ clear, clear_len, /* plaintext */ obj_key, /* key */ header.iv /* iv */); if (ret != CKR_OK) { TRACE_ERROR("aes_256_gcm_seal failed with rc=%08lX.\n", ret); goto done; } *obj_new = object; *obj_new_len = total_len; object = NULL; ret = CKR_OK; done: if (object != NULL) free(object); return ret; } /** * Decrypts the given version 0.0 private object with given old masterkey. * * struct OBJECT_PRIV { * u32 total_len; * u8 private_flag; * //--- enc --- <- enc_old starts here * u32 object_len; * u8 object[object_len]; * u8 sha1[20]; * u8 padding[padding_len]; * }; */ static CK_RV decrypt_OBJECT_PRIV_00(unsigned char **clear, unsigned int *clear_len, unsigned char *enc_old, unsigned int enc_len, const CK_BYTE *masterkey_old) { CK_ULONG_32 obj_data_len_32; CK_BYTE hash_sha[SHA1_HASH_SIZE]; CK_BYTE des3_key[MAX_MASTER_KEY_SIZE]; unsigned char *tmp_clear, *raw_clear; CK_ULONG tmp_clear_len; CK_RV ret; *clear = NULL; *clear_len = 0; /* Allocate storage for clear output */ tmp_clear = malloc(enc_len); if (!tmp_clear) { TRACE_ERROR("Cannot malloc %d bytes, errno=%s.\n", enc_len, strerror(errno)); ret = CKR_HOST_MEMORY; goto done; } /* Decrypt old object */ memcpy(des3_key, masterkey_old, MAX_MASTER_KEY_SIZE); ret = sw_des3_cbc_decrypt(enc_old, enc_len, tmp_clear, &tmp_clear_len, (CK_BYTE *)"10293847", des3_key); if (ret) { TRACE_ERROR("sw_des3_cbc_decrypt failed with ret=%08lX\n", ret); goto done; } /* Validate the length */ memcpy(&obj_data_len_32, tmp_clear, sizeof(CK_ULONG_32)); if (obj_data_len_32 >= enc_len) { TRACE_ERROR("Decrypted object data length %d inconsistent\n", obj_data_len_32); ret = CKR_FUNCTION_FAILED; goto done; } /* Validate the hash */ ret = compute_sha1((char *)(tmp_clear + sizeof(CK_ULONG_32)), obj_data_len_32, (char *)hash_sha); if (ret != CKR_OK) { TRACE_ERROR("compute_sha1 failed with ret=%08lX\n", ret); goto done; } if (memcmp(tmp_clear + sizeof(CK_ULONG_32) + obj_data_len_32, hash_sha, SHA1_HASH_SIZE) != 0) { TRACE_ERROR("Stored hash does not match with newly calculated hash.\n"); ret = CKR_FUNCTION_FAILED; goto done; } /* At this point, tmp_clear points to the full decrypted obj data: * | 4 bytes len | clear obj[obj_data_len_32] | 20 bytes sha | padding | * But the caller only wants clear obj[obj_data_len_32]. */ raw_clear = malloc(obj_data_len_32); if (!raw_clear) { TRACE_ERROR("Cannot malloc %d bytes, errno=%s.\n", enc_len, strerror(errno)); ret = CKR_HOST_MEMORY; goto done; } memcpy(raw_clear, tmp_clear + sizeof(CK_ULONG_32), obj_data_len_32); *clear = raw_clear; *clear_len = (unsigned int)obj_data_len_32; ret = CKR_OK; done: free(tmp_clear); return ret; } /** * This function migrates the private obj to the current format. */ static CK_RV migrate_private_token_object(const char *data_store, const char *name, unsigned char *data, unsigned long len, const CK_BYTE *masterkey_old, const CK_BYTE *masterkey_new, const char *token_group) { const char *tokobj = "TOK_OBJ"; char fname[PATH_MAX]; unsigned char *clear = NULL; unsigned int clear_len; unsigned char *obj_new = NULL; unsigned int obj_new_len; FILE *fp = NULL; CK_RV ret; /* Decrypt old object */ ret = decrypt_OBJECT_PRIV_00(&clear, &clear_len, data, len, masterkey_old); if (ret != 0) { TRACE_ERROR("Cannot decrypt old object with old masterkey, ret=%08lX.\n", ret); goto done; } /* Create new object */ ret = make_OBJECT_PRIV_312(&obj_new, &obj_new_len, name, clear, clear_len, masterkey_new); if (ret != 0) { TRACE_ERROR("make_OBJECT_PRIV_312 failed with ret=%08lX.\n", ret); goto done; } /* Create file name for new object */ fp = open_tokenobject(fname, sizeof(fname), data_store, tokobj, name, "w"); if (!fp) { ret = CKR_FUNCTION_FAILED; goto done; } ret = set_perm(fileno(fp), token_group); if (ret != CKR_OK) goto done; /* Save new object */ if (fwrite(obj_new, obj_new_len, 1, fp) != 1) { TRACE_ERROR("fwrite(%s) failed, errno=%s\n", fname, strerror(errno)); ret = CKR_FUNCTION_FAILED; goto done; } ret = CKR_OK; done: if (fp) { fclose(fp); fp = NULL; } free(clear); free(obj_new); return ret; } /** * Reads a format 0.0 object: * * struct OBJECT { * u32 total_len; <- indicates old or new format * u8 private_flag; * u8 object; <- can be public or private * }; * * The total_len field has been already read to decide whether this * object is old or new. Its value is passed via the size parm. */ static CK_RV read_object_00(FILE *fp, const char *name, unsigned int size, unsigned char **obj, unsigned int *obj_len, CK_BBOOL *obj_priv) { CK_BBOOL priv; size_t read_size; unsigned char *buf = NULL; CK_RV ret; *obj = NULL; *obj_len = 0; /* Check parms */ if (!fp || !name) { TRACE_ERROR("Arguments bad.\n"); ret = CKR_ARGUMENTS_BAD; goto done; } /* Read 1-char private flag */ read_size = fread(&priv, sizeof(CK_BBOOL), 1, fp); if (read_size != 1) { TRACE_ERROR("Cannot read private flag from old object %s.\n", name); ret = CKR_FUNCTION_FAILED; goto done; } if (size <= sizeof(CK_ULONG_32) + sizeof(CK_BBOOL)) { TRACE_ERROR("Improper size of object %s (ignoring it)\n", name); ret = CKR_FUNCTION_FAILED; goto done; } /* Allocate buffer for obj */ size -= sizeof(CK_ULONG_32) + sizeof(CK_BBOOL); buf = malloc(size); if (!buf) { TRACE_ERROR("Cannot malloc %d bytes for object %s.\n", size, name); ret = CKR_HOST_MEMORY; goto done; } /* Read obj into buf */ read_size = fread((char *)buf, 1, size, fp); if (read_size != size) { TRACE_ERROR("Cannot read old object %s.\n", name); ret = CKR_FUNCTION_FAILED; free(buf); goto done; } *obj = buf; *obj_len = size; *obj_priv = priv; ret = CKR_OK; done: return ret; } /** * Reads the token object given by name from given data_store and returns * pointers to the object, its length, and indications whether the object * is in 0.0 or 3.12 format and whether it's private. */ static CK_RV read_object(const char *data_store, const char *name, unsigned char **obj, unsigned int *obj_len, CK_ULONG *version, CK_BBOOL *obj_priv) { char fname[PATH_MAX]; unsigned int size = 0; size_t read_size; FILE *fp; CK_RV ret; *obj = NULL; *obj_len = 0; /* Open token object file */ fp = open_tokenobject(fname, sizeof(fname), data_store, "TOK_OBJ", name, "r"); if (!fp) { ret = CKR_FUNCTION_FAILED; goto done; } /* Read 32-bit size field */ read_size = fread(&size, sizeof(CK_ULONG_32), 1, fp); if (read_size != 1) { TRACE_ERROR("Cannot read %zu bytes from %s, read_size = %zu. " "Object probably empty or corrupted.\n", sizeof(CK_ULONG_32), name, read_size); ret = CKR_FUNCTION_FAILED; goto done; } /* Check if this object is old or current */ if (size == TOKVERSION_312) { TRACE_INFO("%s is already in current format, nothing to do.\n", name); ret = CKR_OK; *version = TOKVERSION_312; goto done; } /* Read old object */ *version = TOKVERSION_00; ret = read_object_00(fp, name, size, obj, obj_len, obj_priv); if (ret != 0) { TRACE_ERROR("Cannot read old object %s.\n", name); ret = CKR_FUNCTION_FAILED; goto done; } ret = CKR_OK; done: if (fp) fclose(fp); return ret; } /** * Migrate the token objects from old to new format. Some of the token objects * may be in old and some may be in new format if a previous migration run * was interrupted. */ static CK_RV migrate_token_objects(const char *data_store, const CK_BYTE *masterkey_old, const CK_BYTE *masterkey_new, const CK_BYTE *so_wrap_key, const CK_BYTE *user_wrap_key, const char *token_group) { const char *tokobj = "TOK_OBJ"; const char *objidx = "OBJ.IDX"; FILE *fp = NULL; unsigned char *obj = NULL; unsigned int obj_len; char tmp[PATH_MAX]; char iname[PATH_MAX + 1 + strlen(tokobj) + 1 + strlen(objidx) + 1]; CK_BBOOL priv; CK_ULONG version; int count = 0, scount = 0; CK_RV ret; /* Check parms */ if (!data_store || !masterkey_old || !masterkey_new || !so_wrap_key || !user_wrap_key) { TRACE_ERROR("Invalid parms.\n"); ret = CKR_ARGUMENTS_BAD; goto done; } /* Open index file OBJ.IDX */ fp = open_tokenobject(iname, sizeof(iname), data_store, tokobj, objidx, "r"); if (!fp) { ret = CKR_FUNCTION_FAILED; goto done; } /* Migrate items from OBJ.IDX */ while (fgets(tmp, PATH_MAX, fp)) { tmp[strlen(tmp) - 1] = 0; ret = read_object(data_store, tmp, &obj, &obj_len, &version, &priv); if (ret == 0 && version == TOKVERSION_00) { if (priv) { ret = migrate_private_token_object(data_store, tmp, obj, obj_len, masterkey_old, masterkey_new, token_group); if (ret != CKR_OK) { TRACE_ERROR("Cannot migrate private object %s, continuing ... \n", tmp); } else scount++; } else { ret = migrate_public_token_object(data_store, tmp, obj, obj_len, token_group); if (ret != CKR_OK) { TRACE_ERROR("Cannot migrate public object %s, continuing ... \n", tmp); } else scount++; } } if (obj) { free(obj); obj = NULL; } count++; } /* OBJ.IDX must be at eof here */ if (!feof(fp)) { TRACE_WARN("OBJ.IDX is not at eof after object %s, should not happen.\n", tmp); } /* Close OBJ.IDX */ fclose(fp); ret = CKR_OK; TRACE_NONE("Migrated %d object(s) out of %d object(s).\n", scount, count); done: return ret; } /** * loads the new aes256 masterkey. * The new format defines the MK to be an AES-256 key. Its unencrypted format * are just the 32 key bytes. Its encrypted format is a 40 byte key blob */ static CK_RV load_masterkey_312(const char *data_store, const char *mkfile, const char *pin, TOKEN_DATA *tokdata, CK_BYTE *masterkey) { FILE *fp = NULL; CK_RV ret; int rc; char fname[PATH_MAX]; unsigned char inbuf[40]; unsigned char wrap_key[32]; /* Open file */ memset(fname, 0, PATH_MAX); snprintf(fname, PATH_MAX, "%s/%s", data_store, mkfile); fp = fopen(fname, "r"); if (!fp) { TRACE_ERROR("fopen(%s) failed, errno=%s\n", fname, strerror(errno)); ret = CKR_FUNCTION_FAILED; goto done; } /* Read wrapped key from file */ rc = fread(inbuf, sizeof(inbuf), 1, fp); if (rc != 1) { TRACE_ERROR("Cannot read %zu bytes from %s.\n", sizeof(inbuf), fname); ret = CKR_FUNCTION_FAILED; goto done; } /* Derive wrapping key from pin and public info in TOKEN_DATA */ if (strstr(mkfile,"MK_SO")) { rc = PKCS5_PBKDF2_HMAC(pin, strlen(pin), tokdata->dat.so_wrap_salt, 64, tokdata->dat.so_wrap_it, EVP_sha512(), 256 / 8, wrap_key); } else { rc = PKCS5_PBKDF2_HMAC(pin, strlen(pin), tokdata->dat.user_wrap_salt, 64, tokdata->dat.user_wrap_it, EVP_sha512(), 256 / 8, wrap_key); } if (rc != 1) { TRACE_INFO("PKCS5_PBKDF2_HMAC returned rc=%08X.\n", rc); ret = CKR_FUNCTION_FAILED; goto done; } /* Decrypt buffer with pin-related wrapping key */ rc = aes_256_unwrap(masterkey, inbuf, wrap_key); if (rc != CKR_OK) { TRACE_ERROR("aes_256_unwrap failed with rc=%08X.\n", rc); ret = CKR_FUNCTION_FAILED; goto done; } ret = CKR_OK; done: if (fp) fclose(fp); return ret; } /** * loads the old des3 masterkey from given file with given PIN. * The format is: * * struct MK { * u8 MK [24 or 64 (cca)]; * u8 sha1 [20]; * u8 padding[4]; * }; */ static CK_RV load_masterkey_00(const char *mkfile, const char *pin, CK_BYTE *masterkey) { CK_BYTE des3_key[3 * DES_KEY_SIZE]; char hash_sha[SHA1_HASH_SIZE]; char pin_md5_hash[MD5_HASH_SIZE]; unsigned char *cipher = NULL; unsigned char *clear = NULL; unsigned long cipher_len, clear_len; CK_ULONG master_key_len = 0L; int file_size = 0; CK_RV ret; int rc; FILE *fp = NULL; fp = fopen(mkfile, "r"); if (!fp) { TRACE_ERROR("fopen(%s) failed, errno=%s\n", mkfile, strerror(errno)); return CKR_FUNCTION_FAILED; } /* Determine the master key length */ fseek(fp, 0L, SEEK_END); file_size = ftell(fp); switch (file_size) { case MK_FILE_SIZE_00_CCA: /* CCA token */ master_key_len = MASTER_KEY_SIZE_CCA; break; case MK_FILE_SIZE_00: /* All other tokens */ master_key_len = MASTER_KEY_SIZE; break; default: /* Unknown MK format, should not occur. */ TRACE_ERROR("%s has an unknown file size of %d bytes. Should be either 48 or 88 bytes.\n", mkfile, file_size); ret = CKR_FUNCTION_FAILED; goto done; } rewind(fp); /* Read file contents */ clear_len = cipher_len = (master_key_len + SHA1_HASH_SIZE + (DES_BLOCK_SIZE - 1)) & ~(DES_BLOCK_SIZE - 1); cipher = malloc(cipher_len); clear = malloc(clear_len); if (cipher == NULL || clear == NULL) { ret = CKR_HOST_MEMORY; goto done; } rc = fread(cipher, cipher_len, 1, fp); if (rc != 1) { TRACE_ERROR("Cannot read %ld bytes from %s\n", cipher_len, mkfile); ret = CKR_FUNCTION_FAILED; goto done; } /* Decrypt the masterkey */ ret = compute_md5((char *)pin, strlen(pin), pin_md5_hash); if (ret) { TRACE_ERROR("Error calculating MD5 of PIN, ret=%08lX\n", ret); goto done; } memcpy(des3_key, pin_md5_hash, MD5_HASH_SIZE); memcpy(des3_key + MD5_HASH_SIZE, pin_md5_hash, DES_KEY_SIZE); ret = sw_des3_cbc_decrypt(cipher, cipher_len, clear, &clear_len, (unsigned char *) "12345678", des3_key); if (ret != CKR_OK) { TRACE_ERROR("failed to decrypt master key file after read, ret=%08lX\n", ret); ret = CKR_FUNCTION_FAILED; goto done; } /* compare the hashes to verify integrity */ ret = compute_sha1((char *)clear, master_key_len, hash_sha); if (ret) { TRACE_ERROR("Failed to compute sha1 for masterkey, ret=%08lX\n", ret); goto done; } if (memcmp(hash_sha, clear + master_key_len, SHA1_HASH_SIZE) != 0) { TRACE_ERROR("%s appears to be tampered! Cannot migrate.\n", mkfile); ret = CKR_FUNCTION_FAILED; goto done; } memcpy(masterkey, clear, master_key_len); ret = 0; done: if (fp) fclose(fp); free(clear); free(cipher); return ret; } /** * Check if the given conf_dir exists and contains the opencryptoki.conf. */ static CK_BBOOL conffile_exists(const char *conf_dir) { char fname[PATH_MAX]; struct stat statbuf; DIR *dir; TRACE_INFO("Checking if config file exists in %s ...\n", conf_dir); dir = opendir(conf_dir); if (dir == NULL) { TRACE_INFO("Cannot open %s.\n", conf_dir); return CK_FALSE; } /* Check if opencryptoki.conf exists */ memset(fname, 0, PATH_MAX); snprintf(fname, PATH_MAX, "%s/opencryptoki.conf", conf_dir); if (stat(fname, &statbuf) != 0) { TRACE_INFO("Cannot find %s.\n", fname); closedir(dir); return CK_FALSE; } closedir(dir); return CK_TRUE; } /** * Check if the given data_store directory exists. */ static CK_BBOOL datastore_exists(const char *data_store) { DIR *dir; TRACE_INFO("Checking if datastore %s exists ...\n", data_store); dir = opendir(data_store); if (dir == NULL) { TRACE_INFO("Cannot open %s.\n", data_store); return CK_FALSE; } closedir(dir); return CK_TRUE; } /** * */ static CK_RV load_MK_SO_00(const char *data_store, const char *sopin, CK_BYTE *masterkey) { const char *mkso = "MK_SO"; char fname[PATH_MAX]; CK_RV ret; /* Get masterkey from MK_SO. This also verifies SO PIN is correct */ memset(masterkey, 0, MAX_MASTER_KEY_SIZE); if (ock_snprintf(fname, sizeof(fname), "%s/%s", data_store, mkso) != 0) { TRACE_ERROR("path name for old MK_SO too long\n"); return CKR_FUNCTION_FAILED; } ret = load_masterkey_00(fname, sopin, masterkey); if (ret != CKR_OK) { TRACE_ERROR("Cannot load old masterkey from MK_SO, ret=%08lX.\n", ret); // We cannot do anything more here, even when some objs are still old. // We would need the old key in order to open an old obj. } return ret; } /** * */ static CK_RV load_MK_USER_00(const char *data_store, const char *userpin, CK_BYTE *masterkey) { const char *mkuser = "MK_USER"; char fname[PATH_MAX]; CK_RV ret; /* Get masterkey from MK_USER. This also verifies user PIN is correct */ memset(masterkey, 0, MAX_MASTER_KEY_SIZE); if (ock_snprintf(fname, sizeof(fname), "%s/%s", data_store, mkuser) != 0) { TRACE_ERROR("path name for old MK_USER too long\n"); return CKR_FUNCTION_FAILED; } ret = load_masterkey_00(fname, userpin, masterkey); if (ret != CKR_OK) { TRACE_ERROR("Cannot load old masterkey from MK_USER, ret=%08lX.\n", ret); } return ret; } /** * */ static CK_RV load_MK_SO_312(const char *data_store, const char *sopin, TOKEN_DATA *tokdata, CK_BYTE *masterkey) { CK_RV ret; /* Get masterkey from MK_SO_312. This also verifies SO PIN is correct */ memset(masterkey, 0, MAX_MASTER_KEY_SIZE); ret = load_masterkey_312(data_store, "MK_SO_312", sopin, tokdata, masterkey); if (ret != CKR_OK) { TRACE_ERROR("Cannot load masterkey from MK_SO_312, ret=%08lX.\n", ret); } return ret; } /** * */ static CK_RV load_MK_USER_312(const char *data_store, const char *userpin, TOKEN_DATA *tokdata, CK_BYTE *masterkey) { CK_RV ret; /* Get masterkey from MK_USER_312. This also verifies user PIN is correct */ memset(masterkey, 0, MAX_MASTER_KEY_SIZE); ret = load_masterkey_312(data_store, "MK_USER_312", userpin, tokdata, masterkey); if (ret != CKR_OK) { TRACE_ERROR("Cannot load masterkey from MK_USER_312, ret=%08lX.\n", ret); } return ret; } /** * Loads the NVTOK.DAT and returns the TOKEN_DATA struct. */ static CK_RV load_NVTOK_DAT(const char *data_store, const char *nvtok_name, TOKEN_DATA *td) { char fname[PATH_MAX]; struct stat stbuf; int fd; size_t tdlen; FILE *fp = NULL; CK_RV ret; /* Check parms */ if (!data_store || !nvtok_name || !td) { ret = CKR_ARGUMENTS_BAD; goto done; } /* Read the NVTOK.DAT */ fp = open_datastore_file(fname, sizeof(fname), data_store, nvtok_name, "r"); if (!fp) return CKR_FUNCTION_FAILED; fd = fileno(fp); if ((fstat(fd, &stbuf) != 0) || (!S_ISREG(stbuf.st_mode))) { ret = CKR_FUNCTION_FAILED; goto done; } /* Check if this NVTOK.DAT is old or new */ if (stbuf.st_size == sizeof(TOKEN_DATA_OLD)) { /* old data store/pin format */ tdlen = sizeof(TOKEN_DATA_OLD); } else if (stbuf.st_size == sizeof(TOKEN_DATA)) { /* new data store/pin format */ tdlen = sizeof(TOKEN_DATA); } else { TRACE_ERROR("%s has an invalid size of %ld bytes. Neither old nor new token format.\n", fname, stbuf.st_size); ret = CKR_FUNCTION_FAILED; goto done; } /* Read TOKEN_DATA */ ret = fread(td, tdlen, 1, fp); if (ret != 1) { TRACE_ERROR("Cannot read %s, errno=%s\n", fname, strerror(errno)); ret = CKR_FUNCTION_FAILED; goto done; } if (stbuf.st_size == sizeof(TOKEN_DATA)) { /* The 312 version always uses big endian */ td->token_info.flags = be32toh(td->token_info.flags); td->token_info.ulMaxSessionCount = be32toh(td->token_info.ulMaxSessionCount); td->token_info.ulSessionCount = be32toh(td->token_info.ulSessionCount); td->token_info.ulMaxRwSessionCount = be32toh(td->token_info.ulMaxRwSessionCount); td->token_info.ulRwSessionCount = be32toh(td->token_info.ulRwSessionCount); td->token_info.ulMaxPinLen = be32toh(td->token_info.ulMaxPinLen); td->token_info.ulMinPinLen = be32toh(td->token_info.ulMinPinLen); td->token_info.ulTotalPublicMemory = be32toh(td->token_info.ulTotalPublicMemory); td->token_info.ulFreePublicMemory = be32toh(td->token_info.ulFreePublicMemory); td->token_info.ulTotalPrivateMemory = be32toh(td->token_info.ulTotalPrivateMemory); td->token_info.ulFreePrivateMemory = be32toh(td->token_info.ulFreePrivateMemory); td->tweak_vector.allow_weak_des = be32toh(td->tweak_vector.allow_weak_des); td->tweak_vector.check_des_parity = be32toh(td->tweak_vector.check_des_parity); td->tweak_vector.allow_key_mods = be32toh(td->tweak_vector.allow_key_mods); td->tweak_vector.netscape_mods = be32toh(td->tweak_vector.netscape_mods); td->dat.version = be32toh(td->dat.version); td->dat.so_login_it = be64toh(td->dat.so_login_it); td->dat.user_login_it = be64toh(td->dat.user_login_it); td->dat.so_wrap_it = be64toh(td->dat.so_wrap_it); td->dat.user_wrap_it = be64toh(td->dat.user_wrap_it); } ret = CKR_OK; done: if (fp) fclose(fp); return ret; } /** * Strip trailing chars from given string. */ static char *strip_trailing_chars(char *s, int slen, char c) { int i; if (!s || slen == 0) return s; for (i = slen - 1; i >= 0; i--) { if (s[i] == c) s[i] = '\0'; else break; } return s; } /** * Read the token info from NVTOK.DAT. */ static CK_RV get_token_info(const char *data_store, CK_TOKEN_INFO_32 *tokinfo) { TOKEN_DATA tokdata; CK_RV ret; TRACE_INFO("Reading token info from NVTOK.DAT ...\n"); ret = load_NVTOK_DAT(data_store, "NVTOK.DAT", &tokdata); if (ret != CKR_OK) { TRACE_ERROR("Cannot load NVTOK.DAT, datastore inconsistent.\n"); return ret; } memcpy(tokinfo, &(tokdata.token_info), sizeof(CK_TOKEN_INFO_32)); return CKR_OK; } static void config_parse_error(int line, int col, const char *msg) { fprintf(stderr, "Error parsing config file: line %d column %d: %s\n", line, col, msg); } static struct ConfigBaseNode *config_parse(const char *config_file, CK_BBOOL track_comments) { FILE *file; struct ConfigBaseNode *config = NULL; int ret; file = fopen(config_file, "r"); if (file == NULL) return NULL; ret = parse_configlib_file(file, &config, config_parse_error, track_comments); fclose(file); if (ret != 0) return NULL; return config; } /** * Identify the token that belongs to the given slot ID. */ static CK_RV identify_token(CK_SLOT_ID slot_id, char *conf_dir, char *dll_name, size_t dll_name_len, char *token_group, size_t token_group_len) { char conf_file[PATH_MAX]; CK_RV ret; struct ConfigBaseNode *config = NULL, *c; struct ConfigIdxStructNode *slot; size_t max_dllname_size, max_tokengroup_size; char *stdll, *usergroup = ""; max_dllname_size = dll_name_len > sizeof(((Slot_Info_t_64 *)NULL)->dll_location) ? sizeof(((Slot_Info_t_64 *)NULL)->dll_location) : dll_name_len; max_tokengroup_size = token_group_len > sizeof(((Slot_Info_t_64 *)NULL)->usergroup) ? sizeof(((Slot_Info_t_64 *)NULL)->usergroup) : token_group_len; TRACE_INFO("Identifying the token that belongs to slot %ld ...\n", slot_id); if (slot_id >= NUMBER_SLOTS_MANAGED) { ret = CKR_FUNCTION_FAILED; goto done; } /* Open conf file */ if (ock_snprintf(conf_file, PATH_MAX, "%s/%s", conf_dir, "opencryptoki.conf") != 0) { TRACE_ERROR("Path name overflow for config file opencryptoki.conf\n"); return CKR_FUNCTION_FAILED; } config = config_parse(conf_file, FALSE); if (config == NULL) { TRACE_ERROR("Failed to parse config file %s\n", conf_file); ret = CKR_FUNCTION_FAILED; goto done; } slot = confignode_findidx(config, "slot", slot_id); if (slot == NULL) { TRACE_ERROR("Failed to find slot %lu in config file %s\n", slot_id, conf_file); ret = CKR_FUNCTION_FAILED; goto done; } c = confignode_find(slot->value, "stdll"); if (c == NULL || (stdll = confignode_getstr(c)) == NULL) { TRACE_ERROR("Failed to find stdll for slot %lu in config file %s\n", slot_id, conf_file); ret = CKR_FUNCTION_FAILED; goto done; } c = confignode_find(slot->value, "usergroup"); if (c != NULL && (usergroup = confignode_getstr(c)) == NULL) { TRACE_ERROR("Failed to find usergroup for slot %lu in config file %s\n", slot_id, conf_file); ret = CKR_FUNCTION_FAILED; goto done; } strncpy(dll_name, stdll, max_dllname_size); dll_name[max_dllname_size - 1] = 0; strncpy(token_group, usergroup, max_tokengroup_size); token_group[max_tokengroup_size - 1] = 0; ret = CKR_OK; done: confignode_deepfree(config); return ret; } /** * derives the SO wrap key from the given SO pin and given public * info in NVTOK.DAT. */ static CK_RV derive_so_wrap_key_312(const char *sopin, TOKEN_DATA *tokdata, CK_BYTE *so_wrap_key) { CK_RV ret; ret = PKCS5_PBKDF2_HMAC(sopin, strlen(sopin), tokdata->dat.so_wrap_salt, 64, tokdata->dat.so_wrap_it, EVP_sha512(), 256 / 8, so_wrap_key); if (ret != 1) { TRACE_ERROR("PBKDF2 failed.\n"); ret = CKR_FUNCTION_FAILED; goto done; } ret = CKR_OK; done: return ret; } /** * derives the user wrap key from the given user pin and given public * info in NVTOK.DAT. */ static CK_RV derive_user_wrap_key_312(const char *userpin, TOKEN_DATA *tokdata, CK_BYTE *user_wrap_key) { CK_RV ret; ret = PKCS5_PBKDF2_HMAC(userpin, strlen(userpin), tokdata->dat.user_wrap_salt, 64, tokdata->dat.user_wrap_it, EVP_sha512(), 256 / 8, user_wrap_key); if (ret != 1) { TRACE_ERROR("PBKDF2 failed.\n"); ret = CKR_FUNCTION_FAILED; goto done; } ret = CKR_OK; done: return ret; } /** * Activates the new repository by deleting the old MK_USER, MK_SO, and * NVTOK.DAT, and renaming the new MK_SO_312, MK_USER_312, NVTOK.DAT_312 to * their normal names. */ static CK_RV cleanup_repository_backup(const char *data_store) { static char *names[] = { "MK_SO", "MK_USER", "NVTOK.DAT" }; int num_names = sizeof(names) / sizeof(char *); char fname1[PATH_MAX + 9 + 1]; // satisfy compiler warning char fname2[PATH_MAX + 1 + 1]; // satisfy compiler warning int i, rc; CK_RV ret; /* Delete old files */ for (i = 0; i < num_names; i++) { snprintf(fname1, sizeof(fname1), "%s/%s", data_store, names[i]); rc = remove(fname1); if (rc) { TRACE_ERROR("Cannot delete old file %s.\n", fname1); ret = CKR_FUNCTION_FAILED; goto done; } } /* Rename new files */ for (i = 0; i < num_names; i++) { snprintf(fname1, sizeof(fname1), "%s/%s_312", data_store, names[i]); snprintf(fname2, sizeof(fname2), "%s/%s", data_store, names[i]); rc = rename(fname1, fname2); if (rc) { TRACE_ERROR("Cannot rename new file %s.\n", fname1); ret = CKR_FUNCTION_FAILED; goto done; } } ret = CKR_OK; done: return ret; } /** * Migrates the repository. This process may be interrupted at any time and * must be able to resume until the complete repository is successfully * migrated. This especially requires to keep the old keys until * everything is done. */ static CK_RV migrate_repository(const char *data_store, const char *sopin, const char *userpin, const char *token_group) { CK_BYTE so_masterkey_old[MAX_MASTER_KEY_SIZE]; CK_BYTE so_masterkey_new[MAX_MASTER_KEY_SIZE]; CK_BYTE user_masterkey_old[MAX_MASTER_KEY_SIZE]; CK_BYTE user_masterkey_new[MAX_MASTER_KEY_SIZE]; CK_BYTE so_wrap_key[32]; CK_BYTE user_wrap_key[32]; CK_RV ret; TOKEN_DATA tokdata; TRACE_INFO("Migrating the repository ...\n"); /* Load NVTOK.DAT_312, which was either created before or exists from a * previous interrupted run. So tokdata definitely contains the 3.12 * extension. */ ret = load_NVTOK_DAT(data_store, "NVTOK.DAT_312", &tokdata); if (ret != CKR_OK) { TRACE_ERROR("Cannot load NVTOK.DAT_312, ret=%08lX.\n", ret); goto done; } ret = load_MK_SO_00(data_store, sopin, so_masterkey_old); if (ret != CKR_OK) { TRACE_ERROR("Cannot load old masterkey, ret=%08lX.\n", ret); goto done; } ret = load_MK_USER_00(data_store, userpin, user_masterkey_old); if (ret != CKR_OK) { TRACE_ERROR("Cannot load old masterkey, ret=%08lX.\n", ret); goto done; } if (memcmp(so_masterkey_old, user_masterkey_old, MAX_MASTER_KEY_SIZE) != 0) { TRACE_ERROR("MK_SO and MK_USER are inconsistent, got different MKs.\n"); ret = CKR_FUNCTION_FAILED; goto done; } ret = load_MK_SO_312(data_store, sopin, &tokdata, so_masterkey_new); if (ret != CKR_OK) { TRACE_ERROR("Cannot load new masterkey from MK_SO_312, ret=%08lX.\n", ret); goto done; } ret = load_MK_USER_312(data_store, userpin, &tokdata, user_masterkey_new); if (ret != CKR_OK) { TRACE_ERROR("Cannot load new masterkey from MK_USER_312, ret=%08lX.\n", ret); goto done; } if (memcmp(so_masterkey_new, user_masterkey_new, MAX_MASTER_KEY_SIZE) != 0) { TRACE_ERROR("MK_SO_312 and MK_USER_312 are inconsistent, got different MKs.\n"); ret = CKR_FUNCTION_FAILED; goto done; } /* This function needs a new NVTOK.DAT with the public salt and icount */ ret = derive_so_wrap_key_312(sopin, &tokdata, so_wrap_key); if (ret != CKR_OK) { TRACE_ERROR("Cannot create new so_wrap_key, ret=%08lX.\n", ret); goto done; } /* This function needs a new NVTOK.DAT with the public salt and icount */ ret = derive_user_wrap_key_312(userpin, &tokdata, user_wrap_key); if (ret != CKR_OK) { TRACE_ERROR("Cannot create new user_wrap_key, ret=%08lX.\n", ret); goto done; } /* Now do the migration */ ret = migrate_token_objects(data_store, so_masterkey_old, so_masterkey_new, so_wrap_key, user_wrap_key, token_group); if (ret != CKR_OK) { TRACE_ERROR("Migrating token objects failed with ret=%08lX.\n", ret); goto done; } /* Remove temp files in backup */ ret = cleanup_repository_backup(data_store); if (ret != CKR_OK) { TRACE_ERROR("Cleanup repository backup failed with ret=%08lX.\n", ret); goto done; } done: return ret; } /** * creates a MK_USER_312 file containing the new user MK. */ static CK_RV create_MK_USER_312(const char *data_store, const char *userpin, const CK_BYTE *masterkey, TOKEN_DATA *tokdata, const char *token_group) { const char *mkuser = "MK_USER_312"; char fname[PATH_MAX]; CK_BYTE user_wrap_key[32]; CK_BYTE outbuf[40]; FILE *fp = NULL; size_t rv; CK_RV ret; /* Create user wrap key */ ret = derive_user_wrap_key_312(userpin, tokdata, (unsigned char *)&user_wrap_key); if (ret != CKR_OK) { TRACE_ERROR("Cannot derive user wrap key, ret=%08lX.\n", ret); ret = CKR_FUNCTION_FAILED; goto done; } /* Wrap user MK with user_wrap_key */ ret = aes_256_wrap(outbuf, masterkey, user_wrap_key); if (ret != CKR_OK) goto done; /* Create file MK_USER_312 */ fp = open_datastore_file(fname, sizeof(fname), data_store, mkuser, "w"); if (!fp) { ret = CKR_FUNCTION_FAILED; goto done; } ret = set_perm(fileno(fp), token_group); if (ret != CKR_OK) goto done; rv = fwrite(outbuf, sizeof(outbuf), 1, fp); if (rv != 1) { TRACE_ERROR("fwrite(%s) failed, errno=%s.\n", fname, strerror(errno)); ret = CKR_FUNCTION_FAILED; goto done; } ret = CKR_OK; done: if (fp) fclose(fp); return ret; } /** * creates a MK_SO_312 file containing the new SO MK. */ static CK_RV create_MK_SO_312(const char *data_store, const char *sopin, const CK_BYTE *masterkey, TOKEN_DATA *tokdata, const char *token_group) { const char *mkso = "MK_SO_312"; char fname[PATH_MAX]; CK_BYTE outbuf[40]; CK_BYTE so_wrap_key[32]; FILE *fp = NULL; size_t rv; CK_RV ret; /* Derive so wrap key from sopin and tokdata */ ret = derive_so_wrap_key_312(sopin, tokdata, so_wrap_key); if (ret != CKR_OK) { TRACE_ERROR("Cannot derive new so wrap key, ret=%08lX.\n", ret); ret = CKR_FUNCTION_FAILED; goto done; } /* Wrap masterkey with SO_wrap_key */ ret = aes_256_wrap(outbuf, masterkey, so_wrap_key); if (ret != CKR_OK) { TRACE_ERROR("Cannot wrap masterkey with so wrap key, ret=%08lX.\n", ret); goto done; } /* Create file MK_SO_312 */ fp = open_datastore_file(fname, sizeof(fname), data_store, mkso, "w"); if (!fp) { TRACE_ERROR("fopen(%s) failed, errno=%s\n", fname, strerror(errno)); ret = CKR_FUNCTION_FAILED; goto done; } ret = set_perm(fileno(fp), token_group); if (ret != CKR_OK) goto done; rv = fwrite(outbuf, sizeof(outbuf), 1, fp); if (rv != 1) { TRACE_ERROR("fwrite(%s) failed, errno=%s.\n", fname, strerror(errno)); ret = CKR_FUNCTION_FAILED; goto done; } ret = CKR_OK; done: if (fp) fclose(fp); return ret; } /** * reads the old NVTOK.DAT and returns its contents: */ static CK_RV read_NVTOK_DAT_00(const char *data_store, TOKEN_DATA *tokdata) { FILE *fp; const char *nvtok = "NVTOK.DAT"; char fname[PATH_MAX]; struct stat stbuf; int fd; CK_RV ret; /* Check parms */ if (!data_store || !tokdata) { return CKR_ARGUMENTS_BAD; } /* Read the old NVTOK.DAT */ fp = open_datastore_file(fname, sizeof(fname), data_store, nvtok, "r"); if (!fp) return CKR_FUNCTION_FAILED; fd = fileno(fp); if ((fstat(fd, &stbuf) != 0) || (!S_ISREG(stbuf.st_mode))) { ret = CKR_FUNCTION_FAILED; goto done; } /* Ensure that this NVTOK.DAT is in fact old */ if (stbuf.st_size != sizeof(TOKEN_DATA_OLD)) { TRACE_ERROR("%s has an invalid size of %ld bytes.\n", fname, stbuf.st_size); ret = CKR_FUNCTION_FAILED; goto done; } /* Read TOKEN_DATA_OLD */ ret = fread(tokdata, sizeof(TOKEN_DATA_OLD), 1, fp); if (ret != 1) { TRACE_ERROR("Cannot read %s, errno=%s\n", fname, strerror(errno)); ret = CKR_FUNCTION_FAILED; goto done; } ret = CKR_OK; done: if (fp) fclose(fp); return ret; } /** * creates the additions for new format. */ static CK_RV create_TOKEN_DATA_VERSION(const char *sopin, const char *userpin, TOKEN_DATA *tokdata) { CK_RV ret; int rc; tokdata->dat.version = TOKVERSION_312; tokdata->dat.so_login_it = SO_KDF_LOGIN_IT; memcpy(tokdata->dat.so_login_salt, SO_KDF_LOGIN_PURPOSE, 32); ret = local_rng(tokdata->dat.so_login_salt + 32, 32); if (ret != CKR_OK) { TRACE_ERROR("local_rng returned %lX\n", ret); goto done; } rc = PKCS5_PBKDF2_HMAC(sopin, strlen(sopin), tokdata->dat.so_login_salt, 64, tokdata->dat.so_login_it, EVP_sha512(), 256 / 8, tokdata->dat.so_login_key); if (rc != 1) { TRACE_ERROR("Error: PKCS5_PBKDF2_HMAC\n"); ret = CKR_FUNCTION_FAILED; goto done; } tokdata->dat.so_wrap_it = SO_KDF_WRAP_IT; memcpy(tokdata->dat.so_wrap_salt, SO_KDF_WRAP_PURPOSE, 32); ret = local_rng(tokdata->dat.so_wrap_salt + 32, 32); if (ret != CKR_OK) { TRACE_ERROR("local_rng returned %lX\n", ret); goto done; } tokdata->dat.user_login_it = USER_KDF_LOGIN_IT; memcpy(tokdata->dat.user_login_salt, USER_KDF_LOGIN_PURPOSE, 32); ret = local_rng(tokdata->dat.user_login_salt + 32, 32); if (ret != CKR_OK) { TRACE_ERROR("local_rng returned %lX\n", ret); goto done; } rc = PKCS5_PBKDF2_HMAC(userpin, strlen(userpin), tokdata->dat.user_login_salt, 64, tokdata->dat.user_login_it, EVP_sha512(), 256 / 8, tokdata->dat.user_login_key); if (rc != 1) { TRACE_ERROR("Error: PKCS5_PBKDF2_HMAC\n"); ret = CKR_FUNCTION_FAILED; goto done; } tokdata->dat.user_wrap_it = USER_KDF_WRAP_IT; memcpy(tokdata->dat.user_wrap_salt, USER_KDF_WRAP_PURPOSE, 32); ret = local_rng(tokdata->dat.user_wrap_salt + 32, 32); if (ret != CKR_OK) { TRACE_ERROR("local_rng returned %lX\n", ret); goto done; } ret = CKR_OK; done: return ret; } /** * Creates the new NVTOK.DAT which now contains the public salt and iteration * count values that are necessary for re-deriving the pin-related * wrapping keys. */ static CK_RV create_NVTOK_DAT_312(const char *data_store, const char *sopin, const char *userpin, TOKEN_DATA *tokdata, const char *token_group) { const char *nvtok = "NVTOK.DAT_312"; char fname[PATH_MAX]; TOKEN_DATA be_tokdata; FILE *fp = NULL; CK_RV ret; size_t rc; /* Check parms */ if (!data_store || !sopin || !userpin || !tokdata) { TRACE_ERROR("invalid parms.\n"); ret = CKR_ARGUMENTS_BAD; goto done; } /* Create new file NVTOK.DAT_312 */ fp = open_datastore_file(fname, sizeof(fname), data_store, nvtok, "w"); if (!fp) { ret = CKR_FUNCTION_FAILED; goto done; } ret = set_perm(fileno(fp), token_group); if (ret != CKR_OK) goto done; /* Get contents from old NVTOK.DAT */ ret = read_NVTOK_DAT_00(data_store, tokdata); if (ret != CKR_OK) { TRACE_ERROR("Cannot read old NVTOK.DAT, ret=%08lX\n", ret); goto done; } /* Create additions for new format */ ret = create_TOKEN_DATA_VERSION(sopin, userpin, tokdata); if (ret != CKR_OK) { TRACE_ERROR("Cannot create TOKEN_DATA_VERSION struct, ret=%08lX\n", ret); goto done; } /* The 312 version always uses big endian */ memcpy(&be_tokdata, tokdata, sizeof(TOKEN_DATA)); be_tokdata.token_info.flags = htobe32(tokdata->token_info.flags); be_tokdata.token_info.ulMaxSessionCount = htobe32(tokdata->token_info.ulMaxSessionCount); be_tokdata.token_info.ulSessionCount = htobe32(tokdata->token_info.ulSessionCount); be_tokdata.token_info.ulMaxRwSessionCount = htobe32(tokdata->token_info.ulMaxRwSessionCount); be_tokdata.token_info.ulRwSessionCount = htobe32(tokdata->token_info.ulRwSessionCount); be_tokdata.token_info.ulMaxPinLen = htobe32(tokdata->token_info.ulMaxPinLen); be_tokdata.token_info.ulMinPinLen = htobe32(tokdata->token_info.ulMinPinLen); be_tokdata.token_info.ulTotalPublicMemory = htobe32(tokdata->token_info.ulTotalPublicMemory); be_tokdata.token_info.ulFreePublicMemory = htobe32(tokdata->token_info.ulFreePublicMemory); be_tokdata.token_info.ulTotalPrivateMemory = htobe32(tokdata->token_info.ulTotalPrivateMemory); be_tokdata.token_info.ulFreePrivateMemory = htobe32(tokdata->token_info.ulFreePrivateMemory); be_tokdata.tweak_vector.allow_weak_des = htobe32(tokdata->tweak_vector.allow_weak_des); be_tokdata.tweak_vector.check_des_parity = htobe32(tokdata->tweak_vector.check_des_parity); be_tokdata.tweak_vector.allow_key_mods = htobe32(tokdata->tweak_vector.allow_key_mods); be_tokdata.tweak_vector.netscape_mods = htobe32(tokdata->tweak_vector.netscape_mods); be_tokdata.dat.version = htobe32(tokdata->dat.version); be_tokdata.dat.so_login_it = htobe64(tokdata->dat.so_login_it); be_tokdata.dat.user_login_it = htobe64(tokdata->dat.user_login_it); be_tokdata.dat.so_wrap_it = htobe64(tokdata->dat.so_wrap_it); be_tokdata.dat.user_wrap_it = htobe64(tokdata->dat.user_wrap_it); /* Write converted token data into NVTOK.DAT_312 */ rc = fwrite(&be_tokdata, sizeof(TOKEN_DATA), 1, fp); if (rc != 1) { TRACE_ERROR("fwrite(%s) failed, errno=%s.\n", fname, strerror(errno)); ret = CKR_FUNCTION_FAILED; goto done; } ret = CKR_OK; done: if (fp) fclose(fp); return ret; } /** * Creates new token keys MK_USER_312 and MK_SO_312. The old keys in * MK_USER and MK_SO are kept until the migration is fully completed. * Then the old keys are deleted and the new keys are renamed. */ static CK_RV create_token_keys_312(const char *data_store, const char *sopin, const char *userpin, const char *token_group) { unsigned char masterkey[32]; TOKEN_DATA tokdata; CK_RV ret = CKR_OK; TRACE_INFO("Creating new v3.12 MK_SO, MK_USER, and NVTOK.DAT ...\n"); /* Create master key */ ret = local_rng(masterkey, 32); if (ret != CKR_OK) { TRACE_ERROR("Cannot create master key, ret=%08lX\n", ret); goto done; } ret = create_NVTOK_DAT_312(data_store, sopin, userpin, &tokdata, token_group); if (ret != CKR_OK) { TRACE_ERROR("Cannot create NVTOK.DAT_312, ret=%08lX\n", ret); goto done; } ret = create_MK_SO_312(data_store, sopin, masterkey, &tokdata, token_group); if (ret != CKR_OK) { TRACE_ERROR("Cannot create MK_SO_312, ret=%08lX\n", ret); goto done; } ret = create_MK_USER_312(data_store, userpin, masterkey, &tokdata, token_group); if (ret != CKR_OK) { TRACE_ERROR("Cannot create MK_USER_312, ret=%08lX\n", ret); goto done; } ret = CKR_OK; done: return ret; } /** * Count the objs in the data_store and return the number of total objs * and number of old objs. */ static CK_RV count_objects(const char *data_store, unsigned int *num_objs, unsigned int *num_old_objs) { char tmp[PATH_MAX], iname[PATH_MAX]; unsigned char *obj = NULL; unsigned int obj_len; CK_ULONG version; CK_BBOOL priv; FILE *fp; CK_RV ret; *num_objs = 0; *num_old_objs = 0; /* Open index file OBJ.IDX */ snprintf(iname, sizeof(iname), "%s/TOK_OBJ/OBJ.IDX", data_store); fp = fopen((char *) iname, "r"); if (!fp) { TRACE_INFO("Cannot open %s, datastore probably empty.\n", iname); ret = CKR_OK; goto done; } /* Count objects and old objects */ while (fgets(tmp, PATH_MAX, fp)) { tmp[strlen(tmp) - 1] = 0; (*num_objs)++; ret = read_object(data_store, tmp, &obj, &obj_len, &version, &priv); if (ret == 0 && version == TOKVERSION_00) (*num_old_objs)++; if (obj) { free(obj); obj = NULL; } } /* OBJ.IDX must be at eof here */ if (!feof(fp)) { TRACE_WARN("OBJ.IDX is not at eof after object %s, should not happen.\n", tmp); } fclose(fp); ret = CKR_OK; done: return ret; } /** * Set parameter "*new" to true if the NVTOK.DAT in the given data store * is on 3.12 level, or false otherwise. */ static CK_RV NVTOK_DAT_is_312(const char *data_store, CK_BBOOL *new) { CK_RV ret; char fname[PATH_MAX]; struct stat stbuf; int fd; FILE *fp = NULL; *new = CK_FALSE; /* Read the NVTOK.DAT */ snprintf(fname, PATH_MAX, "%s/NVTOK.DAT", data_store); fp = fopen((char *)fname, "r"); if (!fp) { TRACE_ERROR("Cannot open %s, errno=%s\n", fname, strerror(errno)); return CKR_FUNCTION_FAILED; } fd = fileno(fp); if ((fstat(fd, &stbuf) != 0) || (!S_ISREG(stbuf.st_mode))) { ret = CKR_FUNCTION_FAILED; goto done; } /* Check if this NVTOK.DAT is old or new */ if (stbuf.st_size == sizeof(TOKEN_DATA_OLD)) { *new = CK_FALSE; } else if (stbuf.st_size == sizeof(TOKEN_DATA)) { *new = CK_TRUE; } else { TRACE_ERROR("%s has an invalid size of %ld bytes. Neither old nor new token format.\n", fname, stbuf.st_size); ret = CKR_FUNCTION_FAILED; goto done; } ret = CKR_OK; done: fclose(fp); return ret; } /** * Check if the data store is in 3.12 format. */ static CK_RV datastore_is_312(const char *data_store, const char *sopin, const char *userpin, CK_BBOOL *new) { CK_RV ret; CK_BYTE masterkey_so[32]; CK_BYTE masterkey_user[32]; unsigned int num_objs = 0, num_old_objs = 0; TOKEN_DATA tokdata; *new = CK_FALSE; TRACE_INFO("Checking if data store is already in 3.12 format ...\n"); /* Check if NVTOK.DAT is new */ ret = NVTOK_DAT_is_312(data_store, new); if (ret != CKR_OK) { warnx("Cannot determine if NVTOK.DAT has an old or new format."); warnx("Note that generic token formats cannot be migrated."); ret = CKR_FUNCTION_FAILED; goto done; } if (*new == CK_FALSE) { ret = CKR_OK; goto done; } /* NVTOK.DAT is already new, now check if we can read the keys */ ret = load_NVTOK_DAT(data_store, "NVTOK.DAT", &tokdata); if (ret != CKR_OK) { TRACE_ERROR("Cannot load NVTOK.DAT, datastore inconsistent, ret=%08lX\n", ret); ret = CKR_FUNCTION_FAILED; goto done; } ret = load_masterkey_312(data_store, "MK_SO", sopin, &tokdata, masterkey_so); if (ret != CKR_OK) { TRACE_INFO("Cannot load new MK from MK_SO, datastore probably old.\n"); goto done; } ret = load_masterkey_312(data_store, "MK_USER", userpin, &tokdata, masterkey_user); if (ret != CKR_OK) { TRACE_INFO("Cannot load new MK from MK_USER, datastore probably old.\n"); goto done; } if (memcmp(masterkey_so, masterkey_user, 32) != 0) { TRACE_ERROR("MKs from MK_SO and MK_USER don't match, datastore inconsistent.\n"); ret = CKR_FUNCTION_FAILED; goto done; } ret = count_objects(data_store, &num_objs, &num_old_objs); if (ret != CKR_OK) { TRACE_ERROR("cannot count objects in %s.\n", data_store); ret = CKR_FUNCTION_FAILED; goto done; } TRACE_INFO("Found %d objects total, %d old objects.\n", num_objs, num_old_objs); if (num_old_objs > 0) TRACE_WARN("Note that the old objects are not usable anymore, because " "we don't have the corresponding old masterkey!\n"); if (num_objs > 0 && num_old_objs == 0) *new = CK_TRUE; ret = CKR_OK; done: return ret; } /** * Switch to new repository by deleting the old repository and renaming * the backup folder to the original data store name. */ static CK_RV switch_to_new_repository(const char *data_store_old, const char *data_store_new) { char fname1[PATH_MAX]; CK_RV ret; int rc = -1; TRACE_INFO("Switching to new repository ...\n"); /* Rename original repository folder */ snprintf(fname1, sizeof(fname1), "%s_BAK", data_store_old); rc = rename(data_store_old, fname1); if (rc) { TRACE_ERROR("Cannot rename %s, errno=%s.\n", data_store_old, strerror(errno)); ret = CKR_FUNCTION_FAILED; goto done; } /* Rename backup folder */ rc = rename(data_store_new, data_store_old); if (rc) { TRACE_ERROR("Cannot rename %s, errno=%s.\n", data_store_new, strerror(errno)); ret = CKR_FUNCTION_FAILED; goto done; } ret = CKR_OK; done: return ret; } /** * Inserts the new tokversion parm in the token's slot configuration, e.g. * * slot 2 * { * stdll = libpkcs11_cca.so * tokversion = 3.12 * } */ static CK_RV update_opencryptoki_conf(CK_SLOT_ID slot_id, char *location) { char dst_file[PATH_MAX], src_file[PATH_MAX], fname[PATH_MAX+20]; struct ConfigBaseNode *config = NULL, *c; struct ConfigVersionValNode *v; struct ConfigIdxStructNode *slot; FILE *fp_w = NULL; CK_RV ret; int rc; TRACE_INFO("Updating config file ...\n"); /* Open current conf file for read */ snprintf(src_file, PATH_MAX, "%s/%s", location, "opencryptoki.conf"); config = config_parse(src_file, TRUE); if (config == NULL) { TRACE_ERROR("failed to parse config file %s\n", src_file); ret = CKR_FUNCTION_FAILED; goto done; } /* Update the tokeversion for the selected slot */ slot = confignode_findidx(config, "slot", slot_id); if (slot == NULL) { TRACE_ERROR("failed to find slot %lu in config file %s\n", slot_id, src_file); ret = CKR_FUNCTION_FAILED; goto done; } c = confignode_find(slot->value, "tokversion"); if (c != NULL) { /* modify existing tokversion */ if (confignode_hastype(c, CT_VERSIONVAL)) { confignode_to_versionval(c)->value = TOKVERSION_312; } else if (confignode_hastype(c, CT_STRINGVAL)) { free(confignode_to_stringval(c)->value); confignode_to_stringval(c)->value = strdup(TOKVERSION_312_STRING); if (confignode_to_stringval(c)->value == NULL) { TRACE_ERROR("strdup failed\n"); ret = CKR_HOST_MEMORY; goto done; } } else { TRACE_ERROR("tokversion is invalid in slot %lu in config file %s\n", slot_id, src_file); ret = CKR_FUNCTION_FAILED; goto done; } } else { /* add new tokversion */ v = confignode_allocversionvaldumpable("tokversion", TOKVERSION_312, 0, " added by pkcstok_migrate"); if (v == NULL) { TRACE_ERROR("failed to allocate config node for config file %s\n", src_file); ret = CKR_HOST_MEMORY; goto done; } confignode_append(slot->value, &v->base); } /* Open new conf file for write */ snprintf(dst_file, PATH_MAX, "%s/%s", location, "opencryptoki.conf_new"); fp_w = fopen(dst_file, "w"); if (!fp_w) { TRACE_ERROR("fopen(%s) failed, errno=%s\n", dst_file, strerror(errno)); ret = CKR_FUNCTION_FAILED; goto done; } fchmod(fileno(fp_w), S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); confignode_dump(fp_w, config, NULL, 2); fclose(fp_w); fp_w = NULL; /* Rename old conf file */ snprintf(fname, sizeof(fname), "%s_BAK", src_file); rc = rename(src_file, fname); if (rc) { TRACE_ERROR("Cannot rename %s\n", src_file); ret = CKR_FUNCTION_FAILED; goto done; } /* Rename new file */ rc = rename(dst_file, src_file); if (rc) { TRACE_ERROR("Cannot rename %s.\n", dst_file); ret = CKR_FUNCTION_FAILED; goto done; } ret = CKR_OK; done: confignode_deepfree(config); return ret; } /** * Removes the token_s shared memory from /dev/shm */ static CK_RV remove_shared_memory(char *location) { char shm_name[PATH_MAX]; int i, k, rc; i = k = 0; shm_name[k++] = '/'; if (location[i] == '/') i++; for (; location[i]; i++, k++) { if (location[i] == '/') shm_name[k] = '.'; else shm_name[k] = location[i]; } shm_name[k] = '\0'; rc = shm_unlink(shm_name); if (rc != 0 && errno != ENOENT) { warnx("shm_unlink(%s) failed, errno=%s", shm_name, strerror(errno)); return CKR_FUNCTION_FAILED; } return CKR_OK; } /** * Copy a file given by name from a src folder to a dst folder. */ static CK_RV file_copy(char *dst, const char *src, const char *name, const char *token_group) { char dst_file[PATH_MAX], src_file[PATH_MAX], buf[4096]; FILE *fp_r = NULL, *fp_w = NULL; size_t written; CK_RV ret; snprintf(dst_file, PATH_MAX, "%s/%s", dst, name); snprintf(src_file, PATH_MAX, "%s/%s", src, name); fp_r = fopen(src_file, "r"); if (!fp_r) { warnx("fopen(%s) failed, errno=%s", src_file, strerror(errno)); ret = CKR_FUNCTION_FAILED; goto done; } fp_w = fopen(dst_file, "w"); if (!fp_w) { warnx("fopen(%s) failed, errno=%s", dst_file, strerror(errno)); ret = CKR_FUNCTION_FAILED; goto done; } ret = set_perm(fileno(fp_w), token_group); if (ret != CKR_OK) goto done; while (!feof(fp_r)) { size_t bytes = fread(buf, 1, sizeof(buf), fp_r); if (bytes) { // can be zero, if file empty written = fwrite(buf, 1, bytes, fp_w); if (written != bytes) { warnx("fwrite(%s) failed, errno=%s", dst_file, strerror(errno)); ret = CKR_FUNCTION_FAILED; goto done; } } } ret = CKR_OK; done: if (fp_r) fclose(fp_r); if (fp_w) fclose(fp_w); return ret; } /** * Change the group owner of the given directory to 'pkcs11'. */ static CK_RV change_owner(char *dir, const char *token_group) { struct group* grp; CK_RV ret; if (token_group == NULL || token_group[0] == '\0') token_group = PKCS_GROUP; /* Set group owner */ grp = getgrnam(token_group); if (grp) { if (chown(dir, -1, grp->gr_gid)) { ret = CKR_FUNCTION_FAILED; goto done; } } else { ret = CKR_FUNCTION_FAILED; goto done; } /* Fix group permissions (see man 2 mkdir for details) */ if (chmod(dir, 0770)) { ret = CKR_FUNCTION_FAILED; goto done; } ret = CKR_OK; done: return ret; } /** * Copy the given src folder to the given dst folder including all * subdirectories and files. */ static CK_RV folder_copy(char *dst, const char *src, const char *token_group) { char d[PATH_MAX], s[PATH_MAX]; struct dirent *entry; CK_RV ret; DIR *dir; /* Open src */ dir = opendir(src); if (dir == NULL) { TRACE_ERROR("Cannot open %s\n", src); return CKR_FUNCTION_FAILED; } /* Create dst */ if (mkdir(dst, 0) != 0) { TRACE_ERROR("Cannot create %s\n", dst); ret = CKR_FUNCTION_FAILED; goto done; } /* Change group owner and set permissions */ ret = change_owner(dst, token_group); if (ret != CKR_OK) { TRACE_ERROR("Cannot change owner and permissions for %s\n", dst); ret = CKR_FUNCTION_FAILED; goto done; } /* Copy folder recursively, skip the "." and ".." entries */ while ((entry = readdir(dir)) != NULL) { #if defined(_AIX) /* POSIX does not mandate the d_type member, so get that with stat */ struct stat buf; int rc; strncpy(s, src, PATH_MAX - NAME_MAX - 1); /* strncpy will NOT include NULL if it copied exactly n bytes */ s[PATH_MAX - NAME_MAX] = '\0'; strncat(s, "/", 1); strncat(s, entry->d_name, NAME_MAX); rc = stat(s, &buf); if (rc != 0) { TRACE_ERROR("Cannot stat file %s: %d", entry->d_name, rc); continue; /* something went wrong, skip */ } if (S_ISDIR(buf.st_mode)) { #else if (entry->d_type == DT_DIR) { #endif if (strncmp(entry->d_name, ".", 1) != 0) { snprintf(d, PATH_MAX, "%s/%s", dst, entry->d_name); snprintf(s, PATH_MAX, "%s/%s", src, entry->d_name); ret = folder_copy(d, s, token_group); if (ret != CKR_OK) goto done; } } else { ret = file_copy(dst, src, entry->d_name, token_group); if (ret != CKR_OK) goto done; } } ret = CKR_OK; done: closedir(dir); return ret; } /** * Remove the given folder and all of its contents. */ static CK_RV folder_delete(const char *folder) { DIR *dir; char fname[PATH_MAX]; size_t len, path_len; struct stat statbuf; struct dirent *ent; CK_RV ret = CKR_OK; dir = opendir(folder); if (!dir) { TRACE_INFO("Folder %s doesn't exist.\n", folder); return CKR_OK; } path_len = strlen(folder); while (!ret && (ent = readdir(dir))) { if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) continue; len = path_len + strlen(ent->d_name) + 2; snprintf(fname, len, "%s/%s", folder, ent->d_name); if (!stat(fname, &statbuf)) { if (S_ISDIR(statbuf.st_mode)) { ret = folder_delete(fname); if (ret != CKR_OK) goto done; } else { ret = remove(fname); if (ret != CKR_OK) goto done; } } else { /* stat failed */ TRACE_ERROR("Cannot stat %s, errno=%s.\n", fname, strerror(errno)); ret = CKR_FUNCTION_FAILED; goto done; } } ret = CKR_OK; done: closedir(dir); if (ret == CKR_OK) rmdir(folder); return ret; } static CK_BBOOL backups_already_existent(const char *data_store, const char *conf_dir) { char fname[PATH_MAX]; struct stat statbuf; CK_BBOOL ret = CK_FALSE; memset(fname, 0, PATH_MAX); snprintf(fname, PATH_MAX, "%s_BAK", data_store); TRACE_INFO("Checking if backup datastore exists in %s ...\n", fname); if (stat(fname, &statbuf) == 0) { warnx("Error: datastore backup already exists already: %s", fname); ret = CK_TRUE; } memset(fname, 0, PATH_MAX); snprintf(fname, PATH_MAX, "%s/opencryptoki.conf_BAK", conf_dir); TRACE_INFO("Checking if config file backup exists in %s ...\n", fname); if (stat(fname, &statbuf) == 0) { warnx("Error: config file backup already exists already: %s", fname); ret = CK_TRUE; } return ret; } /** * Backs up the given data_store to data_store_PKCSTOK_MIGRATE_TMP. * All folders and files are recursively created and copied. * Remove the backup if it already exists so that we always have * a clean backup. * The calling routine ensures that data_store does not end with a '/' ! */ static CK_RV backup_repository(const char *data_store, const char *token_group) { char dst[PATH_MAX]; CK_RV ret = CKR_OK; TRACE_INFO("Creating data store backup ...\n"); memset(dst, 0, PATH_MAX); snprintf(dst, PATH_MAX, "%s_PKCSTOK_MIGRATE_TMP", data_store); ret = folder_delete(dst); if (ret != CKR_OK) { warnx("Fatal error: cannot delete old backup: %s", dst); return CKR_FUNCTION_FAILED; } return folder_copy(dst, data_store, token_group); } /** * Checks if the pkcsslotd is running. */ static CK_BBOOL pkcsslotd_running(void) { FILE *fp; char* endptr; long lpid; char fname[PATH_MAX]; char buf[PATH_MAX]; char* first; TRACE_INFO("Checking if pkcsslotd is running ...\n"); fp = fopen(PID_FILE_PATH, "r"); if (fp == NULL) { TRACE_INFO("Pid file '%s' not existent, pkcsslotd is not running\n", PID_FILE_PATH); return CK_FALSE; } if (fgets(buf, sizeof(buf), fp) == NULL) { TRACE_WARN("Cannot read pid file '%s': %s\n", PID_FILE_PATH, strerror(errno)); fclose(fp); return CK_FALSE; } fclose(fp); lpid = strtol(buf, &endptr, 10); if (*endptr != '\0' && *endptr != '\n') { TRACE_WARN("Failed to parse pid file '%s': %s\n", PID_FILE_PATH, buf); return CK_FALSE; } snprintf(fname, sizeof(fname), "/proc/%ld/cmdline", lpid); fp = fopen(fname, "r"); if (fp == NULL) { TRACE_INFO("Stale pid file, pkcsslotd is not running\n"); return CK_FALSE; } if (fgets(buf, sizeof(buf), fp) == NULL) { TRACE_INFO("Failed to read '%s'\n", fname); fclose(fp); return CK_FALSE; } fclose(fp); first = strtok(buf, " "); return (first != NULL && strstr(first, "pkcsslotd") != NULL); } /** * */ static CK_BBOOL token_invalid(const char *dll) { if (strcmp(dll, INVALID_TOKEN) == 0) return CK_TRUE; else return CK_FALSE; } /** * returns the token name related to the given stdll name for the * 4 supported tokens. */ static const char *dll2name(const char *dll) { static char *dlls[] = { "libpkcs11_ica.so", "libpkcs11_cca.so", "libpkcs11_sw.so", "libpkcs11_ep11.so" }; static char *names[] = { "ICA", "CCA", "Soft", "EP11" }; int i, num_tokens = sizeof(names) / sizeof(char *); for (i = 0; i < num_tokens; i++) { if (strcmp(dll, dlls[i]) == 0) return names[i]; } return INVALID_TOKEN; } /** * translates the given verbose level string into a numeric verbose level. * Returns -1 if the string is invalid. */ static int verbose_str2level(char *str) { const char *tlevel[] = {"none", "error", "warn", "info", "devel", "debug"}; const int num = sizeof(tlevel) / sizeof(char *); int i; for (i = 0; i < num; i++) { if (strcmp(str, tlevel[i]) == 0) { return i; } } return -1; } static void usage(char *progname) { printf(" Help:\t\t\t\t%s -h\n", progname); printf(" -h, --help \t\t\tShow this help\n\n"); printf(" Options:\n"); printf(" -s, --slotid SLOTID\t\tPKCS slot number (required)\n"); printf(" -d, --datastore DATASTORE\ttoken datastore location (required)\n"); printf(" -c, --confdir CONFDIR\t\tlocation of opencryptoki.conf (required)\n"); printf(" -u, --userpin USERPIN\t\ttoken user pin (prompted if not specified)\n"); printf(" -p, --sopin SOPIN\t\ttoken SO pin (prompted if not specified)\n"); printf(" -v, --verbose LEVEL\t\tset verbose level (optional):\n"); printf("\t\t\t\tnone (default), error, warn, info, devel, debug\n"); return; } int main(int argc, char **argv) { CK_RV ret = 0; int opt = 0, vlevel = -1; CK_SLOT_ID slot_id = 0; CK_BBOOL slot_id_specified = CK_FALSE; size_t buflen = 0; ssize_t num_chars; char *data_store = NULL, *data_store_old = NULL, *conf_dir = NULL; const char *sopin = NULL, *userpin = NULL; char *buf_so = NULL, *buf_user = NULL; char *verbose = NULL; char *buff = NULL; char dll_name[PATH_MAX]; char token_group[PATH_MAX] = { 0 }; char data_store_new[PATH_MAX]; CK_TOKEN_INFO_32 tokinfo; CK_BBOOL new; static const struct option long_opts[] = { {"datastore", required_argument, NULL, 'd'}, {"confdir", required_argument, NULL, 'c'}, {"slotid", required_argument, NULL, 's'}, {"userpin", required_argument, NULL, 'u'}, {"sopin", required_argument, NULL, 'p'}, {"verbose", required_argument, NULL, 'v'}, {"help", no_argument, NULL, 'h'}, {0, 0, 0, 0} }; while ((opt = getopt_long(argc, argv, "d:c:s:u:p:v:h", long_opts, NULL)) != -1) { switch (opt) { case 'd': data_store = strdup(optarg); if (data_store == NULL) { warnx("strdup failed."); exit(1); } break; case 'c': conf_dir = strdup(optarg); if (conf_dir == NULL) { warnx("strdup failed."); exit(1); } break; case 's': slot_id = atoi(optarg); slot_id_specified = CK_TRUE; break; case 'u': userpin = optarg; break; case 'p': sopin = optarg; break; case 'v': verbose = strdup(optarg); if (verbose == NULL) { warnx("strdup failed."); exit(1); } vlevel = verbose_str2level(verbose); if (vlevel < 0) { warnx("Invalid verbose level '%s' specified.", verbose); usage(argv[0]); exit(1); } break; case 'h': usage(argv[0]); exit(0); default: warnx("Parameters are required."); usage(argv[0]); exit(1); } } if (argc == 1) { usage(argv[0]); exit(1); } if (geteuid() != 0) { fprintf(stderr, "%s can only be used as root.\n", argv[0]); exit(-1); } printf("\npkcstok_migrate:\n"); printf("Summary of input parameters:\n"); if (data_store) { strip_trailing_chars(data_store, strlen(data_store), '/'); printf(" datastore = %s \n", data_store); } if (conf_dir) { strip_trailing_chars(conf_dir, strlen(conf_dir), '/'); printf(" confdir = %s \n", conf_dir); } if (slot_id_specified) printf(" slot ID = %lu\n", slot_id); if (userpin) printf(" user PIN specified\n"); if (sopin) printf(" SO PIN specified\n"); if (vlevel >= 0) { trace_level = vlevel; printf(" verbose level = %s\n", verbose); } printf("\n"); /* Slot ID must be given */ if (!slot_id_specified) { warnx("Slot ID must be specified."); goto done; } /* Datastore must be given */ if (data_store == NULL) { warnx("Data store path must be specified."); goto done; } /* Limit datastore path length because of appended suffixes */ if (strlen(data_store) > PKCSTOK_MIGRATE_MAX_PATH_LEN) { warnx("Datastore path (%zu characters) is too long (max = %u).\n", strlen(data_store), PKCSTOK_MIGRATE_MAX_PATH_LEN); ret = CKR_FUNCTION_FAILED; goto done; } /* Location of opencryptoki.conf must be specified. */ if (conf_dir == NULL) { warnx("Location of opencryptoki.conf must be specified."); goto done; } /* Limit path to config file because of appended suffixes */ if (strlen(conf_dir) > PKCSTOK_MIGRATE_MAX_PATH_LEN) { warnx("Path to config file (%zd characters) is too long (max = %u).\n", strlen(conf_dir), PKCSTOK_MIGRATE_MAX_PATH_LEN); ret = CKR_FUNCTION_FAILED; goto done; } /* Check if given data_store exists */ if (!datastore_exists(data_store)) { ret = CKR_FUNCTION_FAILED; warnx("Datastore %s does not exist.", data_store); goto done; } /* Check if given conf_dir exists and contains opencryptoki.conf */ if (!conffile_exists(conf_dir)) { ret = CKR_FUNCTION_FAILED; warnx("%s does not exist or does not contain opencryptoki.conf", conf_dir); goto done; } if (backups_already_existent(data_store, conf_dir)) { warnx("Please remove the backups before running this utility."); ret = CKR_FUNCTION_FAILED; goto done; } /* Check if pkcsslotd is running */ if (pkcsslotd_running()) { warnx("Please stop pkcsslotd before running this utility."); ret = CKR_FUNCTION_FAILED; goto done; } /* Identify token related to given slot ID */ ret = identify_token(slot_id, conf_dir, dll_name, sizeof(dll_name), token_group, sizeof(token_group)); if (ret != CKR_OK) { warnx("Cannot identify a token related to given slot ID %ld", slot_id); goto done; } /* Check if DLL name from conf file is a known and migratable token */ printf("Slot ID %lu points to DLL name %s, which is a %s token.\n", slot_id, dll_name, dll2name(dll_name)); if (token_invalid(dll2name(dll_name))) { warnx("Please check your input."); goto done; } /* Get token info from NVTOK.DAT */ ret = get_token_info(data_store, &tokinfo); if (ret != CKR_OK) { warnx("Cannot get the token label from NVTOK.DAT"); goto done; } /* Check with user if ok to migrate this token, or quit if token not migratable */ printf("Data store %s points to this token info:\n", data_store); printf(" label : %.*s\n", 32, tokinfo.label); printf(" manufacturerID : %.*s\n", 32, tokinfo.manufacturerID); printf(" model : %.*s\n", 16, tokinfo.model); printf(" serialNumber : %.*s\n", 16, tokinfo.serialNumber); printf(" hardwareVersion : %i.%i\n", tokinfo.hardwareVersion.major, tokinfo.hardwareVersion.minor); printf(" firmwareVersion : %i.%i\n", tokinfo.firmwareVersion.major, tokinfo.firmwareVersion.minor); printf(" user group: : %s\n", token_group[0] == '\0' ? PKCS_GROUP " (default)" : token_group); printf("Migrate this token with given slot ID? y/n\n"); num_chars = getline(&buff, &buflen, stdin); if (num_chars < 0 || strncmp(buff, "y", 1) != 0) { printf("ok, let's quit.\n"); goto done; } /* Get the SO pin to authorize migration */ if (!sopin) sopin = pin_prompt(&buf_so, "Enter the SO PIN: "); if(!sopin) { warnx("Could not get SO PIN."); goto done; } /* Get the USER pin to authorize migration */ if (!userpin) userpin = pin_prompt(&buf_user, "Enter the USER PIN: "); if (!userpin) { warnx("Could not get USER PIN."); goto done; } /* Verify the SO and USER PINs entered against NVTOK.DAT. */ ret = verify_pins(data_store, sopin, strlen(sopin), userpin, strlen(userpin)); if (ret) { warnx("Could not verify pins."); goto done; } /* Check if data store is already new */ ret = datastore_is_312(data_store, sopin, userpin, &new); if (ret == 0 && new) { printf("Data store %s is already in new format.\n", data_store); goto finalize; } /* Backup repository if not already done */ ret = backup_repository(data_store, token_group); if (ret != CKR_OK) { warnx("Failed to create backup."); goto done; } /* Perform all actions on the backup */ data_store_old = data_store; snprintf(data_store_new, PATH_MAX, "%s_PKCSTOK_MIGRATE_TMP", data_store_old); /* Create new temp token keys, which exist in parallel to the old ones * until the migration is fully completed. */ ret = create_token_keys_312(data_store_new, sopin, userpin, token_group); if (ret != CKR_OK) { warnx("Failed to create new token keys."); goto done; } /* Migrate repository */ ret = migrate_repository(data_store_new, sopin, userpin, token_group); if (ret != CKR_OK) { warnx("Failed to migrate repository."); goto done; } /* Switch to new repository */ ret = switch_to_new_repository(data_store_old, data_store_new); if (ret != CKR_OK) { warnx("Switch to new repository failed."); goto done; } finalize: /* Remove the token's shared memory */ ret = remove_shared_memory(data_store); if (ret != CKR_OK) { warnx("Failed to remove token's shared memory."); goto done; } /* Now insert new 'tokversion=3.12' parm in opencryptoki.conf */ ret = update_opencryptoki_conf(slot_id, conf_dir); if (ret != CKR_OK) { warnx("Failed to update opencryptoki.conf, you must do this manually."); goto done; } if (data_store_old != NULL) printf("Pre-migration data backed up at '%s_BAK'\n", data_store_old); printf("Config file backed up at '%s/opencryptoki.conf_BAK'\n", conf_dir); printf("Remove these backups manually after testing the new repository.\n"); ret = CKR_OK; done: free(buff); pin_free(&buf_so); pin_free(&buf_user); free(data_store); free(conf_dir); free(verbose); if (ret == CKR_OK) { printf("pkcstok_migrate finished successfully.\n"); return EXIT_SUCCESS; } else { printf("pkcstok_migrate finished with warnings/errors.\n"); return EXIT_FAILURE; } } opencryptoki-opencryptoki-451d99c/usr/sbin/pkcstok_migrate/pkcstok_migrate.mk000066400000000000000000000022451520105705100300000ustar00rootroot00000000000000sbin_PROGRAMS += usr/sbin/pkcstok_migrate/pkcstok_migrate usr_sbin_pkcstok_migrate_pkcstok_migrate_LDFLAGS = -lcrypto -ldl -lrt if AIX usr_sbin_pkcstok_migrate_pkcstok_migrate_LDFLAGS += -lpthread endif usr_sbin_pkcstok_migrate_pkcstok_migrate_CFLAGS = \ -DSTDLL_NAME=\"pkcstok_migrate\" \ -I${srcdir}/usr/include \ -I${srcdir}/usr/lib/common \ -I${srcdir}/usr/sbin/pkcstok_migrate \ -I${srcdir}/usr/lib/api \ -I${top_builddir}/usr/lib/api \ -I${srcdir}/usr/lib/config \ -I${top_builddir}/usr/lib/config usr_sbin_pkcstok_migrate_pkcstok_migrate_SOURCES = \ usr/lib/common/p11util.c \ usr/lib/common/sw_crypt.c \ usr/lib/common/trace.c \ usr/lib/common/pkcs_utils.c \ usr/lib/common/pin_prompt.c \ usr/sbin/pkcstok_migrate/pkcstok_migrate.c \ usr/lib/config/configuration.c \ usr/lib/config/cfgparse.y \ usr/lib/config/cfglex.l if AIX usr_sbin_pkcstok_migrate_pkcstok_migrate_SOURCES += usr/lib/common/aix/err.c \ usr/lib/common/aix/getopt_long.c endif nodist_usr_sbin_pkcstok_migrate_pkcstok_migrate_SOURCES = \ usr/lib/api/mechtable.c usr/sbin/pkcstok_migrate/pkcstok_migrate.$(OBJEXT): usr/lib/config/cfgparse.h opencryptoki-opencryptoki-451d99c/usr/sbin/sbin.mk000066400000000000000000000015011520105705100223510ustar00rootroot00000000000000if 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 if ENABLE_PKCSCCA include usr/sbin/pkcscca/pkcscca.mk endif endif if ENABLE_P11SAK include usr/sbin/p11sak/p11sak.mk endif if ENABLE_PKCSTOK_MIGRATE include usr/sbin/pkcstok_migrate/pkcstok_migrate.mk endif if ENABLE_PKCSSTATS include usr/sbin/pkcsstats/pkcsstats.mk endif if ENABLE_PKCSHSM_MK_CHANGE include usr/sbin/pkcshsm_mk_change/pkcshsm_mk_change.mk endif if ENABLE_PKCSTOK_ADMIN include usr/sbin/pkcstok_admin/pkcstok_admin.mk endif if ENABLE_P11KMIP include usr/sbin/p11kmip/p11kmip.mk endif include usr/sbin/pkcsslotd/pkcsslotd.mk include usr/sbin/pkcsconf/pkcsconf.mk opencryptoki-opencryptoki-451d99c/usr/usr.mk000066400000000000000000000001471520105705100213010ustar00rootroot00000000000000if ENABLE_DAEMON include usr/include/include.mk include usr/sbin/sbin.mk endif include usr/lib/lib.mk